From 6298b371b7f176bf73f90604857f2eb15fa64da4 Mon Sep 17 00:00:00 2001 From: gxia0005 Date: Sat, 25 Apr 2026 12:02:08 +1000 Subject: [PATCH 1/9] Unit Counter Commit --- C3X.h | 56 +++++- civ_prog_objects.csv | 9 +- default.c3x_config.ini | 52 +++++ injected_code.c | 439 +++++++++++++++++++++++++++++++---------- 4 files changed, 444 insertions(+), 112 deletions(-) diff --git a/C3X.h b/C3X.h index 2723875b..ed1770dd 100644 --- a/C3X.h +++ b/C3X.h @@ -1,4 +1,3 @@ - #include #define NOVIRTUALKEYCODES // Keycodes defined in Civ3Conquests.h instead @@ -10,8 +9,8 @@ typedef unsigned char byte; #define __fastcall __attribute__((fastcall)) #include "Civ3Conquests.h" -#define MOD_VERSION 2700 -#define MOD_PREVIEW_VERSION 1 +#define MOD_VERSION 2600 +#define MOD_PREVIEW_VERSION 0 #define COUNT_TILE_HIGHLIGHTS 11 #define MAX_BUILDING_PREREQS_FOR_UNIT 10 @@ -196,6 +195,38 @@ enum perfume_kind { COUNT_PERFUME_KINDS }; +struct unit_counter_group { + char * name; + int * type_ids; + int count_type_ids; +}; + +// 攻击方/防守方匹配方式 +#define UCM_ANY -1 // * 任意兵种 +#define UCM_GROUP -2 // 用 group_name 字段匹配 + +struct counter_rule { + // 攻击方 + int attacker_match; // UnitTypeID,或 UCM_ANY / UCM_GROUP + char * attacker_group; // attacker_match == UCM_GROUP 时有效 + + // 防守方 + int defender_match; + char * defender_group; + + // 环境条件(-1 / false 表示不限) + int terrain_type; // enum SquareTypes,-1 = 不限 + bool only_in_city; + int district_id; // -1 = 不限 + bool ignore_terrain; // true = 将防守方 Defence 置 0 + + // 效果(百分比,100 = 无变化) + int self_atk_pct; + int self_def_pct; + int enemy_atk_pct; + int enemy_def_pct; +}; + struct c3x_config { bool enable_stack_bombard; bool enable_disorder_warning; @@ -350,7 +381,11 @@ struct c3x_config { bool allow_sale_of_small_wonders; enum no_ai_patrol_override override_no_ai_patrol; enum barbarian_activity_override override_barbarian_activity_level_for_scenario_maps; - bool initialize_preplaced_scenario_leaders_as_mgls; + bool enable_unit_counters; + struct unit_counter_group * unit_counter_groups; + int count_unit_counter_groups; + struct counter_rule * counter_rules; + int count_counter_rules; bool enable_trade_net_x; bool optimize_improvement_loops; @@ -1826,6 +1861,17 @@ struct injected_state { int unit_id, tile_x, tile_y; } unit_display_override; + // Set in patch_Fighter_get_odds_for_main_combat_loop, read by patch_Unit_get_attack/defense_strength. + // Stores counter multipliers for the current combat. Active only during Fighter_get_combat_odds call. + struct { + bool active; + Unit * attacker; + Unit * defender; + int attacker_atk_pct; // 攻击方攻击力倍率(合并了 self-atk 正向和 enemy-atk 反向) + int defender_def_pct; // 防守方防御力倍率(合并了 enemy-def 正向和 self-def 反向) + bool ignore_terrain; + } counter_combat_ctx; + // Used to extract which unit (if any) exerted zone of control from within Fighter::apply_zone_of_control. Unit * zoc_interceptor; @@ -2270,4 +2316,4 @@ struct civ_prog_object { int addr; char const * name; char const * type; -}; +}; \ No newline at end of file diff --git a/civ_prog_objects.csv b/civ_prog_objects.csv index 83fd741b..4c0a4eed 100644 --- a/civ_prog_objects.csv +++ b/civ_prog_objects.csv @@ -31,7 +31,7 @@ define, 0x499FE0, 0x49F9F0, 0x49A070, "is_online_game", "char (__stdcall * define, 0x437A70, 0x439620, 0x437AF0, "tile_at", "Tile * (__cdecl *) (int x, int y)" define, 0x426C80, 0x4283C0, 0x426D00, "TileUnits_TileUnitID_to_UnitID", "int (__fastcall *) (TileUnits * this, int edx, int tile_unit_id, int * out_UnitItem_field_0)" inlead, 0x5C1410, 0x5CFFA0, 0x5C1120, "Unit_bombard_tile", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -define, 0x5BE820, 0x5CD420, 0x5BE530, "Unit_get_defense_strength", "int (__fastcall *) (Unit * this)" +inlead, 0x5BE820, 0x5CD420, 0x5BE530, "Unit_get_defense_strength", "int (__fastcall *) (Unit * this)" inlead, 0x5BB650, 0x5CA190, 0x5BB360, "Unit_is_visible_to_civ", "char (__fastcall *) (Unit * this, int edx, int civ_id, int param_2)" define, 0x5EA6C0, 0x5F9F10, 0x5EA5F0, "Tile_has_city", "char (__fastcall *) (Tile * this)" define, 0x5EA6E0, 0x5F9F30, 0x5EA610, "Tile_has_colony", "bool (__fastcall *) (Tile * this)" @@ -410,7 +410,7 @@ repl call, 0x4A784E, 0x4AE509, 0x4a78DE, "Tile_check_water_for_sea_zoc", "" define, 0x4A79C2, 0x4AE66D, 0x4A7A52, "ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC", "byte *" define, 0x4A7CAA, 0x4AE962, 0x4A7D3A, "ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC", "byte *" repl call, 0x4A7BF2, 0x4AE8AA, 0x4A7C82, "Tile_check_water_for_land_zoc", "" -define, 0x5BE6E0, 0x5CD2C0, 0x5BE3F0, "Unit_get_attack_strength", "int (__fastcall *) (Unit * this)" +inlead, 0x5BE6E0, 0x5CD2C0, 0x5BE3F0, "Unit_get_attack_strength", "int (__fastcall *) (Unit * this)" repl call, 0x4A79CA, 0x4AE675, 0x4A7A5A, "Unit_get_attack_strength_for_sea_zoc", "" repl call, 0x4A7B15, 0x4AE7BE, 0x4A7BA5, "Unit_get_attack_strength_for_sea_zoc", "" repl call, 0x4A7B20, 0x4AE7C9, 0x4A7BB0, "Unit_get_attack_strength_for_sea_zoc", "" @@ -923,11 +923,6 @@ inlead, 0x440100, 0x441ED0, 0x440180, "Leader_get_attitude_toward", "int (_ inlead, 0x5D7080, 0x5E64E0, 0x5D6FB0, "Map_check_colony_location", "int (__fastcall *) (Map * this, int edx, int tile_x, int tile_y, int civ_id)" inlead, 0x5BCE60, 0x5CBA10, 0x5BCB70, "Unit_select_army_member_for_combat", "Unit * (__fastcall *) (Unit * this, int edx, int param_1, char param_2)" inlead, 0x44C340, 0x44E330, 0x44C3C0, "Unit_ai_eval_bombard_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, int param_3)" -define, 0x5CD770, 0x5DC720, 0x5CD690, "UnitIDList_insert_after", "void (__fastcall *) (UnitIDList * this, int edx, int id, UnitIDItem * item)" -repl call, 0x5BBBA6, 0x5CA70C, 0x5BB8B6, "UnitIDList_insert_after_init", "" -define, 0x5BCC90, 0x5CB840, 0x5BC9A0, "Unit_load_into_army", "void (__fastcall *) (Unit * this, int edx, Unit * loadee)" -repl call, 0x5B9FEC, 0x5C8AB3, 0x5B9CFC, "Unit_load_into_army_after_move_to_adj_tile", "" - ignore, 0x5FC710, 0x0, 0x0, "PCX_Image_create_and_init_jgl_image", "int (__fastcall *) (PCX_Image * this, int edx, int width, int height, int bit_depth, int param_4, int param_5, int param_6)" ignore, 0x5FCC50, 0x0, 0x0, "PCX_Image_draw_region_to_location", "void (__fastcall *) (PCX_Image * this, int edx, PCX_Image * canvas, int src_x, int src_y, int dest_x, int dest_y, int width, int height)" ignore, 0x600050, 0x0, 0x0, "PCX_Image_fill", "void (__fastcall *) (PCX_Image * this, int edx, int color)" diff --git a/default.c3x_config.ini b/default.c3x_config.ini index 7f0a9c5a..60c232c2 100644 --- a/default.c3x_config.ini +++ b/default.c3x_config.ini @@ -891,6 +891,58 @@ override_barbarian_activity_level_for_scenario_maps = none ; types at the start of the game so they behave like normal MGLs spawned during a game. initialize_preplaced_scenario_leaders_as_mgls = false +enable_unit_counters = true + +; unit_group allows you gruop your units in a group,please refer to building_prereqs_for_units for the format. +; This function will not work if enable_unit_counters is false. +unit_group = [] +; ── counter_rule format ────────────────────────────────────────────────────────────── +; +; counter_rule = [Friendly vs Enemy Effect... Conditions...] +; +; 【Friendly / Enemy】 +; This can be one of the following three options: +; · The specific unit type, such as "Archer" (must match the name in BIQ exactly; names containing spaces must be enclosed in quotation marks) +; · A unit group name, such as melee (i.e. the group defined in the unit_group section above) +; · "*" represents any unit type (the asterisk must be enclosed in quotation marks) +; +; 【Effect】(Expressed as a percentage; when multiple rules apply to the same battle, their effects are multiplied.) +; +; "self" always refers to the first unit, and "enemy" always refers to the second unit, regardless of who is attacking whom: +; self-atk value — The unit’s attack power becomes N% of its original value +; Example: self-atk 150 = attack power ×1.5; self-atk 50 = attack power ×0.5 +; self-def value — Your defence becomes N% of the original value; +; enemy-atk value — The enemy’s attack becomes N% of the original value; +; enemy-def value — The enemy’s defence becomes N% of the original value; +; +; 【Conditions】(Optional; leaving blank indicates no restrictions; conditions take effect only when all are met simultaneously) +; in-city —— Takes effect only when the enemy is on a city tile +; terrain terrain_name —— Takes effect only when the enemy is on a tile of the specified terrain +; The terrain name must match the name in BIQ, e.g. Grassland, Forest, Hills +; ignore-terrain —— Ignores the enemy’s terrain defence bonus (sets their terrain bonus to zero) +; Can be used in conjunction with enemy-def; when used together, ignore-terrain takes precedence +; district district_name —— Only takes effect when the enemy is in a specified district (enable_districts must be enabled) +; +; 【Examples】 +; counter_rule = [ranged vs melee self-atk 125] +; → When a ranged unit attacks a melee unit, its attack power is multiplied by 1.25 +; +; counter_rule = ["骑士" vs melee in-city enemy-def 150] +; → When knights attack melee units within a city, the enemy’s defence is multiplied by 1.5 +; +; counter_rule = ["火枪手" vs "中世纪步兵" terrain Grassland self-atk 125] +; → When musketeers attack medieval infantry on grassland terrain, their attack power is multiplied by 1.25 +; +; counter_rule = ["骑士" vs "*" ignore-terrain self-atk 150] +; → When a Knight attacks any unit, its attack power is multiplied by 1.5 and it ignores the enemy’s terrain bonus. +; counter_rule = [Archer vs Swordsman self-atk 130 self-def 120] +; → When an archer attacks a swordsman: Archer’s attack power ×130% +; When a swordsman attacks an archer: Archer’s defence ×120% +; +; ───────────────────────────────────────────────────────────────────────────── + +counter_rule = [] + [==================] [=== AESTHETICS ===] [==================] diff --git a/injected_code.c b/injected_code.c index 1e437218..1995b9d6 100644 --- a/injected_code.c +++ b/injected_code.c @@ -211,6 +211,10 @@ get_city_ptr (int id) return NULL; } +// Forward declarations for unit counter system (defined after their dependencies) +enum recognizable_parse_result parse_unit_counter_group (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_group); +enum recognizable_parse_result parse_counter_rule (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_rule); + // Declare various functions needed for districts and hard to untangle and reorder here void __fastcall patch_City_recompute_yields_and_happiness (City * this); void __fastcall patch_Map_build_trade_network (Map * this); @@ -774,6 +778,13 @@ reset_to_base_config () // Overwrite the current config with the base config memcpy (&is->current_config, &is->base_config, sizeof is->current_config); + // These fields are heap-allocated and must not be inherited from base_config + // (base_config never owns valid pointers for them) + is->current_config.unit_counter_groups = NULL; + is->current_config.count_unit_counter_groups = 0; + is->current_config.counter_rules = NULL; + is->current_config.count_counter_rules = 0; + // Recreate loaded config names list with just the base config is->loaded_config_names = malloc (sizeof *is->loaded_config_names); is->loaded_config_names->name = strdup ("(base)"); @@ -1324,6 +1335,7 @@ parse_era_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_line return RPR_PARSE_ERROR; } + enum recognizable_parse_result parse_civ_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_civ_era_alias_list) { @@ -2620,6 +2632,22 @@ load_config (char const * file_path, int path_is_relative_to_mod_dir) cfg->share_visibility_in_hotseat = ival != 0; else handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "unit_group")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct unit_counter_group), + parse_unit_counter_group, + (void **)&cfg->unit_counter_groups, + &cfg->count_unit_counter_groups))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "counter_rule")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct counter_rule), + parse_counter_rule, + (void **)&cfg->counter_rules, + &cfg->count_counter_rules))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); } else { handle_config_error (&p, CPE_BAD_KEY); @@ -3818,12 +3846,11 @@ wai_init_cities (int x, int y) (aerodrome_inst->district_id == AERODROME_DISTRICT_ID) && \ district_is_complete (aerodrome_tile, AERODROME_DISTRICT_ID); \ aerodrome_inst = NULL) \ - for (int aerodrome_x = 0, aerodrome_y = 0, _iter_count = 0; \ - _iter_count == 0 && \ + for (int aerodrome_x = 0, aerodrome_y = 0; \ district_instance_get_coords (aerodrome_inst, aerodrome_tile, &aerodrome_x, &aerodrome_y) && \ (aerodrome_tile->vtable->m38_Get_Territory_OwnerID (aerodrome_tile) == (unit_ptr)->Body.CivID) && \ patch_Unit_is_in_rebase_range ((unit_ptr), __, aerodrome_x, aerodrome_y); \ - _iter_count++) + aerodrome_x = 0, aerodrome_y = 0) struct tile_rings_iter { int center_x, center_y; @@ -7762,6 +7789,247 @@ find_special_district_index_by_name (char const * name) return -1; } + +// --------------------------------------------------------------- +// 兵种克制系统 +// --------------------------------------------------------------- + +struct unit_counter_group * +find_unit_counter_group_by_name (struct c3x_config * cfg, char const * name) +{ + for (int i = 0; i < cfg->count_unit_counter_groups; i++) { + struct unit_counter_group * g = &cfg->unit_counter_groups[i]; + if (g->name && strcmp (g->name, name) == 0) + return g; + } + return NULL; +} + +bool +unit_type_in_group (struct unit_counter_group * g, int type_id) +{ + char const * name = p_bic_data->UnitTypes[type_id].Name; + for (int i = 0; i < g->count_type_ids; i++) + if (strcmp (p_bic_data->UnitTypes[g->type_ids[i]].Name, name) == 0) + return true; + return false; +} + +bool +unit_matches_counter_side (struct c3x_config * cfg, int type_id, + int match, char * group_name) +{ + if (match == UCM_ANY) + return true; + if (match == UCM_GROUP) { + struct unit_counter_group * g = + find_unit_counter_group_by_name (cfg, group_name); + return g && unit_type_in_group (g, type_id); + } + // Direct unit type match: compare by name rather than exact ID so that + // AI strategy duplicates (same name, different ID) are also matched. + return strcmp (p_bic_data->UnitTypes[match].Name, + p_bic_data->UnitTypes[type_id].Name) == 0; +} + +enum recognizable_parse_result +parse_unit_counter_group (char ** p_cursor, + struct error_line ** p_unrecognized_lines, + void * out_group) +{ + char * cur = *p_cursor; + struct string_slice group_name; + if (! (parse_string (&cur, &group_name) && skip_punctuation (&cur, ':'))) + return RPR_PARSE_ERROR; + + struct unit_counter_group * g = out_group; + g->name = extract_slice (&group_name); + g->type_ids = NULL; + g->count_type_ids = 0; + + int any_unrecognized = 0; + struct string_slice type_name; + while (parse_string (&cur, &type_name)) { + // Loop through all unit types with this name, including AI strategy + // duplicates (same name, different ID), which the game creates internally. + int type_id = 0; + bool found_any = false; + while (find_unit_type_id_by_name (&type_name, type_id, &type_id)) { + g->type_ids = realloc (g->type_ids, + (g->count_type_ids + 1) * sizeof (int)); + g->type_ids[g->count_type_ids++] = type_id; + found_any = true; + type_id++; // continue search from next index + } + if (! found_any) { + add_unrecognized_line (p_unrecognized_lines, &type_name); + any_unrecognized = 1; + } + if (! skip_punctuation (&cur, ',')) + break; + } + *p_cursor = cur; + return any_unrecognized ? RPR_UNRECOGNIZED : RPR_OK; +} + +enum recognizable_parse_result +parse_counter_rule (char ** p_cursor, + struct error_line ** p_unrecognized_lines, + void * out_rule) +{ + char * cur = *p_cursor; + struct string_slice attacker_name, vs_token, defender_name; + + if (! parse_string (&cur, &attacker_name)) + return RPR_PARSE_ERROR; + if (! (parse_string (&cur, &vs_token) && + slice_matches_str (&vs_token, "vs"))) + return RPR_PARSE_ERROR; + if (! parse_string (&cur, &defender_name)) + return RPR_PARSE_ERROR; + + struct counter_rule * r = out_rule; + *r = (struct counter_rule) { + .attacker_match = UCM_ANY, + .defender_match = UCM_ANY, + .terrain_type = -1, + .district_id = -1, + .self_atk_pct = 100, + .self_def_pct = 100, + .enemy_atk_pct = 100, + .enemy_def_pct = 100, + }; + + if (! slice_matches_str (&attacker_name, "*")) { + int type_id; + if (find_unit_type_id_by_name (&attacker_name, 0, &type_id)) + r->attacker_match = type_id; + else { + r->attacker_match = UCM_GROUP; + r->attacker_group = extract_slice (&attacker_name); + } + } + + if (! slice_matches_str (&defender_name, "*")) { + int type_id; + if (find_unit_type_id_by_name (&defender_name, 0, &type_id)) + r->defender_match = type_id; + else { + r->defender_match = UCM_GROUP; + r->defender_group = extract_slice (&defender_name); + } + } + + struct string_slice token; + while (parse_string (&cur, &token)) { + if (slice_matches_str (&token, "in-city")) { + r->only_in_city = true; + } else if (slice_matches_str (&token, "ignore-terrain")) { + r->ignore_terrain = true; + } else if (slice_matches_str (&token, "self-atk")) { + if (! parse_int (&cur, &r->self_atk_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "self-def")) { + if (! parse_int (&cur, &r->self_def_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "enemy-atk")) { + if (! parse_int (&cur, &r->enemy_atk_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "enemy-def")) { + if (! parse_int (&cur, &r->enemy_def_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "terrain")) { + struct string_slice terrain_name; + if (! parse_string (&cur, &terrain_name)) + return RPR_PARSE_ERROR; + if (! read_tile_terrain_type_value (&terrain_name, + (enum SquareTypes *)&r->terrain_type)) { + add_unrecognized_line (p_unrecognized_lines, &terrain_name); + return RPR_UNRECOGNIZED; + } + } else if (slice_matches_str (&token, "district")) { + struct string_slice district_name; + if (! parse_string (&cur, &district_name)) + return RPR_PARSE_ERROR; + char * dname = extract_slice (&district_name); + int idx = find_special_district_index_by_name (dname); + free (dname); + if (idx < 0) { + add_unrecognized_line (p_unrecognized_lines, &district_name); + return RPR_UNRECOGNIZED; + } + r->district_id = idx; + } else { + break; + } + } + + *p_cursor = cur; + return RPR_OK; +} + +void +apply_counter_rules (struct c3x_config * cfg, + Unit * attacker, Unit * defender, Tile * def_tile, + int * out_attacker_atk, int * out_defender_def, + bool * out_ignore_terrain) +{ + int a_type = attacker->Body.UnitTypeID; + int d_type = defender->Body.UnitTypeID; + bool in_city = Tile_has_city (def_tile); + + int aa = 100, dd = 100; + bool ignore = false; + + for (int i = 0; i < cfg->count_counter_rules; i++) { + struct counter_rule * r = &cfg->counter_rules[i]; + + // 检查正向匹配(attacker=规则攻击方,defender=规则防守方) + // 生效字段:self-atk(攻击方攻击力)、enemy-def(防守方防御力) + bool forward = unit_matches_counter_side (cfg, a_type, + r->attacker_match, r->attacker_group) && + unit_matches_counter_side (cfg, d_type, + r->defender_match, r->defender_group); + + // 检查反向匹配(attacker=规则防守方,defender=规则攻击方) + // 生效字段:self-def(规则攻击方现在是防守方)、enemy-atk(规则防守方现在是攻击方) + bool reverse = unit_matches_counter_side (cfg, a_type, + r->defender_match, r->defender_group) && + unit_matches_counter_side (cfg, d_type, + r->attacker_match, r->attacker_group); + + if (! forward && ! reverse) + continue; + + // 环境条件以防守方所在格为准 + if (r->only_in_city && ! in_city) + continue; + if (r->terrain_type != -1 && + ! tile_matches_square_type (def_tile, + (enum SquareTypes)r->terrain_type)) + continue; + if (r->district_id != -1 && + ! (cfg->enable_districts && + district_is_complete (def_tile, r->district_id))) + continue; + + if (forward) { + aa = aa * r->self_atk_pct / 100; // self-atk:攻击方攻击力 + dd = dd * r->enemy_def_pct / 100; // enemy-def:防守方防御力 + } + if (reverse) { + aa = aa * r->enemy_atk_pct / 100; // enemy-atk:规则防守方现在作为攻击方 + dd = dd * r->self_def_pct / 100; // self-def:规则攻击方现在作为防守方 + } + if (forward || reverse) + ignore = ignore || r->ignore_terrain; + } + + *out_attacker_atk = aa; + *out_defender_def = dd; + *out_ignore_terrain = ignore; +} + bool district_is_included_by_final_config (int district_id) { @@ -17739,7 +18007,7 @@ patch_init_floating_point () {"allow_adjacent_resources_of_different_types" , false, offsetof (struct c3x_config, allow_adjacent_resources_of_different_types)}, {"allow_corruption_in_capital" , false, offsetof (struct c3x_config, allow_corruption_in_capital)}, {"allow_sale_of_small_wonders" , false, offsetof (struct c3x_config, allow_sale_of_small_wonders)}, - {"initialize_preplaced_scenario_leaders_as_mgls" , false, offsetof (struct c3x_config, initialize_preplaced_scenario_leaders_as_mgls)}, + {"enable_unit_counters" , false, offsetof (struct c3x_config, enable_unit_counters)}, }; struct integer_config_option { @@ -21629,12 +21897,11 @@ patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, in bool __fastcall patch_Unit_can_hurry_production (Unit * this, int edx, City * city, bool exclude_cheap_improvements) { - if (is->current_config.allow_military_leaders_to_hurry_wonders && - Unit_has_ability (this, __, UTA_Leader) && - this->Body.leader_kind == LK_Military) { + if (is->current_config.allow_military_leaders_to_hurry_wonders && Unit_has_ability (this, __, UTA_Leader)) { + LeaderKind actual_kind = this->Body.leader_kind; this->Body.leader_kind = LK_Scientific; bool tr = Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); - this->Body.leader_kind = LK_Military; + this->Body.leader_kind = actual_kind; return tr; } else return Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); @@ -22621,19 +22888,6 @@ patch_Unit_disembark_passengers (Unit * this, int edx, int tile_x, int tile_y) * target = tile_at (tile_x , tile_y); if (is->current_config.patch_blocked_disembark_freeze && (tile != NULL) && (target != NULL)) { enum SquareTypes target_terrain = target->vtable->m50_Get_Square_BaseType (target); - - bool blocked_by_district = false, blocked_by_district_for_wheeled = false; { - if (is->current_config.enable_districts) { - bool impassible, impassible_to_wheeled; - if (great_wall_blocks_civ (target, this->Body.CivID)) - blocked_by_district = blocked_by_district_for_wheeled = true; - else if (get_tile_district_impassibility (target, &impassible, &impassible_to_wheeled)) { - blocked_by_district = impassible; - blocked_by_district_for_wheeled = impassible || impassible_to_wheeled; - } - } - } - FOR_UNITS_ON (uti, tile) { Unit * escortee = get_unit_ptr (uti.unit->Body.escortee); if ( (escortee != NULL) @@ -22643,10 +22897,7 @@ patch_Unit_disembark_passengers (Unit * this, int edx, int tile_x, int tile_y) || ( is->current_config.disallow_trespassing && check_trespassing (uti.unit->Body.CivID, tile, target) && ! is_allowed_to_trespass (uti.unit)) - || Unit_is_terrain_impassable (uti.unit, __, target_terrain) - || blocked_by_district - || ( blocked_by_district_for_wheeled - && Unit_has_ability (uti.unit, __, UTA_Wheeled)))) + || Unit_is_terrain_impassable (uti.unit, __, target_terrain))) Unit_set_escortee (uti.unit, __, -1); } } @@ -27653,17 +27904,6 @@ patch_Unit_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, bool return tr; } -void __fastcall -patch_Unit_load_into_army_after_move_to_adj_tile (Unit * this, int edx, Unit * loadee) -{ - // Take care not to load an army into itself b/c that will cause the game to crash. The game may attempt to do that at the end of - // move_to_adjacent_tile b/c we return the unit itself as a transport target when we want to allow it to move onto coast. - if (is->coast_walk_transport_override && this == loadee) - return; - - Unit_load_into_army (this, __, loadee); -} - int __fastcall patch_Unit_teleport (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad) { @@ -27782,23 +28022,68 @@ patch_Fighter_damage_by_db_in_main_loop (Fighter * this, int edx, Unit * bombard int __fastcall patch_Fighter_get_odds_for_main_combat_loop (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses) { - // If the attacker was destroyed by defensive bombard, return a number that will ensure the defender wins the first round of combat, otherwise - // the zero HP attacker might go on to win an absurd victory. (The attacker in the overall combat is the defender during DB). if (is->dbe.defender_was_destroyed) return 1025; - else - return Fighter_get_combat_odds (this, __, attacker, defender, bombarding, ignore_defensive_bonuses); + struct c3x_config * cfg = &is->current_config; + if (cfg->enable_unit_counters && attacker != NULL && defender != NULL) { + Tile * def_tile = tile_at (this->defender_location_x, + this->defender_location_y); + int aa, dd; + bool ignore_terrain; + apply_counter_rules (cfg, attacker, defender, def_tile, + &aa, &dd, &ignore_terrain); + + is->counter_combat_ctx.active = true; + is->counter_combat_ctx.attacker = attacker; + is->counter_combat_ctx.defender = defender; + is->counter_combat_ctx.attacker_atk_pct = aa; + is->counter_combat_ctx.defender_def_pct = dd; + is->counter_combat_ctx.ignore_terrain = ignore_terrain; + } + + int result = Fighter_get_combat_odds (this, __, attacker, defender, bombarding, + ignore_defensive_bonuses || is->counter_combat_ctx.ignore_terrain); + is->counter_combat_ctx.active = false; + return result; } +void +apply_counter_rules_unused_placeholder () {} // 占位,已移至正确位置 + byte __fastcall -patch_Fighter_fight (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender_or_null) +patch_Fighter_fight (Fighter * this, int edx, Unit * attacker, + int attack_direction, Unit * defender_or_null) { - byte tr = Fighter_fight (this, __, attacker, attack_direction, defender_or_null); + byte tr = Fighter_fight (this, __, attacker, attack_direction, + defender_or_null); is->dbe = (struct defensive_bombard_event) {0}; + is->counter_combat_ctx.active = false; return tr; } +int __fastcall +patch_Unit_get_attack_strength (Unit * this) +{ + int base = Unit_get_attack_strength (this); + if (! is->counter_combat_ctx.active) + return base; + if (this == is->counter_combat_ctx.attacker) + return base * is->counter_combat_ctx.attacker_atk_pct / 100; + return base; +} + +int __fastcall +patch_Unit_get_defense_strength (Unit * this) +{ + int base = Unit_get_defense_strength (this); + if (! is->counter_combat_ctx.active) + return base; + if (this == is->counter_combat_ctx.defender) + return base * is->counter_combat_ctx.defender_def_pct / 100; + return base; +} + void __fastcall patch_Unit_score_kill_by_defender (Unit * this, int edx, Unit * victim, bool was_attacking) { @@ -28066,29 +28351,6 @@ patch_Unit_can_disembark_anything (Unit * this, int edx, int tile_x, int tile_y) return false; } - // Apply district restrictions on tile entry - if (base && is->current_config.enable_districts) { - if (great_wall_blocks_civ (target_tile, this->Body.CivID)) - return false; - - bool impassible = false, impassible_to_wheeled = false; - if (get_tile_district_impassibility (target_tile, &impassible, &impassible_to_wheeled)) { - if (impassible) - return false; - - if (impassible_to_wheeled) { - bool any_non_wheeled_passengers = false; - FOR_UNITS_ON (uti, this_tile) - if ((uti.unit->Body.Container_Unit == this->Body.ID) && ! Unit_has_ability (uti.unit, __, UTA_Wheeled)) { - any_non_wheeled_passengers = true; - break; - } - if (! any_non_wheeled_passengers) - return false; - } - } - } - // Apply trespassing restriction. First check if this civ may move into (tile_x, tile_y) without trespassing. If it would be trespassing, then // we can only disembark anything if this transport has a passenger that can ignore the restriction. Without this check, the game can enter an // infinite loop under rare circumstances. @@ -29279,13 +29541,6 @@ patch_Map_place_scenario_things (Map * this) Map_place_scenario_things (this); - if (is->current_config.initialize_preplaced_scenario_leaders_as_mgls && p_units->Units != NULL) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if (unit != NULL && Unit_has_ability (unit, __, UTA_Leader) && unit->Body.leader_kind == 0) - unit->Body.leader_kind = LK_Military; - } - // If there are any mills in the config then recompute yields & happiness in all cities. This must be done because we avoid doing this as // mills are added to cities while placing scenario things. if (is->current_config.count_mills > 0) @@ -31818,13 +32073,11 @@ patch_find_nearest_city_for_ai_alliance_eval (int tile_x, int tile_y, int owner_ int __fastcall patch_Unit_get_max_move_points (Unit * this) { - bool is_army = Unit_has_ability (this, __, UTA_Army); - if (is_army && is->current_config.patch_empty_army_movement) { + if (Unit_has_ability (this, __, UTA_Army) && is->current_config.patch_empty_army_movement) { int slowest_member_mp = INT_MAX; bool any_units_in_army = false; FOR_UNITS_ON (uti, tile_at (this->Body.X, this->Body.Y)) { - // Must check 'uni.unit != this' to prevent recursive crash mentioned below - if (uti.unit != this && uti.unit->Body.Container_Unit == this->Body.ID) { + if (uti.unit->Body.Container_Unit == this->Body.ID) { any_units_in_army = true; slowest_member_mp = not_above (Unit_get_max_move_points (uti.unit), slowest_member_mp); } @@ -31833,15 +32086,6 @@ patch_Unit_get_max_move_points (Unit * this) return slowest_member_mp + p_bic_data->General.RoadsMovementRate; else return get_max_move_points (&p_bic_data->UnitTypes[this->Body.UnitTypeID], this->Body.CivID); - - // If the unit is an army and has been set as contained inside itself for a coast walk, the game will crash due to recursive calls computing - // the max MP of each member. In that case, temporarily restore its true container. - } else if (is_army && is->coast_walk_transport_override && this->Body.Container_Unit == this->Body.ID) { - this->Body.Container_Unit = is->coast_walk_prev_container; - int tr = Unit_get_max_move_points (this); - this->Body.Container_Unit = this->Body.ID; - return tr; - } else return Unit_get_max_move_points (this); } @@ -35499,7 +35743,7 @@ try_path_to_friendly_port_district (Unit * unit, bool require_damaged, bool requ continue; } - if (! is_below_stack_limit (tile, unit->Body.CivID, unit->Body.UnitTypeID)) + if (! is_below_stack_limit (tile, unit->Body.CivID, UTC_Sea)) continue; int path_len = 0; @@ -35615,7 +35859,7 @@ patch_Unit_ai_move_naval_missile_transport (Unit * this) if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts || ! is->current_config.naval_units_use_port_districts_not_cities) { - Unit_ai_move_naval_missile_transport (this); + patch_Unit_ai_move_naval_missile_transport (this); return; } @@ -35674,7 +35918,8 @@ patch_Unit_ai_move_air_bombard_unit (Unit * this) int best_base_score = 0x7fffffff; int base_x = -1, base_y = -1; FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, this->Body.UnitTypeID)) + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) continue; int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 6, -1, -1); @@ -35729,7 +35974,8 @@ patch_Unit_ai_move_air_defense_unit (Unit * this) int best_base_score = 0x7fffffff; int base_x = -1, base_y = -1; FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, this->Body.UnitTypeID)) + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) continue; int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 7, -1, -1); @@ -35800,11 +36046,12 @@ patch_Unit_ai_move_air_transport (Unit * this) int best_score = -1; int base_x = -1, base_y = -1; FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, this->Body.UnitTypeID)) + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) continue; int score = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 0, -1, -1) + - count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 1, -1, -1) + 1; + count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 1, -1, -1) + 1; if (count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 9, -1, -1) == 0) score *= 2; int cont_id = aerodrome_tile->vtable->m46_Get_ContinentID (aerodrome_tile); @@ -36258,14 +36505,6 @@ patch_Main_Screen_Form_find_next_unit_for_cycling (Main_Screen_Form * this) } } -void __fastcall -patch_UnitIDList_insert_after_init (UnitIDList * this, int edx, int id, UnitIDItem * item) -{ - // If using non-standard unit cycling, avoid calling this method b/c it sometimes causes a crash - if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) - UnitIDList_insert_after (this, __, id, item); -} - void __fastcall patch_City_m22 (City * this, int edx, bool param_1) { @@ -36431,4 +36670,4 @@ patch_Tile_check_water_for_canal_move_to_adjacent_tile_dest (Tile * this) } // TCC requires a main function be defined even though it's never used. -int main () { return 0; } +int main () { return 0; } \ No newline at end of file From 466a838e1b82e9a4fdc1a025f01bd2a96f5a9750 Mon Sep 17 00:00:00 2001 From: gxia0005 Date: Mon, 27 Apr 2026 14:55:22 +1000 Subject: [PATCH 2/9] Implement use_civ4_style_best_defender --- C3X.h | 4637 +-- default.c3x_config.ini | 2329 +- injected_code.c | 73587 ++++++++++++++++++++------------------- 3 files changed, 40405 insertions(+), 40148 deletions(-) diff --git a/C3X.h b/C3X.h index ed1770dd..d5bbf7f5 100644 --- a/C3X.h +++ b/C3X.h @@ -1,2319 +1,2320 @@ -#include - -#define NOVIRTUALKEYCODES // Keycodes defined in Civ3Conquests.h instead -#include "windows.h" - -typedef unsigned char byte; - -// Use fastcall as substitute for thiscall because TCC doesn't recognize thiscall -#define __fastcall __attribute__((fastcall)) -#include "Civ3Conquests.h" - -#define MOD_VERSION 2600 -#define MOD_PREVIEW_VERSION 0 - -#define COUNT_TILE_HIGHLIGHTS 11 -#define MAX_BUILDING_PREREQS_FOR_UNIT 10 - -#define COUNT_SPECIAL_DISTRICT_TYPES 10 -#define USED_SPECIAL_DISTRICT_TYPES 11 -#define MAX_DYNAMIC_DISTRICT_TYPES 22 -#define COUNT_DISTRICT_TYPES (COUNT_SPECIAL_DISTRICT_TYPES + MAX_DYNAMIC_DISTRICT_TYPES) -#define MAX_WONDER_DISTRICT_TYPES 32 -#define MAX_NATURAL_WONDER_DISTRICT_TYPES 32 -#define MAX_DISTRICT_VARIANT_COUNT 5 -#define MAX_DISTRICT_ERA_COUNT 4 -#define MAX_DISTRICT_COLUMN_COUNT 10 -#define C3X_DISTRICT_COMMAND_BASE (-11000000) - -// Initialize to zero. Implementation is in common.c -struct table { - void * block; - size_t capacity_exponent; // Actual capacity is 1 << capacity_exponent - size_t len; -}; - -// Initialize to zero. Implementation in common.c -struct buffer { - byte * contents; - int length; - int capacity; -}; - -// A mill is a city improvement that spawns a resource. These are read from the "buildings_generating_resources" key in the config but are called -// "mills" internally for brevity. -enum mill_flag { - MF_LOCAL = 1, - MF_NO_TECH_REQ = 2, - MF_YIELDS = 4, - MF_SHOW_BONUS = 8, - MF_HIDE_NON_BONUS = 16 -}; -struct mill { - short improv_id; - short resource_id; - short flags; -}; - -#define ERA_ALIAS_LIST_CAPACITY 4 // Must not exceed 32 so we can store all genders as bits in an int - -// A list of per-era aliases for a civ's noun, adjective, or formal name. -struct civ_era_alias_list { - char * key; - char * aliases[ERA_ALIAS_LIST_CAPACITY]; -}; - -// A list of per-era aliases for a civ's leader's name, including genders and (optionally) titles. -struct leader_era_alias_list { - char * key; - char * aliases[ERA_ALIAS_LIST_CAPACITY]; - int gender_bits; // Gender of each alias. Like LeaderGender in the Race object, 0 for male and 1 for female. - char * titles[ERA_ALIAS_LIST_CAPACITY]; // Title for each alias. May be NULL. -}; - -struct unit_type_limit { - int per_civ; - int per_city; - int cities_per; -}; - -struct work_area_improvement { - short improv_id; - int work_area_radius_limit; - int work_area_radius_bonus; -}; - -enum retreat_rules { - RR_STANDARD = 0, - RR_NONE, - RR_ALL_UNITS, - RR_IF_FASTER, - RR_IF_NOT_SLOWER, - RR_IF_FAST_AND_NOT_SLOWER, -}; - -enum line_drawing_override { - LDO_NEVER = 0, - LDO_WINE, - LDO_ALWAYS -}; - -enum minimap_doubling_mode { - MDM_NEVER = 0, - MDM_HIGH_DEF, - MDM_ALWAYS -}; - -enum unit_cycle_search_criteria { - UCSC_STANDARD = 0, - UCSC_SIMILAR_NEAR_START, - UCSC_SIMILAR_NEAR_DESTINATION -}; - -enum no_ai_patrol_override { - NAPO_ZERO = 0, - NAPO_ONE, - NAPO_NONE -}; - -enum barbarian_activity_override { - BAO_NONE = -2, - - // The values for these levels must match what the game uses internally for Map.World.Final_Barbarians_Activity - BAO_NO_BARBARIANS = -1, - BAO_SEDENTARY = 0, - BAO_ROAMING = 1, - BAO_RESTLESS = 2, - BAO_RAGING = 3, - BAO_RANDOM = 4 -}; - -enum special_defensive_bombard_rules { - SDBR_LETHAL = 1, - SDBR_NOT_INVISIBLE = 2, - SDBR_AERIAL = 4, - SDBR_BLITZ = 8, - SDBR_DOCKED_VS_LAND = 16, -}; - -enum special_zone_of_control_rules { - SZOCR_LETHAL = 1, - SZOCR_AERIAL = 2, - SZOCR_AMPHIBIOUS = 4, - SZOCR_NOT_FROM_INSIDE = 8, -}; - -enum land_transport_rules { - LTR_LOAD_ONTO_BOAT = 1, - LTR_JOIN_ARMY = 2, - LTR_NO_DEFENSE_FROM_INSIDE = 4, - LTR_NO_ESCAPE = 8, -}; - -enum special_helicopter_rules { - SHR_ALLOW_ON_CARRIERS = 1, - SHR_PASSENGER_AIRDROP = 2, - SHR_NO_DEFENSE_FROM_INSIDE = 4, - SHR_NO_ESCAPE = 8, -}; - -enum work_area_limit { - WAL_NONE = 0, - WAL_CULTURAL, - WAL_CULTURAL_MIN_2, - WAL_CULTURAL_OR_ADJACENT -}; - -enum day_night_cycle_mode { - DNCM_OFF = 0, - DNCM_TIMER, - DNCM_USER_TIME, - DNCM_EVERY_TURN, - DNCM_SPECIFIED -}; - -enum distribution_hub_yield_division_mode { - DHYDM_FLAT = 0, - DHYDM_SCALE_BY_CITY_COUNT -}; - -enum ai_distribution_hub_build_strategy { - ADHBS_AUTO = 0, - ADHBS_BY_CITY_COUNT -}; - -enum ai_auto_build_great_wall_strategy { - AAGWS_ALL_BORDERS = 0, - AAGWS_OTHER_CIV_BORDERED_ONLY -}; - -enum perfume_kind { - PK_PRODUCTION = 0, - PK_TECHNOLOGY, - PK_GOVERNMENT, - - COUNT_PERFUME_KINDS -}; - -struct unit_counter_group { - char * name; - int * type_ids; - int count_type_ids; -}; - -// 攻击方/防守方匹配方式 -#define UCM_ANY -1 // * 任意兵种 -#define UCM_GROUP -2 // 用 group_name 字段匹配 - -struct counter_rule { - // 攻击方 - int attacker_match; // UnitTypeID,或 UCM_ANY / UCM_GROUP - char * attacker_group; // attacker_match == UCM_GROUP 时有效 - - // 防守方 - int defender_match; - char * defender_group; - - // 环境条件(-1 / false 表示不限) - int terrain_type; // enum SquareTypes,-1 = 不限 - bool only_in_city; - int district_id; // -1 = 不限 - bool ignore_terrain; // true = 将防守方 Defence 置 0 - - // 效果(百分比,100 = 无变化) - int self_atk_pct; - int self_def_pct; - int enemy_atk_pct; - int enemy_def_pct; -}; - -struct c3x_config { - bool enable_stack_bombard; - bool enable_disorder_warning; - bool allow_stealth_attack_against_single_unit; - bool show_detailed_city_production_info; - int limit_railroad_movement; - bool limited_railroads_work_like_fast_roads; - int limit_units_per_tile[3]; // Limits for land, sea, and air units respectively - bool exclude_cities_from_units_per_tile_limit; - struct table exclude_types_from_units_per_tile_limit; - bool enable_free_buildings_from_small_wonders; - bool enable_stack_unit_commands; - bool skip_repeated_tile_improv_replacement_asks; - bool autofill_best_gold_amount_when_trading; - int minimum_city_separation; - bool disallow_founding_next_to_foreign_city; - bool enable_trade_screen_scroll; - bool group_units_on_right_click_menu; - bool gray_out_units_on_menu_with_no_remaining_moves; - bool put_movement_icons_on_units_on_menu; - bool describe_states_of_units_on_menu; - int anarchy_length_percent; - bool show_golden_age_turns_remaining; - bool show_zoc_attacks_from_mid_stack; - bool show_armies_performing_defensive_bombard; - bool cut_research_spending_to_avoid_bankruptcy; - bool dont_pause_for_love_the_king_messages; - bool reverse_specialist_order_with_shift; - bool toggle_zoom_with_z_on_city_screen; - bool enable_mouse_wheel_zoom; - bool dont_give_king_names_in_non_regicide_games; - bool no_elvis_easter_egg; - bool disable_worker_automation; - bool enable_land_sea_intersections; - bool disallow_trespassing; - bool show_detailed_tile_info; - struct table perfume_specs[COUNT_PERFUME_KINDS]; // Each table maps strings to i31b's. Each i31b combines an amount and whether it's a percent - struct table building_unit_prereqs; // A mapping from int keys to int values. The keys are unit type IDs. If an ID is present as a key in the - // table that means that unit type has one or more prereq buildings. The associated value is either a - // pointer to a list of MAX_BUILDING_PREREQS_FOR_UNITS improvement IDs or a single encoded improv ID. The - // contents of the list are NOT encoded and unused slots store -1. Encoding an ID is done by left-shifting - // it one place then inserting a 1 in the LSB. This way encoded IDs can be told apart from list pointers - // by checking the LSB (1 => encoded improv ID, 0 => list pointer). - struct mill * mills; - int count_mills; - bool warn_about_unrecognized_names; - bool enable_ai_production_ranking; - bool enable_ai_city_location_desirability_display; - bool show_ai_city_location_desirability_if_settler; - bool zero_corruption_when_off; - bool disallow_land_units_from_affecting_water_tiles; - bool dont_end_units_turn_after_airdrop; - bool allow_airdrop_without_airport; - bool enable_negative_pop_pollution; - enum retreat_rules land_retreat_rules; - enum retreat_rules sea_retreat_rules; - bool allow_defensive_retreat_on_water; - struct table limit_defensive_retreat_on_water_to_types; // Table mapping unit type IDs to 1's; used as a hash set - int ai_multi_city_start; - int max_tries_to_place_fp_city; - int * ai_multi_start_extra_palaces; - int count_ai_multi_start_extra_palaces; - int ai_multi_start_extra_palaces_capacity; - bool promote_wonder_decorruption_effect; - bool allow_military_leaders_to_hurry_wonders; - int ai_research_multiplier; - int ai_settler_perfume_on_founding; - int ai_settler_perfume_on_founding_duration; - bool aggressively_penalize_bankruptcy; - bool no_penalty_exception_for_agri_fresh_water_city_tiles; - bool suppress_hypertext_links_exceeded_popup; - bool indicate_non_upgradability_in_pedia; - bool show_message_after_dodging_sam; - bool include_stealth_attack_cancel_option; - bool intercept_recon_missions; - bool charge_one_move_for_recon_and_interception; - bool polish_precision_striking; - bool enable_stealth_attack_via_bombardment; - bool immunize_aircraft_against_bombardment; - bool replay_ai_moves_in_hotseat_games; - struct table ptw_arty_types; // Table mapping unit type IDs to 1's; used as a hash set - struct table can_bombard_only_sea_tiles; // Table mapping unit type IDs to 1's; used as a hash set - bool restore_unit_directions_on_game_load; - bool apply_grid_ini_setting_on_game_load; - bool charm_flag_triggers_ptw_like_targeting; - bool city_icons_show_unit_effects_not_trade; - bool ignore_king_ability_for_defense_priority; - bool show_untradable_techs_on_trade_screen; - bool disallow_useless_bombard_vs_airfields; - enum line_drawing_override draw_lines_using_gdi_plus; - bool compact_luxury_display_on_city_screen; - bool compact_strategic_resource_display_on_city_screen; - bool warn_when_chosen_building_would_replace_another; - bool do_not_unassign_workers_from_polluted_tiles; - bool do_not_make_capital_cities_appear_larger; - bool show_territory_colors_on_water_tiles_in_minimap; - bool convert_some_popups_into_online_mp_messages; - bool enable_debug_mode_switch; - bool accentuate_cities_on_minimap; - enum minimap_doubling_mode double_minimap_size; - bool allow_multipage_civilopedia_descriptions; - enum unit_cycle_search_criteria unit_cycle_search_criteria; - bool reformat_turns_remaining_on_domestic_advisor_screen; - bool enable_city_capture_by_barbarians; - bool share_visibility_in_hotseat; - bool share_wonders_in_hotseat; - bool allow_precision_strikes_against_tile_improvements; - bool dont_end_units_turn_after_bombarding_barricade; - bool remove_land_artillery_target_restrictions; - bool allow_bombard_of_other_improvs_on_occupied_airfield; - bool show_total_city_count; - bool strengthen_forbidden_palace_ocn_effect; - int extra_unit_maintenance_per_shields; - enum special_zone_of_control_rules special_zone_of_control_rules; - enum special_defensive_bombard_rules special_defensive_bombard_rules; - struct civ_era_alias_list * civ_era_alias_lists; - int count_civ_era_alias_lists; - struct leader_era_alias_list * leader_era_alias_lists; - int count_leader_era_alias_lists; - struct table unit_limits; // Maps unit type names (strings) to pointers to limit objects (struct unit_type_limit *) - bool allow_upgrades_in_any_city; - bool do_not_generate_volcanos; - bool do_not_pollute_impassable_tiles; - bool show_hp_of_stealth_attack_options; - bool exclude_invisible_units_from_stealth_attack; - bool exclude_passengers_from_stealth_attack; - bool convert_to_landmark_after_planting_forest; - int chance_for_nukes_to_destroy_max_one_hp_units; - bool allow_sale_of_aqueducts_and_hospitals; - bool no_cross_shore_detection; - int city_work_radius; - bool auto_zoom_city_screen_for_large_work_areas; - enum work_area_limit work_area_limit; - struct work_area_improvement * work_area_improvements; - int count_work_area_improvements; - int rebase_range_multiplier; - bool limit_unit_loading_to_one_transport_per_turn; - bool prevent_old_units_from_upgrading_past_ability_block; - bool introduce_all_human_players_at_start_of_hotseat_game; - bool allow_unload_from_army; - enum land_transport_rules land_transport_rules; - bool allow_adjacent_resources_of_different_types; - bool allow_corruption_in_capital; - int special_capital_decorruption_effect; - int luxury_randomized_appearance_rate_percent; - int tiles_per_non_luxury_resource; - bool no_land_anti_air_from_inside_naval_transport; - enum special_helicopter_rules special_helicopter_rules; - bool prevent_enslaving_by_bombardment; - int years_to_double_building_culture; - int tourism_time_scale_percent; - bool allow_sale_of_small_wonders; - enum no_ai_patrol_override override_no_ai_patrol; - enum barbarian_activity_override override_barbarian_activity_level_for_scenario_maps; - bool enable_unit_counters; - struct unit_counter_group * unit_counter_groups; - int count_unit_counter_groups; - struct counter_rule * counter_rules; - int count_counter_rules; - - bool enable_trade_net_x; - bool optimize_improvement_loops; - bool measure_turn_times; - - bool use_offensive_artillery_ai; - bool dont_escort_unflagged_units; - int ai_build_artillery_ratio; - int ai_artillery_value_damage_percent; - int ai_build_bomber_ratio; - bool replace_leader_unit_ai; - bool fix_ai_army_composition; - bool enable_pop_unit_ai; - bool enable_caravan_unit_ai; - int max_ai_naval_escorts; - int ai_worker_requirement_percent; - - bool remove_unit_limit; - bool remove_city_improvement_limit; - int city_limit; - bool remove_cap_on_turn_limit; - bool remove_era_limit; - - bool patch_submarine_bug; - bool patch_science_age_bug; - bool patch_pedia_texture_bug; - bool patch_blocked_disembark_freeze; - bool patch_houseboat_bug; - bool patch_intercept_lost_turn_bug; - bool patch_phantom_resource_bug; - bool patch_maintenance_persisting_for_obsolete_buildings; - bool patch_barbarian_diagonal_bug; - bool patch_disease_stopping_tech_flag_bug; - bool patch_division_by_zero_in_ai_alliance_eval; - bool patch_empty_army_movement; - bool patch_empty_army_combat_crash; - bool delete_off_map_ai_units; - bool fix_overlapping_specialist_yield_icons; - bool patch_premature_truncation_of_found_paths; - bool patch_zero_production_crash; - bool patch_ai_can_form_army_without_special_ability; - bool patch_ai_can_sacrifice_without_special_ability; - bool patch_crash_in_leader_unit_ai; - bool patch_failure_to_find_new_city_build; - bool patch_passengers_out_of_order_on_menu; - - bool prevent_autorazing; - bool prevent_razing_by_players; - - bool allow_extraterritorial_colonies; - int per_extraterritorial_colony_relation_penalty; - - bool draw_forests_over_roads_and_railroads; - - bool enable_named_tiles; - - char * aircraft_victory_animation; // NULL if set to "none" in config - - int day_night_cycle_mode; - int elapsed_minutes_per_day_night_hour_transition; - int fixed_hours_per_turn_for_day_night_cycle; - int pinned_hour_for_day_night_cycle; - - bool enable_natural_wonders; - bool add_natural_wonders_to_scenarios_if_none; - bool show_natural_wonder_name_on_map; - int minimum_natural_wonder_separation; - - bool enable_districts; - bool enable_neighborhood_districts; - bool enable_wonder_districts; - bool enable_distribution_hub_districts; - bool enable_aerodrome_districts; - bool enable_port_districts; - bool enable_bridge_districts; - bool enable_canal_districts; - bool enable_central_rail_hub_districts; - bool enable_energy_grid_districts; - bool enable_great_wall_districts; - - bool cities_with_mutual_district_receive_buildings; - bool cities_with_mutual_district_receive_wonders; - bool show_message_when_building_received_by_mutual_district; - bool show_message_when_building_lost_to_destroyed_district; - - bool air_units_use_aerodrome_districts_not_cities; - bool naval_units_use_port_districts_not_cities; - - int maximum_pop_before_neighborhood_needed; - int per_neighborhood_pop_growth_enabled; - int neighborhood_needed_message_frequency; - bool destroying_neighborhood_reduces_pop; - - bool completed_wonder_districts_can_be_destroyed; - bool destroyed_wonders_can_be_built_again; - - int distribution_hub_yield_division_mode; - int distribution_hub_food_yield_divisor; - int distribution_hub_shield_yield_divisor; - int ai_distribution_hub_build_strategy; - int ai_ideal_distribution_hub_count_per_100_cities; - int max_distribution_hub_count_per_100_cities; - int central_rail_hub_distribution_food_bonus_percent; - int central_rail_hub_distribution_shield_bonus_percent; - - bool workers_can_enter_coast; - bool expand_water_tile_checks_to_city_work_area; - int max_contiguous_bridge_districts; - int max_contiguous_canal_districts; - int ai_canal_eval_min_bisected_land_tiles; - int ai_bridge_canal_eval_block_size; - int ai_bridge_eval_lake_tile_threshold; - bool ai_can_replace_existing_districts_with_canals; - bool ai_builds_bridges; - bool ai_builds_canals; - - bool ai_defends_districts; - int ai_city_district_max_build_wait_turns; - - bool disable_great_wall_city_defense_bonus; - bool great_wall_districts_impassible_by_others; - bool auto_build_great_wall_around_territory; - char * great_wall_auto_build_wonder_name; - int great_wall_auto_build_wonder_improv_id; - int ai_auto_build_great_wall_strategy; - - bool enable_city_work_radii_highlights; -}; - -enum stackable_command { - SC_BOMBARD = 0, - SC_BOMB, - SC_FORTRESS, - SC_MINE, - SC_IRRIGATE, - SC_CHOP_FOREST, - SC_CHOP_JUNGLE, - SC_PLANT, - SC_CLEAN_POLLUTION, - SC_ROAD, - SC_RAILROAD, - SC_FORTIFY, - SC_UPGRADE, - SC_DISBAND, - COUNT_STACKABLE_COMMANDS -}; - -enum stackable_command_kind { - SCK_BOMBARD = 0, - SCK_TERRAFORM, - SCK_UNIT_MGMT, - COUNT_STACKABLE_COMMAND_KINDS -}; - -struct sc_button_info { - enum Unit_Command_Values command; - enum stackable_command_kind kind; - int tile_sheet_column, - tile_sheet_row; -} const sc_button_infos[COUNT_STACKABLE_COMMANDS] = { - /* Bombard */ { .command = UCV_Bombard , .kind = SCK_BOMBARD , .tile_sheet_column = 3, .tile_sheet_row = 1 }, - /* Bomb */ { .command = UCV_Bombing , .kind = SCK_BOMBARD , .tile_sheet_column = 5, .tile_sheet_row = 4 }, - /* Fortress */ { .command = UCV_Build_Fortress , .kind = SCK_TERRAFORM, .tile_sheet_column = 0, .tile_sheet_row = 3 }, - /* Mine */ { .command = UCV_Build_Mine , .kind = SCK_TERRAFORM, .tile_sheet_column = 1, .tile_sheet_row = 3 }, - /* Irrigate */ { .command = UCV_Irrigate , .kind = SCK_TERRAFORM, .tile_sheet_column = 2, .tile_sheet_row = 3 }, - /* Chop For. */ { .command = UCV_Clear_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 3, .tile_sheet_row = 3 }, - /* Chop Jun. */ { .command = UCV_Clear_Jungle , .kind = SCK_TERRAFORM, .tile_sheet_column = 4, .tile_sheet_row = 3 }, - /* Plant */ { .command = UCV_Plant_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 5, .tile_sheet_row = 3 }, - /* Clean Pol. */ { .command = UCV_Clear_Pollution, .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 3 }, - /* Road */ { .command = UCV_Build_Road , .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 2 }, - /* Railroad */ { .command = UCV_Build_Railroad , .kind = SCK_TERRAFORM, .tile_sheet_column = 7, .tile_sheet_row = 2 }, - /* Fortify */ { .command = UCV_Fortify , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 2, .tile_sheet_row = 0 }, - /* Upgrade */ { .command = UCV_Upgrade_Unit , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 7, .tile_sheet_row = 1 }, - /* Disband */ { .command = UCV_Disband , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 3, .tile_sheet_row = 0 }, -}; - -enum init_state { - IS_UNINITED = 0, - IS_OK, - IS_INIT_FAILED -}; - -enum c3x_label { - CL_NEVER_COMPLETES = 0, - CL_HALTED, - CL_SURPLUS, - CL_SURPLUS_NONE, - CL_SURPLUS_NA, - CL_SB_TOOLTIP, - CL_CHOPPED, - CL_OFF, - CL_MOD_INFO_BUTTON_TEXT, - CL_VERSION, - CL_CONFIG_FILES_LOADED, - CL_CREATING_CITIES, - CL_MCS_FAILED_SANITY_CHECK, - CL_MCS_ADJACENT_CITIES, - CL_MCS_MISSING_CITIES, - CL_OBSOLETED_BY, - CL_NO_STEALTH_ATTACK, - CL_DODGED_SAM, - CL_PREVIEW, - CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP, - CL_TOTAL_CITIES, - - // Offense, Defense, Artillery, etc. - CL_FIRST_UNIT_STRAT, - CL_LAST_UNIT_STRAT = CL_FIRST_UNIT_STRAT + 19, - - // Unit actions for right-click menu - CL_IDLE, - CL_FORTIFIED, - CL_SENTRY, - CL_MINING, - CL_IRRIGATING, - CL_BUILDING_FORTRESS, - CL_BUILDING_ROAD, - CL_BUILDING_RAILROAD, - CL_PLANTING_FOREST, - CL_CLEARING_FOREST, - CL_CLEARING_WETLANDS, - CL_CLEARING_DAMAGE, - CL_BUILDING_AIRFIELD, - CL_BUILDING_RADAR_TOWER, - CL_BUILDING_OUTPOST, - CL_BUILDING_BARRICADE, - CL_BUILDING_COLONY, - CL_INTERCEPTING, - CL_MOVING, - CL_AUTOMATED, - CL_EXPLORING, - CL_BOMBARDING, - - // Generic "Building" phrase for Districts right-click menu - CL_BUILDING, - - // Districts-related texts - CL_REQUIRES, - CL_TO_GROW, - CL_DISTRICT_DESTROYED_BY_VOLCANO, - CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT, - CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD, - - CL_RECEIVED, - CL_FROM_SHARED, - CL_WITH, - - CL_APOSTROPHE_S, - CL_AND, - CL_OTHER_BUILDINGS_HAVE_BEEN, - CL_LOST_DUE_TO_DESTROYED, - - // Districts config mismatch checked on game load - CL_DISTRICT_ID, - CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW, - CL_DISTRICT_NAME_MISMATCH, - CL_SAVE_FILE_HAD, - CL_CURRENT_CONFIG_HAS_ONLY, - CL_WARNING_DISTRICTS_CONFIG_MISMATCH, - CL_MAY_BE_OTHER_ERRORS_AS_WELL, - CL_DISTRICTS_IN_SAVE_FILE, - CL_CURRENTLY_CONFIGURED_DISTRICTS, - - // Tile naming - CL_NAME_TILE, - CL_RENAME_TILE, - - // "Action" for passenger units - CL_TRANSPORTED, - - CL_IN_STATE_27, - CL_IN_STATE_28, - CL_IN_STATE_29, - CL_IN_STATE_30, - CL_IN_STATE_33, - - CL_AGRICULTURAL, - CL_COMMERCIAL, - CL_EXPANSIONIST, - CL_INDUSTRIOUS, - CL_MILITARISTIC, - CL_RELIGIOUS, - CL_SCIENTIFIC, - CL_SEAFARING, - - COUNT_C3X_LABELS -}; - -struct worker_job_and_location { - enum Worker_Jobs job; - int tile_x, tile_y; -}; - -struct ai_prod_valuation { - int order_type; - int order_id; - int point_value; -}; - -enum unit_rcm_icon { - URCMI_UNMOVED = 0, - URCMI_MOVED_CAN_ATTACK, - URCMI_MOVED_NO_ATTACK, - URCMI_CANT_MOVE, - - COUNT_UNIT_RCM_ICONS -}; - -enum unit_rcm_icon_set { - URCMIS_ATTACKER = 0, - URCMIS_NONCOMBAT, - URCMIS_BUSY_ATTACKER, - URCMIS_BUSY_NONCOMBAT, - - COUNT_UNIT_RCM_ICON_SETS -}; - -enum city_gain_reason { - CGR_FOUNDED = 0, - CGR_CONQUERED, - CGR_CONVERTED, // covers culture flips & bribes - CGR_TRADED, - CGR_POPPED_FROM_HUT, - CGR_PLACED_FOR_AI_RESPAWN, - CGR_PLACED_FOR_SCENARIO, - CGR_PLACED_FOR_AI_MULTI_CITY_START, -}; - -enum city_loss_reason { - CLR_DESTROYED = 0, // means city was razed for any reason (inc. by conqueror) - CLR_CONQUERED, - CLR_CONVERTED, // covers culture flips & bribes - CLR_TRADED -}; - -enum { - MAX_DISTRICT_DEPENDENTS = 64 -}; - -enum { - DEFAULT_DISTRICT_BUILDABLE_MASK = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain) | (1 << SQ_Hills) -}; - -enum { - MAX_DISTRICT_BONUS_ENTRIES = 16 -}; - -enum district_bonus_entry_type { - DBET_TILE = 0, - DBET_BUILDING = 1 -}; - -enum great_wall_auto_build_state { - GWABS_NOT_STARTED = 0, - GWABS_RUNNING, - GWABS_DONE -}; - -struct district_bonus_entry { - enum district_bonus_entry_type type; - int bonus; - enum SquareTypes tile_type; - int building_id; - char const * building_name; -}; - -struct district_bonus_list { - int count; - struct district_bonus_entry entries[MAX_DISTRICT_BONUS_ENTRIES]; -}; - -enum district_render_strategy { - DRS_BY_COUNT = 0, - DRS_BY_BUILDING = 1 -}; - -enum district_ai_build_strategy { - DABS_DISTRICT = 0, - DABS_TILE_IMPROVEMENT = 1 -}; - -struct district_config { - enum Unit_Command_Values command; - char const * name; - char const * display_name; - char const * tooltip; - char const * advance_prereqs[MAX_DISTRICT_DEPENDENTS]; - int advance_prereq_count; - char const * obsoleted_by; - char const * resource_prereqs[MAX_DISTRICT_DEPENDENTS]; - char const * resource_prereq_on_tile; - char const * dependent_improvements[MAX_DISTRICT_DEPENDENTS]; - char const * wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; - char const * natural_wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; - char const * buildable_on_districts[MAX_DISTRICT_DEPENDENTS]; - char const * buildable_adjacent_to_districts[MAX_DISTRICT_DEPENDENTS]; - char const * img_paths[10]; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_without_removal_mask; - unsigned int buildable_on_overlays_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - bool allow_multiple; - bool vary_img_by_era; - bool vary_img_by_culture; - enum district_render_strategy render_strategy; - enum district_ai_build_strategy ai_build_strategy; - bool is_dynamic; - bool align_to_coast; - bool draw_over_resources; - bool allow_irrigation_from; - bool auto_add_road; - bool auto_add_railroad; - int custom_width; - int custom_height; - int x_offset; - int y_offset; - int resource_prereq_count; - int dependent_improvement_max_index; - int wonder_prereq_count; - int natural_wonder_prereq_count; - int buildable_on_district_count; - int buildable_adjacent_to_district_count; - int img_path_count; - int img_column_count; - bool has_img_column_count_override; - int btn_tile_sheet_column; - int btn_tile_sheet_row; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - struct district_bonus_list culture_bonus_extras; - struct district_bonus_list science_bonus_extras; - struct district_bonus_list food_bonus_extras; - struct district_bonus_list gold_bonus_extras; - struct district_bonus_list shield_bonus_extras; - struct district_bonus_list happiness_bonus_extras; - struct district_bonus_list defense_bonus_extras; - int defense_bonus_percent; - bool heal_units_in_one_turn; - bool impassible; - bool impassible_to_wheeled; - char const * generated_resource; - int generated_resource_id; - short generated_resource_flags; - int buildable_on_district_ids[MAX_DISTRICT_DEPENDENTS]; - int buildable_on_district_id_count; - bool has_buildable_on_districts; - int buildable_adjacent_to_district_ids[MAX_DISTRICT_DEPENDENTS]; - int buildable_adjacent_to_district_id_count; - bool has_buildable_adjacent_to; - bool has_buildable_adjacent_to_districts; - bool has_buildable_without_removal; - bool has_buildable_on_overlays; - bool has_buildable_adjacent_to_overlays; - bool has_buildable_on_rivers; - char const * buildable_by_civs[32]; - int buildable_by_civ_count; - bool has_buildable_by_civs; - int buildable_by_civ_traits_ids[8]; - int buildable_by_civ_traits_id_count; - bool has_buildable_by_civ_traits; - int buildable_by_civ_govs_ids[5]; - int buildable_by_civ_govs_id_count; - bool has_buildable_by_civ_govs; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_buildable_by_civ_cultures; - bool buildable_by_war_allies; - bool buildable_by_pact_allies; -}; - -struct wonder_district_config { - char const * wonder_name; - char const * img_path; - int index, - img_row, - img_column, - img_construct_row, - img_construct_column, - img_alt_dir_construct_row, - img_alt_dir_construct_column, - img_alt_dir_row, - img_alt_dir_column, - custom_width, - custom_height; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - char const * buildable_by_civs[32]; - int buildable_by_civ_count; - bool has_buildable_by_civs; - int buildable_by_civ_traits_ids[8]; - int buildable_by_civ_traits_id_count; - bool has_buildable_by_civ_traits; - int buildable_by_civ_govs_ids[5]; - int buildable_by_civ_govs_id_count; - bool has_buildable_by_civ_govs; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_buildable_by_civ_cultures; - bool enable_img_alt_dir; - bool is_dynamic; - bool has_buildable_adjacent_to; - bool has_buildable_adjacent_to_overlays; -}; - -enum square_type_extras { - SQ_INVALID = -1, - SQ_RIVER = SQ_Ocean + 1, - SQ_SNOW_VOLCANO, - SQ_SNOW_FOREST, - SQ_SNOW_MOUNTAIN -}; - -enum district_overlay_mask_bits { - DOM_MINE = 1u << 0, - DOM_IRRIGATION = 1u << 1, - DOM_FORTRESS = 1u << 2, - DOM_BARRICADE = 1u << 3, - DOM_OUTPOST = 1u << 4, - DOM_RADAR_TOWER = 1u << 5, - DOM_JUNGLE = 1u << 6, - DOM_FOREST = 1u << 7, - DOM_SWAMP = 1u << 8, - DOM_RIVER = 1u << 9, - DOM_AIRFIELD = 1u << 10 -}; - -struct natural_wonder_district_config { - char const * name; - char const * img_path; - enum SquareTypes terrain_type; - enum SquareTypes adjacent_to; - enum direction adjacency_dir; - int index; - int img_row; - int img_column; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - bool impassible; - bool impassible_to_wheeled; - bool is_dynamic; -}; - -struct natural_wonder_candidate { - Tile * tile; - short x, y; -}; - -struct natural_wonder_candidate_list { - struct natural_wonder_candidate * entries; - int count; - int capacity; -}; - -struct wonder_location { - short x; - short y; -}; - -const struct district_config special_district_defaults[USED_SPECIAL_DISTRICT_TYPES] = { - { - .command = UCV_Build_Neighborhood, .name = "Neighborhood", .tooltip = "Build Neighborhood", .display_name = "Neighborhood", - .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = true, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {"Neighborhood_AMER.pcx", "Neighborhood_EURO.pcx", "Neighborhood_ROMAN.pcx", "Neighborhood_MIDEAST.pcx", "Neighborhood_ASIAN.pcx"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 5, .img_column_count = 4, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, - .culture_bonus = 1, .science_bonus = 1, .food_bonus = 0, .gold_bonus = 1, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 25, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - - }, - { - .command = UCV_Build_WonderDistrict, .name = "Wonder District", .tooltip = "Build Wonder District", .display_name = "Wonder District", - .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {"WonderDistrict.pcx"}, - .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Coast) | (1 << SQ_Mountains)), - .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 1, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - - }, - { - .command = UCV_Build_DistributionHub, .name = "Distribution Hub", .tooltip = "Build Distribution Hub", .display_name = "Distribution Hub", - .advance_prereqs = {"Construction"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {"DistributionHub.pcx"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 2, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - - }, - { - .command = UCV_Build_Aerodrome, .name = "Aerodrome", .tooltip = "Build Aerodrome", .display_name = "Aerodrome", - .advance_prereqs = {"Flight"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 1, - .img_paths = {"Aerodrome.pcx"}, .dependent_improvements = {"Airport"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 1, .img_column_count = 2, .btn_tile_sheet_column = 3, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = -1, .name = "Natural Wonder", .tooltip = NULL, .display_name = "Natural Wonder", - .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {0}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 0, .img_column_count = 0, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_Port, .name = "Port", .tooltip = "Build Port", .display_name = "Port", - .advance_prereqs = {"Map Making"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 2, .align_to_coast = true, - .img_paths = {"Port_NW.pcx", "Port_NE.pcx", "Port_SE.pcx", "Port_SW.pcx"}, .dependent_improvements = {"Harbor", "Commercial Dock"}, - .buildable_square_types_mask = (1 << SQ_Coast), - .img_path_count = 4, .img_column_count = 4, .btn_tile_sheet_column = 4, .btn_tile_sheet_row = 0, .align_to_coast = true, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_CentralRailHub, .name = "Central Rail Hub", .tooltip = "Build Central Rail Hub", .display_name = "Central Rail Hub", - .advance_prereqs = {"Steam Power"}, .advance_prereq_count = 1, .resource_prereqs = {"Iron", "Coal"}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 2, .dependent_improvement_max_index = 0, - .img_paths = {"CentralRailHub_AMER.pcx", "CentralRailHub_EURO.pcx", "CentralRailHub_ROMAN.pcx", "CentralRailHub_MIDEAST.pcx", "CentralRailHub_ASIAN.pcx"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .auto_add_road = true, .auto_add_railroad = true, - .img_path_count = 5, .img_column_count = 2, .btn_tile_sheet_column = 5, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_EnergyGrid, .name = "Energy Grid", .tooltip = "Build Energy Grid", .display_name = "Energy Grid", - .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 4, - .img_paths = {"EnergyGrid.pcx"}, .dependent_improvements = {"Coal Plant", "Hydro Plant", "Nuclear Plant", "Solar Plant"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .custom_height = 84, - .img_path_count = 1, .img_column_count = 5, .btn_tile_sheet_column = 6, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 2, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_Bridge, .name = "Bridge", .tooltip = "Build Bridge", .display_name = "Bridge", - .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, - .img_paths = {"Bridge.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, - .buildable_square_types_mask = (1 << SQ_Coast), .auto_add_road = true, - .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 7, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_Canal, .name = "Canal", .tooltip = "Build Canal", .display_name = "Canal", - .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, - .img_paths = {"Canal.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, - .buildable_square_types_mask = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain), - .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 8, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_GreatWall, .name = "Great Wall", .tooltip = "Build Great Wall", .display_name = "Great Wall", - .advance_prereqs = {0}, .advance_prereq_count = 0, .obsoleted_by = "Metallurgy", .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, - .img_paths = {"GreatWall.pcx"}, .dependent_improvements = {0}, .custom_height = 88, .wonder_prereqs = {"The Great Wall"}, .wonder_prereq_count = 1, - .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Mountains) | (1 << SQ_Forest) | (1 << SQ_Swamp) | (1 << SQ_Jungle) | (1 << SQ_Volcano)), .draw_over_resources = true, - .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 9, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 50, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - } -}; - -struct parsed_district_definition { - char * name; - char * display_name; - char * tooltip; - char * advance_prereqs[5]; - int advance_prereq_count; - char * obsoleted_by; - char * resource_prereqs[5]; - char * resource_prereq_on_tile; - char * dependent_improvements[5]; - char * wonder_prereqs[5]; - char * natural_wonder_prereqs[5]; - char * buildable_on_districts[5]; - char * buildable_adjacent_to_districts[5]; - char * img_paths[5]; - int resource_prereq_count; - int dependent_improvement_max_index; - int wonder_prereq_count; - int natural_wonder_prereq_count; - int buildable_on_district_count; - int buildable_adjacent_to_district_count; - int img_path_count; - int img_column_count; - bool allow_multiple; - bool vary_img_by_era; - bool vary_img_by_culture; - enum district_render_strategy render_strategy; - enum district_ai_build_strategy ai_build_strategy; - bool align_to_coast; - bool draw_over_resources; - bool allow_irrigation_from; - bool auto_add_road; - bool auto_add_railroad; - bool impassible; - bool impassible_to_wheeled; - int custom_width; - int custom_height; - int x_offset; - int y_offset; - int btn_tile_sheet_column; - int btn_tile_sheet_row; - int defense_bonus_percent; - bool heal_units_in_one_turn; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - struct district_bonus_list culture_bonus_extras; - struct district_bonus_list science_bonus_extras; - struct district_bonus_list food_bonus_extras; - struct district_bonus_list gold_bonus_extras; - struct district_bonus_list shield_bonus_extras; - struct district_bonus_list happiness_bonus_extras; - struct district_bonus_list defense_bonus_extras; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_without_removal_mask; - unsigned int buildable_on_overlays_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - char * buildable_by_civs[32]; - int buildable_by_civ_count; - bool buildable_by_war_allies; - bool buildable_by_pact_allies; - bool has_name; - bool has_tooltip; - bool has_advance_prereqs; - bool has_obsoleted_by; - bool has_resource_prereqs; - bool has_dependent_improvements; - bool has_wonder_prereqs; - bool has_natural_wonder_prereqs; - bool has_display_name; - bool has_img_paths; - bool has_img_column_count; - bool has_allow_multiple; - bool has_vary_img_by_era; - bool has_vary_img_by_culture; - bool has_render_strategy; - bool has_ai_build_strategy; - bool has_align_to_coast; - bool has_draw_over_resources; - bool has_custom_width; - bool has_custom_height; - bool has_x_offset; - bool has_y_offset; - bool has_btn_tile_sheet_column; - bool has_btn_tile_sheet_row; - bool has_defense_bonus_percent; - bool has_heal_units_in_one_turn; - bool has_culture_bonus; - bool has_science_bonus; - bool has_food_bonus; - bool has_gold_bonus; - bool has_shield_bonus; - bool has_happiness_bonus; - bool has_buildable_on; - bool has_buildable_adjacent_to; - bool has_buildable_without_removal; - bool has_buildable_on_overlays; - bool has_buildable_adjacent_to_overlays; - bool has_buildable_on_rivers; - bool has_resource_prereq_on_tile; - bool has_buildable_by_civs; - bool has_buildable_by_war_allies; - bool has_buildable_by_pact_allies; - char * generated_resource; - short generated_resource_flags; - bool has_generated_resource; - char * buildable_by_civ_traits[10]; - int buildable_by_civ_traits_count; - int buildable_by_civ_traits_ids[10]; - int buildable_by_civ_traits_id_count; - bool has_buildable_by_civ_traits; - char * buildable_by_civ_govs[10]; - int buildable_by_civ_govs_count; - int buildable_by_civ_govs_ids[32]; - int buildable_by_civ_govs_id_count; - bool has_buildable_by_civ_govs; - char * buildable_by_civ_cultures[5]; - int buildable_by_civ_cultures_count; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_buildable_by_civ_cultures; - bool has_buildable_on_districts; - bool has_buildable_adjacent_to_districts; - bool has_allow_irrigation_from; - bool has_auto_add_road; - bool has_auto_add_railroad; - bool has_impassible; - bool has_impassible_to_wheeled; -}; - -struct parsed_wonder_definition { - char * name; - char * img_path; - int img_row; - int img_column; - int img_construct_row; - int img_construct_column; - int img_alt_dir_construct_row; - int img_alt_dir_construct_column; - int img_alt_dir_row; - int img_alt_dir_column; - int custom_width; - int custom_height; - bool enable_img_alt_dir; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - char * buildable_by_civs[32]; - int buildable_by_civ_count; - char * buildable_by_civ_traits[10]; - int buildable_by_civ_traits_count; - int buildable_by_civ_traits_ids[10]; - int buildable_by_civ_traits_id_count; - char * buildable_by_civ_govs[10]; - int buildable_by_civ_govs_count; - int buildable_by_civ_govs_ids[32]; - int buildable_by_civ_govs_id_count; - char * buildable_by_civ_cultures[5]; - int buildable_by_civ_cultures_count; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_name; - bool has_img_path; - bool has_img_row; - bool has_img_column; - bool has_img_construct_row; - bool has_img_construct_column; - bool has_img_alt_dir_construct_row; - bool has_img_alt_dir_construct_column; - bool has_img_alt_dir_row; - bool has_img_alt_dir_column; - bool has_custom_width; - bool has_custom_height; - bool has_enable_img_alt_dir; - bool has_buildable_on; - bool has_buildable_adjacent_to; - bool has_buildable_adjacent_to_overlays; - bool has_buildable_on_rivers; - bool has_buildable_by_civs; - bool has_buildable_by_civ_traits; - bool has_buildable_by_civ_govs; - bool has_buildable_by_civ_cultures; -}; - -struct parsed_natural_wonder_definition { - char * name; - char * img_path; - enum SquareTypes terrain_type; - enum SquareTypes adjacent_to; - enum direction adjacency_dir; - int img_row; - int img_column; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - bool impassible; - bool impassible_to_wheeled; - bool has_name; - bool has_img_path; - bool has_img_row; - bool has_img_column; - bool has_terrain_type; - bool has_adjacent_to; - bool has_adjacency_dir; - bool has_culture_bonus; - bool has_science_bonus; - bool has_food_bonus; - bool has_gold_bonus; - bool has_shield_bonus; - bool has_happiness_bonus; - bool has_impassible; - bool has_impassible_to_wheeled; -}; - -struct scenario_district_entry { - int tile_x; - int tile_y; - int has_coordinates; - char * district_name; - int has_district_name; - char * wonder_city_name; - int has_wonder_city; - char * wonder_name; - int has_wonder_name; -}; - -struct scenario_named_tile_entry { - int tile_x; - int tile_y; - int has_coordinates; - char * name; - int has_name; -}; - -struct distribution_hub_record { - Tile * tile; - int tile_x; - int tile_y; - int civ_id; - int food_yield; - int shield_yield; - int raw_food_yield; - int raw_shield_yield; -}; - -struct ai_best_feasible_order { - City_Order order; - int value; -}; - -struct district_building_prereq_list { - int count; - int district_ids[MAX_DISTRICT_DEPENDENTS]; -}; - -struct pending_district_request { - City * city; - int city_id; - int civ_id; - int district_id; - int assigned_worker_id; - int target_x; - int target_y; - int worker_assigned_turn; -}; - -struct ai_candidate_bridge_or_canal_entry { - int district_id; - short owner_civ_id; - short * tile_x; - short * tile_y; - short tile_count; - short assigned_tile_index; - int assigned_worker_id; - bool completed; - struct pending_district_request pending_req; - int tile_capacity; -}; - -struct district_worker_record { - Unit * worker; - int unit_id; - int continent_id; - struct pending_district_request * pending_req; -}; - -enum wonder_district_state { - WDS_UNUSED = 0, // Wonder district built, no wonder assigned - WDS_UNDER_CONSTRUCTION, // Reserved by a city for wonder construction - WDS_COMPLETED, // Wonder completed on this district - WDS_RUINED // (Future) Wonder was destroyed -}; - -struct wonder_district_info { - enum wonder_district_state state; - City * city; // City that reserved/completed (NULL if unused) - int city_id; - int wonder_index; // Wonder index (-1 if unused/reserved, valid if completed) -}; - -struct natural_wonder_district_info { - int natural_wonder_id; -}; - -enum district_state { - DS_UNDER_CONSTRUCTION = 0, - DS_COMPLETED = 1 -}; - -struct district_instance { - enum district_state state; - int district_id; // Index into district_configs array - int tile_x; - int tile_y; - int built_by_civ_id; - int completed_turn; - struct wonder_district_info wonder_info; // Only used if district_id is a wonder district - struct natural_wonder_district_info natural_wonder_info; // Only used if district_id is a natural wonder district -}; - -enum extra_resource_tile_type { - ERT_MILL_RESOURCE = 0, - ERT_DISTRICT_RESOURCE -}; - -struct extra_resource_tile { - Tile * tile; - enum extra_resource_tile_type type; - union { - struct { - City * city; - struct mill * mill; - } mill_info; - struct { - struct district_instance * inst; - struct district_config * cfg; - } district_info; - }; -}; - -struct named_tile_entry { - int tile_x; - int tile_y; - char name[100]; -}; - -struct highlighted_city_radius_tile_info { - int highlight_level; -}; - -struct injected_state { - // ========== - // These fields are valid at any time in the injected code because they're set by the patcher { - // ========== - - int mod_version; - // "mod relative directory" is the mod dir relative to the conquests dir. Usually it's "C3X_Rn" but it might be deeper. - // It must be non-empty and must not have an ending backslash. - char mod_rel_dir[MAX_PATH]; - - enum init_state sc_img_state; - enum init_state tile_highlight_state; - enum init_state mod_info_button_images_state; - enum init_state disabled_command_img_state; - enum init_state unit_rcm_icon_state; - enum init_state red_food_icon_state; - enum init_state distribution_hub_icons_img_state; - enum init_state tile_already_worked_zoomed_out_sprite_init_state; - enum init_state day_night_cycle_img_state; - enum init_state large_minimap_frame_img_state; - - // ========== - // } These fields are valid at any time after patch_init_floating_point runs (which is at the program launch). { - // ========== - - struct c3x_config base_config; - - // Windows modules - HMODULE kernel32; - HMODULE user32; - HMODULE msvcrt; - HMODULE msimg32; - - // Win32 API functions - WINBOOL (WINAPI * VirtualProtect) (LPVOID, SIZE_T, DWORD, PDWORD); - WINBOOL (WINAPI * CloseHandle) (HANDLE); - HANDLE (WINAPI * CreateFileA) (LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); - DWORD (WINAPI * GetFileSize) (HANDLE, LPDWORD); - WINBOOL (WINAPI * ReadFile) (HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); - HMODULE (WINAPI * LoadLibraryA) (LPCSTR); - BOOL (WINAPI * FreeLibrary) (HMODULE); - int (WINAPI * MultiByteToWideChar) (UINT, DWORD, LPCCH, int, LPWSTR, int); - int (WINAPI * WideCharToMultiByte) (UINT, DWORD, LPCWCH, int, LPSTR, int, LPCCH, LPBOOL); - int (WINAPI * GetLastError) (); - BOOL (WINAPI * QueryPerformanceCounter) (LARGE_INTEGER *); - BOOL (WINAPI * QueryPerformanceFrequency) (LARGE_INTEGER *); - void (WINAPI * GetLocalTime) (LPSYSTEMTIME); - - // Win32 funcs from user32.dll - int (WINAPI * MessageBoxA) (HWND, LPCSTR, LPCSTR, UINT); - - // Win32 funcs from Msimg32.dll - BOOL (WINAPI * TransparentBlt) (HDC, int, int, int, int, HDC, int, int, int, int, UINT); - - // C standard library functions - int (* snprintf) (char *, size_t, char const *, ...); - void * (* malloc) (size_t); - void * (* calloc) (size_t, size_t); - void * (* realloc) (void *, size_t); - void (* free) (void *); - long (* strtol) (char const *, char **, int); - float (* strtof) (char const *, char **); - int (* strcmp) (char const *, char const *); - int (* strncmp) (char const *, char const *, size_t); - int (* _stricmp) (char const *, char const *); - size_t (* strlen) (char const *); - char * (* strncpy) (char *, char const *, size_t); - char * (* strcpy) (char *, char const *); - char * (* strdup) (char const *); - char * (* strstr) (char const *, char const *); - void (* qsort) (void *, size_t, size_t, int (*) (void const *, void const *)); - int (* memcmp) (void const *, void const *, size_t); - void * (* memcpy) (void *, void const *, size_t); - void * (* memmove) (void *, void const *, size_t); - int (* tolower) (int); - int (* toupper) (int); - - Unit * sb_next_up; // The unit currently doing a stack bombard or NULL otherwise. Gets set to NULL if the unit is despawned. - - Trade_Net * trade_net; // Pointer to the trade net object. If it hasn't been moved by the mod, this equals p_original_trade_net. - int city_limit; // Stores the current actual city limit. Not necessarily the same as the stride of the trade net matrix or the config setting. - - enum init_state trade_net_addrs_load_state; - int * trade_net_addrs; - - HMODULE trade_net_x; - void (__stdcall * set_exe_version) (int); - void * (__stdcall * create_tnx_cache) (Map *); - void (__stdcall * destroy_tnx_cache) (void *); - void (__stdcall * set_up_before_building_network) (void *); - int (__stdcall * get_move_cost_for_sea_trade) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags, int neighbor_index, Trade_Net_Distance_Info * dist_info); - void (__stdcall * flood_fill_road_network) (void * tnx_cache, int from_x, int from_y, int civ_id); - bool (__stdcall * try_drawing_sea_trade_route) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags); - - void * tnx_cache; // Cache object used by Trade Net X. Initially NULL, must be recreated every time a new map is loaded. - enum init_state tnx_init_state; - bool is_computing_city_connections; // Set to true only while Trade_Net::recompute_city_connections is running - bool keep_tnx_cache; - - // This flag gets set whenever a trade deal is signed or broken for a resource that's an input to a mill. It's necessary to call - // recompute_resources in that case since a mill may have been de/activated by the change. We can't call it right when the change happens as - // that can crash the game for reasons I don't completely understand. I believe it's because the recomputation can't be done while some other - // econ logic is running. Instead, we set this variable then recompute before obsolete data would be an issue. Specifically, this is done: - // - When any player or AI begins their production phase - // - When the player zooms to any city - // - When the player opens the shift + right-click production chooser menu - // - When the player visits any advisor - // - When the player selects any unit - bool must_recompute_resources_for_mill_inputs; - - bool is_placing_scenario_things; // Set to true only while Map::place_scenario_things is running - - bool paused_for_popup; // Set to true while a popup, map message, or the diplo screen is open - long long time_spent_paused_during_popup; // Tracks time spent waiting for the three things above - - // This variable is increased with the time elapsed during every call to Trade_Net::recompute_city_connections. Time is measured using - // Windows performance counter. - long long time_spent_computing_city_connections; - int count_calls_to_recompute_city_connections; - - long long time_spent_filling_roads; - - struct c3x_config current_config; - - // Keeps a record of all configs currently loaded. Useful to know. "name" is the file name for configs that come from files, which is all of - // them except for the base config, whose name is "(base)". - struct loaded_config_name { - char * name; - struct loaded_config_name * next; - } * loaded_config_names; - - char current_districts_config_path[MAX_PATH]; - - char mod_script_path[MAX_PATH]; - - char * c3x_labels[COUNT_C3X_LABELS]; - - int have_job_and_loc_to_skip; // 0 or 1 if the variable below has anything actionable in it. Gets cleared to 0 after every turn. - struct worker_job_and_location to_skip; - - struct table saved_code_areas; - - int * unit_menu_duplicates; // NULL initialized, allocated to an array of 0x100 ints when needed - bool named_tile_menu_active; - int named_tile_menu_tile_x; - int named_tile_menu_tile_y; - - // List of temporary ints. Initializes to NULL/0/0, used with functions "memoize" and "clear_memo" - int * memo; - int memo_len; - int memo_capacity; - - // Array mapping cultural neighbor indices to the standard indices that correspond to the same tiles. Generated at program start. - byte * cultural_ni_to_standard; - - // Array mapping standard neighbor indices to the smallest work radius that includes the corresponding tile. Ex., if a given n.i. corresponds - // to one of the adjacent tiles, maps to 1, if it's in the fat cross but not adjacent, maps to 2, and so forth, out into the extended area. - char ni_to_work_radius[256]; - - // The maximum number of tiles workable by cities including the city tile itself (21 under standard game rules). Updated whenever the - // city_work_radius config value gets changed. - int workable_tile_count; - - // The civ ID of the player from whose perspective we're currently showing city loc desirability, or -1 if none. Initialized to -1. - int city_loc_display_perspective; - - // These are all bit fields that run parallel to player bits. Each bit indicates whether or not that name was replaced with an era-specific - // version for that player. This allows us to tell the difference between custom names set by human players and replacements made by the mod. - int aliased_civ_noun_bits; - int aliased_civ_adjective_bits; - int aliased_civ_formal_name_bits; - int aliased_leader_name_bits; - int aliased_leader_title_bits; - - // Stores resource access bits for resources beyond the first 32, used to fix the phantom resource bug. Initialized to NULL/0 and allocated as - // necessary by get_extra_resource_bits. Contains an array of groups of unsigned ints. There is one group per city (allocated lazily so you - // must use the getter) and the number of ints in each group depends on the number of resources defined in the scenario, one for every 32 - // after the first 32. - unsigned * extra_available_resources; - int extra_available_resources_capacity; // In number of cities. - - // These lists store interception events per-player during the interturn so we can clear the interception state on fighters that have done so - // at the beginning of their next turn. The point of this is to imitate the base game behavior where fighters that perform an interception are - // knocked out of the interception state. We can't knock them out immediately b/c that will prevent them from doing multiple interceptions per - // turn, so instead we record the event in these lists and reset their state later. - struct interceptor_reset_list { - struct interception { - int unit_id; - int x, y; - } * items; - int count; - int capacity; - } interceptor_reset_lists[32]; - - // Records the turn number on which each player has most recently founded a city. This is intended to be used for the temp settler perfume - // after founding feature so it may not be set if that feature is not activated or applicable. Defaults to -1. - int turn_no_of_last_founding_for_settler_perfume[32]; - - // Stores the byte offsets into the c3x_config struct of all boolean/integer config options, accessible using the options' names as - // strings. Used when reading in a config INI file. - struct table boolean_config_offsets; - struct table integer_config_offsets; - - // Maps unit types IDs to AI strategy indices (0 = offense, 1 = defense, 2 = artillery, etc.). If a unit type ID is in this table, that means - // it's one of several duplicate types created to spread multiple AI strategies out so each type has only one. - struct table unit_type_alt_strategies; - - // Stores a linked list of unit type duplicates. Maps unit type IDs to the next duplicate ID. Use list_unit_type_duplicates to get the list of - // the duplicates of a particular type as an array. - struct table unit_type_duplicates; - - // Tracks the number of "extra" defensive bombards units have performed, by their IDs. If the "blitz" special defensive bombard rule is - // activated, units with blitz get an extra chance to perform DB for each movement point they have beyond the first. - struct table extra_defensive_bombards; - - // Table mapping unit IDs to how many times that unit has airdropped on the current turn. This is used to prevent units from airdropping - // multiple times. That doesn't matter for the base game but stops the dont-end-turn-after-airdrop setting from letting units airdrop an - // unlimited number of times. - struct table airdrops_this_turn; - - // Stores city improvement bits for improvs beyond the first 256 - struct table extra_city_improvs; - - // These variables store the number of units of each type that each player has - int unit_type_count_init_bits; // Player bits tracking which unit type count tables have been initialized. - struct table unit_type_counts[32]; // One table per player. Each one maps unit type ids (ints) to counts (ints) - - // ========== - // } These fields are valid only after init_stackable_command_buttons has been called. { - // ========== - - struct sc_button_image_set { - Sprite imgs[4]; - } sc_button_image_sets[COUNT_STACKABLE_COMMANDS]; - - int sb_activated_by_button; // Gets set to 1 when the player clicks on the SB button so that perform_action_on_tile knows - // to do stack instead of regular bombard. This is necessary since the SB button actually just activates regular bombard. - // The proper way to implement the SB button would be to give it its own mode action but that's difficult to do because - // the existing mode actions are baked into the code. Implementing it this way I estimate is less fragile and requires - // less patching. The hard part is knowing when to clear this flag so that the player doesn't activate SB, cancel it, then - // activate regular bombard and get SB instead. One trick to make this easier is to look for the change of cursor away - // from the little bomb indicator instead of trying to intercept every relevant UI event. This flag is changed in these - // circumstances: - // (1) At init, the flag is cleared, of course. - // (2) Pressing the SB button sets the flag and pressing another unit command button clears it. - // (3) If handle_cursor_change_in_jgl is called and the main_screen_form's Mode_Action isn't (air) bombard, the flag - // is cleared. That covers every case of switching off SB mode except one, when the player presses a key to switch - // off of SB to regular bombard, that's what case (4) is for. - // (4) The flag is cleared when the player presses the B key or (if the unit is capable of precision strikes) the P key. - // One final complication, that I only discovered after trying to implement this, is that when clicking on the map with a - // mode action, the cursor is cleared before the action is carried out. So we have to intercept that map click as well for - // a total of 4 UI functions patched to make this damn button work. I doubt this is optimal but it works and I've wasted - // enough time on this already. That click interceptor sets a flag value of 2 to indicate this annoying state. - - // ========== - // } This field is only valid after init_disabled_command_buttons has been called and disabled_command_img_state equals IS_OK { - // ========== - - Sprite disabled_build_city_button_img; - - // ========== - // } This field is only valid after init_unit_rcm_icons has been called and unit_rcm_icon_state equals IS_OK { - // ========== - - // Sprites are stored together as sets, so the first COUNT_UNIT_RCM_ICONS elements are those from the first set, then the same number from the - // second set, etc. - Sprite unit_rcm_icons[COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS]; - - // ========== - // } These fields are valid only after init_tile_highlights as been called. { - // ========== - - Sprite tile_highlights[COUNT_TILE_HIGHLIGHTS]; - - // ========== - // } This one is valid only if init_mod_info_button_images has been called and mod_info_button_images_state equals IS_OK { - // ========== - - Sprite mod_info_button_images[3]; - - // ========== - // } This one is valid only if init_red_food_icon has been called and red_food_icon_state equals IS_OK { - // ========== - - Sprite red_food_icon; - - // ========== - // } These are valid only if init_large_minimap_frame has been called and large_minimap_frame_img_state equals IS_OK { - // ========== - - Sprite double_size_box_left_color_pcx, double_size_box_left_alpha_pcx; - - // ========== - // } These fields are temporary/situational { - // ========== - - int saved_road_movement_rate; // Valid when railroad movement limit is applied (limit_railroad_movement > 0) and BIC data has been loaded - int road_mp_cost; // The cost of moving one tile along a road, in MP. Valid after BIC data was loaded. - int railroad_mp_cost_per_move; // The cost of moving one tile along a railroad, in MP, per move available to the unit. This is measured per - // move since the cost of moving along a railroad is scaled by the total number of moves available to the - // unit. Valid after BIC data was loaded. - - int saved_barb_culture_group; // Valid when barb city capturing is enabled and BIC data has been loaded - - Leader * leader_param_for_patch_get_wonder_city_id; // Valid in patch_get_wonder_city_id when called from - // Leader_recompute_auto_improvements - - int show_popup_was_called; // Set to 1 in show_popup. Used in patch_Leader_can_do_worker_job to check if the replacement - // popup was shown. - - // Used to control trade screen scroll - int open_diplo_form_straight_to_trade; // Initialized to 0, gets set to 1 by patch_DiploForm_do_diplomacy to signal - // to patch_DiploForm_m68_Show_Dialog to open the diplo form straight into trade mode. - int trade_screen_scroll_to_id; // Set by patch_DiploForm_m82_handle_key_event to signal to do_diplomacy that the form - // was closed in order to scroll to the civ with the set ID. -1 indicates no scrolling. - Button * trade_scroll_button_left; // initialized to NULL - Button * trade_scroll_button_right; // initialized to NULL - Sprite * trade_scroll_button_images; // inited to NULL, array of 6 images: normal, rollover, and highlight for left & right - enum init_state trade_scroll_button_state; - int eligible_for_trade_scroll; - - char ask_gold_default[32]; - - // Set in patch_ai_choose_production, used by the various bits of injected code that run during the AI production choosing process. - City * ai_considering_production_for_city; - - // This variable stores what improvement or unit the AI is evaluating inside ai_choose_production. It gets set inside two call replacements, - // first inside the loop over improvements then again inside a loop over unit types. The var is used by the intercept consideration functions - // which run at the end of each loop iteration. - City_Order ai_considering_order; - int handling_ai_district_fallback; - - // Used in the code that adds additional info to the tile info box - bool tile_info_open; - int viewing_tile_info_x, viewing_tile_info_y; - - // Used in patch_Tile_m43_Get_field_30_for_city_loc_eval to change how the AI evaluates overlap between cities - int ai_evaling_city_loc_x, ai_evaling_city_loc_y; - int ai_evaling_city_field_30_get_counter; - - // Stores a list of the production options in a given city and the point value the AI would assign to each. The list is populated by - // rank_ai_production_options, items are added by record_improv_val which gets called by some code injected into one of the loops in - // ai_choose_production. These vars are initialized to zero. - struct ai_prod_valuation * ai_prod_valuations; - int count_ai_prod_valuations; - int ai_prod_valuations_capacity; - - // Used for generating resources from buildings and districts - struct extra_resource_tile * resource_tiles; - int count_resource_tiles; - int resource_tiles_capacity; - struct extra_resource_tile * got_resource_tile; - int saved_tile_count; // Stores the actual tile count in case p_bic_data->Map.TileCount was temporarily overwritten. Set to -1 when empty. - byte * mill_input_resource_bits; // Array of bits, one for each resource. Stores whether or not each one is an input to any mill. - - // Used for displaying yields from generated resources on the city screen - int tourism_icon_counter; // Incremented each time a tourism yield icon (normally commerce) is drawn. Reset between improvs. - int convert_displayed_tourism_to_food, convert_displayed_tourism_to_shields; // Number of commerce tourism icons to convert to food, shields - int combined_tourism_and_mill_commerce; // Number of commerce tourism icons to display inc. from mills, maybe negative - - int drawing_icons_for_improv_id; // Stores the improv ID whose icons we're drawing. -1 while not drawing. - - PCX_Image * resources_sheet; // Sprite sheet of resource icons, i.e. resources.pcx - - Sprite tile_already_worked_zoomed_out_sprite; // Valid only if init state is OK - - // Only for use by patch_City_Form_draw_yields_on_worked_tiles and patch_Sprite_draw_already_worked_tile_img - bool do_not_draw_already_worked_tile_img; - - // Stores the trade offer object being modified when the user right-clicks on a gold offer/ask on the trade table. Gets set by a special - // function call replacement (see apply_machine_code_edits for details). - TradeOffer * modifying_gold_trade; - - // Initialized to NULL and reset to NULL after Unit::bombard_tile returns. Gets set just before the call to Unit::play_bombard_fire_animation - // from inside bombard_tile. The value is the unit on the bombarded tile specifically targeted by the attack, if applicable. - Unit * bombard_stealth_target; - - // Set to zero when Unit::select_stealth_attack_target is called then checked inside in the call to PopupSelection::add_item and set to - // 1. This variable lets the add_item replacement function run special code for only the first item added, in order to insert an additional - // first option to cancel the stealth attack. - int added_any_stealth_target; - - // Initialized to zero. Temporarily set to 1 across a call to patch_Unit_select_stealth_attack_target to request that the selected target must - // be suitable for attack via bombardment. - int selecting_stealth_target_for_bombard; - - // Set in rand_int_to_dodge_city_aa and read immediately after in Unit_get_defense_to_dodge_city_aa. Allows us to determine whether the dodge - // roll was successful in order to popup the message. - int result_of_roll_to_dodge_city_aa; - - // Initialized to NULL. If set to non-NULL, the next call to show_map_message will consume that value and use it as the text on the - // message. Used to implement show_map_specific_text. - char const * map_message_text_override; - - // Initialized to NULL. If set to non-NULL, the next call to do_load_game will consume this value and use it as the file path of the game to - // load instead of opening the file picker. - char const * load_file_path_override; - - // A set of player bits indicating which players should see a replay of the AI's moves. Normally all zero, gets filled in by - // patch_perform_interturn_in_main_loop only when/as appropriate. As replays are played (in patch_show_movement_phase_popup), the - // corresponding bits are cleared. - int replay_for_players; - - // Used by patch_perform_interturn_in_main_loop to determine which players need to see the replay. Clear before interturn processing, then - // every time an AI unit moves onto or bombards a tile, any players that have vision on that tile will have their bit set in this var. - int players_saw_ai_unit; - - // Initialized to 0. If set to non-zero, the next call to do_load_game will consume the value and skip the intro popup. - int suppress_intro_after_load_popup; - - struct improv_id_list { - int * items; - int count; - int capacity; - } water_trade_improvs, air_trade_improvs, combat_defense_improvs; - - // Used by the fix for the barbarian diagonal bug - int barb_diag_patch_dy_fix; - - // Initialized to 0. If 1, barbarian activity is force activated b/c there are barb cities on the map that need to do production. - int force_barb_activity_for_cities; - - // Used as a stand-in for an actual tile where needed. In particular, this object is returned from various get_tile and tile_at replacements - // when we need to override the visibility data to implement hotseat shared vis. - Tile * dummy_tile; - - // When the game checks visibility for a tile, it accesses all four visibility fields with separate calls to Map::get_tile and/or tile_at. We - // replace the first call, maybe altering its return to implement shared visibility, cache the return in this variable, then re-use the cached - // value for the next three calls. - Tile * tile_returned_for_visibility_check; - - // Initialized to all -1. If set, the unit with the specified ID will always be the top unit displayed on the specified tile. If the unit is - // not on that tile, there is no effect. This is only intended to be used on a temporary basis. - struct unit_display_override { - int unit_id, tile_x, tile_y; - } unit_display_override; - - // Set in patch_Fighter_get_odds_for_main_combat_loop, read by patch_Unit_get_attack/defense_strength. - // Stores counter multipliers for the current combat. Active only during Fighter_get_combat_odds call. - struct { - bool active; - Unit * attacker; - Unit * defender; - int attacker_atk_pct; // 攻击方攻击力倍率(合并了 self-atk 正向和 enemy-atk 反向) - int defender_def_pct; // 防守方防御力倍率(合并了 enemy-def 正向和 self-def 反向) - bool ignore_terrain; - } counter_combat_ctx; - - // Used to extract which unit (if any) exerted zone of control from within Fighter::apply_zone_of_control. - Unit * zoc_interceptor; - - // Set when Fighter::apply_zone_of_control is called to store the defending unit, used by the injected filter and Unit::move_to_adjacent_tile. - // Cleared at each call to move_to_adjacent_tile and by Unit::despawn. - Unit * zoc_defender; - - // Set to the bombarding unit while Unit::bombard_tile is running. NULL otherwise. - Unit * bombarding_unit; - - // Normally set to NULL. When a unit bombards a tile (the tile itself, not something on it), set to point to that unit during the call to - // Unit::attack_tile. Used to stop the unit from losing all of its movement if configured. - Unit * unit_bombard_attacking_tile; - - // Set to the coords of the tile being attacked while Unit::attack_tile is running, -1 otherwise. - int attacking_tile_x, attacking_tile_y; - - // Cleared to false when Fighter::apply_zone_of_control is called. The interceptor must be unfortified to ensure it plays its animation. If - // that happens, this flag is set so that apply_zone_of_control knows to refortify the unit after the ZoC process is done. - bool refortify_interceptor_after_zoc; - - // These flags are used to turn off lethal ZoC for units that capture an enemy on the tile they're moving into. Without this rule, the unit - // might get killed by ZoC but the captured units will remain on a tile that was never actually entered (that tile might have an enemy city - // for extra weirdness). Here's how it works: - // 1. The moving_unit_to_adjacent_tile flag is set when Unit::move_to_adjacent_tile is called. - // 2. If that flag is set and a unit is captured (detected by intercepting the calls to Leader::spawn_unit inside Unit::do_capture_units) - // then temporarily_disallow_lethal_zoc is set. - // 3. If temporar... is set, the code to filter ZoC interceptors acts as if lethal ZoC were turned off. - // 4. Both flags are cleared when Unit::move_to_adjacent_tile returns. - bool temporarily_disallow_lethal_zoc; - bool moving_unit_to_adjacent_tile; - - // Tracks temporary transport bypass when letting workers step onto coast tiles without a boat - Unit * coast_walk_unit; - bool coast_walk_transport_override; - enum UnitStateType coast_walk_prev_state; - int coast_walk_prev_container; - bool coast_walk_restore_goto_path; - int coast_walk_prev_path_len; - int coast_walk_prev_path_dest_x; - int coast_walk_prev_path_dest_y; - Unit * move_spend_override_unit; - int move_spend_override_value; - - // Used to record info about a defensive bomardment event during Fighter::fight. Gets set by Fighter::damage_by_defensive_bombardment and - // cleared when Fighter::fight returns. - struct defensive_bombard_event { - Unit * bombarder; - Unit * defender; - bool damage_done, defender_was_destroyed, saved_animation_setting; - } dbe; - - // Set to true IFF we're showing a replay of AI moves in hotseat mode - bool showing_hotseat_replay; - - // Set to true only during the first call to get_tile_occupier_id from Trade_Net::get_movement_cost. While this is set, we need to edit unit - // visibility to patch the submarine bug. - bool getting_tile_occupier_for_ai_pathfinding; - - bool running_on_wine; // Set to 1 IFF we're running in Wine, as opposed to actual Windows - - // gdi_plus.init_state is valid any time after patch_init_floating_point. All the other fields are only valid after set_up_gdi_plus has been - // called and gdi_plus.init_state equals IS_OK. - struct gdi_plus { - enum init_state init_state; - HMODULE module; - ULONG_PTR token; - void * gp_graphics; - - int (__stdcall * CreateFromHDC) (HDC hdc, void ** p_gp_graphics); - int (__stdcall * DeleteGraphics) (void * gp_graphics); - int (__stdcall * SetSmoothingMode) (void * graphics, int smoothing_mode); - int (__stdcall * SetPenDashStyle) (void * gp_pen, int dash_style); - int (__stdcall * CreatePen1) (unsigned int argb_color, float width, int gp_unit, void ** p_gp_pen); - int (__stdcall * DeletePen) (void * gp_pen); - int (__stdcall * DrawLineI) (void * gp_graphics, void * gp_pen, int x1, int y1, int x2, int y2); - } gdi_plus; - - // These variables track the states of some OpenGL parameters. They're updated whenever methods like OpenGLRenderer::set_color are called. - unsigned int ogl_color; - int ogl_line_width; - bool ogl_line_stipple_enabled; - - // Records how many units of each type we're going to upgrade to during an upgrade-all. This info will be used to impose the unit type limit - // during the upgrade. Keep in mind units all get upgraded from the same type but might end up as different types after upgrade-all. - struct penciled_in_upgrade { - int unit_type_id; - int count; - } * penciled_in_upgrades; - int penciled_in_upgrade_count; - int penciled_in_upgrade_capacity; - - // While in Leader::do_capture_city, the city in question is stored in this var. Otherwise it's NULL. - City * currently_capturing_city; - - // While a game is being saved or loaded, this variable points to the save file's MappedFile object. Otherwise it's NULL. - MappedFile * accessing_save_file; - - // Used in patch_work_simple_job. If a method sets this variable while that method is running then at the end it sets the given tile as LM. - Tile * lmify_tile_after_working_simple_job; - - // Reset to zero every time City_Form::draw is called. Incremented everything a strategic resource is drawn on the city screen. - int drawn_strat_resource_count; - - int * charmed_types_converted_to_ptw_arty; - int count_charmed_types_converted_to_ptw_arty; - int charmed_types_converted_to_ptw_arty_capacity; - - // While Unit::is_visible_to_civ is running, this var is set to the unit in question. Otherwise it's NULL. - Unit * checking_visibility_for_unit; - - // Normally false. When true, calls to bounce_trespassing_units won't kick out invisible units even if they're revealed. - bool do_not_bounce_invisible_units; - - // Normally false. When true, Unit::despawn also despawns any passenger units inside instead of making exceptions in some cases. - bool always_despawn_passengers; - - // Normally false. When true, calls to Unit::score_kill will not enslave. - bool do_not_enslave_units; - - // If limit_unit_loading_to_one_transport_per_turn is on, maps unit IDs to the ID of the transport unit they're tied to for the current turn. - struct table unit_transport_ties; - - // Initialized to NULL/0, used in patch_City_add_happiness_from_buildings - short * saved_improv_counts; - int saved_improv_counts_capacity; - - // Used to de-overlap specialist yield icons (option name fix_overlapping_specialist_yield_icons) - int specialist_icon_drawing_running_x; - - // Initialized to 0, used to draw multipage descriptions in the Civilopedia - struct civilopedia_multipage_description { - bool drawing_lines; - int line_count; - int shown_page; // zero-based - int last_page; // also zero-based - Civilopedia_Article * article; - Button * effects_btn; - Button * previous_btn; - } cmpd; - - // Day-Night cycle data - int current_day_night_cycle; - bool day_night_cycle_unstarted; // If current_day_night_cycle has not been set, f.e. because it's the first turn of a new game. - bool day_night_cycle_img_proxies_indexed; - LARGE_INTEGER last_day_night_cycle_update_time; - - struct table day_night_sprite_proxy_by_hour[24]; - - struct wonder_district_image_set { - Sprite img; - Sprite construct_img; - Sprite alt_dir_img; - Sprite alt_dir_construct_img; - } wonder_district_img_sets[MAX_WONDER_DISTRICT_TYPES]; - - struct natural_wonder_district_image_set { - Sprite img; - } natural_wonder_img_sets[MAX_NATURAL_WONDER_DISTRICT_TYPES]; - struct natural_wonder_label_draw_info { - int text_left; - int text_top; - int text_width; - int font_size; - char const * text; - }; - - struct day_night_cycle_img_set - { - SpriteList Std_Terrain_Images[9]; - SpriteList LM_Terrain_Images[9]; - Sprite City_Images[80]; - Sprite Destroyed_City_Images[3]; - Sprite Resources[36]; - Sprite ResourcesShadows[36]; - Sprite Terrain_Buldings_Barbarian_Camp; - Sprite Terrain_Buldings_Mines; - Sprite Victory_Image; - Sprite Flood_Plains_Images[16]; - Sprite Fog_Of_War_Images[81]; - Sprite Polar_Icecaps_Images[32]; - Sprite Railroads_Images[272]; - Sprite Roads_Images[256]; - Sprite Minor_Roads_Images[256]; - Sprite Terrain_Buldings_Airfields[2]; - Sprite Terrain_Buldings_Airfields_Shadow[2]; - Sprite Terrain_Buldings_Camp[4]; - Sprite Terrain_Buldings_Fortress[4]; - Sprite Terrain_Buldings_Barricade[4]; - Sprite Goody_Huts_Images[8]; - Sprite Terrain_Buldings_Outposts[3]; - Sprite Terrain_Buldings_Outposts_Shadow[3]; - Sprite Pollution[25]; - Sprite Craters[25]; - Sprite Terrain_Buldings_Radar; - Sprite Terrain_Buldings_Radar_Shadow; - Sprite Tnt_Images[18]; - Sprite Waterfalls_Images[4]; - Sprite LM_Terrain[7]; - Sprite Marsh_Large[8]; - Sprite Marsh_Small[10]; - Sprite Volcanos_Images[16]; - Sprite Volcanos_Forests_Images[16]; - Sprite Volcanos_Jungles_Images[16]; - Sprite Volcanos_Snow_Images[16]; - Sprite Grassland_Forests_Large[8]; - Sprite Plains_Forests_Large[8]; - Sprite Tundra_Forests_Large[8]; - Sprite Grassland_Forests_Small[10]; - Sprite Plains_Forests_Small[10]; - Sprite Tundra_Forests_Small[10]; - Sprite Grassland_Forests_Pines[12]; - Sprite Plains_Forests_Pines[12]; - Sprite Tundra_Forests_Pines[12]; - Sprite Irrigation_Desert_Images[16]; - Sprite Irrigation_Plains_Images[16]; - Sprite Irrigation_Images[16]; - Sprite Irrigation_Tundra_Images[16]; - Sprite Grassland_Jungles_Large[8]; - Sprite Grassland_Jungles_Small[12]; - Sprite Mountains_Images[16]; - Sprite Mountains_Forests_Images[16]; - Sprite Mountains_Jungles_Images[16]; - Sprite Mountains_Snow_Images[16]; - Sprite Hills_Images[16]; - Sprite Hills_Forests_Images[16]; - Sprite Hills_Jungle_Images[16]; - Sprite Delta_Rivers_Images[16]; - Sprite Mountain_Rivers_Images[16]; - Sprite Territory_Images[8]; - Sprite LM_Mountains_Images[16]; - Sprite LM_Forests_Large_Images[8]; - Sprite LM_Forests_Small_Images[10]; - Sprite LM_Forests_Pines_Images[12]; - Sprite LM_Hills_Images[16]; - Sprite District_Images[COUNT_DISTRICT_TYPES][MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [district][variant][era][column] - Sprite Abandoned_District_Image; - Sprite Abandoned_Maritime_District_Image; - struct wonder_district_image_set Wonder_District_Images[MAX_WONDER_DISTRICT_TYPES]; - struct natural_wonder_district_image_set Natural_Wonder_Images[MAX_NATURAL_WONDER_DISTRICT_TYPES]; - } day_night_cycle_imgs[24]; - - // Districts - enum init_state dc_img_state; - enum init_state dc_btn_img_state; - enum init_state dc_icons_img_state; - - struct district_config district_configs[COUNT_DISTRICT_TYPES]; - struct wonder_district_config wonder_district_configs[MAX_WONDER_DISTRICT_TYPES]; - struct natural_wonder_district_config natural_wonder_configs[MAX_NATURAL_WONDER_DISTRICT_TYPES]; - -struct district_image_set { - Sprite imgs[MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [variant][era][column] -} district_img_sets[COUNT_DISTRICT_TYPES]; - Sprite abandoned_district_img; - Sprite abandoned_maritime_district_img; - -struct district_button_image_set { - Sprite imgs[4]; -} district_btn_img_sets[COUNT_DISTRICT_TYPES]; - - // Building ID keys -> district ID. If a building ID is present in the - // table that means that building can only be built if there is a corresponding district is present in the city radius. - struct table district_building_prereqs; - - // Tile pointer IDs -> district_instance pointer. Maps tiles to dynamically allocated - // district_instance structs tracking district type and state (UNDER_CONSTRUCTION or COMPLETED). - // For wonder districts, the wonder_info field tracks wonder-specific state (unused, reserved, completed, ruined), - // which city reserved/completed the wonder, and which wonder index is on this district. - struct table district_tile_map; - struct table named_tile_map; - - // Tracks per-turn airlift usage for aerodrome districts (tile pointer -> civ bitmask). - struct table aerodrome_airlift_usage; - - // Command ID keys -> district ID. Used to identify which district - // a unit command (e.g., build order) corresponds to. - struct table command_id_to_district_id; - - // Array of 32 tables (one per civ) of pending district requests keyed by city & district (values are struct pending_district_request pointers). - struct table city_pending_district_requests[32]; - - // City pointer keys -> improvement ID. Tracks which improvements (buildings/wonders) - // requiring districts a city has ordered to be built (pending district completion). - struct table city_pending_building_orders; - - // AI cache mapping city pointer keys -> AI_Order pointer. Stores the best feasible - // production order for AI cities to optimize decision-making. - struct table ai_best_feasible_orders; - - // String building/wonder name keys -> int building/improvement ID. - // Used to look up building IDs by their text names from the game data. - struct table building_name_to_id; - - struct district_infos { - int advance_prereq_ids[MAX_DISTRICT_DEPENDENTS]; // Tech IDs that enable the district (all required) - int advance_prereq_count; - int obsoleted_by_id; - int resource_prereq_ids[MAX_DISTRICT_DEPENDENTS]; - int resource_prereq_count; - int resource_prereq_on_tile_id; - int wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; - int wonder_prereq_count; - int natural_wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; - int natural_wonder_prereq_count; - int dependent_building_count; - int dependent_building_ids[MAX_DISTRICT_DEPENDENTS]; // Building types the district enables - } district_infos[COUNT_DISTRICT_TYPES]; - - // District tracking counters: total = special (hard-coded) + dynamic (from config/scenario) - // next_custom_dynamic_command_index assigns unique command IDs for custom dynamic commands - int district_count; - int special_district_count; - int dynamic_district_count; - int wonder_district_count; - int natural_wonder_count; - int next_custom_dynamic_command_index; - - // Distribution Hub tracking: records keyed by tile plus per-tile coverage counts; dirty/refresh flags - // control when totals are recalculated - struct table distribution_hub_records; - struct table distribution_hub_coverage_counts; - bool distribution_hub_totals_dirty; - bool distribution_hub_refresh_in_progress; - - // Distribution Hub UI sprites loaded from PCX files for rendering food/shield icons in city interface - // *_icons_remaining counters track how many icons to draw from each source (non-district, district, hub, corruption) - Sprite distribution_hub_shield_icon; - Sprite distribution_hub_corruption_icon; - Sprite distribution_hub_food_icon; - Sprite distribution_hub_eaten_food_icon; - Sprite distribution_hub_shield_icon_small; - Sprite distribution_hub_food_icon_small; - int non_district_shield_icons_remaining; - int corruption_shield_icons_remaining; - int district_shield_icons_remaining; - int distribution_hub_shield_icons_remaining; - int district_corruption_icons_remaining; - int distribution_hub_corruption_icons_remaining; - - // District UI sprites loaded from PCX files for rendering yield icons (science, commerce, shield, food, culture, happiness) - // Available in both regular and small sizes for different UI contexts in city interface - Sprite district_science_icon; - Sprite district_commerce_icon; - Sprite district_shield_icon; - Sprite district_corruption_icon; - Sprite district_food_icon; - Sprite district_food_eaten_icon; - Sprite district_happiness_icon_small; - Sprite district_shield_icon_small; - Sprite district_commerce_icon_small; - Sprite district_food_icon_small; - Sprite district_science_icon_small; - Sprite district_culture_icon_small; - Sprite district_unhappiness_icon_small; - Sprite district_negative_shield_icon_small; - Sprite district_negative_commerce_icon_small; - Sprite district_negative_food_icon_small; - Sprite district_negative_science_icon_small; - Sprite district_negative_culture_icon_small; - - // Guard to prevent recursive sharing when auto-adding buildings across cities - bool sharing_buildings_by_districts_in_progress; - - // Worker tracking: 32 tables (one per civ), each mapping unit_id -> district_worker_record pointer - struct table district_worker_tables[32]; - - // Natural Wonder labels: table mapping natural wonder name strings to their IDs, count of defined natural wonders, - struct table natural_wonder_name_to_id; - - struct ai_candidate_bridge_or_canal_entry * ai_candidate_bridge_or_canals; - int ai_candidate_bridge_or_canals_count; - int ai_candidate_bridge_or_canals_capacity; - bool ai_candidate_bridge_or_canals_initialized; - - // City work radius highlighting: flag to enable/disable, table mapping tile pointers to highlight_level for visual feedback - bool highlight_city_radii; - struct table highlighted_city_radius_tile_pointers; - - // Initialized to 0. Every time Main_Screen_Form::m82_handle_key_event receives an event with is_down == 0, the virtual key code is prepended - // to this list. - int last_main_screen_key_up_events[5]; - - // Stores the parameters to Unit::can_load while it's running, NULL otherwise. - Unit * can_load_transport, * can_load_passenger; - - // Current tile being rendered in Map_Renderer_m19_Draw_Tile_by_XY_and_Flags. For use within various Map_Renderer::impl_m*_Draw_* functions. Nulled out after the render function is complete - Tile * current_render_tile; - struct district_instance * current_render_tile_district; - int current_render_tile_x, current_render_tile_y; - - // Used in patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp and so on for flagging whether to draw forests over roads on the tile being rendered - bool draw_forests_over_roads_on_tile; - - // Set to true once the auto-build process for the Great Wall is complete to avoid running it again - enum great_wall_auto_build_state great_wall_auto_build; - Tile * focused_tile; - - // Stores the improve ID currently being evaluated inside patch_City_can_build_improvement. - int current_evaluating_improve_id; - - // Stores the index in the list of target civs currently being drawn on the espionage form. Used to replace the civ name with its era-specific alias. - int espionage_form_drawing_target_index; - - // Tracks information about the last unit that was selected. These fields are updated when a new unit is selected or when the selected unit - // moves or is destroyed. - struct { - int initial_x, initial_y; // Stores the unit's location when it was selected - int last_x, last_y, type_id; // Stores the unit's current or last available location and type id - Unit * ptr; // A pointer to the unit, may be NULL if the unit was destroyed - } last_selected_unit; - - // Maps unit IDs to the level at which they are waiting. Units with lower levels move first. Units that have not been set to wait are not in the table. - struct table waiting_units; - - // Set to true when waiting_units has been initialized by loading from the save. Causes the game to skip clearing the table when setting up - // unit cycling for the turn. - bool have_loaded_waiting_units; - - // Used in patch_Unit_do_capture_units and patch_Unit_despawn - Unit ** extra_capture_despawns; - int count_extra_capture_despawns; - int extra_capture_despawns_capacity; - - // ========== - // } - // ========== -}; - -enum object_job { - OJ_DEFINE = 0, - OJ_INLEAD, // Patch this function with an inlead - OJ_REPL_VPTR, // Patch this function by replacing a pointer to it. The address column is the addr of the VPTR not the function itself. - OJ_REPL_CALL, // Patch a single function call. The address column is the addr of the call instruction, name refers to the new target function, type is not used. - OJ_REPL_VIS, // Patch a cluster of four function calls that make up a check of tile visibility. See implementation for details. - OJ_EXT_WALUP, // "EXTend Work Area LuP" Patch a jump instruction at the end of a "lup" (loop) over a city's workable area to extend it - OJ_IGNORE -}; - -struct civ_prog_object { - enum object_job job; - int addr; - char const * name; - char const * type; +#include + +#define NOVIRTUALKEYCODES // Keycodes defined in Civ3Conquests.h instead +#include "windows.h" + +typedef unsigned char byte; + +// Use fastcall as substitute for thiscall because TCC doesn't recognize thiscall +#define __fastcall __attribute__((fastcall)) +#include "Civ3Conquests.h" + +#define MOD_VERSION 2700 +#define MOD_PREVIEW_VERSION 0 + +#define COUNT_TILE_HIGHLIGHTS 11 +#define MAX_BUILDING_PREREQS_FOR_UNIT 10 + +#define COUNT_SPECIAL_DISTRICT_TYPES 10 +#define USED_SPECIAL_DISTRICT_TYPES 11 +#define MAX_DYNAMIC_DISTRICT_TYPES 22 +#define COUNT_DISTRICT_TYPES (COUNT_SPECIAL_DISTRICT_TYPES + MAX_DYNAMIC_DISTRICT_TYPES) +#define MAX_WONDER_DISTRICT_TYPES 32 +#define MAX_NATURAL_WONDER_DISTRICT_TYPES 32 +#define MAX_DISTRICT_VARIANT_COUNT 5 +#define MAX_DISTRICT_ERA_COUNT 4 +#define MAX_DISTRICT_COLUMN_COUNT 10 +#define C3X_DISTRICT_COMMAND_BASE (-11000000) + +// Initialize to zero. Implementation is in common.c +struct table { + void * block; + size_t capacity_exponent; // Actual capacity is 1 << capacity_exponent + size_t len; +}; + +// Initialize to zero. Implementation in common.c +struct buffer { + byte * contents; + int length; + int capacity; +}; + +// A mill is a city improvement that spawns a resource. These are read from the "buildings_generating_resources" key in the config but are called +// "mills" internally for brevity. +enum mill_flag { + MF_LOCAL = 1, + MF_NO_TECH_REQ = 2, + MF_YIELDS = 4, + MF_SHOW_BONUS = 8, + MF_HIDE_NON_BONUS = 16 +}; +struct mill { + short improv_id; + short resource_id; + short flags; +}; + +#define ERA_ALIAS_LIST_CAPACITY 4 // Must not exceed 32 so we can store all genders as bits in an int + +// A list of per-era aliases for a civ's noun, adjective, or formal name. +struct civ_era_alias_list { + char * key; + char * aliases[ERA_ALIAS_LIST_CAPACITY]; +}; + +// A list of per-era aliases for a civ's leader's name, including genders and (optionally) titles. +struct leader_era_alias_list { + char * key; + char * aliases[ERA_ALIAS_LIST_CAPACITY]; + int gender_bits; // Gender of each alias. Like LeaderGender in the Race object, 0 for male and 1 for female. + char * titles[ERA_ALIAS_LIST_CAPACITY]; // Title for each alias. May be NULL. +}; + +struct unit_type_limit { + int per_civ; + int per_city; + int cities_per; +}; + +struct work_area_improvement { + short improv_id; + int work_area_radius_limit; + int work_area_radius_bonus; +}; + +enum retreat_rules { + RR_STANDARD = 0, + RR_NONE, + RR_ALL_UNITS, + RR_IF_FASTER, + RR_IF_NOT_SLOWER, + RR_IF_FAST_AND_NOT_SLOWER, +}; + +enum line_drawing_override { + LDO_NEVER = 0, + LDO_WINE, + LDO_ALWAYS +}; + +enum minimap_doubling_mode { + MDM_NEVER = 0, + MDM_HIGH_DEF, + MDM_ALWAYS +}; + +enum unit_cycle_search_criteria { + UCSC_STANDARD = 0, + UCSC_SIMILAR_NEAR_START, + UCSC_SIMILAR_NEAR_DESTINATION +}; + +enum no_ai_patrol_override { + NAPO_ZERO = 0, + NAPO_ONE, + NAPO_NONE +}; + +enum barbarian_activity_override { + BAO_NONE = -2, + + // The values for these levels must match what the game uses internally for Map.World.Final_Barbarians_Activity + BAO_NO_BARBARIANS = -1, + BAO_SEDENTARY = 0, + BAO_ROAMING = 1, + BAO_RESTLESS = 2, + BAO_RAGING = 3, + BAO_RANDOM = 4 +}; + +enum special_defensive_bombard_rules { + SDBR_LETHAL = 1, + SDBR_NOT_INVISIBLE = 2, + SDBR_AERIAL = 4, + SDBR_BLITZ = 8, + SDBR_DOCKED_VS_LAND = 16, +}; + +enum special_zone_of_control_rules { + SZOCR_LETHAL = 1, + SZOCR_AERIAL = 2, + SZOCR_AMPHIBIOUS = 4, + SZOCR_NOT_FROM_INSIDE = 8, +}; + +enum land_transport_rules { + LTR_LOAD_ONTO_BOAT = 1, + LTR_JOIN_ARMY = 2, + LTR_NO_DEFENSE_FROM_INSIDE = 4, + LTR_NO_ESCAPE = 8, +}; + +enum special_helicopter_rules { + SHR_ALLOW_ON_CARRIERS = 1, + SHR_PASSENGER_AIRDROP = 2, + SHR_NO_DEFENSE_FROM_INSIDE = 4, + SHR_NO_ESCAPE = 8, +}; + +enum work_area_limit { + WAL_NONE = 0, + WAL_CULTURAL, + WAL_CULTURAL_MIN_2, + WAL_CULTURAL_OR_ADJACENT +}; + +enum day_night_cycle_mode { + DNCM_OFF = 0, + DNCM_TIMER, + DNCM_USER_TIME, + DNCM_EVERY_TURN, + DNCM_SPECIFIED +}; + +enum distribution_hub_yield_division_mode { + DHYDM_FLAT = 0, + DHYDM_SCALE_BY_CITY_COUNT +}; + +enum ai_distribution_hub_build_strategy { + ADHBS_AUTO = 0, + ADHBS_BY_CITY_COUNT +}; + +enum ai_auto_build_great_wall_strategy { + AAGWS_ALL_BORDERS = 0, + AAGWS_OTHER_CIV_BORDERED_ONLY +}; + +enum perfume_kind { + PK_PRODUCTION = 0, + PK_TECHNOLOGY, + PK_GOVERNMENT, + + COUNT_PERFUME_KINDS +}; + +struct unit_counter_group { + char * name; + int * type_ids; + int count_type_ids; +}; + +// 攻击方/防守方匹配方式 +#define UCM_ANY -1 // * 任意兵种 +#define UCM_GROUP -2 // 用 group_name 字段匹配 + +struct counter_rule { + // 攻击方 + int attacker_match; // UnitTypeID,或 UCM_ANY / UCM_GROUP + char * attacker_group; // attacker_match == UCM_GROUP 时有效 + + // 防守方 + int defender_match; + char * defender_group; + + // 环境条件(-1 / false 表示不限) + int terrain_type; // enum SquareTypes,-1 = 不限 + bool only_in_city; + int district_id; // -1 = 不限 + bool ignore_terrain; // true = 将防守方 Defence 置 0 + + // 效果(百分比,100 = 无变化) + int self_atk_pct; + int self_def_pct; + int enemy_atk_pct; + int enemy_def_pct; +}; + +struct c3x_config { + bool enable_stack_bombard; + bool enable_disorder_warning; + bool allow_stealth_attack_against_single_unit; + bool show_detailed_city_production_info; + int limit_railroad_movement; + bool limited_railroads_work_like_fast_roads; + int limit_units_per_tile[3]; // Limits for land, sea, and air units respectively + bool exclude_cities_from_units_per_tile_limit; + struct table exclude_types_from_units_per_tile_limit; + bool enable_free_buildings_from_small_wonders; + bool enable_stack_unit_commands; + bool skip_repeated_tile_improv_replacement_asks; + bool autofill_best_gold_amount_when_trading; + int minimum_city_separation; + bool disallow_founding_next_to_foreign_city; + bool enable_trade_screen_scroll; + bool group_units_on_right_click_menu; + bool gray_out_units_on_menu_with_no_remaining_moves; + bool put_movement_icons_on_units_on_menu; + bool describe_states_of_units_on_menu; + int anarchy_length_percent; + bool show_golden_age_turns_remaining; + bool show_zoc_attacks_from_mid_stack; + bool show_armies_performing_defensive_bombard; + bool cut_research_spending_to_avoid_bankruptcy; + bool dont_pause_for_love_the_king_messages; + bool reverse_specialist_order_with_shift; + bool toggle_zoom_with_z_on_city_screen; + bool enable_mouse_wheel_zoom; + bool dont_give_king_names_in_non_regicide_games; + bool no_elvis_easter_egg; + bool disable_worker_automation; + bool enable_land_sea_intersections; + bool disallow_trespassing; + bool show_detailed_tile_info; + struct table perfume_specs[COUNT_PERFUME_KINDS]; // Each table maps strings to i31b's. Each i31b combines an amount and whether it's a percent + struct table building_unit_prereqs; // A mapping from int keys to int values. The keys are unit type IDs. If an ID is present as a key in the + // table that means that unit type has one or more prereq buildings. The associated value is either a + // pointer to a list of MAX_BUILDING_PREREQS_FOR_UNITS improvement IDs or a single encoded improv ID. The + // contents of the list are NOT encoded and unused slots store -1. Encoding an ID is done by left-shifting + // it one place then inserting a 1 in the LSB. This way encoded IDs can be told apart from list pointers + // by checking the LSB (1 => encoded improv ID, 0 => list pointer). + struct mill * mills; + int count_mills; + bool warn_about_unrecognized_names; + bool enable_ai_production_ranking; + bool enable_ai_city_location_desirability_display; + bool show_ai_city_location_desirability_if_settler; + bool zero_corruption_when_off; + bool disallow_land_units_from_affecting_water_tiles; + bool dont_end_units_turn_after_airdrop; + bool allow_airdrop_without_airport; + bool enable_negative_pop_pollution; + enum retreat_rules land_retreat_rules; + enum retreat_rules sea_retreat_rules; + bool allow_defensive_retreat_on_water; + struct table limit_defensive_retreat_on_water_to_types; // Table mapping unit type IDs to 1's; used as a hash set + int ai_multi_city_start; + int max_tries_to_place_fp_city; + int * ai_multi_start_extra_palaces; + int count_ai_multi_start_extra_palaces; + int ai_multi_start_extra_palaces_capacity; + bool promote_wonder_decorruption_effect; + bool allow_military_leaders_to_hurry_wonders; + int ai_research_multiplier; + int ai_settler_perfume_on_founding; + int ai_settler_perfume_on_founding_duration; + bool aggressively_penalize_bankruptcy; + bool no_penalty_exception_for_agri_fresh_water_city_tiles; + bool suppress_hypertext_links_exceeded_popup; + bool indicate_non_upgradability_in_pedia; + bool show_message_after_dodging_sam; + bool include_stealth_attack_cancel_option; + bool intercept_recon_missions; + bool charge_one_move_for_recon_and_interception; + bool polish_precision_striking; + bool enable_stealth_attack_via_bombardment; + bool immunize_aircraft_against_bombardment; + bool replay_ai_moves_in_hotseat_games; + struct table ptw_arty_types; // Table mapping unit type IDs to 1's; used as a hash set + struct table can_bombard_only_sea_tiles; // Table mapping unit type IDs to 1's; used as a hash set + bool restore_unit_directions_on_game_load; + bool apply_grid_ini_setting_on_game_load; + bool charm_flag_triggers_ptw_like_targeting; + bool city_icons_show_unit_effects_not_trade; + bool ignore_king_ability_for_defense_priority; + bool show_untradable_techs_on_trade_screen; + bool disallow_useless_bombard_vs_airfields; + enum line_drawing_override draw_lines_using_gdi_plus; + bool compact_luxury_display_on_city_screen; + bool compact_strategic_resource_display_on_city_screen; + bool warn_when_chosen_building_would_replace_another; + bool do_not_unassign_workers_from_polluted_tiles; + bool do_not_make_capital_cities_appear_larger; + bool show_territory_colors_on_water_tiles_in_minimap; + bool convert_some_popups_into_online_mp_messages; + bool enable_debug_mode_switch; + bool accentuate_cities_on_minimap; + enum minimap_doubling_mode double_minimap_size; + bool allow_multipage_civilopedia_descriptions; + enum unit_cycle_search_criteria unit_cycle_search_criteria; + bool reformat_turns_remaining_on_domestic_advisor_screen; + bool enable_city_capture_by_barbarians; + bool share_visibility_in_hotseat; + bool share_wonders_in_hotseat; + bool allow_precision_strikes_against_tile_improvements; + bool dont_end_units_turn_after_bombarding_barricade; + bool remove_land_artillery_target_restrictions; + bool allow_bombard_of_other_improvs_on_occupied_airfield; + bool show_total_city_count; + bool strengthen_forbidden_palace_ocn_effect; + int extra_unit_maintenance_per_shields; + enum special_zone_of_control_rules special_zone_of_control_rules; + enum special_defensive_bombard_rules special_defensive_bombard_rules; + struct civ_era_alias_list * civ_era_alias_lists; + int count_civ_era_alias_lists; + struct leader_era_alias_list * leader_era_alias_lists; + int count_leader_era_alias_lists; + struct table unit_limits; // Maps unit type names (strings) to pointers to limit objects (struct unit_type_limit *) + bool allow_upgrades_in_any_city; + bool do_not_generate_volcanos; + bool do_not_pollute_impassable_tiles; + bool show_hp_of_stealth_attack_options; + bool exclude_invisible_units_from_stealth_attack; + bool exclude_passengers_from_stealth_attack; + bool convert_to_landmark_after_planting_forest; + int chance_for_nukes_to_destroy_max_one_hp_units; + bool allow_sale_of_aqueducts_and_hospitals; + bool no_cross_shore_detection; + int city_work_radius; + bool auto_zoom_city_screen_for_large_work_areas; + enum work_area_limit work_area_limit; + struct work_area_improvement * work_area_improvements; + int count_work_area_improvements; + int rebase_range_multiplier; + bool limit_unit_loading_to_one_transport_per_turn; + bool prevent_old_units_from_upgrading_past_ability_block; + bool introduce_all_human_players_at_start_of_hotseat_game; + bool allow_unload_from_army; + enum land_transport_rules land_transport_rules; + bool allow_adjacent_resources_of_different_types; + bool allow_corruption_in_capital; + int special_capital_decorruption_effect; + int luxury_randomized_appearance_rate_percent; + int tiles_per_non_luxury_resource; + bool no_land_anti_air_from_inside_naval_transport; + enum special_helicopter_rules special_helicopter_rules; + bool prevent_enslaving_by_bombardment; + int years_to_double_building_culture; + int tourism_time_scale_percent; + bool allow_sale_of_small_wonders; + enum no_ai_patrol_override override_no_ai_patrol; + enum barbarian_activity_override override_barbarian_activity_level_for_scenario_maps; + bool enable_unit_counters; + struct unit_counter_group * unit_counter_groups; + int count_unit_counter_groups; + struct counter_rule * counter_rules; + int count_counter_rules; + bool use_civ4_style_best_defender; + + bool enable_trade_net_x; + bool optimize_improvement_loops; + bool measure_turn_times; + + bool use_offensive_artillery_ai; + bool dont_escort_unflagged_units; + int ai_build_artillery_ratio; + int ai_artillery_value_damage_percent; + int ai_build_bomber_ratio; + bool replace_leader_unit_ai; + bool fix_ai_army_composition; + bool enable_pop_unit_ai; + bool enable_caravan_unit_ai; + int max_ai_naval_escorts; + int ai_worker_requirement_percent; + + bool remove_unit_limit; + bool remove_city_improvement_limit; + int city_limit; + bool remove_cap_on_turn_limit; + bool remove_era_limit; + + bool patch_submarine_bug; + bool patch_science_age_bug; + bool patch_pedia_texture_bug; + bool patch_blocked_disembark_freeze; + bool patch_houseboat_bug; + bool patch_intercept_lost_turn_bug; + bool patch_phantom_resource_bug; + bool patch_maintenance_persisting_for_obsolete_buildings; + bool patch_barbarian_diagonal_bug; + bool patch_disease_stopping_tech_flag_bug; + bool patch_division_by_zero_in_ai_alliance_eval; + bool patch_empty_army_movement; + bool patch_empty_army_combat_crash; + bool delete_off_map_ai_units; + bool fix_overlapping_specialist_yield_icons; + bool patch_premature_truncation_of_found_paths; + bool patch_zero_production_crash; + bool patch_ai_can_form_army_without_special_ability; + bool patch_ai_can_sacrifice_without_special_ability; + bool patch_crash_in_leader_unit_ai; + bool patch_failure_to_find_new_city_build; + bool patch_passengers_out_of_order_on_menu; + + bool prevent_autorazing; + bool prevent_razing_by_players; + + bool allow_extraterritorial_colonies; + int per_extraterritorial_colony_relation_penalty; + + bool draw_forests_over_roads_and_railroads; + + bool enable_named_tiles; + + char * aircraft_victory_animation; // NULL if set to "none" in config + + int day_night_cycle_mode; + int elapsed_minutes_per_day_night_hour_transition; + int fixed_hours_per_turn_for_day_night_cycle; + int pinned_hour_for_day_night_cycle; + + bool enable_natural_wonders; + bool add_natural_wonders_to_scenarios_if_none; + bool show_natural_wonder_name_on_map; + int minimum_natural_wonder_separation; + + bool enable_districts; + bool enable_neighborhood_districts; + bool enable_wonder_districts; + bool enable_distribution_hub_districts; + bool enable_aerodrome_districts; + bool enable_port_districts; + bool enable_bridge_districts; + bool enable_canal_districts; + bool enable_central_rail_hub_districts; + bool enable_energy_grid_districts; + bool enable_great_wall_districts; + + bool cities_with_mutual_district_receive_buildings; + bool cities_with_mutual_district_receive_wonders; + bool show_message_when_building_received_by_mutual_district; + bool show_message_when_building_lost_to_destroyed_district; + + bool air_units_use_aerodrome_districts_not_cities; + bool naval_units_use_port_districts_not_cities; + + int maximum_pop_before_neighborhood_needed; + int per_neighborhood_pop_growth_enabled; + int neighborhood_needed_message_frequency; + bool destroying_neighborhood_reduces_pop; + + bool completed_wonder_districts_can_be_destroyed; + bool destroyed_wonders_can_be_built_again; + + int distribution_hub_yield_division_mode; + int distribution_hub_food_yield_divisor; + int distribution_hub_shield_yield_divisor; + int ai_distribution_hub_build_strategy; + int ai_ideal_distribution_hub_count_per_100_cities; + int max_distribution_hub_count_per_100_cities; + int central_rail_hub_distribution_food_bonus_percent; + int central_rail_hub_distribution_shield_bonus_percent; + + bool workers_can_enter_coast; + bool expand_water_tile_checks_to_city_work_area; + int max_contiguous_bridge_districts; + int max_contiguous_canal_districts; + int ai_canal_eval_min_bisected_land_tiles; + int ai_bridge_canal_eval_block_size; + int ai_bridge_eval_lake_tile_threshold; + bool ai_can_replace_existing_districts_with_canals; + bool ai_builds_bridges; + bool ai_builds_canals; + + bool ai_defends_districts; + int ai_city_district_max_build_wait_turns; + + bool disable_great_wall_city_defense_bonus; + bool great_wall_districts_impassible_by_others; + bool auto_build_great_wall_around_territory; + char * great_wall_auto_build_wonder_name; + int great_wall_auto_build_wonder_improv_id; + int ai_auto_build_great_wall_strategy; + + bool enable_city_work_radii_highlights; +}; + +enum stackable_command { + SC_BOMBARD = 0, + SC_BOMB, + SC_FORTRESS, + SC_MINE, + SC_IRRIGATE, + SC_CHOP_FOREST, + SC_CHOP_JUNGLE, + SC_PLANT, + SC_CLEAN_POLLUTION, + SC_ROAD, + SC_RAILROAD, + SC_FORTIFY, + SC_UPGRADE, + SC_DISBAND, + COUNT_STACKABLE_COMMANDS +}; + +enum stackable_command_kind { + SCK_BOMBARD = 0, + SCK_TERRAFORM, + SCK_UNIT_MGMT, + COUNT_STACKABLE_COMMAND_KINDS +}; + +struct sc_button_info { + enum Unit_Command_Values command; + enum stackable_command_kind kind; + int tile_sheet_column, + tile_sheet_row; +} const sc_button_infos[COUNT_STACKABLE_COMMANDS] = { + /* Bombard */ { .command = UCV_Bombard , .kind = SCK_BOMBARD , .tile_sheet_column = 3, .tile_sheet_row = 1 }, + /* Bomb */ { .command = UCV_Bombing , .kind = SCK_BOMBARD , .tile_sheet_column = 5, .tile_sheet_row = 4 }, + /* Fortress */ { .command = UCV_Build_Fortress , .kind = SCK_TERRAFORM, .tile_sheet_column = 0, .tile_sheet_row = 3 }, + /* Mine */ { .command = UCV_Build_Mine , .kind = SCK_TERRAFORM, .tile_sheet_column = 1, .tile_sheet_row = 3 }, + /* Irrigate */ { .command = UCV_Irrigate , .kind = SCK_TERRAFORM, .tile_sheet_column = 2, .tile_sheet_row = 3 }, + /* Chop For. */ { .command = UCV_Clear_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 3, .tile_sheet_row = 3 }, + /* Chop Jun. */ { .command = UCV_Clear_Jungle , .kind = SCK_TERRAFORM, .tile_sheet_column = 4, .tile_sheet_row = 3 }, + /* Plant */ { .command = UCV_Plant_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 5, .tile_sheet_row = 3 }, + /* Clean Pol. */ { .command = UCV_Clear_Pollution, .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 3 }, + /* Road */ { .command = UCV_Build_Road , .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 2 }, + /* Railroad */ { .command = UCV_Build_Railroad , .kind = SCK_TERRAFORM, .tile_sheet_column = 7, .tile_sheet_row = 2 }, + /* Fortify */ { .command = UCV_Fortify , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 2, .tile_sheet_row = 0 }, + /* Upgrade */ { .command = UCV_Upgrade_Unit , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 7, .tile_sheet_row = 1 }, + /* Disband */ { .command = UCV_Disband , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 3, .tile_sheet_row = 0 }, +}; + +enum init_state { + IS_UNINITED = 0, + IS_OK, + IS_INIT_FAILED +}; + +enum c3x_label { + CL_NEVER_COMPLETES = 0, + CL_HALTED, + CL_SURPLUS, + CL_SURPLUS_NONE, + CL_SURPLUS_NA, + CL_SB_TOOLTIP, + CL_CHOPPED, + CL_OFF, + CL_MOD_INFO_BUTTON_TEXT, + CL_VERSION, + CL_CONFIG_FILES_LOADED, + CL_CREATING_CITIES, + CL_MCS_FAILED_SANITY_CHECK, + CL_MCS_ADJACENT_CITIES, + CL_MCS_MISSING_CITIES, + CL_OBSOLETED_BY, + CL_NO_STEALTH_ATTACK, + CL_DODGED_SAM, + CL_PREVIEW, + CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP, + CL_TOTAL_CITIES, + + // Offense, Defense, Artillery, etc. + CL_FIRST_UNIT_STRAT, + CL_LAST_UNIT_STRAT = CL_FIRST_UNIT_STRAT + 19, + + // Unit actions for right-click menu + CL_IDLE, + CL_FORTIFIED, + CL_SENTRY, + CL_MINING, + CL_IRRIGATING, + CL_BUILDING_FORTRESS, + CL_BUILDING_ROAD, + CL_BUILDING_RAILROAD, + CL_PLANTING_FOREST, + CL_CLEARING_FOREST, + CL_CLEARING_WETLANDS, + CL_CLEARING_DAMAGE, + CL_BUILDING_AIRFIELD, + CL_BUILDING_RADAR_TOWER, + CL_BUILDING_OUTPOST, + CL_BUILDING_BARRICADE, + CL_BUILDING_COLONY, + CL_INTERCEPTING, + CL_MOVING, + CL_AUTOMATED, + CL_EXPLORING, + CL_BOMBARDING, + + // Generic "Building" phrase for Districts right-click menu + CL_BUILDING, + + // Districts-related texts + CL_REQUIRES, + CL_TO_GROW, + CL_DISTRICT_DESTROYED_BY_VOLCANO, + CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT, + CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD, + + CL_RECEIVED, + CL_FROM_SHARED, + CL_WITH, + + CL_APOSTROPHE_S, + CL_AND, + CL_OTHER_BUILDINGS_HAVE_BEEN, + CL_LOST_DUE_TO_DESTROYED, + + // Districts config mismatch checked on game load + CL_DISTRICT_ID, + CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW, + CL_DISTRICT_NAME_MISMATCH, + CL_SAVE_FILE_HAD, + CL_CURRENT_CONFIG_HAS_ONLY, + CL_WARNING_DISTRICTS_CONFIG_MISMATCH, + CL_MAY_BE_OTHER_ERRORS_AS_WELL, + CL_DISTRICTS_IN_SAVE_FILE, + CL_CURRENTLY_CONFIGURED_DISTRICTS, + + // Tile naming + CL_NAME_TILE, + CL_RENAME_TILE, + + // "Action" for passenger units + CL_TRANSPORTED, + + CL_IN_STATE_27, + CL_IN_STATE_28, + CL_IN_STATE_29, + CL_IN_STATE_30, + CL_IN_STATE_33, + + CL_AGRICULTURAL, + CL_COMMERCIAL, + CL_EXPANSIONIST, + CL_INDUSTRIOUS, + CL_MILITARISTIC, + CL_RELIGIOUS, + CL_SCIENTIFIC, + CL_SEAFARING, + + COUNT_C3X_LABELS +}; + +struct worker_job_and_location { + enum Worker_Jobs job; + int tile_x, tile_y; +}; + +struct ai_prod_valuation { + int order_type; + int order_id; + int point_value; +}; + +enum unit_rcm_icon { + URCMI_UNMOVED = 0, + URCMI_MOVED_CAN_ATTACK, + URCMI_MOVED_NO_ATTACK, + URCMI_CANT_MOVE, + + COUNT_UNIT_RCM_ICONS +}; + +enum unit_rcm_icon_set { + URCMIS_ATTACKER = 0, + URCMIS_NONCOMBAT, + URCMIS_BUSY_ATTACKER, + URCMIS_BUSY_NONCOMBAT, + + COUNT_UNIT_RCM_ICON_SETS +}; + +enum city_gain_reason { + CGR_FOUNDED = 0, + CGR_CONQUERED, + CGR_CONVERTED, // covers culture flips & bribes + CGR_TRADED, + CGR_POPPED_FROM_HUT, + CGR_PLACED_FOR_AI_RESPAWN, + CGR_PLACED_FOR_SCENARIO, + CGR_PLACED_FOR_AI_MULTI_CITY_START, +}; + +enum city_loss_reason { + CLR_DESTROYED = 0, // means city was razed for any reason (inc. by conqueror) + CLR_CONQUERED, + CLR_CONVERTED, // covers culture flips & bribes + CLR_TRADED +}; + +enum { + MAX_DISTRICT_DEPENDENTS = 64 +}; + +enum { + DEFAULT_DISTRICT_BUILDABLE_MASK = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain) | (1 << SQ_Hills) +}; + +enum { + MAX_DISTRICT_BONUS_ENTRIES = 16 +}; + +enum district_bonus_entry_type { + DBET_TILE = 0, + DBET_BUILDING = 1 +}; + +enum great_wall_auto_build_state { + GWABS_NOT_STARTED = 0, + GWABS_RUNNING, + GWABS_DONE +}; + +struct district_bonus_entry { + enum district_bonus_entry_type type; + int bonus; + enum SquareTypes tile_type; + int building_id; + char const * building_name; +}; + +struct district_bonus_list { + int count; + struct district_bonus_entry entries[MAX_DISTRICT_BONUS_ENTRIES]; +}; + +enum district_render_strategy { + DRS_BY_COUNT = 0, + DRS_BY_BUILDING = 1 +}; + +enum district_ai_build_strategy { + DABS_DISTRICT = 0, + DABS_TILE_IMPROVEMENT = 1 +}; + +struct district_config { + enum Unit_Command_Values command; + char const * name; + char const * display_name; + char const * tooltip; + char const * advance_prereqs[MAX_DISTRICT_DEPENDENTS]; + int advance_prereq_count; + char const * obsoleted_by; + char const * resource_prereqs[MAX_DISTRICT_DEPENDENTS]; + char const * resource_prereq_on_tile; + char const * dependent_improvements[MAX_DISTRICT_DEPENDENTS]; + char const * wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; + char const * natural_wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; + char const * buildable_on_districts[MAX_DISTRICT_DEPENDENTS]; + char const * buildable_adjacent_to_districts[MAX_DISTRICT_DEPENDENTS]; + char const * img_paths[10]; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_without_removal_mask; + unsigned int buildable_on_overlays_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + bool allow_multiple; + bool vary_img_by_era; + bool vary_img_by_culture; + enum district_render_strategy render_strategy; + enum district_ai_build_strategy ai_build_strategy; + bool is_dynamic; + bool align_to_coast; + bool draw_over_resources; + bool allow_irrigation_from; + bool auto_add_road; + bool auto_add_railroad; + int custom_width; + int custom_height; + int x_offset; + int y_offset; + int resource_prereq_count; + int dependent_improvement_max_index; + int wonder_prereq_count; + int natural_wonder_prereq_count; + int buildable_on_district_count; + int buildable_adjacent_to_district_count; + int img_path_count; + int img_column_count; + bool has_img_column_count_override; + int btn_tile_sheet_column; + int btn_tile_sheet_row; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + struct district_bonus_list culture_bonus_extras; + struct district_bonus_list science_bonus_extras; + struct district_bonus_list food_bonus_extras; + struct district_bonus_list gold_bonus_extras; + struct district_bonus_list shield_bonus_extras; + struct district_bonus_list happiness_bonus_extras; + struct district_bonus_list defense_bonus_extras; + int defense_bonus_percent; + bool heal_units_in_one_turn; + bool impassible; + bool impassible_to_wheeled; + char const * generated_resource; + int generated_resource_id; + short generated_resource_flags; + int buildable_on_district_ids[MAX_DISTRICT_DEPENDENTS]; + int buildable_on_district_id_count; + bool has_buildable_on_districts; + int buildable_adjacent_to_district_ids[MAX_DISTRICT_DEPENDENTS]; + int buildable_adjacent_to_district_id_count; + bool has_buildable_adjacent_to; + bool has_buildable_adjacent_to_districts; + bool has_buildable_without_removal; + bool has_buildable_on_overlays; + bool has_buildable_adjacent_to_overlays; + bool has_buildable_on_rivers; + char const * buildable_by_civs[32]; + int buildable_by_civ_count; + bool has_buildable_by_civs; + int buildable_by_civ_traits_ids[8]; + int buildable_by_civ_traits_id_count; + bool has_buildable_by_civ_traits; + int buildable_by_civ_govs_ids[5]; + int buildable_by_civ_govs_id_count; + bool has_buildable_by_civ_govs; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_buildable_by_civ_cultures; + bool buildable_by_war_allies; + bool buildable_by_pact_allies; +}; + +struct wonder_district_config { + char const * wonder_name; + char const * img_path; + int index, + img_row, + img_column, + img_construct_row, + img_construct_column, + img_alt_dir_construct_row, + img_alt_dir_construct_column, + img_alt_dir_row, + img_alt_dir_column, + custom_width, + custom_height; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + char const * buildable_by_civs[32]; + int buildable_by_civ_count; + bool has_buildable_by_civs; + int buildable_by_civ_traits_ids[8]; + int buildable_by_civ_traits_id_count; + bool has_buildable_by_civ_traits; + int buildable_by_civ_govs_ids[5]; + int buildable_by_civ_govs_id_count; + bool has_buildable_by_civ_govs; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_buildable_by_civ_cultures; + bool enable_img_alt_dir; + bool is_dynamic; + bool has_buildable_adjacent_to; + bool has_buildable_adjacent_to_overlays; +}; + +enum square_type_extras { + SQ_INVALID = -1, + SQ_RIVER = SQ_Ocean + 1, + SQ_SNOW_VOLCANO, + SQ_SNOW_FOREST, + SQ_SNOW_MOUNTAIN +}; + +enum district_overlay_mask_bits { + DOM_MINE = 1u << 0, + DOM_IRRIGATION = 1u << 1, + DOM_FORTRESS = 1u << 2, + DOM_BARRICADE = 1u << 3, + DOM_OUTPOST = 1u << 4, + DOM_RADAR_TOWER = 1u << 5, + DOM_JUNGLE = 1u << 6, + DOM_FOREST = 1u << 7, + DOM_SWAMP = 1u << 8, + DOM_RIVER = 1u << 9, + DOM_AIRFIELD = 1u << 10 +}; + +struct natural_wonder_district_config { + char const * name; + char const * img_path; + enum SquareTypes terrain_type; + enum SquareTypes adjacent_to; + enum direction adjacency_dir; + int index; + int img_row; + int img_column; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + bool impassible; + bool impassible_to_wheeled; + bool is_dynamic; +}; + +struct natural_wonder_candidate { + Tile * tile; + short x, y; +}; + +struct natural_wonder_candidate_list { + struct natural_wonder_candidate * entries; + int count; + int capacity; +}; + +struct wonder_location { + short x; + short y; +}; + +const struct district_config special_district_defaults[USED_SPECIAL_DISTRICT_TYPES] = { + { + .command = UCV_Build_Neighborhood, .name = "Neighborhood", .tooltip = "Build Neighborhood", .display_name = "Neighborhood", + .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = true, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {"Neighborhood_AMER.pcx", "Neighborhood_EURO.pcx", "Neighborhood_ROMAN.pcx", "Neighborhood_MIDEAST.pcx", "Neighborhood_ASIAN.pcx"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 5, .img_column_count = 4, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, + .culture_bonus = 1, .science_bonus = 1, .food_bonus = 0, .gold_bonus = 1, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 25, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + + }, + { + .command = UCV_Build_WonderDistrict, .name = "Wonder District", .tooltip = "Build Wonder District", .display_name = "Wonder District", + .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {"WonderDistrict.pcx"}, + .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Coast) | (1 << SQ_Mountains)), + .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 1, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + + }, + { + .command = UCV_Build_DistributionHub, .name = "Distribution Hub", .tooltip = "Build Distribution Hub", .display_name = "Distribution Hub", + .advance_prereqs = {"Construction"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {"DistributionHub.pcx"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 2, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + + }, + { + .command = UCV_Build_Aerodrome, .name = "Aerodrome", .tooltip = "Build Aerodrome", .display_name = "Aerodrome", + .advance_prereqs = {"Flight"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 1, + .img_paths = {"Aerodrome.pcx"}, .dependent_improvements = {"Airport"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 1, .img_column_count = 2, .btn_tile_sheet_column = 3, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = -1, .name = "Natural Wonder", .tooltip = NULL, .display_name = "Natural Wonder", + .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {0}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 0, .img_column_count = 0, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_Port, .name = "Port", .tooltip = "Build Port", .display_name = "Port", + .advance_prereqs = {"Map Making"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 2, .align_to_coast = true, + .img_paths = {"Port_NW.pcx", "Port_NE.pcx", "Port_SE.pcx", "Port_SW.pcx"}, .dependent_improvements = {"Harbor", "Commercial Dock"}, + .buildable_square_types_mask = (1 << SQ_Coast), + .img_path_count = 4, .img_column_count = 4, .btn_tile_sheet_column = 4, .btn_tile_sheet_row = 0, .align_to_coast = true, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_CentralRailHub, .name = "Central Rail Hub", .tooltip = "Build Central Rail Hub", .display_name = "Central Rail Hub", + .advance_prereqs = {"Steam Power"}, .advance_prereq_count = 1, .resource_prereqs = {"Iron", "Coal"}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 2, .dependent_improvement_max_index = 0, + .img_paths = {"CentralRailHub_AMER.pcx", "CentralRailHub_EURO.pcx", "CentralRailHub_ROMAN.pcx", "CentralRailHub_MIDEAST.pcx", "CentralRailHub_ASIAN.pcx"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .auto_add_road = true, .auto_add_railroad = true, + .img_path_count = 5, .img_column_count = 2, .btn_tile_sheet_column = 5, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_EnergyGrid, .name = "Energy Grid", .tooltip = "Build Energy Grid", .display_name = "Energy Grid", + .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 4, + .img_paths = {"EnergyGrid.pcx"}, .dependent_improvements = {"Coal Plant", "Hydro Plant", "Nuclear Plant", "Solar Plant"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .custom_height = 84, + .img_path_count = 1, .img_column_count = 5, .btn_tile_sheet_column = 6, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 2, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_Bridge, .name = "Bridge", .tooltip = "Build Bridge", .display_name = "Bridge", + .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, + .img_paths = {"Bridge.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, + .buildable_square_types_mask = (1 << SQ_Coast), .auto_add_road = true, + .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 7, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_Canal, .name = "Canal", .tooltip = "Build Canal", .display_name = "Canal", + .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, + .img_paths = {"Canal.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, + .buildable_square_types_mask = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain), + .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 8, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_GreatWall, .name = "Great Wall", .tooltip = "Build Great Wall", .display_name = "Great Wall", + .advance_prereqs = {0}, .advance_prereq_count = 0, .obsoleted_by = "Metallurgy", .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, + .img_paths = {"GreatWall.pcx"}, .dependent_improvements = {0}, .custom_height = 88, .wonder_prereqs = {"The Great Wall"}, .wonder_prereq_count = 1, + .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Mountains) | (1 << SQ_Forest) | (1 << SQ_Swamp) | (1 << SQ_Jungle) | (1 << SQ_Volcano)), .draw_over_resources = true, + .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 9, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 50, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + } +}; + +struct parsed_district_definition { + char * name; + char * display_name; + char * tooltip; + char * advance_prereqs[5]; + int advance_prereq_count; + char * obsoleted_by; + char * resource_prereqs[5]; + char * resource_prereq_on_tile; + char * dependent_improvements[5]; + char * wonder_prereqs[5]; + char * natural_wonder_prereqs[5]; + char * buildable_on_districts[5]; + char * buildable_adjacent_to_districts[5]; + char * img_paths[5]; + int resource_prereq_count; + int dependent_improvement_max_index; + int wonder_prereq_count; + int natural_wonder_prereq_count; + int buildable_on_district_count; + int buildable_adjacent_to_district_count; + int img_path_count; + int img_column_count; + bool allow_multiple; + bool vary_img_by_era; + bool vary_img_by_culture; + enum district_render_strategy render_strategy; + enum district_ai_build_strategy ai_build_strategy; + bool align_to_coast; + bool draw_over_resources; + bool allow_irrigation_from; + bool auto_add_road; + bool auto_add_railroad; + bool impassible; + bool impassible_to_wheeled; + int custom_width; + int custom_height; + int x_offset; + int y_offset; + int btn_tile_sheet_column; + int btn_tile_sheet_row; + int defense_bonus_percent; + bool heal_units_in_one_turn; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + struct district_bonus_list culture_bonus_extras; + struct district_bonus_list science_bonus_extras; + struct district_bonus_list food_bonus_extras; + struct district_bonus_list gold_bonus_extras; + struct district_bonus_list shield_bonus_extras; + struct district_bonus_list happiness_bonus_extras; + struct district_bonus_list defense_bonus_extras; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_without_removal_mask; + unsigned int buildable_on_overlays_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + char * buildable_by_civs[32]; + int buildable_by_civ_count; + bool buildable_by_war_allies; + bool buildable_by_pact_allies; + bool has_name; + bool has_tooltip; + bool has_advance_prereqs; + bool has_obsoleted_by; + bool has_resource_prereqs; + bool has_dependent_improvements; + bool has_wonder_prereqs; + bool has_natural_wonder_prereqs; + bool has_display_name; + bool has_img_paths; + bool has_img_column_count; + bool has_allow_multiple; + bool has_vary_img_by_era; + bool has_vary_img_by_culture; + bool has_render_strategy; + bool has_ai_build_strategy; + bool has_align_to_coast; + bool has_draw_over_resources; + bool has_custom_width; + bool has_custom_height; + bool has_x_offset; + bool has_y_offset; + bool has_btn_tile_sheet_column; + bool has_btn_tile_sheet_row; + bool has_defense_bonus_percent; + bool has_heal_units_in_one_turn; + bool has_culture_bonus; + bool has_science_bonus; + bool has_food_bonus; + bool has_gold_bonus; + bool has_shield_bonus; + bool has_happiness_bonus; + bool has_buildable_on; + bool has_buildable_adjacent_to; + bool has_buildable_without_removal; + bool has_buildable_on_overlays; + bool has_buildable_adjacent_to_overlays; + bool has_buildable_on_rivers; + bool has_resource_prereq_on_tile; + bool has_buildable_by_civs; + bool has_buildable_by_war_allies; + bool has_buildable_by_pact_allies; + char * generated_resource; + short generated_resource_flags; + bool has_generated_resource; + char * buildable_by_civ_traits[10]; + int buildable_by_civ_traits_count; + int buildable_by_civ_traits_ids[10]; + int buildable_by_civ_traits_id_count; + bool has_buildable_by_civ_traits; + char * buildable_by_civ_govs[10]; + int buildable_by_civ_govs_count; + int buildable_by_civ_govs_ids[32]; + int buildable_by_civ_govs_id_count; + bool has_buildable_by_civ_govs; + char * buildable_by_civ_cultures[5]; + int buildable_by_civ_cultures_count; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_buildable_by_civ_cultures; + bool has_buildable_on_districts; + bool has_buildable_adjacent_to_districts; + bool has_allow_irrigation_from; + bool has_auto_add_road; + bool has_auto_add_railroad; + bool has_impassible; + bool has_impassible_to_wheeled; +}; + +struct parsed_wonder_definition { + char * name; + char * img_path; + int img_row; + int img_column; + int img_construct_row; + int img_construct_column; + int img_alt_dir_construct_row; + int img_alt_dir_construct_column; + int img_alt_dir_row; + int img_alt_dir_column; + int custom_width; + int custom_height; + bool enable_img_alt_dir; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + char * buildable_by_civs[32]; + int buildable_by_civ_count; + char * buildable_by_civ_traits[10]; + int buildable_by_civ_traits_count; + int buildable_by_civ_traits_ids[10]; + int buildable_by_civ_traits_id_count; + char * buildable_by_civ_govs[10]; + int buildable_by_civ_govs_count; + int buildable_by_civ_govs_ids[32]; + int buildable_by_civ_govs_id_count; + char * buildable_by_civ_cultures[5]; + int buildable_by_civ_cultures_count; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_name; + bool has_img_path; + bool has_img_row; + bool has_img_column; + bool has_img_construct_row; + bool has_img_construct_column; + bool has_img_alt_dir_construct_row; + bool has_img_alt_dir_construct_column; + bool has_img_alt_dir_row; + bool has_img_alt_dir_column; + bool has_custom_width; + bool has_custom_height; + bool has_enable_img_alt_dir; + bool has_buildable_on; + bool has_buildable_adjacent_to; + bool has_buildable_adjacent_to_overlays; + bool has_buildable_on_rivers; + bool has_buildable_by_civs; + bool has_buildable_by_civ_traits; + bool has_buildable_by_civ_govs; + bool has_buildable_by_civ_cultures; +}; + +struct parsed_natural_wonder_definition { + char * name; + char * img_path; + enum SquareTypes terrain_type; + enum SquareTypes adjacent_to; + enum direction adjacency_dir; + int img_row; + int img_column; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + bool impassible; + bool impassible_to_wheeled; + bool has_name; + bool has_img_path; + bool has_img_row; + bool has_img_column; + bool has_terrain_type; + bool has_adjacent_to; + bool has_adjacency_dir; + bool has_culture_bonus; + bool has_science_bonus; + bool has_food_bonus; + bool has_gold_bonus; + bool has_shield_bonus; + bool has_happiness_bonus; + bool has_impassible; + bool has_impassible_to_wheeled; +}; + +struct scenario_district_entry { + int tile_x; + int tile_y; + int has_coordinates; + char * district_name; + int has_district_name; + char * wonder_city_name; + int has_wonder_city; + char * wonder_name; + int has_wonder_name; +}; + +struct scenario_named_tile_entry { + int tile_x; + int tile_y; + int has_coordinates; + char * name; + int has_name; +}; + +struct distribution_hub_record { + Tile * tile; + int tile_x; + int tile_y; + int civ_id; + int food_yield; + int shield_yield; + int raw_food_yield; + int raw_shield_yield; +}; + +struct ai_best_feasible_order { + City_Order order; + int value; +}; + +struct district_building_prereq_list { + int count; + int district_ids[MAX_DISTRICT_DEPENDENTS]; +}; + +struct pending_district_request { + City * city; + int city_id; + int civ_id; + int district_id; + int assigned_worker_id; + int target_x; + int target_y; + int worker_assigned_turn; +}; + +struct ai_candidate_bridge_or_canal_entry { + int district_id; + short owner_civ_id; + short * tile_x; + short * tile_y; + short tile_count; + short assigned_tile_index; + int assigned_worker_id; + bool completed; + struct pending_district_request pending_req; + int tile_capacity; +}; + +struct district_worker_record { + Unit * worker; + int unit_id; + int continent_id; + struct pending_district_request * pending_req; +}; + +enum wonder_district_state { + WDS_UNUSED = 0, // Wonder district built, no wonder assigned + WDS_UNDER_CONSTRUCTION, // Reserved by a city for wonder construction + WDS_COMPLETED, // Wonder completed on this district + WDS_RUINED // (Future) Wonder was destroyed +}; + +struct wonder_district_info { + enum wonder_district_state state; + City * city; // City that reserved/completed (NULL if unused) + int city_id; + int wonder_index; // Wonder index (-1 if unused/reserved, valid if completed) +}; + +struct natural_wonder_district_info { + int natural_wonder_id; +}; + +enum district_state { + DS_UNDER_CONSTRUCTION = 0, + DS_COMPLETED = 1 +}; + +struct district_instance { + enum district_state state; + int district_id; // Index into district_configs array + int tile_x; + int tile_y; + int built_by_civ_id; + int completed_turn; + struct wonder_district_info wonder_info; // Only used if district_id is a wonder district + struct natural_wonder_district_info natural_wonder_info; // Only used if district_id is a natural wonder district +}; + +enum extra_resource_tile_type { + ERT_MILL_RESOURCE = 0, + ERT_DISTRICT_RESOURCE +}; + +struct extra_resource_tile { + Tile * tile; + enum extra_resource_tile_type type; + union { + struct { + City * city; + struct mill * mill; + } mill_info; + struct { + struct district_instance * inst; + struct district_config * cfg; + } district_info; + }; +}; + +struct named_tile_entry { + int tile_x; + int tile_y; + char name[100]; +}; + +struct highlighted_city_radius_tile_info { + int highlight_level; +}; + +struct injected_state { + // ========== + // These fields are valid at any time in the injected code because they're set by the patcher { + // ========== + + int mod_version; + // "mod relative directory" is the mod dir relative to the conquests dir. Usually it's "C3X_Rn" but it might be deeper. + // It must be non-empty and must not have an ending backslash. + char mod_rel_dir[MAX_PATH]; + + enum init_state sc_img_state; + enum init_state tile_highlight_state; + enum init_state mod_info_button_images_state; + enum init_state disabled_command_img_state; + enum init_state unit_rcm_icon_state; + enum init_state red_food_icon_state; + enum init_state distribution_hub_icons_img_state; + enum init_state tile_already_worked_zoomed_out_sprite_init_state; + enum init_state day_night_cycle_img_state; + enum init_state large_minimap_frame_img_state; + + // ========== + // } These fields are valid at any time after patch_init_floating_point runs (which is at the program launch). { + // ========== + + struct c3x_config base_config; + + // Windows modules + HMODULE kernel32; + HMODULE user32; + HMODULE msvcrt; + HMODULE msimg32; + + // Win32 API functions + WINBOOL (WINAPI * VirtualProtect) (LPVOID, SIZE_T, DWORD, PDWORD); + WINBOOL (WINAPI * CloseHandle) (HANDLE); + HANDLE (WINAPI * CreateFileA) (LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); + DWORD (WINAPI * GetFileSize) (HANDLE, LPDWORD); + WINBOOL (WINAPI * ReadFile) (HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); + HMODULE (WINAPI * LoadLibraryA) (LPCSTR); + BOOL (WINAPI * FreeLibrary) (HMODULE); + int (WINAPI * MultiByteToWideChar) (UINT, DWORD, LPCCH, int, LPWSTR, int); + int (WINAPI * WideCharToMultiByte) (UINT, DWORD, LPCWCH, int, LPSTR, int, LPCCH, LPBOOL); + int (WINAPI * GetLastError) (); + BOOL (WINAPI * QueryPerformanceCounter) (LARGE_INTEGER *); + BOOL (WINAPI * QueryPerformanceFrequency) (LARGE_INTEGER *); + void (WINAPI * GetLocalTime) (LPSYSTEMTIME); + + // Win32 funcs from user32.dll + int (WINAPI * MessageBoxA) (HWND, LPCSTR, LPCSTR, UINT); + + // Win32 funcs from Msimg32.dll + BOOL (WINAPI * TransparentBlt) (HDC, int, int, int, int, HDC, int, int, int, int, UINT); + + // C standard library functions + int (* snprintf) (char *, size_t, char const *, ...); + void * (* malloc) (size_t); + void * (* calloc) (size_t, size_t); + void * (* realloc) (void *, size_t); + void (* free) (void *); + long (* strtol) (char const *, char **, int); + float (* strtof) (char const *, char **); + int (* strcmp) (char const *, char const *); + int (* strncmp) (char const *, char const *, size_t); + int (* _stricmp) (char const *, char const *); + size_t (* strlen) (char const *); + char * (* strncpy) (char *, char const *, size_t); + char * (* strcpy) (char *, char const *); + char * (* strdup) (char const *); + char * (* strstr) (char const *, char const *); + void (* qsort) (void *, size_t, size_t, int (*) (void const *, void const *)); + int (* memcmp) (void const *, void const *, size_t); + void * (* memcpy) (void *, void const *, size_t); + void * (* memmove) (void *, void const *, size_t); + int (* tolower) (int); + int (* toupper) (int); + + Unit * sb_next_up; // The unit currently doing a stack bombard or NULL otherwise. Gets set to NULL if the unit is despawned. + + Trade_Net * trade_net; // Pointer to the trade net object. If it hasn't been moved by the mod, this equals p_original_trade_net. + int city_limit; // Stores the current actual city limit. Not necessarily the same as the stride of the trade net matrix or the config setting. + + enum init_state trade_net_addrs_load_state; + int * trade_net_addrs; + + HMODULE trade_net_x; + void (__stdcall * set_exe_version) (int); + void * (__stdcall * create_tnx_cache) (Map *); + void (__stdcall * destroy_tnx_cache) (void *); + void (__stdcall * set_up_before_building_network) (void *); + int (__stdcall * get_move_cost_for_sea_trade) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags, int neighbor_index, Trade_Net_Distance_Info * dist_info); + void (__stdcall * flood_fill_road_network) (void * tnx_cache, int from_x, int from_y, int civ_id); + bool (__stdcall * try_drawing_sea_trade_route) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags); + + void * tnx_cache; // Cache object used by Trade Net X. Initially NULL, must be recreated every time a new map is loaded. + enum init_state tnx_init_state; + bool is_computing_city_connections; // Set to true only while Trade_Net::recompute_city_connections is running + bool keep_tnx_cache; + + // This flag gets set whenever a trade deal is signed or broken for a resource that's an input to a mill. It's necessary to call + // recompute_resources in that case since a mill may have been de/activated by the change. We can't call it right when the change happens as + // that can crash the game for reasons I don't completely understand. I believe it's because the recomputation can't be done while some other + // econ logic is running. Instead, we set this variable then recompute before obsolete data would be an issue. Specifically, this is done: + // - When any player or AI begins their production phase + // - When the player zooms to any city + // - When the player opens the shift + right-click production chooser menu + // - When the player visits any advisor + // - When the player selects any unit + bool must_recompute_resources_for_mill_inputs; + + bool is_placing_scenario_things; // Set to true only while Map::place_scenario_things is running + + bool paused_for_popup; // Set to true while a popup, map message, or the diplo screen is open + long long time_spent_paused_during_popup; // Tracks time spent waiting for the three things above + + // This variable is increased with the time elapsed during every call to Trade_Net::recompute_city_connections. Time is measured using + // Windows performance counter. + long long time_spent_computing_city_connections; + int count_calls_to_recompute_city_connections; + + long long time_spent_filling_roads; + + struct c3x_config current_config; + + // Keeps a record of all configs currently loaded. Useful to know. "name" is the file name for configs that come from files, which is all of + // them except for the base config, whose name is "(base)". + struct loaded_config_name { + char * name; + struct loaded_config_name * next; + } * loaded_config_names; + + char current_districts_config_path[MAX_PATH]; + + char mod_script_path[MAX_PATH]; + + char * c3x_labels[COUNT_C3X_LABELS]; + + int have_job_and_loc_to_skip; // 0 or 1 if the variable below has anything actionable in it. Gets cleared to 0 after every turn. + struct worker_job_and_location to_skip; + + struct table saved_code_areas; + + int * unit_menu_duplicates; // NULL initialized, allocated to an array of 0x100 ints when needed + bool named_tile_menu_active; + int named_tile_menu_tile_x; + int named_tile_menu_tile_y; + + // List of temporary ints. Initializes to NULL/0/0, used with functions "memoize" and "clear_memo" + int * memo; + int memo_len; + int memo_capacity; + + // Array mapping cultural neighbor indices to the standard indices that correspond to the same tiles. Generated at program start. + byte * cultural_ni_to_standard; + + // Array mapping standard neighbor indices to the smallest work radius that includes the corresponding tile. Ex., if a given n.i. corresponds + // to one of the adjacent tiles, maps to 1, if it's in the fat cross but not adjacent, maps to 2, and so forth, out into the extended area. + char ni_to_work_radius[256]; + + // The maximum number of tiles workable by cities including the city tile itself (21 under standard game rules). Updated whenever the + // city_work_radius config value gets changed. + int workable_tile_count; + + // The civ ID of the player from whose perspective we're currently showing city loc desirability, or -1 if none. Initialized to -1. + int city_loc_display_perspective; + + // These are all bit fields that run parallel to player bits. Each bit indicates whether or not that name was replaced with an era-specific + // version for that player. This allows us to tell the difference between custom names set by human players and replacements made by the mod. + int aliased_civ_noun_bits; + int aliased_civ_adjective_bits; + int aliased_civ_formal_name_bits; + int aliased_leader_name_bits; + int aliased_leader_title_bits; + + // Stores resource access bits for resources beyond the first 32, used to fix the phantom resource bug. Initialized to NULL/0 and allocated as + // necessary by get_extra_resource_bits. Contains an array of groups of unsigned ints. There is one group per city (allocated lazily so you + // must use the getter) and the number of ints in each group depends on the number of resources defined in the scenario, one for every 32 + // after the first 32. + unsigned * extra_available_resources; + int extra_available_resources_capacity; // In number of cities. + + // These lists store interception events per-player during the interturn so we can clear the interception state on fighters that have done so + // at the beginning of their next turn. The point of this is to imitate the base game behavior where fighters that perform an interception are + // knocked out of the interception state. We can't knock them out immediately b/c that will prevent them from doing multiple interceptions per + // turn, so instead we record the event in these lists and reset their state later. + struct interceptor_reset_list { + struct interception { + int unit_id; + int x, y; + } * items; + int count; + int capacity; + } interceptor_reset_lists[32]; + + // Records the turn number on which each player has most recently founded a city. This is intended to be used for the temp settler perfume + // after founding feature so it may not be set if that feature is not activated or applicable. Defaults to -1. + int turn_no_of_last_founding_for_settler_perfume[32]; + + // Stores the byte offsets into the c3x_config struct of all boolean/integer config options, accessible using the options' names as + // strings. Used when reading in a config INI file. + struct table boolean_config_offsets; + struct table integer_config_offsets; + + // Maps unit types IDs to AI strategy indices (0 = offense, 1 = defense, 2 = artillery, etc.). If a unit type ID is in this table, that means + // it's one of several duplicate types created to spread multiple AI strategies out so each type has only one. + struct table unit_type_alt_strategies; + + // Stores a linked list of unit type duplicates. Maps unit type IDs to the next duplicate ID. Use list_unit_type_duplicates to get the list of + // the duplicates of a particular type as an array. + struct table unit_type_duplicates; + + // Tracks the number of "extra" defensive bombards units have performed, by their IDs. If the "blitz" special defensive bombard rule is + // activated, units with blitz get an extra chance to perform DB for each movement point they have beyond the first. + struct table extra_defensive_bombards; + + // Table mapping unit IDs to how many times that unit has airdropped on the current turn. This is used to prevent units from airdropping + // multiple times. That doesn't matter for the base game but stops the dont-end-turn-after-airdrop setting from letting units airdrop an + // unlimited number of times. + struct table airdrops_this_turn; + + // Stores city improvement bits for improvs beyond the first 256 + struct table extra_city_improvs; + + // These variables store the number of units of each type that each player has + int unit_type_count_init_bits; // Player bits tracking which unit type count tables have been initialized. + struct table unit_type_counts[32]; // One table per player. Each one maps unit type ids (ints) to counts (ints) + + // ========== + // } These fields are valid only after init_stackable_command_buttons has been called. { + // ========== + + struct sc_button_image_set { + Sprite imgs[4]; + } sc_button_image_sets[COUNT_STACKABLE_COMMANDS]; + + int sb_activated_by_button; // Gets set to 1 when the player clicks on the SB button so that perform_action_on_tile knows + // to do stack instead of regular bombard. This is necessary since the SB button actually just activates regular bombard. + // The proper way to implement the SB button would be to give it its own mode action but that's difficult to do because + // the existing mode actions are baked into the code. Implementing it this way I estimate is less fragile and requires + // less patching. The hard part is knowing when to clear this flag so that the player doesn't activate SB, cancel it, then + // activate regular bombard and get SB instead. One trick to make this easier is to look for the change of cursor away + // from the little bomb indicator instead of trying to intercept every relevant UI event. This flag is changed in these + // circumstances: + // (1) At init, the flag is cleared, of course. + // (2) Pressing the SB button sets the flag and pressing another unit command button clears it. + // (3) If handle_cursor_change_in_jgl is called and the main_screen_form's Mode_Action isn't (air) bombard, the flag + // is cleared. That covers every case of switching off SB mode except one, when the player presses a key to switch + // off of SB to regular bombard, that's what case (4) is for. + // (4) The flag is cleared when the player presses the B key or (if the unit is capable of precision strikes) the P key. + // One final complication, that I only discovered after trying to implement this, is that when clicking on the map with a + // mode action, the cursor is cleared before the action is carried out. So we have to intercept that map click as well for + // a total of 4 UI functions patched to make this damn button work. I doubt this is optimal but it works and I've wasted + // enough time on this already. That click interceptor sets a flag value of 2 to indicate this annoying state. + + // ========== + // } This field is only valid after init_disabled_command_buttons has been called and disabled_command_img_state equals IS_OK { + // ========== + + Sprite disabled_build_city_button_img; + + // ========== + // } This field is only valid after init_unit_rcm_icons has been called and unit_rcm_icon_state equals IS_OK { + // ========== + + // Sprites are stored together as sets, so the first COUNT_UNIT_RCM_ICONS elements are those from the first set, then the same number from the + // second set, etc. + Sprite unit_rcm_icons[COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS]; + + // ========== + // } These fields are valid only after init_tile_highlights as been called. { + // ========== + + Sprite tile_highlights[COUNT_TILE_HIGHLIGHTS]; + + // ========== + // } This one is valid only if init_mod_info_button_images has been called and mod_info_button_images_state equals IS_OK { + // ========== + + Sprite mod_info_button_images[3]; + + // ========== + // } This one is valid only if init_red_food_icon has been called and red_food_icon_state equals IS_OK { + // ========== + + Sprite red_food_icon; + + // ========== + // } These are valid only if init_large_minimap_frame has been called and large_minimap_frame_img_state equals IS_OK { + // ========== + + Sprite double_size_box_left_color_pcx, double_size_box_left_alpha_pcx; + + // ========== + // } These fields are temporary/situational { + // ========== + + int saved_road_movement_rate; // Valid when railroad movement limit is applied (limit_railroad_movement > 0) and BIC data has been loaded + int road_mp_cost; // The cost of moving one tile along a road, in MP. Valid after BIC data was loaded. + int railroad_mp_cost_per_move; // The cost of moving one tile along a railroad, in MP, per move available to the unit. This is measured per + // move since the cost of moving along a railroad is scaled by the total number of moves available to the + // unit. Valid after BIC data was loaded. + + int saved_barb_culture_group; // Valid when barb city capturing is enabled and BIC data has been loaded + + Leader * leader_param_for_patch_get_wonder_city_id; // Valid in patch_get_wonder_city_id when called from + // Leader_recompute_auto_improvements + + int show_popup_was_called; // Set to 1 in show_popup. Used in patch_Leader_can_do_worker_job to check if the replacement + // popup was shown. + + // Used to control trade screen scroll + int open_diplo_form_straight_to_trade; // Initialized to 0, gets set to 1 by patch_DiploForm_do_diplomacy to signal + // to patch_DiploForm_m68_Show_Dialog to open the diplo form straight into trade mode. + int trade_screen_scroll_to_id; // Set by patch_DiploForm_m82_handle_key_event to signal to do_diplomacy that the form + // was closed in order to scroll to the civ with the set ID. -1 indicates no scrolling. + Button * trade_scroll_button_left; // initialized to NULL + Button * trade_scroll_button_right; // initialized to NULL + Sprite * trade_scroll_button_images; // inited to NULL, array of 6 images: normal, rollover, and highlight for left & right + enum init_state trade_scroll_button_state; + int eligible_for_trade_scroll; + + char ask_gold_default[32]; + + // Set in patch_ai_choose_production, used by the various bits of injected code that run during the AI production choosing process. + City * ai_considering_production_for_city; + + // This variable stores what improvement or unit the AI is evaluating inside ai_choose_production. It gets set inside two call replacements, + // first inside the loop over improvements then again inside a loop over unit types. The var is used by the intercept consideration functions + // which run at the end of each loop iteration. + City_Order ai_considering_order; + int handling_ai_district_fallback; + + // Used in the code that adds additional info to the tile info box + bool tile_info_open; + int viewing_tile_info_x, viewing_tile_info_y; + + // Used in patch_Tile_m43_Get_field_30_for_city_loc_eval to change how the AI evaluates overlap between cities + int ai_evaling_city_loc_x, ai_evaling_city_loc_y; + int ai_evaling_city_field_30_get_counter; + + // Stores a list of the production options in a given city and the point value the AI would assign to each. The list is populated by + // rank_ai_production_options, items are added by record_improv_val which gets called by some code injected into one of the loops in + // ai_choose_production. These vars are initialized to zero. + struct ai_prod_valuation * ai_prod_valuations; + int count_ai_prod_valuations; + int ai_prod_valuations_capacity; + + // Used for generating resources from buildings and districts + struct extra_resource_tile * resource_tiles; + int count_resource_tiles; + int resource_tiles_capacity; + struct extra_resource_tile * got_resource_tile; + int saved_tile_count; // Stores the actual tile count in case p_bic_data->Map.TileCount was temporarily overwritten. Set to -1 when empty. + byte * mill_input_resource_bits; // Array of bits, one for each resource. Stores whether or not each one is an input to any mill. + + // Used for displaying yields from generated resources on the city screen + int tourism_icon_counter; // Incremented each time a tourism yield icon (normally commerce) is drawn. Reset between improvs. + int convert_displayed_tourism_to_food, convert_displayed_tourism_to_shields; // Number of commerce tourism icons to convert to food, shields + int combined_tourism_and_mill_commerce; // Number of commerce tourism icons to display inc. from mills, maybe negative + + int drawing_icons_for_improv_id; // Stores the improv ID whose icons we're drawing. -1 while not drawing. + + PCX_Image * resources_sheet; // Sprite sheet of resource icons, i.e. resources.pcx + + Sprite tile_already_worked_zoomed_out_sprite; // Valid only if init state is OK + + // Only for use by patch_City_Form_draw_yields_on_worked_tiles and patch_Sprite_draw_already_worked_tile_img + bool do_not_draw_already_worked_tile_img; + + // Stores the trade offer object being modified when the user right-clicks on a gold offer/ask on the trade table. Gets set by a special + // function call replacement (see apply_machine_code_edits for details). + TradeOffer * modifying_gold_trade; + + // Initialized to NULL and reset to NULL after Unit::bombard_tile returns. Gets set just before the call to Unit::play_bombard_fire_animation + // from inside bombard_tile. The value is the unit on the bombarded tile specifically targeted by the attack, if applicable. + Unit * bombard_stealth_target; + + // Set to zero when Unit::select_stealth_attack_target is called then checked inside in the call to PopupSelection::add_item and set to + // 1. This variable lets the add_item replacement function run special code for only the first item added, in order to insert an additional + // first option to cancel the stealth attack. + int added_any_stealth_target; + + // Initialized to zero. Temporarily set to 1 across a call to patch_Unit_select_stealth_attack_target to request that the selected target must + // be suitable for attack via bombardment. + int selecting_stealth_target_for_bombard; + + // Set in rand_int_to_dodge_city_aa and read immediately after in Unit_get_defense_to_dodge_city_aa. Allows us to determine whether the dodge + // roll was successful in order to popup the message. + int result_of_roll_to_dodge_city_aa; + + // Initialized to NULL. If set to non-NULL, the next call to show_map_message will consume that value and use it as the text on the + // message. Used to implement show_map_specific_text. + char const * map_message_text_override; + + // Initialized to NULL. If set to non-NULL, the next call to do_load_game will consume this value and use it as the file path of the game to + // load instead of opening the file picker. + char const * load_file_path_override; + + // A set of player bits indicating which players should see a replay of the AI's moves. Normally all zero, gets filled in by + // patch_perform_interturn_in_main_loop only when/as appropriate. As replays are played (in patch_show_movement_phase_popup), the + // corresponding bits are cleared. + int replay_for_players; + + // Used by patch_perform_interturn_in_main_loop to determine which players need to see the replay. Clear before interturn processing, then + // every time an AI unit moves onto or bombards a tile, any players that have vision on that tile will have their bit set in this var. + int players_saw_ai_unit; + + // Initialized to 0. If set to non-zero, the next call to do_load_game will consume the value and skip the intro popup. + int suppress_intro_after_load_popup; + + struct improv_id_list { + int * items; + int count; + int capacity; + } water_trade_improvs, air_trade_improvs, combat_defense_improvs; + + // Used by the fix for the barbarian diagonal bug + int barb_diag_patch_dy_fix; + + // Initialized to 0. If 1, barbarian activity is force activated b/c there are barb cities on the map that need to do production. + int force_barb_activity_for_cities; + + // Used as a stand-in for an actual tile where needed. In particular, this object is returned from various get_tile and tile_at replacements + // when we need to override the visibility data to implement hotseat shared vis. + Tile * dummy_tile; + + // When the game checks visibility for a tile, it accesses all four visibility fields with separate calls to Map::get_tile and/or tile_at. We + // replace the first call, maybe altering its return to implement shared visibility, cache the return in this variable, then re-use the cached + // value for the next three calls. + Tile * tile_returned_for_visibility_check; + + // Initialized to all -1. If set, the unit with the specified ID will always be the top unit displayed on the specified tile. If the unit is + // not on that tile, there is no effect. This is only intended to be used on a temporary basis. + struct unit_display_override { + int unit_id, tile_x, tile_y; + } unit_display_override; + + // Set in patch_Fighter_get_odds_for_main_combat_loop, read by patch_Unit_get_attack/defense_strength. + // Stores counter multipliers for the current combat. Active only during Fighter_get_combat_odds call. + struct { + bool active; + Unit * attacker; + Unit * defender; + int attacker_atk_pct; // 攻击方攻击力倍率(合并了 self-atk 正向和 enemy-atk 反向) + int defender_def_pct; // 防守方防御力倍率(合并了 enemy-def 正向和 self-def 反向) + bool ignore_terrain; + } counter_combat_ctx; + + // Used to extract which unit (if any) exerted zone of control from within Fighter::apply_zone_of_control. + Unit * zoc_interceptor; + + // Set when Fighter::apply_zone_of_control is called to store the defending unit, used by the injected filter and Unit::move_to_adjacent_tile. + // Cleared at each call to move_to_adjacent_tile and by Unit::despawn. + Unit * zoc_defender; + + // Set to the bombarding unit while Unit::bombard_tile is running. NULL otherwise. + Unit * bombarding_unit; + + // Normally set to NULL. When a unit bombards a tile (the tile itself, not something on it), set to point to that unit during the call to + // Unit::attack_tile. Used to stop the unit from losing all of its movement if configured. + Unit * unit_bombard_attacking_tile; + + // Set to the coords of the tile being attacked while Unit::attack_tile is running, -1 otherwise. + int attacking_tile_x, attacking_tile_y; + + // Cleared to false when Fighter::apply_zone_of_control is called. The interceptor must be unfortified to ensure it plays its animation. If + // that happens, this flag is set so that apply_zone_of_control knows to refortify the unit after the ZoC process is done. + bool refortify_interceptor_after_zoc; + + // These flags are used to turn off lethal ZoC for units that capture an enemy on the tile they're moving into. Without this rule, the unit + // might get killed by ZoC but the captured units will remain on a tile that was never actually entered (that tile might have an enemy city + // for extra weirdness). Here's how it works: + // 1. The moving_unit_to_adjacent_tile flag is set when Unit::move_to_adjacent_tile is called. + // 2. If that flag is set and a unit is captured (detected by intercepting the calls to Leader::spawn_unit inside Unit::do_capture_units) + // then temporarily_disallow_lethal_zoc is set. + // 3. If temporar... is set, the code to filter ZoC interceptors acts as if lethal ZoC were turned off. + // 4. Both flags are cleared when Unit::move_to_adjacent_tile returns. + bool temporarily_disallow_lethal_zoc; + bool moving_unit_to_adjacent_tile; + + // Tracks temporary transport bypass when letting workers step onto coast tiles without a boat + Unit * coast_walk_unit; + bool coast_walk_transport_override; + enum UnitStateType coast_walk_prev_state; + int coast_walk_prev_container; + bool coast_walk_restore_goto_path; + int coast_walk_prev_path_len; + int coast_walk_prev_path_dest_x; + int coast_walk_prev_path_dest_y; + Unit * move_spend_override_unit; + int move_spend_override_value; + + // Used to record info about a defensive bomardment event during Fighter::fight. Gets set by Fighter::damage_by_defensive_bombardment and + // cleared when Fighter::fight returns. + struct defensive_bombard_event { + Unit * bombarder; + Unit * defender; + bool damage_done, defender_was_destroyed, saved_animation_setting; + } dbe; + + // Set to true IFF we're showing a replay of AI moves in hotseat mode + bool showing_hotseat_replay; + + // Set to true only during the first call to get_tile_occupier_id from Trade_Net::get_movement_cost. While this is set, we need to edit unit + // visibility to patch the submarine bug. + bool getting_tile_occupier_for_ai_pathfinding; + + bool running_on_wine; // Set to 1 IFF we're running in Wine, as opposed to actual Windows + + // gdi_plus.init_state is valid any time after patch_init_floating_point. All the other fields are only valid after set_up_gdi_plus has been + // called and gdi_plus.init_state equals IS_OK. + struct gdi_plus { + enum init_state init_state; + HMODULE module; + ULONG_PTR token; + void * gp_graphics; + + int (__stdcall * CreateFromHDC) (HDC hdc, void ** p_gp_graphics); + int (__stdcall * DeleteGraphics) (void * gp_graphics); + int (__stdcall * SetSmoothingMode) (void * graphics, int smoothing_mode); + int (__stdcall * SetPenDashStyle) (void * gp_pen, int dash_style); + int (__stdcall * CreatePen1) (unsigned int argb_color, float width, int gp_unit, void ** p_gp_pen); + int (__stdcall * DeletePen) (void * gp_pen); + int (__stdcall * DrawLineI) (void * gp_graphics, void * gp_pen, int x1, int y1, int x2, int y2); + } gdi_plus; + + // These variables track the states of some OpenGL parameters. They're updated whenever methods like OpenGLRenderer::set_color are called. + unsigned int ogl_color; + int ogl_line_width; + bool ogl_line_stipple_enabled; + + // Records how many units of each type we're going to upgrade to during an upgrade-all. This info will be used to impose the unit type limit + // during the upgrade. Keep in mind units all get upgraded from the same type but might end up as different types after upgrade-all. + struct penciled_in_upgrade { + int unit_type_id; + int count; + } * penciled_in_upgrades; + int penciled_in_upgrade_count; + int penciled_in_upgrade_capacity; + + // While in Leader::do_capture_city, the city in question is stored in this var. Otherwise it's NULL. + City * currently_capturing_city; + + // While a game is being saved or loaded, this variable points to the save file's MappedFile object. Otherwise it's NULL. + MappedFile * accessing_save_file; + + // Used in patch_work_simple_job. If a method sets this variable while that method is running then at the end it sets the given tile as LM. + Tile * lmify_tile_after_working_simple_job; + + // Reset to zero every time City_Form::draw is called. Incremented everything a strategic resource is drawn on the city screen. + int drawn_strat_resource_count; + + int * charmed_types_converted_to_ptw_arty; + int count_charmed_types_converted_to_ptw_arty; + int charmed_types_converted_to_ptw_arty_capacity; + + // While Unit::is_visible_to_civ is running, this var is set to the unit in question. Otherwise it's NULL. + Unit * checking_visibility_for_unit; + + // Normally false. When true, calls to bounce_trespassing_units won't kick out invisible units even if they're revealed. + bool do_not_bounce_invisible_units; + + // Normally false. When true, Unit::despawn also despawns any passenger units inside instead of making exceptions in some cases. + bool always_despawn_passengers; + + // Normally false. When true, calls to Unit::score_kill will not enslave. + bool do_not_enslave_units; + + // If limit_unit_loading_to_one_transport_per_turn is on, maps unit IDs to the ID of the transport unit they're tied to for the current turn. + struct table unit_transport_ties; + + // Initialized to NULL/0, used in patch_City_add_happiness_from_buildings + short * saved_improv_counts; + int saved_improv_counts_capacity; + + // Used to de-overlap specialist yield icons (option name fix_overlapping_specialist_yield_icons) + int specialist_icon_drawing_running_x; + + // Initialized to 0, used to draw multipage descriptions in the Civilopedia + struct civilopedia_multipage_description { + bool drawing_lines; + int line_count; + int shown_page; // zero-based + int last_page; // also zero-based + Civilopedia_Article * article; + Button * effects_btn; + Button * previous_btn; + } cmpd; + + // Day-Night cycle data + int current_day_night_cycle; + bool day_night_cycle_unstarted; // If current_day_night_cycle has not been set, f.e. because it's the first turn of a new game. + bool day_night_cycle_img_proxies_indexed; + LARGE_INTEGER last_day_night_cycle_update_time; + + struct table day_night_sprite_proxy_by_hour[24]; + + struct wonder_district_image_set { + Sprite img; + Sprite construct_img; + Sprite alt_dir_img; + Sprite alt_dir_construct_img; + } wonder_district_img_sets[MAX_WONDER_DISTRICT_TYPES]; + + struct natural_wonder_district_image_set { + Sprite img; + } natural_wonder_img_sets[MAX_NATURAL_WONDER_DISTRICT_TYPES]; + struct natural_wonder_label_draw_info { + int text_left; + int text_top; + int text_width; + int font_size; + char const * text; + }; + + struct day_night_cycle_img_set + { + SpriteList Std_Terrain_Images[9]; + SpriteList LM_Terrain_Images[9]; + Sprite City_Images[80]; + Sprite Destroyed_City_Images[3]; + Sprite Resources[36]; + Sprite ResourcesShadows[36]; + Sprite Terrain_Buldings_Barbarian_Camp; + Sprite Terrain_Buldings_Mines; + Sprite Victory_Image; + Sprite Flood_Plains_Images[16]; + Sprite Fog_Of_War_Images[81]; + Sprite Polar_Icecaps_Images[32]; + Sprite Railroads_Images[272]; + Sprite Roads_Images[256]; + Sprite Minor_Roads_Images[256]; + Sprite Terrain_Buldings_Airfields[2]; + Sprite Terrain_Buldings_Airfields_Shadow[2]; + Sprite Terrain_Buldings_Camp[4]; + Sprite Terrain_Buldings_Fortress[4]; + Sprite Terrain_Buldings_Barricade[4]; + Sprite Goody_Huts_Images[8]; + Sprite Terrain_Buldings_Outposts[3]; + Sprite Terrain_Buldings_Outposts_Shadow[3]; + Sprite Pollution[25]; + Sprite Craters[25]; + Sprite Terrain_Buldings_Radar; + Sprite Terrain_Buldings_Radar_Shadow; + Sprite Tnt_Images[18]; + Sprite Waterfalls_Images[4]; + Sprite LM_Terrain[7]; + Sprite Marsh_Large[8]; + Sprite Marsh_Small[10]; + Sprite Volcanos_Images[16]; + Sprite Volcanos_Forests_Images[16]; + Sprite Volcanos_Jungles_Images[16]; + Sprite Volcanos_Snow_Images[16]; + Sprite Grassland_Forests_Large[8]; + Sprite Plains_Forests_Large[8]; + Sprite Tundra_Forests_Large[8]; + Sprite Grassland_Forests_Small[10]; + Sprite Plains_Forests_Small[10]; + Sprite Tundra_Forests_Small[10]; + Sprite Grassland_Forests_Pines[12]; + Sprite Plains_Forests_Pines[12]; + Sprite Tundra_Forests_Pines[12]; + Sprite Irrigation_Desert_Images[16]; + Sprite Irrigation_Plains_Images[16]; + Sprite Irrigation_Images[16]; + Sprite Irrigation_Tundra_Images[16]; + Sprite Grassland_Jungles_Large[8]; + Sprite Grassland_Jungles_Small[12]; + Sprite Mountains_Images[16]; + Sprite Mountains_Forests_Images[16]; + Sprite Mountains_Jungles_Images[16]; + Sprite Mountains_Snow_Images[16]; + Sprite Hills_Images[16]; + Sprite Hills_Forests_Images[16]; + Sprite Hills_Jungle_Images[16]; + Sprite Delta_Rivers_Images[16]; + Sprite Mountain_Rivers_Images[16]; + Sprite Territory_Images[8]; + Sprite LM_Mountains_Images[16]; + Sprite LM_Forests_Large_Images[8]; + Sprite LM_Forests_Small_Images[10]; + Sprite LM_Forests_Pines_Images[12]; + Sprite LM_Hills_Images[16]; + Sprite District_Images[COUNT_DISTRICT_TYPES][MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [district][variant][era][column] + Sprite Abandoned_District_Image; + Sprite Abandoned_Maritime_District_Image; + struct wonder_district_image_set Wonder_District_Images[MAX_WONDER_DISTRICT_TYPES]; + struct natural_wonder_district_image_set Natural_Wonder_Images[MAX_NATURAL_WONDER_DISTRICT_TYPES]; + } day_night_cycle_imgs[24]; + + // Districts + enum init_state dc_img_state; + enum init_state dc_btn_img_state; + enum init_state dc_icons_img_state; + + struct district_config district_configs[COUNT_DISTRICT_TYPES]; + struct wonder_district_config wonder_district_configs[MAX_WONDER_DISTRICT_TYPES]; + struct natural_wonder_district_config natural_wonder_configs[MAX_NATURAL_WONDER_DISTRICT_TYPES]; + +struct district_image_set { + Sprite imgs[MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [variant][era][column] +} district_img_sets[COUNT_DISTRICT_TYPES]; + Sprite abandoned_district_img; + Sprite abandoned_maritime_district_img; + +struct district_button_image_set { + Sprite imgs[4]; +} district_btn_img_sets[COUNT_DISTRICT_TYPES]; + + // Building ID keys -> district ID. If a building ID is present in the + // table that means that building can only be built if there is a corresponding district is present in the city radius. + struct table district_building_prereqs; + + // Tile pointer IDs -> district_instance pointer. Maps tiles to dynamically allocated + // district_instance structs tracking district type and state (UNDER_CONSTRUCTION or COMPLETED). + // For wonder districts, the wonder_info field tracks wonder-specific state (unused, reserved, completed, ruined), + // which city reserved/completed the wonder, and which wonder index is on this district. + struct table district_tile_map; + struct table named_tile_map; + + // Tracks per-turn airlift usage for aerodrome districts (tile pointer -> civ bitmask). + struct table aerodrome_airlift_usage; + + // Command ID keys -> district ID. Used to identify which district + // a unit command (e.g., build order) corresponds to. + struct table command_id_to_district_id; + + // Array of 32 tables (one per civ) of pending district requests keyed by city & district (values are struct pending_district_request pointers). + struct table city_pending_district_requests[32]; + + // City pointer keys -> improvement ID. Tracks which improvements (buildings/wonders) + // requiring districts a city has ordered to be built (pending district completion). + struct table city_pending_building_orders; + + // AI cache mapping city pointer keys -> AI_Order pointer. Stores the best feasible + // production order for AI cities to optimize decision-making. + struct table ai_best_feasible_orders; + + // String building/wonder name keys -> int building/improvement ID. + // Used to look up building IDs by their text names from the game data. + struct table building_name_to_id; + + struct district_infos { + int advance_prereq_ids[MAX_DISTRICT_DEPENDENTS]; // Tech IDs that enable the district (all required) + int advance_prereq_count; + int obsoleted_by_id; + int resource_prereq_ids[MAX_DISTRICT_DEPENDENTS]; + int resource_prereq_count; + int resource_prereq_on_tile_id; + int wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; + int wonder_prereq_count; + int natural_wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; + int natural_wonder_prereq_count; + int dependent_building_count; + int dependent_building_ids[MAX_DISTRICT_DEPENDENTS]; // Building types the district enables + } district_infos[COUNT_DISTRICT_TYPES]; + + // District tracking counters: total = special (hard-coded) + dynamic (from config/scenario) + // next_custom_dynamic_command_index assigns unique command IDs for custom dynamic commands + int district_count; + int special_district_count; + int dynamic_district_count; + int wonder_district_count; + int natural_wonder_count; + int next_custom_dynamic_command_index; + + // Distribution Hub tracking: records keyed by tile plus per-tile coverage counts; dirty/refresh flags + // control when totals are recalculated + struct table distribution_hub_records; + struct table distribution_hub_coverage_counts; + bool distribution_hub_totals_dirty; + bool distribution_hub_refresh_in_progress; + + // Distribution Hub UI sprites loaded from PCX files for rendering food/shield icons in city interface + // *_icons_remaining counters track how many icons to draw from each source (non-district, district, hub, corruption) + Sprite distribution_hub_shield_icon; + Sprite distribution_hub_corruption_icon; + Sprite distribution_hub_food_icon; + Sprite distribution_hub_eaten_food_icon; + Sprite distribution_hub_shield_icon_small; + Sprite distribution_hub_food_icon_small; + int non_district_shield_icons_remaining; + int corruption_shield_icons_remaining; + int district_shield_icons_remaining; + int distribution_hub_shield_icons_remaining; + int district_corruption_icons_remaining; + int distribution_hub_corruption_icons_remaining; + + // District UI sprites loaded from PCX files for rendering yield icons (science, commerce, shield, food, culture, happiness) + // Available in both regular and small sizes for different UI contexts in city interface + Sprite district_science_icon; + Sprite district_commerce_icon; + Sprite district_shield_icon; + Sprite district_corruption_icon; + Sprite district_food_icon; + Sprite district_food_eaten_icon; + Sprite district_happiness_icon_small; + Sprite district_shield_icon_small; + Sprite district_commerce_icon_small; + Sprite district_food_icon_small; + Sprite district_science_icon_small; + Sprite district_culture_icon_small; + Sprite district_unhappiness_icon_small; + Sprite district_negative_shield_icon_small; + Sprite district_negative_commerce_icon_small; + Sprite district_negative_food_icon_small; + Sprite district_negative_science_icon_small; + Sprite district_negative_culture_icon_small; + + // Guard to prevent recursive sharing when auto-adding buildings across cities + bool sharing_buildings_by_districts_in_progress; + + // Worker tracking: 32 tables (one per civ), each mapping unit_id -> district_worker_record pointer + struct table district_worker_tables[32]; + + // Natural Wonder labels: table mapping natural wonder name strings to their IDs, count of defined natural wonders, + struct table natural_wonder_name_to_id; + + struct ai_candidate_bridge_or_canal_entry * ai_candidate_bridge_or_canals; + int ai_candidate_bridge_or_canals_count; + int ai_candidate_bridge_or_canals_capacity; + bool ai_candidate_bridge_or_canals_initialized; + + // City work radius highlighting: flag to enable/disable, table mapping tile pointers to highlight_level for visual feedback + bool highlight_city_radii; + struct table highlighted_city_radius_tile_pointers; + + // Initialized to 0. Every time Main_Screen_Form::m82_handle_key_event receives an event with is_down == 0, the virtual key code is prepended + // to this list. + int last_main_screen_key_up_events[5]; + + // Stores the parameters to Unit::can_load while it's running, NULL otherwise. + Unit * can_load_transport, * can_load_passenger; + + // Current tile being rendered in Map_Renderer_m19_Draw_Tile_by_XY_and_Flags. For use within various Map_Renderer::impl_m*_Draw_* functions. Nulled out after the render function is complete + Tile * current_render_tile; + struct district_instance * current_render_tile_district; + int current_render_tile_x, current_render_tile_y; + + // Used in patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp and so on for flagging whether to draw forests over roads on the tile being rendered + bool draw_forests_over_roads_on_tile; + + // Set to true once the auto-build process for the Great Wall is complete to avoid running it again + enum great_wall_auto_build_state great_wall_auto_build; + Tile * focused_tile; + + // Stores the improve ID currently being evaluated inside patch_City_can_build_improvement. + int current_evaluating_improve_id; + + // Stores the index in the list of target civs currently being drawn on the espionage form. Used to replace the civ name with its era-specific alias. + int espionage_form_drawing_target_index; + + // Tracks information about the last unit that was selected. These fields are updated when a new unit is selected or when the selected unit + // moves or is destroyed. + struct { + int initial_x, initial_y; // Stores the unit's location when it was selected + int last_x, last_y, type_id; // Stores the unit's current or last available location and type id + Unit * ptr; // A pointer to the unit, may be NULL if the unit was destroyed + } last_selected_unit; + + // Maps unit IDs to the level at which they are waiting. Units with lower levels move first. Units that have not been set to wait are not in the table. + struct table waiting_units; + + // Set to true when waiting_units has been initialized by loading from the save. Causes the game to skip clearing the table when setting up + // unit cycling for the turn. + bool have_loaded_waiting_units; + + // Used in patch_Unit_do_capture_units and patch_Unit_despawn + Unit ** extra_capture_despawns; + int count_extra_capture_despawns; + int extra_capture_despawns_capacity; + + // ========== + // } + // ========== +}; + +enum object_job { + OJ_DEFINE = 0, + OJ_INLEAD, // Patch this function with an inlead + OJ_REPL_VPTR, // Patch this function by replacing a pointer to it. The address column is the addr of the VPTR not the function itself. + OJ_REPL_CALL, // Patch a single function call. The address column is the addr of the call instruction, name refers to the new target function, type is not used. + OJ_REPL_VIS, // Patch a cluster of four function calls that make up a check of tile visibility. See implementation for details. + OJ_EXT_WALUP, // "EXTend Work Area LuP" Patch a jump instruction at the end of a "lup" (loop) over a city's workable area to extend it + OJ_IGNORE +}; + +struct civ_prog_object { + enum object_job job; + int addr; + char const * name; + char const * type; }; \ No newline at end of file diff --git a/default.c3x_config.ini b/default.c3x_config.ini index 60c232c2..32396c50 100644 --- a/default.c3x_config.ini +++ b/default.c3x_config.ini @@ -1,1158 +1,1171 @@ -[====================================================== C3X RELEASE 27 PREVIEW 1 DEFAULT CONFIG =====================================================] -[======================================================================= NOTE =======================================================================] -[Instead of editing this file, changes to the settings should be placed in either the scenario or custom config files. The scenario config file must ] -[be named scenario.c3x_config.ini and must be located in your scenario search folder. Of course it only applies if you are using a scenario. The ] -[custom config file must be named custom.c3x_config.ini and located in the C3X folder, which is the folder where this file is. When creating scenario] -[or custom configs, it is only necessary to include the settings you wish to change. ] -[====================================================================================================================================================] - -[============================] -[=== CONVENIENCE FEATURES ===] -[============================] - -enable_stack_bombard = true -enable_stack_unit_commands = true -enable_disorder_warning = true -show_detailed_city_production_info = true -enable_trade_screen_scroll = true -autofill_best_gold_amount_when_trading = true -skip_repeated_tile_improv_replacement_asks = true -group_units_on_right_click_menu = true - -; On the right click menu, units with no remaining moves will appear in gray text -gray_out_units_on_menu_with_no_remaining_moves = true - -; Places an icon next to units on the right-click menu showing their remaining moves & status. The icon is green for unmoved units, red for units that -; have exhausted all their moves, and yellow for those in between. Additionally it contains a little sword for units that can still attack and is -; colored blue for fighters set to intercept. -put_movement_icons_on_units_on_menu = true - -; Replaces the "Wake" or "Activate" text on the right-click menu with more descriptive words indicating what the unit is currently doing. For example, -; "Moving", "Intercepting", or "Working". -describe_states_of_units_on_menu = true - -show_detailed_tile_info = true -show_golden_age_turns_remaining = true - -; This option causes the game to show attack animations for units exerting zone of control from the middle of their tile's stack. Otherwise the game -; will only show such animations for units that are the top visible unit on their tiles. It was presumably an oversight by the original developers -; that units exerting zone of control do not temporarily become the visible unit on their tiles (unlike, for example, defensive bombard). -show_zoc_attacks_from_mid_stack = true - -; Fixes the defensive bombard animation being skipped when the unit performing defensive bombard is inside an army. -show_armies_performing_defensive_bombard = true - -cut_research_spending_to_avoid_bankruptcy = true -dont_pause_for_love_the_king_messages = true - -; Holding shift when clicking a specialist on the city screen will switch to the previous, instead of the next, specialist type -reverse_specialist_order_with_shift = true - -; Pressing the Z key on the city screen will zoom the map in/out -toggle_zoom_with_z_on_city_screen = true - -; When king units are spawned they're named after the leader of their civ. This is undesirable in modded games where the king flag is often used -; on units that aren't intended to be actual kings. This setting helps by bypassing the king unit naming logic when regicide is not enabled. -dont_give_king_names_in_non_regicide_games = true - -; One of the game's "Easter eggs" is that all king-flagged units appear as Elvis Presley on his birthday (Jan 8). This can be annoying when playing -; mods that make wide use of the king flag. -no_elvis_easter_egg = false - -; Removes option to automate workers from the human player. Useful for those who never want to use automation but sometimes accidentally activate it. -disable_worker_automation = false - -; There is a limit to how many links can appear on each Civilopedia page. Some mods exceed that limit. The problem is that the game throws up a popup -; when the limit is exceeded, one popup for each link beyond the limit. That can result in dozens of annoying, useless popups. This option stops them -; from appearing. Note: the game may also crash if the number of links far exceeds the limit. This option does not stop the crash, just the popups. -suppress_hypertext_links_exceeded_popup = true - -; Replaces the text "Upgrades To" with "Obsoleted By" in the Civilopedia for unit types that go obsolete but cannot be upgraded to their successors. -indicate_non_upgradability_in_pedia = true - -; Shows a message when a bomber gets intercepted by enemy air defense buildings but succeedes on its roll to avoid damage. Without this message, there -; is no indication that anything happened in that case except for the bomber losing one movement point. -show_message_after_dodging_sam = true - -; Normally only the last human player in a hotseat game gets to see the AIs move their units since the game processes the interturn while that player -; is still seated. This setting shows the AI moves to the other players in the game. It works by creating a save just before the interturn processing -; happens and then, at the start of the other players' turns, loads the save, sets that player as the seated one, reprocesses the interturn, then -; resumes the original game. -; Note: If the game is manually saved and reloaded, the replay will be lost. So it is recommended to save the game only after all human players have -; seen the replay, i.e. during the last or second to last human players' turns. -replay_ai_moves_in_hotseat_games = false - -; Normally, when you load a save, all units face southeast because the game didn't record which direction they were facing when the save was -; created. However, the game does record which tile they were on before their most recent move, so it is possible to deduce which direction they -; should be facing. That's what this option does. -restore_unit_directions_on_game_load = true - -; The game stores your map grid setting (on or off) in conquests.ini. It applies that setting after creating a new game, but not after loading a -; save. That was presumably an oversight and is corrected by this config option. -apply_grid_ini_setting_on_game_load = true - -; Causes cities to display harbor/airport icons if they have buildings that grant the relevant unit effects (produce veterans & heal in one turn) -; instead of buildings that grant sea/air trade. This makes no difference under the standard rules but is useful with mods that separate the unit -; effects and trade abilities into different buildings. -city_icons_show_unit_effects_not_trade = true - -; The game rules do not permit aircraft in an airfield to be damaged by bombardment. The interface allows players to order such bombardments anyway -; since its logic to check target validity is incomplete. This option completes the logic, causing the interface to reject attempts to bombard an -; airfield which would have no effect. -disallow_useless_bombard_vs_airfields = true - -; This option fixes a graphical bug that appears when the game is run on Linux using Wine. The bug is caused by the game using both Windows GDI and -; OpenGL to draw to the same canvas. Because the game only uses OpenGL to draw lines, it's relatively easy to solve this issue by reimplementing line -; drawing using Windows GDI+ instead. There are three possible settings for this option: -; never: Self-explanatory -; wine: This change will only be applied if the mod detects the game is running on Wine -; always: This change will always be applied, even on an actual Windows system -draw_lines_using_gdi_plus = wine - -; This option reduces the vertical distance between rows in the list of luxuries on the city screen. This allows up to 11 luxuries to be displayed -; neatly inside the box. -compact_luxury_display_on_city_screen = false - -; Similar to the option above, this one packs the strategic resources more tightly into the box on the upper left of the city screen. This allows up -; to 13 resources to be displayed there. -compact_strategic_resource_display_on_city_screen = false - -; Causes the domestic advisor to ask for confirmation before setting city production to a building that would replace another already built in the -; city. It's similar to how the domestic advisor warns you before a production switch would waste shields. Useful for modded games where you might not -; know which buildings replace which. -warn_when_chosen_building_would_replace_another = false - -; This option keeps citizens working the tiles they've been assigned to when pollution spawns there instead of converting them to specialists. This -; reduces micromanage but comes at the cost of the specialist yields. -do_not_unassign_workers_from_polluted_tiles = false - -; Normally the game draws capital cities one level larger than normal. I.e., a capital city at size 1 - 6 uses the graphic for cities at size 7 - 12, -; and a capital at size 7+ uses the graphic for cities 13+. This option turns that off, so capitals use the standard city graphics. -do_not_make_capital_cities_appear_larger = false - -; Tints coast and sea tiles on the minimap based on the culture that controls them, like is normally done for land tiles. -show_territory_colors_on_water_tiles_in_minimap = false - -; In offline games, shows some popup messages as online-multiplayer-style notes to the left of the screen instead of advisor popups that pause -; gameplay until dismissed. The point is to minimize interruptions during turn processing. Affects popups with the following text keys: -; SUMMARY_END_GOLDEN_AGE, SUMMARY_END_SCIENCE_AGE, SUMMARY_NEW_SMALL_WONDER, WONDERPRODUCE, MAKEPEACE, MUTUALPROTECTIONPACT, MILITARYALLIANCE, -; SUMMARY_DECLARE_WAR, TRADEEMBARGOENDS, SUMMARY_CIV_DESTROYED_BY_CIV, SUMMARY_CIV_DESTROYED, LOSTGOOD, TRADEEMBARGO, MILITARYALLIANCEWARONUS, -; MILITARYALLIANCEAGAINSTUS, and SUMMARY_TRAVELERS_REPORT. -convert_some_popups_into_online_mp_messages = false - -; If enabled, pressing the keys d e b u g to type "debug", in-game will allow you to activate debug mode for a game in progress. Typing that with -; debug mode already on will deactivate it. -enable_debug_mode_switch = true - -; Places a small shadow below city dots on the minimap to make them more easily visible especially against light-colored territory. This feature does -; not quite work properly so is left off by default. Its issues are (1) the shadows may not fully appear until you toggle the minimap from territory -; to geography mode and back again and (2) the shadows may appear in geography mode. -accentuate_cities_on_minimap = false - -; Makes the minimap twice as large. Possible values are "never", "always", and "high-def". The first two are self-explanatory; if set to "high-def", -; the minimap's size will be doubled when the game is run at a horizontal resolution of at least 1920 pixels. -double_minimap_size = high-def - -; Allows descriptions for units, civilizations, and game concepts to span multiple pages. If a DESC entry of one of those types is too long for one -; page, it will automatically be divided into multiple with buttons added for navigation. -allow_multipage_civilopedia_descriptions = true - -; Controls how the game searches for the next unit to autoselect. The possible choices are: -; standard: Base game behavior -; similar-near-start: The game will search for similar units near the starting point of the last selected unit. That means, when a unit is selected, -; the game remembers its location then searches out from there for a similar unit when cycling to the next one. Distance is prioritized over -; similarity, meaning the game will select all units on the starting tile no matter how dissimilar before any on nearby tiles. -; similar-near-destination: Like similar-near-start except the search goes outward from whatever tile the last selected unit was last on. -unit_cycle_search_criteria = standard - -; On the domestic advisor screen, tweaks how the number of turns remaining on each city build are displayed to improve readability. Instead of -; "(1turn)" or "(7turns)", the game will display "(1 Turn)" or "(7 Turns)" -reformat_turns_remaining_on_domestic_advisor_screen = true - -[====================] -[=== OPTIMIZATION ===] -[====================] - -; Rewrites the game's trade network computation logic to improve speed. On large maps with many cities, this computation takes up most of the -; interturn time so speeding it up greatly improves turn times. For more info, see the text file in the Trade Net X folder. -enable_trade_net_x = true - -; Rewrites parts of the game logic to improve efficiency. Those parts check every possible improvement defined in the scenario when they really only -; need to check a few. For example, to determine whether a city can trade via air, it's very wasteful to check every improvement since the vast -; majority of them do not enable air trade. This option can improve turn times very significantly in some circumstances. -optimize_improvement_loops = true - -; Displays a popup after each turn has been processed showing the time elapsed, including specifically how much time was spent recomputing trade -; networks. NOTE: Turning this on will skip all animations during the interturn so they don't contribute to the time. You aren't meant to play the -; game with this option left on. -measure_turn_times = false - -[=======================] -[=== AI ENHANCEMENTS ===] -[=======================] - -; Allows artillery unit AI to grab escorts from city defenders, causing the AI to use its artillery offensively instead of leaving it in its cities. -use_offensive_artillery_ai = true - -; If true, the AI will not escort its units unless they have the "requires escort" flag set in the editor. This allows modders to remove the escort -; requirement from certain types of units, for example artillery with non-zero defense. -dont_escort_unflagged_units = false - -; Set to a number to encourage the AI to build more artillery, set to false or <= 0 for no change in AI unit build choices. The number is how many -; artillery units the AI will try to keep around for every 100 non-artillery combat land units it has. The encouragement only applies if the AI is -; already above a minimum of one defensive unit per city and one offensive unit per two cities. Default: 16. -ai_build_artillery_ratio = 16 - -; The above option controls how many artillery the AI will keep around, this one controls how aggressively it builds up to that limit. More -; specifically it controls how valuable (in percent) the AI thinks artillery is as a damage dealer compared to attacking units. Default: 50. -ai_artillery_value_damage_percent = 50 - -; Like the artillery ratio, shifts the AI's build priority from fighters to bombers to keep around this many bombers per 100 fighters. Default: 70. -ai_build_bomber_ratio = 70 - -; Completely replaces the leader unit AI with custom code. The custom version is similar in spirit to the original but fixes several major issues: -; 1. It fixes a bug that allowed the AI to rush any kind of city production, including units and (with an MGL) wonders -; 2. Prioritizes army formation over rushing production when appropriate -; 3. When rushing, prioritizes wonders and costly improvements in high value cities -replace_leader_unit_ai = true - -; Replaces the AI code that determines whether a unit would be a good addition to an army. The replacement code fixes a major bug that prevented the -; AI from filling its armies, prevents the AI from including hidden nationality units in armies to avoid crashes, and removes some logic that -; encouraged the AI to mix unit types in armies. -fix_ai_army_composition = true - -; "Pop units" are special units whose only purpose is to be joined into cities to increase their population. Normally the AI does not know what to do -; with these units, so this option enables a routine that causes them to search for & join an appropriate city. Pop units only appear in some mods -; (for example Tides of Crimson). Under the standard game rules, this option has no effect. In order to function as a pop unit, a unit must use the -; terraform AI strategy, have no worker actions except join city, have a pop cost of at least 1, and have zero attack, defense, & bombard strengths. -enable_pop_unit_ai = true - -; "Caravan units" are special units whose only purpose is to be disbanded to contribute shields to a city. The name comes from the Civ 2 caravan. -; Caravan units may appear in some mods; under the standard game rules, this option has no effect. In order to function as a caravan unit, a unit must -; use the terraform AI strategy, have no worker actions enabled, have the ability to disband, and have zero attack, defense, & bombard strengths. -enable_caravan_unit_ai = true - -; In the base game, the AI will assign 1, 2, or 3 escort units to its naval transports and carriers depending in their shield cost and the number of -; units they're carrying. This option lets you reduce the upper limit on the number of escorts assigned. You can limit the number of escorts to 2, 1, -; or even 0. Setting this option >= 3 will result in base game behavior. The purpose of reducing the limit is to free up the AI's naval power units. -max_ai_naval_escorts = 3 - -; This controls how many workers the AI feels it needs as a percentage of the base amount. For example, if set to 150 (the default), the AI will build -; about 50% more workers than normal. Set to 100 for base game behavior. For more info, see: -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-95#post-16587093 -ai_worker_requirement_percent = 150 - -[=================] -[=== BUG FIXES ===] -[=================] - -; Descriptions of bugs and their fixes: -; SUBMARINE BUG -- The AI runs into invisible units (such as submarines) belonging to other players because it blindly follows paths produced for -; it by the game's pathfinder, which does not see invisible units. After colliding with an invisible unit, the AI initiates combat, declaring war if -; necessary. The mod fixes this bug by modifying the pathfinder so it sees invisible units belonging to other non-hostile players so it can route -; around them. -; SCIENCE AGE BUG -- The bonus science points generated by a scientific golden age are not actually counted towards research progress. They appear -; only on the interface. This is because of a small oversight in the code. There is a setting which controls whether or not science age bonus points -; are included while gathering all research points. It's turned off while gathering points to update research progress. The fix is to turn it on. -; PEDIA TEXTURE BUG -- There is a one pixel wide pink line on the right edge of the Civilopedia screen. This is because the width of the -; Civilopedia background texture is set one pixel too small inside the EXE. This is fixed simply by replacing the width with the correct value. -; BLOCKED DISEMBARK FREEZE -- When using "disembark all" (which the AI always does) on a boat containing units that can't be disembarked, the game -; may freeze as it endlessly tries to disembark them. The root of the problem is that the game's logic to check if there are any disembarkable units -; left on the boat is incomplete. There are two cases that it misses. First, it does not consider the "immobile" unit flag. This is fixed by making -; immobile units appear to have no remaining movement points for this bit of logic so they are correctly considered non-disembarkable. Second, it does -; not consider escort relationships (e.g. for settlers). If a unit has a non-disembarkable escorter then it also can't be disembarked because the game -; will always try to move its escorter ahead of it. The solution here is to clear all escort relationships for ship passengers before disembarking. -; HOUSEBOAT BUG -- The game may crash when an AI player is left alive with only a settler on a boat. This happens because the AI's logic tries to -; check the location of its capital city without considering that there may be no capital. The fix is to modify this logic so that when it looks up -; the location of a non-existent capital, it receives a valid "dummy" location that it can process without crashing. See also: -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16084386 -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16085242 -; INTERCEPT LOST TURN BUG -- When a human player sets a fighter to intercept mode, the game discards all of its remaining movement points, hence it -; cannot intercept during the next interturn. This bug does not affect the AI and is part of the interface logic, not the game logic. I presume it was -; inserted by a programmer who did not understand how the game's unit cycling works. The fix simply restores fighters' discarded moves. -; PHANTOM RESOURCE BUG -- The game only stores one full list of available resources per player. That list contains how many sources of each -; resource type are avaiable in that player's capital and all connected cities. Cities off the capital's network have reduced lists of just 32 bits, -; recording yes-or-no availability for up to 32 resources. Resources beyond the first 32 will share bits in those reduced lists. Specifically, the -; 33rd resource shares the same bit as the 1st, the 34th the same as the 2nd, and so forth. This causes "phantom" resources. For example, if a mod has -; horses set as the 1st resource and steel as the 33rd, then any city off its capital's trade network with access to horses will also have access to -; steel and vice-versa. The fix for this issue is straight forward but not simple. The jist is the mod allocates additional space for the reduced -; lists so they're not limited to 32 bits, rather have enough bits for every resource in the game. After that it's necessary to modify the code that -; accesses the reduced lists so it can make use of the additional space. -; MAINTENANCE PERSISTING FOR OBSOLETE BUILDINGS -- Players are not supposed to pay maintenance for obsolete city improvements however they often do -; because the game does not recompute maintenance after a player unlocks a technology that obsoletes a city improvement. There is a related exploit in -; that, after triggering a recomputation of maintenance, players can then sell their obsolete buildings to have the maintenance deducted again, -; effectively getting credited for the cost of maintenance. The mod fixes both issues. It recomputes maintenance costs when a player unlocks a -; technology that obsoletes a city improvement and it stops the game from deducting the maintenance cost of an obsolete city imp. when it's sold. -; BARBARIAN DIAGONAL BUG -- Barbarians can only search for targets on adjacent tiles or on tiles that are up to 12 steps directly SE or NW of their -; position. The intended behavior was for them to search for targets on all surrounding tiles up to 6 steps away. This bug was caused by a small, -; sloppy programming mistake that can be corrected with a small edit. For details, see: -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-70#post-16434678 -; DISEASE CURING TECH FLAG BUG -- In the base game, the tech flag "Disables Diseases From Flood Plains" (applied to Sanitation) does nothing and -; instead flood plains disease stops once players discover Writing. This happens because that flag is encoded as number 8 and, instead of checking if -; players have a tech with that flag, the code mistakenly checks if players have tech #8, which is Writing under the standard rules. Correcting this -; bug causes a lot more disease, which is a major annoyance, and so this bug fix is turned off by default. -; DIVISION BY ZERO IN AI ALLIANCE EVAL -- When considering whether to agree to a military alliance, the AI computes the distance from its capital to -; the nearest city belonging to the target of the alliance and divides by that distance. For unknown reasons, in rare cases that distance may be zero, -; which crashes the program due to division by zero. The mod fixes this issue by inserting a bit of logic after the distance is computed to check if -; it's zero and, if so, set it to one. -; EMPTY ARMY MOVEMENT -- Empty armies have one less than a full move's worth of movement points regardless of how many moves their unit type has set -; in the editor. Under the standard game rules, this means they can only move two tiles along roads. The cause is a small mistake in the logic that -; attempts to find the slowest member among units in the army. The mod fixes this bug by reimplementing the max movement point calculation for armies. -; PREMATURE TRUNCATION OF FOUND PATHS -- If the game attempts to find a path for a unit that's more than 256 tiles long, the path will not be -; returned properly from the pathfinder. That's because the pathfinder stops reconstructing the final path once it reaches a length of 256. That -; creates a serious problem for long paths because reconstruction works from the end of the path toward the start, so stopping early produces an -; incorrect path that begins in the middle. The fix is simply to multiply the maximum length by 10 (to 2560). Removing the limit entirely risks -; allowing infinite loops. This bug is rarely visible in-game, it usually appears as AI naval units following inappropriate or invalid paths. -; ZERO PRODUCTION CRASH -- If a city has zero production, which is possible using specialists modded to produce negative shields, the game will -; crash due to a division by zero. -; AI CAN SACRIFICE WITHOUT SPECIAL ABILITY -- The base game function that gates the AI's ability to sacrifice units does not check whether the unit -; in question has the sacrifice special ability set on its type. Thus, AIs are allowed to sacrifice any captured units as long as they have the -; required tech. The mod fixes this by patching the gating function to insert the missing condition. -; AI CAN FORM ARMY WITHOUT SPECIAL ABILITY -- Similar to the above issue, the AI's ability to form armies with leader units is not gated by those -; units having the "build army" special ability. -; CRASH IN LEADER UNIT AI -- The base game's AI routine for leader units may crash due to uninitialized variables. -; FAILURE TO FIND NEW CITY BUILD -- After a city completes production, the game searches for a new build for it. If that city is owned by the seated -; player, whatever the game finds will be filled in as the default option in the domestic advisor popup asking the player to choose a new build. If -; the search fails to find anything, there will be no default option, the dropdown selector will not be initialized, and the game will crash when it -; tries to open the popup. To fix this, the mod detects when the game has failed to find a new build option and fills in Wealth instead or, failing -; that, any unit or improvement that the city can build. -; PASSENGERS OUT OF ORDER ON MENU -- When there are multiple doubly-contained units (meaning units contained in other units that are themselves -; contained in something, like a unit in an army on a transport) on a tile, the game will not always show the passenger units in the correct locations -; on the right-click menu. To fix this, the mod double checks the order of the entries on the menu to make sure that passenger units are listed just -; after the unit they're contained in. -; PATCH EMPTY ARMY COMBAT CRASH -- Guards a crash in the army combat selection routine by returning the army unit itself if it has no contained -; units (prevents divide-by-zero in the vanilla selection loop). - -patch_submarine_bug = true -patch_science_age_bug = true -patch_pedia_texture_bug = true -patch_blocked_disembark_freeze = true -patch_houseboat_bug = true -patch_intercept_lost_turn_bug = true -patch_phantom_resource_bug = true -patch_maintenance_persisting_for_obsolete_buildings = true -patch_barbarian_diagonal_bug = true -patch_disease_stopping_tech_flag_bug = false -patch_division_by_zero_in_ai_alliance_eval = true -patch_empty_army_movement = true -patch_premature_truncation_of_found_paths = true -patch_zero_production_crash = true -patch_ai_can_sacrifice_without_special_ability = true -patch_ai_can_form_army_without_special_ability = true -patch_crash_in_leader_unit_ai = true -patch_failure_to_find_new_city_build = true -patch_passengers_out_of_order_on_menu = true -patch_empty_army_combat_crash = true - -; At the beginning of each AI player's turn, deletes any units of theirs that are not on a valid tile. This addresses a rare crash that can occur when -; the unit AI invokes the pathfinder for an off-map unit. I don't know how AI units can end up off the map in the first place. -delete_off_map_ai_units = true - -; On the city screen, the icons for different kinds of specialist yields get drawn over top of, instead of beside, one another. This setting fixes -; that so they are displayed properly. -fix_overlapping_specialist_yield_icons = true - -[======================] -[=== LIMITS REMOVED ===] -[======================] - -remove_unit_limit = true -remove_city_improvement_limit = true - -; The city limit can be configured up to a maximum of 2048 or down to a minimum of 0. For base game behavior, set to 512. -city_limit = 2048 - -; Increases the cap on the game turn limit from 1000 to 1000000 -remove_cap_on_turn_limit = true - -; Be warned: the no era limit feature is incomplete, untested, and not likely to work at this time -remove_era_limit = false - -[=========================] -[=== ENGINE EXTENSIONS ===] -[=========================] - -; These "NoRaze" options can stop cities from being destroyed. "Autorazing" refers to the automatic destruction of size one, cultureless cities. If -; autorazing is prevented, players will be given the option to keep the city. If razing by players is prevented, neither the human player nor AIs will -; be allowed to raze or abandon cities. -prevent_autorazing = false -prevent_razing_by_players = false - -; These options allow you to adjust the minimum allowed distance between cities. minimum_city_separation controls the minimum number of tiles between -; cities so, e.g, if it's set to 1, cities cannot be founded adjacent to one another, there must be at least one open tile separating them. A setting -; of 1 there corresponds to the standard game rules. disallow_founding_next_to_foreign_city is an optional additional restriction. If it's enabled, -; cities may not be founded adjacent to a city belonging to another civ regardless of the minimum separation. It is only relevant when the minimum -; separation is set to zero. -minimum_city_separation = 1 -disallow_founding_next_to_foreign_city = true - -; Set to a number to limit railroad movement to that many tiles per turn. To return to infinite railroad movement, set to false or a number <=0. By -; default, all units travel the same distance along limited rails like in Civ 4, but this can be changed by toggling the next option below. -; NOTE: For best results, the railroad limit should be a multiple of the "movement rate along roads" set in the editor (usually 3). The limitation -; will work in any case, but setting the limit this way helps avoid an integer overflow issue inside the pathfinder that may cause it to fail to find -; the shortest paths for units with a large number of available moves. -limit_railroad_movement = false - -; If set to true, limited railroads will work like fast roads instead of Civ 4 style railroads. The movement rate along fast roads is determined by -; the limit_railroad_movement setting above. If that setting is false or <= 0, this option does nothing. -limited_railroads_work_like_fast_roads = false - -; This option lets you put a limit on how many units may occupy each tile. The limit applies separately for land, sea, and air units. You may set the -; limit differently for each of those classes by setting this option to a list of three numbers. If you set it to a single number, that limit amount -; will apply to all three. If you set it to false or a number <= 0, no limit will apply, as in the base game. Some examples: -; To limit tiles to 5 land, 5 sea, and 5 air units: limit_units_per_tile = 5 -; To limit tiles to 5 land and sea units but 10 air units: limit_units_per_tile = [5 5 10] -; To limit only air units to 10 per tile: limit_units_per_tile = [false false 10] -; To have no limit (as in the standard game rules): limit_units_per_tile = false -; NOTE: The two options below let you exclude cities or certain unit types from the limit. -limit_units_per_tile = false - -; Allows an unlimited number of units to occupy tiles with cities when the unit limit is in force. When the limit (option above) is deactivated, this -; option does nothing. -exclude_cities_from_units_per_tile_limit = false - -; Allows certain unit types to be exempt from the stack limit. Units of these types will not be stopped by the limit and will not count toward it -; (will not stop others). This option is a space separated list of unit type names. Multi-word names must be wrapped in quotes. For example: -; [Worker Settler Flak "Mobile SAM"] -; This option does nothing if limit_units_per_tile is set to false. -exclude_types_from_units_per_tile_limit = [] - -enable_free_buildings_from_small_wonders = true -allow_stealth_attack_against_single_unit = false -disallow_trespassing = false -enable_land_sea_intersections = false - -; All anarchy lengths will be multiplied by this amount as a percent. For example, if set to 50, anarchy length will be reduced by half. Set to 100 -; for standard game behavior. There is a minimum anarchy length of 2 turns, but you can remove anarchy entirely by setting this option < 0. -anarchy_length_percent = 100 - -; Add perfume to an improvement or unit type to encourage the AI to build it more often. When choosing what to buld, the AI computes a point value for -; each of its options and the mod will add the perfume amount to the point total for each named option. For reference, point values are often in the -; hundreds for the most desirable options. You can see the point value the AI gives to every available build by pressing P while viewing one of its -; cities. Perfume amounts can also be specified as a percentage, ex. a perfume amount of 15% will increase the AI's evaluation by 15% and an amount of -; -50% will reduce it by half. -; production_perfume is a list of names and amounts, each one looks like "name": amount -; Here's an example: ["Granary": 15, "Colosseum": -20%, "Courthouse": 30] -; The quotation marks around a name are not necessary if the name is all one word (i.e. does not include spaces) and is made up of only letters, -; digits (0-9), periods, hyphens, or underscores. The category of letters includes the normal English a-z and A-Z as well as accented variants -; (e.g. ä, ö, ñ, ç) and all other non-English letters available in the Windows-1252 encoding (e.g. ß, þ, æ). -production_perfume = [] - -; Add perfume to a technology to change how valuable the AI judges the tech to be. Each point of perfume is worth roughly one gold in trade, and also -; affects what the AI chooses to research. The format matches production_perfume above, ex.: [Medicine: 500, Fascism: -50%, "Replacable Parts": 20%]. -technology_perfume = [] - -; Add perfume to a government to encourage or discourage the AI from switching to that type. The format follows the other perfume options, ex.: -; [Republic: 10%, Fascism: -30%]. Unfortunately I don't know how much each point is worth in this context. I also don't know how perfuming governments -; affects the AI's willingness to overthrow its current govt. The perfume for sure applies when the AI is selecting a new govt type after anarchy. -government_perfume = [] - -; The AI production ranking is the point value the AI gives to each available build in some city. To view it, press P while viewing an AI city. -enable_ai_production_ranking = true - -; Shades/highlights each tile to show how desirable the AI considers it as a city location. To activate, press L while in game. The scale goes from -; white (least desirable) to red (most desirable) with yellow in between. Also the exact number the AI gives any tile can be seen on its info box. -; If show_ai_city_location_desirability_if_settler is true, the desirability overlay will automatically appear when a settler is selected. -enable_ai_city_location_desirability_display = true -show_ai_city_location_desirability_if_settler = false - -; Setting a government's corruption level to "OFF" will remove all corruption, as expected, instead of maximizing it -zero_corruption_when_off = true - -; Prevents land settlers/workers on transports from settling/improving water tiles. This option does not affect the vanilla game but is useful for -; mods that enable city building or improvement of water tiles. -disallow_land_units_from_affecting_water_tiles = true - -; Allows units to move after airdropping by making airdrops cost no movement. Under the standard game rules, units lose all their remaining moves -; after airdropping. Units will be prevented from airdropping more than once in the same turn. -dont_end_units_turn_after_airdrop = false - -allow_airdrop_without_airport = false -enable_negative_pop_pollution = true - -; Here it's possible to set buildings as prerequisites for unit production. It's possible for a unit type to have multiple prereq buildings up to a -; maximum of 10, and all must be present in a city for the unit to be buildable. -; The format is a list of building names and unit type names, each one looks like "building name": "unit type 1" "unit type 2" ... -; Quotation marks around names can be omitted like in production_perfume (see above). -; Here's an example: -; [Factory: Tank "Modern Armor", -; Barracks: Swordsman Cavalry Tank "Modern Armor", -; Airport: Bomber] -building_prereqs_for_units = [] - -; Here it's possible to set buildings to generate resources. Those resources can be added to the trade network or limited to the building's city. The -; format is a list of building name and resource name pairs with optional "local", "no-tech-req", "yields", "show-bonus", and/or "hide-non-bonus" -; settings before each resource name. Example: -; ["Steel Mill": Steel, Terrace: yields show-bonus Rice, "Coal Liquefaction": local Oil, Supercollider: local no-tech-req Antimatter, -; "Hydro Plant": local "Electric Power"] -; Quotation marks around names can be omitted like in production_perfume (see above). -; The "local" setting means that the produced resource will not be added to the trade network, it will be available only in the building's city. -; The "no-tech-req" setting means that the resource will be produced even for players who do not have the technology to reveal it on the map. -; The "yields" setting means that the resource's tile yields will be added to the city as if it were on a worked tile. -; The "show-bonus" setting means that an icon for the generated resource will be displayed on the city screen even if it's a bonus resource. -; The "hide-non-bonus" setting is the opposite of show-bonus. It means an icon will NOT be shown if the resource is of strategic or luxury type. -; Buildings will not generate resources if the resource requirement for the building itself is not met. This makes it possible to set up resource -; production chains. Note for modders: Production chains require the input resources to be listed before the outputs in the scenario data, when the -; inputs also come from buildings. For example if you have iron ore on the map, a building that requires it and produces iron, and a building that -; requires iron and produces steel, iron must be listed before steel in the scenario data or the chain won't work. This is because building resource -; generation is calculated in the same order as the generated resources appear in the scenario data. This limitation does not apply to map resources -; (iron ore in the example) as access to all map resources is calculated first before any building resources. -buildings_generating_resources = [] - -; Shows a warning in case some of the unit, building, or resource names in this config file don't match anything in the scenario data. -warn_about_unrecognized_names = true - -; Overrides the rules for when units are eligible to retreat based on their movement. The possible options are: -; standard: No change from base game rules -; none: No units will ever retreat -; all-units: All non-immobile units may retreat, even if they have only one move or are up against a faster opponent -; if-faster: Units may retreat when they are faster than their opponent, for example a cavalry may retreat from a knight -; if-not-slower: Units may retreat when they are at least as fast as their opponent, for example a knight may retreat from another knight but not -; from a cavalry, and an infantry may retreat from another infantry -; if-fast-and-not-slower: Like if-not-slower but only fast (2+ move) units may retreat -; These settings don't change the fact that units cannot retreat when they start combat with 1 HP or are defending a city. They also do not change -; that naval units cannot retreat defensively (there is a separate option for that below). -land_retreat_rules = standard -sea_retreat_rules = standard - -; Under the base game rules, no unit may retreat defensively if it's located on a water tile. This option removes this special rule so naval units can -; retreat defensively like land units do. See also: the sea_retreat_rules option above and the limit_defensive_retreat_on_water_to_types option below. -allow_defensive_retreat_on_water = false - -; If any unit types are listed here, defensive retreat on water tiles will be limited to those types. Otherwise, all types may retreat that way. The -; list is separated by spaces and multi-word type names must be wrapped in quotation marks. For example, setting to: -; [Submarine "Nuclear Submarine"] -; would mean that only those submarine naval units could retreat defensively. This option does nothing if allow_defensive_retreat_on_water is false. -limit_defensive_retreat_on_water_to_types = [] - -; The multi-city start spawns in multiple cities for AI players at the start of the game instead of their usual one settler. This option controls the -; number of cities the AI starts with. E.g., if it's set to 2, the AI starts with 2 cities. If it's set <= 0, the game starts like normal. The mod can -; also add improvements to the AI's extra cities, which are intended to work like extra palaces, see ai_multi_start_extra_palaces. -ai_multi_city_start = 0 - -; This option only applies if ai_multi_city_start is set > 1. It controls how many tiles the mod will randomly check while searching for a suitable -; location for each of the AI's extra starter cities. Default: 10000. -max_tries_to_place_fp_city = 10000 - -; This option only applies if ai_multi_city_start is set > 1. It specifies a list of improvements to be added to the AI's additional cities. E.g: -; ["Forbidden Palace" Courthouse] -; If the AI multi-city start is set to 3+ with the above extra palaces, the AI players will start with 3+ cities and the first one will have the -; Palace like normal, the second will have the Forbidden Palace, and the third will have a courthouse, any after that will start empty. -; Additionally, any small wonders listed here with the "reduces corruption" effect will be considered "extra palaces" for the AI. They will respawn -; like the real Palace. In other words, if an AI loses a city with an extra palace, it will reappear in another one of its cities following the same -; logic the game uses to select a new Palace location. If the AI is missing an extra palace and acquires a new city, that extra palace will -; automatically be added to the new city. -ai_multi_start_extra_palaces = [] - -; Turning this on makes small or great wonders with the "reduces corruption" effect, such as the Forbidden Palace, as effective at reducing corruption -; as the palace itself. This reduces corruption not only in the city that contains such a wonder, it also reduces distance and rank corruption in -; nearby cities as if the city were an additional capital. -promote_wonder_decorruption_effect = false - -allow_military_leaders_to_hurry_wonders = false - -; The AI's beaker production will be multiplied by this amount, as a percent. A value of 100 gives you the standard game behavior, a value of 75 -; reduces AI research by 25%, a value of 200 doubles AI research, and so on. -ai_research_multiplier = 100 - -; Each time an AI player founds a city, the given amount of perfume will be applied to its settlers over the given duration in number of turns. The -; perfume effect declines steadily to zero over the duration. The perfume amount may be specified as a percentage. The purpose of these options is to -; slow the AI's expansion with negative perfume. -; NOTE: The AI has a very strong tendency to build settlers so you'll need to set these options quite high to slow it down significantly. For example, -; a perfume of -200% over a 30 turn duration left the AI with about half as many cities after 50 turns in my test. -ai_settler_perfume_on_founding = 0 -ai_settler_perfume_on_founding_duration = 0 - -; If a player can't afford to pay maintenance on their buildings and units, the game will forcibly lower expenses and raise money by (in order): -; 1. Selling buildings, excluding those that are maintenance-free or contribute to gold production even indirectly -; 2. Disbanding units, excluding free ones -; 3. Switching cities to building Wealth -; For AI players, the game alternates the order of (1) and (2) each turn. Also for AIs, on every third turn, the game will cut their research spending -; as much as necessary to avoid bankruptcy. -aggressively_penalize_bankruptcy = false - -; Under the standard game rules, the Despotism tile penalty does not apply to food yield from city tiles of Agricultural civs with fresh water. Set -; this option to true to remove that exception to the penalty. -no_penalty_exception_for_agri_fresh_water_city_tiles = false - -; Adds an option to the stealth attack target selection popup that allows the player to opt out of doing a stealth attack. If selected, the unit will -; attack normally, targeting the tile's top defender. Similarly, if stealth bombardment is canceled, the unit will bombard normally and may target -; buildings or population if attacking a city. -include_stealth_attack_cancel_option = false - -; Aircraft flying a recon mission can be intercepted by enemy fighters or ground AA as if they were flying a bombing mission -intercept_recon_missions = false - -; Under the standard rules, performing a recon mission or intercepting an attacker causes a unit to lose all of its remaining moves. Setting this -; option to true causes those actions to only consume one move. This makes them consistent with other air missions like bombing. Note: fighters will -; only be able to intercept multiple times in one turn if they have the blitz ability. -charge_one_move_for_recon_and_interception = false - -; In the base game, precision striking was only intended to be used by bombers. This option extends the precision strike logic to cover land & sea -; artillery and cruise missiles. Specifically what it does is: -; 1. Fixes the animations, so land & sea artillery will play their bombard animations and cruise missiles will play their strike animation -; 2. Makes it so that the strikable range depends on the bombard range for land & sea units instead of operational range -; 3. Despawns cruise missiles after they've performed a precision strike -polish_precision_striking = true - -; Enables units to perform stealth attacks when they bombard or bomb a target. Like regular stealth attacks this opens a popup allowing the player to -; choose a specific unit to target. The attacking unit must have the stealth attack special action checked, must have a list of stealth attack targets -; set, and the target tile must be visible. -enable_stealth_attack_via_bombardment = false - -; Prevents aircraft from being damaged by bombardment or bombing -immunize_aircraft_against_bombardment = false - -; Unit type names listed here will use PTW-like targeting when bombarding cities. PTW-like means there is a 1-in-3 chance they will target each of -; population, buildings, and units. This is unlike Conquests artillery targeting, which always goes after units first. Items in the list are separated -; by spaces and multi-word items must be wrapped in quotation marks like for perfume specs. Example: [Catapult Cannon Artillery "Radar Artillery"] -ptw_like_artillery_targeting = [] - -; Changes the meaning of the charm attack flag to indicate PTW-like targeting. This is a matter of convenience. It allows modders to specify PTW -; targeting using an editor, instead of the list above, at the cost of losing the charm attack function. -charm_flag_triggers_ptw_like_targeting = false - -; Unit types listed here won't be allowed to bombard land tiles. Same format as ptw_like_artillery_targeting, example: [Submarine "Torpedo Bomber"] -can_bombard_only_sea_tiles = [] - -; Units with the king ability will defend like normal, instead of always being the last to defend in a stack. Useful for mods that use the king flag -; for special purposes. Does not apply in regicide games. -ignore_king_ability_for_defense_priority = false - -; Untradable techs will appear grayed out on the trade screen. This lets you see which untradable techs the AI has just like for tradable -; ones. "Untradable" means techs that have been flagged as "cannot be traded" in the editor. This option only matters for modded games as there are no -; untradable techs in the standard game. -show_untradable_techs_on_trade_screen = false - -; Barbarians will capture cities instead of ransacking them. This option also modifies the game's production logic so barbarian cities can build -; things, grow, and even do research. -; This feature is EXPERIMENTAL at the moment. It basically works but hasn't been extensively tested. For example, I don't know what would happen if -; the barb player were to win the game. -; Because of how barb city production works under the hood, it requires barb activity to be turned on in order to work. The mod will handle this -; automatically. If this option is enabled, there is at least one barb city on the map, and the barb activity level is set to 0 (no barbarians), the -; level will be increased to 1 (sedentary) in order not to block barb city production. -enable_city_capture_by_barbarians = false - -; A list of modifications to the rules for defensive bombard. "Defensive bombard" is the free shot a bombard unit gets when the stack it's in is -; attacked. The possible options are: -; lethal: Attackers may be destroyed by defensive bombard if the bombarding unit has the appropriate lethal land/sea bombard ability. -; aerial: Air units may perform defensive bombard if they can perform bombing missions. -; not-invisible: Attacking units are immune to defensive bombard if they are invisible and not detected. -; blitz: Units with blitz may perform defensive bombard multiple times per turn, once for each move they have. -; docked-vs-land: Docked ships (i.e. in a city) can perform defensive bombard against land units attacking their city. -; For example, to activate all options, set to [lethal aerial not-invisible blitz docked-vs-land]. The order of items in the list does not matter. You -; can also activate all options by setting to [all] (with or without the brackets). -special_defensive_bombard_rules = [] - -; A list of modifications to the rules for zone of control, like above for defensive bombard. The possibilities are: -; amphibious: Land units may exert zone of control over sea units and vice-versa. This can only be done using bombard strength, not attack -; strength. It also requires non-zero bombard range. -; lethal: Units may be destroyed by zone of control. The intercepting unit must have the lethal bombard ability in order to do this, even if it's -; using its attack strength to exert ZoC. -; aerial: Air units can exert zone of control if their type has the "Zone of Control" option checked. Additionally, they must be able to perform the -; bombing mission, have non-zero bombard strength, and non-zero operational range. -; not-from-inside: Land units may not exert zone of control while inside a transport (armies do not count as transports) -; Like for defensive bombard, all options can be activated by setting to [all] (with or without the brackets), and order does not matter. -special_zone_of_control_rules = [] - -; All human players in a hotseat game will share visibility -share_visibility_in_hotseat = false - -; All human players in a hotseat game will share the effects of the wonders they've built, great or small. This applies to all civ-wide effects, for -; example if any human player builds Leonardo's Workshop, all human players get half price upgrades. Notes: -; 1. If a human player receiving the shared effect of a small wonder and that SW has no non-shared effects, it becomes unbuildable for that player. -; 2. Building and army requirements for wonders are shared as well. For example, all human players are allowed to build Battlefield Medicine once all -; of them combined have five hospitals. -; 3. For the Great Library effect, known AI civs are shared as well. If an AI has contact with any human player, it is considered to be in contact -; with all of them for the purpose of granting techs to human players. -share_wonders_in_hotseat = false - -allow_precision_strikes_against_tile_improvements = false -dont_end_units_turn_after_bombarding_barricade = false - -; Allows land units to bombard aircraft and naval units in cities -; This does not override the immunity of aircraft vs bombardment, if that option is also activated. -remove_land_artillery_target_restrictions = false - -; Allows tile improvements on a tile with an occupied airfield to be destroyed by bombardment, not including the airfield itself. For example, under -; the standard game rules, if you bombard a tile with a road, airfield, and fighter on it, you will do no damage because the attack will target the -; fighter which is invulnerable (aircraft in an airfield cannot be damaged by bombardment). This option allows such an attack to bypass the fighter -; and hit the tile instead, as long as that tile has an improvement other than the airfield. -allow_bombard_of_other_improvs_on_occupied_airfield = false - -; Displays the total number of cities in the game on the demographics screen (press F11). -show_total_city_count = false - -; Under the standard game rules, each forbidden-palace-like building in an empire increases its optimal city number (OCN) by 37.5% of the base number, -; except if the empire is running a government with communal corruption, in which case the increase is 100% of the base. With this option enabled, the -; communal corruption rule is always in force, so each forbidden palace always increases the OCN by an amount equal to the base number. -; NOTE: The "base" optimal city number comes from the map size. It's the number set on the "World Sizes" tab in the editor. -strengthen_forbidden_palace_ocn_effect = false - -; This option allows you to increase the maintenance cost of units depending on their shield cost. For every X shields that the unit costs to build -; (where X is the setting below), the unit's maintenance increases by one unit's worth. For example, if set to 100, units that cost 0-99 shields will -; have normal maintenace, units costing 100-199 shields will cost double, those costing 200-299 will cost triple, etc. (Note the final cost in GPT -; depends on gov't type). Set <= 0 to disable. -extra_unit_maintenance_per_shields = 0 - -; This option renames players' civs depending on their eras. The format is a list of names each associated with a list of replacements. There is one -; replacement for each era or, if the list is shorter than the number of eras, no replacement will be done in the later eras. Example: -; [Rome: Rome "Byzantine Empire" Italy Italy, -; Roman: Roman Byzantine Italian Italian, -; France: Gaul, French: Gaulic] -; In this example, Rome will be renamed to "Rome" in the first era, "Byzantine Empire" in the second, and "Italy" in the third and fourth. The -; adjectives will be replaced to match. France/French will be renamed to Gaul/Gaulic only in the first era. -; Spaces are used to separate words so if a name or replacement has multiple words it's necessary to use quotation marks to group them together like -; for "Byzantine Empire" in the example. -; The replacements apply to civ nouns, adjectives, and formal names. If a player has put in a custom name, that will not be replaced. -civ_aliases_by_era = [] - -; This option works like the one above except it replaces leader names instead of civ names. Each replacement name may be followed by (M) or (F) to -; specify gender. Example: -; ["Joan d'Arc": Vercingetorix (M) "Joan d'Arc" (F) Napoleon (M) "De Gaulle" (M)] -; If no gender is specified then the game will use whatever gender was set in the scenario data for that civ's leader. That means (F) could be omitted -; in the above example since the leader of France is already female. -; Additionally you can include a replacement title after the gender separated by a comma. Here's the example with titles added: -; ["Joan d'Arc": Vercingetorix (M, King) "Joan d'Arc" (F) Napoleon (M, Emperor) "De Gaulle" (M, President)] -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 -; 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. -; 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. -unit_limits = [] - -; Removes barracks/harbor/airport requirement from upgrades -allow_upgrades_in_any_city = false - -; Stops the game from placing volcanos during map generation. Any tiles that would have been volcanos will be mountains instead. -do_not_generate_volcanos = false - -; Stops the game from placing pollution on impassable tiles -do_not_pollute_impassable_tiles = false - -; Includes the hitpoints of each possible target on the stealth attack selection popup. This makes it easier to pick out weakened units. -show_hp_of_stealth_attack_options = false - -; Stops invisible units from being targeted by stealth attacks. They can still be targeted if they've been revealed by the attacking civ. -exclude_invisible_units_from_stealth_attack = false - -; Stops units from being targeted by stealth attack if they are contained in another unit such as a naval or land transport, or a helicopter. -exclude_passengers_from_stealth_attack = false - -; Normally planting a forest always produces the regular non-LM forest terrain. This option changes that so it instead produces LM forest. -convert_to_landmark_after_planting_forest = false - -; This option specifies how likely it is (in percent) for a combat land or sea unit with a maximum of one HP to be destroyed when struck by a -; nuke. Set to 100 for base game behavior. -chance_for_nukes_to_destroy_max_one_hp_units = 100 - -; Allows you to sell aqueducts and hospitals as well as any modded buildings that uncap population growth. A city must be below the pop cap for a sale -; to be allowed, i.e., under the standard rules, aqueducts may only be sold in cities of pop <= 6 and for hospitals pop <= 12. -allow_sale_of_aqueducts_and_hospitals = false - -; Allows you to sell Small Wonders. This may be useful to relocate Forbidden Palace-like Small Wonders. -allow_sale_of_small_wonders = false - -; This option makes it so that only sea units with the "detect invisible" ability can reveal invisible sea units, and likewise for non-sea units. -no_cross_shore_detection = false - -; Controls the size of the area in which cities can work tiles. The value corresponds to cultural border expansions. For example, setting this to 1 -; means cities would only be able to work tiles within their level 1 cultural borders, meaning the eight tiles neighboring the city's own -; tile. Setting to 2 gives you the game's standard rule that cities may work tiles within their level 2 cultural borders, which they attain after one -; expansion. Setting to 3 allows them to work within level 3 borders and so forth. -; Notes: (1) If the city can work tiles in the fourth ring or farther, the map view on the city screen will be zoomed out when you enter it if -; auto_zoom_city_screen_for_large_work_areas is true. Otherwise it's not possible to show the entire work area. You can zoom back in by pressing Z. -; (2) The next option below can limit cities' workable areas to be smaller than the radius set here, based on their culture. (3) This option has a -; minimum value of 1 and a maximum of 7. -city_work_radius = 2 -auto_zoom_city_screen_for_large_work_areas = true - -; This option can reduce the size of the area cities can work based on their cultural level. -; Possible values are: -; none: Standard game rules apply; cities can work any tile that's within the work radius and within their owner's borders. -; cultural: Cities may only work tiles that are within their direct cultural borders, e.g. a city with zero culture may only work the 8 surrounding -; tiles. After one expansion, it may work the standard 20, after a second expansion it may work the third ring, and so on. -; cultural-min-2: Like "cultural" except cities can always work their standard 20 tiles. -; cultural-or-adjacent: Cities can work tiles in their direct cultural borders plus any tiles adjacent to those. -work_area_limit = none - -; This option can also reduce the size of the area cities can work based on improvements present. -; This mechanic works in tandem with the above work_area_limit condition - tiles cannot be worked if the tiles do not also meet the cultural work area limit requirement. -; If left empty, this mechanic is not used. -; Improvements may be defined to grant a certain radius work area, and the highest radius present is used as the work radius for a city. eg ["Harbor": 3] -; Improvements may also grant a bonus radius, these are added on after the highest radius is found. [Factory: 3, "Mass Transit": 2 extra] -; An entry written as default or "default" will always be present for any given city, and represents an always-present virtual improvement. eg. ["default": 2] gives vanilla behaviour. -work_area_improvements = [] - -; The maximum distance it's possible to rebase an aircraft equals its operational range times this value. For standard game rules, set to 6. -rebase_range_multiplier = 6 - -; This option prevents units from loading into two different transports on the same turn. Once a unit has been loaded into a transport, it becomes -; tied to that transport for the remainder of the turn and cannot be loaded into any other. Loading into armies is not affected. The purpose of this -; option is to make the galley chaining exploit impossible. -limit_unit_loading_to_one_transport_per_turn = false - -; In the base game, if you set Cavalry to upgrade to Tank but don't give it the upgrade ability, intending to make Cavalry obsolete when Tanks become -; available but not upgradable to them, you'll be left with the strange situation that older units such as Knights are allowed to upgrade to Tanks -; even though Cavalry are not. This option makes it so that Knights upgrade to Cavalry in that case. In general, it makes it so that upgrade chains -; stop at the type along the chain that does not have the upgrade ability. -; NOTE: The chain is only stopped if the civ in question can build the unit type. The example above is simplified. In the actual rules, Cavalry -; upgrades to Sipahi, which upgrades to Cossack. Blocking the upgrade chain at Cavalry would prevent Ottomans and Russia from upgrading to their -; unique units, so the mod won't do that. You must clear the upgrade ability from Sipahi and Cossack as well to block those civs there instead. -prevent_old_units_from_upgrading_past_ability_block = false - -; Buildings double their culture production this many years after they were built. For standard game rules, set to 1000. -years_to_double_building_culture = 1000 - -; Controls how long it takes for wonders to produce tourism gold as a percent of the standard rate. For example, if set to 200, it would take 2000 -; years to begin generating 2 GPT tourism, instead of the standard 1000 years, and 3000 years for 4 GPT, instead of the standard 1500. This setting is -; effectively a scaling factor on the tourism time thresholds. For standard rules, set to 100. -tourism_time_scale_percent = 100 - -; On the first turn of a hotseat game, all human players will be given diplomatic contact with each other. -introduce_all_human_players_at_start_of_hotseat_game = false - -; Allows units to be unloaded from an army. The army type must have the "unload" ability set in the editor. -allow_unload_from_army = false - -; Allow colonies to be built on tiles inside another civ's territory (for strategic/luxury resources); applies a relation penalty with the other civ, per each colony. -allow_extraterritorial_colonies = false -per_extraterritorial_colony_relation_penalty = 3 - -; A list of rule modifications to make land transports more practical. Works like special_defensive_bombard_rules. The possibilities are: -; load-onto-boat: Allows land transports to be loaded into naval units -; join-army: Allows empty land transports to join armies -; no-defense-from-inside: Prevents units inside a land transport from defending their tile, performing defensive bombard, or intercepting air units -; no-escape: Destroys the passengers inside a land tranport when the transport itself is destroyed or captured -land_transport_rules = [] - -; Prevents land anti-air units from intercepting overflying units while they're loaded in a naval transport -no_land_anti_air_from_inside_naval_transport = false - -; A list of rule modifications for air units with transport capacity called "helicopters" for short. Works like special_defensive_bombard_rules. The -; possibilities are: -; allow-on-carriers: Allows helicopters to be rebased or loaded onto carriers -; passenger-airdrop: Allows paratroopers inside a helicopter on a carrier to perform airdrops -; no-defense-from-inside: Prevents units inside a helicopter from defending their tile, performing defensive bombard, or intercepting air -; units. Also destroys passengers when the helicopter is destroyed in most circumstances in order to avoid problems such as a helicopter being -; captured by a land unit leaving its passengers alive on the same tile. -; no-escape: In all circumstances, destroys the passengers inside a helicopter when the heli itself is destroyed or captured -special_helicopter_rules = [] - -; Stops units from enslaving a target they've destroyed by bombarding as opposed to direct combat -prevent_enslaving_by_bombardment = false - -; Relaxes a rule that prevents resources from appearing directly next to another resource of a different type -allow_adjacent_resources_of_different_types = false - -; Controls the overall number of luxury resources placed on the map for luxury types that don't have a fixed appearance rate set in the editor. Under -; the standard rules, no luxuries have appearance rates set. Without a set rate, the game randomly chooses a rate between 50 and 100, biased toward -; the middle (75). This setting is a percent scaling on that range, so setting it to 150 means luxuries would have their rate randomized between 75 -; and 150, setting to 50 means a range of 25 to 50, and so on. For base game behavior, set to 100. -luxury_randomized_appearance_rate_percent = 100 - -; During map generation, the game places bonus resources until the total number of strategic and bonus resources reaches the tile count divided by -; this number. Raising this setting causes fewer bonus resources to be generated and lowering it increases them. For the standard rate, set to 32. -tiles_per_non_luxury_resource = 32 - -; Normally the corruption rate in the capital is fixed at zero. Setting this to true removes that, allowing corruption to appear in the capital. The -; capital also has a strong inherent bonus reducing corruption so even when this setting is on, it will usually have zero corruption. To reduce that -; bonus, see the special_capital_decorruption_effect option below. -allow_corruption_in_capital = false - -; Controls the special decorruption bonus that's applied to the capital. This bonus is incorporated into the decorrupting effect from buildings in the -; city and each point is equivalent in strength to one courthouse. For standard game rules, set to 10. This option does nothing unless -; allow_corruption_in_capital is set to true. Min value 0, max 100. -special_capital_decorruption_effect = 10 - -; Overrides the NoAIPatrol setting from conquests.ini. Possible values are: -; none: No override, use the setting from the INI like normal -; one: Set NoAIPatrol to 1, disabling AI patrol behavior -; zero: Set NoAIPatrol to 0, allowing AI units to patrol -; The purpose of this option is to enable you to configure NoAIPatrol like a C3X setting instead of globally. In particlar, it allows you to configure -; NoAIPatrol on or off on a per-scenario basis. -override_no_ai_patrol = none - -; Overrides the barbarian activity level when starting a new game for a scenario with a custom map. Normally, in that case, the game will use the -; barbarian settings kept in conquests.ini, ignoring what was set for the map in the editor. This option allows you to set an activity level on a -; per-scenario basis like other C3X settings. -; The possible values are "none" for no override, i.e. base game behavior, or one of the selectable barbarian activity levels: "No Barbarians", -; Sedentary, Roaming, Restless, Raging, or Random. You can specify either the original English names just listed or the custom/translated names in -; labels.txt. The value is not case sensitive. -override_barbarian_activity_level_for_scenario_maps = none - -; Leader units placed on the map as part of a scenario do not have their leader types filled in properly, which means they behave differently than -; proper military leaders would. In particular, they are allowed to hurry production of great wonders and spaceship parts. This option fills in their -; types at the start of the game so they behave like normal MGLs spawned during a game. -initialize_preplaced_scenario_leaders_as_mgls = false - -enable_unit_counters = true - -; unit_group allows you gruop your units in a group,please refer to building_prereqs_for_units for the format. -; This function will not work if enable_unit_counters is false. -unit_group = [] -; ── counter_rule format ────────────────────────────────────────────────────────────── -; -; counter_rule = [Friendly vs Enemy Effect... Conditions...] -; -; 【Friendly / Enemy】 -; This can be one of the following three options: -; · The specific unit type, such as "Archer" (must match the name in BIQ exactly; names containing spaces must be enclosed in quotation marks) -; · A unit group name, such as melee (i.e. the group defined in the unit_group section above) -; · "*" represents any unit type (the asterisk must be enclosed in quotation marks) -; -; 【Effect】(Expressed as a percentage; when multiple rules apply to the same battle, their effects are multiplied.) -; -; "self" always refers to the first unit, and "enemy" always refers to the second unit, regardless of who is attacking whom: -; self-atk value — The unit’s attack power becomes N% of its original value -; Example: self-atk 150 = attack power ×1.5; self-atk 50 = attack power ×0.5 -; self-def value — Your defence becomes N% of the original value; -; enemy-atk value — The enemy’s attack becomes N% of the original value; -; enemy-def value — The enemy’s defence becomes N% of the original value; -; -; 【Conditions】(Optional; leaving blank indicates no restrictions; conditions take effect only when all are met simultaneously) -; in-city —— Takes effect only when the enemy is on a city tile -; terrain terrain_name —— Takes effect only when the enemy is on a tile of the specified terrain -; The terrain name must match the name in BIQ, e.g. Grassland, Forest, Hills -; ignore-terrain —— Ignores the enemy’s terrain defence bonus (sets their terrain bonus to zero) -; Can be used in conjunction with enemy-def; when used together, ignore-terrain takes precedence -; district district_name —— Only takes effect when the enemy is in a specified district (enable_districts must be enabled) -; -; 【Examples】 -; counter_rule = [ranged vs melee self-atk 125] -; → When a ranged unit attacks a melee unit, its attack power is multiplied by 1.25 -; -; counter_rule = ["骑士" vs melee in-city enemy-def 150] -; → When knights attack melee units within a city, the enemy’s defence is multiplied by 1.5 -; -; counter_rule = ["火枪手" vs "中世纪步兵" terrain Grassland self-atk 125] -; → When musketeers attack medieval infantry on grassland terrain, their attack power is multiplied by 1.25 -; -; counter_rule = ["骑士" vs "*" ignore-terrain self-atk 150] -; → When a Knight attacks any unit, its attack power is multiplied by 1.5 and it ignores the enemy’s terrain bonus. -; counter_rule = [Archer vs Swordsman self-atk 130 self-def 120] -; → When an archer attacks a swordsman: Archer’s attack power ×130% -; When a swordsman attacks an archer: Archer’s defence ×120% -; -; ───────────────────────────────────────────────────────────────────────────── - -counter_rule = [] - -[==================] -[=== AESTHETICS ===] -[==================] - -; If a tile has a forest, render it on top of roads and railroads, instead of underneath them. -draw_forests_over_roads_and_railroads = true - -; This allows you to set a victory animation for air units. Can be set to the name of any animation that is loaded by the game, specifically one of: -; blank, default, run, attack1, attack2, attack3, death, fortify, fidget, victory, capture, fortress, build, road, mine, irrigate, jungle, forest, plant -; Note that bomber units already have their bombing animations in the victory slot so "victory" is not a good choice here. For standard game behavior, -; set to "none". -aircraft_victory_animation = none - -; Enables naming tiles via the right-click menu and displays those names on the map. -enable_named_tiles = true - -[=======================] -[=== DAY/NIGHT CYCLE ===] -[=======================] - -; How the day/night cycle operates in the game. If enabled, terrain, cities, resources, landmarks and terrain buildings will change appearance based on -; the time of day, with 24 possible stages (one for each hour). The base game art is used for 12pm. If set to 'off', only base game art will be used. -; Day/night cycle should not be used if you are using non-standard terrain art or resources. Doing so may result in visual glitches or missing art. -; Note that day/night cycle art is not bundled directly with C3X and must be downloaded separately at https://forums.civfanatics.com/resources/day-night-cycle-in-civ-3-using-c3x.32520/ -; The possible values are: -; off: Only base game art used -; timer: Increment based on time elapsed since last hour transition (e.g., transition to next hour every 3 minutes) -; user-time: Match the user's system clock to determine hour of the day -; every-turn: Increment every turn by a fixed amount of hours -; specified: Pin the hour to a specific value (so hour of day is always the same) -day_night_cycle_mode = off - -; If day_night_cycle_mode is set to 'timer', minimum minutes of real time to elapse before transitioning to the next hour in the cycle. -; This is checked only at the end of the turn, so actual minutes may exceed this number. -elapsed_minutes_per_day_night_hour_transition = 3 - -; If day_night_cycle_mode is set to 'timer' or 'every-turn', the number of hours to transition. This should be a value between 1 and 12 inclusive. -fixed_hours_per_turn_for_day_night_cycle = 1 - -; If day_night_cycle_mode is set to 'specified', the hour of the day to pin the cycle to. This should be a value between 0 (midnight) and 23 (11pm) inclusive. -pinned_hour_for_day_night_cycle = 0 - -[=======================] -[=== NATURAL WONDERS ===] -[=======================] - -; Show or hide natural wonders on the map. When disabled, natural wonders will not appear on the map. -enable_natural_wonders = false - -; If a new scenario is loaded which has no natural wonders defined, add natural wonders. -add_natural_wonders_to_scenarios_if_none = false - -; Show the names of natural wonders on the map below their image. -show_natural_wonder_name_on_map = true - -; Minimum separation (in tiles) between natural wonders when generating the map. This helps prevent clustering of natural wonders. -minimum_natural_wonder_separation = 10 - -[=================] -[=== DISTRICTS ===] -[=================] - -; Districts are Civ6-inspired structures built by workers that enable buildings, provide bonuses, and make cities feel more alive. When enabled, -; districts appear on the map and can be required for certain buildings (configured in default.districts_config.txt). Districts occupy tiles within a -; city's work radius, making those tiles unworkable. They can provide bonuses (food, shields, gold, science, culture, defense) to all cities within -; their work radius. If multiple cities share a district, they can optionally share its buildings and wonders (see options below). Districts with -; pollution or enemy units yield no bonuses. Destroyed districts remove dependent buildings from affected cities unless they have another district of -; that type in range. The five district types below can be enabled independently: -; enable_districts: Enables standard configurable districts (by default: Encampment, Campus, Holy Site, Commercial Hub, Entertainment Complex, Industrial Zone). -; Configured is done in default.districts_config.txt, user.districts_config.txt, and scenario.districts_config.txt -; enable_neighborhood_districts: Enables population growth past a configurable limit (see maximum_pop_before_neighborhood_needed below) -; enable_wonder_districts: Wonders require a dedicated district tile, making them visible on the map and optionally destructible. -; Configured in default.districts_wonders_config.txt, user.districts_wonders_config.txt, and scenario.districts_wonders_config.txt -; enable_distribution_hub_districts: Special districts that distribute food/shields from surrounding tiles to all connected cities -; enable_aerodrome_districts: Air units can only be built/based at Aerodrome districts instead of cities (if air_units_use_aerodrome_districts_not_cities is true) -; enable_port_districts: Enables Port districts, which serve as coastal district tiles for naval production/basing when naval_units_use_port_districts_not_cities is on. -; enable_bridge_districts: Enables Bridge districts on coastal water; completed bridges let land units cross water tiles. -; enable_canal_districts: Enables Canal districts on land; completed canals let naval units traverse land tiles between water bodies. -; enable_central_rail_hub_districts: Enables Central Rail Hub districts used for rail-era infrastructure (e.g., Mass Transit). -; enable_energy_grid_districts: Enables Energy Grid districts associated with power plant infrastructure. -; enable_great_wall_districts: Enables Great Wall districts (wall-like tiles that can block others if great_wall_districts_impassible_by_others is on). -enable_districts = false -enable_neighborhood_districts = false -enable_wonder_districts = false -enable_distribution_hub_districts = false -enable_aerodrome_districts = false -enable_port_districts = false -enable_bridge_districts = false -enable_canal_districts = false -enable_central_rail_hub_districts = false -enable_energy_grid_districts = false -enable_great_wall_districts = false - -; When multiple cities share a district (i.e., the same district tile is within multiple cities' work radii), these options control whether those -; cities automatically share the benefits of buildings and wonders constructed in that district. For example, if Rome and Veii both have the same -; Encampment in their work radius and Rome builds a Barracks in that Encampment, enabling cities_with_mutual_district_receive_buildings will cause -; Veii to automatically receive a Barracks as well. Similarly, cities_with_mutual_district_receive_wonders extends this sharing to Great and Small -; Wonders. This encourages strategic district placement between cities and can reduce micromanagement in dense urban areas. -; Note: receiving buildings is only assessed twice: when a city completes a building, and when a city is founded nearby. A city receiving a building -; cannot in turn recursively share it with third, fourth, fifth, etc. cities in a chain. Only applies if enable_districts is set to true. -cities_with_mutual_district_receive_buildings = true -cities_with_mutual_district_receive_wonders = true -show_message_when_building_received_by_mutual_district = true -show_message_when_building_lost_to_destroyed_district = true - -; When enabled, air units can only be built in cities with an Aerodrome district in their work radius and must be based at Aerodrome districts instead -; of cities. Air units will spawn on Aerodromes and can only land on Aerodromes, vanilla airfields, or carriers. Airlifts and airdrops are similarly -; limited to Aerodromes. This adds strategic depth by requiring infrastructure for air power and making air bases visible and vulnerable on the map. -; Only applies when enable_aerodrome_districts is also set to true. -air_units_use_aerodrome_districts_not_cities = true - -; When enabled, naval units can only be built in cities with a Port district in their work radius and cannot enter city tiles directly. Naval unit -; healing must be done at Port districts, and travel between continents, lakes and so on can instead only be done via Canal districts (via enable_canal_districts), -; rather than cities on an isthmus. Additionally, a city cannot build naval units until it has a Port district in range. Only applies when enable_port_districts is set to true. -naval_units_use_port_districts_not_cities = true - -; Neighborhood district limit population growth. Once a city reaches maximum_pop_before_neighborhood_needed, it cannot -; grow further until it has at least one Neighborhood district in its work radius. Each Neighborhood then enables additional population growth equal to -; per_neighborhood_pop_growth_enabled. For example, with maximum set to 6 and per_neighborhood set to 2, a city can grow to pop 6 without -; Neighborhoods, requires 1 Neighborhood to reach pop 8, requires 2 Neighborhoods to reach pop 10, and so on. Neighborhood bonuses (+1 gold and +1 -; culture, by default) only apply if the city actually needs them based on its population. Periodic popups will remind you when a Neighborhood is needed. Only -; applies when enable_neighborhood_districts is set to true. neighborhood_needed_message_frequency sets how often (in turns) the reminder message appears; -; set to 0 to disable. -; If destroying_neighborhood_reduces_pop is true, losing a Neighborhood district reduces the city's population down to the new cap. -maximum_pop_before_neighborhood_needed = 6 -per_neighborhood_pop_growth_enabled = 3 -neighborhood_needed_message_frequency = 4 -destroying_neighborhood_reduces_pop = true - -; These options control the vulnerability and rebuildability of completed Wonders in Wonder districts. When completed_wonder_districts_can_be_destroyed -; is enabled, completed Wonders (both Great and Small) can be pillaged or destroyed by enemies, making them valuable strategic targets that must be -; defended. When destroyed_wonders_can_be_built_again is enabled, destroyed Wonders become available again for any civ to build, putting them back -; into play. Only applies when enable_wonder_districts is set to true. -completed_wonder_districts_can_be_destroyed = true -destroyed_wonders_can_be_built_again = true - -; Distribution Hubs work as "breadbaskets" and mining areas far from urban centers, minimizing local city potential but benefiting the entire civilization. -; Distribution Hubs make surrounding tiles unworkable and instead distribute their raw food and shield yields to ALL connected cities in your civilization. -; "Divisors" for food and shields multiply the sqrt-based divisor in scale-by-city-count mode, and are a straight divider in flat mode. Yields are subject -; to corruption as with regular shields. -; -; ai_ideal_distribution_hub_count_per_100_cities controls how many hubs the AI tries to maintain per 100 cities if distribution_hub_yield_division_mode -; is set to "flat" (e.g., 25 means the AI aims for 1 hub per 4 cities). -; -; distribution_hub_yield_division_mode controls how a hub splits its collected food/shields across connected cities: -; flat: Divide raw yields by the configured divisors (distribution_hub_food_yield_divisor & distribution_hub_shield_yield_divisor) -; scale-by-city-count: Bonuses gradually reduce as more cities plug into the hub. Formula: floor(raw_yield / (sqrt(connected_city_count) * divisor)) -; -; ai_distribution_hub_build_strategy controls how the AI decides to build distribution hubs: -; by-city-count: AI builds hubs based on its ideal hub count per 100 cities -; auto: AI dynamically assesses need based on city growth and food/shield deficits across civ -distribution_hub_yield_division_mode = scale-by-city-count -ai_distribution_hub_build_strategy = auto -distribution_hub_food_yield_divisor = 2 -distribution_hub_shield_yield_divisor = 2 -ai_ideal_distribution_hub_count_per_100_cities = 50 -max_distribution_hub_count_per_100_cities = 50 - -; Bonus percent applied to Distribution Hub food and shield yields for cities that have a Central Rail Hub district in their work radius. -central_rail_hub_distribution_food_bonus_percent = 25 -central_rail_hub_distribution_shield_bonus_percent = 25 - -; District placement and AI bridge/canal behavior: -; expand_water_tile_checks_to_city_work_area: Use the full city work radius (not just adjacent tiles) for river/lake/sea checks (e.g. to build a port if a -; city has coast within its work area, even if not adjacent to the sea). -; Note that this does not affect Aqueducts or Coastal Fortresses, which still require direct city adjacency. -; workers_can_enter_coast: Allow workers to move onto coast tiles without embarking. -; max_contiguous_bridge_districts: Maximum number of contiguous bridge district tiles allowed in a line (0 = no limit). -; max_contiguous_canal_districts: Maximum number of contiguous canal district tiles allowed in a line (0 = no limit). -; ai_canal_eval_min_bisected_land_tiles: Minimum land tiles required on each side for the AI to consider a canal candidate. -; ai_bridge_canal_eval_block_size: Map block size used when scanning for AI bridge/canal candidates. -; ai_bridge_eval_lake_tile_threshold: Water bodies at or below this size are treated as lakes for AI bridge evaluation. -; ai_can_replace_existing_districts_with_canals: Allow the AI to build canal/bridge districts over existing non-wonder districts. -; ai_builds_bridges: Allow the AI to construct bridge districts. -; ai_builds_canals: Allow the AI to construct canal districts. -expand_water_tile_checks_to_city_work_area = true -workers_can_enter_coast = true -max_contiguous_bridge_districts = 3 -max_contiguous_canal_districts = 5 -ai_canal_eval_min_bisected_land_tiles = 20 -ai_bridge_canal_eval_block_size = 10 -ai_bridge_eval_lake_tile_threshold = 5 -ai_can_replace_existing_districts_with_canals = true -ai_builds_bridges = true -ai_builds_canals = true - -; When enabled, AI defensive units will actively seek out and defend districts within their territory, treating them as valuable assets like colonies. -; The AI prioritizes defending Wonder districts (if destructible wonders are enabled) over regular districts, searching within a 20-tile radius for -; districts that need protection from nearby enemy units. This makes districts meaningful strategic targets and ensures the AI protects its -; infrastructure. Only applies when enable_districts is set to true. -ai_defends_districts = true - -; As AI cities queue up districts needed, the max number of turns to wait for a worker to build it before the request is dropped -; until the AI city is triggered to build the district again (e.g., by trying to build a building that depends on it) -ai_city_district_max_build_wait_turns = 20 - -; Great Wall behavior: -; disable_great_wall_city_defense_bonus: Disables the Great Wall wonder's city defense doubling effect. Only takes effect if districts and great wall districts are enabled. -; great_wall_districts_impassible_by_others: Great Wall district tiles block movement by other civs (unless obsolete). -; auto_build_great_wall_around_territory: Auto-place Great Wall districts along your borders when the specified wonder is built. -; great_wall_auto_build_wonder_name: Name of the wonder that triggers auto-building (empty disables auto-build). -; ai_auto_build_great_wall_strategy: How AI uses auto-built Great Wall: all-borders (any border tiles) or other-civ-bordered-only (only borders touching another civ). -disable_great_wall_city_defense_bonus = false -great_wall_districts_impassible_by_others = true -auto_build_great_wall_around_territory = true -great_wall_auto_build_wonder_name = "The Great Wall" -ai_auto_build_great_wall_strategy = other-civ-bordered-only - -; When enabled, holding down the Control key while a worker is selected will highlight all tiles within the work radii of nearby cities. City centers -; are highlighted more brightly, while tiles that fall within multiple cities' work radii are highlighted more intensely. This visual aid helps you -; strategically place districts and improvements by showing which cities will be affected. The highlights update dynamically as you move the worker -; around the map. Only applies when enable_districts is set to true. -enable_city_work_radii_highlights = true +[====================================================== C3X RELEASE 27 PREVIEW 1 DEFAULT CONFIG =====================================================] +[======================================================================= NOTE =======================================================================] +[Instead of editing this file, changes to the settings should be placed in either the scenario or custom config files. The scenario config file must ] +[be named scenario.c3x_config.ini and must be located in your scenario search folder. Of course it only applies if you are using a scenario. The ] +[custom config file must be named custom.c3x_config.ini and located in the C3X folder, which is the folder where this file is. When creating scenario] +[or custom configs, it is only necessary to include the settings you wish to change. ] +[====================================================================================================================================================] + +[============================] +[=== CONVENIENCE FEATURES ===] +[============================] + +enable_stack_bombard = true +enable_stack_unit_commands = true +enable_disorder_warning = true +show_detailed_city_production_info = true +enable_trade_screen_scroll = true +autofill_best_gold_amount_when_trading = true +skip_repeated_tile_improv_replacement_asks = true +group_units_on_right_click_menu = true + +; On the right click menu, units with no remaining moves will appear in gray text +gray_out_units_on_menu_with_no_remaining_moves = true + +; Places an icon next to units on the right-click menu showing their remaining moves & status. The icon is green for unmoved units, red for units that +; have exhausted all their moves, and yellow for those in between. Additionally it contains a little sword for units that can still attack and is +; colored blue for fighters set to intercept. +put_movement_icons_on_units_on_menu = true + +; Replaces the "Wake" or "Activate" text on the right-click menu with more descriptive words indicating what the unit is currently doing. For example, +; "Moving", "Intercepting", or "Working". +describe_states_of_units_on_menu = true + +show_detailed_tile_info = true +show_golden_age_turns_remaining = true + +; This option causes the game to show attack animations for units exerting zone of control from the middle of their tile's stack. Otherwise the game +; will only show such animations for units that are the top visible unit on their tiles. It was presumably an oversight by the original developers +; that units exerting zone of control do not temporarily become the visible unit on their tiles (unlike, for example, defensive bombard). +show_zoc_attacks_from_mid_stack = true + +; Fixes the defensive bombard animation being skipped when the unit performing defensive bombard is inside an army. +show_armies_performing_defensive_bombard = true + +cut_research_spending_to_avoid_bankruptcy = true +dont_pause_for_love_the_king_messages = true + +; Holding shift when clicking a specialist on the city screen will switch to the previous, instead of the next, specialist type +reverse_specialist_order_with_shift = true + +; Pressing the Z key on the city screen will zoom the map in/out +toggle_zoom_with_z_on_city_screen = true + +; When king units are spawned they're named after the leader of their civ. This is undesirable in modded games where the king flag is often used +; on units that aren't intended to be actual kings. This setting helps by bypassing the king unit naming logic when regicide is not enabled. +dont_give_king_names_in_non_regicide_games = true + +; One of the game's "Easter eggs" is that all king-flagged units appear as Elvis Presley on his birthday (Jan 8). This can be annoying when playing +; mods that make wide use of the king flag. +no_elvis_easter_egg = false + +; Removes option to automate workers from the human player. Useful for those who never want to use automation but sometimes accidentally activate it. +disable_worker_automation = false + +; There is a limit to how many links can appear on each Civilopedia page. Some mods exceed that limit. The problem is that the game throws up a popup +; when the limit is exceeded, one popup for each link beyond the limit. That can result in dozens of annoying, useless popups. This option stops them +; from appearing. Note: the game may also crash if the number of links far exceeds the limit. This option does not stop the crash, just the popups. +suppress_hypertext_links_exceeded_popup = true + +; Replaces the text "Upgrades To" with "Obsoleted By" in the Civilopedia for unit types that go obsolete but cannot be upgraded to their successors. +indicate_non_upgradability_in_pedia = true + +; Shows a message when a bomber gets intercepted by enemy air defense buildings but succeedes on its roll to avoid damage. Without this message, there +; is no indication that anything happened in that case except for the bomber losing one movement point. +show_message_after_dodging_sam = true + +; Normally only the last human player in a hotseat game gets to see the AIs move their units since the game processes the interturn while that player +; is still seated. This setting shows the AI moves to the other players in the game. It works by creating a save just before the interturn processing +; happens and then, at the start of the other players' turns, loads the save, sets that player as the seated one, reprocesses the interturn, then +; resumes the original game. +; Note: If the game is manually saved and reloaded, the replay will be lost. So it is recommended to save the game only after all human players have +; seen the replay, i.e. during the last or second to last human players' turns. +replay_ai_moves_in_hotseat_games = false + +; Normally, when you load a save, all units face southeast because the game didn't record which direction they were facing when the save was +; created. However, the game does record which tile they were on before their most recent move, so it is possible to deduce which direction they +; should be facing. That's what this option does. +restore_unit_directions_on_game_load = true + +; The game stores your map grid setting (on or off) in conquests.ini. It applies that setting after creating a new game, but not after loading a +; save. That was presumably an oversight and is corrected by this config option. +apply_grid_ini_setting_on_game_load = true + +; Causes cities to display harbor/airport icons if they have buildings that grant the relevant unit effects (produce veterans & heal in one turn) +; instead of buildings that grant sea/air trade. This makes no difference under the standard rules but is useful with mods that separate the unit +; effects and trade abilities into different buildings. +city_icons_show_unit_effects_not_trade = true + +; The game rules do not permit aircraft in an airfield to be damaged by bombardment. The interface allows players to order such bombardments anyway +; since its logic to check target validity is incomplete. This option completes the logic, causing the interface to reject attempts to bombard an +; airfield which would have no effect. +disallow_useless_bombard_vs_airfields = true + +; This option fixes a graphical bug that appears when the game is run on Linux using Wine. The bug is caused by the game using both Windows GDI and +; OpenGL to draw to the same canvas. Because the game only uses OpenGL to draw lines, it's relatively easy to solve this issue by reimplementing line +; drawing using Windows GDI+ instead. There are three possible settings for this option: +; never: Self-explanatory +; wine: This change will only be applied if the mod detects the game is running on Wine +; always: This change will always be applied, even on an actual Windows system +draw_lines_using_gdi_plus = wine + +; This option reduces the vertical distance between rows in the list of luxuries on the city screen. This allows up to 11 luxuries to be displayed +; neatly inside the box. +compact_luxury_display_on_city_screen = false + +; Similar to the option above, this one packs the strategic resources more tightly into the box on the upper left of the city screen. This allows up +; to 13 resources to be displayed there. +compact_strategic_resource_display_on_city_screen = false + +; Causes the domestic advisor to ask for confirmation before setting city production to a building that would replace another already built in the +; city. It's similar to how the domestic advisor warns you before a production switch would waste shields. Useful for modded games where you might not +; know which buildings replace which. +warn_when_chosen_building_would_replace_another = false + +; This option keeps citizens working the tiles they've been assigned to when pollution spawns there instead of converting them to specialists. This +; reduces micromanage but comes at the cost of the specialist yields. +do_not_unassign_workers_from_polluted_tiles = false + +; Normally the game draws capital cities one level larger than normal. I.e., a capital city at size 1 - 6 uses the graphic for cities at size 7 - 12, +; and a capital at size 7+ uses the graphic for cities 13+. This option turns that off, so capitals use the standard city graphics. +do_not_make_capital_cities_appear_larger = false + +; Tints coast and sea tiles on the minimap based on the culture that controls them, like is normally done for land tiles. +show_territory_colors_on_water_tiles_in_minimap = false + +; In offline games, shows some popup messages as online-multiplayer-style notes to the left of the screen instead of advisor popups that pause +; gameplay until dismissed. The point is to minimize interruptions during turn processing. Affects popups with the following text keys: +; SUMMARY_END_GOLDEN_AGE, SUMMARY_END_SCIENCE_AGE, SUMMARY_NEW_SMALL_WONDER, WONDERPRODUCE, MAKEPEACE, MUTUALPROTECTIONPACT, MILITARYALLIANCE, +; SUMMARY_DECLARE_WAR, TRADEEMBARGOENDS, SUMMARY_CIV_DESTROYED_BY_CIV, SUMMARY_CIV_DESTROYED, LOSTGOOD, TRADEEMBARGO, MILITARYALLIANCEWARONUS, +; MILITARYALLIANCEAGAINSTUS, and SUMMARY_TRAVELERS_REPORT. +convert_some_popups_into_online_mp_messages = false + +; If enabled, pressing the keys d e b u g to type "debug", in-game will allow you to activate debug mode for a game in progress. Typing that with +; debug mode already on will deactivate it. +enable_debug_mode_switch = true + +; Places a small shadow below city dots on the minimap to make them more easily visible especially against light-colored territory. This feature does +; not quite work properly so is left off by default. Its issues are (1) the shadows may not fully appear until you toggle the minimap from territory +; to geography mode and back again and (2) the shadows may appear in geography mode. +accentuate_cities_on_minimap = false + +; Makes the minimap twice as large. Possible values are "never", "always", and "high-def". The first two are self-explanatory; if set to "high-def", +; the minimap's size will be doubled when the game is run at a horizontal resolution of at least 1920 pixels. +double_minimap_size = high-def + +; Allows descriptions for units, civilizations, and game concepts to span multiple pages. If a DESC entry of one of those types is too long for one +; page, it will automatically be divided into multiple with buttons added for navigation. +allow_multipage_civilopedia_descriptions = true + +; Controls how the game searches for the next unit to autoselect. The possible choices are: +; standard: Base game behavior +; similar-near-start: The game will search for similar units near the starting point of the last selected unit. That means, when a unit is selected, +; the game remembers its location then searches out from there for a similar unit when cycling to the next one. Distance is prioritized over +; similarity, meaning the game will select all units on the starting tile no matter how dissimilar before any on nearby tiles. +; similar-near-destination: Like similar-near-start except the search goes outward from whatever tile the last selected unit was last on. +unit_cycle_search_criteria = standard + +; On the domestic advisor screen, tweaks how the number of turns remaining on each city build are displayed to improve readability. Instead of +; "(1turn)" or "(7turns)", the game will display "(1 Turn)" or "(7 Turns)" +reformat_turns_remaining_on_domestic_advisor_screen = true + +[====================] +[=== OPTIMIZATION ===] +[====================] + +; Rewrites the game's trade network computation logic to improve speed. On large maps with many cities, this computation takes up most of the +; interturn time so speeding it up greatly improves turn times. For more info, see the text file in the Trade Net X folder. +enable_trade_net_x = true + +; Rewrites parts of the game logic to improve efficiency. Those parts check every possible improvement defined in the scenario when they really only +; need to check a few. For example, to determine whether a city can trade via air, it's very wasteful to check every improvement since the vast +; majority of them do not enable air trade. This option can improve turn times very significantly in some circumstances. +optimize_improvement_loops = true + +; Displays a popup after each turn has been processed showing the time elapsed, including specifically how much time was spent recomputing trade +; networks. NOTE: Turning this on will skip all animations during the interturn so they don't contribute to the time. You aren't meant to play the +; game with this option left on. +measure_turn_times = false + +[=======================] +[=== AI ENHANCEMENTS ===] +[=======================] + +; Allows artillery unit AI to grab escorts from city defenders, causing the AI to use its artillery offensively instead of leaving it in its cities. +use_offensive_artillery_ai = true + +; If true, the AI will not escort its units unless they have the "requires escort" flag set in the editor. This allows modders to remove the escort +; requirement from certain types of units, for example artillery with non-zero defense. +dont_escort_unflagged_units = false + +; Set to a number to encourage the AI to build more artillery, set to false or <= 0 for no change in AI unit build choices. The number is how many +; artillery units the AI will try to keep around for every 100 non-artillery combat land units it has. The encouragement only applies if the AI is +; already above a minimum of one defensive unit per city and one offensive unit per two cities. Default: 16. +ai_build_artillery_ratio = 16 + +; The above option controls how many artillery the AI will keep around, this one controls how aggressively it builds up to that limit. More +; specifically it controls how valuable (in percent) the AI thinks artillery is as a damage dealer compared to attacking units. Default: 50. +ai_artillery_value_damage_percent = 50 + +; Like the artillery ratio, shifts the AI's build priority from fighters to bombers to keep around this many bombers per 100 fighters. Default: 70. +ai_build_bomber_ratio = 70 + +; Completely replaces the leader unit AI with custom code. The custom version is similar in spirit to the original but fixes several major issues: +; 1. It fixes a bug that allowed the AI to rush any kind of city production, including units and (with an MGL) wonders +; 2. Prioritizes army formation over rushing production when appropriate +; 3. When rushing, prioritizes wonders and costly improvements in high value cities +replace_leader_unit_ai = true + +; Replaces the AI code that determines whether a unit would be a good addition to an army. The replacement code fixes a major bug that prevented the +; AI from filling its armies, prevents the AI from including hidden nationality units in armies to avoid crashes, and removes some logic that +; encouraged the AI to mix unit types in armies. +fix_ai_army_composition = true + +; "Pop units" are special units whose only purpose is to be joined into cities to increase their population. Normally the AI does not know what to do +; with these units, so this option enables a routine that causes them to search for & join an appropriate city. Pop units only appear in some mods +; (for example Tides of Crimson). Under the standard game rules, this option has no effect. In order to function as a pop unit, a unit must use the +; terraform AI strategy, have no worker actions except join city, have a pop cost of at least 1, and have zero attack, defense, & bombard strengths. +enable_pop_unit_ai = true + +; "Caravan units" are special units whose only purpose is to be disbanded to contribute shields to a city. The name comes from the Civ 2 caravan. +; Caravan units may appear in some mods; under the standard game rules, this option has no effect. In order to function as a caravan unit, a unit must +; use the terraform AI strategy, have no worker actions enabled, have the ability to disband, and have zero attack, defense, & bombard strengths. +enable_caravan_unit_ai = true + +; In the base game, the AI will assign 1, 2, or 3 escort units to its naval transports and carriers depending in their shield cost and the number of +; units they're carrying. This option lets you reduce the upper limit on the number of escorts assigned. You can limit the number of escorts to 2, 1, +; or even 0. Setting this option >= 3 will result in base game behavior. The purpose of reducing the limit is to free up the AI's naval power units. +max_ai_naval_escorts = 3 + +; This controls how many workers the AI feels it needs as a percentage of the base amount. For example, if set to 150 (the default), the AI will build +; about 50% more workers than normal. Set to 100 for base game behavior. For more info, see: +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-95#post-16587093 +ai_worker_requirement_percent = 150 + +[=================] +[=== BUG FIXES ===] +[=================] + +; Descriptions of bugs and their fixes: +; SUBMARINE BUG -- The AI runs into invisible units (such as submarines) belonging to other players because it blindly follows paths produced for +; it by the game's pathfinder, which does not see invisible units. After colliding with an invisible unit, the AI initiates combat, declaring war if +; necessary. The mod fixes this bug by modifying the pathfinder so it sees invisible units belonging to other non-hostile players so it can route +; around them. +; SCIENCE AGE BUG -- The bonus science points generated by a scientific golden age are not actually counted towards research progress. They appear +; only on the interface. This is because of a small oversight in the code. There is a setting which controls whether or not science age bonus points +; are included while gathering all research points. It's turned off while gathering points to update research progress. The fix is to turn it on. +; PEDIA TEXTURE BUG -- There is a one pixel wide pink line on the right edge of the Civilopedia screen. This is because the width of the +; Civilopedia background texture is set one pixel too small inside the EXE. This is fixed simply by replacing the width with the correct value. +; BLOCKED DISEMBARK FREEZE -- When using "disembark all" (which the AI always does) on a boat containing units that can't be disembarked, the game +; may freeze as it endlessly tries to disembark them. The root of the problem is that the game's logic to check if there are any disembarkable units +; left on the boat is incomplete. There are two cases that it misses. First, it does not consider the "immobile" unit flag. This is fixed by making +; immobile units appear to have no remaining movement points for this bit of logic so they are correctly considered non-disembarkable. Second, it does +; not consider escort relationships (e.g. for settlers). If a unit has a non-disembarkable escorter then it also can't be disembarked because the game +; will always try to move its escorter ahead of it. The solution here is to clear all escort relationships for ship passengers before disembarking. +; HOUSEBOAT BUG -- The game may crash when an AI player is left alive with only a settler on a boat. This happens because the AI's logic tries to +; check the location of its capital city without considering that there may be no capital. The fix is to modify this logic so that when it looks up +; the location of a non-existent capital, it receives a valid "dummy" location that it can process without crashing. See also: +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16084386 +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16085242 +; INTERCEPT LOST TURN BUG -- When a human player sets a fighter to intercept mode, the game discards all of its remaining movement points, hence it +; cannot intercept during the next interturn. This bug does not affect the AI and is part of the interface logic, not the game logic. I presume it was +; inserted by a programmer who did not understand how the game's unit cycling works. The fix simply restores fighters' discarded moves. +; PHANTOM RESOURCE BUG -- The game only stores one full list of available resources per player. That list contains how many sources of each +; resource type are avaiable in that player's capital and all connected cities. Cities off the capital's network have reduced lists of just 32 bits, +; recording yes-or-no availability for up to 32 resources. Resources beyond the first 32 will share bits in those reduced lists. Specifically, the +; 33rd resource shares the same bit as the 1st, the 34th the same as the 2nd, and so forth. This causes "phantom" resources. For example, if a mod has +; horses set as the 1st resource and steel as the 33rd, then any city off its capital's trade network with access to horses will also have access to +; steel and vice-versa. The fix for this issue is straight forward but not simple. The jist is the mod allocates additional space for the reduced +; lists so they're not limited to 32 bits, rather have enough bits for every resource in the game. After that it's necessary to modify the code that +; accesses the reduced lists so it can make use of the additional space. +; MAINTENANCE PERSISTING FOR OBSOLETE BUILDINGS -- Players are not supposed to pay maintenance for obsolete city improvements however they often do +; because the game does not recompute maintenance after a player unlocks a technology that obsoletes a city improvement. There is a related exploit in +; that, after triggering a recomputation of maintenance, players can then sell their obsolete buildings to have the maintenance deducted again, +; effectively getting credited for the cost of maintenance. The mod fixes both issues. It recomputes maintenance costs when a player unlocks a +; technology that obsoletes a city improvement and it stops the game from deducting the maintenance cost of an obsolete city imp. when it's sold. +; BARBARIAN DIAGONAL BUG -- Barbarians can only search for targets on adjacent tiles or on tiles that are up to 12 steps directly SE or NW of their +; position. The intended behavior was for them to search for targets on all surrounding tiles up to 6 steps away. This bug was caused by a small, +; sloppy programming mistake that can be corrected with a small edit. For details, see: +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-70#post-16434678 +; DISEASE CURING TECH FLAG BUG -- In the base game, the tech flag "Disables Diseases From Flood Plains" (applied to Sanitation) does nothing and +; instead flood plains disease stops once players discover Writing. This happens because that flag is encoded as number 8 and, instead of checking if +; players have a tech with that flag, the code mistakenly checks if players have tech #8, which is Writing under the standard rules. Correcting this +; bug causes a lot more disease, which is a major annoyance, and so this bug fix is turned off by default. +; DIVISION BY ZERO IN AI ALLIANCE EVAL -- When considering whether to agree to a military alliance, the AI computes the distance from its capital to +; the nearest city belonging to the target of the alliance and divides by that distance. For unknown reasons, in rare cases that distance may be zero, +; which crashes the program due to division by zero. The mod fixes this issue by inserting a bit of logic after the distance is computed to check if +; it's zero and, if so, set it to one. +; EMPTY ARMY MOVEMENT -- Empty armies have one less than a full move's worth of movement points regardless of how many moves their unit type has set +; in the editor. Under the standard game rules, this means they can only move two tiles along roads. The cause is a small mistake in the logic that +; attempts to find the slowest member among units in the army. The mod fixes this bug by reimplementing the max movement point calculation for armies. +; PREMATURE TRUNCATION OF FOUND PATHS -- If the game attempts to find a path for a unit that's more than 256 tiles long, the path will not be +; returned properly from the pathfinder. That's because the pathfinder stops reconstructing the final path once it reaches a length of 256. That +; creates a serious problem for long paths because reconstruction works from the end of the path toward the start, so stopping early produces an +; incorrect path that begins in the middle. The fix is simply to multiply the maximum length by 10 (to 2560). Removing the limit entirely risks +; allowing infinite loops. This bug is rarely visible in-game, it usually appears as AI naval units following inappropriate or invalid paths. +; ZERO PRODUCTION CRASH -- If a city has zero production, which is possible using specialists modded to produce negative shields, the game will +; crash due to a division by zero. +; AI CAN SACRIFICE WITHOUT SPECIAL ABILITY -- The base game function that gates the AI's ability to sacrifice units does not check whether the unit +; in question has the sacrifice special ability set on its type. Thus, AIs are allowed to sacrifice any captured units as long as they have the +; required tech. The mod fixes this by patching the gating function to insert the missing condition. +; AI CAN FORM ARMY WITHOUT SPECIAL ABILITY -- Similar to the above issue, the AI's ability to form armies with leader units is not gated by those +; units having the "build army" special ability. +; CRASH IN LEADER UNIT AI -- The base game's AI routine for leader units may crash due to uninitialized variables. +; FAILURE TO FIND NEW CITY BUILD -- After a city completes production, the game searches for a new build for it. If that city is owned by the seated +; player, whatever the game finds will be filled in as the default option in the domestic advisor popup asking the player to choose a new build. If +; the search fails to find anything, there will be no default option, the dropdown selector will not be initialized, and the game will crash when it +; tries to open the popup. To fix this, the mod detects when the game has failed to find a new build option and fills in Wealth instead or, failing +; that, any unit or improvement that the city can build. +; PASSENGERS OUT OF ORDER ON MENU -- When there are multiple doubly-contained units (meaning units contained in other units that are themselves +; contained in something, like a unit in an army on a transport) on a tile, the game will not always show the passenger units in the correct locations +; on the right-click menu. To fix this, the mod double checks the order of the entries on the menu to make sure that passenger units are listed just +; after the unit they're contained in. +; PATCH EMPTY ARMY COMBAT CRASH -- Guards a crash in the army combat selection routine by returning the army unit itself if it has no contained +; units (prevents divide-by-zero in the vanilla selection loop). + +patch_submarine_bug = true +patch_science_age_bug = true +patch_pedia_texture_bug = true +patch_blocked_disembark_freeze = true +patch_houseboat_bug = true +patch_intercept_lost_turn_bug = true +patch_phantom_resource_bug = true +patch_maintenance_persisting_for_obsolete_buildings = true +patch_barbarian_diagonal_bug = true +patch_disease_stopping_tech_flag_bug = false +patch_division_by_zero_in_ai_alliance_eval = true +patch_empty_army_movement = true +patch_premature_truncation_of_found_paths = true +patch_zero_production_crash = true +patch_ai_can_sacrifice_without_special_ability = true +patch_ai_can_form_army_without_special_ability = true +patch_crash_in_leader_unit_ai = true +patch_failure_to_find_new_city_build = true +patch_passengers_out_of_order_on_menu = true +patch_empty_army_combat_crash = true + +; At the beginning of each AI player's turn, deletes any units of theirs that are not on a valid tile. This addresses a rare crash that can occur when +; the unit AI invokes the pathfinder for an off-map unit. I don't know how AI units can end up off the map in the first place. +delete_off_map_ai_units = true + +; On the city screen, the icons for different kinds of specialist yields get drawn over top of, instead of beside, one another. This setting fixes +; that so they are displayed properly. +fix_overlapping_specialist_yield_icons = true + +[======================] +[=== LIMITS REMOVED ===] +[======================] + +remove_unit_limit = true +remove_city_improvement_limit = true + +; The city limit can be configured up to a maximum of 2048 or down to a minimum of 0. For base game behavior, set to 512. +city_limit = 2048 + +; Increases the cap on the game turn limit from 1000 to 1000000 +remove_cap_on_turn_limit = true + +; Be warned: the no era limit feature is incomplete, untested, and not likely to work at this time +remove_era_limit = false + +[=========================] +[=== ENGINE EXTENSIONS ===] +[=========================] + +; These "NoRaze" options can stop cities from being destroyed. "Autorazing" refers to the automatic destruction of size one, cultureless cities. If +; autorazing is prevented, players will be given the option to keep the city. If razing by players is prevented, neither the human player nor AIs will +; be allowed to raze or abandon cities. +prevent_autorazing = false +prevent_razing_by_players = false + +; These options allow you to adjust the minimum allowed distance between cities. minimum_city_separation controls the minimum number of tiles between +; cities so, e.g, if it's set to 1, cities cannot be founded adjacent to one another, there must be at least one open tile separating them. A setting +; of 1 there corresponds to the standard game rules. disallow_founding_next_to_foreign_city is an optional additional restriction. If it's enabled, +; cities may not be founded adjacent to a city belonging to another civ regardless of the minimum separation. It is only relevant when the minimum +; separation is set to zero. +minimum_city_separation = 1 +disallow_founding_next_to_foreign_city = true + +; Set to a number to limit railroad movement to that many tiles per turn. To return to infinite railroad movement, set to false or a number <=0. By +; default, all units travel the same distance along limited rails like in Civ 4, but this can be changed by toggling the next option below. +; NOTE: For best results, the railroad limit should be a multiple of the "movement rate along roads" set in the editor (usually 3). The limitation +; will work in any case, but setting the limit this way helps avoid an integer overflow issue inside the pathfinder that may cause it to fail to find +; the shortest paths for units with a large number of available moves. +limit_railroad_movement = false + +; If set to true, limited railroads will work like fast roads instead of Civ 4 style railroads. The movement rate along fast roads is determined by +; the limit_railroad_movement setting above. If that setting is false or <= 0, this option does nothing. +limited_railroads_work_like_fast_roads = false + +; This option lets you put a limit on how many units may occupy each tile. The limit applies separately for land, sea, and air units. You may set the +; limit differently for each of those classes by setting this option to a list of three numbers. If you set it to a single number, that limit amount +; will apply to all three. If you set it to false or a number <= 0, no limit will apply, as in the base game. Some examples: +; To limit tiles to 5 land, 5 sea, and 5 air units: limit_units_per_tile = 5 +; To limit tiles to 5 land and sea units but 10 air units: limit_units_per_tile = [5 5 10] +; To limit only air units to 10 per tile: limit_units_per_tile = [false false 10] +; To have no limit (as in the standard game rules): limit_units_per_tile = false +; NOTE: The two options below let you exclude cities or certain unit types from the limit. +limit_units_per_tile = false + +; Allows an unlimited number of units to occupy tiles with cities when the unit limit is in force. When the limit (option above) is deactivated, this +; option does nothing. +exclude_cities_from_units_per_tile_limit = false + +; Allows certain unit types to be exempt from the stack limit. Units of these types will not be stopped by the limit and will not count toward it +; (will not stop others). This option is a space separated list of unit type names. Multi-word names must be wrapped in quotes. For example: +; [Worker Settler Flak "Mobile SAM"] +; This option does nothing if limit_units_per_tile is set to false. +exclude_types_from_units_per_tile_limit = [] + +enable_free_buildings_from_small_wonders = true +allow_stealth_attack_against_single_unit = false +disallow_trespassing = false +enable_land_sea_intersections = false + +; All anarchy lengths will be multiplied by this amount as a percent. For example, if set to 50, anarchy length will be reduced by half. Set to 100 +; for standard game behavior. There is a minimum anarchy length of 2 turns, but you can remove anarchy entirely by setting this option < 0. +anarchy_length_percent = 100 + +; Add perfume to an improvement or unit type to encourage the AI to build it more often. When choosing what to buld, the AI computes a point value for +; each of its options and the mod will add the perfume amount to the point total for each named option. For reference, point values are often in the +; hundreds for the most desirable options. You can see the point value the AI gives to every available build by pressing P while viewing one of its +; cities. Perfume amounts can also be specified as a percentage, ex. a perfume amount of 15% will increase the AI's evaluation by 15% and an amount of +; -50% will reduce it by half. +; production_perfume is a list of names and amounts, each one looks like "name": amount +; Here's an example: ["Granary": 15, "Colosseum": -20%, "Courthouse": 30] +; The quotation marks around a name are not necessary if the name is all one word (i.e. does not include spaces) and is made up of only letters, +; digits (0-9), periods, hyphens, or underscores. The category of letters includes the normal English a-z and A-Z as well as accented variants +; (e.g. ä, ö, ñ, ç) and all other non-English letters available in the Windows-1252 encoding (e.g. ß, þ, æ). +production_perfume = [] + +; Add perfume to a technology to change how valuable the AI judges the tech to be. Each point of perfume is worth roughly one gold in trade, and also +; affects what the AI chooses to research. The format matches production_perfume above, ex.: [Medicine: 500, Fascism: -50%, "Replacable Parts": 20%]. +technology_perfume = [] + +; Add perfume to a government to encourage or discourage the AI from switching to that type. The format follows the other perfume options, ex.: +; [Republic: 10%, Fascism: -30%]. Unfortunately I don't know how much each point is worth in this context. I also don't know how perfuming governments +; affects the AI's willingness to overthrow its current govt. The perfume for sure applies when the AI is selecting a new govt type after anarchy. +government_perfume = [] + +; The AI production ranking is the point value the AI gives to each available build in some city. To view it, press P while viewing an AI city. +enable_ai_production_ranking = true + +; Shades/highlights each tile to show how desirable the AI considers it as a city location. To activate, press L while in game. The scale goes from +; white (least desirable) to red (most desirable) with yellow in between. Also the exact number the AI gives any tile can be seen on its info box. +; If show_ai_city_location_desirability_if_settler is true, the desirability overlay will automatically appear when a settler is selected. +enable_ai_city_location_desirability_display = true +show_ai_city_location_desirability_if_settler = false + +; Setting a government's corruption level to "OFF" will remove all corruption, as expected, instead of maximizing it +zero_corruption_when_off = true + +; Prevents land settlers/workers on transports from settling/improving water tiles. This option does not affect the vanilla game but is useful for +; mods that enable city building or improvement of water tiles. +disallow_land_units_from_affecting_water_tiles = true + +; Allows units to move after airdropping by making airdrops cost no movement. Under the standard game rules, units lose all their remaining moves +; after airdropping. Units will be prevented from airdropping more than once in the same turn. +dont_end_units_turn_after_airdrop = false + +allow_airdrop_without_airport = false +enable_negative_pop_pollution = true + +; Here it's possible to set buildings as prerequisites for unit production. It's possible for a unit type to have multiple prereq buildings up to a +; maximum of 10, and all must be present in a city for the unit to be buildable. +; The format is a list of building names and unit type names, each one looks like "building name": "unit type 1" "unit type 2" ... +; Quotation marks around names can be omitted like in production_perfume (see above). +; Here's an example: +; [Factory: Tank "Modern Armor", +; Barracks: Swordsman Cavalry Tank "Modern Armor", +; Airport: Bomber] +building_prereqs_for_units = [] + +; Here it's possible to set buildings to generate resources. Those resources can be added to the trade network or limited to the building's city. The +; format is a list of building name and resource name pairs with optional "local", "no-tech-req", "yields", "show-bonus", and/or "hide-non-bonus" +; settings before each resource name. Example: +; ["Steel Mill": Steel, Terrace: yields show-bonus Rice, "Coal Liquefaction": local Oil, Supercollider: local no-tech-req Antimatter, +; "Hydro Plant": local "Electric Power"] +; Quotation marks around names can be omitted like in production_perfume (see above). +; The "local" setting means that the produced resource will not be added to the trade network, it will be available only in the building's city. +; The "no-tech-req" setting means that the resource will be produced even for players who do not have the technology to reveal it on the map. +; The "yields" setting means that the resource's tile yields will be added to the city as if it were on a worked tile. +; The "show-bonus" setting means that an icon for the generated resource will be displayed on the city screen even if it's a bonus resource. +; The "hide-non-bonus" setting is the opposite of show-bonus. It means an icon will NOT be shown if the resource is of strategic or luxury type. +; Buildings will not generate resources if the resource requirement for the building itself is not met. This makes it possible to set up resource +; production chains. Note for modders: Production chains require the input resources to be listed before the outputs in the scenario data, when the +; inputs also come from buildings. For example if you have iron ore on the map, a building that requires it and produces iron, and a building that +; requires iron and produces steel, iron must be listed before steel in the scenario data or the chain won't work. This is because building resource +; generation is calculated in the same order as the generated resources appear in the scenario data. This limitation does not apply to map resources +; (iron ore in the example) as access to all map resources is calculated first before any building resources. +buildings_generating_resources = [] + +; Shows a warning in case some of the unit, building, or resource names in this config file don't match anything in the scenario data. +warn_about_unrecognized_names = true + +; Overrides the rules for when units are eligible to retreat based on their movement. The possible options are: +; standard: No change from base game rules +; none: No units will ever retreat +; all-units: All non-immobile units may retreat, even if they have only one move or are up against a faster opponent +; if-faster: Units may retreat when they are faster than their opponent, for example a cavalry may retreat from a knight +; if-not-slower: Units may retreat when they are at least as fast as their opponent, for example a knight may retreat from another knight but not +; from a cavalry, and an infantry may retreat from another infantry +; if-fast-and-not-slower: Like if-not-slower but only fast (2+ move) units may retreat +; These settings don't change the fact that units cannot retreat when they start combat with 1 HP or are defending a city. They also do not change +; that naval units cannot retreat defensively (there is a separate option for that below). +land_retreat_rules = standard +sea_retreat_rules = standard + +; Under the base game rules, no unit may retreat defensively if it's located on a water tile. This option removes this special rule so naval units can +; retreat defensively like land units do. See also: the sea_retreat_rules option above and the limit_defensive_retreat_on_water_to_types option below. +allow_defensive_retreat_on_water = false + +; If any unit types are listed here, defensive retreat on water tiles will be limited to those types. Otherwise, all types may retreat that way. The +; list is separated by spaces and multi-word type names must be wrapped in quotation marks. For example, setting to: +; [Submarine "Nuclear Submarine"] +; would mean that only those submarine naval units could retreat defensively. This option does nothing if allow_defensive_retreat_on_water is false. +limit_defensive_retreat_on_water_to_types = [] + +; The multi-city start spawns in multiple cities for AI players at the start of the game instead of their usual one settler. This option controls the +; number of cities the AI starts with. E.g., if it's set to 2, the AI starts with 2 cities. If it's set <= 0, the game starts like normal. The mod can +; also add improvements to the AI's extra cities, which are intended to work like extra palaces, see ai_multi_start_extra_palaces. +ai_multi_city_start = 0 + +; This option only applies if ai_multi_city_start is set > 1. It controls how many tiles the mod will randomly check while searching for a suitable +; location for each of the AI's extra starter cities. Default: 10000. +max_tries_to_place_fp_city = 10000 + +; This option only applies if ai_multi_city_start is set > 1. It specifies a list of improvements to be added to the AI's additional cities. E.g: +; ["Forbidden Palace" Courthouse] +; If the AI multi-city start is set to 3+ with the above extra palaces, the AI players will start with 3+ cities and the first one will have the +; Palace like normal, the second will have the Forbidden Palace, and the third will have a courthouse, any after that will start empty. +; Additionally, any small wonders listed here with the "reduces corruption" effect will be considered "extra palaces" for the AI. They will respawn +; like the real Palace. In other words, if an AI loses a city with an extra palace, it will reappear in another one of its cities following the same +; logic the game uses to select a new Palace location. If the AI is missing an extra palace and acquires a new city, that extra palace will +; automatically be added to the new city. +ai_multi_start_extra_palaces = [] + +; Turning this on makes small or great wonders with the "reduces corruption" effect, such as the Forbidden Palace, as effective at reducing corruption +; as the palace itself. This reduces corruption not only in the city that contains such a wonder, it also reduces distance and rank corruption in +; nearby cities as if the city were an additional capital. +promote_wonder_decorruption_effect = false + +allow_military_leaders_to_hurry_wonders = false + +; The AI's beaker production will be multiplied by this amount, as a percent. A value of 100 gives you the standard game behavior, a value of 75 +; reduces AI research by 25%, a value of 200 doubles AI research, and so on. +ai_research_multiplier = 100 + +; Each time an AI player founds a city, the given amount of perfume will be applied to its settlers over the given duration in number of turns. The +; perfume effect declines steadily to zero over the duration. The perfume amount may be specified as a percentage. The purpose of these options is to +; slow the AI's expansion with negative perfume. +; NOTE: The AI has a very strong tendency to build settlers so you'll need to set these options quite high to slow it down significantly. For example, +; a perfume of -200% over a 30 turn duration left the AI with about half as many cities after 50 turns in my test. +ai_settler_perfume_on_founding = 0 +ai_settler_perfume_on_founding_duration = 0 + +; If a player can't afford to pay maintenance on their buildings and units, the game will forcibly lower expenses and raise money by (in order): +; 1. Selling buildings, excluding those that are maintenance-free or contribute to gold production even indirectly +; 2. Disbanding units, excluding free ones +; 3. Switching cities to building Wealth +; For AI players, the game alternates the order of (1) and (2) each turn. Also for AIs, on every third turn, the game will cut their research spending +; as much as necessary to avoid bankruptcy. +aggressively_penalize_bankruptcy = false + +; Under the standard game rules, the Despotism tile penalty does not apply to food yield from city tiles of Agricultural civs with fresh water. Set +; this option to true to remove that exception to the penalty. +no_penalty_exception_for_agri_fresh_water_city_tiles = false + +; Adds an option to the stealth attack target selection popup that allows the player to opt out of doing a stealth attack. If selected, the unit will +; attack normally, targeting the tile's top defender. Similarly, if stealth bombardment is canceled, the unit will bombard normally and may target +; buildings or population if attacking a city. +include_stealth_attack_cancel_option = false + +; Aircraft flying a recon mission can be intercepted by enemy fighters or ground AA as if they were flying a bombing mission +intercept_recon_missions = false + +; Under the standard rules, performing a recon mission or intercepting an attacker causes a unit to lose all of its remaining moves. Setting this +; option to true causes those actions to only consume one move. This makes them consistent with other air missions like bombing. Note: fighters will +; only be able to intercept multiple times in one turn if they have the blitz ability. +charge_one_move_for_recon_and_interception = false + +; In the base game, precision striking was only intended to be used by bombers. This option extends the precision strike logic to cover land & sea +; artillery and cruise missiles. Specifically what it does is: +; 1. Fixes the animations, so land & sea artillery will play their bombard animations and cruise missiles will play their strike animation +; 2. Makes it so that the strikable range depends on the bombard range for land & sea units instead of operational range +; 3. Despawns cruise missiles after they've performed a precision strike +polish_precision_striking = true + +; Enables units to perform stealth attacks when they bombard or bomb a target. Like regular stealth attacks this opens a popup allowing the player to +; choose a specific unit to target. The attacking unit must have the stealth attack special action checked, must have a list of stealth attack targets +; set, and the target tile must be visible. +enable_stealth_attack_via_bombardment = false + +; Prevents aircraft from being damaged by bombardment or bombing +immunize_aircraft_against_bombardment = false + +; Unit type names listed here will use PTW-like targeting when bombarding cities. PTW-like means there is a 1-in-3 chance they will target each of +; population, buildings, and units. This is unlike Conquests artillery targeting, which always goes after units first. Items in the list are separated +; by spaces and multi-word items must be wrapped in quotation marks like for perfume specs. Example: [Catapult Cannon Artillery "Radar Artillery"] +ptw_like_artillery_targeting = [] + +; Changes the meaning of the charm attack flag to indicate PTW-like targeting. This is a matter of convenience. It allows modders to specify PTW +; targeting using an editor, instead of the list above, at the cost of losing the charm attack function. +charm_flag_triggers_ptw_like_targeting = false + +; Unit types listed here won't be allowed to bombard land tiles. Same format as ptw_like_artillery_targeting, example: [Submarine "Torpedo Bomber"] +can_bombard_only_sea_tiles = [] + +; Units with the king ability will defend like normal, instead of always being the last to defend in a stack. Useful for mods that use the king flag +; for special purposes. Does not apply in regicide games. +ignore_king_ability_for_defense_priority = false + +; Untradable techs will appear grayed out on the trade screen. This lets you see which untradable techs the AI has just like for tradable +; ones. "Untradable" means techs that have been flagged as "cannot be traded" in the editor. This option only matters for modded games as there are no +; untradable techs in the standard game. +show_untradable_techs_on_trade_screen = false + +; Barbarians will capture cities instead of ransacking them. This option also modifies the game's production logic so barbarian cities can build +; things, grow, and even do research. +; This feature is EXPERIMENTAL at the moment. It basically works but hasn't been extensively tested. For example, I don't know what would happen if +; the barb player were to win the game. +; Because of how barb city production works under the hood, it requires barb activity to be turned on in order to work. The mod will handle this +; automatically. If this option is enabled, there is at least one barb city on the map, and the barb activity level is set to 0 (no barbarians), the +; level will be increased to 1 (sedentary) in order not to block barb city production. +enable_city_capture_by_barbarians = false + +; A list of modifications to the rules for defensive bombard. "Defensive bombard" is the free shot a bombard unit gets when the stack it's in is +; attacked. The possible options are: +; lethal: Attackers may be destroyed by defensive bombard if the bombarding unit has the appropriate lethal land/sea bombard ability. +; aerial: Air units may perform defensive bombard if they can perform bombing missions. +; not-invisible: Attacking units are immune to defensive bombard if they are invisible and not detected. +; blitz: Units with blitz may perform defensive bombard multiple times per turn, once for each move they have. +; docked-vs-land: Docked ships (i.e. in a city) can perform defensive bombard against land units attacking their city. +; For example, to activate all options, set to [lethal aerial not-invisible blitz docked-vs-land]. The order of items in the list does not matter. You +; can also activate all options by setting to [all] (with or without the brackets). +special_defensive_bombard_rules = [] + +; A list of modifications to the rules for zone of control, like above for defensive bombard. The possibilities are: +; amphibious: Land units may exert zone of control over sea units and vice-versa. This can only be done using bombard strength, not attack +; strength. It also requires non-zero bombard range. +; lethal: Units may be destroyed by zone of control. The intercepting unit must have the lethal bombard ability in order to do this, even if it's +; using its attack strength to exert ZoC. +; aerial: Air units can exert zone of control if their type has the "Zone of Control" option checked. Additionally, they must be able to perform the +; bombing mission, have non-zero bombard strength, and non-zero operational range. +; not-from-inside: Land units may not exert zone of control while inside a transport (armies do not count as transports) +; Like for defensive bombard, all options can be activated by setting to [all] (with or without the brackets), and order does not matter. +special_zone_of_control_rules = [] + +; All human players in a hotseat game will share visibility +share_visibility_in_hotseat = false + +; All human players in a hotseat game will share the effects of the wonders they've built, great or small. This applies to all civ-wide effects, for +; example if any human player builds Leonardo's Workshop, all human players get half price upgrades. Notes: +; 1. If a human player receiving the shared effect of a small wonder and that SW has no non-shared effects, it becomes unbuildable for that player. +; 2. Building and army requirements for wonders are shared as well. For example, all human players are allowed to build Battlefield Medicine once all +; of them combined have five hospitals. +; 3. For the Great Library effect, known AI civs are shared as well. If an AI has contact with any human player, it is considered to be in contact +; with all of them for the purpose of granting techs to human players. +share_wonders_in_hotseat = false + +allow_precision_strikes_against_tile_improvements = false +dont_end_units_turn_after_bombarding_barricade = false + +; Allows land units to bombard aircraft and naval units in cities +; This does not override the immunity of aircraft vs bombardment, if that option is also activated. +remove_land_artillery_target_restrictions = false + +; Allows tile improvements on a tile with an occupied airfield to be destroyed by bombardment, not including the airfield itself. For example, under +; the standard game rules, if you bombard a tile with a road, airfield, and fighter on it, you will do no damage because the attack will target the +; fighter which is invulnerable (aircraft in an airfield cannot be damaged by bombardment). This option allows such an attack to bypass the fighter +; and hit the tile instead, as long as that tile has an improvement other than the airfield. +allow_bombard_of_other_improvs_on_occupied_airfield = false + +; Displays the total number of cities in the game on the demographics screen (press F11). +show_total_city_count = false + +; Under the standard game rules, each forbidden-palace-like building in an empire increases its optimal city number (OCN) by 37.5% of the base number, +; except if the empire is running a government with communal corruption, in which case the increase is 100% of the base. With this option enabled, the +; communal corruption rule is always in force, so each forbidden palace always increases the OCN by an amount equal to the base number. +; NOTE: The "base" optimal city number comes from the map size. It's the number set on the "World Sizes" tab in the editor. +strengthen_forbidden_palace_ocn_effect = false + +; This option allows you to increase the maintenance cost of units depending on their shield cost. For every X shields that the unit costs to build +; (where X is the setting below), the unit's maintenance increases by one unit's worth. For example, if set to 100, units that cost 0-99 shields will +; have normal maintenace, units costing 100-199 shields will cost double, those costing 200-299 will cost triple, etc. (Note the final cost in GPT +; depends on gov't type). Set <= 0 to disable. +extra_unit_maintenance_per_shields = 0 + +; This option renames players' civs depending on their eras. The format is a list of names each associated with a list of replacements. There is one +; replacement for each era or, if the list is shorter than the number of eras, no replacement will be done in the later eras. Example: +; [Rome: Rome "Byzantine Empire" Italy Italy, +; Roman: Roman Byzantine Italian Italian, +; France: Gaul, French: Gaulic] +; In this example, Rome will be renamed to "Rome" in the first era, "Byzantine Empire" in the second, and "Italy" in the third and fourth. The +; adjectives will be replaced to match. France/French will be renamed to Gaul/Gaulic only in the first era. +; Spaces are used to separate words so if a name or replacement has multiple words it's necessary to use quotation marks to group them together like +; for "Byzantine Empire" in the example. +; The replacements apply to civ nouns, adjectives, and formal names. If a player has put in a custom name, that will not be replaced. +civ_aliases_by_era = [] + +; This option works like the one above except it replaces leader names instead of civ names. Each replacement name may be followed by (M) or (F) to +; specify gender. Example: +; ["Joan d'Arc": Vercingetorix (M) "Joan d'Arc" (F) Napoleon (M) "De Gaulle" (M)] +; If no gender is specified then the game will use whatever gender was set in the scenario data for that civ's leader. That means (F) could be omitted +; in the above example since the leader of France is already female. +; Additionally you can include a replacement title after the gender separated by a comma. Here's the example with titles added: +; ["Joan d'Arc": Vercingetorix (M, King) "Joan d'Arc" (F) Napoleon (M, Emperor) "De Gaulle" (M, President)] +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 +; 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. +; 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. +unit_limits = [] + +; Removes barracks/harbor/airport requirement from upgrades +allow_upgrades_in_any_city = false + +; Stops the game from placing volcanos during map generation. Any tiles that would have been volcanos will be mountains instead. +do_not_generate_volcanos = false + +; Stops the game from placing pollution on impassable tiles +do_not_pollute_impassable_tiles = false + +; Includes the hitpoints of each possible target on the stealth attack selection popup. This makes it easier to pick out weakened units. +show_hp_of_stealth_attack_options = false + +; Stops invisible units from being targeted by stealth attacks. They can still be targeted if they've been revealed by the attacking civ. +exclude_invisible_units_from_stealth_attack = false + +; Stops units from being targeted by stealth attack if they are contained in another unit such as a naval or land transport, or a helicopter. +exclude_passengers_from_stealth_attack = false + +; Normally planting a forest always produces the regular non-LM forest terrain. This option changes that so it instead produces LM forest. +convert_to_landmark_after_planting_forest = false + +; This option specifies how likely it is (in percent) for a combat land or sea unit with a maximum of one HP to be destroyed when struck by a +; nuke. Set to 100 for base game behavior. +chance_for_nukes_to_destroy_max_one_hp_units = 100 + +; Allows you to sell aqueducts and hospitals as well as any modded buildings that uncap population growth. A city must be below the pop cap for a sale +; to be allowed, i.e., under the standard rules, aqueducts may only be sold in cities of pop <= 6 and for hospitals pop <= 12. +allow_sale_of_aqueducts_and_hospitals = false + +; Allows you to sell Small Wonders. This may be useful to relocate Forbidden Palace-like Small Wonders. +allow_sale_of_small_wonders = false + +; This option makes it so that only sea units with the "detect invisible" ability can reveal invisible sea units, and likewise for non-sea units. +no_cross_shore_detection = false + +; Controls the size of the area in which cities can work tiles. The value corresponds to cultural border expansions. For example, setting this to 1 +; means cities would only be able to work tiles within their level 1 cultural borders, meaning the eight tiles neighboring the city's own +; tile. Setting to 2 gives you the game's standard rule that cities may work tiles within their level 2 cultural borders, which they attain after one +; expansion. Setting to 3 allows them to work within level 3 borders and so forth. +; Notes: (1) If the city can work tiles in the fourth ring or farther, the map view on the city screen will be zoomed out when you enter it if +; auto_zoom_city_screen_for_large_work_areas is true. Otherwise it's not possible to show the entire work area. You can zoom back in by pressing Z. +; (2) The next option below can limit cities' workable areas to be smaller than the radius set here, based on their culture. (3) This option has a +; minimum value of 1 and a maximum of 7. +city_work_radius = 2 +auto_zoom_city_screen_for_large_work_areas = true + +; This option can reduce the size of the area cities can work based on their cultural level. +; Possible values are: +; none: Standard game rules apply; cities can work any tile that's within the work radius and within their owner's borders. +; cultural: Cities may only work tiles that are within their direct cultural borders, e.g. a city with zero culture may only work the 8 surrounding +; tiles. After one expansion, it may work the standard 20, after a second expansion it may work the third ring, and so on. +; cultural-min-2: Like "cultural" except cities can always work their standard 20 tiles. +; cultural-or-adjacent: Cities can work tiles in their direct cultural borders plus any tiles adjacent to those. +work_area_limit = none + +; This option can also reduce the size of the area cities can work based on improvements present. +; This mechanic works in tandem with the above work_area_limit condition - tiles cannot be worked if the tiles do not also meet the cultural work area limit requirement. +; If left empty, this mechanic is not used. +; Improvements may be defined to grant a certain radius work area, and the highest radius present is used as the work radius for a city. eg ["Harbor": 3] +; Improvements may also grant a bonus radius, these are added on after the highest radius is found. [Factory: 3, "Mass Transit": 2 extra] +; An entry written as default or "default" will always be present for any given city, and represents an always-present virtual improvement. eg. ["default": 2] gives vanilla behaviour. +work_area_improvements = [] + +; The maximum distance it's possible to rebase an aircraft equals its operational range times this value. For standard game rules, set to 6. +rebase_range_multiplier = 6 + +; This option prevents units from loading into two different transports on the same turn. Once a unit has been loaded into a transport, it becomes +; tied to that transport for the remainder of the turn and cannot be loaded into any other. Loading into armies is not affected. The purpose of this +; option is to make the galley chaining exploit impossible. +limit_unit_loading_to_one_transport_per_turn = false + +; In the base game, if you set Cavalry to upgrade to Tank but don't give it the upgrade ability, intending to make Cavalry obsolete when Tanks become +; available but not upgradable to them, you'll be left with the strange situation that older units such as Knights are allowed to upgrade to Tanks +; even though Cavalry are not. This option makes it so that Knights upgrade to Cavalry in that case. In general, it makes it so that upgrade chains +; stop at the type along the chain that does not have the upgrade ability. +; NOTE: The chain is only stopped if the civ in question can build the unit type. The example above is simplified. In the actual rules, Cavalry +; upgrades to Sipahi, which upgrades to Cossack. Blocking the upgrade chain at Cavalry would prevent Ottomans and Russia from upgrading to their +; unique units, so the mod won't do that. You must clear the upgrade ability from Sipahi and Cossack as well to block those civs there instead. +prevent_old_units_from_upgrading_past_ability_block = false + +; Buildings double their culture production this many years after they were built. For standard game rules, set to 1000. +years_to_double_building_culture = 1000 + +; Controls how long it takes for wonders to produce tourism gold as a percent of the standard rate. For example, if set to 200, it would take 2000 +; years to begin generating 2 GPT tourism, instead of the standard 1000 years, and 3000 years for 4 GPT, instead of the standard 1500. This setting is +; effectively a scaling factor on the tourism time thresholds. For standard rules, set to 100. +tourism_time_scale_percent = 100 + +; On the first turn of a hotseat game, all human players will be given diplomatic contact with each other. +introduce_all_human_players_at_start_of_hotseat_game = false + +; Allows units to be unloaded from an army. The army type must have the "unload" ability set in the editor. +allow_unload_from_army = false + +; Allow colonies to be built on tiles inside another civ's territory (for strategic/luxury resources); applies a relation penalty with the other civ, per each colony. +allow_extraterritorial_colonies = false +per_extraterritorial_colony_relation_penalty = 3 + +; A list of rule modifications to make land transports more practical. Works like special_defensive_bombard_rules. The possibilities are: +; load-onto-boat: Allows land transports to be loaded into naval units +; join-army: Allows empty land transports to join armies +; no-defense-from-inside: Prevents units inside a land transport from defending their tile, performing defensive bombard, or intercepting air units +; no-escape: Destroys the passengers inside a land tranport when the transport itself is destroyed or captured +land_transport_rules = [] + +; Prevents land anti-air units from intercepting overflying units while they're loaded in a naval transport +no_land_anti_air_from_inside_naval_transport = false + +; A list of rule modifications for air units with transport capacity called "helicopters" for short. Works like special_defensive_bombard_rules. The +; possibilities are: +; allow-on-carriers: Allows helicopters to be rebased or loaded onto carriers +; passenger-airdrop: Allows paratroopers inside a helicopter on a carrier to perform airdrops +; no-defense-from-inside: Prevents units inside a helicopter from defending their tile, performing defensive bombard, or intercepting air +; units. Also destroys passengers when the helicopter is destroyed in most circumstances in order to avoid problems such as a helicopter being +; captured by a land unit leaving its passengers alive on the same tile. +; no-escape: In all circumstances, destroys the passengers inside a helicopter when the heli itself is destroyed or captured +special_helicopter_rules = [] + +; Stops units from enslaving a target they've destroyed by bombarding as opposed to direct combat +prevent_enslaving_by_bombardment = false + +; Relaxes a rule that prevents resources from appearing directly next to another resource of a different type +allow_adjacent_resources_of_different_types = false + +; Controls the overall number of luxury resources placed on the map for luxury types that don't have a fixed appearance rate set in the editor. Under +; the standard rules, no luxuries have appearance rates set. Without a set rate, the game randomly chooses a rate between 50 and 100, biased toward +; the middle (75). This setting is a percent scaling on that range, so setting it to 150 means luxuries would have their rate randomized between 75 +; and 150, setting to 50 means a range of 25 to 50, and so on. For base game behavior, set to 100. +luxury_randomized_appearance_rate_percent = 100 + +; During map generation, the game places bonus resources until the total number of strategic and bonus resources reaches the tile count divided by +; this number. Raising this setting causes fewer bonus resources to be generated and lowering it increases them. For the standard rate, set to 32. +tiles_per_non_luxury_resource = 32 + +; Normally the corruption rate in the capital is fixed at zero. Setting this to true removes that, allowing corruption to appear in the capital. The +; capital also has a strong inherent bonus reducing corruption so even when this setting is on, it will usually have zero corruption. To reduce that +; bonus, see the special_capital_decorruption_effect option below. +allow_corruption_in_capital = false + +; Controls the special decorruption bonus that's applied to the capital. This bonus is incorporated into the decorrupting effect from buildings in the +; city and each point is equivalent in strength to one courthouse. For standard game rules, set to 10. This option does nothing unless +; allow_corruption_in_capital is set to true. Min value 0, max 100. +special_capital_decorruption_effect = 10 + +; Overrides the NoAIPatrol setting from conquests.ini. Possible values are: +; none: No override, use the setting from the INI like normal +; one: Set NoAIPatrol to 1, disabling AI patrol behavior +; zero: Set NoAIPatrol to 0, allowing AI units to patrol +; The purpose of this option is to enable you to configure NoAIPatrol like a C3X setting instead of globally. In particlar, it allows you to configure +; NoAIPatrol on or off on a per-scenario basis. +override_no_ai_patrol = none + +; Overrides the barbarian activity level when starting a new game for a scenario with a custom map. Normally, in that case, the game will use the +; barbarian settings kept in conquests.ini, ignoring what was set for the map in the editor. This option allows you to set an activity level on a +; per-scenario basis like other C3X settings. +; The possible values are "none" for no override, i.e. base game behavior, or one of the selectable barbarian activity levels: "No Barbarians", +; Sedentary, Roaming, Restless, Raging, or Random. You can specify either the original English names just listed or the custom/translated names in +; labels.txt. The value is not case sensitive. +override_barbarian_activity_level_for_scenario_maps = none + +; Leader units placed on the map as part of a scenario do not have their leader types filled in properly, which means they behave differently than +; proper military leaders would. In particular, they are allowed to hurry production of great wonders and spaceship parts. This option fills in their +; types at the start of the game so they behave like normal MGLs spawned during a game. +;initialize_preplaced_scenario_leaders_as_mgls = false + +enable_unit_counters = true + +; Civ 4 style best defender selection. +; When this is on (and enable_unit_counters is also true), every time an attack happens the engine picks the +; defender that is HARDEST for the current attacker to beat (the unit with the highest defender win rate +; once unit-counter rules are applied), instead of the vanilla "highest defense strength" rule. The same +; unit is also forced to the top of the enemy stack on the map whenever a player has an attacker selected, +; so the displayed unit stays in sync with what would actually fight. Re-targeting is automatic: switching +; the selected attacker (different counter match-ups) updates which enemy unit is shown as the best defender. +; Notes: +; - Has no effect when enable_unit_counters = false (then there's nothing to differentiate beyond defense). +; - Applies to both human and AI attackers, so the rule is consistent. +; - Does not change ranged-bombard or defensive-bombard target selection, only normal attacks. +use_civ4_style_best_defender = true + +; unit_group allows you gruop your units in a group,please refer to building_prereqs_for_units for the format. +; This function will not work if enable_unit_counters is false. +unit_group = [] +; ── counter_rule format ────────────────────────────────────────────────────────────── +; +; counter_rule = [Friendly vs Enemy Effect... Conditions...] +; +; 【Friendly / Enemy】 +; This can be one of the following three options: +; · The specific unit type, such as "Archer" (must match the name in BIQ exactly; names containing spaces must be enclosed in quotation marks) +; · A unit group name, such as melee (i.e. the group defined in the unit_group section above) +; · "*" represents any unit type (the asterisk must be enclosed in quotation marks) +; +; 【Effect】(Expressed as a percentage; when multiple rules apply to the same battle, their effects are multiplied.) +; +; "self" always refers to the first unit, and "enemy" always refers to the second unit, regardless of who is attacking whom: +; self-atk value — The unit’s attack power becomes N% of its original value +; Example: self-atk 150 = attack power ×1.5; self-atk 50 = attack power ×0.5 +; self-def value — Your defence becomes N% of the original value; +; enemy-atk value — The enemy’s attack becomes N% of the original value; +; enemy-def value — The enemy’s defence becomes N% of the original value; +; +; 【Conditions】(Optional; leaving blank indicates no restrictions; conditions take effect only when all are met simultaneously) +; in-city —— Takes effect only when the enemy is on a city tile +; terrain terrain_name —— Takes effect only when the enemy is on a tile of the specified terrain +; The terrain name must match the name in BIQ, e.g. Grassland, Forest, Hills +; ignore-terrain —— Ignores the enemy’s terrain defence bonus (sets their terrain bonus to zero) +; Can be used in conjunction with enemy-def; when used together, ignore-terrain takes precedence +; district district_name —— Only takes effect when the enemy is in a specified district (enable_districts must be enabled) +; +; 【Examples】 +; counter_rule = [ranged vs melee self-atk 125] +; → When a ranged unit attacks a melee unit, its attack power is multiplied by 1.25 +; +; counter_rule = ["Knight" vs melee in-city enemy-def 150] +; → When knights attack melee units within a city, the enemy’s defence is multiplied by 1.5 +; +; counter_rule = ["Musketeer" vs "Medival Infantry" terrain Grassland self-atk 125] +; → When musketeers attack medieval infantry on grassland terrain, their attack power is multiplied by 1.25 +; +; counter_rule = ["Knight" vs "*" ignore-terrain self-atk 150] +; → When a Knight attacks any unit, its attack power is multiplied by 1.5 and it ignores the enemy’s terrain bonus. +; counter_rule = [Archer vs Swordsman self-atk 130 self-def 120] +; → When an archer attacks a swordsman: Archer’s attack power ×130% +; When a swordsman attacks an archer: Archer’s defence ×120% +; +; ───────────────────────────────────────────────────────────────────────────── + +counter_rule = [] + +[==================] +[=== AESTHETICS ===] +[==================] + +; If a tile has a forest, render it on top of roads and railroads, instead of underneath them. +draw_forests_over_roads_and_railroads = true + +; This allows you to set a victory animation for air units. Can be set to the name of any animation that is loaded by the game, specifically one of: +; blank, default, run, attack1, attack2, attack3, death, fortify, fidget, victory, capture, fortress, build, road, mine, irrigate, jungle, forest, plant +; Note that bomber units already have their bombing animations in the victory slot so "victory" is not a good choice here. For standard game behavior, +; set to "none". +aircraft_victory_animation = none + +; Enables naming tiles via the right-click menu and displays those names on the map. +enable_named_tiles = true + +[=======================] +[=== DAY/NIGHT CYCLE ===] +[=======================] + +; How the day/night cycle operates in the game. If enabled, terrain, cities, resources, landmarks and terrain buildings will change appearance based on +; the time of day, with 24 possible stages (one for each hour). The base game art is used for 12pm. If set to 'off', only base game art will be used. +; Day/night cycle should not be used if you are using non-standard terrain art or resources. Doing so may result in visual glitches or missing art. +; Note that day/night cycle art is not bundled directly with C3X and must be downloaded separately at https://forums.civfanatics.com/resources/day-night-cycle-in-civ-3-using-c3x.32520/ +; The possible values are: +; off: Only base game art used +; timer: Increment based on time elapsed since last hour transition (e.g., transition to next hour every 3 minutes) +; user-time: Match the user's system clock to determine hour of the day +; every-turn: Increment every turn by a fixed amount of hours +; specified: Pin the hour to a specific value (so hour of day is always the same) +day_night_cycle_mode = off + +; If day_night_cycle_mode is set to 'timer', minimum minutes of real time to elapse before transitioning to the next hour in the cycle. +; This is checked only at the end of the turn, so actual minutes may exceed this number. +elapsed_minutes_per_day_night_hour_transition = 3 + +; If day_night_cycle_mode is set to 'timer' or 'every-turn', the number of hours to transition. This should be a value between 1 and 12 inclusive. +fixed_hours_per_turn_for_day_night_cycle = 1 + +; If day_night_cycle_mode is set to 'specified', the hour of the day to pin the cycle to. This should be a value between 0 (midnight) and 23 (11pm) inclusive. +pinned_hour_for_day_night_cycle = 0 + +[=======================] +[=== NATURAL WONDERS ===] +[=======================] + +; Show or hide natural wonders on the map. When disabled, natural wonders will not appear on the map. +enable_natural_wonders = false + +; If a new scenario is loaded which has no natural wonders defined, add natural wonders. +add_natural_wonders_to_scenarios_if_none = false + +; Show the names of natural wonders on the map below their image. +show_natural_wonder_name_on_map = true + +; Minimum separation (in tiles) between natural wonders when generating the map. This helps prevent clustering of natural wonders. +minimum_natural_wonder_separation = 10 + +[=================] +[=== DISTRICTS ===] +[=================] + +; Districts are Civ6-inspired structures built by workers that enable buildings, provide bonuses, and make cities feel more alive. When enabled, +; districts appear on the map and can be required for certain buildings (configured in default.districts_config.txt). Districts occupy tiles within a +; city's work radius, making those tiles unworkable. They can provide bonuses (food, shields, gold, science, culture, defense) to all cities within +; their work radius. If multiple cities share a district, they can optionally share its buildings and wonders (see options below). Districts with +; pollution or enemy units yield no bonuses. Destroyed districts remove dependent buildings from affected cities unless they have another district of +; that type in range. The five district types below can be enabled independently: +; enable_districts: Enables standard configurable districts (by default: Encampment, Campus, Holy Site, Commercial Hub, Entertainment Complex, Industrial Zone). +; Configured is done in default.districts_config.txt, user.districts_config.txt, and scenario.districts_config.txt +; enable_neighborhood_districts: Enables population growth past a configurable limit (see maximum_pop_before_neighborhood_needed below) +; enable_wonder_districts: Wonders require a dedicated district tile, making them visible on the map and optionally destructible. +; Configured in default.districts_wonders_config.txt, user.districts_wonders_config.txt, and scenario.districts_wonders_config.txt +; enable_distribution_hub_districts: Special districts that distribute food/shields from surrounding tiles to all connected cities +; enable_aerodrome_districts: Air units can only be built/based at Aerodrome districts instead of cities (if air_units_use_aerodrome_districts_not_cities is true) +; enable_port_districts: Enables Port districts, which serve as coastal district tiles for naval production/basing when naval_units_use_port_districts_not_cities is on. +; enable_bridge_districts: Enables Bridge districts on coastal water; completed bridges let land units cross water tiles. +; enable_canal_districts: Enables Canal districts on land; completed canals let naval units traverse land tiles between water bodies. +; enable_central_rail_hub_districts: Enables Central Rail Hub districts used for rail-era infrastructure (e.g., Mass Transit). +; enable_energy_grid_districts: Enables Energy Grid districts associated with power plant infrastructure. +; enable_great_wall_districts: Enables Great Wall districts (wall-like tiles that can block others if great_wall_districts_impassible_by_others is on). +enable_districts = false +enable_neighborhood_districts = false +enable_wonder_districts = false +enable_distribution_hub_districts = false +enable_aerodrome_districts = false +enable_port_districts = false +enable_bridge_districts = false +enable_canal_districts = false +enable_central_rail_hub_districts = false +enable_energy_grid_districts = false +enable_great_wall_districts = false + +; When multiple cities share a district (i.e., the same district tile is within multiple cities' work radii), these options control whether those +; cities automatically share the benefits of buildings and wonders constructed in that district. For example, if Rome and Veii both have the same +; Encampment in their work radius and Rome builds a Barracks in that Encampment, enabling cities_with_mutual_district_receive_buildings will cause +; Veii to automatically receive a Barracks as well. Similarly, cities_with_mutual_district_receive_wonders extends this sharing to Great and Small +; Wonders. This encourages strategic district placement between cities and can reduce micromanagement in dense urban areas. +; Note: receiving buildings is only assessed twice: when a city completes a building, and when a city is founded nearby. A city receiving a building +; cannot in turn recursively share it with third, fourth, fifth, etc. cities in a chain. Only applies if enable_districts is set to true. +cities_with_mutual_district_receive_buildings = true +cities_with_mutual_district_receive_wonders = true +show_message_when_building_received_by_mutual_district = true +show_message_when_building_lost_to_destroyed_district = true + +; When enabled, air units can only be built in cities with an Aerodrome district in their work radius and must be based at Aerodrome districts instead +; of cities. Air units will spawn on Aerodromes and can only land on Aerodromes, vanilla airfields, or carriers. Airlifts and airdrops are similarly +; limited to Aerodromes. This adds strategic depth by requiring infrastructure for air power and making air bases visible and vulnerable on the map. +; Only applies when enable_aerodrome_districts is also set to true. +air_units_use_aerodrome_districts_not_cities = true + +; When enabled, naval units can only be built in cities with a Port district in their work radius and cannot enter city tiles directly. Naval unit +; healing must be done at Port districts, and travel between continents, lakes and so on can instead only be done via Canal districts (via enable_canal_districts), +; rather than cities on an isthmus. Additionally, a city cannot build naval units until it has a Port district in range. Only applies when enable_port_districts is set to true. +naval_units_use_port_districts_not_cities = true + +; Neighborhood district limit population growth. Once a city reaches maximum_pop_before_neighborhood_needed, it cannot +; grow further until it has at least one Neighborhood district in its work radius. Each Neighborhood then enables additional population growth equal to +; per_neighborhood_pop_growth_enabled. For example, with maximum set to 6 and per_neighborhood set to 2, a city can grow to pop 6 without +; Neighborhoods, requires 1 Neighborhood to reach pop 8, requires 2 Neighborhoods to reach pop 10, and so on. Neighborhood bonuses (+1 gold and +1 +; culture, by default) only apply if the city actually needs them based on its population. Periodic popups will remind you when a Neighborhood is needed. Only +; applies when enable_neighborhood_districts is set to true. neighborhood_needed_message_frequency sets how often (in turns) the reminder message appears; +; set to 0 to disable. +; If destroying_neighborhood_reduces_pop is true, losing a Neighborhood district reduces the city's population down to the new cap. +maximum_pop_before_neighborhood_needed = 6 +per_neighborhood_pop_growth_enabled = 3 +neighborhood_needed_message_frequency = 4 +destroying_neighborhood_reduces_pop = true + +; These options control the vulnerability and rebuildability of completed Wonders in Wonder districts. When completed_wonder_districts_can_be_destroyed +; is enabled, completed Wonders (both Great and Small) can be pillaged or destroyed by enemies, making them valuable strategic targets that must be +; defended. When destroyed_wonders_can_be_built_again is enabled, destroyed Wonders become available again for any civ to build, putting them back +; into play. Only applies when enable_wonder_districts is set to true. +completed_wonder_districts_can_be_destroyed = true +destroyed_wonders_can_be_built_again = true + +; Distribution Hubs work as "breadbaskets" and mining areas far from urban centers, minimizing local city potential but benefiting the entire civilization. +; Distribution Hubs make surrounding tiles unworkable and instead distribute their raw food and shield yields to ALL connected cities in your civilization. +; "Divisors" for food and shields multiply the sqrt-based divisor in scale-by-city-count mode, and are a straight divider in flat mode. Yields are subject +; to corruption as with regular shields. +; +; ai_ideal_distribution_hub_count_per_100_cities controls how many hubs the AI tries to maintain per 100 cities if distribution_hub_yield_division_mode +; is set to "flat" (e.g., 25 means the AI aims for 1 hub per 4 cities). +; +; distribution_hub_yield_division_mode controls how a hub splits its collected food/shields across connected cities: +; flat: Divide raw yields by the configured divisors (distribution_hub_food_yield_divisor & distribution_hub_shield_yield_divisor) +; scale-by-city-count: Bonuses gradually reduce as more cities plug into the hub. Formula: floor(raw_yield / (sqrt(connected_city_count) * divisor)) +; +; ai_distribution_hub_build_strategy controls how the AI decides to build distribution hubs: +; by-city-count: AI builds hubs based on its ideal hub count per 100 cities +; auto: AI dynamically assesses need based on city growth and food/shield deficits across civ +distribution_hub_yield_division_mode = scale-by-city-count +ai_distribution_hub_build_strategy = auto +distribution_hub_food_yield_divisor = 2 +distribution_hub_shield_yield_divisor = 2 +ai_ideal_distribution_hub_count_per_100_cities = 50 +max_distribution_hub_count_per_100_cities = 50 + +; Bonus percent applied to Distribution Hub food and shield yields for cities that have a Central Rail Hub district in their work radius. +central_rail_hub_distribution_food_bonus_percent = 25 +central_rail_hub_distribution_shield_bonus_percent = 25 + +; District placement and AI bridge/canal behavior: +; expand_water_tile_checks_to_city_work_area: Use the full city work radius (not just adjacent tiles) for river/lake/sea checks (e.g. to build a port if a +; city has coast within its work area, even if not adjacent to the sea). +; Note that this does not affect Aqueducts or Coastal Fortresses, which still require direct city adjacency. +; workers_can_enter_coast: Allow workers to move onto coast tiles without embarking. +; max_contiguous_bridge_districts: Maximum number of contiguous bridge district tiles allowed in a line (0 = no limit). +; max_contiguous_canal_districts: Maximum number of contiguous canal district tiles allowed in a line (0 = no limit). +; ai_canal_eval_min_bisected_land_tiles: Minimum land tiles required on each side for the AI to consider a canal candidate. +; ai_bridge_canal_eval_block_size: Map block size used when scanning for AI bridge/canal candidates. +; ai_bridge_eval_lake_tile_threshold: Water bodies at or below this size are treated as lakes for AI bridge evaluation. +; ai_can_replace_existing_districts_with_canals: Allow the AI to build canal/bridge districts over existing non-wonder districts. +; ai_builds_bridges: Allow the AI to construct bridge districts. +; ai_builds_canals: Allow the AI to construct canal districts. +expand_water_tile_checks_to_city_work_area = true +workers_can_enter_coast = true +max_contiguous_bridge_districts = 3 +max_contiguous_canal_districts = 5 +ai_canal_eval_min_bisected_land_tiles = 20 +ai_bridge_canal_eval_block_size = 10 +ai_bridge_eval_lake_tile_threshold = 5 +ai_can_replace_existing_districts_with_canals = true +ai_builds_bridges = true +ai_builds_canals = true + +; When enabled, AI defensive units will actively seek out and defend districts within their territory, treating them as valuable assets like colonies. +; The AI prioritizes defending Wonder districts (if destructible wonders are enabled) over regular districts, searching within a 20-tile radius for +; districts that need protection from nearby enemy units. This makes districts meaningful strategic targets and ensures the AI protects its +; infrastructure. Only applies when enable_districts is set to true. +ai_defends_districts = true + +; As AI cities queue up districts needed, the max number of turns to wait for a worker to build it before the request is dropped +; until the AI city is triggered to build the district again (e.g., by trying to build a building that depends on it) +ai_city_district_max_build_wait_turns = 20 + +; Great Wall behavior: +; disable_great_wall_city_defense_bonus: Disables the Great Wall wonder's city defense doubling effect. Only takes effect if districts and great wall districts are enabled. +; great_wall_districts_impassible_by_others: Great Wall district tiles block movement by other civs (unless obsolete). +; auto_build_great_wall_around_territory: Auto-place Great Wall districts along your borders when the specified wonder is built. +; great_wall_auto_build_wonder_name: Name of the wonder that triggers auto-building (empty disables auto-build). +; ai_auto_build_great_wall_strategy: How AI uses auto-built Great Wall: all-borders (any border tiles) or other-civ-bordered-only (only borders touching another civ). +disable_great_wall_city_defense_bonus = false +great_wall_districts_impassible_by_others = true +auto_build_great_wall_around_territory = true +great_wall_auto_build_wonder_name = "The Great Wall" +ai_auto_build_great_wall_strategy = other-civ-bordered-only + +; When enabled, holding down the Control key while a worker is selected will highlight all tiles within the work radii of nearby cities. City centers +; are highlighted more brightly, while tiles that fall within multiple cities' work radii are highlighted more intensely. This visual aid helps you +; strategically place districts and improvements by showing which cities will be affected. The highlights update dynamically as you move the worker +; around the map. Only applies when enable_districts is set to true. +enable_city_work_radii_highlights = true diff --git a/injected_code.c b/injected_code.c index 1995b9d6..2214670e 100644 --- a/injected_code.c +++ b/injected_code.c @@ -1,36673 +1,36916 @@ -#include "stdlib.h" -#include "stdio.h" - -#include "C3X.h" - -void (WINAPI ** p_OutputDebugStringA) (char * lpOutputString) = ADDR_ADDR_OUTPUTDEBUGSTRINGA; -short (WINAPI ** p_GetAsyncKeyState) (int vKey) = ADDR_ADDR_GETASYNCKEYSTATE; -FARPROC (WINAPI ** p_GetProcAddress) (HMODULE hModule, char const * lpProcName) = ADDR_ADDR_GETPROCADDRESS; -HMODULE (WINAPI ** p_GetModuleHandleA) (char const * lpModuleName) = ADDR_ADDR_GETMODULEHANDLEA; -int (WINAPI ** p_MessageBoxA) (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) = ADDR_ADDR_MESSAGEBOXA; - -struct injected_state * is = ADDR_INJECTED_STATE; - -// To be used as placeholder second argument so that we can imitate thiscall convention with fastcall -#define __ 0 - -// Many Windows and C standard library functions have to be loaded dynamically with GetProcAddress and the addresses are stored in the injected -// state. This is covered up with macros, which is not something I would normally do, but in this case it's very useful because it means the code in -// common.c can be shared by the patcher and the injected code. -#define VirtualProtect is->VirtualProtect -#define CloseHandle is->CloseHandle -#define CreateFileA is->CreateFileA -#define GetFileSize is->GetFileSize -#define ReadFile is->ReadFile -#define LoadLibraryA is->LoadLibraryA -#define FreeLibrary is->FreeLibrary -#define MessageBoxA is->MessageBoxA -#define MultiByteToWideChar is->MultiByteToWideChar -#define WideCharToMultiByte is->WideCharToMultiByte -#define GetLastError is->GetLastError -#define QueryPerformanceCounter is->QueryPerformanceCounter -#define QueryPerformanceFrequency is->QueryPerformanceFrequency -#define GetLocalTime is->GetLocalTime -#define TransparentBlt is->TransparentBlt -#define snprintf is->snprintf -#define malloc is->malloc -#define calloc is->calloc -#define realloc is->realloc -#define free is->free -#define strtol is->strtol -#define strtof is->strtof -#define strncmp is->strncmp -#define strcmp is->strcmp -#define _stricmp is->_stricmp -#define strlen is->strlen -#define strncpy is->strncpy -#define strcpy is->strcpy -#define strdup is->strdup -#define strstr is->strstr -#define qsort is->qsort -#define memcmp is->memcmp -#define memcpy is->memcpy -#define tolower is->tolower -#define toupper is->toupper - -#include "common.c" - -#define TRADE_SCROLL_BUTTON_ID_LEFT 0x222001 -#define TRADE_SCROLL_BUTTON_ID_RIGHT 0x222002 - -// Must match size of button images in descbox.pcx -#define MOD_INFO_BUTTON_WIDTH 102 -#define MOD_INFO_BUTTON_HEIGHT 17 - -#define MOD_INFO_BUTTON_ID 0x222003 - -#define PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID 0x222004 -#define PEDIA_MULTIPAGE_PREV_BUTTON_ID 0x222005 - -#define TILE_FLAG_ROAD 0x1 -#define TILE_FLAG_RAILROAD 0x2 -#define TILE_FLAG_MINE 0x4 -#define TILE_FLAG_IRRIGATION 0x8 - -#define NEIGHBORHOOD_DISTRICT_ID 0 -#define WONDER_DISTRICT_ID 1 -#define DISTRIBUTION_HUB_DISTRICT_ID 2 -#define AERODROME_DISTRICT_ID 3 -#define NATURAL_WONDER_DISTRICT_ID 4 -#define PORT_DISTRICT_ID 5 -#define CENTRAL_RAIL_HUB_DISTRICT_ID 6 -#define ENERGY_GRID_DISTRICT_ID 7 -#define BRIDGE_DISTRICT_ID 8 -#define CANAL_DISTRICT_ID 9 -#define GREAT_WALL_DISTRICT_ID 10 - -#define MAX_DISTRICT_VARIANT_COUNT 5 -#define MAX_DISTRICT_ERA_COUNT 4 -#define MAX_DISTRICT_COLUMN_COUNT 10 - -// Max grid of tiles that an AI will evaluate a candidate bridge or canal for, -// used to limit computational complexity -#define AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES 10 - -enum { NAMED_TILE_MENU_ID = 0x90 }; - -char const * const hotseat_replay_save_path = "Saves\\Auto\\ai-move-replay-before-interturn.SAV"; -char const * const hotseat_resume_save_path = "Saves\\Auto\\ai-move-replay-resume.SAV"; - -// Need to define memmove for use by TCC when generated code for functions that return a struct -void * -memmove (void * dest, void const * src, size_t size) -{ - return is->memmove (dest, src, size); -} - -// Also need to define memset for some reason -void * -memset (void * dest, int ch, size_t count) -{ - for (size_t n = 0; n < count; n++) - ((char *)dest)[n] = ch; - return dest; -} - -// Computes num/denom randomly rounded off so that E[rand_div (x,y)] = (float)x/y -// As an example: E[rand_div (6, 5)] = 1.2, it will return 1 with 80% probability and 2 with 20% prob. -int -rand_div (int num, int denom) -{ - int q = num / denom, - r = num % denom; - return q + (rand_int (p_rand_object, __, denom) < r); -} - -bool -are_tiles_adjacent (int ax, int ay, int bx, int by) -{ - int x_dist = int_abs (ax - bx), - y_dist = int_abs (ay - by); - - // Handle edge wrapping by counting from the opposite direction if it would be shorter - if (p_bic_data->Map.Flags & 1) { // if map wraps horizontally - int width = p_bic_data->Map.Width; - if (x_dist > (width>>1)) - x_dist = width - x_dist; - } - if (p_bic_data->Map.Flags & 2) { // if map wraps vertically - int height = p_bic_data->Map.Height; - if (y_dist > (height>>1)) - y_dist = height - y_dist; - } - - return (x_dist + y_dist) == 2; -} - -int -compute_wrapped_component (int diff, int size, bool wraps) -{ - if (! wraps || (size <= 0)) - return diff; - - int half = size >> 1; - if (diff > half) - diff = size - diff; - return diff; -} - -void -compute_wrapped_deltas (int ax, int ay, int bx, int by, int * out_dx, int * out_dy) -{ - int dx = int_abs (ax - bx); - int dy = int_abs (ay - by); - bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; - bool wraps_vert = (p_bic_data->Map.Flags & 2) != 0; - dx = compute_wrapped_component (dx, p_bic_data->Map.Width, wraps_horiz); - dy = compute_wrapped_component (dy, p_bic_data->Map.Height, wraps_vert); - if (out_dx != NULL) - *out_dx = dx; - if (out_dy != NULL) - *out_dy = dy; -} - -int -compute_wrapped_manhattan_distance (int ax, int ay, int bx, int by) -{ - int dx, dy; - compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); - return dx + dy; -} - -int -compute_wrapped_chebyshev_distance (int ax, int ay, int bx, int by) -{ - int dx, dy; - compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); - return (dx > dy) ? dx : dy; -} - -bool -tile_has_resource (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - int resource_type = tile->vtable->m39_Get_Resource_Type (tile); - return (resource_type >= 0) && (resource_type < p_bic_data->ResourceTypeCount); -} - -City * -get_city_ptr (int id) -{ - if ((p_cities->Cities != NULL) && - (id >= 0) && (id <= p_cities->LastIndex)) { - City_Body * body = p_cities->Cities[id].City; - if (body != NULL) { - City * city = (City *)((char *)body - offsetof (City, Body)); - if (city != NULL) - return city; - } - } - return NULL; -} - -// Forward declarations for unit counter system (defined after their dependencies) -enum recognizable_parse_result parse_unit_counter_group (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_group); -enum recognizable_parse_result parse_counter_rule (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_rule); - -// Declare various functions needed for districts and hard to untangle and reorder here -void __fastcall patch_City_recompute_yields_and_happiness (City * this); -void __fastcall patch_Map_build_trade_network (Map * this); -bool __fastcall patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value); -bool __fastcall patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y); -bool __fastcall patch_City_has_resource (City * this, int edx, int resource_id); -bool __fastcall patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2); -char __fastcall patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing); -void __fastcall patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7); -bool can_build_district_on_tile (Tile * tile, int district_id, int civ_id); -bool city_can_build_district (City * city, int district_id); -bool leader_can_build_district (Leader * leader, int district_id); -bool wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id); -bool find_civ_trait_id_by_name (struct string_slice const * name, int * out_id); -bool find_civ_culture_id_by_name (struct string_slice const * name, int * out_id); -Tile * find_tile_for_district (City * city, int district_id, int * out_x, int * out_y); -struct district_instance * get_district_instance (Tile * tile); -struct named_tile_entry * get_named_tile_entry (Tile * tile); -bool city_has_required_district (City * city, int district_id); -bool district_is_complete (Tile * tile, int district_id); -bool city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id); -void clear_city_district_request (City * city, int district_id); -void set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y); -bool city_radius_contains_tile (City * city, int tile_x, int tile_y); -void on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y); -bool ai_move_district_worker (Unit * worker, struct district_worker_record * rec); -bool has_active_building (City * city, int improv_id); -bool tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv); -void recompute_distribution_hub_totals (); -void get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y); -void wrap_tile_coords (Map * map, int * x, int * y); -int count_neighborhoods_in_city_radius (City * city); -int count_utilized_neighborhoods_in_city_radius (City * city); -char * copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes); -bool city_has_resource_r (City * city, int resource_id, int max_generated_resource_id); - -struct pause_for_popup { - bool done; // Set to true to exit for loop - bool redundant; // If true, this pause would overlap a previous one and so should not be counted - long long ts_before; -}; - -struct pause_for_popup -pfp_init () -{ - struct pause_for_popup tr; - tr.done = false; - tr.redundant = is->paused_for_popup; - if (! tr.redundant) { - is->paused_for_popup = true; - QueryPerformanceCounter ((LARGE_INTEGER *)&tr.ts_before); - } - return tr; -} - -void -pfp_finish (struct pause_for_popup * pfp) -{ - if ((! pfp->redundant) && (! pfp->done)) { - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - is->time_spent_paused_during_popup += ts_after - pfp->ts_before; - is->paused_for_popup = false; - } - pfp->done = true; -} - -#define WITH_PAUSE_FOR_POPUP for (struct pause_for_popup pfp = pfp_init (); ! pfp.done; pfp_finish (&pfp)) - -int __fastcall -patch_show_popup (void * this, int edx, int param_1, int param_2) -{ - int tr; - WITH_PAUSE_FOR_POPUP { - is->show_popup_was_called = 1; - tr = show_popup (this, __, param_1, param_2); - } - return tr; -} - -void -pop_up_in_game_error (char const * msg) -{ - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); - PopupForm_add_text (popup, __, (char *)msg, false); - patch_show_popup (popup, __, 0, 0); -} - -void -memoize (int val) -{ - if (is->memo_len < is->memo_capacity) - is->memo[is->memo_len++] = val; - else { - int new_capacity = not_below (100, 2 * is->memo_capacity); - int * new_memo = malloc (new_capacity * sizeof is->memo[0]); - if (new_memo != NULL) { - for (int n = 0; n < is->memo_len; n++) - new_memo[n] = is->memo[n]; - free (is->memo); - is->memo = new_memo; - is->memo_capacity = new_capacity; - is->memo[is->memo_len++] = val; - } - } - -} - -void -clear_memo () -{ - is->memo_len = 0; -} - -// The maximum possible cultural neighbor index. We don't bother dealing with indices beyond this b/c it's the last tile in the seventh ring. Also -// equals one less than the tile count up to & inc. the seventh ring b/c of the zeroth tile. -#define MAX_CULTURAL_NI 192 - -// Number of workable tiles including the city center for each workable radius -unsigned char const workable_tile_counts[8] = {1, 9, 21, 37, 61, 89, 137, 193}; - -char const cultural_ni_to_diffs[(MAX_CULTURAL_NI + 1) * 2] = -{ - 0, 0, - -// first ring - 1, -1, 2, 0, 1, 1, 0, 2, -1, 1, -2, 0, -1, -1, - 0, -2, - -// second ring - 1, -3, 2, -2, 3, -1, 3, 1, 2, 2, 1, 3, -1, 3, -2, 2, - -3, 1, -3, -1, -2, -2, -1, -3, - -// third ring - 0, -4, 4, 0, 0, 4, -4, 0, 2, -4, 3, -3, 4, -2, 4, 2, - 3, 3, 2, 4, -2, 4, -3, 3, -4, 2, -4, -2, -3, -3, -2, -4, - -// fourth ring - 1, -5, 5, -1, 5, 1, 1, 5, -1, 5, -5, 1, -5, -1, -1, -5, - 0, -6, 6, 0, 0, 6, -6, 0, 3, -5, 4, -4, 5, -3, 5, 3, - 4, 4, 3, 5, -3, 5, -4, 4, -5, 3, -5, -3, -4, -4, -3, -5, - -// fifth ring - 1, -7, 2, -6, 6, -2, 7, -1, 7, 1, 6, 2, 2, 6, 1, 7, - -1, 7, -2, 6, -6, 2, -7, 1, -7, -1, -6, -2, -2, -6, -1, -7, - 4, -6, 5, -5, 6, -4, 6, 4, 5, 5, 4, 6, -4, 6, -5, 5, - -6, 4, -6, -4, -5, -5, -4, -6, - -// sixth ring - 0, -8, 8, 0, 0, 8, -8, 0, 1, -9, 2, -8, 3, -7, 7, -3, - 8, -2, 9, -1, 9, 1, 8, 2, 7, 3, 3, 7, 2, 8, 1, 9, - -1, 9, -2, 8, -3, 7, -7, 3, -8, 2, -9, 1, -9, -1, -8, -2, - -7, -3, -3, -7, -2, -8, -1, -9, 4, -8, 5, -7, 6, -6, 7, -5, - 8, -4, 8, 4, 7, 5, 6, 6, 5, 7, 4, 8, -4, 8, -5, 7, - -6, 6, -7, 5, -8, 4, -8, -4, -7, -5, -6, -6, -5, -7, -4, -8, - -// seventh ring - 0, -10, 10, 0, 0, 10, -10, 0, 1, -11, 2, -10, 3, -9, 9, -3, - 10, -2, 11, -1, 11, 1, 10, 2, 9, 3, 3, 9, 2, 10, 1, 11, - -1, 11, -2, 10, -3, 9, -9, 3, -10, 2, -11, 1, -11, -1, -10, -2, - -9, -3, -3, -9, -2, -10, -1, -11, 4, -10, 5, -9, 6, -8, 7, -7, - 8, -6, 9, -5, 10, -4, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, - 5, 9, 4, 10, -4, 10, -5, 9, -6, 8, -7, 7, -8, 6, -9, 5, - -10, 4, -10, -4, -9, -5, -8, -6, -7, -7, -6, -8, -5, -9, -4, -10 -}; - -// Like neighbor_index_to_diff, but enumerates tiles in an order that matches cultural border expansion. Only valid for 0 <= neighbor_index <= MAX_CULTURAL_NI. -void __cdecl -patch_ni_to_diff_for_work_area (int neighbor_index, int * x_disp, int * y_disp) -{ - if (neighbor_index <= 0) { - *x_disp = *y_disp = 0; - return; - } else if (neighbor_index > MAX_CULTURAL_NI) - neighbor_index = neighbor_index % (MAX_CULTURAL_NI + 1); - - int i = neighbor_index << 1; - char const * p = &cultural_ni_to_diffs[neighbor_index << 1]; - *x_disp = p[0]; - *y_disp = p[1]; -} - -int __fastcall -patch_City_find_min_value_tile (City * this) -{ - int tr = City_find_min_value_tile (this); - - // The original function has been edited to enumerate tiles in our custom order matching cultural borders instead of the game's original - // order. It returns a neighbor index from that enumeration. We must convert it to standard order if it's beyond the range where the two - // enumerations overlap. - if (tr >= 21) - tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; - - return tr; -} - -int __fastcall -patch_City_find_best_tile_to_work (City * this, int edx, Unit * worker, bool param_2) -{ - int tr = City_find_best_tile_to_work (this, __, worker, param_2); - if (tr >= 21) - tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; - return tr; -} - -bool __fastcall -City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 21) && (neighbor_index <= MAX_CULTURAL_NI)) - neighbor_index = is->cultural_ni_to_standard[neighbor_index]; - return City_stop_working_tile (this, __, neighbor_index); -} - -int __fastcall -patch_Map_compute_ni_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - // Within the first two rings, there's no difference b/w the standard and custom "work area" neighbor indices so fall back to the base game's - // function in that case. - if (is->workable_tile_count <= 21) - return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); - - // If the work area has been expanded, compute the neighbor index then check that it's within the area. Ignore the limit we were passed and - // instead use the number of tiles in the workable area, doubled to cover the difference between cultural vs standard enumeration. - else { - int ni = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, 2 * is->workable_tile_count); - if ((ni >= 0) && (ni <= ARRAY_LEN (is->ni_to_work_radius)) && - (is->ni_to_work_radius[ni] >= 0) && - (is->ni_to_work_radius[ni] <= is->current_config.city_work_radius)) - return ni; - else - return -1; - } -} - -int __fastcall -patch_Map_m28_find_cnter_neigh_point_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - int ret_addr = ((int *)&x_home)[-1]; - if (ret_addr != ADDR_FIND_CENTER_NP_SPOTLIGHT_RET) - return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); - else - return patch_Map_compute_ni_for_work_area (this, __, x_home, y_home, x_neigh, y_neigh, 500); -} - -int -get_work_ring_limit_by_culture (City * city) -{ - if (is->current_config.work_area_limit == WAL_NONE) - return INT_MAX; - else { - int lower_lim = (is->current_config.work_area_limit == WAL_CULTURAL_MIN_2) ? 2 : 1; - return not_below (lower_lim, city->Body.cultural_level); - } -} - -int -get_work_ring_limit_by_improvements (City * city) -{ - if (is->current_config.count_work_area_improvements == 0) - return INT_MAX; - else { - int maxRadius = 0; - int bonusRadius = 0; - for (int n = 0; n < is->current_config.count_work_area_improvements; n++) { - struct work_area_improvement * work_area_improvement = &is->current_config.work_area_improvements[n]; - if (work_area_improvement->work_area_radius_limit > maxRadius && - (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { - maxRadius = work_area_improvement->work_area_radius_limit; - } - if (work_area_improvement->work_area_radius_bonus > 0 && - (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { - bonusRadius += work_area_improvement->work_area_radius_bonus; - } - } - return maxRadius + bonusRadius; - } -} - -int -get_work_ring_limit_total (City * city) -{ - int cultureLimit = get_work_ring_limit_by_culture(city); - int improvementLimit = get_work_ring_limit_by_improvements(city); - if (cultureLimit < improvementLimit) - return cultureLimit; - return improvementLimit; -} - -bool __fastcall -patch_City_controls_tile (City * this, int edx, int neighbor_index, bool consider_enemy_units) -{ - // Check that this tile is not outside the city's work area. We've deleted a check from the base game code that verifies the n.i. is within 21 - // tiles so we can replicate it here in a way that also works for an expanded work area. - int work_radius = ((neighbor_index >= 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) ? is->ni_to_work_radius[neighbor_index] : -1; - if ((work_radius > is->current_config.city_work_radius) || (work_radius < 0)) - return false; - - int work_ring_limit = get_work_ring_limit_total (this); - if (work_radius > work_ring_limit) { - - // May consider this tile within the limit if any adjacent tiles are within the limit & within borders - bool exempt_from_limit; - if (is->current_config.work_area_limit != WAL_CULTURAL_OR_ADJACENT) - exempt_from_limit = false; - else if (neighbor_index >= 9) { - exempt_from_limit = false; - int center_x, center_y; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, ¢er_x, ¢er_y); - int neighbors_checked = 0; - for (int ni = 1; ni < ARRAY_LEN (is->ni_to_work_radius); ni++) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, ni, &nx, &ny); - if (are_tiles_adjacent (center_x, center_y, nx, ny)) { - neighbors_checked++; - int wr = is->ni_to_work_radius[ni]; - Tile * neighbor; - if (((wr >= 0) && (wr <= work_ring_limit)) && - (neighbor = tile_at (nx, ny)) && - (neighbor->vtable->m38_Get_Territory_OwnerID (neighbor) == this->Body.CivID)) { - exempt_from_limit = true; - break; - } - } - if (neighbors_checked == 8) - break; - } - } else - exempt_from_limit = true; - - if (! exempt_from_limit) - return false; - } - - if (neighbor_index >= 0) { - int tile_x, tile_y; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - // Check if the tile itself is a completed district (includes natural wonders) - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id)) - return false; - - // Check if the tile is covered by a distribution hub - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - return false; - } - } - } - } - - return City_controls_tile (this, __, neighbor_index, consider_enemy_units); -} - -bool __fastcall -patch_City_controls_tile_conv_ni (City * this, int edx, int neighbor_index, bool consider_enemy_units) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return patch_City_controls_tile (this, __, is->cultural_ni_to_standard[neighbor_index], consider_enemy_units); - else - return false; -} - -bool __fastcall -patch_City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return City_stop_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); - else - return false; -} - -bool __fastcall -patch_City_start_working_tile_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return City_start_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); - else - return false; -} - -void __fastcall -patch_City_add_or_remove_tile_yield_conv_ni (City * this, int edx, int neighbor_index, bool add_else_remove) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - City_add_or_remove_tile_yield (this, __, is->cultural_ni_to_standard[neighbor_index], add_else_remove); -} - -bool __fastcall -patch_City_is_neighboring_tile_in_area_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return City_is_neighboring_tile_in_area (this, __, is->cultural_ni_to_standard[neighbor_index]); - else - return false; -} - -int -get_city_screen_center_y (City * city) -{ - int y = city->Body.Y; - if (p_bic_data->is_zoomed_out) - return y + 7; // when zoomed out, shift map up to center city - else if (is->current_config.city_work_radius >= 3) - return y + 4; // when work radius is 3, shift map up one extra tile so as not to overlap citizen heads - else - return y + 2; // base game behavior -} - -void __fastcall -patch_Main_Screen_Form_bring_cnter_view_city_focus (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) -{ - // If the city we're viewing can work tiles in the 4+ ring then zoom out the map display to show them - int effective_radius = not_above (get_work_ring_limit_total (p_city_form->CurrentCity), is->current_config.city_work_radius); - if (is->current_config.work_area_limit == WAL_CULTURAL_OR_ADJACENT) - effective_radius = not_above (is->current_config.city_work_radius, effective_radius + 1); - if (effective_radius >= 4 && is->current_config.auto_zoom_city_screen_for_large_work_areas) - p_bic_data->is_zoomed_out = true; - - Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); -} - -void __fastcall -patch_Main_Screen_Form_bring_cnter_view_city_arrow (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) -{ - Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); -} - -void tile_index_to_coords (Map * map, int index, int * out_x, int * out_y); - -Tile * __fastcall -patch_Map_get_tile_for_work_area_drawing (Map * this, int edx, int index) -{ - Tile * tr = Map_get_tile (this, __, index); - - if (tr != p_null_tile) { - int x, y; - tile_index_to_coords (this, index, &x, &y); - City * viewing_city = p_city_form->CurrentCity; - int ni = Map_compute_neighbor_index (this, __, viewing_city->Body.X, viewing_city->Body.Y, x, y, 1000); - if ((ni > 0) && ! patch_City_controls_tile (viewing_city, __, ni, false)) - tr = p_null_tile; - } - - return tr; -} - -// Resets is->current_config to the base config and updates the list of config names. Does NOT re-apply machine code edits. -void -reset_to_base_config () -{ - struct c3x_config * cc = &is->current_config; - - for (int n = 0; n < ARRAY_LEN (cc->limit_units_per_tile); n++) - cc->limit_units_per_tile[n] = 0; - - table_deinit (&cc->exclude_types_from_units_per_tile_limit); - - for (int n = 0; n < COUNT_PERFUME_KINDS; n++) - stable_deinit (&cc->perfume_specs[n]); - - // Free building-unit prereqs table - FOR_TABLE_ENTRIES (tei, &cc->building_unit_prereqs) { - if ((tei.value & 1) == 0) - free ((void *)tei.value); - } - table_deinit (&cc->building_unit_prereqs); - - // Free list of mills - if (cc->mills != NULL) { - free (cc->mills); - cc->mills = NULL; - cc->count_mills = 0; - } - - // Free list of AI multi-city start extra palaces - if (cc->ai_multi_start_extra_palaces != NULL) { - free (cc->ai_multi_start_extra_palaces); - cc->ai_multi_start_extra_palaces = NULL; - cc->count_ai_multi_start_extra_palaces = 0; - cc->ai_multi_start_extra_palaces_capacity = 0; - } - - table_deinit (&cc->limit_defensive_retreat_on_water_to_types); - table_deinit (&cc->can_bombard_only_sea_tiles); - - // Free set of PTW artillery types and list of converted types - table_deinit (&cc->ptw_arty_types); - if (is->charmed_types_converted_to_ptw_arty != NULL) { - free (is->charmed_types_converted_to_ptw_arty); - is->charmed_types_converted_to_ptw_arty = NULL; - is->count_charmed_types_converted_to_ptw_arty = 0; - is->charmed_types_converted_to_ptw_arty_capacity = 0; - } - - // Free era alias lists - if (cc->civ_era_alias_lists != NULL) { - for (int n = 0; n < cc->count_civ_era_alias_lists; n++) { - struct civ_era_alias_list * list = &cc->civ_era_alias_lists[n]; - free (list->key); - for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) - free (list->aliases[k]); - } - free (cc->civ_era_alias_lists); - cc->civ_era_alias_lists = NULL; - cc->count_civ_era_alias_lists = 0; - } - if (cc->leader_era_alias_lists != NULL) { - for (int n = 0; n < cc->count_leader_era_alias_lists; n++) { - struct leader_era_alias_list * list = &cc->leader_era_alias_lists[n]; - free (list->key); - for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) { - free (list->aliases[k]); - free (list->titles[k]); - } - } - free (cc->leader_era_alias_lists); - cc->leader_era_alias_lists = NULL; - cc->count_leader_era_alias_lists = 0; - } - - // Free list of work_area_improvements - if (cc->work_area_improvements != NULL) { - free (cc->work_area_improvements); - cc->work_area_improvements = NULL; - cc->count_work_area_improvements = 0; - } - - // Free aircraft victory animation string - if (cc->aircraft_victory_animation != NULL) { - free (cc->aircraft_victory_animation); - cc->aircraft_victory_animation = NULL; - } - - if (cc->great_wall_auto_build_wonder_name != NULL) { - free (cc->great_wall_auto_build_wonder_name); - cc->great_wall_auto_build_wonder_name = NULL; - } - - // Free unit limits table - FOR_TABLE_ENTRIES (tei, &cc->unit_limits) - free ((void *)tei.value); - stable_deinit (&cc->unit_limits); - - // Free the linked list of loaded config names and the string name contained in each one - if (is->loaded_config_names != NULL) { - struct loaded_config_name * next = is->loaded_config_names; - while (next != NULL) { - struct loaded_config_name * to_free = next; - next = next->next; - free (to_free->name); - free (to_free); - } - } - - // Overwrite the current config with the base config - memcpy (&is->current_config, &is->base_config, sizeof is->current_config); - - // These fields are heap-allocated and must not be inherited from base_config - // (base_config never owns valid pointers for them) - is->current_config.unit_counter_groups = NULL; - is->current_config.count_unit_counter_groups = 0; - is->current_config.counter_rules = NULL; - is->current_config.count_counter_rules = 0; - - // Recreate loaded config names list with just the base config - is->loaded_config_names = malloc (sizeof *is->loaded_config_names); - is->loaded_config_names->name = strdup ("(base)"); - is->loaded_config_names->next = NULL; - - // Update IS variable that's tied to a config value - is->workable_tile_count = workable_tile_counts[is->current_config.city_work_radius]; -} - -struct id_list { - int length; - int capacity; - int ids[0]; -}; - -struct id_list * -alloc_id_list (int capacity, struct id_list const * copy) -{ - struct id_list * tr = malloc ((sizeof *tr) + capacity * sizeof(tr->ids[0])); - tr->length = 0; - tr->capacity = capacity; - if (copy != NULL) { - int new_len = not_above (capacity, copy->length); - for (int n = 0; n < new_len; n++) - tr->ids[n] = copy->ids[n]; - tr->length = new_len; - } - return tr; -} - -// This is the largest ID that will be stored inline inside sidtables. The amount here must be smaller than any pointer we'd get from malloc since the -// sidtable code compares values against this amount to determine which are inlined values versus pointers. -#define SID_TABLE_MAX_INLINE_ID 10000 - -void -sidtable_deinit (struct table * t) -{ - FOR_TABLE_ENTRIES (tei, t) { - free ((void *)tei.key); - if (tei.value > SID_TABLE_MAX_INLINE_ID) - free ((void *)tei.value); - } - table_deinit (t); -} - -void -sidtable_append (struct table * t, struct string_slice const * key, int id) -{ - // Expand or allocate table as needed - if (t->len >= table_capacity (t) / 2) - table__expand (t, hash_str, compare_str_keys); - - size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); - int * entry = &((int *)TABLE__BASE (t))[2*index]; - if (table__is_occupied (t, index)) { // If key is already in the table - int prev_val = entry[1]; - if (prev_val <= SID_TABLE_MAX_INLINE_ID) { // If prev value is an id, convert it to a list - struct id_list * new_list = alloc_id_list (2, NULL); - new_list->ids[0] = prev_val; - new_list->ids[1] = id; - new_list->length = 2; - entry[1] = (int)new_list; - } else { // Else, prev value is a list so append the new ID to it - struct id_list * list = (void *)prev_val; - if (list->length >= list->capacity) { // Expand list if necessary - struct id_list * new_list = alloc_id_list (2 * list->capacity, list); - entry[1] = (int)new_list; - free (list); - list = new_list; - } - list->ids[list->length] = id; - list->length++; - } - } else { // Key is not in the table, add it for the first time - entry[0] = (int)extract_slice (key); - if (id <= SID_TABLE_MAX_INLINE_ID) // Write ID inline if possible - entry[1] = id; - else { // Otherwise create a list for this one ID - struct id_list * new_list = alloc_id_list (2, NULL); - new_list->ids[0] = id; - new_list->length = 1; - entry[1] = (int)new_list; - } - table__set_occupation (t, index, 1); - t->len++; - } -} - -bool -sidtable_get_by_index (struct table const * t, size_t index, int ** out_ids, int * out_count) -{ - size_t capacity = table_capacity (t); - if ((capacity > 0) && (index < capacity) && table__is_occupied (t, index)) { - int * entry = &((int *)TABLE__BASE (t))[2*index]; - int val = entry[1]; - if (val <= SID_TABLE_MAX_INLINE_ID) { // Value is an ID - *out_ids = &entry[1]; - *out_count = 1; - } else { - struct id_list * list = (void *)val; - *out_ids = &list->ids[0]; - *out_count = list->length; - } - return true; - } else - return false; -} - -bool -sidtable_look_up (struct table const * t, char const * key, int ** out_ids, int * out_count) -{ - if (t->len > 0) { - size_t index = table__place (t, compare_str_keys, (int)key, hash_str ((int)key)); - return sidtable_get_by_index (t, index, out_ids, out_count); - } else - return false; -} - -bool -sidtable_look_up_slice (struct table const * t, struct string_slice const * key, int ** out_ids, int * out_count) -{ - if (t->len > 0) { - size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); - return sidtable_get_by_index (t, index, out_ids, out_count); - } else - return false; -} - -struct error_line { - char text[200]; - struct error_line * next; -}; - -struct error_line * -add_error_line (struct error_line ** p_lines) -{ - struct error_line * tr = calloc (1, sizeof *tr); - - struct error_line ** p_prev = p_lines; - while (*p_prev != NULL) - p_prev = &(*p_prev)->next; - *p_prev = tr; - - return tr; -} - -void -add_unrecognized_line (struct error_line ** p_lines, struct string_slice const * name) -{ - struct error_line * line = add_error_line (p_lines); - char s[100]; - snprintf (line->text, sizeof line->text, "^ %.*s", name->len, name->str); - line->text[(sizeof line->text) - 1] = '\0'; -} - -void -free_error_lines (struct error_line * lines) -{ - while (lines != NULL) { - struct error_line * next = lines->next; - free (lines); - lines = next; - } -} - -bool -find_improv_id_by_name (struct string_slice const * name, int * out) -{ - Improvement * improv; - if (name->len <= sizeof improv->Name) - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { - *out = n; - return true; - } - return false; -} - -// start_id specifies where the search will start. It's useful for finding multiple type IDs with the same name, which commonly happens due to the -// game duplicating unit types. -bool -find_unit_type_id_by_name (struct string_slice const * name, int start_id, int * out) -{ - UnitType * unit_type; - if (name->len <= sizeof unit_type->Name) - for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) - if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { - *out = n; - return true; - } - return false; -} - -bool -find_resource_id_by_name (struct string_slice const * name, int * out) -{ - Resource_Type * res_type; - if (name->len <= sizeof res_type->Name) - for (int n = 0; n < p_bic_data->ResourceTypeCount; n++) - if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { - *out = n; - return true; - } - return false; -} - -bool -find_animation_type_by_name (struct string_slice const * name, bool lower_case, AnimationType * out) -{ - for (int n_anim = 0; n_anim < COUNT_ANIMATION_TYPES; n_anim++) - if (strlen (animation_names[n_anim]) == name->len) { - bool all_chars_match = true; - for (int k = 0; k < name->len; k++) { - int c = animation_names[n_anim][k]; - if (lower_case) - c = tolower (c); - if (c != name->str[k]) { - all_chars_match = false; - break; - } - } - if (all_chars_match) { - *out = n_anim; - return true; - } - } - return false; -} - -enum game_object_kind { - GOK_UNIT_TYPE = 0, - GOK_BUILDING, - GOK_RESOURCE, - GOK_TECHNOLOGY, - GOK_GOVERNMENT, - - COUNT_GAME_OBJECT_KINDS -}; - -bool -find_game_object_id_by_name (enum game_object_kind kind, struct string_slice const * name, int start_id, int * out) -{ - switch (kind) { - case GOK_UNIT_TYPE: { - UnitType * unit_type; - if (name->len <= sizeof unit_type->Name) - for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) - if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { - *out = n; - return true; - } - return false; - } - case GOK_BUILDING: { - Improvement * improv; - if (name->len <= sizeof improv->Name) - for (int n = start_id; n < p_bic_data->ImprovementsCount; n++) - if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { - *out = n; - return true; - } - return false; - } - case GOK_RESOURCE: { - Resource_Type * res_type; - if (name->len <= sizeof res_type->Name) - for (int n = start_id; n < p_bic_data->ResourceTypeCount; n++) - if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { - *out = n; - return true; - } - return false; - } - case GOK_TECHNOLOGY: { - Advance * adv; - if (name->len <= sizeof adv->Name) - for (int n = start_id; n < p_bic_data->AdvanceCount; n++) - if (slice_matches_str (name, p_bic_data->Advances[n].Name)) { - *out = n; - return true; - } - return false; - } - case GOK_GOVERNMENT: { - Government * govt; - if (name->len <= sizeof govt->Name) - for (int n = start_id; n < p_bic_data->GovernmentsCount; n++) - if (slice_matches_str (name, p_bic_data->Governments[n].Name.S)) { - *out = n; - return true; - } - return false; - } - default: - return false; - } -} - -// Converts a build name (like "Spearman" or "Granary") into a City_Order struct. Returns whether or not any improvement or unit type was found under -// the given name. -bool -find_city_order_by_name (struct string_slice const * name, City_Order * out) -{ - int id; - if (find_improv_id_by_name (name, &id)) { - out->OrderID = id; - out->OrderType = COT_Improvement; - return true; - } else if (find_unit_type_id_by_name (name, 0, &id)) { - out->OrderID = id; - out->OrderType = COT_Unit; - return true; - } else - return false; -} - -// Returns a list of AI strat duplicates of the unit type with the given id. This means a list of all other unit types that are identical to the given -// one except were separated out so each can have only one AI strategy. Returns the total number of duplicates, which may be greater than dup_ids_len. -int -list_unit_type_duplicates (int type_id, int * out_dup_ids, int dup_ids_len) -{ - // type_id may be a duplicate itself. Find the base type so we can start assembling the array from there. Otherwise we may miss some. - int alt_for_id = p_bic_data->UnitTypes[type_id].alternate_strategy_for_id; - int base_type_id = (alt_for_id >= 0) ? alt_for_id : type_id; - - int tr = 0, current = base_type_id; - while (1) { - if (current != type_id) { - if (tr < dup_ids_len) - out_dup_ids[tr] = current; - tr++; - } - int next; - if (itable_look_up (&is->unit_type_duplicates, current, &next)) - current = next; - else - break; - } - - return tr; -} - -// A "recognizable" is something that contains the name of a unit, building, etc. When parsing one, it's possible for it to be grammatically valid but -// contain a name that doesn't match anything in the scenario data. That's a special kind of error. In that case, we record the error to report in a -// popup and continue parsing. -enum recognizable_parse_result { - RPR_OK = 0, - RPR_UNRECOGNIZED, - RPR_PARSE_ERROR -}; - -struct perfume_spec { - char name[36]; // Must be large enough to fit the name of a unit type or improvement - i31b value; // Int component stores amount, bool stores whether it's a percentage or not -}; - -enum recognizable_parse_result -parse_perfume_spec (char ** p_cursor, enum perfume_kind kind, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - char * cur = *p_cursor; - struct string_slice name; - City_Order unused_city_order; - int unused_id; - i31b value; - if (parse_string (&cur, &name) && - skip_punctuation (&cur, ':') && - parse_i31b (&cur, &value)) { - *p_cursor = cur; - - if (((kind == PK_PRODUCTION) && find_city_order_by_name (&name, &unused_city_order)) || - ((kind == PK_TECHNOLOGY) && find_game_object_id_by_name (GOK_TECHNOLOGY, &name, 0, &unused_id)) || - ((kind == PK_GOVERNMENT) && find_game_object_id_by_name (GOK_GOVERNMENT, &name, 0, &unused_id))) { - struct perfume_spec * out = out_perfume_spec; - snprintf (out->name, sizeof out->name, "%.*s", name.len, name.str); - out->name[(sizeof out->name) - 1] = '\0'; - out->value = value; - return RPR_OK; - } else { - add_unrecognized_line (p_unrecognized_lines, &name); - return RPR_UNRECOGNIZED; - } - } else - return RPR_PARSE_ERROR; -} - -enum recognizable_parse_result -parse_production_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - return parse_perfume_spec (p_cursor, PK_PRODUCTION, p_unrecognized_lines, out_perfume_spec); -} - -enum recognizable_parse_result -parse_technology_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - return parse_perfume_spec (p_cursor, PK_TECHNOLOGY, p_unrecognized_lines, out_perfume_spec); -} - -enum recognizable_parse_result -parse_government_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - return parse_perfume_spec (p_cursor, PK_GOVERNMENT, p_unrecognized_lines, out_perfume_spec); -} - -enum recognizable_parse_result -parse_mill (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_mill) -{ - char * cur = *p_cursor; - struct string_slice improv_name; - if (parse_string (&cur, &improv_name) && - skip_punctuation (&cur, ':')) { - - short flags = 0; - struct string_slice resource_name; - while (1) { - if (! parse_string (&cur, &resource_name)) - return RPR_PARSE_ERROR; - else if (slice_matches_str (&resource_name, "local")) flags |= MF_LOCAL; - else if (slice_matches_str (&resource_name, "no-tech-req")) flags |= MF_NO_TECH_REQ; - else if (slice_matches_str (&resource_name, "yields")) flags |= MF_YIELDS; - else if (slice_matches_str (&resource_name, "show-bonus")) flags |= MF_SHOW_BONUS; - else if (slice_matches_str (&resource_name, "hide-non-bonus")) flags |= MF_HIDE_NON_BONUS; - else - break; - } - - *p_cursor = cur; - int improv_id, resource_id; - int any_unrecognized = 0; - if (! find_improv_id_by_name (&improv_name, &improv_id)) { - add_unrecognized_line (p_unrecognized_lines, &improv_name); - any_unrecognized = 1; - } - if (! find_resource_id_by_name (&resource_name, &resource_id)) { - add_unrecognized_line (p_unrecognized_lines, &resource_name); - any_unrecognized = 1; - } - if (any_unrecognized) - return RPR_UNRECOGNIZED; - else { - struct mill * out = out_mill; - out->improv_id = improv_id; - out->resource_id = resource_id; - out->flags = flags; - return RPR_OK; - } - } else - return RPR_PARSE_ERROR; -} - -enum recognizable_parse_result -parse_era_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_or_civ_alias_list, bool leader_else_civ_name) -{ - char * cur = *p_cursor; - struct string_slice key; - if (parse_string (&cur, &key) && - skip_punctuation (&cur, ':')) { - - char * aliases[ERA_ALIAS_LIST_CAPACITY] = {0}; - char * titles[ERA_ALIAS_LIST_CAPACITY] = {0}; - int alias_count = 0, - female_bits = 0, - gender_specified_bits = 0; // For each alias, set to 1 if a gender was specified - struct string_slice alias; - while (1) { - if (parse_string (&cur, &alias)) { - if (alias_count < ERA_ALIAS_LIST_CAPACITY) - aliases[alias_count] = extract_slice (&alias); - - // If we're parsing a list of leader names, read in the gender & title if present - if (leader_else_civ_name) { - char * inner_cur = cur; - struct string_slice gender; - struct string_slice title = {0}; - if ( skip_punctuation (&inner_cur, '(') - && parse_string (&inner_cur, &gender) - && ( skip_punctuation (&inner_cur, ')') - || ( skip_punctuation (&inner_cur, ',') - && parse_string (&inner_cur, &title) - && skip_punctuation (&inner_cur, ')'))) - && ( slice_matches_str (&gender, "M") - || slice_matches_str (&gender, "m") - || slice_matches_str (&gender, "F") - || slice_matches_str (&gender, "f"))) { - if (alias_count < 32) { - if (slice_matches_str (&gender, "F") || slice_matches_str (&gender, "f")) - female_bits |= 1 << alias_count; - gender_specified_bits |= 1 << alias_count; - } - if (title.len > 0) - titles[alias_count] = extract_slice (&title); - cur = inner_cur; - } - } - - alias_count++; - } else - break; - } - if (alias_count == 0) - return RPR_PARSE_ERROR; - - *p_cursor = cur; - - // Check that "key" matches a noun, adjective, or formal name of any civ ("race") in the scenario data. Store that civ. - Race * race_matching_key = NULL; { - for (int n = 0; n < p_bic_data->RacesCount; n++) { - Race * race = &p_bic_data->Races[n]; - if ( ( leader_else_civ_name - && slice_matches_str (&key, race->LeaderName)) - || ( (! leader_else_civ_name) - && ( slice_matches_str (&key, race->AdjectiveName) - || slice_matches_str (&key, race->CountryName) - || slice_matches_str (&key, race->SingularName)))) { - race_matching_key = race; - break; - } - } - } - if (race_matching_key == NULL) { - add_unrecognized_line (p_unrecognized_lines, &key); - return RPR_UNRECOGNIZED; - } - - if (leader_else_civ_name) { - struct leader_era_alias_list * out = out_leader_or_civ_alias_list; - memset (out, 0, sizeof *out); // Make sure unspecified aliases & titles are NULL - out->key = extract_slice (&key); - for (int n = 0; n < alias_count; n++) { - out->aliases[n] = aliases[n]; - out->titles[n] = titles[n]; - } - - // Set gender bits - int unreplaced_bits = (race_matching_key->LeaderGender == 0) ? 0 : ~0; - out->gender_bits = (unreplaced_bits & ~gender_specified_bits) | female_bits; - - - } else { - struct civ_era_alias_list * out = out_leader_or_civ_alias_list; - memset (out, 0, sizeof *out); - out->key = extract_slice (&key); - for (int n = 0; n < alias_count; n++) - out->aliases[n] = aliases[n]; - } - - return RPR_OK; - } else - return RPR_PARSE_ERROR; -} - - -enum recognizable_parse_result -parse_civ_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_civ_era_alias_list) -{ - return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_civ_era_alias_list, false); -} - -enum recognizable_parse_result -parse_leader_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_era_alias_list) -{ - return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_leader_era_alias_list, true); -} - -struct parsed_unit_type_limit { - char name[32]; // Same length as Name in Unit_Type - struct unit_type_limit limit; -}; - -enum recognizable_parse_result -parse_unit_type_limit (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_unit_type_limit) -{ - char * cur = *p_cursor; - struct parsed_unit_type_limit * out = out_parsed_unit_type_limit; - - struct string_slice name; - struct unit_type_limit limit = {0}; - if (skip_white_space (&cur) && - parse_string (&cur, &name) && - (name.len < (sizeof out->name)) && - skip_punctuation (&cur, ':')) { - - do { - int num; - if (! parse_int (&cur, &num)) - return RPR_PARSE_ERROR; - - struct string_slice ss; - if (parse_string (&cur, &ss)) { - if (slice_matches_str (&ss, "per-city")) - limit.per_city += num; - else if (slice_matches_str (&ss, "cities-per")) - limit.cities_per += num; - else - return RPR_PARSE_ERROR; - } else - limit.per_civ += num; - - } 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 { - add_unrecognized_line (p_unrecognized_lines, &name); - *p_cursor = cur; - return RPR_UNRECOGNIZED; - } - - } else - return RPR_PARSE_ERROR; -} - -enum recognizable_parse_result -parse_work_area_improvement (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_work_area_improvement) -{ - char * cur = *p_cursor; - struct work_area_improvement * out = out_parsed_work_area_improvement; - out->improv_id = -1; - out->work_area_radius_limit = 0; - out->work_area_radius_bonus = 0; - - struct string_slice improv_name; - if (skip_white_space (&cur) && - parse_string (&cur, &improv_name) && - skip_punctuation (&cur, ':')) { - - int num; - if (! parse_int (&cur, &num)) - return RPR_PARSE_ERROR; - - struct string_slice ss; - if (parse_string (&cur, &ss)) { - if (slice_matches_str (&ss, "extra")) - out->work_area_radius_bonus = num; - else - return RPR_PARSE_ERROR; - } else - out->work_area_radius_limit = num; - - int improv_id; - if (slice_matches_str (&improv_name, "default")) { - out->improv_id = -1; - *p_cursor = cur; - return RPR_OK; - } else if (find_improv_id_by_name (&improv_name, &improv_id)) { - out->improv_id = improv_id; - *p_cursor = cur; - return RPR_OK; - } else { - add_unrecognized_line (p_unrecognized_lines, &improv_name); - *p_cursor = cur; - return RPR_UNRECOGNIZED; - } - - } else - return RPR_PARSE_ERROR; -} - -// Recognizable items are appended to out_list/count, which must have been previously initialized (NULL/0 is valid for an empty list). -// If an error occurs while reading, returns the location of the error inside the slice, specifically the number of characters before the unreadable -// item. If no error occurs, returns -1. -int -read_recognizables (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - int item_size, - enum recognizable_parse_result (* parse_item) (char **, struct error_line **, void *), - void ** inout_list, - int * inout_count) -{ - if (s->len <= 0) - return -1; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - - bool success = false; - void * new_items = NULL; - int count_new_items = 0; - int new_items_capacity = 0; - void * temp_item = malloc (item_size); - - while (1) { - enum recognizable_parse_result result = parse_item (&cursor, p_unrecognized_lines, temp_item); - if (result != RPR_PARSE_ERROR) { - if (result == RPR_OK) { - reserve (item_size, &new_items, &new_items_capacity, count_new_items); - memcpy ((byte *)new_items + count_new_items * item_size, temp_item, item_size); - count_new_items++; - } - - if (skip_punctuation (&cursor, ',') && skip_white_space (&cursor)) - continue; - else if (skip_horiz_space (&cursor) && (*cursor == '\0')) { - success = true; - break; - } else - break; - } else - break; - } - - if (success && (count_new_items > 0)) { - *inout_list = realloc (*inout_list, (*inout_count + count_new_items) * item_size); - memcpy ((byte *)*inout_list + *inout_count * item_size, new_items, count_new_items * item_size); - *inout_count += count_new_items; - } - free (temp_item); - free (new_items); - free (extracted_slice); - return success ? -1 : cursor - extracted_slice; -} - -// Reads a "sidtable" from text. A sidtable maps strings to IDs of scenario objects. The string keys are also expected to be a type of scenario -// object. This method reads text such as: -// Factory: Battleship, Stable: Horseman Knight Cavalry, "Siege Workshop": Catapult Trebuchet -// and converts it to a table mapping "Factory", "Stable", and "Siege Workshop" to the corresponding unit type IDs. All new entries are appended to -// the given table; existing entries are not removed. -// Like read_recognizables, this method returns -1 for success or the location of an error if there is one. -int -read_sidtable (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - enum game_object_kind key_kind, - enum game_object_kind list_elem_kind, - struct table * sidtable) -{ - if (s->len <= 0) - return -1; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - while (1) { - struct string_slice key; - if (skip_white_space (&cursor) && parse_string (&cursor, &key)) { - int unused; - bool recognized_key = find_game_object_id_by_name (key_kind, &key, 0, &unused); - if (! recognized_key) - add_unrecognized_line (p_unrecognized_lines, &key); - if (! skip_punctuation (&cursor, ':')) - break; - struct string_slice elem_name; - while (skip_white_space (&cursor) && parse_string (&cursor, &elem_name)) { - bool recognized_elem = false; - int elem_id = -1; - while (find_game_object_id_by_name (list_elem_kind, &elem_name, elem_id + 1, &elem_id)) { - recognized_elem = true; - if (recognized_key) - sidtable_append (sidtable, &key, elem_id); - } - if (! recognized_elem) - add_unrecognized_line (p_unrecognized_lines, &elem_name); - } - skip_punctuation (&cursor, ','); - } else { - success = (*cursor == '\0'); - break; - } - } - - free (extracted_slice); - return success ? -1 : cursor - extracted_slice; -} - -// Like read_recognizables, returns -1 for success or the location of an error if there is one -int -read_building_unit_prereqs (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - struct table * building_unit_prereqs) -{ - if (s->len <= 0) - return -1; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - struct prereq { - int building_id; - struct string_slice unit_type_name; - } * new_prereqs = NULL; - int new_prereqs_capacity = 0; - int count_new_prereqs = 0; - - while (1) { - struct string_slice building_name; - if (skip_white_space (&cursor) && parse_string (&cursor, &building_name)) { - int building_id; - bool have_building_id = find_improv_id_by_name (&building_name, &building_id); - if (! have_building_id) - add_unrecognized_line (p_unrecognized_lines, &building_name); - if (! skip_punctuation (&cursor, ':')) - break; - struct string_slice unit_type_name; - while (skip_white_space (&cursor) && parse_string (&cursor, &unit_type_name)) { - int unused; - if (find_unit_type_id_by_name (&unit_type_name, 0, &unused)) { // if there is any by this name, later we'll deal with the possibility of multiple - if (have_building_id) { - reserve (sizeof new_prereqs[0], (void **)&new_prereqs, &new_prereqs_capacity, count_new_prereqs); - new_prereqs[count_new_prereqs++] = (struct prereq) { .building_id = building_id, .unit_type_name = unit_type_name }; - } - } else - add_unrecognized_line (p_unrecognized_lines, &unit_type_name); - } - skip_punctuation (&cursor, ','); - } else { - success = (*cursor == '\0'); - break; - } - } - - // If parsing succeeded, add the new prereq rules to the table - if (success) - for (int n = 0; n < count_new_prereqs; n++) { - struct prereq * prereq = &new_prereqs[n]; - - int unit_type_id = -1; - while (find_unit_type_id_by_name (&prereq->unit_type_name, unit_type_id + 1, &unit_type_id)) { - - // If this unit type ID is not already in the table, insert it paired with the encoded building ID - int prev_val; - if (! itable_look_up (building_unit_prereqs, unit_type_id, &prev_val)) - itable_insert (building_unit_prereqs, unit_type_id, (prereq->building_id << 1) | 1); - - // If the unit type ID is already associated with a building ID, create a list for both the old and new building IDs - else if (prev_val & 1) { - int * list = malloc (MAX_BUILDING_PREREQS_FOR_UNIT * sizeof *list); - for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) - list[n] = -1; - list[0] = prev_val >> 1; // Decode - list[1] = prereq->building_id; - itable_insert (building_unit_prereqs, unit_type_id, (int)list); - - // Otherwise, it's already associated with a list. Search the list for a free spot and fill it with the new building ID - } else { - int * list = (int *)prev_val; - for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) - if (list[n] < 0) { - list[n] = prereq->building_id; - break; - } - } - } - } - - - free (new_prereqs); - free (extracted_slice); - return success ? -1 : cursor - extracted_slice; -} - -// Reads a space-separated list of unit types like: -// Worker Galley "Gallic Swordsman" -// Looks up the type ID(s) for each name and inserts them into the unit_types table associated with a value of 1. -bool -read_unit_type_list (struct string_slice const * s, struct error_line ** p_unrecognized_lines, struct table * unit_types) -{ - if (s->len <= 0) - return true; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - while (1) { - struct string_slice name; - if (parse_string (&cursor, &name)) { - - int id = -1; - bool matched_any = false; - while (find_unit_type_id_by_name (&name, id + 1, &id)) { - itable_insert (unit_types, id, 1); - matched_any = true; - } - - if (! matched_any) - add_unrecognized_line (p_unrecognized_lines, &name); - - } else { - skip_white_space (&cursor); - success = *cursor == '\0'; - break; - } - } - - free (extracted_slice); - return success; -} - -bool -read_ai_multi_start_extra_palaces (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - int ** p_ai_multi_start_extra_palaces, - int * p_count_ai_multi_start_extra_palaces, - int * p_ai_multi_start_extra_palaces_capacity) -{ - if (s->len <= 0) - return true; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - while (1) { - struct string_slice name; - if (parse_string (&cursor, &name)) { - int id; - if (find_improv_id_by_name (&name, &id)) { - int count = *p_count_ai_multi_start_extra_palaces; - reserve (sizeof **p_ai_multi_start_extra_palaces, (void **)p_ai_multi_start_extra_palaces, p_ai_multi_start_extra_palaces_capacity, count); - (*p_ai_multi_start_extra_palaces)[count] = id; - *p_count_ai_multi_start_extra_palaces = count + 1; - } else - add_unrecognized_line (p_unrecognized_lines, &name); - - } else { - skip_white_space (&cursor); - success = *cursor == '\0'; - break; - } - } - - free (extracted_slice); - return success; -} - -bool -read_retreat_rules (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "standard" )) { *out_val = RR_STANDARD; return true; } - else if (slice_matches_str (&trimmed, "none" )) { *out_val = RR_NONE; return true; } - else if (slice_matches_str (&trimmed, "all-units" )) { *out_val = RR_ALL_UNITS; return true; } - else if (slice_matches_str (&trimmed, "if-faster" )) { *out_val = RR_IF_FASTER; return true; } - else if (slice_matches_str (&trimmed, "if-not-slower" )) { *out_val = RR_IF_NOT_SLOWER; return true; } - else if (slice_matches_str (&trimmed, "if-fast-and-not-slower")) { *out_val = RR_IF_FAST_AND_NOT_SLOWER; return true; } - else - return false; -} - -bool -read_line_drawing_override (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "never" )) { *out_val = LDO_NEVER; return true; } - else if (slice_matches_str (&trimmed, "wine" )) { *out_val = LDO_WINE; return true; } - else if (slice_matches_str (&trimmed, "always")) { *out_val = LDO_ALWAYS; return true; } - else - return false; -} - -bool -read_minimap_doubling_mode (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "never" )) { *out_val = MDM_NEVER; return true; } - else if (slice_matches_str (&trimmed, "high-def")) { *out_val = MDM_HIGH_DEF; return true; } - else if (slice_matches_str (&trimmed, "always" )) { *out_val = MDM_ALWAYS; return true; } - else - return false; -} - -bool -read_unit_cycle_search_criteria (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "standard" )) { *out_val = UCSC_STANDARD; return true; } - else if (slice_matches_str (&trimmed, "similar-near-start" )) { *out_val = UCSC_SIMILAR_NEAR_START; return true; } - else if (slice_matches_str (&trimmed, "similar-near-destination")) { *out_val = UCSC_SIMILAR_NEAR_DESTINATION; return true; } - else - return false; -} - -bool -read_no_ai_patrol_override (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "zero")) { *out_val = NAPO_ZERO; return true; } - else if (slice_matches_str (&trimmed, "one" )) { *out_val = NAPO_ONE; return true; } - else if (slice_matches_str (&trimmed, "none")) { *out_val = NAPO_NONE; return true; } - else - return false; -} - -bool -read_work_area_limit (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "none" )) { *out_val = WAL_NONE; return true; } - else if (slice_matches_str (&trimmed, "cultural" )) { *out_val = WAL_CULTURAL; return true; } - else if (slice_matches_str (&trimmed, "cultural-min-2" )) { *out_val = WAL_CULTURAL_MIN_2; return true; } - else if (slice_matches_str (&trimmed, "cultural-or-adjacent")) { *out_val = WAL_CULTURAL_OR_ADJACENT; return true; } - else - return false; -} - -bool -read_day_night_cycle_mode (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "off" )) { *out_val = DNCM_OFF; return true; } - else if (slice_matches_str (&trimmed, "timer" )) { *out_val = DNCM_TIMER; return true; } - else if (slice_matches_str (&trimmed, "user-time" )) { *out_val = DNCM_USER_TIME; return true; } - else if (slice_matches_str (&trimmed, "every-turn")) { *out_val = DNCM_EVERY_TURN; return true; } - else if (slice_matches_str (&trimmed, "specified" )) { *out_val = DNCM_SPECIFIED; return true; } - else - return false; -} - -bool -read_distribution_hub_yield_division_mode (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "flat" )) { *out_val = DHYDM_FLAT; return true; } - else if (slice_matches_str (&trimmed, "scale-by-city-count" )) { *out_val = DHYDM_SCALE_BY_CITY_COUNT; return true; } - else - return false; -} - -bool -read_ai_distribution_hub_build_strategy (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "auto" )) { *out_val = ADHBS_AUTO; return true; } - else if (slice_matches_str (&trimmed, "by-city-count" )) { *out_val = ADHBS_BY_CITY_COUNT; return true; } - else - return false; -} - -bool -read_ai_auto_build_great_wall_strategy (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "all-borders" )) { *out_val = AAGWS_ALL_BORDERS; return true; } - else if (slice_matches_str (&trimmed, "other-civ-bordered-only")) { *out_val = AAGWS_OTHER_CIV_BORDERED_ONLY; return true; } - else - return false; -} - -bool -read_tile_terrain_type_value (struct string_slice const * s, enum SquareTypes * out_type) -{ - if (s == NULL || out_type == NULL) - return false; - - struct string_slice trimmed = trim_string_slice (s, 1); - if (trimmed.len <= 0) - return false; - - struct { - char const * name; - int value; - } const entries[] = { - {"desert", SQ_Desert}, - {"deserts", SQ_Desert}, - {"plain", SQ_Plains}, - {"plains", SQ_Plains}, - {"grassland", SQ_Grassland}, - {"grasslands", SQ_Grassland}, - {"tundra", SQ_Tundra}, - {"tundras", SQ_Tundra}, - {"floodplain", SQ_FloodPlain}, - {"floodplains", SQ_FloodPlain}, - {"hill", SQ_Hills}, - {"hills", SQ_Hills}, - {"mountain", SQ_Mountains}, - {"mountains", SQ_Mountains}, - {"forest", SQ_Forest}, - {"forests", SQ_Forest}, - {"jungle", SQ_Jungle}, - {"jungles", SQ_Jungle}, - {"marsh", SQ_Swamp}, - {"marshes", SQ_Swamp}, - {"swamp", SQ_Swamp}, - {"swamps", SQ_Swamp}, - {"volcano", SQ_Volcano}, - {"volcanos", SQ_Volcano}, - {"coast", SQ_Coast}, - {"coasts", SQ_Coast}, - {"sea", SQ_Sea}, - {"seas", SQ_Sea}, - {"ocean", SQ_Ocean}, - {"oceans", SQ_Ocean}, - {"river", SQ_RIVER}, - {"rivers", SQ_RIVER}, - {"snow-volcano", SQ_SNOW_VOLCANO}, - {"snow-volcanos", SQ_SNOW_VOLCANO}, - {"snow-forest", SQ_SNOW_FOREST}, - {"snow-forests", SQ_SNOW_FOREST}, - {"snow-mountain", SQ_SNOW_MOUNTAIN}, - {"snow-mountains", SQ_SNOW_MOUNTAIN}, - {"any", SQ_INVALID} - }; - - for (int i = 0; i < (int)ARRAY_LEN (entries); i++) { - if (slice_matches_str (&trimmed, entries[i].name)) { - *out_type = (enum SquareTypes)entries[i].value; - return true; - } - } - - return false; -} - -unsigned int -square_type_mask_bit (enum SquareTypes type) -{ - if ((int)type < 0 || type > SQ_SNOW_MOUNTAIN) - return 0; - return (unsigned int)(1u << type); -} - -unsigned int -district_buildable_mine_mask_bit (void) -{ - return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 1)); -} - -unsigned int -district_buildable_irrigation_mask_bit (void) -{ - return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 2)); -} - -unsigned int -district_buildable_lake_mask_bit (void) -{ - return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 3)); -} - -unsigned int -all_square_types_mask (void) -{ - return (unsigned int)((1u << (SQ_SNOW_MOUNTAIN + 1)) - 1); -} - -unsigned int -district_default_buildable_mask (void) -{ - return (unsigned int)DEFAULT_DISTRICT_BUILDABLE_MASK; -} - -bool -tile_has_snow_mountain (Tile * tile) -{ - return (tile != NULL) && (tile != p_null_tile) && tile->vtable->m29_Check_Mountain_Snowcap (tile); -} - -bool -tile_is_lake (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (! tile->vtable->m35_Check_Is_Water (tile)) - return false; - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - return false; - - int lake_size_threshold = 21; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - return continent->Body.TileCount <= lake_size_threshold; -} - -bool -tile_has_snow_volcano (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Volcano) - return false; - - int overlays = tile->vtable->m43_Get_field_30 (tile); - return (overlays & 0x100000) != 0; -} - -bool -tile_has_snow_forest (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Forest) - return false; - - int overlays = tile->vtable->m43_Get_field_30 (tile); - return (overlays & 0x100000) != 0; -} - -bool -tile_matches_square_type (Tile * tile, enum SquareTypes type) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - switch (type) { - case SQ_SNOW_MOUNTAIN: - return tile_has_snow_mountain (tile); - case SQ_SNOW_VOLCANO: - return tile_has_snow_volcano (tile); - case SQ_SNOW_FOREST: - return tile_has_snow_forest (tile); - case SQ_RIVER: - return tile->vtable->m37_Get_River_Code (tile) != 0; - default: - return tile->vtable->m50_Get_Square_BaseType (tile) == type; - } -} - -bool -tile_matches_square_type_mask (Tile * tile, unsigned int mask) -{ - if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) - return false; - - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - unsigned int base_bit = square_type_mask_bit (base_type); - if ((base_bit != 0) && ((mask & base_bit) != 0)) - return true; - - enum SquareTypes const special_types[] = {SQ_RIVER, SQ_SNOW_MOUNTAIN, SQ_SNOW_VOLCANO, SQ_SNOW_FOREST}; - for (int i = 0; i < (int)ARRAY_LEN (special_types); i++) { - enum SquareTypes stype = special_types[i]; - unsigned int bit = square_type_mask_bit (stype); - if ((mask & bit) && tile_matches_square_type (tile, stype)) - return true; - } - - unsigned int mine_bit = district_buildable_mine_mask_bit (); - if ((mask & mine_bit) && tile->vtable->m18_Check_Mines (tile, __, 0)) - return true; - - unsigned int irrigation_bit = district_buildable_irrigation_mask_bit (); - if ((mask & irrigation_bit) && tile->vtable->m17_Check_Irrigation (tile, __, 0)) - return true; - - unsigned int lake_bit = district_buildable_lake_mask_bit (); - if ((mask & lake_bit) && tile_is_lake (tile)) - return true; - - return false; -} - -bool -tile_matches_overlay_mask (Tile * tile, unsigned int mask) -{ - if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) - return false; - - unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); - if ((mask & DOM_MINE) && ((overlays & TILE_FLAG_MINE) != 0)) - return true; - if ((mask & DOM_IRRIGATION) && ((overlays & 0x00000008) != 0)) - return true; - if ((mask & DOM_FORTRESS) && ((overlays & 0x00000010) != 0)) - return true; - if ((mask & DOM_BARRICADE) && ((overlays & 0x10000000) != 0)) - return true; - if ((mask & DOM_OUTPOST) && ((overlays & 0x80000000) != 0)) - return true; - if ((mask & DOM_RADAR_TOWER) && ((overlays & 0x40000000) != 0)) - return true; - if ((mask & DOM_AIRFIELD) && ((overlays & 0x20000000) != 0)) - return true; - if ((mask & DOM_JUNGLE) && tile_matches_square_type (tile, SQ_Jungle)) - return true; - if ((mask & DOM_FOREST) && tile_matches_square_type (tile, SQ_Forest)) - return true; - if ((mask & DOM_SWAMP) && tile_matches_square_type (tile, SQ_Swamp)) - return true; - if ((mask & DOM_RIVER) && tile_matches_square_type (tile, SQ_RIVER)) - return true; - - return false; -} - -bool -read_natural_wonder_terrain_type (struct string_slice const * s, enum SquareTypes * out_type) -{ - enum SquareTypes parsed; - if (! read_tile_terrain_type_value (s, &parsed)) - return false; - - switch (parsed) { - case SQ_Desert: - case SQ_Plains: - case SQ_Grassland: - case SQ_Jungle: - case SQ_Tundra: - case SQ_FloodPlain: - case SQ_Swamp: - case SQ_Hills: - case SQ_Mountains: - case SQ_Forest: - case SQ_Volcano: - case SQ_SNOW_MOUNTAIN: - case SQ_SNOW_FOREST: - case SQ_SNOW_VOLCANO: - case SQ_Coast: - case SQ_Sea: - case SQ_Ocean: - *out_type = parsed; - return true; - - default: - return false; - } -} - -bool -read_direction_value (struct string_slice const * s, enum direction * out_dir) -{ - if (s == NULL || out_dir == NULL) - return false; - - struct string_slice trimmed = trim_string_slice (s, 1); - if (trimmed.len <= 0) - return false; - - if (slice_matches_str (&trimmed, "northeast")) { *out_dir = DIR_NE; return true; } - else if (slice_matches_str (&trimmed, "east" )) { *out_dir = DIR_E; return true; } - else if (slice_matches_str (&trimmed, "southeast")) { *out_dir = DIR_SE; return true; } - else if (slice_matches_str (&trimmed, "south" )) { *out_dir = DIR_S; return true; } - else if (slice_matches_str (&trimmed, "southwest")) { *out_dir = DIR_SW; return true; } - else if (slice_matches_str (&trimmed, "west" )) { *out_dir = DIR_W; return true; } - else if (slice_matches_str (&trimmed, "northwest")) { *out_dir = DIR_NW; return true; } - else if (slice_matches_str (&trimmed, "north" )) { *out_dir = DIR_N; return true; } - else - return false; -} - -bool -read_barbarian_activity_override (struct string_slice const * s, enum barbarian_activity_override * out) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (trimmed.len <= 0) - return false; - - bool found = false; - char * extracted = extract_slice (s); - - struct { - char * str; - enum barbarian_activity_override value; - } possibilities[] = {{ .str = "none" , .value = BAO_NONE }, - { .str = (*p_labels)[LBL_NO_BARBARIANS ], .value = BAO_NO_BARBARIANS }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 1], .value = BAO_SEDENTARY }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 2], .value = BAO_ROAMING }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 3], .value = BAO_RESTLESS }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 4], .value = BAO_RAGING }, - { .str = (*p_labels)[LBL_RANDOM_BARBS] , .value = BAO_RANDOM }, - { .str = "No Barbarians" , .value = BAO_NO_BARBARIANS }, - { .str = "Sedentary" , .value = BAO_SEDENTARY }, - { .str = "Roaming" , .value = BAO_ROAMING }, - { .str = "Restless" , .value = BAO_RESTLESS }, - { .str = "Raging" , .value = BAO_RAGING }, - { .str = "Random" , .value = BAO_RANDOM }}; - - // Check for exact match - for (int n = 0; n < ARRAY_LEN (possibilities); n++) - if (0 == strcmp (extracted, possibilities[n].str)) { - *out = possibilities[n].value; - found = true; - break; - } - - // If not found, check again ignoring case - if (! found) - for (int n = 0; n < ARRAY_LEN (possibilities); n++) - if (0 == _stricmp (extracted, possibilities[n].str)) { - *out = possibilities[n].value; - found = true; - break; - } - - free (extracted); - return found; -} - -struct parsable_field_bit { - char * name; - int bit_value; -}; - -bool -read_bit_field (struct string_slice const * s, struct parsable_field_bit const * bits, int count_bits, int * out_field) -{ - struct string_slice trimmed = trim_string_slice (s, 0); - s = &trimmed; - - int tr; - if (s->len <= 0) - tr = 0; - else if (slice_matches_str (s, "all")) - tr = ~0; - else { - tr = 0; - char * cursor = &s->str[0]; - char * s_end = &s->str[s->len]; - while (1) { - struct string_slice name; - - if (cursor >= s_end) - break; - else if (! parse_string (&cursor, &name)) { - skip_white_space (&cursor); - if (cursor >= s_end) - break; - else - return false; // Invalid character in value - } - - bool matched_any = false; - for (int n = 0; n < count_bits; n++) - if (slice_matches_str (&name, bits[n].name)) { - tr |= bits[n].bit_value; - matched_any = true; - break; - } - if (! matched_any) - return false; - } - } - *out_field = tr; - return true; -} - -int -read_units_per_tile_limit (struct string_slice const * s, int * out_limits) -{ - int single_val; - if (read_int (s, &single_val)) { - out_limits[0] = out_limits[1] = out_limits[2] = single_val; - return true; - - } else { - bool success = false; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - int vals[3]; - if (parse_int (&cursor, &vals[0]) && parse_int (&cursor, &vals[1]) && parse_int (&cursor, &vals[2]) && - skip_horiz_space (&cursor) && (*cursor == '\0')) { - for (int n = 0; n < ARRAY_LEN (vals); n++) - out_limits[n] = vals[n]; - success = true; - } - free (extracted_slice); - return success; - } -} - -struct config_parsing { - char * file_path; - char * text; - char * cursor; - struct string_slice key; - int displayed_error_message; -}; - -enum config_parse_error { - CPE_GENERIC, - CPE_BAD_VALUE, - CPE_BAD_BOOL_VALUE, - CPE_BAD_INT_VALUE, - CPE_BAD_STACK_LIMIT_VALUE, - CPE_BAD_KEY -}; - -void -handle_config_error_at (struct config_parsing * p, char * error_loc, enum config_parse_error err) -{ - char err_msg[1000]; - if (! p->displayed_error_message) { - int line_no = 1; - for (char * c = p->text; c < error_loc; c++) - line_no += *c == '\n'; - - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); - snprintf (err_msg, sizeof err_msg, "Error reading \"%s\" on line %d.", p->file_path, line_no); - err_msg[(sizeof err_msg) - 1] = '\0'; - PopupForm_add_text (popup, __, err_msg, false); - - if (err == CPE_GENERIC) { - if (p->key.str != NULL) - snprintf (err_msg, sizeof err_msg, "^The last key successfully read was \"%.*s\".", p->key.len, p->key.str); - else - snprintf (err_msg, sizeof err_msg, "^Error occurred before any keys could be read."); - } else if (err == CPE_BAD_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid.", p->key.len, p->key.str); - else if (err == CPE_BAD_BOOL_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"true\" or \"false\".", p->key.len, p->key.str); - else if (err == CPE_BAD_INT_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected an integer.", p->key.len, p->key.str); - else if (err == CPE_BAD_STACK_LIMIT_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"false\", an integer, or a list of exactly three of those.", p->key.len, p->key.str); - else if (err == CPE_BAD_KEY) - snprintf (err_msg, sizeof err_msg, "^The key name \"%.*s\" is not recognized.", p->key.len, p->key.str); - err_msg[(sizeof err_msg) - 1] = '\0'; - PopupForm_add_text (popup, __, err_msg, false); - - patch_show_popup (popup, __, 0, 0); - p->displayed_error_message = 1; - } -} - -void -handle_config_error (struct config_parsing * p, enum config_parse_error err) -{ - handle_config_error_at (p, p->cursor, err); -} - -// Loads a config from the given file, layering it on top of is->current_config and appending its name to the list of loaded configs. Does NOT -// re-apply machine code edits. -void -load_config (char const * file_path, int path_is_relative_to_mod_dir) -{ - char err_msg[1000]; - struct c3x_config * cfg = &is->current_config; - - int full_path_size = 2 * MAX_PATH; - char * full_path = malloc (full_path_size); - if (path_is_relative_to_mod_dir) - snprintf (full_path, full_path_size, "%s\\%s", is->mod_rel_dir, file_path); - else - strncpy (full_path, file_path, full_path_size); - full_path[full_path_size - 1] = '\0'; - - char * text; { - char * utf8_text = file_to_string (full_path); - if (utf8_text == NULL) { - free (full_path); - return; - } - text = convert_from_utf8 (utf8_text, *p_code_page); - free (utf8_text); - if (text == NULL) { - snprintf (err_msg, sizeof err_msg, "Failed to re-encode contents of \"%s\". This file must contain UTF-8 text and only characters usable by Civ 3.", full_path); - err_msg[(sizeof err_msg) - 1] = '\0'; - pop_up_in_game_error (err_msg); - free (full_path); - return; - } - } - - struct perfume_spec_list { - struct perfume_spec * items; - int count; - } perfume_spec_lists[COUNT_PERFUME_KINDS] = {0}; - - struct parsed_unit_type_limit * parsed_unit_type_limits = NULL; - int parsed_unit_type_limit_count = 0; - - struct config_parsing p = { .file_path = full_path, .text = text, .cursor = text, .key = {0}, .displayed_error_message = 0 }; - struct error_line * unrecognized_lines = NULL; - while (1) { - skip_horiz_space (&p.cursor); - if (*p.cursor == '\0') - break; - else if (*p.cursor == '\n') - p.cursor++; // Continue to next line - else if (*p.cursor == ';') - skip_to_line_end (&p.cursor); // Skip comment line - else if (*p.cursor == '[') - skip_to_line_end (&p.cursor); // Skip section line - else if (parse_string (&p.cursor, &p.key) && skip_punctuation (&p.cursor, '=')) { // Parse key and equals sign - - struct string_slice value; - if (parse_string (&p.cursor, &value) || parse_bracketed_block (&p.cursor, &value)) { // Parse value - int ival, offset, recog_err_offset; - - // if key is for a boolean option - if (stable_look_up_slice (&is->boolean_config_offsets, &p.key, &offset)) { - if (read_int (&value, &ival)) - *((char *)cfg + offset) = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - - // if key is for an integer option - } else if (stable_look_up_slice (&is->integer_config_offsets, &p.key, &offset)) { - if (read_int (&value, &ival)) - *(int *)((byte *)cfg + offset) = ival; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - - // Handle city_work_radius separately from the other int options so we can clamp it and update the count var - } else if (slice_matches_str (&p.key, "city_work_radius")) { - if (read_int (&value, &ival)) { - cfg->city_work_radius = clamp (1, 7, ival); - is->workable_tile_count = workable_tile_counts[cfg->city_work_radius]; - } else - handle_config_error (&p, CPE_BAD_INT_VALUE); - - // if key is for something special - } else if (slice_matches_str (&p.key, "limit_units_per_tile")) { - if (! read_units_per_tile_limit (&value, &cfg->limit_units_per_tile[0])) - handle_config_error (&p, CPE_BAD_STACK_LIMIT_VALUE); - } else if (slice_matches_str (&p.key, "production_perfume") || slice_matches_str (&p.key, "perfume_specs")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct perfume_spec), - parse_production_perfume_spec, - (void **)&perfume_spec_lists[PK_PRODUCTION].items, - &perfume_spec_lists[PK_PRODUCTION].count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "technology_perfume")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct perfume_spec), - parse_technology_perfume_spec, - (void **)&perfume_spec_lists[PK_TECHNOLOGY].items, - &perfume_spec_lists[PK_TECHNOLOGY].count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "government_perfume")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct perfume_spec), - parse_government_perfume_spec, - (void **)&perfume_spec_lists[PK_GOVERNMENT].items, - &perfume_spec_lists[PK_GOVERNMENT].count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "building_prereqs_for_units")) { - if (0 <= (recog_err_offset = read_building_unit_prereqs (&value, &unrecognized_lines, &cfg->building_unit_prereqs))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "buildings_generating_resources")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct mill), - parse_mill, - (void **)&cfg->mills, - &cfg->count_mills))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_multi_start_extra_palaces")) { - if (! read_ai_multi_start_extra_palaces (&value, - &unrecognized_lines, - &cfg->ai_multi_start_extra_palaces, - &cfg->count_ai_multi_start_extra_palaces, - &cfg->ai_multi_start_extra_palaces_capacity)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_settler_perfume_on_founding")) { - if (! read_i31b (&value, &cfg->ai_settler_perfume_on_founding)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "land_retreat_rules")) { - if (! read_retreat_rules (&value, (int *)&cfg->land_retreat_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "sea_retreat_rules")) { - if (! read_retreat_rules (&value, (int *)&cfg->sea_retreat_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "draw_lines_using_gdi_plus")) { - if (! read_line_drawing_override (&value, (int *)&cfg->draw_lines_using_gdi_plus)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "double_minimap_size")) { - if (! read_minimap_doubling_mode (&value, (int *)&cfg->double_minimap_size)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "unit_cycle_search_criteria")) { - if (! read_unit_cycle_search_criteria (&value, (int *)&cfg->unit_cycle_search_criteria)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "override_no_ai_patrol")) { - if (! read_no_ai_patrol_override (&value, (int *)&cfg->override_no_ai_patrol)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "override_barbarian_activity_level_for_scenario_maps")) { - if (! read_barbarian_activity_override (&value, &cfg->override_barbarian_activity_level_for_scenario_maps)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "special_defensive_bombard_rules")) { - struct parsable_field_bit bits[] = { - {"lethal" , SDBR_LETHAL}, - {"not-invisible" , SDBR_NOT_INVISIBLE}, - {"aerial" , SDBR_AERIAL}, - {"blitz" , SDBR_BLITZ}, - {"docked-vs-land", SDBR_DOCKED_VS_LAND}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_defensive_bombard_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "special_zone_of_control_rules")) { - struct parsable_field_bit bits[] = { - {"lethal" , SZOCR_LETHAL}, - {"aerial" , SZOCR_AERIAL}, - {"amphibious" , SZOCR_AMPHIBIOUS}, - {"not-from-inside", SZOCR_NOT_FROM_INSIDE}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_zone_of_control_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "land_transport_rules")) { - struct parsable_field_bit bits[] = { - {"load-onto-boat" , LTR_LOAD_ONTO_BOAT}, - {"join-army" , LTR_JOIN_ARMY}, - {"no-defense-from-inside", LTR_NO_DEFENSE_FROM_INSIDE}, - {"no-escape" , LTR_NO_ESCAPE}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->land_transport_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "special_helicopter_rules")) { - struct parsable_field_bit bits[] = { - {"allow-on-carriers" , SHR_ALLOW_ON_CARRIERS}, - {"passenger-airdrop" , SHR_PASSENGER_AIRDROP}, - {"no-defense-from-inside", SHR_NO_DEFENSE_FROM_INSIDE}, - {"no-escape" , SHR_NO_ESCAPE}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_helicopter_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "work_area_limit")) { - if (! read_work_area_limit (&value, (int *)&cfg->work_area_limit)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "work_area_improvements")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct work_area_improvement), - parse_work_area_improvement, - (void **)&cfg->work_area_improvements, - &cfg->count_work_area_improvements))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "day_night_cycle_mode")) { - if (! read_day_night_cycle_mode (&value, (int *)&cfg->day_night_cycle_mode)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "distribution_hub_yield_division_mode")) { - if (! read_distribution_hub_yield_division_mode (&value, (int *)&cfg->distribution_hub_yield_division_mode)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_distribution_hub_build_strategy")) { - if (! read_ai_distribution_hub_build_strategy (&value, (int *)&cfg->ai_distribution_hub_build_strategy)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_auto_build_great_wall_strategy")) { - if (! read_ai_auto_build_great_wall_strategy (&value, (int *)&cfg->ai_auto_build_great_wall_strategy)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "great_wall_auto_build_wonder_name")) { - if (cfg->great_wall_auto_build_wonder_name != NULL) { - free (cfg->great_wall_auto_build_wonder_name); - cfg->great_wall_auto_build_wonder_name = NULL; - } - cfg->great_wall_auto_build_wonder_name = copy_trimmed_string_or_null (&value, 1); - cfg->great_wall_auto_build_wonder_improv_id = -1; - } else if (slice_matches_str (&p.key, "exclude_types_from_units_per_tile_limit")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->exclude_types_from_units_per_tile_limit)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "limit_defensive_retreat_on_water_to_types")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->limit_defensive_retreat_on_water_to_types)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ptw_like_artillery_targeting")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->ptw_arty_types)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "can_bombard_only_sea_tiles")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->can_bombard_only_sea_tiles)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "civ_aliases_by_era")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct civ_era_alias_list), - parse_civ_name_alias_list, - (void **)&cfg->civ_era_alias_lists, - &cfg->count_civ_era_alias_lists))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "leader_aliases_by_era")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct leader_era_alias_list), - parse_leader_name_alias_list, - (void **)&cfg->leader_era_alias_lists, - &cfg->count_leader_era_alias_lists))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "unit_limits")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct parsed_unit_type_limit), - parse_unit_type_limit, - (void **)&parsed_unit_type_limits, - &parsed_unit_type_limit_count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "aircraft_victory_animation")) { - struct string_slice trimmed = trim_string_slice (&value, 1); - bool value_ok = false; - if (slice_matches_str (&trimmed, "none")) { - if (cfg->aircraft_victory_animation != NULL) { - free (cfg->aircraft_victory_animation); - cfg->aircraft_victory_animation = NULL; - } - value_ok = true; - } else if (trimmed.len > 0) { - AnimationType unused; - if (find_animation_type_by_name (&trimmed, true, &unused)) { - if (cfg->aircraft_victory_animation != NULL) - free (cfg->aircraft_victory_animation); - cfg->aircraft_victory_animation = extract_slice (&trimmed); - value_ok = true; - } - } - if (! value_ok) - handle_config_error (&p, CPE_BAD_VALUE); - - // if key is for an obsolete option - } else if (slice_matches_str (&p.key, "patch_disembark_immobile_bug")) { - if (read_int (&value, &ival)) - cfg->patch_blocked_disembark_freeze = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "anarchy_length_reduction_percent")) { - if (read_int (&value, &ival)) - cfg->anarchy_length_percent = 100 - ival; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - } else if (slice_matches_str (&p.key, "adjust_minimum_city_separation")) { - if (read_int (&value, &ival)) - cfg->minimum_city_separation = ival + 1; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - } else if (slice_matches_str (&p.key, "reduce_max_escorts_per_ai_transport")) { - if (read_int (&value, &ival)) - cfg->max_ai_naval_escorts = 3 - ival; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - } else if (slice_matches_str (&p.key, "retreat_rules")) { - int rules; - if (read_retreat_rules (&value, &rules)) { - cfg->land_retreat_rules = rules; - cfg->sea_retreat_rules = rules; - } else - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "halve_ai_research_rate")) { - if (read_int (&value, &ival)) { - if (ival) // halving = true => set multiplier to 50, otherwise do nothing - cfg->ai_research_multiplier = 50; - } else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "enable_ai_two_city_start")) { - if (read_int (&value, &ival)) - cfg->ai_multi_city_start = (ival != 0) ? 2 : 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "polish_non_air_precision_striking")) { - if (read_int (&value, &ival)) - cfg->polish_precision_striking = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "promote_forbidden_palace_decorruption")) { - if (read_int (&value, &ival)) - cfg->promote_wonder_decorruption_effect = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "move_trade_net_object")) { - ; // No nothing. This setting no longer serves any purpose. - - // if key was previously misspelled - } else if (slice_matches_str (&p.key, "share_visibility_in_hoseat")) { - if (read_int (&value, &ival)) - cfg->share_visibility_in_hotseat = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "unit_group")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct unit_counter_group), - parse_unit_counter_group, - (void **)&cfg->unit_counter_groups, - &cfg->count_unit_counter_groups))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "counter_rule")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct counter_rule), - parse_counter_rule, - (void **)&cfg->counter_rules, - &cfg->count_counter_rules))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - - } else { - handle_config_error (&p, CPE_BAD_KEY); - } - - - } else { // Failed to parse value - handle_config_error (&p, CPE_BAD_VALUE); - skip_to_line_end (&p.cursor); - } - - } else { // Failed to categorize line - handle_config_error (&p, CPE_GENERIC); - skip_to_line_end (&p.cursor); - } - } - - if (cfg->warn_about_unrecognized_names && (unrecognized_lines != NULL)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "Unrecognized names in %s:", full_path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - for (struct error_line * line = unrecognized_lines; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - patch_show_popup (popup, __, 0, 0); - } - - // Copy perfume specs from lists to tables - for (int n = 0; n < COUNT_PERFUME_KINDS; n++) { - struct table * table = &cfg->perfume_specs[n]; - struct perfume_spec_list * list = &perfume_spec_lists[n]; - if (list->items != NULL) { - for (int k = 0; k < list->count; k++) { - struct perfume_spec * ps = &list->items[k]; - stable_insert (table, ps->name, ps->value); - } - free (list->items); - } - } - - // Copy unit type limits from list to table - if (parsed_unit_type_limits != NULL) { - for (int n = 0; n < parsed_unit_type_limit_count; n++) { - struct parsed_unit_type_limit * parsed_lim = &parsed_unit_type_limits[n]; - struct unit_type_limit * lim_values = malloc (sizeof *lim_values); - *lim_values = parsed_lim->limit; - stable_insert (&cfg->unit_limits, parsed_lim->name, (int)lim_values); - } - free (parsed_unit_type_limits); - } - - free (text); - free_error_lines (unrecognized_lines); - - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = full_path; - new_lcn->next = NULL; - - top_lcn->next = new_lcn; -} - -bool -tile_coords_from_ptr (Map * map, Tile * tile, int * out_x, int * out_y) -{ - if ((tile == NULL) || (tile == p_null_tile) || (map == NULL)) - return false; - - int tile_count = map->TileCount; - for (int index = 0; index < tile_count; index++) { - Tile * candidate = Map_get_tile (map, __, index); - if (candidate == tile) { - tile_index_to_coords (map, index, out_x, out_y); - return true; - } - } - - return false; -} - -int -get_pending_district_request_key (int city_id, int district_id) -{ - if ((city_id < 0) || (district_id < 0)) - return -1; - unsigned int key = ((unsigned int)city_id << 16) | (unsigned int)(district_id & 0xffff); - return (int)key; -} - -struct pending_district_request * -find_pending_district_request (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0)) - return NULL; - - int civ_id = city->Body.CivID; - int city_id = city->Body.ID; - int key = get_pending_district_request_key (city_id, district_id); - if (key < 0) - return NULL; - - int stored; - if (itable_look_up (&is->city_pending_district_requests[civ_id], key, &stored)) { - struct pending_district_request * req = (struct pending_district_request *)stored; - if ((req != NULL) && (req->civ_id == civ_id) && (req->city_id == city_id) && (req->district_id == district_id)) { - if (req->city != city) - req->city = city; - return req; - } - } - return NULL; -} - -struct pending_district_request * -create_pending_district_request (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return NULL; - - struct pending_district_request * existing = find_pending_district_request (city, district_id); - if (existing != NULL) - return existing; - - int civ_id = city->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) - return NULL; - - struct pending_district_request * req = (struct pending_district_request *)calloc (1, sizeof *req); - if (req == NULL) - return NULL; - - req->city = city; - req->city_id = city->Body.ID; - req->civ_id = civ_id; - req->district_id = district_id; - req->assigned_worker_id = -1; - req->target_x = -1; - req->target_y = -1; - req->worker_assigned_turn = 0; - - int key = get_pending_district_request_key (req->city_id, district_id); - if (key < 0) { - free (req); - return NULL; - } - - char ss[200]; - snprintf (ss, sizeof ss, "create_pending_district_request: Creating pending district request for city %s (ID %d) district ID %d with key %d\n", - city->Body.CityName, city->Body.ID, district_id, key); - (*p_OutputDebugStringA) (ss); - - itable_insert (&is->city_pending_district_requests[civ_id], key, (int)req); - return req; -} - -struct pending_district_request * -find_pending_district_request_by_coords (City * city_or_null, int tile_x, int tile_y, int district_id) -{ - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - - int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((civ_id < 0) || (civ_id >= 32)) - return NULL; - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req == NULL) continue; - if (req->district_id != district_id) continue; - if (city_or_null != NULL) { - int city_id = city_or_null->Body.ID; - if (req->city_id != city_id) - continue; - req->city = city_or_null; - req->civ_id = city_or_null->Body.CivID; - } - if ((req->target_x == tile_x) && (req->target_y == tile_y)) - return req; - } - return NULL; -} - -bool -is_tile_earmarked_for_district (int tile_x, int tile_y) -{ - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req == NULL) continue; - if ((req->target_x == tile_x) && (req->target_y == tile_y)) - return true; - } - return false; -} - -struct district_instance * -get_district_instance (Tile * tile) -{ - if (tile == NULL || tile == p_null_tile) - return NULL; - - int stored_ptr; - if (! itable_look_up (&is->district_tile_map, (int)tile, &stored_ptr)) - return NULL; - - struct district_instance * inst = (struct district_instance *)stored_ptr; - - if ((inst == NULL) || (inst->district_id < 0) || (inst->district_id >= is->district_count)) - return NULL; - - return inst; -} - -struct wonder_district_info * -get_wonder_district_info (Tile * tile) -{ - if (tile == NULL || tile == p_null_tile) - return NULL; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return NULL; - - return &inst->wonder_info; -} - -void -remove_district_instance (Tile * tile) -{ - if (tile == NULL || tile == p_null_tile) - return; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - free (inst); - itable_remove (&is->district_tile_map, (int)tile); - } -} - -void -district_instance_set_coords (struct district_instance * inst, int tile_x, int tile_y) -{ - if (inst == NULL) - return; - - // Normalize coordinates to map bounds for consistency - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - inst->tile_x = tile_x; - inst->tile_y = tile_y; -} - -struct district_instance * -ensure_district_instance (Tile * tile, int district_id, int tile_x, int tile_y) -{ - if (tile == NULL || tile == p_null_tile) - return NULL; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - return inst; - } - - inst = (struct district_instance *)calloc (1, sizeof(struct district_instance)); - if (inst == NULL) - return NULL; - - inst->state = DS_UNDER_CONSTRUCTION; - inst->district_id = district_id; - inst->built_by_civ_id = -1; - inst->completed_turn = -1; - - // Initialize wonder_info (only relevant for wonder districts) - inst->wonder_info.state = WDS_UNUSED; - inst->wonder_info.city = NULL; - inst->wonder_info.city_id = -1; - inst->wonder_info.wonder_index = -1; - inst->natural_wonder_info.natural_wonder_id = -1; - - district_instance_set_coords (inst, tile_x, tile_y); - itable_insert (&is->district_tile_map, (int)tile, (int)inst); - return inst; -} - -bool -district_instance_get_coords (struct district_instance * inst, Tile * tile, int * out_x, int * out_y) -{ - if ((inst == NULL) || (out_x == NULL) || (out_y == NULL)) - return false; - - int x = inst->tile_x; - int y = inst->tile_y; - if ((x >= 0) && (y >= 0)) { - *out_x = x; - *out_y = y; - return true; - } - - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile_coords_from_ptr (&p_bic_data->Map, tile, &x, &y)) { - district_instance_set_coords (inst, x, y); - *out_x = x; - *out_y = y; - return true; - } - - return false; -} - -struct natural_wonder_district_config const * -get_natural_wonder_config_by_id (int natural_wonder_id) -{ - if (! is->current_config.enable_natural_wonders) - return NULL; - if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) - return NULL; - return &is->natural_wonder_configs[natural_wonder_id]; -} - -void -assign_natural_wonder_to_tile (Tile * tile, int tile_x, int tile_y, int natural_wonder_id) -{ - if (! is->current_config.enable_natural_wonders) - return; - if ((tile == NULL) || (tile == p_null_tile)) - return; - if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) - return; - - if (get_natural_wonder_config_by_id (natural_wonder_id) == NULL) - return; - - struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, tile_x, tile_y); - if (inst == NULL) - return; - - inst->district_id = NATURAL_WONDER_DISTRICT_ID; - inst->state = DS_COMPLETED; - inst->natural_wonder_info.natural_wonder_id = natural_wonder_id; - set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); -} - -int -apply_district_bonus_entries (struct district_instance * inst, - struct district_bonus_list const * extras, - int district_id) -{ - if ((inst == NULL) || (extras == NULL) || (extras->count <= 0)) - return 0; - - int tile_x = inst->tile_x; - int tile_y = inst->tile_y; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return 0; - - int bonus = 0; - for (int i = 0; i < extras->count; i++) { - struct district_bonus_entry const * entry = &extras->entries[i]; - if (entry->type == DBET_TILE) { - if (tile_matches_square_type (tile, entry->tile_type)) - bonus += entry->bonus; - } else if (entry->type == DBET_BUILDING) { - if (entry->building_id >= 0 && - tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, entry->building_id)) - bonus += entry->bonus; - } - } - - return bonus; -} - -void -get_effective_district_yields (struct district_instance * inst, - struct district_config const * cfg, - int * out_food, - int * out_shields, - int * out_gold, - int * out_science, - int * out_culture, - int * out_happiness) -{ - int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; - - if (cfg != NULL && is->current_config.enable_districts) { - food = cfg->food_bonus; - shields = cfg->shield_bonus; - gold = cfg->gold_bonus; - science = cfg->science_bonus; - culture = cfg->culture_bonus; - happiness = cfg->happiness_bonus; - - int district_id = (inst != NULL) ? inst->district_id : -1; - food += apply_district_bonus_entries (inst, &cfg->food_bonus_extras, district_id); - shields += apply_district_bonus_entries (inst, &cfg->shield_bonus_extras, district_id); - gold += apply_district_bonus_entries (inst, &cfg->gold_bonus_extras, district_id); - science += apply_district_bonus_entries (inst, &cfg->science_bonus_extras, district_id); - culture += apply_district_bonus_entries (inst, &cfg->culture_bonus_extras, district_id); - happiness += apply_district_bonus_entries (inst, &cfg->happiness_bonus_extras, district_id); - } - - if (inst != NULL && is->current_config.enable_natural_wonders && inst->district_id == NATURAL_WONDER_DISTRICT_ID) { - struct natural_wonder_district_config const * nwcfg = get_natural_wonder_config_by_id (inst->natural_wonder_info.natural_wonder_id); - if (nwcfg != NULL) { - food += nwcfg->food_bonus; - shields += nwcfg->shield_bonus; - gold += nwcfg->gold_bonus; - science += nwcfg->science_bonus; - culture += nwcfg->culture_bonus; - happiness += nwcfg->happiness_bonus; - } - } - - if (out_food != NULL) - *out_food = food; - if (out_shields != NULL) - *out_shields = shields; - if (out_gold != NULL) - *out_gold = gold; - if (out_science != NULL) - *out_science = science; - if (out_culture != NULL) - *out_culture = culture; - if (out_happiness != NULL) - *out_happiness = happiness; -} - -int -natural_wonder_min_distance_sq (int x, - int y, - struct wonder_location const * placements, - int placement_count) -{ - if ((placements == NULL) || (placement_count <= 0)) - return INT_MAX; - - int best = INT_MAX; - for (int i = 0; i < placement_count; i++) { - int dx, dy; - compute_wrapped_deltas (x, y, placements[i].x, placements[i].y, &dx, &dy); - int dist_sq = dx * dx + dy * dy; - if (dist_sq < best) - best = dist_sq; - } - return best; -} - -bool -continent_has_natural_wonder (int continent_id, - struct wonder_location const * placements, - int placement_count) -{ - if (continent_id < 0) - return false; - if ((placements == NULL) || (placement_count <= 0)) - return false; - - for (int i = 0; i < placement_count; i++) { - Tile * placed_tile = tile_at (placements[i].x, placements[i].y); - if ((placed_tile == NULL) || (placed_tile == p_null_tile)) - continue; - int placed_continent_id = placed_tile->vtable->m46_Get_ContinentID (placed_tile); - if (placed_continent_id == continent_id) - return true; - } - - return false; -} - -bool -natural_wonder_candidate_list_push (struct natural_wonder_candidate_list * list, Tile * tile, int tile_x, int tile_y) -{ - if (list == NULL) - return false; - - if (list->count >= list->capacity) { - int new_capacity = (list->capacity > 0) ? (list->capacity * 2) : 8; - struct natural_wonder_candidate * grown = - (struct natural_wonder_candidate *)realloc (list->entries, new_capacity * sizeof *grown); - if (grown == NULL) - return false; - list->entries = grown; - list->capacity = new_capacity; - } - - struct natural_wonder_candidate * entry = &list->entries[list->count++]; - entry->tile = tile; - entry->x = (short)tile_x; - entry->y = (short)tile_y; - return true; -} - -bool -natural_wonder_tile_is_clear (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (tile->CityID >= 0) return false; - if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return false; - if (tile->vtable->m15_Check_Goody_Hut (tile, __, 0)) return false; - if (tile->vtable->m39_Get_Resource_Type (tile) >= 0) return false; - if (tile->vtable->m18_Check_Mines (tile, __, 0)) return false; - if (get_district_instance (tile) != NULL) return false; - - // Check if this tile is a starting location for any civ - int tile_index = (p_bic_data->Map.Width >> 1) * tile_y + ((tile_x >> 1) & 0x7FFF); - for (int civ = 0; civ < p_bic_data->Map.Civ_Count; civ++) { - if (p_bic_data->Map.Starting_Locations[civ] == tile_index) { - return false; - } - } - - return true; -} - -bool -district_exists_within_distance (int tile_x, int tile_y, int district_id, int civ_id, int min_distance) -{ - if ((district_id < 0) || (district_id >= is->district_count) || (min_distance < 0)) - return false; - - for (int dist = 0; dist <= min_distance; dist++) { - struct vertex { - int x, y; - } vertices[4] = { - {tile_x , tile_y - 2*dist}, - {tile_x + 2*dist, tile_y }, - {tile_x , tile_y + 2*dist}, - {tile_x - 2*dist, tile_y } - }; - - int edge_dirs[4] = {3, 5, 7, 1}; - int edge_len = (dist == 0) ? 1 : 2 * dist; - - for (int vert = 0; vert < 4; vert++) { - wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); - int dx, dy; - neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); - for (int j = 0; j < edge_len; j++) { - int cx = vertices[vert].x + j * dx; - int cy = vertices[vert].y + j * dy; - wrap_tile_coords (&p_bic_data->Map, &cx, &cy); - - Tile * tile = tile_at (cx, cy); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if ((civ_id >= 0) && (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id)) - continue; - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == district_id)) - return true; - } - } - } - - return false; -} - -void -detach_workers_from_request (struct pending_district_request * req) -{ - if (req == NULL) - return; - - int civ_id = req->civ_id; - if ((civ_id < 0) || (civ_id >= 32)) { - for (int civ = 0; civ < 32; civ++) { - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - if ((rec != NULL) && (rec->pending_req == req)) - rec->pending_req = NULL; - } - } - return; - } - - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - if ((rec != NULL) && (rec->pending_req == req)) - rec->pending_req = NULL; - } -} - -void -remove_pending_district_request (struct pending_district_request * req) -{ - if (req == NULL) - return; - - int civ_id = req->civ_id; - if ((civ_id < 0) || (civ_id >= 32)) - return; - - int key = get_pending_district_request_key (req->city_id, req->district_id); - - detach_workers_from_request (req); - - if ((req->target_x >= 0) && (req->target_y >= 0)) { - Tile * tile = tile_at (req->target_x, req->target_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && - (inst->district_id == req->district_id) && - (inst->state != DS_COMPLETED)) - remove_district_instance (tile); - } - } - - if (key >= 0) - itable_remove (&is->city_pending_district_requests[civ_id], key); - req->city = NULL; - req->city_id = -1; - req->civ_id = -1; - free (req); -} - -bool __fastcall -patch_Leader_impl_would_raze_city (Leader * this, int edx, City * city) -{ - return is->current_config.prevent_razing_by_players ? false : Leader_impl_would_raze_city (this, __, city); -} - -int __fastcall patch_Unit_get_max_move_points (Unit * this); - -// This function is used to fix a bug where the game would freeze when using disembark all on a transport that contained an immobile unit. The bug -// comes from the fact that the function to disembark all units loops continuously over units in the transport until there are none left that -// can be disembarked. The problem is the logic to check disembarkability erroneously reports immobile units as disembarkable when they're not, -// so the program gets stuck in an infinite loop. The fix affects the function that checks disembarkability, replacing a call to -// Unit_get_max_move_points with a call to the function below. This function returns zero for immobile units, causing the caller to report -// (correctly) that the unit cannot be disembarked. -int __fastcall -patch_Unit_get_max_move_points_for_disembarking (Unit * this) -{ - if (is->current_config.patch_blocked_disembark_freeze && - UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Immobile)) - return 0; - else - return patch_Unit_get_max_move_points (this); -} - -// Unit::move_to_adjacent_tile uses a separate "spend all remaining movement when disembarking" branch for land units moving from water to land. -// Bridge districts still look like water tiles to that stock logic, so stepping off a bridge can incorrectly consume the whole turn. When the -// wrapper around move_to_adjacent_tile detects bridge->land movement, it precomputes the correct spent-moves total and exposes it here. -int __fastcall -patch_Unit_get_max_move_points_for_bridge_exit (Unit * this) -{ - if ((this != NULL) && (this == is->move_spend_override_unit)) - return is->move_spend_override_value; - else - return patch_Unit_get_max_move_points (this); -} - -// This func implements GA remaining turns indicator. It intercepts a call to some kind of text processing function when it's called to process the -// text in the lower right (containing current research, GA status, & mobilization) and splices in the number of remaining GA turns if in a GA. -int __fastcall -patch_PCX_Image_process_tech_ga_status (PCX_Image * this, int edx, char * str) -{ - Leader * player = &leaders[p_main_screen_form->Player_CivID]; - if (is->current_config.show_golden_age_turns_remaining && - (*p_current_turn_no < player->Golden_Age_End)) { - int turns_left = player->Golden_Age_End - *p_current_turn_no; - char const * ga_label = (*p_labels)[LBL_GOLDEN_AGE]; - char const * ga_str_start = strstr (str, ga_label); - if (ga_str_start != NULL) { - char s[250]; - char const * ga_str_end = ga_str_start + strlen (ga_label); - snprintf (s, sizeof s, "%.*s (%d)%s", ga_str_end - str, str, turns_left, ga_str_end); - s[(sizeof s) - 1] = '\0'; - strncpy (str, s, sizeof s); - } - } - return PCX_Image_process_text (this, __, str); -} - -bool __fastcall -patch_Leader_is_tile_visible (Leader * this, int edx, int x, int y) -{ - Tile_Body * tile = &tile_at (x, y)->Body; - unsigned vis_bits = tile->FOWStatus | tile->V3 | tile->Visibility | tile->field_D0_Visibility; - if (vis_bits & (1 << this->ID)) - return true; - else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND - ((1 << this->ID) & *p_human_player_bits) && // "this" is a human player AND - (vis_bits & *p_human_player_bits)) // any human player has visibility on the tile - return true; - else - return false; -} - -bool __fastcall -patch_Main_Screen_Form_is_unit_visible_to_player (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * unit) -{ - return (unit->Body.CivID == this->Player_CivID) || patch_Leader_is_tile_visible (&leaders[this->Player_CivID], __, tile_x, tile_y); -} - -enum direction -reverse_dir (enum direction dir) -{ - enum direction const reversed[] = { - DIR_ZERO, // DIR_ZERO - DIR_SW , // DIR_NE - DIR_W , // DIR_E - DIR_NW , // DIR_SE - DIR_N , // DIR_S - DIR_NE , // DIR_SW - DIR_E , // DIR_W - DIR_SE , // DIR_NW - DIR_S , // DIR_N - }; - int n = (int)dir; - if ((n >= 0) && (n < ARRAY_LEN (reversed))) - return reversed[n]; - else - return DIR_ZERO; -} - -bool -direction_to_offset (enum direction dir, int * out_dx, int * out_dy) -{ - int dx = 0, dy = 0; - - switch (dir) { - case DIR_NE: dx = 1; dy = -1; break; - case DIR_E: dx = 2; dy = 0; break; - case DIR_SE: dx = 1; dy = 1; break; - case DIR_S: dx = 0; dy = 2; break; - case DIR_SW: dx = -1; dy = 1; break; - case DIR_W: dx = -2; dy = 0; break; - case DIR_NW: dx = -1; dy = -1; break; - case DIR_N: dx = 0; dy = -2; break; - case DIR_ZERO: - default: - return false; - } - - if (out_dx != NULL) - *out_dx = dx; - if (out_dy != NULL) - *out_dy = dy; - return true; -} - -int -direction_to_neighbor_bit (enum direction dir) -{ - switch (dir) { - case DIR_NE: return 1; - case DIR_E: return 2; - case DIR_SE: return 3; - case DIR_S: return 4; - case DIR_SW: return 5; - case DIR_W: return 6; - case DIR_NW: return 7; - case DIR_N: return 0; // Matches engine behaviour where neighbor index 8 maps to 0 - default: - return -1; - } -} - -bool -get_primary_river_direction (Tile * tile, enum direction * out_dir) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - char river_bits = tile->vtable->m37_Get_River_Code (tile); - if (river_bits == 0) - return false; - - enum direction dirs[] = {DIR_E, DIR_W, DIR_SE, DIR_NE, DIR_SW, DIR_NW, DIR_S, DIR_N}; - for (int i = 0; i < (int)ARRAY_LEN (dirs); i++) { - int bit = direction_to_neighbor_bit (dirs[i]); - if ((bit >= 0) && ((river_bits & (1 << bit)) != 0)) { - if (out_dir != NULL) - *out_dir = dirs[i]; - return true; - } - } - - return false; -} - -void -wrap_tile_coords (Map * map, int * x, int * y) -{ - if (map->Flags & 1) { - if (*x < 0) *x += map->Width; - else if (*x >= map->Width) *x -= map->Width; - } - if (map->Flags & 2) { - if (*y < 0) *y += map->Height; - else if (*y >= map->Height) *y -= map->Height; - } -} - -void -tile_index_to_coords (Map * map, int index, int * out_x, int * out_y) -{ - if ((index >= 0) && (index < map->TileCount)) { - int width = map->Width; - int double_row = index / width, double_row_rem = index % width; - if (double_row_rem < width/2) { - *out_x = 2 * double_row_rem; - *out_y = 2 * double_row; - } else { - *out_x = 1 + 2 * (double_row_rem - width/2); - *out_y = 2 * double_row + 1; - } - } else - *out_x = *out_y = -1; -} - -int -tile_coords_to_index (Map * map, int x, int y) -{ - if ((map == NULL) || (x < 0) || (y < 0) || (x >= map->Width) || (y >= map->Height)) - return -1; - - int width = map->Width; - int row = y / 2; - if ((y & 1) == 0) { - return row * width + (x / 2); - } else { - return row * width + (width / 2) + (x / 2); - } -} - -Tile * -tile_at_index (Map * map, int i) -{ - int x, y; - tile_index_to_coords (map, i, &x, &y); - return tile_at (x, y); -} - -void -get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y) -{ - int dx, dy; - neighbor_index_to_diff (neighbor_index, &dx, &dy); - *out_x = x + dx; - *out_y = y + dy; - wrap_tile_coords (map, out_x, out_y); -} - -Tile * __stdcall -tile_at_city_or_null (City * city_or_null) -{ - if (city_or_null) - return tile_at (city_or_null->Body.X, city_or_null->Body.Y); - else - return p_null_tile; -} - -Unit * -get_unit_ptr (int id) -{ - if ((p_units->Units != NULL) && - (id >= 0) && (id <= p_units->LastIndex)) { - Unit_Body * body = p_units->Units[id].Unit; - if (body != NULL) { - Unit * unit = (Unit *)((char *)body - offsetof (Unit, Body)); - if (unit != NULL) - return unit; - } - } - return NULL; -} - -bool -is_land_transport (Unit * unit) -{ - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - return type->Unit_Class == UTC_Land && type->Transport_Capacity > 0 && ! Unit_has_ability (unit, __, UTA_Army); -} - -bool -is_in_land_transport (Unit * unit) -{ - Unit * container = get_unit_ptr (unit->Body.Container_Unit); - return container != NULL && is_land_transport (container); -} - -// Checks if the unit is inside a transport (either helicopter or land transport) from which it is not allowed to defend according to the mod config. -bool -cannot_defend_inside_transport (Unit * unit) -{ - Unit * container = get_unit_ptr (unit->Body.Container_Unit); - if (container != NULL) { - if ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && is_land_transport (container)) - return true; - - if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return true; - } - return false; -} - -struct unit_tile_iter { - int id; - int item_index; - Unit * unit; -}; - -void -uti_next (struct unit_tile_iter * uti) -{ - if (((p_tile_units->Base.Items == NULL) || (uti->item_index < 0)) || - (uti->item_index > p_tile_units->Base.LastIndex)) { - uti->item_index = -1; - uti->id = p_tile_units->DefaultValue; - } else { - Base_List_Item * item = &p_tile_units->Base.Items[uti->item_index]; - uti->item_index = item->V; - uti->id = (int)item->Object; - } - uti->unit = get_unit_ptr (uti->id); -} - -struct unit_tile_iter -uti_init (Tile * tile) -{ - struct unit_tile_iter tr; - int tile_unit_id = tile->vtable->m40_get_TileUnit_ID (tile); - tr.id = TileUnits_TileUnitID_to_UnitID (p_tile_units, __, tile_unit_id, &tr.item_index); - tr.unit = get_unit_ptr (tr.id); - return tr; -} - -#define FOR_UNITS_ON(uti_name, tile) for (struct unit_tile_iter uti_name = uti_init (tile); uti_name.id != -1; uti_next (&uti_name)) - -bool -tile_has_enemy_unit (Tile * tile, int civ_id) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - if ((civ_id < 0) || (civ_id >= 32)) - return false; - - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit == NULL) || (unit->Body.Container_Unit >= 0)) - continue; - if (unit->Body.CivID == civ_id) - continue; - if (unit->vtable->is_enemy_of_civ (unit, __, civ_id, 0)) - return true; - } - - return false; -} - -struct citizen_iter { - int index; - Citizens * list; - Citizen_Base * ctzn; -}; - -void -ci_next (struct citizen_iter * ci) -{ - while (1) { - ci->index++; - if (ci->index > ci->list->LastIndex) { - ci->ctzn = NULL; - break; - } else { - Citizen_Body * body = ci->list->Items[ci->index].Body; - if ((body != NULL) && ((int)body != offsetof (Citizen_Base, Body))) { - ci->ctzn = (Citizen_Base *)((int)body - offsetof (Citizen_Base, Body)); - break; - } - } - } -} - -struct citizen_iter -ci_init (City * city) -{ - struct citizen_iter tr; - tr.index = -1; - tr.list = &city->Body.Citizens; - tr.ctzn = NULL; - if (city->Body.Citizens.Items != NULL) - ci_next (&tr); - return tr; -} - -#define FOR_CITIZENS_IN(ci_name, city) for (struct citizen_iter ci_name = ci_init (city); (ci_name.list->Items != NULL) && (ci_name.index <= ci.list->LastIndex); ci_next (&ci_name)) - -struct city_of_iter { - int city_id; - int civ_id; - City * city; -}; - -void -coi_next (struct city_of_iter * coi) -{ - coi->city_id++; - while (coi->city_id <= p_cities->LastIndex) { - City_Body * body = p_cities->Cities[coi->city_id].City; - if ((body != NULL) && ((int)body != offsetof (City, Body)) && (body->CivID == coi->civ_id)) { - coi->city = (City *)((char *)body - offsetof (City, Body)); - break; - } - coi->city_id++; - } -} - -struct city_of_iter -coi_init (int civ_id) -{ - struct city_of_iter tr = { .city_id = -1, .civ_id = civ_id, .city = NULL }; - if (p_cities->Cities != NULL) - coi_next (&tr); - else - tr.city_id = p_cities->LastIndex + 1; - return tr; -} - -#define FOR_CITIES_OF(coi_name, civ_id) for (struct city_of_iter coi_name = coi_init (civ_id); coi_name.city_id <= p_cities->LastIndex; coi_next (&coi_name)) - -struct tiles_around_iter { - int center_x, center_y; - int n, num_tiles; - Tile * tile; - int tile_x, tile_y; -}; - -void -tai_next (struct tiles_around_iter * tai) -{ - tai->tile = p_null_tile; - while ((tai->n < tai->num_tiles) && (tai->tile == p_null_tile)) { - tai->n += 1; - int tx, ty; - get_neighbor_coords (&p_bic_data->Map, tai->center_x, tai->center_y, tai->n, &tx, &ty); - if ((tx >= 0) && (tx < p_bic_data->Map.Width) && (ty >= 0) && (ty < p_bic_data->Map.Height)) { - tai->tile = tile_at (tx, ty); - tai->tile_x = tx; - tai->tile_y = ty; - } - } -} - -struct tiles_around_iter -tai_init (int num_tiles, int x, int y) -{ - struct tiles_around_iter tr; - tr.center_x = x; - tr.center_y = y; - tr.n = 0; - tr.num_tiles = num_tiles; - tr.tile = tile_at (x, y); - tr.tile_x = x; - tr.tile_y = y; - return tr; -} - -#define FOR_TILES_AROUND(tai_name, _num_tiles, _x, _y) for (struct tiles_around_iter tai_name = tai_init (_num_tiles, _x, _y); (tai_name.n < tai_name.num_tiles); tai_next (&tai_name)) - -enum work_area_iter_output_type { - WAIO_ANY, - WAIO_DISTRICTS, - WAIO_CITIES, -}; - -struct work_area_iter { - int center_x, center_y; - int n, num_tiles; - int civ_id; - int dx, dy; - int tile_x, tile_y; - Tile * tile; - City * city; - struct district_instance * district_inst; - enum work_area_iter_output_type output_type; - bool completed_districts_only; -}; - -void -wai_next (struct work_area_iter * wai) -{ - wai->tile = p_null_tile; - wai->district_inst = NULL; - while ((wai->n + 1) < wai->num_tiles) { - wai->n += 1; - patch_ni_to_diff_for_work_area (wai->n, &wai->dx, &wai->dy); - wai->tile_x = wai->center_x + wai->dx; - wai->tile_y = wai->center_y + wai->dy; - wrap_tile_coords (&p_bic_data->Map, &wai->tile_x, &wai->tile_y); - Tile * candidate = tile_at (wai->tile_x, wai->tile_y); - if ((candidate == NULL) || (candidate == p_null_tile)) - continue; - if ((wai->civ_id < 0) || (candidate->vtable->m38_Get_Territory_OwnerID (candidate) != wai->civ_id)) - continue; - if (tile_has_enemy_unit (candidate, wai->civ_id)) - continue; - if (candidate->vtable->m20_Check_Pollution (candidate, __, 0)) - continue; - City * city; - if (wai->output_type == WAIO_CITIES) { - if (candidate->CityID < 0) - continue; - city = get_city_ptr (candidate->vtable->m45_Get_City_ID (candidate)); - if (city == NULL || city->Body.CivID != wai->civ_id) - continue; - } - struct district_instance * inst = get_district_instance (candidate); - if (wai->output_type == WAIO_DISTRICTS) { - if (inst == NULL) - continue; - int district_id = inst->district_id; - if (wai->completed_districts_only && (! district_is_complete (candidate, district_id))) - continue; - } - wai->city = city; - wai->district_inst = inst; - wai->tile = candidate; - break; - } - if (wai->tile == p_null_tile) - wai->n = wai->num_tiles; -} - -struct work_area_iter -wai_init_common (int x, int y, enum work_area_iter_output_type output, bool completed_districts_only) -{ - struct work_area_iter tr; - tr.center_x = x; - tr.center_y = y; - tr.n = -1; - tr.num_tiles = is->workable_tile_count; - Tile * center_tile = tile_at (x, y); - if ((center_tile == NULL) || (center_tile == p_null_tile)) - tr.civ_id = -1; - else - tr.civ_id = center_tile->vtable->m38_Get_Territory_OwnerID (center_tile); - tr.tile = p_null_tile; - tr.district_inst = NULL; - tr.dx = 0; - tr.dy = 0; - tr.tile_x = 0; - tr.tile_y = 0; - tr.output_type = output; - tr.completed_districts_only = completed_districts_only; - wai_next (&tr); - return tr; -} - -struct work_area_iter -wai_init (int x, int y) -{ - return wai_init_common (x, y, false, false); -} - -struct work_area_iter -wai_init_districts (int x, int y, bool completed_only) -{ - return wai_init_common (x, y, WAIO_DISTRICTS, completed_only); -} - -struct work_area_iter -wai_init_cities (int x, int y) -{ - struct work_area_iter tr = wai_init_common (x, y, WAIO_CITIES, false); - return tr; -} - -#define FOR_WORK_AREA_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) -#define FOR_DISTRICTS_AROUND(wai_name, _x, _y, _completed_only) for (struct work_area_iter wai_name = wai_init_districts (_x, _y, _completed_only); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) -#define FOR_CITIES_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init_cities (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) -#define FOR_AERODROMES_AROUND(unit_ptr) \ - for (struct table_entry_iter _tei = tei_init (&is->district_tile_map); \ - _tei.index < _tei.capacity; \ - tei_next (&_tei)) \ - for (Tile * aerodrome_tile = (Tile *)_tei.key; \ - (aerodrome_tile != NULL) && (aerodrome_tile != p_null_tile); \ - aerodrome_tile = NULL) \ - for (struct district_instance * aerodrome_inst = (struct district_instance *)_tei.value; \ - (aerodrome_inst != NULL) && \ - (aerodrome_inst->district_id == AERODROME_DISTRICT_ID) && \ - district_is_complete (aerodrome_tile, AERODROME_DISTRICT_ID); \ - aerodrome_inst = NULL) \ - for (int aerodrome_x = 0, aerodrome_y = 0; \ - district_instance_get_coords (aerodrome_inst, aerodrome_tile, &aerodrome_x, &aerodrome_y) && \ - (aerodrome_tile->vtable->m38_Get_Territory_OwnerID (aerodrome_tile) == (unit_ptr)->Body.CivID) && \ - patch_Unit_is_in_rebase_range ((unit_ptr), __, aerodrome_x, aerodrome_y); \ - aerodrome_x = 0, aerodrome_y = 0) - -struct tile_rings_iter { - int center_x, center_y; - int const * rings; - int ring_count; - int r_idx; - int ni; - int tile_x, tile_y; - int current_ring; - Tile * tile; -}; - -void -tri_next (struct tile_rings_iter * tri) -{ - tri->tile = p_null_tile; - while (tri->r_idx < tri->ring_count) { - int ring_no = tri->rings[tri->r_idx]; - if ((ring_no <= 0) || (ring_no >= 8)) { - tri->r_idx += 1; - tri->ni = -1; - continue; - } - int start_ni = workable_tile_counts[ring_no - 1]; - int end_ni = workable_tile_counts[ring_no]; - if (tri->ni < start_ni) - tri->ni = start_ni; - else if ((tri->ni + 1) < end_ni) - tri->ni += 1; - else { - tri->r_idx += 1; - tri->ni = -1; - continue; - } - tri->current_ring = ring_no; - int dx, dy; - patch_ni_to_diff_for_work_area (tri->ni, &dx, &dy); - int tx = tri->center_x + dx; - int ty = tri->center_y + dy; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - tri->tile_x = tx; - tri->tile_y = ty; - Tile * candidate = tile_at (tx, ty); - if ((candidate == NULL) || (candidate == p_null_tile)) - continue; - tri->tile = candidate; - break; - } - if (tri->tile == p_null_tile) { - tri->r_idx = tri->ring_count; - tri->ni = -1; - } -} - -struct tile_rings_iter -tri_init (int x, int y, int const * rings, int ring_count) -{ - struct tile_rings_iter tr; - tr.center_x = x; - tr.center_y = y; - tr.rings = rings; - tr.ring_count = ring_count; - tr.r_idx = 0; - tr.ni = -1; - tr.tile_x = 0; - tr.tile_y = 0; - tr.current_ring = 0; - tr.tile = p_null_tile; - tri_next (&tr); - return tr; -} - -#define FOR_TILE_RINGS_AROUND(tri_name, _x, _y, _rings, _ring_count) for (struct tile_rings_iter tri_name = tri_init (_x, _y, _rings, _ring_count); (tri_name.r_idx < tri_name.ring_count); tri_next (&tri_name)) - -bool -tile_square_type_is (Tile * tile, enum SquareTypes type) -{ - return tile_matches_square_type (tile, type); -} - -bool -district_is_buildable_on_tile (struct district_config const * cfg, Tile * tile) -{ - if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - unsigned int mask = cfg->buildable_square_types_mask; - if (mask == 0) - mask = district_default_buildable_mask (); - - bool square_matches = tile_matches_square_type_mask (tile, mask); - bool overlay_allowed = false; - bool overlay_required = false; - - if (cfg->has_buildable_without_removal) - overlay_allowed = tile_matches_overlay_mask (tile, cfg->buildable_without_removal_mask); - - if (cfg->has_buildable_on_overlays) { - overlay_required = tile_matches_overlay_mask (tile, cfg->buildable_on_overlays_mask); - if (! overlay_required) - return false; - } - if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) - return false; - - if (! square_matches && ! overlay_allowed && ! overlay_required) - return false; - - if (cfg->has_buildable_on_districts) { - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - - int existing_district_id = inst->district_id; - if (! district_is_complete (tile, existing_district_id)) - return false; - - bool matches = false; - for (int i = 0; i < cfg->buildable_on_district_id_count; i++) { - if (cfg->buildable_on_district_ids[i] == existing_district_id) { - matches = true; - break; - } - } - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to || cfg->has_buildable_adjacent_to_districts || cfg->has_buildable_adjacent_to_overlays) { - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - return false; - - if (cfg->has_buildable_adjacent_to) { - bool matches = false; - bool city_adjacent = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (Tile_has_city (tai.tile)) { - city_adjacent = true; - if (cfg->buildable_adjacent_to_allows_city) - matches = true; - } - if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) - matches = true; - if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) - break; - } - if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) - return false; - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to_overlays) { - bool matches = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { - matches = true; - break; - } - } - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to_districts) { - bool matches = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - struct district_instance * adj_inst = get_district_instance (tai.tile); - if (adj_inst == NULL) - continue; - int adj_district_id = adj_inst->district_id; - if (! district_is_complete (tai.tile, adj_district_id)) - continue; - for (int i = 0; i < cfg->buildable_adjacent_to_district_id_count; i++) { - if (cfg->buildable_adjacent_to_district_ids[i] == adj_district_id) { - matches = true; - break; - } - } - if (matches) - break; - } - if (! matches) - return false; - } - } - - return true; -} - -bool -is_coastal_island (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile->vtable->m35_Check_Is_Water (tile)) - return false; - - bool has_neighbor = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - return false; - - has_neighbor = true; - if (! adj->vtable->m35_Check_Is_Water (adj)) - return false; - - if (adj->vtable->m50_Get_Square_BaseType (adj) != SQ_Coast) - return false; - } - - return has_neighbor; -} - -bool -natural_wonder_adjacent_requirement_met (struct natural_wonder_district_config const * cfg, - Tile * tile, - int tile_x, - int tile_y) -{ - enum SquareTypes required = cfg->adjacent_to; - if (required == (enum SquareTypes)SQ_INVALID) - return true; - - if (required == SQ_RIVER) { - char river_bits = tile->vtable->m37_Get_River_Code (tile); - if (cfg->adjacency_dir != DIR_ZERO) { - int bit = direction_to_neighbor_bit (cfg->adjacency_dir); - if (bit < 0) - return false; - return (river_bits & (1 << bit)) != 0; - } else - return river_bits != 0; - } - - if (cfg->adjacency_dir != DIR_ZERO) { - int dx, dy; - if (! direction_to_offset (cfg->adjacency_dir, &dx, &dy)) - return false; - int nx = tile_x + dx; - int ny = tile_y + dy; - wrap_tile_coords (&p_bic_data->Map, &nx, &ny); - Tile * neighbor = tile_at (nx, ny); - return tile_square_type_is (neighbor, required); - } - - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_square_type_is (tai.tile, required)) - return true; - } - - return false; -} - -int -count_diagonal_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) -{ - if (type == (enum SquareTypes)SQ_INVALID) - return 0; - - enum direction dirs[4] = {DIR_NE, DIR_NW, DIR_SE, DIR_SW}; - int count = 0; - for (int i = 0; i < 4; i++) { - int dx, dy; - if (! direction_to_offset (dirs[i], &dx, &dy)) - continue; - int nx = tile_x + dx; - int ny = tile_y + dy; - wrap_tile_coords (&p_bic_data->Map, &nx, &ny); - Tile * neighbor = tile_at (nx, ny); - if (tile_square_type_is (neighbor, type)) - count += 1; - } - return count; -} - -int -count_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) -{ - if (type == (enum SquareTypes)SQ_INVALID) - return 0; - - int count = 0; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_square_type_is (tai.tile, type)) - count += 1; - } - return count; -} - -bool -natural_wonder_terrain_matches (struct natural_wonder_district_config const * cfg, Tile * tile, int tile_x, int tile_y) -{ - if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - if (! tile_matches_square_type (tile, cfg->terrain_type)) - return false; - - if (cfg->terrain_type == SQ_Coast) { - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - return false; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - if ((continent == NULL) || (continent->Body.TileCount <= 5)) - return false; - } - - if (is_coastal_island (tile, tile_x, tile_y)) - return false; - - if ((cfg->adjacent_to != SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 0)) - return false; - - if ((cfg->adjacent_to == SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 4)) - return false; - - if (! natural_wonder_adjacent_requirement_met (cfg, tile, tile_x, tile_y)) - return false; - - return true; -} - -struct district_worker_record * -get_tracked_worker_record (Unit * worker) -{ - if (worker == NULL) return NULL; - int civ_id = worker->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) return NULL; - - int value; - if (itable_look_up (&is->district_worker_tables[civ_id], worker->Body.ID, &value)) - return (struct district_worker_record *)value; - return NULL; -} - -struct district_worker_record * -ensure_tracked_worker_record (Unit * worker) -{ - if (worker == NULL) return NULL; - int civ_id = worker->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) return NULL; - - struct district_worker_record * rec = get_tracked_worker_record (worker); - if (rec != NULL) return rec; - - rec = (struct district_worker_record *)calloc (1, sizeof *rec); - if (rec == NULL) return NULL; - - rec->worker = worker; - rec->unit_id = worker->Body.ID; - Tile * tile = tile_at (worker->Body.X, worker->Body.Y); - rec->continent_id = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m46_Get_ContinentID (tile) : -1; - rec->pending_req = NULL; - - itable_insert (&is->district_worker_tables[civ_id], worker->Body.ID, (int)rec); - return rec; -} - -void -remove_tracked_worker_record (int civ_id, int unit_id) -{ - if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) - return; - - int value; - if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) - return; - - struct district_worker_record * rec = (struct district_worker_record *)value; - if (rec->pending_req != NULL) { - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - } - - itable_remove (&is->district_worker_tables[civ_id], unit_id); - free (rec); -} - -void -clear_tracked_worker_assignment (struct district_worker_record * rec) -{ - if (rec == NULL) - return; - - if (rec->pending_req != NULL) { - if (rec->pending_req->assigned_worker_id == rec->unit_id) - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - } -} - -void -clear_tracked_worker_assignment_by_id (int civ_id, int unit_id) -{ - if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) - return; - - int value; - if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) - return; - - struct district_worker_record * rec = (struct district_worker_record *)value; - if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == unit_id)) - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - if ((rec->worker == NULL) || (get_unit_ptr (unit_id) == NULL)) - remove_tracked_worker_record (civ_id, unit_id); -} - -void -clear_all_tracked_workers (void) -{ - for (int civ = 0; civ < 32; civ++) { - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - if (rec == NULL) - continue; - if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == rec->unit_id)) - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - free (rec); - } - is->district_worker_tables[civ].len = 0; - if (is->district_worker_tables[civ].block != NULL) { - free (is->district_worker_tables[civ].block); - is->district_worker_tables[civ].block = NULL; - } - is->district_worker_tables[civ].capacity_exponent = 0; - } -} - -bool is_worker (Unit * unit) -{ - if (unit == NULL) - return false; - - int unit_type_id = unit->Body.UnitTypeID; - int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; - - if (worker_actions == 0 || !(worker_actions & (UCV_Build_Road | UCV_Build_Mine | UCV_Irrigate))) { - return false; - } - - return true; -} - -void -update_tracked_worker_for_unit (Unit * worker) -{ - if (worker == NULL || ! is->current_config.enable_districts) return; - - int civ_id = worker->Body.CivID; - int type_id = worker->Body.UnitTypeID; - if ((civ_id < 0) || (civ_id >= 32)) return; - if ((*p_human_player_bits & (1 << civ_id)) != 0) return; - - char ss[200]; - snprintf (ss, sizeof ss, "Updating tracked worker for unit %d of type %d\n", worker->Body.ID, type_id); - (*p_OutputDebugStringA) (ss); - - if (! is_worker (worker)) { - remove_tracked_worker_record(worker->Body.CivID, worker->Body.ID); - return; - } - - ensure_tracked_worker_record (worker); -} - -bool -assign_worker_to_district (struct pending_district_request * req, Unit * worker, City * city, int district_id, int tile_x, int tile_y) -{ - if (worker == NULL || city == NULL) - return false; - if (req == NULL) - return false; - - req->city = city; - req->city_id = city->Body.ID; - req->civ_id = city->Body.CivID; - req->assigned_worker_id = worker->Body.ID; - req->worker_assigned_turn = *p_current_turn_no; - req->target_x = tile_x; - req->target_y = tile_y; - worker->Body.Auto_CityID = city->Body.ID; - - char ss[200]; - snprintf (ss, sizeof ss, "assign_worker_to_district: Assigned worker unit %d to build district %d in city %s at (%d,%d)\n", - worker->Body.ID, district_id, city->Body.CityName, tile_x, tile_y); - (*p_OutputDebugStringA) (ss); - - struct district_worker_record * record = ensure_tracked_worker_record (worker); - if (record != NULL) { - record->pending_req = req; - } - - return ai_move_district_worker (worker, record); -} - -bool -worker_is_available_for_district (Unit * worker) -{ - if (worker == NULL) - return false; - - int civ_id = worker->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) return false; - if ((*p_human_player_bits & (1 << civ_id)) != 0) return false; - - int type_id = worker->Body.UnitTypeID; - if ((type_id < 0) || (type_id >= p_bic_data->UnitTypeCount)) return false; - - struct district_worker_record * record = get_tracked_worker_record (worker); - if (record == NULL) - return false; - - return record->pending_req == NULL; -} - -Unit * -find_best_worker_for_district (Leader * leader, City * city, int district_id, int target_x, int target_y) -{ - char ss[200]; - - if ((leader == NULL) || (city == NULL)) { - snprintf (ss, sizeof ss, "Invalid leader or city when finding best worker for district %d\n", district_id); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - int civ_id = leader->ID; - if ((civ_id < 0) || (civ_id >= 32)) { - snprintf (ss, sizeof ss, "Invalid civ_id %d when finding best worker for district %d\n", civ_id, district_id); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - if (is->district_worker_tables[civ_id].len == 0) { - snprintf (ss, sizeof ss, "No tracked workers for civ %d when finding best worker for district %d\n", civ_id, district_id); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - Tile * target_tile = tile_at (target_x, target_y); - if ((target_tile == NULL) || (target_tile == p_null_tile)) { - snprintf (ss, sizeof ss, "Invalid target tile (%d,%d) when finding best worker for district %d in city %s\n", - target_x, target_y, district_id, city->Body.CityName); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - int target_continent_id = target_tile->vtable->m46_Get_ContinentID (target_tile); - Unit * best_worker = NULL; - int best_dist = INT_MAX; - - snprintf (ss, sizeof ss, "Finding best worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); - (*p_OutputDebugStringA) (ss); - - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - - if (rec == NULL) { - continue; - } - - Unit * candidate_worker = get_unit_ptr (rec->unit_id); - if ((candidate_worker == NULL) || (candidate_worker->Body.CivID != civ_id)) { - remove_tracked_worker_record (civ_id, rec->unit_id); - continue; - } - rec->worker = candidate_worker; - - if (! worker_is_available_for_district (candidate_worker)) { - continue; - } - - Tile * worker_tile = tile_at (candidate_worker->Body.X, candidate_worker->Body.Y); - if ((worker_tile == NULL) || (worker_tile == p_null_tile)) { - continue; - } - - int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); - if ((target_continent_id >= 0) && (worker_continent_id != target_continent_id)) { - continue; - } - - int dist = compute_wrapped_chebyshev_distance (candidate_worker->Body.X, candidate_worker->Body.Y, target_x, target_y); - - if (dist < best_dist) { - best_worker = candidate_worker; - best_dist = dist; - if (dist == 0) - return best_worker; - } - } - - return best_worker; -} - -void -process_pending_district_request (Leader * leader, struct pending_district_request * req) -{ - if ((leader == NULL) || (req == NULL)) - return; - - City * city = get_city_ptr (req->city_id); - if (city == NULL) { - remove_pending_district_request (req); - return; - } - req->city = city; - - int district_id = req->district_id; - int civ_id = req->civ_id; - - if (city->Body.CivID != civ_id) { - clear_city_district_request (city, district_id); - return; - } - - if (district_id < 0 || district_id >= is->district_count) return; - - // Check if city already has the district if not a neighborhood or distribution hub - if (district_id != NEIGHBORHOOD_DISTRICT_ID && - district_id != DISTRIBUTION_HUB_DISTRICT_ID && - is->district_configs[district_id].allow_multiple == false && - city_has_required_district (city, district_id)) { - - // Clear the request - clear_city_district_request (city, district_id); - return; - } - - // Assigned worker is no longer valid; clear assignment - if (req->assigned_worker_id >= 0) { - Unit * assigned = get_unit_ptr (req->assigned_worker_id); - if (assigned != NULL) { - // Check if more than allowed turns have elapsed since assignment and worker is not at target tile - bool worker_at_target = (assigned->Body.X == req->target_x) && (assigned->Body.Y == req->target_y); - if ((*p_current_turn_no - req->worker_assigned_turn) > is->current_config.ai_city_district_max_build_wait_turns && !worker_at_target) { - clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); - req->assigned_worker_id = -1; - req->worker_assigned_turn = *p_current_turn_no; - } else { - return; - } - } else { - // Assigned worker is null, make sure we get a new one - clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); - req->assigned_worker_id = -1; - } - } - - struct district_instance * inst = NULL; - int target_x = 0; - int target_y = 0; - Tile * tile = find_tile_for_district (city, district_id, &target_x, &target_y); - if ((tile == NULL) || (tile == p_null_tile)) { - clear_city_district_request (city, district_id); - return; - } - wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); - - char ss[200]; - snprintf (ss, sizeof ss, "Assigning worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); - (*p_OutputDebugStringA) (ss); - - Unit * worker = find_best_worker_for_district (leader, city, district_id, target_x, target_y); - if (worker == NULL) - return; - - snprintf (ss, sizeof ss, "Found worker %d for district %d in city %s at (%d,%d)\n", - worker->Body.ID, district_id, city->Body.CityName, target_x, target_y); - (*p_OutputDebugStringA) (ss); - - assign_worker_to_district (req, worker, city, district_id, target_x, target_y); -} - -void -assign_workers_for_pending_districts (Leader * leader) -{ - if ((leader == NULL) || ! is->current_config.enable_districts) - return; - - int civ_id = leader->ID; - if ((civ_id < 0) || (civ_id >= 32)) - return; - - if ((*p_human_player_bits & (1 << civ_id)) != 0) - return; - - int pending_count = is->city_pending_district_requests[civ_id].len; - if (pending_count <= 0) - return; - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req == NULL) - continue; - - City * city = get_city_ptr (req->city_id); - if (city == NULL) { - remove_pending_district_request (req); - continue; - } - - req->city = city; - if (city->Body.CivID != req->civ_id) { - remove_pending_district_request (req); - continue; - } - - process_pending_district_request (leader, req); - } -} - -City * -find_closest_owned_city_for_tile (int civ_id, int tile_x, int tile_y) -{ - City * best_city = NULL; - int best_dist = INT_MAX; - - FOR_CITIES_OF (coi, civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - - int dist = compute_wrapped_chebyshev_distance (city->Body.X, city->Body.Y, tile_x, tile_y); - if (dist < best_dist) { - best_dist = dist; - best_city = city; - } - } - - return best_city; -} - -bool -ai_candidate_bridge_or_canal_is_buildable_for_civ (struct ai_candidate_bridge_or_canal_entry * entry, int civ_id, int * out_tile_index) -{ - if ((entry == NULL) || (entry->tile_count <= 0)) - return false; - - int pending_index = -1; - for (int ti = 0; ti < entry->tile_count; ti++) { - int tx = entry->tile_x[ti]; - int ty = entry->tile_y[ti]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (owner != civ_id) - return false; - if (tile->CityID >= 0) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - if (inst->district_id == entry->district_id) - continue; - if (inst->district_id == WONDER_DISTRICT_ID) - return false; - if (! is->current_config.ai_can_replace_existing_districts_with_canals) { - return false; - } - } - - if (pending_index < 0) - pending_index = ti; - } - - if (pending_index < 0) { - entry->completed = true; - return false; - } - - if (out_tile_index != NULL) - *out_tile_index = pending_index; - - return true; -} - -void -release_ai_candidate_bridge_or_canal_worker (struct ai_candidate_bridge_or_canal_entry * entry) -{ - if ((entry == NULL) || (entry->assigned_worker_id < 0)) - return; - - int civ_id = entry->pending_req.civ_id; - if ((civ_id >= 0) && (civ_id < 32)) - clear_tracked_worker_assignment_by_id (civ_id, entry->assigned_worker_id); - - entry->assigned_worker_id = -1; - entry->assigned_tile_index = -1; - entry->pending_req.city = NULL; - entry->pending_req.city_id = -1; - entry->pending_req.civ_id = -1; - entry->pending_req.district_id = -1; - entry->pending_req.assigned_worker_id = -1; - entry->pending_req.target_x = -1; - entry->pending_req.target_y = -1; - entry->pending_req.worker_assigned_turn = 0; -} - -void -reset_ai_candidate_bridge_or_canals (void) -{ - if (is->ai_candidate_bridge_or_canals != NULL) { - for (int i = 0; i < is->ai_candidate_bridge_or_canals_capacity; i++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[i]; - if (entry->tile_x != NULL) - free (entry->tile_x); - if (entry->tile_y != NULL) - free (entry->tile_y); - } - free (is->ai_candidate_bridge_or_canals); - is->ai_candidate_bridge_or_canals = NULL; - } - is->ai_candidate_bridge_or_canals_capacity = 0; - is->ai_candidate_bridge_or_canals_count = 0; - is->ai_candidate_bridge_or_canals_initialized = false; -} - -bool -tile_has_district_at (int tile_x, int tile_y, int district_id) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - return (inst != NULL) && (inst->district_id == district_id) && (district_is_complete (tile, district_id)); -} - -bool -tile_is_land (int civ_id, int tile_x, int tile_y, bool must_be_same_owner) -{ - if (must_be_same_owner && (civ_id <= 0)) - return false; - - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - return (tile != NULL) && (tile != p_null_tile) && (! tile->vtable->m35_Check_Is_Water (tile)) && - ((! must_be_same_owner) || (tile->Territory_OwnerID == civ_id)); -} - -bool -tile_is_water (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - return (tile != NULL) && (tile != p_null_tile) && (tile->vtable->m35_Check_Is_Water (tile)); -} - -bool -ensure_ai_candidate_bridge_or_canals_capacity (int required) -{ - if (required <= 0) - return true; - if (required <= is->ai_candidate_bridge_or_canals_capacity) - return true; - int new_capacity = (is->ai_candidate_bridge_or_canals_capacity > 0) ? is->ai_candidate_bridge_or_canals_capacity * 2 : 4; - if (new_capacity < required) - new_capacity = required; - struct ai_candidate_bridge_or_canal_entry * larger = (struct ai_candidate_bridge_or_canal_entry *)realloc ( - is->ai_candidate_bridge_or_canals, new_capacity * sizeof *larger); - if (larger == NULL) - return false; - for (int i = is->ai_candidate_bridge_or_canals_capacity; i < new_capacity; i++) { - struct ai_candidate_bridge_or_canal_entry * entry = &larger[i]; - entry->tile_x = NULL; - entry->tile_y = NULL; - entry->tile_capacity = 0; - entry->district_id = -1; - entry->owner_civ_id = -1; - entry->tile_count = 0; - entry->assigned_tile_index = -1; - entry->assigned_worker_id = -1; - entry->completed = false; - struct pending_district_request * req = &entry->pending_req; - req->city = NULL; - req->city_id = -1; - req->civ_id = -1; - req->district_id = -1; - req->assigned_worker_id = -1; - req->target_x = -1; - req->target_y = -1; - req->worker_assigned_turn = 0; - } - is->ai_candidate_bridge_or_canals = larger; - is->ai_candidate_bridge_or_canals_capacity = new_capacity; - return true; -} - -bool -canal_has_different_adjacent_seas (int tile_x, int tile_y, int civ_id) -{ - struct water_pair { - int dx1, dy1; - int dx2, dy2; - }; - - const struct water_pair pairs[] = { - { 1, -1, -1, 1 }, // NE + SW - { 1, 1, -1, -1 }, // SE + NW - }; - - Map * map = &p_bic_data->Map; - bool require_owner = (civ_id >= 0); - - for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { - int ax = tile_x + pairs[i].dx1; - int ay = tile_y + pairs[i].dy1; - wrap_tile_coords (map, &ax, &ay); - Tile * first = tile_at (ax, ay); - if ((first == NULL) || (first == p_null_tile)) - continue; - if (! first->vtable->m35_Check_Is_Water (first)) - continue; - if (require_owner && (first->vtable->m38_Get_Territory_OwnerID (first) != civ_id)) - continue; - - int bx = tile_x + pairs[i].dx2; - int by = tile_y + pairs[i].dy2; - wrap_tile_coords (map, &bx, &by); - Tile * second = tile_at (bx, by); - if ((second == NULL) || (second == p_null_tile)) - continue; - if (! second->vtable->m35_Check_Is_Water (second)) - continue; - if (require_owner && (second->vtable->m38_Get_Territory_OwnerID (second) != civ_id)) - continue; - - int sea_a = first->vtable->m46_Get_ContinentID (first); - int sea_b = second->vtable->m46_Get_ContinentID (second); - if ((sea_a >= 0) && (sea_b >= 0) && (sea_a != sea_b)) - return true; - } - - return false; -} - -// Check if two water tiles can reach each other via water within a radius, excluding a blocked tile -bool -water_tiles_connected_within_radius (int start_x, int start_y, int target_x, int target_y, int block_x, int block_y, int radius) -{ - // Simple BFS using a fixed-size visited array for tiles within radius - // workable_tile_counts[6] = 137 tiles for radius 6 - int max_tiles = 137; - int visited_x[137]; - int visited_y[137]; - int visited_count = 0; - int queue_x[137]; - int queue_y[137]; - int queue_head = 0; - int queue_tail = 0; - - queue_x[queue_tail] = start_x; - queue_y[queue_tail] = start_y; - queue_tail++; - visited_x[visited_count] = start_x; - visited_y[visited_count] = start_y; - visited_count++; - - while (queue_head < queue_tail) { - int cx = queue_x[queue_head]; - int cy = queue_y[queue_head]; - queue_head++; - - // Check 8 adjacent tiles - FOR_TILES_AROUND (tai, 9, cx, cy) { - if (tai.n == 0) - continue; - int nx = tai.tile_x; - int ny = tai.tile_y; - - // Found target - if (nx == target_x && ny == target_y) - return true; - - // Skip blocked tile (the isthmus) - if (nx == block_x && ny == block_y) - continue; - - // Check if within radius of original start - int dx = nx - start_x; - int dy = ny - start_y; - if (dx < 0) dx = -dx; - if (dy < 0) dy = -dy; - // Use Chebyshev distance approximation for hex grid - int dist = (dx + dy + ((dx > dy) ? dx : dy)) / 2; - if (dist > radius) - continue; - - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (! adj->vtable->m35_Check_Is_Water (adj)) - continue; - - // Check if already visited - bool already_visited = false; - for (int i = 0; i < visited_count; i++) { - if (visited_x[i] == nx && visited_y[i] == ny) { - already_visited = true; - break; - } - } - if (already_visited) - continue; - - // Add to queue and visited - if (visited_count < max_tiles && queue_tail < max_tiles) { - visited_x[visited_count] = nx; - visited_y[visited_count] = ny; - visited_count++; - queue_x[queue_tail] = nx; - queue_y[queue_tail] = ny; - queue_tail++; - } - } - } - return false; -} - -// Check if tile separates adjacent water tiles that are not connected within a small radius -bool -canal_has_same_sea_isthmus (int tile_x, int tile_y, int civ_id, int check_radius) -{ - // If another canal exists nearby, this isn't a unique isthmus target. - FOR_TILES_AROUND (tai, workable_tile_counts[2], tile_x, tile_y) { - if (tai.n == 0) - continue; - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - continue; - struct district_instance * adj_inst = get_district_instance (adj); - if ((adj_inst != NULL) && (adj_inst->district_id == CANAL_DISTRICT_ID)) - return false; - } - - // Check opposite diagonal water tiles that are not connected within radius 2 - struct water_pair { - int dx1, dy1; - int dx2, dy2; - }; - - const struct water_pair pairs[] = { - { 1, -1, -1, 1 }, // NE + SW - { 1, 1, -1, -1 }, // SE + NW - }; - - for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { - int ax = tile_x + pairs[i].dx1; - int ay = tile_y + pairs[i].dy1; - wrap_tile_coords (&p_bic_data->Map, &ax, &ay); - Tile * first = tile_at (ax, ay); - if ((first == NULL) || (first == p_null_tile)) - continue; - if (! first->vtable->m35_Check_Is_Water (first)) - continue; - - int bx = tile_x + pairs[i].dx2; - int by = tile_y + pairs[i].dy2; - wrap_tile_coords (&p_bic_data->Map, &bx, &by); - Tile * second = tile_at (bx, by); - if ((second == NULL) || (second == p_null_tile)) - continue; - if (! second->vtable->m35_Check_Is_Water (second)) - continue; - - if (! water_tiles_connected_within_radius ( - ax, ay, - bx, by, - tile_x, tile_y, 2)) { - return true; - } - } - return false; -} - -bool -bridge_tile_connects_two_continents (int tile_x, int tile_y, int civ_id) -{ - struct bridge_pair { - int dx1, dy1; - int dx2, dy2; - }; - - Map * map = &p_bic_data->Map; - const struct bridge_pair pairs[] = { - {0, -2, 0, 2}, - {-2, 0, 2, 0}, - {-1, -1, 1, 1}, - {-1, 1, 1, -1}, - }; - - bool require_owner = (civ_id >= 0); - - for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { - int ax = tile_x + pairs[i].dx1; - int ay = tile_y + pairs[i].dy1; - wrap_tile_coords (map, &ax, &ay); - if (! tile_is_land (civ_id, ax, ay, require_owner)) - continue; - Tile * first = tile_at (ax, ay); - if ((first == NULL) || (first == p_null_tile)) - continue; - - int bx = tile_x + pairs[i].dx2; - int by = tile_y + pairs[i].dy2; - wrap_tile_coords (map, &bx, &by); - if (! tile_is_land (civ_id, bx, by, require_owner)) - continue; - Tile * second = tile_at (bx, by); - if ((second == NULL) || (second == p_null_tile)) - continue; - - int cont_a = first->vtable->m46_Get_ContinentID (first); - int cont_b = second->vtable->m46_Get_ContinentID (second); - if ((cont_a >= 0) && (cont_b >= 0) && (cont_a != cont_b)) - return true; - } - - return false; -} - -bool -tile_point_in_block (int tile_x, int tile_y, int block_x0, int block_y0, int block_x1, int block_y1) -{ - return (tile_x >= block_x0) && (tile_x < block_x1) && (tile_y >= block_y0) && (tile_y < block_y1); -} - -bool -tile_is_coastal_water (int tile_x, int tile_y) -{ - Map * map = &p_bic_data->Map; - wrap_tile_coords (map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - if (! tile->vtable->m35_Check_Is_Water (tile)) - return false; - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - return base_type == SQ_Coast; -} - -bool -tile_exists_at (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - return (tile != NULL) && (tile != p_null_tile); -} - -bool -tile_is_reserved_in_district_tile_map (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - int existing = 0; - return itable_look_up (&is->district_tile_map, (int)tile, &existing); -} - -bool -tile_has_diagonal_water (int tile_x, int tile_y) -{ - Map * map = &p_bic_data->Map; - int const adj_dx[4] = { 1, 1, -1, -1 }; - int const adj_dy[4] = { -1, 1, -1, 1 }; - - for (int i = 0; i < 4; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * tile = tile_at (nx, ny); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m35_Check_Is_Water (tile)) - return true; - } - return false; -} - -bool -tile_part_of_existing_candidate (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if (entry->tile_count <= 0) - continue; - for (int ti = 0; ti < entry->tile_count; ti++) { - if ((entry->tile_x[ti] == tile_x) && (entry->tile_y[ti] == tile_y)) - return true; - } - } - return false; -} - -bool -tile_has_bridge_or_canal_nearby (int tile_x, int tile_y) -{ - FOR_TILES_AROUND (tai, workable_tile_counts[1], tile_x, tile_y) { - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - continue; - struct district_instance * inst = get_district_instance (adj); - if ((inst != NULL) && - ((inst->district_id == BRIDGE_DISTRICT_ID) || (inst->district_id == CANAL_DISTRICT_ID))) - return true; - if (tile_part_of_existing_candidate (tai.tile_x, tai.tile_y)) - return true; - } - return false; -} - -bool -add_ai_candidate_entry (int district_id, short owner_civ_id, short * xs, short * ys, int count) -{ - if (count <= 0) - return false; - if (! ensure_ai_candidate_bridge_or_canals_capacity (is->ai_candidate_bridge_or_canals_count + 1)) - return false; - - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[is->ai_candidate_bridge_or_canals_count]; - entry->tile_x = (short *)malloc (sizeof *entry->tile_x * count); - entry->tile_y = (short *)malloc (sizeof *entry->tile_y * count); - if ((entry->tile_x == NULL) || (entry->tile_y == NULL)) { - if (entry->tile_x != NULL) - free (entry->tile_x); - if (entry->tile_y != NULL) - free (entry->tile_y); - return false; - } - - entry->district_id = district_id; - entry->owner_civ_id = owner_civ_id; - entry->tile_count = (short)count; - entry->tile_capacity = count; - entry->assigned_tile_index = -1; - entry->assigned_worker_id = -1; - entry->completed = false; - for (int ti = 0; ti < count; ti++) { - entry->tile_x[ti] = xs[ti]; - entry->tile_y[ti] = ys[ti]; - } - - struct pending_district_request * req = &entry->pending_req; - req->city = NULL; - req->city_id = -1; - req->civ_id = owner_civ_id; - req->district_id = district_id; - req->assigned_worker_id = -1; - req->target_x = -1; - req->target_y = -1; - req->worker_assigned_turn = 0; - - is->ai_candidate_bridge_or_canals_count++; - return true; -} - -int -find_bridge_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, - int contiguous_limit, int candidate_capacity, - short * out_x, short * out_y, short * out_owner) -{ - const int dirs[4][2] = { - { 0, -2 }, { -2, 0 }, { -1, -1 }, { -1, 1 } - }; - - int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - if (candidate_capacity > 0 && max_len > candidate_capacity) - max_len = candidate_capacity; - - for (int length = 1; length <= max_len; length++) { - for (int ti = 0; ti < map->TileCount; ti++) { - int tx = -1; - int ty = -1; - tile_index_to_coords (map, ti, &tx, &ty); - if (! tile_point_in_block (tx, ty, block_x0, block_y0, block_x1, block_y1)) - continue; - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile_has_resource (tile)) - continue; - if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], tile)) - continue; - if (tile_is_reserved_in_district_tile_map (tx, ty)) - continue; - short owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - for (int di = 0; di < (int)(sizeof (dirs) / sizeof (dirs[0])); di++) { - int dx = dirs[di][0]; - int dy = dirs[di][1]; - int end_x = tx + dx * (length - 1); - int end_y = ty + dy * (length - 1); - wrap_tile_coords (map, &end_x, &end_y); - if (! tile_point_in_block (end_x, end_y, block_x0, block_y0, block_x1, block_y1)) - continue; - - bool ok = true; - for (int step = 0; step < length; step++) { - int cx = tx + dx * step; - int cy = ty + dy * step; - wrap_tile_coords (map, &cx, &cy); - if (! tile_point_in_block (cx, cy, block_x0, block_y0, block_x1, block_y1)) { - ok = false; - break; - } - if (! tile_exists_at (cx, cy)) { - ok = false; - break; - } - if (! tile_is_coastal_water (cx, cy)) { - ok = false; - break; - } - Tile * bridge_tile = tile_at (cx, cy); - if ((bridge_tile == NULL) || (bridge_tile == p_null_tile)) { - ok = false; - break; - } - if (tile_has_resource (bridge_tile)) { - ok = false; - break; - } - if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], bridge_tile)) { - ok = false; - break; - } - if (tile_has_bridge_or_canal_nearby (cx, cy)) { - ok = false; - break; - } - if (tile_is_reserved_in_district_tile_map (cx, cy)) { - ok = false; - break; - } - if (tile_part_of_existing_candidate (cx, cy)) { - ok = false; - break; - } - } - if (! ok) - continue; - - int land_ax = tx - dx; - int land_ay = ty - dy; - wrap_tile_coords (map, &land_ax, &land_ay); - if (! tile_point_in_block (land_ax, land_ay, block_x0, block_y0, block_x1, block_y1)) - continue; - if (! tile_exists_at (land_ax, land_ay)) - continue; - if (! tile_is_land (-1, land_ax, land_ay, false)) - continue; - Tile * land_a = tile_at (land_ax, land_ay); - if ((land_a == NULL) || (land_a == p_null_tile)) - continue; - - int land_bx = tx + dx * length; - int land_by = ty + dy * length; - wrap_tile_coords (map, &land_bx, &land_by); - if (! tile_point_in_block (land_bx, land_by, block_x0, block_y0, block_x1, block_y1)) - continue; - if (! tile_exists_at (land_bx, land_by)) - continue; - if (! tile_is_land (-1, land_bx, land_by, false)) - continue; - Tile * land_b = tile_at (land_bx, land_by); - if ((land_b == NULL) || (land_b == p_null_tile)) - continue; - - int cont_a = land_a->vtable->m46_Get_ContinentID (land_a); - int cont_b = land_b->vtable->m46_Get_ContinentID (land_b); - if ((cont_a < 0) || (cont_b < 0) || (cont_a == cont_b)) - continue; - - for (int step = 0; step < length; step++) { - int cx = tx + dx * step; - int cy = ty + dy * step; - wrap_tile_coords (map, &cx, &cy); - out_x[step] = (short)cx; - out_y[step] = (short)cy; - } - *out_owner = owner; - return length; - } - } - } - return 0; -} - -int -gather_canal_line (int start_x, int start_y, int dx, int dy, int limit, - int block_x0, int block_y0, int block_x1, int block_y1, - short * out_x, short * out_y) -{ - int effective_limit = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, limit); - - if (! tile_is_land (-1, start_x, start_y, false)) - return 0; - if (tile_part_of_existing_candidate (start_x, start_y)) - return 0; - - short back_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - short back_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - short forward_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - short forward_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - int back_count = 0; - int forward_count = 0; - int remaining = effective_limit - 1; - Map * map = &p_bic_data->Map; - - int cx = start_x; - int cy = start_y; - while ((remaining > 0) && (back_count < effective_limit)) { - int nx = cx - dx; - int ny = cy - dy; - wrap_tile_coords (map, &nx, &ny); - if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) - break; - if (! tile_is_land (-1, nx, ny, false)) - break; - if (tile_part_of_existing_candidate (nx, ny)) - break; - back_x[back_count] = (short)nx; - back_y[back_count] = (short)ny; - back_count++; - remaining--; - cx = nx; - cy = ny; - } - - cx = start_x; - cy = start_y; - while ((remaining > 0) && (forward_count < effective_limit)) { - int nx = cx + dx; - int ny = cy + dy; - wrap_tile_coords (map, &nx, &ny); - if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) - break; - if (! tile_is_land (-1, nx, ny, false)) - break; - if (tile_part_of_existing_candidate (nx, ny)) - break; - forward_x[forward_count] = (short)nx; - forward_y[forward_count] = (short)ny; - forward_count++; - remaining--; - cx = nx; - cy = ny; - } - - int write = 0; - for (int bi = back_count - 1; bi >= 0; bi--) { - out_x[write] = back_x[bi]; - out_y[write] = back_y[bi]; - write++; - } - out_x[write] = (short)start_x; - out_y[write] = (short)start_y; - write++; - for (int fi = 0; fi < forward_count; fi++) { - out_x[write] = forward_x[fi]; - out_y[write] = forward_y[fi]; - write++; - } - - return write; -} - -bool -cluster_connects_two_seas_or_isthmus (short * xs, short * ys, int count) -{ - for (int i = 0; i < count; i++) { - if (canal_has_different_adjacent_seas (xs[i], ys[i], -1)) - return true; - if (canal_has_same_sea_isthmus (xs[i], ys[i], -1, 2)) - return true; - } - return false; -} - -int -find_canal_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, - int contiguous_limit, int candidate_capacity, - short * out_x, short * out_y, short * out_owner) -{ - const int dir_dx[8] = { 0, 1, 2, 1, 0, -1, -2, -1 }; - const int dir_dy[8] = { -2, -1, 0, 1, 2, 1, 0, -1 }; - - int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - if (candidate_capacity > 0 && max_len > candidate_capacity) - max_len = candidate_capacity; - - int tile_count = map->TileCount; - int * visit = (int *)malloc (sizeof (*visit) * tile_count); - int * queue_x = (int *)malloc (sizeof (*queue_x) * tile_count); - int * queue_y = (int *)malloc (sizeof (*queue_y) * tile_count); - if ((visit == NULL) || (queue_x == NULL) || (queue_y == NULL)) { - if (visit != NULL) - free (visit); - if (queue_x != NULL) - free (queue_x); - if (queue_y != NULL) - free (queue_y); - return 0; - } - for (int i = 0; i < tile_count; i++) - visit[i] = 0; - - int visit_mark = 1; - - for (int length = 1; length <= max_len; length++) { - for (int ti = 0; ti < map->TileCount; ti++) { - int start_x = -1; - int start_y = -1; - tile_index_to_coords (map, ti, &start_x, &start_y); - if (! tile_point_in_block (start_x, start_y, block_x0, block_y0, block_x1, block_y1)) - continue; - if (! tile_is_land (-1, start_x, start_y, false)) - continue; - if (tile_part_of_existing_candidate (start_x, start_y)) - continue; - if (tile_has_bridge_or_canal_nearby (start_x, start_y)) - continue; - if (tile_is_reserved_in_district_tile_map (start_x, start_y)) - continue; - Tile * start_tile = tile_at (start_x, start_y); - if ((start_tile == NULL) || (start_tile == p_null_tile)) - continue; - if (tile_has_resource (start_tile)) - continue; - if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], start_tile)) - continue; - int continent_id = start_tile->vtable->m46_Get_ContinentID (start_tile); - if (continent_id < 0) - continue; - short owner = start_tile->vtable->m38_Get_Territory_OwnerID (start_tile); - - int stack_len = 1; - int dir_stack[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - int path_dir[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - out_x[0] = (short)start_x; - out_y[0] = (short)start_y; - dir_stack[0] = -1; - path_dir[0] = -1; - - while (stack_len > 0) { - int depth = stack_len - 1; - int cx = out_x[depth]; - int cy = out_y[depth]; - - if (depth + 1 == length) { - bool endpoints_ok = false; - if (length == 1) { - int ex = out_x[0]; - int ey = out_y[0]; - bool pair_ok = false; - if (tile_is_water (ex, ey - 2) && tile_is_water (ex, ey + 2)) pair_ok = true; - if (tile_is_water (ex - 2, ey) && tile_is_water (ex + 2, ey)) pair_ok = true; - if (tile_is_water (ex - 1, ey - 1) && tile_is_water (ex + 1, ey + 1)) pair_ok = true; - if (tile_is_water (ex - 1, ey + 1) && tile_is_water (ex + 1, ey - 1)) pair_ok = true; - if (pair_ok && tile_has_diagonal_water (ex, ey)) - endpoints_ok = true; - } else { - int first_dir = path_dir[1]; - int last_dir = path_dir[length - 1]; - int sx = out_x[0]; - int sy = out_y[0]; - int ex = out_x[length - 1]; - int ey = out_y[length - 1]; - bool start_water = tile_is_water (sx - dir_dx[first_dir], sy - dir_dy[first_dir]); - bool end_water = tile_is_water (ex + dir_dx[last_dir], ey + dir_dy[last_dir]); - if (start_water && end_water && - tile_has_diagonal_water (sx, sy) && - tile_has_diagonal_water (ex, ey)) - endpoints_ok = true; - } - - bool buildable = true; - if (endpoints_ok) { - for (int pi = 0; pi < length; pi++) { - Tile * path_tile = tile_at (out_x[pi], out_y[pi]); - if ((path_tile == NULL) || (path_tile == p_null_tile) || - tile_has_resource (path_tile) || - (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], path_tile)) || - tile_is_reserved_in_district_tile_map (out_x[pi], out_y[pi])) { - buildable = false; - break; - } - if (tile_has_bridge_or_canal_nearby (out_x[pi], out_y[pi])) { - buildable = false; - break; - } - } - } else { - buildable = false; - } - - if (buildable) { - // Collect adjacent land tiles for component checks - int adj_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; - int adj_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; - int adj_count = 0; - for (int pi = 0; pi < length; pi++) { - int px = out_x[pi]; - int py = out_y[pi]; - for (int di = 0; di < 8; di++) { - int nx = px + dir_dx[di]; - int ny = py + dir_dy[di]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_is_land (-1, nx, ny, false)) - continue; - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) - continue; - bool in_path = false; - for (int pj = 0; pj < length; pj++) { - if ((out_x[pj] == nx) && (out_y[pj] == ny)) { - in_path = true; - break; - } - } - if (in_path) - continue; - bool seen = false; - for (int aj = 0; aj < adj_count; aj++) { - if ((adj_x[aj] == nx) && (adj_y[aj] == ny)) { - seen = true; - break; - } - } - if (! seen && (adj_count < (int)(sizeof (adj_x) / sizeof (adj_x[0])))) { - adj_x[adj_count] = nx; - adj_y[adj_count] = ny; - adj_count++; - } - } - } - - if (adj_count >= 2) { - int best1 = 0; - int best2 = 0; - int min_land = is->current_config.ai_canal_eval_min_bisected_land_tiles; - if (min_land < 1) - min_land = 1; - visit_mark++; - if (visit_mark == 0) { - visit_mark = 1; - for (int i = 0; i < tile_count; i++) - visit[i] = 0; - } - - for (int ai = 0; ai < adj_count; ai++) { - int aidx = tile_coords_to_index (map, adj_x[ai], adj_y[ai]); - if ((aidx < 0) || (visit[aidx] == visit_mark)) - continue; - - int comp_size = 0; - int head = 0; - int tail = 0; - visit[aidx] = visit_mark; - queue_x[tail] = adj_x[ai]; - queue_y[tail] = adj_y[ai]; - tail++; - - while (head < tail) { - int qx = queue_x[head]; - int qy = queue_y[head]; - head++; - comp_size++; - for (int di = 0; di < 8; di++) { - int nx = qx + dir_dx[di]; - int ny = qy + dir_dy[di]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_is_land (-1, nx, ny, false)) - continue; - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) - continue; - bool blocked = false; - for (int pj = 0; pj < length; pj++) { - if ((out_x[pj] == nx) && (out_y[pj] == ny)) { - blocked = true; - break; - } - } - if (blocked) - continue; - int nidx = tile_coords_to_index (map, nx, ny); - if ((nidx < 0) || (visit[nidx] == visit_mark)) - continue; - visit[nidx] = visit_mark; - queue_x[tail] = nx; - queue_y[tail] = ny; - tail++; - } - } - - if (comp_size > best1) { - best2 = best1; - best1 = comp_size; - } else if (comp_size > best2) { - best2 = comp_size; - } - } - - if ((best1 >= min_land) && (best2 >= min_land)) { - *out_owner = owner; - free (visit); - free (queue_x); - free (queue_y); - return length; - } - } - } - dir_stack[depth] = -1; - stack_len--; - continue; - } - - int next_dir = dir_stack[depth] + 1; - bool advanced = false; - while (next_dir < 8) { - int ndx = dir_dx[next_dir]; - int ndy = dir_dy[next_dir]; - int nx = cx + ndx; - int ny = cy + ndy; - wrap_tile_coords (map, &nx, &ny); - dir_stack[depth] = next_dir; - - if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) { - next_dir++; - continue; - } - if (! tile_is_land (-1, nx, ny, false)) { - next_dir++; - continue; - } - if (tile_part_of_existing_candidate (nx, ny)) { - next_dir++; - continue; - } - if (tile_is_reserved_in_district_tile_map (nx, ny)) { - next_dir++; - continue; - } - Tile * next_tile = tile_at (nx, ny); - if ((next_tile == NULL) || (next_tile == p_null_tile)) { - next_dir++; - continue; - } - if (tile_has_resource (next_tile)) { - next_dir++; - continue; - } - if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], next_tile)) { - next_dir++; - continue; - } - if (tile_has_bridge_or_canal_nearby (nx, ny)) { - next_dir++; - continue; - } - if (next_tile->vtable->m46_Get_ContinentID (next_tile) != continent_id) { - next_dir++; - continue; - } - bool dup = false; - for (int pi = 0; pi < depth + 1; pi++) { - if ((out_x[pi] == nx) && (out_y[pi] == ny)) { - dup = true; - break; - } - } - if (dup) { - next_dir++; - continue; - } - - if (depth >= 1) { - int prev_dir = dir_stack[depth - 1]; - int diff = next_dir - prev_dir; - if (diff < 0) - diff += 8; - if (diff > 4) - diff = 8 - diff; - if (diff > 1) { - next_dir++; - continue; - } - } - - out_x[depth + 1] = (short)nx; - out_y[depth + 1] = (short)ny; - dir_stack[depth + 1] = -1; - path_dir[depth + 1] = next_dir; - stack_len++; - advanced = true; - break; - } - - if (! advanced) { - dir_stack[depth] = -1; - stack_len--; - } - } - } - } - - free (visit); - free (queue_x); - free (queue_y); - return 0; -} - -void -generate_ai_bridge_candidates_by_block (Map * map, int block_size, int contiguous_limit) -{ - if ((map == NULL) || (block_size <= 0)) - return; - - int width = map->Width; - int height = map->Height; - if ((width <= 0) || (height <= 0)) - return; - - if (block_size < 1) - block_size = 1; - - int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - - short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); - short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); - if ((candidate_x == NULL) || (candidate_y == NULL)) { - if (candidate_x != NULL) - free (candidate_x); - if (candidate_y != NULL) - free (candidate_y); - return; - } - - for (int base_y = 0; base_y < height; base_y += block_size) { - int block_y1 = base_y + block_size; - if (block_y1 > height) - block_y1 = height; - for (int base_x = 0; base_x < width; base_x += block_size) { - int block_x1 = base_x + block_size; - if (block_x1 > width) - block_x1 = width; - short owner = -1; - int count = find_bridge_candidate_in_block ( - map, base_x, base_y, block_x1, block_y1, - contiguous_limit, candidate_capacity, - candidate_x, candidate_y, &owner); - if (count <= 0) - continue; - if (! add_ai_candidate_entry (BRIDGE_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { - free (candidate_x); - free (candidate_y); - return; - } - } - } - - free (candidate_x); - free (candidate_y); -} - -void -generate_ai_canal_candidates_by_block (Map * map, int block_size, int contiguous_limit) -{ - if ((map == NULL) || (block_size <= 0)) - return; - - int width = map->Width; - int height = map->Height; - if ((width <= 0) || (height <= 0)) - return; - - if (block_size < 1) - block_size = 1; - - int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - - short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); - short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); - if ((candidate_x == NULL) || (candidate_y == NULL)) { - if (candidate_x != NULL) - free (candidate_x); - if (candidate_y != NULL) - free (candidate_y); - return; - } - - for (int base_y = 0; base_y < height; base_y += block_size) { - int block_y1 = base_y + block_size; - if (block_y1 > height) - block_y1 = height; - for (int base_x = 0; base_x < width; base_x += block_size) { - int block_x1 = base_x + block_size; - if (block_x1 > width) - block_x1 = width; - short owner = -1; - int count = find_canal_candidate_in_block ( - map, base_x, base_y, block_x1, block_y1, - contiguous_limit, candidate_capacity, - candidate_x, candidate_y, &owner); - if (count <= 0) - continue; - if (! add_ai_candidate_entry (CANAL_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { - free (candidate_x); - free (candidate_y); - return; - } - } - } - - free (candidate_x); - free (candidate_y); -} - -void -generate_ai_canal_and_bridge_targets () -{ - if (is->ai_candidate_bridge_or_canals_initialized) - return; - if ((! is->current_config.enable_canal_districts) && (! is->current_config.enable_bridge_districts)) - return; - - Map * map = &p_bic_data->Map; - int width = map->Width; - int height = map->Height; - if ((width <= 0) || (height <= 0)) - return; - - int block_size = is->current_config.ai_bridge_canal_eval_block_size; - if (block_size <= 0) - block_size = 10; - - if (is->current_config.enable_bridge_districts && is->current_config.ai_builds_bridges) { - generate_ai_bridge_candidates_by_block ( - map, - block_size, - is->current_config.max_contiguous_bridge_districts); - } - - if (is->current_config.enable_canal_districts && is->current_config.ai_builds_canals) { - generate_ai_canal_candidates_by_block ( - map, - block_size, - is->current_config.max_contiguous_canal_districts); - } - - is->ai_candidate_bridge_or_canals_initialized = true; -} - -void -assign_workers_for_ai_candidate_bridge_or_canals (Leader * leader) -{ - if ((leader == NULL) || (is->ai_candidate_bridge_or_canals_count <= 0)) - return; - - int civ_id = leader->ID; - if ((*p_human_player_bits & (1 << civ_id)) != 0) - return; - - if (! leader_can_build_district (leader, CANAL_DISTRICT_ID) && ! leader_can_build_district (leader, BRIDGE_DISTRICT_ID)) - return; - - if (! is->ai_candidate_bridge_or_canals_initialized) { - reset_ai_candidate_bridge_or_canals (); - generate_ai_canal_and_bridge_targets (); - } - - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if (entry->completed) - continue; - - int district_id = entry->district_id; - if ((district_id == CANAL_DISTRICT_ID) && (! is->current_config.enable_canal_districts)) continue; - if ((district_id == BRIDGE_DISTRICT_ID) && (! is->current_config.enable_bridge_districts)) continue; - if (! leader_can_build_district (leader, district_id)) continue; - - if (entry->assigned_worker_id >= 0) { - Unit * worker = get_unit_ptr (entry->assigned_worker_id); - if (worker == NULL) { - release_ai_candidate_bridge_or_canal_worker (entry); - } else if ((entry->assigned_tile_index >= 0) && (entry->assigned_tile_index < entry->tile_count)) { - int tx = entry->tile_x[entry->assigned_tile_index]; - int ty = entry->tile_y[entry->assigned_tile_index]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - Tile * tile = tile_at (tx, ty); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && inst->district_id == district_id && district_is_complete (tile, district_id)) { - release_ai_candidate_bridge_or_canal_worker (entry); - } - } - } - if (entry->assigned_worker_id >= 0) - continue; - } - - int target_idx = -1; - if (! ai_candidate_bridge_or_canal_is_buildable_for_civ (entry, civ_id, &target_idx)) { - release_ai_candidate_bridge_or_canal_worker (entry); - continue; - } - - if (target_idx < 0) - continue; - - City * city = find_closest_owned_city_for_tile (civ_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); - if (city == NULL) - continue; - - Unit * worker = find_best_worker_for_district (leader, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); - if (worker == NULL) - continue; - - memset (&entry->pending_req, 0, sizeof entry->pending_req); - entry->pending_req.district_id = district_id; - entry->pending_req.civ_id = civ_id; - if (! assign_worker_to_district (&entry->pending_req, worker, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx])) - continue; - - entry->assigned_worker_id = worker->Body.ID; - entry->assigned_tile_index = target_idx; - } -} - -void -recompute_city_yields_with_districts (City * city) -{ - if (city == NULL) - return; - - bool prev_flag = is->distribution_hub_refresh_in_progress; - is->distribution_hub_refresh_in_progress = true; - patch_City_recompute_yields_and_happiness (city); - is->distribution_hub_refresh_in_progress = prev_flag; -} - -enum UnitStateType __fastcall -patch_City_instruct_worker (City * this, int edx, int tile_x, int tile_y, bool param_3, Unit * worker) -{ - return City_instruct_worker (this, __, tile_x, tile_y, param_3, worker); -} - -int -find_wonder_config_index_by_improvement_id (int improv_id) -{ - if (improv_id < 0) - return -1; - - char ss[200]; - - for (int wi = 0; wi < is->wonder_district_count; wi++) { - int bid = -1; - if (stable_look_up (&is->building_name_to_id, is->wonder_district_configs[wi].wonder_name, &bid) && - (bid == improv_id)) { - return wi; - } - } - - return -1; -} - -void set_wonder_built_flag (int improv_id, bool is_built); - -unsigned int -wonder_buildable_square_type_mask (struct wonder_district_config const * cfg) -{ - if (cfg == NULL) - return district_default_buildable_mask (); - - unsigned int mask = cfg->buildable_square_types_mask; - if (mask == 0) - mask = district_default_buildable_mask (); - return mask; -} - -unsigned int -wonder_buildable_mask_for_improvement (int improv_id) -{ - int windex = find_wonder_config_index_by_improvement_id (improv_id); - if (windex < 0) - return district_default_buildable_mask (); - return wonder_buildable_square_type_mask (&is->wonder_district_configs[windex]); -} - -bool -wonder_is_buildable_on_square_type (struct wonder_district_config const * cfg, Tile * tile) -{ - if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - if (! tile_matches_square_type_mask (tile, wonder_buildable_square_type_mask (cfg))) - return false; - - if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) - return false; - - if (cfg->has_buildable_adjacent_to) { - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - return false; - - bool matches = false; - bool city_adjacent = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (Tile_has_city (tai.tile)) { - city_adjacent = true; - if (cfg->buildable_adjacent_to_allows_city) - matches = true; - } - if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) - matches = true; - if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) - break; - } - if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) - return false; - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to_overlays) { - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - return false; - - bool matches = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { - matches = true; - break; - } - } - if (! matches) - return false; - } - - return true; -} - -bool -wonder_is_buildable_on_tile (Tile * tile, int wonder_improv_id) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); - if (windex < 0) - return tile_matches_square_type_mask (tile, district_default_buildable_mask ()); - - return wonder_is_buildable_on_square_type (&is->wonder_district_configs[windex], tile); -} - -bool -wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id) -{ - if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) - return false; - if ((civ_id < 0) || (civ_id >= 32)) - return false; - - int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); - if (windex < 0) - return true; - - struct wonder_district_config const * cfg = &is->wonder_district_configs[windex]; - Leader * leader = &leaders[civ_id]; - - if (cfg->has_buildable_by_civs) { - bool civ_match = false; - if (cfg->buildable_by_civ_count > 0) { - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - for (int i = 0; i < cfg->buildable_by_civ_count; i++) { - char const * civ_name = cfg->buildable_by_civs[i]; - if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; - if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; - if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; - if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; - if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; - } - } - if (! civ_match) - return false; - } - - if (cfg->has_buildable_by_civ_traits) { - if (cfg->buildable_by_civ_traits_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL || race->vtable == NULL) - return false; - bool trait_match = false; - for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { - int trait_id = cfg->buildable_by_civ_traits_ids[i]; - if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { - trait_match = true; - break; - } - } - if (! trait_match) - return false; - } - - if (cfg->has_buildable_by_civ_govs) { - if (cfg->buildable_by_civ_govs_id_count <= 0) - return false; - int gov_id = leader->GovernmentType; - bool gov_match = false; - for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { - if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { - gov_match = true; - break; - } - } - if (! gov_match) - return false; - } - - if (cfg->has_buildable_by_civ_cultures) { - if (cfg->buildable_by_civ_cultures_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - int culture_id = race->CultureGroupID; - bool culture_match = false; - for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { - if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { - culture_match = true; - break; - } - } - if (! culture_match) - return false; - } - - return true; -} - -int -get_wonder_improvement_id_from_index (int windex) -{ - if ((windex < 0) || (windex >= is->wonder_district_count)) - return -1; - - char const * wonder_name = is->wonder_district_configs[windex].wonder_name; - if ((wonder_name == NULL) || (wonder_name[0] == '\0')) - return -1; - - int improv_id; - if (stable_look_up (&is->building_name_to_id, (char *)wonder_name, &improv_id)) - return improv_id; - else - return -1; -} - -void -remember_pending_building_order (City * city, int improvement_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (improvement_id < 0)) - return; - - if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) - return; - - itable_insert (&is->city_pending_building_orders, (int)city, improvement_id); -} - -bool -look_up_pending_building_order (City * city, int * out_improv_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (out_improv_id == NULL)) - return false; - - return itable_look_up (&is->city_pending_building_orders, (int)city, out_improv_id); -} - -void -forget_pending_building_order (City * city) -{ - if (! is->current_config.enable_districts || - (city == NULL)) - return; - - itable_remove (&is->city_pending_building_orders, (int)city); -} - -bool -is_wonder_or_small_wonder_already_being_built (City * city, int improv_id) -{ - if ((city == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) - return false; - - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) - return false; - - int civ_id = city->Body.CivID; - FOR_CITIES_OF (coi, civ_id) { - City * other_city = coi.city; - if ((other_city == NULL) || (other_city == city)) - continue; - - if ((other_city->Body.Order_Type == COT_Improvement) && - (other_city->Body.Order_ID == improv_id)) - return true; - } - - return false; -} - -struct district_building_prereq_list * -get_district_building_prereq_list (int improv_id) -{ - if (improv_id < 0) - return NULL; - - int stored = 0; - if (! itable_look_up (&is->district_building_prereqs, improv_id, &stored)) - return NULL; - return (struct district_building_prereq_list *)stored; -} - -bool -district_building_prereq_list_contains (struct district_building_prereq_list * list, int district_id) -{ - if ((list == NULL) || (district_id < 0)) - return false; - for (int i = 0; i < list->count; i++) { - if (list->district_ids[i] == district_id) - return true; - } - return false; -} - -void -add_district_building_prereq (int improv_id, int district_id) -{ - if ((improv_id < 0) || (district_id < 0)) - return; - - struct district_building_prereq_list * list = get_district_building_prereq_list (improv_id); - if (list == NULL) { - list = calloc (1, sizeof *list); - if (list == NULL) - return; - list->count = 0; - itable_insert (&is->district_building_prereqs, improv_id, (int)list); - } - - if (district_building_prereq_list_contains (list, district_id)) - return; - - if (list->count >= ARRAY_LEN (list->district_ids)) - return; - - list->district_ids[list->count++] = district_id; -} - -bool -city_has_river_district (City * city, int district_id) -{ - if (city == NULL) - return false; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if (wai.district_inst->district_id != district_id) - continue; - if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) - return true; - } - return false; -} - -bool -city_has_any_prereq_district_for_improvement (City * city, - struct district_building_prereq_list * list, - bool requires_river, - bool allow_wonder_district) -{ - if ((city == NULL) || (list == NULL)) - return false; - - for (int i = 0; i < list->count; i++) { - int district_id = list->district_ids[i]; - if (district_id < 0) - continue; - if (! allow_wonder_district && district_id == WONDER_DISTRICT_ID) - continue; - if (requires_river) { - if (city_has_river_district (city, district_id)) - return true; - } else if (city_has_required_district (city, district_id)) { - return true; - } - } - return false; -} - -int -pick_missing_district_for_improvement (City * city, struct district_building_prereq_list * list) -{ - if ((list == NULL) || (list->count <= 0)) - return -1; - - int fallback = -1; - for (int i = 0; i < list->count; i++) { - int district_id = list->district_ids[i]; - if (district_id < 0) - continue; - if (fallback < 0) - fallback = district_id; - if ((city != NULL) && leader_can_build_district (&leaders[city->Body.CivID], district_id)) - return district_id; - } - return fallback; -} - - -bool -district_is_complete(Tile * tile, int district_id) -{ - if ((tile == NULL) || (tile == p_null_tile) || - (district_id < 0) || (district_id >= is->district_count)) - return false; - - bool is_natural_wonder = (district_id == NATURAL_WONDER_DISTRICT_ID); - bool districts_disabled = ! is->current_config.enable_districts; - bool natural_wonders_disabled = ! is->current_config.enable_natural_wonders; - struct district_config const * cfg = &is->district_configs[district_id]; - - if (districts_disabled && (!is_natural_wonder || natural_wonders_disabled)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != district_id) - return false; - - // If already marked COMPLETED, just return true - if (inst->state == DS_COMPLETED) - return true; - - // State is UNDER_CONSTRUCTION - check if tile has mines now - bool has_mines = tile->vtable->m18_Check_Mines (tile, __, 0) != 0; - - if (! has_mines) { - // Still under construction - check if we should clean it up - bool worker_present = false; - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit != NULL) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { - worker_present = true; - break; - } - } - if (! worker_present) { - remove_district_instance (tile); - } - return false; - } - - // Mark as completed and run one-time side effects - inst->state = DS_COMPLETED; - inst->completed_turn = *p_current_turn_no; - - int tile_x, tile_y; - if (district_instance_get_coords (inst, tile, &tile_x, &tile_y)) { - set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - if (cfg->auto_add_road) { - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - if (! has_road) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_ROAD, tile_x, tile_y); - } - - if (cfg->auto_add_railroad) { - bool has_railroad = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; - if (! has_railroad) { - if ((territory_owner >= 0) && patch_Leader_can_do_worker_job (&leaders[territory_owner], __, WJ_Build_Railroad, tile_x, tile_y, 0)) { - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_RAILROAD, tile_x, tile_y); - } - } - } - - // Activate distribution hub if applicable - if (is->current_config.enable_distribution_hub_districts && - (district_id == DISTRIBUTION_HUB_DISTRICT_ID)) { - on_distribution_hub_completed (tile, tile_x, tile_y); - } - - // Remove forest/swamp if applicable - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - if ((base_type == SQ_Forest) || (base_type == SQ_Swamp)) { - int new_terrain_type = tile->vtable->m71_Check_Worker_Job (tile); - if (new_terrain_type >= 0) - Map_change_tile_terrain (&p_bic_data->Map, __, (enum SquareTypes)new_terrain_type, tile_x, tile_y); - } - - char ss[200]; - snprintf (ss, sizeof ss, "District %d completed at tile (%d,%d)\n", district_id, tile_x, tile_y); - (*p_OutputDebugStringA) (ss); - - // Check if this was an AI-requested district - struct pending_district_request * req = find_pending_district_request_by_coords (NULL, tile_x, tile_y, district_id); - if (req != NULL) { - City * requesting_city = get_city_ptr (req->city_id); - if (requesting_city != NULL) { - req->city = requesting_city; - snprintf (ss, sizeof ss, "District %d at tile (%d,%d) was ordered by city %s\n", - district_id, tile_x, tile_y, requesting_city->Body.CityName); - (*p_OutputDebugStringA) (ss); - - // Check if city has pending building order that depends on this district - int pending_improv_id; - if (look_up_pending_building_order (requesting_city, &pending_improv_id)) { - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (pending_improv_id); - if (district_building_prereq_list_contains (prereq_list, district_id)) { - snprintf (ss, sizeof ss, "City %s setting production to improvement %d\n", - requesting_city->Body.CityName, pending_improv_id); - (*p_OutputDebugStringA) (ss); - - // Check if another city is already building this wonder/small wonder - bool can_set_production = true; - if (is_wonder_or_small_wonder_already_being_built (requesting_city, pending_improv_id)) { - snprintf (ss, sizeof ss, "City %s cannot build improvement %d - already being built elsewhere\n", - requesting_city->Body.CityName, pending_improv_id); - (*p_OutputDebugStringA) (ss); - can_set_production = false; - } - - // Set city production to the pending improvement - if (can_set_production && City_can_build_improvement (requesting_city, __, pending_improv_id, false)) { - snprintf (ss, sizeof ss, "City %s can now build improvement %d\n", - requesting_city->Body.CityName, pending_improv_id); - (*p_OutputDebugStringA) (ss); - City_set_production (requesting_city, __, COT_Improvement, pending_improv_id, false); - } - - // Clear the pending building order - forget_pending_building_order (requesting_city); - } - } - - // Clear worker assignment so worker is freed up for other tasks - if (req->assigned_worker_id >= 0) { - snprintf (ss, sizeof ss, "Clearing worker assignment for unit %d\n", req->assigned_worker_id); - (*p_OutputDebugStringA) (ss); - int civ_id = req->civ_id; - clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); - } - } - - // Remove the pending district request - remove_pending_district_request (req); - } - } - - return true; -} - -void -mark_city_needs_district (City * city, int district_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (district_id < 0) || (district_id >= is->district_count)) - return; - - create_pending_district_request (city, district_id); -} - -void -set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return; - - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - - City * assigned_city = NULL; - int assigned_city_id = tile->Body.CityAreaID; - if (assigned_city_id >= 0) - assigned_city = get_city_ptr (assigned_city_id); - - if (assigned_city != NULL) { - int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, - assigned_city->Body.X, assigned_city->Body.Y, tile_x, tile_y, 1000); - bool removed_assignment = false; - if ((neighbor_index > 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) - removed_assignment = City_stop_working_tile (assigned_city, __, neighbor_index); - if (! removed_assignment) - tile->Body.CityAreaID = -1; - if (! removed_assignment) - recompute_city_yields_with_districts (assigned_city); - } else - tile->Body.CityAreaID = -1; - - if (p_cities->Cities != NULL) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city == NULL) || (city == assigned_city)) - continue; - int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, - city->Body.X, city->Body.Y, tile_x, tile_y, 1000); - if ((neighbor_index <= 0) || (neighbor_index >= ARRAY_LEN (is->ni_to_work_radius))) - continue; - int work_radius = is->ni_to_work_radius[neighbor_index]; - if ((work_radius < 0) || (work_radius > is->current_config.city_work_radius)) - continue; - recompute_city_yields_with_districts (city); - } - } -} - -struct distribution_hub_record * -get_distribution_hub_record (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - - int stored; - if (itable_look_up (&is->distribution_hub_records, (int)tile, &stored)) - return (struct distribution_hub_record *)stored; - else - return NULL; -} - -City * -get_connected_city_for_distribution_hub (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return NULL; - - Tile * tile = rec->tile; - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - - City * best_city = NULL; - int best_distance = INT_MAX; - int best_y = INT_MAX; - int best_x = INT_MAX; - int best_id = INT_MAX; - - FOR_CITIES_OF (coi, rec->civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, city, rec->tile_x, rec->tile_y)) - continue; - - int distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, city->Body.X, city->Body.Y); - if ((best_city == NULL) || - (distance < best_distance) || - ((distance == best_distance) && (city->Body.Y < best_y)) || - ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X < best_x)) || - ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X == best_x) && (city->Body.ID < best_id))) { - best_city = city; - best_distance = distance; - best_y = city->Body.Y; - best_x = city->Body.X; - best_id = city->Body.ID; - } - } - - return best_city; -} - -bool -distribution_hub_accessible_to_city (struct distribution_hub_record * rec, City * city) -{ - if ((rec == NULL) || (city == NULL)) - return false; - - if (city->Body.CivID != rec->civ_id) - return false; - - City * anchor_city = get_connected_city_for_distribution_hub (rec); - if (anchor_city == NULL) - return false; - - if (anchor_city == city) - return true; - - return Trade_Net_have_trade_connection (is->trade_net, __, anchor_city, city, rec->civ_id); -} - -void -get_distribution_hub_yields_for_city (City * city, int * out_food, int * out_shields) -{ - int food = 0; - int shields = 0; - - if ((city != NULL) && - is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts) { - if (is->distribution_hub_totals_dirty && - ! is->distribution_hub_refresh_in_progress) - recompute_distribution_hub_totals (); - - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (distribution_hub_accessible_to_city (rec, city)) { - food += rec->food_yield; - shields += rec->shield_yield; - } - } - } - - if (city_has_required_district (city, CENTRAL_RAIL_HUB_DISTRICT_ID)) { - food += (food * is->current_config.central_rail_hub_distribution_food_bonus_percent) / 100; - shields += (shields * is->current_config.central_rail_hub_distribution_shield_bonus_percent) / 100; - } - - if (out_food != NULL) - *out_food = food; - if (out_shields != NULL) - *out_shields = shields; -} - -void -adjust_distribution_hub_coverage (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return; - - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if ((area_tile == NULL) || (area_tile == p_null_tile)) - continue; - int tx = tai.tile_x; - int ty = tai.tile_y; - - if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) - continue; - if (Tile_has_city (area_tile)) - continue; - if (get_district_instance (area_tile) != NULL) - continue; - - struct wonder_district_info * area_info = get_wonder_district_info (area_tile); - if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) - continue; - - int key = (int)area_tile; - int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); - itable_insert (&is->distribution_hub_coverage_counts, key, prev + 1); - - if (area_tile->Body.CityAreaID >= 0) { - set_tile_unworkable_for_all_cities (area_tile, tx, ty); - area_tile->Body.CityAreaID = -1; - } - } -} - -void -release_distribution_hub_coverage (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return; - - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if ((area_tile == NULL) || (area_tile == p_null_tile)) - continue; - - int key = (int)area_tile; - int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); - if (prev <= 0) - continue; - - if (prev == 1) - itable_remove (&is->distribution_hub_coverage_counts, key); - else - itable_insert (&is->distribution_hub_coverage_counts, key, prev - 1); - } -} - -void -clear_distribution_hub_tables (void) -{ - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - free (rec); - } - table_deinit (&is->distribution_hub_records); - table_deinit (&is->distribution_hub_coverage_counts); - is->distribution_hub_totals_dirty = true; -} - -bool -city_radius_contains_tile (City * city, int tile_x, int tile_y) -{ - if (city == NULL) - return false; - - int ni = patch_Map_compute_ni_for_work_area (&p_bic_data->Map, __, city->Body.X, city->Body.Y, tile_x, tile_y, is->workable_tile_count); - return ni >= 0; -} - -void -recompute_distribution_hub_yields (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return; - - Tile * tile = tile_at (rec->tile_x, rec->tile_y); - rec->tile = tile; - - if ((tile == NULL) || - (tile == p_null_tile) || - ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID) || - tile->vtable->m20_Check_Pollution (tile, __, 0) || - tile_has_enemy_unit (tile, rec->civ_id)) { - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - return; - } - - int food_sum = 0; - int shield_sum = 0; - City * anchor_city = get_connected_city_for_distribution_hub (rec); - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if (area_tile == p_null_tile) - continue; - int tx = tai.tile_x; - int ty = tai.tile_y; - - // Only include tiles that belong to the distribution hub owner - if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) - continue; - - // Skip city tiles - if (Tile_has_city (area_tile)) - continue; - - // Skip tiles with enemy units - if (tile_has_enemy_unit (area_tile, rec->civ_id)) - continue; - - // Skip tiles with pollution - if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) - continue; - - // Skip tiles that are other districts (but not this hub itself) - struct district_instance * area_district = get_district_instance (area_tile); - if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) - continue; - - // Skip tiles with completed wonders - struct wonder_district_info * area_info = get_wonder_district_info (area_tile); - if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) - continue; - - // Check if another hub of the same civ is closer to this tile - int my_distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, tx, ty); - bool tile_belongs_to_me = true; - - FOR_TABLE_ENTRIES (other_tei, &is->distribution_hub_records) { - struct distribution_hub_record * other_rec = (struct distribution_hub_record *)other_tei.value; - if ((other_rec == NULL) || (other_rec == rec)) - continue; - if (other_rec->civ_id != rec->civ_id) - continue; - - int other_distance = compute_wrapped_manhattan_distance (other_rec->tile_x, other_rec->tile_y, tx, ty); - if (other_distance < my_distance) { - tile_belongs_to_me = false; - break; - } - if (other_distance == my_distance) { - // Tie-breaking: prefer hub with lower Y, then lower X - if (other_rec->tile_y < rec->tile_y) { - tile_belongs_to_me = false; - break; - } - if ((other_rec->tile_y == rec->tile_y) && (other_rec->tile_x < rec->tile_x)) { - tile_belongs_to_me = false; - break; - } - } - } - - if (! tile_belongs_to_me) - continue; - - food_sum += City_calc_tile_yield_at (anchor_city, __, 0, tx, ty); - shield_sum += City_calc_tile_yield_at (anchor_city, __, 1, tx, ty); - } - - rec->raw_food_yield = food_sum; - rec->raw_shield_yield = shield_sum; - - int food_div = is->current_config.distribution_hub_food_yield_divisor; - int shield_div = is->current_config.distribution_hub_shield_yield_divisor; - if (food_div <= 0) - food_div = 1; - if (shield_div <= 0) - shield_div = 1; - - int connected_city_count = 0; - if (anchor_city != NULL) { - FOR_CITIES_OF (coi, rec->civ_id) { - City * other_city = coi.city; - if ((other_city != NULL) && distribution_hub_accessible_to_city (rec, other_city)) - connected_city_count++; - } - } - if (connected_city_count <= 0) - connected_city_count = 1; - - if (is->current_config.distribution_hub_yield_division_mode == DHYDM_SCALE_BY_CITY_COUNT) { - int city_root = 1; - while ((city_root + 1) * (city_root + 1) <= connected_city_count) - city_root++; - int city_food_divisor = city_root * food_div; - int city_shield_divisor = city_root * shield_div; - if (city_food_divisor < 1) city_food_divisor = 1; - if (city_shield_divisor < 1) city_shield_divisor = 1; - rec->food_yield = food_sum / city_food_divisor; - rec->shield_yield = shield_sum / city_shield_divisor; - } else { - rec->food_yield = food_sum / food_div; - rec->shield_yield = shield_sum / shield_div; - } -} - -void -remove_distribution_hub_record (Tile * tile) -{ - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec == NULL) - return; - - int affected_civ_id = rec->civ_id; - release_distribution_hub_coverage (rec); - itable_remove (&is->distribution_hub_records, (int)tile); - free (rec); - is->distribution_hub_totals_dirty = true; - recompute_distribution_hub_totals (); - - // Recalculate yields for all cities of this civ - if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * target_city = get_city_ptr (city_index); - if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) - recompute_city_yields_with_districts (target_city); - } - } -} - -void -recompute_distribution_hub_totals () -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_distribution_hub_districts) { - is->distribution_hub_totals_dirty = false; - return; - } - - struct table new_coverage_counts = {0}; - struct table newly_covered_tiles = {0}; - - clear_memo (); - int civs_needing_recalc[32] = {0}; - - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - Tile * tile = (Tile *)tei.key; - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (rec == NULL) - continue; - - Tile * current_tile = tile_at (rec->tile_x, rec->tile_y); - if ((current_tile == NULL) || - (current_tile == p_null_tile) || - ! district_is_complete (current_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { - memoize (tei.key); - continue; - } - - rec->tile = current_tile; - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - - int old_civ_id = rec->civ_id; - rec->civ_id = current_tile->vtable->m38_Get_Territory_OwnerID (current_tile); - - if (old_civ_id != rec->civ_id) - civs_needing_recalc[old_civ_id] = 1; - civs_needing_recalc[rec->civ_id] = 1; - - City * anchor = get_connected_city_for_distribution_hub (rec); - - if ((anchor == NULL) || - current_tile->vtable->m20_Check_Pollution (current_tile, __, 0) || - tile_has_enemy_unit (current_tile, rec->civ_id)) - continue; - - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if (area_tile == p_null_tile) - continue; - int tx = tai.tile_x; - int ty = tai.tile_y; - - if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) - continue; - if (Tile_has_city (area_tile)) - continue; - if (tile_has_enemy_unit (area_tile, rec->civ_id)) - continue; - if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) - continue; - - struct district_instance * area_district = get_district_instance (area_tile); - if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) - continue; - - struct wonder_district_info * area_info = get_wonder_district_info (area_tile); - if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) - continue; - - int key = (int)area_tile; - int prev_cover_pass = itable_look_up_or (&new_coverage_counts, key, 0); - int prev_cover_old = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); - itable_insert (&new_coverage_counts, key, prev_cover_pass + 1); - if ((prev_cover_pass == 0) && (prev_cover_old <= 0)) - itable_insert (&newly_covered_tiles, key, 1); - } - } - - for (int i = 0; i < is->memo_len; i++) - remove_distribution_hub_record ((Tile *)is->memo[i]); - clear_memo (); - - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (rec == NULL) - continue; - - City * anchor = get_connected_city_for_distribution_hub (rec); - if (anchor == NULL) { - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - continue; - } - - recompute_distribution_hub_yields (rec); - } - - table_deinit (&is->distribution_hub_coverage_counts); - is->distribution_hub_coverage_counts = new_coverage_counts; - memset (&new_coverage_counts, 0, sizeof new_coverage_counts); - - FOR_TABLE_ENTRIES (tei, &newly_covered_tiles) { - Tile * covered_tile = (Tile *)tei.key; - if ((covered_tile == NULL) || (covered_tile == p_null_tile)) - continue; - int tx, ty; - if (! tile_coords_from_ptr (&p_bic_data->Map, covered_tile, &tx, &ty)) - continue; - set_tile_unworkable_for_all_cities (covered_tile, tx, ty); - covered_tile->Body.CityAreaID = -1; - } - table_deinit (&newly_covered_tiles); - - // Recalculate yields for cities of civs whose distribution hub ownership changed - for (int civ_id = 0; civ_id < 32; civ_id++) { - if (civs_needing_recalc[civ_id] && (p_cities->Cities != NULL)) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city != NULL) && (city->Body.CivID == civ_id)) - recompute_city_yields_with_districts (city); - } - } - } - - is->distribution_hub_totals_dirty = false; -} - -void -on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y) -{ - if (! is->current_config.enable_districts || ! is->current_config.enable_distribution_hub_districts) - return; - - int tile_owner = -1; - if ((tile != NULL) && (tile != p_null_tile)) - tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec != NULL) { - int old_civ_id = rec->civ_id; - rec->tile = tile; - rec->tile_x = tile_x; - rec->tile_y = tile_y; - - release_distribution_hub_coverage (rec); - rec->civ_id = tile_owner; - is->distribution_hub_totals_dirty = true; - recompute_distribution_hub_totals (); - - if (old_civ_id != tile_owner) { - // Recompute for old civ - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * target_city = get_city_ptr (city_index); - if ((target_city != NULL) && (target_city->Body.CivID == old_civ_id)) - recompute_city_yields_with_districts (target_city); - } - } - } - - rec = malloc (sizeof *rec); - if (rec == NULL) - return; - rec->tile = tile; - rec->tile_x = tile_x; - rec->tile_y = tile_y; - rec->civ_id = tile_owner; - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - itable_insert (&is->distribution_hub_records, (int)tile, (int)rec); - adjust_distribution_hub_coverage (rec); - - is->distribution_hub_totals_dirty = true; - recompute_distribution_hub_totals (); - - // Recalculate yields for all cities of this civ - int affected_civ_id = rec->civ_id; - if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * target_city = get_city_ptr (city_index); - if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) - recompute_city_yields_with_districts (target_city); - } - } -} - -void -refresh_distribution_hubs_for_city (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_distribution_hub_districts || - (city == NULL)) - return; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int tx = wai.tile_x, ty = wai.tile_y; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID) - continue; - on_distribution_hub_completed (tile, tx, ty); - } -} - -bool -is_space_char (char c) -{ - switch (c) { - case ' ': - case '\t': - case '\n': - case '\r': - case '\f': - case '\v': - return true; - default: - return false; - } -} - -enum key_value_parse_status { - KVP_SUCCESS, - KVP_NO_EQUALS, - KVP_EMPTY_KEY -}; - -enum key_value_parse_status -parse_trimmed_key_value (struct string_slice const * trimmed, - struct string_slice * out_key, - struct string_slice * out_value) -{ - if ((trimmed == NULL) || (trimmed->len <= 0)) - return KVP_NO_EQUALS; - - char * equals = NULL; - for (int i = 0; i < trimmed->len; i++) { - if (trimmed->str[i] == '=') { - equals = trimmed->str + i; - break; - } - } - if (equals == NULL) - return KVP_NO_EQUALS; - - struct string_slice key = { .str = trimmed->str, .len = (int)(equals - trimmed->str) }; - key = trim_string_slice (&key, 0); - if (key.len == 0) - return KVP_EMPTY_KEY; - - struct string_slice value = { .str = equals + 1, .len = (int)((trimmed->str + trimmed->len) - (equals + 1)) }; - *out_key = key; - *out_value = trim_string_slice (&value, 0); - return KVP_SUCCESS; -} - -void -add_key_parse_error (struct error_line ** parse_errors, - int line_number, - struct string_slice const * key, - struct string_slice const * value, - char const * message_suffix) -{ - struct error_line * err = add_error_line (parse_errors); - char * key_str = extract_slice (key); - char * value_str = (value != NULL) ? extract_slice (value) : NULL; - if (value_str != NULL) - snprintf (err->text, sizeof err->text, "^ Line %d: %s \"%s\" %s", line_number, key_str, value_str, message_suffix); - else - snprintf (err->text, sizeof err->text, "^ Line %d: %s %s", line_number, key_str, message_suffix); - err->text[(sizeof err->text) - 1] = '\0'; - if (value_str != NULL) - free (value_str); - free (key_str); -} - -void -add_unrecognized_key_error (struct error_line ** unrecognized_keys, - int line_number, - struct string_slice const * key) -{ - struct error_line * err_line = add_error_line (unrecognized_keys); - char * key_str = extract_slice (key); - snprintf (err_line->text, sizeof err_line->text, "^ Line %d: %s", line_number, key_str); - err_line->text[(sizeof err_line->text) - 1] = '\0'; - free (key_str); -} - -char * -copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes) -{ - struct string_slice trimmed = trim_string_slice (slice, remove_quotes); - if (trimmed.len == 0) - return NULL; - return extract_slice (&trimmed); -} - -void -free_bonus_entry_list (struct district_bonus_list * list) -{ - if (list == NULL) - return; - - for (int i = 0; i < list->count; i++) { - if (list->entries[i].type == DBET_BUILDING && - list->entries[i].building_name != NULL) { - free ((void *)list->entries[i].building_name); - list->entries[i].building_name = NULL; - } - } - list->count = 0; -} - -void -free_bonus_entry_list_override (struct district_bonus_list * list, - struct district_bonus_list const * defaults) -{ - if (list == NULL) - return; - - for (int i = 0; i < list->count; i++) { - if (list->entries[i].type == DBET_BUILDING && - list->entries[i].building_name != NULL) { - char const * default_name = NULL; - if ((defaults != NULL) && (i < defaults->count)) - default_name = defaults->entries[i].building_name; - if (list->entries[i].building_name != default_name) - free ((void *)list->entries[i].building_name); - list->entries[i].building_name = NULL; - } - } - list->count = (defaults != NULL) ? defaults->count : 0; -} - -void -move_bonus_entry_list (struct district_bonus_list * dest, - struct district_bonus_list * src) -{ - if ((dest == NULL) || (src == NULL)) - return; - - dest->count = src->count; - for (int i = 0; i < src->count; i++) { - dest->entries[i] = src->entries[i]; - src->entries[i].building_name = NULL; - } - src->count = 0; -} - -void -free_dynamic_district_config (struct district_config * cfg) -{ - if (cfg == NULL) - return; - - if (! cfg->is_dynamic) - return; - - char const * name_ptr = cfg->name; - if (cfg->name != NULL) { - free ((void *)cfg->name); - cfg->name = NULL; - } - if ((cfg->display_name != NULL) && - (cfg->display_name != name_ptr)) { - free ((void *)cfg->display_name); - cfg->display_name = NULL; - } - if (cfg->tooltip != NULL) { - free ((void *)cfg->tooltip); - cfg->tooltip = NULL; - } - for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { - if (cfg->advance_prereqs[i] != NULL) { - free ((void *)cfg->advance_prereqs[i]); - cfg->advance_prereqs[i] = NULL; - } - } - cfg->advance_prereq_count = 0; - if (cfg->obsoleted_by != NULL) { - free ((void *)cfg->obsoleted_by); - cfg->obsoleted_by = NULL; - } - - for (int i = 0; i < 5; i++) { - if (cfg->resource_prereqs[i] != NULL) { - free ((void *)cfg->resource_prereqs[i]); - cfg->resource_prereqs[i] = NULL; - } - } - - if (cfg->resource_prereq_on_tile != NULL) { - free ((void *)cfg->resource_prereq_on_tile); - cfg->resource_prereq_on_tile = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { - if (cfg->wonder_prereqs[i] != NULL) { - free ((void *)cfg->wonder_prereqs[i]); - cfg->wonder_prereqs[i] = NULL; - } - } - cfg->wonder_prereq_count = 0; - - for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { - if (cfg->natural_wonder_prereqs[i] != NULL) { - free ((void *)cfg->natural_wonder_prereqs[i]); - cfg->natural_wonder_prereqs[i] = NULL; - } - } - cfg->natural_wonder_prereq_count = 0; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { - if (cfg->buildable_on_districts[i] != NULL) { - free ((void *)cfg->buildable_on_districts[i]); - cfg->buildable_on_districts[i] = NULL; - } - } - cfg->buildable_on_district_count = 0; - cfg->buildable_on_district_id_count = 0; - cfg->has_buildable_on_districts = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { - if (cfg->buildable_adjacent_to_districts[i] != NULL) { - free ((void *)cfg->buildable_adjacent_to_districts[i]); - cfg->buildable_adjacent_to_districts[i] = NULL; - } - } - cfg->buildable_adjacent_to_district_count = 0; - cfg->buildable_adjacent_to_district_id_count = 0; - cfg->has_buildable_adjacent_to = false; - cfg->has_buildable_adjacent_to_districts = false; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - if (cfg->buildable_by_civs[i] != NULL) { - free ((void *)cfg->buildable_by_civs[i]); - cfg->buildable_by_civs[i] = NULL; - } - } - cfg->buildable_by_civ_count = 0; - cfg->has_buildable_by_civs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) - cfg->buildable_by_civ_traits_ids[i] = -1; - cfg->buildable_by_civ_traits_id_count = 0; - cfg->has_buildable_by_civ_traits = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) - cfg->buildable_by_civ_govs_ids[i] = -1; - cfg->buildable_by_civ_govs_id_count = 0; - cfg->has_buildable_by_civ_govs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) - cfg->buildable_by_civ_cultures_ids[i] = -1; - cfg->buildable_by_civ_cultures_id_count = 0; - cfg->has_buildable_by_civ_cultures = false; - - for (int i = 0; i < 5; i++) { - if (cfg->dependent_improvements[i] != NULL) { - free ((void *)cfg->dependent_improvements[i]); - cfg->dependent_improvements[i] = NULL; - } - } - - for (int i = 0; i < 10; i++) { - if (cfg->img_paths[i] != NULL) { - free ((void *)cfg->img_paths[i]); - cfg->img_paths[i] = NULL; - } - } - - free_bonus_entry_list (&cfg->culture_bonus_extras); - free_bonus_entry_list (&cfg->science_bonus_extras); - free_bonus_entry_list (&cfg->food_bonus_extras); - free_bonus_entry_list (&cfg->gold_bonus_extras); - free_bonus_entry_list (&cfg->shield_bonus_extras); - free_bonus_entry_list (&cfg->happiness_bonus_extras); - free_bonus_entry_list (&cfg->defense_bonus_extras); - - memset (cfg, 0, sizeof *cfg); -} - -void -free_dynamic_wonder_config (struct wonder_district_config * cfg) -{ - if (cfg == NULL) - return; - - if (! cfg->is_dynamic) - return; - - if (cfg->wonder_name != NULL) { - free ((void *)cfg->wonder_name); - cfg->wonder_name = NULL; - } - - if (cfg->img_path != NULL) { - free ((void *)cfg->img_path); - cfg->img_path = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - if (cfg->buildable_by_civs[i] != NULL) { - free ((void *)cfg->buildable_by_civs[i]); - cfg->buildable_by_civs[i] = NULL; - } - } - cfg->buildable_by_civ_count = 0; - cfg->has_buildable_by_civs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) - cfg->buildable_by_civ_traits_ids[i] = -1; - cfg->buildable_by_civ_traits_id_count = 0; - cfg->has_buildable_by_civ_traits = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) - cfg->buildable_by_civ_govs_ids[i] = -1; - cfg->buildable_by_civ_govs_id_count = 0; - cfg->has_buildable_by_civ_govs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) - cfg->buildable_by_civ_cultures_ids[i] = -1; - cfg->buildable_by_civ_cultures_id_count = 0; - cfg->has_buildable_by_civ_cultures = false; - - memset (cfg, 0, sizeof *cfg); -} - -void -free_dynamic_natural_wonder_config (struct natural_wonder_district_config * cfg) -{ - if (cfg == NULL) - return; - - if (! cfg->is_dynamic) - return; - - if (cfg->name != NULL) { - free ((void *)cfg->name); - cfg->name = NULL; - } - - if (cfg->img_path != NULL) { - free ((void *)cfg->img_path); - cfg->img_path = NULL; - } - - memset (cfg, 0, sizeof *cfg); - cfg->adjacent_to = (enum SquareTypes)SQ_INVALID; - cfg->adjacency_dir = DIR_ZERO; -} - -enum Unit_Command_Values -allocate_dynamic_district_command (char const * name) -{ - int offset = is->next_custom_dynamic_command_index; - is->next_custom_dynamic_command_index += 1; - int value = C3X_DISTRICT_COMMAND_BASE - (offset + 1); - return (enum Unit_Command_Values)value; -} - -void -free_special_district_override_strings (struct district_config * cfg, struct district_config const * defaults) -{ - if (cfg == NULL || defaults == NULL) - return; - - if ((cfg->display_name != NULL) && - (cfg->display_name != cfg->name) && - (cfg->display_name != defaults->display_name)) { - free ((void *)cfg->display_name); - cfg->display_name = NULL; - } - if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) { - free ((void *)cfg->tooltip); - cfg->tooltip = NULL; - } - for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { - char const * default_value = (defaults != NULL && i < defaults->advance_prereq_count) - ? defaults->advance_prereqs[i] - : NULL; - if ((cfg->advance_prereqs[i] != NULL) && - (cfg->advance_prereqs[i] != default_value)) { - free ((void *)cfg->advance_prereqs[i]); - } - cfg->advance_prereqs[i] = NULL; - } - cfg->advance_prereq_count = 0; - if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) { - free ((void *)cfg->obsoleted_by); - cfg->obsoleted_by = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { - char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; - if ((cfg->resource_prereqs[i] != NULL) && - (cfg->resource_prereqs[i] != default_value)) - free ((void *)cfg->resource_prereqs[i]); - cfg->resource_prereqs[i] = NULL; - } - cfg->resource_prereq_count = defaults->resource_prereq_count; - - if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) { - free ((void *)cfg->resource_prereq_on_tile); - cfg->resource_prereq_on_tile = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { - char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; - if ((cfg->wonder_prereqs[i] != NULL) && - (cfg->wonder_prereqs[i] != default_value)) - free ((void *)cfg->wonder_prereqs[i]); - cfg->wonder_prereqs[i] = NULL; - } - cfg->wonder_prereq_count = defaults->wonder_prereq_count; - - for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { - char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; - if ((cfg->natural_wonder_prereqs[i] != NULL) && - (cfg->natural_wonder_prereqs[i] != default_value)) - free ((void *)cfg->natural_wonder_prereqs[i]); - cfg->natural_wonder_prereqs[i] = NULL; - } - cfg->natural_wonder_prereq_count = defaults->natural_wonder_prereq_count; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { - char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; - if ((cfg->buildable_on_districts[i] != NULL) && - (cfg->buildable_on_districts[i] != default_value)) { - free ((void *)cfg->buildable_on_districts[i]); - } - cfg->buildable_on_districts[i] = NULL; - } - cfg->buildable_on_district_count = defaults->buildable_on_district_count; - cfg->buildable_on_district_id_count = defaults->buildable_on_district_id_count; - cfg->has_buildable_on_districts = defaults->has_buildable_on_districts; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { - char const * default_value = (i < defaults->buildable_adjacent_to_district_count) - ? defaults->buildable_adjacent_to_districts[i] - : NULL; - if ((cfg->buildable_adjacent_to_districts[i] != NULL) && - (cfg->buildable_adjacent_to_districts[i] != default_value)) { - free ((void *)cfg->buildable_adjacent_to_districts[i]); - } - cfg->buildable_adjacent_to_districts[i] = NULL; - } - cfg->buildable_adjacent_to_district_count = defaults->buildable_adjacent_to_district_count; - cfg->buildable_adjacent_to_district_id_count = defaults->buildable_adjacent_to_district_id_count; - cfg->has_buildable_adjacent_to = defaults->has_buildable_adjacent_to; - cfg->has_buildable_adjacent_to_districts = defaults->has_buildable_adjacent_to_districts; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; - if ((cfg->buildable_by_civs[i] != NULL) && - (cfg->buildable_by_civs[i] != default_value)) { - free ((void *)cfg->buildable_by_civs[i]); - } - cfg->buildable_by_civs[i] = NULL; - } - cfg->buildable_by_civ_count = defaults->buildable_by_civ_count; - cfg->has_buildable_by_civs = defaults->has_buildable_by_civs; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) - cfg->buildable_by_civ_traits_ids[i] = -1; - cfg->buildable_by_civ_traits_id_count = defaults->buildable_by_civ_traits_id_count; - cfg->has_buildable_by_civ_traits = defaults->has_buildable_by_civ_traits; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) - cfg->buildable_by_civ_govs_ids[i] = -1; - cfg->buildable_by_civ_govs_id_count = defaults->buildable_by_civ_govs_id_count; - cfg->has_buildable_by_civ_govs = defaults->has_buildable_by_civ_govs; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) - cfg->buildable_by_civ_cultures_ids[i] = -1; - cfg->buildable_by_civ_cultures_id_count = defaults->buildable_by_civ_cultures_id_count; - cfg->has_buildable_by_civ_cultures = defaults->has_buildable_by_civ_cultures; - cfg->buildable_by_war_allies = defaults->buildable_by_war_allies; - cfg->buildable_by_pact_allies = defaults->buildable_by_pact_allies; - - for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { - char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; - if ((cfg->dependent_improvements[i] != NULL) && - (cfg->dependent_improvements[i] != default_value)) { - free ((void *)cfg->dependent_improvements[i]); - } - cfg->dependent_improvements[i] = NULL; - } - cfg->dependent_improvement_max_index = defaults->dependent_improvement_max_index; - - for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { - char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; - if ((cfg->img_paths[i] != NULL) && - (cfg->img_paths[i] != default_value)) { - free ((void *)cfg->img_paths[i]); - } - cfg->img_paths[i] = NULL; - } - cfg->img_path_count = defaults->img_path_count; - - free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); - free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); - free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); - free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); - free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); - free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); - free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); -} - -void -reset_regular_district_configs (void) -{ - for (int i = USED_SPECIAL_DISTRICT_TYPES; i < COUNT_DISTRICT_TYPES; i++) { - if (is->district_configs[i].is_dynamic) - free_dynamic_district_config (&is->district_configs[i]); - } - - for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) - free_special_district_override_strings (&is->district_configs[i], &special_district_defaults[i]); - - memset (is->district_configs, 0, sizeof is->district_configs); - for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) - is->district_configs[i] = special_district_defaults[i]; - - is->special_district_count = USED_SPECIAL_DISTRICT_TYPES; - is->dynamic_district_count = 0; - is->district_count = is->special_district_count; - is->next_custom_dynamic_command_index = 0; -} - -void -reset_wonder_district_configs (void) -{ - for (int i = 0; i < MAX_WONDER_DISTRICT_TYPES; i++) { - if (is->wonder_district_configs[i].is_dynamic) - free_dynamic_wonder_config (&is->wonder_district_configs[i]); - } - - memset (is->wonder_district_configs, 0, sizeof is->wonder_district_configs); - is->wonder_district_count = 0; -} - -void -reset_natural_wonder_configs (void) -{ - for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { - if (is->natural_wonder_configs[i].is_dynamic) - free_dynamic_natural_wonder_config (&is->natural_wonder_configs[i]); - } - - memset (is->natural_wonder_configs, 0, sizeof is->natural_wonder_configs); - for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { - is->natural_wonder_configs[i].adjacent_to = (enum SquareTypes)SQ_INVALID; - is->natural_wonder_configs[i].adjacency_dir = DIR_ZERO; - } - for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) - is->natural_wonder_img_sets[i].img.vtable = NULL; - stable_deinit (&is->natural_wonder_name_to_id); - is->natural_wonder_count = 0; -} - -void -clear_dynamic_district_definitions (void) -{ - reset_regular_district_configs (); - reset_wonder_district_configs (); - reset_natural_wonder_configs (); - reset_ai_candidate_bridge_or_canals (); -} - -void -init_parsed_district_definition (struct parsed_district_definition * def) -{ - memset (def, 0, sizeof *def); - def->img_path_count = -1; - def->defense_bonus_percent = 0; - def->render_strategy = DRS_BY_COUNT; - def->ai_build_strategy = DABS_DISTRICT; - def->buildable_square_types_mask = district_default_buildable_mask (); - def->buildable_adjacent_to_square_types_mask = 0; - def->buildable_without_removal_mask = 0; - def->buildable_on_overlays_mask = 0; - def->buildable_adjacent_to_overlays_mask = 0; - def->buildable_on_rivers = false; - def->buildable_adjacent_to_allows_city = false; -} - -void -free_parsed_district_definition (struct parsed_district_definition * def) -{ - if (def == NULL) - return; - - if (def->display_name != NULL) { - free (def->display_name); - def->display_name = NULL; - } - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - if (def->tooltip != NULL) { - free (def->tooltip); - def->tooltip = NULL; - } - for (int i = 0; i < def->advance_prereq_count; i++) { - if (def->advance_prereqs[i] != NULL) { - free (def->advance_prereqs[i]); - def->advance_prereqs[i] = NULL; - } - } - def->advance_prereq_count = 0; - for (int i = 0; i < ARRAY_LEN (def->buildable_on_districts); i++) { - if (def->buildable_on_districts[i] != NULL) { - free (def->buildable_on_districts[i]); - def->buildable_on_districts[i] = NULL; - } - } - for (int i = 0; i < ARRAY_LEN (def->buildable_adjacent_to_districts); i++) { - if (def->buildable_adjacent_to_districts[i] != NULL) { - free (def->buildable_adjacent_to_districts[i]); - def->buildable_adjacent_to_districts[i] = NULL; - } - } - if (def->obsoleted_by != NULL) { - free (def->obsoleted_by); - def->obsoleted_by = NULL; - } - - for (int i = 0; i < def->resource_prereq_count; i++) { - if (def->resource_prereqs[i] != NULL) { - free (def->resource_prereqs[i]); - def->resource_prereqs[i] = NULL; - } - } - def->resource_prereq_count = 0; - - if (def->resource_prereq_on_tile != NULL) { - free (def->resource_prereq_on_tile); - def->resource_prereq_on_tile = NULL; - } - - for (int i = 0; i < def->wonder_prereq_count; i++) { - if (def->wonder_prereqs[i] != NULL) { - free (def->wonder_prereqs[i]); - def->wonder_prereqs[i] = NULL; - } - } - def->wonder_prereq_count = 0; - - for (int i = 0; i < def->natural_wonder_prereq_count; i++) { - if (def->natural_wonder_prereqs[i] != NULL) { - free (def->natural_wonder_prereqs[i]); - def->natural_wonder_prereqs[i] = NULL; - } - } - def->natural_wonder_prereq_count = 0; - def->buildable_adjacent_to_district_count = 0; - - for (int i = 0; i < def->buildable_by_civ_count; i++) { - if (def->buildable_by_civs[i] != NULL) { - free (def->buildable_by_civs[i]); - def->buildable_by_civs[i] = NULL; - } - } - def->buildable_by_civ_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - - for (int i = 0; i < def->dependent_improvement_max_index; i++) { - if (def->dependent_improvements[i] != NULL) { - free (def->dependent_improvements[i]); - def->dependent_improvements[i] = NULL; - } - } - def->dependent_improvement_max_index = 0; - - for (int i = 0; i < def->img_path_count; i++) { - if (def->img_paths[i] != NULL) { - free (def->img_paths[i]); - def->img_paths[i] = NULL; - } - } - def->img_path_count = 0; - - if (def->generated_resource != NULL) { - free (def->generated_resource); - def->generated_resource = NULL; - } - - free_bonus_entry_list (&def->culture_bonus_extras); - free_bonus_entry_list (&def->science_bonus_extras); - free_bonus_entry_list (&def->food_bonus_extras); - free_bonus_entry_list (&def->gold_bonus_extras); - free_bonus_entry_list (&def->shield_bonus_extras); - free_bonus_entry_list (&def->happiness_bonus_extras); - free_bonus_entry_list (&def->defense_bonus_extras); - - init_parsed_district_definition (def); -} - -int -find_special_district_index_by_name (char const * name) -{ - if (name == NULL) - return -1; - - for (int i = 0; i < is->special_district_count; i++) { - if ((is->district_configs[i].name != NULL) && - (strcmp (is->district_configs[i].name, name) == 0)) - return i; - } - return -1; -} - - -// --------------------------------------------------------------- -// 兵种克制系统 -// --------------------------------------------------------------- - -struct unit_counter_group * -find_unit_counter_group_by_name (struct c3x_config * cfg, char const * name) -{ - for (int i = 0; i < cfg->count_unit_counter_groups; i++) { - struct unit_counter_group * g = &cfg->unit_counter_groups[i]; - if (g->name && strcmp (g->name, name) == 0) - return g; - } - return NULL; -} - -bool -unit_type_in_group (struct unit_counter_group * g, int type_id) -{ - char const * name = p_bic_data->UnitTypes[type_id].Name; - for (int i = 0; i < g->count_type_ids; i++) - if (strcmp (p_bic_data->UnitTypes[g->type_ids[i]].Name, name) == 0) - return true; - return false; -} - -bool -unit_matches_counter_side (struct c3x_config * cfg, int type_id, - int match, char * group_name) -{ - if (match == UCM_ANY) - return true; - if (match == UCM_GROUP) { - struct unit_counter_group * g = - find_unit_counter_group_by_name (cfg, group_name); - return g && unit_type_in_group (g, type_id); - } - // Direct unit type match: compare by name rather than exact ID so that - // AI strategy duplicates (same name, different ID) are also matched. - return strcmp (p_bic_data->UnitTypes[match].Name, - p_bic_data->UnitTypes[type_id].Name) == 0; -} - -enum recognizable_parse_result -parse_unit_counter_group (char ** p_cursor, - struct error_line ** p_unrecognized_lines, - void * out_group) -{ - char * cur = *p_cursor; - struct string_slice group_name; - if (! (parse_string (&cur, &group_name) && skip_punctuation (&cur, ':'))) - return RPR_PARSE_ERROR; - - struct unit_counter_group * g = out_group; - g->name = extract_slice (&group_name); - g->type_ids = NULL; - g->count_type_ids = 0; - - int any_unrecognized = 0; - struct string_slice type_name; - while (parse_string (&cur, &type_name)) { - // Loop through all unit types with this name, including AI strategy - // duplicates (same name, different ID), which the game creates internally. - int type_id = 0; - bool found_any = false; - while (find_unit_type_id_by_name (&type_name, type_id, &type_id)) { - g->type_ids = realloc (g->type_ids, - (g->count_type_ids + 1) * sizeof (int)); - g->type_ids[g->count_type_ids++] = type_id; - found_any = true; - type_id++; // continue search from next index - } - if (! found_any) { - add_unrecognized_line (p_unrecognized_lines, &type_name); - any_unrecognized = 1; - } - if (! skip_punctuation (&cur, ',')) - break; - } - *p_cursor = cur; - return any_unrecognized ? RPR_UNRECOGNIZED : RPR_OK; -} - -enum recognizable_parse_result -parse_counter_rule (char ** p_cursor, - struct error_line ** p_unrecognized_lines, - void * out_rule) -{ - char * cur = *p_cursor; - struct string_slice attacker_name, vs_token, defender_name; - - if (! parse_string (&cur, &attacker_name)) - return RPR_PARSE_ERROR; - if (! (parse_string (&cur, &vs_token) && - slice_matches_str (&vs_token, "vs"))) - return RPR_PARSE_ERROR; - if (! parse_string (&cur, &defender_name)) - return RPR_PARSE_ERROR; - - struct counter_rule * r = out_rule; - *r = (struct counter_rule) { - .attacker_match = UCM_ANY, - .defender_match = UCM_ANY, - .terrain_type = -1, - .district_id = -1, - .self_atk_pct = 100, - .self_def_pct = 100, - .enemy_atk_pct = 100, - .enemy_def_pct = 100, - }; - - if (! slice_matches_str (&attacker_name, "*")) { - int type_id; - if (find_unit_type_id_by_name (&attacker_name, 0, &type_id)) - r->attacker_match = type_id; - else { - r->attacker_match = UCM_GROUP; - r->attacker_group = extract_slice (&attacker_name); - } - } - - if (! slice_matches_str (&defender_name, "*")) { - int type_id; - if (find_unit_type_id_by_name (&defender_name, 0, &type_id)) - r->defender_match = type_id; - else { - r->defender_match = UCM_GROUP; - r->defender_group = extract_slice (&defender_name); - } - } - - struct string_slice token; - while (parse_string (&cur, &token)) { - if (slice_matches_str (&token, "in-city")) { - r->only_in_city = true; - } else if (slice_matches_str (&token, "ignore-terrain")) { - r->ignore_terrain = true; - } else if (slice_matches_str (&token, "self-atk")) { - if (! parse_int (&cur, &r->self_atk_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "self-def")) { - if (! parse_int (&cur, &r->self_def_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "enemy-atk")) { - if (! parse_int (&cur, &r->enemy_atk_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "enemy-def")) { - if (! parse_int (&cur, &r->enemy_def_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "terrain")) { - struct string_slice terrain_name; - if (! parse_string (&cur, &terrain_name)) - return RPR_PARSE_ERROR; - if (! read_tile_terrain_type_value (&terrain_name, - (enum SquareTypes *)&r->terrain_type)) { - add_unrecognized_line (p_unrecognized_lines, &terrain_name); - return RPR_UNRECOGNIZED; - } - } else if (slice_matches_str (&token, "district")) { - struct string_slice district_name; - if (! parse_string (&cur, &district_name)) - return RPR_PARSE_ERROR; - char * dname = extract_slice (&district_name); - int idx = find_special_district_index_by_name (dname); - free (dname); - if (idx < 0) { - add_unrecognized_line (p_unrecognized_lines, &district_name); - return RPR_UNRECOGNIZED; - } - r->district_id = idx; - } else { - break; - } - } - - *p_cursor = cur; - return RPR_OK; -} - -void -apply_counter_rules (struct c3x_config * cfg, - Unit * attacker, Unit * defender, Tile * def_tile, - int * out_attacker_atk, int * out_defender_def, - bool * out_ignore_terrain) -{ - int a_type = attacker->Body.UnitTypeID; - int d_type = defender->Body.UnitTypeID; - bool in_city = Tile_has_city (def_tile); - - int aa = 100, dd = 100; - bool ignore = false; - - for (int i = 0; i < cfg->count_counter_rules; i++) { - struct counter_rule * r = &cfg->counter_rules[i]; - - // 检查正向匹配(attacker=规则攻击方,defender=规则防守方) - // 生效字段:self-atk(攻击方攻击力)、enemy-def(防守方防御力) - bool forward = unit_matches_counter_side (cfg, a_type, - r->attacker_match, r->attacker_group) && - unit_matches_counter_side (cfg, d_type, - r->defender_match, r->defender_group); - - // 检查反向匹配(attacker=规则防守方,defender=规则攻击方) - // 生效字段:self-def(规则攻击方现在是防守方)、enemy-atk(规则防守方现在是攻击方) - bool reverse = unit_matches_counter_side (cfg, a_type, - r->defender_match, r->defender_group) && - unit_matches_counter_side (cfg, d_type, - r->attacker_match, r->attacker_group); - - if (! forward && ! reverse) - continue; - - // 环境条件以防守方所在格为准 - if (r->only_in_city && ! in_city) - continue; - if (r->terrain_type != -1 && - ! tile_matches_square_type (def_tile, - (enum SquareTypes)r->terrain_type)) - continue; - if (r->district_id != -1 && - ! (cfg->enable_districts && - district_is_complete (def_tile, r->district_id))) - continue; - - if (forward) { - aa = aa * r->self_atk_pct / 100; // self-atk:攻击方攻击力 - dd = dd * r->enemy_def_pct / 100; // enemy-def:防守方防御力 - } - if (reverse) { - aa = aa * r->enemy_atk_pct / 100; // enemy-atk:规则防守方现在作为攻击方 - dd = dd * r->self_def_pct / 100; // self-def:规则攻击方现在作为防守方 - } - if (forward || reverse) - ignore = ignore || r->ignore_terrain; - } - - *out_attacker_atk = aa; - *out_defender_def = dd; - *out_ignore_terrain = ignore; -} - -bool -district_is_included_by_final_config (int district_id) -{ - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - if (! is->current_config.enable_districts) - return false; - - switch (district_id) { - case NEIGHBORHOOD_DISTRICT_ID: return is->current_config.enable_neighborhood_districts; - case WONDER_DISTRICT_ID: return is->current_config.enable_wonder_districts; - case DISTRIBUTION_HUB_DISTRICT_ID: return is->current_config.enable_distribution_hub_districts; - case AERODROME_DISTRICT_ID: return is->current_config.enable_aerodrome_districts; - case PORT_DISTRICT_ID: return is->current_config.enable_port_districts; - case CENTRAL_RAIL_HUB_DISTRICT_ID: return is->current_config.enable_central_rail_hub_districts; - case ENERGY_GRID_DISTRICT_ID: return is->current_config.enable_energy_grid_districts; - case BRIDGE_DISTRICT_ID: return is->current_config.enable_bridge_districts; - case CANAL_DISTRICT_ID: return is->current_config.enable_canal_districts; - case GREAT_WALL_DISTRICT_ID: return is->current_config.enable_great_wall_districts; - default: return true; - } -} - -bool -ensure_culture_variant_art (struct district_config * cfg, int section_start_line) -{ - if ((cfg == NULL) || (! cfg->vary_img_by_culture)) - return true; - - const int required_variants = 5; - const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); - if (cfg->img_path_count <= 0) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] load_dynamic_district_configs: district \"%s\" requires culture-specific art but none provided (line %d)\n", cfg->name, section_start_line); - (*p_OutputDebugStringA) (ss); - return false; - } - - while ((cfg->img_path_count < required_variants) && - (cfg->img_path_count < max_img_paths)) { - cfg->img_paths[cfg->img_path_count] = strdup (cfg->img_paths[0]); - cfg->img_path_count += 1; - } - - return true; -} - -bool -parse_config_string_list (char * value_text, - char ** dest, - int capacity, - int * out_count, - struct error_line ** parse_errors, - int line_number, - char const * key) -{ - for (int i = 0; i < capacity; i++) { - if (dest[i] != NULL) { - free (dest[i]); - dest[i] = NULL; - } - } - *out_count = 0; - - if (value_text == NULL || *value_text == '\0') - return true; - - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - if (*cursor == '\0') - break; - - char * item_start; - char * item_end; - if (*cursor == '"') { - cursor++; - item_start = cursor; - while ((*cursor != '\0') && (*cursor != '"')) - cursor++; - if (*cursor != '"') { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (missing closing quote)", line_number, key); - err->text[(sizeof err->text) - 1] = '\0'; - for (int j = 0; j < capacity; j++) { - if (dest[j] != NULL) { - free (dest[j]); - dest[j] = NULL; - } - } - *out_count = 0; - return false; - } - item_end = cursor; - cursor++; - } else { - item_start = cursor; - while ((*cursor != '\0') && (*cursor != ',')) - cursor++; - item_end = cursor; - } - - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - - int item_len = item_end - item_start; - if (item_len > 0) { - if (*out_count < capacity) { - char * copy = malloc (item_len + 1); - if (copy == NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (out of memory)", line_number, key); - err->text[(sizeof err->text) - 1] = '\0'; - for (int j = 0; j < capacity; j++) { - if (dest[j] != NULL) { - free (dest[j]); - dest[j] = NULL; - } - } - *out_count = 0; - return false; - } - memcpy (copy, item_start, item_len); - copy[item_len] = '\0'; - dest[*out_count] = copy; - *out_count += 1; - } - } - - while (is_space_char (*cursor)) - cursor++; - - if (*cursor == ',') { - cursor++; - continue; - } - if (*cursor == '\0') - break; - } - - return true; -} - -bool -parse_buildable_square_type_mask (struct string_slice const * value, - unsigned int * out_mask, - struct error_line ** parse_errors, - int line_number, - char const * key_name, - bool * out_allow_city) -{ - char * value_text = trim_and_extract_slice (value, 0); - unsigned int mask = 0; - int entry_count = 0; - bool allow_city = false; - bool allow_city_token = (key_name != NULL) && (strcmp (key_name, "buildable_adjacent_to") == 0); - if (key_name == NULL) - key_name = "buildable_on"; - - if (value_text != NULL) { - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - char * item_start = cursor; - while ((*cursor != '\0') && (*cursor != ',')) - cursor++; - - char * item_end = cursor; - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - - struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; - if (item_slice.len > 0) { - if (slice_matches_str (&item_slice, "city")) { - if (! allow_city_token) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - allow_city = true; - entry_count += 1; - } else if (slice_matches_str (&item_slice, "lake")) { - mask |= district_buildable_lake_mask_bit (); - entry_count += 1; - } else { - enum SquareTypes parsed; - if (read_tile_terrain_type_value (&item_slice, &parsed)) { - if ((parsed == SQ_RIVER) || - (parsed == SQ_Forest) || - (parsed == SQ_Jungle) || - (parsed == SQ_Swamp)) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - if (parsed == (enum SquareTypes)SQ_INVALID) { - mask = all_square_types_mask (); - mask &= ~(square_type_mask_bit (SQ_Forest) | - square_type_mask_bit (SQ_Jungle) | - square_type_mask_bit (SQ_Swamp)); - } else - mask |= square_type_mask_bit (parsed); - entry_count += 1; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - } - } - - if (*cursor == ',') { - cursor++; - continue; - } - break; - } - } - - if (value_text != NULL) - free (value_text); - - if ((entry_count == 0) || ((mask == 0) && ! allow_city)) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one tile terrain type)", line_number, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - return false; - } - - *out_mask = mask; - if (out_allow_city != NULL) - *out_allow_city = allow_city; - return true; -} - -bool -parse_buildable_overlay_mask (struct string_slice const * value, - unsigned int * out_mask, - struct error_line ** parse_errors, - int line_number, - char const * key_name) -{ - char * value_text = trim_and_extract_slice (value, 0); - unsigned int mask = 0; - unsigned int allowed_mask = (DOM_MINE | DOM_IRRIGATION | DOM_FORTRESS | DOM_BARRICADE | - DOM_OUTPOST | DOM_RADAR_TOWER | DOM_JUNGLE | DOM_FOREST | - DOM_SWAMP | DOM_RIVER | DOM_AIRFIELD); - int entry_count = 0; - - if (key_name == NULL) - key_name = "buildable_without_removal"; - if (strcmp (key_name, "buildable_without_removal") == 0) - allowed_mask = (DOM_JUNGLE | DOM_FOREST | DOM_SWAMP); - else if (strcmp (key_name, "buildable_on_overlays") == 0) - allowed_mask &= ~DOM_RIVER; - - if (value_text != NULL) { - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - char * item_start = cursor; - while ((*cursor != '\0') && (*cursor != ',')) - cursor++; - - char * item_end = cursor; - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - - struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; - if (item_slice.len > 0) { - unsigned int bit = 0; - if (slice_matches_str (&item_slice, "mine")) { - bit = DOM_MINE; - } else if (slice_matches_str (&item_slice, "irrigation")) { - bit = DOM_IRRIGATION; - } else if (slice_matches_str (&item_slice, "fortress")) { - bit = DOM_FORTRESS; - } else if (slice_matches_str (&item_slice, "barricade")) { - bit = DOM_BARRICADE; - } else if (slice_matches_str (&item_slice, "outpost")) { - bit = DOM_OUTPOST; - } else if (slice_matches_str (&item_slice, "radar-tower")) { - bit = DOM_RADAR_TOWER; - } else if (slice_matches_str (&item_slice, "airfield")) { - bit = DOM_AIRFIELD; - } else if (slice_matches_str (&item_slice, "jungle")) { - bit = DOM_JUNGLE; - } else if (slice_matches_str (&item_slice, "jungles")) { - bit = DOM_JUNGLE; - } else if (slice_matches_str (&item_slice, "forest")) { - bit = DOM_FOREST; - } else if (slice_matches_str (&item_slice, "forests")) { - bit = DOM_FOREST; - } else if (slice_matches_str (&item_slice, "marsh")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "marshes")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "swamp")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "swamps")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "river")) { - bit = DOM_RIVER; - } else if (slice_matches_str (&item_slice, "rivers")) { - bit = DOM_RIVER; - } - - if (bit != 0) { - if ((allowed_mask & bit) == 0) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - mask |= bit; - entry_count += 1; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - } - - if (*cursor == ',') { - cursor++; - continue; - } - break; - } - } - - if (value_text != NULL) - free (value_text); - - if ((entry_count == 0) || (mask == 0)) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one overlay)", line_number, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - return false; - } - - *out_mask = mask; - return true; -} - -bool -parse_district_bonus_entries (struct string_slice const * value, - int * out_base_bonus, - struct district_bonus_list * out_extras, - struct error_line ** parse_errors, - int line_number, - struct string_slice const * key) -{ - if ((out_base_bonus == NULL) || (out_extras == NULL)) { - add_key_parse_error (parse_errors, line_number, key, value, "(invalid bonus target)"); - return false; - } - - char * value_text = trim_and_extract_slice (value, 0); - free_bonus_entry_list (out_extras); - *out_base_bonus = 0; - - if ((value_text == NULL) || (*value_text == '\0')) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); - free (value_text); - return false; - } - - bool got_base = false; - int base_bonus = 0; - - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - if (*cursor == '\0') - break; - - char * item_start = cursor; - bool in_quotes = false; - while (*cursor != '\0') { - if (*cursor == '"') - in_quotes = ! in_quotes; - if ((! in_quotes) && (*cursor == ',')) - break; - cursor++; - } - - char * item_end = cursor; - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - while ((item_start < item_end) && is_space_char (*item_start)) - item_start++; - - if (item_end > item_start) { - struct string_slice item = { .str = item_start, .len = (int)(item_end - item_start) }; - - if (! got_base) { - struct string_slice base_slice = trim_string_slice (&item, 0); - if (! read_int (&base_slice, &base_bonus)) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - got_base = true; - } else { - char * colon = NULL; - in_quotes = false; - for (char * p = item_start; p < item_end; p++) { - if (*p == '"') - in_quotes = ! in_quotes; - if ((! in_quotes) && (*p == ':')) { - colon = p; - break; - } - } - - if (colon == NULL) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected \"name: bonus\" entry)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - struct string_slice name_slice = { .str = item_start, .len = (int)(colon - item_start) }; - struct string_slice bonus_slice = { .str = colon + 1, .len = (int)(item_end - (colon + 1)) }; - struct string_slice trimmed_name = trim_string_slice (&name_slice, 1); - struct string_slice trimmed_bonus = trim_string_slice (&bonus_slice, 0); - - if (trimmed_name.len <= 0) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus name)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - int bonus_value = 0; - if (! read_int (&trimmed_bonus, &bonus_value)) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus value)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - if (out_extras->count >= MAX_DISTRICT_BONUS_ENTRIES) { - add_key_parse_error (parse_errors, line_number, key, value, "(too many bonus entries)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - struct district_bonus_entry * entry = &out_extras->entries[out_extras->count++]; - entry->bonus = bonus_value; - entry->building_id = -1; - entry->building_name = NULL; - - enum SquareTypes parsed_type; - if (read_tile_terrain_type_value (&trimmed_name, &parsed_type)) { - entry->type = DBET_TILE; - entry->tile_type = parsed_type; - } else { - entry->type = DBET_BUILDING; - entry->tile_type = (enum SquareTypes)SQ_INVALID; - entry->building_name = extract_slice (&trimmed_name); - } - } - } - - if (*cursor == ',') { - cursor++; - continue; - } - if (*cursor == '\0') - break; - } - - free (value_text); - - if (! got_base) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); - free_bonus_entry_list (out_extras); - return false; - } - - *out_base_bonus = base_bonus; - return true; -} - -bool -override_special_district_from_definition (struct parsed_district_definition * def, int section_start_line) -{ - if ((! def->has_name) || (def->name == NULL)) - return false; - - int index = find_special_district_index_by_name (def->name); - if (index < 0) - return false; - - struct district_config * cfg = &is->district_configs[index]; - struct district_config const * defaults = &special_district_defaults[index]; - - free (def->name); - def->name = NULL; - def->has_name = false; - - if (def->has_display_name) { - if ((cfg->display_name != NULL) && - (cfg->display_name != cfg->name) && - (cfg->display_name != defaults->display_name)) - free ((void *)cfg->display_name); - cfg->display_name = def->display_name; - def->display_name = NULL; - } - - if (def->has_tooltip) { - if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) - free ((void *)cfg->tooltip); - cfg->tooltip = def->tooltip; - def->tooltip = NULL; - } - - if (def->has_advance_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { - char const * default_value = (i < defaults->advance_prereq_count) ? defaults->advance_prereqs[i] : NULL; - if ((cfg->advance_prereqs[i] != NULL) && - (cfg->advance_prereqs[i] != default_value)) - free ((void *)cfg->advance_prereqs[i]); - cfg->advance_prereqs[i] = NULL; - } - - cfg->advance_prereq_count = def->advance_prereq_count; - const int max_entries = ARRAY_LEN (cfg->advance_prereqs); - if (cfg->advance_prereq_count > max_entries) - cfg->advance_prereq_count = max_entries; - for (int i = 0; i < cfg->advance_prereq_count; i++) { - cfg->advance_prereqs[i] = def->advance_prereqs[i]; - def->advance_prereqs[i] = NULL; - } - def->advance_prereq_count = 0; - } - - if (def->has_obsoleted_by) { - if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) - free ((void *)cfg->obsoleted_by); - cfg->obsoleted_by = def->obsoleted_by; - def->obsoleted_by = NULL; - } - - if (def->has_resource_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { - char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; - if ((cfg->resource_prereqs[i] != NULL) && - (cfg->resource_prereqs[i] != default_value)) - free ((void *)cfg->resource_prereqs[i]); - cfg->resource_prereqs[i] = NULL; - } - - cfg->resource_prereq_count = def->resource_prereq_count; - const int max_entries = ARRAY_LEN (cfg->resource_prereqs); - if (cfg->resource_prereq_count > max_entries) - cfg->resource_prereq_count = max_entries; - for (int i = 0; i < cfg->resource_prereq_count; i++) { - cfg->resource_prereqs[i] = def->resource_prereqs[i]; - def->resource_prereqs[i] = NULL; - } - } - - if (def->has_resource_prereq_on_tile) { - if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) - free ((void *)cfg->resource_prereq_on_tile); - cfg->resource_prereq_on_tile = def->resource_prereq_on_tile; - def->resource_prereq_on_tile = NULL; - } - - if (def->has_wonder_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { - char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; - if ((cfg->wonder_prereqs[i] != NULL) && - (cfg->wonder_prereqs[i] != default_value)) - free ((void *)cfg->wonder_prereqs[i]); - cfg->wonder_prereqs[i] = NULL; - } - - cfg->wonder_prereq_count = def->wonder_prereq_count; - const int max_entries = ARRAY_LEN (cfg->wonder_prereqs); - if (cfg->wonder_prereq_count > max_entries) - cfg->wonder_prereq_count = max_entries; - for (int i = 0; i < cfg->wonder_prereq_count; i++) { - cfg->wonder_prereqs[i] = def->wonder_prereqs[i]; - def->wonder_prereqs[i] = NULL; - } - } - - if (def->has_natural_wonder_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { - char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; - if ((cfg->natural_wonder_prereqs[i] != NULL) && - (cfg->natural_wonder_prereqs[i] != default_value)) - free ((void *)cfg->natural_wonder_prereqs[i]); - cfg->natural_wonder_prereqs[i] = NULL; - } - - cfg->natural_wonder_prereq_count = def->natural_wonder_prereq_count; - const int max_entries = ARRAY_LEN (cfg->natural_wonder_prereqs); - if (cfg->natural_wonder_prereq_count > max_entries) - cfg->natural_wonder_prereq_count = max_entries; - for (int i = 0; i < cfg->natural_wonder_prereq_count; i++) { - cfg->natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; - def->natural_wonder_prereqs[i] = NULL; - } - } - - if (def->has_buildable_on_districts) { - for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { - char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; - if ((cfg->buildable_on_districts[i] != NULL) && - (cfg->buildable_on_districts[i] != default_value)) - free ((void *)cfg->buildable_on_districts[i]); - cfg->buildable_on_districts[i] = NULL; - } - - cfg->buildable_on_district_count = def->buildable_on_district_count; - const int max_entries = ARRAY_LEN (cfg->buildable_on_districts); - if (cfg->buildable_on_district_count > max_entries) - cfg->buildable_on_district_count = max_entries; - for (int i = 0; i < cfg->buildable_on_district_count; i++) { - cfg->buildable_on_districts[i] = def->buildable_on_districts[i]; - def->buildable_on_districts[i] = NULL; - } - cfg->buildable_on_district_id_count = 0; - cfg->has_buildable_on_districts = true; - } - - if (def->has_buildable_adjacent_to_districts) { - for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { - char const * default_value = (i < defaults->buildable_adjacent_to_district_count) - ? defaults->buildable_adjacent_to_districts[i] - : NULL; - if ((cfg->buildable_adjacent_to_districts[i] != NULL) && - (cfg->buildable_adjacent_to_districts[i] != default_value)) - free ((void *)cfg->buildable_adjacent_to_districts[i]); - cfg->buildable_adjacent_to_districts[i] = NULL; - } - - cfg->buildable_adjacent_to_district_count = def->buildable_adjacent_to_district_count; - const int max_entries = ARRAY_LEN (cfg->buildable_adjacent_to_districts); - if (cfg->buildable_adjacent_to_district_count > max_entries) - cfg->buildable_adjacent_to_district_count = max_entries; - for (int i = 0; i < cfg->buildable_adjacent_to_district_count; i++) { - cfg->buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; - def->buildable_adjacent_to_districts[i] = NULL; - } - cfg->buildable_adjacent_to_district_id_count = 0; - cfg->has_buildable_adjacent_to_districts = true; - } - - if (def->has_buildable_by_civs) { - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; - if ((cfg->buildable_by_civs[i] != NULL) && - (cfg->buildable_by_civs[i] != default_value)) - free ((void *)cfg->buildable_by_civs[i]); - cfg->buildable_by_civs[i] = NULL; - } - cfg->buildable_by_civ_count = def->buildable_by_civ_count; - const int max_civ_names = ARRAY_LEN (cfg->buildable_by_civs); - if (cfg->buildable_by_civ_count > max_civ_names) - cfg->buildable_by_civ_count = max_civ_names; - for (int i = 0; i < cfg->buildable_by_civ_count; i++) { - cfg->buildable_by_civs[i] = def->buildable_by_civs[i]; - def->buildable_by_civs[i] = NULL; - } - cfg->has_buildable_by_civs = true; - } - - if (def->has_buildable_by_civ_traits) { - cfg->buildable_by_civ_traits_id_count = def->buildable_by_civ_traits_id_count; - const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_traits_ids); - if (cfg->buildable_by_civ_traits_id_count > max_entries) - cfg->buildable_by_civ_traits_id_count = max_entries; - for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) - cfg->buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; - cfg->has_buildable_by_civ_traits = true; - } - - if (def->has_buildable_by_civ_govs) { - cfg->buildable_by_civ_govs_id_count = def->buildable_by_civ_govs_id_count; - const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_govs_ids); - if (cfg->buildable_by_civ_govs_id_count > max_entries) - cfg->buildable_by_civ_govs_id_count = max_entries; - for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) - cfg->buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; - cfg->has_buildable_by_civ_govs = true; - } - - if (def->has_buildable_by_civ_cultures) { - cfg->buildable_by_civ_cultures_id_count = def->buildable_by_civ_cultures_id_count; - const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); - if (cfg->buildable_by_civ_cultures_id_count > max_entries) - cfg->buildable_by_civ_cultures_id_count = max_entries; - for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) - cfg->buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; - cfg->has_buildable_by_civ_cultures = true; - } - - if (def->has_buildable_by_war_allies) - cfg->buildable_by_war_allies = def->buildable_by_war_allies; - if (def->has_buildable_by_pact_allies) - cfg->buildable_by_pact_allies = def->buildable_by_pact_allies; - - if (def->has_allow_multiple) - cfg->allow_multiple = def->allow_multiple; - if (def->has_vary_img_by_era) - cfg->vary_img_by_era = def->vary_img_by_era; - if (def->has_vary_img_by_culture) - cfg->vary_img_by_culture = def->vary_img_by_culture; - if (def->has_render_strategy) - cfg->render_strategy = def->render_strategy; - if (def->has_ai_build_strategy) - cfg->ai_build_strategy = def->ai_build_strategy; - if (def->has_align_to_coast) - cfg->align_to_coast = def->align_to_coast; - if (def->has_draw_over_resources) - cfg->draw_over_resources = def->draw_over_resources; - if (def->has_allow_irrigation_from) - cfg->allow_irrigation_from = def->allow_irrigation_from; - if (def->has_auto_add_road) - cfg->auto_add_road = def->auto_add_road; - if (def->has_auto_add_railroad) - cfg->auto_add_railroad = def->auto_add_railroad; - if (def->has_custom_width) - cfg->custom_width = def->custom_width; - if (def->has_custom_height) - cfg->custom_height = def->custom_height; - if (def->has_x_offset) - cfg->x_offset = def->x_offset; - if (def->has_y_offset) - cfg->y_offset = def->y_offset; - if (def->has_btn_tile_sheet_column) - cfg->btn_tile_sheet_column = def->btn_tile_sheet_column; - if (def->has_btn_tile_sheet_row) - cfg->btn_tile_sheet_row = def->btn_tile_sheet_row; - if (def->has_defense_bonus_percent) { - cfg->defense_bonus_percent = def->defense_bonus_percent; - free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); - move_bonus_entry_list (&cfg->defense_bonus_extras, &def->defense_bonus_extras); - } - if (def->has_heal_units_in_one_turn) - cfg->heal_units_in_one_turn = def->heal_units_in_one_turn; - if (def->has_impassible) - cfg->impassible = def->impassible; - if (def->has_impassible_to_wheeled) - cfg->impassible_to_wheeled = def->impassible_to_wheeled; - if (def->has_culture_bonus) { - cfg->culture_bonus = def->culture_bonus; - free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); - move_bonus_entry_list (&cfg->culture_bonus_extras, &def->culture_bonus_extras); - } - if (def->has_science_bonus) { - cfg->science_bonus = def->science_bonus; - free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); - move_bonus_entry_list (&cfg->science_bonus_extras, &def->science_bonus_extras); - } - if (def->has_food_bonus) { - cfg->food_bonus = def->food_bonus; - free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); - move_bonus_entry_list (&cfg->food_bonus_extras, &def->food_bonus_extras); - } - if (def->has_gold_bonus) { - cfg->gold_bonus = def->gold_bonus; - free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); - move_bonus_entry_list (&cfg->gold_bonus_extras, &def->gold_bonus_extras); - } - if (def->has_shield_bonus) { - cfg->shield_bonus = def->shield_bonus; - free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); - move_bonus_entry_list (&cfg->shield_bonus_extras, &def->shield_bonus_extras); - } - if (def->has_happiness_bonus) { - cfg->happiness_bonus = def->happiness_bonus; - free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); - move_bonus_entry_list (&cfg->happiness_bonus_extras, &def->happiness_bonus_extras); - } - if (def->has_buildable_on) - cfg->buildable_square_types_mask = def->buildable_square_types_mask; - if (def->has_buildable_adjacent_to) { - cfg->buildable_adjacent_to_square_types_mask = def->buildable_adjacent_to_square_types_mask; - cfg->has_buildable_adjacent_to = true; - cfg->buildable_adjacent_to_allows_city = def->buildable_adjacent_to_allows_city; - } - if (def->has_buildable_without_removal) { - cfg->buildable_without_removal_mask = def->buildable_without_removal_mask; - cfg->has_buildable_without_removal = true; - } - if (def->has_buildable_on_overlays) { - cfg->buildable_on_overlays_mask = def->buildable_on_overlays_mask; - cfg->has_buildable_on_overlays = true; - } - if (def->has_buildable_on_rivers) - cfg->buildable_on_rivers = def->buildable_on_rivers; - if (def->has_buildable_adjacent_to_overlays) { - cfg->buildable_adjacent_to_overlays_mask = def->buildable_adjacent_to_overlays_mask; - cfg->has_buildable_adjacent_to_overlays = true; - } - - if (def->has_generated_resource) { - if ((cfg->generated_resource != NULL) && (cfg->generated_resource != defaults->generated_resource)) - free ((void *)cfg->generated_resource); - cfg->generated_resource = def->generated_resource; - def->generated_resource = NULL; - cfg->generated_resource_flags = def->generated_resource_flags; - cfg->generated_resource_id = -1; - } - - if (def->has_dependent_improvements) { - for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { - char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; - if ((cfg->dependent_improvements[i] != NULL) && - (cfg->dependent_improvements[i] != default_value)) - free ((void *)cfg->dependent_improvements[i]); - cfg->dependent_improvements[i] = NULL; - } - - cfg->dependent_improvement_max_index = def->dependent_improvement_max_index; - const int max_entries = ARRAY_LEN (cfg->dependent_improvements); - if (cfg->dependent_improvement_max_index > max_entries) - cfg->dependent_improvement_max_index = max_entries; - for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { - cfg->dependent_improvements[i] = def->dependent_improvements[i]; - def->dependent_improvements[i] = NULL; - } - if (! def->has_img_column_count) { - cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->dependent_improvement_max_index + 1); - cfg->has_img_column_count_override = false; - } - } - - if (def->has_img_paths) { - for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { - char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; - if ((cfg->img_paths[i] != NULL) && - (cfg->img_paths[i] != default_value)) - free ((void *)cfg->img_paths[i]); - cfg->img_paths[i] = NULL; - } - - cfg->img_path_count = def->img_path_count; - const int max_img_paths = ARRAY_LEN (cfg->img_paths); - if (cfg->img_path_count > max_img_paths) - cfg->img_path_count = max_img_paths; - for (int i = 0; i < cfg->img_path_count; i++) { - cfg->img_paths[i] = def->img_paths[i]; - def->img_paths[i] = NULL; - } - } - - if (def->has_img_column_count) { - cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->img_column_count); - cfg->has_img_column_count_override = true; - } - - if (! ensure_culture_variant_art (cfg, section_start_line)) { - free_special_district_override_strings (cfg, defaults); - *cfg = *defaults; - return false; - } - - return true; -} - -bool -add_dynamic_district_from_definition (struct parsed_district_definition * def, int section_start_line) -{ - if ((! def->has_name) || (def->name == NULL)) - return false; - - if ((! def->has_img_paths) || (def->img_path_count <= 0)) - return false; - - int existing_index = -1; - for (int i = is->special_district_count; i < is->district_count; i++) { - if ((is->district_configs[i].name != NULL) && - (strcmp (is->district_configs[i].name, def->name) == 0)) { - existing_index = i; - break; - } - } - - bool reusing_existing = existing_index >= 0; - int dest_index = reusing_existing ? existing_index : (is->special_district_count + is->dynamic_district_count); - - if ((! reusing_existing) && (dest_index >= COUNT_DISTRICT_TYPES)) - return false; - - enum Unit_Command_Values preserved_command = 0; - if (reusing_existing) - preserved_command = is->district_configs[dest_index].command; - - struct district_config new_cfg; - memset (&new_cfg, 0, sizeof new_cfg); - new_cfg.is_dynamic = true; - - new_cfg.name = def->name; - def->name = NULL; - if (def->has_display_name) { - new_cfg.display_name = def->display_name; - if (new_cfg.display_name == NULL) - new_cfg.display_name = new_cfg.name; - def->display_name = NULL; - } else { - new_cfg.display_name = new_cfg.name; - } - - if (def->has_tooltip) { - new_cfg.tooltip = def->tooltip; - def->tooltip = NULL; - } else if (new_cfg.name != NULL) { - char buffer[128]; - snprintf (buffer, sizeof buffer, "Build %s", new_cfg.name); - new_cfg.tooltip = strdup (buffer); - } - - if (def->has_advance_prereqs) { - new_cfg.advance_prereq_count = def->advance_prereq_count; - const int max_entries = ARRAY_LEN (new_cfg.advance_prereqs); - if (new_cfg.advance_prereq_count > max_entries) - new_cfg.advance_prereq_count = max_entries; - for (int i = 0; i < new_cfg.advance_prereq_count; i++) { - new_cfg.advance_prereqs[i] = def->advance_prereqs[i]; - def->advance_prereqs[i] = NULL; - } - def->advance_prereq_count = 0; - } - - if (def->has_obsoleted_by) { - new_cfg.obsoleted_by = def->obsoleted_by; - def->obsoleted_by = NULL; - } - - new_cfg.resource_prereq_count = def->has_resource_prereqs ? def->resource_prereq_count : 0; - const int max_resource_entries = ARRAY_LEN (new_cfg.resource_prereqs); - if (new_cfg.resource_prereq_count > max_resource_entries) - new_cfg.resource_prereq_count = max_resource_entries; - for (int i = 0; i < new_cfg.resource_prereq_count; i++) { - new_cfg.resource_prereqs[i] = def->resource_prereqs[i]; - def->resource_prereqs[i] = NULL; - } - - if (def->has_resource_prereq_on_tile) { - new_cfg.resource_prereq_on_tile = def->resource_prereq_on_tile; - def->resource_prereq_on_tile = NULL; - } - - new_cfg.wonder_prereq_count = def->has_wonder_prereqs ? def->wonder_prereq_count : 0; - const int max_required_wonders = ARRAY_LEN (new_cfg.wonder_prereqs); - if (new_cfg.wonder_prereq_count > max_required_wonders) - new_cfg.wonder_prereq_count = max_required_wonders; - for (int i = 0; i < new_cfg.wonder_prereq_count; i++) { - new_cfg.wonder_prereqs[i] = def->wonder_prereqs[i]; - def->wonder_prereqs[i] = NULL; - } - - new_cfg.natural_wonder_prereq_count = def->has_natural_wonder_prereqs ? def->natural_wonder_prereq_count : 0; - const int max_required_natural_wonders = ARRAY_LEN (new_cfg.natural_wonder_prereqs); - if (new_cfg.natural_wonder_prereq_count > max_required_natural_wonders) - new_cfg.natural_wonder_prereq_count = max_required_natural_wonders; - for (int i = 0; i < new_cfg.natural_wonder_prereq_count; i++) { - new_cfg.natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; - def->natural_wonder_prereqs[i] = NULL; - } - - new_cfg.buildable_on_district_count = def->has_buildable_on_districts ? def->buildable_on_district_count : 0; - const int max_buildable_on_districts = ARRAY_LEN (new_cfg.buildable_on_districts); - if (new_cfg.buildable_on_district_count > max_buildable_on_districts) - new_cfg.buildable_on_district_count = max_buildable_on_districts; - for (int i = 0; i < new_cfg.buildable_on_district_count; i++) { - new_cfg.buildable_on_districts[i] = def->buildable_on_districts[i]; - def->buildable_on_districts[i] = NULL; - } - new_cfg.buildable_on_district_id_count = 0; - new_cfg.has_buildable_on_districts = def->has_buildable_on_districts; - - new_cfg.buildable_adjacent_to_district_count = def->has_buildable_adjacent_to_districts ? def->buildable_adjacent_to_district_count : 0; - const int max_adjacent_to_districts = ARRAY_LEN (new_cfg.buildable_adjacent_to_districts); - if (new_cfg.buildable_adjacent_to_district_count > max_adjacent_to_districts) - new_cfg.buildable_adjacent_to_district_count = max_adjacent_to_districts; - for (int i = 0; i < new_cfg.buildable_adjacent_to_district_count; i++) { - new_cfg.buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; - def->buildable_adjacent_to_districts[i] = NULL; - } - new_cfg.buildable_adjacent_to_district_id_count = 0; - new_cfg.has_buildable_adjacent_to_districts = def->has_buildable_adjacent_to_districts; - - new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; - const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); - if (new_cfg.buildable_by_civ_count > max_civ_names) - new_cfg.buildable_by_civ_count = max_civ_names; - for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { - new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; - def->buildable_by_civs[i] = NULL; - } - - new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; - - new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; - const int max_buildable_traits = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); - if (new_cfg.buildable_by_civ_traits_id_count > max_buildable_traits) - new_cfg.buildable_by_civ_traits_id_count = max_buildable_traits; - for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) - new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; - new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; - - new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; - const int max_buildable_govs = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); - if (new_cfg.buildable_by_civ_govs_id_count > max_buildable_govs) - new_cfg.buildable_by_civ_govs_id_count = max_buildable_govs; - for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) - new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; - new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; - - new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; - const int max_buildable_cultures = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); - if (new_cfg.buildable_by_civ_cultures_id_count > max_buildable_cultures) - new_cfg.buildable_by_civ_cultures_id_count = max_buildable_cultures; - for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) - new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; - new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; - - new_cfg.buildable_by_war_allies = def->has_buildable_by_war_allies ? def->buildable_by_war_allies : false; - new_cfg.buildable_by_pact_allies = def->has_buildable_by_pact_allies ? def->buildable_by_pact_allies : false; - - new_cfg.allow_multiple = def->has_allow_multiple ? def->allow_multiple : false; - new_cfg.vary_img_by_era = def->has_vary_img_by_era ? def->vary_img_by_era : false; - new_cfg.vary_img_by_culture = def->has_vary_img_by_culture ? def->vary_img_by_culture : false; - new_cfg.render_strategy = def->has_render_strategy ? def->render_strategy : DRS_BY_COUNT; - new_cfg.ai_build_strategy = def->has_ai_build_strategy ? def->ai_build_strategy : DABS_DISTRICT; - new_cfg.align_to_coast = def->has_align_to_coast ? def->align_to_coast : false; - new_cfg.draw_over_resources = def->has_draw_over_resources ? def->draw_over_resources : false; - new_cfg.allow_irrigation_from = def->has_allow_irrigation_from ? def->allow_irrigation_from : false; - new_cfg.auto_add_road = def->has_auto_add_road ? def->auto_add_road : false; - new_cfg.auto_add_railroad = def->has_auto_add_railroad ? def->auto_add_railroad : false; - new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; - new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; - new_cfg.x_offset = def->has_x_offset ? def->x_offset : 0; - new_cfg.y_offset = def->has_y_offset ? def->y_offset : 0; - new_cfg.btn_tile_sheet_column = def->has_btn_tile_sheet_column ? def->btn_tile_sheet_column : 0; - new_cfg.btn_tile_sheet_row = def->has_btn_tile_sheet_row ? def->btn_tile_sheet_row : 0; - new_cfg.defense_bonus_percent = def->has_defense_bonus_percent ? def->defense_bonus_percent : 0; - new_cfg.heal_units_in_one_turn = def->has_heal_units_in_one_turn ? def->heal_units_in_one_turn : false; - new_cfg.impassible = def->has_impassible ? def->impassible : false; - new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; - new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; - new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; - new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; - new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; - new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; - new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; - new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); - new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; - new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; - new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; - new_cfg.buildable_without_removal_mask = def->has_buildable_without_removal ? def->buildable_without_removal_mask : 0; - new_cfg.has_buildable_without_removal = def->has_buildable_without_removal; - new_cfg.buildable_on_overlays_mask = def->has_buildable_on_overlays ? def->buildable_on_overlays_mask : 0; - new_cfg.has_buildable_on_overlays = def->has_buildable_on_overlays; - new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; - new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; - new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; - - if (def->has_culture_bonus) - move_bonus_entry_list (&new_cfg.culture_bonus_extras, &def->culture_bonus_extras); - if (def->has_science_bonus) - move_bonus_entry_list (&new_cfg.science_bonus_extras, &def->science_bonus_extras); - if (def->has_food_bonus) - move_bonus_entry_list (&new_cfg.food_bonus_extras, &def->food_bonus_extras); - if (def->has_gold_bonus) - move_bonus_entry_list (&new_cfg.gold_bonus_extras, &def->gold_bonus_extras); - if (def->has_shield_bonus) - move_bonus_entry_list (&new_cfg.shield_bonus_extras, &def->shield_bonus_extras); - if (def->has_happiness_bonus) - move_bonus_entry_list (&new_cfg.happiness_bonus_extras, &def->happiness_bonus_extras); - if (def->has_defense_bonus_percent) - move_bonus_entry_list (&new_cfg.defense_bonus_extras, &def->defense_bonus_extras); - - if (def->has_generated_resource) { - new_cfg.generated_resource = def->generated_resource; - def->generated_resource = NULL; - new_cfg.generated_resource_flags = def->generated_resource_flags; - new_cfg.generated_resource_id = -1; - } else { - new_cfg.generated_resource = NULL; - new_cfg.generated_resource_id = -1; - new_cfg.generated_resource_flags = 0; - } - - new_cfg.dependent_improvement_max_index = def->has_dependent_improvements ? def->dependent_improvement_max_index : 0; - const int max_dependent_entries = ARRAY_LEN (is->district_configs[0].dependent_improvements); - if (new_cfg.dependent_improvement_max_index > max_dependent_entries) - new_cfg.dependent_improvement_max_index = max_dependent_entries; - for (int i = 0; i < new_cfg.dependent_improvement_max_index; i++) { - new_cfg.dependent_improvements[i] = def->dependent_improvements[i]; - def->dependent_improvements[i] = NULL; - } - - new_cfg.img_path_count = def->img_path_count; - const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); - if (new_cfg.img_path_count > max_img_paths) - new_cfg.img_path_count = max_img_paths; - for (int i = 0; i < new_cfg.img_path_count; i++) { - new_cfg.img_paths[i] = def->img_paths[i]; - def->img_paths[i] = NULL; - } - - if (! ensure_culture_variant_art (&new_cfg, section_start_line)) { - free_dynamic_district_config (&new_cfg); - return false; - } - - new_cfg.img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, def->has_img_column_count ? def->img_column_count : new_cfg.dependent_improvement_max_index + 1); - new_cfg.has_img_column_count_override = def->has_img_column_count; - - if (reusing_existing) - new_cfg.command = preserved_command; - else - new_cfg.command = allocate_dynamic_district_command (new_cfg.name); - - struct district_config * dest_cfg = &is->district_configs[dest_index]; - if (reusing_existing) { - enum Unit_Command_Values saved_command = preserved_command; - free_dynamic_district_config (dest_cfg); - *dest_cfg = new_cfg; - dest_cfg->command = saved_command; - } else { - free_dynamic_district_config (dest_cfg); - *dest_cfg = new_cfg; - is->dynamic_district_count += 1; - is->district_count = is->special_district_count + is->dynamic_district_count; - } - - return true; -} - -void -finalize_parsed_district_definition (struct parsed_district_definition * def, int section_start_line) -{ - if ((! def->has_name) || (def->name == NULL)) - return; - - if (! override_special_district_from_definition (def, section_start_line)) - add_dynamic_district_from_definition (def, section_start_line); - - free_parsed_district_definition (def); -} - -void -handle_district_definition_key (struct parsed_district_definition * def, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if (slice_matches_str (key, "name")) { - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - char * name_copy = copy_trimmed_string_or_null (value, 1); - if (name_copy == NULL) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else { - def->name = name_copy; - def->has_name = true; - } - - } else if (slice_matches_str (key, "display_name")) { - if (def->display_name != NULL) { - free (def->display_name); - def->display_name = NULL; - } - def->display_name = copy_trimmed_string_or_null (value, 1); - def->has_display_name = true; - - } else if (slice_matches_str (key, "tooltip")) { - if (def->tooltip != NULL) { - free (def->tooltip); - def->tooltip = NULL; - } - def->tooltip = copy_trimmed_string_or_null (value, 1); - def->has_tooltip = true; - - } else if (slice_matches_str (key, "advance_prereqs") || slice_matches_str (key, "advance_prereq")) { - for (int i = 0; i < def->advance_prereq_count; i++) { - if (def->advance_prereqs[i] != NULL) { - free (def->advance_prereqs[i]); - def->advance_prereqs[i] = NULL; - } - } - def->advance_prereq_count = 0; - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->advance_prereqs, - ARRAY_LEN (def->advance_prereqs), - &list_count, - parse_errors, - line_number, - "advance_prereqs")) { - def->advance_prereq_count = list_count; - def->has_advance_prereqs = true; - } else { - def->advance_prereq_count = 0; - def->has_advance_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "obsoleted_by")) { - if (def->obsoleted_by != NULL) { - free (def->obsoleted_by); - def->obsoleted_by = NULL; - } - def->obsoleted_by = copy_trimmed_string_or_null (value, 1); - def->has_obsoleted_by = true; - - } else if (slice_matches_str (key, "resource_prereqs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->resource_prereqs, - ARRAY_LEN (def->resource_prereqs), - &list_count, - parse_errors, - line_number, - "resource_prereqs")) { - def->resource_prereq_count = list_count; - def->has_resource_prereqs = true; - } else { - def->resource_prereq_count = 0; - def->has_resource_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "resource_prereq_on_tile")) { - if (def->resource_prereq_on_tile != NULL) { - free (def->resource_prereq_on_tile); - def->resource_prereq_on_tile = NULL; - } - def->resource_prereq_on_tile = copy_trimmed_string_or_null (value, 1); - def->has_resource_prereq_on_tile = true; - - } else if (slice_matches_str (key, "wonder_prereqs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->wonder_prereqs, - ARRAY_LEN (def->wonder_prereqs), - &list_count, - parse_errors, - line_number, - "wonder_prereqs")) { - def->wonder_prereq_count = list_count; - def->has_wonder_prereqs = true; - } else { - def->wonder_prereq_count = 0; - def->has_wonder_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "natural_wonder_prereqs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->natural_wonder_prereqs, - ARRAY_LEN (def->natural_wonder_prereqs), - &list_count, - parse_errors, - line_number, - "natural_wonder_prereqs")) { - def->natural_wonder_prereq_count = list_count; - def->has_natural_wonder_prereqs = true; - } else { - def->natural_wonder_prereq_count = 0; - def->has_natural_wonder_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_on_districts")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_on_districts, - ARRAY_LEN (def->buildable_on_districts), - &list_count, - parse_errors, - line_number, - "buildable_on_districts")) { - def->buildable_on_district_count = list_count; - def->has_buildable_on_districts = true; - } else { - def->buildable_on_district_count = 0; - def->has_buildable_on_districts = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_adjacent_to_districts")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_adjacent_to_districts, - ARRAY_LEN (def->buildable_adjacent_to_districts), - &list_count, - parse_errors, - line_number, - "buildable_adjacent_to_districts")) { - def->buildable_adjacent_to_district_count = list_count; - def->has_buildable_adjacent_to_districts = true; - } else { - def->buildable_adjacent_to_district_count = 0; - def->has_buildable_adjacent_to_districts = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civs, - ARRAY_LEN (def->buildable_by_civs), - &list_count, - parse_errors, - line_number, - "buildable_by_civs")) { - def->buildable_by_civ_count = list_count; - def->has_buildable_by_civs = true; - } else { - def->buildable_by_civ_count = 0; - def->has_buildable_by_civs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_traits")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_traits, - ARRAY_LEN (def->buildable_by_civ_traits), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_traits")) { - def->buildable_by_civ_traits_count = list_count; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - char const * trait_name = def->buildable_by_civ_traits[i]; - if ((trait_name == NULL) || (trait_name[0] == '\0')) - continue; - int trait_id = -1; - struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; - if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { - if (def->buildable_by_civ_traits_ids[k] == trait_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) - def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->has_buildable_by_civ_traits = true; - } else { - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - def->has_buildable_by_civ_traits = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_govs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_govs, - ARRAY_LEN (def->buildable_by_civ_govs), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_govs")) { - def->buildable_by_civ_govs_count = list_count; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - char const * gov_name = def->buildable_by_civ_govs[i]; - if ((gov_name == NULL) || (gov_name[0] == '\0')) - continue; - int gov_id = -1; - struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; - if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { - if (def->buildable_by_civ_govs_ids[k] == gov_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) - def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->has_buildable_by_civ_govs = true; - } else { - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - def->has_buildable_by_civ_govs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_cultures, - ARRAY_LEN (def->buildable_by_civ_cultures), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_cultures")) { - def->buildable_by_civ_cultures_count = list_count; - def->buildable_by_civ_cultures_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - char const * culture_name = def->buildable_by_civ_cultures[i]; - if ((culture_name == NULL) || (culture_name[0] == '\0')) - continue; - int culture_id = -1; - struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; - if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { - if (def->buildable_by_civ_cultures_ids[k] == culture_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) - def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->has_buildable_by_civ_cultures = true; - } else { - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - def->has_buildable_by_civ_cultures = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_war_allies")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_by_war_allies = (ival != 0); - def->has_buildable_by_war_allies = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "buildable_by_pact_allies")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_by_pact_allies = (ival != 0); - def->has_buildable_by_pact_allies = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "img_paths")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->img_paths, - ARRAY_LEN (def->img_paths), - &list_count, - parse_errors, - line_number, - "img_paths")) { - def->img_path_count = list_count; - def->has_img_paths = true; - } else { - def->img_path_count = 0; - def->has_img_paths = false; - } - free (value_text); - - } else if (slice_matches_str (key, "img_column_count")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_column_count = ival; - def->has_img_column_count = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "dependent_improvs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->dependent_improvements, - ARRAY_LEN (def->dependent_improvements), - &list_count, - parse_errors, - line_number, - "dependent_improvs")) { - def->dependent_improvement_max_index = list_count; - def->has_dependent_improvements = true; - } else { - def->dependent_improvement_max_index = 0; - def->has_dependent_improvements = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_on")) { - unsigned int mask; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { - def->buildable_square_types_mask = mask; - def->has_buildable_on = true; - } - - } else if (slice_matches_str (key, "buildable_without_removal")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_without_removal")) { - def->buildable_without_removal_mask = mask; - def->has_buildable_without_removal = true; - } else { - def->has_buildable_without_removal = false; - } - - } else if (slice_matches_str (key, "buildable_on_overlays")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_on_overlays")) { - def->buildable_on_overlays_mask = mask; - def->has_buildable_on_overlays = true; - } else { - def->has_buildable_on_overlays = false; - } - - } else if (slice_matches_str (key, "buildable_on_rivers")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_on_rivers = (ival != 0); - def->has_buildable_on_rivers = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "buildable_adjacent_to")) { - unsigned int mask; - def->buildable_adjacent_to_allows_city = false; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { - def->buildable_adjacent_to_square_types_mask = mask; - def->has_buildable_adjacent_to = true; - } - - } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { - def->buildable_adjacent_to_overlays_mask = mask; - def->has_buildable_adjacent_to_overlays = true; - } else { - def->has_buildable_adjacent_to_overlays = false; - } - - } else if (slice_matches_str (key, "allow_multiple")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->allow_multiple = (ival != 0); - def->has_allow_multiple = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "vary_img_by_era")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->vary_img_by_era = (ival != 0); - def->has_vary_img_by_era = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "vary_img_by_culture")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->vary_img_by_culture = (ival != 0); - def->has_vary_img_by_culture = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "render_strategy")) { - char * strategy = copy_trimmed_string_or_null (value, 1); - if (strategy == NULL) { - def->has_render_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else if (strcmp (strategy, "by-count") == 0) { - def->render_strategy = DRS_BY_COUNT; - def->has_render_strategy = true; - } else if (strcmp (strategy, "by-building") == 0) { - def->render_strategy = DRS_BY_BUILDING; - def->has_render_strategy = true; - } else { - def->has_render_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected \"by-count\" or \"by-building\")"); - } - if (strategy != NULL) - free (strategy); - - } else if (slice_matches_str (key, "ai_build_strategy")) { - char * strategy = copy_trimmed_string_or_null (value, 1); - if (strategy == NULL) { - def->has_ai_build_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else if (strcmp (strategy, "district") == 0) { - def->ai_build_strategy = DABS_DISTRICT; - def->has_ai_build_strategy = true; - } else if (strcmp (strategy, "tile-improvement") == 0) { - def->ai_build_strategy = DABS_TILE_IMPROVEMENT; - def->has_ai_build_strategy = true; - } else { - def->has_ai_build_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected \"district\" or \"tile-improvement\")"); - } - if (strategy != NULL) - free (strategy); - - } else if (slice_matches_str (key, "align_to_coast")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->align_to_coast = (ival != 0); - def->has_align_to_coast = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "draw_over_resources")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->draw_over_resources = (ival != 0); - def->has_draw_over_resources = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "allow_irrigation_from")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->allow_irrigation_from = (ival != 0); - def->has_allow_irrigation_from = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "auto_add_road")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->auto_add_road = (ival != 0); - def->has_auto_add_road = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "auto_add_railroad")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->auto_add_railroad = (ival != 0); - def->has_auto_add_railroad = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "impassible")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible = (ival != 0); - def->has_impassible = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "impassible_to_wheeled")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible_to_wheeled = (ival != 0); - def->has_impassible_to_wheeled = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "custom_width")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_width = ival; - def->has_custom_width = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "custom_height")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_height = ival; - def->has_custom_height = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "x_offset")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->x_offset = ival; - def->has_x_offset = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "y_offset")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->y_offset = ival; - def->has_y_offset = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "btn_tile_sheet_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->btn_tile_sheet_column = ival; - def->has_btn_tile_sheet_column = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "btn_tile_sheet_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->btn_tile_sheet_row = ival; - def->has_btn_tile_sheet_row = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "defense_bonus_percent")) { - if (parse_district_bonus_entries (value, &def->defense_bonus_percent, &def->defense_bonus_extras, parse_errors, line_number, key)) { - def->has_defense_bonus_percent = true; - } else { - def->has_defense_bonus_percent = false; - } - - } else if (slice_matches_str (key, "heal_units_in_one_turn")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->heal_units_in_one_turn = (ival != 0); - def->has_heal_units_in_one_turn = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "culture_bonus")) { - if (parse_district_bonus_entries (value, &def->culture_bonus, &def->culture_bonus_extras, parse_errors, line_number, key)) { - def->has_culture_bonus = true; - } else { - def->has_culture_bonus = false; - } - - } else if (slice_matches_str (key, "science_bonus")) { - if (parse_district_bonus_entries (value, &def->science_bonus, &def->science_bonus_extras, parse_errors, line_number, key)) { - def->has_science_bonus = true; - } else { - def->has_science_bonus = false; - } - - } else if (slice_matches_str (key, "food_bonus")) { - if (parse_district_bonus_entries (value, &def->food_bonus, &def->food_bonus_extras, parse_errors, line_number, key)) { - def->has_food_bonus = true; - } else { - def->has_food_bonus = false; - } - - } else if (slice_matches_str (key, "gold_bonus")) { - if (parse_district_bonus_entries (value, &def->gold_bonus, &def->gold_bonus_extras, parse_errors, line_number, key)) { - def->has_gold_bonus = true; - } else { - def->has_gold_bonus = false; - } - - } else if (slice_matches_str (key, "shield_bonus")) { - if (parse_district_bonus_entries (value, &def->shield_bonus, &def->shield_bonus_extras, parse_errors, line_number, key)) { - def->has_shield_bonus = true; - } else { - def->has_shield_bonus = false; - } - - } else if (slice_matches_str (key, "happiness_bonus")) { - if (parse_district_bonus_entries (value, &def->happiness_bonus, &def->happiness_bonus_extras, parse_errors, line_number, key)) { - def->has_happiness_bonus = true; - } else { - def->has_happiness_bonus = false; - } - - } else if (slice_matches_str (key, "generated_resource")) { - if (def->generated_resource != NULL) { - free (def->generated_resource); - def->generated_resource = NULL; - } - def->generated_resource_flags = 0; - - char * value_text = trim_and_extract_slice (value, 0); - if ((value_text == NULL) || (*value_text == '\0')) { - def->generated_resource = NULL; - def->has_generated_resource = true; - } else { - char * cursor = value_text; - struct string_slice resource_name = {0}; - struct string_slice token; - bool ok = true; - while (skip_white_space (&cursor) && parse_string (&cursor, &token)) { - if (slice_matches_str (&token, "local")) - def->generated_resource_flags |= MF_LOCAL; - else if (slice_matches_str (&token, "no-tech-req")) - def->generated_resource_flags |= MF_NO_TECH_REQ; - else if (slice_matches_str (&token, "yields")) - def->generated_resource_flags |= MF_YIELDS; - else if (resource_name.str == NULL) - resource_name = token; - else { - ok = false; - break; - } - } - - if (! ok || (resource_name.str == NULL)) { - def->generated_resource = NULL; - def->has_generated_resource = false; - def->generated_resource_flags = 0; - add_key_parse_error (parse_errors, line_number, key, value, - "(expected resource name plus optional flags: local, yields, no-tech-req)"); - } else { - def->generated_resource = extract_slice (&resource_name); - def->has_generated_resource = true; - } - } - free (value_text); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -bool -line_is_empty_or_comment (struct string_slice const * trimmed) -{ - return ((trimmed == NULL) || (trimmed->len == 0) || (trimmed->str[0] == ';') || (trimmed->str[0] == '[')); -} - -bool -file_exists_at_path (char const * path) -{ - if ((path == NULL) || (path[0] == '\0')) - return false; - - HANDLE file = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (file == INVALID_HANDLE_VALUE) - return false; - - CloseHandle (file); - return true; -} - -void -load_dynamic_district_config_file (char const * file_path, - int path_is_relative_to_mod_dir, - int log_missing, - int drop_existing_configs) -{ - char path[MAX_PATH]; - if (path_is_relative_to_mod_dir) { - if (is->mod_rel_dir == NULL) - return; - snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); - } else { - strncpy (path, file_path, sizeof path); - } - path[(sizeof path) - 1] = '\0'; - - char * text = file_to_string (path); - if (text == NULL) { - if (log_missing) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] Districts config file not found: %s", path); - (*p_OutputDebugStringA) (ss); - } - return; - } - - if (drop_existing_configs) - reset_regular_district_configs (); - - struct parsed_district_definition def; - init_parsed_district_definition (&def); - bool in_section = false; - int section_start_line = 0; - int line_number = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - bool has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if ((directive.len > 0) && slice_matches_str (&directive, "District")) { - if (in_section) - finalize_parsed_district_definition (&def, section_start_line); - in_section = true; - section_start_line = line_number; - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); - if (status == KVP_NO_EQUALS) { - char * line_text = extract_slice (&trimmed); - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); - err->text[(sizeof err->text) - 1] = '\0'; - free (line_text); - cursor = has_newline ? line_end + 1 : line_end; - continue; - } else if (status == KVP_EMPTY_KEY) { - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); - err->text[(sizeof err->text) - 1] = '\0'; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - handle_district_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) - finalize_parsed_district_definition (&def, section_start_line); - - free_parsed_district_definition (&def); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - snprintf (is->current_districts_config_path, sizeof is->current_districts_config_path, path); - - if (parse_errors != NULL || unrecognized_keys != NULL) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "District Config errors in %s:", path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - if (parse_errors != NULL) { - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", false); - PopupForm_add_text (popup, __, "Unrecognized keys:", false); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - patch_show_popup (popup, __, 0, 0); - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); - } -} - -void -load_dynamic_district_configs () -{ - char * scenario_filename = "scenario.districts_config.txt"; - char * scenario_district_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - if ((scenario_district_config_path != NULL) && - (0 != strcmp (scenario_filename, scenario_district_config_path)) && - file_exists_at_path (scenario_district_config_path)) { - load_dynamic_district_config_file (scenario_district_config_path, 0, 0, 1); - return; - } - - if (is->mod_rel_dir != NULL) { - char user_path[MAX_PATH]; - snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_config.txt"); - user_path[(sizeof user_path) - 1] = '\0'; - if (file_exists_at_path (user_path)) { - load_dynamic_district_config_file ("user.districts_config.txt", 1, 0, 1); - return; - } - } - - load_dynamic_district_config_file ("default.districts_config.txt", 1, 1, 1); -} - -void -init_parsed_wonder_definition (struct parsed_wonder_definition * def) -{ - memset (def, 0, sizeof *def); - def->buildable_square_types_mask = district_default_buildable_mask (); - def->buildable_adjacent_to_square_types_mask = 0; - def->buildable_adjacent_to_overlays_mask = 0; - def->buildable_on_rivers = false; - def->buildable_adjacent_to_allows_city = false; - for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_traits_ids); i++) - def->buildable_by_civ_traits_ids[i] = -1; - for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_govs_ids); i++) - def->buildable_by_civ_govs_ids[i] = -1; - for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_cultures_ids); i++) - def->buildable_by_civ_cultures_ids[i] = -1; -} - -void -free_parsed_wonder_definition (struct parsed_wonder_definition * def) -{ - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - - for (int i = 0; i < def->buildable_by_civ_count; i++) { - if (def->buildable_by_civs[i] != NULL) { - free (def->buildable_by_civs[i]); - def->buildable_by_civs[i] = NULL; - } - } - def->buildable_by_civ_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - - init_parsed_wonder_definition (def); -} - -bool -add_dynamic_wonder_from_definition (struct parsed_wonder_definition * def, int section_start_line) -{ - int existing_index = -1; - for (int i = 0; i < is->wonder_district_count; i++) { - if ((is->wonder_district_configs[i].wonder_name != NULL) && - (strcmp (is->wonder_district_configs[i].wonder_name, def->name) == 0)) { - existing_index = i; - break; - } - } - - int dest = (existing_index >= 0) ? existing_index : is->wonder_district_count; - if ((dest < 0) || (dest >= MAX_WONDER_DISTRICT_TYPES)) - return false; - - struct wonder_district_config new_cfg; - memset (&new_cfg, 0, sizeof new_cfg); - new_cfg.index = dest; - new_cfg.is_dynamic = true; - new_cfg.wonder_name = strdup (def->name); - new_cfg.img_path = (def->img_path != NULL) ? strdup (def->img_path) : strdup ("Wonders.pcx"); - new_cfg.img_row = def->img_row; - new_cfg.img_column = def->img_column; - new_cfg.img_construct_row = def->img_construct_row; - new_cfg.img_construct_column = def->img_construct_column; - new_cfg.img_alt_dir_construct_row = def->img_alt_dir_construct_row; - new_cfg.img_alt_dir_construct_column = def->img_alt_dir_construct_column; - new_cfg.img_alt_dir_row = def->img_alt_dir_row; - new_cfg.img_alt_dir_column = def->img_alt_dir_column; - new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; - new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; - new_cfg.enable_img_alt_dir = def->enable_img_alt_dir; - new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); - new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; - new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; - new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; - new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; - new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; - const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); - if (new_cfg.buildable_by_civ_count > max_civ_names) - new_cfg.buildable_by_civ_count = max_civ_names; - for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { - new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; - def->buildable_by_civs[i] = NULL; - } - new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; - new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; - const int max_trait_entries = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); - if (new_cfg.buildable_by_civ_traits_id_count > max_trait_entries) - new_cfg.buildable_by_civ_traits_id_count = max_trait_entries; - for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) - new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; - new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; - new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; - const int max_gov_entries = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); - if (new_cfg.buildable_by_civ_govs_id_count > max_gov_entries) - new_cfg.buildable_by_civ_govs_id_count = max_gov_entries; - for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) - new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; - new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; - new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; - const int max_culture_entries = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); - if (new_cfg.buildable_by_civ_cultures_id_count > max_culture_entries) - new_cfg.buildable_by_civ_cultures_id_count = max_culture_entries; - for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) - new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; - new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; - new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; - new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; - - if (existing_index >= 0) { - struct wonder_district_config * cfg = &is->wonder_district_configs[existing_index]; - free_dynamic_wonder_config (cfg); - *cfg = new_cfg; - cfg->index = existing_index; - } else { - struct wonder_district_config * cfg = &is->wonder_district_configs[dest]; - free_dynamic_wonder_config (cfg); - *cfg = new_cfg; - is->wonder_district_count += 1; - } - - return true; -} - -void -finalize_parsed_wonder_definition (struct parsed_wonder_definition * def, - int section_start_line, - struct error_line ** parse_errors) -{ - bool ok = true; - - if ((! def->has_name) || (def->name == NULL)) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_construct_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_row (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_construct_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_column (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (def->enable_img_alt_dir) { - if (! def->has_img_alt_dir_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_row (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_alt_dir_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_column (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_alt_dir_construct_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_row (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_alt_dir_construct_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_column (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - } - - if (ok) - add_dynamic_wonder_from_definition (def, section_start_line); - - free_parsed_wonder_definition (def); -} - -void -handle_wonder_definition_key (struct parsed_wonder_definition * def, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if (slice_matches_str (key, "name")) { - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else { - char * name_copy = extract_slice (&unquoted); - if (name_copy == NULL) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); - } else { - def->name = name_copy; - def->has_name = true; - } - } - - } else if (slice_matches_str (key, "img_path")) { - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_img_path = false; - } else { - char * path_copy = extract_slice (&unquoted); - if (path_copy == NULL) { - def->has_img_path = false; - } else { - def->img_path = path_copy; - def->has_img_path = true; - } - } - - } else if (slice_matches_str (key, "img_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_row = ival; - def->has_img_row = true; - } else { - def->has_img_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_column = ival; - def->has_img_column = true; - } else { - def->has_img_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_construct_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_construct_row = ival; - def->has_img_construct_row = true; - } else { - def->has_img_construct_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_construct_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_construct_column = ival; - def->has_img_construct_column = true; - } else { - def->has_img_construct_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_construct_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_construct_row = ival; - def->has_img_alt_dir_construct_row = true; - } else { - def->has_img_alt_dir_construct_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_construct_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_construct_column = ival; - def->has_img_alt_dir_construct_column = true; - } else { - def->has_img_alt_dir_construct_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_row = ival; - def->has_img_alt_dir_row = true; - } else { - def->has_img_alt_dir_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_column = ival; - def->has_img_alt_dir_column = true; - } else { - def->has_img_alt_dir_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "custom_width")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_width = ival; - def->has_custom_width = true; - } else { - def->has_custom_width = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "custom_height")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_height = ival; - def->has_custom_height = true; - } else { - def->has_custom_height = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "enable_img_alt_dir")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->enable_img_alt_dir = (ival != 0); - def->has_enable_img_alt_dir = true; - } else { - def->has_enable_img_alt_dir = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "buildable_on")) { - unsigned int mask; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { - def->buildable_square_types_mask = mask; - def->has_buildable_on = true; - } else { - def->has_buildable_on = false; - } - - } else if (slice_matches_str (key, "buildable_on_rivers")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_on_rivers = (ival != 0); - def->has_buildable_on_rivers = true; - } else { - def->has_buildable_on_rivers = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "buildable_adjacent_to")) { - unsigned int mask; - def->buildable_adjacent_to_allows_city = false; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { - def->buildable_adjacent_to_square_types_mask = mask; - def->has_buildable_adjacent_to = true; - } else { - def->has_buildable_adjacent_to = false; - } - - } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { - def->buildable_adjacent_to_overlays_mask = mask; - def->has_buildable_adjacent_to_overlays = true; - } else { - def->has_buildable_adjacent_to_overlays = false; - } - - } else if (slice_matches_str (key, "buildable_by_civs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civs, - ARRAY_LEN (def->buildable_by_civs), - &list_count, - parse_errors, - line_number, - "buildable_by_civs")) { - def->buildable_by_civ_count = list_count; - def->has_buildable_by_civs = true; - } else { - def->buildable_by_civ_count = 0; - def->has_buildable_by_civs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_traits")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_traits, - ARRAY_LEN (def->buildable_by_civ_traits), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_traits")) { - def->buildable_by_civ_traits_count = list_count; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - char const * trait_name = def->buildable_by_civ_traits[i]; - if ((trait_name == NULL) || (trait_name[0] == '\0')) - continue; - int trait_id = -1; - struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; - if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { - if (def->buildable_by_civ_traits_ids[k] == trait_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) - def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->has_buildable_by_civ_traits = true; - } else { - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - def->has_buildable_by_civ_traits = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_govs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_govs, - ARRAY_LEN (def->buildable_by_civ_govs), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_govs")) { - def->buildable_by_civ_govs_count = list_count; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - char const * gov_name = def->buildable_by_civ_govs[i]; - if ((gov_name == NULL) || (gov_name[0] == '\0')) - continue; - int gov_id = -1; - struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; - if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { - if (def->buildable_by_civ_govs_ids[k] == gov_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) - def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->has_buildable_by_civ_govs = true; - } else { - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - def->has_buildable_by_civ_govs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_cultures, - ARRAY_LEN (def->buildable_by_civ_cultures), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_cultures")) { - def->buildable_by_civ_cultures_count = list_count; - def->buildable_by_civ_cultures_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - char const * culture_name = def->buildable_by_civ_cultures[i]; - if ((culture_name == NULL) || (culture_name[0] == '\0')) - continue; - int culture_id = -1; - struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; - if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { - if (def->buildable_by_civ_cultures_ids[k] == culture_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) - def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->has_buildable_by_civ_cultures = true; - } else { - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - def->has_buildable_by_civ_cultures = false; - } - free (value_text); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -void -load_dynamic_wonder_config_file (char const * file_path, - int path_is_relative_to_mod_dir, - int log_missing, - int drop_existing_configs) -{ - char path[MAX_PATH]; - if (path_is_relative_to_mod_dir) { - if (is->mod_rel_dir == NULL) - return; - snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); - } else { - strncpy (path, file_path, sizeof path); - } - path[(sizeof path) - 1] = '\0'; - - char * text = file_to_string (path); - if (text == NULL) { - if (log_missing) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] Wonders config file not found: %s", path); - (*p_OutputDebugStringA) (ss); - } - return; - } - - if (drop_existing_configs) - reset_wonder_district_configs (); - - struct parsed_wonder_definition def; - init_parsed_wonder_definition (&def); - bool in_section = false; - int section_start_line = 0; - int line_number = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - bool has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { - if (in_section) - finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); - in_section = true; - section_start_line = line_number; - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); - if (status == KVP_NO_EQUALS) { - char * line_text = extract_slice (&trimmed); - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); - err->text[(sizeof err->text) - 1] = '\0'; - free (line_text); - cursor = has_newline ? line_end + 1 : line_end; - continue; - } else if (status == KVP_EMPTY_KEY) { - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); - err->text[(sizeof err->text) - 1] = '\0'; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - handle_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) - finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); - - free_parsed_wonder_definition (&def); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - - if (parse_errors != NULL || unrecognized_keys != NULL) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "Wonder District Config errors in %s:", path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - if (parse_errors != NULL) { - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", false); - PopupForm_add_text (popup, __, "Unrecognized keys:", false); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - patch_show_popup (popup, __, 0, 0); - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); - } -} - -void -load_dynamic_wonder_configs () -{ - char * scenario_filename = "scenario.districts_wonders_config.txt"; - char * scenario_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - if ((scenario_wonder_config_path != NULL) && - (0 != strcmp (scenario_filename, scenario_wonder_config_path)) && - file_exists_at_path (scenario_wonder_config_path)) { - load_dynamic_wonder_config_file (scenario_wonder_config_path, 0, 0, 1); - return; - } - - if (is->mod_rel_dir != NULL) { - char user_path[MAX_PATH]; - snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_wonders_config.txt"); - user_path[(sizeof user_path) - 1] = '\0'; - if (file_exists_at_path (user_path)) { - load_dynamic_wonder_config_file ("user.districts_wonders_config.txt", 1, 0, 1); - return; - } - } - - load_dynamic_wonder_config_file ("default.districts_wonders_config.txt", 1, 1, 1); -} - -void -init_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) -{ - memset (def, 0, sizeof *def); - def->terrain_type = SQ_Grassland; - def->adjacent_to = (enum SquareTypes)SQ_INVALID; - def->adjacency_dir = DIR_ZERO; -} - -void -free_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) -{ - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - init_parsed_natural_wonder_definition (def); -} - -bool -add_natural_wonder_from_definition (struct parsed_natural_wonder_definition * def, int section_start_line) -{ - if ((def == NULL) || (def->name == NULL)) - return false; - - int existing_index; - bool has_existing = stable_look_up (&is->natural_wonder_name_to_id, def->name, &existing_index); - - int dest = has_existing ? existing_index : is->natural_wonder_count; - if ((dest < 0) || (dest >= MAX_NATURAL_WONDER_DISTRICT_TYPES)) - return false; - - struct natural_wonder_district_config new_cfg; - memset (&new_cfg, 0, sizeof new_cfg); - new_cfg.index = dest; - new_cfg.is_dynamic = true; - new_cfg.adjacent_to = (enum SquareTypes)SQ_INVALID; - new_cfg.adjacency_dir = DIR_ZERO; - - char * name_copy = strdup (def->name); - if (name_copy == NULL) - return false; - new_cfg.name = name_copy; - - char const * img_path_src = def->img_path; - char * img_copy = strdup (img_path_src); - if (img_copy == NULL) { - free (name_copy); - return false; - } - new_cfg.img_path = img_copy; - new_cfg.img_row = def->img_row; - new_cfg.img_column = def->img_column; - new_cfg.terrain_type = def->terrain_type; - new_cfg.adjacent_to = def->adjacent_to; - new_cfg.adjacency_dir = def->adjacency_dir; - new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; - new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; - new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; - new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; - new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; - new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; - new_cfg.impassible = def->has_impassible ? def->impassible : false; - new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; - - if (has_existing) { - struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[existing_index]; - free_dynamic_natural_wonder_config (cfg); - *cfg = new_cfg; - } else { - struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[dest]; - free_dynamic_natural_wonder_config (cfg); - *cfg = new_cfg; - is->natural_wonder_count = dest + 1; - stable_insert (&is->natural_wonder_name_to_id, new_cfg.name, dest); - } - - return true; -} - -void -finalize_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def, - int section_start_line, - struct error_line ** parse_errors) -{ - bool ok = true; - - if ((! def->has_name) || (def->name == NULL)) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_terrain_type) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: terrain_type (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - if (ok) - add_natural_wonder_from_definition (def, section_start_line); - - free_parsed_natural_wonder_definition (def); -} - -void -handle_natural_wonder_definition_key (struct parsed_natural_wonder_definition * def, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if (slice_matches_str (key, "name")) { - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else { - char * name_copy = extract_slice (&unquoted); - if (name_copy == NULL) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); - } else { - def->name = name_copy; - def->has_name = true; - } - } - - } else if (slice_matches_str (key, "terrain_type")) { - enum SquareTypes terrain; - if (read_natural_wonder_terrain_type (value, &terrain)) { - def->terrain_type = terrain; - def->has_terrain_type = true; - } else { - def->has_terrain_type = false; - add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized terrain type)"); - } - - } else if (slice_matches_str (key, "adjacent_to")) { - enum SquareTypes adj; - if (read_tile_terrain_type_value (value, &adj)) { - def->adjacent_to = adj; - def->has_adjacent_to = true; - } else { - def->adjacent_to = (enum SquareTypes)SQ_INVALID; - def->has_adjacent_to = false; - add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized tile terrain type)"); - } - - } else if (slice_matches_str (key, "adjacency_dir")) { - enum direction dir; - if (read_direction_value (value, &dir)) { - def->adjacency_dir = dir; - def->has_adjacency_dir = true; - } else { - def->adjacency_dir = DIR_ZERO; - def->has_adjacency_dir = false; - add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized direction)"); - } - - } else if (slice_matches_str (key, "img_path")) { - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_img_path = false; - } else { - char * path_copy = extract_slice (&unquoted); - if (path_copy == NULL) { - def->has_img_path = false; - } else { - def->img_path = path_copy; - def->has_img_path = true; - } - } - - } else if (slice_matches_str (key, "img_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_row = ival; - def->has_img_row = true; - } else { - def->has_img_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_column = ival; - def->has_img_column = true; - } else { - def->has_img_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "culture_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->culture_bonus = ival; - def->has_culture_bonus = true; - } else { - def->has_culture_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "science_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->science_bonus = ival; - def->has_science_bonus = true; - } else { - def->has_science_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "food_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->food_bonus = ival; - def->has_food_bonus = true; - } else { - def->has_food_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "gold_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->gold_bonus = ival; - def->has_gold_bonus = true; - } else { - def->has_gold_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "shield_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->shield_bonus = ival; - def->has_shield_bonus = true; - } else { - def->has_shield_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "happiness_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->happiness_bonus = ival; - def->has_happiness_bonus = true; - } else { - def->has_happiness_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "impassible")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible = (ival != 0); - def->has_impassible = true; - } else { - def->has_impassible = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "impassible_to_wheeled")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible_to_wheeled = (ival != 0); - def->has_impassible_to_wheeled = true; - } else { - def->has_impassible_to_wheeled = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -void -load_natural_wonder_config_file (char const * file_path, - int path_is_relative_to_mod_dir, - int log_missing, - int drop_existing_configs) -{ - char path[MAX_PATH]; - if (path_is_relative_to_mod_dir) { - if (is->mod_rel_dir == NULL) - return; - snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); - } else { - strncpy (path, file_path, sizeof path); - } - path[(sizeof path) - 1] = '\0'; - - char * text = file_to_string (path); - if (text == NULL) { - if (log_missing) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] Natural wonders config file not found: %s", path); - (*p_OutputDebugStringA) (ss); - } - return; - } - - if (drop_existing_configs) - reset_natural_wonder_configs (); - - struct parsed_natural_wonder_definition def; - init_parsed_natural_wonder_definition (&def); - bool in_section = false; - int section_start_line = 0; - int line_number = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - bool has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { - if (in_section) - finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); - in_section = true; - section_start_line = line_number; - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); - if (status == KVP_NO_EQUALS) { - char * line_text = extract_slice (&trimmed); - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); - err->text[(sizeof err->text) - 1] = '\0'; - free (line_text); - cursor = has_newline ? line_end + 1 : line_end; - continue; - } else if (status == KVP_EMPTY_KEY) { - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); - err->text[(sizeof err->text) - 1] = '\0'; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - handle_natural_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) - finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); - - free_parsed_natural_wonder_definition (&def); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - - if (parse_errors != NULL || unrecognized_keys != NULL) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "Natural Wonder Config errors in %s:", path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - if (parse_errors != NULL) { - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", false); - PopupForm_add_text (popup, __, "Unrecognized keys:", false); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - patch_show_popup (popup, __, 0, 0); - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); - } -} - -void -load_natural_wonder_configs () -{ - char * scenario_filename = "scenario.districts_natural_wonders_config.txt"; - char * scenario_natural_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - if ((scenario_natural_wonder_config_path != NULL) && - (0 != strcmp (scenario_filename, scenario_natural_wonder_config_path)) && - file_exists_at_path (scenario_natural_wonder_config_path)) { - load_natural_wonder_config_file (scenario_natural_wonder_config_path, 0, 0, 1); - return; - } - - if (is->mod_rel_dir != NULL) { - char user_path[MAX_PATH]; - snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_natural_wonders_config.txt"); - user_path[(sizeof user_path) - 1] = '\0'; - if (file_exists_at_path (user_path)) { - load_natural_wonder_config_file ("user.districts_natural_wonders_config.txt", 1, 0, 1); - return; - } - } - - load_natural_wonder_config_file ("default.districts_natural_wonders_config.txt", 1, 1, 1); -} - -bool -district_config_has_dependent_improvement (struct district_config * cfg, char const * name) -{ - if ((cfg == NULL) || (name == NULL) || (name[0] == '\0')) - return false; - - for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { - char const * existing = cfg->dependent_improvements[i]; - if ((existing != NULL) && (strcmp (existing, name) == 0)) - return true; - } - return false; -} - -bool -find_civ_trait_id_by_name (struct string_slice const * name, int * out_id) -{ - if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) - return false; - - struct trait_entry { enum c3x_label label; char const * fallback_name; int id; } traits[] = { - {CL_AGRICULTURAL, "Agricultural", 6}, - {CL_COMMERCIAL, "Commercial", 1}, - {CL_EXPANSIONIST, "Expansionist", 2}, - {CL_INDUSTRIOUS, "Industrious", 5}, - {CL_MILITARISTIC, "Militaristic", 0}, - {CL_RELIGIOUS, "Religious", 4}, - {CL_SCIENTIFIC, "Scientific", 3}, - {CL_SEAFARING, "Seafaring", 7} - }; - - for (int i = 0; i < ARRAY_LEN (traits); i++) { - char const * localized_name = is->c3x_labels[traits[i].label]; - if (((localized_name != NULL) && (localized_name[0] != '\0') && slice_matches_str (name, localized_name)) - || slice_matches_str (name, traits[i].fallback_name)) { - *out_id = traits[i].id; - return true; - } - } - - return false; -} - -bool -find_civ_culture_id_by_name (struct string_slice const * name, int * out_id) -{ - if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) - return false; - - struct culture_entry { char const * name; int id; } cultures[] = { - {"American", 0}, - {"AMERICAN", 0}, - {"AMER", 0}, - {"European", 1}, - {"EUROPEAN", 1}, - {"EURO", 1}, - {"Roman", 2}, - {"ROMAN", 2}, - {"Mid East", 3}, - {"Mideast", 3}, - {"MIDEAST", 3}, - {"Asian", 4}, - {"ASIAN", 4} - }; - - for (int i = 0; i < ARRAY_LEN (cultures); i++) { - if (slice_matches_str (name, cultures[i].name)) { - *out_id = cultures[i].id; - return true; - } - } - - return false; -} - -int -find_district_index_by_name (char const * name) -{ - if ((name == NULL) || (name[0] == '\0')) - return -1; - - for (int i = 0; i < is->district_count; i++) { - char const * existing = is->district_configs[i].name; - if ((existing != NULL) && (strcmp (existing, name) == 0)) - return i; - } - - return -1; -} - -int -find_wonder_district_index_by_name (char const * name) -{ - if ((name == NULL) || (name[0] == '\0')) - return -1; - - int improv_id; - if (! stable_look_up (&is->building_name_to_id, (char *)name, &improv_id)) - return -1; - - return find_wonder_config_index_by_improvement_id (improv_id); -} - -int -find_natural_wonder_index_by_name (char const * name) -{ - if ((name == NULL) || (name[0] == '\0') || (is == NULL)) - return -1; - - for (int i = 0; i < is->natural_wonder_count; i++) { - char const * existing = is->natural_wonder_configs[i].name; - if ((existing != NULL) && (strcmp (existing, name) == 0)) - return i; - } - return -1; -} - -void -set_wonders_dependent_on_wonder_district (void) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_wonder_districts) - return; - - struct district_config * cfg = &is->district_configs[WONDER_DISTRICT_ID]; - for (int wi = 0; wi < is->wonder_district_count; wi++) { - char const * wonder_name = is->wonder_district_configs[wi].wonder_name; - if ((wonder_name == NULL) || (wonder_name[0] == '\0')) - continue; - if (district_config_has_dependent_improvement (cfg, wonder_name)) - continue; - - int dest = cfg->dependent_improvement_max_index; - if (dest >= ARRAY_LEN (cfg->dependent_improvements)) { - continue; - } - - char * copy = strdup (wonder_name); - if (copy == NULL) { - continue; - } - - cfg->dependent_improvements[dest] = copy; - cfg->dependent_improvement_max_index = dest + 1; - } - - if (! cfg->has_img_column_count_override && - (cfg->img_column_count < cfg->dependent_improvement_max_index + 1)) - cfg->img_column_count = cfg->dependent_improvement_max_index + 1; -} - -void -resolve_district_bonus_building_entries (struct district_bonus_list * list, - char const * district_name, - char const * bonus_name, - struct error_line ** parse_errors) -{ - if (list == NULL) - return; - - for (int i = 0; i < list->count; i++) { - struct district_bonus_entry * entry = &list->entries[i]; - if (entry->type != DBET_BUILDING) - continue; - if ((entry->building_name == NULL) || (entry->building_name[0] == '\0')) { - entry->building_id = -1; - continue; - } - - int improv_id; - struct string_slice improv_name = { .str = (char *)entry->building_name, .len = (int)strlen (entry->building_name) }; - if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { - entry->building_id = improv_id; - stable_insert (&is->building_name_to_id, improv_name.str, improv_id); - } else { - entry->building_id = -1; - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": %s entry \"%.*s\" not found", - district_name, bonus_name, improv_name.len, improv_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } -} - -void parse_building_and_tech_ids () -{ - struct c3x_config * cfg = &is->current_config; - char ss[200]; - struct error_line * district_parse_errors = NULL; - struct error_line * wonder_parse_errors = NULL; - - cfg->great_wall_auto_build_wonder_improv_id = -1; - if (cfg->enable_districts && - cfg->enable_great_wall_districts && - cfg->auto_build_great_wall_around_territory && - cfg->great_wall_auto_build_wonder_name != NULL && - cfg->great_wall_auto_build_wonder_name[0] != '\0') { - struct string_slice wonder_name = { - .str = cfg->great_wall_auto_build_wonder_name, - .len = strlen (cfg->great_wall_auto_build_wonder_name) - }; - if (! find_improv_id_by_name (&wonder_name, &cfg->great_wall_auto_build_wonder_improv_id)) { - snprintf (ss, sizeof ss, - "Error reading config: The value for \"great_wall_auto_build_wonder_name\" is invalid: \"%s\"", - cfg->great_wall_auto_build_wonder_name); - ss[(sizeof ss) - 1] = '\0'; - pop_up_in_game_error (ss); - } - } - - for (int i = 0; i < is->district_count; i++) { - char const * district_name = (is->district_configs[i].name != NULL) ? is->district_configs[i].name : "District"; - if (! district_is_included_by_final_config (i)) { - is->district_infos[i].advance_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) - is->district_infos[i].advance_prereq_ids[j] = -1; - is->district_infos[i].obsoleted_by_id = -1; - is->district_infos[i].resource_prereq_count = 0; - for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) - is->district_infos[i].resource_prereq_ids[j] = -1; - is->district_infos[i].resource_prereq_on_tile_id = -1; - is->district_infos[i].wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) - is->district_infos[i].wonder_prereq_ids[j] = -1; - is->district_infos[i].natural_wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) - is->district_infos[i].natural_wonder_prereq_ids[j] = -1; - is->district_infos[i].dependent_building_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) - is->district_infos[i].dependent_building_ids[j] = -1; - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) - is->district_configs[i].buildable_on_district_ids[j] = -1; - is->district_configs[i].buildable_on_district_id_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) - is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; - is->district_configs[i].buildable_adjacent_to_district_id_count = 0; - is->district_configs[i].generated_resource_id = -1; - continue; - } - if ((is->district_configs[i].name != NULL) && - (is->district_configs[i].command != 0) && - (is->district_configs[i].command != -1)) - itable_insert (&is->command_id_to_district_id, is->district_configs[i].command, i); - is->district_infos[i].advance_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) - is->district_infos[i].advance_prereq_ids[j] = -1; - is->district_infos[i].obsoleted_by_id = -1; - is->district_infos[i].resource_prereq_count = 0; - for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) - is->district_infos[i].resource_prereq_ids[j] = -1; - is->district_infos[i].resource_prereq_on_tile_id = -1; - is->district_infos[i].wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) - is->district_infos[i].wonder_prereq_ids[j] = -1; - is->district_infos[i].natural_wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) - is->district_infos[i].natural_wonder_prereq_ids[j] = -1; - - // Map advance prereqs to districts - int stored_tech_count = 0; - for (int j = 0; j < is->district_configs[i].advance_prereq_count; j++) { - char const * prereq = is->district_configs[i].advance_prereqs[j]; - if (prereq == NULL || prereq[0] == '\0') - continue; - int tech_id; - struct string_slice tech_name = { .str = (char *)prereq, .len = (int)strlen (prereq) }; - if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { - snprintf (ss, sizeof ss, "Found tech prereq \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); - (*p_OutputDebugStringA) (ss); - if (stored_tech_count < ARRAY_LEN (is->district_infos[i].advance_prereq_ids)) { - is->district_infos[i].advance_prereq_ids[stored_tech_count] = tech_id; - stored_tech_count++; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": advance_prereqs entry \"%.*s\" not found", district_name, tech_name.len, tech_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].advance_prereq_count = stored_tech_count; - - // Map obsoleted_by to tech ID - if (is->district_configs[i].obsoleted_by != NULL && is->district_configs[i].obsoleted_by != "") { - int tech_id; - struct string_slice tech_name = { .str = (char *)is->district_configs[i].obsoleted_by, .len = (int)strlen (is->district_configs[i].obsoleted_by) }; - if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { - snprintf (ss, sizeof ss, "Found tech obsoleted_by \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); - (*p_OutputDebugStringA) (ss); - is->district_infos[i].obsoleted_by_id = tech_id; - } else { - is->district_infos[i].obsoleted_by_id = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": obsoleted_by \"%.*s\" not found", district_name, tech_name.len, tech_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - // Map resource prereqs to districts (multiple resources now supported) - int stored_res_count = 0; - for (int j = 0; j < is->district_configs[i].resource_prereq_count; j++) { - if (is->district_configs[i].resource_prereqs[j] == "" || is->district_configs[i].resource_prereqs[j] == NULL) - continue; - int res_id; - struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereqs[j], .len = (int)strlen (is->district_configs[i].resource_prereqs[j]) }; - if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { - snprintf (ss, sizeof ss, "Found resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); - (*p_OutputDebugStringA) (ss); - if (stored_res_count < ARRAY_LEN (is->district_infos[i].resource_prereq_ids)) { - is->district_infos[i].resource_prereq_ids[stored_res_count] = res_id; - stored_res_count++; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq \"%.*s\" not found", district_name, res_name.len, res_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].resource_prereq_count = stored_res_count; - if (is->district_configs[i].resource_prereq_on_tile != NULL && is->district_configs[i].resource_prereq_on_tile != "") { - int res_id; - struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereq_on_tile, .len = (int)strlen (is->district_configs[i].resource_prereq_on_tile) }; - if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { - snprintf (ss, sizeof ss, "Found on-tile resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); - (*p_OutputDebugStringA) (ss); - is->district_infos[i].resource_prereq_on_tile_id = res_id; - } else { - is->district_infos[i].resource_prereq_on_tile_id = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq_on_tile \"%.*s\" not found", district_name, res_name.len, res_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - int stored_wonder_count = 0; - for (int j = 0; j < is->district_configs[i].wonder_prereq_count; j++) { - if (is->district_configs[i].wonder_prereqs[j] == "" || is->district_configs[i].wonder_prereqs[j] == NULL) - continue; - int improv_id; - struct string_slice wonder_name = { .str = (char *)is->district_configs[i].wonder_prereqs[j], .len = (int)strlen (is->district_configs[i].wonder_prereqs[j]) }; - if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { - if (stored_wonder_count < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids)) { - is->district_infos[i].wonder_prereq_ids[stored_wonder_count] = improv_id; - stored_wonder_count += 1; - } - stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": wonder_prereqs entry \"%.*s\" not found", district_name, wonder_name.len, wonder_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].wonder_prereq_count = stored_wonder_count; - - int stored_natural_wonder_count = 0; - for (int j = 0; j < is->district_configs[i].natural_wonder_prereq_count; j++) { - if (is->district_configs[i].natural_wonder_prereqs[j] == "" || is->district_configs[i].natural_wonder_prereqs[j] == NULL) - continue; - int natural_wonder_id = -1; - char const * name = is->district_configs[i].natural_wonder_prereqs[j]; - if (stable_look_up (&is->natural_wonder_name_to_id, (char *)name, &natural_wonder_id)) { - if (stored_natural_wonder_count < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids)) { - is->district_infos[i].natural_wonder_prereq_ids[stored_natural_wonder_count] = natural_wonder_id; - stored_natural_wonder_count += 1; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": natural_wonder_prereqs entry \"%s\" not found", district_name, name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].natural_wonder_prereq_count = stored_natural_wonder_count; - - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) - is->district_configs[i].buildable_on_district_ids[j] = -1; - is->district_configs[i].buildable_on_district_id_count = 0; - - if (is->district_configs[i].has_buildable_on_districts) { - int stored_buildable_on_count = 0; - for (int j = 0; j < is->district_configs[i].buildable_on_district_count; j++) { - char const * name = is->district_configs[i].buildable_on_districts[j]; - if (name == NULL || name[0] == '\0') - continue; - int other_district_id = find_district_index_by_name (name); - if (other_district_id >= 0) { - if (stored_buildable_on_count < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids)) { - is->district_configs[i].buildable_on_district_ids[stored_buildable_on_count] = other_district_id; - stored_buildable_on_count += 1; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_on_districts entry \"%s\" not found", district_name, name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_configs[i].buildable_on_district_id_count = stored_buildable_on_count; - } - - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) - is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; - is->district_configs[i].buildable_adjacent_to_district_id_count = 0; - - if (is->district_configs[i].has_buildable_adjacent_to_districts) { - int stored_adjacent_count = 0; - for (int j = 0; j < is->district_configs[i].buildable_adjacent_to_district_count; j++) { - char const * name = is->district_configs[i].buildable_adjacent_to_districts[j]; - if (name == NULL || name[0] == '\0') - continue; - int other_district_id = find_district_index_by_name (name); - if (other_district_id >= 0) { - if (stored_adjacent_count < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids)) { - is->district_configs[i].buildable_adjacent_to_district_ids[stored_adjacent_count] = other_district_id; - stored_adjacent_count += 1; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_adjacent_to_districts entry \"%s\" not found", district_name, name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_configs[i].buildable_adjacent_to_district_id_count = stored_adjacent_count; - } - - // Resolve generated resource name to ID - if (is->district_configs[i].generated_resource != NULL && is->district_configs[i].generated_resource != "") { - int res_id; - struct string_slice res_name = { .str = (char *)is->district_configs[i].generated_resource, .len = (int)strlen (is->district_configs[i].generated_resource) }; - if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { - snprintf (ss, sizeof ss, "Found generated resource \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); - (*p_OutputDebugStringA) (ss); - is->district_configs[i].generated_resource_id = res_id; - } else { - is->district_configs[i].generated_resource_id = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": generated_resource \"%.*s\" not found", district_name, res_name.len, res_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - // Map improvement prereqs to districts - int stored_count = 0; - for (int j = 0; j < is->district_configs[i].dependent_improvement_max_index; j++) { - int improv_id; - if (is->district_configs[i].dependent_improvements[j] == "" || is->district_configs[i].dependent_improvements[j] == NULL) - continue; - - // Gate wonder district prereqs behind enable_wonder_districts - if ((is->district_configs[i].command == UCV_Build_WonderDistrict) && (! cfg->enable_wonder_districts)) - continue; - - struct string_slice improv_name = { .str = (char *)is->district_configs[i].dependent_improvements[j], .len = (int)strlen (is->district_configs[i].dependent_improvements[j]) }; - if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { - snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for district \"%s\", ID %d\n", improv_name.len, improv_name.str, district_name, improv_id); - (*p_OutputDebugStringA) (ss); - if (stored_count < ARRAY_LEN (is->district_infos[i].dependent_building_ids)) { - is->district_infos[i].dependent_building_ids[stored_count] = improv_id; - stored_count += 1; - } - add_district_building_prereq (improv_id, i); - stable_insert (&is->building_name_to_id, improv_name.str, improv_id); - } else { - is->district_infos[i].dependent_building_ids[j] = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": dependent_improvs entry \"%.*s\" not found", district_name, improv_name.len, improv_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - is->district_infos[i].dependent_building_count = stored_count; - } - - resolve_district_bonus_building_entries (&is->district_configs[i].culture_bonus_extras, district_name, "culture_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].science_bonus_extras, district_name, "science_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].food_bonus_extras, district_name, "food_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].gold_bonus_extras, district_name, "gold_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].shield_bonus_extras, district_name, "shield_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].happiness_bonus_extras, district_name, "happiness_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].defense_bonus_extras, district_name, "defense_bonus_percent", &district_parse_errors); - } - - // Map wonder names to their improvement IDs for rendering under-construction wonders - for (int wi = 0; wi < is->wonder_district_count; wi++) { - if (is->wonder_district_configs[wi].wonder_name == NULL || is->wonder_district_configs[wi].wonder_name[0] == '\0') - continue; - - int improv_id; - struct string_slice wonder_name = { .str = (char *)is->wonder_district_configs[wi].wonder_name, .len = (int)strlen (is->wonder_district_configs[wi].wonder_name) }; - if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { - snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for wonder district \"%s\", ID %d\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name, improv_id); - (*p_OutputDebugStringA) (ss); - stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); - } else { - snprintf (ss, sizeof ss, "Could not find improvement prereq \"%.*s\" for wonder district \"%s\"\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name); - (*p_OutputDebugStringA) (ss); - struct error_line * err = add_error_line (&wonder_parse_errors); - snprintf (err->text, sizeof err->text, "^ Wonder district \"%s\": improvement \"%.*s\" not found", (is->wonder_district_configs[wi].wonder_name != NULL) ? is->wonder_district_configs[wi].wonder_name : "Wonder District", wonder_name.len, wonder_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - if ((district_parse_errors != NULL) || (wonder_parse_errors != NULL)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - - if (district_parse_errors != NULL) { - char header[256]; - if (is->current_districts_config_path[0] != '\0') - snprintf (header, sizeof header, "District Config errors in %s:", is->current_districts_config_path); - else - snprintf (header, sizeof header, "District Config lookup errors:"); - header[(sizeof header) - 1] = '\0'; - PopupForm_add_text (popup, __, header, false); - for (struct error_line * line = district_parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - - if ((district_parse_errors != NULL) && (wonder_parse_errors != NULL)) - PopupForm_add_text (popup, __, "", false); - - if (wonder_parse_errors != NULL) { - char header[256]; - snprintf (header, sizeof header, "Wonder District Config lookup errors:"); - header[(sizeof header) - 1] = '\0'; - PopupForm_add_text (popup, __, header, false); - for (struct error_line * line = wonder_parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - - patch_show_popup (popup, __, 0, 0); - free_error_lines (district_parse_errors); - free_error_lines (wonder_parse_errors); - } -} - -void -load_districts_config () -{ - clear_dynamic_district_definitions (); - load_dynamic_district_configs (); - load_dynamic_wonder_configs (); - load_natural_wonder_configs (); - is->district_count = is->special_district_count + is->dynamic_district_count; - - set_wonders_dependent_on_wonder_district (); - parse_building_and_tech_ids (); -} - -void -place_natural_wonders_on_map (void) -{ - if (! is->current_config.enable_natural_wonders) - return; - - int wonder_count = is->natural_wonder_count; - if (wonder_count <= 0) - return; - - struct natural_wonder_candidate_list * candidate_lists = (struct natural_wonder_candidate_list *)calloc (wonder_count, sizeof *candidate_lists); - bool * already_placed = (bool *)calloc (wonder_count, sizeof *already_placed); - - if ((candidate_lists == NULL) || (already_placed == NULL)) { - if (candidate_lists != NULL) free (candidate_lists); - if (already_placed != NULL) free (already_placed); - return; - } - - struct wonder_location * placements = NULL; - int placement_count = 0; - int placement_capacity = 0; - int existing_count = 0; - - // Record existing natural wonders - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - - int wonder_id = inst->natural_wonder_info.natural_wonder_id; - if ((wonder_id < 0) || (wonder_id >= wonder_count)) - continue; - - already_placed[wonder_id] = true; - - Tile * tile = (Tile *)tei.key; - int tile_x, tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - continue; - - if (placement_count >= placement_capacity) { - int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; - struct wonder_location * grown = - (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); - if (grown == NULL) - continue; - placements = grown; - placement_capacity = new_capacity; - } - - if (placements != NULL) { - placements[placement_count++] = (struct wonder_location){ - .x = (short)tile_x, - .y = (short)tile_y - }; - existing_count += 1; - } - } - - // Build candidate lists - int map_width = p_bic_data->Map.Width; - int map_height = p_bic_data->Map.Height; - int minimum_separation = is->current_config.minimum_natural_wonder_separation; - - for (int y = 0; y < map_height; y++) { - for (int x = 0; x < map_width; x++) { - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - if (! natural_wonder_tile_is_clear (tile, x, y)) continue; - if (district_exists_within_distance (x, y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; - - for (int ni = 0; ni < wonder_count; ni++) { - if (already_placed[ni]) - continue; - - struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; - if (cfg->name == NULL) - continue; - - if (! natural_wonder_terrain_matches (cfg, tile, x, y)) - continue; - - natural_wonder_candidate_list_push (&candidate_lists[ni], tile, x, y); - } - } - } - - bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; - int newly_placed = 0; - int * wonder_order = (int *)malloc (wonder_count * sizeof *wonder_order); - if (wonder_order != NULL) { - for (int i = 0; i < wonder_count; i++) - wonder_order[i] = i; - for (int i = wonder_count - 1; i > 0; i--) { - int swap_index = rand_int (p_rand_object, __, i + 1); - int temp = wonder_order[i]; - wonder_order[i] = wonder_order[swap_index]; - wonder_order[swap_index] = temp; - } - } - - for (int order_index = 0; order_index < wonder_count; order_index++) { - int ni = (wonder_order != NULL) ? wonder_order[order_index] : order_index; - if (already_placed[ni]) - continue; - - struct natural_wonder_candidate_list * list = &candidate_lists[ni]; - if (list->count == 0) { - char msg[256]; - snprintf (msg, sizeof msg, "[C3X] No valid tiles to place natural wonder \"%s\".\n", - (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); - (*p_OutputDebugStringA) (msg); - continue; - } - - int best_index = -1; - int best_dist = -1; - int best_adjacent_count = -1; - int best_target_diff = INT_MAX; - int best_rand = INT_MAX; - int best_same_type_count = -1; - int best_continent_priority = INT_MAX; - int target_x = (wonder_count > 0) - ? (int)(((long long)(2 * ni + 1) * map_width) / (2 * wonder_count)) - : (map_width >> 1); - - for (int ci = 0; ci < list->count; ci++) { - struct natural_wonder_candidate * cand = &list->entries[ci]; - Tile * tile = cand->tile; - if ((tile == NULL) || (tile == p_null_tile)) continue; - if (get_district_instance (tile) != NULL) continue; - if (! natural_wonder_tile_is_clear (tile, cand->x, cand->y)) continue; - if (! natural_wonder_terrain_matches (&is->natural_wonder_configs[ni], tile, cand->x, cand->y)) continue; - if (district_exists_within_distance (cand->x, cand->y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; - - int min_dist_sq = natural_wonder_min_distance_sq (cand->x, cand->y, placements, placement_count); - if (min_dist_sq == INT_MAX) { - int span = (map_width * map_width) + (map_height * map_height); - if (span <= 0) - span = INT_MAX; - min_dist_sq = span; - } - - int dx_raw = int_abs (cand->x - target_x); - int dx_adjusted = compute_wrapped_component (dx_raw, map_width, wraps_horiz); - int rand_val = rand_int (p_rand_object, __, 0x7FFF); - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - int continent_priority = 1; - if ((continent_id >= 0) && ! continent_has_natural_wonder (continent_id, placements, placement_count)) - continent_priority = 0; - - bool adjacency_bonus_active = - (is->natural_wonder_configs[ni].adjacent_to != (enum SquareTypes)SQ_INVALID) && - (is->natural_wonder_configs[ni].adjacency_dir == DIR_ZERO); - int adjacency_count = -1; - if (adjacency_bonus_active) - adjacency_count = count_adjacent_tiles_of_type (cand->x, cand->y, - is->natural_wonder_configs[ni].adjacent_to); - - int same_type_count = count_adjacent_tiles_of_type (cand->x, cand->y, - is->natural_wonder_configs[ni].terrain_type); - - bool better = false; - if (continent_priority < best_continent_priority) - better = true; - else if (continent_priority > best_continent_priority) - continue; - - if (! better && adjacency_bonus_active) { - if (adjacency_count > best_adjacent_count) - better = true; - else if (adjacency_count < best_adjacent_count) - continue; - } - - if (! better) { - if (same_type_count > best_same_type_count) - better = true; - else if (same_type_count < best_same_type_count) - continue; - } - - if (! better) { - if ((min_dist_sq > best_dist) || - ((min_dist_sq == best_dist) && (dx_adjusted < best_target_diff)) || - ((min_dist_sq == best_dist) && (dx_adjusted == best_target_diff) && (rand_val < best_rand))) - better = true; - else - continue; - } - - best_dist = min_dist_sq; - best_target_diff = dx_adjusted; - best_rand = rand_val; - best_index = ci; - best_continent_priority = continent_priority; - if (adjacency_bonus_active) - best_adjacent_count = adjacency_count; - best_same_type_count = same_type_count; - } - - if (best_index < 0) { - char msg[256]; - snprintf (msg, sizeof msg, "[C3X] Could not find a suitable tile for natural wonder \"%s\" after filtering.\n", - (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); - (*p_OutputDebugStringA) (msg); - continue; - } - - struct natural_wonder_candidate * chosen = &list->entries[best_index]; - assign_natural_wonder_to_tile (chosen->tile, chosen->x, chosen->y, ni); - - if (placement_count >= placement_capacity) { - int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; - struct wonder_location * grown = - (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); - if (grown != NULL) { - placements = grown; - placement_capacity = new_capacity; - } - } - - if ((placements != NULL) && (placement_count < placement_capacity)) { - placements[placement_count++] = (struct wonder_location){ - .x = chosen->x, - .y = chosen->y - }; - } - - newly_placed += 1; - - char msg[256]; - snprintf (msg, sizeof msg, "[C3X] Placed natural wonder \"%s\" at (%d,%d).\n", - (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder", - chosen->x, chosen->y); - (*p_OutputDebugStringA) (msg); - } - - char summary[256]; - snprintf (summary, sizeof summary, "[C3X] Natural wonder placement complete. Newly placed: %d, already present: %d.\n", - newly_placed, existing_count); - (*p_OutputDebugStringA) (summary); - - for (int ni = 0; ni < wonder_count; ni++) - free (candidate_lists[ni].entries); - free (wonder_order); - free (candidate_lists); - free (already_placed); - free (placements); -} - -void -init_scenario_district_entry (struct scenario_district_entry * entry) -{ - if (entry == NULL) - return; - - memset (entry, 0, sizeof *entry); -} - -void -init_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) -{ - if (entry == NULL) - return; - - memset (entry, 0, sizeof *entry); -} - -void -free_scenario_district_entry (struct scenario_district_entry * entry) -{ - if (entry == NULL) - return; - - if (entry->district_name != NULL) { - free (entry->district_name); - entry->district_name = NULL; - } - if (entry->wonder_city_name != NULL) { - free (entry->wonder_city_name); - entry->wonder_city_name = NULL; - } - if (entry->wonder_name != NULL) { - free (entry->wonder_name); - entry->wonder_name = NULL; - } - entry->has_coordinates = 0; - entry->has_district_name = 0; - entry->has_wonder_city = 0; - entry->has_wonder_name = 0; -} - -void -free_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) -{ - if (entry == NULL) - return; - - if (entry->name != NULL) { - free (entry->name); - entry->name = NULL; - } - entry->has_coordinates = 0; - entry->has_name = 0; -} - -void -add_scenario_district_error (struct error_line ** parse_errors, - int line_number, - char const * message) -{ - if (message == NULL) - return; - - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s", line_number, message); - err->text[(sizeof err->text) - 1] = '\0'; -} - -int -parse_scenario_district_coordinates (struct string_slice const * value, int * out_x, int * out_y) -{ - if ((value == NULL) || (out_x == NULL) || (out_y == NULL)) - return 0; - - char * text = trim_and_extract_slice (value, 0); - if (text == NULL) - return 0; - - char * cursor = text; - int success = 0; - int x, y; - if (parse_int (&cursor, &x) && - skip_punctuation (&cursor, ',') && - parse_int (&cursor, &y)) { - skip_horiz_space (&cursor); - success = (*cursor == '\0'); - if (success) { - *out_x = x; - *out_y = y; - } - } - - free (text); - return success; -} - -int -finalize_scenario_district_entry (struct scenario_district_entry * entry, - int section_start_line, - struct error_line ** parse_errors) -{ - int success = 1; - if ((entry == NULL) || (parse_errors == NULL)) - return 0; - - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return 1; - } - - if (! entry->has_coordinates) - add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); - if ((! entry->has_district_name) || (entry->district_name == NULL) || (entry->district_name[0] == '\0')) - add_scenario_district_error (parse_errors, section_start_line, "district (value is required)"); - - if ((! entry->has_coordinates) || (! entry->has_district_name) || - (entry->district_name == NULL) || (entry->district_name[0] == '\0')) - success = 0; - - int map_x = entry->tile_x; - int map_y = entry->tile_y; - if (success) { - wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); - Tile * tile = tile_at (map_x, map_y); - if ((tile == NULL) || (tile == p_null_tile)) { - add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); - success = 0; - } else { - int district_id = find_district_index_by_name (entry->district_name); - if ((district_id < 0) || (district_id >= is->district_count)) { - char msg[200]; - snprintf (msg, sizeof msg, "district (unrecognized name: \"%s\")", entry->district_name); - add_scenario_district_error (parse_errors, section_start_line, msg); - success = 0; - } else { - if ((district_id == NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_natural_wonders) { - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return 1; - } - if ((district_id != NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_districts) { - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return 1; - } - struct district_instance * inst = ensure_district_instance (tile, district_id, map_x, map_y); - if (inst == NULL) { - add_scenario_district_error (parse_errors, section_start_line, "Failed to create district instance"); - success = 0; - } else { - inst->district_id = district_id; - district_instance_set_coords (inst, map_x, map_y); - inst->state = DS_COMPLETED; - inst->wonder_info.state = WDS_UNUSED; - inst->wonder_info.city = NULL; - inst->wonder_info.city_id = -1; - inst->wonder_info.wonder_index = -1; - inst->natural_wonder_info.natural_wonder_id = -1; - - if (district_id == WONDER_DISTRICT_ID) { - int has_city = entry->has_wonder_city && - (entry->wonder_city_name != NULL) && (entry->wonder_city_name[0] != '\0'); - int has_wonder = entry->has_wonder_name && - (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); - if (! has_city || ! has_wonder) { - add_scenario_district_error (parse_errors, section_start_line, "Wonder district requires both wonder_city and wonder_name"); - success = 0; - } else { - int wonder_index = find_wonder_district_index_by_name (entry->wonder_name); - if (wonder_index < 0) { - char msg[200]; - snprintf (msg, sizeof msg, "wonder_name (unrecognized wonder: \"%s\")", entry->wonder_name); - add_scenario_district_error (parse_errors, section_start_line, msg); - success = 0; - } else { - inst->wonder_info.city = NULL; - inst->wonder_info.city_id = -1; - inst->wonder_info.state = WDS_COMPLETED; - inst->wonder_info.wonder_index = wonder_index; - } - } - } else if (district_id == NATURAL_WONDER_DISTRICT_ID) { - int has_name = entry->has_wonder_name && - (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); - if (! has_name) { - add_scenario_district_error (parse_errors, section_start_line, "Natural Wonder district requires wonder_name"); - success = 0; - } else { - int natural_index = find_natural_wonder_index_by_name (entry->wonder_name); - if (natural_index < 0) { - char msg[200]; - snprintf (msg, sizeof msg, "wonder_name (unrecognized natural wonder: \"%s\")", entry->wonder_name); - add_scenario_district_error (parse_errors, section_start_line, msg); - success = 0; - } else - inst->natural_wonder_info.natural_wonder_id = natural_index; - } - if (entry->has_wonder_city) - add_scenario_district_error (parse_errors, section_start_line, "wonder_city ignored for Natural Wonder district entries"); - } else if (entry->has_wonder_city || entry->has_wonder_name) { - add_scenario_district_error (parse_errors, section_start_line, "wonder_* fields only valid for Wonder or Natural Wonder district entries"); - } - - if (success) { - if (district_id != NATURAL_WONDER_DISTRICT_ID && !tile->vtable->m18_Check_Mines (tile, __, 0)) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, map_x, map_y); - set_tile_unworkable_for_all_cities (tile, map_x, map_y); - } - } - } - } - } - - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return success; -} - -bool -tile_can_be_named (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) - return false; - return true; -} - -void -remove_named_tile_entry (Tile * tile) -{ - struct named_tile_entry * entry = get_named_tile_entry (tile); - if (entry == NULL) - return; - itable_remove (&is->named_tile_map, (int)tile); - free (entry); -} - -void -set_named_tile_entry (Tile * tile, int tile_x, int tile_y, char const * name) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return; - if ((name == NULL) || (name[0] == '\0')) { - remove_named_tile_entry (tile); - return; - } - - struct named_tile_entry * entry = get_named_tile_entry (tile); - if (entry == NULL) { - entry = calloc (1, sizeof *entry); - if (entry == NULL) - return; - itable_insert (&is->named_tile_map, (int)tile, (int)entry); - } - entry->tile_x = tile_x; - entry->tile_y = tile_y; - strncpy (entry->name, name, sizeof entry->name); - entry->name[(sizeof entry->name) - 1] = '\0'; -} - -int -finalize_scenario_named_tile_entry (struct scenario_named_tile_entry * entry, - int section_start_line, - struct error_line ** parse_errors) -{ - int success = 1; - if ((entry == NULL) || (parse_errors == NULL)) - return 0; - - if (! is->current_config.enable_named_tiles) { - free_scenario_named_tile_entry (entry); - init_scenario_named_tile_entry (entry); - return 1; - } - - if (! entry->has_coordinates) - add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); - if ((! entry->has_name) || (entry->name == NULL) || (entry->name[0] == '\0')) - add_scenario_district_error (parse_errors, section_start_line, "name (value is required)"); - - if ((! entry->has_coordinates) || (! entry->has_name) || - (entry->name == NULL) || (entry->name[0] == '\0')) - success = 0; - - int map_x = entry->tile_x; - int map_y = entry->tile_y; - if (success) { - wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); - Tile * tile = tile_at (map_x, map_y); - if ((tile == NULL) || (tile == p_null_tile)) { - add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); - success = 0; - } else if (! tile_can_be_named (tile, map_x, map_y)) { - add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile cannot be named)"); - success = 0; - } else { - set_named_tile_entry (tile, map_x, map_y, entry->name); - } - } - - free_scenario_named_tile_entry (entry); - init_scenario_named_tile_entry (entry); - return success; -} - -void -handle_scenario_district_key (struct scenario_district_entry * entry, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if ((entry == NULL) || (key == NULL) || (value == NULL)) - return; - - if (slice_matches_str (key, "coordinates")) { - int x, y; - if (parse_scenario_district_coordinates (value, &x, &y)) { - entry->tile_x = x; - entry->tile_y = y; - entry->has_coordinates = 1; - } else - add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); - - } else if (slice_matches_str (key, "district")) { - if (entry->district_name != NULL) { - free (entry->district_name); - entry->district_name = NULL; - } - entry->district_name = copy_trimmed_string_or_null (value, 1); - entry->has_district_name = (entry->district_name != NULL); - if (! entry->has_district_name) - add_scenario_district_error (parse_errors, line_number, "district (value is required)"); - - } else if (slice_matches_str (key, "wonder_city")) { - if (entry->wonder_city_name != NULL) { - free (entry->wonder_city_name); - entry->wonder_city_name = NULL; - } - entry->wonder_city_name = copy_trimmed_string_or_null (value, 1); - entry->has_wonder_city = (entry->wonder_city_name != NULL); - - } else if (slice_matches_str (key, "wonder_name")) { - if (entry->wonder_name != NULL) { - free (entry->wonder_name); - entry->wonder_name = NULL; - } - entry->wonder_name = copy_trimmed_string_or_null (value, 1); - entry->has_wonder_name = (entry->wonder_name != NULL); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -void -handle_scenario_named_tile_key (struct scenario_named_tile_entry * entry, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if ((entry == NULL) || (key == NULL) || (value == NULL)) - return; - - if (slice_matches_str (key, "coordinates")) { - int x, y; - if (parse_scenario_district_coordinates (value, &x, &y)) { - entry->tile_x = x; - entry->tile_y = y; - entry->has_coordinates = 1; - } else - add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); - - } else if (slice_matches_str (key, "name")) { - if (entry->name != NULL) { - free (entry->name); - entry->name = NULL; - } - entry->name = copy_trimmed_string_or_null (value, 1); - entry->has_name = (entry->name != NULL); - if (! entry->has_name) - add_scenario_district_error (parse_errors, line_number, "name (value is required)"); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -// Parses a .c3x.txt file corresponding to the given scenario file path, loading district instances as specified. -// -// The expected file format itself is very simple. Example: -// -// ``` -// DISTRICTS -// -// #District -// coordinates = 12,28 -// district = Entertainment Complex -// -// #District -// coordinates = 9,23 -// district = Wonder District -// wonder_city = Rome -// wonder_name = The Pyramids -// -// #District -// coordinates = 10,30 -// district = Natural Wonder -// wonder_name = Mount Everest -// -// #NamedTile -// coordinates = 41,23 -// name = Tiber River -// ``` -// -// Details at https://github.com/instafluff0/Civ3_Editor_Fork_for_C3X_Districts -void -load_scenario_districts_from_file () -{ - char * scenario_filename = "scenario.districts.txt"; - char * scenario_districts_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - - // BIC_get_asset_path returns the file name when it can't find the file - if ((scenario_districts_path == NULL) || (0 == strcmp (scenario_filename, scenario_districts_path))) - return; - - char * text = file_to_string (scenario_districts_path); - if (text == NULL) - return; - - struct scenario_district_entry entry; - struct scenario_named_tile_entry named_entry; - init_scenario_district_entry (&entry); - init_scenario_named_tile_entry (&named_entry); - int in_section = 0; - int section_start_line = 0; - int section_type = 0; - int line_number = 0; - int header_seen = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - int has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - // Keep support for legacy header, technically not needed - if (! header_seen) { - if (slice_matches_str (&trimmed, "DISTRICTS")) { - header_seen = 1; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if (slice_matches_str (&directive, "District")) { - if (in_section) { - if (section_type == 1) - finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); - else if (section_type == 2) - finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); - } - in_section = 1; - section_type = 1; - section_start_line = line_number; - free_scenario_district_entry (&entry); - init_scenario_district_entry (&entry); - } else if (slice_matches_str (&directive, "NamedTile")) { - if (in_section) { - if (section_type == 1) - finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); - else if (section_type == 2) - finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); - } - in_section = 1; - section_type = 2; - section_start_line = line_number; - free_scenario_named_tile_entry (&named_entry); - init_scenario_named_tile_entry (&named_entry); - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - switch (parse_trimmed_key_value (&trimmed, &key_slice, &value_slice)) { - case KVP_NO_EQUALS: - add_scenario_district_error (&parse_errors, line_number, "(expected '=')"); - break; - case KVP_EMPTY_KEY: - add_scenario_district_error (&parse_errors, line_number, "(missing key)"); - break; - case KVP_SUCCESS: - if (section_type == 1) - handle_scenario_district_key (&entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - else if (section_type == 2) - handle_scenario_named_tile_key (&named_entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - break; - } - - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) { - if (section_type == 1) - finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); - else if (section_type == 2) - finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); - } - - free_scenario_district_entry (&entry); - free_scenario_named_tile_entry (&named_entry); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (scenario_districts_path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - - if ((parse_errors != NULL) || (unrecognized_keys != NULL)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char header[256]; - snprintf (header, sizeof header, "District scenario file issues in %s:", scenario_districts_path); - header[(sizeof header) - 1] = '\0'; - PopupForm_add_text (popup, __, header, 0); - if (parse_errors != NULL) - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, 0); - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", 0); - PopupForm_add_text (popup, __, "Unrecognized keys:", 0); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, 0); - } - patch_show_popup (popup, __, 0, 0); - } - - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); -} - -void -deinit_district_images (void) -{ - if (is->dc_img_state == IS_OK) { - for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) { - for (int variant = 0; variant < ARRAY_LEN (is->district_img_sets[dc].imgs); variant++) - for (int era = 0; era < 4; era++) - for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc].imgs[variant][era]); col++) { - Sprite * sprite = &is->district_img_sets[dc].imgs[variant][era][col]; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - } - - for (int wi = 0; wi < MAX_WONDER_DISTRICT_TYPES; wi++) { - struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; - if (set->img.vtable != NULL) - set->img.vtable->destruct (&set->img, __, 0); - if (set->construct_img.vtable != NULL) - set->construct_img.vtable->destruct (&set->construct_img, __, 0); - if (set->alt_dir_img.vtable != NULL) - set->alt_dir_img.vtable->destruct (&set->alt_dir_img, __, 0); - if (set->alt_dir_construct_img.vtable != NULL) - set->alt_dir_construct_img.vtable->destruct (&set->alt_dir_construct_img, __, 0); - } - - for (int ni = 0; ni < MAX_NATURAL_WONDER_DISTRICT_TYPES; ni++) { - Sprite * sprite = &is->natural_wonder_img_sets[ni].img; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - - if (is->abandoned_district_img.vtable != NULL) - is->abandoned_district_img.vtable->destruct (&is->abandoned_district_img, __, 0); - if (is->abandoned_maritime_district_img.vtable != NULL) - is->abandoned_maritime_district_img.vtable->destruct (&is->abandoned_maritime_district_img, __, 0); - } - - is->dc_img_state = IS_UNINITED; -} - -void -clear_highlighted_worker_tiles_for_districts () -{ - FOR_TABLE_ENTRIES (tei, &is->highlighted_city_radius_tile_pointers) { - struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)tei.value; - if (info != NULL) - free (info); - } - table_deinit (&is->highlighted_city_radius_tile_pointers); -} - - -void -reset_district_state (bool reset_tile_map) -{ - clear_all_tracked_workers (); - deinit_district_images (); - clear_highlighted_worker_tiles_for_districts (); - - FOR_TABLE_ENTRIES (tei, &is->district_building_prereqs) { - struct district_building_prereq_list * list = (struct district_building_prereq_list *)tei.value; - if (list != NULL) - free (list); - } - table_deinit (&is->district_building_prereqs); - table_deinit (&is->command_id_to_district_id); - stable_deinit (&is->building_name_to_id); - if (reset_tile_map) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst != NULL) - free (inst); - } - table_deinit (&is->district_tile_map); - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if (entry != NULL) - free (entry); - } - table_deinit (&is->named_tile_map); - } - - clear_distribution_hub_tables (); - - is->distribution_hub_totals_dirty = true; - - clear_dynamic_district_definitions (); - is->district_count = is->special_district_count; - - for (int i = 0; i < COUNT_DISTRICT_TYPES; i++) { - is->district_infos[i].advance_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) - is->district_infos[i].advance_prereq_ids[j] = -1; - is->district_infos[i].obsoleted_by_id = -1; - is->district_infos[i].resource_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].resource_prereq_ids); j++) - is->district_infos[i].resource_prereq_ids[j] = -1; - is->district_infos[i].resource_prereq_on_tile_id = -1; - is->district_infos[i].wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) - is->district_infos[i].wonder_prereq_ids[j] = -1; - is->district_infos[i].natural_wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) - is->district_infos[i].natural_wonder_prereq_ids[j] = -1; - is->district_infos[i].dependent_building_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) - is->district_infos[i].dependent_building_ids[j] = -1; - } - - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req != NULL) - free (req); - } - table_deinit (&is->city_pending_district_requests[civ_id]); - } - table_deinit (&is->city_pending_building_orders); - - is->great_wall_auto_build = GWABS_NOT_STARTED; -} - -void -clear_city_district_request (City * city, int district_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (district_id < 0) || (district_id >= is->district_count)) - return; - - struct pending_district_request * req = find_pending_district_request (city, district_id); - if (req == NULL) - return; - - remove_pending_district_request (req); - - int pending_improv_id; - if (look_up_pending_building_order (city, &pending_improv_id)) { - int required_district_id; - if (city_requires_district_for_improvement (city, pending_improv_id, &required_district_id)) { - if (required_district_id == district_id) - forget_pending_building_order (city); - } - } -} - -bool -district_resource_prereqs_met_r (Tile * tile, int tile_x, int tile_y, int district_id, int max_req_resource_id) -{ - if ((tile == NULL) || (tile == p_null_tile) || - (district_id < 0) || (district_id >= is->district_count)) - return false; - - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - struct district_infos * info = &is->district_infos[district_id]; - int on_tile_req = info->resource_prereq_on_tile_id; - if (on_tile_req >= 0) { - int res_here = (owner >= 0) ? Tile_get_resource_visible_to (tile, __, owner) : -1; - if (res_here != on_tile_req) - return false; - } - - // If no resource prereqs, then the check passes - if (info->resource_prereq_count <= 0) - return true; - - if (owner < 0) - return false; - - // Check resource prereqs - ALL must be present - for (int i = 0; i < info->resource_prereq_count; i++) { - int resource_req = info->resource_prereq_ids[i]; - if (resource_req < 0) - continue; - if (resource_req > max_req_resource_id) - return false; - - bool has_resource = false; - bool is_bonus_resource = p_bic_data->ResourceTypes[resource_req].Class == RC_Bonus; - - FOR_CITIES_OF (coi, owner) { - City * req_city = coi.city; - if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, req_city, tile_x, tile_y)) - continue; - if (! city_has_resource_r (req_city, resource_req, max_req_resource_id)) - if (! is_bonus_resource) - continue; - else { - int civ_id = req_city->Body.CivID; - FOR_TILES_AROUND (tai, is->workable_tile_count, req_city->Body.X, req_city->Body.Y) { - Tile * radius_tile = tai.tile; - if ((radius_tile == NULL) || (radius_tile == p_null_tile)) - continue; - if (radius_tile->vtable->m38_Get_Territory_OwnerID (radius_tile) != civ_id) - continue; - if (Tile_get_resource_visible_to (radius_tile, __, civ_id) == resource_req) { - has_resource = true; - break; - } - } - if (has_resource) - break; - continue; - } - - has_resource = true; - break; - } - - // If this required resource is not available, the check fails - if (!has_resource) - return false; - } - - return true; -} - -bool -district_resource_prereqs_met (Tile * tile, int tile_x, int tile_y, int district_id) -{ - return district_resource_prereqs_met_r (tile, tile_x, tile_y, district_id, INT_MAX); -} - -int -count_contiguous_bridge_districts (int tile_x, int tile_y, int dx, int dy) -{ - Map * map = &p_bic_data->Map; - int nx = tile_x + dx; - int ny = tile_y + dy; - int count = 0; - int max_steps = map->Width + map->Height; - - for (int step = 0; step < max_steps; step++) { - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) - break; - count++; - nx += dx; - ny += dy; - } - - return count; -} - -int -count_contiguous_canal_districts (int tile_x, int tile_y, int max_count) -{ - if (max_count <= 0) - return 0; - - Map * map = &p_bic_data->Map; - int limit = max_count + 1; - int capacity = limit; - if (capacity < 1) - capacity = 1; - - int * xs = malloc (sizeof (*xs) * capacity); - int * ys = malloc (sizeof (*ys) * capacity); - if ((xs == NULL) || (ys == NULL)) { - if (xs != NULL) - free (xs); - if (ys != NULL) - free (ys); - return limit; - } - - int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; - int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; - int head = 0; - int tail = 0; - int count = 0; - - xs[tail] = tile_x; - ys[tail] = tile_y; - tail++; - - while (head < tail) { - int cx = xs[head]; - int cy = ys[head]; - head++; - count++; - if (count >= limit) - break; - - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) - continue; - - bool seen = false; - for (int j = 0; j < tail; j++) { - if ((xs[j] == nx) && (ys[j] == ny)) { - seen = true; - break; - } - } - if (seen) - continue; - - if (tail < capacity) { - xs[tail] = nx; - ys[tail] = ny; - tail++; - } else { - count = limit; - head = tail; - break; - } - } - } - - free (xs); - free (ys); - - return count; -} - -bool -district_line_is_straight (int tile_x, int tile_y, int district_id) -{ - Map * map = &p_bic_data->Map; - int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; - int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; - - for (int i = 0; i < 8; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, district_id)) - continue; - - int cand_dx = -adj_dx[i]; - int cand_dy = -adj_dy[i]; - - for (int j = 0; j < 8; j++) { - int ox = nx + adj_dx[j]; - int oy = ny + adj_dy[j]; - wrap_tile_coords (map, &ox, &oy); - if ((ox == tile_x) && (oy == tile_y)) - continue; - if (! tile_has_district_at (ox, oy, district_id)) - continue; - - if (! ((adj_dx[j] == cand_dx) && (adj_dy[j] == cand_dy)) && - ! ((adj_dx[j] == -cand_dx) && (adj_dy[j] == -cand_dy))) - return false; - } - } - - return true; -} - -bool -bridge_district_tile_is_valid (int tile_x, int tile_y) -{ - if (! tile_is_coastal_water (tile_x, tile_y)) - return false; - - bool has_adjacent_land_or_bridge = false; - Map * map = &p_bic_data->Map; - int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; - int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; - - for (int i = 0; i < 8; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (tile_is_land (-1, nx, ny, false) || tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) { - has_adjacent_land_or_bridge = true; - break; - } - } - if (! has_adjacent_land_or_bridge) - return false; - - if (is->current_config.max_contiguous_bridge_districts > 0) { - int max_bridges = is->current_config.max_contiguous_bridge_districts; - - int ns_count = count_contiguous_bridge_districts (tile_x, tile_y, 0, -2) + - count_contiguous_bridge_districts (tile_x, tile_y, 0, 2); - if (ns_count >= max_bridges) - return false; - - int we_count = count_contiguous_bridge_districts (tile_x, tile_y, -2, 0) + - count_contiguous_bridge_districts (tile_x, tile_y, 2, 0); - if (we_count >= max_bridges) - return false; - - int swne_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, 1) + - count_contiguous_bridge_districts (tile_x, tile_y, 1, -1); - if (swne_count >= max_bridges) - return false; - - int nwse_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, -1) + - count_contiguous_bridge_districts (tile_x, tile_y, 1, 1); - if (nwse_count >= max_bridges) - return false; - } - - return district_line_is_straight (tile_x, tile_y, BRIDGE_DISTRICT_ID); -} - -bool -canal_district_tile_is_valid (int tile_x, int tile_y) -{ - if (tile_is_water (tile_x, tile_y)) - return false; - - if (is->current_config.max_contiguous_canal_districts > 0) { - int count = count_contiguous_canal_districts (tile_x, tile_y, is->current_config.max_contiguous_canal_districts); - if (count > is->current_config.max_contiguous_canal_districts) - return false; - } - - Map * map = &p_bic_data->Map; - int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; - int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; - - for (int i = 0; i < 8; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * tile = tile_at (nx, ny); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m35_Check_Is_Water (tile)) - return true; - - if (tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && - district_is_complete (tile, CANAL_DISTRICT_ID)) - return true; - } - } - - return false; -} - -bool -can_build_district_on_tile (Tile * tile, int district_id, int civ_id) -{ - if ((! is->current_config.enable_districts) || - (tile == NULL) || (tile == p_null_tile) || - (tile->CityID >= 0) || - tile->vtable->m21_Check_Crates (tile, __, 0) || - tile->vtable->m20_Check_Pollution (tile, __, 0) || - (district_id < 0) || (district_id >= is->district_count)) - return false; - - struct district_config const * cfg = &is->district_configs[district_id]; - if (cfg->command == -1) - return false; - - if ((cfg->command == UCV_Build_Neighborhood) && !is->current_config.enable_neighborhood_districts) return false; - if ((cfg->command == UCV_Build_WonderDistrict) && !is->current_config.enable_wonder_districts) return false; - if ((cfg->command == UCV_Build_DistributionHub) && !is->current_config.enable_distribution_hub_districts) return false; - if ((cfg->command == UCV_Build_Aerodrome) && !is->current_config.enable_aerodrome_districts) return false; - if ((cfg->command == UCV_Build_Port) && !is->current_config.enable_port_districts) return false; - if ((cfg->command == UCV_Build_Bridge) && !is->current_config.enable_bridge_districts) return false; - if ((cfg->command == UCV_Build_CentralRailHub) && !is->current_config.enable_central_rail_hub_districts) return false; - if ((cfg->command == UCV_Build_EnergyGrid) && !is->current_config.enable_energy_grid_districts) return false; - if ((cfg->command == UCV_Build_GreatWall) && !is->current_config.enable_great_wall_districts) return false; - - if (! district_is_buildable_on_tile (cfg, tile)) - return false; - - int tile_x = 0, tile_y = 0; - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - - if (! leader_can_build_district (&leaders[civ_id], district_id)) - return false; - - if (! district_resource_prereqs_met (tile, tile_x, tile_y, district_id)) - return false; - - if ((district_id == CANAL_DISTRICT_ID) && (! canal_district_tile_is_valid (tile_x, tile_y))) - return false; - - if ((district_id == BRIDGE_DISTRICT_ID) && (! bridge_district_tile_is_valid (tile_x, tile_y))) - return false; - - struct district_instance * existing_inst = get_district_instance (tile); - struct district_infos const * info = &is->district_infos[district_id]; - int existing_district_id = (existing_inst != NULL) ? existing_inst->district_id : -1; - bool district_completed = district_is_complete (tile, existing_district_id); - - if ((existing_district_id == district_id) && district_completed) - return false; - if ((existing_district_id >= 0) && (existing_district_id != district_id) && (! district_completed)) - return false; - - if (! cfg->allow_multiple) { - if (district_exists_within_distance (tile_x, tile_y, district_id, civ_id, is->current_config.city_work_radius)) - return false; - } - - return true; -} - -bool -district_is_obsolete_for_civ (int district_id, int civ_id) -{ - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - int obsolete_id = is->district_infos[district_id].obsoleted_by_id; - if (obsolete_id < 0) - return false; - - return Leader_has_tech (&leaders[civ_id], __, obsolete_id); -} - -bool -tile_has_obsolete_district_for_civ (Tile * tile, int civ_id) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - - int district_id = inst->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - if (! district_is_complete (tile, district_id)) - return false; - - return district_is_obsolete_for_civ (district_id, civ_id); -} - -bool -tile_suitable_for_district (Tile * tile, int district_id, City * city, bool * out_has_resource) -{ - bool has_resource = false; - if ((tile != NULL) && (tile != p_null_tile)) - has_resource = tile_has_resource (tile); - if (out_has_resource != NULL) - *out_has_resource = has_resource; - - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (tile->CityID >= 0) return false; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) return false; - if (! can_build_district_on_tile (tile, district_id, city->Body.CivID)) return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - if (tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - return true; - - // Unused wonder districts can be repurposed, completed cannot - if (district_id == WONDER_DISTRICT_ID && inst->state == DS_COMPLETED) { - struct wonder_district_info * winfo = &inst->wonder_info; - if (winfo->state == WDS_COMPLETED) - return false; - } - - return false; - } - - return true; -} - -bool -can_generate_resource (int for_civ_id, struct mill * mill) -{ - int req_tech_id = (mill->flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[mill->resource_id].RequireID; - return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); -} - -bool -district_can_generate_resource (int for_civ_id, struct district_config * dc) -{ - if (dc->generated_resource_id < 0) - return false; - int req_tech_id = (dc->generated_resource_flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[dc->generated_resource_id].RequireID; - return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); -} - -bool -district_generates_resource_for_civ (Tile * tile, struct district_instance * inst, struct district_config * dc, int civ_id) -{ - if ((tile == NULL) || (tile == p_null_tile) || (inst == NULL) || (dc == NULL)) - return false; - if (inst->state != DS_COMPLETED) - return false; - if (dc->generated_resource_id < 0) - return false; - if (! district_can_generate_resource (civ_id, dc)) - return false; - - int tile_x = 0, tile_y = 0; - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - return district_resource_prereqs_met_r (tile, tile_x, tile_y, inst->district_id, dc->generated_resource_id - 1); -} - -void -calculate_city_center_district_bonus (City * city, int * out_food, int * out_shields, int * out_gold) -{ - if (out_food != NULL) - *out_food = 0; - if (out_shields != NULL) - *out_shields = 0; - if (out_gold != NULL) - *out_gold = 0; - - if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) - return; - - int bonus_food = 0; - int bonus_shields = 0; - int bonus_gold = 0; - - int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - int neighborhoods_counted = 0; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) - continue; - Tile * tile = wai.tile; - - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - if (is->current_config.enable_neighborhood_districts && - (district_id == NEIGHBORHOOD_DISTRICT_ID)) { - if (neighborhoods_counted >= utilized_neighborhoods) - continue; - neighborhoods_counted++; - } - - struct district_config * cfg = &is->district_configs[district_id]; - int food_bonus = 0, shield_bonus = 0, gold_bonus = 0; - get_effective_district_yields (inst, cfg, &food_bonus, &shield_bonus, &gold_bonus, NULL, NULL, NULL); - bonus_food += food_bonus; - bonus_shields += shield_bonus; - bonus_gold += gold_bonus; - - if ((cfg->generated_resource_id >= 0) && (cfg->generated_resource_flags & MF_YIELDS)) { - int res_id = cfg->generated_resource_id; - if (district_generates_resource_for_civ (tile, inst, cfg, city->Body.CivID)) { - Resource_Type * res = &p_bic_data->ResourceTypes[res_id]; - bonus_food += res->Food; - bonus_shields += res->Shield; - bonus_gold += res->Commerce; - } - } - } - - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { - int hub_food = 0; - int hub_shields = 0; - get_distribution_hub_yields_for_city (city, &hub_food, &hub_shields); - bonus_food += hub_food; - bonus_shields += hub_shields; - } - - if (out_food != NULL) - *out_food = bonus_food; - if (out_shields != NULL) - *out_shields = bonus_shields; - if (out_gold != NULL) - *out_gold = bonus_gold; -} - -int __fastcall -patch_Map_calc_food_yield_at (Map * this, int edx, int tile_x, int tile_y, int tile_base_type, int civ_id, int imagine_fully_improved, City * city) -{ - if (! is->current_config.enable_districts) - return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id)) { - return 0; - } - } - - return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); -} - -int __fastcall -patch_Map_calc_shield_yield_at (Map * this, int edx, int tile_x, int tile_y, int civ_id, City * city, int param_5, int param_6) -{ - if (! is->current_config.enable_districts) - return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id)) { - return 0; - } - } - - return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); -} - -int -compute_city_tile_yield_sum (City * city, int tile_x, int tile_y) -{ - if (city == NULL) - return 0; - int food = City_calc_tile_yield_at (city, __, YK_FOOD, tile_x, tile_y); - int shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, tile_x, tile_y); - int commerce = City_calc_tile_yield_at (city, __, YK_COMMERCE, tile_x, tile_y); - return food + shields + commerce; -} - -int * -get_water_continent_ids_connected_via_canal (Tile * tile, int * out_count) -{ - if (out_count != NULL) - *out_count = 0; - if (! is->current_config.enable_canal_districts) - return NULL; - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - if (! tile->vtable->m35_Check_Is_Water (tile)) - return NULL; - - int origin_continent_id = tile->vtable->m46_Get_ContinentID (tile); - int continent_count = p_bic_data->Map.Continent_Count; - if ((origin_continent_id < 0) || (origin_continent_id >= continent_count)) - return NULL; - - Map * map = &p_bic_data->Map; - int tile_count = map->TileCount; - if (tile_count <= 0) - return NULL; - - // Use a BFS over completed canal tiles, starting from those touching the origin water body. - int * queue_xs = malloc (sizeof (*queue_xs) * tile_count); - int * queue_ys = malloc (sizeof (*queue_ys) * tile_count); - int * ids = malloc (sizeof (*ids) * continent_count); - bool * seen = calloc (continent_count, sizeof (*seen)); - if ((queue_xs == NULL) || (queue_ys == NULL) || (ids == NULL) || (seen == NULL)) { - if (queue_xs != NULL) - free (queue_xs); - if (queue_ys != NULL) - free (queue_ys); - if (ids != NULL) - free (ids); - if (seen != NULL) - free (seen); - return NULL; - } - - seen[origin_continent_id] = true; - - int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; - int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; - int head = 0; - int tail = 0; - - // Seed queue with completed canal districts adjacent to the origin water body. - for (int index = 0; index < tile_count; index++) { - Tile * cand = Map_get_tile (map, __, index); - if ((cand == NULL) || (cand == p_null_tile)) - continue; - - int cx = 0, cy = 0; - tile_index_to_coords (map, index, &cx, &cy); - if (! tile_has_district_at (cx, cy, CANAL_DISTRICT_ID)) - continue; - - struct district_instance * inst = get_district_instance (cand); - if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || - (! district_is_complete (cand, CANAL_DISTRICT_ID))) - continue; - - bool adjacent_to_origin = false; - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (! adj->vtable->m35_Check_Is_Water (adj)) - continue; - int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); - if (adj_continent_id == origin_continent_id) { - adjacent_to_origin = true; - break; - } - } - if (! adjacent_to_origin) - continue; - - bool seen_canal = false; - for (int j = 0; j < tail; j++) { - if ((queue_xs[j] == cx) && (queue_ys[j] == cy)) { - seen_canal = true; - break; - } - } - if (! seen_canal && (tail < tile_count)) { - queue_xs[tail] = cx; - queue_ys[tail] = cy; - tail++; - } - } - - int id_count = 0; - - while (head < tail) { - int cx = queue_xs[head]; - int cy = queue_ys[head]; - head++; - - // Record all water bodies adjacent to this canal tile. - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (! adj->vtable->m35_Check_Is_Water (adj)) - continue; - - int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); - if ((adj_continent_id < 0) || (adj_continent_id >= continent_count)) - continue; - if (! seen[adj_continent_id]) { - seen[adj_continent_id] = true; - ids[id_count] = adj_continent_id; - id_count++; - } - } - - // Traverse to neighboring completed canal districts. - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) - continue; - - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (adj); - if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || (! district_is_complete (adj, CANAL_DISTRICT_ID))) - continue; - - bool seen_canal = false; - for (int j = 0; j < tail; j++) { - if ((queue_xs[j] == nx) && (queue_ys[j] == ny)) { - seen_canal = true; - break; - } - } - if (! seen_canal && (tail < tile_count)) { - queue_xs[tail] = nx; - queue_ys[tail] = ny; - tail++; - } - } - } - - free (queue_xs); - free (queue_ys); - free (seen); - - if (out_count != NULL) - *out_count = id_count; - if (id_count <= 0) { - free (ids); - return NULL; - } - - return ids; -} - -Tile * -find_tile_for_neighborhood_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - - // Search in order: ring 1, then rings 2..N - // Ring order array: 1, 2, 3, ..., city_work_radius - int ring_order[8]; - int ring_count = 0; - for (int r = 1; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - - Tile * best_tile = NULL; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - bool has_resource = false; - if (is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - continue; - } - - if (! tile_suitable_for_district (tile, NEIGHBORHOOD_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - if (get_district_instance (tile) != NULL && - ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -find_tile_for_port_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - int threshold_for_body_of_water = 21; // Mimic vanilla behavior so AI doesn't build ports in small lakes - - // Search in order: ring 1, then rings 2..N - int ring_order[8]; - int ring_count = 0; - for (int r = 1; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - - Tile * best_tile = NULL; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - bool has_resource = false; - if (is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - continue; - } - - if (! tile_suitable_for_district (tile, PORT_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - if (get_district_instance (tile) != NULL && - ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - continue; - if (! tile->vtable->m35_Check_Is_Water (tile)) - continue; - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - bool large_enough_body = (continent->Body.TileCount >= threshold_for_body_of_water); - if (! large_enough_body) { - int connected_count = 0; - int * connected_ids = get_water_continent_ids_connected_via_canal (tile, &connected_count); - for (int i = 0; i < connected_count; i++) { - int connected_id = connected_ids[i]; - if ((connected_id < 0) || (connected_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * connected_continent = &p_bic_data->Map.Continents[connected_id]; - if (connected_continent->Body.TileCount >= threshold_for_body_of_water) { - large_enough_body = true; - break; - } - } - if (connected_ids != NULL) - free (connected_ids); - } - if (! large_enough_body) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -find_tile_for_wonder_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - int target_improv_id = -1; - if (look_up_pending_building_order (city, &target_improv_id)) { - if ((target_improv_id < 0) || - (target_improv_id >= p_bic_data->ImprovementsCount) || - ((p_bic_data->Improvements[target_improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0)) - target_improv_id = -1; - } - if (target_improv_id < 0) { - int order_id = city->Body.Order_ID; - if ((city->Body.Order_Type == COT_Improvement) && - (order_id >= 0) && - (order_id < p_bic_data->ImprovementsCount)) { - Improvement * order = &p_bic_data->Improvements[order_id]; - if (order->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - target_improv_id = order_id; - } - } - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - - // Search in order: ring 2, then rings 3..N, then ring 1 as last resort - int ring_order[8]; - int ring_count = 0; - ring_order[ring_count++] = 2; - for (int r = 3; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - ring_order[ring_count++] = 1; - - Tile * best_tile = NULL; - bool has_resource = false; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - if (! tile_suitable_for_district (tile, WONDER_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - if (! wonder_is_buildable_on_tile (tile, target_improv_id)) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -find_tile_for_distribution_hub_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - const int resource_penalty = 100; - const int yield_weight = 40; - const int city_distance_weight = 8; - const int capital_distance_weight = 45; - const int desired_min_capital_distance = 8; - const int proximity_penalty_scale = 300; - const int different_continent_bonus = 500; - - Tile * best_tile = NULL; - int best_score = INT_MIN; - int best_adjusted_yield = INT_MIN; - int best_distance = -1; - int best_distance_to_capital = -1; - bool best_has_resource = true; - - int civ_id = city->Body.CivID; - bool has_capital = false; - int capital_x = 0; - int capital_y = 0; - int capital_continent_id = -1; - - City * capital = get_city_ptr (leaders[civ_id].CapitalID); - if (capital != NULL) { - has_capital = true; - capital_x = capital->Body.X; - capital_y = capital->Body.Y; - Tile * capital_tile = tile_at (capital_x, capital_y); - if ((capital_tile != NULL) && (capital_tile != p_null_tile)) - capital_continent_id = capital_tile->vtable->m46_Get_ContinentID (capital_tile); - } - - FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { - int tx = wai.tile_x, ty = wai.tile_y; - Tile * tile = wai.tile; - bool has_resource; - if (! tile_suitable_for_district (tile, DISTRIBUTION_HUB_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - - int chebyshev = compute_wrapped_chebyshev_distance (tx, ty, city->Body.X, city->Body.Y); - if (chebyshev <= 1) - continue; - - bool too_close_to_existing_hub_or_city = false; - for (int m = 0; m < workable_tile_counts[2]; m++) { - int ndx, ndy; - patch_ni_to_diff_for_work_area (m, &ndx, &ndy); - int nx = tx + ndx, ny = ty + ndy; - wrap_tile_coords (&p_bic_data->Map, &nx, &ny); - Tile * nearby_tile = tile_at (nx, ny); - if ((nearby_tile != NULL) && (nearby_tile != p_null_tile)) { - struct district_instance * nearby_inst = get_district_instance (nearby_tile); - if ((nearby_inst != NULL) && - (nearby_inst->district_id == DISTRIBUTION_HUB_DISTRICT_ID) && - district_is_complete (nearby_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { - too_close_to_existing_hub_or_city = true; - break; - } - else if (nearby_tile->CityID >= 0) { - too_close_to_existing_hub_or_city = true; - break; - } - } - } - if (too_close_to_existing_hub_or_city) - continue; - - int raw_yield = compute_city_tile_yield_sum (city, tx, ty); - int adjusted_yield = raw_yield - (has_resource ? resource_penalty : 0); - int distance = compute_wrapped_manhattan_distance (tx, ty, city->Body.X, city->Body.Y); - int distance_to_capital = has_capital - ? compute_wrapped_manhattan_distance (tx, ty, capital_x, capital_y) - : 0; - - int proximity_penalty = 0; - if (has_capital && (distance_to_capital < desired_min_capital_distance)) - proximity_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; - - int continent_bonus = 0; - if ((capital_continent_id >= 0) && (tile != NULL) && (tile != p_null_tile)) { - int tile_continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((tile_continent_id >= 0) && (tile_continent_id != capital_continent_id)) - continent_bonus = different_continent_bonus; - } - - int score = - adjusted_yield * yield_weight + - distance * city_distance_weight + - distance_to_capital * capital_distance_weight - - proximity_penalty + - continent_bonus; - - if ((score > best_score) || - ((score == best_score) && (distance_to_capital > best_distance_to_capital)) || - ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield > best_adjusted_yield)) || - ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance > best_distance)) || - ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance == best_distance) && (! has_resource && best_has_resource))) { - best_tile = tile; - best_score = score; - best_adjusted_yield = adjusted_yield; - best_distance = distance; - best_distance_to_capital = distance_to_capital; - best_has_resource = has_resource; - *out_x = tx; - *out_y = ty; - } - } - - return best_tile; -} - -bool -city_can_build_district (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos const * info = &is->district_infos[district_id]; - - if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) - return false; - - if ((info->resource_prereq_count > 0) || (info->resource_prereq_on_tile_id >= 0)) { - bool resource_prereqs_met = false; - - FOR_TILES_AROUND (tai, is->workable_tile_count, city->Body.X, city->Body.Y) { - Tile * tile = tai.tile; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) - continue; - if (! district_resource_prereqs_met_r (tile, tai.tile_x, tai.tile_y, district_id, INT_MAX)) - continue; - - resource_prereqs_met = true; - break; - } - - if (! resource_prereqs_met) - return false; - } - - // Check if district does not allow multiple and city already has one - if (! cfg->allow_multiple && city_has_required_district (city, district_id)) - return false; - - return true; -} - -bool -leader_has_wonder_prereq (Leader * leader, struct district_infos const * info) -{ - if (info == NULL) - return false; - if (info->wonder_prereq_count <= 0) - return true; - if ((leader == NULL) || (leader->Improvement_Counts == NULL)) - return false; - - for (int i = 0; i < info->wonder_prereq_count; i++) { - int improv_id = info->wonder_prereq_ids[i]; - if (improv_id >= 0 && leader->Improvement_Counts[improv_id] > 0) - return true; - } - - return false; -} - -bool -leader_has_natural_wonder_prereq_in_territory (int civ_id, struct district_infos const * info) -{ - if (info == NULL) - return false; - if (info->natural_wonder_prereq_count <= 0) - return true; - if (! is->current_config.enable_natural_wonders) - return false; - - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - - int wonder_id = inst->natural_wonder_info.natural_wonder_id; - if (wonder_id < 0) - continue; - - bool matches = false; - for (int i = 0; i < info->natural_wonder_prereq_count; i++) { - if (info->natural_wonder_prereq_ids[i] == wonder_id) { - matches = true; - break; - } - } - if (! matches) - continue; - - Tile * tile = (Tile *)tei.key; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; - } - - return false; -} - -int -count_distribution_hubs_for_civ (int civ_id) -{ - int current = 0; - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if ((rec != NULL) && (rec->civ_id == civ_id)) - current++; - } - return current; -} - -bool -leader_can_natively_build_district (Leader * leader, int district_id) -{ - if ((leader == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos const * info = &is->district_infos[district_id]; - - for (int i = 0; i < info->advance_prereq_count; i++) { - int prereq_id = info->advance_prereq_ids[i]; - if ((prereq_id >= 0) && ! Leader_has_tech (leader, __, prereq_id)) - return false; - } - int obsolete_id = info->obsoleted_by_id; - if ((obsolete_id >= 0) && Leader_has_tech (leader, __, obsolete_id)) - return false; - - if (! leader_has_wonder_prereq (leader, info)) - return false; - - if (! leader_has_natural_wonder_prereq_in_territory (leader->ID, info)) - return false; - - if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) { - int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; - if (max_per_100 > 0) { - int city_count = leader->Cities_Count; - int max_allowed = (city_count * max_per_100 + 99) / 100; - if (max_allowed <= 0) - return false; - - int current = count_distribution_hubs_for_civ (leader->ID); - if (current >= max_allowed) - return false; - } - } - - if (cfg->has_buildable_by_civs) { - bool civ_match = false; - if (cfg->buildable_by_civ_count > 0) { - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - for (int i = 0; i < cfg->buildable_by_civ_count; i++) { - char const * civ_name = cfg->buildable_by_civs[i]; - if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; - if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; - if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; - if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; - if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; - } - } - if (! civ_match) - return false; - } - - if (cfg->has_buildable_by_civ_traits) { - if (cfg->buildable_by_civ_traits_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL || race->vtable == NULL) - return false; - bool trait_match = false; - for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { - int trait_id = cfg->buildable_by_civ_traits_ids[i]; - if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { - trait_match = true; - break; - } - } - if (! trait_match) - return false; - } - - if (cfg->has_buildable_by_civ_govs) { - if (cfg->buildable_by_civ_govs_id_count <= 0) - return false; - int gov_id = leader->GovernmentType; - bool gov_match = false; - for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { - if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { - gov_match = true; - break; - } - } - if (! gov_match) - return false; - } - - if (cfg->has_buildable_by_civ_cultures) { - if (cfg->buildable_by_civ_cultures_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - int culture_id = race->CultureGroupID; - bool culture_match = false; - for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { - if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { - culture_match = true; - break; - } - } - if (! culture_match) - return false; - } - - return true; -} - -bool -leader_has_war_ally_district_access (Leader * leader, int district_id) -{ - if (leader == NULL) - return false; - - int self_id = leader->ID; - for (int civ_id = 0; civ_id < 32; civ_id++) { - if (civ_id == self_id) - continue; - Leader * other = &leaders[civ_id]; - if (other->Military_Allies[self_id] != 0 && leader_can_natively_build_district (other, district_id)) - return true; - } - - return false; -} - -bool -leader_has_pact_ally_district_access (Leader * leader, int district_id) -{ - if (leader == NULL) - return false; - - int self_id = leader->ID; - for (int civ_id = 0; civ_id < 32; civ_id++) { - if (civ_id == self_id) - continue; - Leader * other = &leaders[civ_id]; - if (((leader->Relation_Treaties[civ_id] & 1) != 0 && // 1 = peace treaty - (leader->Relation_Treaties[civ_id] & 4) != 0) && // 4 = mutual protection pact - leader_can_natively_build_district (other, district_id)) { - return true; - } - } - - return false; -} - -bool -leader_can_build_district (Leader * leader, int district_id) -{ - bool can_natively_build = leader_can_natively_build_district (leader, district_id); - - if (can_natively_build) - return true; - - struct district_config const * cfg = &is->district_configs[district_id]; - if (cfg->buildable_by_war_allies && leader_has_war_ally_district_access (leader, district_id)) - return true; - if (cfg->buildable_by_pact_allies && leader_has_pact_ally_district_access (leader, district_id)) - return true; - - return can_natively_build; -} - -Tile * -find_tile_for_district (City * city, int district_id, int * out_x, int * out_y) -{ - if ((city == NULL) || (out_x == NULL) || (out_y == NULL)) - return NULL; - if ((district_id < 0) || (district_id >= is->district_count)) - return NULL; - - // Check if city can build this district at all - if (! city_can_build_district (city, district_id)) - return NULL; - - if (district_id == NEIGHBORHOOD_DISTRICT_ID) - return find_tile_for_neighborhood_district (city, out_x, out_y); - if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) - return find_tile_for_distribution_hub_district (city, out_x, out_y); - if (district_id == PORT_DISTRICT_ID) - return find_tile_for_port_district (city, out_x, out_y); - if (district_id == WONDER_DISTRICT_ID) - return find_tile_for_wonder_district (city, out_x, out_y); - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - - // Search in order: ring 2, then rings 3..N, then ring 1 as last resort - // Ring order array: 2, 3, 4, ..., city_work_radius, 1 - int ring_order[8]; - int ring_count = 0; - ring_order[ring_count++] = 2; - for (int r = 3; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - ring_order[ring_count++] = 1; - - Tile * best_tile = NULL; - struct district_config * cfg = &is->district_configs[district_id]; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - bool has_resource = false; - if (is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - continue; - } - - if (! tile_suitable_for_district (tile, district_id, city, &has_resource)) - continue; - if (cfg->resource_prereq_on_tile < 0 && has_resource) - continue; - if (get_district_instance (tile) != NULL && ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -get_completed_district_tile_for_city (City * city, int district_id, int * out_x, int * out_y) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return NULL; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - struct district_instance * inst = wai.district_inst; - - if (inst->district_id != district_id) - continue; - - // For wonder districts, filter based on wonder_district_state - if (district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = &inst->wonder_info; - // Must be either unused or under construction by this city - if (info->state == WDS_COMPLETED) - continue; - if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) - continue; - if (info->state == WDS_UNDER_CONSTRUCTION) { - info->city = city; - info->city_id = city->Body.ID; - } - } - - if (out_x != NULL) - *out_x = x; - if (out_y != NULL) - *out_y = y; - return candidate; - } - - return NULL; -} - -bool -tile_has_friendly_aerodrome_district (Tile * tile, int civ_id, bool require_available) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_aerodrome_districts || - (tile == NULL) || - (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != AERODROME_DISTRICT_ID) - return false; - - if (! district_is_complete (tile, AERODROME_DISTRICT_ID)) - return false; - - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (territory_owner != civ_id) - return false; - - if (require_available) { - int usage_mask; - if (itable_look_up (&is->aerodrome_airlift_usage, (int)tile, &usage_mask) && - (usage_mask & (1 << civ_id))) - return false; - } - - return true; -} - -bool -tile_has_friendly_port_district (Tile * tile, int civ_id) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - (tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != PORT_DISTRICT_ID)) - return false; - - if (! district_is_complete (tile, PORT_DISTRICT_ID)) - return false; - - return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; -} - -bool -city_has_required_district (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - if (get_completed_district_tile_for_city (city, district_id, NULL, NULL) != NULL) { - clear_city_district_request (city, district_id); - return true; - } - return false; -} - -bool -city_has_wonder_district_with_no_completed_wonder (City * city, int wonder_improv_id) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - Tile * candidate = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - - struct wonder_district_info * info = get_wonder_district_info (candidate); - bool buildable = wonder_is_buildable_on_tile (candidate, wonder_improv_id); - if (info == NULL) return true; - if (info->state == WDS_COMPLETED) continue; - if (info->state == WDS_UNUSED && buildable) return true; - if (info->state == WDS_UNDER_CONSTRUCTION && buildable && info->city_id == city->Body.ID) { - info->city = city; - return true; // Reserved by this city - } - } - - return false; -} - -int __fastcall patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city); -int __fastcall patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null); -void __fastcall patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3); - - -void __fastcall -patch_Main_Screen_Form_show_map_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) -{ - WITH_PAUSE_FOR_POPUP { - Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, pause); - } -} - -int __cdecl -patch_process_text_for_map_message (char * in, char * out) -{ - if (is->map_message_text_override != NULL) { - strcpy (out, is->map_message_text_override); - is->map_message_text_override = NULL; - return 0; - } else - return process_text_snippet (in, out); -} - -// Works like show_map_message but takes a bit of text to display instead of a key for script.txt -void -show_map_specific_text (int tile_x, int tile_y, char const * text, bool pause) -{ - is->map_message_text_override = text; - patch_Main_Screen_Form_show_map_message (p_main_screen_form, __, tile_x, tile_y, "LANDCONQUER", pause); // Use any key here. It will be overridden. -} - -bool __fastcall -patch_City_has_improvement (City * this, int edx, int improv_id, bool include_auto_improvements) -{ - bool tr = City_has_improvement (this, __, improv_id, include_auto_improvements); - - // Check if the improvement is provided for free by another human player's wonder if we're in a hotseat game and the config option is on - if ((! tr) && - include_auto_improvements && - is->current_config.share_wonders_in_hotseat && - ((1 << this->Body.CivID) & *p_human_player_bits) && - (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // if we're in a hotseat game - - // Loop over every other human player in the game and check if the city would have the improv if they were its owner - int actual_owner_id = this->Body.CivID; - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != actual_owner_id)) { - this->Body.CivID = n_player; - if (City_has_improvement (this, __, improv_id, include_auto_improvements)) { - tr = true; - break; - } - } - player_bits >>= 1; - n_player++; - } - this->Body.CivID = actual_owner_id; - - } - - return tr; -} - -int -count_neighborhoods_in_city_radius (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return 0; - - int count = 0; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - struct district_instance * inst = wai.district_inst; - if (inst != NULL && - inst->district_id >= 0 && inst->district_id < is->district_count && - inst->district_id == NEIGHBORHOOD_DISTRICT_ID) - count++; - } - return count; -} - -int -count_utilized_neighborhoods_in_city_radius (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return 0; - - int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; - if (base_cap <= 0) - return 0; - - int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; - if (per_neighborhood <= 0) - return 0; - - int pop = city->Body.Population.Size; - if (pop <= base_cap) - return 0; - - int excess_pop = pop - base_cap; - int utilized = (excess_pop + per_neighborhood - 1) / per_neighborhood; - int total_neighborhoods = count_neighborhoods_in_city_radius (city); - - if (utilized > total_neighborhoods) - utilized = total_neighborhoods; - - return utilized; -} - -int -get_neighborhood_pop_cap (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return -1; - - int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; - if (base_cap <= 0) - return -1; - - int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; - if (per_neighborhood < 0) - per_neighborhood = 0; - - int neighborhoods = count_neighborhoods_in_city_radius (city); - long long cap = (long long)base_cap + (long long)per_neighborhood * neighborhoods; - if (cap < base_cap) - cap = base_cap; - - return (int)cap; -} - -bool -city_is_at_neighborhood_cap (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return false; - - int cap = get_neighborhood_pop_cap (city); - if (cap <= 0) - return false; - - return city->Body.Population.Size >= cap; -} - -void -ensure_neighborhood_request_for_city (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return; - - if (! leader_can_build_district (&leaders[city->Body.CivID], NEIGHBORHOOD_DISTRICT_ID)) - return; - - mark_city_needs_district (city, NEIGHBORHOOD_DISTRICT_ID); -} - -void -calculate_district_culture_science_bonuses (City * city, int * culture_bonus, int * science_bonus) -{ - if (culture_bonus != NULL) - *culture_bonus = 0; - if (science_bonus != NULL) - *science_bonus = 0; - - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders) || (city == NULL)) - return; - - int total_culture = 0; - int total_science = 0; - int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) - continue; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - struct district_config const * cfg = &is->district_configs[district_id]; - int district_culture_bonus = 0; - int district_science_bonus = 0; - get_effective_district_yields (inst, cfg, NULL, NULL, NULL, &district_science_bonus, &district_culture_bonus, NULL); - - bool is_neighborhood = (cfg->command == UCV_Build_Neighborhood); - if (is_neighborhood) { - if (utilized_neighborhoods > 0) { - total_culture += district_culture_bonus; - total_science += district_science_bonus; - utilized_neighborhoods--; - } - } else { - total_culture += district_culture_bonus; - total_science += district_science_bonus; - } - } - - if (culture_bonus != NULL) - *culture_bonus = total_culture; - if (science_bonus != NULL) - *science_bonus = total_science; -} - -void -calculate_district_happiness_bonus (City * city, int * happiness_bonus) -{ - if (happiness_bonus != NULL) - *happiness_bonus = 0; - - if (! is->current_config.enable_districts || (city == NULL)) - return; - - int total_happy = 0; - int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) - continue; - - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - struct district_config const * cfg = &is->district_configs[district_id]; - - bool is_neighborhood = district_id == NEIGHBORHOOD_DISTRICT_ID; - if (is_neighborhood && (utilized_neighborhoods <= 0)) - continue; - - if (is_neighborhood) - utilized_neighborhoods--; - - int district_happy = 0; - get_effective_district_yields (inst, cfg, NULL, NULL, NULL, NULL, NULL, &district_happy); - if (district_happy != 0) - total_happy += district_happy; - } - - if (happiness_bonus != NULL) - *happiness_bonus = total_happy; -} - -int __fastcall -patch_City_requires_improvement_to_grow (City * this) -{ - int required_improv = City_requires_improvement_to_grow (this); - if ((required_improv == -1) && - (this != NULL) && - is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - city_is_at_neighborhood_cap (this)) { - return 0; // Neighborhood sentinel - } - - return required_improv; -} - -// Replacement check specifically for stalled growth check function, -// where we can't pass through the neighborhood sentinel. That function itself -// doesn't block growth, it just triggers the dialog, so safe to skip it if -// neighborhoods are needed. -int __fastcall -patch_City_requires_improvement_to_grow_besides_neighborhood (City * this) -{ - return City_requires_improvement_to_grow (this); -} - -void __fastcall -patch_maybe_show_improvement_needed_for_growth_dialog (void * this, int edx, City * city, int * param_2) -{ - int required_improv_id = (int)param_2; - if (is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - (required_improv_id == 0)) // Neighborhood sentinel - return; - - maybe_show_improvement_needed_for_growth_dialog (this, __, city, param_2); -} - -void -maybe_show_neighborhood_growth_warning (City * city) -{ - if ((city == NULL) || ! (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts)) return; - int requirement = patch_City_requires_improvement_to_grow (city); - if (requirement != 0) return; // Neighborhood sentinel not present - if (city->Body.FoodIncome <= 0) return; // Not growing - if (is_online_game ()) return; - int civ_id = city->Body.CivID; - if (civ_id != p_main_screen_form->Player_CivID) return; - if ((*p_human_player_bits & (1u << civ_id)) == 0) return; - - unsigned int turn_no = (unsigned int)*p_current_turn_no; - unsigned int throttle = ((unsigned int)city->Body.X << 5) ^ (unsigned int)city->Body.Y; - int frequency = is->current_config.neighborhood_needed_message_frequency; - if ((frequency <= 0) || (((turn_no + throttle) % frequency) != 0)) - return; - - char msg[160]; - char const * city_name = city->Body.CityName; - snprintf (msg, sizeof msg, "%s %s %s %s", - city_name, - is->c3x_labels[CL_REQUIRES], - is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name, - is->c3x_labels[CL_TO_GROW] - ); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); -} - -bool __stdcall -patch_is_not_pop_capped_or_starving (City * city) -{ - bool tr = is_not_pop_capped_or_starving (city); - if (! tr) return false; - - if (is->current_config.enable_districts) { - if (city_is_at_neighborhood_cap (city)) - return false; - } - - return true; -} - -bool -remove_building_if_no_district (City * city, int district_id, int building_id) -{ - if ((city == NULL) || (building_id < 0)) return false; - if (! patch_City_has_improvement (city, __, building_id, false)) return false; - if (city_has_required_district (city, district_id)) return false; - - patch_City_add_or_remove_improvement (city, __, building_id, 0, false); - return true; -} - -bool -city_has_other_completed_wonder_district_for_improvement (City * city, int wonder_improv_id, int removed_x, int removed_y) -{ - if (! (is->current_config.enable_districts && is->current_config.enable_wonder_districts) || - (city == NULL) || (wonder_improv_id < 0)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - if ((x == removed_x) && (y == removed_y)) - continue; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if (info->state != WDS_COMPLETED) - continue; - - int candidate_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); - if (candidate_improv_id != wonder_improv_id) - continue; - - return true; - } - - return false; -} - -void -remove_shared_wonder_if_no_other_district (City * city, int wonder_improv_id, int removed_x, int removed_y) -{ - if ((city == NULL) || (wonder_improv_id < 0)) - return; - - if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) - return; - - if (leaders[city->Body.CivID].Small_Wonders[wonder_improv_id] == city->Body.ID) - return; - - if (city_has_other_completed_wonder_district_for_improvement (city, wonder_improv_id, removed_x, removed_y)) - return; - - patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); -} - -void -reduce_city_population_due_to_lost_neighborhood (City * city) -{ - if (city == NULL) - return; - - if (! (is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - is->current_config.destroying_neighborhood_reduces_pop)) - return; - - int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; - int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; - if ((base_cap <= 0) || (per_neighborhood <= 0)) - return; - - int neighborhoods = count_neighborhoods_in_city_radius (city); - int cap = base_cap + (per_neighborhood * neighborhoods); - if (cap < base_cap) - cap = base_cap; - - int pop = city->Body.Population.Size; - if (pop <= cap) - return; - - int to_remove = pop - cap; - int removed = 0; - while (to_remove-- > 0) { - City_remove_population (city, __, 1, -1, '\0'); - removed++; - } - - if ((removed > 0) && - ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && - (city->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[160]; - snprintf (msg, sizeof msg, "%s %s %s", - city->Body.CityName, - is->c3x_labels[CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD], - is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name - ); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } -} - -bool -city_has_other_completed_district (City * city, int district_id, int removed_x, int removed_y) -{ - if (! is->current_config.enable_districts || - (city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - if ((x == removed_x) && (y == removed_y)) - continue; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != district_id) - continue; - - return true; - } - - return false; -} - -bool -district_instance_is_redundant (struct district_instance * inst, Tile * tile) -{ - if (! is->current_config.enable_districts || - (inst == NULL) || - (tile == NULL) || (tile == p_null_tile)) - return false; - - int district_id = inst->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - if (! district_is_complete (tile, district_id)) - return false; - - if (district_id == NEIGHBORHOOD_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID) - return false; - - int tile_x = inst->tile_x; - int tile_y = inst->tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - return false; - - int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - - if (district_id == WONDER_DISTRICT_ID) - return inst->wonder_info.state == WDS_UNUSED; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - if (! city_has_other_completed_district (wai.city, district_id, tile_x, tile_y)) - return false; - } - - return true; -} - -bool -any_nearby_city_would_lose_district_benefits (int district_id, int civ_id, int removed_x, int removed_y) -{ - if (! is->current_config.enable_districts) - return false; - - if (district_id < 0 || district_id >= is->district_count) - return false; - - struct district_infos * info = &is->district_infos[district_id]; - - // If there are no dependent buildings, no city can lose benefits - if (info->dependent_building_count == 0) - return false; - - // Check all cities within work radius of the removed district - FOR_CITIES_AROUND (wai, removed_x, removed_y) { - City * city = wai.city; - - // Check if this city has another completed district of the same type nearby (excluding the one being removed) - if (city_has_other_completed_district (city, district_id, removed_x, removed_y)) - continue; - - // This city doesn't have another district, check if it has any dependent buildings - for (int i = 0; i < info->dependent_building_count; i++) { - int building_id = info->dependent_building_ids[i]; - if (building_id >= 0 && patch_City_has_improvement (city, __, building_id, false)) - return true; - } - } - - return false; -} - -void -remove_dependent_buildings_for_district (int district_id, int center_x, int center_y) -{ - if (! is->current_config.enable_districts || (district_id < 0) || (district_id >= is->district_count)) - return; - - struct district_infos * info = &is->district_infos[district_id]; - - if ((center_x < 0) || (center_y < 0) || - (center_x >= p_bic_data->Map.Width) || (center_y >= p_bic_data->Map.Height)) - return; - - FOR_CITIES_AROUND (wai, center_x, center_y) { - City * city = wai.city; - - if (city_has_other_completed_district (city, district_id, center_x, center_y)) - continue; - - int removed_count = 0; - int first_building_id = -1; - - for (int i = 0; i < info->dependent_building_count; i++) { - int building_id = info->dependent_building_ids[i]; - if (building_id >= 0) { - // This also loops through tiles around the city but is not redundant, as the city - // may have multiple districts of the same type in its radius (eg outside radius of this particular district) - if (remove_building_if_no_district (city, district_id, building_id)) { - if (removed_count == 0) - first_building_id = building_id; - removed_count++; - } - } - } - - if ((removed_count > 0) && - is->current_config.show_message_when_building_lost_to_destroyed_district && - ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && - (city->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[200]; - char const * district_name = is->district_configs[district_id].name; - char const * building_name = (first_building_id >= 0) ? p_bic_data->Improvements[first_building_id].Name.S : ""; - - if (removed_count == 1) - snprintf (msg, sizeof msg, "%s%s %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_APOSTROPHE_S], - building_name, - is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], - district_name); - else - snprintf (msg, sizeof msg, "%s%s %s %s %d %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_APOSTROPHE_S], - building_name, - is->c3x_labels[CL_AND], - removed_count - 1, - is->c3x_labels[CL_OTHER_BUILDINGS_HAVE_BEEN], - is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], - district_name); - - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - } -} - -void -remove_wonder_improvement_for_destroyed_district (int wonder_improv_id) -{ - if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) - return; - - if ((p_cities == NULL) || (p_cities->Cities == NULL)) - return; - - for (int idx = 0; idx <= p_cities->LastIndex; idx++) { - City * city = get_city_ptr (idx); - if (city == NULL) - continue; - if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) - continue; - - patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); - } -} - -void -handle_district_removed (Tile * tile, int district_id, int center_x, int center_y, bool leave_ruins) -{ - if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.enable_districts) - return; - - int wonder_windex = -1; - int wonder_improv_id = -1; - - // Get wonder district info before removing - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info != NULL && info->state == WDS_COMPLETED) - wonder_windex = info->wonder_index; - - int actual_district_id = district_id; - if (actual_district_id < 0) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) - actual_district_id = inst->district_id; - } - - remove_district_instance (tile); - - bool removed_neighborhood = actual_district_id == NEIGHBORHOOD_DISTRICT_ID; - - if (is->current_config.enable_wonder_districts && - (actual_district_id == WONDER_DISTRICT_ID) && - (wonder_windex >= 0)) - wonder_improv_id = get_wonder_improvement_id_from_index (wonder_windex); - - if (wonder_improv_id >= 0 && is->current_config.completed_wonder_districts_can_be_destroyed) - remove_wonder_improvement_for_destroyed_district (wonder_improv_id); - - if (is->current_config.enable_distribution_hub_districts && - (actual_district_id == DISTRIBUTION_HUB_DISTRICT_ID)) - remove_distribution_hub_record (tile); - - if (district_id >= 0) - remove_dependent_buildings_for_district (district_id, center_x, center_y); - - // Make the tile workable again by resetting CityAreaID and recomputing yields for nearby cities - tile->Body.CityAreaID = -1; - - int tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - FOR_CITIES_AROUND (wai, center_x, center_y) { - if (removed_neighborhood) - reduce_city_population_due_to_lost_neighborhood (wai.city); - recompute_city_yields_with_districts (wai.city); - } - - if (leave_ruins && (tile->vtable->m60_Set_Ruins != NULL)) { - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, center_x, center_y); - tile->vtable->m60_Set_Ruins (tile, __, 1); - } - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -bool -city_has_active_wonder_for_district (City * city) -{ - struct district_infos * info = &is->district_infos[WONDER_DISTRICT_ID]; - for (int n = 0; n < ARRAY_LEN (info->dependent_building_ids); n++) { - int building_id = info->dependent_building_ids[n]; - if ((building_id >= 0) && has_active_building (city, building_id)) - return true; - } - return false; -} - -bool -city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id) -{ - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); - if ((prereq_list == NULL) || (prereq_list->count <= 0)) - return false; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder = false; - - // Special logic for handling rivers - bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; - bool has_prereq = false; - - if (is->current_config.enable_wonder_districts && - district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) { - is_wonder = true; - if (! wonder_is_buildable_by_civ (improv_id, city->Body.CivID)) { - if (out_district_id != NULL) - *out_district_id = -1; - return false; - } - if (requires_river) { - bool has_river_wonder_district = false; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if (wai.district_inst->district_id != WONDER_DISTRICT_ID) - continue; - if (wai.tile->vtable->m37_Get_River_Code (wai.tile) == 0) - continue; - if (! wonder_is_buildable_on_tile (wai.tile, improv_id)) - continue; - struct wonder_district_info * info = get_wonder_district_info (wai.tile); - if (info == NULL) { - has_river_wonder_district = true; - break; - } - if (info->state == WDS_COMPLETED) - continue; - if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) - continue; - has_river_wonder_district = true; - break; - } - if (has_river_wonder_district) - has_prereq = true; - } else if (city_has_wonder_district_with_no_completed_wonder (city, improv_id)) { - has_prereq = true; - } - } - - if (! has_prereq && city_has_any_prereq_district_for_improvement (city, prereq_list, requires_river, !is_wonder)) - has_prereq = true; - - if (has_prereq) - return false; - - if (out_district_id != NULL) - *out_district_id = pick_missing_district_for_improvement (city, prereq_list); - return true; -} - -void -clear_best_feasible_order (City * city) -{ - int key = (int)city; - int stored_int; - if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) { - struct ai_best_feasible_order * stored = (struct ai_best_feasible_order *)stored_int; - free (stored); - itable_remove (&is->ai_best_feasible_orders, key); - } -} - -void -record_best_feasible_order (City * city, City_Order const * order, int value) -{ - int key = (int)city; - int stored_int; - struct ai_best_feasible_order * stored; - if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) - stored = (struct ai_best_feasible_order *)stored_int; - else { - stored = malloc (sizeof *stored); - if (stored == NULL) - return; - stored->order = *order; - stored->value = value; - itable_insert (&is->ai_best_feasible_orders, key, (int)stored); - return; - } - - if (value > stored->value) { - stored->order = *order; - stored->value = value; - } -} - -struct ai_best_feasible_order * -get_best_feasible_order (City * city) -{ - int stored_int; - if (itable_look_up (&is->ai_best_feasible_orders, (int)city, &stored_int)) - return (struct ai_best_feasible_order *)stored_int; - else - return NULL; -} - -bool -city_is_currently_building_wonder (City * city) -{ - if ((city == NULL) || (city->Body.Order_Type != COT_Improvement)) - return false; - int order_id = city->Body.Order_ID; - if ((order_id < 0) || (order_id >= p_bic_data->ImprovementsCount)) - return false; - return (p_bic_data->Improvements[order_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; -} - -bool -wonder_district_tile_under_construction (Tile * tile, int tile_x, int tile_y, int * out_windex) -{ - if (! is->current_config.enable_wonder_districts || - (tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != WONDER_DISTRICT_ID) - return false; - - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info == NULL || info->state != WDS_UNDER_CONSTRUCTION) - return false; - - City * reserved_city = get_city_ptr (info->city_id); - if (reserved_city == NULL) - return false; - info->city = reserved_city; - info->city_id = reserved_city->Body.ID; - - // Verify the reserved city is still building a wonder - if (! city_is_currently_building_wonder (reserved_city)) - return false; - - // Verify this tile is within the reserved city's radius - if (! city_radius_contains_tile (reserved_city, tile_x, tile_y)) - return false; - - // Get the wonder index for the wonder being built - if (out_windex != NULL) { - int order_id = reserved_city->Body.Order_ID; - int windex = find_wonder_config_index_by_improvement_id (order_id); - *out_windex = windex; - } - - return true; -} - -bool -city_needs_wonder_district (City * city) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - - int pending_improv_id; - if (look_up_pending_building_order (city, &pending_improv_id)) { - // Check if it's actually a wonder - if ((pending_improv_id >= 0) && (pending_improv_id < p_bic_data->ImprovementsCount)) { - Improvement * improv = &p_bic_data->Improvements[pending_improv_id]; - if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - return true; - } - } - if (city_is_currently_building_wonder (city)) - return true; - if (city_has_active_wonder_for_district (city)) - return true; - return false; -} - -bool -city_has_assigned_wonder_district (City * city, Tile * ignore_tile, int wonder_improv_id) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - if (candidate == ignore_tile) - continue; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = inst ? &inst->wonder_info : NULL; - if ((info != NULL) && - (info->state == WDS_UNDER_CONSTRUCTION) && - (info->city_id == city->Body.ID)) { - info->city = city; - if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) { - info->state = WDS_UNUSED; - info->city = NULL; - info->city_id = -1; - info->wonder_index = -1; - continue; - } - return true; - } - } - - return false; -} - -bool -free_wonder_district_for_city (City * city) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) - return false; - if (city_needs_wonder_district (city)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { - int x = wai.tile_x, y = wai.tile_y; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info != NULL && info->state == WDS_COMPLETED) - continue; // Don't remove completed wonder districts - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - continue; - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - - handle_district_removed (tile, WONDER_DISTRICT_ID, city->Body.X, city->Body.Y, false); - return true; - } - - return false; -} - -bool -reserve_wonder_district_for_city (City * city, int wonder_improv_id) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) - return false; - - if (city_has_assigned_wonder_district (city, NULL, wonder_improv_id)) - return true; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if (info->state == WDS_COMPLETED) continue; - if (info->state == WDS_UNDER_CONSTRUCTION) { - if (info->city_id == city->Body.ID) { - info->city = city; - return true; - } - continue; - } - if (city_has_assigned_wonder_district (city, candidate, wonder_improv_id)) - return true; - - // Reserve this Wonder district for this city - info->state = WDS_UNDER_CONSTRUCTION; - info->city = city; - info->city_id = city->Body.ID; - info->wonder_index = -1; - return true; - } - - return false; -} - -void -release_wonder_district_reservation (City * city) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return; - - // Find and remove any reservations for this city - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if ((info != NULL) && - (info->state == WDS_UNDER_CONSTRUCTION) && - (info->city_id == city->Body.ID)) { - info->city = city; - info->state = WDS_UNUSED; - info->city = NULL; - info->city_id = -1; - info->wonder_index = -1; - } - } -} - -void -handle_district_destroyed_by_attack (Tile * tile, int tile_x, int tile_y, bool leave_ruins) -{ - if (! is->current_config.enable_districts || tile == NULL || tile == p_null_tile) - return; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - int district_id = inst->district_id; - - // If this is a Wonder District with a completed wonder and wonders can't be destroyed, restore overlay and keep district - if (is->current_config.enable_wonder_districts) { - struct wonder_district_info * info = get_wonder_district_info (tile); - if ((district_id == WONDER_DISTRICT_ID) && - (info != NULL && info->state == WDS_COMPLETED) && - (! is->current_config.completed_wonder_districts_can_be_destroyed)) { - unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); - if ((overlays & TILE_FLAG_MINE) == 0) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - return; - } - } - if (district_id == BRIDGE_DISTRICT_ID || district_id == CANAL_DISTRICT_ID) { - enum UnitTypeClasses target_class = (district_id == BRIDGE_DISTRICT_ID) ? UTC_Land : UTC_Sea; - clear_memo (); - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if (unit == NULL) - continue; - int unit_type_id = unit->Body.UnitTypeID; - if ((unit_type_id < 0) || (unit_type_id >= p_bic_data->UnitTypeCount)) - continue; - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - bool matches = (type->Unit_Class == target_class); - if (! matches && unit->Body.Container_Unit >= 0) { - Unit * container = get_unit_ptr (unit->Body.Container_Unit); - if (container != NULL) { - int container_type_id = container->Body.UnitTypeID; - if ((container_type_id >= 0) && (container_type_id < p_bic_data->UnitTypeCount)) { - UnitType * container_type = &p_bic_data->UnitTypes[container_type_id]; - matches = (container_type->Unit_Class == target_class); - } - } - } - if (matches) { - bool already = false; - for (int n = 0; n < is->memo_len; n++) - if (is->memo[n] == unit->Body.ID) { - already = true; - break; - } - if (! already) - memoize (unit->Body.ID); - } - } - for (int n = 0; n < is->memo_len; n++) { - Unit * to_despawn = get_unit_ptr (is->memo[n]); - if (to_despawn != NULL) - patch_Unit_despawn (to_despawn, __, 0, 1, 0, 0, 0, 0, 0); - } - clear_memo (); - } - handle_district_removed (tile, district_id, tile_x, tile_y, leave_ruins); - } -} - -bool -has_active_building (City * city, int improv_id) -{ - Leader * owner = &leaders[city->Body.CivID]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - return patch_City_has_improvement (city, __, improv_id, 1) && // building is physically present in city AND - ((improv->ObsoleteID < 0) || (! Leader_has_tech (owner, __, improv->ObsoleteID))) && // building is not obsolete AND - ((improv->GovernmentID < 0) || (improv->GovernmentID == owner->GovernmentType)); // building is not restricted to a different govt -} - -void -init_unit_type_count (Leader * leader) -{ - int id = leader->ID; - struct table * counts = &is->unit_type_counts[id]; - - if (counts->len > 0) - table_deinit (counts); - - if (p_units->Units != NULL) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit_Body * body = p_units->Units[n].Unit; - if ((body != NULL) && ((int)body != offsetof (Unit, Body)) && (body->CivID == id)) { - int prev_count = itable_look_up_or (counts, body->UnitTypeID, 0); - itable_insert (counts, body->UnitTypeID, prev_count + 1); - } - } - - is->unit_type_count_init_bits |= 1 << id; -} - -int -get_unit_type_count (Leader * leader, int unit_type_id) -{ - int id = leader->ID; - struct table * counts = &is->unit_type_counts[id]; - - if ((is->unit_type_count_init_bits & 1<ID; - struct table * counts = &is->unit_type_counts[id]; - if ((is->unit_type_count_init_bits & (1 << id)) == 0) - init_unit_type_count (leader); - - int prev_amount = itable_look_up_or (counts, unit_type_id, 0); - itable_insert (counts, unit_type_id, prev_amount + amount); -} - -// If this unit type is limited, returns true and writes how many units of the type the given player is allowed to "out_limit". If the type is not -// limited, returns false. -bool -get_unit_limit (Leader * leader, int unit_type_id, int * out_limit) -{ - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - struct unit_type_limit * lim; - 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; - if (lim->cities_per != 0) - tr += city_count / lim->cities_per; - *out_limit = tr; - return true; - } else - return false; -} - -// This this unit type is limited, returns true and writes to "out_available" how many units the given player can add before reaching the limit. If -// the type is not limited, returns false. -bool -get_available_unit_count (Leader * leader, int unit_type_id, int * out_available) -{ - int limit; - if (get_unit_limit (leader, unit_type_id, &limit)) { - int count = get_unit_type_count (leader, unit_type_id); - int dups[30]; - int dups_count = list_unit_type_duplicates (unit_type_id, dups, ARRAY_LEN (dups)); - for (int n = 0; n < dups_count; n++) - count += get_unit_type_count (leader, dups[n]); - - *out_available = limit - count; - return true; - } else - return false; -} - -int -add_i31b_to_int (int base, i31b addition) -{ - int amount; - bool percent; - i31b_unpack (addition, &amount, &percent); - if (! percent) - return base + amount; - else { - int fraction = (base * int_abs (amount) + 50) / 100; - return (amount >= 0) ? base + fraction : base - fraction; - } -} - -int -apply_perfume (enum perfume_kind kind, char const * name, int base_amount) -{ - i31b perfume_value; - if (stable_look_up (&is->current_config.perfume_specs[kind], name, &perfume_value)) - return add_i31b_to_int (base_amount, perfume_value); - else - return base_amount; -} - -int __stdcall -intercept_consideration (int valuation) -{ - City * city = is->ai_considering_production_for_city; - City_Order * order = &is->ai_considering_order; - - // Apply perfume - char * order_name; { - if (order->OrderType == COT_Improvement) - order_name = p_bic_data->Improvements[order->OrderID].Name.S; - else - order_name = p_bic_data->UnitTypes[order->OrderID].Name; - } - valuation = apply_perfume (PK_PRODUCTION, order_name, valuation); - - // Apply temp AI settler perfume - if ((order->OrderType == COT_Unit) && - (p_bic_data->UnitTypes[order->OrderID].AI_Strategy & UTAI_Settle) && - (is->current_config.ai_settler_perfume_on_founding != 0) && - (is->current_config.ai_settler_perfume_on_founding_duration != 0) && - (is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID] >= 0)) { - int turns_since_founding = *p_current_turn_no - is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID]; - int duration = is->current_config.ai_settler_perfume_on_founding_duration; - if (turns_since_founding < duration) { - i31b perfume = is->current_config.ai_settler_perfume_on_founding; - - // Scale amount by turns remaining - { - int amount; - bool percent; - i31b_unpack (perfume, &amount, &percent); - - int percent_remaining = (100 * (duration - turns_since_founding)) / duration; - amount = (amount * percent_remaining + 50) / 100; - - perfume = i31b_pack (amount, percent); - } - - valuation = add_i31b_to_int (valuation, perfume); - } - } - - if (is->current_config.enable_districts && - (city != NULL) && - ((*p_human_player_bits & (1 << city->Body.CivID)) == 0)) { - bool feasible = false; - switch (order->OrderType) { - case COT_Improvement: - if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->ImprovementsCount) && - (! city_requires_district_for_improvement (city, order->OrderID, NULL))) - feasible = true; - break; - case COT_Unit: - if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->UnitTypeCount)) - feasible = true; - break; - default: - break; - } - if (feasible) - record_best_feasible_order (city, order, valuation); - } - - // Expand the list of valuations if necessary - reserve (sizeof is->ai_prod_valuations[0], (void **)&is->ai_prod_valuations, &is->ai_prod_valuations_capacity, is->count_ai_prod_valuations); - - // Record this valuation - int n = is->count_ai_prod_valuations++; - is->ai_prod_valuations[n] = (struct ai_prod_valuation) { - .order_type = order->OrderType, - .order_id = order->OrderID, - .point_value = valuation - }; - - return valuation; -} - -// Returns a pointer to a bitfield that can be used to record resource access for resource IDs >= 32. This procedure can work with any city ID since -// it allocates and zero-initializes these bit fields as necessary. The given resource ID must be at least 32. The index of the bit for that resource -// within the field is resource_id%32. -unsigned * -get_extra_resource_bits (int city_id, int resource_id) -{ - int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); - int ints_per_city = 1 + extra_resource_count/32; - if (city_id >= is->extra_available_resources_capacity) { - int new_capacity = city_id + 100; - unsigned * new_array = calloc (new_capacity * ints_per_city, sizeof new_array[0]); - if (is->extra_available_resources != NULL) { - memcpy (new_array, is->extra_available_resources, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); - free (is->extra_available_resources); - } - is->extra_available_resources = new_array; - is->extra_available_resources_capacity = new_capacity; - } - return &is->extra_available_resources[city_id * ints_per_city + (resource_id-32)/32]; -} - -void __stdcall -intercept_set_resource_bit (City * city, int resource_id) -{ - if (resource_id < 32) - city->Body.Available_Resources |= 1 << resource_id; - else - *get_extra_resource_bits (city->Body.ID, resource_id) |= 1 << (resource_id&31); -} - -// Must forward declare this function since there's a circular dependency between it and patch_City_has_resource -bool has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id); - -bool __fastcall -patch_City_has_resource (City * this, int edx, int resource_id) -{ - return city_has_resource_r (this, resource_id, INT_MAX); -} - -bool -city_has_resource_r (City * this, int resource_id, int max_generated_resource_id) -{ - bool tr; - if ((this == NULL) || (resource_id < 0) || (resource_id >= p_bic_data->ResourceTypeCount)) - return false; - if (resource_id > max_generated_resource_id) - return false; - - if (is->current_config.patch_phantom_resource_bug && - (resource_id >= 32) && (resource_id < p_bic_data->ResourceTypeCount) && - (! City_has_trade_connection_to_capital (this))) { - unsigned bits = (this->Body.ID < is->extra_available_resources_capacity) ? *get_extra_resource_bits (this->Body.ID, resource_id) : 0; - tr = (bits >> (resource_id&31)) & 1; - } else - tr = City_has_resource (this, __, resource_id); - - // Check if access to this resource is provided by a building in the city - if (! tr) - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if ((mill->resource_id == resource_id) && - (mill->flags & MF_LOCAL) && - can_generate_resource (this->Body.CivID, mill) && - has_active_building (this, mill->improv_id) && - has_resources_required_by_building_r (this, mill->improv_id, mill->resource_id - 1)) { - tr = true; - break; - } - } - - // Check if access to this resource is provided by a district in the city's work radius - if ((! tr) && is->current_config.enable_districts) { - FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { - struct district_instance * di = wai.district_inst; - int district_id = di->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - continue; - - struct district_config * dc = &is->district_configs[district_id]; - if ((dc->generated_resource_id == resource_id) && - (dc->generated_resource_flags & MF_LOCAL) && - district_generates_resource_for_civ (wai.tile, di, dc, this->Body.CivID)) { - tr = true; - break; - } - } - } - - return tr; -} - -// Checks if the resource requirements for an improvement are satisfied in a given city. The "max_req_resource_id" parameter is to guard against -// infinite loops in case of circular resource dependencies due to mills. The way it works is that resource requirements can only be satisfied if -// their ID is not greater than that limit. This function is called recursively by patch_City_has_resource and in the recursive calls, the limit is -// set to be below the resource ID provided by the mill being considered. So, when considering resource production chains, the limit approaches zero -// with each recursive call, hence infinite loops are not possible. -bool -has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id) -{ - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if (! (improv->ImprovementFlags & ITF_Required_Goods_Must_Be_In_City_Radius)) { - for (int n = 0; n < 2; n++) { - int res_id = (&improv->Resource1ID)[n]; - if ((res_id >= 0) && - ((res_id > max_req_resource_id) || (! city_has_resource_r (city, res_id, max_req_resource_id)))) - return false; - } - return true; - } else { - int * targets = &improv->Resource1ID; - if ((targets[0] < 0) && (targets[1] < 0)) - return true; - int finds[2] = {0, 0}; - - int civ_id = city->Body.CivID; - for (int n = 0; n < is->workable_tile_count; n++) { - int dx, dy; - patch_ni_to_diff_for_work_area (n, &dx, &dy); - int x = city->Body.X + dx, y = city->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &x, &y); - Tile * tile = tile_at (x, y); - if (tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id) { - int res_here = Tile_get_resource_visible_to (tile, __, civ_id); - if (res_here >= 0) { - finds[0] |= targets[0] == res_here; - finds[1] |= targets[1] == res_here; - } - } - } - - return ((targets[0] < 0) || finds[0]) && ((targets[1] < 0) || finds[1]); - } -} - -bool -has_resources_required_by_building (City * city, int improv_id) -{ - return has_resources_required_by_building_r (city, improv_id, INT_MAX); -} - -void __fastcall -patch_City_recompute_commerce (City * this) -{ - City_recompute_commerce (this); - - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - int science_bonus = 0; - calculate_district_culture_science_bonuses (this, NULL, &science_bonus); - - if (science_bonus != 0) { - this->Body.Science += science_bonus; - if (this->Body.Science < 0) - this->Body.Science = 0; - } -} - -void __fastcall -patch_City_recompute_yields_and_happiness (City * this) -{ - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts && - ! is->distribution_hub_refresh_in_progress && - is->distribution_hub_totals_dirty) - recompute_distribution_hub_totals (); - - City_recompute_yields_and_happiness (this); -} - -void __fastcall -patch_City_update_culture (City * this) -{ - City_update_culture (this); - - if ((this == NULL) || ! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - int culture_bonus = 0; - calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); - - if (culture_bonus == 0) - return; - - int culture_income = this->Body.CultureIncome + culture_bonus; - if (culture_income < 0) - culture_income = 0; - this->Body.CultureIncome = culture_income; - - int civ_id = this->Body.CivID; - int total_culture = this->Body.Total_Cultures[civ_id] + culture_bonus; - if (total_culture < 0) - total_culture = 0; - this->Body.Total_Cultures[civ_id] = total_culture; - - City_recompute_cultural_level (this, __, '\0', '\0', '\0'); -} - -void __fastcall -patch_City_recompute_culture_income (City * this) -{ - City_recompute_culture_income (this); - - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - int culture_bonus = 0; - calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); - - if (culture_bonus != 0) { - this->Body.CultureIncome += culture_bonus; - if (this->Body.CultureIncome < 0) - this->Body.CultureIncome = 0; - } -} - -// Recomputes yields in cities with active mills that depend on input resources. Intended to be called when an input resource has been potentially -// gained or lost. Recomputes only for the cities of a given leader or, if NULL, for all cities on the map. -void -recompute_mill_yields_after_resource_change (Leader * leader_or_null) -{ - if (p_cities->Cities != NULL) - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city != NULL) && - ((leader_or_null == NULL) || (city->Body.CivID == leader_or_null->ID))) { - bool any_relevant_mills = false; - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - Improvement * mill_improv = &p_bic_data->Improvements[mill->improv_id]; - if ((mill->flags & MF_YIELDS) && - ((mill_improv->Resource1ID >= 0) || (mill_improv->Resource2ID >= 0)) && - has_active_building (city, mill->improv_id)) { - any_relevant_mills = true; - break; - } - } - if (any_relevant_mills) - patch_City_recompute_yields_and_happiness (city); - } - } -} - - -int -resource_tile_resource_id (struct extra_resource_tile const * rt) -{ - if (rt == NULL) - return -1; - if (rt->type == ERT_MILL_RESOURCE) { - return (rt->mill_info.mill != NULL) ? rt->mill_info.mill->resource_id : -1; - } else if (rt->district_info.cfg != NULL) { - return rt->district_info.cfg->generated_resource_id; - } - return -1; -} - -int -compare_resource_tiles (void const * vp_a, void const * vp_b) -{ - struct extra_resource_tile const * a = vp_a, * b = vp_b; - return resource_tile_resource_id (a) - resource_tile_resource_id (b); -} - -void __fastcall -patch_Trade_Net_recompute_resources (Trade_Net * this, int edx, bool skip_popups) -{ - int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); - int ints_per_city = 1 + extra_resource_count/32; - memset (is->extra_available_resources, 0, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); - - // Assemble list of mill tiles - is->count_resource_tiles = 0; - if (p_cities->Cities != NULL) - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if (city != NULL) - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if (((mill->flags & MF_LOCAL) == 0) && - has_active_building (city, mill->improv_id) && - can_generate_resource (city->Body.CivID, mill)) { - Tile * resource_tile = tile_at (city->Body.X, city->Body.Y); - if ((resource_tile == NULL) || (resource_tile == p_null_tile)) - continue; - reserve (sizeof is->resource_tiles[0], - (void **)&is->resource_tiles, - &is->resource_tiles_capacity, - is->count_resource_tiles); - is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { - .tile = resource_tile, - .type = ERT_MILL_RESOURCE, - .mill_info = { - .city = city, - .mill = mill - } - }; - } - } - } - if (is->current_config.enable_districts) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * district_tile = (Tile *)tei.key; - struct district_instance * inst = (struct district_instance *)tei.value; - if ((district_tile == NULL) || (district_tile == p_null_tile) || (inst == NULL) || (inst->state != DS_COMPLETED)) - continue; - - int district_id = inst->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - continue; - - struct district_config * cfg = &is->district_configs[district_id]; - if ((cfg == NULL) || (cfg->generated_resource_id < 0)) - continue; - - int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); - if (owner_id < 0) - continue; - if ((cfg->generated_resource_flags & MF_LOCAL) != 0) - continue; - if (! district_can_generate_resource (owner_id, cfg)) - continue; - - reserve (sizeof is->resource_tiles[0], - (void **)&is->resource_tiles, - &is->resource_tiles_capacity, - is->count_resource_tiles); - is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { - .tile = district_tile, - .type = ERT_DISTRICT_RESOURCE, - .district_info = { - .inst = inst, - .cfg = cfg - } - }; - } - } - qsort (is->resource_tiles, is->count_resource_tiles, sizeof is->resource_tiles[0], compare_resource_tiles); - - is->got_resource_tile = NULL; - is->saved_tile_count = p_bic_data->Map.TileCount; - p_bic_data->Map.TileCount += is->count_resource_tiles; - Trade_Net_recompute_resources (this, __, skip_popups); - - // Restore the tile count if necessary. It may have already been restored by patch_Map_Renderer_m71_Draw_Tiles. This happens when the call to - // recompute_resources above opens a popup message about connecting a resource for the first time, which triggers redraw of the map. - if (is->saved_tile_count >= 0) { - p_bic_data->Map.TileCount = is->saved_tile_count; - is->saved_tile_count = -1; - } - - recompute_mill_yields_after_resource_change (NULL); - - is->must_recompute_resources_for_mill_inputs = false; -} - -Tile * -get_resource_tile (int index) -{ - struct extra_resource_tile * rt = &is->resource_tiles[index]; - is->got_resource_tile = rt; - return rt->tile; -} - -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_1 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_2 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_3 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_4 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_5 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } - -int __fastcall -patch_Tile_get_visible_resource_when_recomputing (Tile * tile, int edx, int civ_id) -{ - if (is->got_resource_tile != NULL) { - struct extra_resource_tile * rt = is->got_resource_tile; - is->got_resource_tile = NULL; - if (rt->type == ERT_MILL_RESOURCE) { - if ((rt->mill_info.city != NULL) && (rt->mill_info.mill != NULL) && - has_resources_required_by_building (rt->mill_info.city, rt->mill_info.mill->improv_id)) - return rt->mill_info.mill->resource_id; - else - return -1; - } else { - Tile * district_tile = rt->tile; - struct district_instance * inst = rt->district_info.inst; - struct district_config * cfg = rt->district_info.cfg; - if ((district_tile != NULL) && (district_tile != p_null_tile) && (inst != NULL) && - (cfg != NULL) && (inst->state == DS_COMPLETED)) { - int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); - if ((owner_id == civ_id) && district_generates_resource_for_civ (district_tile, inst, cfg, owner_id)) - return cfg->generated_resource_id; - } - return -1; - } - } - - int base_resource = Tile_get_resource_visible_to (tile, __, civ_id); - return base_resource; -} - -int WINAPI -patch_MessageBoxA (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) -{ - if (is->current_config.suppress_hypertext_links_exceeded_popup && - (strcmp (lpText, "Maximum hypertext links exceeded!") == 0)) - return IDOK; - else - return MessageBoxA (hWnd, lpText, lpCaption, uType); -} - -char * __fastcall -do_capture_modified_gold_trade (TradeOffer * trade_offer, int edx, int val, char * str, unsigned base) -{ - is->modifying_gold_trade = trade_offer; - return print_int (val, str, base); -} - -// Here the order of the registers matches the order that they're pushed by the pusha instruction -struct register_set { - int edi, esi, ebp, esp, ebx, edx, ecx, eax; -}; - -// Return 1 to allow the candidate unit to exert ZoC, 0 to exclude it. A pointer to the candidate is in esi. -int __stdcall -filter_zoc_candidate (struct register_set * reg) -{ - Unit * candidate = (Unit *)reg->esi, - * defender = is->zoc_defender; - - UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID], - * defender_type = &p_bic_data->UnitTypes[defender ->Body.UnitTypeID]; - - enum UnitTypeClasses candidate_class = candidate_type->Unit_Class, - defender_class = defender_type ->Unit_Class; - - bool lethal = ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) != 0) && (! is->temporarily_disallow_lethal_zoc); - bool aerial = (is->current_config.special_zone_of_control_rules & SZOCR_AERIAL ) != 0, - amphibious = (is->current_config.special_zone_of_control_rules & SZOCR_AMPHIBIOUS) != 0; - - // Exclude air units if aerial ZoC is not enabled and exclude land-to-sea & sea-to-land ZoC if amphibious is not enabled - if ((! aerial) && (candidate_class == UTC_Air)) - return 0; - if ((! amphibious) && - (((candidate_class == UTC_Land) && (defender_class == UTC_Sea )) || - ((candidate_class == UTC_Sea ) && (defender_class == UTC_Land)))) - return 0; - - // In case of cross-domain ZoC, filter out units with zero bombard strength or range. They can't use their attack strength in this case, so - // without bombard they can be ruled out. Don't forget units may have non-zero bombard strength and zero range for defensive bombard. - int range = (candidate_class != UTC_Air) ? candidate_type->Bombard_Range : candidate_type->OperationalRange; - if ((candidate_class != defender_class) && ((candidate_type->Bombard_Strength <= 0) || (range <= 0))) - return 0; - - // Require lethal config option & lethal bombard against one HP defender - if ((Unit_get_max_hp (defender) - defender->Body.Damage <= 1) && - ((! lethal) || - ((defender_class == UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Sea_Bombardment)) || - ((defender_class != UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Land_Bombardment)))) - return 0; - - // Air units require the bombing action to perform ZoC - if ((candidate_class == UTC_Air) && ! (candidate_type->Air_Missions & UCV_Bombing)) - return 0; - - // Exclude land units in transports if configured - if ((is->current_config.special_zone_of_control_rules & SZOCR_NOT_FROM_INSIDE) && candidate_class == UTC_Land) { - Unit * container = get_unit_ptr (candidate->Body.Container_Unit); - if ((container != NULL) && ! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)) - return 0; - } - - return 1; -} - -#define TRADE_NET_REF_COUNT 315 -#define TRADE_NET_INSTR_COUNT_GOG 22 -#define TRADE_NET_INSTR_COUNT_STEAM 23 -#define TRADE_NET_INSTR_COUNT_PCG 22 -#define TRADE_NET_ADDR_TOTAL_COUNT ((TRADE_NET_REF_COUNT * 3) + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM + TRADE_NET_INSTR_COUNT_PCG) - -int * -load_trade_net_addrs () -{ - if (is->trade_net_addrs_load_state == IS_OK) - return is->trade_net_addrs; - else if (is->trade_net_addrs_load_state == IS_INIT_FAILED) - return NULL; - - bool success = false; - char err_msg[300] = {0}; - - is->trade_net_addrs = calloc (3 * TRADE_NET_ADDR_TOTAL_COUNT, sizeof is->trade_net_addrs[0]); - if (! is->trade_net_addrs) { - snprintf (err_msg, (sizeof err_msg) - 1, "Bad alloc"); - goto done; - } - - char file_path[MAX_PATH] = {0}; - snprintf (file_path, (sizeof file_path) - 1, "%s\\trade_net_addresses.txt", is->mod_rel_dir); - char * refs_file = file_to_string (file_path); - if (! refs_file) { - snprintf (err_msg, (sizeof err_msg) - 1, "Couldn't load %s", file_path); - goto done; - } - - char * cursor = refs_file; - int loaded_count = 0; - while (true) { - if (*cursor == '#') { // comment line - skip_line (&cursor); - continue; - } - - skip_horiz_space (&cursor); - if (*cursor == '\n') { // empty line - cursor++; - continue; - } else if (*cursor == '\0') // end of file - break; - - // otherwise we must be on a line with some addresses - int ref; - bool got_any_addresses = false; - while (parse_int (&cursor, &ref)) { - if (loaded_count >= TRADE_NET_ADDR_TOTAL_COUNT) { - snprintf (err_msg, (sizeof err_msg) - 1, "Too many values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); - goto done; - } - is->trade_net_addrs[loaded_count] = ref; - loaded_count++; - got_any_addresses = true; - } - - if (! got_any_addresses) { - snprintf (err_msg, (sizeof err_msg) - 1, "Parse error"); - goto done; - } - } - - if (loaded_count < TRADE_NET_ADDR_TOTAL_COUNT) { - snprintf (err_msg, (sizeof err_msg) - 1, "Too few values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); - goto done; - } - - success = true; - -done: - free (refs_file); - if (! success) { - char full_err_msg[300] = {0}; - snprintf (full_err_msg, (sizeof full_err_msg) - 1, "Failed to load trade net refs: %s", err_msg); - MessageBox (NULL, full_err_msg, NULL, MB_ICONERROR); - is->trade_net_addrs_load_state = IS_INIT_FAILED; - return NULL; - } else { - is->trade_net_addrs_load_state = IS_OK; - return is->trade_net_addrs; - } -} - -unsigned short * __fastcall -patch_get_pixel_to_draw_city_dot (JGL_Image * this, int edx, int x, int y) -{ - unsigned short * tr = this->vtable->m07_m05_Get_Pixel (this, __, x, y); - - if ((x + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Width2) && (y + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Height2)) { - unsigned short * below = this->vtable->m07_m05_Get_Pixel (this, __, x + 1, y + 1); - if (below != NULL) - *below = 0; - } - - return tr; -} - -enum branch_kind { BK_CALL, BK_JUMP }; - -byte * -emit_branch (enum branch_kind kind, byte * cursor, void const * target) -{ - int offset = (int)target - ((int)cursor + 5); - *cursor++ = (kind == BK_CALL) ? 0xE8 : 0xE9; - return int_to_bytes (cursor, offset); -} - -// Just calls VirtualProtect and displays an error message if it fails. Made for use by the WITH_MEM_PROTECTION macro. -bool -check_virtual_protect (LPVOID addr, SIZE_T size, DWORD flags, PDWORD old_protect) -{ - if (VirtualProtect (addr, size, flags, old_protect)) - return true; - else { - char err_msg[1000]; - snprintf (err_msg, sizeof err_msg, "VirtualProtect failed! Args:\n Address: 0x%p\n Size: %d\n Flags: 0x%x", addr, size, flags); - err_msg[(sizeof err_msg) - 1] = '\0'; - MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); - return false; - } -} - -#define WITH_MEM_PROTECTION(addr, size, flags) \ - for (DWORD old_protect, unused, iter_count = 0; \ - (iter_count == 0) && check_virtual_protect (addr, size, flags, &old_protect); \ - VirtualProtect (addr, size, old_protect, &unused), iter_count++) - -void __fastcall adjust_sliders_preproduction (Leader * this); - -struct saved_code_area { - int size; - byte original_contents[]; -}; - -// Saves an area of base game code and optionally replaces it with no-ops. The area can be restored with restore_code_area. This method assumes that -// the necessary memory protection has already been set on the area, specifically that it can be written to. The method will do nothing if the area -// has already been saved with the same size. It's an error to re-save an address with a different size or overlap two saved areas. -void -save_code_area (byte * addr, int size, bool nopify) -{ - struct saved_code_area * sca; - if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { - if (sca->size != 0) { - if (sca->size != size) { - char s[200]; - snprintf (s, sizeof s, "Save code area conflict: address %p was already saved with size %d, conflicting with new size %d.", addr, sca->size, size); - s[(sizeof s) - 1] = '\0'; - pop_up_in_game_error (s); - } - return; - } - } else { - sca = malloc (size + sizeof *sca); - itable_insert (&is->saved_code_areas, (int)addr, (int)sca); - } - sca->size = size; - memcpy (&sca->original_contents, addr, size); - if (nopify) - memset (addr, 0x90, size); -} - -// Restores a saved chunk of code to its original contents. Does nothing if the area hasn't been saved. Assumes the appropriate memory protection has -// already been set. -void -restore_code_area (byte * addr) -{ - struct saved_code_area * sca; - if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { - memcpy (addr, &sca->original_contents, sca->size); - sca->size = 0; - } -} - -bool -is_code_area_saved (byte * addr) -{ - struct saved_code_area * sca; - return itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca) && (sca->size > 0); -} - -// Nopifies or restores an area depending on if yes_or_no is 1 or 0. Sets the necessary memory protections. -void -set_nopification (int yes_or_no, byte * addr, int size) -{ - WITH_MEM_PROTECTION (addr, size, PAGE_EXECUTE_READWRITE) { - if (yes_or_no) - save_code_area (addr, size, true); - else - restore_code_area (addr); - } -} - -void -apply_machine_code_edits (struct c3x_config const * cfg, bool at_program_start) -{ - DWORD old_protect, unused; - - // Allow stealth attack against single unit - WITH_MEM_PROTECTION (ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK = cfg->allow_stealth_attack_against_single_unit ? 0 : 1; - - // Enable small wonders providing free buildings - WITH_MEM_PROTECTION (ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER, 10, PAGE_EXECUTE_READWRITE) { - byte normal[8] = {0x83, 0xE1, 0x04, 0x80, 0xF9, 0x04, 0x0F, 0x85}; // and ecx, 4; cmp ecx, 4; jnz [offset] - byte modded[8] = {0x83, 0xE1, 0x0C, 0x80, 0xF9, 0x00, 0x0F, 0x84}; // and ecx, 12; cmp ecx, 0; jz [offset] - for (int n = 0; n < 8; n++) - ((byte *)ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER)[n] = cfg->enable_free_buildings_from_small_wonders ? modded[n] : normal[n]; - } - - // Bypass artillery in city check - // replacing 0x74 (= jump if [city ptr is] zero) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_CHECK_ARTILLERY_IN_CITY, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_CHECK_ARTILLERY_IN_CITY = cfg->use_offensive_artillery_ai ? 0xEB : 0x74; - - // Remove unit limit - if (! at_program_start) { - // Replace 0x7C (= jump if less than [unit limit]) with 0xEB (= uncond. jump) in Leader::spawn_unit - WITH_MEM_PROTECTION (ADDR_UNIT_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_UNIT_COUNT_CHECK = cfg->remove_unit_limit ? 0xEB : 0x7C; - - // Increase max ID to search for tradable units by 10x if limit removed - WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_UNIT_ID, 4, PAGE_EXECUTE_READWRITE) - int_to_bytes (ADDR_MAX_TRADABLE_UNIT_ID, cfg->remove_unit_limit ? 81920 : 8192); - - // Reallocate diplo_form->tradable_units array so it's 10x long if limit removed - civ_prog_free (p_diplo_form->tradable_units); - int tradable_units_len = cfg->remove_unit_limit ? 81920 : 8192, - tradable_units_size = tradable_units_len * sizeof (TradableItem); - p_diplo_form->tradable_units = new (tradable_units_size); - for (int n = 0; n < tradable_units_len; n++) - p_diplo_form->tradable_units[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 - - // Patch the size limit on some code that clears the tradable units array when starting a new game - WITH_MEM_PROTECTION (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) - int_to_bytes (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, tradable_units_size); - } - - // Remove era limit - // replacing 0x74 (= jump if zero [after cmp'ing era count with 4]) with 0xEB - WITH_MEM_PROTECTION (ADDR_ERA_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_ERA_COUNT_CHECK = cfg->remove_era_limit ? 0xEB : 0x74; - - // Fix science age bug - // Similar in nature to the sub bug, the function that measures a city's research output accepts a flag that determines whether or not it - // takes science ages into account. It's mistakenly not set by the code that gathers all research points to increment tech progress (but it - // is set elsewhere in code for the interface). The patch simply sets this flag. - WITH_MEM_PROTECTION (ADDR_SCIENCE_AGE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_SCIENCE_AGE_BUG_PATCH = cfg->patch_science_age_bug ? 1 : 0; - - // Pedia pink line bug fix - // The size of the pedia background texture is hard-coded into the EXE and in the base game it's one pixel too small. This shows up in game as - // a one pixel wide pink line along the right edge of the civilopedia. This patch simply increases the texture width by one. - WITH_MEM_PROTECTION (ADDR_PEDIA_TEXTURE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_PEDIA_TEXTURE_BUG_PATCH = cfg->patch_pedia_texture_bug ? 0xA6 : 0xA5; - - // Fix for houseboat bug - // See my posts on CFC for an explanation of the bug and its fix: - // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16084386 - // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16085242 - WITH_MEM_PROTECTION (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, PAGE_EXECUTE_READWRITE) { - if (cfg->patch_houseboat_bug) { - save_code_area (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, true); - byte * cursor = ADDR_HOUSEBOAT_BUG_PATCH; - *cursor++ = 0x50; // push eax - int call_offset = (int)&tile_at_city_or_null - ((int)cursor + 5); - *cursor++ = 0xE8; // call - cursor = int_to_bytes (cursor, call_offset); - } else - restore_code_area (ADDR_HOUSEBOAT_BUG_PATCH); - } - - // NoRaze - WITH_MEM_PROTECTION (ADDR_AUTORAZE_BYPASS, 2, PAGE_EXECUTE_READWRITE) { - byte normal[2] = {0x0F, 0x85}; // jnz - byte bypass[2] = {0x90, 0xE9}; // nop, jmp - for (int n = 0; n < 2; n++) - ((byte *)ADDR_AUTORAZE_BYPASS)[n] = cfg->prevent_autorazing ? bypass[n] : normal[n]; - } - - // Overwrite the instruction(s) where the AI's production choosing code compares the value of what it's currently considering to the best - // option so far. This is done twice since improvements and units are handled in separate loops. The instr(s) are overwritten with a jump to - // an "airlock", which is a bit of code that wraps the call to intercept_consideration. The contents of the airlocks are prepared by the - // patcher in init_consideration_airlocks. - // TODO: This instruction replacement could be done in the patcher too and that might be a better place for it. Think about this. - for (int n = 0; n < 2; n++) { - void * addr_intercept = (n == 0) ? ADDR_INTERCEPT_AI_IMPROV_VALUE : ADDR_INTERCEPT_AI_UNIT_VALUE; - void * addr_airlock = (n == 0) ? ADDR_IMPROV_CONSIDERATION_AIRLOCK : ADDR_UNIT_CONSIDERATION_AIRLOCK; - - WITH_MEM_PROTECTION (addr_intercept, AI_CONSIDERATION_INTERCEPT_LEN, PAGE_EXECUTE_READWRITE) { - byte * cursor = addr_intercept; - - // write jump to airlock - *cursor++ = 0xE9; - int offset = (int)addr_airlock - ((int)addr_intercept + 5); - cursor = int_to_bytes (cursor, offset); - - // fill the rest of the space with NOPs - while (cursor < (byte *)addr_intercept + AI_CONSIDERATION_INTERCEPT_LEN) - *cursor++ = 0x90; // nop - } - } - - // Overwrite instruction that sets bits in City.Body.Available_Resources with a jump to the airlock - WITH_MEM_PROTECTION (ADDR_INTERCEPT_SET_RESOURCE_BIT, 6, PAGE_EXECUTE_READWRITE) { - byte * cursor = ADDR_INTERCEPT_SET_RESOURCE_BIT; - if (cfg->patch_phantom_resource_bug) { - *cursor++ = 0xE9; - int offset = (int)ADDR_SET_RESOURCE_BIT_AIRLOCK - ((int)ADDR_INTERCEPT_SET_RESOURCE_BIT + 5); - cursor = int_to_bytes (cursor, offset); - *cursor++ = 0x90; // nop - } else { - byte original[6] = {0x09, 0xB0, 0x9C, 0x00, 0x00, 0x00}; // or dword ptr [eax+0x9C], esi - for (int n = 0; n < 6; n++) - cursor[n] = original[n]; - } - } - - // Enlarge the mask that's applied to p_bic_data->Map.TileCount in the loop over lines in Trade_Net::recompute_resources. This lets us loop - // over more than 0xFFFF tiles. - WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_MASK, 1, PAGE_EXECUTE_READWRITE) { - *(byte *)ADDR_RESOURCE_TILE_COUNT_MASK = (cfg->count_mills > 0) ? 0xFF : 0x00; - } - // Similarly, enlarge the cmp instruction that jumps over the entire loop when the tile count is zero. Do this by simply removing the operand - // override prefix byte (0x66), overwriting it with a nop (0x90). This converts the instruction "cmp word ptr [bic_data.Map.TileCount], di" - // into "nop; cmp dword ptr [bic_data.Map.TileCount], edi" - WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE, 1, PAGE_EXECUTE_READWRITE) { - *(byte *)ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE = 0x90; - } - - byte * addr_turn_metalimits[] = {ADDR_TURN_METALIMIT_1, ADDR_TURN_METALIMIT_2, ADDR_TURN_METALIMIT_3, ADDR_TURN_METALIMIT_4, - ADDR_TURN_METALIMIT_5, ADDR_TURN_METALIMIT_6, ADDR_TURN_METALIMIT_7}; - for (int n = 0; n < ARRAY_LEN (addr_turn_metalimits); n++) { - byte * addr = addr_turn_metalimits[n]; - WITH_MEM_PROTECTION (addr, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (addr, cfg->remove_cap_on_turn_limit ? 1000000 : 1000); - } - } - - // Overwrite the human-ness test and call to Leader::ai_adjust_sliders that happens during the preproduction player update method. The new - // code calls adjust_sliders_preproduction for all players. - WITH_MEM_PROTECTION (ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT, 9, PAGE_EXECUTE_READWRITE) { - byte * cursor = ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT; - *cursor++ = 0x8B; *cursor++ = 0xCE; // mov ecx, esi - cursor = emit_branch (BK_CALL, cursor, adjust_sliders_preproduction); - for (; cursor < ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT + 9; cursor++) - *cursor = 0x90; // nop - } - - // Set up a special intercept of the base game's calls to print_int in order to grab a pointer to a gold TradeOffer object being modified. The - // calls to print_int happen in the context of creating the default text to be placed in the set-gold-amount popup. Conveniently, a pointer to - // the TradeOffer object is always stored in register ecx when this call happens. It's not easily accessible since print_int uses the cdecl - // convention so we must use an airlock-like thing to effectively convert the calling convention to fastcall. The first part of this code - // simply replaces the call to print_int with a call to the airlock-like thing, and the second part initializes its contents. - byte * addr_print_gold_amounts[] = {ADDR_PRINT_GOLD_AMOUNT_1, ADDR_PRINT_GOLD_AMOUNT_2}; - for (int n = 0; n < ARRAY_LEN (addr_print_gold_amounts); n++) { - byte * addr = addr_print_gold_amounts[n]; - WITH_MEM_PROTECTION (addr, 5, PAGE_EXECUTE_READWRITE) - emit_branch (BK_CALL, addr, ADDR_CAPTURE_MODIFIED_GOLD_TRADE); - } - WITH_MEM_PROTECTION (ADDR_CAPTURE_MODIFIED_GOLD_TRADE, 32, PAGE_EXECUTE_READWRITE) { - byte * cursor = ADDR_CAPTURE_MODIFIED_GOLD_TRADE; - - // Repush all of the arguments to print_int onto the stack, they will be consumed by do_capture_modified_gold_trade since it's - // fastcall. The original args don't need to be removed b/c we're replacing a cdecl function so that's the caller's - // responsibility. The TradeOffer pointer is already in ECX, so that's fine as long as we don't touch that register. - byte repush[] = {0xFF, 0x74, 0x24, 0x0C}; // push [esp+0xC] - for (int n = 0; n < 3; n++) - for (int k = 0; k < ARRAY_LEN (repush); k++) - *cursor++ = repush[k]; - - cursor = emit_branch (BK_CALL, cursor, do_capture_modified_gold_trade); // call do_capture_modified_gold_trade - *cursor++ = 0xC3; // ret - } - - // Edit branch in capture_city to never run code for barbs, this allows barbs to capture cities - WITH_MEM_PROTECTION (ADDR_CAPTURE_CITY_BARB_BRANCH, 2, PAGE_EXECUTE_READWRITE) { - byte normal[2] = {0x0F, 0x85}; // jnz - byte bypass[2] = {0x90, 0xE9}; // nop, jmp - for (int n = 0; n < 2; n++) - ((byte *)ADDR_CAPTURE_CITY_BARB_BRANCH)[n] = cfg->enable_city_capture_by_barbarians ? bypass[n] : normal[n]; - } - - // After the production phase is done for the barb player, there are two jump instructions skipping the production code for civs. Replacing - // those jumps lets us run the civ production code for the barbs as well. - WITH_MEM_PROTECTION (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, PAGE_EXECUTE_READWRITE) { - if (cfg->enable_city_capture_by_barbarians) { - save_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, true); - byte jump_to_civ[6] = {0x0F, 0x8D, 0x0C, 0x00, 0x00, 0x00}; // jge +0x12 - for (int n = 0; n < 6; n++) - ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP[n] = jump_to_civ[n]; - } else - restore_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP); - } - set_nopification (cfg->enable_city_capture_by_barbarians, ADDR_PROD_PHASE_BARB_DONE_JUMP, 5); - - for (int domain = 0; domain < 2; domain++) { - byte * addr_skip = (domain == 0) ? ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC : ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC, - * addr_airlock = (domain == 0) ? ADDR_SEA_ZOC_FILTER_AIRLOCK : ADDR_LAND_ZOC_FILTER_AIRLOCK; - - WITH_MEM_PROTECTION (addr_skip, 6, PAGE_EXECUTE_READWRITE) { - if ((cfg->special_zone_of_control_rules != 0) && ! is_code_area_saved (addr_skip)) { - byte * original_target = addr_skip + 6 + int_from_bytes (addr_skip + 2); // target addr of jump instr we're replacing - save_code_area (addr_skip, 6, true); - - // Initialize airlock. The airlock preserves all registers and calls filter_zoc_candidate then either follows or skips the - // original jump depending on what it returns. If zero is returned, follows the jump, skipping a bunch of code and filtering - // out the unit as a candidate for ZoC. - WITH_MEM_PROTECTION (addr_airlock, INLEAD_SIZE, PAGE_READWRITE) { - byte * cursor = addr_airlock; - *cursor++ = 0x60; // pusha - *cursor++ = 0x54; // push esp - cursor = emit_branch (BK_CALL, cursor, filter_zoc_candidate); - *cursor++ = 0x83; *cursor++ = 0xF8; *cursor++ = 0x01; // cmp eax, 1 - *cursor++ = 0x75; *cursor++ = 0x06; // jne 6 - *cursor++ = 0x61; // popa - cursor = emit_branch (BK_JUMP, cursor, addr_skip + 6); - *cursor++ = 0x61; // popa - cursor = emit_branch (BK_JUMP, cursor, original_target); - } - - // Write jump to airlock - emit_branch (BK_JUMP, addr_skip, addr_airlock); - } else if (cfg->special_zone_of_control_rules == 0) - restore_code_area (addr_skip); - } - } - - set_nopification ( cfg->special_zone_of_control_rules != 0, ADDR_ZOC_CHECK_ATTACKER_ANIM_FIELD_111, 6); - set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_LAND_UNIT , 6); - set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_SEA_UNIT , 6); - - WITH_MEM_PROTECTION (ADDR_LUXURY_BOX_ROW_HEIGHT, 4, PAGE_EXECUTE_READWRITE) { - byte normal [4] = {0x8B, 0x44, 0x24, LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET}; // mov eax, dword ptr [esp + LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET] - byte compact[4] = {0x31, 0xC0, 0xB0, 0x10}; // xor eax, eax; mov al, 0x10 - for (int n = 0; n < 4; n++) - ADDR_LUXURY_BOX_ROW_HEIGHT[n] = cfg->compact_luxury_display_on_city_screen ? compact[n] : normal[n]; - } - - WITH_MEM_PROTECTION (ADDR_MOST_STRAT_RES_ON_CITY_SCREEN, 1, PAGE_EXECUTE_READWRITE) { - *(byte *)ADDR_MOST_STRAT_RES_ON_CITY_SCREEN = cfg->compact_strategic_resource_display_on_city_screen ? 13 : 8; - } - - // Remove a check that a returned neighbor index is within the 21 tile work area in code related to hoving the mouse over the work area on the - // city screen. This check is redundant and could be removed always, but only do so if work area is expanded. - set_nopification (cfg->city_work_radius > 2, ADDR_REDUNDANT_CHECK_ON_WORK_AREA_HOVER, 6); - - // Skip redundant check of clicked tile's neighbor index in City_Form::handle_left_click. - WITH_MEM_PROTECTION (ADDR_CITY_FORM_LEFT_CLICK_JUMP, 1, PAGE_EXECUTE_READWRITE) { - *ADDR_CITY_FORM_LEFT_CLICK_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) - } - - // Skip check that neighbor index passed to City::controls_tile is within work radius. This check is now implemented in the patch func. - WITH_MEM_PROTECTION (ADDR_CONTROLS_TILE_JUMP, 1, PAGE_EXECUTE_READWRITE) { - *ADDR_CONTROLS_TILE_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) - } - - // When searching for a tile on which to spawn pollution, the game wraps its search around by using remainder after division. Here, we replace - // the dividend to match a potentially expanded city work area. - WITH_MEM_PROTECTION (ADDR_SPAWN_POLLUTION_MOD, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_SPAWN_POLLUTION_MOD, is->workable_tile_count - 1); - } - - WITH_MEM_PROTECTION (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, cfg->patch_premature_truncation_of_found_paths ? 2560 : 256); - } - - int * trade_net_addrs; - bool already_moved_trade_net = is->trade_net != p_original_trade_net, - want_moved_trade_net = cfg->city_limit > 512; - int lifted_city_limit_exp = 11; - int lifted_city_limit = 1 << lifted_city_limit_exp; - if ((! at_program_start) && - ((trade_net_addrs = load_trade_net_addrs ()) != NULL) && - ((already_moved_trade_net && ! want_moved_trade_net) || (want_moved_trade_net && ! already_moved_trade_net))) { - // Allocate a new trade net object if necessary. To construct it, all we have to do is zero a few fields and set the vptr. Otherwise, - // set the allocated object aside for deletion later. Also set new & old addresses to the locations we're moving to & from. - Trade_Net * to_free = NULL; - int p_old, p_new; - if (want_moved_trade_net) { - is->trade_net = calloc (1, (sizeof (Trade_Net)) - (4 * 512 * 512) + (4 * lifted_city_limit * lifted_city_limit)); - is->city_limit = lifted_city_limit; - is->trade_net->vtable = p_original_trade_net->vtable; - p_old = (int)p_original_trade_net; - p_new = (int)is->trade_net; - } else { - to_free = is->trade_net; - is->city_limit = 512; - p_old = (int)is->trade_net; - p_new = (int)p_original_trade_net; - is->trade_net = p_original_trade_net; - } - already_moved_trade_net = is->trade_net != p_original_trade_net; // Keep this variable up to date - - // Patch all references from the "old" object to the "new" one - int offset; - bool popped_up_error = false; - char err_msg[200] = {0}; - int * refs; { - if (exe_version_index == 0) - refs = trade_net_addrs; - else if (exe_version_index == 1) // Steam version, skip refs and instructions for GOG - refs = &trade_net_addrs[TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; - else // PCGames.de version, skip two sets of refs and instrs for GOG & Steam - refs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; - } - for (int n_ref = 0; n_ref < TRADE_NET_REF_COUNT; n_ref++) { - int addr = refs[n_ref]; - WITH_MEM_PROTECTION ((void *)(addr - 10), 20, PAGE_EXECUTE_READWRITE) { - byte * instr = (byte *)addr; - if ((instr[0] == 0xB9) && (int_from_bytes (&instr[1]) == p_old)) // move trade net ptr to ecx - int_to_bytes (&instr[1], p_new); - else if ((instr[0] == 0xC7) && (instr[1] == 0x05) && (int_from_bytes (&instr[2]) == p_old)) // write trade net vtable ptr - int_to_bytes (&instr[2], p_new); - else if ((instr[0] == 0x81) && (instr[1] == 0xFE) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp esi, trade net location - ; // Do not patch this location because it's the upper limit for a memcpy - else if ((instr[0] == 0x81) && (instr[1] == 0xFF) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp edi, trade net location - ; // Same - else if ((instr[0] == 0x81) && (instr[1] == 0xFA) && (int_from_bytes (&instr[2]) == (int)&p_original_trade_net->Data2)) // cmp edx, trade net data2 location - ; // Same - else if (((instr[0] == 0xA3) || (instr[0] == 0xA1)) && // move eax to field or vice-versa - (offset = int_from_bytes (&instr[1]) - p_old, (offset >= 0) && (offset < 100))) - int_to_bytes (&instr[1], p_new + offset); - else if ((instr[0] == 0x89) && ((instr[1] >= 0x0D) && (instr[1] <= 0x3D)) && // move other regs to field - (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) - int_to_bytes (&instr[2], p_new + offset); - else if ((instr[0] == 0x8B) && ((instr[1] == 0x35) || (instr[1] == 0x3D) || (instr[1] == 0x0D)) && // mov field to esi, edi or ecx - (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) - int_to_bytes (&instr[2], p_new + offset); - else if (! popped_up_error) { - snprintf (err_msg, (sizeof err_msg) - 1, "Can't move trade net object from address 0x%x. Pattern doesn't match.", addr); - MessageBox (NULL, err_msg, NULL, MB_ICONERROR); - popped_up_error = true; - } - } - } - - // Patch all instructions that involve the stride of Trade_Net.Matrix - int * addrs, addr_count; { - if (exe_version_index == 0) { - addrs = &trade_net_addrs[TRADE_NET_REF_COUNT]; - addr_count = TRADE_NET_INSTR_COUNT_GOG; - } else if (exe_version_index == 1) { - addrs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; - addr_count = TRADE_NET_INSTR_COUNT_STEAM; - } else { - addrs = &trade_net_addrs[3 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; - addr_count = TRADE_NET_INSTR_COUNT_GOG; - } - for (int n = 0; n < addr_count; n++) { - byte * instr = (byte *)addrs[n]; - WITH_MEM_PROTECTION (instr, 10, PAGE_EXECUTE_READWRITE) { - if (! want_moved_trade_net) - restore_code_area (instr); - - else { - if ((instr[0] == 0xC1) && (instr[1] >= 0xE0) && (instr[1] <= 0xE7)) { // shl - save_code_area (instr, 3, false); - // shift amount is either 9 (1<<9 == 512) or 11 (1<<11 == 4*512, stride in bytes) - // in the second case, replace with lifted_exp + 2 to convert to bytes - instr[2] = lifted_city_limit_exp + ((instr[2] == 11) ? 2 : 0); - - } else if ((instr[0] == 0x81) && (instr[1] >= 0xC0) && (instr[1] <= 0xC7)) { // add - save_code_area (instr, 6, false); - int amount = int_from_bytes (&instr[2]); - // amount is either 512 or 4*512, replace with lifted_lim or 4*lifted_lim - int_to_bytes (&instr[2], (amount == 512) ? lifted_city_limit : 4*lifted_city_limit); - - } else if ((instr[0] == 0x8D) && (instr[1] == 0x9C) && (instr[2] == 0x90)) { // lea - save_code_area (instr, 7, false); - int offset = 4 * lifted_city_limit + 0x38; // stride in bytes plus 0x38 offset to Matrix in Trade_Net object - int_to_bytes (&instr[3], offset); - - } else if (instr[0] == 0xB9) { // mov - save_code_area (instr, 5, false); - int_to_bytes (&instr[1], lifted_city_limit * lifted_city_limit); - - } else if (! popped_up_error) { - snprintf (err_msg, (sizeof err_msg) - 1, "Can't patch matrix stride at address 0x%x. Pattern doesn't match.", (int)instr); - MessageBox (NULL, err_msg, NULL, MB_ICONERROR); - popped_up_error = true; - } - } - } - } - } - - // Reallocate diplo_form->tradable_cities array so it matches the city limit - civ_prog_free (p_diplo_form->tradable_cities); - int tradable_cities_len = want_moved_trade_net ? lifted_city_limit : 512, - tradable_cities_size = tradable_cities_len * sizeof (TradableItem); - p_diplo_form->tradable_cities = new (tradable_cities_size); - for (int n = 0; n < tradable_cities_len; n++) - p_diplo_form->tradable_cities[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 - - // Patch the size limit on some code that clears the tradable cities array when starting a new game - WITH_MEM_PROTECTION (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, tradable_cities_size); - } - - if (to_free) { - to_free->vtable->destruct (to_free, __, 0); - free (to_free); - } - } - - // Set is->city_limit and patch two instructions that contain the limit - is->city_limit = clamp (0, already_moved_trade_net ? lifted_city_limit : 512, cfg->city_limit); - WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN, 6, PAGE_EXECUTE_READWRITE) { - int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN[2], is->city_limit); - } - WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CREATE_CITY, 5, PAGE_EXECUTE_READWRITE) { - int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CREATE_CITY[1], is->city_limit); - } - WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_CITY_ID, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_MAX_TRADABLE_CITY_ID, already_moved_trade_net ? lifted_city_limit : 512); - } - - WITH_MEM_PROTECTION (ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR, 6, PAGE_EXECUTE_READWRITE) { - byte * instr = ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR; - if (cfg->years_to_double_building_culture == 1000) - restore_code_area (instr); - else { - if (instr[0] == 0x3D) { // in GOG and PCG EXEs, instr is cmp eax, 0x3E8 - save_code_area (instr, 5, false); - int_to_bytes (&instr[1], cfg->years_to_double_building_culture); - } else if (instr[0] == 0x3B) { // in Steam EXE, instr is cmp eax, dword ptr 0x688C9C - save_code_area (instr, 6, true); - instr[0] = 0x3D; - int_to_bytes (&instr[1], cfg->years_to_double_building_culture); - } - } - } - - WITH_MEM_PROTECTION (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, PAGE_EXECUTE_READWRITE) { - if (cfg->accentuate_cities_on_minimap) { - save_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, false); - emit_branch (BK_JUMP, ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL); - } else - restore_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT); - } - WITH_MEM_PROTECTION (ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { - byte * code = ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL; - code[0] = 0x55; code[1] = 0x53; // write push ebp and push ebx, two overwritten instrs before the call - emit_branch (BK_CALL, &code[2], &patch_get_pixel_to_draw_city_dot); // call patch func - emit_branch (BK_JUMP, &code[7], ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT + 5); // jump back to original code - } - - // Bypass adjacent resource of different type check - // replacing 0x7D (= jge) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9 = cfg->allow_adjacent_resources_of_different_types ? 0xEB : 0x7D; - - WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, PAGE_EXECUTE_READWRITE) { - if (cfg->tiles_per_non_luxury_resource == 32) - restore_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV); - else { - save_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, true); - - // Jump to replacement division logic, kept in an inlead because it doesn't fit in 7 bytes - emit_branch (BK_JUMP, ADDR_RESOURCE_GEN_TILE_COUNT_DIV, ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL); - - // Fill in the replacement division logic. Instead of computing tile_count>>5, compute tile_count/cfg->tiles_per_non_luxury_resource. - WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { - int d = not_below (1, cfg->tiles_per_non_luxury_resource); - byte d0 = d & 0xFF, - d1 = (d >> 8) & 0xFF, - d2 = (d >> 16) & 0xFF, - d3 = d >> 24; - - byte * cursor = ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL; - - // In the Steam EXE, the limit (tile_count/32 by default) must be left in ecx. For the other EXEs, edx. - if (exe_version_index == 1) { - byte new_div[] = { - 0x50, // push eax - 0x52, // push edx - 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count - 0x0F, 0xB7, 0xD2, // movzx edx, dx - 0x89, 0xD0, // mov eax, edx - 0x31, 0xD2, // xor edx, edx - 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} - 0xF7, 0xF1, // div ecx - 0x89, 0xC1, // mov ecx, eax - 0x5A, // pop edx - 0x58 // pop eax - }; - for (int n = 0; n < ARRAY_LEN (new_div); n++) - *cursor++ = new_div[n]; - - } else { - byte new_div[] = { - 0x50, // push eax - 0x51, // push ecx - 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count - 0x0F, 0xB7, 0xD2, // movzx edx, dx - 0x89, 0xD0, // mov eax, edx - 0x31, 0xD2, // xor edx, edx - 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} - 0xF7, 0xF1, // div ecx - 0x89, 0xC2, // mov edx, eax - 0x59, // pop ecx - 0x58 // pop eax - }; - for (int n = 0; n < ARRAY_LEN (new_div); n++) - *cursor++ = new_div[n]; - } - - cursor = emit_branch (BK_JUMP, cursor, ADDR_RESOURCE_GEN_TILE_COUNT_DIV + 7); - } - } - } - - // Disable a jump that skips playing victory animations for air units if they've been configured to have a victory anim - set_nopification (cfg->aircraft_victory_animation != NULL, ADDR_SKIP_VICTORY_ANIM_IF_AIR, 6); - - // Bypass capital check to return zero corruption - // replacing 0x75 (= jnz) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_CORRUPTION_CAPITAL_CHECK, 1, PAGE_EXECUTE_READWRITE) - *ADDR_CORRUPTION_CAPITAL_CHECK = cfg->allow_corruption_in_capital ? 0xEB : 0x75; - - // Insert amount added to building decorruption effect just for the capital - WITH_MEM_PROTECTION (ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT, 3, PAGE_EXECUTE_READWRITE) - *(ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT + 2) = clamp (0, 100, cfg->special_capital_decorruption_effect); -} - -void -get_mod_art_path (char const * file_name, char * out_path, int path_buf_size) -{ - char s[1000]; - snprintf (s, sizeof s, "Art\\%s", file_name); - s[(sizeof s) - 1] = '\0'; - - char * scenario_path = BIC_get_asset_path (p_bic_data, __, s, false); - if (0 != strcmp (scenario_path, s)) // get_asset_path returns its input when the file is not found - snprintf (out_path, path_buf_size, "%s", scenario_path); - else - snprintf (out_path, path_buf_size, "%s\\Art\\%s", is->mod_rel_dir, file_name); - out_path[path_buf_size - 1] = '\0'; -} - - -Sprite* -SpriteList_at(SpriteList *list, int i) { - return &list->field_0[i]; -} - -void -set_path(String260 *dst, const char *p) { - snprintf(dst->S, sizeof(dst->S), "%s", p); -} - -void -slice_grid(Sprite *out, PCX_Image *img, - int tile_w, int tile_h, int full_w, int full_h) -{ - for (int y = 0; y < full_h; y += tile_h) - for (int x = 0; x < full_w; x += tile_w) - Sprite_slice_pcx(out++, __, img, x, y, tile_w, tile_h, 1, 1); -} - -void -slice_grid_into_list(SpriteList *bucket, PCX_Image *img, - int tile_w, int tile_h, int full_w, int full_h) -{ - int k = 0; - for (int y = 0; y < full_h; y += tile_h) - for (int x = 0; x < full_w; x += tile_w) - Sprite_slice_pcx(SpriteList_at(bucket, k++), __, img, x, y, tile_w, tile_h, 1, 1); -} - -void -join_path(char *out, size_t out_sz, const char *dir, const char *file) -{ - size_t n = strlen(dir); - int need_sep = (n > 0 && dir[n-1] != '/' && dir[n-1] != '\\'); - snprintf(out, out_sz, "%s%s%s", dir, need_sep ? "\\" : "", file); -} - -void -read_in_dir(PCX_Image *img, - const char *art_dir, - const char *filename, - String260 *store) { - char pbuf[512]; - join_path(pbuf, sizeof pbuf, art_dir, filename); - if (store) { - // assumes: typedef struct { char S[260]; } String260; - snprintf(store->S, sizeof store->S, "%s", pbuf); - } - - char temp_path[2*MAX_PATH]; - - snprintf(temp_path, sizeof temp_path, "%s\\%s", art_dir, filename); - PCX_Image_read_file(img, __, temp_path, NULL, 0, 0x100, 2); -} - -bool load_day_night_hour_images(struct day_night_cycle_img_set *this, const char *art_dir, const char *hour) -{ - char ss[200]; - PCX_Image img; - PCX_Image_construct(&img); - - // Std terrain (9 sheets): 6x9 of 128x64 over 0x480x0x240 - const char *STD_SHEETS[9] = { - "xtgc.pcx", "xpgc.pcx", "xdgc.pcx", "xdpc.pcx", "xdgp.pcx", "xggc.pcx", - "wCSO.pcx", "wSSS.pcx", "wOOO.pcx" - }; - for (int i = 0; i < 9; ++i) { - read_in_dir(&img, art_dir, STD_SHEETS[i], NULL); - if (img.JGL.Image == NULL) return false; - slice_grid_into_list(&this->Std_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); - } - - // LM terrain (9): same slicing - const char *LMT_SHEETS[9] = { - "lxtgc.pcx", "lxpgc.pcx", "lxdgc.pcx", "lxdpc.pcx", "lxdgp.pcx", "lxggc.pcx", - "lwCSO.pcx", "lwSSS.pcx", "lwOOO.pcx" - }; - for (int i = 0; i < 9; ++i) { - read_in_dir(&img, art_dir, LMT_SHEETS[i], NULL); - if (img.JGL.Image == NULL) return false; - slice_grid_into_list(&this->LM_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); - } - - // Polar icecaps: 8x4 of 128x64 - read_in_dir(&img, art_dir, "polarICEcaps-final.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Polar_Icecaps_Images, &img, 0x80, 0x40, 0x400, 0x100); - - // Hills / LM Hills: 4x3 of 128x72 - read_in_dir(&img, art_dir, "xhills.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); - read_in_dir(&img, art_dir, "hill forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Hills_Forests_Images, &img, 0x80, 0x48, 0x200, 0x120); - read_in_dir(&img, art_dir, "hill jungle.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Hills_Jungle_Images, &img, 0x80, 0x48, 0x200, 0x120); - read_in_dir(&img, art_dir, "LMHills.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->LM_Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); - - // Flood plains: 4x4 of 128x64 - read_in_dir(&img, art_dir, "floodplains.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Flood_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); - - // Delta + Mountain rivers: 4x4 each, interleaved across one contiguous block - { - const char *RIV_SHEETS[2] = { "deltaRivers.pcx", "mtnRivers.pcx" }; - Sprite *contig = this->Delta_Rivers_Images; // Mountain_Rivers_Images follows - for (int s = 0; s < 2; ++s) { - read_in_dir(&img, art_dir, RIV_SHEETS[s], NULL); - if (img.JGL.Image == NULL) return false; - Sprite *p = contig + s; // even=delta, odd=mountain - for (int y = 0; y < 0x100; y += 0x40) - for (int x = 0; x < 0x200; x += 0x80) { - Sprite_slice_pcx(p, __, &img, x, y, 0x80, 0x40, 1, 1); - p += 2; - } - } - } - - // Waterfalls: 4x1 of 128x64 - read_in_dir(&img, art_dir, "waterfalls.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Waterfalls_Images, &img, 0x80, 0x40, 0x200, 0x40); - - // Irrigation (desert/plains/normal/tundra): each 4x4 of 128x64 - read_in_dir(&img, art_dir, "irrigation DESETT.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Desert_Images, &img, 0x80, 0x40, 0x200, 0x100); - read_in_dir(&img, art_dir, "irrigation PLAINS.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); - read_in_dir(&img, art_dir, "irrigation.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Images, &img, 0x80, 0x40, 0x200, 0x100); - read_in_dir(&img, art_dir, "irrigation TUNDRA.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Tundra_Images, &img, 0x80, 0x40, 0x200, 0x100); - - // Volcanos (plain/forests/jungles/snow): 4x4 of 128x88 - read_in_dir(&img, art_dir, "Volcanos.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Volcanos forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Volcanos jungles.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Volcanos-snow.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); - - // Marsh: Large band then Small band (tiles 128x88) - read_in_dir(&img, art_dir, "marsh.pcx", NULL); - if (img.JGL.Image == NULL) return false; - // Large (2 rows, 4 cols) - { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Marsh_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - // Small (2 rows, 5 cols) - { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Marsh_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - // LM mountains + standard mountains (plain/forests/jungles/snow): 4x4 of 128x88 - read_in_dir(&img, art_dir, "LMMountains.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->LM_Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Mountains.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "mountain forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "mountain jungles.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Mountains-snow.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); - - // Roads (16x16) and Railroads (16x17), tiles 128x64 - read_in_dir(&img, art_dir, "roads.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Roads_Images, &img, 0x80, 0x40, 0x800, 0x400); - read_in_dir(&img, art_dir, "railroads.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Railroads_Images, &img, 0x80, 0x40, 0x800, 0x440); - - // LM Forests (Large 2x4, Small 2x6, Pines 2x6), tiles 128x88 - read_in_dir(&img, art_dir, "LMForests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->LM_Forests_Large_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->LM_Forests_Small_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->LM_Forests_Pines_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - // Grassland/Plains/Tundra forests & jungles (bands; tiles 128x88) — order is important - read_in_dir(&img, art_dir, "grassland forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - // Jungles Large, Small - { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Jungles_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Jungles_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - // Forests Large, Small, Pines - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - read_in_dir(&img, art_dir, "plains forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Plains_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Plains_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Plains_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - read_in_dir(&img, art_dir, "tundra forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Tundra_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Tundra_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Tundra_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - // LM Terrain (7 single 128x64, vertical strip) - read_in_dir(&img, art_dir, "landmark_terrain.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i = 0, y = 0; i < 7; ++i, y += 0x40) - Sprite_slice_pcx(&this->LM_Terrain[i], __, &img, 0, y, 0x80, 0x40, 1, 1); - - // TNT (same odd ordering as original) - read_in_dir(&img, art_dir, "tnt.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[6+i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[9+i], __, &img, x, 0x40, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[12+i], __, &img, x, 0x80, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[0+i], __, &img, x, 0xC0, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[15+i], __, &img, x, 0x100, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[3+i], __, &img, x, 0x140, 0x80, 0x40, 1, 1); - - // Goody huts: 8 tiles, x=(i%3)*0x80, y=(i/3)*0x40 - read_in_dir(&img, art_dir, "goodyhuts.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i = 0; i < 8; ++i) { - int x = (i % 3) << 7; - int y = (i / 3) << 6; - Sprite_slice_pcx(&this->Goody_Huts_Images[i], __, &img, x, y, 0x80, 0x40, 1, 1); - } - - // Terrain buildings (fortress/camp/barbarian camp/mines/barricade) - read_in_dir(&img, art_dir, "TerrainBuildings.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Fortress[i], __, &img, 0x00, y, 0x80, 0x40, 1, 1); - for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Camp[i], __, &img, 0x80, y, 0x80, 0x40, 1, 1); - Sprite_slice_pcx(&this->Terrain_Buldings_Barbarian_Camp, __, &img, 0x100, 0x00, 0x80, 0x40, 1, 1); - Sprite_slice_pcx(&this->Terrain_Buldings_Mines, __, &img, 0x100, 0x40, 0x80, 0x40, 1, 1); - for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Barricade[i], __, &img, 0x180, y, 0x80, 0x40, 1, 1); - - // Pollution & Craters (5x5 of 128x64) - read_in_dir(&img, art_dir, "pollution.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Pollution, &img, 0x80, 0x40, 0x280, 0x140); - read_in_dir(&img, art_dir, "craters.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Craters, &img, 0x80, 0x40, 0x280, 0x140); - - // Airfields / Outposts / Radar - read_in_dir(&img, art_dir, "x_airfields and detect.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i=0, x=0; i<2; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Airfields[i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Outposts[i], __, &img, x, 0x40, 0x80, 0x80, 1, 1); - Sprite_slice_pcx(&this->Terrain_Buldings_Radar, __, &img, 0x00, 0xC0, 0x80, 0x80, 1, 1); - - // Victory (single 128x64) - read_in_dir(&img, art_dir, "x_victory.pcx", NULL); - if (img.JGL.Image == NULL) return false; - Sprite_slice_pcx(&this->Victory_Image, __, &img, 0, 0, 0x80, 0x40, 1, 1); - - // Resources - read_in_dir(&img, art_dir, "resources.pcx", NULL); - if (img.JGL.Image == NULL) return false; - size_t k = 0; - for (int r = 0, y = 1; r < 6; ++r, y += 50) { - for (int c = 0, x = 1; c < 6; ++c, x += 50) { - Sprite_slice_pcx(&this->Resources[k++], __, &img, x, y, 49, 49, 1, 1); - } - } - - // Base cities - static const char *CITY_BASE[5] = { - "rAMER.pcx", "rEURO.pcx", "rROMAN.pcx", "rMIDEAST.pcx", "rASIAN.pcx" - }; - for (int culture = 0; culture < 5; culture++) { - read_in_dir(&img, art_dir, CITY_BASE[culture], NULL); - if (img.JGL.Image == NULL) return false; - int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; - int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; - int y = 0; - for (int era = 0; era < 4; ++era, y += sprite_h) { - int x = 0; - for (int size = 0; size < 3; ++size, x += sprite_w) { - const int idx = culture + 5*era + 20*size; - Sprite_slice_pcx(&this->City_Images[idx], __, &img, x, y, sprite_w, sprite_h, 1, 1); - } - } - } - - // Walled cities - static const char *CITY_WALL[5] = { - "AMERWALL.pcx", "EUROWALL.pcx", "ROMANWALL.pcx", "MIDEASTWALL.pcx", "ASIANWALL.pcx" - }; - for (int culture = 0; culture < 5; ++culture) { - read_in_dir(&img, art_dir, CITY_WALL[culture], NULL); - if (img.JGL.Image == NULL) return false; - int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image); - int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; - int y = 0; - for (int era = 0; era < 4; ++era, y += sprite_h) { - const int size = 3; // walled towns are a special category - const int idx = culture + 5*era + 20*size; - Sprite_slice_pcx(&this->City_Images[idx], __, &img, 0, y, sprite_w, sprite_h, 1, 1); - } - } - - // Destroyed cities - read_in_dir(&img, art_dir, "DESTROY.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { - int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; - int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image); - int x = 0; - for (int i = 0; i < 3; ++i, x += sprite_w) - Sprite_slice_pcx(&this->Destroyed_City_Images[i], __, &img, x, 0, sprite_w, sprite_h, 1, 1); - } - - // Districts (if enabled) - if (is->current_config.enable_districts) { - char art_dir[200]; - char temp_path[2*MAX_PATH]; - snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - for (int dc = 0; dc < is->district_count; dc++) { - struct district_config const * cfg = &is->district_configs[dc]; - int variant_capacity = ARRAY_LEN (this->District_Images[dc]); - int variant_count = cfg->img_path_count; - if (variant_count <= 0) - continue; - if (variant_count > variant_capacity) - variant_count = variant_capacity; - - int era_count = cfg->vary_img_by_era ? 4 : 1; - int column_count = cfg->img_column_count; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - - for (int variant_i = 0; variant_i < variant_count; variant_i++) { - const char * img_path = cfg->img_paths[variant_i]; - if ((img_path == NULL) || (img_path[0] == '\0')) - continue; - - read_in_dir (&img, temp_path, img_path, NULL); - if (img.JGL.Image == NULL) - return false; - - for (int era = 0; era < era_count; era++) { - for (int col = 0; col < column_count; col++) { - int tile_x = sprite_width * col; - int tile_y = sprite_height * era; - Sprite_slice_pcx (&this->District_Images[dc][variant_i][era][col], __, &img, tile_x, tile_y, sprite_width, sprite_height, 1, 1); - } - } - } - } - - // Abandoned district art (land + maritime) for this hour - read_in_dir (&img, temp_path, "Abandoned.pcx", NULL); - if (img.JGL.Image == NULL) - return false; - Sprite_slice_pcx (&this->Abandoned_District_Image, __, &img, 0, 0, 128, 64, 1, 1); - Sprite_slice_pcx (&this->Abandoned_Maritime_District_Image, __, &img, 128, 0, 128, 64, 1, 1); - - // Load wonder district images (dynamically per wonder) for this hour - if (is->current_config.enable_wonder_districts) { - char const * last_img_path = NULL; - PCX_Image wpcx; - PCX_Image_construct (&wpcx); - bool pcx_loaded = false; - - for (int wi = 0; wi < is->wonder_district_count; wi++) { - struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; - char const * img_path = cfg->img_path; - if (img_path == NULL) - img_path = "Wonders.pcx"; - - // Load new image file if different from previous - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - - read_in_dir (&wpcx, temp_path, img_path, NULL); - - if (wpcx.JGL.Image == NULL) { - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - struct wonder_district_image_set * set = &this->Wonder_District_Images[wi]; - - Sprite_construct (&set->img); - int x = 128 * cfg->img_column; - int y = 64 * cfg->img_row; - Sprite_slice_pcx (&set->img, __, &wpcx, x, y, 128, 64, 1, 1); - - Sprite_construct (&set->construct_img); - int cx = 128 * cfg->img_construct_column; - int cy = 64 * cfg->img_construct_row; - Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, 128, 64, 1, 1); - - if (cfg->enable_img_alt_dir) { - Sprite_construct (&set->alt_dir_img); - int ax = 128 * cfg->img_alt_dir_column; - int ay = 64 * cfg->img_alt_dir_row; - Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, 128, 64, 1, 1); - - Sprite_construct (&set->alt_dir_construct_img); - int acx = 128 * cfg->img_alt_dir_construct_column; - int acy = 64 * cfg->img_alt_dir_construct_row; - Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, 128, 64, 1, 1); - } - } - - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - wpcx.vtable->destruct (&wpcx, __, 0); - } - - } - - if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { - char art_dir[200]; - char temp_path[2*MAX_PATH]; - snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - - char const * last_img_path = NULL; - PCX_Image nwpcx; - PCX_Image_construct (&nwpcx); - bool pcx_loaded = false; - - for (int ni = 0; ni < is->natural_wonder_count; ni++) { - struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; - if ((cfg->img_path == NULL) || (cfg->img_path[0] == '\0')) - continue; - - char const * img_path = cfg->img_path; - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - - read_in_dir (&nwpcx, temp_path, img_path, NULL); - - if (nwpcx.JGL.Image == NULL) { - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - Sprite_construct (&this->Natural_Wonder_Images[ni].img); - int x = 128 * cfg->img_column; - int y = 88 * cfg->img_row; - Sprite_slice_pcx (&this->Natural_Wonder_Images[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); - } - - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - nwpcx.vtable->destruct (&nwpcx, __, 0); - } - - img.vtable->destruct (&img, __, 0); - - return true; -} - -Sprite * -get_sprite_proxy_for_current_hour(Sprite *s) { - int v; - int hour = is->current_day_night_cycle; // 0..23 - if (itable_look_up(&is->day_night_sprite_proxy_by_hour[hour], (int)s, &v)) - return (Sprite *)v; - return NULL; // not proxied, fall back to s -} - -void -insert_spritelist_proxies(SpriteList *ss, SpriteList *ps, int hour, int len1, int len2) { - for (int i = 0; i < len1; i++) { - for (int j = 0; j < len2; j++) { - Sprite *s = &ss[i].field_0[j]; - Sprite *p = &ps[i].field_0[j]; - if (s && p) { - itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); - } - } - } -} - -void -insert_sprite_proxies(Sprite *ss, Sprite *ps, int hour, int len) { - for (int i = 0; i < len; i++) { - Sprite *s = &ss[i]; - Sprite *p = &ps[i]; - if (s && p) { - itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); - } - } -} - -void -insert_sprite_proxy(Sprite *s, Sprite *p, int hour) { - if (s && p) { - itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); - } -} - -void -build_sprite_proxies_24(Map_Renderer *mr) { - for (int h = 0; h < 24; ++h) { - insert_sprite_proxies(city_sprites, is->day_night_cycle_imgs[h].City_Images, h, 80); - insert_sprite_proxies(destroyed_city_sprites, is->day_night_cycle_imgs[h].Destroyed_City_Images, h, 3); - insert_sprite_proxies(mr->Resources, is->day_night_cycle_imgs[h].Resources, h, 36); - insert_spritelist_proxies(mr->Std_Terrain_Images, is->day_night_cycle_imgs[h].Std_Terrain_Images, h, 9, 81); - insert_spritelist_proxies(mr->LM_Terrain_Images, is->day_night_cycle_imgs[h].LM_Terrain_Images, h, 9, 81); - insert_sprite_proxy(&mr->Terrain_Buldings_Barbarian_Camp, &is->day_night_cycle_imgs[h].Terrain_Buldings_Barbarian_Camp, h); - insert_sprite_proxy(&mr->Terrain_Buldings_Mines, &is->day_night_cycle_imgs[h].Terrain_Buldings_Mines, h); - insert_sprite_proxy(&mr->Victory_Image, &is->day_night_cycle_imgs[h].Victory_Image, h); - insert_sprite_proxy(&mr->Terrain_Buldings_Radar, &is->day_night_cycle_imgs[h].Terrain_Buldings_Radar, h); - insert_sprite_proxies(mr->Flood_Plains_Images, is->day_night_cycle_imgs[h].Flood_Plains_Images, h, 16); - insert_sprite_proxies(mr->Polar_Icecaps_Images, is->day_night_cycle_imgs[h].Polar_Icecaps_Images, h, 32); - insert_sprite_proxies(mr->Roads_Images, is->day_night_cycle_imgs[h].Roads_Images, h, 256); - insert_sprite_proxies(mr->Railroads_Images, is->day_night_cycle_imgs[h].Railroads_Images, h, 272); - insert_sprite_proxies(mr->Terrain_Buldings_Airfields, is->day_night_cycle_imgs[h].Terrain_Buldings_Airfields, h, 2); - insert_sprite_proxies(mr->Terrain_Buldings_Camp, is->day_night_cycle_imgs[h].Terrain_Buldings_Camp, h, 4); - insert_sprite_proxies(mr->Terrain_Buldings_Fortress, is->day_night_cycle_imgs[h].Terrain_Buldings_Fortress, h, 4); - insert_sprite_proxies(mr->Terrain_Buldings_Barricade, is->day_night_cycle_imgs[h].Terrain_Buldings_Barricade, h, 4); - insert_sprite_proxies(mr->Goody_Huts_Images, is->day_night_cycle_imgs[h].Goody_Huts_Images, h, 8); - insert_sprite_proxies(mr->Terrain_Buldings_Outposts, is->day_night_cycle_imgs[h].Terrain_Buldings_Outposts, h, 3); - insert_sprite_proxies(mr->Pollution, is->day_night_cycle_imgs[h].Pollution, h, 25); - insert_sprite_proxies(mr->Craters, is->day_night_cycle_imgs[h].Craters, h, 25); - insert_sprite_proxies(mr->Tnt_Images, is->day_night_cycle_imgs[h].Tnt_Images, h, 18); - insert_sprite_proxies(mr->Waterfalls_Images, is->day_night_cycle_imgs[h].Waterfalls_Images, h, 4); - insert_sprite_proxies(mr->LM_Terrain, is->day_night_cycle_imgs[h].LM_Terrain, h, 7); - insert_sprite_proxies(mr->Marsh_Large, is->day_night_cycle_imgs[h].Marsh_Large, h, 8); - insert_sprite_proxies(mr->Marsh_Small, is->day_night_cycle_imgs[h].Marsh_Small, h, 10); - insert_sprite_proxies(mr->Volcanos_Images, is->day_night_cycle_imgs[h].Volcanos_Images, h, 16); - insert_sprite_proxies(mr->Volcanos_Forests_Images, is->day_night_cycle_imgs[h].Volcanos_Forests_Images, h, 16); - insert_sprite_proxies(mr->Volcanos_Jungles_Images, is->day_night_cycle_imgs[h].Volcanos_Jungles_Images, h, 16); - insert_sprite_proxies(mr->Volcanos_Snow_Images, is->day_night_cycle_imgs[h].Volcanos_Snow_Images, h, 16); - insert_sprite_proxies(mr->Grassland_Forests_Large, is->day_night_cycle_imgs[h].Grassland_Forests_Large, h, 8); - insert_sprite_proxies(mr->Plains_Forests_Large, is->day_night_cycle_imgs[h].Plains_Forests_Large, h, 8); - insert_sprite_proxies(mr->Tundra_Forests_Large, is->day_night_cycle_imgs[h].Tundra_Forests_Large, h, 8); - insert_sprite_proxies(mr->Grassland_Forests_Small, is->day_night_cycle_imgs[h].Grassland_Forests_Small, h, 10); - insert_sprite_proxies(mr->Plains_Forests_Small, is->day_night_cycle_imgs[h].Plains_Forests_Small, h, 10); - insert_sprite_proxies(mr->Tundra_Forests_Small, is->day_night_cycle_imgs[h].Tundra_Forests_Small, h, 10); - insert_sprite_proxies(mr->Grassland_Forests_Pines, is->day_night_cycle_imgs[h].Grassland_Forests_Pines, h, 12); - insert_sprite_proxies(mr->Plains_Forests_Pines, is->day_night_cycle_imgs[h].Plains_Forests_Pines, h, 12); - insert_sprite_proxies(mr->Tundra_Forests_Pines, is->day_night_cycle_imgs[h].Tundra_Forests_Pines, h, 12); - insert_sprite_proxies(mr->Irrigation_Desert_Images, is->day_night_cycle_imgs[h].Irrigation_Desert_Images, h, 16); - insert_sprite_proxies(mr->Irrigation_Plains_Images, is->day_night_cycle_imgs[h].Irrigation_Plains_Images, h, 16); - insert_sprite_proxies(mr->Irrigation_Images, is->day_night_cycle_imgs[h].Irrigation_Images, h, 16); - insert_sprite_proxies(mr->Irrigation_Tundra_Images, is->day_night_cycle_imgs[h].Irrigation_Tundra_Images, h, 16); - insert_sprite_proxies(mr->Grassland_Jungles_Large, is->day_night_cycle_imgs[h].Grassland_Jungles_Large, h, 8); - insert_sprite_proxies(mr->Grassland_Jungles_Small, is->day_night_cycle_imgs[h].Grassland_Jungles_Small, h, 12); - insert_sprite_proxies(mr->Mountains_Images, is->day_night_cycle_imgs[h].Mountains_Images, h, 16); - insert_sprite_proxies(mr->Mountains_Forests_Images, is->day_night_cycle_imgs[h].Mountains_Forests_Images, h, 16); - insert_sprite_proxies(mr->Mountains_Jungles_Images, is->day_night_cycle_imgs[h].Mountains_Jungles_Images, h, 16); - insert_sprite_proxies(mr->Mountains_Snow_Images, is->day_night_cycle_imgs[h].Mountains_Snow_Images, h, 16); - insert_sprite_proxies(mr->Hills_Images, is->day_night_cycle_imgs[h].Hills_Images, h, 16); - insert_sprite_proxies(mr->Hills_Forests_Images, is->day_night_cycle_imgs[h].Hills_Forests_Images, h, 16); - insert_sprite_proxies(mr->Hills_Jungle_Images, is->day_night_cycle_imgs[h].Hills_Jungle_Images, h, 16); - insert_sprite_proxies(mr->Delta_Rivers_Images, is->day_night_cycle_imgs[h].Delta_Rivers_Images, h, 16); - insert_sprite_proxies(mr->Mountain_Rivers_Images, is->day_night_cycle_imgs[h].Mountain_Rivers_Images, h, 16); - insert_sprite_proxies(mr->LM_Mountains_Images, is->day_night_cycle_imgs[h].LM_Mountains_Images, h, 16); - insert_sprite_proxies(mr->LM_Forests_Large_Images, is->day_night_cycle_imgs[h].LM_Forests_Large_Images, h, 8); - insert_sprite_proxies(mr->LM_Forests_Small_Images, is->day_night_cycle_imgs[h].LM_Forests_Small_Images, h, 10); - insert_sprite_proxies(mr->LM_Forests_Pines_Images, is->day_night_cycle_imgs[h].LM_Forests_Pines_Images, h, 12); - insert_sprite_proxies(mr->LM_Hills_Images, is->day_night_cycle_imgs[h].LM_Hills_Images, h, 16); - - if (is->current_config.enable_districts) { - for (int dc = 0; dc < is->district_count; dc++) { - struct district_config const * cfg = &is->district_configs[dc]; - int variant_capacity = ARRAY_LEN (is->district_img_sets[dc].imgs); - int variant_count = cfg->img_path_count; - if (variant_count <= 0) - continue; - if (variant_count > variant_capacity) - variant_count = variant_capacity; - - int era_count = cfg->vary_img_by_era ? 4 : 1; - int column_count = cfg->img_column_count; - - for (int variant_i = 0; variant_i < variant_count; variant_i++) { - if ((cfg->img_paths[variant_i] == NULL) || (cfg->img_paths[variant_i][0] == '\0')) - continue; - for (int era = 0; era < era_count; era++) { - for (int col = 0; col < column_count; col++) { - Sprite * base = &is->district_img_sets[dc].imgs[variant_i][era][col]; - Sprite * proxy = &is->day_night_cycle_imgs[h].District_Images[dc][variant_i][era][col]; - insert_sprite_proxy (base, proxy, h); - } - } - } - } - - insert_sprite_proxy (&is->abandoned_district_img, &is->day_night_cycle_imgs[h].Abandoned_District_Image, h); - insert_sprite_proxy (&is->abandoned_maritime_district_img, &is->day_night_cycle_imgs[h].Abandoned_Maritime_District_Image, h); - - // Wonder districts - if (is->current_config.enable_wonder_districts) { - for (int wi = 0; wi < is->wonder_district_count; wi++) { - Sprite * base_img = &is->wonder_district_img_sets[wi].img; - Sprite * proxy_img = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].img; - insert_sprite_proxy (base_img, proxy_img, h); - - Sprite * base_construct = &is->wonder_district_img_sets[wi].construct_img; - Sprite * proxy_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].construct_img; - insert_sprite_proxy (base_construct, proxy_construct, h); - - if (is->wonder_district_img_sets[wi].alt_dir_img.vtable != NULL) { - Sprite * base_alt = &is->wonder_district_img_sets[wi].alt_dir_img; - Sprite * proxy_alt = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_img; - insert_sprite_proxy (base_alt, proxy_alt, h); - } - - if (is->wonder_district_img_sets[wi].alt_dir_construct_img.vtable != NULL) { - Sprite * base_alt_construct = &is->wonder_district_img_sets[wi].alt_dir_construct_img; - Sprite * proxy_alt_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_construct_img; - insert_sprite_proxy (base_alt_construct, proxy_alt_construct, h); - } - } - } - } - - // Natural wonders - if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { - for (int ni = 0; ni < is->natural_wonder_count; ni++) { - Sprite * base_nw = &is->natural_wonder_img_sets[ni].img; - Sprite * proxy_nw = &is->day_night_cycle_imgs[h].Natural_Wonder_Images[ni].img; - insert_sprite_proxy (base_nw, proxy_nw, h); - } - } - } - is->day_night_cycle_img_proxies_indexed = true; -} - -void -init_day_night_images() -{ - if (is->day_night_cycle_img_state != IS_UNINITED) - return; - - const char *hour_strs[24] = { - "2400", "0100", "0200", "0300", "0400", "0500", "0600", "0700", - "0800", "0900", "1000", "1100", "1200", "1300", "1400", "1500", - "1600", "1700", "1800", "1900", "2000", "2100", "2200", "2300" - }; - - for (int i = 0; i < 24; i++) { - - char art_dir[200]; - char temp_path[2*MAX_PATH]; - snprintf (art_dir, sizeof art_dir, "DayNight/%s", hour_strs[i]); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - bool success = load_day_night_hour_images (&is->day_night_cycle_imgs[i], temp_path, hour_strs[i]); - - if (!success) { - char ss[200]; - snprintf(ss, sizeof ss, "Failed to load day/night cycle images for hour %s, reverting to base game art.", hour_strs[i]); - pop_up_in_game_error (ss); - - is->day_night_cycle_img_state = IS_INIT_FAILED; - return; - } - } - - Map_Renderer * mr = &p_bic_data->Map.Renderer; - build_sprite_proxies_24(mr); - - is->day_night_cycle_img_state = IS_OK; -} - -void -deindex_day_night_image_proxies() -{ - if (!is->day_night_cycle_img_proxies_indexed) - return; - - for (int i = 0; i < 24; i++) { - table_deinit (&is->day_night_sprite_proxy_by_hour[i]); - } - is->day_night_cycle_img_proxies_indexed = false; -} - -int -calculate_current_day_night_cycle_hour () -{ - int output = 12; // Default to noon - int increment = is->current_config.fixed_hours_per_turn_for_day_night_cycle; - - switch (is->current_config.day_night_cycle_mode) { - - // Disabled. This shouldn't be possible, but default to noon to be safe - case DNCM_OFF: - return output; - - // Time elapsed since last update - case DNCM_TIMER: { - LARGE_INTEGER perf_freq; - QueryPerformanceFrequency(&perf_freq); - - if (is->day_night_cycle_unstarted) { - is->current_day_night_cycle = output; - QueryPerformanceCounter(&is->last_day_night_cycle_update_time); - } - - LARGE_INTEGER time_now; - QueryPerformanceCounter(&time_now); - - double elapsed_seconds = - (double)(time_now.QuadPart - is->last_day_night_cycle_update_time.QuadPart) / - (double)perf_freq.QuadPart; - - if (elapsed_seconds > (double)is->current_config.elapsed_minutes_per_day_night_hour_transition * 60.0) { - output = is->current_day_night_cycle + increment; - is->last_day_night_cycle_update_time = time_now; - } else { - output = is->current_day_night_cycle; - } - break; - } - - // Match user's current time - case DNCM_USER_TIME: { - LPSYSTEMTIME lpSystemTime = (LPSYSTEMTIME)malloc(sizeof(SYSTEMTIME)); - GetLocalTime (lpSystemTime); - output = lpSystemTime->wHour; - free (lpSystemTime); - break; - } - - // Increment fixed amount each interturn - case DNCM_EVERY_TURN: { - if (is->day_night_cycle_unstarted) { - increment = 0; - is->current_day_night_cycle = output; - } - output = is->current_day_night_cycle + increment; - break; - } - - // Pin the hour to a specific value - case DNCM_SPECIFIED: { - output = is->current_config.pinned_hour_for_day_night_cycle; - break; - } - } - - // If midnight or over, restart at 0 or later - if (output > 23) output = output - 24; - - // Clamp to valid range of 0-23 in case of weird config values - output = clamp (0, 23, output); - is->day_night_cycle_unstarted = false; - - return output; -} - -void __fastcall -patch_Map_Renderer_load_images (Map_Renderer *this, int edx) -{ - Map_Renderer_load_images(this, __); - - // Initialize day/night cycle and re-calculate hour, if applicable - if (is->current_config.day_night_cycle_mode != DNCM_OFF) { - is->current_day_night_cycle = calculate_current_day_night_cycle_hour (); - - if (is->day_night_cycle_img_state == IS_UNINITED) { - init_day_night_images (); - } - - if (is->day_night_cycle_img_state == IS_OK) { - - // Sprite proxies are deindexed during each load event as sprite instances (really only Resources, which are reloaded) may change. - if (!is->day_night_cycle_img_proxies_indexed) { - build_sprite_proxies_24(this); - } - } - } -} - -void -patch_init_floating_point () -{ - init_floating_point (); - - // NOTE: At this point the program is done with the CRT initialization stuff and will start calling constructors for global - // objects as soon as this function returns. This is a good place to inject code that will run at program start. - - // Specify metadata about all boolean options on the mod config. We'll use this info to set up the table of offsets (for easy parsing) and to - // fill out the base config. - struct boolean_config_option { - char * name; - bool base_val; - int offset; - } boolean_config_options[] = { - {"enable_stack_bombard" , true , offsetof (struct c3x_config, enable_stack_bombard)}, - {"enable_disorder_warning" , true , offsetof (struct c3x_config, enable_disorder_warning)}, - {"allow_stealth_attack_against_single_unit" , false, offsetof (struct c3x_config, allow_stealth_attack_against_single_unit)}, - {"show_detailed_city_production_info" , true , offsetof (struct c3x_config, show_detailed_city_production_info)}, - {"limited_railroads_work_like_fast_roads" , false, offsetof (struct c3x_config, limited_railroads_work_like_fast_roads)}, - {"exclude_cities_from_units_per_tile_limit" , false, offsetof (struct c3x_config, exclude_cities_from_units_per_tile_limit)}, - {"enable_free_buildings_from_small_wonders" , true , offsetof (struct c3x_config, enable_free_buildings_from_small_wonders)}, - {"enable_stack_unit_commands" , true , offsetof (struct c3x_config, enable_stack_unit_commands)}, - {"skip_repeated_tile_improv_replacement_asks" , true , offsetof (struct c3x_config, skip_repeated_tile_improv_replacement_asks)}, - {"autofill_best_gold_amount_when_trading" , true , offsetof (struct c3x_config, autofill_best_gold_amount_when_trading)}, - {"disallow_founding_next_to_foreign_city" , true , offsetof (struct c3x_config, disallow_founding_next_to_foreign_city)}, - {"enable_trade_screen_scroll" , true , offsetof (struct c3x_config, enable_trade_screen_scroll)}, - {"group_units_on_right_click_menu" , true , offsetof (struct c3x_config, group_units_on_right_click_menu)}, - {"gray_out_units_on_menu_with_no_remaining_moves" , true , offsetof (struct c3x_config, gray_out_units_on_menu_with_no_remaining_moves)}, - {"put_movement_icons_on_units_on_menu" , true , offsetof (struct c3x_config, put_movement_icons_on_units_on_menu)}, - {"describe_states_of_units_on_menu" , true , offsetof (struct c3x_config, describe_states_of_units_on_menu)}, - {"show_golden_age_turns_remaining" , true , offsetof (struct c3x_config, show_golden_age_turns_remaining)}, - {"show_zoc_attacks_from_mid_stack" , true , offsetof (struct c3x_config, show_zoc_attacks_from_mid_stack)}, - {"show_armies_performing_defensive_bombard" , true , offsetof (struct c3x_config, show_armies_performing_defensive_bombard)}, - {"cut_research_spending_to_avoid_bankruptcy" , true , offsetof (struct c3x_config, cut_research_spending_to_avoid_bankruptcy)}, - {"dont_pause_for_love_the_king_messages" , true , offsetof (struct c3x_config, dont_pause_for_love_the_king_messages)}, - {"reverse_specialist_order_with_shift" , true , offsetof (struct c3x_config, reverse_specialist_order_with_shift)}, - {"toggle_zoom_with_z_on_city_screen" , true , offsetof (struct c3x_config, toggle_zoom_with_z_on_city_screen)}, - {"dont_give_king_names_in_non_regicide_games" , true , offsetof (struct c3x_config, dont_give_king_names_in_non_regicide_games)}, - {"no_elvis_easter_egg" , false, offsetof (struct c3x_config, no_elvis_easter_egg)}, - {"disable_worker_automation" , false, offsetof (struct c3x_config, disable_worker_automation)}, - {"enable_land_sea_intersections" , false, offsetof (struct c3x_config, enable_land_sea_intersections)}, - {"disallow_trespassing" , false, offsetof (struct c3x_config, disallow_trespassing)}, - {"show_detailed_tile_info" , true , offsetof (struct c3x_config, show_detailed_tile_info)}, - {"warn_about_unrecognized_names" , true , offsetof (struct c3x_config, warn_about_unrecognized_names)}, - {"enable_ai_production_ranking" , true , offsetof (struct c3x_config, enable_ai_production_ranking)}, - {"enable_ai_city_location_desirability_display" , true, offsetof (struct c3x_config, enable_ai_city_location_desirability_display)}, - {"show_ai_city_location_desirability_if_settler" , false, offsetof (struct c3x_config, show_ai_city_location_desirability_if_settler)}, - {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, - {"zero_corruption_when_off" , true , offsetof (struct c3x_config, zero_corruption_when_off)}, - {"disallow_land_units_from_affecting_water_tiles" , true , offsetof (struct c3x_config, disallow_land_units_from_affecting_water_tiles)}, - {"dont_end_units_turn_after_airdrop" , false, offsetof (struct c3x_config, dont_end_units_turn_after_airdrop)}, - {"allow_airdrop_without_airport" , false, offsetof (struct c3x_config, allow_airdrop_without_airport)}, - {"enable_negative_pop_pollution" , true , offsetof (struct c3x_config, enable_negative_pop_pollution)}, - {"allow_defensive_retreat_on_water" , false, offsetof (struct c3x_config, allow_defensive_retreat_on_water)}, - {"promote_wonder_decorruption_effect" , false, offsetof (struct c3x_config, promote_wonder_decorruption_effect)}, - {"allow_military_leaders_to_hurry_wonders" , false, offsetof (struct c3x_config, allow_military_leaders_to_hurry_wonders)}, - {"aggressively_penalize_bankruptcy" , false, offsetof (struct c3x_config, aggressively_penalize_bankruptcy)}, - {"no_penalty_exception_for_agri_fresh_water_city_tiles" , false, offsetof (struct c3x_config, no_penalty_exception_for_agri_fresh_water_city_tiles)}, - {"use_offensive_artillery_ai" , true , offsetof (struct c3x_config, use_offensive_artillery_ai)}, - {"dont_escort_unflagged_units" , false, offsetof (struct c3x_config, dont_escort_unflagged_units)}, - {"replace_leader_unit_ai" , true , offsetof (struct c3x_config, replace_leader_unit_ai)}, - {"fix_ai_army_composition" , true , offsetof (struct c3x_config, fix_ai_army_composition)}, - {"enable_pop_unit_ai" , true , offsetof (struct c3x_config, enable_pop_unit_ai)}, - {"enable_caravan_unit_ai" , true , offsetof (struct c3x_config, enable_caravan_unit_ai)}, - {"remove_unit_limit" , true , offsetof (struct c3x_config, remove_unit_limit)}, - {"remove_city_improvement_limit" , true , offsetof (struct c3x_config, remove_city_improvement_limit)}, - {"remove_cap_on_turn_limit" , true , offsetof (struct c3x_config, remove_cap_on_turn_limit)}, - {"remove_era_limit" , false, offsetof (struct c3x_config, remove_era_limit)}, - {"patch_submarine_bug" , true , offsetof (struct c3x_config, patch_submarine_bug)}, - {"patch_science_age_bug" , true , offsetof (struct c3x_config, patch_science_age_bug)}, - {"patch_pedia_texture_bug" , true , offsetof (struct c3x_config, patch_pedia_texture_bug)}, - {"patch_blocked_disembark_freeze" , true , offsetof (struct c3x_config, patch_blocked_disembark_freeze)}, - {"patch_houseboat_bug" , true , offsetof (struct c3x_config, patch_houseboat_bug)}, - {"patch_intercept_lost_turn_bug" , true , offsetof (struct c3x_config, patch_intercept_lost_turn_bug)}, - {"patch_phantom_resource_bug" , true , offsetof (struct c3x_config, patch_phantom_resource_bug)}, - {"patch_maintenance_persisting_for_obsolete_buildings" , true , offsetof (struct c3x_config, patch_maintenance_persisting_for_obsolete_buildings)}, - {"patch_barbarian_diagonal_bug" , true , offsetof (struct c3x_config, patch_barbarian_diagonal_bug)}, - {"patch_disease_stopping_tech_flag_bug" , false, offsetof (struct c3x_config, patch_disease_stopping_tech_flag_bug)}, - {"patch_division_by_zero_in_ai_alliance_eval" , true , offsetof (struct c3x_config, patch_division_by_zero_in_ai_alliance_eval)}, - {"patch_empty_army_movement" , true , offsetof (struct c3x_config, patch_empty_army_movement)}, - {"patch_empty_army_combat_crash" , true , offsetof (struct c3x_config, patch_empty_army_combat_crash)}, - {"patch_premature_truncation_of_found_paths" , true , offsetof (struct c3x_config, patch_premature_truncation_of_found_paths)}, - {"patch_zero_production_crash" , true , offsetof (struct c3x_config, patch_zero_production_crash)}, - {"patch_ai_can_form_army_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_form_army_without_special_ability)}, - {"patch_ai_can_sacrifice_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_sacrifice_without_special_ability)}, - {"patch_crash_in_leader_unit_ai" , true , offsetof (struct c3x_config, patch_crash_in_leader_unit_ai)}, - {"patch_failure_to_find_new_city_build" , true , offsetof (struct c3x_config, patch_failure_to_find_new_city_build)}, - {"patch_passengers_out_of_order_on_menu" , true , offsetof (struct c3x_config, patch_passengers_out_of_order_on_menu)}, - {"delete_off_map_ai_units" , true , offsetof (struct c3x_config, delete_off_map_ai_units)}, - {"fix_overlapping_specialist_yield_icons" , true , offsetof (struct c3x_config, fix_overlapping_specialist_yield_icons)}, - {"prevent_autorazing" , false, offsetof (struct c3x_config, prevent_autorazing)}, - {"prevent_razing_by_players" , false, offsetof (struct c3x_config, prevent_razing_by_players)}, - {"suppress_hypertext_links_exceeded_popup" , true , offsetof (struct c3x_config, suppress_hypertext_links_exceeded_popup)}, - {"indicate_non_upgradability_in_pedia" , true , offsetof (struct c3x_config, indicate_non_upgradability_in_pedia)}, - {"show_message_after_dodging_sam" , true , offsetof (struct c3x_config, show_message_after_dodging_sam)}, - {"include_stealth_attack_cancel_option" , false, offsetof (struct c3x_config, include_stealth_attack_cancel_option)}, - {"intercept_recon_missions" , false, offsetof (struct c3x_config, intercept_recon_missions)}, - {"charge_one_move_for_recon_and_interception" , false, offsetof (struct c3x_config, charge_one_move_for_recon_and_interception)}, - {"polish_precision_striking" , true , offsetof (struct c3x_config, polish_precision_striking)}, - {"enable_stealth_attack_via_bombardment" , false, offsetof (struct c3x_config, enable_stealth_attack_via_bombardment)}, - {"immunize_aircraft_against_bombardment" , false, offsetof (struct c3x_config, immunize_aircraft_against_bombardment)}, - {"replay_ai_moves_in_hotseat_games" , false, offsetof (struct c3x_config, replay_ai_moves_in_hotseat_games)}, - {"restore_unit_directions_on_game_load" , true , offsetof (struct c3x_config, restore_unit_directions_on_game_load)}, - {"apply_grid_ini_setting_on_game_load" , true , offsetof (struct c3x_config, apply_grid_ini_setting_on_game_load)}, - {"charm_flag_triggers_ptw_like_targeting" , false, offsetof (struct c3x_config, charm_flag_triggers_ptw_like_targeting)}, - {"city_icons_show_unit_effects_not_trade" , true , offsetof (struct c3x_config, city_icons_show_unit_effects_not_trade)}, - {"ignore_king_ability_for_defense_priority" , false, offsetof (struct c3x_config, ignore_king_ability_for_defense_priority)}, - {"show_untradable_techs_on_trade_screen" , false, offsetof (struct c3x_config, show_untradable_techs_on_trade_screen)}, - {"disallow_useless_bombard_vs_airfields" , true , offsetof (struct c3x_config, disallow_useless_bombard_vs_airfields)}, - {"compact_luxury_display_on_city_screen" , false, offsetof (struct c3x_config, compact_luxury_display_on_city_screen)}, - {"compact_strategic_resource_display_on_city_screen" , false, offsetof (struct c3x_config, compact_strategic_resource_display_on_city_screen)}, - {"warn_when_chosen_building_would_replace_another" , false, offsetof (struct c3x_config, warn_when_chosen_building_would_replace_another)}, - {"do_not_unassign_workers_from_polluted_tiles" , false, offsetof (struct c3x_config, do_not_unassign_workers_from_polluted_tiles)}, - {"do_not_make_capital_cities_appear_larger" , false, offsetof (struct c3x_config, do_not_make_capital_cities_appear_larger)}, - {"show_territory_colors_on_water_tiles_in_minimap" , false, offsetof (struct c3x_config, show_territory_colors_on_water_tiles_in_minimap)}, - {"convert_some_popups_into_online_mp_messages" , false, offsetof (struct c3x_config, convert_some_popups_into_online_mp_messages)}, - {"enable_debug_mode_switch" , false, offsetof (struct c3x_config, enable_debug_mode_switch)}, - {"accentuate_cities_on_minimap" , false, offsetof (struct c3x_config, accentuate_cities_on_minimap)}, - {"allow_multipage_civilopedia_descriptions" , true , offsetof (struct c3x_config, allow_multipage_civilopedia_descriptions)}, - {"reformat_turns_remaining_on_domestic_advisor_screen" , true , offsetof (struct c3x_config, reformat_turns_remaining_on_domestic_advisor_screen)}, - {"enable_trade_net_x" , true , offsetof (struct c3x_config, enable_trade_net_x)}, - {"optimize_improvement_loops" , true , offsetof (struct c3x_config, optimize_improvement_loops)}, - {"measure_turn_times" , false, offsetof (struct c3x_config, measure_turn_times)}, - {"enable_city_capture_by_barbarians" , false, offsetof (struct c3x_config, enable_city_capture_by_barbarians)}, - {"share_visibility_in_hotseat" , false, offsetof (struct c3x_config, share_visibility_in_hotseat)}, - {"share_wonders_in_hotseat" , false, offsetof (struct c3x_config, share_wonders_in_hotseat)}, - {"allow_precision_strikes_against_tile_improvements" , false, offsetof (struct c3x_config, allow_precision_strikes_against_tile_improvements)}, - {"dont_end_units_turn_after_bombarding_barricade" , false, offsetof (struct c3x_config, dont_end_units_turn_after_bombarding_barricade)}, - {"remove_land_artillery_target_restrictions" , false, offsetof (struct c3x_config, remove_land_artillery_target_restrictions)}, - {"allow_bombard_of_other_improvs_on_occupied_airfield" , false, offsetof (struct c3x_config, allow_bombard_of_other_improvs_on_occupied_airfield)}, - {"show_total_city_count" , false, offsetof (struct c3x_config, show_total_city_count)}, - {"strengthen_forbidden_palace_ocn_effect" , false, offsetof (struct c3x_config, strengthen_forbidden_palace_ocn_effect)}, - {"allow_upgrades_in_any_city" , false, offsetof (struct c3x_config, allow_upgrades_in_any_city)}, - {"do_not_generate_volcanos" , false, offsetof (struct c3x_config, do_not_generate_volcanos)}, - {"do_not_pollute_impassable_tiles" , false, offsetof (struct c3x_config, do_not_pollute_impassable_tiles)}, - {"show_hp_of_stealth_attack_options" , false, offsetof (struct c3x_config, show_hp_of_stealth_attack_options)}, - {"exclude_invisible_units_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_invisible_units_from_stealth_attack)}, - {"exclude_passengers_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_passengers_from_stealth_attack)}, - {"convert_to_landmark_after_planting_forest" , false, offsetof (struct c3x_config, convert_to_landmark_after_planting_forest)}, - {"allow_sale_of_aqueducts_and_hospitals" , false, offsetof (struct c3x_config, allow_sale_of_aqueducts_and_hospitals)}, - {"no_cross_shore_detection" , false, offsetof (struct c3x_config, no_cross_shore_detection)}, - {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, - {"limit_unit_loading_to_one_transport_per_turn" , false, offsetof (struct c3x_config, limit_unit_loading_to_one_transport_per_turn)}, - {"prevent_old_units_from_upgrading_past_ability_block" , false, offsetof (struct c3x_config, prevent_old_units_from_upgrading_past_ability_block)}, - {"allow_extraterritorial_colonies" , false, offsetof (struct c3x_config, allow_extraterritorial_colonies)}, - {"draw_forests_over_roads_and_railroads" , false, offsetof (struct c3x_config, draw_forests_over_roads_and_railroads)}, - {"enable_districts" , false, offsetof (struct c3x_config, enable_districts)}, - {"enable_neighborhood_districts" , false, offsetof (struct c3x_config, enable_neighborhood_districts)}, - {"enable_wonder_districts" , false, offsetof (struct c3x_config, enable_wonder_districts)}, - {"enable_natural_wonders" , false, offsetof (struct c3x_config, enable_natural_wonders)}, - {"add_natural_wonders_to_scenarios_if_none" , false, offsetof (struct c3x_config, add_natural_wonders_to_scenarios_if_none)}, - {"enable_named_tiles" , false, offsetof (struct c3x_config, enable_named_tiles)}, - {"enable_distribution_hub_districts" , false, offsetof (struct c3x_config, enable_distribution_hub_districts)}, - {"enable_aerodrome_districts" , false, offsetof (struct c3x_config, enable_aerodrome_districts)}, - {"enable_port_districts" , false, offsetof (struct c3x_config, enable_port_districts)}, - {"enable_bridge_districts" , false, offsetof (struct c3x_config, enable_bridge_districts)}, - {"enable_canal_districts" , false, offsetof (struct c3x_config, enable_canal_districts)}, - {"enable_central_rail_hub_districts" , false, offsetof (struct c3x_config, enable_central_rail_hub_districts)}, - {"enable_energy_grid_districts" , false, offsetof (struct c3x_config, enable_energy_grid_districts)}, - {"enable_great_wall_districts" , false, offsetof (struct c3x_config, enable_great_wall_districts)}, - {"completed_wonder_districts_can_be_destroyed" , false, offsetof (struct c3x_config, completed_wonder_districts_can_be_destroyed)}, - {"destroyed_wonders_can_be_built_again" , false, offsetof (struct c3x_config, destroyed_wonders_can_be_built_again)}, - {"cities_with_mutual_district_receive_buildings" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_buildings)}, - {"cities_with_mutual_district_receive_wonders" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_wonders)}, - {"show_message_when_building_received_by_mutual_district", false, offsetof (struct c3x_config, show_message_when_building_received_by_mutual_district)}, - {"show_message_when_building_lost_to_destroyed_district" , false, offsetof (struct c3x_config, show_message_when_building_lost_to_destroyed_district)}, - {"destroying_neighborhood_reduces_pop" , false, offsetof (struct c3x_config, destroying_neighborhood_reduces_pop)}, - {"air_units_use_aerodrome_districts_not_cities" , false, offsetof (struct c3x_config, air_units_use_aerodrome_districts_not_cities)}, - {"naval_units_use_port_districts_not_cities" , false, offsetof (struct c3x_config, naval_units_use_port_districts_not_cities)}, - {"show_natural_wonder_name_on_map" , false, offsetof (struct c3x_config, show_natural_wonder_name_on_map)}, - {"ai_defends_districts" , false, offsetof (struct c3x_config, ai_defends_districts)}, - {"great_wall_districts_impassible_by_others" , false, offsetof (struct c3x_config, great_wall_districts_impassible_by_others)}, - {"auto_build_great_wall_around_territory" , false, offsetof (struct c3x_config, auto_build_great_wall_around_territory)}, - {"disable_great_wall_city_defense_bonus" , false, offsetof (struct c3x_config, disable_great_wall_city_defense_bonus)}, - {"expand_water_tile_checks_to_city_work_area" , false, offsetof (struct c3x_config, expand_water_tile_checks_to_city_work_area)}, - {"ai_can_replace_existing_districts_with_canals" , false, offsetof (struct c3x_config, ai_can_replace_existing_districts_with_canals)}, - {"ai_builds_bridges" , false, offsetof (struct c3x_config, ai_builds_bridges)}, - {"ai_builds_canals" , false, offsetof (struct c3x_config, ai_builds_canals)}, - {"workers_can_enter_coast" , false, offsetof (struct c3x_config, workers_can_enter_coast)}, - {"enable_city_work_radii_highlights" , false, offsetof (struct c3x_config, enable_city_work_radii_highlights)}, - {"introduce_all_human_players_at_start_of_hotseat_game" , false, offsetof (struct c3x_config, introduce_all_human_players_at_start_of_hotseat_game)}, - {"allow_unload_from_army" , false, offsetof (struct c3x_config, allow_unload_from_army)}, - {"no_land_anti_air_from_inside_naval_transport" , false, offsetof (struct c3x_config, no_land_anti_air_from_inside_naval_transport)}, - {"prevent_enslaving_by_bombardment" , false, offsetof (struct c3x_config, prevent_enslaving_by_bombardment)}, - {"allow_adjacent_resources_of_different_types" , false, offsetof (struct c3x_config, allow_adjacent_resources_of_different_types)}, - {"allow_corruption_in_capital" , false, offsetof (struct c3x_config, allow_corruption_in_capital)}, - {"allow_sale_of_small_wonders" , false, offsetof (struct c3x_config, allow_sale_of_small_wonders)}, - {"enable_unit_counters" , false, offsetof (struct c3x_config, enable_unit_counters)}, - }; - - struct integer_config_option { - char * name; - int base_val; - int offset; - } integer_config_options[] = { - {"limit_railroad_movement" , 0, offsetof (struct c3x_config, limit_railroad_movement)}, - {"minimum_city_separation" , 1, offsetof (struct c3x_config, minimum_city_separation)}, - {"anarchy_length_percent" , 100, offsetof (struct c3x_config, anarchy_length_percent)}, - {"ai_multi_city_start" , 0, offsetof (struct c3x_config, ai_multi_city_start)}, - {"max_tries_to_place_fp_city" , 10000, offsetof (struct c3x_config, max_tries_to_place_fp_city)}, - {"ai_research_multiplier" , 100, offsetof (struct c3x_config, ai_research_multiplier)}, - {"ai_settler_perfume_on_founding_duration" , 0, offsetof (struct c3x_config, ai_settler_perfume_on_founding_duration)}, - {"extra_unit_maintenance_per_shields" , 0, offsetof (struct c3x_config, extra_unit_maintenance_per_shields)}, - {"ai_build_artillery_ratio" , 16, offsetof (struct c3x_config, ai_build_artillery_ratio)}, - {"ai_artillery_value_damage_percent" , 50, offsetof (struct c3x_config, ai_artillery_value_damage_percent)}, - {"ai_build_bomber_ratio" , 70, offsetof (struct c3x_config, ai_build_bomber_ratio)}, - {"max_ai_naval_escorts" , 3, offsetof (struct c3x_config, max_ai_naval_escorts)}, - {"ai_worker_requirement_percent" , 150, offsetof (struct c3x_config, ai_worker_requirement_percent)}, - {"chance_for_nukes_to_destroy_max_one_hp_units" , 100, offsetof (struct c3x_config, chance_for_nukes_to_destroy_max_one_hp_units)}, - {"rebase_range_multiplier" , 6, offsetof (struct c3x_config, rebase_range_multiplier)}, - {"elapsed_minutes_per_day_night_hour_transition" , 3, offsetof (struct c3x_config, elapsed_minutes_per_day_night_hour_transition)}, - {"fixed_hours_per_turn_for_day_night_cycle" , 1, offsetof (struct c3x_config, fixed_hours_per_turn_for_day_night_cycle)}, - {"pinned_hour_for_day_night_cycle" , 0, offsetof (struct c3x_config, pinned_hour_for_day_night_cycle)}, - {"years_to_double_building_culture" , 1000, offsetof (struct c3x_config, years_to_double_building_culture)}, - {"tourism_time_scale_percent" , 100, offsetof (struct c3x_config, tourism_time_scale_percent)}, - {"luxury_randomized_appearance_rate_percent" , 100, offsetof (struct c3x_config, luxury_randomized_appearance_rate_percent)}, - {"tiles_per_non_luxury_resource" , 32, offsetof (struct c3x_config, tiles_per_non_luxury_resource)}, - {"special_capital_decorruption_effect" , 10, offsetof (struct c3x_config, special_capital_decorruption_effect)}, - {"city_limit" , 2048, offsetof (struct c3x_config, city_limit)}, - {"maximum_pop_before_neighborhood_needed" , 8, offsetof (struct c3x_config, maximum_pop_before_neighborhood_needed)}, - {"per_neighborhood_pop_growth_enabled" , 2, offsetof (struct c3x_config, per_neighborhood_pop_growth_enabled)}, - {"minimum_natural_wonder_separation" , 10, offsetof (struct c3x_config, minimum_natural_wonder_separation)}, - {"distribution_hub_food_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_food_yield_divisor)}, - {"distribution_hub_shield_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_shield_yield_divisor)}, - {"ai_ideal_distribution_hub_count_per_100_cities" , 1, offsetof (struct c3x_config, ai_ideal_distribution_hub_count_per_100_cities)}, - {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, - {"max_distribution_hub_count_per_100_cities" , 50, offsetof (struct c3x_config, max_distribution_hub_count_per_100_cities)}, - {"central_rail_hub_distribution_food_bonus_percent" , 25, offsetof (struct c3x_config, central_rail_hub_distribution_food_bonus_percent)}, - {"central_rail_hub_distribution_shield_bonus_percent", 25, offsetof (struct c3x_config, central_rail_hub_distribution_shield_bonus_percent)}, - {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, - {"max_contiguous_bridge_districts" , 3, offsetof (struct c3x_config, max_contiguous_bridge_districts)}, - {"max_contiguous_canal_districts" , 5, offsetof (struct c3x_config, max_contiguous_canal_districts)}, - {"ai_canal_eval_min_bisected_land_tiles" , 10, offsetof (struct c3x_config, ai_canal_eval_min_bisected_land_tiles)}, - {"ai_bridge_canal_eval_block_size" , 20, offsetof (struct c3x_config, ai_bridge_canal_eval_block_size)}, - {"ai_bridge_eval_lake_tile_threshold" , 6, offsetof (struct c3x_config, ai_bridge_eval_lake_tile_threshold)}, - {"ai_city_district_max_build_wait_turns" , 20, offsetof (struct c3x_config, ai_city_district_max_build_wait_turns)}, - {"per_extraterritorial_colony_relation_penalty" , 0, offsetof (struct c3x_config, per_extraterritorial_colony_relation_penalty)}, - }; - - is->kernel32 = (*p_GetModuleHandleA) ("kernel32.dll"); - is->user32 = (*p_GetModuleHandleA) ("user32.dll"); - is->msvcrt = (*p_GetModuleHandleA) ("msvcrt.dll"); - - // Remember the function names here are macros that expand to is->... - VirtualProtect = (void *)(*p_GetProcAddress) (is->kernel32, "VirtualProtect"); - CloseHandle = (void *)(*p_GetProcAddress) (is->kernel32, "CloseHandle"); - CreateFileA = (void *)(*p_GetProcAddress) (is->kernel32, "CreateFileA"); - GetFileSize = (void *)(*p_GetProcAddress) (is->kernel32, "GetFileSize"); - ReadFile = (void *)(*p_GetProcAddress) (is->kernel32, "ReadFile"); - LoadLibraryA = (void *)(*p_GetProcAddress) (is->kernel32, "LoadLibraryA"); - FreeLibrary = (void *)(*p_GetProcAddress) (is->kernel32, "FreeLibrary"); - MultiByteToWideChar = (void *)(*p_GetProcAddress) (is->kernel32, "MultiByteToWideChar"); - WideCharToMultiByte = (void *)(*p_GetProcAddress) (is->kernel32, "WideCharToMultiByte"); - GetLastError = (void *)(*p_GetProcAddress) (is->kernel32, "GetLastError"); - QueryPerformanceCounter = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceCounter"); - QueryPerformanceFrequency = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceFrequency"); - GetLocalTime = (void *)(*p_GetProcAddress) (is->kernel32, "GetLocalTime"); - MessageBoxA = (void *)(*p_GetProcAddress) (is->user32, "MessageBoxA"); - is->msimg32 = LoadLibraryA ("Msimg32.dll"); - TransparentBlt = (void *)(*p_GetProcAddress) (is->msimg32, "TransparentBlt"); - snprintf = (void *)(*p_GetProcAddress) (is->msvcrt, "_snprintf"); - malloc = (void *)(*p_GetProcAddress) (is->msvcrt, "malloc"); - calloc = (void *)(*p_GetProcAddress) (is->msvcrt, "calloc"); - realloc = (void *)(*p_GetProcAddress) (is->msvcrt, "realloc"); - free = (void *)(*p_GetProcAddress) (is->msvcrt, "free"); - strtol = (void *)(*p_GetProcAddress) (is->msvcrt, "strtol"); - strcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strcmp"); - strncmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strncmp"); - _stricmp = (void *)(*p_GetProcAddress) (is->msvcrt, "_stricmp"); - strlen = (void *)(*p_GetProcAddress) (is->msvcrt, "strlen"); - strncpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strncpy"); - strcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strcpy"); - strdup = (void *)(*p_GetProcAddress) (is->msvcrt, "_strdup"); - strstr = (void *)(*p_GetProcAddress) (is->msvcrt, "strstr"); - qsort = (void *)(*p_GetProcAddress) (is->msvcrt, "qsort"); - memcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "memcmp"); - memcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "memcpy"); - tolower = (void *)(*p_GetProcAddress) (is->msvcrt, "tolower"); - toupper = (void *)(*p_GetProcAddress) (is->msvcrt, "toupper"); - is->memmove = (void *)(*p_GetProcAddress) (is->msvcrt, "memmove"); // No #define for this one, instead it has a wrapper func - - // Intercept the game's calls to MessageBoxA. We can't do this through the patcher since that would interfere with the runtime loader. - WITH_MEM_PROTECTION (p_MessageBoxA, 4, PAGE_READWRITE) - *p_MessageBoxA = patch_MessageBoxA; - - // Set file path to mod's script.txt - snprintf (is->mod_script_path, sizeof is->mod_script_path, "%s\\Text\\c3x-script.txt", is->mod_rel_dir); - is->mod_script_path[(sizeof is->mod_script_path) - 1] = '\0'; - - // Fill in base config - struct c3x_config base_config = {0}; - base_config.land_retreat_rules = RR_STANDARD; - base_config.sea_retreat_rules = RR_STANDARD; - base_config.ai_settler_perfume_on_founding = 0; - base_config.work_area_limit = WAL_NONE; - base_config.draw_lines_using_gdi_plus = LDO_WINE; - base_config.double_minimap_size = MDM_HIGH_DEF; - base_config.override_no_ai_patrol = NAPO_NONE; - base_config.override_barbarian_activity_level_for_scenario_maps = BAO_NONE; - base_config.unit_cycle_search_criteria = UCSC_STANDARD; - base_config.city_work_radius = 2; - base_config.day_night_cycle_mode = DNCM_OFF; - base_config.distribution_hub_yield_division_mode = DHYDM_FLAT; - base_config.ai_distribution_hub_build_strategy = ADHBS_BY_CITY_COUNT; - base_config.ai_auto_build_great_wall_strategy = AAGWS_ALL_BORDERS; - base_config.great_wall_auto_build_wonder_improv_id = -1; - for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) - *((char *)&base_config + boolean_config_options[n].offset) = boolean_config_options[n].base_val; - for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) - *(int *)((byte *)&base_config + integer_config_options[n].offset) = integer_config_options[n].base_val; - memcpy (&is->base_config, &base_config, sizeof base_config); - - // Load labels - { - for (int n = 0; n < COUNT_C3X_LABELS; n++) - is->c3x_labels[n] = ""; - - char labels_path[MAX_PATH]; - snprintf (labels_path, sizeof labels_path, "%s\\Text\\c3x-labels.txt", is->mod_rel_dir); - labels_path[(sizeof labels_path) - 1] = '\0'; - char * labels_file_contents = file_to_string (labels_path); - - if (labels_file_contents != NULL) { - char * cursor = labels_file_contents; - int n = 0; - while ((n < COUNT_C3X_LABELS) && (*cursor != '\0')) { - if (*cursor == '\n') - cursor++; - else if ((cursor[0] == '\r') && (cursor[1] == '\n')) - cursor += 2; - else if (*cursor == ';') { - while ((*cursor != '\0') && (*cursor != '\n')) - cursor++; - } else { - char * line_start = cursor; - while ((*cursor != '\0') && (*cursor != '\r') && (*cursor != '\n')) - cursor++; - int line_len = cursor - line_start; - if (NULL != (is->c3x_labels[n] = malloc (line_len + 1))) { - strncpy (is->c3x_labels[n], line_start, line_len); - is->c3x_labels[n][line_len] = '\0'; - } - n++; - } - } - free (labels_file_contents); - - } else { - char err_msg[500]; - snprintf (err_msg, sizeof err_msg, "Couldn't read labels from %s\nPlease make sure the file exists. If you moved the modded EXE you must move the mod folder after it.", labels_path); - err_msg[(sizeof err_msg) - 1] = '\0'; - MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); - } - } - - is->sb_next_up = NULL; - is->trade_net = p_original_trade_net; - is->city_limit = 512; - is->trade_net_addrs_load_state = IS_UNINITED; - is->trade_net_addrs = NULL; - is->tnx_cache = NULL; - is->is_computing_city_connections = false; - is->keep_tnx_cache = false; - is->must_recompute_resources_for_mill_inputs = false; - is->is_placing_scenario_things = false; - is->paused_for_popup = false; - is->time_spent_paused_during_popup = 0; - is->time_spent_computing_city_connections = 0; - is->count_calls_to_recompute_city_connections = 0; - - is->have_job_and_loc_to_skip = 0; - - // Initialize trade screen scroll vars - is->open_diplo_form_straight_to_trade = 0; - is->trade_screen_scroll_to_id = -1; - is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; - is->trade_scroll_button_images = NULL; - is->trade_scroll_button_state = IS_UNINITED; - is->eligible_for_trade_scroll = 0; - - memset (&is->saved_code_areas, 0, sizeof is->saved_code_areas); - - is->unit_menu_duplicates = NULL; - - is->memo = NULL; - is->memo_len = 0; - is->memo_capacity = 0; - - // Fill in array mapping cultural NIs to standard ones. - is->cultural_ni_to_standard = malloc (MAX_CULTURAL_NI + 1); - for (int n = 0; n <= MAX_CULTURAL_NI; n++) { - char const * p = &cultural_ni_to_diffs[n << 1]; - is->cultural_ni_to_standard[n] = diff_to_neighbor_index (p[0], p[1], 1000); - } - - // Fill in array mapping standard NIs to work radii AKA work ring numbers - for (int n = 0; n < ARRAY_LEN (is->ni_to_work_radius); n++) { - int work_radius = -1; - int dx, dy; - neighbor_index_to_diff (n, &dx, &dy); - for (int ring_no = 0; ring_no <= 7; ring_no++) { - for (int k = workable_tile_counts[ring_no-1]; k < workable_tile_counts[ring_no]; k++) { - char const * p = &cultural_ni_to_diffs[k<<1]; - if ((p[0] == dx) && (p[1] == dy)) { - work_radius = ring_no; - break; - } - } - if (work_radius != -1) - break; - } - is->ni_to_work_radius[n] = work_radius; - } - - is->city_loc_display_perspective = -1; - - is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; - - is->extra_available_resources = NULL; - is->extra_available_resources_capacity = 0; - - memset (is->interceptor_reset_lists, 0, sizeof is->interceptor_reset_lists); - - is->ai_prod_valuations = NULL; - is->count_ai_prod_valuations = 0; - is->ai_prod_valuations_capacity = 0; - - is->resource_tiles = NULL; - is->count_resource_tiles = 0; - is->resource_tiles_capacity = 0; - is->got_resource_tile = NULL; - is->saved_tile_count = -1; - is->mill_input_resource_bits = NULL; - - is->drawing_icons_for_improv_id = -1; - - is->resources_sheet = NULL; - - is->modifying_gold_trade = NULL; - - is->bombard_stealth_target = NULL; - is->selecting_stealth_target_for_bombard = 0; - - is->map_message_text_override = NULL; - - is->load_file_path_override = NULL; - - is->replay_for_players = 0; - - is->suppress_intro_after_load_popup = 0; - - is->force_barb_activity_for_cities = 0; - - is->dummy_tile = calloc (1, sizeof *is->dummy_tile); - - is->bombarding_unit = NULL; - - is->unit_bombard_attacking_tile = NULL; - is->attacking_tile_x = is->attacking_tile_y = -1; - - is->temporarily_disallow_lethal_zoc = false; - is->moving_unit_to_adjacent_tile = false; - is->showing_hotseat_replay = false; - is->getting_tile_occupier_for_ai_pathfinding = false; - - is->running_on_wine = false; { - HMODULE ntdll = (*p_GetModuleHandleA) ("ntdll.dll"); - is->running_on_wine = (ntdll != NULL) && ((*p_GetProcAddress) (ntdll, "wine_get_version") != NULL); - } - - is->gdi_plus.init_state = IS_UNINITED; - - is->water_trade_improvs = (struct improv_id_list) {0}; - is->air_trade_improvs = (struct improv_id_list) {0}; - is->combat_defense_improvs = (struct improv_id_list) {0}; - - is->unit_display_override = (struct unit_display_override) {-1, -1, -1}; - - is->dbe = (struct defensive_bombard_event) {0}; - - memset (&is->boolean_config_offsets, 0, sizeof is->boolean_config_offsets); - for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) - stable_insert (&is->boolean_config_offsets, boolean_config_options[n].name, boolean_config_options[n].offset); - memset (&is->integer_config_offsets, 0, sizeof is->integer_config_offsets); - for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) - stable_insert (&is->integer_config_offsets, integer_config_options[n].name, integer_config_options[n].offset); - - memset (&is->unit_type_alt_strategies, 0, sizeof is->unit_type_alt_strategies); - memset (&is->unit_type_duplicates , 0, sizeof is->unit_type_duplicates); - memset (&is->extra_defensive_bombards, 0, sizeof is->extra_defensive_bombards); - memset (&is->airdrops_this_turn , 0, sizeof is->airdrops_this_turn); - memset (&is->unit_transport_ties , 0, sizeof is->unit_transport_ties); - memset (&is->extra_city_improvs , 0, sizeof is->extra_city_improvs); - - is->unit_type_count_init_bits = 0; - for (int n = 0; n < 32; n++) - memset (&is->unit_type_counts[n], 0, sizeof is->unit_type_counts[n]); - - is->penciled_in_upgrades = NULL; - is->penciled_in_upgrade_count = is->penciled_in_upgrade_capacity = 0; - - is->currently_capturing_city = NULL; - is->accessing_save_file = NULL; - - is->drawn_strat_resource_count = 0; - - is->charmed_types_converted_to_ptw_arty = NULL; - is->count_charmed_types_converted_to_ptw_arty = 0; - is->charmed_types_converted_to_ptw_arty_capacity = 0; - - is->checking_visibility_for_unit = NULL; - - is->do_not_bounce_invisible_units = false; - is->always_despawn_passengers = false; - is->do_not_enslave_units = false; - - is->saved_improv_counts = NULL; - is->saved_improv_counts_capacity = 0; - - memset (is->last_main_screen_key_up_events, 0, sizeof is->last_main_screen_key_up_events); - - reset_district_state (true); - - is->natural_wonder_count = 0; - - is->sharing_buildings_by_districts_in_progress = false; - is->can_load_transport = is->can_load_passenger = NULL; - - is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; - is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; - is->last_selected_unit.ptr = NULL; - - is->waiting_units = (struct table) {0}; - is->have_loaded_waiting_units = false; - - is->extra_capture_despawns = NULL; - is->count_extra_capture_despawns = 0; - is->extra_capture_despawns_capacity = 0; - - is->loaded_config_names = NULL; - reset_to_base_config (); - apply_machine_code_edits (&is->current_config, true); -} - -void -init_stackable_command_buttons () -{ - if (is->sc_img_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - for (int n = 0; n < 4; n++) - Sprite_construct (&is->sc_button_image_sets[sc].imgs[n]); - - char temp_path[2*MAX_PATH]; - - is->sb_activated_by_button = 0; - is->sc_img_state = IS_INIT_FAILED; - - char const * filenames[4] = {"StackedNormButtons.pcx", "StackedRolloverButtons.pcx", "StackedHighlightedButtons.pcx", "StackedButtonsAlpha.pcx"}; - for (int n = 0; n < 4; n++) { - get_mod_art_path (filenames[n], temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - for (int k = 0; k < 4; k++) { - Sprite * sprite = &is->sc_button_image_sets[sc].imgs[k]; - sprite->vtable->destruct (sprite, __, 0); - } - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) { - int x = 32 * sc_button_infos[sc].tile_sheet_column, - y = 32 * sc_button_infos[sc].tile_sheet_row; - Sprite_slice_pcx (&is->sc_button_image_sets[sc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); - } - - pcx.vtable->clear_JGL (&pcx); - } - - is->sc_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -void -init_disabled_command_buttons () -{ - if (is->disabled_command_img_state != IS_UNINITED) - return; - - is->disabled_command_img_state = IS_INIT_FAILED; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("DisabledButtons.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load disabled command buttons sprite sheet.\n"); - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - Sprite_construct (&is->disabled_build_city_button_img); - Sprite_slice_pcx (&is->disabled_build_city_button_img, __, &pcx, 32*5, 32*2, 32, 32, 1, 0); - - is->disabled_command_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_stackable_command_buttons () -{ - if (is->sc_img_state == IS_OK) - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - for (int n = 0; n < 4; n++) { - Sprite * sprite = &is->sc_button_image_sets[sc].imgs[n]; - sprite->vtable->destruct (sprite, __, 0); - } - is->sc_img_state = IS_UNINITED; -} - -void -deinit_disabled_command_buttons () -{ - Sprite * sprite = &is->disabled_build_city_button_img; - if (is->disabled_command_img_state == IS_OK) - sprite->vtable->destruct (sprite, __, 0); - memset (sprite, 0, sizeof *sprite); - is->disabled_command_img_state = IS_UNINITED; -} - -void -init_tile_highlights () -{ - if (is->tile_highlight_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - - is->tile_highlight_state = IS_INIT_FAILED; - - snprintf (temp_path, sizeof temp_path, "%s\\Art\\TileHighlights.pcx", is->mod_rel_dir); - temp_path[(sizeof temp_path) - 1] = '\0'; - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); - goto cleanup; - } - - for (int n = 0; n < COUNT_TILE_HIGHLIGHTS; n++) - Sprite_slice_pcx (&is->tile_highlights[n], __, &pcx, 128*n, 0, 128, 64, 1, 0); - - is->tile_highlight_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -init_unit_rcm_icons () -{ - if (is->unit_rcm_icon_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("UnitRCMIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image == NULL) || - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 57) || - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 64)) { - (*p_OutputDebugStringA) ("[C3X] PCX file for unit RCM icons failed to load or is too small.\n"); - goto cleanup; - } - - for (int set = 0; set < COUNT_UNIT_RCM_ICON_SETS; set++) { - Sprite * icons = &is->unit_rcm_icons[set * COUNT_UNIT_RCM_ICONS]; - for (int n = 0; n < COUNT_UNIT_RCM_ICONS; n++) { - Sprite_construct (&icons[n]); - Sprite_slice_pcx (&icons[n], __, &pcx, 1 + 14*set, 1 + 16*n, 14, 15, 1, 0); - } - } - - is->unit_rcm_icon_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_unit_rcm_icons () -{ - if (is->unit_rcm_icon_state == IS_OK) { - int total_icon_count = COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS; - for (int n = 0; n < total_icon_count; n++) { - Sprite * sprite = &is->unit_rcm_icons[n]; - sprite->vtable->destruct (sprite, __, 0); - } - is->unit_rcm_icon_state = IS_UNINITED; - } -} - -void -init_red_food_icon () -{ - if (is->red_food_icon_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("MoreCityIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image != NULL) && - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) >= 32) && - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) == 32)) { - Sprite_construct (&is->red_food_icon); - Sprite_slice_pcx (&is->red_food_icon, __, &pcx, 1, 1, 30, 30, 1, 1); - is->red_food_icon_state = IS_OK; - } else { - (*p_OutputDebugStringA) ("[C3X] PCX file for red food icon failed to load or is not the correct size.\n"); - is->red_food_icon_state = IS_INIT_FAILED; - } - - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_red_food_icon () -{ - if (is->red_food_icon_state == IS_OK) - is->red_food_icon.vtable->destruct (&is->red_food_icon, __, 0); - is->red_food_icon_state = IS_UNINITED; -} - -enum init_state -init_large_minimap_frame () -{ - if (is->large_minimap_frame_img_state != IS_UNINITED) - return is->large_minimap_frame_img_state; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - - get_mod_art_path ("interface\\DoubleSizeBoxLeftColor.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image != NULL) { - Sprite_construct (&is->double_size_box_left_color_pcx); - int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), - height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); - Sprite_slice_pcx (&is->double_size_box_left_color_pcx, __, &pcx, 0, 0, width, height, 1, 1); - } else { - pcx.vtable->destruct (&pcx, __, 0); - return is->large_minimap_frame_img_state = IS_INIT_FAILED; - } - - get_mod_art_path ("interface\\DoubleSizeBoxLeftAlpha.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image != NULL) { - Sprite_construct (&is->double_size_box_left_alpha_pcx); - int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), - height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); - Sprite_slice_pcx (&is->double_size_box_left_alpha_pcx, __, &pcx, 0, 0, width, height, 1, 1); - } else { - is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); - pcx.vtable->destruct (&pcx, __, 0); - return is->large_minimap_frame_img_state = IS_INIT_FAILED;; - } - - pcx.vtable->destruct (&pcx, __, 0); - return is->large_minimap_frame_img_state = IS_OK; -} - -void -deinit_large_minimap_frame () -{ - if (is->large_minimap_frame_img_state == IS_OK) { - is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); - is->double_size_box_left_alpha_pcx.vtable->destruct (&is->double_size_box_left_alpha_pcx, __, 0); - } - is->large_minimap_frame_img_state = IS_UNINITED; -} - -int __cdecl -patch_get_tile_occupier_for_ai_path (int x, int y, int pov_civ_id, bool respect_unit_invisibility) -{ - is->getting_tile_occupier_for_ai_pathfinding = true; - return get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); - is->getting_tile_occupier_for_ai_pathfinding = false; -} - -char __fastcall patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2); - -char __fastcall -patch_Unit_is_tile_occupier_visible (Unit * this, int edx, int civ_id, int param_2) -{ - // Here's the fix for the submarine bug: If we're constructing a path for an AI unit, ignore unit invisibility so the pathfinder will path - // around instead of over other civ's units. We must carve out an exception if the AI is at war with the unit in question. In that case if it - // "accidentally" paths over the unit, it should get stuck in combat like the human player would. - if (is->current_config.patch_submarine_bug && - is->getting_tile_occupier_for_ai_pathfinding && - ! this->vtable->is_enemy_of_civ (this, __, civ_id, 0)) - return 1; - else - return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); -} - -void do_trade_scroll (DiploForm * diplo, int forward); - -void __cdecl -activate_trade_scroll_button (int control_id) -{ - do_trade_scroll (p_diplo_form, control_id == TRADE_SCROLL_BUTTON_ID_RIGHT); -} - -void -init_trade_scroll_buttons (DiploForm * diplo_form) -{ - if (is->trade_scroll_button_state != IS_UNINITED) - return; - - char temp_path[2*MAX_PATH]; - PCX_Image pcx; - PCX_Image_construct (&pcx); - get_mod_art_path ("TradeScrollButtons.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - is->trade_scroll_button_state = IS_INIT_FAILED; - (*p_OutputDebugStringA) ("[C3X] Failed to load TradeScrollButtons.pcx\n"); - goto cleanup; - } - - // Stores normal, rollover, and highlight images, in that order, first for the left button then for the right - is->trade_scroll_button_images = calloc (6, sizeof is->trade_scroll_button_images[0]); - for (int n = 0; n < 6; n++) - Sprite_construct (&is->trade_scroll_button_images[n]); - Sprite * imgs = is->trade_scroll_button_images; - - for (int right = 0; right < 2; right++) - for (int n = 0; n < 3; n++) - Sprite_slice_pcx (&imgs[n + 3*right], __, &pcx, right ? 44 : 0, 1 + 48*n, 43, 47, 1, 1); - - for (int right = 0; right < 2; right++) { - Button * b = new (sizeof *b); - - Button_construct (b); - int id = right ? TRADE_SCROLL_BUTTON_ID_RIGHT : TRADE_SCROLL_BUTTON_ID_LEFT; - Button_initialize (b, __, NULL, id, right ? 622 : 358, 50, 43, 47, (Base_Form *)diplo_form, 0); - for (int n = 0; n < 3; n++) - b->Images[n] = &imgs[n + 3*right]; - - b->activation_handler = &activate_trade_scroll_button; - b->field_630[0] = 0; // TODO: Is this necessary? It's done by the base game code when creating the city screen scroll buttons - - if (! right) - is->trade_scroll_button_left = b; - else - is->trade_scroll_button_right = b; - } - - is->trade_scroll_button_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_trade_scroll_buttons () -{ - if (is->trade_scroll_button_state == IS_OK) { - is->trade_scroll_button_left ->vtable->destruct ((Base_Form *)is->trade_scroll_button_left , __, 0); - is->trade_scroll_button_right->vtable->destruct ((Base_Form *)is->trade_scroll_button_right, __, 0); - is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; - for (int n = 0; n < 6; n++) { - Sprite * sprite = &is->trade_scroll_button_images[n]; - sprite->vtable->destruct (sprite, __, 0); - } - free (is->trade_scroll_button_images); - is->trade_scroll_button_images = NULL; - } - is->trade_scroll_button_state = IS_UNINITED; -} - -void -init_mod_info_button_images () -{ - if (is->mod_info_button_images_state != IS_UNINITED) - return; - - is->mod_info_button_images_state = IS_INIT_FAILED; - - PCX_Image * descbox_pcx = new (sizeof *descbox_pcx); - PCX_Image_construct (descbox_pcx); - char * descbox_path = BIC_get_asset_path (p_bic_data, __, "art\\civilopedia\\descbox.pcx", true); - PCX_Image_read_file (descbox_pcx, __, descbox_path, NULL, 0, 0x100, 1); - if (descbox_pcx->JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load descbox.pcx\n"); - return; - } - - for (int n = 0; n < 3; n++) { - Sprite_construct (&is->mod_info_button_images[n]); - Sprite_slice_pcx_with_color_table (&is->mod_info_button_images[n], __, descbox_pcx, 1 + n * 103, 1, MOD_INFO_BUTTON_WIDTH, - MOD_INFO_BUTTON_HEIGHT, 1, 1); - } - - is->mod_info_button_images_state = IS_OK; -} - -int -count_escorters (Unit * unit) -{ - IDLS * idls = &unit->Body.IDLS; - if (idls->escorters.contents != NULL) { - int tr = 0; - for (int * p_escorter_id = idls->escorters.contents; p_escorter_id < idls->escorters.contents_end; p_escorter_id++) - tr += NULL != get_unit_ptr (*p_escorter_id); - return tr; - } else - return 0; -} - -// If "unit" belongs to the AI, records that all players that have visibility on (x, y) have seen an AI unit -void -record_ai_unit_seen (Unit * unit, int x, int y) -{ - if (0 == (*p_human_player_bits & 1<Body.CivID)) { - Tile * tile = tile_at (x, y); - if ((tile != NULL) && (tile != p_null_tile)) { - Tile_Body * body = &tile->Body; - is->players_saw_ai_unit |= body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility; - } - } -} - -void -recompute_resources_if_necessary () -{ - if (is->must_recompute_resources_for_mill_inputs) - patch_Trade_Net_recompute_resources (is->trade_net, __, false); -} - -void __fastcall -patch_Unit_bombard_tile (Unit * this, int edx, int x, int y) -{ - Tile * target_tile = NULL; - bool had_district_before = false; - int tile_x = x; - int tile_y = y; - struct district_instance * inst; - - if (is->current_config.enable_districts) { - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - target_tile = tile_at (tile_x, tile_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - inst = get_district_instance (target_tile); - had_district_before = (inst != NULL); - } - } - - is->bombarding_unit = this; - record_ai_unit_seen (this, x, y); - Unit_bombard_tile (this, __, x, y); - is->bombard_stealth_target = NULL; - is->bombarding_unit = NULL; - - if (had_district_before && target_tile != NULL && target_tile != p_null_tile && inst->district_id != NATURAL_WONDER_DISTRICT_ID) { - unsigned int overlays = target_tile->vtable->m42_Get_Overlays (target_tile, __, 0); - if ((overlays & TILE_FLAG_MINE) == 0) - handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, false); - } -} - -void __fastcall -patch_Unit_move (Unit * this, int edx, int tile_x, int tile_y) -{ - record_ai_unit_seen (this, tile_x, tile_y); - - Unit_move (this, __, tile_x, tile_y); - - if (this == is->last_selected_unit.ptr) { - is->last_selected_unit.last_x = this->Body.X; - is->last_selected_unit.last_y = this->Body.Y; - } -} - -// Returns true if the unit has attacked & does not have blitz or if it's run out of movement points for the turn -bool -has_exhausted_attack (Unit * unit) -{ - return (unit->Body.Moves >= patch_Unit_get_max_move_points (unit)) || - ((unit->Body.Status & USF_USED_ATTACK) && ! UnitType_has_ability (&p_bic_data->UnitTypes[unit->Body.UnitTypeID], __, UTA_Blitz)); -} - -// Returns whether or not the unit type is a combat type and can do damage on offense (as opposed to only being able to defend). This includes units -// that can only do damage by bombarding and nuclear weapons. -bool -is_offensive_combat_type (UnitType * unit_type) -{ - return (unit_type->Attack > 0) || - ((((unit_type->Special_Actions & UCV_Bombard) | (unit_type->Air_Missions & UCV_Bombing)) & 0x0FFFFFFF) && // (type can perform bombard or bombing AND - ((unit_type->Bombard_Strength > 0) || UnitType_has_ability (unit_type, __, UTA_Nuclear_Weapon))); // (unit has bombard strength OR is a nuclear weapon)) -} - -bool -can_damage_bombarding (UnitType * attacker_type, Unit * defender, Tile * defender_tile) -{ - Unit * container; - if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - (container = get_unit_ptr (defender->Body.Container_Unit)) != NULL && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return false; - - UnitType * defender_type = &p_bic_data->UnitTypes[defender->Body.UnitTypeID]; - if (defender_type->Unit_Class == UTC_Land) { - int has_lethal_land_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Land_Bombardment); - return defender->Body.Damage + (! has_lethal_land_bombard) < Unit_get_max_hp (defender); - } else if (defender_type->Unit_Class == UTC_Sea) { - // Land artillery can't normally damage ships in port - if ((attacker_type->Unit_Class == UTC_Land) && (! is->current_config.remove_land_artillery_target_restrictions) && Tile_has_city (defender_tile)) - return false; - int has_lethal_sea_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Sea_Bombardment); - return defender->Body.Damage + (! has_lethal_sea_bombard) < Unit_get_max_hp (defender); - } else if (defender_type->Unit_Class == UTC_Air) { - if (is->current_config.immunize_aircraft_against_bombardment) - return false; - // Can't damage aircraft in an airfield by bombarding, the attack doesn't even go off - if ((defender_tile->vtable->m42_Get_Overlays (defender_tile, __, 0) & 0x20000000) != 0) - return false; - // Land artillery can't normally damage aircraft but naval artillery and other aircraft can. Lethal bombard doesn't apply; anything - // that can damage can kill. - return (attacker_type->Unit_Class != UTC_Land) || is->current_config.remove_land_artillery_target_restrictions; - } else // UTC_Space? UTC_Alternate_Dimension??? - return false; -} - -char __fastcall -patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2) -{ - // Save the previous value here b/c this function gets called recursively - Unit * prev_checking = is->checking_visibility_for_unit; - is->checking_visibility_for_unit = this; - - char base_vis = Unit_is_visible_to_civ (this, __, civ_id, param_2); - if ((! base_vis) && // if unit is not visible to civ_id AND - is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND - ((1 << civ_id) & *p_human_player_bits) && // civ_id is a human player AND - (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game - - // Check if the unit is visible to any other human player in the game - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && - (n_player != civ_id) && - Unit_is_visible_to_civ (this, __, n_player, param_2)) - return 1; - player_bits >>= 1; - n_player++; - } - } - - is->checking_visibility_for_unit = prev_checking; - return base_vis; -} - -bool -has_any_destructible_improvements (City * city) -{ - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * improv = &p_bic_data->Improvements[n]; - if (((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) && // if improv is not a wonder AND - ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && // it's not the palace AND - (improv->SpaceshipPart < 0) && // it's not a spaceship part AND - patch_City_has_improvement (city, __, n, 0)) // it's present in the city ignoring free improvements - return true; - } - return false; -} - -int const destructible_overlays = - 0x00000003 | // road, railroad - 0x00000004 | // mine - 0x00000008 | // irrigation - 0x00000010 | // fortress - 0x10000000 | // barricade - 0x20000000 | // airfield - 0x40000000 | // radar - 0x80000000; // outpost - -bool -has_any_destructible_overlays (Tile * tile, bool precision_strike) -{ - int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); - if ((overlays & destructible_overlays) == 0) - return false; - else { - if (! precision_strike) - return true; - else { - if (overlays == 0x20000000) { // if tile ONLY has an airfield - int any_aircraft_on_tile = 0; { - FOR_UNITS_ON (uti, tile) - if (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class == UTC_Air) { - any_aircraft_on_tile = 1; - break; - } - } - return ! any_aircraft_on_tile; - } else - return true; - } - } -} - -void __fastcall -patch_Main_Screen_Form_perform_action_on_tile (Main_Screen_Form * this, int edx, enum Unit_Mode_Actions action, int x, int y) -{ - if ((! is->current_config.enable_stack_bombard) || // if stack bombard is disabled OR - (! ((action == UMA_Bombard) || (action == UMA_Air_Bombard))) || // action is not bombard OR - ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) && // (control key is not down AND - ((is->sc_img_state != IS_UNINITED) && (is->sb_activated_by_button == 0))) || // (button flag is valid AND not set)) OR - is_online_game ()) { // is online game - Main_Screen_Form_perform_action_on_tile (this, __, action, x, y); - return; - } - - // Save preferences so we can restore them at the end of the stack bombard operation. We might change them to turn off combat animations. - unsigned init_prefs = *p_preferences; - - clear_memo (); - - wrap_tile_coords (&p_bic_data->Map, &x, &y); - Tile * base_tile = tile_at (this->Current_Unit->Body.X, this->Current_Unit->Body.Y); - Tile * target_tile = tile_at (x, y); - int attacker_type_id = this->Current_Unit->Body.UnitTypeID; - UnitType * attacker_type = &p_bic_data->UnitTypes[attacker_type_id]; - int civ_id = this->Current_Unit->Body.CivID; - - // Count & memoize attackers - int selected_unit_id = this->Current_Unit->Body.ID; - FOR_UNITS_ON (uti, base_tile) - if ((uti.id != selected_unit_id) && - (uti.unit->Body.CivID == civ_id) && - (uti.unit->Body.UnitTypeID == attacker_type_id) && - ((uti.unit->Body.Container_Unit < 0) || (attacker_type->Unit_Class == UTC_Air)) && - (uti.unit->Body.UnitState == 0) && - ! has_exhausted_attack (uti.unit)) - memoize (uti.id); - int count_attackers = is->memo_len; - - // Count & memoize targets (also count air units while we're at it) - int num_air_units_on_target_tile = 0; - FOR_UNITS_ON (uti, target_tile) { - num_air_units_on_target_tile += UTC_Air == p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; - if ((uti.unit->Body.CivID != civ_id) && - (Unit_get_defense_strength (uti.unit) > 0) && - (uti.unit->Body.Container_Unit < 0) && - patch_Unit_is_visible_to_civ (uti.unit, __, civ_id, 0) && - can_damage_bombarding (attacker_type, uti.unit, target_tile)) - memoize (uti.id); - } - int count_targets = is->memo_len - count_attackers; - - // Now our attackers and targets arrays will just be pointers into the memo - int * attackers = &is->memo[0], * targets = &is->memo[count_attackers]; - - int attacking_units = 0, attacking_tile = 0; - City * target_city = NULL; - if (count_targets > 0) - attacking_units = 1; - else if (Tile_has_city (target_tile)) - target_city = get_city_ptr (target_tile->vtable->m45_Get_City_ID (target_tile)); - else { - // Make sure not to set attacking_tile when the tile has an airfield and air units (but no land units) on - // it. In that case we can't damage the airfield and if we try to anyway, the units will waste their moves - // without attacking. - int has_airfield = (target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & 0x20000000) != 0; - attacking_tile = (! has_airfield) || (num_air_units_on_target_tile == 0); - } - - is->sb_next_up = this->Current_Unit; - int i_next_attacker = 0; - int anything_left_to_attack; - int last_attack_didnt_happen; - do { - // If combat animations were enabled when the stack bombard operation started, reset the preference according to the state of the - // shift key (down => skip animations, up => show them). - if (init_prefs & P_ANIMATE_BATTLES) { - if ((*p_GetAsyncKeyState) (VK_SHIFT) >> 8) - *p_preferences &= ~P_ANIMATE_BATTLES; - else - *p_preferences |= P_ANIMATE_BATTLES; - } - - int moves_before_bombard = is->sb_next_up->Body.Moves; - - patch_Unit_bombard_tile (is->sb_next_up, __, x, y); - // At this point sb_next_up may have become NULL if the unit was a bomber that got shot down. - - // Check if the last unit sent into battle actually did anything. If it didn't we should at least skip over - // it to avoid an infinite loop, but actually the only time this should happen is if the player is not at - // war with the targeted civ and chose not to declare when prompted. In this case it's better to just stop - // trying to attack so as to not spam the player with prompts. - last_attack_didnt_happen = (is->sb_next_up == NULL) || (is->sb_next_up->Body.Moves == moves_before_bombard); - - if ((is->sb_next_up == NULL) || has_exhausted_attack (is->sb_next_up)) { - is->sb_next_up = NULL; - while ((i_next_attacker < count_attackers) && (is->sb_next_up == NULL)) - is->sb_next_up = get_unit_ptr (attackers[i_next_attacker++]); - } - - if (attacking_units) { - anything_left_to_attack = 0; - for (int n = 0; n < count_targets; n++) { - Unit * unit = get_unit_ptr (targets[n]); - - // Make sure this unit is still a valid target. Keep in mind it's possible for new units to be created during the - // stack bombard operation if the attackers have lethal bombard and the enslave ability. - if ((unit != NULL) && (unit->Body.X == x) && (unit->Body.Y == y) && (unit->Body.CivID != civ_id)) { - - if (can_damage_bombarding (attacker_type, unit, target_tile)) { - anything_left_to_attack = 1; - break; - } - } - } - } else if (target_city != NULL) - anything_left_to_attack = (target_city->Body.Population.Size > 1) || has_any_destructible_improvements (target_city); - else if (attacking_tile) - anything_left_to_attack = has_any_destructible_overlays (target_tile, false); - else - anything_left_to_attack = 0; - } while ((is->sb_next_up != NULL) && anything_left_to_attack && (! last_attack_didnt_happen)); - - is->sb_activated_by_button = 0; - is->sb_next_up = NULL; - *p_preferences = init_prefs; - this->GUI.Base.vtable->m73_call_m22_Draw ((Base_Form *)&this->GUI); -} - -void -set_up_stack_bombard_buttons (Main_GUI * this) -{ - if (is_online_game () || (! is->current_config.enable_stack_bombard)) - return; - - init_stackable_command_buttons (); - if (is->sc_img_state != IS_OK) - return; - - // Find button that the original method set to (air) bombard, then find the next unused button after that. - Command_Button * bombard_button = NULL, * free_button = NULL; { - int i_bombard_button; - for (int n = 0; n < 42; n++) - if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && - (this->Unit_Command_Buttons[n].Command == UCV_Bombard || this->Unit_Command_Buttons[n].Command == UCV_Bombing)) { - bombard_button = &this->Unit_Command_Buttons[n]; - i_bombard_button = n; - break; - } - if (bombard_button != NULL) - for (int n = i_bombard_button + 1; n < 42; n++) - if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { - free_button = &this->Unit_Command_Buttons[n]; - break; - } - } - - if ((bombard_button == NULL) || (free_button == NULL)) - return; - - // Set up free button for stack bombard - free_button->Command = bombard_button->Command; - free_button->field_6D8 = bombard_button->field_6D8; - struct sc_button_image_set * img_set = - (bombard_button->Command == UCV_Bombing) ? &is->sc_button_image_sets[SC_BOMB] : &is->sc_button_image_sets[SC_BOMBARD]; - for (int n = 0; n < 4; n++) - free_button->Button.Images[n] = &img_set->imgs[n]; - free_button->Button.field_664 = bombard_button->Button.field_664; - // FUN_005559E0 is also called in the original code. I don't know what it actually does but I'm pretty sure it doesn't - // matter for our purposes. - Button_set_tooltip (&free_button->Button, __, is->c3x_labels[CL_SB_TOOLTIP]); - free_button->Button.field_5FC[13] = bombard_button->Button.field_5FC[13]; - free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); -} - -void -init_district_command_buttons () -{ - if (is_online_game () || is->dc_btn_img_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) - for (int n = 0; n < 4; n++) - Sprite_construct (&is->district_btn_img_sets[dc].imgs[n]); - - char temp_path[2*MAX_PATH]; - - is->dc_btn_img_state = IS_INIT_FAILED; - - // For each button sprite type (normal, rollover, highlighted, alpha) - char const * filenames[4] = { - "Districts\\WorkerDistrictButtonsNorm.pcx", "Districts\\WorkerDistrictButtonsRollover.pcx", - "Districts\\WorkerDistrictButtonsHighlighted.pcx", "Districts\\WorkerDistrictButtonsAlpha.pcx" - }; - for (int n = 0; n < 4; n++) { - get_mod_art_path (filenames[n], temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load work district command buttons sprite sheet.\n"); - for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) - for (int k = 0; k < 4; k++) { - Sprite * sprite = &is->district_btn_img_sets[dc].imgs[k]; - sprite->vtable->destruct (sprite, __, 0); - } - pcx.vtable->destruct (&pcx, __, 0); - - char ss[200]; - snprintf (ss, sizeof ss, "[C3X] Failed to load district command button images from %s", temp_path); - pop_up_in_game_error (ss); - - return; - } - - // For each district type - for (int dc = 0; dc < is->district_count; dc++) { - int x = 32 * is->district_configs[dc].btn_tile_sheet_column, - y = 32 * is->district_configs[dc].btn_tile_sheet_row; - Sprite_slice_pcx (&is->district_btn_img_sets[dc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); - } - - pcx.vtable->clear_JGL (&pcx); - } - - is->dc_btn_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -int -parse_turns_from_tooltip (char const * tooltip) -{ - if ((tooltip == NULL) || (*tooltip == '\0')) - return -1; - - char const * last_paren = NULL; - for (char const * cursor = tooltip; *cursor != '\0'; cursor++) - if (*cursor == '(') - last_paren = cursor; - if (last_paren == NULL) - return -1; - - char const * digit_ptr = last_paren + 1; - while (*digit_ptr == ' ') - digit_ptr++; - - int turns = 0; - bool have_digit = false; - while ((*digit_ptr >= '0') && (*digit_ptr <= '9')) { - have_digit = true; - turns = (turns * 10) + (*digit_ptr - '0'); - digit_ptr++; - } - return have_digit ? turns : -1; -} - -void -compute_highlighted_worker_tiles_for_districts () -{ - if (is_online_game () - || ! is->current_config.enable_districts - || ! is->current_config.enable_city_work_radii_highlights) - return; - - Unit * selected_unit = p_main_screen_form->Current_Unit; - if (selected_unit == NULL) - return; - - int unit_type_id = selected_unit->Body.UnitTypeID; - if (p_bic_data->UnitTypes[unit_type_id].Worker_Actions == 0) - return; - - if (is->tile_highlight_state == IS_UNINITED) - init_tile_highlights (); - if (is->tile_highlight_state != IS_OK) - return; - - int worker_civ_id = selected_unit->Body.CivID; - if ((p_cities == NULL) || (p_cities->Cities == NULL)) - return; - - // Loop over all cities owned by this civ and tally their workable tiles - FOR_CITIES_OF (coi, worker_civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - - // Highlight city center so players can easily see which cities contribute - Tile * city_center_tile = tile_at (city->Body.X, city->Body.Y); - if ((city_center_tile != NULL) && (city_center_tile != p_null_tile)) { - int stored_ptr; - if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, &stored_ptr)) { - struct highlighted_city_radius_tile_info * info = malloc (sizeof (struct highlighted_city_radius_tile_info)); - info->highlight_level = 0; - itable_insert (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, (int)info); - } - } - - // Add all workable tiles around the city (excluding city center) - for (int n = 1; n < is->workable_tile_count; n++) { - int dx, dy; - patch_ni_to_diff_for_work_area (n, &dx, &dy); - int tile_x = city->Body.X + dx; - int tile_y = city->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - - Tile * workable_tile = tile_at (tile_x, tile_y); - if ((workable_tile == NULL) || (workable_tile == p_null_tile)) continue; - if (workable_tile->vtable->m38_Get_Territory_OwnerID (workable_tile) != worker_civ_id) continue; - - // Upsert into highlighted_city_radius_tile_pointers - int stored_ptr; - struct highlighted_city_radius_tile_info * info; - if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, &stored_ptr)) { - info = malloc (sizeof (struct highlighted_city_radius_tile_info)); - info->highlight_level = 0; - itable_insert (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, (int)info); - } else { - info = (struct highlighted_city_radius_tile_info *)stored_ptr; - info->highlight_level += 3; - } - } - } -} - -void -set_up_district_buttons (Main_GUI * this) -{ - if (is_online_game () || ! is->current_config.enable_districts) return; - if (is->dc_btn_img_state == IS_UNINITED) init_district_command_buttons (); - if (is->dc_btn_img_state != IS_OK) return; - - Unit * selected_unit = p_main_screen_form->Current_Unit; - if (selected_unit == NULL || ! is_worker(selected_unit)) return; - - Tile * tile = tile_at (selected_unit->Body.X, selected_unit->Body.Y); - if ((tile == NULL) || (tile == p_null_tile) || (tile->CityID >= 0)) return; - - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - if (tile->vtable->m21_Check_Crates (tile, __, 0)) return; - if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return; - - Command_Button * fortify_button = NULL; - int i_starting_button; - int mine_turns = -1; - for (int n = 0; n < 42; n++) { - if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && - (this->Unit_Command_Buttons[n].Command == UCV_Fortify)) { - fortify_button = &this->Unit_Command_Buttons[n]; - i_starting_button = n; - } - if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { - mine_turns = parse_turns_from_tooltip (this->Unit_Command_Buttons[n].Button.ToolTip); - } - if (fortify_button != NULL && mine_turns >= 0) - break; - } - - if (fortify_button == NULL) - return; - - i_starting_button = -1; - - // Check if there's already a district on this tile. If so, and the unit can build mines, - // ensure the mine button is enabled so the worker can continue construction. - int existing_district_id = -1; - struct district_instance * existing_inst = get_district_instance (tile); - if (existing_inst != NULL) { - existing_district_id = existing_inst->district_id; - if (is->current_config.enable_natural_wonders && existing_inst->district_id == NATURAL_WONDER_DISTRICT_ID) { - return; - } - if (patch_Unit_can_perform_command(selected_unit, __, UCV_Build_Mine)) { - for (int n = 0; n < 42; n++) { - if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { - Command_Button * mine_button = &this->Unit_Command_Buttons[n]; - if (base_type == SQ_Coast) { - mine_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&mine_button->Button); - break; - } - if ((mine_button->Button.Base_Data.Status2 & 1) == 0) { - mine_button->Button.field_5FC[13] = 0; - mine_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&mine_button->Button, __, 0); - } - break; - } - } - } - } - - bool district_completed = district_is_complete (tile, existing_district_id); - - // First pass: collect which district types should be shown - int active_districts[COUNT_DISTRICT_TYPES]; - int active_count = 0; - - for (int dc = 0; dc < is->district_count; dc++) { - - if (is->district_configs[dc].command == -1) - continue; - - bool already_building = false; - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if (unit != NULL && is_worker(unit) && existing_inst != NULL && existing_inst->district_id == dc) { - // If there's a worker on the tile and it's building this district, - // show the button so more workers can contribute. This works around an - // issue where a specific district requiring irrigation no longer - // is buildable by other workers because initial construction removes the - // required irrigation overlay upon construction start - already_building = true; - break; - } - } - - if (existing_district_id == dc && district_completed) continue; - if ((existing_district_id >= 0) && (existing_district_id != dc) && (! district_completed)) continue; - - if (! can_build_district_on_tile (tile, dc, selected_unit->Body.CivID) && ! already_building) - continue; - - // This district should be shown - active_districts[active_count++] = dc; - } - - - if (active_count == 0) - return; - - // Calculate centered starting position - // For odd counts, center perfectly; for even counts, favor left of center - int center_pos = 6; - i_starting_button = center_pos - (active_count / 2); - if (i_starting_button < 0) - i_starting_button = 0; - - // Second pass: render the buttons - for (int idx = 0; idx < active_count; idx++) { - int dc = active_districts[idx]; - - Command_Button * free_button = NULL; - for (int n = i_starting_button; n < 42; n++) { - if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { - free_button = &this->Unit_Command_Buttons[n]; - i_starting_button = n + 1; - break; - } - } - - if (free_button == NULL) - return; - - // Set up free button for creating district - free_button->Command = is->district_configs[dc].command; - - // Replace the button's image with the district image. Disabling & re-enabling and - // clearing field_5FC[13] are all necessary to trigger a redraw. - free_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&free_button->Button); - free_button->field_6D8 = fortify_button->field_6D8; - for (int k = 0; k < 4; k++) - free_button->Button.Images[k] = &is->district_btn_img_sets[dc].imgs[k]; - free_button->Button.field_664 = fortify_button->Button.field_664; - if (mine_turns >= 0) { - char tooltip[256]; - char const * turn_word = (mine_turns == 1) ? "turn" : "turns"; - snprintf (tooltip, sizeof tooltip, "%s (%d %s)", is->district_configs[dc].tooltip, mine_turns, turn_word); - tooltip[(sizeof tooltip) - 1] = '\0'; - Button_set_tooltip (&free_button->Button, __, tooltip); - } else - Button_set_tooltip (&free_button->Button, __, (char *)is->district_configs[dc].tooltip); - free_button->Button.field_5FC[13] = 0; - free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); - } -} - -void -set_up_stack_worker_buttons (Main_GUI * this) -{ - if ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // (control key is not down OR - (! is->current_config.enable_stack_unit_commands) || // stack worker commands not enabled OR - is_online_game ()) // is online game - return; - - init_stackable_command_buttons (); - if (is->sc_img_state != IS_OK) - return; - - // For each unit command button - for (int n = 0; n < 42; n++) { - Command_Button * cb = &this->Unit_Command_Buttons[n]; - - // If it's enabled and not a bombard button (those are handled in the function above) - if (((cb->Button.Base_Data.Status2 & 1) != 0) && - (cb->Command != UCV_Bombard) && (cb->Command != UCV_Bombing)) { - - // Find the stackable worker command that this button controls, if there is one, and check that - // the button isn't already showing the stack image for that command. Note: this check is important - // b/c this function gets called repeatedly while the CTRL key is held down. - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - if ((cb->Command == sc_button_infos[sc].command) && - (cb->Button.Images[0] != &is->sc_button_image_sets[sc].imgs[0])) { - - // Replace the button's image with the stack image. Disabling & re-enabling and - // clearing field_5FC[13] are all necessary to trigger a redraw. - cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); - for (int k = 0; k < 4; k++) - cb->Button.Images[k] = &is->sc_button_image_sets[sc].imgs[k]; - cb->Button.field_5FC[13] = 0; - cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); - - break; - } - } - } -} - -CityLocValidity __fastcall patch_Map_check_city_location (Map * this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile); - -void __fastcall -patch_Main_GUI_set_up_unit_command_buttons (Main_GUI * this) -{ - // Recompute resources now if needed because of a trade deal involving mill inputs. In rare cases the change in deals might affect a mill that - // produces a resource that's used for a worker job. - recompute_resources_if_necessary (); - - Main_GUI_set_up_unit_command_buttons (this); - set_up_stack_bombard_buttons (this); - set_up_stack_worker_buttons (this); - - if (is->current_config.enable_districts) { - set_up_district_buttons (this); - } - - // If the minimum city separation is increased, then gray out the found city button if we're too close to another city. - if ((is->current_config.minimum_city_separation > 1) && (p_main_screen_form->Current_Unit != NULL) && (is->disabled_command_img_state == IS_OK)) { - Unit_Body * selected_unit = &p_main_screen_form->Current_Unit->Body; - - // For each unit command button - for (int n = 0; n < 42; n++) { - Command_Button * cb = &this->Unit_Command_Buttons[n]; - - // If it's enabled, set to city founding, and the current city location is too close to another city - if (((cb->Button.Base_Data.Status2 & 1) != 0) && - (cb->Command == UCV_Build_City) && - (patch_Map_check_city_location (&p_bic_data->Map, __, selected_unit->X, selected_unit->Y, selected_unit->CivID, false) == CLV_CITY_TOO_CLOSE)) { - - // Replace the button's image with the disabled image, as in set_up_stack_worker_buttons. - cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); - for (int k = 0; k < 3; k++) - cb->Button.Images[k] = &is->disabled_build_city_button_img; - cb->Button.field_5FC[13] = 0; - - char tooltip[200]; { - memset (tooltip, 0, sizeof tooltip); - char * label = is->c3x_labels[CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP], - * to_replace = "$NUM0", - * replace_location = strstr (label, to_replace); - if (replace_location != NULL) - snprintf (tooltip, sizeof tooltip, "%.*s%d%s", replace_location - label, label, is->current_config.minimum_city_separation, replace_location + strlen (to_replace)); - else - snprintf (tooltip, sizeof tooltip, "%s", label); - tooltip[(sizeof tooltip) - 1] = '\0'; - } - Button_set_tooltip (&cb->Button, __, tooltip); - - cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); - - } - } - } -} - -void -clear_highlighted_worker_tiles_and_redraw () -{ - clear_highlighted_worker_tiles_for_districts (); - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -void -check_happiness_at_end_of_turn () -{ - int num_unhappy_cities = 0; - City * first_unhappy_city = NULL; - FOR_CITIES_OF (coi, p_main_screen_form->Player_CivID) { - City_recompute_happiness (coi.city); - int num_happy = 0, num_unhappy = 0; - FOR_CITIZENS_IN (ci, coi.city) { - num_happy += ci.ctzn->Body.Mood == CMT_Happy; - num_unhappy += ci.ctzn->Body.Mood == CMT_Unhappy; - } - if (num_unhappy > num_happy) { - num_unhappy_cities++; - if (first_unhappy_city == NULL) - first_unhappy_city = coi.city; - } - } - - if (first_unhappy_city != NULL) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, first_unhappy_city->Body.CityName, -1, -1); - if (num_unhappy_cities > 1) - set_popup_int_param (1, num_unhappy_cities - 1); - char * key = (num_unhappy_cities > 1) ? "C3X_DISORDER_WARNING_MULTIPLE" : "C3X_DISORDER_WARNING_ONE"; - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, key, -1, 0, 0, 0); - int response = patch_show_popup (popup, __, 0, 0); - - if (response == 2) { // zoom to city - p_main_screen_form->turn_end_flag = 1; - City_zoom_to (first_unhappy_city, __, 0); - } else if (response == 1) // just cancel turn end - p_main_screen_form->turn_end_flag = 1; - // else do nothing, let turn end - - } -} - -void -do_trade_scroll (DiploForm * diplo, int forward) -{ - int increment = forward ? 1 : -1; - int id = -1; - for (int n = (diplo->other_party_civ_id + increment) & 31; n != diplo->other_party_civ_id; n = (n + increment) & 31) - if ((n != 0) && // if N is not barbs AND - (n != p_main_screen_form->Player_CivID) && // N is not the player's AND - (*p_player_bits & (1U << n)) && // N belongs to an active player AND - (leaders[p_main_screen_form->Player_CivID].Contacts[n] & 1) && // N has contact with the player AND - Leader_ai_would_meet_with (&leaders[n], __, p_main_screen_form->Player_CivID)) { // AI is willing to meet - id = n; - break; - } - - if (id >= 0) { - is->trade_screen_scroll_to_id = id; - DiploForm_close (diplo); - // Note extra code needs to get run here if the other player is not an AI - } -} - -void __fastcall -patch_DiploForm_m82_handle_key_event (DiploForm * this, int edx, int virtual_key_code, int is_down) -{ - if (is->eligible_for_trade_scroll && - (this->mode == 2) && - ((virtual_key_code == VK_LEFT) || (virtual_key_code == VK_RIGHT)) && - (! is_down)) - do_trade_scroll (this, virtual_key_code == VK_RIGHT); - else - DiploForm_m82_handle_key_event (this, __, virtual_key_code, is_down); -} - -int __fastcall -patch_DiploForm_m68_Show_Dialog (DiploForm * this, int edx, int param_1, void * param_2, void * param_3) -{ - if (is->open_diplo_form_straight_to_trade) { - is->open_diplo_form_straight_to_trade = 0; - - // Done by the base game but not necessary as far as I can tell - // void (__cdecl * FUN_00537700) (int) = 0x537700; - // FUN_00537700 (0x15); - // this->field_E9C[0] = this->field_E9C[0] + 1; - - // Set diplo screen mode to two-way trade negotation - this->mode = 2; - - // Set AI's diplo message to something like "what did you have in mind" - int iVar35 = DiploForm_set_their_message (this, __, DM_AI_PROPOSAL_RESPONSE, 0, 0x1A8); - this->field_1390[0] = DM_AI_PROPOSAL_RESPONSE; - this->field_1390[1] = 0; - this->field_1390[2] = iVar35; - - // Reset player message options. This will replace the propose deal, declare war, and leave options with the usual "nevermind" option - // that appears for negotiations. - DiploForm_reset_our_message_choices (this); - - // Done by the base game but not necessary as far as I can tell - // void (__fastcall * FUN_004C89A0) (void *) = 0x4C89A0; - // FUN_004C89A0 (&this->field_1BF4[0]); - - } - - return DiploForm_m68_Show_Dialog (this, __, param_1, param_2, param_3); -} - -void __fastcall -patch_DiploForm_do_diplomacy (DiploForm * this, int edx, int diplo_message, int param_2, int civ_id, int do_not_request_audience, int war_negotiation, int disallow_proposal, TradeOfferList * our_offers, TradeOfferList * their_offers) -{ - is->open_diplo_form_straight_to_trade = 0; - is->trade_screen_scroll_to_id = -1; - - // Trade screen scroll is disabled in online games b/c there's extra synchronization we'd need to do to open or close the diplo screen with - // a human player. - is->eligible_for_trade_scroll = is->current_config.enable_trade_screen_scroll && (! is_online_game ()); - - if (is->eligible_for_trade_scroll && (is->trade_scroll_button_state == IS_UNINITED)) - init_trade_scroll_buttons (this); - - WITH_PAUSE_FOR_POPUP { - DiploForm_do_diplomacy (this, __, diplo_message, param_2, civ_id, do_not_request_audience, war_negotiation, disallow_proposal, our_offers, their_offers); - - while (is->trade_screen_scroll_to_id >= 0) { - int scroll_to_id = is->trade_screen_scroll_to_id; - is->trade_screen_scroll_to_id = -1; - is->open_diplo_form_straight_to_trade = 1; - DiploForm_do_diplomacy (this, __, DM_AI_COUNTER, 0, scroll_to_id, 1, 0, 0, NULL, NULL); - } - } - - is->open_diplo_form_straight_to_trade = 0; - is->eligible_for_trade_scroll = 0; -} - -void __fastcall -patch_DiploForm_m22_Draw (DiploForm * this) -{ - if (is->trade_scroll_button_state == IS_OK) { - Button * left = is->trade_scroll_button_left, - * right = is->trade_scroll_button_right; - if (is->eligible_for_trade_scroll && (this->mode == 2)) { - left ->vtable->m01_Show_Enabled ((Base_Form *)left , __, 0); - right->vtable->m01_Show_Enabled ((Base_Form *)right, __, 0); - left ->vtable->m73_call_m22_Draw ((Base_Form *)left); - right->vtable->m73_call_m22_Draw ((Base_Form *)right); - } else { - left ->vtable->m02_Show_Disabled ((Base_Form *)left); - right->vtable->m02_Show_Disabled ((Base_Form *)right); - } - } - - DiploForm_m22_Draw (this); -} - -void -intercept_end_of_turn () -{ - if (is->current_config.enable_disorder_warning) { - check_happiness_at_end_of_turn (); - if (p_main_screen_form->turn_end_flag == 1) // Check if player cancelled turn ending in the disorder warning popup - return; - } - - // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - - if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { - is->city_loc_display_perspective = -1; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw - } - - // Clear things that don't apply across turns - is->have_job_and_loc_to_skip = 0; -} - -bool -is_worker_or_settler_command (int unit_command_value) -{ - return (unit_command_value & 0x20000000) || - ((unit_command_value >= UCV_Build_Remote_Colony) && (unit_command_value <= UCV_Auto_Save_Tiles)); -} - -bool -command_would_replace_district (int unit_command_value) -{ - // Note: Roads & railroads, etc. can coexist with the district - return (unit_command_value == UCV_Build_Mine) || - (unit_command_value == UCV_Irrigate) || - (unit_command_value == UCV_Plant_Forest) || - (unit_command_value == UCV_Build_Outpost) || - (unit_command_value == UCV_Build_Fortress) || - (unit_command_value == UCV_Build_Barricade) || - (unit_command_value == UCV_Build_Airfield) || - (unit_command_value == UCV_Build_Radar_Tower) || - (unit_command_value == UCV_Build_Colony); -} - -bool -handle_worker_command_that_may_replace_district (Unit * unit, int unit_command_value, bool * removed_existing) -{ - if (removed_existing != NULL) - *removed_existing = false; - - if ((! is->current_config.enable_districts) || (unit == NULL)) return true; - if (! is_worker_or_settler_command (unit_command_value)) return true; - if (! command_would_replace_district (unit_command_value)) return true; - if (! patch_Unit_can_perform_command (unit, __, unit_command_value)) return true; - - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - if ((tile == NULL) || (tile == p_null_tile)) - return true; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (! district_is_complete (tile, inst->district_id))) - return true; - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - return false; - - int district_id = inst->district_id; - int civ_id = unit->Body.CivID; - bool redundant_district = district_instance_is_redundant (inst, tile); - bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (district_id, civ_id, tile_x, tile_y); - if (redundant_district) - would_lose_buildings = false; - - bool remove_existing = redundant_district; - if (inst != NULL && district_id >= 0 && district_id < is->district_count) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char *)is->district_configs[district_id].display_name, -1, -1); - set_popup_str_param (1, (char *)is->district_configs[district_id].display_name, -1, -1); - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - would_lose_buildings - ? "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT" - : "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT_SAFE", - -1, 0, 0, 0); - int sel = patch_show_popup (popup, __, 0, 0); - if (sel != 0) - return false; - remove_existing = true; - } - - if (remove_existing) { - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - handle_district_removed (tile, district_id, tile_x, tile_y, false); - if (removed_existing != NULL) - *removed_existing = true; - } - - return true; -} - -bool __fastcall - patch_Unit_can_upgrade (Unit * this) -{ - bool base = Unit_can_upgrade (this); - int available; - City * city = city_at (this->Body.X, this->Body.Y); - if (base && - (city != NULL) && - get_available_unit_count (&leaders[this->Body.CivID], City_get_upgraded_type_id (city, __, this->Body.UnitTypeID), &available) && - (available <= 0)) - return false; - else - return base; -} - -bool -is_district_command (int unit_command_value) -{ - int district_id = -1; - if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) - return false; - - return district_id != NATURAL_WONDER_DISTRICT_ID; -} - -int __fastcall -patch_Map_check_colony_location (Map * this, int edx, int tile_x, int tile_y, int civ_id) -{ - int base = Map_check_colony_location (this, __, tile_x, tile_y, civ_id); - Tile * tile = tile_at (tile_x, tile_y); - - if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.allow_extraterritorial_colonies) - return base; - - if (tile->vtable->m35_Check_Is_Water (tile)) return base; - if (Tile_has_city (tile) || Tile_has_colony (tile)) return base; - - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_id < 0) || (owner_id == civ_id)) return base; - - int resource_type = Tile_get_resource_visible_to (tile, __, civ_id); - if ((resource_type < 0) || (resource_type >= p_bic_data->ResourceTypeCount)) return base; - - int req_tech = p_bic_data->ResourceTypes[resource_type].RequireID; - if ((req_tech >= 0) && (! Leader_has_tech (&leaders[civ_id], __, req_tech))) return base; - - int res_class = p_bic_data->ResourceTypes[resource_type].Class; - if ((res_class != RC_Strategic) && (res_class != RC_Luxury)) return base; - if (tile->vtable->m26_Check_Tile_Building (tile)) - return 6; - - return 0; -} - -bool __fastcall -patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value) -{ - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - // No worker or settler commands allowed on natural wonders - if ((tile != NULL) && (tile != p_null_tile) && is->current_config.enable_natural_wonders) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && - (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) { - if (is_worker_or_settler_command (unit_command_value) || is_district_command (unit_command_value)) - return false; - } - } - - if (is_district_command (unit_command_value)) { - int district_id; - if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) - return false; - - return is_worker (this) && can_build_district_on_tile (tile, district_id, this->Body.CivID); - } - // Extra check for colony founding if extraterritorial colonies allowed - else if (unit_command_value == UCV_Build_Colony || unit_command_value == UCV_Build_Remote_Colony) { - if (is->current_config.allow_extraterritorial_colonies && is_worker (this)) { - return patch_Map_check_colony_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID) == 0; - } - } - // Extra check for road building if bridge districts allowed - else if (unit_command_value == UCV_Build_Road) { - struct district_instance * inst = get_district_instance (tile); - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - if (!has_road && (inst != NULL) && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) - return true; - } - // Extra check for railroad building if bridge districts allowed - else if (unit_command_value == UCV_Build_Railroad) { - struct district_instance * inst = get_district_instance (tile); - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; - if ((inst != NULL) && is_worker (this) && has_road && - ! has_rail && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) { - int req_tech = p_bic_data->WorkerJobs[WJ_Build_Railroad].RequireID; - if ((req_tech < 0) || - ((req_tech != p_bic_data->AdvanceCount) && - Leader_has_tech (&leaders[this->Body.CivID], __, req_tech))) { - if (Leader_has_resources_for_job_at (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y)) - return true; - } - } - } - else if (unit_command_value == UCV_Build_Mine) { - bool has_district = (tile != NULL) && (tile != p_null_tile) && (get_district_instance (tile) != NULL); - - if (has_district) { - return Tile_get_mining_bonus (tile) > 0; - } - } else if (unit_command_value == UCV_Pillage) { - return patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y); - } - } - if (is->current_config.disable_worker_automation && - (this->Body.CivID == p_main_screen_form->Player_CivID) && - (unit_command_value == UCV_Automate)) - return false; - else if (is->current_config.disallow_land_units_from_affecting_water_tiles && - is_worker_or_settler_command (unit_command_value)) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - enum UnitTypeClasses class = p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class; - return ((class != UTC_Land) || (! tile->vtable->m35_Check_Is_Water (tile))) && - Unit_can_perform_command (this, __, unit_command_value); - } - - return Unit_can_perform_command (this, __, unit_command_value); -} - -void __fastcall -patch_Unit_join_city (Unit * this, int edx, City * city) -{ - if (is->current_config.enable_districts && is_worker (this)) { - int civ_id = this->Body.CivID; - bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; - if (! is_human) { - struct district_worker_record * rec = get_tracked_worker_record (this); - if ((rec != NULL) && (rec->pending_req != NULL)) { - ai_move_district_worker (this, rec); - return; - } - - Tile * worker_tile = tile_at (this->Body.X, this->Body.Y); - if ((worker_tile != NULL) && (worker_tile != p_null_tile)) { - int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); - - if ((civ_id >= 0) && (civ_id < 32)) { - struct pending_district_request * same_city_req = NULL; - struct pending_district_request * same_continent_req = NULL; - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req == NULL) || (req->assigned_worker_id >= 0)) - continue; - if ((req->civ_id != civ_id) || (req->city_id < 0)) - continue; - - City * req_city = get_city_ptr (req->city_id); - if (req_city == NULL) - continue; - - if (city != NULL && req_city->Body.ID == city->Body.ID) { - same_city_req = req; - break; - } - - Tile * req_city_tile = tile_at (req_city->Body.X, req_city->Body.Y); - if ((req_city_tile != NULL) && (req_city_tile != p_null_tile)) { - int req_continent_id = req_city_tile->vtable->m46_Get_ContinentID (req_city_tile); - if (req_continent_id == worker_continent_id) { - same_continent_req = req; - } - } - } - - struct pending_district_request * chosen_req = (same_city_req != NULL) ? same_city_req : same_continent_req; - if (chosen_req != NULL) { - City * req_city = get_city_ptr (chosen_req->city_id); - if (req_city != NULL) { - int target_x = 0; - int target_y = 0; - Tile * target_tile = find_tile_for_district (req_city, chosen_req->district_id, &target_x, &target_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); - assign_worker_to_district (chosen_req, this, req_city, chosen_req->district_id, target_x, target_y); - return; - } - } - } - } - } - } - } - - Unit_join_city (this, __, city); -} - -bool __fastcall -patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y) -{ - bool base = Unit_can_pillage (this, __, tile_x, tile_y); - - if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return base; - - int district_id = inst->district_id; - if (is->current_config.enable_natural_wonders && - (district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) - return false; - - if (! district_is_complete (tile, district_id)) - return true; - - if (district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info == NULL || info->state != WDS_COMPLETED) - return true; - return is->current_config.completed_wonder_districts_can_be_destroyed; - } - - return true; -} - -bool __fastcall -patch_Unit_can_do_worker_command_for_button_setup (Unit * this, int edx, int unit_command_value) -{ - bool base = patch_Unit_can_perform_command (this, __, unit_command_value); - - // If the command is to build a city and it can't be done because another city is already too close, and the minimum separation was changed - // from its standard value, then return true here so that the build city button will be added anyway. We'll gray it out later. Check that the - // grayed out button image is initialized now so we don't activate the build city button then find out later we can't gray it out. - if ((! base) && - (unit_command_value == UCV_Build_City) && - (is->current_config.minimum_city_separation > 1) && - (patch_Map_check_city_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID, false) == CLV_CITY_TOO_CLOSE) && - (init_disabled_command_buttons (), is->disabled_command_img_state == IS_OK)) - return true; - - else - return base; -} - -int -compare_helpers (void const * vp_a, void const * vp_b) -{ - Unit * a = get_unit_ptr (*(int *)vp_a), - * b = get_unit_ptr (*(int *)vp_b); - if ((a != NULL) && (b != NULL)) { - // Compute how many movement points each has left (ML = moves left) - int ml_a = patch_Unit_get_max_move_points (a) - a->Body.Moves, - ml_b = patch_Unit_get_max_move_points (b) - b->Body.Moves; - - // Whichever one has more MP left comes first in the array - if (ml_a > ml_b) return 1; - else if (ml_b > ml_a) return -1; - else return 0; - } else - // If at least one of the unit ids is invalid, might as well sort it later in the array - return (a != NULL) ? -1 : ((b != NULL) ? 1 : 0); -} - -void -issue_stack_worker_command (Unit * unit, int command) -{ - int tile_x = unit->Body.X; - int tile_y = unit->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - int unit_type_id = unit->Body.UnitTypeID; - int unit_id = unit->Body.ID; - - // Put together a list of helpers and store it on the memo. Helpers are just other workers on the same tile that can be issued the same command. - clear_memo (); - FOR_UNITS_ON (uti, tile) - if ((uti.id != unit_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) { - // check if the clicked command is among worker actions that this unit type can perform - int actions = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Worker_Actions; - int command_without_category = command & 0x0FFFFFFF; - if ((actions & command_without_category) == command_without_category) - memoize (uti.id); - } - - // Sort the list of helpers so that the ones with the fewest remaining movement points are listed first. - qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_helpers); - - Unit * next_up = unit; - int i_next_helper = 0; - int last_action_didnt_happen; - do { - int state_before_action = next_up->Body.UnitState; - Main_Screen_Form_issue_command (p_main_screen_form, __, command, next_up); - last_action_didnt_happen = (next_up->Body.UnitState == state_before_action); - - // Call this update function to cause the worker to actually perform the action. Otherwise - // it only gets queued, the worker keeps is movement points, and the action doesn't get done - // until the interturn. - if (! last_action_didnt_happen) - next_up->vtable->update_while_active (next_up); - - next_up = NULL; - while ((i_next_helper < is->memo_len) && (next_up == NULL)) - next_up = get_unit_ptr (is->memo[i_next_helper++]); - } while ((next_up != NULL) && (! last_action_didnt_happen)); -} - -void -issue_district_worker_command (Unit * unit, int command) -{ - if (! is->current_config.enable_districts) - return; - - if (unit == NULL) - return; - - int tile_x = unit->Body.X; - int tile_y = unit->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return; - - if (! is_worker(unit)) - return; - - int district_id = -1; - if (! itable_look_up (&is->command_id_to_district_id, command, &district_id)) - return; - if ((district_id < 0) || (district_id >= is->district_count)) - return; - - if (! leader_can_build_district (&leaders[unit->Body.CivID], district_id)) - return; - - // Disallow placing districts on invalid terrain, pollution, or cratered tiles - if (tile->vtable->m21_Check_Crates (tile, __, 0)) - return; - if (tile->vtable->m20_Check_Pollution (tile, __, 0)) - return; - - if (! district_is_buildable_on_tile (&is->district_configs[district_id], tile)) - return; - - // If District will be replaced by another District - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete(tile, inst->district_id)) { - int existing_district_id = inst->district_id; - int inst_x, inst_y; - if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) - return; - - int civ_id = unit->Body.CivID; - bool redundant_district = district_instance_is_redundant (inst, tile); - bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, inst_x, inst_y); - if (redundant_district) - would_lose_buildings = false; - - bool remove_existing = false; - - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char*)is->district_configs[existing_district_id].display_name, -1, -1); - set_popup_str_param (1, (char*)is->district_configs[existing_district_id].display_name, -1, -1); - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - would_lose_buildings - ? "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT" - : "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT_SAFE", - -1, 0, 0, 0 - ); - - int sel = patch_show_popup (popup, __, 0, 0); - if (sel == 0) - remove_existing = true; - else - return; - - if (remove_existing) { - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); - handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); - } - } - - // If District will replace an improvement - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); - - if (removable_flags != 0) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_BUILD_DISTRICT_OVER_IMPROVEMENT", -1, 0, 0, 0); - int sel = patch_show_popup (popup, __, 0, 0); - if (sel != 0) - return; - } - - if (removable_flags != 0) - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - - inst = ensure_district_instance (tile, district_id, tile_x, tile_y); - inst->built_by_civ_id = unit->Body.CivID; - if (inst != NULL) - inst->state = DS_UNDER_CONSTRUCTION; - - Unit_set_state (unit, __, UnitState_Build_Mines); - unit->Body.Job_ID = WJ_Build_Mines; -} - -void -issue_stack_unit_mgmt_command (Unit * unit, int command) -{ - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - int unit_type_id = unit->Body.UnitTypeID; - int unit_id = unit->Body.ID; - - PopupForm * popup = get_popup_form (); - - clear_memo (); - - if (command == UCV_Fortify) { - // This probably won't work for online games since "fortify all" does additional work in that case. See Main_Screen_Form::fortify_all. - // I don't like how this method doesn't place units in the fortified pose. One workaround is so use - // Main_Screen_Form::issue_fortify_command, but that plays the entire fortify animation for each unit which is a major annoyance for - // large stacks. The base game's "fortify all" function also doesn't set the pose so I don't see any easy way to fix this. - FOR_UNITS_ON (uti, tile) - if ((uti.unit->Body.UnitTypeID == unit_type_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - (uti.unit->Body.CivID == unit->Body.CivID) && - (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) - Unit_set_state (uti.unit, __, UnitState_Fortifying); - - } else if (command == UCV_Upgrade_Unit) { - int our_treasury = leaders[unit->Body.CivID].Gold_Encoded + leaders[unit->Body.CivID].Gold_Decrement; - - // If the unit type we're upgrading to is limited, find out how many we can add. Keep that in "available". If the type is not limited, - // leave available set to INT_MAX. - int available = INT_MAX; { - City * city; - int upgrade_id; - if ((is->current_config.unit_limits.len > 0) && - patch_Unit_can_perform_command (unit, __, UCV_Upgrade_Unit) && - (NULL != (city = city_at (unit->Body.X, unit->Body.Y))) && - (0 < (upgrade_id = City_get_upgraded_type_id (city, __, unit_type_id)))) - get_available_unit_count (&leaders[unit->Body.CivID], upgrade_id, &available); - } - - int cost = 0; - FOR_UNITS_ON (uti, tile) - if ((available > 0) && - (uti.unit->Body.UnitTypeID == unit_type_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - patch_Unit_can_perform_command (uti.unit, __, UCV_Upgrade_Unit)) { - cost += Unit_get_upgrade_cost (uti.unit); - available--; - memoize (uti.id); - } - - if (cost <= our_treasury) { - set_popup_str_param (0, p_bic_data->UnitTypes[unit_type_id].Name, -1, -1); - set_popup_int_param (0, is->memo_len); - set_popup_int_param (1, cost); - popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "UPGRADE_ALL", -1, 0, 0, 0); - if (patch_show_popup (popup, __, 0, 0) == 0) - for (int n = 0; n < is->memo_len; n++) { - Unit * to_upgrade = get_unit_ptr (is->memo[n]); - if (to_upgrade != NULL) - Unit_upgrade (to_upgrade, __, false); - } - - } else { - set_popup_int_param (0, cost); - int param_5 = is_online_game () ? 0x4000 : 0; // As in base code - popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "NO_GOLD_TO_UPGRADE_ALL", -1, 0, param_5, 0); - patch_show_popup (popup, __, 0, 0); - } - - } else if (command == UCV_Disband) { - FOR_UNITS_ON (uti, tile) - if ((uti.unit->Body.UnitTypeID == unit_type_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) - memoize (uti.id); - - if (is->memo_len > 0) { - set_popup_int_param (0, is->memo_len); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_STACK_DISBAND", -1, 0, 0, 0); - if (patch_show_popup (popup, __, 0, 0) == 0) { - for (int n = 0; n < is->memo_len; n++) { - Unit * to_disband = get_unit_ptr (is->memo[n]); - if (to_disband) - Unit_disband (to_disband); - } - } - } - } -} - -void __fastcall -patch_Main_GUI_handle_button_press (Main_GUI * this, int edx, int button_id) -{ - // Set SB flag according to case (2) - if (button_id < 42) { - if ((is->sc_img_state == IS_OK) && - ((this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMBARD].imgs[0]) || - (this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMB ].imgs[0]))) - is->sb_activated_by_button = 1; - else - is->sb_activated_by_button = 0; - } - - int command = this->Unit_Command_Buttons[button_id].Command; - - // Clear any highlighted tiles - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - - if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { - is->city_loc_display_perspective = -1; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw - } - - // If a district, run district build logic - if (is->current_config.enable_districts && is_district_command (command)) { - clear_something_1 (); - Timer_clear (&this->timer_1); - issue_district_worker_command (p_main_screen_form->Current_Unit, command); - return; - } - - // Check if command is a worker build command (not a district) and a district exists on the tile - if (is->current_config.enable_districts && p_main_screen_form->Current_Unit != NULL) { - - bool removed_existing = false; - if (! handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) - return; - if (removed_existing) { - clear_something_1 (); - Timer_clear (&this->timer_1); - Main_GUI_handle_button_press (this, __, button_id); - return; - } - } - - struct sc_button_info const * stack_button_info; { - stack_button_info = NULL; - if (button_id < 42) // If button pressed was a unit command button - for (int n = 0; n < COUNT_STACKABLE_COMMANDS; n++) - if (command == sc_button_infos[n].command) { - stack_button_info = &sc_button_infos[n]; - break; - } - } - - if ((stack_button_info == NULL) || // If there's no stack command for the pressed button OR - (! is->current_config.enable_stack_unit_commands) || // stack unit commands are not enabled OR - (((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // CTRL key is not down OR - (p_main_screen_form->Current_Unit == NULL) || // no unit is selected OR - is_online_game ()) { // is online game - Main_GUI_handle_button_press (this, __, button_id); - return; - } - - enum stackable_command_kind kind = stack_button_info->kind; - if ((kind == SCK_TERRAFORM) || (kind == SCK_UNIT_MGMT)) { - // Replicate behavior of function we're replacing - clear_something_1 (); - Timer_clear (&this->timer_1); - - if (kind == SCK_TERRAFORM) - issue_stack_worker_command (p_main_screen_form->Current_Unit, stack_button_info->command); - else if (kind == SCK_UNIT_MGMT) - issue_stack_unit_mgmt_command (p_main_screen_form->Current_Unit, stack_button_info->command); - } else - Main_GUI_handle_button_press (this, __, button_id); -} - -bool __fastcall -patch_Main_Screen_Form_issue_command (Main_Screen_Form * this, int edx, int command, Unit * unit) -{ - Unit * target_unit = unit; - if (target_unit == NULL) - target_unit = this->Current_Unit; - - if (is->current_config.enable_districts) { - bool removed_existing = false; - if (! handle_worker_command_that_may_replace_district (target_unit, command, &removed_existing)) - return false; - } - - return Main_Screen_Form_issue_command (this, __, command, unit); -} - -bool -is_command_button_active (Main_GUI * main_gui, enum Unit_Command_Values command) -{ - Command_Button * buttons = main_gui->Unit_Command_Buttons; - for (int n = 0; n < 42; n++) - if (((buttons[n].Button.Base_Data.Status2 & 1) != 0) && (buttons[n].Command == command)) - return true; - return false; -} - -int __fastcall -patch_Main_Screen_Form_handle_key_down (Main_Screen_Form * this, int edx, int char_code, int virtual_key_code) -{ - // Set SB flag according to case (4) - int precision_strike_is_available = is_command_button_active (&this->GUI, UCV_Precision_Bombing); - if ((virtual_key_code == VK_B) || (precision_strike_is_available && (virtual_key_code == VK_P))) - is->sb_activated_by_button = 0; - - if ((virtual_key_code & 0xFF) == VK_CONTROL) { - set_up_stack_worker_buttons (&this->GUI); - - if (is->current_config.enable_city_work_radii_highlights && - ! is->highlight_city_radii) { - Unit * unit = p_main_screen_form->Current_Unit; - if (unit != NULL) { - is->highlight_city_radii = true; - compute_highlighted_worker_tiles_for_districts (); - this->vtable->m73_call_m22_Draw ((Base_Form *)this); - } - } - } else { - if (is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - } - - char original_turn_end_flag = this->turn_end_flag; - int tr = Main_Screen_Form_handle_key_down (this, __, char_code, virtual_key_code); - if ((original_turn_end_flag == 1) && (this->turn_end_flag == 0)) - intercept_end_of_turn (); - - return tr; -} - -int -patch_handle_cursor_change_in_jgl () -{ - // Set SB flag according to case (3) and the annoying state - if ((is->sb_activated_by_button != 2) && - (p_main_screen_form->Mode_Action != UMA_Bombard) && - (p_main_screen_form->Mode_Action != UMA_Air_Bombard)) - is->sb_activated_by_button = 0; - - return handle_cursor_change_in_jgl (); -} - -void __fastcall -patch_Main_Screen_Form_handle_left_click_on_map_1 (Main_Screen_Form * this, int edx, int param_1, int param_2) -{ - if (is->sb_activated_by_button == 1) - is->sb_activated_by_button = 2; - Main_Screen_Form_handle_left_click_on_map_1 (this, __, param_1, param_2); - is->sb_activated_by_button = 0; -} - - -void __fastcall -patch_Main_GUI_handle_click_in_status_panel (Main_GUI * this, int edx, int mouse_x, int mouse_y) -{ - char original_turn_end_flag = p_main_screen_form->turn_end_flag; - Main_GUI_handle_click_in_status_panel (this, __, mouse_x, mouse_y); - if ((original_turn_end_flag == 1) && (p_main_screen_form->turn_end_flag == 0)) - intercept_end_of_turn (); -} - -// Gets effective shields generated per turn, including civil engineers, disorder, and anarchy. -int -get_city_production_rate (City * city, enum City_Order_Types order_type, int order_id) -{ - int in_disorder = city->Body.Status & CSF_Civil_Disorder, - in_anarchy = p_bic_data->Governments[leaders[city->Body.CivID].GovernmentType].b_Transition_Type, - getting_tile_shields = (! in_disorder) && (! in_anarchy); - - if (order_type == COT_Improvement) { - int building_wealth = (p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0; - int specialist_shields = 0; - FOR_CITIZENS_IN (ci, city) - if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) // I don't know what is check is for but it's done in the base code - specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; - return (getting_tile_shields ? city->Body.ProductionIncome : 0) + ((! building_wealth) ? specialist_shields : 0); - } else if ((order_type == COT_Unit) && getting_tile_shields) - return city->Body.ProductionIncome; - else - return 0; -} - -void __fastcall -patch_City_Form_open (City_Form * this, int edx, City * city, int param_2) -{ - recompute_resources_if_necessary (); - - WITH_PAUSE_FOR_POPUP { - City_Form_open (this, __, city, param_2); - } -} - -void -init_district_icons () -{ - if (is->dc_icons_img_state != IS_UNINITED) - return; - - char ss[200]; - snprintf (ss, sizeof ss, "[C3X] init_district_icons: state=%d\n", is->dc_icons_img_state); - (*p_OutputDebugStringA) (ss); - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("Districts/DistrictIncomeIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image == NULL) || - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { - (*p_OutputDebugStringA) ("[C3X] PCX file for district icons failed to load or is too small.\n"); - is->dc_icons_img_state = IS_INIT_FAILED; - goto cleanup; - } - - // Extract science icon (index 1) - Sprite_construct (&is->district_science_icon); - Sprite_slice_pcx (&is->district_science_icon, __, &pcx, 1 + 1*31, 1, 30, 30, 1, 1); - - // Extract commerce icon (index 2) - Sprite_construct (&is->district_commerce_icon); - Sprite_slice_pcx (&is->district_commerce_icon, __, &pcx, 1 + 2*31, 1, 30, 30, 1, 1); - - // Extract shield icon (index 4) - Sprite_construct (&is->district_shield_icon); - Sprite_slice_pcx (&is->district_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); - - // Extract corruption icon (index 5) - Sprite_construct (&is->district_corruption_icon); - Sprite_slice_pcx (&is->district_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); - - // Extract food icon (index 6) - Sprite_construct (&is->district_food_icon); - Sprite_slice_pcx (&is->district_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); - - // Extract food eaten icon (index 7) - Sprite_construct (&is->district_food_eaten_icon); - Sprite_slice_pcx (&is->district_food_eaten_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); - - // Extract small happiness icon (index 12) - Sprite_construct (&is->district_happiness_icon_small); - Sprite_slice_pcx (&is->district_happiness_icon_small, __, &pcx, 1 + 12*31, 1, 30, 30, 1, 1); - - // Extract small shield icon (index 13) - Sprite_construct (&is->district_shield_icon_small); - Sprite_slice_pcx (&is->district_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); - - // Extract small commerce icon (index 14) - Sprite_construct (&is->district_commerce_icon_small); - Sprite_slice_pcx (&is->district_commerce_icon_small, __, &pcx, 1 + 14*31, 1, 30, 30, 1, 1); - - // Extract small food icon (index 15: x = 1 + 15*31 = 466, width 30) - Sprite_construct (&is->district_food_icon_small); - Sprite_slice_pcx (&is->district_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); - - // Extract small science icon (index 16) - Sprite_construct (&is->district_science_icon_small); - Sprite_slice_pcx (&is->district_science_icon_small, __, &pcx, 1 + 16*31, 1, 30, 30, 1, 1); - - // Extract small culture icon (index 18) - Sprite_construct (&is->district_culture_icon_small); - Sprite_slice_pcx (&is->district_culture_icon_small, __, &pcx, 1 + 18*31, 1, 30, 30, 1, 1); - - // Load Negatives (mostly red) from here - - // Extract negative small commerce icon (index 17) - Sprite_construct (&is->district_negative_commerce_icon_small); - Sprite_slice_pcx (&is->district_negative_commerce_icon_small, __, &pcx, 1 + 17*31, 1, 30, 30, 1, 1); - - // Extract small unhappiness icon (index 19) - Sprite_construct (&is->district_unhappiness_icon_small); - Sprite_slice_pcx (&is->district_unhappiness_icon_small, __, &pcx, 1 + 19*31, 1, 30, 30, 1, 1); - - // Extract negative small shield icon (index 20) - Sprite_construct (&is->district_negative_shield_icon_small); - Sprite_slice_pcx (&is->district_negative_shield_icon_small, __, &pcx, 1 + 20*31, 1, 30, 30, 1, 1); - - // Extract negative small culture icon (index 21) - Sprite_construct (&is->district_negative_culture_icon_small); - Sprite_slice_pcx (&is->district_negative_culture_icon_small, __, &pcx, 1 + 21*31, 1, 30, 30, 1, 1); - - // Extract negative small culture icon (index 22) - Sprite_construct (&is->district_negative_food_icon_small); - Sprite_slice_pcx (&is->district_negative_food_icon_small, __, &pcx, 1 + 22*31, 1, 30, 30, 1, 1); - - // Extract negative small science icon (index 23) - Sprite_construct (&is->district_negative_science_icon_small); - Sprite_slice_pcx (&is->district_negative_science_icon_small, __, &pcx, 1 + 23*31, 1, 30, 30, 1, 1); - - is->dc_icons_img_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void __fastcall -patch_City_Form_draw (City_Form * this) -{ - // Recompute city form production rect location every time because the config might have changed. Doing it here is also easier than - // patching the constructor. - int form_top = (p_bic_data->ScreenHeight - this->Background_Image.Height) / 2; - this->Production_Storage_Indicator.top = form_top + 621 + (is->current_config.show_detailed_city_production_info ? 34 : 0); - - is->drawn_strat_resource_count = 0; - - // Make sure culture income (including from districts) is up to date before the draw event - if (is->current_config.enable_districts) - patch_City_recompute_culture_income(this->CurrentCity); - - City_Form_draw (this); - - if (is->current_config.show_detailed_city_production_info) { - City * city = this->CurrentCity; - int order_type = city->Body.Order_Type, - order_id = city->Body.Order_ID, - order_progress = City_get_order_progress (city), - order_cost = City_get_order_cost (city), - prod_rate = get_city_production_rate (city, order_type, order_id), - building_wealth = (order_type == COT_Improvement) && ((p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0); - - int turns_left, surplus; { - if (prod_rate > 0) { - turns_left = (order_cost - order_progress) / prod_rate; - if ((order_cost - order_progress) % prod_rate != 0) - turns_left++; - if (turns_left < 1) - turns_left = 1; - surplus = (turns_left * prod_rate) - (order_cost - order_progress); - } else { - turns_left = 9999; - surplus = 0; - } - } - - char line1[100]; { - if (prod_rate > 0) { - if (! building_wealth) - snprintf (line1, sizeof line1, "%s %d %s", this->Labels.To_Build, turns_left, (turns_left == 1) ? this->Labels.Single_Turn : this->Labels.Multiple_Turns); - else - snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_NEVER_COMPLETES]); - } else - snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_HALTED]); - line1[(sizeof line1) - 1] = '\0'; - } - - char line2[100]; { - if (! building_wealth) { - int percent_complete = order_cost > 0 ? ((10000 * order_progress) / order_cost + 50) / 100 : 100; - snprintf (line2, sizeof line2, "%d / %d (%d%s)", order_progress, order_cost, percent_complete, this->Labels.Percent); - } else - snprintf (line2, sizeof line2, "---"); - line2[(sizeof line2) - 1] = '\0'; - } - - char line3[100]; { - if ((! building_wealth) && (prod_rate > 0)) { - int s_per, s_rem; { - if (turns_left > 1) { - s_per = surplus / turns_left; - s_rem = surplus % turns_left; - } else { - s_per = surplus; - s_rem = 0; - } - } - char * s_lab = is->c3x_labels[CL_SURPLUS]; - if ((s_per != 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d + %d %s", s_lab, s_rem, s_per, this->Labels.Per_Turn); - else if ((s_per == 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d", s_lab, s_rem); - else if ((s_per != 0) && (s_rem == 0)) snprintf (line3, sizeof line3, "%s: %d %s", s_lab, s_per, this->Labels.Per_Turn); - else snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NONE]); - } else - snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NA]); - line3[(sizeof line3) - 1] = '\0'; - } - - Object_66C3FC * font = get_font (10, FSF_NONE); - int left = this->Production_Storage_Indicator.left, - top = this->Production_Storage_Indicator.top, - width = this->Production_Storage_Indicator.right - left; - PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line1, left, top - 42, width, strlen (line1)); - PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line2, left, top - 28, width, strlen (line2)); - PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line3, left, top - 14, width, strlen (line3)); - } - - // Draw district commerce bonuses (gold and science) - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - // Lazy load district icons - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - if (is->dc_icons_img_state != IS_OK) - return; - - City * city = this->CurrentCity; - if (city == NULL) - return; - - // Calculate district gold and science bonuses by iterating workable tiles - int district_gold = 0; - int city_civ_id = city->Body.CivID; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) continue; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - struct district_config const * cfg = &is->district_configs[district_id]; - int gold_bonus = 0; - get_effective_district_yields (inst, cfg, NULL, NULL, &gold_bonus, NULL, NULL, NULL); - district_gold += gold_bonus; - } - - Leader * leader = &leaders[city_civ_id]; - int gold_proportion = (district_gold * leader->gold_slider) / 10; - int science_proportion = (district_gold * leader->science_slider) / 10; - - // Draw district gold icons - if (gold_proportion > 0) { - Sprite * gold_sprite = &is->district_commerce_icon; - int sprite_width = gold_sprite->Width; - int sprite_height = gold_sprite->Height; - - struct tagRECT * gold_rect = &this->Gold_Income_Rect; - int total_gold = City_get_net_commerce (city, __, 2, true); - - // Calculate spacing - int spacing = sprite_width; - if ((total_gold > 1) && (total_gold * sprite_width != (gold_rect->right - gold_rect->left))) { - int rect_width = gold_rect->right - gold_rect->left; - if (rect_width <= total_gold * sprite_width) { - spacing = (rect_width - sprite_width) / (total_gold - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > sprite_width) - spacing = sprite_width; - } - } - - // Draw from right to left - int x_offset = 0; - int y_offset = 5; - for (int i = 0; i < gold_proportion && i < total_gold; i++) { - int x = gold_rect->right - x_offset - sprite_width; - int y = gold_rect->top + ((gold_rect->bottom - gold_rect->top >> 1) - - (sprite_height >> 1)) + y_offset; - - Sprite_draw (gold_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); - x_offset += spacing; - } - } - - // Draw district science icons - if (science_proportion > 0) { - Sprite * science_sprite = &is->district_commerce_icon; - int sprite_width = science_sprite->Width; - int sprite_height = science_sprite->Height; - - struct tagRECT * science_rect = &this->Science_Income_Rect; - int total_science = City_get_net_commerce (city, __, 1, true); - - // Calculate spacing - int spacing = sprite_width; - if ((total_science > 1) && (total_science * sprite_width != (science_rect->right - science_rect->left))) { - int rect_width = science_rect->right - science_rect->left; - if (rect_width <= total_science * sprite_width) { - spacing = (rect_width - sprite_width) / (total_science - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > sprite_width) - spacing = sprite_width; - } - } - - // Draw from right to left - int x_offset = 0; - int y_offset = 5; - for (int i = 0; i < science_proportion && i < total_science; i++) { - int x = science_rect->right - x_offset - sprite_width; - int y = science_rect->top + ((science_rect->bottom - science_rect->top >> 1) - - (sprite_height >> 1)) + y_offset; - - Sprite_draw (science_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); - x_offset += spacing; - } - } -} - -void __fastcall -patch_City_Form_print_production_info (City_Form *this, int edx, String256 * out_strs, int str_capacity) -{ - City_Form_print_production_info (this, __, out_strs, str_capacity); - if (is->current_config.show_detailed_city_production_info) - out_strs[1].S[0] = '\0'; -} - -int __fastcall -patch_Sprite_draw_strat_res_on_city_screen (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - if (is->current_config.compact_strategic_resource_display_on_city_screen) - pixel_x -= 13 * is->drawn_strat_resource_count + 17; - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -int __fastcall -patch_PCX_Image_do_draw_cntd_text_for_strat_res (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) -{ - if (is->current_config.compact_strategic_resource_display_on_city_screen) - x -= 13 * is->drawn_strat_resource_count + 17; - int tr = PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); - is->drawn_strat_resource_count++; - return tr; -} - -int __fastcall -patch_City_get_turns_to_build (City * this, int edx, enum City_Order_Types order_type, int order_id, bool param_3) -{ - // To fix the zero production crash, return 9999 when the city's total production rate is zero, avoiding a division by zero. That's only - // possible when producing an improvement due to negative shields from specialists. The original logic attempts to return 9999 in case of zero - // production but checks for that before including shields from specialists. - if (is->current_config.patch_zero_production_crash && (order_type == COT_Improvement)) { - - int specialist_shields = 0; - FOR_CITIZENS_IN (ci, this) - if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) - specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; - - // Return 9999 if the denominator in the base function's calculation would be zero. Note the base calc is incorrect in that it - // considers specialist shields to count toward Wealth, however we're not going to address that issue here, just stop the crash. - if (this->Body.ProductionIncome + specialist_shields <= 0) - return 9999; - } - - return City_get_turns_to_build (this, __, order_type, order_id, param_3); -} - -bool -is_below_stack_limit (Tile * tile, int civ_id, int type_id) -{ - enum UnitTypeClasses class = p_bic_data->UnitTypes[type_id].Unit_Class; - - int stack_limit = is->current_config.limit_units_per_tile[class]; - if (stack_limit <= 0) - return true; - - if (is->current_config.exclude_cities_from_units_per_tile_limit && - get_city_ptr (tile->CityID) != NULL) - return true; - - if (itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, type_id, 0)) - return true; - - FOR_UNITS_ON (uti, tile) { - // If there is a foreign unit on the tile then consider it as being below the stack limit. This ensures that the stack limit doesn't - // block combat between players. - if (uti.unit->Body.CivID != civ_id) - return true; - - int uti_type_id = uti.unit->Body.UnitTypeID; - if ((uti.unit->Body.Container_Unit < 0) && - (class == p_bic_data->UnitTypes[uti_type_id].Unit_Class) && - ! itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, uti_type_id, 0)) { - stack_limit -= 1; - if (stack_limit <= 0) - return false; - } - } - return true; -} - -// Returns the ID of the civ this move is trespassing against, or 0 if it's not trespassing. -int -check_trespassing (int civ_id, Tile * from, Tile * to) -{ - int from_territory_id = from->vtable->m38_Get_Territory_OwnerID (from), - to_territory_id = to ->vtable->m38_Get_Territory_OwnerID (to); - if ((civ_id > 0) && - (to_territory_id != civ_id) && - (to_territory_id > 0) && - (to_territory_id != from_territory_id) && - (! leaders[civ_id].At_War[to_territory_id]) && - ((leaders[civ_id].Relation_Treaties[to_territory_id] & 2) == 0)) // Check right of passage - return to_territory_id; - else - return 0; -} - -bool -is_allowed_to_trespass (Unit * unit) -{ - int type_id = unit->Body.UnitTypeID; - if ((type_id >= 0) && (type_id < p_bic_data->UnitTypeCount)) { - UnitType * type = &p_bic_data->UnitTypes[type_id]; - return UnitType_has_ability (type, __, UTA_Hidden_Nationality) || UnitType_has_ability (type, __, UTA_Invisible); - } else - return false; -} - -bool -get_tile_district_impassibility (Tile * tile, bool * out_impassible, bool * out_impassible_to_wheeled) -{ - if (out_impassible != NULL) - *out_impassible = false; - if (out_impassible_to_wheeled != NULL) - *out_impassible_to_wheeled = false; - - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - if (! district_is_complete (tile, inst->district_id)) - return false; - - if (inst->district_id == NATURAL_WONDER_DISTRICT_ID) { - if (! is->current_config.enable_natural_wonders) - return false; - int natural_id = inst->natural_wonder_info.natural_wonder_id; - if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) - return false; - if (out_impassible != NULL) - *out_impassible = is->natural_wonder_configs[natural_id].impassible; - if (out_impassible_to_wheeled != NULL) - *out_impassible_to_wheeled = is->natural_wonder_configs[natural_id].impassible_to_wheeled; - return true; - } - - if (! is->current_config.enable_districts) - return false; - if ((inst->district_id < 0) || (inst->district_id >= is->district_count)) - return false; - - if (out_impassible != NULL) - *out_impassible = is->district_configs[inst->district_id].impassible; - if (out_impassible_to_wheeled != NULL) - *out_impassible_to_wheeled = is->district_configs[inst->district_id].impassible_to_wheeled; - return true; -} - -AdjacentMoveValidity __fastcall -patch_Unit_can_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, int param_2) -{ - AdjacentMoveValidity base_validity = Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2); - - if (is->current_config.enable_districts) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - Tile * dest = tile_at (nx, ny); - - // Let workers step onto coast tiles when the config flag is enabled (base logic treats this as an invalid sea move) - if (is->current_config.workers_can_enter_coast && is_worker (this) && - ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { - if ((dest != NULL) && - dest->vtable->m35_Check_Is_Water (dest) && - (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) - base_validity = AMV_OK; - } - - // Allow land units to enter bridge tiles - if (is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && - ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { - if ((dest != NULL) && (dest != p_null_tile)) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { - base_validity = AMV_OK; - } - } - } - - // Allow naval units to enter completed canal tiles - if (is->current_config.enable_canal_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && - ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { - if ((dest != NULL) && (dest != p_null_tile)) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { - base_validity = AMV_OK; - } - } - } - - if ((base_validity == AMV_OK) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { - if ((dest != NULL) && (dest != p_null_tile) && Tile_has_city (dest)) - return AMV_INVALID_SEA_MOVE; - } - } - - // Apply unit count per tile limit - int type_id = this->Body.UnitTypeID; - if ((base_validity == AMV_OK) && (is->current_config.limit_units_per_tile[p_bic_data->UnitTypes[type_id].Unit_Class] > 0)) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - if (! is_below_stack_limit (tile_at (nx, ny), this->Body.CivID, type_id)) - return AMV_CANNOT_PASS_BETWEEN; - } - - // Apply trespassing restriction - if (is->current_config.disallow_trespassing && (base_validity == AMV_OK)) { - Tile * from = tile_at (this->Body.X, this->Body.Y); - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - int trespasses_against_civ_id = check_trespassing (this->Body.CivID, from, tile_at (nx, ny)); - if ((trespasses_against_civ_id > 0) && (! is_allowed_to_trespass (this))) - // The tile might be occupied by a unit belonging to a civ other than the one that owns the territory (against whom we'd be - // trespassing). In this case we must forbid the move entirely since TRIGGERS_WAR will not stop it if we're at war with the - // occupying civ. This fixes a bug where units could trespass by attacking an enemy unit across a border. They would then get - // stuck halfway between tiles if they won. - return (trespasses_against_civ_id == get_tile_occupier_id (nx, ny, this->Body.CivID, false)) ? AMV_TRIGGERS_WAR : AMV_CANNOT_PASS_BETWEEN; - } - - return base_validity; -} - -bool -great_wall_blocks_civ (Tile * tile, int civ_id) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_great_wall_districts || - ! is->current_config.great_wall_districts_impassible_by_others) - return false; - - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (owner_id <= 0) - return false; - if (owner_id == civ_id) - return false; - if ((civ_id > 0) && ((leaders[civ_id].Relation_Treaties[owner_id] & 2) != 0)) // 2 = right of passage - return false; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID)) - return false; - - if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) - return false; - - if (district_is_obsolete_for_civ (GREAT_WALL_DISTRICT_ID, civ_id)) - return false; - - return true; -} - -int __fastcall -patch_Trade_Net_get_movement_cost (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned flags, int neighbor_index, Trade_Net_Distance_Info * dist_info) -{ - if (is->is_computing_city_connections && // if this call came while rebuilding the trade network AND - (is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL) && // Trade Net X is set up AND - (unit == NULL) && ((flags == 0x1009) || (flags == 0x9))) // this call can be accelerated by TNX - return is->get_move_cost_for_sea_trade (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags, neighbor_index, dist_info); - - int base_cost = Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, neighbor_index, dist_info); - - bool districts_enabled = is->current_config.enable_districts; - if (districts_enabled) { - Tile * to = tile_at (to_x, to_y); - bool to_valid = (to != NULL) && (to != p_null_tile); - struct district_instance * to_inst = NULL; - bool to_inst_complete = false; - if (to_valid) { - to_inst = get_district_instance (to); - if (to_inst != NULL) - to_inst_complete = district_is_complete (to, to_inst->district_id); - } - - if ((unit != NULL) && great_wall_blocks_civ (to, unit->Body.CivID)) - return -1; - if ((unit != NULL) && to_valid) { - bool impassible = false; - bool impassible_to_wheeled = false; - if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { - if (impassible) - return -1; - if (impassible_to_wheeled && Unit_has_ability (unit, __, UTA_Wheeled)) { - Tile * from = tile_at (from_x, from_y); - bool connected_by_road = (from != NULL) && (to != NULL) && - (from->vtable->m25_Check_Roads (from, __, 0) != 0) && - (to->vtable->m25_Check_Roads (to, __, 0) != 0); - if (! connected_by_road) - return -1; - } - } - } - - // Let the pathfinder consider coastal tiles reachable for workers when the config flag is on - if (is->current_config.workers_can_enter_coast && - (base_cost < 0) && (unit != NULL) && is_worker (unit) && - to_valid && - to->vtable->m35_Check_Is_Water (to) && - (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) - base_cost = Unit_get_max_move_points (unit); - - // Let the pathfinder consider bridge tiles reachable for land units - if (is->current_config.enable_bridge_districts && - (base_cost < 0) && (unit != NULL) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == BRIDGE_DISTRICT_ID)) - base_cost = Unit_get_max_move_points (unit); - - // Let the pathfinder consider canal tiles reachable for naval units - if (is->current_config.enable_canal_districts && - (base_cost < 0) && (unit != NULL) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == CANAL_DISTRICT_ID)) - base_cost = Unit_get_max_move_points (unit); - - // Treat roads/rails on bridge districts like land roads/rails for movement cost. - if ((unit != NULL) && - is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land)) { - Tile * from = tile_at (from_x, from_y); - if ((from != NULL) && (from != p_null_tile) && to_valid) { - struct district_instance * from_inst = get_district_instance (from); - bool from_bridge = (from_inst != NULL) && - (from_inst->district_id == BRIDGE_DISTRICT_ID) && - district_is_complete (from, from_inst->district_id); - bool to_bridge = (to_inst != NULL) && - to_inst_complete && - (to_inst->district_id == BRIDGE_DISTRICT_ID); - if (from_bridge || to_bridge) { - bool from_rail = from->vtable->m23_Check_Railroads (from, __, 0) != 0; - bool to_rail = to->vtable->m23_Check_Railroads (to, __, 0) != 0; - bool from_road = from->vtable->m25_Check_Roads (from, __, 0) != 0; - bool to_road = to->vtable->m25_Check_Roads (to, __, 0) != 0; - if (from_rail && to_rail) - base_cost = 0; - else if (from_road && to_road) - base_cost = 1; - } - } - } - - if ((unit != NULL) && - (base_cost >= 0) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && - to_valid && Tile_has_city (to)) - return -1; - } - - // Apply unit count per tile limit - if ((unit != NULL) && ! is_below_stack_limit (tile_at (to_x, to_y), unit->Body.CivID, unit->Body.UnitTypeID)) - return -1; - - // Apply trespassing restriction - if (is->current_config.disallow_trespassing && - check_trespassing (civ_id, tile_at (from_x, from_y), tile_at (to_x, to_y)) && - ((unit == NULL) || (! is_allowed_to_trespass (unit)))) - return -1; - - // Adjust movement cost to enforce limited railroad movement - if ((is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0)) { - if ((unit != NULL) && (base_cost == 0)) { // Railroad move - if (! is->current_config.limited_railroads_work_like_fast_roads) { // If Civ 4 style RR, scale cost by type's moves - int type_moves_available = patch_Unit_get_max_move_points (unit) / p_bic_data->General.RoadsMovementRate; - return type_moves_available * is->railroad_mp_cost_per_move; - } else - return is->railroad_mp_cost_per_move; - } else if (base_cost == 1) // Road move - return is->road_mp_cost; - } - - return base_cost; -} - -int __fastcall -patch_Trade_Net_set_unit_path (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) -{ - int tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); - - bool may_require_length_fix = (is->current_config.limit_railroad_movement > 0) && // if railroad movement is limited AND - (tr > 0) && (out_path_length_in_mp != NULL) && // path was found AND caller wants to know its length AND - (unit != NULL); // the path is for an actual unit - - // We might have to correct the path length returned by the base game's pathfinder. This occurs when railroad movement is limited and the - // unit's total MP exceeds what can be stored in a one-byte integer. The cause of the incorrect length is that the pathfinder internally - // stores the remaining moves at each node of the search in a single byte. This correction fixes the bug (reported several times) that ETAs - // shown in the interface are wrong. - if (may_require_length_fix && (patch_Unit_get_max_move_points (unit) > 255)) { // Need to recompute path length if unit's total MP can overflow a uint8 - - // First memoize the cost of taking each step along the path. This must be done separately because the pathfinder's internal data only - // lets us traverse the path backwards. - { - // Must pass cached "distance info" to Trade_Net::get_movement_cost. Trade_Net stores two sets of cached data, which one was - // used depends on the flags. I believe one is intended to be used for city trade connections and the other for unit movement. - Trade_Net_Distance_Info * dist_info = (flags & 1) ? this->Data2 : this->Data4; - - clear_memo (); - int x = to_x, y = to_y; - do { - // "flags & 1" again determines whether Data2 or Data4 was used. - enum direction dir = Trade_Net_get_direction_from_internal_map (this, __, x, y, flags & 1); - if (dir == DIR_ZERO) - break; - - int prev_x, prev_y; { - int dx, dy; - neighbor_index_to_diff (dir, &dx, &dy); - prev_x = x + dx; prev_y = y + dy; - wrap_tile_coords (&p_bic_data->Map, &prev_x, &prev_y); - } - - memoize (patch_Trade_Net_get_movement_cost (this, __, prev_x, prev_y, x, y, unit, civ_id, flags, reverse_dir (dir), dist_info)); - x = prev_x; y = prev_y; - } while (! ((x == from_x) && (y == from_y))); - } - - // Now walk the path forwards tracking how much MP the unit would spend. We must be aware that the unit can't spend more MP than it - // has. For example, if a unit with 1 move walks onto an unimproved mountain, that effectively costs only 1 move, not 3. - int mp_remaining = patch_Unit_get_max_move_points (unit) - unit->Body.Moves, - mp_spent = 0; - for (int n = is->memo_len - 1; n >= 0; n--) { - int cost = is->memo[n]; - if (cost < mp_remaining) { - mp_spent += cost; - mp_remaining -= cost; - } else { - mp_spent += mp_remaining; - mp_remaining = patch_Unit_get_max_move_points (unit); - } - } - *out_path_length_in_mp = mp_spent; - - // Also, if this is a move between adjacent tiles, make sure the path length doesn't exceed the unit's remaining MP. Otherwise, the game may - // erroneously show an ETA of >1 turn. - } else if (may_require_length_fix && are_tiles_adjacent (from_x, from_y, to_x, to_y)) - *out_path_length_in_mp = not_above (patch_Unit_get_max_move_points (unit) - unit->Body.Moves, *out_path_length_in_mp); - - return tr; -} - -int __fastcall -patch_Trade_Net_set_unit_path_to_find_sea_route (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) -{ - // Accelerate this call with TNX if possible - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { - bool route_exists = is->try_drawing_sea_trade_route (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags); - return route_exists ? 1 : 0; - } else - return Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); -} - -// Renames this leader and their civ based on their era. Era-specific names come from the config file. If this leader has a custom name set by the -// human player, this method does nothing. -void -apply_era_specific_names (Leader * leader) -{ - int leader_bit = 1 << leader->ID; - Race * race = &p_bic_data->Races[leader->RaceID]; - - struct replaceable_name { - char * base_name; - int * tracking_bits; - char * buf; - int buf_size; - } replaceable_names[] = { - {race->vtable->GetAdjectiveName (race), &is->aliased_civ_adjective_bits , leader->tribe_customization.civ_adjective , sizeof leader->tribe_customization.civ_adjective}, - {race->vtable->GetSingularName (race) , &is->aliased_civ_noun_bits , leader->tribe_customization.civ_noun , sizeof leader->tribe_customization.civ_noun}, - {race->vtable->GetCountryName (race) , &is->aliased_civ_formal_name_bits, leader->tribe_customization.civ_formal_name, sizeof leader->tribe_customization.civ_formal_name} - }; - - // Apply replacements to civ noun, adjective, and formal name - for (int n = 0; n < ARRAY_LEN (replaceable_names); n++) { - struct replaceable_name * repl = &replaceable_names[n]; - if ((*repl->tracking_bits & leader_bit) || (repl->buf[0] == '\0')) { - char * replacement = NULL; - if (leader->Era < ERA_ALIAS_LIST_CAPACITY) - // Search through the list of aliases in reverse order so that, if the same key was listed multiple times, the last - // appearance overrides the earlier ones. This is important b/c when configs are loaded, their aliases get appended to - // the list. - for (int k = is->current_config.count_civ_era_alias_lists - 1; k >= 0; k--) { - struct civ_era_alias_list * list = &is->current_config.civ_era_alias_lists[k]; - if (strcmp (list->key, repl->base_name) == 0) { - replacement = list->aliases[leader->Era]; - break; - } - } - if (replacement != NULL) { - strncpy (repl->buf, replacement, repl->buf_size); - repl->buf[repl->buf_size - 1] = '\0'; - *repl->tracking_bits |= leader_bit; - } else { - repl->buf[0] = '\0'; - *repl->tracking_bits &= ~leader_bit; - } - } - } - - // Apply replacement to leader name, gender, and title - if ((is->aliased_leader_name_bits & leader_bit) || (leader->tribe_customization.leader_name[0] == '\0')) { - char * base_name = race->vtable->GetLeaderName (race); - char * replacement_name = NULL; - char * replacement_title = NULL; - int replacement_gender; // Only used if replacement_name is - if (leader->Era < ERA_ALIAS_LIST_CAPACITY) - for (int k = is->current_config.count_leader_era_alias_lists - 1; k >= 0; k--) { - struct leader_era_alias_list * list = &is->current_config.leader_era_alias_lists[k]; - if (strcmp (list->key, base_name) == 0) { - replacement_name = list->aliases[leader->Era]; - replacement_title = list->titles[leader->Era]; - replacement_gender = (list->gender_bits >> leader->Era) & 1; - break; - } - } - if (replacement_name != NULL) { - TribeCustomization * tc = &leader->tribe_customization; - strncpy (tc->leader_name, replacement_name, sizeof tc->leader_name); - tc->leader_name[(sizeof tc->leader_name) - 1] = '\0'; - tc->leader_gender = replacement_gender; - is->aliased_leader_name_bits |= leader_bit; - - // If this replacement name has a special title and this player does not have a custom title set, replace the title. - if ((replacement_title != NULL) && ((is->aliased_leader_title_bits & leader_bit) || (tc->leader_title[0] == '\0'))) { - strncpy (tc->leader_title, replacement_title, sizeof tc->leader_title); - tc->leader_title[(sizeof tc->leader_title) - 1] = '\0'; - is->aliased_leader_title_bits |= leader_bit; - - // If the current name has no title and the player's title was previously replaced, undo the replacement. - } else if ((replacement_title == NULL) && (is->aliased_leader_title_bits & leader_bit)) { - leader->tribe_customization.leader_title[0] = '\0'; - is->aliased_leader_title_bits &= ~leader_bit; - } - } else { - leader->tribe_customization.leader_name[0] = '\0'; - // Don't need to clear custom leader gender since it's not used unless a custom name was set - is->aliased_leader_name_bits &= ~leader_bit; - - // Remove title replacement if present - if (is->aliased_leader_title_bits & leader_bit) { - leader->tribe_customization.leader_title[0] = '\0'; - is->aliased_leader_title_bits &= ~leader_bit; - } - } - } -} - -int __cdecl -patch_do_save_game (char const * file_path, char param_2, GUID * guid) -{ - // Do not save the modified road movement rate, if it was modified to limit railroad movement - int restore_rmr = (is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0); - int rmr; - if (restore_rmr) { - rmr = p_bic_data->General.RoadsMovementRate; - p_bic_data->General.RoadsMovementRate = is->saved_road_movement_rate; - } - - // Do not save the modified barb culture group ID - int restore_barb_culture_group = is->current_config.enable_city_capture_by_barbarians && (is->saved_barb_culture_group >= 0); - int barb_culture; - if (restore_barb_culture_group) { - barb_culture = p_bic_data->Races[leaders[0].RaceID].CultureGroupID; - p_bic_data->Races[leaders[0].RaceID].CultureGroupID = is->saved_barb_culture_group; - } - - // Do not save names that were replaced with era-specific versions - for (int n = 0; n < 32; n++) { - Leader * leader = &leaders[n]; - int leader_bit = 1 << leader->ID; - if (is->aliased_civ_noun_bits & leader_bit) leader->tribe_customization.civ_noun [0] = '\0'; - if (is->aliased_civ_adjective_bits & leader_bit) leader->tribe_customization.civ_adjective [0] = '\0'; - if (is->aliased_civ_formal_name_bits & leader_bit) leader->tribe_customization.civ_formal_name[0] = '\0'; - if (is->aliased_leader_name_bits & leader_bit) leader->tribe_customization.leader_name [0] = '\0'; - if (is->aliased_leader_title_bits & leader_bit) leader->tribe_customization.leader_title [0] = '\0'; - } - is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; - - // Do not save unit types with the charm bits cleared if they were cleared by convertion to PTW targeting. The special actions field must not - // include the top category bits that are part of the UCV_* enum - for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { - UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; - converted_type->Special_Actions |= (0x00FFFFFF & UCV_Charm_Bombard); - } - - int tr = do_save_game (file_path, param_2, guid); - - if (restore_rmr) - p_bic_data->General.RoadsMovementRate = rmr; - if (restore_barb_culture_group) - p_bic_data->Races[leaders[0].RaceID].CultureGroupID = barb_culture; - - // Reapply era aliases - for (int n = 0; n < 32; n++) - if (*p_player_bits & (1 << n)) - apply_era_specific_names (&leaders[n]); - - // Reclear charm bits on converted types - for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { - UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; - converted_type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); - } - - return tr; -} - -void -record_unit_type_alt_strategy (int type_id) -{ - int ai_strat_index; { - int ai_strat_bits = p_bic_data->UnitTypes[type_id].AI_Strategy; - if ((ai_strat_bits & ai_strat_bits - 1) != 0) // Sanity check: must only have one strat (one bit) set - return; - ai_strat_index = 0; - while ((ai_strat_bits & 1) == 0) { - ai_strat_index++; - ai_strat_bits >>= 1; - } - } - - itable_insert (&is->unit_type_alt_strategies, type_id, ai_strat_index); -} - -void -append_improv_id_to_list (struct improv_id_list * list, int id) -{ - reserve (sizeof list->items[0], (void **)&list->items, &list->capacity, list->count); - list->items[list->count] = id; - list->count += 1; -} - -unsigned __fastcall -patch_load_scenario (BIC * this, int edx, char * param_1, unsigned * param_2) -{ - int ret_addr = ((int *)¶m_1)[-1]; - - // Destroy TNX cache from previous map. A new one will be created when needed. - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { - is->destroy_tnx_cache (is->tnx_cache); - is->tnx_cache = NULL; - } - - unsigned tr = load_scenario (this, __, param_1, param_2); - char * scenario_path = param_1; - - // There are two cases when load_scenario is called that we don't want to run our own code. These are (1) when the scenario is loaded to - // generate a preview (map, etc.) for the "Civ Content" or "Conquests" menu and (2) when the function is called recursively. The recursive - // call is done, I believe, only when loading saves using the default rules. The game first tries to load custom rules then falls back on - // loading the default rules. In any case, we want to ignore that call so we don't run the same code twice. - if ((ret_addr == ADDR_LOAD_SCENARIO_PREVIEW_RETURN) || (ret_addr == ADDR_LOAD_SCENARIO_RESUME_SAVE_2_RETURN)) - return tr; - - reset_to_base_config (); - load_config ("default.c3x_config.ini", 1); - char * scenario_config_file_name = "scenario.c3x_config.ini"; - char * scenario_config_path = BIC_get_asset_path (p_bic_data, __, scenario_config_file_name, false); - - // BIC_get_asset_path returns the file name when it can't find the file - if (0 != strcmp (scenario_config_file_name, scenario_config_path)) { - load_config (scenario_config_path, 0); - } - load_config ("custom.c3x_config.ini", 1); - apply_machine_code_edits (&is->current_config, false); - - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - reset_district_state (true); - load_districts_config (); - } - - // Initialize Trade Net X - if (is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_UNINITED)) { - char path[MAX_PATH]; - snprintf (path, sizeof path, "%s\\Trade Net X\\TradeNetX.dll", is->mod_rel_dir); - path[(sizeof path) - 1] = '\0'; - is->trade_net_x = LoadLibraryA (path); - if (is->trade_net_x != NULL) { - is->set_exe_version = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_exe_version"); - is->create_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "create_tnx_cache"); - is->destroy_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "destroy_tnx_cache"); - is->set_up_before_building_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_up_before_building_network"); - is->get_move_cost_for_sea_trade = (void *)(*p_GetProcAddress) (is->trade_net_x, "get_move_cost_for_sea_trade"); - is->flood_fill_road_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "flood_fill_road_network"); - is->try_drawing_sea_trade_route = (void *)(*p_GetProcAddress) (is->trade_net_x, "try_drawing_sea_trade_route"); - - is->set_exe_version (exe_version_index); - - // Run tests - if (0) { - int (__stdcall * test) () = (void *)(*p_GetProcAddress) (is->trade_net_x, "test"); - int failed_test_count = test (); - if (failed_test_count > 0) - MessageBoxA (NULL, "Failed some tests in Trade Net X!", NULL, MB_ICONWARNING); - else - MessageBoxA (NULL, "All tests in Trade Net X passed.", "Success", MB_ICONINFORMATION); - } - - is->tnx_init_state = IS_OK; - } else { - MessageBoxA (NULL, "Failed to load Trade Net X!", NULL, MB_ICONERROR); - is->tnx_init_state = IS_INIT_FAILED; - } - - // Deinitialize Trade Net X - } else if ((! is->current_config.enable_trade_net_x) && (is->tnx_init_state == IS_OK)) { - FreeLibrary (is->trade_net_x); - is->trade_net_x = NULL; - is->tnx_init_state = IS_UNINITED; - } - - // This scenario might use different mod art assets than the old one - deinit_stackable_command_buttons (); - deinit_disabled_command_buttons (); - deinit_trade_scroll_buttons (); - deinit_unit_rcm_icons (); - deinit_red_food_icon (); - deinit_large_minimap_frame (); - if (is->tile_already_worked_zoomed_out_sprite_init_state != IS_UNINITED) { - enum init_state * state = &is->tile_already_worked_zoomed_out_sprite_init_state; - if (*state == IS_OK) { - Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; - sprite->vtable->destruct (sprite, __, 0); - } - *state = IS_UNINITED; - } - - // Need to clear this since the resource count might have changed - if (is->extra_available_resources != NULL) { - free (is->extra_available_resources); - is->extra_available_resources = NULL; - is->extra_available_resources_capacity = 0; - } - - // Similarly, these don't carry over between games - for (int n = 0; n < 32; n++) - is->interceptor_reset_lists[n].count = 0; - is->replay_for_players = 0; - table_deinit (&is->extra_defensive_bombards); - table_deinit (&is->airdrops_this_turn); - table_deinit (&is->unit_transport_ties); - is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; - is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; - is->last_selected_unit.ptr = NULL; - table_deinit (&is->waiting_units); - is->have_loaded_waiting_units = false; - - // Clear extra city improvement bits - FOR_TABLE_ENTRIES (tei, &is->extra_city_improvs) - free ((void *)tei.value); - table_deinit (&is->extra_city_improvs); - - // Clear unit type counts - for (int n = 0; n < 32; n++) - table_deinit (&is->unit_type_counts[n]); - is->unit_type_count_init_bits = 0; - - // Clear last city founding turn numbers - for (int n = 0; n < 32; n++) - is->turn_no_of_last_founding_for_settler_perfume[n] = -1; - - // Load resources.pcx - { - PCX_Image * rs = is->resources_sheet; - if (rs != NULL) - rs->vtable->destruct (rs, __, 0); - else - rs = malloc (sizeof *rs); - memset (rs, 0, sizeof *rs); - PCX_Image_construct (rs); - - char * resources_pcx_path = BIC_get_asset_path (p_bic_data, __, "Art\\resources.pcx", true); - PCX_Image_read_file (rs, __, resources_pcx_path, NULL, 0, 0x100, 2); - is->resources_sheet = rs; - } - - // Recreate table of alt strategies mapping duplicates to their strategies - table_deinit (&is->unit_type_alt_strategies); - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; - if (alt_for_id >= 0) { - record_unit_type_alt_strategy (n); - record_unit_type_alt_strategy (alt_for_id); // Record the original too so we know it has alternatives - } - } - - // Recreate table of duplicates mapping unit types to the next duplicate - table_deinit (&is->unit_type_duplicates); - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; - if (alt_for_id >= 0) { - - // Find the type ID of the last duplicate in the list. alt_for_id refers to the original unit that was duplicated possibly - // multiple times. Begin searching there and, each time we find another duplicate, use its ID to continue the search. When - // we're done last_dup_id will be set to whichever ID in the list of duplicates is not already associated with another. - int last_dup_id = alt_for_id; { - int next; - while (itable_look_up (&is->unit_type_duplicates, last_dup_id, &next)) - last_dup_id = next; - } - - // Add this unit type to the end of the list of duplicates - itable_insert (&is->unit_type_duplicates, last_dup_id, n); - } - } - - // Convert charm-flagged units to using PTW targeting if necessary - if (is->current_config.charm_flag_triggers_ptw_like_targeting) { - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if (type->Special_Actions & UCV_Charm_Bombard) { - // Also add it to the list of converted types - reserve (sizeof is->charmed_types_converted_to_ptw_arty[0], // item size - (void **)&is->charmed_types_converted_to_ptw_arty, // ptr to items - &is->charmed_types_converted_to_ptw_arty_capacity, // ptr to capacity - is->count_charmed_types_converted_to_ptw_arty); // count - is->charmed_types_converted_to_ptw_arty[is->count_charmed_types_converted_to_ptw_arty] = n; - is->count_charmed_types_converted_to_ptw_arty += 1; - - // Add this type ID to the table - itable_insert (&is->current_config.ptw_arty_types, n, 1); - - // Clear the charm flag, taking care not to clear the category bit. This is necessary for the PTW targeting to work - // since the logic to implement it only applies to the non-charm code path. It wouldn't make sense to have both charm - // attack and PTW targeting anyway, since charm attack already works that way vs cities. - type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); - } - } - } - - // Pick out which resources are used as mill inputs - if (is->mill_input_resource_bits) - free (is->mill_input_resource_bits); - is->mill_input_resource_bits = calloc (1, 1 + p_bic_data->ResourceTypeCount / 8); - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - for (int k = 0; k < 2; k++) { - int resource_id = (&p_bic_data->Improvements[mill->improv_id].Resource1ID)[k]; - if ((resource_id >= 0) && (resource_id < p_bic_data->ResourceTypeCount)) { - byte bit = 1 << (resource_id & 7); - is->mill_input_resource_bits[resource_id>>3] |= bit; - } - } - } - - // Recreate lists of water & air trade improvements - is->water_trade_improvs .count = 0; - is->air_trade_improvs .count = 0; - is->combat_defense_improvs.count = 0; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - enum ImprovementTypeFlags flags = p_bic_data->Improvements[n].ImprovementFlags; - if (flags & ITF_Allows_Water_Trade) append_improv_id_to_list (&is->water_trade_improvs , n); - if (flags & ITF_Allows_Air_Trade) append_improv_id_to_list (&is->air_trade_improvs , n); - if (p_bic_data->Improvements[n].Combat_Defence != 0) append_improv_id_to_list (&is->combat_defense_improvs, n); - } - - // Set up for limiting railroad movement - if (is->current_config.limit_railroad_movement > 0) { - // Bit 0x200 of field_484 indicates whether or not the last call to load_scenario loaded the General section of the BIQ. The game will - // skip loading of that section and many others when loading a game with the same standard scenario as the then-current one, common - // when loading an autosave. - bool loaded_general = (this->field_848 & 0x200) != 0; - - // For the base RMR, use the saved rate if it's valid and we haven't loaded a new rate as part of the General section. Otherwise, use - // the rate from that section. - int base_rmr = (loaded_general || is->saved_road_movement_rate <= 0) ? p_bic_data->General.RoadsMovementRate : is->saved_road_movement_rate; - - int g = gcd (base_rmr, is->current_config.limit_railroad_movement); // Scale down all MP costs by this common divisor to help against - // overflow of 8-bit integers inside the pathfinder. - is->saved_road_movement_rate = base_rmr; - p_bic_data->General.RoadsMovementRate = base_rmr * is->current_config.limit_railroad_movement / g; // Full move in MP - is->road_mp_cost = is->current_config.limit_railroad_movement / g; - is->railroad_mp_cost_per_move = base_rmr / g; - } else { - is->saved_road_movement_rate = -1; - is->road_mp_cost = 1; - is->railroad_mp_cost_per_move = 0; - } - - // If barb city capturing is enabled and the barbs have the non-existent "none" culture group (index -1), switch them to the first real - // culture group. The "none" group produces corrupt graphics and crashes. - int * barb_culture_group = &p_bic_data->Races[leaders[0].RaceID].CultureGroupID; - if (is->current_config.enable_city_capture_by_barbarians && (*barb_culture_group < 0)) { - is->saved_barb_culture_group = *barb_culture_group; - *barb_culture_group = 0; - } else - is->saved_barb_culture_group = -1; - - // Clear old alias bits - is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; - - // Apply no AI patrol override - if (is->current_config.override_no_ai_patrol == NAPO_ZERO) - *p_allow_ai_patrol = true; - else if (is->current_config.override_no_ai_patrol == NAPO_ONE) - *p_allow_ai_patrol = false; - else if (is->current_config.override_no_ai_patrol == NAPO_NONE) - *p_allow_ai_patrol = 0 == get_int_from_conquests_ini ("NoAIPatrol", 1, 0); - - // Clear day/night cycle vars and deindex sprite proxies, if necessary. - if (is->current_config.day_night_cycle_mode != DNCM_OFF) { - is->day_night_cycle_unstarted = true; - is->current_day_night_cycle = 12; - if (is->day_night_cycle_img_proxies_indexed) { - deindex_day_night_image_proxies (); - } - } - - return tr; -} - -void __fastcall -patch_Leader_recompute_auto_improvements (Leader * this) -{ - is->leader_param_for_patch_get_wonder_city_id = this; - Leader_recompute_auto_improvements (this); -} - -int __fastcall -patch_Game_get_wonder_city_id (Game * this, int edx, int wonder_improvement_id) -{ - int ret_addr = ((int *)&wonder_improvement_id)[-1]; - if ((is->current_config.enable_free_buildings_from_small_wonders) && (ret_addr == ADDR_SMALL_WONDER_FREE_IMPROVS_RETURN)) { - Leader * leader = is->leader_param_for_patch_get_wonder_city_id; - Improvement * improv = &p_bic_data->Improvements[wonder_improvement_id]; - if ((improv->Characteristics & ITC_Small_Wonder) != 0) { - // Need to check if Small_Wonders array is NULL b/c recompute_auto_improvements gets called with leaders that are absent/dead. - return (leader->Small_Wonders != NULL) ? leader->Small_Wonders[wonder_improvement_id] : -1; - } - } - return Game_get_wonder_city_id (this, __, wonder_improvement_id); -} - -int __fastcall -patch_Main_Screen_Form_handle_key_up (Main_Screen_Form * this, int edx, int virtual_key_code) -{ - if ((virtual_key_code & 0xFF) == VK_CONTROL) { - patch_Main_GUI_set_up_unit_command_buttons (&this->GUI); - - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - } - - return Main_Screen_Form_handle_key_up (this, __, virtual_key_code); -} - -char __fastcall -patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing) -{ - char tr; - bool is_ai = ((*p_human_player_bits & (1 << this->ID)) == 0); - bool skip_replacement_logic = - (p_main_screen_form->Player_CivID == this->ID) && is->current_config.skip_repeated_tile_improv_replacement_asks; - - Tile * tile = tile_at (tile_x, tile_y); - - // If districts on, short-circuit any potential AI workers accidentally building in another civ's territory. - if (is->current_config.enable_districts && is_ai && (tile != NULL) && (tile != p_null_tile)) { - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (territory_owner > 0 && territory_owner != this->ID) - return 0; - } - - // Check if AI is trying to change a district tile (before calling vanilla logic) - if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && - is_ai) { - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { - int district_id = inst->district_id; - bool allow_ai_change = false; - - // Allow AI to modify obsolete districts - if (district_is_obsolete_for_civ (district_id, this->ID)) - allow_ai_change = true; - - // Allow if district could be used as a prerequisite for other buildable districts - if (! allow_ai_change) { - for (int other_id = 0; other_id < is->district_count; other_id++) { - if (other_id == district_id) - continue; - struct district_config const * other_cfg = &is->district_configs[other_id]; - if (! other_cfg->has_buildable_on_districts) - continue; - for (int i = 0; i < other_cfg->buildable_on_district_id_count; i++) { - if (other_cfg->buildable_on_district_ids[i] == district_id) { - if (leader_can_build_district (this, other_id)) - allow_ai_change = true; - break; - } - } - if (allow_ai_change) - break; - } - } - - // Allow AI to build roads/rails on bridge districts - if (! allow_ai_change && (district_id == BRIDGE_DISTRICT_ID) && - (job == WJ_Build_Road || job == WJ_Build_Railroad)) - allow_ai_change = true; - - // For Wonder Districts: check if unused (can be replaced) - if (! allow_ai_change && is->current_config.enable_wonder_districts && (district_id == WONDER_DISTRICT_ID)) { - struct wonder_district_info * info = get_wonder_district_info (tile); - - // If there's a reservation (wonder being built) or completed wonder, block replacement - if (info != NULL && info->state != WDS_UNUSED) - return 0; - - // Wonder district is unused - fall through to normal tech checks - } - else if (! allow_ai_change && is->current_config.enable_natural_wonders && (district_id == NATURAL_WONDER_DISTRICT_ID)) { - return 0; - } - else if (! allow_ai_change) { - // For all other district types: AI should not change them - return 0; - } - } - } - } - - if (! skip_replacement_logic) - tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); - else if (is->have_job_and_loc_to_skip && - (is->to_skip.job == job) && (is->to_skip.tile_x == tile_x) && (is->to_skip.tile_y == tile_y)) - tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, 0); - else { - is->show_popup_was_called = 0; - tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); - if (is->show_popup_was_called && tr) { // Check that the popup was shown and the player chose to replace - is->to_skip = (struct worker_job_and_location) { .job = job, .tile_x = tile_x, .tile_y = tile_y }; - is->have_job_and_loc_to_skip = 1; - } - } - - if (! tr && is->current_config.enable_districts && (job == WJ_Build_Mines)) { - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && - inst->district_id >= 0 && inst->district_id < is->district_count && - ! tile->vtable->m35_Check_Is_Water (tile) && - (tile->CityID < 0) && - ! tile->vtable->m18_Check_Mines (tile, __, 0)) { - int tile_x = 0, tile_y = 0; - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - int owner_civ = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_civ == this->ID) || (owner_civ == 0)) { - if (leader_can_build_district (this, inst->district_id) && - district_resource_prereqs_met (tile, tile_x, tile_y, inst->district_id)) - tr = 1; - } - } - } - } - - if (! tr && is->current_config.enable_districts && is->current_config.enable_bridge_districts && - (job == WJ_Build_Road || job == WJ_Build_Railroad)) { - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - if (job == WJ_Build_Road) { - if (! has_road) - tr = 1; - } else { - bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; - if (has_road && ! has_rail) { - int req_tech = p_bic_data->WorkerJobs[job].RequireID; - if ((req_tech < 0) || - ((req_tech != p_bic_data->AdvanceCount) && - Leader_has_tech (&leaders[this->ID], __, req_tech))) { - if (Leader_has_resources_for_job_at (&leaders[this->ID], __, job, tile_x, tile_y)) - tr = 1; - } - } - } - } - } - } - - return tr; -} - -bool __fastcall -patch_Unit_can_hurry_production (Unit * this, int edx, City * city, bool exclude_cheap_improvements) -{ - if (is->current_config.allow_military_leaders_to_hurry_wonders && Unit_has_ability (this, __, UTA_Leader)) { - LeaderKind actual_kind = this->Body.leader_kind; - this->Body.leader_kind = LK_Scientific; - bool tr = Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); - this->Body.leader_kind = actual_kind; - return tr; - } else - return Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); -} - -bool __fastcall -patch_Unit_can_load (Unit * this, int edx, Unit * passenger) -{ - is->can_load_transport = this; - is->can_load_passenger = passenger; - bool tr; - - // If this potential passenger is tied to a different transport, do not allow it to load into this one - int tied_transport_id = -1; - if (is->current_config.limit_unit_loading_to_one_transport_per_turn && - (! Unit_has_ability (this, __, UTA_Army)) && - itable_look_up (&is->unit_transport_ties, passenger->Body.ID, &tied_transport_id) && - (this->Body.ID != tied_transport_id)) - tr = false; - - else - tr = Unit_can_load (this, __, passenger); - - is->can_load_transport = is->can_load_passenger = NULL; - return tr; -} - -void __fastcall -patch_Unit_load (Unit * this, int edx, Unit * transport) -{ - Unit_load (this, __, transport); - - // Tie the unit to the transport if configured to do so - if (is->current_config.limit_unit_loading_to_one_transport_per_turn && ! Unit_has_ability (transport, __, UTA_Army)) - itable_insert (&is->unit_transport_ties, this->Body.ID, transport->Body.ID); -} - -bool -any_enemies_near (Leader const * me, int tile_x, int tile_y, enum UnitTypeClasses class, int num_tiles) -{ - bool tr = false; - FOR_TILES_AROUND (tai, num_tiles, tile_x, tile_y) { - int enemy_on_this_tile = 0; - FOR_UNITS_ON (uti, tai.tile) { - UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; - if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0) && - (((int)class < 0) || (unit_type->Unit_Class == class))) { - if (me->At_War[uti.unit->Body.CivID]) { - if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { - enemy_on_this_tile = 1; - break; - } - } else - break; - } - } - if (enemy_on_this_tile) { - tr = true; - break; - } - } - return tr; -} - -bool -any_enemies_near_unit (Unit * unit, int num_tiles) -{ - UnitType * unit_type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - return any_enemies_near (&leaders[unit->Body.CivID], unit->Body.X, unit->Body.Y, unit_type->Unit_Class, num_tiles); -} - -void __fastcall -patch_Unit_ai_move_artillery (Unit * this) -{ - if ((! is->current_config.use_offensive_artillery_ai) || - ((this->Body.UnitTypeID < 0) || (this->Body.UnitTypeID >= p_bic_data->UnitTypeCount))) // Check for invalid unit type id which appears sometimes, IDK why - goto base_impl; - - Tile * on_tile = tile_at (this->Body.X, this->Body.Y); - City * in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); - UnitType const * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - int num_escorters_req = this->vtable->eval_escort_requirement (this); - - if ((in_city == NULL) || (count_escorters (this) >= num_escorters_req)) - goto base_impl; - - // Don't assign escort if there are any enemies around because in that case it might be a serious mistake to take a defender out of the city - if (any_enemies_near_unit (this, 37)) - goto base_impl; - - // Find the strongest healthy defender the city has and assign that unit as an escort but make sure doing so doesn't leave the city - // defenseless. I think picking the strongest defender is the right choice here because the artillery pair is more likely to come under - // attack than a city and also leaving obsolete units in the city gives them a chance to upgrade. - int num_defenders = 0; - Unit * best_defender = NULL; - int best_defender_strength = -1; - FOR_UNITS_ON (uti, on_tile) { - Unit_Body * body = &uti.unit->Body; - UnitType * type = &p_bic_data->UnitTypes[body->UnitTypeID]; - if ((type->AI_Strategy & UTAI_Defence) && - (! UnitType_has_ability (type, __, UTA_Immobile)) && - (body->Damage == 0) && - ((body->UnitState == 0) || (body->UnitState == UnitState_Fortifying)) && - (body->escortee < 0)) { - num_defenders++; - int str = type->Defence * Unit_get_max_hp (uti.unit); - if (str > best_defender_strength) { - best_defender = uti.unit; - best_defender_strength = str; - } - } - } - if ((num_defenders >= 2) && (best_defender != NULL)) { - Unit_set_state (best_defender, __, 0); - Unit_set_escortee (best_defender, __, this->Body.ID); - } - -base_impl: - Unit_ai_move_artillery (this); - - // Recompute these since the unit might have moved - on_tile = tile_at (this->Body.X, this->Body.Y); - in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); - - // Load the unit into a transport for a naval invasion if it's just sitting in a city with nothing else to do - if (is->current_config.use_offensive_artillery_ai && - (in_city != NULL) && - (this->Body.Moves == 0) && - (this->Body.UnitState == UnitState_Fortifying) && - (this->Body.Container_Unit < 0)) { - Unit * transport = Unit_find_transport (this, __, this->Body.X, this->Body.Y); - if (transport != NULL) { - - int transport_capacity = p_bic_data->UnitTypes[transport->Body.UnitTypeID].Transport_Capacity; - int units_in_transport, arty_in_transport; { - units_in_transport = arty_in_transport = 0; - FOR_UNITS_ON (uti, on_tile) - if (uti.unit->Body.Container_Unit == transport->Body.ID) { - units_in_transport++; - arty_in_transport += (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].AI_Strategy & UTAI_Artillery) != 0; - } - } - - // Check that there's space for the arty unit and an escort, and that the transport does not have more than one arty per three - // spaces so we're less likely to assemble invasion forces composed of nothing but artillery. - if ((units_in_transport + 2 <= transport_capacity) && - (arty_in_transport < not_below (1, transport_capacity / 3))) { - Unit_set_escortee (this, __, -1); - patch_Unit_load (this, __, transport); - } - } - } -} - -// Estimates the number of turns necessary to move the given unit to the given tile and writes it to *out_num_turns. Returns 0 if there is no path -// from the unit's current position to the given tile, 1 otherwise. -int -estimate_travel_time (Unit * unit, int to_tile_x, int to_tile_y, int * out_num_turns) -{ - int dist_in_mp; - patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, to_tile_x, to_tile_y, unit, unit->Body.CivID, 1, &dist_in_mp); - dist_in_mp += unit->Body.Moves; // Add MP already spent this turn to the distance - int max_mp = patch_Unit_get_max_move_points (unit); - if ((dist_in_mp >= 0) && (max_mp > 0)) { - *out_num_turns = dist_in_mp / max_mp; - return 1; - } else - return 0; // No path or unit cannot move -} - -City * -find_nearest_established_city (Unit * unit, int continent_id) -{ - int lowest_unattractiveness = INT_MAX; - City * least_unattractive_city = NULL; - FOR_CITIES_OF (coi,unit->Body.CivID) { - Tile * city_tile = tile_at (coi.city->Body.X, coi.city->Body.Y); - if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { - int dist_in_turns; - if (! estimate_travel_time (unit, coi.city->Body.X, coi.city->Body.Y, &dist_in_turns)) - continue; - int unattractiveness = 10 * dist_in_turns; - unattractiveness = (10 + unattractiveness) / (10 + coi.city->Body.Population.Size); - if (coi.city->Body.CultureIncome > 0) - unattractiveness /= 5; - if (unattractiveness < lowest_unattractiveness) { - lowest_unattractiveness = unattractiveness; - least_unattractive_city = coi.city; - } - } - } - return least_unattractive_city; -} - -bool __fastcall -patch_Unit_ai_can_form_army (Unit * this) -{ - int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.patch_ai_can_form_army_without_special_ability && ((type->Special_Actions & build_army_action) == 0)) - return false; - else - return Unit_ai_can_form_army (this); -} - -void __fastcall -patch_Unit_ai_move_leader (Unit * this) -{ - if (! is->current_config.replace_leader_unit_ai) { - Unit_ai_move_leader (this); - return; - } - - Tile * tile = tile_at (this->Body.X, this->Body.Y); - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - - // Disband the unit if it's on a continent with no cities of its civ. This is what the original logic does. - if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { - Unit_disband (this); - return; - } - - // Flee if the unit is near an enemy without adequate escort - int has_adequate_escort; { - int escorter_count = 0; - int any_healthy_escorters = 0; - int index; - for (int escorter_id = Unit_next_escorter_id (this, __, &index, true); escorter_id >= 0; escorter_id = Unit_next_escorter_id (this, __, &index, false)) { - Unit * escorter = get_unit_ptr (escorter_id); - if ((escorter != NULL) && (escorter->Body.X == this->Body.X) && (escorter->Body.Y == this->Body.Y)) { - escorter_count++; - int remaining_health = Unit_get_max_hp (escorter) - escorter->Body.Damage; - any_healthy_escorters |= (remaining_health >= 3) || (escorter->Body.Damage == 0); - } - } - has_adequate_escort = (escorter_count > 0) && any_healthy_escorters; - } - if ((! has_adequate_escort) && any_enemies_near_unit (this, 49)) { - Unit_set_state (this, __, UnitState_Fleeing); - bool done = this->vtable->work (this); - if (done || (this->Body.UnitState != 0)) - return; - } - - // Move along path if the unit already has one set - byte next_move = Unit_pop_next_move_from_path (this); - if (next_move > 0) { - this->vtable->Move (this, __, next_move, 0); - return; - } - - // Start a science age if we can - // It would be nice to compute a value for this and compare it to the option of rushing production but it's hard to come up with a valuation - if (is->current_config.patch_science_age_bug && Unit_ai_can_start_science_age (this)) { - Unit_start_science_age (this); - return; - } - - // Estimate the value of creating an army. First test if that's even a possiblity and if not leave the value at -1 so rushing production is - // always preferable (note we can't use Unit_ai_can_form_army for this b/c it returns false for units not in a city). The value of forming - // an army is "infinite" if we don't already have one and otherwise it depends on the army unit's shield cost +/- 25% for each point of - // aggression divided by the number of armies already in the field. - int num_armies = leaders[this->Body.CivID].Armies_Count; - int form_army_value = -1; - int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits - if ((this->Body.leader_kind & LK_Military) && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & build_army_action) && - ((num_armies + 1) * p_bic_data->General.ArmySupportCities <= leaders[this->Body.CivID].Cities_Count) && - (p_bic_data->General.BuildArmyUnitID >= 0) && - (p_bic_data->General.BuildArmyUnitID < p_bic_data->UnitTypeCount)) { - if (num_armies < 1) - form_army_value = INT_MAX; - else { - form_army_value = p_bic_data->UnitTypes[p_bic_data->General.BuildArmyUnitID].Cost; - int aggression_level = p_bic_data->Races[leaders[this->Body.CivID].RaceID].AggressionLevel; // aggression level varies between -2 and +2 - form_army_value = (form_army_value * (4 + aggression_level)) / 4; - if (num_armies > 1) - form_army_value /= num_armies; - } - } - - // Estimate the value of rushing production in every city on this continent and remember the highest one - City * best_rush_loc = NULL; - int best_rush_value = -1; - FOR_CITIES_OF (coi, this->Body.CivID) { - City * city = coi.city; - Tile * city_tile = tile_at (city->Body.X, city->Body.Y); - if ((continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) && - patch_Unit_can_hurry_production (this, __, city, false)) { - // Base value is equal to the number of shields rushing would save - int value = City_get_order_cost (city) - City_get_order_progress (city) - city->Body.ProductionIncome; - if (value <= 0) - continue; - - // Consider distance: Reduce the value by the number of shields produced while the leader is en route to rush. - int dist_in_turns; - if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) - continue; // no path or unit cannot move - value -= dist_in_turns * city->Body.ProductionIncome; - if (value <= 0) - continue; - - // Consider corruption: Scale down the value of rushing an improvement by the corruption rate of the city. - // This is to reflect the fact that infrastructure is more valuable in less corrupt cities. But do not apply - // this to wonders since their benefit is in most cases not lessened by local corruption. - Improvement * improv = (city->Body.Order_Type == COT_Improvement) ? &p_bic_data->Improvements[city->Body.Order_ID] : NULL; - int is_wonder = (improv != NULL) && (0 != (improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder))); - if ((improv != NULL) && (! is_wonder)) { - int good_shields = city->Body.ProductionIncome; - int corrupt_shields = city->Body.ProductionLoss; - if (good_shields + corrupt_shields > 0) - value = (value * good_shields) / (good_shields + corrupt_shields); - else - continue; - } - - if ((value > 0) && (value > best_rush_value)) { - best_rush_loc = city; - best_rush_value = value; - } - } - } - - // Hurry production or form an army depending on the estimated values of doing so. We might have to move to a (different) city if that's where - // we want to rush production or if we want to form an army but aren't already in a city. - City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); - City * moving_to_city = NULL; - if ((best_rush_loc != NULL) && (best_rush_value > form_army_value)) { - if (best_rush_loc == in_city) { - Unit_hurry_production (this); - return; - } else - moving_to_city = best_rush_loc; - } else if ((form_army_value > -1) && patch_Unit_ai_can_form_army (this)) { - Unit_form_army (this); - return; - } else if (in_city == NULL) { - // Nothing to do. Try to find a close, established city to move to & wait in. - moving_to_city = find_nearest_established_city (this, continent_id); - } - if (moving_to_city) { - int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); - if (first_move > 0) { - Unit_set_escortee (this, __, -1); - this->vtable->Move (this, __, first_move, 0); - return; - } - } - - // Nothing to do, nowhere to go, just fortify in place. - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -int -measure_strength_in_army (UnitType * type) -{ - return ((type->Attack + type->Defence) * (4 + type->Hit_Point_Bonus)) / 4; -} - -bool __fastcall -patch_impl_ai_is_good_army_addition (Unit * this, int edx, Unit * candidate) -{ - if (! is->current_config.fix_ai_army_composition) - return impl_ai_is_good_army_addition (this, __, candidate); - - UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - if (((candidate_type->AI_Strategy & UTAI_Offence) == 0) || - UnitType_has_ability (candidate_type, __, UTA_Hidden_Nationality)) - return false; - - int num_units_in_army = 0, - army_min_speed = INT_MAX, - army_min_strength = INT_MAX; - FOR_UNITS_ON (uti, tile) { - if (uti.unit->Body.Container_Unit == this->Body.ID) { - num_units_in_army++; - int movement = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Movement; - if (movement < army_min_speed) - army_min_speed = movement; - int member_strength = measure_strength_in_army (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]); - if (member_strength < army_min_strength) - army_min_strength = member_strength; - } - } - - return (num_units_in_army == 0) || - ((candidate_type->Movement >= army_min_speed) && - (measure_strength_in_army (candidate_type) >= army_min_strength)); -} - -int -rate_artillery (UnitType * type) -{ - int tr = type->Attack + type->Defence + 2 * type->Bombard_Strength * type->FireRate; - - // include movement - int moves = type->Movement; - if (moves >= 2) - tr = tr * (moves + 1) / 2; - - // include range - int range = type->Bombard_Range; - if (range >= 2) - tr = tr * (range + 1) / 2; - - // include extra hp - if (type->Hit_Point_Bonus > 0) - tr = tr * (4 + type->Hit_Point_Bonus) / 4; - - return tr; -} - -int -rate_bomber (UnitType * type) -{ - int tr = type->Bombard_Strength * type->FireRate + type->Defence; - - // include range - tr = tr * (10 + type->OperationalRange) / 10; - - // include cost - tr = (tr * 100) / (100 + type->Cost); - - // include abilities - if (UnitType_has_ability (type, __, UTA_Blitz)) - tr = tr * (type->Movement + 1) / 2; - if (UnitType_has_ability (type, __, UTA_Lethal_Land_Bombardment)) - tr = tr * 3 / 2; - if (UnitType_has_ability (type, __, UTA_Lethal_Sea_Bombardment)) - tr = tr * 5 / 4; - if (UnitType_has_ability (type, __, UTA_Stealth)) - tr = tr * 3 / 2; - - // include extra hp - if (type->Hit_Point_Bonus > 0) - tr = tr * (4 + type->Hit_Point_Bonus) / 4; - - return tr; -} - -bool __fastcall -patch_City_can_build_unit (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) -{ - bool base = City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); - - if (base) { - // Apply building prereqs - int building_prereq; - if (itable_look_up (&is->current_config.building_unit_prereqs, unit_type_id, &building_prereq)) { - // If the prereq is an encoded building ID - if (building_prereq & 1) { - if (! has_active_building (this, building_prereq >> 1)) - return false; - - // Else it's a pointer to a list of building IDs - } else { - int * list = (int *)building_prereq; - for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) - if ((list[n] >= 0) && ! has_active_building (this, list[n])) - return false; - } - } - - // Apply unit type limit - int available; - if (get_available_unit_count (&leaders[this->Body.CivID], unit_type_id, &available) && (available <= 0)) - return false; - } - - if (is->current_config.enable_districts) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - - // Bail if tech reqs are not met - int prereq_id = type->AdvReq; - if (prereq_id >= 0 && ! Leader_has_tech (&leaders[this->Body.CivID], __, prereq_id)) - return false; - - if (! Leader_can_build_unit (&leaders[this->Body.CivID], __, unit_type_id, 1, false)) - return false; - - // Superficially allow the AI to choose the unit for scoring and production. - // If a disallowed air/naval unit is chosen in ai_choose_production, we'll swap it out for a feasible fallback later - // after prioritizing the aerodrome/port to be built - if (! is_human && ( - (type->Unit_Class == UTC_Air || city_can_build_district (this, AERODROME_DISTRICT_ID)) || - (type->Unit_Class == UTC_Sea || city_can_build_district (this, PORT_DISTRICT_ID))) - ) - return base; - - // Air units - if (type->Unit_Class == UTC_Air) { - if (is->current_config.enable_aerodrome_districts && is->current_config.air_units_use_aerodrome_districts_not_cities) { - if (find_pending_district_request (this, AERODROME_DISTRICT_ID) != NULL) - return false; - if (! city_can_build_district (this, AERODROME_DISTRICT_ID)) - return false; - return city_has_required_district (this, AERODROME_DISTRICT_ID); - } - // Naval units - } else if (type->Unit_Class == UTC_Sea) { - if (is->current_config.enable_port_districts && is->current_config.naval_units_use_port_districts_not_cities) { - if (find_pending_district_request (this, PORT_DISTRICT_ID) != NULL) - return false; - if (! city_can_build_district (this, PORT_DISTRICT_ID)) - return false; - return city_has_required_district (this, PORT_DISTRICT_ID); - } - } - } - - return base; -} - -int __fastcall -patch_City_get_largest_adjacent_sea_within_work_area (City * this) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - int improv_id = is->current_evaluating_improve_id; - if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { - - // If Coastal Fortress, default to original logic (city must be next to coast) - if (p_bic_data->Improvements[improv_id].Naval_Bombard_Defence > 0) - return City_get_largest_adjacent_sea (this); - } - int lake_size_threshold = 21; - int largest_size = 0; - int largest_continent_id = -1; - FOR_WORK_AREA_AROUND (wai, this->Body.X, this->Body.Y) { - if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { - int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - if (continent->Body.TileCount <= lake_size_threshold && ! is->current_config.enable_canal_districts) - continue; - if (p_bic_data->Map.Continents[continent_id].Body.TileCount > largest_size) { - largest_size = p_bic_data->Map.Continents[continent_id].Body.TileCount; - largest_continent_id = continent_id; - } - } - } - return largest_continent_id; - } - return City_get_largest_adjacent_sea (this); -} - -bool __fastcall -patch_Map_impl_is_near_river_within_work_area (Map * this, int edx, int x, int y, int num_tiles) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - FOR_WORK_AREA_AROUND (wai, x, y) { - if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) { - return true; - } - } - return false; - } - - return this->vtable->is_near_river (this, __, x, y, num_tiles); -} - -bool __fastcall -patch_Map_impl_is_near_lake_within_work_area (Map * this, int edx, int x, int y, int num_tiles) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - int lake_size_threshold = 21; - FOR_WORK_AREA_AROUND (wai, x, y) { - if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { - int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - if (continent->Body.TileCount <= lake_size_threshold) - return true; - } - } - return false; - } - - return this->vtable->is_near_lake (this, __, x, y, num_tiles); -} - -bool __fastcall -patch_Map_impl_has_fresh_water_within_work_area (Map * this, int edx, int tile_x, int tile_y) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - int improv_id = is->current_evaluating_improve_id; - if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { - - // If an Aqueduct, default to original logic (city must be next to coast) - if ((p_bic_data->Improvements[improv_id].ImprovementFlags & ITF_Allows_City_Level_2) != 0) - return this->vtable->has_fresh_water (this, __, tile_x, tile_y); - } - if (patch_Map_impl_is_near_river_within_work_area (this, __, tile_x, tile_y, 1)) - return true; - if (patch_Map_impl_is_near_lake_within_work_area (this, __, tile_x, tile_y, 1)) - return true; - return false; - } - - return this->vtable->has_fresh_water (this, __, tile_x, tile_y); -} - -bool -city_meets_district_prereqs_to_build_improvement (City * city, int i_improv, bool apply_strict_rules) -{ - // Different logic for human vs AI players - bool is_human = (*p_human_player_bits & (1 << city->Body.CivID)) != 0; - - Improvement * improv = &p_bic_data->Improvements[i_improv]; - bool is_wonder = is->current_config.enable_wonder_districts && (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)); - if (is_wonder && ! wonder_is_buildable_by_civ (i_improv, city->Body.CivID)) - return false; - - bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; - - // Check if the improvement requires a district - bool needs_district = city_requires_district_for_improvement (city, i_improv, NULL); - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); - - // District is either not needed or already built - if (! needs_district) - return true; - - if (prereq_list == NULL) - return false; - - bool has_buildable_candidate = false; - bool has_wonder_candidate = false; - bool has_non_wonder_candidate = false; - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) - continue; - has_buildable_candidate = true; - if (district_id == WONDER_DISTRICT_ID) - has_wonder_candidate = true; - else - has_non_wonder_candidate = true; - } - if (! has_buildable_candidate) - return false; - - // Check that we have the necessary terrain - bool has_terrain_for_district = false; - bool has_terrain_for_wonder = false; - bool has_river_terrain_for_district = false; - FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { - Tile * tile = wai.tile; - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) - continue; - if (! tile_suitable_for_district (tile, district_id, city, NULL)) - continue; - - if (is_wonder && district_id == WONDER_DISTRICT_ID) { - if (! wonder_is_buildable_on_tile (tile, i_improv)) - continue; - } - - has_terrain_for_district = true; - if (requires_river && tile->vtable->m37_Get_River_Code (tile) != 0) - has_river_terrain_for_district = true; - - if (is_wonder && district_id == WONDER_DISTRICT_ID) { - if (! requires_river || tile->vtable->m37_Get_River_Code (tile) != 0) { - has_terrain_for_wonder = true; - } - } - } - } - - bool requires_wonder_terrain = is_wonder && has_wonder_candidate && ! has_non_wonder_candidate; - if (! has_terrain_for_district || - (requires_river && ! has_river_terrain_for_district) || - (requires_wonder_terrain && ! has_terrain_for_wonder)) { - return false; - } - - // If human has everything needed except a built district (which is buildable), allow relaxed checks so UI can gray entry out - if (is_human) { - return ! apply_strict_rules; - } - - // If AI already has a pending district request for this required district, return false - // to prevent wasting a turn trying to choose this improvement - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - if (find_pending_district_request (city, district_id) != NULL) - return false; - } - - // Superficially allow the AI to choose the improvement for scoring and production. - // If a disallowed improvement is chosen in ai_choose_production, we'll swap it out for a feasible fallback later - // after prioritizing the district to be built - return true; -} - -bool __fastcall -patch_City_can_build_improvement (City * this, int edx, int i_improv, bool apply_strict_rules) -{ - is->current_evaluating_improve_id = i_improv; - - char ss[200]; - snprintf (ss, sizeof ss, "patch_City_can_build_improvement:evaluating improvement %s (%d)\n", - p_bic_data->Improvements[i_improv].Name.S, i_improv); - (*p_OutputDebugStringA) (ss); - - // First defer to the base game's logic - bool base = City_can_build_improvement (this, __, i_improv, apply_strict_rules); - if (! base) return false; - if (! is->current_config.enable_districts) return base; - - bool can_build = city_meets_district_prereqs_to_build_improvement (this, i_improv, apply_strict_rules); - is->current_evaluating_improve_id = -1; - - return can_build; -} - -bool -ai_handle_district_production_requirements (City * city, City_Order * out) -{ - clear_best_feasible_order (city); - bool swapped_to_fallback = false; - City_Order fallback_order = {0}; - int required_district_id = -1; - bool should_mark_district = false; - - char ss[200]; - - if (is->current_config.enable_districts && - (out->OrderID >= 0)) { - bool needs_wonder_district = false; - bool requires_district = false; - bool needs_district = false; - - if ((out->OrderType == COT_Unit) && - (out->OrderID < p_bic_data->UnitTypeCount)) { - UnitType * type = &p_bic_data->UnitTypes[out->OrderID]; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { - required_district_id = AERODROME_DISTRICT_ID; - needs_district = true; - should_mark_district = true; - } else if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (city, PORT_DISTRICT_ID))) { - required_district_id = PORT_DISTRICT_ID; - needs_district = true; - should_mark_district = true; - } - } else if ((out->OrderType == COT_Improvement) && - (out->OrderID < p_bic_data->ImprovementsCount)) { - // Check if AI is trying to build a wonder without an incomplete wonder district - requires_district = city_requires_district_for_improvement (city, out->OrderID, &required_district_id); - if (is->current_config.enable_wonder_districts) { - Improvement * improv = &p_bic_data->Improvements[out->OrderID]; - if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && - (! city_has_wonder_district_with_no_completed_wonder (city, out->OrderID))) { - snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: City %d (%s) needs wonder district to build wonder improvement %d\n", - city->Body.ID, city->Body.CityName, out->OrderID); - (*p_OutputDebugStringA) (ss); - needs_wonder_district = true; - if (required_district_id < 0) { - required_district_id = WONDER_DISTRICT_ID; - } - } - } - needs_district = needs_wonder_district || requires_district; - } - - if (needs_district) { - struct ai_best_feasible_order * stored = get_best_feasible_order (city); - if (stored != NULL) { - bool fallback_is_feasible = true; - if (stored->order.OrderType == COT_Improvement) { - if ((stored->order.OrderID < 0) || - (stored->order.OrderID >= p_bic_data->ImprovementsCount)) - fallback_is_feasible = false; - - // Check if fallback requires a district the city doesn't have - if (fallback_is_feasible && - city_requires_district_for_improvement (city, stored->order.OrderID, NULL)) - fallback_is_feasible = false; - - // If original order was a wonder, ensure fallback is not also a wonder - if (fallback_is_feasible && needs_wonder_district) { - Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; - if (fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - fallback_is_feasible = false; - } - - // If fallback is a wonder, check if it has an incomplete wonder district - if (fallback_is_feasible && is->current_config.enable_wonder_districts) { - Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; - if ((fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && - (! city_has_wonder_district_with_no_completed_wonder (city, stored->order.OrderID))) - fallback_is_feasible = false; - } - } else if (stored->order.OrderType == COT_Unit) { - if ((stored->order.OrderID < 0) || - (stored->order.OrderID >= p_bic_data->UnitTypeCount)) - fallback_is_feasible = false; - if (fallback_is_feasible) { - UnitType * type = &p_bic_data->UnitTypes[stored->order.OrderID]; - if (type->Unit_Class != UTC_Land) - fallback_is_feasible = false; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (city, AERODROME_DISTRICT_ID))) - fallback_is_feasible = false; - if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (city, PORT_DISTRICT_ID))) - fallback_is_feasible = false; - } - } else - fallback_is_feasible = false; - - if (fallback_is_feasible) { - if (out->OrderType == COT_Improvement) { - // Remember pending building order for any improvement that requires a district - snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: Remembering fallback pending building order for city %d (%s): order type %d id %d\n", - city->Body.ID, city->Body.CityName, out->OrderType, out->OrderID); - (*p_OutputDebugStringA) (ss); - remember_pending_building_order (city, out->OrderID); - } - - fallback_order = stored->order; - swapped_to_fallback = true; - } - } - } - } - - if (swapped_to_fallback) { - *out = fallback_order; - } - if ((swapped_to_fallback || should_mark_district) && (required_district_id >= 0)) - mark_city_needs_district (city, required_district_id); - - clear_best_feasible_order (city); - return swapped_to_fallback; -} - -void __fastcall -patch_City_ai_choose_production (City * this, int edx, City_Order * out) -{ - is->ai_considering_production_for_city = this; - City_ai_choose_production (this, __, out); - - char ss[200]; - snprintf (ss, sizeof ss, "patch_City_ai_choose_production: City %d (%s) chose order type %d id %d\n", - this->Body.ID, this->Body.CityName, out->OrderType, out->OrderID); - (*p_OutputDebugStringA) (ss); - - if (is->current_config.enable_districts) { - if (ai_handle_district_production_requirements (this, out)) { - return; - } - } - - Leader * me = &leaders[this->Body.CivID]; - int arty_ratio = is->current_config.ai_build_artillery_ratio; - int bomber_ratio = is->current_config.ai_build_bomber_ratio; - - // Check if AI-build-more-artillery mod option is activated and this city is building something that we might want to switch to artillery - if ((arty_ratio > 0) && - (out->OrderType == COT_Unit) && - (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && - (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & (UTAI_Offence | UTAI_Defence))) { - - // Check how many offense/defense/artillery units this AI has already built. We'll only force it to build arty if it has a minimum - // of one defender per city, one attacker per two cities, and of course if it's below the ratio limit. - int num_attackers = me->AI_Strategy_Unit_Counts[0], - num_defenders = me->AI_Strategy_Unit_Counts[1], - num_artillery = me->AI_Strategy_Unit_Counts[2]; - if ((num_attackers > me->Cities_Count / 2) && - (num_defenders > me->Cities_Count) && - (100*num_artillery < arty_ratio*(num_attackers + num_defenders))) { - - // Loop over all build options to determine the best artillery unit available. Record its attack power and also find & record - // the highest attack power available from any offensive unit so we can compare them. - int best_arty_type_id = -1, - best_arty_rating = -1, - best_arty_strength = -1, - best_attacker_strength = -1; - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if ((type->AI_Strategy & (UTAI_Artillery | UTAI_Offence)) && - patch_City_can_build_unit (this, __, n, 1, 0, 0)) { - if (type->AI_Strategy & UTAI_Artillery) { - int this_rating = rate_artillery (&p_bic_data->UnitTypes[n]); - if (this_rating > best_arty_rating) { - best_arty_type_id = n; - best_arty_rating = this_rating; - best_arty_strength = type->Bombard_Strength * type->FireRate; - } - } else { // attacker - int this_strength = (type->Attack * (4 + type->Hit_Point_Bonus)) / 4; - if (this_strength > best_attacker_strength) - best_attacker_strength = this_strength; - } - } - } - - // Randomly switch city production to the artillery unit if we found one - if (best_arty_type_id >= 0) { - int chance = 12 * arty_ratio / 10; - - // Scale the chance of switching by the ratio of the attack power the artillery would provide to the attack power - // of the strongest offensive unit. This way the AI will rapidly build artillery up to the ratio limit only when - // artillery are its best way of dealing damage. - // Some example numbers: - // | Best attacker (str) | Best arty (str) | Chance w/ ratio = 20, damage% = 50 - // | Swordsman (3) | Catapult (4) | 16 - // | Knight (4) | Trebuchet (6) | 18 - // | Cavalry (6) | Cannon (8) | 16 - // | Cavalry (6) | Artillery (24) | 48 - // | Tank (16) | Artillery (24) | 18 - if (best_attacker_strength > 0) - chance = (chance * best_arty_strength * is->current_config.ai_artillery_value_damage_percent) / (best_attacker_strength * 100); - - if (rand_int (p_rand_object, __, 100) < chance) - out->OrderID = best_arty_type_id; - } - } - - } else if ((bomber_ratio > 0) && - (out->OrderType == COT_Unit) && - (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && - (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & UTAI_Air_Defence)) { - int num_fighters = me->AI_Strategy_Unit_Counts[7], - num_bombers = me->AI_Strategy_Unit_Counts[6]; - if (100 * num_bombers < bomber_ratio * num_fighters) { - int best_bomber_type_id = -1, - best_bomber_rating = -1; - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if ((type->AI_Strategy & UTAI_Air_Bombard) && - patch_City_can_build_unit (this, __, n, 1, 0, 0)) { - int this_rating = rate_bomber (&p_bic_data->UnitTypes[n]); - if (this_rating > best_bomber_rating) { - best_bomber_type_id = n; - best_bomber_rating = this_rating; - } - } - } - - if (best_bomber_type_id >= 0) { - int chance = 12 * bomber_ratio / 10; - if (rand_int (p_rand_object, __, 100) < chance) - out->OrderID = best_bomber_type_id; - } - } - } - - is->ai_considering_production_for_city = NULL; -} - -int __fastcall -patch_Unit_disembark_passengers (Unit * this, int edx, int tile_x, int tile_y) -{ - // Break any escort relationships if the escorting unit can't move onto the target tile. This prevents a freeze where the game continues - // trying to disembark units because an escortee looks like it could be disembarked except it can't because it won't move if its escorter - // can't be moved first. - Tile * tile = tile_at (this->Body.X, this->Body.Y), - * target = tile_at (tile_x , tile_y); - if (is->current_config.patch_blocked_disembark_freeze && (tile != NULL) && (target != NULL)) { - enum SquareTypes target_terrain = target->vtable->m50_Get_Square_BaseType (target); - FOR_UNITS_ON (uti, tile) { - Unit * escortee = get_unit_ptr (uti.unit->Body.escortee); - if ( (escortee != NULL) - && (uti.unit->Body.Container_Unit == this->Body.ID) - && (escortee->Body.Container_Unit == this->Body.ID) - && ( UnitType_has_ability (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID], __, UTA_Immobile) - || ( is->current_config.disallow_trespassing - && check_trespassing (uti.unit->Body.CivID, tile, target) - && ! is_allowed_to_trespass (uti.unit)) - || Unit_is_terrain_impassable (uti.unit, __, target_terrain))) - Unit_set_escortee (uti.unit, __, -1); - } - } - - return Unit_disembark_passengers (this, __, tile_x, tile_y); -} - -// Returns whether or not the current deal being offered to the AI on the trade screen would be accepted. How advantageous the AI thinks the -// trade is for itself is stored in out_their_advantage if it's not NULL. This advantage is measured in gold, if it's positive it means the -// AI thinks it's gaining that much value from the trade and if it's negative it thinks it would be losing that much. I don't know what would -// happen if this function were called while the trade screen is not active. -bool -is_current_offer_acceptable (int * out_their_advantage) -{ - int their_id = p_diplo_form->other_party_civ_id; - - DiploMessage consideration = Leader_consider_trade ( - &leaders[their_id], - __, - &p_diplo_form->our_offer_lists[their_id], - &p_diplo_form->their_offer_lists[their_id], - p_main_screen_form->Player_CivID, - 0, true, 0, 0, - out_their_advantage, - NULL, NULL); - - return consideration == DM_AI_ACCEPT; -} - -// Adds an offer of gold to the list and returns it. If one already exists in the list, returns a pointer to it. -TradeOffer * -offer_gold (TradeOfferList * list, int is_lump_sum, int * is_new_offer) -{ - if (list->length > 0) - for (TradeOffer * offer = list->first; offer != NULL; offer = offer->next) - if ((offer->kind == 7) && (offer->param_1 == is_lump_sum)) { - *is_new_offer = 0; - return offer; - } - - TradeOffer * tr = new (sizeof *tr); - *tr = (struct TradeOffer) { - .vtable = p_trade_offer_vtable, - .kind = 7, // TODO: Replace with enum - .param_1 = is_lump_sum, - .param_2 = 0, - .next = NULL, - .prev = NULL - }; - - if (list->length > 0) { - tr->prev = list->last; - list->last->next = tr; - list->last = tr; - list->length += 1; - } else { - list->last = list->first = tr; - list->length = 1; - } - - *is_new_offer = 1; - return tr; -} - -// Removes offer from list of offers but does not free it. Assumes offer is in the list. -void -remove_offer (TradeOfferList * list, TradeOffer * offer) -{ - if (list->length == 1) { - list->first = list->last = NULL; - list->length = 0; - } else if (list->length > 1) { - TradeOffer * prev = offer->prev, * next = offer->next; - if (prev) - prev->next = next; - if (next) - next->prev = prev; - if (list->first == offer) - list->first = next; - if (list->last == offer) - list->last = prev; - list->length -= 1; - } - offer->prev = offer->next = NULL; -} - -void __fastcall -patch_PopupForm_set_text_key_and_flags (PopupForm * this, int edx, char * script_path, char * text_key, int param_3, int param_4, int param_5, int param_6) -{ - int * p_stack = (int *)&script_path; - int ret_addr = p_stack[-1]; - - int is_initial_gold_trade = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_INITIAL_GOLD_OFFER_RETURN), - is_modifying_gold_trade = (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN ) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_OFFER_RETURN); - - // This function gets called from all over the place, check that it's being called to setup the set gold amount popup in the trade screen - if (is->current_config.autofill_best_gold_amount_when_trading && (is_initial_gold_trade || is_modifying_gold_trade)) { - int asking = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN); - int is_lump_sum = is_initial_gold_trade ? - p_stack[TRADE_GOLD_SETTER_IS_LUMP_SUM_OFFSET] : // Read this variable from the caller's frame - is->modifying_gold_trade->param_1; - - int their_id = p_diplo_form->other_party_civ_id, - our_id = p_main_screen_form->Player_CivID; - - // This variable will store the result of the optimization process and it's what will be used as the final amount presented to the - // player in the popup and left in the TradeOffer object (if applicable). Default to zero for new offers and the previous amount when - // modifying an offer. When modifying, we also zero the amount on the table b/c the optimization process only works properly from that - // starting point. - int best_amount = 0; - if (is_modifying_gold_trade) { - best_amount = is->modifying_gold_trade->param_2; - is->modifying_gold_trade->param_2 = 0; - } - - int their_advantage; - bool is_original_acceptable = is_current_offer_acceptable (&their_advantage); - - // if (we're asking for money on an acceptable trade and are offering something) OR (we're offering money on an unacceptable trade and - // are asking for something) - if (( asking && is_original_acceptable && (p_diplo_form->our_offer_lists[their_id] .length > 0)) || - ((! asking) && (! is_original_acceptable) && (p_diplo_form->their_offer_lists[their_id].length > 0))) { - - TradeOfferList * offers = asking ? &p_diplo_form->their_offer_lists[their_id] : &p_diplo_form->our_offer_lists[their_id]; - int test_offer_is_new; - TradeOffer * test_offer = offer_gold (offers, is_lump_sum, &test_offer_is_new); - - // When asking for gold, start at zero and work upwards. When offering gold it's more complicated. For lump sum - // offers, start with our entire treasury and work downward. For GPT offers, start with an upper bound and work - // downward. The upper bound depends on how much the AI thinks it's losing on the trade (in gold) divided by 20 - // (b/c 20 turn deal) with a lot of extra headroom just to make sure. - int starting_amount; { - if (asking) - starting_amount = 0; - else { - if (is_lump_sum) - starting_amount = leaders[our_id].Gold_Encoded + leaders[our_id].Gold_Decrement; - else { - int guess = not_below (0, 0 - their_advantage) / 20; - starting_amount = 10 + guess * 2; - } - } - } - - // Check if optimization is still possible. It's not if we're offering gold and our maximum offer is unacceptable - test_offer->param_2 = starting_amount; - if (asking || is_current_offer_acceptable (NULL)) { - - best_amount = starting_amount; - for (int step_size = asking ? 1000 : -1000; step_size != 0; step_size /= 10) { - test_offer->param_2 = best_amount; - while (1) { - test_offer->param_2 += step_size; - if (test_offer->param_2 < 0) - break; - else if (is_current_offer_acceptable (NULL)) - best_amount = test_offer->param_2; - else - break; - } - } - } - - // Annoying little edge case: The limitation on AIs not to trade more than their entire treasury is handled in the - // interface not the trade evaluation logic so we have to limit our gold request here to their treasury (otherwise - // the amount will default to how much they would pay if they had infinite money). - int their_treasury = leaders[their_id].Gold_Encoded + leaders[their_id].Gold_Decrement; - if (asking && is_lump_sum && (best_amount > their_treasury)) - best_amount = their_treasury; - - // Restore the trade table to its original state. Remove & free test_offer if it was newly created, otherwise put back its - // original amount. - if (test_offer_is_new) { - remove_offer (offers, test_offer); - test_offer->vtable->destruct (test_offer, __, 1); - } - - // If we're offering gold on a trade that's already acceptable, the optimal amount is zero. We must handle this explicitly in case - // we're modifying an amount already on the table. If we didn't, the above condition wouldn't optimize the amount and we'd default to - // the original amount. - } else if ((! asking) && is_original_acceptable) - best_amount = 0; - - if (is_modifying_gold_trade) - is->modifying_gold_trade->param_2 = best_amount; - snprintf (is->ask_gold_default, sizeof is->ask_gold_default, "%d", best_amount); - is->ask_gold_default[(sizeof is->ask_gold_default) - 1] = '\0'; - PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, (int)is->ask_gold_default, param_5, param_6); - } else - PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, param_4, param_5, param_6); -} - -CityLocValidity __fastcall -patch_Map_check_city_location (Map *this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile) -{ - if (is->current_config.enable_natural_wonders) { - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { - return CLV_BLOCKED; - } - } - } - - int min_sep = is->current_config.minimum_city_separation; - CityLocValidity base_result = Map_check_city_location (this, __, tile_x, tile_y, civ_id, check_for_city_on_tile); - - // If minimum separation is one, make no change - if (min_sep == 1) - return base_result; - - // If minimum separation is <= 0, ignore the CITY_TOO_CLOSE objection to city placement unless the location is next to a city belonging to - // another civ and the settings forbid founding there. - else if ((min_sep <= 0) && (base_result == CLV_CITY_TOO_CLOSE)) { - if (is->current_config.disallow_founding_next_to_foreign_city) - for (int n = 1; n <= 8; n++) { - int x, y; - get_neighbor_coords (&p_bic_data->Map, tile_x, tile_y, n, &x, &y); - City * city = city_at (x, y); - if ((city != NULL) && (city->Body.CivID != civ_id)) - return CLV_CITY_TOO_CLOSE; - } - return CLV_OK; - - // If we have an increased separation we might have to exclude some locations the base code allows. - } else if ((min_sep > 1) && (base_result == CLV_OK)) { - // Check tiles around (x, y) for a city. Because the base result is CLV_OK, we don't have to check neighboring tiles, just those at - // distance 2, 3, ... up to (an including) the minimum separation - for (int dist = 2; dist <= min_sep; dist++) { - - // vertices stores the unwrapped coords of the tiles at the vertices of the square of tiles at distance "dist" around - // (tile_x, tile_y). The order of the vertices is north, east, south, west. - struct vertex { - int x, y; - } vertices[4] = { - {tile_x , tile_y - 2*dist}, - {tile_x + 2*dist, tile_y }, - {tile_x , tile_y + 2*dist}, - {tile_x - 2*dist, tile_y } - }; - - // neighbor index for direction of tiles along edge starting from each vertex - // values correspond to directions: southeast, southwest, northwest, northeast - int edge_dirs[4] = {3, 5, 7, 1}; - - // Loop over verts and check tiles along their associated edges. The N vert is associated with the NE edge, the E vert with - // the SE edge, etc. - for (int vert = 0; vert < 4; vert++) { - wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); - int dx, dy; - neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); - for (int j = 0; j < 2*dist; j++) { // loop over tiles along this edge - int cx = vertices[vert].x + j * dx, - cy = vertices[vert].y + j * dy; - wrap_tile_coords (&p_bic_data->Map, &cx, &cy); - if (city_at (cx, cy)) - return CLV_CITY_TOO_CLOSE; - } - } - - } - return base_result; - - } else - return base_result; -} - -bool -is_zero_strength (UnitType * ut) -{ - return (ut->Attack == 0) && (ut->Defence == 0); -} - -bool -is_captured (Unit_Body * u) -{ - return (u->RaceID >= 0) && (u->CivID >= 0) && (u->CivID < 32) && leaders[u->CivID].RaceID != u->RaceID; -} - -// Decides whether or not units "a" and "b" are duplicates, i.e., whether they are interchangeable. -// If surface_only is set, the function checks only surface-level characteristics, meaning those that are visible to other players. -bool -are_units_duplicate (Unit_Body * a, Unit_Body * b, bool surface_only) -{ - UnitType * a_type = &p_bic_data->UnitTypes[a->UnitTypeID], - * b_type = &p_bic_data->UnitTypes[b->UnitTypeID]; - - // If only doing a surface comparison, look through the alternate strategy types to the base types. The difference b/w the alt types is only - // their AI strategies, and that isn't considered a surface feature. - if (surface_only) { - while (a_type->alternate_strategy_for_id >= 0) - a_type = &p_bic_data->UnitTypes[a_type->alternate_strategy_for_id]; - while (b_type->alternate_strategy_for_id >= 0) - b_type = &p_bic_data->UnitTypes[b_type->alternate_strategy_for_id]; - } - - // a and b are duplicates "on the surface" if... - bool are_surface_duplicates = - // ... they belong to the same player ... - (a->CivID == b->CivID) && - - // ... they have the same type that is not [a leader OR army] AND not a transport AND ... - (a_type == b_type) && - (! (UnitType_has_ability (a_type, __, UTA_Leader) || UnitType_has_ability (a_type, __, UTA_Army))) && - (a_type->Transport_Capacity == 0) && - - // ... they've taken the same amount of damage AND have the same charm status AND ... - (a->Damage == b->Damage) && (a->charmed == b->charmed) && - - // ... they're either both fortified or both not AND ... - (! (a->UnitState == UnitState_Fortifying) ^ (b->UnitState == UnitState_Fortifying)) && - - // ... [they have the same experience level OR are zero strength units] AND ... - ((a->Combat_Experience == b->Combat_Experience) || is_zero_strength (a_type)) && - - // ... [they are both not contained in any unit OR they are both contained in the same unit] AND ... - (((a->Container_Unit < 0) && (b->Container_Unit < 0)) || (a->Container_Unit == b->Container_Unit)) && - - // ... neither one is carrying a princess AND ... - ((a->carrying_princess_of_race < 0) && (b->carrying_princess_of_race < 0)) && - - // ... [they are both captured units OR are both native units] AND ... - (! (is_captured (a) ^ is_captured (b))) && - - // ... their custom names are identical. - (0 == strncmp (a->Custom_Name.S, b->Custom_Name.S, sizeof (a->Custom_Name))); - - if ((! are_surface_duplicates) || surface_only) - return are_surface_duplicates; - - // a and b are additionally "deep", i.e. in all ways, duplicates if... - bool are_deep_duplicates = - // ... they've used up the same number of moves AND ... - (a->Moves == b->Moves) && - - // ... they have matching statuses (has attacked this turn, etc.) AND states (is fortified, is doing worker action, etc.) AND automation status AND ... - (a->Status == b->Status) && (a->UnitState == b->UnitState) && (a->automated == b->automated) && - - // ... they have both done the same number of airdrops this turn. - (itable_look_up_or (&is->airdrops_this_turn, a->ID, 0) == itable_look_up_or (&is->airdrops_this_turn, b->ID, 0)); - - return are_deep_duplicates; -} - -bool -is_busy (Unit * unit) -{ - int state = unit->Body.UnitState; - return ((state >= UnitState_Build_Mines) && (state <= UnitState_Explore)) || - (state == UnitState_Auto_Bombard) || (state == UnitState_Auto_Air_Bombard) || - unit->Body.automated; -} - -int __fastcall -patch_Context_Menu_add_item_and_set_color (Context_Menu * this, int edx, int item_id, char * text, int red) -{ - // Initialize the array of duplicate counts. The array is 0x100 items long because that's the maximum number of items a menu can have. - if (is->current_config.group_units_on_right_click_menu && - (is->unit_menu_duplicates == NULL)) { - unsigned dups_size = 0x100 * sizeof is->unit_menu_duplicates[0]; - is->unit_menu_duplicates = malloc (dups_size); - memset (is->unit_menu_duplicates, 0, dups_size); - } - - // Check if this menu item is a valid unit and grab pointers to its info - int unit_id; - Unit_Body * unit_body; - bool disable = false, put_icon = false; - int icon_index = 0; - if ((0 <= (unit_id = item_id - (0x13 + p_bic_data->UnitTypeCount))) && - (NULL != (unit_body = p_units->Units[unit_id].Unit)) && - (unit_body->UnitTypeID >= 0) && (unit_body->UnitTypeID < p_bic_data->UnitTypeCount)) { - - if (is->current_config.group_units_on_right_click_menu) { - // Loop over all existing menu items and check if any of them is a unit that's a duplicate of the one being added - for (int n = 0; n < this->Item_Count; n++) { - Context_Menu_Item * item = &this->Items[n]; - int dup_unit_id = this->Items[n].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount); - Unit_Body * dup_body; - if ((dup_unit_id >= 0) && - (NULL != (dup_body = p_units->Units[dup_unit_id].Unit)) && - are_units_duplicate (unit_body, dup_body, unit_body->CivID != p_main_screen_form->Player_CivID)) { - // The new item is a duplicate of the nth. Mark that in the duplicate counts array and return without actually - // adding the item. It doesn't matter what value we return because the caller doesn't use it. - is->unit_menu_duplicates[n] += 1; - return 0; - } - } - } - - if (unit_body->CivID == p_main_screen_form->Player_CivID) { - Unit * unit = (Unit *)((int)unit_body - offsetof (Unit, Body)); - UnitType * unit_type = &p_bic_data->UnitTypes[unit_body->UnitTypeID]; - bool no_moves_left = unit_body->Moves >= patch_Unit_get_max_move_points (unit); - if (no_moves_left && is->current_config.gray_out_units_on_menu_with_no_remaining_moves) - disable = true; - - // Put an icon next to this unit if we're configured to do so and it's not in an army - Unit * container; - if (is->current_config.put_movement_icons_on_units_on_menu && - ((NULL == (container = get_unit_ptr (unit_body->Container_Unit))) || - (! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)))) { - put_icon = true; - - bool attacker = is_offensive_combat_type (unit_type) || (Unit_has_ability (unit, __, UTA_Army) && (Unit_count_contained_units (unit) >= 1)), - busy = is_busy (unit); - - int icon_set_index = ((int)busy << 1) + (int)(! attacker); - - int icon_row; { - if (no_moves_left) - icon_row = URCMI_CANT_MOVE; - else if (unit_body->Moves == 0) - icon_row = URCMI_UNMOVED; - else if (! attacker) - icon_row = URCMI_MOVED_NO_ATTACK; - else - icon_row = (! has_exhausted_attack (unit)) ? URCMI_MOVED_CAN_ATTACK : URCMI_MOVED_NO_ATTACK; - } - - icon_index = icon_set_index * COUNT_UNIT_RCM_ICONS + icon_row; - } - } - } - - int tr = Context_Menu_add_item_and_set_color (this, __, item_id, text, red); - - if (disable) - Context_Menu_disable_item (this, __, item_id); - - if (put_icon) { - init_unit_rcm_icons (); - if (is->unit_rcm_icon_state == IS_OK) - Context_Menu_put_image_on_item (this, __, item_id, &is->unit_rcm_icons[icon_index]); - } - - return tr; -} - -int __fastcall -patch_Context_Menu_open (Context_Menu * this, int edx, int x, int y, int param_3) -{ - int * p_stack = (int *)&x; - int ret_addr = p_stack[-1]; - - if (is->current_config.enable_named_tiles && - is->named_tile_menu_active) { - int tile_x = is->named_tile_menu_tile_x; - int tile_y = is->named_tile_menu_tile_y; - Tile * tile = tile_at (tile_x, tile_y); - if (tile_can_be_named (tile, tile_x, tile_y)) { - struct named_tile_entry * entry = get_named_tile_entry (tile); - char menu_text[64]; - if ((entry != NULL) && (entry->name[0] != '\0')) - snprintf (menu_text, sizeof menu_text, "%s %s", is->c3x_labels[CL_RENAME_TILE], entry->name); - else - strcpy (menu_text,is->c3x_labels[CL_NAME_TILE]); - if (this->Item_Count > 0) - Context_Menu_add_separator (this, __, 0); - Context_Menu_add_item (this, __, NAMED_TILE_MENU_ID, menu_text, false, (Sprite *)0x0); - } - } - - if (is->current_config.group_units_on_right_click_menu && - (ret_addr == ADDR_OPEN_UNIT_MENU_RETURN) && - (is->unit_menu_duplicates != NULL)) { - - // Change the menu text to include the duplicate counts. This is pretty straight forward except for a couple little issues: we must - // use the game's internal malloc & free for compatibility with the base code and must call a function that widens the menu form, - // as necessary, to accommodate the longer strings. - for (int n = 0; n < this->Item_Count; n++) - if (is->unit_menu_duplicates[n] > 0) { - Context_Menu_Item * item = &this->Items[n]; - unsigned new_text_len = strlen (item->Text) + 20; - char * new_text = civ_prog_malloc (new_text_len); - - // Print entry text including dup count to new_text. Biggest complication here is that we want to print the dup count - // after any leading spaces to preserve indentation. - { - int num_spaces = 0; - while (item->Text[num_spaces] == ' ') - num_spaces++; - snprintf (new_text, new_text_len, "%.*s%dx %s", num_spaces, item->Text, is->unit_menu_duplicates[n] + 1, &item->Text[num_spaces]); - new_text[new_text_len - 1] = '\0'; - } - - civ_prog_free (item->Text); - item->Text = new_text; - Context_Menu_widen_for_text (this, __, new_text); - } - - // Clear the duplicate counts - memset (is->unit_menu_duplicates, 0, 0x100 * sizeof is->unit_menu_duplicates[0]); - } - - return Context_Menu_open (this, __, x, y, param_3); -} - -bool -is_material_unit (UnitType const * type, bool * out_is_pop_else_caravan) -{ - int join_city_action = UCV_Join_City & 0x0FFFFFFF; // To get the join city action code, use the command value and mask out the top 4 category bits - int disband_action = UCV_Disband & 0x0FFFFFFF; - if ((type->Attack | type->Defence | type->Bombard_Strength) == 0) { // if non-combat unit - if ((type->PopulationCost > 0) && (type->Worker_Actions == join_city_action)) { - *out_is_pop_else_caravan = true; - return true; - } else if ((type->Standard_Actions & disband_action) && (type->Worker_Actions == 0)) { - *out_is_pop_else_caravan = false; - return true; - } else - return false; - } else - return false; -} - -void -ai_move_material_unit (Unit * this) -{ - int type_id = this->Body.UnitTypeID; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - UnitType * type = &p_bic_data->UnitTypes[type_id]; - - // Determine whether this is a pop unit (will search for a city to join) or a caravan (will search for a city to disband) - int join_city_action = UCV_Join_City & 0x0FFFFFFF; - bool pop_else_caravan = type->Worker_Actions == join_city_action; - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - - // This part of the code follows how the replacement leader AI works. Basically it disbands the unit if it's on a continent with no - // friendly cities, then flees if it's in danger, then moves it along a set path if it has one. - if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { - Unit_disband (this); - return; - } - if (any_enemies_near_unit (this, 49)) { - Unit_set_state (this, __, UnitState_Fleeing); - bool done = this->vtable->work (this); - if (done || (this->Body.UnitState != 0)) - return; - } - byte next_move = Unit_pop_next_move_from_path (this); - if (next_move > 0) { - this->vtable->Move (this, __, next_move, 0); - return; - } - - // Find the best city to act on - City * best_city = NULL; - int best_city_value = pop_else_caravan ? -1 : 0; // min value to act is 0 for pop units, 1 for caravans - FOR_CITIES_OF (coi, this->Body.CivID) { - City * city = coi.city; - Tile * city_tile = tile_at (city->Body.X, city->Body.Y); - if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { - - if (pop_else_caravan) { - // Skip this city if it can't support another citizen - if ((city->Body.FoodIncome <= 0) || - (City_requires_improvement_to_grow (city) > -1)) - continue; - } else { - // Skip this city if its current build can't be rushed - if (! City_can_take_outside_shields (city, __, 0)) - continue; - } - - // Consider distance. - int dist_in_turns; - if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) - continue; // No path or unit cannot move - - int value; - if (pop_else_caravan) - value = 1000 / (10 + dist_in_turns); // Base value of 100 * 10 / (10 + dist_in_turn) - else { - // value is number of useful shields we'd get by moving to this city and disbanding there - int shields_per_turn = get_city_production_rate (city, city->Body.Order_Type, city->Body.Order_ID), - shields_to_complete_build = City_get_order_cost (city) - City_get_order_progress (city) - shields_per_turn, - disband_value = Leader_get_unit_cost (&leaders[city->Body.CivID], __, type_id, false) >> 2; - value = not_above (shields_to_complete_build, disband_value) - shields_per_turn * dist_in_turns; - } - - // Scale value by city corruption rate for pop units or caravan units targeting cities building improvs - if (pop_else_caravan || (city->Body.Order_Type == COT_Improvement)) { - int good_shields = city->Body.ProductionIncome, - corrupt_shields = city->Body.ProductionLoss; - if (good_shields + corrupt_shields > 0) - value = (value * good_shields) / (good_shields + corrupt_shields); - else - value = -1; - } - - if (value > best_city_value) { - best_city = city; - best_city_value = value; - } - } - } - - // Join city if we're already in the city we want to join, otherwise move to that city. If we couldn't find a city to join, go to the - // nearest established city and wait. - City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); - City * moving_to_city = NULL; - if (best_city != NULL) { - if (best_city == in_city) { - if (pop_else_caravan && patch_Unit_can_perform_command (this, __, UCV_Join_City)) { - Unit_join_city (this, __, in_city); - return; - } else if ((! pop_else_caravan) && patch_Unit_can_perform_command (this, __, UCV_Disband)) { - Unit_disband (this); - return; - } - } else - moving_to_city = best_city; - } else if (in_city == NULL) - moving_to_city = find_nearest_established_city (this, continent_id); - - if (moving_to_city) { - int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); - if (first_move > 0) { - Unit_set_escortee (this, __, -1); - this->vtable->Move (this, __, first_move, 0); - return; - } - } - - // Nothing to do, nowhere to go, just fortify in place. - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -int __stdcall -patch_get_anarchy_length (int leader_id) -{ - int base = get_anarchy_length (leader_id); - int multiplier = is->current_config.anarchy_length_percent; - if (multiplier != 100) { - // Anarchy cannot be less than 2 turns or you'll get an instant government switch. Only let that happen when the percent multiplier is - // set below zero, indicating a desire for no anarchy. Otherwise we can't reduce anarchy below 2 turns. - if (multiplier < 0) - return 1; - else if (base <= 2) - return base; - else - return not_below (2, rand_div (base * multiplier, 100)); - } else - return base; -} - -bool __fastcall -patch_Unit_check_king_ability_while_spawning (Unit * this, int edx, enum UnitTypeAbilities a) -{ - if (is->current_config.dont_give_king_names_in_non_regicide_games && - ((*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) == 0)) - return false; - else - return Unit_has_ability (this, __, a); -} - -int __fastcall -patch_Map_compute_neighbor_index_for_pass_between (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - if (is->current_config.enable_land_sea_intersections) - return 0; - else - return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); -} - -// This call replacement used to be part of improvement perfuming but now its only purpose is to set ai_considering_order when -// ai_choose_production is looping over improvements. -bool __fastcall -patch_Improvement_has_wonder_com_bonus_for_ai_prod (Improvement * this, int edx, enum ImprovementTypeWonderFeatures flag) -{ - is->ai_considering_order.OrderID = this - p_bic_data->Improvements; - is->ai_considering_order.OrderType = COT_Improvement; - return Improvement_has_wonder_flag (this, __, flag); -} - -// Similarly, this one sets the var when looping over unit types. -bool __fastcall -patch_UnitType_has_strat_0_for_ai_prod (UnitType * this, int edx, byte n) -{ - is->ai_considering_order.OrderID = this - p_bic_data->UnitTypes; - is->ai_considering_order.OrderType = COT_Unit; - return UnitType_has_ai_strategy (this, __, n); -} - -int -compare_ai_prod_valuations (void const * vp_a, void const * vp_b) -{ - struct ai_prod_valuation const * a = vp_a, - * b = vp_b; - if (a->point_value > b->point_value) return -1; - else if (b->point_value > a->point_value) return 1; - else return 0; -} - -void -rank_ai_production_options (City * city) -{ - is->count_ai_prod_valuations = 0; - City_Order unused; - patch_City_ai_choose_production (city, __, &unused); // records valuations in is->ai_prod_valuations - qsort (is->ai_prod_valuations, is->count_ai_prod_valuations, sizeof is->ai_prod_valuations[0], compare_ai_prod_valuations); -} - -void __fastcall -patch_City_Form_m82_handle_key_event (City_Form * this, int edx, int virtual_key_code, int is_down) -{ - if (is->current_config.enable_ai_production_ranking && - (~*p_human_player_bits & (1 << this->CurrentCity->Body.CivID)) && - (virtual_key_code == VK_P) && is_down) { - rank_ai_production_options (this->CurrentCity); - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_AI_PROD_RANKING", -1, 0, 0, 0); - char s[200]; - for (int n = 0; n < is->count_ai_prod_valuations; n++) { - struct ai_prod_valuation const * val = &is->ai_prod_valuations[n]; - char * name = (val->order_type == COT_Improvement) ? p_bic_data->Improvements[val->order_id].Name.S : p_bic_data->UnitTypes[val->order_id].Name; - - int show_strategy = -1; - if (val->order_type == COT_Unit) - itable_look_up (&is->unit_type_alt_strategies, val->order_id, &show_strategy); - - if ((show_strategy >= 0) && (show_strategy <= CL_LAST_UNIT_STRAT - CL_FIRST_UNIT_STRAT)) - snprintf (s, sizeof s, "^%d %s (%s)", val->point_value, name, is->c3x_labels[CL_FIRST_UNIT_STRAT + show_strategy]); - else - snprintf (s, sizeof s, "^%d %s", val->point_value, name); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - patch_show_popup (popup, __, 0, 0); - - } else if (is->current_config.toggle_zoom_with_z_on_city_screen && - (virtual_key_code == VK_Z) && is_down) { - p_bic_data->is_zoomed_out = ! p_bic_data->is_zoomed_out; - Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, this->CurrentCity->Body.X, get_city_screen_center_y (this->CurrentCity), 0, true, false); // also redraws map - this->Base.vtable->m73_call_m22_Draw ((Base_Form *)this); - } - - City_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); -} - -bool -can_harvest_shields_from_forest (Tile * tile) -{ - int flags = tile->vtable->m43_Get_field_30 (tile); - return (flags & 0x10000000) == 0; -} - -void __fastcall -patch_open_tile_info (void * this, int edx, int mouse_x, int mouse_y, int civ_id) -{ - int tx, ty; - if (is->current_config.show_detailed_tile_info && - (! Main_Screen_Form_get_tile_coords_under_mouse (p_main_screen_form, __, mouse_x, mouse_y, &tx, &ty))) { - is->viewing_tile_info_x = tx; - is->viewing_tile_info_y = ty; - is->tile_info_open = true; - } else - is->viewing_tile_info_x = is->viewing_tile_info_y = -1; - - open_tile_info (this, __, mouse_x, mouse_y, civ_id); - - is->tile_info_open = false; -} - -int __fastcall -patch_Match_ai_eval_city_location (void * this, int edx, int x, int y, int civ_id, bool param_4, int * out_breakdown) -{ - is->ai_evaling_city_loc_x = x; - is->ai_evaling_city_loc_y = y; - is->ai_evaling_city_field_30_get_counter = 0; - - return Match_ai_eval_city_location (this, __, x, y, civ_id, param_4, out_breakdown); -} - -bool -is_explored (Tile * tile, int civ_id) -{ - unsigned explored_bits = tile->Body.Fog_Of_War; - int in_debug_mode = (*p_debug_mode_bits & 8) != 0; // checking bit 3 here b/c that's how resource visibility is checked in open_tile_info - if (in_debug_mode || (explored_bits & (1 << civ_id))) - return true; - else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND - ((1 << civ_id) & *p_human_player_bits) && // "civ_id" is a human player AND - (explored_bits & *p_human_player_bits)) // any human player has visibility on the tile - return true; - else - return false; -} - -// On the GOG executable, this function intercepts the call to draw the "No information available" text on a unexplored (black) tile. In that case we -// replace that text with the coords. But on the Steam EXE this func also intercepts the call that draws the resource name on the visible tile info -// box b/c the call site is reused via a jump. So we must check that the tile is actually unexplored before replacing the text so that the resource -// name doesn't get overwritten. -int __fastcall -patch_PCX_Image_draw_no_tile_info (PCX_Image * this, int edx, char * str, int x, int y, int str_len) -{ - Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if ((tile != p_null_tile) && ! is_explored (tile, p_main_screen_form->Player_CivID)) { - char s[100]; - snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); - s[(sizeof s) - 1] = '\0'; - return PCX_Image_draw_text (this, __, s, x, y, strlen (s)); - } else - return PCX_Image_draw_text (this, __, str, x, y, str_len); -} - -int __fastcall -patch_PCX_Image_draw_tile_info_terrain (PCX_Image * this, int edx, char * str, int x, int y, int str_len) -{ - Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if (tile != p_null_tile) { - bool show_district_name = false; - - char s[200]; - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - // Draw district name to the right of terrain name if tile has one - struct district_instance * dist = get_district_instance (tile); - - if (dist != NULL) { - show_district_name = true; - char const * display_name = is->district_configs[dist->district_id].display_name; - if ((display_name == NULL) || (display_name[0] == '\0')) - display_name = is->district_configs[dist->district_id].name; - - // If it's a wonder district with a completed wonder, show the wonder name instead - if ((dist->district_id == WONDER_DISTRICT_ID) && - (dist->wonder_info.state == WDS_COMPLETED) && - (dist->wonder_info.wonder_index >= 0) && - (dist->wonder_info.wonder_index < is->wonder_district_count)) { - char const * wonder_name = is->wonder_district_configs[dist->wonder_info.wonder_index].wonder_name; - if ((wonder_name != NULL) && (wonder_name[0] != '\0')) { - display_name = wonder_name; - } - } else if ((dist->district_id == NATURAL_WONDER_DISTRICT_ID) && - (dist->natural_wonder_info.natural_wonder_id >= 0) && - (dist->natural_wonder_info.natural_wonder_id < is->natural_wonder_count)) { - int natural_id = dist->natural_wonder_info.natural_wonder_id; - char const * natural_name = is->natural_wonder_configs[natural_id].name; - if ((natural_name != NULL) && (natural_name[0] != '\0')) { - display_name = natural_name; - } - } - - snprintf (s, sizeof s, "%s", display_name); - PCX_Image_draw_text (this, __, s, x + 68, y, strlen (s)); - } - } - - // Show sprites & sheet indexes if in debug mode - int is_debug_mode = (*p_debug_mode_bits & 4) != 0; - if (is_debug_mode) { - int sheet_index = (tile->SquareParts >> 8) & 0xFF; - int sprite_index = tile->SquareParts & 0xFF; - snprintf (s, sizeof s, "%d, %d", sheet_index, sprite_index); - PCX_Image_draw_text (this, __, s, x, y - 18, strlen (s)); - } - - // Draw tile coords on line below terrain name - snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); - PCX_Image_draw_text (this, __, s, x, y + 14, strlen (s)); - - if ((is->city_loc_display_perspective >= 0) && - ((1 << is->city_loc_display_perspective) & *p_player_bits)) { - int eval = patch_Match_ai_eval_city_location (p_match, __, is->viewing_tile_info_x, is->viewing_tile_info_y, is->city_loc_display_perspective, false, NULL); - if (eval > 0) { - snprintf (s, sizeof s, "%d", eval - 1000000); - PCX_Image_draw_text (this, __, s, x + 95, y, strlen (s)); - } - } - - // If tile has been chopped and district name not shown (uses same space), indicate that to the right of the terrain name - if (! can_harvest_shields_from_forest (tile) && !show_district_name) - PCX_Image_draw_text (this, __, is->c3x_labels[CL_CHOPPED], x + 145, y, strlen (is->c3x_labels[CL_CHOPPED])); - } - return PCX_Image_draw_text (this, __, str, x, y, str_len); -} - -int __fastcall -patch_City_compute_corrupted_yield (City * this, int edx, int gross_yield, bool is_production) -{ - Leader * leader = &leaders[this->Body.CivID]; - - if (is->current_config.zero_corruption_when_off && - (p_bic_data->Governments[leader->GovernmentType].CorruptionAndWaste == CWT_Off)) - return 0; - - int tr = City_compute_corrupted_yield (this, __, gross_yield, is_production); - - if (is->current_config.promote_wonder_decorruption_effect) { - int actual_capital_id = leader->CapitalID; - for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { - Improvement * improv = &p_bic_data->Improvements[improv_id]; - City * pseudo_capital = NULL; - if (improv->SmallWonderFlags & ITSW_Reduces_Corruption) { - if (improv->Characteristics & ITC_Small_Wonder) { - pseudo_capital = get_city_ptr (leader->Small_Wonders[improv_id]); - } else if (improv->Characteristics & ITC_Wonder) { - pseudo_capital = get_city_ptr (Game_get_wonder_city_id(p_game, __, improv_id)); - } - - if (pseudo_capital != NULL && pseudo_capital->Body.CivID == this->Body.CivID && pseudo_capital->Body.ID != actual_capital_id) { - leader->CapitalID = pseudo_capital->Body.ID; - int fp_corrupted_yield = City_compute_corrupted_yield (this, __, gross_yield, is_production); - if (fp_corrupted_yield < tr) - tr = fp_corrupted_yield; - } - } - } - leader->CapitalID = actual_capital_id; - } - - return tr; -} - -int __fastcall -patch_Sprite_draw (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - Sprite * to_draw = get_sprite_proxy_for_current_hour(this); - return Sprite_draw(to_draw ? to_draw : this, __, canvas, pixel_x, pixel_y, color_table); -} - -int __fastcall -patch_Sprite_draw_on_map (Sprite * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) -{ - Sprite * to_draw = get_sprite_proxy_for_current_hour(this); - return Sprite_draw_on_map(to_draw ? to_draw : this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); -} - -bool -is_or_could_become_grassland (Tile * tile) -{ - enum SquareTypes sq_type = tile->vtable->m50_Get_Square_BaseType (tile), - underlying_type = tile->vtable->m49_Get_Square_RealType (tile); - int worker_job_id = p_bic_data->TileTypes[sq_type].WorkerJobID; - return sq_type == SQ_Grassland || - (underlying_type == SQ_Grassland && (worker_job_id == WJ_Clean_Forest || worker_job_id == WJ_Clear_Swamp)) || - tile->vtable->m72_Get_Pollution_Effect (tile) == SQ_Grassland; -} - -void __fastcall -patch_Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (Map_Renderer * this, int edx, int param_1, int pixel_x, int pixel_y, Map_Renderer * map_renderer, int param_5, int tile_x, int tile_y, int param_8) -{ - Map * map = &p_bic_data->Map; - Tile * tile = tile_at (tile_x, tile_y); - - is->current_render_tile = tile; - is->current_render_tile_x = tile_x; - is->current_render_tile_y = tile_y; - is->current_render_tile_district = get_district_instance (tile); - - Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (this, __, param_1, pixel_x, pixel_y, map_renderer, param_5, tile_x, tile_y, param_8); - - is->current_render_tile = NULL; - is->current_render_tile_x = -1; - is->current_render_tile_y = -1; - is->current_render_tile_district = NULL; - - if ((is->city_loc_display_perspective >= 0) && - (! map->vtable->m10_Get_Map_Zoom (map)) && // Turn off display when zoomed out. Need another set of highlight images for that. - ((1 << is->city_loc_display_perspective) & *p_player_bits) && - (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. - - init_tile_highlights (); - if (is->tile_highlight_state == IS_OK) { - int eval = patch_Match_ai_eval_city_location (p_match, __, tile_x, tile_y, is->city_loc_display_perspective, false, NULL); - if (eval > 0) { - int step_size = 10; - int midpoint = (COUNT_TILE_HIGHLIGHTS % 2 == 0) ? 1000000 : (1000000 - step_size/2); - int grade = (eval >= midpoint) ? (eval - midpoint) / step_size : (eval - midpoint) / step_size - 1; - int i_highlight = clamp (0, COUNT_TILE_HIGHLIGHTS - 1, COUNT_TILE_HIGHLIGHTS/2 + grade); - Sprite_draw_on_map (&is->tile_highlights[i_highlight], __, this, pixel_x, pixel_y, 1, 1, 1, 0); - } - } - } - - // Districts-related highlights - if (is->current_config.enable_districts && - (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. - init_tile_highlights (); - if (is->tile_highlight_state == IS_OK) { - - // Draw city work radius highlights for selected worker - if (is->current_config.enable_city_work_radii_highlights && - is->highlight_city_radii) { - - if ((tile != NULL) && (tile != p_null_tile)) { - int stored_ptr; - if (itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)tile, &stored_ptr)) { - struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)stored_ptr; - Sprite_draw_on_map (&is->tile_highlights[clamp(0, COUNT_TILE_HIGHLIGHTS - 1, info->highlight_level)], __, this, pixel_x, pixel_y, 1, 1, 1, 0); - } - } - } - - // If focusing on a tile after Great Wall completed, highlight the tile while getting user confirmation - if (is->focused_tile != NULL && is->focused_tile == tile) { - Sprite_draw_on_map (&is->tile_highlights[10], __, this, pixel_x, pixel_y, 1, 1, 1, 0); - } - } - } -} - -// We determine at the start of the game where *any* AI player might want to build canals and bridges. -// This is done up front in a single pass, as re-assessing every single turn per AI is wasteful and the -// geography of the map doesn't change. This function adds all the candidates as districts, effectively -// drawing them directly on the map. We don't use it in a normal game, but this is extremely useful for -// debugging so good to keep it around. For debugging, just call it immediately after -// generate_ai_canal_and_bridge_targets () -void -insert_ai_candidate_bridge_or_canals_into_district_tile_map () -{ - if ((is->ai_candidate_bridge_or_canals_count <= 0) || (! is->ai_candidate_bridge_or_canals_initialized)) - return; - - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if (entry == NULL) - continue; - - char ss[256]; - snprintf (ss, sizeof ss, "Entry %d: district %d owner %d tiles %d completed %d\n", - ei, entry->district_id, entry->owner_civ_id, entry->tile_count, entry->completed ? 1 : 0); - (*p_OutputDebugStringA)(ss); - - for (int ti = 0; ti < entry->tile_count; ti++) { - int tx = entry->tile_x[ti]; - int ty = entry->tile_y[ti]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - snprintf (ss, sizeof ss, " (%d,%d)%s\n", tx, ty, (ti == entry->assigned_tile_index) ? " [assigned]" : ""); - (*p_OutputDebugStringA)(ss); - } - } - - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if ((entry == NULL) || (entry->completed)) - continue; - - for (int ti = 0; ti < entry->tile_count; ti++) { - int tx = entry->tile_x[ti]; - int ty = entry->tile_y[ti]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int key = (int)tile; - int existing; - if (itable_look_up (&is->district_tile_map, key, &existing)) - continue; - - struct district_instance * inst = (struct district_instance *)calloc (1, sizeof *inst); - if (inst == NULL) - continue; - inst->state = DS_COMPLETED; - inst->district_id = entry->district_id; - inst->tile_x = tx; - inst->tile_y = ty; - - itable_insert (&is->district_tile_map, key, (int)inst); - } - } -} - -void __fastcall -patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (Map_Renderer * this, int edx, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (! is->current_config.draw_forests_over_roads_and_railroads) { - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - Tile * tile = is->current_render_tile; - if ((tile == NULL) || (tile == p_null_tile)) - return; - - if ((tile->vtable->m50_Get_Square_BaseType (tile) == SQ_Forest) && - (*tile->vtable->m25_Check_Roads)(tile, __, 0)) { - is->draw_forests_over_roads_on_tile = true; - return; - } - - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Map_Renderer_m52_Draw_Roads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - // Don't draw roads if a bridge is here - if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { - Tile * tile = is->current_render_tile; - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * dist = get_district_instance (tile); - if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { - return; - } - } - } - - Map_Renderer_m52_Draw_Roads (this, __, image_index, map_renderer, pixel_x, pixel_y); - - if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) - return; - - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Map_Renderer_m52_Draw_Railroads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - // Don't draw railroads if a bridge is here - if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { - Tile * tile = is->current_render_tile; - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * dist = get_district_instance (tile); - if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { - return; - } - } - } - - Map_Renderer_m52_Draw_Railroads (this, __, image_index, map_renderer, pixel_x, pixel_y); - - if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) - return; - - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Main_Screen_Form_m82_handle_key_event (Main_Screen_Form * this, int edx, int virtual_key_code, int is_down) -{ - char s[200]; - int * last_events = is->last_main_screen_key_up_events; - bool in_game = *p_player_bits != 0; // Player bits all zero indicates we aren't currently in a game. Need to check for this because UI events - // on the main menu also pass through this function. - - if (! is_down) { - for (int n = ARRAY_LEN (is->last_main_screen_key_up_events) - 1; n > 0; n--) - last_events[n] = last_events[n - 1]; - last_events[0] = virtual_key_code; - } - - if (is->current_config.enable_ai_city_location_desirability_display && - (virtual_key_code == VK_L) && is_down && - (! (is_command_button_active (&this->GUI, UCV_Load) || is_command_button_active (&this->GUI, UCV_Unload))) && - in_game) { - int is_debug_mode = (*p_debug_mode_bits & 4) != 0; // This is how the check is done in open_tile_info. Actually there are two debug - // mode bits (4 and 8) and I don't know what the difference is. - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CITY_LOC_HIGHLIGHTS", -1, 0, 0x40, 0); - snprintf (s, sizeof s, " %s", is->c3x_labels[CL_OFF]); - s[(sizeof s) - 1] = '\0'; - PopupSelection_add_item (&popup->selection, __, s, 0); - for (int n = 1; n < 32; n++) - if ((*p_player_bits & (1 << n)) && - (is_debug_mode || (n == p_main_screen_form->Player_CivID))) { - Race * race = &p_bic_data->Races[leaders[n].RaceID]; - snprintf (s, sizeof s, " (%d) %s", n, race->vtable->GetLeaderName (race)); - s[(sizeof s) - 1] = '\0'; - PopupSelection_add_item (&popup->selection, __, s, n); - } - int sel = patch_show_popup (popup, __, 0, 0); - if (sel >= 0) { // -1 indicates popup was closed without making a selection - is->city_loc_display_perspective = (sel >= 1) ? sel : -1; - this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw - } - - } else if (is->current_config.enable_debug_mode_switch && - (in_game && ! is_down) && - (last_events[4] == VK_D) && (last_events[3] == VK_E) && (last_events[2] == VK_B) && (last_events[1] == VK_U) && (last_events[0] == VK_G)) { - PopupForm * popup = get_popup_form (); - if ((*p_debug_mode_bits & 0xC) != 0) { // Consider debug mode on if either bit is set - *p_debug_mode_bits &= ~0xC; - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - PopupForm_add_text (popup, __, "Debug mode deactivated.", 0); - patch_show_popup (popup, __, 0, 0); - } else { - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_DEBUG_ACTIVATION", -1, 0, 0, 0); - int sel = patch_show_popup (popup, __, 0, 0); - if (sel == 0) { - *p_debug_mode_bits |= 0xC; - *(bool *)((int)p_human_player_bits + 37) = true; // Set MegaTrainerXL flag indicating edited save - } - } - this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw - - // Worker keyboard shortcuts that would normally go to patch_Main_Screen_Form_issue_command - // unfortunately get short-circuited if a district is on a tile and the default popup to replace a "mine" is shown. - // The only way to catch these beforehand I've found it is to intercept the key event here. - } else if (is->current_config.enable_districts && - p_main_screen_form->Current_Unit != NULL && - is_down && - is_worker (p_main_screen_form->Current_Unit)) { - int command = -1; - bool removed_existing = false; - if (virtual_key_code == VK_M && is_command_button_active (&this->GUI, UCV_Build_Mine)) command = UCV_Build_Mine; - else if (virtual_key_code == VK_I && is_command_button_active (&this->GUI, UCV_Irrigate)) command = UCV_Irrigate; - else if (virtual_key_code == VK_N && is_command_button_active (&this->GUI, UCV_Plant_Forest)) command = UCV_Plant_Forest; - - if (handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) { - Main_Screen_Form_issue_command (this, __, command, p_main_screen_form->Current_Unit); - } - } - -after_district_key_handling: - Main_Screen_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); -} - -int __fastcall -patch_Unit_get_move_points_after_airdrop (Unit * this) -{ - int prev_airdrop_count = itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0); - itable_insert (&is->airdrops_this_turn, this->Body.ID, prev_airdrop_count + 1); - - return is->current_config.dont_end_units_turn_after_airdrop ? this->Body.Moves : patch_Unit_get_max_move_points (this); -} - -int __fastcall -patch_Unit_get_move_points_after_set_to_intercept (Unit * this) -{ - return is->current_config.patch_intercept_lost_turn_bug ? this->Body.Moves : patch_Unit_get_max_move_points (this); -} - -void __cdecl -activate_mod_info_button (int control_id) -{ - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - char s[500]; - char version_letter = 'A' + MOD_VERSION%100; - - if (MOD_PREVIEW_VERSION == 0) - snprintf (s, sizeof s, "%s: %d%c", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' '); - else - snprintf (s, sizeof s, "%s: %d%c%s %d", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' ', is->c3x_labels[CL_PREVIEW], MOD_PREVIEW_VERSION); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_CONFIG_FILES_LOADED]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - int n = 1; - for (struct loaded_config_name * lcn = is->loaded_config_names; lcn != NULL; lcn = lcn->next) { - snprintf (s, sizeof s, "^ %d. %s", n, lcn->name); - s[(sizeof s) - 1] = '\0'; - n++; - PopupForm_add_text (popup, __, s, 0); - } - - patch_show_popup (popup, __, 0, 0); -} - -int __fastcall -patch_Parameters_Form_m68_Show_Dialog (Parameters_Form * this, int edx, int param_1, void * param_2, void * param_3) -{ - init_mod_info_button_images (); - - // "b" is the mod info button. It's created each time the preferences form (or "parameters" form as Antal called it) is opened and destroyed - // every time the form is closed. This is the easiest way since it matches how the base game works. At first I tried creating the button once - // but then it will only appear once since its attachment to the prefs form is lost when the form is destroyed on closure. I tried reattaching - // the button to each newly created form but wasn't able to make that work. - Button * b = NULL; - if (is->mod_info_button_images_state == IS_OK) { - b = malloc (sizeof *b); - Button_construct (b); - - Button_initialize (b, __, - is->c3x_labels[CL_MOD_INFO_BUTTON_TEXT], // text - MOD_INFO_BUTTON_ID, // control ID - (p_bic_data->ScreenWidth - 1024) / 2 + 891, // location x - (p_bic_data->ScreenHeight - 768) / 2 + 31, // location y - MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height - (Base_Form *)this, // parent - 0); // ? - - for (int n = 0; n < 3; n++) - b->Images[n] = &is->mod_info_button_images[n]; - PCX_Image_set_font (&b->Base_Data.Canvas, __, get_font (15, FSF_NONE), 0, 0, 0); - b->activation_handler = &activate_mod_info_button; - - // Need to draw once manually or the button won't look right - b->vtable->m73_call_m22_Draw ((Base_Form *)b); - } - - int tr = Parameters_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); - - if (b != NULL) { - b->vtable->destruct ((Base_Form *)b, __, 0); - free (b); - } - - return tr; -} - -bool __fastcall -patch_City_cycle_specialist_type (City * this, int edx, int mouse_x, int mouse_y, Citizen * citizen, City_Form * city_form) -{ - int specialist_count = 0; { - Leader * city_owner = &leaders[this->Body.CivID]; - for (int n = 0; n < p_bic_data->CitizenTypeCount; n++) - specialist_count += (n != p_bic_data->default_citizen_type) && - Leader_has_tech (city_owner, __, p_bic_data->CitizenTypes[n].RequireID); - } - int shift_down = (*p_GetAsyncKeyState) (VK_SHIFT) >> 8; - int original_worker_type = citizen->WorkerType; - - // The return value of this function is not actually used by either of the two original callers. - bool tr = City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); - - // Cycle all the way around back to the previous specialist type, if appropriate. - // If the worker type was not changed after the first call to cycle_specialist_type, that indicates that the player was asked to disable - // governor management and chose not to. Do not try to cycle backwards in that case or else we'll spam the player with more popups. - if (is->current_config.reverse_specialist_order_with_shift && - shift_down && (specialist_count > 2) && (citizen->WorkerType != original_worker_type)) { - for (int n = 0; n < specialist_count - 2; n++) - City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); - } - - return tr; -} - -int __fastcall -patch_City_get_pollution_from_pop (City * this) -{ - if (! is->current_config.enable_negative_pop_pollution) - return City_get_pollution_from_pop (this); - - int base_pollution = this->Body.Population.Size - p_bic_data->General.MaximumSize_City; - if (base_pollution <= 0) - return 0; - - // Consider improvements - int net_pollution = base_pollution; - int any_cleaning_improvs = 0; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * improv = &p_bic_data->Improvements[n]; - if ((improv->ImprovementFlags & ITF_Removes_Population_Pollution) && has_active_building (this, n)) { - any_cleaning_improvs = 1; - if (improv->Pollution < 0) - net_pollution += improv->Pollution; - } - } - - if (net_pollution <= 0) - return 0; - else if (any_cleaning_improvs) - return 1; - else - return net_pollution; -} - -// The original version of this function in the base game contains a duplicate of the logic that computes the total pollution from buildings and -// pop. By re-implementing it to use the get_pollution_from_* functions, we ensure that our changes to get_pollution_from_pop will be accounted for. -// Note: This function is called from two places, one is the city screen and the other I'm not sure about. The pollution spawning logic works by -// calling the get_pollution_from_* funcs directly. -int __fastcall -patch_City_get_total_pollution (City * this) -{ - return City_get_pollution_from_buildings (this) + patch_City_get_pollution_from_pop (this); -} - -void remove_extra_palaces (City * city, City * excluded_destination); - -void -set_wonder_built_flag (int improv_id, bool is_built) -{ - if ((p_match == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) - return; - - byte * built_flags = *(byte **)((byte *)p_match + 0x4fc); - if (built_flags == NULL) - return; - - built_flags[improv_id] = is_built; -} - -bool -choose_defensive_unit_order (City * city, City_Order * out_order) -{ - if ((city == NULL) || (out_order == NULL)) - return false; - - for (int pass = 0; pass < 3; pass++) { - int best_unit_id = -1; - int best_defence = -1; - - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if (! patch_City_can_build_unit (city, __, n, 1, 0, 0)) - continue; - - int defence = type->Defence; - if ((pass < 2) && (defence <= 0)) - continue; - if ((pass <= 1) && (type->Unit_Class != UTC_Land)) - continue; - if ((pass == 0) && ((type->AI_Strategy & UTAI_Defence) == 0)) - continue; - - if (defence > best_defence) { - best_defence = defence; - best_unit_id = n; - } - } - - if (best_unit_id >= 0) { - out_order->OrderType = COT_Unit; - out_order->OrderID = best_unit_id; - return true; - } - } - - return false; -} - -// When a city adds a building that depends on a district, optionally mirror that -// building to all other same-civ cities that can also work the district tile. -void -copy_building_with_cities_in_radius (City * source, int improv_id, int required_district_id, int tile_x, int tile_y) -{ - if (! is->current_config.enable_districts) return; - if (source == NULL) return; - - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - - if (is_wonder) { - if (! is->current_config.cities_with_mutual_district_receive_wonders) - return; - } else if (! is->current_config.cities_with_mutual_district_receive_buildings) - return; - - // If a Wonder, we know the specific tile it is at, so determine which other cities have that in work radius. - if (is_wonder) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile == p_null_tile) return; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != source->Body.CivID) return; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != required_district_id) return; - if (! district_is_complete (tile, required_district_id)) return; - - FOR_CITIES_OF (coi, source->Body.CivID) { - City * city = coi.city; - if (city == NULL) continue; - if (city == source) continue; - - if (! city_radius_contains_tile (city, tile_x, tile_y)) - continue; - - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) - continue; - - if (! patch_City_has_improvement (city, __, improv_id, false)) { - City_add_or_remove_improvement (city, __, improv_id, 1, false); - } - } - } - // Else there may be multiple district instances of this type, so check each tile around the city - else { - FOR_DISTRICTS_AROUND (wai, source->Body.X, source->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != required_district_id) continue; - - FOR_CITIES_OF (coi, source->Body.CivID) { - City * city = coi.city; - if (city == NULL) continue; - if (city == source) continue; - - if (! city_radius_contains_tile (city, x, y)) - continue; - - if (! patch_City_has_improvement (city, __, improv_id, false)) { - City_add_or_remove_improvement (city, __, improv_id, 1, false); - - // If city already building it, switch to a defensive unit instead - int current_improv_id = city->Body.Order_ID; - if (current_improv_id == improv_id) { - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - // Show message to user - if (is->current_config.show_message_when_building_received_by_mutual_district && - city->Body.CivID == p_main_screen_form->Player_CivID) { - char msg[300]; - snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_RECEIVED], - p_bic_data->Improvements[improv_id].Name.S, - is->c3x_labels[CL_FROM_SHARED], - is->district_configs[required_district_id].name, - is->c3x_labels[CL_WITH], - source->Body.CityName); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - } - } - } - } -} - -void -grant_existing_district_buildings_to_city (City * city) -{ - if (! is->current_config.enable_districts || - (! is->current_config.cities_with_mutual_district_receive_buildings && - ! is->current_config.cities_with_mutual_district_receive_wonders) || - (city == NULL)) - return; - - int civ_id = city->Body.CivID; - int current_improv_id = city->Body.Order_ID; - bool prev_flag = is->sharing_buildings_by_districts_in_progress; - is->sharing_buildings_by_districts_in_progress = true; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - Tile * tile = wai.tile; - - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - struct district_infos * info = &is->district_infos[district_id]; - if (info->dependent_building_count <= 0) - continue; - - FOR_CITIES_OF (coi, civ_id) { - City * other = coi.city; - if ((other == NULL) || (other == city)) - continue; - - if (! city_radius_contains_tile (other, wai.tile_x, wai.tile_y)) - continue; - - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != other->Body.CivID) - continue; - - for (int i = 0; i < info->dependent_building_count; i++) { - int building_id = info->dependent_building_ids[i]; - if (building_id < 0) - continue; - - Improvement * building = &p_bic_data->Improvements[building_id]; - bool is_wonder = (building->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - - if (is_wonder) - continue; - - if (! patch_City_has_improvement (other, __, building_id, false)) - continue; - - if (patch_City_has_improvement (city, __, building_id, false)) - continue; - - City_add_or_remove_improvement (city, __, building_id, 1, false); - - // If city already building it, switch to a defensive unit instead - if (current_improv_id == building_id) { - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - if (is->current_config.show_message_when_building_received_by_mutual_district && - city->Body.CivID == p_main_screen_form->Player_CivID) { - char msg[300]; - snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_RECEIVED], - p_bic_data->Improvements[building_id].Name.S, - is->c3x_labels[CL_FROM_SHARED], - is->district_configs[district_id].name, - is->c3x_labels[CL_WITH], - other->Body.CityName); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - } - } - } - - is->sharing_buildings_by_districts_in_progress = prev_flag; -} - -void -auto_build_great_wall_districts_for_civ (int civ_id) -{ - if ((! is->current_config.enable_districts) || - (! is->current_config.enable_great_wall_districts) || - (! is->current_config.auto_build_great_wall_around_territory) || - (is->great_wall_auto_build == GWABS_DONE) || - (civ_id < 0) || - is->is_placing_scenario_things) - return; - - bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; - - if ((GREAT_WALL_DISTRICT_ID < 0) || (GREAT_WALL_DISTRICT_ID >= is->district_count)) { - is->great_wall_auto_build = GWABS_DONE; - return; - } - - init_tile_highlights (); - - struct district_config const * cfg = &is->district_configs[GREAT_WALL_DISTRICT_ID]; - if ((cfg->command == -1) || (! leader_can_build_district (&leaders[civ_id], GREAT_WALL_DISTRICT_ID))) { - is->great_wall_auto_build = GWABS_DONE; - return; - } - - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_BEGIN_GREAT_WALL_AUTO_BUILD", -1, 0, 0, 0); - if (civ_id == p_main_screen_form->Player_CivID) - patch_show_popup (popup, __, 0, 0); - - is->great_wall_auto_build = GWABS_RUNNING; - - unsigned int const replaceable_flags = TILE_FLAG_MINE | TILE_FLAG_IRRIGATION; - bool require_other_civ_border = (! is_human) && is->current_config.ai_auto_build_great_wall_strategy == AAGWS_OTHER_CIV_BORDERED_ONLY; - - for (int index = 0; index < p_bic_data->Map.TileCount; index++) { - int x, y; - tile_index_to_coords (&p_bic_data->Map, index, &x, &y); - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->CityID >= 0) - continue; - if (tile->vtable->m35_Check_Is_Water (tile)) - continue; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) - continue; - - bool has_border = false; - bool has_other_civ_border = false; - FOR_TILES_AROUND (tai, 9, x, y) { - if (tai.n == 0) - continue; - Tile * neighbor = tai.tile; - if (neighbor->vtable->m35_Check_Is_Water (neighbor)) - continue; - int owner_id = neighbor->vtable->m38_Get_Territory_OwnerID (neighbor); - if (owner_id != civ_id) { - has_border = true; - if (owner_id > 0) { - has_other_civ_border = true; - break; - } - } - } - if (! has_border) - continue; - if (require_other_civ_border && (! has_other_civ_border)) - continue; - - if (! district_is_buildable_on_tile (cfg, tile)) - continue; - if (! district_resource_prereqs_met (tile, x, y, GREAT_WALL_DISTRICT_ID)) - continue; - - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == GREAT_WALL_DISTRICT_ID)) { - if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) { - inst->state = DS_COMPLETED; - if (! tile->vtable->m18_Check_Mines (tile, __, 0)) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); - set_tile_unworkable_for_all_cities (tile, x, y); - } - continue; - } - - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int replace_flags = overlay_flags & replaceable_flags; - bool has_district = (inst != NULL); - int existing_district_id = -1; - if (has_district) - existing_district_id = inst->district_id; - - if (is_human && civ_id == p_main_screen_form->Player_CivID) { - is->focused_tile = tile; - Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, x, y, 0, true, false); - - char * popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL"; - set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); - - if (has_district) { - bool redundant_district = district_instance_is_redundant (inst, tile); - bool would_lose_buildings; - would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, x, y); - if (redundant_district) - would_lose_buildings = false; - if ((existing_district_id >= 0) && (existing_district_id < is->district_count)) { - set_popup_str_param (1, (char *)is->district_configs[existing_district_id].display_name, -1, -1); - } - popup_key = would_lose_buildings - ? "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT" - : "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT_SAFE"; - } else if (replace_flags != 0) { - popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_IMPROVEMENT"; - } - - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - popup_key, - -1, 0, 0, 0); - - int sel = patch_show_popup (popup, __, 0, 0); - if (sel != 0) - continue; - } - - if (has_district || (replace_flags != 0)) { - if (has_district) { - int inst_x = x, inst_y = y; - if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) - continue; - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); - handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); - } - - if (replace_flags != 0) - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, replace_flags, x, y); - } - - if (get_district_instance (tile) != NULL) - continue; - - inst = ensure_district_instance (tile, GREAT_WALL_DISTRICT_ID, x, y); - if (inst == NULL) - continue; - - inst->district_id = GREAT_WALL_DISTRICT_ID; - district_instance_set_coords (inst, x, y); - inst->state = DS_COMPLETED; - if (! tile->vtable->m18_Check_Mines (tile, __, 0)) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); - set_tile_unworkable_for_all_cities (tile, x, y); - } - - is->great_wall_auto_build = GWABS_DONE; - is->focused_tile = NULL; -} - -//We need to forwards-declare this -void __fastcall -patch_City_manage_by_governor (City * this, int edx, bool manage_professions); - -void __fastcall -patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3) -{ - int init_maintenance = this->Body.Improvements_Maintenance; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder_removal = (! add) && - ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && - (! is->is_placing_scenario_things); - int init_work_area_radius = get_work_ring_limit_total(this); - - // The enable_negative_pop_pollution feature changes the rules so that improvements flagged as removing pop pollution and having a negative - // pollution amount contribute to the city's pop pollution instead of building pollution. Here we make sure that such improvements do not - // contribute to building pollution by temporarily zeroing out their pollution stat when they're added to or removed from a city. - if (is->current_config.enable_negative_pop_pollution && - (improv->ImprovementFlags & ITF_Removes_Population_Pollution) && - (improv->Pollution < 0)) { - int saved_pollution_amount = improv->Pollution; - improv->Pollution = 0; - City_add_or_remove_improvement (this, __, improv_id, add, param_3); - improv->Pollution = saved_pollution_amount; - } else - City_add_or_remove_improvement (this, __, improv_id, add, param_3); - - if (is->current_config.enable_districts && is_wonder_removal && ((improv->Characteristics & ITC_Wonder) != 0)) { - if (is->current_config.destroyed_wonders_can_be_built_again) - set_wonder_built_flag (improv_id, false); - - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, improv->Name.S, -1, -1); - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - is->current_config.destroyed_wonders_can_be_built_again ? "C3X_DISTRICT_WONDER_DESTROYED_REBUILD" : "C3X_DISTRICT_WONDER_DESTROYED", - -1, 0, 0, 0 - ); - patch_show_popup (popup, __, 0, 0); - } - - // If the city just finished a wonder and was using a wonder district for that, set the wonder - // as completed (which switches the art over and prevents the tile from being used again) - int x, y; - if (add && is->current_config.enable_districts && is->current_config.enable_wonder_districts) { - if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { - int matched_windex = find_wonder_config_index_by_improvement_id (improv_id); - - if (matched_windex >= 0) { - FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { - x = wai.tile_x; - y = wai.tile_y; - Tile * t = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - if (! wonder_is_buildable_on_tile (t, improv_id)) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if (info->state != WDS_UNDER_CONSTRUCTION) continue; - if (info->city_id != this->Body.ID) continue; - - // Mark this wonder district as completed with the wonder - info->city = this; - info->city_id = this->Body.ID; - info->state = WDS_COMPLETED; - info->wonder_index = matched_windex; - break; - } - } - } - } - - int gw_auto_build_improv_id = is->current_config.great_wall_auto_build_wonder_improv_id; - if (add && is->current_config.enable_districts && - is->current_config.auto_build_great_wall_around_territory && - (gw_auto_build_improv_id >= 0) && (improv_id == gw_auto_build_improv_id)) - auto_build_great_wall_districts_for_civ (this->Body.CivID); - - //Calculate if work_area has shrunk, and if so, redistribute citizens. - int post_work_area_radius = get_work_ring_limit_total(this); - if (post_work_area_radius < init_work_area_radius) { - patch_City_manage_by_governor(this, __, false); - } - - // Update things in case we've added or removed a mill. This is only necessary while in-game. If the game is still loading the scenario, it - // will recompute resources after it's done and we'll recompute yields and happiness ourselves. - if (! is->is_placing_scenario_things) { - // Collect info about this mill, if in fact the added or removed improvement is a mill. If it's not, all these vars will be left - // false. "generates_input" tracks whether or not the mill generates a resource that's an input for another mill. - bool is_non_local_mill, is_yielding_mill, generates_input; { - is_non_local_mill = is_yielding_mill = generates_input = false; - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if (mill->improv_id == improv_id) { - is_non_local_mill |= (mill->flags & MF_LOCAL) == 0; - is_yielding_mill |= (mill->flags & MF_YIELDS) != 0; - generates_input |= (is->mill_input_resource_bits[mill->resource_id >> 3] & (1 << (mill->resource_id & 7))) != 0; - } - } - } - - // If the mill generates a resource that's added to the trade network or it's generating an input (potentially used locally to - // generate a traded resource) then rebuild the resource network. This is not necessary if the improvement also affects trade routes - // since the base method will have already done this recomputation. - if ((is_non_local_mill || generates_input) && - ((improv->ImprovementFlags & ITF_Allows_Water_Trade) == 0) && - ((improv->ImprovementFlags & ITF_Allows_Air_Trade) == 0) && - ((improv->WonderFlags & ITW_Safe_Sea_Travel) == 0)) - patch_Trade_Net_recompute_resources (is->trade_net, __, 0); - - // If the mill adds yields or might be a link in a resource production chain that does, recompute yields in the city. - if (is_yielding_mill || generates_input) - patch_City_recompute_yields_and_happiness (this); - } - - // Adding or removing an obsolete improvement should not change the total maintenance since obsolete improvs shouldn't cost maintenance. In - // the base game, they usually do since the game doesn't update maintenance costs when buildings are obsoleted, but with that bug patched we - // can enforce the correct behavior. - if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && - (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) - this->Body.Improvements_Maintenance = init_maintenance; - - // If AI MCS is enabled and we've added the Palace to a city, then remove any extra palaces from that city. If we're in the process of - // capturing a city, it's necessary to exclude that city as a possible destination for removed extra palaces. - if ((is->current_config.ai_multi_city_start > 1) && - (! is->is_placing_scenario_things) && - add && (improv->ImprovementFlags & ITF_Center_of_Empire) && - ((*p_human_player_bits & (1 << this->Body.CivID)) == 0)) - remove_extra_palaces (this, is->currently_capturing_city); - - // If sharing wonders in hotseat mode, we must recompute improvement maintenance for all human players when any one of them gains or loses a - // wonder that grants free improvements. - if ((! is->is_placing_scenario_things) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->Body.CivID) & *p_human_player_bits)) { // is this city owned by a human player - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->Body.CivID)) - Leader_recompute_buildings_maintenance (&leaders[n_player]); - player_bits >>= 1; - n_player++; - } - } - - // Optionally share district-dependent buildings or wonders to other cities in range of the same district - bool allow_wonder_sharing = is->current_config.cities_with_mutual_district_receive_wonders; - bool allow_building_sharing = is->current_config.cities_with_mutual_district_receive_buildings; - - if ((! is->is_placing_scenario_things) && add && - is->current_config.enable_districts && (allow_building_sharing || allow_wonder_sharing) && - (! is->sharing_buildings_by_districts_in_progress)) { - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); - if (prereq_list != NULL) { - bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - if ((! is_wonder && allow_building_sharing) || (is_wonder && allow_wonder_sharing)) { - is->sharing_buildings_by_districts_in_progress = true; - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - copy_building_with_cities_in_radius (this, improv_id, district_id, x, y); - } - is->sharing_buildings_by_districts_in_progress = false; - } - } - } -} - -void __fastcall -patch_Fighter_begin (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender) -{ - Fighter_begin (this, __, attacker, attack_direction, defender); - - // Apply override of retreat eligibility - // Must use this->defender instead of the defender argument since the argument is often NULL, in which case Fighter_begin finds a defender on - // the target tile and stores it in this->defender. Also must check that against NULL since Fighter_begin might fail to find a defender. - enum UnitTypeClasses class = p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID].Unit_Class; - if ((this->defender != NULL) && ((class == UTC_Land) || (class == UTC_Sea))) { - enum retreat_rules retreat_rules = (class == UTC_Land) ? is->current_config.land_retreat_rules : is->current_config.sea_retreat_rules; - if (retreat_rules != RR_STANDARD) { - int attacker_max_mp = patch_Unit_get_max_move_points (this->attacker), - defender_max_mp = patch_Unit_get_max_move_points (this->defender); - - if (retreat_rules == RR_NONE) - this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 0; - else if (retreat_rules == RR_ALL_UNITS) - this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 1; - else if (retreat_rules == RR_IF_FASTER) { - this->attacker_eligible_to_retreat = attacker_max_mp > defender_max_mp; - this->defender_eligible_to_retreat = defender_max_mp > attacker_max_mp; - } else if (retreat_rules == RR_IF_NOT_SLOWER) { - this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp; - this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp; - } else if (retreat_rules == RR_IF_FAST_AND_NOT_SLOWER) { - this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp && attacker_max_mp > p_bic_data->General.RoadsMovementRate; - this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp && defender_max_mp > p_bic_data->General.RoadsMovementRate; - } - - // Prevent immobile units from retreating - this->attacker_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID], __, UTA_Immobile); - this->defender_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->defender->Body.UnitTypeID], __, UTA_Immobile); - - // Prevent defender from retreating if in a city - this->defender_eligible_to_retreat &= city_at (this->defender_location_x, this->defender_location_y) == NULL; - } - } -} - -void __fastcall -patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) -{ - // Determine whether this despawn happened involuntarily, i.e. whether it's because of the actions of a player other than its owner. This - // includes cases where the unit was destroyed in combat, captured, kicked from territory with nowhere to go, etc. - int ret_addr = ((int *)&civ_id_responsible)[-1]; - bool involuntary = - ret_addr == DESPAWN_TO_FIGHT_1_RETURN || ret_addr == DESPAWN_TO_FIGHT_2_RETURN - || ret_addr == DESPAWN_TO_DO_BOMBARD_TILE_RETURN || ret_addr == DESPAWN_TO_CRUISE_MISSILE_DEFENDER_RETURN - || ret_addr == DESPAWN_TO_BOUNCE_TRESPASSING_UNITS_RETURN || ret_addr == DESPAWN_TO_NUKE_DAMAGE_RETURN - || ret_addr == DESPAWN_RECURSIVE_RETURN || ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN - || ret_addr == DESPAWN_TO_TRY_FLYING_OVER_TILE_RETURN; - - int owner_id = this->Body.CivID; - int type_id = this->Body.UnitTypeID; - UnitType * type = &p_bic_data->UnitTypes[type_id]; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - // Clear extra DBs, airdrops, wait records, and transport ties used by this unit - itable_remove (&is->extra_defensive_bombards, this->Body.ID); - itable_remove (&is->airdrops_this_turn, this->Body.ID); - itable_remove (&is->waiting_units, this->Body.ID); - itable_remove (&is->unit_transport_ties, this->Body.ID); - - // If we're despawning the stored ZoC defender, clear that variable so we don't despawn it again in check_life_after_zoc - if (this == is->zoc_defender) - is->zoc_defender = NULL; - - if (this == is->sb_next_up) - is->sb_next_up = NULL; - - if (this == is->last_selected_unit.ptr) - is->last_selected_unit.ptr = NULL; - - // Remove this unit from the list of extra units to despawn after capturing - int original_count = is->count_extra_capture_despawns; - for (int n_src = 0, n_dest = 0; n_src < original_count; n_src++) { - if (is->extra_capture_despawns[n_src] != this) { - is->extra_capture_despawns[n_dest] = is->extra_capture_despawns[n_src]; - n_dest++; - } else - is->count_extra_capture_despawns -= 1; - } - - // If the unit being despawned is a land transport or helicopter, we may have to make sure to despawn its passengers as well because the base - // game won't. In general, the passengers are lost if the transport was despawned involuntarily, i.e. because of another player's attack or - // something like that, or if the passengers couldn't survive outside the transport, specifically because it's a helicopter at sea. - bool must_despawn_passengers = false; { - if (is_land_transport (this)) - must_despawn_passengers = involuntary && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); - - else if (type->Unit_Class == UTC_Air && type->Transport_Capacity > 0) { // if "this" is a helicopter - Unit * container = get_unit_ptr (this->Body.Container_Unit); - bool on_carrier = container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea && - Unit_has_ability (container, __, UTA_Transports_Only_Aircraft); - bool passengers_could_survive = Tile_has_city (tile) || ! tile->vtable->m35_Check_Is_Water (tile); - - // If no-defense-from-inside is off, passengers in helicopters will fight to defend their tile, so they wouldn't be left - // inside the helicopter when their tile is taken. If it's on, an occupied heli can be destroyed or captured by a land unit, - // and we must make sure to despawn the passengers in that case because they can't remain on the tile. Hence, - // no-defense-from-inside implies no-escape in almost all circumstances (nukes are the exception). - enum special_helicopter_rules special_rules = is->current_config.special_helicopter_rules; - if (((special_rules & SHR_ALLOW_ON_CARRIERS) && on_carrier) || (special_rules & (SHR_NO_DEFENSE_FROM_INSIDE | SHR_NO_ESCAPE))) - must_despawn_passengers = involuntary || ! passengers_could_survive; - } - } - - bool prev_always_despawn_passengers = is->always_despawn_passengers; - - if (must_despawn_passengers) { - // If we've been called from do_capture_units, record the passengers in the list of units to be despawned after do_capture_units - // returns. We can't simply despawn the units now even by setting always_despawn_passengers because the despawning messes up an - // iterator over tile units inside do_capture_units. - if (ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN) { - FOR_UNITS_ON (uti, tile) - if (uti.unit->Body.Container_Unit == this->Body.ID) { - reserve (sizeof is->extra_capture_despawns[0], // item size - (void **)&is->extra_capture_despawns, // ptr to items - &is->extra_capture_despawns_capacity, // ptr to capacity - is->count_extra_capture_despawns); // count - is->extra_capture_despawns[is->count_extra_capture_despawns] = uti.unit; - is->count_extra_capture_despawns += 1; - } - - } else - is->always_despawn_passengers = true; - } - - Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); - - is->always_despawn_passengers = prev_always_despawn_passengers; - - change_unit_type_count (&leaders[owner_id], type_id, -1); -} - -bool __fastcall -patch_Unit_do_capture_units (Unit * this, int edx, int tile_x, int tile_y, int owner_civ_id) -{ - is->count_extra_capture_despawns = 0; - - bool tr = Unit_do_capture_units (this, __, tile_x, tile_y, owner_civ_id); - - // Here we rely on patch_Unit_despawn to remove despawned units from the list - while (is->count_extra_capture_despawns > 0) - patch_Unit_despawn (is->extra_capture_despawns[0], __, this->Body.ID, 0, 0, 0, 0, 0, 0); - - return tr; -} - -void __fastcall -patch_Map_Renderer_m71_Draw_Tiles (Map_Renderer * this, int edx, int param_1, int param_2, int param_3) -{ - // Restore the tile count if it was saved by recompute_resources. This is necessary because the Draw_Tiles method loops over all tiles. - if (is->saved_tile_count >= 0) { - p_bic_data->Map.TileCount = is->saved_tile_count; - is->saved_tile_count = -1; - } - - Map_Renderer_m71_Draw_Tiles (this, __, param_1, param_2, param_3); -} - -struct named_tile_entry * -get_named_tile_entry (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - int stored_ptr = 0; - if (! itable_look_up (&is->named_tile_map, (int)tile, &stored_ptr)) - return NULL; - return (struct named_tile_entry *)stored_ptr; -} - -bool -prompt_for_named_tile (char const * seed_name, char * out_name, int out_len) -{ - if ((out_name == NULL) || (out_len <= 0)) - return false; - out_name[0] = '\0'; - - PopupForm * popup = get_popup_form (); - if (popup == NULL) - return false; - - char seed_buf[101]; - if (seed_name == NULL) - seed_name = ""; - strncpy (seed_buf, seed_name, sizeof seed_buf); - seed_buf[(sizeof seed_buf) - 1] = '\0'; - if (seed_buf[0] == '\0') - strncpy (seed_buf, "Tile", sizeof seed_buf); - - set_popup_str_param (0, seed_buf, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "RENAME_CITY", 0x64, (int)seed_buf, 0x44, 0); - int sel = patch_show_popup (popup, __, 0, 0); - is->focused_tile = NULL; - if (sel != 0) - return false; - - if (temp_ui_strs[0][0] == '\0') - return true; - - strncpy (out_name, temp_ui_strs[0], out_len); - out_name[out_len - 1] = '\0'; - return true; -} - -void -handle_named_tile_menu_selection (void) -{ - int tile_x = is->named_tile_menu_tile_x; - int tile_y = is->named_tile_menu_tile_y; - Tile * tile = tile_at (tile_x, tile_y); - if (! tile_can_be_named (tile, tile_x, tile_y)) - return; - - init_tile_highlights (); - - struct named_tile_entry * entry = get_named_tile_entry (tile); - char const * current_name = (entry != NULL) ? entry->name : ""; - char new_name[100]; - is->focused_tile = tile; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - bool got_name = prompt_for_named_tile (current_name, new_name, sizeof new_name); - is->focused_tile = NULL; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - if (! got_name) - return; - - set_named_tile_entry (tile, tile_x, tile_y, new_name); - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -void __fastcall -patch_Main_Screen_Form_handle_right_click_on_tile (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) -{ - if (is->current_config.enable_named_tiles) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile_can_be_named (tile, tile_x, tile_y) && ! Tile_has_city (tile)) { - is->named_tile_menu_active = true; - is->named_tile_menu_tile_x = tile_x; - is->named_tile_menu_tile_y = tile_y; - Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); - is->named_tile_menu_active = false; - return; - } - } - - Main_Screen_Form_handle_right_click_on_tile (this, __, tile_x, tile_y, mouse_x, mouse_y); -} - -void __fastcall -patch_Main_Screen_Form_open_right_click_menu (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) -{ - bool set_active = false; - if (!is->named_tile_menu_active && is->current_config.enable_named_tiles) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile_can_be_named (tile, tile_x, tile_y)) { - is->named_tile_menu_active = true; - is->named_tile_menu_tile_x = tile_x; - is->named_tile_menu_tile_y = tile_y; - set_active = true; - } - } - Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); - if (set_active) - is->named_tile_menu_active = false; -} - -void -draw_map_tile_text (Main_Screen_Form * this, PCX_Image * canvas, char * text, int screen_x, int screen_y, int base_screen_height, int y_offset) -{ - int is_zoomed_out = (p_bic_data->is_zoomed_out != false); - int scale = is_zoomed_out ? 2 : 1; - int screen_width = 128 / scale; - int screen_height = base_screen_height / scale; - int text_width = screen_width - (is_zoomed_out ? 4 : 8); - if (text_width < 12) - text_width = screen_width; - - int text_left = screen_x + (screen_width - text_width) / 2; - int draw_y = screen_y - y_offset; - int text_top = draw_y + screen_height + (is_zoomed_out ? 2 : 4); - - Object_66C3FC * font = get_font (10, FSF_NONE); - if (font != NULL) { - PCX_Image_set_text_effects (canvas, __, 0x80FFFFFF, 0x80000000, 1, 1); - PCX_Image_draw_centered_text (canvas, __, font, text, text_left, text_top - 10, text_width, strlen (text)); - } -} - -void __fastcall -patch_Main_Screen_Form_draw_city_hud (Main_Screen_Form * this, int edx, PCX_Image * canvas) -{ - Main_Screen_Form_draw_city_hud (this, __, canvas); - - bool draw_natural_wonders = is->current_config.enable_natural_wonders && - is->current_config.show_natural_wonder_name_on_map; - bool draw_named_tiles = is->current_config.enable_named_tiles; - if (!draw_natural_wonders && !draw_named_tiles) - return; - - if (canvas == NULL) - canvas = &this->Base_Data.Canvas; - - if ((canvas == NULL) || (canvas->JGL.Image == NULL)) - return; - - if (draw_natural_wonders) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - - int natural_id = inst->natural_wonder_info.natural_wonder_id; - if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) - continue; - - struct natural_wonder_district_config const * nw_cfg = &is->natural_wonder_configs[natural_id]; - if ((nw_cfg == NULL) || (nw_cfg->name == NULL) || (nw_cfg->name[0] == '\0')) - continue; - - Tile * tile = (Tile *)tei.key; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int tile_x, tile_y; - if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - continue; - - int screen_x, screen_y; - Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); - - draw_map_tile_text (this, canvas, (char *)nw_cfg->name, screen_x, screen_y, 88, 88 - 64); - } - } - - if (draw_named_tiles) { - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if ((entry == NULL) || (entry->name[0] == '\0')) - continue; - - Tile * tile = (Tile *)tei.key; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int tile_x, tile_y; - if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) { - tile_x = entry->tile_x; - tile_y = entry->tile_y; - tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - } - - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) - continue; - - int screen_x, screen_y; - Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); - - draw_map_tile_text (this, canvas, entry->name, screen_x, screen_y, 64, 3); - } - } -} - -// Returns whether or not city has an "extra palace", a concept used by the AI multi-city start. Extra palaces are small wonders that reduce -// corruption (e.g. forbidden palace) that are listed under the ai_multi_start_extra_palaces config option. -bool -has_extra_palace (City * city) -{ - for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { - int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) && - (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && - (leaders[city->Body.CivID].Small_Wonders[improv_id] == city->Body.ID)) { - return true; - } - } - return false; -} - -// Removes any extra palaces from this city to other cities owned by the same player (if possible). Does not check that the city belongs to an AI or -// that AI MCS is enabled. -void -remove_extra_palaces (City * city, City * excluded_destination) -{ - Leader * leader = &leaders[city->Body.CivID]; - int extra_palace_lost; - do { - // Search for an extra palace in the city and delete it. Remember its ID so we can put it elsewhere. - extra_palace_lost = -1; - for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { - int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) && - (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && - (leader->Small_Wonders[improv_id] == city->Body.ID)) { - patch_City_add_or_remove_improvement (city, __, improv_id, 0, false); - extra_palace_lost = improv_id; - break; - } - } - - // Replace the lost extra palace like what happens to the real palace - if (extra_palace_lost >= 0) { - int best_rating = -1; - City * best_location = NULL; - FOR_CITIES_OF (coi, leader->ID) { - City * candidate = coi.city; - if ((candidate != city) && - (candidate->Body.ID != leader->CapitalID) && - (candidate != excluded_destination) && - ! has_extra_palace (candidate)) { - - // Rate this candidate as a possible (extra) palace location. The criteria we use to rate it are identical to - // what the base game uses to find a new location for the palace. - int rating = 0; - rating += candidate->Body.Population.Size; - rating += count_units_at (candidate->Body.X, candidate->Body.Y, UF_4, -1, 0, -1); - rating += 2 * City_count_citizens_of_race (candidate, __, leader->RaceID); - FOR_TILES_AROUND (tai, 0x121, candidate->Body.X, candidate->Body.Y) { - if (tai.n == 0) - continue; - City * neighbor = get_city_ptr (tai.tile->CityID); - if ((neighbor != NULL) && (neighbor != city) && (neighbor->Body.CivID == leader->ID)) { - int size = neighbor->Body.Population.Size; - if (size > p_bic_data->General.MaximumSize_City) rating += 3; - else if (size > p_bic_data->General.MaximumSize_Town) rating += 2; - else rating += 1; - } - } - - if (rating > best_rating) { - best_rating = rating; - best_location = candidate; - } - } - } - - if (best_location != NULL) - City_add_or_remove_improvement (best_location, __, extra_palace_lost, 1, false); - } - } while (extra_palace_lost >= 0); -} - -// Give a city any completed wonder districts in work radius, if cities_with_mutual_district_receive_wonders is true. -// This is essentially for cases where the original Wonder-constructing city is lost and a new city is built -// that can work the same wonder district tile. -void -grant_nearby_wonders_to_city (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_wonder_districts || - ! is->current_config.cities_with_mutual_district_receive_wonders || - (city == NULL)) - return; - - bool prev_flag = is->sharing_buildings_by_districts_in_progress; - is->sharing_buildings_by_districts_in_progress = true; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * tile = wai.tile; - - // Make sure Wonder is completed - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - struct wonder_district_info * info = &inst->wonder_info; - if ((info == NULL) || (info->state != WDS_COMPLETED)) continue; - - // Check that city doesn't already have the Wonder - int improv_id = get_wonder_improvement_id_from_index (info->wonder_index); - if (improv_id < 0) continue; - - if (patch_City_has_improvement (city, __, improv_id, false)) continue; - - // Small wonders use Leader.Small_Wonders as their canonical owner record. If the city - // just changed hands and the new owner already has that small wonder elsewhere, do not - // re-grant it from the nearby district or the capture can recreate a duplicate. - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) != 0) { - City * owning_city = get_city_ptr (leaders[city->Body.CivID].Small_Wonders[improv_id]); - if ((owning_city != NULL) && - (owning_city->Body.CivID == city->Body.CivID) && - ! city_radius_contains_tile (owning_city, x, y)) - continue; - } - - // Add the Wonder to the city - patch_City_add_or_remove_improvement (city, __, improv_id, 1, false); - } - - is->sharing_buildings_by_districts_in_progress = prev_flag; -} - -void -on_gain_city (Leader * leader, City * city, enum city_gain_reason reason) -{ - if (reason == CGR_FOUNDED) - is->turn_no_of_last_founding_for_settler_perfume[leader->ID] = *p_current_turn_no; - - // Handle extra palaces for AI multi-city start - if (((*p_human_player_bits & (1<ID)) == 0) && // If leader is an AI AND - (is->current_config.ai_multi_city_start > 1) && // AI multi-city start is enabled AND - (leader->Cities_Count > 1) && // city is not the only one the AI has (i.e. it's not the capital) AND - (reason != CGR_PLACED_FOR_SCENARIO) && (reason != CGR_PLACED_FOR_AI_MULTI_CITY_START)) { // city was not placed before the game started - - // Find an extra palace that this player does not already have - int free_extra_palace = -1; - for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { - int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) && - (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && - (NULL == get_city_ptr (leader->Small_Wonders[improv_id]))) { - free_extra_palace = improv_id; - break; - } - } - - // Place that extra palace here - if (free_extra_palace >= 0) - City_add_or_remove_improvement (city, __, free_extra_palace, 1, false); - } - - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - patch_City_recompute_yields_and_happiness (city); - patch_City_recompute_culture_income (city); - } - - if (is->current_config.enable_districts) { - - // Remove any district previously on the tile, if city just founded - if (reason == CGR_FOUNDED) { - Tile * city_tile = tile_at (city->Body.X, city->Body.Y); - if ((city_tile != NULL) && (city_tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (city_tile); - if (inst != NULL) - handle_district_removed (city_tile, inst->district_id, city->Body.X, city->Body.Y, false); - } - } - - bool receive_buildings = is->current_config.cities_with_mutual_district_receive_buildings; - bool receive_wonders = is->current_config.cities_with_mutual_district_receive_wonders; - - // Grant buildings and wonders from nearby completed districts owned by other cities of same civ, if enabled - if (receive_buildings) { - grant_existing_district_buildings_to_city (city); - } - - // Grant wonders nearby in same territory, regardless of city (i.e., orphaned wonders from destroyed cities), if enabled - if (receive_wonders) { - grant_nearby_wonders_to_city (city); - } - - if (is->current_config.enable_distribution_hub_districts) { - refresh_distribution_hubs_for_city (city); - } - } -} - -void -on_lose_city (Leader * leader, City * city, enum city_loss_reason reason) -{ - // If leader is an AI and AI MCS is enabled, remove any extra palaces the city has - if (((*p_human_player_bits & (1<ID)) == 0) && - (is->current_config.ai_multi_city_start > 1)) - remove_extra_palaces (city, NULL); - - if (is->current_config.enable_districts) { - if (is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; - - forget_pending_building_order (city); - for (int district_id = 0; district_id < is->district_count; district_id++) - clear_city_district_request (city, district_id); - - if (is->current_config.enable_wonder_districts) - release_wonder_district_reservation (city); - } else if (is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; -} - -// Returns -1 if the location is unusable, 0-9 if it's usable but doesn't satisfy all criteria, and 10 if it couldn't be better -int -eval_starting_location (Map * map, int const * alt_starting_locs, int alt_starting_loc_count, int tile_x, int tile_y, int civ_id) -{ - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != p_null_tile) && - (patch_Map_check_city_location (map, __, tile_x, tile_y, civ_id, true) == CLV_OK) && - (tile->vtable->m15_Check_Goody_Hut (tile, __, 0) == 0) && - (tile->vtable->m40_get_TileUnit_ID (tile) == -1)) { - int tr = 0; - - // Avoid this location if it's too close to another starting location. If it's much too close, it's ruled out entirely. - int closest_dist = INT_MAX; - for (int n = 1; n <= map->Civ_Count; n++) - if (map->Starting_Locations[n] >= 0) { - int other_x, other_y; - tile_index_to_coords (map, map->Starting_Locations[n], &other_x, &other_y); - int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); - if (dist < closest_dist) - closest_dist = dist; - } - for (int n = 0; n < alt_starting_loc_count; n++) - if (alt_starting_locs[n] >= 0) { - int other_x, other_y; - tile_index_to_coords (map, alt_starting_locs[n], &other_x, &other_y); - int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); - if (dist < closest_dist) - closest_dist = dist; - } - if (closest_dist < map->Civ_Distance/3) - return -1; - else if (closest_dist >= 2*map->Civ_Distance/3) - tr += 1; - - // Avoid tiny islands - // tr += map->vtable->m33_Get_Continent (map, __, tile->ContinentID)->Body.TileCount >= 20; - - // Avoid garbage terrain, e.g. all desert or tundra - int break_even_food_tiles = 0; - FOR_TILES_AROUND (tai, 21, tile_x, tile_y) { - if (tai.n == 0) - continue; // Skip tile that would be covered by the city - int tile_food = patch_Map_calc_food_yield_at (map, __, tai.tile_x, tai.tile_y, tai.tile->vtable->m50_Get_Square_BaseType (tai.tile), civ_id, 0, NULL); - int food_required = p_bic_data->General.FoodPerCitizen + (tai.tile->vtable->m35_Check_Is_Water (tai.tile) ? 1 : 0); - break_even_food_tiles += tile_food >= food_required; - } - tr += break_even_food_tiles >= 2; - - // Avoid wasting a food bonus - tr += (tile->ResourceType < 0) || (tile->ResourceType >= p_bic_data->ResourceTypeCount) || - (p_bic_data->ResourceTypes[tile->ResourceType].Food == 0); - - int max_score = 3; - return (10*tr)/max_score; - } else - return -1; -} - -City * -create_starter_city (Map * map, int civ_id, int tile_index) -{ - int x, y; - tile_index_to_coords (map, tile_index, &x, &y); - City * tr = Leader_create_city (&leaders[civ_id], __, x, y, leaders[civ_id].RaceID, -1, NULL, true); - if (tr != NULL) - on_gain_city (&leaders[civ_id], tr, CGR_PLACED_FOR_AI_MULTI_CITY_START); - return tr; -} - -void -set_up_ai_multi_city_start (Map * map, int city_count) -{ - // Set of bits determining which players are eligible for the two-city start - int eligibility_bits = 0, - count_eligible_civs = 0; - for (int n = 1; n < 32; n++) - if ((*p_player_bits & 1<Starting_Locations[n]) != p_null_tile)) { // has a valid starting location - eligibility_bits |= 1 << n; - count_eligible_civs++; - } - - if ((city_count < 1) || (count_eligible_civs == 0)) // if we have nothing to do - return; - - char load_text[50]; - snprintf (load_text, sizeof load_text, "%s...", is->c3x_labels[CL_CREATING_CITIES]); - load_text[(sizeof load_text) - 1] = '\0'; - Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); - - // Generate alternate sets of starting locations. We need one set for each extra city we're going to create per player. Each set only needs to - // include starting locations for eligible players, all others will be left as -1. - int alt_starting_loc_count = 32 * (city_count - 1); - int * alt_starting_locs = malloc (alt_starting_loc_count * sizeof *alt_starting_locs); { - for (int n = 0; n < alt_starting_loc_count; n++) - alt_starting_locs[n] = -1; - - for (int i_loc = 0; i_loc < alt_starting_loc_count; i_loc++) { - int civ_id = i_loc % 32; - if ((civ_id != 0) && (eligibility_bits & 1<current_config.max_tries_to_place_fp_city; try++) { - int i_loc = rand_int (p_rand_object, __, map->TileCount); - int x_loc, y_loc; - tile_index_to_coords (map, i_loc, &x_loc, &y_loc); - if ((x_loc >= 0) && (y_loc >= 0)) { - int val = eval_starting_location (map, alt_starting_locs, alt_starting_loc_count, x_loc, y_loc, civ_id); - if (val >= 10) { - best_loc_index = i_loc; - break; - } else if (val > best_loc_val) { - best_loc_val = val; - best_loc_index = i_loc; - } - } - } - - if (best_loc_index >= 0) - alt_starting_locs[i_loc] = best_loc_index; - } - } - } - - int count_cities_created = 0; - int count_eligible_civs_handled = 0; - for (int civ_id = 1; civ_id < 32; civ_id++) - if (eligibility_bits & 1<Starting_Locations[civ_id]; - - // Create the first starting city for the AI. This one is its capital and is located at its actual starting - // location. Afterward, delete its starting settler so it's as if the settler founded the city. - { - Unit * starting_settler = NULL; - FOR_UNITS_ON (tai, tile_at_index (map, sloc)) { - if (p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].AI_Strategy & UTAI_Settle) { - starting_settler = tai.unit; - break; - } - } - - create_starter_city (map, civ_id, sloc); - count_cities_created++; - - if (starting_settler != NULL) - patch_Unit_despawn (starting_settler, __, 0, 1, 0, 0, 0, 0, 0); - - } - - // Memoize all of the AI's starting units - clear_memo (); - FOR_UNITS_ON (tai, tile_at_index (map, sloc)) - memoize ((int)tai.unit); - - int extra_city_count = 0; - for (int i_city = 1; i_city < city_count; i_city++) { - int loc = alt_starting_locs[(i_city-1)*32 + civ_id]; - City * city; - if ((loc >= 0) && - (NULL != (city = create_starter_city (map, civ_id, loc)))) { - count_cities_created++; - extra_city_count++; - - // Spawn palace substitute in new city - if (extra_city_count-1 < is->current_config.count_ai_multi_start_extra_palaces) - patch_City_add_or_remove_improvement (city, __, is->current_config.ai_multi_start_extra_palaces[extra_city_count - 1], 1, true); - - // Move starting units over to the new city. Do this by moving every Nth unit where N is the number of extra - // cities we've founded so far plus one. ("Extra" cities are the ones created after the capital.) E.g., if - // this is the 1st city after the capital, move every 2nd unit to it. If it's the 2nd, move every 3rd, etc. - for (int n = 0; n < is->memo_len; n++) - if (n % (extra_city_count+1) == extra_city_count) - patch_Unit_move ((Unit *)is->memo[n], __, city->Body.X, city->Body.Y); - - } - } - - // Update progress report - count_eligible_civs_handled++; - int progress = 100 * count_eligible_civs_handled / count_eligible_civs; - snprintf (load_text, sizeof load_text, "%s %d%%", is->c3x_labels[CL_CREATING_CITIES], progress); - load_text[(sizeof load_text) - 1] = '\0'; - Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); - - } - - free (alt_starting_locs); - - // Sanity check - int any_adjacent_cities = 0; { - if (p_cities->Cities != NULL) - for (int city_index = 0; (city_index <= p_cities->LastIndex) && ! any_adjacent_cities; city_index++) { - City * city = get_city_ptr (city_index); - if (city != NULL) - FOR_TILES_AROUND (tai, 9, city->Body.X, city->Body.Y) - if ((tai.n > 0) && (NULL != get_city_ptr (tai.tile->vtable->m45_Get_City_ID (tai.tile)))) { - any_adjacent_cities = 1; - break; - } - } - } - int any_missing_fp_cities = (count_cities_created < city_count * count_eligible_civs); - if (any_adjacent_cities || any_missing_fp_cities) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[100]; - snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_FAILED_SANITY_CHECK]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - if (any_adjacent_cities) { - snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_ADJACENT_CITIES]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - if (any_missing_fp_cities) { - snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_MISSING_CITIES]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - patch_show_popup (popup, __, 0, 0); - } -} - -void __fastcall -patch_Map_process_after_placing (Map * this, int edx, bool param_1) -{ - if ((is->current_config.ai_multi_city_start > 0) && (*p_current_turn_no == 0)) - set_up_ai_multi_city_start (this, is->current_config.ai_multi_city_start); - - Map_process_after_placing (this, __, param_1); -} - -void __fastcall -patch_Map_impl_generate (Map * this, int edx, int seed, bool is_multiplayer_game, int num_seafaring_civs) -{ - Map_impl_generate (this, __, seed, is_multiplayer_game, num_seafaring_civs); - - if (is->current_config.enable_natural_wonders) - place_natural_wonders_on_map (); -} - -int __fastcall -patch_City_get_net_commerce (City * this, int edx, int kind, bool include_science_age) -{ - int base = City_get_net_commerce (this, __, kind, include_science_age); - - if ((kind == 1) && // beakers, as opposed to 2 which is gold - (is->current_config.ai_research_multiplier != 100) && - ((*p_human_player_bits & 1<Body.CivID) == 0)) - return (base * is->current_config.ai_research_multiplier + 50) / 100; - else - return base; -} - -// Cuts research spending while total expenditures > treasury. Returns whether spending has been cut. -bool -cut_unaffordable_research_spending (Leader * leader, bool skip_popup) -{ - // The rate cap limits AI players' spending on the gold slider (in Leader::ai_adjust_sliders) however it does not apply to human players when - // adjusting sliders manually on the domestic advisor screen. - int gold_rate_cap = ((*p_human_player_bits & 1<ID) != 0) ? 10 : p_bic_data->Governments[leader->GovernmentType].RateCap; - - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - bool reduced_spending = false; - while (leader->science_slider > 0 && - leader->gold_slider < gold_rate_cap && - treasury + Leader_compute_income (leader) < 0) { - leader->science_slider -= 1; - leader->gold_slider += 1; - Leader_recompute_economy (leader); - reduced_spending = true; - } - if (reduced_spending && ! skip_popup && leader->ID == p_main_screen_form->Player_CivID) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_CUT_RESEARCH_SPENDING", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - return reduced_spending; -} - -void __fastcall -adjust_sliders_preproduction (Leader * this) -{ - if ((*p_human_player_bits & 1<ID) == 0) { - // Replicate the behavior of the original code for AI players. (apply_machine_code_edits overwrites an equivalent branch & call in the - // original code with a call to this method.) - this->vtable->ai_adjust_sliders (this); - - // If aggressively penalize bankruptcy is on, cut the AI's research spending if it can't afford it. This may be redundant as - // ai_adjust_sliders will already cut AI spending but maybe not all the way to zero. Do this only every third turn so the AI is not - // completely prevented from researching. - if (is->current_config.aggressively_penalize_bankruptcy && (*p_current_turn_no + this->ID) % 3 == 0) - cut_unaffordable_research_spending (this, true); - - // If human player would go bankrupt, try reducing their research spending to avoid that - } else if (is->current_config.cut_research_spending_to_avoid_bankruptcy) - cut_unaffordable_research_spending (this, false); -} - -int __fastcall -patch_City_get_improvement_maintenance (City * this, int edx, int improv_id) -{ - // Check if this improvment is provided for free by another player via shared wonder effects - int civ_id = this->Body.CivID; - bool free_from_sharing = false; - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << civ_id) & *p_human_player_bits)) { // is this city owned by a human player - - // Check if any other human player in the game has this improv in their auto improvs table, including for this city's continent - bool has_free_improv = false; - Tile * city_tile = tile_at (this->Body.X, this->Body.Y); - int continent_id = city_tile->vtable->m46_Get_ContinentID (city_tile); - int cont_coded_key = (continent_id + 1) * p_bic_data->ImprovementsCount + improv_id;; - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != civ_id)) - if (Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, improv_id , NULL) || - Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, cont_coded_key, NULL)) { - free_from_sharing = true; - break; - } - player_bits >>= 1; - n_player++; - } - } - - if (! free_from_sharing) - return City_get_improvement_maintenance (this, __, improv_id); - else - return 0; -} - -int __fastcall -patch_Leader_count_maintenance_free_units (Leader * this) -{ - if ((is->current_config.extra_unit_maintenance_per_shields <= 0) && (this->ID != 0)) - return Leader_count_maintenance_free_units (this); - else { - int tr = 0; - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if ((unit != NULL) && (unit->Body.CivID == this->ID)) { - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - - // If this is a free unit - if ((unit->Body.RaceID != this->RaceID) || (type->requires_support == 0)) - tr++; - - // If this unit belongs to the barbs and has a tribe ID set (indicating it was spawned in a barb camp) then count it - // as a free unit in order not to bankrupt the barb player if the barb player controls any cities. A tribe ID of 75 is - // the generic ID that's assigned to barb units when they're spawned with no specific tribe ID. - else if ((unit->Body.CivID == 0) && (unit->Body.barb_tribe_id >= 0) && (unit->Body.barb_tribe_id < 75)) - tr++; - - // Otherwise, if we're configured to apply extra maintenance based on shield cost, reduce the free unit count by - // however many times this unit's cost is above the threshold for extra maintenace. It's alright if the resulting free - // unit count is negative since all callers of this function subtract its return value from the total unit count to - // obtain the count of units that must be paid for. - else if (is->current_config.extra_unit_maintenance_per_shields > 0) - tr -= type->Cost / is->current_config.extra_unit_maintenance_per_shields; - } - } - return tr; - } -} - -int __fastcall -patch_Leader_sum_unit_maintenance (Leader * this, int edx, int government_id) -{ - if (is->current_config.extra_unit_maintenance_per_shields <= 0) - return Leader_sum_unit_maintenance (this, __, government_id); - else if (this->Cities_Count > 0) { - int maint_free_count = patch_Leader_count_maintenance_free_units (this); - int cost_per_unit, base_free_count; - get_unit_support_info (this->ID, government_id, &cost_per_unit, &base_free_count); - int ai_free_count; { - if (*p_human_player_bits & 1<ID) - ai_free_count = 0; - else { - Difficulty_Level * difficulty = &p_bic_data->DifficultyLevels[*p_game_difficulty]; - ai_free_count = difficulty->Bonus_For_Each_City * this->Cities_Count + difficulty->Additional_Free_Support; - } - } - return not_below (0, (this->Unit_Count - base_free_count - ai_free_count - maint_free_count) * cost_per_unit); - } else - return 0; -} - -int -sum_improvements_maintenance_to_pay (Leader * leader, int govt_id) -{ - if (is->current_config.aggressively_penalize_bankruptcy) - // We're going to replace the logic that charges maintenance, and the replacement will charge both unit & building maintenance b/c - // they're intertwined under the new rules. Return zero here so the base game code doesn't charge any building maintenance on its own. - return 0; - else - return Leader_sum_improvements_maintenance (leader, __, govt_id); -} - -// The sum_improvements_maintenance function is called in two places as part of the randomization of whether improv or unit maintenance gets paid -// first. Redirect both of these calls to one function of our own. -int __fastcall patch_Leader_sum_improv_maintenance_to_pay_1 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } -int __fastcall patch_Leader_sum_improv_maintenance_to_pay_2 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } - -int -compare_buildings_to_sell (void const * a, void const * b) -{ - int maint_a = (*(int const *)a >> 26) & 31, - maint_b = (*(int const *)b >> 26) & 31; - return maint_b - maint_a; -} - -// Returns the final improv cost after buildings were sold -int -sell_unaffordable_buildings (Leader * leader, int improv_cost, int unit_cost) -{ - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - - clear_memo (); - - // Memoize all buildings this player owns that we might potentially sell. B/c the memo can only contain ints, we must pack the maintenance - // cost, improv ID, and city ID all into one int. The city ID is stored in the lowest 13 bits, then the improv ID in the next 13, and finally - // the maintenance amount in the 5 above those. - FOR_CITIES_OF (coi, leader->ID) - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * improv = &p_bic_data->Improvements[n]; - - int unsellable_flags = - ITF_Center_of_Empire | - ITF_50_Luxury_Output | - ITF_50_Tax_Output | - ITF_Reduces_Corruption | - ITF_Increases_Luxury_Trade | - ITF_Allows_City_Level_2 | - ITF_Allows_City_Level_3 | - ITF_Capitalization | - ITF_Allows_Water_Trade | - ITF_Allows_Air_Trade | - ITF_Increases_Shields_In_Water | - ITF_Increases_Food_In_Water | - ITF_Increases_Trade_In_Water; - - // Only sell improvements that aren't contributing gold, even indirectly through e.g. happiness or boosting shield production - // for Wealth - bool sellable = - ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) == 0) && - ((improv->ImprovementFlags & unsellable_flags) == 0) && - (improv->Happy_Faces_All <= 0) && (improv->Happy_Faces <= 0) && - (improv->Production <= 0); - - if (sellable && patch_City_has_improvement (coi.city, __, n, 0)) { - int maint = patch_City_get_improvement_maintenance (coi.city, __, n); - if (maint > 0) - memoize ((not_above (31, maint) << 26) | (n << 13) | coi.city_id); - } - } - - // Sort the list of buildings so the highest maintenance ones come first - qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_buildings_to_sell); - - // Sell buildings until we can cover maintenance costs or until we run out of ones to sell - int count_sold = 0; - while ((improv_cost + unit_cost > treasury) && (count_sold < is->memo_len)) { - int improv_id = ((1<<13) - 1) & (is->memo[count_sold] >> 13), - city_id = ((1<<13) - 1) & is->memo[count_sold]; - City * city = get_city_ptr (city_id); - improv_cost -= patch_City_get_improvement_maintenance (city, __, improv_id); - City_sell_improvement (city, __, improv_id, false); - treasury = leader->Gold_Encoded + leader->Gold_Decrement; - count_sold++; - } - - // Show popup informing the player that their buildings were force sold - if ((leader->ID == p_main_screen_form->Player_CivID) && ! is_online_game ()) { - PopupForm * popup = get_popup_form (); - if (count_sold == 1) { - int improv_id = ((1<<13) - 1) & (is->memo[0] >> 13), - city_id = ((1<<13) - 1) & is->memo[0]; - set_popup_str_param (0, get_city_ptr (city_id)->Body.CityName , -1, -1); - set_popup_str_param (1, p_bic_data->Improvements[improv_id].Name.S, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_SINGLE_IMPROV", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } else if (count_sold > 1) { - set_popup_int_param (0, count_sold); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_MULTIPLE_IMPROVS", -1, 0, 0, 0); - - // Add list of sold improvements to popup - for (int n = 0; n < count_sold; n++) { - int improv_id = ((1<<13) - 1) & (is->memo[n] >> 13), - city_id = ((1<<13) - 1) & is->memo[n]; - char s[200]; - snprintf (s, sizeof s, "^ %s in %s", - p_bic_data->Improvements[improv_id].Name.S, - get_city_ptr (city_id)->Body.CityName); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - - patch_show_popup (popup, __, 0, 0); - } - } - - return improv_cost; -} - -// Returns the final unit cost after disbanding -int -disband_unaffordable_units (Leader * leader, int improv_cost, int unit_cost, int cost_per_unit) -{ - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - int count_disbanded = 0; - Unit * to_disband; - char first_disbanded_name[32]; - while ((improv_cost + unit_cost > treasury) && - (unit_cost > 0) && - (NULL != (to_disband = leader->vtable->find_unsupported_unit (leader)))) { - if (count_disbanded == 0) { - char const * name_src = (to_disband->Body.Custom_Name.S[0] == '\0') - ? p_bic_data->UnitTypes[to_disband->Body.UnitTypeID].Name - : to_disband->Body.Custom_Name.S; - strncpy (first_disbanded_name, name_src, sizeof first_disbanded_name); - first_disbanded_name[(sizeof first_disbanded_name) - 1] = '\0'; - } - Unit_disband (to_disband); - count_disbanded++; - unit_cost -= cost_per_unit; - } - - // Show popup informing the player that their units were disbanded - if (leader->ID == p_main_screen_form->Player_CivID) { - PopupForm * popup = get_popup_form (); - if (count_disbanded == 1) { - set_popup_str_param (0, first_disbanded_name, -1, -1); - int online_flag = is_online_game () ? 0x4000 : 0; - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_SINGLE_UNIT", -1, 0, online_flag, 0); - patch_show_popup (popup, __, 0, 0); - } else if ((count_disbanded > 1) && ! is_online_game ()) { - set_popup_int_param (0, count_disbanded); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_MULTIPLE_UNITS", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - } - - return unit_cost; -} - -int -compare_cities_by_production (void const * vp_id_a, void const * vp_id_b) -{ - City * a = get_city_ptr (*(int const *)vp_id_a), - * b = get_city_ptr (*(int const *)vp_id_b); - return a->Body.ProductionIncome - b->Body.ProductionIncome; -} - -void -charge_maintenance_with_aggressive_penalties (Leader * leader) -{ - int cost_per_unit; - get_unit_support_info (leader->ID, leader->GovernmentType, &cost_per_unit, NULL); - - int improv_cost = Leader_sum_improvements_maintenance (leader, __, leader->GovernmentType); - - int unit_cost = 0; { - if (leader->Cities_Count > 0) // Players with no cities don't pay unit maintenance, per the original game rules - if (cost_per_unit > 0) { - int count_free_units = Leader_get_free_unit_count (leader, __, leader->GovernmentType) + patch_Leader_count_maintenance_free_units (leader); - unit_cost += not_below (0, (leader->Unit_Count - count_free_units) * cost_per_unit); - } - } - - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - if (improv_cost + unit_cost > treasury) { - - // For AIs, alternate between selling buildings and disbanding units when maintenance can't be paid - if (((1<ID & *p_human_player_bits) != 0) || ((leader->ID + *p_current_turn_no) % 2 == 0)) { - improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); - unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); - } else { - unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); - improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); - } - - treasury = leader->Gold_Encoded + leader->Gold_Decrement; // Update b/c selling buildings recovers some gold - - // If the player still can't afford maintenance, even after all that, start switching their cities to Wealth - int wealth_income = 0; - if (improv_cost + unit_cost > treasury + wealth_income) { - // Memoize all cities not already building wealth and sort by production (lowest first) - clear_memo (); - FOR_CITIES_OF (coi, leader->ID) - if ((coi.city->Body.Status & CSF_Capitalization) == 0) - memoize (coi.city_id); - qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_cities_by_production); - - int wealth_improv_id = -1; { - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { - wealth_improv_id = n; - break; - } - } - - if (wealth_improv_id >= 0) { - int n = 0, - switched_any = 0; - - while ((n < is->memo_len) && (improv_cost + unit_cost > treasury + wealth_income)) { - City * city = get_city_ptr (is->memo[n]); - City_set_production (city, __, COT_Improvement, wealth_improv_id, false); - switched_any = 1; - wealth_income += City_get_income_from_wealth_build (city); - n++; - } - - if (switched_any && (leader->ID == p_main_screen_form->Player_CivID)) { - PopupForm * popup = get_popup_form (); - Improvement * wealth = &p_bic_data->Improvements[wealth_improv_id]; - set_popup_str_param (0, wealth->Name.S, -1, -1); - set_popup_str_param (1, wealth->CivilopediaEntry.S, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_BUILD_WEALTH", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - } - } - } - - Leader_set_treasury (leader, __, treasury - improv_cost - unit_cost); -} - -bool __fastcall -patch_Unit_has_king_ability_for_find_unsupported (Unit * this, int edx, enum UnitTypeAbilities king_ability) -{ - // If we're set to aggressively penalize bankruptcy and this unit doesn't require support, return that it is a king so it doesn't get - // disbanded. - if (is->current_config.aggressively_penalize_bankruptcy && ! p_bic_data->UnitTypes[this->Body.UnitTypeID].requires_support) - return true; - - else - return Unit_has_ability (this, __, king_ability); -} - -void __fastcall -patch_Leader_pay_unit_maintenance (Leader * this) -{ - if (! is->current_config.aggressively_penalize_bankruptcy) - Leader_pay_unit_maintenance (this); - else - charge_maintenance_with_aggressive_penalties (this); -} - -void __fastcall -patch_Main_Screen_Form_show_wltk_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) -{ - patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); -} - -void __fastcall -patch_Main_Screen_Form_show_wltk_ended_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) -{ - patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); -} - -char __fastcall -patch_Tile_has_city_for_agri_penalty_exception (Tile * this) -{ - return is->current_config.no_penalty_exception_for_agri_fresh_water_city_tiles ? 0 : Tile_has_city (this); -} - -int -show_razing_popup (void * popup_object, int popup_param_1, int popup_param_2, int razing_option) -{ - int response = patch_show_popup (popup_object, __, popup_param_1, popup_param_2); - if (is->current_config.prevent_razing_by_players && (response == razing_option)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_RAZE", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - return 0; - } - return response; -} - -int __fastcall patch_show_popup_option_1_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 1); } -int __fastcall patch_show_popup_option_2_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 2); } - -int __fastcall -patch_Context_Menu_add_abandon_city (Context_Menu * this, int edx, int item_id, char * text, bool checkbox, Sprite * image) -{ - if (is->current_config.prevent_razing_by_players) - return 0; // Return value is ignored by the caller - else - return Context_Menu_add_item (this, __, item_id, text, checkbox, image); -} - -char * -check_pedia_upgrades_to_ptr (TextBuffer * this, char * str) -{ - Civilopedia_Form * pedia = p_civilopedia_form; - UnitType * unit_type = NULL; - if (is->current_config.indicate_non_upgradability_in_pedia && - (pedia->Current_Article_ID >= 0) && (pedia->Current_Article_ID <= pedia->Max_Article_ID) && - (NULL != (unit_type = pedia->Articles[pedia->Current_Article_ID]->unit_type)) && - ((unit_type->Special_Actions & UCV_Upgrade_Unit) == 0)) - return is->c3x_labels[CL_OBSOLETED_BY]; - else - return TextBuffer_check_ptr (this, __, str); -} - -char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_1 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } -char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_2 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } - -bool __fastcall -patch_Unit_select_stealth_attack_target (Unit * this, int edx, int target_civ_id, int x, int y, bool allow_popup, Unit ** out_selected_target) -{ - is->added_any_stealth_target = 0; - return Unit_select_stealth_attack_target (this, __, target_civ_id, x, y, allow_popup, out_selected_target); -} - -bool __fastcall -patch_Unit_can_stealth_attack (Unit * this, int edx, Unit * target) -{ - bool tr = Unit_can_stealth_attack (this, __, target); - - // If we're selecting a target for stealth attack via bombardment, we must filter out candidates we can't damage that way - if (tr && is->selecting_stealth_target_for_bombard && - ! can_damage_bombarding (&p_bic_data->UnitTypes[this->Body.UnitTypeID], target, tile_at (target->Body.X, target->Body.Y))) - return false; - - else if (tr && is->current_config.exclude_invisible_units_from_stealth_attack && ! patch_Unit_is_visible_to_civ (target, __, this->Body.CivID, 1)) - return false; - - else if (tr && is->current_config.exclude_passengers_from_stealth_attack && get_unit_ptr (target->Body.Container_Unit) != NULL) - return false; - - else - return tr; -} - -int __fastcall -patch_Tile_check_water_for_stealth_attack (Tile * this) -{ - // When stealth attack bombard is enabled, remove a special rule inside can_stealth_attack that prevents land units from stealth attacking - // onto sea tiles. This allows land artillery to stealth attack naval units. - return is->current_config.enable_stealth_attack_via_bombardment ? 0 : this->vtable->m35_Check_Is_Water (this); -} - -int __fastcall -patch_PopupSelection_add_stealth_attack_target (PopupSelection * this, int edx, char * text, int value) -{ - if (is->current_config.include_stealth_attack_cancel_option && (! is->added_any_stealth_target)) { - PopupSelection_add_item (this, __, is->c3x_labels[CL_NO_STEALTH_ATTACK], -1); - is->added_any_stealth_target = 1; - } - - Unit * unit; - if (is->current_config.show_hp_of_stealth_attack_options && - ((unit = get_unit_ptr (value)) != NULL)) { - char s[500]; - int max_hp = Unit_get_max_hp (unit); - snprintf (s, sizeof s, "(%d/%d) %s", max_hp - unit->Body.Damage, max_hp, text); - s[(sizeof s) - 1] = '\0'; - return PopupSelection_add_item (this, __, s, value); - } else - return PopupSelection_add_item (this, __, text, value); -} - -void __fastcall -patch_Unit_perform_air_recon (Unit * this, int edx, int x, int y) -{ - int moves_plus_one = this->Body.Moves + p_bic_data->General.RoadsMovementRate; - - bool was_intercepted = false; - if (is->current_config.intercept_recon_missions) { - // Temporarily add vision on the target tile so the game plays the animation if the unit is show down by ground AA - Tile_Body * tile = &tile_at (x, y)->Body; - int saved_vis = tile->Visibility; - tile->Visibility |= 1 << this->Body.CivID; - was_intercepted = Unit_try_flying_over_tile (this, __, x, y); - tile->Visibility = saved_vis; - } - - if (! was_intercepted) { - Unit_perform_air_recon (this, __, x, y); - if (is->current_config.charge_one_move_for_recon_and_interception) - this->Body.Moves = moves_plus_one; - } -} - -int __fastcall -patch_Unit_get_interceptor_max_moves (Unit * this) -{ - // Stop fighters from intercepting multiple times per turn without blitz - if (is->current_config.charge_one_move_for_recon_and_interception && - (this->Body.Status & USF_USED_ATTACK != 0) && ! UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Blitz)) - return 0; - - else - return patch_Unit_get_max_move_points (this); -} - -int __fastcall -patch_Unit_get_moves_after_interception (Unit * this) -{ - if (is->current_config.charge_one_move_for_recon_and_interception) { - this->Body.Status |= USF_USED_ATTACK; // Set status bit indicating that the interceptor has attacked this turn - return this->Body.Moves + p_bic_data->General.RoadsMovementRate; - } else - return patch_Unit_get_max_move_points (this); -} - -void __fastcall -patch_Unit_set_state_after_interception (Unit * this, int edx, int new_state) -{ - if (! is->current_config.charge_one_move_for_recon_and_interception) - Unit_set_state (this, __, new_state); - - // If fighters are supposed to be able to intercept multiple times per turn, then we can't knock them out of the interception state as soon as - // they intercept something like in the base game. Instead, record this interception event so that we can clear their state at the start of - // their next turn. - else { - struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->Body.CivID]; - reserve (sizeof irl->items[0], (void **)&irl->items, &irl->capacity, irl->count); - irl->items[irl->count++] = (struct interception) { - .unit_id = this->Body.ID, - .x = this->Body.X, - .y = this->Body.Y - }; - } -} - -// Goes through every entry in a table with unit IDs as keys and filters out any that belong to the given owner (or are invalid). -void -remove_unit_id_entries_owned_by (struct table * t, int owner_id) -{ - if (t->len > 0) { - clear_memo (); - FOR_TABLE_ENTRIES (tei, t) { - Unit * unit = get_unit_ptr (tei.key); - if ((unit == NULL) || (unit->Body.CivID == owner_id)) - memoize (tei.key); - } - for (int n = 0; n < is->memo_len; n++) - itable_remove (t, is->memo[n]); - } -} - -void __fastcall -patch_Leader_begin_turn (Leader * this) -{ - if (is->aerodrome_airlift_usage.len > 0) { - int civ_bit = 1 << this->ID; - clear_memo (); - FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { - int mask = tei.value; - if (mask & civ_bit) { - int new_mask = mask & ~civ_bit; - memoize (tei.key); - memoize (new_mask); - } - } - for (int n = 0; n < is->memo_len; n += 2) { - int key = is->memo[n]; - int new_mask = is->memo[n + 1]; - if (new_mask == 0) - itable_remove (&is->aerodrome_airlift_usage, key); - else - itable_insert (&is->aerodrome_airlift_usage, key, new_mask); - } - clear_memo (); - } - - // Eject trespassers - is->do_not_bounce_invisible_units = true; - if (is->current_config.disallow_trespassing && (*p_current_turn_no > 0)) - for (int n = 1; n < 32; n++) - if ((*p_player_bits & (1 << n)) && - (n != this->ID) && - (! this->At_War[n]) && - ((this->Relation_Treaties[n] & 2) == 0)) // Check right of passage - Leader_bounce_trespassing_units (&leaders[n], __, this->ID); - is->do_not_bounce_invisible_units = false; - - if (is->current_config.introduce_all_human_players_at_start_of_hotseat_game && - (*p_current_turn_no == 0) && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((*p_human_player_bits & (1 << this->ID)) != 0)) - for (int n = 0; n < 32; n++) - if (*p_human_player_bits & (1 << n)) - Leader_make_contact (this, __, n, false); - - Leader_begin_turn (this); -} - -void __fastcall -patch_Leader_begin_unit_turns (Leader * this) -{ - // Reset the states of all fighters that performed an interception on the previous turn. - struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->ID]; - for (int n = 0; n < irl->count; n++) { - struct interception * record = &irl->items[n]; - Unit * interceptor = get_unit_ptr (record->unit_id); - if ((interceptor != NULL) && - (interceptor->Body.CivID == this->ID) && - (interceptor->Body.X == record->x) && - (interceptor->Body.Y == record->y) && - (interceptor->Body.UnitState == UnitState_Intercept)) - Unit_set_state (interceptor, __, 0); - } - irl->count = 0; - - // Reset extra defensive bombard and airdrop counters - remove_unit_id_entries_owned_by (&is->extra_defensive_bombards, this->ID); - remove_unit_id_entries_owned_by (&is->airdrops_this_turn , this->ID); - remove_unit_id_entries_owned_by (&is->unit_transport_ties , this->ID); - - clear_memo (); - if (is->current_config.delete_off_map_ai_units && - ((*p_human_player_bits & (1 << this->ID)) == 0) && - (p_units->Units != NULL)) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit_Body * body = p_units->Units[n].Unit; - if ((body != NULL) && - ((int)body != offsetof (Unit, Body)) && - (body->CivID == this->ID) && - ! Map_in_range (&p_bic_data->Map, __, body->X, body->Y)) - memoize (body->ID); - } - for (int n = 0; n < is->memo_len; n++) - patch_Unit_despawn (get_unit_ptr (is->memo[n]), __, 0, 1, 0, 0, 0, 0, 0); - - Leader_begin_unit_turns (this); -} - -Unit * __fastcall -patch_Fighter_find_actual_bombard_defender (Fighter * this, int edx, Unit * bombarder, int tile_x, int tile_y, int bombarder_civ_id, bool land_lethal, bool sea_lethal) -{ - if (is->bombard_stealth_target == NULL) - return Fighter_find_defender_against_bombardment (this, __, bombarder, tile_x, tile_y, bombarder_civ_id, land_lethal, sea_lethal); - else - return is->bombard_stealth_target; -} - -Unit * -select_stealth_attack_bombard_target (Unit * unit, int tile_x, int tile_y) -{ - bool land_lethal = Unit_has_ability (unit, __, UTA_Lethal_Land_Bombardment), - sea_lethal = Unit_has_ability (unit, __, UTA_Lethal_Sea_Bombardment); - Unit * defender = Fighter_find_defender_against_bombardment (&p_bic_data->fighter, __, unit, tile_x, tile_y, unit->Body.CivID, land_lethal, sea_lethal); - if (defender != NULL) { - Unit * target; - is->selecting_stealth_target_for_bombard = 1; - bool got_one = patch_Unit_select_stealth_attack_target (unit, __, defender->Body.CivID, tile_x, tile_y, true, &target); - is->selecting_stealth_target_for_bombard = 0; - return got_one ? target : NULL; - } else - return NULL; -} - -bool __fastcall -patch_Unit_try_flying_for_precision_strike (Unit * this, int edx, int x, int y) -{ - bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); - if (is->current_config.polish_precision_striking && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) && - ! is_cruise_missile) - // This method returns -1 when some kind of error occurs. In that case, return true implying the unit was shot down so the caller - // doesn't do anything more. Otherwise, return false so it goes ahead and applies damage. - return Unit_play_bombard_fire_animation (this, __, x, y) == -1; - - else if (is->current_config.polish_precision_striking && is_cruise_missile) { - Unit_animate_cruise_missile_strike (this, __, x, y); - return false; - - } else - return Unit_try_flying_over_tile (this, __, x, y); -} - -void __fastcall -patch_Unit_play_bombing_anim_for_precision_strike (Unit * this, int edx, int x, int y) -{ - // Only play the bombing animation here if we haven't already played an animation in the above method. We don't want to play all animations - // here since the bombard fire animation can fail for whatever reason but this method can't handle failure. - bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); - if ((! is->current_config.polish_precision_striking) || - ((p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && ! is_cruise_missile)) - Unit_play_bombing_animation (this, __, x, y); -} - -int __fastcall -patch_Unit_play_anim_for_bombard_tile (Unit * this, int edx, int x, int y) -{ - Unit * stealth_attack_target = NULL; - if (((p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && - is->current_config.enable_stealth_attack_via_bombardment && - (! is_online_game ()) && - patch_Leader_is_tile_visible (&leaders[this->Body.CivID], __, x, y)) - is->bombard_stealth_target = select_stealth_attack_bombard_target (this, x, y); - - return Unit_play_bombard_fire_animation (this, __, x, y); -} - -void __fastcall -patch_Main_Screen_Form_issue_precision_strike_cmd (Main_Screen_Form * this, int edx, Unit * unit) -{ - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - if ((! is->current_config.polish_precision_striking) || (type->Unit_Class == UTC_Air)) - Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); - else { - // issue_precision_strike_cmd will use the unit type's operational range. To make it use bombard range instead, place that value in - // the operational range field temporarily. Conveniently, it's only necessary to do this temporary switch once, here, because the main - // screen form stores a copy of the range for its own use and the method to actually perform the strike doesn't check the range. - int saved_op_range = type->OperationalRange; - type->OperationalRange = type->Bombard_Range; - Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); - type->OperationalRange = saved_op_range; - } -} - -int __fastcall -patch_Map_compute_neighbor_index_for_cm_strike (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - int tr = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); - - if ((tr >= 0) && - (is->bombarding_unit != NULL) && - ((p_bic_data->UnitTypes[is->bombarding_unit->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && - is->current_config.enable_stealth_attack_via_bombardment && - (! is_online_game ()) && - patch_Leader_is_tile_visible (&leaders[is->bombarding_unit->Body.CivID], __, x_neigh, y_neigh)) - is->bombard_stealth_target = select_stealth_attack_bombard_target (is->bombarding_unit, x_neigh, y_neigh); - - return tr; -} - -int __fastcall -patch_rand_bombard_target (void * this, int edx, int lim) -{ - // If we have a bombard stealth attack target set then return 2 so that the bombard damage will be applied to units not pop or buildings. - return (is->bombard_stealth_target == NULL) ? rand_int (this, __, lim) : 2; -} - -int __fastcall -patch_rand_int_to_dodge_city_aa (void * this, int edx, int lim) -{ - int tr = rand_int (this, __, lim); - is->result_of_roll_to_dodge_city_aa = tr; - return tr; -} - -int __fastcall -patch_Unit_get_defense_to_dodge_city_aa (Unit * this) -{ - int defense = Unit_get_defense_strength (this); - if (is->current_config.show_message_after_dodging_sam && - (defense > is->result_of_roll_to_dodge_city_aa) && - (this->Body.CivID == p_main_screen_form->Player_CivID)) - show_map_specific_text (this->Body.X, this->Body.Y, is->c3x_labels[CL_DODGED_SAM], 0); - return defense; -} - -int __fastcall -patch_Unit_get_defense_to_find_bombard_defender (Unit * this) -{ - // The caller is filtering out candidates with zero defense strength as possible targets to receive damage from bombardment. We can return 0 - // here to make sure "this" unit is not targeted. - - Unit * container; - - if (is->current_config.immunize_aircraft_against_bombardment && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air)) - return 0; - - else if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return 0; - - else - return Unit_get_defense_strength (this); -} - -int __cdecl -patch_get_WindowsFileBox_from_ini (LPCSTR key, int param_2, int param_3) -{ - // If the file path has already been determined, then avoid using the Windows file picker. This makes the later code to insert the path easier - // since we only have to intercept the opening of the civ-style file picker instead of both that and the Windows one. - if (is->load_file_path_override == NULL) - return get_int_from_conquests_ini (key, param_2, param_3); - else - return 0; -} - -char const * __fastcall -patch_do_open_load_game_file_picker (void * this) -{ - if (is->load_file_path_override != NULL) { - char const * tr = is->load_file_path_override; - is->load_file_path_override = NULL; - return tr; - } else - return open_load_game_file_picker (this); -} - -int __fastcall -patch_show_intro_after_load_popup (void * this, int edx, int param_1, int param_2) -{ - if (! is->suppress_intro_after_load_popup) - return patch_show_popup (this, __, param_1, param_2); - else { - is->suppress_intro_after_load_popup = 0; - return 0; - } -} - -void __fastcall patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id); - -void * __cdecl -patch_do_load_game (char * param_1) -{ - void * tr = do_load_game (param_1); - - if (is->current_config.restore_unit_directions_on_game_load && (p_units->Units != NULL)) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if ((unit != NULL) && (unit->Body.UnitState != UnitState_Fortifying)) { - if (Map_in_range (&p_bic_data->Map, __, unit->Body.X, unit->Body.Y) && - Map_in_range (&p_bic_data->Map, __, unit->Body.PrevMoveX, unit->Body.PrevMoveY)) { - int dx = unit->Body.X - unit->Body.PrevMoveX, dy = unit->Body.Y - unit->Body.PrevMoveY; - int dir = -1; - if ((dx == 1) && (dy == -1)) dir = DIR_NE; - else if ((dx == 2) && (dy == 0)) dir = DIR_E; - else if ((dx == 1) && (dy == 1)) dir = DIR_SE; - else if ((dx == 0) && (dy == 2)) dir = DIR_S; - else if ((dx == -1) && (dy == 1)) dir = DIR_SW; - else if ((dx == -2) && (dy == 0)) dir = DIR_W; - else if ((dx == -1) && (dy == -1)) dir = DIR_NW; - else if ((dx == 0) && (dy == -2)) dir = DIR_N; - if (dir >= 0) - unit->Body.Animation.summary.direction = dir; - } - } - } - - // Apply era aliases - for (int n = 0; n < 32; n++) - if (*p_player_bits & (1 << n)) - apply_era_specific_names (&leaders[n]); - - if (is->current_config.apply_grid_ini_setting_on_game_load) { - int grid_on = get_int_from_conquests_ini ("GridOn", 0, 0); - Map_Renderer * mr = &p_bic_data->Map.Renderer; - if (grid_on && ! mr->MapGrid_Flag) - mr->vtable->m68_Toggle_Grid (mr); - } - - return tr; -} - -void * -load_game_ex (char const * file_path, int suppress_intro_popup) -{ - is->suppress_intro_after_load_popup = suppress_intro_popup; - is->load_file_path_override = file_path; - return patch_do_load_game (NULL); -} - -int __fastcall -patch_show_movement_phase_popup (void * this, int edx, int param_1, int param_2) -{ - int tr = patch_show_popup (this, __, param_1, param_2); - - int player_civ_id = p_main_screen_form->Player_CivID; - int replay_for_players = is->replay_for_players; // Store this b/c it gets reset on game load - if (replay_for_players & 1<showing_hotseat_replay = true; - - patch_do_save_game (hotseat_resume_save_path, 1, 0); - load_game_ex (hotseat_replay_save_path, 1); - p_main_screen_form->Player_CivID = player_civ_id; - - // Re-enable the GUI so the minimap is visible during the replay. We must also reset the minimap & redraw it so that it reflects the - // player we just seated (above) instead of leftover data from the last player. - Main_GUI * main_gui = &p_main_screen_form->GUI; - main_gui->is_enabled = 1; - Navigator_Data_reset (&main_gui->Navigator_Data); - main_gui->Base.vtable->m73_call_m22_Draw ((Base_Form *)main_gui); - - perform_interturn (); - load_game_ex (hotseat_resume_save_path, 1); - p_main_screen_form->is_now_loading_game = 0; - - // Restore the replay_for_players variable b/c it gets cleared when loading a game. Also mask out the bit for the player we just - // showed the replay to. - is->replay_for_players = replay_for_players & ~(1<showing_hotseat_replay = false; - } - - return tr; -} - -// Returns a set of player bits containing only those players that are human and can see at least one AI unit. For speed and simplicity, does not -// account for units' invisibility ability, units are considered visible as long as they're on a visible tile. -int -find_human_players_seeing_ai_units () -{ - int tr = 0; - Map * map = &p_bic_data->Map; - if (map->Tiles != NULL) - for (int n_tile = 0; n_tile < map->TileCount; n_tile++) { - Tile * tile = map->Tiles[n_tile]; - Tile_Body * body = &tile->Body; - int human_vis_bits = (body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility) & *p_human_player_bits; - if (human_vis_bits != 0) // If any human players can see this tile - for (int n_player = 0; n_player < 32; n_player++) - if (human_vis_bits & 1<TileUnitID, &unused); - Unit * unit = get_unit_ptr (unit_id); - if ((unit != NULL) && - ((*p_human_player_bits & 1<Body.CivID) == 0)) { - tr |= 1<current_config.replay_ai_moves_in_hotseat_games && - (*p_is_offline_mp_game && ! *p_is_pbem_game); // offline MP but not PBEM => we're in a hotseat game - int ai_unit_vis_before; - if (save_replay) { - ai_unit_vis_before = find_human_players_seeing_ai_units (); - int toggleable_rules = *p_toggleable_rules; - *p_toggleable_rules |= TR_PRESERVE_RANDOM_SEED; // Make sure preserve random seed is on for the replay save - patch_do_save_game (hotseat_replay_save_path, 1, 0); - *p_toggleable_rules = toggleable_rules; - } - - is->players_saw_ai_unit = 0; // Clear bits. After perform_interturn, each set bit will indicate a player that has seen an AI unit move - long long ts_before; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); - is->time_spent_paused_during_popup = 0; - is->time_spent_computing_city_connections = 0; - is->count_calls_to_recompute_city_connections = 0; - unsigned saved_prefs = *p_preferences; - if (is->current_config.measure_turn_times) - *p_preferences &= ~(P_ANIMATE_BATTLES | P_SHOW_FRIEND_MOVES | P_SHOW_ENEMY_MOVES); - - perform_interturn (); - - if (is->current_config.day_night_cycle_mode) { - if (is->day_night_cycle_img_state == IS_OK) { - int new_hour = calculate_current_day_night_cycle_hour (); - if (new_hour != is->current_day_night_cycle) { - is->current_day_night_cycle = new_hour; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - } - } - } - - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_for_districts (); - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - } - - if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { - is->city_loc_display_perspective = -1; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw - } - - if (is->current_config.measure_turn_times) { - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - long long perf_freq; - QueryPerformanceFrequency ((LARGE_INTEGER *)&perf_freq); - int turn_time_in_ms = 1000 * (ts_after - ts_before - is->time_spent_paused_during_popup) / perf_freq; - int city_con_time_in_ms = 1000 * is->time_spent_computing_city_connections / perf_freq; - int road_time_in_ms = 1000 * is->time_spent_filling_roads / perf_freq; - - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - char msg[1000]; - - struct c3x_opt { - bool is_active; - char * name; - } opts[] = {{is->current_config.optimize_improvement_loops, "improv. loops"}, - {is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_OK), "trade net x"}}; - char opt_list[1000]; - memset (opt_list, 0, sizeof opt_list); - strncpy (opt_list, "^C3X optimizations: ", sizeof opt_list); - bool any_active_opts = false; - for (int n = 0; n < ARRAY_LEN (opts); n++) - if (opts[n].is_active) { - char * cursor = &opt_list[strlen (opt_list)]; - snprintf (cursor, opt_list + (sizeof opt_list) - cursor, "%s%s", any_active_opts ? ", " : "", opts[n].name); - any_active_opts = true; - } - if (! any_active_opts) { - char * cursor = &opt_list[strlen (opt_list)]; - strncpy (cursor, "None", opt_list + (sizeof opt_list) - cursor); - } - PopupForm_add_text (popup, __, (char *)opt_list, false); - - snprintf (msg, sizeof msg, "^Turn time: %d.%03d sec", turn_time_in_ms/1000, turn_time_in_ms%1000); - PopupForm_add_text (popup, __, (char *)msg, false); - snprintf (msg, sizeof msg, "^ Recomputing city connections: %d.%03d sec (%d calls)", - city_con_time_in_ms/1000, city_con_time_in_ms%1000, - is->count_calls_to_recompute_city_connections); - PopupForm_add_text (popup, __, (char *)msg, false); - snprintf (msg, sizeof msg, "^ Flood filling road network: %d.%03d sec", - road_time_in_ms/1000, road_time_in_ms%1000); - PopupForm_add_text (popup, __, (char *)msg, false); - patch_show_popup (popup, __, 0, 0); - - *p_preferences = saved_prefs; - } - - if (save_replay) { - int last_human_player_bit = 0; { - for (int n = 0; n < 32; n++) - if (*p_human_player_bits & 1<replay_for_players = (ai_unit_vis_before | (is->players_saw_ai_unit & *p_human_player_bits)) & ~last_human_player_bit; - } -} - -void __cdecl -patch_initialize_map_music (int civ_id, int era_id, bool param_3) -{ - if (! is->showing_hotseat_replay) - initialize_map_music (civ_id, era_id, param_3); -} - -void __stdcall -patch_deinitialize_map_music () -{ - if (! is->showing_hotseat_replay) - deinitialize_map_music (); -} - -void __fastcall -patch_Fighter_do_bombard_tile (Fighter * this, int edx, Unit * unit, int neighbor_index, int mp_tile_x, int mp_tile_y) -{ - // Unit::score_kill will be called if the bombarder destroys its target, and that is the only way score_kill can be called while this method - // is running. So if we're configured to stop enslaving from bombard, turn off enslaving while it's running. - is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; - - // Check if we're going to do PTW-like targeting, if not fall back on the base game's do_bombard_tile method. We'll also fall back on that - // method in the case where we're in an online game and the bombard can't happen b/c the tile is occupied by another battle. In that case, no - // bombard is possible but we'll call the base method anyway since it will show a little message saying as much. - if (itable_look_up_or (&is->current_config.ptw_arty_types, unit->Body.UnitTypeID, 0) && - (is->bombard_stealth_target == NULL) && - ! (is_online_game () && mp_check_current_combat (p_mp_object, __, mp_tile_x, mp_tile_y))) { - - City * city; { - int dx, dy; - neighbor_index_to_diff (neighbor_index, &dx, &dy); - int tile_x = unit->Body.X + dx, tile_y = unit->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - city = city_at (tile_x, tile_y); - } - - int rv; - if ((city != NULL) && ((rv = rand_int (p_rand_object, __, 3)) < 2)) - Fighter_damage_city_by_bombardment (this, __, unit, city, rv, 0); - else - Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); - - } else - Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); - - is->do_not_enslave_units = false; -} - -bool __fastcall -patch_Unit_check_king_for_defense_priority (Unit * this, int edx, enum UnitTypeAbilities king_ability) -{ - return (! is->current_config.ignore_king_ability_for_defense_priority) || (*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) ? - Unit_has_ability (this, __, king_ability) : - false; -} - -void WINAPI -patch_get_local_time_for_unit_ini (LPSYSTEMTIME lpSystemTime) -{ - GetLocalTime (lpSystemTime); - if (is->current_config.no_elvis_easter_egg && (lpSystemTime->wMonth == 1) && (lpSystemTime->wDay == 8)) - lpSystemTime->wDay = 9; -} - -bool __fastcall -patch_Leader_could_buy_tech_for_trade_screen (Leader * this, int edx, int tech_id, int from_civ_id) -{ - // Temporarily remove the untradable flag so this tech is listed on the screen instead of skipped over. After all the items have been - // assembled, we'll go back and disable the untradable techs. - if (is->current_config.show_untradable_techs_on_trade_screen) { - int saved_flags = p_bic_data->Advances[tech_id].Flags; - p_bic_data->Advances[tech_id].Flags &= ~ATF_Cannot_Be_Traded; - bool tr = this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); - p_bic_data->Advances[tech_id].Flags = saved_flags; - return tr; - - } else - return this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); -} - -void __fastcall -patch_DiploForm_assemble_tradable_items (DiploForm * this) -{ - DiploForm_assemble_tradable_items (this); - - // Disable (gray out) all untradable techs - if (is->current_config.show_untradable_techs_on_trade_screen) - for (int n = 0; n < p_bic_data->AdvanceCount; n++) - if (p_bic_data->Advances[n].Flags & ATF_Cannot_Be_Traded) { - this->tradable_technologies[n].can_be_bought = 0; - this->tradable_technologies[n].can_be_sold = 0; - } -} - -bool __fastcall -patch_City_can_trade_via_water (City * this) -{ - if (is->current_config.optimize_improvement_loops) { - for (int n = 0; n < is->water_trade_improvs.count; n++) - if (has_active_building (this, is->water_trade_improvs.items[n])) - return true; - return false; - } else - return City_can_trade_via_water (this); -} - -bool __fastcall -patch_City_can_trade_via_air (City * this) -{ - if (is->current_config.optimize_improvement_loops) { - for (int n = 0; n < is->air_trade_improvs.count; n++) - if (has_active_building (this, is->air_trade_improvs.items[n])) - return true; - return false; - } else - return City_can_trade_via_air (this); -} - -int __fastcall -patch_City_get_building_defense_bonus (City * this) -{ - bool cancel_great_wall_boost = is->current_config.enable_districts && - is->current_config.enable_great_wall_districts && - is->current_config.disable_great_wall_city_defense_bonus; - - if (is->current_config.optimize_improvement_loops || cancel_great_wall_boost) { - int tr = 0; - int is_size_level_1 = (this->Body.Population.Size <= p_bic_data->General.MaximumSize_City) && - (this->Body.Population.Size <= p_bic_data->General.MaximumSize_Town); - for (int n = 0; n < is->combat_defense_improvs.count; n++) { - int improv_id = is->combat_defense_improvs.items[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((is_size_level_1 || (improv->Combat_Bombard == 0)) && has_active_building (this, improv_id)) { - int multiplier; - if ((improv->Combat_Bombard > 0) && - (! cancel_great_wall_boost) && - (patch_Leader_count_any_shared_wonders_with_flag (&leaders[(this->Body).CivID], __, ITW_Doubles_City_Defenses, NULL) > 0)) - multiplier = 2; - else - multiplier = 1; - - int building_defense = multiplier * improv->Combat_Defence; - if (building_defense > tr) - tr = building_defense; - } - } - return tr; - } else - return City_get_building_defense_bonus (this); -} - -bool __fastcall -patch_City_shows_harbor_icon (City * this) -{ - return is->current_config.city_icons_show_unit_effects_not_trade ? - City_count_improvements_with_flag (this, __, ITF_Veteran_Sea_Units) > 0 : - patch_City_can_trade_via_water (this); -} - -bool __fastcall -patch_City_shows_airport_icon (City * this) -{ - return is->current_config.city_icons_show_unit_effects_not_trade ? - City_count_improvements_with_flag (this, __, ITF_Veteran_Air_Units) > 0 : - patch_City_can_trade_via_air (this); -} - -int __fastcall -patch_Unit_eval_escort_requirement (Unit * this) -{ - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - int ai_strat = type->AI_Strategy; - bool owned_by_ai = (*p_human_player_bits & 1<Body.CivID) == 0; // We must not reduce the escort requirement for human-owned units - // because that will interfere with group movement of units. - - // Apply special escort rules - if (owned_by_ai && is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) - return 0; - else if (owned_by_ai && is->current_config.use_offensive_artillery_ai && (ai_strat & UTAI_Artillery)) - return 1; - - else { - int base = Unit_eval_escort_requirement (this); - if (owned_by_ai && (ai_strat & (UTAI_Naval_Transport | UTAI_Naval_Carrier | UTAI_Naval_Missile_Transport))) - return not_above (is->current_config.max_ai_naval_escorts, base); - else - return base; - } -} - -bool __fastcall -patch_Unit_has_enough_escorters_present (Unit * this) -{ - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) - return true; - else - return Unit_has_enough_escorters_present (this); -} - -void __fastcall -patch_Unit_check_escorter_health (Unit * this, int edx, bool * has_any_escort_present, bool * any_escorter_cant_heal) -{ - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) { - *has_any_escort_present = true; - *any_escorter_cant_heal = true; // Returning true here indicates the unit should not stop to wait for its escorter(s) to heal. - } else - Unit_check_escorter_health (this, __, has_any_escort_present, any_escorter_cant_heal); -} - -void __fastcall -patch_Leader_unlock_technology (Leader * this, int edx, int tech_id, bool param_2, bool param_3, bool param_4) -{ - int * p_stack = (int *)&tech_id; - int ret_addr = p_stack[-1]; - - Leader_unlock_technology (this, __, tech_id, param_2, param_3, param_4); - - // If this method was not called during game initialization - if ((ret_addr != ADDR_UNLOCK_TECH_AT_INIT_1) && - (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_2) && - (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_3)) { - - // If this tech obsoletes some building and we're configured to fix the maintenance bug then recompute city maintenance. - if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings) { - bool obsoletes_anything = false; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (p_bic_data->Improvements[n].ObsoleteID == tech_id) { - obsoletes_anything = true; - break; - } - if (obsoletes_anything) - Leader_recompute_buildings_maintenance (this); - } - } -} - -int __fastcall -patch_City_get_improv_maintenance_for_ui (City * this, int edx, int improv_id) -{ - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && - (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) - return 0; - else - return patch_City_get_improvement_maintenance (this, __, improv_id); -} - -// Patch for barbarian diagonal bug. This bug is a small mistake in the original code, maybe a copy+paste error. The original code tries to loop over -// tiles around the barb unit by incrementing a neighbor index and coverting it to tile coords (like normal). The problem is that after it converts -// the neighbor index to dx and dy, it adds dx to both coords of the unit's position instead of using dy. The fix is simply to subtract off dx and add -// in dy when the Y coord is passed to Map::wrap_vert. -void __cdecl -patch_neighbor_index_to_diff_for_barb_ai (int neighbor_index, int * out_x, int * out_y) -{ - neighbor_index_to_diff (neighbor_index, out_x, out_y); - is->barb_diag_patch_dy_fix = *out_y - *out_x; -} -int __fastcall -patch_Map_wrap_vert_for_barb_ai (Map * this, int edx, int y) -{ - return Map_wrap_vert (this, __, is->current_config.patch_barbarian_diagonal_bug ? (y + is->barb_diag_patch_dy_fix) : y); -} - -int -count_workable_tiles_for_city (City * city) -{ - if (city == NULL) - return 0; - - int workable = 0; - FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { - Tile * tile = wai.tile; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - if (tile->Body.CityAreaID != city->Body.ID) - continue; - - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && district_is_complete (tile, inst->district_id)) - continue; - - workable++; - } - return workable; -} - -int -compute_auto_distribution_hub_goal (Leader * leader, int city_count) -{ - int total_unused_tiles = 0; - int stagnating_cities = 0; - int slow_growth_cities = 0; - int very_low_production_cities = 0; - int low_production_cities = 0; - - FOR_CITIES_OF (coi, leader->ID) { - City * city = coi.city; - if (city == NULL) - continue; - - int pop_size = city->Body.Population.Size; - int workable_tiles = count_workable_tiles_for_city (city); - if ((workable_tiles > 0) && (pop_size < workable_tiles)) - total_unused_tiles += workable_tiles - pop_size; - - int net_food = city->Body.FoodIncome; - if (net_food <= 0) - stagnating_cities++; - else if (net_food <= 2) - slow_growth_cities++; - - int net_shields = city->Body.ProductionIncome + city->Body.ProductionLoss; - if (net_shields < 0) - net_shields = 0; - if (net_shields <= 3) - very_low_production_cities++; - else if (net_shields <= 6) - low_production_cities++; - } - - int base_desired = (city_count + 3) / 4; - - int tiles_per_chunk = is->workable_tile_count; - if (tiles_per_chunk <= 0) - tiles_per_chunk = 1; - int unused_bonus = (total_unused_tiles + tiles_per_chunk * 3 - 1) / (tiles_per_chunk * 3); - - int food_pressure = stagnating_cities * 2 + slow_growth_cities; - int food_bonus = (food_pressure + 2) / 3; - - int production_pressure = very_low_production_cities * 2 + low_production_cities; - int production_bonus = (production_pressure + 2) / 3; - - int desired = base_desired + unused_bonus + food_bonus + production_bonus; - int max_reasonable = (city_count + 1) / 2; - int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; - if (max_per_100 > 0) { - int capped = (city_count * max_per_100 + 99) / 100; - if (capped >= 0) - max_reasonable = capped; - } - if (desired > max_reasonable) - desired = max_reasonable; - if (desired < 1) - desired = 1; - - return desired; -} - -void -ai_update_distribution_hub_goal_for_leader (Leader * leader) -{ - if (leader == NULL) - return; - if (! is->current_config.enable_districts || - ! is->current_config.enable_distribution_hub_districts) - return; - - int civ_id = leader->ID; - if ((1 << civ_id) & *p_human_player_bits) - return; - - int city_count = leader->Cities_Count; - if (city_count <= 0) - return; - - int desired = 0; - if (is->current_config.ai_distribution_hub_build_strategy == ADHBS_AUTO) - desired = compute_auto_distribution_hub_goal (leader, city_count); - else { - int ideal_per_100 = is->current_config.ai_ideal_distribution_hub_count_per_100_cities; - if (ideal_per_100 <= 0) - return; - desired = (city_count * ideal_per_100) / 100; - } - if (desired <= 0) - return; - - int current = 0; - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if ((rec != NULL) && (rec->civ_id == civ_id)) - current++; - } - - int in_progress = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * tile = (Tile *)tei.key; - int mapped_district_id = tei.value; - if ((tile != NULL) && - (mapped_district_id == DISTRIBUTION_HUB_DISTRICT_ID) && - ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID)) { - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (owner == civ_id) - in_progress++; - } - } - - int pending = 0; - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req != NULL) && (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID)) - pending++; - } - - int planned = current + in_progress + pending; - if (planned >= desired) - return; - - City * capital = get_city_ptr (leader->CapitalID); - bool has_capital = (capital != NULL); - int capital_x = has_capital ? capital->Body.X : 0; - int capital_y = has_capital ? capital->Body.Y : 0; - - const int yield_weight = 40; - const int capital_distance_weight = 45; - const int desired_min_capital_distance = 8; - const int proximity_penalty_scale = 300; - - while (planned < desired) { - City * best_city = NULL; - int best_tile_x = 0; - int best_tile_y = 0; - int best_score = INT_MIN; - - FOR_CITIES_OF (coi, civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - if (city_has_required_district (city, DISTRIBUTION_HUB_DISTRICT_ID)) - continue; - - if (find_pending_district_request (city, DISTRIBUTION_HUB_DISTRICT_ID) != NULL) - continue; - - int tile_x, tile_y; - Tile * candidate = find_tile_for_district (city, DISTRIBUTION_HUB_DISTRICT_ID, &tile_x, &tile_y); - if (candidate == NULL) - continue; - - int yield_sum = compute_city_tile_yield_sum (city, tile_x, tile_y); - int distance_to_capital = 0; - if (has_capital) - distance_to_capital = compute_wrapped_manhattan_distance (city->Body.X, city->Body.Y, capital_x, capital_y); - - int closeness_penalty = 0; - if (has_capital && (distance_to_capital < desired_min_capital_distance)) - closeness_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; - - int score = yield_sum * yield_weight + distance_to_capital * capital_distance_weight - closeness_penalty; - if (tile_has_resource (candidate)) - score -= 500; - - if (score > best_score) { - best_score = score; - best_city = city; - best_tile_x = tile_x; - best_tile_y = tile_y; - } - } - - if (best_city == NULL) - break; - - mark_city_needs_district (best_city, DISTRIBUTION_HUB_DISTRICT_ID); - planned++; - } -} - -bool -assign_ai_fallback_production (City * city, int disallowed_improvement_id) -{ - if (city == NULL) - return false; - - City_Order new_order = { .OrderID = -1, .OrderType = 0 }; - patch_City_ai_choose_production (city, __, &new_order); - - bool order_ok = false; - if (new_order.OrderType == COT_Improvement) { - if ((new_order.OrderID >= 0) && - (new_order.OrderID < p_bic_data->ImprovementsCount) && - (new_order.OrderID != disallowed_improvement_id) && - ! city_requires_district_for_improvement (city, new_order.OrderID, NULL) && - ! is_wonder_or_small_wonder_already_being_built (city, new_order.OrderID)) - order_ok = true; - } else if (new_order.OrderType == COT_Unit) { - if ((new_order.OrderID >= 0) && - (new_order.OrderID < p_bic_data->UnitTypeCount) && - (p_bic_data->UnitTypes[new_order.OrderID].Unit_Class == UTC_Land) && - patch_City_can_build_unit (city, __, new_order.OrderID, 1, 0, 0)) - order_ok = true; - } - - char ss[200]; - snprintf (ss, sizeof ss, "assign_ai_fallback_production: Remembering fallback pending building order for city %d (%s): id %d\n", - city->Body.ID, city->Body.CityName, disallowed_improvement_id); - (*p_OutputDebugStringA) (ss); - remember_pending_building_order (city, disallowed_improvement_id); - - if (order_ok) { - City_set_production (city, __, new_order.OrderType, new_order.OrderID, false); - return true; - } - - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) { - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - return true; - } - } - - return false; -} - -void __fastcall -patch_Leader_do_production_phase (Leader * this) -{ - recompute_resources_if_necessary (); - - if (is->current_config.enable_districts) { - assign_workers_for_pending_districts (this); - - if ((is->current_config.enable_canal_districts || is->current_config.enable_bridge_districts) && - (is->current_config.ai_builds_bridges || is->current_config.ai_builds_canals)) - assign_workers_for_ai_candidate_bridge_or_canals (this); - - bool ai_player = ((*p_human_player_bits & (1 << this->ID)) == 0); - int auto_dynamic_district_ids[COUNT_DISTRICT_TYPES]; - int auto_dynamic_district_count = 0; - - // For dynamic districts, the AI will never be triggered to build them if they have no dependent buildings. - // Determine which dynamic districts the AI could build. In the city loop after, mark which cities need them - if (ai_player) { - for (int district_id = is->special_district_count; district_id < is->district_count; district_id++) { - struct district_config * cfg = &is->district_configs[district_id]; - struct district_infos * info = &is->district_infos[district_id]; - - if (info->dependent_building_count > 0) continue; - if (cfg->command == -1) continue; - - if (! leader_can_build_district (this, district_id)) - continue; - - if (auto_dynamic_district_count < ARRAY_LEN (auto_dynamic_district_ids)) - auto_dynamic_district_ids[auto_dynamic_district_count++] = district_id; - } - } - - // Special exception for AI to build Central Rail Hub, which is available in Industrial era but Mass Transit, - // the only building dependent on it, is in the Modern era. Without this the AI wouldn't build in Industrial era. - if (is->current_config.enable_central_rail_hub_districts) { - if (leader_can_build_district (this, CENTRAL_RAIL_HUB_DISTRICT_ID)) - auto_dynamic_district_ids[auto_dynamic_district_count++] = CENTRAL_RAIL_HUB_DISTRICT_ID; - } - - if (is->current_config.enable_distribution_hub_districts) { - if (leader_can_build_district (this, DISTRIBUTION_HUB_DISTRICT_ID)) - ai_update_distribution_hub_goal_for_leader (this); - } - - FOR_CITIES_OF (coi, this->ID) { - City * city = coi.city; - if (city == NULL) continue; - - bool at_neighborhood_cap = is->current_config.enable_neighborhood_districts && city_is_at_neighborhood_cap (city); - - // Mark any needed dynamic districts for AI players. This isn't the most intelligent approach (we're not weighing district benefits), - // but it's simple and works reasonably well - if (ai_player && (auto_dynamic_district_count > 0)) { - for (int i = 0; i < auto_dynamic_district_count; i++) { - int district_id = auto_dynamic_district_ids[i]; - - if (city_has_required_district (city, district_id)) continue; - if (! city_can_build_district (city, district_id)) continue; - if (find_pending_district_request (city, district_id) != NULL) continue; - - int target_x = 0, target_y = 0; - if (find_tile_for_district (city, district_id, &target_x, &target_y) == NULL) - continue; - - mark_city_needs_district (city, district_id); - } - } - - if (at_neighborhood_cap) { - if (! ai_player) - maybe_show_neighborhood_growth_warning (city); - else - ensure_neighborhood_request_for_city (city); - } - - if (city->Body.Order_Type == COT_Unit) { - int unit_id = city->Body.Order_ID; - int req_district_id = -1; - bool needs_halt = false; - - if ((unit_id >= 0) && (unit_id < p_bic_data->UnitTypeCount)) { - UnitType * type = &p_bic_data->UnitTypes[unit_id]; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { - req_district_id = AERODROME_DISTRICT_ID; - needs_halt = true; - } else if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (city, PORT_DISTRICT_ID))) { - req_district_id = PORT_DISTRICT_ID; - needs_halt = true; - } - } - - if (needs_halt) { - char ss[200]; - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting unit %d due to missing district %d\n", - city->Body.ID, city->Body.CityName, unit_id, req_district_id); - (*p_OutputDebugStringA) (ss); - - if (ai_player) - mark_city_needs_district (city, req_district_id); - - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - - continue; - } - } - - if (city->Body.Order_Type != COT_Improvement) continue; - int i_improv = city->Body.Order_ID; - - // Check if production needs to be halted due to missing district - int req_district_id = -1; - char const * district_description = NULL; - bool needs_halt = false; - - // Check buildings & wonders dependent on districts - if (city_requires_district_for_improvement (city, i_improv, &req_district_id)) { - if (req_district_id >= 0) { - needs_halt = true; - district_description = is->district_configs[req_district_id].name; - } - } - - // Wonders - char ss[200]; - if (is->current_config.enable_wonder_districts) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: Checking wonder improv %d for city %d (%s)\n", - i_improv, city->Body.ID, city->Body.CityName); - (*p_OutputDebugStringA) (ss); - if (city_is_currently_building_wonder (city)) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) is building wonder improv %d\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - bool wonder_requires_district = false; - if (i_improv >= 0) { - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); - if (district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) - wonder_requires_district = true; - } - - if (wonder_requires_district) { - bool has_wonder_district = reserve_wonder_district_for_city (city, i_improv); - if (! has_wonder_district) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) lacks Wonder District for wonder improv %d\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - needs_halt = true; - req_district_id = WONDER_DISTRICT_ID; - district_description = "Wonder District"; - } - } else { - release_wonder_district_reservation (city); - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) wonder improv %d does not require Wonder District\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - } - } else { - release_wonder_district_reservation (city); - } - } - - // If production needs to be halted, handle the reassignment and messaging - if (needs_halt) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting improv %d due to missing district %d\n", - city->Body.ID, city->Body.CityName, i_improv, req_district_id); - (*p_OutputDebugStringA) (ss); - // Switch production to another option - if (ai_player) { - mark_city_needs_district (city, req_district_id); - assign_ai_fallback_production (city, i_improv); - } else { - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - // Show message to human player - if (! ai_player && (city->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[160]; - char const * bname = p_bic_data->Improvements[i_improv].Name.S; - snprintf (msg, sizeof msg, "%s %s %s", bname, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_description); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - continue; - } - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) improv %d passed missing district check\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - } - } - - // Force-activate the barbs if there are any barb cities on the map and barb city capturing is enabled. This is necessary for barb city - // production to work given how it's currently implemented. - if (is->current_config.enable_city_capture_by_barbarians && (this->ID == 0)) { - int any_barb_cities = 0; - FOR_CITIES_OF (coi, this->ID) { - any_barb_cities = 1; - break; - } - if (any_barb_cities) - is->force_barb_activity_for_cities = 1; - } - - // If barbs are force-activated, make sure their activity level is at least 1 (sedentary). - int * p_barb_activity = &p_bic_data->Map.World.Final_Barbarians_Activity; - int saved_barb_activity = *p_barb_activity; - if (is->force_barb_activity_for_cities && (*p_barb_activity <= 0)) - *p_barb_activity = 1; - - Leader_do_production_phase (this); - - if (is->force_barb_activity_for_cities) { - *p_barb_activity = saved_barb_activity; - is->force_barb_activity_for_cities = 0; - } -} - -// This function counts the number of players in the game. The return value will be compared to the number of cities on the map to determine if there -// are enough cities (per player) to unlock barb production. If barb activity is forced on, return zero so that the check always passes. -int __cdecl -patch_count_player_bits_for_barb_prod (unsigned int bit_field) -{ - return is->force_barb_activity_for_cities ? 0 : count_set_bits (bit_field); -} - -Tile * __fastcall -patch_Map_get_tile_to_check_visibility (Map * this, int edx, int index) -{ - Tile * tr = Map_get_tile (this, __, index); - int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; - if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { - int human_bits = *p_human_player_bits; - is->dummy_tile->Body.Fog_Of_War = tr->Body.Fog_Of_War | ((tr->Body.Fog_Of_War & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.FOWStatus = tr->Body.FOWStatus | ((tr->Body.FOWStatus & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.V3 = tr->Body.V3 | ((tr->Body.V3 & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.Visibility = tr->Body.Visibility | ((tr->Body.Visibility & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.field_D0_Visibility = tr->Body.field_D0_Visibility | ((tr->Body.field_D0_Visibility & human_bits) != 0 ? human_bits : 0); - tr = is->dummy_tile; - } - is->tile_returned_for_visibility_check = tr; - return tr; -} - -Tile * __fastcall -patch_Map_get_tile_to_check_visibility_again (Map * this, int edx, int index) -{ - return is->tile_returned_for_visibility_check; -} - -// Same as above except this method uses the FOWStatus field instead of Fog_Of_War -Tile * __fastcall -patch_Map_get_tile_for_fow_status_check (Map * this, int edx, int index) -{ - Tile * tile = Map_get_tile (this, __, index); - int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; - if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { - is->dummy_tile->Body.FOWStatus = ((tile->Body.FOWStatus & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; - return is->dummy_tile; - } else - return tile; -} - -Tile * __cdecl -patch_tile_at_to_check_visibility (int x, int y) -{ - return patch_Map_get_tile_to_check_visibility (&p_bic_data->Map, __, (p_bic_data->Map.Width >> 1) * y + (x >> 1)); -} - -Tile * __cdecl -patch_tile_at_to_check_visibility_again (int x, int y) -{ - return is->tile_returned_for_visibility_check; -} - -unsigned __fastcall -patch_Tile_m42_Get_Overlays (Tile * this, int edx, byte visible_to_civ) -{ - unsigned base_vis_overlays = Tile_m42_Get_Overlays (this, __, visible_to_civ); - if ((visible_to_civ != 0) && // if we're seeing from a player's persp. instead of seeing the actual overlays AND - is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND - ((1 << visible_to_civ) & *p_human_player_bits) && // the perspective is of a human player AND - (base_vis_overlays != this->Overlays) && // that player can't already see all the actual overlays AND - (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game - - // Check if there's another human player that can see the actual overlays. If so, give that info to this player and return it. - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != visible_to_civ) && - (Tile_m42_Get_Overlays (this, __, n_player) == this->Overlays)) { - this->Body.Visibile_Overlays[visible_to_civ] = this->Overlays; - return this->Overlays; - } - player_bits >>= 1; - n_player++; - } - - return base_vis_overlays; - } else - return base_vis_overlays; -} - -int __fastcall -patch_Tile_check_water_for_sea_zoc (Tile * this) -{ - if ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) - return this->vtable->m35_Check_Is_Water (this); - else - return 1; // The caller will skip ZoC logic if this is a land tile without a city because the targeted unit is a sea unit. Instead - // return 1, so all tiles are considered sea tiles, so we can run the ZoC logic for land units or air units on land. -} - -int __fastcall -patch_Tile_check_water_for_land_zoc (Tile * this) -{ - // Same as above except this time we want to consider all tiles to be land - return ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) ? - this->vtable->m35_Check_Is_Water (this) : - 0; -} - - -int __fastcall -patch_Unit_get_attack_strength_for_sea_zoc (Unit * this) -{ - return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) ? Unit_get_attack_strength (this) : 0; -} - -int __fastcall -patch_Unit_get_attack_strength_for_land_zoc (Unit * this) -{ - return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) ? Unit_get_attack_strength (this) : 0; -} - -Unit * __fastcall -patch_Main_Screen_Form_find_visible_unit (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * excluded) -{ - struct unit_display_override * override = &is->unit_display_override; - if ((override->unit_id >= 0) && (override->tile_x == tile_x) && (override->tile_y == tile_y)) { - Unit * unit = get_unit_ptr (override->unit_id); - if (unit != NULL) { - if ((unit->Body.X == tile_x) && (unit->Body.Y == tile_y)) - return unit; - } - } - - return Main_Screen_Form_find_visible_unit (this, __, tile_x, tile_y, excluded); -} - -void __fastcall -patch_Animator_play_zoc_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) -{ - if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Air) - Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); -} - -bool __fastcall -patch_Fighter_check_zoc_anim_visibility (Fighter * this, int edx, Unit * attacker, Unit * defender, bool param_3) -{ - // If we've reached this point in the code (in the calling method) then a unit has been selected to exert zone of control and it has passed - // its dice roll to cause damage. Stash its pointer for possible use later. - is->zoc_interceptor = attacker; - - // If an air unit was selected, pre-emptively undo the damage from ZoC since we'll want to run our own bit of logic to do that (the air unit - // may still get shot down). Return false from this function to skip over all of the animation logic in the caller since it wouldn't work for - // aircraft. - if (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Air) { - defender->Body.Damage -= 1; - return false; - - // Repeat a check done by the caller. We've deleted this check to ensure that this function always gets called so we can grab the interceptor. - } else if (attacker->Body.Animation.field_111 == 0) - return false; - - else { - bool tr = Fighter_check_combat_anim_visibility (this, __, attacker, defender, param_3); - - // If necessary, set up to ensure the unit's attack animation is visible. This means forcing it to the top of its stack and - // temporarily unfortifying it if it's fortified. (If it's fortified, the animation is occasionally not visible. Don't know why.) - if (tr && is->current_config.show_zoc_attacks_from_mid_stack) { - is->unit_display_override = (struct unit_display_override) { attacker->Body.ID, attacker->Body.X, attacker->Body.Y }; - if (attacker->Body.UnitState == UnitState_Fortifying) { - Unit_set_state (attacker, __, 0); - is->refortify_interceptor_after_zoc = true; - } - } - - return tr; - } -} - -int __fastcall -patch_City_sum_buildings_naval_power_for_zoc (City * this) -{ - // Cancel out city's naval power if the unit has only one HP left. This prevents coastal fortresses from knocking that last hit point off - // passing units when lethal ZoC is enabled, because to make that work we delete an earlier check excusing 1-HP units from ZoC. - if ((is->zoc_defender != NULL) && - ((Unit_get_max_hp (is->zoc_defender) - is->zoc_defender->Body.Damage) <= 1)) - return 0; - - else - return City_sum_buildings_naval_power (this); -} - -void __fastcall -patch_Fighter_apply_zone_of_control (Fighter * this, int edx, Unit * unit, int from_x, int from_y, int to_x, int to_y) -{ - is->zoc_interceptor = NULL; - is->zoc_defender = unit; - is->refortify_interceptor_after_zoc = false; - struct unit_display_override saved_udo = is->unit_display_override; - Fighter_apply_zone_of_control (this, __, unit, from_x, from_y, to_x, to_y); - - // Actually exert ZoC if an air unit managed to do so. - if ((is->zoc_interceptor != NULL) && (p_bic_data->UnitTypes[is->zoc_interceptor->Body.UnitTypeID].Unit_Class == UTC_Air)) { - bool intercepted = Unit_try_flying_over_tile (is->zoc_interceptor, __, from_x, from_y); - if (! intercepted) { - Unit_play_bombing_animation (is->zoc_interceptor, __, from_x, from_y); - unit->Body.Damage = not_below (0, unit->Body.Damage + 1); - } - } - - if (is->refortify_interceptor_after_zoc) - Unit_set_state (is->zoc_interceptor, __, UnitState_Fortifying); - is->unit_display_override = saved_udo; -} - -// These two patches replace two function calls in Unit::move_to_adjacent_tile that come immediately after the unit has been subjected to zone of -// control. These calls recheck that the move is valid, not sure why. Here they're patched to indicate that the move in invalid when the unit was -// previously killed by ZoC. This causes move_to_adjacent_tile to return early without running the code that would place the unit on the destination -// tile and, for example, capturing an enemy city there. -int __fastcall -patch_Trade_Net_get_move_cost_after_zoc (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned param_7, int neighbor_index, Trade_Net_Distance_Info * dist_info) -{ - return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (unit) - unit->Body.Damage) > 0) ? - patch_Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, param_7, neighbor_index, dist_info) : - -1; -} - -AdjacentMoveValidity __fastcall -patch_Unit_can_move_after_zoc (Unit * this, int edx, int neighbor_index, int param_2) -{ - return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (this) - this->Body.Damage) > 0) ? - patch_Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2) : - AMV_1; -} - -// Checks unit's HP after it was possibly hit by ZoC and deals with the consequences if it's dead. Does nothing if config option to make ZoC lethal -// isn't set or if interceptor is NULL. Returns true if the unit was killed, false otherwise. -bool -check_life_after_zoc (Unit * unit, Unit * interceptor) -{ - if ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) && (interceptor != NULL) && - ((Unit_get_max_hp (unit) - unit->Body.Damage) <= 0)) { - - // Call Unit::score_kill but turn off enslaving if we're configured to stop enslaving after bombardment and the ZoC was performed by - // bombardment, which is always the case for cross-domain ZoC or when bombard str > attack. - UnitType * interceptor_type = &p_bic_data->UnitTypes[interceptor->Body.UnitTypeID]; - if (is->current_config.prevent_enslaving_by_bombardment && - ((p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != interceptor_type->Unit_Class) || - (interceptor_type->Bombard_Strength >= Unit_get_attack_strength (interceptor)))) - is->do_not_enslave_units = true; - Unit_score_kill (interceptor, __, unit, false); - is->do_not_enslave_units = false; - - if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (&p_bic_data->fighter, __, interceptor, unit, true)) - Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, unit, AT_DEATH, false); - - bool prev_always_despawn_passengers = is->always_despawn_passengers; - is->always_despawn_passengers = is_land_transport (unit) && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); - patch_Unit_despawn (unit, __, interceptor->Body.CivID, 0, 0, 0, 0, 0, 0); - is->always_despawn_passengers = prev_always_despawn_passengers; - - return true; - } else - return false; -} - -int __fastcall -patch_Unit_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, bool param_2, int param_3, byte param_4) -{ - is->moving_unit_to_adjacent_tile = true; - is->move_spend_override_unit = NULL; - is->move_spend_override_value = 0; - - bool const allow_worker_coast = is->current_config.enable_districts && is->current_config.workers_can_enter_coast && is_worker (this); - bool const allow_bridge_walk = is->current_config.enable_districts && - is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land); - bool const allow_canal_sail = is->current_config.enable_districts && - is->current_config.enable_canal_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea); - bool coast_override_active = false; - enum UnitStateType prev_state = this->Body.UnitState; - int prev_container = this->Body.Container_Unit; - bool restore_goto_path = prev_state == UnitState_Go_To; - int prev_path_len = this->Body.path_len; - int prev_path_dest_x = this->Body.path_dest_x; - int prev_path_dest_y = this->Body.path_dest_y; - - if (allow_worker_coast || allow_bridge_walk || allow_canal_sail) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - Tile * dest = tile_at (nx, ny); - if (dest != NULL) { - if (allow_bridge_walk && ! dest->vtable->m35_Check_Is_Water (dest)) { - Tile * src = tile_at (this->Body.X, this->Body.Y); - if ((src != NULL) && (src != p_null_tile)) { - struct district_instance * src_inst = get_district_instance (src); - bool from_bridge = (src_inst != NULL) && - (src_inst->district_id == BRIDGE_DISTRICT_ID) && - district_is_complete (src, src_inst->district_id); - if (from_bridge) { - int move_cost = patch_Trade_Net_get_movement_cost ( - is->trade_net, __, - this->Body.X, this->Body.Y, nx, ny, - this, this->Body.CivID, 0, neighbor_index, NULL); - if (move_cost >= 0) { - int spent_moves = this->Body.Moves + move_cost; - is->move_spend_override_unit = this; - is->move_spend_override_value = not_above (spent_moves, patch_Unit_get_max_move_points (this)); - } - } - } - } - - bool should_override = false; - if (allow_worker_coast && - dest->vtable->m35_Check_Is_Water (dest) && - (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - if (is_human) { - should_override = true; - } else { - struct district_worker_record * rec = get_tracked_worker_record (this); - struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; - if (req != NULL) { - City * req_city = (req->city != NULL) ? req->city : get_city_ptr (req->city_id); - if ((req->district_id >= 0) && - (req->district_id < is->district_count) && - (req_city != NULL) && - city_radius_contains_tile (req_city, nx, ny) && - (req->target_x == nx) && (req->target_y == ny)) { - struct district_config const * cfg = &is->district_configs[req->district_id]; - if ((cfg->buildable_square_types_mask & (1 << SQ_Coast)) != 0) - should_override = true; - } - } - } - } - - if (! should_override && allow_bridge_walk) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && - (inst->district_id == BRIDGE_DISTRICT_ID) && - district_is_complete (dest, inst->district_id)) - should_override = true; - } - - if (! should_override && allow_canal_sail) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && - (inst->district_id == CANAL_DISTRICT_ID) && - district_is_complete (dest, inst->district_id)) - should_override = true; - } - - if (should_override) { - coast_override_active = true; - is->coast_walk_unit = this; - is->coast_walk_transport_override = false; - is->coast_walk_prev_state = prev_state; - is->coast_walk_prev_container = prev_container; - is->coast_walk_restore_goto_path = restore_goto_path; - is->coast_walk_prev_path_len = prev_path_len; - is->coast_walk_prev_path_dest_x = prev_path_dest_x; - is->coast_walk_prev_path_dest_y = prev_path_dest_y; - } - } - } - - is->zoc_interceptor = is->zoc_defender = NULL; - int tr = Unit_move_to_adjacent_tile (this, __, neighbor_index, param_2, param_3, param_4); - if ((this == is->zoc_defender) && check_life_after_zoc (this, is->zoc_interceptor)) - tr = ! is_online_game (); // This is what the original method returns when the unit was destroyed in combat - - if (coast_override_active) { - is->coast_walk_unit = NULL; - is->coast_walk_transport_override = false; - - if (this->Body.Container_Unit == this->Body.ID) { - this->Body.Container_Unit = is->coast_walk_prev_container; - Unit_set_state (this, __, is->coast_walk_prev_state); - if (is->coast_walk_restore_goto_path) { - this->Body.path_len = is->coast_walk_prev_path_len; - this->Body.path_dest_x = is->coast_walk_prev_path_dest_x; - this->Body.path_dest_y = is->coast_walk_prev_path_dest_y; - } - } - } - - is->temporarily_disallow_lethal_zoc = false; - is->moving_unit_to_adjacent_tile = false; - is->move_spend_override_unit = NULL; - is->move_spend_override_value = 0; - return tr; -} - -int __fastcall -patch_Unit_teleport (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad) -{ - is->zoc_interceptor = NULL; - int tr = Unit_teleport (this, __, tile_x, tile_y, unit_telepad); - check_life_after_zoc (this, is->zoc_interceptor); - return tr; -} - -bool -can_do_defensive_bombard (Unit * unit, UnitType * type) -{ - if ((type->Bombard_Strength > 0) && (! Unit_has_ability (unit, __, UTA_Cruise_Missile))) { - if (cannot_defend_inside_transport (unit)) - return false; - - if ((unit->Body.Status & USF_USED_DEFENSIVE_BOMBARD) == 0) // has not already done DB this turn - return true; - - // If the "blitz" special DB rule is activated and this unit has blitz, check if it still has an extra DB to use - else if ((is->current_config.special_defensive_bombard_rules & SDBR_BLITZ) && UnitType_has_ability (type, __, UTA_Blitz)) { - int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, unit->Body.ID, 0); - return type->Movement > extra_dbs + 1; - - } else - return false; - } else - return false; -} - -Unit * __fastcall -patch_Fighter_find_defensive_bombarder (Fighter * this, int edx, Unit * attacker, Unit * defender) -{ - int special_db_rules = is->current_config.special_defensive_bombard_rules; - if ((special_db_rules == 0) && - ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) == 0) && - ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) == 0)) - return Fighter_find_defensive_bombarder (this, __, attacker, defender); - else { - enum UnitTypeClasses attacker_class = p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class; - int attacker_has_one_hp = Unit_get_max_hp (attacker) - attacker->Body.Damage <= 1; - - Tile * defender_tile = tile_at (defender->Body.X, defender->Body.Y); - if ((Unit_get_defense_strength (attacker) < 1) || // if attacker cannot defend OR - (defender_tile == NULL) || (defender_tile == p_null_tile) || // defender tile is invalid OR - (((special_db_rules & SDBR_LETHAL) == 0) && attacker_has_one_hp) || // (DB is non-lethal AND attacker has one HP remaining) OR - ((special_db_rules & SDBR_NOT_INVISIBLE) && ! patch_Unit_is_visible_to_civ (attacker, __, defender->Body.CivID, 1))) // (invisible units are immune to DB AND attacker is invisible) - return NULL; - - Unit * tr = NULL; - int highest_strength = -1; - enum UnitTypeAbilities lethal_bombard_req = (attacker_class == UTC_Sea) ? UTA_Lethal_Sea_Bombardment : UTA_Lethal_Land_Bombardment; - FOR_UNITS_ON (uti, defender_tile) { - Unit * candidate = uti.unit; - UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; - if (can_do_defensive_bombard (candidate, candidate_type) && - (candidate_type->Bombard_Strength > highest_strength) && - (candidate != defender) && - (Unit_get_containing_army (candidate) != defender) && - ((attacker_class == candidate_type->Unit_Class) || - ((special_db_rules & SDBR_AERIAL) && - (candidate_type->Unit_Class == UTC_Air) && - (candidate_type->Air_Missions & UCV_Bombing)) || - ((special_db_rules & SDBR_DOCKED_VS_LAND) && - (candidate_type->Unit_Class == UTC_Sea) && - (get_city_ptr (defender_tile->CityID) != NULL))) && - ((! attacker_has_one_hp) || UnitType_has_ability (candidate_type, __, lethal_bombard_req))) { - tr = candidate; - highest_strength = candidate_type->Bombard_Strength; - } - } - return tr; - } -} - -void __fastcall -patch_Fighter_damage_by_db_in_main_loop (Fighter * this, int edx, Unit * bombarder, Unit * defender) -{ - if (p_bic_data->UnitTypes[bombarder->Body.UnitTypeID].Unit_Class == UTC_Air) { - if (Unit_try_flying_over_tile (bombarder, __, defender->Body.X, defender->Body.Y)) - return; // intercepted - else if (patch_Main_Screen_Form_is_unit_visible_to_player (p_main_screen_form, __, defender->Body.X, defender->Body.Y, bombarder)) - Unit_play_bombing_animation (bombarder, __, defender->Body.X, defender->Body.Y); - } - - // If the unit has already performed DB this turn, then record that it's consumed one of its extra DBs - if (bombarder->Body.Status & USF_USED_DEFENSIVE_BOMBARD) { - int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, bombarder->Body.ID, 0); - itable_insert (&is->extra_defensive_bombards, bombarder->Body.ID, extra_dbs + 1); - } - - int damage_before = defender->Body.Damage; - Fighter_damage_by_defensive_bombard (this, __, bombarder, defender); - int damage_after = defender->Body.Damage; - - is->dbe.bombarder = bombarder; - is->dbe.defender = defender; - if (damage_after > damage_before) { - is->dbe.damage_done = true; - int max_hp = Unit_get_max_hp (defender); - int dead_before = damage_before >= max_hp, dead_after = damage_after >= max_hp; - - // If the unit was killed by defensive bombard, play its death animation then toggle off animations for the rest of the combat so it - // doesn't look like anything else happens. Technically, the combat continues and the dead unit is guarantted to lose because the - // patch to get_combat_odds ensures the dead unit has no chance of winning a round. - if (dead_before ^ dead_after) { - is->dbe.defender_was_destroyed = true; - if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (this, __, bombarder, defender, true)) - Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, defender, AT_DEATH, false); - is->dbe.saved_animation_setting = this->play_animations; - this->play_animations = 0; - } - } -} - -int __fastcall -patch_Fighter_get_odds_for_main_combat_loop (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses) -{ - if (is->dbe.defender_was_destroyed) - return 1025; - - struct c3x_config * cfg = &is->current_config; - if (cfg->enable_unit_counters && attacker != NULL && defender != NULL) { - Tile * def_tile = tile_at (this->defender_location_x, - this->defender_location_y); - int aa, dd; - bool ignore_terrain; - apply_counter_rules (cfg, attacker, defender, def_tile, - &aa, &dd, &ignore_terrain); - - is->counter_combat_ctx.active = true; - is->counter_combat_ctx.attacker = attacker; - is->counter_combat_ctx.defender = defender; - is->counter_combat_ctx.attacker_atk_pct = aa; - is->counter_combat_ctx.defender_def_pct = dd; - is->counter_combat_ctx.ignore_terrain = ignore_terrain; - } - - int result = Fighter_get_combat_odds (this, __, attacker, defender, bombarding, - ignore_defensive_bonuses || is->counter_combat_ctx.ignore_terrain); - is->counter_combat_ctx.active = false; - return result; -} - -void -apply_counter_rules_unused_placeholder () {} // 占位,已移至正确位置 - -byte __fastcall -patch_Fighter_fight (Fighter * this, int edx, Unit * attacker, - int attack_direction, Unit * defender_or_null) -{ - byte tr = Fighter_fight (this, __, attacker, attack_direction, - defender_or_null); - is->dbe = (struct defensive_bombard_event) {0}; - is->counter_combat_ctx.active = false; - return tr; -} - -int __fastcall -patch_Unit_get_attack_strength (Unit * this) -{ - int base = Unit_get_attack_strength (this); - if (! is->counter_combat_ctx.active) - return base; - if (this == is->counter_combat_ctx.attacker) - return base * is->counter_combat_ctx.attacker_atk_pct / 100; - return base; -} - -int __fastcall -patch_Unit_get_defense_strength (Unit * this) -{ - int base = Unit_get_defense_strength (this); - if (! is->counter_combat_ctx.active) - return base; - if (this == is->counter_combat_ctx.defender) - return base * is->counter_combat_ctx.defender_def_pct / 100; - return base; -} - -void __fastcall -patch_Unit_score_kill_by_defender (Unit * this, int edx, Unit * victim, bool was_attacking) -{ - // This function is called when the defender wins in combat. If the attacker was actually killed by defensive bombardment, then award credit - // for that kill to the defensive bombarder not the defender in combat. - if (is->dbe.defender_was_destroyed) { - is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; - Unit_score_kill (is->dbe.bombarder, __, victim, was_attacking); - is->do_not_enslave_units = false; - p_bic_data->fighter.play_animations = is->dbe.saved_animation_setting; - - } else - Unit_score_kill (this, __, victim, was_attacking); -} - -void __fastcall -patch_Unit_play_attack_anim_for_def_bombard (Unit * this, int edx, int direction) -{ - // Don't play any animation for air units, the animations are instead handled in the patch for damage_by_defensive_bombard - if (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) { - - // Make sure the unit is displayed if it's in an army and we're configured for that - struct unit_display_override saved_udo = is->unit_display_override; - Unit * container; - if (is->current_config.show_armies_performing_defensive_bombard && - (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && - Unit_has_ability (container, __, UTA_Army)) - is->unit_display_override = (struct unit_display_override) { this->Body.ID, this->Body.X, this->Body.Y }; - - Unit_play_attack_animation (this, __, direction); - - is->unit_display_override = saved_udo; - } -} - -bool -can_precision_strike_tile_improv_at (Unit * unit, int x, int y) -{ - Tile * tile; - return is->current_config.allow_precision_strikes_against_tile_improvements && // we're configured to allow prec. strikes vs tiles AND - ((tile = tile_at (x, y)) != p_null_tile) && // get tile, make sure it's valid AND - is_explored (tile, unit->Body.CivID) && // tile has been explored by attacker AND - has_any_destructible_overlays (tile, true); // it has something that can be destroyed by prec. strike -} - -// Same as above function except this one applies to the V3 field instead of FOWStatus -Tile * __cdecl -patch_tile_at_for_v3_check (int x, int y) -{ - Tile * tile = tile_at (x, y); - int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; - if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { - is->dummy_tile->Body.V3 = ((tile->Body.V3 & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; - return is->dummy_tile; - } else - return tile; -} - -bool __fastcall -patch_Unit_check_contact_bit_6_on_right_click (Unit * this, int edx, int civ_id) -{ - bool tr = Unit_check_contact_bit_6 (this, __, civ_id); - if ((! tr) && - is->current_config.share_visibility_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << civ_id) & *p_human_player_bits)) { // is civ_id a human player - if ((1 << this->Body.CivID) & *p_human_player_bits) - tr = true; - - else { - // Check if any other human player has contact - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != civ_id) && - Unit_check_contact_bit_6 (this, __, n_player)) { - tr = true; - break; - } - player_bits >>= 1; - n_player++; - } - } - } - return tr; -} - -bool __fastcall -patch_Unit_check_precision_strike_target (Unit * this, int edx, int tile_x, int tile_y) -{ - return Unit_check_precision_strike_target (this, __, tile_x, tile_y) || can_precision_strike_tile_improv_at (this, tile_x, tile_y); -} - -void __fastcall -patch_Unit_play_attack_animation_vs_tile (Unit * this, int edx, int direction) -{ - if (is->current_config.polish_precision_striking && - UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile) && - (is->attacking_tile_x != this->Body.X) && (is->attacking_tile_y != this->Body.Y)) - Unit_animate_cruise_missile_strike (this, __, is->attacking_tile_x, is->attacking_tile_y); - else - Unit_play_attack_animation (this, __, direction); -} - -void __fastcall -patch_Unit_attack_tile (Unit * this, int edx, int x, int y, int bombarding) -{ - Tile * target_tile = NULL; - bool had_district_before = false; - int district_id_before = -1; - int tile_x = x; - int tile_y = y; - - if (is->current_config.enable_districts) { - - // Check if this is a completed wonder district that cannot be destroyed - if (is->current_config.enable_wonder_districts && - !is->current_config.completed_wonder_districts_can_be_destroyed) { - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - target_tile = tile_at (tile_x, tile_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - struct wonder_district_info * info = get_wonder_district_info (target_tile); - if (info != NULL && info->state == WDS_COMPLETED) { - // This tile has a completed wonder district and they can't be destroyed - if (((*p_human_player_bits & (1 << this->Body.CivID)) != 0) && - (this->Body.CivID == p_main_screen_form->Player_CivID)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_PILLAGE", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - return; - } - } - } - - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - target_tile = tile_at (tile_x, tile_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (target_tile); - if (inst != NULL) { - had_district_before = true; - district_id_before = inst->district_id; - } - } - } - - is->attacking_tile_x = x; - is->attacking_tile_y = y; - if (bombarding) - is->unit_bombard_attacking_tile = this; - - Unit_attack_tile (this, __, x, y, bombarding); - - // Check if the district was destroyed by the attack - if (had_district_before && (target_tile != NULL) && (target_tile != p_null_tile) && district_id_before != NATURAL_WONDER_DISTRICT_ID) { - struct district_instance * inst_after = get_district_instance (target_tile); - bool has_district_after = (inst_after != NULL); - int district_id_after = (inst_after != NULL) ? inst_after->district_id : -1; - - // If the district existed before but not after, or the tile no longer has a mine, the district was destroyed - if (!has_district_after || !(target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & TILE_FLAG_MINE)) { - bool is_water_tile = target_tile != NULL && target_tile->vtable->m35_Check_Is_Water (target_tile); - handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, ! is_water_tile); - } - } - - is->unit_bombard_attacking_tile = NULL; - is->attacking_tile_x = is->attacking_tile_y = -1; -} - -void __fastcall -patch_Unit_do_precision_strike (Unit * this, int edx, int x, int y) -{ - if ((city_at (x, y) == NULL) && can_precision_strike_tile_improv_at (this, x, y)) - patch_Unit_attack_tile (this, __, x, y, 1); - else - Unit_do_precision_strike (this, __, x, y); - - if (is->current_config.polish_precision_striking && - UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile)) - patch_Unit_despawn (this, __, 0, false, false, 0, 0, 0, 0); -} - -int __fastcall -patch_Unit_get_max_moves_after_barricade_attack (Unit * this) -{ - if (is->current_config.dont_end_units_turn_after_bombarding_barricade && (this == is->unit_bombard_attacking_tile)) - return this->Body.Moves + p_bic_data->General.RoadsMovementRate; - else - return patch_Unit_get_max_move_points (this); -} - -City * __cdecl -patch_city_at_in_find_bombard_defender (int x, int y) -{ - // The caller (Fighter::find_defender_against_bombardment) has a set of lists of bombard priority/eligibility in its stack memory. The list - // for land units bombarding land tiles normally restricts the targets to land units by containing [UTC_Land, -1, -1]. If we're configured to - // remove that restriction, modify the list so it contains instead [UTC_Land, UTC_Sea, UTC_Air]. Conveniently, the offset from this function's - // first parameter to the list is 0x40 bytes in all executables. - if (is->current_config.remove_land_artillery_target_restrictions) { - enum UnitTypeClasses * list = (void *)((byte *)&x + 0x40); - list[1] = UTC_Sea; - list[2] = UTC_Air; - } - - return city_at (x, y); -} - -bool __fastcall -patch_Unit_check_bombard_target (Unit * this, int edx, int tile_x, int tile_y) -{ - bool base = Unit_check_bombard_target (this, __, tile_x, tile_y); - Tile * tile = tile_at (tile_x, tile_y); - int overlays; - - if (base && - itable_look_up_or (&is->current_config.can_bombard_only_sea_tiles, this->Body.UnitTypeID, 0) && - ! tile->vtable->m35_Check_Is_Water (tile)) - return false; - - else if (base && - is->current_config.disallow_useless_bombard_vs_airfields && - ! Unit_has_ability (this, __, UTA_Nuclear_Weapon) && - ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // if tile has an airfield AND - (overlays == 0x20000000)) { // tile only has an airfield - UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - - // Check that a bombard attack vs this tile would not be wasted. It won't be if either (1) there are no units on the tile, (2) there - // is a unit that can be damaged by bombarding, or (3) there are no units that can be damaged and no air units. The rules for - // bombardment are that you can't damage aircraft in an airfield and you also can't destroy an airfield from underneath aircraft. - int any_units = 0, - any_vulnerable_units = 0, - any_air_units = 0; - FOR_UNITS_ON (uti, tile) { - enum UnitTypeClasses class = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; - any_units = 1; - any_air_units |= class == UTC_Air; - any_vulnerable_units |= (class != UTC_Air) && (Unit_get_defense_strength (uti.unit) > 0) && - can_damage_bombarding (this_type, uti.unit, tile); - } - return (! any_units) || // case (1) above - any_vulnerable_units || // case (2) - ((! any_air_units) && (! any_vulnerable_units)); // case (3) - - } else - return base; -} - -bool __fastcall -patch_Unit_can_disembark_anything (Unit * this, int edx, int tile_x, int tile_y) -{ - Tile * this_tile = tile_at (this->Body.X, this->Body.Y); - Tile * target_tile = tile_at (tile_x, tile_y); - bool base = Unit_can_disembark_anything (this, __, tile_x, tile_y); - - // Apply units per tile limit - if (base) { - bool stack_limited_for_all = true; - FOR_UNITS_ON (uti, this_tile) - if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_below_stack_limit (target_tile, this->Body.CivID, uti.unit->Body.UnitTypeID)) { - stack_limited_for_all = false; - break; - } - if (stack_limited_for_all) - return false; - } - - // Apply trespassing restriction. First check if this civ may move into (tile_x, tile_y) without trespassing. If it would be trespassing, then - // we can only disembark anything if this transport has a passenger that can ignore the restriction. Without this check, the game can enter an - // infinite loop under rare circumstances. - if (base && - is->current_config.disallow_trespassing && - check_trespassing (this->Body.CivID, this_tile, target_tile)) { - bool any_exempt_passengers = false; - FOR_UNITS_ON (uti, this_tile) - if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_allowed_to_trespass (uti.unit)) { - any_exempt_passengers = true; - break; - } - return any_exempt_passengers; - - } else - return base; -} - -int __fastcall -patch_Unit_get_defense_for_bombardable_unit_check (Unit * this) -{ - // Returning a defense value of zero indicates this unit is not a target for bombardment. If configured, exclude all air units from - // bombardment so the attacks target tile improvements instead. Do this only if the tile has another improvement in addition to an airfield, - // or we could destroy the airfield itself. - Tile * tile; - int overlays; - if (is->current_config.allow_bombard_of_other_improvs_on_occupied_airfield && // If configured AND - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && // "this" is an air unit AND - ((tile = tile_at (this->Body.X, this->Body.Y)) != p_null_tile) && // "this" is on a valid tile AND - ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // tile has an airfield AND - (overlays != 0x20000000)) // tile does not only have an airfield - return 0; - - else - return Unit_get_defense_strength (this); -} - -void __fastcall -patch_Demographics_Form_m22_draw (Demographics_Form * this) -{ - Demographics_Form_m22_draw (this); - - if (is->current_config.show_total_city_count) { - // There's proably a better way to get the city count, but better safe than sorry. I don't know if it's possible for the city list to - // contain holes so the surest thing is to check every possible ID. - int city_count = 0; { - if (p_cities->Cities != NULL) - for (int n = 0; n <= p_cities->LastIndex; n++) { - City_Body * body = p_cities->Cities[n].City; - city_count += (body != NULL) && ((int)body != offsetof (City, Body)); - } - } - - PCX_Image * canvas = &this->Base.Data.Canvas; - - // Draw backdrop - { - char temp_path[2*MAX_PATH]; - PCX_Image backdrop; - PCX_Image_construct (&backdrop); - get_mod_art_path ("CityCountBackdrop.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&backdrop, __, temp_path, NULL, 0, 0x100, 2); - if (backdrop.JGL.Image != NULL) { - int w = backdrop.JGL.Image->vtable->m54_Get_Width (backdrop.JGL.Image); - PCX_Image_draw_onto (&backdrop, __, canvas, (1024 - w) / 2, 720); - } - backdrop.vtable->destruct (&backdrop, __, 0); - } - - // Draw text on top of the backdrop - char s[100]; - snprintf (s, sizeof s, "%s %d / %d", is->c3x_labels[CL_TOTAL_CITIES], city_count, is->city_limit); - s[(sizeof s) - 1] = '\0'; - PCX_Image_set_text_effects (canvas, __, 0x80000000, -1, 2, 2); // Set text color to black - PCX_Image_draw_centered_text (canvas, __, get_font (14, FSF_NONE), s, 1024/2 - 100, 730, 200, strlen (s)); - } -} - -int __fastcall -patch_Leader_get_optimal_city_number (Leader * this) -{ - if (! is->current_config.strengthen_forbidden_palace_ocn_effect) - return Leader_get_optimal_city_number (this); - else { - int num_sans_fp = Leader_get_optimal_city_number (this), // OCN w/o contrib from num of FPs - fp_count = patch_Leader_count_wonders_with_small_flag (this, __, ITSW_Reduces_Corruption, NULL), - s_diff = p_bic_data->DifficultyLevels[this->player_difficulty].Optimal_Cities, // Difficulty scaling, called "percentage of optimal cities" in the editor - base_ocn = p_bic_data->WorldSizes[p_bic_data->Map.World.World_Size].OptimalCityCount; - return num_sans_fp + (s_diff * fp_count * base_ocn + 50) / 100; // Add 50 to round off - } -} - -int __fastcall -patch_Leader_count_forbidden_palaces_for_ocn (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) -{ - if (! is->current_config.strengthen_forbidden_palace_ocn_effect) - return patch_Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); - else - return 0; // We'll add in the FP effect later with a different weight -} - -void __fastcall -patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id) -{ - is->is_computing_city_connections = true; - long long ts_before; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); - - if (is->tnx_init_state == IS_OK) { - if (is->tnx_cache == NULL) { - is->tnx_cache = is->create_tnx_cache (&p_bic_data->Map); - is->set_up_before_building_network (is->tnx_cache); - } else if (! is->keep_tnx_cache) - is->set_up_before_building_network (is->tnx_cache); - } - - Trade_Net_recompute_city_connections (this, __, civ_id, redo_road_network, param_3, redo_roads_for_city_id); - - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; - - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - is->time_spent_computing_city_connections += ts_after - ts_before; - is->count_calls_to_recompute_city_connections++; - is->is_computing_city_connections = false; -} - -void __fastcall -patch_Map_build_trade_network (Map * this) -{ - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) - is->set_up_before_building_network (is->tnx_cache); - is->keep_tnx_cache = true; - Map_build_trade_network (this); - is->keep_tnx_cache = false; - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; -} - -void __fastcall -patch_Trade_Net_recompute_city_cons_and_res (Trade_Net * this, int edx, bool param_1) -{ - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) - is->set_up_before_building_network (is->tnx_cache); - - is->keep_tnx_cache = true; - Trade_Net_recompute_city_cons_and_res (this, __, param_1); - is->keep_tnx_cache = false; - - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; -} - -int __fastcall -patch_Trade_Net_set_unit_path_to_fill_road_net (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) -{ - int tr; - long long ts_before; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); - - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { - is->flood_fill_road_network (is->tnx_cache, from_x, from_y, civ_id); - tr = 0; // Return value is not used by caller anyway - } else - tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); - - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - is->time_spent_filling_roads += ts_after - ts_before; - return tr; -} - -bool -set_up_gdi_plus () -{ - if (is->gdi_plus.init_state == IS_UNINITED) { - is->gdi_plus.init_state = IS_INIT_FAILED; - is->gdi_plus.gp_graphics = NULL; - - struct startup_input { - UINT32 GdiplusVersion; - void * DebugEventCallback; - BOOL SuppressBackgroundThread; - BOOL SuppressExternalCodecs; - } startup_input = {1, NULL, FALSE, FALSE}; - - is->gdi_plus.module = LoadLibraryA ("gdiplus.dll"); - if (is->gdi_plus.module == NULL) { - MessageBoxA (NULL, "Failed to load gdiplus.dll!", "Error", MB_ICONERROR); - goto end_init; - } - - int (WINAPI * GdiplusStartup) (ULONG_PTR * out_token, struct startup_input *, void * startup_output) = - (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdiplusStartup"); - - is->gdi_plus.CreateFromHDC = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreateFromHDC"); - is->gdi_plus.DeleteGraphics = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeleteGraphics"); - is->gdi_plus.SetSmoothingMode = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetSmoothingMode"); - is->gdi_plus.SetPenDashStyle = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetPenDashStyle"); - is->gdi_plus.CreatePen1 = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreatePen1"); - is->gdi_plus.DeletePen = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeletePen"); - is->gdi_plus.DrawLineI = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDrawLineI"); - if ((is->gdi_plus.CreateFromHDC == NULL) || (is->gdi_plus.DeleteGraphics == NULL) || - (is->gdi_plus.SetSmoothingMode == NULL) || (is->gdi_plus.SetPenDashStyle == NULL) || - (is->gdi_plus.CreatePen1 == NULL) || (is->gdi_plus.DeletePen == NULL) || - (is->gdi_plus.DrawLineI == NULL)) { - MessageBoxA (NULL, "Failed to get GDI+ proc addresses!", "Error", MB_ICONERROR); - goto end_init; - } - - int status = GdiplusStartup (&is->gdi_plus.token, &startup_input, NULL); - if (status != 0) { - char s[200]; - snprintf (s, sizeof s, "Failed to initialize GDI+! Startup status: %d", status); - MessageBoxA (NULL, s, "Error", MB_ICONERROR); - goto end_init; - } - - is->gdi_plus.init_state = IS_OK; - end_init: - ; - } - - return is->gdi_plus.init_state == IS_OK; -} - -int __fastcall -patch_OpenGLRenderer_initialize (OpenGLRenderer * this, int edx, PCX_Image * texture) -{ - if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || - ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) - return OpenGLRenderer_initialize (this, __, texture); - - // Initialize GDI+ instead - else { - if (! set_up_gdi_plus ()) - return 2; - if (is->gdi_plus.gp_graphics != NULL) { - is->gdi_plus.DeleteGraphics (is->gdi_plus.gp_graphics); - is->gdi_plus.gp_graphics = NULL; - } - int status = is->gdi_plus.CreateFromHDC (texture->JGL.Image->DC, &is->gdi_plus.gp_graphics); - if (status == 0) { - is->gdi_plus.SetSmoothingMode (is->gdi_plus.gp_graphics, 4); // 4 = SmoothingModeAntiAlias from GdiPlusEnums.h - return 0; - } else - return 2; - } -} - -void __fastcall -patch_OpenGLRenderer_set_color (OpenGLRenderer * this, int edx, unsigned int rgb555) -{ - // Convert rgb555 to rgb888 - unsigned int rgb888 = 0; { - unsigned int mask = 31; - int shift = 3; - for (int n = 0; n < 3; n++) { - rgb888 |= (rgb555 & mask) << shift; - mask <<= 5; - shift += 3; - } - } - - is->ogl_color = (is->ogl_color & 0xFF000000) | rgb888; - OpenGLRenderer_set_color (this, __, rgb555); -} - -void __fastcall -patch_OpenGLRenderer_set_opacity (OpenGLRenderer * this, int edx, unsigned int alpha) -{ - is->ogl_color = (is->ogl_color & 0x00FFFFFF) | (alpha << 24); - OpenGLRenderer_set_opacity (this, __, alpha); -} - -void __fastcall -patch_OpenGLRenderer_set_line_width (OpenGLRenderer * this, int edx, int width) -{ - is->ogl_line_width = width; - OpenGLRenderer_set_line_width (this, __, width); -} - -void __fastcall -patch_OpenGLRenderer_enable_line_dashing (OpenGLRenderer * this) -{ - is->ogl_line_stipple_enabled = true; - OpenGLRenderer_enable_line_dashing (this); -} - -void __fastcall -patch_OpenGLRenderer_disable_line_dashing (OpenGLRenderer * this) -{ - is->ogl_line_stipple_enabled = false; - OpenGLRenderer_disable_line_dashing (this); -} - -void __fastcall -patch_OpenGLRenderer_draw_line (OpenGLRenderer * this, int edx, int x1, int y1, int x2, int y2) -{ - if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || - ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) - OpenGLRenderer_draw_line (this, __, x1, y1, x2, y2); - - else if ((is->gdi_plus.init_state == IS_OK) && (is->gdi_plus.gp_graphics != NULL)) { - void * gp_pen; - int unit_world = 0; // = UnitWorld from gdiplusenums.h - int status = is->gdi_plus.CreatePen1 (is->ogl_color, (float)is->ogl_line_width, unit_world, &gp_pen); - if (status == 0) { - if (is->ogl_line_stipple_enabled) - is->gdi_plus.SetPenDashStyle (gp_pen, 1); // 1 = DashStyleDash from GdiPlusEnums.h - is->gdi_plus.DrawLineI (is->gdi_plus.gp_graphics, gp_pen, x1, y1, x2, y2); - is->gdi_plus.DeletePen (gp_pen); - } - } -} - -int __fastcall -patch_Tile_check_water_for_retreat_on_defense (Tile * this) -{ - Unit * defender = p_bic_data->fighter.defender; - - // Under the standard game rules, defensively retreating onto a water tile is not allowed. Set retreat_blocked to true if "this" is a water - // tile and we're not configured to allow retreating onto water tiles. - bool retreat_blocked; { - if (this->vtable->m35_Check_Is_Water (this)) { - if ( is->current_config.allow_defensive_retreat_on_water - && defender != NULL - && p_bic_data->UnitTypes[defender->Body.UnitTypeID].Unit_Class == UTC_Sea - && ( is->current_config.limit_defensive_retreat_on_water_to_types.len == 0 - || (bool)itable_look_up_or (&is->current_config.limit_defensive_retreat_on_water_to_types, defender->Body.UnitTypeID, 0))) - retreat_blocked = false; - else - retreat_blocked = true; - } else - retreat_blocked = false; - } - - // Check stack limit - if ((! retreat_blocked) && - (defender != NULL) && - ! is_below_stack_limit (this, defender->Body.CivID, defender->Body.UnitTypeID)) - retreat_blocked = true; - - // The return from this call is only used to filter the given tile as a possible retreat destination based on whether it's water or not - return (int)retreat_blocked; -} - -int __fastcall -patch_City_count_airports_for_airdrop (City * this, int edx, enum ImprovementTypeFlags airport_flag) -{ - if (is->current_config.allow_airdrop_without_airport) - return 1; - else - return City_count_improvements_with_flag (this, __, airport_flag); -} - -int __fastcall -patch_Leader_get_cont_city_count_for_worker_req (Leader * this, int edx, int cont_id) -{ - int tr = Leader_get_city_count_on_continent (this, __, cont_id); - if (is->current_config.ai_worker_requirement_percent != 100) - tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; - return tr; -} - -int __fastcall -patch_Leader_get_city_count_for_worker_prod_cap (Leader * this) -{ - int tr = this->Cities_Count; - // Don't scale down the cap since it's pretty low to begin with - if (is->current_config.ai_worker_requirement_percent > 100) - tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; - return tr; -} - -// If "only_improv_id" is >= 0, will only return yields from mills attached to that improv, otherwise returns all yields from all improvs -void -gather_mill_yields (City * city, int only_improv_id, int * out_food, int * out_shields, int * out_commerce) -{ - int food = 0, shields = 0, commerce = 0; - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if ((mill->flags & MF_YIELDS) && - ((only_improv_id < 0) || (mill->improv_id == only_improv_id)) && - can_generate_resource (city->Body.CivID, mill) && - has_active_building (city, mill->improv_id) && - has_resources_required_by_building (city, mill->improv_id)) { - Resource_Type * res = &p_bic_data->ResourceTypes[mill->resource_id]; - food += res->Food; - shields += res->Shield; - commerce += res->Commerce; - } - } - *out_food = food; - *out_shields = shields; - *out_commerce = commerce; -} - -int __fastcall -patch_City_calc_tile_yield_while_gathering (City * this, int edx, YieldKind kind, int tile_x, int tile_y) -{ - int tr = City_calc_tile_yield_at (this, __, kind, tile_x, tile_y); - - // Include yields from generated resources - if ((this->Body.X == tile_x) && (this->Body.Y == tile_y)) { - int mill_food, mill_shields, mill_commerce; - gather_mill_yields (this, -1, &mill_food, &mill_shields, &mill_commerce); - if (kind == YK_FOOD) tr += mill_food; - else if (kind == YK_SHIELDS) tr += mill_shields; - else if (kind == YK_COMMERCE) tr += mill_commerce; - - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - int bonus_food = 0, bonus_shields = 0, bonus_gold = 0; - calculate_city_center_district_bonus (this, &bonus_food, &bonus_shields, &bonus_gold); - if (kind == YK_FOOD) tr += bonus_food; - else if (kind == YK_SHIELDS) tr += bonus_shields; - else if (kind == YK_COMMERCE) tr += bonus_gold; - } - } - - return tr; -} - -bool __fastcall -patch_Leader_record_export (Leader * this, int edx, int importer_civ_id, int resource_id) -{ - bool exported = Leader_record_export (this, __, importer_civ_id, resource_id); - if (exported && - (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill - is->must_recompute_resources_for_mill_inputs = true; - return exported; -} - -bool __fastcall -patch_Leader_erase_export (Leader * this, int edx, int importer_civ_id, int resource_id) -{ - bool erased = Leader_erase_export (this, __, importer_civ_id, resource_id); - if (erased && - (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill - is->must_recompute_resources_for_mill_inputs = true; - return erased; -} - -int __fastcall -patch_Sprite_draw_improv_img_on_city_form (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int tr = Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); - - int generated_resources[16]; - int generated_resource_count = 0; - for (int n = 0; (n < is->current_config.count_mills) && (generated_resource_count < ARRAY_LEN (generated_resources)); n++) { - struct mill * mill = &is->current_config.mills[n]; - if ((mill->improv_id == is->drawing_icons_for_improv_id) && - ((mill->flags & MF_SHOW_BONUS) || (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus)) && - (! ((mill->flags & MF_HIDE_NON_BONUS) && (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus))) && - can_generate_resource (p_city_form->CurrentCity->Body.CivID, mill) && - has_active_building (p_city_form->CurrentCity, mill->improv_id) && - has_resources_required_by_building (p_city_form->CurrentCity, mill->improv_id)) - generated_resources[generated_resource_count++] = mill->resource_id; - } - - if ((generated_resource_count > 0) && (is->resources_sheet != NULL) && (is->resources_sheet->JGL.Image != NULL) && (TransparentBlt != NULL)) { - JGL_Image * jgl_canvas = canvas->JGL.Image, - * jgl_sheet = is->resources_sheet->JGL.Image; - - HDC canvas_dc = jgl_canvas->vtable->acquire_dc (jgl_canvas); - if (canvas_dc != NULL) { - HDC sheet_dc = jgl_sheet->vtable->acquire_dc (jgl_sheet); - if (sheet_dc != NULL) { - - for (int n = 0; n < generated_resource_count; n++) { - int icon_id = p_bic_data->ResourceTypes[generated_resources[n]].IconID, - sheet_row = icon_id / 6, - sheet_col = icon_id % 6; - - int dy = (n * 160 / not_below (1, generated_resource_count - 1) + 5) / 10; - TransparentBlt (canvas_dc, // dest DC - pixel_x + 15, pixel_y + dy, 24, 24, // dest x, y, width, height - sheet_dc, // src DC - 9 + 50*sheet_col, 9 + 50*sheet_row, 33, 33, // src x, y, width, height - 0xFF00FF); // transparent color (RGB) - } - - jgl_sheet->vtable->release_dc (jgl_sheet, __, 1); - } - jgl_canvas->vtable->release_dc (jgl_canvas, __, 1); - } - } - return tr; -} - -void __cdecl -patch_draw_improv_icons_on_city_screen (Base_List_Control * control, int improv_id, int item_index, int offset_x, int offset_y) -{ - is->drawing_icons_for_improv_id = improv_id; - draw_improv_icons_on_city_screen (control, improv_id, item_index, offset_x, offset_y); - is->drawing_icons_for_improv_id = -1; -} - -int __fastcall -patch_City_get_tourism_amount_to_draw (City * this, int edx, int improv_id) -{ - is->tourism_icon_counter = 0; - - int mill_food, mill_shields, mill_commerce; - gather_mill_yields (this, improv_id, &mill_food, &mill_shields, &mill_commerce); - int combined_commerce = mill_commerce + City_get_tourism_amount (this, __, improv_id); - - is->convert_displayed_tourism_to_food = mill_food; - is->convert_displayed_tourism_to_shields = mill_shields; - is->combined_tourism_and_mill_commerce = combined_commerce; - return int_abs (mill_food) + int_abs (mill_shields) + int_abs (combined_commerce); -} - -int __fastcall -patch_Sprite_draw_tourism_gold (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - // Replace the yield sprite we're drawing with food or a shield if needed. - Sprite * sprite = NULL; { - if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food)) { - if (is->convert_displayed_tourism_to_food >= 0) - sprite = &p_city_form->City_Icons_Images.Icon_15_Food; - else { - init_red_food_icon (); - if (is->red_food_icon_state == IS_OK) - sprite = &is->red_food_icon; - } - } else if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food) + int_abs (is->convert_displayed_tourism_to_shields)) - sprite = (is->convert_displayed_tourism_to_shields >= 0) ? &p_city_form->City_Icons_Images.Icon_13_Shield : &p_city_form->City_Icons_Images.Icon_05_Shield_Outcome; - else if (is->combined_tourism_and_mill_commerce < 0) - sprite = &p_city_form->City_Icons_Images.Icon_17_Gold_Outcome; - else - sprite = this; - } - - int tr = 0; // return value is not used by caller - if (sprite != NULL) - tr = Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, color_table); - is->tourism_icon_counter++; - return tr; -} - -Unit * __fastcall -patch_Leader_spawn_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) -{ - int spawn_x = tile_x, - spawn_y = tile_y; - - if (is->current_config.enable_districts) { - UnitType * type = &p_bic_data->UnitTypes[type_id]; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities) { - City * spawn_city = city_at (tile_x, tile_y); - if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { - int district_x, district_y; - Tile * district_tile = get_completed_district_tile_for_city (spawn_city, AERODROME_DISTRICT_ID, &district_x, &district_y); - if ((district_tile != NULL) && (district_tile != p_null_tile) && - (district_tile->Territory_OwnerID == this->ID) && - is_below_stack_limit (district_tile, this->ID, type_id)) { - spawn_x = district_x; - spawn_y = district_y; - } - } - } - - if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities) { - City * spawn_city = city_at (tile_x, tile_y); - if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { - int district_x, district_y; - Tile * district_tile = get_completed_district_tile_for_city (spawn_city, PORT_DISTRICT_ID, &district_x, &district_y); - if ((district_tile != NULL) && (district_tile != p_null_tile) && - (district_tile->Territory_OwnerID == this->ID) && - is_below_stack_limit (district_tile, this->ID, type_id)) { - spawn_x = district_x; - spawn_y = district_y; - } - } - } - } - - Unit * tr = Leader_spawn_unit (this, __, type_id, spawn_x, spawn_y, barb_tribe_id, id, param_6, leader_kind, race_id); - if (tr != NULL) - change_unit_type_count (this, type_id, 1); - return tr; -} - -Unit * __fastcall -patch_Leader_spawn_captured_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) -{ - Unit * tr = patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); - if ((tr != NULL) && is->moving_unit_to_adjacent_tile) - is->temporarily_disallow_lethal_zoc = true; - return tr; -} - -void __fastcall -patch_Leader_enter_new_era (Leader * this, int edx, bool param_1, bool no_online_sync) -{ - Leader_enter_new_era (this, __, param_1, no_online_sync); - apply_era_specific_names (this); -} - -char * __fastcall -patch_Leader_get_player_title_for_intro_popup (Leader * this) -{ - // Normally the era-specific names are applied later, after game loading is finished, but in this case we apply the player's names ahead of - // time so they appear on the intro popup. "this" will always refer to the human player in this call. - apply_era_specific_names (this); - return Leader_get_title (this); -} - -void __fastcall -patch_City_spawn_unit_if_done (City * this) -{ - bool skip_spawn = false; - - // Apply unit limit. If this city's owner has reached the limit for the unit type it's building then force it to build something else. - int available; - if ((this->Body.Order_Type == COT_Unit) && - get_available_unit_count (&leaders[this->Body.CivID], this->Body.Order_ID, &available) && - (available <= 0)) { - int limited_unit_type_id = this->Body.Order_ID; - - if (*p_human_player_bits & 1<Body.CivID) { - // Find another type ID to build instead of the limited one - int replacement_type_id = -1; { - int limited_unit_strat = p_bic_data->UnitTypes[limited_unit_type_id].AI_Strategy, - shields_in_box = this->Body.StoredProduction; - UnitType * replacement_type; - for (int can_type_id = 0; can_type_id < p_bic_data->UnitTypeCount; can_type_id++) - if (patch_City_can_build_unit (this, __, can_type_id, 1, 0, 0)) { - UnitType * candidate_type = &p_bic_data->UnitTypes[can_type_id]; - - // If we haven't found a replacement yet, use this one - if (replacement_type_id < 0) { - replacement_type_id = can_type_id; - replacement_type = candidate_type; - - // Keep the prev replacement if it doesn't waste shields but this candidate would - } else if ((replacement_type->Cost >= shields_in_box) && (candidate_type->Cost < shields_in_box)) - continue; - - // Keep the prev if it shares an AI strategy with the limited unit but this candidate doesn't - else if (((replacement_type->AI_Strategy & limited_unit_strat) != 0) && - ((candidate_type ->AI_Strategy & limited_unit_strat) == 0)) - continue; - - // At this point we know switching to the candidate would not cause us to waste shields and would not - // give us a worse match role-wise to the original limited unit. So pick it if it's better somehow, - // either a better role match or more expensive. - else if ((candidate_type->Cost > replacement_type->Cost) || - (((replacement_type->AI_Strategy & limited_unit_strat) == 0) && - ((candidate_type ->AI_Strategy & limited_unit_strat) != 0))) { - replacement_type_id = can_type_id; - replacement_type = candidate_type; - } - } - } - - if (replacement_type_id >= 0) { - City_set_production (this, __, COT_Unit, replacement_type_id, false); - if (this->Body.CivID == p_main_screen_form->Player_CivID) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, this->Body.CityName, -1, -1); - set_popup_str_param (1, p_bic_data->UnitTypes[limited_unit_type_id].Name, -1, -1); - int limit = -1; - get_unit_limit (&leaders[this->Body.CivID], limited_unit_type_id, &limit); - set_popup_int_param (2, limit); - set_popup_str_param (3, p_bic_data->UnitTypes[replacement_type_id].Name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_LIMITED_UNIT_CHANGE", -1, 0, 0, 0); - int response = patch_show_popup (popup, __, 0, 0); - if (response == 0) - *p_zoom_to_city_after_update = true; - } - } - - } else { - City_Order order; - patch_City_ai_choose_production (this, __, &order); - City_set_production (this, __, order.OrderType, order.OrderID, false); - } - - // If the player changed production to something other than a unit, don't spawn anything - if (this->Body.Order_Type != COT_Unit) - skip_spawn = true; - - // Just as a final check, if we weren't able to switch production off the limited unit, prevent it from being spawned so the limit - // doesn't get violated. - if ((this->Body.Order_Type == COT_Unit) && (this->Body.Order_ID == limited_unit_type_id)) - skip_spawn = true; - } - - // Check district requirements for air and naval units - if ((! skip_spawn) && (this->Body.Order_Type == COT_Unit) && is->current_config.enable_districts) { - int unit_id = this->Body.Order_ID; - UnitType * type = &p_bic_data->UnitTypes[unit_id]; - bool needs_district = false; - int required_district_id = -1; - - // Air units require aerodrome - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (this, AERODROME_DISTRICT_ID))) { - needs_district = true; - required_district_id = AERODROME_DISTRICT_ID; - } - // Naval units require port - else if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (this, PORT_DISTRICT_ID))) { - needs_district = true; - required_district_id = PORT_DISTRICT_ID; - } - - if (needs_district) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - - // For AI, redirect to a safe fallback and queue the missing district. - // For humans, this late hook should only veto the spawn and show a warning, - // otherwise the city gets switched off the intended build with no unit spawned. - if (! is_human) { - mark_city_needs_district (this, required_district_id); - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (this, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - // Show message to human player - if (is_human && (this->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[160]; - char const * unit_name = type->Name; - char const * district_name = is->district_configs[required_district_id].name; - snprintf (msg, sizeof msg, "%s %s %s", unit_name, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_name); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (this->Body.X, this->Body.Y, msg, true); - } - - skip_spawn = true; - } - } - - if (! skip_spawn) - City_spawn_unit_if_done (this); -} - -void __fastcall -patch_Leader_upgrade_all_units (Leader * this, int edx, int type_id) -{ - is->penciled_in_upgrade_count = 0; - Leader_upgrade_all_units (this, __, type_id); -} - -void __fastcall -patch_Main_Screen_Form_upgrade_all_units (Main_Screen_Form * this, int edx, int type_id) -{ - is->penciled_in_upgrade_count = 0; - Main_Screen_Form_upgrade_all_units (this, __, type_id); -} - -bool __fastcall -patch_Unit_can_perform_upgrade_all (Unit * this, int edx, int unit_command_value) -{ - bool base = patch_Unit_can_perform_command (this, __, unit_command_value); - - // Deal with unit limits. If the unit type we're upgrading to is limited, we need to pencil in the upgrade to make sure that we don't queue up - // so many upgrades that we exceed the limit. - City * city; - int upgrade_id, available; - if (base && - (is->current_config.unit_limits.len > 0) && - (NULL != (city = city_at (this->Body.X, this->Body.Y))) && - (0 <= (upgrade_id = City_get_upgraded_type_id (city, __, this->Body.UnitTypeID))) && - get_available_unit_count (&leaders[this->Body.CivID], upgrade_id, &available)) { - - // Find penciled in upgrade. Add a new one if we don't already have one. - struct penciled_in_upgrade * piu = NULL; { - for (int n = 0; n < is->penciled_in_upgrade_count; n++) - if (is->penciled_in_upgrades[n].unit_type_id == upgrade_id) { - piu = &is->penciled_in_upgrades[n]; - break; - } - if (piu == NULL) { - reserve (sizeof is->penciled_in_upgrades[0], (void **)&is->penciled_in_upgrades, &is->penciled_in_upgrade_capacity, is->penciled_in_upgrade_count); - piu = &is->penciled_in_upgrades[is->penciled_in_upgrade_count]; - is->penciled_in_upgrade_count += 1; - piu->unit_type_id = upgrade_id; - piu->count = 0; - } - } - - // If we can have more units of the type we're upgrading to, pencil in another upgrade and return true. Otherwise return false so this - // unit isn't considered one of the upgradable ones. - if (piu->count < available) { - piu->count += 1; - return true; - } else - return false; - - } else - return base; -} - -void __fastcall -patch_Fighter_animate_start_of_combat (Fighter * this, int edx, Unit * attacker, Unit * defender) -{ - // Temporarily clear the attacker retreat eligibility flag when needed so naval units are rotated and animated properly. Normally the game - // does not use ranged animations when the attacker can retreat and, worse, not using ranged anims means it also ignores the - // rotate-before-attack setting. - bool restore_attacker_retreat_eligibility = false; - if ((is->current_config.sea_retreat_rules != RR_STANDARD) && - (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Sea) && - Unit_has_ability (attacker, __, UTA_Ranged_Attack_Animation) && - Unit_has_ability (defender, __, UTA_Ranged_Attack_Animation) && - this->attacker_eligible_to_retreat) { - this->attacker_eligible_to_retreat = false; - restore_attacker_retreat_eligibility = true; - } - - Fighter_animate_start_of_combat (this, __, attacker, defender); - - if (restore_attacker_retreat_eligibility) - this->attacker_eligible_to_retreat = true; -} - -Unit * __fastcall -patch_Leader_spawn_unit_from_building (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) -{ - int available; - if (get_available_unit_count (this, type_id, &available) && (available <= 0)) - return NULL; - else - return patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); -} - -int __fastcall -patch_City_count_improvs_enabling_upgrade (City * this, int edx, enum ImprovementTypeFlags flag) -{ - return is->current_config.allow_upgrades_in_any_city ? 1 : City_count_improvements_with_flag (this, __, flag); -} - -City * __fastcall -patch_Leader_create_city_from_hut (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_POPPED_FROM_HUT); - return tr; -} - -City * __fastcall -patch_Leader_create_city_for_ai_respawn (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_PLACED_FOR_AI_RESPAWN); - return tr; -} - -City * __fastcall -patch_Leader_create_city_for_founding (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_FOUNDED); - return tr; -} - -City * __fastcall -patch_Leader_create_city_for_scenario (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_PLACED_FOR_SCENARIO); - return tr; -} - -City * -find_city_to_inherit_shared_small_wonder (Leader * leader, int wonder_improv_id) -{ - if ((leader == NULL) || - (! is->current_config.enable_districts) || - (! is->current_config.enable_wonder_districts) || - (! is->current_config.cities_with_mutual_district_receive_wonders)) - return NULL; - - FOR_CITIES_OF (coi, leader->ID) { - City * city = coi.city; - if ((city == NULL) || (! patch_City_has_improvement (city, __, wonder_improv_id, false))) - continue; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - Tile * tile = wai.tile; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if ((info == NULL) || (info->state != WDS_COMPLETED)) - continue; - - int nearby_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); - if (nearby_improv_id == wonder_improv_id) - return city; - } - } - - return NULL; -} - -void -collect_small_wonders_present_in_city (City * city, int * lost_small_wonders, int * lost_small_wonder_count, int max_lost_small_wonders) -{ - if ((city == NULL) || - (lost_small_wonders == NULL) || - (lost_small_wonder_count == NULL) || - (max_lost_small_wonders <= 0)) - return; - - *lost_small_wonder_count = 0; - - if (! is->current_config.enable_districts || - ! is->current_config.enable_wonder_districts || - ! is->current_config.cities_with_mutual_district_receive_wonders) - return; - - for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) == 0) - continue; - if (! patch_City_has_improvement (city, __, improv_id, false)) - continue; - if (*lost_small_wonder_count >= max_lost_small_wonders) - break; - lost_small_wonders[(*lost_small_wonder_count)++] = improv_id; - } -} - -void -reassign_shared_small_wonder_owners_after_city_loss (Leader * leader, int const * lost_small_wonders, int lost_small_wonder_count) -{ - if ((! is->current_config.enable_districts) || - (leader == NULL) || - (! is->current_config.enable_wonder_districts) || - (! is->current_config.cities_with_mutual_district_receive_wonders) || - (lost_small_wonders == NULL) || - (lost_small_wonder_count <= 0)) - return; - - for (int n = 0; n < lost_small_wonder_count; n++) { - int improv_id = lost_small_wonders[n]; - if ((improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) - continue; - - if (leader->Small_Wonders[improv_id] != -1) - continue; - - // Vanilla clears Leader.Small_Wonders when the recorded owner city loses the building during - // capture. Only repair the small wonders that were actually present in the lost city before - // capture, and if another city of the same civ still legitimately shares the wonder district, - // promote that city to be the new canonical owner so the small wonder's effects still work. - City * replacement = find_city_to_inherit_shared_small_wonder (leader, improv_id); - if (replacement != NULL) - leader->Small_Wonders[improv_id] = replacement->Body.ID; - } -} - -bool __fastcall -patch_Leader_do_capture_city (Leader * this, int edx, City * city, bool involuntary, bool converted) -{ - Leader * previous_owner = &leaders[city->Body.CivID]; - int lost_small_wonders[32]; - int lost_small_wonder_count; - - // Record which small wonders were physically present in the city before capture so any - // post-capture ownership repair only touches wonders actually affected. - collect_small_wonders_present_in_city (city, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); - - is->currently_capturing_city = city; - on_lose_city (previous_owner, city, converted ? CLR_CONVERTED : (involuntary ? CLR_CONQUERED : CLR_TRADED)); - bool tr = Leader_do_capture_city (this, __, city, involuntary, converted); - - // The game clears the losing civ's canonical Small_Wonders owner when the recorded city loses - // the building. Reassign that ownership here if another same-civ city still legitimately shares the wonder district. - if (is->current_config.enable_districts && - is->current_config.enable_wonder_districts && - is->current_config.cities_with_mutual_district_receive_wonders && - lost_small_wonder_count > 0) { - reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); - } - - on_gain_city (this, city, converted ? CGR_CONVERTED : (involuntary ? CGR_CONQUERED : CGR_TRADED)); - is->currently_capturing_city = NULL; - return tr; -} - -void __fastcall -patch_City_raze (City * this, int edx, int civ_id_responsible, bool checking_elimination) -{ - Leader * previous_owner = &leaders[this->Body.CivID]; - int lost_small_wonders[32]; - int lost_small_wonder_count; - - collect_small_wonders_present_in_city (this, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); - on_lose_city (previous_owner, this, CLR_DESTROYED); - City_raze (this, __, civ_id_responsible, checking_elimination); - - if (lost_small_wonder_count > 0) - reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); - - // Delete the extra improvement bits records for this city - City_Improvements * improv_lists[2] = {&this->Body.Improvements_1, &this->Body.Improvements_2}; - for (int n = 0; n < ARRAY_LEN (improv_lists); n++) { - City_Improvements * improv_list = improv_lists[n]; - byte * extra_bits; - if (itable_look_up (&is->extra_city_improvs, (int)improv_list, (int *)&extra_bits)) { - free (extra_bits); - itable_remove (&is->extra_city_improvs, (int)improv_list); - } - } -} - -void __fastcall -patch_City_draw_hud_icon (City * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y) -{ - Leader * owner = &leaders[this->Body.CivID]; - int restore_capital = owner->CapitalID; - - // Temporarily set this city as the capital if it has an extra palace so it gets the capital star icon - if ((is->current_config.ai_multi_city_start > 1) && - ((*p_human_player_bits & (1 << owner->ID)) == 0) && - has_extra_palace (this)) - owner->CapitalID = this->Body.ID; - - City_draw_hud_icon (this, __, canvas, pixel_x, pixel_y); - owner->CapitalID = restore_capital; -} - -bool __fastcall -patch_City_has_hud_icon (City * this) -{ - return City_has_hud_icon (this) - || ( (is->current_config.ai_multi_city_start > 1) - && ((*p_human_player_bits & (1 << this->Body.CivID)) == 0) - && has_extra_palace (this)); -} - -void __fastcall -patch_City_draw_on_map (City * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) -{ - Leader * owner = &leaders[this->Body.CivID]; - int restore_capital = owner->CapitalID; - - if (is->current_config.do_not_make_capital_cities_appear_larger) - owner->CapitalID = -1; - - // Temporarily set this city as the capital if it has an extra palace so it gets drawn with the next larger size - else if ((is->current_config.ai_multi_city_start > 1) && - ((*p_human_player_bits & (1 << owner->ID)) == 0) && - has_extra_palace (this)) - owner->CapitalID = this->Body.ID; - - City_draw_on_map (this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); - owner->CapitalID = restore_capital; -} - -// Writes a string to replace "Wake" or "Activate" on the right-click menu entry for the given unit. Some units might not have a replacement, in which -// case the function writes nothing and returns false. The string is written to out_str which must point to a buffer of at least str_capacity bytes. -bool -get_menu_verb_for_unit (Unit * unit, char * out_str, int str_capacity) -{ - struct state_desc { - enum c3x_label label; - bool is_doing_worker_job; - } state_descs[35] = { - {CL_IDLE , false}, // [No state] = 0x0 - {CL_FORTIFIED , false}, // Fortifying = 0x1 - {CL_MINING , true }, // Build_Mines = 0x2 - {CL_IRRIGATING , true }, // Irrigate = 0x3 - {CL_BUILDING_FORTRESS , true }, // Build_Fortress = 0x4 - {CL_BUILDING_ROAD , true }, // Build_Road = 0x5 - {CL_BUILDING_RAILROAD , true }, // Build_Railroad = 0x6 - {CL_PLANTING_FOREST , true }, // Plant_Forest = 0x7 - {CL_CLEARING_FOREST , true }, // Clear_Forest = 0x8 - {CL_CLEARING_WETLANDS , true }, // Clear_Wetlands = 0x9 - {CL_CLEARING_DAMAGE , true }, // Clear_Damage = 0xA - {CL_BUILDING_AIRFIELD , true }, // Build_Airfield = 0xB - {CL_BUILDING_RADAR_TOWER, true }, // Build_Radar_Tower = 0xC - {CL_BUILDING_OUTPOST , true }, // Build_Outpost = 0xD - {CL_BUILDING_BARRICADE , true }, // Build_Barricade = 0xE - {CL_INTERCEPTING , false}, // Intercept = 0xF - {CL_MOVING , false}, // Go_To = 0x10 - {CL_BUILDING_ROAD , true }, // Road_To_Tile = 0x11 - {CL_BUILDING_RAILROAD , true }, // Railroad_To_Tile = 0x12 - {CL_BUILDING_COLONY , true }, // Build_Colony = 0x13 - {CL_AUTOMATED , true }, // Auto_Irrigate = 0x14 - {CL_AUTOMATED , true }, // Build_Trade_Routes = 0x15 - {CL_AUTOMATED , true }, // Auto_Clear_Forest = 0x16 - {CL_AUTOMATED , true }, // Auto_Clear_Swamp = 0x17 - {CL_AUTOMATED , true }, // Auto_Clear_Pollution = 0x18 - {CL_AUTOMATED , true }, // Auto_Save_City_Tiles = 0x19 - {CL_EXPLORING , false}, // Explore = 0x1A - {CL_IN_STATE_27 , false}, // ? = 0x1B - {CL_IN_STATE_28 , false}, // Fleeing = 0x1C - {CL_IN_STATE_29 , false}, // ? = 0x1D - {CL_IN_STATE_30 , false}, // ? = 0x1E - {CL_BOMBARDING , false}, // Auto_Bombard = 0x1F - {CL_BOMBARDING , false}, // Auto_Air_Bombard = 0x20 - {CL_BOMBARDING , false}, // Auto_Precision_Strike = 0x21 - {CL_IDLE , false}, // Exhausted = 0x22 - }; - enum UnitStateType state = unit->Body.UnitState; - struct state_desc const * desc; - if ((state >= 0) && (state < ARRAY_LEN (state_descs)) && (desc = &state_descs[state]) && (desc->label >= 0) && (desc->label < COUNT_C3X_LABELS)) { - enum c3x_label label = desc->label; - Unit * container; - if (((label == CL_IDLE) || (label == CL_MOVING) || (label == CL_IN_STATE_29) || desc->is_doing_worker_job) && unit->Body.automated) - label = CL_AUTOMATED; - else if ((label == CL_FORTIFIED) && (NULL != (container = get_unit_ptr (unit->Body.Container_Unit))) && ! Unit_has_ability (container, __, UTA_Army)) - label = CL_TRANSPORTED; - else if ((label == CL_FORTIFIED) && (unit->Body.Status & (USF_SENTRY | USF_SENTRY_ENEMY_ONLY))) - label = CL_SENTRY; - else if ((label == CL_MINING) && is->current_config.enable_districts) { - - // Check if this unit is actually building a district instead of a mine - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - struct district_instance * inst = get_district_instance (tile); - if ((tile != NULL) && (tile != p_null_tile) && inst != NULL) { - char const * district_name = is->district_configs[inst->district_id].name; - snprintf (out_str, str_capacity, "%s %s", is->c3x_labels[CL_BUILDING], district_name); - out_str[str_capacity - 1] = '\0'; - return true; - } - } - - strncpy (out_str, is->c3x_labels[label], str_capacity); - out_str[str_capacity - 1] = '\0'; - return true; - } else - return false; -} - -void __fastcall -patch_MenuUnitItem_write_text_to_temp_str (MenuUnitItem * this) -{ - MenuUnitItem_write_text_to_temp_str (this); - - Unit * unit = this->unit; - char repl_verb[32]; - if (is->current_config.describe_states_of_units_on_menu && - (unit->Body.CivID == p_main_screen_form->Player_CivID) && - (Unit_get_containing_army (unit) == NULL) && - get_menu_verb_for_unit (unit, repl_verb, sizeof repl_verb)) { - char * verb = (unit->Body.UnitState == UnitState_Fortifying) ? (*p_labels)[LBL_WAKE] : (*p_labels)[LBL_ACTIVATE]; - char * verb_str_start = strstr (temp_str, verb); - if (verb_str_start != NULL) { - char s[500]; - char * verb_str_end = verb_str_start + strlen (verb); - snprintf (s, sizeof s, "%.*s%s%s", verb_str_start - temp_str, temp_str, repl_verb, verb_str_end); - s[(sizeof s) - 1] = '\0'; - strncpy (temp_str, s, sizeof s); - } - } -} - -void __fastcall -patch_Tile_m74_Set_Square_Type_for_hill_gen (Tile * this, int edx, enum SquareTypes sq, int tile_x, int tile_y) -{ - if ((sq == SQ_Volcano) && is->current_config.do_not_generate_volcanos) - sq = SQ_Mountains; - this->vtable->m74_Set_Square_Type (this, __, sq, tile_x, tile_y); -} - -void __fastcall -patch_Map_place_scenario_things (Map * this) -{ - is->is_placing_scenario_things = true; - - Map_place_scenario_things (this); - - // If there are any mills in the config then recompute yields & happiness in all cities. This must be done because we avoid doing this as - // mills are added to cities while placing scenario things. - if (is->current_config.count_mills > 0) - for (int n = 0; n <= p_cities->LastIndex; n++) { - City * city = get_city_ptr (n); - if (city != NULL) - patch_City_recompute_yields_and_happiness (city); - } - - if (is->current_config.enable_districts || - is->current_config.enable_natural_wonders || - is->current_config.enable_named_tiles) - load_scenario_districts_from_file (); - - if (is->current_config.enable_natural_wonders && - is->current_config.add_natural_wonders_to_scenarios_if_none) { - bool any_natural_wonders = false; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst != NULL) && - (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) { - any_natural_wonders = true; - break; - } - } - if (! any_natural_wonders) - place_natural_wonders_on_map (); - } - is->is_placing_scenario_things = false; -} - -void -on_open_advisor (AdvisorKind kind) -{ - recompute_resources_if_necessary (); -} - -bool __fastcall patch_Advisor_Base_Form_domestic_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_DOMESTIC); return Advisor_Base_Form_domestic_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_trade_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_TRADE) ; return Advisor_Base_Form_trade_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_military_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_MILITARY); return Advisor_Base_Form_military_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_foreign_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_FOREIGN) ; return Advisor_Base_Form_foreign_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_cultural_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_CULTURAL); return Advisor_Base_Form_cultural_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_science_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_SCIENCE) ; return Advisor_Base_Form_science_m95 (this); } - -void __fastcall -patch_Main_Screen_Form_open_quick_build_chooser (Main_Screen_Form * this, int edx, City * city, int mouse_x, int mouse_y) -{ - recompute_resources_if_necessary (); - Main_Screen_Form_open_quick_build_chooser (this, __, city, mouse_x, mouse_y); -} - -int __fastcall -patch_Context_Menu_get_selected_item_on_unit_rcm (Context_Menu * this) -{ - // In the base game, this method returns -1 for any disabled item which prevents the player from clicking those. We want players to be able to - // click unit items which have been disabled by the mod so they can interrupt the queued actions of units that have no moves left. - int index = this->Selected_Item; - if (index >= 0) { - if (is->current_config.enable_named_tiles && is->named_tile_menu_active) { - Context_Menu_Item * item = &this->Items[index]; - if (item->Menu_Item_ID == NAMED_TILE_MENU_ID) { - handle_named_tile_menu_selection (); - return -1; - } - } - bool is_enabled = (this->Items[index].Status & 2) == 0; - bool is_unit_item = (this->Items[index].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount)) >= 0; - return (is_enabled || is_unit_item) ? index : -1; - } - return -1; -} - -int __fastcall -patch_Tile_check_water_to_block_pollution (Tile * this) -{ - if (this->vtable->m35_Check_Is_Water (this)) - return 1; - else if (is->current_config.do_not_pollute_impassable_tiles) { - enum SquareTypes terrain_type = this->vtable->m50_Get_Square_BaseType (this); - return p_bic_data->TileTypes[terrain_type].Flags.Impassable; - } else - return 0; -} - -void __fastcall -patch_Tile_set_flag_for_eruption_damage (Tile * this, int edx, int param_1, int param_2, int x, int y) -{ - if (is->current_config.enable_districts) { - struct district_instance * inst = get_district_instance (this); - if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { - // District found - handle removal - int district_id = inst->district_id; - - // Notify human player if this tile is in their territory - int territory_owner = this->vtable->m38_Get_Territory_OwnerID (this); - if (territory_owner == p_main_screen_form->Player_CivID) { - char msg[160]; - char const * district_name = is->district_configs[district_id].name; - snprintf (msg, sizeof msg, "%s %s", district_name, is->c3x_labels[CL_DISTRICT_DESTROYED_BY_VOLCANO]); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (x, y, msg, true); - } - - // Remove the district - handle_district_removed (this, district_id, x, y, false); - - // Clear the mine flags - this->vtable->m62_Set_Tile_BuildingID (this, __, -1); - this->vtable->m51_Unset_Tile_Flags (this, __, 0, TILE_FLAG_MINE, x, y); - } - } - - // Apply the normal eruption damage (lava flag) if allowed - if (! (is->current_config.do_not_pollute_impassable_tiles && - p_bic_data->TileTypes[this->vtable->m50_Get_Square_BaseType (this)].Flags.Impassable)) - this->vtable->m56_Set_Tile_Flags (this, __, param_1, param_2, x, y); -} - -bool __fastcall -patch_City_confirm_production_switch (City * this, int edx, int order_type, int order_id) -{ - bool tr = City_confirm_production_switch (this, __, order_type, order_id); - if (tr && - (order_type == COT_Improvement) && (order_id >= 0) && (order_id < p_bic_data->ImprovementsCount) && - (this->Body.CivID == p_main_screen_form->Player_CivID) && - is->current_config.warn_when_chosen_building_would_replace_another) { - Improvement * improv = &p_bic_data->Improvements[order_id]; - if (improv->ImprovementFlags & ITF_Replaces_Other_Buildings) { - Improvement * replaced = NULL; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * other = &p_bic_data->Improvements[n]; - if ((other->ImprovementFlags & ITF_Replaces_Other_Buildings) && - patch_City_has_improvement (this, __, n, false)) { - replaced = other; - break; - } - } - if (replaced != NULL) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, improv->Name.S, -1, -1); - set_popup_str_param (1, replaced->Name.S, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARN_ABOUT_BUILDING_REPLACEMENT", -1, 0, 0, 0); - if (patch_show_popup (popup, __, 0, 0) == 1) - return false; - } - } - } - return tr; -} - -byte const c3x_save_segment_bookend[4] = {0x22, 'C', '3', 'X'}; - -// Writes a string to the buffer and pads the end so it's four-byte aligned (assuming the existing contents is already so aligned). -void -serialize_aligned_text (char const * text, struct buffer * b) -{ - int len = strlen (text); - if (len > 0) { - int padded_len = (len + 4) & ~3; // +1 for null terminator then +3 & ~3 for alignment - byte * p = buffer_allocate (b, padded_len); - strcpy (p, text); - for (int n = 0; n < padded_len - len; n++) - p[len + n] = (byte)0; - } -} - -void * __fastcall -patch_MappedFile_open_to_load_game (MappedFile * this, int edx, char * file_name, int sequential_access) -{ - void * tr = MappedFile_open (this, __, file_name, sequential_access); - if (tr != NULL) - is->accessing_save_file = this; - return tr; -} - -void * __fastcall -patch_MappedFile_create_file_to_save_game (MappedFile * this, int edx, LPCSTR file_path, unsigned file_size, int is_shared) -{ - // Determine if we're currently applying settler perfume to any AI player - bool any_current_settler_perfume = false; - if (is->current_config.ai_settler_perfume_on_founding != 0) { - int duration = is->current_config.ai_settler_perfume_on_founding_duration; - for (int n = 0; n < 32; n++) { - int last_founding_turn = is->turn_no_of_last_founding_for_settler_perfume[n]; - if ((last_founding_turn != -1) && ((*p_current_turn_no - last_founding_turn) < duration)) - any_current_settler_perfume = true; - } - } - - // Assemble mod save data - struct buffer mod_data = {0}; { - if (is->extra_defensive_bombards.len > 0) { - serialize_aligned_text ("extra_defensive_bombards", &mod_data); - itable_serialize (&is->extra_defensive_bombards, &mod_data); - } - if (is->airdrops_this_turn.len > 0) { - serialize_aligned_text ("airdrops_this_turn", &mod_data); - itable_serialize (&is->airdrops_this_turn, &mod_data); - } - if (is->unit_transport_ties.len > 0) { - serialize_aligned_text ("unit_transport_ties", &mod_data); - itable_serialize (&is->unit_transport_ties, &mod_data); - } - if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && is->waiting_units.len > 0) { - serialize_aligned_text ("waiting_units", &mod_data); - itable_serialize (&is->waiting_units, &mod_data); - } - if ((p_bic_data->ImprovementsCount > 256) && (p_cities->Cities != NULL) && (is->extra_city_improvs.len > 0)) { - serialize_aligned_text ("extra_city_improvs", &mod_data); - int extra_improv_count = p_bic_data->ImprovementsCount - 256; - *(int *)buffer_allocate (&mod_data, sizeof(int)) = extra_improv_count; - - int count_entries = 0; { - for (int n = 0; n <= p_cities->LastIndex; n++) { - City_Body * body = p_cities->Cities[n].City; - if ((body != NULL) && ((int)body != offsetof (City, Body))) { - int unused; - if (itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_1, &unused) || - itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_2, &unused)) - count_entries++; - } - } - } - *(int *)buffer_allocate (&mod_data, sizeof(int)) = count_entries; - - int ints_per_list = (extra_improv_count + 31) / 32; - int bytes_per_list = (extra_improv_count + 7) / 8; - for (int n = 0; n <= p_cities->LastIndex; n++) { - City_Body * body = p_cities->Cities[n].City; - if ((body != NULL) && ((int)body != offsetof (City, Body))) { - byte * extra_bit_lists[2]; - extra_bit_lists[0] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_1, 0); - extra_bit_lists[1] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_2, 0); - if ((extra_bit_lists[0] != NULL) || (extra_bit_lists[1] != NULL)) { - *(int *)buffer_allocate (&mod_data, sizeof(int)) = body->ID; - for (int k = 0; k < 2; k++) { - int list_size = sizeof(int) * ints_per_list; - int * list = (int *)buffer_allocate (&mod_data, list_size); - memset (list, 0, list_size); - if (extra_bit_lists[k] != NULL) - memcpy (list, extra_bit_lists[k], bytes_per_list); - } - } - } - } - } - if (any_current_settler_perfume) { - serialize_aligned_text ("turn_no_of_last_founding_for_settler_perfume", &mod_data); - void * area = buffer_allocate (&mod_data, sizeof is->turn_no_of_last_founding_for_settler_perfume); - memcpy (area, is->turn_no_of_last_founding_for_settler_perfume, sizeof is->turn_no_of_last_founding_for_settler_perfume); - } - if (is->current_config.day_night_cycle_mode != DNCM_OFF) { - serialize_aligned_text ("current_day_night_cycle", &mod_data); - int_to_bytes (buffer_allocate (&mod_data, sizeof is->current_day_night_cycle), is->current_day_night_cycle); - } - if (is->current_config.enable_districts && (is->district_count > 0)) { - serialize_aligned_text ("district_config_names", &mod_data); - int * entry_count = (int *)buffer_allocate (&mod_data, sizeof(int)); - *entry_count = is->district_count; - for (int district_id = 0; district_id < is->district_count; district_id++) { - *(int *)buffer_allocate (&mod_data, sizeof(int)) = district_id; - char const * name = is->district_configs[district_id].name; - if (name == NULL) - name = ""; - serialize_aligned_text (name, &mod_data); - } - } - - if (is->current_config.enable_districts) { - int entry_count = 0; - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req != NULL) && (req->city_id >= 0)) - entry_count++; - } - } - if (entry_count > 0) { - serialize_aligned_text ("district_pending_requests", &mod_data); - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 5 * entry_count)); - int * out = chunk + 1; - chunk[0] = entry_count; - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req == NULL) || (req->city_id < 0)) - continue; - out[0] = req->city_id; - out[1] = req->district_id; - out[2] = req->assigned_worker_id; - out[3] = req->target_x; - out[4] = req->target_y; - out += 5; - } - } - } - } - - if (is->current_config.enable_districts && - (is->city_pending_building_orders.len > 0)) { - int entry_count = 0; - FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { - City * city = (City *)tei.key; - int improv_id = tei.value; - if ((city != NULL) && (improv_id >= 0)) - entry_count++; - } - if (entry_count > 0) { - serialize_aligned_text ("building_pending_orders", &mod_data); - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 2 * entry_count)); - int * out = chunk + 1; - chunk[0] = entry_count; - FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { - City * city = (City *)tei.key; - int improv_id = tei.value; - if ((city == NULL) || (improv_id < 0)) - continue; - out[0] = city->Body.ID; - out[1] = improv_id; - out += 2; - } - } - } - - if (is->current_config.enable_districts && (is->district_tile_map.len > 0)) { - serialize_aligned_text ("district_tile_map", &mod_data); - int entry_capacity = is->district_tile_map.len; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 9 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * tile = (Tile *)tei.key; - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst == NULL) - continue; - int x, y; - if (! district_instance_get_coords (inst, tile, &x, &y)) - continue; - int wonder_city_id = inst->wonder_info.city_id; - if (wonder_city_id >= 0) { - City * info_city = get_city_ptr (wonder_city_id); - inst->wonder_info.city = info_city; - if (info_city == NULL) - wonder_city_id = -1; - } else - inst->wonder_info.city = NULL; - out[0] = x; - out[1] = y; - out[2] = inst->district_id; - out[3] = (int)inst->state; - out[4] = inst->built_by_civ_id; - out[5] = inst->completed_turn; - out[6] = (int)inst->wonder_info.state; - out[7] = wonder_city_id; - out[8] = inst->wonder_info.wonder_index; - out += 9; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 9 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - - if (is->current_config.enable_natural_wonders && (is->district_tile_map.len > 0)) { - int entry_capacity = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - if (inst->natural_wonder_info.natural_wonder_id < 0) - continue; - entry_capacity++; - } - if (entry_capacity > 0) { - serialize_aligned_text ("natural_wonder_districts", &mod_data); - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * tile = (Tile *)tei.key; - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || - (inst->district_id != NATURAL_WONDER_DISTRICT_ID) || - (inst->natural_wonder_info.natural_wonder_id < 0)) - continue; - int x, y; - if (! district_instance_get_coords (inst, tile, &x, &y)) - continue; - out[0] = x; - out[1] = y; - out[2] = inst->natural_wonder_info.natural_wonder_id; - out += 3; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - } - - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts && - (is->distribution_hub_records.len > 0)) { - serialize_aligned_text ("distribution_hub_records", &mod_data); - int entry_capacity = is->distribution_hub_records.len; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (rec == NULL) - continue; - out[0] = rec->tile_x; - out[1] = rec->tile_y; - out[2] = rec->civ_id; - out += 3; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - - if (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (is->aerodrome_airlift_usage.len > 0)) { - serialize_aligned_text ("aerodrome_airlift_usage", &mod_data); - int entry_capacity = is->aerodrome_airlift_usage.len; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { - Tile * tile = (Tile *)tei.key; - int mask = tei.value; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - continue; - - out[0] = tile_x; - out[1] = tile_y; - out[2] = mask; - out += 3; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - - if (is->current_config.enable_named_tiles && (is->named_tile_map.len > 0)) { - serialize_aligned_text ("named_tiles", &mod_data); - int entry_capacity = is->named_tile_map.len; - int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); - byte * chunk = (byte *)buffer_allocate (&mod_data, (int)sizeof(int) + bytes_per_entry * entry_capacity); - int * count = (int *)chunk; - byte * out = (byte *)(count + 1); - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if ((entry == NULL) || (entry->name[0] == '\0')) - continue; - Tile * tile = (Tile *)tei.key; - int tile_x = entry->tile_x; - int tile_y = entry->tile_y; - if ((tile != NULL) && (tile != p_null_tile)) - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - ((int *)out)[0] = tile_x; - ((int *)out)[1] = tile_y; - out += sizeof(int) * 2; - memcpy (out, entry->name, sizeof entry->name); - out += sizeof entry->name; - written++; - } - *count = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * bytes_per_entry; - mod_data.length -= trimmed_bytes; - } - } - - if (is->great_wall_auto_build != GWABS_NOT_STARTED) { - serialize_aligned_text ("great_wall_auto_build_state", &mod_data); - *(int *)buffer_allocate (&mod_data, sizeof(int)) = (int)is->great_wall_auto_build; - } - - if (is->ai_candidate_bridge_or_canals_initialized || (is->ai_candidate_bridge_or_canals_count > 0)) { - serialize_aligned_text ("ai_candidate_bridge_or_canals", &mod_data); - int * header = (int *)buffer_allocate (&mod_data, sizeof(int) * 3); - header[0] = is->ai_candidate_bridge_or_canals_initialized ? 1 : 0; - header[1] = is->ai_candidate_bridge_or_canals_count; - header[2] = is->ai_candidate_bridge_or_canals_capacity; - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - int tile_count = (int)entry->tile_count; - if ((tile_count <= 0) || (entry->tile_x == NULL) || (entry->tile_y == NULL)) - tile_count = 0; - - int field_count = 14; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (field_count + tile_count * 2)); - int pending_city_id = entry->pending_req.city_id; - if ((pending_city_id < 0) && (entry->pending_req.city != NULL)) - pending_city_id = entry->pending_req.city->Body.ID; - - chunk[0] = entry->district_id; - chunk[1] = (int)entry->owner_civ_id; - chunk[2] = tile_count; - chunk[3] = (entry->tile_capacity > 0) ? entry->tile_capacity : tile_count; - chunk[4] = entry->assigned_tile_index; - chunk[5] = entry->assigned_worker_id; - chunk[6] = entry->completed ? 1 : 0; - chunk[7] = pending_city_id; - chunk[8] = entry->pending_req.civ_id; - chunk[9] = entry->pending_req.district_id; - chunk[10] = entry->pending_req.assigned_worker_id; - chunk[11] = entry->pending_req.target_x; - chunk[12] = entry->pending_req.target_y; - chunk[13] = entry->pending_req.worker_assigned_turn; - - int * out = chunk + field_count; - for (int ti = 0; ti < tile_count; ti++) { - out[0] = entry->tile_x[ti]; - out[1] = entry->tile_y[ti]; - out += 2; - } - } - } - } - - int metadata_size = (mod_data.length > 0) ? 12 : 0; // Two four-byte bookends plus one four-byte size, only written if there's any mod data - - void * tr = MappedFile_create_file (this, __, file_path, file_size + mod_data.length + metadata_size, is_shared); - if (tr != NULL) { - is->accessing_save_file = this; - if ((mod_data.length > 0) && (mod_data.length + metadata_size <= this->size)) { - // Write first bookend to mod's segment in the save data - byte * seg_start = (byte *)tr + file_size; - for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) - seg_start[n] = c3x_save_segment_bookend[n]; - - // Write actual mod game data - memcpy ((byte *)tr + file_size + 4, mod_data.contents, mod_data.length); - - // Write size of mod data - byte * seg_end = (byte *)tr + file_size + 4 + mod_data.length; - int_to_bytes (seg_end, mod_data.length); - - // Finish off with another bookend - for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) - seg_end[4+n] = c3x_save_segment_bookend[n]; - } - } - buffer_deinit (&mod_data); - return tr; -} - -bool -match_save_chunk_name (byte ** cursor, char const * name) -{ - if (strcmp (name, *cursor) == 0) { - // Move cursor past the string if it matched. Also move past any padding that was added to ensure alignment (see serialize_aligned_text). - *cursor = (byte *)((int)*cursor + strlen (name) + 4 & ~3); - return true; - } else - return false; -} - -bool -match_save_segment_bookend (byte * b) -{ - return memcmp (c3x_save_segment_bookend, b, ARRAY_LEN (c3x_save_segment_bookend)) == 0; -} - -int __cdecl -patch_move_game_data (byte * buffer, bool save_else_load) -{ - int tr = move_game_data (buffer, save_else_load); - - if (! save_else_load) { - // Free all district_instance structs first - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst != NULL) - free (inst); - } - table_deinit (&is->district_tile_map); - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if (entry != NULL) - free (entry); - } - table_deinit (&is->named_tile_map); - clear_all_tracked_workers (); - reset_ai_candidate_bridge_or_canals (); - } - - // Check for a mod save data section and load it if present - MappedFile * save; - int seg_size; - byte * seg; - if ((! save_else_load) && - ((save = is->accessing_save_file) != NULL) && - (save->size >= 8) && - match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - 4)) && - ((seg_size = int_from_bytes ((byte *)((int)save->base_addr + save->size - 8))) > 0) && - (save->size >= seg_size + 12) && - match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - seg_size - 12)) && - ((seg = malloc (seg_size)) != NULL)) { - memcpy (seg, (void *)((int)save->base_addr + save->size - seg_size - 8), seg_size); - - byte * cursor = seg; - char * error_chunk_name = NULL; - while (cursor < seg + seg_size) { - if (match_save_chunk_name (&cursor, "special save message")) { - char * msg = (char *)cursor; - cursor = (byte *)((int)cursor + strlen (msg) + 4 & ~3); - - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - PopupForm_add_text (popup, __, "This save contains a special message:", 0); - PopupForm_add_text (popup, __, msg, 0); - patch_show_popup (popup, __, 0, 0); - - } else if (match_save_chunk_name (&cursor, "extra_defensive_bombards")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->extra_defensive_bombards); - if (bytes_read > 0) - cursor += bytes_read; - else { - error_chunk_name = "extra_defensive_bombards"; - break; - } - - } else if (match_save_chunk_name (&cursor, "airdrops_this_turn")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->airdrops_this_turn); - if (bytes_read > 0) - cursor += bytes_read; - else { - error_chunk_name = "airdrops_this_turn"; - break; - } - - } else if (match_save_chunk_name (&cursor, "unit_transport_ties")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->unit_transport_ties); - if (bytes_read > 0) - cursor += bytes_read; - else { - error_chunk_name = "unit_transport_ties"; - break; - } - - } else if (match_save_chunk_name (&cursor, "waiting_units")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->waiting_units); - if (bytes_read > 0) { - cursor += bytes_read; - is->have_loaded_waiting_units = true; - } else { - error_chunk_name = "waiting_units"; - break; - } - - } else if (match_save_chunk_name (&cursor, "extra_city_improvs")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - - // Read two int vars from this save chunk - int file_extra_improv_count, count_entries; - if (remaining_bytes >= 8) { - file_extra_improv_count = *((int *)cursor)++; - count_entries = *((int *)cursor)++; - remaining_bytes -= 8; - } else - goto done_with_extra_city_improvs; - - // Check that the extra improv counts are valid. They must be greater than zero and what was stored in the save must - // match what we got from the current scenario data. - int extra_improv_count = not_below (0, p_bic_data->ImprovementsCount - 256); - if ((file_extra_improv_count <= 0) || (extra_improv_count != file_extra_improv_count)) - goto done_with_extra_city_improvs; - - // The extra bits data in the save is stored in 32-bit chunks, "ints", to maintain alignment. Compute how many ints we - // need for each list of bits and check that reading all entries won't overrun the buffer. - int ints_per_list = (extra_improv_count + 31) / 32, - ints_per_entry = 1 + 2 * ints_per_list; - if (count_entries * ints_per_entry * sizeof(int) > remaining_bytes) - goto done_with_extra_city_improvs; - - // Main loop reading the extra bits data - for (int n = 0; n < count_entries; n++) { - City * city = get_city_ptr (*((int *)cursor)++); - if (city == NULL) - goto done_with_extra_city_improvs; - - byte * extra_bits_1 = calloc (sizeof (int), ints_per_list); - for (int k = 0; k < ints_per_list; k++) - ((int *)extra_bits_1)[k] = *((int *)cursor)++; - itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_1, (int)extra_bits_1); - - byte * extra_bits_2 = calloc (sizeof (int), ints_per_list); - for (int k = 0; k < ints_per_list; k++) - ((int *)extra_bits_2)[k] = *((int *)cursor)++; - itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_2, (int)extra_bits_2); - } - - // Rebuild the trade network since it may have changed as a result of the additional buildings. This method also - // refreshes the free improvement tables and recomputes city happiness. - patch_Map_build_trade_network (&p_bic_data->Map); - - success = true; - - done_with_extra_city_improvs: - if (! success) { - error_chunk_name = "extra_city_improvs";; - break; - } - - } else if (match_save_chunk_name (&cursor, "turn_no_of_last_founding_for_settler_perfume")) { - for (int n = 0; n < 32; n++) - is->turn_no_of_last_founding_for_settler_perfume[n] = *((int *)cursor)++; - - } else if (match_save_chunk_name (&cursor, "current_day_night_cycle")) { - is->current_day_night_cycle = *((int *)cursor)++; - is->day_night_cycle_unstarted = false; - - // The day/night cycle sprite proxies will have been cleared in patch_load_scenario. They will not necessarily be set - // up again in the usual way because Map_Renderer::load_images is not necessarily called when loading a save. The game - // skips reloading all graphics when loading a save while in-game with another that uses the same graphics (possibly - // only the standard graphics; I didn't test). If day/night cycle mode is active, restore the proxies now if they - // haven't already been. - if ((is->day_night_cycle_img_state == IS_OK) && ! is->day_night_cycle_img_proxies_indexed) - build_sprite_proxies_24 (&p_bic_data->Map.Renderer); - - // Because we've restored current_day_night_cycle from the save, set that is is not the first turn so the cycle - // doesn't get restarted. - is->day_night_cycle_unstarted = false; - - } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_state")) { - int state = *((int *)cursor)++; - if ((state >= GWABS_NOT_STARTED) && (state <= GWABS_DONE)) - is->great_wall_auto_build = (enum great_wall_auto_build_state)state; - else - is->great_wall_auto_build = GWABS_NOT_STARTED; - - } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_is_done")) { - bool was_done = (*((int *)cursor)++ != 0); - is->great_wall_auto_build = was_done ? GWABS_DONE : GWABS_NOT_STARTED; - - } else if (match_save_chunk_name (&cursor, "district_pending_requests")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && - (remaining_bytes >= entry_count * 5 * (int)sizeof(int))) { - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req != NULL) - free (req); - } - table_deinit (&is->city_pending_district_requests[civ_id]); - } - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 5 * (int)sizeof(int)) { - success = false; - break; - } - int city_id = *ints++; - int district_id = *ints++; - int assigned_worker_id = *ints++; - int target_x = *ints++; - int target_y = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 5 * (int)sizeof(int); - City * city = get_city_ptr (city_id); - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - continue; - struct pending_district_request * req = create_pending_district_request (city, district_id); - if (req == NULL) - continue; - if ((assigned_worker_id >= 0) && (get_unit_ptr (assigned_worker_id) == NULL)) - assigned_worker_id = -1; - req->assigned_worker_id = assigned_worker_id; - req->target_x = target_x; - req->target_y = target_y; - } - if (! success) { - for (int civ_id = 0; civ_id < 32; civ_id++) - table_deinit (&is->city_pending_district_requests[civ_id]); - } - } - } - if (! success) { - error_chunk_name = "district_pending_requests"; - break; - } - } else if (match_save_chunk_name (&cursor, "building_pending_orders")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && - (remaining_bytes >= entry_count * 2 * (int)sizeof(int))) { - table_deinit (&is->city_pending_building_orders); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 2 * (int)sizeof(int)) { - success = false; - break; - } - int city_id = *ints++; - int improv_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 2 * (int)sizeof(int); - if (improv_id < 0) - continue; - City * city = get_city_ptr (city_id); - if (city == NULL) - continue; - itable_insert (&is->city_pending_building_orders, (int)city, improv_id); - } - if (! success) - table_deinit (&is->city_pending_building_orders); - } - } - if (! success) { - error_chunk_name = "building_pending_orders"; - break; - } - } else if (match_save_chunk_name (&cursor, "district_tile_map")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if (entry_count >= 0) { - int ints_per_entry = 9; - success = true; - int required_bytes = entry_count * ints_per_entry * (int)sizeof(int); - if (success && remaining_bytes >= required_bytes) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst != NULL) - free (inst); - } - table_deinit (&is->district_tile_map); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < ints_per_entry * (int)sizeof(int)) { - success = false; - break; - } - int x = *ints++; - int y = *ints++; - int district_id = *ints++; - int state_val = *ints++; - int built_by_civ_id = *ints++; - int completed_turn = *ints++; - int wonder_state = *ints++; - int wonder_city_id = *ints++; - int wonder_index = *ints++; - cursor = (byte *)ints; - remaining_bytes -= ints_per_entry * (int)sizeof(int); - if ((district_id < 0) || (district_id >= is->district_count)) - continue; - Tile * tile = tile_at (x, y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = ensure_district_instance (tile, district_id, x, y); - if (inst != NULL) { - enum district_state new_state; - switch (state_val) { - case DS_COMPLETED: - new_state = DS_COMPLETED; - break; - case DS_UNDER_CONSTRUCTION: - new_state = DS_UNDER_CONSTRUCTION; - break; - default: - new_state = DS_UNDER_CONSTRUCTION; - break; - } - inst->state = new_state; - inst->built_by_civ_id = built_by_civ_id; - inst->completed_turn = completed_turn; - - inst->wonder_info.state = (enum wonder_district_state)wonder_state; - inst->wonder_info.city_id = (wonder_city_id >= 0) ? wonder_city_id : -1; - City * info_city = (wonder_city_id >= 0) ? get_city_ptr (wonder_city_id) : NULL; - inst->wonder_info.city = info_city; - if (info_city == NULL) - inst->wonder_info.city_id = -1; - inst->wonder_info.wonder_index = wonder_index; - set_tile_unworkable_for_all_cities (tile, x, y); - } - } - } - } - else - success = false; - } - } - if (! success) { - error_chunk_name = "district_tile_map"; - break; - } - } else if (match_save_chunk_name (&cursor, "natural_wonder_districts")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 3 * (int)sizeof(int)) { - success = false; - break; - } - int x = *ints++; - int y = *ints++; - int natural_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 3 * (int)sizeof(int); - if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) - continue; - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, x, y); - if (inst == NULL) - continue; - inst->district_id = NATURAL_WONDER_DISTRICT_ID; - inst->state = DS_COMPLETED; - inst->natural_wonder_info.natural_wonder_id = natural_id; - set_tile_unworkable_for_all_cities (tile, x, y); - } - } - } - if (! success) { - error_chunk_name = "natural_wonder_districts"; - break; - } - } else if (match_save_chunk_name (&cursor, "distribution_hub_records")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { - clear_distribution_hub_tables (); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 3 * (int)sizeof(int)) { - success = false; - break; - } - int x = *ints++; - int y = *ints++; - int civ_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 3 * (int)sizeof(int); - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - on_distribution_hub_completed (tile, x, y); - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec != NULL) - rec->civ_id = civ_id; - } - } - } - if (! success) { - error_chunk_name = "distribution_hub_records"; - break; - } - } else if (match_save_chunk_name (&cursor, "aerodrome_airlift_usage")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && - (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { - table_deinit (&is->aerodrome_airlift_usage); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 3 * (int)sizeof(int)) { - success = false; - break; - } - int tile_x = *ints++; - int tile_y = *ints++; - int mask = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 3 * (int)sizeof(int); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - itable_insert (&is->aerodrome_airlift_usage, (int)tile, mask); - } - if (! success) - table_deinit (&is->aerodrome_airlift_usage); - } - } - if (! success) { - error_chunk_name = "aerodrome_airlift_usage"; - break; - } - - } else if (match_save_chunk_name (&cursor, "named_tiles")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); - if ((entry_count >= 0) && (remaining_bytes >= entry_count * bytes_per_entry)) { - table_deinit (&is->named_tile_map); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < bytes_per_entry) { - success = false; - break; - } - int tile_x = *ints++; - int tile_y = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int) * 2; - - char name_buf[101]; - memcpy (name_buf, cursor, sizeof name_buf); - name_buf[(sizeof name_buf) - 1] = '\0'; - cursor += sizeof name_buf; - remaining_bytes -= sizeof name_buf; - ints = (int *)cursor; - - if (name_buf[0] == '\0') - continue; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - struct named_tile_entry * entry = calloc (1, sizeof *entry); - if (entry == NULL) { - success = false; - break; - } - entry->tile_x = tile_x; - entry->tile_y = tile_y; - strncpy (entry->name, name_buf, sizeof entry->name); - entry->name[(sizeof entry->name) - 1] = '\0'; - itable_insert (&is->named_tile_map, (int)tile, (int)entry); - } - if (! success) { - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if (entry != NULL) - free (entry); - } - table_deinit (&is->named_tile_map); - } - } - } - if (! success) { - error_chunk_name = "named_tiles"; - break; - } - - } else if (match_save_chunk_name (&cursor, "ai_candidate_bridge_or_canals")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int) * 3) { - int * ints = (int *)cursor; - int saved_initialized = *ints++; - int saved_count = *ints++; - int saved_capacity = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int) * 3; - - if ((saved_count >= 0) && (saved_capacity >= 0)) { - reset_ai_candidate_bridge_or_canals (); - success = true; - - int alloc_capacity = saved_capacity; - if (alloc_capacity < saved_count) - alloc_capacity = saved_count; - if (alloc_capacity > 0) { - is->ai_candidate_bridge_or_canals = (struct ai_candidate_bridge_or_canal_entry *)calloc (alloc_capacity, sizeof *is->ai_candidate_bridge_or_canals); - if (is->ai_candidate_bridge_or_canals == NULL) { - success = false; - alloc_capacity = 0; - } else - is->ai_candidate_bridge_or_canals_capacity = alloc_capacity; - } - - is->ai_candidate_bridge_or_canals_initialized = (saved_initialized != 0); - int loaded_count = 0; - for (int ei = 0; ei < saved_count; ei++) { - if (remaining_bytes < (int)sizeof(int) * 14) { - success = false; - break; - } - int district_id = *ints++; - int owner_civ_id = *ints++; - int tile_count = *ints++; - int tile_capacity = *ints++; - int assigned_tile_index = *ints++; - int assigned_worker_id = *ints++; - int completed = *ints++; - int pending_city_id = *ints++; - int pending_civ_id = *ints++; - int pending_district_id = *ints++; - int pending_assigned_worker_id = *ints++; - int pending_target_x = *ints++; - int pending_target_y = *ints++; - int pending_worker_assigned_turn = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int) * 14; - - if (tile_count < 0) { - success = false; - break; - } - if (remaining_bytes < tile_count * 2 * (int)sizeof(int)) { - success = false; - break; - } - - int stored_tile_count = tile_count; - if (tile_count > AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES) - tile_count = AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES; - if (tile_capacity < tile_count) - tile_capacity = tile_count; - - struct ai_candidate_bridge_or_canal_entry * entry = NULL; - if ((alloc_capacity > 0) && (loaded_count < alloc_capacity)) - entry = &is->ai_candidate_bridge_or_canals[loaded_count]; - - if (entry != NULL) { - entry->district_id = district_id; - entry->owner_civ_id = (short)owner_civ_id; - entry->tile_count = (short)tile_count; - entry->tile_capacity = tile_capacity; - entry->assigned_tile_index = assigned_tile_index; - entry->assigned_worker_id = assigned_worker_id; - entry->completed = (completed != 0); - - entry->tile_x = (short *)calloc (sizeof *entry->tile_x, tile_count); - entry->tile_y = (short *)calloc (sizeof *entry->tile_y, tile_count); - if ((tile_count > 0) && ((entry->tile_x == NULL) || (entry->tile_y == NULL))) { - if (entry->tile_x != NULL) - free (entry->tile_x); - if (entry->tile_y != NULL) - free (entry->tile_y); - entry->tile_x = NULL; - entry->tile_y = NULL; - entry->tile_count = 0; - entry->tile_capacity = 0; - } - - for (int ti = 0; ti < stored_tile_count; ti++) { - int tx = *ints++; - int ty = *ints++; - if ((entry->tile_x != NULL) && (ti < tile_count)) { - entry->tile_x[ti] = (short)tx; - entry->tile_y[ti] = (short)ty; - } - } - - entry->pending_req.city = (pending_city_id >= 0) ? get_city_ptr (pending_city_id) : NULL; - entry->pending_req.city_id = (entry->pending_req.city != NULL) ? pending_city_id : -1; - entry->pending_req.civ_id = pending_civ_id; - entry->pending_req.district_id = pending_district_id; - entry->pending_req.assigned_worker_id = pending_assigned_worker_id; - entry->pending_req.target_x = pending_target_x; - entry->pending_req.target_y = pending_target_y; - entry->pending_req.worker_assigned_turn = pending_worker_assigned_turn; - - if ((entry->assigned_worker_id >= 0) && (get_unit_ptr (entry->assigned_worker_id) == NULL)) - entry->assigned_worker_id = -1; - if ((entry->pending_req.assigned_worker_id >= 0) && (get_unit_ptr (entry->pending_req.assigned_worker_id) == NULL)) - entry->pending_req.assigned_worker_id = -1; - if ((entry->assigned_tile_index < 0) || (entry->assigned_tile_index >= entry->tile_count)) - entry->assigned_tile_index = -1; - - loaded_count++; - } else { - for (int ti = 0; ti < stored_tile_count; ti++) { - ints += 2; - } - } - - cursor = (byte *)ints; - remaining_bytes -= stored_tile_count * 2 * (int)sizeof(int); - } - if (success) - is->ai_candidate_bridge_or_canals_count = loaded_count; - } - } - if (! success) { - error_chunk_name = "ai_candidate_bridge_or_canals"; - break; - } - - } else if (match_save_chunk_name (&cursor, "district_config_names")) { - bool success = false; - bool mismatch_found = false; - bool count_mismatch = false; - char first_mismatch[200]; - first_mismatch[0] = '\0'; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int saved_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if (saved_count >= 0) { - success = true; - count_mismatch = (saved_count != is->district_count); - char * saved_names[saved_count]; - for (int n = 0; n < saved_count; n++) { - if (remaining_bytes < (int)sizeof(int)) { - success = false; - break; - } - ints = (int *)cursor; - int saved_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - - int name_len = -1; - for (int k = 0; k < remaining_bytes; k++) { - if (cursor[k] == '\0') { - name_len = k; - break; - } - } - if (name_len < 0) { - success = false; - break; - } - int padded_len = (name_len + 4) & ~3; - if (padded_len > remaining_bytes) { - success = false; - break; - } - - char * saved_name = (char *)cursor; - saved_names[n] = saved_name; - if (! mismatch_found) { - if ((saved_id < 0) || (saved_id >= is->district_count)) { - snprintf (first_mismatch, sizeof first_mismatch, "%s %d (\"%s\") %s", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW]); - first_mismatch[(sizeof first_mismatch) - 1] = '\0'; - mismatch_found = true; - } else { - char const * current_name = is->district_configs[saved_id].name; - if (current_name == NULL) - current_name = ""; - if (strcmp (current_name, saved_name) != 0) { - snprintf (first_mismatch, sizeof first_mismatch, "%s %d \"%s\" %s \"%s\"", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_NAME_MISMATCH], current_name); - first_mismatch[(sizeof first_mismatch) - 1] = '\0'; - mismatch_found = true; - } - } - } - - cursor += padded_len; - remaining_bytes -= padded_len; - } - if (success && count_mismatch && (first_mismatch[0] == '\0')) { - snprintf (first_mismatch, sizeof first_mismatch, "%s %d %s %d", is->c3x_labels[CL_SAVE_FILE_HAD], saved_count, is->c3x_labels[CL_CURRENT_CONFIG_HAS_ONLY], is->district_count); - first_mismatch[(sizeof first_mismatch) - 1] = '\0'; - mismatch_found = true; - } - if (success && mismatch_found) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); - - char s[1000]; - snprintf (s, sizeof s, "%s %s", is->c3x_labels[CL_WARNING_DISTRICTS_CONFIG_MISMATCH], first_mismatch); - snprintf (s, sizeof s, "%s. %s", s, is->c3x_labels[CL_MAY_BE_OTHER_ERRORS_AS_WELL]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^"); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_DISTRICTS_IN_SAVE_FILE]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - for (int n = 0; n < saved_count; n++) { - snprintf (s, sizeof s, "^ (%d) %s", n, saved_names[n]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - - snprintf (s, sizeof s, "^"); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^%s \"%s\":", is->c3x_labels[CL_CURRENTLY_CONFIGURED_DISTRICTS], is->current_districts_config_path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - for (int n = 0; n < is->district_count; n++) { - snprintf (s, sizeof s, "^ (%d) %s", n, is->district_configs[n].name); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - - patch_show_popup (popup, __, 0, 0); - } - } - } - if (! success) { - error_chunk_name = "district_config_names"; - break; - } - - } else { - error_chunk_name = "N/A"; - break; - } - } - - if (error_chunk_name != NULL) { - char s[200]; - snprintf (s, sizeof s, "Failed to read mod save data. Error occured in chunk: %s", error_chunk_name); - s[(sizeof s) - 1] = '\0'; - pop_up_in_game_error (s); - } - - free (seg); - } - - return tr; -} - -void __fastcall -patch_MappedFile_deinit_after_saving_or_loading (MappedFile * this) -{ - is->accessing_save_file = NULL; - MappedFile_deinit (this); -} - -bool __fastcall -patch_Tile_m7_Check_Barbarian_Camp (Tile * this, int edx, int visible_to_civ) -{ - int * p_stack = (int *)&visible_to_civ; - int ret_addr = p_stack[-1]; - - // If the barb unit AI is calling this method to check if there's a camp to defend, return true if we're allowing barb city capture and the - // tile has a city. This causes barb units to defend cities they've captured, otherwise they'll ignore them. - if ((ret_addr == ADDR_CHECK_BARB_CAMP_TO_DEFEND_RETURN) && - is->current_config.enable_city_capture_by_barbarians && - Tile_has_city (this)) - return true; - else - return Tile_m7_Check_Barbarian_Camp (this, __, visible_to_civ); -} - -bool __fastcall -patch_Unit_can_heal_at (Unit * this, int edx, int tile_x, int tile_y) -{ - if (is->current_config.enable_districts && - is->current_config.enable_port_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile_has_friendly_port_district (tile, this->Body.CivID)) { - int occupier_id = get_tile_occupier_id (tile_x, tile_y, -1, true); - return (occupier_id == -1) || (occupier_id == this->Body.CivID); - } - } - - return Unit_can_heal_at (this, __, tile_x, tile_y); -} - -bool __fastcall -patch_Unit_can_airdrop (Unit * this) -{ - UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - - bool allowed = Unit_can_airdrop (this); - - bool require_aerodrome = (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities); - - if (require_aerodrome) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - bool has_aerodrome = false; - - if ((tile != NULL) && (tile != p_null_tile)) - has_aerodrome = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); - - if (! has_aerodrome) - allowed = false; - else if (! allowed) { - if ((this_type->Unit_Class != UTC_Air) && - (this_type->Air_Missions & UCV_Airdrop) && - (this->Body.Moves == 0)) - allowed = true; - } - } - - // Possibly rule in this airdrop as allowed if it's by a paratrooper in a helicopter on a carrier and we're configured to allow airdrops under - // those circumstances. - if ((! allowed) && (is->current_config.special_helicopter_rules & SHR_PASSENGER_AIRDROP)) { - Unit * container = get_unit_ptr (this->Body.Container_Unit); - if (container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) { // if in helicopter - Unit * metacontainer = get_unit_ptr (container->Body.Container_Unit); - if (metacontainer != NULL && p_bic_data->UnitTypes[metacontainer->Body.UnitTypeID].Unit_Class == UTC_Sea && - Unit_has_ability (metacontainer, __, UTA_Transports_Only_Aircraft)) { // if that helicopter is on a carrier - // Allow the airdrop under the same restrictions as from an airfield - allowed = this_type->Unit_Class != UTC_Air && this->Body.Moves == 0; - } - } - } - - if (! allowed) - return false; - - return itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0) == 0; -} - -bool __fastcall -patch_City_Improvements_contains (City_Improvements * this, int edx, int id) -{ - byte * extra_bits; - if ((id < 256) || ! is->current_config.remove_city_improvement_limit) - return City_Improvements_contains (this, __, id); - else if (itable_look_up (&is->extra_city_improvs, (int)this, (int *)&extra_bits)) { - int extra_id = id - 256; - return (extra_bits[extra_id>>3] >> (extra_id & 7)) & 1; - } else - return false; -} - -void __fastcall -patch_City_Improvements_set (City_Improvements * this, int edx, int id, bool add_else_remove) -{ - if ((id < 256) || ! is->current_config.remove_city_improvement_limit) - return City_Improvements_set (this, __, id, add_else_remove); - else { - byte * extra_bits = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)this, 0); - int extra_id = id - 256; - byte mask = 1 << (extra_id & 7); - if (add_else_remove) { - if (! extra_bits) { - int extra_bits_size = (not_below (0, p_bic_data->ImprovementsCount - 256) >> 3) + 1; - extra_bits = calloc (1, extra_bits_size); - itable_insert (&is->extra_city_improvs, (int)this, (int)extra_bits); - } - extra_bits[extra_id>>3] |= mask; - } else if ((! add_else_remove) && (extra_bits != NULL)) - extra_bits[extra_id>>3] &= ~mask; - } -} - -bool __fastcall -patch_Leader_has_tech_to_stop_disease (Leader * this, int edx, int id) -{ - if (! is->current_config.patch_disease_stopping_tech_flag_bug) - return Leader_has_tech (this, __, id); - else - return Leader_has_tech_with_flag (this, __, ATF_Disabled_Deseases_From_Flood_Plains); -} - -void __fastcall -patch_set_worker_animation (void * this, int edx, Unit * unit, int job_id) -{ - AnimationType anim_type; - - // If districts disabled or unit is null or job is not building mines, use base logic - if ((! is->current_config.enable_districts) || - (unit == NULL) || - (job_id != WJ_Build_Mines)) { - set_worker_animation(this, __, unit, job_id); - return; - } - - // If tile has a district under construction - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && - ! district_is_complete (tile, inst->district_id) && job_id == WJ_Build_Mines) { - - // Override and ensure build animation is used - job_id = AT_BUILD; - } - - set_worker_animation(this, __, unit, job_id); -} - -void __fastcall -patch_Unit_work_simple_job (Unit * this, int edx, int job_id) -{ - is->lmify_tile_after_working_simple_job = NULL; - - // Check if districts are enabled - if (is->current_config.enable_districts) { - int tile_x = this->Body.X; - int tile_y = this->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - - if (tile != NULL && tile != p_null_tile) { - // Check if there's a completed district on this tile - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete(tile, inst->district_id)) { - int district_id = inst->district_id; - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - - // AI players only (human removal is handled via issue_district_worker_command) - if (!is_human) { - bool allow_removal = false; - if (district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = &inst->wonder_info; - allow_removal = (info->state == WDS_UNUSED); - } - - if (allow_removal) { - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - handle_district_removed (tile, district_id, tile_x, tile_y, false); - } - } - } - } - } - - Unit_work_simple_job (this, __, job_id); - - if (is->lmify_tile_after_working_simple_job != NULL) - is->lmify_tile_after_working_simple_job->vtable->m31_set_landmark (is->lmify_tile_after_working_simple_job, __, true); -} - -void __fastcall -patch_Map_change_tile_terrain_by_worker (Map * this, int edx, enum SquareTypes new_terrain_type, int x, int y) -{ - Map_change_tile_terrain (this, __, new_terrain_type, x, y); - - if (is->current_config.convert_to_landmark_after_planting_forest && (new_terrain_type == SQ_Forest)) - is->lmify_tile_after_working_simple_job = tile_at (x, y); -} - -int __fastcall -patch_Leader_ai_eval_technology (Leader * this, int edx, int id, bool param_2, bool param_3) -{ - int base = Leader_ai_eval_technology (this, __, id, param_2, param_3); - return apply_perfume (PK_TECHNOLOGY, p_bic_data->Advances[id].Name, base); -} - -int __fastcall -patch_Leader_ai_eval_government (Leader * this, int edx, int id) -{ - int base = Leader_ai_eval_government (this, __, id); - return apply_perfume (PK_GOVERNMENT, p_bic_data->Governments[id].Name.S, base); -} - -bool -roll_to_spare_unit_from_nuke (Unit * unit) -{ - int one_hp_destroy_chance = is->current_config.chance_for_nukes_to_destroy_max_one_hp_units; - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - if ((one_hp_destroy_chance < 100) && - (Unit_get_max_hp (unit) <= 1) && - (type->Defence > 0) && - ((type->Unit_Class == UTC_Land) || (type->Unit_Class == UTC_Sea))) - return ! (rand_int (p_rand_object, __, 100) < one_hp_destroy_chance); - else - return false; -} - -void __fastcall -patch_Unit_despawn_after_killed_by_nuke (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) -{ - if (roll_to_spare_unit_from_nuke (this)) - this->Body.Damage = Unit_get_max_hp (this) - 1; - else { - bool prev_always_despawn_passengers = is->always_despawn_passengers; - if ((is->current_config.land_transport_rules & LTR_NO_ESCAPE) && is_land_transport (this)) - is->always_despawn_passengers = true; - else if ((is->current_config.special_helicopter_rules & SHR_NO_ESCAPE) && p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air && - p_bic_data->UnitTypes[this->Body.UnitTypeID].Transport_Capacity > 0) - is->always_despawn_passengers = true; - patch_Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); - is->always_despawn_passengers = prev_always_despawn_passengers; - } -} - -void __fastcall -patch_mp_despawn_after_killed_by_nuke (void * this, int edx, int unit_id, int civ_id_responsible, byte param_3, byte param_4, byte param_5, byte param_6) -{ - Unit * unit = get_unit_ptr (unit_id); - if ((unit != NULL) && roll_to_spare_unit_from_nuke (unit)) - unit->Body.Damage = Unit_get_max_hp (unit) - 1; - else - mp_despawn (this, __, unit_id, civ_id_responsible, param_3, param_4, param_5, param_6); -} - -bool __fastcall -patch_City_has_unprotected_improv_to_sell (City * this, int edx, int id) -{ - // Fall back to original logic only if the config doesn't alter the behavior. - if (! is->current_config.allow_sale_of_aqueducts_and_hospitals && !is->current_config.allow_sale_of_small_wonders) - return City_has_unprotected_improv (this, __, id); - - else if (patch_City_has_improvement (this, __, id, false)) { - Improvement * improv = &p_bic_data->Improvements[id]; - int max_pop_to_sell = INT_MAX; // By default, population-based sell isn't restricted - if (improv->ImprovementFlags & (ITF_Allows_City_Level_2 | ITF_Allows_City_Level_3)) { // Aqueduct/Hospital? - if (is->current_config.allow_sale_of_aqueducts_and_hospitals) { - if (improv->ImprovementFlags & ITF_Allows_City_Level_2) - max_pop_to_sell = p_bic_data->General.MaximumSize_Town; - else if (improv->ImprovementFlags & ITF_Allows_City_Level_3) - max_pop_to_sell = p_bic_data->General.MaximumSize_City; - } else { - // Do not allow selling these. - max_pop_to_sell = 0; - } - } - - // Can't sell: - // - Great Wonders - // - Small Wonders, unless the config allows it - // - Capital - // - Aqueduct/Hospital if the city is too big for that population - return ((improv->Characteristics & ITC_Wonder) == 0) && - (is->current_config.allow_sale_of_small_wonders || ((improv->Characteristics & ITC_Small_Wonder) == 0)) && - ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && - (this->Body.Population.Size <= max_pop_to_sell); - - } else - return false; -} - -bool __fastcall -patch_UnitType_has_detector_ability_for_vis_check (UnitType * this, int edx, enum UnitTypeAbilities a) -{ - bool tr = UnitType_has_ability (this, __, a); - - // Restrict detection by sea units to other sea units and non-sea units to other non-sea units - if (tr && - is->current_config.no_cross_shore_detection && - (is->checking_visibility_for_unit != NULL) && - ((this->Unit_Class == UTC_Sea) ^ (p_bic_data->UnitTypes[is->checking_visibility_for_unit->Body.UnitTypeID].Unit_Class == UTC_Sea))) - tr = false; - - return tr; -} - -bool -is_airdrop_trespassing (Unit * unit, int target_x, int target_y) -{ - if (is->current_config.disallow_trespassing && - check_trespassing (unit->Body.CivID, tile_at (unit->Body.X, unit->Body.Y), tile_at (target_x, target_y))) { - bool allowed = is_allowed_to_trespass (unit); - - // If "unit" is an air unit that can carry others, like helicopters, then this airdrop is only allowed if all of its passengers are - // allowed to trespass. - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - if (allowed && (type->Unit_Class == UTC_Air) && (type->Transport_Capacity > 0)) - FOR_UNITS_ON (uti, tile_at (unit->Body.X, unit->Body.Y)) - if ((uti.unit->Body.Container_Unit == unit->Body.ID) && - (! is_allowed_to_trespass (uti.unit))) { - allowed = false; - break; - } - - return ! allowed; - } else - return false; -} - -bool __fastcall -patch_Unit_check_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) -{ - return Unit_check_airdrop_target (this, __, tile_x, tile_y) && - is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID) && - ! is_airdrop_trespassing (this, tile_x, tile_y); -} - -bool __fastcall -patch_Unit_can_airlift (Unit * this) -{ - bool base = Unit_can_airlift (this); - - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) - return base; - - Tile * tile = tile_at (this->Body.X, this->Body.Y); - if ((tile == NULL) || (tile == p_null_tile)) - return base; - - bool allow_from_non_city = false; - if (base) { - City * city = city_at (this->Body.X, this->Body.Y); - if ((city == NULL) || (city->Body.CivID != this->Body.CivID)) - allow_from_non_city = true; - } - - if (allow_from_non_city) - return true; - - return tile_has_friendly_aerodrome_district (tile, this->Body.CivID, true); -} - -bool __fastcall -patch_Unit_check_airlift_target (Unit * this, int edx, int tile_x, int tile_y) -{ - bool base = Unit_check_airlift_target (this, __, tile_x, tile_y); - bool allowed = base; - - Tile * tile = tile_at (tile_x, tile_y); - - if (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities) { - if ((tile == NULL) || (tile == p_null_tile)) { - allowed = false; - } else { - City * target_city = city_at (tile_x, tile_y); - if (allowed && - (target_city != NULL) && - (target_city->Body.CivID == this->Body.CivID)) - allowed = false; - - if (! allowed) - allowed = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); - } - } - - if (! allowed) - return false; - - return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); -} - -void __fastcall -patch_Unit_airlift (Unit * this, int edx, int tile_x, int tile_y) -{ - Tile * source_tile = NULL; - bool mark_usage = false; - - if (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities) { - source_tile = tile_at (this->Body.X, this->Body.Y); - if (tile_has_friendly_aerodrome_district (source_tile, this->Body.CivID, true)) - mark_usage = true; - } - - Unit_airlift (this, __, tile_x, tile_y); - - if (mark_usage && (source_tile != NULL) && (source_tile != p_null_tile)) { - int mask = itable_look_up_or (&is->aerodrome_airlift_usage, (int)source_tile, 0); - mask |= (1 << this->Body.CivID); - itable_insert (&is->aerodrome_airlift_usage, (int)source_tile, mask); - } -} - -int __fastcall -patch_City_count_airports_for_ai_airlift_target (City * this, int edx, enum ImprovementTypeFlags airport_flag) -{ - // When this function is called, the AI unit being moved is stored in register ESI. - Unit * unit; - __asm__ __volatile__("mov %%esi, %0" : "=r" (unit)); - - int tr = City_count_improvements_with_flag (this, __, airport_flag); - - // Check the stack limit here. If the city's tile is at the limit, return that it has no airport so the AI can't airlift there. - if ((tr > 0) && ! is_below_stack_limit (tile_at (this->Body.X, this->Body.Y), this->Body.CivID, unit->Body.UnitTypeID)) - return 0; - - else - return tr; -} - -int __fastcall -patch_Unit_ai_eval_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) -{ - int tr = Unit_ai_eval_airdrop_target (this, __, tile_x, tile_y); - - // Prevent the AI from airdropping onto tiles in violation of the stack limit or trespassing restriction - if ((tr > 0) && - ((! is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID)) || - is_airdrop_trespassing (this, tile_x, tile_y))) - tr = 0; - - return tr; -} - -bool __fastcall -patch_Unit_find_telepad_on_tile (Unit * this, int edx, int x, int y, bool show_selection_popup, Unit ** out_unit_telepad) -{ - if (! is_below_stack_limit (tile_at (x, y), this->Body.CivID, this->Body.UnitTypeID)) { - *out_unit_telepad = NULL; - return false; - } else - return Unit_find_telepad_on_tile (this, __, x, y, show_selection_popup, out_unit_telepad); -} - -bool __fastcall -patch_Unit_ai_go_to_capital (Unit * this) -{ - City * capital = get_city_ptr (leaders[this->Body.CivID].CapitalID); - - // Block going to capital if the capital's tile is at the stack limit. This stops the AI from airlifting there (would violate the limit) and - // saves it from trying to pathfind there. - if ((capital != NULL) && - ! is_below_stack_limit (tile_at (capital->Body.X, capital->Body.Y), this->Body.CivID, this->Body.UnitTypeID)) - return false; - - return Unit_ai_go_to_capital (this); -} - -bool __fastcall -patch_Unit_is_in_rebase_range (Unit * this, int edx, int tile_x, int tile_y) -{ - bool in_range; - - // 6 is the game's standard value, so fall back on the base game logic in that case - if (is->current_config.rebase_range_multiplier == 6) - in_range = Unit_is_in_rebase_range (this, __, tile_x, tile_y); - - else { - int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - if (op_range < 1) - op_range = 500; - - int x_dist = Map_get_x_dist (&p_bic_data->Map, __, tile_x, this->Body.X), - y_dist = Map_get_y_dist (&p_bic_data->Map, __, tile_y, this->Body.Y); - - in_range = ((x_dist + y_dist) >> 1) <= (op_range * is->current_config.rebase_range_multiplier); - } - - return in_range && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); -} - -bool __fastcall -patch_Unit_check_rebase_target (Unit * this, int edx, int tile_x, int tile_y) -{ - // Check if this is an air unit - bool is_air_unit = (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air); - - // If districts are enabled and this is an air unit, check for aerodrome districts - if (is_air_unit && is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts) { - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - // Check if tile has a district - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - int district_id = inst->district_id; - // Check if this is an aerodrome district owned by this unit's civ - if ((district_id == AERODROME_DISTRICT_ID) && (tile->Territory_OwnerID == this->Body.CivID)) { - // Check if aerodrome is complete - if (district_is_complete (tile, district_id)) { - // Perform range check - bool in_range = patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y); - if (in_range) { - return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); - } - } - } - } - - // If air_units_use_aerodrome_districts_not_cities is enabled, check if there's a city and disallow it - if (is->current_config.air_units_use_aerodrome_districts_not_cities) { - City * target_city = city_at (tile_x, tile_y); - if (target_city != NULL && target_city->Body.CivID == this->Body.CivID) { - // There's a friendly city here - disallow landing since configured to use aerodromes/airfields/carriers only - return false; - } - } - } - } - - // 6 is the game's standard value, so fall back on the base game logic in that case - if (is->current_config.rebase_range_multiplier == 6) { - return Unit_check_rebase_target (this, __, tile_x, tile_y) && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); - - // Otherwise, we have to redo the range check. Unlike Unit::is_in_rebase_range, the base method here does more than just check the range so we - // want to make sure to call it even if we determine that the target is in range. In that case, set the range to unlimited temporarily so the - // base game's range check passes. - } else { - if (patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y)) { - int * p_op_range = &p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - int original_op_range = *p_op_range; - *p_op_range = 0; - bool tr = Unit_check_rebase_target (this, __, tile_x, tile_y); - *p_op_range = original_op_range; - return tr; - } else - return false; - } -} - -int __fastcall -patch_Sprite_draw_already_worked_tile_img (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - Sprite * to_draw = this; - - if (is->do_not_draw_already_worked_tile_img) - return 0; - - if (is->current_config.toggle_zoom_with_z_on_city_screen && p_bic_data->is_zoomed_out) { - - // Load sprite if necessary - if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_UNINITED) { - is->tile_already_worked_zoomed_out_sprite_init_state = IS_INIT_FAILED; - PCX_Image * pcx = malloc (sizeof *pcx); - if (pcx != NULL) { - memset (pcx, 0, sizeof *pcx); - PCX_Image_construct (pcx); - char path[2*MAX_PATH]; - get_mod_art_path ("TileAlreadyWorkedZoomedOut.pcx", path, sizeof path); - PCX_Image_read_file (pcx, __, path, NULL, 0, 0x100, 2); - if (pcx->JGL.Image != NULL) { - Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; - memset (sprite, 0, sizeof *sprite); - Sprite_construct (sprite); - Sprite_slice_pcx (sprite, __, pcx, 0, 0, 64, 32, 1, 1); - is->tile_already_worked_zoomed_out_sprite_init_state = IS_OK; - } - pcx->vtable->destruct (pcx, __, 0); - free (pcx); - } - } - - if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_OK) - to_draw = &is->tile_already_worked_zoomed_out_sprite; - } - - return Sprite_draw (to_draw, __, canvas, pixel_x, pixel_y, color_table); -} - -int __fastcall -patch_Tile_m43_Get_field_30_for_city_loc_eval (Tile * this) -{ - int tr = this->vtable->m43_Get_field_30 (this); - - // This patch function replaces two places where ai_eval_city_location calls Tile::m43_Get_field_30 to check the 18th bit, which indicates - // whether the tile is in the workable area of any city. If it is but the work area has been expanded, check that it's actually within the - // normal 20-tile area. This prevents work area expansion from causing AIs to space their cities further apart. - // The field_30_get_counter is a crazy workaround for the fact that the game doesn't have any way to determine a tile's coordinates given a - // pointer to its object. So we track the initial (x, y) for the tile we're evaluating and then count calls to this func to know what - // neighboring coords "this" corresponds to. - int get_counter = is->ai_evaling_city_field_30_get_counter; - if (((tr >> 17) & 1) && (is->current_config.city_work_radius >= 3)) { - bool found_city = false; - int this_x, this_y; { - int dx, dy; - patch_ni_to_diff_for_work_area (get_counter, &dx, &dy); - this_x = is->ai_evaling_city_loc_x + dx; - this_y = is->ai_evaling_city_loc_y + dy; - wrap_tile_coords (&p_bic_data->Map, &this_x, &this_y); - } - FOR_TILES_AROUND (tai, 21, this_x, this_y) - if (Tile_has_city (tai.tile)) { - found_city = true; - break; - } - if (! found_city) - tr &= ~(1 << 17); - } - get_counter++; - if (get_counter >= 21) - get_counter = 0; - is->ai_evaling_city_field_30_get_counter = get_counter; - - return tr; - -} - -// Intercept the call where the game gets a random index at which to start searching for a suitable tile to become polluted. Normally, it passes 20 as -// the limit here. We must replace that to cover a potentially modded work area. -int __fastcall -patch_rand_int_to_place_pollution (void * this, int edx, int lim) -{ - return rand_int (this, __, is->workable_tile_count - 1); -} - -void __fastcall -patch_Main_Screen_Form_t2s_coords_to_draw_yields (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int * out_x, int * out_y) -{ - Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, out_x, out_y); - - // If we've zoomed out the map on the city screen, we may end up drawing the tile yields off screen depending on the map size. If this is the - // case, detected by negative screen coords, then shift the coords over by one map-screen back onto the actual screen. The shift amounts are - // 64*map_width/2 and 32*map_height/2 for x and y because (64, 32) is the size of a zoomed out tile and /2 is for overlap (I think). - if (p_bic_data->is_zoomed_out && (*out_x < 0)) - *out_x += p_bic_data->Map.Width << 5; - if (p_bic_data->is_zoomed_out && (*out_y < 0)) - *out_y += p_bic_data->Map.Height << 4; -} - -void -set_clip_area_to_map_view (City_Form * city_form) -{ - int left_margin = (p_bic_data->ScreenWidth - city_form->Background_Image.Width) / 2, - top_margin = (p_bic_data->ScreenHeight - city_form->Background_Image.Height) / 2; - RECT map_view_on_screen = { .left = left_margin, .top = top_margin + 92, .right = left_margin + 1024, .bottom = top_margin + 508 }; - JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; - jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &map_view_on_screen); -} - -void -clear_clip_area (City_Form * city_form) -{ - JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; - jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &jgl_canvas->Image_Rect); -} - -void -init_distribution_hub_icons () -{ - if (is->distribution_hub_icons_img_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char ss[200]; - snprintf (ss, sizeof ss, "[C3X] init_distribution_hub_icons: state=%d\n", is->distribution_hub_icons_img_state); - (*p_OutputDebugStringA) (ss); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("Districts/DistributionHubIncomeIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image == NULL) || - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { - (*p_OutputDebugStringA) ("[C3X] PCX file for distribution hub icons failed to load or is too small.\n"); - is->distribution_hub_icons_img_state = IS_INIT_FAILED; - goto cleanup; - } - - // Extract shield icon (index 4: x = 1 + 4*31 = 125, width 30) - Sprite_construct (&is->distribution_hub_shield_icon); - Sprite_slice_pcx (&is->distribution_hub_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); - - // Extract shield corruption icon (index 5: x = 1 + 5*31 = 156, width 30) - Sprite_construct (&is->distribution_hub_corruption_icon); - Sprite_slice_pcx (&is->distribution_hub_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); - - // Extract small shield icon (index 13) - Sprite_construct (&is->distribution_hub_shield_icon_small); - Sprite_slice_pcx (&is->distribution_hub_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); - - // Extract surplus food icon (index 6: x = 1 + 6*31 = 187, width 30) - Sprite_construct (&is->distribution_hub_food_icon); - Sprite_slice_pcx (&is->distribution_hub_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); - - // Extract small surplus food icon (index 15) - Sprite_construct (&is->distribution_hub_food_icon_small); - Sprite_slice_pcx (&is->distribution_hub_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); - - // Extract eaten food icon (index 7: x = 1 + 7*31 = 218, width 30) - Sprite_construct (&is->distribution_hub_eaten_food_icon); - Sprite_slice_pcx (&is->distribution_hub_eaten_food_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); - - is->distribution_hub_icons_img_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -draw_district_yields (City_Form * city_form, Tile * tile, int district_id, int screen_x, int screen_y) -{ - // Lazy load district icons - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - if (is->dc_icons_img_state != IS_OK) - return; - - if (district_id < 0 || district_id >= is->district_count) - return; - - // Get district configuration - struct district_config * config = &is->district_configs[district_id]; - struct district_instance * inst = get_district_instance (tile); - - // Count total yields from bonuses - int food_bonus = 0, shield_bonus = 0, gold_bonus = 0, science_bonus = 0, culture_bonus = 0, happiness_bonus = 0; - get_effective_district_yields (inst, config, &food_bonus, &shield_bonus, &gold_bonus, &science_bonus, &culture_bonus, &happiness_bonus); - if ((config->generated_resource_id >= 0) && - (config->generated_resource_flags & MF_YIELDS) && - (city_form->CurrentCity != NULL) && - district_generates_resource_for_civ (tile, inst, config, city_form->CurrentCity->Body.CivID)) { - Resource_Type * res = &p_bic_data->ResourceTypes[config->generated_resource_id]; - food_bonus += res->Food; - shield_bonus += res->Shield; - gold_bonus += res->Commerce; - } - - int food_pos = food_bonus > 0 ? food_bonus : 0; - int food_neg = food_bonus < 0 ? -food_bonus : 0; - int shield_pos = shield_bonus > 0 ? shield_bonus : 0; - int shield_neg = shield_bonus < 0 ? -shield_bonus : 0; - int gold_pos = gold_bonus > 0 ? gold_bonus : 0; - int gold_neg = gold_bonus < 0 ? -gold_bonus : 0; - int science_pos = science_bonus > 0 ? science_bonus : 0; - int science_neg = science_bonus < 0 ? -science_bonus : 0; - int culture_pos = culture_bonus > 0 ? culture_bonus : 0; - int culture_neg = culture_bonus < 0 ? -culture_bonus : 0; - int happiness_pos = happiness_bonus > 0 ? happiness_bonus : 0; - int happiness_neg = happiness_bonus < 0 ? -happiness_bonus : 0; - - int total_yield = 0; - total_yield += food_pos + food_neg; - total_yield += shield_pos + shield_neg; - total_yield += gold_pos + gold_neg; - total_yield += science_pos + science_neg; - total_yield += culture_pos + culture_neg; - total_yield += happiness_pos + happiness_neg; - - if (total_yield <= 0) - return; - - // Get sprites - Sprite * food_sprite = &is->district_food_icon_small; - Sprite * shield_sprite = &is->district_shield_icon_small; - Sprite * commerce_sprite = &is->district_commerce_icon_small; - Sprite * science_sprite = &is->district_science_icon_small; - Sprite * culture_sprite = &is->district_culture_icon_small; - Sprite * happiness_sprite = &is->district_happiness_icon_small; - Sprite * food_negative_sprite = &is->district_negative_food_icon_small; - Sprite * shield_negative_sprite = &is->district_negative_shield_icon_small; - Sprite * commerce_negative_sprite = &is->district_negative_commerce_icon_small; - Sprite * science_negative_sprite = &is->district_negative_science_icon_small; - Sprite * culture_negative_sprite = &is->district_negative_culture_icon_small; - Sprite * happiness_negative_sprite = &is->district_unhappiness_icon_small; - - // Determine sprite dimensions - int sprite_width = food_sprite->Width3; - int sprite_height = food_sprite->Height; - - // Calculate total width of all icons - int total_width = total_yield * sprite_width; - - // Center the icons horizontally - int half_width = total_width >> 1; - int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; - int max_offset = (tile_width >> 1) - 5; - if (half_width > max_offset) - half_width = max_offset; - - int pixel_x = screen_x - half_width; - int pixel_y = screen_y - (sprite_height >> 1); - - // Adjust spacing if icons would exceed tile width - int spacing = sprite_width; - if (total_width > tile_width - 10) { - if (total_yield > 1) { - spacing = (tile_width - 10 - sprite_width) / (total_yield - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > sprite_width) - spacing = sprite_width; - } - } - - // Draw icons in order: shields, food, science, commerce, culture - for (int i = 0; i < shield_pos; i++) { - Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < shield_neg; i++) { - Sprite_draw (shield_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < food_pos; i++) { - Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < food_neg; i++) { - Sprite_draw (food_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < science_pos; i++) { - Sprite_draw (science_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < science_neg; i++) { - Sprite_draw (science_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < gold_pos; i++) { - Sprite_draw (commerce_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < gold_neg; i++) { - Sprite_draw (commerce_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < culture_pos; i++) { - Sprite_draw (culture_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < culture_neg; i++) { - Sprite_draw (culture_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < happiness_pos; i++) { - Sprite_draw (happiness_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < happiness_neg; i++) { - Sprite_draw (happiness_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } -} - -void -draw_distribution_hub_yields (City_Form * city_form, Tile * tile, int tile_x, int tile_y, int screen_x, int screen_y) -{ - // Get the distribution hub record for this tile - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec == NULL) - return; - - City * anchor_city = get_connected_city_for_distribution_hub (rec); - if (! distribution_hub_accessible_to_city (rec, city_form->CurrentCity)) - return; - - int food_yield = rec->food_yield; - int shield_yield = rec->shield_yield; - int total_yield = food_yield + shield_yield; - - if (total_yield <= 0) - return; - - // Lazy load distribution hub icons - if (is->distribution_hub_icons_img_state == IS_UNINITED) - init_distribution_hub_icons (); - if (is->distribution_hub_icons_img_state != IS_OK) - return; - - Sprite * food_sprite = &is->distribution_hub_food_icon_small; - Sprite * shield_sprite = &is->distribution_hub_shield_icon_small; - - if (food_sprite->Width3 == 0) food_sprite = &is->distribution_hub_food_icon; - if (shield_sprite->Width3 == 0) shield_sprite = &is->distribution_hub_shield_icon; - - int sprite_height = food_sprite->Height; - if (sprite_height == 0) sprite_height = shield_sprite->Height; - - int food_width = food_sprite->Width3; - int shield_width = shield_sprite->Width3; - if ((food_width <= 0) && (shield_width > 0)) food_width = shield_width; - if ((shield_width <= 0) && (food_width > 0)) shield_width = food_width; - - // Calculate total width of all icons - int total_width = 0; - if (food_yield > 0) total_width += food_width * food_yield; - if (shield_yield > 0) total_width += shield_width * shield_yield; - - // Center the icons horizontally - int half_width = total_width >> 1; - int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; - int max_offset = (tile_width >> 1) - 5; - if (half_width > max_offset) half_width = max_offset; - - int pixel_x = screen_x - half_width; - int pixel_y = screen_y - (sprite_height >> 1); - - // Adjust spacing if icons would exceed tile width - int spacing_food = food_width; - int spacing_shield = shield_width; - - if (total_width > tile_width - 10) { - if (total_yield > 1) { - int spacing = (tile_width - 10 - food_width) / (total_yield - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > food_width) - spacing = food_width; - spacing_food = spacing; - spacing_shield = spacing; - } - } - - // Draw food icons first - for (int i = 0; i < food_yield; i++) { - Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing_food; - } - - // Draw shield icons - for (int i = 0; i < shield_yield; i++) { - Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing_shield; - } -} - -void __fastcall -patch_City_Form_draw_yields_on_worked_tiles (City_Form * this) -{ - // If we're zoomed in and the city work radius is at least 4 then it's likely we'll end up drawing things outside of the city screen's usual - // map area. Set the clip area to the map area so none of those draws are visible. - bool changed_clip_area = false; - if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { - set_clip_area_to_map_view (this); - changed_clip_area = true; - } - - if (is->current_config.enable_districts && this->CurrentCity != NULL) { - recompute_city_yields_with_districts (this->CurrentCity); - } - - is->do_not_draw_already_worked_tile_img = false; - City_Form_draw_yields_on_worked_tiles (this); - - // If we're zoomed out then draw the yields again but this time skip drawing of the tile-already-worked sprites. This is because the - // transparent regions of those sprites get drawn overtop of the yield sprites when zoomed out, and that overdrawing deletes parts of the - // yields, i.e., it overwrites their colored pixels with transparent ones. The simplest solution is to draw the yields again after the - // already-worked sprites to ensure the former get drawn overtop of the latter. - if (p_bic_data->is_zoomed_out) { - is->do_not_draw_already_worked_tile_img = true; - City_Form_draw_yields_on_worked_tiles (this); - } - - // Draw district bonuses on district tiles - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - City * city = this->CurrentCity; - if (city == NULL) - goto skip_district_yields; - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int civ_id = city->Body.CivID; - - // Calculate screen coordinates for city center - int center_screen_x, center_screen_y; - Main_Screen_Form_tile_to_screen_coords (p_main_screen_form, __, city_x, city_y, ¢er_screen_x, ¢er_screen_y); - - int tile_half_width = p_bic_data->is_zoomed_out ? 32 : 64; - int tile_half_height = p_bic_data->is_zoomed_out ? 16 : 32; - center_screen_x += tile_half_width; - if (center_screen_x < 0) - center_screen_x += p_bic_data->Map.Width * tile_half_width; - center_screen_y += tile_half_height; - if (center_screen_y < 0) - center_screen_y += p_bic_data->Map.Height * tile_half_height; - - int remaining_utilized_neighborhoods = 0; - if (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts) - remaining_utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - - FOR_DISTRICTS_AROUND (wai, city_x, city_y, true) { - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - bool is_distribution_hub = district_id == DISTRIBUTION_HUB_DISTRICT_ID; - bool is_natural_wonder = district_id == NATURAL_WONDER_DISTRICT_ID; - - if (is_natural_wonder && (!is->current_config.enable_natural_wonders)) - continue; - - // Distribution hubs are drawn in the dedicated wider-radius pass below. - if (is_distribution_hub) - continue; - - if (!is_natural_wonder && (!is->current_config.enable_districts)) - continue; - - // For neighborhood districts, check if population is high enough to utilize them - if (is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - district_id == NEIGHBORHOOD_DISTRICT_ID) { - // Only draw yields if this neighborhood is utilized - if (remaining_utilized_neighborhoods <= 0) - continue; - remaining_utilized_neighborhoods--; - } - - // Calculate screen coordinates for this tile - int screen_x = center_screen_x + (wai.dx * tile_half_width); - int screen_y = center_screen_y + (wai.dy * tile_half_height); - - // Call the appropriate drawing function - draw_district_yields (this, wai.tile, district_id, screen_x, screen_y); - } - - // Draw distribution hub yields around a larger radius so connected hubs outside the work area are shown - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { - int const max_tiles = workable_tile_counts[7]; - - for (int ni = 0; ni < max_tiles; ni++) { - int dx, dy; - patch_ni_to_diff_for_work_area (ni, &dx, &dy); - - int tile_x = city_x + dx; - int tile_y = city_y + dy; - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID)) - continue; - - int screen_x = center_screen_x + (dx * tile_half_width); - int screen_y = center_screen_y + (dy * tile_half_height); - draw_distribution_hub_yields (this, tile, tile_x, tile_y, screen_x, screen_y); - } - } - } - -skip_district_yields: - if (changed_clip_area) - clear_clip_area (this); -} - -bool __fastcall -patch_City_Form_draw_highlighted_yields (City_Form * this, int edx, int tile_x, int tile_y, int neighbor_index) -{ - // Make sure we don't draw outside the map area - bool changed_clip_area = false; - if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { - set_clip_area_to_map_view (this); - changed_clip_area = true; - } - - bool tr = City_Form_draw_highlighted_yields (this, __, tile_x, tile_y, neighbor_index); - - if (changed_clip_area) - clear_clip_area (this); - return tr; -} - -void __fastcall -patch_City_Form_draw_border_around_workable_tiles (City_Form * this) -{ - // Make sure we don't draw outside the map area - bool changed_clip_area = false; - if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { - set_clip_area_to_map_view (this); - changed_clip_area = true; - } - - City_Form_draw_border_around_workable_tiles (this); - - if (changed_clip_area) - clear_clip_area (this); -} - -bool __fastcall -patch_City_stop_working_polluted_tile (City * this, int edx, int neighbor_index) -{ - if (is->current_config.do_not_unassign_workers_from_polluted_tiles && - (*p_human_player_bits & (1 << this->Body.CivID))) - return false; // do nothing; return value is not used - else - return City_stop_working_tile (this, __, neighbor_index); -} - -void __fastcall -patch_City_manage_by_governor (City * this, int edx, bool manage_professions) -{ - int * p_stack = (int *)&manage_professions; - int ret_addr = p_stack[-1]; - - // Do nothing if called after spawning pollution but didn't unassign worker - if ((ret_addr == ADDR_MANAGE_CITY_AFTER_POLLUTION_RETURN) && - is->current_config.do_not_unassign_workers_from_polluted_tiles && - (*p_human_player_bits & (1 << this->Body.CivID))) - return; - - City_manage_by_governor (this, __, manage_professions); -} - -City * __cdecl -patch_find_nearest_city_for_ai_alliance_eval (int tile_x, int tile_y, int owner_id, int continent_id, int ignore_owner_id, int perspective_id, City * ignore_city) -{ - City * tr = find_nearest_city (tile_x, tile_y, owner_id, continent_id, ignore_owner_id, perspective_id, ignore_city); - if (is->current_config.patch_division_by_zero_in_ai_alliance_eval && (*p_nearest_city_distance == 0)) - *p_nearest_city_distance = 1; - return tr; -} - -int __fastcall -patch_Unit_get_max_move_points (Unit * this) -{ - if (Unit_has_ability (this, __, UTA_Army) && is->current_config.patch_empty_army_movement) { - int slowest_member_mp = INT_MAX; - bool any_units_in_army = false; - FOR_UNITS_ON (uti, tile_at (this->Body.X, this->Body.Y)) { - if (uti.unit->Body.Container_Unit == this->Body.ID) { - any_units_in_army = true; - slowest_member_mp = not_above (Unit_get_max_move_points (uti.unit), slowest_member_mp); - } - } - if (any_units_in_army) - return slowest_member_mp + p_bic_data->General.RoadsMovementRate; - else - return get_max_move_points (&p_bic_data->UnitTypes[this->Body.UnitTypeID], this->Body.CivID); - } else - return Unit_get_max_move_points (this); -} - -char __fastcall -patch_Unit_is_visible_to_civ_for_bouncing (Unit * this, int edx, int civ_id, int param_2) -{ - // If we're set not to kick out invisible units and this one is invis. then report that it's not seen so it's left alone - if (is->do_not_bounce_invisible_units && Unit_has_ability (this, __, UTA_Invisible)) - return 0; - else - return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); -} - -void __fastcall -patch_Leader_make_peace (Leader * this, int edx, int civ_id) -{ - Leader_make_peace (this, __, civ_id); - - if (is->current_config.disallow_trespassing && - (! this->At_War[civ_id]) && // Make sure the war actually ended - ((this->Relation_Treaties[civ_id] & 2) == 0)) { // Check right of passage (just in case) - is->do_not_bounce_invisible_units = true; - Leader_bounce_trespassing_units (&leaders[civ_id], __, this->ID); - is->do_not_bounce_invisible_units = false; - } -} - -// This patch function replaces calls to Leader::count_wonders_with_flag but is only valid in cases where it only matters whether the return value is -// zero or non-zero. This function will not return the actual count, just zero if no wonders are present and some >0 value if there is at least one. -int __fastcall -patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) -{ - int tr = Leader_count_wonders_with_flag (this, __, flag, only_in_city); - - if ((tr == 0) && - (only_in_city == NULL) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player - - // Sum up wonders owned by other human players - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->ID)) - if (Leader_count_wonders_with_flag (&leaders[n_player], __, flag, only_in_city) > 0) { - tr = 1; - break; - } - player_bits >>= 1; - n_player++; - } - } - - return tr; -} - -int __fastcall -patch_Leader_count_wonders_with_flag_ignore_great_wall (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) -{ - if (is->current_config.enable_districts && - is->current_config.enable_great_wall_districts && - is->current_config.disable_great_wall_city_defense_bonus && - flag == ITW_Doubles_City_Defenses) - return 0; - - return patch_Leader_count_any_shared_wonders_with_flag (this, __, flag, only_in_city); -} - -int const shared_small_wonder_flags = - ITSW_Increases_Chance_of_Leader_Appearance | - ITSW_Build_Larger_Armies | - ITSW_Treasury_Earns_5_Percent | - ITSW_Decreases_Success_Of_Missile_Attacks | - ITSW_Allows_Spy_Missions | - ITSW_Allows_Healing_In_Enemy_Territory | - ITSW_Requires_Victorous_Army | - ITSE_Requires_Elite_Naval_Units; - - -int __fastcall -patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) -{ - int tr = Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); - - // If "this" is a human player who's sharing wonders in hotseat and the flag is one of the ones that gets shared, include the wonders owned by - // all other humans in the game - if ((city_or_null == NULL) && - (flag & shared_small_wonder_flags) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player - - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->ID)) - tr += Leader_count_wonders_with_small_flag (&leaders[n_player], __, flag, city_or_null); - player_bits >>= 1; - n_player++; - } - } - - return tr; -} - -int -find_human_player_with_small_wonder (int improv_id) -{ - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if (player_bits & 1) - if (leaders[n_player].Small_Wonders[improv_id] != -1) - return n_player; - player_bits >>= 1; - n_player++; - } - return -1; -} - -bool __fastcall -patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2) -{ - Improvement * improv = &p_bic_data->Improvements[i_improv]; - bool restore = false; - bool already_shared = false; - int saved_status, saved_required_building_count, saved_armies_count; - if ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) && // if the improv in question is a great or small wonder - is->current_config.share_wonders_in_hotseat && // if we're configured to share wonder effects - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // if in a hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // if "this" is a human player - - // If another human player has already built this small wonder and it has no non-shared effects, then make it unbuildable - if ((improv->Characteristics & ITC_Small_Wonder) && - (find_human_player_with_small_wonder (i_improv) != -1) && - ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) - already_shared = true; - - else { - restore = true; - saved_status = this->Status; - if (improv->RequiredBuildingID != -1) - saved_required_building_count = this->Improvement_Counts[improv->RequiredBuildingID]; - saved_armies_count = this->Armies_Count; - - // Loop over all other human players in the game - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->ID)) { - - // Combine status bits - this->Status |= leaders[n_player].Status & (LSF_HAS_VICTORIOUS_ARMY | LSF_HAS_ELITE_NAVAL_UNIT); - - // Combine building counts for the required building if there is one - if (improv->RequiredBuildingID != -1) - this->Improvement_Counts[improv->RequiredBuildingID] += leaders[n_player].Improvement_Counts[improv->RequiredBuildingID]; - - // Combine army counts - this->Armies_Count += leaders[n_player].Armies_Count; - - } - player_bits >>= 1; - n_player++; - } - } - } - - bool tr = (! already_shared) && Leader_can_build_city_improvement (this, __, i_improv, param_2); - - if (restore) { - this->Status = saved_status; - if (improv->RequiredBuildingID != -1) - this->Improvement_Counts[improv->RequiredBuildingID] = saved_required_building_count; - - this->Armies_Count = saved_armies_count; - } - return tr; - -} - -void __fastcall -patch_City_add_happiness_from_buildings (City * this, int edx, int * inout_happiness, int * inout_unhappiness) -{ - // If we're in a hotseat game with shared wonder effects, merge all human player's improvement counts together so the base function checks for - // happiness from improvements owned by other human players. - Leader * owner = &leaders[this->Body.CivID]; - bool restore_improv_counts = false; - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->Body.CivID) & *p_human_player_bits)) { // "this" is owned by a human player - - // Ensure the space we've set aside for saving the real improv counts is large enough - if ((is->saved_improv_counts == NULL) || (is->saved_improv_counts_capacity < p_bic_data->ImprovementsCount)) { - free (is->saved_improv_counts); - is->saved_improv_counts = calloc (p_bic_data->ImprovementsCount, sizeof is->saved_improv_counts[0]); - is->saved_improv_counts_capacity = (is->saved_improv_counts != NULL) ? p_bic_data->ImprovementsCount : 0; - } - - - if (is->saved_improv_counts != NULL) { - // Save the owner's real improv counts and remember to restore them before returning - restore_improv_counts = true; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - is->saved_improv_counts[n] = owner->Improvement_Counts[n]; - - // Add in improv counts for wonders from all other human players in the game - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != owner->ID)) - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (p_bic_data->Improvements[n].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - owner->Improvement_Counts[n] += leaders[n_player].Improvement_Counts[n]; - player_bits >>= 1; - n_player++; - } - } - - } - - City_add_happiness_from_buildings (this, __, inout_happiness, inout_unhappiness); - - if (is->current_config.enable_districts) { - int district_happy = 0; - calculate_district_happiness_bonus (this, &district_happy); - - if (district_happy != 0) - *inout_happiness += district_happy; - } - - if (restore_improv_counts) { - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - owner->Improvement_Counts[n] = is->saved_improv_counts[n]; - } -} - -int __fastcall -patch_City_count_other_cont_happiness_buildings (City * this, int edx, int improv_id) -{ - int tr = City_count_other_buildings_on_continent (this, __, improv_id); - - // If it's a hotseat game where we're sharing wonders, "improv_id" refers to a wonder, and "this" is owned by a human player - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((p_bic_data->Improvements[improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && - ((1 << this->Body.CivID) & *p_human_player_bits)) { - - // Add in instances of this improvment on this continent owned by other human players - Tile * this_city_tile = tile_at (this->Body.X, this->Body.Y); - int this_cont_id = this_city_tile->vtable->m46_Get_ContinentID (this_city_tile); - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city != NULL) && (city != this) && - (city->Body.CivID != this->Body.CivID) && // if city is owned by a different player AND - ((1 << city->Body.CivID) & *p_human_player_bits)) { // that player is a human - Tile * that_city_tile = tile_at (city->Body.X, city->Body.Y); - int that_cont_id = that_city_tile->vtable->m46_Get_ContinentID (that_city_tile); - if ((this_cont_id == that_cont_id) && patch_City_has_improvement (city, __, improv_id, true)) - tr++; - } - } - - } - - return tr; -} - -void __fastcall -patch_Leader_update_great_library_unlocks (Leader * this) -{ - // If it's a hotseat game with shared wonder effects and "this" is a human player, share contacts among all human players so that "this" gets - // techs from civs known to any human player in the game. Save the real contact info and restore it afterward. NOTE: Contact info has to go - // two ways here; we must mark that "this" has contacted the AIs and vice-versa otherwise the techs won't be granted. That's why we must save - // & restore all contact bits for all players. - bool restore_contacts = false; - struct contact_set { - int contacts[32]; - } saved_contact_sets[32]; - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player - - restore_contacts = true; - for (int n = 0; n < 32; n++) - for (int k = 0; k < 32; k++) - saved_contact_sets[n].contacts[k] = leaders[n].Contacts[k]; - - unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_human = 1; - while (human_player_bits != 0) { - if ((human_player_bits & 1) && (n_human != this->ID)) // n_human is ID of a human player other than "this" - for (int n_ai = 0; n_ai < 32; n_ai++) - if ((*p_player_bits & (1 << n_ai)) && ((*p_human_player_bits & (1 << n_ai)) == 0)) { - // If the human and AI players have contact, mark "this" as having contact with the AI and vice-versa - if (leaders[n_human].Contacts[n_ai] & 1) { - this->Contacts[n_ai] |= 1; - leaders[n_ai].Contacts[this->ID] |= 1; - } - } - human_player_bits >>= 1; - n_human++; - } - } - - Leader_update_great_library_unlocks (this); - - if (restore_contacts) - for (int n = 0; n < 32; n++) - for (int k = 0; k < 32; k++) - leaders[n].Contacts[k] = saved_contact_sets[n].contacts[k]; -} - -bool __fastcall -patch_Leader_has_wonder_doubling_happiness_from (Leader * this, int edx, int improv_id) -{ - bool tr = Leader_has_wonder_doubling_happiness_from (this, __, improv_id); - - // If we're sharing wonder effects in a hotseat game and "this" is a human player, return true when another human player in the game has a - // wonder doubling happiness - if ((! tr) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player - unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_human = 1; - while (human_player_bits != 0) { - if ((human_player_bits & 1) && - (n_human != this->ID) && - Leader_has_wonder_doubling_happiness_from (&leaders[n_human], __, improv_id)) { - tr = true; - break; - } - human_player_bits >>= 1; - n_human++; - } - } - - return tr; -} - -int __fastcall -patch_Sprite_draw_citizen_head (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - // Reset variable - is->specialist_icon_drawing_running_x = INT_MIN; - - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -int -adjust_specialist_yield_icon_x (int pixel_x, int width) -{ - if (is->current_config.fix_overlapping_specialist_yield_icons) { - if (is->specialist_icon_drawing_running_x == INT_MIN) // first icon drawn - is->specialist_icon_drawing_running_x = pixel_x; - int tr = is->specialist_icon_drawing_running_x; - is->specialist_icon_drawing_running_x += width; - return tr; - } else - return pixel_x; -} - -int __fastcall -patch_Sprite_draw_entertainer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_12_Happy_Faces.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_scientist_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_16_Science.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_tax_collector_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_14_Gold.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_civil_engineer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_13_Shield.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_police_officer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_17_Gold_Outcome.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} - -void __fastcall -patch_City_add_building_if_done (City * this) -{ - // If sharing small wonders in hotseat, check whether the city is building a small wonder that's no longer available to the player b/c its - // effects are provided from another. - int improv_id = this->Body.Order_ID; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - int already_built_by_id; - if ((improv->Characteristics & ITC_Small_Wonder) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->Body.CivID) & *p_human_player_bits) && // city owned by a human player - ((already_built_by_id = find_human_player_with_small_wonder (improv_id)) != -1) && // SW already built by another human player - ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) { // SW has no non-shared effects - - // Switch city production to something else and notify the player - this->vtable->set_production_to_most_expensive_option (this); - if ((this->Body.CivID == p_main_screen_form->Player_CivID) && (already_built_by_id != p_main_screen_form->Player_CivID)) { - char * new_build_name = (this->Body.Order_Type == COT_Improvement) ? - p_bic_data->Improvements[this->Body.Order_ID].Name.S : - p_bic_data->UnitTypes[this->Body.Order_ID].Name; - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, this->Body.CityName, -1, -1); - set_popup_str_param (1, improv->Name.S, -1, -1); - set_popup_str_param (2, Leader_get_civ_noun (&leaders[already_built_by_id]), -1, -1); - set_popup_str_param (3, new_build_name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_SHARED_WONDER_CHANGE", -1, 0, 0, 0); - int response = patch_show_popup (popup, __, 0, 0); - if (response == 0) - *p_zoom_to_city_after_update = true; - } - - // As in the base logic, if production gets switched, the game doesn't check if it might still complete on the same turn. - return; - } - - // If production ended up on a wonder, make sure the city can actually build it; otherwise fall back to a defensive unit. - int order_type = this->Body.Order_Type; - int order_id = this->Body.Order_ID; - if (is->current_config.enable_districts && order_type == COT_Improvement) { - Improvement * new_improv = &p_bic_data->Improvements[order_id]; // Improvement might have changed - if (new_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { - if (! (City_can_build_improvement (this, __, order_id, false) && city_meets_district_prereqs_to_build_improvement (this, order_id, true))) { - char ss[256]; - snprintf (ss, sizeof ss, "patch_City_add_building_if_done: City '%s' cannot complete building of wonder '%s'; switching to defensive unit.\n", - this->Body.CityName, - new_improv->Name.S); - (*p_OutputDebugStringA) (ss); - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (this, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) { - City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); - return; - } - } - } - } - } - - City_add_building_if_done (this); -} - -bool __fastcall -patch_City_can_build_upgrade_type (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) -{ - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - if (is->current_config.prevent_old_units_from_upgrading_past_ability_block && - ((type->Special_Actions & UCV_Upgrade_Unit) == 0) && - (type->Available_To & (1 << leaders[this->Body.CivID].RaceID))) - exclude_upgradable = false; - - return patch_City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); -} - -void __fastcall -patch_Main_GUI_position_elements (Main_GUI * this) -{ - Main_GUI_position_elements (this); - - // Double size of minimap if configured - bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || - ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); - if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) { - this->Mini_Map_Click_Rect.top -= 105; - this->Mini_Map_Click_Rect.right += 229; - } -} - -#define PEDIA_DESC_LINES_PER_PAGE 38 - -// Returns whether or not the line should be drawn -bool -do_next_line_for_pedia_desc (PCX_Image * canvas, int * inout_y) -{ - if (is->cmpd.drawing_lines && is->current_config.allow_multipage_civilopedia_descriptions) { - int first_line_on_shown_page = is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE; - int page = is->cmpd.line_count / PEDIA_DESC_LINES_PER_PAGE; - is->cmpd.line_count += 1; - is->cmpd.last_page = (page > is->cmpd.last_page) ? page : is->cmpd.last_page; - - if (page == is->cmpd.shown_page) { - *inout_y -= is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE * PCX_Image_get_text_line_height (canvas); - return true; - } else - return false; - } - return true; -} - -int __fastcall -patch_PCX_Image_do_draw_centered_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) -{ - if (do_next_line_for_pedia_desc (this, &y)) - return PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); - else - return 0; // Caller does not use return value -} - -int __fastcall -patch_PCX_Image_draw_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int str_len) -{ - if (do_next_line_for_pedia_desc (this, &y)) - return PCX_Image_draw_text (this, __, str, x, y, str_len); - else - return PCX_Image_draw_text (this, __, " ", x, y, 1); // Caller uses the return value here so draw an empty string isntead of doing nothing -} - -// Steam code is slightly different; this no-len version of draw_text gets called sometimes. It's the same as draw_text instead it computes the string -// length itself instead of taking it in as a parameter. -int __fastcall -patch_PCX_Image_draw_text_no_len_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y) -{ - return patch_PCX_Image_draw_text_in_wrap_func (this, __, str, x, y, strlen (str)); -} - -void -draw_civilopedia_article (void (__fastcall * base) (Civilopedia_Article *), Civilopedia_Article * article) -{ - // If the article changed then clear things from the old one - if (is->cmpd.article != article) { - is->cmpd.last_page = 0; - is->cmpd.shown_page = 0; - is->cmpd.article = article; - } - - is->cmpd.line_count = 0; - is->cmpd.drawing_lines = article->show_description; - - base (article); - - is->cmpd.drawing_lines = false; -} - -void __fastcall -patch_Civilopedia_Article_m01_Draw_GCON_or_RACE (Civilopedia_Article * this) -{ - draw_civilopedia_article (Civilopedia_Article_m01_Draw_GCON_or_RACE, this); -} - -void __fastcall -patch_Civilopedia_Article_m01_Draw_UNIT (Civilopedia_Article * this) -{ - draw_civilopedia_article (Civilopedia_Article_m01_Draw_UNIT, this); -} - -void __fastcall -patch_Civilopedia_Form_m53_On_Control_Click (Civilopedia_Form * this, int edx, CivilopediaControlID control_id) -{ - Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; - - // "Effects" button leaves description mode, returns to showing effects - if ((control_id == PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID) && (current_article != NULL)) { - current_article->show_description = false; - is->cmpd.shown_page = 0; - play_sound_effect (26); // 26 = SE_SELECT - p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); - - // "Previous" button shows the previous page of a multi-page description or switches to effects mode if on the first page - } else if (control_id == PEDIA_MULTIPAGE_PREV_BUTTON_ID) { - if (is->cmpd.shown_page > 0) - is->cmpd.shown_page -= 1; - else - current_article->show_description = false; - play_sound_effect (26); - p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); - - } else if ((control_id == CCID_DESCRIPTION_BTN) && // if description/more/prev button was clicked AND - (current_article != NULL) && current_article->show_description && // currently showing a description of an article AND - (is->cmpd.last_page > 0)) { // this is a multi-page description - - // Show the next page of the multi-page description unless it's a two-page description and we're on the second page, in which case go - // back to the first. - if ((is->cmpd.last_page == 1) && (is->cmpd.shown_page == 1)) - is->cmpd.shown_page = 0; - else - is->cmpd.shown_page = not_above (is->cmpd.last_page, is->cmpd.shown_page + 1); - play_sound_effect (26); - p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); - - } else - Civilopedia_Form_m53_On_Control_Click (this, __, control_id); -} - -void __fastcall -patch_Civilopedia_Form_m22_Draw (Civilopedia_Form * this) -{ - // Make sure the new buttons are not visible and the multipage variables are cleared when we exit description mode - if ((this->Current_Article_ID < 0) || ! this->Articles[this->Current_Article_ID]->show_description) { - is->cmpd.shown_page = is->cmpd.last_page = 0; - if (is->cmpd.effects_btn != NULL) - is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); - if (is->cmpd.previous_btn != NULL) - is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); - } - - Civilopedia_Form_m22_Draw (this); -} - -int __fastcall -patch_Button_initialize_civilopedia_description (Button * this, int edx, char * text, int control_id, int x, int y, int width, int height, Base_Form * parent, int param_8) -{ - Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; - if (current_article == NULL) - return Button_initialize (this, __, text, control_id, x, y, width, height, parent, param_8); - - // Set button visibility for multi-page descriptions if we're showing such a thing right now - bool show_desc_btn = true, show_effects_btn = false, show_previous_btn = false; - char * desc_btn_text = text; - if (current_article->show_description && (is->cmpd.last_page > 0)) { - - // Tribe articles act like one long descripton. - if ((current_article->article_kind == CAK_TRIBE) || (current_article->article_kind == CAK_GAME_CONCEPT)) { - - // Show the more button as long as we're not on the last page. Show the previous always since we're in description mode. - show_previous_btn = true; - desc_btn_text = (*p_labels)[LBL_MORE]; - if (is->cmpd.shown_page >= is->cmpd.last_page) - show_desc_btn = false; - - // Unit articles have separate description/effects modes. - } else if (current_article->article_kind == CAK_UNIT) { - - // For a two-page description, show the effects button and the description button which will act as a next/previous button - if (is->cmpd.last_page == 1) { - show_effects_btn = true; - desc_btn_text = is->cmpd.shown_page == 0 ? (*p_labels)[LBL_MORE] : (*p_labels)[LBL_PREVIOUS]; - - // For a three or more page description, show the effects button, and show the description button only if we're not on the - // last page (b/c it's the next button), and show the previous button only if we're not on the first page. If the desc button - // is visible, make it say "More". - } else { - show_effects_btn = true; - if (is->cmpd.shown_page >= is->cmpd.last_page) - show_desc_btn = false; - else - desc_btn_text = (*p_labels)[LBL_MORE]; - show_previous_btn = is->cmpd.shown_page > 0; - } - } - } - - int tr = Button_initialize (this, __, desc_btn_text, control_id, x, y, width, height, parent, param_8); - - if (! show_desc_btn) - this->vtable->m02_Show_Disabled ((Base_Form *)this); - - if (is->cmpd.effects_btn != NULL) { - if (show_effects_btn) - is->cmpd.effects_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.effects_btn, __, 0); - else - is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); - } - - if (is->cmpd.previous_btn != NULL) { - if (show_previous_btn) - is->cmpd.previous_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.previous_btn, __, 0); - else - is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); - } - - return tr; -} - -int __fastcall -patch_Civilopedia_Form_m68_Show_Dialog (Civilopedia_Form * this, int edx, int param_1, void * param_2, void * param_3) -{ - memset (&is->cmpd, 0, sizeof is->cmpd); - - Button * bs[] = {malloc (sizeof Button), malloc (sizeof Button)}; - for (int n = 0; n < ARRAY_LEN (bs); n++) { - if (bs[n] == NULL) - continue; - Button_construct (bs[n]); - - int desc_btn_x = 535, desc_btn_y = 222, desc_btn_height = 17; - - Button_initialize (bs[n], __, - n == 0 ? (*p_labels)[LBL_EFFECTS] : (*p_labels)[LBL_PREVIOUS], - n == 0 ? PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID : PEDIA_MULTIPAGE_PREV_BUTTON_ID, // control ID - desc_btn_x, // location x - desc_btn_y + (n == 0 ? -2 : 2) * desc_btn_height, // location y - MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height - (Base_Form *)this, // parent - 0); // ? - - for (int k = 0; k < 3; k++) - bs[n]->Images[k] = &this->Description_Btn_Images[k]; - - // Do now draw the button until needed - bs[n]->vtable->m02_Show_Disabled ((Base_Form *)bs[n]); - } - is->cmpd.effects_btn = bs[0]; - is->cmpd.previous_btn = bs[1]; - - int tr = Civilopedia_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); - - for (int n = 0; n < ARRAY_LEN (bs); n++) - if (bs[n] != NULL) { - bs[n]->vtable->destruct ((Base_Form *)bs[n], __, 0); - free (bs[n]); - } - is->cmpd.effects_btn = is->cmpd.previous_btn = NULL; - - return tr; -} - -void -init_district_images () -{ - if (is_online_game () || is->dc_img_state != IS_UNINITED) - return; - - char art_dir[200]; - char temp_path[2*MAX_PATH]; - - is->dc_img_state = IS_INIT_FAILED; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - // For each district type - for (int dc = 0; dc < is->district_count; dc++) { - struct district_config const * cfg = &is->district_configs[dc]; - int variant_count = cfg->img_path_count; - if (variant_count <= 0) - continue; - - int era_count = cfg->vary_img_by_era ? 4 : 1; - int column_count = cfg->img_column_count; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - - // For each cultural variant - for (int variant_i = 0; variant_i < variant_count; variant_i++) { - if (cfg->img_paths[variant_i] == NULL) - continue; - - // Read PCX file - snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", cfg->img_paths[variant_i]); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - - if (pcx.JGL.Image == NULL) { - - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load district images from %s", temp_path); - pop_up_in_game_error (ss); - - (*p_OutputDebugStringA) ("[C3X] Failed to load districts sprite sheet.\n"); - for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) - for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) - for (int era_i = 0; era_i < 4; era_i++) { - for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { - Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - } - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - // For each era - for (int era_i = 0; era_i < era_count; era_i++) { - - // For each column in the image (variations on the district image for that era) - for (int col_i = 0; col_i < column_count; col_i++) { - Sprite_construct (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i]); - - int x = sprite_width * col_i, - y = sprite_height * era_i; - Sprite_slice_pcx (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i], __, &pcx, x, y, sprite_width, sprite_height, 1, 1); - } - } - - pcx.vtable->clear_JGL (&pcx); - } - } - // Load abandoned district images (land + maritime) - get_mod_art_path ("Districts/1200/Abandoned.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - - if (pcx.JGL.Image == NULL) { - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load abandoned district images from %s", temp_path); - pop_up_in_game_error (ss); - for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) - for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) - for (int era_i = 0; era_i < 4; era_i++) { - for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { - Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - } - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - Sprite_construct (&is->abandoned_district_img); - Sprite_slice_pcx (&is->abandoned_district_img, __, &pcx, 0, 0, 128, 64, 1, 1); - - Sprite_construct (&is->abandoned_maritime_district_img); - Sprite_slice_pcx (&is->abandoned_maritime_district_img, __, &pcx, 128, 0, 128, 64, 1, 1); - pcx.vtable->clear_JGL (&pcx); - - // Load wonder district images (dynamically per wonder) - if (is->current_config.enable_wonder_districts) { - char const * last_img_path = NULL; - PCX_Image wpcx; - PCX_Image_construct (&wpcx); - bool pcx_loaded = false; - - for (int wi = 0; wi < is->wonder_district_count; wi++) { - struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; - char const * img_path = cfg->img_path; - if (img_path == NULL) - img_path = "Wonders.pcx"; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - - // Load new image file if different from previous - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - - snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - PCX_Image_read_file (&wpcx, __, temp_path, NULL, 0, 0x100, 2); - - if (wpcx.JGL.Image == NULL) { - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load wonder district images from %s", temp_path); - pop_up_in_game_error (ss); - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; - - Sprite_construct (&set->img); - int x = sprite_width * cfg->img_column; - int y = sprite_height * cfg->img_row; - Sprite_slice_pcx (&set->img, __, &wpcx, x, y, sprite_width, sprite_height, 1, 1); - - Sprite_construct (&set->construct_img); - int cx = sprite_width * cfg->img_construct_column; - int cy = sprite_height * cfg->img_construct_row; - Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, sprite_width, sprite_height, 1, 1); - - if (cfg->enable_img_alt_dir) { - Sprite_construct (&set->alt_dir_img); - int ax = sprite_width * cfg->img_alt_dir_column; - int ay = sprite_height * cfg->img_alt_dir_row; - Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, sprite_width, sprite_height, 1, 1); - - Sprite_construct (&set->alt_dir_construct_img); - int acx = sprite_width * cfg->img_alt_dir_construct_column; - int acy = sprite_height * cfg->img_alt_dir_construct_row; - Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, sprite_width, sprite_height, 1, 1); - } - } - - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - wpcx.vtable->destruct (&wpcx, __, 0); - } - - if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { - char const * last_img_path = NULL; - PCX_Image nwpcx; - PCX_Image_construct (&nwpcx); - bool pcx_loaded = false; - - for (int ni = 0; ni < is->natural_wonder_count; ni++) { - struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[ni]; - if (cfg->name == NULL) - continue; - - char const * img_path = cfg->img_path; - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - - snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - PCX_Image_read_file (&nwpcx, __, temp_path, NULL, 0, 0x100, 2); - - if (nwpcx.JGL.Image == NULL) { - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load natural wonder images from %s", temp_path); - pop_up_in_game_error (ss); - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - Sprite_construct (&is->natural_wonder_img_sets[ni].img); - int x = 128 * cfg->img_column; - int y = 88 * cfg->img_row; - Sprite_slice_pcx (&is->natural_wonder_img_sets[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); - } - - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - nwpcx.vtable->destruct (&nwpcx, __, 0); - } - - is->dc_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -bool -tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv) -{ - Tile * center = tile_at (tile_x, tile_y); - - if ((center == NULL) || (center == p_null_tile)) return false; - int owner_id = center->Territory_OwnerID; - if (owner_id <= 0) return false; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - if (has_active_building (wai.city, i_improv)) - return true; - } - - return false; -} - -bool -wonder_requires_river (struct wonder_district_config const * cfg) -{ - unsigned int build_mask = wonder_buildable_square_type_mask (cfg); - if (build_mask == 0) - build_mask = district_default_buildable_mask (); - if ((build_mask & square_type_mask_bit (SQ_RIVER)) != 0) - return true; - if (cfg->buildable_on_rivers) - return true; - return false; -} - -Tile * -get_tile_sprite_indices (int tile_x, int tile_y, int * out_sheet_index, int * out_sprite_index) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - - if (tile != NULL && tile != p_null_tile) { - *out_sheet_index = (tile->SquareParts >> 8) & 0xFF; - *out_sprite_index = tile->SquareParts & 0xFF; - } else { - *out_sheet_index = -1; - *out_sprite_index = -1; - } - - return tile; -} - -void -align_district_with_river (Tile * tile, int * out_pixel_x, int * out_pixel_y, enum direction * out_dir) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return; - - enum direction dir = DIR_ZERO; - if (! get_primary_river_direction (tile, &dir)) - return; - - int dx, dy; - int offset = 36; - direction_to_offset (dir, &dx, &dy); - - dy = 0; - switch (dir) { - case DIR_N: dy = -offset; break; - case DIR_NE: dy = -offset/2; break; - case DIR_E: dy = 0; break; - case DIR_SE: dy = offset/2; break; - case DIR_S: dy = offset; break; - case DIR_SW: dy = offset/2; break; - case DIR_W: dy = 0; break; - case DIR_NW: dy = -offset/2; break; - default: break; - } - - if (out_pixel_x != NULL) - *out_pixel_x += dx; - if (out_pixel_y != NULL) - *out_pixel_y += dy; - if (out_dir != NULL) - *out_dir = dir; -} - -void -align_variant_and_pixel_offsets_with_coastline (Tile * tile, int * out_variant, int * out_pixel_x, int * out_pixel_y) -{ - if ((tile == NULL) || (tile == p_null_tile) || (out_variant == NULL)) - return; - - int owner_id = tile->Territory_OwnerID; - if (owner_id <= 0) - return; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return; - - int tile_x = inst->tile_x; - int tile_y = inst->tile_y; - Map * map = &p_bic_data->Map; - - City * closest_city = NULL; - int closest_dx = 0, closest_dy = 0; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - City * city = wai.city; - int ndx = city->Body.X - tile_x; - int ndy = city->Body.Y - tile_y; - - if (map->Flags & 1) { - int half_width = map->Width / 2; - if (ndx > half_width) - ndx -= map->Width; - else if (ndx < -half_width) - ndx += map->Width; - } - if (map->Flags & 2) { - int half_height = map->Height / 2; - if (ndy > half_height) - ndy -= map->Height; - else if (ndy < -half_height) - ndy += map->Height; - } - - closest_city = city; - closest_dx = ndx; - closest_dy = ndy; - break; - } - - if (closest_city == NULL) - return; - - bool city_is_directly_above_port = (closest_dx == 0) && (closest_dy == -2); - bool city_is_directly_below_port = (closest_dx == 0) && (closest_dy == 2); - bool city_is_directly_west_of_port = (closest_dx < 0) && (closest_dy == 0); - bool city_is_directly_east_of_port = (closest_dx > 0) && (closest_dy == 0); - bool city_is_directly_northeast_of_port = (closest_dx == 1) && (closest_dy == -1); - bool city_is_directly_southeast_of_port = (closest_dx == 1) && (closest_dy == 1); - bool city_is_directly_southwest_of_port = (closest_dx == -1) && (closest_dy == 1); - bool city_is_directly_northwest_of_port = (closest_dx == -1) && (closest_dy == -1); - - // Variant indices; can't use direction enum as values are slightly different - int NONE = -1; - int NW = 0; - int NE = 1; - int SE = 2; - int SW = 3; - *out_variant = NONE; - - enum direction anchor = NONE; - bool direct_diagonal = false; - - // Direct diagonals - if (city_is_directly_northeast_of_port) { *out_variant = SW; anchor = DIR_NE; direct_diagonal = true; } - else if (city_is_directly_southeast_of_port) { *out_variant = NW; anchor = DIR_SE; direct_diagonal = true; } - else if (city_is_directly_southwest_of_port) { *out_variant = NE; anchor = DIR_SW; direct_diagonal = true; } - else if (city_is_directly_northwest_of_port) { *out_variant = SE; anchor = DIR_NW; direct_diagonal = true; } - - // City either in a direct cardinal direction or not adjacent, check relative directions - else { - bool city_is_west_of_port = (closest_dx < 0); - bool city_is_east_of_port = (closest_dx > 0); - bool city_is_north_of_port = (closest_dy < 0); - bool city_is_south_of_port = (closest_dy > 0); - bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, true); - bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, true); - bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); - bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); - bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); - bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, true); - bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, true); - bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, true); - - if (city_is_directly_above_port) { - if (northwest_tile_is_land && ! tile_is_land (owner_id, tile_x + 1, tile_y + 1, true)) { - *out_variant = SE; anchor = DIR_NW; - } else if (northeast_tile_is_land && ! tile_is_land (owner_id, tile_x - 1, tile_y + 1, true)) { - *out_variant = SW; anchor = DIR_NE; - } else { - *out_variant = SW; anchor = DIR_NE; - *out_pixel_x -= 4; *out_pixel_y -= 4; - } - } else if (city_is_directly_below_port) { - if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else { - *out_variant = NE; anchor = DIR_SW; - *out_pixel_x += 4; *out_pixel_y += 4; - } - } else if (city_is_directly_west_of_port) { - if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else { - *out_variant = SE; anchor = DIR_NW; - *out_pixel_x -= 30; *out_pixel_y += 24; - } - } else if (city_is_directly_east_of_port) { - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else { - *out_variant = SW; anchor = DIR_NE; - *out_pixel_x += 30; *out_pixel_y -= 24; - } - } else if (city_is_north_of_port && city_is_west_of_port) { - if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - } else if (city_is_north_of_port && city_is_east_of_port) { - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - } else if (city_is_south_of_port && city_is_east_of_port) { - if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - } else if (city_is_south_of_port && city_is_west_of_port) { - if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - } - - // No ideal direction, pick based on any owner land tiles around port - if (*out_variant == NONE) { - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } - else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } - else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } - else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } - } - - // Same civ doesn't own any adjacent land tiles, pick based on *any* land tiles - if (*out_variant == NONE) { - bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); - bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); - bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); - bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); - bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); - bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); - bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); - bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } - else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } - else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } - else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } - else { *out_variant = SW; anchor = DIR_NE; } // Somehow no land tiles at all? Default to NE - } - } - - Tile * anchor_tile; - int anchor_sheet_index, anchor_sprite_index; - switch (anchor) { - case DIR_N: anchor_tile = get_tile_sprite_indices (tile_x, tile_y - 2, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_NE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_E: anchor_tile = get_tile_sprite_indices (tile_x + 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_SE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_S: anchor_tile = get_tile_sprite_indices (tile_x, tile_y + 2, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_SW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_W: anchor_tile = get_tile_sprite_indices (tile_x - 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_NW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; - default: anchor_sheet_index = -1; anchor_sprite_index = -1; break; - } - - bool anchor_is_hill = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Hills; - bool anchor_is_mountain = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Mountains; - - // Determine general pixel offsets based on direction & anchor - if (*out_variant == SW && anchor == DIR_NE) { *out_pixel_x -= 0; *out_pixel_y += 6; } - else if (*out_variant == SE && anchor == DIR_NW) { *out_pixel_x -= 2; *out_pixel_y += 6; } - else if (*out_variant == NW && anchor == DIR_SE) { *out_pixel_x -= 0; *out_pixel_y -= 2; } - else if (*out_variant == SW && anchor == DIR_N) { *out_pixel_x -= 56; *out_pixel_y -= 26; } - else if (*out_variant == SW && anchor == DIR_E) { *out_pixel_x += 36; *out_pixel_y += 18; } - else if (*out_variant == NE && anchor == DIR_S) { *out_pixel_x += 70; *out_pixel_y += 30; } - else if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 14; } - - // Handle edge cases. Tedious, but looks quite a bit better so worth it - if (! (anchor_is_hill || anchor_is_mountain) && ! direct_diagonal) { - if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 20; } - - // Sheet 0 - if (anchor_sheet_index == 0) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 32; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 32; } - - if ((*out_variant == NE || *out_variant == NW) && anchor == DIR_S && anchor_sprite_index == 26) { *out_pixel_x -= 4; *out_pixel_y += 30; } - else if (*out_variant == NE && anchor == DIR_SW && anchor_sprite_index == 20) { *out_pixel_x -= 2; *out_pixel_y += 4; } - - if (*out_variant == SW && (anchor_sprite_index == 0 || anchor_sprite_index == 4 || anchor_sprite_index == 10 || anchor_sprite_index == 1)) { *out_pixel_x +=2; *out_pixel_y -= 8; } - else if (*out_variant == SW && anchor == DIR_N && (anchor_sprite_index == 6)) { *out_pixel_x -= 6; *out_pixel_y -= 8; } - else if (*out_variant == SE && anchor == DIR_W && (anchor_sprite_index == 18)) { *out_pixel_x += 6; *out_pixel_y += 4; } - else if (*out_variant == NE && anchor == DIR_SW && (anchor_sprite_index == 51)) { *out_pixel_x += 20; *out_pixel_y -= 20; } - else if (*out_variant == SW && anchor == DIR_NE && (anchor_sprite_index == 0)) { *out_pixel_x -= 4; *out_pixel_y += 4; } - else if (*out_variant == NW && anchor == DIR_SE && (anchor_sprite_index == 44)) { *out_pixel_x -= 8; *out_pixel_y -= 12; } - } - // Sheet 1 - else if (anchor_sheet_index == 1) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 10; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 10; } - - if (*out_variant == SW && (anchor_sprite_index == 7 || anchor_sprite_index == 17 || anchor_sprite_index == 16)) { *out_pixel_x +=10; *out_pixel_y -= 8; } - } - // Sheet 3 - else if (anchor_sheet_index == 2) { - if (*out_variant == SW && (anchor_sprite_index == 6)) { *out_pixel_x +=2; *out_pixel_y -= 8; } - } - // Sheet 3 - else if (anchor_sheet_index == 3) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 16; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 16; } - - if (*out_variant == SW && (anchor_sprite_index == 43 || anchor_sprite_index == 40)) { *out_pixel_x +=6; *out_pixel_y -= 12; } - else if (*out_variant == SW && (anchor_sprite_index == 35 || anchor_sprite_index == 39)) { *out_pixel_x +=6; *out_pixel_y -= 12; } - else if (*out_variant == SE && (anchor_sprite_index == 50)) { *out_pixel_x -=6; *out_pixel_y -= 12; } - else if (*out_variant == SE && (anchor_sprite_index == 26)) { *out_pixel_x += 50; *out_pixel_y -= 2; } - } - // Sheet 4 - else if (anchor_sheet_index == 4) { - if (*out_variant == SW && (anchor_sprite_index == 71)) { *out_pixel_x +=2; *out_pixel_y -= 8; } - } - // Sheet 5 - else if (anchor_sheet_index == 5) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 18; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 18; } - - if ((*out_variant == SW || *out_variant == SE) && anchor_sprite_index == 18) { *out_pixel_y -= 10; } - else if (*out_variant == SW && anchor_sprite_index == 73) { *out_pixel_x -=4; *out_pixel_y -= 10; } - else if (*out_variant == NW && anchor == DIR_SE && anchor_sprite_index == 42) { *out_pixel_y -= 8; } - else if ((*out_variant == NW || *out_variant == SW) && anchor_sprite_index == 6) { *out_pixel_x += 12; *out_pixel_y -= 6; } - else if ((*out_variant == SW) && anchor_sprite_index == 16) { *out_pixel_x -=8; *out_pixel_y -= 10; } - } - } - else if (direct_diagonal && *out_variant == SW && anchor == DIR_NE) { *out_pixel_x -=8; *out_pixel_y -= 8; } - else if (direct_diagonal && *out_variant == SE && anchor == DIR_NW) { *out_pixel_x -=8; *out_pixel_y -= 8; } - else if (direct_diagonal && *out_variant == NW && anchor == DIR_SE) { *out_pixel_x +=6; *out_pixel_y += 6; } - else if (direct_diagonal && *out_variant == NE && anchor == DIR_SW) { *out_pixel_x +=6; *out_pixel_y += 6; } -} - -bool -wonder_should_use_alternative_direction_image (int tile_x, int tile_y, int owner_id, struct wonder_district_config const * cfg) -{ - if (owner_id <= 0) - return false; - - // We only care about the nearest same-civ city in the work area around the tile. - // Assumes the base wonder art (img_row/column) faces west and the alt art faces east. - // To "face away" from the nearest city, we pick the alt art when that city lies to the east. - Tile * center = is->current_render_tile; - if ((center == NULL) || (center == p_null_tile)) - return false; - - // If on a river and the wonder allows river alignment, make sure we face the river instead - bool allow_river = wonder_requires_river (cfg); - if (allow_river) { - enum direction river_dir = DIR_ZERO; - if (get_primary_river_direction (center, &river_dir)) { - int dx, dy; - - if (direction_to_offset (river_dir, &dx, &dy)) { - // I'm not completely sure of the logic here, but this seems to match the vanilla behavior - // in terms of having the wonder face the general direction of the river flow - if (dx == 2) - return false; - - return dx > 0; - } - } - } - - // Else face away from the nearest same-civ city - Map * map = &p_bic_data->Map; - int best_dist = INT_MAX; - int best_dx = 0; - int city_dx = 0; - int city_dy = 0; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - City * city = wai.city; - if ((city == NULL) || (city->Body.CivID != owner_id)) - continue; - - int dx = city->Body.X - tile_x; - int dy = city->Body.Y - tile_y; - - if (map->Flags & 1) { - int half_width = map->Width >> 1; - if (dx > half_width) - dx -= map->Width; - else if (dx < -half_width) - dx += map->Width; - } - if (map->Flags & 2) { - int half_height = map->Height >> 1; - if (dy > half_height) - dy -= map->Height; - else if (dy < -half_height) - dy += map->Height; - } - - int dist = int_abs (dx) + int_abs (dy); - // Pick the closest city; if tied, favor the one with a clearer east/west offset so we know which way to face. - if ((dist < best_dist) || - ((dist == best_dist) && ((int_abs (dx) < int_abs (best_dx)) || (best_dx == 0)))) { - best_dist = dist; - best_dx = dx; - city_dx = city->Body.X; - city_dy = city->Body.Y; - } - } - - bool city_is_directly_above_port = city_dx == tile_x && city_dy == tile_y - 2; - bool city_is_directly_below_port = city_dx == tile_x && city_dy == tile_y + 2; - - if (city_is_directly_above_port || city_is_directly_below_port) { - bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); - bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); - bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); - - if (northeast_tile_is_land || east_tile_is_land || southeast_tile_is_land) - return true; - } - - if ((best_dist == INT_MAX) || (best_dx == 0)) - return false; - - return best_dx > 0; -} - -void -draw_district_on_map_or_canvas(Sprite * sprite, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (is->tile_info_open) { - PCX_Image * canvas = (PCX_Image *)map_renderer; - patch_Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, NULL); - return; - } - - patch_Sprite_draw_on_map (sprite, __, map_renderer, pixel_x, pixel_y, 1, 1, (p_bic_data->is_zoomed_out != false) + 1, 0); -} - -int -get_energy_grid_image_index (int tile_x, int tile_y) -{ - struct district_infos * info = &is->district_infos[ENERGY_GRID_DISTRICT_ID]; - for (int i = 0; i < info->dependent_building_count; i++) { - // Zero is "no building"; Buildings start from index one - int column_index = i + 1; - int building_id = info->dependent_building_ids[i]; - if (tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) - return column_index; - } - - return 0; -} - -int -get_bridge_image_index (Tile * tile, int tile_x, int tile_y) -{ - int SW_NE = 0; - int NW_SE = 1; - int N_S = 2; - int W_E = 3; - - if ((tile->vtable->m42_Get_Overlays (tile, __, 0) & TILE_FLAG_RAILROAD) != 0) { - SW_NE += 4; - NW_SE += 4; - N_S += 4; - W_E += 4; - } - - bool bridge_n = tile_has_district_at (tile_x, tile_y - 2, BRIDGE_DISTRICT_ID); - bool bridge_s = tile_has_district_at (tile_x, tile_y + 2, BRIDGE_DISTRICT_ID); - bool bridge_w = tile_has_district_at (tile_x - 2, tile_y, BRIDGE_DISTRICT_ID); - bool bridge_e = tile_has_district_at (tile_x + 2, tile_y, BRIDGE_DISTRICT_ID); - bool bridge_ne = tile_has_district_at (tile_x + 1, tile_y - 1, BRIDGE_DISTRICT_ID); - bool bridge_nw = tile_has_district_at (tile_x - 1, tile_y - 1, BRIDGE_DISTRICT_ID); - bool bridge_se = tile_has_district_at (tile_x + 1, tile_y + 1, BRIDGE_DISTRICT_ID); - bool bridge_sw = tile_has_district_at (tile_x - 1, tile_y + 1, BRIDGE_DISTRICT_ID); - - if (bridge_n || bridge_s || bridge_w || bridge_e || bridge_ne || bridge_nw || bridge_se || bridge_sw) { - int ns_count = (bridge_n ? 1 : 0) + (bridge_s ? 1 : 0); - int we_count = (bridge_w ? 1 : 0) + (bridge_e ? 1 : 0); - int swne_count = (bridge_sw ? 1 : 0) + (bridge_ne ? 1 : 0); - int nwse_count = (bridge_nw ? 1 : 0) + (bridge_se ? 1 : 0); - - if (swne_count == 2) return SW_NE; - if (nwse_count == 2) return NW_SE; - if (ns_count == 2) return N_S; - if (we_count == 2) return W_E; - - if (bridge_ne || bridge_sw) return SW_NE; - if (bridge_nw || bridge_se) return NW_SE; - if (bridge_n || bridge_s) return N_S; - if (bridge_w || bridge_e) return W_E; - } - - int owner_id = tile->Territory_OwnerID; - bool north_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); - bool south_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); - bool west_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); - bool east_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); - bool ne_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); - bool nw_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); - bool se_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); - bool sw_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); - - bool north_link = north_land || bridge_n; - bool south_link = south_land || bridge_s; - bool west_link = west_land || bridge_w; - bool east_link = east_land || bridge_e; - bool ne_link = ne_land || bridge_ne; - bool nw_link = nw_land || bridge_nw; - bool se_link = se_land || bridge_se; - bool sw_link = sw_land || bridge_sw; - - if (sw_link && ne_link) return SW_NE; - if (nw_link && se_link) return NW_SE; - if (north_link && south_link) return N_S; - if (west_link && east_link) return W_E; - - if (ne_link || sw_link) return SW_NE; - if (nw_link || se_link) return NW_SE; - if (north_link || south_link) return N_S; - if (west_link || east_link) return W_E; - - return SW_NE; -} - -void -get_bridge_directions (Tile * tile, int tile_x, int tile_y, int * out_dir1, int * out_dir2) -{ - int dir1 = -1; - int dir2 = -1; - int index = get_bridge_image_index (tile, tile_x, tile_y); - - switch (index) { - case 0: dir1 = DIR_SW; dir2 = DIR_NE; break; - case 1: dir1 = DIR_NW; dir2 = DIR_SE; break; - case 2: dir1 = DIR_N; dir2 = DIR_S; break; - case 3: dir1 = DIR_W; dir2 = DIR_E; break; - default: break; - } - - *out_dir1 = dir1; - *out_dir2 = dir2; -} - -void -get_canal_directions (Tile * tile, int tile_x, int tile_y, bool out_water_dirs[9], int * out_dir1, int * out_dir2) -{ - bool canal_at_n = tile_has_district_at (tile_x, tile_y - 2, CANAL_DISTRICT_ID); - bool canal_at_s = tile_has_district_at (tile_x, tile_y + 2, CANAL_DISTRICT_ID); - bool canal_at_w = tile_has_district_at (tile_x - 2, tile_y, CANAL_DISTRICT_ID); - bool canal_at_e = tile_has_district_at (tile_x + 2, tile_y, CANAL_DISTRICT_ID); - bool canal_at_ne = tile_has_district_at (tile_x + 1, tile_y - 1, CANAL_DISTRICT_ID); - bool canal_at_nw = tile_has_district_at (tile_x - 1, tile_y - 1, CANAL_DISTRICT_ID); - bool canal_at_se = tile_has_district_at (tile_x + 1, tile_y + 1, CANAL_DISTRICT_ID); - bool canal_at_sw = tile_has_district_at (tile_x - 1, tile_y + 1, CANAL_DISTRICT_ID); - bool water_n = tile_is_water (tile_x, tile_y - 2); - bool water_s = tile_is_water (tile_x, tile_y + 2); - bool water_w = tile_is_water (tile_x - 2, tile_y); - bool water_e = tile_is_water (tile_x + 2, tile_y); - bool water_ne = tile_is_water (tile_x + 1, tile_y - 1); - bool water_nw = tile_is_water (tile_x - 1, tile_y - 1); - bool water_se = tile_is_water (tile_x + 1, tile_y + 1); - bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); - bool canal_or_water_n = canal_at_n || water_n; - bool canal_or_water_s = canal_at_s || water_s; - bool canal_or_water_w = canal_at_w || water_w; - bool canal_or_water_e = canal_at_e || water_e; - bool canal_or_water_ne = canal_at_ne || water_ne; - bool canal_or_water_nw = canal_at_nw || water_nw; - bool canal_or_water_se = canal_at_se || water_se; - bool canal_or_water_sw = canal_at_sw || water_sw; - - bool canal_dirs[9] = { - false, canal_at_ne, canal_at_e, canal_at_se, - canal_at_s, canal_at_sw, canal_at_w, canal_at_nw, canal_at_n - }; - bool water_dirs[9] = { - false, water_ne, water_e, water_se, - water_s, water_sw, water_w, water_nw, water_n - }; - bool available_dirs[9] = { - false, canal_or_water_ne, canal_or_water_e, canal_or_water_se, - canal_or_water_s, canal_or_water_sw, canal_or_water_w, canal_or_water_nw, canal_or_water_n - }; - - // Avoid acute angles (adjacent directions) that look cramped. - int disallowed_pairs[][2] = { - { DIR_N, DIR_NE }, { DIR_NE, DIR_E }, { DIR_E, DIR_SE }, { DIR_SE, DIR_S }, - { DIR_S, DIR_SW }, { DIR_SW, DIR_W }, { DIR_W, DIR_NW }, { DIR_NW, DIR_N } - }; - int disallowed_pair_count = sizeof(disallowed_pairs) / sizeof(disallowed_pairs[0]); - int pref_dirs[8] = { DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_N, DIR_E, DIR_S, DIR_W }; - - int dir1 = -1; - int dir2 = -1; - - bool has_canal_dir = canal_dirs[DIR_N] || canal_dirs[DIR_NE] || canal_dirs[DIR_E] || canal_dirs[DIR_SE] || - canal_dirs[DIR_S] || canal_dirs[DIR_SW] || canal_dirs[DIR_W] || canal_dirs[DIR_NW]; - - if (has_canal_dir) { - for (int i = 0; i < 8 && dir1 == -1; i++) { - int d = pref_dirs[i]; - if (canal_dirs[d]) - dir1 = d; - } - } else { - for (int i = 0; i < 8 && dir1 == -1; i++) { - int d = pref_dirs[i]; - if (available_dirs[d]) - dir1 = d; - } - } - - if (dir1 >= 0) { - for (int pass = 0; pass < 2 && dir2 == -1; pass++) { - bool * dirs = (pass == 0) ? canal_dirs : available_dirs; - for (int i = 0; i < 8; i++) { - int d = pref_dirs[i]; - if (d == dir1 || ! dirs[d]) - continue; - bool pair_is_too_close = false; - for (int k = 0; k < disallowed_pair_count; k++) { - if ((dir1 == disallowed_pairs[k][0] && d == disallowed_pairs[k][1]) || - (dir1 == disallowed_pairs[k][1] && d == disallowed_pairs[k][0])) { - pair_is_too_close = true; - break; - } - } - if (pair_is_too_close) - continue; - dir2 = d; - break; - } - } - } - - int draw_dir1 = dir1; - int draw_dir2 = dir2; - if ((draw_dir1 >= 0) && (draw_dir2 >= 0)) { - int weight1 = 0; - int weight2 = 0; - - if (draw_dir1 == DIR_S) weight1 = 2; - else if ((draw_dir1 == DIR_SE) || (draw_dir1 == DIR_SW)) weight1 = 1; - else if ((draw_dir1 == DIR_NE) || (draw_dir1 == DIR_NW) || (draw_dir1 == DIR_N)) weight1 = -1; - - if (draw_dir2 == DIR_S) weight2 = 2; - else if ((draw_dir2 == DIR_SE) || (draw_dir2 == DIR_SW)) weight2 = 1; - else if ((draw_dir2 == DIR_NE) || (draw_dir2 == DIR_NW) || (draw_dir2 == DIR_N)) weight2 = -1; - - if (weight1 > weight2) { - int tmp = draw_dir1; - draw_dir1 = draw_dir2; - draw_dir2 = tmp; - } - } - - // Manual overrides - overall algorithm works pretty well, but handle corner cases - if (!has_canal_dir && water_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir1 = DIR_NE; draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && water_dirs[DIR_N] && water_dirs[DIR_NE]) { draw_dir1 = DIR_N; draw_dir2 = DIR_S; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_SE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_NE] && water_dirs[DIR_N]) { draw_dir1 = DIR_N; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && water_dirs[DIR_S]) { draw_dir2 = DIR_S; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && canal_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && canal_dirs[DIR_NE] && water_dirs[DIR_S]) { draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NW && draw_dir2 == DIR_NE && canal_dirs[DIR_NW] && water_dirs[DIR_SE]) { draw_dir2 = DIR_SE; } - if (draw_dir1 == DIR_NW && draw_dir2 == DIR_S && canal_dirs[DIR_NW] && water_dirs[DIR_S]) { draw_dir2 = DIR_SE; } - - *out_dir1 = draw_dir1; - *out_dir2 = draw_dir2; - for (int i = 0; i < 9; i++) - out_water_dirs[i] = water_dirs[i]; -} - -void -draw_canal_on_map_or_canvas(Sprite * sprite, int tile_x, int tile_y, int dir, bool water_dirs[9], Map_Renderer * map_renderer, int draw_x, int draw_y) -{ - int y_offset = 9; - int x_offset = y_offset * 2; - - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y); - - // In certain cases, add an additional draw if adjacent to water so that the canal appears to extend far enough - if (dir == DIR_N && water_dirs[DIR_N]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y - y_offset); - else if (dir == DIR_NE && water_dirs[DIR_NE]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y - y_offset); - else if (dir == DIR_E && water_dirs[DIR_E]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y); - else if (dir == DIR_SE && water_dirs[DIR_SE]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y + y_offset); - else if (dir == DIR_S && water_dirs[DIR_S]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y + y_offset); - else if (dir == DIR_SW && water_dirs[DIR_SW]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y + y_offset); - else if (dir == DIR_W && water_dirs[DIR_W]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y); - else if (dir == DIR_NW && water_dirs[DIR_NW]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y - y_offset); -} - -void -draw_canal_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int era) -{ - struct district_config const * cfg = &is->district_configs[CANAL_DISTRICT_ID]; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - int offset_x = pixel_x + cfg->x_offset; - int offset_y = pixel_y + cfg->y_offset; - int dir1_draw_x = offset_x - ((sprite_width - 128) / 2); - int dir1_draw_y = offset_y - (sprite_height - 64); - int dir2_draw_x = dir1_draw_x; - int dir2_draw_y = dir1_draw_y; - - int draw_dir1 = -1; - int draw_dir2 = -1; - bool water_dirs[9] = { false, false, false, false, false, false, false, false, false }; - get_canal_directions (tile, tile_x, tile_y, water_dirs, &draw_dir1, &draw_dir2); - - // Set offsets based on directions for (literal) edge cases - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S) { dir1_draw_x += 7; dir1_draw_y -= 2; } - else if (draw_dir1 == DIR_N && draw_dir2 == DIR_W) { dir2_draw_x -= 12; } - else if (draw_dir1 == DIR_N && draw_dir2 == DIR_SE) { dir2_draw_x += 4; } - - if (draw_dir1 >= 0) { - Sprite * sprite1 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir1]; - draw_canal_on_map_or_canvas(sprite1, tile_x, tile_y, draw_dir1, water_dirs, map_renderer, dir1_draw_x, dir1_draw_y); - } - - if (draw_dir2 >= 0) { - Sprite * sprite2 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir2]; - draw_canal_on_map_or_canvas(sprite2, tile_x, tile_y, draw_dir2, water_dirs, map_renderer, dir2_draw_x, dir2_draw_y); - } -} - -void -draw_great_wall_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - bool wall_nw = tile_has_district_at (tile_x - 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); - bool wall_ne = tile_has_district_at (tile_x + 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); - bool wall_se = tile_has_district_at (tile_x + 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); - bool wall_sw = tile_has_district_at (tile_x - 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); - bool wall_s = tile_has_district_at (tile_x, tile_y + 2, GREAT_WALL_DISTRICT_ID); - bool wall_n = tile_has_district_at (tile_x, tile_y - 2, GREAT_WALL_DISTRICT_ID); - - bool water_ne = tile_is_water (tile_x - 1, tile_y - 1); - bool water_nw = tile_is_water (tile_x + 1, tile_y - 1); - bool water_w = tile_is_water (tile_x - 2, tile_y); - bool water_n = tile_is_water (tile_x, tile_y + 2); - bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); - bool water_se = tile_is_water (tile_x + 1, tile_y + 1); - - Sprite * sprites = is->district_img_sets[GREAT_WALL_DISTRICT_ID].imgs[0][0]; - Sprite * base = &sprites[0]; - - // Rotate around clockwise NW -> SW to get the perspective right - if (wall_nw) draw_district_on_map_or_canvas(&sprites[DIR_NW], map_renderer, pixel_x, pixel_y); - if (wall_ne) draw_district_on_map_or_canvas(&sprites[DIR_NE], map_renderer, pixel_x, pixel_y); - - // Base pillar - draw_district_on_map_or_canvas(base, map_renderer, pixel_x, pixel_y); - - if (wall_sw) draw_district_on_map_or_canvas(&sprites[DIR_SW], map_renderer, pixel_x, pixel_y); - if (wall_se) draw_district_on_map_or_canvas(&sprites[DIR_SE], map_renderer, pixel_x, pixel_y); -} - -void -draw_district_generated_resource_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, - int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) -{ - int base_resource = Tile_get_resource_visible_to (tile, __, visible_to_civ_id); - int district_resource = -1; - - if (inst->state == DS_COMPLETED) { - int district_id = inst->district_id; - if ((district_id >= 0) && (district_id < is->district_count)) { - struct district_config * cfg = &is->district_configs[district_id]; - if (cfg->generated_resource_id >= 0) { - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_id >= 0) && ((visible_to_civ_id < 0) || (owner_id == visible_to_civ_id))) { - int res_id = cfg->generated_resource_id; - if (district_generates_resource_for_civ (tile, inst, cfg, owner_id)) - district_resource = res_id; - } - } - } - } - - if (district_resource < 0) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; - int offset = tile_width >> 2; - int left_x = pixel_x - (offset >> 1); - int right_x = pixel_x + (offset >> 1); - - int icon_id = p_bic_data->ResourceTypes[district_resource].IconID; - Sprite * sprite = NULL; - Map_Renderer * resource_renderer = is->tile_info_open ? &p_bic_data->Map.Renderer : map_renderer; - int resource_sprite_count = 0; - if ((resource_renderer != NULL) && (resource_renderer->Resources != NULL)) - // The renderer allocates Resources as a counted heap array: the int stored just before the - // first Sprite is the number of entries loaded from resources.pcx. - resource_sprite_count = ((int *)resource_renderer->Resources)[-1]; - if ((icon_id < 0) || (icon_id >= resource_sprite_count)) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - sprite = &resource_renderer->Resources[icon_id]; - if (sprite == NULL) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - if (base_resource >= 0) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, left_x, pixel_y); - } - - int tile_height = tile_width >> 1; - int sprite_width = sprite->Width; - int sprite_height = sprite->Height; - if (sprite_width <= 0) sprite_width = sprite->Width3; - if (sprite_height <= 0) sprite_height = sprite->Height3; - int center_x = (tile_width - sprite_width) >> 1; - int center_y = (tile_height - sprite_height) >> 1; - int draw_x = (base_resource >= 0) ? right_x : pixel_x; - draw_x += center_x; - int draw_y = pixel_y + center_y; - if (is->tile_info_open) { - PCX_Image * canvas = (PCX_Image *)map_renderer; - patch_Sprite_draw (sprite, __, canvas, draw_x, draw_y, NULL); - } else { - int draw_scale = (p_bic_data->is_zoomed_out != false) + 1; - patch_Sprite_draw_on_map (sprite, __, map_renderer, draw_x, draw_y, 1, 1, draw_scale, 0); - } -} - -int -count_completed_buildings_in_district_radius (int tile_x, int tile_y, int district_id) -{ - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos * district_info = &is->district_infos[district_id]; - int completed_count = 0; - for (int i = 0; i < district_info->dependent_building_count; i++) { - int building_id = district_info->dependent_building_ids[i]; - if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) - completed_count++; - } - return completed_count; -} - -void -draw_district_on_map_or_canvas_by_buildings (Sprite * base_sprite, Map_Renderer * map_renderer, int district_id, int variant, int era, int tile_x, int tile_y, int draw_x, int draw_y) -{ - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos * district_info = &is->district_infos[district_id]; - - draw_district_on_map_or_canvas(base_sprite, map_renderer, draw_x, draw_y); - - for (int i = 0; i < district_info->dependent_building_count; i++) { - // Zero is "base texture"; Actual building column art starts from index one - int column_index = i + 1; - int building_id = district_info->dependent_building_ids[i]; - if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) { - Sprite * district_sprite = &is->district_img_sets[district_id].imgs[variant][era][column_index]; - draw_district_on_map_or_canvas(district_sprite, map_renderer, draw_x, draw_y); - } - } -} - -void -draw_district_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) -{ - int district_id = inst->district_id; - if (is->dc_img_state == IS_UNINITED) - init_district_images (); - - if (is->dc_img_state != IS_OK) - return; - - // Natural Wonder - if (district_id == NATURAL_WONDER_DISTRICT_ID) { - if (! is->current_config.enable_natural_wonders) - return; - - int natural_id = inst->natural_wonder_info.natural_wonder_id; - if ((natural_id >= 0) && (natural_id < is->natural_wonder_count)) { - Sprite * nsprite = &is->natural_wonder_img_sets[natural_id].img; - int y_offset = 88 - 64; // Height of wonder img minus height of tile - int draw_y = pixel_y - y_offset; - - draw_district_on_map_or_canvas(nsprite, map_renderer, pixel_x, draw_y); - } - return; - } - - // Districts - if (is->current_config.enable_districts) { - if (district_id < 0 || district_id >= is->district_count) return; - bool completed = district_is_complete (tile, district_id); - - if (! completed) - return; - - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos * district_info = &is->district_infos[district_id]; - int territory_owner_id = tile->Territory_OwnerID; - int variant = 0; - int era = 0; - int culture = 0; - int buildings = 0; - int draw_pixel_x = pixel_x; - int draw_pixel_y = pixel_y; - enum direction river_dir = DIR_ZERO; - - // If in a territory, use owner's culture/era - if (territory_owner_id > 0) { - Leader * leader = &leaders[territory_owner_id]; - culture = p_bic_data->Races[leader->RaceID].CultureGroupID; - if (cfg->vary_img_by_culture) - variant = culture; - if (cfg->vary_img_by_era) - era = leader->Era; - if (cfg->align_to_coast) - align_variant_and_pixel_offsets_with_coastline (tile, &variant, &draw_pixel_x, &draw_pixel_y); - - // Else render abandoned if not a Wonder, Natural Wonder, Bridge, or Canal - } else if (district_id != WONDER_DISTRICT_ID && district_id != NATURAL_WONDER_DISTRICT_ID && district_id != BRIDGE_DISTRICT_ID && district_id != CANAL_DISTRICT_ID) { - Sprite * abandoned_sprite = &is->abandoned_district_img; - if (tile->vtable->m35_Check_Is_Water (tile) && is->abandoned_maritime_district_img.vtable != NULL) - abandoned_sprite = &is->abandoned_maritime_district_img; - if (abandoned_sprite->vtable != NULL) { - draw_district_on_map_or_canvas(abandoned_sprite, map_renderer, draw_pixel_x + cfg->x_offset, draw_pixel_y + cfg->y_offset); - } - return; - } - - // If out of a territory (and not abandoned) but builder is known, use builder's era & culture - if (territory_owner_id < 0 && inst->built_by_civ_id >= 0) { - Leader * builder = &leaders[inst->built_by_civ_id]; - culture = p_bic_data->Races[builder->RaceID].CultureGroupID; - if (cfg->vary_img_by_culture) - variant = culture; - if (cfg->vary_img_by_era) - era = builder->Era; - } - - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - int offset_x = draw_pixel_x + cfg->x_offset; - int offset_y = draw_pixel_y + cfg->y_offset; - int draw_x = offset_x - ((sprite_width - 128) / 2); - int draw_y = offset_y - (sprite_height - 64); - Sprite (*sprites)[MAX_DISTRICT_ERA_COUNT][MAX_DISTRICT_COLUMN_COUNT] = is->district_img_sets[district_id].imgs; - - // Render - switch (district_id) { - case WONDER_DISTRICT_ID: - { - if (! is->current_config.enable_wonder_districts) - return; - - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info == NULL) - return; - - int construct_windex = -1; - Sprite * wsprite = NULL; - - struct wonder_district_config * wcfg = NULL; - struct wonder_district_image_set * set = NULL; - - // Completed - if (info->state == WDS_COMPLETED) { - int windex = info->wonder_index; - if ((windex < 0) || (windex >= is->wonder_district_count)) - return; - wcfg = &is->wonder_district_configs[windex]; - set = &is->wonder_district_img_sets[windex]; - // Under construction - } else if (wonder_district_tile_under_construction (tile, tile_x, tile_y, &construct_windex) && (construct_windex >= 0)) { - if (construct_windex >= is->wonder_district_count) - return; - wcfg = &is->wonder_district_configs[construct_windex]; - set = &is->wonder_district_img_sets[construct_windex]; - // Unused - } else { - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - - if (wonder_requires_river(wcfg)) - align_district_with_river (tile, &draw_pixel_x, &draw_pixel_y, &river_dir); - - int wonder_width = (wcfg->custom_width > 0) ? wcfg->custom_width : 128; - int wonder_height = (wcfg->custom_height > 0) ? wcfg->custom_height : 64; - int wonder_offset_x = draw_pixel_x + cfg->x_offset; - int wonder_offset_y = draw_pixel_y + cfg->y_offset; - int wonder_draw_x = wonder_offset_x - ((wonder_width - 128) / 2); - int wonder_draw_y = wonder_offset_y - (wonder_height - 64); - - bool use_alt_dir = wcfg->enable_img_alt_dir && wonder_should_use_alternative_direction_image (tile_x, tile_y, territory_owner_id, wcfg); - if (info->state == WDS_COMPLETED) - wsprite = (use_alt_dir && (set->alt_dir_img.vtable != NULL)) ? &set->alt_dir_img : &set->img; - else - wsprite = (use_alt_dir && (set->alt_dir_construct_img.vtable != NULL)) ? &set->alt_dir_construct_img : &set->construct_img; - - draw_district_on_map_or_canvas(wsprite, map_renderer, wonder_draw_x, wonder_draw_y); - return; - } - case NEIGHBORHOOD_DISTRICT_ID: - { - if (! is->current_config.enable_neighborhood_districts) - return; - - unsigned v = (unsigned)tile_x * 0x9E3779B1u + (unsigned)tile_y * 0x85EBCA6Bu; - v ^= v >> 16; - v *= 0x7FEB352Du; - v ^= v >> 15; - v *= 0x846CA68Bu; - v ^= v >> 16; - buildings = clamp(0, 3, (int)(v & 3u)); /* final 0..3 */ - variant = culture; - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - case DISTRIBUTION_HUB_DISTRICT_ID: - if (! is->current_config.enable_distribution_hub_districts) - return; - - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - case ENERGY_GRID_DISTRICT_ID: - { - if (! is->current_config.enable_energy_grid_districts) - return; - - buildings = get_energy_grid_image_index (tile_x, tile_y); - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - case BRIDGE_DISTRICT_ID: - { - if (! is->current_config.enable_bridge_districts) - return; - - buildings = get_bridge_image_index (tile, tile_x, tile_y); - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - case CANAL_DISTRICT_ID: - { - if (! is->current_config.enable_canal_districts) - return; - - draw_canal_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y, era); - return; - } - case GREAT_WALL_DISTRICT_ID: - { - if (! is->current_config.enable_great_wall_districts) - return; - - draw_great_wall_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - default: - { - // Draw by counting number of completed buildings in radius - if (cfg->render_strategy == DRS_BY_COUNT) { - buildings = count_completed_buildings_in_district_radius (tile_x, tile_y, district_id); - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - // Draw by checking each building individually and layering images - else if (cfg->render_strategy == DRS_BY_BUILDING) { - Sprite * base_sprite = &is->district_img_sets[district_id].imgs[variant][era][0]; - draw_district_on_map_or_canvas_by_buildings(base_sprite, map_renderer, district_id, variant, era, tile_x, tile_y, draw_x, draw_y); - return; - } - } - } - } - - Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Map_Renderer_m12_Draw_Tile_Buildings(Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { - Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - Tile * tile = is->current_render_tile; - if (is->tile_info_open) - tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if ((tile == NULL) || (tile == p_null_tile)) - return; - - struct district_instance * inst = is->current_render_tile_district; - if (is->tile_info_open) - inst = get_district_instance (tile); - if (inst == NULL) { - Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - // Draw resources first if needed - if (is->district_configs[inst->district_id].draw_over_resources) - draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); - - draw_district_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); -} - -void __fastcall -patch_Map_Renderer_m09_Draw_Tile_Resources (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (! is->current_config.enable_districts) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - Tile * tile = is->current_render_tile; - if (is->tile_info_open) - tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if ((tile == NULL) || (tile == p_null_tile)) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - struct district_instance * inst = is->current_render_tile_district; - if (is->tile_info_open) - inst = get_district_instance (tile); - if (inst == NULL) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - // Resources that should be drawn below district are already drawn, skip in that case - if (is->district_configs[inst->district_id].draw_over_resources) - return; - - draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); -} - -void __fastcall -patch_Map_Renderer_m11_Draw_Tile_Irrigation (Map_Renderer *this, int edx, int visible_to_civ, int tile_x, int tile_y, int param_4, int param_5, int param_6) -{ - if (! is->current_config.enable_districts) { - Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); - return; - } - - struct district_instance * inst = is->current_render_tile_district; - if (inst == NULL) { - Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); - return; - } - - // If it has a completed district that serves as pseudo-irrigation source, suppress drawing irrigation - if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (is->current_render_tile, inst->district_id)) - return; - - Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); -} - -bool __fastcall -patch_Tile_has_city_or_district (Tile * this) -{ - bool has_city = Tile_has_city (this); - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - return has_city || (get_district_instance (this) != NULL); - } - return has_city; -} - -int __fastcall -patch_Tile_check_water_for_navigator_cell_coloring (Tile * this) -{ - if (! is->current_config.show_territory_colors_on_water_tiles_in_minimap) - return this->vtable->m35_Check_Is_Water (this); - else - return 0; -} - -bool -is_skippable_popup (char * text_key) -{ - char * skippable_keys[] = {"SUMMARY_END_GOLDEN_AGE", "SUMMARY_END_SCIENCE_AGE", "SUMMARY_NEW_SMALL_WONDER", // unimportant domestic things - "WONDERPRODUCE", // another civ completed a wonder - "MAKEPEACE", "MUTUALPROTECTIONPACT", "MILITARYALLIANCE", "SUMMARY_DECLARE_WAR", // diplo events not involving the player - "TRADEEMBARGOENDS", // embargo vs player ends - "SUMMARY_CIV_DESTROYED_BY_CIV", "SUMMARY_CIV_DESTROYED", // foreign civs destroyed not by player - "LOSTGOOD", // 'We lost our supply of ...!' - "TRADEEMBARGO", "MILITARYALLIANCEWARONUS", "MILITARYALLIANCEAGAINSTUS", // trade embargo or alliance vs player - "SUMMARY_TRAVELERS_REPORT"}; // another civs starts a wonder - - for (int n = 0; n < ARRAY_LEN (skippable_keys); n++) - if (strcmp (text_key, skippable_keys[n]) == 0) - return true; - return false; -} - -int __fastcall -patch_PopupForm_impl_begin_showing_popup (PopupForm * this) -{ - if (is_online_game () || - (! is->current_config.convert_some_popups_into_online_mp_messages) || - (! is_skippable_popup (this->text_key))) - return PopupForm_impl_begin_showing_popup (this); - - else { - unsigned saved_prefs = *p_preferences; - int saved_flags = this->field_1BF0[0xE4]; - - *p_preferences |= P_SHOW_FEWER_MP_POPUPS; - this->field_1BF0[0xE4] |= 0x4000; - int tr = PopupForm_impl_begin_showing_popup (this); - - *(bool *)(p_main_screen_form->animator.field_18E4 + 10) = true; // Set what must be a dirty flag - Animator_update (&p_main_screen_form->animator); // Make sure message appears - - this->field_1BF0[0xE4] = saved_flags; - *p_preferences = saved_prefs; - - return tr; - } -} - -bool __stdcall -patch_is_online_game_for_show_popup () -{ - return is->current_config.convert_some_popups_into_online_mp_messages ? true : is_online_game (); -} - -bool -ai_move_district_worker (Unit * worker, struct district_worker_record * rec) -{ - if ((worker == NULL) || (rec == NULL)) - return false; - - char ss[200]; - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d assigned to build district\n", worker->Body.ID); - (*p_OutputDebugStringA) (ss); - - // Check the original request city made for district - struct pending_district_request * req = rec->pending_req; - if ((req == NULL) || - (req->assigned_worker_id != worker->Body.ID) || - (req->target_x < 0) || (req->target_y < 0)) - return false; - - int district_id = req->district_id; - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d moving to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); - (*p_OutputDebugStringA) (ss); - - City * request_city = get_city_ptr (req->city_id); - if (request_city == NULL) { - clear_tracked_worker_assignment (rec); - remove_pending_district_request (req); - return false; - } - req->city = request_city; - struct district_config * cfg = &is->district_configs[district_id]; - Tile * target_tile = tile_at (req->target_x, req->target_y); - if ((target_tile == NULL) || (target_tile == p_null_tile) || - (target_tile->vtable->m38_Get_Territory_OwnerID (target_tile) != worker->Body.CivID) || - (! city_radius_contains_tile (request_city, req->target_x, req->target_y))) { - clear_city_district_request (request_city, req->district_id); - return false; - } - - // If the worker has arrived - if ((worker->Body.X == req->target_x) && (worker->Body.Y == req->target_y)) { - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d arrived at (%d,%d) to build district\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - Tile * tile = tile_at (worker->Body.X, worker->Body.Y); - struct district_instance * inst = get_district_instance (tile); - bool do_replacement = false; - - // If there is a completed district here already - if ((inst != NULL) && district_is_complete (tile, inst->district_id)) { - int existing_district_id = inst->district_id; - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d found existing district ID %d at (%d,%d)\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - if (existing_district_id == req->district_id) { - clear_city_district_request (request_city, req->district_id); - clear_tracked_worker_assignment (rec); - return false; - } - - // Allow replacement of unused wonder districts - if (existing_district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = &inst->wonder_info; - if (info->state == WDS_UNUSED) - do_replacement = true; - } else if (district_is_obsolete_for_civ (existing_district_id, request_city->Body.CivID)) { - do_replacement = true; - } else { - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d cannot replace existing district ID %d at (%d,%d), cancelling request\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - clear_city_district_request (request_city, req->district_id); - return false; - } - - if (!do_replacement) { - return false; // Nothing left to do here - } - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for duplicate districts near city at (%d,%d)\n", request_city->Body.X, request_city->Body.Y); - (*p_OutputDebugStringA) (ss); - - // One final check: do we still need the district? Check for any dupes nearby - if (req->district_id != DISTRIBUTION_HUB_DISTRICT_ID && req->district_id != NEIGHBORHOOD_DISTRICT_ID) { - FOR_DISTRICTS_AROUND (wai, request_city->Body.X, request_city->Body.Y, false) { - if (wai.tile == tile) - continue; - - if (wai.district_inst->district_id == req->district_id) { - snprintf (ss, sizeof ss, "ai_move_district_worker: Found duplicate district ID %d near city at (%d,%d), cancelling request\n", req->district_id, request_city->Body.X, request_city->Body.Y); - (*p_OutputDebugStringA) (ss); - clear_city_district_request (request_city, req->district_id); - return false; - } - } - } - - // Need to make sure distro hubs get roads. If this will be one, build the road first to be sure - if (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID) { - bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); - if (! has_road && ! cfg->auto_add_road) { - Unit_set_state(worker, __, UnitState_Build_Road); - worker->Body.Job_ID = WJ_Build_Road; - return true; - } - } - - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); - bool district_buildable_here = district_is_buildable_on_tile (&is->district_configs[req->district_id], tile); - - // Remove any existing improvements - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); - if (do_replacement) { - remove_district_instance (tile); - handle_district_removed (tile, req->district_id, worker->Body.X, worker->Body.Y, false); - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for craters or pollution at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - if (tile->vtable->m21_Check_Crates (tile, __, 0) || tile->vtable->m20_Check_Pollution (tile, __, 0)) { - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d clearing craters or pollution at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - Unit_set_state(worker, __, UnitState_Clear_Damage); - worker->Body.Job_ID = WJ_Clean_Pollution; - return true; - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for forest or wetlands at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - // Clear any forest/wetlands - if (! district_buildable_here && base_type == SQ_Forest) { - Unit_set_state(worker, __, UnitState_Clear_Forest); - worker->Body.Job_ID = WJ_Clean_Forest; - return true; - } else if (! district_buildable_here && ((base_type == SQ_Jungle) || (base_type == SQ_Swamp))) { - Unit_set_state(worker, __, UnitState_Clear_Wetlands); - worker->Body.Job_ID = WJ_Clear_Swamp; - return true; - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d starting construction of district at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - // Clear any existing improvements (irrigation and mines) - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); - - // Start construction of district - inst = ensure_district_instance (tile, req->district_id, req->target_x, req->target_y); - inst->built_by_civ_id = worker->Body.CivID; - Unit_set_state(worker, __, UnitState_Build_Mines); - worker->Body.Job_ID = WJ_Build_Mines; // Build district - return true; - - // Else if the worker needs to be sent - } else { - if ((worker->Body.UnitState != UnitState_Go_To) || - (worker->Body.path_dest_x != req->target_x) || - (worker->Body.path_dest_y != req->target_y)) { - int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, - worker->Body.X, worker->Body.Y, req->target_x, req->target_y, - worker, worker->Body.CivID, 0x41, NULL); - if (path_result > 0) { - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d path set to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); - (*p_OutputDebugStringA) (ss); - - Unit_set_escortee (worker, __, -1); - Unit_set_state (worker, __, UnitState_Go_To); - worker->Body.path_dest_x = req->target_x; - worker->Body.path_dest_y = req->target_y; - } else { - clear_tracked_worker_assignment (rec); - return false; - } - } - } - return false; -} - -bool -ai_worker_try_tile_improvement_district (Unit * worker) -{ - if (! is->current_config.enable_districts || worker == NULL) return false; - if (! is_worker (worker)) return false; - if (worker->Body.Auto_CityID < 0) return false; - - City * city = get_city_ptr (worker->Body.Auto_CityID); - if (city == NULL) return false; - if (city->Body.CivID != worker->Body.CivID) return false; - - int civ_id = worker->Body.CivID; - int tile_x = worker->Body.X; - int tile_y = worker->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (tile->CityID >= 0) return false; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; - if (! city_radius_contains_tile (city, tile_x, tile_y)) return false; - if (get_district_instance (tile) != NULL) return false; - - // Evaluate whether the best improvement here is irrigation, mines, or a district, using heuristics based on city needs - int food_weight = (city->Body.FoodIncome < city->Body.FoodRequired) ? 3 : 1; - int shield_weight = (city->Body.ProductionIncome < city->Body.Population.Size) ? 2 : 1; - int unhappy_percent = - city->Body.UnhappyNoReasonPercent + - city->Body.UnhappyCrowdedPercent + - city->Body.UnhappyWarWearinessPercent + - city->Body.UnhappyAgresssionPercent + - city->Body.UnhappyPropagandaPercent + - city->Body.UnhappyDraftPercent + - city->Body.UnhappyOppressionPercent + - city->Body.UnhappyThisCityImprovementsPercent + - city->Body.UnhappyOtherCityImprovementsPercent; - int happiness_weight = (unhappy_percent > 0) ? 2 : 1; - int gold_weight = 1; - int resource_boost = 5 * (food_weight + shield_weight + gold_weight + happiness_weight); - - int irrigation_score = INT_MIN; - if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Irrigate, tile_x, tile_y, 0) && - ! tile->vtable->m17_Check_Irrigation (tile, __, 0)) { - int base_type = tile->vtable->m50_Get_Square_BaseType (tile); - int bonus = p_bic_data->TileTypes[base_type].IrrigationBonus; - if (bonus < 0) - bonus = 0; - irrigation_score = bonus * food_weight; - } - - int mine_score = INT_MIN; - if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Build_Mines, tile_x, tile_y, 0) && - ! tile->vtable->m18_Check_Mines (tile, __, 0)) { - int base_type = tile->vtable->m50_Get_Square_BaseType (tile); - int bonus = p_bic_data->TileTypes[base_type].MiningBonus; - if (bonus < 0) - bonus = 0; - mine_score = bonus * shield_weight; - } - - int best_score = INT_MIN; - int best_district_id = -1; - for (int i = 0; i < is->district_count; i++) { - struct district_config const * cfg = &is->district_configs[i]; - if (cfg->ai_build_strategy != DABS_TILE_IMPROVEMENT) - continue; - if (! can_build_district_on_tile (tile, i, civ_id)) - continue; - - struct district_instance temp = {0}; - temp.district_id = i; - temp.tile_x = (short)tile_x; - temp.tile_y = (short)tile_y; - - int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; - get_effective_district_yields (&temp, cfg, &food, &shields, &gold, &science, &culture, &happiness); - - int score = food * food_weight + shields * shield_weight + gold * gold_weight; - score += (science + culture) / 2; - score += happiness * happiness_weight; - if ((cfg->generated_resource_id >= 0) && - ! patch_City_has_resource (city, __, cfg->generated_resource_id)) - score += resource_boost; - - if (score > best_score) { - best_score = score; - best_district_id = i; - } - } - - if ((best_district_id >= 0) && - (best_score >= irrigation_score) && - (best_score >= mine_score)) { - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - if (removable_flags != 0) - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); - ensure_district_instance (tile, best_district_id, tile_x, tile_y); - Unit_set_state (worker, __, UnitState_Build_Mines); - worker->Body.Job_ID = WJ_Build_Mines; - return true; - } - - return false; -} - -void __fastcall -patch_Unit_ai_move_terraformer (Unit * this) -{ - Map * map = &p_bic_data->Map; - int type_id = this->Body.UnitTypeID; - int civ_id = this->Body.CivID; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - int territory_owner = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m38_Get_Territory_OwnerID (tile) : -1; - - - if (is->current_config.enable_districts && ! is_human && is_worker (this)) { - update_tracked_worker_for_unit (this); - struct district_instance * inst = get_district_instance (tile); - - if ((territory_owner == civ_id) && - inst != NULL && inst->district_id != NATURAL_WONDER_DISTRICT_ID && - tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Coast) { - // Roads should be made after district builds. The district is complete but - // worker is still likely on the tile, so check here and build road if needed - struct district_config * cfg = &is->district_configs[inst->district_id]; - bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); - if (! has_road && ! cfg->auto_add_road) { - Unit_set_state(this, __, UnitState_Build_Road); - this->Body.Job_ID = WJ_Build_Road; - return; - } - - // Same check for railroads - bool can_build_railroad = Leader_can_do_worker_job (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y, 0); - bool has_railroad = (*tile->vtable->m23_Check_Railroads)(tile, __, 0); - if (can_build_railroad && !has_railroad && ! cfg->auto_add_railroad) { - Unit_set_state(this, __, UnitState_Build_Railroad); - this->Body.Job_ID = WJ_Build_Railroad; - return; - } - } - - struct district_worker_record * rec = get_tracked_worker_record (this); - if (rec != NULL && rec->pending_req != NULL) { - if (ai_move_district_worker (this, rec)) - return; - } - - if ((this->Body.Auto_CityID >= 0) && ai_worker_try_tile_improvement_district (this)) - return; - } - - bool pop_else_caravan; - if ((tile != NULL) && (tile != p_null_tile) && - (type_id >= 0) && (type_id < p_bic_data->UnitTypeCount) && - is_material_unit (&p_bic_data->UnitTypes[type_id], &pop_else_caravan) && - ((pop_else_caravan && is->current_config.enable_pop_unit_ai) || - ((! pop_else_caravan) && is->current_config.enable_caravan_unit_ai))) { - ai_move_material_unit (this); - return; - } - - Unit_ai_move_terraformer (this); -} - -bool __fastcall -patch_Unit_ai_can_sacrifice (Unit * this, int edx, bool requires_city) -{ - int sacrifice_action = UCV_Sacrifice & 0x0FFFFFFF; // Mask out top four category bits - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.patch_ai_can_sacrifice_without_special_ability && ((type->Special_Actions & sacrifice_action) == 0)) - return false; - else - return Unit_ai_can_sacrifice (this, __, requires_city); -} - -int __cdecl -patch_get_building_defense_bonus_at (int x, int y, int param_3) -{ - // Get base building defense bonus first - int base = get_building_defense_bonus_at (x, y, param_3); - - // If districts are disabled, return base - if (!is->current_config.enable_districts) - return base; - - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - struct district_config const * cfg = &is->district_configs[inst->district_id]; - int bonus = cfg->defense_bonus_percent; - bonus += apply_district_bonus_entries (inst, &cfg->defense_bonus_extras, inst->district_id); - return bonus; - } - - return base; -} - -void __fastcall -patch_Unit_select (Unit * this) -{ - if (is->current_config.enable_districts) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && is_worker(this) && inst->district_id >= 0 && inst->district_id <= is->district_count && - ! district_is_complete (tile, inst->district_id)) { - int district_id = inst->district_id; - PopupForm * popup = get_popup_form (); - int remaining_turns = get_worker_remaining_turns_to_complete (this, __, 0); - set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); - set_popup_int_param (1, remaining_turns); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_CANCEL_BUILD_DISTRICT", -1, 0, 0, 0); - - int sel = patch_show_popup (popup, __, 0, 0); - if (sel == 0) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, 0); - - bool other_workers_present = false; - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit != NULL) && (unit != this) && - (unit->Body.UnitState == UnitState_Build_Mines) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { - other_workers_present = true; - break; - } - } - if (! other_workers_present) { - remove_district_instance (tile); - } - } else { - return; - } - } - } - - // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - - Unit_select (this); -} - -void __fastcall -patch_City_Form_draw_food_income_icons (City_Form * this) -{ - // Call original function first - City_Form_draw_food_income_icons (this); - - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) - return; - - // Get current city - City * city = this->CurrentCity; - if (city == NULL) - return; - - // Calculate standard district food bonus - int standard_district_food = 0; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int district_id = wai.district_inst->district_id; - int food_bonus = 0; - get_effective_district_yields (wai.district_inst, &is->district_configs[district_id], &food_bonus, NULL, NULL, NULL, NULL, NULL); - standard_district_food += food_bonus; - } - - // Get distribution hub food bonus - int distribution_hub_food = 0; - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) - get_distribution_hub_yields_for_city (city, &distribution_hub_food, NULL); - - // Total district food - int total_district_food = standard_district_food + distribution_hub_food; - if (total_district_food <= 0) - return; - - // Lazy load icons - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { - if (is->distribution_hub_icons_img_state == IS_UNINITED) - init_distribution_hub_icons (); - if (is->distribution_hub_icons_img_state != IS_OK) - return; - } - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - if (is->dc_icons_img_state != IS_OK) - return; - - int food_income = city->Body.FoodIncome; - int food_required = city->Body.FoodRequired; - - // Calculate how standard district food icons are distributed - int standard_food_eaten = 0; - int standard_food_surplus = 0; - if (standard_district_food > 0) { - if (standard_district_food >= food_income) { - standard_food_surplus = food_income; - standard_food_eaten = standard_district_food - food_income; - } else { - standard_food_surplus = standard_district_food; - standard_food_eaten = 0; - } - } - - // Calculate how distribution hub food icons are distributed - int hub_food_eaten = 0; - int hub_food_surplus = 0; - int remaining_income = food_income - standard_food_surplus; - if (distribution_hub_food > 0) { - if (distribution_hub_food >= remaining_income) { - hub_food_surplus = remaining_income; - hub_food_eaten = distribution_hub_food - remaining_income; - } else { - hub_food_surplus = distribution_hub_food; - hub_food_eaten = 0; - } - } - - // Draw eaten district food icons (left side, from right to left) - int total_eaten = standard_food_eaten + hub_food_eaten; - if (total_eaten > 0) { - Sprite * base_eaten_sprite = &(this->City_Icons_Images).Icon_07; - int eaten_sprite_width = base_eaten_sprite->Width; - int eaten_sprite_height = base_eaten_sprite->Height; - struct tagRECT * eaten_rect = &this->Food_Consumption_Rect; - int eaten_rect_width = eaten_rect->right - eaten_rect->left; - - int eaten_spacing = eaten_sprite_width; - if ((food_required > 1) && (food_required * eaten_sprite_width - eaten_rect_width != 0) && - (eaten_rect_width <= food_required * eaten_sprite_width)) { - eaten_spacing = (eaten_rect_width - eaten_sprite_width) / (food_required - 1); - if (eaten_spacing < 1) - eaten_spacing = 1; - else if (eaten_spacing > eaten_sprite_width) - eaten_spacing = eaten_sprite_width; - } - - int eaten_x_offset = eaten_spacing * (food_required - 1); - // Draw standard district eaten first - for (int i = 0; i < standard_food_eaten && i < food_required; i++) { - int x = eaten_rect->left + eaten_x_offset; - int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - - (eaten_sprite_height >> 1)); - Sprite_draw (&is->district_food_eaten_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - eaten_x_offset -= eaten_spacing; - } - // Draw distribution hub eaten - for (int i = 0; i < hub_food_eaten && eaten_x_offset >= 0; i++) { - int x = eaten_rect->left + eaten_x_offset; - int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - - (eaten_sprite_height >> 1)); - Sprite_draw (&is->distribution_hub_eaten_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - eaten_x_offset -= eaten_spacing; - } - } - - // Draw surplus district food icons (right side, from right to left) - int total_surplus = standard_food_surplus + hub_food_surplus; - if (total_surplus > 0) { - Sprite * base_surplus_sprite = &(this->City_Icons_Images).Icon_06; - int surplus_sprite_width = base_surplus_sprite->Width; - int surplus_sprite_height = base_surplus_sprite->Height; - struct tagRECT * surplus_rect = &this->Food_Storage_Rect; - int surplus_rect_width = surplus_rect->right - surplus_rect->left; - - int surplus_spacing = surplus_sprite_width; - if ((food_income > 1) && (food_income * surplus_sprite_width - surplus_rect_width != 0) && - (surplus_rect_width <= food_income * surplus_sprite_width)) { - surplus_spacing = (surplus_rect_width - surplus_sprite_width) / (food_income - 1); - if (surplus_spacing < 1) - surplus_spacing = 1; - else if (surplus_spacing > surplus_sprite_width) - surplus_spacing = surplus_sprite_width; - } - - int surplus_x_offset = 0; - // Draw standard district surplus first - for (int i = 0; i < standard_food_surplus && i < food_income; i++) { - int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; - int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - - (surplus_sprite_height >> 1)) - 1; - Sprite_draw (&is->district_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - surplus_x_offset += surplus_spacing; - } - // Draw distribution hub surplus - for (int i = 0; i < hub_food_surplus && surplus_x_offset < surplus_rect_width; i++) { - int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; - int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - - (surplus_sprite_height >> 1)) - 1; - Sprite_draw (&is->distribution_hub_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - surplus_x_offset += surplus_spacing; - } - } -} - -void -recompute_district_and_distribution_hub_shields_for_city_view (City * city) -{ - if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) - return; - - int city_id = city->Body.ID; - int city_x = city->Body.X; - int city_y = city->Body.Y; - - // District yields are injected through the city center tile in patch_City_calc_tile_yield_while_gathering. - // Grab the base yield (no districts) directly from the original function, then compute the - // district bonus that calculate_city_center_district_bonus will layer on afterward. - int city_center_base_shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, city_x, city_y); - int total_district_shield_bonus = 0; - calculate_city_center_district_bonus (city, NULL, &total_district_shield_bonus, NULL); - - // Distribution hub contribution is tracked separately for icon rendering. - int distribution_hub_shields = 0; - if (is->current_config.enable_distribution_hub_districts) - get_distribution_hub_yields_for_city (city, NULL, &distribution_hub_shields); - if (distribution_hub_shields < 0) - distribution_hub_shields = 0; - if (distribution_hub_shields > total_district_shield_bonus) - distribution_hub_shields = total_district_shield_bonus; - - int standard_district_shields = total_district_shield_bonus - distribution_hub_shields; - if (standard_district_shields < 0) - standard_district_shields = 0; - - // Recompute yields with districts active so ProductionIncome/Loss reflect the city view. - recompute_city_yields_with_districts (city); - int total_production_income = city->Body.ProductionIncome; - int total_production_loss = city->Body.ProductionLoss; - int total_net_shields = total_production_income + total_production_loss; // ProductionLoss stored as negative - - // Remove the district bonus from the gross tile production and recompute corruption on that base value. - int city_center_with_districts = city_center_base_shields + total_district_shield_bonus; - int gross_without_specials = city->Body.Tiles_Production - (city_center_with_districts - city_center_base_shields); - if (gross_without_specials < 0) - gross_without_specials = 0; - - int base_corruption_abs = patch_City_compute_corrupted_yield (city, __, gross_without_specials, true); - if (base_corruption_abs < 0) - base_corruption_abs = 0; - int base_production_loss = -base_corruption_abs; - - // Corruption becomes more negative as it increases. - int additional_corruption = total_production_loss - base_production_loss; - - int district_shields_remaining = standard_district_shields; - int hub_shields_remaining = distribution_hub_shields; - - if (additional_corruption < 0) { - int extra_loss = -additional_corruption; - - if (district_shields_remaining > 0) { - int from_districts = (extra_loss < district_shields_remaining) ? extra_loss : district_shields_remaining; - district_shields_remaining -= from_districts; - extra_loss -= from_districts; - } - - if ((extra_loss > 0) && (hub_shields_remaining > 0)) { - int from_hub = (extra_loss < hub_shields_remaining) ? extra_loss : hub_shields_remaining; - hub_shields_remaining -= from_hub; - extra_loss -= from_hub; - } - } - - int non_district_shields_remaining = total_net_shields - district_shields_remaining - hub_shields_remaining; - if (non_district_shields_remaining < 0) - non_district_shields_remaining = 0; - - int total_corruption = -total_production_loss; - if (total_corruption < 0) - total_corruption = 0; - int district_corruption = standard_district_shields - district_shields_remaining; - int hub_corruption = distribution_hub_shields - hub_shields_remaining; - int base_corruption = total_corruption - district_corruption - hub_corruption; - if (base_corruption < 0) - base_corruption = 0; - - is->non_district_shield_icons_remaining = non_district_shields_remaining; - is->district_shield_icons_remaining = district_shields_remaining; - is->distribution_hub_shield_icons_remaining = hub_shields_remaining; - - is->corruption_shield_icons_remaining = base_corruption; - is->district_corruption_icons_remaining = district_corruption; - is->distribution_hub_corruption_icons_remaining = hub_corruption; -} - -void __fastcall -patch_City_draw_production_income_icons (City * this, int edx, int canvas, int * rect_ptr) -{ - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { - City_draw_production_income_icons (this, __, canvas, rect_ptr); - return; - } - - recompute_district_and_distribution_hub_shields_for_city_view (this); - City_draw_production_income_icons (this, __, canvas, rect_ptr); - - is->corruption_shield_icons_remaining = 0; - is->district_corruption_icons_remaining = 0; - is->distribution_hub_corruption_icons_remaining = 0; - - is->non_district_shield_icons_remaining = 0; - is->district_shield_icons_remaining = 0; - is->distribution_hub_shield_icons_remaining = 0; -} - -int __fastcall -patch_Sprite_draw_production_income_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - if (is->distribution_hub_icons_img_state == IS_UNINITED) - init_distribution_hub_icons (); - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - - if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && is->dc_icons_img_state == IS_OK) { - Sprite to_draw = *this; - if (is->corruption_shield_icons_remaining > 0 || - is->district_corruption_icons_remaining > 0 || - is->distribution_hub_corruption_icons_remaining > 0) { - - if (is->corruption_shield_icons_remaining > 0) { - is->corruption_shield_icons_remaining--; - } else if (is->district_corruption_icons_remaining > 0) { - to_draw = is->district_corruption_icon; - is->district_corruption_icons_remaining--; - } else if (is->distribution_hub_icons_img_state == IS_OK) { - to_draw = is->distribution_hub_corruption_icon; - is->distribution_hub_corruption_icons_remaining--; - } - } - else if (is->non_district_shield_icons_remaining > 0 || - is->district_shield_icons_remaining > 0 || - is->distribution_hub_shield_icons_remaining > 0) { - - if (is->non_district_shield_icons_remaining > 0) { - is->non_district_shield_icons_remaining--; - } else if (is->district_shield_icons_remaining > 0) { - to_draw = is->district_shield_icon; - is->district_shield_icons_remaining--; - } else if (is->distribution_hub_icons_img_state == IS_OK) { - to_draw = is->distribution_hub_shield_icon; - is->distribution_hub_shield_icons_remaining--; - } - - } - return Sprite_draw (&to_draw, __, canvas, pixel_x, pixel_y, color_table); - } - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -bool -district_tile_needs_defense (Tile * tile, int tile_x, int tile_y, struct district_instance * inst, int civ_id, int work_radius) -{ - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (inst == NULL) return false; - - int district_id = inst->district_id; - struct district_config const * cfg = &is->district_configs[district_id]; - if (! district_is_complete (tile, district_id)) return false; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; - - // Check if already has enough defenders (2 for aerodromes, distribution hubs, destroyable completed wonders) - int defender_count = count_units_at (tile_x, tile_y, UF_DEFENDER_VIS_TO_A_OF_CLASS_B, civ_id, 0, -1); - int max_defenders = - (district_id == AERODROME_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID || - (cfg->defense_bonus_percent > 0 && district_id != NEIGHBORHOOD_DISTRICT_ID) || - (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed)) - ? 2 : 1; - if (defender_count >= max_defenders) - return false; - - // Distribution hubs always need defense - if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) - return true; - - // Wonder districts need defense if under construction or completed (not unused) - if (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed) { - enum wonder_district_state state = inst->wonder_info.state; - if (state == WDS_UNDER_CONSTRUCTION || state == WDS_COMPLETED) - return true; - // Unused wonder districts don't need defense - return false; - } - - return any_enemies_near (&leaders[civ_id], tile_x, tile_y, -1, work_radius); -} - -int -compute_turns_required_for_path (Unit * unit, int path_length) -{ - if (path_length < 1) - return 0; - - int max_mp = patch_Unit_get_max_move_points (unit); - if (max_mp <= 0) - return 9999; - - int moves_used_this_turn = max_mp - unit->Body.Moves; - moves_used_this_turn = not_below (0, moves_used_this_turn); - moves_used_this_turn = not_above (moves_used_this_turn, 9999); - - int remaining_mp = path_length - moves_used_this_turn; - if (remaining_mp < 0) - remaining_mp = 0; - - return (max_mp - 1 + remaining_mp) / max_mp + 1; -} - -void -maybe_update_best_district_target (Unit * unit, - int civ_id, - int max_distance, - int unit_x, - int unit_y, - int tile_x, - int tile_y, - int base_score, - int * best_score, - int * best_x, - int * best_y, - int * best_path_length, - int * evaluated_paths, - int max_path_checks) -{ - if (*evaluated_paths >= max_path_checks) - return; - - int path_length; - int path_result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, tile_x, tile_y, - unit, civ_id, 0x81, &path_length); - *evaluated_paths += 1; - if (path_result <= 0) - return; - - if (max_distance > 0) { - int turns = compute_turns_required_for_path (unit, path_length); - if (turns > max_distance) - return; - } - - int score = base_score - path_length; - if ((score > *best_score) || ((score == *best_score) && (path_length < *best_path_length))) { - *best_score = score; - *best_x = tile_x; - *best_y = tile_y; - *best_path_length = path_length; - } -} - -// Patch seek_colony to actively search for undefended districts -int __fastcall -patch_Unit_seek_colony (Unit * this, int edx, bool for_own_defense, int max_distance) -{ - // Only intercept if defending own assets and districts are enabled - if (!for_own_defense || - !is->current_config.enable_districts || - !is->current_config.ai_defends_districts) - return Unit_seek_colony (this, __, for_own_defense, max_distance); - - int civ_id = this->Body.CivID; - int unit_x = this->Body.X; - int unit_y = this->Body.Y; - - Tile * current_tile = tile_at (unit_x, unit_y); - if ((current_tile == NULL) || (current_tile == p_null_tile)) - return Unit_seek_colony (this, __, for_own_defense, max_distance); - - int continent_id = current_tile->vtable->m46_Get_ContinentID (current_tile); - - const int search_radius = 20; - const int max_path_checks = 64; - const int wonder_base_score = 1000; - const int regular_base_score = 500; - - int best_x = -1; - int best_y = -1; - int best_score = INT_MIN; - int best_path_length = INT_MAX; - int evaluated_paths = 0; - - bool abort_search = false; - - if ((is->current_config.enable_wonder_districts && is->current_config.completed_wonder_districts_can_be_destroyed) || - is->current_config.enable_distribution_hub_districts) { - for (int dx = -search_radius; (dx <= search_radius) && !abort_search; dx++) { - for (int dy = -search_radius; dy <= search_radius; dy++) { - if (evaluated_paths >= max_path_checks) { - abort_search = true; - break; - } - - int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); - int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); - Tile * district_tile = tile_at (target_x, target_y); - if ((district_tile == NULL) || (district_tile == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (district_tile); - if (inst == NULL) - continue; - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) - continue; - if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) - continue; - if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) - continue; - - maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, - tile_x, tile_y, wonder_base_score, - &best_score, &best_x, &best_y, - &best_path_length, &evaluated_paths, - max_path_checks); - } - } - } - - if ((best_x < 0) && (evaluated_paths < max_path_checks)) { - for (int dx = -search_radius; (dx <= search_radius) && (evaluated_paths < max_path_checks); dx++) { - for (int dy = -search_radius; dy <= search_radius; dy++) { - if (evaluated_paths >= max_path_checks) - break; - - int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); - int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); - Tile * district_tile = tile_at (target_x, target_y); - if ((district_tile == NULL) || (district_tile == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (district_tile); - if ((inst == NULL) || (inst->district_id == WONDER_DISTRICT_ID)) - continue; - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) - continue; - if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) - continue; - if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) - continue; - - maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, - tile_x, tile_y, regular_base_score, - &best_score, &best_x, &best_y, - &best_path_length, &evaluated_paths, - max_path_checks); - } - } - } - - if ((best_x >= 0) && (best_y >= 0)) { - int result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, best_x, best_y, - this, civ_id, 0x181, NULL); - return result; - } - - return Unit_seek_colony (this, __, for_own_defense, max_distance); -} - -// Patch has_colony to make units stay on districts, only patches within Unit::ai_move_defensive_unit -bool __fastcall -patch_Tile_has_district_or_colony (Tile * this) -{ - if (is->current_config.enable_districts && - is->current_config.ai_defends_districts) { - - struct district_instance * inst = get_district_instance (this); - return (inst != NULL) && district_is_complete (this, inst->district_id); - } - - // Fallback to original has_colony logic - return Tile_has_colony (this); -} - -int __fastcall -patch_Buildings_Info_get_age_in_years_for_tourism (Buildings_Info * this, int edx, int building_index) -{ - int base = Buildings_Info_get_age_in_years (this, __, building_index); - if (is->current_config.tourism_time_scale_percent == 100) - return base; - else if (is->current_config.tourism_time_scale_percent <= 0) - return INT_MAX; - else - return (base * 100 + 50) / is->current_config.tourism_time_scale_percent; -} - -int __fastcall -patch_Sprite_draw_minimap_frame (Sprite * this, int edx, Sprite * alpha, int param_2, PCX_Image * canvas, int x, int y, int param_6) -{ - bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || - ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); - if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) - return Sprite_draw_for_hud (&is->double_size_box_left_color_pcx, __, &is->double_size_box_left_alpha_pcx, param_2, canvas, x, y, param_6); - else - return Sprite_draw_for_hud (this, __, alpha, param_2, canvas, x, y, param_6); -} - -int __fastcall -patch_City_get_turns_to_build_2_for_ai_move_leader (City * this, int edx, City_Order * order, bool param_2) -{ - // Initialize order variable to city's current build. This is not done in the base logic and can cause crashes. - City_Order current_order = { .OrderID = this->Body.Order_ID, .OrderType = this->Body.Order_Type }; - if (is->current_config.patch_crash_in_leader_unit_ai) - order = ¤t_order; - - return City_get_turns_to_build_2 (this, __, order, param_2); -} - -void __fastcall -patch_City_set_production (City * this, int edx, int order_type, int order_id, bool ask_to_confirm) -{ - City_set_production (this, __, order_type, order_id, ask_to_confirm); - - if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) - return; - - // If the human player, we need to set/unset a wonder district for this city, depending - // on what is being built. The human player wouldn't be able to choose a wonder if a wonder - // district wasn't available, so we don't need to worry about feasibility here. - // The AI uses a different mechanism to reserve wonder districts via patch_Leader_do_production_phase. - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - if (! is_human) - return; - - char ss[256]; - bool release_reservation = true; - if (this->Body.Order_Type == COT_Improvement) { - Improvement * improv = &p_bic_data->Improvements[this->Body.Order_ID]; - if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { - if (reserve_wonder_district_for_city (this, this->Body.Order_ID)) { - release_reservation = false; - } - } - } - - if (release_reservation) { - release_wonder_district_reservation (this); - } -} - -int __fastcall -patch_Tile_m71_Check_Worker_Job (Tile * this) -{ - if (is->current_config.enable_natural_wonders) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && - (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) { - return -1; // No worker job allowed on natural wonders - } - } - return Tile_m71_Check_Worker_Job (this); -} - -int __fastcall -patch_Tile_get_road_bonus (Tile * this) -{ - if (is->current_config.enable_natural_wonders) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { - return 0; - } - } - if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { - return 1; - } - } - return Tile_get_road_bonus (this); -} - -bool __fastcall -patch_Unit_has_army_ability_to_perform_unload (Unit * this, int edx, enum UnitTypeAbilities a) -{ - return is->current_config.allow_unload_from_army ? false : Unit_has_ability (this, __, a); -} - -void __fastcall -patch_Unit_disembark (Unit * this, int edx, int tile_x, int tile_y) -{ - Unit * container = get_unit_ptr (this->Body.Container_Unit); - bool unloading_from_army = is->current_config.allow_unload_from_army && container != NULL && Unit_has_ability (container, __, UTA_Army); - - // If removing a unit from an army, transfer a proportional amount of damage to the unit removed - int damage_transferred = 0; - if (unloading_from_army) { - int army_damage_percent = container->Body.Damage * 100 / Unit_get_max_hp (container), - max_damage = Unit_get_max_hp (this) - 1 - this->Body.Damage; - damage_transferred = clamp (0, max_damage, (army_damage_percent * Unit_get_max_hp (this) + 50) / 100); - } - - Unit_disembark (this, __, tile_x, tile_y); - - if (unloading_from_army) { - this->Body.Damage = not_above (Unit_get_max_hp (this) - 1, this->Body.Damage + damage_transferred); - container->Body.Damage = not_below (0, container->Body.Damage - damage_transferred); - - if (this->Body.ID == container->Body.army_top_defender_id) { - Unit * new_top_defender = NULL; - FOR_UNITS_ON (uti, tile_at (container->Body.X, container->Body.Y)) - if (uti.unit->Body.Container_Unit == container->Body.ID) { - if (new_top_defender == NULL) - new_top_defender = uti.unit; - else if (Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, uti.unit, Unit_get_defense_strength (uti.unit), new_top_defender, Unit_get_defense_strength (new_top_defender), true)) - new_top_defender = uti.unit; - } - container->Body.army_top_defender_id = (new_top_defender != NULL) ? new_top_defender->Body.ID : -1; - } - } -} - -bool __fastcall -patch_Unit_has_ability_no_load_non_army_passengers (Unit * this, int edx, enum UnitTypeAbilities army_ability) -{ - UnitType * transport_type = &p_bic_data->UnitTypes[is->can_load_transport->Body.UnitTypeID], - * passenger_type = &p_bic_data->UnitTypes[this ->Body.UnitTypeID]; - - // This call comes from Unit::can_load at the point where it's determined that the passenger (this) has transport capacity > 0 and is checking - // whether it's an army. If not, it can't be loaded. Add two exceptions here for land transports, if configured, one to allow LTs to load into - // naval units and another to allow empty LTs to load into armies. - if (is->current_config.land_transport_rules != 0) - if ((passenger_type->Unit_Class == UTC_Land) && ! Unit_has_ability (this, __, army_ability)) { // if it's a land transport - if ((is->current_config.land_transport_rules & LTR_LOAD_ONTO_BOAT) && (transport_type->Unit_Class == UTC_Sea)) - return true; - if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && - Unit_has_ability (is->can_load_transport, __, army_ability) && (Unit_count_contained_units (this) == 0)) - return true; - } - - // Similarly, allow helicopters to be loaded onto carriers if so configured - if ((is->current_config.special_helicopter_rules & SHR_ALLOW_ON_CARRIERS) && - passenger_type->Unit_Class == UTC_Air && - transport_type->Unit_Class == UTC_Sea && - Unit_has_ability (is->can_load_transport, __, UTA_Transports_Only_Aircraft)) - return true; - - return Unit_has_ability (this, __, army_ability); -} - -bool __fastcall -patch_Unit_has_ability_no_load_transport_into_army (Unit * this, int edx, enum UnitTypeAbilities army_ability) -{ - // Similar to above, here it checks if the target unit is an army and rejects the load if it is (again, already determined that the passenger - // has transport capacity). Modify this rule to return false for land transports trying to join armies if configured. We don't have to check - // that the LT is empty since that is already disallowed by the modified check above. - bool is_army = Unit_has_ability (this, __, army_ability); - if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && is_army && - (p_bic_data->UnitTypes[is->can_load_passenger->Body.UnitTypeID].Unit_Class == UTC_Land)) - return false; - - else - return is_army; -} - -bool __fastcall -patch_Fighter_unit_can_defend (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) -{ - if (cannot_defend_inside_transport (unit)) - return false; - else - return Fighter_unit_can_defend (this, __, unit, tile_x, tile_y); -} - -bool __fastcall -patch_Leader_is_enemy_unit_for_ground_aa (Leader * this, int edx, Unit * bomber) -{ - // When this function is called, the potential interceptor unit is stored in register ESI. - Unit * interceptor; - __asm__ __volatile__("mov %%esi, %0" : "=r" (interceptor)); - - Unit * container = get_unit_ptr (interceptor->Body.Container_Unit); - bool in_transport = (container != NULL) && ! Unit_has_ability (container, __, UTA_Army); - if (in_transport && - (is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Land) - return false; - else if (in_transport && - (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return false; - else if (in_transport && - is->current_config.no_land_anti_air_from_inside_naval_transport && - (p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea)) - return false; - else - return Leader_is_enemy_unit (this, __, bomber); -} - -bool __fastcall -patch_Unit_has_army_ability_for_passenger_despawn (Unit * this, int edx, enum UnitTypeAbilities army_ability) -{ - // If the unit has the army ability, the game will always despawn the passengers. Otherwise there are exceptions like land unit passengers - // won't be despawned if the transport is on a land tile. - return is->always_despawn_passengers || Unit_has_ability (this, __, army_ability); -} - -int __cdecl -patch_count_units_at_in_try_capturing (int x, int y, enum unit_filter filter, int arg_a, int arg_b, int arg_c) -{ - Tile * tile = tile_at (x, y); - - // If one of the no-defense-from-inside rules is in force, count units like the function normally would except skip units that are inside - // transports from which they can't defend. Otherwise, if those transports have 0 defense, the passengers will prevent them from being - // captured but not fight themselves, making movement onto their tile impossible. - if (tile->vtable->m35_Check_Is_Water (tile) == 0 && - ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) || (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE))) { - int tr = 0; - FOR_UNITS_ON (tai, tile) { - if ((arg_b == -1 || p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].Unit_Class == arg_b) && - (arg_a == -1 || patch_Unit_is_visible_to_civ (tai.unit, __, arg_a, 1)) && - (Unit_get_defense_strength (tai.unit) > 0) && - ! cannot_defend_inside_transport (tai.unit)) - tr++; - } - return tr; - - } else - return count_units_at (x, y, filter, arg_a, arg_b, arg_c); -} - -void __fastcall -patch_Map_generate_resources (Map * this, int edx, int secondary_seed) -{ - int const bic_tag_good = 0x444f4f47; // = 'GOOD' - int resource_type_count = this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, -1, NULL); - bool * ratios_to_clear = NULL; - int lux_percent = is->current_config.luxury_randomized_appearance_rate_percent; - int seed = (this->Seed + 0x180E3) * secondary_seed; - - // To change the randomized appearance rate for luxuries, fill in an appearance rate for any that would be randomized (rate set == 0) using - // the same process the game would to randomize the rate but with different limits. That process involves taking two random numbers from 0 to - // 25 then adding them together and to 50 to produce a random rate from 50 to 100 biased toward the middle of that range. - if (lux_percent != 100 && - (ratios_to_clear = calloc (1, resource_type_count)) != NULL) { - for (int n = 0; n < resource_type_count; n++) { - Resource_Type * res; - this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); - if (res->Class == RC_Luxury && res->AppearanceRatio == 0) { - ratios_to_clear[n] = true; - int half_lux_percent = (lux_percent * 50 + 50) / 100, - quarter_lux_percent = (lux_percent * 25 + 50) / 100; - res->AppearanceRatio = not_below (1, half_lux_percent + rand_int (&seed, __, quarter_lux_percent) + rand_int (&seed, __, quarter_lux_percent)); - } - } - } - - Map_generate_resources (this, __, secondary_seed); - - if (ratios_to_clear != NULL) { - for (int n = 0; n < resource_type_count; n++) - if (ratios_to_clear[n]) { - Resource_Type * res; - this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); - res->AppearanceRatio = 0; - } - free (ratios_to_clear); - } -} - -PassBetweenValidity __fastcall -patch_Unit_can_pass_between (Unit * this, int edx, int from_x, int from_y, int to_x, int to_y, int param_5) -{ - PassBetweenValidity base = Unit_can_pass_between (this, __, from_x, from_y, to_x, to_y, param_5); - - if (is->current_config.enable_districts) { - Tile * to = tile_at (to_x, to_y); - bool to_valid = (to != NULL) && (to != p_null_tile); - struct district_instance * to_inst = NULL; - bool to_inst_complete = false; - if (to_valid) { - to_inst = get_district_instance (to); - if (to_inst != NULL) - to_inst_complete = district_is_complete (to, to_inst->district_id); - } - if (great_wall_blocks_civ (to, this->Body.CivID)) - return PBV_GENERIC_INVALID_MOVE; - if (to_valid) { - bool impassible = false; - bool impassible_to_wheeled = false; - if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { - if (impassible) - return PBV_GENERIC_INVALID_MOVE; - if (impassible_to_wheeled && Unit_has_ability (this, __, UTA_Wheeled)) { - Tile * from = tile_at (from_x, from_y); - bool connected_by_road = (from != NULL) && (to != NULL) && - (from->vtable->m25_Check_Roads (from, __, 0) != 0) && - (to->vtable->m25_Check_Roads (to, __, 0) != 0); - if (! connected_by_road) - return PBV_REQUIRES_ROAD; - } - } - } - - if (is->current_config.workers_can_enter_coast && - base != PBV_OK && is_worker(this)) { - Tile * source = tile_at (from_x, from_y); - if (source != NULL && - source->vtable->m35_Check_Is_Water (source) && - (source->vtable->m50_Get_Square_BaseType (source) == SQ_Coast)) - return PBV_OK; - - if (to_valid && - to->vtable->m35_Check_Is_Water (to) && - (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - - // If human, okay to enter coast tile - if (is_human) - return PBV_OK; - - struct district_worker_record * rec = get_tracked_worker_record (this); - struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; - if (req != NULL) - return PBV_OK; - } - } - - if (is->current_config.enable_bridge_districts && - base != PBV_OK && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == BRIDGE_DISTRICT_ID)) - return PBV_OK; - - if (is->current_config.enable_canal_districts && - base != PBV_OK && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == CANAL_DISTRICT_ID)) - return PBV_OK; - } - - return base; -} - -Unit * __fastcall -patch_Unit_select_transport (Unit * this, int edx, int tile_x, int tile_y, bool do_show_popup) -{ - Unit * transport = Unit_select_transport (this, __, tile_x, tile_y, do_show_popup); - - if (is->current_config.enable_districts && - (transport == NULL) && (this == is->coast_walk_unit)) { - Tile * dest = tile_at (tile_x, tile_y); - if (dest != NULL) { - bool allow_move = false; - if (is->current_config.workers_can_enter_coast && is_worker (this) && - dest->vtable->m35_Check_Is_Water (dest) && - (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) - allow_move = true; - - if (! allow_move && is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land)) { - struct district_instance * inst = get_district_instance (dest); - if (inst != NULL && inst->district_id == BRIDGE_DISTRICT_ID && - district_is_complete (dest, inst->district_id)) { - allow_move = true; - } - } - - if (allow_move) { - is->coast_walk_transport_override = true; - return this; // Fake a transport so the move logic proceeds - } - } - } - - return transport; -} - -// Returns true if the given tile is a water district owned by an enemy of the unit -bool -is_enemy_maritime_district_tile (Unit * unit, Tile * tile) -{ - if ((unit == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - if (! is->current_config.enable_districts) - return false; - - if (! tile->vtable->m35_Check_Is_Water (tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner <= 0) || (owner == unit->Body.CivID)) - return false; - - Leader * leader = &leaders[unit->Body.CivID]; - return leader->At_War[owner]; -} - -// Boost pillage desirability for maritime districts -int __fastcall -patch_Unit_ai_eval_pillage_target (Unit * this, int edx, int tile_x, int tile_y) -{ - int base = Unit_ai_eval_pillage_target (this, __, tile_x, tile_y); - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if (is_enemy_maritime_district_tile (this, tile)) { - // Double the base score so districts outrank generic coast targets - base += base + 0x300; - } - - return base; -} - -// Light-weight hunt for nearby friendly ports; returns true if a path/command was issued -bool -try_path_to_friendly_port_district (Unit * unit, bool require_damaged, bool require_undefended) -{ - if ((unit == NULL) || - ! is->current_config.enable_districts || - ! is->current_config.enable_port_districts) - return false; - - if (unit->Body.Container_Unit >= 0) // Don't redirect cargo - return false; - - if (unit->Body.Moves <= 0) - return false; - - if (require_damaged && (unit->Body.Damage <= 0)) - return false; - - if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Sea) - return false; - - int sea_id = unit->vtable->get_sea_id (unit); - if (sea_id < 0) - return false; - - int best_x = -1, best_y = -1, best_path_len = INT_MAX; - const int search_radius = 10; - for (int dy = -search_radius; dy <= search_radius; dy++) { - for (int dx = -search_radius; dx <= search_radius; dx++) { - int tx = unit->Body.X + dx, ty = unit->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - if ((short)tile->vtable->m46_Get_ContinentID (tile) != sea_id) - continue; - - if (! tile_has_friendly_port_district (tile, unit->Body.CivID)) - continue; - - int occupier_id = get_tile_occupier_id (tx, ty, -1, true); - if ((occupier_id != -1) && (occupier_id != unit->Body.CivID)) - continue; - - if (require_undefended) { - bool has_friendly_sea_unit = false; - FOR_UNITS_ON (uti, tile) { - Unit * on_tile = uti.unit; - if ((on_tile == NULL) || (on_tile->Body.Container_Unit >= 0)) - continue; - if (on_tile->Body.CivID != unit->Body.CivID) - continue; - if (p_bic_data->UnitTypes[on_tile->Body.UnitTypeID].Unit_Class != UTC_Sea) - continue; - if (on_tile->Body.ID == unit->Body.ID) - continue; - has_friendly_sea_unit = true; - break; - } - if (has_friendly_sea_unit) - continue; - } - - if (! is_below_stack_limit (tile, unit->Body.CivID, UTC_Sea)) - continue; - - int path_len = 0; - int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, - tx, ty, unit, unit->Body.CivID, 0x81, &path_len); - if (path_result <= 0) - continue; - - if (path_len < best_path_len) { - best_path_len = path_len; - best_x = tx; - best_y = ty; - } - } - } - - if (unit->Body.X == best_x && unit->Body.Y == best_y) { - Unit_set_escortee (unit, __, -1); - Unit_set_state (unit, __, UnitState_Fortifying); - return true; - } - else if (best_x >= 0) { - patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, best_x, best_y, - unit, unit->Body.CivID, 0x81, NULL); - Unit_set_escortee (unit, __, -1); - Unit_set_state (unit, __, UnitState_Go_To); - unit->Body.path_dest_x = best_x; - unit->Body.path_dest_y = best_y; - return true; - } - - return false; -} - -void __fastcall -patch_Unit_ai_move_naval_power_unit (Unit * this) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - ! is->current_config.naval_units_use_port_districts_not_cities) { - Unit_ai_move_naval_power_unit (this); - return; - } - - Tile * here = tile_at (this->Body.X, this->Body.Y); - if (here == NULL) { - Unit_ai_move_naval_power_unit (this); - return; - } - - // If we're on a port and the sole unit, fortify - if (is->current_config.ai_defends_districts && - tile_has_friendly_port_district (here, this->Body.CivID) && - count_units_at (this->Body.X, this->Body.Y, UF_0, this->Body.CivID, 0, -1) == 1) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If we're already sitting on an enemy maritime district, pillage it immediately - if (this->Body.Container_Unit < 0) { - if (is_enemy_maritime_district_tile (this, here) && - patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y) && - (patch_Unit_ai_eval_pillage_target (this, __, this->Body.X, this->Body.Y) > 0)) { - patch_Unit_attack_tile (this, __, this->Body.X, this->Body.Y, false); - return; - } - } - - // If damaged and CAN heal at current location (e.g. port district), fortify to heal - if (this->Body.Damage > 0 && patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If damaged and cannot heal here, try to path to a friendly port district - if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) - return; - - Unit_ai_move_naval_power_unit (this); - return; -} - -void __fastcall -patch_Unit_ai_move_naval_transport (Unit * this) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - ! is->current_config.naval_units_use_port_districts_not_cities) { - Unit_ai_move_naval_transport (this); - return; - } - - // If damaged and CAN heal at current location (e.g. port district), fortify to heal - if ((this->Body.Damage > 0) && - patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If damaged and cannot heal here, try to path to a friendly port district - if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) - return; - - Unit_ai_move_naval_transport (this); -} - -void __fastcall -patch_Unit_ai_move_naval_missile_transport (Unit * this) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - ! is->current_config.naval_units_use_port_districts_not_cities) { - patch_Unit_ai_move_naval_missile_transport (this); - return; - } - - // If damaged and CAN heal at current location (e.g. port district), fortify to heal - if ((this->Body.Damage > 0) && - patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If damaged and cannot heal here, try to path to a friendly port district - if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) - return; - - Unit_ai_move_naval_missile_transport (this); -} - -void __fastcall -patch_Unit_ai_move_air_bombard_unit (Unit * this) -{ - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) { - Unit_ai_move_air_bombard_unit (this); - return; - } - - if (this->Body.Damage > 0) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - int best_target = 0; - int target_x = -1, target_y = -1; - int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - int grid = op_range * 2 + 1; - if (1 < grid * grid) { - for (int n = 1; n < grid * grid; n++) { - int dx, dy; - neighbor_index_to_diff (n, &dx, &dy); - int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); - int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); - if (Map_in_range (&p_bic_data->Map, __, x, y)) { - int score = Unit_ai_eval_bombard_target (this, __, x, y, 1); - if (score > best_target) { - best_target = score; - target_x = x; - target_y = y; - } - } - } - } - - int best_base_score = 0x7fffffff; - int base_x = -1, base_y = -1; - FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, - p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) - continue; - - int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 6, -1, -1); - int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); - int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); - int score = (count * 10) + ((x_dist + y_dist) >> 1); - if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) - score -= 20; - - if (score < best_base_score) { - best_base_score = score; - base_x = aerodrome_x; - base_y = aerodrome_y; - } - } - - if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { - Unit_set_escortee (this, __, -1); - Unit_rebase (this, __, base_x, base_y); - return; - } - - if ((target_x >= 0) && (target_y >= 0)) { - Unit_set_escortee (this, __, -1); - patch_Unit_bombard_tile (this, __, target_x, target_y); - return; - } - - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -void __fastcall -patch_Unit_ai_move_air_defense_unit (Unit * this) -{ - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) { - Unit_ai_move_air_defense_unit (this); - return; - } - - Unit_ai_move_air_defense_unit (this); - - Unit_set_state (this, __, 0); - if (this->Body.Damage > 0) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - int best_base_score = 0x7fffffff; - int base_x = -1, base_y = -1; - FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, - p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) - continue; - - int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 7, -1, -1); - int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); - int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); - int score = (count * 10) + ((x_dist + y_dist) >> 1); - if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) - score -= 20; - - if (score < best_base_score) { - best_base_score = score; - base_x = aerodrome_x; - base_y = aerodrome_y; - } - } - - if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { - Unit_set_escortee (this, __, -1); - Unit_rebase (this, __, base_x, base_y); - return; - } - - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Intercept); -} - -void __fastcall -patch_Unit_ai_move_air_transport (Unit * this) -{ - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) { - Unit_ai_move_air_transport (this); - return; - } - - Unit_ai_move_air_transport (this); - - if (this->Body.Damage < 1) { - if (Unit_can_airdrop (this)) { - int best_score = 0; - int best_x = -1, best_y = -1; - int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - int grid = op_range * 2 + 1; - if (1 < grid * grid) { - for (int n = 1; n < grid * grid; n++) { - int dx, dy; - neighbor_index_to_diff (n, &dx, &dy); - int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); - int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); - if (Map_in_range (&p_bic_data->Map, __, x, y)) { - int score = Unit_ai_eval_airdrop_target (this, __, x, y); - if (score > best_score) { - best_score = score; - best_x = x; - best_y = y; - } - } - } - if ((best_x >= 0) && (best_y >= 0)) { - Unit_set_escortee (this, __, -1); - Unit_airdrop (this, __, best_x, best_y); - return; - } - } - } - - int best_score = -1; - int base_x = -1, base_y = -1; - FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, - p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) - continue; - - int score = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 0, -1, -1) + - count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 1, -1, -1) + 1; - if (count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 9, -1, -1) == 0) - score *= 2; - int cont_id = aerodrome_tile->vtable->m46_Get_ContinentID (aerodrome_tile); - if ((cont_id >= 0) && (cont_id < p_bic_data->Map.Continent_Count) && - (p_bic_data->Map.Continents[cont_id].Body.TileCount > 0x15)) - score *= 2; - - if (score > best_score) { - best_score = score; - base_x = aerodrome_x; - base_y = aerodrome_y; - } - } - - if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { - Unit_set_escortee (this, __, -1); - Unit_rebase (this, __, base_x, base_y); - if (Unit_count_contained_units (this) > 0) { - patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); - } - return; - } - } - - if (Unit_count_contained_units (this) > 0) - patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); - - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -bool __fastcall -patch_Tile_has_colony_ignore_extraterritorial (Tile * tile) -{ - if (!Tile_has_colony (tile)) - return false; - - if (!is->current_config.allow_extraterritorial_colonies) - return true; - - if ((tile == NULL) || (tile == p_null_tile)) - return true; - - int tile_building_id = tile->vtable->m47_Get_Tile_BuildingID (tile); - if ((tile_building_id < 0) || (p_colonies == NULL) || (p_colonies->Items == NULL) || - (tile_building_id > p_colonies->LastIndex)) - return true; - - Tile_Building_Body * colony_body = p_colonies->Items[tile_building_id].Object; - if ((colony_body == NULL) || ((int)colony_body == offsetof (Tile_Building, Body))) - return true; - - return colony_body->OwnerID == tile->vtable->m38_Get_Territory_OwnerID (tile); -} - -int __fastcall -patch_Leader_get_attitude_toward (Leader * this, int edx, int civ_id, int param_2) -{ - int score = Leader_get_attitude_toward (this, __, civ_id, param_2); - if (!is->current_config.allow_extraterritorial_colonies) - return score; - - int penalty = is->current_config.per_extraterritorial_colony_relation_penalty; - if (penalty != 0) { - int this_civ_id = this->ID; - if ((p_colonies != NULL) && (p_colonies->Items != NULL)) { - for (int n = 0; n <= p_colonies->LastIndex; n++) { - Tile_Building_Body * colony_body = p_colonies->Items[n].Object; - if ((colony_body == NULL) || - ((int)colony_body == offsetof (Tile_Building, Body))) - continue; - - Tile * tile = tile_at (colony_body->X, colony_body->Y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != this_civ_id) - continue; - if (colony_body->OwnerID != civ_id) - continue; - score -= penalty; - } - } - } - return score; -} - -bool __fastcall -patch_Tile_m17_Check_Irrigation (Tile * this, int edx, int visible_to_civ_id) -{ - bool base = Tile_m17_Check_Irrigation (this, __, visible_to_civ_id); - if (base) - return true; - - if (! is->current_config.enable_districts) - return base; - - struct district_instance * inst = get_district_instance (this); - if (inst == NULL) - return base; - - if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (this, inst->district_id)) - return true; - - return base; -} - -int __fastcall -patch_Unit_ai_eval_bombard_target (Unit * this, int edx, int tile_x, int tile_y, int param_3) -{ - int score = Unit_ai_eval_bombard_target (this, __, tile_x, tile_y, param_3); - - if (! (is->current_config.enable_districts && - is->current_config.enable_great_wall_districts)) - return score; - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return score; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID) || (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID))) - return score; - - int obsolete_id = is->district_infos[GREAT_WALL_DISTRICT_ID].obsoleted_by_id; - if ((obsolete_id >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, obsolete_id)) - return score; - - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_id <= 0) || (owner_id == this->Body.CivID)) - return score; - if (! this->vtable->is_enemy_of_civ (this, __, owner_id, false)) - return score; - - bool has_unit_on_tile = false; - bool has_enemy_on_tile = false; - Leader * me = &leaders[this->Body.CivID]; - FOR_UNITS_ON (uti, tile) { - UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; - if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0)) { - has_unit_on_tile = true; - if (me->At_War[uti.unit->Body.CivID]) { - if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { - has_enemy_on_tile = true; - break; - } - } else - break; - } - } - - if (has_unit_on_tile && ! has_enemy_on_tile) - return score; - - // Boost score to prioritize Great Wall targets - if (score < 0x6000) - score = 0x6000; - - // Additional boost if there is no unit on it, more likely to destroy it - if (! has_enemy_on_tile) - score += 0x200; - - return score; -} - -void __fastcall -patch_Unit_heal_at_start_of_turn (Unit * this) -{ - if (is->current_config.enable_districts) { - Tile * tile = tile_at ((this->Body).X, (this->Body).Y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id) && - is->district_configs[inst->district_id].heal_units_in_one_turn) { - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (territory_owner == this->Body.CivID) { - (this->Body).Damage = 0; - return; - } - } - } - } - - Unit_heal_at_start_of_turn (this); -} - -// Makes naval AI treat enemy port districts as valid targets to path toward. -int __cdecl -patch_get_tile_occupier_id_in_Unit_ai_move_naval_power_unit (int x, int y, int pov_civ_id, bool respect_unit_invisibility) -{ - int base = get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); - if (base != -1) - return base; - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return -1; - - Tile * tile = tile_at (x, y); - if (tile == NULL || tile == p_null_tile) - return -1; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return -1; - - return (*tile->vtable->m38_Get_Territory_OwnerID) (tile); -} - -// Returns a non-zero score for enemy port district tiles so they pass the threshold check and are bombard targets -int __fastcall -patch_Fighter_eval_tile_vulnerability_in_Unit_ai_move_naval_power_unit (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) -{ - int base = Fighter_eval_tile_vulnerability (this, __, unit, tile_x, tile_y); - if (base > 0) - return base; - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if (tile == NULL || tile == p_null_tile) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return base; - - int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); - if (owner <= 0 || owner == unit->Body.CivID) - return base; - - if (! leaders[unit->Body.CivID].At_War[owner]) - return base; - - // Return a score high enough to pass threshold (iVar13 * 8 + 0x100) - // 0x300 should be sufficient for most cases - return 0x300; -} - -// Returns the territory owner for enemy port districts so the score isn't reduced and naval units move to enemy ports -// (to subsequently pillage them) -int __cdecl -patch_get_combat_occupier_in_Unit_ai_move_naval_power_unit (int tile_x, int tile_y, int civ_id, byte ignore_visibility) -{ - int base = get_combat_occupier (tile_x, tile_y, civ_id, ignore_visibility); - if (base != -1) - return base; - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if (tile == NULL || tile == p_null_tile) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return base; - - int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); - if (owner <= 0 || owner == civ_id) - return base; - - if (! leaders[civ_id].At_War[owner]) - return base; - - return owner; -} - -int __fastcall -patch_rand_int_to_enslave (void * this, int edx, int lim) -{ - // lim is 100, enslaving happens if the return value is < 33 - int r = rand_int (this, __, lim); - return is->do_not_enslave_units ? 100 : r; -} - -int __fastcall -patch_Sprite_draw_espionage_screen_target_civ_bkg (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - // Figure out which of the potential target civs we're drawing by working backwards from the Y location - int top = (p_bic_data->ScreenHeight - p_espionage_form->Image.Height) / 2; - is->espionage_form_drawing_target_index = (pixel_y - top - 0x5C) / 0x3a + p_espionage_form->field_1584; - - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -char * __fastcall -patch_Civilopedia_Article_get_name_for_esp_screen (Civilopedia_Article * this) -{ - // Ensure that we have captured a valid civ ID being drawn then, if that civ has an era-specific formal name, return that so that the - // era-specific names apply on the espionage screen. - int target_civ_id; - if (is->espionage_form_drawing_target_index >= 0 && - is->espionage_form_drawing_target_index < p_espionage_form->target_civ_id_count && - (target_civ_id = p_espionage_form->target_civ_ids[is->espionage_form_drawing_target_index]) >= 0 && - target_civ_id < 32 && - is->aliased_civ_formal_name_bits & 1<Name.S; -} - -void __fastcall -patch_Animator_play_one_shot_victory_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) -{ - if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Air && is->current_config.aircraft_victory_animation != NULL) { - struct string_slice slice = {.str = is->current_config.aircraft_victory_animation, .len = strlen (is->current_config.aircraft_victory_animation)}; - find_animation_type_by_name (&slice, true, &anim_type); - } - - Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); -} - -void -clear_selectable_units_list (Main_Screen_Form * main_screen_form, bool include_unit_objects) -{ - // This is what the base game does to clear things at the start of assemble_selectable_units - if (include_unit_objects && p_units->Units != NULL) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if (unit != NULL) - unit->Body.in_selectable_units_list = false; - } - UnitIDItem * item = main_screen_form->selectable_units.first; - while (item != NULL) { - UnitIDItem * next = item->next; - item->vtable->destruct (item, __, 1); - item = next; - } - main_screen_form->selectable_units.first = main_screen_form->selectable_units.last = NULL; - main_screen_form->selectable_units.length = 0; -} - -void __fastcall -patch_Main_Screen_Form_assemble_selectable_units (Main_Screen_Form * this) -{ - if (is->have_loaded_waiting_units) - is->have_loaded_waiting_units = false; - else - table_deinit (&is->waiting_units); - - if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) - Main_Screen_Form_assemble_selectable_units (this); - else { - clear_selectable_units_list (this, true); - this->unit_cycle_cursor = NULL; - this->completed_unit_cycle = false; - } -} - -void __fastcall -patch_Main_Screen_Form_set_selected_unit (Main_Screen_Form * this, int edx, Unit * unit, bool param_2) -{ - // To set a unit to wait, Main_Screen_Form::issue_command calls this method with unit == NULL and param_2 == false. Detect when that's - // happened and record that the unit's been set to wait so we can reimplement the wait command when replacing the base unit cycling logic. - int * p_stack = (int *)&unit; - int ret_addr = p_stack[-1]; - if (ret_addr == SET_SELECTED_UNIT_TO_ISSUE_WAIT_COMMAND_RET && unit == NULL && this->Current_Unit != NULL) { - // Give the unit a waiting level higher than the minimum among all units already set to wait. This ensures that this unit does not get - // immediately picked up again by the cycling logic unless it's the only selectable unit left. This also means that the first unit set - // to wait will be the first cycled to once all the non-waiting units have been moved (it's the only one at level 1). I consider that - // an advantage. - int min_others_waiting_level = INT_MAX; - bool any_others_waiting = false; - FOR_TABLE_ENTRIES (tei, &is->waiting_units) - if (tei.key != this->Current_Unit->Body.ID) { - any_others_waiting = true; - if (tei.value < min_others_waiting_level) - min_others_waiting_level = tei.value; - } - itable_insert (&is->waiting_units, this->Current_Unit->Body.ID, any_others_waiting ? min_others_waiting_level + 1 : 1); - } - - if (unit != NULL) { - is->last_selected_unit.initial_x = is->last_selected_unit.last_x = unit->Body.X; - is->last_selected_unit.initial_y = is->last_selected_unit.last_y = unit->Body.Y; - is->last_selected_unit.type_id = unit->Body.UnitTypeID; - is->last_selected_unit.ptr = unit; - itable_remove (&is->waiting_units, unit->Body.ID); // Clear waiting record when waiting unit is selected - } - - if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD) - clear_selectable_units_list (this, false); - - bool redraw = false; - if (is->current_config.show_ai_city_location_desirability_if_settler) { - int new_perspective = -1; - if (unit != NULL) { - int unit_type_id = unit->Body.UnitTypeID; - int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; - new_perspective = (worker_actions >= 1 && (worker_actions & (UCV_Build_City)) && !is_worker(unit)) ? p_main_screen_form->Player_CivID : -1; - } - - if (new_perspective != is->city_loc_display_perspective) { - is->city_loc_display_perspective = new_perspective; - redraw = true; - } - } - - Main_Screen_Form_set_selected_unit (this, __, unit, param_2); - - // If selecting a new unit, must insert it into the list to ensure it's actually selected. - if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && unit != NULL) { - UnitIDList_insert_before (&this->selectable_units, __, unit->Body.ID, NULL); - this->unit_cycle_cursor = this->selectable_units.first; - } - - if (redraw && ! this->is_now_loading_game) - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -Unit * __fastcall -patch_Main_Screen_Form_find_next_unit_for_cycling (Main_Screen_Form * this) -{ - if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) - return Main_Screen_Form_find_next_unit_for_cycling (this); - - else { - int least_difference = INT_MAX; - Unit * least_different_unit = NULL; - int sx = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_x : is->last_selected_unit.last_x, - sy = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_y : is->last_selected_unit.last_y; - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if (unit != NULL && unit->Body.CivID == this->Player_CivID && Unit_can_cycle_to (unit)) { - int distance = not_above (1<<15, int_abs (unit->Body.X - sx) + int_abs (unit->Body.Y - sy)); - - bool other_type, not_duplicate; { - if (is->last_selected_unit.type_id == unit->Body.UnitTypeID) { - other_type = false; - if (is->last_selected_unit.ptr != NULL) - not_duplicate = ! are_units_duplicate (&is->last_selected_unit.ptr->Body, &unit->Body, false); - else - not_duplicate = true; - } else - other_type = not_duplicate = true; - } - - int wait_level = itable_look_up_or (&is->waiting_units, unit->Body.ID, 0); - - int difference = ((int)wait_level << 20) + (distance << 2) + ((int)other_type << 1) + (int)not_duplicate; - if (difference < least_difference) { - least_difference = difference; - least_different_unit = unit; - } - } - } - this->completed_unit_cycle = least_different_unit == NULL; - return least_different_unit; - } -} - -void __fastcall -patch_City_m22 (City * this, int edx, bool param_1) -{ - int * p_stack = (int *)¶m_1; - int ret_addr = p_stack[-1]; - - City_m22 (this, __, param_1); - - // If the base game method failed to find a new thing for city to build, we've been called by the methods that complete a previous build, and - // the city is owned by the UI controller, the game will crash because there will be no default option for the build selector popup. If we're - // configured to fix that, suggest Wealth for the new build or, failing that, any buildable unit or improvement. - if ( this->Body.Order_Type == 0 - && is->current_config.patch_failure_to_find_new_city_build - && this->Body.CivID == p_main_screen_form->Player_CivID - && ( ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_1 - || ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_2 - || ret_addr == CITY_M22_TO_SPAWN_UNIT_IF_DONE_RETURN)) { - - // Search for an improvement-type order we can build. Choose Wealth if possible, otherwise just pick the first thing that can be built - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (patch_City_can_build_improvement (this, __, n, true)) { - if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { - this->Body.Order_Type = COT_Improvement; - this->Body.Order_ID = n; - break; - } else if (this->Body.Order_Type == 0) { - this->Body.Order_Type = COT_Improvement; - this->Body.Order_ID = n; - } - } - - // If we still don't have a build, pick the first buildable unit - if (this->Body.Order_Type == 0) - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) - if (patch_City_can_build_unit (this, __, n, true, 0, false)) { - this->Body.Order_Type = COT_Unit; - this->Body.Order_ID = n; - break; - } - } -} - -int __fastcall -patch_PCX_Image_process_dom_adv_turn_count_text (PCX_Image * this, int edx, char * str) -{ - if (is->current_config.reformat_turns_remaining_on_domestic_advisor_screen) { - char * start = strstr (str, p_advisor_internal_form->Labels[16].S); // Search for "turns" - if (start == NULL) - start = strstr (str, p_advisor_internal_form->Labels[17].S); // Search for "turn" - - if (start != NULL) { - *start = toupper (*start); // Upcase first letter of "turn/s" - - char s[64]; // Must be same size as "str" param, which is a 64-byte stack-allocated string - snprintf (s, sizeof s, "%.*s %s", start - str, str, start); // Reprint string with space before "Turn/s" - s[(sizeof s) - 1] = '\0'; - memcpy (str, s, sizeof s); - } - } - - return PCX_Image_process_text (this, __, str); -} - -int -compare_menu_unit_items (void const * a, void const * b) -{ - return MenuUnitItem_should_appear_after ((MenuUnitItem *)a, __, (MenuUnitItem *)b) ? 1 : -1; -} - -int __fastcall -patch_MenuUnitList_get_length_before_sorting (MenuUnitList * this) -{ - int length = MenuUnitList_get_length (this); - - if (is->current_config.patch_passengers_out_of_order_on_menu && length > 0) { - qsort (this->items, length, sizeof this->items[0], compare_menu_unit_items); - - // Fix any units not being listed immediately after the unit they're contained in - // First, loop over all units in the list, stopping at each that might contain others - for (int n = 0; n < length - 1; n++) { - Unit * container = this->items[n].unit; - if ((int)container > 1 && // original code checks if unit ptrs are NULL or equal to 1 - p_bic_data->UnitTypes[container->Body.UnitTypeID].Transport_Capacity > 0) { - - // Advance iterator "j" past the container and past any empty slots or correctly positioned units right after it - int j = n + 1; - while (j < length && ((int)this->items[j].unit <= 1 || this->items[j].unit->Body.Container_Unit == container->Body.ID)) - j++; - - // Check the rest of the list for out-of-place passengers - for (int k = j + 1; k < length; k++) { - if ((int)this->items[k].unit > 1 && this->items[k].unit->Body.Container_Unit == container->Body.ID) { - - // Move item from index "k" to index "j" and advance "j" past it - MenuUnitItem moved = this->items[k]; - memmove (&this->items[j + 1], &this->items[j], (k - j) * sizeof this->items[0]); - this->items[j] = moved; - j++; - } - } - } - } - - // The caller is checking if the length is > 0 before sorting the list. Since we've already sorted it, return 0. - return 0; - } else - return length; -} - -void __fastcall -patch_Map_finalize_params_for_scenario_map (Map * this) -{ - Map_finalize_params (this); - - enum barbarian_activity_override barb_override = is->current_config.override_barbarian_activity_level_for_scenario_maps; - if (barb_override != BAO_NONE) { - if (barb_override == BAO_RANDOM) { - LARGE_INTEGER time; - QueryPerformanceCounter (&time); - int r = this->Seed ^ time.u.LowPart; // The map seed will be the same every time so incorporate some entropy - this->World.Final_Barbarians_Activity = rand_int (&r, __, 5) - 1; - } else - this->World.Final_Barbarians_Activity = clamp (-1, 3, barb_override); - } -} - -Unit * __fastcall -patch_Unit_select_army_member_for_combat (Unit * this, int edx, int param_1, char param_2) -{ - if (is->current_config.patch_empty_army_combat_crash) { - int unit_count = 0; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - if (tile != NULL && tile != p_null_tile) { - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit != NULL) && (unit->Body.Container_Unit == this->Body.ID)) - unit_count += Unit_count_contained_units (unit) + 1; - } - } - if (unit_count == 0) - return this; - } - - return Unit_select_army_member_for_combat (this, __, param_1, param_2); -} - -int __fastcall -patch_Tile_check_water_for_canal_move_to_adjacent_tile_dest (Tile * this) -{ - if ((this != NULL) && (this != p_null_tile) && - is->current_config.enable_districts && - is->current_config.enable_canal_districts && - (is->coast_walk_unit != NULL) && - (p_bic_data->UnitTypes[is->coast_walk_unit->Body.UnitTypeID].Unit_Class == UTC_Sea)) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && - (inst->district_id == CANAL_DISTRICT_ID) && - district_is_complete (this, inst->district_id)) - return 1; - } - - return this->vtable->m35_Check_Is_Water (this); -} - -// TCC requires a main function be defined even though it's never used. +#include "stdlib.h" +#include "stdio.h" + +#include "C3X.h" + +void (WINAPI ** p_OutputDebugStringA) (char * lpOutputString) = ADDR_ADDR_OUTPUTDEBUGSTRINGA; +short (WINAPI ** p_GetAsyncKeyState) (int vKey) = ADDR_ADDR_GETASYNCKEYSTATE; +FARPROC (WINAPI ** p_GetProcAddress) (HMODULE hModule, char const * lpProcName) = ADDR_ADDR_GETPROCADDRESS; +HMODULE (WINAPI ** p_GetModuleHandleA) (char const * lpModuleName) = ADDR_ADDR_GETMODULEHANDLEA; +int (WINAPI ** p_MessageBoxA) (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) = ADDR_ADDR_MESSAGEBOXA; + +struct injected_state * is = ADDR_INJECTED_STATE; + +// To be used as placeholder second argument so that we can imitate thiscall convention with fastcall +#define __ 0 + +// Many Windows and C standard library functions have to be loaded dynamically with GetProcAddress and the addresses are stored in the injected +// state. This is covered up with macros, which is not something I would normally do, but in this case it's very useful because it means the code in +// common.c can be shared by the patcher and the injected code. +#define VirtualProtect is->VirtualProtect +#define CloseHandle is->CloseHandle +#define CreateFileA is->CreateFileA +#define GetFileSize is->GetFileSize +#define ReadFile is->ReadFile +#define LoadLibraryA is->LoadLibraryA +#define FreeLibrary is->FreeLibrary +#define MessageBoxA is->MessageBoxA +#define MultiByteToWideChar is->MultiByteToWideChar +#define WideCharToMultiByte is->WideCharToMultiByte +#define GetLastError is->GetLastError +#define QueryPerformanceCounter is->QueryPerformanceCounter +#define QueryPerformanceFrequency is->QueryPerformanceFrequency +#define GetLocalTime is->GetLocalTime +#define TransparentBlt is->TransparentBlt +#define snprintf is->snprintf +#define malloc is->malloc +#define calloc is->calloc +#define realloc is->realloc +#define free is->free +#define strtol is->strtol +#define strtof is->strtof +#define strncmp is->strncmp +#define strcmp is->strcmp +#define _stricmp is->_stricmp +#define strlen is->strlen +#define strncpy is->strncpy +#define strcpy is->strcpy +#define strdup is->strdup +#define strstr is->strstr +#define qsort is->qsort +#define memcmp is->memcmp +#define memcpy is->memcpy +#define tolower is->tolower +#define toupper is->toupper + +#include "common.c" + +#define TRADE_SCROLL_BUTTON_ID_LEFT 0x222001 +#define TRADE_SCROLL_BUTTON_ID_RIGHT 0x222002 + +// Must match size of button images in descbox.pcx +#define MOD_INFO_BUTTON_WIDTH 102 +#define MOD_INFO_BUTTON_HEIGHT 17 + +#define MOD_INFO_BUTTON_ID 0x222003 + +#define PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID 0x222004 +#define PEDIA_MULTIPAGE_PREV_BUTTON_ID 0x222005 + +#define TILE_FLAG_ROAD 0x1 +#define TILE_FLAG_RAILROAD 0x2 +#define TILE_FLAG_MINE 0x4 +#define TILE_FLAG_IRRIGATION 0x8 + +#define NEIGHBORHOOD_DISTRICT_ID 0 +#define WONDER_DISTRICT_ID 1 +#define DISTRIBUTION_HUB_DISTRICT_ID 2 +#define AERODROME_DISTRICT_ID 3 +#define NATURAL_WONDER_DISTRICT_ID 4 +#define PORT_DISTRICT_ID 5 +#define CENTRAL_RAIL_HUB_DISTRICT_ID 6 +#define ENERGY_GRID_DISTRICT_ID 7 +#define BRIDGE_DISTRICT_ID 8 +#define CANAL_DISTRICT_ID 9 +#define GREAT_WALL_DISTRICT_ID 10 + +#define MAX_DISTRICT_VARIANT_COUNT 5 +#define MAX_DISTRICT_ERA_COUNT 4 +#define MAX_DISTRICT_COLUMN_COUNT 10 + +// Max grid of tiles that an AI will evaluate a candidate bridge or canal for, +// used to limit computational complexity +#define AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES 10 + +enum { NAMED_TILE_MENU_ID = 0x90 }; + +char const * const hotseat_replay_save_path = "Saves\\Auto\\ai-move-replay-before-interturn.SAV"; +char const * const hotseat_resume_save_path = "Saves\\Auto\\ai-move-replay-resume.SAV"; + +// Need to define memmove for use by TCC when generated code for functions that return a struct +void * +memmove (void * dest, void const * src, size_t size) +{ + return is->memmove (dest, src, size); +} + +// Also need to define memset for some reason +void * +memset (void * dest, int ch, size_t count) +{ + for (size_t n = 0; n < count; n++) + ((char *)dest)[n] = ch; + return dest; +} + +// Computes num/denom randomly rounded off so that E[rand_div (x,y)] = (float)x/y +// As an example: E[rand_div (6, 5)] = 1.2, it will return 1 with 80% probability and 2 with 20% prob. +int +rand_div (int num, int denom) +{ + int q = num / denom, + r = num % denom; + return q + (rand_int (p_rand_object, __, denom) < r); +} + +bool +are_tiles_adjacent (int ax, int ay, int bx, int by) +{ + int x_dist = int_abs (ax - bx), + y_dist = int_abs (ay - by); + + // Handle edge wrapping by counting from the opposite direction if it would be shorter + if (p_bic_data->Map.Flags & 1) { // if map wraps horizontally + int width = p_bic_data->Map.Width; + if (x_dist > (width>>1)) + x_dist = width - x_dist; + } + if (p_bic_data->Map.Flags & 2) { // if map wraps vertically + int height = p_bic_data->Map.Height; + if (y_dist > (height>>1)) + y_dist = height - y_dist; + } + + return (x_dist + y_dist) == 2; +} + +int +compute_wrapped_component (int diff, int size, bool wraps) +{ + if (! wraps || (size <= 0)) + return diff; + + int half = size >> 1; + if (diff > half) + diff = size - diff; + return diff; +} + +void +compute_wrapped_deltas (int ax, int ay, int bx, int by, int * out_dx, int * out_dy) +{ + int dx = int_abs (ax - bx); + int dy = int_abs (ay - by); + bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; + bool wraps_vert = (p_bic_data->Map.Flags & 2) != 0; + dx = compute_wrapped_component (dx, p_bic_data->Map.Width, wraps_horiz); + dy = compute_wrapped_component (dy, p_bic_data->Map.Height, wraps_vert); + if (out_dx != NULL) + *out_dx = dx; + if (out_dy != NULL) + *out_dy = dy; +} + +int +compute_wrapped_manhattan_distance (int ax, int ay, int bx, int by) +{ + int dx, dy; + compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); + return dx + dy; +} + +int +compute_wrapped_chebyshev_distance (int ax, int ay, int bx, int by) +{ + int dx, dy; + compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); + return (dx > dy) ? dx : dy; +} + +bool +tile_has_resource (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + int resource_type = tile->vtable->m39_Get_Resource_Type (tile); + return (resource_type >= 0) && (resource_type < p_bic_data->ResourceTypeCount); +} + +City * +get_city_ptr (int id) +{ + if ((p_cities->Cities != NULL) && + (id >= 0) && (id <= p_cities->LastIndex)) { + City_Body * body = p_cities->Cities[id].City; + if (body != NULL) { + City * city = (City *)((char *)body - offsetof (City, Body)); + if (city != NULL) + return city; + } + } + return NULL; +} + +// Forward declarations for unit counter system (defined after their dependencies) +enum recognizable_parse_result parse_unit_counter_group (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_group); +enum recognizable_parse_result parse_counter_rule (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_rule); + +// Declare various functions needed for districts and hard to untangle and reorder here +void __fastcall patch_City_recompute_yields_and_happiness (City * this); +void __fastcall patch_Map_build_trade_network (Map * this); +bool __fastcall patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value); +bool __fastcall patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y); +bool __fastcall patch_City_has_resource (City * this, int edx, int resource_id); +bool __fastcall patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2); +char __fastcall patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing); +void __fastcall patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7); +bool can_build_district_on_tile (Tile * tile, int district_id, int civ_id); +bool city_can_build_district (City * city, int district_id); +bool leader_can_build_district (Leader * leader, int district_id); +bool wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id); +bool find_civ_trait_id_by_name (struct string_slice const * name, int * out_id); +bool find_civ_culture_id_by_name (struct string_slice const * name, int * out_id); +Tile * find_tile_for_district (City * city, int district_id, int * out_x, int * out_y); +struct district_instance * get_district_instance (Tile * tile); +struct named_tile_entry * get_named_tile_entry (Tile * tile); +bool city_has_required_district (City * city, int district_id); +bool district_is_complete (Tile * tile, int district_id); +bool city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id); +void clear_city_district_request (City * city, int district_id); +void set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y); +bool city_radius_contains_tile (City * city, int tile_x, int tile_y); +void on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y); +bool ai_move_district_worker (Unit * worker, struct district_worker_record * rec); +bool has_active_building (City * city, int improv_id); +bool tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv); +void recompute_distribution_hub_totals (); +void get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y); +void wrap_tile_coords (Map * map, int * x, int * y); +int count_neighborhoods_in_city_radius (City * city); +int count_utilized_neighborhoods_in_city_radius (City * city); +char * copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes); +bool city_has_resource_r (City * city, int resource_id, int max_generated_resource_id); + +struct pause_for_popup { + bool done; // Set to true to exit for loop + bool redundant; // If true, this pause would overlap a previous one and so should not be counted + long long ts_before; +}; + +struct pause_for_popup +pfp_init () +{ + struct pause_for_popup tr; + tr.done = false; + tr.redundant = is->paused_for_popup; + if (! tr.redundant) { + is->paused_for_popup = true; + QueryPerformanceCounter ((LARGE_INTEGER *)&tr.ts_before); + } + return tr; +} + +void +pfp_finish (struct pause_for_popup * pfp) +{ + if ((! pfp->redundant) && (! pfp->done)) { + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + is->time_spent_paused_during_popup += ts_after - pfp->ts_before; + is->paused_for_popup = false; + } + pfp->done = true; +} + +#define WITH_PAUSE_FOR_POPUP for (struct pause_for_popup pfp = pfp_init (); ! pfp.done; pfp_finish (&pfp)) + +int __fastcall +patch_show_popup (void * this, int edx, int param_1, int param_2) +{ + int tr; + WITH_PAUSE_FOR_POPUP { + is->show_popup_was_called = 1; + tr = show_popup (this, __, param_1, param_2); + } + return tr; +} + +void +pop_up_in_game_error (char const * msg) +{ + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); + PopupForm_add_text (popup, __, (char *)msg, false); + patch_show_popup (popup, __, 0, 0); +} + +void +memoize (int val) +{ + if (is->memo_len < is->memo_capacity) + is->memo[is->memo_len++] = val; + else { + int new_capacity = not_below (100, 2 * is->memo_capacity); + int * new_memo = malloc (new_capacity * sizeof is->memo[0]); + if (new_memo != NULL) { + for (int n = 0; n < is->memo_len; n++) + new_memo[n] = is->memo[n]; + free (is->memo); + is->memo = new_memo; + is->memo_capacity = new_capacity; + is->memo[is->memo_len++] = val; + } + } + +} + +void +clear_memo () +{ + is->memo_len = 0; +} + +// The maximum possible cultural neighbor index. We don't bother dealing with indices beyond this b/c it's the last tile in the seventh ring. Also +// equals one less than the tile count up to & inc. the seventh ring b/c of the zeroth tile. +#define MAX_CULTURAL_NI 192 + +// Number of workable tiles including the city center for each workable radius +unsigned char const workable_tile_counts[8] = {1, 9, 21, 37, 61, 89, 137, 193}; + +char const cultural_ni_to_diffs[(MAX_CULTURAL_NI + 1) * 2] = +{ + 0, 0, + +// first ring + 1, -1, 2, 0, 1, 1, 0, 2, -1, 1, -2, 0, -1, -1, + 0, -2, + +// second ring + 1, -3, 2, -2, 3, -1, 3, 1, 2, 2, 1, 3, -1, 3, -2, 2, + -3, 1, -3, -1, -2, -2, -1, -3, + +// third ring + 0, -4, 4, 0, 0, 4, -4, 0, 2, -4, 3, -3, 4, -2, 4, 2, + 3, 3, 2, 4, -2, 4, -3, 3, -4, 2, -4, -2, -3, -3, -2, -4, + +// fourth ring + 1, -5, 5, -1, 5, 1, 1, 5, -1, 5, -5, 1, -5, -1, -1, -5, + 0, -6, 6, 0, 0, 6, -6, 0, 3, -5, 4, -4, 5, -3, 5, 3, + 4, 4, 3, 5, -3, 5, -4, 4, -5, 3, -5, -3, -4, -4, -3, -5, + +// fifth ring + 1, -7, 2, -6, 6, -2, 7, -1, 7, 1, 6, 2, 2, 6, 1, 7, + -1, 7, -2, 6, -6, 2, -7, 1, -7, -1, -6, -2, -2, -6, -1, -7, + 4, -6, 5, -5, 6, -4, 6, 4, 5, 5, 4, 6, -4, 6, -5, 5, + -6, 4, -6, -4, -5, -5, -4, -6, + +// sixth ring + 0, -8, 8, 0, 0, 8, -8, 0, 1, -9, 2, -8, 3, -7, 7, -3, + 8, -2, 9, -1, 9, 1, 8, 2, 7, 3, 3, 7, 2, 8, 1, 9, + -1, 9, -2, 8, -3, 7, -7, 3, -8, 2, -9, 1, -9, -1, -8, -2, + -7, -3, -3, -7, -2, -8, -1, -9, 4, -8, 5, -7, 6, -6, 7, -5, + 8, -4, 8, 4, 7, 5, 6, 6, 5, 7, 4, 8, -4, 8, -5, 7, + -6, 6, -7, 5, -8, 4, -8, -4, -7, -5, -6, -6, -5, -7, -4, -8, + +// seventh ring + 0, -10, 10, 0, 0, 10, -10, 0, 1, -11, 2, -10, 3, -9, 9, -3, + 10, -2, 11, -1, 11, 1, 10, 2, 9, 3, 3, 9, 2, 10, 1, 11, + -1, 11, -2, 10, -3, 9, -9, 3, -10, 2, -11, 1, -11, -1, -10, -2, + -9, -3, -3, -9, -2, -10, -1, -11, 4, -10, 5, -9, 6, -8, 7, -7, + 8, -6, 9, -5, 10, -4, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, + 5, 9, 4, 10, -4, 10, -5, 9, -6, 8, -7, 7, -8, 6, -9, 5, + -10, 4, -10, -4, -9, -5, -8, -6, -7, -7, -6, -8, -5, -9, -4, -10 +}; + +// Like neighbor_index_to_diff, but enumerates tiles in an order that matches cultural border expansion. Only valid for 0 <= neighbor_index <= MAX_CULTURAL_NI. +void __cdecl +patch_ni_to_diff_for_work_area (int neighbor_index, int * x_disp, int * y_disp) +{ + if (neighbor_index <= 0) { + *x_disp = *y_disp = 0; + return; + } else if (neighbor_index > MAX_CULTURAL_NI) + neighbor_index = neighbor_index % (MAX_CULTURAL_NI + 1); + + int i = neighbor_index << 1; + char const * p = &cultural_ni_to_diffs[neighbor_index << 1]; + *x_disp = p[0]; + *y_disp = p[1]; +} + +int __fastcall +patch_City_find_min_value_tile (City * this) +{ + int tr = City_find_min_value_tile (this); + + // The original function has been edited to enumerate tiles in our custom order matching cultural borders instead of the game's original + // order. It returns a neighbor index from that enumeration. We must convert it to standard order if it's beyond the range where the two + // enumerations overlap. + if (tr >= 21) + tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; + + return tr; +} + +int __fastcall +patch_City_find_best_tile_to_work (City * this, int edx, Unit * worker, bool param_2) +{ + int tr = City_find_best_tile_to_work (this, __, worker, param_2); + if (tr >= 21) + tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; + return tr; +} + +bool __fastcall +City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 21) && (neighbor_index <= MAX_CULTURAL_NI)) + neighbor_index = is->cultural_ni_to_standard[neighbor_index]; + return City_stop_working_tile (this, __, neighbor_index); +} + +int __fastcall +patch_Map_compute_ni_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + // Within the first two rings, there's no difference b/w the standard and custom "work area" neighbor indices so fall back to the base game's + // function in that case. + if (is->workable_tile_count <= 21) + return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); + + // If the work area has been expanded, compute the neighbor index then check that it's within the area. Ignore the limit we were passed and + // instead use the number of tiles in the workable area, doubled to cover the difference between cultural vs standard enumeration. + else { + int ni = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, 2 * is->workable_tile_count); + if ((ni >= 0) && (ni <= ARRAY_LEN (is->ni_to_work_radius)) && + (is->ni_to_work_radius[ni] >= 0) && + (is->ni_to_work_radius[ni] <= is->current_config.city_work_radius)) + return ni; + else + return -1; + } +} + +int __fastcall +patch_Map_m28_find_cnter_neigh_point_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + int ret_addr = ((int *)&x_home)[-1]; + if (ret_addr != ADDR_FIND_CENTER_NP_SPOTLIGHT_RET) + return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); + else + return patch_Map_compute_ni_for_work_area (this, __, x_home, y_home, x_neigh, y_neigh, 500); +} + +int +get_work_ring_limit_by_culture (City * city) +{ + if (is->current_config.work_area_limit == WAL_NONE) + return INT_MAX; + else { + int lower_lim = (is->current_config.work_area_limit == WAL_CULTURAL_MIN_2) ? 2 : 1; + return not_below (lower_lim, city->Body.cultural_level); + } +} + +int +get_work_ring_limit_by_improvements (City * city) +{ + if (is->current_config.count_work_area_improvements == 0) + return INT_MAX; + else { + int maxRadius = 0; + int bonusRadius = 0; + for (int n = 0; n < is->current_config.count_work_area_improvements; n++) { + struct work_area_improvement * work_area_improvement = &is->current_config.work_area_improvements[n]; + if (work_area_improvement->work_area_radius_limit > maxRadius && + (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { + maxRadius = work_area_improvement->work_area_radius_limit; + } + if (work_area_improvement->work_area_radius_bonus > 0 && + (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { + bonusRadius += work_area_improvement->work_area_radius_bonus; + } + } + return maxRadius + bonusRadius; + } +} + +int +get_work_ring_limit_total (City * city) +{ + int cultureLimit = get_work_ring_limit_by_culture(city); + int improvementLimit = get_work_ring_limit_by_improvements(city); + if (cultureLimit < improvementLimit) + return cultureLimit; + return improvementLimit; +} + +bool __fastcall +patch_City_controls_tile (City * this, int edx, int neighbor_index, bool consider_enemy_units) +{ + // Check that this tile is not outside the city's work area. We've deleted a check from the base game code that verifies the n.i. is within 21 + // tiles so we can replicate it here in a way that also works for an expanded work area. + int work_radius = ((neighbor_index >= 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) ? is->ni_to_work_radius[neighbor_index] : -1; + if ((work_radius > is->current_config.city_work_radius) || (work_radius < 0)) + return false; + + int work_ring_limit = get_work_ring_limit_total (this); + if (work_radius > work_ring_limit) { + + // May consider this tile within the limit if any adjacent tiles are within the limit & within borders + bool exempt_from_limit; + if (is->current_config.work_area_limit != WAL_CULTURAL_OR_ADJACENT) + exempt_from_limit = false; + else if (neighbor_index >= 9) { + exempt_from_limit = false; + int center_x, center_y; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, ¢er_x, ¢er_y); + int neighbors_checked = 0; + for (int ni = 1; ni < ARRAY_LEN (is->ni_to_work_radius); ni++) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, ni, &nx, &ny); + if (are_tiles_adjacent (center_x, center_y, nx, ny)) { + neighbors_checked++; + int wr = is->ni_to_work_radius[ni]; + Tile * neighbor; + if (((wr >= 0) && (wr <= work_ring_limit)) && + (neighbor = tile_at (nx, ny)) && + (neighbor->vtable->m38_Get_Territory_OwnerID (neighbor) == this->Body.CivID)) { + exempt_from_limit = true; + break; + } + } + if (neighbors_checked == 8) + break; + } + } else + exempt_from_limit = true; + + if (! exempt_from_limit) + return false; + } + + if (neighbor_index >= 0) { + int tile_x, tile_y; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + // Check if the tile itself is a completed district (includes natural wonders) + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id)) + return false; + + // Check if the tile is covered by a distribution hub + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + return false; + } + } + } + } + + return City_controls_tile (this, __, neighbor_index, consider_enemy_units); +} + +bool __fastcall +patch_City_controls_tile_conv_ni (City * this, int edx, int neighbor_index, bool consider_enemy_units) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return patch_City_controls_tile (this, __, is->cultural_ni_to_standard[neighbor_index], consider_enemy_units); + else + return false; +} + +bool __fastcall +patch_City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return City_stop_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); + else + return false; +} + +bool __fastcall +patch_City_start_working_tile_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return City_start_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); + else + return false; +} + +void __fastcall +patch_City_add_or_remove_tile_yield_conv_ni (City * this, int edx, int neighbor_index, bool add_else_remove) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + City_add_or_remove_tile_yield (this, __, is->cultural_ni_to_standard[neighbor_index], add_else_remove); +} + +bool __fastcall +patch_City_is_neighboring_tile_in_area_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return City_is_neighboring_tile_in_area (this, __, is->cultural_ni_to_standard[neighbor_index]); + else + return false; +} + +int +get_city_screen_center_y (City * city) +{ + int y = city->Body.Y; + if (p_bic_data->is_zoomed_out) + return y + 7; // when zoomed out, shift map up to center city + else if (is->current_config.city_work_radius >= 3) + return y + 4; // when work radius is 3, shift map up one extra tile so as not to overlap citizen heads + else + return y + 2; // base game behavior +} + +void __fastcall +patch_Main_Screen_Form_bring_cnter_view_city_focus (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) +{ + // If the city we're viewing can work tiles in the 4+ ring then zoom out the map display to show them + int effective_radius = not_above (get_work_ring_limit_total (p_city_form->CurrentCity), is->current_config.city_work_radius); + if (is->current_config.work_area_limit == WAL_CULTURAL_OR_ADJACENT) + effective_radius = not_above (is->current_config.city_work_radius, effective_radius + 1); + if (effective_radius >= 4 && is->current_config.auto_zoom_city_screen_for_large_work_areas) + p_bic_data->is_zoomed_out = true; + + Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); +} + +void __fastcall +patch_Main_Screen_Form_bring_cnter_view_city_arrow (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) +{ + Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); +} + +void tile_index_to_coords (Map * map, int index, int * out_x, int * out_y); + +Tile * __fastcall +patch_Map_get_tile_for_work_area_drawing (Map * this, int edx, int index) +{ + Tile * tr = Map_get_tile (this, __, index); + + if (tr != p_null_tile) { + int x, y; + tile_index_to_coords (this, index, &x, &y); + City * viewing_city = p_city_form->CurrentCity; + int ni = Map_compute_neighbor_index (this, __, viewing_city->Body.X, viewing_city->Body.Y, x, y, 1000); + if ((ni > 0) && ! patch_City_controls_tile (viewing_city, __, ni, false)) + tr = p_null_tile; + } + + return tr; +} + +// Resets is->current_config to the base config and updates the list of config names. Does NOT re-apply machine code edits. +void +reset_to_base_config () +{ + struct c3x_config * cc = &is->current_config; + + for (int n = 0; n < ARRAY_LEN (cc->limit_units_per_tile); n++) + cc->limit_units_per_tile[n] = 0; + + table_deinit (&cc->exclude_types_from_units_per_tile_limit); + + for (int n = 0; n < COUNT_PERFUME_KINDS; n++) + stable_deinit (&cc->perfume_specs[n]); + + // Free building-unit prereqs table + FOR_TABLE_ENTRIES (tei, &cc->building_unit_prereqs) { + if ((tei.value & 1) == 0) + free ((void *)tei.value); + } + table_deinit (&cc->building_unit_prereqs); + + // Free list of mills + if (cc->mills != NULL) { + free (cc->mills); + cc->mills = NULL; + cc->count_mills = 0; + } + + // Free list of AI multi-city start extra palaces + if (cc->ai_multi_start_extra_palaces != NULL) { + free (cc->ai_multi_start_extra_palaces); + cc->ai_multi_start_extra_palaces = NULL; + cc->count_ai_multi_start_extra_palaces = 0; + cc->ai_multi_start_extra_palaces_capacity = 0; + } + + table_deinit (&cc->limit_defensive_retreat_on_water_to_types); + table_deinit (&cc->can_bombard_only_sea_tiles); + + // Free set of PTW artillery types and list of converted types + table_deinit (&cc->ptw_arty_types); + if (is->charmed_types_converted_to_ptw_arty != NULL) { + free (is->charmed_types_converted_to_ptw_arty); + is->charmed_types_converted_to_ptw_arty = NULL; + is->count_charmed_types_converted_to_ptw_arty = 0; + is->charmed_types_converted_to_ptw_arty_capacity = 0; + } + + // Free era alias lists + if (cc->civ_era_alias_lists != NULL) { + for (int n = 0; n < cc->count_civ_era_alias_lists; n++) { + struct civ_era_alias_list * list = &cc->civ_era_alias_lists[n]; + free (list->key); + for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) + free (list->aliases[k]); + } + free (cc->civ_era_alias_lists); + cc->civ_era_alias_lists = NULL; + cc->count_civ_era_alias_lists = 0; + } + if (cc->leader_era_alias_lists != NULL) { + for (int n = 0; n < cc->count_leader_era_alias_lists; n++) { + struct leader_era_alias_list * list = &cc->leader_era_alias_lists[n]; + free (list->key); + for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) { + free (list->aliases[k]); + free (list->titles[k]); + } + } + free (cc->leader_era_alias_lists); + cc->leader_era_alias_lists = NULL; + cc->count_leader_era_alias_lists = 0; + } + + // Free list of work_area_improvements + if (cc->work_area_improvements != NULL) { + free (cc->work_area_improvements); + cc->work_area_improvements = NULL; + cc->count_work_area_improvements = 0; + } + + // Free aircraft victory animation string + if (cc->aircraft_victory_animation != NULL) { + free (cc->aircraft_victory_animation); + cc->aircraft_victory_animation = NULL; + } + + if (cc->great_wall_auto_build_wonder_name != NULL) { + free (cc->great_wall_auto_build_wonder_name); + cc->great_wall_auto_build_wonder_name = NULL; + } + + // Free unit limits table + FOR_TABLE_ENTRIES (tei, &cc->unit_limits) + free ((void *)tei.value); + stable_deinit (&cc->unit_limits); + + // Free the linked list of loaded config names and the string name contained in each one + if (is->loaded_config_names != NULL) { + struct loaded_config_name * next = is->loaded_config_names; + while (next != NULL) { + struct loaded_config_name * to_free = next; + next = next->next; + free (to_free->name); + free (to_free); + } + } + + // Overwrite the current config with the base config + memcpy (&is->current_config, &is->base_config, sizeof is->current_config); + + // These fields are heap-allocated and must not be inherited from base_config + // (base_config never owns valid pointers for them) + is->current_config.unit_counter_groups = NULL; + is->current_config.count_unit_counter_groups = 0; + is->current_config.counter_rules = NULL; + is->current_config.count_counter_rules = 0; + + // Recreate loaded config names list with just the base config + is->loaded_config_names = malloc (sizeof *is->loaded_config_names); + is->loaded_config_names->name = strdup ("(base)"); + is->loaded_config_names->next = NULL; + + // Update IS variable that's tied to a config value + is->workable_tile_count = workable_tile_counts[is->current_config.city_work_radius]; +} + +struct id_list { + int length; + int capacity; + int ids[0]; +}; + +struct id_list * +alloc_id_list (int capacity, struct id_list const * copy) +{ + struct id_list * tr = malloc ((sizeof *tr) + capacity * sizeof(tr->ids[0])); + tr->length = 0; + tr->capacity = capacity; + if (copy != NULL) { + int new_len = not_above (capacity, copy->length); + for (int n = 0; n < new_len; n++) + tr->ids[n] = copy->ids[n]; + tr->length = new_len; + } + return tr; +} + +// This is the largest ID that will be stored inline inside sidtables. The amount here must be smaller than any pointer we'd get from malloc since the +// sidtable code compares values against this amount to determine which are inlined values versus pointers. +#define SID_TABLE_MAX_INLINE_ID 10000 + +void +sidtable_deinit (struct table * t) +{ + FOR_TABLE_ENTRIES (tei, t) { + free ((void *)tei.key); + if (tei.value > SID_TABLE_MAX_INLINE_ID) + free ((void *)tei.value); + } + table_deinit (t); +} + +void +sidtable_append (struct table * t, struct string_slice const * key, int id) +{ + // Expand or allocate table as needed + if (t->len >= table_capacity (t) / 2) + table__expand (t, hash_str, compare_str_keys); + + size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); + int * entry = &((int *)TABLE__BASE (t))[2*index]; + if (table__is_occupied (t, index)) { // If key is already in the table + int prev_val = entry[1]; + if (prev_val <= SID_TABLE_MAX_INLINE_ID) { // If prev value is an id, convert it to a list + struct id_list * new_list = alloc_id_list (2, NULL); + new_list->ids[0] = prev_val; + new_list->ids[1] = id; + new_list->length = 2; + entry[1] = (int)new_list; + } else { // Else, prev value is a list so append the new ID to it + struct id_list * list = (void *)prev_val; + if (list->length >= list->capacity) { // Expand list if necessary + struct id_list * new_list = alloc_id_list (2 * list->capacity, list); + entry[1] = (int)new_list; + free (list); + list = new_list; + } + list->ids[list->length] = id; + list->length++; + } + } else { // Key is not in the table, add it for the first time + entry[0] = (int)extract_slice (key); + if (id <= SID_TABLE_MAX_INLINE_ID) // Write ID inline if possible + entry[1] = id; + else { // Otherwise create a list for this one ID + struct id_list * new_list = alloc_id_list (2, NULL); + new_list->ids[0] = id; + new_list->length = 1; + entry[1] = (int)new_list; + } + table__set_occupation (t, index, 1); + t->len++; + } +} + +bool +sidtable_get_by_index (struct table const * t, size_t index, int ** out_ids, int * out_count) +{ + size_t capacity = table_capacity (t); + if ((capacity > 0) && (index < capacity) && table__is_occupied (t, index)) { + int * entry = &((int *)TABLE__BASE (t))[2*index]; + int val = entry[1]; + if (val <= SID_TABLE_MAX_INLINE_ID) { // Value is an ID + *out_ids = &entry[1]; + *out_count = 1; + } else { + struct id_list * list = (void *)val; + *out_ids = &list->ids[0]; + *out_count = list->length; + } + return true; + } else + return false; +} + +bool +sidtable_look_up (struct table const * t, char const * key, int ** out_ids, int * out_count) +{ + if (t->len > 0) { + size_t index = table__place (t, compare_str_keys, (int)key, hash_str ((int)key)); + return sidtable_get_by_index (t, index, out_ids, out_count); + } else + return false; +} + +bool +sidtable_look_up_slice (struct table const * t, struct string_slice const * key, int ** out_ids, int * out_count) +{ + if (t->len > 0) { + size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); + return sidtable_get_by_index (t, index, out_ids, out_count); + } else + return false; +} + +struct error_line { + char text[200]; + struct error_line * next; +}; + +struct error_line * +add_error_line (struct error_line ** p_lines) +{ + struct error_line * tr = calloc (1, sizeof *tr); + + struct error_line ** p_prev = p_lines; + while (*p_prev != NULL) + p_prev = &(*p_prev)->next; + *p_prev = tr; + + return tr; +} + +void +add_unrecognized_line (struct error_line ** p_lines, struct string_slice const * name) +{ + struct error_line * line = add_error_line (p_lines); + char s[100]; + snprintf (line->text, sizeof line->text, "^ %.*s", name->len, name->str); + line->text[(sizeof line->text) - 1] = '\0'; +} + +void +free_error_lines (struct error_line * lines) +{ + while (lines != NULL) { + struct error_line * next = lines->next; + free (lines); + lines = next; + } +} + +bool +find_improv_id_by_name (struct string_slice const * name, int * out) +{ + Improvement * improv; + if (name->len <= sizeof improv->Name) + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { + *out = n; + return true; + } + return false; +} + +// start_id specifies where the search will start. It's useful for finding multiple type IDs with the same name, which commonly happens due to the +// game duplicating unit types. +bool +find_unit_type_id_by_name (struct string_slice const * name, int start_id, int * out) +{ + UnitType * unit_type; + if (name->len <= sizeof unit_type->Name) + for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) + if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { + *out = n; + return true; + } + return false; +} + +bool +find_resource_id_by_name (struct string_slice const * name, int * out) +{ + Resource_Type * res_type; + if (name->len <= sizeof res_type->Name) + for (int n = 0; n < p_bic_data->ResourceTypeCount; n++) + if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { + *out = n; + return true; + } + return false; +} + +bool +find_animation_type_by_name (struct string_slice const * name, bool lower_case, AnimationType * out) +{ + for (int n_anim = 0; n_anim < COUNT_ANIMATION_TYPES; n_anim++) + if (strlen (animation_names[n_anim]) == name->len) { + bool all_chars_match = true; + for (int k = 0; k < name->len; k++) { + int c = animation_names[n_anim][k]; + if (lower_case) + c = tolower (c); + if (c != name->str[k]) { + all_chars_match = false; + break; + } + } + if (all_chars_match) { + *out = n_anim; + return true; + } + } + return false; +} + +enum game_object_kind { + GOK_UNIT_TYPE = 0, + GOK_BUILDING, + GOK_RESOURCE, + GOK_TECHNOLOGY, + GOK_GOVERNMENT, + + COUNT_GAME_OBJECT_KINDS +}; + +bool +find_game_object_id_by_name (enum game_object_kind kind, struct string_slice const * name, int start_id, int * out) +{ + switch (kind) { + case GOK_UNIT_TYPE: { + UnitType * unit_type; + if (name->len <= sizeof unit_type->Name) + for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) + if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { + *out = n; + return true; + } + return false; + } + case GOK_BUILDING: { + Improvement * improv; + if (name->len <= sizeof improv->Name) + for (int n = start_id; n < p_bic_data->ImprovementsCount; n++) + if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { + *out = n; + return true; + } + return false; + } + case GOK_RESOURCE: { + Resource_Type * res_type; + if (name->len <= sizeof res_type->Name) + for (int n = start_id; n < p_bic_data->ResourceTypeCount; n++) + if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { + *out = n; + return true; + } + return false; + } + case GOK_TECHNOLOGY: { + Advance * adv; + if (name->len <= sizeof adv->Name) + for (int n = start_id; n < p_bic_data->AdvanceCount; n++) + if (slice_matches_str (name, p_bic_data->Advances[n].Name)) { + *out = n; + return true; + } + return false; + } + case GOK_GOVERNMENT: { + Government * govt; + if (name->len <= sizeof govt->Name) + for (int n = start_id; n < p_bic_data->GovernmentsCount; n++) + if (slice_matches_str (name, p_bic_data->Governments[n].Name.S)) { + *out = n; + return true; + } + return false; + } + default: + return false; + } +} + +// Converts a build name (like "Spearman" or "Granary") into a City_Order struct. Returns whether or not any improvement or unit type was found under +// the given name. +bool +find_city_order_by_name (struct string_slice const * name, City_Order * out) +{ + int id; + if (find_improv_id_by_name (name, &id)) { + out->OrderID = id; + out->OrderType = COT_Improvement; + return true; + } else if (find_unit_type_id_by_name (name, 0, &id)) { + out->OrderID = id; + out->OrderType = COT_Unit; + return true; + } else + return false; +} + +// Returns a list of AI strat duplicates of the unit type with the given id. This means a list of all other unit types that are identical to the given +// one except were separated out so each can have only one AI strategy. Returns the total number of duplicates, which may be greater than dup_ids_len. +int +list_unit_type_duplicates (int type_id, int * out_dup_ids, int dup_ids_len) +{ + // type_id may be a duplicate itself. Find the base type so we can start assembling the array from there. Otherwise we may miss some. + int alt_for_id = p_bic_data->UnitTypes[type_id].alternate_strategy_for_id; + int base_type_id = (alt_for_id >= 0) ? alt_for_id : type_id; + + int tr = 0, current = base_type_id; + while (1) { + if (current != type_id) { + if (tr < dup_ids_len) + out_dup_ids[tr] = current; + tr++; + } + int next; + if (itable_look_up (&is->unit_type_duplicates, current, &next)) + current = next; + else + break; + } + + return tr; +} + +// A "recognizable" is something that contains the name of a unit, building, etc. When parsing one, it's possible for it to be grammatically valid but +// contain a name that doesn't match anything in the scenario data. That's a special kind of error. In that case, we record the error to report in a +// popup and continue parsing. +enum recognizable_parse_result { + RPR_OK = 0, + RPR_UNRECOGNIZED, + RPR_PARSE_ERROR +}; + +struct perfume_spec { + char name[36]; // Must be large enough to fit the name of a unit type or improvement + i31b value; // Int component stores amount, bool stores whether it's a percentage or not +}; + +enum recognizable_parse_result +parse_perfume_spec (char ** p_cursor, enum perfume_kind kind, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + char * cur = *p_cursor; + struct string_slice name; + City_Order unused_city_order; + int unused_id; + i31b value; + if (parse_string (&cur, &name) && + skip_punctuation (&cur, ':') && + parse_i31b (&cur, &value)) { + *p_cursor = cur; + + if (((kind == PK_PRODUCTION) && find_city_order_by_name (&name, &unused_city_order)) || + ((kind == PK_TECHNOLOGY) && find_game_object_id_by_name (GOK_TECHNOLOGY, &name, 0, &unused_id)) || + ((kind == PK_GOVERNMENT) && find_game_object_id_by_name (GOK_GOVERNMENT, &name, 0, &unused_id))) { + struct perfume_spec * out = out_perfume_spec; + snprintf (out->name, sizeof out->name, "%.*s", name.len, name.str); + out->name[(sizeof out->name) - 1] = '\0'; + out->value = value; + return RPR_OK; + } else { + add_unrecognized_line (p_unrecognized_lines, &name); + return RPR_UNRECOGNIZED; + } + } else + return RPR_PARSE_ERROR; +} + +enum recognizable_parse_result +parse_production_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + return parse_perfume_spec (p_cursor, PK_PRODUCTION, p_unrecognized_lines, out_perfume_spec); +} + +enum recognizable_parse_result +parse_technology_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + return parse_perfume_spec (p_cursor, PK_TECHNOLOGY, p_unrecognized_lines, out_perfume_spec); +} + +enum recognizable_parse_result +parse_government_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + return parse_perfume_spec (p_cursor, PK_GOVERNMENT, p_unrecognized_lines, out_perfume_spec); +} + +enum recognizable_parse_result +parse_mill (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_mill) +{ + char * cur = *p_cursor; + struct string_slice improv_name; + if (parse_string (&cur, &improv_name) && + skip_punctuation (&cur, ':')) { + + short flags = 0; + struct string_slice resource_name; + while (1) { + if (! parse_string (&cur, &resource_name)) + return RPR_PARSE_ERROR; + else if (slice_matches_str (&resource_name, "local")) flags |= MF_LOCAL; + else if (slice_matches_str (&resource_name, "no-tech-req")) flags |= MF_NO_TECH_REQ; + else if (slice_matches_str (&resource_name, "yields")) flags |= MF_YIELDS; + else if (slice_matches_str (&resource_name, "show-bonus")) flags |= MF_SHOW_BONUS; + else if (slice_matches_str (&resource_name, "hide-non-bonus")) flags |= MF_HIDE_NON_BONUS; + else + break; + } + + *p_cursor = cur; + int improv_id, resource_id; + int any_unrecognized = 0; + if (! find_improv_id_by_name (&improv_name, &improv_id)) { + add_unrecognized_line (p_unrecognized_lines, &improv_name); + any_unrecognized = 1; + } + if (! find_resource_id_by_name (&resource_name, &resource_id)) { + add_unrecognized_line (p_unrecognized_lines, &resource_name); + any_unrecognized = 1; + } + if (any_unrecognized) + return RPR_UNRECOGNIZED; + else { + struct mill * out = out_mill; + out->improv_id = improv_id; + out->resource_id = resource_id; + out->flags = flags; + return RPR_OK; + } + } else + return RPR_PARSE_ERROR; +} + +enum recognizable_parse_result +parse_era_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_or_civ_alias_list, bool leader_else_civ_name) +{ + char * cur = *p_cursor; + struct string_slice key; + if (parse_string (&cur, &key) && + skip_punctuation (&cur, ':')) { + + char * aliases[ERA_ALIAS_LIST_CAPACITY] = {0}; + char * titles[ERA_ALIAS_LIST_CAPACITY] = {0}; + int alias_count = 0, + female_bits = 0, + gender_specified_bits = 0; // For each alias, set to 1 if a gender was specified + struct string_slice alias; + while (1) { + if (parse_string (&cur, &alias)) { + if (alias_count < ERA_ALIAS_LIST_CAPACITY) + aliases[alias_count] = extract_slice (&alias); + + // If we're parsing a list of leader names, read in the gender & title if present + if (leader_else_civ_name) { + char * inner_cur = cur; + struct string_slice gender; + struct string_slice title = {0}; + if ( skip_punctuation (&inner_cur, '(') + && parse_string (&inner_cur, &gender) + && ( skip_punctuation (&inner_cur, ')') + || ( skip_punctuation (&inner_cur, ',') + && parse_string (&inner_cur, &title) + && skip_punctuation (&inner_cur, ')'))) + && ( slice_matches_str (&gender, "M") + || slice_matches_str (&gender, "m") + || slice_matches_str (&gender, "F") + || slice_matches_str (&gender, "f"))) { + if (alias_count < 32) { + if (slice_matches_str (&gender, "F") || slice_matches_str (&gender, "f")) + female_bits |= 1 << alias_count; + gender_specified_bits |= 1 << alias_count; + } + if (title.len > 0) + titles[alias_count] = extract_slice (&title); + cur = inner_cur; + } + } + + alias_count++; + } else + break; + } + if (alias_count == 0) + return RPR_PARSE_ERROR; + + *p_cursor = cur; + + // Check that "key" matches a noun, adjective, or formal name of any civ ("race") in the scenario data. Store that civ. + Race * race_matching_key = NULL; { + for (int n = 0; n < p_bic_data->RacesCount; n++) { + Race * race = &p_bic_data->Races[n]; + if ( ( leader_else_civ_name + && slice_matches_str (&key, race->LeaderName)) + || ( (! leader_else_civ_name) + && ( slice_matches_str (&key, race->AdjectiveName) + || slice_matches_str (&key, race->CountryName) + || slice_matches_str (&key, race->SingularName)))) { + race_matching_key = race; + break; + } + } + } + if (race_matching_key == NULL) { + add_unrecognized_line (p_unrecognized_lines, &key); + return RPR_UNRECOGNIZED; + } + + if (leader_else_civ_name) { + struct leader_era_alias_list * out = out_leader_or_civ_alias_list; + memset (out, 0, sizeof *out); // Make sure unspecified aliases & titles are NULL + out->key = extract_slice (&key); + for (int n = 0; n < alias_count; n++) { + out->aliases[n] = aliases[n]; + out->titles[n] = titles[n]; + } + + // Set gender bits + int unreplaced_bits = (race_matching_key->LeaderGender == 0) ? 0 : ~0; + out->gender_bits = (unreplaced_bits & ~gender_specified_bits) | female_bits; + + + } else { + struct civ_era_alias_list * out = out_leader_or_civ_alias_list; + memset (out, 0, sizeof *out); + out->key = extract_slice (&key); + for (int n = 0; n < alias_count; n++) + out->aliases[n] = aliases[n]; + } + + return RPR_OK; + } else + return RPR_PARSE_ERROR; +} + + +enum recognizable_parse_result +parse_civ_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_civ_era_alias_list) +{ + return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_civ_era_alias_list, false); +} + +enum recognizable_parse_result +parse_leader_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_era_alias_list) +{ + return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_leader_era_alias_list, true); +} + +struct parsed_unit_type_limit { + char name[32]; // Same length as Name in Unit_Type + struct unit_type_limit limit; +}; + +enum recognizable_parse_result +parse_unit_type_limit (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_unit_type_limit) +{ + char * cur = *p_cursor; + struct parsed_unit_type_limit * out = out_parsed_unit_type_limit; + + struct string_slice name; + struct unit_type_limit limit = {0}; + if (skip_white_space (&cur) && + parse_string (&cur, &name) && + (name.len < (sizeof out->name)) && + skip_punctuation (&cur, ':')) { + + do { + int num; + if (! parse_int (&cur, &num)) + return RPR_PARSE_ERROR; + + struct string_slice ss; + if (parse_string (&cur, &ss)) { + if (slice_matches_str (&ss, "per-city")) + limit.per_city += num; + else if (slice_matches_str (&ss, "cities-per")) + limit.cities_per += num; + else + return RPR_PARSE_ERROR; + } else + limit.per_civ += num; + + } 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 { + add_unrecognized_line (p_unrecognized_lines, &name); + *p_cursor = cur; + return RPR_UNRECOGNIZED; + } + + } else + return RPR_PARSE_ERROR; +} + +enum recognizable_parse_result +parse_work_area_improvement (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_work_area_improvement) +{ + char * cur = *p_cursor; + struct work_area_improvement * out = out_parsed_work_area_improvement; + out->improv_id = -1; + out->work_area_radius_limit = 0; + out->work_area_radius_bonus = 0; + + struct string_slice improv_name; + if (skip_white_space (&cur) && + parse_string (&cur, &improv_name) && + skip_punctuation (&cur, ':')) { + + int num; + if (! parse_int (&cur, &num)) + return RPR_PARSE_ERROR; + + struct string_slice ss; + if (parse_string (&cur, &ss)) { + if (slice_matches_str (&ss, "extra")) + out->work_area_radius_bonus = num; + else + return RPR_PARSE_ERROR; + } else + out->work_area_radius_limit = num; + + int improv_id; + if (slice_matches_str (&improv_name, "default")) { + out->improv_id = -1; + *p_cursor = cur; + return RPR_OK; + } else if (find_improv_id_by_name (&improv_name, &improv_id)) { + out->improv_id = improv_id; + *p_cursor = cur; + return RPR_OK; + } else { + add_unrecognized_line (p_unrecognized_lines, &improv_name); + *p_cursor = cur; + return RPR_UNRECOGNIZED; + } + + } else + return RPR_PARSE_ERROR; +} + +// Recognizable items are appended to out_list/count, which must have been previously initialized (NULL/0 is valid for an empty list). +// If an error occurs while reading, returns the location of the error inside the slice, specifically the number of characters before the unreadable +// item. If no error occurs, returns -1. +int +read_recognizables (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + int item_size, + enum recognizable_parse_result (* parse_item) (char **, struct error_line **, void *), + void ** inout_list, + int * inout_count) +{ + if (s->len <= 0) + return -1; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + + bool success = false; + void * new_items = NULL; + int count_new_items = 0; + int new_items_capacity = 0; + void * temp_item = malloc (item_size); + + while (1) { + enum recognizable_parse_result result = parse_item (&cursor, p_unrecognized_lines, temp_item); + if (result != RPR_PARSE_ERROR) { + if (result == RPR_OK) { + reserve (item_size, &new_items, &new_items_capacity, count_new_items); + memcpy ((byte *)new_items + count_new_items * item_size, temp_item, item_size); + count_new_items++; + } + + if (skip_punctuation (&cursor, ',') && skip_white_space (&cursor)) + continue; + else if (skip_horiz_space (&cursor) && (*cursor == '\0')) { + success = true; + break; + } else + break; + } else + break; + } + + if (success && (count_new_items > 0)) { + *inout_list = realloc (*inout_list, (*inout_count + count_new_items) * item_size); + memcpy ((byte *)*inout_list + *inout_count * item_size, new_items, count_new_items * item_size); + *inout_count += count_new_items; + } + free (temp_item); + free (new_items); + free (extracted_slice); + return success ? -1 : cursor - extracted_slice; +} + +// Reads a "sidtable" from text. A sidtable maps strings to IDs of scenario objects. The string keys are also expected to be a type of scenario +// object. This method reads text such as: +// Factory: Battleship, Stable: Horseman Knight Cavalry, "Siege Workshop": Catapult Trebuchet +// and converts it to a table mapping "Factory", "Stable", and "Siege Workshop" to the corresponding unit type IDs. All new entries are appended to +// the given table; existing entries are not removed. +// Like read_recognizables, this method returns -1 for success or the location of an error if there is one. +int +read_sidtable (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + enum game_object_kind key_kind, + enum game_object_kind list_elem_kind, + struct table * sidtable) +{ + if (s->len <= 0) + return -1; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + while (1) { + struct string_slice key; + if (skip_white_space (&cursor) && parse_string (&cursor, &key)) { + int unused; + bool recognized_key = find_game_object_id_by_name (key_kind, &key, 0, &unused); + if (! recognized_key) + add_unrecognized_line (p_unrecognized_lines, &key); + if (! skip_punctuation (&cursor, ':')) + break; + struct string_slice elem_name; + while (skip_white_space (&cursor) && parse_string (&cursor, &elem_name)) { + bool recognized_elem = false; + int elem_id = -1; + while (find_game_object_id_by_name (list_elem_kind, &elem_name, elem_id + 1, &elem_id)) { + recognized_elem = true; + if (recognized_key) + sidtable_append (sidtable, &key, elem_id); + } + if (! recognized_elem) + add_unrecognized_line (p_unrecognized_lines, &elem_name); + } + skip_punctuation (&cursor, ','); + } else { + success = (*cursor == '\0'); + break; + } + } + + free (extracted_slice); + return success ? -1 : cursor - extracted_slice; +} + +// Like read_recognizables, returns -1 for success or the location of an error if there is one +int +read_building_unit_prereqs (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + struct table * building_unit_prereqs) +{ + if (s->len <= 0) + return -1; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + struct prereq { + int building_id; + struct string_slice unit_type_name; + } * new_prereqs = NULL; + int new_prereqs_capacity = 0; + int count_new_prereqs = 0; + + while (1) { + struct string_slice building_name; + if (skip_white_space (&cursor) && parse_string (&cursor, &building_name)) { + int building_id; + bool have_building_id = find_improv_id_by_name (&building_name, &building_id); + if (! have_building_id) + add_unrecognized_line (p_unrecognized_lines, &building_name); + if (! skip_punctuation (&cursor, ':')) + break; + struct string_slice unit_type_name; + while (skip_white_space (&cursor) && parse_string (&cursor, &unit_type_name)) { + int unused; + if (find_unit_type_id_by_name (&unit_type_name, 0, &unused)) { // if there is any by this name, later we'll deal with the possibility of multiple + if (have_building_id) { + reserve (sizeof new_prereqs[0], (void **)&new_prereqs, &new_prereqs_capacity, count_new_prereqs); + new_prereqs[count_new_prereqs++] = (struct prereq) { .building_id = building_id, .unit_type_name = unit_type_name }; + } + } else + add_unrecognized_line (p_unrecognized_lines, &unit_type_name); + } + skip_punctuation (&cursor, ','); + } else { + success = (*cursor == '\0'); + break; + } + } + + // If parsing succeeded, add the new prereq rules to the table + if (success) + for (int n = 0; n < count_new_prereqs; n++) { + struct prereq * prereq = &new_prereqs[n]; + + int unit_type_id = -1; + while (find_unit_type_id_by_name (&prereq->unit_type_name, unit_type_id + 1, &unit_type_id)) { + + // If this unit type ID is not already in the table, insert it paired with the encoded building ID + int prev_val; + if (! itable_look_up (building_unit_prereqs, unit_type_id, &prev_val)) + itable_insert (building_unit_prereqs, unit_type_id, (prereq->building_id << 1) | 1); + + // If the unit type ID is already associated with a building ID, create a list for both the old and new building IDs + else if (prev_val & 1) { + int * list = malloc (MAX_BUILDING_PREREQS_FOR_UNIT * sizeof *list); + for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) + list[n] = -1; + list[0] = prev_val >> 1; // Decode + list[1] = prereq->building_id; + itable_insert (building_unit_prereqs, unit_type_id, (int)list); + + // Otherwise, it's already associated with a list. Search the list for a free spot and fill it with the new building ID + } else { + int * list = (int *)prev_val; + for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) + if (list[n] < 0) { + list[n] = prereq->building_id; + break; + } + } + } + } + + + free (new_prereqs); + free (extracted_slice); + return success ? -1 : cursor - extracted_slice; +} + +// Reads a space-separated list of unit types like: +// Worker Galley "Gallic Swordsman" +// Looks up the type ID(s) for each name and inserts them into the unit_types table associated with a value of 1. +bool +read_unit_type_list (struct string_slice const * s, struct error_line ** p_unrecognized_lines, struct table * unit_types) +{ + if (s->len <= 0) + return true; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + while (1) { + struct string_slice name; + if (parse_string (&cursor, &name)) { + + int id = -1; + bool matched_any = false; + while (find_unit_type_id_by_name (&name, id + 1, &id)) { + itable_insert (unit_types, id, 1); + matched_any = true; + } + + if (! matched_any) + add_unrecognized_line (p_unrecognized_lines, &name); + + } else { + skip_white_space (&cursor); + success = *cursor == '\0'; + break; + } + } + + free (extracted_slice); + return success; +} + +bool +read_ai_multi_start_extra_palaces (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + int ** p_ai_multi_start_extra_palaces, + int * p_count_ai_multi_start_extra_palaces, + int * p_ai_multi_start_extra_palaces_capacity) +{ + if (s->len <= 0) + return true; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + while (1) { + struct string_slice name; + if (parse_string (&cursor, &name)) { + int id; + if (find_improv_id_by_name (&name, &id)) { + int count = *p_count_ai_multi_start_extra_palaces; + reserve (sizeof **p_ai_multi_start_extra_palaces, (void **)p_ai_multi_start_extra_palaces, p_ai_multi_start_extra_palaces_capacity, count); + (*p_ai_multi_start_extra_palaces)[count] = id; + *p_count_ai_multi_start_extra_palaces = count + 1; + } else + add_unrecognized_line (p_unrecognized_lines, &name); + + } else { + skip_white_space (&cursor); + success = *cursor == '\0'; + break; + } + } + + free (extracted_slice); + return success; +} + +bool +read_retreat_rules (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "standard" )) { *out_val = RR_STANDARD; return true; } + else if (slice_matches_str (&trimmed, "none" )) { *out_val = RR_NONE; return true; } + else if (slice_matches_str (&trimmed, "all-units" )) { *out_val = RR_ALL_UNITS; return true; } + else if (slice_matches_str (&trimmed, "if-faster" )) { *out_val = RR_IF_FASTER; return true; } + else if (slice_matches_str (&trimmed, "if-not-slower" )) { *out_val = RR_IF_NOT_SLOWER; return true; } + else if (slice_matches_str (&trimmed, "if-fast-and-not-slower")) { *out_val = RR_IF_FAST_AND_NOT_SLOWER; return true; } + else + return false; +} + +bool +read_line_drawing_override (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "never" )) { *out_val = LDO_NEVER; return true; } + else if (slice_matches_str (&trimmed, "wine" )) { *out_val = LDO_WINE; return true; } + else if (slice_matches_str (&trimmed, "always")) { *out_val = LDO_ALWAYS; return true; } + else + return false; +} + +bool +read_minimap_doubling_mode (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "never" )) { *out_val = MDM_NEVER; return true; } + else if (slice_matches_str (&trimmed, "high-def")) { *out_val = MDM_HIGH_DEF; return true; } + else if (slice_matches_str (&trimmed, "always" )) { *out_val = MDM_ALWAYS; return true; } + else + return false; +} + +bool +read_unit_cycle_search_criteria (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "standard" )) { *out_val = UCSC_STANDARD; return true; } + else if (slice_matches_str (&trimmed, "similar-near-start" )) { *out_val = UCSC_SIMILAR_NEAR_START; return true; } + else if (slice_matches_str (&trimmed, "similar-near-destination")) { *out_val = UCSC_SIMILAR_NEAR_DESTINATION; return true; } + else + return false; +} + +bool +read_no_ai_patrol_override (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "zero")) { *out_val = NAPO_ZERO; return true; } + else if (slice_matches_str (&trimmed, "one" )) { *out_val = NAPO_ONE; return true; } + else if (slice_matches_str (&trimmed, "none")) { *out_val = NAPO_NONE; return true; } + else + return false; +} + +bool +read_work_area_limit (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "none" )) { *out_val = WAL_NONE; return true; } + else if (slice_matches_str (&trimmed, "cultural" )) { *out_val = WAL_CULTURAL; return true; } + else if (slice_matches_str (&trimmed, "cultural-min-2" )) { *out_val = WAL_CULTURAL_MIN_2; return true; } + else if (slice_matches_str (&trimmed, "cultural-or-adjacent")) { *out_val = WAL_CULTURAL_OR_ADJACENT; return true; } + else + return false; +} + +bool +read_day_night_cycle_mode (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "off" )) { *out_val = DNCM_OFF; return true; } + else if (slice_matches_str (&trimmed, "timer" )) { *out_val = DNCM_TIMER; return true; } + else if (slice_matches_str (&trimmed, "user-time" )) { *out_val = DNCM_USER_TIME; return true; } + else if (slice_matches_str (&trimmed, "every-turn")) { *out_val = DNCM_EVERY_TURN; return true; } + else if (slice_matches_str (&trimmed, "specified" )) { *out_val = DNCM_SPECIFIED; return true; } + else + return false; +} + +bool +read_distribution_hub_yield_division_mode (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "flat" )) { *out_val = DHYDM_FLAT; return true; } + else if (slice_matches_str (&trimmed, "scale-by-city-count" )) { *out_val = DHYDM_SCALE_BY_CITY_COUNT; return true; } + else + return false; +} + +bool +read_ai_distribution_hub_build_strategy (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "auto" )) { *out_val = ADHBS_AUTO; return true; } + else if (slice_matches_str (&trimmed, "by-city-count" )) { *out_val = ADHBS_BY_CITY_COUNT; return true; } + else + return false; +} + +bool +read_ai_auto_build_great_wall_strategy (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "all-borders" )) { *out_val = AAGWS_ALL_BORDERS; return true; } + else if (slice_matches_str (&trimmed, "other-civ-bordered-only")) { *out_val = AAGWS_OTHER_CIV_BORDERED_ONLY; return true; } + else + return false; +} + +bool +read_tile_terrain_type_value (struct string_slice const * s, enum SquareTypes * out_type) +{ + if (s == NULL || out_type == NULL) + return false; + + struct string_slice trimmed = trim_string_slice (s, 1); + if (trimmed.len <= 0) + return false; + + struct { + char const * name; + int value; + } const entries[] = { + {"desert", SQ_Desert}, + {"deserts", SQ_Desert}, + {"plain", SQ_Plains}, + {"plains", SQ_Plains}, + {"grassland", SQ_Grassland}, + {"grasslands", SQ_Grassland}, + {"tundra", SQ_Tundra}, + {"tundras", SQ_Tundra}, + {"floodplain", SQ_FloodPlain}, + {"floodplains", SQ_FloodPlain}, + {"hill", SQ_Hills}, + {"hills", SQ_Hills}, + {"mountain", SQ_Mountains}, + {"mountains", SQ_Mountains}, + {"forest", SQ_Forest}, + {"forests", SQ_Forest}, + {"jungle", SQ_Jungle}, + {"jungles", SQ_Jungle}, + {"marsh", SQ_Swamp}, + {"marshes", SQ_Swamp}, + {"swamp", SQ_Swamp}, + {"swamps", SQ_Swamp}, + {"volcano", SQ_Volcano}, + {"volcanos", SQ_Volcano}, + {"coast", SQ_Coast}, + {"coasts", SQ_Coast}, + {"sea", SQ_Sea}, + {"seas", SQ_Sea}, + {"ocean", SQ_Ocean}, + {"oceans", SQ_Ocean}, + {"river", SQ_RIVER}, + {"rivers", SQ_RIVER}, + {"snow-volcano", SQ_SNOW_VOLCANO}, + {"snow-volcanos", SQ_SNOW_VOLCANO}, + {"snow-forest", SQ_SNOW_FOREST}, + {"snow-forests", SQ_SNOW_FOREST}, + {"snow-mountain", SQ_SNOW_MOUNTAIN}, + {"snow-mountains", SQ_SNOW_MOUNTAIN}, + {"any", SQ_INVALID} + }; + + for (int i = 0; i < (int)ARRAY_LEN (entries); i++) { + if (slice_matches_str (&trimmed, entries[i].name)) { + *out_type = (enum SquareTypes)entries[i].value; + return true; + } + } + + return false; +} + +unsigned int +square_type_mask_bit (enum SquareTypes type) +{ + if ((int)type < 0 || type > SQ_SNOW_MOUNTAIN) + return 0; + return (unsigned int)(1u << type); +} + +unsigned int +district_buildable_mine_mask_bit (void) +{ + return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 1)); +} + +unsigned int +district_buildable_irrigation_mask_bit (void) +{ + return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 2)); +} + +unsigned int +district_buildable_lake_mask_bit (void) +{ + return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 3)); +} + +unsigned int +all_square_types_mask (void) +{ + return (unsigned int)((1u << (SQ_SNOW_MOUNTAIN + 1)) - 1); +} + +unsigned int +district_default_buildable_mask (void) +{ + return (unsigned int)DEFAULT_DISTRICT_BUILDABLE_MASK; +} + +bool +tile_has_snow_mountain (Tile * tile) +{ + return (tile != NULL) && (tile != p_null_tile) && tile->vtable->m29_Check_Mountain_Snowcap (tile); +} + +bool +tile_is_lake (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (! tile->vtable->m35_Check_Is_Water (tile)) + return false; + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + return false; + + int lake_size_threshold = 21; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + return continent->Body.TileCount <= lake_size_threshold; +} + +bool +tile_has_snow_volcano (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Volcano) + return false; + + int overlays = tile->vtable->m43_Get_field_30 (tile); + return (overlays & 0x100000) != 0; +} + +bool +tile_has_snow_forest (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Forest) + return false; + + int overlays = tile->vtable->m43_Get_field_30 (tile); + return (overlays & 0x100000) != 0; +} + +bool +tile_matches_square_type (Tile * tile, enum SquareTypes type) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + switch (type) { + case SQ_SNOW_MOUNTAIN: + return tile_has_snow_mountain (tile); + case SQ_SNOW_VOLCANO: + return tile_has_snow_volcano (tile); + case SQ_SNOW_FOREST: + return tile_has_snow_forest (tile); + case SQ_RIVER: + return tile->vtable->m37_Get_River_Code (tile) != 0; + default: + return tile->vtable->m50_Get_Square_BaseType (tile) == type; + } +} + +bool +tile_matches_square_type_mask (Tile * tile, unsigned int mask) +{ + if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) + return false; + + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + unsigned int base_bit = square_type_mask_bit (base_type); + if ((base_bit != 0) && ((mask & base_bit) != 0)) + return true; + + enum SquareTypes const special_types[] = {SQ_RIVER, SQ_SNOW_MOUNTAIN, SQ_SNOW_VOLCANO, SQ_SNOW_FOREST}; + for (int i = 0; i < (int)ARRAY_LEN (special_types); i++) { + enum SquareTypes stype = special_types[i]; + unsigned int bit = square_type_mask_bit (stype); + if ((mask & bit) && tile_matches_square_type (tile, stype)) + return true; + } + + unsigned int mine_bit = district_buildable_mine_mask_bit (); + if ((mask & mine_bit) && tile->vtable->m18_Check_Mines (tile, __, 0)) + return true; + + unsigned int irrigation_bit = district_buildable_irrigation_mask_bit (); + if ((mask & irrigation_bit) && tile->vtable->m17_Check_Irrigation (tile, __, 0)) + return true; + + unsigned int lake_bit = district_buildable_lake_mask_bit (); + if ((mask & lake_bit) && tile_is_lake (tile)) + return true; + + return false; +} + +bool +tile_matches_overlay_mask (Tile * tile, unsigned int mask) +{ + if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) + return false; + + unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); + if ((mask & DOM_MINE) && ((overlays & TILE_FLAG_MINE) != 0)) + return true; + if ((mask & DOM_IRRIGATION) && ((overlays & 0x00000008) != 0)) + return true; + if ((mask & DOM_FORTRESS) && ((overlays & 0x00000010) != 0)) + return true; + if ((mask & DOM_BARRICADE) && ((overlays & 0x10000000) != 0)) + return true; + if ((mask & DOM_OUTPOST) && ((overlays & 0x80000000) != 0)) + return true; + if ((mask & DOM_RADAR_TOWER) && ((overlays & 0x40000000) != 0)) + return true; + if ((mask & DOM_AIRFIELD) && ((overlays & 0x20000000) != 0)) + return true; + if ((mask & DOM_JUNGLE) && tile_matches_square_type (tile, SQ_Jungle)) + return true; + if ((mask & DOM_FOREST) && tile_matches_square_type (tile, SQ_Forest)) + return true; + if ((mask & DOM_SWAMP) && tile_matches_square_type (tile, SQ_Swamp)) + return true; + if ((mask & DOM_RIVER) && tile_matches_square_type (tile, SQ_RIVER)) + return true; + + return false; +} + +bool +read_natural_wonder_terrain_type (struct string_slice const * s, enum SquareTypes * out_type) +{ + enum SquareTypes parsed; + if (! read_tile_terrain_type_value (s, &parsed)) + return false; + + switch (parsed) { + case SQ_Desert: + case SQ_Plains: + case SQ_Grassland: + case SQ_Jungle: + case SQ_Tundra: + case SQ_FloodPlain: + case SQ_Swamp: + case SQ_Hills: + case SQ_Mountains: + case SQ_Forest: + case SQ_Volcano: + case SQ_SNOW_MOUNTAIN: + case SQ_SNOW_FOREST: + case SQ_SNOW_VOLCANO: + case SQ_Coast: + case SQ_Sea: + case SQ_Ocean: + *out_type = parsed; + return true; + + default: + return false; + } +} + +bool +read_direction_value (struct string_slice const * s, enum direction * out_dir) +{ + if (s == NULL || out_dir == NULL) + return false; + + struct string_slice trimmed = trim_string_slice (s, 1); + if (trimmed.len <= 0) + return false; + + if (slice_matches_str (&trimmed, "northeast")) { *out_dir = DIR_NE; return true; } + else if (slice_matches_str (&trimmed, "east" )) { *out_dir = DIR_E; return true; } + else if (slice_matches_str (&trimmed, "southeast")) { *out_dir = DIR_SE; return true; } + else if (slice_matches_str (&trimmed, "south" )) { *out_dir = DIR_S; return true; } + else if (slice_matches_str (&trimmed, "southwest")) { *out_dir = DIR_SW; return true; } + else if (slice_matches_str (&trimmed, "west" )) { *out_dir = DIR_W; return true; } + else if (slice_matches_str (&trimmed, "northwest")) { *out_dir = DIR_NW; return true; } + else if (slice_matches_str (&trimmed, "north" )) { *out_dir = DIR_N; return true; } + else + return false; +} + +bool +read_barbarian_activity_override (struct string_slice const * s, enum barbarian_activity_override * out) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (trimmed.len <= 0) + return false; + + bool found = false; + char * extracted = extract_slice (s); + + struct { + char * str; + enum barbarian_activity_override value; + } possibilities[] = {{ .str = "none" , .value = BAO_NONE }, + { .str = (*p_labels)[LBL_NO_BARBARIANS ], .value = BAO_NO_BARBARIANS }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 1], .value = BAO_SEDENTARY }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 2], .value = BAO_ROAMING }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 3], .value = BAO_RESTLESS }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 4], .value = BAO_RAGING }, + { .str = (*p_labels)[LBL_RANDOM_BARBS] , .value = BAO_RANDOM }, + { .str = "No Barbarians" , .value = BAO_NO_BARBARIANS }, + { .str = "Sedentary" , .value = BAO_SEDENTARY }, + { .str = "Roaming" , .value = BAO_ROAMING }, + { .str = "Restless" , .value = BAO_RESTLESS }, + { .str = "Raging" , .value = BAO_RAGING }, + { .str = "Random" , .value = BAO_RANDOM }}; + + // Check for exact match + for (int n = 0; n < ARRAY_LEN (possibilities); n++) + if (0 == strcmp (extracted, possibilities[n].str)) { + *out = possibilities[n].value; + found = true; + break; + } + + // If not found, check again ignoring case + if (! found) + for (int n = 0; n < ARRAY_LEN (possibilities); n++) + if (0 == _stricmp (extracted, possibilities[n].str)) { + *out = possibilities[n].value; + found = true; + break; + } + + free (extracted); + return found; +} + +struct parsable_field_bit { + char * name; + int bit_value; +}; + +bool +read_bit_field (struct string_slice const * s, struct parsable_field_bit const * bits, int count_bits, int * out_field) +{ + struct string_slice trimmed = trim_string_slice (s, 0); + s = &trimmed; + + int tr; + if (s->len <= 0) + tr = 0; + else if (slice_matches_str (s, "all")) + tr = ~0; + else { + tr = 0; + char * cursor = &s->str[0]; + char * s_end = &s->str[s->len]; + while (1) { + struct string_slice name; + + if (cursor >= s_end) + break; + else if (! parse_string (&cursor, &name)) { + skip_white_space (&cursor); + if (cursor >= s_end) + break; + else + return false; // Invalid character in value + } + + bool matched_any = false; + for (int n = 0; n < count_bits; n++) + if (slice_matches_str (&name, bits[n].name)) { + tr |= bits[n].bit_value; + matched_any = true; + break; + } + if (! matched_any) + return false; + } + } + *out_field = tr; + return true; +} + +int +read_units_per_tile_limit (struct string_slice const * s, int * out_limits) +{ + int single_val; + if (read_int (s, &single_val)) { + out_limits[0] = out_limits[1] = out_limits[2] = single_val; + return true; + + } else { + bool success = false; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + int vals[3]; + if (parse_int (&cursor, &vals[0]) && parse_int (&cursor, &vals[1]) && parse_int (&cursor, &vals[2]) && + skip_horiz_space (&cursor) && (*cursor == '\0')) { + for (int n = 0; n < ARRAY_LEN (vals); n++) + out_limits[n] = vals[n]; + success = true; + } + free (extracted_slice); + return success; + } +} + +struct config_parsing { + char * file_path; + char * text; + char * cursor; + struct string_slice key; + int displayed_error_message; +}; + +enum config_parse_error { + CPE_GENERIC, + CPE_BAD_VALUE, + CPE_BAD_BOOL_VALUE, + CPE_BAD_INT_VALUE, + CPE_BAD_STACK_LIMIT_VALUE, + CPE_BAD_KEY +}; + +void +handle_config_error_at (struct config_parsing * p, char * error_loc, enum config_parse_error err) +{ + char err_msg[1000]; + if (! p->displayed_error_message) { + int line_no = 1; + for (char * c = p->text; c < error_loc; c++) + line_no += *c == '\n'; + + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); + snprintf (err_msg, sizeof err_msg, "Error reading \"%s\" on line %d.", p->file_path, line_no); + err_msg[(sizeof err_msg) - 1] = '\0'; + PopupForm_add_text (popup, __, err_msg, false); + + if (err == CPE_GENERIC) { + if (p->key.str != NULL) + snprintf (err_msg, sizeof err_msg, "^The last key successfully read was \"%.*s\".", p->key.len, p->key.str); + else + snprintf (err_msg, sizeof err_msg, "^Error occurred before any keys could be read."); + } else if (err == CPE_BAD_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid.", p->key.len, p->key.str); + else if (err == CPE_BAD_BOOL_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"true\" or \"false\".", p->key.len, p->key.str); + else if (err == CPE_BAD_INT_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected an integer.", p->key.len, p->key.str); + else if (err == CPE_BAD_STACK_LIMIT_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"false\", an integer, or a list of exactly three of those.", p->key.len, p->key.str); + else if (err == CPE_BAD_KEY) + snprintf (err_msg, sizeof err_msg, "^The key name \"%.*s\" is not recognized.", p->key.len, p->key.str); + err_msg[(sizeof err_msg) - 1] = '\0'; + PopupForm_add_text (popup, __, err_msg, false); + + patch_show_popup (popup, __, 0, 0); + p->displayed_error_message = 1; + } +} + +void +handle_config_error (struct config_parsing * p, enum config_parse_error err) +{ + handle_config_error_at (p, p->cursor, err); +} + +// Loads a config from the given file, layering it on top of is->current_config and appending its name to the list of loaded configs. Does NOT +// re-apply machine code edits. +void +load_config (char const * file_path, int path_is_relative_to_mod_dir) +{ + char err_msg[1000]; + struct c3x_config * cfg = &is->current_config; + + int full_path_size = 2 * MAX_PATH; + char * full_path = malloc (full_path_size); + if (path_is_relative_to_mod_dir) + snprintf (full_path, full_path_size, "%s\\%s", is->mod_rel_dir, file_path); + else + strncpy (full_path, file_path, full_path_size); + full_path[full_path_size - 1] = '\0'; + + char * text; { + char * utf8_text = file_to_string (full_path); + if (utf8_text == NULL) { + free (full_path); + return; + } + text = convert_from_utf8 (utf8_text, *p_code_page); + free (utf8_text); + if (text == NULL) { + snprintf (err_msg, sizeof err_msg, "Failed to re-encode contents of \"%s\". This file must contain UTF-8 text and only characters usable by Civ 3.", full_path); + err_msg[(sizeof err_msg) - 1] = '\0'; + pop_up_in_game_error (err_msg); + free (full_path); + return; + } + } + + struct perfume_spec_list { + struct perfume_spec * items; + int count; + } perfume_spec_lists[COUNT_PERFUME_KINDS] = {0}; + + struct parsed_unit_type_limit * parsed_unit_type_limits = NULL; + int parsed_unit_type_limit_count = 0; + + struct config_parsing p = { .file_path = full_path, .text = text, .cursor = text, .key = {0}, .displayed_error_message = 0 }; + struct error_line * unrecognized_lines = NULL; + while (1) { + skip_horiz_space (&p.cursor); + if (*p.cursor == '\0') + break; + else if (*p.cursor == '\n') + p.cursor++; // Continue to next line + else if (*p.cursor == ';') + skip_to_line_end (&p.cursor); // Skip comment line + else if (*p.cursor == '[') + skip_to_line_end (&p.cursor); // Skip section line + else if (parse_string (&p.cursor, &p.key) && skip_punctuation (&p.cursor, '=')) { // Parse key and equals sign + + struct string_slice value; + if (parse_string (&p.cursor, &value) || parse_bracketed_block (&p.cursor, &value)) { // Parse value + int ival, offset, recog_err_offset; + + // if key is for a boolean option + if (stable_look_up_slice (&is->boolean_config_offsets, &p.key, &offset)) { + if (read_int (&value, &ival)) + *((char *)cfg + offset) = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + + // if key is for an integer option + } else if (stable_look_up_slice (&is->integer_config_offsets, &p.key, &offset)) { + if (read_int (&value, &ival)) + *(int *)((byte *)cfg + offset) = ival; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + + // Handle city_work_radius separately from the other int options so we can clamp it and update the count var + } else if (slice_matches_str (&p.key, "city_work_radius")) { + if (read_int (&value, &ival)) { + cfg->city_work_radius = clamp (1, 7, ival); + is->workable_tile_count = workable_tile_counts[cfg->city_work_radius]; + } else + handle_config_error (&p, CPE_BAD_INT_VALUE); + + // if key is for something special + } else if (slice_matches_str (&p.key, "limit_units_per_tile")) { + if (! read_units_per_tile_limit (&value, &cfg->limit_units_per_tile[0])) + handle_config_error (&p, CPE_BAD_STACK_LIMIT_VALUE); + } else if (slice_matches_str (&p.key, "production_perfume") || slice_matches_str (&p.key, "perfume_specs")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct perfume_spec), + parse_production_perfume_spec, + (void **)&perfume_spec_lists[PK_PRODUCTION].items, + &perfume_spec_lists[PK_PRODUCTION].count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "technology_perfume")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct perfume_spec), + parse_technology_perfume_spec, + (void **)&perfume_spec_lists[PK_TECHNOLOGY].items, + &perfume_spec_lists[PK_TECHNOLOGY].count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "government_perfume")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct perfume_spec), + parse_government_perfume_spec, + (void **)&perfume_spec_lists[PK_GOVERNMENT].items, + &perfume_spec_lists[PK_GOVERNMENT].count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "building_prereqs_for_units")) { + if (0 <= (recog_err_offset = read_building_unit_prereqs (&value, &unrecognized_lines, &cfg->building_unit_prereqs))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "buildings_generating_resources")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct mill), + parse_mill, + (void **)&cfg->mills, + &cfg->count_mills))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_multi_start_extra_palaces")) { + if (! read_ai_multi_start_extra_palaces (&value, + &unrecognized_lines, + &cfg->ai_multi_start_extra_palaces, + &cfg->count_ai_multi_start_extra_palaces, + &cfg->ai_multi_start_extra_palaces_capacity)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_settler_perfume_on_founding")) { + if (! read_i31b (&value, &cfg->ai_settler_perfume_on_founding)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "land_retreat_rules")) { + if (! read_retreat_rules (&value, (int *)&cfg->land_retreat_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "sea_retreat_rules")) { + if (! read_retreat_rules (&value, (int *)&cfg->sea_retreat_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "draw_lines_using_gdi_plus")) { + if (! read_line_drawing_override (&value, (int *)&cfg->draw_lines_using_gdi_plus)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "double_minimap_size")) { + if (! read_minimap_doubling_mode (&value, (int *)&cfg->double_minimap_size)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "unit_cycle_search_criteria")) { + if (! read_unit_cycle_search_criteria (&value, (int *)&cfg->unit_cycle_search_criteria)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "override_no_ai_patrol")) { + if (! read_no_ai_patrol_override (&value, (int *)&cfg->override_no_ai_patrol)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "override_barbarian_activity_level_for_scenario_maps")) { + if (! read_barbarian_activity_override (&value, &cfg->override_barbarian_activity_level_for_scenario_maps)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "special_defensive_bombard_rules")) { + struct parsable_field_bit bits[] = { + {"lethal" , SDBR_LETHAL}, + {"not-invisible" , SDBR_NOT_INVISIBLE}, + {"aerial" , SDBR_AERIAL}, + {"blitz" , SDBR_BLITZ}, + {"docked-vs-land", SDBR_DOCKED_VS_LAND}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_defensive_bombard_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "special_zone_of_control_rules")) { + struct parsable_field_bit bits[] = { + {"lethal" , SZOCR_LETHAL}, + {"aerial" , SZOCR_AERIAL}, + {"amphibious" , SZOCR_AMPHIBIOUS}, + {"not-from-inside", SZOCR_NOT_FROM_INSIDE}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_zone_of_control_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "land_transport_rules")) { + struct parsable_field_bit bits[] = { + {"load-onto-boat" , LTR_LOAD_ONTO_BOAT}, + {"join-army" , LTR_JOIN_ARMY}, + {"no-defense-from-inside", LTR_NO_DEFENSE_FROM_INSIDE}, + {"no-escape" , LTR_NO_ESCAPE}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->land_transport_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "special_helicopter_rules")) { + struct parsable_field_bit bits[] = { + {"allow-on-carriers" , SHR_ALLOW_ON_CARRIERS}, + {"passenger-airdrop" , SHR_PASSENGER_AIRDROP}, + {"no-defense-from-inside", SHR_NO_DEFENSE_FROM_INSIDE}, + {"no-escape" , SHR_NO_ESCAPE}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_helicopter_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "work_area_limit")) { + if (! read_work_area_limit (&value, (int *)&cfg->work_area_limit)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "work_area_improvements")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct work_area_improvement), + parse_work_area_improvement, + (void **)&cfg->work_area_improvements, + &cfg->count_work_area_improvements))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "day_night_cycle_mode")) { + if (! read_day_night_cycle_mode (&value, (int *)&cfg->day_night_cycle_mode)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "distribution_hub_yield_division_mode")) { + if (! read_distribution_hub_yield_division_mode (&value, (int *)&cfg->distribution_hub_yield_division_mode)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_distribution_hub_build_strategy")) { + if (! read_ai_distribution_hub_build_strategy (&value, (int *)&cfg->ai_distribution_hub_build_strategy)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_auto_build_great_wall_strategy")) { + if (! read_ai_auto_build_great_wall_strategy (&value, (int *)&cfg->ai_auto_build_great_wall_strategy)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "great_wall_auto_build_wonder_name")) { + if (cfg->great_wall_auto_build_wonder_name != NULL) { + free (cfg->great_wall_auto_build_wonder_name); + cfg->great_wall_auto_build_wonder_name = NULL; + } + cfg->great_wall_auto_build_wonder_name = copy_trimmed_string_or_null (&value, 1); + cfg->great_wall_auto_build_wonder_improv_id = -1; + } else if (slice_matches_str (&p.key, "exclude_types_from_units_per_tile_limit")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->exclude_types_from_units_per_tile_limit)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "limit_defensive_retreat_on_water_to_types")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->limit_defensive_retreat_on_water_to_types)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ptw_like_artillery_targeting")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->ptw_arty_types)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "can_bombard_only_sea_tiles")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->can_bombard_only_sea_tiles)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "civ_aliases_by_era")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct civ_era_alias_list), + parse_civ_name_alias_list, + (void **)&cfg->civ_era_alias_lists, + &cfg->count_civ_era_alias_lists))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "leader_aliases_by_era")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct leader_era_alias_list), + parse_leader_name_alias_list, + (void **)&cfg->leader_era_alias_lists, + &cfg->count_leader_era_alias_lists))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "unit_limits")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct parsed_unit_type_limit), + parse_unit_type_limit, + (void **)&parsed_unit_type_limits, + &parsed_unit_type_limit_count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "aircraft_victory_animation")) { + struct string_slice trimmed = trim_string_slice (&value, 1); + bool value_ok = false; + if (slice_matches_str (&trimmed, "none")) { + if (cfg->aircraft_victory_animation != NULL) { + free (cfg->aircraft_victory_animation); + cfg->aircraft_victory_animation = NULL; + } + value_ok = true; + } else if (trimmed.len > 0) { + AnimationType unused; + if (find_animation_type_by_name (&trimmed, true, &unused)) { + if (cfg->aircraft_victory_animation != NULL) + free (cfg->aircraft_victory_animation); + cfg->aircraft_victory_animation = extract_slice (&trimmed); + value_ok = true; + } + } + if (! value_ok) + handle_config_error (&p, CPE_BAD_VALUE); + + // if key is for an obsolete option + } else if (slice_matches_str (&p.key, "patch_disembark_immobile_bug")) { + if (read_int (&value, &ival)) + cfg->patch_blocked_disembark_freeze = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "anarchy_length_reduction_percent")) { + if (read_int (&value, &ival)) + cfg->anarchy_length_percent = 100 - ival; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + } else if (slice_matches_str (&p.key, "adjust_minimum_city_separation")) { + if (read_int (&value, &ival)) + cfg->minimum_city_separation = ival + 1; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + } else if (slice_matches_str (&p.key, "reduce_max_escorts_per_ai_transport")) { + if (read_int (&value, &ival)) + cfg->max_ai_naval_escorts = 3 - ival; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + } else if (slice_matches_str (&p.key, "retreat_rules")) { + int rules; + if (read_retreat_rules (&value, &rules)) { + cfg->land_retreat_rules = rules; + cfg->sea_retreat_rules = rules; + } else + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "halve_ai_research_rate")) { + if (read_int (&value, &ival)) { + if (ival) // halving = true => set multiplier to 50, otherwise do nothing + cfg->ai_research_multiplier = 50; + } else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "enable_ai_two_city_start")) { + if (read_int (&value, &ival)) + cfg->ai_multi_city_start = (ival != 0) ? 2 : 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "polish_non_air_precision_striking")) { + if (read_int (&value, &ival)) + cfg->polish_precision_striking = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "promote_forbidden_palace_decorruption")) { + if (read_int (&value, &ival)) + cfg->promote_wonder_decorruption_effect = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "move_trade_net_object")) { + ; // No nothing. This setting no longer serves any purpose. + + // if key was previously misspelled + } else if (slice_matches_str (&p.key, "share_visibility_in_hoseat")) { + if (read_int (&value, &ival)) + cfg->share_visibility_in_hotseat = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "unit_group")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct unit_counter_group), + parse_unit_counter_group, + (void **)&cfg->unit_counter_groups, + &cfg->count_unit_counter_groups))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "counter_rule")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct counter_rule), + parse_counter_rule, + (void **)&cfg->counter_rules, + &cfg->count_counter_rules))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + + } else { + handle_config_error (&p, CPE_BAD_KEY); + } + + + } else { // Failed to parse value + handle_config_error (&p, CPE_BAD_VALUE); + skip_to_line_end (&p.cursor); + } + + } else { // Failed to categorize line + handle_config_error (&p, CPE_GENERIC); + skip_to_line_end (&p.cursor); + } + } + + if (cfg->warn_about_unrecognized_names && (unrecognized_lines != NULL)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "Unrecognized names in %s:", full_path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + for (struct error_line * line = unrecognized_lines; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + patch_show_popup (popup, __, 0, 0); + } + + // Copy perfume specs from lists to tables + for (int n = 0; n < COUNT_PERFUME_KINDS; n++) { + struct table * table = &cfg->perfume_specs[n]; + struct perfume_spec_list * list = &perfume_spec_lists[n]; + if (list->items != NULL) { + for (int k = 0; k < list->count; k++) { + struct perfume_spec * ps = &list->items[k]; + stable_insert (table, ps->name, ps->value); + } + free (list->items); + } + } + + // Copy unit type limits from list to table + if (parsed_unit_type_limits != NULL) { + for (int n = 0; n < parsed_unit_type_limit_count; n++) { + struct parsed_unit_type_limit * parsed_lim = &parsed_unit_type_limits[n]; + struct unit_type_limit * lim_values = malloc (sizeof *lim_values); + *lim_values = parsed_lim->limit; + stable_insert (&cfg->unit_limits, parsed_lim->name, (int)lim_values); + } + free (parsed_unit_type_limits); + } + + free (text); + free_error_lines (unrecognized_lines); + + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = full_path; + new_lcn->next = NULL; + + top_lcn->next = new_lcn; +} + +bool +tile_coords_from_ptr (Map * map, Tile * tile, int * out_x, int * out_y) +{ + if ((tile == NULL) || (tile == p_null_tile) || (map == NULL)) + return false; + + int tile_count = map->TileCount; + for (int index = 0; index < tile_count; index++) { + Tile * candidate = Map_get_tile (map, __, index); + if (candidate == tile) { + tile_index_to_coords (map, index, out_x, out_y); + return true; + } + } + + return false; +} + +int +get_pending_district_request_key (int city_id, int district_id) +{ + if ((city_id < 0) || (district_id < 0)) + return -1; + unsigned int key = ((unsigned int)city_id << 16) | (unsigned int)(district_id & 0xffff); + return (int)key; +} + +struct pending_district_request * +find_pending_district_request (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0)) + return NULL; + + int civ_id = city->Body.CivID; + int city_id = city->Body.ID; + int key = get_pending_district_request_key (city_id, district_id); + if (key < 0) + return NULL; + + int stored; + if (itable_look_up (&is->city_pending_district_requests[civ_id], key, &stored)) { + struct pending_district_request * req = (struct pending_district_request *)stored; + if ((req != NULL) && (req->civ_id == civ_id) && (req->city_id == city_id) && (req->district_id == district_id)) { + if (req->city != city) + req->city = city; + return req; + } + } + return NULL; +} + +struct pending_district_request * +create_pending_district_request (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return NULL; + + struct pending_district_request * existing = find_pending_district_request (city, district_id); + if (existing != NULL) + return existing; + + int civ_id = city->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) + return NULL; + + struct pending_district_request * req = (struct pending_district_request *)calloc (1, sizeof *req); + if (req == NULL) + return NULL; + + req->city = city; + req->city_id = city->Body.ID; + req->civ_id = civ_id; + req->district_id = district_id; + req->assigned_worker_id = -1; + req->target_x = -1; + req->target_y = -1; + req->worker_assigned_turn = 0; + + int key = get_pending_district_request_key (req->city_id, district_id); + if (key < 0) { + free (req); + return NULL; + } + + char ss[200]; + snprintf (ss, sizeof ss, "create_pending_district_request: Creating pending district request for city %s (ID %d) district ID %d with key %d\n", + city->Body.CityName, city->Body.ID, district_id, key); + (*p_OutputDebugStringA) (ss); + + itable_insert (&is->city_pending_district_requests[civ_id], key, (int)req); + return req; +} + +struct pending_district_request * +find_pending_district_request_by_coords (City * city_or_null, int tile_x, int tile_y, int district_id) +{ + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + + int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((civ_id < 0) || (civ_id >= 32)) + return NULL; + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req == NULL) continue; + if (req->district_id != district_id) continue; + if (city_or_null != NULL) { + int city_id = city_or_null->Body.ID; + if (req->city_id != city_id) + continue; + req->city = city_or_null; + req->civ_id = city_or_null->Body.CivID; + } + if ((req->target_x == tile_x) && (req->target_y == tile_y)) + return req; + } + return NULL; +} + +bool +is_tile_earmarked_for_district (int tile_x, int tile_y) +{ + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req == NULL) continue; + if ((req->target_x == tile_x) && (req->target_y == tile_y)) + return true; + } + return false; +} + +struct district_instance * +get_district_instance (Tile * tile) +{ + if (tile == NULL || tile == p_null_tile) + return NULL; + + int stored_ptr; + if (! itable_look_up (&is->district_tile_map, (int)tile, &stored_ptr)) + return NULL; + + struct district_instance * inst = (struct district_instance *)stored_ptr; + + if ((inst == NULL) || (inst->district_id < 0) || (inst->district_id >= is->district_count)) + return NULL; + + return inst; +} + +struct wonder_district_info * +get_wonder_district_info (Tile * tile) +{ + if (tile == NULL || tile == p_null_tile) + return NULL; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return NULL; + + return &inst->wonder_info; +} + +void +remove_district_instance (Tile * tile) +{ + if (tile == NULL || tile == p_null_tile) + return; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + free (inst); + itable_remove (&is->district_tile_map, (int)tile); + } +} + +void +district_instance_set_coords (struct district_instance * inst, int tile_x, int tile_y) +{ + if (inst == NULL) + return; + + // Normalize coordinates to map bounds for consistency + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + inst->tile_x = tile_x; + inst->tile_y = tile_y; +} + +struct district_instance * +ensure_district_instance (Tile * tile, int district_id, int tile_x, int tile_y) +{ + if (tile == NULL || tile == p_null_tile) + return NULL; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + return inst; + } + + inst = (struct district_instance *)calloc (1, sizeof(struct district_instance)); + if (inst == NULL) + return NULL; + + inst->state = DS_UNDER_CONSTRUCTION; + inst->district_id = district_id; + inst->built_by_civ_id = -1; + inst->completed_turn = -1; + + // Initialize wonder_info (only relevant for wonder districts) + inst->wonder_info.state = WDS_UNUSED; + inst->wonder_info.city = NULL; + inst->wonder_info.city_id = -1; + inst->wonder_info.wonder_index = -1; + inst->natural_wonder_info.natural_wonder_id = -1; + + district_instance_set_coords (inst, tile_x, tile_y); + itable_insert (&is->district_tile_map, (int)tile, (int)inst); + return inst; +} + +bool +district_instance_get_coords (struct district_instance * inst, Tile * tile, int * out_x, int * out_y) +{ + if ((inst == NULL) || (out_x == NULL) || (out_y == NULL)) + return false; + + int x = inst->tile_x; + int y = inst->tile_y; + if ((x >= 0) && (y >= 0)) { + *out_x = x; + *out_y = y; + return true; + } + + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile_coords_from_ptr (&p_bic_data->Map, tile, &x, &y)) { + district_instance_set_coords (inst, x, y); + *out_x = x; + *out_y = y; + return true; + } + + return false; +} + +struct natural_wonder_district_config const * +get_natural_wonder_config_by_id (int natural_wonder_id) +{ + if (! is->current_config.enable_natural_wonders) + return NULL; + if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) + return NULL; + return &is->natural_wonder_configs[natural_wonder_id]; +} + +void +assign_natural_wonder_to_tile (Tile * tile, int tile_x, int tile_y, int natural_wonder_id) +{ + if (! is->current_config.enable_natural_wonders) + return; + if ((tile == NULL) || (tile == p_null_tile)) + return; + if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) + return; + + if (get_natural_wonder_config_by_id (natural_wonder_id) == NULL) + return; + + struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, tile_x, tile_y); + if (inst == NULL) + return; + + inst->district_id = NATURAL_WONDER_DISTRICT_ID; + inst->state = DS_COMPLETED; + inst->natural_wonder_info.natural_wonder_id = natural_wonder_id; + set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); +} + +int +apply_district_bonus_entries (struct district_instance * inst, + struct district_bonus_list const * extras, + int district_id) +{ + if ((inst == NULL) || (extras == NULL) || (extras->count <= 0)) + return 0; + + int tile_x = inst->tile_x; + int tile_y = inst->tile_y; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return 0; + + int bonus = 0; + for (int i = 0; i < extras->count; i++) { + struct district_bonus_entry const * entry = &extras->entries[i]; + if (entry->type == DBET_TILE) { + if (tile_matches_square_type (tile, entry->tile_type)) + bonus += entry->bonus; + } else if (entry->type == DBET_BUILDING) { + if (entry->building_id >= 0 && + tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, entry->building_id)) + bonus += entry->bonus; + } + } + + return bonus; +} + +void +get_effective_district_yields (struct district_instance * inst, + struct district_config const * cfg, + int * out_food, + int * out_shields, + int * out_gold, + int * out_science, + int * out_culture, + int * out_happiness) +{ + int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; + + if (cfg != NULL && is->current_config.enable_districts) { + food = cfg->food_bonus; + shields = cfg->shield_bonus; + gold = cfg->gold_bonus; + science = cfg->science_bonus; + culture = cfg->culture_bonus; + happiness = cfg->happiness_bonus; + + int district_id = (inst != NULL) ? inst->district_id : -1; + food += apply_district_bonus_entries (inst, &cfg->food_bonus_extras, district_id); + shields += apply_district_bonus_entries (inst, &cfg->shield_bonus_extras, district_id); + gold += apply_district_bonus_entries (inst, &cfg->gold_bonus_extras, district_id); + science += apply_district_bonus_entries (inst, &cfg->science_bonus_extras, district_id); + culture += apply_district_bonus_entries (inst, &cfg->culture_bonus_extras, district_id); + happiness += apply_district_bonus_entries (inst, &cfg->happiness_bonus_extras, district_id); + } + + if (inst != NULL && is->current_config.enable_natural_wonders && inst->district_id == NATURAL_WONDER_DISTRICT_ID) { + struct natural_wonder_district_config const * nwcfg = get_natural_wonder_config_by_id (inst->natural_wonder_info.natural_wonder_id); + if (nwcfg != NULL) { + food += nwcfg->food_bonus; + shields += nwcfg->shield_bonus; + gold += nwcfg->gold_bonus; + science += nwcfg->science_bonus; + culture += nwcfg->culture_bonus; + happiness += nwcfg->happiness_bonus; + } + } + + if (out_food != NULL) + *out_food = food; + if (out_shields != NULL) + *out_shields = shields; + if (out_gold != NULL) + *out_gold = gold; + if (out_science != NULL) + *out_science = science; + if (out_culture != NULL) + *out_culture = culture; + if (out_happiness != NULL) + *out_happiness = happiness; +} + +int +natural_wonder_min_distance_sq (int x, + int y, + struct wonder_location const * placements, + int placement_count) +{ + if ((placements == NULL) || (placement_count <= 0)) + return INT_MAX; + + int best = INT_MAX; + for (int i = 0; i < placement_count; i++) { + int dx, dy; + compute_wrapped_deltas (x, y, placements[i].x, placements[i].y, &dx, &dy); + int dist_sq = dx * dx + dy * dy; + if (dist_sq < best) + best = dist_sq; + } + return best; +} + +bool +continent_has_natural_wonder (int continent_id, + struct wonder_location const * placements, + int placement_count) +{ + if (continent_id < 0) + return false; + if ((placements == NULL) || (placement_count <= 0)) + return false; + + for (int i = 0; i < placement_count; i++) { + Tile * placed_tile = tile_at (placements[i].x, placements[i].y); + if ((placed_tile == NULL) || (placed_tile == p_null_tile)) + continue; + int placed_continent_id = placed_tile->vtable->m46_Get_ContinentID (placed_tile); + if (placed_continent_id == continent_id) + return true; + } + + return false; +} + +bool +natural_wonder_candidate_list_push (struct natural_wonder_candidate_list * list, Tile * tile, int tile_x, int tile_y) +{ + if (list == NULL) + return false; + + if (list->count >= list->capacity) { + int new_capacity = (list->capacity > 0) ? (list->capacity * 2) : 8; + struct natural_wonder_candidate * grown = + (struct natural_wonder_candidate *)realloc (list->entries, new_capacity * sizeof *grown); + if (grown == NULL) + return false; + list->entries = grown; + list->capacity = new_capacity; + } + + struct natural_wonder_candidate * entry = &list->entries[list->count++]; + entry->tile = tile; + entry->x = (short)tile_x; + entry->y = (short)tile_y; + return true; +} + +bool +natural_wonder_tile_is_clear (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (tile->CityID >= 0) return false; + if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return false; + if (tile->vtable->m15_Check_Goody_Hut (tile, __, 0)) return false; + if (tile->vtable->m39_Get_Resource_Type (tile) >= 0) return false; + if (tile->vtable->m18_Check_Mines (tile, __, 0)) return false; + if (get_district_instance (tile) != NULL) return false; + + // Check if this tile is a starting location for any civ + int tile_index = (p_bic_data->Map.Width >> 1) * tile_y + ((tile_x >> 1) & 0x7FFF); + for (int civ = 0; civ < p_bic_data->Map.Civ_Count; civ++) { + if (p_bic_data->Map.Starting_Locations[civ] == tile_index) { + return false; + } + } + + return true; +} + +bool +district_exists_within_distance (int tile_x, int tile_y, int district_id, int civ_id, int min_distance) +{ + if ((district_id < 0) || (district_id >= is->district_count) || (min_distance < 0)) + return false; + + for (int dist = 0; dist <= min_distance; dist++) { + struct vertex { + int x, y; + } vertices[4] = { + {tile_x , tile_y - 2*dist}, + {tile_x + 2*dist, tile_y }, + {tile_x , tile_y + 2*dist}, + {tile_x - 2*dist, tile_y } + }; + + int edge_dirs[4] = {3, 5, 7, 1}; + int edge_len = (dist == 0) ? 1 : 2 * dist; + + for (int vert = 0; vert < 4; vert++) { + wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); + int dx, dy; + neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); + for (int j = 0; j < edge_len; j++) { + int cx = vertices[vert].x + j * dx; + int cy = vertices[vert].y + j * dy; + wrap_tile_coords (&p_bic_data->Map, &cx, &cy); + + Tile * tile = tile_at (cx, cy); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if ((civ_id >= 0) && (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id)) + continue; + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == district_id)) + return true; + } + } + } + + return false; +} + +void +detach_workers_from_request (struct pending_district_request * req) +{ + if (req == NULL) + return; + + int civ_id = req->civ_id; + if ((civ_id < 0) || (civ_id >= 32)) { + for (int civ = 0; civ < 32; civ++) { + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + if ((rec != NULL) && (rec->pending_req == req)) + rec->pending_req = NULL; + } + } + return; + } + + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + if ((rec != NULL) && (rec->pending_req == req)) + rec->pending_req = NULL; + } +} + +void +remove_pending_district_request (struct pending_district_request * req) +{ + if (req == NULL) + return; + + int civ_id = req->civ_id; + if ((civ_id < 0) || (civ_id >= 32)) + return; + + int key = get_pending_district_request_key (req->city_id, req->district_id); + + detach_workers_from_request (req); + + if ((req->target_x >= 0) && (req->target_y >= 0)) { + Tile * tile = tile_at (req->target_x, req->target_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && + (inst->district_id == req->district_id) && + (inst->state != DS_COMPLETED)) + remove_district_instance (tile); + } + } + + if (key >= 0) + itable_remove (&is->city_pending_district_requests[civ_id], key); + req->city = NULL; + req->city_id = -1; + req->civ_id = -1; + free (req); +} + +bool __fastcall +patch_Leader_impl_would_raze_city (Leader * this, int edx, City * city) +{ + return is->current_config.prevent_razing_by_players ? false : Leader_impl_would_raze_city (this, __, city); +} + +int __fastcall patch_Unit_get_max_move_points (Unit * this); + +// This function is used to fix a bug where the game would freeze when using disembark all on a transport that contained an immobile unit. The bug +// comes from the fact that the function to disembark all units loops continuously over units in the transport until there are none left that +// can be disembarked. The problem is the logic to check disembarkability erroneously reports immobile units as disembarkable when they're not, +// so the program gets stuck in an infinite loop. The fix affects the function that checks disembarkability, replacing a call to +// Unit_get_max_move_points with a call to the function below. This function returns zero for immobile units, causing the caller to report +// (correctly) that the unit cannot be disembarked. +int __fastcall +patch_Unit_get_max_move_points_for_disembarking (Unit * this) +{ + if (is->current_config.patch_blocked_disembark_freeze && + UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Immobile)) + return 0; + else + return patch_Unit_get_max_move_points (this); +} + +// Unit::move_to_adjacent_tile uses a separate "spend all remaining movement when disembarking" branch for land units moving from water to land. +// Bridge districts still look like water tiles to that stock logic, so stepping off a bridge can incorrectly consume the whole turn. When the +// wrapper around move_to_adjacent_tile detects bridge->land movement, it precomputes the correct spent-moves total and exposes it here. +int __fastcall +patch_Unit_get_max_move_points_for_bridge_exit (Unit * this) +{ + if ((this != NULL) && (this == is->move_spend_override_unit)) + return is->move_spend_override_value; + else + return patch_Unit_get_max_move_points (this); +} + +// This func implements GA remaining turns indicator. It intercepts a call to some kind of text processing function when it's called to process the +// text in the lower right (containing current research, GA status, & mobilization) and splices in the number of remaining GA turns if in a GA. +int __fastcall +patch_PCX_Image_process_tech_ga_status (PCX_Image * this, int edx, char * str) +{ + Leader * player = &leaders[p_main_screen_form->Player_CivID]; + if (is->current_config.show_golden_age_turns_remaining && + (*p_current_turn_no < player->Golden_Age_End)) { + int turns_left = player->Golden_Age_End - *p_current_turn_no; + char const * ga_label = (*p_labels)[LBL_GOLDEN_AGE]; + char const * ga_str_start = strstr (str, ga_label); + if (ga_str_start != NULL) { + char s[250]; + char const * ga_str_end = ga_str_start + strlen (ga_label); + snprintf (s, sizeof s, "%.*s (%d)%s", ga_str_end - str, str, turns_left, ga_str_end); + s[(sizeof s) - 1] = '\0'; + strncpy (str, s, sizeof s); + } + } + return PCX_Image_process_text (this, __, str); +} + +bool __fastcall +patch_Leader_is_tile_visible (Leader * this, int edx, int x, int y) +{ + Tile_Body * tile = &tile_at (x, y)->Body; + unsigned vis_bits = tile->FOWStatus | tile->V3 | tile->Visibility | tile->field_D0_Visibility; + if (vis_bits & (1 << this->ID)) + return true; + else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND + ((1 << this->ID) & *p_human_player_bits) && // "this" is a human player AND + (vis_bits & *p_human_player_bits)) // any human player has visibility on the tile + return true; + else + return false; +} + +bool __fastcall +patch_Main_Screen_Form_is_unit_visible_to_player (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * unit) +{ + return (unit->Body.CivID == this->Player_CivID) || patch_Leader_is_tile_visible (&leaders[this->Player_CivID], __, tile_x, tile_y); +} + +enum direction +reverse_dir (enum direction dir) +{ + enum direction const reversed[] = { + DIR_ZERO, // DIR_ZERO + DIR_SW , // DIR_NE + DIR_W , // DIR_E + DIR_NW , // DIR_SE + DIR_N , // DIR_S + DIR_NE , // DIR_SW + DIR_E , // DIR_W + DIR_SE , // DIR_NW + DIR_S , // DIR_N + }; + int n = (int)dir; + if ((n >= 0) && (n < ARRAY_LEN (reversed))) + return reversed[n]; + else + return DIR_ZERO; +} + +bool +direction_to_offset (enum direction dir, int * out_dx, int * out_dy) +{ + int dx = 0, dy = 0; + + switch (dir) { + case DIR_NE: dx = 1; dy = -1; break; + case DIR_E: dx = 2; dy = 0; break; + case DIR_SE: dx = 1; dy = 1; break; + case DIR_S: dx = 0; dy = 2; break; + case DIR_SW: dx = -1; dy = 1; break; + case DIR_W: dx = -2; dy = 0; break; + case DIR_NW: dx = -1; dy = -1; break; + case DIR_N: dx = 0; dy = -2; break; + case DIR_ZERO: + default: + return false; + } + + if (out_dx != NULL) + *out_dx = dx; + if (out_dy != NULL) + *out_dy = dy; + return true; +} + +int +direction_to_neighbor_bit (enum direction dir) +{ + switch (dir) { + case DIR_NE: return 1; + case DIR_E: return 2; + case DIR_SE: return 3; + case DIR_S: return 4; + case DIR_SW: return 5; + case DIR_W: return 6; + case DIR_NW: return 7; + case DIR_N: return 0; // Matches engine behaviour where neighbor index 8 maps to 0 + default: + return -1; + } +} + +bool +get_primary_river_direction (Tile * tile, enum direction * out_dir) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + char river_bits = tile->vtable->m37_Get_River_Code (tile); + if (river_bits == 0) + return false; + + enum direction dirs[] = {DIR_E, DIR_W, DIR_SE, DIR_NE, DIR_SW, DIR_NW, DIR_S, DIR_N}; + for (int i = 0; i < (int)ARRAY_LEN (dirs); i++) { + int bit = direction_to_neighbor_bit (dirs[i]); + if ((bit >= 0) && ((river_bits & (1 << bit)) != 0)) { + if (out_dir != NULL) + *out_dir = dirs[i]; + return true; + } + } + + return false; +} + +void +wrap_tile_coords (Map * map, int * x, int * y) +{ + if (map->Flags & 1) { + if (*x < 0) *x += map->Width; + else if (*x >= map->Width) *x -= map->Width; + } + if (map->Flags & 2) { + if (*y < 0) *y += map->Height; + else if (*y >= map->Height) *y -= map->Height; + } +} + +void +tile_index_to_coords (Map * map, int index, int * out_x, int * out_y) +{ + if ((index >= 0) && (index < map->TileCount)) { + int width = map->Width; + int double_row = index / width, double_row_rem = index % width; + if (double_row_rem < width/2) { + *out_x = 2 * double_row_rem; + *out_y = 2 * double_row; + } else { + *out_x = 1 + 2 * (double_row_rem - width/2); + *out_y = 2 * double_row + 1; + } + } else + *out_x = *out_y = -1; +} + +int +tile_coords_to_index (Map * map, int x, int y) +{ + if ((map == NULL) || (x < 0) || (y < 0) || (x >= map->Width) || (y >= map->Height)) + return -1; + + int width = map->Width; + int row = y / 2; + if ((y & 1) == 0) { + return row * width + (x / 2); + } else { + return row * width + (width / 2) + (x / 2); + } +} + +Tile * +tile_at_index (Map * map, int i) +{ + int x, y; + tile_index_to_coords (map, i, &x, &y); + return tile_at (x, y); +} + +void +get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y) +{ + int dx, dy; + neighbor_index_to_diff (neighbor_index, &dx, &dy); + *out_x = x + dx; + *out_y = y + dy; + wrap_tile_coords (map, out_x, out_y); +} + +Tile * __stdcall +tile_at_city_or_null (City * city_or_null) +{ + if (city_or_null) + return tile_at (city_or_null->Body.X, city_or_null->Body.Y); + else + return p_null_tile; +} + +Unit * +get_unit_ptr (int id) +{ + if ((p_units->Units != NULL) && + (id >= 0) && (id <= p_units->LastIndex)) { + Unit_Body * body = p_units->Units[id].Unit; + if (body != NULL) { + Unit * unit = (Unit *)((char *)body - offsetof (Unit, Body)); + if (unit != NULL) + return unit; + } + } + return NULL; +} + +bool +is_land_transport (Unit * unit) +{ + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + return type->Unit_Class == UTC_Land && type->Transport_Capacity > 0 && ! Unit_has_ability (unit, __, UTA_Army); +} + +bool +is_in_land_transport (Unit * unit) +{ + Unit * container = get_unit_ptr (unit->Body.Container_Unit); + return container != NULL && is_land_transport (container); +} + +// Checks if the unit is inside a transport (either helicopter or land transport) from which it is not allowed to defend according to the mod config. +bool +cannot_defend_inside_transport (Unit * unit) +{ + Unit * container = get_unit_ptr (unit->Body.Container_Unit); + if (container != NULL) { + if ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && is_land_transport (container)) + return true; + + if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return true; + } + return false; +} + +struct unit_tile_iter { + int id; + int item_index; + Unit * unit; +}; + +void +uti_next (struct unit_tile_iter * uti) +{ + if (((p_tile_units->Base.Items == NULL) || (uti->item_index < 0)) || + (uti->item_index > p_tile_units->Base.LastIndex)) { + uti->item_index = -1; + uti->id = p_tile_units->DefaultValue; + } else { + Base_List_Item * item = &p_tile_units->Base.Items[uti->item_index]; + uti->item_index = item->V; + uti->id = (int)item->Object; + } + uti->unit = get_unit_ptr (uti->id); +} + +struct unit_tile_iter +uti_init (Tile * tile) +{ + struct unit_tile_iter tr; + int tile_unit_id = tile->vtable->m40_get_TileUnit_ID (tile); + tr.id = TileUnits_TileUnitID_to_UnitID (p_tile_units, __, tile_unit_id, &tr.item_index); + tr.unit = get_unit_ptr (tr.id); + return tr; +} + +#define FOR_UNITS_ON(uti_name, tile) for (struct unit_tile_iter uti_name = uti_init (tile); uti_name.id != -1; uti_next (&uti_name)) + +bool +tile_has_enemy_unit (Tile * tile, int civ_id) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + if ((civ_id < 0) || (civ_id >= 32)) + return false; + + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit == NULL) || (unit->Body.Container_Unit >= 0)) + continue; + if (unit->Body.CivID == civ_id) + continue; + if (unit->vtable->is_enemy_of_civ (unit, __, civ_id, 0)) + return true; + } + + return false; +} + +struct citizen_iter { + int index; + Citizens * list; + Citizen_Base * ctzn; +}; + +void +ci_next (struct citizen_iter * ci) +{ + while (1) { + ci->index++; + if (ci->index > ci->list->LastIndex) { + ci->ctzn = NULL; + break; + } else { + Citizen_Body * body = ci->list->Items[ci->index].Body; + if ((body != NULL) && ((int)body != offsetof (Citizen_Base, Body))) { + ci->ctzn = (Citizen_Base *)((int)body - offsetof (Citizen_Base, Body)); + break; + } + } + } +} + +struct citizen_iter +ci_init (City * city) +{ + struct citizen_iter tr; + tr.index = -1; + tr.list = &city->Body.Citizens; + tr.ctzn = NULL; + if (city->Body.Citizens.Items != NULL) + ci_next (&tr); + return tr; +} + +#define FOR_CITIZENS_IN(ci_name, city) for (struct citizen_iter ci_name = ci_init (city); (ci_name.list->Items != NULL) && (ci_name.index <= ci.list->LastIndex); ci_next (&ci_name)) + +struct city_of_iter { + int city_id; + int civ_id; + City * city; +}; + +void +coi_next (struct city_of_iter * coi) +{ + coi->city_id++; + while (coi->city_id <= p_cities->LastIndex) { + City_Body * body = p_cities->Cities[coi->city_id].City; + if ((body != NULL) && ((int)body != offsetof (City, Body)) && (body->CivID == coi->civ_id)) { + coi->city = (City *)((char *)body - offsetof (City, Body)); + break; + } + coi->city_id++; + } +} + +struct city_of_iter +coi_init (int civ_id) +{ + struct city_of_iter tr = { .city_id = -1, .civ_id = civ_id, .city = NULL }; + if (p_cities->Cities != NULL) + coi_next (&tr); + else + tr.city_id = p_cities->LastIndex + 1; + return tr; +} + +#define FOR_CITIES_OF(coi_name, civ_id) for (struct city_of_iter coi_name = coi_init (civ_id); coi_name.city_id <= p_cities->LastIndex; coi_next (&coi_name)) + +struct tiles_around_iter { + int center_x, center_y; + int n, num_tiles; + Tile * tile; + int tile_x, tile_y; +}; + +void +tai_next (struct tiles_around_iter * tai) +{ + tai->tile = p_null_tile; + while ((tai->n < tai->num_tiles) && (tai->tile == p_null_tile)) { + tai->n += 1; + int tx, ty; + get_neighbor_coords (&p_bic_data->Map, tai->center_x, tai->center_y, tai->n, &tx, &ty); + if ((tx >= 0) && (tx < p_bic_data->Map.Width) && (ty >= 0) && (ty < p_bic_data->Map.Height)) { + tai->tile = tile_at (tx, ty); + tai->tile_x = tx; + tai->tile_y = ty; + } + } +} + +struct tiles_around_iter +tai_init (int num_tiles, int x, int y) +{ + struct tiles_around_iter tr; + tr.center_x = x; + tr.center_y = y; + tr.n = 0; + tr.num_tiles = num_tiles; + tr.tile = tile_at (x, y); + tr.tile_x = x; + tr.tile_y = y; + return tr; +} + +#define FOR_TILES_AROUND(tai_name, _num_tiles, _x, _y) for (struct tiles_around_iter tai_name = tai_init (_num_tiles, _x, _y); (tai_name.n < tai_name.num_tiles); tai_next (&tai_name)) + +enum work_area_iter_output_type { + WAIO_ANY, + WAIO_DISTRICTS, + WAIO_CITIES, +}; + +struct work_area_iter { + int center_x, center_y; + int n, num_tiles; + int civ_id; + int dx, dy; + int tile_x, tile_y; + Tile * tile; + City * city; + struct district_instance * district_inst; + enum work_area_iter_output_type output_type; + bool completed_districts_only; +}; + +void +wai_next (struct work_area_iter * wai) +{ + wai->tile = p_null_tile; + wai->district_inst = NULL; + while ((wai->n + 1) < wai->num_tiles) { + wai->n += 1; + patch_ni_to_diff_for_work_area (wai->n, &wai->dx, &wai->dy); + wai->tile_x = wai->center_x + wai->dx; + wai->tile_y = wai->center_y + wai->dy; + wrap_tile_coords (&p_bic_data->Map, &wai->tile_x, &wai->tile_y); + Tile * candidate = tile_at (wai->tile_x, wai->tile_y); + if ((candidate == NULL) || (candidate == p_null_tile)) + continue; + if ((wai->civ_id < 0) || (candidate->vtable->m38_Get_Territory_OwnerID (candidate) != wai->civ_id)) + continue; + if (tile_has_enemy_unit (candidate, wai->civ_id)) + continue; + if (candidate->vtable->m20_Check_Pollution (candidate, __, 0)) + continue; + City * city; + if (wai->output_type == WAIO_CITIES) { + if (candidate->CityID < 0) + continue; + city = get_city_ptr (candidate->vtable->m45_Get_City_ID (candidate)); + if (city == NULL || city->Body.CivID != wai->civ_id) + continue; + } + struct district_instance * inst = get_district_instance (candidate); + if (wai->output_type == WAIO_DISTRICTS) { + if (inst == NULL) + continue; + int district_id = inst->district_id; + if (wai->completed_districts_only && (! district_is_complete (candidate, district_id))) + continue; + } + wai->city = city; + wai->district_inst = inst; + wai->tile = candidate; + break; + } + if (wai->tile == p_null_tile) + wai->n = wai->num_tiles; +} + +struct work_area_iter +wai_init_common (int x, int y, enum work_area_iter_output_type output, bool completed_districts_only) +{ + struct work_area_iter tr; + tr.center_x = x; + tr.center_y = y; + tr.n = -1; + tr.num_tiles = is->workable_tile_count; + Tile * center_tile = tile_at (x, y); + if ((center_tile == NULL) || (center_tile == p_null_tile)) + tr.civ_id = -1; + else + tr.civ_id = center_tile->vtable->m38_Get_Territory_OwnerID (center_tile); + tr.tile = p_null_tile; + tr.district_inst = NULL; + tr.dx = 0; + tr.dy = 0; + tr.tile_x = 0; + tr.tile_y = 0; + tr.output_type = output; + tr.completed_districts_only = completed_districts_only; + wai_next (&tr); + return tr; +} + +struct work_area_iter +wai_init (int x, int y) +{ + return wai_init_common (x, y, false, false); +} + +struct work_area_iter +wai_init_districts (int x, int y, bool completed_only) +{ + return wai_init_common (x, y, WAIO_DISTRICTS, completed_only); +} + +struct work_area_iter +wai_init_cities (int x, int y) +{ + struct work_area_iter tr = wai_init_common (x, y, WAIO_CITIES, false); + return tr; +} + +#define FOR_WORK_AREA_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) +#define FOR_DISTRICTS_AROUND(wai_name, _x, _y, _completed_only) for (struct work_area_iter wai_name = wai_init_districts (_x, _y, _completed_only); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) +#define FOR_CITIES_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init_cities (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) +#define FOR_AERODROMES_AROUND(unit_ptr) \ + for (struct table_entry_iter _tei = tei_init (&is->district_tile_map); \ + _tei.index < _tei.capacity; \ + tei_next (&_tei)) \ + for (Tile * aerodrome_tile = (Tile *)_tei.key; \ + (aerodrome_tile != NULL) && (aerodrome_tile != p_null_tile); \ + aerodrome_tile = NULL) \ + for (struct district_instance * aerodrome_inst = (struct district_instance *)_tei.value; \ + (aerodrome_inst != NULL) && \ + (aerodrome_inst->district_id == AERODROME_DISTRICT_ID) && \ + district_is_complete (aerodrome_tile, AERODROME_DISTRICT_ID); \ + aerodrome_inst = NULL) \ + for (int aerodrome_x = 0, aerodrome_y = 0; \ + district_instance_get_coords (aerodrome_inst, aerodrome_tile, &aerodrome_x, &aerodrome_y) && \ + (aerodrome_tile->vtable->m38_Get_Territory_OwnerID (aerodrome_tile) == (unit_ptr)->Body.CivID) && \ + patch_Unit_is_in_rebase_range ((unit_ptr), __, aerodrome_x, aerodrome_y); \ + aerodrome_x = 0, aerodrome_y = 0) + +struct tile_rings_iter { + int center_x, center_y; + int const * rings; + int ring_count; + int r_idx; + int ni; + int tile_x, tile_y; + int current_ring; + Tile * tile; +}; + +void +tri_next (struct tile_rings_iter * tri) +{ + tri->tile = p_null_tile; + while (tri->r_idx < tri->ring_count) { + int ring_no = tri->rings[tri->r_idx]; + if ((ring_no <= 0) || (ring_no >= 8)) { + tri->r_idx += 1; + tri->ni = -1; + continue; + } + int start_ni = workable_tile_counts[ring_no - 1]; + int end_ni = workable_tile_counts[ring_no]; + if (tri->ni < start_ni) + tri->ni = start_ni; + else if ((tri->ni + 1) < end_ni) + tri->ni += 1; + else { + tri->r_idx += 1; + tri->ni = -1; + continue; + } + tri->current_ring = ring_no; + int dx, dy; + patch_ni_to_diff_for_work_area (tri->ni, &dx, &dy); + int tx = tri->center_x + dx; + int ty = tri->center_y + dy; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + tri->tile_x = tx; + tri->tile_y = ty; + Tile * candidate = tile_at (tx, ty); + if ((candidate == NULL) || (candidate == p_null_tile)) + continue; + tri->tile = candidate; + break; + } + if (tri->tile == p_null_tile) { + tri->r_idx = tri->ring_count; + tri->ni = -1; + } +} + +struct tile_rings_iter +tri_init (int x, int y, int const * rings, int ring_count) +{ + struct tile_rings_iter tr; + tr.center_x = x; + tr.center_y = y; + tr.rings = rings; + tr.ring_count = ring_count; + tr.r_idx = 0; + tr.ni = -1; + tr.tile_x = 0; + tr.tile_y = 0; + tr.current_ring = 0; + tr.tile = p_null_tile; + tri_next (&tr); + return tr; +} + +#define FOR_TILE_RINGS_AROUND(tri_name, _x, _y, _rings, _ring_count) for (struct tile_rings_iter tri_name = tri_init (_x, _y, _rings, _ring_count); (tri_name.r_idx < tri_name.ring_count); tri_next (&tri_name)) + +bool +tile_square_type_is (Tile * tile, enum SquareTypes type) +{ + return tile_matches_square_type (tile, type); +} + +bool +district_is_buildable_on_tile (struct district_config const * cfg, Tile * tile) +{ + if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + unsigned int mask = cfg->buildable_square_types_mask; + if (mask == 0) + mask = district_default_buildable_mask (); + + bool square_matches = tile_matches_square_type_mask (tile, mask); + bool overlay_allowed = false; + bool overlay_required = false; + + if (cfg->has_buildable_without_removal) + overlay_allowed = tile_matches_overlay_mask (tile, cfg->buildable_without_removal_mask); + + if (cfg->has_buildable_on_overlays) { + overlay_required = tile_matches_overlay_mask (tile, cfg->buildable_on_overlays_mask); + if (! overlay_required) + return false; + } + if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) + return false; + + if (! square_matches && ! overlay_allowed && ! overlay_required) + return false; + + if (cfg->has_buildable_on_districts) { + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + + int existing_district_id = inst->district_id; + if (! district_is_complete (tile, existing_district_id)) + return false; + + bool matches = false; + for (int i = 0; i < cfg->buildable_on_district_id_count; i++) { + if (cfg->buildable_on_district_ids[i] == existing_district_id) { + matches = true; + break; + } + } + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to || cfg->has_buildable_adjacent_to_districts || cfg->has_buildable_adjacent_to_overlays) { + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + return false; + + if (cfg->has_buildable_adjacent_to) { + bool matches = false; + bool city_adjacent = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (Tile_has_city (tai.tile)) { + city_adjacent = true; + if (cfg->buildable_adjacent_to_allows_city) + matches = true; + } + if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) + matches = true; + if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) + break; + } + if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) + return false; + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to_overlays) { + bool matches = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { + matches = true; + break; + } + } + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to_districts) { + bool matches = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + struct district_instance * adj_inst = get_district_instance (tai.tile); + if (adj_inst == NULL) + continue; + int adj_district_id = adj_inst->district_id; + if (! district_is_complete (tai.tile, adj_district_id)) + continue; + for (int i = 0; i < cfg->buildable_adjacent_to_district_id_count; i++) { + if (cfg->buildable_adjacent_to_district_ids[i] == adj_district_id) { + matches = true; + break; + } + } + if (matches) + break; + } + if (! matches) + return false; + } + } + + return true; +} + +bool +is_coastal_island (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile->vtable->m35_Check_Is_Water (tile)) + return false; + + bool has_neighbor = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + return false; + + has_neighbor = true; + if (! adj->vtable->m35_Check_Is_Water (adj)) + return false; + + if (adj->vtable->m50_Get_Square_BaseType (adj) != SQ_Coast) + return false; + } + + return has_neighbor; +} + +bool +natural_wonder_adjacent_requirement_met (struct natural_wonder_district_config const * cfg, + Tile * tile, + int tile_x, + int tile_y) +{ + enum SquareTypes required = cfg->adjacent_to; + if (required == (enum SquareTypes)SQ_INVALID) + return true; + + if (required == SQ_RIVER) { + char river_bits = tile->vtable->m37_Get_River_Code (tile); + if (cfg->adjacency_dir != DIR_ZERO) { + int bit = direction_to_neighbor_bit (cfg->adjacency_dir); + if (bit < 0) + return false; + return (river_bits & (1 << bit)) != 0; + } else + return river_bits != 0; + } + + if (cfg->adjacency_dir != DIR_ZERO) { + int dx, dy; + if (! direction_to_offset (cfg->adjacency_dir, &dx, &dy)) + return false; + int nx = tile_x + dx; + int ny = tile_y + dy; + wrap_tile_coords (&p_bic_data->Map, &nx, &ny); + Tile * neighbor = tile_at (nx, ny); + return tile_square_type_is (neighbor, required); + } + + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_square_type_is (tai.tile, required)) + return true; + } + + return false; +} + +int +count_diagonal_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) +{ + if (type == (enum SquareTypes)SQ_INVALID) + return 0; + + enum direction dirs[4] = {DIR_NE, DIR_NW, DIR_SE, DIR_SW}; + int count = 0; + for (int i = 0; i < 4; i++) { + int dx, dy; + if (! direction_to_offset (dirs[i], &dx, &dy)) + continue; + int nx = tile_x + dx; + int ny = tile_y + dy; + wrap_tile_coords (&p_bic_data->Map, &nx, &ny); + Tile * neighbor = tile_at (nx, ny); + if (tile_square_type_is (neighbor, type)) + count += 1; + } + return count; +} + +int +count_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) +{ + if (type == (enum SquareTypes)SQ_INVALID) + return 0; + + int count = 0; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_square_type_is (tai.tile, type)) + count += 1; + } + return count; +} + +bool +natural_wonder_terrain_matches (struct natural_wonder_district_config const * cfg, Tile * tile, int tile_x, int tile_y) +{ + if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + if (! tile_matches_square_type (tile, cfg->terrain_type)) + return false; + + if (cfg->terrain_type == SQ_Coast) { + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + return false; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + if ((continent == NULL) || (continent->Body.TileCount <= 5)) + return false; + } + + if (is_coastal_island (tile, tile_x, tile_y)) + return false; + + if ((cfg->adjacent_to != SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 0)) + return false; + + if ((cfg->adjacent_to == SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 4)) + return false; + + if (! natural_wonder_adjacent_requirement_met (cfg, tile, tile_x, tile_y)) + return false; + + return true; +} + +struct district_worker_record * +get_tracked_worker_record (Unit * worker) +{ + if (worker == NULL) return NULL; + int civ_id = worker->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) return NULL; + + int value; + if (itable_look_up (&is->district_worker_tables[civ_id], worker->Body.ID, &value)) + return (struct district_worker_record *)value; + return NULL; +} + +struct district_worker_record * +ensure_tracked_worker_record (Unit * worker) +{ + if (worker == NULL) return NULL; + int civ_id = worker->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) return NULL; + + struct district_worker_record * rec = get_tracked_worker_record (worker); + if (rec != NULL) return rec; + + rec = (struct district_worker_record *)calloc (1, sizeof *rec); + if (rec == NULL) return NULL; + + rec->worker = worker; + rec->unit_id = worker->Body.ID; + Tile * tile = tile_at (worker->Body.X, worker->Body.Y); + rec->continent_id = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m46_Get_ContinentID (tile) : -1; + rec->pending_req = NULL; + + itable_insert (&is->district_worker_tables[civ_id], worker->Body.ID, (int)rec); + return rec; +} + +void +remove_tracked_worker_record (int civ_id, int unit_id) +{ + if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) + return; + + int value; + if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) + return; + + struct district_worker_record * rec = (struct district_worker_record *)value; + if (rec->pending_req != NULL) { + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + } + + itable_remove (&is->district_worker_tables[civ_id], unit_id); + free (rec); +} + +void +clear_tracked_worker_assignment (struct district_worker_record * rec) +{ + if (rec == NULL) + return; + + if (rec->pending_req != NULL) { + if (rec->pending_req->assigned_worker_id == rec->unit_id) + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + } +} + +void +clear_tracked_worker_assignment_by_id (int civ_id, int unit_id) +{ + if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) + return; + + int value; + if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) + return; + + struct district_worker_record * rec = (struct district_worker_record *)value; + if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == unit_id)) + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + if ((rec->worker == NULL) || (get_unit_ptr (unit_id) == NULL)) + remove_tracked_worker_record (civ_id, unit_id); +} + +void +clear_all_tracked_workers (void) +{ + for (int civ = 0; civ < 32; civ++) { + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + if (rec == NULL) + continue; + if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == rec->unit_id)) + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + free (rec); + } + is->district_worker_tables[civ].len = 0; + if (is->district_worker_tables[civ].block != NULL) { + free (is->district_worker_tables[civ].block); + is->district_worker_tables[civ].block = NULL; + } + is->district_worker_tables[civ].capacity_exponent = 0; + } +} + +bool is_worker (Unit * unit) +{ + if (unit == NULL) + return false; + + int unit_type_id = unit->Body.UnitTypeID; + int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; + + if (worker_actions == 0 || !(worker_actions & (UCV_Build_Road | UCV_Build_Mine | UCV_Irrigate))) { + return false; + } + + return true; +} + +void +update_tracked_worker_for_unit (Unit * worker) +{ + if (worker == NULL || ! is->current_config.enable_districts) return; + + int civ_id = worker->Body.CivID; + int type_id = worker->Body.UnitTypeID; + if ((civ_id < 0) || (civ_id >= 32)) return; + if ((*p_human_player_bits & (1 << civ_id)) != 0) return; + + char ss[200]; + snprintf (ss, sizeof ss, "Updating tracked worker for unit %d of type %d\n", worker->Body.ID, type_id); + (*p_OutputDebugStringA) (ss); + + if (! is_worker (worker)) { + remove_tracked_worker_record(worker->Body.CivID, worker->Body.ID); + return; + } + + ensure_tracked_worker_record (worker); +} + +bool +assign_worker_to_district (struct pending_district_request * req, Unit * worker, City * city, int district_id, int tile_x, int tile_y) +{ + if (worker == NULL || city == NULL) + return false; + if (req == NULL) + return false; + + req->city = city; + req->city_id = city->Body.ID; + req->civ_id = city->Body.CivID; + req->assigned_worker_id = worker->Body.ID; + req->worker_assigned_turn = *p_current_turn_no; + req->target_x = tile_x; + req->target_y = tile_y; + worker->Body.Auto_CityID = city->Body.ID; + + char ss[200]; + snprintf (ss, sizeof ss, "assign_worker_to_district: Assigned worker unit %d to build district %d in city %s at (%d,%d)\n", + worker->Body.ID, district_id, city->Body.CityName, tile_x, tile_y); + (*p_OutputDebugStringA) (ss); + + struct district_worker_record * record = ensure_tracked_worker_record (worker); + if (record != NULL) { + record->pending_req = req; + } + + return ai_move_district_worker (worker, record); +} + +bool +worker_is_available_for_district (Unit * worker) +{ + if (worker == NULL) + return false; + + int civ_id = worker->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) return false; + if ((*p_human_player_bits & (1 << civ_id)) != 0) return false; + + int type_id = worker->Body.UnitTypeID; + if ((type_id < 0) || (type_id >= p_bic_data->UnitTypeCount)) return false; + + struct district_worker_record * record = get_tracked_worker_record (worker); + if (record == NULL) + return false; + + return record->pending_req == NULL; +} + +Unit * +find_best_worker_for_district (Leader * leader, City * city, int district_id, int target_x, int target_y) +{ + char ss[200]; + + if ((leader == NULL) || (city == NULL)) { + snprintf (ss, sizeof ss, "Invalid leader or city when finding best worker for district %d\n", district_id); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + int civ_id = leader->ID; + if ((civ_id < 0) || (civ_id >= 32)) { + snprintf (ss, sizeof ss, "Invalid civ_id %d when finding best worker for district %d\n", civ_id, district_id); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + if (is->district_worker_tables[civ_id].len == 0) { + snprintf (ss, sizeof ss, "No tracked workers for civ %d when finding best worker for district %d\n", civ_id, district_id); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + Tile * target_tile = tile_at (target_x, target_y); + if ((target_tile == NULL) || (target_tile == p_null_tile)) { + snprintf (ss, sizeof ss, "Invalid target tile (%d,%d) when finding best worker for district %d in city %s\n", + target_x, target_y, district_id, city->Body.CityName); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + int target_continent_id = target_tile->vtable->m46_Get_ContinentID (target_tile); + Unit * best_worker = NULL; + int best_dist = INT_MAX; + + snprintf (ss, sizeof ss, "Finding best worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); + (*p_OutputDebugStringA) (ss); + + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + + if (rec == NULL) { + continue; + } + + Unit * candidate_worker = get_unit_ptr (rec->unit_id); + if ((candidate_worker == NULL) || (candidate_worker->Body.CivID != civ_id)) { + remove_tracked_worker_record (civ_id, rec->unit_id); + continue; + } + rec->worker = candidate_worker; + + if (! worker_is_available_for_district (candidate_worker)) { + continue; + } + + Tile * worker_tile = tile_at (candidate_worker->Body.X, candidate_worker->Body.Y); + if ((worker_tile == NULL) || (worker_tile == p_null_tile)) { + continue; + } + + int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); + if ((target_continent_id >= 0) && (worker_continent_id != target_continent_id)) { + continue; + } + + int dist = compute_wrapped_chebyshev_distance (candidate_worker->Body.X, candidate_worker->Body.Y, target_x, target_y); + + if (dist < best_dist) { + best_worker = candidate_worker; + best_dist = dist; + if (dist == 0) + return best_worker; + } + } + + return best_worker; +} + +void +process_pending_district_request (Leader * leader, struct pending_district_request * req) +{ + if ((leader == NULL) || (req == NULL)) + return; + + City * city = get_city_ptr (req->city_id); + if (city == NULL) { + remove_pending_district_request (req); + return; + } + req->city = city; + + int district_id = req->district_id; + int civ_id = req->civ_id; + + if (city->Body.CivID != civ_id) { + clear_city_district_request (city, district_id); + return; + } + + if (district_id < 0 || district_id >= is->district_count) return; + + // Check if city already has the district if not a neighborhood or distribution hub + if (district_id != NEIGHBORHOOD_DISTRICT_ID && + district_id != DISTRIBUTION_HUB_DISTRICT_ID && + is->district_configs[district_id].allow_multiple == false && + city_has_required_district (city, district_id)) { + + // Clear the request + clear_city_district_request (city, district_id); + return; + } + + // Assigned worker is no longer valid; clear assignment + if (req->assigned_worker_id >= 0) { + Unit * assigned = get_unit_ptr (req->assigned_worker_id); + if (assigned != NULL) { + // Check if more than allowed turns have elapsed since assignment and worker is not at target tile + bool worker_at_target = (assigned->Body.X == req->target_x) && (assigned->Body.Y == req->target_y); + if ((*p_current_turn_no - req->worker_assigned_turn) > is->current_config.ai_city_district_max_build_wait_turns && !worker_at_target) { + clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); + req->assigned_worker_id = -1; + req->worker_assigned_turn = *p_current_turn_no; + } else { + return; + } + } else { + // Assigned worker is null, make sure we get a new one + clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); + req->assigned_worker_id = -1; + } + } + + struct district_instance * inst = NULL; + int target_x = 0; + int target_y = 0; + Tile * tile = find_tile_for_district (city, district_id, &target_x, &target_y); + if ((tile == NULL) || (tile == p_null_tile)) { + clear_city_district_request (city, district_id); + return; + } + wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); + + char ss[200]; + snprintf (ss, sizeof ss, "Assigning worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); + (*p_OutputDebugStringA) (ss); + + Unit * worker = find_best_worker_for_district (leader, city, district_id, target_x, target_y); + if (worker == NULL) + return; + + snprintf (ss, sizeof ss, "Found worker %d for district %d in city %s at (%d,%d)\n", + worker->Body.ID, district_id, city->Body.CityName, target_x, target_y); + (*p_OutputDebugStringA) (ss); + + assign_worker_to_district (req, worker, city, district_id, target_x, target_y); +} + +void +assign_workers_for_pending_districts (Leader * leader) +{ + if ((leader == NULL) || ! is->current_config.enable_districts) + return; + + int civ_id = leader->ID; + if ((civ_id < 0) || (civ_id >= 32)) + return; + + if ((*p_human_player_bits & (1 << civ_id)) != 0) + return; + + int pending_count = is->city_pending_district_requests[civ_id].len; + if (pending_count <= 0) + return; + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req == NULL) + continue; + + City * city = get_city_ptr (req->city_id); + if (city == NULL) { + remove_pending_district_request (req); + continue; + } + + req->city = city; + if (city->Body.CivID != req->civ_id) { + remove_pending_district_request (req); + continue; + } + + process_pending_district_request (leader, req); + } +} + +City * +find_closest_owned_city_for_tile (int civ_id, int tile_x, int tile_y) +{ + City * best_city = NULL; + int best_dist = INT_MAX; + + FOR_CITIES_OF (coi, civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + + int dist = compute_wrapped_chebyshev_distance (city->Body.X, city->Body.Y, tile_x, tile_y); + if (dist < best_dist) { + best_dist = dist; + best_city = city; + } + } + + return best_city; +} + +bool +ai_candidate_bridge_or_canal_is_buildable_for_civ (struct ai_candidate_bridge_or_canal_entry * entry, int civ_id, int * out_tile_index) +{ + if ((entry == NULL) || (entry->tile_count <= 0)) + return false; + + int pending_index = -1; + for (int ti = 0; ti < entry->tile_count; ti++) { + int tx = entry->tile_x[ti]; + int ty = entry->tile_y[ti]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (owner != civ_id) + return false; + if (tile->CityID >= 0) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + if (inst->district_id == entry->district_id) + continue; + if (inst->district_id == WONDER_DISTRICT_ID) + return false; + if (! is->current_config.ai_can_replace_existing_districts_with_canals) { + return false; + } + } + + if (pending_index < 0) + pending_index = ti; + } + + if (pending_index < 0) { + entry->completed = true; + return false; + } + + if (out_tile_index != NULL) + *out_tile_index = pending_index; + + return true; +} + +void +release_ai_candidate_bridge_or_canal_worker (struct ai_candidate_bridge_or_canal_entry * entry) +{ + if ((entry == NULL) || (entry->assigned_worker_id < 0)) + return; + + int civ_id = entry->pending_req.civ_id; + if ((civ_id >= 0) && (civ_id < 32)) + clear_tracked_worker_assignment_by_id (civ_id, entry->assigned_worker_id); + + entry->assigned_worker_id = -1; + entry->assigned_tile_index = -1; + entry->pending_req.city = NULL; + entry->pending_req.city_id = -1; + entry->pending_req.civ_id = -1; + entry->pending_req.district_id = -1; + entry->pending_req.assigned_worker_id = -1; + entry->pending_req.target_x = -1; + entry->pending_req.target_y = -1; + entry->pending_req.worker_assigned_turn = 0; +} + +void +reset_ai_candidate_bridge_or_canals (void) +{ + if (is->ai_candidate_bridge_or_canals != NULL) { + for (int i = 0; i < is->ai_candidate_bridge_or_canals_capacity; i++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[i]; + if (entry->tile_x != NULL) + free (entry->tile_x); + if (entry->tile_y != NULL) + free (entry->tile_y); + } + free (is->ai_candidate_bridge_or_canals); + is->ai_candidate_bridge_or_canals = NULL; + } + is->ai_candidate_bridge_or_canals_capacity = 0; + is->ai_candidate_bridge_or_canals_count = 0; + is->ai_candidate_bridge_or_canals_initialized = false; +} + +bool +tile_has_district_at (int tile_x, int tile_y, int district_id) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + return (inst != NULL) && (inst->district_id == district_id) && (district_is_complete (tile, district_id)); +} + +bool +tile_is_land (int civ_id, int tile_x, int tile_y, bool must_be_same_owner) +{ + if (must_be_same_owner && (civ_id <= 0)) + return false; + + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + return (tile != NULL) && (tile != p_null_tile) && (! tile->vtable->m35_Check_Is_Water (tile)) && + ((! must_be_same_owner) || (tile->Territory_OwnerID == civ_id)); +} + +bool +tile_is_water (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + return (tile != NULL) && (tile != p_null_tile) && (tile->vtable->m35_Check_Is_Water (tile)); +} + +bool +ensure_ai_candidate_bridge_or_canals_capacity (int required) +{ + if (required <= 0) + return true; + if (required <= is->ai_candidate_bridge_or_canals_capacity) + return true; + int new_capacity = (is->ai_candidate_bridge_or_canals_capacity > 0) ? is->ai_candidate_bridge_or_canals_capacity * 2 : 4; + if (new_capacity < required) + new_capacity = required; + struct ai_candidate_bridge_or_canal_entry * larger = (struct ai_candidate_bridge_or_canal_entry *)realloc ( + is->ai_candidate_bridge_or_canals, new_capacity * sizeof *larger); + if (larger == NULL) + return false; + for (int i = is->ai_candidate_bridge_or_canals_capacity; i < new_capacity; i++) { + struct ai_candidate_bridge_or_canal_entry * entry = &larger[i]; + entry->tile_x = NULL; + entry->tile_y = NULL; + entry->tile_capacity = 0; + entry->district_id = -1; + entry->owner_civ_id = -1; + entry->tile_count = 0; + entry->assigned_tile_index = -1; + entry->assigned_worker_id = -1; + entry->completed = false; + struct pending_district_request * req = &entry->pending_req; + req->city = NULL; + req->city_id = -1; + req->civ_id = -1; + req->district_id = -1; + req->assigned_worker_id = -1; + req->target_x = -1; + req->target_y = -1; + req->worker_assigned_turn = 0; + } + is->ai_candidate_bridge_or_canals = larger; + is->ai_candidate_bridge_or_canals_capacity = new_capacity; + return true; +} + +bool +canal_has_different_adjacent_seas (int tile_x, int tile_y, int civ_id) +{ + struct water_pair { + int dx1, dy1; + int dx2, dy2; + }; + + const struct water_pair pairs[] = { + { 1, -1, -1, 1 }, // NE + SW + { 1, 1, -1, -1 }, // SE + NW + }; + + Map * map = &p_bic_data->Map; + bool require_owner = (civ_id >= 0); + + for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { + int ax = tile_x + pairs[i].dx1; + int ay = tile_y + pairs[i].dy1; + wrap_tile_coords (map, &ax, &ay); + Tile * first = tile_at (ax, ay); + if ((first == NULL) || (first == p_null_tile)) + continue; + if (! first->vtable->m35_Check_Is_Water (first)) + continue; + if (require_owner && (first->vtable->m38_Get_Territory_OwnerID (first) != civ_id)) + continue; + + int bx = tile_x + pairs[i].dx2; + int by = tile_y + pairs[i].dy2; + wrap_tile_coords (map, &bx, &by); + Tile * second = tile_at (bx, by); + if ((second == NULL) || (second == p_null_tile)) + continue; + if (! second->vtable->m35_Check_Is_Water (second)) + continue; + if (require_owner && (second->vtable->m38_Get_Territory_OwnerID (second) != civ_id)) + continue; + + int sea_a = first->vtable->m46_Get_ContinentID (first); + int sea_b = second->vtable->m46_Get_ContinentID (second); + if ((sea_a >= 0) && (sea_b >= 0) && (sea_a != sea_b)) + return true; + } + + return false; +} + +// Check if two water tiles can reach each other via water within a radius, excluding a blocked tile +bool +water_tiles_connected_within_radius (int start_x, int start_y, int target_x, int target_y, int block_x, int block_y, int radius) +{ + // Simple BFS using a fixed-size visited array for tiles within radius + // workable_tile_counts[6] = 137 tiles for radius 6 + int max_tiles = 137; + int visited_x[137]; + int visited_y[137]; + int visited_count = 0; + int queue_x[137]; + int queue_y[137]; + int queue_head = 0; + int queue_tail = 0; + + queue_x[queue_tail] = start_x; + queue_y[queue_tail] = start_y; + queue_tail++; + visited_x[visited_count] = start_x; + visited_y[visited_count] = start_y; + visited_count++; + + while (queue_head < queue_tail) { + int cx = queue_x[queue_head]; + int cy = queue_y[queue_head]; + queue_head++; + + // Check 8 adjacent tiles + FOR_TILES_AROUND (tai, 9, cx, cy) { + if (tai.n == 0) + continue; + int nx = tai.tile_x; + int ny = tai.tile_y; + + // Found target + if (nx == target_x && ny == target_y) + return true; + + // Skip blocked tile (the isthmus) + if (nx == block_x && ny == block_y) + continue; + + // Check if within radius of original start + int dx = nx - start_x; + int dy = ny - start_y; + if (dx < 0) dx = -dx; + if (dy < 0) dy = -dy; + // Use Chebyshev distance approximation for hex grid + int dist = (dx + dy + ((dx > dy) ? dx : dy)) / 2; + if (dist > radius) + continue; + + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (! adj->vtable->m35_Check_Is_Water (adj)) + continue; + + // Check if already visited + bool already_visited = false; + for (int i = 0; i < visited_count; i++) { + if (visited_x[i] == nx && visited_y[i] == ny) { + already_visited = true; + break; + } + } + if (already_visited) + continue; + + // Add to queue and visited + if (visited_count < max_tiles && queue_tail < max_tiles) { + visited_x[visited_count] = nx; + visited_y[visited_count] = ny; + visited_count++; + queue_x[queue_tail] = nx; + queue_y[queue_tail] = ny; + queue_tail++; + } + } + } + return false; +} + +// Check if tile separates adjacent water tiles that are not connected within a small radius +bool +canal_has_same_sea_isthmus (int tile_x, int tile_y, int civ_id, int check_radius) +{ + // If another canal exists nearby, this isn't a unique isthmus target. + FOR_TILES_AROUND (tai, workable_tile_counts[2], tile_x, tile_y) { + if (tai.n == 0) + continue; + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + continue; + struct district_instance * adj_inst = get_district_instance (adj); + if ((adj_inst != NULL) && (adj_inst->district_id == CANAL_DISTRICT_ID)) + return false; + } + + // Check opposite diagonal water tiles that are not connected within radius 2 + struct water_pair { + int dx1, dy1; + int dx2, dy2; + }; + + const struct water_pair pairs[] = { + { 1, -1, -1, 1 }, // NE + SW + { 1, 1, -1, -1 }, // SE + NW + }; + + for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { + int ax = tile_x + pairs[i].dx1; + int ay = tile_y + pairs[i].dy1; + wrap_tile_coords (&p_bic_data->Map, &ax, &ay); + Tile * first = tile_at (ax, ay); + if ((first == NULL) || (first == p_null_tile)) + continue; + if (! first->vtable->m35_Check_Is_Water (first)) + continue; + + int bx = tile_x + pairs[i].dx2; + int by = tile_y + pairs[i].dy2; + wrap_tile_coords (&p_bic_data->Map, &bx, &by); + Tile * second = tile_at (bx, by); + if ((second == NULL) || (second == p_null_tile)) + continue; + if (! second->vtable->m35_Check_Is_Water (second)) + continue; + + if (! water_tiles_connected_within_radius ( + ax, ay, + bx, by, + tile_x, tile_y, 2)) { + return true; + } + } + return false; +} + +bool +bridge_tile_connects_two_continents (int tile_x, int tile_y, int civ_id) +{ + struct bridge_pair { + int dx1, dy1; + int dx2, dy2; + }; + + Map * map = &p_bic_data->Map; + const struct bridge_pair pairs[] = { + {0, -2, 0, 2}, + {-2, 0, 2, 0}, + {-1, -1, 1, 1}, + {-1, 1, 1, -1}, + }; + + bool require_owner = (civ_id >= 0); + + for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { + int ax = tile_x + pairs[i].dx1; + int ay = tile_y + pairs[i].dy1; + wrap_tile_coords (map, &ax, &ay); + if (! tile_is_land (civ_id, ax, ay, require_owner)) + continue; + Tile * first = tile_at (ax, ay); + if ((first == NULL) || (first == p_null_tile)) + continue; + + int bx = tile_x + pairs[i].dx2; + int by = tile_y + pairs[i].dy2; + wrap_tile_coords (map, &bx, &by); + if (! tile_is_land (civ_id, bx, by, require_owner)) + continue; + Tile * second = tile_at (bx, by); + if ((second == NULL) || (second == p_null_tile)) + continue; + + int cont_a = first->vtable->m46_Get_ContinentID (first); + int cont_b = second->vtable->m46_Get_ContinentID (second); + if ((cont_a >= 0) && (cont_b >= 0) && (cont_a != cont_b)) + return true; + } + + return false; +} + +bool +tile_point_in_block (int tile_x, int tile_y, int block_x0, int block_y0, int block_x1, int block_y1) +{ + return (tile_x >= block_x0) && (tile_x < block_x1) && (tile_y >= block_y0) && (tile_y < block_y1); +} + +bool +tile_is_coastal_water (int tile_x, int tile_y) +{ + Map * map = &p_bic_data->Map; + wrap_tile_coords (map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + if (! tile->vtable->m35_Check_Is_Water (tile)) + return false; + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + return base_type == SQ_Coast; +} + +bool +tile_exists_at (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + return (tile != NULL) && (tile != p_null_tile); +} + +bool +tile_is_reserved_in_district_tile_map (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + int existing = 0; + return itable_look_up (&is->district_tile_map, (int)tile, &existing); +} + +bool +tile_has_diagonal_water (int tile_x, int tile_y) +{ + Map * map = &p_bic_data->Map; + int const adj_dx[4] = { 1, 1, -1, -1 }; + int const adj_dy[4] = { -1, 1, -1, 1 }; + + for (int i = 0; i < 4; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * tile = tile_at (nx, ny); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m35_Check_Is_Water (tile)) + return true; + } + return false; +} + +bool +tile_part_of_existing_candidate (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if (entry->tile_count <= 0) + continue; + for (int ti = 0; ti < entry->tile_count; ti++) { + if ((entry->tile_x[ti] == tile_x) && (entry->tile_y[ti] == tile_y)) + return true; + } + } + return false; +} + +bool +tile_has_bridge_or_canal_nearby (int tile_x, int tile_y) +{ + FOR_TILES_AROUND (tai, workable_tile_counts[1], tile_x, tile_y) { + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + continue; + struct district_instance * inst = get_district_instance (adj); + if ((inst != NULL) && + ((inst->district_id == BRIDGE_DISTRICT_ID) || (inst->district_id == CANAL_DISTRICT_ID))) + return true; + if (tile_part_of_existing_candidate (tai.tile_x, tai.tile_y)) + return true; + } + return false; +} + +bool +add_ai_candidate_entry (int district_id, short owner_civ_id, short * xs, short * ys, int count) +{ + if (count <= 0) + return false; + if (! ensure_ai_candidate_bridge_or_canals_capacity (is->ai_candidate_bridge_or_canals_count + 1)) + return false; + + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[is->ai_candidate_bridge_or_canals_count]; + entry->tile_x = (short *)malloc (sizeof *entry->tile_x * count); + entry->tile_y = (short *)malloc (sizeof *entry->tile_y * count); + if ((entry->tile_x == NULL) || (entry->tile_y == NULL)) { + if (entry->tile_x != NULL) + free (entry->tile_x); + if (entry->tile_y != NULL) + free (entry->tile_y); + return false; + } + + entry->district_id = district_id; + entry->owner_civ_id = owner_civ_id; + entry->tile_count = (short)count; + entry->tile_capacity = count; + entry->assigned_tile_index = -1; + entry->assigned_worker_id = -1; + entry->completed = false; + for (int ti = 0; ti < count; ti++) { + entry->tile_x[ti] = xs[ti]; + entry->tile_y[ti] = ys[ti]; + } + + struct pending_district_request * req = &entry->pending_req; + req->city = NULL; + req->city_id = -1; + req->civ_id = owner_civ_id; + req->district_id = district_id; + req->assigned_worker_id = -1; + req->target_x = -1; + req->target_y = -1; + req->worker_assigned_turn = 0; + + is->ai_candidate_bridge_or_canals_count++; + return true; +} + +int +find_bridge_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, + int contiguous_limit, int candidate_capacity, + short * out_x, short * out_y, short * out_owner) +{ + const int dirs[4][2] = { + { 0, -2 }, { -2, 0 }, { -1, -1 }, { -1, 1 } + }; + + int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + if (candidate_capacity > 0 && max_len > candidate_capacity) + max_len = candidate_capacity; + + for (int length = 1; length <= max_len; length++) { + for (int ti = 0; ti < map->TileCount; ti++) { + int tx = -1; + int ty = -1; + tile_index_to_coords (map, ti, &tx, &ty); + if (! tile_point_in_block (tx, ty, block_x0, block_y0, block_x1, block_y1)) + continue; + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile_has_resource (tile)) + continue; + if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], tile)) + continue; + if (tile_is_reserved_in_district_tile_map (tx, ty)) + continue; + short owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + for (int di = 0; di < (int)(sizeof (dirs) / sizeof (dirs[0])); di++) { + int dx = dirs[di][0]; + int dy = dirs[di][1]; + int end_x = tx + dx * (length - 1); + int end_y = ty + dy * (length - 1); + wrap_tile_coords (map, &end_x, &end_y); + if (! tile_point_in_block (end_x, end_y, block_x0, block_y0, block_x1, block_y1)) + continue; + + bool ok = true; + for (int step = 0; step < length; step++) { + int cx = tx + dx * step; + int cy = ty + dy * step; + wrap_tile_coords (map, &cx, &cy); + if (! tile_point_in_block (cx, cy, block_x0, block_y0, block_x1, block_y1)) { + ok = false; + break; + } + if (! tile_exists_at (cx, cy)) { + ok = false; + break; + } + if (! tile_is_coastal_water (cx, cy)) { + ok = false; + break; + } + Tile * bridge_tile = tile_at (cx, cy); + if ((bridge_tile == NULL) || (bridge_tile == p_null_tile)) { + ok = false; + break; + } + if (tile_has_resource (bridge_tile)) { + ok = false; + break; + } + if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], bridge_tile)) { + ok = false; + break; + } + if (tile_has_bridge_or_canal_nearby (cx, cy)) { + ok = false; + break; + } + if (tile_is_reserved_in_district_tile_map (cx, cy)) { + ok = false; + break; + } + if (tile_part_of_existing_candidate (cx, cy)) { + ok = false; + break; + } + } + if (! ok) + continue; + + int land_ax = tx - dx; + int land_ay = ty - dy; + wrap_tile_coords (map, &land_ax, &land_ay); + if (! tile_point_in_block (land_ax, land_ay, block_x0, block_y0, block_x1, block_y1)) + continue; + if (! tile_exists_at (land_ax, land_ay)) + continue; + if (! tile_is_land (-1, land_ax, land_ay, false)) + continue; + Tile * land_a = tile_at (land_ax, land_ay); + if ((land_a == NULL) || (land_a == p_null_tile)) + continue; + + int land_bx = tx + dx * length; + int land_by = ty + dy * length; + wrap_tile_coords (map, &land_bx, &land_by); + if (! tile_point_in_block (land_bx, land_by, block_x0, block_y0, block_x1, block_y1)) + continue; + if (! tile_exists_at (land_bx, land_by)) + continue; + if (! tile_is_land (-1, land_bx, land_by, false)) + continue; + Tile * land_b = tile_at (land_bx, land_by); + if ((land_b == NULL) || (land_b == p_null_tile)) + continue; + + int cont_a = land_a->vtable->m46_Get_ContinentID (land_a); + int cont_b = land_b->vtable->m46_Get_ContinentID (land_b); + if ((cont_a < 0) || (cont_b < 0) || (cont_a == cont_b)) + continue; + + for (int step = 0; step < length; step++) { + int cx = tx + dx * step; + int cy = ty + dy * step; + wrap_tile_coords (map, &cx, &cy); + out_x[step] = (short)cx; + out_y[step] = (short)cy; + } + *out_owner = owner; + return length; + } + } + } + return 0; +} + +int +gather_canal_line (int start_x, int start_y, int dx, int dy, int limit, + int block_x0, int block_y0, int block_x1, int block_y1, + short * out_x, short * out_y) +{ + int effective_limit = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, limit); + + if (! tile_is_land (-1, start_x, start_y, false)) + return 0; + if (tile_part_of_existing_candidate (start_x, start_y)) + return 0; + + short back_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + short back_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + short forward_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + short forward_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + int back_count = 0; + int forward_count = 0; + int remaining = effective_limit - 1; + Map * map = &p_bic_data->Map; + + int cx = start_x; + int cy = start_y; + while ((remaining > 0) && (back_count < effective_limit)) { + int nx = cx - dx; + int ny = cy - dy; + wrap_tile_coords (map, &nx, &ny); + if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) + break; + if (! tile_is_land (-1, nx, ny, false)) + break; + if (tile_part_of_existing_candidate (nx, ny)) + break; + back_x[back_count] = (short)nx; + back_y[back_count] = (short)ny; + back_count++; + remaining--; + cx = nx; + cy = ny; + } + + cx = start_x; + cy = start_y; + while ((remaining > 0) && (forward_count < effective_limit)) { + int nx = cx + dx; + int ny = cy + dy; + wrap_tile_coords (map, &nx, &ny); + if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) + break; + if (! tile_is_land (-1, nx, ny, false)) + break; + if (tile_part_of_existing_candidate (nx, ny)) + break; + forward_x[forward_count] = (short)nx; + forward_y[forward_count] = (short)ny; + forward_count++; + remaining--; + cx = nx; + cy = ny; + } + + int write = 0; + for (int bi = back_count - 1; bi >= 0; bi--) { + out_x[write] = back_x[bi]; + out_y[write] = back_y[bi]; + write++; + } + out_x[write] = (short)start_x; + out_y[write] = (short)start_y; + write++; + for (int fi = 0; fi < forward_count; fi++) { + out_x[write] = forward_x[fi]; + out_y[write] = forward_y[fi]; + write++; + } + + return write; +} + +bool +cluster_connects_two_seas_or_isthmus (short * xs, short * ys, int count) +{ + for (int i = 0; i < count; i++) { + if (canal_has_different_adjacent_seas (xs[i], ys[i], -1)) + return true; + if (canal_has_same_sea_isthmus (xs[i], ys[i], -1, 2)) + return true; + } + return false; +} + +int +find_canal_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, + int contiguous_limit, int candidate_capacity, + short * out_x, short * out_y, short * out_owner) +{ + const int dir_dx[8] = { 0, 1, 2, 1, 0, -1, -2, -1 }; + const int dir_dy[8] = { -2, -1, 0, 1, 2, 1, 0, -1 }; + + int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + if (candidate_capacity > 0 && max_len > candidate_capacity) + max_len = candidate_capacity; + + int tile_count = map->TileCount; + int * visit = (int *)malloc (sizeof (*visit) * tile_count); + int * queue_x = (int *)malloc (sizeof (*queue_x) * tile_count); + int * queue_y = (int *)malloc (sizeof (*queue_y) * tile_count); + if ((visit == NULL) || (queue_x == NULL) || (queue_y == NULL)) { + if (visit != NULL) + free (visit); + if (queue_x != NULL) + free (queue_x); + if (queue_y != NULL) + free (queue_y); + return 0; + } + for (int i = 0; i < tile_count; i++) + visit[i] = 0; + + int visit_mark = 1; + + for (int length = 1; length <= max_len; length++) { + for (int ti = 0; ti < map->TileCount; ti++) { + int start_x = -1; + int start_y = -1; + tile_index_to_coords (map, ti, &start_x, &start_y); + if (! tile_point_in_block (start_x, start_y, block_x0, block_y0, block_x1, block_y1)) + continue; + if (! tile_is_land (-1, start_x, start_y, false)) + continue; + if (tile_part_of_existing_candidate (start_x, start_y)) + continue; + if (tile_has_bridge_or_canal_nearby (start_x, start_y)) + continue; + if (tile_is_reserved_in_district_tile_map (start_x, start_y)) + continue; + Tile * start_tile = tile_at (start_x, start_y); + if ((start_tile == NULL) || (start_tile == p_null_tile)) + continue; + if (tile_has_resource (start_tile)) + continue; + if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], start_tile)) + continue; + int continent_id = start_tile->vtable->m46_Get_ContinentID (start_tile); + if (continent_id < 0) + continue; + short owner = start_tile->vtable->m38_Get_Territory_OwnerID (start_tile); + + int stack_len = 1; + int dir_stack[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + int path_dir[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + out_x[0] = (short)start_x; + out_y[0] = (short)start_y; + dir_stack[0] = -1; + path_dir[0] = -1; + + while (stack_len > 0) { + int depth = stack_len - 1; + int cx = out_x[depth]; + int cy = out_y[depth]; + + if (depth + 1 == length) { + bool endpoints_ok = false; + if (length == 1) { + int ex = out_x[0]; + int ey = out_y[0]; + bool pair_ok = false; + if (tile_is_water (ex, ey - 2) && tile_is_water (ex, ey + 2)) pair_ok = true; + if (tile_is_water (ex - 2, ey) && tile_is_water (ex + 2, ey)) pair_ok = true; + if (tile_is_water (ex - 1, ey - 1) && tile_is_water (ex + 1, ey + 1)) pair_ok = true; + if (tile_is_water (ex - 1, ey + 1) && tile_is_water (ex + 1, ey - 1)) pair_ok = true; + if (pair_ok && tile_has_diagonal_water (ex, ey)) + endpoints_ok = true; + } else { + int first_dir = path_dir[1]; + int last_dir = path_dir[length - 1]; + int sx = out_x[0]; + int sy = out_y[0]; + int ex = out_x[length - 1]; + int ey = out_y[length - 1]; + bool start_water = tile_is_water (sx - dir_dx[first_dir], sy - dir_dy[first_dir]); + bool end_water = tile_is_water (ex + dir_dx[last_dir], ey + dir_dy[last_dir]); + if (start_water && end_water && + tile_has_diagonal_water (sx, sy) && + tile_has_diagonal_water (ex, ey)) + endpoints_ok = true; + } + + bool buildable = true; + if (endpoints_ok) { + for (int pi = 0; pi < length; pi++) { + Tile * path_tile = tile_at (out_x[pi], out_y[pi]); + if ((path_tile == NULL) || (path_tile == p_null_tile) || + tile_has_resource (path_tile) || + (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], path_tile)) || + tile_is_reserved_in_district_tile_map (out_x[pi], out_y[pi])) { + buildable = false; + break; + } + if (tile_has_bridge_or_canal_nearby (out_x[pi], out_y[pi])) { + buildable = false; + break; + } + } + } else { + buildable = false; + } + + if (buildable) { + // Collect adjacent land tiles for component checks + int adj_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; + int adj_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; + int adj_count = 0; + for (int pi = 0; pi < length; pi++) { + int px = out_x[pi]; + int py = out_y[pi]; + for (int di = 0; di < 8; di++) { + int nx = px + dir_dx[di]; + int ny = py + dir_dy[di]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_is_land (-1, nx, ny, false)) + continue; + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) + continue; + bool in_path = false; + for (int pj = 0; pj < length; pj++) { + if ((out_x[pj] == nx) && (out_y[pj] == ny)) { + in_path = true; + break; + } + } + if (in_path) + continue; + bool seen = false; + for (int aj = 0; aj < adj_count; aj++) { + if ((adj_x[aj] == nx) && (adj_y[aj] == ny)) { + seen = true; + break; + } + } + if (! seen && (adj_count < (int)(sizeof (adj_x) / sizeof (adj_x[0])))) { + adj_x[adj_count] = nx; + adj_y[adj_count] = ny; + adj_count++; + } + } + } + + if (adj_count >= 2) { + int best1 = 0; + int best2 = 0; + int min_land = is->current_config.ai_canal_eval_min_bisected_land_tiles; + if (min_land < 1) + min_land = 1; + visit_mark++; + if (visit_mark == 0) { + visit_mark = 1; + for (int i = 0; i < tile_count; i++) + visit[i] = 0; + } + + for (int ai = 0; ai < adj_count; ai++) { + int aidx = tile_coords_to_index (map, adj_x[ai], adj_y[ai]); + if ((aidx < 0) || (visit[aidx] == visit_mark)) + continue; + + int comp_size = 0; + int head = 0; + int tail = 0; + visit[aidx] = visit_mark; + queue_x[tail] = adj_x[ai]; + queue_y[tail] = adj_y[ai]; + tail++; + + while (head < tail) { + int qx = queue_x[head]; + int qy = queue_y[head]; + head++; + comp_size++; + for (int di = 0; di < 8; di++) { + int nx = qx + dir_dx[di]; + int ny = qy + dir_dy[di]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_is_land (-1, nx, ny, false)) + continue; + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) + continue; + bool blocked = false; + for (int pj = 0; pj < length; pj++) { + if ((out_x[pj] == nx) && (out_y[pj] == ny)) { + blocked = true; + break; + } + } + if (blocked) + continue; + int nidx = tile_coords_to_index (map, nx, ny); + if ((nidx < 0) || (visit[nidx] == visit_mark)) + continue; + visit[nidx] = visit_mark; + queue_x[tail] = nx; + queue_y[tail] = ny; + tail++; + } + } + + if (comp_size > best1) { + best2 = best1; + best1 = comp_size; + } else if (comp_size > best2) { + best2 = comp_size; + } + } + + if ((best1 >= min_land) && (best2 >= min_land)) { + *out_owner = owner; + free (visit); + free (queue_x); + free (queue_y); + return length; + } + } + } + dir_stack[depth] = -1; + stack_len--; + continue; + } + + int next_dir = dir_stack[depth] + 1; + bool advanced = false; + while (next_dir < 8) { + int ndx = dir_dx[next_dir]; + int ndy = dir_dy[next_dir]; + int nx = cx + ndx; + int ny = cy + ndy; + wrap_tile_coords (map, &nx, &ny); + dir_stack[depth] = next_dir; + + if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) { + next_dir++; + continue; + } + if (! tile_is_land (-1, nx, ny, false)) { + next_dir++; + continue; + } + if (tile_part_of_existing_candidate (nx, ny)) { + next_dir++; + continue; + } + if (tile_is_reserved_in_district_tile_map (nx, ny)) { + next_dir++; + continue; + } + Tile * next_tile = tile_at (nx, ny); + if ((next_tile == NULL) || (next_tile == p_null_tile)) { + next_dir++; + continue; + } + if (tile_has_resource (next_tile)) { + next_dir++; + continue; + } + if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], next_tile)) { + next_dir++; + continue; + } + if (tile_has_bridge_or_canal_nearby (nx, ny)) { + next_dir++; + continue; + } + if (next_tile->vtable->m46_Get_ContinentID (next_tile) != continent_id) { + next_dir++; + continue; + } + bool dup = false; + for (int pi = 0; pi < depth + 1; pi++) { + if ((out_x[pi] == nx) && (out_y[pi] == ny)) { + dup = true; + break; + } + } + if (dup) { + next_dir++; + continue; + } + + if (depth >= 1) { + int prev_dir = dir_stack[depth - 1]; + int diff = next_dir - prev_dir; + if (diff < 0) + diff += 8; + if (diff > 4) + diff = 8 - diff; + if (diff > 1) { + next_dir++; + continue; + } + } + + out_x[depth + 1] = (short)nx; + out_y[depth + 1] = (short)ny; + dir_stack[depth + 1] = -1; + path_dir[depth + 1] = next_dir; + stack_len++; + advanced = true; + break; + } + + if (! advanced) { + dir_stack[depth] = -1; + stack_len--; + } + } + } + } + + free (visit); + free (queue_x); + free (queue_y); + return 0; +} + +void +generate_ai_bridge_candidates_by_block (Map * map, int block_size, int contiguous_limit) +{ + if ((map == NULL) || (block_size <= 0)) + return; + + int width = map->Width; + int height = map->Height; + if ((width <= 0) || (height <= 0)) + return; + + if (block_size < 1) + block_size = 1; + + int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + + short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); + short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); + if ((candidate_x == NULL) || (candidate_y == NULL)) { + if (candidate_x != NULL) + free (candidate_x); + if (candidate_y != NULL) + free (candidate_y); + return; + } + + for (int base_y = 0; base_y < height; base_y += block_size) { + int block_y1 = base_y + block_size; + if (block_y1 > height) + block_y1 = height; + for (int base_x = 0; base_x < width; base_x += block_size) { + int block_x1 = base_x + block_size; + if (block_x1 > width) + block_x1 = width; + short owner = -1; + int count = find_bridge_candidate_in_block ( + map, base_x, base_y, block_x1, block_y1, + contiguous_limit, candidate_capacity, + candidate_x, candidate_y, &owner); + if (count <= 0) + continue; + if (! add_ai_candidate_entry (BRIDGE_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { + free (candidate_x); + free (candidate_y); + return; + } + } + } + + free (candidate_x); + free (candidate_y); +} + +void +generate_ai_canal_candidates_by_block (Map * map, int block_size, int contiguous_limit) +{ + if ((map == NULL) || (block_size <= 0)) + return; + + int width = map->Width; + int height = map->Height; + if ((width <= 0) || (height <= 0)) + return; + + if (block_size < 1) + block_size = 1; + + int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + + short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); + short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); + if ((candidate_x == NULL) || (candidate_y == NULL)) { + if (candidate_x != NULL) + free (candidate_x); + if (candidate_y != NULL) + free (candidate_y); + return; + } + + for (int base_y = 0; base_y < height; base_y += block_size) { + int block_y1 = base_y + block_size; + if (block_y1 > height) + block_y1 = height; + for (int base_x = 0; base_x < width; base_x += block_size) { + int block_x1 = base_x + block_size; + if (block_x1 > width) + block_x1 = width; + short owner = -1; + int count = find_canal_candidate_in_block ( + map, base_x, base_y, block_x1, block_y1, + contiguous_limit, candidate_capacity, + candidate_x, candidate_y, &owner); + if (count <= 0) + continue; + if (! add_ai_candidate_entry (CANAL_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { + free (candidate_x); + free (candidate_y); + return; + } + } + } + + free (candidate_x); + free (candidate_y); +} + +void +generate_ai_canal_and_bridge_targets () +{ + if (is->ai_candidate_bridge_or_canals_initialized) + return; + if ((! is->current_config.enable_canal_districts) && (! is->current_config.enable_bridge_districts)) + return; + + Map * map = &p_bic_data->Map; + int width = map->Width; + int height = map->Height; + if ((width <= 0) || (height <= 0)) + return; + + int block_size = is->current_config.ai_bridge_canal_eval_block_size; + if (block_size <= 0) + block_size = 10; + + if (is->current_config.enable_bridge_districts && is->current_config.ai_builds_bridges) { + generate_ai_bridge_candidates_by_block ( + map, + block_size, + is->current_config.max_contiguous_bridge_districts); + } + + if (is->current_config.enable_canal_districts && is->current_config.ai_builds_canals) { + generate_ai_canal_candidates_by_block ( + map, + block_size, + is->current_config.max_contiguous_canal_districts); + } + + is->ai_candidate_bridge_or_canals_initialized = true; +} + +void +assign_workers_for_ai_candidate_bridge_or_canals (Leader * leader) +{ + if ((leader == NULL) || (is->ai_candidate_bridge_or_canals_count <= 0)) + return; + + int civ_id = leader->ID; + if ((*p_human_player_bits & (1 << civ_id)) != 0) + return; + + if (! leader_can_build_district (leader, CANAL_DISTRICT_ID) && ! leader_can_build_district (leader, BRIDGE_DISTRICT_ID)) + return; + + if (! is->ai_candidate_bridge_or_canals_initialized) { + reset_ai_candidate_bridge_or_canals (); + generate_ai_canal_and_bridge_targets (); + } + + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if (entry->completed) + continue; + + int district_id = entry->district_id; + if ((district_id == CANAL_DISTRICT_ID) && (! is->current_config.enable_canal_districts)) continue; + if ((district_id == BRIDGE_DISTRICT_ID) && (! is->current_config.enable_bridge_districts)) continue; + if (! leader_can_build_district (leader, district_id)) continue; + + if (entry->assigned_worker_id >= 0) { + Unit * worker = get_unit_ptr (entry->assigned_worker_id); + if (worker == NULL) { + release_ai_candidate_bridge_or_canal_worker (entry); + } else if ((entry->assigned_tile_index >= 0) && (entry->assigned_tile_index < entry->tile_count)) { + int tx = entry->tile_x[entry->assigned_tile_index]; + int ty = entry->tile_y[entry->assigned_tile_index]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + Tile * tile = tile_at (tx, ty); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && inst->district_id == district_id && district_is_complete (tile, district_id)) { + release_ai_candidate_bridge_or_canal_worker (entry); + } + } + } + if (entry->assigned_worker_id >= 0) + continue; + } + + int target_idx = -1; + if (! ai_candidate_bridge_or_canal_is_buildable_for_civ (entry, civ_id, &target_idx)) { + release_ai_candidate_bridge_or_canal_worker (entry); + continue; + } + + if (target_idx < 0) + continue; + + City * city = find_closest_owned_city_for_tile (civ_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); + if (city == NULL) + continue; + + Unit * worker = find_best_worker_for_district (leader, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); + if (worker == NULL) + continue; + + memset (&entry->pending_req, 0, sizeof entry->pending_req); + entry->pending_req.district_id = district_id; + entry->pending_req.civ_id = civ_id; + if (! assign_worker_to_district (&entry->pending_req, worker, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx])) + continue; + + entry->assigned_worker_id = worker->Body.ID; + entry->assigned_tile_index = target_idx; + } +} + +void +recompute_city_yields_with_districts (City * city) +{ + if (city == NULL) + return; + + bool prev_flag = is->distribution_hub_refresh_in_progress; + is->distribution_hub_refresh_in_progress = true; + patch_City_recompute_yields_and_happiness (city); + is->distribution_hub_refresh_in_progress = prev_flag; +} + +enum UnitStateType __fastcall +patch_City_instruct_worker (City * this, int edx, int tile_x, int tile_y, bool param_3, Unit * worker) +{ + return City_instruct_worker (this, __, tile_x, tile_y, param_3, worker); +} + +int +find_wonder_config_index_by_improvement_id (int improv_id) +{ + if (improv_id < 0) + return -1; + + char ss[200]; + + for (int wi = 0; wi < is->wonder_district_count; wi++) { + int bid = -1; + if (stable_look_up (&is->building_name_to_id, is->wonder_district_configs[wi].wonder_name, &bid) && + (bid == improv_id)) { + return wi; + } + } + + return -1; +} + +void set_wonder_built_flag (int improv_id, bool is_built); + +unsigned int +wonder_buildable_square_type_mask (struct wonder_district_config const * cfg) +{ + if (cfg == NULL) + return district_default_buildable_mask (); + + unsigned int mask = cfg->buildable_square_types_mask; + if (mask == 0) + mask = district_default_buildable_mask (); + return mask; +} + +unsigned int +wonder_buildable_mask_for_improvement (int improv_id) +{ + int windex = find_wonder_config_index_by_improvement_id (improv_id); + if (windex < 0) + return district_default_buildable_mask (); + return wonder_buildable_square_type_mask (&is->wonder_district_configs[windex]); +} + +bool +wonder_is_buildable_on_square_type (struct wonder_district_config const * cfg, Tile * tile) +{ + if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + if (! tile_matches_square_type_mask (tile, wonder_buildable_square_type_mask (cfg))) + return false; + + if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) + return false; + + if (cfg->has_buildable_adjacent_to) { + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + return false; + + bool matches = false; + bool city_adjacent = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (Tile_has_city (tai.tile)) { + city_adjacent = true; + if (cfg->buildable_adjacent_to_allows_city) + matches = true; + } + if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) + matches = true; + if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) + break; + } + if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) + return false; + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to_overlays) { + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + return false; + + bool matches = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { + matches = true; + break; + } + } + if (! matches) + return false; + } + + return true; +} + +bool +wonder_is_buildable_on_tile (Tile * tile, int wonder_improv_id) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); + if (windex < 0) + return tile_matches_square_type_mask (tile, district_default_buildable_mask ()); + + return wonder_is_buildable_on_square_type (&is->wonder_district_configs[windex], tile); +} + +bool +wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id) +{ + if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) + return false; + if ((civ_id < 0) || (civ_id >= 32)) + return false; + + int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); + if (windex < 0) + return true; + + struct wonder_district_config const * cfg = &is->wonder_district_configs[windex]; + Leader * leader = &leaders[civ_id]; + + if (cfg->has_buildable_by_civs) { + bool civ_match = false; + if (cfg->buildable_by_civ_count > 0) { + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + for (int i = 0; i < cfg->buildable_by_civ_count; i++) { + char const * civ_name = cfg->buildable_by_civs[i]; + if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; + if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; + if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; + if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; + if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; + } + } + if (! civ_match) + return false; + } + + if (cfg->has_buildable_by_civ_traits) { + if (cfg->buildable_by_civ_traits_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL || race->vtable == NULL) + return false; + bool trait_match = false; + for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { + int trait_id = cfg->buildable_by_civ_traits_ids[i]; + if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { + trait_match = true; + break; + } + } + if (! trait_match) + return false; + } + + if (cfg->has_buildable_by_civ_govs) { + if (cfg->buildable_by_civ_govs_id_count <= 0) + return false; + int gov_id = leader->GovernmentType; + bool gov_match = false; + for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { + if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { + gov_match = true; + break; + } + } + if (! gov_match) + return false; + } + + if (cfg->has_buildable_by_civ_cultures) { + if (cfg->buildable_by_civ_cultures_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + int culture_id = race->CultureGroupID; + bool culture_match = false; + for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { + if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { + culture_match = true; + break; + } + } + if (! culture_match) + return false; + } + + return true; +} + +int +get_wonder_improvement_id_from_index (int windex) +{ + if ((windex < 0) || (windex >= is->wonder_district_count)) + return -1; + + char const * wonder_name = is->wonder_district_configs[windex].wonder_name; + if ((wonder_name == NULL) || (wonder_name[0] == '\0')) + return -1; + + int improv_id; + if (stable_look_up (&is->building_name_to_id, (char *)wonder_name, &improv_id)) + return improv_id; + else + return -1; +} + +void +remember_pending_building_order (City * city, int improvement_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (improvement_id < 0)) + return; + + if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) + return; + + itable_insert (&is->city_pending_building_orders, (int)city, improvement_id); +} + +bool +look_up_pending_building_order (City * city, int * out_improv_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (out_improv_id == NULL)) + return false; + + return itable_look_up (&is->city_pending_building_orders, (int)city, out_improv_id); +} + +void +forget_pending_building_order (City * city) +{ + if (! is->current_config.enable_districts || + (city == NULL)) + return; + + itable_remove (&is->city_pending_building_orders, (int)city); +} + +bool +is_wonder_or_small_wonder_already_being_built (City * city, int improv_id) +{ + if ((city == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) + return false; + + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) + return false; + + int civ_id = city->Body.CivID; + FOR_CITIES_OF (coi, civ_id) { + City * other_city = coi.city; + if ((other_city == NULL) || (other_city == city)) + continue; + + if ((other_city->Body.Order_Type == COT_Improvement) && + (other_city->Body.Order_ID == improv_id)) + return true; + } + + return false; +} + +struct district_building_prereq_list * +get_district_building_prereq_list (int improv_id) +{ + if (improv_id < 0) + return NULL; + + int stored = 0; + if (! itable_look_up (&is->district_building_prereqs, improv_id, &stored)) + return NULL; + return (struct district_building_prereq_list *)stored; +} + +bool +district_building_prereq_list_contains (struct district_building_prereq_list * list, int district_id) +{ + if ((list == NULL) || (district_id < 0)) + return false; + for (int i = 0; i < list->count; i++) { + if (list->district_ids[i] == district_id) + return true; + } + return false; +} + +void +add_district_building_prereq (int improv_id, int district_id) +{ + if ((improv_id < 0) || (district_id < 0)) + return; + + struct district_building_prereq_list * list = get_district_building_prereq_list (improv_id); + if (list == NULL) { + list = calloc (1, sizeof *list); + if (list == NULL) + return; + list->count = 0; + itable_insert (&is->district_building_prereqs, improv_id, (int)list); + } + + if (district_building_prereq_list_contains (list, district_id)) + return; + + if (list->count >= ARRAY_LEN (list->district_ids)) + return; + + list->district_ids[list->count++] = district_id; +} + +bool +city_has_river_district (City * city, int district_id) +{ + if (city == NULL) + return false; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if (wai.district_inst->district_id != district_id) + continue; + if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) + return true; + } + return false; +} + +bool +city_has_any_prereq_district_for_improvement (City * city, + struct district_building_prereq_list * list, + bool requires_river, + bool allow_wonder_district) +{ + if ((city == NULL) || (list == NULL)) + return false; + + for (int i = 0; i < list->count; i++) { + int district_id = list->district_ids[i]; + if (district_id < 0) + continue; + if (! allow_wonder_district && district_id == WONDER_DISTRICT_ID) + continue; + if (requires_river) { + if (city_has_river_district (city, district_id)) + return true; + } else if (city_has_required_district (city, district_id)) { + return true; + } + } + return false; +} + +int +pick_missing_district_for_improvement (City * city, struct district_building_prereq_list * list) +{ + if ((list == NULL) || (list->count <= 0)) + return -1; + + int fallback = -1; + for (int i = 0; i < list->count; i++) { + int district_id = list->district_ids[i]; + if (district_id < 0) + continue; + if (fallback < 0) + fallback = district_id; + if ((city != NULL) && leader_can_build_district (&leaders[city->Body.CivID], district_id)) + return district_id; + } + return fallback; +} + + +bool +district_is_complete(Tile * tile, int district_id) +{ + if ((tile == NULL) || (tile == p_null_tile) || + (district_id < 0) || (district_id >= is->district_count)) + return false; + + bool is_natural_wonder = (district_id == NATURAL_WONDER_DISTRICT_ID); + bool districts_disabled = ! is->current_config.enable_districts; + bool natural_wonders_disabled = ! is->current_config.enable_natural_wonders; + struct district_config const * cfg = &is->district_configs[district_id]; + + if (districts_disabled && (!is_natural_wonder || natural_wonders_disabled)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != district_id) + return false; + + // If already marked COMPLETED, just return true + if (inst->state == DS_COMPLETED) + return true; + + // State is UNDER_CONSTRUCTION - check if tile has mines now + bool has_mines = tile->vtable->m18_Check_Mines (tile, __, 0) != 0; + + if (! has_mines) { + // Still under construction - check if we should clean it up + bool worker_present = false; + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit != NULL) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { + worker_present = true; + break; + } + } + if (! worker_present) { + remove_district_instance (tile); + } + return false; + } + + // Mark as completed and run one-time side effects + inst->state = DS_COMPLETED; + inst->completed_turn = *p_current_turn_no; + + int tile_x, tile_y; + if (district_instance_get_coords (inst, tile, &tile_x, &tile_y)) { + set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + if (cfg->auto_add_road) { + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + if (! has_road) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_ROAD, tile_x, tile_y); + } + + if (cfg->auto_add_railroad) { + bool has_railroad = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; + if (! has_railroad) { + if ((territory_owner >= 0) && patch_Leader_can_do_worker_job (&leaders[territory_owner], __, WJ_Build_Railroad, tile_x, tile_y, 0)) { + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_RAILROAD, tile_x, tile_y); + } + } + } + + // Activate distribution hub if applicable + if (is->current_config.enable_distribution_hub_districts && + (district_id == DISTRIBUTION_HUB_DISTRICT_ID)) { + on_distribution_hub_completed (tile, tile_x, tile_y); + } + + // Remove forest/swamp if applicable + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + if ((base_type == SQ_Forest) || (base_type == SQ_Swamp)) { + int new_terrain_type = tile->vtable->m71_Check_Worker_Job (tile); + if (new_terrain_type >= 0) + Map_change_tile_terrain (&p_bic_data->Map, __, (enum SquareTypes)new_terrain_type, tile_x, tile_y); + } + + char ss[200]; + snprintf (ss, sizeof ss, "District %d completed at tile (%d,%d)\n", district_id, tile_x, tile_y); + (*p_OutputDebugStringA) (ss); + + // Check if this was an AI-requested district + struct pending_district_request * req = find_pending_district_request_by_coords (NULL, tile_x, tile_y, district_id); + if (req != NULL) { + City * requesting_city = get_city_ptr (req->city_id); + if (requesting_city != NULL) { + req->city = requesting_city; + snprintf (ss, sizeof ss, "District %d at tile (%d,%d) was ordered by city %s\n", + district_id, tile_x, tile_y, requesting_city->Body.CityName); + (*p_OutputDebugStringA) (ss); + + // Check if city has pending building order that depends on this district + int pending_improv_id; + if (look_up_pending_building_order (requesting_city, &pending_improv_id)) { + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (pending_improv_id); + if (district_building_prereq_list_contains (prereq_list, district_id)) { + snprintf (ss, sizeof ss, "City %s setting production to improvement %d\n", + requesting_city->Body.CityName, pending_improv_id); + (*p_OutputDebugStringA) (ss); + + // Check if another city is already building this wonder/small wonder + bool can_set_production = true; + if (is_wonder_or_small_wonder_already_being_built (requesting_city, pending_improv_id)) { + snprintf (ss, sizeof ss, "City %s cannot build improvement %d - already being built elsewhere\n", + requesting_city->Body.CityName, pending_improv_id); + (*p_OutputDebugStringA) (ss); + can_set_production = false; + } + + // Set city production to the pending improvement + if (can_set_production && City_can_build_improvement (requesting_city, __, pending_improv_id, false)) { + snprintf (ss, sizeof ss, "City %s can now build improvement %d\n", + requesting_city->Body.CityName, pending_improv_id); + (*p_OutputDebugStringA) (ss); + City_set_production (requesting_city, __, COT_Improvement, pending_improv_id, false); + } + + // Clear the pending building order + forget_pending_building_order (requesting_city); + } + } + + // Clear worker assignment so worker is freed up for other tasks + if (req->assigned_worker_id >= 0) { + snprintf (ss, sizeof ss, "Clearing worker assignment for unit %d\n", req->assigned_worker_id); + (*p_OutputDebugStringA) (ss); + int civ_id = req->civ_id; + clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); + } + } + + // Remove the pending district request + remove_pending_district_request (req); + } + } + + return true; +} + +void +mark_city_needs_district (City * city, int district_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (district_id < 0) || (district_id >= is->district_count)) + return; + + create_pending_district_request (city, district_id); +} + +void +set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return; + + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + + City * assigned_city = NULL; + int assigned_city_id = tile->Body.CityAreaID; + if (assigned_city_id >= 0) + assigned_city = get_city_ptr (assigned_city_id); + + if (assigned_city != NULL) { + int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, + assigned_city->Body.X, assigned_city->Body.Y, tile_x, tile_y, 1000); + bool removed_assignment = false; + if ((neighbor_index > 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) + removed_assignment = City_stop_working_tile (assigned_city, __, neighbor_index); + if (! removed_assignment) + tile->Body.CityAreaID = -1; + if (! removed_assignment) + recompute_city_yields_with_districts (assigned_city); + } else + tile->Body.CityAreaID = -1; + + if (p_cities->Cities != NULL) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city == NULL) || (city == assigned_city)) + continue; + int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, + city->Body.X, city->Body.Y, tile_x, tile_y, 1000); + if ((neighbor_index <= 0) || (neighbor_index >= ARRAY_LEN (is->ni_to_work_radius))) + continue; + int work_radius = is->ni_to_work_radius[neighbor_index]; + if ((work_radius < 0) || (work_radius > is->current_config.city_work_radius)) + continue; + recompute_city_yields_with_districts (city); + } + } +} + +struct distribution_hub_record * +get_distribution_hub_record (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + + int stored; + if (itable_look_up (&is->distribution_hub_records, (int)tile, &stored)) + return (struct distribution_hub_record *)stored; + else + return NULL; +} + +City * +get_connected_city_for_distribution_hub (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return NULL; + + Tile * tile = rec->tile; + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + + City * best_city = NULL; + int best_distance = INT_MAX; + int best_y = INT_MAX; + int best_x = INT_MAX; + int best_id = INT_MAX; + + FOR_CITIES_OF (coi, rec->civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, city, rec->tile_x, rec->tile_y)) + continue; + + int distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, city->Body.X, city->Body.Y); + if ((best_city == NULL) || + (distance < best_distance) || + ((distance == best_distance) && (city->Body.Y < best_y)) || + ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X < best_x)) || + ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X == best_x) && (city->Body.ID < best_id))) { + best_city = city; + best_distance = distance; + best_y = city->Body.Y; + best_x = city->Body.X; + best_id = city->Body.ID; + } + } + + return best_city; +} + +bool +distribution_hub_accessible_to_city (struct distribution_hub_record * rec, City * city) +{ + if ((rec == NULL) || (city == NULL)) + return false; + + if (city->Body.CivID != rec->civ_id) + return false; + + City * anchor_city = get_connected_city_for_distribution_hub (rec); + if (anchor_city == NULL) + return false; + + if (anchor_city == city) + return true; + + return Trade_Net_have_trade_connection (is->trade_net, __, anchor_city, city, rec->civ_id); +} + +void +get_distribution_hub_yields_for_city (City * city, int * out_food, int * out_shields) +{ + int food = 0; + int shields = 0; + + if ((city != NULL) && + is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts) { + if (is->distribution_hub_totals_dirty && + ! is->distribution_hub_refresh_in_progress) + recompute_distribution_hub_totals (); + + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (distribution_hub_accessible_to_city (rec, city)) { + food += rec->food_yield; + shields += rec->shield_yield; + } + } + } + + if (city_has_required_district (city, CENTRAL_RAIL_HUB_DISTRICT_ID)) { + food += (food * is->current_config.central_rail_hub_distribution_food_bonus_percent) / 100; + shields += (shields * is->current_config.central_rail_hub_distribution_shield_bonus_percent) / 100; + } + + if (out_food != NULL) + *out_food = food; + if (out_shields != NULL) + *out_shields = shields; +} + +void +adjust_distribution_hub_coverage (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return; + + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if ((area_tile == NULL) || (area_tile == p_null_tile)) + continue; + int tx = tai.tile_x; + int ty = tai.tile_y; + + if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) + continue; + if (Tile_has_city (area_tile)) + continue; + if (get_district_instance (area_tile) != NULL) + continue; + + struct wonder_district_info * area_info = get_wonder_district_info (area_tile); + if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) + continue; + + int key = (int)area_tile; + int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); + itable_insert (&is->distribution_hub_coverage_counts, key, prev + 1); + + if (area_tile->Body.CityAreaID >= 0) { + set_tile_unworkable_for_all_cities (area_tile, tx, ty); + area_tile->Body.CityAreaID = -1; + } + } +} + +void +release_distribution_hub_coverage (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return; + + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if ((area_tile == NULL) || (area_tile == p_null_tile)) + continue; + + int key = (int)area_tile; + int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); + if (prev <= 0) + continue; + + if (prev == 1) + itable_remove (&is->distribution_hub_coverage_counts, key); + else + itable_insert (&is->distribution_hub_coverage_counts, key, prev - 1); + } +} + +void +clear_distribution_hub_tables (void) +{ + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + free (rec); + } + table_deinit (&is->distribution_hub_records); + table_deinit (&is->distribution_hub_coverage_counts); + is->distribution_hub_totals_dirty = true; +} + +bool +city_radius_contains_tile (City * city, int tile_x, int tile_y) +{ + if (city == NULL) + return false; + + int ni = patch_Map_compute_ni_for_work_area (&p_bic_data->Map, __, city->Body.X, city->Body.Y, tile_x, tile_y, is->workable_tile_count); + return ni >= 0; +} + +void +recompute_distribution_hub_yields (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return; + + Tile * tile = tile_at (rec->tile_x, rec->tile_y); + rec->tile = tile; + + if ((tile == NULL) || + (tile == p_null_tile) || + ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID) || + tile->vtable->m20_Check_Pollution (tile, __, 0) || + tile_has_enemy_unit (tile, rec->civ_id)) { + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + return; + } + + int food_sum = 0; + int shield_sum = 0; + City * anchor_city = get_connected_city_for_distribution_hub (rec); + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if (area_tile == p_null_tile) + continue; + int tx = tai.tile_x; + int ty = tai.tile_y; + + // Only include tiles that belong to the distribution hub owner + if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) + continue; + + // Skip city tiles + if (Tile_has_city (area_tile)) + continue; + + // Skip tiles with enemy units + if (tile_has_enemy_unit (area_tile, rec->civ_id)) + continue; + + // Skip tiles with pollution + if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) + continue; + + // Skip tiles that are other districts (but not this hub itself) + struct district_instance * area_district = get_district_instance (area_tile); + if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) + continue; + + // Skip tiles with completed wonders + struct wonder_district_info * area_info = get_wonder_district_info (area_tile); + if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) + continue; + + // Check if another hub of the same civ is closer to this tile + int my_distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, tx, ty); + bool tile_belongs_to_me = true; + + FOR_TABLE_ENTRIES (other_tei, &is->distribution_hub_records) { + struct distribution_hub_record * other_rec = (struct distribution_hub_record *)other_tei.value; + if ((other_rec == NULL) || (other_rec == rec)) + continue; + if (other_rec->civ_id != rec->civ_id) + continue; + + int other_distance = compute_wrapped_manhattan_distance (other_rec->tile_x, other_rec->tile_y, tx, ty); + if (other_distance < my_distance) { + tile_belongs_to_me = false; + break; + } + if (other_distance == my_distance) { + // Tie-breaking: prefer hub with lower Y, then lower X + if (other_rec->tile_y < rec->tile_y) { + tile_belongs_to_me = false; + break; + } + if ((other_rec->tile_y == rec->tile_y) && (other_rec->tile_x < rec->tile_x)) { + tile_belongs_to_me = false; + break; + } + } + } + + if (! tile_belongs_to_me) + continue; + + food_sum += City_calc_tile_yield_at (anchor_city, __, 0, tx, ty); + shield_sum += City_calc_tile_yield_at (anchor_city, __, 1, tx, ty); + } + + rec->raw_food_yield = food_sum; + rec->raw_shield_yield = shield_sum; + + int food_div = is->current_config.distribution_hub_food_yield_divisor; + int shield_div = is->current_config.distribution_hub_shield_yield_divisor; + if (food_div <= 0) + food_div = 1; + if (shield_div <= 0) + shield_div = 1; + + int connected_city_count = 0; + if (anchor_city != NULL) { + FOR_CITIES_OF (coi, rec->civ_id) { + City * other_city = coi.city; + if ((other_city != NULL) && distribution_hub_accessible_to_city (rec, other_city)) + connected_city_count++; + } + } + if (connected_city_count <= 0) + connected_city_count = 1; + + if (is->current_config.distribution_hub_yield_division_mode == DHYDM_SCALE_BY_CITY_COUNT) { + int city_root = 1; + while ((city_root + 1) * (city_root + 1) <= connected_city_count) + city_root++; + int city_food_divisor = city_root * food_div; + int city_shield_divisor = city_root * shield_div; + if (city_food_divisor < 1) city_food_divisor = 1; + if (city_shield_divisor < 1) city_shield_divisor = 1; + rec->food_yield = food_sum / city_food_divisor; + rec->shield_yield = shield_sum / city_shield_divisor; + } else { + rec->food_yield = food_sum / food_div; + rec->shield_yield = shield_sum / shield_div; + } +} + +void +remove_distribution_hub_record (Tile * tile) +{ + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec == NULL) + return; + + int affected_civ_id = rec->civ_id; + release_distribution_hub_coverage (rec); + itable_remove (&is->distribution_hub_records, (int)tile); + free (rec); + is->distribution_hub_totals_dirty = true; + recompute_distribution_hub_totals (); + + // Recalculate yields for all cities of this civ + if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * target_city = get_city_ptr (city_index); + if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) + recompute_city_yields_with_districts (target_city); + } + } +} + +void +recompute_distribution_hub_totals () +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_distribution_hub_districts) { + is->distribution_hub_totals_dirty = false; + return; + } + + struct table new_coverage_counts = {0}; + struct table newly_covered_tiles = {0}; + + clear_memo (); + int civs_needing_recalc[32] = {0}; + + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + Tile * tile = (Tile *)tei.key; + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (rec == NULL) + continue; + + Tile * current_tile = tile_at (rec->tile_x, rec->tile_y); + if ((current_tile == NULL) || + (current_tile == p_null_tile) || + ! district_is_complete (current_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { + memoize (tei.key); + continue; + } + + rec->tile = current_tile; + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + + int old_civ_id = rec->civ_id; + rec->civ_id = current_tile->vtable->m38_Get_Territory_OwnerID (current_tile); + + if (old_civ_id != rec->civ_id) + civs_needing_recalc[old_civ_id] = 1; + civs_needing_recalc[rec->civ_id] = 1; + + City * anchor = get_connected_city_for_distribution_hub (rec); + + if ((anchor == NULL) || + current_tile->vtable->m20_Check_Pollution (current_tile, __, 0) || + tile_has_enemy_unit (current_tile, rec->civ_id)) + continue; + + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if (area_tile == p_null_tile) + continue; + int tx = tai.tile_x; + int ty = tai.tile_y; + + if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) + continue; + if (Tile_has_city (area_tile)) + continue; + if (tile_has_enemy_unit (area_tile, rec->civ_id)) + continue; + if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) + continue; + + struct district_instance * area_district = get_district_instance (area_tile); + if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) + continue; + + struct wonder_district_info * area_info = get_wonder_district_info (area_tile); + if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) + continue; + + int key = (int)area_tile; + int prev_cover_pass = itable_look_up_or (&new_coverage_counts, key, 0); + int prev_cover_old = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); + itable_insert (&new_coverage_counts, key, prev_cover_pass + 1); + if ((prev_cover_pass == 0) && (prev_cover_old <= 0)) + itable_insert (&newly_covered_tiles, key, 1); + } + } + + for (int i = 0; i < is->memo_len; i++) + remove_distribution_hub_record ((Tile *)is->memo[i]); + clear_memo (); + + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (rec == NULL) + continue; + + City * anchor = get_connected_city_for_distribution_hub (rec); + if (anchor == NULL) { + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + continue; + } + + recompute_distribution_hub_yields (rec); + } + + table_deinit (&is->distribution_hub_coverage_counts); + is->distribution_hub_coverage_counts = new_coverage_counts; + memset (&new_coverage_counts, 0, sizeof new_coverage_counts); + + FOR_TABLE_ENTRIES (tei, &newly_covered_tiles) { + Tile * covered_tile = (Tile *)tei.key; + if ((covered_tile == NULL) || (covered_tile == p_null_tile)) + continue; + int tx, ty; + if (! tile_coords_from_ptr (&p_bic_data->Map, covered_tile, &tx, &ty)) + continue; + set_tile_unworkable_for_all_cities (covered_tile, tx, ty); + covered_tile->Body.CityAreaID = -1; + } + table_deinit (&newly_covered_tiles); + + // Recalculate yields for cities of civs whose distribution hub ownership changed + for (int civ_id = 0; civ_id < 32; civ_id++) { + if (civs_needing_recalc[civ_id] && (p_cities->Cities != NULL)) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city != NULL) && (city->Body.CivID == civ_id)) + recompute_city_yields_with_districts (city); + } + } + } + + is->distribution_hub_totals_dirty = false; +} + +void +on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y) +{ + if (! is->current_config.enable_districts || ! is->current_config.enable_distribution_hub_districts) + return; + + int tile_owner = -1; + if ((tile != NULL) && (tile != p_null_tile)) + tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec != NULL) { + int old_civ_id = rec->civ_id; + rec->tile = tile; + rec->tile_x = tile_x; + rec->tile_y = tile_y; + + release_distribution_hub_coverage (rec); + rec->civ_id = tile_owner; + is->distribution_hub_totals_dirty = true; + recompute_distribution_hub_totals (); + + if (old_civ_id != tile_owner) { + // Recompute for old civ + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * target_city = get_city_ptr (city_index); + if ((target_city != NULL) && (target_city->Body.CivID == old_civ_id)) + recompute_city_yields_with_districts (target_city); + } + } + } + + rec = malloc (sizeof *rec); + if (rec == NULL) + return; + rec->tile = tile; + rec->tile_x = tile_x; + rec->tile_y = tile_y; + rec->civ_id = tile_owner; + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + itable_insert (&is->distribution_hub_records, (int)tile, (int)rec); + adjust_distribution_hub_coverage (rec); + + is->distribution_hub_totals_dirty = true; + recompute_distribution_hub_totals (); + + // Recalculate yields for all cities of this civ + int affected_civ_id = rec->civ_id; + if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * target_city = get_city_ptr (city_index); + if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) + recompute_city_yields_with_districts (target_city); + } + } +} + +void +refresh_distribution_hubs_for_city (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_distribution_hub_districts || + (city == NULL)) + return; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int tx = wai.tile_x, ty = wai.tile_y; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID) + continue; + on_distribution_hub_completed (tile, tx, ty); + } +} + +bool +is_space_char (char c) +{ + switch (c) { + case ' ': + case '\t': + case '\n': + case '\r': + case '\f': + case '\v': + return true; + default: + return false; + } +} + +enum key_value_parse_status { + KVP_SUCCESS, + KVP_NO_EQUALS, + KVP_EMPTY_KEY +}; + +enum key_value_parse_status +parse_trimmed_key_value (struct string_slice const * trimmed, + struct string_slice * out_key, + struct string_slice * out_value) +{ + if ((trimmed == NULL) || (trimmed->len <= 0)) + return KVP_NO_EQUALS; + + char * equals = NULL; + for (int i = 0; i < trimmed->len; i++) { + if (trimmed->str[i] == '=') { + equals = trimmed->str + i; + break; + } + } + if (equals == NULL) + return KVP_NO_EQUALS; + + struct string_slice key = { .str = trimmed->str, .len = (int)(equals - trimmed->str) }; + key = trim_string_slice (&key, 0); + if (key.len == 0) + return KVP_EMPTY_KEY; + + struct string_slice value = { .str = equals + 1, .len = (int)((trimmed->str + trimmed->len) - (equals + 1)) }; + *out_key = key; + *out_value = trim_string_slice (&value, 0); + return KVP_SUCCESS; +} + +void +add_key_parse_error (struct error_line ** parse_errors, + int line_number, + struct string_slice const * key, + struct string_slice const * value, + char const * message_suffix) +{ + struct error_line * err = add_error_line (parse_errors); + char * key_str = extract_slice (key); + char * value_str = (value != NULL) ? extract_slice (value) : NULL; + if (value_str != NULL) + snprintf (err->text, sizeof err->text, "^ Line %d: %s \"%s\" %s", line_number, key_str, value_str, message_suffix); + else + snprintf (err->text, sizeof err->text, "^ Line %d: %s %s", line_number, key_str, message_suffix); + err->text[(sizeof err->text) - 1] = '\0'; + if (value_str != NULL) + free (value_str); + free (key_str); +} + +void +add_unrecognized_key_error (struct error_line ** unrecognized_keys, + int line_number, + struct string_slice const * key) +{ + struct error_line * err_line = add_error_line (unrecognized_keys); + char * key_str = extract_slice (key); + snprintf (err_line->text, sizeof err_line->text, "^ Line %d: %s", line_number, key_str); + err_line->text[(sizeof err_line->text) - 1] = '\0'; + free (key_str); +} + +char * +copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes) +{ + struct string_slice trimmed = trim_string_slice (slice, remove_quotes); + if (trimmed.len == 0) + return NULL; + return extract_slice (&trimmed); +} + +void +free_bonus_entry_list (struct district_bonus_list * list) +{ + if (list == NULL) + return; + + for (int i = 0; i < list->count; i++) { + if (list->entries[i].type == DBET_BUILDING && + list->entries[i].building_name != NULL) { + free ((void *)list->entries[i].building_name); + list->entries[i].building_name = NULL; + } + } + list->count = 0; +} + +void +free_bonus_entry_list_override (struct district_bonus_list * list, + struct district_bonus_list const * defaults) +{ + if (list == NULL) + return; + + for (int i = 0; i < list->count; i++) { + if (list->entries[i].type == DBET_BUILDING && + list->entries[i].building_name != NULL) { + char const * default_name = NULL; + if ((defaults != NULL) && (i < defaults->count)) + default_name = defaults->entries[i].building_name; + if (list->entries[i].building_name != default_name) + free ((void *)list->entries[i].building_name); + list->entries[i].building_name = NULL; + } + } + list->count = (defaults != NULL) ? defaults->count : 0; +} + +void +move_bonus_entry_list (struct district_bonus_list * dest, + struct district_bonus_list * src) +{ + if ((dest == NULL) || (src == NULL)) + return; + + dest->count = src->count; + for (int i = 0; i < src->count; i++) { + dest->entries[i] = src->entries[i]; + src->entries[i].building_name = NULL; + } + src->count = 0; +} + +void +free_dynamic_district_config (struct district_config * cfg) +{ + if (cfg == NULL) + return; + + if (! cfg->is_dynamic) + return; + + char const * name_ptr = cfg->name; + if (cfg->name != NULL) { + free ((void *)cfg->name); + cfg->name = NULL; + } + if ((cfg->display_name != NULL) && + (cfg->display_name != name_ptr)) { + free ((void *)cfg->display_name); + cfg->display_name = NULL; + } + if (cfg->tooltip != NULL) { + free ((void *)cfg->tooltip); + cfg->tooltip = NULL; + } + for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { + if (cfg->advance_prereqs[i] != NULL) { + free ((void *)cfg->advance_prereqs[i]); + cfg->advance_prereqs[i] = NULL; + } + } + cfg->advance_prereq_count = 0; + if (cfg->obsoleted_by != NULL) { + free ((void *)cfg->obsoleted_by); + cfg->obsoleted_by = NULL; + } + + for (int i = 0; i < 5; i++) { + if (cfg->resource_prereqs[i] != NULL) { + free ((void *)cfg->resource_prereqs[i]); + cfg->resource_prereqs[i] = NULL; + } + } + + if (cfg->resource_prereq_on_tile != NULL) { + free ((void *)cfg->resource_prereq_on_tile); + cfg->resource_prereq_on_tile = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { + if (cfg->wonder_prereqs[i] != NULL) { + free ((void *)cfg->wonder_prereqs[i]); + cfg->wonder_prereqs[i] = NULL; + } + } + cfg->wonder_prereq_count = 0; + + for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { + if (cfg->natural_wonder_prereqs[i] != NULL) { + free ((void *)cfg->natural_wonder_prereqs[i]); + cfg->natural_wonder_prereqs[i] = NULL; + } + } + cfg->natural_wonder_prereq_count = 0; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { + if (cfg->buildable_on_districts[i] != NULL) { + free ((void *)cfg->buildable_on_districts[i]); + cfg->buildable_on_districts[i] = NULL; + } + } + cfg->buildable_on_district_count = 0; + cfg->buildable_on_district_id_count = 0; + cfg->has_buildable_on_districts = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { + if (cfg->buildable_adjacent_to_districts[i] != NULL) { + free ((void *)cfg->buildable_adjacent_to_districts[i]); + cfg->buildable_adjacent_to_districts[i] = NULL; + } + } + cfg->buildable_adjacent_to_district_count = 0; + cfg->buildable_adjacent_to_district_id_count = 0; + cfg->has_buildable_adjacent_to = false; + cfg->has_buildable_adjacent_to_districts = false; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + if (cfg->buildable_by_civs[i] != NULL) { + free ((void *)cfg->buildable_by_civs[i]); + cfg->buildable_by_civs[i] = NULL; + } + } + cfg->buildable_by_civ_count = 0; + cfg->has_buildable_by_civs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) + cfg->buildable_by_civ_traits_ids[i] = -1; + cfg->buildable_by_civ_traits_id_count = 0; + cfg->has_buildable_by_civ_traits = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) + cfg->buildable_by_civ_govs_ids[i] = -1; + cfg->buildable_by_civ_govs_id_count = 0; + cfg->has_buildable_by_civ_govs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) + cfg->buildable_by_civ_cultures_ids[i] = -1; + cfg->buildable_by_civ_cultures_id_count = 0; + cfg->has_buildable_by_civ_cultures = false; + + for (int i = 0; i < 5; i++) { + if (cfg->dependent_improvements[i] != NULL) { + free ((void *)cfg->dependent_improvements[i]); + cfg->dependent_improvements[i] = NULL; + } + } + + for (int i = 0; i < 10; i++) { + if (cfg->img_paths[i] != NULL) { + free ((void *)cfg->img_paths[i]); + cfg->img_paths[i] = NULL; + } + } + + free_bonus_entry_list (&cfg->culture_bonus_extras); + free_bonus_entry_list (&cfg->science_bonus_extras); + free_bonus_entry_list (&cfg->food_bonus_extras); + free_bonus_entry_list (&cfg->gold_bonus_extras); + free_bonus_entry_list (&cfg->shield_bonus_extras); + free_bonus_entry_list (&cfg->happiness_bonus_extras); + free_bonus_entry_list (&cfg->defense_bonus_extras); + + memset (cfg, 0, sizeof *cfg); +} + +void +free_dynamic_wonder_config (struct wonder_district_config * cfg) +{ + if (cfg == NULL) + return; + + if (! cfg->is_dynamic) + return; + + if (cfg->wonder_name != NULL) { + free ((void *)cfg->wonder_name); + cfg->wonder_name = NULL; + } + + if (cfg->img_path != NULL) { + free ((void *)cfg->img_path); + cfg->img_path = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + if (cfg->buildable_by_civs[i] != NULL) { + free ((void *)cfg->buildable_by_civs[i]); + cfg->buildable_by_civs[i] = NULL; + } + } + cfg->buildable_by_civ_count = 0; + cfg->has_buildable_by_civs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) + cfg->buildable_by_civ_traits_ids[i] = -1; + cfg->buildable_by_civ_traits_id_count = 0; + cfg->has_buildable_by_civ_traits = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) + cfg->buildable_by_civ_govs_ids[i] = -1; + cfg->buildable_by_civ_govs_id_count = 0; + cfg->has_buildable_by_civ_govs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) + cfg->buildable_by_civ_cultures_ids[i] = -1; + cfg->buildable_by_civ_cultures_id_count = 0; + cfg->has_buildable_by_civ_cultures = false; + + memset (cfg, 0, sizeof *cfg); +} + +void +free_dynamic_natural_wonder_config (struct natural_wonder_district_config * cfg) +{ + if (cfg == NULL) + return; + + if (! cfg->is_dynamic) + return; + + if (cfg->name != NULL) { + free ((void *)cfg->name); + cfg->name = NULL; + } + + if (cfg->img_path != NULL) { + free ((void *)cfg->img_path); + cfg->img_path = NULL; + } + + memset (cfg, 0, sizeof *cfg); + cfg->adjacent_to = (enum SquareTypes)SQ_INVALID; + cfg->adjacency_dir = DIR_ZERO; +} + +enum Unit_Command_Values +allocate_dynamic_district_command (char const * name) +{ + int offset = is->next_custom_dynamic_command_index; + is->next_custom_dynamic_command_index += 1; + int value = C3X_DISTRICT_COMMAND_BASE - (offset + 1); + return (enum Unit_Command_Values)value; +} + +void +free_special_district_override_strings (struct district_config * cfg, struct district_config const * defaults) +{ + if (cfg == NULL || defaults == NULL) + return; + + if ((cfg->display_name != NULL) && + (cfg->display_name != cfg->name) && + (cfg->display_name != defaults->display_name)) { + free ((void *)cfg->display_name); + cfg->display_name = NULL; + } + if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) { + free ((void *)cfg->tooltip); + cfg->tooltip = NULL; + } + for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { + char const * default_value = (defaults != NULL && i < defaults->advance_prereq_count) + ? defaults->advance_prereqs[i] + : NULL; + if ((cfg->advance_prereqs[i] != NULL) && + (cfg->advance_prereqs[i] != default_value)) { + free ((void *)cfg->advance_prereqs[i]); + } + cfg->advance_prereqs[i] = NULL; + } + cfg->advance_prereq_count = 0; + if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) { + free ((void *)cfg->obsoleted_by); + cfg->obsoleted_by = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { + char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; + if ((cfg->resource_prereqs[i] != NULL) && + (cfg->resource_prereqs[i] != default_value)) + free ((void *)cfg->resource_prereqs[i]); + cfg->resource_prereqs[i] = NULL; + } + cfg->resource_prereq_count = defaults->resource_prereq_count; + + if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) { + free ((void *)cfg->resource_prereq_on_tile); + cfg->resource_prereq_on_tile = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { + char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; + if ((cfg->wonder_prereqs[i] != NULL) && + (cfg->wonder_prereqs[i] != default_value)) + free ((void *)cfg->wonder_prereqs[i]); + cfg->wonder_prereqs[i] = NULL; + } + cfg->wonder_prereq_count = defaults->wonder_prereq_count; + + for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { + char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; + if ((cfg->natural_wonder_prereqs[i] != NULL) && + (cfg->natural_wonder_prereqs[i] != default_value)) + free ((void *)cfg->natural_wonder_prereqs[i]); + cfg->natural_wonder_prereqs[i] = NULL; + } + cfg->natural_wonder_prereq_count = defaults->natural_wonder_prereq_count; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { + char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; + if ((cfg->buildable_on_districts[i] != NULL) && + (cfg->buildable_on_districts[i] != default_value)) { + free ((void *)cfg->buildable_on_districts[i]); + } + cfg->buildable_on_districts[i] = NULL; + } + cfg->buildable_on_district_count = defaults->buildable_on_district_count; + cfg->buildable_on_district_id_count = defaults->buildable_on_district_id_count; + cfg->has_buildable_on_districts = defaults->has_buildable_on_districts; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { + char const * default_value = (i < defaults->buildable_adjacent_to_district_count) + ? defaults->buildable_adjacent_to_districts[i] + : NULL; + if ((cfg->buildable_adjacent_to_districts[i] != NULL) && + (cfg->buildable_adjacent_to_districts[i] != default_value)) { + free ((void *)cfg->buildable_adjacent_to_districts[i]); + } + cfg->buildable_adjacent_to_districts[i] = NULL; + } + cfg->buildable_adjacent_to_district_count = defaults->buildable_adjacent_to_district_count; + cfg->buildable_adjacent_to_district_id_count = defaults->buildable_adjacent_to_district_id_count; + cfg->has_buildable_adjacent_to = defaults->has_buildable_adjacent_to; + cfg->has_buildable_adjacent_to_districts = defaults->has_buildable_adjacent_to_districts; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; + if ((cfg->buildable_by_civs[i] != NULL) && + (cfg->buildable_by_civs[i] != default_value)) { + free ((void *)cfg->buildable_by_civs[i]); + } + cfg->buildable_by_civs[i] = NULL; + } + cfg->buildable_by_civ_count = defaults->buildable_by_civ_count; + cfg->has_buildable_by_civs = defaults->has_buildable_by_civs; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) + cfg->buildable_by_civ_traits_ids[i] = -1; + cfg->buildable_by_civ_traits_id_count = defaults->buildable_by_civ_traits_id_count; + cfg->has_buildable_by_civ_traits = defaults->has_buildable_by_civ_traits; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) + cfg->buildable_by_civ_govs_ids[i] = -1; + cfg->buildable_by_civ_govs_id_count = defaults->buildable_by_civ_govs_id_count; + cfg->has_buildable_by_civ_govs = defaults->has_buildable_by_civ_govs; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) + cfg->buildable_by_civ_cultures_ids[i] = -1; + cfg->buildable_by_civ_cultures_id_count = defaults->buildable_by_civ_cultures_id_count; + cfg->has_buildable_by_civ_cultures = defaults->has_buildable_by_civ_cultures; + cfg->buildable_by_war_allies = defaults->buildable_by_war_allies; + cfg->buildable_by_pact_allies = defaults->buildable_by_pact_allies; + + for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { + char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; + if ((cfg->dependent_improvements[i] != NULL) && + (cfg->dependent_improvements[i] != default_value)) { + free ((void *)cfg->dependent_improvements[i]); + } + cfg->dependent_improvements[i] = NULL; + } + cfg->dependent_improvement_max_index = defaults->dependent_improvement_max_index; + + for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { + char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; + if ((cfg->img_paths[i] != NULL) && + (cfg->img_paths[i] != default_value)) { + free ((void *)cfg->img_paths[i]); + } + cfg->img_paths[i] = NULL; + } + cfg->img_path_count = defaults->img_path_count; + + free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); + free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); + free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); + free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); + free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); + free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); + free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); +} + +void +reset_regular_district_configs (void) +{ + for (int i = USED_SPECIAL_DISTRICT_TYPES; i < COUNT_DISTRICT_TYPES; i++) { + if (is->district_configs[i].is_dynamic) + free_dynamic_district_config (&is->district_configs[i]); + } + + for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) + free_special_district_override_strings (&is->district_configs[i], &special_district_defaults[i]); + + memset (is->district_configs, 0, sizeof is->district_configs); + for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) + is->district_configs[i] = special_district_defaults[i]; + + is->special_district_count = USED_SPECIAL_DISTRICT_TYPES; + is->dynamic_district_count = 0; + is->district_count = is->special_district_count; + is->next_custom_dynamic_command_index = 0; +} + +void +reset_wonder_district_configs (void) +{ + for (int i = 0; i < MAX_WONDER_DISTRICT_TYPES; i++) { + if (is->wonder_district_configs[i].is_dynamic) + free_dynamic_wonder_config (&is->wonder_district_configs[i]); + } + + memset (is->wonder_district_configs, 0, sizeof is->wonder_district_configs); + is->wonder_district_count = 0; +} + +void +reset_natural_wonder_configs (void) +{ + for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { + if (is->natural_wonder_configs[i].is_dynamic) + free_dynamic_natural_wonder_config (&is->natural_wonder_configs[i]); + } + + memset (is->natural_wonder_configs, 0, sizeof is->natural_wonder_configs); + for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { + is->natural_wonder_configs[i].adjacent_to = (enum SquareTypes)SQ_INVALID; + is->natural_wonder_configs[i].adjacency_dir = DIR_ZERO; + } + for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) + is->natural_wonder_img_sets[i].img.vtable = NULL; + stable_deinit (&is->natural_wonder_name_to_id); + is->natural_wonder_count = 0; +} + +void +clear_dynamic_district_definitions (void) +{ + reset_regular_district_configs (); + reset_wonder_district_configs (); + reset_natural_wonder_configs (); + reset_ai_candidate_bridge_or_canals (); +} + +void +init_parsed_district_definition (struct parsed_district_definition * def) +{ + memset (def, 0, sizeof *def); + def->img_path_count = -1; + def->defense_bonus_percent = 0; + def->render_strategy = DRS_BY_COUNT; + def->ai_build_strategy = DABS_DISTRICT; + def->buildable_square_types_mask = district_default_buildable_mask (); + def->buildable_adjacent_to_square_types_mask = 0; + def->buildable_without_removal_mask = 0; + def->buildable_on_overlays_mask = 0; + def->buildable_adjacent_to_overlays_mask = 0; + def->buildable_on_rivers = false; + def->buildable_adjacent_to_allows_city = false; +} + +void +free_parsed_district_definition (struct parsed_district_definition * def) +{ + if (def == NULL) + return; + + if (def->display_name != NULL) { + free (def->display_name); + def->display_name = NULL; + } + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + if (def->tooltip != NULL) { + free (def->tooltip); + def->tooltip = NULL; + } + for (int i = 0; i < def->advance_prereq_count; i++) { + if (def->advance_prereqs[i] != NULL) { + free (def->advance_prereqs[i]); + def->advance_prereqs[i] = NULL; + } + } + def->advance_prereq_count = 0; + for (int i = 0; i < ARRAY_LEN (def->buildable_on_districts); i++) { + if (def->buildable_on_districts[i] != NULL) { + free (def->buildable_on_districts[i]); + def->buildable_on_districts[i] = NULL; + } + } + for (int i = 0; i < ARRAY_LEN (def->buildable_adjacent_to_districts); i++) { + if (def->buildable_adjacent_to_districts[i] != NULL) { + free (def->buildable_adjacent_to_districts[i]); + def->buildable_adjacent_to_districts[i] = NULL; + } + } + if (def->obsoleted_by != NULL) { + free (def->obsoleted_by); + def->obsoleted_by = NULL; + } + + for (int i = 0; i < def->resource_prereq_count; i++) { + if (def->resource_prereqs[i] != NULL) { + free (def->resource_prereqs[i]); + def->resource_prereqs[i] = NULL; + } + } + def->resource_prereq_count = 0; + + if (def->resource_prereq_on_tile != NULL) { + free (def->resource_prereq_on_tile); + def->resource_prereq_on_tile = NULL; + } + + for (int i = 0; i < def->wonder_prereq_count; i++) { + if (def->wonder_prereqs[i] != NULL) { + free (def->wonder_prereqs[i]); + def->wonder_prereqs[i] = NULL; + } + } + def->wonder_prereq_count = 0; + + for (int i = 0; i < def->natural_wonder_prereq_count; i++) { + if (def->natural_wonder_prereqs[i] != NULL) { + free (def->natural_wonder_prereqs[i]); + def->natural_wonder_prereqs[i] = NULL; + } + } + def->natural_wonder_prereq_count = 0; + def->buildable_adjacent_to_district_count = 0; + + for (int i = 0; i < def->buildable_by_civ_count; i++) { + if (def->buildable_by_civs[i] != NULL) { + free (def->buildable_by_civs[i]); + def->buildable_by_civs[i] = NULL; + } + } + def->buildable_by_civ_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + + for (int i = 0; i < def->dependent_improvement_max_index; i++) { + if (def->dependent_improvements[i] != NULL) { + free (def->dependent_improvements[i]); + def->dependent_improvements[i] = NULL; + } + } + def->dependent_improvement_max_index = 0; + + for (int i = 0; i < def->img_path_count; i++) { + if (def->img_paths[i] != NULL) { + free (def->img_paths[i]); + def->img_paths[i] = NULL; + } + } + def->img_path_count = 0; + + if (def->generated_resource != NULL) { + free (def->generated_resource); + def->generated_resource = NULL; + } + + free_bonus_entry_list (&def->culture_bonus_extras); + free_bonus_entry_list (&def->science_bonus_extras); + free_bonus_entry_list (&def->food_bonus_extras); + free_bonus_entry_list (&def->gold_bonus_extras); + free_bonus_entry_list (&def->shield_bonus_extras); + free_bonus_entry_list (&def->happiness_bonus_extras); + free_bonus_entry_list (&def->defense_bonus_extras); + + init_parsed_district_definition (def); +} + +int +find_special_district_index_by_name (char const * name) +{ + if (name == NULL) + return -1; + + for (int i = 0; i < is->special_district_count; i++) { + if ((is->district_configs[i].name != NULL) && + (strcmp (is->district_configs[i].name, name) == 0)) + return i; + } + return -1; +} + + +// --------------------------------------------------------------- +// 兵种克制系统 +// --------------------------------------------------------------- + +struct unit_counter_group * +find_unit_counter_group_by_name (struct c3x_config * cfg, char const * name) +{ + for (int i = 0; i < cfg->count_unit_counter_groups; i++) { + struct unit_counter_group * g = &cfg->unit_counter_groups[i]; + if (g->name && strcmp (g->name, name) == 0) + return g; + } + return NULL; +} + +bool +unit_type_in_group (struct unit_counter_group * g, int type_id) +{ + char const * name = p_bic_data->UnitTypes[type_id].Name; + for (int i = 0; i < g->count_type_ids; i++) + if (strcmp (p_bic_data->UnitTypes[g->type_ids[i]].Name, name) == 0) + return true; + return false; +} + +bool +unit_matches_counter_side (struct c3x_config * cfg, int type_id, + int match, char * group_name) +{ + if (match == UCM_ANY) + return true; + if (match == UCM_GROUP) { + struct unit_counter_group * g = + find_unit_counter_group_by_name (cfg, group_name); + return g && unit_type_in_group (g, type_id); + } + // Direct unit type match: compare by name rather than exact ID so that + // AI strategy duplicates (same name, different ID) are also matched. + return strcmp (p_bic_data->UnitTypes[match].Name, + p_bic_data->UnitTypes[type_id].Name) == 0; +} + +enum recognizable_parse_result +parse_unit_counter_group (char ** p_cursor, + struct error_line ** p_unrecognized_lines, + void * out_group) +{ + char * cur = *p_cursor; + struct string_slice group_name; + if (! (parse_string (&cur, &group_name) && skip_punctuation (&cur, ':'))) + return RPR_PARSE_ERROR; + + struct unit_counter_group * g = out_group; + g->name = extract_slice (&group_name); + g->type_ids = NULL; + g->count_type_ids = 0; + + int any_unrecognized = 0; + struct string_slice type_name; + while (parse_string (&cur, &type_name)) { + // Loop through all unit types with this name, including AI strategy + // duplicates (same name, different ID), which the game creates internally. + int type_id = 0; + bool found_any = false; + while (find_unit_type_id_by_name (&type_name, type_id, &type_id)) { + g->type_ids = realloc (g->type_ids, + (g->count_type_ids + 1) * sizeof (int)); + g->type_ids[g->count_type_ids++] = type_id; + found_any = true; + type_id++; // continue search from next index + } + if (! found_any) { + add_unrecognized_line (p_unrecognized_lines, &type_name); + any_unrecognized = 1; + } + if (! skip_punctuation (&cur, ',')) + break; + } + *p_cursor = cur; + return any_unrecognized ? RPR_UNRECOGNIZED : RPR_OK; +} + +enum recognizable_parse_result +parse_counter_rule (char ** p_cursor, + struct error_line ** p_unrecognized_lines, + void * out_rule) +{ + char * cur = *p_cursor; + struct string_slice attacker_name, vs_token, defender_name; + + if (! parse_string (&cur, &attacker_name)) + return RPR_PARSE_ERROR; + if (! (parse_string (&cur, &vs_token) && + slice_matches_str (&vs_token, "vs"))) + return RPR_PARSE_ERROR; + if (! parse_string (&cur, &defender_name)) + return RPR_PARSE_ERROR; + + struct counter_rule * r = out_rule; + *r = (struct counter_rule) { + .attacker_match = UCM_ANY, + .defender_match = UCM_ANY, + .terrain_type = -1, + .district_id = -1, + .self_atk_pct = 100, + .self_def_pct = 100, + .enemy_atk_pct = 100, + .enemy_def_pct = 100, + }; + + if (! slice_matches_str (&attacker_name, "*")) { + int type_id; + if (find_unit_type_id_by_name (&attacker_name, 0, &type_id)) + r->attacker_match = type_id; + else { + r->attacker_match = UCM_GROUP; + r->attacker_group = extract_slice (&attacker_name); + } + } + + if (! slice_matches_str (&defender_name, "*")) { + int type_id; + if (find_unit_type_id_by_name (&defender_name, 0, &type_id)) + r->defender_match = type_id; + else { + r->defender_match = UCM_GROUP; + r->defender_group = extract_slice (&defender_name); + } + } + + struct string_slice token; + while (parse_string (&cur, &token)) { + if (slice_matches_str (&token, "in-city")) { + r->only_in_city = true; + } else if (slice_matches_str (&token, "ignore-terrain")) { + r->ignore_terrain = true; + } else if (slice_matches_str (&token, "self-atk")) { + if (! parse_int (&cur, &r->self_atk_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "self-def")) { + if (! parse_int (&cur, &r->self_def_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "enemy-atk")) { + if (! parse_int (&cur, &r->enemy_atk_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "enemy-def")) { + if (! parse_int (&cur, &r->enemy_def_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "terrain")) { + struct string_slice terrain_name; + if (! parse_string (&cur, &terrain_name)) + return RPR_PARSE_ERROR; + if (! read_tile_terrain_type_value (&terrain_name, + (enum SquareTypes *)&r->terrain_type)) { + add_unrecognized_line (p_unrecognized_lines, &terrain_name); + return RPR_UNRECOGNIZED; + } + } else if (slice_matches_str (&token, "district")) { + struct string_slice district_name; + if (! parse_string (&cur, &district_name)) + return RPR_PARSE_ERROR; + char * dname = extract_slice (&district_name); + int idx = find_special_district_index_by_name (dname); + free (dname); + if (idx < 0) { + add_unrecognized_line (p_unrecognized_lines, &district_name); + return RPR_UNRECOGNIZED; + } + r->district_id = idx; + } else { + break; + } + } + + *p_cursor = cur; + return RPR_OK; +} + +void +apply_counter_rules (struct c3x_config * cfg, + Unit * attacker, Unit * defender, Tile * def_tile, + int * out_attacker_atk, int * out_defender_def, + bool * out_ignore_terrain) +{ + int a_type = attacker->Body.UnitTypeID; + int d_type = defender->Body.UnitTypeID; + bool in_city = Tile_has_city (def_tile); + + int aa = 100, dd = 100; + bool ignore = false; + + for (int i = 0; i < cfg->count_counter_rules; i++) { + struct counter_rule * r = &cfg->counter_rules[i]; + + // 检查正向匹配(attacker=规则攻击方,defender=规则防守方) + // 生效字段:self-atk(攻击方攻击力)、enemy-def(防守方防御力) + bool forward = unit_matches_counter_side (cfg, a_type, + r->attacker_match, r->attacker_group) && + unit_matches_counter_side (cfg, d_type, + r->defender_match, r->defender_group); + + // 检查反向匹配(attacker=规则防守方,defender=规则攻击方) + // 生效字段:self-def(规则攻击方现在是防守方)、enemy-atk(规则防守方现在是攻击方) + bool reverse = unit_matches_counter_side (cfg, a_type, + r->defender_match, r->defender_group) && + unit_matches_counter_side (cfg, d_type, + r->attacker_match, r->attacker_group); + + if (! forward && ! reverse) + continue; + + // 环境条件以防守方所在格为准 + if (r->only_in_city && ! in_city) + continue; + if (r->terrain_type != -1 && + ! tile_matches_square_type (def_tile, + (enum SquareTypes)r->terrain_type)) + continue; + if (r->district_id != -1 && + ! (cfg->enable_districts && + district_is_complete (def_tile, r->district_id))) + continue; + + if (forward) { + aa = aa * r->self_atk_pct / 100; // self-atk:攻击方攻击力 + dd = dd * r->enemy_def_pct / 100; // enemy-def:防守方防御力 + } + if (reverse) { + aa = aa * r->enemy_atk_pct / 100; // enemy-atk:规则防守方现在作为攻击方 + dd = dd * r->self_def_pct / 100; // self-def:规则攻击方现在作为防守方 + } + if (forward || reverse) + ignore = ignore || r->ignore_terrain; + } + + *out_attacker_atk = aa; + *out_defender_def = dd; + *out_ignore_terrain = ignore; +} + +bool +district_is_included_by_final_config (int district_id) +{ + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + if (! is->current_config.enable_districts) + return false; + + switch (district_id) { + case NEIGHBORHOOD_DISTRICT_ID: return is->current_config.enable_neighborhood_districts; + case WONDER_DISTRICT_ID: return is->current_config.enable_wonder_districts; + case DISTRIBUTION_HUB_DISTRICT_ID: return is->current_config.enable_distribution_hub_districts; + case AERODROME_DISTRICT_ID: return is->current_config.enable_aerodrome_districts; + case PORT_DISTRICT_ID: return is->current_config.enable_port_districts; + case CENTRAL_RAIL_HUB_DISTRICT_ID: return is->current_config.enable_central_rail_hub_districts; + case ENERGY_GRID_DISTRICT_ID: return is->current_config.enable_energy_grid_districts; + case BRIDGE_DISTRICT_ID: return is->current_config.enable_bridge_districts; + case CANAL_DISTRICT_ID: return is->current_config.enable_canal_districts; + case GREAT_WALL_DISTRICT_ID: return is->current_config.enable_great_wall_districts; + default: return true; + } +} + +bool +ensure_culture_variant_art (struct district_config * cfg, int section_start_line) +{ + if ((cfg == NULL) || (! cfg->vary_img_by_culture)) + return true; + + const int required_variants = 5; + const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); + if (cfg->img_path_count <= 0) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] load_dynamic_district_configs: district \"%s\" requires culture-specific art but none provided (line %d)\n", cfg->name, section_start_line); + (*p_OutputDebugStringA) (ss); + return false; + } + + while ((cfg->img_path_count < required_variants) && + (cfg->img_path_count < max_img_paths)) { + cfg->img_paths[cfg->img_path_count] = strdup (cfg->img_paths[0]); + cfg->img_path_count += 1; + } + + return true; +} + +bool +parse_config_string_list (char * value_text, + char ** dest, + int capacity, + int * out_count, + struct error_line ** parse_errors, + int line_number, + char const * key) +{ + for (int i = 0; i < capacity; i++) { + if (dest[i] != NULL) { + free (dest[i]); + dest[i] = NULL; + } + } + *out_count = 0; + + if (value_text == NULL || *value_text == '\0') + return true; + + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + if (*cursor == '\0') + break; + + char * item_start; + char * item_end; + if (*cursor == '"') { + cursor++; + item_start = cursor; + while ((*cursor != '\0') && (*cursor != '"')) + cursor++; + if (*cursor != '"') { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (missing closing quote)", line_number, key); + err->text[(sizeof err->text) - 1] = '\0'; + for (int j = 0; j < capacity; j++) { + if (dest[j] != NULL) { + free (dest[j]); + dest[j] = NULL; + } + } + *out_count = 0; + return false; + } + item_end = cursor; + cursor++; + } else { + item_start = cursor; + while ((*cursor != '\0') && (*cursor != ',')) + cursor++; + item_end = cursor; + } + + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + + int item_len = item_end - item_start; + if (item_len > 0) { + if (*out_count < capacity) { + char * copy = malloc (item_len + 1); + if (copy == NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (out of memory)", line_number, key); + err->text[(sizeof err->text) - 1] = '\0'; + for (int j = 0; j < capacity; j++) { + if (dest[j] != NULL) { + free (dest[j]); + dest[j] = NULL; + } + } + *out_count = 0; + return false; + } + memcpy (copy, item_start, item_len); + copy[item_len] = '\0'; + dest[*out_count] = copy; + *out_count += 1; + } + } + + while (is_space_char (*cursor)) + cursor++; + + if (*cursor == ',') { + cursor++; + continue; + } + if (*cursor == '\0') + break; + } + + return true; +} + +bool +parse_buildable_square_type_mask (struct string_slice const * value, + unsigned int * out_mask, + struct error_line ** parse_errors, + int line_number, + char const * key_name, + bool * out_allow_city) +{ + char * value_text = trim_and_extract_slice (value, 0); + unsigned int mask = 0; + int entry_count = 0; + bool allow_city = false; + bool allow_city_token = (key_name != NULL) && (strcmp (key_name, "buildable_adjacent_to") == 0); + if (key_name == NULL) + key_name = "buildable_on"; + + if (value_text != NULL) { + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + char * item_start = cursor; + while ((*cursor != '\0') && (*cursor != ',')) + cursor++; + + char * item_end = cursor; + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + + struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; + if (item_slice.len > 0) { + if (slice_matches_str (&item_slice, "city")) { + if (! allow_city_token) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + allow_city = true; + entry_count += 1; + } else if (slice_matches_str (&item_slice, "lake")) { + mask |= district_buildable_lake_mask_bit (); + entry_count += 1; + } else { + enum SquareTypes parsed; + if (read_tile_terrain_type_value (&item_slice, &parsed)) { + if ((parsed == SQ_RIVER) || + (parsed == SQ_Forest) || + (parsed == SQ_Jungle) || + (parsed == SQ_Swamp)) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + if (parsed == (enum SquareTypes)SQ_INVALID) { + mask = all_square_types_mask (); + mask &= ~(square_type_mask_bit (SQ_Forest) | + square_type_mask_bit (SQ_Jungle) | + square_type_mask_bit (SQ_Swamp)); + } else + mask |= square_type_mask_bit (parsed); + entry_count += 1; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + } + } + + if (*cursor == ',') { + cursor++; + continue; + } + break; + } + } + + if (value_text != NULL) + free (value_text); + + if ((entry_count == 0) || ((mask == 0) && ! allow_city)) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one tile terrain type)", line_number, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + return false; + } + + *out_mask = mask; + if (out_allow_city != NULL) + *out_allow_city = allow_city; + return true; +} + +bool +parse_buildable_overlay_mask (struct string_slice const * value, + unsigned int * out_mask, + struct error_line ** parse_errors, + int line_number, + char const * key_name) +{ + char * value_text = trim_and_extract_slice (value, 0); + unsigned int mask = 0; + unsigned int allowed_mask = (DOM_MINE | DOM_IRRIGATION | DOM_FORTRESS | DOM_BARRICADE | + DOM_OUTPOST | DOM_RADAR_TOWER | DOM_JUNGLE | DOM_FOREST | + DOM_SWAMP | DOM_RIVER | DOM_AIRFIELD); + int entry_count = 0; + + if (key_name == NULL) + key_name = "buildable_without_removal"; + if (strcmp (key_name, "buildable_without_removal") == 0) + allowed_mask = (DOM_JUNGLE | DOM_FOREST | DOM_SWAMP); + else if (strcmp (key_name, "buildable_on_overlays") == 0) + allowed_mask &= ~DOM_RIVER; + + if (value_text != NULL) { + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + char * item_start = cursor; + while ((*cursor != '\0') && (*cursor != ',')) + cursor++; + + char * item_end = cursor; + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + + struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; + if (item_slice.len > 0) { + unsigned int bit = 0; + if (slice_matches_str (&item_slice, "mine")) { + bit = DOM_MINE; + } else if (slice_matches_str (&item_slice, "irrigation")) { + bit = DOM_IRRIGATION; + } else if (slice_matches_str (&item_slice, "fortress")) { + bit = DOM_FORTRESS; + } else if (slice_matches_str (&item_slice, "barricade")) { + bit = DOM_BARRICADE; + } else if (slice_matches_str (&item_slice, "outpost")) { + bit = DOM_OUTPOST; + } else if (slice_matches_str (&item_slice, "radar-tower")) { + bit = DOM_RADAR_TOWER; + } else if (slice_matches_str (&item_slice, "airfield")) { + bit = DOM_AIRFIELD; + } else if (slice_matches_str (&item_slice, "jungle")) { + bit = DOM_JUNGLE; + } else if (slice_matches_str (&item_slice, "jungles")) { + bit = DOM_JUNGLE; + } else if (slice_matches_str (&item_slice, "forest")) { + bit = DOM_FOREST; + } else if (slice_matches_str (&item_slice, "forests")) { + bit = DOM_FOREST; + } else if (slice_matches_str (&item_slice, "marsh")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "marshes")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "swamp")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "swamps")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "river")) { + bit = DOM_RIVER; + } else if (slice_matches_str (&item_slice, "rivers")) { + bit = DOM_RIVER; + } + + if (bit != 0) { + if ((allowed_mask & bit) == 0) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + mask |= bit; + entry_count += 1; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + } + + if (*cursor == ',') { + cursor++; + continue; + } + break; + } + } + + if (value_text != NULL) + free (value_text); + + if ((entry_count == 0) || (mask == 0)) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one overlay)", line_number, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + return false; + } + + *out_mask = mask; + return true; +} + +bool +parse_district_bonus_entries (struct string_slice const * value, + int * out_base_bonus, + struct district_bonus_list * out_extras, + struct error_line ** parse_errors, + int line_number, + struct string_slice const * key) +{ + if ((out_base_bonus == NULL) || (out_extras == NULL)) { + add_key_parse_error (parse_errors, line_number, key, value, "(invalid bonus target)"); + return false; + } + + char * value_text = trim_and_extract_slice (value, 0); + free_bonus_entry_list (out_extras); + *out_base_bonus = 0; + + if ((value_text == NULL) || (*value_text == '\0')) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); + free (value_text); + return false; + } + + bool got_base = false; + int base_bonus = 0; + + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + if (*cursor == '\0') + break; + + char * item_start = cursor; + bool in_quotes = false; + while (*cursor != '\0') { + if (*cursor == '"') + in_quotes = ! in_quotes; + if ((! in_quotes) && (*cursor == ',')) + break; + cursor++; + } + + char * item_end = cursor; + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + while ((item_start < item_end) && is_space_char (*item_start)) + item_start++; + + if (item_end > item_start) { + struct string_slice item = { .str = item_start, .len = (int)(item_end - item_start) }; + + if (! got_base) { + struct string_slice base_slice = trim_string_slice (&item, 0); + if (! read_int (&base_slice, &base_bonus)) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + got_base = true; + } else { + char * colon = NULL; + in_quotes = false; + for (char * p = item_start; p < item_end; p++) { + if (*p == '"') + in_quotes = ! in_quotes; + if ((! in_quotes) && (*p == ':')) { + colon = p; + break; + } + } + + if (colon == NULL) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected \"name: bonus\" entry)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + struct string_slice name_slice = { .str = item_start, .len = (int)(colon - item_start) }; + struct string_slice bonus_slice = { .str = colon + 1, .len = (int)(item_end - (colon + 1)) }; + struct string_slice trimmed_name = trim_string_slice (&name_slice, 1); + struct string_slice trimmed_bonus = trim_string_slice (&bonus_slice, 0); + + if (trimmed_name.len <= 0) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus name)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + int bonus_value = 0; + if (! read_int (&trimmed_bonus, &bonus_value)) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus value)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + if (out_extras->count >= MAX_DISTRICT_BONUS_ENTRIES) { + add_key_parse_error (parse_errors, line_number, key, value, "(too many bonus entries)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + struct district_bonus_entry * entry = &out_extras->entries[out_extras->count++]; + entry->bonus = bonus_value; + entry->building_id = -1; + entry->building_name = NULL; + + enum SquareTypes parsed_type; + if (read_tile_terrain_type_value (&trimmed_name, &parsed_type)) { + entry->type = DBET_TILE; + entry->tile_type = parsed_type; + } else { + entry->type = DBET_BUILDING; + entry->tile_type = (enum SquareTypes)SQ_INVALID; + entry->building_name = extract_slice (&trimmed_name); + } + } + } + + if (*cursor == ',') { + cursor++; + continue; + } + if (*cursor == '\0') + break; + } + + free (value_text); + + if (! got_base) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); + free_bonus_entry_list (out_extras); + return false; + } + + *out_base_bonus = base_bonus; + return true; +} + +bool +override_special_district_from_definition (struct parsed_district_definition * def, int section_start_line) +{ + if ((! def->has_name) || (def->name == NULL)) + return false; + + int index = find_special_district_index_by_name (def->name); + if (index < 0) + return false; + + struct district_config * cfg = &is->district_configs[index]; + struct district_config const * defaults = &special_district_defaults[index]; + + free (def->name); + def->name = NULL; + def->has_name = false; + + if (def->has_display_name) { + if ((cfg->display_name != NULL) && + (cfg->display_name != cfg->name) && + (cfg->display_name != defaults->display_name)) + free ((void *)cfg->display_name); + cfg->display_name = def->display_name; + def->display_name = NULL; + } + + if (def->has_tooltip) { + if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) + free ((void *)cfg->tooltip); + cfg->tooltip = def->tooltip; + def->tooltip = NULL; + } + + if (def->has_advance_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { + char const * default_value = (i < defaults->advance_prereq_count) ? defaults->advance_prereqs[i] : NULL; + if ((cfg->advance_prereqs[i] != NULL) && + (cfg->advance_prereqs[i] != default_value)) + free ((void *)cfg->advance_prereqs[i]); + cfg->advance_prereqs[i] = NULL; + } + + cfg->advance_prereq_count = def->advance_prereq_count; + const int max_entries = ARRAY_LEN (cfg->advance_prereqs); + if (cfg->advance_prereq_count > max_entries) + cfg->advance_prereq_count = max_entries; + for (int i = 0; i < cfg->advance_prereq_count; i++) { + cfg->advance_prereqs[i] = def->advance_prereqs[i]; + def->advance_prereqs[i] = NULL; + } + def->advance_prereq_count = 0; + } + + if (def->has_obsoleted_by) { + if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) + free ((void *)cfg->obsoleted_by); + cfg->obsoleted_by = def->obsoleted_by; + def->obsoleted_by = NULL; + } + + if (def->has_resource_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { + char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; + if ((cfg->resource_prereqs[i] != NULL) && + (cfg->resource_prereqs[i] != default_value)) + free ((void *)cfg->resource_prereqs[i]); + cfg->resource_prereqs[i] = NULL; + } + + cfg->resource_prereq_count = def->resource_prereq_count; + const int max_entries = ARRAY_LEN (cfg->resource_prereqs); + if (cfg->resource_prereq_count > max_entries) + cfg->resource_prereq_count = max_entries; + for (int i = 0; i < cfg->resource_prereq_count; i++) { + cfg->resource_prereqs[i] = def->resource_prereqs[i]; + def->resource_prereqs[i] = NULL; + } + } + + if (def->has_resource_prereq_on_tile) { + if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) + free ((void *)cfg->resource_prereq_on_tile); + cfg->resource_prereq_on_tile = def->resource_prereq_on_tile; + def->resource_prereq_on_tile = NULL; + } + + if (def->has_wonder_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { + char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; + if ((cfg->wonder_prereqs[i] != NULL) && + (cfg->wonder_prereqs[i] != default_value)) + free ((void *)cfg->wonder_prereqs[i]); + cfg->wonder_prereqs[i] = NULL; + } + + cfg->wonder_prereq_count = def->wonder_prereq_count; + const int max_entries = ARRAY_LEN (cfg->wonder_prereqs); + if (cfg->wonder_prereq_count > max_entries) + cfg->wonder_prereq_count = max_entries; + for (int i = 0; i < cfg->wonder_prereq_count; i++) { + cfg->wonder_prereqs[i] = def->wonder_prereqs[i]; + def->wonder_prereqs[i] = NULL; + } + } + + if (def->has_natural_wonder_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { + char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; + if ((cfg->natural_wonder_prereqs[i] != NULL) && + (cfg->natural_wonder_prereqs[i] != default_value)) + free ((void *)cfg->natural_wonder_prereqs[i]); + cfg->natural_wonder_prereqs[i] = NULL; + } + + cfg->natural_wonder_prereq_count = def->natural_wonder_prereq_count; + const int max_entries = ARRAY_LEN (cfg->natural_wonder_prereqs); + if (cfg->natural_wonder_prereq_count > max_entries) + cfg->natural_wonder_prereq_count = max_entries; + for (int i = 0; i < cfg->natural_wonder_prereq_count; i++) { + cfg->natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; + def->natural_wonder_prereqs[i] = NULL; + } + } + + if (def->has_buildable_on_districts) { + for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { + char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; + if ((cfg->buildable_on_districts[i] != NULL) && + (cfg->buildable_on_districts[i] != default_value)) + free ((void *)cfg->buildable_on_districts[i]); + cfg->buildable_on_districts[i] = NULL; + } + + cfg->buildable_on_district_count = def->buildable_on_district_count; + const int max_entries = ARRAY_LEN (cfg->buildable_on_districts); + if (cfg->buildable_on_district_count > max_entries) + cfg->buildable_on_district_count = max_entries; + for (int i = 0; i < cfg->buildable_on_district_count; i++) { + cfg->buildable_on_districts[i] = def->buildable_on_districts[i]; + def->buildable_on_districts[i] = NULL; + } + cfg->buildable_on_district_id_count = 0; + cfg->has_buildable_on_districts = true; + } + + if (def->has_buildable_adjacent_to_districts) { + for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { + char const * default_value = (i < defaults->buildable_adjacent_to_district_count) + ? defaults->buildable_adjacent_to_districts[i] + : NULL; + if ((cfg->buildable_adjacent_to_districts[i] != NULL) && + (cfg->buildable_adjacent_to_districts[i] != default_value)) + free ((void *)cfg->buildable_adjacent_to_districts[i]); + cfg->buildable_adjacent_to_districts[i] = NULL; + } + + cfg->buildable_adjacent_to_district_count = def->buildable_adjacent_to_district_count; + const int max_entries = ARRAY_LEN (cfg->buildable_adjacent_to_districts); + if (cfg->buildable_adjacent_to_district_count > max_entries) + cfg->buildable_adjacent_to_district_count = max_entries; + for (int i = 0; i < cfg->buildable_adjacent_to_district_count; i++) { + cfg->buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; + def->buildable_adjacent_to_districts[i] = NULL; + } + cfg->buildable_adjacent_to_district_id_count = 0; + cfg->has_buildable_adjacent_to_districts = true; + } + + if (def->has_buildable_by_civs) { + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; + if ((cfg->buildable_by_civs[i] != NULL) && + (cfg->buildable_by_civs[i] != default_value)) + free ((void *)cfg->buildable_by_civs[i]); + cfg->buildable_by_civs[i] = NULL; + } + cfg->buildable_by_civ_count = def->buildable_by_civ_count; + const int max_civ_names = ARRAY_LEN (cfg->buildable_by_civs); + if (cfg->buildable_by_civ_count > max_civ_names) + cfg->buildable_by_civ_count = max_civ_names; + for (int i = 0; i < cfg->buildable_by_civ_count; i++) { + cfg->buildable_by_civs[i] = def->buildable_by_civs[i]; + def->buildable_by_civs[i] = NULL; + } + cfg->has_buildable_by_civs = true; + } + + if (def->has_buildable_by_civ_traits) { + cfg->buildable_by_civ_traits_id_count = def->buildable_by_civ_traits_id_count; + const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_traits_ids); + if (cfg->buildable_by_civ_traits_id_count > max_entries) + cfg->buildable_by_civ_traits_id_count = max_entries; + for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) + cfg->buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; + cfg->has_buildable_by_civ_traits = true; + } + + if (def->has_buildable_by_civ_govs) { + cfg->buildable_by_civ_govs_id_count = def->buildable_by_civ_govs_id_count; + const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_govs_ids); + if (cfg->buildable_by_civ_govs_id_count > max_entries) + cfg->buildable_by_civ_govs_id_count = max_entries; + for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) + cfg->buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; + cfg->has_buildable_by_civ_govs = true; + } + + if (def->has_buildable_by_civ_cultures) { + cfg->buildable_by_civ_cultures_id_count = def->buildable_by_civ_cultures_id_count; + const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); + if (cfg->buildable_by_civ_cultures_id_count > max_entries) + cfg->buildable_by_civ_cultures_id_count = max_entries; + for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) + cfg->buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; + cfg->has_buildable_by_civ_cultures = true; + } + + if (def->has_buildable_by_war_allies) + cfg->buildable_by_war_allies = def->buildable_by_war_allies; + if (def->has_buildable_by_pact_allies) + cfg->buildable_by_pact_allies = def->buildable_by_pact_allies; + + if (def->has_allow_multiple) + cfg->allow_multiple = def->allow_multiple; + if (def->has_vary_img_by_era) + cfg->vary_img_by_era = def->vary_img_by_era; + if (def->has_vary_img_by_culture) + cfg->vary_img_by_culture = def->vary_img_by_culture; + if (def->has_render_strategy) + cfg->render_strategy = def->render_strategy; + if (def->has_ai_build_strategy) + cfg->ai_build_strategy = def->ai_build_strategy; + if (def->has_align_to_coast) + cfg->align_to_coast = def->align_to_coast; + if (def->has_draw_over_resources) + cfg->draw_over_resources = def->draw_over_resources; + if (def->has_allow_irrigation_from) + cfg->allow_irrigation_from = def->allow_irrigation_from; + if (def->has_auto_add_road) + cfg->auto_add_road = def->auto_add_road; + if (def->has_auto_add_railroad) + cfg->auto_add_railroad = def->auto_add_railroad; + if (def->has_custom_width) + cfg->custom_width = def->custom_width; + if (def->has_custom_height) + cfg->custom_height = def->custom_height; + if (def->has_x_offset) + cfg->x_offset = def->x_offset; + if (def->has_y_offset) + cfg->y_offset = def->y_offset; + if (def->has_btn_tile_sheet_column) + cfg->btn_tile_sheet_column = def->btn_tile_sheet_column; + if (def->has_btn_tile_sheet_row) + cfg->btn_tile_sheet_row = def->btn_tile_sheet_row; + if (def->has_defense_bonus_percent) { + cfg->defense_bonus_percent = def->defense_bonus_percent; + free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); + move_bonus_entry_list (&cfg->defense_bonus_extras, &def->defense_bonus_extras); + } + if (def->has_heal_units_in_one_turn) + cfg->heal_units_in_one_turn = def->heal_units_in_one_turn; + if (def->has_impassible) + cfg->impassible = def->impassible; + if (def->has_impassible_to_wheeled) + cfg->impassible_to_wheeled = def->impassible_to_wheeled; + if (def->has_culture_bonus) { + cfg->culture_bonus = def->culture_bonus; + free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); + move_bonus_entry_list (&cfg->culture_bonus_extras, &def->culture_bonus_extras); + } + if (def->has_science_bonus) { + cfg->science_bonus = def->science_bonus; + free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); + move_bonus_entry_list (&cfg->science_bonus_extras, &def->science_bonus_extras); + } + if (def->has_food_bonus) { + cfg->food_bonus = def->food_bonus; + free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); + move_bonus_entry_list (&cfg->food_bonus_extras, &def->food_bonus_extras); + } + if (def->has_gold_bonus) { + cfg->gold_bonus = def->gold_bonus; + free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); + move_bonus_entry_list (&cfg->gold_bonus_extras, &def->gold_bonus_extras); + } + if (def->has_shield_bonus) { + cfg->shield_bonus = def->shield_bonus; + free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); + move_bonus_entry_list (&cfg->shield_bonus_extras, &def->shield_bonus_extras); + } + if (def->has_happiness_bonus) { + cfg->happiness_bonus = def->happiness_bonus; + free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); + move_bonus_entry_list (&cfg->happiness_bonus_extras, &def->happiness_bonus_extras); + } + if (def->has_buildable_on) + cfg->buildable_square_types_mask = def->buildable_square_types_mask; + if (def->has_buildable_adjacent_to) { + cfg->buildable_adjacent_to_square_types_mask = def->buildable_adjacent_to_square_types_mask; + cfg->has_buildable_adjacent_to = true; + cfg->buildable_adjacent_to_allows_city = def->buildable_adjacent_to_allows_city; + } + if (def->has_buildable_without_removal) { + cfg->buildable_without_removal_mask = def->buildable_without_removal_mask; + cfg->has_buildable_without_removal = true; + } + if (def->has_buildable_on_overlays) { + cfg->buildable_on_overlays_mask = def->buildable_on_overlays_mask; + cfg->has_buildable_on_overlays = true; + } + if (def->has_buildable_on_rivers) + cfg->buildable_on_rivers = def->buildable_on_rivers; + if (def->has_buildable_adjacent_to_overlays) { + cfg->buildable_adjacent_to_overlays_mask = def->buildable_adjacent_to_overlays_mask; + cfg->has_buildable_adjacent_to_overlays = true; + } + + if (def->has_generated_resource) { + if ((cfg->generated_resource != NULL) && (cfg->generated_resource != defaults->generated_resource)) + free ((void *)cfg->generated_resource); + cfg->generated_resource = def->generated_resource; + def->generated_resource = NULL; + cfg->generated_resource_flags = def->generated_resource_flags; + cfg->generated_resource_id = -1; + } + + if (def->has_dependent_improvements) { + for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { + char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; + if ((cfg->dependent_improvements[i] != NULL) && + (cfg->dependent_improvements[i] != default_value)) + free ((void *)cfg->dependent_improvements[i]); + cfg->dependent_improvements[i] = NULL; + } + + cfg->dependent_improvement_max_index = def->dependent_improvement_max_index; + const int max_entries = ARRAY_LEN (cfg->dependent_improvements); + if (cfg->dependent_improvement_max_index > max_entries) + cfg->dependent_improvement_max_index = max_entries; + for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { + cfg->dependent_improvements[i] = def->dependent_improvements[i]; + def->dependent_improvements[i] = NULL; + } + if (! def->has_img_column_count) { + cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->dependent_improvement_max_index + 1); + cfg->has_img_column_count_override = false; + } + } + + if (def->has_img_paths) { + for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { + char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; + if ((cfg->img_paths[i] != NULL) && + (cfg->img_paths[i] != default_value)) + free ((void *)cfg->img_paths[i]); + cfg->img_paths[i] = NULL; + } + + cfg->img_path_count = def->img_path_count; + const int max_img_paths = ARRAY_LEN (cfg->img_paths); + if (cfg->img_path_count > max_img_paths) + cfg->img_path_count = max_img_paths; + for (int i = 0; i < cfg->img_path_count; i++) { + cfg->img_paths[i] = def->img_paths[i]; + def->img_paths[i] = NULL; + } + } + + if (def->has_img_column_count) { + cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->img_column_count); + cfg->has_img_column_count_override = true; + } + + if (! ensure_culture_variant_art (cfg, section_start_line)) { + free_special_district_override_strings (cfg, defaults); + *cfg = *defaults; + return false; + } + + return true; +} + +bool +add_dynamic_district_from_definition (struct parsed_district_definition * def, int section_start_line) +{ + if ((! def->has_name) || (def->name == NULL)) + return false; + + if ((! def->has_img_paths) || (def->img_path_count <= 0)) + return false; + + int existing_index = -1; + for (int i = is->special_district_count; i < is->district_count; i++) { + if ((is->district_configs[i].name != NULL) && + (strcmp (is->district_configs[i].name, def->name) == 0)) { + existing_index = i; + break; + } + } + + bool reusing_existing = existing_index >= 0; + int dest_index = reusing_existing ? existing_index : (is->special_district_count + is->dynamic_district_count); + + if ((! reusing_existing) && (dest_index >= COUNT_DISTRICT_TYPES)) + return false; + + enum Unit_Command_Values preserved_command = 0; + if (reusing_existing) + preserved_command = is->district_configs[dest_index].command; + + struct district_config new_cfg; + memset (&new_cfg, 0, sizeof new_cfg); + new_cfg.is_dynamic = true; + + new_cfg.name = def->name; + def->name = NULL; + if (def->has_display_name) { + new_cfg.display_name = def->display_name; + if (new_cfg.display_name == NULL) + new_cfg.display_name = new_cfg.name; + def->display_name = NULL; + } else { + new_cfg.display_name = new_cfg.name; + } + + if (def->has_tooltip) { + new_cfg.tooltip = def->tooltip; + def->tooltip = NULL; + } else if (new_cfg.name != NULL) { + char buffer[128]; + snprintf (buffer, sizeof buffer, "Build %s", new_cfg.name); + new_cfg.tooltip = strdup (buffer); + } + + if (def->has_advance_prereqs) { + new_cfg.advance_prereq_count = def->advance_prereq_count; + const int max_entries = ARRAY_LEN (new_cfg.advance_prereqs); + if (new_cfg.advance_prereq_count > max_entries) + new_cfg.advance_prereq_count = max_entries; + for (int i = 0; i < new_cfg.advance_prereq_count; i++) { + new_cfg.advance_prereqs[i] = def->advance_prereqs[i]; + def->advance_prereqs[i] = NULL; + } + def->advance_prereq_count = 0; + } + + if (def->has_obsoleted_by) { + new_cfg.obsoleted_by = def->obsoleted_by; + def->obsoleted_by = NULL; + } + + new_cfg.resource_prereq_count = def->has_resource_prereqs ? def->resource_prereq_count : 0; + const int max_resource_entries = ARRAY_LEN (new_cfg.resource_prereqs); + if (new_cfg.resource_prereq_count > max_resource_entries) + new_cfg.resource_prereq_count = max_resource_entries; + for (int i = 0; i < new_cfg.resource_prereq_count; i++) { + new_cfg.resource_prereqs[i] = def->resource_prereqs[i]; + def->resource_prereqs[i] = NULL; + } + + if (def->has_resource_prereq_on_tile) { + new_cfg.resource_prereq_on_tile = def->resource_prereq_on_tile; + def->resource_prereq_on_tile = NULL; + } + + new_cfg.wonder_prereq_count = def->has_wonder_prereqs ? def->wonder_prereq_count : 0; + const int max_required_wonders = ARRAY_LEN (new_cfg.wonder_prereqs); + if (new_cfg.wonder_prereq_count > max_required_wonders) + new_cfg.wonder_prereq_count = max_required_wonders; + for (int i = 0; i < new_cfg.wonder_prereq_count; i++) { + new_cfg.wonder_prereqs[i] = def->wonder_prereqs[i]; + def->wonder_prereqs[i] = NULL; + } + + new_cfg.natural_wonder_prereq_count = def->has_natural_wonder_prereqs ? def->natural_wonder_prereq_count : 0; + const int max_required_natural_wonders = ARRAY_LEN (new_cfg.natural_wonder_prereqs); + if (new_cfg.natural_wonder_prereq_count > max_required_natural_wonders) + new_cfg.natural_wonder_prereq_count = max_required_natural_wonders; + for (int i = 0; i < new_cfg.natural_wonder_prereq_count; i++) { + new_cfg.natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; + def->natural_wonder_prereqs[i] = NULL; + } + + new_cfg.buildable_on_district_count = def->has_buildable_on_districts ? def->buildable_on_district_count : 0; + const int max_buildable_on_districts = ARRAY_LEN (new_cfg.buildable_on_districts); + if (new_cfg.buildable_on_district_count > max_buildable_on_districts) + new_cfg.buildable_on_district_count = max_buildable_on_districts; + for (int i = 0; i < new_cfg.buildable_on_district_count; i++) { + new_cfg.buildable_on_districts[i] = def->buildable_on_districts[i]; + def->buildable_on_districts[i] = NULL; + } + new_cfg.buildable_on_district_id_count = 0; + new_cfg.has_buildable_on_districts = def->has_buildable_on_districts; + + new_cfg.buildable_adjacent_to_district_count = def->has_buildable_adjacent_to_districts ? def->buildable_adjacent_to_district_count : 0; + const int max_adjacent_to_districts = ARRAY_LEN (new_cfg.buildable_adjacent_to_districts); + if (new_cfg.buildable_adjacent_to_district_count > max_adjacent_to_districts) + new_cfg.buildable_adjacent_to_district_count = max_adjacent_to_districts; + for (int i = 0; i < new_cfg.buildable_adjacent_to_district_count; i++) { + new_cfg.buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; + def->buildable_adjacent_to_districts[i] = NULL; + } + new_cfg.buildable_adjacent_to_district_id_count = 0; + new_cfg.has_buildable_adjacent_to_districts = def->has_buildable_adjacent_to_districts; + + new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; + const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); + if (new_cfg.buildable_by_civ_count > max_civ_names) + new_cfg.buildable_by_civ_count = max_civ_names; + for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { + new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; + def->buildable_by_civs[i] = NULL; + } + + new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; + + new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; + const int max_buildable_traits = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); + if (new_cfg.buildable_by_civ_traits_id_count > max_buildable_traits) + new_cfg.buildable_by_civ_traits_id_count = max_buildable_traits; + for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) + new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; + new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; + + new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; + const int max_buildable_govs = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); + if (new_cfg.buildable_by_civ_govs_id_count > max_buildable_govs) + new_cfg.buildable_by_civ_govs_id_count = max_buildable_govs; + for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) + new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; + new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; + + new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; + const int max_buildable_cultures = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); + if (new_cfg.buildable_by_civ_cultures_id_count > max_buildable_cultures) + new_cfg.buildable_by_civ_cultures_id_count = max_buildable_cultures; + for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) + new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; + new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; + + new_cfg.buildable_by_war_allies = def->has_buildable_by_war_allies ? def->buildable_by_war_allies : false; + new_cfg.buildable_by_pact_allies = def->has_buildable_by_pact_allies ? def->buildable_by_pact_allies : false; + + new_cfg.allow_multiple = def->has_allow_multiple ? def->allow_multiple : false; + new_cfg.vary_img_by_era = def->has_vary_img_by_era ? def->vary_img_by_era : false; + new_cfg.vary_img_by_culture = def->has_vary_img_by_culture ? def->vary_img_by_culture : false; + new_cfg.render_strategy = def->has_render_strategy ? def->render_strategy : DRS_BY_COUNT; + new_cfg.ai_build_strategy = def->has_ai_build_strategy ? def->ai_build_strategy : DABS_DISTRICT; + new_cfg.align_to_coast = def->has_align_to_coast ? def->align_to_coast : false; + new_cfg.draw_over_resources = def->has_draw_over_resources ? def->draw_over_resources : false; + new_cfg.allow_irrigation_from = def->has_allow_irrigation_from ? def->allow_irrigation_from : false; + new_cfg.auto_add_road = def->has_auto_add_road ? def->auto_add_road : false; + new_cfg.auto_add_railroad = def->has_auto_add_railroad ? def->auto_add_railroad : false; + new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; + new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; + new_cfg.x_offset = def->has_x_offset ? def->x_offset : 0; + new_cfg.y_offset = def->has_y_offset ? def->y_offset : 0; + new_cfg.btn_tile_sheet_column = def->has_btn_tile_sheet_column ? def->btn_tile_sheet_column : 0; + new_cfg.btn_tile_sheet_row = def->has_btn_tile_sheet_row ? def->btn_tile_sheet_row : 0; + new_cfg.defense_bonus_percent = def->has_defense_bonus_percent ? def->defense_bonus_percent : 0; + new_cfg.heal_units_in_one_turn = def->has_heal_units_in_one_turn ? def->heal_units_in_one_turn : false; + new_cfg.impassible = def->has_impassible ? def->impassible : false; + new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; + new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; + new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; + new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; + new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; + new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; + new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; + new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); + new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; + new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; + new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; + new_cfg.buildable_without_removal_mask = def->has_buildable_without_removal ? def->buildable_without_removal_mask : 0; + new_cfg.has_buildable_without_removal = def->has_buildable_without_removal; + new_cfg.buildable_on_overlays_mask = def->has_buildable_on_overlays ? def->buildable_on_overlays_mask : 0; + new_cfg.has_buildable_on_overlays = def->has_buildable_on_overlays; + new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; + new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; + new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; + + if (def->has_culture_bonus) + move_bonus_entry_list (&new_cfg.culture_bonus_extras, &def->culture_bonus_extras); + if (def->has_science_bonus) + move_bonus_entry_list (&new_cfg.science_bonus_extras, &def->science_bonus_extras); + if (def->has_food_bonus) + move_bonus_entry_list (&new_cfg.food_bonus_extras, &def->food_bonus_extras); + if (def->has_gold_bonus) + move_bonus_entry_list (&new_cfg.gold_bonus_extras, &def->gold_bonus_extras); + if (def->has_shield_bonus) + move_bonus_entry_list (&new_cfg.shield_bonus_extras, &def->shield_bonus_extras); + if (def->has_happiness_bonus) + move_bonus_entry_list (&new_cfg.happiness_bonus_extras, &def->happiness_bonus_extras); + if (def->has_defense_bonus_percent) + move_bonus_entry_list (&new_cfg.defense_bonus_extras, &def->defense_bonus_extras); + + if (def->has_generated_resource) { + new_cfg.generated_resource = def->generated_resource; + def->generated_resource = NULL; + new_cfg.generated_resource_flags = def->generated_resource_flags; + new_cfg.generated_resource_id = -1; + } else { + new_cfg.generated_resource = NULL; + new_cfg.generated_resource_id = -1; + new_cfg.generated_resource_flags = 0; + } + + new_cfg.dependent_improvement_max_index = def->has_dependent_improvements ? def->dependent_improvement_max_index : 0; + const int max_dependent_entries = ARRAY_LEN (is->district_configs[0].dependent_improvements); + if (new_cfg.dependent_improvement_max_index > max_dependent_entries) + new_cfg.dependent_improvement_max_index = max_dependent_entries; + for (int i = 0; i < new_cfg.dependent_improvement_max_index; i++) { + new_cfg.dependent_improvements[i] = def->dependent_improvements[i]; + def->dependent_improvements[i] = NULL; + } + + new_cfg.img_path_count = def->img_path_count; + const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); + if (new_cfg.img_path_count > max_img_paths) + new_cfg.img_path_count = max_img_paths; + for (int i = 0; i < new_cfg.img_path_count; i++) { + new_cfg.img_paths[i] = def->img_paths[i]; + def->img_paths[i] = NULL; + } + + if (! ensure_culture_variant_art (&new_cfg, section_start_line)) { + free_dynamic_district_config (&new_cfg); + return false; + } + + new_cfg.img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, def->has_img_column_count ? def->img_column_count : new_cfg.dependent_improvement_max_index + 1); + new_cfg.has_img_column_count_override = def->has_img_column_count; + + if (reusing_existing) + new_cfg.command = preserved_command; + else + new_cfg.command = allocate_dynamic_district_command (new_cfg.name); + + struct district_config * dest_cfg = &is->district_configs[dest_index]; + if (reusing_existing) { + enum Unit_Command_Values saved_command = preserved_command; + free_dynamic_district_config (dest_cfg); + *dest_cfg = new_cfg; + dest_cfg->command = saved_command; + } else { + free_dynamic_district_config (dest_cfg); + *dest_cfg = new_cfg; + is->dynamic_district_count += 1; + is->district_count = is->special_district_count + is->dynamic_district_count; + } + + return true; +} + +void +finalize_parsed_district_definition (struct parsed_district_definition * def, int section_start_line) +{ + if ((! def->has_name) || (def->name == NULL)) + return; + + if (! override_special_district_from_definition (def, section_start_line)) + add_dynamic_district_from_definition (def, section_start_line); + + free_parsed_district_definition (def); +} + +void +handle_district_definition_key (struct parsed_district_definition * def, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if (slice_matches_str (key, "name")) { + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + char * name_copy = copy_trimmed_string_or_null (value, 1); + if (name_copy == NULL) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else { + def->name = name_copy; + def->has_name = true; + } + + } else if (slice_matches_str (key, "display_name")) { + if (def->display_name != NULL) { + free (def->display_name); + def->display_name = NULL; + } + def->display_name = copy_trimmed_string_or_null (value, 1); + def->has_display_name = true; + + } else if (slice_matches_str (key, "tooltip")) { + if (def->tooltip != NULL) { + free (def->tooltip); + def->tooltip = NULL; + } + def->tooltip = copy_trimmed_string_or_null (value, 1); + def->has_tooltip = true; + + } else if (slice_matches_str (key, "advance_prereqs") || slice_matches_str (key, "advance_prereq")) { + for (int i = 0; i < def->advance_prereq_count; i++) { + if (def->advance_prereqs[i] != NULL) { + free (def->advance_prereqs[i]); + def->advance_prereqs[i] = NULL; + } + } + def->advance_prereq_count = 0; + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->advance_prereqs, + ARRAY_LEN (def->advance_prereqs), + &list_count, + parse_errors, + line_number, + "advance_prereqs")) { + def->advance_prereq_count = list_count; + def->has_advance_prereqs = true; + } else { + def->advance_prereq_count = 0; + def->has_advance_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "obsoleted_by")) { + if (def->obsoleted_by != NULL) { + free (def->obsoleted_by); + def->obsoleted_by = NULL; + } + def->obsoleted_by = copy_trimmed_string_or_null (value, 1); + def->has_obsoleted_by = true; + + } else if (slice_matches_str (key, "resource_prereqs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->resource_prereqs, + ARRAY_LEN (def->resource_prereqs), + &list_count, + parse_errors, + line_number, + "resource_prereqs")) { + def->resource_prereq_count = list_count; + def->has_resource_prereqs = true; + } else { + def->resource_prereq_count = 0; + def->has_resource_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "resource_prereq_on_tile")) { + if (def->resource_prereq_on_tile != NULL) { + free (def->resource_prereq_on_tile); + def->resource_prereq_on_tile = NULL; + } + def->resource_prereq_on_tile = copy_trimmed_string_or_null (value, 1); + def->has_resource_prereq_on_tile = true; + + } else if (slice_matches_str (key, "wonder_prereqs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->wonder_prereqs, + ARRAY_LEN (def->wonder_prereqs), + &list_count, + parse_errors, + line_number, + "wonder_prereqs")) { + def->wonder_prereq_count = list_count; + def->has_wonder_prereqs = true; + } else { + def->wonder_prereq_count = 0; + def->has_wonder_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "natural_wonder_prereqs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->natural_wonder_prereqs, + ARRAY_LEN (def->natural_wonder_prereqs), + &list_count, + parse_errors, + line_number, + "natural_wonder_prereqs")) { + def->natural_wonder_prereq_count = list_count; + def->has_natural_wonder_prereqs = true; + } else { + def->natural_wonder_prereq_count = 0; + def->has_natural_wonder_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_on_districts")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_on_districts, + ARRAY_LEN (def->buildable_on_districts), + &list_count, + parse_errors, + line_number, + "buildable_on_districts")) { + def->buildable_on_district_count = list_count; + def->has_buildable_on_districts = true; + } else { + def->buildable_on_district_count = 0; + def->has_buildable_on_districts = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_adjacent_to_districts")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_adjacent_to_districts, + ARRAY_LEN (def->buildable_adjacent_to_districts), + &list_count, + parse_errors, + line_number, + "buildable_adjacent_to_districts")) { + def->buildable_adjacent_to_district_count = list_count; + def->has_buildable_adjacent_to_districts = true; + } else { + def->buildable_adjacent_to_district_count = 0; + def->has_buildable_adjacent_to_districts = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civs, + ARRAY_LEN (def->buildable_by_civs), + &list_count, + parse_errors, + line_number, + "buildable_by_civs")) { + def->buildable_by_civ_count = list_count; + def->has_buildable_by_civs = true; + } else { + def->buildable_by_civ_count = 0; + def->has_buildable_by_civs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_traits")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_traits, + ARRAY_LEN (def->buildable_by_civ_traits), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_traits")) { + def->buildable_by_civ_traits_count = list_count; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + char const * trait_name = def->buildable_by_civ_traits[i]; + if ((trait_name == NULL) || (trait_name[0] == '\0')) + continue; + int trait_id = -1; + struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; + if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { + if (def->buildable_by_civ_traits_ids[k] == trait_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) + def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->has_buildable_by_civ_traits = true; + } else { + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + def->has_buildable_by_civ_traits = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_govs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_govs, + ARRAY_LEN (def->buildable_by_civ_govs), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_govs")) { + def->buildable_by_civ_govs_count = list_count; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + char const * gov_name = def->buildable_by_civ_govs[i]; + if ((gov_name == NULL) || (gov_name[0] == '\0')) + continue; + int gov_id = -1; + struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; + if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { + if (def->buildable_by_civ_govs_ids[k] == gov_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) + def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->has_buildable_by_civ_govs = true; + } else { + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + def->has_buildable_by_civ_govs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_cultures, + ARRAY_LEN (def->buildable_by_civ_cultures), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_cultures")) { + def->buildable_by_civ_cultures_count = list_count; + def->buildable_by_civ_cultures_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + char const * culture_name = def->buildable_by_civ_cultures[i]; + if ((culture_name == NULL) || (culture_name[0] == '\0')) + continue; + int culture_id = -1; + struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; + if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { + if (def->buildable_by_civ_cultures_ids[k] == culture_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) + def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->has_buildable_by_civ_cultures = true; + } else { + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + def->has_buildable_by_civ_cultures = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_war_allies")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_by_war_allies = (ival != 0); + def->has_buildable_by_war_allies = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "buildable_by_pact_allies")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_by_pact_allies = (ival != 0); + def->has_buildable_by_pact_allies = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "img_paths")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->img_paths, + ARRAY_LEN (def->img_paths), + &list_count, + parse_errors, + line_number, + "img_paths")) { + def->img_path_count = list_count; + def->has_img_paths = true; + } else { + def->img_path_count = 0; + def->has_img_paths = false; + } + free (value_text); + + } else if (slice_matches_str (key, "img_column_count")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_column_count = ival; + def->has_img_column_count = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "dependent_improvs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->dependent_improvements, + ARRAY_LEN (def->dependent_improvements), + &list_count, + parse_errors, + line_number, + "dependent_improvs")) { + def->dependent_improvement_max_index = list_count; + def->has_dependent_improvements = true; + } else { + def->dependent_improvement_max_index = 0; + def->has_dependent_improvements = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_on")) { + unsigned int mask; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { + def->buildable_square_types_mask = mask; + def->has_buildable_on = true; + } + + } else if (slice_matches_str (key, "buildable_without_removal")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_without_removal")) { + def->buildable_without_removal_mask = mask; + def->has_buildable_without_removal = true; + } else { + def->has_buildable_without_removal = false; + } + + } else if (slice_matches_str (key, "buildable_on_overlays")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_on_overlays")) { + def->buildable_on_overlays_mask = mask; + def->has_buildable_on_overlays = true; + } else { + def->has_buildable_on_overlays = false; + } + + } else if (slice_matches_str (key, "buildable_on_rivers")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_on_rivers = (ival != 0); + def->has_buildable_on_rivers = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "buildable_adjacent_to")) { + unsigned int mask; + def->buildable_adjacent_to_allows_city = false; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { + def->buildable_adjacent_to_square_types_mask = mask; + def->has_buildable_adjacent_to = true; + } + + } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { + def->buildable_adjacent_to_overlays_mask = mask; + def->has_buildable_adjacent_to_overlays = true; + } else { + def->has_buildable_adjacent_to_overlays = false; + } + + } else if (slice_matches_str (key, "allow_multiple")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->allow_multiple = (ival != 0); + def->has_allow_multiple = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "vary_img_by_era")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->vary_img_by_era = (ival != 0); + def->has_vary_img_by_era = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "vary_img_by_culture")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->vary_img_by_culture = (ival != 0); + def->has_vary_img_by_culture = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "render_strategy")) { + char * strategy = copy_trimmed_string_or_null (value, 1); + if (strategy == NULL) { + def->has_render_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else if (strcmp (strategy, "by-count") == 0) { + def->render_strategy = DRS_BY_COUNT; + def->has_render_strategy = true; + } else if (strcmp (strategy, "by-building") == 0) { + def->render_strategy = DRS_BY_BUILDING; + def->has_render_strategy = true; + } else { + def->has_render_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected \"by-count\" or \"by-building\")"); + } + if (strategy != NULL) + free (strategy); + + } else if (slice_matches_str (key, "ai_build_strategy")) { + char * strategy = copy_trimmed_string_or_null (value, 1); + if (strategy == NULL) { + def->has_ai_build_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else if (strcmp (strategy, "district") == 0) { + def->ai_build_strategy = DABS_DISTRICT; + def->has_ai_build_strategy = true; + } else if (strcmp (strategy, "tile-improvement") == 0) { + def->ai_build_strategy = DABS_TILE_IMPROVEMENT; + def->has_ai_build_strategy = true; + } else { + def->has_ai_build_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected \"district\" or \"tile-improvement\")"); + } + if (strategy != NULL) + free (strategy); + + } else if (slice_matches_str (key, "align_to_coast")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->align_to_coast = (ival != 0); + def->has_align_to_coast = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "draw_over_resources")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->draw_over_resources = (ival != 0); + def->has_draw_over_resources = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "allow_irrigation_from")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->allow_irrigation_from = (ival != 0); + def->has_allow_irrigation_from = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "auto_add_road")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->auto_add_road = (ival != 0); + def->has_auto_add_road = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "auto_add_railroad")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->auto_add_railroad = (ival != 0); + def->has_auto_add_railroad = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "impassible")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible = (ival != 0); + def->has_impassible = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "impassible_to_wheeled")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible_to_wheeled = (ival != 0); + def->has_impassible_to_wheeled = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "custom_width")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_width = ival; + def->has_custom_width = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "custom_height")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_height = ival; + def->has_custom_height = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "x_offset")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->x_offset = ival; + def->has_x_offset = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "y_offset")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->y_offset = ival; + def->has_y_offset = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "btn_tile_sheet_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->btn_tile_sheet_column = ival; + def->has_btn_tile_sheet_column = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "btn_tile_sheet_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->btn_tile_sheet_row = ival; + def->has_btn_tile_sheet_row = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "defense_bonus_percent")) { + if (parse_district_bonus_entries (value, &def->defense_bonus_percent, &def->defense_bonus_extras, parse_errors, line_number, key)) { + def->has_defense_bonus_percent = true; + } else { + def->has_defense_bonus_percent = false; + } + + } else if (slice_matches_str (key, "heal_units_in_one_turn")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->heal_units_in_one_turn = (ival != 0); + def->has_heal_units_in_one_turn = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "culture_bonus")) { + if (parse_district_bonus_entries (value, &def->culture_bonus, &def->culture_bonus_extras, parse_errors, line_number, key)) { + def->has_culture_bonus = true; + } else { + def->has_culture_bonus = false; + } + + } else if (slice_matches_str (key, "science_bonus")) { + if (parse_district_bonus_entries (value, &def->science_bonus, &def->science_bonus_extras, parse_errors, line_number, key)) { + def->has_science_bonus = true; + } else { + def->has_science_bonus = false; + } + + } else if (slice_matches_str (key, "food_bonus")) { + if (parse_district_bonus_entries (value, &def->food_bonus, &def->food_bonus_extras, parse_errors, line_number, key)) { + def->has_food_bonus = true; + } else { + def->has_food_bonus = false; + } + + } else if (slice_matches_str (key, "gold_bonus")) { + if (parse_district_bonus_entries (value, &def->gold_bonus, &def->gold_bonus_extras, parse_errors, line_number, key)) { + def->has_gold_bonus = true; + } else { + def->has_gold_bonus = false; + } + + } else if (slice_matches_str (key, "shield_bonus")) { + if (parse_district_bonus_entries (value, &def->shield_bonus, &def->shield_bonus_extras, parse_errors, line_number, key)) { + def->has_shield_bonus = true; + } else { + def->has_shield_bonus = false; + } + + } else if (slice_matches_str (key, "happiness_bonus")) { + if (parse_district_bonus_entries (value, &def->happiness_bonus, &def->happiness_bonus_extras, parse_errors, line_number, key)) { + def->has_happiness_bonus = true; + } else { + def->has_happiness_bonus = false; + } + + } else if (slice_matches_str (key, "generated_resource")) { + if (def->generated_resource != NULL) { + free (def->generated_resource); + def->generated_resource = NULL; + } + def->generated_resource_flags = 0; + + char * value_text = trim_and_extract_slice (value, 0); + if ((value_text == NULL) || (*value_text == '\0')) { + def->generated_resource = NULL; + def->has_generated_resource = true; + } else { + char * cursor = value_text; + struct string_slice resource_name = {0}; + struct string_slice token; + bool ok = true; + while (skip_white_space (&cursor) && parse_string (&cursor, &token)) { + if (slice_matches_str (&token, "local")) + def->generated_resource_flags |= MF_LOCAL; + else if (slice_matches_str (&token, "no-tech-req")) + def->generated_resource_flags |= MF_NO_TECH_REQ; + else if (slice_matches_str (&token, "yields")) + def->generated_resource_flags |= MF_YIELDS; + else if (resource_name.str == NULL) + resource_name = token; + else { + ok = false; + break; + } + } + + if (! ok || (resource_name.str == NULL)) { + def->generated_resource = NULL; + def->has_generated_resource = false; + def->generated_resource_flags = 0; + add_key_parse_error (parse_errors, line_number, key, value, + "(expected resource name plus optional flags: local, yields, no-tech-req)"); + } else { + def->generated_resource = extract_slice (&resource_name); + def->has_generated_resource = true; + } + } + free (value_text); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +bool +line_is_empty_or_comment (struct string_slice const * trimmed) +{ + return ((trimmed == NULL) || (trimmed->len == 0) || (trimmed->str[0] == ';') || (trimmed->str[0] == '[')); +} + +bool +file_exists_at_path (char const * path) +{ + if ((path == NULL) || (path[0] == '\0')) + return false; + + HANDLE file = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + return false; + + CloseHandle (file); + return true; +} + +void +load_dynamic_district_config_file (char const * file_path, + int path_is_relative_to_mod_dir, + int log_missing, + int drop_existing_configs) +{ + char path[MAX_PATH]; + if (path_is_relative_to_mod_dir) { + if (is->mod_rel_dir == NULL) + return; + snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); + } else { + strncpy (path, file_path, sizeof path); + } + path[(sizeof path) - 1] = '\0'; + + char * text = file_to_string (path); + if (text == NULL) { + if (log_missing) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] Districts config file not found: %s", path); + (*p_OutputDebugStringA) (ss); + } + return; + } + + if (drop_existing_configs) + reset_regular_district_configs (); + + struct parsed_district_definition def; + init_parsed_district_definition (&def); + bool in_section = false; + int section_start_line = 0; + int line_number = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + bool has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if ((directive.len > 0) && slice_matches_str (&directive, "District")) { + if (in_section) + finalize_parsed_district_definition (&def, section_start_line); + in_section = true; + section_start_line = line_number; + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); + if (status == KVP_NO_EQUALS) { + char * line_text = extract_slice (&trimmed); + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); + err->text[(sizeof err->text) - 1] = '\0'; + free (line_text); + cursor = has_newline ? line_end + 1 : line_end; + continue; + } else if (status == KVP_EMPTY_KEY) { + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); + err->text[(sizeof err->text) - 1] = '\0'; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + handle_district_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) + finalize_parsed_district_definition (&def, section_start_line); + + free_parsed_district_definition (&def); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + snprintf (is->current_districts_config_path, sizeof is->current_districts_config_path, path); + + if (parse_errors != NULL || unrecognized_keys != NULL) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "District Config errors in %s:", path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + if (parse_errors != NULL) { + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", false); + PopupForm_add_text (popup, __, "Unrecognized keys:", false); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + patch_show_popup (popup, __, 0, 0); + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); + } +} + +void +load_dynamic_district_configs () +{ + char * scenario_filename = "scenario.districts_config.txt"; + char * scenario_district_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + if ((scenario_district_config_path != NULL) && + (0 != strcmp (scenario_filename, scenario_district_config_path)) && + file_exists_at_path (scenario_district_config_path)) { + load_dynamic_district_config_file (scenario_district_config_path, 0, 0, 1); + return; + } + + if (is->mod_rel_dir != NULL) { + char user_path[MAX_PATH]; + snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_config.txt"); + user_path[(sizeof user_path) - 1] = '\0'; + if (file_exists_at_path (user_path)) { + load_dynamic_district_config_file ("user.districts_config.txt", 1, 0, 1); + return; + } + } + + load_dynamic_district_config_file ("default.districts_config.txt", 1, 1, 1); +} + +void +init_parsed_wonder_definition (struct parsed_wonder_definition * def) +{ + memset (def, 0, sizeof *def); + def->buildable_square_types_mask = district_default_buildable_mask (); + def->buildable_adjacent_to_square_types_mask = 0; + def->buildable_adjacent_to_overlays_mask = 0; + def->buildable_on_rivers = false; + def->buildable_adjacent_to_allows_city = false; + for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_traits_ids); i++) + def->buildable_by_civ_traits_ids[i] = -1; + for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_govs_ids); i++) + def->buildable_by_civ_govs_ids[i] = -1; + for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_cultures_ids); i++) + def->buildable_by_civ_cultures_ids[i] = -1; +} + +void +free_parsed_wonder_definition (struct parsed_wonder_definition * def) +{ + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + + for (int i = 0; i < def->buildable_by_civ_count; i++) { + if (def->buildable_by_civs[i] != NULL) { + free (def->buildable_by_civs[i]); + def->buildable_by_civs[i] = NULL; + } + } + def->buildable_by_civ_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + + init_parsed_wonder_definition (def); +} + +bool +add_dynamic_wonder_from_definition (struct parsed_wonder_definition * def, int section_start_line) +{ + int existing_index = -1; + for (int i = 0; i < is->wonder_district_count; i++) { + if ((is->wonder_district_configs[i].wonder_name != NULL) && + (strcmp (is->wonder_district_configs[i].wonder_name, def->name) == 0)) { + existing_index = i; + break; + } + } + + int dest = (existing_index >= 0) ? existing_index : is->wonder_district_count; + if ((dest < 0) || (dest >= MAX_WONDER_DISTRICT_TYPES)) + return false; + + struct wonder_district_config new_cfg; + memset (&new_cfg, 0, sizeof new_cfg); + new_cfg.index = dest; + new_cfg.is_dynamic = true; + new_cfg.wonder_name = strdup (def->name); + new_cfg.img_path = (def->img_path != NULL) ? strdup (def->img_path) : strdup ("Wonders.pcx"); + new_cfg.img_row = def->img_row; + new_cfg.img_column = def->img_column; + new_cfg.img_construct_row = def->img_construct_row; + new_cfg.img_construct_column = def->img_construct_column; + new_cfg.img_alt_dir_construct_row = def->img_alt_dir_construct_row; + new_cfg.img_alt_dir_construct_column = def->img_alt_dir_construct_column; + new_cfg.img_alt_dir_row = def->img_alt_dir_row; + new_cfg.img_alt_dir_column = def->img_alt_dir_column; + new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; + new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; + new_cfg.enable_img_alt_dir = def->enable_img_alt_dir; + new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); + new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; + new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; + new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; + new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; + new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; + const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); + if (new_cfg.buildable_by_civ_count > max_civ_names) + new_cfg.buildable_by_civ_count = max_civ_names; + for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { + new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; + def->buildable_by_civs[i] = NULL; + } + new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; + new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; + const int max_trait_entries = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); + if (new_cfg.buildable_by_civ_traits_id_count > max_trait_entries) + new_cfg.buildable_by_civ_traits_id_count = max_trait_entries; + for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) + new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; + new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; + new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; + const int max_gov_entries = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); + if (new_cfg.buildable_by_civ_govs_id_count > max_gov_entries) + new_cfg.buildable_by_civ_govs_id_count = max_gov_entries; + for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) + new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; + new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; + new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; + const int max_culture_entries = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); + if (new_cfg.buildable_by_civ_cultures_id_count > max_culture_entries) + new_cfg.buildable_by_civ_cultures_id_count = max_culture_entries; + for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) + new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; + new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; + new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; + new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; + + if (existing_index >= 0) { + struct wonder_district_config * cfg = &is->wonder_district_configs[existing_index]; + free_dynamic_wonder_config (cfg); + *cfg = new_cfg; + cfg->index = existing_index; + } else { + struct wonder_district_config * cfg = &is->wonder_district_configs[dest]; + free_dynamic_wonder_config (cfg); + *cfg = new_cfg; + is->wonder_district_count += 1; + } + + return true; +} + +void +finalize_parsed_wonder_definition (struct parsed_wonder_definition * def, + int section_start_line, + struct error_line ** parse_errors) +{ + bool ok = true; + + if ((! def->has_name) || (def->name == NULL)) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_construct_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_row (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_construct_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_column (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (def->enable_img_alt_dir) { + if (! def->has_img_alt_dir_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_row (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_alt_dir_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_column (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_alt_dir_construct_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_row (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_alt_dir_construct_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_column (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + } + + if (ok) + add_dynamic_wonder_from_definition (def, section_start_line); + + free_parsed_wonder_definition (def); +} + +void +handle_wonder_definition_key (struct parsed_wonder_definition * def, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if (slice_matches_str (key, "name")) { + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else { + char * name_copy = extract_slice (&unquoted); + if (name_copy == NULL) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); + } else { + def->name = name_copy; + def->has_name = true; + } + } + + } else if (slice_matches_str (key, "img_path")) { + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_img_path = false; + } else { + char * path_copy = extract_slice (&unquoted); + if (path_copy == NULL) { + def->has_img_path = false; + } else { + def->img_path = path_copy; + def->has_img_path = true; + } + } + + } else if (slice_matches_str (key, "img_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_row = ival; + def->has_img_row = true; + } else { + def->has_img_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_column = ival; + def->has_img_column = true; + } else { + def->has_img_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_construct_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_construct_row = ival; + def->has_img_construct_row = true; + } else { + def->has_img_construct_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_construct_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_construct_column = ival; + def->has_img_construct_column = true; + } else { + def->has_img_construct_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_construct_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_construct_row = ival; + def->has_img_alt_dir_construct_row = true; + } else { + def->has_img_alt_dir_construct_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_construct_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_construct_column = ival; + def->has_img_alt_dir_construct_column = true; + } else { + def->has_img_alt_dir_construct_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_row = ival; + def->has_img_alt_dir_row = true; + } else { + def->has_img_alt_dir_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_column = ival; + def->has_img_alt_dir_column = true; + } else { + def->has_img_alt_dir_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "custom_width")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_width = ival; + def->has_custom_width = true; + } else { + def->has_custom_width = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "custom_height")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_height = ival; + def->has_custom_height = true; + } else { + def->has_custom_height = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "enable_img_alt_dir")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->enable_img_alt_dir = (ival != 0); + def->has_enable_img_alt_dir = true; + } else { + def->has_enable_img_alt_dir = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "buildable_on")) { + unsigned int mask; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { + def->buildable_square_types_mask = mask; + def->has_buildable_on = true; + } else { + def->has_buildable_on = false; + } + + } else if (slice_matches_str (key, "buildable_on_rivers")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_on_rivers = (ival != 0); + def->has_buildable_on_rivers = true; + } else { + def->has_buildable_on_rivers = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "buildable_adjacent_to")) { + unsigned int mask; + def->buildable_adjacent_to_allows_city = false; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { + def->buildable_adjacent_to_square_types_mask = mask; + def->has_buildable_adjacent_to = true; + } else { + def->has_buildable_adjacent_to = false; + } + + } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { + def->buildable_adjacent_to_overlays_mask = mask; + def->has_buildable_adjacent_to_overlays = true; + } else { + def->has_buildable_adjacent_to_overlays = false; + } + + } else if (slice_matches_str (key, "buildable_by_civs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civs, + ARRAY_LEN (def->buildable_by_civs), + &list_count, + parse_errors, + line_number, + "buildable_by_civs")) { + def->buildable_by_civ_count = list_count; + def->has_buildable_by_civs = true; + } else { + def->buildable_by_civ_count = 0; + def->has_buildable_by_civs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_traits")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_traits, + ARRAY_LEN (def->buildable_by_civ_traits), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_traits")) { + def->buildable_by_civ_traits_count = list_count; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + char const * trait_name = def->buildable_by_civ_traits[i]; + if ((trait_name == NULL) || (trait_name[0] == '\0')) + continue; + int trait_id = -1; + struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; + if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { + if (def->buildable_by_civ_traits_ids[k] == trait_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) + def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->has_buildable_by_civ_traits = true; + } else { + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + def->has_buildable_by_civ_traits = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_govs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_govs, + ARRAY_LEN (def->buildable_by_civ_govs), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_govs")) { + def->buildable_by_civ_govs_count = list_count; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + char const * gov_name = def->buildable_by_civ_govs[i]; + if ((gov_name == NULL) || (gov_name[0] == '\0')) + continue; + int gov_id = -1; + struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; + if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { + if (def->buildable_by_civ_govs_ids[k] == gov_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) + def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->has_buildable_by_civ_govs = true; + } else { + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + def->has_buildable_by_civ_govs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_cultures, + ARRAY_LEN (def->buildable_by_civ_cultures), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_cultures")) { + def->buildable_by_civ_cultures_count = list_count; + def->buildable_by_civ_cultures_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + char const * culture_name = def->buildable_by_civ_cultures[i]; + if ((culture_name == NULL) || (culture_name[0] == '\0')) + continue; + int culture_id = -1; + struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; + if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { + if (def->buildable_by_civ_cultures_ids[k] == culture_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) + def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->has_buildable_by_civ_cultures = true; + } else { + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + def->has_buildable_by_civ_cultures = false; + } + free (value_text); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +void +load_dynamic_wonder_config_file (char const * file_path, + int path_is_relative_to_mod_dir, + int log_missing, + int drop_existing_configs) +{ + char path[MAX_PATH]; + if (path_is_relative_to_mod_dir) { + if (is->mod_rel_dir == NULL) + return; + snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); + } else { + strncpy (path, file_path, sizeof path); + } + path[(sizeof path) - 1] = '\0'; + + char * text = file_to_string (path); + if (text == NULL) { + if (log_missing) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] Wonders config file not found: %s", path); + (*p_OutputDebugStringA) (ss); + } + return; + } + + if (drop_existing_configs) + reset_wonder_district_configs (); + + struct parsed_wonder_definition def; + init_parsed_wonder_definition (&def); + bool in_section = false; + int section_start_line = 0; + int line_number = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + bool has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { + if (in_section) + finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); + in_section = true; + section_start_line = line_number; + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); + if (status == KVP_NO_EQUALS) { + char * line_text = extract_slice (&trimmed); + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); + err->text[(sizeof err->text) - 1] = '\0'; + free (line_text); + cursor = has_newline ? line_end + 1 : line_end; + continue; + } else if (status == KVP_EMPTY_KEY) { + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); + err->text[(sizeof err->text) - 1] = '\0'; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + handle_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) + finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); + + free_parsed_wonder_definition (&def); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + + if (parse_errors != NULL || unrecognized_keys != NULL) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "Wonder District Config errors in %s:", path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + if (parse_errors != NULL) { + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", false); + PopupForm_add_text (popup, __, "Unrecognized keys:", false); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + patch_show_popup (popup, __, 0, 0); + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); + } +} + +void +load_dynamic_wonder_configs () +{ + char * scenario_filename = "scenario.districts_wonders_config.txt"; + char * scenario_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + if ((scenario_wonder_config_path != NULL) && + (0 != strcmp (scenario_filename, scenario_wonder_config_path)) && + file_exists_at_path (scenario_wonder_config_path)) { + load_dynamic_wonder_config_file (scenario_wonder_config_path, 0, 0, 1); + return; + } + + if (is->mod_rel_dir != NULL) { + char user_path[MAX_PATH]; + snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_wonders_config.txt"); + user_path[(sizeof user_path) - 1] = '\0'; + if (file_exists_at_path (user_path)) { + load_dynamic_wonder_config_file ("user.districts_wonders_config.txt", 1, 0, 1); + return; + } + } + + load_dynamic_wonder_config_file ("default.districts_wonders_config.txt", 1, 1, 1); +} + +void +init_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) +{ + memset (def, 0, sizeof *def); + def->terrain_type = SQ_Grassland; + def->adjacent_to = (enum SquareTypes)SQ_INVALID; + def->adjacency_dir = DIR_ZERO; +} + +void +free_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) +{ + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + init_parsed_natural_wonder_definition (def); +} + +bool +add_natural_wonder_from_definition (struct parsed_natural_wonder_definition * def, int section_start_line) +{ + if ((def == NULL) || (def->name == NULL)) + return false; + + int existing_index; + bool has_existing = stable_look_up (&is->natural_wonder_name_to_id, def->name, &existing_index); + + int dest = has_existing ? existing_index : is->natural_wonder_count; + if ((dest < 0) || (dest >= MAX_NATURAL_WONDER_DISTRICT_TYPES)) + return false; + + struct natural_wonder_district_config new_cfg; + memset (&new_cfg, 0, sizeof new_cfg); + new_cfg.index = dest; + new_cfg.is_dynamic = true; + new_cfg.adjacent_to = (enum SquareTypes)SQ_INVALID; + new_cfg.adjacency_dir = DIR_ZERO; + + char * name_copy = strdup (def->name); + if (name_copy == NULL) + return false; + new_cfg.name = name_copy; + + char const * img_path_src = def->img_path; + char * img_copy = strdup (img_path_src); + if (img_copy == NULL) { + free (name_copy); + return false; + } + new_cfg.img_path = img_copy; + new_cfg.img_row = def->img_row; + new_cfg.img_column = def->img_column; + new_cfg.terrain_type = def->terrain_type; + new_cfg.adjacent_to = def->adjacent_to; + new_cfg.adjacency_dir = def->adjacency_dir; + new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; + new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; + new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; + new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; + new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; + new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; + new_cfg.impassible = def->has_impassible ? def->impassible : false; + new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; + + if (has_existing) { + struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[existing_index]; + free_dynamic_natural_wonder_config (cfg); + *cfg = new_cfg; + } else { + struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[dest]; + free_dynamic_natural_wonder_config (cfg); + *cfg = new_cfg; + is->natural_wonder_count = dest + 1; + stable_insert (&is->natural_wonder_name_to_id, new_cfg.name, dest); + } + + return true; +} + +void +finalize_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def, + int section_start_line, + struct error_line ** parse_errors) +{ + bool ok = true; + + if ((! def->has_name) || (def->name == NULL)) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_terrain_type) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: terrain_type (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + if (ok) + add_natural_wonder_from_definition (def, section_start_line); + + free_parsed_natural_wonder_definition (def); +} + +void +handle_natural_wonder_definition_key (struct parsed_natural_wonder_definition * def, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if (slice_matches_str (key, "name")) { + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else { + char * name_copy = extract_slice (&unquoted); + if (name_copy == NULL) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); + } else { + def->name = name_copy; + def->has_name = true; + } + } + + } else if (slice_matches_str (key, "terrain_type")) { + enum SquareTypes terrain; + if (read_natural_wonder_terrain_type (value, &terrain)) { + def->terrain_type = terrain; + def->has_terrain_type = true; + } else { + def->has_terrain_type = false; + add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized terrain type)"); + } + + } else if (slice_matches_str (key, "adjacent_to")) { + enum SquareTypes adj; + if (read_tile_terrain_type_value (value, &adj)) { + def->adjacent_to = adj; + def->has_adjacent_to = true; + } else { + def->adjacent_to = (enum SquareTypes)SQ_INVALID; + def->has_adjacent_to = false; + add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized tile terrain type)"); + } + + } else if (slice_matches_str (key, "adjacency_dir")) { + enum direction dir; + if (read_direction_value (value, &dir)) { + def->adjacency_dir = dir; + def->has_adjacency_dir = true; + } else { + def->adjacency_dir = DIR_ZERO; + def->has_adjacency_dir = false; + add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized direction)"); + } + + } else if (slice_matches_str (key, "img_path")) { + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_img_path = false; + } else { + char * path_copy = extract_slice (&unquoted); + if (path_copy == NULL) { + def->has_img_path = false; + } else { + def->img_path = path_copy; + def->has_img_path = true; + } + } + + } else if (slice_matches_str (key, "img_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_row = ival; + def->has_img_row = true; + } else { + def->has_img_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_column = ival; + def->has_img_column = true; + } else { + def->has_img_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "culture_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->culture_bonus = ival; + def->has_culture_bonus = true; + } else { + def->has_culture_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "science_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->science_bonus = ival; + def->has_science_bonus = true; + } else { + def->has_science_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "food_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->food_bonus = ival; + def->has_food_bonus = true; + } else { + def->has_food_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "gold_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->gold_bonus = ival; + def->has_gold_bonus = true; + } else { + def->has_gold_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "shield_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->shield_bonus = ival; + def->has_shield_bonus = true; + } else { + def->has_shield_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "happiness_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->happiness_bonus = ival; + def->has_happiness_bonus = true; + } else { + def->has_happiness_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "impassible")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible = (ival != 0); + def->has_impassible = true; + } else { + def->has_impassible = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "impassible_to_wheeled")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible_to_wheeled = (ival != 0); + def->has_impassible_to_wheeled = true; + } else { + def->has_impassible_to_wheeled = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +void +load_natural_wonder_config_file (char const * file_path, + int path_is_relative_to_mod_dir, + int log_missing, + int drop_existing_configs) +{ + char path[MAX_PATH]; + if (path_is_relative_to_mod_dir) { + if (is->mod_rel_dir == NULL) + return; + snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); + } else { + strncpy (path, file_path, sizeof path); + } + path[(sizeof path) - 1] = '\0'; + + char * text = file_to_string (path); + if (text == NULL) { + if (log_missing) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] Natural wonders config file not found: %s", path); + (*p_OutputDebugStringA) (ss); + } + return; + } + + if (drop_existing_configs) + reset_natural_wonder_configs (); + + struct parsed_natural_wonder_definition def; + init_parsed_natural_wonder_definition (&def); + bool in_section = false; + int section_start_line = 0; + int line_number = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + bool has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { + if (in_section) + finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); + in_section = true; + section_start_line = line_number; + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); + if (status == KVP_NO_EQUALS) { + char * line_text = extract_slice (&trimmed); + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); + err->text[(sizeof err->text) - 1] = '\0'; + free (line_text); + cursor = has_newline ? line_end + 1 : line_end; + continue; + } else if (status == KVP_EMPTY_KEY) { + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); + err->text[(sizeof err->text) - 1] = '\0'; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + handle_natural_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) + finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); + + free_parsed_natural_wonder_definition (&def); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + + if (parse_errors != NULL || unrecognized_keys != NULL) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "Natural Wonder Config errors in %s:", path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + if (parse_errors != NULL) { + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", false); + PopupForm_add_text (popup, __, "Unrecognized keys:", false); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + patch_show_popup (popup, __, 0, 0); + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); + } +} + +void +load_natural_wonder_configs () +{ + char * scenario_filename = "scenario.districts_natural_wonders_config.txt"; + char * scenario_natural_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + if ((scenario_natural_wonder_config_path != NULL) && + (0 != strcmp (scenario_filename, scenario_natural_wonder_config_path)) && + file_exists_at_path (scenario_natural_wonder_config_path)) { + load_natural_wonder_config_file (scenario_natural_wonder_config_path, 0, 0, 1); + return; + } + + if (is->mod_rel_dir != NULL) { + char user_path[MAX_PATH]; + snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_natural_wonders_config.txt"); + user_path[(sizeof user_path) - 1] = '\0'; + if (file_exists_at_path (user_path)) { + load_natural_wonder_config_file ("user.districts_natural_wonders_config.txt", 1, 0, 1); + return; + } + } + + load_natural_wonder_config_file ("default.districts_natural_wonders_config.txt", 1, 1, 1); +} + +bool +district_config_has_dependent_improvement (struct district_config * cfg, char const * name) +{ + if ((cfg == NULL) || (name == NULL) || (name[0] == '\0')) + return false; + + for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { + char const * existing = cfg->dependent_improvements[i]; + if ((existing != NULL) && (strcmp (existing, name) == 0)) + return true; + } + return false; +} + +bool +find_civ_trait_id_by_name (struct string_slice const * name, int * out_id) +{ + if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) + return false; + + struct trait_entry { enum c3x_label label; char const * fallback_name; int id; } traits[] = { + {CL_AGRICULTURAL, "Agricultural", 6}, + {CL_COMMERCIAL, "Commercial", 1}, + {CL_EXPANSIONIST, "Expansionist", 2}, + {CL_INDUSTRIOUS, "Industrious", 5}, + {CL_MILITARISTIC, "Militaristic", 0}, + {CL_RELIGIOUS, "Religious", 4}, + {CL_SCIENTIFIC, "Scientific", 3}, + {CL_SEAFARING, "Seafaring", 7} + }; + + for (int i = 0; i < ARRAY_LEN (traits); i++) { + char const * localized_name = is->c3x_labels[traits[i].label]; + if (((localized_name != NULL) && (localized_name[0] != '\0') && slice_matches_str (name, localized_name)) + || slice_matches_str (name, traits[i].fallback_name)) { + *out_id = traits[i].id; + return true; + } + } + + return false; +} + +bool +find_civ_culture_id_by_name (struct string_slice const * name, int * out_id) +{ + if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) + return false; + + struct culture_entry { char const * name; int id; } cultures[] = { + {"American", 0}, + {"AMERICAN", 0}, + {"AMER", 0}, + {"European", 1}, + {"EUROPEAN", 1}, + {"EURO", 1}, + {"Roman", 2}, + {"ROMAN", 2}, + {"Mid East", 3}, + {"Mideast", 3}, + {"MIDEAST", 3}, + {"Asian", 4}, + {"ASIAN", 4} + }; + + for (int i = 0; i < ARRAY_LEN (cultures); i++) { + if (slice_matches_str (name, cultures[i].name)) { + *out_id = cultures[i].id; + return true; + } + } + + return false; +} + +int +find_district_index_by_name (char const * name) +{ + if ((name == NULL) || (name[0] == '\0')) + return -1; + + for (int i = 0; i < is->district_count; i++) { + char const * existing = is->district_configs[i].name; + if ((existing != NULL) && (strcmp (existing, name) == 0)) + return i; + } + + return -1; +} + +int +find_wonder_district_index_by_name (char const * name) +{ + if ((name == NULL) || (name[0] == '\0')) + return -1; + + int improv_id; + if (! stable_look_up (&is->building_name_to_id, (char *)name, &improv_id)) + return -1; + + return find_wonder_config_index_by_improvement_id (improv_id); +} + +int +find_natural_wonder_index_by_name (char const * name) +{ + if ((name == NULL) || (name[0] == '\0') || (is == NULL)) + return -1; + + for (int i = 0; i < is->natural_wonder_count; i++) { + char const * existing = is->natural_wonder_configs[i].name; + if ((existing != NULL) && (strcmp (existing, name) == 0)) + return i; + } + return -1; +} + +void +set_wonders_dependent_on_wonder_district (void) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_wonder_districts) + return; + + struct district_config * cfg = &is->district_configs[WONDER_DISTRICT_ID]; + for (int wi = 0; wi < is->wonder_district_count; wi++) { + char const * wonder_name = is->wonder_district_configs[wi].wonder_name; + if ((wonder_name == NULL) || (wonder_name[0] == '\0')) + continue; + if (district_config_has_dependent_improvement (cfg, wonder_name)) + continue; + + int dest = cfg->dependent_improvement_max_index; + if (dest >= ARRAY_LEN (cfg->dependent_improvements)) { + continue; + } + + char * copy = strdup (wonder_name); + if (copy == NULL) { + continue; + } + + cfg->dependent_improvements[dest] = copy; + cfg->dependent_improvement_max_index = dest + 1; + } + + if (! cfg->has_img_column_count_override && + (cfg->img_column_count < cfg->dependent_improvement_max_index + 1)) + cfg->img_column_count = cfg->dependent_improvement_max_index + 1; +} + +void +resolve_district_bonus_building_entries (struct district_bonus_list * list, + char const * district_name, + char const * bonus_name, + struct error_line ** parse_errors) +{ + if (list == NULL) + return; + + for (int i = 0; i < list->count; i++) { + struct district_bonus_entry * entry = &list->entries[i]; + if (entry->type != DBET_BUILDING) + continue; + if ((entry->building_name == NULL) || (entry->building_name[0] == '\0')) { + entry->building_id = -1; + continue; + } + + int improv_id; + struct string_slice improv_name = { .str = (char *)entry->building_name, .len = (int)strlen (entry->building_name) }; + if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { + entry->building_id = improv_id; + stable_insert (&is->building_name_to_id, improv_name.str, improv_id); + } else { + entry->building_id = -1; + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": %s entry \"%.*s\" not found", + district_name, bonus_name, improv_name.len, improv_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } +} + +void parse_building_and_tech_ids () +{ + struct c3x_config * cfg = &is->current_config; + char ss[200]; + struct error_line * district_parse_errors = NULL; + struct error_line * wonder_parse_errors = NULL; + + cfg->great_wall_auto_build_wonder_improv_id = -1; + if (cfg->enable_districts && + cfg->enable_great_wall_districts && + cfg->auto_build_great_wall_around_territory && + cfg->great_wall_auto_build_wonder_name != NULL && + cfg->great_wall_auto_build_wonder_name[0] != '\0') { + struct string_slice wonder_name = { + .str = cfg->great_wall_auto_build_wonder_name, + .len = strlen (cfg->great_wall_auto_build_wonder_name) + }; + if (! find_improv_id_by_name (&wonder_name, &cfg->great_wall_auto_build_wonder_improv_id)) { + snprintf (ss, sizeof ss, + "Error reading config: The value for \"great_wall_auto_build_wonder_name\" is invalid: \"%s\"", + cfg->great_wall_auto_build_wonder_name); + ss[(sizeof ss) - 1] = '\0'; + pop_up_in_game_error (ss); + } + } + + for (int i = 0; i < is->district_count; i++) { + char const * district_name = (is->district_configs[i].name != NULL) ? is->district_configs[i].name : "District"; + if (! district_is_included_by_final_config (i)) { + is->district_infos[i].advance_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) + is->district_infos[i].advance_prereq_ids[j] = -1; + is->district_infos[i].obsoleted_by_id = -1; + is->district_infos[i].resource_prereq_count = 0; + for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) + is->district_infos[i].resource_prereq_ids[j] = -1; + is->district_infos[i].resource_prereq_on_tile_id = -1; + is->district_infos[i].wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) + is->district_infos[i].wonder_prereq_ids[j] = -1; + is->district_infos[i].natural_wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) + is->district_infos[i].natural_wonder_prereq_ids[j] = -1; + is->district_infos[i].dependent_building_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) + is->district_infos[i].dependent_building_ids[j] = -1; + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) + is->district_configs[i].buildable_on_district_ids[j] = -1; + is->district_configs[i].buildable_on_district_id_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) + is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; + is->district_configs[i].buildable_adjacent_to_district_id_count = 0; + is->district_configs[i].generated_resource_id = -1; + continue; + } + if ((is->district_configs[i].name != NULL) && + (is->district_configs[i].command != 0) && + (is->district_configs[i].command != -1)) + itable_insert (&is->command_id_to_district_id, is->district_configs[i].command, i); + is->district_infos[i].advance_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) + is->district_infos[i].advance_prereq_ids[j] = -1; + is->district_infos[i].obsoleted_by_id = -1; + is->district_infos[i].resource_prereq_count = 0; + for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) + is->district_infos[i].resource_prereq_ids[j] = -1; + is->district_infos[i].resource_prereq_on_tile_id = -1; + is->district_infos[i].wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) + is->district_infos[i].wonder_prereq_ids[j] = -1; + is->district_infos[i].natural_wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) + is->district_infos[i].natural_wonder_prereq_ids[j] = -1; + + // Map advance prereqs to districts + int stored_tech_count = 0; + for (int j = 0; j < is->district_configs[i].advance_prereq_count; j++) { + char const * prereq = is->district_configs[i].advance_prereqs[j]; + if (prereq == NULL || prereq[0] == '\0') + continue; + int tech_id; + struct string_slice tech_name = { .str = (char *)prereq, .len = (int)strlen (prereq) }; + if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { + snprintf (ss, sizeof ss, "Found tech prereq \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); + (*p_OutputDebugStringA) (ss); + if (stored_tech_count < ARRAY_LEN (is->district_infos[i].advance_prereq_ids)) { + is->district_infos[i].advance_prereq_ids[stored_tech_count] = tech_id; + stored_tech_count++; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": advance_prereqs entry \"%.*s\" not found", district_name, tech_name.len, tech_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].advance_prereq_count = stored_tech_count; + + // Map obsoleted_by to tech ID + if (is->district_configs[i].obsoleted_by != NULL && is->district_configs[i].obsoleted_by != "") { + int tech_id; + struct string_slice tech_name = { .str = (char *)is->district_configs[i].obsoleted_by, .len = (int)strlen (is->district_configs[i].obsoleted_by) }; + if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { + snprintf (ss, sizeof ss, "Found tech obsoleted_by \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); + (*p_OutputDebugStringA) (ss); + is->district_infos[i].obsoleted_by_id = tech_id; + } else { + is->district_infos[i].obsoleted_by_id = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": obsoleted_by \"%.*s\" not found", district_name, tech_name.len, tech_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + // Map resource prereqs to districts (multiple resources now supported) + int stored_res_count = 0; + for (int j = 0; j < is->district_configs[i].resource_prereq_count; j++) { + if (is->district_configs[i].resource_prereqs[j] == "" || is->district_configs[i].resource_prereqs[j] == NULL) + continue; + int res_id; + struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereqs[j], .len = (int)strlen (is->district_configs[i].resource_prereqs[j]) }; + if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { + snprintf (ss, sizeof ss, "Found resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); + (*p_OutputDebugStringA) (ss); + if (stored_res_count < ARRAY_LEN (is->district_infos[i].resource_prereq_ids)) { + is->district_infos[i].resource_prereq_ids[stored_res_count] = res_id; + stored_res_count++; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq \"%.*s\" not found", district_name, res_name.len, res_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].resource_prereq_count = stored_res_count; + if (is->district_configs[i].resource_prereq_on_tile != NULL && is->district_configs[i].resource_prereq_on_tile != "") { + int res_id; + struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereq_on_tile, .len = (int)strlen (is->district_configs[i].resource_prereq_on_tile) }; + if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { + snprintf (ss, sizeof ss, "Found on-tile resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); + (*p_OutputDebugStringA) (ss); + is->district_infos[i].resource_prereq_on_tile_id = res_id; + } else { + is->district_infos[i].resource_prereq_on_tile_id = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq_on_tile \"%.*s\" not found", district_name, res_name.len, res_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + int stored_wonder_count = 0; + for (int j = 0; j < is->district_configs[i].wonder_prereq_count; j++) { + if (is->district_configs[i].wonder_prereqs[j] == "" || is->district_configs[i].wonder_prereqs[j] == NULL) + continue; + int improv_id; + struct string_slice wonder_name = { .str = (char *)is->district_configs[i].wonder_prereqs[j], .len = (int)strlen (is->district_configs[i].wonder_prereqs[j]) }; + if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { + if (stored_wonder_count < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids)) { + is->district_infos[i].wonder_prereq_ids[stored_wonder_count] = improv_id; + stored_wonder_count += 1; + } + stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": wonder_prereqs entry \"%.*s\" not found", district_name, wonder_name.len, wonder_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].wonder_prereq_count = stored_wonder_count; + + int stored_natural_wonder_count = 0; + for (int j = 0; j < is->district_configs[i].natural_wonder_prereq_count; j++) { + if (is->district_configs[i].natural_wonder_prereqs[j] == "" || is->district_configs[i].natural_wonder_prereqs[j] == NULL) + continue; + int natural_wonder_id = -1; + char const * name = is->district_configs[i].natural_wonder_prereqs[j]; + if (stable_look_up (&is->natural_wonder_name_to_id, (char *)name, &natural_wonder_id)) { + if (stored_natural_wonder_count < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids)) { + is->district_infos[i].natural_wonder_prereq_ids[stored_natural_wonder_count] = natural_wonder_id; + stored_natural_wonder_count += 1; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": natural_wonder_prereqs entry \"%s\" not found", district_name, name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].natural_wonder_prereq_count = stored_natural_wonder_count; + + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) + is->district_configs[i].buildable_on_district_ids[j] = -1; + is->district_configs[i].buildable_on_district_id_count = 0; + + if (is->district_configs[i].has_buildable_on_districts) { + int stored_buildable_on_count = 0; + for (int j = 0; j < is->district_configs[i].buildable_on_district_count; j++) { + char const * name = is->district_configs[i].buildable_on_districts[j]; + if (name == NULL || name[0] == '\0') + continue; + int other_district_id = find_district_index_by_name (name); + if (other_district_id >= 0) { + if (stored_buildable_on_count < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids)) { + is->district_configs[i].buildable_on_district_ids[stored_buildable_on_count] = other_district_id; + stored_buildable_on_count += 1; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_on_districts entry \"%s\" not found", district_name, name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_configs[i].buildable_on_district_id_count = stored_buildable_on_count; + } + + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) + is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; + is->district_configs[i].buildable_adjacent_to_district_id_count = 0; + + if (is->district_configs[i].has_buildable_adjacent_to_districts) { + int stored_adjacent_count = 0; + for (int j = 0; j < is->district_configs[i].buildable_adjacent_to_district_count; j++) { + char const * name = is->district_configs[i].buildable_adjacent_to_districts[j]; + if (name == NULL || name[0] == '\0') + continue; + int other_district_id = find_district_index_by_name (name); + if (other_district_id >= 0) { + if (stored_adjacent_count < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids)) { + is->district_configs[i].buildable_adjacent_to_district_ids[stored_adjacent_count] = other_district_id; + stored_adjacent_count += 1; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_adjacent_to_districts entry \"%s\" not found", district_name, name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_configs[i].buildable_adjacent_to_district_id_count = stored_adjacent_count; + } + + // Resolve generated resource name to ID + if (is->district_configs[i].generated_resource != NULL && is->district_configs[i].generated_resource != "") { + int res_id; + struct string_slice res_name = { .str = (char *)is->district_configs[i].generated_resource, .len = (int)strlen (is->district_configs[i].generated_resource) }; + if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { + snprintf (ss, sizeof ss, "Found generated resource \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); + (*p_OutputDebugStringA) (ss); + is->district_configs[i].generated_resource_id = res_id; + } else { + is->district_configs[i].generated_resource_id = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": generated_resource \"%.*s\" not found", district_name, res_name.len, res_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + // Map improvement prereqs to districts + int stored_count = 0; + for (int j = 0; j < is->district_configs[i].dependent_improvement_max_index; j++) { + int improv_id; + if (is->district_configs[i].dependent_improvements[j] == "" || is->district_configs[i].dependent_improvements[j] == NULL) + continue; + + // Gate wonder district prereqs behind enable_wonder_districts + if ((is->district_configs[i].command == UCV_Build_WonderDistrict) && (! cfg->enable_wonder_districts)) + continue; + + struct string_slice improv_name = { .str = (char *)is->district_configs[i].dependent_improvements[j], .len = (int)strlen (is->district_configs[i].dependent_improvements[j]) }; + if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { + snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for district \"%s\", ID %d\n", improv_name.len, improv_name.str, district_name, improv_id); + (*p_OutputDebugStringA) (ss); + if (stored_count < ARRAY_LEN (is->district_infos[i].dependent_building_ids)) { + is->district_infos[i].dependent_building_ids[stored_count] = improv_id; + stored_count += 1; + } + add_district_building_prereq (improv_id, i); + stable_insert (&is->building_name_to_id, improv_name.str, improv_id); + } else { + is->district_infos[i].dependent_building_ids[j] = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": dependent_improvs entry \"%.*s\" not found", district_name, improv_name.len, improv_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + is->district_infos[i].dependent_building_count = stored_count; + } + + resolve_district_bonus_building_entries (&is->district_configs[i].culture_bonus_extras, district_name, "culture_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].science_bonus_extras, district_name, "science_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].food_bonus_extras, district_name, "food_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].gold_bonus_extras, district_name, "gold_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].shield_bonus_extras, district_name, "shield_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].happiness_bonus_extras, district_name, "happiness_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].defense_bonus_extras, district_name, "defense_bonus_percent", &district_parse_errors); + } + + // Map wonder names to their improvement IDs for rendering under-construction wonders + for (int wi = 0; wi < is->wonder_district_count; wi++) { + if (is->wonder_district_configs[wi].wonder_name == NULL || is->wonder_district_configs[wi].wonder_name[0] == '\0') + continue; + + int improv_id; + struct string_slice wonder_name = { .str = (char *)is->wonder_district_configs[wi].wonder_name, .len = (int)strlen (is->wonder_district_configs[wi].wonder_name) }; + if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { + snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for wonder district \"%s\", ID %d\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name, improv_id); + (*p_OutputDebugStringA) (ss); + stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); + } else { + snprintf (ss, sizeof ss, "Could not find improvement prereq \"%.*s\" for wonder district \"%s\"\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name); + (*p_OutputDebugStringA) (ss); + struct error_line * err = add_error_line (&wonder_parse_errors); + snprintf (err->text, sizeof err->text, "^ Wonder district \"%s\": improvement \"%.*s\" not found", (is->wonder_district_configs[wi].wonder_name != NULL) ? is->wonder_district_configs[wi].wonder_name : "Wonder District", wonder_name.len, wonder_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + if ((district_parse_errors != NULL) || (wonder_parse_errors != NULL)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + + if (district_parse_errors != NULL) { + char header[256]; + if (is->current_districts_config_path[0] != '\0') + snprintf (header, sizeof header, "District Config errors in %s:", is->current_districts_config_path); + else + snprintf (header, sizeof header, "District Config lookup errors:"); + header[(sizeof header) - 1] = '\0'; + PopupForm_add_text (popup, __, header, false); + for (struct error_line * line = district_parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + + if ((district_parse_errors != NULL) && (wonder_parse_errors != NULL)) + PopupForm_add_text (popup, __, "", false); + + if (wonder_parse_errors != NULL) { + char header[256]; + snprintf (header, sizeof header, "Wonder District Config lookup errors:"); + header[(sizeof header) - 1] = '\0'; + PopupForm_add_text (popup, __, header, false); + for (struct error_line * line = wonder_parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + + patch_show_popup (popup, __, 0, 0); + free_error_lines (district_parse_errors); + free_error_lines (wonder_parse_errors); + } +} + +void +load_districts_config () +{ + clear_dynamic_district_definitions (); + load_dynamic_district_configs (); + load_dynamic_wonder_configs (); + load_natural_wonder_configs (); + is->district_count = is->special_district_count + is->dynamic_district_count; + + set_wonders_dependent_on_wonder_district (); + parse_building_and_tech_ids (); +} + +void +place_natural_wonders_on_map (void) +{ + if (! is->current_config.enable_natural_wonders) + return; + + int wonder_count = is->natural_wonder_count; + if (wonder_count <= 0) + return; + + struct natural_wonder_candidate_list * candidate_lists = (struct natural_wonder_candidate_list *)calloc (wonder_count, sizeof *candidate_lists); + bool * already_placed = (bool *)calloc (wonder_count, sizeof *already_placed); + + if ((candidate_lists == NULL) || (already_placed == NULL)) { + if (candidate_lists != NULL) free (candidate_lists); + if (already_placed != NULL) free (already_placed); + return; + } + + struct wonder_location * placements = NULL; + int placement_count = 0; + int placement_capacity = 0; + int existing_count = 0; + + // Record existing natural wonders + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + + int wonder_id = inst->natural_wonder_info.natural_wonder_id; + if ((wonder_id < 0) || (wonder_id >= wonder_count)) + continue; + + already_placed[wonder_id] = true; + + Tile * tile = (Tile *)tei.key; + int tile_x, tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + continue; + + if (placement_count >= placement_capacity) { + int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; + struct wonder_location * grown = + (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); + if (grown == NULL) + continue; + placements = grown; + placement_capacity = new_capacity; + } + + if (placements != NULL) { + placements[placement_count++] = (struct wonder_location){ + .x = (short)tile_x, + .y = (short)tile_y + }; + existing_count += 1; + } + } + + // Build candidate lists + int map_width = p_bic_data->Map.Width; + int map_height = p_bic_data->Map.Height; + int minimum_separation = is->current_config.minimum_natural_wonder_separation; + + for (int y = 0; y < map_height; y++) { + for (int x = 0; x < map_width; x++) { + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + if (! natural_wonder_tile_is_clear (tile, x, y)) continue; + if (district_exists_within_distance (x, y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; + + for (int ni = 0; ni < wonder_count; ni++) { + if (already_placed[ni]) + continue; + + struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; + if (cfg->name == NULL) + continue; + + if (! natural_wonder_terrain_matches (cfg, tile, x, y)) + continue; + + natural_wonder_candidate_list_push (&candidate_lists[ni], tile, x, y); + } + } + } + + bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; + int newly_placed = 0; + int * wonder_order = (int *)malloc (wonder_count * sizeof *wonder_order); + if (wonder_order != NULL) { + for (int i = 0; i < wonder_count; i++) + wonder_order[i] = i; + for (int i = wonder_count - 1; i > 0; i--) { + int swap_index = rand_int (p_rand_object, __, i + 1); + int temp = wonder_order[i]; + wonder_order[i] = wonder_order[swap_index]; + wonder_order[swap_index] = temp; + } + } + + for (int order_index = 0; order_index < wonder_count; order_index++) { + int ni = (wonder_order != NULL) ? wonder_order[order_index] : order_index; + if (already_placed[ni]) + continue; + + struct natural_wonder_candidate_list * list = &candidate_lists[ni]; + if (list->count == 0) { + char msg[256]; + snprintf (msg, sizeof msg, "[C3X] No valid tiles to place natural wonder \"%s\".\n", + (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); + (*p_OutputDebugStringA) (msg); + continue; + } + + int best_index = -1; + int best_dist = -1; + int best_adjacent_count = -1; + int best_target_diff = INT_MAX; + int best_rand = INT_MAX; + int best_same_type_count = -1; + int best_continent_priority = INT_MAX; + int target_x = (wonder_count > 0) + ? (int)(((long long)(2 * ni + 1) * map_width) / (2 * wonder_count)) + : (map_width >> 1); + + for (int ci = 0; ci < list->count; ci++) { + struct natural_wonder_candidate * cand = &list->entries[ci]; + Tile * tile = cand->tile; + if ((tile == NULL) || (tile == p_null_tile)) continue; + if (get_district_instance (tile) != NULL) continue; + if (! natural_wonder_tile_is_clear (tile, cand->x, cand->y)) continue; + if (! natural_wonder_terrain_matches (&is->natural_wonder_configs[ni], tile, cand->x, cand->y)) continue; + if (district_exists_within_distance (cand->x, cand->y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; + + int min_dist_sq = natural_wonder_min_distance_sq (cand->x, cand->y, placements, placement_count); + if (min_dist_sq == INT_MAX) { + int span = (map_width * map_width) + (map_height * map_height); + if (span <= 0) + span = INT_MAX; + min_dist_sq = span; + } + + int dx_raw = int_abs (cand->x - target_x); + int dx_adjusted = compute_wrapped_component (dx_raw, map_width, wraps_horiz); + int rand_val = rand_int (p_rand_object, __, 0x7FFF); + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + int continent_priority = 1; + if ((continent_id >= 0) && ! continent_has_natural_wonder (continent_id, placements, placement_count)) + continent_priority = 0; + + bool adjacency_bonus_active = + (is->natural_wonder_configs[ni].adjacent_to != (enum SquareTypes)SQ_INVALID) && + (is->natural_wonder_configs[ni].adjacency_dir == DIR_ZERO); + int adjacency_count = -1; + if (adjacency_bonus_active) + adjacency_count = count_adjacent_tiles_of_type (cand->x, cand->y, + is->natural_wonder_configs[ni].adjacent_to); + + int same_type_count = count_adjacent_tiles_of_type (cand->x, cand->y, + is->natural_wonder_configs[ni].terrain_type); + + bool better = false; + if (continent_priority < best_continent_priority) + better = true; + else if (continent_priority > best_continent_priority) + continue; + + if (! better && adjacency_bonus_active) { + if (adjacency_count > best_adjacent_count) + better = true; + else if (adjacency_count < best_adjacent_count) + continue; + } + + if (! better) { + if (same_type_count > best_same_type_count) + better = true; + else if (same_type_count < best_same_type_count) + continue; + } + + if (! better) { + if ((min_dist_sq > best_dist) || + ((min_dist_sq == best_dist) && (dx_adjusted < best_target_diff)) || + ((min_dist_sq == best_dist) && (dx_adjusted == best_target_diff) && (rand_val < best_rand))) + better = true; + else + continue; + } + + best_dist = min_dist_sq; + best_target_diff = dx_adjusted; + best_rand = rand_val; + best_index = ci; + best_continent_priority = continent_priority; + if (adjacency_bonus_active) + best_adjacent_count = adjacency_count; + best_same_type_count = same_type_count; + } + + if (best_index < 0) { + char msg[256]; + snprintf (msg, sizeof msg, "[C3X] Could not find a suitable tile for natural wonder \"%s\" after filtering.\n", + (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); + (*p_OutputDebugStringA) (msg); + continue; + } + + struct natural_wonder_candidate * chosen = &list->entries[best_index]; + assign_natural_wonder_to_tile (chosen->tile, chosen->x, chosen->y, ni); + + if (placement_count >= placement_capacity) { + int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; + struct wonder_location * grown = + (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); + if (grown != NULL) { + placements = grown; + placement_capacity = new_capacity; + } + } + + if ((placements != NULL) && (placement_count < placement_capacity)) { + placements[placement_count++] = (struct wonder_location){ + .x = chosen->x, + .y = chosen->y + }; + } + + newly_placed += 1; + + char msg[256]; + snprintf (msg, sizeof msg, "[C3X] Placed natural wonder \"%s\" at (%d,%d).\n", + (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder", + chosen->x, chosen->y); + (*p_OutputDebugStringA) (msg); + } + + char summary[256]; + snprintf (summary, sizeof summary, "[C3X] Natural wonder placement complete. Newly placed: %d, already present: %d.\n", + newly_placed, existing_count); + (*p_OutputDebugStringA) (summary); + + for (int ni = 0; ni < wonder_count; ni++) + free (candidate_lists[ni].entries); + free (wonder_order); + free (candidate_lists); + free (already_placed); + free (placements); +} + +void +init_scenario_district_entry (struct scenario_district_entry * entry) +{ + if (entry == NULL) + return; + + memset (entry, 0, sizeof *entry); +} + +void +init_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) +{ + if (entry == NULL) + return; + + memset (entry, 0, sizeof *entry); +} + +void +free_scenario_district_entry (struct scenario_district_entry * entry) +{ + if (entry == NULL) + return; + + if (entry->district_name != NULL) { + free (entry->district_name); + entry->district_name = NULL; + } + if (entry->wonder_city_name != NULL) { + free (entry->wonder_city_name); + entry->wonder_city_name = NULL; + } + if (entry->wonder_name != NULL) { + free (entry->wonder_name); + entry->wonder_name = NULL; + } + entry->has_coordinates = 0; + entry->has_district_name = 0; + entry->has_wonder_city = 0; + entry->has_wonder_name = 0; +} + +void +free_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) +{ + if (entry == NULL) + return; + + if (entry->name != NULL) { + free (entry->name); + entry->name = NULL; + } + entry->has_coordinates = 0; + entry->has_name = 0; +} + +void +add_scenario_district_error (struct error_line ** parse_errors, + int line_number, + char const * message) +{ + if (message == NULL) + return; + + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s", line_number, message); + err->text[(sizeof err->text) - 1] = '\0'; +} + +int +parse_scenario_district_coordinates (struct string_slice const * value, int * out_x, int * out_y) +{ + if ((value == NULL) || (out_x == NULL) || (out_y == NULL)) + return 0; + + char * text = trim_and_extract_slice (value, 0); + if (text == NULL) + return 0; + + char * cursor = text; + int success = 0; + int x, y; + if (parse_int (&cursor, &x) && + skip_punctuation (&cursor, ',') && + parse_int (&cursor, &y)) { + skip_horiz_space (&cursor); + success = (*cursor == '\0'); + if (success) { + *out_x = x; + *out_y = y; + } + } + + free (text); + return success; +} + +int +finalize_scenario_district_entry (struct scenario_district_entry * entry, + int section_start_line, + struct error_line ** parse_errors) +{ + int success = 1; + if ((entry == NULL) || (parse_errors == NULL)) + return 0; + + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return 1; + } + + if (! entry->has_coordinates) + add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); + if ((! entry->has_district_name) || (entry->district_name == NULL) || (entry->district_name[0] == '\0')) + add_scenario_district_error (parse_errors, section_start_line, "district (value is required)"); + + if ((! entry->has_coordinates) || (! entry->has_district_name) || + (entry->district_name == NULL) || (entry->district_name[0] == '\0')) + success = 0; + + int map_x = entry->tile_x; + int map_y = entry->tile_y; + if (success) { + wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); + Tile * tile = tile_at (map_x, map_y); + if ((tile == NULL) || (tile == p_null_tile)) { + add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); + success = 0; + } else { + int district_id = find_district_index_by_name (entry->district_name); + if ((district_id < 0) || (district_id >= is->district_count)) { + char msg[200]; + snprintf (msg, sizeof msg, "district (unrecognized name: \"%s\")", entry->district_name); + add_scenario_district_error (parse_errors, section_start_line, msg); + success = 0; + } else { + if ((district_id == NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_natural_wonders) { + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return 1; + } + if ((district_id != NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_districts) { + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return 1; + } + struct district_instance * inst = ensure_district_instance (tile, district_id, map_x, map_y); + if (inst == NULL) { + add_scenario_district_error (parse_errors, section_start_line, "Failed to create district instance"); + success = 0; + } else { + inst->district_id = district_id; + district_instance_set_coords (inst, map_x, map_y); + inst->state = DS_COMPLETED; + inst->wonder_info.state = WDS_UNUSED; + inst->wonder_info.city = NULL; + inst->wonder_info.city_id = -1; + inst->wonder_info.wonder_index = -1; + inst->natural_wonder_info.natural_wonder_id = -1; + + if (district_id == WONDER_DISTRICT_ID) { + int has_city = entry->has_wonder_city && + (entry->wonder_city_name != NULL) && (entry->wonder_city_name[0] != '\0'); + int has_wonder = entry->has_wonder_name && + (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); + if (! has_city || ! has_wonder) { + add_scenario_district_error (parse_errors, section_start_line, "Wonder district requires both wonder_city and wonder_name"); + success = 0; + } else { + int wonder_index = find_wonder_district_index_by_name (entry->wonder_name); + if (wonder_index < 0) { + char msg[200]; + snprintf (msg, sizeof msg, "wonder_name (unrecognized wonder: \"%s\")", entry->wonder_name); + add_scenario_district_error (parse_errors, section_start_line, msg); + success = 0; + } else { + inst->wonder_info.city = NULL; + inst->wonder_info.city_id = -1; + inst->wonder_info.state = WDS_COMPLETED; + inst->wonder_info.wonder_index = wonder_index; + } + } + } else if (district_id == NATURAL_WONDER_DISTRICT_ID) { + int has_name = entry->has_wonder_name && + (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); + if (! has_name) { + add_scenario_district_error (parse_errors, section_start_line, "Natural Wonder district requires wonder_name"); + success = 0; + } else { + int natural_index = find_natural_wonder_index_by_name (entry->wonder_name); + if (natural_index < 0) { + char msg[200]; + snprintf (msg, sizeof msg, "wonder_name (unrecognized natural wonder: \"%s\")", entry->wonder_name); + add_scenario_district_error (parse_errors, section_start_line, msg); + success = 0; + } else + inst->natural_wonder_info.natural_wonder_id = natural_index; + } + if (entry->has_wonder_city) + add_scenario_district_error (parse_errors, section_start_line, "wonder_city ignored for Natural Wonder district entries"); + } else if (entry->has_wonder_city || entry->has_wonder_name) { + add_scenario_district_error (parse_errors, section_start_line, "wonder_* fields only valid for Wonder or Natural Wonder district entries"); + } + + if (success) { + if (district_id != NATURAL_WONDER_DISTRICT_ID && !tile->vtable->m18_Check_Mines (tile, __, 0)) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, map_x, map_y); + set_tile_unworkable_for_all_cities (tile, map_x, map_y); + } + } + } + } + } + + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return success; +} + +bool +tile_can_be_named (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) + return false; + return true; +} + +void +remove_named_tile_entry (Tile * tile) +{ + struct named_tile_entry * entry = get_named_tile_entry (tile); + if (entry == NULL) + return; + itable_remove (&is->named_tile_map, (int)tile); + free (entry); +} + +void +set_named_tile_entry (Tile * tile, int tile_x, int tile_y, char const * name) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return; + if ((name == NULL) || (name[0] == '\0')) { + remove_named_tile_entry (tile); + return; + } + + struct named_tile_entry * entry = get_named_tile_entry (tile); + if (entry == NULL) { + entry = calloc (1, sizeof *entry); + if (entry == NULL) + return; + itable_insert (&is->named_tile_map, (int)tile, (int)entry); + } + entry->tile_x = tile_x; + entry->tile_y = tile_y; + strncpy (entry->name, name, sizeof entry->name); + entry->name[(sizeof entry->name) - 1] = '\0'; +} + +int +finalize_scenario_named_tile_entry (struct scenario_named_tile_entry * entry, + int section_start_line, + struct error_line ** parse_errors) +{ + int success = 1; + if ((entry == NULL) || (parse_errors == NULL)) + return 0; + + if (! is->current_config.enable_named_tiles) { + free_scenario_named_tile_entry (entry); + init_scenario_named_tile_entry (entry); + return 1; + } + + if (! entry->has_coordinates) + add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); + if ((! entry->has_name) || (entry->name == NULL) || (entry->name[0] == '\0')) + add_scenario_district_error (parse_errors, section_start_line, "name (value is required)"); + + if ((! entry->has_coordinates) || (! entry->has_name) || + (entry->name == NULL) || (entry->name[0] == '\0')) + success = 0; + + int map_x = entry->tile_x; + int map_y = entry->tile_y; + if (success) { + wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); + Tile * tile = tile_at (map_x, map_y); + if ((tile == NULL) || (tile == p_null_tile)) { + add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); + success = 0; + } else if (! tile_can_be_named (tile, map_x, map_y)) { + add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile cannot be named)"); + success = 0; + } else { + set_named_tile_entry (tile, map_x, map_y, entry->name); + } + } + + free_scenario_named_tile_entry (entry); + init_scenario_named_tile_entry (entry); + return success; +} + +void +handle_scenario_district_key (struct scenario_district_entry * entry, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if ((entry == NULL) || (key == NULL) || (value == NULL)) + return; + + if (slice_matches_str (key, "coordinates")) { + int x, y; + if (parse_scenario_district_coordinates (value, &x, &y)) { + entry->tile_x = x; + entry->tile_y = y; + entry->has_coordinates = 1; + } else + add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); + + } else if (slice_matches_str (key, "district")) { + if (entry->district_name != NULL) { + free (entry->district_name); + entry->district_name = NULL; + } + entry->district_name = copy_trimmed_string_or_null (value, 1); + entry->has_district_name = (entry->district_name != NULL); + if (! entry->has_district_name) + add_scenario_district_error (parse_errors, line_number, "district (value is required)"); + + } else if (slice_matches_str (key, "wonder_city")) { + if (entry->wonder_city_name != NULL) { + free (entry->wonder_city_name); + entry->wonder_city_name = NULL; + } + entry->wonder_city_name = copy_trimmed_string_or_null (value, 1); + entry->has_wonder_city = (entry->wonder_city_name != NULL); + + } else if (slice_matches_str (key, "wonder_name")) { + if (entry->wonder_name != NULL) { + free (entry->wonder_name); + entry->wonder_name = NULL; + } + entry->wonder_name = copy_trimmed_string_or_null (value, 1); + entry->has_wonder_name = (entry->wonder_name != NULL); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +void +handle_scenario_named_tile_key (struct scenario_named_tile_entry * entry, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if ((entry == NULL) || (key == NULL) || (value == NULL)) + return; + + if (slice_matches_str (key, "coordinates")) { + int x, y; + if (parse_scenario_district_coordinates (value, &x, &y)) { + entry->tile_x = x; + entry->tile_y = y; + entry->has_coordinates = 1; + } else + add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); + + } else if (slice_matches_str (key, "name")) { + if (entry->name != NULL) { + free (entry->name); + entry->name = NULL; + } + entry->name = copy_trimmed_string_or_null (value, 1); + entry->has_name = (entry->name != NULL); + if (! entry->has_name) + add_scenario_district_error (parse_errors, line_number, "name (value is required)"); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +// Parses a .c3x.txt file corresponding to the given scenario file path, loading district instances as specified. +// +// The expected file format itself is very simple. Example: +// +// ``` +// DISTRICTS +// +// #District +// coordinates = 12,28 +// district = Entertainment Complex +// +// #District +// coordinates = 9,23 +// district = Wonder District +// wonder_city = Rome +// wonder_name = The Pyramids +// +// #District +// coordinates = 10,30 +// district = Natural Wonder +// wonder_name = Mount Everest +// +// #NamedTile +// coordinates = 41,23 +// name = Tiber River +// ``` +// +// Details at https://github.com/instafluff0/Civ3_Editor_Fork_for_C3X_Districts +void +load_scenario_districts_from_file () +{ + char * scenario_filename = "scenario.districts.txt"; + char * scenario_districts_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + + // BIC_get_asset_path returns the file name when it can't find the file + if ((scenario_districts_path == NULL) || (0 == strcmp (scenario_filename, scenario_districts_path))) + return; + + char * text = file_to_string (scenario_districts_path); + if (text == NULL) + return; + + struct scenario_district_entry entry; + struct scenario_named_tile_entry named_entry; + init_scenario_district_entry (&entry); + init_scenario_named_tile_entry (&named_entry); + int in_section = 0; + int section_start_line = 0; + int section_type = 0; + int line_number = 0; + int header_seen = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + int has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + // Keep support for legacy header, technically not needed + if (! header_seen) { + if (slice_matches_str (&trimmed, "DISTRICTS")) { + header_seen = 1; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if (slice_matches_str (&directive, "District")) { + if (in_section) { + if (section_type == 1) + finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); + else if (section_type == 2) + finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); + } + in_section = 1; + section_type = 1; + section_start_line = line_number; + free_scenario_district_entry (&entry); + init_scenario_district_entry (&entry); + } else if (slice_matches_str (&directive, "NamedTile")) { + if (in_section) { + if (section_type == 1) + finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); + else if (section_type == 2) + finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); + } + in_section = 1; + section_type = 2; + section_start_line = line_number; + free_scenario_named_tile_entry (&named_entry); + init_scenario_named_tile_entry (&named_entry); + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + switch (parse_trimmed_key_value (&trimmed, &key_slice, &value_slice)) { + case KVP_NO_EQUALS: + add_scenario_district_error (&parse_errors, line_number, "(expected '=')"); + break; + case KVP_EMPTY_KEY: + add_scenario_district_error (&parse_errors, line_number, "(missing key)"); + break; + case KVP_SUCCESS: + if (section_type == 1) + handle_scenario_district_key (&entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + else if (section_type == 2) + handle_scenario_named_tile_key (&named_entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + break; + } + + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) { + if (section_type == 1) + finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); + else if (section_type == 2) + finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); + } + + free_scenario_district_entry (&entry); + free_scenario_named_tile_entry (&named_entry); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (scenario_districts_path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + + if ((parse_errors != NULL) || (unrecognized_keys != NULL)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char header[256]; + snprintf (header, sizeof header, "District scenario file issues in %s:", scenario_districts_path); + header[(sizeof header) - 1] = '\0'; + PopupForm_add_text (popup, __, header, 0); + if (parse_errors != NULL) + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, 0); + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", 0); + PopupForm_add_text (popup, __, "Unrecognized keys:", 0); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, 0); + } + patch_show_popup (popup, __, 0, 0); + } + + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); +} + +void +deinit_district_images (void) +{ + if (is->dc_img_state == IS_OK) { + for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) { + for (int variant = 0; variant < ARRAY_LEN (is->district_img_sets[dc].imgs); variant++) + for (int era = 0; era < 4; era++) + for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc].imgs[variant][era]); col++) { + Sprite * sprite = &is->district_img_sets[dc].imgs[variant][era][col]; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + } + + for (int wi = 0; wi < MAX_WONDER_DISTRICT_TYPES; wi++) { + struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; + if (set->img.vtable != NULL) + set->img.vtable->destruct (&set->img, __, 0); + if (set->construct_img.vtable != NULL) + set->construct_img.vtable->destruct (&set->construct_img, __, 0); + if (set->alt_dir_img.vtable != NULL) + set->alt_dir_img.vtable->destruct (&set->alt_dir_img, __, 0); + if (set->alt_dir_construct_img.vtable != NULL) + set->alt_dir_construct_img.vtable->destruct (&set->alt_dir_construct_img, __, 0); + } + + for (int ni = 0; ni < MAX_NATURAL_WONDER_DISTRICT_TYPES; ni++) { + Sprite * sprite = &is->natural_wonder_img_sets[ni].img; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + + if (is->abandoned_district_img.vtable != NULL) + is->abandoned_district_img.vtable->destruct (&is->abandoned_district_img, __, 0); + if (is->abandoned_maritime_district_img.vtable != NULL) + is->abandoned_maritime_district_img.vtable->destruct (&is->abandoned_maritime_district_img, __, 0); + } + + is->dc_img_state = IS_UNINITED; +} + +void +clear_highlighted_worker_tiles_for_districts () +{ + FOR_TABLE_ENTRIES (tei, &is->highlighted_city_radius_tile_pointers) { + struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)tei.value; + if (info != NULL) + free (info); + } + table_deinit (&is->highlighted_city_radius_tile_pointers); +} + + +void +reset_district_state (bool reset_tile_map) +{ + clear_all_tracked_workers (); + deinit_district_images (); + clear_highlighted_worker_tiles_for_districts (); + + FOR_TABLE_ENTRIES (tei, &is->district_building_prereqs) { + struct district_building_prereq_list * list = (struct district_building_prereq_list *)tei.value; + if (list != NULL) + free (list); + } + table_deinit (&is->district_building_prereqs); + table_deinit (&is->command_id_to_district_id); + stable_deinit (&is->building_name_to_id); + if (reset_tile_map) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst != NULL) + free (inst); + } + table_deinit (&is->district_tile_map); + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if (entry != NULL) + free (entry); + } + table_deinit (&is->named_tile_map); + } + + clear_distribution_hub_tables (); + + is->distribution_hub_totals_dirty = true; + + clear_dynamic_district_definitions (); + is->district_count = is->special_district_count; + + for (int i = 0; i < COUNT_DISTRICT_TYPES; i++) { + is->district_infos[i].advance_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) + is->district_infos[i].advance_prereq_ids[j] = -1; + is->district_infos[i].obsoleted_by_id = -1; + is->district_infos[i].resource_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].resource_prereq_ids); j++) + is->district_infos[i].resource_prereq_ids[j] = -1; + is->district_infos[i].resource_prereq_on_tile_id = -1; + is->district_infos[i].wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) + is->district_infos[i].wonder_prereq_ids[j] = -1; + is->district_infos[i].natural_wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) + is->district_infos[i].natural_wonder_prereq_ids[j] = -1; + is->district_infos[i].dependent_building_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) + is->district_infos[i].dependent_building_ids[j] = -1; + } + + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req != NULL) + free (req); + } + table_deinit (&is->city_pending_district_requests[civ_id]); + } + table_deinit (&is->city_pending_building_orders); + + is->great_wall_auto_build = GWABS_NOT_STARTED; +} + +void +clear_city_district_request (City * city, int district_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (district_id < 0) || (district_id >= is->district_count)) + return; + + struct pending_district_request * req = find_pending_district_request (city, district_id); + if (req == NULL) + return; + + remove_pending_district_request (req); + + int pending_improv_id; + if (look_up_pending_building_order (city, &pending_improv_id)) { + int required_district_id; + if (city_requires_district_for_improvement (city, pending_improv_id, &required_district_id)) { + if (required_district_id == district_id) + forget_pending_building_order (city); + } + } +} + +bool +district_resource_prereqs_met_r (Tile * tile, int tile_x, int tile_y, int district_id, int max_req_resource_id) +{ + if ((tile == NULL) || (tile == p_null_tile) || + (district_id < 0) || (district_id >= is->district_count)) + return false; + + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + struct district_infos * info = &is->district_infos[district_id]; + int on_tile_req = info->resource_prereq_on_tile_id; + if (on_tile_req >= 0) { + int res_here = (owner >= 0) ? Tile_get_resource_visible_to (tile, __, owner) : -1; + if (res_here != on_tile_req) + return false; + } + + // If no resource prereqs, then the check passes + if (info->resource_prereq_count <= 0) + return true; + + if (owner < 0) + return false; + + // Check resource prereqs - ALL must be present + for (int i = 0; i < info->resource_prereq_count; i++) { + int resource_req = info->resource_prereq_ids[i]; + if (resource_req < 0) + continue; + if (resource_req > max_req_resource_id) + return false; + + bool has_resource = false; + bool is_bonus_resource = p_bic_data->ResourceTypes[resource_req].Class == RC_Bonus; + + FOR_CITIES_OF (coi, owner) { + City * req_city = coi.city; + if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, req_city, tile_x, tile_y)) + continue; + if (! city_has_resource_r (req_city, resource_req, max_req_resource_id)) + if (! is_bonus_resource) + continue; + else { + int civ_id = req_city->Body.CivID; + FOR_TILES_AROUND (tai, is->workable_tile_count, req_city->Body.X, req_city->Body.Y) { + Tile * radius_tile = tai.tile; + if ((radius_tile == NULL) || (radius_tile == p_null_tile)) + continue; + if (radius_tile->vtable->m38_Get_Territory_OwnerID (radius_tile) != civ_id) + continue; + if (Tile_get_resource_visible_to (radius_tile, __, civ_id) == resource_req) { + has_resource = true; + break; + } + } + if (has_resource) + break; + continue; + } + + has_resource = true; + break; + } + + // If this required resource is not available, the check fails + if (!has_resource) + return false; + } + + return true; +} + +bool +district_resource_prereqs_met (Tile * tile, int tile_x, int tile_y, int district_id) +{ + return district_resource_prereqs_met_r (tile, tile_x, tile_y, district_id, INT_MAX); +} + +int +count_contiguous_bridge_districts (int tile_x, int tile_y, int dx, int dy) +{ + Map * map = &p_bic_data->Map; + int nx = tile_x + dx; + int ny = tile_y + dy; + int count = 0; + int max_steps = map->Width + map->Height; + + for (int step = 0; step < max_steps; step++) { + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) + break; + count++; + nx += dx; + ny += dy; + } + + return count; +} + +int +count_contiguous_canal_districts (int tile_x, int tile_y, int max_count) +{ + if (max_count <= 0) + return 0; + + Map * map = &p_bic_data->Map; + int limit = max_count + 1; + int capacity = limit; + if (capacity < 1) + capacity = 1; + + int * xs = malloc (sizeof (*xs) * capacity); + int * ys = malloc (sizeof (*ys) * capacity); + if ((xs == NULL) || (ys == NULL)) { + if (xs != NULL) + free (xs); + if (ys != NULL) + free (ys); + return limit; + } + + int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; + int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; + int head = 0; + int tail = 0; + int count = 0; + + xs[tail] = tile_x; + ys[tail] = tile_y; + tail++; + + while (head < tail) { + int cx = xs[head]; + int cy = ys[head]; + head++; + count++; + if (count >= limit) + break; + + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) + continue; + + bool seen = false; + for (int j = 0; j < tail; j++) { + if ((xs[j] == nx) && (ys[j] == ny)) { + seen = true; + break; + } + } + if (seen) + continue; + + if (tail < capacity) { + xs[tail] = nx; + ys[tail] = ny; + tail++; + } else { + count = limit; + head = tail; + break; + } + } + } + + free (xs); + free (ys); + + return count; +} + +bool +district_line_is_straight (int tile_x, int tile_y, int district_id) +{ + Map * map = &p_bic_data->Map; + int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; + int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; + + for (int i = 0; i < 8; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, district_id)) + continue; + + int cand_dx = -adj_dx[i]; + int cand_dy = -adj_dy[i]; + + for (int j = 0; j < 8; j++) { + int ox = nx + adj_dx[j]; + int oy = ny + adj_dy[j]; + wrap_tile_coords (map, &ox, &oy); + if ((ox == tile_x) && (oy == tile_y)) + continue; + if (! tile_has_district_at (ox, oy, district_id)) + continue; + + if (! ((adj_dx[j] == cand_dx) && (adj_dy[j] == cand_dy)) && + ! ((adj_dx[j] == -cand_dx) && (adj_dy[j] == -cand_dy))) + return false; + } + } + + return true; +} + +bool +bridge_district_tile_is_valid (int tile_x, int tile_y) +{ + if (! tile_is_coastal_water (tile_x, tile_y)) + return false; + + bool has_adjacent_land_or_bridge = false; + Map * map = &p_bic_data->Map; + int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; + int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; + + for (int i = 0; i < 8; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (tile_is_land (-1, nx, ny, false) || tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) { + has_adjacent_land_or_bridge = true; + break; + } + } + if (! has_adjacent_land_or_bridge) + return false; + + if (is->current_config.max_contiguous_bridge_districts > 0) { + int max_bridges = is->current_config.max_contiguous_bridge_districts; + + int ns_count = count_contiguous_bridge_districts (tile_x, tile_y, 0, -2) + + count_contiguous_bridge_districts (tile_x, tile_y, 0, 2); + if (ns_count >= max_bridges) + return false; + + int we_count = count_contiguous_bridge_districts (tile_x, tile_y, -2, 0) + + count_contiguous_bridge_districts (tile_x, tile_y, 2, 0); + if (we_count >= max_bridges) + return false; + + int swne_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, 1) + + count_contiguous_bridge_districts (tile_x, tile_y, 1, -1); + if (swne_count >= max_bridges) + return false; + + int nwse_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, -1) + + count_contiguous_bridge_districts (tile_x, tile_y, 1, 1); + if (nwse_count >= max_bridges) + return false; + } + + return district_line_is_straight (tile_x, tile_y, BRIDGE_DISTRICT_ID); +} + +bool +canal_district_tile_is_valid (int tile_x, int tile_y) +{ + if (tile_is_water (tile_x, tile_y)) + return false; + + if (is->current_config.max_contiguous_canal_districts > 0) { + int count = count_contiguous_canal_districts (tile_x, tile_y, is->current_config.max_contiguous_canal_districts); + if (count > is->current_config.max_contiguous_canal_districts) + return false; + } + + Map * map = &p_bic_data->Map; + int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; + int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; + + for (int i = 0; i < 8; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * tile = tile_at (nx, ny); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m35_Check_Is_Water (tile)) + return true; + + if (tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && + district_is_complete (tile, CANAL_DISTRICT_ID)) + return true; + } + } + + return false; +} + +bool +can_build_district_on_tile (Tile * tile, int district_id, int civ_id) +{ + if ((! is->current_config.enable_districts) || + (tile == NULL) || (tile == p_null_tile) || + (tile->CityID >= 0) || + tile->vtable->m21_Check_Crates (tile, __, 0) || + tile->vtable->m20_Check_Pollution (tile, __, 0) || + (district_id < 0) || (district_id >= is->district_count)) + return false; + + struct district_config const * cfg = &is->district_configs[district_id]; + if (cfg->command == -1) + return false; + + if ((cfg->command == UCV_Build_Neighborhood) && !is->current_config.enable_neighborhood_districts) return false; + if ((cfg->command == UCV_Build_WonderDistrict) && !is->current_config.enable_wonder_districts) return false; + if ((cfg->command == UCV_Build_DistributionHub) && !is->current_config.enable_distribution_hub_districts) return false; + if ((cfg->command == UCV_Build_Aerodrome) && !is->current_config.enable_aerodrome_districts) return false; + if ((cfg->command == UCV_Build_Port) && !is->current_config.enable_port_districts) return false; + if ((cfg->command == UCV_Build_Bridge) && !is->current_config.enable_bridge_districts) return false; + if ((cfg->command == UCV_Build_CentralRailHub) && !is->current_config.enable_central_rail_hub_districts) return false; + if ((cfg->command == UCV_Build_EnergyGrid) && !is->current_config.enable_energy_grid_districts) return false; + if ((cfg->command == UCV_Build_GreatWall) && !is->current_config.enable_great_wall_districts) return false; + + if (! district_is_buildable_on_tile (cfg, tile)) + return false; + + int tile_x = 0, tile_y = 0; + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + + if (! leader_can_build_district (&leaders[civ_id], district_id)) + return false; + + if (! district_resource_prereqs_met (tile, tile_x, tile_y, district_id)) + return false; + + if ((district_id == CANAL_DISTRICT_ID) && (! canal_district_tile_is_valid (tile_x, tile_y))) + return false; + + if ((district_id == BRIDGE_DISTRICT_ID) && (! bridge_district_tile_is_valid (tile_x, tile_y))) + return false; + + struct district_instance * existing_inst = get_district_instance (tile); + struct district_infos const * info = &is->district_infos[district_id]; + int existing_district_id = (existing_inst != NULL) ? existing_inst->district_id : -1; + bool district_completed = district_is_complete (tile, existing_district_id); + + if ((existing_district_id == district_id) && district_completed) + return false; + if ((existing_district_id >= 0) && (existing_district_id != district_id) && (! district_completed)) + return false; + + if (! cfg->allow_multiple) { + if (district_exists_within_distance (tile_x, tile_y, district_id, civ_id, is->current_config.city_work_radius)) + return false; + } + + return true; +} + +bool +district_is_obsolete_for_civ (int district_id, int civ_id) +{ + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + int obsolete_id = is->district_infos[district_id].obsoleted_by_id; + if (obsolete_id < 0) + return false; + + return Leader_has_tech (&leaders[civ_id], __, obsolete_id); +} + +bool +tile_has_obsolete_district_for_civ (Tile * tile, int civ_id) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + + int district_id = inst->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + if (! district_is_complete (tile, district_id)) + return false; + + return district_is_obsolete_for_civ (district_id, civ_id); +} + +bool +tile_suitable_for_district (Tile * tile, int district_id, City * city, bool * out_has_resource) +{ + bool has_resource = false; + if ((tile != NULL) && (tile != p_null_tile)) + has_resource = tile_has_resource (tile); + if (out_has_resource != NULL) + *out_has_resource = has_resource; + + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (tile->CityID >= 0) return false; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) return false; + if (! can_build_district_on_tile (tile, district_id, city->Body.CivID)) return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + if (tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + return true; + + // Unused wonder districts can be repurposed, completed cannot + if (district_id == WONDER_DISTRICT_ID && inst->state == DS_COMPLETED) { + struct wonder_district_info * winfo = &inst->wonder_info; + if (winfo->state == WDS_COMPLETED) + return false; + } + + return false; + } + + return true; +} + +bool +can_generate_resource (int for_civ_id, struct mill * mill) +{ + int req_tech_id = (mill->flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[mill->resource_id].RequireID; + return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); +} + +bool +district_can_generate_resource (int for_civ_id, struct district_config * dc) +{ + if (dc->generated_resource_id < 0) + return false; + int req_tech_id = (dc->generated_resource_flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[dc->generated_resource_id].RequireID; + return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); +} + +bool +district_generates_resource_for_civ (Tile * tile, struct district_instance * inst, struct district_config * dc, int civ_id) +{ + if ((tile == NULL) || (tile == p_null_tile) || (inst == NULL) || (dc == NULL)) + return false; + if (inst->state != DS_COMPLETED) + return false; + if (dc->generated_resource_id < 0) + return false; + if (! district_can_generate_resource (civ_id, dc)) + return false; + + int tile_x = 0, tile_y = 0; + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + return district_resource_prereqs_met_r (tile, tile_x, tile_y, inst->district_id, dc->generated_resource_id - 1); +} + +void +calculate_city_center_district_bonus (City * city, int * out_food, int * out_shields, int * out_gold) +{ + if (out_food != NULL) + *out_food = 0; + if (out_shields != NULL) + *out_shields = 0; + if (out_gold != NULL) + *out_gold = 0; + + if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) + return; + + int bonus_food = 0; + int bonus_shields = 0; + int bonus_gold = 0; + + int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + int neighborhoods_counted = 0; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) + continue; + Tile * tile = wai.tile; + + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + if (is->current_config.enable_neighborhood_districts && + (district_id == NEIGHBORHOOD_DISTRICT_ID)) { + if (neighborhoods_counted >= utilized_neighborhoods) + continue; + neighborhoods_counted++; + } + + struct district_config * cfg = &is->district_configs[district_id]; + int food_bonus = 0, shield_bonus = 0, gold_bonus = 0; + get_effective_district_yields (inst, cfg, &food_bonus, &shield_bonus, &gold_bonus, NULL, NULL, NULL); + bonus_food += food_bonus; + bonus_shields += shield_bonus; + bonus_gold += gold_bonus; + + if ((cfg->generated_resource_id >= 0) && (cfg->generated_resource_flags & MF_YIELDS)) { + int res_id = cfg->generated_resource_id; + if (district_generates_resource_for_civ (tile, inst, cfg, city->Body.CivID)) { + Resource_Type * res = &p_bic_data->ResourceTypes[res_id]; + bonus_food += res->Food; + bonus_shields += res->Shield; + bonus_gold += res->Commerce; + } + } + } + + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { + int hub_food = 0; + int hub_shields = 0; + get_distribution_hub_yields_for_city (city, &hub_food, &hub_shields); + bonus_food += hub_food; + bonus_shields += hub_shields; + } + + if (out_food != NULL) + *out_food = bonus_food; + if (out_shields != NULL) + *out_shields = bonus_shields; + if (out_gold != NULL) + *out_gold = bonus_gold; +} + +int __fastcall +patch_Map_calc_food_yield_at (Map * this, int edx, int tile_x, int tile_y, int tile_base_type, int civ_id, int imagine_fully_improved, City * city) +{ + if (! is->current_config.enable_districts) + return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id)) { + return 0; + } + } + + return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); +} + +int __fastcall +patch_Map_calc_shield_yield_at (Map * this, int edx, int tile_x, int tile_y, int civ_id, City * city, int param_5, int param_6) +{ + if (! is->current_config.enable_districts) + return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id)) { + return 0; + } + } + + return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); +} + +int +compute_city_tile_yield_sum (City * city, int tile_x, int tile_y) +{ + if (city == NULL) + return 0; + int food = City_calc_tile_yield_at (city, __, YK_FOOD, tile_x, tile_y); + int shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, tile_x, tile_y); + int commerce = City_calc_tile_yield_at (city, __, YK_COMMERCE, tile_x, tile_y); + return food + shields + commerce; +} + +int * +get_water_continent_ids_connected_via_canal (Tile * tile, int * out_count) +{ + if (out_count != NULL) + *out_count = 0; + if (! is->current_config.enable_canal_districts) + return NULL; + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + if (! tile->vtable->m35_Check_Is_Water (tile)) + return NULL; + + int origin_continent_id = tile->vtable->m46_Get_ContinentID (tile); + int continent_count = p_bic_data->Map.Continent_Count; + if ((origin_continent_id < 0) || (origin_continent_id >= continent_count)) + return NULL; + + Map * map = &p_bic_data->Map; + int tile_count = map->TileCount; + if (tile_count <= 0) + return NULL; + + // Use a BFS over completed canal tiles, starting from those touching the origin water body. + int * queue_xs = malloc (sizeof (*queue_xs) * tile_count); + int * queue_ys = malloc (sizeof (*queue_ys) * tile_count); + int * ids = malloc (sizeof (*ids) * continent_count); + bool * seen = calloc (continent_count, sizeof (*seen)); + if ((queue_xs == NULL) || (queue_ys == NULL) || (ids == NULL) || (seen == NULL)) { + if (queue_xs != NULL) + free (queue_xs); + if (queue_ys != NULL) + free (queue_ys); + if (ids != NULL) + free (ids); + if (seen != NULL) + free (seen); + return NULL; + } + + seen[origin_continent_id] = true; + + int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; + int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; + int head = 0; + int tail = 0; + + // Seed queue with completed canal districts adjacent to the origin water body. + for (int index = 0; index < tile_count; index++) { + Tile * cand = Map_get_tile (map, __, index); + if ((cand == NULL) || (cand == p_null_tile)) + continue; + + int cx = 0, cy = 0; + tile_index_to_coords (map, index, &cx, &cy); + if (! tile_has_district_at (cx, cy, CANAL_DISTRICT_ID)) + continue; + + struct district_instance * inst = get_district_instance (cand); + if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || + (! district_is_complete (cand, CANAL_DISTRICT_ID))) + continue; + + bool adjacent_to_origin = false; + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (! adj->vtable->m35_Check_Is_Water (adj)) + continue; + int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); + if (adj_continent_id == origin_continent_id) { + adjacent_to_origin = true; + break; + } + } + if (! adjacent_to_origin) + continue; + + bool seen_canal = false; + for (int j = 0; j < tail; j++) { + if ((queue_xs[j] == cx) && (queue_ys[j] == cy)) { + seen_canal = true; + break; + } + } + if (! seen_canal && (tail < tile_count)) { + queue_xs[tail] = cx; + queue_ys[tail] = cy; + tail++; + } + } + + int id_count = 0; + + while (head < tail) { + int cx = queue_xs[head]; + int cy = queue_ys[head]; + head++; + + // Record all water bodies adjacent to this canal tile. + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (! adj->vtable->m35_Check_Is_Water (adj)) + continue; + + int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); + if ((adj_continent_id < 0) || (adj_continent_id >= continent_count)) + continue; + if (! seen[adj_continent_id]) { + seen[adj_continent_id] = true; + ids[id_count] = adj_continent_id; + id_count++; + } + } + + // Traverse to neighboring completed canal districts. + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) + continue; + + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (adj); + if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || (! district_is_complete (adj, CANAL_DISTRICT_ID))) + continue; + + bool seen_canal = false; + for (int j = 0; j < tail; j++) { + if ((queue_xs[j] == nx) && (queue_ys[j] == ny)) { + seen_canal = true; + break; + } + } + if (! seen_canal && (tail < tile_count)) { + queue_xs[tail] = nx; + queue_ys[tail] = ny; + tail++; + } + } + } + + free (queue_xs); + free (queue_ys); + free (seen); + + if (out_count != NULL) + *out_count = id_count; + if (id_count <= 0) { + free (ids); + return NULL; + } + + return ids; +} + +Tile * +find_tile_for_neighborhood_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + + // Search in order: ring 1, then rings 2..N + // Ring order array: 1, 2, 3, ..., city_work_radius + int ring_order[8]; + int ring_count = 0; + for (int r = 1; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + + Tile * best_tile = NULL; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + bool has_resource = false; + if (is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + continue; + } + + if (! tile_suitable_for_district (tile, NEIGHBORHOOD_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + if (get_district_instance (tile) != NULL && + ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +find_tile_for_port_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + int threshold_for_body_of_water = 21; // Mimic vanilla behavior so AI doesn't build ports in small lakes + + // Search in order: ring 1, then rings 2..N + int ring_order[8]; + int ring_count = 0; + for (int r = 1; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + + Tile * best_tile = NULL; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + bool has_resource = false; + if (is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + continue; + } + + if (! tile_suitable_for_district (tile, PORT_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + if (get_district_instance (tile) != NULL && + ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + continue; + if (! tile->vtable->m35_Check_Is_Water (tile)) + continue; + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + bool large_enough_body = (continent->Body.TileCount >= threshold_for_body_of_water); + if (! large_enough_body) { + int connected_count = 0; + int * connected_ids = get_water_continent_ids_connected_via_canal (tile, &connected_count); + for (int i = 0; i < connected_count; i++) { + int connected_id = connected_ids[i]; + if ((connected_id < 0) || (connected_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * connected_continent = &p_bic_data->Map.Continents[connected_id]; + if (connected_continent->Body.TileCount >= threshold_for_body_of_water) { + large_enough_body = true; + break; + } + } + if (connected_ids != NULL) + free (connected_ids); + } + if (! large_enough_body) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +find_tile_for_wonder_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + int target_improv_id = -1; + if (look_up_pending_building_order (city, &target_improv_id)) { + if ((target_improv_id < 0) || + (target_improv_id >= p_bic_data->ImprovementsCount) || + ((p_bic_data->Improvements[target_improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0)) + target_improv_id = -1; + } + if (target_improv_id < 0) { + int order_id = city->Body.Order_ID; + if ((city->Body.Order_Type == COT_Improvement) && + (order_id >= 0) && + (order_id < p_bic_data->ImprovementsCount)) { + Improvement * order = &p_bic_data->Improvements[order_id]; + if (order->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + target_improv_id = order_id; + } + } + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + + // Search in order: ring 2, then rings 3..N, then ring 1 as last resort + int ring_order[8]; + int ring_count = 0; + ring_order[ring_count++] = 2; + for (int r = 3; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + ring_order[ring_count++] = 1; + + Tile * best_tile = NULL; + bool has_resource = false; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + if (! tile_suitable_for_district (tile, WONDER_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + if (! wonder_is_buildable_on_tile (tile, target_improv_id)) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +find_tile_for_distribution_hub_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + const int resource_penalty = 100; + const int yield_weight = 40; + const int city_distance_weight = 8; + const int capital_distance_weight = 45; + const int desired_min_capital_distance = 8; + const int proximity_penalty_scale = 300; + const int different_continent_bonus = 500; + + Tile * best_tile = NULL; + int best_score = INT_MIN; + int best_adjusted_yield = INT_MIN; + int best_distance = -1; + int best_distance_to_capital = -1; + bool best_has_resource = true; + + int civ_id = city->Body.CivID; + bool has_capital = false; + int capital_x = 0; + int capital_y = 0; + int capital_continent_id = -1; + + City * capital = get_city_ptr (leaders[civ_id].CapitalID); + if (capital != NULL) { + has_capital = true; + capital_x = capital->Body.X; + capital_y = capital->Body.Y; + Tile * capital_tile = tile_at (capital_x, capital_y); + if ((capital_tile != NULL) && (capital_tile != p_null_tile)) + capital_continent_id = capital_tile->vtable->m46_Get_ContinentID (capital_tile); + } + + FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { + int tx = wai.tile_x, ty = wai.tile_y; + Tile * tile = wai.tile; + bool has_resource; + if (! tile_suitable_for_district (tile, DISTRIBUTION_HUB_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + + int chebyshev = compute_wrapped_chebyshev_distance (tx, ty, city->Body.X, city->Body.Y); + if (chebyshev <= 1) + continue; + + bool too_close_to_existing_hub_or_city = false; + for (int m = 0; m < workable_tile_counts[2]; m++) { + int ndx, ndy; + patch_ni_to_diff_for_work_area (m, &ndx, &ndy); + int nx = tx + ndx, ny = ty + ndy; + wrap_tile_coords (&p_bic_data->Map, &nx, &ny); + Tile * nearby_tile = tile_at (nx, ny); + if ((nearby_tile != NULL) && (nearby_tile != p_null_tile)) { + struct district_instance * nearby_inst = get_district_instance (nearby_tile); + if ((nearby_inst != NULL) && + (nearby_inst->district_id == DISTRIBUTION_HUB_DISTRICT_ID) && + district_is_complete (nearby_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { + too_close_to_existing_hub_or_city = true; + break; + } + else if (nearby_tile->CityID >= 0) { + too_close_to_existing_hub_or_city = true; + break; + } + } + } + if (too_close_to_existing_hub_or_city) + continue; + + int raw_yield = compute_city_tile_yield_sum (city, tx, ty); + int adjusted_yield = raw_yield - (has_resource ? resource_penalty : 0); + int distance = compute_wrapped_manhattan_distance (tx, ty, city->Body.X, city->Body.Y); + int distance_to_capital = has_capital + ? compute_wrapped_manhattan_distance (tx, ty, capital_x, capital_y) + : 0; + + int proximity_penalty = 0; + if (has_capital && (distance_to_capital < desired_min_capital_distance)) + proximity_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; + + int continent_bonus = 0; + if ((capital_continent_id >= 0) && (tile != NULL) && (tile != p_null_tile)) { + int tile_continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((tile_continent_id >= 0) && (tile_continent_id != capital_continent_id)) + continent_bonus = different_continent_bonus; + } + + int score = + adjusted_yield * yield_weight + + distance * city_distance_weight + + distance_to_capital * capital_distance_weight - + proximity_penalty + + continent_bonus; + + if ((score > best_score) || + ((score == best_score) && (distance_to_capital > best_distance_to_capital)) || + ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield > best_adjusted_yield)) || + ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance > best_distance)) || + ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance == best_distance) && (! has_resource && best_has_resource))) { + best_tile = tile; + best_score = score; + best_adjusted_yield = adjusted_yield; + best_distance = distance; + best_distance_to_capital = distance_to_capital; + best_has_resource = has_resource; + *out_x = tx; + *out_y = ty; + } + } + + return best_tile; +} + +bool +city_can_build_district (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos const * info = &is->district_infos[district_id]; + + if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) + return false; + + if ((info->resource_prereq_count > 0) || (info->resource_prereq_on_tile_id >= 0)) { + bool resource_prereqs_met = false; + + FOR_TILES_AROUND (tai, is->workable_tile_count, city->Body.X, city->Body.Y) { + Tile * tile = tai.tile; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) + continue; + if (! district_resource_prereqs_met_r (tile, tai.tile_x, tai.tile_y, district_id, INT_MAX)) + continue; + + resource_prereqs_met = true; + break; + } + + if (! resource_prereqs_met) + return false; + } + + // Check if district does not allow multiple and city already has one + if (! cfg->allow_multiple && city_has_required_district (city, district_id)) + return false; + + return true; +} + +bool +leader_has_wonder_prereq (Leader * leader, struct district_infos const * info) +{ + if (info == NULL) + return false; + if (info->wonder_prereq_count <= 0) + return true; + if ((leader == NULL) || (leader->Improvement_Counts == NULL)) + return false; + + for (int i = 0; i < info->wonder_prereq_count; i++) { + int improv_id = info->wonder_prereq_ids[i]; + if (improv_id >= 0 && leader->Improvement_Counts[improv_id] > 0) + return true; + } + + return false; +} + +bool +leader_has_natural_wonder_prereq_in_territory (int civ_id, struct district_infos const * info) +{ + if (info == NULL) + return false; + if (info->natural_wonder_prereq_count <= 0) + return true; + if (! is->current_config.enable_natural_wonders) + return false; + + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + + int wonder_id = inst->natural_wonder_info.natural_wonder_id; + if (wonder_id < 0) + continue; + + bool matches = false; + for (int i = 0; i < info->natural_wonder_prereq_count; i++) { + if (info->natural_wonder_prereq_ids[i] == wonder_id) { + matches = true; + break; + } + } + if (! matches) + continue; + + Tile * tile = (Tile *)tei.key; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; + } + + return false; +} + +int +count_distribution_hubs_for_civ (int civ_id) +{ + int current = 0; + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if ((rec != NULL) && (rec->civ_id == civ_id)) + current++; + } + return current; +} + +bool +leader_can_natively_build_district (Leader * leader, int district_id) +{ + if ((leader == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos const * info = &is->district_infos[district_id]; + + for (int i = 0; i < info->advance_prereq_count; i++) { + int prereq_id = info->advance_prereq_ids[i]; + if ((prereq_id >= 0) && ! Leader_has_tech (leader, __, prereq_id)) + return false; + } + int obsolete_id = info->obsoleted_by_id; + if ((obsolete_id >= 0) && Leader_has_tech (leader, __, obsolete_id)) + return false; + + if (! leader_has_wonder_prereq (leader, info)) + return false; + + if (! leader_has_natural_wonder_prereq_in_territory (leader->ID, info)) + return false; + + if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) { + int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; + if (max_per_100 > 0) { + int city_count = leader->Cities_Count; + int max_allowed = (city_count * max_per_100 + 99) / 100; + if (max_allowed <= 0) + return false; + + int current = count_distribution_hubs_for_civ (leader->ID); + if (current >= max_allowed) + return false; + } + } + + if (cfg->has_buildable_by_civs) { + bool civ_match = false; + if (cfg->buildable_by_civ_count > 0) { + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + for (int i = 0; i < cfg->buildable_by_civ_count; i++) { + char const * civ_name = cfg->buildable_by_civs[i]; + if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; + if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; + if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; + if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; + if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; + } + } + if (! civ_match) + return false; + } + + if (cfg->has_buildable_by_civ_traits) { + if (cfg->buildable_by_civ_traits_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL || race->vtable == NULL) + return false; + bool trait_match = false; + for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { + int trait_id = cfg->buildable_by_civ_traits_ids[i]; + if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { + trait_match = true; + break; + } + } + if (! trait_match) + return false; + } + + if (cfg->has_buildable_by_civ_govs) { + if (cfg->buildable_by_civ_govs_id_count <= 0) + return false; + int gov_id = leader->GovernmentType; + bool gov_match = false; + for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { + if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { + gov_match = true; + break; + } + } + if (! gov_match) + return false; + } + + if (cfg->has_buildable_by_civ_cultures) { + if (cfg->buildable_by_civ_cultures_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + int culture_id = race->CultureGroupID; + bool culture_match = false; + for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { + if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { + culture_match = true; + break; + } + } + if (! culture_match) + return false; + } + + return true; +} + +bool +leader_has_war_ally_district_access (Leader * leader, int district_id) +{ + if (leader == NULL) + return false; + + int self_id = leader->ID; + for (int civ_id = 0; civ_id < 32; civ_id++) { + if (civ_id == self_id) + continue; + Leader * other = &leaders[civ_id]; + if (other->Military_Allies[self_id] != 0 && leader_can_natively_build_district (other, district_id)) + return true; + } + + return false; +} + +bool +leader_has_pact_ally_district_access (Leader * leader, int district_id) +{ + if (leader == NULL) + return false; + + int self_id = leader->ID; + for (int civ_id = 0; civ_id < 32; civ_id++) { + if (civ_id == self_id) + continue; + Leader * other = &leaders[civ_id]; + if (((leader->Relation_Treaties[civ_id] & 1) != 0 && // 1 = peace treaty + (leader->Relation_Treaties[civ_id] & 4) != 0) && // 4 = mutual protection pact + leader_can_natively_build_district (other, district_id)) { + return true; + } + } + + return false; +} + +bool +leader_can_build_district (Leader * leader, int district_id) +{ + bool can_natively_build = leader_can_natively_build_district (leader, district_id); + + if (can_natively_build) + return true; + + struct district_config const * cfg = &is->district_configs[district_id]; + if (cfg->buildable_by_war_allies && leader_has_war_ally_district_access (leader, district_id)) + return true; + if (cfg->buildable_by_pact_allies && leader_has_pact_ally_district_access (leader, district_id)) + return true; + + return can_natively_build; +} + +Tile * +find_tile_for_district (City * city, int district_id, int * out_x, int * out_y) +{ + if ((city == NULL) || (out_x == NULL) || (out_y == NULL)) + return NULL; + if ((district_id < 0) || (district_id >= is->district_count)) + return NULL; + + // Check if city can build this district at all + if (! city_can_build_district (city, district_id)) + return NULL; + + if (district_id == NEIGHBORHOOD_DISTRICT_ID) + return find_tile_for_neighborhood_district (city, out_x, out_y); + if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) + return find_tile_for_distribution_hub_district (city, out_x, out_y); + if (district_id == PORT_DISTRICT_ID) + return find_tile_for_port_district (city, out_x, out_y); + if (district_id == WONDER_DISTRICT_ID) + return find_tile_for_wonder_district (city, out_x, out_y); + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + + // Search in order: ring 2, then rings 3..N, then ring 1 as last resort + // Ring order array: 2, 3, 4, ..., city_work_radius, 1 + int ring_order[8]; + int ring_count = 0; + ring_order[ring_count++] = 2; + for (int r = 3; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + ring_order[ring_count++] = 1; + + Tile * best_tile = NULL; + struct district_config * cfg = &is->district_configs[district_id]; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + bool has_resource = false; + if (is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + continue; + } + + if (! tile_suitable_for_district (tile, district_id, city, &has_resource)) + continue; + if (cfg->resource_prereq_on_tile < 0 && has_resource) + continue; + if (get_district_instance (tile) != NULL && ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +get_completed_district_tile_for_city (City * city, int district_id, int * out_x, int * out_y) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return NULL; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + struct district_instance * inst = wai.district_inst; + + if (inst->district_id != district_id) + continue; + + // For wonder districts, filter based on wonder_district_state + if (district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = &inst->wonder_info; + // Must be either unused or under construction by this city + if (info->state == WDS_COMPLETED) + continue; + if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) + continue; + if (info->state == WDS_UNDER_CONSTRUCTION) { + info->city = city; + info->city_id = city->Body.ID; + } + } + + if (out_x != NULL) + *out_x = x; + if (out_y != NULL) + *out_y = y; + return candidate; + } + + return NULL; +} + +bool +tile_has_friendly_aerodrome_district (Tile * tile, int civ_id, bool require_available) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_aerodrome_districts || + (tile == NULL) || + (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != AERODROME_DISTRICT_ID) + return false; + + if (! district_is_complete (tile, AERODROME_DISTRICT_ID)) + return false; + + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (territory_owner != civ_id) + return false; + + if (require_available) { + int usage_mask; + if (itable_look_up (&is->aerodrome_airlift_usage, (int)tile, &usage_mask) && + (usage_mask & (1 << civ_id))) + return false; + } + + return true; +} + +bool +tile_has_friendly_port_district (Tile * tile, int civ_id) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + (tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != PORT_DISTRICT_ID)) + return false; + + if (! district_is_complete (tile, PORT_DISTRICT_ID)) + return false; + + return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; +} + +bool +city_has_required_district (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + if (get_completed_district_tile_for_city (city, district_id, NULL, NULL) != NULL) { + clear_city_district_request (city, district_id); + return true; + } + return false; +} + +bool +city_has_wonder_district_with_no_completed_wonder (City * city, int wonder_improv_id) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + Tile * candidate = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + + struct wonder_district_info * info = get_wonder_district_info (candidate); + bool buildable = wonder_is_buildable_on_tile (candidate, wonder_improv_id); + if (info == NULL) return true; + if (info->state == WDS_COMPLETED) continue; + if (info->state == WDS_UNUSED && buildable) return true; + if (info->state == WDS_UNDER_CONSTRUCTION && buildable && info->city_id == city->Body.ID) { + info->city = city; + return true; // Reserved by this city + } + } + + return false; +} + +int __fastcall patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city); +int __fastcall patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null); +void __fastcall patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3); + + +void __fastcall +patch_Main_Screen_Form_show_map_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) +{ + WITH_PAUSE_FOR_POPUP { + Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, pause); + } +} + +int __cdecl +patch_process_text_for_map_message (char * in, char * out) +{ + if (is->map_message_text_override != NULL) { + strcpy (out, is->map_message_text_override); + is->map_message_text_override = NULL; + return 0; + } else + return process_text_snippet (in, out); +} + +// Works like show_map_message but takes a bit of text to display instead of a key for script.txt +void +show_map_specific_text (int tile_x, int tile_y, char const * text, bool pause) +{ + is->map_message_text_override = text; + patch_Main_Screen_Form_show_map_message (p_main_screen_form, __, tile_x, tile_y, "LANDCONQUER", pause); // Use any key here. It will be overridden. +} + +bool __fastcall +patch_City_has_improvement (City * this, int edx, int improv_id, bool include_auto_improvements) +{ + bool tr = City_has_improvement (this, __, improv_id, include_auto_improvements); + + // Check if the improvement is provided for free by another human player's wonder if we're in a hotseat game and the config option is on + if ((! tr) && + include_auto_improvements && + is->current_config.share_wonders_in_hotseat && + ((1 << this->Body.CivID) & *p_human_player_bits) && + (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // if we're in a hotseat game + + // Loop over every other human player in the game and check if the city would have the improv if they were its owner + int actual_owner_id = this->Body.CivID; + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != actual_owner_id)) { + this->Body.CivID = n_player; + if (City_has_improvement (this, __, improv_id, include_auto_improvements)) { + tr = true; + break; + } + } + player_bits >>= 1; + n_player++; + } + this->Body.CivID = actual_owner_id; + + } + + return tr; +} + +int +count_neighborhoods_in_city_radius (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return 0; + + int count = 0; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + struct district_instance * inst = wai.district_inst; + if (inst != NULL && + inst->district_id >= 0 && inst->district_id < is->district_count && + inst->district_id == NEIGHBORHOOD_DISTRICT_ID) + count++; + } + return count; +} + +int +count_utilized_neighborhoods_in_city_radius (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return 0; + + int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; + if (base_cap <= 0) + return 0; + + int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; + if (per_neighborhood <= 0) + return 0; + + int pop = city->Body.Population.Size; + if (pop <= base_cap) + return 0; + + int excess_pop = pop - base_cap; + int utilized = (excess_pop + per_neighborhood - 1) / per_neighborhood; + int total_neighborhoods = count_neighborhoods_in_city_radius (city); + + if (utilized > total_neighborhoods) + utilized = total_neighborhoods; + + return utilized; +} + +int +get_neighborhood_pop_cap (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return -1; + + int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; + if (base_cap <= 0) + return -1; + + int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; + if (per_neighborhood < 0) + per_neighborhood = 0; + + int neighborhoods = count_neighborhoods_in_city_radius (city); + long long cap = (long long)base_cap + (long long)per_neighborhood * neighborhoods; + if (cap < base_cap) + cap = base_cap; + + return (int)cap; +} + +bool +city_is_at_neighborhood_cap (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return false; + + int cap = get_neighborhood_pop_cap (city); + if (cap <= 0) + return false; + + return city->Body.Population.Size >= cap; +} + +void +ensure_neighborhood_request_for_city (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return; + + if (! leader_can_build_district (&leaders[city->Body.CivID], NEIGHBORHOOD_DISTRICT_ID)) + return; + + mark_city_needs_district (city, NEIGHBORHOOD_DISTRICT_ID); +} + +void +calculate_district_culture_science_bonuses (City * city, int * culture_bonus, int * science_bonus) +{ + if (culture_bonus != NULL) + *culture_bonus = 0; + if (science_bonus != NULL) + *science_bonus = 0; + + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders) || (city == NULL)) + return; + + int total_culture = 0; + int total_science = 0; + int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) + continue; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + struct district_config const * cfg = &is->district_configs[district_id]; + int district_culture_bonus = 0; + int district_science_bonus = 0; + get_effective_district_yields (inst, cfg, NULL, NULL, NULL, &district_science_bonus, &district_culture_bonus, NULL); + + bool is_neighborhood = (cfg->command == UCV_Build_Neighborhood); + if (is_neighborhood) { + if (utilized_neighborhoods > 0) { + total_culture += district_culture_bonus; + total_science += district_science_bonus; + utilized_neighborhoods--; + } + } else { + total_culture += district_culture_bonus; + total_science += district_science_bonus; + } + } + + if (culture_bonus != NULL) + *culture_bonus = total_culture; + if (science_bonus != NULL) + *science_bonus = total_science; +} + +void +calculate_district_happiness_bonus (City * city, int * happiness_bonus) +{ + if (happiness_bonus != NULL) + *happiness_bonus = 0; + + if (! is->current_config.enable_districts || (city == NULL)) + return; + + int total_happy = 0; + int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) + continue; + + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + struct district_config const * cfg = &is->district_configs[district_id]; + + bool is_neighborhood = district_id == NEIGHBORHOOD_DISTRICT_ID; + if (is_neighborhood && (utilized_neighborhoods <= 0)) + continue; + + if (is_neighborhood) + utilized_neighborhoods--; + + int district_happy = 0; + get_effective_district_yields (inst, cfg, NULL, NULL, NULL, NULL, NULL, &district_happy); + if (district_happy != 0) + total_happy += district_happy; + } + + if (happiness_bonus != NULL) + *happiness_bonus = total_happy; +} + +int __fastcall +patch_City_requires_improvement_to_grow (City * this) +{ + int required_improv = City_requires_improvement_to_grow (this); + if ((required_improv == -1) && + (this != NULL) && + is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + city_is_at_neighborhood_cap (this)) { + return 0; // Neighborhood sentinel + } + + return required_improv; +} + +// Replacement check specifically for stalled growth check function, +// where we can't pass through the neighborhood sentinel. That function itself +// doesn't block growth, it just triggers the dialog, so safe to skip it if +// neighborhoods are needed. +int __fastcall +patch_City_requires_improvement_to_grow_besides_neighborhood (City * this) +{ + return City_requires_improvement_to_grow (this); +} + +void __fastcall +patch_maybe_show_improvement_needed_for_growth_dialog (void * this, int edx, City * city, int * param_2) +{ + int required_improv_id = (int)param_2; + if (is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + (required_improv_id == 0)) // Neighborhood sentinel + return; + + maybe_show_improvement_needed_for_growth_dialog (this, __, city, param_2); +} + +void +maybe_show_neighborhood_growth_warning (City * city) +{ + if ((city == NULL) || ! (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts)) return; + int requirement = patch_City_requires_improvement_to_grow (city); + if (requirement != 0) return; // Neighborhood sentinel not present + if (city->Body.FoodIncome <= 0) return; // Not growing + if (is_online_game ()) return; + int civ_id = city->Body.CivID; + if (civ_id != p_main_screen_form->Player_CivID) return; + if ((*p_human_player_bits & (1u << civ_id)) == 0) return; + + unsigned int turn_no = (unsigned int)*p_current_turn_no; + unsigned int throttle = ((unsigned int)city->Body.X << 5) ^ (unsigned int)city->Body.Y; + int frequency = is->current_config.neighborhood_needed_message_frequency; + if ((frequency <= 0) || (((turn_no + throttle) % frequency) != 0)) + return; + + char msg[160]; + char const * city_name = city->Body.CityName; + snprintf (msg, sizeof msg, "%s %s %s %s", + city_name, + is->c3x_labels[CL_REQUIRES], + is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name, + is->c3x_labels[CL_TO_GROW] + ); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); +} + +bool __stdcall +patch_is_not_pop_capped_or_starving (City * city) +{ + bool tr = is_not_pop_capped_or_starving (city); + if (! tr) return false; + + if (is->current_config.enable_districts) { + if (city_is_at_neighborhood_cap (city)) + return false; + } + + return true; +} + +bool +remove_building_if_no_district (City * city, int district_id, int building_id) +{ + if ((city == NULL) || (building_id < 0)) return false; + if (! patch_City_has_improvement (city, __, building_id, false)) return false; + if (city_has_required_district (city, district_id)) return false; + + patch_City_add_or_remove_improvement (city, __, building_id, 0, false); + return true; +} + +bool +city_has_other_completed_wonder_district_for_improvement (City * city, int wonder_improv_id, int removed_x, int removed_y) +{ + if (! (is->current_config.enable_districts && is->current_config.enable_wonder_districts) || + (city == NULL) || (wonder_improv_id < 0)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + if ((x == removed_x) && (y == removed_y)) + continue; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if (info->state != WDS_COMPLETED) + continue; + + int candidate_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); + if (candidate_improv_id != wonder_improv_id) + continue; + + return true; + } + + return false; +} + +void +remove_shared_wonder_if_no_other_district (City * city, int wonder_improv_id, int removed_x, int removed_y) +{ + if ((city == NULL) || (wonder_improv_id < 0)) + return; + + if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) + return; + + if (leaders[city->Body.CivID].Small_Wonders[wonder_improv_id] == city->Body.ID) + return; + + if (city_has_other_completed_wonder_district_for_improvement (city, wonder_improv_id, removed_x, removed_y)) + return; + + patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); +} + +void +reduce_city_population_due_to_lost_neighborhood (City * city) +{ + if (city == NULL) + return; + + if (! (is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + is->current_config.destroying_neighborhood_reduces_pop)) + return; + + int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; + int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; + if ((base_cap <= 0) || (per_neighborhood <= 0)) + return; + + int neighborhoods = count_neighborhoods_in_city_radius (city); + int cap = base_cap + (per_neighborhood * neighborhoods); + if (cap < base_cap) + cap = base_cap; + + int pop = city->Body.Population.Size; + if (pop <= cap) + return; + + int to_remove = pop - cap; + int removed = 0; + while (to_remove-- > 0) { + City_remove_population (city, __, 1, -1, '\0'); + removed++; + } + + if ((removed > 0) && + ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && + (city->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[160]; + snprintf (msg, sizeof msg, "%s %s %s", + city->Body.CityName, + is->c3x_labels[CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD], + is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name + ); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } +} + +bool +city_has_other_completed_district (City * city, int district_id, int removed_x, int removed_y) +{ + if (! is->current_config.enable_districts || + (city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + if ((x == removed_x) && (y == removed_y)) + continue; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != district_id) + continue; + + return true; + } + + return false; +} + +bool +district_instance_is_redundant (struct district_instance * inst, Tile * tile) +{ + if (! is->current_config.enable_districts || + (inst == NULL) || + (tile == NULL) || (tile == p_null_tile)) + return false; + + int district_id = inst->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + if (! district_is_complete (tile, district_id)) + return false; + + if (district_id == NEIGHBORHOOD_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID) + return false; + + int tile_x = inst->tile_x; + int tile_y = inst->tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + return false; + + int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + + if (district_id == WONDER_DISTRICT_ID) + return inst->wonder_info.state == WDS_UNUSED; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + if (! city_has_other_completed_district (wai.city, district_id, tile_x, tile_y)) + return false; + } + + return true; +} + +bool +any_nearby_city_would_lose_district_benefits (int district_id, int civ_id, int removed_x, int removed_y) +{ + if (! is->current_config.enable_districts) + return false; + + if (district_id < 0 || district_id >= is->district_count) + return false; + + struct district_infos * info = &is->district_infos[district_id]; + + // If there are no dependent buildings, no city can lose benefits + if (info->dependent_building_count == 0) + return false; + + // Check all cities within work radius of the removed district + FOR_CITIES_AROUND (wai, removed_x, removed_y) { + City * city = wai.city; + + // Check if this city has another completed district of the same type nearby (excluding the one being removed) + if (city_has_other_completed_district (city, district_id, removed_x, removed_y)) + continue; + + // This city doesn't have another district, check if it has any dependent buildings + for (int i = 0; i < info->dependent_building_count; i++) { + int building_id = info->dependent_building_ids[i]; + if (building_id >= 0 && patch_City_has_improvement (city, __, building_id, false)) + return true; + } + } + + return false; +} + +void +remove_dependent_buildings_for_district (int district_id, int center_x, int center_y) +{ + if (! is->current_config.enable_districts || (district_id < 0) || (district_id >= is->district_count)) + return; + + struct district_infos * info = &is->district_infos[district_id]; + + if ((center_x < 0) || (center_y < 0) || + (center_x >= p_bic_data->Map.Width) || (center_y >= p_bic_data->Map.Height)) + return; + + FOR_CITIES_AROUND (wai, center_x, center_y) { + City * city = wai.city; + + if (city_has_other_completed_district (city, district_id, center_x, center_y)) + continue; + + int removed_count = 0; + int first_building_id = -1; + + for (int i = 0; i < info->dependent_building_count; i++) { + int building_id = info->dependent_building_ids[i]; + if (building_id >= 0) { + // This also loops through tiles around the city but is not redundant, as the city + // may have multiple districts of the same type in its radius (eg outside radius of this particular district) + if (remove_building_if_no_district (city, district_id, building_id)) { + if (removed_count == 0) + first_building_id = building_id; + removed_count++; + } + } + } + + if ((removed_count > 0) && + is->current_config.show_message_when_building_lost_to_destroyed_district && + ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && + (city->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[200]; + char const * district_name = is->district_configs[district_id].name; + char const * building_name = (first_building_id >= 0) ? p_bic_data->Improvements[first_building_id].Name.S : ""; + + if (removed_count == 1) + snprintf (msg, sizeof msg, "%s%s %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_APOSTROPHE_S], + building_name, + is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], + district_name); + else + snprintf (msg, sizeof msg, "%s%s %s %s %d %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_APOSTROPHE_S], + building_name, + is->c3x_labels[CL_AND], + removed_count - 1, + is->c3x_labels[CL_OTHER_BUILDINGS_HAVE_BEEN], + is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], + district_name); + + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + } +} + +void +remove_wonder_improvement_for_destroyed_district (int wonder_improv_id) +{ + if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) + return; + + if ((p_cities == NULL) || (p_cities->Cities == NULL)) + return; + + for (int idx = 0; idx <= p_cities->LastIndex; idx++) { + City * city = get_city_ptr (idx); + if (city == NULL) + continue; + if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) + continue; + + patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); + } +} + +void +handle_district_removed (Tile * tile, int district_id, int center_x, int center_y, bool leave_ruins) +{ + if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.enable_districts) + return; + + int wonder_windex = -1; + int wonder_improv_id = -1; + + // Get wonder district info before removing + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info != NULL && info->state == WDS_COMPLETED) + wonder_windex = info->wonder_index; + + int actual_district_id = district_id; + if (actual_district_id < 0) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) + actual_district_id = inst->district_id; + } + + remove_district_instance (tile); + + bool removed_neighborhood = actual_district_id == NEIGHBORHOOD_DISTRICT_ID; + + if (is->current_config.enable_wonder_districts && + (actual_district_id == WONDER_DISTRICT_ID) && + (wonder_windex >= 0)) + wonder_improv_id = get_wonder_improvement_id_from_index (wonder_windex); + + if (wonder_improv_id >= 0 && is->current_config.completed_wonder_districts_can_be_destroyed) + remove_wonder_improvement_for_destroyed_district (wonder_improv_id); + + if (is->current_config.enable_distribution_hub_districts && + (actual_district_id == DISTRIBUTION_HUB_DISTRICT_ID)) + remove_distribution_hub_record (tile); + + if (district_id >= 0) + remove_dependent_buildings_for_district (district_id, center_x, center_y); + + // Make the tile workable again by resetting CityAreaID and recomputing yields for nearby cities + tile->Body.CityAreaID = -1; + + int tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + FOR_CITIES_AROUND (wai, center_x, center_y) { + if (removed_neighborhood) + reduce_city_population_due_to_lost_neighborhood (wai.city); + recompute_city_yields_with_districts (wai.city); + } + + if (leave_ruins && (tile->vtable->m60_Set_Ruins != NULL)) { + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, center_x, center_y); + tile->vtable->m60_Set_Ruins (tile, __, 1); + } + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +bool +city_has_active_wonder_for_district (City * city) +{ + struct district_infos * info = &is->district_infos[WONDER_DISTRICT_ID]; + for (int n = 0; n < ARRAY_LEN (info->dependent_building_ids); n++) { + int building_id = info->dependent_building_ids[n]; + if ((building_id >= 0) && has_active_building (city, building_id)) + return true; + } + return false; +} + +bool +city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id) +{ + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); + if ((prereq_list == NULL) || (prereq_list->count <= 0)) + return false; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder = false; + + // Special logic for handling rivers + bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; + bool has_prereq = false; + + if (is->current_config.enable_wonder_districts && + district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) { + is_wonder = true; + if (! wonder_is_buildable_by_civ (improv_id, city->Body.CivID)) { + if (out_district_id != NULL) + *out_district_id = -1; + return false; + } + if (requires_river) { + bool has_river_wonder_district = false; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if (wai.district_inst->district_id != WONDER_DISTRICT_ID) + continue; + if (wai.tile->vtable->m37_Get_River_Code (wai.tile) == 0) + continue; + if (! wonder_is_buildable_on_tile (wai.tile, improv_id)) + continue; + struct wonder_district_info * info = get_wonder_district_info (wai.tile); + if (info == NULL) { + has_river_wonder_district = true; + break; + } + if (info->state == WDS_COMPLETED) + continue; + if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) + continue; + has_river_wonder_district = true; + break; + } + if (has_river_wonder_district) + has_prereq = true; + } else if (city_has_wonder_district_with_no_completed_wonder (city, improv_id)) { + has_prereq = true; + } + } + + if (! has_prereq && city_has_any_prereq_district_for_improvement (city, prereq_list, requires_river, !is_wonder)) + has_prereq = true; + + if (has_prereq) + return false; + + if (out_district_id != NULL) + *out_district_id = pick_missing_district_for_improvement (city, prereq_list); + return true; +} + +void +clear_best_feasible_order (City * city) +{ + int key = (int)city; + int stored_int; + if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) { + struct ai_best_feasible_order * stored = (struct ai_best_feasible_order *)stored_int; + free (stored); + itable_remove (&is->ai_best_feasible_orders, key); + } +} + +void +record_best_feasible_order (City * city, City_Order const * order, int value) +{ + int key = (int)city; + int stored_int; + struct ai_best_feasible_order * stored; + if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) + stored = (struct ai_best_feasible_order *)stored_int; + else { + stored = malloc (sizeof *stored); + if (stored == NULL) + return; + stored->order = *order; + stored->value = value; + itable_insert (&is->ai_best_feasible_orders, key, (int)stored); + return; + } + + if (value > stored->value) { + stored->order = *order; + stored->value = value; + } +} + +struct ai_best_feasible_order * +get_best_feasible_order (City * city) +{ + int stored_int; + if (itable_look_up (&is->ai_best_feasible_orders, (int)city, &stored_int)) + return (struct ai_best_feasible_order *)stored_int; + else + return NULL; +} + +bool +city_is_currently_building_wonder (City * city) +{ + if ((city == NULL) || (city->Body.Order_Type != COT_Improvement)) + return false; + int order_id = city->Body.Order_ID; + if ((order_id < 0) || (order_id >= p_bic_data->ImprovementsCount)) + return false; + return (p_bic_data->Improvements[order_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; +} + +bool +wonder_district_tile_under_construction (Tile * tile, int tile_x, int tile_y, int * out_windex) +{ + if (! is->current_config.enable_wonder_districts || + (tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != WONDER_DISTRICT_ID) + return false; + + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info == NULL || info->state != WDS_UNDER_CONSTRUCTION) + return false; + + City * reserved_city = get_city_ptr (info->city_id); + if (reserved_city == NULL) + return false; + info->city = reserved_city; + info->city_id = reserved_city->Body.ID; + + // Verify the reserved city is still building a wonder + if (! city_is_currently_building_wonder (reserved_city)) + return false; + + // Verify this tile is within the reserved city's radius + if (! city_radius_contains_tile (reserved_city, tile_x, tile_y)) + return false; + + // Get the wonder index for the wonder being built + if (out_windex != NULL) { + int order_id = reserved_city->Body.Order_ID; + int windex = find_wonder_config_index_by_improvement_id (order_id); + *out_windex = windex; + } + + return true; +} + +bool +city_needs_wonder_district (City * city) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + + int pending_improv_id; + if (look_up_pending_building_order (city, &pending_improv_id)) { + // Check if it's actually a wonder + if ((pending_improv_id >= 0) && (pending_improv_id < p_bic_data->ImprovementsCount)) { + Improvement * improv = &p_bic_data->Improvements[pending_improv_id]; + if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + return true; + } + } + if (city_is_currently_building_wonder (city)) + return true; + if (city_has_active_wonder_for_district (city)) + return true; + return false; +} + +bool +city_has_assigned_wonder_district (City * city, Tile * ignore_tile, int wonder_improv_id) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + if (candidate == ignore_tile) + continue; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = inst ? &inst->wonder_info : NULL; + if ((info != NULL) && + (info->state == WDS_UNDER_CONSTRUCTION) && + (info->city_id == city->Body.ID)) { + info->city = city; + if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) { + info->state = WDS_UNUSED; + info->city = NULL; + info->city_id = -1; + info->wonder_index = -1; + continue; + } + return true; + } + } + + return false; +} + +bool +free_wonder_district_for_city (City * city) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) + return false; + if (city_needs_wonder_district (city)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { + int x = wai.tile_x, y = wai.tile_y; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info != NULL && info->state == WDS_COMPLETED) + continue; // Don't remove completed wonder districts + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + continue; + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + + handle_district_removed (tile, WONDER_DISTRICT_ID, city->Body.X, city->Body.Y, false); + return true; + } + + return false; +} + +bool +reserve_wonder_district_for_city (City * city, int wonder_improv_id) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) + return false; + + if (city_has_assigned_wonder_district (city, NULL, wonder_improv_id)) + return true; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if (info->state == WDS_COMPLETED) continue; + if (info->state == WDS_UNDER_CONSTRUCTION) { + if (info->city_id == city->Body.ID) { + info->city = city; + return true; + } + continue; + } + if (city_has_assigned_wonder_district (city, candidate, wonder_improv_id)) + return true; + + // Reserve this Wonder district for this city + info->state = WDS_UNDER_CONSTRUCTION; + info->city = city; + info->city_id = city->Body.ID; + info->wonder_index = -1; + return true; + } + + return false; +} + +void +release_wonder_district_reservation (City * city) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return; + + // Find and remove any reservations for this city + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if ((info != NULL) && + (info->state == WDS_UNDER_CONSTRUCTION) && + (info->city_id == city->Body.ID)) { + info->city = city; + info->state = WDS_UNUSED; + info->city = NULL; + info->city_id = -1; + info->wonder_index = -1; + } + } +} + +void +handle_district_destroyed_by_attack (Tile * tile, int tile_x, int tile_y, bool leave_ruins) +{ + if (! is->current_config.enable_districts || tile == NULL || tile == p_null_tile) + return; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + int district_id = inst->district_id; + + // If this is a Wonder District with a completed wonder and wonders can't be destroyed, restore overlay and keep district + if (is->current_config.enable_wonder_districts) { + struct wonder_district_info * info = get_wonder_district_info (tile); + if ((district_id == WONDER_DISTRICT_ID) && + (info != NULL && info->state == WDS_COMPLETED) && + (! is->current_config.completed_wonder_districts_can_be_destroyed)) { + unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); + if ((overlays & TILE_FLAG_MINE) == 0) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + return; + } + } + if (district_id == BRIDGE_DISTRICT_ID || district_id == CANAL_DISTRICT_ID) { + enum UnitTypeClasses target_class = (district_id == BRIDGE_DISTRICT_ID) ? UTC_Land : UTC_Sea; + clear_memo (); + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if (unit == NULL) + continue; + int unit_type_id = unit->Body.UnitTypeID; + if ((unit_type_id < 0) || (unit_type_id >= p_bic_data->UnitTypeCount)) + continue; + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + bool matches = (type->Unit_Class == target_class); + if (! matches && unit->Body.Container_Unit >= 0) { + Unit * container = get_unit_ptr (unit->Body.Container_Unit); + if (container != NULL) { + int container_type_id = container->Body.UnitTypeID; + if ((container_type_id >= 0) && (container_type_id < p_bic_data->UnitTypeCount)) { + UnitType * container_type = &p_bic_data->UnitTypes[container_type_id]; + matches = (container_type->Unit_Class == target_class); + } + } + } + if (matches) { + bool already = false; + for (int n = 0; n < is->memo_len; n++) + if (is->memo[n] == unit->Body.ID) { + already = true; + break; + } + if (! already) + memoize (unit->Body.ID); + } + } + for (int n = 0; n < is->memo_len; n++) { + Unit * to_despawn = get_unit_ptr (is->memo[n]); + if (to_despawn != NULL) + patch_Unit_despawn (to_despawn, __, 0, 1, 0, 0, 0, 0, 0); + } + clear_memo (); + } + handle_district_removed (tile, district_id, tile_x, tile_y, leave_ruins); + } +} + +bool +has_active_building (City * city, int improv_id) +{ + Leader * owner = &leaders[city->Body.CivID]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + return patch_City_has_improvement (city, __, improv_id, 1) && // building is physically present in city AND + ((improv->ObsoleteID < 0) || (! Leader_has_tech (owner, __, improv->ObsoleteID))) && // building is not obsolete AND + ((improv->GovernmentID < 0) || (improv->GovernmentID == owner->GovernmentType)); // building is not restricted to a different govt +} + +void +init_unit_type_count (Leader * leader) +{ + int id = leader->ID; + struct table * counts = &is->unit_type_counts[id]; + + if (counts->len > 0) + table_deinit (counts); + + if (p_units->Units != NULL) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit_Body * body = p_units->Units[n].Unit; + if ((body != NULL) && ((int)body != offsetof (Unit, Body)) && (body->CivID == id)) { + int prev_count = itable_look_up_or (counts, body->UnitTypeID, 0); + itable_insert (counts, body->UnitTypeID, prev_count + 1); + } + } + + is->unit_type_count_init_bits |= 1 << id; +} + +int +get_unit_type_count (Leader * leader, int unit_type_id) +{ + int id = leader->ID; + struct table * counts = &is->unit_type_counts[id]; + + if ((is->unit_type_count_init_bits & 1<ID; + struct table * counts = &is->unit_type_counts[id]; + if ((is->unit_type_count_init_bits & (1 << id)) == 0) + init_unit_type_count (leader); + + int prev_amount = itable_look_up_or (counts, unit_type_id, 0); + itable_insert (counts, unit_type_id, prev_amount + amount); +} + +// If this unit type is limited, returns true and writes how many units of the type the given player is allowed to "out_limit". If the type is not +// limited, returns false. +bool +get_unit_limit (Leader * leader, int unit_type_id, int * out_limit) +{ + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + struct unit_type_limit * lim; + 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; + if (lim->cities_per != 0) + tr += city_count / lim->cities_per; + *out_limit = tr; + return true; + } else + return false; +} + +// This this unit type is limited, returns true and writes to "out_available" how many units the given player can add before reaching the limit. If +// the type is not limited, returns false. +bool +get_available_unit_count (Leader * leader, int unit_type_id, int * out_available) +{ + int limit; + if (get_unit_limit (leader, unit_type_id, &limit)) { + int count = get_unit_type_count (leader, unit_type_id); + int dups[30]; + int dups_count = list_unit_type_duplicates (unit_type_id, dups, ARRAY_LEN (dups)); + for (int n = 0; n < dups_count; n++) + count += get_unit_type_count (leader, dups[n]); + + *out_available = limit - count; + return true; + } else + return false; +} + +int +add_i31b_to_int (int base, i31b addition) +{ + int amount; + bool percent; + i31b_unpack (addition, &amount, &percent); + if (! percent) + return base + amount; + else { + int fraction = (base * int_abs (amount) + 50) / 100; + return (amount >= 0) ? base + fraction : base - fraction; + } +} + +int +apply_perfume (enum perfume_kind kind, char const * name, int base_amount) +{ + i31b perfume_value; + if (stable_look_up (&is->current_config.perfume_specs[kind], name, &perfume_value)) + return add_i31b_to_int (base_amount, perfume_value); + else + return base_amount; +} + +int __stdcall +intercept_consideration (int valuation) +{ + City * city = is->ai_considering_production_for_city; + City_Order * order = &is->ai_considering_order; + + // Apply perfume + char * order_name; { + if (order->OrderType == COT_Improvement) + order_name = p_bic_data->Improvements[order->OrderID].Name.S; + else + order_name = p_bic_data->UnitTypes[order->OrderID].Name; + } + valuation = apply_perfume (PK_PRODUCTION, order_name, valuation); + + // Apply temp AI settler perfume + if ((order->OrderType == COT_Unit) && + (p_bic_data->UnitTypes[order->OrderID].AI_Strategy & UTAI_Settle) && + (is->current_config.ai_settler_perfume_on_founding != 0) && + (is->current_config.ai_settler_perfume_on_founding_duration != 0) && + (is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID] >= 0)) { + int turns_since_founding = *p_current_turn_no - is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID]; + int duration = is->current_config.ai_settler_perfume_on_founding_duration; + if (turns_since_founding < duration) { + i31b perfume = is->current_config.ai_settler_perfume_on_founding; + + // Scale amount by turns remaining + { + int amount; + bool percent; + i31b_unpack (perfume, &amount, &percent); + + int percent_remaining = (100 * (duration - turns_since_founding)) / duration; + amount = (amount * percent_remaining + 50) / 100; + + perfume = i31b_pack (amount, percent); + } + + valuation = add_i31b_to_int (valuation, perfume); + } + } + + if (is->current_config.enable_districts && + (city != NULL) && + ((*p_human_player_bits & (1 << city->Body.CivID)) == 0)) { + bool feasible = false; + switch (order->OrderType) { + case COT_Improvement: + if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->ImprovementsCount) && + (! city_requires_district_for_improvement (city, order->OrderID, NULL))) + feasible = true; + break; + case COT_Unit: + if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->UnitTypeCount)) + feasible = true; + break; + default: + break; + } + if (feasible) + record_best_feasible_order (city, order, valuation); + } + + // Expand the list of valuations if necessary + reserve (sizeof is->ai_prod_valuations[0], (void **)&is->ai_prod_valuations, &is->ai_prod_valuations_capacity, is->count_ai_prod_valuations); + + // Record this valuation + int n = is->count_ai_prod_valuations++; + is->ai_prod_valuations[n] = (struct ai_prod_valuation) { + .order_type = order->OrderType, + .order_id = order->OrderID, + .point_value = valuation + }; + + return valuation; +} + +// Returns a pointer to a bitfield that can be used to record resource access for resource IDs >= 32. This procedure can work with any city ID since +// it allocates and zero-initializes these bit fields as necessary. The given resource ID must be at least 32. The index of the bit for that resource +// within the field is resource_id%32. +unsigned * +get_extra_resource_bits (int city_id, int resource_id) +{ + int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); + int ints_per_city = 1 + extra_resource_count/32; + if (city_id >= is->extra_available_resources_capacity) { + int new_capacity = city_id + 100; + unsigned * new_array = calloc (new_capacity * ints_per_city, sizeof new_array[0]); + if (is->extra_available_resources != NULL) { + memcpy (new_array, is->extra_available_resources, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); + free (is->extra_available_resources); + } + is->extra_available_resources = new_array; + is->extra_available_resources_capacity = new_capacity; + } + return &is->extra_available_resources[city_id * ints_per_city + (resource_id-32)/32]; +} + +void __stdcall +intercept_set_resource_bit (City * city, int resource_id) +{ + if (resource_id < 32) + city->Body.Available_Resources |= 1 << resource_id; + else + *get_extra_resource_bits (city->Body.ID, resource_id) |= 1 << (resource_id&31); +} + +// Must forward declare this function since there's a circular dependency between it and patch_City_has_resource +bool has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id); + +bool __fastcall +patch_City_has_resource (City * this, int edx, int resource_id) +{ + return city_has_resource_r (this, resource_id, INT_MAX); +} + +bool +city_has_resource_r (City * this, int resource_id, int max_generated_resource_id) +{ + bool tr; + if ((this == NULL) || (resource_id < 0) || (resource_id >= p_bic_data->ResourceTypeCount)) + return false; + if (resource_id > max_generated_resource_id) + return false; + + if (is->current_config.patch_phantom_resource_bug && + (resource_id >= 32) && (resource_id < p_bic_data->ResourceTypeCount) && + (! City_has_trade_connection_to_capital (this))) { + unsigned bits = (this->Body.ID < is->extra_available_resources_capacity) ? *get_extra_resource_bits (this->Body.ID, resource_id) : 0; + tr = (bits >> (resource_id&31)) & 1; + } else + tr = City_has_resource (this, __, resource_id); + + // Check if access to this resource is provided by a building in the city + if (! tr) + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if ((mill->resource_id == resource_id) && + (mill->flags & MF_LOCAL) && + can_generate_resource (this->Body.CivID, mill) && + has_active_building (this, mill->improv_id) && + has_resources_required_by_building_r (this, mill->improv_id, mill->resource_id - 1)) { + tr = true; + break; + } + } + + // Check if access to this resource is provided by a district in the city's work radius + if ((! tr) && is->current_config.enable_districts) { + FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { + struct district_instance * di = wai.district_inst; + int district_id = di->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + continue; + + struct district_config * dc = &is->district_configs[district_id]; + if ((dc->generated_resource_id == resource_id) && + (dc->generated_resource_flags & MF_LOCAL) && + district_generates_resource_for_civ (wai.tile, di, dc, this->Body.CivID)) { + tr = true; + break; + } + } + } + + return tr; +} + +// Checks if the resource requirements for an improvement are satisfied in a given city. The "max_req_resource_id" parameter is to guard against +// infinite loops in case of circular resource dependencies due to mills. The way it works is that resource requirements can only be satisfied if +// their ID is not greater than that limit. This function is called recursively by patch_City_has_resource and in the recursive calls, the limit is +// set to be below the resource ID provided by the mill being considered. So, when considering resource production chains, the limit approaches zero +// with each recursive call, hence infinite loops are not possible. +bool +has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id) +{ + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if (! (improv->ImprovementFlags & ITF_Required_Goods_Must_Be_In_City_Radius)) { + for (int n = 0; n < 2; n++) { + int res_id = (&improv->Resource1ID)[n]; + if ((res_id >= 0) && + ((res_id > max_req_resource_id) || (! city_has_resource_r (city, res_id, max_req_resource_id)))) + return false; + } + return true; + } else { + int * targets = &improv->Resource1ID; + if ((targets[0] < 0) && (targets[1] < 0)) + return true; + int finds[2] = {0, 0}; + + int civ_id = city->Body.CivID; + for (int n = 0; n < is->workable_tile_count; n++) { + int dx, dy; + patch_ni_to_diff_for_work_area (n, &dx, &dy); + int x = city->Body.X + dx, y = city->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &x, &y); + Tile * tile = tile_at (x, y); + if (tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id) { + int res_here = Tile_get_resource_visible_to (tile, __, civ_id); + if (res_here >= 0) { + finds[0] |= targets[0] == res_here; + finds[1] |= targets[1] == res_here; + } + } + } + + return ((targets[0] < 0) || finds[0]) && ((targets[1] < 0) || finds[1]); + } +} + +bool +has_resources_required_by_building (City * city, int improv_id) +{ + return has_resources_required_by_building_r (city, improv_id, INT_MAX); +} + +void __fastcall +patch_City_recompute_commerce (City * this) +{ + City_recompute_commerce (this); + + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + int science_bonus = 0; + calculate_district_culture_science_bonuses (this, NULL, &science_bonus); + + if (science_bonus != 0) { + this->Body.Science += science_bonus; + if (this->Body.Science < 0) + this->Body.Science = 0; + } +} + +void __fastcall +patch_City_recompute_yields_and_happiness (City * this) +{ + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts && + ! is->distribution_hub_refresh_in_progress && + is->distribution_hub_totals_dirty) + recompute_distribution_hub_totals (); + + City_recompute_yields_and_happiness (this); +} + +void __fastcall +patch_City_update_culture (City * this) +{ + City_update_culture (this); + + if ((this == NULL) || ! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + int culture_bonus = 0; + calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); + + if (culture_bonus == 0) + return; + + int culture_income = this->Body.CultureIncome + culture_bonus; + if (culture_income < 0) + culture_income = 0; + this->Body.CultureIncome = culture_income; + + int civ_id = this->Body.CivID; + int total_culture = this->Body.Total_Cultures[civ_id] + culture_bonus; + if (total_culture < 0) + total_culture = 0; + this->Body.Total_Cultures[civ_id] = total_culture; + + City_recompute_cultural_level (this, __, '\0', '\0', '\0'); +} + +void __fastcall +patch_City_recompute_culture_income (City * this) +{ + City_recompute_culture_income (this); + + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + int culture_bonus = 0; + calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); + + if (culture_bonus != 0) { + this->Body.CultureIncome += culture_bonus; + if (this->Body.CultureIncome < 0) + this->Body.CultureIncome = 0; + } +} + +// Recomputes yields in cities with active mills that depend on input resources. Intended to be called when an input resource has been potentially +// gained or lost. Recomputes only for the cities of a given leader or, if NULL, for all cities on the map. +void +recompute_mill_yields_after_resource_change (Leader * leader_or_null) +{ + if (p_cities->Cities != NULL) + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city != NULL) && + ((leader_or_null == NULL) || (city->Body.CivID == leader_or_null->ID))) { + bool any_relevant_mills = false; + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + Improvement * mill_improv = &p_bic_data->Improvements[mill->improv_id]; + if ((mill->flags & MF_YIELDS) && + ((mill_improv->Resource1ID >= 0) || (mill_improv->Resource2ID >= 0)) && + has_active_building (city, mill->improv_id)) { + any_relevant_mills = true; + break; + } + } + if (any_relevant_mills) + patch_City_recompute_yields_and_happiness (city); + } + } +} + + +int +resource_tile_resource_id (struct extra_resource_tile const * rt) +{ + if (rt == NULL) + return -1; + if (rt->type == ERT_MILL_RESOURCE) { + return (rt->mill_info.mill != NULL) ? rt->mill_info.mill->resource_id : -1; + } else if (rt->district_info.cfg != NULL) { + return rt->district_info.cfg->generated_resource_id; + } + return -1; +} + +int +compare_resource_tiles (void const * vp_a, void const * vp_b) +{ + struct extra_resource_tile const * a = vp_a, * b = vp_b; + return resource_tile_resource_id (a) - resource_tile_resource_id (b); +} + +void __fastcall +patch_Trade_Net_recompute_resources (Trade_Net * this, int edx, bool skip_popups) +{ + int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); + int ints_per_city = 1 + extra_resource_count/32; + memset (is->extra_available_resources, 0, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); + + // Assemble list of mill tiles + is->count_resource_tiles = 0; + if (p_cities->Cities != NULL) + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if (city != NULL) + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if (((mill->flags & MF_LOCAL) == 0) && + has_active_building (city, mill->improv_id) && + can_generate_resource (city->Body.CivID, mill)) { + Tile * resource_tile = tile_at (city->Body.X, city->Body.Y); + if ((resource_tile == NULL) || (resource_tile == p_null_tile)) + continue; + reserve (sizeof is->resource_tiles[0], + (void **)&is->resource_tiles, + &is->resource_tiles_capacity, + is->count_resource_tiles); + is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { + .tile = resource_tile, + .type = ERT_MILL_RESOURCE, + .mill_info = { + .city = city, + .mill = mill + } + }; + } + } + } + if (is->current_config.enable_districts) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * district_tile = (Tile *)tei.key; + struct district_instance * inst = (struct district_instance *)tei.value; + if ((district_tile == NULL) || (district_tile == p_null_tile) || (inst == NULL) || (inst->state != DS_COMPLETED)) + continue; + + int district_id = inst->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + continue; + + struct district_config * cfg = &is->district_configs[district_id]; + if ((cfg == NULL) || (cfg->generated_resource_id < 0)) + continue; + + int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); + if (owner_id < 0) + continue; + if ((cfg->generated_resource_flags & MF_LOCAL) != 0) + continue; + if (! district_can_generate_resource (owner_id, cfg)) + continue; + + reserve (sizeof is->resource_tiles[0], + (void **)&is->resource_tiles, + &is->resource_tiles_capacity, + is->count_resource_tiles); + is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { + .tile = district_tile, + .type = ERT_DISTRICT_RESOURCE, + .district_info = { + .inst = inst, + .cfg = cfg + } + }; + } + } + qsort (is->resource_tiles, is->count_resource_tiles, sizeof is->resource_tiles[0], compare_resource_tiles); + + is->got_resource_tile = NULL; + is->saved_tile_count = p_bic_data->Map.TileCount; + p_bic_data->Map.TileCount += is->count_resource_tiles; + Trade_Net_recompute_resources (this, __, skip_popups); + + // Restore the tile count if necessary. It may have already been restored by patch_Map_Renderer_m71_Draw_Tiles. This happens when the call to + // recompute_resources above opens a popup message about connecting a resource for the first time, which triggers redraw of the map. + if (is->saved_tile_count >= 0) { + p_bic_data->Map.TileCount = is->saved_tile_count; + is->saved_tile_count = -1; + } + + recompute_mill_yields_after_resource_change (NULL); + + is->must_recompute_resources_for_mill_inputs = false; +} + +Tile * +get_resource_tile (int index) +{ + struct extra_resource_tile * rt = &is->resource_tiles[index]; + is->got_resource_tile = rt; + return rt->tile; +} + +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_1 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_2 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_3 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_4 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_5 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } + +int __fastcall +patch_Tile_get_visible_resource_when_recomputing (Tile * tile, int edx, int civ_id) +{ + if (is->got_resource_tile != NULL) { + struct extra_resource_tile * rt = is->got_resource_tile; + is->got_resource_tile = NULL; + if (rt->type == ERT_MILL_RESOURCE) { + if ((rt->mill_info.city != NULL) && (rt->mill_info.mill != NULL) && + has_resources_required_by_building (rt->mill_info.city, rt->mill_info.mill->improv_id)) + return rt->mill_info.mill->resource_id; + else + return -1; + } else { + Tile * district_tile = rt->tile; + struct district_instance * inst = rt->district_info.inst; + struct district_config * cfg = rt->district_info.cfg; + if ((district_tile != NULL) && (district_tile != p_null_tile) && (inst != NULL) && + (cfg != NULL) && (inst->state == DS_COMPLETED)) { + int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); + if ((owner_id == civ_id) && district_generates_resource_for_civ (district_tile, inst, cfg, owner_id)) + return cfg->generated_resource_id; + } + return -1; + } + } + + int base_resource = Tile_get_resource_visible_to (tile, __, civ_id); + return base_resource; +} + +int WINAPI +patch_MessageBoxA (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) +{ + if (is->current_config.suppress_hypertext_links_exceeded_popup && + (strcmp (lpText, "Maximum hypertext links exceeded!") == 0)) + return IDOK; + else + return MessageBoxA (hWnd, lpText, lpCaption, uType); +} + +char * __fastcall +do_capture_modified_gold_trade (TradeOffer * trade_offer, int edx, int val, char * str, unsigned base) +{ + is->modifying_gold_trade = trade_offer; + return print_int (val, str, base); +} + +// Here the order of the registers matches the order that they're pushed by the pusha instruction +struct register_set { + int edi, esi, ebp, esp, ebx, edx, ecx, eax; +}; + +// Return 1 to allow the candidate unit to exert ZoC, 0 to exclude it. A pointer to the candidate is in esi. +int __stdcall +filter_zoc_candidate (struct register_set * reg) +{ + Unit * candidate = (Unit *)reg->esi, + * defender = is->zoc_defender; + + UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID], + * defender_type = &p_bic_data->UnitTypes[defender ->Body.UnitTypeID]; + + enum UnitTypeClasses candidate_class = candidate_type->Unit_Class, + defender_class = defender_type ->Unit_Class; + + bool lethal = ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) != 0) && (! is->temporarily_disallow_lethal_zoc); + bool aerial = (is->current_config.special_zone_of_control_rules & SZOCR_AERIAL ) != 0, + amphibious = (is->current_config.special_zone_of_control_rules & SZOCR_AMPHIBIOUS) != 0; + + // Exclude air units if aerial ZoC is not enabled and exclude land-to-sea & sea-to-land ZoC if amphibious is not enabled + if ((! aerial) && (candidate_class == UTC_Air)) + return 0; + if ((! amphibious) && + (((candidate_class == UTC_Land) && (defender_class == UTC_Sea )) || + ((candidate_class == UTC_Sea ) && (defender_class == UTC_Land)))) + return 0; + + // In case of cross-domain ZoC, filter out units with zero bombard strength or range. They can't use their attack strength in this case, so + // without bombard they can be ruled out. Don't forget units may have non-zero bombard strength and zero range for defensive bombard. + int range = (candidate_class != UTC_Air) ? candidate_type->Bombard_Range : candidate_type->OperationalRange; + if ((candidate_class != defender_class) && ((candidate_type->Bombard_Strength <= 0) || (range <= 0))) + return 0; + + // Require lethal config option & lethal bombard against one HP defender + if ((Unit_get_max_hp (defender) - defender->Body.Damage <= 1) && + ((! lethal) || + ((defender_class == UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Sea_Bombardment)) || + ((defender_class != UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Land_Bombardment)))) + return 0; + + // Air units require the bombing action to perform ZoC + if ((candidate_class == UTC_Air) && ! (candidate_type->Air_Missions & UCV_Bombing)) + return 0; + + // Exclude land units in transports if configured + if ((is->current_config.special_zone_of_control_rules & SZOCR_NOT_FROM_INSIDE) && candidate_class == UTC_Land) { + Unit * container = get_unit_ptr (candidate->Body.Container_Unit); + if ((container != NULL) && ! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)) + return 0; + } + + return 1; +} + +#define TRADE_NET_REF_COUNT 315 +#define TRADE_NET_INSTR_COUNT_GOG 22 +#define TRADE_NET_INSTR_COUNT_STEAM 23 +#define TRADE_NET_INSTR_COUNT_PCG 22 +#define TRADE_NET_ADDR_TOTAL_COUNT ((TRADE_NET_REF_COUNT * 3) + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM + TRADE_NET_INSTR_COUNT_PCG) + +int * +load_trade_net_addrs () +{ + if (is->trade_net_addrs_load_state == IS_OK) + return is->trade_net_addrs; + else if (is->trade_net_addrs_load_state == IS_INIT_FAILED) + return NULL; + + bool success = false; + char err_msg[300] = {0}; + + is->trade_net_addrs = calloc (3 * TRADE_NET_ADDR_TOTAL_COUNT, sizeof is->trade_net_addrs[0]); + if (! is->trade_net_addrs) { + snprintf (err_msg, (sizeof err_msg) - 1, "Bad alloc"); + goto done; + } + + char file_path[MAX_PATH] = {0}; + snprintf (file_path, (sizeof file_path) - 1, "%s\\trade_net_addresses.txt", is->mod_rel_dir); + char * refs_file = file_to_string (file_path); + if (! refs_file) { + snprintf (err_msg, (sizeof err_msg) - 1, "Couldn't load %s", file_path); + goto done; + } + + char * cursor = refs_file; + int loaded_count = 0; + while (true) { + if (*cursor == '#') { // comment line + skip_line (&cursor); + continue; + } + + skip_horiz_space (&cursor); + if (*cursor == '\n') { // empty line + cursor++; + continue; + } else if (*cursor == '\0') // end of file + break; + + // otherwise we must be on a line with some addresses + int ref; + bool got_any_addresses = false; + while (parse_int (&cursor, &ref)) { + if (loaded_count >= TRADE_NET_ADDR_TOTAL_COUNT) { + snprintf (err_msg, (sizeof err_msg) - 1, "Too many values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); + goto done; + } + is->trade_net_addrs[loaded_count] = ref; + loaded_count++; + got_any_addresses = true; + } + + if (! got_any_addresses) { + snprintf (err_msg, (sizeof err_msg) - 1, "Parse error"); + goto done; + } + } + + if (loaded_count < TRADE_NET_ADDR_TOTAL_COUNT) { + snprintf (err_msg, (sizeof err_msg) - 1, "Too few values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); + goto done; + } + + success = true; + +done: + free (refs_file); + if (! success) { + char full_err_msg[300] = {0}; + snprintf (full_err_msg, (sizeof full_err_msg) - 1, "Failed to load trade net refs: %s", err_msg); + MessageBox (NULL, full_err_msg, NULL, MB_ICONERROR); + is->trade_net_addrs_load_state = IS_INIT_FAILED; + return NULL; + } else { + is->trade_net_addrs_load_state = IS_OK; + return is->trade_net_addrs; + } +} + +unsigned short * __fastcall +patch_get_pixel_to_draw_city_dot (JGL_Image * this, int edx, int x, int y) +{ + unsigned short * tr = this->vtable->m07_m05_Get_Pixel (this, __, x, y); + + if ((x + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Width2) && (y + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Height2)) { + unsigned short * below = this->vtable->m07_m05_Get_Pixel (this, __, x + 1, y + 1); + if (below != NULL) + *below = 0; + } + + return tr; +} + +enum branch_kind { BK_CALL, BK_JUMP }; + +byte * +emit_branch (enum branch_kind kind, byte * cursor, void const * target) +{ + int offset = (int)target - ((int)cursor + 5); + *cursor++ = (kind == BK_CALL) ? 0xE8 : 0xE9; + return int_to_bytes (cursor, offset); +} + +// Just calls VirtualProtect and displays an error message if it fails. Made for use by the WITH_MEM_PROTECTION macro. +bool +check_virtual_protect (LPVOID addr, SIZE_T size, DWORD flags, PDWORD old_protect) +{ + if (VirtualProtect (addr, size, flags, old_protect)) + return true; + else { + char err_msg[1000]; + snprintf (err_msg, sizeof err_msg, "VirtualProtect failed! Args:\n Address: 0x%p\n Size: %d\n Flags: 0x%x", addr, size, flags); + err_msg[(sizeof err_msg) - 1] = '\0'; + MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); + return false; + } +} + +#define WITH_MEM_PROTECTION(addr, size, flags) \ + for (DWORD old_protect, unused, iter_count = 0; \ + (iter_count == 0) && check_virtual_protect (addr, size, flags, &old_protect); \ + VirtualProtect (addr, size, old_protect, &unused), iter_count++) + +void __fastcall adjust_sliders_preproduction (Leader * this); + +struct saved_code_area { + int size; + byte original_contents[]; +}; + +// Saves an area of base game code and optionally replaces it with no-ops. The area can be restored with restore_code_area. This method assumes that +// the necessary memory protection has already been set on the area, specifically that it can be written to. The method will do nothing if the area +// has already been saved with the same size. It's an error to re-save an address with a different size or overlap two saved areas. +void +save_code_area (byte * addr, int size, bool nopify) +{ + struct saved_code_area * sca; + if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { + if (sca->size != 0) { + if (sca->size != size) { + char s[200]; + snprintf (s, sizeof s, "Save code area conflict: address %p was already saved with size %d, conflicting with new size %d.", addr, sca->size, size); + s[(sizeof s) - 1] = '\0'; + pop_up_in_game_error (s); + } + return; + } + } else { + sca = malloc (size + sizeof *sca); + itable_insert (&is->saved_code_areas, (int)addr, (int)sca); + } + sca->size = size; + memcpy (&sca->original_contents, addr, size); + if (nopify) + memset (addr, 0x90, size); +} + +// Restores a saved chunk of code to its original contents. Does nothing if the area hasn't been saved. Assumes the appropriate memory protection has +// already been set. +void +restore_code_area (byte * addr) +{ + struct saved_code_area * sca; + if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { + memcpy (addr, &sca->original_contents, sca->size); + sca->size = 0; + } +} + +bool +is_code_area_saved (byte * addr) +{ + struct saved_code_area * sca; + return itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca) && (sca->size > 0); +} + +// Nopifies or restores an area depending on if yes_or_no is 1 or 0. Sets the necessary memory protections. +void +set_nopification (int yes_or_no, byte * addr, int size) +{ + WITH_MEM_PROTECTION (addr, size, PAGE_EXECUTE_READWRITE) { + if (yes_or_no) + save_code_area (addr, size, true); + else + restore_code_area (addr); + } +} + +void +apply_machine_code_edits (struct c3x_config const * cfg, bool at_program_start) +{ + DWORD old_protect, unused; + + // Allow stealth attack against single unit + WITH_MEM_PROTECTION (ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK = cfg->allow_stealth_attack_against_single_unit ? 0 : 1; + + // Enable small wonders providing free buildings + WITH_MEM_PROTECTION (ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER, 10, PAGE_EXECUTE_READWRITE) { + byte normal[8] = {0x83, 0xE1, 0x04, 0x80, 0xF9, 0x04, 0x0F, 0x85}; // and ecx, 4; cmp ecx, 4; jnz [offset] + byte modded[8] = {0x83, 0xE1, 0x0C, 0x80, 0xF9, 0x00, 0x0F, 0x84}; // and ecx, 12; cmp ecx, 0; jz [offset] + for (int n = 0; n < 8; n++) + ((byte *)ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER)[n] = cfg->enable_free_buildings_from_small_wonders ? modded[n] : normal[n]; + } + + // Bypass artillery in city check + // replacing 0x74 (= jump if [city ptr is] zero) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_CHECK_ARTILLERY_IN_CITY, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_CHECK_ARTILLERY_IN_CITY = cfg->use_offensive_artillery_ai ? 0xEB : 0x74; + + // Remove unit limit + if (! at_program_start) { + // Replace 0x7C (= jump if less than [unit limit]) with 0xEB (= uncond. jump) in Leader::spawn_unit + WITH_MEM_PROTECTION (ADDR_UNIT_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_UNIT_COUNT_CHECK = cfg->remove_unit_limit ? 0xEB : 0x7C; + + // Increase max ID to search for tradable units by 10x if limit removed + WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_UNIT_ID, 4, PAGE_EXECUTE_READWRITE) + int_to_bytes (ADDR_MAX_TRADABLE_UNIT_ID, cfg->remove_unit_limit ? 81920 : 8192); + + // Reallocate diplo_form->tradable_units array so it's 10x long if limit removed + civ_prog_free (p_diplo_form->tradable_units); + int tradable_units_len = cfg->remove_unit_limit ? 81920 : 8192, + tradable_units_size = tradable_units_len * sizeof (TradableItem); + p_diplo_form->tradable_units = new (tradable_units_size); + for (int n = 0; n < tradable_units_len; n++) + p_diplo_form->tradable_units[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 + + // Patch the size limit on some code that clears the tradable units array when starting a new game + WITH_MEM_PROTECTION (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) + int_to_bytes (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, tradable_units_size); + } + + // Remove era limit + // replacing 0x74 (= jump if zero [after cmp'ing era count with 4]) with 0xEB + WITH_MEM_PROTECTION (ADDR_ERA_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_ERA_COUNT_CHECK = cfg->remove_era_limit ? 0xEB : 0x74; + + // Fix science age bug + // Similar in nature to the sub bug, the function that measures a city's research output accepts a flag that determines whether or not it + // takes science ages into account. It's mistakenly not set by the code that gathers all research points to increment tech progress (but it + // is set elsewhere in code for the interface). The patch simply sets this flag. + WITH_MEM_PROTECTION (ADDR_SCIENCE_AGE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_SCIENCE_AGE_BUG_PATCH = cfg->patch_science_age_bug ? 1 : 0; + + // Pedia pink line bug fix + // The size of the pedia background texture is hard-coded into the EXE and in the base game it's one pixel too small. This shows up in game as + // a one pixel wide pink line along the right edge of the civilopedia. This patch simply increases the texture width by one. + WITH_MEM_PROTECTION (ADDR_PEDIA_TEXTURE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_PEDIA_TEXTURE_BUG_PATCH = cfg->patch_pedia_texture_bug ? 0xA6 : 0xA5; + + // Fix for houseboat bug + // See my posts on CFC for an explanation of the bug and its fix: + // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16084386 + // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16085242 + WITH_MEM_PROTECTION (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, PAGE_EXECUTE_READWRITE) { + if (cfg->patch_houseboat_bug) { + save_code_area (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, true); + byte * cursor = ADDR_HOUSEBOAT_BUG_PATCH; + *cursor++ = 0x50; // push eax + int call_offset = (int)&tile_at_city_or_null - ((int)cursor + 5); + *cursor++ = 0xE8; // call + cursor = int_to_bytes (cursor, call_offset); + } else + restore_code_area (ADDR_HOUSEBOAT_BUG_PATCH); + } + + // NoRaze + WITH_MEM_PROTECTION (ADDR_AUTORAZE_BYPASS, 2, PAGE_EXECUTE_READWRITE) { + byte normal[2] = {0x0F, 0x85}; // jnz + byte bypass[2] = {0x90, 0xE9}; // nop, jmp + for (int n = 0; n < 2; n++) + ((byte *)ADDR_AUTORAZE_BYPASS)[n] = cfg->prevent_autorazing ? bypass[n] : normal[n]; + } + + // Overwrite the instruction(s) where the AI's production choosing code compares the value of what it's currently considering to the best + // option so far. This is done twice since improvements and units are handled in separate loops. The instr(s) are overwritten with a jump to + // an "airlock", which is a bit of code that wraps the call to intercept_consideration. The contents of the airlocks are prepared by the + // patcher in init_consideration_airlocks. + // TODO: This instruction replacement could be done in the patcher too and that might be a better place for it. Think about this. + for (int n = 0; n < 2; n++) { + void * addr_intercept = (n == 0) ? ADDR_INTERCEPT_AI_IMPROV_VALUE : ADDR_INTERCEPT_AI_UNIT_VALUE; + void * addr_airlock = (n == 0) ? ADDR_IMPROV_CONSIDERATION_AIRLOCK : ADDR_UNIT_CONSIDERATION_AIRLOCK; + + WITH_MEM_PROTECTION (addr_intercept, AI_CONSIDERATION_INTERCEPT_LEN, PAGE_EXECUTE_READWRITE) { + byte * cursor = addr_intercept; + + // write jump to airlock + *cursor++ = 0xE9; + int offset = (int)addr_airlock - ((int)addr_intercept + 5); + cursor = int_to_bytes (cursor, offset); + + // fill the rest of the space with NOPs + while (cursor < (byte *)addr_intercept + AI_CONSIDERATION_INTERCEPT_LEN) + *cursor++ = 0x90; // nop + } + } + + // Overwrite instruction that sets bits in City.Body.Available_Resources with a jump to the airlock + WITH_MEM_PROTECTION (ADDR_INTERCEPT_SET_RESOURCE_BIT, 6, PAGE_EXECUTE_READWRITE) { + byte * cursor = ADDR_INTERCEPT_SET_RESOURCE_BIT; + if (cfg->patch_phantom_resource_bug) { + *cursor++ = 0xE9; + int offset = (int)ADDR_SET_RESOURCE_BIT_AIRLOCK - ((int)ADDR_INTERCEPT_SET_RESOURCE_BIT + 5); + cursor = int_to_bytes (cursor, offset); + *cursor++ = 0x90; // nop + } else { + byte original[6] = {0x09, 0xB0, 0x9C, 0x00, 0x00, 0x00}; // or dword ptr [eax+0x9C], esi + for (int n = 0; n < 6; n++) + cursor[n] = original[n]; + } + } + + // Enlarge the mask that's applied to p_bic_data->Map.TileCount in the loop over lines in Trade_Net::recompute_resources. This lets us loop + // over more than 0xFFFF tiles. + WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_MASK, 1, PAGE_EXECUTE_READWRITE) { + *(byte *)ADDR_RESOURCE_TILE_COUNT_MASK = (cfg->count_mills > 0) ? 0xFF : 0x00; + } + // Similarly, enlarge the cmp instruction that jumps over the entire loop when the tile count is zero. Do this by simply removing the operand + // override prefix byte (0x66), overwriting it with a nop (0x90). This converts the instruction "cmp word ptr [bic_data.Map.TileCount], di" + // into "nop; cmp dword ptr [bic_data.Map.TileCount], edi" + WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE, 1, PAGE_EXECUTE_READWRITE) { + *(byte *)ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE = 0x90; + } + + byte * addr_turn_metalimits[] = {ADDR_TURN_METALIMIT_1, ADDR_TURN_METALIMIT_2, ADDR_TURN_METALIMIT_3, ADDR_TURN_METALIMIT_4, + ADDR_TURN_METALIMIT_5, ADDR_TURN_METALIMIT_6, ADDR_TURN_METALIMIT_7}; + for (int n = 0; n < ARRAY_LEN (addr_turn_metalimits); n++) { + byte * addr = addr_turn_metalimits[n]; + WITH_MEM_PROTECTION (addr, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (addr, cfg->remove_cap_on_turn_limit ? 1000000 : 1000); + } + } + + // Overwrite the human-ness test and call to Leader::ai_adjust_sliders that happens during the preproduction player update method. The new + // code calls adjust_sliders_preproduction for all players. + WITH_MEM_PROTECTION (ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT, 9, PAGE_EXECUTE_READWRITE) { + byte * cursor = ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT; + *cursor++ = 0x8B; *cursor++ = 0xCE; // mov ecx, esi + cursor = emit_branch (BK_CALL, cursor, adjust_sliders_preproduction); + for (; cursor < ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT + 9; cursor++) + *cursor = 0x90; // nop + } + + // Set up a special intercept of the base game's calls to print_int in order to grab a pointer to a gold TradeOffer object being modified. The + // calls to print_int happen in the context of creating the default text to be placed in the set-gold-amount popup. Conveniently, a pointer to + // the TradeOffer object is always stored in register ecx when this call happens. It's not easily accessible since print_int uses the cdecl + // convention so we must use an airlock-like thing to effectively convert the calling convention to fastcall. The first part of this code + // simply replaces the call to print_int with a call to the airlock-like thing, and the second part initializes its contents. + byte * addr_print_gold_amounts[] = {ADDR_PRINT_GOLD_AMOUNT_1, ADDR_PRINT_GOLD_AMOUNT_2}; + for (int n = 0; n < ARRAY_LEN (addr_print_gold_amounts); n++) { + byte * addr = addr_print_gold_amounts[n]; + WITH_MEM_PROTECTION (addr, 5, PAGE_EXECUTE_READWRITE) + emit_branch (BK_CALL, addr, ADDR_CAPTURE_MODIFIED_GOLD_TRADE); + } + WITH_MEM_PROTECTION (ADDR_CAPTURE_MODIFIED_GOLD_TRADE, 32, PAGE_EXECUTE_READWRITE) { + byte * cursor = ADDR_CAPTURE_MODIFIED_GOLD_TRADE; + + // Repush all of the arguments to print_int onto the stack, they will be consumed by do_capture_modified_gold_trade since it's + // fastcall. The original args don't need to be removed b/c we're replacing a cdecl function so that's the caller's + // responsibility. The TradeOffer pointer is already in ECX, so that's fine as long as we don't touch that register. + byte repush[] = {0xFF, 0x74, 0x24, 0x0C}; // push [esp+0xC] + for (int n = 0; n < 3; n++) + for (int k = 0; k < ARRAY_LEN (repush); k++) + *cursor++ = repush[k]; + + cursor = emit_branch (BK_CALL, cursor, do_capture_modified_gold_trade); // call do_capture_modified_gold_trade + *cursor++ = 0xC3; // ret + } + + // Edit branch in capture_city to never run code for barbs, this allows barbs to capture cities + WITH_MEM_PROTECTION (ADDR_CAPTURE_CITY_BARB_BRANCH, 2, PAGE_EXECUTE_READWRITE) { + byte normal[2] = {0x0F, 0x85}; // jnz + byte bypass[2] = {0x90, 0xE9}; // nop, jmp + for (int n = 0; n < 2; n++) + ((byte *)ADDR_CAPTURE_CITY_BARB_BRANCH)[n] = cfg->enable_city_capture_by_barbarians ? bypass[n] : normal[n]; + } + + // After the production phase is done for the barb player, there are two jump instructions skipping the production code for civs. Replacing + // those jumps lets us run the civ production code for the barbs as well. + WITH_MEM_PROTECTION (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, PAGE_EXECUTE_READWRITE) { + if (cfg->enable_city_capture_by_barbarians) { + save_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, true); + byte jump_to_civ[6] = {0x0F, 0x8D, 0x0C, 0x00, 0x00, 0x00}; // jge +0x12 + for (int n = 0; n < 6; n++) + ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP[n] = jump_to_civ[n]; + } else + restore_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP); + } + set_nopification (cfg->enable_city_capture_by_barbarians, ADDR_PROD_PHASE_BARB_DONE_JUMP, 5); + + for (int domain = 0; domain < 2; domain++) { + byte * addr_skip = (domain == 0) ? ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC : ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC, + * addr_airlock = (domain == 0) ? ADDR_SEA_ZOC_FILTER_AIRLOCK : ADDR_LAND_ZOC_FILTER_AIRLOCK; + + WITH_MEM_PROTECTION (addr_skip, 6, PAGE_EXECUTE_READWRITE) { + if ((cfg->special_zone_of_control_rules != 0) && ! is_code_area_saved (addr_skip)) { + byte * original_target = addr_skip + 6 + int_from_bytes (addr_skip + 2); // target addr of jump instr we're replacing + save_code_area (addr_skip, 6, true); + + // Initialize airlock. The airlock preserves all registers and calls filter_zoc_candidate then either follows or skips the + // original jump depending on what it returns. If zero is returned, follows the jump, skipping a bunch of code and filtering + // out the unit as a candidate for ZoC. + WITH_MEM_PROTECTION (addr_airlock, INLEAD_SIZE, PAGE_READWRITE) { + byte * cursor = addr_airlock; + *cursor++ = 0x60; // pusha + *cursor++ = 0x54; // push esp + cursor = emit_branch (BK_CALL, cursor, filter_zoc_candidate); + *cursor++ = 0x83; *cursor++ = 0xF8; *cursor++ = 0x01; // cmp eax, 1 + *cursor++ = 0x75; *cursor++ = 0x06; // jne 6 + *cursor++ = 0x61; // popa + cursor = emit_branch (BK_JUMP, cursor, addr_skip + 6); + *cursor++ = 0x61; // popa + cursor = emit_branch (BK_JUMP, cursor, original_target); + } + + // Write jump to airlock + emit_branch (BK_JUMP, addr_skip, addr_airlock); + } else if (cfg->special_zone_of_control_rules == 0) + restore_code_area (addr_skip); + } + } + + set_nopification ( cfg->special_zone_of_control_rules != 0, ADDR_ZOC_CHECK_ATTACKER_ANIM_FIELD_111, 6); + set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_LAND_UNIT , 6); + set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_SEA_UNIT , 6); + + WITH_MEM_PROTECTION (ADDR_LUXURY_BOX_ROW_HEIGHT, 4, PAGE_EXECUTE_READWRITE) { + byte normal [4] = {0x8B, 0x44, 0x24, LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET}; // mov eax, dword ptr [esp + LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET] + byte compact[4] = {0x31, 0xC0, 0xB0, 0x10}; // xor eax, eax; mov al, 0x10 + for (int n = 0; n < 4; n++) + ADDR_LUXURY_BOX_ROW_HEIGHT[n] = cfg->compact_luxury_display_on_city_screen ? compact[n] : normal[n]; + } + + WITH_MEM_PROTECTION (ADDR_MOST_STRAT_RES_ON_CITY_SCREEN, 1, PAGE_EXECUTE_READWRITE) { + *(byte *)ADDR_MOST_STRAT_RES_ON_CITY_SCREEN = cfg->compact_strategic_resource_display_on_city_screen ? 13 : 8; + } + + // Remove a check that a returned neighbor index is within the 21 tile work area in code related to hoving the mouse over the work area on the + // city screen. This check is redundant and could be removed always, but only do so if work area is expanded. + set_nopification (cfg->city_work_radius > 2, ADDR_REDUNDANT_CHECK_ON_WORK_AREA_HOVER, 6); + + // Skip redundant check of clicked tile's neighbor index in City_Form::handle_left_click. + WITH_MEM_PROTECTION (ADDR_CITY_FORM_LEFT_CLICK_JUMP, 1, PAGE_EXECUTE_READWRITE) { + *ADDR_CITY_FORM_LEFT_CLICK_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) + } + + // Skip check that neighbor index passed to City::controls_tile is within work radius. This check is now implemented in the patch func. + WITH_MEM_PROTECTION (ADDR_CONTROLS_TILE_JUMP, 1, PAGE_EXECUTE_READWRITE) { + *ADDR_CONTROLS_TILE_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) + } + + // When searching for a tile on which to spawn pollution, the game wraps its search around by using remainder after division. Here, we replace + // the dividend to match a potentially expanded city work area. + WITH_MEM_PROTECTION (ADDR_SPAWN_POLLUTION_MOD, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_SPAWN_POLLUTION_MOD, is->workable_tile_count - 1); + } + + WITH_MEM_PROTECTION (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, cfg->patch_premature_truncation_of_found_paths ? 2560 : 256); + } + + int * trade_net_addrs; + bool already_moved_trade_net = is->trade_net != p_original_trade_net, + want_moved_trade_net = cfg->city_limit > 512; + int lifted_city_limit_exp = 11; + int lifted_city_limit = 1 << lifted_city_limit_exp; + if ((! at_program_start) && + ((trade_net_addrs = load_trade_net_addrs ()) != NULL) && + ((already_moved_trade_net && ! want_moved_trade_net) || (want_moved_trade_net && ! already_moved_trade_net))) { + // Allocate a new trade net object if necessary. To construct it, all we have to do is zero a few fields and set the vptr. Otherwise, + // set the allocated object aside for deletion later. Also set new & old addresses to the locations we're moving to & from. + Trade_Net * to_free = NULL; + int p_old, p_new; + if (want_moved_trade_net) { + is->trade_net = calloc (1, (sizeof (Trade_Net)) - (4 * 512 * 512) + (4 * lifted_city_limit * lifted_city_limit)); + is->city_limit = lifted_city_limit; + is->trade_net->vtable = p_original_trade_net->vtable; + p_old = (int)p_original_trade_net; + p_new = (int)is->trade_net; + } else { + to_free = is->trade_net; + is->city_limit = 512; + p_old = (int)is->trade_net; + p_new = (int)p_original_trade_net; + is->trade_net = p_original_trade_net; + } + already_moved_trade_net = is->trade_net != p_original_trade_net; // Keep this variable up to date + + // Patch all references from the "old" object to the "new" one + int offset; + bool popped_up_error = false; + char err_msg[200] = {0}; + int * refs; { + if (exe_version_index == 0) + refs = trade_net_addrs; + else if (exe_version_index == 1) // Steam version, skip refs and instructions for GOG + refs = &trade_net_addrs[TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; + else // PCGames.de version, skip two sets of refs and instrs for GOG & Steam + refs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; + } + for (int n_ref = 0; n_ref < TRADE_NET_REF_COUNT; n_ref++) { + int addr = refs[n_ref]; + WITH_MEM_PROTECTION ((void *)(addr - 10), 20, PAGE_EXECUTE_READWRITE) { + byte * instr = (byte *)addr; + if ((instr[0] == 0xB9) && (int_from_bytes (&instr[1]) == p_old)) // move trade net ptr to ecx + int_to_bytes (&instr[1], p_new); + else if ((instr[0] == 0xC7) && (instr[1] == 0x05) && (int_from_bytes (&instr[2]) == p_old)) // write trade net vtable ptr + int_to_bytes (&instr[2], p_new); + else if ((instr[0] == 0x81) && (instr[1] == 0xFE) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp esi, trade net location + ; // Do not patch this location because it's the upper limit for a memcpy + else if ((instr[0] == 0x81) && (instr[1] == 0xFF) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp edi, trade net location + ; // Same + else if ((instr[0] == 0x81) && (instr[1] == 0xFA) && (int_from_bytes (&instr[2]) == (int)&p_original_trade_net->Data2)) // cmp edx, trade net data2 location + ; // Same + else if (((instr[0] == 0xA3) || (instr[0] == 0xA1)) && // move eax to field or vice-versa + (offset = int_from_bytes (&instr[1]) - p_old, (offset >= 0) && (offset < 100))) + int_to_bytes (&instr[1], p_new + offset); + else if ((instr[0] == 0x89) && ((instr[1] >= 0x0D) && (instr[1] <= 0x3D)) && // move other regs to field + (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) + int_to_bytes (&instr[2], p_new + offset); + else if ((instr[0] == 0x8B) && ((instr[1] == 0x35) || (instr[1] == 0x3D) || (instr[1] == 0x0D)) && // mov field to esi, edi or ecx + (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) + int_to_bytes (&instr[2], p_new + offset); + else if (! popped_up_error) { + snprintf (err_msg, (sizeof err_msg) - 1, "Can't move trade net object from address 0x%x. Pattern doesn't match.", addr); + MessageBox (NULL, err_msg, NULL, MB_ICONERROR); + popped_up_error = true; + } + } + } + + // Patch all instructions that involve the stride of Trade_Net.Matrix + int * addrs, addr_count; { + if (exe_version_index == 0) { + addrs = &trade_net_addrs[TRADE_NET_REF_COUNT]; + addr_count = TRADE_NET_INSTR_COUNT_GOG; + } else if (exe_version_index == 1) { + addrs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; + addr_count = TRADE_NET_INSTR_COUNT_STEAM; + } else { + addrs = &trade_net_addrs[3 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; + addr_count = TRADE_NET_INSTR_COUNT_GOG; + } + for (int n = 0; n < addr_count; n++) { + byte * instr = (byte *)addrs[n]; + WITH_MEM_PROTECTION (instr, 10, PAGE_EXECUTE_READWRITE) { + if (! want_moved_trade_net) + restore_code_area (instr); + + else { + if ((instr[0] == 0xC1) && (instr[1] >= 0xE0) && (instr[1] <= 0xE7)) { // shl + save_code_area (instr, 3, false); + // shift amount is either 9 (1<<9 == 512) or 11 (1<<11 == 4*512, stride in bytes) + // in the second case, replace with lifted_exp + 2 to convert to bytes + instr[2] = lifted_city_limit_exp + ((instr[2] == 11) ? 2 : 0); + + } else if ((instr[0] == 0x81) && (instr[1] >= 0xC0) && (instr[1] <= 0xC7)) { // add + save_code_area (instr, 6, false); + int amount = int_from_bytes (&instr[2]); + // amount is either 512 or 4*512, replace with lifted_lim or 4*lifted_lim + int_to_bytes (&instr[2], (amount == 512) ? lifted_city_limit : 4*lifted_city_limit); + + } else if ((instr[0] == 0x8D) && (instr[1] == 0x9C) && (instr[2] == 0x90)) { // lea + save_code_area (instr, 7, false); + int offset = 4 * lifted_city_limit + 0x38; // stride in bytes plus 0x38 offset to Matrix in Trade_Net object + int_to_bytes (&instr[3], offset); + + } else if (instr[0] == 0xB9) { // mov + save_code_area (instr, 5, false); + int_to_bytes (&instr[1], lifted_city_limit * lifted_city_limit); + + } else if (! popped_up_error) { + snprintf (err_msg, (sizeof err_msg) - 1, "Can't patch matrix stride at address 0x%x. Pattern doesn't match.", (int)instr); + MessageBox (NULL, err_msg, NULL, MB_ICONERROR); + popped_up_error = true; + } + } + } + } + } + + // Reallocate diplo_form->tradable_cities array so it matches the city limit + civ_prog_free (p_diplo_form->tradable_cities); + int tradable_cities_len = want_moved_trade_net ? lifted_city_limit : 512, + tradable_cities_size = tradable_cities_len * sizeof (TradableItem); + p_diplo_form->tradable_cities = new (tradable_cities_size); + for (int n = 0; n < tradable_cities_len; n++) + p_diplo_form->tradable_cities[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 + + // Patch the size limit on some code that clears the tradable cities array when starting a new game + WITH_MEM_PROTECTION (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, tradable_cities_size); + } + + if (to_free) { + to_free->vtable->destruct (to_free, __, 0); + free (to_free); + } + } + + // Set is->city_limit and patch two instructions that contain the limit + is->city_limit = clamp (0, already_moved_trade_net ? lifted_city_limit : 512, cfg->city_limit); + WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN, 6, PAGE_EXECUTE_READWRITE) { + int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN[2], is->city_limit); + } + WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CREATE_CITY, 5, PAGE_EXECUTE_READWRITE) { + int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CREATE_CITY[1], is->city_limit); + } + WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_CITY_ID, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_MAX_TRADABLE_CITY_ID, already_moved_trade_net ? lifted_city_limit : 512); + } + + WITH_MEM_PROTECTION (ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR, 6, PAGE_EXECUTE_READWRITE) { + byte * instr = ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR; + if (cfg->years_to_double_building_culture == 1000) + restore_code_area (instr); + else { + if (instr[0] == 0x3D) { // in GOG and PCG EXEs, instr is cmp eax, 0x3E8 + save_code_area (instr, 5, false); + int_to_bytes (&instr[1], cfg->years_to_double_building_culture); + } else if (instr[0] == 0x3B) { // in Steam EXE, instr is cmp eax, dword ptr 0x688C9C + save_code_area (instr, 6, true); + instr[0] = 0x3D; + int_to_bytes (&instr[1], cfg->years_to_double_building_culture); + } + } + } + + WITH_MEM_PROTECTION (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, PAGE_EXECUTE_READWRITE) { + if (cfg->accentuate_cities_on_minimap) { + save_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, false); + emit_branch (BK_JUMP, ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL); + } else + restore_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT); + } + WITH_MEM_PROTECTION (ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { + byte * code = ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL; + code[0] = 0x55; code[1] = 0x53; // write push ebp and push ebx, two overwritten instrs before the call + emit_branch (BK_CALL, &code[2], &patch_get_pixel_to_draw_city_dot); // call patch func + emit_branch (BK_JUMP, &code[7], ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT + 5); // jump back to original code + } + + // Bypass adjacent resource of different type check + // replacing 0x7D (= jge) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9 = cfg->allow_adjacent_resources_of_different_types ? 0xEB : 0x7D; + + WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, PAGE_EXECUTE_READWRITE) { + if (cfg->tiles_per_non_luxury_resource == 32) + restore_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV); + else { + save_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, true); + + // Jump to replacement division logic, kept in an inlead because it doesn't fit in 7 bytes + emit_branch (BK_JUMP, ADDR_RESOURCE_GEN_TILE_COUNT_DIV, ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL); + + // Fill in the replacement division logic. Instead of computing tile_count>>5, compute tile_count/cfg->tiles_per_non_luxury_resource. + WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { + int d = not_below (1, cfg->tiles_per_non_luxury_resource); + byte d0 = d & 0xFF, + d1 = (d >> 8) & 0xFF, + d2 = (d >> 16) & 0xFF, + d3 = d >> 24; + + byte * cursor = ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL; + + // In the Steam EXE, the limit (tile_count/32 by default) must be left in ecx. For the other EXEs, edx. + if (exe_version_index == 1) { + byte new_div[] = { + 0x50, // push eax + 0x52, // push edx + 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count + 0x0F, 0xB7, 0xD2, // movzx edx, dx + 0x89, 0xD0, // mov eax, edx + 0x31, 0xD2, // xor edx, edx + 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} + 0xF7, 0xF1, // div ecx + 0x89, 0xC1, // mov ecx, eax + 0x5A, // pop edx + 0x58 // pop eax + }; + for (int n = 0; n < ARRAY_LEN (new_div); n++) + *cursor++ = new_div[n]; + + } else { + byte new_div[] = { + 0x50, // push eax + 0x51, // push ecx + 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count + 0x0F, 0xB7, 0xD2, // movzx edx, dx + 0x89, 0xD0, // mov eax, edx + 0x31, 0xD2, // xor edx, edx + 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} + 0xF7, 0xF1, // div ecx + 0x89, 0xC2, // mov edx, eax + 0x59, // pop ecx + 0x58 // pop eax + }; + for (int n = 0; n < ARRAY_LEN (new_div); n++) + *cursor++ = new_div[n]; + } + + cursor = emit_branch (BK_JUMP, cursor, ADDR_RESOURCE_GEN_TILE_COUNT_DIV + 7); + } + } + } + + // Disable a jump that skips playing victory animations for air units if they've been configured to have a victory anim + set_nopification (cfg->aircraft_victory_animation != NULL, ADDR_SKIP_VICTORY_ANIM_IF_AIR, 6); + + // Bypass capital check to return zero corruption + // replacing 0x75 (= jnz) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_CORRUPTION_CAPITAL_CHECK, 1, PAGE_EXECUTE_READWRITE) + *ADDR_CORRUPTION_CAPITAL_CHECK = cfg->allow_corruption_in_capital ? 0xEB : 0x75; + + // Insert amount added to building decorruption effect just for the capital + WITH_MEM_PROTECTION (ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT, 3, PAGE_EXECUTE_READWRITE) + *(ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT + 2) = clamp (0, 100, cfg->special_capital_decorruption_effect); +} + +void +get_mod_art_path (char const * file_name, char * out_path, int path_buf_size) +{ + char s[1000]; + snprintf (s, sizeof s, "Art\\%s", file_name); + s[(sizeof s) - 1] = '\0'; + + char * scenario_path = BIC_get_asset_path (p_bic_data, __, s, false); + if (0 != strcmp (scenario_path, s)) // get_asset_path returns its input when the file is not found + snprintf (out_path, path_buf_size, "%s", scenario_path); + else + snprintf (out_path, path_buf_size, "%s\\Art\\%s", is->mod_rel_dir, file_name); + out_path[path_buf_size - 1] = '\0'; +} + + +Sprite* +SpriteList_at(SpriteList *list, int i) { + return &list->field_0[i]; +} + +void +set_path(String260 *dst, const char *p) { + snprintf(dst->S, sizeof(dst->S), "%s", p); +} + +void +slice_grid(Sprite *out, PCX_Image *img, + int tile_w, int tile_h, int full_w, int full_h) +{ + for (int y = 0; y < full_h; y += tile_h) + for (int x = 0; x < full_w; x += tile_w) + Sprite_slice_pcx(out++, __, img, x, y, tile_w, tile_h, 1, 1); +} + +void +slice_grid_into_list(SpriteList *bucket, PCX_Image *img, + int tile_w, int tile_h, int full_w, int full_h) +{ + int k = 0; + for (int y = 0; y < full_h; y += tile_h) + for (int x = 0; x < full_w; x += tile_w) + Sprite_slice_pcx(SpriteList_at(bucket, k++), __, img, x, y, tile_w, tile_h, 1, 1); +} + +void +join_path(char *out, size_t out_sz, const char *dir, const char *file) +{ + size_t n = strlen(dir); + int need_sep = (n > 0 && dir[n-1] != '/' && dir[n-1] != '\\'); + snprintf(out, out_sz, "%s%s%s", dir, need_sep ? "\\" : "", file); +} + +void +read_in_dir(PCX_Image *img, + const char *art_dir, + const char *filename, + String260 *store) { + char pbuf[512]; + join_path(pbuf, sizeof pbuf, art_dir, filename); + if (store) { + // assumes: typedef struct { char S[260]; } String260; + snprintf(store->S, sizeof store->S, "%s", pbuf); + } + + char temp_path[2*MAX_PATH]; + + snprintf(temp_path, sizeof temp_path, "%s\\%s", art_dir, filename); + PCX_Image_read_file(img, __, temp_path, NULL, 0, 0x100, 2); +} + +bool load_day_night_hour_images(struct day_night_cycle_img_set *this, const char *art_dir, const char *hour) +{ + char ss[200]; + PCX_Image img; + PCX_Image_construct(&img); + + // Std terrain (9 sheets): 6x9 of 128x64 over 0x480x0x240 + const char *STD_SHEETS[9] = { + "xtgc.pcx", "xpgc.pcx", "xdgc.pcx", "xdpc.pcx", "xdgp.pcx", "xggc.pcx", + "wCSO.pcx", "wSSS.pcx", "wOOO.pcx" + }; + for (int i = 0; i < 9; ++i) { + read_in_dir(&img, art_dir, STD_SHEETS[i], NULL); + if (img.JGL.Image == NULL) return false; + slice_grid_into_list(&this->Std_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); + } + + // LM terrain (9): same slicing + const char *LMT_SHEETS[9] = { + "lxtgc.pcx", "lxpgc.pcx", "lxdgc.pcx", "lxdpc.pcx", "lxdgp.pcx", "lxggc.pcx", + "lwCSO.pcx", "lwSSS.pcx", "lwOOO.pcx" + }; + for (int i = 0; i < 9; ++i) { + read_in_dir(&img, art_dir, LMT_SHEETS[i], NULL); + if (img.JGL.Image == NULL) return false; + slice_grid_into_list(&this->LM_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); + } + + // Polar icecaps: 8x4 of 128x64 + read_in_dir(&img, art_dir, "polarICEcaps-final.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Polar_Icecaps_Images, &img, 0x80, 0x40, 0x400, 0x100); + + // Hills / LM Hills: 4x3 of 128x72 + read_in_dir(&img, art_dir, "xhills.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); + read_in_dir(&img, art_dir, "hill forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Hills_Forests_Images, &img, 0x80, 0x48, 0x200, 0x120); + read_in_dir(&img, art_dir, "hill jungle.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Hills_Jungle_Images, &img, 0x80, 0x48, 0x200, 0x120); + read_in_dir(&img, art_dir, "LMHills.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->LM_Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); + + // Flood plains: 4x4 of 128x64 + read_in_dir(&img, art_dir, "floodplains.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Flood_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); + + // Delta + Mountain rivers: 4x4 each, interleaved across one contiguous block + { + const char *RIV_SHEETS[2] = { "deltaRivers.pcx", "mtnRivers.pcx" }; + Sprite *contig = this->Delta_Rivers_Images; // Mountain_Rivers_Images follows + for (int s = 0; s < 2; ++s) { + read_in_dir(&img, art_dir, RIV_SHEETS[s], NULL); + if (img.JGL.Image == NULL) return false; + Sprite *p = contig + s; // even=delta, odd=mountain + for (int y = 0; y < 0x100; y += 0x40) + for (int x = 0; x < 0x200; x += 0x80) { + Sprite_slice_pcx(p, __, &img, x, y, 0x80, 0x40, 1, 1); + p += 2; + } + } + } + + // Waterfalls: 4x1 of 128x64 + read_in_dir(&img, art_dir, "waterfalls.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Waterfalls_Images, &img, 0x80, 0x40, 0x200, 0x40); + + // Irrigation (desert/plains/normal/tundra): each 4x4 of 128x64 + read_in_dir(&img, art_dir, "irrigation DESETT.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Desert_Images, &img, 0x80, 0x40, 0x200, 0x100); + read_in_dir(&img, art_dir, "irrigation PLAINS.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); + read_in_dir(&img, art_dir, "irrigation.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Images, &img, 0x80, 0x40, 0x200, 0x100); + read_in_dir(&img, art_dir, "irrigation TUNDRA.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Tundra_Images, &img, 0x80, 0x40, 0x200, 0x100); + + // Volcanos (plain/forests/jungles/snow): 4x4 of 128x88 + read_in_dir(&img, art_dir, "Volcanos.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Volcanos forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Volcanos jungles.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Volcanos-snow.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); + + // Marsh: Large band then Small band (tiles 128x88) + read_in_dir(&img, art_dir, "marsh.pcx", NULL); + if (img.JGL.Image == NULL) return false; + // Large (2 rows, 4 cols) + { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Marsh_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + // Small (2 rows, 5 cols) + { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Marsh_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + // LM mountains + standard mountains (plain/forests/jungles/snow): 4x4 of 128x88 + read_in_dir(&img, art_dir, "LMMountains.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->LM_Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Mountains.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "mountain forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "mountain jungles.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Mountains-snow.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); + + // Roads (16x16) and Railroads (16x17), tiles 128x64 + read_in_dir(&img, art_dir, "roads.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Roads_Images, &img, 0x80, 0x40, 0x800, 0x400); + read_in_dir(&img, art_dir, "railroads.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Railroads_Images, &img, 0x80, 0x40, 0x800, 0x440); + + // LM Forests (Large 2x4, Small 2x6, Pines 2x6), tiles 128x88 + read_in_dir(&img, art_dir, "LMForests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->LM_Forests_Large_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->LM_Forests_Small_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->LM_Forests_Pines_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + // Grassland/Plains/Tundra forests & jungles (bands; tiles 128x88) — order is important + read_in_dir(&img, art_dir, "grassland forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + // Jungles Large, Small + { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Jungles_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Jungles_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + // Forests Large, Small, Pines + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + read_in_dir(&img, art_dir, "plains forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Plains_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Plains_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Plains_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + read_in_dir(&img, art_dir, "tundra forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Tundra_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Tundra_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Tundra_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + // LM Terrain (7 single 128x64, vertical strip) + read_in_dir(&img, art_dir, "landmark_terrain.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i = 0, y = 0; i < 7; ++i, y += 0x40) + Sprite_slice_pcx(&this->LM_Terrain[i], __, &img, 0, y, 0x80, 0x40, 1, 1); + + // TNT (same odd ordering as original) + read_in_dir(&img, art_dir, "tnt.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[6+i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[9+i], __, &img, x, 0x40, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[12+i], __, &img, x, 0x80, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[0+i], __, &img, x, 0xC0, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[15+i], __, &img, x, 0x100, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[3+i], __, &img, x, 0x140, 0x80, 0x40, 1, 1); + + // Goody huts: 8 tiles, x=(i%3)*0x80, y=(i/3)*0x40 + read_in_dir(&img, art_dir, "goodyhuts.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i = 0; i < 8; ++i) { + int x = (i % 3) << 7; + int y = (i / 3) << 6; + Sprite_slice_pcx(&this->Goody_Huts_Images[i], __, &img, x, y, 0x80, 0x40, 1, 1); + } + + // Terrain buildings (fortress/camp/barbarian camp/mines/barricade) + read_in_dir(&img, art_dir, "TerrainBuildings.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Fortress[i], __, &img, 0x00, y, 0x80, 0x40, 1, 1); + for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Camp[i], __, &img, 0x80, y, 0x80, 0x40, 1, 1); + Sprite_slice_pcx(&this->Terrain_Buldings_Barbarian_Camp, __, &img, 0x100, 0x00, 0x80, 0x40, 1, 1); + Sprite_slice_pcx(&this->Terrain_Buldings_Mines, __, &img, 0x100, 0x40, 0x80, 0x40, 1, 1); + for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Barricade[i], __, &img, 0x180, y, 0x80, 0x40, 1, 1); + + // Pollution & Craters (5x5 of 128x64) + read_in_dir(&img, art_dir, "pollution.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Pollution, &img, 0x80, 0x40, 0x280, 0x140); + read_in_dir(&img, art_dir, "craters.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Craters, &img, 0x80, 0x40, 0x280, 0x140); + + // Airfields / Outposts / Radar + read_in_dir(&img, art_dir, "x_airfields and detect.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i=0, x=0; i<2; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Airfields[i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Outposts[i], __, &img, x, 0x40, 0x80, 0x80, 1, 1); + Sprite_slice_pcx(&this->Terrain_Buldings_Radar, __, &img, 0x00, 0xC0, 0x80, 0x80, 1, 1); + + // Victory (single 128x64) + read_in_dir(&img, art_dir, "x_victory.pcx", NULL); + if (img.JGL.Image == NULL) return false; + Sprite_slice_pcx(&this->Victory_Image, __, &img, 0, 0, 0x80, 0x40, 1, 1); + + // Resources + read_in_dir(&img, art_dir, "resources.pcx", NULL); + if (img.JGL.Image == NULL) return false; + size_t k = 0; + for (int r = 0, y = 1; r < 6; ++r, y += 50) { + for (int c = 0, x = 1; c < 6; ++c, x += 50) { + Sprite_slice_pcx(&this->Resources[k++], __, &img, x, y, 49, 49, 1, 1); + } + } + + // Base cities + static const char *CITY_BASE[5] = { + "rAMER.pcx", "rEURO.pcx", "rROMAN.pcx", "rMIDEAST.pcx", "rASIAN.pcx" + }; + for (int culture = 0; culture < 5; culture++) { + read_in_dir(&img, art_dir, CITY_BASE[culture], NULL); + if (img.JGL.Image == NULL) return false; + int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; + int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; + int y = 0; + for (int era = 0; era < 4; ++era, y += sprite_h) { + int x = 0; + for (int size = 0; size < 3; ++size, x += sprite_w) { + const int idx = culture + 5*era + 20*size; + Sprite_slice_pcx(&this->City_Images[idx], __, &img, x, y, sprite_w, sprite_h, 1, 1); + } + } + } + + // Walled cities + static const char *CITY_WALL[5] = { + "AMERWALL.pcx", "EUROWALL.pcx", "ROMANWALL.pcx", "MIDEASTWALL.pcx", "ASIANWALL.pcx" + }; + for (int culture = 0; culture < 5; ++culture) { + read_in_dir(&img, art_dir, CITY_WALL[culture], NULL); + if (img.JGL.Image == NULL) return false; + int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image); + int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; + int y = 0; + for (int era = 0; era < 4; ++era, y += sprite_h) { + const int size = 3; // walled towns are a special category + const int idx = culture + 5*era + 20*size; + Sprite_slice_pcx(&this->City_Images[idx], __, &img, 0, y, sprite_w, sprite_h, 1, 1); + } + } + + // Destroyed cities + read_in_dir(&img, art_dir, "DESTROY.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { + int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; + int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image); + int x = 0; + for (int i = 0; i < 3; ++i, x += sprite_w) + Sprite_slice_pcx(&this->Destroyed_City_Images[i], __, &img, x, 0, sprite_w, sprite_h, 1, 1); + } + + // Districts (if enabled) + if (is->current_config.enable_districts) { + char art_dir[200]; + char temp_path[2*MAX_PATH]; + snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + for (int dc = 0; dc < is->district_count; dc++) { + struct district_config const * cfg = &is->district_configs[dc]; + int variant_capacity = ARRAY_LEN (this->District_Images[dc]); + int variant_count = cfg->img_path_count; + if (variant_count <= 0) + continue; + if (variant_count > variant_capacity) + variant_count = variant_capacity; + + int era_count = cfg->vary_img_by_era ? 4 : 1; + int column_count = cfg->img_column_count; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + + for (int variant_i = 0; variant_i < variant_count; variant_i++) { + const char * img_path = cfg->img_paths[variant_i]; + if ((img_path == NULL) || (img_path[0] == '\0')) + continue; + + read_in_dir (&img, temp_path, img_path, NULL); + if (img.JGL.Image == NULL) + return false; + + for (int era = 0; era < era_count; era++) { + for (int col = 0; col < column_count; col++) { + int tile_x = sprite_width * col; + int tile_y = sprite_height * era; + Sprite_slice_pcx (&this->District_Images[dc][variant_i][era][col], __, &img, tile_x, tile_y, sprite_width, sprite_height, 1, 1); + } + } + } + } + + // Abandoned district art (land + maritime) for this hour + read_in_dir (&img, temp_path, "Abandoned.pcx", NULL); + if (img.JGL.Image == NULL) + return false; + Sprite_slice_pcx (&this->Abandoned_District_Image, __, &img, 0, 0, 128, 64, 1, 1); + Sprite_slice_pcx (&this->Abandoned_Maritime_District_Image, __, &img, 128, 0, 128, 64, 1, 1); + + // Load wonder district images (dynamically per wonder) for this hour + if (is->current_config.enable_wonder_districts) { + char const * last_img_path = NULL; + PCX_Image wpcx; + PCX_Image_construct (&wpcx); + bool pcx_loaded = false; + + for (int wi = 0; wi < is->wonder_district_count; wi++) { + struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; + char const * img_path = cfg->img_path; + if (img_path == NULL) + img_path = "Wonders.pcx"; + + // Load new image file if different from previous + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + + read_in_dir (&wpcx, temp_path, img_path, NULL); + + if (wpcx.JGL.Image == NULL) { + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + struct wonder_district_image_set * set = &this->Wonder_District_Images[wi]; + + Sprite_construct (&set->img); + int x = 128 * cfg->img_column; + int y = 64 * cfg->img_row; + Sprite_slice_pcx (&set->img, __, &wpcx, x, y, 128, 64, 1, 1); + + Sprite_construct (&set->construct_img); + int cx = 128 * cfg->img_construct_column; + int cy = 64 * cfg->img_construct_row; + Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, 128, 64, 1, 1); + + if (cfg->enable_img_alt_dir) { + Sprite_construct (&set->alt_dir_img); + int ax = 128 * cfg->img_alt_dir_column; + int ay = 64 * cfg->img_alt_dir_row; + Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, 128, 64, 1, 1); + + Sprite_construct (&set->alt_dir_construct_img); + int acx = 128 * cfg->img_alt_dir_construct_column; + int acy = 64 * cfg->img_alt_dir_construct_row; + Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, 128, 64, 1, 1); + } + } + + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + wpcx.vtable->destruct (&wpcx, __, 0); + } + + } + + if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { + char art_dir[200]; + char temp_path[2*MAX_PATH]; + snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + + char const * last_img_path = NULL; + PCX_Image nwpcx; + PCX_Image_construct (&nwpcx); + bool pcx_loaded = false; + + for (int ni = 0; ni < is->natural_wonder_count; ni++) { + struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; + if ((cfg->img_path == NULL) || (cfg->img_path[0] == '\0')) + continue; + + char const * img_path = cfg->img_path; + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + + read_in_dir (&nwpcx, temp_path, img_path, NULL); + + if (nwpcx.JGL.Image == NULL) { + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + Sprite_construct (&this->Natural_Wonder_Images[ni].img); + int x = 128 * cfg->img_column; + int y = 88 * cfg->img_row; + Sprite_slice_pcx (&this->Natural_Wonder_Images[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); + } + + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + nwpcx.vtable->destruct (&nwpcx, __, 0); + } + + img.vtable->destruct (&img, __, 0); + + return true; +} + +Sprite * +get_sprite_proxy_for_current_hour(Sprite *s) { + int v; + int hour = is->current_day_night_cycle; // 0..23 + if (itable_look_up(&is->day_night_sprite_proxy_by_hour[hour], (int)s, &v)) + return (Sprite *)v; + return NULL; // not proxied, fall back to s +} + +void +insert_spritelist_proxies(SpriteList *ss, SpriteList *ps, int hour, int len1, int len2) { + for (int i = 0; i < len1; i++) { + for (int j = 0; j < len2; j++) { + Sprite *s = &ss[i].field_0[j]; + Sprite *p = &ps[i].field_0[j]; + if (s && p) { + itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); + } + } + } +} + +void +insert_sprite_proxies(Sprite *ss, Sprite *ps, int hour, int len) { + for (int i = 0; i < len; i++) { + Sprite *s = &ss[i]; + Sprite *p = &ps[i]; + if (s && p) { + itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); + } + } +} + +void +insert_sprite_proxy(Sprite *s, Sprite *p, int hour) { + if (s && p) { + itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); + } +} + +void +build_sprite_proxies_24(Map_Renderer *mr) { + for (int h = 0; h < 24; ++h) { + insert_sprite_proxies(city_sprites, is->day_night_cycle_imgs[h].City_Images, h, 80); + insert_sprite_proxies(destroyed_city_sprites, is->day_night_cycle_imgs[h].Destroyed_City_Images, h, 3); + insert_sprite_proxies(mr->Resources, is->day_night_cycle_imgs[h].Resources, h, 36); + insert_spritelist_proxies(mr->Std_Terrain_Images, is->day_night_cycle_imgs[h].Std_Terrain_Images, h, 9, 81); + insert_spritelist_proxies(mr->LM_Terrain_Images, is->day_night_cycle_imgs[h].LM_Terrain_Images, h, 9, 81); + insert_sprite_proxy(&mr->Terrain_Buldings_Barbarian_Camp, &is->day_night_cycle_imgs[h].Terrain_Buldings_Barbarian_Camp, h); + insert_sprite_proxy(&mr->Terrain_Buldings_Mines, &is->day_night_cycle_imgs[h].Terrain_Buldings_Mines, h); + insert_sprite_proxy(&mr->Victory_Image, &is->day_night_cycle_imgs[h].Victory_Image, h); + insert_sprite_proxy(&mr->Terrain_Buldings_Radar, &is->day_night_cycle_imgs[h].Terrain_Buldings_Radar, h); + insert_sprite_proxies(mr->Flood_Plains_Images, is->day_night_cycle_imgs[h].Flood_Plains_Images, h, 16); + insert_sprite_proxies(mr->Polar_Icecaps_Images, is->day_night_cycle_imgs[h].Polar_Icecaps_Images, h, 32); + insert_sprite_proxies(mr->Roads_Images, is->day_night_cycle_imgs[h].Roads_Images, h, 256); + insert_sprite_proxies(mr->Railroads_Images, is->day_night_cycle_imgs[h].Railroads_Images, h, 272); + insert_sprite_proxies(mr->Terrain_Buldings_Airfields, is->day_night_cycle_imgs[h].Terrain_Buldings_Airfields, h, 2); + insert_sprite_proxies(mr->Terrain_Buldings_Camp, is->day_night_cycle_imgs[h].Terrain_Buldings_Camp, h, 4); + insert_sprite_proxies(mr->Terrain_Buldings_Fortress, is->day_night_cycle_imgs[h].Terrain_Buldings_Fortress, h, 4); + insert_sprite_proxies(mr->Terrain_Buldings_Barricade, is->day_night_cycle_imgs[h].Terrain_Buldings_Barricade, h, 4); + insert_sprite_proxies(mr->Goody_Huts_Images, is->day_night_cycle_imgs[h].Goody_Huts_Images, h, 8); + insert_sprite_proxies(mr->Terrain_Buldings_Outposts, is->day_night_cycle_imgs[h].Terrain_Buldings_Outposts, h, 3); + insert_sprite_proxies(mr->Pollution, is->day_night_cycle_imgs[h].Pollution, h, 25); + insert_sprite_proxies(mr->Craters, is->day_night_cycle_imgs[h].Craters, h, 25); + insert_sprite_proxies(mr->Tnt_Images, is->day_night_cycle_imgs[h].Tnt_Images, h, 18); + insert_sprite_proxies(mr->Waterfalls_Images, is->day_night_cycle_imgs[h].Waterfalls_Images, h, 4); + insert_sprite_proxies(mr->LM_Terrain, is->day_night_cycle_imgs[h].LM_Terrain, h, 7); + insert_sprite_proxies(mr->Marsh_Large, is->day_night_cycle_imgs[h].Marsh_Large, h, 8); + insert_sprite_proxies(mr->Marsh_Small, is->day_night_cycle_imgs[h].Marsh_Small, h, 10); + insert_sprite_proxies(mr->Volcanos_Images, is->day_night_cycle_imgs[h].Volcanos_Images, h, 16); + insert_sprite_proxies(mr->Volcanos_Forests_Images, is->day_night_cycle_imgs[h].Volcanos_Forests_Images, h, 16); + insert_sprite_proxies(mr->Volcanos_Jungles_Images, is->day_night_cycle_imgs[h].Volcanos_Jungles_Images, h, 16); + insert_sprite_proxies(mr->Volcanos_Snow_Images, is->day_night_cycle_imgs[h].Volcanos_Snow_Images, h, 16); + insert_sprite_proxies(mr->Grassland_Forests_Large, is->day_night_cycle_imgs[h].Grassland_Forests_Large, h, 8); + insert_sprite_proxies(mr->Plains_Forests_Large, is->day_night_cycle_imgs[h].Plains_Forests_Large, h, 8); + insert_sprite_proxies(mr->Tundra_Forests_Large, is->day_night_cycle_imgs[h].Tundra_Forests_Large, h, 8); + insert_sprite_proxies(mr->Grassland_Forests_Small, is->day_night_cycle_imgs[h].Grassland_Forests_Small, h, 10); + insert_sprite_proxies(mr->Plains_Forests_Small, is->day_night_cycle_imgs[h].Plains_Forests_Small, h, 10); + insert_sprite_proxies(mr->Tundra_Forests_Small, is->day_night_cycle_imgs[h].Tundra_Forests_Small, h, 10); + insert_sprite_proxies(mr->Grassland_Forests_Pines, is->day_night_cycle_imgs[h].Grassland_Forests_Pines, h, 12); + insert_sprite_proxies(mr->Plains_Forests_Pines, is->day_night_cycle_imgs[h].Plains_Forests_Pines, h, 12); + insert_sprite_proxies(mr->Tundra_Forests_Pines, is->day_night_cycle_imgs[h].Tundra_Forests_Pines, h, 12); + insert_sprite_proxies(mr->Irrigation_Desert_Images, is->day_night_cycle_imgs[h].Irrigation_Desert_Images, h, 16); + insert_sprite_proxies(mr->Irrigation_Plains_Images, is->day_night_cycle_imgs[h].Irrigation_Plains_Images, h, 16); + insert_sprite_proxies(mr->Irrigation_Images, is->day_night_cycle_imgs[h].Irrigation_Images, h, 16); + insert_sprite_proxies(mr->Irrigation_Tundra_Images, is->day_night_cycle_imgs[h].Irrigation_Tundra_Images, h, 16); + insert_sprite_proxies(mr->Grassland_Jungles_Large, is->day_night_cycle_imgs[h].Grassland_Jungles_Large, h, 8); + insert_sprite_proxies(mr->Grassland_Jungles_Small, is->day_night_cycle_imgs[h].Grassland_Jungles_Small, h, 12); + insert_sprite_proxies(mr->Mountains_Images, is->day_night_cycle_imgs[h].Mountains_Images, h, 16); + insert_sprite_proxies(mr->Mountains_Forests_Images, is->day_night_cycle_imgs[h].Mountains_Forests_Images, h, 16); + insert_sprite_proxies(mr->Mountains_Jungles_Images, is->day_night_cycle_imgs[h].Mountains_Jungles_Images, h, 16); + insert_sprite_proxies(mr->Mountains_Snow_Images, is->day_night_cycle_imgs[h].Mountains_Snow_Images, h, 16); + insert_sprite_proxies(mr->Hills_Images, is->day_night_cycle_imgs[h].Hills_Images, h, 16); + insert_sprite_proxies(mr->Hills_Forests_Images, is->day_night_cycle_imgs[h].Hills_Forests_Images, h, 16); + insert_sprite_proxies(mr->Hills_Jungle_Images, is->day_night_cycle_imgs[h].Hills_Jungle_Images, h, 16); + insert_sprite_proxies(mr->Delta_Rivers_Images, is->day_night_cycle_imgs[h].Delta_Rivers_Images, h, 16); + insert_sprite_proxies(mr->Mountain_Rivers_Images, is->day_night_cycle_imgs[h].Mountain_Rivers_Images, h, 16); + insert_sprite_proxies(mr->LM_Mountains_Images, is->day_night_cycle_imgs[h].LM_Mountains_Images, h, 16); + insert_sprite_proxies(mr->LM_Forests_Large_Images, is->day_night_cycle_imgs[h].LM_Forests_Large_Images, h, 8); + insert_sprite_proxies(mr->LM_Forests_Small_Images, is->day_night_cycle_imgs[h].LM_Forests_Small_Images, h, 10); + insert_sprite_proxies(mr->LM_Forests_Pines_Images, is->day_night_cycle_imgs[h].LM_Forests_Pines_Images, h, 12); + insert_sprite_proxies(mr->LM_Hills_Images, is->day_night_cycle_imgs[h].LM_Hills_Images, h, 16); + + if (is->current_config.enable_districts) { + for (int dc = 0; dc < is->district_count; dc++) { + struct district_config const * cfg = &is->district_configs[dc]; + int variant_capacity = ARRAY_LEN (is->district_img_sets[dc].imgs); + int variant_count = cfg->img_path_count; + if (variant_count <= 0) + continue; + if (variant_count > variant_capacity) + variant_count = variant_capacity; + + int era_count = cfg->vary_img_by_era ? 4 : 1; + int column_count = cfg->img_column_count; + + for (int variant_i = 0; variant_i < variant_count; variant_i++) { + if ((cfg->img_paths[variant_i] == NULL) || (cfg->img_paths[variant_i][0] == '\0')) + continue; + for (int era = 0; era < era_count; era++) { + for (int col = 0; col < column_count; col++) { + Sprite * base = &is->district_img_sets[dc].imgs[variant_i][era][col]; + Sprite * proxy = &is->day_night_cycle_imgs[h].District_Images[dc][variant_i][era][col]; + insert_sprite_proxy (base, proxy, h); + } + } + } + } + + insert_sprite_proxy (&is->abandoned_district_img, &is->day_night_cycle_imgs[h].Abandoned_District_Image, h); + insert_sprite_proxy (&is->abandoned_maritime_district_img, &is->day_night_cycle_imgs[h].Abandoned_Maritime_District_Image, h); + + // Wonder districts + if (is->current_config.enable_wonder_districts) { + for (int wi = 0; wi < is->wonder_district_count; wi++) { + Sprite * base_img = &is->wonder_district_img_sets[wi].img; + Sprite * proxy_img = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].img; + insert_sprite_proxy (base_img, proxy_img, h); + + Sprite * base_construct = &is->wonder_district_img_sets[wi].construct_img; + Sprite * proxy_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].construct_img; + insert_sprite_proxy (base_construct, proxy_construct, h); + + if (is->wonder_district_img_sets[wi].alt_dir_img.vtable != NULL) { + Sprite * base_alt = &is->wonder_district_img_sets[wi].alt_dir_img; + Sprite * proxy_alt = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_img; + insert_sprite_proxy (base_alt, proxy_alt, h); + } + + if (is->wonder_district_img_sets[wi].alt_dir_construct_img.vtable != NULL) { + Sprite * base_alt_construct = &is->wonder_district_img_sets[wi].alt_dir_construct_img; + Sprite * proxy_alt_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_construct_img; + insert_sprite_proxy (base_alt_construct, proxy_alt_construct, h); + } + } + } + } + + // Natural wonders + if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { + for (int ni = 0; ni < is->natural_wonder_count; ni++) { + Sprite * base_nw = &is->natural_wonder_img_sets[ni].img; + Sprite * proxy_nw = &is->day_night_cycle_imgs[h].Natural_Wonder_Images[ni].img; + insert_sprite_proxy (base_nw, proxy_nw, h); + } + } + } + is->day_night_cycle_img_proxies_indexed = true; +} + +void +init_day_night_images() +{ + if (is->day_night_cycle_img_state != IS_UNINITED) + return; + + const char *hour_strs[24] = { + "2400", "0100", "0200", "0300", "0400", "0500", "0600", "0700", + "0800", "0900", "1000", "1100", "1200", "1300", "1400", "1500", + "1600", "1700", "1800", "1900", "2000", "2100", "2200", "2300" + }; + + for (int i = 0; i < 24; i++) { + + char art_dir[200]; + char temp_path[2*MAX_PATH]; + snprintf (art_dir, sizeof art_dir, "DayNight/%s", hour_strs[i]); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + bool success = load_day_night_hour_images (&is->day_night_cycle_imgs[i], temp_path, hour_strs[i]); + + if (!success) { + char ss[200]; + snprintf(ss, sizeof ss, "Failed to load day/night cycle images for hour %s, reverting to base game art.", hour_strs[i]); + pop_up_in_game_error (ss); + + is->day_night_cycle_img_state = IS_INIT_FAILED; + return; + } + } + + Map_Renderer * mr = &p_bic_data->Map.Renderer; + build_sprite_proxies_24(mr); + + is->day_night_cycle_img_state = IS_OK; +} + +void +deindex_day_night_image_proxies() +{ + if (!is->day_night_cycle_img_proxies_indexed) + return; + + for (int i = 0; i < 24; i++) { + table_deinit (&is->day_night_sprite_proxy_by_hour[i]); + } + is->day_night_cycle_img_proxies_indexed = false; +} + +int +calculate_current_day_night_cycle_hour () +{ + int output = 12; // Default to noon + int increment = is->current_config.fixed_hours_per_turn_for_day_night_cycle; + + switch (is->current_config.day_night_cycle_mode) { + + // Disabled. This shouldn't be possible, but default to noon to be safe + case DNCM_OFF: + return output; + + // Time elapsed since last update + case DNCM_TIMER: { + LARGE_INTEGER perf_freq; + QueryPerformanceFrequency(&perf_freq); + + if (is->day_night_cycle_unstarted) { + is->current_day_night_cycle = output; + QueryPerformanceCounter(&is->last_day_night_cycle_update_time); + } + + LARGE_INTEGER time_now; + QueryPerformanceCounter(&time_now); + + double elapsed_seconds = + (double)(time_now.QuadPart - is->last_day_night_cycle_update_time.QuadPart) / + (double)perf_freq.QuadPart; + + if (elapsed_seconds > (double)is->current_config.elapsed_minutes_per_day_night_hour_transition * 60.0) { + output = is->current_day_night_cycle + increment; + is->last_day_night_cycle_update_time = time_now; + } else { + output = is->current_day_night_cycle; + } + break; + } + + // Match user's current time + case DNCM_USER_TIME: { + LPSYSTEMTIME lpSystemTime = (LPSYSTEMTIME)malloc(sizeof(SYSTEMTIME)); + GetLocalTime (lpSystemTime); + output = lpSystemTime->wHour; + free (lpSystemTime); + break; + } + + // Increment fixed amount each interturn + case DNCM_EVERY_TURN: { + if (is->day_night_cycle_unstarted) { + increment = 0; + is->current_day_night_cycle = output; + } + output = is->current_day_night_cycle + increment; + break; + } + + // Pin the hour to a specific value + case DNCM_SPECIFIED: { + output = is->current_config.pinned_hour_for_day_night_cycle; + break; + } + } + + // If midnight or over, restart at 0 or later + if (output > 23) output = output - 24; + + // Clamp to valid range of 0-23 in case of weird config values + output = clamp (0, 23, output); + is->day_night_cycle_unstarted = false; + + return output; +} + +void __fastcall +patch_Map_Renderer_load_images (Map_Renderer *this, int edx) +{ + Map_Renderer_load_images(this, __); + + // Initialize day/night cycle and re-calculate hour, if applicable + if (is->current_config.day_night_cycle_mode != DNCM_OFF) { + is->current_day_night_cycle = calculate_current_day_night_cycle_hour (); + + if (is->day_night_cycle_img_state == IS_UNINITED) { + init_day_night_images (); + } + + if (is->day_night_cycle_img_state == IS_OK) { + + // Sprite proxies are deindexed during each load event as sprite instances (really only Resources, which are reloaded) may change. + if (!is->day_night_cycle_img_proxies_indexed) { + build_sprite_proxies_24(this); + } + } + } +} + +void +patch_init_floating_point () +{ + init_floating_point (); + + // NOTE: At this point the program is done with the CRT initialization stuff and will start calling constructors for global + // objects as soon as this function returns. This is a good place to inject code that will run at program start. + + // Specify metadata about all boolean options on the mod config. We'll use this info to set up the table of offsets (for easy parsing) and to + // fill out the base config. + struct boolean_config_option { + char * name; + bool base_val; + int offset; + } boolean_config_options[] = { + {"enable_stack_bombard" , true , offsetof (struct c3x_config, enable_stack_bombard)}, + {"enable_disorder_warning" , true , offsetof (struct c3x_config, enable_disorder_warning)}, + {"allow_stealth_attack_against_single_unit" , false, offsetof (struct c3x_config, allow_stealth_attack_against_single_unit)}, + {"show_detailed_city_production_info" , true , offsetof (struct c3x_config, show_detailed_city_production_info)}, + {"limited_railroads_work_like_fast_roads" , false, offsetof (struct c3x_config, limited_railroads_work_like_fast_roads)}, + {"exclude_cities_from_units_per_tile_limit" , false, offsetof (struct c3x_config, exclude_cities_from_units_per_tile_limit)}, + {"enable_free_buildings_from_small_wonders" , true , offsetof (struct c3x_config, enable_free_buildings_from_small_wonders)}, + {"enable_stack_unit_commands" , true , offsetof (struct c3x_config, enable_stack_unit_commands)}, + {"skip_repeated_tile_improv_replacement_asks" , true , offsetof (struct c3x_config, skip_repeated_tile_improv_replacement_asks)}, + {"autofill_best_gold_amount_when_trading" , true , offsetof (struct c3x_config, autofill_best_gold_amount_when_trading)}, + {"disallow_founding_next_to_foreign_city" , true , offsetof (struct c3x_config, disallow_founding_next_to_foreign_city)}, + {"enable_trade_screen_scroll" , true , offsetof (struct c3x_config, enable_trade_screen_scroll)}, + {"group_units_on_right_click_menu" , true , offsetof (struct c3x_config, group_units_on_right_click_menu)}, + {"gray_out_units_on_menu_with_no_remaining_moves" , true , offsetof (struct c3x_config, gray_out_units_on_menu_with_no_remaining_moves)}, + {"put_movement_icons_on_units_on_menu" , true , offsetof (struct c3x_config, put_movement_icons_on_units_on_menu)}, + {"describe_states_of_units_on_menu" , true , offsetof (struct c3x_config, describe_states_of_units_on_menu)}, + {"show_golden_age_turns_remaining" , true , offsetof (struct c3x_config, show_golden_age_turns_remaining)}, + {"show_zoc_attacks_from_mid_stack" , true , offsetof (struct c3x_config, show_zoc_attacks_from_mid_stack)}, + {"show_armies_performing_defensive_bombard" , true , offsetof (struct c3x_config, show_armies_performing_defensive_bombard)}, + {"cut_research_spending_to_avoid_bankruptcy" , true , offsetof (struct c3x_config, cut_research_spending_to_avoid_bankruptcy)}, + {"dont_pause_for_love_the_king_messages" , true , offsetof (struct c3x_config, dont_pause_for_love_the_king_messages)}, + {"reverse_specialist_order_with_shift" , true , offsetof (struct c3x_config, reverse_specialist_order_with_shift)}, + {"toggle_zoom_with_z_on_city_screen" , true , offsetof (struct c3x_config, toggle_zoom_with_z_on_city_screen)}, + {"dont_give_king_names_in_non_regicide_games" , true , offsetof (struct c3x_config, dont_give_king_names_in_non_regicide_games)}, + {"no_elvis_easter_egg" , false, offsetof (struct c3x_config, no_elvis_easter_egg)}, + {"disable_worker_automation" , false, offsetof (struct c3x_config, disable_worker_automation)}, + {"enable_land_sea_intersections" , false, offsetof (struct c3x_config, enable_land_sea_intersections)}, + {"disallow_trespassing" , false, offsetof (struct c3x_config, disallow_trespassing)}, + {"show_detailed_tile_info" , true , offsetof (struct c3x_config, show_detailed_tile_info)}, + {"warn_about_unrecognized_names" , true , offsetof (struct c3x_config, warn_about_unrecognized_names)}, + {"enable_ai_production_ranking" , true , offsetof (struct c3x_config, enable_ai_production_ranking)}, + {"enable_ai_city_location_desirability_display" , true, offsetof (struct c3x_config, enable_ai_city_location_desirability_display)}, + {"show_ai_city_location_desirability_if_settler" , false, offsetof (struct c3x_config, show_ai_city_location_desirability_if_settler)}, + {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, + {"zero_corruption_when_off" , true , offsetof (struct c3x_config, zero_corruption_when_off)}, + {"disallow_land_units_from_affecting_water_tiles" , true , offsetof (struct c3x_config, disallow_land_units_from_affecting_water_tiles)}, + {"dont_end_units_turn_after_airdrop" , false, offsetof (struct c3x_config, dont_end_units_turn_after_airdrop)}, + {"allow_airdrop_without_airport" , false, offsetof (struct c3x_config, allow_airdrop_without_airport)}, + {"enable_negative_pop_pollution" , true , offsetof (struct c3x_config, enable_negative_pop_pollution)}, + {"allow_defensive_retreat_on_water" , false, offsetof (struct c3x_config, allow_defensive_retreat_on_water)}, + {"promote_wonder_decorruption_effect" , false, offsetof (struct c3x_config, promote_wonder_decorruption_effect)}, + {"allow_military_leaders_to_hurry_wonders" , false, offsetof (struct c3x_config, allow_military_leaders_to_hurry_wonders)}, + {"aggressively_penalize_bankruptcy" , false, offsetof (struct c3x_config, aggressively_penalize_bankruptcy)}, + {"no_penalty_exception_for_agri_fresh_water_city_tiles" , false, offsetof (struct c3x_config, no_penalty_exception_for_agri_fresh_water_city_tiles)}, + {"use_offensive_artillery_ai" , true , offsetof (struct c3x_config, use_offensive_artillery_ai)}, + {"dont_escort_unflagged_units" , false, offsetof (struct c3x_config, dont_escort_unflagged_units)}, + {"replace_leader_unit_ai" , true , offsetof (struct c3x_config, replace_leader_unit_ai)}, + {"fix_ai_army_composition" , true , offsetof (struct c3x_config, fix_ai_army_composition)}, + {"enable_pop_unit_ai" , true , offsetof (struct c3x_config, enable_pop_unit_ai)}, + {"enable_caravan_unit_ai" , true , offsetof (struct c3x_config, enable_caravan_unit_ai)}, + {"remove_unit_limit" , true , offsetof (struct c3x_config, remove_unit_limit)}, + {"remove_city_improvement_limit" , true , offsetof (struct c3x_config, remove_city_improvement_limit)}, + {"remove_cap_on_turn_limit" , true , offsetof (struct c3x_config, remove_cap_on_turn_limit)}, + {"remove_era_limit" , false, offsetof (struct c3x_config, remove_era_limit)}, + {"patch_submarine_bug" , true , offsetof (struct c3x_config, patch_submarine_bug)}, + {"patch_science_age_bug" , true , offsetof (struct c3x_config, patch_science_age_bug)}, + {"patch_pedia_texture_bug" , true , offsetof (struct c3x_config, patch_pedia_texture_bug)}, + {"patch_blocked_disembark_freeze" , true , offsetof (struct c3x_config, patch_blocked_disembark_freeze)}, + {"patch_houseboat_bug" , true , offsetof (struct c3x_config, patch_houseboat_bug)}, + {"patch_intercept_lost_turn_bug" , true , offsetof (struct c3x_config, patch_intercept_lost_turn_bug)}, + {"patch_phantom_resource_bug" , true , offsetof (struct c3x_config, patch_phantom_resource_bug)}, + {"patch_maintenance_persisting_for_obsolete_buildings" , true , offsetof (struct c3x_config, patch_maintenance_persisting_for_obsolete_buildings)}, + {"patch_barbarian_diagonal_bug" , true , offsetof (struct c3x_config, patch_barbarian_diagonal_bug)}, + {"patch_disease_stopping_tech_flag_bug" , false, offsetof (struct c3x_config, patch_disease_stopping_tech_flag_bug)}, + {"patch_division_by_zero_in_ai_alliance_eval" , true , offsetof (struct c3x_config, patch_division_by_zero_in_ai_alliance_eval)}, + {"patch_empty_army_movement" , true , offsetof (struct c3x_config, patch_empty_army_movement)}, + {"patch_empty_army_combat_crash" , true , offsetof (struct c3x_config, patch_empty_army_combat_crash)}, + {"patch_premature_truncation_of_found_paths" , true , offsetof (struct c3x_config, patch_premature_truncation_of_found_paths)}, + {"patch_zero_production_crash" , true , offsetof (struct c3x_config, patch_zero_production_crash)}, + {"patch_ai_can_form_army_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_form_army_without_special_ability)}, + {"patch_ai_can_sacrifice_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_sacrifice_without_special_ability)}, + {"patch_crash_in_leader_unit_ai" , true , offsetof (struct c3x_config, patch_crash_in_leader_unit_ai)}, + {"patch_failure_to_find_new_city_build" , true , offsetof (struct c3x_config, patch_failure_to_find_new_city_build)}, + {"patch_passengers_out_of_order_on_menu" , true , offsetof (struct c3x_config, patch_passengers_out_of_order_on_menu)}, + {"delete_off_map_ai_units" , true , offsetof (struct c3x_config, delete_off_map_ai_units)}, + {"fix_overlapping_specialist_yield_icons" , true , offsetof (struct c3x_config, fix_overlapping_specialist_yield_icons)}, + {"prevent_autorazing" , false, offsetof (struct c3x_config, prevent_autorazing)}, + {"prevent_razing_by_players" , false, offsetof (struct c3x_config, prevent_razing_by_players)}, + {"suppress_hypertext_links_exceeded_popup" , true , offsetof (struct c3x_config, suppress_hypertext_links_exceeded_popup)}, + {"indicate_non_upgradability_in_pedia" , true , offsetof (struct c3x_config, indicate_non_upgradability_in_pedia)}, + {"show_message_after_dodging_sam" , true , offsetof (struct c3x_config, show_message_after_dodging_sam)}, + {"include_stealth_attack_cancel_option" , false, offsetof (struct c3x_config, include_stealth_attack_cancel_option)}, + {"intercept_recon_missions" , false, offsetof (struct c3x_config, intercept_recon_missions)}, + {"charge_one_move_for_recon_and_interception" , false, offsetof (struct c3x_config, charge_one_move_for_recon_and_interception)}, + {"polish_precision_striking" , true , offsetof (struct c3x_config, polish_precision_striking)}, + {"enable_stealth_attack_via_bombardment" , false, offsetof (struct c3x_config, enable_stealth_attack_via_bombardment)}, + {"immunize_aircraft_against_bombardment" , false, offsetof (struct c3x_config, immunize_aircraft_against_bombardment)}, + {"replay_ai_moves_in_hotseat_games" , false, offsetof (struct c3x_config, replay_ai_moves_in_hotseat_games)}, + {"restore_unit_directions_on_game_load" , true , offsetof (struct c3x_config, restore_unit_directions_on_game_load)}, + {"apply_grid_ini_setting_on_game_load" , true , offsetof (struct c3x_config, apply_grid_ini_setting_on_game_load)}, + {"charm_flag_triggers_ptw_like_targeting" , false, offsetof (struct c3x_config, charm_flag_triggers_ptw_like_targeting)}, + {"city_icons_show_unit_effects_not_trade" , true , offsetof (struct c3x_config, city_icons_show_unit_effects_not_trade)}, + {"ignore_king_ability_for_defense_priority" , false, offsetof (struct c3x_config, ignore_king_ability_for_defense_priority)}, + {"show_untradable_techs_on_trade_screen" , false, offsetof (struct c3x_config, show_untradable_techs_on_trade_screen)}, + {"disallow_useless_bombard_vs_airfields" , true , offsetof (struct c3x_config, disallow_useless_bombard_vs_airfields)}, + {"compact_luxury_display_on_city_screen" , false, offsetof (struct c3x_config, compact_luxury_display_on_city_screen)}, + {"compact_strategic_resource_display_on_city_screen" , false, offsetof (struct c3x_config, compact_strategic_resource_display_on_city_screen)}, + {"warn_when_chosen_building_would_replace_another" , false, offsetof (struct c3x_config, warn_when_chosen_building_would_replace_another)}, + {"do_not_unassign_workers_from_polluted_tiles" , false, offsetof (struct c3x_config, do_not_unassign_workers_from_polluted_tiles)}, + {"do_not_make_capital_cities_appear_larger" , false, offsetof (struct c3x_config, do_not_make_capital_cities_appear_larger)}, + {"show_territory_colors_on_water_tiles_in_minimap" , false, offsetof (struct c3x_config, show_territory_colors_on_water_tiles_in_minimap)}, + {"convert_some_popups_into_online_mp_messages" , false, offsetof (struct c3x_config, convert_some_popups_into_online_mp_messages)}, + {"enable_debug_mode_switch" , false, offsetof (struct c3x_config, enable_debug_mode_switch)}, + {"accentuate_cities_on_minimap" , false, offsetof (struct c3x_config, accentuate_cities_on_minimap)}, + {"allow_multipage_civilopedia_descriptions" , true , offsetof (struct c3x_config, allow_multipage_civilopedia_descriptions)}, + {"reformat_turns_remaining_on_domestic_advisor_screen" , true , offsetof (struct c3x_config, reformat_turns_remaining_on_domestic_advisor_screen)}, + {"enable_trade_net_x" , true , offsetof (struct c3x_config, enable_trade_net_x)}, + {"optimize_improvement_loops" , true , offsetof (struct c3x_config, optimize_improvement_loops)}, + {"measure_turn_times" , false, offsetof (struct c3x_config, measure_turn_times)}, + {"enable_city_capture_by_barbarians" , false, offsetof (struct c3x_config, enable_city_capture_by_barbarians)}, + {"share_visibility_in_hotseat" , false, offsetof (struct c3x_config, share_visibility_in_hotseat)}, + {"share_wonders_in_hotseat" , false, offsetof (struct c3x_config, share_wonders_in_hotseat)}, + {"allow_precision_strikes_against_tile_improvements" , false, offsetof (struct c3x_config, allow_precision_strikes_against_tile_improvements)}, + {"dont_end_units_turn_after_bombarding_barricade" , false, offsetof (struct c3x_config, dont_end_units_turn_after_bombarding_barricade)}, + {"remove_land_artillery_target_restrictions" , false, offsetof (struct c3x_config, remove_land_artillery_target_restrictions)}, + {"allow_bombard_of_other_improvs_on_occupied_airfield" , false, offsetof (struct c3x_config, allow_bombard_of_other_improvs_on_occupied_airfield)}, + {"show_total_city_count" , false, offsetof (struct c3x_config, show_total_city_count)}, + {"strengthen_forbidden_palace_ocn_effect" , false, offsetof (struct c3x_config, strengthen_forbidden_palace_ocn_effect)}, + {"allow_upgrades_in_any_city" , false, offsetof (struct c3x_config, allow_upgrades_in_any_city)}, + {"do_not_generate_volcanos" , false, offsetof (struct c3x_config, do_not_generate_volcanos)}, + {"do_not_pollute_impassable_tiles" , false, offsetof (struct c3x_config, do_not_pollute_impassable_tiles)}, + {"show_hp_of_stealth_attack_options" , false, offsetof (struct c3x_config, show_hp_of_stealth_attack_options)}, + {"exclude_invisible_units_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_invisible_units_from_stealth_attack)}, + {"exclude_passengers_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_passengers_from_stealth_attack)}, + {"convert_to_landmark_after_planting_forest" , false, offsetof (struct c3x_config, convert_to_landmark_after_planting_forest)}, + {"allow_sale_of_aqueducts_and_hospitals" , false, offsetof (struct c3x_config, allow_sale_of_aqueducts_and_hospitals)}, + {"no_cross_shore_detection" , false, offsetof (struct c3x_config, no_cross_shore_detection)}, + {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, + {"limit_unit_loading_to_one_transport_per_turn" , false, offsetof (struct c3x_config, limit_unit_loading_to_one_transport_per_turn)}, + {"prevent_old_units_from_upgrading_past_ability_block" , false, offsetof (struct c3x_config, prevent_old_units_from_upgrading_past_ability_block)}, + {"allow_extraterritorial_colonies" , false, offsetof (struct c3x_config, allow_extraterritorial_colonies)}, + {"draw_forests_over_roads_and_railroads" , false, offsetof (struct c3x_config, draw_forests_over_roads_and_railroads)}, + {"enable_districts" , false, offsetof (struct c3x_config, enable_districts)}, + {"enable_neighborhood_districts" , false, offsetof (struct c3x_config, enable_neighborhood_districts)}, + {"enable_wonder_districts" , false, offsetof (struct c3x_config, enable_wonder_districts)}, + {"enable_natural_wonders" , false, offsetof (struct c3x_config, enable_natural_wonders)}, + {"add_natural_wonders_to_scenarios_if_none" , false, offsetof (struct c3x_config, add_natural_wonders_to_scenarios_if_none)}, + {"enable_named_tiles" , false, offsetof (struct c3x_config, enable_named_tiles)}, + {"enable_distribution_hub_districts" , false, offsetof (struct c3x_config, enable_distribution_hub_districts)}, + {"enable_aerodrome_districts" , false, offsetof (struct c3x_config, enable_aerodrome_districts)}, + {"enable_port_districts" , false, offsetof (struct c3x_config, enable_port_districts)}, + {"enable_bridge_districts" , false, offsetof (struct c3x_config, enable_bridge_districts)}, + {"enable_canal_districts" , false, offsetof (struct c3x_config, enable_canal_districts)}, + {"enable_central_rail_hub_districts" , false, offsetof (struct c3x_config, enable_central_rail_hub_districts)}, + {"enable_energy_grid_districts" , false, offsetof (struct c3x_config, enable_energy_grid_districts)}, + {"enable_great_wall_districts" , false, offsetof (struct c3x_config, enable_great_wall_districts)}, + {"completed_wonder_districts_can_be_destroyed" , false, offsetof (struct c3x_config, completed_wonder_districts_can_be_destroyed)}, + {"destroyed_wonders_can_be_built_again" , false, offsetof (struct c3x_config, destroyed_wonders_can_be_built_again)}, + {"cities_with_mutual_district_receive_buildings" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_buildings)}, + {"cities_with_mutual_district_receive_wonders" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_wonders)}, + {"show_message_when_building_received_by_mutual_district", false, offsetof (struct c3x_config, show_message_when_building_received_by_mutual_district)}, + {"show_message_when_building_lost_to_destroyed_district" , false, offsetof (struct c3x_config, show_message_when_building_lost_to_destroyed_district)}, + {"destroying_neighborhood_reduces_pop" , false, offsetof (struct c3x_config, destroying_neighborhood_reduces_pop)}, + {"air_units_use_aerodrome_districts_not_cities" , false, offsetof (struct c3x_config, air_units_use_aerodrome_districts_not_cities)}, + {"naval_units_use_port_districts_not_cities" , false, offsetof (struct c3x_config, naval_units_use_port_districts_not_cities)}, + {"show_natural_wonder_name_on_map" , false, offsetof (struct c3x_config, show_natural_wonder_name_on_map)}, + {"ai_defends_districts" , false, offsetof (struct c3x_config, ai_defends_districts)}, + {"great_wall_districts_impassible_by_others" , false, offsetof (struct c3x_config, great_wall_districts_impassible_by_others)}, + {"auto_build_great_wall_around_territory" , false, offsetof (struct c3x_config, auto_build_great_wall_around_territory)}, + {"disable_great_wall_city_defense_bonus" , false, offsetof (struct c3x_config, disable_great_wall_city_defense_bonus)}, + {"expand_water_tile_checks_to_city_work_area" , false, offsetof (struct c3x_config, expand_water_tile_checks_to_city_work_area)}, + {"ai_can_replace_existing_districts_with_canals" , false, offsetof (struct c3x_config, ai_can_replace_existing_districts_with_canals)}, + {"ai_builds_bridges" , false, offsetof (struct c3x_config, ai_builds_bridges)}, + {"ai_builds_canals" , false, offsetof (struct c3x_config, ai_builds_canals)}, + {"workers_can_enter_coast" , false, offsetof (struct c3x_config, workers_can_enter_coast)}, + {"enable_city_work_radii_highlights" , false, offsetof (struct c3x_config, enable_city_work_radii_highlights)}, + {"introduce_all_human_players_at_start_of_hotseat_game" , false, offsetof (struct c3x_config, introduce_all_human_players_at_start_of_hotseat_game)}, + {"allow_unload_from_army" , false, offsetof (struct c3x_config, allow_unload_from_army)}, + {"no_land_anti_air_from_inside_naval_transport" , false, offsetof (struct c3x_config, no_land_anti_air_from_inside_naval_transport)}, + {"prevent_enslaving_by_bombardment" , false, offsetof (struct c3x_config, prevent_enslaving_by_bombardment)}, + {"allow_adjacent_resources_of_different_types" , false, offsetof (struct c3x_config, allow_adjacent_resources_of_different_types)}, + {"allow_corruption_in_capital" , false, offsetof (struct c3x_config, allow_corruption_in_capital)}, + {"allow_sale_of_small_wonders" , false, offsetof (struct c3x_config, allow_sale_of_small_wonders)}, + {"enable_unit_counters" , false, offsetof (struct c3x_config, enable_unit_counters)}, + {"use_civ4_style_best_defender" , false, offsetof (struct c3x_config, use_civ4_style_best_defender)}, + }; + + struct integer_config_option { + char * name; + int base_val; + int offset; + } integer_config_options[] = { + {"limit_railroad_movement" , 0, offsetof (struct c3x_config, limit_railroad_movement)}, + {"minimum_city_separation" , 1, offsetof (struct c3x_config, minimum_city_separation)}, + {"anarchy_length_percent" , 100, offsetof (struct c3x_config, anarchy_length_percent)}, + {"ai_multi_city_start" , 0, offsetof (struct c3x_config, ai_multi_city_start)}, + {"max_tries_to_place_fp_city" , 10000, offsetof (struct c3x_config, max_tries_to_place_fp_city)}, + {"ai_research_multiplier" , 100, offsetof (struct c3x_config, ai_research_multiplier)}, + {"ai_settler_perfume_on_founding_duration" , 0, offsetof (struct c3x_config, ai_settler_perfume_on_founding_duration)}, + {"extra_unit_maintenance_per_shields" , 0, offsetof (struct c3x_config, extra_unit_maintenance_per_shields)}, + {"ai_build_artillery_ratio" , 16, offsetof (struct c3x_config, ai_build_artillery_ratio)}, + {"ai_artillery_value_damage_percent" , 50, offsetof (struct c3x_config, ai_artillery_value_damage_percent)}, + {"ai_build_bomber_ratio" , 70, offsetof (struct c3x_config, ai_build_bomber_ratio)}, + {"max_ai_naval_escorts" , 3, offsetof (struct c3x_config, max_ai_naval_escorts)}, + {"ai_worker_requirement_percent" , 150, offsetof (struct c3x_config, ai_worker_requirement_percent)}, + {"chance_for_nukes_to_destroy_max_one_hp_units" , 100, offsetof (struct c3x_config, chance_for_nukes_to_destroy_max_one_hp_units)}, + {"rebase_range_multiplier" , 6, offsetof (struct c3x_config, rebase_range_multiplier)}, + {"elapsed_minutes_per_day_night_hour_transition" , 3, offsetof (struct c3x_config, elapsed_minutes_per_day_night_hour_transition)}, + {"fixed_hours_per_turn_for_day_night_cycle" , 1, offsetof (struct c3x_config, fixed_hours_per_turn_for_day_night_cycle)}, + {"pinned_hour_for_day_night_cycle" , 0, offsetof (struct c3x_config, pinned_hour_for_day_night_cycle)}, + {"years_to_double_building_culture" , 1000, offsetof (struct c3x_config, years_to_double_building_culture)}, + {"tourism_time_scale_percent" , 100, offsetof (struct c3x_config, tourism_time_scale_percent)}, + {"luxury_randomized_appearance_rate_percent" , 100, offsetof (struct c3x_config, luxury_randomized_appearance_rate_percent)}, + {"tiles_per_non_luxury_resource" , 32, offsetof (struct c3x_config, tiles_per_non_luxury_resource)}, + {"special_capital_decorruption_effect" , 10, offsetof (struct c3x_config, special_capital_decorruption_effect)}, + {"city_limit" , 2048, offsetof (struct c3x_config, city_limit)}, + {"maximum_pop_before_neighborhood_needed" , 8, offsetof (struct c3x_config, maximum_pop_before_neighborhood_needed)}, + {"per_neighborhood_pop_growth_enabled" , 2, offsetof (struct c3x_config, per_neighborhood_pop_growth_enabled)}, + {"minimum_natural_wonder_separation" , 10, offsetof (struct c3x_config, minimum_natural_wonder_separation)}, + {"distribution_hub_food_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_food_yield_divisor)}, + {"distribution_hub_shield_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_shield_yield_divisor)}, + {"ai_ideal_distribution_hub_count_per_100_cities" , 1, offsetof (struct c3x_config, ai_ideal_distribution_hub_count_per_100_cities)}, + {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, + {"max_distribution_hub_count_per_100_cities" , 50, offsetof (struct c3x_config, max_distribution_hub_count_per_100_cities)}, + {"central_rail_hub_distribution_food_bonus_percent" , 25, offsetof (struct c3x_config, central_rail_hub_distribution_food_bonus_percent)}, + {"central_rail_hub_distribution_shield_bonus_percent", 25, offsetof (struct c3x_config, central_rail_hub_distribution_shield_bonus_percent)}, + {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, + {"max_contiguous_bridge_districts" , 3, offsetof (struct c3x_config, max_contiguous_bridge_districts)}, + {"max_contiguous_canal_districts" , 5, offsetof (struct c3x_config, max_contiguous_canal_districts)}, + {"ai_canal_eval_min_bisected_land_tiles" , 10, offsetof (struct c3x_config, ai_canal_eval_min_bisected_land_tiles)}, + {"ai_bridge_canal_eval_block_size" , 20, offsetof (struct c3x_config, ai_bridge_canal_eval_block_size)}, + {"ai_bridge_eval_lake_tile_threshold" , 6, offsetof (struct c3x_config, ai_bridge_eval_lake_tile_threshold)}, + {"ai_city_district_max_build_wait_turns" , 20, offsetof (struct c3x_config, ai_city_district_max_build_wait_turns)}, + {"per_extraterritorial_colony_relation_penalty" , 0, offsetof (struct c3x_config, per_extraterritorial_colony_relation_penalty)}, + }; + + is->kernel32 = (*p_GetModuleHandleA) ("kernel32.dll"); + is->user32 = (*p_GetModuleHandleA) ("user32.dll"); + is->msvcrt = (*p_GetModuleHandleA) ("msvcrt.dll"); + + // Remember the function names here are macros that expand to is->... + VirtualProtect = (void *)(*p_GetProcAddress) (is->kernel32, "VirtualProtect"); + CloseHandle = (void *)(*p_GetProcAddress) (is->kernel32, "CloseHandle"); + CreateFileA = (void *)(*p_GetProcAddress) (is->kernel32, "CreateFileA"); + GetFileSize = (void *)(*p_GetProcAddress) (is->kernel32, "GetFileSize"); + ReadFile = (void *)(*p_GetProcAddress) (is->kernel32, "ReadFile"); + LoadLibraryA = (void *)(*p_GetProcAddress) (is->kernel32, "LoadLibraryA"); + FreeLibrary = (void *)(*p_GetProcAddress) (is->kernel32, "FreeLibrary"); + MultiByteToWideChar = (void *)(*p_GetProcAddress) (is->kernel32, "MultiByteToWideChar"); + WideCharToMultiByte = (void *)(*p_GetProcAddress) (is->kernel32, "WideCharToMultiByte"); + GetLastError = (void *)(*p_GetProcAddress) (is->kernel32, "GetLastError"); + QueryPerformanceCounter = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceCounter"); + QueryPerformanceFrequency = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceFrequency"); + GetLocalTime = (void *)(*p_GetProcAddress) (is->kernel32, "GetLocalTime"); + MessageBoxA = (void *)(*p_GetProcAddress) (is->user32, "MessageBoxA"); + is->msimg32 = LoadLibraryA ("Msimg32.dll"); + TransparentBlt = (void *)(*p_GetProcAddress) (is->msimg32, "TransparentBlt"); + snprintf = (void *)(*p_GetProcAddress) (is->msvcrt, "_snprintf"); + malloc = (void *)(*p_GetProcAddress) (is->msvcrt, "malloc"); + calloc = (void *)(*p_GetProcAddress) (is->msvcrt, "calloc"); + realloc = (void *)(*p_GetProcAddress) (is->msvcrt, "realloc"); + free = (void *)(*p_GetProcAddress) (is->msvcrt, "free"); + strtol = (void *)(*p_GetProcAddress) (is->msvcrt, "strtol"); + strcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strcmp"); + strncmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strncmp"); + _stricmp = (void *)(*p_GetProcAddress) (is->msvcrt, "_stricmp"); + strlen = (void *)(*p_GetProcAddress) (is->msvcrt, "strlen"); + strncpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strncpy"); + strcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strcpy"); + strdup = (void *)(*p_GetProcAddress) (is->msvcrt, "_strdup"); + strstr = (void *)(*p_GetProcAddress) (is->msvcrt, "strstr"); + qsort = (void *)(*p_GetProcAddress) (is->msvcrt, "qsort"); + memcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "memcmp"); + memcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "memcpy"); + tolower = (void *)(*p_GetProcAddress) (is->msvcrt, "tolower"); + toupper = (void *)(*p_GetProcAddress) (is->msvcrt, "toupper"); + is->memmove = (void *)(*p_GetProcAddress) (is->msvcrt, "memmove"); // No #define for this one, instead it has a wrapper func + + // Intercept the game's calls to MessageBoxA. We can't do this through the patcher since that would interfere with the runtime loader. + WITH_MEM_PROTECTION (p_MessageBoxA, 4, PAGE_READWRITE) + *p_MessageBoxA = patch_MessageBoxA; + + // Set file path to mod's script.txt + snprintf (is->mod_script_path, sizeof is->mod_script_path, "%s\\Text\\c3x-script.txt", is->mod_rel_dir); + is->mod_script_path[(sizeof is->mod_script_path) - 1] = '\0'; + + // Fill in base config + struct c3x_config base_config = {0}; + base_config.land_retreat_rules = RR_STANDARD; + base_config.sea_retreat_rules = RR_STANDARD; + base_config.ai_settler_perfume_on_founding = 0; + base_config.work_area_limit = WAL_NONE; + base_config.draw_lines_using_gdi_plus = LDO_WINE; + base_config.double_minimap_size = MDM_HIGH_DEF; + base_config.override_no_ai_patrol = NAPO_NONE; + base_config.override_barbarian_activity_level_for_scenario_maps = BAO_NONE; + base_config.unit_cycle_search_criteria = UCSC_STANDARD; + base_config.city_work_radius = 2; + base_config.day_night_cycle_mode = DNCM_OFF; + base_config.distribution_hub_yield_division_mode = DHYDM_FLAT; + base_config.ai_distribution_hub_build_strategy = ADHBS_BY_CITY_COUNT; + base_config.ai_auto_build_great_wall_strategy = AAGWS_ALL_BORDERS; + base_config.great_wall_auto_build_wonder_improv_id = -1; + for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) + *((char *)&base_config + boolean_config_options[n].offset) = boolean_config_options[n].base_val; + for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) + *(int *)((byte *)&base_config + integer_config_options[n].offset) = integer_config_options[n].base_val; + memcpy (&is->base_config, &base_config, sizeof base_config); + + // Load labels + { + for (int n = 0; n < COUNT_C3X_LABELS; n++) + is->c3x_labels[n] = ""; + + char labels_path[MAX_PATH]; + snprintf (labels_path, sizeof labels_path, "%s\\Text\\c3x-labels.txt", is->mod_rel_dir); + labels_path[(sizeof labels_path) - 1] = '\0'; + char * labels_file_contents = file_to_string (labels_path); + + if (labels_file_contents != NULL) { + char * cursor = labels_file_contents; + int n = 0; + while ((n < COUNT_C3X_LABELS) && (*cursor != '\0')) { + if (*cursor == '\n') + cursor++; + else if ((cursor[0] == '\r') && (cursor[1] == '\n')) + cursor += 2; + else if (*cursor == ';') { + while ((*cursor != '\0') && (*cursor != '\n')) + cursor++; + } else { + char * line_start = cursor; + while ((*cursor != '\0') && (*cursor != '\r') && (*cursor != '\n')) + cursor++; + int line_len = cursor - line_start; + if (NULL != (is->c3x_labels[n] = malloc (line_len + 1))) { + strncpy (is->c3x_labels[n], line_start, line_len); + is->c3x_labels[n][line_len] = '\0'; + } + n++; + } + } + free (labels_file_contents); + + } else { + char err_msg[500]; + snprintf (err_msg, sizeof err_msg, "Couldn't read labels from %s\nPlease make sure the file exists. If you moved the modded EXE you must move the mod folder after it.", labels_path); + err_msg[(sizeof err_msg) - 1] = '\0'; + MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); + } + } + + is->sb_next_up = NULL; + is->trade_net = p_original_trade_net; + is->city_limit = 512; + is->trade_net_addrs_load_state = IS_UNINITED; + is->trade_net_addrs = NULL; + is->tnx_cache = NULL; + is->is_computing_city_connections = false; + is->keep_tnx_cache = false; + is->must_recompute_resources_for_mill_inputs = false; + is->is_placing_scenario_things = false; + is->paused_for_popup = false; + is->time_spent_paused_during_popup = 0; + is->time_spent_computing_city_connections = 0; + is->count_calls_to_recompute_city_connections = 0; + + is->have_job_and_loc_to_skip = 0; + + // Initialize trade screen scroll vars + is->open_diplo_form_straight_to_trade = 0; + is->trade_screen_scroll_to_id = -1; + is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; + is->trade_scroll_button_images = NULL; + is->trade_scroll_button_state = IS_UNINITED; + is->eligible_for_trade_scroll = 0; + + memset (&is->saved_code_areas, 0, sizeof is->saved_code_areas); + + is->unit_menu_duplicates = NULL; + + is->memo = NULL; + is->memo_len = 0; + is->memo_capacity = 0; + + // Fill in array mapping cultural NIs to standard ones. + is->cultural_ni_to_standard = malloc (MAX_CULTURAL_NI + 1); + for (int n = 0; n <= MAX_CULTURAL_NI; n++) { + char const * p = &cultural_ni_to_diffs[n << 1]; + is->cultural_ni_to_standard[n] = diff_to_neighbor_index (p[0], p[1], 1000); + } + + // Fill in array mapping standard NIs to work radii AKA work ring numbers + for (int n = 0; n < ARRAY_LEN (is->ni_to_work_radius); n++) { + int work_radius = -1; + int dx, dy; + neighbor_index_to_diff (n, &dx, &dy); + for (int ring_no = 0; ring_no <= 7; ring_no++) { + for (int k = workable_tile_counts[ring_no-1]; k < workable_tile_counts[ring_no]; k++) { + char const * p = &cultural_ni_to_diffs[k<<1]; + if ((p[0] == dx) && (p[1] == dy)) { + work_radius = ring_no; + break; + } + } + if (work_radius != -1) + break; + } + is->ni_to_work_radius[n] = work_radius; + } + + is->city_loc_display_perspective = -1; + + is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; + + is->extra_available_resources = NULL; + is->extra_available_resources_capacity = 0; + + memset (is->interceptor_reset_lists, 0, sizeof is->interceptor_reset_lists); + + is->ai_prod_valuations = NULL; + is->count_ai_prod_valuations = 0; + is->ai_prod_valuations_capacity = 0; + + is->resource_tiles = NULL; + is->count_resource_tiles = 0; + is->resource_tiles_capacity = 0; + is->got_resource_tile = NULL; + is->saved_tile_count = -1; + is->mill_input_resource_bits = NULL; + + is->drawing_icons_for_improv_id = -1; + + is->resources_sheet = NULL; + + is->modifying_gold_trade = NULL; + + is->bombard_stealth_target = NULL; + is->selecting_stealth_target_for_bombard = 0; + + is->map_message_text_override = NULL; + + is->load_file_path_override = NULL; + + is->replay_for_players = 0; + + is->suppress_intro_after_load_popup = 0; + + is->force_barb_activity_for_cities = 0; + + is->dummy_tile = calloc (1, sizeof *is->dummy_tile); + + is->bombarding_unit = NULL; + + is->unit_bombard_attacking_tile = NULL; + is->attacking_tile_x = is->attacking_tile_y = -1; + + is->temporarily_disallow_lethal_zoc = false; + is->moving_unit_to_adjacent_tile = false; + is->showing_hotseat_replay = false; + is->getting_tile_occupier_for_ai_pathfinding = false; + + is->running_on_wine = false; { + HMODULE ntdll = (*p_GetModuleHandleA) ("ntdll.dll"); + is->running_on_wine = (ntdll != NULL) && ((*p_GetProcAddress) (ntdll, "wine_get_version") != NULL); + } + + is->gdi_plus.init_state = IS_UNINITED; + + is->water_trade_improvs = (struct improv_id_list) {0}; + is->air_trade_improvs = (struct improv_id_list) {0}; + is->combat_defense_improvs = (struct improv_id_list) {0}; + + is->unit_display_override = (struct unit_display_override) {-1, -1, -1}; + + is->dbe = (struct defensive_bombard_event) {0}; + + memset (&is->boolean_config_offsets, 0, sizeof is->boolean_config_offsets); + for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) + stable_insert (&is->boolean_config_offsets, boolean_config_options[n].name, boolean_config_options[n].offset); + memset (&is->integer_config_offsets, 0, sizeof is->integer_config_offsets); + for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) + stable_insert (&is->integer_config_offsets, integer_config_options[n].name, integer_config_options[n].offset); + + memset (&is->unit_type_alt_strategies, 0, sizeof is->unit_type_alt_strategies); + memset (&is->unit_type_duplicates , 0, sizeof is->unit_type_duplicates); + memset (&is->extra_defensive_bombards, 0, sizeof is->extra_defensive_bombards); + memset (&is->airdrops_this_turn , 0, sizeof is->airdrops_this_turn); + memset (&is->unit_transport_ties , 0, sizeof is->unit_transport_ties); + memset (&is->extra_city_improvs , 0, sizeof is->extra_city_improvs); + + is->unit_type_count_init_bits = 0; + for (int n = 0; n < 32; n++) + memset (&is->unit_type_counts[n], 0, sizeof is->unit_type_counts[n]); + + is->penciled_in_upgrades = NULL; + is->penciled_in_upgrade_count = is->penciled_in_upgrade_capacity = 0; + + is->currently_capturing_city = NULL; + is->accessing_save_file = NULL; + + is->drawn_strat_resource_count = 0; + + is->charmed_types_converted_to_ptw_arty = NULL; + is->count_charmed_types_converted_to_ptw_arty = 0; + is->charmed_types_converted_to_ptw_arty_capacity = 0; + + is->checking_visibility_for_unit = NULL; + + is->do_not_bounce_invisible_units = false; + is->always_despawn_passengers = false; + is->do_not_enslave_units = false; + + is->saved_improv_counts = NULL; + is->saved_improv_counts_capacity = 0; + + memset (is->last_main_screen_key_up_events, 0, sizeof is->last_main_screen_key_up_events); + + reset_district_state (true); + + is->natural_wonder_count = 0; + + is->sharing_buildings_by_districts_in_progress = false; + is->can_load_transport = is->can_load_passenger = NULL; + + is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; + is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; + is->last_selected_unit.ptr = NULL; + + is->waiting_units = (struct table) {0}; + is->have_loaded_waiting_units = false; + + is->extra_capture_despawns = NULL; + is->count_extra_capture_despawns = 0; + is->extra_capture_despawns_capacity = 0; + + is->loaded_config_names = NULL; + reset_to_base_config (); + apply_machine_code_edits (&is->current_config, true); +} + +void +init_stackable_command_buttons () +{ + if (is->sc_img_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + for (int n = 0; n < 4; n++) + Sprite_construct (&is->sc_button_image_sets[sc].imgs[n]); + + char temp_path[2*MAX_PATH]; + + is->sb_activated_by_button = 0; + is->sc_img_state = IS_INIT_FAILED; + + char const * filenames[4] = {"StackedNormButtons.pcx", "StackedRolloverButtons.pcx", "StackedHighlightedButtons.pcx", "StackedButtonsAlpha.pcx"}; + for (int n = 0; n < 4; n++) { + get_mod_art_path (filenames[n], temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + for (int k = 0; k < 4; k++) { + Sprite * sprite = &is->sc_button_image_sets[sc].imgs[k]; + sprite->vtable->destruct (sprite, __, 0); + } + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) { + int x = 32 * sc_button_infos[sc].tile_sheet_column, + y = 32 * sc_button_infos[sc].tile_sheet_row; + Sprite_slice_pcx (&is->sc_button_image_sets[sc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); + } + + pcx.vtable->clear_JGL (&pcx); + } + + is->sc_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +void +init_disabled_command_buttons () +{ + if (is->disabled_command_img_state != IS_UNINITED) + return; + + is->disabled_command_img_state = IS_INIT_FAILED; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("DisabledButtons.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load disabled command buttons sprite sheet.\n"); + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + Sprite_construct (&is->disabled_build_city_button_img); + Sprite_slice_pcx (&is->disabled_build_city_button_img, __, &pcx, 32*5, 32*2, 32, 32, 1, 0); + + is->disabled_command_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_stackable_command_buttons () +{ + if (is->sc_img_state == IS_OK) + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + for (int n = 0; n < 4; n++) { + Sprite * sprite = &is->sc_button_image_sets[sc].imgs[n]; + sprite->vtable->destruct (sprite, __, 0); + } + is->sc_img_state = IS_UNINITED; +} + +void +deinit_disabled_command_buttons () +{ + Sprite * sprite = &is->disabled_build_city_button_img; + if (is->disabled_command_img_state == IS_OK) + sprite->vtable->destruct (sprite, __, 0); + memset (sprite, 0, sizeof *sprite); + is->disabled_command_img_state = IS_UNINITED; +} + +void +init_tile_highlights () +{ + if (is->tile_highlight_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + + is->tile_highlight_state = IS_INIT_FAILED; + + snprintf (temp_path, sizeof temp_path, "%s\\Art\\TileHighlights.pcx", is->mod_rel_dir); + temp_path[(sizeof temp_path) - 1] = '\0'; + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); + goto cleanup; + } + + for (int n = 0; n < COUNT_TILE_HIGHLIGHTS; n++) + Sprite_slice_pcx (&is->tile_highlights[n], __, &pcx, 128*n, 0, 128, 64, 1, 0); + + is->tile_highlight_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +init_unit_rcm_icons () +{ + if (is->unit_rcm_icon_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("UnitRCMIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image == NULL) || + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 57) || + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 64)) { + (*p_OutputDebugStringA) ("[C3X] PCX file for unit RCM icons failed to load or is too small.\n"); + goto cleanup; + } + + for (int set = 0; set < COUNT_UNIT_RCM_ICON_SETS; set++) { + Sprite * icons = &is->unit_rcm_icons[set * COUNT_UNIT_RCM_ICONS]; + for (int n = 0; n < COUNT_UNIT_RCM_ICONS; n++) { + Sprite_construct (&icons[n]); + Sprite_slice_pcx (&icons[n], __, &pcx, 1 + 14*set, 1 + 16*n, 14, 15, 1, 0); + } + } + + is->unit_rcm_icon_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_unit_rcm_icons () +{ + if (is->unit_rcm_icon_state == IS_OK) { + int total_icon_count = COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS; + for (int n = 0; n < total_icon_count; n++) { + Sprite * sprite = &is->unit_rcm_icons[n]; + sprite->vtable->destruct (sprite, __, 0); + } + is->unit_rcm_icon_state = IS_UNINITED; + } +} + +void +init_red_food_icon () +{ + if (is->red_food_icon_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("MoreCityIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image != NULL) && + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) >= 32) && + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) == 32)) { + Sprite_construct (&is->red_food_icon); + Sprite_slice_pcx (&is->red_food_icon, __, &pcx, 1, 1, 30, 30, 1, 1); + is->red_food_icon_state = IS_OK; + } else { + (*p_OutputDebugStringA) ("[C3X] PCX file for red food icon failed to load or is not the correct size.\n"); + is->red_food_icon_state = IS_INIT_FAILED; + } + + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_red_food_icon () +{ + if (is->red_food_icon_state == IS_OK) + is->red_food_icon.vtable->destruct (&is->red_food_icon, __, 0); + is->red_food_icon_state = IS_UNINITED; +} + +enum init_state +init_large_minimap_frame () +{ + if (is->large_minimap_frame_img_state != IS_UNINITED) + return is->large_minimap_frame_img_state; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + + get_mod_art_path ("interface\\DoubleSizeBoxLeftColor.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image != NULL) { + Sprite_construct (&is->double_size_box_left_color_pcx); + int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), + height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); + Sprite_slice_pcx (&is->double_size_box_left_color_pcx, __, &pcx, 0, 0, width, height, 1, 1); + } else { + pcx.vtable->destruct (&pcx, __, 0); + return is->large_minimap_frame_img_state = IS_INIT_FAILED; + } + + get_mod_art_path ("interface\\DoubleSizeBoxLeftAlpha.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image != NULL) { + Sprite_construct (&is->double_size_box_left_alpha_pcx); + int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), + height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); + Sprite_slice_pcx (&is->double_size_box_left_alpha_pcx, __, &pcx, 0, 0, width, height, 1, 1); + } else { + is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); + pcx.vtable->destruct (&pcx, __, 0); + return is->large_minimap_frame_img_state = IS_INIT_FAILED;; + } + + pcx.vtable->destruct (&pcx, __, 0); + return is->large_minimap_frame_img_state = IS_OK; +} + +void +deinit_large_minimap_frame () +{ + if (is->large_minimap_frame_img_state == IS_OK) { + is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); + is->double_size_box_left_alpha_pcx.vtable->destruct (&is->double_size_box_left_alpha_pcx, __, 0); + } + is->large_minimap_frame_img_state = IS_UNINITED; +} + +int __cdecl +patch_get_tile_occupier_for_ai_path (int x, int y, int pov_civ_id, bool respect_unit_invisibility) +{ + is->getting_tile_occupier_for_ai_pathfinding = true; + return get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); + is->getting_tile_occupier_for_ai_pathfinding = false; +} + +char __fastcall patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2); + +char __fastcall +patch_Unit_is_tile_occupier_visible (Unit * this, int edx, int civ_id, int param_2) +{ + // Here's the fix for the submarine bug: If we're constructing a path for an AI unit, ignore unit invisibility so the pathfinder will path + // around instead of over other civ's units. We must carve out an exception if the AI is at war with the unit in question. In that case if it + // "accidentally" paths over the unit, it should get stuck in combat like the human player would. + if (is->current_config.patch_submarine_bug && + is->getting_tile_occupier_for_ai_pathfinding && + ! this->vtable->is_enemy_of_civ (this, __, civ_id, 0)) + return 1; + else + return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); +} + +void do_trade_scroll (DiploForm * diplo, int forward); + +void __cdecl +activate_trade_scroll_button (int control_id) +{ + do_trade_scroll (p_diplo_form, control_id == TRADE_SCROLL_BUTTON_ID_RIGHT); +} + +void +init_trade_scroll_buttons (DiploForm * diplo_form) +{ + if (is->trade_scroll_button_state != IS_UNINITED) + return; + + char temp_path[2*MAX_PATH]; + PCX_Image pcx; + PCX_Image_construct (&pcx); + get_mod_art_path ("TradeScrollButtons.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + is->trade_scroll_button_state = IS_INIT_FAILED; + (*p_OutputDebugStringA) ("[C3X] Failed to load TradeScrollButtons.pcx\n"); + goto cleanup; + } + + // Stores normal, rollover, and highlight images, in that order, first for the left button then for the right + is->trade_scroll_button_images = calloc (6, sizeof is->trade_scroll_button_images[0]); + for (int n = 0; n < 6; n++) + Sprite_construct (&is->trade_scroll_button_images[n]); + Sprite * imgs = is->trade_scroll_button_images; + + for (int right = 0; right < 2; right++) + for (int n = 0; n < 3; n++) + Sprite_slice_pcx (&imgs[n + 3*right], __, &pcx, right ? 44 : 0, 1 + 48*n, 43, 47, 1, 1); + + for (int right = 0; right < 2; right++) { + Button * b = new (sizeof *b); + + Button_construct (b); + int id = right ? TRADE_SCROLL_BUTTON_ID_RIGHT : TRADE_SCROLL_BUTTON_ID_LEFT; + Button_initialize (b, __, NULL, id, right ? 622 : 358, 50, 43, 47, (Base_Form *)diplo_form, 0); + for (int n = 0; n < 3; n++) + b->Images[n] = &imgs[n + 3*right]; + + b->activation_handler = &activate_trade_scroll_button; + b->field_630[0] = 0; // TODO: Is this necessary? It's done by the base game code when creating the city screen scroll buttons + + if (! right) + is->trade_scroll_button_left = b; + else + is->trade_scroll_button_right = b; + } + + is->trade_scroll_button_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_trade_scroll_buttons () +{ + if (is->trade_scroll_button_state == IS_OK) { + is->trade_scroll_button_left ->vtable->destruct ((Base_Form *)is->trade_scroll_button_left , __, 0); + is->trade_scroll_button_right->vtable->destruct ((Base_Form *)is->trade_scroll_button_right, __, 0); + is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; + for (int n = 0; n < 6; n++) { + Sprite * sprite = &is->trade_scroll_button_images[n]; + sprite->vtable->destruct (sprite, __, 0); + } + free (is->trade_scroll_button_images); + is->trade_scroll_button_images = NULL; + } + is->trade_scroll_button_state = IS_UNINITED; +} + +void +init_mod_info_button_images () +{ + if (is->mod_info_button_images_state != IS_UNINITED) + return; + + is->mod_info_button_images_state = IS_INIT_FAILED; + + PCX_Image * descbox_pcx = new (sizeof *descbox_pcx); + PCX_Image_construct (descbox_pcx); + char * descbox_path = BIC_get_asset_path (p_bic_data, __, "art\\civilopedia\\descbox.pcx", true); + PCX_Image_read_file (descbox_pcx, __, descbox_path, NULL, 0, 0x100, 1); + if (descbox_pcx->JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load descbox.pcx\n"); + return; + } + + for (int n = 0; n < 3; n++) { + Sprite_construct (&is->mod_info_button_images[n]); + Sprite_slice_pcx_with_color_table (&is->mod_info_button_images[n], __, descbox_pcx, 1 + n * 103, 1, MOD_INFO_BUTTON_WIDTH, + MOD_INFO_BUTTON_HEIGHT, 1, 1); + } + + is->mod_info_button_images_state = IS_OK; +} + +int +count_escorters (Unit * unit) +{ + IDLS * idls = &unit->Body.IDLS; + if (idls->escorters.contents != NULL) { + int tr = 0; + for (int * p_escorter_id = idls->escorters.contents; p_escorter_id < idls->escorters.contents_end; p_escorter_id++) + tr += NULL != get_unit_ptr (*p_escorter_id); + return tr; + } else + return 0; +} + +// If "unit" belongs to the AI, records that all players that have visibility on (x, y) have seen an AI unit +void +record_ai_unit_seen (Unit * unit, int x, int y) +{ + if (0 == (*p_human_player_bits & 1<Body.CivID)) { + Tile * tile = tile_at (x, y); + if ((tile != NULL) && (tile != p_null_tile)) { + Tile_Body * body = &tile->Body; + is->players_saw_ai_unit |= body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility; + } + } +} + +void +recompute_resources_if_necessary () +{ + if (is->must_recompute_resources_for_mill_inputs) + patch_Trade_Net_recompute_resources (is->trade_net, __, false); +} + +void __fastcall +patch_Unit_bombard_tile (Unit * this, int edx, int x, int y) +{ + Tile * target_tile = NULL; + bool had_district_before = false; + int tile_x = x; + int tile_y = y; + struct district_instance * inst; + + if (is->current_config.enable_districts) { + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + target_tile = tile_at (tile_x, tile_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + inst = get_district_instance (target_tile); + had_district_before = (inst != NULL); + } + } + + is->bombarding_unit = this; + record_ai_unit_seen (this, x, y); + Unit_bombard_tile (this, __, x, y); + is->bombard_stealth_target = NULL; + is->bombarding_unit = NULL; + + if (had_district_before && target_tile != NULL && target_tile != p_null_tile && inst->district_id != NATURAL_WONDER_DISTRICT_ID) { + unsigned int overlays = target_tile->vtable->m42_Get_Overlays (target_tile, __, 0); + if ((overlays & TILE_FLAG_MINE) == 0) + handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, false); + } +} + +void __fastcall +patch_Unit_move (Unit * this, int edx, int tile_x, int tile_y) +{ + record_ai_unit_seen (this, tile_x, tile_y); + + Unit_move (this, __, tile_x, tile_y); + + if (this == is->last_selected_unit.ptr) { + is->last_selected_unit.last_x = this->Body.X; + is->last_selected_unit.last_y = this->Body.Y; + } +} + +// Returns true if the unit has attacked & does not have blitz or if it's run out of movement points for the turn +bool +has_exhausted_attack (Unit * unit) +{ + return (unit->Body.Moves >= patch_Unit_get_max_move_points (unit)) || + ((unit->Body.Status & USF_USED_ATTACK) && ! UnitType_has_ability (&p_bic_data->UnitTypes[unit->Body.UnitTypeID], __, UTA_Blitz)); +} + +// Returns whether or not the unit type is a combat type and can do damage on offense (as opposed to only being able to defend). This includes units +// that can only do damage by bombarding and nuclear weapons. +bool +is_offensive_combat_type (UnitType * unit_type) +{ + return (unit_type->Attack > 0) || + ((((unit_type->Special_Actions & UCV_Bombard) | (unit_type->Air_Missions & UCV_Bombing)) & 0x0FFFFFFF) && // (type can perform bombard or bombing AND + ((unit_type->Bombard_Strength > 0) || UnitType_has_ability (unit_type, __, UTA_Nuclear_Weapon))); // (unit has bombard strength OR is a nuclear weapon)) +} + +bool +can_damage_bombarding (UnitType * attacker_type, Unit * defender, Tile * defender_tile) +{ + Unit * container; + if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + (container = get_unit_ptr (defender->Body.Container_Unit)) != NULL && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return false; + + UnitType * defender_type = &p_bic_data->UnitTypes[defender->Body.UnitTypeID]; + if (defender_type->Unit_Class == UTC_Land) { + int has_lethal_land_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Land_Bombardment); + return defender->Body.Damage + (! has_lethal_land_bombard) < Unit_get_max_hp (defender); + } else if (defender_type->Unit_Class == UTC_Sea) { + // Land artillery can't normally damage ships in port + if ((attacker_type->Unit_Class == UTC_Land) && (! is->current_config.remove_land_artillery_target_restrictions) && Tile_has_city (defender_tile)) + return false; + int has_lethal_sea_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Sea_Bombardment); + return defender->Body.Damage + (! has_lethal_sea_bombard) < Unit_get_max_hp (defender); + } else if (defender_type->Unit_Class == UTC_Air) { + if (is->current_config.immunize_aircraft_against_bombardment) + return false; + // Can't damage aircraft in an airfield by bombarding, the attack doesn't even go off + if ((defender_tile->vtable->m42_Get_Overlays (defender_tile, __, 0) & 0x20000000) != 0) + return false; + // Land artillery can't normally damage aircraft but naval artillery and other aircraft can. Lethal bombard doesn't apply; anything + // that can damage can kill. + return (attacker_type->Unit_Class != UTC_Land) || is->current_config.remove_land_artillery_target_restrictions; + } else // UTC_Space? UTC_Alternate_Dimension??? + return false; +} + +char __fastcall +patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2) +{ + // Save the previous value here b/c this function gets called recursively + Unit * prev_checking = is->checking_visibility_for_unit; + is->checking_visibility_for_unit = this; + + char base_vis = Unit_is_visible_to_civ (this, __, civ_id, param_2); + if ((! base_vis) && // if unit is not visible to civ_id AND + is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND + ((1 << civ_id) & *p_human_player_bits) && // civ_id is a human player AND + (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game + + // Check if the unit is visible to any other human player in the game + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && + (n_player != civ_id) && + Unit_is_visible_to_civ (this, __, n_player, param_2)) + return 1; + player_bits >>= 1; + n_player++; + } + } + + is->checking_visibility_for_unit = prev_checking; + return base_vis; +} + +bool +has_any_destructible_improvements (City * city) +{ + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * improv = &p_bic_data->Improvements[n]; + if (((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) && // if improv is not a wonder AND + ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && // it's not the palace AND + (improv->SpaceshipPart < 0) && // it's not a spaceship part AND + patch_City_has_improvement (city, __, n, 0)) // it's present in the city ignoring free improvements + return true; + } + return false; +} + +int const destructible_overlays = + 0x00000003 | // road, railroad + 0x00000004 | // mine + 0x00000008 | // irrigation + 0x00000010 | // fortress + 0x10000000 | // barricade + 0x20000000 | // airfield + 0x40000000 | // radar + 0x80000000; // outpost + +bool +has_any_destructible_overlays (Tile * tile, bool precision_strike) +{ + int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); + if ((overlays & destructible_overlays) == 0) + return false; + else { + if (! precision_strike) + return true; + else { + if (overlays == 0x20000000) { // if tile ONLY has an airfield + int any_aircraft_on_tile = 0; { + FOR_UNITS_ON (uti, tile) + if (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class == UTC_Air) { + any_aircraft_on_tile = 1; + break; + } + } + return ! any_aircraft_on_tile; + } else + return true; + } + } +} + +void __fastcall +patch_Main_Screen_Form_perform_action_on_tile (Main_Screen_Form * this, int edx, enum Unit_Mode_Actions action, int x, int y) +{ + if ((! is->current_config.enable_stack_bombard) || // if stack bombard is disabled OR + (! ((action == UMA_Bombard) || (action == UMA_Air_Bombard))) || // action is not bombard OR + ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) && // (control key is not down AND + ((is->sc_img_state != IS_UNINITED) && (is->sb_activated_by_button == 0))) || // (button flag is valid AND not set)) OR + is_online_game ()) { // is online game + Main_Screen_Form_perform_action_on_tile (this, __, action, x, y); + return; + } + + // Save preferences so we can restore them at the end of the stack bombard operation. We might change them to turn off combat animations. + unsigned init_prefs = *p_preferences; + + clear_memo (); + + wrap_tile_coords (&p_bic_data->Map, &x, &y); + Tile * base_tile = tile_at (this->Current_Unit->Body.X, this->Current_Unit->Body.Y); + Tile * target_tile = tile_at (x, y); + int attacker_type_id = this->Current_Unit->Body.UnitTypeID; + UnitType * attacker_type = &p_bic_data->UnitTypes[attacker_type_id]; + int civ_id = this->Current_Unit->Body.CivID; + + // Count & memoize attackers + int selected_unit_id = this->Current_Unit->Body.ID; + FOR_UNITS_ON (uti, base_tile) + if ((uti.id != selected_unit_id) && + (uti.unit->Body.CivID == civ_id) && + (uti.unit->Body.UnitTypeID == attacker_type_id) && + ((uti.unit->Body.Container_Unit < 0) || (attacker_type->Unit_Class == UTC_Air)) && + (uti.unit->Body.UnitState == 0) && + ! has_exhausted_attack (uti.unit)) + memoize (uti.id); + int count_attackers = is->memo_len; + + // Count & memoize targets (also count air units while we're at it) + int num_air_units_on_target_tile = 0; + FOR_UNITS_ON (uti, target_tile) { + num_air_units_on_target_tile += UTC_Air == p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; + if ((uti.unit->Body.CivID != civ_id) && + (Unit_get_defense_strength (uti.unit) > 0) && + (uti.unit->Body.Container_Unit < 0) && + patch_Unit_is_visible_to_civ (uti.unit, __, civ_id, 0) && + can_damage_bombarding (attacker_type, uti.unit, target_tile)) + memoize (uti.id); + } + int count_targets = is->memo_len - count_attackers; + + // Now our attackers and targets arrays will just be pointers into the memo + int * attackers = &is->memo[0], * targets = &is->memo[count_attackers]; + + int attacking_units = 0, attacking_tile = 0; + City * target_city = NULL; + if (count_targets > 0) + attacking_units = 1; + else if (Tile_has_city (target_tile)) + target_city = get_city_ptr (target_tile->vtable->m45_Get_City_ID (target_tile)); + else { + // Make sure not to set attacking_tile when the tile has an airfield and air units (but no land units) on + // it. In that case we can't damage the airfield and if we try to anyway, the units will waste their moves + // without attacking. + int has_airfield = (target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & 0x20000000) != 0; + attacking_tile = (! has_airfield) || (num_air_units_on_target_tile == 0); + } + + is->sb_next_up = this->Current_Unit; + int i_next_attacker = 0; + int anything_left_to_attack; + int last_attack_didnt_happen; + do { + // If combat animations were enabled when the stack bombard operation started, reset the preference according to the state of the + // shift key (down => skip animations, up => show them). + if (init_prefs & P_ANIMATE_BATTLES) { + if ((*p_GetAsyncKeyState) (VK_SHIFT) >> 8) + *p_preferences &= ~P_ANIMATE_BATTLES; + else + *p_preferences |= P_ANIMATE_BATTLES; + } + + int moves_before_bombard = is->sb_next_up->Body.Moves; + + patch_Unit_bombard_tile (is->sb_next_up, __, x, y); + // At this point sb_next_up may have become NULL if the unit was a bomber that got shot down. + + // Check if the last unit sent into battle actually did anything. If it didn't we should at least skip over + // it to avoid an infinite loop, but actually the only time this should happen is if the player is not at + // war with the targeted civ and chose not to declare when prompted. In this case it's better to just stop + // trying to attack so as to not spam the player with prompts. + last_attack_didnt_happen = (is->sb_next_up == NULL) || (is->sb_next_up->Body.Moves == moves_before_bombard); + + if ((is->sb_next_up == NULL) || has_exhausted_attack (is->sb_next_up)) { + is->sb_next_up = NULL; + while ((i_next_attacker < count_attackers) && (is->sb_next_up == NULL)) + is->sb_next_up = get_unit_ptr (attackers[i_next_attacker++]); + } + + if (attacking_units) { + anything_left_to_attack = 0; + for (int n = 0; n < count_targets; n++) { + Unit * unit = get_unit_ptr (targets[n]); + + // Make sure this unit is still a valid target. Keep in mind it's possible for new units to be created during the + // stack bombard operation if the attackers have lethal bombard and the enslave ability. + if ((unit != NULL) && (unit->Body.X == x) && (unit->Body.Y == y) && (unit->Body.CivID != civ_id)) { + + if (can_damage_bombarding (attacker_type, unit, target_tile)) { + anything_left_to_attack = 1; + break; + } + } + } + } else if (target_city != NULL) + anything_left_to_attack = (target_city->Body.Population.Size > 1) || has_any_destructible_improvements (target_city); + else if (attacking_tile) + anything_left_to_attack = has_any_destructible_overlays (target_tile, false); + else + anything_left_to_attack = 0; + } while ((is->sb_next_up != NULL) && anything_left_to_attack && (! last_attack_didnt_happen)); + + is->sb_activated_by_button = 0; + is->sb_next_up = NULL; + *p_preferences = init_prefs; + this->GUI.Base.vtable->m73_call_m22_Draw ((Base_Form *)&this->GUI); +} + +void +set_up_stack_bombard_buttons (Main_GUI * this) +{ + if (is_online_game () || (! is->current_config.enable_stack_bombard)) + return; + + init_stackable_command_buttons (); + if (is->sc_img_state != IS_OK) + return; + + // Find button that the original method set to (air) bombard, then find the next unused button after that. + Command_Button * bombard_button = NULL, * free_button = NULL; { + int i_bombard_button; + for (int n = 0; n < 42; n++) + if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && + (this->Unit_Command_Buttons[n].Command == UCV_Bombard || this->Unit_Command_Buttons[n].Command == UCV_Bombing)) { + bombard_button = &this->Unit_Command_Buttons[n]; + i_bombard_button = n; + break; + } + if (bombard_button != NULL) + for (int n = i_bombard_button + 1; n < 42; n++) + if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { + free_button = &this->Unit_Command_Buttons[n]; + break; + } + } + + if ((bombard_button == NULL) || (free_button == NULL)) + return; + + // Set up free button for stack bombard + free_button->Command = bombard_button->Command; + free_button->field_6D8 = bombard_button->field_6D8; + struct sc_button_image_set * img_set = + (bombard_button->Command == UCV_Bombing) ? &is->sc_button_image_sets[SC_BOMB] : &is->sc_button_image_sets[SC_BOMBARD]; + for (int n = 0; n < 4; n++) + free_button->Button.Images[n] = &img_set->imgs[n]; + free_button->Button.field_664 = bombard_button->Button.field_664; + // FUN_005559E0 is also called in the original code. I don't know what it actually does but I'm pretty sure it doesn't + // matter for our purposes. + Button_set_tooltip (&free_button->Button, __, is->c3x_labels[CL_SB_TOOLTIP]); + free_button->Button.field_5FC[13] = bombard_button->Button.field_5FC[13]; + free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); +} + +void +init_district_command_buttons () +{ + if (is_online_game () || is->dc_btn_img_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) + for (int n = 0; n < 4; n++) + Sprite_construct (&is->district_btn_img_sets[dc].imgs[n]); + + char temp_path[2*MAX_PATH]; + + is->dc_btn_img_state = IS_INIT_FAILED; + + // For each button sprite type (normal, rollover, highlighted, alpha) + char const * filenames[4] = { + "Districts\\WorkerDistrictButtonsNorm.pcx", "Districts\\WorkerDistrictButtonsRollover.pcx", + "Districts\\WorkerDistrictButtonsHighlighted.pcx", "Districts\\WorkerDistrictButtonsAlpha.pcx" + }; + for (int n = 0; n < 4; n++) { + get_mod_art_path (filenames[n], temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load work district command buttons sprite sheet.\n"); + for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) + for (int k = 0; k < 4; k++) { + Sprite * sprite = &is->district_btn_img_sets[dc].imgs[k]; + sprite->vtable->destruct (sprite, __, 0); + } + pcx.vtable->destruct (&pcx, __, 0); + + char ss[200]; + snprintf (ss, sizeof ss, "[C3X] Failed to load district command button images from %s", temp_path); + pop_up_in_game_error (ss); + + return; + } + + // For each district type + for (int dc = 0; dc < is->district_count; dc++) { + int x = 32 * is->district_configs[dc].btn_tile_sheet_column, + y = 32 * is->district_configs[dc].btn_tile_sheet_row; + Sprite_slice_pcx (&is->district_btn_img_sets[dc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); + } + + pcx.vtable->clear_JGL (&pcx); + } + + is->dc_btn_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +int +parse_turns_from_tooltip (char const * tooltip) +{ + if ((tooltip == NULL) || (*tooltip == '\0')) + return -1; + + char const * last_paren = NULL; + for (char const * cursor = tooltip; *cursor != '\0'; cursor++) + if (*cursor == '(') + last_paren = cursor; + if (last_paren == NULL) + return -1; + + char const * digit_ptr = last_paren + 1; + while (*digit_ptr == ' ') + digit_ptr++; + + int turns = 0; + bool have_digit = false; + while ((*digit_ptr >= '0') && (*digit_ptr <= '9')) { + have_digit = true; + turns = (turns * 10) + (*digit_ptr - '0'); + digit_ptr++; + } + return have_digit ? turns : -1; +} + +void +compute_highlighted_worker_tiles_for_districts () +{ + if (is_online_game () + || ! is->current_config.enable_districts + || ! is->current_config.enable_city_work_radii_highlights) + return; + + Unit * selected_unit = p_main_screen_form->Current_Unit; + if (selected_unit == NULL) + return; + + int unit_type_id = selected_unit->Body.UnitTypeID; + if (p_bic_data->UnitTypes[unit_type_id].Worker_Actions == 0) + return; + + if (is->tile_highlight_state == IS_UNINITED) + init_tile_highlights (); + if (is->tile_highlight_state != IS_OK) + return; + + int worker_civ_id = selected_unit->Body.CivID; + if ((p_cities == NULL) || (p_cities->Cities == NULL)) + return; + + // Loop over all cities owned by this civ and tally their workable tiles + FOR_CITIES_OF (coi, worker_civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + + // Highlight city center so players can easily see which cities contribute + Tile * city_center_tile = tile_at (city->Body.X, city->Body.Y); + if ((city_center_tile != NULL) && (city_center_tile != p_null_tile)) { + int stored_ptr; + if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, &stored_ptr)) { + struct highlighted_city_radius_tile_info * info = malloc (sizeof (struct highlighted_city_radius_tile_info)); + info->highlight_level = 0; + itable_insert (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, (int)info); + } + } + + // Add all workable tiles around the city (excluding city center) + for (int n = 1; n < is->workable_tile_count; n++) { + int dx, dy; + patch_ni_to_diff_for_work_area (n, &dx, &dy); + int tile_x = city->Body.X + dx; + int tile_y = city->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + + Tile * workable_tile = tile_at (tile_x, tile_y); + if ((workable_tile == NULL) || (workable_tile == p_null_tile)) continue; + if (workable_tile->vtable->m38_Get_Territory_OwnerID (workable_tile) != worker_civ_id) continue; + + // Upsert into highlighted_city_radius_tile_pointers + int stored_ptr; + struct highlighted_city_radius_tile_info * info; + if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, &stored_ptr)) { + info = malloc (sizeof (struct highlighted_city_radius_tile_info)); + info->highlight_level = 0; + itable_insert (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, (int)info); + } else { + info = (struct highlighted_city_radius_tile_info *)stored_ptr; + info->highlight_level += 3; + } + } + } +} + +void +set_up_district_buttons (Main_GUI * this) +{ + if (is_online_game () || ! is->current_config.enable_districts) return; + if (is->dc_btn_img_state == IS_UNINITED) init_district_command_buttons (); + if (is->dc_btn_img_state != IS_OK) return; + + Unit * selected_unit = p_main_screen_form->Current_Unit; + if (selected_unit == NULL || ! is_worker(selected_unit)) return; + + Tile * tile = tile_at (selected_unit->Body.X, selected_unit->Body.Y); + if ((tile == NULL) || (tile == p_null_tile) || (tile->CityID >= 0)) return; + + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + if (tile->vtable->m21_Check_Crates (tile, __, 0)) return; + if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return; + + Command_Button * fortify_button = NULL; + int i_starting_button; + int mine_turns = -1; + for (int n = 0; n < 42; n++) { + if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && + (this->Unit_Command_Buttons[n].Command == UCV_Fortify)) { + fortify_button = &this->Unit_Command_Buttons[n]; + i_starting_button = n; + } + if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { + mine_turns = parse_turns_from_tooltip (this->Unit_Command_Buttons[n].Button.ToolTip); + } + if (fortify_button != NULL && mine_turns >= 0) + break; + } + + if (fortify_button == NULL) + return; + + i_starting_button = -1; + + // Check if there's already a district on this tile. If so, and the unit can build mines, + // ensure the mine button is enabled so the worker can continue construction. + int existing_district_id = -1; + struct district_instance * existing_inst = get_district_instance (tile); + if (existing_inst != NULL) { + existing_district_id = existing_inst->district_id; + if (is->current_config.enable_natural_wonders && existing_inst->district_id == NATURAL_WONDER_DISTRICT_ID) { + return; + } + if (patch_Unit_can_perform_command(selected_unit, __, UCV_Build_Mine)) { + for (int n = 0; n < 42; n++) { + if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { + Command_Button * mine_button = &this->Unit_Command_Buttons[n]; + if (base_type == SQ_Coast) { + mine_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&mine_button->Button); + break; + } + if ((mine_button->Button.Base_Data.Status2 & 1) == 0) { + mine_button->Button.field_5FC[13] = 0; + mine_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&mine_button->Button, __, 0); + } + break; + } + } + } + } + + bool district_completed = district_is_complete (tile, existing_district_id); + + // First pass: collect which district types should be shown + int active_districts[COUNT_DISTRICT_TYPES]; + int active_count = 0; + + for (int dc = 0; dc < is->district_count; dc++) { + + if (is->district_configs[dc].command == -1) + continue; + + bool already_building = false; + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if (unit != NULL && is_worker(unit) && existing_inst != NULL && existing_inst->district_id == dc) { + // If there's a worker on the tile and it's building this district, + // show the button so more workers can contribute. This works around an + // issue where a specific district requiring irrigation no longer + // is buildable by other workers because initial construction removes the + // required irrigation overlay upon construction start + already_building = true; + break; + } + } + + if (existing_district_id == dc && district_completed) continue; + if ((existing_district_id >= 0) && (existing_district_id != dc) && (! district_completed)) continue; + + if (! can_build_district_on_tile (tile, dc, selected_unit->Body.CivID) && ! already_building) + continue; + + // This district should be shown + active_districts[active_count++] = dc; + } + + + if (active_count == 0) + return; + + // Calculate centered starting position + // For odd counts, center perfectly; for even counts, favor left of center + int center_pos = 6; + i_starting_button = center_pos - (active_count / 2); + if (i_starting_button < 0) + i_starting_button = 0; + + // Second pass: render the buttons + for (int idx = 0; idx < active_count; idx++) { + int dc = active_districts[idx]; + + Command_Button * free_button = NULL; + for (int n = i_starting_button; n < 42; n++) { + if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { + free_button = &this->Unit_Command_Buttons[n]; + i_starting_button = n + 1; + break; + } + } + + if (free_button == NULL) + return; + + // Set up free button for creating district + free_button->Command = is->district_configs[dc].command; + + // Replace the button's image with the district image. Disabling & re-enabling and + // clearing field_5FC[13] are all necessary to trigger a redraw. + free_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&free_button->Button); + free_button->field_6D8 = fortify_button->field_6D8; + for (int k = 0; k < 4; k++) + free_button->Button.Images[k] = &is->district_btn_img_sets[dc].imgs[k]; + free_button->Button.field_664 = fortify_button->Button.field_664; + if (mine_turns >= 0) { + char tooltip[256]; + char const * turn_word = (mine_turns == 1) ? "turn" : "turns"; + snprintf (tooltip, sizeof tooltip, "%s (%d %s)", is->district_configs[dc].tooltip, mine_turns, turn_word); + tooltip[(sizeof tooltip) - 1] = '\0'; + Button_set_tooltip (&free_button->Button, __, tooltip); + } else + Button_set_tooltip (&free_button->Button, __, (char *)is->district_configs[dc].tooltip); + free_button->Button.field_5FC[13] = 0; + free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); + } +} + +void +set_up_stack_worker_buttons (Main_GUI * this) +{ + if ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // (control key is not down OR + (! is->current_config.enable_stack_unit_commands) || // stack worker commands not enabled OR + is_online_game ()) // is online game + return; + + init_stackable_command_buttons (); + if (is->sc_img_state != IS_OK) + return; + + // For each unit command button + for (int n = 0; n < 42; n++) { + Command_Button * cb = &this->Unit_Command_Buttons[n]; + + // If it's enabled and not a bombard button (those are handled in the function above) + if (((cb->Button.Base_Data.Status2 & 1) != 0) && + (cb->Command != UCV_Bombard) && (cb->Command != UCV_Bombing)) { + + // Find the stackable worker command that this button controls, if there is one, and check that + // the button isn't already showing the stack image for that command. Note: this check is important + // b/c this function gets called repeatedly while the CTRL key is held down. + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + if ((cb->Command == sc_button_infos[sc].command) && + (cb->Button.Images[0] != &is->sc_button_image_sets[sc].imgs[0])) { + + // Replace the button's image with the stack image. Disabling & re-enabling and + // clearing field_5FC[13] are all necessary to trigger a redraw. + cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); + for (int k = 0; k < 4; k++) + cb->Button.Images[k] = &is->sc_button_image_sets[sc].imgs[k]; + cb->Button.field_5FC[13] = 0; + cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); + + break; + } + } + } +} + +CityLocValidity __fastcall patch_Map_check_city_location (Map * this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile); + +void __fastcall +patch_Main_GUI_set_up_unit_command_buttons (Main_GUI * this) +{ + // Recompute resources now if needed because of a trade deal involving mill inputs. In rare cases the change in deals might affect a mill that + // produces a resource that's used for a worker job. + recompute_resources_if_necessary (); + + Main_GUI_set_up_unit_command_buttons (this); + set_up_stack_bombard_buttons (this); + set_up_stack_worker_buttons (this); + + if (is->current_config.enable_districts) { + set_up_district_buttons (this); + } + + // If the minimum city separation is increased, then gray out the found city button if we're too close to another city. + if ((is->current_config.minimum_city_separation > 1) && (p_main_screen_form->Current_Unit != NULL) && (is->disabled_command_img_state == IS_OK)) { + Unit_Body * selected_unit = &p_main_screen_form->Current_Unit->Body; + + // For each unit command button + for (int n = 0; n < 42; n++) { + Command_Button * cb = &this->Unit_Command_Buttons[n]; + + // If it's enabled, set to city founding, and the current city location is too close to another city + if (((cb->Button.Base_Data.Status2 & 1) != 0) && + (cb->Command == UCV_Build_City) && + (patch_Map_check_city_location (&p_bic_data->Map, __, selected_unit->X, selected_unit->Y, selected_unit->CivID, false) == CLV_CITY_TOO_CLOSE)) { + + // Replace the button's image with the disabled image, as in set_up_stack_worker_buttons. + cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); + for (int k = 0; k < 3; k++) + cb->Button.Images[k] = &is->disabled_build_city_button_img; + cb->Button.field_5FC[13] = 0; + + char tooltip[200]; { + memset (tooltip, 0, sizeof tooltip); + char * label = is->c3x_labels[CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP], + * to_replace = "$NUM0", + * replace_location = strstr (label, to_replace); + if (replace_location != NULL) + snprintf (tooltip, sizeof tooltip, "%.*s%d%s", replace_location - label, label, is->current_config.minimum_city_separation, replace_location + strlen (to_replace)); + else + snprintf (tooltip, sizeof tooltip, "%s", label); + tooltip[(sizeof tooltip) - 1] = '\0'; + } + Button_set_tooltip (&cb->Button, __, tooltip); + + cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); + + } + } + } +} + +void +clear_highlighted_worker_tiles_and_redraw () +{ + clear_highlighted_worker_tiles_for_districts (); + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +void +check_happiness_at_end_of_turn () +{ + int num_unhappy_cities = 0; + City * first_unhappy_city = NULL; + FOR_CITIES_OF (coi, p_main_screen_form->Player_CivID) { + City_recompute_happiness (coi.city); + int num_happy = 0, num_unhappy = 0; + FOR_CITIZENS_IN (ci, coi.city) { + num_happy += ci.ctzn->Body.Mood == CMT_Happy; + num_unhappy += ci.ctzn->Body.Mood == CMT_Unhappy; + } + if (num_unhappy > num_happy) { + num_unhappy_cities++; + if (first_unhappy_city == NULL) + first_unhappy_city = coi.city; + } + } + + if (first_unhappy_city != NULL) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, first_unhappy_city->Body.CityName, -1, -1); + if (num_unhappy_cities > 1) + set_popup_int_param (1, num_unhappy_cities - 1); + char * key = (num_unhappy_cities > 1) ? "C3X_DISORDER_WARNING_MULTIPLE" : "C3X_DISORDER_WARNING_ONE"; + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, key, -1, 0, 0, 0); + int response = patch_show_popup (popup, __, 0, 0); + + if (response == 2) { // zoom to city + p_main_screen_form->turn_end_flag = 1; + City_zoom_to (first_unhappy_city, __, 0); + } else if (response == 1) // just cancel turn end + p_main_screen_form->turn_end_flag = 1; + // else do nothing, let turn end + + } +} + +void +do_trade_scroll (DiploForm * diplo, int forward) +{ + int increment = forward ? 1 : -1; + int id = -1; + for (int n = (diplo->other_party_civ_id + increment) & 31; n != diplo->other_party_civ_id; n = (n + increment) & 31) + if ((n != 0) && // if N is not barbs AND + (n != p_main_screen_form->Player_CivID) && // N is not the player's AND + (*p_player_bits & (1U << n)) && // N belongs to an active player AND + (leaders[p_main_screen_form->Player_CivID].Contacts[n] & 1) && // N has contact with the player AND + Leader_ai_would_meet_with (&leaders[n], __, p_main_screen_form->Player_CivID)) { // AI is willing to meet + id = n; + break; + } + + if (id >= 0) { + is->trade_screen_scroll_to_id = id; + DiploForm_close (diplo); + // Note extra code needs to get run here if the other player is not an AI + } +} + +void __fastcall +patch_DiploForm_m82_handle_key_event (DiploForm * this, int edx, int virtual_key_code, int is_down) +{ + if (is->eligible_for_trade_scroll && + (this->mode == 2) && + ((virtual_key_code == VK_LEFT) || (virtual_key_code == VK_RIGHT)) && + (! is_down)) + do_trade_scroll (this, virtual_key_code == VK_RIGHT); + else + DiploForm_m82_handle_key_event (this, __, virtual_key_code, is_down); +} + +int __fastcall +patch_DiploForm_m68_Show_Dialog (DiploForm * this, int edx, int param_1, void * param_2, void * param_3) +{ + if (is->open_diplo_form_straight_to_trade) { + is->open_diplo_form_straight_to_trade = 0; + + // Done by the base game but not necessary as far as I can tell + // void (__cdecl * FUN_00537700) (int) = 0x537700; + // FUN_00537700 (0x15); + // this->field_E9C[0] = this->field_E9C[0] + 1; + + // Set diplo screen mode to two-way trade negotation + this->mode = 2; + + // Set AI's diplo message to something like "what did you have in mind" + int iVar35 = DiploForm_set_their_message (this, __, DM_AI_PROPOSAL_RESPONSE, 0, 0x1A8); + this->field_1390[0] = DM_AI_PROPOSAL_RESPONSE; + this->field_1390[1] = 0; + this->field_1390[2] = iVar35; + + // Reset player message options. This will replace the propose deal, declare war, and leave options with the usual "nevermind" option + // that appears for negotiations. + DiploForm_reset_our_message_choices (this); + + // Done by the base game but not necessary as far as I can tell + // void (__fastcall * FUN_004C89A0) (void *) = 0x4C89A0; + // FUN_004C89A0 (&this->field_1BF4[0]); + + } + + return DiploForm_m68_Show_Dialog (this, __, param_1, param_2, param_3); +} + +void __fastcall +patch_DiploForm_do_diplomacy (DiploForm * this, int edx, int diplo_message, int param_2, int civ_id, int do_not_request_audience, int war_negotiation, int disallow_proposal, TradeOfferList * our_offers, TradeOfferList * their_offers) +{ + is->open_diplo_form_straight_to_trade = 0; + is->trade_screen_scroll_to_id = -1; + + // Trade screen scroll is disabled in online games b/c there's extra synchronization we'd need to do to open or close the diplo screen with + // a human player. + is->eligible_for_trade_scroll = is->current_config.enable_trade_screen_scroll && (! is_online_game ()); + + if (is->eligible_for_trade_scroll && (is->trade_scroll_button_state == IS_UNINITED)) + init_trade_scroll_buttons (this); + + WITH_PAUSE_FOR_POPUP { + DiploForm_do_diplomacy (this, __, diplo_message, param_2, civ_id, do_not_request_audience, war_negotiation, disallow_proposal, our_offers, their_offers); + + while (is->trade_screen_scroll_to_id >= 0) { + int scroll_to_id = is->trade_screen_scroll_to_id; + is->trade_screen_scroll_to_id = -1; + is->open_diplo_form_straight_to_trade = 1; + DiploForm_do_diplomacy (this, __, DM_AI_COUNTER, 0, scroll_to_id, 1, 0, 0, NULL, NULL); + } + } + + is->open_diplo_form_straight_to_trade = 0; + is->eligible_for_trade_scroll = 0; +} + +void __fastcall +patch_DiploForm_m22_Draw (DiploForm * this) +{ + if (is->trade_scroll_button_state == IS_OK) { + Button * left = is->trade_scroll_button_left, + * right = is->trade_scroll_button_right; + if (is->eligible_for_trade_scroll && (this->mode == 2)) { + left ->vtable->m01_Show_Enabled ((Base_Form *)left , __, 0); + right->vtable->m01_Show_Enabled ((Base_Form *)right, __, 0); + left ->vtable->m73_call_m22_Draw ((Base_Form *)left); + right->vtable->m73_call_m22_Draw ((Base_Form *)right); + } else { + left ->vtable->m02_Show_Disabled ((Base_Form *)left); + right->vtable->m02_Show_Disabled ((Base_Form *)right); + } + } + + DiploForm_m22_Draw (this); +} + +void +intercept_end_of_turn () +{ + if (is->current_config.enable_disorder_warning) { + check_happiness_at_end_of_turn (); + if (p_main_screen_form->turn_end_flag == 1) // Check if player cancelled turn ending in the disorder warning popup + return; + } + + // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + + if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { + is->city_loc_display_perspective = -1; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw + } + + // Clear things that don't apply across turns + is->have_job_and_loc_to_skip = 0; +} + +bool +is_worker_or_settler_command (int unit_command_value) +{ + return (unit_command_value & 0x20000000) || + ((unit_command_value >= UCV_Build_Remote_Colony) && (unit_command_value <= UCV_Auto_Save_Tiles)); +} + +bool +command_would_replace_district (int unit_command_value) +{ + // Note: Roads & railroads, etc. can coexist with the district + return (unit_command_value == UCV_Build_Mine) || + (unit_command_value == UCV_Irrigate) || + (unit_command_value == UCV_Plant_Forest) || + (unit_command_value == UCV_Build_Outpost) || + (unit_command_value == UCV_Build_Fortress) || + (unit_command_value == UCV_Build_Barricade) || + (unit_command_value == UCV_Build_Airfield) || + (unit_command_value == UCV_Build_Radar_Tower) || + (unit_command_value == UCV_Build_Colony); +} + +bool +handle_worker_command_that_may_replace_district (Unit * unit, int unit_command_value, bool * removed_existing) +{ + if (removed_existing != NULL) + *removed_existing = false; + + if ((! is->current_config.enable_districts) || (unit == NULL)) return true; + if (! is_worker_or_settler_command (unit_command_value)) return true; + if (! command_would_replace_district (unit_command_value)) return true; + if (! patch_Unit_can_perform_command (unit, __, unit_command_value)) return true; + + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + if ((tile == NULL) || (tile == p_null_tile)) + return true; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (! district_is_complete (tile, inst->district_id))) + return true; + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + return false; + + int district_id = inst->district_id; + int civ_id = unit->Body.CivID; + bool redundant_district = district_instance_is_redundant (inst, tile); + bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (district_id, civ_id, tile_x, tile_y); + if (redundant_district) + would_lose_buildings = false; + + bool remove_existing = redundant_district; + if (inst != NULL && district_id >= 0 && district_id < is->district_count) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char *)is->district_configs[district_id].display_name, -1, -1); + set_popup_str_param (1, (char *)is->district_configs[district_id].display_name, -1, -1); + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + would_lose_buildings + ? "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT" + : "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT_SAFE", + -1, 0, 0, 0); + int sel = patch_show_popup (popup, __, 0, 0); + if (sel != 0) + return false; + remove_existing = true; + } + + if (remove_existing) { + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + handle_district_removed (tile, district_id, tile_x, tile_y, false); + if (removed_existing != NULL) + *removed_existing = true; + } + + return true; +} + +bool __fastcall + patch_Unit_can_upgrade (Unit * this) +{ + bool base = Unit_can_upgrade (this); + int available; + City * city = city_at (this->Body.X, this->Body.Y); + if (base && + (city != NULL) && + get_available_unit_count (&leaders[this->Body.CivID], City_get_upgraded_type_id (city, __, this->Body.UnitTypeID), &available) && + (available <= 0)) + return false; + else + return base; +} + +bool +is_district_command (int unit_command_value) +{ + int district_id = -1; + if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) + return false; + + return district_id != NATURAL_WONDER_DISTRICT_ID; +} + +int __fastcall +patch_Map_check_colony_location (Map * this, int edx, int tile_x, int tile_y, int civ_id) +{ + int base = Map_check_colony_location (this, __, tile_x, tile_y, civ_id); + Tile * tile = tile_at (tile_x, tile_y); + + if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.allow_extraterritorial_colonies) + return base; + + if (tile->vtable->m35_Check_Is_Water (tile)) return base; + if (Tile_has_city (tile) || Tile_has_colony (tile)) return base; + + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_id < 0) || (owner_id == civ_id)) return base; + + int resource_type = Tile_get_resource_visible_to (tile, __, civ_id); + if ((resource_type < 0) || (resource_type >= p_bic_data->ResourceTypeCount)) return base; + + int req_tech = p_bic_data->ResourceTypes[resource_type].RequireID; + if ((req_tech >= 0) && (! Leader_has_tech (&leaders[civ_id], __, req_tech))) return base; + + int res_class = p_bic_data->ResourceTypes[resource_type].Class; + if ((res_class != RC_Strategic) && (res_class != RC_Luxury)) return base; + if (tile->vtable->m26_Check_Tile_Building (tile)) + return 6; + + return 0; +} + +bool __fastcall +patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value) +{ + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + // No worker or settler commands allowed on natural wonders + if ((tile != NULL) && (tile != p_null_tile) && is->current_config.enable_natural_wonders) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && + (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) { + if (is_worker_or_settler_command (unit_command_value) || is_district_command (unit_command_value)) + return false; + } + } + + if (is_district_command (unit_command_value)) { + int district_id; + if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) + return false; + + return is_worker (this) && can_build_district_on_tile (tile, district_id, this->Body.CivID); + } + // Extra check for colony founding if extraterritorial colonies allowed + else if (unit_command_value == UCV_Build_Colony || unit_command_value == UCV_Build_Remote_Colony) { + if (is->current_config.allow_extraterritorial_colonies && is_worker (this)) { + return patch_Map_check_colony_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID) == 0; + } + } + // Extra check for road building if bridge districts allowed + else if (unit_command_value == UCV_Build_Road) { + struct district_instance * inst = get_district_instance (tile); + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + if (!has_road && (inst != NULL) && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) + return true; + } + // Extra check for railroad building if bridge districts allowed + else if (unit_command_value == UCV_Build_Railroad) { + struct district_instance * inst = get_district_instance (tile); + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; + if ((inst != NULL) && is_worker (this) && has_road && + ! has_rail && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) { + int req_tech = p_bic_data->WorkerJobs[WJ_Build_Railroad].RequireID; + if ((req_tech < 0) || + ((req_tech != p_bic_data->AdvanceCount) && + Leader_has_tech (&leaders[this->Body.CivID], __, req_tech))) { + if (Leader_has_resources_for_job_at (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y)) + return true; + } + } + } + else if (unit_command_value == UCV_Build_Mine) { + bool has_district = (tile != NULL) && (tile != p_null_tile) && (get_district_instance (tile) != NULL); + + if (has_district) { + return Tile_get_mining_bonus (tile) > 0; + } + } else if (unit_command_value == UCV_Pillage) { + return patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y); + } + } + if (is->current_config.disable_worker_automation && + (this->Body.CivID == p_main_screen_form->Player_CivID) && + (unit_command_value == UCV_Automate)) + return false; + else if (is->current_config.disallow_land_units_from_affecting_water_tiles && + is_worker_or_settler_command (unit_command_value)) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + enum UnitTypeClasses class = p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class; + return ((class != UTC_Land) || (! tile->vtable->m35_Check_Is_Water (tile))) && + Unit_can_perform_command (this, __, unit_command_value); + } + + return Unit_can_perform_command (this, __, unit_command_value); +} + +void __fastcall +patch_Unit_join_city (Unit * this, int edx, City * city) +{ + if (is->current_config.enable_districts && is_worker (this)) { + int civ_id = this->Body.CivID; + bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; + if (! is_human) { + struct district_worker_record * rec = get_tracked_worker_record (this); + if ((rec != NULL) && (rec->pending_req != NULL)) { + ai_move_district_worker (this, rec); + return; + } + + Tile * worker_tile = tile_at (this->Body.X, this->Body.Y); + if ((worker_tile != NULL) && (worker_tile != p_null_tile)) { + int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); + + if ((civ_id >= 0) && (civ_id < 32)) { + struct pending_district_request * same_city_req = NULL; + struct pending_district_request * same_continent_req = NULL; + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req == NULL) || (req->assigned_worker_id >= 0)) + continue; + if ((req->civ_id != civ_id) || (req->city_id < 0)) + continue; + + City * req_city = get_city_ptr (req->city_id); + if (req_city == NULL) + continue; + + if (city != NULL && req_city->Body.ID == city->Body.ID) { + same_city_req = req; + break; + } + + Tile * req_city_tile = tile_at (req_city->Body.X, req_city->Body.Y); + if ((req_city_tile != NULL) && (req_city_tile != p_null_tile)) { + int req_continent_id = req_city_tile->vtable->m46_Get_ContinentID (req_city_tile); + if (req_continent_id == worker_continent_id) { + same_continent_req = req; + } + } + } + + struct pending_district_request * chosen_req = (same_city_req != NULL) ? same_city_req : same_continent_req; + if (chosen_req != NULL) { + City * req_city = get_city_ptr (chosen_req->city_id); + if (req_city != NULL) { + int target_x = 0; + int target_y = 0; + Tile * target_tile = find_tile_for_district (req_city, chosen_req->district_id, &target_x, &target_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); + assign_worker_to_district (chosen_req, this, req_city, chosen_req->district_id, target_x, target_y); + return; + } + } + } + } + } + } + } + + Unit_join_city (this, __, city); +} + +bool __fastcall +patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y) +{ + bool base = Unit_can_pillage (this, __, tile_x, tile_y); + + if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return base; + + int district_id = inst->district_id; + if (is->current_config.enable_natural_wonders && + (district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) + return false; + + if (! district_is_complete (tile, district_id)) + return true; + + if (district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info == NULL || info->state != WDS_COMPLETED) + return true; + return is->current_config.completed_wonder_districts_can_be_destroyed; + } + + return true; +} + +bool __fastcall +patch_Unit_can_do_worker_command_for_button_setup (Unit * this, int edx, int unit_command_value) +{ + bool base = patch_Unit_can_perform_command (this, __, unit_command_value); + + // If the command is to build a city and it can't be done because another city is already too close, and the minimum separation was changed + // from its standard value, then return true here so that the build city button will be added anyway. We'll gray it out later. Check that the + // grayed out button image is initialized now so we don't activate the build city button then find out later we can't gray it out. + if ((! base) && + (unit_command_value == UCV_Build_City) && + (is->current_config.minimum_city_separation > 1) && + (patch_Map_check_city_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID, false) == CLV_CITY_TOO_CLOSE) && + (init_disabled_command_buttons (), is->disabled_command_img_state == IS_OK)) + return true; + + else + return base; +} + +int +compare_helpers (void const * vp_a, void const * vp_b) +{ + Unit * a = get_unit_ptr (*(int *)vp_a), + * b = get_unit_ptr (*(int *)vp_b); + if ((a != NULL) && (b != NULL)) { + // Compute how many movement points each has left (ML = moves left) + int ml_a = patch_Unit_get_max_move_points (a) - a->Body.Moves, + ml_b = patch_Unit_get_max_move_points (b) - b->Body.Moves; + + // Whichever one has more MP left comes first in the array + if (ml_a > ml_b) return 1; + else if (ml_b > ml_a) return -1; + else return 0; + } else + // If at least one of the unit ids is invalid, might as well sort it later in the array + return (a != NULL) ? -1 : ((b != NULL) ? 1 : 0); +} + +void +issue_stack_worker_command (Unit * unit, int command) +{ + int tile_x = unit->Body.X; + int tile_y = unit->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + int unit_type_id = unit->Body.UnitTypeID; + int unit_id = unit->Body.ID; + + // Put together a list of helpers and store it on the memo. Helpers are just other workers on the same tile that can be issued the same command. + clear_memo (); + FOR_UNITS_ON (uti, tile) + if ((uti.id != unit_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) { + // check if the clicked command is among worker actions that this unit type can perform + int actions = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Worker_Actions; + int command_without_category = command & 0x0FFFFFFF; + if ((actions & command_without_category) == command_without_category) + memoize (uti.id); + } + + // Sort the list of helpers so that the ones with the fewest remaining movement points are listed first. + qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_helpers); + + Unit * next_up = unit; + int i_next_helper = 0; + int last_action_didnt_happen; + do { + int state_before_action = next_up->Body.UnitState; + Main_Screen_Form_issue_command (p_main_screen_form, __, command, next_up); + last_action_didnt_happen = (next_up->Body.UnitState == state_before_action); + + // Call this update function to cause the worker to actually perform the action. Otherwise + // it only gets queued, the worker keeps is movement points, and the action doesn't get done + // until the interturn. + if (! last_action_didnt_happen) + next_up->vtable->update_while_active (next_up); + + next_up = NULL; + while ((i_next_helper < is->memo_len) && (next_up == NULL)) + next_up = get_unit_ptr (is->memo[i_next_helper++]); + } while ((next_up != NULL) && (! last_action_didnt_happen)); +} + +void +issue_district_worker_command (Unit * unit, int command) +{ + if (! is->current_config.enable_districts) + return; + + if (unit == NULL) + return; + + int tile_x = unit->Body.X; + int tile_y = unit->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return; + + if (! is_worker(unit)) + return; + + int district_id = -1; + if (! itable_look_up (&is->command_id_to_district_id, command, &district_id)) + return; + if ((district_id < 0) || (district_id >= is->district_count)) + return; + + if (! leader_can_build_district (&leaders[unit->Body.CivID], district_id)) + return; + + // Disallow placing districts on invalid terrain, pollution, or cratered tiles + if (tile->vtable->m21_Check_Crates (tile, __, 0)) + return; + if (tile->vtable->m20_Check_Pollution (tile, __, 0)) + return; + + if (! district_is_buildable_on_tile (&is->district_configs[district_id], tile)) + return; + + // If District will be replaced by another District + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete(tile, inst->district_id)) { + int existing_district_id = inst->district_id; + int inst_x, inst_y; + if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) + return; + + int civ_id = unit->Body.CivID; + bool redundant_district = district_instance_is_redundant (inst, tile); + bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, inst_x, inst_y); + if (redundant_district) + would_lose_buildings = false; + + bool remove_existing = false; + + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char*)is->district_configs[existing_district_id].display_name, -1, -1); + set_popup_str_param (1, (char*)is->district_configs[existing_district_id].display_name, -1, -1); + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + would_lose_buildings + ? "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT" + : "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT_SAFE", + -1, 0, 0, 0 + ); + + int sel = patch_show_popup (popup, __, 0, 0); + if (sel == 0) + remove_existing = true; + else + return; + + if (remove_existing) { + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); + handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); + } + } + + // If District will replace an improvement + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); + + if (removable_flags != 0) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_BUILD_DISTRICT_OVER_IMPROVEMENT", -1, 0, 0, 0); + int sel = patch_show_popup (popup, __, 0, 0); + if (sel != 0) + return; + } + + if (removable_flags != 0) + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + + inst = ensure_district_instance (tile, district_id, tile_x, tile_y); + inst->built_by_civ_id = unit->Body.CivID; + if (inst != NULL) + inst->state = DS_UNDER_CONSTRUCTION; + + Unit_set_state (unit, __, UnitState_Build_Mines); + unit->Body.Job_ID = WJ_Build_Mines; +} + +void +issue_stack_unit_mgmt_command (Unit * unit, int command) +{ + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + int unit_type_id = unit->Body.UnitTypeID; + int unit_id = unit->Body.ID; + + PopupForm * popup = get_popup_form (); + + clear_memo (); + + if (command == UCV_Fortify) { + // This probably won't work for online games since "fortify all" does additional work in that case. See Main_Screen_Form::fortify_all. + // I don't like how this method doesn't place units in the fortified pose. One workaround is so use + // Main_Screen_Form::issue_fortify_command, but that plays the entire fortify animation for each unit which is a major annoyance for + // large stacks. The base game's "fortify all" function also doesn't set the pose so I don't see any easy way to fix this. + FOR_UNITS_ON (uti, tile) + if ((uti.unit->Body.UnitTypeID == unit_type_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + (uti.unit->Body.CivID == unit->Body.CivID) && + (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) + Unit_set_state (uti.unit, __, UnitState_Fortifying); + + } else if (command == UCV_Upgrade_Unit) { + int our_treasury = leaders[unit->Body.CivID].Gold_Encoded + leaders[unit->Body.CivID].Gold_Decrement; + + // If the unit type we're upgrading to is limited, find out how many we can add. Keep that in "available". If the type is not limited, + // leave available set to INT_MAX. + int available = INT_MAX; { + City * city; + int upgrade_id; + if ((is->current_config.unit_limits.len > 0) && + patch_Unit_can_perform_command (unit, __, UCV_Upgrade_Unit) && + (NULL != (city = city_at (unit->Body.X, unit->Body.Y))) && + (0 < (upgrade_id = City_get_upgraded_type_id (city, __, unit_type_id)))) + get_available_unit_count (&leaders[unit->Body.CivID], upgrade_id, &available); + } + + int cost = 0; + FOR_UNITS_ON (uti, tile) + if ((available > 0) && + (uti.unit->Body.UnitTypeID == unit_type_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + patch_Unit_can_perform_command (uti.unit, __, UCV_Upgrade_Unit)) { + cost += Unit_get_upgrade_cost (uti.unit); + available--; + memoize (uti.id); + } + + if (cost <= our_treasury) { + set_popup_str_param (0, p_bic_data->UnitTypes[unit_type_id].Name, -1, -1); + set_popup_int_param (0, is->memo_len); + set_popup_int_param (1, cost); + popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "UPGRADE_ALL", -1, 0, 0, 0); + if (patch_show_popup (popup, __, 0, 0) == 0) + for (int n = 0; n < is->memo_len; n++) { + Unit * to_upgrade = get_unit_ptr (is->memo[n]); + if (to_upgrade != NULL) + Unit_upgrade (to_upgrade, __, false); + } + + } else { + set_popup_int_param (0, cost); + int param_5 = is_online_game () ? 0x4000 : 0; // As in base code + popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "NO_GOLD_TO_UPGRADE_ALL", -1, 0, param_5, 0); + patch_show_popup (popup, __, 0, 0); + } + + } else if (command == UCV_Disband) { + FOR_UNITS_ON (uti, tile) + if ((uti.unit->Body.UnitTypeID == unit_type_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) + memoize (uti.id); + + if (is->memo_len > 0) { + set_popup_int_param (0, is->memo_len); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_STACK_DISBAND", -1, 0, 0, 0); + if (patch_show_popup (popup, __, 0, 0) == 0) { + for (int n = 0; n < is->memo_len; n++) { + Unit * to_disband = get_unit_ptr (is->memo[n]); + if (to_disband) + Unit_disband (to_disband); + } + } + } + } +} + +void __fastcall +patch_Main_GUI_handle_button_press (Main_GUI * this, int edx, int button_id) +{ + // Set SB flag according to case (2) + if (button_id < 42) { + if ((is->sc_img_state == IS_OK) && + ((this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMBARD].imgs[0]) || + (this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMB ].imgs[0]))) + is->sb_activated_by_button = 1; + else + is->sb_activated_by_button = 0; + } + + int command = this->Unit_Command_Buttons[button_id].Command; + + // Clear any highlighted tiles + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + + if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { + is->city_loc_display_perspective = -1; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw + } + + // If a district, run district build logic + if (is->current_config.enable_districts && is_district_command (command)) { + clear_something_1 (); + Timer_clear (&this->timer_1); + issue_district_worker_command (p_main_screen_form->Current_Unit, command); + return; + } + + // Check if command is a worker build command (not a district) and a district exists on the tile + if (is->current_config.enable_districts && p_main_screen_form->Current_Unit != NULL) { + + bool removed_existing = false; + if (! handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) + return; + if (removed_existing) { + clear_something_1 (); + Timer_clear (&this->timer_1); + Main_GUI_handle_button_press (this, __, button_id); + return; + } + } + + struct sc_button_info const * stack_button_info; { + stack_button_info = NULL; + if (button_id < 42) // If button pressed was a unit command button + for (int n = 0; n < COUNT_STACKABLE_COMMANDS; n++) + if (command == sc_button_infos[n].command) { + stack_button_info = &sc_button_infos[n]; + break; + } + } + + if ((stack_button_info == NULL) || // If there's no stack command for the pressed button OR + (! is->current_config.enable_stack_unit_commands) || // stack unit commands are not enabled OR + (((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // CTRL key is not down OR + (p_main_screen_form->Current_Unit == NULL) || // no unit is selected OR + is_online_game ()) { // is online game + Main_GUI_handle_button_press (this, __, button_id); + return; + } + + enum stackable_command_kind kind = stack_button_info->kind; + if ((kind == SCK_TERRAFORM) || (kind == SCK_UNIT_MGMT)) { + // Replicate behavior of function we're replacing + clear_something_1 (); + Timer_clear (&this->timer_1); + + if (kind == SCK_TERRAFORM) + issue_stack_worker_command (p_main_screen_form->Current_Unit, stack_button_info->command); + else if (kind == SCK_UNIT_MGMT) + issue_stack_unit_mgmt_command (p_main_screen_form->Current_Unit, stack_button_info->command); + } else + Main_GUI_handle_button_press (this, __, button_id); +} + +bool __fastcall +patch_Main_Screen_Form_issue_command (Main_Screen_Form * this, int edx, int command, Unit * unit) +{ + Unit * target_unit = unit; + if (target_unit == NULL) + target_unit = this->Current_Unit; + + if (is->current_config.enable_districts) { + bool removed_existing = false; + if (! handle_worker_command_that_may_replace_district (target_unit, command, &removed_existing)) + return false; + } + + return Main_Screen_Form_issue_command (this, __, command, unit); +} + +bool +is_command_button_active (Main_GUI * main_gui, enum Unit_Command_Values command) +{ + Command_Button * buttons = main_gui->Unit_Command_Buttons; + for (int n = 0; n < 42; n++) + if (((buttons[n].Button.Base_Data.Status2 & 1) != 0) && (buttons[n].Command == command)) + return true; + return false; +} + +int __fastcall +patch_Main_Screen_Form_handle_key_down (Main_Screen_Form * this, int edx, int char_code, int virtual_key_code) +{ + // Set SB flag according to case (4) + int precision_strike_is_available = is_command_button_active (&this->GUI, UCV_Precision_Bombing); + if ((virtual_key_code == VK_B) || (precision_strike_is_available && (virtual_key_code == VK_P))) + is->sb_activated_by_button = 0; + + if ((virtual_key_code & 0xFF) == VK_CONTROL) { + set_up_stack_worker_buttons (&this->GUI); + + if (is->current_config.enable_city_work_radii_highlights && + ! is->highlight_city_radii) { + Unit * unit = p_main_screen_form->Current_Unit; + if (unit != NULL) { + is->highlight_city_radii = true; + compute_highlighted_worker_tiles_for_districts (); + this->vtable->m73_call_m22_Draw ((Base_Form *)this); + } + } + } else { + if (is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + } + + char original_turn_end_flag = this->turn_end_flag; + int tr = Main_Screen_Form_handle_key_down (this, __, char_code, virtual_key_code); + if ((original_turn_end_flag == 1) && (this->turn_end_flag == 0)) + intercept_end_of_turn (); + + return tr; +} + +int +patch_handle_cursor_change_in_jgl () +{ + // Set SB flag according to case (3) and the annoying state + if ((is->sb_activated_by_button != 2) && + (p_main_screen_form->Mode_Action != UMA_Bombard) && + (p_main_screen_form->Mode_Action != UMA_Air_Bombard)) + is->sb_activated_by_button = 0; + + return handle_cursor_change_in_jgl (); +} + +void __fastcall +patch_Main_Screen_Form_handle_left_click_on_map_1 (Main_Screen_Form * this, int edx, int param_1, int param_2) +{ + if (is->sb_activated_by_button == 1) + is->sb_activated_by_button = 2; + Main_Screen_Form_handle_left_click_on_map_1 (this, __, param_1, param_2); + is->sb_activated_by_button = 0; +} + + +void __fastcall +patch_Main_GUI_handle_click_in_status_panel (Main_GUI * this, int edx, int mouse_x, int mouse_y) +{ + char original_turn_end_flag = p_main_screen_form->turn_end_flag; + Main_GUI_handle_click_in_status_panel (this, __, mouse_x, mouse_y); + if ((original_turn_end_flag == 1) && (p_main_screen_form->turn_end_flag == 0)) + intercept_end_of_turn (); +} + +// Gets effective shields generated per turn, including civil engineers, disorder, and anarchy. +int +get_city_production_rate (City * city, enum City_Order_Types order_type, int order_id) +{ + int in_disorder = city->Body.Status & CSF_Civil_Disorder, + in_anarchy = p_bic_data->Governments[leaders[city->Body.CivID].GovernmentType].b_Transition_Type, + getting_tile_shields = (! in_disorder) && (! in_anarchy); + + if (order_type == COT_Improvement) { + int building_wealth = (p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0; + int specialist_shields = 0; + FOR_CITIZENS_IN (ci, city) + if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) // I don't know what is check is for but it's done in the base code + specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; + return (getting_tile_shields ? city->Body.ProductionIncome : 0) + ((! building_wealth) ? specialist_shields : 0); + } else if ((order_type == COT_Unit) && getting_tile_shields) + return city->Body.ProductionIncome; + else + return 0; +} + +void __fastcall +patch_City_Form_open (City_Form * this, int edx, City * city, int param_2) +{ + recompute_resources_if_necessary (); + + WITH_PAUSE_FOR_POPUP { + City_Form_open (this, __, city, param_2); + } +} + +void +init_district_icons () +{ + if (is->dc_icons_img_state != IS_UNINITED) + return; + + char ss[200]; + snprintf (ss, sizeof ss, "[C3X] init_district_icons: state=%d\n", is->dc_icons_img_state); + (*p_OutputDebugStringA) (ss); + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("Districts/DistrictIncomeIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image == NULL) || + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { + (*p_OutputDebugStringA) ("[C3X] PCX file for district icons failed to load or is too small.\n"); + is->dc_icons_img_state = IS_INIT_FAILED; + goto cleanup; + } + + // Extract science icon (index 1) + Sprite_construct (&is->district_science_icon); + Sprite_slice_pcx (&is->district_science_icon, __, &pcx, 1 + 1*31, 1, 30, 30, 1, 1); + + // Extract commerce icon (index 2) + Sprite_construct (&is->district_commerce_icon); + Sprite_slice_pcx (&is->district_commerce_icon, __, &pcx, 1 + 2*31, 1, 30, 30, 1, 1); + + // Extract shield icon (index 4) + Sprite_construct (&is->district_shield_icon); + Sprite_slice_pcx (&is->district_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); + + // Extract corruption icon (index 5) + Sprite_construct (&is->district_corruption_icon); + Sprite_slice_pcx (&is->district_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); + + // Extract food icon (index 6) + Sprite_construct (&is->district_food_icon); + Sprite_slice_pcx (&is->district_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); + + // Extract food eaten icon (index 7) + Sprite_construct (&is->district_food_eaten_icon); + Sprite_slice_pcx (&is->district_food_eaten_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); + + // Extract small happiness icon (index 12) + Sprite_construct (&is->district_happiness_icon_small); + Sprite_slice_pcx (&is->district_happiness_icon_small, __, &pcx, 1 + 12*31, 1, 30, 30, 1, 1); + + // Extract small shield icon (index 13) + Sprite_construct (&is->district_shield_icon_small); + Sprite_slice_pcx (&is->district_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); + + // Extract small commerce icon (index 14) + Sprite_construct (&is->district_commerce_icon_small); + Sprite_slice_pcx (&is->district_commerce_icon_small, __, &pcx, 1 + 14*31, 1, 30, 30, 1, 1); + + // Extract small food icon (index 15: x = 1 + 15*31 = 466, width 30) + Sprite_construct (&is->district_food_icon_small); + Sprite_slice_pcx (&is->district_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); + + // Extract small science icon (index 16) + Sprite_construct (&is->district_science_icon_small); + Sprite_slice_pcx (&is->district_science_icon_small, __, &pcx, 1 + 16*31, 1, 30, 30, 1, 1); + + // Extract small culture icon (index 18) + Sprite_construct (&is->district_culture_icon_small); + Sprite_slice_pcx (&is->district_culture_icon_small, __, &pcx, 1 + 18*31, 1, 30, 30, 1, 1); + + // Load Negatives (mostly red) from here + + // Extract negative small commerce icon (index 17) + Sprite_construct (&is->district_negative_commerce_icon_small); + Sprite_slice_pcx (&is->district_negative_commerce_icon_small, __, &pcx, 1 + 17*31, 1, 30, 30, 1, 1); + + // Extract small unhappiness icon (index 19) + Sprite_construct (&is->district_unhappiness_icon_small); + Sprite_slice_pcx (&is->district_unhappiness_icon_small, __, &pcx, 1 + 19*31, 1, 30, 30, 1, 1); + + // Extract negative small shield icon (index 20) + Sprite_construct (&is->district_negative_shield_icon_small); + Sprite_slice_pcx (&is->district_negative_shield_icon_small, __, &pcx, 1 + 20*31, 1, 30, 30, 1, 1); + + // Extract negative small culture icon (index 21) + Sprite_construct (&is->district_negative_culture_icon_small); + Sprite_slice_pcx (&is->district_negative_culture_icon_small, __, &pcx, 1 + 21*31, 1, 30, 30, 1, 1); + + // Extract negative small culture icon (index 22) + Sprite_construct (&is->district_negative_food_icon_small); + Sprite_slice_pcx (&is->district_negative_food_icon_small, __, &pcx, 1 + 22*31, 1, 30, 30, 1, 1); + + // Extract negative small science icon (index 23) + Sprite_construct (&is->district_negative_science_icon_small); + Sprite_slice_pcx (&is->district_negative_science_icon_small, __, &pcx, 1 + 23*31, 1, 30, 30, 1, 1); + + is->dc_icons_img_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void __fastcall +patch_City_Form_draw (City_Form * this) +{ + // Recompute city form production rect location every time because the config might have changed. Doing it here is also easier than + // patching the constructor. + int form_top = (p_bic_data->ScreenHeight - this->Background_Image.Height) / 2; + this->Production_Storage_Indicator.top = form_top + 621 + (is->current_config.show_detailed_city_production_info ? 34 : 0); + + is->drawn_strat_resource_count = 0; + + // Make sure culture income (including from districts) is up to date before the draw event + if (is->current_config.enable_districts) + patch_City_recompute_culture_income(this->CurrentCity); + + City_Form_draw (this); + + if (is->current_config.show_detailed_city_production_info) { + City * city = this->CurrentCity; + int order_type = city->Body.Order_Type, + order_id = city->Body.Order_ID, + order_progress = City_get_order_progress (city), + order_cost = City_get_order_cost (city), + prod_rate = get_city_production_rate (city, order_type, order_id), + building_wealth = (order_type == COT_Improvement) && ((p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0); + + int turns_left, surplus; { + if (prod_rate > 0) { + turns_left = (order_cost - order_progress) / prod_rate; + if ((order_cost - order_progress) % prod_rate != 0) + turns_left++; + if (turns_left < 1) + turns_left = 1; + surplus = (turns_left * prod_rate) - (order_cost - order_progress); + } else { + turns_left = 9999; + surplus = 0; + } + } + + char line1[100]; { + if (prod_rate > 0) { + if (! building_wealth) + snprintf (line1, sizeof line1, "%s %d %s", this->Labels.To_Build, turns_left, (turns_left == 1) ? this->Labels.Single_Turn : this->Labels.Multiple_Turns); + else + snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_NEVER_COMPLETES]); + } else + snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_HALTED]); + line1[(sizeof line1) - 1] = '\0'; + } + + char line2[100]; { + if (! building_wealth) { + int percent_complete = order_cost > 0 ? ((10000 * order_progress) / order_cost + 50) / 100 : 100; + snprintf (line2, sizeof line2, "%d / %d (%d%s)", order_progress, order_cost, percent_complete, this->Labels.Percent); + } else + snprintf (line2, sizeof line2, "---"); + line2[(sizeof line2) - 1] = '\0'; + } + + char line3[100]; { + if ((! building_wealth) && (prod_rate > 0)) { + int s_per, s_rem; { + if (turns_left > 1) { + s_per = surplus / turns_left; + s_rem = surplus % turns_left; + } else { + s_per = surplus; + s_rem = 0; + } + } + char * s_lab = is->c3x_labels[CL_SURPLUS]; + if ((s_per != 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d + %d %s", s_lab, s_rem, s_per, this->Labels.Per_Turn); + else if ((s_per == 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d", s_lab, s_rem); + else if ((s_per != 0) && (s_rem == 0)) snprintf (line3, sizeof line3, "%s: %d %s", s_lab, s_per, this->Labels.Per_Turn); + else snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NONE]); + } else + snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NA]); + line3[(sizeof line3) - 1] = '\0'; + } + + Object_66C3FC * font = get_font (10, FSF_NONE); + int left = this->Production_Storage_Indicator.left, + top = this->Production_Storage_Indicator.top, + width = this->Production_Storage_Indicator.right - left; + PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line1, left, top - 42, width, strlen (line1)); + PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line2, left, top - 28, width, strlen (line2)); + PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line3, left, top - 14, width, strlen (line3)); + } + + // Draw district commerce bonuses (gold and science) + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + // Lazy load district icons + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + if (is->dc_icons_img_state != IS_OK) + return; + + City * city = this->CurrentCity; + if (city == NULL) + return; + + // Calculate district gold and science bonuses by iterating workable tiles + int district_gold = 0; + int city_civ_id = city->Body.CivID; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) continue; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + struct district_config const * cfg = &is->district_configs[district_id]; + int gold_bonus = 0; + get_effective_district_yields (inst, cfg, NULL, NULL, &gold_bonus, NULL, NULL, NULL); + district_gold += gold_bonus; + } + + Leader * leader = &leaders[city_civ_id]; + int gold_proportion = (district_gold * leader->gold_slider) / 10; + int science_proportion = (district_gold * leader->science_slider) / 10; + + // Draw district gold icons + if (gold_proportion > 0) { + Sprite * gold_sprite = &is->district_commerce_icon; + int sprite_width = gold_sprite->Width; + int sprite_height = gold_sprite->Height; + + struct tagRECT * gold_rect = &this->Gold_Income_Rect; + int total_gold = City_get_net_commerce (city, __, 2, true); + + // Calculate spacing + int spacing = sprite_width; + if ((total_gold > 1) && (total_gold * sprite_width != (gold_rect->right - gold_rect->left))) { + int rect_width = gold_rect->right - gold_rect->left; + if (rect_width <= total_gold * sprite_width) { + spacing = (rect_width - sprite_width) / (total_gold - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > sprite_width) + spacing = sprite_width; + } + } + + // Draw from right to left + int x_offset = 0; + int y_offset = 5; + for (int i = 0; i < gold_proportion && i < total_gold; i++) { + int x = gold_rect->right - x_offset - sprite_width; + int y = gold_rect->top + ((gold_rect->bottom - gold_rect->top >> 1) - + (sprite_height >> 1)) + y_offset; + + Sprite_draw (gold_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); + x_offset += spacing; + } + } + + // Draw district science icons + if (science_proportion > 0) { + Sprite * science_sprite = &is->district_commerce_icon; + int sprite_width = science_sprite->Width; + int sprite_height = science_sprite->Height; + + struct tagRECT * science_rect = &this->Science_Income_Rect; + int total_science = City_get_net_commerce (city, __, 1, true); + + // Calculate spacing + int spacing = sprite_width; + if ((total_science > 1) && (total_science * sprite_width != (science_rect->right - science_rect->left))) { + int rect_width = science_rect->right - science_rect->left; + if (rect_width <= total_science * sprite_width) { + spacing = (rect_width - sprite_width) / (total_science - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > sprite_width) + spacing = sprite_width; + } + } + + // Draw from right to left + int x_offset = 0; + int y_offset = 5; + for (int i = 0; i < science_proportion && i < total_science; i++) { + int x = science_rect->right - x_offset - sprite_width; + int y = science_rect->top + ((science_rect->bottom - science_rect->top >> 1) - + (sprite_height >> 1)) + y_offset; + + Sprite_draw (science_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); + x_offset += spacing; + } + } +} + +void __fastcall +patch_City_Form_print_production_info (City_Form *this, int edx, String256 * out_strs, int str_capacity) +{ + City_Form_print_production_info (this, __, out_strs, str_capacity); + if (is->current_config.show_detailed_city_production_info) + out_strs[1].S[0] = '\0'; +} + +int __fastcall +patch_Sprite_draw_strat_res_on_city_screen (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + if (is->current_config.compact_strategic_resource_display_on_city_screen) + pixel_x -= 13 * is->drawn_strat_resource_count + 17; + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +int __fastcall +patch_PCX_Image_do_draw_cntd_text_for_strat_res (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) +{ + if (is->current_config.compact_strategic_resource_display_on_city_screen) + x -= 13 * is->drawn_strat_resource_count + 17; + int tr = PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); + is->drawn_strat_resource_count++; + return tr; +} + +int __fastcall +patch_City_get_turns_to_build (City * this, int edx, enum City_Order_Types order_type, int order_id, bool param_3) +{ + // To fix the zero production crash, return 9999 when the city's total production rate is zero, avoiding a division by zero. That's only + // possible when producing an improvement due to negative shields from specialists. The original logic attempts to return 9999 in case of zero + // production but checks for that before including shields from specialists. + if (is->current_config.patch_zero_production_crash && (order_type == COT_Improvement)) { + + int specialist_shields = 0; + FOR_CITIZENS_IN (ci, this) + if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) + specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; + + // Return 9999 if the denominator in the base function's calculation would be zero. Note the base calc is incorrect in that it + // considers specialist shields to count toward Wealth, however we're not going to address that issue here, just stop the crash. + if (this->Body.ProductionIncome + specialist_shields <= 0) + return 9999; + } + + return City_get_turns_to_build (this, __, order_type, order_id, param_3); +} + +bool +is_below_stack_limit (Tile * tile, int civ_id, int type_id) +{ + enum UnitTypeClasses class = p_bic_data->UnitTypes[type_id].Unit_Class; + + int stack_limit = is->current_config.limit_units_per_tile[class]; + if (stack_limit <= 0) + return true; + + if (is->current_config.exclude_cities_from_units_per_tile_limit && + get_city_ptr (tile->CityID) != NULL) + return true; + + if (itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, type_id, 0)) + return true; + + FOR_UNITS_ON (uti, tile) { + // If there is a foreign unit on the tile then consider it as being below the stack limit. This ensures that the stack limit doesn't + // block combat between players. + if (uti.unit->Body.CivID != civ_id) + return true; + + int uti_type_id = uti.unit->Body.UnitTypeID; + if ((uti.unit->Body.Container_Unit < 0) && + (class == p_bic_data->UnitTypes[uti_type_id].Unit_Class) && + ! itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, uti_type_id, 0)) { + stack_limit -= 1; + if (stack_limit <= 0) + return false; + } + } + return true; +} + +// Returns the ID of the civ this move is trespassing against, or 0 if it's not trespassing. +int +check_trespassing (int civ_id, Tile * from, Tile * to) +{ + int from_territory_id = from->vtable->m38_Get_Territory_OwnerID (from), + to_territory_id = to ->vtable->m38_Get_Territory_OwnerID (to); + if ((civ_id > 0) && + (to_territory_id != civ_id) && + (to_territory_id > 0) && + (to_territory_id != from_territory_id) && + (! leaders[civ_id].At_War[to_territory_id]) && + ((leaders[civ_id].Relation_Treaties[to_territory_id] & 2) == 0)) // Check right of passage + return to_territory_id; + else + return 0; +} + +bool +is_allowed_to_trespass (Unit * unit) +{ + int type_id = unit->Body.UnitTypeID; + if ((type_id >= 0) && (type_id < p_bic_data->UnitTypeCount)) { + UnitType * type = &p_bic_data->UnitTypes[type_id]; + return UnitType_has_ability (type, __, UTA_Hidden_Nationality) || UnitType_has_ability (type, __, UTA_Invisible); + } else + return false; +} + +bool +get_tile_district_impassibility (Tile * tile, bool * out_impassible, bool * out_impassible_to_wheeled) +{ + if (out_impassible != NULL) + *out_impassible = false; + if (out_impassible_to_wheeled != NULL) + *out_impassible_to_wheeled = false; + + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + if (! district_is_complete (tile, inst->district_id)) + return false; + + if (inst->district_id == NATURAL_WONDER_DISTRICT_ID) { + if (! is->current_config.enable_natural_wonders) + return false; + int natural_id = inst->natural_wonder_info.natural_wonder_id; + if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) + return false; + if (out_impassible != NULL) + *out_impassible = is->natural_wonder_configs[natural_id].impassible; + if (out_impassible_to_wheeled != NULL) + *out_impassible_to_wheeled = is->natural_wonder_configs[natural_id].impassible_to_wheeled; + return true; + } + + if (! is->current_config.enable_districts) + return false; + if ((inst->district_id < 0) || (inst->district_id >= is->district_count)) + return false; + + if (out_impassible != NULL) + *out_impassible = is->district_configs[inst->district_id].impassible; + if (out_impassible_to_wheeled != NULL) + *out_impassible_to_wheeled = is->district_configs[inst->district_id].impassible_to_wheeled; + return true; +} + +AdjacentMoveValidity __fastcall +patch_Unit_can_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, int param_2) +{ + AdjacentMoveValidity base_validity = Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2); + + if (is->current_config.enable_districts) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + Tile * dest = tile_at (nx, ny); + + // Let workers step onto coast tiles when the config flag is enabled (base logic treats this as an invalid sea move) + if (is->current_config.workers_can_enter_coast && is_worker (this) && + ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { + if ((dest != NULL) && + dest->vtable->m35_Check_Is_Water (dest) && + (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) + base_validity = AMV_OK; + } + + // Allow land units to enter bridge tiles + if (is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && + ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { + if ((dest != NULL) && (dest != p_null_tile)) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { + base_validity = AMV_OK; + } + } + } + + // Allow naval units to enter completed canal tiles + if (is->current_config.enable_canal_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && + ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { + if ((dest != NULL) && (dest != p_null_tile)) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { + base_validity = AMV_OK; + } + } + } + + if ((base_validity == AMV_OK) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { + if ((dest != NULL) && (dest != p_null_tile) && Tile_has_city (dest)) + return AMV_INVALID_SEA_MOVE; + } + } + + // Apply unit count per tile limit + int type_id = this->Body.UnitTypeID; + if ((base_validity == AMV_OK) && (is->current_config.limit_units_per_tile[p_bic_data->UnitTypes[type_id].Unit_Class] > 0)) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + if (! is_below_stack_limit (tile_at (nx, ny), this->Body.CivID, type_id)) + return AMV_CANNOT_PASS_BETWEEN; + } + + // Apply trespassing restriction + if (is->current_config.disallow_trespassing && (base_validity == AMV_OK)) { + Tile * from = tile_at (this->Body.X, this->Body.Y); + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + int trespasses_against_civ_id = check_trespassing (this->Body.CivID, from, tile_at (nx, ny)); + if ((trespasses_against_civ_id > 0) && (! is_allowed_to_trespass (this))) + // The tile might be occupied by a unit belonging to a civ other than the one that owns the territory (against whom we'd be + // trespassing). In this case we must forbid the move entirely since TRIGGERS_WAR will not stop it if we're at war with the + // occupying civ. This fixes a bug where units could trespass by attacking an enemy unit across a border. They would then get + // stuck halfway between tiles if they won. + return (trespasses_against_civ_id == get_tile_occupier_id (nx, ny, this->Body.CivID, false)) ? AMV_TRIGGERS_WAR : AMV_CANNOT_PASS_BETWEEN; + } + + return base_validity; +} + +bool +great_wall_blocks_civ (Tile * tile, int civ_id) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_great_wall_districts || + ! is->current_config.great_wall_districts_impassible_by_others) + return false; + + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (owner_id <= 0) + return false; + if (owner_id == civ_id) + return false; + if ((civ_id > 0) && ((leaders[civ_id].Relation_Treaties[owner_id] & 2) != 0)) // 2 = right of passage + return false; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID)) + return false; + + if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) + return false; + + if (district_is_obsolete_for_civ (GREAT_WALL_DISTRICT_ID, civ_id)) + return false; + + return true; +} + +int __fastcall +patch_Trade_Net_get_movement_cost (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned flags, int neighbor_index, Trade_Net_Distance_Info * dist_info) +{ + if (is->is_computing_city_connections && // if this call came while rebuilding the trade network AND + (is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL) && // Trade Net X is set up AND + (unit == NULL) && ((flags == 0x1009) || (flags == 0x9))) // this call can be accelerated by TNX + return is->get_move_cost_for_sea_trade (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags, neighbor_index, dist_info); + + int base_cost = Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, neighbor_index, dist_info); + + bool districts_enabled = is->current_config.enable_districts; + if (districts_enabled) { + Tile * to = tile_at (to_x, to_y); + bool to_valid = (to != NULL) && (to != p_null_tile); + struct district_instance * to_inst = NULL; + bool to_inst_complete = false; + if (to_valid) { + to_inst = get_district_instance (to); + if (to_inst != NULL) + to_inst_complete = district_is_complete (to, to_inst->district_id); + } + + if ((unit != NULL) && great_wall_blocks_civ (to, unit->Body.CivID)) + return -1; + if ((unit != NULL) && to_valid) { + bool impassible = false; + bool impassible_to_wheeled = false; + if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { + if (impassible) + return -1; + if (impassible_to_wheeled && Unit_has_ability (unit, __, UTA_Wheeled)) { + Tile * from = tile_at (from_x, from_y); + bool connected_by_road = (from != NULL) && (to != NULL) && + (from->vtable->m25_Check_Roads (from, __, 0) != 0) && + (to->vtable->m25_Check_Roads (to, __, 0) != 0); + if (! connected_by_road) + return -1; + } + } + } + + // Let the pathfinder consider coastal tiles reachable for workers when the config flag is on + if (is->current_config.workers_can_enter_coast && + (base_cost < 0) && (unit != NULL) && is_worker (unit) && + to_valid && + to->vtable->m35_Check_Is_Water (to) && + (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) + base_cost = Unit_get_max_move_points (unit); + + // Let the pathfinder consider bridge tiles reachable for land units + if (is->current_config.enable_bridge_districts && + (base_cost < 0) && (unit != NULL) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == BRIDGE_DISTRICT_ID)) + base_cost = Unit_get_max_move_points (unit); + + // Let the pathfinder consider canal tiles reachable for naval units + if (is->current_config.enable_canal_districts && + (base_cost < 0) && (unit != NULL) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == CANAL_DISTRICT_ID)) + base_cost = Unit_get_max_move_points (unit); + + // Treat roads/rails on bridge districts like land roads/rails for movement cost. + if ((unit != NULL) && + is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land)) { + Tile * from = tile_at (from_x, from_y); + if ((from != NULL) && (from != p_null_tile) && to_valid) { + struct district_instance * from_inst = get_district_instance (from); + bool from_bridge = (from_inst != NULL) && + (from_inst->district_id == BRIDGE_DISTRICT_ID) && + district_is_complete (from, from_inst->district_id); + bool to_bridge = (to_inst != NULL) && + to_inst_complete && + (to_inst->district_id == BRIDGE_DISTRICT_ID); + if (from_bridge || to_bridge) { + bool from_rail = from->vtable->m23_Check_Railroads (from, __, 0) != 0; + bool to_rail = to->vtable->m23_Check_Railroads (to, __, 0) != 0; + bool from_road = from->vtable->m25_Check_Roads (from, __, 0) != 0; + bool to_road = to->vtable->m25_Check_Roads (to, __, 0) != 0; + if (from_rail && to_rail) + base_cost = 0; + else if (from_road && to_road) + base_cost = 1; + } + } + } + + if ((unit != NULL) && + (base_cost >= 0) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && + to_valid && Tile_has_city (to)) + return -1; + } + + // Apply unit count per tile limit + if ((unit != NULL) && ! is_below_stack_limit (tile_at (to_x, to_y), unit->Body.CivID, unit->Body.UnitTypeID)) + return -1; + + // Apply trespassing restriction + if (is->current_config.disallow_trespassing && + check_trespassing (civ_id, tile_at (from_x, from_y), tile_at (to_x, to_y)) && + ((unit == NULL) || (! is_allowed_to_trespass (unit)))) + return -1; + + // Adjust movement cost to enforce limited railroad movement + if ((is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0)) { + if ((unit != NULL) && (base_cost == 0)) { // Railroad move + if (! is->current_config.limited_railroads_work_like_fast_roads) { // If Civ 4 style RR, scale cost by type's moves + int type_moves_available = patch_Unit_get_max_move_points (unit) / p_bic_data->General.RoadsMovementRate; + return type_moves_available * is->railroad_mp_cost_per_move; + } else + return is->railroad_mp_cost_per_move; + } else if (base_cost == 1) // Road move + return is->road_mp_cost; + } + + return base_cost; +} + +int __fastcall +patch_Trade_Net_set_unit_path (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) +{ + int tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); + + bool may_require_length_fix = (is->current_config.limit_railroad_movement > 0) && // if railroad movement is limited AND + (tr > 0) && (out_path_length_in_mp != NULL) && // path was found AND caller wants to know its length AND + (unit != NULL); // the path is for an actual unit + + // We might have to correct the path length returned by the base game's pathfinder. This occurs when railroad movement is limited and the + // unit's total MP exceeds what can be stored in a one-byte integer. The cause of the incorrect length is that the pathfinder internally + // stores the remaining moves at each node of the search in a single byte. This correction fixes the bug (reported several times) that ETAs + // shown in the interface are wrong. + if (may_require_length_fix && (patch_Unit_get_max_move_points (unit) > 255)) { // Need to recompute path length if unit's total MP can overflow a uint8 + + // First memoize the cost of taking each step along the path. This must be done separately because the pathfinder's internal data only + // lets us traverse the path backwards. + { + // Must pass cached "distance info" to Trade_Net::get_movement_cost. Trade_Net stores two sets of cached data, which one was + // used depends on the flags. I believe one is intended to be used for city trade connections and the other for unit movement. + Trade_Net_Distance_Info * dist_info = (flags & 1) ? this->Data2 : this->Data4; + + clear_memo (); + int x = to_x, y = to_y; + do { + // "flags & 1" again determines whether Data2 or Data4 was used. + enum direction dir = Trade_Net_get_direction_from_internal_map (this, __, x, y, flags & 1); + if (dir == DIR_ZERO) + break; + + int prev_x, prev_y; { + int dx, dy; + neighbor_index_to_diff (dir, &dx, &dy); + prev_x = x + dx; prev_y = y + dy; + wrap_tile_coords (&p_bic_data->Map, &prev_x, &prev_y); + } + + memoize (patch_Trade_Net_get_movement_cost (this, __, prev_x, prev_y, x, y, unit, civ_id, flags, reverse_dir (dir), dist_info)); + x = prev_x; y = prev_y; + } while (! ((x == from_x) && (y == from_y))); + } + + // Now walk the path forwards tracking how much MP the unit would spend. We must be aware that the unit can't spend more MP than it + // has. For example, if a unit with 1 move walks onto an unimproved mountain, that effectively costs only 1 move, not 3. + int mp_remaining = patch_Unit_get_max_move_points (unit) - unit->Body.Moves, + mp_spent = 0; + for (int n = is->memo_len - 1; n >= 0; n--) { + int cost = is->memo[n]; + if (cost < mp_remaining) { + mp_spent += cost; + mp_remaining -= cost; + } else { + mp_spent += mp_remaining; + mp_remaining = patch_Unit_get_max_move_points (unit); + } + } + *out_path_length_in_mp = mp_spent; + + // Also, if this is a move between adjacent tiles, make sure the path length doesn't exceed the unit's remaining MP. Otherwise, the game may + // erroneously show an ETA of >1 turn. + } else if (may_require_length_fix && are_tiles_adjacent (from_x, from_y, to_x, to_y)) + *out_path_length_in_mp = not_above (patch_Unit_get_max_move_points (unit) - unit->Body.Moves, *out_path_length_in_mp); + + return tr; +} + +int __fastcall +patch_Trade_Net_set_unit_path_to_find_sea_route (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) +{ + // Accelerate this call with TNX if possible + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { + bool route_exists = is->try_drawing_sea_trade_route (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags); + return route_exists ? 1 : 0; + } else + return Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); +} + +// Renames this leader and their civ based on their era. Era-specific names come from the config file. If this leader has a custom name set by the +// human player, this method does nothing. +void +apply_era_specific_names (Leader * leader) +{ + int leader_bit = 1 << leader->ID; + Race * race = &p_bic_data->Races[leader->RaceID]; + + struct replaceable_name { + char * base_name; + int * tracking_bits; + char * buf; + int buf_size; + } replaceable_names[] = { + {race->vtable->GetAdjectiveName (race), &is->aliased_civ_adjective_bits , leader->tribe_customization.civ_adjective , sizeof leader->tribe_customization.civ_adjective}, + {race->vtable->GetSingularName (race) , &is->aliased_civ_noun_bits , leader->tribe_customization.civ_noun , sizeof leader->tribe_customization.civ_noun}, + {race->vtable->GetCountryName (race) , &is->aliased_civ_formal_name_bits, leader->tribe_customization.civ_formal_name, sizeof leader->tribe_customization.civ_formal_name} + }; + + // Apply replacements to civ noun, adjective, and formal name + for (int n = 0; n < ARRAY_LEN (replaceable_names); n++) { + struct replaceable_name * repl = &replaceable_names[n]; + if ((*repl->tracking_bits & leader_bit) || (repl->buf[0] == '\0')) { + char * replacement = NULL; + if (leader->Era < ERA_ALIAS_LIST_CAPACITY) + // Search through the list of aliases in reverse order so that, if the same key was listed multiple times, the last + // appearance overrides the earlier ones. This is important b/c when configs are loaded, their aliases get appended to + // the list. + for (int k = is->current_config.count_civ_era_alias_lists - 1; k >= 0; k--) { + struct civ_era_alias_list * list = &is->current_config.civ_era_alias_lists[k]; + if (strcmp (list->key, repl->base_name) == 0) { + replacement = list->aliases[leader->Era]; + break; + } + } + if (replacement != NULL) { + strncpy (repl->buf, replacement, repl->buf_size); + repl->buf[repl->buf_size - 1] = '\0'; + *repl->tracking_bits |= leader_bit; + } else { + repl->buf[0] = '\0'; + *repl->tracking_bits &= ~leader_bit; + } + } + } + + // Apply replacement to leader name, gender, and title + if ((is->aliased_leader_name_bits & leader_bit) || (leader->tribe_customization.leader_name[0] == '\0')) { + char * base_name = race->vtable->GetLeaderName (race); + char * replacement_name = NULL; + char * replacement_title = NULL; + int replacement_gender; // Only used if replacement_name is + if (leader->Era < ERA_ALIAS_LIST_CAPACITY) + for (int k = is->current_config.count_leader_era_alias_lists - 1; k >= 0; k--) { + struct leader_era_alias_list * list = &is->current_config.leader_era_alias_lists[k]; + if (strcmp (list->key, base_name) == 0) { + replacement_name = list->aliases[leader->Era]; + replacement_title = list->titles[leader->Era]; + replacement_gender = (list->gender_bits >> leader->Era) & 1; + break; + } + } + if (replacement_name != NULL) { + TribeCustomization * tc = &leader->tribe_customization; + strncpy (tc->leader_name, replacement_name, sizeof tc->leader_name); + tc->leader_name[(sizeof tc->leader_name) - 1] = '\0'; + tc->leader_gender = replacement_gender; + is->aliased_leader_name_bits |= leader_bit; + + // If this replacement name has a special title and this player does not have a custom title set, replace the title. + if ((replacement_title != NULL) && ((is->aliased_leader_title_bits & leader_bit) || (tc->leader_title[0] == '\0'))) { + strncpy (tc->leader_title, replacement_title, sizeof tc->leader_title); + tc->leader_title[(sizeof tc->leader_title) - 1] = '\0'; + is->aliased_leader_title_bits |= leader_bit; + + // If the current name has no title and the player's title was previously replaced, undo the replacement. + } else if ((replacement_title == NULL) && (is->aliased_leader_title_bits & leader_bit)) { + leader->tribe_customization.leader_title[0] = '\0'; + is->aliased_leader_title_bits &= ~leader_bit; + } + } else { + leader->tribe_customization.leader_name[0] = '\0'; + // Don't need to clear custom leader gender since it's not used unless a custom name was set + is->aliased_leader_name_bits &= ~leader_bit; + + // Remove title replacement if present + if (is->aliased_leader_title_bits & leader_bit) { + leader->tribe_customization.leader_title[0] = '\0'; + is->aliased_leader_title_bits &= ~leader_bit; + } + } + } +} + +int __cdecl +patch_do_save_game (char const * file_path, char param_2, GUID * guid) +{ + // Do not save the modified road movement rate, if it was modified to limit railroad movement + int restore_rmr = (is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0); + int rmr; + if (restore_rmr) { + rmr = p_bic_data->General.RoadsMovementRate; + p_bic_data->General.RoadsMovementRate = is->saved_road_movement_rate; + } + + // Do not save the modified barb culture group ID + int restore_barb_culture_group = is->current_config.enable_city_capture_by_barbarians && (is->saved_barb_culture_group >= 0); + int barb_culture; + if (restore_barb_culture_group) { + barb_culture = p_bic_data->Races[leaders[0].RaceID].CultureGroupID; + p_bic_data->Races[leaders[0].RaceID].CultureGroupID = is->saved_barb_culture_group; + } + + // Do not save names that were replaced with era-specific versions + for (int n = 0; n < 32; n++) { + Leader * leader = &leaders[n]; + int leader_bit = 1 << leader->ID; + if (is->aliased_civ_noun_bits & leader_bit) leader->tribe_customization.civ_noun [0] = '\0'; + if (is->aliased_civ_adjective_bits & leader_bit) leader->tribe_customization.civ_adjective [0] = '\0'; + if (is->aliased_civ_formal_name_bits & leader_bit) leader->tribe_customization.civ_formal_name[0] = '\0'; + if (is->aliased_leader_name_bits & leader_bit) leader->tribe_customization.leader_name [0] = '\0'; + if (is->aliased_leader_title_bits & leader_bit) leader->tribe_customization.leader_title [0] = '\0'; + } + is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; + + // Do not save unit types with the charm bits cleared if they were cleared by convertion to PTW targeting. The special actions field must not + // include the top category bits that are part of the UCV_* enum + for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { + UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; + converted_type->Special_Actions |= (0x00FFFFFF & UCV_Charm_Bombard); + } + + int tr = do_save_game (file_path, param_2, guid); + + if (restore_rmr) + p_bic_data->General.RoadsMovementRate = rmr; + if (restore_barb_culture_group) + p_bic_data->Races[leaders[0].RaceID].CultureGroupID = barb_culture; + + // Reapply era aliases + for (int n = 0; n < 32; n++) + if (*p_player_bits & (1 << n)) + apply_era_specific_names (&leaders[n]); + + // Reclear charm bits on converted types + for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { + UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; + converted_type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); + } + + return tr; +} + +void +record_unit_type_alt_strategy (int type_id) +{ + int ai_strat_index; { + int ai_strat_bits = p_bic_data->UnitTypes[type_id].AI_Strategy; + if ((ai_strat_bits & ai_strat_bits - 1) != 0) // Sanity check: must only have one strat (one bit) set + return; + ai_strat_index = 0; + while ((ai_strat_bits & 1) == 0) { + ai_strat_index++; + ai_strat_bits >>= 1; + } + } + + itable_insert (&is->unit_type_alt_strategies, type_id, ai_strat_index); +} + +void +append_improv_id_to_list (struct improv_id_list * list, int id) +{ + reserve (sizeof list->items[0], (void **)&list->items, &list->capacity, list->count); + list->items[list->count] = id; + list->count += 1; +} + +unsigned __fastcall +patch_load_scenario (BIC * this, int edx, char * param_1, unsigned * param_2) +{ + int ret_addr = ((int *)¶m_1)[-1]; + + // Destroy TNX cache from previous map. A new one will be created when needed. + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { + is->destroy_tnx_cache (is->tnx_cache); + is->tnx_cache = NULL; + } + + unsigned tr = load_scenario (this, __, param_1, param_2); + char * scenario_path = param_1; + + // There are two cases when load_scenario is called that we don't want to run our own code. These are (1) when the scenario is loaded to + // generate a preview (map, etc.) for the "Civ Content" or "Conquests" menu and (2) when the function is called recursively. The recursive + // call is done, I believe, only when loading saves using the default rules. The game first tries to load custom rules then falls back on + // loading the default rules. In any case, we want to ignore that call so we don't run the same code twice. + if ((ret_addr == ADDR_LOAD_SCENARIO_PREVIEW_RETURN) || (ret_addr == ADDR_LOAD_SCENARIO_RESUME_SAVE_2_RETURN)) + return tr; + + reset_to_base_config (); + load_config ("default.c3x_config.ini", 1); + char * scenario_config_file_name = "scenario.c3x_config.ini"; + char * scenario_config_path = BIC_get_asset_path (p_bic_data, __, scenario_config_file_name, false); + + // BIC_get_asset_path returns the file name when it can't find the file + if (0 != strcmp (scenario_config_file_name, scenario_config_path)) { + load_config (scenario_config_path, 0); + } + load_config ("custom.c3x_config.ini", 1); + apply_machine_code_edits (&is->current_config, false); + + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + reset_district_state (true); + load_districts_config (); + } + + // Initialize Trade Net X + if (is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_UNINITED)) { + char path[MAX_PATH]; + snprintf (path, sizeof path, "%s\\Trade Net X\\TradeNetX.dll", is->mod_rel_dir); + path[(sizeof path) - 1] = '\0'; + is->trade_net_x = LoadLibraryA (path); + if (is->trade_net_x != NULL) { + is->set_exe_version = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_exe_version"); + is->create_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "create_tnx_cache"); + is->destroy_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "destroy_tnx_cache"); + is->set_up_before_building_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_up_before_building_network"); + is->get_move_cost_for_sea_trade = (void *)(*p_GetProcAddress) (is->trade_net_x, "get_move_cost_for_sea_trade"); + is->flood_fill_road_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "flood_fill_road_network"); + is->try_drawing_sea_trade_route = (void *)(*p_GetProcAddress) (is->trade_net_x, "try_drawing_sea_trade_route"); + + is->set_exe_version (exe_version_index); + + // Run tests + if (0) { + int (__stdcall * test) () = (void *)(*p_GetProcAddress) (is->trade_net_x, "test"); + int failed_test_count = test (); + if (failed_test_count > 0) + MessageBoxA (NULL, "Failed some tests in Trade Net X!", NULL, MB_ICONWARNING); + else + MessageBoxA (NULL, "All tests in Trade Net X passed.", "Success", MB_ICONINFORMATION); + } + + is->tnx_init_state = IS_OK; + } else { + MessageBoxA (NULL, "Failed to load Trade Net X!", NULL, MB_ICONERROR); + is->tnx_init_state = IS_INIT_FAILED; + } + + // Deinitialize Trade Net X + } else if ((! is->current_config.enable_trade_net_x) && (is->tnx_init_state == IS_OK)) { + FreeLibrary (is->trade_net_x); + is->trade_net_x = NULL; + is->tnx_init_state = IS_UNINITED; + } + + // This scenario might use different mod art assets than the old one + deinit_stackable_command_buttons (); + deinit_disabled_command_buttons (); + deinit_trade_scroll_buttons (); + deinit_unit_rcm_icons (); + deinit_red_food_icon (); + deinit_large_minimap_frame (); + if (is->tile_already_worked_zoomed_out_sprite_init_state != IS_UNINITED) { + enum init_state * state = &is->tile_already_worked_zoomed_out_sprite_init_state; + if (*state == IS_OK) { + Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; + sprite->vtable->destruct (sprite, __, 0); + } + *state = IS_UNINITED; + } + + // Need to clear this since the resource count might have changed + if (is->extra_available_resources != NULL) { + free (is->extra_available_resources); + is->extra_available_resources = NULL; + is->extra_available_resources_capacity = 0; + } + + // Similarly, these don't carry over between games + for (int n = 0; n < 32; n++) + is->interceptor_reset_lists[n].count = 0; + is->replay_for_players = 0; + table_deinit (&is->extra_defensive_bombards); + table_deinit (&is->airdrops_this_turn); + table_deinit (&is->unit_transport_ties); + is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; + is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; + is->last_selected_unit.ptr = NULL; + table_deinit (&is->waiting_units); + is->have_loaded_waiting_units = false; + + // Clear extra city improvement bits + FOR_TABLE_ENTRIES (tei, &is->extra_city_improvs) + free ((void *)tei.value); + table_deinit (&is->extra_city_improvs); + + // Clear unit type counts + for (int n = 0; n < 32; n++) + table_deinit (&is->unit_type_counts[n]); + is->unit_type_count_init_bits = 0; + + // Clear last city founding turn numbers + for (int n = 0; n < 32; n++) + is->turn_no_of_last_founding_for_settler_perfume[n] = -1; + + // Load resources.pcx + { + PCX_Image * rs = is->resources_sheet; + if (rs != NULL) + rs->vtable->destruct (rs, __, 0); + else + rs = malloc (sizeof *rs); + memset (rs, 0, sizeof *rs); + PCX_Image_construct (rs); + + char * resources_pcx_path = BIC_get_asset_path (p_bic_data, __, "Art\\resources.pcx", true); + PCX_Image_read_file (rs, __, resources_pcx_path, NULL, 0, 0x100, 2); + is->resources_sheet = rs; + } + + // Recreate table of alt strategies mapping duplicates to their strategies + table_deinit (&is->unit_type_alt_strategies); + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; + if (alt_for_id >= 0) { + record_unit_type_alt_strategy (n); + record_unit_type_alt_strategy (alt_for_id); // Record the original too so we know it has alternatives + } + } + + // Recreate table of duplicates mapping unit types to the next duplicate + table_deinit (&is->unit_type_duplicates); + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; + if (alt_for_id >= 0) { + + // Find the type ID of the last duplicate in the list. alt_for_id refers to the original unit that was duplicated possibly + // multiple times. Begin searching there and, each time we find another duplicate, use its ID to continue the search. When + // we're done last_dup_id will be set to whichever ID in the list of duplicates is not already associated with another. + int last_dup_id = alt_for_id; { + int next; + while (itable_look_up (&is->unit_type_duplicates, last_dup_id, &next)) + last_dup_id = next; + } + + // Add this unit type to the end of the list of duplicates + itable_insert (&is->unit_type_duplicates, last_dup_id, n); + } + } + + // Convert charm-flagged units to using PTW targeting if necessary + if (is->current_config.charm_flag_triggers_ptw_like_targeting) { + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if (type->Special_Actions & UCV_Charm_Bombard) { + // Also add it to the list of converted types + reserve (sizeof is->charmed_types_converted_to_ptw_arty[0], // item size + (void **)&is->charmed_types_converted_to_ptw_arty, // ptr to items + &is->charmed_types_converted_to_ptw_arty_capacity, // ptr to capacity + is->count_charmed_types_converted_to_ptw_arty); // count + is->charmed_types_converted_to_ptw_arty[is->count_charmed_types_converted_to_ptw_arty] = n; + is->count_charmed_types_converted_to_ptw_arty += 1; + + // Add this type ID to the table + itable_insert (&is->current_config.ptw_arty_types, n, 1); + + // Clear the charm flag, taking care not to clear the category bit. This is necessary for the PTW targeting to work + // since the logic to implement it only applies to the non-charm code path. It wouldn't make sense to have both charm + // attack and PTW targeting anyway, since charm attack already works that way vs cities. + type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); + } + } + } + + // Pick out which resources are used as mill inputs + if (is->mill_input_resource_bits) + free (is->mill_input_resource_bits); + is->mill_input_resource_bits = calloc (1, 1 + p_bic_data->ResourceTypeCount / 8); + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + for (int k = 0; k < 2; k++) { + int resource_id = (&p_bic_data->Improvements[mill->improv_id].Resource1ID)[k]; + if ((resource_id >= 0) && (resource_id < p_bic_data->ResourceTypeCount)) { + byte bit = 1 << (resource_id & 7); + is->mill_input_resource_bits[resource_id>>3] |= bit; + } + } + } + + // Recreate lists of water & air trade improvements + is->water_trade_improvs .count = 0; + is->air_trade_improvs .count = 0; + is->combat_defense_improvs.count = 0; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + enum ImprovementTypeFlags flags = p_bic_data->Improvements[n].ImprovementFlags; + if (flags & ITF_Allows_Water_Trade) append_improv_id_to_list (&is->water_trade_improvs , n); + if (flags & ITF_Allows_Air_Trade) append_improv_id_to_list (&is->air_trade_improvs , n); + if (p_bic_data->Improvements[n].Combat_Defence != 0) append_improv_id_to_list (&is->combat_defense_improvs, n); + } + + // Set up for limiting railroad movement + if (is->current_config.limit_railroad_movement > 0) { + // Bit 0x200 of field_484 indicates whether or not the last call to load_scenario loaded the General section of the BIQ. The game will + // skip loading of that section and many others when loading a game with the same standard scenario as the then-current one, common + // when loading an autosave. + bool loaded_general = (this->field_848 & 0x200) != 0; + + // For the base RMR, use the saved rate if it's valid and we haven't loaded a new rate as part of the General section. Otherwise, use + // the rate from that section. + int base_rmr = (loaded_general || is->saved_road_movement_rate <= 0) ? p_bic_data->General.RoadsMovementRate : is->saved_road_movement_rate; + + int g = gcd (base_rmr, is->current_config.limit_railroad_movement); // Scale down all MP costs by this common divisor to help against + // overflow of 8-bit integers inside the pathfinder. + is->saved_road_movement_rate = base_rmr; + p_bic_data->General.RoadsMovementRate = base_rmr * is->current_config.limit_railroad_movement / g; // Full move in MP + is->road_mp_cost = is->current_config.limit_railroad_movement / g; + is->railroad_mp_cost_per_move = base_rmr / g; + } else { + is->saved_road_movement_rate = -1; + is->road_mp_cost = 1; + is->railroad_mp_cost_per_move = 0; + } + + // If barb city capturing is enabled and the barbs have the non-existent "none" culture group (index -1), switch them to the first real + // culture group. The "none" group produces corrupt graphics and crashes. + int * barb_culture_group = &p_bic_data->Races[leaders[0].RaceID].CultureGroupID; + if (is->current_config.enable_city_capture_by_barbarians && (*barb_culture_group < 0)) { + is->saved_barb_culture_group = *barb_culture_group; + *barb_culture_group = 0; + } else + is->saved_barb_culture_group = -1; + + // Clear old alias bits + is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; + + // Apply no AI patrol override + if (is->current_config.override_no_ai_patrol == NAPO_ZERO) + *p_allow_ai_patrol = true; + else if (is->current_config.override_no_ai_patrol == NAPO_ONE) + *p_allow_ai_patrol = false; + else if (is->current_config.override_no_ai_patrol == NAPO_NONE) + *p_allow_ai_patrol = 0 == get_int_from_conquests_ini ("NoAIPatrol", 1, 0); + + // Clear day/night cycle vars and deindex sprite proxies, if necessary. + if (is->current_config.day_night_cycle_mode != DNCM_OFF) { + is->day_night_cycle_unstarted = true; + is->current_day_night_cycle = 12; + if (is->day_night_cycle_img_proxies_indexed) { + deindex_day_night_image_proxies (); + } + } + + return tr; +} + +void __fastcall +patch_Leader_recompute_auto_improvements (Leader * this) +{ + is->leader_param_for_patch_get_wonder_city_id = this; + Leader_recompute_auto_improvements (this); +} + +int __fastcall +patch_Game_get_wonder_city_id (Game * this, int edx, int wonder_improvement_id) +{ + int ret_addr = ((int *)&wonder_improvement_id)[-1]; + if ((is->current_config.enable_free_buildings_from_small_wonders) && (ret_addr == ADDR_SMALL_WONDER_FREE_IMPROVS_RETURN)) { + Leader * leader = is->leader_param_for_patch_get_wonder_city_id; + Improvement * improv = &p_bic_data->Improvements[wonder_improvement_id]; + if ((improv->Characteristics & ITC_Small_Wonder) != 0) { + // Need to check if Small_Wonders array is NULL b/c recompute_auto_improvements gets called with leaders that are absent/dead. + return (leader->Small_Wonders != NULL) ? leader->Small_Wonders[wonder_improvement_id] : -1; + } + } + return Game_get_wonder_city_id (this, __, wonder_improvement_id); +} + +int __fastcall +patch_Main_Screen_Form_handle_key_up (Main_Screen_Form * this, int edx, int virtual_key_code) +{ + if ((virtual_key_code & 0xFF) == VK_CONTROL) { + patch_Main_GUI_set_up_unit_command_buttons (&this->GUI); + + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + } + + return Main_Screen_Form_handle_key_up (this, __, virtual_key_code); +} + +char __fastcall +patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing) +{ + char tr; + bool is_ai = ((*p_human_player_bits & (1 << this->ID)) == 0); + bool skip_replacement_logic = + (p_main_screen_form->Player_CivID == this->ID) && is->current_config.skip_repeated_tile_improv_replacement_asks; + + Tile * tile = tile_at (tile_x, tile_y); + + // If districts on, short-circuit any potential AI workers accidentally building in another civ's territory. + if (is->current_config.enable_districts && is_ai && (tile != NULL) && (tile != p_null_tile)) { + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (territory_owner > 0 && territory_owner != this->ID) + return 0; + } + + // Check if AI is trying to change a district tile (before calling vanilla logic) + if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && + is_ai) { + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { + int district_id = inst->district_id; + bool allow_ai_change = false; + + // Allow AI to modify obsolete districts + if (district_is_obsolete_for_civ (district_id, this->ID)) + allow_ai_change = true; + + // Allow if district could be used as a prerequisite for other buildable districts + if (! allow_ai_change) { + for (int other_id = 0; other_id < is->district_count; other_id++) { + if (other_id == district_id) + continue; + struct district_config const * other_cfg = &is->district_configs[other_id]; + if (! other_cfg->has_buildable_on_districts) + continue; + for (int i = 0; i < other_cfg->buildable_on_district_id_count; i++) { + if (other_cfg->buildable_on_district_ids[i] == district_id) { + if (leader_can_build_district (this, other_id)) + allow_ai_change = true; + break; + } + } + if (allow_ai_change) + break; + } + } + + // Allow AI to build roads/rails on bridge districts + if (! allow_ai_change && (district_id == BRIDGE_DISTRICT_ID) && + (job == WJ_Build_Road || job == WJ_Build_Railroad)) + allow_ai_change = true; + + // For Wonder Districts: check if unused (can be replaced) + if (! allow_ai_change && is->current_config.enable_wonder_districts && (district_id == WONDER_DISTRICT_ID)) { + struct wonder_district_info * info = get_wonder_district_info (tile); + + // If there's a reservation (wonder being built) or completed wonder, block replacement + if (info != NULL && info->state != WDS_UNUSED) + return 0; + + // Wonder district is unused - fall through to normal tech checks + } + else if (! allow_ai_change && is->current_config.enable_natural_wonders && (district_id == NATURAL_WONDER_DISTRICT_ID)) { + return 0; + } + else if (! allow_ai_change) { + // For all other district types: AI should not change them + return 0; + } + } + } + } + + if (! skip_replacement_logic) + tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); + else if (is->have_job_and_loc_to_skip && + (is->to_skip.job == job) && (is->to_skip.tile_x == tile_x) && (is->to_skip.tile_y == tile_y)) + tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, 0); + else { + is->show_popup_was_called = 0; + tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); + if (is->show_popup_was_called && tr) { // Check that the popup was shown and the player chose to replace + is->to_skip = (struct worker_job_and_location) { .job = job, .tile_x = tile_x, .tile_y = tile_y }; + is->have_job_and_loc_to_skip = 1; + } + } + + if (! tr && is->current_config.enable_districts && (job == WJ_Build_Mines)) { + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && + inst->district_id >= 0 && inst->district_id < is->district_count && + ! tile->vtable->m35_Check_Is_Water (tile) && + (tile->CityID < 0) && + ! tile->vtable->m18_Check_Mines (tile, __, 0)) { + int tile_x = 0, tile_y = 0; + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + int owner_civ = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_civ == this->ID) || (owner_civ == 0)) { + if (leader_can_build_district (this, inst->district_id) && + district_resource_prereqs_met (tile, tile_x, tile_y, inst->district_id)) + tr = 1; + } + } + } + } + + if (! tr && is->current_config.enable_districts && is->current_config.enable_bridge_districts && + (job == WJ_Build_Road || job == WJ_Build_Railroad)) { + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + if (job == WJ_Build_Road) { + if (! has_road) + tr = 1; + } else { + bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; + if (has_road && ! has_rail) { + int req_tech = p_bic_data->WorkerJobs[job].RequireID; + if ((req_tech < 0) || + ((req_tech != p_bic_data->AdvanceCount) && + Leader_has_tech (&leaders[this->ID], __, req_tech))) { + if (Leader_has_resources_for_job_at (&leaders[this->ID], __, job, tile_x, tile_y)) + tr = 1; + } + } + } + } + } + } + + return tr; +} + +bool __fastcall +patch_Unit_can_hurry_production (Unit * this, int edx, City * city, bool exclude_cheap_improvements) +{ + if (is->current_config.allow_military_leaders_to_hurry_wonders && Unit_has_ability (this, __, UTA_Leader)) { + LeaderKind actual_kind = this->Body.leader_kind; + this->Body.leader_kind = LK_Scientific; + bool tr = Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); + this->Body.leader_kind = actual_kind; + return tr; + } else + return Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); +} + +bool __fastcall +patch_Unit_can_load (Unit * this, int edx, Unit * passenger) +{ + is->can_load_transport = this; + is->can_load_passenger = passenger; + bool tr; + + // If this potential passenger is tied to a different transport, do not allow it to load into this one + int tied_transport_id = -1; + if (is->current_config.limit_unit_loading_to_one_transport_per_turn && + (! Unit_has_ability (this, __, UTA_Army)) && + itable_look_up (&is->unit_transport_ties, passenger->Body.ID, &tied_transport_id) && + (this->Body.ID != tied_transport_id)) + tr = false; + + else + tr = Unit_can_load (this, __, passenger); + + is->can_load_transport = is->can_load_passenger = NULL; + return tr; +} + +void __fastcall +patch_Unit_load (Unit * this, int edx, Unit * transport) +{ + Unit_load (this, __, transport); + + // Tie the unit to the transport if configured to do so + if (is->current_config.limit_unit_loading_to_one_transport_per_turn && ! Unit_has_ability (transport, __, UTA_Army)) + itable_insert (&is->unit_transport_ties, this->Body.ID, transport->Body.ID); +} + +bool +any_enemies_near (Leader const * me, int tile_x, int tile_y, enum UnitTypeClasses class, int num_tiles) +{ + bool tr = false; + FOR_TILES_AROUND (tai, num_tiles, tile_x, tile_y) { + int enemy_on_this_tile = 0; + FOR_UNITS_ON (uti, tai.tile) { + UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; + if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0) && + (((int)class < 0) || (unit_type->Unit_Class == class))) { + if (me->At_War[uti.unit->Body.CivID]) { + if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { + enemy_on_this_tile = 1; + break; + } + } else + break; + } + } + if (enemy_on_this_tile) { + tr = true; + break; + } + } + return tr; +} + +bool +any_enemies_near_unit (Unit * unit, int num_tiles) +{ + UnitType * unit_type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + return any_enemies_near (&leaders[unit->Body.CivID], unit->Body.X, unit->Body.Y, unit_type->Unit_Class, num_tiles); +} + +void __fastcall +patch_Unit_ai_move_artillery (Unit * this) +{ + if ((! is->current_config.use_offensive_artillery_ai) || + ((this->Body.UnitTypeID < 0) || (this->Body.UnitTypeID >= p_bic_data->UnitTypeCount))) // Check for invalid unit type id which appears sometimes, IDK why + goto base_impl; + + Tile * on_tile = tile_at (this->Body.X, this->Body.Y); + City * in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); + UnitType const * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + int num_escorters_req = this->vtable->eval_escort_requirement (this); + + if ((in_city == NULL) || (count_escorters (this) >= num_escorters_req)) + goto base_impl; + + // Don't assign escort if there are any enemies around because in that case it might be a serious mistake to take a defender out of the city + if (any_enemies_near_unit (this, 37)) + goto base_impl; + + // Find the strongest healthy defender the city has and assign that unit as an escort but make sure doing so doesn't leave the city + // defenseless. I think picking the strongest defender is the right choice here because the artillery pair is more likely to come under + // attack than a city and also leaving obsolete units in the city gives them a chance to upgrade. + int num_defenders = 0; + Unit * best_defender = NULL; + int best_defender_strength = -1; + FOR_UNITS_ON (uti, on_tile) { + Unit_Body * body = &uti.unit->Body; + UnitType * type = &p_bic_data->UnitTypes[body->UnitTypeID]; + if ((type->AI_Strategy & UTAI_Defence) && + (! UnitType_has_ability (type, __, UTA_Immobile)) && + (body->Damage == 0) && + ((body->UnitState == 0) || (body->UnitState == UnitState_Fortifying)) && + (body->escortee < 0)) { + num_defenders++; + int str = type->Defence * Unit_get_max_hp (uti.unit); + if (str > best_defender_strength) { + best_defender = uti.unit; + best_defender_strength = str; + } + } + } + if ((num_defenders >= 2) && (best_defender != NULL)) { + Unit_set_state (best_defender, __, 0); + Unit_set_escortee (best_defender, __, this->Body.ID); + } + +base_impl: + Unit_ai_move_artillery (this); + + // Recompute these since the unit might have moved + on_tile = tile_at (this->Body.X, this->Body.Y); + in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); + + // Load the unit into a transport for a naval invasion if it's just sitting in a city with nothing else to do + if (is->current_config.use_offensive_artillery_ai && + (in_city != NULL) && + (this->Body.Moves == 0) && + (this->Body.UnitState == UnitState_Fortifying) && + (this->Body.Container_Unit < 0)) { + Unit * transport = Unit_find_transport (this, __, this->Body.X, this->Body.Y); + if (transport != NULL) { + + int transport_capacity = p_bic_data->UnitTypes[transport->Body.UnitTypeID].Transport_Capacity; + int units_in_transport, arty_in_transport; { + units_in_transport = arty_in_transport = 0; + FOR_UNITS_ON (uti, on_tile) + if (uti.unit->Body.Container_Unit == transport->Body.ID) { + units_in_transport++; + arty_in_transport += (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].AI_Strategy & UTAI_Artillery) != 0; + } + } + + // Check that there's space for the arty unit and an escort, and that the transport does not have more than one arty per three + // spaces so we're less likely to assemble invasion forces composed of nothing but artillery. + if ((units_in_transport + 2 <= transport_capacity) && + (arty_in_transport < not_below (1, transport_capacity / 3))) { + Unit_set_escortee (this, __, -1); + patch_Unit_load (this, __, transport); + } + } + } +} + +// Estimates the number of turns necessary to move the given unit to the given tile and writes it to *out_num_turns. Returns 0 if there is no path +// from the unit's current position to the given tile, 1 otherwise. +int +estimate_travel_time (Unit * unit, int to_tile_x, int to_tile_y, int * out_num_turns) +{ + int dist_in_mp; + patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, to_tile_x, to_tile_y, unit, unit->Body.CivID, 1, &dist_in_mp); + dist_in_mp += unit->Body.Moves; // Add MP already spent this turn to the distance + int max_mp = patch_Unit_get_max_move_points (unit); + if ((dist_in_mp >= 0) && (max_mp > 0)) { + *out_num_turns = dist_in_mp / max_mp; + return 1; + } else + return 0; // No path or unit cannot move +} + +City * +find_nearest_established_city (Unit * unit, int continent_id) +{ + int lowest_unattractiveness = INT_MAX; + City * least_unattractive_city = NULL; + FOR_CITIES_OF (coi,unit->Body.CivID) { + Tile * city_tile = tile_at (coi.city->Body.X, coi.city->Body.Y); + if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { + int dist_in_turns; + if (! estimate_travel_time (unit, coi.city->Body.X, coi.city->Body.Y, &dist_in_turns)) + continue; + int unattractiveness = 10 * dist_in_turns; + unattractiveness = (10 + unattractiveness) / (10 + coi.city->Body.Population.Size); + if (coi.city->Body.CultureIncome > 0) + unattractiveness /= 5; + if (unattractiveness < lowest_unattractiveness) { + lowest_unattractiveness = unattractiveness; + least_unattractive_city = coi.city; + } + } + } + return least_unattractive_city; +} + +bool __fastcall +patch_Unit_ai_can_form_army (Unit * this) +{ + int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.patch_ai_can_form_army_without_special_ability && ((type->Special_Actions & build_army_action) == 0)) + return false; + else + return Unit_ai_can_form_army (this); +} + +void __fastcall +patch_Unit_ai_move_leader (Unit * this) +{ + if (! is->current_config.replace_leader_unit_ai) { + Unit_ai_move_leader (this); + return; + } + + Tile * tile = tile_at (this->Body.X, this->Body.Y); + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + + // Disband the unit if it's on a continent with no cities of its civ. This is what the original logic does. + if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { + Unit_disband (this); + return; + } + + // Flee if the unit is near an enemy without adequate escort + int has_adequate_escort; { + int escorter_count = 0; + int any_healthy_escorters = 0; + int index; + for (int escorter_id = Unit_next_escorter_id (this, __, &index, true); escorter_id >= 0; escorter_id = Unit_next_escorter_id (this, __, &index, false)) { + Unit * escorter = get_unit_ptr (escorter_id); + if ((escorter != NULL) && (escorter->Body.X == this->Body.X) && (escorter->Body.Y == this->Body.Y)) { + escorter_count++; + int remaining_health = Unit_get_max_hp (escorter) - escorter->Body.Damage; + any_healthy_escorters |= (remaining_health >= 3) || (escorter->Body.Damage == 0); + } + } + has_adequate_escort = (escorter_count > 0) && any_healthy_escorters; + } + if ((! has_adequate_escort) && any_enemies_near_unit (this, 49)) { + Unit_set_state (this, __, UnitState_Fleeing); + bool done = this->vtable->work (this); + if (done || (this->Body.UnitState != 0)) + return; + } + + // Move along path if the unit already has one set + byte next_move = Unit_pop_next_move_from_path (this); + if (next_move > 0) { + this->vtable->Move (this, __, next_move, 0); + return; + } + + // Start a science age if we can + // It would be nice to compute a value for this and compare it to the option of rushing production but it's hard to come up with a valuation + if (is->current_config.patch_science_age_bug && Unit_ai_can_start_science_age (this)) { + Unit_start_science_age (this); + return; + } + + // Estimate the value of creating an army. First test if that's even a possiblity and if not leave the value at -1 so rushing production is + // always preferable (note we can't use Unit_ai_can_form_army for this b/c it returns false for units not in a city). The value of forming + // an army is "infinite" if we don't already have one and otherwise it depends on the army unit's shield cost +/- 25% for each point of + // aggression divided by the number of armies already in the field. + int num_armies = leaders[this->Body.CivID].Armies_Count; + int form_army_value = -1; + int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits + if ((this->Body.leader_kind & LK_Military) && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & build_army_action) && + ((num_armies + 1) * p_bic_data->General.ArmySupportCities <= leaders[this->Body.CivID].Cities_Count) && + (p_bic_data->General.BuildArmyUnitID >= 0) && + (p_bic_data->General.BuildArmyUnitID < p_bic_data->UnitTypeCount)) { + if (num_armies < 1) + form_army_value = INT_MAX; + else { + form_army_value = p_bic_data->UnitTypes[p_bic_data->General.BuildArmyUnitID].Cost; + int aggression_level = p_bic_data->Races[leaders[this->Body.CivID].RaceID].AggressionLevel; // aggression level varies between -2 and +2 + form_army_value = (form_army_value * (4 + aggression_level)) / 4; + if (num_armies > 1) + form_army_value /= num_armies; + } + } + + // Estimate the value of rushing production in every city on this continent and remember the highest one + City * best_rush_loc = NULL; + int best_rush_value = -1; + FOR_CITIES_OF (coi, this->Body.CivID) { + City * city = coi.city; + Tile * city_tile = tile_at (city->Body.X, city->Body.Y); + if ((continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) && + patch_Unit_can_hurry_production (this, __, city, false)) { + // Base value is equal to the number of shields rushing would save + int value = City_get_order_cost (city) - City_get_order_progress (city) - city->Body.ProductionIncome; + if (value <= 0) + continue; + + // Consider distance: Reduce the value by the number of shields produced while the leader is en route to rush. + int dist_in_turns; + if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) + continue; // no path or unit cannot move + value -= dist_in_turns * city->Body.ProductionIncome; + if (value <= 0) + continue; + + // Consider corruption: Scale down the value of rushing an improvement by the corruption rate of the city. + // This is to reflect the fact that infrastructure is more valuable in less corrupt cities. But do not apply + // this to wonders since their benefit is in most cases not lessened by local corruption. + Improvement * improv = (city->Body.Order_Type == COT_Improvement) ? &p_bic_data->Improvements[city->Body.Order_ID] : NULL; + int is_wonder = (improv != NULL) && (0 != (improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder))); + if ((improv != NULL) && (! is_wonder)) { + int good_shields = city->Body.ProductionIncome; + int corrupt_shields = city->Body.ProductionLoss; + if (good_shields + corrupt_shields > 0) + value = (value * good_shields) / (good_shields + corrupt_shields); + else + continue; + } + + if ((value > 0) && (value > best_rush_value)) { + best_rush_loc = city; + best_rush_value = value; + } + } + } + + // Hurry production or form an army depending on the estimated values of doing so. We might have to move to a (different) city if that's where + // we want to rush production or if we want to form an army but aren't already in a city. + City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); + City * moving_to_city = NULL; + if ((best_rush_loc != NULL) && (best_rush_value > form_army_value)) { + if (best_rush_loc == in_city) { + Unit_hurry_production (this); + return; + } else + moving_to_city = best_rush_loc; + } else if ((form_army_value > -1) && patch_Unit_ai_can_form_army (this)) { + Unit_form_army (this); + return; + } else if (in_city == NULL) { + // Nothing to do. Try to find a close, established city to move to & wait in. + moving_to_city = find_nearest_established_city (this, continent_id); + } + if (moving_to_city) { + int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); + if (first_move > 0) { + Unit_set_escortee (this, __, -1); + this->vtable->Move (this, __, first_move, 0); + return; + } + } + + // Nothing to do, nowhere to go, just fortify in place. + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +int +measure_strength_in_army (UnitType * type) +{ + return ((type->Attack + type->Defence) * (4 + type->Hit_Point_Bonus)) / 4; +} + +bool __fastcall +patch_impl_ai_is_good_army_addition (Unit * this, int edx, Unit * candidate) +{ + if (! is->current_config.fix_ai_army_composition) + return impl_ai_is_good_army_addition (this, __, candidate); + + UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + if (((candidate_type->AI_Strategy & UTAI_Offence) == 0) || + UnitType_has_ability (candidate_type, __, UTA_Hidden_Nationality)) + return false; + + int num_units_in_army = 0, + army_min_speed = INT_MAX, + army_min_strength = INT_MAX; + FOR_UNITS_ON (uti, tile) { + if (uti.unit->Body.Container_Unit == this->Body.ID) { + num_units_in_army++; + int movement = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Movement; + if (movement < army_min_speed) + army_min_speed = movement; + int member_strength = measure_strength_in_army (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]); + if (member_strength < army_min_strength) + army_min_strength = member_strength; + } + } + + return (num_units_in_army == 0) || + ((candidate_type->Movement >= army_min_speed) && + (measure_strength_in_army (candidate_type) >= army_min_strength)); +} + +int +rate_artillery (UnitType * type) +{ + int tr = type->Attack + type->Defence + 2 * type->Bombard_Strength * type->FireRate; + + // include movement + int moves = type->Movement; + if (moves >= 2) + tr = tr * (moves + 1) / 2; + + // include range + int range = type->Bombard_Range; + if (range >= 2) + tr = tr * (range + 1) / 2; + + // include extra hp + if (type->Hit_Point_Bonus > 0) + tr = tr * (4 + type->Hit_Point_Bonus) / 4; + + return tr; +} + +int +rate_bomber (UnitType * type) +{ + int tr = type->Bombard_Strength * type->FireRate + type->Defence; + + // include range + tr = tr * (10 + type->OperationalRange) / 10; + + // include cost + tr = (tr * 100) / (100 + type->Cost); + + // include abilities + if (UnitType_has_ability (type, __, UTA_Blitz)) + tr = tr * (type->Movement + 1) / 2; + if (UnitType_has_ability (type, __, UTA_Lethal_Land_Bombardment)) + tr = tr * 3 / 2; + if (UnitType_has_ability (type, __, UTA_Lethal_Sea_Bombardment)) + tr = tr * 5 / 4; + if (UnitType_has_ability (type, __, UTA_Stealth)) + tr = tr * 3 / 2; + + // include extra hp + if (type->Hit_Point_Bonus > 0) + tr = tr * (4 + type->Hit_Point_Bonus) / 4; + + return tr; +} + +bool __fastcall +patch_City_can_build_unit (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) +{ + bool base = City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); + + if (base) { + // Apply building prereqs + int building_prereq; + if (itable_look_up (&is->current_config.building_unit_prereqs, unit_type_id, &building_prereq)) { + // If the prereq is an encoded building ID + if (building_prereq & 1) { + if (! has_active_building (this, building_prereq >> 1)) + return false; + + // Else it's a pointer to a list of building IDs + } else { + int * list = (int *)building_prereq; + for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) + if ((list[n] >= 0) && ! has_active_building (this, list[n])) + return false; + } + } + + // Apply unit type limit + int available; + if (get_available_unit_count (&leaders[this->Body.CivID], unit_type_id, &available) && (available <= 0)) + return false; + } + + if (is->current_config.enable_districts) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + + // Bail if tech reqs are not met + int prereq_id = type->AdvReq; + if (prereq_id >= 0 && ! Leader_has_tech (&leaders[this->Body.CivID], __, prereq_id)) + return false; + + if (! Leader_can_build_unit (&leaders[this->Body.CivID], __, unit_type_id, 1, false)) + return false; + + // Superficially allow the AI to choose the unit for scoring and production. + // If a disallowed air/naval unit is chosen in ai_choose_production, we'll swap it out for a feasible fallback later + // after prioritizing the aerodrome/port to be built + if (! is_human && ( + (type->Unit_Class == UTC_Air || city_can_build_district (this, AERODROME_DISTRICT_ID)) || + (type->Unit_Class == UTC_Sea || city_can_build_district (this, PORT_DISTRICT_ID))) + ) + return base; + + // Air units + if (type->Unit_Class == UTC_Air) { + if (is->current_config.enable_aerodrome_districts && is->current_config.air_units_use_aerodrome_districts_not_cities) { + if (find_pending_district_request (this, AERODROME_DISTRICT_ID) != NULL) + return false; + if (! city_can_build_district (this, AERODROME_DISTRICT_ID)) + return false; + return city_has_required_district (this, AERODROME_DISTRICT_ID); + } + // Naval units + } else if (type->Unit_Class == UTC_Sea) { + if (is->current_config.enable_port_districts && is->current_config.naval_units_use_port_districts_not_cities) { + if (find_pending_district_request (this, PORT_DISTRICT_ID) != NULL) + return false; + if (! city_can_build_district (this, PORT_DISTRICT_ID)) + return false; + return city_has_required_district (this, PORT_DISTRICT_ID); + } + } + } + + return base; +} + +int __fastcall +patch_City_get_largest_adjacent_sea_within_work_area (City * this) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + int improv_id = is->current_evaluating_improve_id; + if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { + + // If Coastal Fortress, default to original logic (city must be next to coast) + if (p_bic_data->Improvements[improv_id].Naval_Bombard_Defence > 0) + return City_get_largest_adjacent_sea (this); + } + int lake_size_threshold = 21; + int largest_size = 0; + int largest_continent_id = -1; + FOR_WORK_AREA_AROUND (wai, this->Body.X, this->Body.Y) { + if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { + int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + if (continent->Body.TileCount <= lake_size_threshold && ! is->current_config.enable_canal_districts) + continue; + if (p_bic_data->Map.Continents[continent_id].Body.TileCount > largest_size) { + largest_size = p_bic_data->Map.Continents[continent_id].Body.TileCount; + largest_continent_id = continent_id; + } + } + } + return largest_continent_id; + } + return City_get_largest_adjacent_sea (this); +} + +bool __fastcall +patch_Map_impl_is_near_river_within_work_area (Map * this, int edx, int x, int y, int num_tiles) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + FOR_WORK_AREA_AROUND (wai, x, y) { + if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) { + return true; + } + } + return false; + } + + return this->vtable->is_near_river (this, __, x, y, num_tiles); +} + +bool __fastcall +patch_Map_impl_is_near_lake_within_work_area (Map * this, int edx, int x, int y, int num_tiles) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + int lake_size_threshold = 21; + FOR_WORK_AREA_AROUND (wai, x, y) { + if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { + int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + if (continent->Body.TileCount <= lake_size_threshold) + return true; + } + } + return false; + } + + return this->vtable->is_near_lake (this, __, x, y, num_tiles); +} + +bool __fastcall +patch_Map_impl_has_fresh_water_within_work_area (Map * this, int edx, int tile_x, int tile_y) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + int improv_id = is->current_evaluating_improve_id; + if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { + + // If an Aqueduct, default to original logic (city must be next to coast) + if ((p_bic_data->Improvements[improv_id].ImprovementFlags & ITF_Allows_City_Level_2) != 0) + return this->vtable->has_fresh_water (this, __, tile_x, tile_y); + } + if (patch_Map_impl_is_near_river_within_work_area (this, __, tile_x, tile_y, 1)) + return true; + if (patch_Map_impl_is_near_lake_within_work_area (this, __, tile_x, tile_y, 1)) + return true; + return false; + } + + return this->vtable->has_fresh_water (this, __, tile_x, tile_y); +} + +bool +city_meets_district_prereqs_to_build_improvement (City * city, int i_improv, bool apply_strict_rules) +{ + // Different logic for human vs AI players + bool is_human = (*p_human_player_bits & (1 << city->Body.CivID)) != 0; + + Improvement * improv = &p_bic_data->Improvements[i_improv]; + bool is_wonder = is->current_config.enable_wonder_districts && (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)); + if (is_wonder && ! wonder_is_buildable_by_civ (i_improv, city->Body.CivID)) + return false; + + bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; + + // Check if the improvement requires a district + bool needs_district = city_requires_district_for_improvement (city, i_improv, NULL); + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); + + // District is either not needed or already built + if (! needs_district) + return true; + + if (prereq_list == NULL) + return false; + + bool has_buildable_candidate = false; + bool has_wonder_candidate = false; + bool has_non_wonder_candidate = false; + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) + continue; + has_buildable_candidate = true; + if (district_id == WONDER_DISTRICT_ID) + has_wonder_candidate = true; + else + has_non_wonder_candidate = true; + } + if (! has_buildable_candidate) + return false; + + // Check that we have the necessary terrain + bool has_terrain_for_district = false; + bool has_terrain_for_wonder = false; + bool has_river_terrain_for_district = false; + FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { + Tile * tile = wai.tile; + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) + continue; + if (! tile_suitable_for_district (tile, district_id, city, NULL)) + continue; + + if (is_wonder && district_id == WONDER_DISTRICT_ID) { + if (! wonder_is_buildable_on_tile (tile, i_improv)) + continue; + } + + has_terrain_for_district = true; + if (requires_river && tile->vtable->m37_Get_River_Code (tile) != 0) + has_river_terrain_for_district = true; + + if (is_wonder && district_id == WONDER_DISTRICT_ID) { + if (! requires_river || tile->vtable->m37_Get_River_Code (tile) != 0) { + has_terrain_for_wonder = true; + } + } + } + } + + bool requires_wonder_terrain = is_wonder && has_wonder_candidate && ! has_non_wonder_candidate; + if (! has_terrain_for_district || + (requires_river && ! has_river_terrain_for_district) || + (requires_wonder_terrain && ! has_terrain_for_wonder)) { + return false; + } + + // If human has everything needed except a built district (which is buildable), allow relaxed checks so UI can gray entry out + if (is_human) { + return ! apply_strict_rules; + } + + // If AI already has a pending district request for this required district, return false + // to prevent wasting a turn trying to choose this improvement + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + if (find_pending_district_request (city, district_id) != NULL) + return false; + } + + // Superficially allow the AI to choose the improvement for scoring and production. + // If a disallowed improvement is chosen in ai_choose_production, we'll swap it out for a feasible fallback later + // after prioritizing the district to be built + return true; +} + +bool __fastcall +patch_City_can_build_improvement (City * this, int edx, int i_improv, bool apply_strict_rules) +{ + is->current_evaluating_improve_id = i_improv; + + char ss[200]; + snprintf (ss, sizeof ss, "patch_City_can_build_improvement:evaluating improvement %s (%d)\n", + p_bic_data->Improvements[i_improv].Name.S, i_improv); + (*p_OutputDebugStringA) (ss); + + // First defer to the base game's logic + bool base = City_can_build_improvement (this, __, i_improv, apply_strict_rules); + if (! base) return false; + if (! is->current_config.enable_districts) return base; + + bool can_build = city_meets_district_prereqs_to_build_improvement (this, i_improv, apply_strict_rules); + is->current_evaluating_improve_id = -1; + + return can_build; +} + +bool +ai_handle_district_production_requirements (City * city, City_Order * out) +{ + clear_best_feasible_order (city); + bool swapped_to_fallback = false; + City_Order fallback_order = {0}; + int required_district_id = -1; + bool should_mark_district = false; + + char ss[200]; + + if (is->current_config.enable_districts && + (out->OrderID >= 0)) { + bool needs_wonder_district = false; + bool requires_district = false; + bool needs_district = false; + + if ((out->OrderType == COT_Unit) && + (out->OrderID < p_bic_data->UnitTypeCount)) { + UnitType * type = &p_bic_data->UnitTypes[out->OrderID]; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { + required_district_id = AERODROME_DISTRICT_ID; + needs_district = true; + should_mark_district = true; + } else if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (city, PORT_DISTRICT_ID))) { + required_district_id = PORT_DISTRICT_ID; + needs_district = true; + should_mark_district = true; + } + } else if ((out->OrderType == COT_Improvement) && + (out->OrderID < p_bic_data->ImprovementsCount)) { + // Check if AI is trying to build a wonder without an incomplete wonder district + requires_district = city_requires_district_for_improvement (city, out->OrderID, &required_district_id); + if (is->current_config.enable_wonder_districts) { + Improvement * improv = &p_bic_data->Improvements[out->OrderID]; + if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && + (! city_has_wonder_district_with_no_completed_wonder (city, out->OrderID))) { + snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: City %d (%s) needs wonder district to build wonder improvement %d\n", + city->Body.ID, city->Body.CityName, out->OrderID); + (*p_OutputDebugStringA) (ss); + needs_wonder_district = true; + if (required_district_id < 0) { + required_district_id = WONDER_DISTRICT_ID; + } + } + } + needs_district = needs_wonder_district || requires_district; + } + + if (needs_district) { + struct ai_best_feasible_order * stored = get_best_feasible_order (city); + if (stored != NULL) { + bool fallback_is_feasible = true; + if (stored->order.OrderType == COT_Improvement) { + if ((stored->order.OrderID < 0) || + (stored->order.OrderID >= p_bic_data->ImprovementsCount)) + fallback_is_feasible = false; + + // Check if fallback requires a district the city doesn't have + if (fallback_is_feasible && + city_requires_district_for_improvement (city, stored->order.OrderID, NULL)) + fallback_is_feasible = false; + + // If original order was a wonder, ensure fallback is not also a wonder + if (fallback_is_feasible && needs_wonder_district) { + Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; + if (fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + fallback_is_feasible = false; + } + + // If fallback is a wonder, check if it has an incomplete wonder district + if (fallback_is_feasible && is->current_config.enable_wonder_districts) { + Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; + if ((fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && + (! city_has_wonder_district_with_no_completed_wonder (city, stored->order.OrderID))) + fallback_is_feasible = false; + } + } else if (stored->order.OrderType == COT_Unit) { + if ((stored->order.OrderID < 0) || + (stored->order.OrderID >= p_bic_data->UnitTypeCount)) + fallback_is_feasible = false; + if (fallback_is_feasible) { + UnitType * type = &p_bic_data->UnitTypes[stored->order.OrderID]; + if (type->Unit_Class != UTC_Land) + fallback_is_feasible = false; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (city, AERODROME_DISTRICT_ID))) + fallback_is_feasible = false; + if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (city, PORT_DISTRICT_ID))) + fallback_is_feasible = false; + } + } else + fallback_is_feasible = false; + + if (fallback_is_feasible) { + if (out->OrderType == COT_Improvement) { + // Remember pending building order for any improvement that requires a district + snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: Remembering fallback pending building order for city %d (%s): order type %d id %d\n", + city->Body.ID, city->Body.CityName, out->OrderType, out->OrderID); + (*p_OutputDebugStringA) (ss); + remember_pending_building_order (city, out->OrderID); + } + + fallback_order = stored->order; + swapped_to_fallback = true; + } + } + } + } + + if (swapped_to_fallback) { + *out = fallback_order; + } + if ((swapped_to_fallback || should_mark_district) && (required_district_id >= 0)) + mark_city_needs_district (city, required_district_id); + + clear_best_feasible_order (city); + return swapped_to_fallback; +} + +void __fastcall +patch_City_ai_choose_production (City * this, int edx, City_Order * out) +{ + is->ai_considering_production_for_city = this; + City_ai_choose_production (this, __, out); + + char ss[200]; + snprintf (ss, sizeof ss, "patch_City_ai_choose_production: City %d (%s) chose order type %d id %d\n", + this->Body.ID, this->Body.CityName, out->OrderType, out->OrderID); + (*p_OutputDebugStringA) (ss); + + if (is->current_config.enable_districts) { + if (ai_handle_district_production_requirements (this, out)) { + return; + } + } + + Leader * me = &leaders[this->Body.CivID]; + int arty_ratio = is->current_config.ai_build_artillery_ratio; + int bomber_ratio = is->current_config.ai_build_bomber_ratio; + + // Check if AI-build-more-artillery mod option is activated and this city is building something that we might want to switch to artillery + if ((arty_ratio > 0) && + (out->OrderType == COT_Unit) && + (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && + (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & (UTAI_Offence | UTAI_Defence))) { + + // Check how many offense/defense/artillery units this AI has already built. We'll only force it to build arty if it has a minimum + // of one defender per city, one attacker per two cities, and of course if it's below the ratio limit. + int num_attackers = me->AI_Strategy_Unit_Counts[0], + num_defenders = me->AI_Strategy_Unit_Counts[1], + num_artillery = me->AI_Strategy_Unit_Counts[2]; + if ((num_attackers > me->Cities_Count / 2) && + (num_defenders > me->Cities_Count) && + (100*num_artillery < arty_ratio*(num_attackers + num_defenders))) { + + // Loop over all build options to determine the best artillery unit available. Record its attack power and also find & record + // the highest attack power available from any offensive unit so we can compare them. + int best_arty_type_id = -1, + best_arty_rating = -1, + best_arty_strength = -1, + best_attacker_strength = -1; + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if ((type->AI_Strategy & (UTAI_Artillery | UTAI_Offence)) && + patch_City_can_build_unit (this, __, n, 1, 0, 0)) { + if (type->AI_Strategy & UTAI_Artillery) { + int this_rating = rate_artillery (&p_bic_data->UnitTypes[n]); + if (this_rating > best_arty_rating) { + best_arty_type_id = n; + best_arty_rating = this_rating; + best_arty_strength = type->Bombard_Strength * type->FireRate; + } + } else { // attacker + int this_strength = (type->Attack * (4 + type->Hit_Point_Bonus)) / 4; + if (this_strength > best_attacker_strength) + best_attacker_strength = this_strength; + } + } + } + + // Randomly switch city production to the artillery unit if we found one + if (best_arty_type_id >= 0) { + int chance = 12 * arty_ratio / 10; + + // Scale the chance of switching by the ratio of the attack power the artillery would provide to the attack power + // of the strongest offensive unit. This way the AI will rapidly build artillery up to the ratio limit only when + // artillery are its best way of dealing damage. + // Some example numbers: + // | Best attacker (str) | Best arty (str) | Chance w/ ratio = 20, damage% = 50 + // | Swordsman (3) | Catapult (4) | 16 + // | Knight (4) | Trebuchet (6) | 18 + // | Cavalry (6) | Cannon (8) | 16 + // | Cavalry (6) | Artillery (24) | 48 + // | Tank (16) | Artillery (24) | 18 + if (best_attacker_strength > 0) + chance = (chance * best_arty_strength * is->current_config.ai_artillery_value_damage_percent) / (best_attacker_strength * 100); + + if (rand_int (p_rand_object, __, 100) < chance) + out->OrderID = best_arty_type_id; + } + } + + } else if ((bomber_ratio > 0) && + (out->OrderType == COT_Unit) && + (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && + (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & UTAI_Air_Defence)) { + int num_fighters = me->AI_Strategy_Unit_Counts[7], + num_bombers = me->AI_Strategy_Unit_Counts[6]; + if (100 * num_bombers < bomber_ratio * num_fighters) { + int best_bomber_type_id = -1, + best_bomber_rating = -1; + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if ((type->AI_Strategy & UTAI_Air_Bombard) && + patch_City_can_build_unit (this, __, n, 1, 0, 0)) { + int this_rating = rate_bomber (&p_bic_data->UnitTypes[n]); + if (this_rating > best_bomber_rating) { + best_bomber_type_id = n; + best_bomber_rating = this_rating; + } + } + } + + if (best_bomber_type_id >= 0) { + int chance = 12 * bomber_ratio / 10; + if (rand_int (p_rand_object, __, 100) < chance) + out->OrderID = best_bomber_type_id; + } + } + } + + is->ai_considering_production_for_city = NULL; +} + +int __fastcall +patch_Unit_disembark_passengers (Unit * this, int edx, int tile_x, int tile_y) +{ + // Break any escort relationships if the escorting unit can't move onto the target tile. This prevents a freeze where the game continues + // trying to disembark units because an escortee looks like it could be disembarked except it can't because it won't move if its escorter + // can't be moved first. + Tile * tile = tile_at (this->Body.X, this->Body.Y), + * target = tile_at (tile_x , tile_y); + if (is->current_config.patch_blocked_disembark_freeze && (tile != NULL) && (target != NULL)) { + enum SquareTypes target_terrain = target->vtable->m50_Get_Square_BaseType (target); + FOR_UNITS_ON (uti, tile) { + Unit * escortee = get_unit_ptr (uti.unit->Body.escortee); + if ( (escortee != NULL) + && (uti.unit->Body.Container_Unit == this->Body.ID) + && (escortee->Body.Container_Unit == this->Body.ID) + && ( UnitType_has_ability (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID], __, UTA_Immobile) + || ( is->current_config.disallow_trespassing + && check_trespassing (uti.unit->Body.CivID, tile, target) + && ! is_allowed_to_trespass (uti.unit)) + || Unit_is_terrain_impassable (uti.unit, __, target_terrain))) + Unit_set_escortee (uti.unit, __, -1); + } + } + + return Unit_disembark_passengers (this, __, tile_x, tile_y); +} + +// Returns whether or not the current deal being offered to the AI on the trade screen would be accepted. How advantageous the AI thinks the +// trade is for itself is stored in out_their_advantage if it's not NULL. This advantage is measured in gold, if it's positive it means the +// AI thinks it's gaining that much value from the trade and if it's negative it thinks it would be losing that much. I don't know what would +// happen if this function were called while the trade screen is not active. +bool +is_current_offer_acceptable (int * out_their_advantage) +{ + int their_id = p_diplo_form->other_party_civ_id; + + DiploMessage consideration = Leader_consider_trade ( + &leaders[their_id], + __, + &p_diplo_form->our_offer_lists[their_id], + &p_diplo_form->their_offer_lists[their_id], + p_main_screen_form->Player_CivID, + 0, true, 0, 0, + out_their_advantage, + NULL, NULL); + + return consideration == DM_AI_ACCEPT; +} + +// Adds an offer of gold to the list and returns it. If one already exists in the list, returns a pointer to it. +TradeOffer * +offer_gold (TradeOfferList * list, int is_lump_sum, int * is_new_offer) +{ + if (list->length > 0) + for (TradeOffer * offer = list->first; offer != NULL; offer = offer->next) + if ((offer->kind == 7) && (offer->param_1 == is_lump_sum)) { + *is_new_offer = 0; + return offer; + } + + TradeOffer * tr = new (sizeof *tr); + *tr = (struct TradeOffer) { + .vtable = p_trade_offer_vtable, + .kind = 7, // TODO: Replace with enum + .param_1 = is_lump_sum, + .param_2 = 0, + .next = NULL, + .prev = NULL + }; + + if (list->length > 0) { + tr->prev = list->last; + list->last->next = tr; + list->last = tr; + list->length += 1; + } else { + list->last = list->first = tr; + list->length = 1; + } + + *is_new_offer = 1; + return tr; +} + +// Removes offer from list of offers but does not free it. Assumes offer is in the list. +void +remove_offer (TradeOfferList * list, TradeOffer * offer) +{ + if (list->length == 1) { + list->first = list->last = NULL; + list->length = 0; + } else if (list->length > 1) { + TradeOffer * prev = offer->prev, * next = offer->next; + if (prev) + prev->next = next; + if (next) + next->prev = prev; + if (list->first == offer) + list->first = next; + if (list->last == offer) + list->last = prev; + list->length -= 1; + } + offer->prev = offer->next = NULL; +} + +void __fastcall +patch_PopupForm_set_text_key_and_flags (PopupForm * this, int edx, char * script_path, char * text_key, int param_3, int param_4, int param_5, int param_6) +{ + int * p_stack = (int *)&script_path; + int ret_addr = p_stack[-1]; + + int is_initial_gold_trade = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_INITIAL_GOLD_OFFER_RETURN), + is_modifying_gold_trade = (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN ) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_OFFER_RETURN); + + // This function gets called from all over the place, check that it's being called to setup the set gold amount popup in the trade screen + if (is->current_config.autofill_best_gold_amount_when_trading && (is_initial_gold_trade || is_modifying_gold_trade)) { + int asking = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN); + int is_lump_sum = is_initial_gold_trade ? + p_stack[TRADE_GOLD_SETTER_IS_LUMP_SUM_OFFSET] : // Read this variable from the caller's frame + is->modifying_gold_trade->param_1; + + int their_id = p_diplo_form->other_party_civ_id, + our_id = p_main_screen_form->Player_CivID; + + // This variable will store the result of the optimization process and it's what will be used as the final amount presented to the + // player in the popup and left in the TradeOffer object (if applicable). Default to zero for new offers and the previous amount when + // modifying an offer. When modifying, we also zero the amount on the table b/c the optimization process only works properly from that + // starting point. + int best_amount = 0; + if (is_modifying_gold_trade) { + best_amount = is->modifying_gold_trade->param_2; + is->modifying_gold_trade->param_2 = 0; + } + + int their_advantage; + bool is_original_acceptable = is_current_offer_acceptable (&their_advantage); + + // if (we're asking for money on an acceptable trade and are offering something) OR (we're offering money on an unacceptable trade and + // are asking for something) + if (( asking && is_original_acceptable && (p_diplo_form->our_offer_lists[their_id] .length > 0)) || + ((! asking) && (! is_original_acceptable) && (p_diplo_form->their_offer_lists[their_id].length > 0))) { + + TradeOfferList * offers = asking ? &p_diplo_form->their_offer_lists[their_id] : &p_diplo_form->our_offer_lists[their_id]; + int test_offer_is_new; + TradeOffer * test_offer = offer_gold (offers, is_lump_sum, &test_offer_is_new); + + // When asking for gold, start at zero and work upwards. When offering gold it's more complicated. For lump sum + // offers, start with our entire treasury and work downward. For GPT offers, start with an upper bound and work + // downward. The upper bound depends on how much the AI thinks it's losing on the trade (in gold) divided by 20 + // (b/c 20 turn deal) with a lot of extra headroom just to make sure. + int starting_amount; { + if (asking) + starting_amount = 0; + else { + if (is_lump_sum) + starting_amount = leaders[our_id].Gold_Encoded + leaders[our_id].Gold_Decrement; + else { + int guess = not_below (0, 0 - their_advantage) / 20; + starting_amount = 10 + guess * 2; + } + } + } + + // Check if optimization is still possible. It's not if we're offering gold and our maximum offer is unacceptable + test_offer->param_2 = starting_amount; + if (asking || is_current_offer_acceptable (NULL)) { + + best_amount = starting_amount; + for (int step_size = asking ? 1000 : -1000; step_size != 0; step_size /= 10) { + test_offer->param_2 = best_amount; + while (1) { + test_offer->param_2 += step_size; + if (test_offer->param_2 < 0) + break; + else if (is_current_offer_acceptable (NULL)) + best_amount = test_offer->param_2; + else + break; + } + } + } + + // Annoying little edge case: The limitation on AIs not to trade more than their entire treasury is handled in the + // interface not the trade evaluation logic so we have to limit our gold request here to their treasury (otherwise + // the amount will default to how much they would pay if they had infinite money). + int their_treasury = leaders[their_id].Gold_Encoded + leaders[their_id].Gold_Decrement; + if (asking && is_lump_sum && (best_amount > their_treasury)) + best_amount = their_treasury; + + // Restore the trade table to its original state. Remove & free test_offer if it was newly created, otherwise put back its + // original amount. + if (test_offer_is_new) { + remove_offer (offers, test_offer); + test_offer->vtable->destruct (test_offer, __, 1); + } + + // If we're offering gold on a trade that's already acceptable, the optimal amount is zero. We must handle this explicitly in case + // we're modifying an amount already on the table. If we didn't, the above condition wouldn't optimize the amount and we'd default to + // the original amount. + } else if ((! asking) && is_original_acceptable) + best_amount = 0; + + if (is_modifying_gold_trade) + is->modifying_gold_trade->param_2 = best_amount; + snprintf (is->ask_gold_default, sizeof is->ask_gold_default, "%d", best_amount); + is->ask_gold_default[(sizeof is->ask_gold_default) - 1] = '\0'; + PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, (int)is->ask_gold_default, param_5, param_6); + } else + PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, param_4, param_5, param_6); +} + +CityLocValidity __fastcall +patch_Map_check_city_location (Map *this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile) +{ + if (is->current_config.enable_natural_wonders) { + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { + return CLV_BLOCKED; + } + } + } + + int min_sep = is->current_config.minimum_city_separation; + CityLocValidity base_result = Map_check_city_location (this, __, tile_x, tile_y, civ_id, check_for_city_on_tile); + + // If minimum separation is one, make no change + if (min_sep == 1) + return base_result; + + // If minimum separation is <= 0, ignore the CITY_TOO_CLOSE objection to city placement unless the location is next to a city belonging to + // another civ and the settings forbid founding there. + else if ((min_sep <= 0) && (base_result == CLV_CITY_TOO_CLOSE)) { + if (is->current_config.disallow_founding_next_to_foreign_city) + for (int n = 1; n <= 8; n++) { + int x, y; + get_neighbor_coords (&p_bic_data->Map, tile_x, tile_y, n, &x, &y); + City * city = city_at (x, y); + if ((city != NULL) && (city->Body.CivID != civ_id)) + return CLV_CITY_TOO_CLOSE; + } + return CLV_OK; + + // If we have an increased separation we might have to exclude some locations the base code allows. + } else if ((min_sep > 1) && (base_result == CLV_OK)) { + // Check tiles around (x, y) for a city. Because the base result is CLV_OK, we don't have to check neighboring tiles, just those at + // distance 2, 3, ... up to (an including) the minimum separation + for (int dist = 2; dist <= min_sep; dist++) { + + // vertices stores the unwrapped coords of the tiles at the vertices of the square of tiles at distance "dist" around + // (tile_x, tile_y). The order of the vertices is north, east, south, west. + struct vertex { + int x, y; + } vertices[4] = { + {tile_x , tile_y - 2*dist}, + {tile_x + 2*dist, tile_y }, + {tile_x , tile_y + 2*dist}, + {tile_x - 2*dist, tile_y } + }; + + // neighbor index for direction of tiles along edge starting from each vertex + // values correspond to directions: southeast, southwest, northwest, northeast + int edge_dirs[4] = {3, 5, 7, 1}; + + // Loop over verts and check tiles along their associated edges. The N vert is associated with the NE edge, the E vert with + // the SE edge, etc. + for (int vert = 0; vert < 4; vert++) { + wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); + int dx, dy; + neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); + for (int j = 0; j < 2*dist; j++) { // loop over tiles along this edge + int cx = vertices[vert].x + j * dx, + cy = vertices[vert].y + j * dy; + wrap_tile_coords (&p_bic_data->Map, &cx, &cy); + if (city_at (cx, cy)) + return CLV_CITY_TOO_CLOSE; + } + } + + } + return base_result; + + } else + return base_result; +} + +bool +is_zero_strength (UnitType * ut) +{ + return (ut->Attack == 0) && (ut->Defence == 0); +} + +bool +is_captured (Unit_Body * u) +{ + return (u->RaceID >= 0) && (u->CivID >= 0) && (u->CivID < 32) && leaders[u->CivID].RaceID != u->RaceID; +} + +// Decides whether or not units "a" and "b" are duplicates, i.e., whether they are interchangeable. +// If surface_only is set, the function checks only surface-level characteristics, meaning those that are visible to other players. +bool +are_units_duplicate (Unit_Body * a, Unit_Body * b, bool surface_only) +{ + UnitType * a_type = &p_bic_data->UnitTypes[a->UnitTypeID], + * b_type = &p_bic_data->UnitTypes[b->UnitTypeID]; + + // If only doing a surface comparison, look through the alternate strategy types to the base types. The difference b/w the alt types is only + // their AI strategies, and that isn't considered a surface feature. + if (surface_only) { + while (a_type->alternate_strategy_for_id >= 0) + a_type = &p_bic_data->UnitTypes[a_type->alternate_strategy_for_id]; + while (b_type->alternate_strategy_for_id >= 0) + b_type = &p_bic_data->UnitTypes[b_type->alternate_strategy_for_id]; + } + + // a and b are duplicates "on the surface" if... + bool are_surface_duplicates = + // ... they belong to the same player ... + (a->CivID == b->CivID) && + + // ... they have the same type that is not [a leader OR army] AND not a transport AND ... + (a_type == b_type) && + (! (UnitType_has_ability (a_type, __, UTA_Leader) || UnitType_has_ability (a_type, __, UTA_Army))) && + (a_type->Transport_Capacity == 0) && + + // ... they've taken the same amount of damage AND have the same charm status AND ... + (a->Damage == b->Damage) && (a->charmed == b->charmed) && + + // ... they're either both fortified or both not AND ... + (! (a->UnitState == UnitState_Fortifying) ^ (b->UnitState == UnitState_Fortifying)) && + + // ... [they have the same experience level OR are zero strength units] AND ... + ((a->Combat_Experience == b->Combat_Experience) || is_zero_strength (a_type)) && + + // ... [they are both not contained in any unit OR they are both contained in the same unit] AND ... + (((a->Container_Unit < 0) && (b->Container_Unit < 0)) || (a->Container_Unit == b->Container_Unit)) && + + // ... neither one is carrying a princess AND ... + ((a->carrying_princess_of_race < 0) && (b->carrying_princess_of_race < 0)) && + + // ... [they are both captured units OR are both native units] AND ... + (! (is_captured (a) ^ is_captured (b))) && + + // ... their custom names are identical. + (0 == strncmp (a->Custom_Name.S, b->Custom_Name.S, sizeof (a->Custom_Name))); + + if ((! are_surface_duplicates) || surface_only) + return are_surface_duplicates; + + // a and b are additionally "deep", i.e. in all ways, duplicates if... + bool are_deep_duplicates = + // ... they've used up the same number of moves AND ... + (a->Moves == b->Moves) && + + // ... they have matching statuses (has attacked this turn, etc.) AND states (is fortified, is doing worker action, etc.) AND automation status AND ... + (a->Status == b->Status) && (a->UnitState == b->UnitState) && (a->automated == b->automated) && + + // ... they have both done the same number of airdrops this turn. + (itable_look_up_or (&is->airdrops_this_turn, a->ID, 0) == itable_look_up_or (&is->airdrops_this_turn, b->ID, 0)); + + return are_deep_duplicates; +} + +bool +is_busy (Unit * unit) +{ + int state = unit->Body.UnitState; + return ((state >= UnitState_Build_Mines) && (state <= UnitState_Explore)) || + (state == UnitState_Auto_Bombard) || (state == UnitState_Auto_Air_Bombard) || + unit->Body.automated; +} + +int __fastcall +patch_Context_Menu_add_item_and_set_color (Context_Menu * this, int edx, int item_id, char * text, int red) +{ + // Initialize the array of duplicate counts. The array is 0x100 items long because that's the maximum number of items a menu can have. + if (is->current_config.group_units_on_right_click_menu && + (is->unit_menu_duplicates == NULL)) { + unsigned dups_size = 0x100 * sizeof is->unit_menu_duplicates[0]; + is->unit_menu_duplicates = malloc (dups_size); + memset (is->unit_menu_duplicates, 0, dups_size); + } + + // Check if this menu item is a valid unit and grab pointers to its info + int unit_id; + Unit_Body * unit_body; + bool disable = false, put_icon = false; + int icon_index = 0; + if ((0 <= (unit_id = item_id - (0x13 + p_bic_data->UnitTypeCount))) && + (NULL != (unit_body = p_units->Units[unit_id].Unit)) && + (unit_body->UnitTypeID >= 0) && (unit_body->UnitTypeID < p_bic_data->UnitTypeCount)) { + + if (is->current_config.group_units_on_right_click_menu) { + // Loop over all existing menu items and check if any of them is a unit that's a duplicate of the one being added + for (int n = 0; n < this->Item_Count; n++) { + Context_Menu_Item * item = &this->Items[n]; + int dup_unit_id = this->Items[n].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount); + Unit_Body * dup_body; + if ((dup_unit_id >= 0) && + (NULL != (dup_body = p_units->Units[dup_unit_id].Unit)) && + are_units_duplicate (unit_body, dup_body, unit_body->CivID != p_main_screen_form->Player_CivID)) { + // The new item is a duplicate of the nth. Mark that in the duplicate counts array and return without actually + // adding the item. It doesn't matter what value we return because the caller doesn't use it. + is->unit_menu_duplicates[n] += 1; + return 0; + } + } + } + + if (unit_body->CivID == p_main_screen_form->Player_CivID) { + Unit * unit = (Unit *)((int)unit_body - offsetof (Unit, Body)); + UnitType * unit_type = &p_bic_data->UnitTypes[unit_body->UnitTypeID]; + bool no_moves_left = unit_body->Moves >= patch_Unit_get_max_move_points (unit); + if (no_moves_left && is->current_config.gray_out_units_on_menu_with_no_remaining_moves) + disable = true; + + // Put an icon next to this unit if we're configured to do so and it's not in an army + Unit * container; + if (is->current_config.put_movement_icons_on_units_on_menu && + ((NULL == (container = get_unit_ptr (unit_body->Container_Unit))) || + (! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)))) { + put_icon = true; + + bool attacker = is_offensive_combat_type (unit_type) || (Unit_has_ability (unit, __, UTA_Army) && (Unit_count_contained_units (unit) >= 1)), + busy = is_busy (unit); + + int icon_set_index = ((int)busy << 1) + (int)(! attacker); + + int icon_row; { + if (no_moves_left) + icon_row = URCMI_CANT_MOVE; + else if (unit_body->Moves == 0) + icon_row = URCMI_UNMOVED; + else if (! attacker) + icon_row = URCMI_MOVED_NO_ATTACK; + else + icon_row = (! has_exhausted_attack (unit)) ? URCMI_MOVED_CAN_ATTACK : URCMI_MOVED_NO_ATTACK; + } + + icon_index = icon_set_index * COUNT_UNIT_RCM_ICONS + icon_row; + } + } + } + + int tr = Context_Menu_add_item_and_set_color (this, __, item_id, text, red); + + if (disable) + Context_Menu_disable_item (this, __, item_id); + + if (put_icon) { + init_unit_rcm_icons (); + if (is->unit_rcm_icon_state == IS_OK) + Context_Menu_put_image_on_item (this, __, item_id, &is->unit_rcm_icons[icon_index]); + } + + return tr; +} + +int __fastcall +patch_Context_Menu_open (Context_Menu * this, int edx, int x, int y, int param_3) +{ + int * p_stack = (int *)&x; + int ret_addr = p_stack[-1]; + + if (is->current_config.enable_named_tiles && + is->named_tile_menu_active) { + int tile_x = is->named_tile_menu_tile_x; + int tile_y = is->named_tile_menu_tile_y; + Tile * tile = tile_at (tile_x, tile_y); + if (tile_can_be_named (tile, tile_x, tile_y)) { + struct named_tile_entry * entry = get_named_tile_entry (tile); + char menu_text[64]; + if ((entry != NULL) && (entry->name[0] != '\0')) + snprintf (menu_text, sizeof menu_text, "%s %s", is->c3x_labels[CL_RENAME_TILE], entry->name); + else + strcpy (menu_text,is->c3x_labels[CL_NAME_TILE]); + if (this->Item_Count > 0) + Context_Menu_add_separator (this, __, 0); + Context_Menu_add_item (this, __, NAMED_TILE_MENU_ID, menu_text, false, (Sprite *)0x0); + } + } + + if (is->current_config.group_units_on_right_click_menu && + (ret_addr == ADDR_OPEN_UNIT_MENU_RETURN) && + (is->unit_menu_duplicates != NULL)) { + + // Change the menu text to include the duplicate counts. This is pretty straight forward except for a couple little issues: we must + // use the game's internal malloc & free for compatibility with the base code and must call a function that widens the menu form, + // as necessary, to accommodate the longer strings. + for (int n = 0; n < this->Item_Count; n++) + if (is->unit_menu_duplicates[n] > 0) { + Context_Menu_Item * item = &this->Items[n]; + unsigned new_text_len = strlen (item->Text) + 20; + char * new_text = civ_prog_malloc (new_text_len); + + // Print entry text including dup count to new_text. Biggest complication here is that we want to print the dup count + // after any leading spaces to preserve indentation. + { + int num_spaces = 0; + while (item->Text[num_spaces] == ' ') + num_spaces++; + snprintf (new_text, new_text_len, "%.*s%dx %s", num_spaces, item->Text, is->unit_menu_duplicates[n] + 1, &item->Text[num_spaces]); + new_text[new_text_len - 1] = '\0'; + } + + civ_prog_free (item->Text); + item->Text = new_text; + Context_Menu_widen_for_text (this, __, new_text); + } + + // Clear the duplicate counts + memset (is->unit_menu_duplicates, 0, 0x100 * sizeof is->unit_menu_duplicates[0]); + } + + return Context_Menu_open (this, __, x, y, param_3); +} + +bool +is_material_unit (UnitType const * type, bool * out_is_pop_else_caravan) +{ + int join_city_action = UCV_Join_City & 0x0FFFFFFF; // To get the join city action code, use the command value and mask out the top 4 category bits + int disband_action = UCV_Disband & 0x0FFFFFFF; + if ((type->Attack | type->Defence | type->Bombard_Strength) == 0) { // if non-combat unit + if ((type->PopulationCost > 0) && (type->Worker_Actions == join_city_action)) { + *out_is_pop_else_caravan = true; + return true; + } else if ((type->Standard_Actions & disband_action) && (type->Worker_Actions == 0)) { + *out_is_pop_else_caravan = false; + return true; + } else + return false; + } else + return false; +} + +void +ai_move_material_unit (Unit * this) +{ + int type_id = this->Body.UnitTypeID; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + UnitType * type = &p_bic_data->UnitTypes[type_id]; + + // Determine whether this is a pop unit (will search for a city to join) or a caravan (will search for a city to disband) + int join_city_action = UCV_Join_City & 0x0FFFFFFF; + bool pop_else_caravan = type->Worker_Actions == join_city_action; + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + + // This part of the code follows how the replacement leader AI works. Basically it disbands the unit if it's on a continent with no + // friendly cities, then flees if it's in danger, then moves it along a set path if it has one. + if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { + Unit_disband (this); + return; + } + if (any_enemies_near_unit (this, 49)) { + Unit_set_state (this, __, UnitState_Fleeing); + bool done = this->vtable->work (this); + if (done || (this->Body.UnitState != 0)) + return; + } + byte next_move = Unit_pop_next_move_from_path (this); + if (next_move > 0) { + this->vtable->Move (this, __, next_move, 0); + return; + } + + // Find the best city to act on + City * best_city = NULL; + int best_city_value = pop_else_caravan ? -1 : 0; // min value to act is 0 for pop units, 1 for caravans + FOR_CITIES_OF (coi, this->Body.CivID) { + City * city = coi.city; + Tile * city_tile = tile_at (city->Body.X, city->Body.Y); + if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { + + if (pop_else_caravan) { + // Skip this city if it can't support another citizen + if ((city->Body.FoodIncome <= 0) || + (City_requires_improvement_to_grow (city) > -1)) + continue; + } else { + // Skip this city if its current build can't be rushed + if (! City_can_take_outside_shields (city, __, 0)) + continue; + } + + // Consider distance. + int dist_in_turns; + if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) + continue; // No path or unit cannot move + + int value; + if (pop_else_caravan) + value = 1000 / (10 + dist_in_turns); // Base value of 100 * 10 / (10 + dist_in_turn) + else { + // value is number of useful shields we'd get by moving to this city and disbanding there + int shields_per_turn = get_city_production_rate (city, city->Body.Order_Type, city->Body.Order_ID), + shields_to_complete_build = City_get_order_cost (city) - City_get_order_progress (city) - shields_per_turn, + disband_value = Leader_get_unit_cost (&leaders[city->Body.CivID], __, type_id, false) >> 2; + value = not_above (shields_to_complete_build, disband_value) - shields_per_turn * dist_in_turns; + } + + // Scale value by city corruption rate for pop units or caravan units targeting cities building improvs + if (pop_else_caravan || (city->Body.Order_Type == COT_Improvement)) { + int good_shields = city->Body.ProductionIncome, + corrupt_shields = city->Body.ProductionLoss; + if (good_shields + corrupt_shields > 0) + value = (value * good_shields) / (good_shields + corrupt_shields); + else + value = -1; + } + + if (value > best_city_value) { + best_city = city; + best_city_value = value; + } + } + } + + // Join city if we're already in the city we want to join, otherwise move to that city. If we couldn't find a city to join, go to the + // nearest established city and wait. + City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); + City * moving_to_city = NULL; + if (best_city != NULL) { + if (best_city == in_city) { + if (pop_else_caravan && patch_Unit_can_perform_command (this, __, UCV_Join_City)) { + Unit_join_city (this, __, in_city); + return; + } else if ((! pop_else_caravan) && patch_Unit_can_perform_command (this, __, UCV_Disband)) { + Unit_disband (this); + return; + } + } else + moving_to_city = best_city; + } else if (in_city == NULL) + moving_to_city = find_nearest_established_city (this, continent_id); + + if (moving_to_city) { + int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); + if (first_move > 0) { + Unit_set_escortee (this, __, -1); + this->vtable->Move (this, __, first_move, 0); + return; + } + } + + // Nothing to do, nowhere to go, just fortify in place. + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +int __stdcall +patch_get_anarchy_length (int leader_id) +{ + int base = get_anarchy_length (leader_id); + int multiplier = is->current_config.anarchy_length_percent; + if (multiplier != 100) { + // Anarchy cannot be less than 2 turns or you'll get an instant government switch. Only let that happen when the percent multiplier is + // set below zero, indicating a desire for no anarchy. Otherwise we can't reduce anarchy below 2 turns. + if (multiplier < 0) + return 1; + else if (base <= 2) + return base; + else + return not_below (2, rand_div (base * multiplier, 100)); + } else + return base; +} + +bool __fastcall +patch_Unit_check_king_ability_while_spawning (Unit * this, int edx, enum UnitTypeAbilities a) +{ + if (is->current_config.dont_give_king_names_in_non_regicide_games && + ((*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) == 0)) + return false; + else + return Unit_has_ability (this, __, a); +} + +int __fastcall +patch_Map_compute_neighbor_index_for_pass_between (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + if (is->current_config.enable_land_sea_intersections) + return 0; + else + return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); +} + +// This call replacement used to be part of improvement perfuming but now its only purpose is to set ai_considering_order when +// ai_choose_production is looping over improvements. +bool __fastcall +patch_Improvement_has_wonder_com_bonus_for_ai_prod (Improvement * this, int edx, enum ImprovementTypeWonderFeatures flag) +{ + is->ai_considering_order.OrderID = this - p_bic_data->Improvements; + is->ai_considering_order.OrderType = COT_Improvement; + return Improvement_has_wonder_flag (this, __, flag); +} + +// Similarly, this one sets the var when looping over unit types. +bool __fastcall +patch_UnitType_has_strat_0_for_ai_prod (UnitType * this, int edx, byte n) +{ + is->ai_considering_order.OrderID = this - p_bic_data->UnitTypes; + is->ai_considering_order.OrderType = COT_Unit; + return UnitType_has_ai_strategy (this, __, n); +} + +int +compare_ai_prod_valuations (void const * vp_a, void const * vp_b) +{ + struct ai_prod_valuation const * a = vp_a, + * b = vp_b; + if (a->point_value > b->point_value) return -1; + else if (b->point_value > a->point_value) return 1; + else return 0; +} + +void +rank_ai_production_options (City * city) +{ + is->count_ai_prod_valuations = 0; + City_Order unused; + patch_City_ai_choose_production (city, __, &unused); // records valuations in is->ai_prod_valuations + qsort (is->ai_prod_valuations, is->count_ai_prod_valuations, sizeof is->ai_prod_valuations[0], compare_ai_prod_valuations); +} + +void __fastcall +patch_City_Form_m82_handle_key_event (City_Form * this, int edx, int virtual_key_code, int is_down) +{ + if (is->current_config.enable_ai_production_ranking && + (~*p_human_player_bits & (1 << this->CurrentCity->Body.CivID)) && + (virtual_key_code == VK_P) && is_down) { + rank_ai_production_options (this->CurrentCity); + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_AI_PROD_RANKING", -1, 0, 0, 0); + char s[200]; + for (int n = 0; n < is->count_ai_prod_valuations; n++) { + struct ai_prod_valuation const * val = &is->ai_prod_valuations[n]; + char * name = (val->order_type == COT_Improvement) ? p_bic_data->Improvements[val->order_id].Name.S : p_bic_data->UnitTypes[val->order_id].Name; + + int show_strategy = -1; + if (val->order_type == COT_Unit) + itable_look_up (&is->unit_type_alt_strategies, val->order_id, &show_strategy); + + if ((show_strategy >= 0) && (show_strategy <= CL_LAST_UNIT_STRAT - CL_FIRST_UNIT_STRAT)) + snprintf (s, sizeof s, "^%d %s (%s)", val->point_value, name, is->c3x_labels[CL_FIRST_UNIT_STRAT + show_strategy]); + else + snprintf (s, sizeof s, "^%d %s", val->point_value, name); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + patch_show_popup (popup, __, 0, 0); + + } else if (is->current_config.toggle_zoom_with_z_on_city_screen && + (virtual_key_code == VK_Z) && is_down) { + p_bic_data->is_zoomed_out = ! p_bic_data->is_zoomed_out; + Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, this->CurrentCity->Body.X, get_city_screen_center_y (this->CurrentCity), 0, true, false); // also redraws map + this->Base.vtable->m73_call_m22_Draw ((Base_Form *)this); + } + + City_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); +} + +bool +can_harvest_shields_from_forest (Tile * tile) +{ + int flags = tile->vtable->m43_Get_field_30 (tile); + return (flags & 0x10000000) == 0; +} + +void __fastcall +patch_open_tile_info (void * this, int edx, int mouse_x, int mouse_y, int civ_id) +{ + int tx, ty; + if (is->current_config.show_detailed_tile_info && + (! Main_Screen_Form_get_tile_coords_under_mouse (p_main_screen_form, __, mouse_x, mouse_y, &tx, &ty))) { + is->viewing_tile_info_x = tx; + is->viewing_tile_info_y = ty; + is->tile_info_open = true; + } else + is->viewing_tile_info_x = is->viewing_tile_info_y = -1; + + open_tile_info (this, __, mouse_x, mouse_y, civ_id); + + is->tile_info_open = false; +} + +int __fastcall +patch_Match_ai_eval_city_location (void * this, int edx, int x, int y, int civ_id, bool param_4, int * out_breakdown) +{ + is->ai_evaling_city_loc_x = x; + is->ai_evaling_city_loc_y = y; + is->ai_evaling_city_field_30_get_counter = 0; + + return Match_ai_eval_city_location (this, __, x, y, civ_id, param_4, out_breakdown); +} + +bool +is_explored (Tile * tile, int civ_id) +{ + unsigned explored_bits = tile->Body.Fog_Of_War; + int in_debug_mode = (*p_debug_mode_bits & 8) != 0; // checking bit 3 here b/c that's how resource visibility is checked in open_tile_info + if (in_debug_mode || (explored_bits & (1 << civ_id))) + return true; + else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND + ((1 << civ_id) & *p_human_player_bits) && // "civ_id" is a human player AND + (explored_bits & *p_human_player_bits)) // any human player has visibility on the tile + return true; + else + return false; +} + +// On the GOG executable, this function intercepts the call to draw the "No information available" text on a unexplored (black) tile. In that case we +// replace that text with the coords. But on the Steam EXE this func also intercepts the call that draws the resource name on the visible tile info +// box b/c the call site is reused via a jump. So we must check that the tile is actually unexplored before replacing the text so that the resource +// name doesn't get overwritten. +int __fastcall +patch_PCX_Image_draw_no_tile_info (PCX_Image * this, int edx, char * str, int x, int y, int str_len) +{ + Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if ((tile != p_null_tile) && ! is_explored (tile, p_main_screen_form->Player_CivID)) { + char s[100]; + snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); + s[(sizeof s) - 1] = '\0'; + return PCX_Image_draw_text (this, __, s, x, y, strlen (s)); + } else + return PCX_Image_draw_text (this, __, str, x, y, str_len); +} + +int __fastcall +patch_PCX_Image_draw_tile_info_terrain (PCX_Image * this, int edx, char * str, int x, int y, int str_len) +{ + Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if (tile != p_null_tile) { + bool show_district_name = false; + + char s[200]; + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + // Draw district name to the right of terrain name if tile has one + struct district_instance * dist = get_district_instance (tile); + + if (dist != NULL) { + show_district_name = true; + char const * display_name = is->district_configs[dist->district_id].display_name; + if ((display_name == NULL) || (display_name[0] == '\0')) + display_name = is->district_configs[dist->district_id].name; + + // If it's a wonder district with a completed wonder, show the wonder name instead + if ((dist->district_id == WONDER_DISTRICT_ID) && + (dist->wonder_info.state == WDS_COMPLETED) && + (dist->wonder_info.wonder_index >= 0) && + (dist->wonder_info.wonder_index < is->wonder_district_count)) { + char const * wonder_name = is->wonder_district_configs[dist->wonder_info.wonder_index].wonder_name; + if ((wonder_name != NULL) && (wonder_name[0] != '\0')) { + display_name = wonder_name; + } + } else if ((dist->district_id == NATURAL_WONDER_DISTRICT_ID) && + (dist->natural_wonder_info.natural_wonder_id >= 0) && + (dist->natural_wonder_info.natural_wonder_id < is->natural_wonder_count)) { + int natural_id = dist->natural_wonder_info.natural_wonder_id; + char const * natural_name = is->natural_wonder_configs[natural_id].name; + if ((natural_name != NULL) && (natural_name[0] != '\0')) { + display_name = natural_name; + } + } + + snprintf (s, sizeof s, "%s", display_name); + PCX_Image_draw_text (this, __, s, x + 68, y, strlen (s)); + } + } + + // Show sprites & sheet indexes if in debug mode + int is_debug_mode = (*p_debug_mode_bits & 4) != 0; + if (is_debug_mode) { + int sheet_index = (tile->SquareParts >> 8) & 0xFF; + int sprite_index = tile->SquareParts & 0xFF; + snprintf (s, sizeof s, "%d, %d", sheet_index, sprite_index); + PCX_Image_draw_text (this, __, s, x, y - 18, strlen (s)); + } + + // Draw tile coords on line below terrain name + snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); + PCX_Image_draw_text (this, __, s, x, y + 14, strlen (s)); + + if ((is->city_loc_display_perspective >= 0) && + ((1 << is->city_loc_display_perspective) & *p_player_bits)) { + int eval = patch_Match_ai_eval_city_location (p_match, __, is->viewing_tile_info_x, is->viewing_tile_info_y, is->city_loc_display_perspective, false, NULL); + if (eval > 0) { + snprintf (s, sizeof s, "%d", eval - 1000000); + PCX_Image_draw_text (this, __, s, x + 95, y, strlen (s)); + } + } + + // If tile has been chopped and district name not shown (uses same space), indicate that to the right of the terrain name + if (! can_harvest_shields_from_forest (tile) && !show_district_name) + PCX_Image_draw_text (this, __, is->c3x_labels[CL_CHOPPED], x + 145, y, strlen (is->c3x_labels[CL_CHOPPED])); + } + return PCX_Image_draw_text (this, __, str, x, y, str_len); +} + +int __fastcall +patch_City_compute_corrupted_yield (City * this, int edx, int gross_yield, bool is_production) +{ + Leader * leader = &leaders[this->Body.CivID]; + + if (is->current_config.zero_corruption_when_off && + (p_bic_data->Governments[leader->GovernmentType].CorruptionAndWaste == CWT_Off)) + return 0; + + int tr = City_compute_corrupted_yield (this, __, gross_yield, is_production); + + if (is->current_config.promote_wonder_decorruption_effect) { + int actual_capital_id = leader->CapitalID; + for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { + Improvement * improv = &p_bic_data->Improvements[improv_id]; + City * pseudo_capital = NULL; + if (improv->SmallWonderFlags & ITSW_Reduces_Corruption) { + if (improv->Characteristics & ITC_Small_Wonder) { + pseudo_capital = get_city_ptr (leader->Small_Wonders[improv_id]); + } else if (improv->Characteristics & ITC_Wonder) { + pseudo_capital = get_city_ptr (Game_get_wonder_city_id(p_game, __, improv_id)); + } + + if (pseudo_capital != NULL && pseudo_capital->Body.CivID == this->Body.CivID && pseudo_capital->Body.ID != actual_capital_id) { + leader->CapitalID = pseudo_capital->Body.ID; + int fp_corrupted_yield = City_compute_corrupted_yield (this, __, gross_yield, is_production); + if (fp_corrupted_yield < tr) + tr = fp_corrupted_yield; + } + } + } + leader->CapitalID = actual_capital_id; + } + + return tr; +} + +int __fastcall +patch_Sprite_draw (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + Sprite * to_draw = get_sprite_proxy_for_current_hour(this); + return Sprite_draw(to_draw ? to_draw : this, __, canvas, pixel_x, pixel_y, color_table); +} + +int __fastcall +patch_Sprite_draw_on_map (Sprite * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) +{ + Sprite * to_draw = get_sprite_proxy_for_current_hour(this); + return Sprite_draw_on_map(to_draw ? to_draw : this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); +} + +bool +is_or_could_become_grassland (Tile * tile) +{ + enum SquareTypes sq_type = tile->vtable->m50_Get_Square_BaseType (tile), + underlying_type = tile->vtable->m49_Get_Square_RealType (tile); + int worker_job_id = p_bic_data->TileTypes[sq_type].WorkerJobID; + return sq_type == SQ_Grassland || + (underlying_type == SQ_Grassland && (worker_job_id == WJ_Clean_Forest || worker_job_id == WJ_Clear_Swamp)) || + tile->vtable->m72_Get_Pollution_Effect (tile) == SQ_Grassland; +} + +void __fastcall +patch_Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (Map_Renderer * this, int edx, int param_1, int pixel_x, int pixel_y, Map_Renderer * map_renderer, int param_5, int tile_x, int tile_y, int param_8) +{ + Map * map = &p_bic_data->Map; + Tile * tile = tile_at (tile_x, tile_y); + + is->current_render_tile = tile; + is->current_render_tile_x = tile_x; + is->current_render_tile_y = tile_y; + is->current_render_tile_district = get_district_instance (tile); + + Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (this, __, param_1, pixel_x, pixel_y, map_renderer, param_5, tile_x, tile_y, param_8); + + is->current_render_tile = NULL; + is->current_render_tile_x = -1; + is->current_render_tile_y = -1; + is->current_render_tile_district = NULL; + + if ((is->city_loc_display_perspective >= 0) && + (! map->vtable->m10_Get_Map_Zoom (map)) && // Turn off display when zoomed out. Need another set of highlight images for that. + ((1 << is->city_loc_display_perspective) & *p_player_bits) && + (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. + + init_tile_highlights (); + if (is->tile_highlight_state == IS_OK) { + int eval = patch_Match_ai_eval_city_location (p_match, __, tile_x, tile_y, is->city_loc_display_perspective, false, NULL); + if (eval > 0) { + int step_size = 10; + int midpoint = (COUNT_TILE_HIGHLIGHTS % 2 == 0) ? 1000000 : (1000000 - step_size/2); + int grade = (eval >= midpoint) ? (eval - midpoint) / step_size : (eval - midpoint) / step_size - 1; + int i_highlight = clamp (0, COUNT_TILE_HIGHLIGHTS - 1, COUNT_TILE_HIGHLIGHTS/2 + grade); + Sprite_draw_on_map (&is->tile_highlights[i_highlight], __, this, pixel_x, pixel_y, 1, 1, 1, 0); + } + } + } + + // Districts-related highlights + if (is->current_config.enable_districts && + (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. + init_tile_highlights (); + if (is->tile_highlight_state == IS_OK) { + + // Draw city work radius highlights for selected worker + if (is->current_config.enable_city_work_radii_highlights && + is->highlight_city_radii) { + + if ((tile != NULL) && (tile != p_null_tile)) { + int stored_ptr; + if (itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)tile, &stored_ptr)) { + struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)stored_ptr; + Sprite_draw_on_map (&is->tile_highlights[clamp(0, COUNT_TILE_HIGHLIGHTS - 1, info->highlight_level)], __, this, pixel_x, pixel_y, 1, 1, 1, 0); + } + } + } + + // If focusing on a tile after Great Wall completed, highlight the tile while getting user confirmation + if (is->focused_tile != NULL && is->focused_tile == tile) { + Sprite_draw_on_map (&is->tile_highlights[10], __, this, pixel_x, pixel_y, 1, 1, 1, 0); + } + } + } +} + +// We determine at the start of the game where *any* AI player might want to build canals and bridges. +// This is done up front in a single pass, as re-assessing every single turn per AI is wasteful and the +// geography of the map doesn't change. This function adds all the candidates as districts, effectively +// drawing them directly on the map. We don't use it in a normal game, but this is extremely useful for +// debugging so good to keep it around. For debugging, just call it immediately after +// generate_ai_canal_and_bridge_targets () +void +insert_ai_candidate_bridge_or_canals_into_district_tile_map () +{ + if ((is->ai_candidate_bridge_or_canals_count <= 0) || (! is->ai_candidate_bridge_or_canals_initialized)) + return; + + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if (entry == NULL) + continue; + + char ss[256]; + snprintf (ss, sizeof ss, "Entry %d: district %d owner %d tiles %d completed %d\n", + ei, entry->district_id, entry->owner_civ_id, entry->tile_count, entry->completed ? 1 : 0); + (*p_OutputDebugStringA)(ss); + + for (int ti = 0; ti < entry->tile_count; ti++) { + int tx = entry->tile_x[ti]; + int ty = entry->tile_y[ti]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + snprintf (ss, sizeof ss, " (%d,%d)%s\n", tx, ty, (ti == entry->assigned_tile_index) ? " [assigned]" : ""); + (*p_OutputDebugStringA)(ss); + } + } + + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if ((entry == NULL) || (entry->completed)) + continue; + + for (int ti = 0; ti < entry->tile_count; ti++) { + int tx = entry->tile_x[ti]; + int ty = entry->tile_y[ti]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int key = (int)tile; + int existing; + if (itable_look_up (&is->district_tile_map, key, &existing)) + continue; + + struct district_instance * inst = (struct district_instance *)calloc (1, sizeof *inst); + if (inst == NULL) + continue; + inst->state = DS_COMPLETED; + inst->district_id = entry->district_id; + inst->tile_x = tx; + inst->tile_y = ty; + + itable_insert (&is->district_tile_map, key, (int)inst); + } + } +} + +void __fastcall +patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (Map_Renderer * this, int edx, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (! is->current_config.draw_forests_over_roads_and_railroads) { + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + Tile * tile = is->current_render_tile; + if ((tile == NULL) || (tile == p_null_tile)) + return; + + if ((tile->vtable->m50_Get_Square_BaseType (tile) == SQ_Forest) && + (*tile->vtable->m25_Check_Roads)(tile, __, 0)) { + is->draw_forests_over_roads_on_tile = true; + return; + } + + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Map_Renderer_m52_Draw_Roads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + // Don't draw roads if a bridge is here + if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { + Tile * tile = is->current_render_tile; + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * dist = get_district_instance (tile); + if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { + return; + } + } + } + + Map_Renderer_m52_Draw_Roads (this, __, image_index, map_renderer, pixel_x, pixel_y); + + if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) + return; + + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Map_Renderer_m52_Draw_Railroads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + // Don't draw railroads if a bridge is here + if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { + Tile * tile = is->current_render_tile; + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * dist = get_district_instance (tile); + if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { + return; + } + } + } + + Map_Renderer_m52_Draw_Railroads (this, __, image_index, map_renderer, pixel_x, pixel_y); + + if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) + return; + + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Main_Screen_Form_m82_handle_key_event (Main_Screen_Form * this, int edx, int virtual_key_code, int is_down) +{ + char s[200]; + int * last_events = is->last_main_screen_key_up_events; + bool in_game = *p_player_bits != 0; // Player bits all zero indicates we aren't currently in a game. Need to check for this because UI events + // on the main menu also pass through this function. + + if (! is_down) { + for (int n = ARRAY_LEN (is->last_main_screen_key_up_events) - 1; n > 0; n--) + last_events[n] = last_events[n - 1]; + last_events[0] = virtual_key_code; + } + + if (is->current_config.enable_ai_city_location_desirability_display && + (virtual_key_code == VK_L) && is_down && + (! (is_command_button_active (&this->GUI, UCV_Load) || is_command_button_active (&this->GUI, UCV_Unload))) && + in_game) { + int is_debug_mode = (*p_debug_mode_bits & 4) != 0; // This is how the check is done in open_tile_info. Actually there are two debug + // mode bits (4 and 8) and I don't know what the difference is. + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CITY_LOC_HIGHLIGHTS", -1, 0, 0x40, 0); + snprintf (s, sizeof s, " %s", is->c3x_labels[CL_OFF]); + s[(sizeof s) - 1] = '\0'; + PopupSelection_add_item (&popup->selection, __, s, 0); + for (int n = 1; n < 32; n++) + if ((*p_player_bits & (1 << n)) && + (is_debug_mode || (n == p_main_screen_form->Player_CivID))) { + Race * race = &p_bic_data->Races[leaders[n].RaceID]; + snprintf (s, sizeof s, " (%d) %s", n, race->vtable->GetLeaderName (race)); + s[(sizeof s) - 1] = '\0'; + PopupSelection_add_item (&popup->selection, __, s, n); + } + int sel = patch_show_popup (popup, __, 0, 0); + if (sel >= 0) { // -1 indicates popup was closed without making a selection + is->city_loc_display_perspective = (sel >= 1) ? sel : -1; + this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw + } + + } else if (is->current_config.enable_debug_mode_switch && + (in_game && ! is_down) && + (last_events[4] == VK_D) && (last_events[3] == VK_E) && (last_events[2] == VK_B) && (last_events[1] == VK_U) && (last_events[0] == VK_G)) { + PopupForm * popup = get_popup_form (); + if ((*p_debug_mode_bits & 0xC) != 0) { // Consider debug mode on if either bit is set + *p_debug_mode_bits &= ~0xC; + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + PopupForm_add_text (popup, __, "Debug mode deactivated.", 0); + patch_show_popup (popup, __, 0, 0); + } else { + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_DEBUG_ACTIVATION", -1, 0, 0, 0); + int sel = patch_show_popup (popup, __, 0, 0); + if (sel == 0) { + *p_debug_mode_bits |= 0xC; + *(bool *)((int)p_human_player_bits + 37) = true; // Set MegaTrainerXL flag indicating edited save + } + } + this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw + + // Worker keyboard shortcuts that would normally go to patch_Main_Screen_Form_issue_command + // unfortunately get short-circuited if a district is on a tile and the default popup to replace a "mine" is shown. + // The only way to catch these beforehand I've found it is to intercept the key event here. + } else if (is->current_config.enable_districts && + p_main_screen_form->Current_Unit != NULL && + is_down && + is_worker (p_main_screen_form->Current_Unit)) { + int command = -1; + bool removed_existing = false; + if (virtual_key_code == VK_M && is_command_button_active (&this->GUI, UCV_Build_Mine)) command = UCV_Build_Mine; + else if (virtual_key_code == VK_I && is_command_button_active (&this->GUI, UCV_Irrigate)) command = UCV_Irrigate; + else if (virtual_key_code == VK_N && is_command_button_active (&this->GUI, UCV_Plant_Forest)) command = UCV_Plant_Forest; + + if (handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) { + Main_Screen_Form_issue_command (this, __, command, p_main_screen_form->Current_Unit); + } + } + +after_district_key_handling: + Main_Screen_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); +} + +int __fastcall +patch_Unit_get_move_points_after_airdrop (Unit * this) +{ + int prev_airdrop_count = itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0); + itable_insert (&is->airdrops_this_turn, this->Body.ID, prev_airdrop_count + 1); + + return is->current_config.dont_end_units_turn_after_airdrop ? this->Body.Moves : patch_Unit_get_max_move_points (this); +} + +int __fastcall +patch_Unit_get_move_points_after_set_to_intercept (Unit * this) +{ + return is->current_config.patch_intercept_lost_turn_bug ? this->Body.Moves : patch_Unit_get_max_move_points (this); +} + +void __cdecl +activate_mod_info_button (int control_id) +{ + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + char s[500]; + char version_letter = 'A' + MOD_VERSION%100; + + if (MOD_PREVIEW_VERSION == 0) + snprintf (s, sizeof s, "%s: %d%c", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' '); + else + snprintf (s, sizeof s, "%s: %d%c%s %d", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' ', is->c3x_labels[CL_PREVIEW], MOD_PREVIEW_VERSION); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_CONFIG_FILES_LOADED]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + int n = 1; + for (struct loaded_config_name * lcn = is->loaded_config_names; lcn != NULL; lcn = lcn->next) { + snprintf (s, sizeof s, "^ %d. %s", n, lcn->name); + s[(sizeof s) - 1] = '\0'; + n++; + PopupForm_add_text (popup, __, s, 0); + } + + patch_show_popup (popup, __, 0, 0); +} + +int __fastcall +patch_Parameters_Form_m68_Show_Dialog (Parameters_Form * this, int edx, int param_1, void * param_2, void * param_3) +{ + init_mod_info_button_images (); + + // "b" is the mod info button. It's created each time the preferences form (or "parameters" form as Antal called it) is opened and destroyed + // every time the form is closed. This is the easiest way since it matches how the base game works. At first I tried creating the button once + // but then it will only appear once since its attachment to the prefs form is lost when the form is destroyed on closure. I tried reattaching + // the button to each newly created form but wasn't able to make that work. + Button * b = NULL; + if (is->mod_info_button_images_state == IS_OK) { + b = malloc (sizeof *b); + Button_construct (b); + + Button_initialize (b, __, + is->c3x_labels[CL_MOD_INFO_BUTTON_TEXT], // text + MOD_INFO_BUTTON_ID, // control ID + (p_bic_data->ScreenWidth - 1024) / 2 + 891, // location x + (p_bic_data->ScreenHeight - 768) / 2 + 31, // location y + MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height + (Base_Form *)this, // parent + 0); // ? + + for (int n = 0; n < 3; n++) + b->Images[n] = &is->mod_info_button_images[n]; + PCX_Image_set_font (&b->Base_Data.Canvas, __, get_font (15, FSF_NONE), 0, 0, 0); + b->activation_handler = &activate_mod_info_button; + + // Need to draw once manually or the button won't look right + b->vtable->m73_call_m22_Draw ((Base_Form *)b); + } + + int tr = Parameters_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); + + if (b != NULL) { + b->vtable->destruct ((Base_Form *)b, __, 0); + free (b); + } + + return tr; +} + +bool __fastcall +patch_City_cycle_specialist_type (City * this, int edx, int mouse_x, int mouse_y, Citizen * citizen, City_Form * city_form) +{ + int specialist_count = 0; { + Leader * city_owner = &leaders[this->Body.CivID]; + for (int n = 0; n < p_bic_data->CitizenTypeCount; n++) + specialist_count += (n != p_bic_data->default_citizen_type) && + Leader_has_tech (city_owner, __, p_bic_data->CitizenTypes[n].RequireID); + } + int shift_down = (*p_GetAsyncKeyState) (VK_SHIFT) >> 8; + int original_worker_type = citizen->WorkerType; + + // The return value of this function is not actually used by either of the two original callers. + bool tr = City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); + + // Cycle all the way around back to the previous specialist type, if appropriate. + // If the worker type was not changed after the first call to cycle_specialist_type, that indicates that the player was asked to disable + // governor management and chose not to. Do not try to cycle backwards in that case or else we'll spam the player with more popups. + if (is->current_config.reverse_specialist_order_with_shift && + shift_down && (specialist_count > 2) && (citizen->WorkerType != original_worker_type)) { + for (int n = 0; n < specialist_count - 2; n++) + City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); + } + + return tr; +} + +int __fastcall +patch_City_get_pollution_from_pop (City * this) +{ + if (! is->current_config.enable_negative_pop_pollution) + return City_get_pollution_from_pop (this); + + int base_pollution = this->Body.Population.Size - p_bic_data->General.MaximumSize_City; + if (base_pollution <= 0) + return 0; + + // Consider improvements + int net_pollution = base_pollution; + int any_cleaning_improvs = 0; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * improv = &p_bic_data->Improvements[n]; + if ((improv->ImprovementFlags & ITF_Removes_Population_Pollution) && has_active_building (this, n)) { + any_cleaning_improvs = 1; + if (improv->Pollution < 0) + net_pollution += improv->Pollution; + } + } + + if (net_pollution <= 0) + return 0; + else if (any_cleaning_improvs) + return 1; + else + return net_pollution; +} + +// The original version of this function in the base game contains a duplicate of the logic that computes the total pollution from buildings and +// pop. By re-implementing it to use the get_pollution_from_* functions, we ensure that our changes to get_pollution_from_pop will be accounted for. +// Note: This function is called from two places, one is the city screen and the other I'm not sure about. The pollution spawning logic works by +// calling the get_pollution_from_* funcs directly. +int __fastcall +patch_City_get_total_pollution (City * this) +{ + return City_get_pollution_from_buildings (this) + patch_City_get_pollution_from_pop (this); +} + +void remove_extra_palaces (City * city, City * excluded_destination); + +void +set_wonder_built_flag (int improv_id, bool is_built) +{ + if ((p_match == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) + return; + + byte * built_flags = *(byte **)((byte *)p_match + 0x4fc); + if (built_flags == NULL) + return; + + built_flags[improv_id] = is_built; +} + +bool +choose_defensive_unit_order (City * city, City_Order * out_order) +{ + if ((city == NULL) || (out_order == NULL)) + return false; + + for (int pass = 0; pass < 3; pass++) { + int best_unit_id = -1; + int best_defence = -1; + + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if (! patch_City_can_build_unit (city, __, n, 1, 0, 0)) + continue; + + int defence = type->Defence; + if ((pass < 2) && (defence <= 0)) + continue; + if ((pass <= 1) && (type->Unit_Class != UTC_Land)) + continue; + if ((pass == 0) && ((type->AI_Strategy & UTAI_Defence) == 0)) + continue; + + if (defence > best_defence) { + best_defence = defence; + best_unit_id = n; + } + } + + if (best_unit_id >= 0) { + out_order->OrderType = COT_Unit; + out_order->OrderID = best_unit_id; + return true; + } + } + + return false; +} + +// When a city adds a building that depends on a district, optionally mirror that +// building to all other same-civ cities that can also work the district tile. +void +copy_building_with_cities_in_radius (City * source, int improv_id, int required_district_id, int tile_x, int tile_y) +{ + if (! is->current_config.enable_districts) return; + if (source == NULL) return; + + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + + if (is_wonder) { + if (! is->current_config.cities_with_mutual_district_receive_wonders) + return; + } else if (! is->current_config.cities_with_mutual_district_receive_buildings) + return; + + // If a Wonder, we know the specific tile it is at, so determine which other cities have that in work radius. + if (is_wonder) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile == p_null_tile) return; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != source->Body.CivID) return; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != required_district_id) return; + if (! district_is_complete (tile, required_district_id)) return; + + FOR_CITIES_OF (coi, source->Body.CivID) { + City * city = coi.city; + if (city == NULL) continue; + if (city == source) continue; + + if (! city_radius_contains_tile (city, tile_x, tile_y)) + continue; + + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) + continue; + + if (! patch_City_has_improvement (city, __, improv_id, false)) { + City_add_or_remove_improvement (city, __, improv_id, 1, false); + } + } + } + // Else there may be multiple district instances of this type, so check each tile around the city + else { + FOR_DISTRICTS_AROUND (wai, source->Body.X, source->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != required_district_id) continue; + + FOR_CITIES_OF (coi, source->Body.CivID) { + City * city = coi.city; + if (city == NULL) continue; + if (city == source) continue; + + if (! city_radius_contains_tile (city, x, y)) + continue; + + if (! patch_City_has_improvement (city, __, improv_id, false)) { + City_add_or_remove_improvement (city, __, improv_id, 1, false); + + // If city already building it, switch to a defensive unit instead + int current_improv_id = city->Body.Order_ID; + if (current_improv_id == improv_id) { + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + // Show message to user + if (is->current_config.show_message_when_building_received_by_mutual_district && + city->Body.CivID == p_main_screen_form->Player_CivID) { + char msg[300]; + snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_RECEIVED], + p_bic_data->Improvements[improv_id].Name.S, + is->c3x_labels[CL_FROM_SHARED], + is->district_configs[required_district_id].name, + is->c3x_labels[CL_WITH], + source->Body.CityName); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + } + } + } + } +} + +void +grant_existing_district_buildings_to_city (City * city) +{ + if (! is->current_config.enable_districts || + (! is->current_config.cities_with_mutual_district_receive_buildings && + ! is->current_config.cities_with_mutual_district_receive_wonders) || + (city == NULL)) + return; + + int civ_id = city->Body.CivID; + int current_improv_id = city->Body.Order_ID; + bool prev_flag = is->sharing_buildings_by_districts_in_progress; + is->sharing_buildings_by_districts_in_progress = true; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + Tile * tile = wai.tile; + + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + struct district_infos * info = &is->district_infos[district_id]; + if (info->dependent_building_count <= 0) + continue; + + FOR_CITIES_OF (coi, civ_id) { + City * other = coi.city; + if ((other == NULL) || (other == city)) + continue; + + if (! city_radius_contains_tile (other, wai.tile_x, wai.tile_y)) + continue; + + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != other->Body.CivID) + continue; + + for (int i = 0; i < info->dependent_building_count; i++) { + int building_id = info->dependent_building_ids[i]; + if (building_id < 0) + continue; + + Improvement * building = &p_bic_data->Improvements[building_id]; + bool is_wonder = (building->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + + if (is_wonder) + continue; + + if (! patch_City_has_improvement (other, __, building_id, false)) + continue; + + if (patch_City_has_improvement (city, __, building_id, false)) + continue; + + City_add_or_remove_improvement (city, __, building_id, 1, false); + + // If city already building it, switch to a defensive unit instead + if (current_improv_id == building_id) { + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + if (is->current_config.show_message_when_building_received_by_mutual_district && + city->Body.CivID == p_main_screen_form->Player_CivID) { + char msg[300]; + snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_RECEIVED], + p_bic_data->Improvements[building_id].Name.S, + is->c3x_labels[CL_FROM_SHARED], + is->district_configs[district_id].name, + is->c3x_labels[CL_WITH], + other->Body.CityName); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + } + } + } + + is->sharing_buildings_by_districts_in_progress = prev_flag; +} + +void +auto_build_great_wall_districts_for_civ (int civ_id) +{ + if ((! is->current_config.enable_districts) || + (! is->current_config.enable_great_wall_districts) || + (! is->current_config.auto_build_great_wall_around_territory) || + (is->great_wall_auto_build == GWABS_DONE) || + (civ_id < 0) || + is->is_placing_scenario_things) + return; + + bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; + + if ((GREAT_WALL_DISTRICT_ID < 0) || (GREAT_WALL_DISTRICT_ID >= is->district_count)) { + is->great_wall_auto_build = GWABS_DONE; + return; + } + + init_tile_highlights (); + + struct district_config const * cfg = &is->district_configs[GREAT_WALL_DISTRICT_ID]; + if ((cfg->command == -1) || (! leader_can_build_district (&leaders[civ_id], GREAT_WALL_DISTRICT_ID))) { + is->great_wall_auto_build = GWABS_DONE; + return; + } + + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_BEGIN_GREAT_WALL_AUTO_BUILD", -1, 0, 0, 0); + if (civ_id == p_main_screen_form->Player_CivID) + patch_show_popup (popup, __, 0, 0); + + is->great_wall_auto_build = GWABS_RUNNING; + + unsigned int const replaceable_flags = TILE_FLAG_MINE | TILE_FLAG_IRRIGATION; + bool require_other_civ_border = (! is_human) && is->current_config.ai_auto_build_great_wall_strategy == AAGWS_OTHER_CIV_BORDERED_ONLY; + + for (int index = 0; index < p_bic_data->Map.TileCount; index++) { + int x, y; + tile_index_to_coords (&p_bic_data->Map, index, &x, &y); + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->CityID >= 0) + continue; + if (tile->vtable->m35_Check_Is_Water (tile)) + continue; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) + continue; + + bool has_border = false; + bool has_other_civ_border = false; + FOR_TILES_AROUND (tai, 9, x, y) { + if (tai.n == 0) + continue; + Tile * neighbor = tai.tile; + if (neighbor->vtable->m35_Check_Is_Water (neighbor)) + continue; + int owner_id = neighbor->vtable->m38_Get_Territory_OwnerID (neighbor); + if (owner_id != civ_id) { + has_border = true; + if (owner_id > 0) { + has_other_civ_border = true; + break; + } + } + } + if (! has_border) + continue; + if (require_other_civ_border && (! has_other_civ_border)) + continue; + + if (! district_is_buildable_on_tile (cfg, tile)) + continue; + if (! district_resource_prereqs_met (tile, x, y, GREAT_WALL_DISTRICT_ID)) + continue; + + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == GREAT_WALL_DISTRICT_ID)) { + if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) { + inst->state = DS_COMPLETED; + if (! tile->vtable->m18_Check_Mines (tile, __, 0)) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); + set_tile_unworkable_for_all_cities (tile, x, y); + } + continue; + } + + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int replace_flags = overlay_flags & replaceable_flags; + bool has_district = (inst != NULL); + int existing_district_id = -1; + if (has_district) + existing_district_id = inst->district_id; + + if (is_human && civ_id == p_main_screen_form->Player_CivID) { + is->focused_tile = tile; + Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, x, y, 0, true, false); + + char * popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL"; + set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); + + if (has_district) { + bool redundant_district = district_instance_is_redundant (inst, tile); + bool would_lose_buildings; + would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, x, y); + if (redundant_district) + would_lose_buildings = false; + if ((existing_district_id >= 0) && (existing_district_id < is->district_count)) { + set_popup_str_param (1, (char *)is->district_configs[existing_district_id].display_name, -1, -1); + } + popup_key = would_lose_buildings + ? "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT" + : "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT_SAFE"; + } else if (replace_flags != 0) { + popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_IMPROVEMENT"; + } + + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + popup_key, + -1, 0, 0, 0); + + int sel = patch_show_popup (popup, __, 0, 0); + if (sel != 0) + continue; + } + + if (has_district || (replace_flags != 0)) { + if (has_district) { + int inst_x = x, inst_y = y; + if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) + continue; + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); + handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); + } + + if (replace_flags != 0) + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, replace_flags, x, y); + } + + if (get_district_instance (tile) != NULL) + continue; + + inst = ensure_district_instance (tile, GREAT_WALL_DISTRICT_ID, x, y); + if (inst == NULL) + continue; + + inst->district_id = GREAT_WALL_DISTRICT_ID; + district_instance_set_coords (inst, x, y); + inst->state = DS_COMPLETED; + if (! tile->vtable->m18_Check_Mines (tile, __, 0)) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); + set_tile_unworkable_for_all_cities (tile, x, y); + } + + is->great_wall_auto_build = GWABS_DONE; + is->focused_tile = NULL; +} + +//We need to forwards-declare this +void __fastcall +patch_City_manage_by_governor (City * this, int edx, bool manage_professions); + +void __fastcall +patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3) +{ + int init_maintenance = this->Body.Improvements_Maintenance; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder_removal = (! add) && + ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && + (! is->is_placing_scenario_things); + int init_work_area_radius = get_work_ring_limit_total(this); + + // The enable_negative_pop_pollution feature changes the rules so that improvements flagged as removing pop pollution and having a negative + // pollution amount contribute to the city's pop pollution instead of building pollution. Here we make sure that such improvements do not + // contribute to building pollution by temporarily zeroing out their pollution stat when they're added to or removed from a city. + if (is->current_config.enable_negative_pop_pollution && + (improv->ImprovementFlags & ITF_Removes_Population_Pollution) && + (improv->Pollution < 0)) { + int saved_pollution_amount = improv->Pollution; + improv->Pollution = 0; + City_add_or_remove_improvement (this, __, improv_id, add, param_3); + improv->Pollution = saved_pollution_amount; + } else + City_add_or_remove_improvement (this, __, improv_id, add, param_3); + + if (is->current_config.enable_districts && is_wonder_removal && ((improv->Characteristics & ITC_Wonder) != 0)) { + if (is->current_config.destroyed_wonders_can_be_built_again) + set_wonder_built_flag (improv_id, false); + + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, improv->Name.S, -1, -1); + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + is->current_config.destroyed_wonders_can_be_built_again ? "C3X_DISTRICT_WONDER_DESTROYED_REBUILD" : "C3X_DISTRICT_WONDER_DESTROYED", + -1, 0, 0, 0 + ); + patch_show_popup (popup, __, 0, 0); + } + + // If the city just finished a wonder and was using a wonder district for that, set the wonder + // as completed (which switches the art over and prevents the tile from being used again) + int x, y; + if (add && is->current_config.enable_districts && is->current_config.enable_wonder_districts) { + if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { + int matched_windex = find_wonder_config_index_by_improvement_id (improv_id); + + if (matched_windex >= 0) { + FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { + x = wai.tile_x; + y = wai.tile_y; + Tile * t = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + if (! wonder_is_buildable_on_tile (t, improv_id)) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if (info->state != WDS_UNDER_CONSTRUCTION) continue; + if (info->city_id != this->Body.ID) continue; + + // Mark this wonder district as completed with the wonder + info->city = this; + info->city_id = this->Body.ID; + info->state = WDS_COMPLETED; + info->wonder_index = matched_windex; + break; + } + } + } + } + + int gw_auto_build_improv_id = is->current_config.great_wall_auto_build_wonder_improv_id; + if (add && is->current_config.enable_districts && + is->current_config.auto_build_great_wall_around_territory && + (gw_auto_build_improv_id >= 0) && (improv_id == gw_auto_build_improv_id)) + auto_build_great_wall_districts_for_civ (this->Body.CivID); + + //Calculate if work_area has shrunk, and if so, redistribute citizens. + int post_work_area_radius = get_work_ring_limit_total(this); + if (post_work_area_radius < init_work_area_radius) { + patch_City_manage_by_governor(this, __, false); + } + + // Update things in case we've added or removed a mill. This is only necessary while in-game. If the game is still loading the scenario, it + // will recompute resources after it's done and we'll recompute yields and happiness ourselves. + if (! is->is_placing_scenario_things) { + // Collect info about this mill, if in fact the added or removed improvement is a mill. If it's not, all these vars will be left + // false. "generates_input" tracks whether or not the mill generates a resource that's an input for another mill. + bool is_non_local_mill, is_yielding_mill, generates_input; { + is_non_local_mill = is_yielding_mill = generates_input = false; + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if (mill->improv_id == improv_id) { + is_non_local_mill |= (mill->flags & MF_LOCAL) == 0; + is_yielding_mill |= (mill->flags & MF_YIELDS) != 0; + generates_input |= (is->mill_input_resource_bits[mill->resource_id >> 3] & (1 << (mill->resource_id & 7))) != 0; + } + } + } + + // If the mill generates a resource that's added to the trade network or it's generating an input (potentially used locally to + // generate a traded resource) then rebuild the resource network. This is not necessary if the improvement also affects trade routes + // since the base method will have already done this recomputation. + if ((is_non_local_mill || generates_input) && + ((improv->ImprovementFlags & ITF_Allows_Water_Trade) == 0) && + ((improv->ImprovementFlags & ITF_Allows_Air_Trade) == 0) && + ((improv->WonderFlags & ITW_Safe_Sea_Travel) == 0)) + patch_Trade_Net_recompute_resources (is->trade_net, __, 0); + + // If the mill adds yields or might be a link in a resource production chain that does, recompute yields in the city. + if (is_yielding_mill || generates_input) + patch_City_recompute_yields_and_happiness (this); + } + + // Adding or removing an obsolete improvement should not change the total maintenance since obsolete improvs shouldn't cost maintenance. In + // the base game, they usually do since the game doesn't update maintenance costs when buildings are obsoleted, but with that bug patched we + // can enforce the correct behavior. + if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && + (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) + this->Body.Improvements_Maintenance = init_maintenance; + + // If AI MCS is enabled and we've added the Palace to a city, then remove any extra palaces from that city. If we're in the process of + // capturing a city, it's necessary to exclude that city as a possible destination for removed extra palaces. + if ((is->current_config.ai_multi_city_start > 1) && + (! is->is_placing_scenario_things) && + add && (improv->ImprovementFlags & ITF_Center_of_Empire) && + ((*p_human_player_bits & (1 << this->Body.CivID)) == 0)) + remove_extra_palaces (this, is->currently_capturing_city); + + // If sharing wonders in hotseat mode, we must recompute improvement maintenance for all human players when any one of them gains or loses a + // wonder that grants free improvements. + if ((! is->is_placing_scenario_things) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->Body.CivID) & *p_human_player_bits)) { // is this city owned by a human player + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->Body.CivID)) + Leader_recompute_buildings_maintenance (&leaders[n_player]); + player_bits >>= 1; + n_player++; + } + } + + // Optionally share district-dependent buildings or wonders to other cities in range of the same district + bool allow_wonder_sharing = is->current_config.cities_with_mutual_district_receive_wonders; + bool allow_building_sharing = is->current_config.cities_with_mutual_district_receive_buildings; + + if ((! is->is_placing_scenario_things) && add && + is->current_config.enable_districts && (allow_building_sharing || allow_wonder_sharing) && + (! is->sharing_buildings_by_districts_in_progress)) { + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); + if (prereq_list != NULL) { + bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + if ((! is_wonder && allow_building_sharing) || (is_wonder && allow_wonder_sharing)) { + is->sharing_buildings_by_districts_in_progress = true; + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + copy_building_with_cities_in_radius (this, improv_id, district_id, x, y); + } + is->sharing_buildings_by_districts_in_progress = false; + } + } + } +} + +void __fastcall +patch_Fighter_begin (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender) +{ + Fighter_begin (this, __, attacker, attack_direction, defender); + + // Apply override of retreat eligibility + // Must use this->defender instead of the defender argument since the argument is often NULL, in which case Fighter_begin finds a defender on + // the target tile and stores it in this->defender. Also must check that against NULL since Fighter_begin might fail to find a defender. + enum UnitTypeClasses class = p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID].Unit_Class; + if ((this->defender != NULL) && ((class == UTC_Land) || (class == UTC_Sea))) { + enum retreat_rules retreat_rules = (class == UTC_Land) ? is->current_config.land_retreat_rules : is->current_config.sea_retreat_rules; + if (retreat_rules != RR_STANDARD) { + int attacker_max_mp = patch_Unit_get_max_move_points (this->attacker), + defender_max_mp = patch_Unit_get_max_move_points (this->defender); + + if (retreat_rules == RR_NONE) + this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 0; + else if (retreat_rules == RR_ALL_UNITS) + this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 1; + else if (retreat_rules == RR_IF_FASTER) { + this->attacker_eligible_to_retreat = attacker_max_mp > defender_max_mp; + this->defender_eligible_to_retreat = defender_max_mp > attacker_max_mp; + } else if (retreat_rules == RR_IF_NOT_SLOWER) { + this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp; + this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp; + } else if (retreat_rules == RR_IF_FAST_AND_NOT_SLOWER) { + this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp && attacker_max_mp > p_bic_data->General.RoadsMovementRate; + this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp && defender_max_mp > p_bic_data->General.RoadsMovementRate; + } + + // Prevent immobile units from retreating + this->attacker_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID], __, UTA_Immobile); + this->defender_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->defender->Body.UnitTypeID], __, UTA_Immobile); + + // Prevent defender from retreating if in a city + this->defender_eligible_to_retreat &= city_at (this->defender_location_x, this->defender_location_y) == NULL; + } + } +} + +void __fastcall +patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) +{ + // Determine whether this despawn happened involuntarily, i.e. whether it's because of the actions of a player other than its owner. This + // includes cases where the unit was destroyed in combat, captured, kicked from territory with nowhere to go, etc. + int ret_addr = ((int *)&civ_id_responsible)[-1]; + bool involuntary = + ret_addr == DESPAWN_TO_FIGHT_1_RETURN || ret_addr == DESPAWN_TO_FIGHT_2_RETURN + || ret_addr == DESPAWN_TO_DO_BOMBARD_TILE_RETURN || ret_addr == DESPAWN_TO_CRUISE_MISSILE_DEFENDER_RETURN + || ret_addr == DESPAWN_TO_BOUNCE_TRESPASSING_UNITS_RETURN || ret_addr == DESPAWN_TO_NUKE_DAMAGE_RETURN + || ret_addr == DESPAWN_RECURSIVE_RETURN || ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN + || ret_addr == DESPAWN_TO_TRY_FLYING_OVER_TILE_RETURN; + + int owner_id = this->Body.CivID; + int type_id = this->Body.UnitTypeID; + UnitType * type = &p_bic_data->UnitTypes[type_id]; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + // Clear extra DBs, airdrops, wait records, and transport ties used by this unit + itable_remove (&is->extra_defensive_bombards, this->Body.ID); + itable_remove (&is->airdrops_this_turn, this->Body.ID); + itable_remove (&is->waiting_units, this->Body.ID); + itable_remove (&is->unit_transport_ties, this->Body.ID); + + // If we're despawning the stored ZoC defender, clear that variable so we don't despawn it again in check_life_after_zoc + if (this == is->zoc_defender) + is->zoc_defender = NULL; + + if (this == is->sb_next_up) + is->sb_next_up = NULL; + + if (this == is->last_selected_unit.ptr) + is->last_selected_unit.ptr = NULL; + + // Remove this unit from the list of extra units to despawn after capturing + int original_count = is->count_extra_capture_despawns; + for (int n_src = 0, n_dest = 0; n_src < original_count; n_src++) { + if (is->extra_capture_despawns[n_src] != this) { + is->extra_capture_despawns[n_dest] = is->extra_capture_despawns[n_src]; + n_dest++; + } else + is->count_extra_capture_despawns -= 1; + } + + // If the unit being despawned is a land transport or helicopter, we may have to make sure to despawn its passengers as well because the base + // game won't. In general, the passengers are lost if the transport was despawned involuntarily, i.e. because of another player's attack or + // something like that, or if the passengers couldn't survive outside the transport, specifically because it's a helicopter at sea. + bool must_despawn_passengers = false; { + if (is_land_transport (this)) + must_despawn_passengers = involuntary && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); + + else if (type->Unit_Class == UTC_Air && type->Transport_Capacity > 0) { // if "this" is a helicopter + Unit * container = get_unit_ptr (this->Body.Container_Unit); + bool on_carrier = container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea && + Unit_has_ability (container, __, UTA_Transports_Only_Aircraft); + bool passengers_could_survive = Tile_has_city (tile) || ! tile->vtable->m35_Check_Is_Water (tile); + + // If no-defense-from-inside is off, passengers in helicopters will fight to defend their tile, so they wouldn't be left + // inside the helicopter when their tile is taken. If it's on, an occupied heli can be destroyed or captured by a land unit, + // and we must make sure to despawn the passengers in that case because they can't remain on the tile. Hence, + // no-defense-from-inside implies no-escape in almost all circumstances (nukes are the exception). + enum special_helicopter_rules special_rules = is->current_config.special_helicopter_rules; + if (((special_rules & SHR_ALLOW_ON_CARRIERS) && on_carrier) || (special_rules & (SHR_NO_DEFENSE_FROM_INSIDE | SHR_NO_ESCAPE))) + must_despawn_passengers = involuntary || ! passengers_could_survive; + } + } + + bool prev_always_despawn_passengers = is->always_despawn_passengers; + + if (must_despawn_passengers) { + // If we've been called from do_capture_units, record the passengers in the list of units to be despawned after do_capture_units + // returns. We can't simply despawn the units now even by setting always_despawn_passengers because the despawning messes up an + // iterator over tile units inside do_capture_units. + if (ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN) { + FOR_UNITS_ON (uti, tile) + if (uti.unit->Body.Container_Unit == this->Body.ID) { + reserve (sizeof is->extra_capture_despawns[0], // item size + (void **)&is->extra_capture_despawns, // ptr to items + &is->extra_capture_despawns_capacity, // ptr to capacity + is->count_extra_capture_despawns); // count + is->extra_capture_despawns[is->count_extra_capture_despawns] = uti.unit; + is->count_extra_capture_despawns += 1; + } + + } else + is->always_despawn_passengers = true; + } + + Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); + + is->always_despawn_passengers = prev_always_despawn_passengers; + + change_unit_type_count (&leaders[owner_id], type_id, -1); +} + +bool __fastcall +patch_Unit_do_capture_units (Unit * this, int edx, int tile_x, int tile_y, int owner_civ_id) +{ + is->count_extra_capture_despawns = 0; + + bool tr = Unit_do_capture_units (this, __, tile_x, tile_y, owner_civ_id); + + // Here we rely on patch_Unit_despawn to remove despawned units from the list + while (is->count_extra_capture_despawns > 0) + patch_Unit_despawn (is->extra_capture_despawns[0], __, this->Body.ID, 0, 0, 0, 0, 0, 0); + + return tr; +} + +void __fastcall +patch_Map_Renderer_m71_Draw_Tiles (Map_Renderer * this, int edx, int param_1, int param_2, int param_3) +{ + // Restore the tile count if it was saved by recompute_resources. This is necessary because the Draw_Tiles method loops over all tiles. + if (is->saved_tile_count >= 0) { + p_bic_data->Map.TileCount = is->saved_tile_count; + is->saved_tile_count = -1; + } + + Map_Renderer_m71_Draw_Tiles (this, __, param_1, param_2, param_3); +} + +struct named_tile_entry * +get_named_tile_entry (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + int stored_ptr = 0; + if (! itable_look_up (&is->named_tile_map, (int)tile, &stored_ptr)) + return NULL; + return (struct named_tile_entry *)stored_ptr; +} + +bool +prompt_for_named_tile (char const * seed_name, char * out_name, int out_len) +{ + if ((out_name == NULL) || (out_len <= 0)) + return false; + out_name[0] = '\0'; + + PopupForm * popup = get_popup_form (); + if (popup == NULL) + return false; + + char seed_buf[101]; + if (seed_name == NULL) + seed_name = ""; + strncpy (seed_buf, seed_name, sizeof seed_buf); + seed_buf[(sizeof seed_buf) - 1] = '\0'; + if (seed_buf[0] == '\0') + strncpy (seed_buf, "Tile", sizeof seed_buf); + + set_popup_str_param (0, seed_buf, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "RENAME_CITY", 0x64, (int)seed_buf, 0x44, 0); + int sel = patch_show_popup (popup, __, 0, 0); + is->focused_tile = NULL; + if (sel != 0) + return false; + + if (temp_ui_strs[0][0] == '\0') + return true; + + strncpy (out_name, temp_ui_strs[0], out_len); + out_name[out_len - 1] = '\0'; + return true; +} + +void +handle_named_tile_menu_selection (void) +{ + int tile_x = is->named_tile_menu_tile_x; + int tile_y = is->named_tile_menu_tile_y; + Tile * tile = tile_at (tile_x, tile_y); + if (! tile_can_be_named (tile, tile_x, tile_y)) + return; + + init_tile_highlights (); + + struct named_tile_entry * entry = get_named_tile_entry (tile); + char const * current_name = (entry != NULL) ? entry->name : ""; + char new_name[100]; + is->focused_tile = tile; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + bool got_name = prompt_for_named_tile (current_name, new_name, sizeof new_name); + is->focused_tile = NULL; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + if (! got_name) + return; + + set_named_tile_entry (tile, tile_x, tile_y, new_name); + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +void __fastcall +patch_Main_Screen_Form_handle_right_click_on_tile (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) +{ + if (is->current_config.enable_named_tiles) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile_can_be_named (tile, tile_x, tile_y) && ! Tile_has_city (tile)) { + is->named_tile_menu_active = true; + is->named_tile_menu_tile_x = tile_x; + is->named_tile_menu_tile_y = tile_y; + Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); + is->named_tile_menu_active = false; + return; + } + } + + Main_Screen_Form_handle_right_click_on_tile (this, __, tile_x, tile_y, mouse_x, mouse_y); +} + +void __fastcall +patch_Main_Screen_Form_open_right_click_menu (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) +{ + bool set_active = false; + if (!is->named_tile_menu_active && is->current_config.enable_named_tiles) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile_can_be_named (tile, tile_x, tile_y)) { + is->named_tile_menu_active = true; + is->named_tile_menu_tile_x = tile_x; + is->named_tile_menu_tile_y = tile_y; + set_active = true; + } + } + Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); + if (set_active) + is->named_tile_menu_active = false; +} + +void +draw_map_tile_text (Main_Screen_Form * this, PCX_Image * canvas, char * text, int screen_x, int screen_y, int base_screen_height, int y_offset) +{ + int is_zoomed_out = (p_bic_data->is_zoomed_out != false); + int scale = is_zoomed_out ? 2 : 1; + int screen_width = 128 / scale; + int screen_height = base_screen_height / scale; + int text_width = screen_width - (is_zoomed_out ? 4 : 8); + if (text_width < 12) + text_width = screen_width; + + int text_left = screen_x + (screen_width - text_width) / 2; + int draw_y = screen_y - y_offset; + int text_top = draw_y + screen_height + (is_zoomed_out ? 2 : 4); + + Object_66C3FC * font = get_font (10, FSF_NONE); + if (font != NULL) { + PCX_Image_set_text_effects (canvas, __, 0x80FFFFFF, 0x80000000, 1, 1); + PCX_Image_draw_centered_text (canvas, __, font, text, text_left, text_top - 10, text_width, strlen (text)); + } +} + +void __fastcall +patch_Main_Screen_Form_draw_city_hud (Main_Screen_Form * this, int edx, PCX_Image * canvas) +{ + Main_Screen_Form_draw_city_hud (this, __, canvas); + + bool draw_natural_wonders = is->current_config.enable_natural_wonders && + is->current_config.show_natural_wonder_name_on_map; + bool draw_named_tiles = is->current_config.enable_named_tiles; + if (!draw_natural_wonders && !draw_named_tiles) + return; + + if (canvas == NULL) + canvas = &this->Base_Data.Canvas; + + if ((canvas == NULL) || (canvas->JGL.Image == NULL)) + return; + + if (draw_natural_wonders) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + + int natural_id = inst->natural_wonder_info.natural_wonder_id; + if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) + continue; + + struct natural_wonder_district_config const * nw_cfg = &is->natural_wonder_configs[natural_id]; + if ((nw_cfg == NULL) || (nw_cfg->name == NULL) || (nw_cfg->name[0] == '\0')) + continue; + + Tile * tile = (Tile *)tei.key; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int tile_x, tile_y; + if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + continue; + + int screen_x, screen_y; + Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); + + draw_map_tile_text (this, canvas, (char *)nw_cfg->name, screen_x, screen_y, 88, 88 - 64); + } + } + + if (draw_named_tiles) { + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if ((entry == NULL) || (entry->name[0] == '\0')) + continue; + + Tile * tile = (Tile *)tei.key; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int tile_x, tile_y; + if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) { + tile_x = entry->tile_x; + tile_y = entry->tile_y; + tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + } + + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) + continue; + + int screen_x, screen_y; + Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); + + draw_map_tile_text (this, canvas, entry->name, screen_x, screen_y, 64, 3); + } + } +} + +// Returns whether or not city has an "extra palace", a concept used by the AI multi-city start. Extra palaces are small wonders that reduce +// corruption (e.g. forbidden palace) that are listed under the ai_multi_start_extra_palaces config option. +bool +has_extra_palace (City * city) +{ + for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { + int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) && + (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && + (leaders[city->Body.CivID].Small_Wonders[improv_id] == city->Body.ID)) { + return true; + } + } + return false; +} + +// Removes any extra palaces from this city to other cities owned by the same player (if possible). Does not check that the city belongs to an AI or +// that AI MCS is enabled. +void +remove_extra_palaces (City * city, City * excluded_destination) +{ + Leader * leader = &leaders[city->Body.CivID]; + int extra_palace_lost; + do { + // Search for an extra palace in the city and delete it. Remember its ID so we can put it elsewhere. + extra_palace_lost = -1; + for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { + int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) && + (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && + (leader->Small_Wonders[improv_id] == city->Body.ID)) { + patch_City_add_or_remove_improvement (city, __, improv_id, 0, false); + extra_palace_lost = improv_id; + break; + } + } + + // Replace the lost extra palace like what happens to the real palace + if (extra_palace_lost >= 0) { + int best_rating = -1; + City * best_location = NULL; + FOR_CITIES_OF (coi, leader->ID) { + City * candidate = coi.city; + if ((candidate != city) && + (candidate->Body.ID != leader->CapitalID) && + (candidate != excluded_destination) && + ! has_extra_palace (candidate)) { + + // Rate this candidate as a possible (extra) palace location. The criteria we use to rate it are identical to + // what the base game uses to find a new location for the palace. + int rating = 0; + rating += candidate->Body.Population.Size; + rating += count_units_at (candidate->Body.X, candidate->Body.Y, UF_4, -1, 0, -1); + rating += 2 * City_count_citizens_of_race (candidate, __, leader->RaceID); + FOR_TILES_AROUND (tai, 0x121, candidate->Body.X, candidate->Body.Y) { + if (tai.n == 0) + continue; + City * neighbor = get_city_ptr (tai.tile->CityID); + if ((neighbor != NULL) && (neighbor != city) && (neighbor->Body.CivID == leader->ID)) { + int size = neighbor->Body.Population.Size; + if (size > p_bic_data->General.MaximumSize_City) rating += 3; + else if (size > p_bic_data->General.MaximumSize_Town) rating += 2; + else rating += 1; + } + } + + if (rating > best_rating) { + best_rating = rating; + best_location = candidate; + } + } + } + + if (best_location != NULL) + City_add_or_remove_improvement (best_location, __, extra_palace_lost, 1, false); + } + } while (extra_palace_lost >= 0); +} + +// Give a city any completed wonder districts in work radius, if cities_with_mutual_district_receive_wonders is true. +// This is essentially for cases where the original Wonder-constructing city is lost and a new city is built +// that can work the same wonder district tile. +void +grant_nearby_wonders_to_city (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_wonder_districts || + ! is->current_config.cities_with_mutual_district_receive_wonders || + (city == NULL)) + return; + + bool prev_flag = is->sharing_buildings_by_districts_in_progress; + is->sharing_buildings_by_districts_in_progress = true; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * tile = wai.tile; + + // Make sure Wonder is completed + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + struct wonder_district_info * info = &inst->wonder_info; + if ((info == NULL) || (info->state != WDS_COMPLETED)) continue; + + // Check that city doesn't already have the Wonder + int improv_id = get_wonder_improvement_id_from_index (info->wonder_index); + if (improv_id < 0) continue; + + if (patch_City_has_improvement (city, __, improv_id, false)) continue; + + // Small wonders use Leader.Small_Wonders as their canonical owner record. If the city + // just changed hands and the new owner already has that small wonder elsewhere, do not + // re-grant it from the nearby district or the capture can recreate a duplicate. + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) != 0) { + City * owning_city = get_city_ptr (leaders[city->Body.CivID].Small_Wonders[improv_id]); + if ((owning_city != NULL) && + (owning_city->Body.CivID == city->Body.CivID) && + ! city_radius_contains_tile (owning_city, x, y)) + continue; + } + + // Add the Wonder to the city + patch_City_add_or_remove_improvement (city, __, improv_id, 1, false); + } + + is->sharing_buildings_by_districts_in_progress = prev_flag; +} + +void +on_gain_city (Leader * leader, City * city, enum city_gain_reason reason) +{ + if (reason == CGR_FOUNDED) + is->turn_no_of_last_founding_for_settler_perfume[leader->ID] = *p_current_turn_no; + + // Handle extra palaces for AI multi-city start + if (((*p_human_player_bits & (1<ID)) == 0) && // If leader is an AI AND + (is->current_config.ai_multi_city_start > 1) && // AI multi-city start is enabled AND + (leader->Cities_Count > 1) && // city is not the only one the AI has (i.e. it's not the capital) AND + (reason != CGR_PLACED_FOR_SCENARIO) && (reason != CGR_PLACED_FOR_AI_MULTI_CITY_START)) { // city was not placed before the game started + + // Find an extra palace that this player does not already have + int free_extra_palace = -1; + for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { + int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) && + (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && + (NULL == get_city_ptr (leader->Small_Wonders[improv_id]))) { + free_extra_palace = improv_id; + break; + } + } + + // Place that extra palace here + if (free_extra_palace >= 0) + City_add_or_remove_improvement (city, __, free_extra_palace, 1, false); + } + + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + patch_City_recompute_yields_and_happiness (city); + patch_City_recompute_culture_income (city); + } + + if (is->current_config.enable_districts) { + + // Remove any district previously on the tile, if city just founded + if (reason == CGR_FOUNDED) { + Tile * city_tile = tile_at (city->Body.X, city->Body.Y); + if ((city_tile != NULL) && (city_tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (city_tile); + if (inst != NULL) + handle_district_removed (city_tile, inst->district_id, city->Body.X, city->Body.Y, false); + } + } + + bool receive_buildings = is->current_config.cities_with_mutual_district_receive_buildings; + bool receive_wonders = is->current_config.cities_with_mutual_district_receive_wonders; + + // Grant buildings and wonders from nearby completed districts owned by other cities of same civ, if enabled + if (receive_buildings) { + grant_existing_district_buildings_to_city (city); + } + + // Grant wonders nearby in same territory, regardless of city (i.e., orphaned wonders from destroyed cities), if enabled + if (receive_wonders) { + grant_nearby_wonders_to_city (city); + } + + if (is->current_config.enable_distribution_hub_districts) { + refresh_distribution_hubs_for_city (city); + } + } +} + +void +on_lose_city (Leader * leader, City * city, enum city_loss_reason reason) +{ + // If leader is an AI and AI MCS is enabled, remove any extra palaces the city has + if (((*p_human_player_bits & (1<ID)) == 0) && + (is->current_config.ai_multi_city_start > 1)) + remove_extra_palaces (city, NULL); + + if (is->current_config.enable_districts) { + if (is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; + + forget_pending_building_order (city); + for (int district_id = 0; district_id < is->district_count; district_id++) + clear_city_district_request (city, district_id); + + if (is->current_config.enable_wonder_districts) + release_wonder_district_reservation (city); + } else if (is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; +} + +// Returns -1 if the location is unusable, 0-9 if it's usable but doesn't satisfy all criteria, and 10 if it couldn't be better +int +eval_starting_location (Map * map, int const * alt_starting_locs, int alt_starting_loc_count, int tile_x, int tile_y, int civ_id) +{ + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != p_null_tile) && + (patch_Map_check_city_location (map, __, tile_x, tile_y, civ_id, true) == CLV_OK) && + (tile->vtable->m15_Check_Goody_Hut (tile, __, 0) == 0) && + (tile->vtable->m40_get_TileUnit_ID (tile) == -1)) { + int tr = 0; + + // Avoid this location if it's too close to another starting location. If it's much too close, it's ruled out entirely. + int closest_dist = INT_MAX; + for (int n = 1; n <= map->Civ_Count; n++) + if (map->Starting_Locations[n] >= 0) { + int other_x, other_y; + tile_index_to_coords (map, map->Starting_Locations[n], &other_x, &other_y); + int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); + if (dist < closest_dist) + closest_dist = dist; + } + for (int n = 0; n < alt_starting_loc_count; n++) + if (alt_starting_locs[n] >= 0) { + int other_x, other_y; + tile_index_to_coords (map, alt_starting_locs[n], &other_x, &other_y); + int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); + if (dist < closest_dist) + closest_dist = dist; + } + if (closest_dist < map->Civ_Distance/3) + return -1; + else if (closest_dist >= 2*map->Civ_Distance/3) + tr += 1; + + // Avoid tiny islands + // tr += map->vtable->m33_Get_Continent (map, __, tile->ContinentID)->Body.TileCount >= 20; + + // Avoid garbage terrain, e.g. all desert or tundra + int break_even_food_tiles = 0; + FOR_TILES_AROUND (tai, 21, tile_x, tile_y) { + if (tai.n == 0) + continue; // Skip tile that would be covered by the city + int tile_food = patch_Map_calc_food_yield_at (map, __, tai.tile_x, tai.tile_y, tai.tile->vtable->m50_Get_Square_BaseType (tai.tile), civ_id, 0, NULL); + int food_required = p_bic_data->General.FoodPerCitizen + (tai.tile->vtable->m35_Check_Is_Water (tai.tile) ? 1 : 0); + break_even_food_tiles += tile_food >= food_required; + } + tr += break_even_food_tiles >= 2; + + // Avoid wasting a food bonus + tr += (tile->ResourceType < 0) || (tile->ResourceType >= p_bic_data->ResourceTypeCount) || + (p_bic_data->ResourceTypes[tile->ResourceType].Food == 0); + + int max_score = 3; + return (10*tr)/max_score; + } else + return -1; +} + +City * +create_starter_city (Map * map, int civ_id, int tile_index) +{ + int x, y; + tile_index_to_coords (map, tile_index, &x, &y); + City * tr = Leader_create_city (&leaders[civ_id], __, x, y, leaders[civ_id].RaceID, -1, NULL, true); + if (tr != NULL) + on_gain_city (&leaders[civ_id], tr, CGR_PLACED_FOR_AI_MULTI_CITY_START); + return tr; +} + +void +set_up_ai_multi_city_start (Map * map, int city_count) +{ + // Set of bits determining which players are eligible for the two-city start + int eligibility_bits = 0, + count_eligible_civs = 0; + for (int n = 1; n < 32; n++) + if ((*p_player_bits & 1<Starting_Locations[n]) != p_null_tile)) { // has a valid starting location + eligibility_bits |= 1 << n; + count_eligible_civs++; + } + + if ((city_count < 1) || (count_eligible_civs == 0)) // if we have nothing to do + return; + + char load_text[50]; + snprintf (load_text, sizeof load_text, "%s...", is->c3x_labels[CL_CREATING_CITIES]); + load_text[(sizeof load_text) - 1] = '\0'; + Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); + + // Generate alternate sets of starting locations. We need one set for each extra city we're going to create per player. Each set only needs to + // include starting locations for eligible players, all others will be left as -1. + int alt_starting_loc_count = 32 * (city_count - 1); + int * alt_starting_locs = malloc (alt_starting_loc_count * sizeof *alt_starting_locs); { + for (int n = 0; n < alt_starting_loc_count; n++) + alt_starting_locs[n] = -1; + + for (int i_loc = 0; i_loc < alt_starting_loc_count; i_loc++) { + int civ_id = i_loc % 32; + if ((civ_id != 0) && (eligibility_bits & 1<current_config.max_tries_to_place_fp_city; try++) { + int i_loc = rand_int (p_rand_object, __, map->TileCount); + int x_loc, y_loc; + tile_index_to_coords (map, i_loc, &x_loc, &y_loc); + if ((x_loc >= 0) && (y_loc >= 0)) { + int val = eval_starting_location (map, alt_starting_locs, alt_starting_loc_count, x_loc, y_loc, civ_id); + if (val >= 10) { + best_loc_index = i_loc; + break; + } else if (val > best_loc_val) { + best_loc_val = val; + best_loc_index = i_loc; + } + } + } + + if (best_loc_index >= 0) + alt_starting_locs[i_loc] = best_loc_index; + } + } + } + + int count_cities_created = 0; + int count_eligible_civs_handled = 0; + for (int civ_id = 1; civ_id < 32; civ_id++) + if (eligibility_bits & 1<Starting_Locations[civ_id]; + + // Create the first starting city for the AI. This one is its capital and is located at its actual starting + // location. Afterward, delete its starting settler so it's as if the settler founded the city. + { + Unit * starting_settler = NULL; + FOR_UNITS_ON (tai, tile_at_index (map, sloc)) { + if (p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].AI_Strategy & UTAI_Settle) { + starting_settler = tai.unit; + break; + } + } + + create_starter_city (map, civ_id, sloc); + count_cities_created++; + + if (starting_settler != NULL) + patch_Unit_despawn (starting_settler, __, 0, 1, 0, 0, 0, 0, 0); + + } + + // Memoize all of the AI's starting units + clear_memo (); + FOR_UNITS_ON (tai, tile_at_index (map, sloc)) + memoize ((int)tai.unit); + + int extra_city_count = 0; + for (int i_city = 1; i_city < city_count; i_city++) { + int loc = alt_starting_locs[(i_city-1)*32 + civ_id]; + City * city; + if ((loc >= 0) && + (NULL != (city = create_starter_city (map, civ_id, loc)))) { + count_cities_created++; + extra_city_count++; + + // Spawn palace substitute in new city + if (extra_city_count-1 < is->current_config.count_ai_multi_start_extra_palaces) + patch_City_add_or_remove_improvement (city, __, is->current_config.ai_multi_start_extra_palaces[extra_city_count - 1], 1, true); + + // Move starting units over to the new city. Do this by moving every Nth unit where N is the number of extra + // cities we've founded so far plus one. ("Extra" cities are the ones created after the capital.) E.g., if + // this is the 1st city after the capital, move every 2nd unit to it. If it's the 2nd, move every 3rd, etc. + for (int n = 0; n < is->memo_len; n++) + if (n % (extra_city_count+1) == extra_city_count) + patch_Unit_move ((Unit *)is->memo[n], __, city->Body.X, city->Body.Y); + + } + } + + // Update progress report + count_eligible_civs_handled++; + int progress = 100 * count_eligible_civs_handled / count_eligible_civs; + snprintf (load_text, sizeof load_text, "%s %d%%", is->c3x_labels[CL_CREATING_CITIES], progress); + load_text[(sizeof load_text) - 1] = '\0'; + Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); + + } + + free (alt_starting_locs); + + // Sanity check + int any_adjacent_cities = 0; { + if (p_cities->Cities != NULL) + for (int city_index = 0; (city_index <= p_cities->LastIndex) && ! any_adjacent_cities; city_index++) { + City * city = get_city_ptr (city_index); + if (city != NULL) + FOR_TILES_AROUND (tai, 9, city->Body.X, city->Body.Y) + if ((tai.n > 0) && (NULL != get_city_ptr (tai.tile->vtable->m45_Get_City_ID (tai.tile)))) { + any_adjacent_cities = 1; + break; + } + } + } + int any_missing_fp_cities = (count_cities_created < city_count * count_eligible_civs); + if (any_adjacent_cities || any_missing_fp_cities) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[100]; + snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_FAILED_SANITY_CHECK]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + if (any_adjacent_cities) { + snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_ADJACENT_CITIES]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + if (any_missing_fp_cities) { + snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_MISSING_CITIES]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + patch_show_popup (popup, __, 0, 0); + } +} + +void __fastcall +patch_Map_process_after_placing (Map * this, int edx, bool param_1) +{ + if ((is->current_config.ai_multi_city_start > 0) && (*p_current_turn_no == 0)) + set_up_ai_multi_city_start (this, is->current_config.ai_multi_city_start); + + Map_process_after_placing (this, __, param_1); +} + +void __fastcall +patch_Map_impl_generate (Map * this, int edx, int seed, bool is_multiplayer_game, int num_seafaring_civs) +{ + Map_impl_generate (this, __, seed, is_multiplayer_game, num_seafaring_civs); + + if (is->current_config.enable_natural_wonders) + place_natural_wonders_on_map (); +} + +int __fastcall +patch_City_get_net_commerce (City * this, int edx, int kind, bool include_science_age) +{ + int base = City_get_net_commerce (this, __, kind, include_science_age); + + if ((kind == 1) && // beakers, as opposed to 2 which is gold + (is->current_config.ai_research_multiplier != 100) && + ((*p_human_player_bits & 1<Body.CivID) == 0)) + return (base * is->current_config.ai_research_multiplier + 50) / 100; + else + return base; +} + +// Cuts research spending while total expenditures > treasury. Returns whether spending has been cut. +bool +cut_unaffordable_research_spending (Leader * leader, bool skip_popup) +{ + // The rate cap limits AI players' spending on the gold slider (in Leader::ai_adjust_sliders) however it does not apply to human players when + // adjusting sliders manually on the domestic advisor screen. + int gold_rate_cap = ((*p_human_player_bits & 1<ID) != 0) ? 10 : p_bic_data->Governments[leader->GovernmentType].RateCap; + + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + bool reduced_spending = false; + while (leader->science_slider > 0 && + leader->gold_slider < gold_rate_cap && + treasury + Leader_compute_income (leader) < 0) { + leader->science_slider -= 1; + leader->gold_slider += 1; + Leader_recompute_economy (leader); + reduced_spending = true; + } + if (reduced_spending && ! skip_popup && leader->ID == p_main_screen_form->Player_CivID) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_CUT_RESEARCH_SPENDING", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + return reduced_spending; +} + +void __fastcall +adjust_sliders_preproduction (Leader * this) +{ + if ((*p_human_player_bits & 1<ID) == 0) { + // Replicate the behavior of the original code for AI players. (apply_machine_code_edits overwrites an equivalent branch & call in the + // original code with a call to this method.) + this->vtable->ai_adjust_sliders (this); + + // If aggressively penalize bankruptcy is on, cut the AI's research spending if it can't afford it. This may be redundant as + // ai_adjust_sliders will already cut AI spending but maybe not all the way to zero. Do this only every third turn so the AI is not + // completely prevented from researching. + if (is->current_config.aggressively_penalize_bankruptcy && (*p_current_turn_no + this->ID) % 3 == 0) + cut_unaffordable_research_spending (this, true); + + // If human player would go bankrupt, try reducing their research spending to avoid that + } else if (is->current_config.cut_research_spending_to_avoid_bankruptcy) + cut_unaffordable_research_spending (this, false); +} + +int __fastcall +patch_City_get_improvement_maintenance (City * this, int edx, int improv_id) +{ + // Check if this improvment is provided for free by another player via shared wonder effects + int civ_id = this->Body.CivID; + bool free_from_sharing = false; + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << civ_id) & *p_human_player_bits)) { // is this city owned by a human player + + // Check if any other human player in the game has this improv in their auto improvs table, including for this city's continent + bool has_free_improv = false; + Tile * city_tile = tile_at (this->Body.X, this->Body.Y); + int continent_id = city_tile->vtable->m46_Get_ContinentID (city_tile); + int cont_coded_key = (continent_id + 1) * p_bic_data->ImprovementsCount + improv_id;; + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != civ_id)) + if (Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, improv_id , NULL) || + Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, cont_coded_key, NULL)) { + free_from_sharing = true; + break; + } + player_bits >>= 1; + n_player++; + } + } + + if (! free_from_sharing) + return City_get_improvement_maintenance (this, __, improv_id); + else + return 0; +} + +int __fastcall +patch_Leader_count_maintenance_free_units (Leader * this) +{ + if ((is->current_config.extra_unit_maintenance_per_shields <= 0) && (this->ID != 0)) + return Leader_count_maintenance_free_units (this); + else { + int tr = 0; + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if ((unit != NULL) && (unit->Body.CivID == this->ID)) { + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + + // If this is a free unit + if ((unit->Body.RaceID != this->RaceID) || (type->requires_support == 0)) + tr++; + + // If this unit belongs to the barbs and has a tribe ID set (indicating it was spawned in a barb camp) then count it + // as a free unit in order not to bankrupt the barb player if the barb player controls any cities. A tribe ID of 75 is + // the generic ID that's assigned to barb units when they're spawned with no specific tribe ID. + else if ((unit->Body.CivID == 0) && (unit->Body.barb_tribe_id >= 0) && (unit->Body.barb_tribe_id < 75)) + tr++; + + // Otherwise, if we're configured to apply extra maintenance based on shield cost, reduce the free unit count by + // however many times this unit's cost is above the threshold for extra maintenace. It's alright if the resulting free + // unit count is negative since all callers of this function subtract its return value from the total unit count to + // obtain the count of units that must be paid for. + else if (is->current_config.extra_unit_maintenance_per_shields > 0) + tr -= type->Cost / is->current_config.extra_unit_maintenance_per_shields; + } + } + return tr; + } +} + +int __fastcall +patch_Leader_sum_unit_maintenance (Leader * this, int edx, int government_id) +{ + if (is->current_config.extra_unit_maintenance_per_shields <= 0) + return Leader_sum_unit_maintenance (this, __, government_id); + else if (this->Cities_Count > 0) { + int maint_free_count = patch_Leader_count_maintenance_free_units (this); + int cost_per_unit, base_free_count; + get_unit_support_info (this->ID, government_id, &cost_per_unit, &base_free_count); + int ai_free_count; { + if (*p_human_player_bits & 1<ID) + ai_free_count = 0; + else { + Difficulty_Level * difficulty = &p_bic_data->DifficultyLevels[*p_game_difficulty]; + ai_free_count = difficulty->Bonus_For_Each_City * this->Cities_Count + difficulty->Additional_Free_Support; + } + } + return not_below (0, (this->Unit_Count - base_free_count - ai_free_count - maint_free_count) * cost_per_unit); + } else + return 0; +} + +int +sum_improvements_maintenance_to_pay (Leader * leader, int govt_id) +{ + if (is->current_config.aggressively_penalize_bankruptcy) + // We're going to replace the logic that charges maintenance, and the replacement will charge both unit & building maintenance b/c + // they're intertwined under the new rules. Return zero here so the base game code doesn't charge any building maintenance on its own. + return 0; + else + return Leader_sum_improvements_maintenance (leader, __, govt_id); +} + +// The sum_improvements_maintenance function is called in two places as part of the randomization of whether improv or unit maintenance gets paid +// first. Redirect both of these calls to one function of our own. +int __fastcall patch_Leader_sum_improv_maintenance_to_pay_1 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } +int __fastcall patch_Leader_sum_improv_maintenance_to_pay_2 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } + +int +compare_buildings_to_sell (void const * a, void const * b) +{ + int maint_a = (*(int const *)a >> 26) & 31, + maint_b = (*(int const *)b >> 26) & 31; + return maint_b - maint_a; +} + +// Returns the final improv cost after buildings were sold +int +sell_unaffordable_buildings (Leader * leader, int improv_cost, int unit_cost) +{ + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + + clear_memo (); + + // Memoize all buildings this player owns that we might potentially sell. B/c the memo can only contain ints, we must pack the maintenance + // cost, improv ID, and city ID all into one int. The city ID is stored in the lowest 13 bits, then the improv ID in the next 13, and finally + // the maintenance amount in the 5 above those. + FOR_CITIES_OF (coi, leader->ID) + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * improv = &p_bic_data->Improvements[n]; + + int unsellable_flags = + ITF_Center_of_Empire | + ITF_50_Luxury_Output | + ITF_50_Tax_Output | + ITF_Reduces_Corruption | + ITF_Increases_Luxury_Trade | + ITF_Allows_City_Level_2 | + ITF_Allows_City_Level_3 | + ITF_Capitalization | + ITF_Allows_Water_Trade | + ITF_Allows_Air_Trade | + ITF_Increases_Shields_In_Water | + ITF_Increases_Food_In_Water | + ITF_Increases_Trade_In_Water; + + // Only sell improvements that aren't contributing gold, even indirectly through e.g. happiness or boosting shield production + // for Wealth + bool sellable = + ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) == 0) && + ((improv->ImprovementFlags & unsellable_flags) == 0) && + (improv->Happy_Faces_All <= 0) && (improv->Happy_Faces <= 0) && + (improv->Production <= 0); + + if (sellable && patch_City_has_improvement (coi.city, __, n, 0)) { + int maint = patch_City_get_improvement_maintenance (coi.city, __, n); + if (maint > 0) + memoize ((not_above (31, maint) << 26) | (n << 13) | coi.city_id); + } + } + + // Sort the list of buildings so the highest maintenance ones come first + qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_buildings_to_sell); + + // Sell buildings until we can cover maintenance costs or until we run out of ones to sell + int count_sold = 0; + while ((improv_cost + unit_cost > treasury) && (count_sold < is->memo_len)) { + int improv_id = ((1<<13) - 1) & (is->memo[count_sold] >> 13), + city_id = ((1<<13) - 1) & is->memo[count_sold]; + City * city = get_city_ptr (city_id); + improv_cost -= patch_City_get_improvement_maintenance (city, __, improv_id); + City_sell_improvement (city, __, improv_id, false); + treasury = leader->Gold_Encoded + leader->Gold_Decrement; + count_sold++; + } + + // Show popup informing the player that their buildings were force sold + if ((leader->ID == p_main_screen_form->Player_CivID) && ! is_online_game ()) { + PopupForm * popup = get_popup_form (); + if (count_sold == 1) { + int improv_id = ((1<<13) - 1) & (is->memo[0] >> 13), + city_id = ((1<<13) - 1) & is->memo[0]; + set_popup_str_param (0, get_city_ptr (city_id)->Body.CityName , -1, -1); + set_popup_str_param (1, p_bic_data->Improvements[improv_id].Name.S, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_SINGLE_IMPROV", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } else if (count_sold > 1) { + set_popup_int_param (0, count_sold); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_MULTIPLE_IMPROVS", -1, 0, 0, 0); + + // Add list of sold improvements to popup + for (int n = 0; n < count_sold; n++) { + int improv_id = ((1<<13) - 1) & (is->memo[n] >> 13), + city_id = ((1<<13) - 1) & is->memo[n]; + char s[200]; + snprintf (s, sizeof s, "^ %s in %s", + p_bic_data->Improvements[improv_id].Name.S, + get_city_ptr (city_id)->Body.CityName); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + + patch_show_popup (popup, __, 0, 0); + } + } + + return improv_cost; +} + +// Returns the final unit cost after disbanding +int +disband_unaffordable_units (Leader * leader, int improv_cost, int unit_cost, int cost_per_unit) +{ + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + int count_disbanded = 0; + Unit * to_disband; + char first_disbanded_name[32]; + while ((improv_cost + unit_cost > treasury) && + (unit_cost > 0) && + (NULL != (to_disband = leader->vtable->find_unsupported_unit (leader)))) { + if (count_disbanded == 0) { + char const * name_src = (to_disband->Body.Custom_Name.S[0] == '\0') + ? p_bic_data->UnitTypes[to_disband->Body.UnitTypeID].Name + : to_disband->Body.Custom_Name.S; + strncpy (first_disbanded_name, name_src, sizeof first_disbanded_name); + first_disbanded_name[(sizeof first_disbanded_name) - 1] = '\0'; + } + Unit_disband (to_disband); + count_disbanded++; + unit_cost -= cost_per_unit; + } + + // Show popup informing the player that their units were disbanded + if (leader->ID == p_main_screen_form->Player_CivID) { + PopupForm * popup = get_popup_form (); + if (count_disbanded == 1) { + set_popup_str_param (0, first_disbanded_name, -1, -1); + int online_flag = is_online_game () ? 0x4000 : 0; + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_SINGLE_UNIT", -1, 0, online_flag, 0); + patch_show_popup (popup, __, 0, 0); + } else if ((count_disbanded > 1) && ! is_online_game ()) { + set_popup_int_param (0, count_disbanded); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_MULTIPLE_UNITS", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + } + + return unit_cost; +} + +int +compare_cities_by_production (void const * vp_id_a, void const * vp_id_b) +{ + City * a = get_city_ptr (*(int const *)vp_id_a), + * b = get_city_ptr (*(int const *)vp_id_b); + return a->Body.ProductionIncome - b->Body.ProductionIncome; +} + +void +charge_maintenance_with_aggressive_penalties (Leader * leader) +{ + int cost_per_unit; + get_unit_support_info (leader->ID, leader->GovernmentType, &cost_per_unit, NULL); + + int improv_cost = Leader_sum_improvements_maintenance (leader, __, leader->GovernmentType); + + int unit_cost = 0; { + if (leader->Cities_Count > 0) // Players with no cities don't pay unit maintenance, per the original game rules + if (cost_per_unit > 0) { + int count_free_units = Leader_get_free_unit_count (leader, __, leader->GovernmentType) + patch_Leader_count_maintenance_free_units (leader); + unit_cost += not_below (0, (leader->Unit_Count - count_free_units) * cost_per_unit); + } + } + + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + if (improv_cost + unit_cost > treasury) { + + // For AIs, alternate between selling buildings and disbanding units when maintenance can't be paid + if (((1<ID & *p_human_player_bits) != 0) || ((leader->ID + *p_current_turn_no) % 2 == 0)) { + improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); + unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); + } else { + unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); + improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); + } + + treasury = leader->Gold_Encoded + leader->Gold_Decrement; // Update b/c selling buildings recovers some gold + + // If the player still can't afford maintenance, even after all that, start switching their cities to Wealth + int wealth_income = 0; + if (improv_cost + unit_cost > treasury + wealth_income) { + // Memoize all cities not already building wealth and sort by production (lowest first) + clear_memo (); + FOR_CITIES_OF (coi, leader->ID) + if ((coi.city->Body.Status & CSF_Capitalization) == 0) + memoize (coi.city_id); + qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_cities_by_production); + + int wealth_improv_id = -1; { + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { + wealth_improv_id = n; + break; + } + } + + if (wealth_improv_id >= 0) { + int n = 0, + switched_any = 0; + + while ((n < is->memo_len) && (improv_cost + unit_cost > treasury + wealth_income)) { + City * city = get_city_ptr (is->memo[n]); + City_set_production (city, __, COT_Improvement, wealth_improv_id, false); + switched_any = 1; + wealth_income += City_get_income_from_wealth_build (city); + n++; + } + + if (switched_any && (leader->ID == p_main_screen_form->Player_CivID)) { + PopupForm * popup = get_popup_form (); + Improvement * wealth = &p_bic_data->Improvements[wealth_improv_id]; + set_popup_str_param (0, wealth->Name.S, -1, -1); + set_popup_str_param (1, wealth->CivilopediaEntry.S, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_BUILD_WEALTH", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + } + } + } + + Leader_set_treasury (leader, __, treasury - improv_cost - unit_cost); +} + +bool __fastcall +patch_Unit_has_king_ability_for_find_unsupported (Unit * this, int edx, enum UnitTypeAbilities king_ability) +{ + // If we're set to aggressively penalize bankruptcy and this unit doesn't require support, return that it is a king so it doesn't get + // disbanded. + if (is->current_config.aggressively_penalize_bankruptcy && ! p_bic_data->UnitTypes[this->Body.UnitTypeID].requires_support) + return true; + + else + return Unit_has_ability (this, __, king_ability); +} + +void __fastcall +patch_Leader_pay_unit_maintenance (Leader * this) +{ + if (! is->current_config.aggressively_penalize_bankruptcy) + Leader_pay_unit_maintenance (this); + else + charge_maintenance_with_aggressive_penalties (this); +} + +void __fastcall +patch_Main_Screen_Form_show_wltk_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) +{ + patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); +} + +void __fastcall +patch_Main_Screen_Form_show_wltk_ended_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) +{ + patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); +} + +char __fastcall +patch_Tile_has_city_for_agri_penalty_exception (Tile * this) +{ + return is->current_config.no_penalty_exception_for_agri_fresh_water_city_tiles ? 0 : Tile_has_city (this); +} + +int +show_razing_popup (void * popup_object, int popup_param_1, int popup_param_2, int razing_option) +{ + int response = patch_show_popup (popup_object, __, popup_param_1, popup_param_2); + if (is->current_config.prevent_razing_by_players && (response == razing_option)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_RAZE", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + return 0; + } + return response; +} + +int __fastcall patch_show_popup_option_1_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 1); } +int __fastcall patch_show_popup_option_2_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 2); } + +int __fastcall +patch_Context_Menu_add_abandon_city (Context_Menu * this, int edx, int item_id, char * text, bool checkbox, Sprite * image) +{ + if (is->current_config.prevent_razing_by_players) + return 0; // Return value is ignored by the caller + else + return Context_Menu_add_item (this, __, item_id, text, checkbox, image); +} + +char * +check_pedia_upgrades_to_ptr (TextBuffer * this, char * str) +{ + Civilopedia_Form * pedia = p_civilopedia_form; + UnitType * unit_type = NULL; + if (is->current_config.indicate_non_upgradability_in_pedia && + (pedia->Current_Article_ID >= 0) && (pedia->Current_Article_ID <= pedia->Max_Article_ID) && + (NULL != (unit_type = pedia->Articles[pedia->Current_Article_ID]->unit_type)) && + ((unit_type->Special_Actions & UCV_Upgrade_Unit) == 0)) + return is->c3x_labels[CL_OBSOLETED_BY]; + else + return TextBuffer_check_ptr (this, __, str); +} + +char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_1 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } +char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_2 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } + +bool __fastcall +patch_Unit_select_stealth_attack_target (Unit * this, int edx, int target_civ_id, int x, int y, bool allow_popup, Unit ** out_selected_target) +{ + is->added_any_stealth_target = 0; + return Unit_select_stealth_attack_target (this, __, target_civ_id, x, y, allow_popup, out_selected_target); +} + +bool __fastcall +patch_Unit_can_stealth_attack (Unit * this, int edx, Unit * target) +{ + bool tr = Unit_can_stealth_attack (this, __, target); + + // If we're selecting a target for stealth attack via bombardment, we must filter out candidates we can't damage that way + if (tr && is->selecting_stealth_target_for_bombard && + ! can_damage_bombarding (&p_bic_data->UnitTypes[this->Body.UnitTypeID], target, tile_at (target->Body.X, target->Body.Y))) + return false; + + else if (tr && is->current_config.exclude_invisible_units_from_stealth_attack && ! patch_Unit_is_visible_to_civ (target, __, this->Body.CivID, 1)) + return false; + + else if (tr && is->current_config.exclude_passengers_from_stealth_attack && get_unit_ptr (target->Body.Container_Unit) != NULL) + return false; + + else + return tr; +} + +int __fastcall +patch_Tile_check_water_for_stealth_attack (Tile * this) +{ + // When stealth attack bombard is enabled, remove a special rule inside can_stealth_attack that prevents land units from stealth attacking + // onto sea tiles. This allows land artillery to stealth attack naval units. + return is->current_config.enable_stealth_attack_via_bombardment ? 0 : this->vtable->m35_Check_Is_Water (this); +} + +int __fastcall +patch_PopupSelection_add_stealth_attack_target (PopupSelection * this, int edx, char * text, int value) +{ + if (is->current_config.include_stealth_attack_cancel_option && (! is->added_any_stealth_target)) { + PopupSelection_add_item (this, __, is->c3x_labels[CL_NO_STEALTH_ATTACK], -1); + is->added_any_stealth_target = 1; + } + + Unit * unit; + if (is->current_config.show_hp_of_stealth_attack_options && + ((unit = get_unit_ptr (value)) != NULL)) { + char s[500]; + int max_hp = Unit_get_max_hp (unit); + snprintf (s, sizeof s, "(%d/%d) %s", max_hp - unit->Body.Damage, max_hp, text); + s[(sizeof s) - 1] = '\0'; + return PopupSelection_add_item (this, __, s, value); + } else + return PopupSelection_add_item (this, __, text, value); +} + +void __fastcall +patch_Unit_perform_air_recon (Unit * this, int edx, int x, int y) +{ + int moves_plus_one = this->Body.Moves + p_bic_data->General.RoadsMovementRate; + + bool was_intercepted = false; + if (is->current_config.intercept_recon_missions) { + // Temporarily add vision on the target tile so the game plays the animation if the unit is show down by ground AA + Tile_Body * tile = &tile_at (x, y)->Body; + int saved_vis = tile->Visibility; + tile->Visibility |= 1 << this->Body.CivID; + was_intercepted = Unit_try_flying_over_tile (this, __, x, y); + tile->Visibility = saved_vis; + } + + if (! was_intercepted) { + Unit_perform_air_recon (this, __, x, y); + if (is->current_config.charge_one_move_for_recon_and_interception) + this->Body.Moves = moves_plus_one; + } +} + +int __fastcall +patch_Unit_get_interceptor_max_moves (Unit * this) +{ + // Stop fighters from intercepting multiple times per turn without blitz + if (is->current_config.charge_one_move_for_recon_and_interception && + (this->Body.Status & USF_USED_ATTACK != 0) && ! UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Blitz)) + return 0; + + else + return patch_Unit_get_max_move_points (this); +} + +int __fastcall +patch_Unit_get_moves_after_interception (Unit * this) +{ + if (is->current_config.charge_one_move_for_recon_and_interception) { + this->Body.Status |= USF_USED_ATTACK; // Set status bit indicating that the interceptor has attacked this turn + return this->Body.Moves + p_bic_data->General.RoadsMovementRate; + } else + return patch_Unit_get_max_move_points (this); +} + +void __fastcall +patch_Unit_set_state_after_interception (Unit * this, int edx, int new_state) +{ + if (! is->current_config.charge_one_move_for_recon_and_interception) + Unit_set_state (this, __, new_state); + + // If fighters are supposed to be able to intercept multiple times per turn, then we can't knock them out of the interception state as soon as + // they intercept something like in the base game. Instead, record this interception event so that we can clear their state at the start of + // their next turn. + else { + struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->Body.CivID]; + reserve (sizeof irl->items[0], (void **)&irl->items, &irl->capacity, irl->count); + irl->items[irl->count++] = (struct interception) { + .unit_id = this->Body.ID, + .x = this->Body.X, + .y = this->Body.Y + }; + } +} + +// Goes through every entry in a table with unit IDs as keys and filters out any that belong to the given owner (or are invalid). +void +remove_unit_id_entries_owned_by (struct table * t, int owner_id) +{ + if (t->len > 0) { + clear_memo (); + FOR_TABLE_ENTRIES (tei, t) { + Unit * unit = get_unit_ptr (tei.key); + if ((unit == NULL) || (unit->Body.CivID == owner_id)) + memoize (tei.key); + } + for (int n = 0; n < is->memo_len; n++) + itable_remove (t, is->memo[n]); + } +} + +void __fastcall +patch_Leader_begin_turn (Leader * this) +{ + if (is->aerodrome_airlift_usage.len > 0) { + int civ_bit = 1 << this->ID; + clear_memo (); + FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { + int mask = tei.value; + if (mask & civ_bit) { + int new_mask = mask & ~civ_bit; + memoize (tei.key); + memoize (new_mask); + } + } + for (int n = 0; n < is->memo_len; n += 2) { + int key = is->memo[n]; + int new_mask = is->memo[n + 1]; + if (new_mask == 0) + itable_remove (&is->aerodrome_airlift_usage, key); + else + itable_insert (&is->aerodrome_airlift_usage, key, new_mask); + } + clear_memo (); + } + + // Eject trespassers + is->do_not_bounce_invisible_units = true; + if (is->current_config.disallow_trespassing && (*p_current_turn_no > 0)) + for (int n = 1; n < 32; n++) + if ((*p_player_bits & (1 << n)) && + (n != this->ID) && + (! this->At_War[n]) && + ((this->Relation_Treaties[n] & 2) == 0)) // Check right of passage + Leader_bounce_trespassing_units (&leaders[n], __, this->ID); + is->do_not_bounce_invisible_units = false; + + if (is->current_config.introduce_all_human_players_at_start_of_hotseat_game && + (*p_current_turn_no == 0) && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((*p_human_player_bits & (1 << this->ID)) != 0)) + for (int n = 0; n < 32; n++) + if (*p_human_player_bits & (1 << n)) + Leader_make_contact (this, __, n, false); + + Leader_begin_turn (this); +} + +void __fastcall +patch_Leader_begin_unit_turns (Leader * this) +{ + // Reset the states of all fighters that performed an interception on the previous turn. + struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->ID]; + for (int n = 0; n < irl->count; n++) { + struct interception * record = &irl->items[n]; + Unit * interceptor = get_unit_ptr (record->unit_id); + if ((interceptor != NULL) && + (interceptor->Body.CivID == this->ID) && + (interceptor->Body.X == record->x) && + (interceptor->Body.Y == record->y) && + (interceptor->Body.UnitState == UnitState_Intercept)) + Unit_set_state (interceptor, __, 0); + } + irl->count = 0; + + // Reset extra defensive bombard and airdrop counters + remove_unit_id_entries_owned_by (&is->extra_defensive_bombards, this->ID); + remove_unit_id_entries_owned_by (&is->airdrops_this_turn , this->ID); + remove_unit_id_entries_owned_by (&is->unit_transport_ties , this->ID); + + clear_memo (); + if (is->current_config.delete_off_map_ai_units && + ((*p_human_player_bits & (1 << this->ID)) == 0) && + (p_units->Units != NULL)) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit_Body * body = p_units->Units[n].Unit; + if ((body != NULL) && + ((int)body != offsetof (Unit, Body)) && + (body->CivID == this->ID) && + ! Map_in_range (&p_bic_data->Map, __, body->X, body->Y)) + memoize (body->ID); + } + for (int n = 0; n < is->memo_len; n++) + patch_Unit_despawn (get_unit_ptr (is->memo[n]), __, 0, 1, 0, 0, 0, 0, 0); + + Leader_begin_unit_turns (this); +} + +Unit * __fastcall +patch_Fighter_find_actual_bombard_defender (Fighter * this, int edx, Unit * bombarder, int tile_x, int tile_y, int bombarder_civ_id, bool land_lethal, bool sea_lethal) +{ + if (is->bombard_stealth_target == NULL) + return Fighter_find_defender_against_bombardment (this, __, bombarder, tile_x, tile_y, bombarder_civ_id, land_lethal, sea_lethal); + else + return is->bombard_stealth_target; +} + +Unit * +select_stealth_attack_bombard_target (Unit * unit, int tile_x, int tile_y) +{ + bool land_lethal = Unit_has_ability (unit, __, UTA_Lethal_Land_Bombardment), + sea_lethal = Unit_has_ability (unit, __, UTA_Lethal_Sea_Bombardment); + Unit * defender = Fighter_find_defender_against_bombardment (&p_bic_data->fighter, __, unit, tile_x, tile_y, unit->Body.CivID, land_lethal, sea_lethal); + if (defender != NULL) { + Unit * target; + is->selecting_stealth_target_for_bombard = 1; + bool got_one = patch_Unit_select_stealth_attack_target (unit, __, defender->Body.CivID, tile_x, tile_y, true, &target); + is->selecting_stealth_target_for_bombard = 0; + return got_one ? target : NULL; + } else + return NULL; +} + +bool __fastcall +patch_Unit_try_flying_for_precision_strike (Unit * this, int edx, int x, int y) +{ + bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); + if (is->current_config.polish_precision_striking && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) && + ! is_cruise_missile) + // This method returns -1 when some kind of error occurs. In that case, return true implying the unit was shot down so the caller + // doesn't do anything more. Otherwise, return false so it goes ahead and applies damage. + return Unit_play_bombard_fire_animation (this, __, x, y) == -1; + + else if (is->current_config.polish_precision_striking && is_cruise_missile) { + Unit_animate_cruise_missile_strike (this, __, x, y); + return false; + + } else + return Unit_try_flying_over_tile (this, __, x, y); +} + +void __fastcall +patch_Unit_play_bombing_anim_for_precision_strike (Unit * this, int edx, int x, int y) +{ + // Only play the bombing animation here if we haven't already played an animation in the above method. We don't want to play all animations + // here since the bombard fire animation can fail for whatever reason but this method can't handle failure. + bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); + if ((! is->current_config.polish_precision_striking) || + ((p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && ! is_cruise_missile)) + Unit_play_bombing_animation (this, __, x, y); +} + +int __fastcall +patch_Unit_play_anim_for_bombard_tile (Unit * this, int edx, int x, int y) +{ + Unit * stealth_attack_target = NULL; + if (((p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && + is->current_config.enable_stealth_attack_via_bombardment && + (! is_online_game ()) && + patch_Leader_is_tile_visible (&leaders[this->Body.CivID], __, x, y)) + is->bombard_stealth_target = select_stealth_attack_bombard_target (this, x, y); + + return Unit_play_bombard_fire_animation (this, __, x, y); +} + +void __fastcall +patch_Main_Screen_Form_issue_precision_strike_cmd (Main_Screen_Form * this, int edx, Unit * unit) +{ + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + if ((! is->current_config.polish_precision_striking) || (type->Unit_Class == UTC_Air)) + Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); + else { + // issue_precision_strike_cmd will use the unit type's operational range. To make it use bombard range instead, place that value in + // the operational range field temporarily. Conveniently, it's only necessary to do this temporary switch once, here, because the main + // screen form stores a copy of the range for its own use and the method to actually perform the strike doesn't check the range. + int saved_op_range = type->OperationalRange; + type->OperationalRange = type->Bombard_Range; + Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); + type->OperationalRange = saved_op_range; + } +} + +int __fastcall +patch_Map_compute_neighbor_index_for_cm_strike (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + int tr = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); + + if ((tr >= 0) && + (is->bombarding_unit != NULL) && + ((p_bic_data->UnitTypes[is->bombarding_unit->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && + is->current_config.enable_stealth_attack_via_bombardment && + (! is_online_game ()) && + patch_Leader_is_tile_visible (&leaders[is->bombarding_unit->Body.CivID], __, x_neigh, y_neigh)) + is->bombard_stealth_target = select_stealth_attack_bombard_target (is->bombarding_unit, x_neigh, y_neigh); + + return tr; +} + +int __fastcall +patch_rand_bombard_target (void * this, int edx, int lim) +{ + // If we have a bombard stealth attack target set then return 2 so that the bombard damage will be applied to units not pop or buildings. + return (is->bombard_stealth_target == NULL) ? rand_int (this, __, lim) : 2; +} + +int __fastcall +patch_rand_int_to_dodge_city_aa (void * this, int edx, int lim) +{ + int tr = rand_int (this, __, lim); + is->result_of_roll_to_dodge_city_aa = tr; + return tr; +} + +int __fastcall +patch_Unit_get_defense_to_dodge_city_aa (Unit * this) +{ + int defense = Unit_get_defense_strength (this); + if (is->current_config.show_message_after_dodging_sam && + (defense > is->result_of_roll_to_dodge_city_aa) && + (this->Body.CivID == p_main_screen_form->Player_CivID)) + show_map_specific_text (this->Body.X, this->Body.Y, is->c3x_labels[CL_DODGED_SAM], 0); + return defense; +} + +int __fastcall +patch_Unit_get_defense_to_find_bombard_defender (Unit * this) +{ + // The caller is filtering out candidates with zero defense strength as possible targets to receive damage from bombardment. We can return 0 + // here to make sure "this" unit is not targeted. + + Unit * container; + + if (is->current_config.immunize_aircraft_against_bombardment && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air)) + return 0; + + else if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return 0; + + else + return Unit_get_defense_strength (this); +} + +int __cdecl +patch_get_WindowsFileBox_from_ini (LPCSTR key, int param_2, int param_3) +{ + // If the file path has already been determined, then avoid using the Windows file picker. This makes the later code to insert the path easier + // since we only have to intercept the opening of the civ-style file picker instead of both that and the Windows one. + if (is->load_file_path_override == NULL) + return get_int_from_conquests_ini (key, param_2, param_3); + else + return 0; +} + +char const * __fastcall +patch_do_open_load_game_file_picker (void * this) +{ + if (is->load_file_path_override != NULL) { + char const * tr = is->load_file_path_override; + is->load_file_path_override = NULL; + return tr; + } else + return open_load_game_file_picker (this); +} + +int __fastcall +patch_show_intro_after_load_popup (void * this, int edx, int param_1, int param_2) +{ + if (! is->suppress_intro_after_load_popup) + return patch_show_popup (this, __, param_1, param_2); + else { + is->suppress_intro_after_load_popup = 0; + return 0; + } +} + +void __fastcall patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id); + +void * __cdecl +patch_do_load_game (char * param_1) +{ + void * tr = do_load_game (param_1); + + if (is->current_config.restore_unit_directions_on_game_load && (p_units->Units != NULL)) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if ((unit != NULL) && (unit->Body.UnitState != UnitState_Fortifying)) { + if (Map_in_range (&p_bic_data->Map, __, unit->Body.X, unit->Body.Y) && + Map_in_range (&p_bic_data->Map, __, unit->Body.PrevMoveX, unit->Body.PrevMoveY)) { + int dx = unit->Body.X - unit->Body.PrevMoveX, dy = unit->Body.Y - unit->Body.PrevMoveY; + int dir = -1; + if ((dx == 1) && (dy == -1)) dir = DIR_NE; + else if ((dx == 2) && (dy == 0)) dir = DIR_E; + else if ((dx == 1) && (dy == 1)) dir = DIR_SE; + else if ((dx == 0) && (dy == 2)) dir = DIR_S; + else if ((dx == -1) && (dy == 1)) dir = DIR_SW; + else if ((dx == -2) && (dy == 0)) dir = DIR_W; + else if ((dx == -1) && (dy == -1)) dir = DIR_NW; + else if ((dx == 0) && (dy == -2)) dir = DIR_N; + if (dir >= 0) + unit->Body.Animation.summary.direction = dir; + } + } + } + + // Apply era aliases + for (int n = 0; n < 32; n++) + if (*p_player_bits & (1 << n)) + apply_era_specific_names (&leaders[n]); + + if (is->current_config.apply_grid_ini_setting_on_game_load) { + int grid_on = get_int_from_conquests_ini ("GridOn", 0, 0); + Map_Renderer * mr = &p_bic_data->Map.Renderer; + if (grid_on && ! mr->MapGrid_Flag) + mr->vtable->m68_Toggle_Grid (mr); + } + + return tr; +} + +void * +load_game_ex (char const * file_path, int suppress_intro_popup) +{ + is->suppress_intro_after_load_popup = suppress_intro_popup; + is->load_file_path_override = file_path; + return patch_do_load_game (NULL); +} + +int __fastcall +patch_show_movement_phase_popup (void * this, int edx, int param_1, int param_2) +{ + int tr = patch_show_popup (this, __, param_1, param_2); + + int player_civ_id = p_main_screen_form->Player_CivID; + int replay_for_players = is->replay_for_players; // Store this b/c it gets reset on game load + if (replay_for_players & 1<showing_hotseat_replay = true; + + patch_do_save_game (hotseat_resume_save_path, 1, 0); + load_game_ex (hotseat_replay_save_path, 1); + p_main_screen_form->Player_CivID = player_civ_id; + + // Re-enable the GUI so the minimap is visible during the replay. We must also reset the minimap & redraw it so that it reflects the + // player we just seated (above) instead of leftover data from the last player. + Main_GUI * main_gui = &p_main_screen_form->GUI; + main_gui->is_enabled = 1; + Navigator_Data_reset (&main_gui->Navigator_Data); + main_gui->Base.vtable->m73_call_m22_Draw ((Base_Form *)main_gui); + + perform_interturn (); + load_game_ex (hotseat_resume_save_path, 1); + p_main_screen_form->is_now_loading_game = 0; + + // Restore the replay_for_players variable b/c it gets cleared when loading a game. Also mask out the bit for the player we just + // showed the replay to. + is->replay_for_players = replay_for_players & ~(1<showing_hotseat_replay = false; + } + + return tr; +} + +// Returns a set of player bits containing only those players that are human and can see at least one AI unit. For speed and simplicity, does not +// account for units' invisibility ability, units are considered visible as long as they're on a visible tile. +int +find_human_players_seeing_ai_units () +{ + int tr = 0; + Map * map = &p_bic_data->Map; + if (map->Tiles != NULL) + for (int n_tile = 0; n_tile < map->TileCount; n_tile++) { + Tile * tile = map->Tiles[n_tile]; + Tile_Body * body = &tile->Body; + int human_vis_bits = (body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility) & *p_human_player_bits; + if (human_vis_bits != 0) // If any human players can see this tile + for (int n_player = 0; n_player < 32; n_player++) + if (human_vis_bits & 1<TileUnitID, &unused); + Unit * unit = get_unit_ptr (unit_id); + if ((unit != NULL) && + ((*p_human_player_bits & 1<Body.CivID) == 0)) { + tr |= 1<current_config.replay_ai_moves_in_hotseat_games && + (*p_is_offline_mp_game && ! *p_is_pbem_game); // offline MP but not PBEM => we're in a hotseat game + int ai_unit_vis_before; + if (save_replay) { + ai_unit_vis_before = find_human_players_seeing_ai_units (); + int toggleable_rules = *p_toggleable_rules; + *p_toggleable_rules |= TR_PRESERVE_RANDOM_SEED; // Make sure preserve random seed is on for the replay save + patch_do_save_game (hotseat_replay_save_path, 1, 0); + *p_toggleable_rules = toggleable_rules; + } + + is->players_saw_ai_unit = 0; // Clear bits. After perform_interturn, each set bit will indicate a player that has seen an AI unit move + long long ts_before; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); + is->time_spent_paused_during_popup = 0; + is->time_spent_computing_city_connections = 0; + is->count_calls_to_recompute_city_connections = 0; + unsigned saved_prefs = *p_preferences; + if (is->current_config.measure_turn_times) + *p_preferences &= ~(P_ANIMATE_BATTLES | P_SHOW_FRIEND_MOVES | P_SHOW_ENEMY_MOVES); + + perform_interturn (); + + if (is->current_config.day_night_cycle_mode) { + if (is->day_night_cycle_img_state == IS_OK) { + int new_hour = calculate_current_day_night_cycle_hour (); + if (new_hour != is->current_day_night_cycle) { + is->current_day_night_cycle = new_hour; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + } + } + } + + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_for_districts (); + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + } + + if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { + is->city_loc_display_perspective = -1; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw + } + + if (is->current_config.measure_turn_times) { + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + long long perf_freq; + QueryPerformanceFrequency ((LARGE_INTEGER *)&perf_freq); + int turn_time_in_ms = 1000 * (ts_after - ts_before - is->time_spent_paused_during_popup) / perf_freq; + int city_con_time_in_ms = 1000 * is->time_spent_computing_city_connections / perf_freq; + int road_time_in_ms = 1000 * is->time_spent_filling_roads / perf_freq; + + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + char msg[1000]; + + struct c3x_opt { + bool is_active; + char * name; + } opts[] = {{is->current_config.optimize_improvement_loops, "improv. loops"}, + {is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_OK), "trade net x"}}; + char opt_list[1000]; + memset (opt_list, 0, sizeof opt_list); + strncpy (opt_list, "^C3X optimizations: ", sizeof opt_list); + bool any_active_opts = false; + for (int n = 0; n < ARRAY_LEN (opts); n++) + if (opts[n].is_active) { + char * cursor = &opt_list[strlen (opt_list)]; + snprintf (cursor, opt_list + (sizeof opt_list) - cursor, "%s%s", any_active_opts ? ", " : "", opts[n].name); + any_active_opts = true; + } + if (! any_active_opts) { + char * cursor = &opt_list[strlen (opt_list)]; + strncpy (cursor, "None", opt_list + (sizeof opt_list) - cursor); + } + PopupForm_add_text (popup, __, (char *)opt_list, false); + + snprintf (msg, sizeof msg, "^Turn time: %d.%03d sec", turn_time_in_ms/1000, turn_time_in_ms%1000); + PopupForm_add_text (popup, __, (char *)msg, false); + snprintf (msg, sizeof msg, "^ Recomputing city connections: %d.%03d sec (%d calls)", + city_con_time_in_ms/1000, city_con_time_in_ms%1000, + is->count_calls_to_recompute_city_connections); + PopupForm_add_text (popup, __, (char *)msg, false); + snprintf (msg, sizeof msg, "^ Flood filling road network: %d.%03d sec", + road_time_in_ms/1000, road_time_in_ms%1000); + PopupForm_add_text (popup, __, (char *)msg, false); + patch_show_popup (popup, __, 0, 0); + + *p_preferences = saved_prefs; + } + + if (save_replay) { + int last_human_player_bit = 0; { + for (int n = 0; n < 32; n++) + if (*p_human_player_bits & 1<replay_for_players = (ai_unit_vis_before | (is->players_saw_ai_unit & *p_human_player_bits)) & ~last_human_player_bit; + } +} + +void __cdecl +patch_initialize_map_music (int civ_id, int era_id, bool param_3) +{ + if (! is->showing_hotseat_replay) + initialize_map_music (civ_id, era_id, param_3); +} + +void __stdcall +patch_deinitialize_map_music () +{ + if (! is->showing_hotseat_replay) + deinitialize_map_music (); +} + +void __fastcall +patch_Fighter_do_bombard_tile (Fighter * this, int edx, Unit * unit, int neighbor_index, int mp_tile_x, int mp_tile_y) +{ + // Unit::score_kill will be called if the bombarder destroys its target, and that is the only way score_kill can be called while this method + // is running. So if we're configured to stop enslaving from bombard, turn off enslaving while it's running. + is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; + + // Check if we're going to do PTW-like targeting, if not fall back on the base game's do_bombard_tile method. We'll also fall back on that + // method in the case where we're in an online game and the bombard can't happen b/c the tile is occupied by another battle. In that case, no + // bombard is possible but we'll call the base method anyway since it will show a little message saying as much. + if (itable_look_up_or (&is->current_config.ptw_arty_types, unit->Body.UnitTypeID, 0) && + (is->bombard_stealth_target == NULL) && + ! (is_online_game () && mp_check_current_combat (p_mp_object, __, mp_tile_x, mp_tile_y))) { + + City * city; { + int dx, dy; + neighbor_index_to_diff (neighbor_index, &dx, &dy); + int tile_x = unit->Body.X + dx, tile_y = unit->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + city = city_at (tile_x, tile_y); + } + + int rv; + if ((city != NULL) && ((rv = rand_int (p_rand_object, __, 3)) < 2)) + Fighter_damage_city_by_bombardment (this, __, unit, city, rv, 0); + else + Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); + + } else + Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); + + is->do_not_enslave_units = false; +} + +bool __fastcall +patch_Unit_check_king_for_defense_priority (Unit * this, int edx, enum UnitTypeAbilities king_ability) +{ + return (! is->current_config.ignore_king_ability_for_defense_priority) || (*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) ? + Unit_has_ability (this, __, king_ability) : + false; +} + +void WINAPI +patch_get_local_time_for_unit_ini (LPSYSTEMTIME lpSystemTime) +{ + GetLocalTime (lpSystemTime); + if (is->current_config.no_elvis_easter_egg && (lpSystemTime->wMonth == 1) && (lpSystemTime->wDay == 8)) + lpSystemTime->wDay = 9; +} + +bool __fastcall +patch_Leader_could_buy_tech_for_trade_screen (Leader * this, int edx, int tech_id, int from_civ_id) +{ + // Temporarily remove the untradable flag so this tech is listed on the screen instead of skipped over. After all the items have been + // assembled, we'll go back and disable the untradable techs. + if (is->current_config.show_untradable_techs_on_trade_screen) { + int saved_flags = p_bic_data->Advances[tech_id].Flags; + p_bic_data->Advances[tech_id].Flags &= ~ATF_Cannot_Be_Traded; + bool tr = this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); + p_bic_data->Advances[tech_id].Flags = saved_flags; + return tr; + + } else + return this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); +} + +void __fastcall +patch_DiploForm_assemble_tradable_items (DiploForm * this) +{ + DiploForm_assemble_tradable_items (this); + + // Disable (gray out) all untradable techs + if (is->current_config.show_untradable_techs_on_trade_screen) + for (int n = 0; n < p_bic_data->AdvanceCount; n++) + if (p_bic_data->Advances[n].Flags & ATF_Cannot_Be_Traded) { + this->tradable_technologies[n].can_be_bought = 0; + this->tradable_technologies[n].can_be_sold = 0; + } +} + +bool __fastcall +patch_City_can_trade_via_water (City * this) +{ + if (is->current_config.optimize_improvement_loops) { + for (int n = 0; n < is->water_trade_improvs.count; n++) + if (has_active_building (this, is->water_trade_improvs.items[n])) + return true; + return false; + } else + return City_can_trade_via_water (this); +} + +bool __fastcall +patch_City_can_trade_via_air (City * this) +{ + if (is->current_config.optimize_improvement_loops) { + for (int n = 0; n < is->air_trade_improvs.count; n++) + if (has_active_building (this, is->air_trade_improvs.items[n])) + return true; + return false; + } else + return City_can_trade_via_air (this); +} + +int __fastcall +patch_City_get_building_defense_bonus (City * this) +{ + bool cancel_great_wall_boost = is->current_config.enable_districts && + is->current_config.enable_great_wall_districts && + is->current_config.disable_great_wall_city_defense_bonus; + + if (is->current_config.optimize_improvement_loops || cancel_great_wall_boost) { + int tr = 0; + int is_size_level_1 = (this->Body.Population.Size <= p_bic_data->General.MaximumSize_City) && + (this->Body.Population.Size <= p_bic_data->General.MaximumSize_Town); + for (int n = 0; n < is->combat_defense_improvs.count; n++) { + int improv_id = is->combat_defense_improvs.items[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((is_size_level_1 || (improv->Combat_Bombard == 0)) && has_active_building (this, improv_id)) { + int multiplier; + if ((improv->Combat_Bombard > 0) && + (! cancel_great_wall_boost) && + (patch_Leader_count_any_shared_wonders_with_flag (&leaders[(this->Body).CivID], __, ITW_Doubles_City_Defenses, NULL) > 0)) + multiplier = 2; + else + multiplier = 1; + + int building_defense = multiplier * improv->Combat_Defence; + if (building_defense > tr) + tr = building_defense; + } + } + return tr; + } else + return City_get_building_defense_bonus (this); +} + +bool __fastcall +patch_City_shows_harbor_icon (City * this) +{ + return is->current_config.city_icons_show_unit_effects_not_trade ? + City_count_improvements_with_flag (this, __, ITF_Veteran_Sea_Units) > 0 : + patch_City_can_trade_via_water (this); +} + +bool __fastcall +patch_City_shows_airport_icon (City * this) +{ + return is->current_config.city_icons_show_unit_effects_not_trade ? + City_count_improvements_with_flag (this, __, ITF_Veteran_Air_Units) > 0 : + patch_City_can_trade_via_air (this); +} + +int __fastcall +patch_Unit_eval_escort_requirement (Unit * this) +{ + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + int ai_strat = type->AI_Strategy; + bool owned_by_ai = (*p_human_player_bits & 1<Body.CivID) == 0; // We must not reduce the escort requirement for human-owned units + // because that will interfere with group movement of units. + + // Apply special escort rules + if (owned_by_ai && is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) + return 0; + else if (owned_by_ai && is->current_config.use_offensive_artillery_ai && (ai_strat & UTAI_Artillery)) + return 1; + + else { + int base = Unit_eval_escort_requirement (this); + if (owned_by_ai && (ai_strat & (UTAI_Naval_Transport | UTAI_Naval_Carrier | UTAI_Naval_Missile_Transport))) + return not_above (is->current_config.max_ai_naval_escorts, base); + else + return base; + } +} + +bool __fastcall +patch_Unit_has_enough_escorters_present (Unit * this) +{ + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) + return true; + else + return Unit_has_enough_escorters_present (this); +} + +void __fastcall +patch_Unit_check_escorter_health (Unit * this, int edx, bool * has_any_escort_present, bool * any_escorter_cant_heal) +{ + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) { + *has_any_escort_present = true; + *any_escorter_cant_heal = true; // Returning true here indicates the unit should not stop to wait for its escorter(s) to heal. + } else + Unit_check_escorter_health (this, __, has_any_escort_present, any_escorter_cant_heal); +} + +void __fastcall +patch_Leader_unlock_technology (Leader * this, int edx, int tech_id, bool param_2, bool param_3, bool param_4) +{ + int * p_stack = (int *)&tech_id; + int ret_addr = p_stack[-1]; + + Leader_unlock_technology (this, __, tech_id, param_2, param_3, param_4); + + // If this method was not called during game initialization + if ((ret_addr != ADDR_UNLOCK_TECH_AT_INIT_1) && + (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_2) && + (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_3)) { + + // If this tech obsoletes some building and we're configured to fix the maintenance bug then recompute city maintenance. + if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings) { + bool obsoletes_anything = false; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (p_bic_data->Improvements[n].ObsoleteID == tech_id) { + obsoletes_anything = true; + break; + } + if (obsoletes_anything) + Leader_recompute_buildings_maintenance (this); + } + } +} + +int __fastcall +patch_City_get_improv_maintenance_for_ui (City * this, int edx, int improv_id) +{ + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && + (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) + return 0; + else + return patch_City_get_improvement_maintenance (this, __, improv_id); +} + +// Patch for barbarian diagonal bug. This bug is a small mistake in the original code, maybe a copy+paste error. The original code tries to loop over +// tiles around the barb unit by incrementing a neighbor index and coverting it to tile coords (like normal). The problem is that after it converts +// the neighbor index to dx and dy, it adds dx to both coords of the unit's position instead of using dy. The fix is simply to subtract off dx and add +// in dy when the Y coord is passed to Map::wrap_vert. +void __cdecl +patch_neighbor_index_to_diff_for_barb_ai (int neighbor_index, int * out_x, int * out_y) +{ + neighbor_index_to_diff (neighbor_index, out_x, out_y); + is->barb_diag_patch_dy_fix = *out_y - *out_x; +} +int __fastcall +patch_Map_wrap_vert_for_barb_ai (Map * this, int edx, int y) +{ + return Map_wrap_vert (this, __, is->current_config.patch_barbarian_diagonal_bug ? (y + is->barb_diag_patch_dy_fix) : y); +} + +int +count_workable_tiles_for_city (City * city) +{ + if (city == NULL) + return 0; + + int workable = 0; + FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { + Tile * tile = wai.tile; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + if (tile->Body.CityAreaID != city->Body.ID) + continue; + + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && district_is_complete (tile, inst->district_id)) + continue; + + workable++; + } + return workable; +} + +int +compute_auto_distribution_hub_goal (Leader * leader, int city_count) +{ + int total_unused_tiles = 0; + int stagnating_cities = 0; + int slow_growth_cities = 0; + int very_low_production_cities = 0; + int low_production_cities = 0; + + FOR_CITIES_OF (coi, leader->ID) { + City * city = coi.city; + if (city == NULL) + continue; + + int pop_size = city->Body.Population.Size; + int workable_tiles = count_workable_tiles_for_city (city); + if ((workable_tiles > 0) && (pop_size < workable_tiles)) + total_unused_tiles += workable_tiles - pop_size; + + int net_food = city->Body.FoodIncome; + if (net_food <= 0) + stagnating_cities++; + else if (net_food <= 2) + slow_growth_cities++; + + int net_shields = city->Body.ProductionIncome + city->Body.ProductionLoss; + if (net_shields < 0) + net_shields = 0; + if (net_shields <= 3) + very_low_production_cities++; + else if (net_shields <= 6) + low_production_cities++; + } + + int base_desired = (city_count + 3) / 4; + + int tiles_per_chunk = is->workable_tile_count; + if (tiles_per_chunk <= 0) + tiles_per_chunk = 1; + int unused_bonus = (total_unused_tiles + tiles_per_chunk * 3 - 1) / (tiles_per_chunk * 3); + + int food_pressure = stagnating_cities * 2 + slow_growth_cities; + int food_bonus = (food_pressure + 2) / 3; + + int production_pressure = very_low_production_cities * 2 + low_production_cities; + int production_bonus = (production_pressure + 2) / 3; + + int desired = base_desired + unused_bonus + food_bonus + production_bonus; + int max_reasonable = (city_count + 1) / 2; + int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; + if (max_per_100 > 0) { + int capped = (city_count * max_per_100 + 99) / 100; + if (capped >= 0) + max_reasonable = capped; + } + if (desired > max_reasonable) + desired = max_reasonable; + if (desired < 1) + desired = 1; + + return desired; +} + +void +ai_update_distribution_hub_goal_for_leader (Leader * leader) +{ + if (leader == NULL) + return; + if (! is->current_config.enable_districts || + ! is->current_config.enable_distribution_hub_districts) + return; + + int civ_id = leader->ID; + if ((1 << civ_id) & *p_human_player_bits) + return; + + int city_count = leader->Cities_Count; + if (city_count <= 0) + return; + + int desired = 0; + if (is->current_config.ai_distribution_hub_build_strategy == ADHBS_AUTO) + desired = compute_auto_distribution_hub_goal (leader, city_count); + else { + int ideal_per_100 = is->current_config.ai_ideal_distribution_hub_count_per_100_cities; + if (ideal_per_100 <= 0) + return; + desired = (city_count * ideal_per_100) / 100; + } + if (desired <= 0) + return; + + int current = 0; + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if ((rec != NULL) && (rec->civ_id == civ_id)) + current++; + } + + int in_progress = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * tile = (Tile *)tei.key; + int mapped_district_id = tei.value; + if ((tile != NULL) && + (mapped_district_id == DISTRIBUTION_HUB_DISTRICT_ID) && + ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID)) { + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (owner == civ_id) + in_progress++; + } + } + + int pending = 0; + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req != NULL) && (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID)) + pending++; + } + + int planned = current + in_progress + pending; + if (planned >= desired) + return; + + City * capital = get_city_ptr (leader->CapitalID); + bool has_capital = (capital != NULL); + int capital_x = has_capital ? capital->Body.X : 0; + int capital_y = has_capital ? capital->Body.Y : 0; + + const int yield_weight = 40; + const int capital_distance_weight = 45; + const int desired_min_capital_distance = 8; + const int proximity_penalty_scale = 300; + + while (planned < desired) { + City * best_city = NULL; + int best_tile_x = 0; + int best_tile_y = 0; + int best_score = INT_MIN; + + FOR_CITIES_OF (coi, civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + if (city_has_required_district (city, DISTRIBUTION_HUB_DISTRICT_ID)) + continue; + + if (find_pending_district_request (city, DISTRIBUTION_HUB_DISTRICT_ID) != NULL) + continue; + + int tile_x, tile_y; + Tile * candidate = find_tile_for_district (city, DISTRIBUTION_HUB_DISTRICT_ID, &tile_x, &tile_y); + if (candidate == NULL) + continue; + + int yield_sum = compute_city_tile_yield_sum (city, tile_x, tile_y); + int distance_to_capital = 0; + if (has_capital) + distance_to_capital = compute_wrapped_manhattan_distance (city->Body.X, city->Body.Y, capital_x, capital_y); + + int closeness_penalty = 0; + if (has_capital && (distance_to_capital < desired_min_capital_distance)) + closeness_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; + + int score = yield_sum * yield_weight + distance_to_capital * capital_distance_weight - closeness_penalty; + if (tile_has_resource (candidate)) + score -= 500; + + if (score > best_score) { + best_score = score; + best_city = city; + best_tile_x = tile_x; + best_tile_y = tile_y; + } + } + + if (best_city == NULL) + break; + + mark_city_needs_district (best_city, DISTRIBUTION_HUB_DISTRICT_ID); + planned++; + } +} + +bool +assign_ai_fallback_production (City * city, int disallowed_improvement_id) +{ + if (city == NULL) + return false; + + City_Order new_order = { .OrderID = -1, .OrderType = 0 }; + patch_City_ai_choose_production (city, __, &new_order); + + bool order_ok = false; + if (new_order.OrderType == COT_Improvement) { + if ((new_order.OrderID >= 0) && + (new_order.OrderID < p_bic_data->ImprovementsCount) && + (new_order.OrderID != disallowed_improvement_id) && + ! city_requires_district_for_improvement (city, new_order.OrderID, NULL) && + ! is_wonder_or_small_wonder_already_being_built (city, new_order.OrderID)) + order_ok = true; + } else if (new_order.OrderType == COT_Unit) { + if ((new_order.OrderID >= 0) && + (new_order.OrderID < p_bic_data->UnitTypeCount) && + (p_bic_data->UnitTypes[new_order.OrderID].Unit_Class == UTC_Land) && + patch_City_can_build_unit (city, __, new_order.OrderID, 1, 0, 0)) + order_ok = true; + } + + char ss[200]; + snprintf (ss, sizeof ss, "assign_ai_fallback_production: Remembering fallback pending building order for city %d (%s): id %d\n", + city->Body.ID, city->Body.CityName, disallowed_improvement_id); + (*p_OutputDebugStringA) (ss); + remember_pending_building_order (city, disallowed_improvement_id); + + if (order_ok) { + City_set_production (city, __, new_order.OrderType, new_order.OrderID, false); + return true; + } + + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) { + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + return true; + } + } + + return false; +} + +void __fastcall +patch_Leader_do_production_phase (Leader * this) +{ + recompute_resources_if_necessary (); + + if (is->current_config.enable_districts) { + assign_workers_for_pending_districts (this); + + if ((is->current_config.enable_canal_districts || is->current_config.enable_bridge_districts) && + (is->current_config.ai_builds_bridges || is->current_config.ai_builds_canals)) + assign_workers_for_ai_candidate_bridge_or_canals (this); + + bool ai_player = ((*p_human_player_bits & (1 << this->ID)) == 0); + int auto_dynamic_district_ids[COUNT_DISTRICT_TYPES]; + int auto_dynamic_district_count = 0; + + // For dynamic districts, the AI will never be triggered to build them if they have no dependent buildings. + // Determine which dynamic districts the AI could build. In the city loop after, mark which cities need them + if (ai_player) { + for (int district_id = is->special_district_count; district_id < is->district_count; district_id++) { + struct district_config * cfg = &is->district_configs[district_id]; + struct district_infos * info = &is->district_infos[district_id]; + + if (info->dependent_building_count > 0) continue; + if (cfg->command == -1) continue; + + if (! leader_can_build_district (this, district_id)) + continue; + + if (auto_dynamic_district_count < ARRAY_LEN (auto_dynamic_district_ids)) + auto_dynamic_district_ids[auto_dynamic_district_count++] = district_id; + } + } + + // Special exception for AI to build Central Rail Hub, which is available in Industrial era but Mass Transit, + // the only building dependent on it, is in the Modern era. Without this the AI wouldn't build in Industrial era. + if (is->current_config.enable_central_rail_hub_districts) { + if (leader_can_build_district (this, CENTRAL_RAIL_HUB_DISTRICT_ID)) + auto_dynamic_district_ids[auto_dynamic_district_count++] = CENTRAL_RAIL_HUB_DISTRICT_ID; + } + + if (is->current_config.enable_distribution_hub_districts) { + if (leader_can_build_district (this, DISTRIBUTION_HUB_DISTRICT_ID)) + ai_update_distribution_hub_goal_for_leader (this); + } + + FOR_CITIES_OF (coi, this->ID) { + City * city = coi.city; + if (city == NULL) continue; + + bool at_neighborhood_cap = is->current_config.enable_neighborhood_districts && city_is_at_neighborhood_cap (city); + + // Mark any needed dynamic districts for AI players. This isn't the most intelligent approach (we're not weighing district benefits), + // but it's simple and works reasonably well + if (ai_player && (auto_dynamic_district_count > 0)) { + for (int i = 0; i < auto_dynamic_district_count; i++) { + int district_id = auto_dynamic_district_ids[i]; + + if (city_has_required_district (city, district_id)) continue; + if (! city_can_build_district (city, district_id)) continue; + if (find_pending_district_request (city, district_id) != NULL) continue; + + int target_x = 0, target_y = 0; + if (find_tile_for_district (city, district_id, &target_x, &target_y) == NULL) + continue; + + mark_city_needs_district (city, district_id); + } + } + + if (at_neighborhood_cap) { + if (! ai_player) + maybe_show_neighborhood_growth_warning (city); + else + ensure_neighborhood_request_for_city (city); + } + + if (city->Body.Order_Type == COT_Unit) { + int unit_id = city->Body.Order_ID; + int req_district_id = -1; + bool needs_halt = false; + + if ((unit_id >= 0) && (unit_id < p_bic_data->UnitTypeCount)) { + UnitType * type = &p_bic_data->UnitTypes[unit_id]; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { + req_district_id = AERODROME_DISTRICT_ID; + needs_halt = true; + } else if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (city, PORT_DISTRICT_ID))) { + req_district_id = PORT_DISTRICT_ID; + needs_halt = true; + } + } + + if (needs_halt) { + char ss[200]; + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting unit %d due to missing district %d\n", + city->Body.ID, city->Body.CityName, unit_id, req_district_id); + (*p_OutputDebugStringA) (ss); + + if (ai_player) + mark_city_needs_district (city, req_district_id); + + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + + continue; + } + } + + if (city->Body.Order_Type != COT_Improvement) continue; + int i_improv = city->Body.Order_ID; + + // Check if production needs to be halted due to missing district + int req_district_id = -1; + char const * district_description = NULL; + bool needs_halt = false; + + // Check buildings & wonders dependent on districts + if (city_requires_district_for_improvement (city, i_improv, &req_district_id)) { + if (req_district_id >= 0) { + needs_halt = true; + district_description = is->district_configs[req_district_id].name; + } + } + + // Wonders + char ss[200]; + if (is->current_config.enable_wonder_districts) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: Checking wonder improv %d for city %d (%s)\n", + i_improv, city->Body.ID, city->Body.CityName); + (*p_OutputDebugStringA) (ss); + if (city_is_currently_building_wonder (city)) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) is building wonder improv %d\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + bool wonder_requires_district = false; + if (i_improv >= 0) { + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); + if (district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) + wonder_requires_district = true; + } + + if (wonder_requires_district) { + bool has_wonder_district = reserve_wonder_district_for_city (city, i_improv); + if (! has_wonder_district) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) lacks Wonder District for wonder improv %d\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + needs_halt = true; + req_district_id = WONDER_DISTRICT_ID; + district_description = "Wonder District"; + } + } else { + release_wonder_district_reservation (city); + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) wonder improv %d does not require Wonder District\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + } + } else { + release_wonder_district_reservation (city); + } + } + + // If production needs to be halted, handle the reassignment and messaging + if (needs_halt) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting improv %d due to missing district %d\n", + city->Body.ID, city->Body.CityName, i_improv, req_district_id); + (*p_OutputDebugStringA) (ss); + // Switch production to another option + if (ai_player) { + mark_city_needs_district (city, req_district_id); + assign_ai_fallback_production (city, i_improv); + } else { + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + // Show message to human player + if (! ai_player && (city->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[160]; + char const * bname = p_bic_data->Improvements[i_improv].Name.S; + snprintf (msg, sizeof msg, "%s %s %s", bname, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_description); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + continue; + } + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) improv %d passed missing district check\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + } + } + + // Force-activate the barbs if there are any barb cities on the map and barb city capturing is enabled. This is necessary for barb city + // production to work given how it's currently implemented. + if (is->current_config.enable_city_capture_by_barbarians && (this->ID == 0)) { + int any_barb_cities = 0; + FOR_CITIES_OF (coi, this->ID) { + any_barb_cities = 1; + break; + } + if (any_barb_cities) + is->force_barb_activity_for_cities = 1; + } + + // If barbs are force-activated, make sure their activity level is at least 1 (sedentary). + int * p_barb_activity = &p_bic_data->Map.World.Final_Barbarians_Activity; + int saved_barb_activity = *p_barb_activity; + if (is->force_barb_activity_for_cities && (*p_barb_activity <= 0)) + *p_barb_activity = 1; + + Leader_do_production_phase (this); + + if (is->force_barb_activity_for_cities) { + *p_barb_activity = saved_barb_activity; + is->force_barb_activity_for_cities = 0; + } +} + +// This function counts the number of players in the game. The return value will be compared to the number of cities on the map to determine if there +// are enough cities (per player) to unlock barb production. If barb activity is forced on, return zero so that the check always passes. +int __cdecl +patch_count_player_bits_for_barb_prod (unsigned int bit_field) +{ + return is->force_barb_activity_for_cities ? 0 : count_set_bits (bit_field); +} + +Tile * __fastcall +patch_Map_get_tile_to_check_visibility (Map * this, int edx, int index) +{ + Tile * tr = Map_get_tile (this, __, index); + int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; + if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { + int human_bits = *p_human_player_bits; + is->dummy_tile->Body.Fog_Of_War = tr->Body.Fog_Of_War | ((tr->Body.Fog_Of_War & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.FOWStatus = tr->Body.FOWStatus | ((tr->Body.FOWStatus & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.V3 = tr->Body.V3 | ((tr->Body.V3 & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.Visibility = tr->Body.Visibility | ((tr->Body.Visibility & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.field_D0_Visibility = tr->Body.field_D0_Visibility | ((tr->Body.field_D0_Visibility & human_bits) != 0 ? human_bits : 0); + tr = is->dummy_tile; + } + is->tile_returned_for_visibility_check = tr; + return tr; +} + +Tile * __fastcall +patch_Map_get_tile_to_check_visibility_again (Map * this, int edx, int index) +{ + return is->tile_returned_for_visibility_check; +} + +// Same as above except this method uses the FOWStatus field instead of Fog_Of_War +Tile * __fastcall +patch_Map_get_tile_for_fow_status_check (Map * this, int edx, int index) +{ + Tile * tile = Map_get_tile (this, __, index); + int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; + if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { + is->dummy_tile->Body.FOWStatus = ((tile->Body.FOWStatus & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; + return is->dummy_tile; + } else + return tile; +} + +Tile * __cdecl +patch_tile_at_to_check_visibility (int x, int y) +{ + return patch_Map_get_tile_to_check_visibility (&p_bic_data->Map, __, (p_bic_data->Map.Width >> 1) * y + (x >> 1)); +} + +Tile * __cdecl +patch_tile_at_to_check_visibility_again (int x, int y) +{ + return is->tile_returned_for_visibility_check; +} + +unsigned __fastcall +patch_Tile_m42_Get_Overlays (Tile * this, int edx, byte visible_to_civ) +{ + unsigned base_vis_overlays = Tile_m42_Get_Overlays (this, __, visible_to_civ); + if ((visible_to_civ != 0) && // if we're seeing from a player's persp. instead of seeing the actual overlays AND + is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND + ((1 << visible_to_civ) & *p_human_player_bits) && // the perspective is of a human player AND + (base_vis_overlays != this->Overlays) && // that player can't already see all the actual overlays AND + (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game + + // Check if there's another human player that can see the actual overlays. If so, give that info to this player and return it. + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != visible_to_civ) && + (Tile_m42_Get_Overlays (this, __, n_player) == this->Overlays)) { + this->Body.Visibile_Overlays[visible_to_civ] = this->Overlays; + return this->Overlays; + } + player_bits >>= 1; + n_player++; + } + + return base_vis_overlays; + } else + return base_vis_overlays; +} + +int __fastcall +patch_Tile_check_water_for_sea_zoc (Tile * this) +{ + if ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) + return this->vtable->m35_Check_Is_Water (this); + else + return 1; // The caller will skip ZoC logic if this is a land tile without a city because the targeted unit is a sea unit. Instead + // return 1, so all tiles are considered sea tiles, so we can run the ZoC logic for land units or air units on land. +} + +int __fastcall +patch_Tile_check_water_for_land_zoc (Tile * this) +{ + // Same as above except this time we want to consider all tiles to be land + return ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) ? + this->vtable->m35_Check_Is_Water (this) : + 0; +} + + +int __fastcall +patch_Unit_get_attack_strength_for_sea_zoc (Unit * this) +{ + return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) ? Unit_get_attack_strength (this) : 0; +} + +int __fastcall +patch_Unit_get_attack_strength_for_land_zoc (Unit * this) +{ + return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) ? Unit_get_attack_strength (this) : 0; +} + +// Forward declaration; defined further below near patch_Fighter_get_odds_for_main_combat_loop +// where its dependencies (apply_counter_rules, Fighter_get_combat_odds, counter_combat_ctx) live. +Unit * find_civ4_best_defender_against (Unit * attacker, Tile * tile, int tile_x, int tile_y); + +Unit * __fastcall +patch_Main_Screen_Form_find_visible_unit (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * excluded) +{ + struct unit_display_override * override = &is->unit_display_override; + if ((override->unit_id >= 0) && (override->tile_x == tile_x) && (override->tile_y == tile_y)) { + Unit * unit = get_unit_ptr (override->unit_id); + if (unit != NULL) { + if ((unit->Body.X == tile_x) && (unit->Body.Y == tile_y)) + return unit; + } + } + + // Civ 4-style 'best defender' display: when a player selects an attacker, the unit at the top of the enemy stack + // should be the one with the lowest win rate against that attacker. + // Only takes effect when both `use_civ4_style_best_defender` and `enable_unit_counters` are enabled, + // and provided the currently selected unit belongs to the local player and there is an enemy unit on the target square. + // + if (is->current_config.use_civ4_style_best_defender && + is->current_config.enable_unit_counters && + (this->Current_Unit != NULL) && + (this->Current_Unit->Body.CivID == this->Player_CivID) && + ((this->Current_Unit->Body.X != tile_x) || (this->Current_Unit->Body.Y != tile_y))) { + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile) && + tile_has_enemy_unit (tile, this->Current_Unit->Body.CivID)) { + Unit * best = find_civ4_best_defender_against (this->Current_Unit, tile, tile_x, tile_y); + if ((best != NULL) && (best != excluded)) + return best; + } + } + + return Main_Screen_Form_find_visible_unit (this, __, tile_x, tile_y, excluded); +} + +void __fastcall +patch_Animator_play_zoc_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) +{ + if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Air) + Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); +} + +bool __fastcall +patch_Fighter_check_zoc_anim_visibility (Fighter * this, int edx, Unit * attacker, Unit * defender, bool param_3) +{ + // If we've reached this point in the code (in the calling method) then a unit has been selected to exert zone of control and it has passed + // its dice roll to cause damage. Stash its pointer for possible use later. + is->zoc_interceptor = attacker; + + // If an air unit was selected, pre-emptively undo the damage from ZoC since we'll want to run our own bit of logic to do that (the air unit + // may still get shot down). Return false from this function to skip over all of the animation logic in the caller since it wouldn't work for + // aircraft. + if (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Air) { + defender->Body.Damage -= 1; + return false; + + // Repeat a check done by the caller. We've deleted this check to ensure that this function always gets called so we can grab the interceptor. + } else if (attacker->Body.Animation.field_111 == 0) + return false; + + else { + bool tr = Fighter_check_combat_anim_visibility (this, __, attacker, defender, param_3); + + // If necessary, set up to ensure the unit's attack animation is visible. This means forcing it to the top of its stack and + // temporarily unfortifying it if it's fortified. (If it's fortified, the animation is occasionally not visible. Don't know why.) + if (tr && is->current_config.show_zoc_attacks_from_mid_stack) { + is->unit_display_override = (struct unit_display_override) { attacker->Body.ID, attacker->Body.X, attacker->Body.Y }; + if (attacker->Body.UnitState == UnitState_Fortifying) { + Unit_set_state (attacker, __, 0); + is->refortify_interceptor_after_zoc = true; + } + } + + return tr; + } +} + +int __fastcall +patch_City_sum_buildings_naval_power_for_zoc (City * this) +{ + // Cancel out city's naval power if the unit has only one HP left. This prevents coastal fortresses from knocking that last hit point off + // passing units when lethal ZoC is enabled, because to make that work we delete an earlier check excusing 1-HP units from ZoC. + if ((is->zoc_defender != NULL) && + ((Unit_get_max_hp (is->zoc_defender) - is->zoc_defender->Body.Damage) <= 1)) + return 0; + + else + return City_sum_buildings_naval_power (this); +} + +void __fastcall +patch_Fighter_apply_zone_of_control (Fighter * this, int edx, Unit * unit, int from_x, int from_y, int to_x, int to_y) +{ + is->zoc_interceptor = NULL; + is->zoc_defender = unit; + is->refortify_interceptor_after_zoc = false; + struct unit_display_override saved_udo = is->unit_display_override; + Fighter_apply_zone_of_control (this, __, unit, from_x, from_y, to_x, to_y); + + // Actually exert ZoC if an air unit managed to do so. + if ((is->zoc_interceptor != NULL) && (p_bic_data->UnitTypes[is->zoc_interceptor->Body.UnitTypeID].Unit_Class == UTC_Air)) { + bool intercepted = Unit_try_flying_over_tile (is->zoc_interceptor, __, from_x, from_y); + if (! intercepted) { + Unit_play_bombing_animation (is->zoc_interceptor, __, from_x, from_y); + unit->Body.Damage = not_below (0, unit->Body.Damage + 1); + } + } + + if (is->refortify_interceptor_after_zoc) + Unit_set_state (is->zoc_interceptor, __, UnitState_Fortifying); + is->unit_display_override = saved_udo; +} + +// These two patches replace two function calls in Unit::move_to_adjacent_tile that come immediately after the unit has been subjected to zone of +// control. These calls recheck that the move is valid, not sure why. Here they're patched to indicate that the move in invalid when the unit was +// previously killed by ZoC. This causes move_to_adjacent_tile to return early without running the code that would place the unit on the destination +// tile and, for example, capturing an enemy city there. +int __fastcall +patch_Trade_Net_get_move_cost_after_zoc (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned param_7, int neighbor_index, Trade_Net_Distance_Info * dist_info) +{ + return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (unit) - unit->Body.Damage) > 0) ? + patch_Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, param_7, neighbor_index, dist_info) : + -1; +} + +AdjacentMoveValidity __fastcall +patch_Unit_can_move_after_zoc (Unit * this, int edx, int neighbor_index, int param_2) +{ + return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (this) - this->Body.Damage) > 0) ? + patch_Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2) : + AMV_1; +} + +// Checks unit's HP after it was possibly hit by ZoC and deals with the consequences if it's dead. Does nothing if config option to make ZoC lethal +// isn't set or if interceptor is NULL. Returns true if the unit was killed, false otherwise. +bool +check_life_after_zoc (Unit * unit, Unit * interceptor) +{ + if ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) && (interceptor != NULL) && + ((Unit_get_max_hp (unit) - unit->Body.Damage) <= 0)) { + + // Call Unit::score_kill but turn off enslaving if we're configured to stop enslaving after bombardment and the ZoC was performed by + // bombardment, which is always the case for cross-domain ZoC or when bombard str > attack. + UnitType * interceptor_type = &p_bic_data->UnitTypes[interceptor->Body.UnitTypeID]; + if (is->current_config.prevent_enslaving_by_bombardment && + ((p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != interceptor_type->Unit_Class) || + (interceptor_type->Bombard_Strength >= Unit_get_attack_strength (interceptor)))) + is->do_not_enslave_units = true; + Unit_score_kill (interceptor, __, unit, false); + is->do_not_enslave_units = false; + + if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (&p_bic_data->fighter, __, interceptor, unit, true)) + Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, unit, AT_DEATH, false); + + bool prev_always_despawn_passengers = is->always_despawn_passengers; + is->always_despawn_passengers = is_land_transport (unit) && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); + patch_Unit_despawn (unit, __, interceptor->Body.CivID, 0, 0, 0, 0, 0, 0); + is->always_despawn_passengers = prev_always_despawn_passengers; + + return true; + } else + return false; +} + +int __fastcall +patch_Unit_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, bool param_2, int param_3, byte param_4) +{ + is->moving_unit_to_adjacent_tile = true; + is->move_spend_override_unit = NULL; + is->move_spend_override_value = 0; + + bool const allow_worker_coast = is->current_config.enable_districts && is->current_config.workers_can_enter_coast && is_worker (this); + bool const allow_bridge_walk = is->current_config.enable_districts && + is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land); + bool const allow_canal_sail = is->current_config.enable_districts && + is->current_config.enable_canal_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea); + bool coast_override_active = false; + enum UnitStateType prev_state = this->Body.UnitState; + int prev_container = this->Body.Container_Unit; + bool restore_goto_path = prev_state == UnitState_Go_To; + int prev_path_len = this->Body.path_len; + int prev_path_dest_x = this->Body.path_dest_x; + int prev_path_dest_y = this->Body.path_dest_y; + + if (allow_worker_coast || allow_bridge_walk || allow_canal_sail) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + Tile * dest = tile_at (nx, ny); + if (dest != NULL) { + if (allow_bridge_walk && ! dest->vtable->m35_Check_Is_Water (dest)) { + Tile * src = tile_at (this->Body.X, this->Body.Y); + if ((src != NULL) && (src != p_null_tile)) { + struct district_instance * src_inst = get_district_instance (src); + bool from_bridge = (src_inst != NULL) && + (src_inst->district_id == BRIDGE_DISTRICT_ID) && + district_is_complete (src, src_inst->district_id); + if (from_bridge) { + int move_cost = patch_Trade_Net_get_movement_cost ( + is->trade_net, __, + this->Body.X, this->Body.Y, nx, ny, + this, this->Body.CivID, 0, neighbor_index, NULL); + if (move_cost >= 0) { + int spent_moves = this->Body.Moves + move_cost; + is->move_spend_override_unit = this; + is->move_spend_override_value = not_above (spent_moves, patch_Unit_get_max_move_points (this)); + } + } + } + } + + bool should_override = false; + if (allow_worker_coast && + dest->vtable->m35_Check_Is_Water (dest) && + (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + if (is_human) { + should_override = true; + } else { + struct district_worker_record * rec = get_tracked_worker_record (this); + struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; + if (req != NULL) { + City * req_city = (req->city != NULL) ? req->city : get_city_ptr (req->city_id); + if ((req->district_id >= 0) && + (req->district_id < is->district_count) && + (req_city != NULL) && + city_radius_contains_tile (req_city, nx, ny) && + (req->target_x == nx) && (req->target_y == ny)) { + struct district_config const * cfg = &is->district_configs[req->district_id]; + if ((cfg->buildable_square_types_mask & (1 << SQ_Coast)) != 0) + should_override = true; + } + } + } + } + + if (! should_override && allow_bridge_walk) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && + (inst->district_id == BRIDGE_DISTRICT_ID) && + district_is_complete (dest, inst->district_id)) + should_override = true; + } + + if (! should_override && allow_canal_sail) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && + (inst->district_id == CANAL_DISTRICT_ID) && + district_is_complete (dest, inst->district_id)) + should_override = true; + } + + if (should_override) { + coast_override_active = true; + is->coast_walk_unit = this; + is->coast_walk_transport_override = false; + is->coast_walk_prev_state = prev_state; + is->coast_walk_prev_container = prev_container; + is->coast_walk_restore_goto_path = restore_goto_path; + is->coast_walk_prev_path_len = prev_path_len; + is->coast_walk_prev_path_dest_x = prev_path_dest_x; + is->coast_walk_prev_path_dest_y = prev_path_dest_y; + } + } + } + + is->zoc_interceptor = is->zoc_defender = NULL; + int tr = Unit_move_to_adjacent_tile (this, __, neighbor_index, param_2, param_3, param_4); + if ((this == is->zoc_defender) && check_life_after_zoc (this, is->zoc_interceptor)) + tr = ! is_online_game (); // This is what the original method returns when the unit was destroyed in combat + + if (coast_override_active) { + is->coast_walk_unit = NULL; + is->coast_walk_transport_override = false; + + if (this->Body.Container_Unit == this->Body.ID) { + this->Body.Container_Unit = is->coast_walk_prev_container; + Unit_set_state (this, __, is->coast_walk_prev_state); + if (is->coast_walk_restore_goto_path) { + this->Body.path_len = is->coast_walk_prev_path_len; + this->Body.path_dest_x = is->coast_walk_prev_path_dest_x; + this->Body.path_dest_y = is->coast_walk_prev_path_dest_y; + } + } + } + + is->temporarily_disallow_lethal_zoc = false; + is->moving_unit_to_adjacent_tile = false; + is->move_spend_override_unit = NULL; + is->move_spend_override_value = 0; + return tr; +} + +int __fastcall +patch_Unit_teleport (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad) +{ + is->zoc_interceptor = NULL; + int tr = Unit_teleport (this, __, tile_x, tile_y, unit_telepad); + check_life_after_zoc (this, is->zoc_interceptor); + return tr; +} + +bool +can_do_defensive_bombard (Unit * unit, UnitType * type) +{ + if ((type->Bombard_Strength > 0) && (! Unit_has_ability (unit, __, UTA_Cruise_Missile))) { + if (cannot_defend_inside_transport (unit)) + return false; + + if ((unit->Body.Status & USF_USED_DEFENSIVE_BOMBARD) == 0) // has not already done DB this turn + return true; + + // If the "blitz" special DB rule is activated and this unit has blitz, check if it still has an extra DB to use + else if ((is->current_config.special_defensive_bombard_rules & SDBR_BLITZ) && UnitType_has_ability (type, __, UTA_Blitz)) { + int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, unit->Body.ID, 0); + return type->Movement > extra_dbs + 1; + + } else + return false; + } else + return false; +} + +Unit * __fastcall +patch_Fighter_find_defensive_bombarder (Fighter * this, int edx, Unit * attacker, Unit * defender) +{ + int special_db_rules = is->current_config.special_defensive_bombard_rules; + if ((special_db_rules == 0) && + ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) == 0) && + ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) == 0)) + return Fighter_find_defensive_bombarder (this, __, attacker, defender); + else { + enum UnitTypeClasses attacker_class = p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class; + int attacker_has_one_hp = Unit_get_max_hp (attacker) - attacker->Body.Damage <= 1; + + Tile * defender_tile = tile_at (defender->Body.X, defender->Body.Y); + if ((Unit_get_defense_strength (attacker) < 1) || // if attacker cannot defend OR + (defender_tile == NULL) || (defender_tile == p_null_tile) || // defender tile is invalid OR + (((special_db_rules & SDBR_LETHAL) == 0) && attacker_has_one_hp) || // (DB is non-lethal AND attacker has one HP remaining) OR + ((special_db_rules & SDBR_NOT_INVISIBLE) && ! patch_Unit_is_visible_to_civ (attacker, __, defender->Body.CivID, 1))) // (invisible units are immune to DB AND attacker is invisible) + return NULL; + + Unit * tr = NULL; + int highest_strength = -1; + enum UnitTypeAbilities lethal_bombard_req = (attacker_class == UTC_Sea) ? UTA_Lethal_Sea_Bombardment : UTA_Lethal_Land_Bombardment; + FOR_UNITS_ON (uti, defender_tile) { + Unit * candidate = uti.unit; + UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; + if (can_do_defensive_bombard (candidate, candidate_type) && + (candidate_type->Bombard_Strength > highest_strength) && + (candidate != defender) && + (Unit_get_containing_army (candidate) != defender) && + ((attacker_class == candidate_type->Unit_Class) || + ((special_db_rules & SDBR_AERIAL) && + (candidate_type->Unit_Class == UTC_Air) && + (candidate_type->Air_Missions & UCV_Bombing)) || + ((special_db_rules & SDBR_DOCKED_VS_LAND) && + (candidate_type->Unit_Class == UTC_Sea) && + (get_city_ptr (defender_tile->CityID) != NULL))) && + ((! attacker_has_one_hp) || UnitType_has_ability (candidate_type, __, lethal_bombard_req))) { + tr = candidate; + highest_strength = candidate_type->Bombard_Strength; + } + } + return tr; + } +} + +void __fastcall +patch_Fighter_damage_by_db_in_main_loop (Fighter * this, int edx, Unit * bombarder, Unit * defender) +{ + if (p_bic_data->UnitTypes[bombarder->Body.UnitTypeID].Unit_Class == UTC_Air) { + if (Unit_try_flying_over_tile (bombarder, __, defender->Body.X, defender->Body.Y)) + return; // intercepted + else if (patch_Main_Screen_Form_is_unit_visible_to_player (p_main_screen_form, __, defender->Body.X, defender->Body.Y, bombarder)) + Unit_play_bombing_animation (bombarder, __, defender->Body.X, defender->Body.Y); + } + + // If the unit has already performed DB this turn, then record that it's consumed one of its extra DBs + if (bombarder->Body.Status & USF_USED_DEFENSIVE_BOMBARD) { + int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, bombarder->Body.ID, 0); + itable_insert (&is->extra_defensive_bombards, bombarder->Body.ID, extra_dbs + 1); + } + + int damage_before = defender->Body.Damage; + Fighter_damage_by_defensive_bombard (this, __, bombarder, defender); + int damage_after = defender->Body.Damage; + + is->dbe.bombarder = bombarder; + is->dbe.defender = defender; + if (damage_after > damage_before) { + is->dbe.damage_done = true; + int max_hp = Unit_get_max_hp (defender); + int dead_before = damage_before >= max_hp, dead_after = damage_after >= max_hp; + + // If the unit was killed by defensive bombard, play its death animation then toggle off animations for the rest of the combat so it + // doesn't look like anything else happens. Technically, the combat continues and the dead unit is guarantted to lose because the + // patch to get_combat_odds ensures the dead unit has no chance of winning a round. + if (dead_before ^ dead_after) { + is->dbe.defender_was_destroyed = true; + if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (this, __, bombarder, defender, true)) + Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, defender, AT_DEATH, false); + is->dbe.saved_animation_setting = this->play_animations; + this->play_animations = 0; + } + } +} + +int __fastcall +patch_Fighter_get_odds_for_main_combat_loop (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses) +{ + if (is->dbe.defender_was_destroyed) + return 1025; + + struct c3x_config * cfg = &is->current_config; + if (cfg->enable_unit_counters && attacker != NULL && defender != NULL) { + Tile * def_tile = tile_at (this->defender_location_x, + this->defender_location_y); + int aa, dd; + bool ignore_terrain; + apply_counter_rules (cfg, attacker, defender, def_tile, + &aa, &dd, &ignore_terrain); + + is->counter_combat_ctx.active = true; + is->counter_combat_ctx.attacker = attacker; + is->counter_combat_ctx.defender = defender; + is->counter_combat_ctx.attacker_atk_pct = aa; + is->counter_combat_ctx.defender_def_pct = dd; + is->counter_combat_ctx.ignore_terrain = ignore_terrain; + } + + int result = Fighter_get_combat_odds (this, __, attacker, defender, bombarding, + ignore_defensive_bonuses || is->counter_combat_ctx.ignore_terrain); + is->counter_combat_ctx.active = false; + return result; +} + +// Civ 4-style best defender: On the specified tile, pick the defender that is hardest for the +// attacker to beat (i.e. the one with the highest *defender* win rate against the attacker). +// Takes unit counter rules into account. Returns NULL if there is no suitable defender. +// +// IMPORTANT — odds semantics: vanilla Fighter_get_combat_odds returns the *defender*'s win +// chance (out of ~1024), not the attacker's. Confirmed by the existing patch at +// patch_Fighter_get_odds_for_main_combat_loop: when the attacker has been killed by defensive +// bombardment ("defender_was_destroyed"), the patch returns 1025 so the still-running combat +// loop sees ~100% defender win chance and finishes off the doomed attacker. Therefore "hardest +// to beat" = "highest defender win chance" = max odds. +// +// Notes: +// - Skips units with Container_Unit >= 0 (units inside armies/transports; only the top unit represents the group). +// - Skips units not visible to the attacker's civ, avoiding revealing invisible units. +// - Skips units of the same civ as the attacker (they cannot defend). +// - Skips units with defense strength <= 0 (incapable of combat). +// - Temporarily overwrites is->counter_combat_ctx internally and saves/restores the context before/after execution, +// to avoid disrupting the actual combat odds context. +Unit * +find_civ4_best_defender_against (Unit * attacker, Tile * tile, int tile_x, int tile_y) +{ + if ((attacker == NULL) || (tile == NULL) || (tile == p_null_tile)) + return NULL; + + // Defensive: validate attacker shape before we deref any of its fields downstream. If the + // pointer is stale or refers to a half-initialized unit, UnitTypeID will be out of range and + // we bail out instead of crashing inside Fighter_get_combat_odds / vtable calls. + int atk_tid = attacker->Body.UnitTypeID; + if ((atk_tid < 0) || (atk_tid >= p_bic_data->UnitTypeCount)) + return NULL; + + struct c3x_config * cfg = &is->current_config; + int attacker_civ = attacker->Body.CivID; + + // Backup the current counter ctx, as we'll be repeatedly overwriting it within the loop. + bool saved_active = is->counter_combat_ctx.active; + Unit * saved_attacker = is->counter_combat_ctx.attacker; + Unit * saved_defender = is->counter_combat_ctx.defender; + int saved_attacker_atk = is->counter_combat_ctx.attacker_atk_pct; + int saved_defender_def = is->counter_combat_ctx.defender_def_pct; + bool saved_ignore_terrain = is->counter_combat_ctx.ignore_terrain; + + // Backup the live Fighter struct fields. Vanilla Fighter_get_combat_odds may consult + // fighter.attacker / fighter.defender / fighter.defender_location_x/y to fetch terrain or + // state; if those still point at units from a previous combat (or are NULL during init), the + // vanilla code can dereference garbage and crash. We point them at the current candidate + // inside the loop and restore the originals at the end. + Unit * saved_fighter_attacker = p_bic_data->fighter.attacker; + Unit * saved_fighter_defender = p_bic_data->fighter.defender; + int saved_fighter_atk_x = p_bic_data->fighter.attacker_location_x; + int saved_fighter_atk_y = p_bic_data->fighter.attacker_location_y; + int saved_fighter_def_x = p_bic_data->fighter.defender_location_x; + int saved_fighter_def_y = p_bic_data->fighter.defender_location_y; + + Unit * best = NULL; + // We track the maximum defender win rate. Start below any possible result so the first + // eligible candidate always becomes the initial best. + int best_odds = -1; + + FOR_UNITS_ON (uti, tile) { + Unit * d = uti.unit; + if ((d == NULL) || (d == attacker)) + continue; + // Defensive: a unit on the tile_units linked list with an out-of-range type id is almost + // certainly stale or in some half-initialized state — skip it entirely so we never pass it + // to anything that dereferences UnitType. + int dtid = d->Body.UnitTypeID; + if ((dtid < 0) || (dtid >= p_bic_data->UnitTypeCount)) + continue; + if (d->Body.Container_Unit >= 0) + continue; + if (d->Body.CivID == attacker_civ) + continue; + // Must be a true enemy of the attacker (allies/peace treaties). + if (! d->vtable->is_enemy_of_civ (d, __, attacker_civ, 0)) + continue; + if (Unit_get_defense_strength (d) <= 0) + continue; + if (! patch_Unit_is_visible_to_civ (d, __, attacker_civ, 0)) + continue; + + // Apply unit counter multipliers (100 if unit counters are disabled, equivalent to vanilla win rate formula). + int aa = 100, dd = 100; + bool ignore_terrain = false; + if (cfg->enable_unit_counters) + apply_counter_rules (cfg, attacker, d, tile, &aa, &dd, &ignore_terrain); + + is->counter_combat_ctx.active = true; + is->counter_combat_ctx.attacker = attacker; + is->counter_combat_ctx.defender = d; + is->counter_combat_ctx.attacker_atk_pct = aa; + is->counter_combat_ctx.defender_def_pct = dd; + is->counter_combat_ctx.ignore_terrain = ignore_terrain; + + // Point the live Fighter struct at the (attacker, d) pair so the vanilla odds function + // reads valid pointers instead of stale ones. + p_bic_data->fighter.attacker = attacker; + p_bic_data->fighter.defender = d; + p_bic_data->fighter.attacker_location_x = attacker->Body.X; + p_bic_data->fighter.attacker_location_y = attacker->Body.Y; + p_bic_data->fighter.defender_location_x = tile_x; + p_bic_data->fighter.defender_location_y = tile_y; + + // IMPORTANT: vanilla Fighter_get_combat_odds reads attack/defense values directly from + // UnitType.Attack and UnitType.Defence — it does NOT route through Unit_get_attack/defense_strength + // in a way that this mod has hooked (Unit_get_defense_strength is not registered in + // civ_prog_objects.csv as an inlead, so patch_Unit_get_defense_strength never gets called from + // inside vanilla odds computation). To make our counter multipliers actually affect the odds we + // compute here, we monkey-patch the UnitType fields for the duration of the call and restore + // them immediately after. This is single-threaded mod code and the call window is microseconds, + // so no other reader can observe the temporary values. + UnitType * a_type = &p_bic_data->UnitTypes[atk_tid]; + UnitType * d_type = &p_bic_data->UnitTypes[dtid]; + int saved_a_attack = a_type->Attack; + int saved_d_defence = d_type->Defence; + if (aa != 100) + a_type->Attack = (saved_a_attack * aa) / 100; + if (dd != 100) + d_type->Defence = (saved_d_defence * dd) / 100; + + int odds = Fighter_get_combat_odds (&p_bic_data->fighter, __, attacker, d, false, ignore_terrain); + + a_type->Attack = saved_a_attack; + d_type->Defence = saved_d_defence; + + // odds = defender's win chance (see comment above the function). We want the candidate + // that is hardest for the attacker to beat, i.e. the one with the *highest* odds. + bool replace; + if (best == NULL) { + replace = true; + } else if (odds > best_odds) { + replace = true; + } else if (odds < best_odds) { + replace = false; + } else { + // Odds tie. Defer to vanilla's own defender comparator (cheaper-cost-defends-first + // etc.) — but we must give it the *effective* defense of each candidate against + // this attacker, otherwise it would compare base defenses (e.g. Swordsman base 2 vs + // Musketman base 4) and pick Musketman immediately, never reaching the cost + // tie-break that should decide between two units that are effectively equally hard + // to beat (Swordsman with a x2 counter has effective def 4, equal to Musketman's + // base 4 — vanilla's tie-break should then prefer the cheaper Swordsman). + // + // We can't rely on counter_combat_ctx flowing through Unit_get_defense_strength + // here (see the long comment above the odds call: the patch isn't actually hooked + // into vanilla code). So we apply the multiplier ourselves on top of whatever + // Unit_get_defense_strength returns for each candidate. + int best_aa = 100, best_dd = 100; + bool best_ignore = false; + if (cfg->enable_unit_counters) + apply_counter_rules (cfg, attacker, best, tile, &best_aa, &best_dd, &best_ignore); + + int d_def = (Unit_get_defense_strength (d) * dd ) / 100; + int best_def = (Unit_get_defense_strength (best) * best_dd) / 100; + + replace = Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, + d, d_def, best, best_def, true); + } + if (replace) { + best = d; + best_odds = odds; + } + } + + is->counter_combat_ctx.active = saved_active; + is->counter_combat_ctx.attacker = saved_attacker; + is->counter_combat_ctx.defender = saved_defender; + is->counter_combat_ctx.attacker_atk_pct = saved_attacker_atk; + is->counter_combat_ctx.defender_def_pct = saved_defender_def; + is->counter_combat_ctx.ignore_terrain = saved_ignore_terrain; + + // Restore the live Fighter struct so we don't leave it pointing at our probe values when a + // real combat (or other code path that reads it) starts. + p_bic_data->fighter.attacker = saved_fighter_attacker; + p_bic_data->fighter.defender = saved_fighter_defender; + p_bic_data->fighter.attacker_location_x = saved_fighter_atk_x; + p_bic_data->fighter.attacker_location_y = saved_fighter_atk_y; + p_bic_data->fighter.defender_location_x = saved_fighter_def_x; + p_bic_data->fighter.defender_location_y = saved_fighter_def_y; + + return best; +} + +byte __fastcall +patch_Fighter_fight (Fighter * this, int edx, Unit * attacker, + int attack_direction, Unit * defender_or_null) +{ + // Civ 4-style best defender: compute the defender from the target tile (neighbor of the + // attacker) using counter-aware odds, then use that unit for combat. + // + // Vanilla usually *pre-resolves* a defender and passes it non-NULL. That selection uses base + // UnitType stats (and cost tie-breaks), not our counter rules — so combat could hit Musketman + // while Main_Screen_Form_find_visible_unit (which always calls find_civ4_best_defender_against) + // showed Swordsman. We therefore apply our pick whenever the attack is a normal 8-neighbor + // strike and either no defender was passed, or the passed defender still sits on the target + // tile (vanilla's stack defender). If vanilla passes a defender on some other tile, leave it + // alone (unusual / non-adjacent paths). + if (is->current_config.use_civ4_style_best_defender && + is->current_config.enable_unit_counters && + (attacker != NULL) && + // Strict guard: attack_direction must be a valid 8-neighbor index. Some non-combat code + // paths call Fighter_fight with sentinel values (-1 etc.); forwarding those into + // neighbor_index_to_diff would produce a junk target tile and crash. + (attack_direction >= 0) && (attack_direction < 8)) { + int dx = 0, dy = 0; + neighbor_index_to_diff (attack_direction, &dx, &dy); + // Belt-and-braces: dx/dy must lie on the 8-neighbor lattice. + if ((dx >= -1) && (dx <= 1) && (dy >= -1) && (dy <= 1) && ((dx != 0) || (dy != 0))) { + int target_x = attacker->Body.X + dx; + int target_y = attacker->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); + Tile * target_tile = tile_at (target_x, target_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + bool vanilla_defender_on_target = + (defender_or_null != NULL) && + (defender_or_null->Body.X == target_x) && + (defender_or_null->Body.Y == target_y); + if ((defender_or_null == NULL) || vanilla_defender_on_target) { + Unit * picked = find_civ4_best_defender_against (attacker, target_tile, target_x, target_y); + if (picked != NULL) + defender_or_null = picked; + } + } + } + } + + byte tr = Fighter_fight (this, __, attacker, attack_direction, + defender_or_null); + is->dbe = (struct defensive_bombard_event) {0}; + is->counter_combat_ctx.active = false; + return tr; +} + +int __fastcall +patch_Unit_get_attack_strength (Unit * this) +{ + int base = Unit_get_attack_strength (this); + if (! is->counter_combat_ctx.active) + return base; + if (this == is->counter_combat_ctx.attacker) + return base * is->counter_combat_ctx.attacker_atk_pct / 100; + return base; +} + +int __fastcall +patch_Unit_get_defense_strength (Unit * this) +{ + int base = Unit_get_defense_strength (this); + if (! is->counter_combat_ctx.active) + return base; + if (this == is->counter_combat_ctx.defender) + return base * is->counter_combat_ctx.defender_def_pct / 100; + return base; +} + +void __fastcall +patch_Unit_score_kill_by_defender (Unit * this, int edx, Unit * victim, bool was_attacking) +{ + // This function is called when the defender wins in combat. If the attacker was actually killed by defensive bombardment, then award credit + // for that kill to the defensive bombarder not the defender in combat. + if (is->dbe.defender_was_destroyed) { + is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; + Unit_score_kill (is->dbe.bombarder, __, victim, was_attacking); + is->do_not_enslave_units = false; + p_bic_data->fighter.play_animations = is->dbe.saved_animation_setting; + + } else + Unit_score_kill (this, __, victim, was_attacking); +} + +void __fastcall +patch_Unit_play_attack_anim_for_def_bombard (Unit * this, int edx, int direction) +{ + // Don't play any animation for air units, the animations are instead handled in the patch for damage_by_defensive_bombard + if (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) { + + // Make sure the unit is displayed if it's in an army and we're configured for that + struct unit_display_override saved_udo = is->unit_display_override; + Unit * container; + if (is->current_config.show_armies_performing_defensive_bombard && + (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && + Unit_has_ability (container, __, UTA_Army)) + is->unit_display_override = (struct unit_display_override) { this->Body.ID, this->Body.X, this->Body.Y }; + + Unit_play_attack_animation (this, __, direction); + + is->unit_display_override = saved_udo; + } +} + +bool +can_precision_strike_tile_improv_at (Unit * unit, int x, int y) +{ + Tile * tile; + return is->current_config.allow_precision_strikes_against_tile_improvements && // we're configured to allow prec. strikes vs tiles AND + ((tile = tile_at (x, y)) != p_null_tile) && // get tile, make sure it's valid AND + is_explored (tile, unit->Body.CivID) && // tile has been explored by attacker AND + has_any_destructible_overlays (tile, true); // it has something that can be destroyed by prec. strike +} + +// Same as above function except this one applies to the V3 field instead of FOWStatus +Tile * __cdecl +patch_tile_at_for_v3_check (int x, int y) +{ + Tile * tile = tile_at (x, y); + int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; + if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { + is->dummy_tile->Body.V3 = ((tile->Body.V3 & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; + return is->dummy_tile; + } else + return tile; +} + +bool __fastcall +patch_Unit_check_contact_bit_6_on_right_click (Unit * this, int edx, int civ_id) +{ + bool tr = Unit_check_contact_bit_6 (this, __, civ_id); + if ((! tr) && + is->current_config.share_visibility_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << civ_id) & *p_human_player_bits)) { // is civ_id a human player + if ((1 << this->Body.CivID) & *p_human_player_bits) + tr = true; + + else { + // Check if any other human player has contact + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != civ_id) && + Unit_check_contact_bit_6 (this, __, n_player)) { + tr = true; + break; + } + player_bits >>= 1; + n_player++; + } + } + } + return tr; +} + +bool __fastcall +patch_Unit_check_precision_strike_target (Unit * this, int edx, int tile_x, int tile_y) +{ + return Unit_check_precision_strike_target (this, __, tile_x, tile_y) || can_precision_strike_tile_improv_at (this, tile_x, tile_y); +} + +void __fastcall +patch_Unit_play_attack_animation_vs_tile (Unit * this, int edx, int direction) +{ + if (is->current_config.polish_precision_striking && + UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile) && + (is->attacking_tile_x != this->Body.X) && (is->attacking_tile_y != this->Body.Y)) + Unit_animate_cruise_missile_strike (this, __, is->attacking_tile_x, is->attacking_tile_y); + else + Unit_play_attack_animation (this, __, direction); +} + +void __fastcall +patch_Unit_attack_tile (Unit * this, int edx, int x, int y, int bombarding) +{ + Tile * target_tile = NULL; + bool had_district_before = false; + int district_id_before = -1; + int tile_x = x; + int tile_y = y; + + if (is->current_config.enable_districts) { + + // Check if this is a completed wonder district that cannot be destroyed + if (is->current_config.enable_wonder_districts && + !is->current_config.completed_wonder_districts_can_be_destroyed) { + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + target_tile = tile_at (tile_x, tile_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + struct wonder_district_info * info = get_wonder_district_info (target_tile); + if (info != NULL && info->state == WDS_COMPLETED) { + // This tile has a completed wonder district and they can't be destroyed + if (((*p_human_player_bits & (1 << this->Body.CivID)) != 0) && + (this->Body.CivID == p_main_screen_form->Player_CivID)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_PILLAGE", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + return; + } + } + } + + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + target_tile = tile_at (tile_x, tile_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (target_tile); + if (inst != NULL) { + had_district_before = true; + district_id_before = inst->district_id; + } + } + } + + is->attacking_tile_x = x; + is->attacking_tile_y = y; + if (bombarding) + is->unit_bombard_attacking_tile = this; + + Unit_attack_tile (this, __, x, y, bombarding); + + // Check if the district was destroyed by the attack + if (had_district_before && (target_tile != NULL) && (target_tile != p_null_tile) && district_id_before != NATURAL_WONDER_DISTRICT_ID) { + struct district_instance * inst_after = get_district_instance (target_tile); + bool has_district_after = (inst_after != NULL); + int district_id_after = (inst_after != NULL) ? inst_after->district_id : -1; + + // If the district existed before but not after, or the tile no longer has a mine, the district was destroyed + if (!has_district_after || !(target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & TILE_FLAG_MINE)) { + bool is_water_tile = target_tile != NULL && target_tile->vtable->m35_Check_Is_Water (target_tile); + handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, ! is_water_tile); + } + } + + is->unit_bombard_attacking_tile = NULL; + is->attacking_tile_x = is->attacking_tile_y = -1; +} + +void __fastcall +patch_Unit_do_precision_strike (Unit * this, int edx, int x, int y) +{ + if ((city_at (x, y) == NULL) && can_precision_strike_tile_improv_at (this, x, y)) + patch_Unit_attack_tile (this, __, x, y, 1); + else + Unit_do_precision_strike (this, __, x, y); + + if (is->current_config.polish_precision_striking && + UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile)) + patch_Unit_despawn (this, __, 0, false, false, 0, 0, 0, 0); +} + +int __fastcall +patch_Unit_get_max_moves_after_barricade_attack (Unit * this) +{ + if (is->current_config.dont_end_units_turn_after_bombarding_barricade && (this == is->unit_bombard_attacking_tile)) + return this->Body.Moves + p_bic_data->General.RoadsMovementRate; + else + return patch_Unit_get_max_move_points (this); +} + +City * __cdecl +patch_city_at_in_find_bombard_defender (int x, int y) +{ + // The caller (Fighter::find_defender_against_bombardment) has a set of lists of bombard priority/eligibility in its stack memory. The list + // for land units bombarding land tiles normally restricts the targets to land units by containing [UTC_Land, -1, -1]. If we're configured to + // remove that restriction, modify the list so it contains instead [UTC_Land, UTC_Sea, UTC_Air]. Conveniently, the offset from this function's + // first parameter to the list is 0x40 bytes in all executables. + if (is->current_config.remove_land_artillery_target_restrictions) { + enum UnitTypeClasses * list = (void *)((byte *)&x + 0x40); + list[1] = UTC_Sea; + list[2] = UTC_Air; + } + + return city_at (x, y); +} + +bool __fastcall +patch_Unit_check_bombard_target (Unit * this, int edx, int tile_x, int tile_y) +{ + bool base = Unit_check_bombard_target (this, __, tile_x, tile_y); + Tile * tile = tile_at (tile_x, tile_y); + int overlays; + + if (base && + itable_look_up_or (&is->current_config.can_bombard_only_sea_tiles, this->Body.UnitTypeID, 0) && + ! tile->vtable->m35_Check_Is_Water (tile)) + return false; + + else if (base && + is->current_config.disallow_useless_bombard_vs_airfields && + ! Unit_has_ability (this, __, UTA_Nuclear_Weapon) && + ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // if tile has an airfield AND + (overlays == 0x20000000)) { // tile only has an airfield + UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + + // Check that a bombard attack vs this tile would not be wasted. It won't be if either (1) there are no units on the tile, (2) there + // is a unit that can be damaged by bombarding, or (3) there are no units that can be damaged and no air units. The rules for + // bombardment are that you can't damage aircraft in an airfield and you also can't destroy an airfield from underneath aircraft. + int any_units = 0, + any_vulnerable_units = 0, + any_air_units = 0; + FOR_UNITS_ON (uti, tile) { + enum UnitTypeClasses class = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; + any_units = 1; + any_air_units |= class == UTC_Air; + any_vulnerable_units |= (class != UTC_Air) && (Unit_get_defense_strength (uti.unit) > 0) && + can_damage_bombarding (this_type, uti.unit, tile); + } + return (! any_units) || // case (1) above + any_vulnerable_units || // case (2) + ((! any_air_units) && (! any_vulnerable_units)); // case (3) + + } else + return base; +} + +bool __fastcall +patch_Unit_can_disembark_anything (Unit * this, int edx, int tile_x, int tile_y) +{ + Tile * this_tile = tile_at (this->Body.X, this->Body.Y); + Tile * target_tile = tile_at (tile_x, tile_y); + bool base = Unit_can_disembark_anything (this, __, tile_x, tile_y); + + // Apply units per tile limit + if (base) { + bool stack_limited_for_all = true; + FOR_UNITS_ON (uti, this_tile) + if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_below_stack_limit (target_tile, this->Body.CivID, uti.unit->Body.UnitTypeID)) { + stack_limited_for_all = false; + break; + } + if (stack_limited_for_all) + return false; + } + + // Apply trespassing restriction. First check if this civ may move into (tile_x, tile_y) without trespassing. If it would be trespassing, then + // we can only disembark anything if this transport has a passenger that can ignore the restriction. Without this check, the game can enter an + // infinite loop under rare circumstances. + if (base && + is->current_config.disallow_trespassing && + check_trespassing (this->Body.CivID, this_tile, target_tile)) { + bool any_exempt_passengers = false; + FOR_UNITS_ON (uti, this_tile) + if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_allowed_to_trespass (uti.unit)) { + any_exempt_passengers = true; + break; + } + return any_exempt_passengers; + + } else + return base; +} + +int __fastcall +patch_Unit_get_defense_for_bombardable_unit_check (Unit * this) +{ + // Returning a defense value of zero indicates this unit is not a target for bombardment. If configured, exclude all air units from + // bombardment so the attacks target tile improvements instead. Do this only if the tile has another improvement in addition to an airfield, + // or we could destroy the airfield itself. + Tile * tile; + int overlays; + if (is->current_config.allow_bombard_of_other_improvs_on_occupied_airfield && // If configured AND + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && // "this" is an air unit AND + ((tile = tile_at (this->Body.X, this->Body.Y)) != p_null_tile) && // "this" is on a valid tile AND + ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // tile has an airfield AND + (overlays != 0x20000000)) // tile does not only have an airfield + return 0; + + else + return Unit_get_defense_strength (this); +} + +void __fastcall +patch_Demographics_Form_m22_draw (Demographics_Form * this) +{ + Demographics_Form_m22_draw (this); + + if (is->current_config.show_total_city_count) { + // There's proably a better way to get the city count, but better safe than sorry. I don't know if it's possible for the city list to + // contain holes so the surest thing is to check every possible ID. + int city_count = 0; { + if (p_cities->Cities != NULL) + for (int n = 0; n <= p_cities->LastIndex; n++) { + City_Body * body = p_cities->Cities[n].City; + city_count += (body != NULL) && ((int)body != offsetof (City, Body)); + } + } + + PCX_Image * canvas = &this->Base.Data.Canvas; + + // Draw backdrop + { + char temp_path[2*MAX_PATH]; + PCX_Image backdrop; + PCX_Image_construct (&backdrop); + get_mod_art_path ("CityCountBackdrop.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&backdrop, __, temp_path, NULL, 0, 0x100, 2); + if (backdrop.JGL.Image != NULL) { + int w = backdrop.JGL.Image->vtable->m54_Get_Width (backdrop.JGL.Image); + PCX_Image_draw_onto (&backdrop, __, canvas, (1024 - w) / 2, 720); + } + backdrop.vtable->destruct (&backdrop, __, 0); + } + + // Draw text on top of the backdrop + char s[100]; + snprintf (s, sizeof s, "%s %d / %d", is->c3x_labels[CL_TOTAL_CITIES], city_count, is->city_limit); + s[(sizeof s) - 1] = '\0'; + PCX_Image_set_text_effects (canvas, __, 0x80000000, -1, 2, 2); // Set text color to black + PCX_Image_draw_centered_text (canvas, __, get_font (14, FSF_NONE), s, 1024/2 - 100, 730, 200, strlen (s)); + } +} + +int __fastcall +patch_Leader_get_optimal_city_number (Leader * this) +{ + if (! is->current_config.strengthen_forbidden_palace_ocn_effect) + return Leader_get_optimal_city_number (this); + else { + int num_sans_fp = Leader_get_optimal_city_number (this), // OCN w/o contrib from num of FPs + fp_count = patch_Leader_count_wonders_with_small_flag (this, __, ITSW_Reduces_Corruption, NULL), + s_diff = p_bic_data->DifficultyLevels[this->player_difficulty].Optimal_Cities, // Difficulty scaling, called "percentage of optimal cities" in the editor + base_ocn = p_bic_data->WorldSizes[p_bic_data->Map.World.World_Size].OptimalCityCount; + return num_sans_fp + (s_diff * fp_count * base_ocn + 50) / 100; // Add 50 to round off + } +} + +int __fastcall +patch_Leader_count_forbidden_palaces_for_ocn (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) +{ + if (! is->current_config.strengthen_forbidden_palace_ocn_effect) + return patch_Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); + else + return 0; // We'll add in the FP effect later with a different weight +} + +void __fastcall +patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id) +{ + is->is_computing_city_connections = true; + long long ts_before; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); + + if (is->tnx_init_state == IS_OK) { + if (is->tnx_cache == NULL) { + is->tnx_cache = is->create_tnx_cache (&p_bic_data->Map); + is->set_up_before_building_network (is->tnx_cache); + } else if (! is->keep_tnx_cache) + is->set_up_before_building_network (is->tnx_cache); + } + + Trade_Net_recompute_city_connections (this, __, civ_id, redo_road_network, param_3, redo_roads_for_city_id); + + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; + + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + is->time_spent_computing_city_connections += ts_after - ts_before; + is->count_calls_to_recompute_city_connections++; + is->is_computing_city_connections = false; +} + +void __fastcall +patch_Map_build_trade_network (Map * this) +{ + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) + is->set_up_before_building_network (is->tnx_cache); + is->keep_tnx_cache = true; + Map_build_trade_network (this); + is->keep_tnx_cache = false; + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; +} + +void __fastcall +patch_Trade_Net_recompute_city_cons_and_res (Trade_Net * this, int edx, bool param_1) +{ + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) + is->set_up_before_building_network (is->tnx_cache); + + is->keep_tnx_cache = true; + Trade_Net_recompute_city_cons_and_res (this, __, param_1); + is->keep_tnx_cache = false; + + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; +} + +int __fastcall +patch_Trade_Net_set_unit_path_to_fill_road_net (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) +{ + int tr; + long long ts_before; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); + + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { + is->flood_fill_road_network (is->tnx_cache, from_x, from_y, civ_id); + tr = 0; // Return value is not used by caller anyway + } else + tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); + + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + is->time_spent_filling_roads += ts_after - ts_before; + return tr; +} + +bool +set_up_gdi_plus () +{ + if (is->gdi_plus.init_state == IS_UNINITED) { + is->gdi_plus.init_state = IS_INIT_FAILED; + is->gdi_plus.gp_graphics = NULL; + + struct startup_input { + UINT32 GdiplusVersion; + void * DebugEventCallback; + BOOL SuppressBackgroundThread; + BOOL SuppressExternalCodecs; + } startup_input = {1, NULL, FALSE, FALSE}; + + is->gdi_plus.module = LoadLibraryA ("gdiplus.dll"); + if (is->gdi_plus.module == NULL) { + MessageBoxA (NULL, "Failed to load gdiplus.dll!", "Error", MB_ICONERROR); + goto end_init; + } + + int (WINAPI * GdiplusStartup) (ULONG_PTR * out_token, struct startup_input *, void * startup_output) = + (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdiplusStartup"); + + is->gdi_plus.CreateFromHDC = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreateFromHDC"); + is->gdi_plus.DeleteGraphics = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeleteGraphics"); + is->gdi_plus.SetSmoothingMode = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetSmoothingMode"); + is->gdi_plus.SetPenDashStyle = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetPenDashStyle"); + is->gdi_plus.CreatePen1 = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreatePen1"); + is->gdi_plus.DeletePen = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeletePen"); + is->gdi_plus.DrawLineI = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDrawLineI"); + if ((is->gdi_plus.CreateFromHDC == NULL) || (is->gdi_plus.DeleteGraphics == NULL) || + (is->gdi_plus.SetSmoothingMode == NULL) || (is->gdi_plus.SetPenDashStyle == NULL) || + (is->gdi_plus.CreatePen1 == NULL) || (is->gdi_plus.DeletePen == NULL) || + (is->gdi_plus.DrawLineI == NULL)) { + MessageBoxA (NULL, "Failed to get GDI+ proc addresses!", "Error", MB_ICONERROR); + goto end_init; + } + + int status = GdiplusStartup (&is->gdi_plus.token, &startup_input, NULL); + if (status != 0) { + char s[200]; + snprintf (s, sizeof s, "Failed to initialize GDI+! Startup status: %d", status); + MessageBoxA (NULL, s, "Error", MB_ICONERROR); + goto end_init; + } + + is->gdi_plus.init_state = IS_OK; + end_init: + ; + } + + return is->gdi_plus.init_state == IS_OK; +} + +int __fastcall +patch_OpenGLRenderer_initialize (OpenGLRenderer * this, int edx, PCX_Image * texture) +{ + if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || + ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) + return OpenGLRenderer_initialize (this, __, texture); + + // Initialize GDI+ instead + else { + if (! set_up_gdi_plus ()) + return 2; + if (is->gdi_plus.gp_graphics != NULL) { + is->gdi_plus.DeleteGraphics (is->gdi_plus.gp_graphics); + is->gdi_plus.gp_graphics = NULL; + } + int status = is->gdi_plus.CreateFromHDC (texture->JGL.Image->DC, &is->gdi_plus.gp_graphics); + if (status == 0) { + is->gdi_plus.SetSmoothingMode (is->gdi_plus.gp_graphics, 4); // 4 = SmoothingModeAntiAlias from GdiPlusEnums.h + return 0; + } else + return 2; + } +} + +void __fastcall +patch_OpenGLRenderer_set_color (OpenGLRenderer * this, int edx, unsigned int rgb555) +{ + // Convert rgb555 to rgb888 + unsigned int rgb888 = 0; { + unsigned int mask = 31; + int shift = 3; + for (int n = 0; n < 3; n++) { + rgb888 |= (rgb555 & mask) << shift; + mask <<= 5; + shift += 3; + } + } + + is->ogl_color = (is->ogl_color & 0xFF000000) | rgb888; + OpenGLRenderer_set_color (this, __, rgb555); +} + +void __fastcall +patch_OpenGLRenderer_set_opacity (OpenGLRenderer * this, int edx, unsigned int alpha) +{ + is->ogl_color = (is->ogl_color & 0x00FFFFFF) | (alpha << 24); + OpenGLRenderer_set_opacity (this, __, alpha); +} + +void __fastcall +patch_OpenGLRenderer_set_line_width (OpenGLRenderer * this, int edx, int width) +{ + is->ogl_line_width = width; + OpenGLRenderer_set_line_width (this, __, width); +} + +void __fastcall +patch_OpenGLRenderer_enable_line_dashing (OpenGLRenderer * this) +{ + is->ogl_line_stipple_enabled = true; + OpenGLRenderer_enable_line_dashing (this); +} + +void __fastcall +patch_OpenGLRenderer_disable_line_dashing (OpenGLRenderer * this) +{ + is->ogl_line_stipple_enabled = false; + OpenGLRenderer_disable_line_dashing (this); +} + +void __fastcall +patch_OpenGLRenderer_draw_line (OpenGLRenderer * this, int edx, int x1, int y1, int x2, int y2) +{ + if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || + ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) + OpenGLRenderer_draw_line (this, __, x1, y1, x2, y2); + + else if ((is->gdi_plus.init_state == IS_OK) && (is->gdi_plus.gp_graphics != NULL)) { + void * gp_pen; + int unit_world = 0; // = UnitWorld from gdiplusenums.h + int status = is->gdi_plus.CreatePen1 (is->ogl_color, (float)is->ogl_line_width, unit_world, &gp_pen); + if (status == 0) { + if (is->ogl_line_stipple_enabled) + is->gdi_plus.SetPenDashStyle (gp_pen, 1); // 1 = DashStyleDash from GdiPlusEnums.h + is->gdi_plus.DrawLineI (is->gdi_plus.gp_graphics, gp_pen, x1, y1, x2, y2); + is->gdi_plus.DeletePen (gp_pen); + } + } +} + +int __fastcall +patch_Tile_check_water_for_retreat_on_defense (Tile * this) +{ + Unit * defender = p_bic_data->fighter.defender; + + // Under the standard game rules, defensively retreating onto a water tile is not allowed. Set retreat_blocked to true if "this" is a water + // tile and we're not configured to allow retreating onto water tiles. + bool retreat_blocked; { + if (this->vtable->m35_Check_Is_Water (this)) { + if ( is->current_config.allow_defensive_retreat_on_water + && defender != NULL + && p_bic_data->UnitTypes[defender->Body.UnitTypeID].Unit_Class == UTC_Sea + && ( is->current_config.limit_defensive_retreat_on_water_to_types.len == 0 + || (bool)itable_look_up_or (&is->current_config.limit_defensive_retreat_on_water_to_types, defender->Body.UnitTypeID, 0))) + retreat_blocked = false; + else + retreat_blocked = true; + } else + retreat_blocked = false; + } + + // Check stack limit + if ((! retreat_blocked) && + (defender != NULL) && + ! is_below_stack_limit (this, defender->Body.CivID, defender->Body.UnitTypeID)) + retreat_blocked = true; + + // The return from this call is only used to filter the given tile as a possible retreat destination based on whether it's water or not + return (int)retreat_blocked; +} + +int __fastcall +patch_City_count_airports_for_airdrop (City * this, int edx, enum ImprovementTypeFlags airport_flag) +{ + if (is->current_config.allow_airdrop_without_airport) + return 1; + else + return City_count_improvements_with_flag (this, __, airport_flag); +} + +int __fastcall +patch_Leader_get_cont_city_count_for_worker_req (Leader * this, int edx, int cont_id) +{ + int tr = Leader_get_city_count_on_continent (this, __, cont_id); + if (is->current_config.ai_worker_requirement_percent != 100) + tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; + return tr; +} + +int __fastcall +patch_Leader_get_city_count_for_worker_prod_cap (Leader * this) +{ + int tr = this->Cities_Count; + // Don't scale down the cap since it's pretty low to begin with + if (is->current_config.ai_worker_requirement_percent > 100) + tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; + return tr; +} + +// If "only_improv_id" is >= 0, will only return yields from mills attached to that improv, otherwise returns all yields from all improvs +void +gather_mill_yields (City * city, int only_improv_id, int * out_food, int * out_shields, int * out_commerce) +{ + int food = 0, shields = 0, commerce = 0; + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if ((mill->flags & MF_YIELDS) && + ((only_improv_id < 0) || (mill->improv_id == only_improv_id)) && + can_generate_resource (city->Body.CivID, mill) && + has_active_building (city, mill->improv_id) && + has_resources_required_by_building (city, mill->improv_id)) { + Resource_Type * res = &p_bic_data->ResourceTypes[mill->resource_id]; + food += res->Food; + shields += res->Shield; + commerce += res->Commerce; + } + } + *out_food = food; + *out_shields = shields; + *out_commerce = commerce; +} + +int __fastcall +patch_City_calc_tile_yield_while_gathering (City * this, int edx, YieldKind kind, int tile_x, int tile_y) +{ + int tr = City_calc_tile_yield_at (this, __, kind, tile_x, tile_y); + + // Include yields from generated resources + if ((this->Body.X == tile_x) && (this->Body.Y == tile_y)) { + int mill_food, mill_shields, mill_commerce; + gather_mill_yields (this, -1, &mill_food, &mill_shields, &mill_commerce); + if (kind == YK_FOOD) tr += mill_food; + else if (kind == YK_SHIELDS) tr += mill_shields; + else if (kind == YK_COMMERCE) tr += mill_commerce; + + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + int bonus_food = 0, bonus_shields = 0, bonus_gold = 0; + calculate_city_center_district_bonus (this, &bonus_food, &bonus_shields, &bonus_gold); + if (kind == YK_FOOD) tr += bonus_food; + else if (kind == YK_SHIELDS) tr += bonus_shields; + else if (kind == YK_COMMERCE) tr += bonus_gold; + } + } + + return tr; +} + +bool __fastcall +patch_Leader_record_export (Leader * this, int edx, int importer_civ_id, int resource_id) +{ + bool exported = Leader_record_export (this, __, importer_civ_id, resource_id); + if (exported && + (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill + is->must_recompute_resources_for_mill_inputs = true; + return exported; +} + +bool __fastcall +patch_Leader_erase_export (Leader * this, int edx, int importer_civ_id, int resource_id) +{ + bool erased = Leader_erase_export (this, __, importer_civ_id, resource_id); + if (erased && + (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill + is->must_recompute_resources_for_mill_inputs = true; + return erased; +} + +int __fastcall +patch_Sprite_draw_improv_img_on_city_form (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int tr = Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); + + int generated_resources[16]; + int generated_resource_count = 0; + for (int n = 0; (n < is->current_config.count_mills) && (generated_resource_count < ARRAY_LEN (generated_resources)); n++) { + struct mill * mill = &is->current_config.mills[n]; + if ((mill->improv_id == is->drawing_icons_for_improv_id) && + ((mill->flags & MF_SHOW_BONUS) || (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus)) && + (! ((mill->flags & MF_HIDE_NON_BONUS) && (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus))) && + can_generate_resource (p_city_form->CurrentCity->Body.CivID, mill) && + has_active_building (p_city_form->CurrentCity, mill->improv_id) && + has_resources_required_by_building (p_city_form->CurrentCity, mill->improv_id)) + generated_resources[generated_resource_count++] = mill->resource_id; + } + + if ((generated_resource_count > 0) && (is->resources_sheet != NULL) && (is->resources_sheet->JGL.Image != NULL) && (TransparentBlt != NULL)) { + JGL_Image * jgl_canvas = canvas->JGL.Image, + * jgl_sheet = is->resources_sheet->JGL.Image; + + HDC canvas_dc = jgl_canvas->vtable->acquire_dc (jgl_canvas); + if (canvas_dc != NULL) { + HDC sheet_dc = jgl_sheet->vtable->acquire_dc (jgl_sheet); + if (sheet_dc != NULL) { + + for (int n = 0; n < generated_resource_count; n++) { + int icon_id = p_bic_data->ResourceTypes[generated_resources[n]].IconID, + sheet_row = icon_id / 6, + sheet_col = icon_id % 6; + + int dy = (n * 160 / not_below (1, generated_resource_count - 1) + 5) / 10; + TransparentBlt (canvas_dc, // dest DC + pixel_x + 15, pixel_y + dy, 24, 24, // dest x, y, width, height + sheet_dc, // src DC + 9 + 50*sheet_col, 9 + 50*sheet_row, 33, 33, // src x, y, width, height + 0xFF00FF); // transparent color (RGB) + } + + jgl_sheet->vtable->release_dc (jgl_sheet, __, 1); + } + jgl_canvas->vtable->release_dc (jgl_canvas, __, 1); + } + } + return tr; +} + +void __cdecl +patch_draw_improv_icons_on_city_screen (Base_List_Control * control, int improv_id, int item_index, int offset_x, int offset_y) +{ + is->drawing_icons_for_improv_id = improv_id; + draw_improv_icons_on_city_screen (control, improv_id, item_index, offset_x, offset_y); + is->drawing_icons_for_improv_id = -1; +} + +int __fastcall +patch_City_get_tourism_amount_to_draw (City * this, int edx, int improv_id) +{ + is->tourism_icon_counter = 0; + + int mill_food, mill_shields, mill_commerce; + gather_mill_yields (this, improv_id, &mill_food, &mill_shields, &mill_commerce); + int combined_commerce = mill_commerce + City_get_tourism_amount (this, __, improv_id); + + is->convert_displayed_tourism_to_food = mill_food; + is->convert_displayed_tourism_to_shields = mill_shields; + is->combined_tourism_and_mill_commerce = combined_commerce; + return int_abs (mill_food) + int_abs (mill_shields) + int_abs (combined_commerce); +} + +int __fastcall +patch_Sprite_draw_tourism_gold (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + // Replace the yield sprite we're drawing with food or a shield if needed. + Sprite * sprite = NULL; { + if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food)) { + if (is->convert_displayed_tourism_to_food >= 0) + sprite = &p_city_form->City_Icons_Images.Icon_15_Food; + else { + init_red_food_icon (); + if (is->red_food_icon_state == IS_OK) + sprite = &is->red_food_icon; + } + } else if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food) + int_abs (is->convert_displayed_tourism_to_shields)) + sprite = (is->convert_displayed_tourism_to_shields >= 0) ? &p_city_form->City_Icons_Images.Icon_13_Shield : &p_city_form->City_Icons_Images.Icon_05_Shield_Outcome; + else if (is->combined_tourism_and_mill_commerce < 0) + sprite = &p_city_form->City_Icons_Images.Icon_17_Gold_Outcome; + else + sprite = this; + } + + int tr = 0; // return value is not used by caller + if (sprite != NULL) + tr = Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, color_table); + is->tourism_icon_counter++; + return tr; +} + +Unit * __fastcall +patch_Leader_spawn_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) +{ + int spawn_x = tile_x, + spawn_y = tile_y; + + if (is->current_config.enable_districts) { + UnitType * type = &p_bic_data->UnitTypes[type_id]; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities) { + City * spawn_city = city_at (tile_x, tile_y); + if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { + int district_x, district_y; + Tile * district_tile = get_completed_district_tile_for_city (spawn_city, AERODROME_DISTRICT_ID, &district_x, &district_y); + if ((district_tile != NULL) && (district_tile != p_null_tile) && + (district_tile->Territory_OwnerID == this->ID) && + is_below_stack_limit (district_tile, this->ID, type_id)) { + spawn_x = district_x; + spawn_y = district_y; + } + } + } + + if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities) { + City * spawn_city = city_at (tile_x, tile_y); + if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { + int district_x, district_y; + Tile * district_tile = get_completed_district_tile_for_city (spawn_city, PORT_DISTRICT_ID, &district_x, &district_y); + if ((district_tile != NULL) && (district_tile != p_null_tile) && + (district_tile->Territory_OwnerID == this->ID) && + is_below_stack_limit (district_tile, this->ID, type_id)) { + spawn_x = district_x; + spawn_y = district_y; + } + } + } + } + + Unit * tr = Leader_spawn_unit (this, __, type_id, spawn_x, spawn_y, barb_tribe_id, id, param_6, leader_kind, race_id); + if (tr != NULL) + change_unit_type_count (this, type_id, 1); + return tr; +} + +Unit * __fastcall +patch_Leader_spawn_captured_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) +{ + Unit * tr = patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); + if ((tr != NULL) && is->moving_unit_to_adjacent_tile) + is->temporarily_disallow_lethal_zoc = true; + return tr; +} + +void __fastcall +patch_Leader_enter_new_era (Leader * this, int edx, bool param_1, bool no_online_sync) +{ + Leader_enter_new_era (this, __, param_1, no_online_sync); + apply_era_specific_names (this); +} + +char * __fastcall +patch_Leader_get_player_title_for_intro_popup (Leader * this) +{ + // Normally the era-specific names are applied later, after game loading is finished, but in this case we apply the player's names ahead of + // time so they appear on the intro popup. "this" will always refer to the human player in this call. + apply_era_specific_names (this); + return Leader_get_title (this); +} + +void __fastcall +patch_City_spawn_unit_if_done (City * this) +{ + bool skip_spawn = false; + + // Apply unit limit. If this city's owner has reached the limit for the unit type it's building then force it to build something else. + int available; + if ((this->Body.Order_Type == COT_Unit) && + get_available_unit_count (&leaders[this->Body.CivID], this->Body.Order_ID, &available) && + (available <= 0)) { + int limited_unit_type_id = this->Body.Order_ID; + + if (*p_human_player_bits & 1<Body.CivID) { + // Find another type ID to build instead of the limited one + int replacement_type_id = -1; { + int limited_unit_strat = p_bic_data->UnitTypes[limited_unit_type_id].AI_Strategy, + shields_in_box = this->Body.StoredProduction; + UnitType * replacement_type; + for (int can_type_id = 0; can_type_id < p_bic_data->UnitTypeCount; can_type_id++) + if (patch_City_can_build_unit (this, __, can_type_id, 1, 0, 0)) { + UnitType * candidate_type = &p_bic_data->UnitTypes[can_type_id]; + + // If we haven't found a replacement yet, use this one + if (replacement_type_id < 0) { + replacement_type_id = can_type_id; + replacement_type = candidate_type; + + // Keep the prev replacement if it doesn't waste shields but this candidate would + } else if ((replacement_type->Cost >= shields_in_box) && (candidate_type->Cost < shields_in_box)) + continue; + + // Keep the prev if it shares an AI strategy with the limited unit but this candidate doesn't + else if (((replacement_type->AI_Strategy & limited_unit_strat) != 0) && + ((candidate_type ->AI_Strategy & limited_unit_strat) == 0)) + continue; + + // At this point we know switching to the candidate would not cause us to waste shields and would not + // give us a worse match role-wise to the original limited unit. So pick it if it's better somehow, + // either a better role match or more expensive. + else if ((candidate_type->Cost > replacement_type->Cost) || + (((replacement_type->AI_Strategy & limited_unit_strat) == 0) && + ((candidate_type ->AI_Strategy & limited_unit_strat) != 0))) { + replacement_type_id = can_type_id; + replacement_type = candidate_type; + } + } + } + + if (replacement_type_id >= 0) { + City_set_production (this, __, COT_Unit, replacement_type_id, false); + if (this->Body.CivID == p_main_screen_form->Player_CivID) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, this->Body.CityName, -1, -1); + set_popup_str_param (1, p_bic_data->UnitTypes[limited_unit_type_id].Name, -1, -1); + int limit = -1; + get_unit_limit (&leaders[this->Body.CivID], limited_unit_type_id, &limit); + set_popup_int_param (2, limit); + set_popup_str_param (3, p_bic_data->UnitTypes[replacement_type_id].Name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_LIMITED_UNIT_CHANGE", -1, 0, 0, 0); + int response = patch_show_popup (popup, __, 0, 0); + if (response == 0) + *p_zoom_to_city_after_update = true; + } + } + + } else { + City_Order order; + patch_City_ai_choose_production (this, __, &order); + City_set_production (this, __, order.OrderType, order.OrderID, false); + } + + // If the player changed production to something other than a unit, don't spawn anything + if (this->Body.Order_Type != COT_Unit) + skip_spawn = true; + + // Just as a final check, if we weren't able to switch production off the limited unit, prevent it from being spawned so the limit + // doesn't get violated. + if ((this->Body.Order_Type == COT_Unit) && (this->Body.Order_ID == limited_unit_type_id)) + skip_spawn = true; + } + + // Check district requirements for air and naval units + if ((! skip_spawn) && (this->Body.Order_Type == COT_Unit) && is->current_config.enable_districts) { + int unit_id = this->Body.Order_ID; + UnitType * type = &p_bic_data->UnitTypes[unit_id]; + bool needs_district = false; + int required_district_id = -1; + + // Air units require aerodrome + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (this, AERODROME_DISTRICT_ID))) { + needs_district = true; + required_district_id = AERODROME_DISTRICT_ID; + } + // Naval units require port + else if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (this, PORT_DISTRICT_ID))) { + needs_district = true; + required_district_id = PORT_DISTRICT_ID; + } + + if (needs_district) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + + // For AI, redirect to a safe fallback and queue the missing district. + // For humans, this late hook should only veto the spawn and show a warning, + // otherwise the city gets switched off the intended build with no unit spawned. + if (! is_human) { + mark_city_needs_district (this, required_district_id); + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (this, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + // Show message to human player + if (is_human && (this->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[160]; + char const * unit_name = type->Name; + char const * district_name = is->district_configs[required_district_id].name; + snprintf (msg, sizeof msg, "%s %s %s", unit_name, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_name); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (this->Body.X, this->Body.Y, msg, true); + } + + skip_spawn = true; + } + } + + if (! skip_spawn) + City_spawn_unit_if_done (this); +} + +void __fastcall +patch_Leader_upgrade_all_units (Leader * this, int edx, int type_id) +{ + is->penciled_in_upgrade_count = 0; + Leader_upgrade_all_units (this, __, type_id); +} + +void __fastcall +patch_Main_Screen_Form_upgrade_all_units (Main_Screen_Form * this, int edx, int type_id) +{ + is->penciled_in_upgrade_count = 0; + Main_Screen_Form_upgrade_all_units (this, __, type_id); +} + +bool __fastcall +patch_Unit_can_perform_upgrade_all (Unit * this, int edx, int unit_command_value) +{ + bool base = patch_Unit_can_perform_command (this, __, unit_command_value); + + // Deal with unit limits. If the unit type we're upgrading to is limited, we need to pencil in the upgrade to make sure that we don't queue up + // so many upgrades that we exceed the limit. + City * city; + int upgrade_id, available; + if (base && + (is->current_config.unit_limits.len > 0) && + (NULL != (city = city_at (this->Body.X, this->Body.Y))) && + (0 <= (upgrade_id = City_get_upgraded_type_id (city, __, this->Body.UnitTypeID))) && + get_available_unit_count (&leaders[this->Body.CivID], upgrade_id, &available)) { + + // Find penciled in upgrade. Add a new one if we don't already have one. + struct penciled_in_upgrade * piu = NULL; { + for (int n = 0; n < is->penciled_in_upgrade_count; n++) + if (is->penciled_in_upgrades[n].unit_type_id == upgrade_id) { + piu = &is->penciled_in_upgrades[n]; + break; + } + if (piu == NULL) { + reserve (sizeof is->penciled_in_upgrades[0], (void **)&is->penciled_in_upgrades, &is->penciled_in_upgrade_capacity, is->penciled_in_upgrade_count); + piu = &is->penciled_in_upgrades[is->penciled_in_upgrade_count]; + is->penciled_in_upgrade_count += 1; + piu->unit_type_id = upgrade_id; + piu->count = 0; + } + } + + // If we can have more units of the type we're upgrading to, pencil in another upgrade and return true. Otherwise return false so this + // unit isn't considered one of the upgradable ones. + if (piu->count < available) { + piu->count += 1; + return true; + } else + return false; + + } else + return base; +} + +void __fastcall +patch_Fighter_animate_start_of_combat (Fighter * this, int edx, Unit * attacker, Unit * defender) +{ + // Temporarily clear the attacker retreat eligibility flag when needed so naval units are rotated and animated properly. Normally the game + // does not use ranged animations when the attacker can retreat and, worse, not using ranged anims means it also ignores the + // rotate-before-attack setting. + bool restore_attacker_retreat_eligibility = false; + if ((is->current_config.sea_retreat_rules != RR_STANDARD) && + (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Sea) && + Unit_has_ability (attacker, __, UTA_Ranged_Attack_Animation) && + Unit_has_ability (defender, __, UTA_Ranged_Attack_Animation) && + this->attacker_eligible_to_retreat) { + this->attacker_eligible_to_retreat = false; + restore_attacker_retreat_eligibility = true; + } + + Fighter_animate_start_of_combat (this, __, attacker, defender); + + if (restore_attacker_retreat_eligibility) + this->attacker_eligible_to_retreat = true; +} + +Unit * __fastcall +patch_Leader_spawn_unit_from_building (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) +{ + int available; + if (get_available_unit_count (this, type_id, &available) && (available <= 0)) + return NULL; + else + return patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); +} + +int __fastcall +patch_City_count_improvs_enabling_upgrade (City * this, int edx, enum ImprovementTypeFlags flag) +{ + return is->current_config.allow_upgrades_in_any_city ? 1 : City_count_improvements_with_flag (this, __, flag); +} + +City * __fastcall +patch_Leader_create_city_from_hut (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_POPPED_FROM_HUT); + return tr; +} + +City * __fastcall +patch_Leader_create_city_for_ai_respawn (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_PLACED_FOR_AI_RESPAWN); + return tr; +} + +City * __fastcall +patch_Leader_create_city_for_founding (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_FOUNDED); + return tr; +} + +City * __fastcall +patch_Leader_create_city_for_scenario (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_PLACED_FOR_SCENARIO); + return tr; +} + +City * +find_city_to_inherit_shared_small_wonder (Leader * leader, int wonder_improv_id) +{ + if ((leader == NULL) || + (! is->current_config.enable_districts) || + (! is->current_config.enable_wonder_districts) || + (! is->current_config.cities_with_mutual_district_receive_wonders)) + return NULL; + + FOR_CITIES_OF (coi, leader->ID) { + City * city = coi.city; + if ((city == NULL) || (! patch_City_has_improvement (city, __, wonder_improv_id, false))) + continue; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + Tile * tile = wai.tile; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if ((info == NULL) || (info->state != WDS_COMPLETED)) + continue; + + int nearby_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); + if (nearby_improv_id == wonder_improv_id) + return city; + } + } + + return NULL; +} + +void +collect_small_wonders_present_in_city (City * city, int * lost_small_wonders, int * lost_small_wonder_count, int max_lost_small_wonders) +{ + if ((city == NULL) || + (lost_small_wonders == NULL) || + (lost_small_wonder_count == NULL) || + (max_lost_small_wonders <= 0)) + return; + + *lost_small_wonder_count = 0; + + if (! is->current_config.enable_districts || + ! is->current_config.enable_wonder_districts || + ! is->current_config.cities_with_mutual_district_receive_wonders) + return; + + for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) == 0) + continue; + if (! patch_City_has_improvement (city, __, improv_id, false)) + continue; + if (*lost_small_wonder_count >= max_lost_small_wonders) + break; + lost_small_wonders[(*lost_small_wonder_count)++] = improv_id; + } +} + +void +reassign_shared_small_wonder_owners_after_city_loss (Leader * leader, int const * lost_small_wonders, int lost_small_wonder_count) +{ + if ((! is->current_config.enable_districts) || + (leader == NULL) || + (! is->current_config.enable_wonder_districts) || + (! is->current_config.cities_with_mutual_district_receive_wonders) || + (lost_small_wonders == NULL) || + (lost_small_wonder_count <= 0)) + return; + + for (int n = 0; n < lost_small_wonder_count; n++) { + int improv_id = lost_small_wonders[n]; + if ((improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) + continue; + + if (leader->Small_Wonders[improv_id] != -1) + continue; + + // Vanilla clears Leader.Small_Wonders when the recorded owner city loses the building during + // capture. Only repair the small wonders that were actually present in the lost city before + // capture, and if another city of the same civ still legitimately shares the wonder district, + // promote that city to be the new canonical owner so the small wonder's effects still work. + City * replacement = find_city_to_inherit_shared_small_wonder (leader, improv_id); + if (replacement != NULL) + leader->Small_Wonders[improv_id] = replacement->Body.ID; + } +} + +bool __fastcall +patch_Leader_do_capture_city (Leader * this, int edx, City * city, bool involuntary, bool converted) +{ + Leader * previous_owner = &leaders[city->Body.CivID]; + int lost_small_wonders[32]; + int lost_small_wonder_count; + + // Record which small wonders were physically present in the city before capture so any + // post-capture ownership repair only touches wonders actually affected. + collect_small_wonders_present_in_city (city, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); + + is->currently_capturing_city = city; + on_lose_city (previous_owner, city, converted ? CLR_CONVERTED : (involuntary ? CLR_CONQUERED : CLR_TRADED)); + bool tr = Leader_do_capture_city (this, __, city, involuntary, converted); + + // The game clears the losing civ's canonical Small_Wonders owner when the recorded city loses + // the building. Reassign that ownership here if another same-civ city still legitimately shares the wonder district. + if (is->current_config.enable_districts && + is->current_config.enable_wonder_districts && + is->current_config.cities_with_mutual_district_receive_wonders && + lost_small_wonder_count > 0) { + reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); + } + + on_gain_city (this, city, converted ? CGR_CONVERTED : (involuntary ? CGR_CONQUERED : CGR_TRADED)); + is->currently_capturing_city = NULL; + return tr; +} + +void __fastcall +patch_City_raze (City * this, int edx, int civ_id_responsible, bool checking_elimination) +{ + Leader * previous_owner = &leaders[this->Body.CivID]; + int lost_small_wonders[32]; + int lost_small_wonder_count; + + collect_small_wonders_present_in_city (this, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); + on_lose_city (previous_owner, this, CLR_DESTROYED); + City_raze (this, __, civ_id_responsible, checking_elimination); + + if (lost_small_wonder_count > 0) + reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); + + // Delete the extra improvement bits records for this city + City_Improvements * improv_lists[2] = {&this->Body.Improvements_1, &this->Body.Improvements_2}; + for (int n = 0; n < ARRAY_LEN (improv_lists); n++) { + City_Improvements * improv_list = improv_lists[n]; + byte * extra_bits; + if (itable_look_up (&is->extra_city_improvs, (int)improv_list, (int *)&extra_bits)) { + free (extra_bits); + itable_remove (&is->extra_city_improvs, (int)improv_list); + } + } +} + +void __fastcall +patch_City_draw_hud_icon (City * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y) +{ + Leader * owner = &leaders[this->Body.CivID]; + int restore_capital = owner->CapitalID; + + // Temporarily set this city as the capital if it has an extra palace so it gets the capital star icon + if ((is->current_config.ai_multi_city_start > 1) && + ((*p_human_player_bits & (1 << owner->ID)) == 0) && + has_extra_palace (this)) + owner->CapitalID = this->Body.ID; + + City_draw_hud_icon (this, __, canvas, pixel_x, pixel_y); + owner->CapitalID = restore_capital; +} + +bool __fastcall +patch_City_has_hud_icon (City * this) +{ + return City_has_hud_icon (this) + || ( (is->current_config.ai_multi_city_start > 1) + && ((*p_human_player_bits & (1 << this->Body.CivID)) == 0) + && has_extra_palace (this)); +} + +void __fastcall +patch_City_draw_on_map (City * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) +{ + Leader * owner = &leaders[this->Body.CivID]; + int restore_capital = owner->CapitalID; + + if (is->current_config.do_not_make_capital_cities_appear_larger) + owner->CapitalID = -1; + + // Temporarily set this city as the capital if it has an extra palace so it gets drawn with the next larger size + else if ((is->current_config.ai_multi_city_start > 1) && + ((*p_human_player_bits & (1 << owner->ID)) == 0) && + has_extra_palace (this)) + owner->CapitalID = this->Body.ID; + + City_draw_on_map (this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); + owner->CapitalID = restore_capital; +} + +// Writes a string to replace "Wake" or "Activate" on the right-click menu entry for the given unit. Some units might not have a replacement, in which +// case the function writes nothing and returns false. The string is written to out_str which must point to a buffer of at least str_capacity bytes. +bool +get_menu_verb_for_unit (Unit * unit, char * out_str, int str_capacity) +{ + struct state_desc { + enum c3x_label label; + bool is_doing_worker_job; + } state_descs[35] = { + {CL_IDLE , false}, // [No state] = 0x0 + {CL_FORTIFIED , false}, // Fortifying = 0x1 + {CL_MINING , true }, // Build_Mines = 0x2 + {CL_IRRIGATING , true }, // Irrigate = 0x3 + {CL_BUILDING_FORTRESS , true }, // Build_Fortress = 0x4 + {CL_BUILDING_ROAD , true }, // Build_Road = 0x5 + {CL_BUILDING_RAILROAD , true }, // Build_Railroad = 0x6 + {CL_PLANTING_FOREST , true }, // Plant_Forest = 0x7 + {CL_CLEARING_FOREST , true }, // Clear_Forest = 0x8 + {CL_CLEARING_WETLANDS , true }, // Clear_Wetlands = 0x9 + {CL_CLEARING_DAMAGE , true }, // Clear_Damage = 0xA + {CL_BUILDING_AIRFIELD , true }, // Build_Airfield = 0xB + {CL_BUILDING_RADAR_TOWER, true }, // Build_Radar_Tower = 0xC + {CL_BUILDING_OUTPOST , true }, // Build_Outpost = 0xD + {CL_BUILDING_BARRICADE , true }, // Build_Barricade = 0xE + {CL_INTERCEPTING , false}, // Intercept = 0xF + {CL_MOVING , false}, // Go_To = 0x10 + {CL_BUILDING_ROAD , true }, // Road_To_Tile = 0x11 + {CL_BUILDING_RAILROAD , true }, // Railroad_To_Tile = 0x12 + {CL_BUILDING_COLONY , true }, // Build_Colony = 0x13 + {CL_AUTOMATED , true }, // Auto_Irrigate = 0x14 + {CL_AUTOMATED , true }, // Build_Trade_Routes = 0x15 + {CL_AUTOMATED , true }, // Auto_Clear_Forest = 0x16 + {CL_AUTOMATED , true }, // Auto_Clear_Swamp = 0x17 + {CL_AUTOMATED , true }, // Auto_Clear_Pollution = 0x18 + {CL_AUTOMATED , true }, // Auto_Save_City_Tiles = 0x19 + {CL_EXPLORING , false}, // Explore = 0x1A + {CL_IN_STATE_27 , false}, // ? = 0x1B + {CL_IN_STATE_28 , false}, // Fleeing = 0x1C + {CL_IN_STATE_29 , false}, // ? = 0x1D + {CL_IN_STATE_30 , false}, // ? = 0x1E + {CL_BOMBARDING , false}, // Auto_Bombard = 0x1F + {CL_BOMBARDING , false}, // Auto_Air_Bombard = 0x20 + {CL_BOMBARDING , false}, // Auto_Precision_Strike = 0x21 + {CL_IDLE , false}, // Exhausted = 0x22 + }; + enum UnitStateType state = unit->Body.UnitState; + struct state_desc const * desc; + if ((state >= 0) && (state < ARRAY_LEN (state_descs)) && (desc = &state_descs[state]) && (desc->label >= 0) && (desc->label < COUNT_C3X_LABELS)) { + enum c3x_label label = desc->label; + Unit * container; + if (((label == CL_IDLE) || (label == CL_MOVING) || (label == CL_IN_STATE_29) || desc->is_doing_worker_job) && unit->Body.automated) + label = CL_AUTOMATED; + else if ((label == CL_FORTIFIED) && (NULL != (container = get_unit_ptr (unit->Body.Container_Unit))) && ! Unit_has_ability (container, __, UTA_Army)) + label = CL_TRANSPORTED; + else if ((label == CL_FORTIFIED) && (unit->Body.Status & (USF_SENTRY | USF_SENTRY_ENEMY_ONLY))) + label = CL_SENTRY; + else if ((label == CL_MINING) && is->current_config.enable_districts) { + + // Check if this unit is actually building a district instead of a mine + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + struct district_instance * inst = get_district_instance (tile); + if ((tile != NULL) && (tile != p_null_tile) && inst != NULL) { + char const * district_name = is->district_configs[inst->district_id].name; + snprintf (out_str, str_capacity, "%s %s", is->c3x_labels[CL_BUILDING], district_name); + out_str[str_capacity - 1] = '\0'; + return true; + } + } + + strncpy (out_str, is->c3x_labels[label], str_capacity); + out_str[str_capacity - 1] = '\0'; + return true; + } else + return false; +} + +void __fastcall +patch_MenuUnitItem_write_text_to_temp_str (MenuUnitItem * this) +{ + MenuUnitItem_write_text_to_temp_str (this); + + Unit * unit = this->unit; + char repl_verb[32]; + if (is->current_config.describe_states_of_units_on_menu && + (unit->Body.CivID == p_main_screen_form->Player_CivID) && + (Unit_get_containing_army (unit) == NULL) && + get_menu_verb_for_unit (unit, repl_verb, sizeof repl_verb)) { + char * verb = (unit->Body.UnitState == UnitState_Fortifying) ? (*p_labels)[LBL_WAKE] : (*p_labels)[LBL_ACTIVATE]; + char * verb_str_start = strstr (temp_str, verb); + if (verb_str_start != NULL) { + char s[500]; + char * verb_str_end = verb_str_start + strlen (verb); + snprintf (s, sizeof s, "%.*s%s%s", verb_str_start - temp_str, temp_str, repl_verb, verb_str_end); + s[(sizeof s) - 1] = '\0'; + strncpy (temp_str, s, sizeof s); + } + } +} + +void __fastcall +patch_Tile_m74_Set_Square_Type_for_hill_gen (Tile * this, int edx, enum SquareTypes sq, int tile_x, int tile_y) +{ + if ((sq == SQ_Volcano) && is->current_config.do_not_generate_volcanos) + sq = SQ_Mountains; + this->vtable->m74_Set_Square_Type (this, __, sq, tile_x, tile_y); +} + +void __fastcall +patch_Map_place_scenario_things (Map * this) +{ + is->is_placing_scenario_things = true; + + Map_place_scenario_things (this); + + // If there are any mills in the config then recompute yields & happiness in all cities. This must be done because we avoid doing this as + // mills are added to cities while placing scenario things. + if (is->current_config.count_mills > 0) + for (int n = 0; n <= p_cities->LastIndex; n++) { + City * city = get_city_ptr (n); + if (city != NULL) + patch_City_recompute_yields_and_happiness (city); + } + + if (is->current_config.enable_districts || + is->current_config.enable_natural_wonders || + is->current_config.enable_named_tiles) + load_scenario_districts_from_file (); + + if (is->current_config.enable_natural_wonders && + is->current_config.add_natural_wonders_to_scenarios_if_none) { + bool any_natural_wonders = false; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst != NULL) && + (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) { + any_natural_wonders = true; + break; + } + } + if (! any_natural_wonders) + place_natural_wonders_on_map (); + } + is->is_placing_scenario_things = false; +} + +void +on_open_advisor (AdvisorKind kind) +{ + recompute_resources_if_necessary (); +} + +bool __fastcall patch_Advisor_Base_Form_domestic_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_DOMESTIC); return Advisor_Base_Form_domestic_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_trade_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_TRADE) ; return Advisor_Base_Form_trade_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_military_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_MILITARY); return Advisor_Base_Form_military_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_foreign_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_FOREIGN) ; return Advisor_Base_Form_foreign_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_cultural_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_CULTURAL); return Advisor_Base_Form_cultural_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_science_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_SCIENCE) ; return Advisor_Base_Form_science_m95 (this); } + +void __fastcall +patch_Main_Screen_Form_open_quick_build_chooser (Main_Screen_Form * this, int edx, City * city, int mouse_x, int mouse_y) +{ + recompute_resources_if_necessary (); + Main_Screen_Form_open_quick_build_chooser (this, __, city, mouse_x, mouse_y); +} + +int __fastcall +patch_Context_Menu_get_selected_item_on_unit_rcm (Context_Menu * this) +{ + // In the base game, this method returns -1 for any disabled item which prevents the player from clicking those. We want players to be able to + // click unit items which have been disabled by the mod so they can interrupt the queued actions of units that have no moves left. + int index = this->Selected_Item; + if (index >= 0) { + if (is->current_config.enable_named_tiles && is->named_tile_menu_active) { + Context_Menu_Item * item = &this->Items[index]; + if (item->Menu_Item_ID == NAMED_TILE_MENU_ID) { + handle_named_tile_menu_selection (); + return -1; + } + } + bool is_enabled = (this->Items[index].Status & 2) == 0; + bool is_unit_item = (this->Items[index].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount)) >= 0; + return (is_enabled || is_unit_item) ? index : -1; + } + return -1; +} + +int __fastcall +patch_Tile_check_water_to_block_pollution (Tile * this) +{ + if (this->vtable->m35_Check_Is_Water (this)) + return 1; + else if (is->current_config.do_not_pollute_impassable_tiles) { + enum SquareTypes terrain_type = this->vtable->m50_Get_Square_BaseType (this); + return p_bic_data->TileTypes[terrain_type].Flags.Impassable; + } else + return 0; +} + +void __fastcall +patch_Tile_set_flag_for_eruption_damage (Tile * this, int edx, int param_1, int param_2, int x, int y) +{ + if (is->current_config.enable_districts) { + struct district_instance * inst = get_district_instance (this); + if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { + // District found - handle removal + int district_id = inst->district_id; + + // Notify human player if this tile is in their territory + int territory_owner = this->vtable->m38_Get_Territory_OwnerID (this); + if (territory_owner == p_main_screen_form->Player_CivID) { + char msg[160]; + char const * district_name = is->district_configs[district_id].name; + snprintf (msg, sizeof msg, "%s %s", district_name, is->c3x_labels[CL_DISTRICT_DESTROYED_BY_VOLCANO]); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (x, y, msg, true); + } + + // Remove the district + handle_district_removed (this, district_id, x, y, false); + + // Clear the mine flags + this->vtable->m62_Set_Tile_BuildingID (this, __, -1); + this->vtable->m51_Unset_Tile_Flags (this, __, 0, TILE_FLAG_MINE, x, y); + } + } + + // Apply the normal eruption damage (lava flag) if allowed + if (! (is->current_config.do_not_pollute_impassable_tiles && + p_bic_data->TileTypes[this->vtable->m50_Get_Square_BaseType (this)].Flags.Impassable)) + this->vtable->m56_Set_Tile_Flags (this, __, param_1, param_2, x, y); +} + +bool __fastcall +patch_City_confirm_production_switch (City * this, int edx, int order_type, int order_id) +{ + bool tr = City_confirm_production_switch (this, __, order_type, order_id); + if (tr && + (order_type == COT_Improvement) && (order_id >= 0) && (order_id < p_bic_data->ImprovementsCount) && + (this->Body.CivID == p_main_screen_form->Player_CivID) && + is->current_config.warn_when_chosen_building_would_replace_another) { + Improvement * improv = &p_bic_data->Improvements[order_id]; + if (improv->ImprovementFlags & ITF_Replaces_Other_Buildings) { + Improvement * replaced = NULL; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * other = &p_bic_data->Improvements[n]; + if ((other->ImprovementFlags & ITF_Replaces_Other_Buildings) && + patch_City_has_improvement (this, __, n, false)) { + replaced = other; + break; + } + } + if (replaced != NULL) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, improv->Name.S, -1, -1); + set_popup_str_param (1, replaced->Name.S, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARN_ABOUT_BUILDING_REPLACEMENT", -1, 0, 0, 0); + if (patch_show_popup (popup, __, 0, 0) == 1) + return false; + } + } + } + return tr; +} + +byte const c3x_save_segment_bookend[4] = {0x22, 'C', '3', 'X'}; + +// Writes a string to the buffer and pads the end so it's four-byte aligned (assuming the existing contents is already so aligned). +void +serialize_aligned_text (char const * text, struct buffer * b) +{ + int len = strlen (text); + if (len > 0) { + int padded_len = (len + 4) & ~3; // +1 for null terminator then +3 & ~3 for alignment + byte * p = buffer_allocate (b, padded_len); + strcpy (p, text); + for (int n = 0; n < padded_len - len; n++) + p[len + n] = (byte)0; + } +} + +void * __fastcall +patch_MappedFile_open_to_load_game (MappedFile * this, int edx, char * file_name, int sequential_access) +{ + void * tr = MappedFile_open (this, __, file_name, sequential_access); + if (tr != NULL) + is->accessing_save_file = this; + return tr; +} + +void * __fastcall +patch_MappedFile_create_file_to_save_game (MappedFile * this, int edx, LPCSTR file_path, unsigned file_size, int is_shared) +{ + // Determine if we're currently applying settler perfume to any AI player + bool any_current_settler_perfume = false; + if (is->current_config.ai_settler_perfume_on_founding != 0) { + int duration = is->current_config.ai_settler_perfume_on_founding_duration; + for (int n = 0; n < 32; n++) { + int last_founding_turn = is->turn_no_of_last_founding_for_settler_perfume[n]; + if ((last_founding_turn != -1) && ((*p_current_turn_no - last_founding_turn) < duration)) + any_current_settler_perfume = true; + } + } + + // Assemble mod save data + struct buffer mod_data = {0}; { + if (is->extra_defensive_bombards.len > 0) { + serialize_aligned_text ("extra_defensive_bombards", &mod_data); + itable_serialize (&is->extra_defensive_bombards, &mod_data); + } + if (is->airdrops_this_turn.len > 0) { + serialize_aligned_text ("airdrops_this_turn", &mod_data); + itable_serialize (&is->airdrops_this_turn, &mod_data); + } + if (is->unit_transport_ties.len > 0) { + serialize_aligned_text ("unit_transport_ties", &mod_data); + itable_serialize (&is->unit_transport_ties, &mod_data); + } + if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && is->waiting_units.len > 0) { + serialize_aligned_text ("waiting_units", &mod_data); + itable_serialize (&is->waiting_units, &mod_data); + } + if ((p_bic_data->ImprovementsCount > 256) && (p_cities->Cities != NULL) && (is->extra_city_improvs.len > 0)) { + serialize_aligned_text ("extra_city_improvs", &mod_data); + int extra_improv_count = p_bic_data->ImprovementsCount - 256; + *(int *)buffer_allocate (&mod_data, sizeof(int)) = extra_improv_count; + + int count_entries = 0; { + for (int n = 0; n <= p_cities->LastIndex; n++) { + City_Body * body = p_cities->Cities[n].City; + if ((body != NULL) && ((int)body != offsetof (City, Body))) { + int unused; + if (itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_1, &unused) || + itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_2, &unused)) + count_entries++; + } + } + } + *(int *)buffer_allocate (&mod_data, sizeof(int)) = count_entries; + + int ints_per_list = (extra_improv_count + 31) / 32; + int bytes_per_list = (extra_improv_count + 7) / 8; + for (int n = 0; n <= p_cities->LastIndex; n++) { + City_Body * body = p_cities->Cities[n].City; + if ((body != NULL) && ((int)body != offsetof (City, Body))) { + byte * extra_bit_lists[2]; + extra_bit_lists[0] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_1, 0); + extra_bit_lists[1] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_2, 0); + if ((extra_bit_lists[0] != NULL) || (extra_bit_lists[1] != NULL)) { + *(int *)buffer_allocate (&mod_data, sizeof(int)) = body->ID; + for (int k = 0; k < 2; k++) { + int list_size = sizeof(int) * ints_per_list; + int * list = (int *)buffer_allocate (&mod_data, list_size); + memset (list, 0, list_size); + if (extra_bit_lists[k] != NULL) + memcpy (list, extra_bit_lists[k], bytes_per_list); + } + } + } + } + } + if (any_current_settler_perfume) { + serialize_aligned_text ("turn_no_of_last_founding_for_settler_perfume", &mod_data); + void * area = buffer_allocate (&mod_data, sizeof is->turn_no_of_last_founding_for_settler_perfume); + memcpy (area, is->turn_no_of_last_founding_for_settler_perfume, sizeof is->turn_no_of_last_founding_for_settler_perfume); + } + if (is->current_config.day_night_cycle_mode != DNCM_OFF) { + serialize_aligned_text ("current_day_night_cycle", &mod_data); + int_to_bytes (buffer_allocate (&mod_data, sizeof is->current_day_night_cycle), is->current_day_night_cycle); + } + if (is->current_config.enable_districts && (is->district_count > 0)) { + serialize_aligned_text ("district_config_names", &mod_data); + int * entry_count = (int *)buffer_allocate (&mod_data, sizeof(int)); + *entry_count = is->district_count; + for (int district_id = 0; district_id < is->district_count; district_id++) { + *(int *)buffer_allocate (&mod_data, sizeof(int)) = district_id; + char const * name = is->district_configs[district_id].name; + if (name == NULL) + name = ""; + serialize_aligned_text (name, &mod_data); + } + } + + if (is->current_config.enable_districts) { + int entry_count = 0; + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req != NULL) && (req->city_id >= 0)) + entry_count++; + } + } + if (entry_count > 0) { + serialize_aligned_text ("district_pending_requests", &mod_data); + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 5 * entry_count)); + int * out = chunk + 1; + chunk[0] = entry_count; + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req == NULL) || (req->city_id < 0)) + continue; + out[0] = req->city_id; + out[1] = req->district_id; + out[2] = req->assigned_worker_id; + out[3] = req->target_x; + out[4] = req->target_y; + out += 5; + } + } + } + } + + if (is->current_config.enable_districts && + (is->city_pending_building_orders.len > 0)) { + int entry_count = 0; + FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { + City * city = (City *)tei.key; + int improv_id = tei.value; + if ((city != NULL) && (improv_id >= 0)) + entry_count++; + } + if (entry_count > 0) { + serialize_aligned_text ("building_pending_orders", &mod_data); + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 2 * entry_count)); + int * out = chunk + 1; + chunk[0] = entry_count; + FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { + City * city = (City *)tei.key; + int improv_id = tei.value; + if ((city == NULL) || (improv_id < 0)) + continue; + out[0] = city->Body.ID; + out[1] = improv_id; + out += 2; + } + } + } + + if (is->current_config.enable_districts && (is->district_tile_map.len > 0)) { + serialize_aligned_text ("district_tile_map", &mod_data); + int entry_capacity = is->district_tile_map.len; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 9 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * tile = (Tile *)tei.key; + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst == NULL) + continue; + int x, y; + if (! district_instance_get_coords (inst, tile, &x, &y)) + continue; + int wonder_city_id = inst->wonder_info.city_id; + if (wonder_city_id >= 0) { + City * info_city = get_city_ptr (wonder_city_id); + inst->wonder_info.city = info_city; + if (info_city == NULL) + wonder_city_id = -1; + } else + inst->wonder_info.city = NULL; + out[0] = x; + out[1] = y; + out[2] = inst->district_id; + out[3] = (int)inst->state; + out[4] = inst->built_by_civ_id; + out[5] = inst->completed_turn; + out[6] = (int)inst->wonder_info.state; + out[7] = wonder_city_id; + out[8] = inst->wonder_info.wonder_index; + out += 9; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 9 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + + if (is->current_config.enable_natural_wonders && (is->district_tile_map.len > 0)) { + int entry_capacity = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + if (inst->natural_wonder_info.natural_wonder_id < 0) + continue; + entry_capacity++; + } + if (entry_capacity > 0) { + serialize_aligned_text ("natural_wonder_districts", &mod_data); + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * tile = (Tile *)tei.key; + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || + (inst->district_id != NATURAL_WONDER_DISTRICT_ID) || + (inst->natural_wonder_info.natural_wonder_id < 0)) + continue; + int x, y; + if (! district_instance_get_coords (inst, tile, &x, &y)) + continue; + out[0] = x; + out[1] = y; + out[2] = inst->natural_wonder_info.natural_wonder_id; + out += 3; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + } + + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts && + (is->distribution_hub_records.len > 0)) { + serialize_aligned_text ("distribution_hub_records", &mod_data); + int entry_capacity = is->distribution_hub_records.len; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (rec == NULL) + continue; + out[0] = rec->tile_x; + out[1] = rec->tile_y; + out[2] = rec->civ_id; + out += 3; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + + if (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (is->aerodrome_airlift_usage.len > 0)) { + serialize_aligned_text ("aerodrome_airlift_usage", &mod_data); + int entry_capacity = is->aerodrome_airlift_usage.len; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { + Tile * tile = (Tile *)tei.key; + int mask = tei.value; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + continue; + + out[0] = tile_x; + out[1] = tile_y; + out[2] = mask; + out += 3; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + + if (is->current_config.enable_named_tiles && (is->named_tile_map.len > 0)) { + serialize_aligned_text ("named_tiles", &mod_data); + int entry_capacity = is->named_tile_map.len; + int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); + byte * chunk = (byte *)buffer_allocate (&mod_data, (int)sizeof(int) + bytes_per_entry * entry_capacity); + int * count = (int *)chunk; + byte * out = (byte *)(count + 1); + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if ((entry == NULL) || (entry->name[0] == '\0')) + continue; + Tile * tile = (Tile *)tei.key; + int tile_x = entry->tile_x; + int tile_y = entry->tile_y; + if ((tile != NULL) && (tile != p_null_tile)) + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + ((int *)out)[0] = tile_x; + ((int *)out)[1] = tile_y; + out += sizeof(int) * 2; + memcpy (out, entry->name, sizeof entry->name); + out += sizeof entry->name; + written++; + } + *count = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * bytes_per_entry; + mod_data.length -= trimmed_bytes; + } + } + + if (is->great_wall_auto_build != GWABS_NOT_STARTED) { + serialize_aligned_text ("great_wall_auto_build_state", &mod_data); + *(int *)buffer_allocate (&mod_data, sizeof(int)) = (int)is->great_wall_auto_build; + } + + if (is->ai_candidate_bridge_or_canals_initialized || (is->ai_candidate_bridge_or_canals_count > 0)) { + serialize_aligned_text ("ai_candidate_bridge_or_canals", &mod_data); + int * header = (int *)buffer_allocate (&mod_data, sizeof(int) * 3); + header[0] = is->ai_candidate_bridge_or_canals_initialized ? 1 : 0; + header[1] = is->ai_candidate_bridge_or_canals_count; + header[2] = is->ai_candidate_bridge_or_canals_capacity; + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + int tile_count = (int)entry->tile_count; + if ((tile_count <= 0) || (entry->tile_x == NULL) || (entry->tile_y == NULL)) + tile_count = 0; + + int field_count = 14; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (field_count + tile_count * 2)); + int pending_city_id = entry->pending_req.city_id; + if ((pending_city_id < 0) && (entry->pending_req.city != NULL)) + pending_city_id = entry->pending_req.city->Body.ID; + + chunk[0] = entry->district_id; + chunk[1] = (int)entry->owner_civ_id; + chunk[2] = tile_count; + chunk[3] = (entry->tile_capacity > 0) ? entry->tile_capacity : tile_count; + chunk[4] = entry->assigned_tile_index; + chunk[5] = entry->assigned_worker_id; + chunk[6] = entry->completed ? 1 : 0; + chunk[7] = pending_city_id; + chunk[8] = entry->pending_req.civ_id; + chunk[9] = entry->pending_req.district_id; + chunk[10] = entry->pending_req.assigned_worker_id; + chunk[11] = entry->pending_req.target_x; + chunk[12] = entry->pending_req.target_y; + chunk[13] = entry->pending_req.worker_assigned_turn; + + int * out = chunk + field_count; + for (int ti = 0; ti < tile_count; ti++) { + out[0] = entry->tile_x[ti]; + out[1] = entry->tile_y[ti]; + out += 2; + } + } + } + } + + int metadata_size = (mod_data.length > 0) ? 12 : 0; // Two four-byte bookends plus one four-byte size, only written if there's any mod data + + void * tr = MappedFile_create_file (this, __, file_path, file_size + mod_data.length + metadata_size, is_shared); + if (tr != NULL) { + is->accessing_save_file = this; + if ((mod_data.length > 0) && (mod_data.length + metadata_size <= this->size)) { + // Write first bookend to mod's segment in the save data + byte * seg_start = (byte *)tr + file_size; + for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) + seg_start[n] = c3x_save_segment_bookend[n]; + + // Write actual mod game data + memcpy ((byte *)tr + file_size + 4, mod_data.contents, mod_data.length); + + // Write size of mod data + byte * seg_end = (byte *)tr + file_size + 4 + mod_data.length; + int_to_bytes (seg_end, mod_data.length); + + // Finish off with another bookend + for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) + seg_end[4+n] = c3x_save_segment_bookend[n]; + } + } + buffer_deinit (&mod_data); + return tr; +} + +bool +match_save_chunk_name (byte ** cursor, char const * name) +{ + if (strcmp (name, *cursor) == 0) { + // Move cursor past the string if it matched. Also move past any padding that was added to ensure alignment (see serialize_aligned_text). + *cursor = (byte *)((int)*cursor + strlen (name) + 4 & ~3); + return true; + } else + return false; +} + +bool +match_save_segment_bookend (byte * b) +{ + return memcmp (c3x_save_segment_bookend, b, ARRAY_LEN (c3x_save_segment_bookend)) == 0; +} + +int __cdecl +patch_move_game_data (byte * buffer, bool save_else_load) +{ + int tr = move_game_data (buffer, save_else_load); + + if (! save_else_load) { + // Free all district_instance structs first + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst != NULL) + free (inst); + } + table_deinit (&is->district_tile_map); + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if (entry != NULL) + free (entry); + } + table_deinit (&is->named_tile_map); + clear_all_tracked_workers (); + reset_ai_candidate_bridge_or_canals (); + } + + // Check for a mod save data section and load it if present + MappedFile * save; + int seg_size; + byte * seg; + if ((! save_else_load) && + ((save = is->accessing_save_file) != NULL) && + (save->size >= 8) && + match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - 4)) && + ((seg_size = int_from_bytes ((byte *)((int)save->base_addr + save->size - 8))) > 0) && + (save->size >= seg_size + 12) && + match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - seg_size - 12)) && + ((seg = malloc (seg_size)) != NULL)) { + memcpy (seg, (void *)((int)save->base_addr + save->size - seg_size - 8), seg_size); + + byte * cursor = seg; + char * error_chunk_name = NULL; + while (cursor < seg + seg_size) { + if (match_save_chunk_name (&cursor, "special save message")) { + char * msg = (char *)cursor; + cursor = (byte *)((int)cursor + strlen (msg) + 4 & ~3); + + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + PopupForm_add_text (popup, __, "This save contains a special message:", 0); + PopupForm_add_text (popup, __, msg, 0); + patch_show_popup (popup, __, 0, 0); + + } else if (match_save_chunk_name (&cursor, "extra_defensive_bombards")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->extra_defensive_bombards); + if (bytes_read > 0) + cursor += bytes_read; + else { + error_chunk_name = "extra_defensive_bombards"; + break; + } + + } else if (match_save_chunk_name (&cursor, "airdrops_this_turn")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->airdrops_this_turn); + if (bytes_read > 0) + cursor += bytes_read; + else { + error_chunk_name = "airdrops_this_turn"; + break; + } + + } else if (match_save_chunk_name (&cursor, "unit_transport_ties")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->unit_transport_ties); + if (bytes_read > 0) + cursor += bytes_read; + else { + error_chunk_name = "unit_transport_ties"; + break; + } + + } else if (match_save_chunk_name (&cursor, "waiting_units")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->waiting_units); + if (bytes_read > 0) { + cursor += bytes_read; + is->have_loaded_waiting_units = true; + } else { + error_chunk_name = "waiting_units"; + break; + } + + } else if (match_save_chunk_name (&cursor, "extra_city_improvs")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + + // Read two int vars from this save chunk + int file_extra_improv_count, count_entries; + if (remaining_bytes >= 8) { + file_extra_improv_count = *((int *)cursor)++; + count_entries = *((int *)cursor)++; + remaining_bytes -= 8; + } else + goto done_with_extra_city_improvs; + + // Check that the extra improv counts are valid. They must be greater than zero and what was stored in the save must + // match what we got from the current scenario data. + int extra_improv_count = not_below (0, p_bic_data->ImprovementsCount - 256); + if ((file_extra_improv_count <= 0) || (extra_improv_count != file_extra_improv_count)) + goto done_with_extra_city_improvs; + + // The extra bits data in the save is stored in 32-bit chunks, "ints", to maintain alignment. Compute how many ints we + // need for each list of bits and check that reading all entries won't overrun the buffer. + int ints_per_list = (extra_improv_count + 31) / 32, + ints_per_entry = 1 + 2 * ints_per_list; + if (count_entries * ints_per_entry * sizeof(int) > remaining_bytes) + goto done_with_extra_city_improvs; + + // Main loop reading the extra bits data + for (int n = 0; n < count_entries; n++) { + City * city = get_city_ptr (*((int *)cursor)++); + if (city == NULL) + goto done_with_extra_city_improvs; + + byte * extra_bits_1 = calloc (sizeof (int), ints_per_list); + for (int k = 0; k < ints_per_list; k++) + ((int *)extra_bits_1)[k] = *((int *)cursor)++; + itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_1, (int)extra_bits_1); + + byte * extra_bits_2 = calloc (sizeof (int), ints_per_list); + for (int k = 0; k < ints_per_list; k++) + ((int *)extra_bits_2)[k] = *((int *)cursor)++; + itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_2, (int)extra_bits_2); + } + + // Rebuild the trade network since it may have changed as a result of the additional buildings. This method also + // refreshes the free improvement tables and recomputes city happiness. + patch_Map_build_trade_network (&p_bic_data->Map); + + success = true; + + done_with_extra_city_improvs: + if (! success) { + error_chunk_name = "extra_city_improvs";; + break; + } + + } else if (match_save_chunk_name (&cursor, "turn_no_of_last_founding_for_settler_perfume")) { + for (int n = 0; n < 32; n++) + is->turn_no_of_last_founding_for_settler_perfume[n] = *((int *)cursor)++; + + } else if (match_save_chunk_name (&cursor, "current_day_night_cycle")) { + is->current_day_night_cycle = *((int *)cursor)++; + is->day_night_cycle_unstarted = false; + + // The day/night cycle sprite proxies will have been cleared in patch_load_scenario. They will not necessarily be set + // up again in the usual way because Map_Renderer::load_images is not necessarily called when loading a save. The game + // skips reloading all graphics when loading a save while in-game with another that uses the same graphics (possibly + // only the standard graphics; I didn't test). If day/night cycle mode is active, restore the proxies now if they + // haven't already been. + if ((is->day_night_cycle_img_state == IS_OK) && ! is->day_night_cycle_img_proxies_indexed) + build_sprite_proxies_24 (&p_bic_data->Map.Renderer); + + // Because we've restored current_day_night_cycle from the save, set that is is not the first turn so the cycle + // doesn't get restarted. + is->day_night_cycle_unstarted = false; + + } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_state")) { + int state = *((int *)cursor)++; + if ((state >= GWABS_NOT_STARTED) && (state <= GWABS_DONE)) + is->great_wall_auto_build = (enum great_wall_auto_build_state)state; + else + is->great_wall_auto_build = GWABS_NOT_STARTED; + + } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_is_done")) { + bool was_done = (*((int *)cursor)++ != 0); + is->great_wall_auto_build = was_done ? GWABS_DONE : GWABS_NOT_STARTED; + + } else if (match_save_chunk_name (&cursor, "district_pending_requests")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && + (remaining_bytes >= entry_count * 5 * (int)sizeof(int))) { + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req != NULL) + free (req); + } + table_deinit (&is->city_pending_district_requests[civ_id]); + } + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 5 * (int)sizeof(int)) { + success = false; + break; + } + int city_id = *ints++; + int district_id = *ints++; + int assigned_worker_id = *ints++; + int target_x = *ints++; + int target_y = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 5 * (int)sizeof(int); + City * city = get_city_ptr (city_id); + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + continue; + struct pending_district_request * req = create_pending_district_request (city, district_id); + if (req == NULL) + continue; + if ((assigned_worker_id >= 0) && (get_unit_ptr (assigned_worker_id) == NULL)) + assigned_worker_id = -1; + req->assigned_worker_id = assigned_worker_id; + req->target_x = target_x; + req->target_y = target_y; + } + if (! success) { + for (int civ_id = 0; civ_id < 32; civ_id++) + table_deinit (&is->city_pending_district_requests[civ_id]); + } + } + } + if (! success) { + error_chunk_name = "district_pending_requests"; + break; + } + } else if (match_save_chunk_name (&cursor, "building_pending_orders")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && + (remaining_bytes >= entry_count * 2 * (int)sizeof(int))) { + table_deinit (&is->city_pending_building_orders); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 2 * (int)sizeof(int)) { + success = false; + break; + } + int city_id = *ints++; + int improv_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 2 * (int)sizeof(int); + if (improv_id < 0) + continue; + City * city = get_city_ptr (city_id); + if (city == NULL) + continue; + itable_insert (&is->city_pending_building_orders, (int)city, improv_id); + } + if (! success) + table_deinit (&is->city_pending_building_orders); + } + } + if (! success) { + error_chunk_name = "building_pending_orders"; + break; + } + } else if (match_save_chunk_name (&cursor, "district_tile_map")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if (entry_count >= 0) { + int ints_per_entry = 9; + success = true; + int required_bytes = entry_count * ints_per_entry * (int)sizeof(int); + if (success && remaining_bytes >= required_bytes) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst != NULL) + free (inst); + } + table_deinit (&is->district_tile_map); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < ints_per_entry * (int)sizeof(int)) { + success = false; + break; + } + int x = *ints++; + int y = *ints++; + int district_id = *ints++; + int state_val = *ints++; + int built_by_civ_id = *ints++; + int completed_turn = *ints++; + int wonder_state = *ints++; + int wonder_city_id = *ints++; + int wonder_index = *ints++; + cursor = (byte *)ints; + remaining_bytes -= ints_per_entry * (int)sizeof(int); + if ((district_id < 0) || (district_id >= is->district_count)) + continue; + Tile * tile = tile_at (x, y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = ensure_district_instance (tile, district_id, x, y); + if (inst != NULL) { + enum district_state new_state; + switch (state_val) { + case DS_COMPLETED: + new_state = DS_COMPLETED; + break; + case DS_UNDER_CONSTRUCTION: + new_state = DS_UNDER_CONSTRUCTION; + break; + default: + new_state = DS_UNDER_CONSTRUCTION; + break; + } + inst->state = new_state; + inst->built_by_civ_id = built_by_civ_id; + inst->completed_turn = completed_turn; + + inst->wonder_info.state = (enum wonder_district_state)wonder_state; + inst->wonder_info.city_id = (wonder_city_id >= 0) ? wonder_city_id : -1; + City * info_city = (wonder_city_id >= 0) ? get_city_ptr (wonder_city_id) : NULL; + inst->wonder_info.city = info_city; + if (info_city == NULL) + inst->wonder_info.city_id = -1; + inst->wonder_info.wonder_index = wonder_index; + set_tile_unworkable_for_all_cities (tile, x, y); + } + } + } + } + else + success = false; + } + } + if (! success) { + error_chunk_name = "district_tile_map"; + break; + } + } else if (match_save_chunk_name (&cursor, "natural_wonder_districts")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 3 * (int)sizeof(int)) { + success = false; + break; + } + int x = *ints++; + int y = *ints++; + int natural_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 3 * (int)sizeof(int); + if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) + continue; + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, x, y); + if (inst == NULL) + continue; + inst->district_id = NATURAL_WONDER_DISTRICT_ID; + inst->state = DS_COMPLETED; + inst->natural_wonder_info.natural_wonder_id = natural_id; + set_tile_unworkable_for_all_cities (tile, x, y); + } + } + } + if (! success) { + error_chunk_name = "natural_wonder_districts"; + break; + } + } else if (match_save_chunk_name (&cursor, "distribution_hub_records")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { + clear_distribution_hub_tables (); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 3 * (int)sizeof(int)) { + success = false; + break; + } + int x = *ints++; + int y = *ints++; + int civ_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 3 * (int)sizeof(int); + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + on_distribution_hub_completed (tile, x, y); + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec != NULL) + rec->civ_id = civ_id; + } + } + } + if (! success) { + error_chunk_name = "distribution_hub_records"; + break; + } + } else if (match_save_chunk_name (&cursor, "aerodrome_airlift_usage")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && + (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { + table_deinit (&is->aerodrome_airlift_usage); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 3 * (int)sizeof(int)) { + success = false; + break; + } + int tile_x = *ints++; + int tile_y = *ints++; + int mask = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 3 * (int)sizeof(int); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + itable_insert (&is->aerodrome_airlift_usage, (int)tile, mask); + } + if (! success) + table_deinit (&is->aerodrome_airlift_usage); + } + } + if (! success) { + error_chunk_name = "aerodrome_airlift_usage"; + break; + } + + } else if (match_save_chunk_name (&cursor, "named_tiles")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); + if ((entry_count >= 0) && (remaining_bytes >= entry_count * bytes_per_entry)) { + table_deinit (&is->named_tile_map); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < bytes_per_entry) { + success = false; + break; + } + int tile_x = *ints++; + int tile_y = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int) * 2; + + char name_buf[101]; + memcpy (name_buf, cursor, sizeof name_buf); + name_buf[(sizeof name_buf) - 1] = '\0'; + cursor += sizeof name_buf; + remaining_bytes -= sizeof name_buf; + ints = (int *)cursor; + + if (name_buf[0] == '\0') + continue; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + struct named_tile_entry * entry = calloc (1, sizeof *entry); + if (entry == NULL) { + success = false; + break; + } + entry->tile_x = tile_x; + entry->tile_y = tile_y; + strncpy (entry->name, name_buf, sizeof entry->name); + entry->name[(sizeof entry->name) - 1] = '\0'; + itable_insert (&is->named_tile_map, (int)tile, (int)entry); + } + if (! success) { + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if (entry != NULL) + free (entry); + } + table_deinit (&is->named_tile_map); + } + } + } + if (! success) { + error_chunk_name = "named_tiles"; + break; + } + + } else if (match_save_chunk_name (&cursor, "ai_candidate_bridge_or_canals")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int) * 3) { + int * ints = (int *)cursor; + int saved_initialized = *ints++; + int saved_count = *ints++; + int saved_capacity = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int) * 3; + + if ((saved_count >= 0) && (saved_capacity >= 0)) { + reset_ai_candidate_bridge_or_canals (); + success = true; + + int alloc_capacity = saved_capacity; + if (alloc_capacity < saved_count) + alloc_capacity = saved_count; + if (alloc_capacity > 0) { + is->ai_candidate_bridge_or_canals = (struct ai_candidate_bridge_or_canal_entry *)calloc (alloc_capacity, sizeof *is->ai_candidate_bridge_or_canals); + if (is->ai_candidate_bridge_or_canals == NULL) { + success = false; + alloc_capacity = 0; + } else + is->ai_candidate_bridge_or_canals_capacity = alloc_capacity; + } + + is->ai_candidate_bridge_or_canals_initialized = (saved_initialized != 0); + int loaded_count = 0; + for (int ei = 0; ei < saved_count; ei++) { + if (remaining_bytes < (int)sizeof(int) * 14) { + success = false; + break; + } + int district_id = *ints++; + int owner_civ_id = *ints++; + int tile_count = *ints++; + int tile_capacity = *ints++; + int assigned_tile_index = *ints++; + int assigned_worker_id = *ints++; + int completed = *ints++; + int pending_city_id = *ints++; + int pending_civ_id = *ints++; + int pending_district_id = *ints++; + int pending_assigned_worker_id = *ints++; + int pending_target_x = *ints++; + int pending_target_y = *ints++; + int pending_worker_assigned_turn = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int) * 14; + + if (tile_count < 0) { + success = false; + break; + } + if (remaining_bytes < tile_count * 2 * (int)sizeof(int)) { + success = false; + break; + } + + int stored_tile_count = tile_count; + if (tile_count > AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES) + tile_count = AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES; + if (tile_capacity < tile_count) + tile_capacity = tile_count; + + struct ai_candidate_bridge_or_canal_entry * entry = NULL; + if ((alloc_capacity > 0) && (loaded_count < alloc_capacity)) + entry = &is->ai_candidate_bridge_or_canals[loaded_count]; + + if (entry != NULL) { + entry->district_id = district_id; + entry->owner_civ_id = (short)owner_civ_id; + entry->tile_count = (short)tile_count; + entry->tile_capacity = tile_capacity; + entry->assigned_tile_index = assigned_tile_index; + entry->assigned_worker_id = assigned_worker_id; + entry->completed = (completed != 0); + + entry->tile_x = (short *)calloc (sizeof *entry->tile_x, tile_count); + entry->tile_y = (short *)calloc (sizeof *entry->tile_y, tile_count); + if ((tile_count > 0) && ((entry->tile_x == NULL) || (entry->tile_y == NULL))) { + if (entry->tile_x != NULL) + free (entry->tile_x); + if (entry->tile_y != NULL) + free (entry->tile_y); + entry->tile_x = NULL; + entry->tile_y = NULL; + entry->tile_count = 0; + entry->tile_capacity = 0; + } + + for (int ti = 0; ti < stored_tile_count; ti++) { + int tx = *ints++; + int ty = *ints++; + if ((entry->tile_x != NULL) && (ti < tile_count)) { + entry->tile_x[ti] = (short)tx; + entry->tile_y[ti] = (short)ty; + } + } + + entry->pending_req.city = (pending_city_id >= 0) ? get_city_ptr (pending_city_id) : NULL; + entry->pending_req.city_id = (entry->pending_req.city != NULL) ? pending_city_id : -1; + entry->pending_req.civ_id = pending_civ_id; + entry->pending_req.district_id = pending_district_id; + entry->pending_req.assigned_worker_id = pending_assigned_worker_id; + entry->pending_req.target_x = pending_target_x; + entry->pending_req.target_y = pending_target_y; + entry->pending_req.worker_assigned_turn = pending_worker_assigned_turn; + + if ((entry->assigned_worker_id >= 0) && (get_unit_ptr (entry->assigned_worker_id) == NULL)) + entry->assigned_worker_id = -1; + if ((entry->pending_req.assigned_worker_id >= 0) && (get_unit_ptr (entry->pending_req.assigned_worker_id) == NULL)) + entry->pending_req.assigned_worker_id = -1; + if ((entry->assigned_tile_index < 0) || (entry->assigned_tile_index >= entry->tile_count)) + entry->assigned_tile_index = -1; + + loaded_count++; + } else { + for (int ti = 0; ti < stored_tile_count; ti++) { + ints += 2; + } + } + + cursor = (byte *)ints; + remaining_bytes -= stored_tile_count * 2 * (int)sizeof(int); + } + if (success) + is->ai_candidate_bridge_or_canals_count = loaded_count; + } + } + if (! success) { + error_chunk_name = "ai_candidate_bridge_or_canals"; + break; + } + + } else if (match_save_chunk_name (&cursor, "district_config_names")) { + bool success = false; + bool mismatch_found = false; + bool count_mismatch = false; + char first_mismatch[200]; + first_mismatch[0] = '\0'; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int saved_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if (saved_count >= 0) { + success = true; + count_mismatch = (saved_count != is->district_count); + char * saved_names[saved_count]; + for (int n = 0; n < saved_count; n++) { + if (remaining_bytes < (int)sizeof(int)) { + success = false; + break; + } + ints = (int *)cursor; + int saved_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + + int name_len = -1; + for (int k = 0; k < remaining_bytes; k++) { + if (cursor[k] == '\0') { + name_len = k; + break; + } + } + if (name_len < 0) { + success = false; + break; + } + int padded_len = (name_len + 4) & ~3; + if (padded_len > remaining_bytes) { + success = false; + break; + } + + char * saved_name = (char *)cursor; + saved_names[n] = saved_name; + if (! mismatch_found) { + if ((saved_id < 0) || (saved_id >= is->district_count)) { + snprintf (first_mismatch, sizeof first_mismatch, "%s %d (\"%s\") %s", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW]); + first_mismatch[(sizeof first_mismatch) - 1] = '\0'; + mismatch_found = true; + } else { + char const * current_name = is->district_configs[saved_id].name; + if (current_name == NULL) + current_name = ""; + if (strcmp (current_name, saved_name) != 0) { + snprintf (first_mismatch, sizeof first_mismatch, "%s %d \"%s\" %s \"%s\"", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_NAME_MISMATCH], current_name); + first_mismatch[(sizeof first_mismatch) - 1] = '\0'; + mismatch_found = true; + } + } + } + + cursor += padded_len; + remaining_bytes -= padded_len; + } + if (success && count_mismatch && (first_mismatch[0] == '\0')) { + snprintf (first_mismatch, sizeof first_mismatch, "%s %d %s %d", is->c3x_labels[CL_SAVE_FILE_HAD], saved_count, is->c3x_labels[CL_CURRENT_CONFIG_HAS_ONLY], is->district_count); + first_mismatch[(sizeof first_mismatch) - 1] = '\0'; + mismatch_found = true; + } + if (success && mismatch_found) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); + + char s[1000]; + snprintf (s, sizeof s, "%s %s", is->c3x_labels[CL_WARNING_DISTRICTS_CONFIG_MISMATCH], first_mismatch); + snprintf (s, sizeof s, "%s. %s", s, is->c3x_labels[CL_MAY_BE_OTHER_ERRORS_AS_WELL]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^"); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_DISTRICTS_IN_SAVE_FILE]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + for (int n = 0; n < saved_count; n++) { + snprintf (s, sizeof s, "^ (%d) %s", n, saved_names[n]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + + snprintf (s, sizeof s, "^"); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^%s \"%s\":", is->c3x_labels[CL_CURRENTLY_CONFIGURED_DISTRICTS], is->current_districts_config_path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + for (int n = 0; n < is->district_count; n++) { + snprintf (s, sizeof s, "^ (%d) %s", n, is->district_configs[n].name); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + + patch_show_popup (popup, __, 0, 0); + } + } + } + if (! success) { + error_chunk_name = "district_config_names"; + break; + } + + } else { + error_chunk_name = "N/A"; + break; + } + } + + if (error_chunk_name != NULL) { + char s[200]; + snprintf (s, sizeof s, "Failed to read mod save data. Error occured in chunk: %s", error_chunk_name); + s[(sizeof s) - 1] = '\0'; + pop_up_in_game_error (s); + } + + free (seg); + } + + return tr; +} + +void __fastcall +patch_MappedFile_deinit_after_saving_or_loading (MappedFile * this) +{ + is->accessing_save_file = NULL; + MappedFile_deinit (this); +} + +bool __fastcall +patch_Tile_m7_Check_Barbarian_Camp (Tile * this, int edx, int visible_to_civ) +{ + int * p_stack = (int *)&visible_to_civ; + int ret_addr = p_stack[-1]; + + // If the barb unit AI is calling this method to check if there's a camp to defend, return true if we're allowing barb city capture and the + // tile has a city. This causes barb units to defend cities they've captured, otherwise they'll ignore them. + if ((ret_addr == ADDR_CHECK_BARB_CAMP_TO_DEFEND_RETURN) && + is->current_config.enable_city_capture_by_barbarians && + Tile_has_city (this)) + return true; + else + return Tile_m7_Check_Barbarian_Camp (this, __, visible_to_civ); +} + +bool __fastcall +patch_Unit_can_heal_at (Unit * this, int edx, int tile_x, int tile_y) +{ + if (is->current_config.enable_districts && + is->current_config.enable_port_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile_has_friendly_port_district (tile, this->Body.CivID)) { + int occupier_id = get_tile_occupier_id (tile_x, tile_y, -1, true); + return (occupier_id == -1) || (occupier_id == this->Body.CivID); + } + } + + return Unit_can_heal_at (this, __, tile_x, tile_y); +} + +bool __fastcall +patch_Unit_can_airdrop (Unit * this) +{ + UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + + bool allowed = Unit_can_airdrop (this); + + bool require_aerodrome = (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities); + + if (require_aerodrome) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + bool has_aerodrome = false; + + if ((tile != NULL) && (tile != p_null_tile)) + has_aerodrome = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); + + if (! has_aerodrome) + allowed = false; + else if (! allowed) { + if ((this_type->Unit_Class != UTC_Air) && + (this_type->Air_Missions & UCV_Airdrop) && + (this->Body.Moves == 0)) + allowed = true; + } + } + + // Possibly rule in this airdrop as allowed if it's by a paratrooper in a helicopter on a carrier and we're configured to allow airdrops under + // those circumstances. + if ((! allowed) && (is->current_config.special_helicopter_rules & SHR_PASSENGER_AIRDROP)) { + Unit * container = get_unit_ptr (this->Body.Container_Unit); + if (container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) { // if in helicopter + Unit * metacontainer = get_unit_ptr (container->Body.Container_Unit); + if (metacontainer != NULL && p_bic_data->UnitTypes[metacontainer->Body.UnitTypeID].Unit_Class == UTC_Sea && + Unit_has_ability (metacontainer, __, UTA_Transports_Only_Aircraft)) { // if that helicopter is on a carrier + // Allow the airdrop under the same restrictions as from an airfield + allowed = this_type->Unit_Class != UTC_Air && this->Body.Moves == 0; + } + } + } + + if (! allowed) + return false; + + return itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0) == 0; +} + +bool __fastcall +patch_City_Improvements_contains (City_Improvements * this, int edx, int id) +{ + byte * extra_bits; + if ((id < 256) || ! is->current_config.remove_city_improvement_limit) + return City_Improvements_contains (this, __, id); + else if (itable_look_up (&is->extra_city_improvs, (int)this, (int *)&extra_bits)) { + int extra_id = id - 256; + return (extra_bits[extra_id>>3] >> (extra_id & 7)) & 1; + } else + return false; +} + +void __fastcall +patch_City_Improvements_set (City_Improvements * this, int edx, int id, bool add_else_remove) +{ + if ((id < 256) || ! is->current_config.remove_city_improvement_limit) + return City_Improvements_set (this, __, id, add_else_remove); + else { + byte * extra_bits = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)this, 0); + int extra_id = id - 256; + byte mask = 1 << (extra_id & 7); + if (add_else_remove) { + if (! extra_bits) { + int extra_bits_size = (not_below (0, p_bic_data->ImprovementsCount - 256) >> 3) + 1; + extra_bits = calloc (1, extra_bits_size); + itable_insert (&is->extra_city_improvs, (int)this, (int)extra_bits); + } + extra_bits[extra_id>>3] |= mask; + } else if ((! add_else_remove) && (extra_bits != NULL)) + extra_bits[extra_id>>3] &= ~mask; + } +} + +bool __fastcall +patch_Leader_has_tech_to_stop_disease (Leader * this, int edx, int id) +{ + if (! is->current_config.patch_disease_stopping_tech_flag_bug) + return Leader_has_tech (this, __, id); + else + return Leader_has_tech_with_flag (this, __, ATF_Disabled_Deseases_From_Flood_Plains); +} + +void __fastcall +patch_set_worker_animation (void * this, int edx, Unit * unit, int job_id) +{ + AnimationType anim_type; + + // If districts disabled or unit is null or job is not building mines, use base logic + if ((! is->current_config.enable_districts) || + (unit == NULL) || + (job_id != WJ_Build_Mines)) { + set_worker_animation(this, __, unit, job_id); + return; + } + + // If tile has a district under construction + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && + ! district_is_complete (tile, inst->district_id) && job_id == WJ_Build_Mines) { + + // Override and ensure build animation is used + job_id = AT_BUILD; + } + + set_worker_animation(this, __, unit, job_id); +} + +void __fastcall +patch_Unit_work_simple_job (Unit * this, int edx, int job_id) +{ + is->lmify_tile_after_working_simple_job = NULL; + + // Check if districts are enabled + if (is->current_config.enable_districts) { + int tile_x = this->Body.X; + int tile_y = this->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + + if (tile != NULL && tile != p_null_tile) { + // Check if there's a completed district on this tile + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete(tile, inst->district_id)) { + int district_id = inst->district_id; + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + + // AI players only (human removal is handled via issue_district_worker_command) + if (!is_human) { + bool allow_removal = false; + if (district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = &inst->wonder_info; + allow_removal = (info->state == WDS_UNUSED); + } + + if (allow_removal) { + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + handle_district_removed (tile, district_id, tile_x, tile_y, false); + } + } + } + } + } + + Unit_work_simple_job (this, __, job_id); + + if (is->lmify_tile_after_working_simple_job != NULL) + is->lmify_tile_after_working_simple_job->vtable->m31_set_landmark (is->lmify_tile_after_working_simple_job, __, true); +} + +void __fastcall +patch_Map_change_tile_terrain_by_worker (Map * this, int edx, enum SquareTypes new_terrain_type, int x, int y) +{ + Map_change_tile_terrain (this, __, new_terrain_type, x, y); + + if (is->current_config.convert_to_landmark_after_planting_forest && (new_terrain_type == SQ_Forest)) + is->lmify_tile_after_working_simple_job = tile_at (x, y); +} + +int __fastcall +patch_Leader_ai_eval_technology (Leader * this, int edx, int id, bool param_2, bool param_3) +{ + int base = Leader_ai_eval_technology (this, __, id, param_2, param_3); + return apply_perfume (PK_TECHNOLOGY, p_bic_data->Advances[id].Name, base); +} + +int __fastcall +patch_Leader_ai_eval_government (Leader * this, int edx, int id) +{ + int base = Leader_ai_eval_government (this, __, id); + return apply_perfume (PK_GOVERNMENT, p_bic_data->Governments[id].Name.S, base); +} + +bool +roll_to_spare_unit_from_nuke (Unit * unit) +{ + int one_hp_destroy_chance = is->current_config.chance_for_nukes_to_destroy_max_one_hp_units; + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + if ((one_hp_destroy_chance < 100) && + (Unit_get_max_hp (unit) <= 1) && + (type->Defence > 0) && + ((type->Unit_Class == UTC_Land) || (type->Unit_Class == UTC_Sea))) + return ! (rand_int (p_rand_object, __, 100) < one_hp_destroy_chance); + else + return false; +} + +void __fastcall +patch_Unit_despawn_after_killed_by_nuke (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) +{ + if (roll_to_spare_unit_from_nuke (this)) + this->Body.Damage = Unit_get_max_hp (this) - 1; + else { + bool prev_always_despawn_passengers = is->always_despawn_passengers; + if ((is->current_config.land_transport_rules & LTR_NO_ESCAPE) && is_land_transport (this)) + is->always_despawn_passengers = true; + else if ((is->current_config.special_helicopter_rules & SHR_NO_ESCAPE) && p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air && + p_bic_data->UnitTypes[this->Body.UnitTypeID].Transport_Capacity > 0) + is->always_despawn_passengers = true; + patch_Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); + is->always_despawn_passengers = prev_always_despawn_passengers; + } +} + +void __fastcall +patch_mp_despawn_after_killed_by_nuke (void * this, int edx, int unit_id, int civ_id_responsible, byte param_3, byte param_4, byte param_5, byte param_6) +{ + Unit * unit = get_unit_ptr (unit_id); + if ((unit != NULL) && roll_to_spare_unit_from_nuke (unit)) + unit->Body.Damage = Unit_get_max_hp (unit) - 1; + else + mp_despawn (this, __, unit_id, civ_id_responsible, param_3, param_4, param_5, param_6); +} + +bool __fastcall +patch_City_has_unprotected_improv_to_sell (City * this, int edx, int id) +{ + // Fall back to original logic only if the config doesn't alter the behavior. + if (! is->current_config.allow_sale_of_aqueducts_and_hospitals && !is->current_config.allow_sale_of_small_wonders) + return City_has_unprotected_improv (this, __, id); + + else if (patch_City_has_improvement (this, __, id, false)) { + Improvement * improv = &p_bic_data->Improvements[id]; + int max_pop_to_sell = INT_MAX; // By default, population-based sell isn't restricted + if (improv->ImprovementFlags & (ITF_Allows_City_Level_2 | ITF_Allows_City_Level_3)) { // Aqueduct/Hospital? + if (is->current_config.allow_sale_of_aqueducts_and_hospitals) { + if (improv->ImprovementFlags & ITF_Allows_City_Level_2) + max_pop_to_sell = p_bic_data->General.MaximumSize_Town; + else if (improv->ImprovementFlags & ITF_Allows_City_Level_3) + max_pop_to_sell = p_bic_data->General.MaximumSize_City; + } else { + // Do not allow selling these. + max_pop_to_sell = 0; + } + } + + // Can't sell: + // - Great Wonders + // - Small Wonders, unless the config allows it + // - Capital + // - Aqueduct/Hospital if the city is too big for that population + return ((improv->Characteristics & ITC_Wonder) == 0) && + (is->current_config.allow_sale_of_small_wonders || ((improv->Characteristics & ITC_Small_Wonder) == 0)) && + ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && + (this->Body.Population.Size <= max_pop_to_sell); + + } else + return false; +} + +bool __fastcall +patch_UnitType_has_detector_ability_for_vis_check (UnitType * this, int edx, enum UnitTypeAbilities a) +{ + bool tr = UnitType_has_ability (this, __, a); + + // Restrict detection by sea units to other sea units and non-sea units to other non-sea units + if (tr && + is->current_config.no_cross_shore_detection && + (is->checking_visibility_for_unit != NULL) && + ((this->Unit_Class == UTC_Sea) ^ (p_bic_data->UnitTypes[is->checking_visibility_for_unit->Body.UnitTypeID].Unit_Class == UTC_Sea))) + tr = false; + + return tr; +} + +bool +is_airdrop_trespassing (Unit * unit, int target_x, int target_y) +{ + if (is->current_config.disallow_trespassing && + check_trespassing (unit->Body.CivID, tile_at (unit->Body.X, unit->Body.Y), tile_at (target_x, target_y))) { + bool allowed = is_allowed_to_trespass (unit); + + // If "unit" is an air unit that can carry others, like helicopters, then this airdrop is only allowed if all of its passengers are + // allowed to trespass. + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + if (allowed && (type->Unit_Class == UTC_Air) && (type->Transport_Capacity > 0)) + FOR_UNITS_ON (uti, tile_at (unit->Body.X, unit->Body.Y)) + if ((uti.unit->Body.Container_Unit == unit->Body.ID) && + (! is_allowed_to_trespass (uti.unit))) { + allowed = false; + break; + } + + return ! allowed; + } else + return false; +} + +bool __fastcall +patch_Unit_check_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) +{ + return Unit_check_airdrop_target (this, __, tile_x, tile_y) && + is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID) && + ! is_airdrop_trespassing (this, tile_x, tile_y); +} + +bool __fastcall +patch_Unit_can_airlift (Unit * this) +{ + bool base = Unit_can_airlift (this); + + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) + return base; + + Tile * tile = tile_at (this->Body.X, this->Body.Y); + if ((tile == NULL) || (tile == p_null_tile)) + return base; + + bool allow_from_non_city = false; + if (base) { + City * city = city_at (this->Body.X, this->Body.Y); + if ((city == NULL) || (city->Body.CivID != this->Body.CivID)) + allow_from_non_city = true; + } + + if (allow_from_non_city) + return true; + + return tile_has_friendly_aerodrome_district (tile, this->Body.CivID, true); +} + +bool __fastcall +patch_Unit_check_airlift_target (Unit * this, int edx, int tile_x, int tile_y) +{ + bool base = Unit_check_airlift_target (this, __, tile_x, tile_y); + bool allowed = base; + + Tile * tile = tile_at (tile_x, tile_y); + + if (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities) { + if ((tile == NULL) || (tile == p_null_tile)) { + allowed = false; + } else { + City * target_city = city_at (tile_x, tile_y); + if (allowed && + (target_city != NULL) && + (target_city->Body.CivID == this->Body.CivID)) + allowed = false; + + if (! allowed) + allowed = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); + } + } + + if (! allowed) + return false; + + return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); +} + +void __fastcall +patch_Unit_airlift (Unit * this, int edx, int tile_x, int tile_y) +{ + Tile * source_tile = NULL; + bool mark_usage = false; + + if (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities) { + source_tile = tile_at (this->Body.X, this->Body.Y); + if (tile_has_friendly_aerodrome_district (source_tile, this->Body.CivID, true)) + mark_usage = true; + } + + Unit_airlift (this, __, tile_x, tile_y); + + if (mark_usage && (source_tile != NULL) && (source_tile != p_null_tile)) { + int mask = itable_look_up_or (&is->aerodrome_airlift_usage, (int)source_tile, 0); + mask |= (1 << this->Body.CivID); + itable_insert (&is->aerodrome_airlift_usage, (int)source_tile, mask); + } +} + +int __fastcall +patch_City_count_airports_for_ai_airlift_target (City * this, int edx, enum ImprovementTypeFlags airport_flag) +{ + // When this function is called, the AI unit being moved is stored in register ESI. + Unit * unit; + __asm__ __volatile__("mov %%esi, %0" : "=r" (unit)); + + int tr = City_count_improvements_with_flag (this, __, airport_flag); + + // Check the stack limit here. If the city's tile is at the limit, return that it has no airport so the AI can't airlift there. + if ((tr > 0) && ! is_below_stack_limit (tile_at (this->Body.X, this->Body.Y), this->Body.CivID, unit->Body.UnitTypeID)) + return 0; + + else + return tr; +} + +int __fastcall +patch_Unit_ai_eval_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) +{ + int tr = Unit_ai_eval_airdrop_target (this, __, tile_x, tile_y); + + // Prevent the AI from airdropping onto tiles in violation of the stack limit or trespassing restriction + if ((tr > 0) && + ((! is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID)) || + is_airdrop_trespassing (this, tile_x, tile_y))) + tr = 0; + + return tr; +} + +bool __fastcall +patch_Unit_find_telepad_on_tile (Unit * this, int edx, int x, int y, bool show_selection_popup, Unit ** out_unit_telepad) +{ + if (! is_below_stack_limit (tile_at (x, y), this->Body.CivID, this->Body.UnitTypeID)) { + *out_unit_telepad = NULL; + return false; + } else + return Unit_find_telepad_on_tile (this, __, x, y, show_selection_popup, out_unit_telepad); +} + +bool __fastcall +patch_Unit_ai_go_to_capital (Unit * this) +{ + City * capital = get_city_ptr (leaders[this->Body.CivID].CapitalID); + + // Block going to capital if the capital's tile is at the stack limit. This stops the AI from airlifting there (would violate the limit) and + // saves it from trying to pathfind there. + if ((capital != NULL) && + ! is_below_stack_limit (tile_at (capital->Body.X, capital->Body.Y), this->Body.CivID, this->Body.UnitTypeID)) + return false; + + return Unit_ai_go_to_capital (this); +} + +bool __fastcall +patch_Unit_is_in_rebase_range (Unit * this, int edx, int tile_x, int tile_y) +{ + bool in_range; + + // 6 is the game's standard value, so fall back on the base game logic in that case + if (is->current_config.rebase_range_multiplier == 6) + in_range = Unit_is_in_rebase_range (this, __, tile_x, tile_y); + + else { + int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + if (op_range < 1) + op_range = 500; + + int x_dist = Map_get_x_dist (&p_bic_data->Map, __, tile_x, this->Body.X), + y_dist = Map_get_y_dist (&p_bic_data->Map, __, tile_y, this->Body.Y); + + in_range = ((x_dist + y_dist) >> 1) <= (op_range * is->current_config.rebase_range_multiplier); + } + + return in_range && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); +} + +bool __fastcall +patch_Unit_check_rebase_target (Unit * this, int edx, int tile_x, int tile_y) +{ + // Check if this is an air unit + bool is_air_unit = (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air); + + // If districts are enabled and this is an air unit, check for aerodrome districts + if (is_air_unit && is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts) { + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + // Check if tile has a district + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + int district_id = inst->district_id; + // Check if this is an aerodrome district owned by this unit's civ + if ((district_id == AERODROME_DISTRICT_ID) && (tile->Territory_OwnerID == this->Body.CivID)) { + // Check if aerodrome is complete + if (district_is_complete (tile, district_id)) { + // Perform range check + bool in_range = patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y); + if (in_range) { + return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); + } + } + } + } + + // If air_units_use_aerodrome_districts_not_cities is enabled, check if there's a city and disallow it + if (is->current_config.air_units_use_aerodrome_districts_not_cities) { + City * target_city = city_at (tile_x, tile_y); + if (target_city != NULL && target_city->Body.CivID == this->Body.CivID) { + // There's a friendly city here - disallow landing since configured to use aerodromes/airfields/carriers only + return false; + } + } + } + } + + // 6 is the game's standard value, so fall back on the base game logic in that case + if (is->current_config.rebase_range_multiplier == 6) { + return Unit_check_rebase_target (this, __, tile_x, tile_y) && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); + + // Otherwise, we have to redo the range check. Unlike Unit::is_in_rebase_range, the base method here does more than just check the range so we + // want to make sure to call it even if we determine that the target is in range. In that case, set the range to unlimited temporarily so the + // base game's range check passes. + } else { + if (patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y)) { + int * p_op_range = &p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + int original_op_range = *p_op_range; + *p_op_range = 0; + bool tr = Unit_check_rebase_target (this, __, tile_x, tile_y); + *p_op_range = original_op_range; + return tr; + } else + return false; + } +} + +int __fastcall +patch_Sprite_draw_already_worked_tile_img (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + Sprite * to_draw = this; + + if (is->do_not_draw_already_worked_tile_img) + return 0; + + if (is->current_config.toggle_zoom_with_z_on_city_screen && p_bic_data->is_zoomed_out) { + + // Load sprite if necessary + if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_UNINITED) { + is->tile_already_worked_zoomed_out_sprite_init_state = IS_INIT_FAILED; + PCX_Image * pcx = malloc (sizeof *pcx); + if (pcx != NULL) { + memset (pcx, 0, sizeof *pcx); + PCX_Image_construct (pcx); + char path[2*MAX_PATH]; + get_mod_art_path ("TileAlreadyWorkedZoomedOut.pcx", path, sizeof path); + PCX_Image_read_file (pcx, __, path, NULL, 0, 0x100, 2); + if (pcx->JGL.Image != NULL) { + Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; + memset (sprite, 0, sizeof *sprite); + Sprite_construct (sprite); + Sprite_slice_pcx (sprite, __, pcx, 0, 0, 64, 32, 1, 1); + is->tile_already_worked_zoomed_out_sprite_init_state = IS_OK; + } + pcx->vtable->destruct (pcx, __, 0); + free (pcx); + } + } + + if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_OK) + to_draw = &is->tile_already_worked_zoomed_out_sprite; + } + + return Sprite_draw (to_draw, __, canvas, pixel_x, pixel_y, color_table); +} + +int __fastcall +patch_Tile_m43_Get_field_30_for_city_loc_eval (Tile * this) +{ + int tr = this->vtable->m43_Get_field_30 (this); + + // This patch function replaces two places where ai_eval_city_location calls Tile::m43_Get_field_30 to check the 18th bit, which indicates + // whether the tile is in the workable area of any city. If it is but the work area has been expanded, check that it's actually within the + // normal 20-tile area. This prevents work area expansion from causing AIs to space their cities further apart. + // The field_30_get_counter is a crazy workaround for the fact that the game doesn't have any way to determine a tile's coordinates given a + // pointer to its object. So we track the initial (x, y) for the tile we're evaluating and then count calls to this func to know what + // neighboring coords "this" corresponds to. + int get_counter = is->ai_evaling_city_field_30_get_counter; + if (((tr >> 17) & 1) && (is->current_config.city_work_radius >= 3)) { + bool found_city = false; + int this_x, this_y; { + int dx, dy; + patch_ni_to_diff_for_work_area (get_counter, &dx, &dy); + this_x = is->ai_evaling_city_loc_x + dx; + this_y = is->ai_evaling_city_loc_y + dy; + wrap_tile_coords (&p_bic_data->Map, &this_x, &this_y); + } + FOR_TILES_AROUND (tai, 21, this_x, this_y) + if (Tile_has_city (tai.tile)) { + found_city = true; + break; + } + if (! found_city) + tr &= ~(1 << 17); + } + get_counter++; + if (get_counter >= 21) + get_counter = 0; + is->ai_evaling_city_field_30_get_counter = get_counter; + + return tr; + +} + +// Intercept the call where the game gets a random index at which to start searching for a suitable tile to become polluted. Normally, it passes 20 as +// the limit here. We must replace that to cover a potentially modded work area. +int __fastcall +patch_rand_int_to_place_pollution (void * this, int edx, int lim) +{ + return rand_int (this, __, is->workable_tile_count - 1); +} + +void __fastcall +patch_Main_Screen_Form_t2s_coords_to_draw_yields (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int * out_x, int * out_y) +{ + Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, out_x, out_y); + + // If we've zoomed out the map on the city screen, we may end up drawing the tile yields off screen depending on the map size. If this is the + // case, detected by negative screen coords, then shift the coords over by one map-screen back onto the actual screen. The shift amounts are + // 64*map_width/2 and 32*map_height/2 for x and y because (64, 32) is the size of a zoomed out tile and /2 is for overlap (I think). + if (p_bic_data->is_zoomed_out && (*out_x < 0)) + *out_x += p_bic_data->Map.Width << 5; + if (p_bic_data->is_zoomed_out && (*out_y < 0)) + *out_y += p_bic_data->Map.Height << 4; +} + +void +set_clip_area_to_map_view (City_Form * city_form) +{ + int left_margin = (p_bic_data->ScreenWidth - city_form->Background_Image.Width) / 2, + top_margin = (p_bic_data->ScreenHeight - city_form->Background_Image.Height) / 2; + RECT map_view_on_screen = { .left = left_margin, .top = top_margin + 92, .right = left_margin + 1024, .bottom = top_margin + 508 }; + JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; + jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &map_view_on_screen); +} + +void +clear_clip_area (City_Form * city_form) +{ + JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; + jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &jgl_canvas->Image_Rect); +} + +void +init_distribution_hub_icons () +{ + if (is->distribution_hub_icons_img_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char ss[200]; + snprintf (ss, sizeof ss, "[C3X] init_distribution_hub_icons: state=%d\n", is->distribution_hub_icons_img_state); + (*p_OutputDebugStringA) (ss); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("Districts/DistributionHubIncomeIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image == NULL) || + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { + (*p_OutputDebugStringA) ("[C3X] PCX file for distribution hub icons failed to load or is too small.\n"); + is->distribution_hub_icons_img_state = IS_INIT_FAILED; + goto cleanup; + } + + // Extract shield icon (index 4: x = 1 + 4*31 = 125, width 30) + Sprite_construct (&is->distribution_hub_shield_icon); + Sprite_slice_pcx (&is->distribution_hub_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); + + // Extract shield corruption icon (index 5: x = 1 + 5*31 = 156, width 30) + Sprite_construct (&is->distribution_hub_corruption_icon); + Sprite_slice_pcx (&is->distribution_hub_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); + + // Extract small shield icon (index 13) + Sprite_construct (&is->distribution_hub_shield_icon_small); + Sprite_slice_pcx (&is->distribution_hub_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); + + // Extract surplus food icon (index 6: x = 1 + 6*31 = 187, width 30) + Sprite_construct (&is->distribution_hub_food_icon); + Sprite_slice_pcx (&is->distribution_hub_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); + + // Extract small surplus food icon (index 15) + Sprite_construct (&is->distribution_hub_food_icon_small); + Sprite_slice_pcx (&is->distribution_hub_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); + + // Extract eaten food icon (index 7: x = 1 + 7*31 = 218, width 30) + Sprite_construct (&is->distribution_hub_eaten_food_icon); + Sprite_slice_pcx (&is->distribution_hub_eaten_food_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); + + is->distribution_hub_icons_img_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +draw_district_yields (City_Form * city_form, Tile * tile, int district_id, int screen_x, int screen_y) +{ + // Lazy load district icons + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + if (is->dc_icons_img_state != IS_OK) + return; + + if (district_id < 0 || district_id >= is->district_count) + return; + + // Get district configuration + struct district_config * config = &is->district_configs[district_id]; + struct district_instance * inst = get_district_instance (tile); + + // Count total yields from bonuses + int food_bonus = 0, shield_bonus = 0, gold_bonus = 0, science_bonus = 0, culture_bonus = 0, happiness_bonus = 0; + get_effective_district_yields (inst, config, &food_bonus, &shield_bonus, &gold_bonus, &science_bonus, &culture_bonus, &happiness_bonus); + if ((config->generated_resource_id >= 0) && + (config->generated_resource_flags & MF_YIELDS) && + (city_form->CurrentCity != NULL) && + district_generates_resource_for_civ (tile, inst, config, city_form->CurrentCity->Body.CivID)) { + Resource_Type * res = &p_bic_data->ResourceTypes[config->generated_resource_id]; + food_bonus += res->Food; + shield_bonus += res->Shield; + gold_bonus += res->Commerce; + } + + int food_pos = food_bonus > 0 ? food_bonus : 0; + int food_neg = food_bonus < 0 ? -food_bonus : 0; + int shield_pos = shield_bonus > 0 ? shield_bonus : 0; + int shield_neg = shield_bonus < 0 ? -shield_bonus : 0; + int gold_pos = gold_bonus > 0 ? gold_bonus : 0; + int gold_neg = gold_bonus < 0 ? -gold_bonus : 0; + int science_pos = science_bonus > 0 ? science_bonus : 0; + int science_neg = science_bonus < 0 ? -science_bonus : 0; + int culture_pos = culture_bonus > 0 ? culture_bonus : 0; + int culture_neg = culture_bonus < 0 ? -culture_bonus : 0; + int happiness_pos = happiness_bonus > 0 ? happiness_bonus : 0; + int happiness_neg = happiness_bonus < 0 ? -happiness_bonus : 0; + + int total_yield = 0; + total_yield += food_pos + food_neg; + total_yield += shield_pos + shield_neg; + total_yield += gold_pos + gold_neg; + total_yield += science_pos + science_neg; + total_yield += culture_pos + culture_neg; + total_yield += happiness_pos + happiness_neg; + + if (total_yield <= 0) + return; + + // Get sprites + Sprite * food_sprite = &is->district_food_icon_small; + Sprite * shield_sprite = &is->district_shield_icon_small; + Sprite * commerce_sprite = &is->district_commerce_icon_small; + Sprite * science_sprite = &is->district_science_icon_small; + Sprite * culture_sprite = &is->district_culture_icon_small; + Sprite * happiness_sprite = &is->district_happiness_icon_small; + Sprite * food_negative_sprite = &is->district_negative_food_icon_small; + Sprite * shield_negative_sprite = &is->district_negative_shield_icon_small; + Sprite * commerce_negative_sprite = &is->district_negative_commerce_icon_small; + Sprite * science_negative_sprite = &is->district_negative_science_icon_small; + Sprite * culture_negative_sprite = &is->district_negative_culture_icon_small; + Sprite * happiness_negative_sprite = &is->district_unhappiness_icon_small; + + // Determine sprite dimensions + int sprite_width = food_sprite->Width3; + int sprite_height = food_sprite->Height; + + // Calculate total width of all icons + int total_width = total_yield * sprite_width; + + // Center the icons horizontally + int half_width = total_width >> 1; + int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; + int max_offset = (tile_width >> 1) - 5; + if (half_width > max_offset) + half_width = max_offset; + + int pixel_x = screen_x - half_width; + int pixel_y = screen_y - (sprite_height >> 1); + + // Adjust spacing if icons would exceed tile width + int spacing = sprite_width; + if (total_width > tile_width - 10) { + if (total_yield > 1) { + spacing = (tile_width - 10 - sprite_width) / (total_yield - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > sprite_width) + spacing = sprite_width; + } + } + + // Draw icons in order: shields, food, science, commerce, culture + for (int i = 0; i < shield_pos; i++) { + Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < shield_neg; i++) { + Sprite_draw (shield_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < food_pos; i++) { + Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < food_neg; i++) { + Sprite_draw (food_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < science_pos; i++) { + Sprite_draw (science_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < science_neg; i++) { + Sprite_draw (science_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < gold_pos; i++) { + Sprite_draw (commerce_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < gold_neg; i++) { + Sprite_draw (commerce_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < culture_pos; i++) { + Sprite_draw (culture_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < culture_neg; i++) { + Sprite_draw (culture_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < happiness_pos; i++) { + Sprite_draw (happiness_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < happiness_neg; i++) { + Sprite_draw (happiness_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } +} + +void +draw_distribution_hub_yields (City_Form * city_form, Tile * tile, int tile_x, int tile_y, int screen_x, int screen_y) +{ + // Get the distribution hub record for this tile + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec == NULL) + return; + + City * anchor_city = get_connected_city_for_distribution_hub (rec); + if (! distribution_hub_accessible_to_city (rec, city_form->CurrentCity)) + return; + + int food_yield = rec->food_yield; + int shield_yield = rec->shield_yield; + int total_yield = food_yield + shield_yield; + + if (total_yield <= 0) + return; + + // Lazy load distribution hub icons + if (is->distribution_hub_icons_img_state == IS_UNINITED) + init_distribution_hub_icons (); + if (is->distribution_hub_icons_img_state != IS_OK) + return; + + Sprite * food_sprite = &is->distribution_hub_food_icon_small; + Sprite * shield_sprite = &is->distribution_hub_shield_icon_small; + + if (food_sprite->Width3 == 0) food_sprite = &is->distribution_hub_food_icon; + if (shield_sprite->Width3 == 0) shield_sprite = &is->distribution_hub_shield_icon; + + int sprite_height = food_sprite->Height; + if (sprite_height == 0) sprite_height = shield_sprite->Height; + + int food_width = food_sprite->Width3; + int shield_width = shield_sprite->Width3; + if ((food_width <= 0) && (shield_width > 0)) food_width = shield_width; + if ((shield_width <= 0) && (food_width > 0)) shield_width = food_width; + + // Calculate total width of all icons + int total_width = 0; + if (food_yield > 0) total_width += food_width * food_yield; + if (shield_yield > 0) total_width += shield_width * shield_yield; + + // Center the icons horizontally + int half_width = total_width >> 1; + int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; + int max_offset = (tile_width >> 1) - 5; + if (half_width > max_offset) half_width = max_offset; + + int pixel_x = screen_x - half_width; + int pixel_y = screen_y - (sprite_height >> 1); + + // Adjust spacing if icons would exceed tile width + int spacing_food = food_width; + int spacing_shield = shield_width; + + if (total_width > tile_width - 10) { + if (total_yield > 1) { + int spacing = (tile_width - 10 - food_width) / (total_yield - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > food_width) + spacing = food_width; + spacing_food = spacing; + spacing_shield = spacing; + } + } + + // Draw food icons first + for (int i = 0; i < food_yield; i++) { + Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing_food; + } + + // Draw shield icons + for (int i = 0; i < shield_yield; i++) { + Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing_shield; + } +} + +void __fastcall +patch_City_Form_draw_yields_on_worked_tiles (City_Form * this) +{ + // If we're zoomed in and the city work radius is at least 4 then it's likely we'll end up drawing things outside of the city screen's usual + // map area. Set the clip area to the map area so none of those draws are visible. + bool changed_clip_area = false; + if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { + set_clip_area_to_map_view (this); + changed_clip_area = true; + } + + if (is->current_config.enable_districts && this->CurrentCity != NULL) { + recompute_city_yields_with_districts (this->CurrentCity); + } + + is->do_not_draw_already_worked_tile_img = false; + City_Form_draw_yields_on_worked_tiles (this); + + // If we're zoomed out then draw the yields again but this time skip drawing of the tile-already-worked sprites. This is because the + // transparent regions of those sprites get drawn overtop of the yield sprites when zoomed out, and that overdrawing deletes parts of the + // yields, i.e., it overwrites their colored pixels with transparent ones. The simplest solution is to draw the yields again after the + // already-worked sprites to ensure the former get drawn overtop of the latter. + if (p_bic_data->is_zoomed_out) { + is->do_not_draw_already_worked_tile_img = true; + City_Form_draw_yields_on_worked_tiles (this); + } + + // Draw district bonuses on district tiles + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + City * city = this->CurrentCity; + if (city == NULL) + goto skip_district_yields; + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int civ_id = city->Body.CivID; + + // Calculate screen coordinates for city center + int center_screen_x, center_screen_y; + Main_Screen_Form_tile_to_screen_coords (p_main_screen_form, __, city_x, city_y, ¢er_screen_x, ¢er_screen_y); + + int tile_half_width = p_bic_data->is_zoomed_out ? 32 : 64; + int tile_half_height = p_bic_data->is_zoomed_out ? 16 : 32; + center_screen_x += tile_half_width; + if (center_screen_x < 0) + center_screen_x += p_bic_data->Map.Width * tile_half_width; + center_screen_y += tile_half_height; + if (center_screen_y < 0) + center_screen_y += p_bic_data->Map.Height * tile_half_height; + + int remaining_utilized_neighborhoods = 0; + if (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts) + remaining_utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + + FOR_DISTRICTS_AROUND (wai, city_x, city_y, true) { + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + bool is_distribution_hub = district_id == DISTRIBUTION_HUB_DISTRICT_ID; + bool is_natural_wonder = district_id == NATURAL_WONDER_DISTRICT_ID; + + if (is_natural_wonder && (!is->current_config.enable_natural_wonders)) + continue; + + // Distribution hubs are drawn in the dedicated wider-radius pass below. + if (is_distribution_hub) + continue; + + if (!is_natural_wonder && (!is->current_config.enable_districts)) + continue; + + // For neighborhood districts, check if population is high enough to utilize them + if (is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + district_id == NEIGHBORHOOD_DISTRICT_ID) { + // Only draw yields if this neighborhood is utilized + if (remaining_utilized_neighborhoods <= 0) + continue; + remaining_utilized_neighborhoods--; + } + + // Calculate screen coordinates for this tile + int screen_x = center_screen_x + (wai.dx * tile_half_width); + int screen_y = center_screen_y + (wai.dy * tile_half_height); + + // Call the appropriate drawing function + draw_district_yields (this, wai.tile, district_id, screen_x, screen_y); + } + + // Draw distribution hub yields around a larger radius so connected hubs outside the work area are shown + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { + int const max_tiles = workable_tile_counts[7]; + + for (int ni = 0; ni < max_tiles; ni++) { + int dx, dy; + patch_ni_to_diff_for_work_area (ni, &dx, &dy); + + int tile_x = city_x + dx; + int tile_y = city_y + dy; + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID)) + continue; + + int screen_x = center_screen_x + (dx * tile_half_width); + int screen_y = center_screen_y + (dy * tile_half_height); + draw_distribution_hub_yields (this, tile, tile_x, tile_y, screen_x, screen_y); + } + } + } + +skip_district_yields: + if (changed_clip_area) + clear_clip_area (this); +} + +bool __fastcall +patch_City_Form_draw_highlighted_yields (City_Form * this, int edx, int tile_x, int tile_y, int neighbor_index) +{ + // Make sure we don't draw outside the map area + bool changed_clip_area = false; + if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { + set_clip_area_to_map_view (this); + changed_clip_area = true; + } + + bool tr = City_Form_draw_highlighted_yields (this, __, tile_x, tile_y, neighbor_index); + + if (changed_clip_area) + clear_clip_area (this); + return tr; +} + +void __fastcall +patch_City_Form_draw_border_around_workable_tiles (City_Form * this) +{ + // Make sure we don't draw outside the map area + bool changed_clip_area = false; + if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { + set_clip_area_to_map_view (this); + changed_clip_area = true; + } + + City_Form_draw_border_around_workable_tiles (this); + + if (changed_clip_area) + clear_clip_area (this); +} + +bool __fastcall +patch_City_stop_working_polluted_tile (City * this, int edx, int neighbor_index) +{ + if (is->current_config.do_not_unassign_workers_from_polluted_tiles && + (*p_human_player_bits & (1 << this->Body.CivID))) + return false; // do nothing; return value is not used + else + return City_stop_working_tile (this, __, neighbor_index); +} + +void __fastcall +patch_City_manage_by_governor (City * this, int edx, bool manage_professions) +{ + int * p_stack = (int *)&manage_professions; + int ret_addr = p_stack[-1]; + + // Do nothing if called after spawning pollution but didn't unassign worker + if ((ret_addr == ADDR_MANAGE_CITY_AFTER_POLLUTION_RETURN) && + is->current_config.do_not_unassign_workers_from_polluted_tiles && + (*p_human_player_bits & (1 << this->Body.CivID))) + return; + + City_manage_by_governor (this, __, manage_professions); +} + +City * __cdecl +patch_find_nearest_city_for_ai_alliance_eval (int tile_x, int tile_y, int owner_id, int continent_id, int ignore_owner_id, int perspective_id, City * ignore_city) +{ + City * tr = find_nearest_city (tile_x, tile_y, owner_id, continent_id, ignore_owner_id, perspective_id, ignore_city); + if (is->current_config.patch_division_by_zero_in_ai_alliance_eval && (*p_nearest_city_distance == 0)) + *p_nearest_city_distance = 1; + return tr; +} + +int __fastcall +patch_Unit_get_max_move_points (Unit * this) +{ + if (Unit_has_ability (this, __, UTA_Army) && is->current_config.patch_empty_army_movement) { + int slowest_member_mp = INT_MAX; + bool any_units_in_army = false; + FOR_UNITS_ON (uti, tile_at (this->Body.X, this->Body.Y)) { + if (uti.unit->Body.Container_Unit == this->Body.ID) { + any_units_in_army = true; + slowest_member_mp = not_above (Unit_get_max_move_points (uti.unit), slowest_member_mp); + } + } + if (any_units_in_army) + return slowest_member_mp + p_bic_data->General.RoadsMovementRate; + else + return get_max_move_points (&p_bic_data->UnitTypes[this->Body.UnitTypeID], this->Body.CivID); + } else + return Unit_get_max_move_points (this); +} + +char __fastcall +patch_Unit_is_visible_to_civ_for_bouncing (Unit * this, int edx, int civ_id, int param_2) +{ + // If we're set not to kick out invisible units and this one is invis. then report that it's not seen so it's left alone + if (is->do_not_bounce_invisible_units && Unit_has_ability (this, __, UTA_Invisible)) + return 0; + else + return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); +} + +void __fastcall +patch_Leader_make_peace (Leader * this, int edx, int civ_id) +{ + Leader_make_peace (this, __, civ_id); + + if (is->current_config.disallow_trespassing && + (! this->At_War[civ_id]) && // Make sure the war actually ended + ((this->Relation_Treaties[civ_id] & 2) == 0)) { // Check right of passage (just in case) + is->do_not_bounce_invisible_units = true; + Leader_bounce_trespassing_units (&leaders[civ_id], __, this->ID); + is->do_not_bounce_invisible_units = false; + } +} + +// This patch function replaces calls to Leader::count_wonders_with_flag but is only valid in cases where it only matters whether the return value is +// zero or non-zero. This function will not return the actual count, just zero if no wonders are present and some >0 value if there is at least one. +int __fastcall +patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) +{ + int tr = Leader_count_wonders_with_flag (this, __, flag, only_in_city); + + if ((tr == 0) && + (only_in_city == NULL) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player + + // Sum up wonders owned by other human players + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->ID)) + if (Leader_count_wonders_with_flag (&leaders[n_player], __, flag, only_in_city) > 0) { + tr = 1; + break; + } + player_bits >>= 1; + n_player++; + } + } + + return tr; +} + +int __fastcall +patch_Leader_count_wonders_with_flag_ignore_great_wall (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) +{ + if (is->current_config.enable_districts && + is->current_config.enable_great_wall_districts && + is->current_config.disable_great_wall_city_defense_bonus && + flag == ITW_Doubles_City_Defenses) + return 0; + + return patch_Leader_count_any_shared_wonders_with_flag (this, __, flag, only_in_city); +} + +int const shared_small_wonder_flags = + ITSW_Increases_Chance_of_Leader_Appearance | + ITSW_Build_Larger_Armies | + ITSW_Treasury_Earns_5_Percent | + ITSW_Decreases_Success_Of_Missile_Attacks | + ITSW_Allows_Spy_Missions | + ITSW_Allows_Healing_In_Enemy_Territory | + ITSW_Requires_Victorous_Army | + ITSE_Requires_Elite_Naval_Units; + + +int __fastcall +patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) +{ + int tr = Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); + + // If "this" is a human player who's sharing wonders in hotseat and the flag is one of the ones that gets shared, include the wonders owned by + // all other humans in the game + if ((city_or_null == NULL) && + (flag & shared_small_wonder_flags) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player + + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->ID)) + tr += Leader_count_wonders_with_small_flag (&leaders[n_player], __, flag, city_or_null); + player_bits >>= 1; + n_player++; + } + } + + return tr; +} + +int +find_human_player_with_small_wonder (int improv_id) +{ + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if (player_bits & 1) + if (leaders[n_player].Small_Wonders[improv_id] != -1) + return n_player; + player_bits >>= 1; + n_player++; + } + return -1; +} + +bool __fastcall +patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2) +{ + Improvement * improv = &p_bic_data->Improvements[i_improv]; + bool restore = false; + bool already_shared = false; + int saved_status, saved_required_building_count, saved_armies_count; + if ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) && // if the improv in question is a great or small wonder + is->current_config.share_wonders_in_hotseat && // if we're configured to share wonder effects + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // if in a hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // if "this" is a human player + + // If another human player has already built this small wonder and it has no non-shared effects, then make it unbuildable + if ((improv->Characteristics & ITC_Small_Wonder) && + (find_human_player_with_small_wonder (i_improv) != -1) && + ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) + already_shared = true; + + else { + restore = true; + saved_status = this->Status; + if (improv->RequiredBuildingID != -1) + saved_required_building_count = this->Improvement_Counts[improv->RequiredBuildingID]; + saved_armies_count = this->Armies_Count; + + // Loop over all other human players in the game + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->ID)) { + + // Combine status bits + this->Status |= leaders[n_player].Status & (LSF_HAS_VICTORIOUS_ARMY | LSF_HAS_ELITE_NAVAL_UNIT); + + // Combine building counts for the required building if there is one + if (improv->RequiredBuildingID != -1) + this->Improvement_Counts[improv->RequiredBuildingID] += leaders[n_player].Improvement_Counts[improv->RequiredBuildingID]; + + // Combine army counts + this->Armies_Count += leaders[n_player].Armies_Count; + + } + player_bits >>= 1; + n_player++; + } + } + } + + bool tr = (! already_shared) && Leader_can_build_city_improvement (this, __, i_improv, param_2); + + if (restore) { + this->Status = saved_status; + if (improv->RequiredBuildingID != -1) + this->Improvement_Counts[improv->RequiredBuildingID] = saved_required_building_count; + + this->Armies_Count = saved_armies_count; + } + return tr; + +} + +void __fastcall +patch_City_add_happiness_from_buildings (City * this, int edx, int * inout_happiness, int * inout_unhappiness) +{ + // If we're in a hotseat game with shared wonder effects, merge all human player's improvement counts together so the base function checks for + // happiness from improvements owned by other human players. + Leader * owner = &leaders[this->Body.CivID]; + bool restore_improv_counts = false; + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->Body.CivID) & *p_human_player_bits)) { // "this" is owned by a human player + + // Ensure the space we've set aside for saving the real improv counts is large enough + if ((is->saved_improv_counts == NULL) || (is->saved_improv_counts_capacity < p_bic_data->ImprovementsCount)) { + free (is->saved_improv_counts); + is->saved_improv_counts = calloc (p_bic_data->ImprovementsCount, sizeof is->saved_improv_counts[0]); + is->saved_improv_counts_capacity = (is->saved_improv_counts != NULL) ? p_bic_data->ImprovementsCount : 0; + } + + + if (is->saved_improv_counts != NULL) { + // Save the owner's real improv counts and remember to restore them before returning + restore_improv_counts = true; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + is->saved_improv_counts[n] = owner->Improvement_Counts[n]; + + // Add in improv counts for wonders from all other human players in the game + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != owner->ID)) + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (p_bic_data->Improvements[n].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + owner->Improvement_Counts[n] += leaders[n_player].Improvement_Counts[n]; + player_bits >>= 1; + n_player++; + } + } + + } + + City_add_happiness_from_buildings (this, __, inout_happiness, inout_unhappiness); + + if (is->current_config.enable_districts) { + int district_happy = 0; + calculate_district_happiness_bonus (this, &district_happy); + + if (district_happy != 0) + *inout_happiness += district_happy; + } + + if (restore_improv_counts) { + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + owner->Improvement_Counts[n] = is->saved_improv_counts[n]; + } +} + +int __fastcall +patch_City_count_other_cont_happiness_buildings (City * this, int edx, int improv_id) +{ + int tr = City_count_other_buildings_on_continent (this, __, improv_id); + + // If it's a hotseat game where we're sharing wonders, "improv_id" refers to a wonder, and "this" is owned by a human player + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((p_bic_data->Improvements[improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && + ((1 << this->Body.CivID) & *p_human_player_bits)) { + + // Add in instances of this improvment on this continent owned by other human players + Tile * this_city_tile = tile_at (this->Body.X, this->Body.Y); + int this_cont_id = this_city_tile->vtable->m46_Get_ContinentID (this_city_tile); + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city != NULL) && (city != this) && + (city->Body.CivID != this->Body.CivID) && // if city is owned by a different player AND + ((1 << city->Body.CivID) & *p_human_player_bits)) { // that player is a human + Tile * that_city_tile = tile_at (city->Body.X, city->Body.Y); + int that_cont_id = that_city_tile->vtable->m46_Get_ContinentID (that_city_tile); + if ((this_cont_id == that_cont_id) && patch_City_has_improvement (city, __, improv_id, true)) + tr++; + } + } + + } + + return tr; +} + +void __fastcall +patch_Leader_update_great_library_unlocks (Leader * this) +{ + // If it's a hotseat game with shared wonder effects and "this" is a human player, share contacts among all human players so that "this" gets + // techs from civs known to any human player in the game. Save the real contact info and restore it afterward. NOTE: Contact info has to go + // two ways here; we must mark that "this" has contacted the AIs and vice-versa otherwise the techs won't be granted. That's why we must save + // & restore all contact bits for all players. + bool restore_contacts = false; + struct contact_set { + int contacts[32]; + } saved_contact_sets[32]; + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player + + restore_contacts = true; + for (int n = 0; n < 32; n++) + for (int k = 0; k < 32; k++) + saved_contact_sets[n].contacts[k] = leaders[n].Contacts[k]; + + unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_human = 1; + while (human_player_bits != 0) { + if ((human_player_bits & 1) && (n_human != this->ID)) // n_human is ID of a human player other than "this" + for (int n_ai = 0; n_ai < 32; n_ai++) + if ((*p_player_bits & (1 << n_ai)) && ((*p_human_player_bits & (1 << n_ai)) == 0)) { + // If the human and AI players have contact, mark "this" as having contact with the AI and vice-versa + if (leaders[n_human].Contacts[n_ai] & 1) { + this->Contacts[n_ai] |= 1; + leaders[n_ai].Contacts[this->ID] |= 1; + } + } + human_player_bits >>= 1; + n_human++; + } + } + + Leader_update_great_library_unlocks (this); + + if (restore_contacts) + for (int n = 0; n < 32; n++) + for (int k = 0; k < 32; k++) + leaders[n].Contacts[k] = saved_contact_sets[n].contacts[k]; +} + +bool __fastcall +patch_Leader_has_wonder_doubling_happiness_from (Leader * this, int edx, int improv_id) +{ + bool tr = Leader_has_wonder_doubling_happiness_from (this, __, improv_id); + + // If we're sharing wonder effects in a hotseat game and "this" is a human player, return true when another human player in the game has a + // wonder doubling happiness + if ((! tr) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player + unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_human = 1; + while (human_player_bits != 0) { + if ((human_player_bits & 1) && + (n_human != this->ID) && + Leader_has_wonder_doubling_happiness_from (&leaders[n_human], __, improv_id)) { + tr = true; + break; + } + human_player_bits >>= 1; + n_human++; + } + } + + return tr; +} + +int __fastcall +patch_Sprite_draw_citizen_head (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + // Reset variable + is->specialist_icon_drawing_running_x = INT_MIN; + + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +int +adjust_specialist_yield_icon_x (int pixel_x, int width) +{ + if (is->current_config.fix_overlapping_specialist_yield_icons) { + if (is->specialist_icon_drawing_running_x == INT_MIN) // first icon drawn + is->specialist_icon_drawing_running_x = pixel_x; + int tr = is->specialist_icon_drawing_running_x; + is->specialist_icon_drawing_running_x += width; + return tr; + } else + return pixel_x; +} + +int __fastcall +patch_Sprite_draw_entertainer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_12_Happy_Faces.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_scientist_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_16_Science.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_tax_collector_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_14_Gold.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_civil_engineer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_13_Shield.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_police_officer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_17_Gold_Outcome.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} + +void __fastcall +patch_City_add_building_if_done (City * this) +{ + // If sharing small wonders in hotseat, check whether the city is building a small wonder that's no longer available to the player b/c its + // effects are provided from another. + int improv_id = this->Body.Order_ID; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + int already_built_by_id; + if ((improv->Characteristics & ITC_Small_Wonder) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->Body.CivID) & *p_human_player_bits) && // city owned by a human player + ((already_built_by_id = find_human_player_with_small_wonder (improv_id)) != -1) && // SW already built by another human player + ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) { // SW has no non-shared effects + + // Switch city production to something else and notify the player + this->vtable->set_production_to_most_expensive_option (this); + if ((this->Body.CivID == p_main_screen_form->Player_CivID) && (already_built_by_id != p_main_screen_form->Player_CivID)) { + char * new_build_name = (this->Body.Order_Type == COT_Improvement) ? + p_bic_data->Improvements[this->Body.Order_ID].Name.S : + p_bic_data->UnitTypes[this->Body.Order_ID].Name; + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, this->Body.CityName, -1, -1); + set_popup_str_param (1, improv->Name.S, -1, -1); + set_popup_str_param (2, Leader_get_civ_noun (&leaders[already_built_by_id]), -1, -1); + set_popup_str_param (3, new_build_name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_SHARED_WONDER_CHANGE", -1, 0, 0, 0); + int response = patch_show_popup (popup, __, 0, 0); + if (response == 0) + *p_zoom_to_city_after_update = true; + } + + // As in the base logic, if production gets switched, the game doesn't check if it might still complete on the same turn. + return; + } + + // If production ended up on a wonder, make sure the city can actually build it; otherwise fall back to a defensive unit. + int order_type = this->Body.Order_Type; + int order_id = this->Body.Order_ID; + if (is->current_config.enable_districts && order_type == COT_Improvement) { + Improvement * new_improv = &p_bic_data->Improvements[order_id]; // Improvement might have changed + if (new_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { + if (! (City_can_build_improvement (this, __, order_id, false) && city_meets_district_prereqs_to_build_improvement (this, order_id, true))) { + char ss[256]; + snprintf (ss, sizeof ss, "patch_City_add_building_if_done: City '%s' cannot complete building of wonder '%s'; switching to defensive unit.\n", + this->Body.CityName, + new_improv->Name.S); + (*p_OutputDebugStringA) (ss); + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (this, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) { + City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); + return; + } + } + } + } + } + + City_add_building_if_done (this); +} + +bool __fastcall +patch_City_can_build_upgrade_type (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) +{ + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + if (is->current_config.prevent_old_units_from_upgrading_past_ability_block && + ((type->Special_Actions & UCV_Upgrade_Unit) == 0) && + (type->Available_To & (1 << leaders[this->Body.CivID].RaceID))) + exclude_upgradable = false; + + return patch_City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); +} + +void __fastcall +patch_Main_GUI_position_elements (Main_GUI * this) +{ + Main_GUI_position_elements (this); + + // Double size of minimap if configured + bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || + ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); + if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) { + this->Mini_Map_Click_Rect.top -= 105; + this->Mini_Map_Click_Rect.right += 229; + } +} + +#define PEDIA_DESC_LINES_PER_PAGE 38 + +// Returns whether or not the line should be drawn +bool +do_next_line_for_pedia_desc (PCX_Image * canvas, int * inout_y) +{ + if (is->cmpd.drawing_lines && is->current_config.allow_multipage_civilopedia_descriptions) { + int first_line_on_shown_page = is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE; + int page = is->cmpd.line_count / PEDIA_DESC_LINES_PER_PAGE; + is->cmpd.line_count += 1; + is->cmpd.last_page = (page > is->cmpd.last_page) ? page : is->cmpd.last_page; + + if (page == is->cmpd.shown_page) { + *inout_y -= is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE * PCX_Image_get_text_line_height (canvas); + return true; + } else + return false; + } + return true; +} + +int __fastcall +patch_PCX_Image_do_draw_centered_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) +{ + if (do_next_line_for_pedia_desc (this, &y)) + return PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); + else + return 0; // Caller does not use return value +} + +int __fastcall +patch_PCX_Image_draw_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int str_len) +{ + if (do_next_line_for_pedia_desc (this, &y)) + return PCX_Image_draw_text (this, __, str, x, y, str_len); + else + return PCX_Image_draw_text (this, __, " ", x, y, 1); // Caller uses the return value here so draw an empty string isntead of doing nothing +} + +// Steam code is slightly different; this no-len version of draw_text gets called sometimes. It's the same as draw_text instead it computes the string +// length itself instead of taking it in as a parameter. +int __fastcall +patch_PCX_Image_draw_text_no_len_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y) +{ + return patch_PCX_Image_draw_text_in_wrap_func (this, __, str, x, y, strlen (str)); +} + +void +draw_civilopedia_article (void (__fastcall * base) (Civilopedia_Article *), Civilopedia_Article * article) +{ + // If the article changed then clear things from the old one + if (is->cmpd.article != article) { + is->cmpd.last_page = 0; + is->cmpd.shown_page = 0; + is->cmpd.article = article; + } + + is->cmpd.line_count = 0; + is->cmpd.drawing_lines = article->show_description; + + base (article); + + is->cmpd.drawing_lines = false; +} + +void __fastcall +patch_Civilopedia_Article_m01_Draw_GCON_or_RACE (Civilopedia_Article * this) +{ + draw_civilopedia_article (Civilopedia_Article_m01_Draw_GCON_or_RACE, this); +} + +void __fastcall +patch_Civilopedia_Article_m01_Draw_UNIT (Civilopedia_Article * this) +{ + draw_civilopedia_article (Civilopedia_Article_m01_Draw_UNIT, this); +} + +void __fastcall +patch_Civilopedia_Form_m53_On_Control_Click (Civilopedia_Form * this, int edx, CivilopediaControlID control_id) +{ + Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; + + // "Effects" button leaves description mode, returns to showing effects + if ((control_id == PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID) && (current_article != NULL)) { + current_article->show_description = false; + is->cmpd.shown_page = 0; + play_sound_effect (26); // 26 = SE_SELECT + p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); + + // "Previous" button shows the previous page of a multi-page description or switches to effects mode if on the first page + } else if (control_id == PEDIA_MULTIPAGE_PREV_BUTTON_ID) { + if (is->cmpd.shown_page > 0) + is->cmpd.shown_page -= 1; + else + current_article->show_description = false; + play_sound_effect (26); + p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); + + } else if ((control_id == CCID_DESCRIPTION_BTN) && // if description/more/prev button was clicked AND + (current_article != NULL) && current_article->show_description && // currently showing a description of an article AND + (is->cmpd.last_page > 0)) { // this is a multi-page description + + // Show the next page of the multi-page description unless it's a two-page description and we're on the second page, in which case go + // back to the first. + if ((is->cmpd.last_page == 1) && (is->cmpd.shown_page == 1)) + is->cmpd.shown_page = 0; + else + is->cmpd.shown_page = not_above (is->cmpd.last_page, is->cmpd.shown_page + 1); + play_sound_effect (26); + p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); + + } else + Civilopedia_Form_m53_On_Control_Click (this, __, control_id); +} + +void __fastcall +patch_Civilopedia_Form_m22_Draw (Civilopedia_Form * this) +{ + // Make sure the new buttons are not visible and the multipage variables are cleared when we exit description mode + if ((this->Current_Article_ID < 0) || ! this->Articles[this->Current_Article_ID]->show_description) { + is->cmpd.shown_page = is->cmpd.last_page = 0; + if (is->cmpd.effects_btn != NULL) + is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); + if (is->cmpd.previous_btn != NULL) + is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); + } + + Civilopedia_Form_m22_Draw (this); +} + +int __fastcall +patch_Button_initialize_civilopedia_description (Button * this, int edx, char * text, int control_id, int x, int y, int width, int height, Base_Form * parent, int param_8) +{ + Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; + if (current_article == NULL) + return Button_initialize (this, __, text, control_id, x, y, width, height, parent, param_8); + + // Set button visibility for multi-page descriptions if we're showing such a thing right now + bool show_desc_btn = true, show_effects_btn = false, show_previous_btn = false; + char * desc_btn_text = text; + if (current_article->show_description && (is->cmpd.last_page > 0)) { + + // Tribe articles act like one long descripton. + if ((current_article->article_kind == CAK_TRIBE) || (current_article->article_kind == CAK_GAME_CONCEPT)) { + + // Show the more button as long as we're not on the last page. Show the previous always since we're in description mode. + show_previous_btn = true; + desc_btn_text = (*p_labels)[LBL_MORE]; + if (is->cmpd.shown_page >= is->cmpd.last_page) + show_desc_btn = false; + + // Unit articles have separate description/effects modes. + } else if (current_article->article_kind == CAK_UNIT) { + + // For a two-page description, show the effects button and the description button which will act as a next/previous button + if (is->cmpd.last_page == 1) { + show_effects_btn = true; + desc_btn_text = is->cmpd.shown_page == 0 ? (*p_labels)[LBL_MORE] : (*p_labels)[LBL_PREVIOUS]; + + // For a three or more page description, show the effects button, and show the description button only if we're not on the + // last page (b/c it's the next button), and show the previous button only if we're not on the first page. If the desc button + // is visible, make it say "More". + } else { + show_effects_btn = true; + if (is->cmpd.shown_page >= is->cmpd.last_page) + show_desc_btn = false; + else + desc_btn_text = (*p_labels)[LBL_MORE]; + show_previous_btn = is->cmpd.shown_page > 0; + } + } + } + + int tr = Button_initialize (this, __, desc_btn_text, control_id, x, y, width, height, parent, param_8); + + if (! show_desc_btn) + this->vtable->m02_Show_Disabled ((Base_Form *)this); + + if (is->cmpd.effects_btn != NULL) { + if (show_effects_btn) + is->cmpd.effects_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.effects_btn, __, 0); + else + is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); + } + + if (is->cmpd.previous_btn != NULL) { + if (show_previous_btn) + is->cmpd.previous_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.previous_btn, __, 0); + else + is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); + } + + return tr; +} + +int __fastcall +patch_Civilopedia_Form_m68_Show_Dialog (Civilopedia_Form * this, int edx, int param_1, void * param_2, void * param_3) +{ + memset (&is->cmpd, 0, sizeof is->cmpd); + + Button * bs[] = {malloc (sizeof Button), malloc (sizeof Button)}; + for (int n = 0; n < ARRAY_LEN (bs); n++) { + if (bs[n] == NULL) + continue; + Button_construct (bs[n]); + + int desc_btn_x = 535, desc_btn_y = 222, desc_btn_height = 17; + + Button_initialize (bs[n], __, + n == 0 ? (*p_labels)[LBL_EFFECTS] : (*p_labels)[LBL_PREVIOUS], + n == 0 ? PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID : PEDIA_MULTIPAGE_PREV_BUTTON_ID, // control ID + desc_btn_x, // location x + desc_btn_y + (n == 0 ? -2 : 2) * desc_btn_height, // location y + MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height + (Base_Form *)this, // parent + 0); // ? + + for (int k = 0; k < 3; k++) + bs[n]->Images[k] = &this->Description_Btn_Images[k]; + + // Do now draw the button until needed + bs[n]->vtable->m02_Show_Disabled ((Base_Form *)bs[n]); + } + is->cmpd.effects_btn = bs[0]; + is->cmpd.previous_btn = bs[1]; + + int tr = Civilopedia_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); + + for (int n = 0; n < ARRAY_LEN (bs); n++) + if (bs[n] != NULL) { + bs[n]->vtable->destruct ((Base_Form *)bs[n], __, 0); + free (bs[n]); + } + is->cmpd.effects_btn = is->cmpd.previous_btn = NULL; + + return tr; +} + +void +init_district_images () +{ + if (is_online_game () || is->dc_img_state != IS_UNINITED) + return; + + char art_dir[200]; + char temp_path[2*MAX_PATH]; + + is->dc_img_state = IS_INIT_FAILED; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + // For each district type + for (int dc = 0; dc < is->district_count; dc++) { + struct district_config const * cfg = &is->district_configs[dc]; + int variant_count = cfg->img_path_count; + if (variant_count <= 0) + continue; + + int era_count = cfg->vary_img_by_era ? 4 : 1; + int column_count = cfg->img_column_count; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + + // For each cultural variant + for (int variant_i = 0; variant_i < variant_count; variant_i++) { + if (cfg->img_paths[variant_i] == NULL) + continue; + + // Read PCX file + snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", cfg->img_paths[variant_i]); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + + if (pcx.JGL.Image == NULL) { + + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load district images from %s", temp_path); + pop_up_in_game_error (ss); + + (*p_OutputDebugStringA) ("[C3X] Failed to load districts sprite sheet.\n"); + for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) + for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) + for (int era_i = 0; era_i < 4; era_i++) { + for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { + Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + } + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + // For each era + for (int era_i = 0; era_i < era_count; era_i++) { + + // For each column in the image (variations on the district image for that era) + for (int col_i = 0; col_i < column_count; col_i++) { + Sprite_construct (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i]); + + int x = sprite_width * col_i, + y = sprite_height * era_i; + Sprite_slice_pcx (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i], __, &pcx, x, y, sprite_width, sprite_height, 1, 1); + } + } + + pcx.vtable->clear_JGL (&pcx); + } + } + // Load abandoned district images (land + maritime) + get_mod_art_path ("Districts/1200/Abandoned.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + + if (pcx.JGL.Image == NULL) { + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load abandoned district images from %s", temp_path); + pop_up_in_game_error (ss); + for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) + for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) + for (int era_i = 0; era_i < 4; era_i++) { + for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { + Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + } + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + Sprite_construct (&is->abandoned_district_img); + Sprite_slice_pcx (&is->abandoned_district_img, __, &pcx, 0, 0, 128, 64, 1, 1); + + Sprite_construct (&is->abandoned_maritime_district_img); + Sprite_slice_pcx (&is->abandoned_maritime_district_img, __, &pcx, 128, 0, 128, 64, 1, 1); + pcx.vtable->clear_JGL (&pcx); + + // Load wonder district images (dynamically per wonder) + if (is->current_config.enable_wonder_districts) { + char const * last_img_path = NULL; + PCX_Image wpcx; + PCX_Image_construct (&wpcx); + bool pcx_loaded = false; + + for (int wi = 0; wi < is->wonder_district_count; wi++) { + struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; + char const * img_path = cfg->img_path; + if (img_path == NULL) + img_path = "Wonders.pcx"; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + + // Load new image file if different from previous + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + + snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + PCX_Image_read_file (&wpcx, __, temp_path, NULL, 0, 0x100, 2); + + if (wpcx.JGL.Image == NULL) { + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load wonder district images from %s", temp_path); + pop_up_in_game_error (ss); + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; + + Sprite_construct (&set->img); + int x = sprite_width * cfg->img_column; + int y = sprite_height * cfg->img_row; + Sprite_slice_pcx (&set->img, __, &wpcx, x, y, sprite_width, sprite_height, 1, 1); + + Sprite_construct (&set->construct_img); + int cx = sprite_width * cfg->img_construct_column; + int cy = sprite_height * cfg->img_construct_row; + Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, sprite_width, sprite_height, 1, 1); + + if (cfg->enable_img_alt_dir) { + Sprite_construct (&set->alt_dir_img); + int ax = sprite_width * cfg->img_alt_dir_column; + int ay = sprite_height * cfg->img_alt_dir_row; + Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, sprite_width, sprite_height, 1, 1); + + Sprite_construct (&set->alt_dir_construct_img); + int acx = sprite_width * cfg->img_alt_dir_construct_column; + int acy = sprite_height * cfg->img_alt_dir_construct_row; + Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, sprite_width, sprite_height, 1, 1); + } + } + + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + wpcx.vtable->destruct (&wpcx, __, 0); + } + + if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { + char const * last_img_path = NULL; + PCX_Image nwpcx; + PCX_Image_construct (&nwpcx); + bool pcx_loaded = false; + + for (int ni = 0; ni < is->natural_wonder_count; ni++) { + struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[ni]; + if (cfg->name == NULL) + continue; + + char const * img_path = cfg->img_path; + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + + snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + PCX_Image_read_file (&nwpcx, __, temp_path, NULL, 0, 0x100, 2); + + if (nwpcx.JGL.Image == NULL) { + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load natural wonder images from %s", temp_path); + pop_up_in_game_error (ss); + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + Sprite_construct (&is->natural_wonder_img_sets[ni].img); + int x = 128 * cfg->img_column; + int y = 88 * cfg->img_row; + Sprite_slice_pcx (&is->natural_wonder_img_sets[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); + } + + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + nwpcx.vtable->destruct (&nwpcx, __, 0); + } + + is->dc_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +bool +tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv) +{ + Tile * center = tile_at (tile_x, tile_y); + + if ((center == NULL) || (center == p_null_tile)) return false; + int owner_id = center->Territory_OwnerID; + if (owner_id <= 0) return false; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + if (has_active_building (wai.city, i_improv)) + return true; + } + + return false; +} + +bool +wonder_requires_river (struct wonder_district_config const * cfg) +{ + unsigned int build_mask = wonder_buildable_square_type_mask (cfg); + if (build_mask == 0) + build_mask = district_default_buildable_mask (); + if ((build_mask & square_type_mask_bit (SQ_RIVER)) != 0) + return true; + if (cfg->buildable_on_rivers) + return true; + return false; +} + +Tile * +get_tile_sprite_indices (int tile_x, int tile_y, int * out_sheet_index, int * out_sprite_index) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + + if (tile != NULL && tile != p_null_tile) { + *out_sheet_index = (tile->SquareParts >> 8) & 0xFF; + *out_sprite_index = tile->SquareParts & 0xFF; + } else { + *out_sheet_index = -1; + *out_sprite_index = -1; + } + + return tile; +} + +void +align_district_with_river (Tile * tile, int * out_pixel_x, int * out_pixel_y, enum direction * out_dir) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return; + + enum direction dir = DIR_ZERO; + if (! get_primary_river_direction (tile, &dir)) + return; + + int dx, dy; + int offset = 36; + direction_to_offset (dir, &dx, &dy); + + dy = 0; + switch (dir) { + case DIR_N: dy = -offset; break; + case DIR_NE: dy = -offset/2; break; + case DIR_E: dy = 0; break; + case DIR_SE: dy = offset/2; break; + case DIR_S: dy = offset; break; + case DIR_SW: dy = offset/2; break; + case DIR_W: dy = 0; break; + case DIR_NW: dy = -offset/2; break; + default: break; + } + + if (out_pixel_x != NULL) + *out_pixel_x += dx; + if (out_pixel_y != NULL) + *out_pixel_y += dy; + if (out_dir != NULL) + *out_dir = dir; +} + +void +align_variant_and_pixel_offsets_with_coastline (Tile * tile, int * out_variant, int * out_pixel_x, int * out_pixel_y) +{ + if ((tile == NULL) || (tile == p_null_tile) || (out_variant == NULL)) + return; + + int owner_id = tile->Territory_OwnerID; + if (owner_id <= 0) + return; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return; + + int tile_x = inst->tile_x; + int tile_y = inst->tile_y; + Map * map = &p_bic_data->Map; + + City * closest_city = NULL; + int closest_dx = 0, closest_dy = 0; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + City * city = wai.city; + int ndx = city->Body.X - tile_x; + int ndy = city->Body.Y - tile_y; + + if (map->Flags & 1) { + int half_width = map->Width / 2; + if (ndx > half_width) + ndx -= map->Width; + else if (ndx < -half_width) + ndx += map->Width; + } + if (map->Flags & 2) { + int half_height = map->Height / 2; + if (ndy > half_height) + ndy -= map->Height; + else if (ndy < -half_height) + ndy += map->Height; + } + + closest_city = city; + closest_dx = ndx; + closest_dy = ndy; + break; + } + + if (closest_city == NULL) + return; + + bool city_is_directly_above_port = (closest_dx == 0) && (closest_dy == -2); + bool city_is_directly_below_port = (closest_dx == 0) && (closest_dy == 2); + bool city_is_directly_west_of_port = (closest_dx < 0) && (closest_dy == 0); + bool city_is_directly_east_of_port = (closest_dx > 0) && (closest_dy == 0); + bool city_is_directly_northeast_of_port = (closest_dx == 1) && (closest_dy == -1); + bool city_is_directly_southeast_of_port = (closest_dx == 1) && (closest_dy == 1); + bool city_is_directly_southwest_of_port = (closest_dx == -1) && (closest_dy == 1); + bool city_is_directly_northwest_of_port = (closest_dx == -1) && (closest_dy == -1); + + // Variant indices; can't use direction enum as values are slightly different + int NONE = -1; + int NW = 0; + int NE = 1; + int SE = 2; + int SW = 3; + *out_variant = NONE; + + enum direction anchor = NONE; + bool direct_diagonal = false; + + // Direct diagonals + if (city_is_directly_northeast_of_port) { *out_variant = SW; anchor = DIR_NE; direct_diagonal = true; } + else if (city_is_directly_southeast_of_port) { *out_variant = NW; anchor = DIR_SE; direct_diagonal = true; } + else if (city_is_directly_southwest_of_port) { *out_variant = NE; anchor = DIR_SW; direct_diagonal = true; } + else if (city_is_directly_northwest_of_port) { *out_variant = SE; anchor = DIR_NW; direct_diagonal = true; } + + // City either in a direct cardinal direction or not adjacent, check relative directions + else { + bool city_is_west_of_port = (closest_dx < 0); + bool city_is_east_of_port = (closest_dx > 0); + bool city_is_north_of_port = (closest_dy < 0); + bool city_is_south_of_port = (closest_dy > 0); + bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, true); + bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, true); + bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); + bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); + bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); + bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, true); + bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, true); + bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, true); + + if (city_is_directly_above_port) { + if (northwest_tile_is_land && ! tile_is_land (owner_id, tile_x + 1, tile_y + 1, true)) { + *out_variant = SE; anchor = DIR_NW; + } else if (northeast_tile_is_land && ! tile_is_land (owner_id, tile_x - 1, tile_y + 1, true)) { + *out_variant = SW; anchor = DIR_NE; + } else { + *out_variant = SW; anchor = DIR_NE; + *out_pixel_x -= 4; *out_pixel_y -= 4; + } + } else if (city_is_directly_below_port) { + if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else { + *out_variant = NE; anchor = DIR_SW; + *out_pixel_x += 4; *out_pixel_y += 4; + } + } else if (city_is_directly_west_of_port) { + if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else { + *out_variant = SE; anchor = DIR_NW; + *out_pixel_x -= 30; *out_pixel_y += 24; + } + } else if (city_is_directly_east_of_port) { + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else { + *out_variant = SW; anchor = DIR_NE; + *out_pixel_x += 30; *out_pixel_y -= 24; + } + } else if (city_is_north_of_port && city_is_west_of_port) { + if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + } else if (city_is_north_of_port && city_is_east_of_port) { + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + } else if (city_is_south_of_port && city_is_east_of_port) { + if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + } else if (city_is_south_of_port && city_is_west_of_port) { + if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + } + + // No ideal direction, pick based on any owner land tiles around port + if (*out_variant == NONE) { + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } + else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } + else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } + else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } + } + + // Same civ doesn't own any adjacent land tiles, pick based on *any* land tiles + if (*out_variant == NONE) { + bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); + bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); + bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); + bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); + bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); + bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); + bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); + bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } + else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } + else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } + else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } + else { *out_variant = SW; anchor = DIR_NE; } // Somehow no land tiles at all? Default to NE + } + } + + Tile * anchor_tile; + int anchor_sheet_index, anchor_sprite_index; + switch (anchor) { + case DIR_N: anchor_tile = get_tile_sprite_indices (tile_x, tile_y - 2, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_NE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_E: anchor_tile = get_tile_sprite_indices (tile_x + 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_SE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_S: anchor_tile = get_tile_sprite_indices (tile_x, tile_y + 2, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_SW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_W: anchor_tile = get_tile_sprite_indices (tile_x - 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_NW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; + default: anchor_sheet_index = -1; anchor_sprite_index = -1; break; + } + + bool anchor_is_hill = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Hills; + bool anchor_is_mountain = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Mountains; + + // Determine general pixel offsets based on direction & anchor + if (*out_variant == SW && anchor == DIR_NE) { *out_pixel_x -= 0; *out_pixel_y += 6; } + else if (*out_variant == SE && anchor == DIR_NW) { *out_pixel_x -= 2; *out_pixel_y += 6; } + else if (*out_variant == NW && anchor == DIR_SE) { *out_pixel_x -= 0; *out_pixel_y -= 2; } + else if (*out_variant == SW && anchor == DIR_N) { *out_pixel_x -= 56; *out_pixel_y -= 26; } + else if (*out_variant == SW && anchor == DIR_E) { *out_pixel_x += 36; *out_pixel_y += 18; } + else if (*out_variant == NE && anchor == DIR_S) { *out_pixel_x += 70; *out_pixel_y += 30; } + else if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 14; } + + // Handle edge cases. Tedious, but looks quite a bit better so worth it + if (! (anchor_is_hill || anchor_is_mountain) && ! direct_diagonal) { + if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 20; } + + // Sheet 0 + if (anchor_sheet_index == 0) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 32; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 32; } + + if ((*out_variant == NE || *out_variant == NW) && anchor == DIR_S && anchor_sprite_index == 26) { *out_pixel_x -= 4; *out_pixel_y += 30; } + else if (*out_variant == NE && anchor == DIR_SW && anchor_sprite_index == 20) { *out_pixel_x -= 2; *out_pixel_y += 4; } + + if (*out_variant == SW && (anchor_sprite_index == 0 || anchor_sprite_index == 4 || anchor_sprite_index == 10 || anchor_sprite_index == 1)) { *out_pixel_x +=2; *out_pixel_y -= 8; } + else if (*out_variant == SW && anchor == DIR_N && (anchor_sprite_index == 6)) { *out_pixel_x -= 6; *out_pixel_y -= 8; } + else if (*out_variant == SE && anchor == DIR_W && (anchor_sprite_index == 18)) { *out_pixel_x += 6; *out_pixel_y += 4; } + else if (*out_variant == NE && anchor == DIR_SW && (anchor_sprite_index == 51)) { *out_pixel_x += 20; *out_pixel_y -= 20; } + else if (*out_variant == SW && anchor == DIR_NE && (anchor_sprite_index == 0)) { *out_pixel_x -= 4; *out_pixel_y += 4; } + else if (*out_variant == NW && anchor == DIR_SE && (anchor_sprite_index == 44)) { *out_pixel_x -= 8; *out_pixel_y -= 12; } + } + // Sheet 1 + else if (anchor_sheet_index == 1) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 10; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 10; } + + if (*out_variant == SW && (anchor_sprite_index == 7 || anchor_sprite_index == 17 || anchor_sprite_index == 16)) { *out_pixel_x +=10; *out_pixel_y -= 8; } + } + // Sheet 3 + else if (anchor_sheet_index == 2) { + if (*out_variant == SW && (anchor_sprite_index == 6)) { *out_pixel_x +=2; *out_pixel_y -= 8; } + } + // Sheet 3 + else if (anchor_sheet_index == 3) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 16; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 16; } + + if (*out_variant == SW && (anchor_sprite_index == 43 || anchor_sprite_index == 40)) { *out_pixel_x +=6; *out_pixel_y -= 12; } + else if (*out_variant == SW && (anchor_sprite_index == 35 || anchor_sprite_index == 39)) { *out_pixel_x +=6; *out_pixel_y -= 12; } + else if (*out_variant == SE && (anchor_sprite_index == 50)) { *out_pixel_x -=6; *out_pixel_y -= 12; } + else if (*out_variant == SE && (anchor_sprite_index == 26)) { *out_pixel_x += 50; *out_pixel_y -= 2; } + } + // Sheet 4 + else if (anchor_sheet_index == 4) { + if (*out_variant == SW && (anchor_sprite_index == 71)) { *out_pixel_x +=2; *out_pixel_y -= 8; } + } + // Sheet 5 + else if (anchor_sheet_index == 5) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 18; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 18; } + + if ((*out_variant == SW || *out_variant == SE) && anchor_sprite_index == 18) { *out_pixel_y -= 10; } + else if (*out_variant == SW && anchor_sprite_index == 73) { *out_pixel_x -=4; *out_pixel_y -= 10; } + else if (*out_variant == NW && anchor == DIR_SE && anchor_sprite_index == 42) { *out_pixel_y -= 8; } + else if ((*out_variant == NW || *out_variant == SW) && anchor_sprite_index == 6) { *out_pixel_x += 12; *out_pixel_y -= 6; } + else if ((*out_variant == SW) && anchor_sprite_index == 16) { *out_pixel_x -=8; *out_pixel_y -= 10; } + } + } + else if (direct_diagonal && *out_variant == SW && anchor == DIR_NE) { *out_pixel_x -=8; *out_pixel_y -= 8; } + else if (direct_diagonal && *out_variant == SE && anchor == DIR_NW) { *out_pixel_x -=8; *out_pixel_y -= 8; } + else if (direct_diagonal && *out_variant == NW && anchor == DIR_SE) { *out_pixel_x +=6; *out_pixel_y += 6; } + else if (direct_diagonal && *out_variant == NE && anchor == DIR_SW) { *out_pixel_x +=6; *out_pixel_y += 6; } +} + +bool +wonder_should_use_alternative_direction_image (int tile_x, int tile_y, int owner_id, struct wonder_district_config const * cfg) +{ + if (owner_id <= 0) + return false; + + // We only care about the nearest same-civ city in the work area around the tile. + // Assumes the base wonder art (img_row/column) faces west and the alt art faces east. + // To "face away" from the nearest city, we pick the alt art when that city lies to the east. + Tile * center = is->current_render_tile; + if ((center == NULL) || (center == p_null_tile)) + return false; + + // If on a river and the wonder allows river alignment, make sure we face the river instead + bool allow_river = wonder_requires_river (cfg); + if (allow_river) { + enum direction river_dir = DIR_ZERO; + if (get_primary_river_direction (center, &river_dir)) { + int dx, dy; + + if (direction_to_offset (river_dir, &dx, &dy)) { + // I'm not completely sure of the logic here, but this seems to match the vanilla behavior + // in terms of having the wonder face the general direction of the river flow + if (dx == 2) + return false; + + return dx > 0; + } + } + } + + // Else face away from the nearest same-civ city + Map * map = &p_bic_data->Map; + int best_dist = INT_MAX; + int best_dx = 0; + int city_dx = 0; + int city_dy = 0; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + City * city = wai.city; + if ((city == NULL) || (city->Body.CivID != owner_id)) + continue; + + int dx = city->Body.X - tile_x; + int dy = city->Body.Y - tile_y; + + if (map->Flags & 1) { + int half_width = map->Width >> 1; + if (dx > half_width) + dx -= map->Width; + else if (dx < -half_width) + dx += map->Width; + } + if (map->Flags & 2) { + int half_height = map->Height >> 1; + if (dy > half_height) + dy -= map->Height; + else if (dy < -half_height) + dy += map->Height; + } + + int dist = int_abs (dx) + int_abs (dy); + // Pick the closest city; if tied, favor the one with a clearer east/west offset so we know which way to face. + if ((dist < best_dist) || + ((dist == best_dist) && ((int_abs (dx) < int_abs (best_dx)) || (best_dx == 0)))) { + best_dist = dist; + best_dx = dx; + city_dx = city->Body.X; + city_dy = city->Body.Y; + } + } + + bool city_is_directly_above_port = city_dx == tile_x && city_dy == tile_y - 2; + bool city_is_directly_below_port = city_dx == tile_x && city_dy == tile_y + 2; + + if (city_is_directly_above_port || city_is_directly_below_port) { + bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); + bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); + bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); + + if (northeast_tile_is_land || east_tile_is_land || southeast_tile_is_land) + return true; + } + + if ((best_dist == INT_MAX) || (best_dx == 0)) + return false; + + return best_dx > 0; +} + +void +draw_district_on_map_or_canvas(Sprite * sprite, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (is->tile_info_open) { + PCX_Image * canvas = (PCX_Image *)map_renderer; + patch_Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, NULL); + return; + } + + patch_Sprite_draw_on_map (sprite, __, map_renderer, pixel_x, pixel_y, 1, 1, (p_bic_data->is_zoomed_out != false) + 1, 0); +} + +int +get_energy_grid_image_index (int tile_x, int tile_y) +{ + struct district_infos * info = &is->district_infos[ENERGY_GRID_DISTRICT_ID]; + for (int i = 0; i < info->dependent_building_count; i++) { + // Zero is "no building"; Buildings start from index one + int column_index = i + 1; + int building_id = info->dependent_building_ids[i]; + if (tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) + return column_index; + } + + return 0; +} + +int +get_bridge_image_index (Tile * tile, int tile_x, int tile_y) +{ + int SW_NE = 0; + int NW_SE = 1; + int N_S = 2; + int W_E = 3; + + if ((tile->vtable->m42_Get_Overlays (tile, __, 0) & TILE_FLAG_RAILROAD) != 0) { + SW_NE += 4; + NW_SE += 4; + N_S += 4; + W_E += 4; + } + + bool bridge_n = tile_has_district_at (tile_x, tile_y - 2, BRIDGE_DISTRICT_ID); + bool bridge_s = tile_has_district_at (tile_x, tile_y + 2, BRIDGE_DISTRICT_ID); + bool bridge_w = tile_has_district_at (tile_x - 2, tile_y, BRIDGE_DISTRICT_ID); + bool bridge_e = tile_has_district_at (tile_x + 2, tile_y, BRIDGE_DISTRICT_ID); + bool bridge_ne = tile_has_district_at (tile_x + 1, tile_y - 1, BRIDGE_DISTRICT_ID); + bool bridge_nw = tile_has_district_at (tile_x - 1, tile_y - 1, BRIDGE_DISTRICT_ID); + bool bridge_se = tile_has_district_at (tile_x + 1, tile_y + 1, BRIDGE_DISTRICT_ID); + bool bridge_sw = tile_has_district_at (tile_x - 1, tile_y + 1, BRIDGE_DISTRICT_ID); + + if (bridge_n || bridge_s || bridge_w || bridge_e || bridge_ne || bridge_nw || bridge_se || bridge_sw) { + int ns_count = (bridge_n ? 1 : 0) + (bridge_s ? 1 : 0); + int we_count = (bridge_w ? 1 : 0) + (bridge_e ? 1 : 0); + int swne_count = (bridge_sw ? 1 : 0) + (bridge_ne ? 1 : 0); + int nwse_count = (bridge_nw ? 1 : 0) + (bridge_se ? 1 : 0); + + if (swne_count == 2) return SW_NE; + if (nwse_count == 2) return NW_SE; + if (ns_count == 2) return N_S; + if (we_count == 2) return W_E; + + if (bridge_ne || bridge_sw) return SW_NE; + if (bridge_nw || bridge_se) return NW_SE; + if (bridge_n || bridge_s) return N_S; + if (bridge_w || bridge_e) return W_E; + } + + int owner_id = tile->Territory_OwnerID; + bool north_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); + bool south_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); + bool west_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); + bool east_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); + bool ne_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); + bool nw_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); + bool se_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); + bool sw_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); + + bool north_link = north_land || bridge_n; + bool south_link = south_land || bridge_s; + bool west_link = west_land || bridge_w; + bool east_link = east_land || bridge_e; + bool ne_link = ne_land || bridge_ne; + bool nw_link = nw_land || bridge_nw; + bool se_link = se_land || bridge_se; + bool sw_link = sw_land || bridge_sw; + + if (sw_link && ne_link) return SW_NE; + if (nw_link && se_link) return NW_SE; + if (north_link && south_link) return N_S; + if (west_link && east_link) return W_E; + + if (ne_link || sw_link) return SW_NE; + if (nw_link || se_link) return NW_SE; + if (north_link || south_link) return N_S; + if (west_link || east_link) return W_E; + + return SW_NE; +} + +void +get_bridge_directions (Tile * tile, int tile_x, int tile_y, int * out_dir1, int * out_dir2) +{ + int dir1 = -1; + int dir2 = -1; + int index = get_bridge_image_index (tile, tile_x, tile_y); + + switch (index) { + case 0: dir1 = DIR_SW; dir2 = DIR_NE; break; + case 1: dir1 = DIR_NW; dir2 = DIR_SE; break; + case 2: dir1 = DIR_N; dir2 = DIR_S; break; + case 3: dir1 = DIR_W; dir2 = DIR_E; break; + default: break; + } + + *out_dir1 = dir1; + *out_dir2 = dir2; +} + +void +get_canal_directions (Tile * tile, int tile_x, int tile_y, bool out_water_dirs[9], int * out_dir1, int * out_dir2) +{ + bool canal_at_n = tile_has_district_at (tile_x, tile_y - 2, CANAL_DISTRICT_ID); + bool canal_at_s = tile_has_district_at (tile_x, tile_y + 2, CANAL_DISTRICT_ID); + bool canal_at_w = tile_has_district_at (tile_x - 2, tile_y, CANAL_DISTRICT_ID); + bool canal_at_e = tile_has_district_at (tile_x + 2, tile_y, CANAL_DISTRICT_ID); + bool canal_at_ne = tile_has_district_at (tile_x + 1, tile_y - 1, CANAL_DISTRICT_ID); + bool canal_at_nw = tile_has_district_at (tile_x - 1, tile_y - 1, CANAL_DISTRICT_ID); + bool canal_at_se = tile_has_district_at (tile_x + 1, tile_y + 1, CANAL_DISTRICT_ID); + bool canal_at_sw = tile_has_district_at (tile_x - 1, tile_y + 1, CANAL_DISTRICT_ID); + bool water_n = tile_is_water (tile_x, tile_y - 2); + bool water_s = tile_is_water (tile_x, tile_y + 2); + bool water_w = tile_is_water (tile_x - 2, tile_y); + bool water_e = tile_is_water (tile_x + 2, tile_y); + bool water_ne = tile_is_water (tile_x + 1, tile_y - 1); + bool water_nw = tile_is_water (tile_x - 1, tile_y - 1); + bool water_se = tile_is_water (tile_x + 1, tile_y + 1); + bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); + bool canal_or_water_n = canal_at_n || water_n; + bool canal_or_water_s = canal_at_s || water_s; + bool canal_or_water_w = canal_at_w || water_w; + bool canal_or_water_e = canal_at_e || water_e; + bool canal_or_water_ne = canal_at_ne || water_ne; + bool canal_or_water_nw = canal_at_nw || water_nw; + bool canal_or_water_se = canal_at_se || water_se; + bool canal_or_water_sw = canal_at_sw || water_sw; + + bool canal_dirs[9] = { + false, canal_at_ne, canal_at_e, canal_at_se, + canal_at_s, canal_at_sw, canal_at_w, canal_at_nw, canal_at_n + }; + bool water_dirs[9] = { + false, water_ne, water_e, water_se, + water_s, water_sw, water_w, water_nw, water_n + }; + bool available_dirs[9] = { + false, canal_or_water_ne, canal_or_water_e, canal_or_water_se, + canal_or_water_s, canal_or_water_sw, canal_or_water_w, canal_or_water_nw, canal_or_water_n + }; + + // Avoid acute angles (adjacent directions) that look cramped. + int disallowed_pairs[][2] = { + { DIR_N, DIR_NE }, { DIR_NE, DIR_E }, { DIR_E, DIR_SE }, { DIR_SE, DIR_S }, + { DIR_S, DIR_SW }, { DIR_SW, DIR_W }, { DIR_W, DIR_NW }, { DIR_NW, DIR_N } + }; + int disallowed_pair_count = sizeof(disallowed_pairs) / sizeof(disallowed_pairs[0]); + int pref_dirs[8] = { DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_N, DIR_E, DIR_S, DIR_W }; + + int dir1 = -1; + int dir2 = -1; + + bool has_canal_dir = canal_dirs[DIR_N] || canal_dirs[DIR_NE] || canal_dirs[DIR_E] || canal_dirs[DIR_SE] || + canal_dirs[DIR_S] || canal_dirs[DIR_SW] || canal_dirs[DIR_W] || canal_dirs[DIR_NW]; + + if (has_canal_dir) { + for (int i = 0; i < 8 && dir1 == -1; i++) { + int d = pref_dirs[i]; + if (canal_dirs[d]) + dir1 = d; + } + } else { + for (int i = 0; i < 8 && dir1 == -1; i++) { + int d = pref_dirs[i]; + if (available_dirs[d]) + dir1 = d; + } + } + + if (dir1 >= 0) { + for (int pass = 0; pass < 2 && dir2 == -1; pass++) { + bool * dirs = (pass == 0) ? canal_dirs : available_dirs; + for (int i = 0; i < 8; i++) { + int d = pref_dirs[i]; + if (d == dir1 || ! dirs[d]) + continue; + bool pair_is_too_close = false; + for (int k = 0; k < disallowed_pair_count; k++) { + if ((dir1 == disallowed_pairs[k][0] && d == disallowed_pairs[k][1]) || + (dir1 == disallowed_pairs[k][1] && d == disallowed_pairs[k][0])) { + pair_is_too_close = true; + break; + } + } + if (pair_is_too_close) + continue; + dir2 = d; + break; + } + } + } + + int draw_dir1 = dir1; + int draw_dir2 = dir2; + if ((draw_dir1 >= 0) && (draw_dir2 >= 0)) { + int weight1 = 0; + int weight2 = 0; + + if (draw_dir1 == DIR_S) weight1 = 2; + else if ((draw_dir1 == DIR_SE) || (draw_dir1 == DIR_SW)) weight1 = 1; + else if ((draw_dir1 == DIR_NE) || (draw_dir1 == DIR_NW) || (draw_dir1 == DIR_N)) weight1 = -1; + + if (draw_dir2 == DIR_S) weight2 = 2; + else if ((draw_dir2 == DIR_SE) || (draw_dir2 == DIR_SW)) weight2 = 1; + else if ((draw_dir2 == DIR_NE) || (draw_dir2 == DIR_NW) || (draw_dir2 == DIR_N)) weight2 = -1; + + if (weight1 > weight2) { + int tmp = draw_dir1; + draw_dir1 = draw_dir2; + draw_dir2 = tmp; + } + } + + // Manual overrides - overall algorithm works pretty well, but handle corner cases + if (!has_canal_dir && water_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir1 = DIR_NE; draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && water_dirs[DIR_N] && water_dirs[DIR_NE]) { draw_dir1 = DIR_N; draw_dir2 = DIR_S; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_SE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_NE] && water_dirs[DIR_N]) { draw_dir1 = DIR_N; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && water_dirs[DIR_S]) { draw_dir2 = DIR_S; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && canal_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && canal_dirs[DIR_NE] && water_dirs[DIR_S]) { draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NW && draw_dir2 == DIR_NE && canal_dirs[DIR_NW] && water_dirs[DIR_SE]) { draw_dir2 = DIR_SE; } + if (draw_dir1 == DIR_NW && draw_dir2 == DIR_S && canal_dirs[DIR_NW] && water_dirs[DIR_S]) { draw_dir2 = DIR_SE; } + + *out_dir1 = draw_dir1; + *out_dir2 = draw_dir2; + for (int i = 0; i < 9; i++) + out_water_dirs[i] = water_dirs[i]; +} + +void +draw_canal_on_map_or_canvas(Sprite * sprite, int tile_x, int tile_y, int dir, bool water_dirs[9], Map_Renderer * map_renderer, int draw_x, int draw_y) +{ + int y_offset = 9; + int x_offset = y_offset * 2; + + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y); + + // In certain cases, add an additional draw if adjacent to water so that the canal appears to extend far enough + if (dir == DIR_N && water_dirs[DIR_N]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y - y_offset); + else if (dir == DIR_NE && water_dirs[DIR_NE]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y - y_offset); + else if (dir == DIR_E && water_dirs[DIR_E]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y); + else if (dir == DIR_SE && water_dirs[DIR_SE]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y + y_offset); + else if (dir == DIR_S && water_dirs[DIR_S]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y + y_offset); + else if (dir == DIR_SW && water_dirs[DIR_SW]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y + y_offset); + else if (dir == DIR_W && water_dirs[DIR_W]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y); + else if (dir == DIR_NW && water_dirs[DIR_NW]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y - y_offset); +} + +void +draw_canal_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int era) +{ + struct district_config const * cfg = &is->district_configs[CANAL_DISTRICT_ID]; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + int offset_x = pixel_x + cfg->x_offset; + int offset_y = pixel_y + cfg->y_offset; + int dir1_draw_x = offset_x - ((sprite_width - 128) / 2); + int dir1_draw_y = offset_y - (sprite_height - 64); + int dir2_draw_x = dir1_draw_x; + int dir2_draw_y = dir1_draw_y; + + int draw_dir1 = -1; + int draw_dir2 = -1; + bool water_dirs[9] = { false, false, false, false, false, false, false, false, false }; + get_canal_directions (tile, tile_x, tile_y, water_dirs, &draw_dir1, &draw_dir2); + + // Set offsets based on directions for (literal) edge cases + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S) { dir1_draw_x += 7; dir1_draw_y -= 2; } + else if (draw_dir1 == DIR_N && draw_dir2 == DIR_W) { dir2_draw_x -= 12; } + else if (draw_dir1 == DIR_N && draw_dir2 == DIR_SE) { dir2_draw_x += 4; } + + if (draw_dir1 >= 0) { + Sprite * sprite1 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir1]; + draw_canal_on_map_or_canvas(sprite1, tile_x, tile_y, draw_dir1, water_dirs, map_renderer, dir1_draw_x, dir1_draw_y); + } + + if (draw_dir2 >= 0) { + Sprite * sprite2 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir2]; + draw_canal_on_map_or_canvas(sprite2, tile_x, tile_y, draw_dir2, water_dirs, map_renderer, dir2_draw_x, dir2_draw_y); + } +} + +void +draw_great_wall_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + bool wall_nw = tile_has_district_at (tile_x - 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); + bool wall_ne = tile_has_district_at (tile_x + 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); + bool wall_se = tile_has_district_at (tile_x + 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); + bool wall_sw = tile_has_district_at (tile_x - 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); + bool wall_s = tile_has_district_at (tile_x, tile_y + 2, GREAT_WALL_DISTRICT_ID); + bool wall_n = tile_has_district_at (tile_x, tile_y - 2, GREAT_WALL_DISTRICT_ID); + + bool water_ne = tile_is_water (tile_x - 1, tile_y - 1); + bool water_nw = tile_is_water (tile_x + 1, tile_y - 1); + bool water_w = tile_is_water (tile_x - 2, tile_y); + bool water_n = tile_is_water (tile_x, tile_y + 2); + bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); + bool water_se = tile_is_water (tile_x + 1, tile_y + 1); + + Sprite * sprites = is->district_img_sets[GREAT_WALL_DISTRICT_ID].imgs[0][0]; + Sprite * base = &sprites[0]; + + // Rotate around clockwise NW -> SW to get the perspective right + if (wall_nw) draw_district_on_map_or_canvas(&sprites[DIR_NW], map_renderer, pixel_x, pixel_y); + if (wall_ne) draw_district_on_map_or_canvas(&sprites[DIR_NE], map_renderer, pixel_x, pixel_y); + + // Base pillar + draw_district_on_map_or_canvas(base, map_renderer, pixel_x, pixel_y); + + if (wall_sw) draw_district_on_map_or_canvas(&sprites[DIR_SW], map_renderer, pixel_x, pixel_y); + if (wall_se) draw_district_on_map_or_canvas(&sprites[DIR_SE], map_renderer, pixel_x, pixel_y); +} + +void +draw_district_generated_resource_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, + int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) +{ + int base_resource = Tile_get_resource_visible_to (tile, __, visible_to_civ_id); + int district_resource = -1; + + if (inst->state == DS_COMPLETED) { + int district_id = inst->district_id; + if ((district_id >= 0) && (district_id < is->district_count)) { + struct district_config * cfg = &is->district_configs[district_id]; + if (cfg->generated_resource_id >= 0) { + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_id >= 0) && ((visible_to_civ_id < 0) || (owner_id == visible_to_civ_id))) { + int res_id = cfg->generated_resource_id; + if (district_generates_resource_for_civ (tile, inst, cfg, owner_id)) + district_resource = res_id; + } + } + } + } + + if (district_resource < 0) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; + int offset = tile_width >> 2; + int left_x = pixel_x - (offset >> 1); + int right_x = pixel_x + (offset >> 1); + + int icon_id = p_bic_data->ResourceTypes[district_resource].IconID; + Sprite * sprite = NULL; + Map_Renderer * resource_renderer = is->tile_info_open ? &p_bic_data->Map.Renderer : map_renderer; + int resource_sprite_count = 0; + if ((resource_renderer != NULL) && (resource_renderer->Resources != NULL)) + // The renderer allocates Resources as a counted heap array: the int stored just before the + // first Sprite is the number of entries loaded from resources.pcx. + resource_sprite_count = ((int *)resource_renderer->Resources)[-1]; + if ((icon_id < 0) || (icon_id >= resource_sprite_count)) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + sprite = &resource_renderer->Resources[icon_id]; + if (sprite == NULL) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + if (base_resource >= 0) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, left_x, pixel_y); + } + + int tile_height = tile_width >> 1; + int sprite_width = sprite->Width; + int sprite_height = sprite->Height; + if (sprite_width <= 0) sprite_width = sprite->Width3; + if (sprite_height <= 0) sprite_height = sprite->Height3; + int center_x = (tile_width - sprite_width) >> 1; + int center_y = (tile_height - sprite_height) >> 1; + int draw_x = (base_resource >= 0) ? right_x : pixel_x; + draw_x += center_x; + int draw_y = pixel_y + center_y; + if (is->tile_info_open) { + PCX_Image * canvas = (PCX_Image *)map_renderer; + patch_Sprite_draw (sprite, __, canvas, draw_x, draw_y, NULL); + } else { + int draw_scale = (p_bic_data->is_zoomed_out != false) + 1; + patch_Sprite_draw_on_map (sprite, __, map_renderer, draw_x, draw_y, 1, 1, draw_scale, 0); + } +} + +int +count_completed_buildings_in_district_radius (int tile_x, int tile_y, int district_id) +{ + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos * district_info = &is->district_infos[district_id]; + int completed_count = 0; + for (int i = 0; i < district_info->dependent_building_count; i++) { + int building_id = district_info->dependent_building_ids[i]; + if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) + completed_count++; + } + return completed_count; +} + +void +draw_district_on_map_or_canvas_by_buildings (Sprite * base_sprite, Map_Renderer * map_renderer, int district_id, int variant, int era, int tile_x, int tile_y, int draw_x, int draw_y) +{ + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos * district_info = &is->district_infos[district_id]; + + draw_district_on_map_or_canvas(base_sprite, map_renderer, draw_x, draw_y); + + for (int i = 0; i < district_info->dependent_building_count; i++) { + // Zero is "base texture"; Actual building column art starts from index one + int column_index = i + 1; + int building_id = district_info->dependent_building_ids[i]; + if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) { + Sprite * district_sprite = &is->district_img_sets[district_id].imgs[variant][era][column_index]; + draw_district_on_map_or_canvas(district_sprite, map_renderer, draw_x, draw_y); + } + } +} + +void +draw_district_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) +{ + int district_id = inst->district_id; + if (is->dc_img_state == IS_UNINITED) + init_district_images (); + + if (is->dc_img_state != IS_OK) + return; + + // Natural Wonder + if (district_id == NATURAL_WONDER_DISTRICT_ID) { + if (! is->current_config.enable_natural_wonders) + return; + + int natural_id = inst->natural_wonder_info.natural_wonder_id; + if ((natural_id >= 0) && (natural_id < is->natural_wonder_count)) { + Sprite * nsprite = &is->natural_wonder_img_sets[natural_id].img; + int y_offset = 88 - 64; // Height of wonder img minus height of tile + int draw_y = pixel_y - y_offset; + + draw_district_on_map_or_canvas(nsprite, map_renderer, pixel_x, draw_y); + } + return; + } + + // Districts + if (is->current_config.enable_districts) { + if (district_id < 0 || district_id >= is->district_count) return; + bool completed = district_is_complete (tile, district_id); + + if (! completed) + return; + + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos * district_info = &is->district_infos[district_id]; + int territory_owner_id = tile->Territory_OwnerID; + int variant = 0; + int era = 0; + int culture = 0; + int buildings = 0; + int draw_pixel_x = pixel_x; + int draw_pixel_y = pixel_y; + enum direction river_dir = DIR_ZERO; + + // If in a territory, use owner's culture/era + if (territory_owner_id > 0) { + Leader * leader = &leaders[territory_owner_id]; + culture = p_bic_data->Races[leader->RaceID].CultureGroupID; + if (cfg->vary_img_by_culture) + variant = culture; + if (cfg->vary_img_by_era) + era = leader->Era; + if (cfg->align_to_coast) + align_variant_and_pixel_offsets_with_coastline (tile, &variant, &draw_pixel_x, &draw_pixel_y); + + // Else render abandoned if not a Wonder, Natural Wonder, Bridge, or Canal + } else if (district_id != WONDER_DISTRICT_ID && district_id != NATURAL_WONDER_DISTRICT_ID && district_id != BRIDGE_DISTRICT_ID && district_id != CANAL_DISTRICT_ID) { + Sprite * abandoned_sprite = &is->abandoned_district_img; + if (tile->vtable->m35_Check_Is_Water (tile) && is->abandoned_maritime_district_img.vtable != NULL) + abandoned_sprite = &is->abandoned_maritime_district_img; + if (abandoned_sprite->vtable != NULL) { + draw_district_on_map_or_canvas(abandoned_sprite, map_renderer, draw_pixel_x + cfg->x_offset, draw_pixel_y + cfg->y_offset); + } + return; + } + + // If out of a territory (and not abandoned) but builder is known, use builder's era & culture + if (territory_owner_id < 0 && inst->built_by_civ_id >= 0) { + Leader * builder = &leaders[inst->built_by_civ_id]; + culture = p_bic_data->Races[builder->RaceID].CultureGroupID; + if (cfg->vary_img_by_culture) + variant = culture; + if (cfg->vary_img_by_era) + era = builder->Era; + } + + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + int offset_x = draw_pixel_x + cfg->x_offset; + int offset_y = draw_pixel_y + cfg->y_offset; + int draw_x = offset_x - ((sprite_width - 128) / 2); + int draw_y = offset_y - (sprite_height - 64); + Sprite (*sprites)[MAX_DISTRICT_ERA_COUNT][MAX_DISTRICT_COLUMN_COUNT] = is->district_img_sets[district_id].imgs; + + // Render + switch (district_id) { + case WONDER_DISTRICT_ID: + { + if (! is->current_config.enable_wonder_districts) + return; + + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info == NULL) + return; + + int construct_windex = -1; + Sprite * wsprite = NULL; + + struct wonder_district_config * wcfg = NULL; + struct wonder_district_image_set * set = NULL; + + // Completed + if (info->state == WDS_COMPLETED) { + int windex = info->wonder_index; + if ((windex < 0) || (windex >= is->wonder_district_count)) + return; + wcfg = &is->wonder_district_configs[windex]; + set = &is->wonder_district_img_sets[windex]; + // Under construction + } else if (wonder_district_tile_under_construction (tile, tile_x, tile_y, &construct_windex) && (construct_windex >= 0)) { + if (construct_windex >= is->wonder_district_count) + return; + wcfg = &is->wonder_district_configs[construct_windex]; + set = &is->wonder_district_img_sets[construct_windex]; + // Unused + } else { + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + + if (wonder_requires_river(wcfg)) + align_district_with_river (tile, &draw_pixel_x, &draw_pixel_y, &river_dir); + + int wonder_width = (wcfg->custom_width > 0) ? wcfg->custom_width : 128; + int wonder_height = (wcfg->custom_height > 0) ? wcfg->custom_height : 64; + int wonder_offset_x = draw_pixel_x + cfg->x_offset; + int wonder_offset_y = draw_pixel_y + cfg->y_offset; + int wonder_draw_x = wonder_offset_x - ((wonder_width - 128) / 2); + int wonder_draw_y = wonder_offset_y - (wonder_height - 64); + + bool use_alt_dir = wcfg->enable_img_alt_dir && wonder_should_use_alternative_direction_image (tile_x, tile_y, territory_owner_id, wcfg); + if (info->state == WDS_COMPLETED) + wsprite = (use_alt_dir && (set->alt_dir_img.vtable != NULL)) ? &set->alt_dir_img : &set->img; + else + wsprite = (use_alt_dir && (set->alt_dir_construct_img.vtable != NULL)) ? &set->alt_dir_construct_img : &set->construct_img; + + draw_district_on_map_or_canvas(wsprite, map_renderer, wonder_draw_x, wonder_draw_y); + return; + } + case NEIGHBORHOOD_DISTRICT_ID: + { + if (! is->current_config.enable_neighborhood_districts) + return; + + unsigned v = (unsigned)tile_x * 0x9E3779B1u + (unsigned)tile_y * 0x85EBCA6Bu; + v ^= v >> 16; + v *= 0x7FEB352Du; + v ^= v >> 15; + v *= 0x846CA68Bu; + v ^= v >> 16; + buildings = clamp(0, 3, (int)(v & 3u)); /* final 0..3 */ + variant = culture; + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + case DISTRIBUTION_HUB_DISTRICT_ID: + if (! is->current_config.enable_distribution_hub_districts) + return; + + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + case ENERGY_GRID_DISTRICT_ID: + { + if (! is->current_config.enable_energy_grid_districts) + return; + + buildings = get_energy_grid_image_index (tile_x, tile_y); + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + case BRIDGE_DISTRICT_ID: + { + if (! is->current_config.enable_bridge_districts) + return; + + buildings = get_bridge_image_index (tile, tile_x, tile_y); + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + case CANAL_DISTRICT_ID: + { + if (! is->current_config.enable_canal_districts) + return; + + draw_canal_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y, era); + return; + } + case GREAT_WALL_DISTRICT_ID: + { + if (! is->current_config.enable_great_wall_districts) + return; + + draw_great_wall_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + default: + { + // Draw by counting number of completed buildings in radius + if (cfg->render_strategy == DRS_BY_COUNT) { + buildings = count_completed_buildings_in_district_radius (tile_x, tile_y, district_id); + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + // Draw by checking each building individually and layering images + else if (cfg->render_strategy == DRS_BY_BUILDING) { + Sprite * base_sprite = &is->district_img_sets[district_id].imgs[variant][era][0]; + draw_district_on_map_or_canvas_by_buildings(base_sprite, map_renderer, district_id, variant, era, tile_x, tile_y, draw_x, draw_y); + return; + } + } + } + } + + Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Map_Renderer_m12_Draw_Tile_Buildings(Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { + Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + Tile * tile = is->current_render_tile; + if (is->tile_info_open) + tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if ((tile == NULL) || (tile == p_null_tile)) + return; + + struct district_instance * inst = is->current_render_tile_district; + if (is->tile_info_open) + inst = get_district_instance (tile); + if (inst == NULL) { + Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + // Draw resources first if needed + if (is->district_configs[inst->district_id].draw_over_resources) + draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); + + draw_district_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); +} + +void __fastcall +patch_Map_Renderer_m09_Draw_Tile_Resources (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (! is->current_config.enable_districts) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + Tile * tile = is->current_render_tile; + if (is->tile_info_open) + tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if ((tile == NULL) || (tile == p_null_tile)) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + struct district_instance * inst = is->current_render_tile_district; + if (is->tile_info_open) + inst = get_district_instance (tile); + if (inst == NULL) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + // Resources that should be drawn below district are already drawn, skip in that case + if (is->district_configs[inst->district_id].draw_over_resources) + return; + + draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); +} + +void __fastcall +patch_Map_Renderer_m11_Draw_Tile_Irrigation (Map_Renderer *this, int edx, int visible_to_civ, int tile_x, int tile_y, int param_4, int param_5, int param_6) +{ + if (! is->current_config.enable_districts) { + Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); + return; + } + + struct district_instance * inst = is->current_render_tile_district; + if (inst == NULL) { + Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); + return; + } + + // If it has a completed district that serves as pseudo-irrigation source, suppress drawing irrigation + if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (is->current_render_tile, inst->district_id)) + return; + + Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); +} + +bool __fastcall +patch_Tile_has_city_or_district (Tile * this) +{ + bool has_city = Tile_has_city (this); + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + return has_city || (get_district_instance (this) != NULL); + } + return has_city; +} + +int __fastcall +patch_Tile_check_water_for_navigator_cell_coloring (Tile * this) +{ + if (! is->current_config.show_territory_colors_on_water_tiles_in_minimap) + return this->vtable->m35_Check_Is_Water (this); + else + return 0; +} + +bool +is_skippable_popup (char * text_key) +{ + char * skippable_keys[] = {"SUMMARY_END_GOLDEN_AGE", "SUMMARY_END_SCIENCE_AGE", "SUMMARY_NEW_SMALL_WONDER", // unimportant domestic things + "WONDERPRODUCE", // another civ completed a wonder + "MAKEPEACE", "MUTUALPROTECTIONPACT", "MILITARYALLIANCE", "SUMMARY_DECLARE_WAR", // diplo events not involving the player + "TRADEEMBARGOENDS", // embargo vs player ends + "SUMMARY_CIV_DESTROYED_BY_CIV", "SUMMARY_CIV_DESTROYED", // foreign civs destroyed not by player + "LOSTGOOD", // 'We lost our supply of ...!' + "TRADEEMBARGO", "MILITARYALLIANCEWARONUS", "MILITARYALLIANCEAGAINSTUS", // trade embargo or alliance vs player + "SUMMARY_TRAVELERS_REPORT"}; // another civs starts a wonder + + for (int n = 0; n < ARRAY_LEN (skippable_keys); n++) + if (strcmp (text_key, skippable_keys[n]) == 0) + return true; + return false; +} + +int __fastcall +patch_PopupForm_impl_begin_showing_popup (PopupForm * this) +{ + if (is_online_game () || + (! is->current_config.convert_some_popups_into_online_mp_messages) || + (! is_skippable_popup (this->text_key))) + return PopupForm_impl_begin_showing_popup (this); + + else { + unsigned saved_prefs = *p_preferences; + int saved_flags = this->field_1BF0[0xE4]; + + *p_preferences |= P_SHOW_FEWER_MP_POPUPS; + this->field_1BF0[0xE4] |= 0x4000; + int tr = PopupForm_impl_begin_showing_popup (this); + + *(bool *)(p_main_screen_form->animator.field_18E4 + 10) = true; // Set what must be a dirty flag + Animator_update (&p_main_screen_form->animator); // Make sure message appears + + this->field_1BF0[0xE4] = saved_flags; + *p_preferences = saved_prefs; + + return tr; + } +} + +bool __stdcall +patch_is_online_game_for_show_popup () +{ + return is->current_config.convert_some_popups_into_online_mp_messages ? true : is_online_game (); +} + +bool +ai_move_district_worker (Unit * worker, struct district_worker_record * rec) +{ + if ((worker == NULL) || (rec == NULL)) + return false; + + char ss[200]; + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d assigned to build district\n", worker->Body.ID); + (*p_OutputDebugStringA) (ss); + + // Check the original request city made for district + struct pending_district_request * req = rec->pending_req; + if ((req == NULL) || + (req->assigned_worker_id != worker->Body.ID) || + (req->target_x < 0) || (req->target_y < 0)) + return false; + + int district_id = req->district_id; + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d moving to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); + (*p_OutputDebugStringA) (ss); + + City * request_city = get_city_ptr (req->city_id); + if (request_city == NULL) { + clear_tracked_worker_assignment (rec); + remove_pending_district_request (req); + return false; + } + req->city = request_city; + struct district_config * cfg = &is->district_configs[district_id]; + Tile * target_tile = tile_at (req->target_x, req->target_y); + if ((target_tile == NULL) || (target_tile == p_null_tile) || + (target_tile->vtable->m38_Get_Territory_OwnerID (target_tile) != worker->Body.CivID) || + (! city_radius_contains_tile (request_city, req->target_x, req->target_y))) { + clear_city_district_request (request_city, req->district_id); + return false; + } + + // If the worker has arrived + if ((worker->Body.X == req->target_x) && (worker->Body.Y == req->target_y)) { + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d arrived at (%d,%d) to build district\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + Tile * tile = tile_at (worker->Body.X, worker->Body.Y); + struct district_instance * inst = get_district_instance (tile); + bool do_replacement = false; + + // If there is a completed district here already + if ((inst != NULL) && district_is_complete (tile, inst->district_id)) { + int existing_district_id = inst->district_id; + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d found existing district ID %d at (%d,%d)\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + if (existing_district_id == req->district_id) { + clear_city_district_request (request_city, req->district_id); + clear_tracked_worker_assignment (rec); + return false; + } + + // Allow replacement of unused wonder districts + if (existing_district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = &inst->wonder_info; + if (info->state == WDS_UNUSED) + do_replacement = true; + } else if (district_is_obsolete_for_civ (existing_district_id, request_city->Body.CivID)) { + do_replacement = true; + } else { + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d cannot replace existing district ID %d at (%d,%d), cancelling request\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + clear_city_district_request (request_city, req->district_id); + return false; + } + + if (!do_replacement) { + return false; // Nothing left to do here + } + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for duplicate districts near city at (%d,%d)\n", request_city->Body.X, request_city->Body.Y); + (*p_OutputDebugStringA) (ss); + + // One final check: do we still need the district? Check for any dupes nearby + if (req->district_id != DISTRIBUTION_HUB_DISTRICT_ID && req->district_id != NEIGHBORHOOD_DISTRICT_ID) { + FOR_DISTRICTS_AROUND (wai, request_city->Body.X, request_city->Body.Y, false) { + if (wai.tile == tile) + continue; + + if (wai.district_inst->district_id == req->district_id) { + snprintf (ss, sizeof ss, "ai_move_district_worker: Found duplicate district ID %d near city at (%d,%d), cancelling request\n", req->district_id, request_city->Body.X, request_city->Body.Y); + (*p_OutputDebugStringA) (ss); + clear_city_district_request (request_city, req->district_id); + return false; + } + } + } + + // Need to make sure distro hubs get roads. If this will be one, build the road first to be sure + if (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID) { + bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); + if (! has_road && ! cfg->auto_add_road) { + Unit_set_state(worker, __, UnitState_Build_Road); + worker->Body.Job_ID = WJ_Build_Road; + return true; + } + } + + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); + bool district_buildable_here = district_is_buildable_on_tile (&is->district_configs[req->district_id], tile); + + // Remove any existing improvements + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); + if (do_replacement) { + remove_district_instance (tile); + handle_district_removed (tile, req->district_id, worker->Body.X, worker->Body.Y, false); + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for craters or pollution at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + if (tile->vtable->m21_Check_Crates (tile, __, 0) || tile->vtable->m20_Check_Pollution (tile, __, 0)) { + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d clearing craters or pollution at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + Unit_set_state(worker, __, UnitState_Clear_Damage); + worker->Body.Job_ID = WJ_Clean_Pollution; + return true; + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for forest or wetlands at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + // Clear any forest/wetlands + if (! district_buildable_here && base_type == SQ_Forest) { + Unit_set_state(worker, __, UnitState_Clear_Forest); + worker->Body.Job_ID = WJ_Clean_Forest; + return true; + } else if (! district_buildable_here && ((base_type == SQ_Jungle) || (base_type == SQ_Swamp))) { + Unit_set_state(worker, __, UnitState_Clear_Wetlands); + worker->Body.Job_ID = WJ_Clear_Swamp; + return true; + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d starting construction of district at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + // Clear any existing improvements (irrigation and mines) + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); + + // Start construction of district + inst = ensure_district_instance (tile, req->district_id, req->target_x, req->target_y); + inst->built_by_civ_id = worker->Body.CivID; + Unit_set_state(worker, __, UnitState_Build_Mines); + worker->Body.Job_ID = WJ_Build_Mines; // Build district + return true; + + // Else if the worker needs to be sent + } else { + if ((worker->Body.UnitState != UnitState_Go_To) || + (worker->Body.path_dest_x != req->target_x) || + (worker->Body.path_dest_y != req->target_y)) { + int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, + worker->Body.X, worker->Body.Y, req->target_x, req->target_y, + worker, worker->Body.CivID, 0x41, NULL); + if (path_result > 0) { + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d path set to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); + (*p_OutputDebugStringA) (ss); + + Unit_set_escortee (worker, __, -1); + Unit_set_state (worker, __, UnitState_Go_To); + worker->Body.path_dest_x = req->target_x; + worker->Body.path_dest_y = req->target_y; + } else { + clear_tracked_worker_assignment (rec); + return false; + } + } + } + return false; +} + +bool +ai_worker_try_tile_improvement_district (Unit * worker) +{ + if (! is->current_config.enable_districts || worker == NULL) return false; + if (! is_worker (worker)) return false; + if (worker->Body.Auto_CityID < 0) return false; + + City * city = get_city_ptr (worker->Body.Auto_CityID); + if (city == NULL) return false; + if (city->Body.CivID != worker->Body.CivID) return false; + + int civ_id = worker->Body.CivID; + int tile_x = worker->Body.X; + int tile_y = worker->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (tile->CityID >= 0) return false; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; + if (! city_radius_contains_tile (city, tile_x, tile_y)) return false; + if (get_district_instance (tile) != NULL) return false; + + // Evaluate whether the best improvement here is irrigation, mines, or a district, using heuristics based on city needs + int food_weight = (city->Body.FoodIncome < city->Body.FoodRequired) ? 3 : 1; + int shield_weight = (city->Body.ProductionIncome < city->Body.Population.Size) ? 2 : 1; + int unhappy_percent = + city->Body.UnhappyNoReasonPercent + + city->Body.UnhappyCrowdedPercent + + city->Body.UnhappyWarWearinessPercent + + city->Body.UnhappyAgresssionPercent + + city->Body.UnhappyPropagandaPercent + + city->Body.UnhappyDraftPercent + + city->Body.UnhappyOppressionPercent + + city->Body.UnhappyThisCityImprovementsPercent + + city->Body.UnhappyOtherCityImprovementsPercent; + int happiness_weight = (unhappy_percent > 0) ? 2 : 1; + int gold_weight = 1; + int resource_boost = 5 * (food_weight + shield_weight + gold_weight + happiness_weight); + + int irrigation_score = INT_MIN; + if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Irrigate, tile_x, tile_y, 0) && + ! tile->vtable->m17_Check_Irrigation (tile, __, 0)) { + int base_type = tile->vtable->m50_Get_Square_BaseType (tile); + int bonus = p_bic_data->TileTypes[base_type].IrrigationBonus; + if (bonus < 0) + bonus = 0; + irrigation_score = bonus * food_weight; + } + + int mine_score = INT_MIN; + if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Build_Mines, tile_x, tile_y, 0) && + ! tile->vtable->m18_Check_Mines (tile, __, 0)) { + int base_type = tile->vtable->m50_Get_Square_BaseType (tile); + int bonus = p_bic_data->TileTypes[base_type].MiningBonus; + if (bonus < 0) + bonus = 0; + mine_score = bonus * shield_weight; + } + + int best_score = INT_MIN; + int best_district_id = -1; + for (int i = 0; i < is->district_count; i++) { + struct district_config const * cfg = &is->district_configs[i]; + if (cfg->ai_build_strategy != DABS_TILE_IMPROVEMENT) + continue; + if (! can_build_district_on_tile (tile, i, civ_id)) + continue; + + struct district_instance temp = {0}; + temp.district_id = i; + temp.tile_x = (short)tile_x; + temp.tile_y = (short)tile_y; + + int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; + get_effective_district_yields (&temp, cfg, &food, &shields, &gold, &science, &culture, &happiness); + + int score = food * food_weight + shields * shield_weight + gold * gold_weight; + score += (science + culture) / 2; + score += happiness * happiness_weight; + if ((cfg->generated_resource_id >= 0) && + ! patch_City_has_resource (city, __, cfg->generated_resource_id)) + score += resource_boost; + + if (score > best_score) { + best_score = score; + best_district_id = i; + } + } + + if ((best_district_id >= 0) && + (best_score >= irrigation_score) && + (best_score >= mine_score)) { + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + if (removable_flags != 0) + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); + ensure_district_instance (tile, best_district_id, tile_x, tile_y); + Unit_set_state (worker, __, UnitState_Build_Mines); + worker->Body.Job_ID = WJ_Build_Mines; + return true; + } + + return false; +} + +void __fastcall +patch_Unit_ai_move_terraformer (Unit * this) +{ + Map * map = &p_bic_data->Map; + int type_id = this->Body.UnitTypeID; + int civ_id = this->Body.CivID; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + int territory_owner = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m38_Get_Territory_OwnerID (tile) : -1; + + + if (is->current_config.enable_districts && ! is_human && is_worker (this)) { + update_tracked_worker_for_unit (this); + struct district_instance * inst = get_district_instance (tile); + + if ((territory_owner == civ_id) && + inst != NULL && inst->district_id != NATURAL_WONDER_DISTRICT_ID && + tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Coast) { + // Roads should be made after district builds. The district is complete but + // worker is still likely on the tile, so check here and build road if needed + struct district_config * cfg = &is->district_configs[inst->district_id]; + bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); + if (! has_road && ! cfg->auto_add_road) { + Unit_set_state(this, __, UnitState_Build_Road); + this->Body.Job_ID = WJ_Build_Road; + return; + } + + // Same check for railroads + bool can_build_railroad = Leader_can_do_worker_job (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y, 0); + bool has_railroad = (*tile->vtable->m23_Check_Railroads)(tile, __, 0); + if (can_build_railroad && !has_railroad && ! cfg->auto_add_railroad) { + Unit_set_state(this, __, UnitState_Build_Railroad); + this->Body.Job_ID = WJ_Build_Railroad; + return; + } + } + + struct district_worker_record * rec = get_tracked_worker_record (this); + if (rec != NULL && rec->pending_req != NULL) { + if (ai_move_district_worker (this, rec)) + return; + } + + if ((this->Body.Auto_CityID >= 0) && ai_worker_try_tile_improvement_district (this)) + return; + } + + bool pop_else_caravan; + if ((tile != NULL) && (tile != p_null_tile) && + (type_id >= 0) && (type_id < p_bic_data->UnitTypeCount) && + is_material_unit (&p_bic_data->UnitTypes[type_id], &pop_else_caravan) && + ((pop_else_caravan && is->current_config.enable_pop_unit_ai) || + ((! pop_else_caravan) && is->current_config.enable_caravan_unit_ai))) { + ai_move_material_unit (this); + return; + } + + Unit_ai_move_terraformer (this); +} + +bool __fastcall +patch_Unit_ai_can_sacrifice (Unit * this, int edx, bool requires_city) +{ + int sacrifice_action = UCV_Sacrifice & 0x0FFFFFFF; // Mask out top four category bits + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.patch_ai_can_sacrifice_without_special_ability && ((type->Special_Actions & sacrifice_action) == 0)) + return false; + else + return Unit_ai_can_sacrifice (this, __, requires_city); +} + +int __cdecl +patch_get_building_defense_bonus_at (int x, int y, int param_3) +{ + // Get base building defense bonus first + int base = get_building_defense_bonus_at (x, y, param_3); + + // If districts are disabled, return base + if (!is->current_config.enable_districts) + return base; + + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + struct district_config const * cfg = &is->district_configs[inst->district_id]; + int bonus = cfg->defense_bonus_percent; + bonus += apply_district_bonus_entries (inst, &cfg->defense_bonus_extras, inst->district_id); + return bonus; + } + + return base; +} + +void __fastcall +patch_Unit_select (Unit * this) +{ + if (is->current_config.enable_districts) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && is_worker(this) && inst->district_id >= 0 && inst->district_id <= is->district_count && + ! district_is_complete (tile, inst->district_id)) { + int district_id = inst->district_id; + PopupForm * popup = get_popup_form (); + int remaining_turns = get_worker_remaining_turns_to_complete (this, __, 0); + set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); + set_popup_int_param (1, remaining_turns); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_CANCEL_BUILD_DISTRICT", -1, 0, 0, 0); + + int sel = patch_show_popup (popup, __, 0, 0); + if (sel == 0) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, 0); + + bool other_workers_present = false; + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit != NULL) && (unit != this) && + (unit->Body.UnitState == UnitState_Build_Mines) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { + other_workers_present = true; + break; + } + } + if (! other_workers_present) { + remove_district_instance (tile); + } + } else { + return; + } + } + } + + // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + + Unit_select (this); +} + +void __fastcall +patch_City_Form_draw_food_income_icons (City_Form * this) +{ + // Call original function first + City_Form_draw_food_income_icons (this); + + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) + return; + + // Get current city + City * city = this->CurrentCity; + if (city == NULL) + return; + + // Calculate standard district food bonus + int standard_district_food = 0; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int district_id = wai.district_inst->district_id; + int food_bonus = 0; + get_effective_district_yields (wai.district_inst, &is->district_configs[district_id], &food_bonus, NULL, NULL, NULL, NULL, NULL); + standard_district_food += food_bonus; + } + + // Get distribution hub food bonus + int distribution_hub_food = 0; + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) + get_distribution_hub_yields_for_city (city, &distribution_hub_food, NULL); + + // Total district food + int total_district_food = standard_district_food + distribution_hub_food; + if (total_district_food <= 0) + return; + + // Lazy load icons + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { + if (is->distribution_hub_icons_img_state == IS_UNINITED) + init_distribution_hub_icons (); + if (is->distribution_hub_icons_img_state != IS_OK) + return; + } + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + if (is->dc_icons_img_state != IS_OK) + return; + + int food_income = city->Body.FoodIncome; + int food_required = city->Body.FoodRequired; + + // Calculate how standard district food icons are distributed + int standard_food_eaten = 0; + int standard_food_surplus = 0; + if (standard_district_food > 0) { + if (standard_district_food >= food_income) { + standard_food_surplus = food_income; + standard_food_eaten = standard_district_food - food_income; + } else { + standard_food_surplus = standard_district_food; + standard_food_eaten = 0; + } + } + + // Calculate how distribution hub food icons are distributed + int hub_food_eaten = 0; + int hub_food_surplus = 0; + int remaining_income = food_income - standard_food_surplus; + if (distribution_hub_food > 0) { + if (distribution_hub_food >= remaining_income) { + hub_food_surplus = remaining_income; + hub_food_eaten = distribution_hub_food - remaining_income; + } else { + hub_food_surplus = distribution_hub_food; + hub_food_eaten = 0; + } + } + + // Draw eaten district food icons (left side, from right to left) + int total_eaten = standard_food_eaten + hub_food_eaten; + if (total_eaten > 0) { + Sprite * base_eaten_sprite = &(this->City_Icons_Images).Icon_07; + int eaten_sprite_width = base_eaten_sprite->Width; + int eaten_sprite_height = base_eaten_sprite->Height; + struct tagRECT * eaten_rect = &this->Food_Consumption_Rect; + int eaten_rect_width = eaten_rect->right - eaten_rect->left; + + int eaten_spacing = eaten_sprite_width; + if ((food_required > 1) && (food_required * eaten_sprite_width - eaten_rect_width != 0) && + (eaten_rect_width <= food_required * eaten_sprite_width)) { + eaten_spacing = (eaten_rect_width - eaten_sprite_width) / (food_required - 1); + if (eaten_spacing < 1) + eaten_spacing = 1; + else if (eaten_spacing > eaten_sprite_width) + eaten_spacing = eaten_sprite_width; + } + + int eaten_x_offset = eaten_spacing * (food_required - 1); + // Draw standard district eaten first + for (int i = 0; i < standard_food_eaten && i < food_required; i++) { + int x = eaten_rect->left + eaten_x_offset; + int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - + (eaten_sprite_height >> 1)); + Sprite_draw (&is->district_food_eaten_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + eaten_x_offset -= eaten_spacing; + } + // Draw distribution hub eaten + for (int i = 0; i < hub_food_eaten && eaten_x_offset >= 0; i++) { + int x = eaten_rect->left + eaten_x_offset; + int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - + (eaten_sprite_height >> 1)); + Sprite_draw (&is->distribution_hub_eaten_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + eaten_x_offset -= eaten_spacing; + } + } + + // Draw surplus district food icons (right side, from right to left) + int total_surplus = standard_food_surplus + hub_food_surplus; + if (total_surplus > 0) { + Sprite * base_surplus_sprite = &(this->City_Icons_Images).Icon_06; + int surplus_sprite_width = base_surplus_sprite->Width; + int surplus_sprite_height = base_surplus_sprite->Height; + struct tagRECT * surplus_rect = &this->Food_Storage_Rect; + int surplus_rect_width = surplus_rect->right - surplus_rect->left; + + int surplus_spacing = surplus_sprite_width; + if ((food_income > 1) && (food_income * surplus_sprite_width - surplus_rect_width != 0) && + (surplus_rect_width <= food_income * surplus_sprite_width)) { + surplus_spacing = (surplus_rect_width - surplus_sprite_width) / (food_income - 1); + if (surplus_spacing < 1) + surplus_spacing = 1; + else if (surplus_spacing > surplus_sprite_width) + surplus_spacing = surplus_sprite_width; + } + + int surplus_x_offset = 0; + // Draw standard district surplus first + for (int i = 0; i < standard_food_surplus && i < food_income; i++) { + int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; + int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - + (surplus_sprite_height >> 1)) - 1; + Sprite_draw (&is->district_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + surplus_x_offset += surplus_spacing; + } + // Draw distribution hub surplus + for (int i = 0; i < hub_food_surplus && surplus_x_offset < surplus_rect_width; i++) { + int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; + int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - + (surplus_sprite_height >> 1)) - 1; + Sprite_draw (&is->distribution_hub_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + surplus_x_offset += surplus_spacing; + } + } +} + +void +recompute_district_and_distribution_hub_shields_for_city_view (City * city) +{ + if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) + return; + + int city_id = city->Body.ID; + int city_x = city->Body.X; + int city_y = city->Body.Y; + + // District yields are injected through the city center tile in patch_City_calc_tile_yield_while_gathering. + // Grab the base yield (no districts) directly from the original function, then compute the + // district bonus that calculate_city_center_district_bonus will layer on afterward. + int city_center_base_shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, city_x, city_y); + int total_district_shield_bonus = 0; + calculate_city_center_district_bonus (city, NULL, &total_district_shield_bonus, NULL); + + // Distribution hub contribution is tracked separately for icon rendering. + int distribution_hub_shields = 0; + if (is->current_config.enable_distribution_hub_districts) + get_distribution_hub_yields_for_city (city, NULL, &distribution_hub_shields); + if (distribution_hub_shields < 0) + distribution_hub_shields = 0; + if (distribution_hub_shields > total_district_shield_bonus) + distribution_hub_shields = total_district_shield_bonus; + + int standard_district_shields = total_district_shield_bonus - distribution_hub_shields; + if (standard_district_shields < 0) + standard_district_shields = 0; + + // Recompute yields with districts active so ProductionIncome/Loss reflect the city view. + recompute_city_yields_with_districts (city); + int total_production_income = city->Body.ProductionIncome; + int total_production_loss = city->Body.ProductionLoss; + int total_net_shields = total_production_income + total_production_loss; // ProductionLoss stored as negative + + // Remove the district bonus from the gross tile production and recompute corruption on that base value. + int city_center_with_districts = city_center_base_shields + total_district_shield_bonus; + int gross_without_specials = city->Body.Tiles_Production - (city_center_with_districts - city_center_base_shields); + if (gross_without_specials < 0) + gross_without_specials = 0; + + int base_corruption_abs = patch_City_compute_corrupted_yield (city, __, gross_without_specials, true); + if (base_corruption_abs < 0) + base_corruption_abs = 0; + int base_production_loss = -base_corruption_abs; + + // Corruption becomes more negative as it increases. + int additional_corruption = total_production_loss - base_production_loss; + + int district_shields_remaining = standard_district_shields; + int hub_shields_remaining = distribution_hub_shields; + + if (additional_corruption < 0) { + int extra_loss = -additional_corruption; + + if (district_shields_remaining > 0) { + int from_districts = (extra_loss < district_shields_remaining) ? extra_loss : district_shields_remaining; + district_shields_remaining -= from_districts; + extra_loss -= from_districts; + } + + if ((extra_loss > 0) && (hub_shields_remaining > 0)) { + int from_hub = (extra_loss < hub_shields_remaining) ? extra_loss : hub_shields_remaining; + hub_shields_remaining -= from_hub; + extra_loss -= from_hub; + } + } + + int non_district_shields_remaining = total_net_shields - district_shields_remaining - hub_shields_remaining; + if (non_district_shields_remaining < 0) + non_district_shields_remaining = 0; + + int total_corruption = -total_production_loss; + if (total_corruption < 0) + total_corruption = 0; + int district_corruption = standard_district_shields - district_shields_remaining; + int hub_corruption = distribution_hub_shields - hub_shields_remaining; + int base_corruption = total_corruption - district_corruption - hub_corruption; + if (base_corruption < 0) + base_corruption = 0; + + is->non_district_shield_icons_remaining = non_district_shields_remaining; + is->district_shield_icons_remaining = district_shields_remaining; + is->distribution_hub_shield_icons_remaining = hub_shields_remaining; + + is->corruption_shield_icons_remaining = base_corruption; + is->district_corruption_icons_remaining = district_corruption; + is->distribution_hub_corruption_icons_remaining = hub_corruption; +} + +void __fastcall +patch_City_draw_production_income_icons (City * this, int edx, int canvas, int * rect_ptr) +{ + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { + City_draw_production_income_icons (this, __, canvas, rect_ptr); + return; + } + + recompute_district_and_distribution_hub_shields_for_city_view (this); + City_draw_production_income_icons (this, __, canvas, rect_ptr); + + is->corruption_shield_icons_remaining = 0; + is->district_corruption_icons_remaining = 0; + is->distribution_hub_corruption_icons_remaining = 0; + + is->non_district_shield_icons_remaining = 0; + is->district_shield_icons_remaining = 0; + is->distribution_hub_shield_icons_remaining = 0; +} + +int __fastcall +patch_Sprite_draw_production_income_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + if (is->distribution_hub_icons_img_state == IS_UNINITED) + init_distribution_hub_icons (); + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + + if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && is->dc_icons_img_state == IS_OK) { + Sprite to_draw = *this; + if (is->corruption_shield_icons_remaining > 0 || + is->district_corruption_icons_remaining > 0 || + is->distribution_hub_corruption_icons_remaining > 0) { + + if (is->corruption_shield_icons_remaining > 0) { + is->corruption_shield_icons_remaining--; + } else if (is->district_corruption_icons_remaining > 0) { + to_draw = is->district_corruption_icon; + is->district_corruption_icons_remaining--; + } else if (is->distribution_hub_icons_img_state == IS_OK) { + to_draw = is->distribution_hub_corruption_icon; + is->distribution_hub_corruption_icons_remaining--; + } + } + else if (is->non_district_shield_icons_remaining > 0 || + is->district_shield_icons_remaining > 0 || + is->distribution_hub_shield_icons_remaining > 0) { + + if (is->non_district_shield_icons_remaining > 0) { + is->non_district_shield_icons_remaining--; + } else if (is->district_shield_icons_remaining > 0) { + to_draw = is->district_shield_icon; + is->district_shield_icons_remaining--; + } else if (is->distribution_hub_icons_img_state == IS_OK) { + to_draw = is->distribution_hub_shield_icon; + is->distribution_hub_shield_icons_remaining--; + } + + } + return Sprite_draw (&to_draw, __, canvas, pixel_x, pixel_y, color_table); + } + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +bool +district_tile_needs_defense (Tile * tile, int tile_x, int tile_y, struct district_instance * inst, int civ_id, int work_radius) +{ + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (inst == NULL) return false; + + int district_id = inst->district_id; + struct district_config const * cfg = &is->district_configs[district_id]; + if (! district_is_complete (tile, district_id)) return false; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; + + // Check if already has enough defenders (2 for aerodromes, distribution hubs, destroyable completed wonders) + int defender_count = count_units_at (tile_x, tile_y, UF_DEFENDER_VIS_TO_A_OF_CLASS_B, civ_id, 0, -1); + int max_defenders = + (district_id == AERODROME_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID || + (cfg->defense_bonus_percent > 0 && district_id != NEIGHBORHOOD_DISTRICT_ID) || + (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed)) + ? 2 : 1; + if (defender_count >= max_defenders) + return false; + + // Distribution hubs always need defense + if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) + return true; + + // Wonder districts need defense if under construction or completed (not unused) + if (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed) { + enum wonder_district_state state = inst->wonder_info.state; + if (state == WDS_UNDER_CONSTRUCTION || state == WDS_COMPLETED) + return true; + // Unused wonder districts don't need defense + return false; + } + + return any_enemies_near (&leaders[civ_id], tile_x, tile_y, -1, work_radius); +} + +int +compute_turns_required_for_path (Unit * unit, int path_length) +{ + if (path_length < 1) + return 0; + + int max_mp = patch_Unit_get_max_move_points (unit); + if (max_mp <= 0) + return 9999; + + int moves_used_this_turn = max_mp - unit->Body.Moves; + moves_used_this_turn = not_below (0, moves_used_this_turn); + moves_used_this_turn = not_above (moves_used_this_turn, 9999); + + int remaining_mp = path_length - moves_used_this_turn; + if (remaining_mp < 0) + remaining_mp = 0; + + return (max_mp - 1 + remaining_mp) / max_mp + 1; +} + +void +maybe_update_best_district_target (Unit * unit, + int civ_id, + int max_distance, + int unit_x, + int unit_y, + int tile_x, + int tile_y, + int base_score, + int * best_score, + int * best_x, + int * best_y, + int * best_path_length, + int * evaluated_paths, + int max_path_checks) +{ + if (*evaluated_paths >= max_path_checks) + return; + + int path_length; + int path_result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, tile_x, tile_y, + unit, civ_id, 0x81, &path_length); + *evaluated_paths += 1; + if (path_result <= 0) + return; + + if (max_distance > 0) { + int turns = compute_turns_required_for_path (unit, path_length); + if (turns > max_distance) + return; + } + + int score = base_score - path_length; + if ((score > *best_score) || ((score == *best_score) && (path_length < *best_path_length))) { + *best_score = score; + *best_x = tile_x; + *best_y = tile_y; + *best_path_length = path_length; + } +} + +// Patch seek_colony to actively search for undefended districts +int __fastcall +patch_Unit_seek_colony (Unit * this, int edx, bool for_own_defense, int max_distance) +{ + // Only intercept if defending own assets and districts are enabled + if (!for_own_defense || + !is->current_config.enable_districts || + !is->current_config.ai_defends_districts) + return Unit_seek_colony (this, __, for_own_defense, max_distance); + + int civ_id = this->Body.CivID; + int unit_x = this->Body.X; + int unit_y = this->Body.Y; + + Tile * current_tile = tile_at (unit_x, unit_y); + if ((current_tile == NULL) || (current_tile == p_null_tile)) + return Unit_seek_colony (this, __, for_own_defense, max_distance); + + int continent_id = current_tile->vtable->m46_Get_ContinentID (current_tile); + + const int search_radius = 20; + const int max_path_checks = 64; + const int wonder_base_score = 1000; + const int regular_base_score = 500; + + int best_x = -1; + int best_y = -1; + int best_score = INT_MIN; + int best_path_length = INT_MAX; + int evaluated_paths = 0; + + bool abort_search = false; + + if ((is->current_config.enable_wonder_districts && is->current_config.completed_wonder_districts_can_be_destroyed) || + is->current_config.enable_distribution_hub_districts) { + for (int dx = -search_radius; (dx <= search_radius) && !abort_search; dx++) { + for (int dy = -search_radius; dy <= search_radius; dy++) { + if (evaluated_paths >= max_path_checks) { + abort_search = true; + break; + } + + int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); + int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); + Tile * district_tile = tile_at (target_x, target_y); + if ((district_tile == NULL) || (district_tile == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (district_tile); + if (inst == NULL) + continue; + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) + continue; + if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) + continue; + if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) + continue; + + maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, + tile_x, tile_y, wonder_base_score, + &best_score, &best_x, &best_y, + &best_path_length, &evaluated_paths, + max_path_checks); + } + } + } + + if ((best_x < 0) && (evaluated_paths < max_path_checks)) { + for (int dx = -search_radius; (dx <= search_radius) && (evaluated_paths < max_path_checks); dx++) { + for (int dy = -search_radius; dy <= search_radius; dy++) { + if (evaluated_paths >= max_path_checks) + break; + + int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); + int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); + Tile * district_tile = tile_at (target_x, target_y); + if ((district_tile == NULL) || (district_tile == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (district_tile); + if ((inst == NULL) || (inst->district_id == WONDER_DISTRICT_ID)) + continue; + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) + continue; + if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) + continue; + if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) + continue; + + maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, + tile_x, tile_y, regular_base_score, + &best_score, &best_x, &best_y, + &best_path_length, &evaluated_paths, + max_path_checks); + } + } + } + + if ((best_x >= 0) && (best_y >= 0)) { + int result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, best_x, best_y, + this, civ_id, 0x181, NULL); + return result; + } + + return Unit_seek_colony (this, __, for_own_defense, max_distance); +} + +// Patch has_colony to make units stay on districts, only patches within Unit::ai_move_defensive_unit +bool __fastcall +patch_Tile_has_district_or_colony (Tile * this) +{ + if (is->current_config.enable_districts && + is->current_config.ai_defends_districts) { + + struct district_instance * inst = get_district_instance (this); + return (inst != NULL) && district_is_complete (this, inst->district_id); + } + + // Fallback to original has_colony logic + return Tile_has_colony (this); +} + +int __fastcall +patch_Buildings_Info_get_age_in_years_for_tourism (Buildings_Info * this, int edx, int building_index) +{ + int base = Buildings_Info_get_age_in_years (this, __, building_index); + if (is->current_config.tourism_time_scale_percent == 100) + return base; + else if (is->current_config.tourism_time_scale_percent <= 0) + return INT_MAX; + else + return (base * 100 + 50) / is->current_config.tourism_time_scale_percent; +} + +int __fastcall +patch_Sprite_draw_minimap_frame (Sprite * this, int edx, Sprite * alpha, int param_2, PCX_Image * canvas, int x, int y, int param_6) +{ + bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || + ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); + if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) + return Sprite_draw_for_hud (&is->double_size_box_left_color_pcx, __, &is->double_size_box_left_alpha_pcx, param_2, canvas, x, y, param_6); + else + return Sprite_draw_for_hud (this, __, alpha, param_2, canvas, x, y, param_6); +} + +int __fastcall +patch_City_get_turns_to_build_2_for_ai_move_leader (City * this, int edx, City_Order * order, bool param_2) +{ + // Initialize order variable to city's current build. This is not done in the base logic and can cause crashes. + City_Order current_order = { .OrderID = this->Body.Order_ID, .OrderType = this->Body.Order_Type }; + if (is->current_config.patch_crash_in_leader_unit_ai) + order = ¤t_order; + + return City_get_turns_to_build_2 (this, __, order, param_2); +} + +void __fastcall +patch_City_set_production (City * this, int edx, int order_type, int order_id, bool ask_to_confirm) +{ + City_set_production (this, __, order_type, order_id, ask_to_confirm); + + if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) + return; + + // If the human player, we need to set/unset a wonder district for this city, depending + // on what is being built. The human player wouldn't be able to choose a wonder if a wonder + // district wasn't available, so we don't need to worry about feasibility here. + // The AI uses a different mechanism to reserve wonder districts via patch_Leader_do_production_phase. + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + if (! is_human) + return; + + char ss[256]; + bool release_reservation = true; + if (this->Body.Order_Type == COT_Improvement) { + Improvement * improv = &p_bic_data->Improvements[this->Body.Order_ID]; + if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { + if (reserve_wonder_district_for_city (this, this->Body.Order_ID)) { + release_reservation = false; + } + } + } + + if (release_reservation) { + release_wonder_district_reservation (this); + } +} + +int __fastcall +patch_Tile_m71_Check_Worker_Job (Tile * this) +{ + if (is->current_config.enable_natural_wonders) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && + (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) { + return -1; // No worker job allowed on natural wonders + } + } + return Tile_m71_Check_Worker_Job (this); +} + +int __fastcall +patch_Tile_get_road_bonus (Tile * this) +{ + if (is->current_config.enable_natural_wonders) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { + return 0; + } + } + if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { + return 1; + } + } + return Tile_get_road_bonus (this); +} + +bool __fastcall +patch_Unit_has_army_ability_to_perform_unload (Unit * this, int edx, enum UnitTypeAbilities a) +{ + return is->current_config.allow_unload_from_army ? false : Unit_has_ability (this, __, a); +} + +void __fastcall +patch_Unit_disembark (Unit * this, int edx, int tile_x, int tile_y) +{ + Unit * container = get_unit_ptr (this->Body.Container_Unit); + bool unloading_from_army = is->current_config.allow_unload_from_army && container != NULL && Unit_has_ability (container, __, UTA_Army); + + // If removing a unit from an army, transfer a proportional amount of damage to the unit removed + int damage_transferred = 0; + if (unloading_from_army) { + int army_damage_percent = container->Body.Damage * 100 / Unit_get_max_hp (container), + max_damage = Unit_get_max_hp (this) - 1 - this->Body.Damage; + damage_transferred = clamp (0, max_damage, (army_damage_percent * Unit_get_max_hp (this) + 50) / 100); + } + + Unit_disembark (this, __, tile_x, tile_y); + + if (unloading_from_army) { + this->Body.Damage = not_above (Unit_get_max_hp (this) - 1, this->Body.Damage + damage_transferred); + container->Body.Damage = not_below (0, container->Body.Damage - damage_transferred); + + if (this->Body.ID == container->Body.army_top_defender_id) { + Unit * new_top_defender = NULL; + FOR_UNITS_ON (uti, tile_at (container->Body.X, container->Body.Y)) + if (uti.unit->Body.Container_Unit == container->Body.ID) { + if (new_top_defender == NULL) + new_top_defender = uti.unit; + else if (Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, uti.unit, Unit_get_defense_strength (uti.unit), new_top_defender, Unit_get_defense_strength (new_top_defender), true)) + new_top_defender = uti.unit; + } + container->Body.army_top_defender_id = (new_top_defender != NULL) ? new_top_defender->Body.ID : -1; + } + } +} + +bool __fastcall +patch_Unit_has_ability_no_load_non_army_passengers (Unit * this, int edx, enum UnitTypeAbilities army_ability) +{ + UnitType * transport_type = &p_bic_data->UnitTypes[is->can_load_transport->Body.UnitTypeID], + * passenger_type = &p_bic_data->UnitTypes[this ->Body.UnitTypeID]; + + // This call comes from Unit::can_load at the point where it's determined that the passenger (this) has transport capacity > 0 and is checking + // whether it's an army. If not, it can't be loaded. Add two exceptions here for land transports, if configured, one to allow LTs to load into + // naval units and another to allow empty LTs to load into armies. + if (is->current_config.land_transport_rules != 0) + if ((passenger_type->Unit_Class == UTC_Land) && ! Unit_has_ability (this, __, army_ability)) { // if it's a land transport + if ((is->current_config.land_transport_rules & LTR_LOAD_ONTO_BOAT) && (transport_type->Unit_Class == UTC_Sea)) + return true; + if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && + Unit_has_ability (is->can_load_transport, __, army_ability) && (Unit_count_contained_units (this) == 0)) + return true; + } + + // Similarly, allow helicopters to be loaded onto carriers if so configured + if ((is->current_config.special_helicopter_rules & SHR_ALLOW_ON_CARRIERS) && + passenger_type->Unit_Class == UTC_Air && + transport_type->Unit_Class == UTC_Sea && + Unit_has_ability (is->can_load_transport, __, UTA_Transports_Only_Aircraft)) + return true; + + return Unit_has_ability (this, __, army_ability); +} + +bool __fastcall +patch_Unit_has_ability_no_load_transport_into_army (Unit * this, int edx, enum UnitTypeAbilities army_ability) +{ + // Similar to above, here it checks if the target unit is an army and rejects the load if it is (again, already determined that the passenger + // has transport capacity). Modify this rule to return false for land transports trying to join armies if configured. We don't have to check + // that the LT is empty since that is already disallowed by the modified check above. + bool is_army = Unit_has_ability (this, __, army_ability); + if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && is_army && + (p_bic_data->UnitTypes[is->can_load_passenger->Body.UnitTypeID].Unit_Class == UTC_Land)) + return false; + + else + return is_army; +} + +bool __fastcall +patch_Fighter_unit_can_defend (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) +{ + if (cannot_defend_inside_transport (unit)) + return false; + else + return Fighter_unit_can_defend (this, __, unit, tile_x, tile_y); +} + +bool __fastcall +patch_Leader_is_enemy_unit_for_ground_aa (Leader * this, int edx, Unit * bomber) +{ + // When this function is called, the potential interceptor unit is stored in register ESI. + Unit * interceptor; + __asm__ __volatile__("mov %%esi, %0" : "=r" (interceptor)); + + Unit * container = get_unit_ptr (interceptor->Body.Container_Unit); + bool in_transport = (container != NULL) && ! Unit_has_ability (container, __, UTA_Army); + if (in_transport && + (is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Land) + return false; + else if (in_transport && + (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return false; + else if (in_transport && + is->current_config.no_land_anti_air_from_inside_naval_transport && + (p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea)) + return false; + else + return Leader_is_enemy_unit (this, __, bomber); +} + +bool __fastcall +patch_Unit_has_army_ability_for_passenger_despawn (Unit * this, int edx, enum UnitTypeAbilities army_ability) +{ + // If the unit has the army ability, the game will always despawn the passengers. Otherwise there are exceptions like land unit passengers + // won't be despawned if the transport is on a land tile. + return is->always_despawn_passengers || Unit_has_ability (this, __, army_ability); +} + +int __cdecl +patch_count_units_at_in_try_capturing (int x, int y, enum unit_filter filter, int arg_a, int arg_b, int arg_c) +{ + Tile * tile = tile_at (x, y); + + // If one of the no-defense-from-inside rules is in force, count units like the function normally would except skip units that are inside + // transports from which they can't defend. Otherwise, if those transports have 0 defense, the passengers will prevent them from being + // captured but not fight themselves, making movement onto their tile impossible. + if (tile->vtable->m35_Check_Is_Water (tile) == 0 && + ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) || (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE))) { + int tr = 0; + FOR_UNITS_ON (tai, tile) { + if ((arg_b == -1 || p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].Unit_Class == arg_b) && + (arg_a == -1 || patch_Unit_is_visible_to_civ (tai.unit, __, arg_a, 1)) && + (Unit_get_defense_strength (tai.unit) > 0) && + ! cannot_defend_inside_transport (tai.unit)) + tr++; + } + return tr; + + } else + return count_units_at (x, y, filter, arg_a, arg_b, arg_c); +} + +void __fastcall +patch_Map_generate_resources (Map * this, int edx, int secondary_seed) +{ + int const bic_tag_good = 0x444f4f47; // = 'GOOD' + int resource_type_count = this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, -1, NULL); + bool * ratios_to_clear = NULL; + int lux_percent = is->current_config.luxury_randomized_appearance_rate_percent; + int seed = (this->Seed + 0x180E3) * secondary_seed; + + // To change the randomized appearance rate for luxuries, fill in an appearance rate for any that would be randomized (rate set == 0) using + // the same process the game would to randomize the rate but with different limits. That process involves taking two random numbers from 0 to + // 25 then adding them together and to 50 to produce a random rate from 50 to 100 biased toward the middle of that range. + if (lux_percent != 100 && + (ratios_to_clear = calloc (1, resource_type_count)) != NULL) { + for (int n = 0; n < resource_type_count; n++) { + Resource_Type * res; + this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); + if (res->Class == RC_Luxury && res->AppearanceRatio == 0) { + ratios_to_clear[n] = true; + int half_lux_percent = (lux_percent * 50 + 50) / 100, + quarter_lux_percent = (lux_percent * 25 + 50) / 100; + res->AppearanceRatio = not_below (1, half_lux_percent + rand_int (&seed, __, quarter_lux_percent) + rand_int (&seed, __, quarter_lux_percent)); + } + } + } + + Map_generate_resources (this, __, secondary_seed); + + if (ratios_to_clear != NULL) { + for (int n = 0; n < resource_type_count; n++) + if (ratios_to_clear[n]) { + Resource_Type * res; + this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); + res->AppearanceRatio = 0; + } + free (ratios_to_clear); + } +} + +PassBetweenValidity __fastcall +patch_Unit_can_pass_between (Unit * this, int edx, int from_x, int from_y, int to_x, int to_y, int param_5) +{ + PassBetweenValidity base = Unit_can_pass_between (this, __, from_x, from_y, to_x, to_y, param_5); + + if (is->current_config.enable_districts) { + Tile * to = tile_at (to_x, to_y); + bool to_valid = (to != NULL) && (to != p_null_tile); + struct district_instance * to_inst = NULL; + bool to_inst_complete = false; + if (to_valid) { + to_inst = get_district_instance (to); + if (to_inst != NULL) + to_inst_complete = district_is_complete (to, to_inst->district_id); + } + if (great_wall_blocks_civ (to, this->Body.CivID)) + return PBV_GENERIC_INVALID_MOVE; + if (to_valid) { + bool impassible = false; + bool impassible_to_wheeled = false; + if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { + if (impassible) + return PBV_GENERIC_INVALID_MOVE; + if (impassible_to_wheeled && Unit_has_ability (this, __, UTA_Wheeled)) { + Tile * from = tile_at (from_x, from_y); + bool connected_by_road = (from != NULL) && (to != NULL) && + (from->vtable->m25_Check_Roads (from, __, 0) != 0) && + (to->vtable->m25_Check_Roads (to, __, 0) != 0); + if (! connected_by_road) + return PBV_REQUIRES_ROAD; + } + } + } + + if (is->current_config.workers_can_enter_coast && + base != PBV_OK && is_worker(this)) { + Tile * source = tile_at (from_x, from_y); + if (source != NULL && + source->vtable->m35_Check_Is_Water (source) && + (source->vtable->m50_Get_Square_BaseType (source) == SQ_Coast)) + return PBV_OK; + + if (to_valid && + to->vtable->m35_Check_Is_Water (to) && + (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + + // If human, okay to enter coast tile + if (is_human) + return PBV_OK; + + struct district_worker_record * rec = get_tracked_worker_record (this); + struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; + if (req != NULL) + return PBV_OK; + } + } + + if (is->current_config.enable_bridge_districts && + base != PBV_OK && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == BRIDGE_DISTRICT_ID)) + return PBV_OK; + + if (is->current_config.enable_canal_districts && + base != PBV_OK && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == CANAL_DISTRICT_ID)) + return PBV_OK; + } + + return base; +} + +Unit * __fastcall +patch_Unit_select_transport (Unit * this, int edx, int tile_x, int tile_y, bool do_show_popup) +{ + Unit * transport = Unit_select_transport (this, __, tile_x, tile_y, do_show_popup); + + if (is->current_config.enable_districts && + (transport == NULL) && (this == is->coast_walk_unit)) { + Tile * dest = tile_at (tile_x, tile_y); + if (dest != NULL) { + bool allow_move = false; + if (is->current_config.workers_can_enter_coast && is_worker (this) && + dest->vtable->m35_Check_Is_Water (dest) && + (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) + allow_move = true; + + if (! allow_move && is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land)) { + struct district_instance * inst = get_district_instance (dest); + if (inst != NULL && inst->district_id == BRIDGE_DISTRICT_ID && + district_is_complete (dest, inst->district_id)) { + allow_move = true; + } + } + + if (allow_move) { + is->coast_walk_transport_override = true; + return this; // Fake a transport so the move logic proceeds + } + } + } + + return transport; +} + +// Returns true if the given tile is a water district owned by an enemy of the unit +bool +is_enemy_maritime_district_tile (Unit * unit, Tile * tile) +{ + if ((unit == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + if (! is->current_config.enable_districts) + return false; + + if (! tile->vtable->m35_Check_Is_Water (tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner <= 0) || (owner == unit->Body.CivID)) + return false; + + Leader * leader = &leaders[unit->Body.CivID]; + return leader->At_War[owner]; +} + +// Boost pillage desirability for maritime districts +int __fastcall +patch_Unit_ai_eval_pillage_target (Unit * this, int edx, int tile_x, int tile_y) +{ + int base = Unit_ai_eval_pillage_target (this, __, tile_x, tile_y); + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if (is_enemy_maritime_district_tile (this, tile)) { + // Double the base score so districts outrank generic coast targets + base += base + 0x300; + } + + return base; +} + +// Light-weight hunt for nearby friendly ports; returns true if a path/command was issued +bool +try_path_to_friendly_port_district (Unit * unit, bool require_damaged, bool require_undefended) +{ + if ((unit == NULL) || + ! is->current_config.enable_districts || + ! is->current_config.enable_port_districts) + return false; + + if (unit->Body.Container_Unit >= 0) // Don't redirect cargo + return false; + + if (unit->Body.Moves <= 0) + return false; + + if (require_damaged && (unit->Body.Damage <= 0)) + return false; + + if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Sea) + return false; + + int sea_id = unit->vtable->get_sea_id (unit); + if (sea_id < 0) + return false; + + int best_x = -1, best_y = -1, best_path_len = INT_MAX; + const int search_radius = 10; + for (int dy = -search_radius; dy <= search_radius; dy++) { + for (int dx = -search_radius; dx <= search_radius; dx++) { + int tx = unit->Body.X + dx, ty = unit->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + if ((short)tile->vtable->m46_Get_ContinentID (tile) != sea_id) + continue; + + if (! tile_has_friendly_port_district (tile, unit->Body.CivID)) + continue; + + int occupier_id = get_tile_occupier_id (tx, ty, -1, true); + if ((occupier_id != -1) && (occupier_id != unit->Body.CivID)) + continue; + + if (require_undefended) { + bool has_friendly_sea_unit = false; + FOR_UNITS_ON (uti, tile) { + Unit * on_tile = uti.unit; + if ((on_tile == NULL) || (on_tile->Body.Container_Unit >= 0)) + continue; + if (on_tile->Body.CivID != unit->Body.CivID) + continue; + if (p_bic_data->UnitTypes[on_tile->Body.UnitTypeID].Unit_Class != UTC_Sea) + continue; + if (on_tile->Body.ID == unit->Body.ID) + continue; + has_friendly_sea_unit = true; + break; + } + if (has_friendly_sea_unit) + continue; + } + + if (! is_below_stack_limit (tile, unit->Body.CivID, UTC_Sea)) + continue; + + int path_len = 0; + int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, + tx, ty, unit, unit->Body.CivID, 0x81, &path_len); + if (path_result <= 0) + continue; + + if (path_len < best_path_len) { + best_path_len = path_len; + best_x = tx; + best_y = ty; + } + } + } + + if (unit->Body.X == best_x && unit->Body.Y == best_y) { + Unit_set_escortee (unit, __, -1); + Unit_set_state (unit, __, UnitState_Fortifying); + return true; + } + else if (best_x >= 0) { + patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, best_x, best_y, + unit, unit->Body.CivID, 0x81, NULL); + Unit_set_escortee (unit, __, -1); + Unit_set_state (unit, __, UnitState_Go_To); + unit->Body.path_dest_x = best_x; + unit->Body.path_dest_y = best_y; + return true; + } + + return false; +} + +void __fastcall +patch_Unit_ai_move_naval_power_unit (Unit * this) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + ! is->current_config.naval_units_use_port_districts_not_cities) { + Unit_ai_move_naval_power_unit (this); + return; + } + + Tile * here = tile_at (this->Body.X, this->Body.Y); + if (here == NULL) { + Unit_ai_move_naval_power_unit (this); + return; + } + + // If we're on a port and the sole unit, fortify + if (is->current_config.ai_defends_districts && + tile_has_friendly_port_district (here, this->Body.CivID) && + count_units_at (this->Body.X, this->Body.Y, UF_0, this->Body.CivID, 0, -1) == 1) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If we're already sitting on an enemy maritime district, pillage it immediately + if (this->Body.Container_Unit < 0) { + if (is_enemy_maritime_district_tile (this, here) && + patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y) && + (patch_Unit_ai_eval_pillage_target (this, __, this->Body.X, this->Body.Y) > 0)) { + patch_Unit_attack_tile (this, __, this->Body.X, this->Body.Y, false); + return; + } + } + + // If damaged and CAN heal at current location (e.g. port district), fortify to heal + if (this->Body.Damage > 0 && patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If damaged and cannot heal here, try to path to a friendly port district + if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) + return; + + Unit_ai_move_naval_power_unit (this); + return; +} + +void __fastcall +patch_Unit_ai_move_naval_transport (Unit * this) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + ! is->current_config.naval_units_use_port_districts_not_cities) { + Unit_ai_move_naval_transport (this); + return; + } + + // If damaged and CAN heal at current location (e.g. port district), fortify to heal + if ((this->Body.Damage > 0) && + patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If damaged and cannot heal here, try to path to a friendly port district + if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) + return; + + Unit_ai_move_naval_transport (this); +} + +void __fastcall +patch_Unit_ai_move_naval_missile_transport (Unit * this) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + ! is->current_config.naval_units_use_port_districts_not_cities) { + patch_Unit_ai_move_naval_missile_transport (this); + return; + } + + // If damaged and CAN heal at current location (e.g. port district), fortify to heal + if ((this->Body.Damage > 0) && + patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If damaged and cannot heal here, try to path to a friendly port district + if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) + return; + + Unit_ai_move_naval_missile_transport (this); +} + +void __fastcall +patch_Unit_ai_move_air_bombard_unit (Unit * this) +{ + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) { + Unit_ai_move_air_bombard_unit (this); + return; + } + + if (this->Body.Damage > 0) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + int best_target = 0; + int target_x = -1, target_y = -1; + int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + int grid = op_range * 2 + 1; + if (1 < grid * grid) { + for (int n = 1; n < grid * grid; n++) { + int dx, dy; + neighbor_index_to_diff (n, &dx, &dy); + int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); + int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); + if (Map_in_range (&p_bic_data->Map, __, x, y)) { + int score = Unit_ai_eval_bombard_target (this, __, x, y, 1); + if (score > best_target) { + best_target = score; + target_x = x; + target_y = y; + } + } + } + } + + int best_base_score = 0x7fffffff; + int base_x = -1, base_y = -1; + FOR_AERODROMES_AROUND (this) { + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) + continue; + + int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 6, -1, -1); + int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); + int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); + int score = (count * 10) + ((x_dist + y_dist) >> 1); + if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) + score -= 20; + + if (score < best_base_score) { + best_base_score = score; + base_x = aerodrome_x; + base_y = aerodrome_y; + } + } + + if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { + Unit_set_escortee (this, __, -1); + Unit_rebase (this, __, base_x, base_y); + return; + } + + if ((target_x >= 0) && (target_y >= 0)) { + Unit_set_escortee (this, __, -1); + patch_Unit_bombard_tile (this, __, target_x, target_y); + return; + } + + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +void __fastcall +patch_Unit_ai_move_air_defense_unit (Unit * this) +{ + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) { + Unit_ai_move_air_defense_unit (this); + return; + } + + Unit_ai_move_air_defense_unit (this); + + Unit_set_state (this, __, 0); + if (this->Body.Damage > 0) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + int best_base_score = 0x7fffffff; + int base_x = -1, base_y = -1; + FOR_AERODROMES_AROUND (this) { + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) + continue; + + int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 7, -1, -1); + int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); + int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); + int score = (count * 10) + ((x_dist + y_dist) >> 1); + if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) + score -= 20; + + if (score < best_base_score) { + best_base_score = score; + base_x = aerodrome_x; + base_y = aerodrome_y; + } + } + + if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { + Unit_set_escortee (this, __, -1); + Unit_rebase (this, __, base_x, base_y); + return; + } + + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Intercept); +} + +void __fastcall +patch_Unit_ai_move_air_transport (Unit * this) +{ + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) { + Unit_ai_move_air_transport (this); + return; + } + + Unit_ai_move_air_transport (this); + + if (this->Body.Damage < 1) { + if (Unit_can_airdrop (this)) { + int best_score = 0; + int best_x = -1, best_y = -1; + int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + int grid = op_range * 2 + 1; + if (1 < grid * grid) { + for (int n = 1; n < grid * grid; n++) { + int dx, dy; + neighbor_index_to_diff (n, &dx, &dy); + int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); + int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); + if (Map_in_range (&p_bic_data->Map, __, x, y)) { + int score = Unit_ai_eval_airdrop_target (this, __, x, y); + if (score > best_score) { + best_score = score; + best_x = x; + best_y = y; + } + } + } + if ((best_x >= 0) && (best_y >= 0)) { + Unit_set_escortee (this, __, -1); + Unit_airdrop (this, __, best_x, best_y); + return; + } + } + } + + int best_score = -1; + int base_x = -1, base_y = -1; + FOR_AERODROMES_AROUND (this) { + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) + continue; + + int score = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 0, -1, -1) + + count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 1, -1, -1) + 1; + if (count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 9, -1, -1) == 0) + score *= 2; + int cont_id = aerodrome_tile->vtable->m46_Get_ContinentID (aerodrome_tile); + if ((cont_id >= 0) && (cont_id < p_bic_data->Map.Continent_Count) && + (p_bic_data->Map.Continents[cont_id].Body.TileCount > 0x15)) + score *= 2; + + if (score > best_score) { + best_score = score; + base_x = aerodrome_x; + base_y = aerodrome_y; + } + } + + if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { + Unit_set_escortee (this, __, -1); + Unit_rebase (this, __, base_x, base_y); + if (Unit_count_contained_units (this) > 0) { + patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); + } + return; + } + } + + if (Unit_count_contained_units (this) > 0) + patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); + + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +bool __fastcall +patch_Tile_has_colony_ignore_extraterritorial (Tile * tile) +{ + if (!Tile_has_colony (tile)) + return false; + + if (!is->current_config.allow_extraterritorial_colonies) + return true; + + if ((tile == NULL) || (tile == p_null_tile)) + return true; + + int tile_building_id = tile->vtable->m47_Get_Tile_BuildingID (tile); + if ((tile_building_id < 0) || (p_colonies == NULL) || (p_colonies->Items == NULL) || + (tile_building_id > p_colonies->LastIndex)) + return true; + + Tile_Building_Body * colony_body = p_colonies->Items[tile_building_id].Object; + if ((colony_body == NULL) || ((int)colony_body == offsetof (Tile_Building, Body))) + return true; + + return colony_body->OwnerID == tile->vtable->m38_Get_Territory_OwnerID (tile); +} + +int __fastcall +patch_Leader_get_attitude_toward (Leader * this, int edx, int civ_id, int param_2) +{ + int score = Leader_get_attitude_toward (this, __, civ_id, param_2); + if (!is->current_config.allow_extraterritorial_colonies) + return score; + + int penalty = is->current_config.per_extraterritorial_colony_relation_penalty; + if (penalty != 0) { + int this_civ_id = this->ID; + if ((p_colonies != NULL) && (p_colonies->Items != NULL)) { + for (int n = 0; n <= p_colonies->LastIndex; n++) { + Tile_Building_Body * colony_body = p_colonies->Items[n].Object; + if ((colony_body == NULL) || + ((int)colony_body == offsetof (Tile_Building, Body))) + continue; + + Tile * tile = tile_at (colony_body->X, colony_body->Y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != this_civ_id) + continue; + if (colony_body->OwnerID != civ_id) + continue; + score -= penalty; + } + } + } + return score; +} + +bool __fastcall +patch_Tile_m17_Check_Irrigation (Tile * this, int edx, int visible_to_civ_id) +{ + bool base = Tile_m17_Check_Irrigation (this, __, visible_to_civ_id); + if (base) + return true; + + if (! is->current_config.enable_districts) + return base; + + struct district_instance * inst = get_district_instance (this); + if (inst == NULL) + return base; + + if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (this, inst->district_id)) + return true; + + return base; +} + +int __fastcall +patch_Unit_ai_eval_bombard_target (Unit * this, int edx, int tile_x, int tile_y, int param_3) +{ + int score = Unit_ai_eval_bombard_target (this, __, tile_x, tile_y, param_3); + + if (! (is->current_config.enable_districts && + is->current_config.enable_great_wall_districts)) + return score; + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return score; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID) || (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID))) + return score; + + int obsolete_id = is->district_infos[GREAT_WALL_DISTRICT_ID].obsoleted_by_id; + if ((obsolete_id >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, obsolete_id)) + return score; + + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_id <= 0) || (owner_id == this->Body.CivID)) + return score; + if (! this->vtable->is_enemy_of_civ (this, __, owner_id, false)) + return score; + + bool has_unit_on_tile = false; + bool has_enemy_on_tile = false; + Leader * me = &leaders[this->Body.CivID]; + FOR_UNITS_ON (uti, tile) { + UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; + if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0)) { + has_unit_on_tile = true; + if (me->At_War[uti.unit->Body.CivID]) { + if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { + has_enemy_on_tile = true; + break; + } + } else + break; + } + } + + if (has_unit_on_tile && ! has_enemy_on_tile) + return score; + + // Boost score to prioritize Great Wall targets + if (score < 0x6000) + score = 0x6000; + + // Additional boost if there is no unit on it, more likely to destroy it + if (! has_enemy_on_tile) + score += 0x200; + + return score; +} + +void __fastcall +patch_Unit_heal_at_start_of_turn (Unit * this) +{ + if (is->current_config.enable_districts) { + Tile * tile = tile_at ((this->Body).X, (this->Body).Y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id) && + is->district_configs[inst->district_id].heal_units_in_one_turn) { + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (territory_owner == this->Body.CivID) { + (this->Body).Damage = 0; + return; + } + } + } + } + + Unit_heal_at_start_of_turn (this); +} + +// Makes naval AI treat enemy port districts as valid targets to path toward. +int __cdecl +patch_get_tile_occupier_id_in_Unit_ai_move_naval_power_unit (int x, int y, int pov_civ_id, bool respect_unit_invisibility) +{ + int base = get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); + if (base != -1) + return base; + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return -1; + + Tile * tile = tile_at (x, y); + if (tile == NULL || tile == p_null_tile) + return -1; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return -1; + + return (*tile->vtable->m38_Get_Territory_OwnerID) (tile); +} + +// Returns a non-zero score for enemy port district tiles so they pass the threshold check and are bombard targets +int __fastcall +patch_Fighter_eval_tile_vulnerability_in_Unit_ai_move_naval_power_unit (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) +{ + int base = Fighter_eval_tile_vulnerability (this, __, unit, tile_x, tile_y); + if (base > 0) + return base; + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if (tile == NULL || tile == p_null_tile) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return base; + + int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); + if (owner <= 0 || owner == unit->Body.CivID) + return base; + + if (! leaders[unit->Body.CivID].At_War[owner]) + return base; + + // Return a score high enough to pass threshold (iVar13 * 8 + 0x100) + // 0x300 should be sufficient for most cases + return 0x300; +} + +// Returns the territory owner for enemy port districts so the score isn't reduced and naval units move to enemy ports +// (to subsequently pillage them) +int __cdecl +patch_get_combat_occupier_in_Unit_ai_move_naval_power_unit (int tile_x, int tile_y, int civ_id, byte ignore_visibility) +{ + int base = get_combat_occupier (tile_x, tile_y, civ_id, ignore_visibility); + if (base != -1) + return base; + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if (tile == NULL || tile == p_null_tile) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return base; + + int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); + if (owner <= 0 || owner == civ_id) + return base; + + if (! leaders[civ_id].At_War[owner]) + return base; + + return owner; +} + +int __fastcall +patch_rand_int_to_enslave (void * this, int edx, int lim) +{ + // lim is 100, enslaving happens if the return value is < 33 + int r = rand_int (this, __, lim); + return is->do_not_enslave_units ? 100 : r; +} + +int __fastcall +patch_Sprite_draw_espionage_screen_target_civ_bkg (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + // Figure out which of the potential target civs we're drawing by working backwards from the Y location + int top = (p_bic_data->ScreenHeight - p_espionage_form->Image.Height) / 2; + is->espionage_form_drawing_target_index = (pixel_y - top - 0x5C) / 0x3a + p_espionage_form->field_1584; + + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +char * __fastcall +patch_Civilopedia_Article_get_name_for_esp_screen (Civilopedia_Article * this) +{ + // Ensure that we have captured a valid civ ID being drawn then, if that civ has an era-specific formal name, return that so that the + // era-specific names apply on the espionage screen. + int target_civ_id; + if (is->espionage_form_drawing_target_index >= 0 && + is->espionage_form_drawing_target_index < p_espionage_form->target_civ_id_count && + (target_civ_id = p_espionage_form->target_civ_ids[is->espionage_form_drawing_target_index]) >= 0 && + target_civ_id < 32 && + is->aliased_civ_formal_name_bits & 1<Name.S; +} + +void __fastcall +patch_Animator_play_one_shot_victory_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) +{ + if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Air && is->current_config.aircraft_victory_animation != NULL) { + struct string_slice slice = {.str = is->current_config.aircraft_victory_animation, .len = strlen (is->current_config.aircraft_victory_animation)}; + find_animation_type_by_name (&slice, true, &anim_type); + } + + Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); +} + +void +clear_selectable_units_list (Main_Screen_Form * main_screen_form, bool include_unit_objects) +{ + // This is what the base game does to clear things at the start of assemble_selectable_units + if (include_unit_objects && p_units->Units != NULL) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if (unit != NULL) + unit->Body.in_selectable_units_list = false; + } + UnitIDItem * item = main_screen_form->selectable_units.first; + while (item != NULL) { + UnitIDItem * next = item->next; + item->vtable->destruct (item, __, 1); + item = next; + } + main_screen_form->selectable_units.first = main_screen_form->selectable_units.last = NULL; + main_screen_form->selectable_units.length = 0; +} + +void __fastcall +patch_Main_Screen_Form_assemble_selectable_units (Main_Screen_Form * this) +{ + if (is->have_loaded_waiting_units) + is->have_loaded_waiting_units = false; + else + table_deinit (&is->waiting_units); + + if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) + Main_Screen_Form_assemble_selectable_units (this); + else { + clear_selectable_units_list (this, true); + this->unit_cycle_cursor = NULL; + this->completed_unit_cycle = false; + } +} + +void __fastcall +patch_Main_Screen_Form_set_selected_unit (Main_Screen_Form * this, int edx, Unit * unit, bool param_2) +{ + // To set a unit to wait, Main_Screen_Form::issue_command calls this method with unit == NULL and param_2 == false. Detect when that's + // happened and record that the unit's been set to wait so we can reimplement the wait command when replacing the base unit cycling logic. + int * p_stack = (int *)&unit; + int ret_addr = p_stack[-1]; + if (ret_addr == SET_SELECTED_UNIT_TO_ISSUE_WAIT_COMMAND_RET && unit == NULL && this->Current_Unit != NULL) { + // Give the unit a waiting level higher than the minimum among all units already set to wait. This ensures that this unit does not get + // immediately picked up again by the cycling logic unless it's the only selectable unit left. This also means that the first unit set + // to wait will be the first cycled to once all the non-waiting units have been moved (it's the only one at level 1). I consider that + // an advantage. + int min_others_waiting_level = INT_MAX; + bool any_others_waiting = false; + FOR_TABLE_ENTRIES (tei, &is->waiting_units) + if (tei.key != this->Current_Unit->Body.ID) { + any_others_waiting = true; + if (tei.value < min_others_waiting_level) + min_others_waiting_level = tei.value; + } + itable_insert (&is->waiting_units, this->Current_Unit->Body.ID, any_others_waiting ? min_others_waiting_level + 1 : 1); + } + + if (unit != NULL) { + is->last_selected_unit.initial_x = is->last_selected_unit.last_x = unit->Body.X; + is->last_selected_unit.initial_y = is->last_selected_unit.last_y = unit->Body.Y; + is->last_selected_unit.type_id = unit->Body.UnitTypeID; + is->last_selected_unit.ptr = unit; + itable_remove (&is->waiting_units, unit->Body.ID); // Clear waiting record when waiting unit is selected + } + + if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD) + clear_selectable_units_list (this, false); + + bool redraw = false; + if (is->current_config.show_ai_city_location_desirability_if_settler) { + int new_perspective = -1; + if (unit != NULL) { + int unit_type_id = unit->Body.UnitTypeID; + int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; + new_perspective = (worker_actions >= 1 && (worker_actions & (UCV_Build_City)) && !is_worker(unit)) ? p_main_screen_form->Player_CivID : -1; + } + + if (new_perspective != is->city_loc_display_perspective) { + is->city_loc_display_perspective = new_perspective; + redraw = true; + } + } + + Main_Screen_Form_set_selected_unit (this, __, unit, param_2); + + // If selecting a new unit, must insert it into the list to ensure it's actually selected. + if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && unit != NULL) { + UnitIDList_insert_before (&this->selectable_units, __, unit->Body.ID, NULL); + this->unit_cycle_cursor = this->selectable_units.first; + } + + if (redraw && ! this->is_now_loading_game) + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +Unit * __fastcall +patch_Main_Screen_Form_find_next_unit_for_cycling (Main_Screen_Form * this) +{ + if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) + return Main_Screen_Form_find_next_unit_for_cycling (this); + + else { + int least_difference = INT_MAX; + Unit * least_different_unit = NULL; + int sx = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_x : is->last_selected_unit.last_x, + sy = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_y : is->last_selected_unit.last_y; + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if (unit != NULL && unit->Body.CivID == this->Player_CivID && Unit_can_cycle_to (unit)) { + int distance = not_above (1<<15, int_abs (unit->Body.X - sx) + int_abs (unit->Body.Y - sy)); + + bool other_type, not_duplicate; { + if (is->last_selected_unit.type_id == unit->Body.UnitTypeID) { + other_type = false; + if (is->last_selected_unit.ptr != NULL) + not_duplicate = ! are_units_duplicate (&is->last_selected_unit.ptr->Body, &unit->Body, false); + else + not_duplicate = true; + } else + other_type = not_duplicate = true; + } + + int wait_level = itable_look_up_or (&is->waiting_units, unit->Body.ID, 0); + + int difference = ((int)wait_level << 20) + (distance << 2) + ((int)other_type << 1) + (int)not_duplicate; + if (difference < least_difference) { + least_difference = difference; + least_different_unit = unit; + } + } + } + this->completed_unit_cycle = least_different_unit == NULL; + return least_different_unit; + } +} + +void __fastcall +patch_City_m22 (City * this, int edx, bool param_1) +{ + int * p_stack = (int *)¶m_1; + int ret_addr = p_stack[-1]; + + City_m22 (this, __, param_1); + + // If the base game method failed to find a new thing for city to build, we've been called by the methods that complete a previous build, and + // the city is owned by the UI controller, the game will crash because there will be no default option for the build selector popup. If we're + // configured to fix that, suggest Wealth for the new build or, failing that, any buildable unit or improvement. + if ( this->Body.Order_Type == 0 + && is->current_config.patch_failure_to_find_new_city_build + && this->Body.CivID == p_main_screen_form->Player_CivID + && ( ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_1 + || ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_2 + || ret_addr == CITY_M22_TO_SPAWN_UNIT_IF_DONE_RETURN)) { + + // Search for an improvement-type order we can build. Choose Wealth if possible, otherwise just pick the first thing that can be built + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (patch_City_can_build_improvement (this, __, n, true)) { + if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { + this->Body.Order_Type = COT_Improvement; + this->Body.Order_ID = n; + break; + } else if (this->Body.Order_Type == 0) { + this->Body.Order_Type = COT_Improvement; + this->Body.Order_ID = n; + } + } + + // If we still don't have a build, pick the first buildable unit + if (this->Body.Order_Type == 0) + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) + if (patch_City_can_build_unit (this, __, n, true, 0, false)) { + this->Body.Order_Type = COT_Unit; + this->Body.Order_ID = n; + break; + } + } +} + +int __fastcall +patch_PCX_Image_process_dom_adv_turn_count_text (PCX_Image * this, int edx, char * str) +{ + if (is->current_config.reformat_turns_remaining_on_domestic_advisor_screen) { + char * start = strstr (str, p_advisor_internal_form->Labels[16].S); // Search for "turns" + if (start == NULL) + start = strstr (str, p_advisor_internal_form->Labels[17].S); // Search for "turn" + + if (start != NULL) { + *start = toupper (*start); // Upcase first letter of "turn/s" + + char s[64]; // Must be same size as "str" param, which is a 64-byte stack-allocated string + snprintf (s, sizeof s, "%.*s %s", start - str, str, start); // Reprint string with space before "Turn/s" + s[(sizeof s) - 1] = '\0'; + memcpy (str, s, sizeof s); + } + } + + return PCX_Image_process_text (this, __, str); +} + +int +compare_menu_unit_items (void const * a, void const * b) +{ + return MenuUnitItem_should_appear_after ((MenuUnitItem *)a, __, (MenuUnitItem *)b) ? 1 : -1; +} + +int __fastcall +patch_MenuUnitList_get_length_before_sorting (MenuUnitList * this) +{ + int length = MenuUnitList_get_length (this); + + if (is->current_config.patch_passengers_out_of_order_on_menu && length > 0) { + qsort (this->items, length, sizeof this->items[0], compare_menu_unit_items); + + // Fix any units not being listed immediately after the unit they're contained in + // First, loop over all units in the list, stopping at each that might contain others + for (int n = 0; n < length - 1; n++) { + Unit * container = this->items[n].unit; + if ((int)container > 1 && // original code checks if unit ptrs are NULL or equal to 1 + p_bic_data->UnitTypes[container->Body.UnitTypeID].Transport_Capacity > 0) { + + // Advance iterator "j" past the container and past any empty slots or correctly positioned units right after it + int j = n + 1; + while (j < length && ((int)this->items[j].unit <= 1 || this->items[j].unit->Body.Container_Unit == container->Body.ID)) + j++; + + // Check the rest of the list for out-of-place passengers + for (int k = j + 1; k < length; k++) { + if ((int)this->items[k].unit > 1 && this->items[k].unit->Body.Container_Unit == container->Body.ID) { + + // Move item from index "k" to index "j" and advance "j" past it + MenuUnitItem moved = this->items[k]; + memmove (&this->items[j + 1], &this->items[j], (k - j) * sizeof this->items[0]); + this->items[j] = moved; + j++; + } + } + } + } + + // The caller is checking if the length is > 0 before sorting the list. Since we've already sorted it, return 0. + return 0; + } else + return length; +} + +void __fastcall +patch_Map_finalize_params_for_scenario_map (Map * this) +{ + Map_finalize_params (this); + + enum barbarian_activity_override barb_override = is->current_config.override_barbarian_activity_level_for_scenario_maps; + if (barb_override != BAO_NONE) { + if (barb_override == BAO_RANDOM) { + LARGE_INTEGER time; + QueryPerformanceCounter (&time); + int r = this->Seed ^ time.u.LowPart; // The map seed will be the same every time so incorporate some entropy + this->World.Final_Barbarians_Activity = rand_int (&r, __, 5) - 1; + } else + this->World.Final_Barbarians_Activity = clamp (-1, 3, barb_override); + } +} + +Unit * __fastcall +patch_Unit_select_army_member_for_combat (Unit * this, int edx, int param_1, char param_2) +{ + if (is->current_config.patch_empty_army_combat_crash) { + int unit_count = 0; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + if (tile != NULL && tile != p_null_tile) { + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit != NULL) && (unit->Body.Container_Unit == this->Body.ID)) + unit_count += Unit_count_contained_units (unit) + 1; + } + } + if (unit_count == 0) + return this; + } + + return Unit_select_army_member_for_combat (this, __, param_1, param_2); +} + +int __fastcall +patch_Tile_check_water_for_canal_move_to_adjacent_tile_dest (Tile * this) +{ + if ((this != NULL) && (this != p_null_tile) && + is->current_config.enable_districts && + is->current_config.enable_canal_districts && + (is->coast_walk_unit != NULL) && + (p_bic_data->UnitTypes[is->coast_walk_unit->Body.UnitTypeID].Unit_Class == UTC_Sea)) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && + (inst->district_id == CANAL_DISTRICT_ID) && + district_is_complete (this, inst->district_id)) + return 1; + } + + return this->vtable->m35_Check_Is_Water (this); +} + +// TCC requires a main function be defined even though it's never used. int main () { return 0; } \ No newline at end of file From 5ab9a965ff22b04759539a03f15d7c19096f2a51 Mon Sep 17 00:00:00 2001 From: gxia0005 Date: Mon, 27 Apr 2026 17:55:02 +1000 Subject: [PATCH 3/9] Refactor terrain handling in combat odds calculation to ensure accurate application of counter rules. - Introduced a new boolean to manage terrain skipping based on the context of the call, preventing stale data issues from previous computations. --- injected_code.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/injected_code.c b/injected_code.c index a2935383..4de10ac9 100644 --- a/injected_code.c +++ b/injected_code.c @@ -28072,6 +28072,11 @@ patch_Fighter_get_odds_for_main_combat_loop (Fighter * this, int edx, Unit * att return 1025; struct c3x_config * cfg = &is->current_config; + // Only OR in counter-rule terrain skipping when we actually ran apply_counter_rules for this + // call. Otherwise counter_combat_ctx.ignore_terrain can be stale from an earlier probe (e.g. + // find_civ4_best_defender_against) or an earlier combat round — especially risky after + // merges that add new odds call sites. + bool ignore_terrain_for_odds = ignore_defensive_bonuses; if (cfg->enable_unit_counters && attacker != NULL && defender != NULL) { Tile * def_tile = tile_at (this->defender_location_x, this->defender_location_y); @@ -28086,10 +28091,11 @@ patch_Fighter_get_odds_for_main_combat_loop (Fighter * this, int edx, Unit * att is->counter_combat_ctx.attacker_atk_pct = aa; is->counter_combat_ctx.defender_def_pct = dd; is->counter_combat_ctx.ignore_terrain = ignore_terrain; + ignore_terrain_for_odds = ignore_defensive_bonuses || ignore_terrain; } int result = Fighter_get_combat_odds (this, __, attacker, defender, bombarding, - ignore_defensive_bonuses || is->counter_combat_ctx.ignore_terrain); + ignore_terrain_for_odds); is->counter_combat_ctx.active = false; return result; } From 909d962fdf8f5d803b61c3e6929b61f149143081 Mon Sep 17 00:00:00 2001 From: gxia0005 Date: Wed, 29 Apr 2026 12:43:42 +1000 Subject: [PATCH 4/9] Change line endings to CRLF - support dynamic district types - Add details of terrain types to config file --- C3X.h | 7 +-- default.c3x_config.ini | 18 ++++--- injected_code.c | 109 ++++++++++++++++++++++++++++++++++------- 3 files changed, 105 insertions(+), 29 deletions(-) diff --git a/C3X.h b/C3X.h index 033c23f6..65c1770a 100644 --- a/C3X.h +++ b/C3X.h @@ -214,10 +214,11 @@ struct counter_rule { int defender_match; char * defender_group; - // Environment conditions (-1 / false means no restriction) - int terrain_type; // enum SquareTypes, -1 = no restriction + // Environment conditions (0 / false means no restriction) + unsigned int terrain_mask; // SquareTypes mask, 0 = no restriction bool only_in_city; int district_id; // -1 = no restriction + char * district_name; // Resolved after district configs are loaded bool ignore_terrain; // true = set defender terrain defense to 0 // Effects (percent values, 100 = no change) @@ -2329,4 +2330,4 @@ struct civ_prog_object { int addr; char const * name; char const * type; -}; \ No newline at end of file +}; diff --git a/default.c3x_config.ini b/default.c3x_config.ini index d40e8b66..87586952 100644 --- a/default.c3x_config.ini +++ b/default.c3x_config.ini @@ -880,7 +880,7 @@ special_capital_decorruption_effect = 10 ; zero: Set NoAIPatrol to 0, allowing AI units to patrol ; The purpose of this option is to enable you to configure NoAIPatrol like a C3X setting instead of globally. In particlar, it allows you to configure ; NoAIPatrol on or off on a per-scenario basis. -override_no_ai_patrol = none +override_no_ai_patrol = one ; Overrides the barbarian activity level when starting a new game for a scenario with a custom map. Normally, in that case, the game will use the ; barbarian settings kept in conquests.ini, ignoring what was set for the map in the editor. This option allows you to set an activity level on a @@ -934,11 +934,13 @@ unit_group = [] ; ; 【Conditions】(Optional; leaving blank indicates no restrictions; conditions take effect only when all are met simultaneously) ; in-city —— Takes effect only when the enemy is on a city tile -; terrain terrain_name —— Takes effect only when the enemy is on a tile of the specified terrain -; The terrain name must match the name in BIQ, e.g. Grassland, Forest, Hills +; terrain terrain_name -- Takes effect only when the enemy is on a tile of the specified terrain +; Uses the same lower-case English terrain tokens as districts_config buildable_on, not BIQ/localized names. +; Examples: grassland, hills, coast, snow-forest, snow-mountain, snow-volcano, lake ; ignore-terrain —— Ignores the enemy’s terrain defence bonus (sets their terrain bonus to zero) ; Can be used in conjunction with enemy-def; when used together, ignore-terrain takes precedence -; district district_name —— Only takes effect when the enemy is in a specified district (enable_districts must be enabled) +; district district_name -- Only takes effect when the enemy is in a specified district (enable_districts must be enabled) +; District names are resolved after districts_config loads, so dynamic district names are supported. ; ; 【Examples】 ; counter_rule = [ranged vs melee self-atk 125] @@ -947,7 +949,7 @@ unit_group = [] ; counter_rule = ["Knight" vs melee in-city enemy-def 150] ; → When knights attack melee units within a city, the enemy’s defence is multiplied by 1.5 ; -; counter_rule = ["Musketeer" vs "Medival Infantry" terrain Grassland self-atk 125] +; counter_rule = ["Musketman" vs "Medival Infantry" terrain grassland self-atk 125] ; → When musketeers attack medieval infantry on grassland terrain, their attack power is multiplied by 1.25 ; ; counter_rule = ["Knight" vs "*" ignore-terrain self-atk 150] @@ -958,7 +960,7 @@ unit_group = [] ; ; ───────────────────────────────────────────────────────────────────────────── -counter_rule = [] +counter_rule = [Musketman vs Knight self-atk 2000,Longbowman vs Cavalry self-atk 2000] [==================] [=== AESTHETICS ===] @@ -1007,7 +1009,7 @@ pinned_hour_for_day_night_cycle = 0 [=======================] ; Show or hide natural wonders on the map. When disabled, natural wonders will not appear on the map. -enable_natural_wonders = false +enable_natural_wonders = true ; If a new scenario is loaded which has no natural wonders defined, add natural wonders. add_natural_wonders_to_scenarios_if_none = false @@ -1041,7 +1043,7 @@ minimum_natural_wonder_separation = 10 ; enable_central_rail_hub_districts: Enables Central Rail Hub districts used for rail-era infrastructure (e.g., Mass Transit). ; enable_energy_grid_districts: Enables Energy Grid districts associated with power plant infrastructure. ; enable_great_wall_districts: Enables Great Wall districts (wall-like tiles that can block others if great_wall_districts_impassible_by_others is on). -enable_districts = false +enable_districts = true enable_neighborhood_districts = false enable_wonder_districts = false enable_distribution_hub_districts = false diff --git a/injected_code.c b/injected_code.c index 4de10ac9..b83a38de 100644 --- a/injected_code.c +++ b/injected_code.c @@ -759,6 +759,27 @@ reset_to_base_config () cc->great_wall_auto_build_wonder_name = NULL; } + if (cc->unit_counter_groups != NULL) { + for (int n = 0; n < cc->count_unit_counter_groups; n++) { + free (cc->unit_counter_groups[n].name); + free (cc->unit_counter_groups[n].type_ids); + } + free (cc->unit_counter_groups); + cc->unit_counter_groups = NULL; + cc->count_unit_counter_groups = 0; + } + + if (cc->counter_rules != NULL) { + for (int n = 0; n < cc->count_counter_rules; n++) { + free (cc->counter_rules[n].attacker_group); + free (cc->counter_rules[n].defender_group); + free (cc->counter_rules[n].district_name); + } + free (cc->counter_rules); + cc->counter_rules = NULL; + cc->count_counter_rules = 0; + } + // Free unit limits table FOR_TABLE_ENTRIES (tei, &cc->unit_limits) free ((void *)tei.value); @@ -7794,6 +7815,33 @@ find_special_district_index_by_name (char const * name) // Unit counter system // --------------------------------------------------------------- +bool +read_counter_rule_terrain_mask (struct string_slice const * terrain_name, unsigned int * out_mask) +{ + if ((terrain_name == NULL) || (out_mask == NULL)) + return false; + + struct string_slice trimmed = trim_string_slice (terrain_name, 1); + if (trimmed.len <= 0) + return false; + + if (slice_matches_str (&trimmed, "lake") || slice_matches_str (&trimmed, "lakes")) { + *out_mask = district_buildable_lake_mask_bit (); + return true; + } + + enum SquareTypes parsed; + if (! read_tile_terrain_type_value (&trimmed, &parsed)) + return false; + + if (parsed == (enum SquareTypes)SQ_INVALID) + *out_mask = all_square_types_mask () | district_buildable_lake_mask_bit (); + else + *out_mask = square_type_mask_bit (parsed); + + return *out_mask != 0; +} + struct unit_counter_group * find_unit_counter_group_by_name (struct c3x_config * cfg, char const * name) { @@ -7892,8 +7940,9 @@ parse_counter_rule (char ** p_cursor, *r = (struct counter_rule) { .attacker_match = UCM_ANY, .defender_match = UCM_ANY, - .terrain_type = -1, + .terrain_mask = 0, .district_id = -1, + .district_name = NULL, .self_atk_pct = 100, .self_def_pct = 100, .enemy_atk_pct = 100, @@ -7942,8 +7991,7 @@ parse_counter_rule (char ** p_cursor, struct string_slice terrain_name; if (! parse_string (&cur, &terrain_name)) return RPR_PARSE_ERROR; - if (! read_tile_terrain_type_value (&terrain_name, - (enum SquareTypes *)&r->terrain_type)) { + if (! read_counter_rule_terrain_mask (&terrain_name, &r->terrain_mask)) { add_unrecognized_line (p_unrecognized_lines, &terrain_name); return RPR_UNRECOGNIZED; } @@ -7951,14 +7999,9 @@ parse_counter_rule (char ** p_cursor, struct string_slice district_name; if (! parse_string (&cur, &district_name)) return RPR_PARSE_ERROR; - char * dname = extract_slice (&district_name); - int idx = find_special_district_index_by_name (dname); - free (dname); - if (idx < 0) { - add_unrecognized_line (p_unrecognized_lines, &district_name); - return RPR_UNRECOGNIZED; - } - r->district_id = idx; + free (r->district_name); + r->district_name = extract_slice (&district_name); + r->district_id = -1; } else { break; } @@ -8004,12 +8047,12 @@ apply_counter_rules (struct c3x_config * cfg, // Environment checks are based on the defender's tile if (r->only_in_city && ! in_city) continue; - if (r->terrain_type != -1 && - ! tile_matches_square_type (def_tile, - (enum SquareTypes)r->terrain_type)) + if (r->terrain_mask != 0 && + ! tile_matches_square_type_mask (def_tile, r->terrain_mask)) continue; - if (r->district_id != -1 && - ! (cfg->enable_districts && + if (r->district_name != NULL && + ! ((r->district_id != -1) && + cfg->enable_districts && district_is_complete (def_tile, r->district_id))) continue; @@ -11492,6 +11535,29 @@ find_district_index_by_name (char const * name) return -1; } +void +resolve_counter_rule_districts (struct error_line ** parse_errors) +{ + struct c3x_config * cfg = &is->current_config; + + for (int i = 0; i < cfg->count_counter_rules; i++) { + struct counter_rule * rule = &cfg->counter_rules[i]; + rule->district_id = -1; + + if ((rule->district_name == NULL) || (rule->district_name[0] == '\0')) + continue; + + int district_id = find_district_index_by_name (rule->district_name); + if (district_id >= 0) { + rule->district_id = district_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ counter_rule district \"%s\" not found", rule->district_name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } +} + int find_wonder_district_index_by_name (char const * name) { @@ -11879,6 +11945,8 @@ void parse_building_and_tech_ids () resolve_district_bonus_building_entries (&is->district_configs[i].defense_bonus_extras, district_name, "defense_bonus_percent", &district_parse_errors); } + resolve_counter_rule_districts (&district_parse_errors); + // Map wonder names to their improvement IDs for rendering under-construction wonders for (int wi = 0; wi < is->wonder_district_count; wi++) { if (is->wonder_district_configs[wi].wonder_name == NULL || is->wonder_district_configs[wi].wonder_name[0] == '\0') @@ -12840,6 +12908,7 @@ reset_district_state (bool reset_tile_map) { clear_all_tracked_workers (); deinit_district_images (); + deinit_district_command_buttons (); clear_highlighted_worker_tiles_for_districts (); FOR_TABLE_ENTRIES (tei, &is->district_building_prereqs) { @@ -19174,7 +19243,10 @@ init_district_command_buttons () } // For each district type - for (int dc = 0; dc < is->district_count; dc++) { + int district_count = is->district_count; + if (district_count > COUNT_DISTRICT_TYPES) + district_count = COUNT_DISTRICT_TYPES; + for (int dc = 0; dc < district_count; dc++) { int x = 32 * is->district_configs[dc].btn_tile_sheet_column, y = 32 * is->district_configs[dc].btn_tile_sheet_row; Sprite_slice_pcx (&is->district_btn_img_sets[dc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); @@ -21533,6 +21605,7 @@ patch_load_scenario (BIC * this, int edx, char * param_1, unsigned * param_2) // This scenario might use different mod art assets than the old one deinit_stackable_command_buttons (); + deinit_district_command_buttons (); deinit_disabled_command_buttons (); deinit_trade_scroll_buttons (); deinit_unit_rcm_icons (); @@ -37039,4 +37112,4 @@ patch_Tile_check_water_for_canal_move_to_adjacent_tile_dest (Tile * this) } // TCC requires a main function be defined even though it's never used. -int main () { return 0; } \ No newline at end of file +int main () { return 0; } From efc1ccd66ba77728a74e4cc6b399ad05756fdf0f Mon Sep 17 00:00:00 2001 From: gxia0005 Date: Wed, 29 Apr 2026 13:08:41 +1000 Subject: [PATCH 5/9] Turn all files' line endings to LF -turn off some features in default.c3x_config.ini -Actually, the line endings are already LF, but in my last commit I made a typo. --- default.c3x_config.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/default.c3x_config.ini b/default.c3x_config.ini index 87586952..13d15a78 100644 --- a/default.c3x_config.ini +++ b/default.c3x_config.ini @@ -895,7 +895,7 @@ override_barbarian_activity_level_for_scenario_maps = none ; types at the start of the game so they behave like normal MGLs spawned during a game. initialize_preplaced_scenario_leaders_as_mgls = false -enable_unit_counters = true +enable_unit_counters = false ; Civ 4 style best defender selection. ; When this is on (and enable_unit_counters is also true), every time an attack happens the engine picks the @@ -908,7 +908,7 @@ enable_unit_counters = true ; - Has no effect when enable_unit_counters = false (then there's nothing to differentiate beyond defense). ; - Applies to both human and AI attackers, so the rule is consistent. ; - Does not change ranged-bombard or defensive-bombard target selection, only normal attacks. -use_civ4_style_best_defender = true +use_civ4_style_best_defender = false ; unit_group allows you gruop your units in a group,please refer to building_prereqs_for_units for the format. ; This function will not work if enable_unit_counters is false. @@ -960,7 +960,7 @@ unit_group = [] ; ; ───────────────────────────────────────────────────────────────────────────── -counter_rule = [Musketman vs Knight self-atk 2000,Longbowman vs Cavalry self-atk 2000] +counter_rule = [] [==================] [=== AESTHETICS ===] @@ -1043,7 +1043,7 @@ minimum_natural_wonder_separation = 10 ; enable_central_rail_hub_districts: Enables Central Rail Hub districts used for rail-era infrastructure (e.g., Mass Transit). ; enable_energy_grid_districts: Enables Energy Grid districts associated with power plant infrastructure. ; enable_great_wall_districts: Enables Great Wall districts (wall-like tiles that can block others if great_wall_districts_impassible_by_others is on). -enable_districts = true +enable_districts = false enable_neighborhood_districts = false enable_wonder_districts = false enable_distribution_hub_districts = false From 56f08f94a192b90175b52295593c2a7afd9eeed3 Mon Sep 17 00:00:00 2001 From: gxia0005 Date: Thu, 30 Apr 2026 14:47:41 +1000 Subject: [PATCH 6/9] renormalize files --- AMB Editor/RUN.bat | 14 +- AMB Editor/TODO | 20 +- AMB Editor/amb_editor.c | 4382 +- AMB Editor/amb_file.c | 3072 +- AMB Editor/details_window.c | 322 +- AMB Editor/hello_claude.txt | 46 +- AMB Editor/preview.c | 766 +- AMB Editor/wav_file.c | 258 +- AMB Editor/win32_selections.h | 312 +- Art/.gitignore | 48 +- Art/DayNight/.gitignore | 46 +- C3X.h | 4666 +- DayNight/civ3_city_lights.py | 1042 +- DayNight/civ3_day_night.py | 1892 +- DayNight/civ3_day_night_orig.py | 1202 +- DayNight/civ3_postprocess_pixels.py | 560 +- DayNight/find_least_used_colors.py | 196 +- DayNight/find_unused_palette_indexes.py | 214 +- DayNight/generate.sh | 416 +- DayNight/protected_pixels.py | 148 +- DayNight/swap_green_magenta_indices.py | 226 +- Ghidra scripts/Civ3TypesFromHeader.py | 600 +- Ghidra scripts/ExportProgForPython.py | 208 +- Ghidra scripts/ListReturnAddresses.py | 122 +- README.md | 554 +- Sound Test/BUILD_LINUX.sh | 2 +- civ_prog_objects.csv | 1928 +- correlator/CLAUDE.md | 198 +- correlator/correlator.py | 1568 +- default.c3x_config.ini | 2354 +- default.districts_config.txt | 942 +- default.districts_natural_wonders_config.txt | 556 +- default.districts_wonders_config.txt | 466 +- injected_code.c | 74228 ++++++++--------- lend/README.md | 62 +- lend/ld32.c | 160 +- lend/ld32.h | 508 +- tcc/include/_mingw.h | 328 +- tcc/include/assert.h | 124 +- tcc/include/conio.h | 818 +- tcc/include/ctype.h | 562 +- tcc/include/dir.h | 62 +- tcc/include/direct.h | 136 +- tcc/include/dirent.h | 270 +- tcc/include/dos.h | 110 +- tcc/include/errno.h | 150 +- tcc/include/excpt.h | 246 +- tcc/include/fcntl.h | 104 +- tcc/include/fenv.h | 216 +- tcc/include/float.h | 144 +- tcc/include/inttypes.h | 594 +- tcc/include/io.h | 836 +- tcc/include/iso646.h | 72 +- tcc/include/limits.h | 232 +- tcc/include/locale.h | 182 +- tcc/include/malloc.h | 362 +- tcc/include/math.h | 994 +- tcc/include/mem.h | 26 +- tcc/include/memory.h | 80 +- tcc/include/process.h | 352 +- tcc/include/sec_api/conio_s.h | 84 +- tcc/include/sec_api/crtdbg_s.h | 38 +- tcc/include/sec_api/io_s.h | 66 +- tcc/include/sec_api/mbstring_s.h | 104 +- tcc/include/sec_api/search_s.h | 50 +- tcc/include/sec_api/stdio_s.h | 290 +- tcc/include/sec_api/stdlib_s.h | 134 +- tcc/include/sec_api/stralign_s.h | 60 +- tcc/include/sec_api/string_s.h | 82 +- tcc/include/sec_api/sys/timeb_s.h | 68 +- tcc/include/sec_api/tchar_s.h | 532 +- tcc/include/sec_api/time_s.h | 122 +- tcc/include/sec_api/wchar_s.h | 256 +- tcc/include/setjmp.h | 320 +- tcc/include/share.h | 56 +- tcc/include/signal.h | 126 +- tcc/include/stdalign.h | 32 +- tcc/include/stdarg.h | 28 +- tcc/include/stdatomic.h | 250 +- tcc/include/stdbool.h | 22 +- tcc/include/stddef.h | 78 +- tcc/include/stdint.h | 424 +- tcc/include/stdio.h | 858 +- tcc/include/stdlib.h | 1160 +- tcc/include/stdnoreturn.h | 14 +- tcc/include/string.h | 328 +- tcc/include/sys/fcntl.h | 26 +- tcc/include/sys/file.h | 28 +- tcc/include/sys/locking.h | 60 +- tcc/include/sys/stat.h | 580 +- tcc/include/sys/time.h | 138 +- tcc/include/sys/timeb.h | 266 +- tcc/include/sys/types.h | 236 +- tcc/include/sys/unistd.h | 28 +- tcc/include/sys/utime.h | 292 +- tcc/include/tcc/tcc_libm.h | 1236 +- tcc/include/tccdefs.h | 568 +- tcc/include/tcclib.h | 160 +- tcc/include/tchar.h | 2204 +- tcc/include/tgmath.h | 178 +- tcc/include/time.h | 574 +- tcc/include/uchar.h | 66 +- tcc/include/vadefs.h | 22 +- tcc/include/values.h | 8 +- tcc/include/varargs.h | 24 +- tcc/include/wchar.h | 1746 +- tcc/include/wctype.h | 344 +- tcc/include/winapi/basetsd.h | 298 +- tcc/include/winapi/basetyps.h | 170 +- tcc/include/winapi/guiddef.h | 312 +- tcc/include/winapi/poppack.h | 16 +- tcc/include/winapi/pshpack1.h | 16 +- tcc/include/winapi/pshpack2.h | 16 +- tcc/include/winapi/pshpack4.h | 16 +- tcc/include/winapi/pshpack8.h | 16 +- tcc/include/winapi/qos.h | 144 +- tcc/include/winapi/winbase.h | 5902 +- tcc/include/winapi/wincon.h | 602 +- tcc/include/winapi/windef.h | 586 +- tcc/include/winapi/windows.h | 254 +- tcc/include/winapi/winerror.h | 6332 +- tcc/include/winapi/wingdi.h | 8160 +- tcc/include/winapi/winnls.h | 1556 +- tcc/include/winapi/winnt.h | 11670 +-- tcc/include/winapi/winreg.h | 544 +- tcc/include/winapi/winsock2.h | 2948 +- tcc/include/winapi/winuser.h | 11302 +-- tcc/include/winapi/winver.h | 320 +- tcc/include/winapi/ws2ipdef.h | 42 +- tcc/include/winapi/ws2tcpip.h | 782 +- tcc/lib/kernel32.def | 1540 +- tcc/lib/msvcrt.def | 2640 +- tcc/lib/user32.def | 1316 +- tcc/libtcc/libtcc.def | 82 +- tcc/libtcc/libtcc.h | 222 +- 135 files changed, 91736 insertions(+), 91738 deletions(-) diff --git a/AMB Editor/RUN.bat b/AMB Editor/RUN.bat index 1f3c1caf..83d7fa48 100644 --- a/AMB Editor/RUN.bat +++ b/AMB Editor/RUN.bat @@ -1,8 +1,8 @@ -@echo off - -REM See INSTALL.bat for explanation of this line -PUSHD "%~dp0" - -..\tcc\tcc.exe -m32 -run -lmsvcrt -luser32 -lkernel32 -ladvapi32 -lcomdlg32 amb_editor.c - +@echo off + +REM See INSTALL.bat for explanation of this line +PUSHD "%~dp0" + +..\tcc\tcc.exe -m32 -run -lmsvcrt -luser32 -lkernel32 -ladvapi32 -lcomdlg32 amb_editor.c + POPD \ No newline at end of file diff --git a/AMB Editor/TODO b/AMB Editor/TODO index 974b1f0e..40b03198 100644 --- a/AMB Editor/TODO +++ b/AMB Editor/TODO @@ -1,10 +1,10 @@ -- See if the Kmap params do anything useful - -Low priority: -- ArcherRun.amb is missing WAV file names for breath sounds. This is fixable. -- Add row on HopliteAttackA.amb doesn't work properly b/c of the orphan sound track -- Put asterisk in window title if there are unsaved changes -- Warning when you run multiple instances of the editor. Doing so breaks playing of previews. -- Option to create a "new" AMB file -- Consider moving all .c files into a source folder -- Consider adding a column with program numbers +- See if the Kmap params do anything useful + +Low priority: +- ArcherRun.amb is missing WAV file names for breath sounds. This is fixable. +- Add row on HopliteAttackA.amb doesn't work properly b/c of the orphan sound track +- Put asterisk in window title if there are unsaved changes +- Warning when you run multiple instances of the editor. Doing so breaks playing of previews. +- Option to create a "new" AMB file +- Consider moving all .c files into a source folder +- Consider adding a column with program numbers diff --git a/AMB Editor/amb_editor.c b/AMB Editor/amb_editor.c index cdd05fda..a448315b 100644 --- a/AMB Editor/amb_editor.c +++ b/AMB Editor/amb_editor.c @@ -1,2191 +1,2191 @@ -#include -#include -#include -#include -#include -#include - -// Defines the things we need from commctrl.h, commdlg.h, and any other headers that are not available -#include "win32_selections.h" - - - -#define PATH_BUFFER_SIZE 1024 -typedef char Path[PATH_BUFFER_SIZE]; - -Path g_iniCiv3InstallPath; -Path g_iniSoundDLLPath; -Path g_iniTempDirectory; - -void PathAppend(Path path, const char* append) -{ - size_t len = strlen(path); - - // No space at end of buffer - if (len >= PATH_BUFFER_SIZE - 1) - return; - - // Add backslash if needed - if (len > 0 && path[len - 1] != '\\') { - path[len] = '\\'; - path[len + 1] = '\0'; - len++; - } - - // Append the new part - strncpy(path + len, append, PATH_BUFFER_SIZE - len); - path[PATH_BUFFER_SIZE - 1] = '\0'; -} - -bool PathRemoveFileSpec(Path path) -{ - char* lastSlash = strrchr(path, '\\'); - if (lastSlash) { - *lastSlash = '\0'; - return true; - } - return false; -} - - - -#include "amb_file.c" -#include "preview.c" -#include "wav_file.c" - - - -// Forward declarations for ListView functions -void AddListViewColumn(HWND hListView, int index, char *title, int width); -int AddListViewItem(HWND hListView, int index, const char *text); -void SetListViewItemText(HWND hListView, int row, int col, const char *text, BOOL allowRepopulation); -void ClearListView(HWND hListView); -void PopulateAmbListView(void); -BOOL ApplyEditToAmbFile(HWND hwnd, int row, int col, const char *newText, char * outFormattedText, int formattedTextBufferSize); -BOOL IsValidInteger(const char *str); -BOOL GetWavFileDuration(const char* filePath, float* outDuration); -BOOL CheckWavFileExists(const char* wavFileName); -BOOL HasMissingWavFiles(char* missingFiles, int bufferSize); -void MatchDurationToWav(HWND hwndListView); -void LoadAmbFileWithDialog(HWND hwnd); -void SaveAmbFileDirectly(HWND hwnd); -void SaveAmbFileAs(HWND hwnd); -void UpdateOverallDuration(void); - -// Currently loaded AMB file -AmbFile g_ambFile = {0}; - -AmbFile g_fileSnapshots[100] = {0}; -int g_snapshotCount = 0, - g_redoCount = 0; - -void ClearFileSnapshots() -{ - memset(g_fileSnapshots, 0, sizeof g_fileSnapshots); - g_snapshotCount = g_redoCount = 0; -} - -// Saves a copy of the currently loaded file onto the stack of snapshots so any changes to the file can be reverted. If the stack is full, drops the -// oldest item. -void SnapshotCurrentFile() -{ - g_redoCount = 0; - - int snapshotCapacity = (sizeof g_fileSnapshots) / (sizeof g_fileSnapshots[0]); - if (g_snapshotCount == snapshotCapacity) { - memmove(&g_fileSnapshots[0], &g_fileSnapshots[1], (snapshotCapacity - 1) * (sizeof g_fileSnapshots[0])); - g_snapshotCount--; - } - - memcpy(&g_fileSnapshots[g_snapshotCount], &g_ambFile, sizeof(AmbFile)); - g_snapshotCount++; -} - -void Undo() -{ - static AmbFile tempAmb; - - if (g_snapshotCount > 0) { - // Swap most recent snapshot with the current file - memcpy(&tempAmb, &g_ambFile, sizeof(AmbFile)); - memcpy(&g_ambFile, &g_fileSnapshots[g_snapshotCount - 1], sizeof(AmbFile)); - memcpy(&g_fileSnapshots[g_snapshotCount - 1], &tempAmb, sizeof(AmbFile)); - - g_snapshotCount--; - g_redoCount++; - - PopulateAmbListView(); // Refresh the ListView to reflect changes - } else - MessageBeep(MB_ICONERROR); -} - -void Redo() -{ - static AmbFile tempAmb; - - if (g_redoCount > 0) { - // Swap oldest redo (stored one above the newest undo on the stack) with the current file - memcpy(&tempAmb, &g_fileSnapshots[g_snapshotCount], sizeof(AmbFile)); - memcpy(&g_fileSnapshots[g_snapshotCount], &g_ambFile, sizeof(AmbFile)); - memcpy(&g_ambFile, &tempAmb, sizeof(AmbFile)); - - g_snapshotCount++; - g_redoCount--; - - PopulateAmbListView(); // Refresh the ListView to reflect changes - } else - MessageBeep(MB_ICONERROR); -} - -// Function declarations -BOOL WINAPI GetOpenFileNameA(LPOPENFILENAMEA lpofn); -BOOL WINAPI GetSaveFileNameA(LPOPENFILENAMEA lpofn); - -// Menu IDs -#define IDM_FILE_OPEN 1001 -#define IDM_FILE_SAVE 1002 -#define IDM_FILE_SAVE_AS 1003 -#define IDM_FILE_DETAILS 1004 -#define IDM_FILE_EXIT 1005 -#define IDM_EDIT_UNDO 1006 -#define IDM_EDIT_REDO 1007 -#define IDM_EDIT_DELETE 1008 -#define IDM_EDIT_ADD 1009 -#define IDM_EDIT_MATCH_WAV 1010 -#define IDM_EDIT_PRUNE 1011 -#define IDM_HELP_ABOUT 1012 - -// Accelerator table for hotkeys -ACCEL g_accelTable[] = { - {FCONTROL | FVIRTKEY, 'O', IDM_FILE_OPEN}, // Ctrl+O - {FCONTROL | FVIRTKEY, 'S', IDM_FILE_SAVE}, // Ctrl+S - {FCONTROL | FVIRTKEY, 'Z', IDM_EDIT_UNDO}, // Ctrl+Z - {FCONTROL | FVIRTKEY, 'Y', IDM_EDIT_REDO}, // Ctrl+Y - {FVIRTKEY, VK_DELETE, IDM_EDIT_DELETE}, // Delete - {FVIRTKEY, VK_INSERT, IDM_EDIT_ADD} // Insert -}; - -// Control IDs -#define ID_PATH_EDIT 102 -#define ID_PLAY_BUTTON 103 -#define ID_STOP_BUTTON 104 -#define ID_AMB_LISTVIEW 105 - -// ListView Column Indices -typedef enum { - COL_TIME = 0, - COL_DURATION, - COL_WAV_FILE, - COL_SPEED_RANDOM, - COL_SPEED_MIN, - COL_SPEED_MAX, - COL_VOLUME_RANDOM, - COL_VOLUME_MIN, - COL_VOLUME_MAX -} ListViewColumn; - -// Track info structure to associate ListView rows with AMB data -typedef struct { - int trackIndex; // MIDI track index - int kmapIndex; // Index of Kmap chunk - int prgmIndex; // Index of Prgm chunk - int kmapItemIndex; // Index of item within Kmap -} AmbRowInfo; - -// Temporary structure for sorting rows by timestamp -typedef struct { - AmbRowInfo rowInfo; - float timestamp; - float duration; - char timeStr[32]; - char durationStr[32]; - char wavFileName[256]; - char speedMaxStr[32]; - char speedMinStr[32]; - char volumeMaxStr[32]; - char volumeMinStr[32]; - bool hasSpeedRandom; - bool hasVolumeRandom; -} RowData; - -// Comparison function for sorting rows by timestamp -int CompareRowsByTimestamp(const void *a, const void *b) -{ - const RowData *rowA = (const RowData *)a; - const RowData *rowB = (const RowData *)b; - - if (rowA->timestamp < rowB->timestamp) return -1; - if (rowA->timestamp > rowB->timestamp) return 1; - return 0; -} - -// Global variables -Path g_civ3MainPath = {0}; -HWND g_hwndPathEdit = NULL; -HWND g_hwndMainWindow = NULL; -HWND g_hwndPlayButton = NULL; -HWND g_hwndStopButton = NULL; -HWND g_hwndListView = NULL; -HWND g_hwndDurationLabel = NULL; -HBRUSH g_hBackgroundBrush = NULL; // Brush for window background color - -// Track info for each row in the ListView -AmbRowInfo g_rowInfo[MAX_SOUND_TRACKS]; -int g_rowCount = 0; // Number of rows in the ListView - -// Custom path helpers -bool PathFileExists(const Path path) -{ - DWORD attr = GetFileAttributes(path); - return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY)); -} - -bool PathIsDirectory(const Path path) -{ - DWORD attr = GetFileAttributes(path); - return (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)); -} - -// Function to browse for an AMB file to open -bool BrowseForAmbFile(HWND hwnd, Path filePath) -{ - // Initialize the OPENFILENAME structure - OPENFILENAMEA ofn; - ZeroMemory(&ofn, sizeof(ofn)); - - // Set up buffer - ZeroMemory(filePath, PATH_BUFFER_SIZE); - - // Setup the open file dialog - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hwnd; - ofn.lpstrFile = filePath; - ofn.nMaxFile = PATH_BUFFER_SIZE; - ofn.lpstrFilter = "AMB Files\0*.amb\0All Files\0*.*\0"; - ofn.nFilterIndex = 1; - ofn.lpstrTitle = "Select an AMB file to open"; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER; - - // Set initial directory to Civ3 install path if found - if (strlen(g_civ3MainPath) > 0) { - ofn.lpstrInitialDir = g_civ3MainPath; - } - - // Show the dialog and get result - return GetOpenFileNameA(&ofn); -} - -// Load an AMB file selected by the user -void LoadAmbFileWithDialog(HWND hwnd) -{ - Path ambFilePath = {0}; - - if (BrowseForAmbFile(hwnd, ambFilePath)) { - if (LoadAmbFile(ambFilePath, &g_ambFile) && g_hwndMainWindow != NULL) { - ClearFileSnapshots(); - - // Extract the filename part from the path - char *fileName = strrchr(ambFilePath, '\\'); - if (fileName) { - fileName++; // Skip past the backslash - } else { - fileName = (char*)ambFilePath; // No backslash found, use the whole path - } - - char windowTitle[100]; - snprintf(windowTitle, sizeof windowTitle, "%s - AMB Editor", fileName); - windowTitle[(sizeof windowTitle) - 1] = '\0'; - SetWindowText(g_hwndMainWindow, windowTitle); - - // Populate the ListView with the loaded AMB file data - PopulateAmbListView(); - } - } -} - -// Browse for a file to save -BOOL BrowseForSaveFile(HWND hwnd, Path filePath) -{ - OPENFILENAMEA ofn; - ZeroMemory(&ofn, sizeof(ofn)); - - // Initialize the filePath with current file if any - if (g_ambFile.filePath[0] != '\0') { - strcpy(filePath, g_ambFile.filePath); - } - - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hwnd; - ofn.lpstrFilter = "AMB Files (*.amb)\0*.amb\0All Files (*.*)\0*.*\0"; - ofn.lpstrFile = filePath; - ofn.nMaxFile = PATH_BUFFER_SIZE; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_EXPLORER; - ofn.lpstrDefExt = "amb"; - ofn.lpstrTitle = "Save AMB File"; - - return GetSaveFileNameA(&ofn); -} - -// Save AMB file directly (without dialog) -void SaveAmbFileDirectly(HWND hwnd) -{ - if (g_ambFile.filePath[0] == '\0') { - MessageBox(hwnd, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Try to save to the current file path - if (SaveAmbFile(&g_ambFile, g_ambFile.filePath)) { - // Success - file saved silently - return; - } - - // Failed to save (likely permissions issue) - fall back to Save As silently - SaveAmbFileAs(hwnd); -} - -// Save AMB file with Save As dialog -void SaveAmbFileAs(HWND hwnd) -{ - if (g_ambFile.filePath[0] == '\0') { - MessageBox(hwnd, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); - return; - } - - Path filePath = {0}; - - if (BrowseForSaveFile(hwnd, filePath)) { - // Try to save the AMB file - if (SaveAmbFile(&g_ambFile, filePath)) { - // Update the current file path to the new location - strcpy(g_ambFile.filePath, filePath); - - // Extract the filename part from the path and update window title - char *fileName = strrchr(filePath, '\\'); - if (fileName) { - fileName++; // Skip past the backslash - } else { - fileName = (char*)filePath; // No backslash found, use the whole path - } - - char windowTitle[100]; - snprintf(windowTitle, sizeof windowTitle, "%s - AMB Editor", fileName); - windowTitle[(sizeof windowTitle) - 1] = '\0'; - SetWindowText(g_hwndMainWindow, windowTitle); - } else { - MessageBox(hwnd, "Failed to save AMB file. Check file permissions and try again.", "Error", MB_OK | MB_ICONERROR); - } - } -} - -// Function to check if a directory is the main Civ3 folder -bool IsCiv3MainFolder(const Path folderPath) -{ - Path testPath; - - // Check for Art folder - strcpy(testPath, folderPath); - PathAppend(testPath, "Art"); - if (!PathIsDirectory(testPath)) { - return false; - } - - // Check for civ3PTW folder - strcpy(testPath, folderPath); - PathAppend(testPath, "civ3PTW"); - if (!PathIsDirectory(testPath)) { - return false; - } - - return true; -} - -// Function to search parent folders for Civ3 install -bool FindCiv3InstallBySearch(const Path startPath) -{ - Path testPath; - - // Start with working directory - strcpy(testPath, startPath); - - // Go up up to 10 parent directories - for (int i = 0; i < 10; i++) { - // Check current directory and subdirectories for main Civ3 folder - WIN32_FIND_DATA findData; - HANDLE hFind; - Path searchPath; - - strcpy(searchPath, testPath); - PathAppend(searchPath, "*"); - - hFind = FindFirstFile(searchPath, &findData); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && - strcmp(findData.cFileName, ".") != 0 && - strcmp(findData.cFileName, "..") != 0) { - - Path subDirPath; - strcpy(subDirPath, testPath); - PathAppend(subDirPath, findData.cFileName); - - if (IsCiv3MainFolder(subDirPath)) { - // Found main Civ3 directory - strcpy(g_civ3MainPath, subDirPath); - FindClose(hFind); - return true; - } - } - } while (FindNextFile(hFind, &findData)); - FindClose(hFind); - } - - // Move up a directory - if (!PathRemoveFileSpec(testPath)) { - break; // Cannot go up further - } - } - - return false; -} - -// Function to find Civ3 install from registry -bool FindCiv3InstallFromRegistry() -{ - HKEY hKey; - char regValue[PATH_BUFFER_SIZE]; - DWORD valueSize = sizeof(regValue); - DWORD valueType; - - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Infogrames Interactive\\Civilization III", - 0, KEY_READ, &hKey) == ERROR_SUCCESS) { - - if (RegQueryValueEx(hKey, "Install_Path", NULL, &valueType, - (LPBYTE)regValue, &valueSize) == ERROR_SUCCESS) { - - if (valueType == REG_SZ) { - regValue[(sizeof regValue) - 1] = '\0'; // RegQueryValueEx is not guaranteed to return null terminated strings - strcpy(g_civ3MainPath, regValue); - - RegCloseKey(hKey); - return true; - } - } - RegCloseKey(hKey); - } - - return false; -} - -bool GetSoundDLLPath(HWND hwnd, Path outSoundDLLPath) -{ - // First, check if INI has a sound.dll path specified - if (strlen(g_iniSoundDLLPath) > 0) { - strcpy(outSoundDLLPath, g_iniSoundDLLPath); - return true; - } - - // Otherwise, check if Conquests\sound.dll exists in the main Civ3 install - if (strlen(g_civ3MainPath) > 0) { - Path conquestsSoundPath; - strcpy(conquestsSoundPath, g_civ3MainPath); - PathAppend(conquestsSoundPath, "Conquests"); - PathAppend(conquestsSoundPath, "sound.dll"); - - if (PathFileExists(conquestsSoundPath)) { - strcpy(outSoundDLLPath, conquestsSoundPath); - return true; - } - } - - // If neither works, ask the user to locate sound.dll - int result = MessageBox(hwnd, - "Playing a preview requires sound.dll from your Civ 3 Conquests install. This could not be found automatically. " - "Would you like to locate sound.dll manually?", - "DLL not found", MB_YESNO | MB_ICONQUESTION); - if (result == IDYES) { - Path path = {0}; - - OPENFILENAMEA ofn; - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hwnd; - ofn.lpstrFile = path; - ofn.nMaxFile = PATH_BUFFER_SIZE; - ofn.lpstrFilter = "DLL Files\0*.dll\0All Files\0*.*\0"; - ofn.nFilterIndex = 1; - ofn.lpstrTitle = "Select sound.dll from your Civ 3 Conquests install"; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER; - - if (GetOpenFileNameA(&ofn)) { - if (PathFileExists(path)) { - strcpy(outSoundDLLPath, path); - return true; - } - } - } - - return false; -} - -// Find Civ3 installation using all available methods -bool FindCiv3Installation(HWND hwnd) -{ - Path cwdPath; - GetCurrentDirectory(PATH_BUFFER_SIZE, cwdPath); - - // Search parent folders first. If that doesn't work, check the registry. - if (FindCiv3InstallBySearch(cwdPath)) { - return true; - } else - return FindCiv3InstallFromRegistry(); -} - -// Create the play and stop buttons -void CreatePlaybackButtons(HWND hwnd) -{ - // Create Play button - g_hwndPlayButton = CreateWindow( - "BUTTON", - "Play Preview", - WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, - 20, 20, 100, 30, - hwnd, (HMENU)ID_PLAY_BUTTON, GetModuleHandle(NULL), NULL - ); - - // Create Stop button - g_hwndStopButton = CreateWindow( - "BUTTON", - "Stop", - WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, - 130, 20, 80, 30, - hwnd, (HMENU)ID_STOP_BUTTON, GetModuleHandle(NULL), NULL - ); -} - -// Add a column to the ListView -void AddListViewColumn(HWND hListView, int index, char *title, int width) -{ - LVCOLUMNA lvc = {0}; - lvc.mask = LVCF_TEXT | LVCF_WIDTH; - lvc.pszText = title; - lvc.cx = width; - - SendMessage(hListView, LVM_INSERTCOLUMN, index, (LPARAM)&lvc); -} - -// Add a row to the ListView -int AddListViewItem(HWND hListView, int index, const char *text) -{ - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = index; - lvi.iSubItem = 0; - lvi.pszText = (LPSTR)text; - - return SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&lvi); -} - -// Set text in a ListView cell -void SetListViewItemText(HWND hListView, int row, int col, const char *text, BOOL allowRepopulation) -{ - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = row; - lvi.iSubItem = col; - lvi.pszText = (LPSTR)text; - - SendMessage(hListView, LVM_SETITEM, 0, (LPARAM)&lvi); - - // Check if we need to repopulate when time changes - if (allowRepopulation && col == COL_TIME) { - PopulateAmbListView(); - } -} - -// Clear all items from the ListView -void ClearListView(HWND hListView) -{ - SendMessage(hListView, LVM_DELETEALLITEMS, 0, 0); -} - -// Check if a WAV file exists in the AMB file's directory -BOOL CheckWavFileExists(const char* wavFileName) -{ - if (!wavFileName || strlen(wavFileName) == 0 || g_ambFile.filePath[0] == '\0') { - return FALSE; - } - - // Construct full path to WAV file - Path wavFilePath; - strcpy(wavFilePath, g_ambFile.filePath); - PathRemoveFileSpec(wavFilePath); // Remove filename, keep directory - PathAppend(wavFilePath, wavFileName); - - // Check if file exists - return PathFileExists(wavFilePath); -} - -// Check if any WAV files are missing and return a list of missing files -BOOL HasMissingWavFiles(char* missingFiles, int bufferSize) -{ - if (!missingFiles || bufferSize == 0 || g_ambFile.filePath[0] == '\0') { - return FALSE; - } - - missingFiles[0] = '\0'; // Initialize as empty string - BOOL hasMissing = FALSE; - - // Check each row in the ListView for missing WAV files - for (int i = 0; i < g_rowCount; i++) { - AmbRowInfo *rowInfo = &g_rowInfo[i]; - if (rowInfo->kmapIndex >= 0 && rowInfo->kmapIndex < g_ambFile.kmapChunkCount && - rowInfo->kmapItemIndex >= 0 && rowInfo->kmapItemIndex < g_ambFile.kmapChunks[rowInfo->kmapIndex].itemCount) { - - KmapChunk *kmap = &g_ambFile.kmapChunks[rowInfo->kmapIndex]; - const char *wavFileName = kmap->items[rowInfo->kmapItemIndex].wavFileName; - - // Ignore empty WAV file names since those don't interfere with playback - if ((wavFileName[0] != '\0') && !CheckWavFileExists(wavFileName)) { - hasMissing = TRUE; - - // Add to missing files list if there's space - if (strlen(missingFiles) > 0) { - strncat(missingFiles, "\n", bufferSize - strlen(missingFiles) - 1); - } - strncat(missingFiles, wavFileName, bufferSize - strlen(missingFiles) - 1); - } - } - } - - return hasMissing; -} - -// Function to check if a string is a valid integer -BOOL IsValidInteger(const char *str) -{ - // Allow for a leading + or - sign - if (*str == '+' || *str == '-') { - str++; - } - - // Empty string or just a sign isn't a valid integer - if (*str == '\0') { - return FALSE; - } - - // Check that all characters are digits - while (*str) { - if (!isdigit(*str)) { - return FALSE; - } - str++; - } - - return TRUE; -} - - - - -// Defines void ShowAmbDetailsWindow(HWND hwndParent) -#include "details_window.c" - - - -// Returns the index of the Prgm chunk referred to by the given sound track. If the track does not validly refer to any Prgm, returns -1. In order for -// the track to be valid, the channel numbers of all events must match and specify a valid Prgm index and the program change event must specify the -// corresponding program number. -int GetReferencedPrgmIfValid(int trackIndex) -{ - SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; - - int prgmIndex = track->programChange.programNumber - 1; - - if ((prgmIndex < 0) || (prgmIndex >= g_ambFile.prgmChunkCount)) - return -1; - - for (int i = 0; i < track->controlChangeCount; i++) - if (track->controlChanges[i].channelNumber != prgmIndex) - return -1; - - if ((track->programChange.channelNumber != prgmIndex) || - (track->noteOn .channelNumber != prgmIndex) || - (track->noteOff .channelNumber != prgmIndex)) - return -1; - - return prgmIndex; -} - -// Populate the ListView with AMB file data -void PopulateAmbListView(void) -{ - if (g_hwndListView == NULL) { - MessageBox(NULL, "ListView control is NULL", "Debug", MB_OK); - return; - } - - // Clear any existing data - ClearListView(g_hwndListView); - - // Reset row info - g_rowCount = 0; - memset(g_rowInfo, 0, sizeof(g_rowInfo)); - - // Check if we have valid AMB data - if (g_ambFile.kmapChunkCount == 0 || g_ambFile.prgmChunkCount == 0 || g_ambFile.midi.trackCount == 0) { - MessageBox(NULL, "AMB file has missing data or is invalid", "Debug", MB_OK); - return; - } - - // Calculate seconds per tick for timing - float secondsPerTick = 0.0f; - if (g_ambFile.midi.ticksPerQuarterNote > 0) { - secondsPerTick = g_ambFile.midi.secondsPerQuarterNote / g_ambFile.midi.ticksPerQuarterNote; - } - - // Collect all row data before sorting - RowData rowData[MAX_SOUND_TRACKS]; - int rowDataCount = 0; - - // Process each MIDI sound track - int soundTrackCount = g_ambFile.midi.trackCount - 1; // Minus one to exclude the info track - for (int trackIndex = 0; trackIndex < soundTrackCount; trackIndex++) { - SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; - - int prgmIndex = GetReferencedPrgmIfValid(trackIndex); - if (prgmIndex < 0) - continue; // No valid Prgm, skip this track - PrgmChunk *matchingPrgm = &g_ambFile.prgmChunks[prgmIndex]; - - // Get the var name from the matching Prgm chunk - const char *varName = matchingPrgm->varName; - - // Find corresponding Kmap chunk with the same var name - KmapChunk *matchingKmap = NULL; - int kmapIndex = -1; - for (int i = 0; i < g_ambFile.kmapChunkCount; i++) { - if (strcmp(g_ambFile.kmapChunks[i].varName, varName) == 0) { - matchingKmap = &g_ambFile.kmapChunks[i]; - kmapIndex = i; - break; - } - } - - if (matchingKmap == NULL || matchingKmap->itemCount == 0) { - continue; // Skip if no matching Kmap found or no items in Kmap - } - - float timestamp = track->deltaTimeNoteOn * secondsPerTick; - float duration = track->deltaTimeNoteOff * secondsPerTick; - - // Check flags for randomization settings (LSB = speed random, bit 1 = volume random) - bool hasSpeedRandom = (matchingPrgm->flags & 0x01) != 0; - bool hasVolumeRandom = (matchingPrgm->flags & 0x02) != 0; - - // For each item in the kmap (usually just one WAV file per track) - for (int j = 0; j < matchingKmap->itemCount; j++) { - if (rowDataCount >= MAX_SOUND_TRACKS) { - break; // Prevent overflow - } - - // Collect row data - RowData *row = &rowData[rowDataCount]; - row->rowInfo.trackIndex = trackIndex; - row->rowInfo.kmapIndex = kmapIndex; - row->rowInfo.prgmIndex = prgmIndex; - row->rowInfo.kmapItemIndex = j; - row->timestamp = timestamp; - row->duration = duration; - row->hasSpeedRandom = hasSpeedRandom; - row->hasVolumeRandom = hasVolumeRandom; - - // Format strings - snprintf(row->timeStr, sizeof(row->timeStr), "%04.3f", timestamp); - snprintf(row->durationStr, sizeof(row->durationStr), "%04.3f", duration); - strncpy(row->wavFileName, matchingKmap->items[j].wavFileName, sizeof(row->wavFileName) - 1); - row->wavFileName[sizeof(row->wavFileName) - 1] = '\0'; - snprintf(row->speedMaxStr, sizeof(row->speedMaxStr), "%d", matchingPrgm->maxRandomSpeed); - snprintf(row->speedMinStr, sizeof(row->speedMinStr), "%d", matchingPrgm->minRandomSpeed); - snprintf(row->volumeMaxStr, sizeof(row->volumeMaxStr), "%d", matchingPrgm->maxRandomVolume); - snprintf(row->volumeMinStr, sizeof(row->volumeMinStr), "%d", matchingPrgm->minRandomVolume); - - rowDataCount++; - } - } - - // Sort rows by timestamp - qsort(rowData, rowDataCount, sizeof(RowData), CompareRowsByTimestamp); - - // Add sorted rows to ListView - for (int i = 0; i < rowDataCount; i++) { - RowData *row = &rowData[i]; - - // Add the item to the ListView - int listRow = AddListViewItem(g_hwndListView, 0x7FFFFFFF, row->timeStr); - if (listRow >= 0) { - // Store the track info for this row - g_rowInfo[g_rowCount] = row->rowInfo; - g_rowCount++; - - // Set all the column values - SetListViewItemText(g_hwndListView, listRow, COL_DURATION, row->durationStr, FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_WAV_FILE, row->wavFileName, FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_SPEED_RANDOM, row->hasSpeedRandom ? "Yes" : "No", FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_SPEED_MIN, row->speedMinStr, FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_SPEED_MAX, row->speedMaxStr, FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_RANDOM, row->hasVolumeRandom ? "Yes" : "No", FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_MIN, row->volumeMinStr, FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_MAX, row->volumeMaxStr, FALSE); - } - } - - // Update the overall duration display - UpdateOverallDuration(); -} - -// Handle the beginning of a ListView label edit -BOOL HandleBeginLabelEdit(HWND hwnd, NMLVDISPINFOA *pInfo) -{ - // You can reject edits for specific columns or rows if needed - // For now, allow editing all cells - return TRUE; // Return TRUE to allow the edit, FALSE to prevent it -} - -// Apply an edit to the AMB file data structure. Returns TRUE if the edit was accepted or FALSE if it was invalid. If the edit was accepted, the new -// text is written to outFormattedText in a way that is consistent with the usual format of the ListView display (e.g. float fields are formatted -// to 3 decimal places). If the new text exactly matches the current cell text, the edit is accepted but no snapshot is taken and no AMB data is modified. -// outFormattedText must not be NULL and formattedTextBufferSize must be at least 1. -BOOL ApplyEditToAmbFile(HWND hwnd, int row, int col, const char *newText, char * outFormattedText, int formattedTextBufferSize) -{ - // Make sure we have valid row info - if (row >= g_rowCount) { - MessageBox(hwnd, "Invalid row index", "Error", MB_OK | MB_ICONERROR); - return FALSE; - } - - // Get the track information for this row - AmbRowInfo *rowInfo = &g_rowInfo[row]; - int trackIndex = rowInfo->trackIndex; - int kmapIndex = rowInfo->kmapIndex; - int prgmIndex = rowInfo->prgmIndex; - int kmapItemIndex = rowInfo->kmapItemIndex; - - // Check if indices are valid - if (trackIndex < 0 || trackIndex >= g_ambFile.midi.trackCount || - kmapIndex < 0 || kmapIndex >= g_ambFile.kmapChunkCount || - prgmIndex < 0 || prgmIndex >= g_ambFile.prgmChunkCount || - kmapItemIndex < 0 || kmapItemIndex >= g_ambFile.kmapChunks[kmapIndex].itemCount) { - - MessageBox(hwnd, "Invalid track indices", "Error", MB_OK | MB_ICONERROR); - return FALSE; - } - - // Check if new text matches the current value in the cell - if so, accept without changing anything - char currentText[256] = {0}; - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = row; - lvi.iSubItem = col; - lvi.pszText = currentText; - lvi.cchTextMax = sizeof(currentText); - SendMessage(g_hwndListView, LVM_GETITEMTEXT, row, (LPARAM)&lvi); - - if (strcmp(newText, currentText) == 0) { - // Text unchanged - accept edit but don't modify data or take snapshot - strncpy(outFormattedText, newText, formattedTextBufferSize); - outFormattedText[formattedTextBufferSize - 1] = '\0'; - return TRUE; - } - - // Get references to the actual AMB data structures - PrgmChunk *prgm = &g_ambFile.prgmChunks[prgmIndex]; - KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; - - // Update the appropriate field based on the column that was edited - BOOL newTextIsValid = TRUE; - switch (col) { - case COL_TIME: - { - char * afterParsing; - float newTime = strtod(newText, &afterParsing); - if (afterParsing != newText) { - SnapshotCurrentFile(); - - float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; - g_ambFile.midi.soundTracks[trackIndex].deltaTimeNoteOn = round(newTime * ticksPerSecond); - - snprintf(outFormattedText, formattedTextBufferSize, "%04.3f", newTime); - - // Update overall duration since timestamp changed - UpdateOverallDuration(); - - } else { - newTextIsValid = FALSE; - } - } - break; - - case COL_DURATION: - { - char * afterParsing; - float newDuration = strtod(newText, &afterParsing); - if (afterParsing != newText) { - SnapshotCurrentFile(); - - float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; - g_ambFile.midi.soundTracks[trackIndex].deltaTimeNoteOff = round(newDuration * ticksPerSecond); - - snprintf(outFormattedText, formattedTextBufferSize, "%04.3f", newDuration); - - // Update overall duration since duration changed - UpdateOverallDuration(); - - } else { - newTextIsValid = FALSE; - } - } - break; - - case COL_WAV_FILE: // WAV filename - // Reject the edit if the new text contains a slash - if ((strchr(newText, '\\') == NULL) && (strchr(newText, '/') == NULL)) { - SnapshotCurrentFile(); - - // Write new text to kmap item - strncpy(kmap->items[kmapItemIndex].wavFileName, newText, sizeof(kmap->items[kmapItemIndex].wavFileName) - 1); - kmap->items[kmapItemIndex].wavFileName[sizeof(kmap->items[kmapItemIndex].wavFileName) - 1] = '\0'; - - // Update Kmap size - kmap->size = ComputeKmapChunkSize(kmap); - - // Write new text to formatted output - strncpy(outFormattedText, newText, formattedTextBufferSize); - } else { - newTextIsValid = FALSE; - } - break; - - case COL_SPEED_RANDOM: // Speed Random flag - { - if (strcmp(newText, "Yes") == 0 || strcmp(newText, "No") == 0) { - SnapshotCurrentFile(); - - if (strcmp(newText, "Yes") == 0) { - prgm->flags |= 0x01; // Set bit 0 - } else { - prgm->flags &= ~0x01; // Clear bit 0 - } - - strncpy(outFormattedText, (prgm->flags & 0x01) ? "Yes" : "No", formattedTextBufferSize); - } else { - newTextIsValid = FALSE; - } - } - break; - - case COL_SPEED_MIN: // Speed Min - if (IsValidInteger(newText)) { - SnapshotCurrentFile(); - prgm->minRandomSpeed = atoi(newText); - snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->minRandomSpeed); - } else { - newTextIsValid = FALSE; - } - break; - - case COL_SPEED_MAX: // Speed Max - if (IsValidInteger(newText)) { - SnapshotCurrentFile(); - prgm->maxRandomSpeed = atoi(newText); - snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->maxRandomSpeed); - } else { - newTextIsValid = FALSE; - } - break; - - case COL_VOLUME_RANDOM: // Volume Random flag - { - if (strcmp(newText, "Yes") == 0 || strcmp(newText, "No") == 0) { - SnapshotCurrentFile(); - - if (strcmp(newText, "Yes") == 0) { - prgm->flags |= 0x02; // Set bit 1 - } else { - prgm->flags &= ~0x02; // Clear bit 1 - } - - strncpy(outFormattedText, (prgm->flags & 0x02) ? "Yes" : "No", formattedTextBufferSize); - } else { - newTextIsValid = FALSE; - } - } - break; - - case COL_VOLUME_MIN: // Volume Min - if (IsValidInteger(newText)) { - SnapshotCurrentFile(); - prgm->minRandomVolume = atoi(newText); - snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->minRandomVolume); - } else { - newTextIsValid = FALSE; - } - break; - - case COL_VOLUME_MAX: // Volume Max - if (IsValidInteger(newText)) { - SnapshotCurrentFile(); - prgm->maxRandomVolume = atoi(newText); - snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->maxRandomVolume); - } else { - newTextIsValid = FALSE; - } - break; - } - - // Play error beep if new text didn't validate. If it did that means we wrote something to outFormattedText so make sure it's null terminated. - if (! newTextIsValid) - MessageBeep(MB_ICONERROR); - else - outFormattedText[formattedTextBufferSize - 1] = '\0'; - - return newTextIsValid; -} - -void DeleteKmapChunk(int kmapIndex) -{ - // Shift all Kmap chunks after this one forward - for (int i = kmapIndex; i < g_ambFile.kmapChunkCount - 1; i++) { - memcpy(&g_ambFile.kmapChunks[i], &g_ambFile.kmapChunks[i + 1], sizeof(KmapChunk)); - } - g_ambFile.kmapChunkCount--; -} - -void DeletePrgmChunk(int prgmIndex) -{ - // Shift all Prgm chunks after this one forward - for (int i = prgmIndex; i < g_ambFile.prgmChunkCount - 1; i++) { - memcpy(&g_ambFile.prgmChunks[i], &g_ambFile.prgmChunks[i + 1], sizeof(PrgmChunk)); - } - g_ambFile.prgmChunkCount--; - - // Update the number field of any remaining Prgm chunks - they are 1-based - for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { - g_ambFile.prgmChunks[i].number = i + 1; - } - - // Update channelNumber in all MIDI sound tracks for any that reference - // Prgm chunks with indices greater than the one we deleted - for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track - SoundTrack *track = &g_ambFile.midi.soundTracks[i]; - - // Check all control change events - for (int j = 0; j < track->controlChangeCount; j++) { - if (track->controlChanges[j].channelNumber > prgmIndex) { - track->controlChanges[j].channelNumber--; - } - } - - // Check program change event - if (track->programChange.channelNumber > prgmIndex) { - track->programChange.channelNumber--; - } - - // Update programNumber if it references deleted program or those after it - // Note: programNumbers are 1-based (matching the Prgm number field) - if (track->programChange.programNumber == prgmIndex + 1) { - // This is referencing the deleted program - we'd need to update it - // to a valid program or potentially disable this track - // For now, if there are other programs, use the first available one - if (g_ambFile.prgmChunkCount > 0) { - track->programChange.programNumber = 1; // Use first available program (1-based) - } - } - else if (track->programChange.programNumber > prgmIndex + 1) { - // This references a program that got shifted down, so update the index - track->programChange.programNumber--; - } - - // Check note on event - if (track->noteOn.channelNumber > prgmIndex) { - track->noteOn.channelNumber--; - } - - // Check note off event - if (track->noteOff.channelNumber > prgmIndex) { - track->noteOff.channelNumber--; - } - } -} - -void DeleteSoundTrack(int trackIndex) -{ - for (int i = trackIndex; i < g_ambFile.midi.trackCount - 2; i++) { // -2 because we skip info track (0) and want to leave room for the last valid track - memcpy(&g_ambFile.midi.soundTracks[i], &g_ambFile.midi.soundTracks[i + 1], sizeof(SoundTrack)); - } - g_ambFile.midi.trackCount--; -} - -void DeleteRow(int row) -{ - // If no file loaded or row is invalid, do nothing - if (g_ambFile.filePath[0] == '\0' || row < 0 || row >= g_rowCount) { - MessageBox(NULL, "Invalid row or no AMB file loaded", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Get the references to the chunks and tracks we need to work with - AmbRowInfo *rowInfo = &g_rowInfo[row]; - int trackIndex = rowInfo->trackIndex; - int kmapIndex = rowInfo->kmapIndex; - int prgmIndex = rowInfo->prgmIndex; - - // Take a snapshot before making changes - SnapshotCurrentFile(); - - // First, check if the Kmap chunk is referenced by other Prgm chunks - KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; - const char *kmapVarName = kmap->varName; - int kmapReferenceCount = 0; - - for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { - if (strcmp(g_ambFile.prgmChunks[i].varName, kmapVarName) == 0) { - kmapReferenceCount++; - } - } - - // Delete the Kmap chunk if it's only referenced by the Prgm we're deleting - if (kmapReferenceCount <= 1) { - DeleteKmapChunk(kmapIndex); - } - - // Next, check if the Prgm chunk is referenced by other MIDI tracks - int prgmReferenceCount = 0; - for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track - if (GetReferencedPrgmIfValid(i) == prgmIndex) - prgmReferenceCount++; - } - - // Delete the Prgm chunk if it's only referenced by the track we're deleting - if (prgmReferenceCount <= 1) { - DeletePrgmChunk(prgmIndex); - } - - // Delete the MIDI track - DeleteSoundTrack(trackIndex); - - // Refresh the ListView to show updated AMB data - PopulateAmbListView(); -} - -void AddRow() -{ - // If no file is loaded or we're already at the limit of how many sound tracks, prgm chunks, or kmap chunks we can have one file, report an - // error then return. - if (g_ambFile.filePath[0] == '\0') { - MessageBox(NULL, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); - return; - } - - if (g_ambFile.kmapChunkCount >= MAX_CHUNKS) { - MessageBox(NULL, "Cannot add more rows: Maximum number of Kmap chunks reached.", "Error", MB_OK | MB_ICONERROR); - return; - } - - if (g_ambFile.prgmChunkCount >= MAX_CHUNKS) { - MessageBox(NULL, "Cannot add more rows: Maximum number of Prgm chunks reached.", "Error", MB_OK | MB_ICONERROR); - return; - } - - if (g_ambFile.midi.trackCount >= MAX_SOUND_TRACKS + 1) { // +1 because first track is info track - MessageBox(NULL, "Cannot add more rows: Maximum number of sound tracks reached.", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Snapshot file - SnapshotCurrentFile(); - - // Find a unique name - char uniqueName[32]; - int nameCounter = 1; - bool nameIsUnique; - - do { - snprintf(uniqueName, sizeof(uniqueName), "NewTrack%d", nameCounter++); - nameIsUnique = true; - - // Check if this name is already used as a track name - for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track - if (strcmp(g_ambFile.midi.soundTracks[i].trackName.name, uniqueName) == 0) { - nameIsUnique = false; - break; - } - } - - // Check if this name is already used as a var name or effect name - if (nameIsUnique) { - for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { - if (strcmp(g_ambFile.prgmChunks[i].varName, uniqueName) == 0 || - strcmp(g_ambFile.prgmChunks[i].effectName, uniqueName) == 0) { - nameIsUnique = false; - break; - } - } - } - - // Check if this name is already used as a kmap var name - if (nameIsUnique) { - for (int i = 0; i < g_ambFile.kmapChunkCount; i++) { - if (strcmp(g_ambFile.kmapChunks[i].varName, uniqueName) == 0) { - nameIsUnique = false; - break; - } - } - } - } while (!nameIsUnique && nameCounter < 1000); // Prevent infinite loop - - if (!nameIsUnique) { - MessageBox(NULL, "Failed to generate a unique name for new row.", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Create a Kmap chunk - int kmapIndex = g_ambFile.kmapChunkCount; - KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; - - // Initialize the Kmap chunk - memset(kmap, 0, sizeof(KmapChunk)); - - kmap->flags = 2; // Standard flags value in Civ3 AMBs - kmap->itemCount = 1; - kmap->itemSize = 12; - - // Set the varName to our unique name - strcpy(kmap->varName, uniqueName); - - // Initialize the Kmap item - static const unsigned char kmapItemData[12] = { 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }; - memcpy(kmap->items[0].data, kmapItemData, 12); - strcpy(kmap->items[0].wavFileName, "<.wav file name>"); - - // Calculate the size of the Kmap chunk - kmap->size = ComputeKmapChunkSize(kmap); - - // Increment the Kmap count - g_ambFile.kmapChunkCount++; - - // Create a Prgm chunk - int prgmIndex = g_ambFile.prgmChunkCount; - PrgmChunk *prgm = &g_ambFile.prgmChunks[prgmIndex]; - - // Initialize the Prgm chunk - memset(prgm, 0, sizeof(PrgmChunk)); - - // Fill in names and set number (1-based) - strcpy(prgm->effectName, uniqueName); - strcpy(prgm->varName, uniqueName); - prgm->number = prgmIndex + 1; - - // Calculate the size of the Prgm chunk - prgm->size = ComputePrgmChunkSize(prgm); - - // Increment the Prgm count - g_ambFile.prgmChunkCount++; - - // Create a sound track - int trackIndex = g_ambFile.midi.trackCount - 1; // Index for the new track (after info track) - SoundTrack *track = &g_ambFile.midi.soundTracks[trackIndex]; - - // Initialize the sound track - memset(track, 0, sizeof(SoundTrack)); - - // Set track name - track->deltaTimeTrackName = 0; - strcpy(track->trackName.name, uniqueName); - - // Add one control change event - track->controlChangeCount = 1; - track->deltaTimeControlChanges[0] = 0; - track->controlChanges[0].channelNumber = prgmIndex; // 0-based index - track->controlChanges[0].controllerNumber = 32; - track->controlChanges[0].value = 0; - - // Set program change event - track->deltaTimeProgramChange = 0; - track->programChange.channelNumber = prgmIndex; // 0-based index - track->programChange.programNumber = prgmIndex + 1; // 1-based number - - // Find a unique key for the note on/off events - int keyValue = 60; // Start at middle C - bool keyIsUnique; - - do { - keyIsUnique = true; - - // Check if this key is already used in any other track - for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track - if (i != trackIndex && g_ambFile.midi.soundTracks[i].noteOn.key == keyValue) { - keyIsUnique = false; - keyValue++; - break; - } - } - } while (!keyIsUnique && keyValue < 127); - - // Set note on event - track->deltaTimeNoteOn = 0; - track->noteOn.channelNumber = prgmIndex; // 0-based index - track->noteOn.key = keyValue; - track->noteOn.velocity = 64; // Medium velocity - - // Set note off event - one second after note on - float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; - track->deltaTimeNoteOff = (int)ticksPerSecond; // 1 second duration - track->noteOff.channelNumber = prgmIndex; // 0-based index - track->noteOff.key = keyValue; - track->noteOff.velocity = 64; // Same as note on - - // Set end of track - track->deltaTimeEndOfTrack = 0; - - // Calculate the size of the sound track - track->size = ComputeSoundTrackSize(track); - - // Increment the track count - g_ambFile.midi.trackCount++; - - // Refresh the ListView - PopulateAmbListView(); -} - -void Prune() -{ - if (g_ambFile.filePath[0] == '\0') { - MessageBox(NULL, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Make sure the ListView is up to date. We're going to delete any Kmap or Prgm chunks and any sound tracks that don't appear in it. - PopulateAmbListView(); - - int unneededKmapCount = 0; - int unneededPrgmCount = 0; - int unneededTrackCount = 0; - bool tookSnapshot = false; - - for (int kmapIndex = g_ambFile.kmapChunkCount - 1; kmapIndex >= 0; kmapIndex--) { - bool inAnyRow = false; - for (int i = 0; i < g_rowCount; i++) { - if (g_rowInfo[i].kmapIndex == kmapIndex) { - inAnyRow = true; - break; - } - } - if (! inAnyRow) { - if (! tookSnapshot) { - SnapshotCurrentFile(); - tookSnapshot = true; - } - DeleteKmapChunk(kmapIndex); - unneededKmapCount++; - } - } - - for (int prgmIndex = g_ambFile.prgmChunkCount - 1; prgmIndex >= 0; prgmIndex--) { - bool inAnyRow = false; - for (int i = 0; i < g_rowCount; i++) { - if (g_rowInfo[i].prgmIndex == prgmIndex) { - inAnyRow = true; - break; - } - } - if (! inAnyRow) { - if (! tookSnapshot) { - SnapshotCurrentFile(); - tookSnapshot = true; - } - DeletePrgmChunk(prgmIndex); - unneededPrgmCount++; - } - } - - for (int trackIndex = g_ambFile.midi.trackCount - 2; trackIndex >= 0; trackIndex--) { // Skip info track - bool inAnyRow = false; - for (int i = 0; i < g_rowCount; i++) { - if (g_rowInfo[i].trackIndex == trackIndex) { - inAnyRow = true; - break; - } - } - if (! inAnyRow) { - if (! tookSnapshot) { - SnapshotCurrentFile(); - tookSnapshot = true; - } - DeleteSoundTrack(trackIndex); - unneededTrackCount++; - } - } - - if ((unneededKmapCount == 0) && (unneededPrgmCount == 0) && (unneededTrackCount == 0)) { - MessageBox(NULL, "The AMB data has no superfluous parts.", "Nothing to do", MB_OK | MB_ICONINFORMATION); - } else { - char msg[300] = {0}; - snprintf (msg, (sizeof msg) - 1, "Deleted %d unused Kmap chunk%s, %d unused Prgm chunk%s, and %d unused or invalid MIDI track%s.", - unneededKmapCount , unneededKmapCount == 1 ? "" : "s", - unneededPrgmCount , unneededPrgmCount == 1 ? "" : "s", - unneededTrackCount, unneededTrackCount == 1 ? "" : "s"); - MessageBox(NULL, msg, "Pruning results", MB_OK | MB_ICONINFORMATION); - - PopulateAmbListView(); - } -} - -// Handle the end of a ListView label edit -BOOL HandleEndLabelEdit(HWND hwnd, NMLVDISPINFOA *pInfo) -{ - // Check if the edit was cancelled - if (pInfo->item.pszText == NULL) { - return FALSE; // Edit was cancelled, no update needed - } - - // Get the row and column (subitem) being edited - int row = pInfo->item.iItem; - int col = pInfo->item.iSubItem; - char *newText = pInfo->item.pszText; - - // Apply the edit to the AMB file data structure - char formattedText[256]; - BOOL editAccepted = ApplyEditToAmbFile(hwnd, row, col, newText, formattedText, sizeof formattedText); - if (editAccepted) { - SetListViewItemText(g_hwndListView, row, col, formattedText, TRUE); - } - return editAccepted; -} - -// Global variables to track the current edit control's position -int g_editRow = -1; -int g_editCol = -1; -HWND g_hwndEdit = NULL; -WNDPROC g_oldEditProc = NULL; // Original window procedure for the edit control - -// Custom window procedure for the edit control to handle keyboard input -LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_KEYDOWN: - switch (wParam) - { - case VK_RETURN: - // Enter key - accept changes and destroy edit control - if (g_hwndEdit != NULL && g_editRow >= 0 && g_editCol >= 0) { - char buffer[256]; - GetWindowText(g_hwndEdit, buffer, sizeof(buffer)); - - // Apply the edit to the AMB file data structure and update the ListView with the formatted text - char formattedBuffer[256]; - if (ApplyEditToAmbFile(GetParent(GetParent(hwnd)), g_editRow, g_editCol, buffer, formattedBuffer, sizeof formattedBuffer)) { - SetListViewItemText(g_hwndListView, g_editRow, g_editCol, formattedBuffer, TRUE); - } - - // Destroy the edit control - DestroyWindow(g_hwndEdit); - g_hwndEdit = NULL; - g_editRow = -1; - g_editCol = -1; - } - return 0; - - case VK_ESCAPE: - // Escape key - cancel edit - if (g_hwndEdit != NULL) { - DestroyWindow(g_hwndEdit); - g_hwndEdit = NULL; - g_editRow = -1; - g_editCol = -1; - } - return 0; - } - break; - } - - // Call the original window procedure for other messages - return CallWindowProc(g_oldEditProc, hwnd, uMsg, wParam, lParam); -} - -// Returns the currently selected row and whether or not any was selected. Optionally displays an error when none is selected. -bool GetSelectedRow(char const * errorMsg, int * outSelectedRow) -{ - int rowCount = SendMessage(g_hwndListView, LVM_GETITEMCOUNT, 0, 0); - for (int i = 0; i < rowCount; i++) { - UINT state = SendMessage(g_hwndListView, LVM_GETITEMSTATE, i, LVIS_SELECTED); - if (state & LVIS_SELECTED) { - *outSelectedRow = i; - return true; - } - } - - // If we get here, no row was selected - if (errorMsg) - MessageBox(NULL, errorMsg, "Information", MB_OK | MB_ICONINFORMATION); - return false; -} - -// Function to match duration to WAV file for the selected row -void MatchDurationToWav(HWND hwndListView) -{ - int selectedRow; - if (! GetSelectedRow("Please select a row to match duration", &selectedRow)) - return; - - // Make sure we have valid row info - if (selectedRow >= g_rowCount) { - MessageBox(NULL, "Invalid row selection", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Get the WAV filename from the selected row - char wavFileName[256] = {0}; - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = selectedRow; - lvi.iSubItem = COL_WAV_FILE; - lvi.pszText = wavFileName; - lvi.cchTextMax = sizeof(wavFileName); - SendMessage(hwndListView, LVM_GETITEMTEXT, selectedRow, (LPARAM)&lvi); - - if (strlen(wavFileName) == 0) { - MessageBox(NULL, "No WAV filename found in selected row", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Construct full path to WAV file (assuming it's in the same directory as the AMB file) - Path wavFilePath; - strcpy(wavFilePath, g_ambFile.filePath); - PathRemoveFileSpec(wavFilePath); // Remove filename, keep directory - PathAppend(wavFilePath, wavFileName); - - // Get WAV file duration - float wavDuration; - if (!GetWavFileDuration(wavFilePath, &wavDuration)) { - char errorMsg[512]; - snprintf(errorMsg, sizeof(errorMsg), "Could not read duration from WAV file:\n%s\n\nMake sure the file exists and is a valid WAV file.", wavFilePath); - MessageBox(NULL, errorMsg, "Error", MB_OK | MB_ICONERROR); - return; - } - - // Convert duration to string and apply it to the AMB file - char durationStr[32]; - snprintf(durationStr, sizeof(durationStr), "%.3f", wavDuration); - - char formattedText[256]; - if (ApplyEditToAmbFile(GetParent(hwndListView), selectedRow, COL_DURATION, durationStr, formattedText, sizeof(formattedText))) { - SetListViewItemText(hwndListView, selectedRow, COL_DURATION, formattedText, TRUE); - } else { - MessageBeep(MB_ICONERROR); - } -} - -// Function to programmatically start editing a ListView subitem -void EditListViewSubItem(HWND hwndListView, int row, int col) -{ - // First select the item - LVITEMA lvi = {0}; - lvi.stateMask = LVIS_SELECTED; - lvi.state = LVIS_SELECTED; - SendMessage(hwndListView, LVM_SETITEMSTATE, row, (LPARAM)&lvi); - - // For subitems, we need to create a custom edit control - // First get the text of the subitem - char buffer[256] = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = row; - lvi.iSubItem = col; - lvi.pszText = buffer; - lvi.cchTextMax = sizeof(buffer); - SendMessage(hwndListView, LVM_GETITEMTEXT, row, (LPARAM)&lvi); - - // Create a structure for LVM_GETSUBITEMRECT - // The struct needs to have subItem in top and flags in left - RECT rect; - memset(&rect, 0, sizeof(RECT)); - rect.top = col; // subItem index - rect.left = LVIR_BOUNDS; // Type of rectangle (LVIR_BOUNDS for entire cell) - SendMessage(hwndListView, LVM_GETSUBITEMRECT, row, (LPARAM)&rect); - - // If we already have an edit control, destroy it - if (g_hwndEdit != NULL) { - DestroyWindow(g_hwndEdit); - g_hwndEdit = NULL; - } - - // For column 0 (Time), we need to adjust the width to match the column width - // instead of using the full row width that LVIR_BOUNDS returns - if (col == COL_TIME) { - // Get the width of column 0 - LVCOLUMNA lvc = {0}; - lvc.mask = LVCF_WIDTH; - SendMessage(hwndListView, LVM_GETCOLUMN, COL_TIME, (LPARAM)&lvc); - - // Adjust the rectangle to match the column width - rect.right = rect.left + lvc.cx; - } - - // Create an edit control over the subitem - g_hwndEdit = CreateWindow( - "EDIT", buffer, - WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - hwndListView, (HMENU)1000, GetModuleHandle(NULL), NULL); - - if (g_hwndEdit) { - // Store which row and column we're editing - g_editRow = row; - g_editCol = col; - - // Subclass the edit control to handle keyboard input - g_oldEditProc = (WNDPROC)SetWindowLongPtr(g_hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditSubclassProc); - - // Set focus to the edit control and select all text - SetFocus(g_hwndEdit); - SendMessage(g_hwndEdit, EM_SETSEL, 0, -1); - } -} - -// Calculate and update the overall duration display -void UpdateOverallDuration(void) -{ - if (g_hwndDurationLabel == NULL) { - return; - } - - float maxEndTime = 0.0f; - - // Check if we have valid AMB data - if (g_ambFile.kmapChunkCount == 0 || g_ambFile.prgmChunkCount == 0 || g_ambFile.midi.trackCount == 0) { - SetWindowText(g_hwndDurationLabel, "Overall Duration: 0.000 sec"); - return; - } - - // Calculate seconds per tick for timing - float secondsPerTick = 0.0f; - if (g_ambFile.midi.ticksPerQuarterNote > 0) { - secondsPerTick = g_ambFile.midi.secondsPerQuarterNote / g_ambFile.midi.ticksPerQuarterNote; - } - - // Process each MIDI sound track to find the longest duration - int soundTrackCount = g_ambFile.midi.trackCount - 1; // Minus one to exclude the info track - for (int trackIndex = 0; trackIndex < soundTrackCount; trackIndex++) { - SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; - - int prgmIndex = GetReferencedPrgmIfValid(trackIndex); - if (prgmIndex < 0) - continue; // No valid Prgm, skip this track - - float timestamp = track->deltaTimeNoteOn * secondsPerTick; - float duration = track->deltaTimeNoteOff * secondsPerTick; - float endTime = timestamp + duration; - - if (endTime > maxEndTime) { - maxEndTime = endTime; - } - } - - // Update the label text - char durationText[64] = {0}; - snprintf(durationText, sizeof(durationText) - 1, "Overall Duration: %04.3f sec", maxEndTime); - SetWindowText(g_hwndDurationLabel, durationText); -} - -// Create and initialize the ListView control -void CreateAmbListView(HWND hwnd) -{ - // Create ListView control below the playback buttons - g_hwndListView = CreateWindow( - WC_LISTVIEW, - "", - WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_NOHSCROLL | LVS_EDITLABELS, - 20, 70, // x, y position (below the buttons) - 835, 460, // width, height (fill most of the window) - hwnd, - (HMENU)ID_AMB_LISTVIEW, - GetModuleHandle(NULL), - NULL - ); - - if (g_hwndListView == NULL) { - MessageBox(hwnd, "Could not create ListView control", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Set extended ListView styles - DWORD exStyle = LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES; - SendMessage(g_hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle); - - // Add columns to the ListView - AddListViewColumn(g_hwndListView, COL_TIME, "Time (sec.)", 85); - AddListViewColumn(g_hwndListView, COL_DURATION, "Duration (sec.)", 95); - AddListViewColumn(g_hwndListView, COL_WAV_FILE, "WAV File", 235); - AddListViewColumn(g_hwndListView, COL_SPEED_RANDOM, "Speed Rnd", 70); - AddListViewColumn(g_hwndListView, COL_SPEED_MIN, "Speed Min", 70); - AddListViewColumn(g_hwndListView, COL_SPEED_MAX, "Speed Max", 70); - AddListViewColumn(g_hwndListView, COL_VOLUME_RANDOM, "Vol. Rnd", 70); - AddListViewColumn(g_hwndListView, COL_VOLUME_MIN, "Vol. Min", 70); - AddListViewColumn(g_hwndListView, COL_VOLUME_MAX, "Vol. Max", 70); - - // Create duration label below the ListView - g_hwndDurationLabel = CreateWindow( - "STATIC", - "Overall Duration: 0.000 sec", - WS_CHILD | WS_VISIBLE | SS_LEFT, - 20, 540, // x, y position (below the ListView) - 250, 20, // width, height - hwnd, - NULL, - GetModuleHandle(NULL), - NULL - ); -} - -LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_CREATE: - // Read INI settings - { - Path iniFullPath; - GetCurrentDirectory(PATH_BUFFER_SIZE, iniFullPath); - PathAppend(iniFullPath, "amb_editor.ini"); - - GetPrivateProfileString("Paths", "civ_3_install_path", "", g_iniCiv3InstallPath, PATH_BUFFER_SIZE, iniFullPath); - GetPrivateProfileString("Paths", "sound_dll_path" , "", g_iniSoundDLLPath , PATH_BUFFER_SIZE, iniFullPath); - GetPrivateProfileString("Paths", "temp_directory" , "", g_iniTempDirectory , PATH_BUFFER_SIZE, iniFullPath); - } - - // If we've been given a specific Civ 3 install path in the INI, use that. Otherwise search for one. - if (strlen(g_iniCiv3InstallPath) > 0) { - strcpy(g_civ3MainPath, g_iniCiv3InstallPath); - } else { - FindCiv3Installation(hwnd); - } - - g_hwndMainWindow = hwnd; - - // Create playback buttons - CreatePlaybackButtons(hwnd); - - // Create the AMB ListView control - CreateAmbListView(hwnd); - - return 0; - - case WM_COMMAND: - // Handle menu commands - switch (LOWORD(wParam)) - { - case IDM_FILE_OPEN: - // Show open file dialog to load an AMB file - LoadAmbFileWithDialog(hwnd); - return 0; - - case IDM_FILE_SAVE: - // Save AMB file directly - SaveAmbFileDirectly(hwnd); - return 0; - - case IDM_FILE_SAVE_AS: - // Show save file dialog to save AMB file as - SaveAmbFileAs(hwnd); - return 0; - - case IDM_FILE_DETAILS: - // Show window with AMB file details - ShowAmbDetailsWindow(hwnd); - return 0; - - case IDM_FILE_EXIT: - // Exit the application - PostMessage(hwnd, WM_CLOSE, 0, 0); - return 0; - - case IDM_EDIT_UNDO: - // Perform undo operation - Undo(); - return 0; - - case IDM_EDIT_REDO: - // Perform redo operation - Redo(); - return 0; - - case IDM_EDIT_ADD: - // Add a new row - AddRow(); - return 0; - - case IDM_EDIT_DELETE: - { - // Delete the selected row - int selectedRow; - if (GetSelectedRow("Please select a row to delete", &selectedRow)) - DeleteRow(selectedRow); - - return 0; - } - - case IDM_EDIT_MATCH_WAV: - // Match duration to WAV file - MatchDurationToWav(g_hwndListView); - return 0; - - case IDM_EDIT_PRUNE: - Prune(); - return 0; - - case IDM_HELP_ABOUT: - // Show about dialog - MessageBox(hwnd, - "This is a tool for inspecting and modifying the AMB sound files used by Sid Meier's Civilization III.\n\n" - "Last updated in C3X Release 23\n\n" - "For more info, see README.txt", - "About AMB Editor", - MB_OK | MB_ICONINFORMATION); - return 0; - - case ID_PLAY_BUTTON: - // Handle Play button click - if (g_ambFile.filePath[0] != '\0') { - bool encounteredError = false; - - // Check that the preview player is initialized. If it's not, try to initialize it. - if (! previewPlayerIsInitialized) { - Path soundDLLPath; - if (GetSoundDLLPath(hwnd, soundDLLPath)) { - InitializePreviewPlayer(hwnd, soundDLLPath); - } - if (! previewPlayerIsInitialized) - encounteredError = true; - } - - // Check for missing WAV files before attempting preview - if (! encounteredError) { - char missingFiles[1024]; - if (HasMissingWavFiles(missingFiles, sizeof(missingFiles))) { - char errorMsg[1280]; - snprintf(errorMsg, sizeof(errorMsg), - "Cannot preview AMB file because the following WAV files are missing:\n\n%s\n\nPlease ensure all WAV files are present in the AMB file's directory.", - missingFiles); - MessageBox(hwnd, errorMsg, "Missing WAV Files", MB_OK | MB_ICONERROR); - } - } - - if (! encounteredError) - PreviewAmbFile(g_iniTempDirectory, &g_ambFile); - } else { - MessageBox(hwnd, "No AMB file loaded. Please open an AMB file first.", - "Error", MB_OK | MB_ICONINFORMATION); - } - return 0; - - case ID_STOP_BUTTON: - // Handle Stop button click - StopAmbPreview(); - return 0; - - // Check if the command is from the edit control created for subitem editing - default: - if (LOWORD(wParam) == 1000 && HIWORD(wParam) == EN_KILLFOCUS) { - // When the edit control loses focus, get its text and update the list view item - if (g_hwndEdit != NULL && g_editRow >= 0 && g_editCol >= 0) { - char buffer[256]; - GetWindowText(g_hwndEdit, buffer, sizeof(buffer)); - - // Apply the edit to the AMB file data structure - char formattedBuffer[256]; - if (ApplyEditToAmbFile(hwnd, g_editRow, g_editCol, buffer, formattedBuffer, sizeof formattedBuffer)) { - SetListViewItemText(g_hwndListView, g_editRow, g_editCol, formattedBuffer, TRUE); - } - - // Destroy the edit control - DestroyWindow(g_hwndEdit); - g_hwndEdit = NULL; - g_editRow = -1; - g_editCol = -1; - } - return 0; - } - } - break; - - case WM_NOTIFY: - // Handle control notifications - { - NMHDR *nmhdr = (NMHDR *)lParam; - - // Check if the notification is from our ListView - if (nmhdr->hwndFrom == g_hwndListView) { - switch (nmhdr->code) { - case LVN_BEGINLABELEDIT: - // Notification when a label edit begins - return HandleBeginLabelEdit(hwnd, (NMLVDISPINFOA *)lParam); - - case LVN_ENDLABELEDIT: - // Notification when a label edit ends - return HandleEndLabelEdit(hwnd, (NMLVDISPINFOA *)lParam); - - case NM_DBLCLK: - // Handle double-click on a ListView item to edit the cell - { - NMITEMACTIVATE *nia = (NMITEMACTIVATE *)lParam; - // Only process if a valid item was clicked - if (nia->iItem != -1) { - // Check if this is a boolean column - if (nia->iSubItem == COL_SPEED_RANDOM || nia->iSubItem == COL_VOLUME_RANDOM) { - // Toggle the boolean value directly - char currentText[32]; - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = nia->iItem; - lvi.iSubItem = nia->iSubItem; - lvi.pszText = currentText; - lvi.cchTextMax = sizeof(currentText); - SendMessage(g_hwndListView, LVM_GETITEMTEXT, nia->iItem, (LPARAM)&lvi); - - // Toggle: if current is "Yes", change to "No", otherwise change to "Yes" - const char *newText = (strcmp(currentText, "Yes") == 0) ? "No" : "Yes"; - - // Apply the toggle to the AMB file data structure - char formattedText[256]; - if (ApplyEditToAmbFile(hwnd, nia->iItem, nia->iSubItem, newText, formattedText, sizeof(formattedText))) { - SetListViewItemText(g_hwndListView, nia->iItem, nia->iSubItem, formattedText, TRUE); - } - } else { - // For non-boolean columns, start editing the subitem that was clicked - EditListViewSubItem(g_hwndListView, nia->iItem, nia->iSubItem); - } - - // Tell the system we handled this message - SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); - return TRUE; - } - } - break; - - case NM_CUSTOMDRAW: - // Handle custom drawing for ListView - { - LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam; - - switch (lplvcd->nmcd.dwDrawStage) { - case CDDS_PREPAINT: - // Tell Windows we want to be notified for each item - return CDRF_NOTIFYITEMDRAW; - - case CDDS_ITEMPREPAINT: - // Tell Windows we want to be notified for each subitem - return CDRF_NOTIFYSUBITEMDRAW; - - case CDDS_SUBITEM | CDDS_ITEMPREPAINT: - // Custom draw for individual cells - { - int item = (int)lplvcd->nmcd.dwItemSpec; - int subItem = lplvcd->iSubItem; - - // Check if this is the WAV file column - if (subItem == COL_WAV_FILE) { - // Get the WAV filename for this row - char wavFileName[256] = {0}; - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = item; - lvi.iSubItem = COL_WAV_FILE; - lvi.pszText = wavFileName; - lvi.cchTextMax = sizeof(wavFileName); - SendMessage(g_hwndListView, LVM_GETITEMTEXT, item, (LPARAM)&lvi); - - // Check if WAV file exists - if (!CheckWavFileExists(wavFileName)) { - // Set text color to red for missing files - lplvcd->clrText = RGB(255, 0, 0); - } else { - // Use default text color - lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); - } - - return CDRF_NEWFONT; - } else if (subItem == COL_SPEED_MIN || subItem == COL_SPEED_MAX || - subItem == COL_VOLUME_MIN || subItem == COL_VOLUME_MAX) { - // Check if min/max columns should be grayed out based on flags - if (item < g_rowCount) { - AmbRowInfo *rowInfo = &g_rowInfo[item]; - if (rowInfo->prgmIndex >= 0 && rowInfo->prgmIndex < g_ambFile.prgmChunkCount) { - PrgmChunk *prgm = &g_ambFile.prgmChunks[rowInfo->prgmIndex]; - - BOOL shouldGrayOut = FALSE; - if (subItem == COL_SPEED_MIN || subItem == COL_SPEED_MAX) { - // Gray out if speed random is disabled (flags & 1 == 0) - shouldGrayOut = !(prgm->flags & 0x01); - } else { - // Gray out if volume random is disabled (flags & 2 == 0) - shouldGrayOut = !(prgm->flags & 0x02); - } - - if (shouldGrayOut) { - lplvcd->clrText = GetSysColor(COLOR_GRAYTEXT); - } else { - lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); - } - - return CDRF_NEWFONT; - } - } - - // Fallback to default color - lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); - return CDRF_NEWFONT; - } else { - // For all other columns, use default text color - lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); - return CDRF_NEWFONT; - } - } - } - } - return CDRF_DODEFAULT; - } - } - } - break; - - case WM_ERASEBKGND: - { - // Handle window background erasure - HDC hdc = (HDC)wParam; - RECT rect; - GetClientRect(hwnd, &rect); - FillRect(hdc, &rect, g_hBackgroundBrush); - return 1; // Return non-zero to indicate we processed this message - } - - case WM_CTLCOLORDLG: - case WM_CTLCOLORSTATIC: - case WM_CTLCOLORBTN: - // Set background color for dialog, static controls, and buttons - return (LRESULT)g_hBackgroundBrush; - - case WM_CLOSE: - DestroyWindow(hwnd); - return 0; - - case WM_DESTROY: - // Clean up resources - if (g_hBackgroundBrush != NULL) { - DeleteObject(g_hBackgroundBrush); - g_hBackgroundBrush = NULL; - } - DeinitializePreviewPlayer(); - PostQuitMessage(0); - return 0; - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -// Create a simple menu -HMENU CreateAmbEditorMenu() -{ - HMENU hMenu, hFileMenu, hEditMenu, hHelpMenu; - - hMenu = CreateMenu(); - - // File menu - hFileMenu = CreatePopupMenu(); - AppendMenu(hFileMenu, MF_STRING, IDM_FILE_OPEN, "&Open AMB File...\tCtrl+O"); - AppendMenu(hFileMenu, MF_STRING, IDM_FILE_SAVE, "&Save\tCtrl+S"); - AppendMenu(hFileMenu, MF_STRING, IDM_FILE_SAVE_AS, "Save &As..."); - AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hFileMenu, MF_STRING, IDM_FILE_DETAILS, "&View AMB Details"); - AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hFileMenu, MF_STRING, IDM_FILE_EXIT, "E&xit"); - - // Edit menu - hEditMenu = CreatePopupMenu(); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_UNDO, "&Undo\tCtrl+Z"); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_REDO, "&Redo\tCtrl+Y"); - AppendMenu(hEditMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_ADD, "&Add Row\tIns"); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_DELETE, "&Delete Row\tDel"); - AppendMenu(hEditMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_MATCH_WAV, "&Match duration to WAV"); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_PRUNE, "&Prune"); - - // Help menu - hHelpMenu = CreatePopupMenu(); - AppendMenu(hHelpMenu, MF_STRING, IDM_HELP_ABOUT, "&About..."); - - // Add menus to the main menu - AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, "&File"); - AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hEditMenu, "&Edit"); - AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hHelpMenu, "&Help"); - - return hMenu; -} - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ - // Register the window class - const char CLASS_NAME[] = "AMB Editor Window Class"; - - // Create a pleasant beige brush for the background - RGB(245, 245, 220) is a nice beige color - g_hBackgroundBrush = CreateSolidBrush(RGB(245, 235, 200)); - - WNDCLASS wc = {0}; - wc.lpfnWndProc = WindowProc; - wc.hInstance = hInstance; - wc.lpszClassName = CLASS_NAME; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = g_hBackgroundBrush; - - RegisterClass(&wc); - - // Create menu - HMENU hMenu = CreateAmbEditorMenu(); - - // Create the window - HWND hwnd = CreateWindowEx( - 0, // Optional window styles - CLASS_NAME, // Window class - "AMB Editor", // Window title - WS_OVERLAPPEDWINDOW, // Window style - - // Size and position - CW_USEDEFAULT, CW_USEDEFAULT, 895, 620, - - NULL, // Parent window - hMenu, // Menu - hInstance, // Instance handle - NULL // Additional application data - ); - - if (hwnd == NULL) { - return 0; - } - - ShowWindow(hwnd, nCmdShow); - - // Create accelerator table - HACCEL hAccel = CreateAcceleratorTable(g_accelTable, sizeof(g_accelTable) / sizeof(g_accelTable[0])); - - // Run the message loop - MSG msg = {0}; - while (GetMessage(&msg, NULL, 0, 0)) { - if (!TranslateAccelerator(hwnd, hAccel, &msg)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - return (int)msg.wParam; -} +#include +#include +#include +#include +#include +#include + +// Defines the things we need from commctrl.h, commdlg.h, and any other headers that are not available +#include "win32_selections.h" + + + +#define PATH_BUFFER_SIZE 1024 +typedef char Path[PATH_BUFFER_SIZE]; + +Path g_iniCiv3InstallPath; +Path g_iniSoundDLLPath; +Path g_iniTempDirectory; + +void PathAppend(Path path, const char* append) +{ + size_t len = strlen(path); + + // No space at end of buffer + if (len >= PATH_BUFFER_SIZE - 1) + return; + + // Add backslash if needed + if (len > 0 && path[len - 1] != '\\') { + path[len] = '\\'; + path[len + 1] = '\0'; + len++; + } + + // Append the new part + strncpy(path + len, append, PATH_BUFFER_SIZE - len); + path[PATH_BUFFER_SIZE - 1] = '\0'; +} + +bool PathRemoveFileSpec(Path path) +{ + char* lastSlash = strrchr(path, '\\'); + if (lastSlash) { + *lastSlash = '\0'; + return true; + } + return false; +} + + + +#include "amb_file.c" +#include "preview.c" +#include "wav_file.c" + + + +// Forward declarations for ListView functions +void AddListViewColumn(HWND hListView, int index, char *title, int width); +int AddListViewItem(HWND hListView, int index, const char *text); +void SetListViewItemText(HWND hListView, int row, int col, const char *text, BOOL allowRepopulation); +void ClearListView(HWND hListView); +void PopulateAmbListView(void); +BOOL ApplyEditToAmbFile(HWND hwnd, int row, int col, const char *newText, char * outFormattedText, int formattedTextBufferSize); +BOOL IsValidInteger(const char *str); +BOOL GetWavFileDuration(const char* filePath, float* outDuration); +BOOL CheckWavFileExists(const char* wavFileName); +BOOL HasMissingWavFiles(char* missingFiles, int bufferSize); +void MatchDurationToWav(HWND hwndListView); +void LoadAmbFileWithDialog(HWND hwnd); +void SaveAmbFileDirectly(HWND hwnd); +void SaveAmbFileAs(HWND hwnd); +void UpdateOverallDuration(void); + +// Currently loaded AMB file +AmbFile g_ambFile = {0}; + +AmbFile g_fileSnapshots[100] = {0}; +int g_snapshotCount = 0, + g_redoCount = 0; + +void ClearFileSnapshots() +{ + memset(g_fileSnapshots, 0, sizeof g_fileSnapshots); + g_snapshotCount = g_redoCount = 0; +} + +// Saves a copy of the currently loaded file onto the stack of snapshots so any changes to the file can be reverted. If the stack is full, drops the +// oldest item. +void SnapshotCurrentFile() +{ + g_redoCount = 0; + + int snapshotCapacity = (sizeof g_fileSnapshots) / (sizeof g_fileSnapshots[0]); + if (g_snapshotCount == snapshotCapacity) { + memmove(&g_fileSnapshots[0], &g_fileSnapshots[1], (snapshotCapacity - 1) * (sizeof g_fileSnapshots[0])); + g_snapshotCount--; + } + + memcpy(&g_fileSnapshots[g_snapshotCount], &g_ambFile, sizeof(AmbFile)); + g_snapshotCount++; +} + +void Undo() +{ + static AmbFile tempAmb; + + if (g_snapshotCount > 0) { + // Swap most recent snapshot with the current file + memcpy(&tempAmb, &g_ambFile, sizeof(AmbFile)); + memcpy(&g_ambFile, &g_fileSnapshots[g_snapshotCount - 1], sizeof(AmbFile)); + memcpy(&g_fileSnapshots[g_snapshotCount - 1], &tempAmb, sizeof(AmbFile)); + + g_snapshotCount--; + g_redoCount++; + + PopulateAmbListView(); // Refresh the ListView to reflect changes + } else + MessageBeep(MB_ICONERROR); +} + +void Redo() +{ + static AmbFile tempAmb; + + if (g_redoCount > 0) { + // Swap oldest redo (stored one above the newest undo on the stack) with the current file + memcpy(&tempAmb, &g_fileSnapshots[g_snapshotCount], sizeof(AmbFile)); + memcpy(&g_fileSnapshots[g_snapshotCount], &g_ambFile, sizeof(AmbFile)); + memcpy(&g_ambFile, &tempAmb, sizeof(AmbFile)); + + g_snapshotCount++; + g_redoCount--; + + PopulateAmbListView(); // Refresh the ListView to reflect changes + } else + MessageBeep(MB_ICONERROR); +} + +// Function declarations +BOOL WINAPI GetOpenFileNameA(LPOPENFILENAMEA lpofn); +BOOL WINAPI GetSaveFileNameA(LPOPENFILENAMEA lpofn); + +// Menu IDs +#define IDM_FILE_OPEN 1001 +#define IDM_FILE_SAVE 1002 +#define IDM_FILE_SAVE_AS 1003 +#define IDM_FILE_DETAILS 1004 +#define IDM_FILE_EXIT 1005 +#define IDM_EDIT_UNDO 1006 +#define IDM_EDIT_REDO 1007 +#define IDM_EDIT_DELETE 1008 +#define IDM_EDIT_ADD 1009 +#define IDM_EDIT_MATCH_WAV 1010 +#define IDM_EDIT_PRUNE 1011 +#define IDM_HELP_ABOUT 1012 + +// Accelerator table for hotkeys +ACCEL g_accelTable[] = { + {FCONTROL | FVIRTKEY, 'O', IDM_FILE_OPEN}, // Ctrl+O + {FCONTROL | FVIRTKEY, 'S', IDM_FILE_SAVE}, // Ctrl+S + {FCONTROL | FVIRTKEY, 'Z', IDM_EDIT_UNDO}, // Ctrl+Z + {FCONTROL | FVIRTKEY, 'Y', IDM_EDIT_REDO}, // Ctrl+Y + {FVIRTKEY, VK_DELETE, IDM_EDIT_DELETE}, // Delete + {FVIRTKEY, VK_INSERT, IDM_EDIT_ADD} // Insert +}; + +// Control IDs +#define ID_PATH_EDIT 102 +#define ID_PLAY_BUTTON 103 +#define ID_STOP_BUTTON 104 +#define ID_AMB_LISTVIEW 105 + +// ListView Column Indices +typedef enum { + COL_TIME = 0, + COL_DURATION, + COL_WAV_FILE, + COL_SPEED_RANDOM, + COL_SPEED_MIN, + COL_SPEED_MAX, + COL_VOLUME_RANDOM, + COL_VOLUME_MIN, + COL_VOLUME_MAX +} ListViewColumn; + +// Track info structure to associate ListView rows with AMB data +typedef struct { + int trackIndex; // MIDI track index + int kmapIndex; // Index of Kmap chunk + int prgmIndex; // Index of Prgm chunk + int kmapItemIndex; // Index of item within Kmap +} AmbRowInfo; + +// Temporary structure for sorting rows by timestamp +typedef struct { + AmbRowInfo rowInfo; + float timestamp; + float duration; + char timeStr[32]; + char durationStr[32]; + char wavFileName[256]; + char speedMaxStr[32]; + char speedMinStr[32]; + char volumeMaxStr[32]; + char volumeMinStr[32]; + bool hasSpeedRandom; + bool hasVolumeRandom; +} RowData; + +// Comparison function for sorting rows by timestamp +int CompareRowsByTimestamp(const void *a, const void *b) +{ + const RowData *rowA = (const RowData *)a; + const RowData *rowB = (const RowData *)b; + + if (rowA->timestamp < rowB->timestamp) return -1; + if (rowA->timestamp > rowB->timestamp) return 1; + return 0; +} + +// Global variables +Path g_civ3MainPath = {0}; +HWND g_hwndPathEdit = NULL; +HWND g_hwndMainWindow = NULL; +HWND g_hwndPlayButton = NULL; +HWND g_hwndStopButton = NULL; +HWND g_hwndListView = NULL; +HWND g_hwndDurationLabel = NULL; +HBRUSH g_hBackgroundBrush = NULL; // Brush for window background color + +// Track info for each row in the ListView +AmbRowInfo g_rowInfo[MAX_SOUND_TRACKS]; +int g_rowCount = 0; // Number of rows in the ListView + +// Custom path helpers +bool PathFileExists(const Path path) +{ + DWORD attr = GetFileAttributes(path); + return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY)); +} + +bool PathIsDirectory(const Path path) +{ + DWORD attr = GetFileAttributes(path); + return (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)); +} + +// Function to browse for an AMB file to open +bool BrowseForAmbFile(HWND hwnd, Path filePath) +{ + // Initialize the OPENFILENAME structure + OPENFILENAMEA ofn; + ZeroMemory(&ofn, sizeof(ofn)); + + // Set up buffer + ZeroMemory(filePath, PATH_BUFFER_SIZE); + + // Setup the open file dialog + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = filePath; + ofn.nMaxFile = PATH_BUFFER_SIZE; + ofn.lpstrFilter = "AMB Files\0*.amb\0All Files\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrTitle = "Select an AMB file to open"; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER; + + // Set initial directory to Civ3 install path if found + if (strlen(g_civ3MainPath) > 0) { + ofn.lpstrInitialDir = g_civ3MainPath; + } + + // Show the dialog and get result + return GetOpenFileNameA(&ofn); +} + +// Load an AMB file selected by the user +void LoadAmbFileWithDialog(HWND hwnd) +{ + Path ambFilePath = {0}; + + if (BrowseForAmbFile(hwnd, ambFilePath)) { + if (LoadAmbFile(ambFilePath, &g_ambFile) && g_hwndMainWindow != NULL) { + ClearFileSnapshots(); + + // Extract the filename part from the path + char *fileName = strrchr(ambFilePath, '\\'); + if (fileName) { + fileName++; // Skip past the backslash + } else { + fileName = (char*)ambFilePath; // No backslash found, use the whole path + } + + char windowTitle[100]; + snprintf(windowTitle, sizeof windowTitle, "%s - AMB Editor", fileName); + windowTitle[(sizeof windowTitle) - 1] = '\0'; + SetWindowText(g_hwndMainWindow, windowTitle); + + // Populate the ListView with the loaded AMB file data + PopulateAmbListView(); + } + } +} + +// Browse for a file to save +BOOL BrowseForSaveFile(HWND hwnd, Path filePath) +{ + OPENFILENAMEA ofn; + ZeroMemory(&ofn, sizeof(ofn)); + + // Initialize the filePath with current file if any + if (g_ambFile.filePath[0] != '\0') { + strcpy(filePath, g_ambFile.filePath); + } + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = "AMB Files (*.amb)\0*.amb\0All Files (*.*)\0*.*\0"; + ofn.lpstrFile = filePath; + ofn.nMaxFile = PATH_BUFFER_SIZE; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_EXPLORER; + ofn.lpstrDefExt = "amb"; + ofn.lpstrTitle = "Save AMB File"; + + return GetSaveFileNameA(&ofn); +} + +// Save AMB file directly (without dialog) +void SaveAmbFileDirectly(HWND hwnd) +{ + if (g_ambFile.filePath[0] == '\0') { + MessageBox(hwnd, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Try to save to the current file path + if (SaveAmbFile(&g_ambFile, g_ambFile.filePath)) { + // Success - file saved silently + return; + } + + // Failed to save (likely permissions issue) - fall back to Save As silently + SaveAmbFileAs(hwnd); +} + +// Save AMB file with Save As dialog +void SaveAmbFileAs(HWND hwnd) +{ + if (g_ambFile.filePath[0] == '\0') { + MessageBox(hwnd, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); + return; + } + + Path filePath = {0}; + + if (BrowseForSaveFile(hwnd, filePath)) { + // Try to save the AMB file + if (SaveAmbFile(&g_ambFile, filePath)) { + // Update the current file path to the new location + strcpy(g_ambFile.filePath, filePath); + + // Extract the filename part from the path and update window title + char *fileName = strrchr(filePath, '\\'); + if (fileName) { + fileName++; // Skip past the backslash + } else { + fileName = (char*)filePath; // No backslash found, use the whole path + } + + char windowTitle[100]; + snprintf(windowTitle, sizeof windowTitle, "%s - AMB Editor", fileName); + windowTitle[(sizeof windowTitle) - 1] = '\0'; + SetWindowText(g_hwndMainWindow, windowTitle); + } else { + MessageBox(hwnd, "Failed to save AMB file. Check file permissions and try again.", "Error", MB_OK | MB_ICONERROR); + } + } +} + +// Function to check if a directory is the main Civ3 folder +bool IsCiv3MainFolder(const Path folderPath) +{ + Path testPath; + + // Check for Art folder + strcpy(testPath, folderPath); + PathAppend(testPath, "Art"); + if (!PathIsDirectory(testPath)) { + return false; + } + + // Check for civ3PTW folder + strcpy(testPath, folderPath); + PathAppend(testPath, "civ3PTW"); + if (!PathIsDirectory(testPath)) { + return false; + } + + return true; +} + +// Function to search parent folders for Civ3 install +bool FindCiv3InstallBySearch(const Path startPath) +{ + Path testPath; + + // Start with working directory + strcpy(testPath, startPath); + + // Go up up to 10 parent directories + for (int i = 0; i < 10; i++) { + // Check current directory and subdirectories for main Civ3 folder + WIN32_FIND_DATA findData; + HANDLE hFind; + Path searchPath; + + strcpy(searchPath, testPath); + PathAppend(searchPath, "*"); + + hFind = FindFirstFile(searchPath, &findData); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + strcmp(findData.cFileName, ".") != 0 && + strcmp(findData.cFileName, "..") != 0) { + + Path subDirPath; + strcpy(subDirPath, testPath); + PathAppend(subDirPath, findData.cFileName); + + if (IsCiv3MainFolder(subDirPath)) { + // Found main Civ3 directory + strcpy(g_civ3MainPath, subDirPath); + FindClose(hFind); + return true; + } + } + } while (FindNextFile(hFind, &findData)); + FindClose(hFind); + } + + // Move up a directory + if (!PathRemoveFileSpec(testPath)) { + break; // Cannot go up further + } + } + + return false; +} + +// Function to find Civ3 install from registry +bool FindCiv3InstallFromRegistry() +{ + HKEY hKey; + char regValue[PATH_BUFFER_SIZE]; + DWORD valueSize = sizeof(regValue); + DWORD valueType; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Infogrames Interactive\\Civilization III", + 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + + if (RegQueryValueEx(hKey, "Install_Path", NULL, &valueType, + (LPBYTE)regValue, &valueSize) == ERROR_SUCCESS) { + + if (valueType == REG_SZ) { + regValue[(sizeof regValue) - 1] = '\0'; // RegQueryValueEx is not guaranteed to return null terminated strings + strcpy(g_civ3MainPath, regValue); + + RegCloseKey(hKey); + return true; + } + } + RegCloseKey(hKey); + } + + return false; +} + +bool GetSoundDLLPath(HWND hwnd, Path outSoundDLLPath) +{ + // First, check if INI has a sound.dll path specified + if (strlen(g_iniSoundDLLPath) > 0) { + strcpy(outSoundDLLPath, g_iniSoundDLLPath); + return true; + } + + // Otherwise, check if Conquests\sound.dll exists in the main Civ3 install + if (strlen(g_civ3MainPath) > 0) { + Path conquestsSoundPath; + strcpy(conquestsSoundPath, g_civ3MainPath); + PathAppend(conquestsSoundPath, "Conquests"); + PathAppend(conquestsSoundPath, "sound.dll"); + + if (PathFileExists(conquestsSoundPath)) { + strcpy(outSoundDLLPath, conquestsSoundPath); + return true; + } + } + + // If neither works, ask the user to locate sound.dll + int result = MessageBox(hwnd, + "Playing a preview requires sound.dll from your Civ 3 Conquests install. This could not be found automatically. " + "Would you like to locate sound.dll manually?", + "DLL not found", MB_YESNO | MB_ICONQUESTION); + if (result == IDYES) { + Path path = {0}; + + OPENFILENAMEA ofn; + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = path; + ofn.nMaxFile = PATH_BUFFER_SIZE; + ofn.lpstrFilter = "DLL Files\0*.dll\0All Files\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrTitle = "Select sound.dll from your Civ 3 Conquests install"; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileNameA(&ofn)) { + if (PathFileExists(path)) { + strcpy(outSoundDLLPath, path); + return true; + } + } + } + + return false; +} + +// Find Civ3 installation using all available methods +bool FindCiv3Installation(HWND hwnd) +{ + Path cwdPath; + GetCurrentDirectory(PATH_BUFFER_SIZE, cwdPath); + + // Search parent folders first. If that doesn't work, check the registry. + if (FindCiv3InstallBySearch(cwdPath)) { + return true; + } else + return FindCiv3InstallFromRegistry(); +} + +// Create the play and stop buttons +void CreatePlaybackButtons(HWND hwnd) +{ + // Create Play button + g_hwndPlayButton = CreateWindow( + "BUTTON", + "Play Preview", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, + 20, 20, 100, 30, + hwnd, (HMENU)ID_PLAY_BUTTON, GetModuleHandle(NULL), NULL + ); + + // Create Stop button + g_hwndStopButton = CreateWindow( + "BUTTON", + "Stop", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, + 130, 20, 80, 30, + hwnd, (HMENU)ID_STOP_BUTTON, GetModuleHandle(NULL), NULL + ); +} + +// Add a column to the ListView +void AddListViewColumn(HWND hListView, int index, char *title, int width) +{ + LVCOLUMNA lvc = {0}; + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + lvc.pszText = title; + lvc.cx = width; + + SendMessage(hListView, LVM_INSERTCOLUMN, index, (LPARAM)&lvc); +} + +// Add a row to the ListView +int AddListViewItem(HWND hListView, int index, const char *text) +{ + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = index; + lvi.iSubItem = 0; + lvi.pszText = (LPSTR)text; + + return SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&lvi); +} + +// Set text in a ListView cell +void SetListViewItemText(HWND hListView, int row, int col, const char *text, BOOL allowRepopulation) +{ + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = row; + lvi.iSubItem = col; + lvi.pszText = (LPSTR)text; + + SendMessage(hListView, LVM_SETITEM, 0, (LPARAM)&lvi); + + // Check if we need to repopulate when time changes + if (allowRepopulation && col == COL_TIME) { + PopulateAmbListView(); + } +} + +// Clear all items from the ListView +void ClearListView(HWND hListView) +{ + SendMessage(hListView, LVM_DELETEALLITEMS, 0, 0); +} + +// Check if a WAV file exists in the AMB file's directory +BOOL CheckWavFileExists(const char* wavFileName) +{ + if (!wavFileName || strlen(wavFileName) == 0 || g_ambFile.filePath[0] == '\0') { + return FALSE; + } + + // Construct full path to WAV file + Path wavFilePath; + strcpy(wavFilePath, g_ambFile.filePath); + PathRemoveFileSpec(wavFilePath); // Remove filename, keep directory + PathAppend(wavFilePath, wavFileName); + + // Check if file exists + return PathFileExists(wavFilePath); +} + +// Check if any WAV files are missing and return a list of missing files +BOOL HasMissingWavFiles(char* missingFiles, int bufferSize) +{ + if (!missingFiles || bufferSize == 0 || g_ambFile.filePath[0] == '\0') { + return FALSE; + } + + missingFiles[0] = '\0'; // Initialize as empty string + BOOL hasMissing = FALSE; + + // Check each row in the ListView for missing WAV files + for (int i = 0; i < g_rowCount; i++) { + AmbRowInfo *rowInfo = &g_rowInfo[i]; + if (rowInfo->kmapIndex >= 0 && rowInfo->kmapIndex < g_ambFile.kmapChunkCount && + rowInfo->kmapItemIndex >= 0 && rowInfo->kmapItemIndex < g_ambFile.kmapChunks[rowInfo->kmapIndex].itemCount) { + + KmapChunk *kmap = &g_ambFile.kmapChunks[rowInfo->kmapIndex]; + const char *wavFileName = kmap->items[rowInfo->kmapItemIndex].wavFileName; + + // Ignore empty WAV file names since those don't interfere with playback + if ((wavFileName[0] != '\0') && !CheckWavFileExists(wavFileName)) { + hasMissing = TRUE; + + // Add to missing files list if there's space + if (strlen(missingFiles) > 0) { + strncat(missingFiles, "\n", bufferSize - strlen(missingFiles) - 1); + } + strncat(missingFiles, wavFileName, bufferSize - strlen(missingFiles) - 1); + } + } + } + + return hasMissing; +} + +// Function to check if a string is a valid integer +BOOL IsValidInteger(const char *str) +{ + // Allow for a leading + or - sign + if (*str == '+' || *str == '-') { + str++; + } + + // Empty string or just a sign isn't a valid integer + if (*str == '\0') { + return FALSE; + } + + // Check that all characters are digits + while (*str) { + if (!isdigit(*str)) { + return FALSE; + } + str++; + } + + return TRUE; +} + + + + +// Defines void ShowAmbDetailsWindow(HWND hwndParent) +#include "details_window.c" + + + +// Returns the index of the Prgm chunk referred to by the given sound track. If the track does not validly refer to any Prgm, returns -1. In order for +// the track to be valid, the channel numbers of all events must match and specify a valid Prgm index and the program change event must specify the +// corresponding program number. +int GetReferencedPrgmIfValid(int trackIndex) +{ + SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; + + int prgmIndex = track->programChange.programNumber - 1; + + if ((prgmIndex < 0) || (prgmIndex >= g_ambFile.prgmChunkCount)) + return -1; + + for (int i = 0; i < track->controlChangeCount; i++) + if (track->controlChanges[i].channelNumber != prgmIndex) + return -1; + + if ((track->programChange.channelNumber != prgmIndex) || + (track->noteOn .channelNumber != prgmIndex) || + (track->noteOff .channelNumber != prgmIndex)) + return -1; + + return prgmIndex; +} + +// Populate the ListView with AMB file data +void PopulateAmbListView(void) +{ + if (g_hwndListView == NULL) { + MessageBox(NULL, "ListView control is NULL", "Debug", MB_OK); + return; + } + + // Clear any existing data + ClearListView(g_hwndListView); + + // Reset row info + g_rowCount = 0; + memset(g_rowInfo, 0, sizeof(g_rowInfo)); + + // Check if we have valid AMB data + if (g_ambFile.kmapChunkCount == 0 || g_ambFile.prgmChunkCount == 0 || g_ambFile.midi.trackCount == 0) { + MessageBox(NULL, "AMB file has missing data or is invalid", "Debug", MB_OK); + return; + } + + // Calculate seconds per tick for timing + float secondsPerTick = 0.0f; + if (g_ambFile.midi.ticksPerQuarterNote > 0) { + secondsPerTick = g_ambFile.midi.secondsPerQuarterNote / g_ambFile.midi.ticksPerQuarterNote; + } + + // Collect all row data before sorting + RowData rowData[MAX_SOUND_TRACKS]; + int rowDataCount = 0; + + // Process each MIDI sound track + int soundTrackCount = g_ambFile.midi.trackCount - 1; // Minus one to exclude the info track + for (int trackIndex = 0; trackIndex < soundTrackCount; trackIndex++) { + SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; + + int prgmIndex = GetReferencedPrgmIfValid(trackIndex); + if (prgmIndex < 0) + continue; // No valid Prgm, skip this track + PrgmChunk *matchingPrgm = &g_ambFile.prgmChunks[prgmIndex]; + + // Get the var name from the matching Prgm chunk + const char *varName = matchingPrgm->varName; + + // Find corresponding Kmap chunk with the same var name + KmapChunk *matchingKmap = NULL; + int kmapIndex = -1; + for (int i = 0; i < g_ambFile.kmapChunkCount; i++) { + if (strcmp(g_ambFile.kmapChunks[i].varName, varName) == 0) { + matchingKmap = &g_ambFile.kmapChunks[i]; + kmapIndex = i; + break; + } + } + + if (matchingKmap == NULL || matchingKmap->itemCount == 0) { + continue; // Skip if no matching Kmap found or no items in Kmap + } + + float timestamp = track->deltaTimeNoteOn * secondsPerTick; + float duration = track->deltaTimeNoteOff * secondsPerTick; + + // Check flags for randomization settings (LSB = speed random, bit 1 = volume random) + bool hasSpeedRandom = (matchingPrgm->flags & 0x01) != 0; + bool hasVolumeRandom = (matchingPrgm->flags & 0x02) != 0; + + // For each item in the kmap (usually just one WAV file per track) + for (int j = 0; j < matchingKmap->itemCount; j++) { + if (rowDataCount >= MAX_SOUND_TRACKS) { + break; // Prevent overflow + } + + // Collect row data + RowData *row = &rowData[rowDataCount]; + row->rowInfo.trackIndex = trackIndex; + row->rowInfo.kmapIndex = kmapIndex; + row->rowInfo.prgmIndex = prgmIndex; + row->rowInfo.kmapItemIndex = j; + row->timestamp = timestamp; + row->duration = duration; + row->hasSpeedRandom = hasSpeedRandom; + row->hasVolumeRandom = hasVolumeRandom; + + // Format strings + snprintf(row->timeStr, sizeof(row->timeStr), "%04.3f", timestamp); + snprintf(row->durationStr, sizeof(row->durationStr), "%04.3f", duration); + strncpy(row->wavFileName, matchingKmap->items[j].wavFileName, sizeof(row->wavFileName) - 1); + row->wavFileName[sizeof(row->wavFileName) - 1] = '\0'; + snprintf(row->speedMaxStr, sizeof(row->speedMaxStr), "%d", matchingPrgm->maxRandomSpeed); + snprintf(row->speedMinStr, sizeof(row->speedMinStr), "%d", matchingPrgm->minRandomSpeed); + snprintf(row->volumeMaxStr, sizeof(row->volumeMaxStr), "%d", matchingPrgm->maxRandomVolume); + snprintf(row->volumeMinStr, sizeof(row->volumeMinStr), "%d", matchingPrgm->minRandomVolume); + + rowDataCount++; + } + } + + // Sort rows by timestamp + qsort(rowData, rowDataCount, sizeof(RowData), CompareRowsByTimestamp); + + // Add sorted rows to ListView + for (int i = 0; i < rowDataCount; i++) { + RowData *row = &rowData[i]; + + // Add the item to the ListView + int listRow = AddListViewItem(g_hwndListView, 0x7FFFFFFF, row->timeStr); + if (listRow >= 0) { + // Store the track info for this row + g_rowInfo[g_rowCount] = row->rowInfo; + g_rowCount++; + + // Set all the column values + SetListViewItemText(g_hwndListView, listRow, COL_DURATION, row->durationStr, FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_WAV_FILE, row->wavFileName, FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_SPEED_RANDOM, row->hasSpeedRandom ? "Yes" : "No", FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_SPEED_MIN, row->speedMinStr, FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_SPEED_MAX, row->speedMaxStr, FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_RANDOM, row->hasVolumeRandom ? "Yes" : "No", FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_MIN, row->volumeMinStr, FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_MAX, row->volumeMaxStr, FALSE); + } + } + + // Update the overall duration display + UpdateOverallDuration(); +} + +// Handle the beginning of a ListView label edit +BOOL HandleBeginLabelEdit(HWND hwnd, NMLVDISPINFOA *pInfo) +{ + // You can reject edits for specific columns or rows if needed + // For now, allow editing all cells + return TRUE; // Return TRUE to allow the edit, FALSE to prevent it +} + +// Apply an edit to the AMB file data structure. Returns TRUE if the edit was accepted or FALSE if it was invalid. If the edit was accepted, the new +// text is written to outFormattedText in a way that is consistent with the usual format of the ListView display (e.g. float fields are formatted +// to 3 decimal places). If the new text exactly matches the current cell text, the edit is accepted but no snapshot is taken and no AMB data is modified. +// outFormattedText must not be NULL and formattedTextBufferSize must be at least 1. +BOOL ApplyEditToAmbFile(HWND hwnd, int row, int col, const char *newText, char * outFormattedText, int formattedTextBufferSize) +{ + // Make sure we have valid row info + if (row >= g_rowCount) { + MessageBox(hwnd, "Invalid row index", "Error", MB_OK | MB_ICONERROR); + return FALSE; + } + + // Get the track information for this row + AmbRowInfo *rowInfo = &g_rowInfo[row]; + int trackIndex = rowInfo->trackIndex; + int kmapIndex = rowInfo->kmapIndex; + int prgmIndex = rowInfo->prgmIndex; + int kmapItemIndex = rowInfo->kmapItemIndex; + + // Check if indices are valid + if (trackIndex < 0 || trackIndex >= g_ambFile.midi.trackCount || + kmapIndex < 0 || kmapIndex >= g_ambFile.kmapChunkCount || + prgmIndex < 0 || prgmIndex >= g_ambFile.prgmChunkCount || + kmapItemIndex < 0 || kmapItemIndex >= g_ambFile.kmapChunks[kmapIndex].itemCount) { + + MessageBox(hwnd, "Invalid track indices", "Error", MB_OK | MB_ICONERROR); + return FALSE; + } + + // Check if new text matches the current value in the cell - if so, accept without changing anything + char currentText[256] = {0}; + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = row; + lvi.iSubItem = col; + lvi.pszText = currentText; + lvi.cchTextMax = sizeof(currentText); + SendMessage(g_hwndListView, LVM_GETITEMTEXT, row, (LPARAM)&lvi); + + if (strcmp(newText, currentText) == 0) { + // Text unchanged - accept edit but don't modify data or take snapshot + strncpy(outFormattedText, newText, formattedTextBufferSize); + outFormattedText[formattedTextBufferSize - 1] = '\0'; + return TRUE; + } + + // Get references to the actual AMB data structures + PrgmChunk *prgm = &g_ambFile.prgmChunks[prgmIndex]; + KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; + + // Update the appropriate field based on the column that was edited + BOOL newTextIsValid = TRUE; + switch (col) { + case COL_TIME: + { + char * afterParsing; + float newTime = strtod(newText, &afterParsing); + if (afterParsing != newText) { + SnapshotCurrentFile(); + + float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; + g_ambFile.midi.soundTracks[trackIndex].deltaTimeNoteOn = round(newTime * ticksPerSecond); + + snprintf(outFormattedText, formattedTextBufferSize, "%04.3f", newTime); + + // Update overall duration since timestamp changed + UpdateOverallDuration(); + + } else { + newTextIsValid = FALSE; + } + } + break; + + case COL_DURATION: + { + char * afterParsing; + float newDuration = strtod(newText, &afterParsing); + if (afterParsing != newText) { + SnapshotCurrentFile(); + + float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; + g_ambFile.midi.soundTracks[trackIndex].deltaTimeNoteOff = round(newDuration * ticksPerSecond); + + snprintf(outFormattedText, formattedTextBufferSize, "%04.3f", newDuration); + + // Update overall duration since duration changed + UpdateOverallDuration(); + + } else { + newTextIsValid = FALSE; + } + } + break; + + case COL_WAV_FILE: // WAV filename + // Reject the edit if the new text contains a slash + if ((strchr(newText, '\\') == NULL) && (strchr(newText, '/') == NULL)) { + SnapshotCurrentFile(); + + // Write new text to kmap item + strncpy(kmap->items[kmapItemIndex].wavFileName, newText, sizeof(kmap->items[kmapItemIndex].wavFileName) - 1); + kmap->items[kmapItemIndex].wavFileName[sizeof(kmap->items[kmapItemIndex].wavFileName) - 1] = '\0'; + + // Update Kmap size + kmap->size = ComputeKmapChunkSize(kmap); + + // Write new text to formatted output + strncpy(outFormattedText, newText, formattedTextBufferSize); + } else { + newTextIsValid = FALSE; + } + break; + + case COL_SPEED_RANDOM: // Speed Random flag + { + if (strcmp(newText, "Yes") == 0 || strcmp(newText, "No") == 0) { + SnapshotCurrentFile(); + + if (strcmp(newText, "Yes") == 0) { + prgm->flags |= 0x01; // Set bit 0 + } else { + prgm->flags &= ~0x01; // Clear bit 0 + } + + strncpy(outFormattedText, (prgm->flags & 0x01) ? "Yes" : "No", formattedTextBufferSize); + } else { + newTextIsValid = FALSE; + } + } + break; + + case COL_SPEED_MIN: // Speed Min + if (IsValidInteger(newText)) { + SnapshotCurrentFile(); + prgm->minRandomSpeed = atoi(newText); + snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->minRandomSpeed); + } else { + newTextIsValid = FALSE; + } + break; + + case COL_SPEED_MAX: // Speed Max + if (IsValidInteger(newText)) { + SnapshotCurrentFile(); + prgm->maxRandomSpeed = atoi(newText); + snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->maxRandomSpeed); + } else { + newTextIsValid = FALSE; + } + break; + + case COL_VOLUME_RANDOM: // Volume Random flag + { + if (strcmp(newText, "Yes") == 0 || strcmp(newText, "No") == 0) { + SnapshotCurrentFile(); + + if (strcmp(newText, "Yes") == 0) { + prgm->flags |= 0x02; // Set bit 1 + } else { + prgm->flags &= ~0x02; // Clear bit 1 + } + + strncpy(outFormattedText, (prgm->flags & 0x02) ? "Yes" : "No", formattedTextBufferSize); + } else { + newTextIsValid = FALSE; + } + } + break; + + case COL_VOLUME_MIN: // Volume Min + if (IsValidInteger(newText)) { + SnapshotCurrentFile(); + prgm->minRandomVolume = atoi(newText); + snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->minRandomVolume); + } else { + newTextIsValid = FALSE; + } + break; + + case COL_VOLUME_MAX: // Volume Max + if (IsValidInteger(newText)) { + SnapshotCurrentFile(); + prgm->maxRandomVolume = atoi(newText); + snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->maxRandomVolume); + } else { + newTextIsValid = FALSE; + } + break; + } + + // Play error beep if new text didn't validate. If it did that means we wrote something to outFormattedText so make sure it's null terminated. + if (! newTextIsValid) + MessageBeep(MB_ICONERROR); + else + outFormattedText[formattedTextBufferSize - 1] = '\0'; + + return newTextIsValid; +} + +void DeleteKmapChunk(int kmapIndex) +{ + // Shift all Kmap chunks after this one forward + for (int i = kmapIndex; i < g_ambFile.kmapChunkCount - 1; i++) { + memcpy(&g_ambFile.kmapChunks[i], &g_ambFile.kmapChunks[i + 1], sizeof(KmapChunk)); + } + g_ambFile.kmapChunkCount--; +} + +void DeletePrgmChunk(int prgmIndex) +{ + // Shift all Prgm chunks after this one forward + for (int i = prgmIndex; i < g_ambFile.prgmChunkCount - 1; i++) { + memcpy(&g_ambFile.prgmChunks[i], &g_ambFile.prgmChunks[i + 1], sizeof(PrgmChunk)); + } + g_ambFile.prgmChunkCount--; + + // Update the number field of any remaining Prgm chunks - they are 1-based + for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { + g_ambFile.prgmChunks[i].number = i + 1; + } + + // Update channelNumber in all MIDI sound tracks for any that reference + // Prgm chunks with indices greater than the one we deleted + for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track + SoundTrack *track = &g_ambFile.midi.soundTracks[i]; + + // Check all control change events + for (int j = 0; j < track->controlChangeCount; j++) { + if (track->controlChanges[j].channelNumber > prgmIndex) { + track->controlChanges[j].channelNumber--; + } + } + + // Check program change event + if (track->programChange.channelNumber > prgmIndex) { + track->programChange.channelNumber--; + } + + // Update programNumber if it references deleted program or those after it + // Note: programNumbers are 1-based (matching the Prgm number field) + if (track->programChange.programNumber == prgmIndex + 1) { + // This is referencing the deleted program - we'd need to update it + // to a valid program or potentially disable this track + // For now, if there are other programs, use the first available one + if (g_ambFile.prgmChunkCount > 0) { + track->programChange.programNumber = 1; // Use first available program (1-based) + } + } + else if (track->programChange.programNumber > prgmIndex + 1) { + // This references a program that got shifted down, so update the index + track->programChange.programNumber--; + } + + // Check note on event + if (track->noteOn.channelNumber > prgmIndex) { + track->noteOn.channelNumber--; + } + + // Check note off event + if (track->noteOff.channelNumber > prgmIndex) { + track->noteOff.channelNumber--; + } + } +} + +void DeleteSoundTrack(int trackIndex) +{ + for (int i = trackIndex; i < g_ambFile.midi.trackCount - 2; i++) { // -2 because we skip info track (0) and want to leave room for the last valid track + memcpy(&g_ambFile.midi.soundTracks[i], &g_ambFile.midi.soundTracks[i + 1], sizeof(SoundTrack)); + } + g_ambFile.midi.trackCount--; +} + +void DeleteRow(int row) +{ + // If no file loaded or row is invalid, do nothing + if (g_ambFile.filePath[0] == '\0' || row < 0 || row >= g_rowCount) { + MessageBox(NULL, "Invalid row or no AMB file loaded", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Get the references to the chunks and tracks we need to work with + AmbRowInfo *rowInfo = &g_rowInfo[row]; + int trackIndex = rowInfo->trackIndex; + int kmapIndex = rowInfo->kmapIndex; + int prgmIndex = rowInfo->prgmIndex; + + // Take a snapshot before making changes + SnapshotCurrentFile(); + + // First, check if the Kmap chunk is referenced by other Prgm chunks + KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; + const char *kmapVarName = kmap->varName; + int kmapReferenceCount = 0; + + for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { + if (strcmp(g_ambFile.prgmChunks[i].varName, kmapVarName) == 0) { + kmapReferenceCount++; + } + } + + // Delete the Kmap chunk if it's only referenced by the Prgm we're deleting + if (kmapReferenceCount <= 1) { + DeleteKmapChunk(kmapIndex); + } + + // Next, check if the Prgm chunk is referenced by other MIDI tracks + int prgmReferenceCount = 0; + for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track + if (GetReferencedPrgmIfValid(i) == prgmIndex) + prgmReferenceCount++; + } + + // Delete the Prgm chunk if it's only referenced by the track we're deleting + if (prgmReferenceCount <= 1) { + DeletePrgmChunk(prgmIndex); + } + + // Delete the MIDI track + DeleteSoundTrack(trackIndex); + + // Refresh the ListView to show updated AMB data + PopulateAmbListView(); +} + +void AddRow() +{ + // If no file is loaded or we're already at the limit of how many sound tracks, prgm chunks, or kmap chunks we can have one file, report an + // error then return. + if (g_ambFile.filePath[0] == '\0') { + MessageBox(NULL, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); + return; + } + + if (g_ambFile.kmapChunkCount >= MAX_CHUNKS) { + MessageBox(NULL, "Cannot add more rows: Maximum number of Kmap chunks reached.", "Error", MB_OK | MB_ICONERROR); + return; + } + + if (g_ambFile.prgmChunkCount >= MAX_CHUNKS) { + MessageBox(NULL, "Cannot add more rows: Maximum number of Prgm chunks reached.", "Error", MB_OK | MB_ICONERROR); + return; + } + + if (g_ambFile.midi.trackCount >= MAX_SOUND_TRACKS + 1) { // +1 because first track is info track + MessageBox(NULL, "Cannot add more rows: Maximum number of sound tracks reached.", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Snapshot file + SnapshotCurrentFile(); + + // Find a unique name + char uniqueName[32]; + int nameCounter = 1; + bool nameIsUnique; + + do { + snprintf(uniqueName, sizeof(uniqueName), "NewTrack%d", nameCounter++); + nameIsUnique = true; + + // Check if this name is already used as a track name + for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track + if (strcmp(g_ambFile.midi.soundTracks[i].trackName.name, uniqueName) == 0) { + nameIsUnique = false; + break; + } + } + + // Check if this name is already used as a var name or effect name + if (nameIsUnique) { + for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { + if (strcmp(g_ambFile.prgmChunks[i].varName, uniqueName) == 0 || + strcmp(g_ambFile.prgmChunks[i].effectName, uniqueName) == 0) { + nameIsUnique = false; + break; + } + } + } + + // Check if this name is already used as a kmap var name + if (nameIsUnique) { + for (int i = 0; i < g_ambFile.kmapChunkCount; i++) { + if (strcmp(g_ambFile.kmapChunks[i].varName, uniqueName) == 0) { + nameIsUnique = false; + break; + } + } + } + } while (!nameIsUnique && nameCounter < 1000); // Prevent infinite loop + + if (!nameIsUnique) { + MessageBox(NULL, "Failed to generate a unique name for new row.", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Create a Kmap chunk + int kmapIndex = g_ambFile.kmapChunkCount; + KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; + + // Initialize the Kmap chunk + memset(kmap, 0, sizeof(KmapChunk)); + + kmap->flags = 2; // Standard flags value in Civ3 AMBs + kmap->itemCount = 1; + kmap->itemSize = 12; + + // Set the varName to our unique name + strcpy(kmap->varName, uniqueName); + + // Initialize the Kmap item + static const unsigned char kmapItemData[12] = { 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }; + memcpy(kmap->items[0].data, kmapItemData, 12); + strcpy(kmap->items[0].wavFileName, "<.wav file name>"); + + // Calculate the size of the Kmap chunk + kmap->size = ComputeKmapChunkSize(kmap); + + // Increment the Kmap count + g_ambFile.kmapChunkCount++; + + // Create a Prgm chunk + int prgmIndex = g_ambFile.prgmChunkCount; + PrgmChunk *prgm = &g_ambFile.prgmChunks[prgmIndex]; + + // Initialize the Prgm chunk + memset(prgm, 0, sizeof(PrgmChunk)); + + // Fill in names and set number (1-based) + strcpy(prgm->effectName, uniqueName); + strcpy(prgm->varName, uniqueName); + prgm->number = prgmIndex + 1; + + // Calculate the size of the Prgm chunk + prgm->size = ComputePrgmChunkSize(prgm); + + // Increment the Prgm count + g_ambFile.prgmChunkCount++; + + // Create a sound track + int trackIndex = g_ambFile.midi.trackCount - 1; // Index for the new track (after info track) + SoundTrack *track = &g_ambFile.midi.soundTracks[trackIndex]; + + // Initialize the sound track + memset(track, 0, sizeof(SoundTrack)); + + // Set track name + track->deltaTimeTrackName = 0; + strcpy(track->trackName.name, uniqueName); + + // Add one control change event + track->controlChangeCount = 1; + track->deltaTimeControlChanges[0] = 0; + track->controlChanges[0].channelNumber = prgmIndex; // 0-based index + track->controlChanges[0].controllerNumber = 32; + track->controlChanges[0].value = 0; + + // Set program change event + track->deltaTimeProgramChange = 0; + track->programChange.channelNumber = prgmIndex; // 0-based index + track->programChange.programNumber = prgmIndex + 1; // 1-based number + + // Find a unique key for the note on/off events + int keyValue = 60; // Start at middle C + bool keyIsUnique; + + do { + keyIsUnique = true; + + // Check if this key is already used in any other track + for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track + if (i != trackIndex && g_ambFile.midi.soundTracks[i].noteOn.key == keyValue) { + keyIsUnique = false; + keyValue++; + break; + } + } + } while (!keyIsUnique && keyValue < 127); + + // Set note on event + track->deltaTimeNoteOn = 0; + track->noteOn.channelNumber = prgmIndex; // 0-based index + track->noteOn.key = keyValue; + track->noteOn.velocity = 64; // Medium velocity + + // Set note off event - one second after note on + float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; + track->deltaTimeNoteOff = (int)ticksPerSecond; // 1 second duration + track->noteOff.channelNumber = prgmIndex; // 0-based index + track->noteOff.key = keyValue; + track->noteOff.velocity = 64; // Same as note on + + // Set end of track + track->deltaTimeEndOfTrack = 0; + + // Calculate the size of the sound track + track->size = ComputeSoundTrackSize(track); + + // Increment the track count + g_ambFile.midi.trackCount++; + + // Refresh the ListView + PopulateAmbListView(); +} + +void Prune() +{ + if (g_ambFile.filePath[0] == '\0') { + MessageBox(NULL, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Make sure the ListView is up to date. We're going to delete any Kmap or Prgm chunks and any sound tracks that don't appear in it. + PopulateAmbListView(); + + int unneededKmapCount = 0; + int unneededPrgmCount = 0; + int unneededTrackCount = 0; + bool tookSnapshot = false; + + for (int kmapIndex = g_ambFile.kmapChunkCount - 1; kmapIndex >= 0; kmapIndex--) { + bool inAnyRow = false; + for (int i = 0; i < g_rowCount; i++) { + if (g_rowInfo[i].kmapIndex == kmapIndex) { + inAnyRow = true; + break; + } + } + if (! inAnyRow) { + if (! tookSnapshot) { + SnapshotCurrentFile(); + tookSnapshot = true; + } + DeleteKmapChunk(kmapIndex); + unneededKmapCount++; + } + } + + for (int prgmIndex = g_ambFile.prgmChunkCount - 1; prgmIndex >= 0; prgmIndex--) { + bool inAnyRow = false; + for (int i = 0; i < g_rowCount; i++) { + if (g_rowInfo[i].prgmIndex == prgmIndex) { + inAnyRow = true; + break; + } + } + if (! inAnyRow) { + if (! tookSnapshot) { + SnapshotCurrentFile(); + tookSnapshot = true; + } + DeletePrgmChunk(prgmIndex); + unneededPrgmCount++; + } + } + + for (int trackIndex = g_ambFile.midi.trackCount - 2; trackIndex >= 0; trackIndex--) { // Skip info track + bool inAnyRow = false; + for (int i = 0; i < g_rowCount; i++) { + if (g_rowInfo[i].trackIndex == trackIndex) { + inAnyRow = true; + break; + } + } + if (! inAnyRow) { + if (! tookSnapshot) { + SnapshotCurrentFile(); + tookSnapshot = true; + } + DeleteSoundTrack(trackIndex); + unneededTrackCount++; + } + } + + if ((unneededKmapCount == 0) && (unneededPrgmCount == 0) && (unneededTrackCount == 0)) { + MessageBox(NULL, "The AMB data has no superfluous parts.", "Nothing to do", MB_OK | MB_ICONINFORMATION); + } else { + char msg[300] = {0}; + snprintf (msg, (sizeof msg) - 1, "Deleted %d unused Kmap chunk%s, %d unused Prgm chunk%s, and %d unused or invalid MIDI track%s.", + unneededKmapCount , unneededKmapCount == 1 ? "" : "s", + unneededPrgmCount , unneededPrgmCount == 1 ? "" : "s", + unneededTrackCount, unneededTrackCount == 1 ? "" : "s"); + MessageBox(NULL, msg, "Pruning results", MB_OK | MB_ICONINFORMATION); + + PopulateAmbListView(); + } +} + +// Handle the end of a ListView label edit +BOOL HandleEndLabelEdit(HWND hwnd, NMLVDISPINFOA *pInfo) +{ + // Check if the edit was cancelled + if (pInfo->item.pszText == NULL) { + return FALSE; // Edit was cancelled, no update needed + } + + // Get the row and column (subitem) being edited + int row = pInfo->item.iItem; + int col = pInfo->item.iSubItem; + char *newText = pInfo->item.pszText; + + // Apply the edit to the AMB file data structure + char formattedText[256]; + BOOL editAccepted = ApplyEditToAmbFile(hwnd, row, col, newText, formattedText, sizeof formattedText); + if (editAccepted) { + SetListViewItemText(g_hwndListView, row, col, formattedText, TRUE); + } + return editAccepted; +} + +// Global variables to track the current edit control's position +int g_editRow = -1; +int g_editCol = -1; +HWND g_hwndEdit = NULL; +WNDPROC g_oldEditProc = NULL; // Original window procedure for the edit control + +// Custom window procedure for the edit control to handle keyboard input +LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_KEYDOWN: + switch (wParam) + { + case VK_RETURN: + // Enter key - accept changes and destroy edit control + if (g_hwndEdit != NULL && g_editRow >= 0 && g_editCol >= 0) { + char buffer[256]; + GetWindowText(g_hwndEdit, buffer, sizeof(buffer)); + + // Apply the edit to the AMB file data structure and update the ListView with the formatted text + char formattedBuffer[256]; + if (ApplyEditToAmbFile(GetParent(GetParent(hwnd)), g_editRow, g_editCol, buffer, formattedBuffer, sizeof formattedBuffer)) { + SetListViewItemText(g_hwndListView, g_editRow, g_editCol, formattedBuffer, TRUE); + } + + // Destroy the edit control + DestroyWindow(g_hwndEdit); + g_hwndEdit = NULL; + g_editRow = -1; + g_editCol = -1; + } + return 0; + + case VK_ESCAPE: + // Escape key - cancel edit + if (g_hwndEdit != NULL) { + DestroyWindow(g_hwndEdit); + g_hwndEdit = NULL; + g_editRow = -1; + g_editCol = -1; + } + return 0; + } + break; + } + + // Call the original window procedure for other messages + return CallWindowProc(g_oldEditProc, hwnd, uMsg, wParam, lParam); +} + +// Returns the currently selected row and whether or not any was selected. Optionally displays an error when none is selected. +bool GetSelectedRow(char const * errorMsg, int * outSelectedRow) +{ + int rowCount = SendMessage(g_hwndListView, LVM_GETITEMCOUNT, 0, 0); + for (int i = 0; i < rowCount; i++) { + UINT state = SendMessage(g_hwndListView, LVM_GETITEMSTATE, i, LVIS_SELECTED); + if (state & LVIS_SELECTED) { + *outSelectedRow = i; + return true; + } + } + + // If we get here, no row was selected + if (errorMsg) + MessageBox(NULL, errorMsg, "Information", MB_OK | MB_ICONINFORMATION); + return false; +} + +// Function to match duration to WAV file for the selected row +void MatchDurationToWav(HWND hwndListView) +{ + int selectedRow; + if (! GetSelectedRow("Please select a row to match duration", &selectedRow)) + return; + + // Make sure we have valid row info + if (selectedRow >= g_rowCount) { + MessageBox(NULL, "Invalid row selection", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Get the WAV filename from the selected row + char wavFileName[256] = {0}; + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = selectedRow; + lvi.iSubItem = COL_WAV_FILE; + lvi.pszText = wavFileName; + lvi.cchTextMax = sizeof(wavFileName); + SendMessage(hwndListView, LVM_GETITEMTEXT, selectedRow, (LPARAM)&lvi); + + if (strlen(wavFileName) == 0) { + MessageBox(NULL, "No WAV filename found in selected row", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Construct full path to WAV file (assuming it's in the same directory as the AMB file) + Path wavFilePath; + strcpy(wavFilePath, g_ambFile.filePath); + PathRemoveFileSpec(wavFilePath); // Remove filename, keep directory + PathAppend(wavFilePath, wavFileName); + + // Get WAV file duration + float wavDuration; + if (!GetWavFileDuration(wavFilePath, &wavDuration)) { + char errorMsg[512]; + snprintf(errorMsg, sizeof(errorMsg), "Could not read duration from WAV file:\n%s\n\nMake sure the file exists and is a valid WAV file.", wavFilePath); + MessageBox(NULL, errorMsg, "Error", MB_OK | MB_ICONERROR); + return; + } + + // Convert duration to string and apply it to the AMB file + char durationStr[32]; + snprintf(durationStr, sizeof(durationStr), "%.3f", wavDuration); + + char formattedText[256]; + if (ApplyEditToAmbFile(GetParent(hwndListView), selectedRow, COL_DURATION, durationStr, formattedText, sizeof(formattedText))) { + SetListViewItemText(hwndListView, selectedRow, COL_DURATION, formattedText, TRUE); + } else { + MessageBeep(MB_ICONERROR); + } +} + +// Function to programmatically start editing a ListView subitem +void EditListViewSubItem(HWND hwndListView, int row, int col) +{ + // First select the item + LVITEMA lvi = {0}; + lvi.stateMask = LVIS_SELECTED; + lvi.state = LVIS_SELECTED; + SendMessage(hwndListView, LVM_SETITEMSTATE, row, (LPARAM)&lvi); + + // For subitems, we need to create a custom edit control + // First get the text of the subitem + char buffer[256] = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = row; + lvi.iSubItem = col; + lvi.pszText = buffer; + lvi.cchTextMax = sizeof(buffer); + SendMessage(hwndListView, LVM_GETITEMTEXT, row, (LPARAM)&lvi); + + // Create a structure for LVM_GETSUBITEMRECT + // The struct needs to have subItem in top and flags in left + RECT rect; + memset(&rect, 0, sizeof(RECT)); + rect.top = col; // subItem index + rect.left = LVIR_BOUNDS; // Type of rectangle (LVIR_BOUNDS for entire cell) + SendMessage(hwndListView, LVM_GETSUBITEMRECT, row, (LPARAM)&rect); + + // If we already have an edit control, destroy it + if (g_hwndEdit != NULL) { + DestroyWindow(g_hwndEdit); + g_hwndEdit = NULL; + } + + // For column 0 (Time), we need to adjust the width to match the column width + // instead of using the full row width that LVIR_BOUNDS returns + if (col == COL_TIME) { + // Get the width of column 0 + LVCOLUMNA lvc = {0}; + lvc.mask = LVCF_WIDTH; + SendMessage(hwndListView, LVM_GETCOLUMN, COL_TIME, (LPARAM)&lvc); + + // Adjust the rectangle to match the column width + rect.right = rect.left + lvc.cx; + } + + // Create an edit control over the subitem + g_hwndEdit = CreateWindow( + "EDIT", buffer, + WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + hwndListView, (HMENU)1000, GetModuleHandle(NULL), NULL); + + if (g_hwndEdit) { + // Store which row and column we're editing + g_editRow = row; + g_editCol = col; + + // Subclass the edit control to handle keyboard input + g_oldEditProc = (WNDPROC)SetWindowLongPtr(g_hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditSubclassProc); + + // Set focus to the edit control and select all text + SetFocus(g_hwndEdit); + SendMessage(g_hwndEdit, EM_SETSEL, 0, -1); + } +} + +// Calculate and update the overall duration display +void UpdateOverallDuration(void) +{ + if (g_hwndDurationLabel == NULL) { + return; + } + + float maxEndTime = 0.0f; + + // Check if we have valid AMB data + if (g_ambFile.kmapChunkCount == 0 || g_ambFile.prgmChunkCount == 0 || g_ambFile.midi.trackCount == 0) { + SetWindowText(g_hwndDurationLabel, "Overall Duration: 0.000 sec"); + return; + } + + // Calculate seconds per tick for timing + float secondsPerTick = 0.0f; + if (g_ambFile.midi.ticksPerQuarterNote > 0) { + secondsPerTick = g_ambFile.midi.secondsPerQuarterNote / g_ambFile.midi.ticksPerQuarterNote; + } + + // Process each MIDI sound track to find the longest duration + int soundTrackCount = g_ambFile.midi.trackCount - 1; // Minus one to exclude the info track + for (int trackIndex = 0; trackIndex < soundTrackCount; trackIndex++) { + SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; + + int prgmIndex = GetReferencedPrgmIfValid(trackIndex); + if (prgmIndex < 0) + continue; // No valid Prgm, skip this track + + float timestamp = track->deltaTimeNoteOn * secondsPerTick; + float duration = track->deltaTimeNoteOff * secondsPerTick; + float endTime = timestamp + duration; + + if (endTime > maxEndTime) { + maxEndTime = endTime; + } + } + + // Update the label text + char durationText[64] = {0}; + snprintf(durationText, sizeof(durationText) - 1, "Overall Duration: %04.3f sec", maxEndTime); + SetWindowText(g_hwndDurationLabel, durationText); +} + +// Create and initialize the ListView control +void CreateAmbListView(HWND hwnd) +{ + // Create ListView control below the playback buttons + g_hwndListView = CreateWindow( + WC_LISTVIEW, + "", + WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_NOHSCROLL | LVS_EDITLABELS, + 20, 70, // x, y position (below the buttons) + 835, 460, // width, height (fill most of the window) + hwnd, + (HMENU)ID_AMB_LISTVIEW, + GetModuleHandle(NULL), + NULL + ); + + if (g_hwndListView == NULL) { + MessageBox(hwnd, "Could not create ListView control", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Set extended ListView styles + DWORD exStyle = LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES; + SendMessage(g_hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle); + + // Add columns to the ListView + AddListViewColumn(g_hwndListView, COL_TIME, "Time (sec.)", 85); + AddListViewColumn(g_hwndListView, COL_DURATION, "Duration (sec.)", 95); + AddListViewColumn(g_hwndListView, COL_WAV_FILE, "WAV File", 235); + AddListViewColumn(g_hwndListView, COL_SPEED_RANDOM, "Speed Rnd", 70); + AddListViewColumn(g_hwndListView, COL_SPEED_MIN, "Speed Min", 70); + AddListViewColumn(g_hwndListView, COL_SPEED_MAX, "Speed Max", 70); + AddListViewColumn(g_hwndListView, COL_VOLUME_RANDOM, "Vol. Rnd", 70); + AddListViewColumn(g_hwndListView, COL_VOLUME_MIN, "Vol. Min", 70); + AddListViewColumn(g_hwndListView, COL_VOLUME_MAX, "Vol. Max", 70); + + // Create duration label below the ListView + g_hwndDurationLabel = CreateWindow( + "STATIC", + "Overall Duration: 0.000 sec", + WS_CHILD | WS_VISIBLE | SS_LEFT, + 20, 540, // x, y position (below the ListView) + 250, 20, // width, height + hwnd, + NULL, + GetModuleHandle(NULL), + NULL + ); +} + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + // Read INI settings + { + Path iniFullPath; + GetCurrentDirectory(PATH_BUFFER_SIZE, iniFullPath); + PathAppend(iniFullPath, "amb_editor.ini"); + + GetPrivateProfileString("Paths", "civ_3_install_path", "", g_iniCiv3InstallPath, PATH_BUFFER_SIZE, iniFullPath); + GetPrivateProfileString("Paths", "sound_dll_path" , "", g_iniSoundDLLPath , PATH_BUFFER_SIZE, iniFullPath); + GetPrivateProfileString("Paths", "temp_directory" , "", g_iniTempDirectory , PATH_BUFFER_SIZE, iniFullPath); + } + + // If we've been given a specific Civ 3 install path in the INI, use that. Otherwise search for one. + if (strlen(g_iniCiv3InstallPath) > 0) { + strcpy(g_civ3MainPath, g_iniCiv3InstallPath); + } else { + FindCiv3Installation(hwnd); + } + + g_hwndMainWindow = hwnd; + + // Create playback buttons + CreatePlaybackButtons(hwnd); + + // Create the AMB ListView control + CreateAmbListView(hwnd); + + return 0; + + case WM_COMMAND: + // Handle menu commands + switch (LOWORD(wParam)) + { + case IDM_FILE_OPEN: + // Show open file dialog to load an AMB file + LoadAmbFileWithDialog(hwnd); + return 0; + + case IDM_FILE_SAVE: + // Save AMB file directly + SaveAmbFileDirectly(hwnd); + return 0; + + case IDM_FILE_SAVE_AS: + // Show save file dialog to save AMB file as + SaveAmbFileAs(hwnd); + return 0; + + case IDM_FILE_DETAILS: + // Show window with AMB file details + ShowAmbDetailsWindow(hwnd); + return 0; + + case IDM_FILE_EXIT: + // Exit the application + PostMessage(hwnd, WM_CLOSE, 0, 0); + return 0; + + case IDM_EDIT_UNDO: + // Perform undo operation + Undo(); + return 0; + + case IDM_EDIT_REDO: + // Perform redo operation + Redo(); + return 0; + + case IDM_EDIT_ADD: + // Add a new row + AddRow(); + return 0; + + case IDM_EDIT_DELETE: + { + // Delete the selected row + int selectedRow; + if (GetSelectedRow("Please select a row to delete", &selectedRow)) + DeleteRow(selectedRow); + + return 0; + } + + case IDM_EDIT_MATCH_WAV: + // Match duration to WAV file + MatchDurationToWav(g_hwndListView); + return 0; + + case IDM_EDIT_PRUNE: + Prune(); + return 0; + + case IDM_HELP_ABOUT: + // Show about dialog + MessageBox(hwnd, + "This is a tool for inspecting and modifying the AMB sound files used by Sid Meier's Civilization III.\n\n" + "Last updated in C3X Release 23\n\n" + "For more info, see README.txt", + "About AMB Editor", + MB_OK | MB_ICONINFORMATION); + return 0; + + case ID_PLAY_BUTTON: + // Handle Play button click + if (g_ambFile.filePath[0] != '\0') { + bool encounteredError = false; + + // Check that the preview player is initialized. If it's not, try to initialize it. + if (! previewPlayerIsInitialized) { + Path soundDLLPath; + if (GetSoundDLLPath(hwnd, soundDLLPath)) { + InitializePreviewPlayer(hwnd, soundDLLPath); + } + if (! previewPlayerIsInitialized) + encounteredError = true; + } + + // Check for missing WAV files before attempting preview + if (! encounteredError) { + char missingFiles[1024]; + if (HasMissingWavFiles(missingFiles, sizeof(missingFiles))) { + char errorMsg[1280]; + snprintf(errorMsg, sizeof(errorMsg), + "Cannot preview AMB file because the following WAV files are missing:\n\n%s\n\nPlease ensure all WAV files are present in the AMB file's directory.", + missingFiles); + MessageBox(hwnd, errorMsg, "Missing WAV Files", MB_OK | MB_ICONERROR); + } + } + + if (! encounteredError) + PreviewAmbFile(g_iniTempDirectory, &g_ambFile); + } else { + MessageBox(hwnd, "No AMB file loaded. Please open an AMB file first.", + "Error", MB_OK | MB_ICONINFORMATION); + } + return 0; + + case ID_STOP_BUTTON: + // Handle Stop button click + StopAmbPreview(); + return 0; + + // Check if the command is from the edit control created for subitem editing + default: + if (LOWORD(wParam) == 1000 && HIWORD(wParam) == EN_KILLFOCUS) { + // When the edit control loses focus, get its text and update the list view item + if (g_hwndEdit != NULL && g_editRow >= 0 && g_editCol >= 0) { + char buffer[256]; + GetWindowText(g_hwndEdit, buffer, sizeof(buffer)); + + // Apply the edit to the AMB file data structure + char formattedBuffer[256]; + if (ApplyEditToAmbFile(hwnd, g_editRow, g_editCol, buffer, formattedBuffer, sizeof formattedBuffer)) { + SetListViewItemText(g_hwndListView, g_editRow, g_editCol, formattedBuffer, TRUE); + } + + // Destroy the edit control + DestroyWindow(g_hwndEdit); + g_hwndEdit = NULL; + g_editRow = -1; + g_editCol = -1; + } + return 0; + } + } + break; + + case WM_NOTIFY: + // Handle control notifications + { + NMHDR *nmhdr = (NMHDR *)lParam; + + // Check if the notification is from our ListView + if (nmhdr->hwndFrom == g_hwndListView) { + switch (nmhdr->code) { + case LVN_BEGINLABELEDIT: + // Notification when a label edit begins + return HandleBeginLabelEdit(hwnd, (NMLVDISPINFOA *)lParam); + + case LVN_ENDLABELEDIT: + // Notification when a label edit ends + return HandleEndLabelEdit(hwnd, (NMLVDISPINFOA *)lParam); + + case NM_DBLCLK: + // Handle double-click on a ListView item to edit the cell + { + NMITEMACTIVATE *nia = (NMITEMACTIVATE *)lParam; + // Only process if a valid item was clicked + if (nia->iItem != -1) { + // Check if this is a boolean column + if (nia->iSubItem == COL_SPEED_RANDOM || nia->iSubItem == COL_VOLUME_RANDOM) { + // Toggle the boolean value directly + char currentText[32]; + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = nia->iItem; + lvi.iSubItem = nia->iSubItem; + lvi.pszText = currentText; + lvi.cchTextMax = sizeof(currentText); + SendMessage(g_hwndListView, LVM_GETITEMTEXT, nia->iItem, (LPARAM)&lvi); + + // Toggle: if current is "Yes", change to "No", otherwise change to "Yes" + const char *newText = (strcmp(currentText, "Yes") == 0) ? "No" : "Yes"; + + // Apply the toggle to the AMB file data structure + char formattedText[256]; + if (ApplyEditToAmbFile(hwnd, nia->iItem, nia->iSubItem, newText, formattedText, sizeof(formattedText))) { + SetListViewItemText(g_hwndListView, nia->iItem, nia->iSubItem, formattedText, TRUE); + } + } else { + // For non-boolean columns, start editing the subitem that was clicked + EditListViewSubItem(g_hwndListView, nia->iItem, nia->iSubItem); + } + + // Tell the system we handled this message + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); + return TRUE; + } + } + break; + + case NM_CUSTOMDRAW: + // Handle custom drawing for ListView + { + LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam; + + switch (lplvcd->nmcd.dwDrawStage) { + case CDDS_PREPAINT: + // Tell Windows we want to be notified for each item + return CDRF_NOTIFYITEMDRAW; + + case CDDS_ITEMPREPAINT: + // Tell Windows we want to be notified for each subitem + return CDRF_NOTIFYSUBITEMDRAW; + + case CDDS_SUBITEM | CDDS_ITEMPREPAINT: + // Custom draw for individual cells + { + int item = (int)lplvcd->nmcd.dwItemSpec; + int subItem = lplvcd->iSubItem; + + // Check if this is the WAV file column + if (subItem == COL_WAV_FILE) { + // Get the WAV filename for this row + char wavFileName[256] = {0}; + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = item; + lvi.iSubItem = COL_WAV_FILE; + lvi.pszText = wavFileName; + lvi.cchTextMax = sizeof(wavFileName); + SendMessage(g_hwndListView, LVM_GETITEMTEXT, item, (LPARAM)&lvi); + + // Check if WAV file exists + if (!CheckWavFileExists(wavFileName)) { + // Set text color to red for missing files + lplvcd->clrText = RGB(255, 0, 0); + } else { + // Use default text color + lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); + } + + return CDRF_NEWFONT; + } else if (subItem == COL_SPEED_MIN || subItem == COL_SPEED_MAX || + subItem == COL_VOLUME_MIN || subItem == COL_VOLUME_MAX) { + // Check if min/max columns should be grayed out based on flags + if (item < g_rowCount) { + AmbRowInfo *rowInfo = &g_rowInfo[item]; + if (rowInfo->prgmIndex >= 0 && rowInfo->prgmIndex < g_ambFile.prgmChunkCount) { + PrgmChunk *prgm = &g_ambFile.prgmChunks[rowInfo->prgmIndex]; + + BOOL shouldGrayOut = FALSE; + if (subItem == COL_SPEED_MIN || subItem == COL_SPEED_MAX) { + // Gray out if speed random is disabled (flags & 1 == 0) + shouldGrayOut = !(prgm->flags & 0x01); + } else { + // Gray out if volume random is disabled (flags & 2 == 0) + shouldGrayOut = !(prgm->flags & 0x02); + } + + if (shouldGrayOut) { + lplvcd->clrText = GetSysColor(COLOR_GRAYTEXT); + } else { + lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); + } + + return CDRF_NEWFONT; + } + } + + // Fallback to default color + lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); + return CDRF_NEWFONT; + } else { + // For all other columns, use default text color + lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); + return CDRF_NEWFONT; + } + } + } + } + return CDRF_DODEFAULT; + } + } + } + break; + + case WM_ERASEBKGND: + { + // Handle window background erasure + HDC hdc = (HDC)wParam; + RECT rect; + GetClientRect(hwnd, &rect); + FillRect(hdc, &rect, g_hBackgroundBrush); + return 1; // Return non-zero to indicate we processed this message + } + + case WM_CTLCOLORDLG: + case WM_CTLCOLORSTATIC: + case WM_CTLCOLORBTN: + // Set background color for dialog, static controls, and buttons + return (LRESULT)g_hBackgroundBrush; + + case WM_CLOSE: + DestroyWindow(hwnd); + return 0; + + case WM_DESTROY: + // Clean up resources + if (g_hBackgroundBrush != NULL) { + DeleteObject(g_hBackgroundBrush); + g_hBackgroundBrush = NULL; + } + DeinitializePreviewPlayer(); + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +// Create a simple menu +HMENU CreateAmbEditorMenu() +{ + HMENU hMenu, hFileMenu, hEditMenu, hHelpMenu; + + hMenu = CreateMenu(); + + // File menu + hFileMenu = CreatePopupMenu(); + AppendMenu(hFileMenu, MF_STRING, IDM_FILE_OPEN, "&Open AMB File...\tCtrl+O"); + AppendMenu(hFileMenu, MF_STRING, IDM_FILE_SAVE, "&Save\tCtrl+S"); + AppendMenu(hFileMenu, MF_STRING, IDM_FILE_SAVE_AS, "Save &As..."); + AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hFileMenu, MF_STRING, IDM_FILE_DETAILS, "&View AMB Details"); + AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hFileMenu, MF_STRING, IDM_FILE_EXIT, "E&xit"); + + // Edit menu + hEditMenu = CreatePopupMenu(); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_UNDO, "&Undo\tCtrl+Z"); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_REDO, "&Redo\tCtrl+Y"); + AppendMenu(hEditMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_ADD, "&Add Row\tIns"); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_DELETE, "&Delete Row\tDel"); + AppendMenu(hEditMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_MATCH_WAV, "&Match duration to WAV"); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_PRUNE, "&Prune"); + + // Help menu + hHelpMenu = CreatePopupMenu(); + AppendMenu(hHelpMenu, MF_STRING, IDM_HELP_ABOUT, "&About..."); + + // Add menus to the main menu + AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, "&File"); + AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hEditMenu, "&Edit"); + AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hHelpMenu, "&Help"); + + return hMenu; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + // Register the window class + const char CLASS_NAME[] = "AMB Editor Window Class"; + + // Create a pleasant beige brush for the background - RGB(245, 245, 220) is a nice beige color + g_hBackgroundBrush = CreateSolidBrush(RGB(245, 235, 200)); + + WNDCLASS wc = {0}; + wc.lpfnWndProc = WindowProc; + wc.hInstance = hInstance; + wc.lpszClassName = CLASS_NAME; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = g_hBackgroundBrush; + + RegisterClass(&wc); + + // Create menu + HMENU hMenu = CreateAmbEditorMenu(); + + // Create the window + HWND hwnd = CreateWindowEx( + 0, // Optional window styles + CLASS_NAME, // Window class + "AMB Editor", // Window title + WS_OVERLAPPEDWINDOW, // Window style + + // Size and position + CW_USEDEFAULT, CW_USEDEFAULT, 895, 620, + + NULL, // Parent window + hMenu, // Menu + hInstance, // Instance handle + NULL // Additional application data + ); + + if (hwnd == NULL) { + return 0; + } + + ShowWindow(hwnd, nCmdShow); + + // Create accelerator table + HACCEL hAccel = CreateAcceleratorTable(g_accelTable, sizeof(g_accelTable) / sizeof(g_accelTable[0])); + + // Run the message loop + MSG msg = {0}; + while (GetMessage(&msg, NULL, 0, 0)) { + if (!TranslateAccelerator(hwnd, hAccel, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return (int)msg.wParam; +} diff --git a/AMB Editor/amb_file.c b/AMB Editor/amb_file.c index 530e8e02..6a98b128 100644 --- a/AMB Editor/amb_file.c +++ b/AMB Editor/amb_file.c @@ -1,1536 +1,1536 @@ -// This file gets #included into amb_editor.c - -#include -#include -#include -#include -#include - -#define MAX_CHUNKS 30 // No AMB in Civ 3 has more than 12 Kmap or Prgm chunks -#define MAX_SOUND_TRACKS 30 // No AMB in Civ 3 has more than 12 sound tracks -#define MAX_CONTROL_CHANGES 2 // No AMB in Civ 3 has more than 2 control changes per track -#define MAX_ITEMS 2 // No AMB in Civ 3 has more than 1 item - -// AMB file structures for Civ 3 -typedef struct { - int size; - int number; - int flags; - int maxRandomSpeed; - int minRandomSpeed; - int maxRandomVolume; - int minRandomVolume; - char effectName[256]; - char varName[256]; -} PrgmChunk; - -typedef struct { - unsigned char data[12]; - char wavFileName[256]; -} KmapItem; - -typedef struct { - int size; - int flags; - int param1; - int param2; - char varName[256]; - int itemCount; - int itemSize; - KmapItem items[MAX_ITEMS]; -} KmapChunk; - -typedef struct { - int size; - int dataSize; - unsigned char data[12]; - unsigned char extraData[512]; - int extraDataSize; -} GlblChunk; - -// MIDI event types - specific to Civ3 AMB files -typedef struct { - char name[256]; // Always "Seq-1" in Civ3 AMBs -} TrackNameEvent; - -typedef struct { - int hr, mn, se, fr, ff; -} SMPTEOffsetEvent; - -typedef struct { - int nn, dd, cc, bb; -} TimeSignatureEvent; - -typedef struct { - int microsecondsPerQuarterNote; -} SetTempoEvent; - -typedef struct { - int channelNumber, controllerNumber, value; -} ControlChangeEvent; - -typedef struct { - int channelNumber, programNumber; -} ProgramChangeEvent; - -typedef struct { - int channelNumber, key, velocity; -} NoteOffEvent; - -typedef struct { - int channelNumber, key, velocity; -} NoteOnEvent; - -// Specific track structures for Civ3 AMB files -typedef struct { - int size; - int deltaTimeTrackName; - TrackNameEvent trackName; - int deltaTimeSMPTEOffset; - SMPTEOffsetEvent smpteOffset; - int deltaTimeTimeSignature; - TimeSignatureEvent timeSignature; - int deltaTimeSetTempo; - SetTempoEvent setTempo; - int deltaTimeEndOfTrack; -} InfoTrack; - -typedef struct { - int size; - int deltaTimeTrackName; - TrackNameEvent trackName; - int controlChangeCount; - int deltaTimeControlChanges[MAX_CONTROL_CHANGES]; - ControlChangeEvent controlChanges[MAX_CONTROL_CHANGES]; - int deltaTimeProgramChange; - ProgramChangeEvent programChange; - int deltaTimeNoteOn; - NoteOnEvent noteOn; - int deltaTimeNoteOff; - NoteOffEvent noteOff; - int deltaTimeEndOfTrack; -} SoundTrack; - -typedef struct { - short format; - short trackCount; - short ticksPerQuarterNote; - float secondsPerQuarterNote; - InfoTrack infoTrack; - SoundTrack soundTracks[MAX_SOUND_TRACKS]; -} MidiData; - -typedef struct { - Path filePath; - - // Chunks - PrgmChunk prgmChunks[MAX_CHUNKS]; - int prgmChunkCount; - - KmapChunk kmapChunks[MAX_CHUNKS]; - int kmapChunkCount; - - GlblChunk glblChunk; - bool hasGlblChunk; - - MidiData midi; -} AmbFile; - -// Helper functions for file parsing and writing -unsigned int ReadAmbInt(FILE *file, bool isUnsigned) { - unsigned char buffer[4]; - fread(buffer, 1, 4, file); - - // Little endian - unsigned int result = - (buffer[0]) | - (buffer[1] << 8) | - (buffer[2] << 16) | - (buffer[3] << 24); - - if (!isUnsigned && (result & 0x80000000)) { - // Convert to signed if needed - return (int)result; - } - - return result; -} - -// Helper functions for file writing -void WriteAmbInt(FILE *file, unsigned int value, bool isUnsigned) { - unsigned char buffer[4]; - - // Little endian - buffer[0] = value & 0xFF; - buffer[1] = (value >> 8) & 0xFF; - buffer[2] = (value >> 16) & 0xFF; - buffer[3] = (value >> 24) & 0xFF; - - fwrite(buffer, 1, 4, file); -} - -void WriteMidiInt(FILE *file, unsigned int value, bool isUnsigned) { - unsigned char buffer[4]; - - // Big endian - buffer[0] = (value >> 24) & 0xFF; - buffer[1] = (value >> 16) & 0xFF; - buffer[2] = (value >> 8) & 0xFF; - buffer[3] = value & 0xFF; - - fwrite(buffer, 1, 4, file); -} - -void WriteMidiShort(FILE *file, unsigned short value, bool isUnsigned) { - unsigned char buffer[2]; - - // Big endian - buffer[0] = (value >> 8) & 0xFF; - buffer[1] = value & 0xFF; - - fwrite(buffer, 1, 2, file); -} - -void WriteMidiVarInt(FILE *file, unsigned int value) { - unsigned char buffer[4]; - int numBytes = 0; - - // Build the bytes from least significant to most significant - do { - buffer[numBytes++] = (value & 0x7F) | (numBytes > 0 ? 0x80 : 0); - value >>= 7; - } while (value > 0 && numBytes < 4); - - // Write the bytes in reverse order - for (int i = numBytes - 1; i >= 0; i--) { - // Clear the continuation bit for the last byte - if (i == 0) { - buffer[i] &= 0x7F; - } - fwrite(&buffer[i], 1, 1, file); - } -} - -void WriteString(FILE *file, const char *str) { - // Write null-terminated string - fwrite(str, 1, strlen(str) + 1, file); -} - -unsigned int ReadMidiInt(FILE *file, bool isUnsigned) { - unsigned char buffer[4]; - fread(buffer, 1, 4, file); - - // Big endian - unsigned int result = - (buffer[0] << 24) | - (buffer[1] << 16) | - (buffer[2] << 8) | - (buffer[3]); - - if (!isUnsigned && (result & 0x80000000)) { - // Convert to signed if needed - return (int)result; - } - - return result; -} - -unsigned short ReadMidiShort(FILE *file, bool isUnsigned) { - unsigned char buffer[2]; - fread(buffer, 1, 2, file); - - // Big endian - unsigned short result = (buffer[0] << 8) | buffer[1]; - - if (!isUnsigned && (result & 0x8000)) { - // Convert to signed if needed - return (short)result; - } - - return result; -} - -unsigned int ReadMidiVarInt(FILE *file) { - unsigned int result = 0; - unsigned char byte; - - do { - fread(&byte, 1, 1, file); - result = (result << 7) | (byte & 0x7F); - } while (byte & 0x80); - - return result; -} - -void ReadString(FILE *file, char *buffer, int maxLength) { - int i = 0; - char byte; - - while (i < maxLength - 1) { - fread(&byte, 1, 1, file); - if (byte == 0) { - break; - } - buffer[i++] = byte; - } - - buffer[i] = '\0'; -} - -// Parse AMB file chunks -bool ParsePrgmChunk(FILE *file, PrgmChunk *chunk) { - chunk->size = ReadAmbInt(file, true); - chunk->number = ReadAmbInt(file, true); - chunk->flags = ReadAmbInt(file, false); - chunk->maxRandomSpeed = ReadAmbInt(file, false); - chunk->minRandomSpeed = ReadAmbInt(file, false); - chunk->maxRandomVolume = ReadAmbInt(file, false); - chunk->minRandomVolume = ReadAmbInt(file, false); - - // Read end marker - unsigned int endMarker = ReadAmbInt(file, true); - if (endMarker != 0xFA) { - MessageBox(NULL, "Expected 0xFA marker before strings in Prgm chunk", "Error", MB_OK | MB_ICONERROR); - return false; - } - - ReadString(file, chunk->effectName, sizeof(chunk->effectName)); - ReadString(file, chunk->varName, sizeof(chunk->varName)); - - return true; -} - -bool ParseKmapChunk(FILE *file, KmapChunk *chunk) { - chunk->size = ReadAmbInt(file, true); - chunk->flags = ReadAmbInt(file, true); - chunk->param1 = ReadAmbInt(file, true); - chunk->param2 = ReadAmbInt(file, true); - - ReadString(file, chunk->varName, sizeof(chunk->varName)); - - chunk->itemCount = ReadAmbInt(file, true); - - if ((chunk->flags & 6) != 0) { - chunk->itemSize = ReadAmbInt(file, true); - } else { - chunk->itemSize = 0; - } - - // Read items - for (int i = 0; i < chunk->itemCount && i < MAX_ITEMS; i++) { - if ((chunk->flags & 6) == 0) { - // Not used in Civ3 - int aint1 = ReadAmbInt(file, true); - int aint2 = ReadAmbInt(file, true); - } else { - // Read the 12-byte data block - fread(chunk->items[i].data, 1, chunk->itemSize, file); - } - - ReadString(file, chunk->items[i].wavFileName, sizeof(chunk->items[i].wavFileName)); - } - - // Read end marker - unsigned int endMarker = ReadAmbInt(file, true); - if (endMarker != 0xFA) { - MessageBox(NULL, "Expected 0xFA marker at end of Kmap chunk", "Error", MB_OK | MB_ICONERROR); - return false; - } - - return true; -} - -bool ParseGlblChunk(FILE *file, GlblChunk *chunk) { - chunk->size = ReadAmbInt(file, true); - long startPos = ftell(file); - - chunk->dataSize = ReadAmbInt(file, true); - fread(chunk->data, 1, chunk->dataSize, file); - - // Read any extra data - long currentPos = ftell(file); - long remainingSize = chunk->size - (currentPos - startPos); - - if (remainingSize > 0 && remainingSize < sizeof(chunk->extraData)) { - fread(chunk->extraData, 1, remainingSize, file); - chunk->extraDataSize = (int)remainingSize; - } else { - chunk->extraDataSize = 0; - } - - return true; -} - -// Parse TrackName event from MIDI file -bool ParseTrackNameEvent(FILE *file, TrackNameEvent *event) { - unsigned char metaType; - fread(&metaType, 1, 1, file); - - if (metaType != 0x03) { - MessageBox(NULL, "Expected TrackName event (0x03)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned int length = ReadMidiVarInt(file); - memset(event->name, 0, sizeof(event->name)); - fread(event->name, 1, length < sizeof(event->name) ? length : sizeof(event->name) - 1, file); - - return true; -} - -// Parse SMPTEOffset event from MIDI file -bool ParseSMPTEOffsetEvent(FILE *file, SMPTEOffsetEvent *event) { - unsigned char metaType; - fread(&metaType, 1, 1, file); - - if (metaType != 0x54) { - MessageBox(NULL, "Expected SMPTEOffset event (0x54)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned char length; - fread(&length, 1, 1, file); - - if (length != 5) { - MessageBox(NULL, "Invalid SMPTEOffset event length (expected 5)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - event->hr = fgetc(file); - event->mn = fgetc(file); - event->se = fgetc(file); - event->fr = fgetc(file); - event->ff = fgetc(file); - - return true; -} - -// Parse TimeSignature event from MIDI file -bool ParseTimeSignatureEvent(FILE *file, TimeSignatureEvent *event) { - unsigned char metaType; - fread(&metaType, 1, 1, file); - - if (metaType != 0x58) { - MessageBox(NULL, "Expected TimeSignature event (0x58)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned char length; - fread(&length, 1, 1, file); - - if (length != 4) { - MessageBox(NULL, "Invalid TimeSignature event length (expected 4)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - event->nn = fgetc(file); - event->dd = fgetc(file); - event->cc = fgetc(file); - event->bb = fgetc(file); - - return true; -} - -// Parse SetTempo event from MIDI file -bool ParseSetTempoEvent(FILE *file, SetTempoEvent *event) { - unsigned char metaType; - fread(&metaType, 1, 1, file); - - if (metaType != 0x51) { - MessageBox(NULL, "Expected SetTempo event (0x51)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned char length; - fread(&length, 1, 1, file); - - if (length != 3) { - MessageBox(NULL, "Invalid SetTempo event length (expected 3)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned char tempo[3]; - fread(tempo, 1, 3, file); - event->microsecondsPerQuarterNote = (tempo[0] << 16) | (tempo[1] << 8) | tempo[2]; - - return true; -} - -// Parse EndOfTrack event from MIDI file -bool ParseEndOfTrackEvent(FILE *file) { - unsigned char metaType; - fread(&metaType, 1, 1, file); - - if (metaType != 0x2F) { - MessageBox(NULL, "Expected EndOfTrack event (0x2F)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned char zero; - fread(&zero, 1, 1, file); // Should be zero - - return true; -} - -// Parse ControlChange event from MIDI file -bool ParseControlChangeEvent(FILE *file, ControlChangeEvent *event, int *channelNumber) { - unsigned char statusByte; - fread(&statusByte, 1, 1, file); - - // Check if the status byte indicates a control change event (0xBn) - if ((statusByte >> 4) != 0xB) { - // If channelNumber pointer is provided, we're expecting running status - if (channelNumber != NULL) { - // Put the byte back for reading data - fseek(file, -1, SEEK_CUR); - event->channelNumber = *channelNumber; - } else { - MessageBox(NULL, "Expected ControlChange event (0xBn)", "Error", MB_OK | MB_ICONERROR); - return false; - } - } else { - event->channelNumber = statusByte & 0x0F; - // Save channel number for possible running status - if (channelNumber != NULL) { - *channelNumber = event->channelNumber; - } - } - - event->controllerNumber = fgetc(file); - event->value = fgetc(file); - - return true; -} - -// Parse ProgramChange event from MIDI file -bool ParseProgramChangeEvent(FILE *file, ProgramChangeEvent *event, int *channelNumber) { - unsigned char statusByte; - fread(&statusByte, 1, 1, file); - - // Check if the status byte indicates a program change event (0xCn) - if ((statusByte >> 4) != 0xC) { - // If channelNumber pointer is provided, we're expecting running status - if (channelNumber != NULL) { - // Put the byte back for reading data - fseek(file, -1, SEEK_CUR); - event->channelNumber = *channelNumber; - } else { - MessageBox(NULL, "Expected ProgramChange event (0xCn)", "Error", MB_OK | MB_ICONERROR); - return false; - } - } else { - event->channelNumber = statusByte & 0x0F; - // Save channel number for possible running status - if (channelNumber != NULL) { - *channelNumber = event->channelNumber; - } - } - - event->programNumber = fgetc(file); - - return true; -} - -// Parse NoteOn event from MIDI file -bool ParseNoteOnEvent(FILE *file, NoteOnEvent *event, int *channelNumber) { - unsigned char statusByte; - fread(&statusByte, 1, 1, file); - - // Check if the status byte indicates a note on event (0x9n) - if ((statusByte >> 4) != 0x9) { - // If channelNumber pointer is provided, we're expecting running status - if (channelNumber != NULL) { - // Put the byte back for reading data - fseek(file, -1, SEEK_CUR); - event->channelNumber = *channelNumber; - } else { - MessageBox(NULL, "Expected NoteOn event (0x9n)", "Error", MB_OK | MB_ICONERROR); - return false; - } - } else { - event->channelNumber = statusByte & 0x0F; - // Save channel number for possible running status - if (channelNumber != NULL) { - *channelNumber = event->channelNumber; - } - } - - event->key = fgetc(file); - event->velocity = fgetc(file); - - return true; -} - -// Parse NoteOff event from MIDI file -bool ParseNoteOffEvent(FILE *file, NoteOffEvent *event, int *channelNumber) { - unsigned char statusByte; - fread(&statusByte, 1, 1, file); - - // Check if the status byte indicates a note off event (0x8n) - if ((statusByte >> 4) != 0x8) { - // Check if it's a note on with velocity 0 (equivalent to note off) - if ((statusByte >> 4) == 0x9) { - event->channelNumber = statusByte & 0x0F; - event->key = fgetc(file); - event->velocity = fgetc(file); - - // Check if velocity is 0 (note off) - if (event->velocity > 0) { - MessageBox(NULL, "Expected NoteOff event but got NoteOn with velocity > 0", "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Save channel number for possible running status - if (channelNumber != NULL) { - *channelNumber = event->channelNumber; - } - - return true; - } - - // If channelNumber pointer is provided, we're expecting running status - if (channelNumber != NULL) { - // Put the byte back for reading data - fseek(file, -1, SEEK_CUR); - event->channelNumber = *channelNumber; - } else { - MessageBox(NULL, "Expected NoteOff event (0x8n)", "Error", MB_OK | MB_ICONERROR); - return false; - } - } else { - event->channelNumber = statusByte & 0x0F; - // Save channel number for possible running status - if (channelNumber != NULL) { - *channelNumber = event->channelNumber; - } - } - - event->key = fgetc(file); - event->velocity = fgetc(file); - - return true; -} - -// Parse InfoTrack from MIDI file -bool ParseInfoTrack(FILE *file, InfoTrack *track) { - // Read the file tag - char trackTag[5] = {0}; - fread(trackTag, 1, 4, file); - - if (strcmp(trackTag, "MTrk") != 0) { - char errMsg[256]; - sprintf(errMsg, "Invalid MIDI info track header: expected 'MTrk', got '%.4s'", trackTag); - MessageBox(NULL, errMsg, "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Read track chunk size - track->size = ReadMidiInt(file, true); - long startPos = ftell(file); - - // Read events in the InfoTrack - - // 1. TrackName event - track->deltaTimeTrackName = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for TrackName", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseTrackNameEvent(file, &track->trackName)) return false; - - // 2. SMPTEOffset event - track->deltaTimeSMPTEOffset = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for SMPTEOffset", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseSMPTEOffsetEvent(file, &track->smpteOffset)) return false; - - // 3. TimeSignature event - track->deltaTimeTimeSignature = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for TimeSignature", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseTimeSignatureEvent(file, &track->timeSignature)) return false; - - // 4. SetTempo event - track->deltaTimeSetTempo = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for SetTempo", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseSetTempoEvent(file, &track->setTempo)) return false; - - // 5. EndOfTrack event - track->deltaTimeEndOfTrack = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for EndOfTrack", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseEndOfTrackEvent(file)) return false; - - // Ensure we've read exactly the size of the track - long currentPos = ftell(file); - if (currentPos != startPos + track->size) { - MessageBox(NULL, "Info track size mismatch", "Error", MB_OK | MB_ICONERROR); - return false; - } - - return true; -} - -// Parse SoundTrack from MIDI file -bool ParseSoundTrack(FILE *file, SoundTrack *track) { - // Read the file tag - char trackTag[5] = {0}; - fread(trackTag, 1, 4, file); - - if (strcmp(trackTag, "MTrk") != 0) { - char errMsg[256]; - sprintf(errMsg, "Invalid MIDI sound track header: expected 'MTrk', got '%.4s'", trackTag); - MessageBox(NULL, errMsg, "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Read track chunk size - track->size = ReadMidiInt(file, true); - long startPos = ftell(file); - - // Initialize control change count - track->controlChangeCount = 0; - - // 1. TrackName event - track->deltaTimeTrackName = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for TrackName", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseTrackNameEvent(file, &track->trackName)) return false; - - // 2. ControlChange events (1 or 2) - unsigned char nextByte; - int currentChannelNumber = -1; // For running status - - // Peek at the next byte to determine event type - long peekPos = ftell(file); - track->deltaTimeControlChanges[0] = ReadMidiVarInt(file); - nextByte = fgetc(file); - fseek(file, peekPos, SEEK_SET); // Go back to where we were - - // Check for control change events (0xBn) - while (((nextByte >> 4) == 0xB || currentChannelNumber != -1) && - track->controlChangeCount < MAX_CONTROL_CHANGES) { - - // Read the delta time - track->deltaTimeControlChanges[track->controlChangeCount] = ReadMidiVarInt(file); - - // Parse the control change event - if (!ParseControlChangeEvent(file, &track->controlChanges[track->controlChangeCount], ¤tChannelNumber)) { - return false; - } - - track->controlChangeCount++; - - // Peek at the next byte to determine if there's another control change - if (track->controlChangeCount < MAX_CONTROL_CHANGES) { - peekPos = ftell(file); - int testDeltaTime = ReadMidiVarInt(file); - nextByte = fgetc(file); - fseek(file, peekPos, SEEK_SET); // Go back to where we were - - // If next byte is not a control change and not a running status, break - if ((nextByte >> 4) != 0xB && (nextByte & 0x80) != 0) { - currentChannelNumber = -1; // Reset running status - break; - } - } - } - - // 3. ProgramChange event - track->deltaTimeProgramChange = ReadMidiVarInt(file); - if (!ParseProgramChangeEvent(file, &track->programChange, NULL)) return false; - - // 4. NoteOn event - track->deltaTimeNoteOn = ReadMidiVarInt(file); - if (!ParseNoteOnEvent(file, &track->noteOn, NULL)) return false; - - // 5. NoteOff event - track->deltaTimeNoteOff = ReadMidiVarInt(file); - if (!ParseNoteOffEvent(file, &track->noteOff, NULL)) return false; - - // 6. EndOfTrack event - track->deltaTimeEndOfTrack = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for EndOfTrack", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseEndOfTrackEvent(file)) return false; - - // Ensure we've read exactly the size of the track - long currentPos = ftell(file); - if (currentPos != startPos + track->size) { - MessageBox(NULL, "Sound track size mismatch", "Error", MB_OK | MB_ICONERROR); - return false; - } - - return true; -} - -bool ParseMidi(FILE *file, MidiData *midi) { - // Read header size - unsigned char sizeBytes[4]; - fread(sizeBytes, 1, 4, file); - - // Values for MIDI header should be big-endian (MSB first) - int headerSize = (sizeBytes[0] << 24) | (sizeBytes[1] << 16) | (sizeBytes[2] << 8) | sizeBytes[3]; - - // The header size should be 6 for standard MIDI files - if (headerSize != 6) { - MessageBox(NULL, "Invalid MIDI header size", "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Read format, track count, and division - unsigned char formatBytes[2], trackCountBytes[2], divisionBytes[2]; - - fread(formatBytes, 1, 2, file); - fread(trackCountBytes, 1, 2, file); - fread(divisionBytes, 1, 2, file); - - // Interpret as big-endian values - midi->format = (formatBytes[0] << 8) | formatBytes[1]; - midi->trackCount = (trackCountBytes[0] << 8) | trackCountBytes[1]; - midi->ticksPerQuarterNote = (divisionBytes[0] << 8) | divisionBytes[1]; - - if (midi->format != 1) { - MessageBox(NULL, "Unsupported MIDI format", "Error", MB_OK | MB_ICONERROR); - return false; - } - - if (midi->trackCount < 2 || midi->trackCount > (MAX_SOUND_TRACKS + 1)) { - MessageBox(NULL, "Invalid MIDI track count", "Error", MB_OK | MB_ICONERROR); - return false; - } - - if ((midi->ticksPerQuarterNote & 0x8000) != 0) { - MessageBox(NULL, "Unsupported MIDI time division format", "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Parse InfoTrack (first track) - if (!ParseInfoTrack(file, &midi->infoTrack)) { - return false; - } - - // Set seconds per quarter note from the tempo in the InfoTrack - midi->secondsPerQuarterNote = midi->infoTrack.setTempo.microsecondsPerQuarterNote / 1000000.0f; - - // Parse SoundTracks - int soundTrackCount = midi->trackCount - 1; // First track is InfoTrack - - for (int i = 0; i < soundTrackCount && i < MAX_SOUND_TRACKS; i++) { - if (!ParseSoundTrack(file, &midi->soundTracks[i])) { - return false; - } - } - - return true; -} - -// Load AMB file -bool LoadAmbFile(const Path filePath, AmbFile * out) { - FILE *file = fopen(filePath, "rb"); - if (!file) { - MessageBox(NULL, "Failed to open AMB file", "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Initialize AMB file structure - memset(out, 0, sizeof *out); - strcpy(out->filePath, filePath); - - // Parse all chunks - bool success = true; - while (!feof(file)) { - char tag[5] = {0}; - if (fread(tag, 1, 4, file) != 4) { - break; // End of file - } - - if (strcmp(tag, "prgm") == 0) { - if (out->prgmChunkCount < MAX_CHUNKS) { - if (!ParsePrgmChunk(file, &out->prgmChunks[out->prgmChunkCount++])) { - success = false; - break; - } - } else { - MessageBox(NULL, "Too many Prgm chunks", "Error", MB_OK | MB_ICONERROR); - success = false; - break; - } - } else if (strcmp(tag, "kmap") == 0) { - if (out->kmapChunkCount < MAX_CHUNKS) { - if (!ParseKmapChunk(file, &out->kmapChunks[out->kmapChunkCount++])) { - success = false; - break; - } - } else { - MessageBox(NULL, "Too many Kmap chunks", "Error", MB_OK | MB_ICONERROR); - success = false; - break; - } - } else if (strcmp(tag, "glbl") == 0) { - if (!out->hasGlblChunk) { - if (!ParseGlblChunk(file, &out->glblChunk)) { - success = false; - break; - } - out->hasGlblChunk = true; - } else { - MessageBox(NULL, "Multiple Glbl chunks not supported", "Error", MB_OK | MB_ICONERROR); - success = false; - break; - } - } else if (strcmp(tag, "MThd") == 0) { - // MIDI header detected, parse the MIDI data - // Don't need to go back, ParseMidi now expects to be positioned after the tag - if (!ParseMidi(file, &out->midi)) { - success = false; - break; - } - } else { - char message[256]; - sprintf(message, "Unknown chunk tag: %s", tag); - MessageBox(NULL, message, "Error", MB_OK | MB_ICONERROR); - success = false; - break; - } - } - - fclose(file); - - return success; -} - -int ComputePrgmChunkSize(PrgmChunk const * chunk) { - // size = 28 bytes for 7 4-byte ints + 2 null terminators + lengths of the two strings - // All Prgm chunks in the AMBs that ship with Civ 3 are confirmed to follow this rule - return 30 + strlen(chunk->effectName) + strlen(chunk->varName); -} - -// Functions to write AMB file chunks -bool WritePrgmChunk(FILE *file, PrgmChunk const * chunk) { - // Write tag - fwrite("prgm", 1, 4, file); - - // Write chunk data - WriteAmbInt(file, chunk->size, true); - WriteAmbInt(file, chunk->number, true); - WriteAmbInt(file, chunk->flags, false); - WriteAmbInt(file, chunk->maxRandomSpeed, false); - WriteAmbInt(file, chunk->minRandomSpeed, false); - WriteAmbInt(file, chunk->maxRandomVolume, false); - WriteAmbInt(file, chunk->minRandomVolume, false); - - // Write end marker before strings - WriteAmbInt(file, 0xFA, true); - - // Write strings - WriteString(file, chunk->effectName); - WriteString(file, chunk->varName); - - return true; -} - -int ComputeKmapChunkSize(KmapChunk const * chunk) { - // size w/o items = 20 bytes for 5 4-byte ints + length of var name + null terminator + end indicator - int size = 25 + strlen(chunk->varName); - for (int i = 0; i < chunk->itemCount; i++) - // size of each item = 12 bytes unknown data + length of wav file name + null terminator - size += 12 + strlen(chunk->items[i].wavFileName) + 1; - // This rule matches the size of all Kmap chunks in the Civ 3 AMBs except two, both in GalleyAttack.amb. Those chunks are broken, however, and - // don't play any sound. - return size; -} - -bool WriteKmapChunk(FILE *file, KmapChunk const * chunk) { - // Write tag - fwrite("kmap", 1, 4, file); - - // Write chunk data - WriteAmbInt(file, chunk->size, true); - WriteAmbInt(file, chunk->flags, true); - WriteAmbInt(file, chunk->param1, true); - WriteAmbInt(file, chunk->param2, true); - - // Write variable name - WriteString(file, chunk->varName); - - // Write item count - WriteAmbInt(file, chunk->itemCount, true); - - // Write item size if needed - if ((chunk->flags & 6) != 0) { - WriteAmbInt(file, chunk->itemSize, true); - } - - // Write items - for (int i = 0; i < chunk->itemCount && i < MAX_ITEMS; i++) { - if ((chunk->flags & 6) == 0) { - // Not used in Civ3, but we should still write placeholder data - WriteAmbInt(file, 0, true); // Placeholder for aint1 - WriteAmbInt(file, 0, true); // Placeholder for aint2 - } else { - // Write the data block - fwrite(chunk->items[i].data, 1, chunk->itemSize, file); - } - - // Write WAV filename - WriteString(file, chunk->items[i].wavFileName); - } - - // Write end marker - WriteAmbInt(file, 0xFA, true); - - return true; -} - -bool WriteGlblChunk(FILE *file, GlblChunk const * chunk) { - // Write tag - fwrite("glbl", 1, 4, file); - - // Write chunk size - WriteAmbInt(file, chunk->size, true); - - // Write data size - WriteAmbInt(file, chunk->dataSize, true); - - // Write data - fwrite(chunk->data, 1, chunk->dataSize, file); - - // Write extra data if present - if (chunk->extraDataSize > 0) { - fwrite(chunk->extraData, 1, chunk->extraDataSize, file); - } - - return true; -} - -// Function to write TrackName event to MIDI file -void WriteTrackNameEvent(FILE *file, const TrackNameEvent *event) { - fputc(0x03, file); // Track name meta event type - - // Length of the name - WriteMidiVarInt(file, strlen(event->name)); - - // Name data - fwrite(event->name, 1, strlen(event->name), file); -} - -// Function to write SMPTEOffset event to MIDI file -void WriteSMPTEOffsetEvent(FILE *file, const SMPTEOffsetEvent *event) { - fputc(0x54, file); // SMPTE offset meta event type - fputc(0x05, file); // Length is always 5 - - // SMPTE data - fputc(event->hr, file); - fputc(event->mn, file); - fputc(event->se, file); - fputc(event->fr, file); - fputc(event->ff, file); -} - -// Function to write TimeSignature event to MIDI file -void WriteTimeSignatureEvent(FILE *file, const TimeSignatureEvent *event) { - fputc(0x58, file); // Time signature meta event type - fputc(0x04, file); // Length is always 4 - - // Time signature data - fputc(event->nn, file); - fputc(event->dd, file); - fputc(event->cc, file); - fputc(event->bb, file); -} - -// Function to write SetTempo event to MIDI file -void WriteSetTempoEvent(FILE *file, const SetTempoEvent *event) { - fputc(0x51, file); // Set tempo meta event type - fputc(0x03, file); // Length is always 3 - - // Tempo data (microseconds per quarter note) - unsigned int tempo = event->microsecondsPerQuarterNote; - fputc((tempo >> 16) & 0xFF, file); - fputc((tempo >> 8) & 0xFF, file); - fputc(tempo & 0xFF, file); -} - -// Function to write EndOfTrack event to MIDI file -void WriteEndOfTrackEvent(FILE *file) { - fputc(0x2F, file); // End of track meta event type - fputc(0x00, file); // Length is always 0 -} - -// Function to write ControlChange event to MIDI file -void WriteControlChangeEvent(FILE *file, const ControlChangeEvent *event) { - // Control change status byte: 0xBn, where n is the channel number - fputc(0xB0 | (event->channelNumber & 0x0F), file); - - // Controller number and value - fputc(event->controllerNumber & 0x7F, file); - fputc(event->value & 0x7F, file); -} - -// Function to write ProgramChange event to MIDI file -void WriteProgramChangeEvent(FILE *file, const ProgramChangeEvent *event) { - // Program change status byte: 0xCn, where n is the channel number - fputc(0xC0 | (event->channelNumber & 0x0F), file); - - // Program number - fputc(event->programNumber & 0x7F, file); -} - -// Function to write NoteOn event to MIDI file -void WriteNoteOnEvent(FILE *file, const NoteOnEvent *event) { - // Note on status byte: 0x9n, where n is the channel number - fputc(0x90 | (event->channelNumber & 0x0F), file); - - // Key and velocity - fputc(event->key & 0x7F, file); - fputc(event->velocity & 0x7F, file); -} - -// Function to write NoteOff event to MIDI file -void WriteNoteOffEvent(FILE *file, const NoteOffEvent *event) { - // Note off status byte: 0x8n, where n is the channel number - fputc(0x80 | (event->channelNumber & 0x0F), file); - - // Key and velocity - fputc(event->key & 0x7F, file); - fputc(event->velocity & 0x7F, file); -} - -// Function to write InfoTrack to MIDI file -void WriteInfoTrack(FILE *file, const InfoTrack *track) { - // Write track tag - fwrite("MTrk", 1, 4, file); - - // We need to calculate track size, so we'll save the current position, - // write a placeholder, write the events, then come back and update it - long sizePos = ftell(file); - - // Write placeholder for size - WriteMidiInt(file, 0, true); - - // Save position at start of track data - long startPos = ftell(file); - - // Write all events in sequence - - // 1. TrackName event - WriteMidiVarInt(file, track->deltaTimeTrackName); - fputc(0xFF, file); // Meta event marker - WriteTrackNameEvent(file, &track->trackName); - - // 2. SMPTEOffset event - WriteMidiVarInt(file, track->deltaTimeSMPTEOffset); - fputc(0xFF, file); // Meta event marker - WriteSMPTEOffsetEvent(file, &track->smpteOffset); - - // 3. TimeSignature event - WriteMidiVarInt(file, track->deltaTimeTimeSignature); - fputc(0xFF, file); // Meta event marker - WriteTimeSignatureEvent(file, &track->timeSignature); - - // 4. SetTempo event - WriteMidiVarInt(file, track->deltaTimeSetTempo); - fputc(0xFF, file); // Meta event marker - WriteSetTempoEvent(file, &track->setTempo); - - // 5. EndOfTrack event - WriteMidiVarInt(file, track->deltaTimeEndOfTrack); - fputc(0xFF, file); // Meta event marker - WriteEndOfTrackEvent(file); - - // Get end position and calculate size - long endPos = ftell(file); - unsigned int trackSize = (unsigned int)(endPos - startPos); - - // Go back and write the actual size - fseek(file, sizePos, SEEK_SET); - WriteMidiInt(file, trackSize, true); - - // Return to the end of the track - fseek(file, endPos, SEEK_SET); -} - -// Function to write SoundTrack to MIDI file -unsigned int WriteSoundTrack(FILE *file, const SoundTrack *track) { - // Write track tag - fwrite("MTrk", 1, 4, file); - - // We need to calculate track size, so we'll save the current position, - // write a placeholder, write the events, then come back and update it - long sizePos = ftell(file); - - // Write placeholder for size - WriteMidiInt(file, 0, true); - - // Save position at start of track data - long startPos = ftell(file); - - // Write all events in sequence - - // 1. TrackName event - WriteMidiVarInt(file, track->deltaTimeTrackName); - fputc(0xFF, file); // Meta event marker - WriteTrackNameEvent(file, &track->trackName); - - // 2. ControlChange events (1 or 2) - for (int i = 0; i < track->controlChangeCount; i++) { - WriteMidiVarInt(file, track->deltaTimeControlChanges[i]); - WriteControlChangeEvent(file, &track->controlChanges[i]); - } - - // 3. ProgramChange event - WriteMidiVarInt(file, track->deltaTimeProgramChange); - WriteProgramChangeEvent(file, &track->programChange); - - // 4. NoteOn event - WriteMidiVarInt(file, track->deltaTimeNoteOn); - WriteNoteOnEvent(file, &track->noteOn); - - // 5. NoteOff event - WriteMidiVarInt(file, track->deltaTimeNoteOff); - WriteNoteOffEvent(file, &track->noteOff); - - // 6. EndOfTrack event - WriteMidiVarInt(file, track->deltaTimeEndOfTrack); - fputc(0xFF, file); // Meta event marker - WriteEndOfTrackEvent(file); - - // Get end position and calculate size - long endPos = ftell(file); - unsigned int trackSize = (unsigned int)(endPos - startPos); - - // Go back and write the actual size - fseek(file, sizePos, SEEK_SET); - WriteMidiInt(file, trackSize, true); - - // Return to the end of the track - fseek(file, endPos, SEEK_SET); - - return trackSize; -} - -int ComputeSoundTrackSize(SoundTrack const * track) { - FILE *memFile = tmpfile(); - unsigned int size = WriteSoundTrack(memFile, track); - fclose(memFile); - return size; -} - -bool WriteMidi(FILE *file, MidiData const * midi) { - // Write MIDI header - fwrite("MThd", 1, 4, file); - - // Header size is always 6 - WriteMidiInt(file, 6, true); - - // Write format, track count, and division - WriteMidiShort(file, midi->format, false); - WriteMidiShort(file, midi->trackCount, false); - WriteMidiShort(file, midi->ticksPerQuarterNote, false); - - // Write InfoTrack - WriteInfoTrack(file, &midi->infoTrack); - - // Write SoundTracks - int soundTrackCount = midi->trackCount - 1; // First track is InfoTrack - - for (int i = 0; i < soundTrackCount && i < MAX_SOUND_TRACKS; i++) { - WriteSoundTrack(file, &midi->soundTracks[i]); - } - - return true; -} - -// Function to save AMB file to the specified path -bool SaveAmbFile(AmbFile const * amb, const Path filePath) { - FILE *file = fopen(filePath, "wb"); - if (!file) { - return false; - } - - bool success = true; - - // Write Prgm chunks - for (int i = 0; i < amb->prgmChunkCount; i++) { - if (!WritePrgmChunk(file, &amb->prgmChunks[i])) { - success = false; - break; - } - } - - // Write Kmap chunks - if (success) { - for (int i = 0; i < amb->kmapChunkCount; i++) { - if (!WriteKmapChunk(file, &amb->kmapChunks[i])) { - success = false; - break; - } - } - } - - // Write Glbl chunk if present - if (success && amb->hasGlblChunk) { - if (!WriteGlblChunk(file, &amb->glblChunk)) { - success = false; - } - } - - // Write MIDI data - if (success) { - if (!WriteMidi(file, &amb->midi)) { - success = false; - } - } - - fclose(file); - - // Remove the file if we failed - if (!success) { - remove(filePath); - } - - return success; -} - -// Utility function to get sound track count -int GetSoundTrackCount(const MidiData *midi) { - return midi->trackCount - 1; // First track is InfoTrack -} - -// Function to describe the loaded AMB file (for debugging) -void DescribeAmbFile(AmbFile const * amb, char *buffer, size_t bufferSize) { - char *pos = buffer; - int remainingSize = (int)bufferSize; - - // Describe file path - int written = snprintf(pos, remainingSize, "File: %s\r\n\r\n", amb->filePath); - pos += written; - remainingSize -= written; - - // Describe Prgm chunks - for (int i = 0; i < amb->prgmChunkCount && remainingSize > 0; i++) { - PrgmChunk *chunk = &amb->prgmChunks[i]; - written = snprintf(pos, remainingSize, - "Prgm #%d:\r\n" - " Size: %d\r\n" - " Number: %d\r\n" - " Flags: %d\r\n" - " Max Random Speed: %d\r\n" - " Min Random Speed: %d\r\n" - " Max Random Volume: %d\r\n" - " Min Random Volume: %d\r\n" - " Effect Name: '%s'\r\n" - " Var Name: '%s'\r\n\r\n", - i + 1, chunk->size, chunk->number, chunk->flags, - chunk->maxRandomSpeed, chunk->minRandomSpeed, - chunk->maxRandomVolume, chunk->minRandomVolume, - chunk->effectName, chunk->varName); - pos += written; - remainingSize -= written; - } - - // Describe Kmap chunks - for (int i = 0; i < amb->kmapChunkCount && remainingSize > 0; i++) { - KmapChunk *chunk = &amb->kmapChunks[i]; - written = snprintf(pos, remainingSize, - "Kmap #%d:\r\n" - " Size: %d\r\n" - " Flags: %d\r\n" - " Param1: %d\r\n" - " Param2: %d\r\n" - " Var Name: '%s'\r\n" - " Item Count: %d\r\n" - " Item Size: %d\r\n", - i + 1, chunk->size, chunk->flags, - chunk->param1, chunk->param2, - chunk->varName, chunk->itemCount, chunk->itemSize); - pos += written; - remainingSize -= written; - - // Describe Kmap items - for (int j = 0; j < chunk->itemCount && remainingSize > 0; j++) { - written = snprintf(pos, remainingSize, - " Item #%d: WAV File: '%s'\r\n", - j + 1, chunk->items[j].wavFileName); - pos += written; - remainingSize -= written; - } - - written = snprintf(pos, remainingSize, "\r\n"); - pos += written; - remainingSize -= written; - } - - // Describe Glbl chunk - if (amb->hasGlblChunk && remainingSize > 0) { - GlblChunk const * chunk = &amb->glblChunk; - written = snprintf(pos, remainingSize, - "Glbl:\r\n" - " Size: %d\r\n" - " Data Size: %d\r\n\r\n", - chunk->size, chunk->dataSize); - pos += written; - remainingSize -= written; - } - - // Describe MIDI data - if (remainingSize > 0) { - written = snprintf(pos, remainingSize, - "MIDI:\r\n" - " Format: %d\r\n" - " Track Count: %d\r\n" - " Ticks Per Quarter Note: %d\r\n" - " Seconds Per Quarter Note: %.6f\r\n\r\n", - amb->midi.format, amb->midi.trackCount, - amb->midi.ticksPerQuarterNote, amb->midi.secondsPerQuarterNote); - pos += written; - remainingSize -= written; - - // Describe InfoTrack - if (remainingSize > 0) { - InfoTrack const *infoTrack = &amb->midi.infoTrack; - float secondsPerTick = amb->midi.secondsPerQuarterNote / amb->midi.ticksPerQuarterNote; - float timestamp = 0.0f; - - written = snprintf(pos, remainingSize, - " InfoTrack:\r\n" - " Size: %d\r\n", - infoTrack->size); - pos += written; - remainingSize -= written; - - // Track name event - timestamp += infoTrack->deltaTimeTrackName * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: TrackName '%s'\r\n", - timestamp, infoTrack->trackName.name); - pos += written; - remainingSize -= written; - - // SMPTE offset event - timestamp += infoTrack->deltaTimeSMPTEOffset * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: SMPTEOffset %d %d %d %d %d\r\n", - timestamp, infoTrack->smpteOffset.hr, - infoTrack->smpteOffset.mn, - infoTrack->smpteOffset.se, - infoTrack->smpteOffset.fr, - infoTrack->smpteOffset.ff); - pos += written; - remainingSize -= written; - - // Time signature event - timestamp += infoTrack->deltaTimeTimeSignature * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: TimeSignature %d %d %d %d\r\n", - timestamp, infoTrack->timeSignature.nn, - infoTrack->timeSignature.dd, - infoTrack->timeSignature.cc, - infoTrack->timeSignature.bb); - pos += written; - remainingSize -= written; - - // Set tempo event - timestamp += infoTrack->deltaTimeSetTempo * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: SetTempo %d\r\n", - timestamp, infoTrack->setTempo.microsecondsPerQuarterNote); - pos += written; - remainingSize -= written; - - // End of track event - timestamp += infoTrack->deltaTimeEndOfTrack * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: EndOfTrack\r\n\r\n", - timestamp); - pos += written; - remainingSize -= written; - } - - // Describe each SoundTrack - int soundTrackCount = GetSoundTrackCount(&amb->midi); - for (int i = 0; i < soundTrackCount && remainingSize > 0; i++) { - SoundTrack const *soundTrack = &amb->midi.soundTracks[i]; - float secondsPerTick = amb->midi.secondsPerQuarterNote / amb->midi.ticksPerQuarterNote; - float timestamp = 0.0f; - - written = snprintf(pos, remainingSize, - " SoundTrack #%d:\r\n" - " Size: %d\r\n", - i + 1, soundTrack->size); - pos += written; - remainingSize -= written; - - // Track name event - timestamp += soundTrack->deltaTimeTrackName * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: TrackName '%s'\r\n", - timestamp, soundTrack->trackName.name); - pos += written; - remainingSize -= written; - - // Control change events - for (int j = 0; j < soundTrack->controlChangeCount && remainingSize > 0; j++) { - timestamp += soundTrack->deltaTimeControlChanges[j] * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: ControlChange %d %d %d\r\n", - timestamp, soundTrack->controlChanges[j].channelNumber, - soundTrack->controlChanges[j].controllerNumber, - soundTrack->controlChanges[j].value); - pos += written; - remainingSize -= written; - } - - // Program change event - timestamp += soundTrack->deltaTimeProgramChange * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: ProgramChange %d %d\r\n", - timestamp, soundTrack->programChange.channelNumber, - soundTrack->programChange.programNumber); - pos += written; - remainingSize -= written; - - // Note on event - timestamp += soundTrack->deltaTimeNoteOn * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: NoteOn %d %d %d\r\n", - timestamp, soundTrack->noteOn.channelNumber, - soundTrack->noteOn.key, - soundTrack->noteOn.velocity); - pos += written; - remainingSize -= written; - - // Note off event - timestamp += soundTrack->deltaTimeNoteOff * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: NoteOff %d %d %d\r\n", - timestamp, soundTrack->noteOff.channelNumber, - soundTrack->noteOff.key, - soundTrack->noteOff.velocity); - pos += written; - remainingSize -= written; - - // End of track event - timestamp += soundTrack->deltaTimeEndOfTrack * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: EndOfTrack\r\n\r\n", - timestamp); - pos += written; - remainingSize -= written; - } - } -} +// This file gets #included into amb_editor.c + +#include +#include +#include +#include +#include + +#define MAX_CHUNKS 30 // No AMB in Civ 3 has more than 12 Kmap or Prgm chunks +#define MAX_SOUND_TRACKS 30 // No AMB in Civ 3 has more than 12 sound tracks +#define MAX_CONTROL_CHANGES 2 // No AMB in Civ 3 has more than 2 control changes per track +#define MAX_ITEMS 2 // No AMB in Civ 3 has more than 1 item + +// AMB file structures for Civ 3 +typedef struct { + int size; + int number; + int flags; + int maxRandomSpeed; + int minRandomSpeed; + int maxRandomVolume; + int minRandomVolume; + char effectName[256]; + char varName[256]; +} PrgmChunk; + +typedef struct { + unsigned char data[12]; + char wavFileName[256]; +} KmapItem; + +typedef struct { + int size; + int flags; + int param1; + int param2; + char varName[256]; + int itemCount; + int itemSize; + KmapItem items[MAX_ITEMS]; +} KmapChunk; + +typedef struct { + int size; + int dataSize; + unsigned char data[12]; + unsigned char extraData[512]; + int extraDataSize; +} GlblChunk; + +// MIDI event types - specific to Civ3 AMB files +typedef struct { + char name[256]; // Always "Seq-1" in Civ3 AMBs +} TrackNameEvent; + +typedef struct { + int hr, mn, se, fr, ff; +} SMPTEOffsetEvent; + +typedef struct { + int nn, dd, cc, bb; +} TimeSignatureEvent; + +typedef struct { + int microsecondsPerQuarterNote; +} SetTempoEvent; + +typedef struct { + int channelNumber, controllerNumber, value; +} ControlChangeEvent; + +typedef struct { + int channelNumber, programNumber; +} ProgramChangeEvent; + +typedef struct { + int channelNumber, key, velocity; +} NoteOffEvent; + +typedef struct { + int channelNumber, key, velocity; +} NoteOnEvent; + +// Specific track structures for Civ3 AMB files +typedef struct { + int size; + int deltaTimeTrackName; + TrackNameEvent trackName; + int deltaTimeSMPTEOffset; + SMPTEOffsetEvent smpteOffset; + int deltaTimeTimeSignature; + TimeSignatureEvent timeSignature; + int deltaTimeSetTempo; + SetTempoEvent setTempo; + int deltaTimeEndOfTrack; +} InfoTrack; + +typedef struct { + int size; + int deltaTimeTrackName; + TrackNameEvent trackName; + int controlChangeCount; + int deltaTimeControlChanges[MAX_CONTROL_CHANGES]; + ControlChangeEvent controlChanges[MAX_CONTROL_CHANGES]; + int deltaTimeProgramChange; + ProgramChangeEvent programChange; + int deltaTimeNoteOn; + NoteOnEvent noteOn; + int deltaTimeNoteOff; + NoteOffEvent noteOff; + int deltaTimeEndOfTrack; +} SoundTrack; + +typedef struct { + short format; + short trackCount; + short ticksPerQuarterNote; + float secondsPerQuarterNote; + InfoTrack infoTrack; + SoundTrack soundTracks[MAX_SOUND_TRACKS]; +} MidiData; + +typedef struct { + Path filePath; + + // Chunks + PrgmChunk prgmChunks[MAX_CHUNKS]; + int prgmChunkCount; + + KmapChunk kmapChunks[MAX_CHUNKS]; + int kmapChunkCount; + + GlblChunk glblChunk; + bool hasGlblChunk; + + MidiData midi; +} AmbFile; + +// Helper functions for file parsing and writing +unsigned int ReadAmbInt(FILE *file, bool isUnsigned) { + unsigned char buffer[4]; + fread(buffer, 1, 4, file); + + // Little endian + unsigned int result = + (buffer[0]) | + (buffer[1] << 8) | + (buffer[2] << 16) | + (buffer[3] << 24); + + if (!isUnsigned && (result & 0x80000000)) { + // Convert to signed if needed + return (int)result; + } + + return result; +} + +// Helper functions for file writing +void WriteAmbInt(FILE *file, unsigned int value, bool isUnsigned) { + unsigned char buffer[4]; + + // Little endian + buffer[0] = value & 0xFF; + buffer[1] = (value >> 8) & 0xFF; + buffer[2] = (value >> 16) & 0xFF; + buffer[3] = (value >> 24) & 0xFF; + + fwrite(buffer, 1, 4, file); +} + +void WriteMidiInt(FILE *file, unsigned int value, bool isUnsigned) { + unsigned char buffer[4]; + + // Big endian + buffer[0] = (value >> 24) & 0xFF; + buffer[1] = (value >> 16) & 0xFF; + buffer[2] = (value >> 8) & 0xFF; + buffer[3] = value & 0xFF; + + fwrite(buffer, 1, 4, file); +} + +void WriteMidiShort(FILE *file, unsigned short value, bool isUnsigned) { + unsigned char buffer[2]; + + // Big endian + buffer[0] = (value >> 8) & 0xFF; + buffer[1] = value & 0xFF; + + fwrite(buffer, 1, 2, file); +} + +void WriteMidiVarInt(FILE *file, unsigned int value) { + unsigned char buffer[4]; + int numBytes = 0; + + // Build the bytes from least significant to most significant + do { + buffer[numBytes++] = (value & 0x7F) | (numBytes > 0 ? 0x80 : 0); + value >>= 7; + } while (value > 0 && numBytes < 4); + + // Write the bytes in reverse order + for (int i = numBytes - 1; i >= 0; i--) { + // Clear the continuation bit for the last byte + if (i == 0) { + buffer[i] &= 0x7F; + } + fwrite(&buffer[i], 1, 1, file); + } +} + +void WriteString(FILE *file, const char *str) { + // Write null-terminated string + fwrite(str, 1, strlen(str) + 1, file); +} + +unsigned int ReadMidiInt(FILE *file, bool isUnsigned) { + unsigned char buffer[4]; + fread(buffer, 1, 4, file); + + // Big endian + unsigned int result = + (buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + (buffer[3]); + + if (!isUnsigned && (result & 0x80000000)) { + // Convert to signed if needed + return (int)result; + } + + return result; +} + +unsigned short ReadMidiShort(FILE *file, bool isUnsigned) { + unsigned char buffer[2]; + fread(buffer, 1, 2, file); + + // Big endian + unsigned short result = (buffer[0] << 8) | buffer[1]; + + if (!isUnsigned && (result & 0x8000)) { + // Convert to signed if needed + return (short)result; + } + + return result; +} + +unsigned int ReadMidiVarInt(FILE *file) { + unsigned int result = 0; + unsigned char byte; + + do { + fread(&byte, 1, 1, file); + result = (result << 7) | (byte & 0x7F); + } while (byte & 0x80); + + return result; +} + +void ReadString(FILE *file, char *buffer, int maxLength) { + int i = 0; + char byte; + + while (i < maxLength - 1) { + fread(&byte, 1, 1, file); + if (byte == 0) { + break; + } + buffer[i++] = byte; + } + + buffer[i] = '\0'; +} + +// Parse AMB file chunks +bool ParsePrgmChunk(FILE *file, PrgmChunk *chunk) { + chunk->size = ReadAmbInt(file, true); + chunk->number = ReadAmbInt(file, true); + chunk->flags = ReadAmbInt(file, false); + chunk->maxRandomSpeed = ReadAmbInt(file, false); + chunk->minRandomSpeed = ReadAmbInt(file, false); + chunk->maxRandomVolume = ReadAmbInt(file, false); + chunk->minRandomVolume = ReadAmbInt(file, false); + + // Read end marker + unsigned int endMarker = ReadAmbInt(file, true); + if (endMarker != 0xFA) { + MessageBox(NULL, "Expected 0xFA marker before strings in Prgm chunk", "Error", MB_OK | MB_ICONERROR); + return false; + } + + ReadString(file, chunk->effectName, sizeof(chunk->effectName)); + ReadString(file, chunk->varName, sizeof(chunk->varName)); + + return true; +} + +bool ParseKmapChunk(FILE *file, KmapChunk *chunk) { + chunk->size = ReadAmbInt(file, true); + chunk->flags = ReadAmbInt(file, true); + chunk->param1 = ReadAmbInt(file, true); + chunk->param2 = ReadAmbInt(file, true); + + ReadString(file, chunk->varName, sizeof(chunk->varName)); + + chunk->itemCount = ReadAmbInt(file, true); + + if ((chunk->flags & 6) != 0) { + chunk->itemSize = ReadAmbInt(file, true); + } else { + chunk->itemSize = 0; + } + + // Read items + for (int i = 0; i < chunk->itemCount && i < MAX_ITEMS; i++) { + if ((chunk->flags & 6) == 0) { + // Not used in Civ3 + int aint1 = ReadAmbInt(file, true); + int aint2 = ReadAmbInt(file, true); + } else { + // Read the 12-byte data block + fread(chunk->items[i].data, 1, chunk->itemSize, file); + } + + ReadString(file, chunk->items[i].wavFileName, sizeof(chunk->items[i].wavFileName)); + } + + // Read end marker + unsigned int endMarker = ReadAmbInt(file, true); + if (endMarker != 0xFA) { + MessageBox(NULL, "Expected 0xFA marker at end of Kmap chunk", "Error", MB_OK | MB_ICONERROR); + return false; + } + + return true; +} + +bool ParseGlblChunk(FILE *file, GlblChunk *chunk) { + chunk->size = ReadAmbInt(file, true); + long startPos = ftell(file); + + chunk->dataSize = ReadAmbInt(file, true); + fread(chunk->data, 1, chunk->dataSize, file); + + // Read any extra data + long currentPos = ftell(file); + long remainingSize = chunk->size - (currentPos - startPos); + + if (remainingSize > 0 && remainingSize < sizeof(chunk->extraData)) { + fread(chunk->extraData, 1, remainingSize, file); + chunk->extraDataSize = (int)remainingSize; + } else { + chunk->extraDataSize = 0; + } + + return true; +} + +// Parse TrackName event from MIDI file +bool ParseTrackNameEvent(FILE *file, TrackNameEvent *event) { + unsigned char metaType; + fread(&metaType, 1, 1, file); + + if (metaType != 0x03) { + MessageBox(NULL, "Expected TrackName event (0x03)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned int length = ReadMidiVarInt(file); + memset(event->name, 0, sizeof(event->name)); + fread(event->name, 1, length < sizeof(event->name) ? length : sizeof(event->name) - 1, file); + + return true; +} + +// Parse SMPTEOffset event from MIDI file +bool ParseSMPTEOffsetEvent(FILE *file, SMPTEOffsetEvent *event) { + unsigned char metaType; + fread(&metaType, 1, 1, file); + + if (metaType != 0x54) { + MessageBox(NULL, "Expected SMPTEOffset event (0x54)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned char length; + fread(&length, 1, 1, file); + + if (length != 5) { + MessageBox(NULL, "Invalid SMPTEOffset event length (expected 5)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + event->hr = fgetc(file); + event->mn = fgetc(file); + event->se = fgetc(file); + event->fr = fgetc(file); + event->ff = fgetc(file); + + return true; +} + +// Parse TimeSignature event from MIDI file +bool ParseTimeSignatureEvent(FILE *file, TimeSignatureEvent *event) { + unsigned char metaType; + fread(&metaType, 1, 1, file); + + if (metaType != 0x58) { + MessageBox(NULL, "Expected TimeSignature event (0x58)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned char length; + fread(&length, 1, 1, file); + + if (length != 4) { + MessageBox(NULL, "Invalid TimeSignature event length (expected 4)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + event->nn = fgetc(file); + event->dd = fgetc(file); + event->cc = fgetc(file); + event->bb = fgetc(file); + + return true; +} + +// Parse SetTempo event from MIDI file +bool ParseSetTempoEvent(FILE *file, SetTempoEvent *event) { + unsigned char metaType; + fread(&metaType, 1, 1, file); + + if (metaType != 0x51) { + MessageBox(NULL, "Expected SetTempo event (0x51)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned char length; + fread(&length, 1, 1, file); + + if (length != 3) { + MessageBox(NULL, "Invalid SetTempo event length (expected 3)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned char tempo[3]; + fread(tempo, 1, 3, file); + event->microsecondsPerQuarterNote = (tempo[0] << 16) | (tempo[1] << 8) | tempo[2]; + + return true; +} + +// Parse EndOfTrack event from MIDI file +bool ParseEndOfTrackEvent(FILE *file) { + unsigned char metaType; + fread(&metaType, 1, 1, file); + + if (metaType != 0x2F) { + MessageBox(NULL, "Expected EndOfTrack event (0x2F)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned char zero; + fread(&zero, 1, 1, file); // Should be zero + + return true; +} + +// Parse ControlChange event from MIDI file +bool ParseControlChangeEvent(FILE *file, ControlChangeEvent *event, int *channelNumber) { + unsigned char statusByte; + fread(&statusByte, 1, 1, file); + + // Check if the status byte indicates a control change event (0xBn) + if ((statusByte >> 4) != 0xB) { + // If channelNumber pointer is provided, we're expecting running status + if (channelNumber != NULL) { + // Put the byte back for reading data + fseek(file, -1, SEEK_CUR); + event->channelNumber = *channelNumber; + } else { + MessageBox(NULL, "Expected ControlChange event (0xBn)", "Error", MB_OK | MB_ICONERROR); + return false; + } + } else { + event->channelNumber = statusByte & 0x0F; + // Save channel number for possible running status + if (channelNumber != NULL) { + *channelNumber = event->channelNumber; + } + } + + event->controllerNumber = fgetc(file); + event->value = fgetc(file); + + return true; +} + +// Parse ProgramChange event from MIDI file +bool ParseProgramChangeEvent(FILE *file, ProgramChangeEvent *event, int *channelNumber) { + unsigned char statusByte; + fread(&statusByte, 1, 1, file); + + // Check if the status byte indicates a program change event (0xCn) + if ((statusByte >> 4) != 0xC) { + // If channelNumber pointer is provided, we're expecting running status + if (channelNumber != NULL) { + // Put the byte back for reading data + fseek(file, -1, SEEK_CUR); + event->channelNumber = *channelNumber; + } else { + MessageBox(NULL, "Expected ProgramChange event (0xCn)", "Error", MB_OK | MB_ICONERROR); + return false; + } + } else { + event->channelNumber = statusByte & 0x0F; + // Save channel number for possible running status + if (channelNumber != NULL) { + *channelNumber = event->channelNumber; + } + } + + event->programNumber = fgetc(file); + + return true; +} + +// Parse NoteOn event from MIDI file +bool ParseNoteOnEvent(FILE *file, NoteOnEvent *event, int *channelNumber) { + unsigned char statusByte; + fread(&statusByte, 1, 1, file); + + // Check if the status byte indicates a note on event (0x9n) + if ((statusByte >> 4) != 0x9) { + // If channelNumber pointer is provided, we're expecting running status + if (channelNumber != NULL) { + // Put the byte back for reading data + fseek(file, -1, SEEK_CUR); + event->channelNumber = *channelNumber; + } else { + MessageBox(NULL, "Expected NoteOn event (0x9n)", "Error", MB_OK | MB_ICONERROR); + return false; + } + } else { + event->channelNumber = statusByte & 0x0F; + // Save channel number for possible running status + if (channelNumber != NULL) { + *channelNumber = event->channelNumber; + } + } + + event->key = fgetc(file); + event->velocity = fgetc(file); + + return true; +} + +// Parse NoteOff event from MIDI file +bool ParseNoteOffEvent(FILE *file, NoteOffEvent *event, int *channelNumber) { + unsigned char statusByte; + fread(&statusByte, 1, 1, file); + + // Check if the status byte indicates a note off event (0x8n) + if ((statusByte >> 4) != 0x8) { + // Check if it's a note on with velocity 0 (equivalent to note off) + if ((statusByte >> 4) == 0x9) { + event->channelNumber = statusByte & 0x0F; + event->key = fgetc(file); + event->velocity = fgetc(file); + + // Check if velocity is 0 (note off) + if (event->velocity > 0) { + MessageBox(NULL, "Expected NoteOff event but got NoteOn with velocity > 0", "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Save channel number for possible running status + if (channelNumber != NULL) { + *channelNumber = event->channelNumber; + } + + return true; + } + + // If channelNumber pointer is provided, we're expecting running status + if (channelNumber != NULL) { + // Put the byte back for reading data + fseek(file, -1, SEEK_CUR); + event->channelNumber = *channelNumber; + } else { + MessageBox(NULL, "Expected NoteOff event (0x8n)", "Error", MB_OK | MB_ICONERROR); + return false; + } + } else { + event->channelNumber = statusByte & 0x0F; + // Save channel number for possible running status + if (channelNumber != NULL) { + *channelNumber = event->channelNumber; + } + } + + event->key = fgetc(file); + event->velocity = fgetc(file); + + return true; +} + +// Parse InfoTrack from MIDI file +bool ParseInfoTrack(FILE *file, InfoTrack *track) { + // Read the file tag + char trackTag[5] = {0}; + fread(trackTag, 1, 4, file); + + if (strcmp(trackTag, "MTrk") != 0) { + char errMsg[256]; + sprintf(errMsg, "Invalid MIDI info track header: expected 'MTrk', got '%.4s'", trackTag); + MessageBox(NULL, errMsg, "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Read track chunk size + track->size = ReadMidiInt(file, true); + long startPos = ftell(file); + + // Read events in the InfoTrack + + // 1. TrackName event + track->deltaTimeTrackName = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for TrackName", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseTrackNameEvent(file, &track->trackName)) return false; + + // 2. SMPTEOffset event + track->deltaTimeSMPTEOffset = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for SMPTEOffset", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseSMPTEOffsetEvent(file, &track->smpteOffset)) return false; + + // 3. TimeSignature event + track->deltaTimeTimeSignature = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for TimeSignature", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseTimeSignatureEvent(file, &track->timeSignature)) return false; + + // 4. SetTempo event + track->deltaTimeSetTempo = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for SetTempo", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseSetTempoEvent(file, &track->setTempo)) return false; + + // 5. EndOfTrack event + track->deltaTimeEndOfTrack = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for EndOfTrack", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseEndOfTrackEvent(file)) return false; + + // Ensure we've read exactly the size of the track + long currentPos = ftell(file); + if (currentPos != startPos + track->size) { + MessageBox(NULL, "Info track size mismatch", "Error", MB_OK | MB_ICONERROR); + return false; + } + + return true; +} + +// Parse SoundTrack from MIDI file +bool ParseSoundTrack(FILE *file, SoundTrack *track) { + // Read the file tag + char trackTag[5] = {0}; + fread(trackTag, 1, 4, file); + + if (strcmp(trackTag, "MTrk") != 0) { + char errMsg[256]; + sprintf(errMsg, "Invalid MIDI sound track header: expected 'MTrk', got '%.4s'", trackTag); + MessageBox(NULL, errMsg, "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Read track chunk size + track->size = ReadMidiInt(file, true); + long startPos = ftell(file); + + // Initialize control change count + track->controlChangeCount = 0; + + // 1. TrackName event + track->deltaTimeTrackName = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for TrackName", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseTrackNameEvent(file, &track->trackName)) return false; + + // 2. ControlChange events (1 or 2) + unsigned char nextByte; + int currentChannelNumber = -1; // For running status + + // Peek at the next byte to determine event type + long peekPos = ftell(file); + track->deltaTimeControlChanges[0] = ReadMidiVarInt(file); + nextByte = fgetc(file); + fseek(file, peekPos, SEEK_SET); // Go back to where we were + + // Check for control change events (0xBn) + while (((nextByte >> 4) == 0xB || currentChannelNumber != -1) && + track->controlChangeCount < MAX_CONTROL_CHANGES) { + + // Read the delta time + track->deltaTimeControlChanges[track->controlChangeCount] = ReadMidiVarInt(file); + + // Parse the control change event + if (!ParseControlChangeEvent(file, &track->controlChanges[track->controlChangeCount], ¤tChannelNumber)) { + return false; + } + + track->controlChangeCount++; + + // Peek at the next byte to determine if there's another control change + if (track->controlChangeCount < MAX_CONTROL_CHANGES) { + peekPos = ftell(file); + int testDeltaTime = ReadMidiVarInt(file); + nextByte = fgetc(file); + fseek(file, peekPos, SEEK_SET); // Go back to where we were + + // If next byte is not a control change and not a running status, break + if ((nextByte >> 4) != 0xB && (nextByte & 0x80) != 0) { + currentChannelNumber = -1; // Reset running status + break; + } + } + } + + // 3. ProgramChange event + track->deltaTimeProgramChange = ReadMidiVarInt(file); + if (!ParseProgramChangeEvent(file, &track->programChange, NULL)) return false; + + // 4. NoteOn event + track->deltaTimeNoteOn = ReadMidiVarInt(file); + if (!ParseNoteOnEvent(file, &track->noteOn, NULL)) return false; + + // 5. NoteOff event + track->deltaTimeNoteOff = ReadMidiVarInt(file); + if (!ParseNoteOffEvent(file, &track->noteOff, NULL)) return false; + + // 6. EndOfTrack event + track->deltaTimeEndOfTrack = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for EndOfTrack", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseEndOfTrackEvent(file)) return false; + + // Ensure we've read exactly the size of the track + long currentPos = ftell(file); + if (currentPos != startPos + track->size) { + MessageBox(NULL, "Sound track size mismatch", "Error", MB_OK | MB_ICONERROR); + return false; + } + + return true; +} + +bool ParseMidi(FILE *file, MidiData *midi) { + // Read header size + unsigned char sizeBytes[4]; + fread(sizeBytes, 1, 4, file); + + // Values for MIDI header should be big-endian (MSB first) + int headerSize = (sizeBytes[0] << 24) | (sizeBytes[1] << 16) | (sizeBytes[2] << 8) | sizeBytes[3]; + + // The header size should be 6 for standard MIDI files + if (headerSize != 6) { + MessageBox(NULL, "Invalid MIDI header size", "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Read format, track count, and division + unsigned char formatBytes[2], trackCountBytes[2], divisionBytes[2]; + + fread(formatBytes, 1, 2, file); + fread(trackCountBytes, 1, 2, file); + fread(divisionBytes, 1, 2, file); + + // Interpret as big-endian values + midi->format = (formatBytes[0] << 8) | formatBytes[1]; + midi->trackCount = (trackCountBytes[0] << 8) | trackCountBytes[1]; + midi->ticksPerQuarterNote = (divisionBytes[0] << 8) | divisionBytes[1]; + + if (midi->format != 1) { + MessageBox(NULL, "Unsupported MIDI format", "Error", MB_OK | MB_ICONERROR); + return false; + } + + if (midi->trackCount < 2 || midi->trackCount > (MAX_SOUND_TRACKS + 1)) { + MessageBox(NULL, "Invalid MIDI track count", "Error", MB_OK | MB_ICONERROR); + return false; + } + + if ((midi->ticksPerQuarterNote & 0x8000) != 0) { + MessageBox(NULL, "Unsupported MIDI time division format", "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Parse InfoTrack (first track) + if (!ParseInfoTrack(file, &midi->infoTrack)) { + return false; + } + + // Set seconds per quarter note from the tempo in the InfoTrack + midi->secondsPerQuarterNote = midi->infoTrack.setTempo.microsecondsPerQuarterNote / 1000000.0f; + + // Parse SoundTracks + int soundTrackCount = midi->trackCount - 1; // First track is InfoTrack + + for (int i = 0; i < soundTrackCount && i < MAX_SOUND_TRACKS; i++) { + if (!ParseSoundTrack(file, &midi->soundTracks[i])) { + return false; + } + } + + return true; +} + +// Load AMB file +bool LoadAmbFile(const Path filePath, AmbFile * out) { + FILE *file = fopen(filePath, "rb"); + if (!file) { + MessageBox(NULL, "Failed to open AMB file", "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Initialize AMB file structure + memset(out, 0, sizeof *out); + strcpy(out->filePath, filePath); + + // Parse all chunks + bool success = true; + while (!feof(file)) { + char tag[5] = {0}; + if (fread(tag, 1, 4, file) != 4) { + break; // End of file + } + + if (strcmp(tag, "prgm") == 0) { + if (out->prgmChunkCount < MAX_CHUNKS) { + if (!ParsePrgmChunk(file, &out->prgmChunks[out->prgmChunkCount++])) { + success = false; + break; + } + } else { + MessageBox(NULL, "Too many Prgm chunks", "Error", MB_OK | MB_ICONERROR); + success = false; + break; + } + } else if (strcmp(tag, "kmap") == 0) { + if (out->kmapChunkCount < MAX_CHUNKS) { + if (!ParseKmapChunk(file, &out->kmapChunks[out->kmapChunkCount++])) { + success = false; + break; + } + } else { + MessageBox(NULL, "Too many Kmap chunks", "Error", MB_OK | MB_ICONERROR); + success = false; + break; + } + } else if (strcmp(tag, "glbl") == 0) { + if (!out->hasGlblChunk) { + if (!ParseGlblChunk(file, &out->glblChunk)) { + success = false; + break; + } + out->hasGlblChunk = true; + } else { + MessageBox(NULL, "Multiple Glbl chunks not supported", "Error", MB_OK | MB_ICONERROR); + success = false; + break; + } + } else if (strcmp(tag, "MThd") == 0) { + // MIDI header detected, parse the MIDI data + // Don't need to go back, ParseMidi now expects to be positioned after the tag + if (!ParseMidi(file, &out->midi)) { + success = false; + break; + } + } else { + char message[256]; + sprintf(message, "Unknown chunk tag: %s", tag); + MessageBox(NULL, message, "Error", MB_OK | MB_ICONERROR); + success = false; + break; + } + } + + fclose(file); + + return success; +} + +int ComputePrgmChunkSize(PrgmChunk const * chunk) { + // size = 28 bytes for 7 4-byte ints + 2 null terminators + lengths of the two strings + // All Prgm chunks in the AMBs that ship with Civ 3 are confirmed to follow this rule + return 30 + strlen(chunk->effectName) + strlen(chunk->varName); +} + +// Functions to write AMB file chunks +bool WritePrgmChunk(FILE *file, PrgmChunk const * chunk) { + // Write tag + fwrite("prgm", 1, 4, file); + + // Write chunk data + WriteAmbInt(file, chunk->size, true); + WriteAmbInt(file, chunk->number, true); + WriteAmbInt(file, chunk->flags, false); + WriteAmbInt(file, chunk->maxRandomSpeed, false); + WriteAmbInt(file, chunk->minRandomSpeed, false); + WriteAmbInt(file, chunk->maxRandomVolume, false); + WriteAmbInt(file, chunk->minRandomVolume, false); + + // Write end marker before strings + WriteAmbInt(file, 0xFA, true); + + // Write strings + WriteString(file, chunk->effectName); + WriteString(file, chunk->varName); + + return true; +} + +int ComputeKmapChunkSize(KmapChunk const * chunk) { + // size w/o items = 20 bytes for 5 4-byte ints + length of var name + null terminator + end indicator + int size = 25 + strlen(chunk->varName); + for (int i = 0; i < chunk->itemCount; i++) + // size of each item = 12 bytes unknown data + length of wav file name + null terminator + size += 12 + strlen(chunk->items[i].wavFileName) + 1; + // This rule matches the size of all Kmap chunks in the Civ 3 AMBs except two, both in GalleyAttack.amb. Those chunks are broken, however, and + // don't play any sound. + return size; +} + +bool WriteKmapChunk(FILE *file, KmapChunk const * chunk) { + // Write tag + fwrite("kmap", 1, 4, file); + + // Write chunk data + WriteAmbInt(file, chunk->size, true); + WriteAmbInt(file, chunk->flags, true); + WriteAmbInt(file, chunk->param1, true); + WriteAmbInt(file, chunk->param2, true); + + // Write variable name + WriteString(file, chunk->varName); + + // Write item count + WriteAmbInt(file, chunk->itemCount, true); + + // Write item size if needed + if ((chunk->flags & 6) != 0) { + WriteAmbInt(file, chunk->itemSize, true); + } + + // Write items + for (int i = 0; i < chunk->itemCount && i < MAX_ITEMS; i++) { + if ((chunk->flags & 6) == 0) { + // Not used in Civ3, but we should still write placeholder data + WriteAmbInt(file, 0, true); // Placeholder for aint1 + WriteAmbInt(file, 0, true); // Placeholder for aint2 + } else { + // Write the data block + fwrite(chunk->items[i].data, 1, chunk->itemSize, file); + } + + // Write WAV filename + WriteString(file, chunk->items[i].wavFileName); + } + + // Write end marker + WriteAmbInt(file, 0xFA, true); + + return true; +} + +bool WriteGlblChunk(FILE *file, GlblChunk const * chunk) { + // Write tag + fwrite("glbl", 1, 4, file); + + // Write chunk size + WriteAmbInt(file, chunk->size, true); + + // Write data size + WriteAmbInt(file, chunk->dataSize, true); + + // Write data + fwrite(chunk->data, 1, chunk->dataSize, file); + + // Write extra data if present + if (chunk->extraDataSize > 0) { + fwrite(chunk->extraData, 1, chunk->extraDataSize, file); + } + + return true; +} + +// Function to write TrackName event to MIDI file +void WriteTrackNameEvent(FILE *file, const TrackNameEvent *event) { + fputc(0x03, file); // Track name meta event type + + // Length of the name + WriteMidiVarInt(file, strlen(event->name)); + + // Name data + fwrite(event->name, 1, strlen(event->name), file); +} + +// Function to write SMPTEOffset event to MIDI file +void WriteSMPTEOffsetEvent(FILE *file, const SMPTEOffsetEvent *event) { + fputc(0x54, file); // SMPTE offset meta event type + fputc(0x05, file); // Length is always 5 + + // SMPTE data + fputc(event->hr, file); + fputc(event->mn, file); + fputc(event->se, file); + fputc(event->fr, file); + fputc(event->ff, file); +} + +// Function to write TimeSignature event to MIDI file +void WriteTimeSignatureEvent(FILE *file, const TimeSignatureEvent *event) { + fputc(0x58, file); // Time signature meta event type + fputc(0x04, file); // Length is always 4 + + // Time signature data + fputc(event->nn, file); + fputc(event->dd, file); + fputc(event->cc, file); + fputc(event->bb, file); +} + +// Function to write SetTempo event to MIDI file +void WriteSetTempoEvent(FILE *file, const SetTempoEvent *event) { + fputc(0x51, file); // Set tempo meta event type + fputc(0x03, file); // Length is always 3 + + // Tempo data (microseconds per quarter note) + unsigned int tempo = event->microsecondsPerQuarterNote; + fputc((tempo >> 16) & 0xFF, file); + fputc((tempo >> 8) & 0xFF, file); + fputc(tempo & 0xFF, file); +} + +// Function to write EndOfTrack event to MIDI file +void WriteEndOfTrackEvent(FILE *file) { + fputc(0x2F, file); // End of track meta event type + fputc(0x00, file); // Length is always 0 +} + +// Function to write ControlChange event to MIDI file +void WriteControlChangeEvent(FILE *file, const ControlChangeEvent *event) { + // Control change status byte: 0xBn, where n is the channel number + fputc(0xB0 | (event->channelNumber & 0x0F), file); + + // Controller number and value + fputc(event->controllerNumber & 0x7F, file); + fputc(event->value & 0x7F, file); +} + +// Function to write ProgramChange event to MIDI file +void WriteProgramChangeEvent(FILE *file, const ProgramChangeEvent *event) { + // Program change status byte: 0xCn, where n is the channel number + fputc(0xC0 | (event->channelNumber & 0x0F), file); + + // Program number + fputc(event->programNumber & 0x7F, file); +} + +// Function to write NoteOn event to MIDI file +void WriteNoteOnEvent(FILE *file, const NoteOnEvent *event) { + // Note on status byte: 0x9n, where n is the channel number + fputc(0x90 | (event->channelNumber & 0x0F), file); + + // Key and velocity + fputc(event->key & 0x7F, file); + fputc(event->velocity & 0x7F, file); +} + +// Function to write NoteOff event to MIDI file +void WriteNoteOffEvent(FILE *file, const NoteOffEvent *event) { + // Note off status byte: 0x8n, where n is the channel number + fputc(0x80 | (event->channelNumber & 0x0F), file); + + // Key and velocity + fputc(event->key & 0x7F, file); + fputc(event->velocity & 0x7F, file); +} + +// Function to write InfoTrack to MIDI file +void WriteInfoTrack(FILE *file, const InfoTrack *track) { + // Write track tag + fwrite("MTrk", 1, 4, file); + + // We need to calculate track size, so we'll save the current position, + // write a placeholder, write the events, then come back and update it + long sizePos = ftell(file); + + // Write placeholder for size + WriteMidiInt(file, 0, true); + + // Save position at start of track data + long startPos = ftell(file); + + // Write all events in sequence + + // 1. TrackName event + WriteMidiVarInt(file, track->deltaTimeTrackName); + fputc(0xFF, file); // Meta event marker + WriteTrackNameEvent(file, &track->trackName); + + // 2. SMPTEOffset event + WriteMidiVarInt(file, track->deltaTimeSMPTEOffset); + fputc(0xFF, file); // Meta event marker + WriteSMPTEOffsetEvent(file, &track->smpteOffset); + + // 3. TimeSignature event + WriteMidiVarInt(file, track->deltaTimeTimeSignature); + fputc(0xFF, file); // Meta event marker + WriteTimeSignatureEvent(file, &track->timeSignature); + + // 4. SetTempo event + WriteMidiVarInt(file, track->deltaTimeSetTempo); + fputc(0xFF, file); // Meta event marker + WriteSetTempoEvent(file, &track->setTempo); + + // 5. EndOfTrack event + WriteMidiVarInt(file, track->deltaTimeEndOfTrack); + fputc(0xFF, file); // Meta event marker + WriteEndOfTrackEvent(file); + + // Get end position and calculate size + long endPos = ftell(file); + unsigned int trackSize = (unsigned int)(endPos - startPos); + + // Go back and write the actual size + fseek(file, sizePos, SEEK_SET); + WriteMidiInt(file, trackSize, true); + + // Return to the end of the track + fseek(file, endPos, SEEK_SET); +} + +// Function to write SoundTrack to MIDI file +unsigned int WriteSoundTrack(FILE *file, const SoundTrack *track) { + // Write track tag + fwrite("MTrk", 1, 4, file); + + // We need to calculate track size, so we'll save the current position, + // write a placeholder, write the events, then come back and update it + long sizePos = ftell(file); + + // Write placeholder for size + WriteMidiInt(file, 0, true); + + // Save position at start of track data + long startPos = ftell(file); + + // Write all events in sequence + + // 1. TrackName event + WriteMidiVarInt(file, track->deltaTimeTrackName); + fputc(0xFF, file); // Meta event marker + WriteTrackNameEvent(file, &track->trackName); + + // 2. ControlChange events (1 or 2) + for (int i = 0; i < track->controlChangeCount; i++) { + WriteMidiVarInt(file, track->deltaTimeControlChanges[i]); + WriteControlChangeEvent(file, &track->controlChanges[i]); + } + + // 3. ProgramChange event + WriteMidiVarInt(file, track->deltaTimeProgramChange); + WriteProgramChangeEvent(file, &track->programChange); + + // 4. NoteOn event + WriteMidiVarInt(file, track->deltaTimeNoteOn); + WriteNoteOnEvent(file, &track->noteOn); + + // 5. NoteOff event + WriteMidiVarInt(file, track->deltaTimeNoteOff); + WriteNoteOffEvent(file, &track->noteOff); + + // 6. EndOfTrack event + WriteMidiVarInt(file, track->deltaTimeEndOfTrack); + fputc(0xFF, file); // Meta event marker + WriteEndOfTrackEvent(file); + + // Get end position and calculate size + long endPos = ftell(file); + unsigned int trackSize = (unsigned int)(endPos - startPos); + + // Go back and write the actual size + fseek(file, sizePos, SEEK_SET); + WriteMidiInt(file, trackSize, true); + + // Return to the end of the track + fseek(file, endPos, SEEK_SET); + + return trackSize; +} + +int ComputeSoundTrackSize(SoundTrack const * track) { + FILE *memFile = tmpfile(); + unsigned int size = WriteSoundTrack(memFile, track); + fclose(memFile); + return size; +} + +bool WriteMidi(FILE *file, MidiData const * midi) { + // Write MIDI header + fwrite("MThd", 1, 4, file); + + // Header size is always 6 + WriteMidiInt(file, 6, true); + + // Write format, track count, and division + WriteMidiShort(file, midi->format, false); + WriteMidiShort(file, midi->trackCount, false); + WriteMidiShort(file, midi->ticksPerQuarterNote, false); + + // Write InfoTrack + WriteInfoTrack(file, &midi->infoTrack); + + // Write SoundTracks + int soundTrackCount = midi->trackCount - 1; // First track is InfoTrack + + for (int i = 0; i < soundTrackCount && i < MAX_SOUND_TRACKS; i++) { + WriteSoundTrack(file, &midi->soundTracks[i]); + } + + return true; +} + +// Function to save AMB file to the specified path +bool SaveAmbFile(AmbFile const * amb, const Path filePath) { + FILE *file = fopen(filePath, "wb"); + if (!file) { + return false; + } + + bool success = true; + + // Write Prgm chunks + for (int i = 0; i < amb->prgmChunkCount; i++) { + if (!WritePrgmChunk(file, &amb->prgmChunks[i])) { + success = false; + break; + } + } + + // Write Kmap chunks + if (success) { + for (int i = 0; i < amb->kmapChunkCount; i++) { + if (!WriteKmapChunk(file, &amb->kmapChunks[i])) { + success = false; + break; + } + } + } + + // Write Glbl chunk if present + if (success && amb->hasGlblChunk) { + if (!WriteGlblChunk(file, &amb->glblChunk)) { + success = false; + } + } + + // Write MIDI data + if (success) { + if (!WriteMidi(file, &amb->midi)) { + success = false; + } + } + + fclose(file); + + // Remove the file if we failed + if (!success) { + remove(filePath); + } + + return success; +} + +// Utility function to get sound track count +int GetSoundTrackCount(const MidiData *midi) { + return midi->trackCount - 1; // First track is InfoTrack +} + +// Function to describe the loaded AMB file (for debugging) +void DescribeAmbFile(AmbFile const * amb, char *buffer, size_t bufferSize) { + char *pos = buffer; + int remainingSize = (int)bufferSize; + + // Describe file path + int written = snprintf(pos, remainingSize, "File: %s\r\n\r\n", amb->filePath); + pos += written; + remainingSize -= written; + + // Describe Prgm chunks + for (int i = 0; i < amb->prgmChunkCount && remainingSize > 0; i++) { + PrgmChunk *chunk = &amb->prgmChunks[i]; + written = snprintf(pos, remainingSize, + "Prgm #%d:\r\n" + " Size: %d\r\n" + " Number: %d\r\n" + " Flags: %d\r\n" + " Max Random Speed: %d\r\n" + " Min Random Speed: %d\r\n" + " Max Random Volume: %d\r\n" + " Min Random Volume: %d\r\n" + " Effect Name: '%s'\r\n" + " Var Name: '%s'\r\n\r\n", + i + 1, chunk->size, chunk->number, chunk->flags, + chunk->maxRandomSpeed, chunk->minRandomSpeed, + chunk->maxRandomVolume, chunk->minRandomVolume, + chunk->effectName, chunk->varName); + pos += written; + remainingSize -= written; + } + + // Describe Kmap chunks + for (int i = 0; i < amb->kmapChunkCount && remainingSize > 0; i++) { + KmapChunk *chunk = &amb->kmapChunks[i]; + written = snprintf(pos, remainingSize, + "Kmap #%d:\r\n" + " Size: %d\r\n" + " Flags: %d\r\n" + " Param1: %d\r\n" + " Param2: %d\r\n" + " Var Name: '%s'\r\n" + " Item Count: %d\r\n" + " Item Size: %d\r\n", + i + 1, chunk->size, chunk->flags, + chunk->param1, chunk->param2, + chunk->varName, chunk->itemCount, chunk->itemSize); + pos += written; + remainingSize -= written; + + // Describe Kmap items + for (int j = 0; j < chunk->itemCount && remainingSize > 0; j++) { + written = snprintf(pos, remainingSize, + " Item #%d: WAV File: '%s'\r\n", + j + 1, chunk->items[j].wavFileName); + pos += written; + remainingSize -= written; + } + + written = snprintf(pos, remainingSize, "\r\n"); + pos += written; + remainingSize -= written; + } + + // Describe Glbl chunk + if (amb->hasGlblChunk && remainingSize > 0) { + GlblChunk const * chunk = &amb->glblChunk; + written = snprintf(pos, remainingSize, + "Glbl:\r\n" + " Size: %d\r\n" + " Data Size: %d\r\n\r\n", + chunk->size, chunk->dataSize); + pos += written; + remainingSize -= written; + } + + // Describe MIDI data + if (remainingSize > 0) { + written = snprintf(pos, remainingSize, + "MIDI:\r\n" + " Format: %d\r\n" + " Track Count: %d\r\n" + " Ticks Per Quarter Note: %d\r\n" + " Seconds Per Quarter Note: %.6f\r\n\r\n", + amb->midi.format, amb->midi.trackCount, + amb->midi.ticksPerQuarterNote, amb->midi.secondsPerQuarterNote); + pos += written; + remainingSize -= written; + + // Describe InfoTrack + if (remainingSize > 0) { + InfoTrack const *infoTrack = &amb->midi.infoTrack; + float secondsPerTick = amb->midi.secondsPerQuarterNote / amb->midi.ticksPerQuarterNote; + float timestamp = 0.0f; + + written = snprintf(pos, remainingSize, + " InfoTrack:\r\n" + " Size: %d\r\n", + infoTrack->size); + pos += written; + remainingSize -= written; + + // Track name event + timestamp += infoTrack->deltaTimeTrackName * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: TrackName '%s'\r\n", + timestamp, infoTrack->trackName.name); + pos += written; + remainingSize -= written; + + // SMPTE offset event + timestamp += infoTrack->deltaTimeSMPTEOffset * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: SMPTEOffset %d %d %d %d %d\r\n", + timestamp, infoTrack->smpteOffset.hr, + infoTrack->smpteOffset.mn, + infoTrack->smpteOffset.se, + infoTrack->smpteOffset.fr, + infoTrack->smpteOffset.ff); + pos += written; + remainingSize -= written; + + // Time signature event + timestamp += infoTrack->deltaTimeTimeSignature * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: TimeSignature %d %d %d %d\r\n", + timestamp, infoTrack->timeSignature.nn, + infoTrack->timeSignature.dd, + infoTrack->timeSignature.cc, + infoTrack->timeSignature.bb); + pos += written; + remainingSize -= written; + + // Set tempo event + timestamp += infoTrack->deltaTimeSetTempo * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: SetTempo %d\r\n", + timestamp, infoTrack->setTempo.microsecondsPerQuarterNote); + pos += written; + remainingSize -= written; + + // End of track event + timestamp += infoTrack->deltaTimeEndOfTrack * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: EndOfTrack\r\n\r\n", + timestamp); + pos += written; + remainingSize -= written; + } + + // Describe each SoundTrack + int soundTrackCount = GetSoundTrackCount(&amb->midi); + for (int i = 0; i < soundTrackCount && remainingSize > 0; i++) { + SoundTrack const *soundTrack = &amb->midi.soundTracks[i]; + float secondsPerTick = amb->midi.secondsPerQuarterNote / amb->midi.ticksPerQuarterNote; + float timestamp = 0.0f; + + written = snprintf(pos, remainingSize, + " SoundTrack #%d:\r\n" + " Size: %d\r\n", + i + 1, soundTrack->size); + pos += written; + remainingSize -= written; + + // Track name event + timestamp += soundTrack->deltaTimeTrackName * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: TrackName '%s'\r\n", + timestamp, soundTrack->trackName.name); + pos += written; + remainingSize -= written; + + // Control change events + for (int j = 0; j < soundTrack->controlChangeCount && remainingSize > 0; j++) { + timestamp += soundTrack->deltaTimeControlChanges[j] * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: ControlChange %d %d %d\r\n", + timestamp, soundTrack->controlChanges[j].channelNumber, + soundTrack->controlChanges[j].controllerNumber, + soundTrack->controlChanges[j].value); + pos += written; + remainingSize -= written; + } + + // Program change event + timestamp += soundTrack->deltaTimeProgramChange * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: ProgramChange %d %d\r\n", + timestamp, soundTrack->programChange.channelNumber, + soundTrack->programChange.programNumber); + pos += written; + remainingSize -= written; + + // Note on event + timestamp += soundTrack->deltaTimeNoteOn * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: NoteOn %d %d %d\r\n", + timestamp, soundTrack->noteOn.channelNumber, + soundTrack->noteOn.key, + soundTrack->noteOn.velocity); + pos += written; + remainingSize -= written; + + // Note off event + timestamp += soundTrack->deltaTimeNoteOff * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: NoteOff %d %d %d\r\n", + timestamp, soundTrack->noteOff.channelNumber, + soundTrack->noteOff.key, + soundTrack->noteOff.velocity); + pos += written; + remainingSize -= written; + + // End of track event + timestamp += soundTrack->deltaTimeEndOfTrack * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: EndOfTrack\r\n\r\n", + timestamp); + pos += written; + remainingSize -= written; + } + } +} diff --git a/AMB Editor/details_window.c b/AMB Editor/details_window.c index e2885f44..0bb7f313 100644 --- a/AMB Editor/details_window.c +++ b/AMB Editor/details_window.c @@ -1,161 +1,161 @@ -// This file gets #included into amb_editor.c - -// Global variables for the AMB details window -HWND g_hwndDetailsWindow = NULL; -HWND g_hwndDetailsTextbox = NULL; -WNDPROC g_origDetailsWindowProc = NULL; - -// Window procedure for the details window -LRESULT CALLBACK DetailsWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_SIZE: - // Resize the textbox to fill the window - if (g_hwndDetailsTextbox != NULL) { - RECT rcClient; - GetClientRect(hwnd, &rcClient); - SetWindowPos(g_hwndDetailsTextbox, NULL, - 0, 0, - rcClient.right, rcClient.bottom, - SWP_NOZORDER); - } - return 0; - - case WM_CLOSE: - DestroyWindow(hwnd); - return 0; - - case WM_DESTROY: - g_hwndDetailsWindow = NULL; - g_hwndDetailsTextbox = NULL; - return 0; - } - - return CallWindowProc(g_origDetailsWindowProc, hwnd, uMsg, wParam, lParam); -} - -// Function to show the AMB details window -void ShowAmbDetailsWindow(HWND hwndParent) -{ - // Check if we have a valid AMB file loaded - if (g_ambFile.filePath[0] == '\0') { - MessageBox(hwndParent, "No AMB file loaded. Please open an AMB file first.", - "Error", MB_OK | MB_ICONERROR); - return; - } - - // If the window already exists, just bring it to the front - if (g_hwndDetailsWindow != NULL) { - SetForegroundWindow(g_hwndDetailsWindow); - return; - } - - // Create a new window for the details - HINSTANCE hInstance = GetModuleHandle(NULL); - WNDCLASS wc = {0}; - - // Check if the window class is already registered - if (!GetClassInfo(hInstance, "AMBDetailsWindowClass", &wc)) { - // Register a window class for the details window - wc.lpfnWndProc = DefWindowProc; - wc.hInstance = hInstance; - wc.lpszClassName = "AMBDetailsWindowClass"; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); - - if (!RegisterClass(&wc)) { - MessageBox(hwndParent, "Failed to register window class", "Error", MB_OK | MB_ICONERROR); - return; - } - } - - // Extract filename from the full path for the window title - const char *fileName = strrchr(g_ambFile.filePath, '\\'); - if (fileName) { - fileName++; // Skip past the backslash - } else { - fileName = g_ambFile.filePath; // No backslash found, use the whole path - } - - char windowTitle[100] = {0}; - snprintf(windowTitle, sizeof(windowTitle) - 1, "%s - AMB Details", fileName); - - // Create the details window - g_hwndDetailsWindow = CreateWindowEx( - WS_EX_CLIENTEDGE, - "AMBDetailsWindowClass", - windowTitle, - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 600, 500, - hwndParent, - NULL, - hInstance, - NULL - ); - - if (g_hwndDetailsWindow == NULL) { - MessageBox(hwndParent, "Failed to create details window", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Subclass the window to handle resize events - g_origDetailsWindowProc = (WNDPROC)SetWindowLongPtr(g_hwndDetailsWindow, GWLP_WNDPROC, (LONG_PTR)DetailsWindowProc); - - // Create a multiline read-only text box to display the details - g_hwndDetailsTextbox = CreateWindowEx( - WS_EX_CLIENTEDGE, - "EDIT", - "", - WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | - ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY, - 0, 0, 0, 0, // Will be resized in WM_SIZE handler - g_hwndDetailsWindow, - NULL, - hInstance, - NULL - ); - - if (g_hwndDetailsTextbox == NULL) { - MessageBox(hwndParent, "Failed to create textbox control", "Error", MB_OK | MB_ICONERROR); - DestroyWindow(g_hwndDetailsWindow); - g_hwndDetailsWindow = NULL; - return; - } - - // Set a monospaced font for the textbox - HFONT hFont = CreateFont(14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, - DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "Courier New"); - if (hFont != NULL) { - SendMessage(g_hwndDetailsTextbox, WM_SETFONT, (WPARAM)hFont, TRUE); - } - - // Generate the AMB file details - char *details = (char *)malloc(50000); - if (details) { - DescribeAmbFile(&g_ambFile, details, 50000); - - // Set the text in the textbox - SetWindowText(g_hwndDetailsTextbox, details); - - free(details); - } else { - MessageBox(hwndParent, "Failed to allocate memory for details", "Error", MB_OK | MB_ICONERROR); - DestroyWindow(g_hwndDetailsWindow); - g_hwndDetailsWindow = NULL; - return; - } - - // Force the window to resize the textbox initially - RECT rcClient; - GetClientRect(g_hwndDetailsWindow, &rcClient); - SetWindowPos(g_hwndDetailsTextbox, NULL, - 0, 0, - rcClient.right, rcClient.bottom, - SWP_NOZORDER); - - // Show the window - ShowWindow(g_hwndDetailsWindow, SW_SHOW); - UpdateWindow(g_hwndDetailsWindow); -} +// This file gets #included into amb_editor.c + +// Global variables for the AMB details window +HWND g_hwndDetailsWindow = NULL; +HWND g_hwndDetailsTextbox = NULL; +WNDPROC g_origDetailsWindowProc = NULL; + +// Window procedure for the details window +LRESULT CALLBACK DetailsWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_SIZE: + // Resize the textbox to fill the window + if (g_hwndDetailsTextbox != NULL) { + RECT rcClient; + GetClientRect(hwnd, &rcClient); + SetWindowPos(g_hwndDetailsTextbox, NULL, + 0, 0, + rcClient.right, rcClient.bottom, + SWP_NOZORDER); + } + return 0; + + case WM_CLOSE: + DestroyWindow(hwnd); + return 0; + + case WM_DESTROY: + g_hwndDetailsWindow = NULL; + g_hwndDetailsTextbox = NULL; + return 0; + } + + return CallWindowProc(g_origDetailsWindowProc, hwnd, uMsg, wParam, lParam); +} + +// Function to show the AMB details window +void ShowAmbDetailsWindow(HWND hwndParent) +{ + // Check if we have a valid AMB file loaded + if (g_ambFile.filePath[0] == '\0') { + MessageBox(hwndParent, "No AMB file loaded. Please open an AMB file first.", + "Error", MB_OK | MB_ICONERROR); + return; + } + + // If the window already exists, just bring it to the front + if (g_hwndDetailsWindow != NULL) { + SetForegroundWindow(g_hwndDetailsWindow); + return; + } + + // Create a new window for the details + HINSTANCE hInstance = GetModuleHandle(NULL); + WNDCLASS wc = {0}; + + // Check if the window class is already registered + if (!GetClassInfo(hInstance, "AMBDetailsWindowClass", &wc)) { + // Register a window class for the details window + wc.lpfnWndProc = DefWindowProc; + wc.hInstance = hInstance; + wc.lpszClassName = "AMBDetailsWindowClass"; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + + if (!RegisterClass(&wc)) { + MessageBox(hwndParent, "Failed to register window class", "Error", MB_OK | MB_ICONERROR); + return; + } + } + + // Extract filename from the full path for the window title + const char *fileName = strrchr(g_ambFile.filePath, '\\'); + if (fileName) { + fileName++; // Skip past the backslash + } else { + fileName = g_ambFile.filePath; // No backslash found, use the whole path + } + + char windowTitle[100] = {0}; + snprintf(windowTitle, sizeof(windowTitle) - 1, "%s - AMB Details", fileName); + + // Create the details window + g_hwndDetailsWindow = CreateWindowEx( + WS_EX_CLIENTEDGE, + "AMBDetailsWindowClass", + windowTitle, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 600, 500, + hwndParent, + NULL, + hInstance, + NULL + ); + + if (g_hwndDetailsWindow == NULL) { + MessageBox(hwndParent, "Failed to create details window", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Subclass the window to handle resize events + g_origDetailsWindowProc = (WNDPROC)SetWindowLongPtr(g_hwndDetailsWindow, GWLP_WNDPROC, (LONG_PTR)DetailsWindowProc); + + // Create a multiline read-only text box to display the details + g_hwndDetailsTextbox = CreateWindowEx( + WS_EX_CLIENTEDGE, + "EDIT", + "", + WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | + ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY, + 0, 0, 0, 0, // Will be resized in WM_SIZE handler + g_hwndDetailsWindow, + NULL, + hInstance, + NULL + ); + + if (g_hwndDetailsTextbox == NULL) { + MessageBox(hwndParent, "Failed to create textbox control", "Error", MB_OK | MB_ICONERROR); + DestroyWindow(g_hwndDetailsWindow); + g_hwndDetailsWindow = NULL; + return; + } + + // Set a monospaced font for the textbox + HFONT hFont = CreateFont(14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "Courier New"); + if (hFont != NULL) { + SendMessage(g_hwndDetailsTextbox, WM_SETFONT, (WPARAM)hFont, TRUE); + } + + // Generate the AMB file details + char *details = (char *)malloc(50000); + if (details) { + DescribeAmbFile(&g_ambFile, details, 50000); + + // Set the text in the textbox + SetWindowText(g_hwndDetailsTextbox, details); + + free(details); + } else { + MessageBox(hwndParent, "Failed to allocate memory for details", "Error", MB_OK | MB_ICONERROR); + DestroyWindow(g_hwndDetailsWindow); + g_hwndDetailsWindow = NULL; + return; + } + + // Force the window to resize the textbox initially + RECT rcClient; + GetClientRect(g_hwndDetailsWindow, &rcClient); + SetWindowPos(g_hwndDetailsTextbox, NULL, + 0, 0, + rcClient.right, rcClient.bottom, + SWP_NOZORDER); + + // Show the window + ShowWindow(g_hwndDetailsWindow, SW_SHOW); + UpdateWindow(g_hwndDetailsWindow); +} diff --git a/AMB Editor/hello_claude.txt b/AMB Editor/hello_claude.txt index bfa69e3d..d45c845f 100644 --- a/AMB Editor/hello_claude.txt +++ b/AMB Editor/hello_claude.txt @@ -1,24 +1,24 @@ -Hello Claude! Welcome to the AMB Editor project. - -## What This Is -You're working on a Windows C program that edits AMB files - special sound files used by Civilization III (circa 2001). This is apparently the first reverse-engineered editor for this format. AMB files contain MIDI timing data plus references to WAV files, with various audio parameters like volume/speed randomization. - -## Technical Overview -- **Compiler**: Uses TCC (Tiny C Compiler) via RUN.bat - don't try to compile with GCC on Linux -- **UI**: Win32 ListView control with extensive custom drawing for visual feedback -- **File Structure**: AMB files contain MIDI tracks, Prgm chunks (audio parameters), and Kmap chunks (WAV file references) -- **Key Pattern**: The `g_rowInfo[]` array maps ListView rows to the underlying AMB data structures - -## Important Features -- **Visual Feedback**: WAV filenames turn red if files don't exist, min/max values gray out when randomization is disabled -- **Timestamp Sorting**: ListView rows are sorted by play time and auto-re-sort when times change -- **Undo/Redo**: Uses snapshot system - always call `SnapshotCurrentFile()` before data changes -- **Smart Editing**: `SetListViewItemText()` has an `allowRepopulation` flag to prevent recursion during sorting - -## Code Conventions -- Use enum values (COL_TIME, etc.) instead of bare integers for columns -- Boolean fields display as "Yes"/"No" but are stored as flags (bit 0 = speed random, bit 1 = volume random) -- Float fields format to 3 decimal places -- Minimize message boxes - users found them annoying - +Hello Claude! Welcome to the AMB Editor project. + +## What This Is +You're working on a Windows C program that edits AMB files - special sound files used by Civilization III (circa 2001). This is apparently the first reverse-engineered editor for this format. AMB files contain MIDI timing data plus references to WAV files, with various audio parameters like volume/speed randomization. + +## Technical Overview +- **Compiler**: Uses TCC (Tiny C Compiler) via RUN.bat - don't try to compile with GCC on Linux +- **UI**: Win32 ListView control with extensive custom drawing for visual feedback +- **File Structure**: AMB files contain MIDI tracks, Prgm chunks (audio parameters), and Kmap chunks (WAV file references) +- **Key Pattern**: The `g_rowInfo[]` array maps ListView rows to the underlying AMB data structures + +## Important Features +- **Visual Feedback**: WAV filenames turn red if files don't exist, min/max values gray out when randomization is disabled +- **Timestamp Sorting**: ListView rows are sorted by play time and auto-re-sort when times change +- **Undo/Redo**: Uses snapshot system - always call `SnapshotCurrentFile()` before data changes +- **Smart Editing**: `SetListViewItemText()` has an `allowRepopulation` flag to prevent recursion during sorting + +## Code Conventions +- Use enum values (COL_TIME, etc.) instead of bare integers for columns +- Boolean fields display as "Yes"/"No" but are stored as flags (bit 0 = speed random, bit 1 = volume random) +- Float fields format to 3 decimal places +- Minimize message boxes - users found them annoying + The codebase is well-structured with clear separation between AMB file handling, UI management, and data validation. Most recent work focused on improving the user experience with better visual feedback and timestamp-based organization. \ No newline at end of file diff --git a/AMB Editor/preview.c b/AMB Editor/preview.c index 8576b917..12c2a7d0 100644 --- a/AMB Editor/preview.c +++ b/AMB Editor/preview.c @@ -1,383 +1,383 @@ - -// This file gets #included into amb_editor.c - -// Forward declarations for functions defined in amb_editor.c -extern bool PathIsDirectory(const char* path); -extern bool PathFileExists(const char* path); - -// Using fastcall to substitute for lack of thiscall on a C compiler, as usual. This is the dummy second param. -#define __ 0 - -typedef struct WaveDevice WaveDevice; - -typedef struct { - void * omitted[4]; - int (__fastcall * Initialize) (WaveDevice *, int, HWND, unsigned); - void * omitted_2[38]; -} WaveDeviceVTable; - -struct WaveDevice { - WaveDeviceVTable * vtable; - // other fields omitted -}; - -typedef struct MidiDevice MidiDevice; - -typedef struct { - void * omitted[4]; - int (__fastcall * Initialize)(MidiDevice *, int, HWND, unsigned); - void * omitted_2[38]; -} MidiDeviceVTable; - -struct MidiDevice { - MidiDeviceVTable * vtable; - // other fields omitted -}; - -typedef struct SoundCore SoundCore; - -typedef struct { - void * omitted[4]; - int (__fastcall * LoadFile)(SoundCore *, int, char const *); // takes file path - void * omitted_2[2]; - int (__fastcall * Play)(SoundCore *); - int (__fastcall * Stop)(SoundCore *); - void * omitted_3[7]; - void (__fastcall * SetVolume)(SoundCore *, int, int); // volume is >= 0 and <= 127 - void * omitted_4[5]; - int (__fastcall * M22)(SoundCore *); - void * omitted_5; - int (__fastcall * M24)(SoundCore *); - void * omitted_6[2]; - int (__fastcall * SetFlags)(SoundCore *, int, unsigned); - void * omitted_7[22]; - int (__fastcall * M50)(SoundCore *); - void * omitted_8[26]; -} SoundCoreVTable; - -struct SoundCore { - SoundCoreVTable * vtable; - // many more fields omitted -}; - -enum sound_core_type { - SCT_DETECT_FROM_FILE_EXT = 0, // Does not work - SCT_WAV, - SCT_MIDI, - SCT_AIF, - SCT_4, - SCT_AMB, - SCT_6, - SCT_7, - SCT_8 -}; - -bool previewPlayerIsInitialized = false; - -HMODULE soundModule = NULL; -int (__cdecl * InitSoundTimer)(int param_1, int param_2) = NULL; -int (__cdecl * CreateSound)(SoundCore ** out_sound_core, char const * file_path, int sound_core_type) = NULL; -int (__cdecl * DeleteSound)(SoundCore * sound_core) = NULL; -int (__cdecl * CreateWaveDevice)(WaveDevice ** out, unsigned param_2) = NULL; -int (__cdecl * CreateMidiDevice)(MidiDevice ** out, unsigned param_2) = NULL; - -WaveDevice * waveDevice = NULL; -MidiDevice * midiDevice = NULL; - -SoundCore * playingCore = NULL; - -void InitializePreviewPlayer(HWND window, char *soundDLLPath) -{ - if (previewPlayerIsInitialized) - return; - - char errorMsg[1000] = {0}; - Path savedCWD; - Path soundDLLDir; - char* fileName; - - // Save current directory - GetCurrentDirectory(sizeof(savedCWD), savedCWD); - - // Extract directory and filename from sound.dll path - strcpy(soundDLLDir, soundDLLPath); - char* lastSlash = strrchr(soundDLLDir, '\\'); - if (lastSlash) { - fileName = lastSlash + 1; // point to filename part - *lastSlash = '\0'; // truncate to get directory - SetCurrentDirectory(soundDLLDir); - } else { - // No path separators, assume it's just a filename - fileName = soundDLLPath; - } - - soundModule = LoadLibraryA(fileName); - if (soundModule == NULL) { - DWORD error = GetLastError(); - char errorString[256]; - if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, error, 0, errorString, sizeof(errorString), NULL) == 0) { - snprintf(errorMsg, sizeof(errorMsg) - 1, "Failed to load sound.dll: Error code %lu", error); - } else { - snprintf(errorMsg, sizeof(errorMsg) - 1, "Failed to load sound.dll: %s", errorString); - } - goto done; - } - - InitSoundTimer = (void *)GetProcAddress(soundModule, "init_sound_timer"); - CreateSound = (void *)GetProcAddress(soundModule, "create_sound"); - DeleteSound = (void *)GetProcAddress(soundModule, "delete_sound"); - CreateWaveDevice = (void *)GetProcAddress(soundModule, (LPCSTR)5); // Use ordinal b/c name is mangled - CreateMidiDevice = (void *)GetProcAddress(soundModule, (LPCSTR)7); - - if (InitSoundTimer == NULL || CreateSound == NULL || DeleteSound == NULL || - CreateWaveDevice == NULL || CreateMidiDevice == NULL) { - snprintf(errorMsg, sizeof(errorMsg) - 1, - "Failed to load required functions from sound.dll. This may not be a valid Civ3 sound.dll file."); - goto done; - } - - InitSoundTimer(0, 0); - - CreateWaveDevice(&waveDevice, 0); - waveDevice->vtable->Initialize(waveDevice, __, window, 2); // Civ 3 passes 2 for second param (flags) - - CreateMidiDevice(&midiDevice, 0); - midiDevice->vtable->Initialize(midiDevice, __, window, 0); - -done: - // Restore original directory - SetCurrentDirectory(savedCWD); - - if (strlen(errorMsg) > 0) { - MessageBox(NULL, errorMsg, "Couldn't load sound.dll", MB_ICONERROR); - if (soundModule != NULL) { - FreeLibrary(soundModule); - soundModule = NULL; - } - previewPlayerIsInitialized = false; - } else - previewPlayerIsInitialized = true; -} - -void StopAmbPreview() -{ - if (playingCore != NULL) { - playingCore->vtable->Stop(playingCore); - DeleteSound(playingCore); - playingCore = NULL; - } -} - -void DeinitializePreviewPlayer() -{ - if (previewPlayerIsInitialized) { - StopAmbPreview(); - FreeLibrary(soundModule); - previewPlayerIsInitialized = false; - } -} - -#define TEMP_FOLDER "AMBEditorTemp" -#ifndef MAX_PATH -#define MAX_PATH 260 -#endif - -// Helper function to clear .wav and .amb files from numbered directories -void ClearTempDirectory(const char *baseTempDir) -{ - WIN32_FIND_DATA findData; - char searchPattern[MAX_PATH] = {0}; - char numberedDirPath[MAX_PATH] = {0}; - - snprintf(searchPattern, sizeof(searchPattern) - 1, "%s\\*", baseTempDir); - HANDLE hFind = FindFirstFile(searchPattern, &findData); - - if (hFind != INVALID_HANDLE_VALUE) { - do { - // Skip . and .. directory entries - if (strcmp(findData.cFileName, ".") == 0 || - strcmp(findData.cFileName, "..") == 0) { - continue; - } - - // Check if this is a numbered directory (1, 2, 3, etc.) - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - char *endPtr; - long dirNumber = strtol(findData.cFileName, &endPtr, 10); - - // If the entire filename is a number, it's a numbered directory - if (*endPtr == '\0' && dirNumber > 0) { - snprintf(numberedDirPath, sizeof(numberedDirPath) - 1, "%s\\%s", baseTempDir, findData.cFileName); - - // Delete .wav and .amb files from this numbered directory - WIN32_FIND_DATA fileData; - char fileSearchPattern[MAX_PATH] = {0}; - char filePath[MAX_PATH] = {0}; - - snprintf(fileSearchPattern, sizeof(fileSearchPattern) - 1, "%s\\*.*", numberedDirPath); - HANDLE hFileFind = FindFirstFile(fileSearchPattern, &fileData); - - if (hFileFind != INVALID_HANDLE_VALUE) { - do { - if (strcmp(fileData.cFileName, ".") != 0 && - strcmp(fileData.cFileName, "..") != 0 && - !(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - - char *extension = strrchr(fileData.cFileName, '.'); - if (extension != NULL) { - if (_stricmp(extension, ".wav") == 0 || _stricmp(extension, ".amb") == 0) { - snprintf(filePath, sizeof(filePath) - 1, "%s\\%s", numberedDirPath, fileData.cFileName); - DeleteFile(filePath); - } - } - } - } while (FindNextFile(hFileFind, &fileData)); - FindClose(hFileFind); - } - - // Try to remove the empty directory - RemoveDirectory(numberedDirPath); - } - } - } while (FindNextFile(hFind, &findData)); - FindClose(hFind); - } -} - -// Prepare temporary directory for AMB previewing, creating a numbered subfolder -BOOL PrepareTempDirectory(Path forcedTempPath, char *tempDirPath, size_t tempDirPathSize) -{ - char tempPath[MAX_PATH] = {0}; - char baseTempDir[MAX_PATH] = {0}; - - // Check if forcedTempPath is provided and non-empty - if (strlen(forcedTempPath) > 0) { - // Validate that the forced temp path exists and is a directory - if (!PathIsDirectory(forcedTempPath)) { - return FALSE; - } - strncpy(baseTempDir, forcedTempPath, (sizeof baseTempDir) - 1); - } else { - // Get the system temp directory - DWORD result = GetTempPath(MAX_PATH, tempPath); - if (result == 0 || result > MAX_PATH) { - return FALSE; - } - - // Create our base temp folder in the system temp directory - snprintf(baseTempDir, sizeof(baseTempDir) - 1, "%s%s", tempPath, TEMP_FOLDER); - } - - // Create the directory if it doesn't exist - if (!PathIsDirectory(baseTempDir)) { - if (!CreateDirectory(baseTempDir, NULL)) { - return FALSE; - } - } - - // Clear .wav and .amb files from numbered directories within the base temp directory - ClearTempDirectory(baseTempDir); - - // Find an unused numbered subfolder - char numberedPath[MAX_PATH] = {0}; - int folderNumber = 1; - - while (folderNumber <= 9999) { // Reasonable upper limit - snprintf(numberedPath, sizeof(numberedPath) - 1, "%s\\%d", baseTempDir, folderNumber); - - if (!PathIsDirectory(numberedPath)) { - // This number is available, create the directory - if (CreateDirectory(numberedPath, NULL)) { - // Update the output path to the numbered folder - snprintf(tempDirPath, tempDirPathSize - 1, "%s", numberedPath); - return TRUE; - } else { - return FALSE; - } - } - - folderNumber++; - } - - // If we couldn't find an unused number, fail - return FALSE; -} - -// Copy WAV files referenced by the AMB to the temp directory -BOOL CopyWavFilesToTempDir(AmbFile const * ambFile, char *tempDirPath) -{ - Path sourcePath = {0}; - Path targetPath = {0}; - BOOL success = TRUE; - - // Get the directory of the original AMB file to find the WAV files - Path ambDir; - strcpy(ambDir, ambFile->filePath); - - // Find the last backslash in the path - char *lastBackslash = strrchr(ambDir, '\\'); - if (lastBackslash != NULL) { - *lastBackslash = '\0'; // Truncate the path at the last backslash - } - - // For each Kmap chunk, copy any referenced WAV files - for (int i = 0; i < ambFile->kmapChunkCount; i++) { - KmapChunk const * chunk = &ambFile->kmapChunks[i]; - - // For each item in the Kmap chunk, copy its WAV file - for (int j = 0; j < chunk->itemCount && j < MAX_ITEMS; j++) { - const char *wavFileName = chunk->items[j].wavFileName; - - // Skip if no WAV file is specified - if (strlen(wavFileName) == 0) { - continue; - } - - // Construct the source and target paths - snprintf(sourcePath, PATH_BUFFER_SIZE - 1, "%s\\%s", ambDir, wavFileName); - snprintf(targetPath, PATH_BUFFER_SIZE - 1, "%s\\%s", tempDirPath, wavFileName); - - // Copy the file - if (!CopyFile(sourcePath, targetPath, FALSE)) { - success = FALSE; - } - } - } - - return success; -} - -void PreviewAmbFile(Path forcedTempPath, AmbFile const * amb) -{ - if (! previewPlayerIsInitialized) - return; - - StopAmbPreview(); - - // Save the AMB to a temporary file first. Begin by preparing a temp directory - Path tempFilePath = {0}; - Path tempDirPath = {0}; - bool success = false; - if (PrepareTempDirectory(forcedTempPath, tempDirPath, PATH_BUFFER_SIZE)) { - // Generate a temp file path for the AMB - snprintf(tempFilePath, PATH_BUFFER_SIZE - 1, "%s\\temp.amb", tempDirPath); - - // Save the current AMB to the temp file - if (SaveAmbFile(amb, tempFilePath)) { - // Copy all WAV files referenced by the AMB to the temp directory - if (CopyWavFilesToTempDir(amb, tempDirPath)) { - success = true; - } - } - } - - // Play the temp copy if it was created successfully - if (success) { - CreateSound(&playingCore, NULL, SCT_AMB); - if (playingCore != NULL) { - playingCore->vtable->LoadFile(playingCore, __, tempFilePath); - playingCore->vtable->Play(playingCore); - } - } -} + +// This file gets #included into amb_editor.c + +// Forward declarations for functions defined in amb_editor.c +extern bool PathIsDirectory(const char* path); +extern bool PathFileExists(const char* path); + +// Using fastcall to substitute for lack of thiscall on a C compiler, as usual. This is the dummy second param. +#define __ 0 + +typedef struct WaveDevice WaveDevice; + +typedef struct { + void * omitted[4]; + int (__fastcall * Initialize) (WaveDevice *, int, HWND, unsigned); + void * omitted_2[38]; +} WaveDeviceVTable; + +struct WaveDevice { + WaveDeviceVTable * vtable; + // other fields omitted +}; + +typedef struct MidiDevice MidiDevice; + +typedef struct { + void * omitted[4]; + int (__fastcall * Initialize)(MidiDevice *, int, HWND, unsigned); + void * omitted_2[38]; +} MidiDeviceVTable; + +struct MidiDevice { + MidiDeviceVTable * vtable; + // other fields omitted +}; + +typedef struct SoundCore SoundCore; + +typedef struct { + void * omitted[4]; + int (__fastcall * LoadFile)(SoundCore *, int, char const *); // takes file path + void * omitted_2[2]; + int (__fastcall * Play)(SoundCore *); + int (__fastcall * Stop)(SoundCore *); + void * omitted_3[7]; + void (__fastcall * SetVolume)(SoundCore *, int, int); // volume is >= 0 and <= 127 + void * omitted_4[5]; + int (__fastcall * M22)(SoundCore *); + void * omitted_5; + int (__fastcall * M24)(SoundCore *); + void * omitted_6[2]; + int (__fastcall * SetFlags)(SoundCore *, int, unsigned); + void * omitted_7[22]; + int (__fastcall * M50)(SoundCore *); + void * omitted_8[26]; +} SoundCoreVTable; + +struct SoundCore { + SoundCoreVTable * vtable; + // many more fields omitted +}; + +enum sound_core_type { + SCT_DETECT_FROM_FILE_EXT = 0, // Does not work + SCT_WAV, + SCT_MIDI, + SCT_AIF, + SCT_4, + SCT_AMB, + SCT_6, + SCT_7, + SCT_8 +}; + +bool previewPlayerIsInitialized = false; + +HMODULE soundModule = NULL; +int (__cdecl * InitSoundTimer)(int param_1, int param_2) = NULL; +int (__cdecl * CreateSound)(SoundCore ** out_sound_core, char const * file_path, int sound_core_type) = NULL; +int (__cdecl * DeleteSound)(SoundCore * sound_core) = NULL; +int (__cdecl * CreateWaveDevice)(WaveDevice ** out, unsigned param_2) = NULL; +int (__cdecl * CreateMidiDevice)(MidiDevice ** out, unsigned param_2) = NULL; + +WaveDevice * waveDevice = NULL; +MidiDevice * midiDevice = NULL; + +SoundCore * playingCore = NULL; + +void InitializePreviewPlayer(HWND window, char *soundDLLPath) +{ + if (previewPlayerIsInitialized) + return; + + char errorMsg[1000] = {0}; + Path savedCWD; + Path soundDLLDir; + char* fileName; + + // Save current directory + GetCurrentDirectory(sizeof(savedCWD), savedCWD); + + // Extract directory and filename from sound.dll path + strcpy(soundDLLDir, soundDLLPath); + char* lastSlash = strrchr(soundDLLDir, '\\'); + if (lastSlash) { + fileName = lastSlash + 1; // point to filename part + *lastSlash = '\0'; // truncate to get directory + SetCurrentDirectory(soundDLLDir); + } else { + // No path separators, assume it's just a filename + fileName = soundDLLPath; + } + + soundModule = LoadLibraryA(fileName); + if (soundModule == NULL) { + DWORD error = GetLastError(); + char errorString[256]; + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, 0, errorString, sizeof(errorString), NULL) == 0) { + snprintf(errorMsg, sizeof(errorMsg) - 1, "Failed to load sound.dll: Error code %lu", error); + } else { + snprintf(errorMsg, sizeof(errorMsg) - 1, "Failed to load sound.dll: %s", errorString); + } + goto done; + } + + InitSoundTimer = (void *)GetProcAddress(soundModule, "init_sound_timer"); + CreateSound = (void *)GetProcAddress(soundModule, "create_sound"); + DeleteSound = (void *)GetProcAddress(soundModule, "delete_sound"); + CreateWaveDevice = (void *)GetProcAddress(soundModule, (LPCSTR)5); // Use ordinal b/c name is mangled + CreateMidiDevice = (void *)GetProcAddress(soundModule, (LPCSTR)7); + + if (InitSoundTimer == NULL || CreateSound == NULL || DeleteSound == NULL || + CreateWaveDevice == NULL || CreateMidiDevice == NULL) { + snprintf(errorMsg, sizeof(errorMsg) - 1, + "Failed to load required functions from sound.dll. This may not be a valid Civ3 sound.dll file."); + goto done; + } + + InitSoundTimer(0, 0); + + CreateWaveDevice(&waveDevice, 0); + waveDevice->vtable->Initialize(waveDevice, __, window, 2); // Civ 3 passes 2 for second param (flags) + + CreateMidiDevice(&midiDevice, 0); + midiDevice->vtable->Initialize(midiDevice, __, window, 0); + +done: + // Restore original directory + SetCurrentDirectory(savedCWD); + + if (strlen(errorMsg) > 0) { + MessageBox(NULL, errorMsg, "Couldn't load sound.dll", MB_ICONERROR); + if (soundModule != NULL) { + FreeLibrary(soundModule); + soundModule = NULL; + } + previewPlayerIsInitialized = false; + } else + previewPlayerIsInitialized = true; +} + +void StopAmbPreview() +{ + if (playingCore != NULL) { + playingCore->vtable->Stop(playingCore); + DeleteSound(playingCore); + playingCore = NULL; + } +} + +void DeinitializePreviewPlayer() +{ + if (previewPlayerIsInitialized) { + StopAmbPreview(); + FreeLibrary(soundModule); + previewPlayerIsInitialized = false; + } +} + +#define TEMP_FOLDER "AMBEditorTemp" +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +// Helper function to clear .wav and .amb files from numbered directories +void ClearTempDirectory(const char *baseTempDir) +{ + WIN32_FIND_DATA findData; + char searchPattern[MAX_PATH] = {0}; + char numberedDirPath[MAX_PATH] = {0}; + + snprintf(searchPattern, sizeof(searchPattern) - 1, "%s\\*", baseTempDir); + HANDLE hFind = FindFirstFile(searchPattern, &findData); + + if (hFind != INVALID_HANDLE_VALUE) { + do { + // Skip . and .. directory entries + if (strcmp(findData.cFileName, ".") == 0 || + strcmp(findData.cFileName, "..") == 0) { + continue; + } + + // Check if this is a numbered directory (1, 2, 3, etc.) + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + char *endPtr; + long dirNumber = strtol(findData.cFileName, &endPtr, 10); + + // If the entire filename is a number, it's a numbered directory + if (*endPtr == '\0' && dirNumber > 0) { + snprintf(numberedDirPath, sizeof(numberedDirPath) - 1, "%s\\%s", baseTempDir, findData.cFileName); + + // Delete .wav and .amb files from this numbered directory + WIN32_FIND_DATA fileData; + char fileSearchPattern[MAX_PATH] = {0}; + char filePath[MAX_PATH] = {0}; + + snprintf(fileSearchPattern, sizeof(fileSearchPattern) - 1, "%s\\*.*", numberedDirPath); + HANDLE hFileFind = FindFirstFile(fileSearchPattern, &fileData); + + if (hFileFind != INVALID_HANDLE_VALUE) { + do { + if (strcmp(fileData.cFileName, ".") != 0 && + strcmp(fileData.cFileName, "..") != 0 && + !(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + + char *extension = strrchr(fileData.cFileName, '.'); + if (extension != NULL) { + if (_stricmp(extension, ".wav") == 0 || _stricmp(extension, ".amb") == 0) { + snprintf(filePath, sizeof(filePath) - 1, "%s\\%s", numberedDirPath, fileData.cFileName); + DeleteFile(filePath); + } + } + } + } while (FindNextFile(hFileFind, &fileData)); + FindClose(hFileFind); + } + + // Try to remove the empty directory + RemoveDirectory(numberedDirPath); + } + } + } while (FindNextFile(hFind, &findData)); + FindClose(hFind); + } +} + +// Prepare temporary directory for AMB previewing, creating a numbered subfolder +BOOL PrepareTempDirectory(Path forcedTempPath, char *tempDirPath, size_t tempDirPathSize) +{ + char tempPath[MAX_PATH] = {0}; + char baseTempDir[MAX_PATH] = {0}; + + // Check if forcedTempPath is provided and non-empty + if (strlen(forcedTempPath) > 0) { + // Validate that the forced temp path exists and is a directory + if (!PathIsDirectory(forcedTempPath)) { + return FALSE; + } + strncpy(baseTempDir, forcedTempPath, (sizeof baseTempDir) - 1); + } else { + // Get the system temp directory + DWORD result = GetTempPath(MAX_PATH, tempPath); + if (result == 0 || result > MAX_PATH) { + return FALSE; + } + + // Create our base temp folder in the system temp directory + snprintf(baseTempDir, sizeof(baseTempDir) - 1, "%s%s", tempPath, TEMP_FOLDER); + } + + // Create the directory if it doesn't exist + if (!PathIsDirectory(baseTempDir)) { + if (!CreateDirectory(baseTempDir, NULL)) { + return FALSE; + } + } + + // Clear .wav and .amb files from numbered directories within the base temp directory + ClearTempDirectory(baseTempDir); + + // Find an unused numbered subfolder + char numberedPath[MAX_PATH] = {0}; + int folderNumber = 1; + + while (folderNumber <= 9999) { // Reasonable upper limit + snprintf(numberedPath, sizeof(numberedPath) - 1, "%s\\%d", baseTempDir, folderNumber); + + if (!PathIsDirectory(numberedPath)) { + // This number is available, create the directory + if (CreateDirectory(numberedPath, NULL)) { + // Update the output path to the numbered folder + snprintf(tempDirPath, tempDirPathSize - 1, "%s", numberedPath); + return TRUE; + } else { + return FALSE; + } + } + + folderNumber++; + } + + // If we couldn't find an unused number, fail + return FALSE; +} + +// Copy WAV files referenced by the AMB to the temp directory +BOOL CopyWavFilesToTempDir(AmbFile const * ambFile, char *tempDirPath) +{ + Path sourcePath = {0}; + Path targetPath = {0}; + BOOL success = TRUE; + + // Get the directory of the original AMB file to find the WAV files + Path ambDir; + strcpy(ambDir, ambFile->filePath); + + // Find the last backslash in the path + char *lastBackslash = strrchr(ambDir, '\\'); + if (lastBackslash != NULL) { + *lastBackslash = '\0'; // Truncate the path at the last backslash + } + + // For each Kmap chunk, copy any referenced WAV files + for (int i = 0; i < ambFile->kmapChunkCount; i++) { + KmapChunk const * chunk = &ambFile->kmapChunks[i]; + + // For each item in the Kmap chunk, copy its WAV file + for (int j = 0; j < chunk->itemCount && j < MAX_ITEMS; j++) { + const char *wavFileName = chunk->items[j].wavFileName; + + // Skip if no WAV file is specified + if (strlen(wavFileName) == 0) { + continue; + } + + // Construct the source and target paths + snprintf(sourcePath, PATH_BUFFER_SIZE - 1, "%s\\%s", ambDir, wavFileName); + snprintf(targetPath, PATH_BUFFER_SIZE - 1, "%s\\%s", tempDirPath, wavFileName); + + // Copy the file + if (!CopyFile(sourcePath, targetPath, FALSE)) { + success = FALSE; + } + } + } + + return success; +} + +void PreviewAmbFile(Path forcedTempPath, AmbFile const * amb) +{ + if (! previewPlayerIsInitialized) + return; + + StopAmbPreview(); + + // Save the AMB to a temporary file first. Begin by preparing a temp directory + Path tempFilePath = {0}; + Path tempDirPath = {0}; + bool success = false; + if (PrepareTempDirectory(forcedTempPath, tempDirPath, PATH_BUFFER_SIZE)) { + // Generate a temp file path for the AMB + snprintf(tempFilePath, PATH_BUFFER_SIZE - 1, "%s\\temp.amb", tempDirPath); + + // Save the current AMB to the temp file + if (SaveAmbFile(amb, tempFilePath)) { + // Copy all WAV files referenced by the AMB to the temp directory + if (CopyWavFilesToTempDir(amb, tempDirPath)) { + success = true; + } + } + } + + // Play the temp copy if it was created successfully + if (success) { + CreateSound(&playingCore, NULL, SCT_AMB); + if (playingCore != NULL) { + playingCore->vtable->LoadFile(playingCore, __, tempFilePath); + playingCore->vtable->Play(playingCore); + } + } +} diff --git a/AMB Editor/wav_file.c b/AMB Editor/wav_file.c index 93092b26..7dc8b2d9 100644 --- a/AMB Editor/wav_file.c +++ b/AMB Editor/wav_file.c @@ -1,130 +1,130 @@ -#include -#include - -// WAV file header structures -typedef struct { - char riff[4]; // "RIFF" - DWORD fileSize; // File size - 8 - char wave[4]; // "WAVE" -} RiffHeader; - -typedef struct { - char fmt[4]; // "fmt " - DWORD chunkSize; // Size of fmt chunk data - WORD audioFormat; // 1 = PCM - WORD numChannels; // 1 = mono, 2 = stereo - DWORD sampleRate; // Sample rate (Hz) - DWORD byteRate; // Bytes per second - WORD blockAlign; // Bytes per sample frame - WORD bitsPerSample; // Bits per sample -} FmtChunk; - -typedef struct { - char data[4]; // "data" - DWORD dataSize; // Size of audio data -} DataChunkHeader; - -// Read WAV file duration -// Returns TRUE on success, FALSE on failure -// Duration is returned in seconds through outDuration parameter -BOOL GetWavFileDuration(const char* filePath, float* outDuration) -{ - HANDLE hFile = INVALID_HANDLE_VALUE; - RiffHeader riffHeader; - FmtChunk fmtChunk; - DataChunkHeader dataHeader; - DWORD bytesRead; - BOOL success = FALSE; - - if (!filePath || !outDuration) { - return FALSE; - } - - // Open the file - hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return FALSE; - } - - // Read RIFF header - if (!ReadFile(hFile, &riffHeader, sizeof(RiffHeader), &bytesRead, NULL) || - bytesRead != sizeof(RiffHeader)) { - goto cleanup; - } - - // Verify RIFF and WAVE signatures - if (memcmp(riffHeader.riff, "RIFF", 4) != 0 || - memcmp(riffHeader.wave, "WAVE", 4) != 0) { - goto cleanup; - } - - // Read fmt chunk - if (!ReadFile(hFile, &fmtChunk, sizeof(FmtChunk), &bytesRead, NULL) || - bytesRead != sizeof(FmtChunk)) { - goto cleanup; - } - - // Verify fmt signature and basic PCM format - if (memcmp(fmtChunk.fmt, "fmt ", 4) != 0 || - fmtChunk.audioFormat != 1 || // PCM format - fmtChunk.numChannels == 0 || - fmtChunk.sampleRate == 0 || - fmtChunk.bitsPerSample == 0) { - goto cleanup; - } - - // Skip any extra fmt chunk data beyond the standard 16 bytes - if (fmtChunk.chunkSize > 16) { - DWORD extraBytes = fmtChunk.chunkSize - 16; - SetFilePointer(hFile, extraBytes, NULL, FILE_CURRENT); - } - - // Look for data chunk - char chunkId[4]; - DWORD chunkSize; - BOOL foundData = FALSE; - - while (!foundData) { - // Read chunk header (ID + size) - if (!ReadFile(hFile, chunkId, 4, &bytesRead, NULL) || bytesRead != 4) { - goto cleanup; - } - if (!ReadFile(hFile, &chunkSize, 4, &bytesRead, NULL) || bytesRead != 4) { - goto cleanup; - } - - if (memcmp(chunkId, "data", 4) == 0) { - // Found data chunk - dataHeader.dataSize = chunkSize; - foundData = TRUE; - } else { - // Skip this chunk - if (SetFilePointer(hFile, chunkSize, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { - goto cleanup; - } - } - } - - if (!foundData || dataHeader.dataSize == 0) { - goto cleanup; - } - - // Calculate duration: data_size / (sample_rate * channels * bytes_per_sample) - DWORD bytesPerSample = (fmtChunk.bitsPerSample + 7) / 8; // Round up to nearest byte - DWORD bytesPerSecond = fmtChunk.sampleRate * fmtChunk.numChannels * bytesPerSample; - - if (bytesPerSecond == 0) { - goto cleanup; - } - - *outDuration = (float)dataHeader.dataSize / (float)bytesPerSecond; - success = TRUE; - -cleanup: - if (hFile != INVALID_HANDLE_VALUE) { - CloseHandle(hFile); - } - - return success; +#include +#include + +// WAV file header structures +typedef struct { + char riff[4]; // "RIFF" + DWORD fileSize; // File size - 8 + char wave[4]; // "WAVE" +} RiffHeader; + +typedef struct { + char fmt[4]; // "fmt " + DWORD chunkSize; // Size of fmt chunk data + WORD audioFormat; // 1 = PCM + WORD numChannels; // 1 = mono, 2 = stereo + DWORD sampleRate; // Sample rate (Hz) + DWORD byteRate; // Bytes per second + WORD blockAlign; // Bytes per sample frame + WORD bitsPerSample; // Bits per sample +} FmtChunk; + +typedef struct { + char data[4]; // "data" + DWORD dataSize; // Size of audio data +} DataChunkHeader; + +// Read WAV file duration +// Returns TRUE on success, FALSE on failure +// Duration is returned in seconds through outDuration parameter +BOOL GetWavFileDuration(const char* filePath, float* outDuration) +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + RiffHeader riffHeader; + FmtChunk fmtChunk; + DataChunkHeader dataHeader; + DWORD bytesRead; + BOOL success = FALSE; + + if (!filePath || !outDuration) { + return FALSE; + } + + // Open the file + hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return FALSE; + } + + // Read RIFF header + if (!ReadFile(hFile, &riffHeader, sizeof(RiffHeader), &bytesRead, NULL) || + bytesRead != sizeof(RiffHeader)) { + goto cleanup; + } + + // Verify RIFF and WAVE signatures + if (memcmp(riffHeader.riff, "RIFF", 4) != 0 || + memcmp(riffHeader.wave, "WAVE", 4) != 0) { + goto cleanup; + } + + // Read fmt chunk + if (!ReadFile(hFile, &fmtChunk, sizeof(FmtChunk), &bytesRead, NULL) || + bytesRead != sizeof(FmtChunk)) { + goto cleanup; + } + + // Verify fmt signature and basic PCM format + if (memcmp(fmtChunk.fmt, "fmt ", 4) != 0 || + fmtChunk.audioFormat != 1 || // PCM format + fmtChunk.numChannels == 0 || + fmtChunk.sampleRate == 0 || + fmtChunk.bitsPerSample == 0) { + goto cleanup; + } + + // Skip any extra fmt chunk data beyond the standard 16 bytes + if (fmtChunk.chunkSize > 16) { + DWORD extraBytes = fmtChunk.chunkSize - 16; + SetFilePointer(hFile, extraBytes, NULL, FILE_CURRENT); + } + + // Look for data chunk + char chunkId[4]; + DWORD chunkSize; + BOOL foundData = FALSE; + + while (!foundData) { + // Read chunk header (ID + size) + if (!ReadFile(hFile, chunkId, 4, &bytesRead, NULL) || bytesRead != 4) { + goto cleanup; + } + if (!ReadFile(hFile, &chunkSize, 4, &bytesRead, NULL) || bytesRead != 4) { + goto cleanup; + } + + if (memcmp(chunkId, "data", 4) == 0) { + // Found data chunk + dataHeader.dataSize = chunkSize; + foundData = TRUE; + } else { + // Skip this chunk + if (SetFilePointer(hFile, chunkSize, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { + goto cleanup; + } + } + } + + if (!foundData || dataHeader.dataSize == 0) { + goto cleanup; + } + + // Calculate duration: data_size / (sample_rate * channels * bytes_per_sample) + DWORD bytesPerSample = (fmtChunk.bitsPerSample + 7) / 8; // Round up to nearest byte + DWORD bytesPerSecond = fmtChunk.sampleRate * fmtChunk.numChannels * bytesPerSample; + + if (bytesPerSecond == 0) { + goto cleanup; + } + + *outDuration = (float)dataHeader.dataSize / (float)bytesPerSecond; + success = TRUE; + +cleanup: + if (hFile != INVALID_HANDLE_VALUE) { + CloseHandle(hFile); + } + + return success; } \ No newline at end of file diff --git a/AMB Editor/win32_selections.h b/AMB Editor/win32_selections.h index 863fe227..08161058 100644 --- a/AMB Editor/win32_selections.h +++ b/AMB Editor/win32_selections.h @@ -1,156 +1,156 @@ - -// This file contains only the Win32 definitions needed by the AMB editor. Normally one would #include the needed header files, however that's not -// possible because they aren't available with TCC. - -// Common Control definitions (normally from commctrl.h) -#define WC_LISTVIEW "SysListView32" -#define LVS_REPORT 0x0001 -#define LVS_SHOWSELALWAYS 0x0008 -#define LVS_SINGLESEL 0x0004 -#define LVS_EDITLABELS 0x0200 -#define LVS_NOHSCROLL 0x8000 -#define LVM_INSERTCOLUMN (LVM_FIRST + 27) -#define LVM_INSERTITEM (LVM_FIRST + 7) -#define LVM_SETITEM (LVM_FIRST + 6) -#define LVM_SETITEMSTATE (LVM_FIRST + 43) -#define LVM_GETITEMCOUNT (LVM_FIRST + 4) -#define LVM_DELETEALLITEMS (LVM_FIRST + 9) -#define LVM_GETITEMSTATE (LVM_FIRST + 44) -#define LVM_FIRST 0x1000 -#define LVCF_TEXT 0x0004 -#define LVCF_WIDTH 0x0002 -#define LVIF_TEXT 0x0001 -#define LVIF_STATE 0x0008 -#define LVIS_STATEIMAGEMASK 0xF000 -#define LVIS_SELECTED 0x0002 -#define LVS_EX_GRIDLINES 0x00000001 -#define LVS_EX_FULLROWSELECT 0x00000020 -#define LVS_EX_CHECKBOXES 0x00000004 -#define LVM_SETEXTENDEDLISTVIEWSTYLE (LVM_FIRST + 54) -#define LVM_GETEXTENDEDLISTVIEWSTYLE (LVM_FIRST + 55) -#define LVN_FIRST (-100) -#define LVN_BEGINLABELEDIT (LVN_FIRST-5) -#define LVN_ENDLABELEDIT (LVN_FIRST-6) -#define LVN_COLUMNCLICK (LVN_FIRST-8) -#define NM_CUSTOMDRAW (NM_FIRST-12) -#define LVM_GETEDITCONTROL (LVM_FIRST + 24) -#define LVM_EDITLABEL (LVM_FIRST + 23) -#define LVM_GETITEMTEXT (LVM_FIRST + 45) -#define LVM_GETSUBITEMRECT (LVM_FIRST + 56) -#define LVM_GETCOLUMN (LVM_FIRST + 25) -#define EM_SETSEL 0x00B1 -#define LVIR_BOUNDS 0 -#define LVIR_ICON 1 -#define LVIR_LABEL 2 -#define LVIR_SELECTBOUNDS 3 - -// Custom draw constants -#define CDDS_PREPAINT 0x00000001 -#define CDDS_POSTPAINT 0x00000002 -#define CDDS_PREERASE 0x00000003 -#define CDDS_POSTERASE 0x00000004 -#define CDDS_ITEM 0x00010000 -#define CDDS_ITEMPREPAINT (CDDS_ITEM | CDDS_PREPAINT) -#define CDDS_ITEMPOSTPAINT (CDDS_ITEM | CDDS_POSTPAINT) -#define CDDS_SUBITEM 0x00020000 -#define CDRF_DODEFAULT 0x00000000 -#define CDRF_NEWFONT 0x00000002 -#define CDRF_SKIPDEFAULT 0x00000004 -#define CDRF_NOTIFYPOSTPAINT 0x00000010 -#define CDRF_NOTIFYITEMDRAW 0x00000020 -#define CDRF_NOTIFYSUBITEMDRAW 0x00000020 - -typedef struct tagLVCOLUMNA { - UINT mask; - int fmt; - int cx; - LPSTR pszText; - int cchTextMax; - int iSubItem; - int iImage; - int iOrder; -} LVCOLUMNA, *LPLVCOLUMNA; - -typedef struct tagLVITEMA { - UINT mask; - int iItem; - int iSubItem; - UINT state; - UINT stateMask; - LPSTR pszText; - int cchTextMax; - int iImage; - LPARAM lParam; - int iIndent; -} LVITEMA, *LPLVITEMA; - -typedef struct tagNMLVDISPINFOA { - NMHDR hdr; - LVITEMA item; -} NMLVDISPINFOA, *LPNMLVDISPINFOA; - -typedef struct tagNMITEMACTIVATE { - NMHDR hdr; - int iItem; - int iSubItem; - UINT uNewState; - UINT uOldState; - UINT uChanged; - POINT ptAction; - LPARAM lParam; - UINT uKeyFlags; -} NMITEMACTIVATE, *LPNMITEMACTIVATE; - -typedef struct tagNMCUSTOMDRAWINFO { - NMHDR hdr; - DWORD dwDrawStage; - HDC hdc; - RECT rc; - DWORD_PTR dwItemSpec; - UINT uItemState; - LPARAM lItemlParam; -} NMCUSTOMDRAW, *LPNMCUSTOMDRAW; - -typedef struct tagNMLVCUSTOMDRAW { - NMCUSTOMDRAW nmcd; - COLORREF clrText; - COLORREF clrTextBk; - int iSubItem; -} NMLVCUSTOMDRAW, *LPNMLVCUSTOMDRAW; - -#define NM_FIRST (0U- 0U) -#define NM_DBLCLK (NM_FIRST-3) -#define EN_KILLFOCUS 0x0200 - -// Minimal declarations for common dialogs (normally from commdlg.h) -#define OFN_PATHMUSTEXIST 0x00000800 -#define OFN_FILEMUSTEXIST 0x00001000 -#define OFN_HIDEREADONLY 0x00000004 -#define OFN_NOCHANGEDIR 0x00000008 -#define OFN_EXPLORER 0x00080000 - -typedef struct tagOFNA { - DWORD lStructSize; - HWND hwndOwner; - HINSTANCE hInstance; - LPCSTR lpstrFilter; - LPSTR lpstrCustomFilter; - DWORD nMaxCustFilter; - DWORD nFilterIndex; - LPSTR lpstrFile; - DWORD nMaxFile; - LPSTR lpstrFileTitle; - DWORD nMaxFileTitle; - LPCSTR lpstrInitialDir; - LPCSTR lpstrTitle; - DWORD Flags; - WORD nFileOffset; - WORD nFileExtension; - LPCSTR lpstrDefExt; - LPARAM lCustData; - LPVOID lpfnHook; - LPCSTR lpTemplateName; - void* pvReserved; - DWORD dwReserved; - DWORD FlagsEx; -} OPENFILENAMEA, *LPOPENFILENAMEA; + +// This file contains only the Win32 definitions needed by the AMB editor. Normally one would #include the needed header files, however that's not +// possible because they aren't available with TCC. + +// Common Control definitions (normally from commctrl.h) +#define WC_LISTVIEW "SysListView32" +#define LVS_REPORT 0x0001 +#define LVS_SHOWSELALWAYS 0x0008 +#define LVS_SINGLESEL 0x0004 +#define LVS_EDITLABELS 0x0200 +#define LVS_NOHSCROLL 0x8000 +#define LVM_INSERTCOLUMN (LVM_FIRST + 27) +#define LVM_INSERTITEM (LVM_FIRST + 7) +#define LVM_SETITEM (LVM_FIRST + 6) +#define LVM_SETITEMSTATE (LVM_FIRST + 43) +#define LVM_GETITEMCOUNT (LVM_FIRST + 4) +#define LVM_DELETEALLITEMS (LVM_FIRST + 9) +#define LVM_GETITEMSTATE (LVM_FIRST + 44) +#define LVM_FIRST 0x1000 +#define LVCF_TEXT 0x0004 +#define LVCF_WIDTH 0x0002 +#define LVIF_TEXT 0x0001 +#define LVIF_STATE 0x0008 +#define LVIS_STATEIMAGEMASK 0xF000 +#define LVIS_SELECTED 0x0002 +#define LVS_EX_GRIDLINES 0x00000001 +#define LVS_EX_FULLROWSELECT 0x00000020 +#define LVS_EX_CHECKBOXES 0x00000004 +#define LVM_SETEXTENDEDLISTVIEWSTYLE (LVM_FIRST + 54) +#define LVM_GETEXTENDEDLISTVIEWSTYLE (LVM_FIRST + 55) +#define LVN_FIRST (-100) +#define LVN_BEGINLABELEDIT (LVN_FIRST-5) +#define LVN_ENDLABELEDIT (LVN_FIRST-6) +#define LVN_COLUMNCLICK (LVN_FIRST-8) +#define NM_CUSTOMDRAW (NM_FIRST-12) +#define LVM_GETEDITCONTROL (LVM_FIRST + 24) +#define LVM_EDITLABEL (LVM_FIRST + 23) +#define LVM_GETITEMTEXT (LVM_FIRST + 45) +#define LVM_GETSUBITEMRECT (LVM_FIRST + 56) +#define LVM_GETCOLUMN (LVM_FIRST + 25) +#define EM_SETSEL 0x00B1 +#define LVIR_BOUNDS 0 +#define LVIR_ICON 1 +#define LVIR_LABEL 2 +#define LVIR_SELECTBOUNDS 3 + +// Custom draw constants +#define CDDS_PREPAINT 0x00000001 +#define CDDS_POSTPAINT 0x00000002 +#define CDDS_PREERASE 0x00000003 +#define CDDS_POSTERASE 0x00000004 +#define CDDS_ITEM 0x00010000 +#define CDDS_ITEMPREPAINT (CDDS_ITEM | CDDS_PREPAINT) +#define CDDS_ITEMPOSTPAINT (CDDS_ITEM | CDDS_POSTPAINT) +#define CDDS_SUBITEM 0x00020000 +#define CDRF_DODEFAULT 0x00000000 +#define CDRF_NEWFONT 0x00000002 +#define CDRF_SKIPDEFAULT 0x00000004 +#define CDRF_NOTIFYPOSTPAINT 0x00000010 +#define CDRF_NOTIFYITEMDRAW 0x00000020 +#define CDRF_NOTIFYSUBITEMDRAW 0x00000020 + +typedef struct tagLVCOLUMNA { + UINT mask; + int fmt; + int cx; + LPSTR pszText; + int cchTextMax; + int iSubItem; + int iImage; + int iOrder; +} LVCOLUMNA, *LPLVCOLUMNA; + +typedef struct tagLVITEMA { + UINT mask; + int iItem; + int iSubItem; + UINT state; + UINT stateMask; + LPSTR pszText; + int cchTextMax; + int iImage; + LPARAM lParam; + int iIndent; +} LVITEMA, *LPLVITEMA; + +typedef struct tagNMLVDISPINFOA { + NMHDR hdr; + LVITEMA item; +} NMLVDISPINFOA, *LPNMLVDISPINFOA; + +typedef struct tagNMITEMACTIVATE { + NMHDR hdr; + int iItem; + int iSubItem; + UINT uNewState; + UINT uOldState; + UINT uChanged; + POINT ptAction; + LPARAM lParam; + UINT uKeyFlags; +} NMITEMACTIVATE, *LPNMITEMACTIVATE; + +typedef struct tagNMCUSTOMDRAWINFO { + NMHDR hdr; + DWORD dwDrawStage; + HDC hdc; + RECT rc; + DWORD_PTR dwItemSpec; + UINT uItemState; + LPARAM lItemlParam; +} NMCUSTOMDRAW, *LPNMCUSTOMDRAW; + +typedef struct tagNMLVCUSTOMDRAW { + NMCUSTOMDRAW nmcd; + COLORREF clrText; + COLORREF clrTextBk; + int iSubItem; +} NMLVCUSTOMDRAW, *LPNMLVCUSTOMDRAW; + +#define NM_FIRST (0U- 0U) +#define NM_DBLCLK (NM_FIRST-3) +#define EN_KILLFOCUS 0x0200 + +// Minimal declarations for common dialogs (normally from commdlg.h) +#define OFN_PATHMUSTEXIST 0x00000800 +#define OFN_FILEMUSTEXIST 0x00001000 +#define OFN_HIDEREADONLY 0x00000004 +#define OFN_NOCHANGEDIR 0x00000008 +#define OFN_EXPLORER 0x00080000 + +typedef struct tagOFNA { + DWORD lStructSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCSTR lpstrFilter; + LPSTR lpstrCustomFilter; + DWORD nMaxCustFilter; + DWORD nFilterIndex; + LPSTR lpstrFile; + DWORD nMaxFile; + LPSTR lpstrFileTitle; + DWORD nMaxFileTitle; + LPCSTR lpstrInitialDir; + LPCSTR lpstrTitle; + DWORD Flags; + WORD nFileOffset; + WORD nFileExtension; + LPCSTR lpstrDefExt; + LPARAM lCustData; + LPVOID lpfnHook; + LPCSTR lpTemplateName; + void* pvReserved; + DWORD dwReserved; + DWORD FlagsEx; +} OPENFILENAMEA, *LPOPENFILENAMEA; diff --git a/Art/.gitignore b/Art/.gitignore index 5ab70449..a0a982d9 100644 --- a/Art/.gitignore +++ b/Art/.gitignore @@ -1,25 +1,25 @@ -Seasons/ -0100/ -0200/ -0300/ -0400/ -0500/ -0600/ -0700/ -0800/ -0900/ -1000/ -1100/ - -1300/ -1400/ -1500/ -1600/ -1700/ -1800/ -1900/ -2000/ -2100/ -2200/ -2300/ +Seasons/ +0100/ +0200/ +0300/ +0400/ +0500/ +0600/ +0700/ +0800/ +0900/ +1000/ +1100/ + +1300/ +1400/ +1500/ +1600/ +1700/ +1800/ +1900/ +2000/ +2100/ +2200/ +2300/ 2400/ \ No newline at end of file diff --git a/Art/DayNight/.gitignore b/Art/DayNight/.gitignore index 37ab4d22..bfb96e82 100644 --- a/Art/DayNight/.gitignore +++ b/Art/DayNight/.gitignore @@ -1,24 +1,24 @@ -0100/ -0200/ -0300/ -0400/ -0500/ -0600/ -0700/ -0800/ -0900/ -1000/ -1100/ -1200/ -1300/ -1400/ -1500/ -1600/ -1700/ -1800/ -1900/ -2000/ -2100/ -2200/ -2300/ +0100/ +0200/ +0300/ +0400/ +0500/ +0600/ +0700/ +0800/ +0900/ +1000/ +1100/ +1200/ +1300/ +1400/ +1500/ +1600/ +1700/ +1800/ +1900/ +2000/ +2100/ +2200/ +2300/ 2400/ \ No newline at end of file diff --git a/C3X.h b/C3X.h index 65c1770a..8d3cc092 100644 --- a/C3X.h +++ b/C3X.h @@ -1,2333 +1,2333 @@ -#include - -#define NOVIRTUALKEYCODES // Keycodes defined in Civ3Conquests.h instead -#include "windows.h" - -typedef unsigned char byte; - -// Use fastcall as substitute for thiscall because TCC doesn't recognize thiscall -#define __fastcall __attribute__((fastcall)) -#include "Civ3Conquests.h" - -#define MOD_VERSION 2700 -#define MOD_PREVIEW_VERSION 2 - -#define COUNT_TILE_HIGHLIGHTS 11 -#define MAX_BUILDING_PREREQS_FOR_UNIT 10 - -#define COUNT_SPECIAL_DISTRICT_TYPES 10 -#define USED_SPECIAL_DISTRICT_TYPES 11 -#define MAX_DYNAMIC_DISTRICT_TYPES 22 -#define COUNT_DISTRICT_TYPES (COUNT_SPECIAL_DISTRICT_TYPES + MAX_DYNAMIC_DISTRICT_TYPES) -#define MAX_WONDER_DISTRICT_TYPES 32 -#define MAX_NATURAL_WONDER_DISTRICT_TYPES 32 -#define MAX_DISTRICT_VARIANT_COUNT 5 -#define MAX_DISTRICT_ERA_COUNT 4 -#define MAX_DISTRICT_COLUMN_COUNT 10 -#define C3X_DISTRICT_COMMAND_BASE (-11000000) - -// Initialize to zero. Implementation is in common.c -struct table { - void * block; - size_t capacity_exponent; // Actual capacity is 1 << capacity_exponent - size_t len; -}; - -// Initialize to zero. Implementation in common.c -struct buffer { - byte * contents; - int length; - int capacity; -}; - -// A mill is a city improvement that spawns a resource. These are read from the "buildings_generating_resources" key in the config but are called -// "mills" internally for brevity. -enum mill_flag { - MF_LOCAL = 1, - MF_NO_TECH_REQ = 2, - MF_YIELDS = 4, - MF_SHOW_BONUS = 8, - MF_HIDE_NON_BONUS = 16 -}; -struct mill { - short improv_id; - short resource_id; - short flags; -}; - -#define ERA_ALIAS_LIST_CAPACITY 4 // Must not exceed 32 so we can store all genders as bits in an int - -// A list of per-era aliases for a civ's noun, adjective, or formal name. -struct civ_era_alias_list { - char * key; - char * aliases[ERA_ALIAS_LIST_CAPACITY]; -}; - -// A list of per-era aliases for a civ's leader's name, including genders and (optionally) titles. -struct leader_era_alias_list { - char * key; - char * aliases[ERA_ALIAS_LIST_CAPACITY]; - int gender_bits; // Gender of each alias. Like LeaderGender in the Race object, 0 for male and 1 for female. - char * titles[ERA_ALIAS_LIST_CAPACITY]; // Title for each alias. May be NULL. -}; - -struct unit_type_limit { - int per_civ; - int per_city; - int cities_per; -}; - -struct work_area_improvement { - short improv_id; - int work_area_radius_limit; - int work_area_radius_bonus; -}; - -enum retreat_rules { - RR_STANDARD = 0, - RR_NONE, - RR_ALL_UNITS, - RR_IF_FASTER, - RR_IF_NOT_SLOWER, - RR_IF_FAST_AND_NOT_SLOWER, -}; - -enum line_drawing_override { - LDO_NEVER = 0, - LDO_WINE, - LDO_ALWAYS -}; - -enum minimap_doubling_mode { - MDM_NEVER = 0, - MDM_HIGH_DEF, - MDM_ALWAYS -}; - -enum unit_cycle_search_criteria { - UCSC_STANDARD = 0, - UCSC_SIMILAR_NEAR_START, - UCSC_SIMILAR_NEAR_DESTINATION -}; - -enum no_ai_patrol_override { - NAPO_ZERO = 0, - NAPO_ONE, - NAPO_NONE -}; - -enum barbarian_activity_override { - BAO_NONE = -2, - - // The values for these levels must match what the game uses internally for Map.World.Final_Barbarians_Activity - BAO_NO_BARBARIANS = -1, - BAO_SEDENTARY = 0, - BAO_ROAMING = 1, - BAO_RESTLESS = 2, - BAO_RAGING = 3, - BAO_RANDOM = 4 -}; - -enum special_defensive_bombard_rules { - SDBR_LETHAL = 1, - SDBR_NOT_INVISIBLE = 2, - SDBR_AERIAL = 4, - SDBR_BLITZ = 8, - SDBR_DOCKED_VS_LAND = 16, -}; - -enum special_zone_of_control_rules { - SZOCR_LETHAL = 1, - SZOCR_AERIAL = 2, - SZOCR_AMPHIBIOUS = 4, - SZOCR_NOT_FROM_INSIDE = 8, -}; - -enum land_transport_rules { - LTR_LOAD_ONTO_BOAT = 1, - LTR_JOIN_ARMY = 2, - LTR_NO_DEFENSE_FROM_INSIDE = 4, - LTR_NO_ESCAPE = 8, -}; - -enum special_helicopter_rules { - SHR_ALLOW_ON_CARRIERS = 1, - SHR_PASSENGER_AIRDROP = 2, - SHR_NO_DEFENSE_FROM_INSIDE = 4, - SHR_NO_ESCAPE = 8, -}; - -enum work_area_limit { - WAL_NONE = 0, - WAL_CULTURAL, - WAL_CULTURAL_MIN_2, - WAL_CULTURAL_OR_ADJACENT -}; - -enum day_night_cycle_mode { - DNCM_OFF = 0, - DNCM_TIMER, - DNCM_USER_TIME, - DNCM_EVERY_TURN, - DNCM_SPECIFIED -}; - -enum distribution_hub_yield_division_mode { - DHYDM_FLAT = 0, - DHYDM_SCALE_BY_CITY_COUNT -}; - -enum ai_distribution_hub_build_strategy { - ADHBS_AUTO = 0, - ADHBS_BY_CITY_COUNT -}; - -enum ai_auto_build_great_wall_strategy { - AAGWS_ALL_BORDERS = 0, - AAGWS_OTHER_CIV_BORDERED_ONLY -}; - -enum perfume_kind { - PK_PRODUCTION = 0, - PK_TECHNOLOGY, - PK_GOVERNMENT, - - COUNT_PERFUME_KINDS -}; - -struct unit_counter_group { - char * name; - int * type_ids; - int count_type_ids; -}; - -// Attacker/defender match modes -#define UCM_ANY -1 // * Any unit type -#define UCM_GROUP -2 // Match using the group_name field - -struct counter_rule { - // Attacker side - int attacker_match; // UnitTypeID, or UCM_ANY / UCM_GROUP - char * attacker_group; // Used when attacker_match == UCM_GROUP - - // Defender side - int defender_match; - char * defender_group; - - // Environment conditions (0 / false means no restriction) - unsigned int terrain_mask; // SquareTypes mask, 0 = no restriction - bool only_in_city; - int district_id; // -1 = no restriction - char * district_name; // Resolved after district configs are loaded - bool ignore_terrain; // true = set defender terrain defense to 0 - - // Effects (percent values, 100 = no change) - int self_atk_pct; - int self_def_pct; - int enemy_atk_pct; - int enemy_def_pct; -}; - -struct c3x_config { - bool enable_stack_bombard; - bool enable_disorder_warning; - bool allow_stealth_attack_against_single_unit; - bool show_detailed_city_production_info; - int limit_railroad_movement; - bool limited_railroads_work_like_fast_roads; - int limit_units_per_tile[3]; // Limits for land, sea, and air units respectively - bool exclude_cities_from_units_per_tile_limit; - struct table exclude_types_from_units_per_tile_limit; - bool enable_free_buildings_from_small_wonders; - bool enable_stack_unit_commands; - bool skip_repeated_tile_improv_replacement_asks; - bool autofill_best_gold_amount_when_trading; - int minimum_city_separation; - bool disallow_founding_next_to_foreign_city; - bool enable_trade_screen_scroll; - bool group_units_on_right_click_menu; - bool gray_out_units_on_menu_with_no_remaining_moves; - bool put_movement_icons_on_units_on_menu; - bool describe_states_of_units_on_menu; - int anarchy_length_percent; - bool show_golden_age_turns_remaining; - bool show_zoc_attacks_from_mid_stack; - bool show_armies_performing_defensive_bombard; - bool cut_research_spending_to_avoid_bankruptcy; - bool dont_pause_for_love_the_king_messages; - bool reverse_specialist_order_with_shift; - bool toggle_zoom_with_z_on_city_screen; - bool enable_mouse_wheel_zoom; - bool dont_give_king_names_in_non_regicide_games; - bool no_elvis_easter_egg; - bool disable_worker_automation; - bool enable_land_sea_intersections; - bool disallow_trespassing; - bool show_detailed_tile_info; - struct table perfume_specs[COUNT_PERFUME_KINDS]; // Each table maps strings to i31b's. Each i31b combines an amount and whether it's a percent - struct table building_unit_prereqs; // A mapping from int keys to int values. The keys are unit type IDs. If an ID is present as a key in the - // table that means that unit type has one or more prereq buildings. The associated value is either a - // pointer to a list of MAX_BUILDING_PREREQS_FOR_UNITS improvement IDs or a single encoded improv ID. The - // contents of the list are NOT encoded and unused slots store -1. Encoding an ID is done by left-shifting - // it one place then inserting a 1 in the LSB. This way encoded IDs can be told apart from list pointers - // by checking the LSB (1 => encoded improv ID, 0 => list pointer). - struct mill * mills; - int count_mills; - bool warn_about_unrecognized_names; - bool enable_ai_production_ranking; - bool enable_ai_city_location_desirability_display; - bool show_ai_city_location_desirability_if_settler; - bool zero_corruption_when_off; - bool disallow_land_units_from_affecting_water_tiles; - bool dont_end_units_turn_after_airdrop; - bool allow_airdrop_without_airport; - bool enable_negative_pop_pollution; - enum retreat_rules land_retreat_rules; - enum retreat_rules sea_retreat_rules; - bool allow_defensive_retreat_on_water; - struct table limit_defensive_retreat_on_water_to_types; // Table mapping unit type IDs to 1's; used as a hash set - int ai_multi_city_start; - int max_tries_to_place_fp_city; - int * ai_multi_start_extra_palaces; - int count_ai_multi_start_extra_palaces; - int ai_multi_start_extra_palaces_capacity; - bool promote_wonder_decorruption_effect; - bool allow_military_leaders_to_hurry_wonders; - bool allow_multiple_battle_created_units_per_player; - int ai_research_multiplier; - int ai_settler_perfume_on_founding; - int ai_settler_perfume_on_founding_duration; - bool aggressively_penalize_bankruptcy; - bool no_penalty_exception_for_agri_fresh_water_city_tiles; - bool suppress_hypertext_links_exceeded_popup; - bool indicate_non_upgradability_in_pedia; - bool show_message_after_dodging_sam; - bool include_stealth_attack_cancel_option; - bool intercept_recon_missions; - bool charge_one_move_for_recon_and_interception; - bool polish_precision_striking; - bool enable_stealth_attack_via_bombardment; - bool immunize_aircraft_against_bombardment; - bool replay_ai_moves_in_hotseat_games; - struct table ptw_arty_types; // Table mapping unit type IDs to 1's; used as a hash set - struct table can_bombard_only_sea_tiles; // Table mapping unit type IDs to 1's; used as a hash set - bool restore_unit_directions_on_game_load; - bool apply_grid_ini_setting_on_game_load; - bool charm_flag_triggers_ptw_like_targeting; - bool city_icons_show_unit_effects_not_trade; - bool ignore_king_ability_for_defense_priority; - bool show_untradable_techs_on_trade_screen; - bool disallow_useless_bombard_vs_airfields; - enum line_drawing_override draw_lines_using_gdi_plus; - bool compact_luxury_display_on_city_screen; - bool compact_strategic_resource_display_on_city_screen; - bool warn_when_chosen_building_would_replace_another; - bool do_not_unassign_workers_from_polluted_tiles; - bool do_not_make_capital_cities_appear_larger; - bool show_territory_colors_on_water_tiles_in_minimap; - bool convert_some_popups_into_online_mp_messages; - bool enable_debug_mode_switch; - bool accentuate_cities_on_minimap; - enum minimap_doubling_mode double_minimap_size; - bool allow_multipage_civilopedia_descriptions; - enum unit_cycle_search_criteria unit_cycle_search_criteria; - bool reformat_turns_remaining_on_domestic_advisor_screen; - bool expand_civilopedia_unit_stats; - bool enable_city_capture_by_barbarians; - bool share_visibility_in_hotseat; - bool share_wonders_in_hotseat; - bool allow_precision_strikes_against_tile_improvements; - bool dont_end_units_turn_after_bombarding_barricade; - bool remove_land_artillery_target_restrictions; - bool allow_bombard_of_other_improvs_on_occupied_airfield; - bool show_total_city_count; - bool strengthen_forbidden_palace_ocn_effect; - int extra_unit_maintenance_per_shields; - enum special_zone_of_control_rules special_zone_of_control_rules; - enum special_defensive_bombard_rules special_defensive_bombard_rules; - struct civ_era_alias_list * civ_era_alias_lists; - int count_civ_era_alias_lists; - struct leader_era_alias_list * leader_era_alias_lists; - int count_leader_era_alias_lists; - struct table unit_limits; // Maps unit type names (strings) to pointers to limit objects (struct unit_type_limit *) - bool allow_upgrades_in_any_city; - bool do_not_generate_volcanos; - bool do_not_pollute_impassable_tiles; - bool show_hp_of_stealth_attack_options; - bool exclude_invisible_units_from_stealth_attack; - bool exclude_passengers_from_stealth_attack; - bool convert_to_landmark_after_planting_forest; - int chance_for_nukes_to_destroy_max_one_hp_units; - bool allow_sale_of_aqueducts_and_hospitals; - bool no_cross_shore_detection; - int city_work_radius; - bool auto_zoom_city_screen_for_large_work_areas; - enum work_area_limit work_area_limit; - struct work_area_improvement * work_area_improvements; - int count_work_area_improvements; - int rebase_range_multiplier; - bool limit_unit_loading_to_one_transport_per_turn; - bool prevent_old_units_from_upgrading_past_ability_block; - bool introduce_all_human_players_at_start_of_hotseat_game; - bool allow_unload_from_army; - enum land_transport_rules land_transport_rules; - bool allow_adjacent_resources_of_different_types; - bool allow_corruption_in_capital; - int special_capital_decorruption_effect; - int luxury_randomized_appearance_rate_percent; - int tiles_per_non_luxury_resource; - bool no_land_anti_air_from_inside_naval_transport; - enum special_helicopter_rules special_helicopter_rules; - bool prevent_enslaving_by_bombardment; - int years_to_double_building_culture; - int tourism_time_scale_percent; - bool allow_sale_of_small_wonders; - enum no_ai_patrol_override override_no_ai_patrol; - enum barbarian_activity_override override_barbarian_activity_level_for_scenario_maps; - bool initialize_preplaced_scenario_leaders_as_mgls; - bool enable_unit_counters; - struct unit_counter_group * unit_counter_groups; - int count_unit_counter_groups; - struct counter_rule * counter_rules; - int count_counter_rules; - bool use_civ4_style_best_defender; - - bool enable_trade_net_x; - bool optimize_improvement_loops; - bool measure_turn_times; - - bool use_offensive_artillery_ai; - bool dont_escort_unflagged_units; - int ai_build_artillery_ratio; - int ai_artillery_value_damage_percent; - int ai_build_bomber_ratio; - bool replace_leader_unit_ai; - bool fix_ai_army_composition; - bool enable_pop_unit_ai; - bool enable_caravan_unit_ai; - int max_ai_naval_escorts; - int ai_worker_requirement_percent; - - bool remove_unit_limit; - bool remove_city_improvement_limit; - int city_limit; - bool remove_cap_on_turn_limit; - bool remove_era_limit; - - bool patch_submarine_bug; - bool patch_science_age_bug; - bool patch_pedia_texture_bug; - bool patch_blocked_disembark_freeze; - bool patch_houseboat_bug; - bool patch_intercept_lost_turn_bug; - bool patch_phantom_resource_bug; - bool patch_maintenance_persisting_for_obsolete_buildings; - bool patch_barbarian_diagonal_bug; - bool patch_disease_stopping_tech_flag_bug; - bool patch_division_by_zero_in_ai_alliance_eval; - bool patch_empty_army_movement; - bool patch_empty_army_combat_crash; - bool delete_off_map_ai_units; - bool fix_overlapping_specialist_yield_icons; - bool patch_premature_truncation_of_found_paths; - bool patch_zero_production_crash; - bool patch_ai_can_form_army_without_special_ability; - bool patch_ai_can_sacrifice_without_special_ability; - bool patch_crash_in_leader_unit_ai; - bool patch_failure_to_find_new_city_build; - bool patch_passengers_out_of_order_on_menu; - - bool prevent_autorazing; - bool prevent_razing_by_players; - - bool allow_extraterritorial_colonies; - int per_extraterritorial_colony_relation_penalty; - - bool draw_forests_over_roads_and_railroads; - - bool enable_named_tiles; - - char * aircraft_victory_animation; // NULL if set to "none" in config - - int day_night_cycle_mode; - int elapsed_minutes_per_day_night_hour_transition; - int fixed_hours_per_turn_for_day_night_cycle; - int pinned_hour_for_day_night_cycle; - - bool enable_natural_wonders; - bool add_natural_wonders_to_scenarios_if_none; - bool show_natural_wonder_name_on_map; - int minimum_natural_wonder_separation; - - bool enable_districts; - bool enable_neighborhood_districts; - bool enable_wonder_districts; - bool enable_distribution_hub_districts; - bool enable_aerodrome_districts; - bool enable_port_districts; - bool enable_bridge_districts; - bool enable_canal_districts; - bool enable_central_rail_hub_districts; - bool enable_energy_grid_districts; - bool enable_great_wall_districts; - - bool cities_with_mutual_district_receive_buildings; - bool cities_with_mutual_district_receive_wonders; - bool show_message_when_building_received_by_mutual_district; - bool show_message_when_building_lost_to_destroyed_district; - - bool air_units_use_aerodrome_districts_not_cities; - bool naval_units_use_port_districts_not_cities; - - int maximum_pop_before_neighborhood_needed; - int per_neighborhood_pop_growth_enabled; - int neighborhood_needed_message_frequency; - bool destroying_neighborhood_reduces_pop; - - bool completed_wonder_districts_can_be_destroyed; - bool destroyed_wonders_can_be_built_again; - - int distribution_hub_yield_division_mode; - int distribution_hub_food_yield_divisor; - int distribution_hub_shield_yield_divisor; - int ai_distribution_hub_build_strategy; - int ai_ideal_distribution_hub_count_per_100_cities; - int max_distribution_hub_count_per_100_cities; - int central_rail_hub_distribution_food_bonus_percent; - int central_rail_hub_distribution_shield_bonus_percent; - - bool workers_can_enter_coast; - bool expand_water_tile_checks_to_city_work_area; - int max_contiguous_bridge_districts; - int max_contiguous_canal_districts; - int ai_canal_eval_min_bisected_land_tiles; - int ai_bridge_canal_eval_block_size; - int ai_bridge_eval_lake_tile_threshold; - bool ai_can_replace_existing_districts_with_canals; - bool ai_builds_bridges; - bool ai_builds_canals; - - bool ai_defends_districts; - int ai_city_district_max_build_wait_turns; - - bool disable_great_wall_city_defense_bonus; - bool great_wall_districts_impassible_by_others; - bool auto_build_great_wall_around_territory; - char * great_wall_auto_build_wonder_name; - int great_wall_auto_build_wonder_improv_id; - int ai_auto_build_great_wall_strategy; - - bool enable_city_work_radii_highlights; -}; - -enum stackable_command { - SC_BOMBARD = 0, - SC_BOMB, - SC_FORTRESS, - SC_MINE, - SC_IRRIGATE, - SC_CHOP_FOREST, - SC_CHOP_JUNGLE, - SC_PLANT, - SC_CLEAN_POLLUTION, - SC_ROAD, - SC_RAILROAD, - SC_FORTIFY, - SC_UPGRADE, - SC_DISBAND, - COUNT_STACKABLE_COMMANDS -}; - -enum stackable_command_kind { - SCK_BOMBARD = 0, - SCK_TERRAFORM, - SCK_UNIT_MGMT, - COUNT_STACKABLE_COMMAND_KINDS -}; - -struct sc_button_info { - enum Unit_Command_Values command; - enum stackable_command_kind kind; - int tile_sheet_column, - tile_sheet_row; -} const sc_button_infos[COUNT_STACKABLE_COMMANDS] = { - /* Bombard */ { .command = UCV_Bombard , .kind = SCK_BOMBARD , .tile_sheet_column = 3, .tile_sheet_row = 1 }, - /* Bomb */ { .command = UCV_Bombing , .kind = SCK_BOMBARD , .tile_sheet_column = 5, .tile_sheet_row = 4 }, - /* Fortress */ { .command = UCV_Build_Fortress , .kind = SCK_TERRAFORM, .tile_sheet_column = 0, .tile_sheet_row = 3 }, - /* Mine */ { .command = UCV_Build_Mine , .kind = SCK_TERRAFORM, .tile_sheet_column = 1, .tile_sheet_row = 3 }, - /* Irrigate */ { .command = UCV_Irrigate , .kind = SCK_TERRAFORM, .tile_sheet_column = 2, .tile_sheet_row = 3 }, - /* Chop For. */ { .command = UCV_Clear_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 3, .tile_sheet_row = 3 }, - /* Chop Jun. */ { .command = UCV_Clear_Jungle , .kind = SCK_TERRAFORM, .tile_sheet_column = 4, .tile_sheet_row = 3 }, - /* Plant */ { .command = UCV_Plant_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 5, .tile_sheet_row = 3 }, - /* Clean Pol. */ { .command = UCV_Clear_Pollution, .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 3 }, - /* Road */ { .command = UCV_Build_Road , .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 2 }, - /* Railroad */ { .command = UCV_Build_Railroad , .kind = SCK_TERRAFORM, .tile_sheet_column = 7, .tile_sheet_row = 2 }, - /* Fortify */ { .command = UCV_Fortify , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 2, .tile_sheet_row = 0 }, - /* Upgrade */ { .command = UCV_Upgrade_Unit , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 7, .tile_sheet_row = 1 }, - /* Disband */ { .command = UCV_Disband , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 3, .tile_sheet_row = 0 }, -}; - -enum init_state { - IS_UNINITED = 0, - IS_OK, - IS_INIT_FAILED -}; - -enum c3x_label { - CL_NEVER_COMPLETES = 0, - CL_HALTED, - CL_SURPLUS, - CL_SURPLUS_NONE, - CL_SURPLUS_NA, - CL_SB_TOOLTIP, - CL_CHOPPED, - CL_OFF, - CL_MOD_INFO_BUTTON_TEXT, - CL_VERSION, - CL_CONFIG_FILES_LOADED, - CL_CREATING_CITIES, - CL_MCS_FAILED_SANITY_CHECK, - CL_MCS_ADJACENT_CITIES, - CL_MCS_MISSING_CITIES, - CL_OBSOLETED_BY, - CL_NO_STEALTH_ATTACK, - CL_DODGED_SAM, - CL_PREVIEW, - CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP, - CL_TOTAL_CITIES, - - // Offense, Defense, Artillery, etc. - CL_FIRST_UNIT_STRAT, - CL_LAST_UNIT_STRAT = CL_FIRST_UNIT_STRAT + 19, - - // Unit actions for right-click menu - CL_IDLE, - CL_FORTIFIED, - CL_SENTRY, - CL_MINING, - CL_IRRIGATING, - CL_BUILDING_FORTRESS, - CL_BUILDING_ROAD, - CL_BUILDING_RAILROAD, - CL_PLANTING_FOREST, - CL_CLEARING_FOREST, - CL_CLEARING_WETLANDS, - CL_CLEARING_DAMAGE, - CL_BUILDING_AIRFIELD, - CL_BUILDING_RADAR_TOWER, - CL_BUILDING_OUTPOST, - CL_BUILDING_BARRICADE, - CL_BUILDING_COLONY, - CL_INTERCEPTING, - CL_MOVING, - CL_AUTOMATED, - CL_EXPLORING, - CL_BOMBARDING, - - // Generic "Building" phrase for Districts right-click menu - CL_BUILDING, - - // Districts-related texts - CL_REQUIRES, - CL_TO_GROW, - CL_DISTRICT_DESTROYED_BY_VOLCANO, - CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT, - CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD, - - CL_RECEIVED, - CL_FROM_SHARED, - CL_WITH, - - CL_APOSTROPHE_S, - CL_AND, - CL_OTHER_BUILDINGS_HAVE_BEEN, - CL_LOST_DUE_TO_DESTROYED, - - // Districts config mismatch checked on game load - CL_DISTRICT_ID, - CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW, - CL_DISTRICT_NAME_MISMATCH, - CL_SAVE_FILE_HAD, - CL_CURRENT_CONFIG_HAS_ONLY, - CL_WARNING_DISTRICTS_CONFIG_MISMATCH, - CL_MAY_BE_OTHER_ERRORS_AS_WELL, - CL_DISTRICTS_IN_SAVE_FILE, - CL_CURRENTLY_CONFIGURED_DISTRICTS, - - // Tile naming - CL_NAME_TILE, - CL_RENAME_TILE, - - // "Action" for passenger units - CL_TRANSPORTED, - - CL_IN_STATE_27, - CL_IN_STATE_28, - CL_IN_STATE_29, - CL_IN_STATE_30, - CL_IN_STATE_33, - - // For unit stats on Civilopedia - CL_HP_BONUS, - CL_WORKER_STRENGTH, - - CL_AGRICULTURAL, - CL_COMMERCIAL, - CL_EXPANSIONIST, - CL_INDUSTRIOUS, - CL_MILITARISTIC, - CL_RELIGIOUS, - CL_SCIENTIFIC, - CL_SEAFARING, - - COUNT_C3X_LABELS -}; - -struct worker_job_and_location { - enum Worker_Jobs job; - int tile_x, tile_y; -}; - -struct ai_prod_valuation { - int order_type; - int order_id; - int point_value; -}; - -enum unit_rcm_icon { - URCMI_UNMOVED = 0, - URCMI_MOVED_CAN_ATTACK, - URCMI_MOVED_NO_ATTACK, - URCMI_CANT_MOVE, - - COUNT_UNIT_RCM_ICONS -}; - -enum unit_rcm_icon_set { - URCMIS_ATTACKER = 0, - URCMIS_NONCOMBAT, - URCMIS_BUSY_ATTACKER, - URCMIS_BUSY_NONCOMBAT, - - COUNT_UNIT_RCM_ICON_SETS -}; - -enum city_gain_reason { - CGR_FOUNDED = 0, - CGR_CONQUERED, - CGR_CONVERTED, // covers culture flips & bribes - CGR_TRADED, - CGR_POPPED_FROM_HUT, - CGR_PLACED_FOR_AI_RESPAWN, - CGR_PLACED_FOR_SCENARIO, - CGR_PLACED_FOR_AI_MULTI_CITY_START, -}; - -enum city_loss_reason { - CLR_DESTROYED = 0, // means city was razed for any reason (inc. by conqueror) - CLR_CONQUERED, - CLR_CONVERTED, // covers culture flips & bribes - CLR_TRADED -}; - -enum { - MAX_DISTRICT_DEPENDENTS = 64 -}; - -enum { - DEFAULT_DISTRICT_BUILDABLE_MASK = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain) | (1 << SQ_Hills) -}; - -enum { - MAX_DISTRICT_BONUS_ENTRIES = 16 -}; - -enum district_bonus_entry_type { - DBET_TILE = 0, - DBET_BUILDING = 1 -}; - -enum great_wall_auto_build_state { - GWABS_NOT_STARTED = 0, - GWABS_RUNNING, - GWABS_DONE -}; - -struct district_bonus_entry { - enum district_bonus_entry_type type; - int bonus; - enum SquareTypes tile_type; - int building_id; - char const * building_name; -}; - -struct district_bonus_list { - int count; - struct district_bonus_entry entries[MAX_DISTRICT_BONUS_ENTRIES]; -}; - -enum district_render_strategy { - DRS_BY_COUNT = 0, - DRS_BY_BUILDING = 1 -}; - -enum district_ai_build_strategy { - DABS_DISTRICT = 0, - DABS_TILE_IMPROVEMENT = 1 -}; - -struct district_config { - enum Unit_Command_Values command; - char const * name; - char const * display_name; - char const * tooltip; - char const * advance_prereqs[MAX_DISTRICT_DEPENDENTS]; - int advance_prereq_count; - char const * obsoleted_by; - char const * resource_prereqs[MAX_DISTRICT_DEPENDENTS]; - char const * resource_prereq_on_tile; - char const * dependent_improvements[MAX_DISTRICT_DEPENDENTS]; - char const * wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; - char const * natural_wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; - char const * buildable_on_districts[MAX_DISTRICT_DEPENDENTS]; - char const * buildable_adjacent_to_districts[MAX_DISTRICT_DEPENDENTS]; - char const * img_paths[10]; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_without_removal_mask; - unsigned int buildable_on_overlays_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - bool allow_multiple; - bool vary_img_by_era; - bool vary_img_by_culture; - enum district_render_strategy render_strategy; - enum district_ai_build_strategy ai_build_strategy; - bool is_dynamic; - bool align_to_coast; - bool draw_over_resources; - bool allow_irrigation_from; - bool auto_add_road; - bool auto_add_railroad; - int custom_width; - int custom_height; - int x_offset; - int y_offset; - int resource_prereq_count; - int dependent_improvement_max_index; - int wonder_prereq_count; - int natural_wonder_prereq_count; - int buildable_on_district_count; - int buildable_adjacent_to_district_count; - int img_path_count; - int img_column_count; - bool has_img_column_count_override; - int btn_tile_sheet_column; - int btn_tile_sheet_row; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - struct district_bonus_list culture_bonus_extras; - struct district_bonus_list science_bonus_extras; - struct district_bonus_list food_bonus_extras; - struct district_bonus_list gold_bonus_extras; - struct district_bonus_list shield_bonus_extras; - struct district_bonus_list happiness_bonus_extras; - struct district_bonus_list defense_bonus_extras; - int defense_bonus_percent; - bool heal_units_in_one_turn; - bool impassible; - bool impassible_to_wheeled; - char const * generated_resource; - int generated_resource_id; - short generated_resource_flags; - int buildable_on_district_ids[MAX_DISTRICT_DEPENDENTS]; - int buildable_on_district_id_count; - bool has_buildable_on_districts; - int buildable_adjacent_to_district_ids[MAX_DISTRICT_DEPENDENTS]; - int buildable_adjacent_to_district_id_count; - bool has_buildable_adjacent_to; - bool has_buildable_adjacent_to_districts; - bool has_buildable_without_removal; - bool has_buildable_on_overlays; - bool has_buildable_adjacent_to_overlays; - bool has_buildable_on_rivers; - char const * buildable_by_civs[32]; - int buildable_by_civ_count; - bool has_buildable_by_civs; - int buildable_by_civ_traits_ids[8]; - int buildable_by_civ_traits_id_count; - bool has_buildable_by_civ_traits; - int buildable_by_civ_govs_ids[5]; - int buildable_by_civ_govs_id_count; - bool has_buildable_by_civ_govs; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_buildable_by_civ_cultures; - bool buildable_by_war_allies; - bool buildable_by_pact_allies; -}; - -struct wonder_district_config { - char const * wonder_name; - char const * img_path; - int index, - img_row, - img_column, - img_construct_row, - img_construct_column, - img_alt_dir_construct_row, - img_alt_dir_construct_column, - img_alt_dir_row, - img_alt_dir_column, - custom_width, - custom_height; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - char const * buildable_by_civs[32]; - int buildable_by_civ_count; - bool has_buildable_by_civs; - int buildable_by_civ_traits_ids[8]; - int buildable_by_civ_traits_id_count; - bool has_buildable_by_civ_traits; - int buildable_by_civ_govs_ids[5]; - int buildable_by_civ_govs_id_count; - bool has_buildable_by_civ_govs; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_buildable_by_civ_cultures; - bool enable_img_alt_dir; - bool is_dynamic; - bool has_buildable_adjacent_to; - bool has_buildable_adjacent_to_overlays; -}; - -enum square_type_extras { - SQ_INVALID = -1, - SQ_RIVER = SQ_Ocean + 1, - SQ_SNOW_VOLCANO, - SQ_SNOW_FOREST, - SQ_SNOW_MOUNTAIN -}; - -enum district_overlay_mask_bits { - DOM_MINE = 1u << 0, - DOM_IRRIGATION = 1u << 1, - DOM_FORTRESS = 1u << 2, - DOM_BARRICADE = 1u << 3, - DOM_OUTPOST = 1u << 4, - DOM_RADAR_TOWER = 1u << 5, - DOM_JUNGLE = 1u << 6, - DOM_FOREST = 1u << 7, - DOM_SWAMP = 1u << 8, - DOM_RIVER = 1u << 9, - DOM_AIRFIELD = 1u << 10 -}; - -struct natural_wonder_district_config { - char const * name; - char const * img_path; - enum SquareTypes terrain_type; - enum SquareTypes adjacent_to; - enum direction adjacency_dir; - int index; - int img_row; - int img_column; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - bool impassible; - bool impassible_to_wheeled; - bool is_dynamic; -}; - -struct natural_wonder_candidate { - Tile * tile; - short x, y; -}; - -struct natural_wonder_candidate_list { - struct natural_wonder_candidate * entries; - int count; - int capacity; -}; - -struct wonder_location { - short x; - short y; -}; - -const struct district_config special_district_defaults[USED_SPECIAL_DISTRICT_TYPES] = { - { - .command = UCV_Build_Neighborhood, .name = "Neighborhood", .tooltip = "Build Neighborhood", .display_name = "Neighborhood", - .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = true, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {"Neighborhood_AMER.pcx", "Neighborhood_EURO.pcx", "Neighborhood_ROMAN.pcx", "Neighborhood_MIDEAST.pcx", "Neighborhood_ASIAN.pcx"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 5, .img_column_count = 4, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, - .culture_bonus = 1, .science_bonus = 1, .food_bonus = 0, .gold_bonus = 1, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 25, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - - }, - { - .command = UCV_Build_WonderDistrict, .name = "Wonder District", .tooltip = "Build Wonder District", .display_name = "Wonder District", - .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {"WonderDistrict.pcx"}, - .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Coast) | (1 << SQ_Mountains)), - .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 1, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - - }, - { - .command = UCV_Build_DistributionHub, .name = "Distribution Hub", .tooltip = "Build Distribution Hub", .display_name = "Distribution Hub", - .advance_prereqs = {"Construction"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {"DistributionHub.pcx"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 2, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - - }, - { - .command = UCV_Build_Aerodrome, .name = "Aerodrome", .tooltip = "Build Aerodrome", .display_name = "Aerodrome", - .advance_prereqs = {"Flight"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 1, - .img_paths = {"Aerodrome.pcx"}, .dependent_improvements = {"Airport"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 1, .img_column_count = 2, .btn_tile_sheet_column = 3, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = -1, .name = "Natural Wonder", .tooltip = NULL, .display_name = "Natural Wonder", - .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {0}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 0, .img_column_count = 0, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_Port, .name = "Port", .tooltip = "Build Port", .display_name = "Port", - .advance_prereqs = {"Map Making"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 2, .align_to_coast = true, - .img_paths = {"Port_NW.pcx", "Port_NE.pcx", "Port_SE.pcx", "Port_SW.pcx"}, .dependent_improvements = {"Harbor", "Commercial Dock"}, - .buildable_square_types_mask = (1 << SQ_Coast), - .img_path_count = 4, .img_column_count = 4, .btn_tile_sheet_column = 4, .btn_tile_sheet_row = 0, .align_to_coast = true, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_CentralRailHub, .name = "Central Rail Hub", .tooltip = "Build Central Rail Hub", .display_name = "Central Rail Hub", - .advance_prereqs = {"Steam Power"}, .advance_prereq_count = 1, .resource_prereqs = {"Iron", "Coal"}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 2, .dependent_improvement_max_index = 0, - .img_paths = {"CentralRailHub_AMER.pcx", "CentralRailHub_EURO.pcx", "CentralRailHub_ROMAN.pcx", "CentralRailHub_MIDEAST.pcx", "CentralRailHub_ASIAN.pcx"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .auto_add_road = true, .auto_add_railroad = true, - .img_path_count = 5, .img_column_count = 2, .btn_tile_sheet_column = 5, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_EnergyGrid, .name = "Energy Grid", .tooltip = "Build Energy Grid", .display_name = "Energy Grid", - .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 4, - .img_paths = {"EnergyGrid.pcx"}, .dependent_improvements = {"Coal Plant", "Hydro Plant", "Nuclear Plant", "Solar Plant"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .custom_height = 84, - .img_path_count = 1, .img_column_count = 5, .btn_tile_sheet_column = 6, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 2, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_Bridge, .name = "Bridge", .tooltip = "Build Bridge", .display_name = "Bridge", - .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, - .img_paths = {"Bridge.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, - .buildable_square_types_mask = (1 << SQ_Coast), .auto_add_road = true, - .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 7, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_Canal, .name = "Canal", .tooltip = "Build Canal", .display_name = "Canal", - .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, - .img_paths = {"Canal.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, - .buildable_square_types_mask = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain), - .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 8, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_GreatWall, .name = "Great Wall", .tooltip = "Build Great Wall", .display_name = "Great Wall", - .advance_prereqs = {0}, .advance_prereq_count = 0, .obsoleted_by = "Metallurgy", .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, - .img_paths = {"GreatWall.pcx"}, .dependent_improvements = {0}, .custom_height = 88, .wonder_prereqs = {"The Great Wall"}, .wonder_prereq_count = 1, - .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Mountains) | (1 << SQ_Forest) | (1 << SQ_Swamp) | (1 << SQ_Jungle) | (1 << SQ_Volcano)), .draw_over_resources = true, - .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 9, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 50, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - } -}; - -struct parsed_district_definition { - char * name; - char * display_name; - char * tooltip; - char * advance_prereqs[5]; - int advance_prereq_count; - char * obsoleted_by; - char * resource_prereqs[5]; - char * resource_prereq_on_tile; - char * dependent_improvements[5]; - char * wonder_prereqs[5]; - char * natural_wonder_prereqs[5]; - char * buildable_on_districts[5]; - char * buildable_adjacent_to_districts[5]; - char * img_paths[5]; - int resource_prereq_count; - int dependent_improvement_max_index; - int wonder_prereq_count; - int natural_wonder_prereq_count; - int buildable_on_district_count; - int buildable_adjacent_to_district_count; - int img_path_count; - int img_column_count; - bool allow_multiple; - bool vary_img_by_era; - bool vary_img_by_culture; - enum district_render_strategy render_strategy; - enum district_ai_build_strategy ai_build_strategy; - bool align_to_coast; - bool draw_over_resources; - bool allow_irrigation_from; - bool auto_add_road; - bool auto_add_railroad; - bool impassible; - bool impassible_to_wheeled; - int custom_width; - int custom_height; - int x_offset; - int y_offset; - int btn_tile_sheet_column; - int btn_tile_sheet_row; - int defense_bonus_percent; - bool heal_units_in_one_turn; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - struct district_bonus_list culture_bonus_extras; - struct district_bonus_list science_bonus_extras; - struct district_bonus_list food_bonus_extras; - struct district_bonus_list gold_bonus_extras; - struct district_bonus_list shield_bonus_extras; - struct district_bonus_list happiness_bonus_extras; - struct district_bonus_list defense_bonus_extras; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_without_removal_mask; - unsigned int buildable_on_overlays_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - char * buildable_by_civs[32]; - int buildable_by_civ_count; - bool buildable_by_war_allies; - bool buildable_by_pact_allies; - bool has_name; - bool has_tooltip; - bool has_advance_prereqs; - bool has_obsoleted_by; - bool has_resource_prereqs; - bool has_dependent_improvements; - bool has_wonder_prereqs; - bool has_natural_wonder_prereqs; - bool has_display_name; - bool has_img_paths; - bool has_img_column_count; - bool has_allow_multiple; - bool has_vary_img_by_era; - bool has_vary_img_by_culture; - bool has_render_strategy; - bool has_ai_build_strategy; - bool has_align_to_coast; - bool has_draw_over_resources; - bool has_custom_width; - bool has_custom_height; - bool has_x_offset; - bool has_y_offset; - bool has_btn_tile_sheet_column; - bool has_btn_tile_sheet_row; - bool has_defense_bonus_percent; - bool has_heal_units_in_one_turn; - bool has_culture_bonus; - bool has_science_bonus; - bool has_food_bonus; - bool has_gold_bonus; - bool has_shield_bonus; - bool has_happiness_bonus; - bool has_buildable_on; - bool has_buildable_adjacent_to; - bool has_buildable_without_removal; - bool has_buildable_on_overlays; - bool has_buildable_adjacent_to_overlays; - bool has_buildable_on_rivers; - bool has_resource_prereq_on_tile; - bool has_buildable_by_civs; - bool has_buildable_by_war_allies; - bool has_buildable_by_pact_allies; - char * generated_resource; - short generated_resource_flags; - bool has_generated_resource; - char * buildable_by_civ_traits[10]; - int buildable_by_civ_traits_count; - int buildable_by_civ_traits_ids[10]; - int buildable_by_civ_traits_id_count; - bool has_buildable_by_civ_traits; - char * buildable_by_civ_govs[10]; - int buildable_by_civ_govs_count; - int buildable_by_civ_govs_ids[32]; - int buildable_by_civ_govs_id_count; - bool has_buildable_by_civ_govs; - char * buildable_by_civ_cultures[5]; - int buildable_by_civ_cultures_count; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_buildable_by_civ_cultures; - bool has_buildable_on_districts; - bool has_buildable_adjacent_to_districts; - bool has_allow_irrigation_from; - bool has_auto_add_road; - bool has_auto_add_railroad; - bool has_impassible; - bool has_impassible_to_wheeled; -}; - -struct parsed_wonder_definition { - char * name; - char * img_path; - int img_row; - int img_column; - int img_construct_row; - int img_construct_column; - int img_alt_dir_construct_row; - int img_alt_dir_construct_column; - int img_alt_dir_row; - int img_alt_dir_column; - int custom_width; - int custom_height; - bool enable_img_alt_dir; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - char * buildable_by_civs[32]; - int buildable_by_civ_count; - char * buildable_by_civ_traits[10]; - int buildable_by_civ_traits_count; - int buildable_by_civ_traits_ids[10]; - int buildable_by_civ_traits_id_count; - char * buildable_by_civ_govs[10]; - int buildable_by_civ_govs_count; - int buildable_by_civ_govs_ids[32]; - int buildable_by_civ_govs_id_count; - char * buildable_by_civ_cultures[5]; - int buildable_by_civ_cultures_count; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_name; - bool has_img_path; - bool has_img_row; - bool has_img_column; - bool has_img_construct_row; - bool has_img_construct_column; - bool has_img_alt_dir_construct_row; - bool has_img_alt_dir_construct_column; - bool has_img_alt_dir_row; - bool has_img_alt_dir_column; - bool has_custom_width; - bool has_custom_height; - bool has_enable_img_alt_dir; - bool has_buildable_on; - bool has_buildable_adjacent_to; - bool has_buildable_adjacent_to_overlays; - bool has_buildable_on_rivers; - bool has_buildable_by_civs; - bool has_buildable_by_civ_traits; - bool has_buildable_by_civ_govs; - bool has_buildable_by_civ_cultures; -}; - -struct parsed_natural_wonder_definition { - char * name; - char * img_path; - enum SquareTypes terrain_type; - enum SquareTypes adjacent_to; - enum direction adjacency_dir; - int img_row; - int img_column; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - bool impassible; - bool impassible_to_wheeled; - bool has_name; - bool has_img_path; - bool has_img_row; - bool has_img_column; - bool has_terrain_type; - bool has_adjacent_to; - bool has_adjacency_dir; - bool has_culture_bonus; - bool has_science_bonus; - bool has_food_bonus; - bool has_gold_bonus; - bool has_shield_bonus; - bool has_happiness_bonus; - bool has_impassible; - bool has_impassible_to_wheeled; -}; - -struct scenario_district_entry { - int tile_x; - int tile_y; - int has_coordinates; - char * district_name; - int has_district_name; - char * wonder_city_name; - int has_wonder_city; - char * wonder_name; - int has_wonder_name; -}; - -struct scenario_named_tile_entry { - int tile_x; - int tile_y; - int has_coordinates; - char * name; - int has_name; -}; - -struct distribution_hub_record { - Tile * tile; - int tile_x; - int tile_y; - int civ_id; - int food_yield; - int shield_yield; - int raw_food_yield; - int raw_shield_yield; -}; - -struct ai_best_feasible_order { - City_Order order; - int value; -}; - -struct district_building_prereq_list { - int count; - int district_ids[MAX_DISTRICT_DEPENDENTS]; -}; - -struct pending_district_request { - City * city; - int city_id; - int civ_id; - int district_id; - int assigned_worker_id; - int target_x; - int target_y; - int worker_assigned_turn; -}; - -struct ai_candidate_bridge_or_canal_entry { - int district_id; - short owner_civ_id; - short * tile_x; - short * tile_y; - short tile_count; - short assigned_tile_index; - int assigned_worker_id; - bool completed; - struct pending_district_request pending_req; - int tile_capacity; -}; - -struct district_worker_record { - Unit * worker; - int unit_id; - int continent_id; - struct pending_district_request * pending_req; -}; - -enum wonder_district_state { - WDS_UNUSED = 0, // Wonder district built, no wonder assigned - WDS_UNDER_CONSTRUCTION, // Reserved by a city for wonder construction - WDS_COMPLETED, // Wonder completed on this district - WDS_RUINED // (Future) Wonder was destroyed -}; - -struct wonder_district_info { - enum wonder_district_state state; - City * city; // City that reserved/completed (NULL if unused) - int city_id; - int wonder_index; // Wonder index (-1 if unused/reserved, valid if completed) -}; - -struct natural_wonder_district_info { - int natural_wonder_id; -}; - -enum district_state { - DS_UNDER_CONSTRUCTION = 0, - DS_COMPLETED = 1 -}; - -struct district_instance { - enum district_state state; - int district_id; // Index into district_configs array - int tile_x; - int tile_y; - int built_by_civ_id; - int completed_turn; - struct wonder_district_info wonder_info; // Only used if district_id is a wonder district - struct natural_wonder_district_info natural_wonder_info; // Only used if district_id is a natural wonder district -}; - -enum extra_resource_tile_type { - ERT_MILL_RESOURCE = 0, - ERT_DISTRICT_RESOURCE -}; - -struct extra_resource_tile { - Tile * tile; - enum extra_resource_tile_type type; - union { - struct { - City * city; - struct mill * mill; - } mill_info; - struct { - struct district_instance * inst; - struct district_config * cfg; - } district_info; - }; -}; - -struct named_tile_entry { - int tile_x; - int tile_y; - char name[100]; -}; - -struct highlighted_city_radius_tile_info { - int highlight_level; -}; - -struct injected_state { - // ========== - // These fields are valid at any time in the injected code because they're set by the patcher { - // ========== - - int mod_version; - // "mod relative directory" is the mod dir relative to the conquests dir. Usually it's "C3X_Rn" but it might be deeper. - // It must be non-empty and must not have an ending backslash. - char mod_rel_dir[MAX_PATH]; - - enum init_state sc_img_state; - enum init_state tile_highlight_state; - enum init_state mod_info_button_images_state; - enum init_state disabled_command_img_state; - enum init_state unit_rcm_icon_state; - enum init_state red_food_icon_state; - enum init_state distribution_hub_icons_img_state; - enum init_state tile_already_worked_zoomed_out_sprite_init_state; - enum init_state day_night_cycle_img_state; - enum init_state large_minimap_frame_img_state; - - // ========== - // } These fields are valid at any time after patch_init_floating_point runs (which is at the program launch). { - // ========== - - struct c3x_config base_config; - - // Windows modules - HMODULE kernel32; - HMODULE user32; - HMODULE msvcrt; - HMODULE msimg32; - - // Win32 API functions - WINBOOL (WINAPI * VirtualProtect) (LPVOID, SIZE_T, DWORD, PDWORD); - WINBOOL (WINAPI * CloseHandle) (HANDLE); - HANDLE (WINAPI * CreateFileA) (LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); - DWORD (WINAPI * GetFileSize) (HANDLE, LPDWORD); - WINBOOL (WINAPI * ReadFile) (HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); - HMODULE (WINAPI * LoadLibraryA) (LPCSTR); - BOOL (WINAPI * FreeLibrary) (HMODULE); - int (WINAPI * MultiByteToWideChar) (UINT, DWORD, LPCCH, int, LPWSTR, int); - int (WINAPI * WideCharToMultiByte) (UINT, DWORD, LPCWCH, int, LPSTR, int, LPCCH, LPBOOL); - int (WINAPI * GetLastError) (); - BOOL (WINAPI * QueryPerformanceCounter) (LARGE_INTEGER *); - BOOL (WINAPI * QueryPerformanceFrequency) (LARGE_INTEGER *); - void (WINAPI * GetLocalTime) (LPSYSTEMTIME); - - // Win32 funcs from user32.dll - int (WINAPI * MessageBoxA) (HWND, LPCSTR, LPCSTR, UINT); - - // Win32 funcs from Msimg32.dll - BOOL (WINAPI * TransparentBlt) (HDC, int, int, int, int, HDC, int, int, int, int, UINT); - - // C standard library functions - int (* snprintf) (char *, size_t, char const *, ...); - void * (* malloc) (size_t); - void * (* calloc) (size_t, size_t); - void * (* realloc) (void *, size_t); - void (* free) (void *); - long (* strtol) (char const *, char **, int); - float (* strtof) (char const *, char **); - int (* strcmp) (char const *, char const *); - int (* strncmp) (char const *, char const *, size_t); - int (* _stricmp) (char const *, char const *); - size_t (* strlen) (char const *); - char * (* strncpy) (char *, char const *, size_t); - char * (* strcpy) (char *, char const *); - char * (* strdup) (char const *); - char * (* strstr) (char const *, char const *); - void (* qsort) (void *, size_t, size_t, int (*) (void const *, void const *)); - int (* memcmp) (void const *, void const *, size_t); - void * (* memcpy) (void *, void const *, size_t); - void * (* memmove) (void *, void const *, size_t); - int (* tolower) (int); - int (* toupper) (int); - - Unit * sb_next_up; // The unit currently doing a stack bombard or NULL otherwise. Gets set to NULL if the unit is despawned. - - Trade_Net * trade_net; // Pointer to the trade net object. If it hasn't been moved by the mod, this equals p_original_trade_net. - int city_limit; // Stores the current actual city limit. Not necessarily the same as the stride of the trade net matrix or the config setting. - - enum init_state trade_net_addrs_load_state; - int * trade_net_addrs; - - HMODULE trade_net_x; - void (__stdcall * set_exe_version) (int); - void * (__stdcall * create_tnx_cache) (Map *); - void (__stdcall * destroy_tnx_cache) (void *); - void (__stdcall * set_up_before_building_network) (void *); - int (__stdcall * get_move_cost_for_sea_trade) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags, int neighbor_index, Trade_Net_Distance_Info * dist_info); - void (__stdcall * flood_fill_road_network) (void * tnx_cache, int from_x, int from_y, int civ_id); - bool (__stdcall * try_drawing_sea_trade_route) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags); - - void * tnx_cache; // Cache object used by Trade Net X. Initially NULL, must be recreated every time a new map is loaded. - enum init_state tnx_init_state; - bool is_computing_city_connections; // Set to true only while Trade_Net::recompute_city_connections is running - bool keep_tnx_cache; - - // This flag gets set whenever a trade deal is signed or broken for a resource that's an input to a mill. It's necessary to call - // recompute_resources in that case since a mill may have been de/activated by the change. We can't call it right when the change happens as - // that can crash the game for reasons I don't completely understand. I believe it's because the recomputation can't be done while some other - // econ logic is running. Instead, we set this variable then recompute before obsolete data would be an issue. Specifically, this is done: - // - When any player or AI begins their production phase - // - When the player zooms to any city - // - When the player opens the shift + right-click production chooser menu - // - When the player visits any advisor - // - When the player selects any unit - bool must_recompute_resources_for_mill_inputs; - - bool is_placing_scenario_things; // Set to true only while Map::place_scenario_things is running - - bool paused_for_popup; // Set to true while a popup, map message, or the diplo screen is open - long long time_spent_paused_during_popup; // Tracks time spent waiting for the three things above - - // This variable is increased with the time elapsed during every call to Trade_Net::recompute_city_connections. Time is measured using - // Windows performance counter. - long long time_spent_computing_city_connections; - int count_calls_to_recompute_city_connections; - - long long time_spent_filling_roads; - - struct c3x_config current_config; - - // Keeps a record of all configs currently loaded. Useful to know. "name" is the file name for configs that come from files, which is all of - // them except for the base config, whose name is "(base)". - struct loaded_config_name { - char * name; - struct loaded_config_name * next; - } * loaded_config_names; - - char current_districts_config_path[MAX_PATH]; - - char mod_script_path[MAX_PATH]; - - char * c3x_labels[COUNT_C3X_LABELS]; - - int have_job_and_loc_to_skip; // 0 or 1 if the variable below has anything actionable in it. Gets cleared to 0 after every turn. - struct worker_job_and_location to_skip; - - struct table saved_code_areas; - - int * unit_menu_duplicates; // NULL initialized, allocated to an array of 0x100 ints when needed - bool named_tile_menu_active; - int named_tile_menu_tile_x; - int named_tile_menu_tile_y; - - // List of temporary ints. Initializes to NULL/0/0, used with functions "memoize" and "clear_memo" - int * memo; - int memo_len; - int memo_capacity; - - // Array mapping cultural neighbor indices to the standard indices that correspond to the same tiles. Generated at program start. - byte * cultural_ni_to_standard; - - // Array mapping standard neighbor indices to the smallest work radius that includes the corresponding tile. Ex., if a given n.i. corresponds - // to one of the adjacent tiles, maps to 1, if it's in the fat cross but not adjacent, maps to 2, and so forth, out into the extended area. - char ni_to_work_radius[256]; - - // The maximum number of tiles workable by cities including the city tile itself (21 under standard game rules). Updated whenever the - // city_work_radius config value gets changed. - int workable_tile_count; - - // The civ ID of the player from whose perspective we're currently showing city loc desirability, or -1 if none. Initialized to -1. - int city_loc_display_perspective; - - // These are all bit fields that run parallel to player bits. Each bit indicates whether or not that name was replaced with an era-specific - // version for that player. This allows us to tell the difference between custom names set by human players and replacements made by the mod. - int aliased_civ_noun_bits; - int aliased_civ_adjective_bits; - int aliased_civ_formal_name_bits; - int aliased_leader_name_bits; - int aliased_leader_title_bits; - - // Stores resource access bits for resources beyond the first 32, used to fix the phantom resource bug. Initialized to NULL/0 and allocated as - // necessary by get_extra_resource_bits. Contains an array of groups of unsigned ints. There is one group per city (allocated lazily so you - // must use the getter) and the number of ints in each group depends on the number of resources defined in the scenario, one for every 32 - // after the first 32. - unsigned * extra_available_resources; - int extra_available_resources_capacity; // In number of cities. - - // These lists store interception events per-player during the interturn so we can clear the interception state on fighters that have done so - // at the beginning of their next turn. The point of this is to imitate the base game behavior where fighters that perform an interception are - // knocked out of the interception state. We can't knock them out immediately b/c that will prevent them from doing multiple interceptions per - // turn, so instead we record the event in these lists and reset their state later. - struct interceptor_reset_list { - struct interception { - int unit_id; - int x, y; - } * items; - int count; - int capacity; - } interceptor_reset_lists[32]; - - // Records the turn number on which each player has most recently founded a city. This is intended to be used for the temp settler perfume - // after founding feature so it may not be set if that feature is not activated or applicable. Defaults to -1. - int turn_no_of_last_founding_for_settler_perfume[32]; - - // Stores the byte offsets into the c3x_config struct of all boolean/integer config options, accessible using the options' names as - // strings. Used when reading in a config INI file. - struct table boolean_config_offsets; - struct table integer_config_offsets; - - // Maps unit types IDs to AI strategy indices (0 = offense, 1 = defense, 2 = artillery, etc.). If a unit type ID is in this table, that means - // it's one of several duplicate types created to spread multiple AI strategies out so each type has only one. - struct table unit_type_alt_strategies; - - // Stores a linked list of unit type duplicates. Maps unit type IDs to the next duplicate ID. Use list_unit_type_duplicates to get the list of - // the duplicates of a particular type as an array. - struct table unit_type_duplicates; - - // Tracks the number of "extra" defensive bombards units have performed, by their IDs. If the "blitz" special defensive bombard rule is - // activated, units with blitz get an extra chance to perform DB for each movement point they have beyond the first. - struct table extra_defensive_bombards; - - // Table mapping unit IDs to how many times that unit has airdropped on the current turn. This is used to prevent units from airdropping - // multiple times. That doesn't matter for the base game but stops the dont-end-turn-after-airdrop setting from letting units airdrop an - // unlimited number of times. - struct table airdrops_this_turn; - - // Stores city improvement bits for improvs beyond the first 256 - struct table extra_city_improvs; - - // These variables store the number of units of each type that each player has - int unit_type_count_init_bits; // Player bits tracking which unit type count tables have been initialized. - struct table unit_type_counts[32]; // One table per player. Each one maps unit type ids (ints) to counts (ints) - - // ========== - // } These fields are valid only after init_stackable_command_buttons has been called. { - // ========== - - struct sc_button_image_set { - Sprite imgs[4]; - } sc_button_image_sets[COUNT_STACKABLE_COMMANDS]; - - int sb_activated_by_button; // Gets set to 1 when the player clicks on the SB button so that perform_action_on_tile knows - // to do stack instead of regular bombard. This is necessary since the SB button actually just activates regular bombard. - // The proper way to implement the SB button would be to give it its own mode action but that's difficult to do because - // the existing mode actions are baked into the code. Implementing it this way I estimate is less fragile and requires - // less patching. The hard part is knowing when to clear this flag so that the player doesn't activate SB, cancel it, then - // activate regular bombard and get SB instead. One trick to make this easier is to look for the change of cursor away - // from the little bomb indicator instead of trying to intercept every relevant UI event. This flag is changed in these - // circumstances: - // (1) At init, the flag is cleared, of course. - // (2) Pressing the SB button sets the flag and pressing another unit command button clears it. - // (3) If handle_cursor_change_in_jgl is called and the main_screen_form's Mode_Action isn't (air) bombard, the flag - // is cleared. That covers every case of switching off SB mode except one, when the player presses a key to switch - // off of SB to regular bombard, that's what case (4) is for. - // (4) The flag is cleared when the player presses the B key or (if the unit is capable of precision strikes) the P key. - // One final complication, that I only discovered after trying to implement this, is that when clicking on the map with a - // mode action, the cursor is cleared before the action is carried out. So we have to intercept that map click as well for - // a total of 4 UI functions patched to make this damn button work. I doubt this is optimal but it works and I've wasted - // enough time on this already. That click interceptor sets a flag value of 2 to indicate this annoying state. - - // ========== - // } This field is only valid after init_disabled_command_buttons has been called and disabled_command_img_state equals IS_OK { - // ========== - - Sprite disabled_build_city_button_img; - - // ========== - // } This field is only valid after init_unit_rcm_icons has been called and unit_rcm_icon_state equals IS_OK { - // ========== - - // Sprites are stored together as sets, so the first COUNT_UNIT_RCM_ICONS elements are those from the first set, then the same number from the - // second set, etc. - Sprite unit_rcm_icons[COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS]; - - // ========== - // } These fields are valid only after init_tile_highlights as been called. { - // ========== - - Sprite tile_highlights[COUNT_TILE_HIGHLIGHTS]; - - // ========== - // } This one is valid only if init_mod_info_button_images has been called and mod_info_button_images_state equals IS_OK { - // ========== - - Sprite mod_info_button_images[3]; - - // ========== - // } This one is valid only if init_red_food_icon has been called and red_food_icon_state equals IS_OK { - // ========== - - Sprite red_food_icon; - - // ========== - // } These are valid only if init_large_minimap_frame has been called and large_minimap_frame_img_state equals IS_OK { - // ========== - - Sprite double_size_box_left_color_pcx, double_size_box_left_alpha_pcx; - - // ========== - // } These fields are temporary/situational { - // ========== - - int saved_road_movement_rate; // Valid when railroad movement limit is applied (limit_railroad_movement > 0) and BIC data has been loaded - int road_mp_cost; // The cost of moving one tile along a road, in MP. Valid after BIC data was loaded. - int railroad_mp_cost_per_move; // The cost of moving one tile along a railroad, in MP, per move available to the unit. This is measured per - // move since the cost of moving along a railroad is scaled by the total number of moves available to the - // unit. Valid after BIC data was loaded. - - int saved_barb_culture_group; // Valid when barb city capturing is enabled and BIC data has been loaded - - Leader * leader_param_for_patch_get_wonder_city_id; // Valid in patch_get_wonder_city_id when called from - // Leader_recompute_auto_improvements - - int show_popup_was_called; // Set to 1 in show_popup. Used in patch_Leader_can_do_worker_job to check if the replacement - // popup was shown. - - // Used to control trade screen scroll - int open_diplo_form_straight_to_trade; // Initialized to 0, gets set to 1 by patch_DiploForm_do_diplomacy to signal - // to patch_DiploForm_m68_Show_Dialog to open the diplo form straight into trade mode. - int trade_screen_scroll_to_id; // Set by patch_DiploForm_m82_handle_key_event to signal to do_diplomacy that the form - // was closed in order to scroll to the civ with the set ID. -1 indicates no scrolling. - Button * trade_scroll_button_left; // initialized to NULL - Button * trade_scroll_button_right; // initialized to NULL - Sprite * trade_scroll_button_images; // inited to NULL, array of 6 images: normal, rollover, and highlight for left & right - enum init_state trade_scroll_button_state; - int eligible_for_trade_scroll; - - char ask_gold_default[32]; - - // Set in patch_ai_choose_production, used by the various bits of injected code that run during the AI production choosing process. - City * ai_considering_production_for_city; - - // This variable stores what improvement or unit the AI is evaluating inside ai_choose_production. It gets set inside two call replacements, - // first inside the loop over improvements then again inside a loop over unit types. The var is used by the intercept consideration functions - // which run at the end of each loop iteration. - City_Order ai_considering_order; - int handling_ai_district_fallback; - - // Used in the code that adds additional info to the tile info box - bool tile_info_open; - int viewing_tile_info_x, viewing_tile_info_y; - - // Used in patch_Tile_m43_Get_field_30_for_city_loc_eval to change how the AI evaluates overlap between cities - int ai_evaling_city_loc_x, ai_evaling_city_loc_y; - int ai_evaling_city_field_30_get_counter; - - // Stores a list of the production options in a given city and the point value the AI would assign to each. The list is populated by - // rank_ai_production_options, items are added by record_improv_val which gets called by some code injected into one of the loops in - // ai_choose_production. These vars are initialized to zero. - struct ai_prod_valuation * ai_prod_valuations; - int count_ai_prod_valuations; - int ai_prod_valuations_capacity; - - // Used for generating resources from buildings and districts - struct extra_resource_tile * resource_tiles; - int count_resource_tiles; - int resource_tiles_capacity; - struct extra_resource_tile * got_resource_tile; - int saved_tile_count; // Stores the actual tile count in case p_bic_data->Map.TileCount was temporarily overwritten. Set to -1 when empty. - byte * mill_input_resource_bits; // Array of bits, one for each resource. Stores whether or not each one is an input to any mill. - - // Used for displaying yields from generated resources on the city screen - int tourism_icon_counter; // Incremented each time a tourism yield icon (normally commerce) is drawn. Reset between improvs. - int convert_displayed_tourism_to_food, convert_displayed_tourism_to_shields; // Number of commerce tourism icons to convert to food, shields - int combined_tourism_and_mill_commerce; // Number of commerce tourism icons to display inc. from mills, maybe negative - - int drawing_icons_for_improv_id; // Stores the improv ID whose icons we're drawing. -1 while not drawing. - - PCX_Image * resources_sheet; // Sprite sheet of resource icons, i.e. resources.pcx - - Sprite tile_already_worked_zoomed_out_sprite; // Valid only if init state is OK - - // Only for use by patch_City_Form_draw_yields_on_worked_tiles and patch_Sprite_draw_already_worked_tile_img - bool do_not_draw_already_worked_tile_img; - - // Stores the trade offer object being modified when the user right-clicks on a gold offer/ask on the trade table. Gets set by a special - // function call replacement (see apply_machine_code_edits for details). - TradeOffer * modifying_gold_trade; - - // Initialized to NULL and reset to NULL after Unit::bombard_tile returns. Gets set just before the call to Unit::play_bombard_fire_animation - // from inside bombard_tile. The value is the unit on the bombarded tile specifically targeted by the attack, if applicable. - Unit * bombard_stealth_target; - - // Set to zero when Unit::select_stealth_attack_target is called then checked inside in the call to PopupSelection::add_item and set to - // 1. This variable lets the add_item replacement function run special code for only the first item added, in order to insert an additional - // first option to cancel the stealth attack. - int added_any_stealth_target; - - // Initialized to zero. Temporarily set to 1 across a call to patch_Unit_select_stealth_attack_target to request that the selected target must - // be suitable for attack via bombardment. - int selecting_stealth_target_for_bombard; - - // Set in rand_int_to_dodge_city_aa and read immediately after in Unit_get_defense_to_dodge_city_aa. Allows us to determine whether the dodge - // roll was successful in order to popup the message. - int result_of_roll_to_dodge_city_aa; - - // Initialized to NULL. If set to non-NULL, the next call to show_map_message will consume that value and use it as the text on the - // message. Used to implement show_map_specific_text. - char const * map_message_text_override; - - // Initialized to NULL. If set to non-NULL, the next call to do_load_game will consume this value and use it as the file path of the game to - // load instead of opening the file picker. - char const * load_file_path_override; - - // A set of player bits indicating which players should see a replay of the AI's moves. Normally all zero, gets filled in by - // patch_perform_interturn_in_main_loop only when/as appropriate. As replays are played (in patch_show_movement_phase_popup), the - // corresponding bits are cleared. - int replay_for_players; - - // Used by patch_perform_interturn_in_main_loop to determine which players need to see the replay. Clear before interturn processing, then - // every time an AI unit moves onto or bombards a tile, any players that have vision on that tile will have their bit set in this var. - int players_saw_ai_unit; - - // Initialized to 0. If set to non-zero, the next call to do_load_game will consume the value and skip the intro popup. - int suppress_intro_after_load_popup; - - struct improv_id_list { - int * items; - int count; - int capacity; - } water_trade_improvs, air_trade_improvs, combat_defense_improvs; - - // Used by the fix for the barbarian diagonal bug - int barb_diag_patch_dy_fix; - - // Initialized to 0. If 1, barbarian activity is force activated b/c there are barb cities on the map that need to do production. - int force_barb_activity_for_cities; - - // Used as a stand-in for an actual tile where needed. In particular, this object is returned from various get_tile and tile_at replacements - // when we need to override the visibility data to implement hotseat shared vis. - Tile * dummy_tile; - - // When the game checks visibility for a tile, it accesses all four visibility fields with separate calls to Map::get_tile and/or tile_at. We - // replace the first call, maybe altering its return to implement shared visibility, cache the return in this variable, then re-use the cached - // value for the next three calls. - Tile * tile_returned_for_visibility_check; - - // Initialized to all -1. If set, the unit with the specified ID will always be the top unit displayed on the specified tile. If the unit is - // not on that tile, there is no effect. This is only intended to be used on a temporary basis. - struct unit_display_override { - int unit_id, tile_x, tile_y; - } unit_display_override; - - // Set in patch_Fighter_get_odds_for_main_combat_loop, read by patch_Unit_get_attack/defense_strength. - // Stores counter multipliers for the current combat. Active only during Fighter_get_combat_odds call. - struct { - bool active; - Unit * attacker; - Unit * defender; - int attacker_atk_pct; // Attacker attack multiplier (combines forward self-atk and reverse enemy-atk) - int defender_def_pct; // Defender defense multiplier (combines forward enemy-def and reverse self-def) - bool ignore_terrain; - } counter_combat_ctx; - - // Used to extract which unit (if any) exerted zone of control from within Fighter::apply_zone_of_control. - Unit * zoc_interceptor; - - // Set when Fighter::apply_zone_of_control is called to store the defending unit, used by the injected filter and Unit::move_to_adjacent_tile. - // Cleared at each call to move_to_adjacent_tile and by Unit::despawn. - Unit * zoc_defender; - - // Set to the bombarding unit while Unit::bombard_tile is running. NULL otherwise. - Unit * bombarding_unit; - - // Normally set to NULL. When a unit bombards a tile (the tile itself, not something on it), set to point to that unit during the call to - // Unit::attack_tile. Used to stop the unit from losing all of its movement if configured. - Unit * unit_bombard_attacking_tile; - - // Set to the coords of the tile being attacked while Unit::attack_tile is running, -1 otherwise. - int attacking_tile_x, attacking_tile_y; - - // Cleared to false when Fighter::apply_zone_of_control is called. The interceptor must be unfortified to ensure it plays its animation. If - // that happens, this flag is set so that apply_zone_of_control knows to refortify the unit after the ZoC process is done. - bool refortify_interceptor_after_zoc; - - // These flags are used to turn off lethal ZoC for units that capture an enemy on the tile they're moving into. Without this rule, the unit - // might get killed by ZoC but the captured units will remain on a tile that was never actually entered (that tile might have an enemy city - // for extra weirdness). Here's how it works: - // 1. The moving_unit_to_adjacent_tile flag is set when Unit::move_to_adjacent_tile is called. - // 2. If that flag is set and a unit is captured (detected by intercepting the calls to Leader::spawn_unit inside Unit::do_capture_units) - // then temporarily_disallow_lethal_zoc is set. - // 3. If temporar... is set, the code to filter ZoC interceptors acts as if lethal ZoC were turned off. - // 4. Both flags are cleared when Unit::move_to_adjacent_tile returns. - bool temporarily_disallow_lethal_zoc; - bool moving_unit_to_adjacent_tile; - - // Tracks temporary transport bypass when letting workers step onto coast tiles without a boat - Unit * coast_walk_unit; - bool coast_walk_transport_override; - enum UnitStateType coast_walk_prev_state; - int coast_walk_prev_container; - bool coast_walk_restore_goto_path; - int coast_walk_prev_path_len; - int coast_walk_prev_path_dest_x; - int coast_walk_prev_path_dest_y; - Unit * move_spend_override_unit; - int move_spend_override_value; - - // Used to record info about a defensive bomardment event during Fighter::fight. Gets set by Fighter::damage_by_defensive_bombardment and - // cleared when Fighter::fight returns. - struct defensive_bombard_event { - Unit * bombarder; - Unit * defender; - bool damage_done, defender_was_destroyed, saved_animation_setting; - } dbe; - - // Set to true IFF we're showing a replay of AI moves in hotseat mode - bool showing_hotseat_replay; - - // Set to true only during the first call to get_tile_occupier_id from Trade_Net::get_movement_cost. While this is set, we need to edit unit - // visibility to patch the submarine bug. - bool getting_tile_occupier_for_ai_pathfinding; - - bool running_on_wine; // Set to 1 IFF we're running in Wine, as opposed to actual Windows - - // gdi_plus.init_state is valid any time after patch_init_floating_point. All the other fields are only valid after set_up_gdi_plus has been - // called and gdi_plus.init_state equals IS_OK. - struct gdi_plus { - enum init_state init_state; - HMODULE module; - ULONG_PTR token; - void * gp_graphics; - - int (__stdcall * CreateFromHDC) (HDC hdc, void ** p_gp_graphics); - int (__stdcall * DeleteGraphics) (void * gp_graphics); - int (__stdcall * SetSmoothingMode) (void * graphics, int smoothing_mode); - int (__stdcall * SetPenDashStyle) (void * gp_pen, int dash_style); - int (__stdcall * CreatePen1) (unsigned int argb_color, float width, int gp_unit, void ** p_gp_pen); - int (__stdcall * DeletePen) (void * gp_pen); - int (__stdcall * DrawLineI) (void * gp_graphics, void * gp_pen, int x1, int y1, int x2, int y2); - } gdi_plus; - - // These variables track the states of some OpenGL parameters. They're updated whenever methods like OpenGLRenderer::set_color are called. - unsigned int ogl_color; - int ogl_line_width; - bool ogl_line_stipple_enabled; - - // Records how many units of each type we're going to upgrade to during an upgrade-all. This info will be used to impose the unit type limit - // during the upgrade. Keep in mind units all get upgraded from the same type but might end up as different types after upgrade-all. - struct penciled_in_upgrade { - int unit_type_id; - int count; - } * penciled_in_upgrades; - int penciled_in_upgrade_count; - int penciled_in_upgrade_capacity; - - // While in Leader::do_capture_city, the city in question is stored in this var. Otherwise it's NULL. - City * currently_capturing_city; - - // While a game is being saved or loaded, this variable points to the save file's MappedFile object. Otherwise it's NULL. - MappedFile * accessing_save_file; - - // Used in patch_work_simple_job. If a method sets this variable while that method is running then at the end it sets the given tile as LM. - Tile * lmify_tile_after_working_simple_job; - - // Reset to zero every time City_Form::draw is called. Incremented everything a strategic resource is drawn on the city screen. - int drawn_strat_resource_count; - - int * charmed_types_converted_to_ptw_arty; - int count_charmed_types_converted_to_ptw_arty; - int charmed_types_converted_to_ptw_arty_capacity; - - // While Unit::is_visible_to_civ is running, this var is set to the unit in question. Otherwise it's NULL. - Unit * checking_visibility_for_unit; - - // Normally false. When true, calls to bounce_trespassing_units won't kick out invisible units even if they're revealed. - bool do_not_bounce_invisible_units; - - // Normally false. When true, Unit::despawn also despawns any passenger units inside instead of making exceptions in some cases. - bool always_despawn_passengers; - - // Normally false. When true, calls to Unit::score_kill will not enslave. - bool do_not_enslave_units; - - // If limit_unit_loading_to_one_transport_per_turn is on, maps unit IDs to the ID of the transport unit they're tied to for the current turn. - struct table unit_transport_ties; - - // Initialized to NULL/0, used in patch_City_add_happiness_from_buildings - short * saved_improv_counts; - int saved_improv_counts_capacity; - - // Used to de-overlap specialist yield icons (option name fix_overlapping_specialist_yield_icons) - int specialist_icon_drawing_running_x; - - // Initialized to 0, used to draw multipage descriptions in the Civilopedia - struct civilopedia_multipage_description { - bool drawing_lines; - int line_count; - int shown_page; // zero-based - int last_page; // also zero-based - Civilopedia_Article * article; - Button * effects_btn; - Button * previous_btn; - } cmpd; - - // When expand_civilopedia_unit_stats is on, all the game's calls to draw_and_wrap_text to draw the second column of unit stats are - // intercepted to draw nothing and store their strings here. Then we possible add some entries of our own. The game will add up to 6 entries - // and we'll add up to 4. - char * pedia_unit_stats_second_column_strs[10]; - - // Day-Night cycle data - int current_day_night_cycle; - bool day_night_cycle_unstarted; // If current_day_night_cycle has not been set, f.e. because it's the first turn of a new game. - bool day_night_cycle_img_proxies_indexed; - LARGE_INTEGER last_day_night_cycle_update_time; - - struct table day_night_sprite_proxy_by_hour[24]; - - struct wonder_district_image_set { - Sprite img; - Sprite construct_img; - Sprite alt_dir_img; - Sprite alt_dir_construct_img; - } wonder_district_img_sets[MAX_WONDER_DISTRICT_TYPES]; - - struct natural_wonder_district_image_set { - Sprite img; - } natural_wonder_img_sets[MAX_NATURAL_WONDER_DISTRICT_TYPES]; - struct natural_wonder_label_draw_info { - int text_left; - int text_top; - int text_width; - int font_size; - char const * text; - }; - - struct day_night_cycle_img_set - { - SpriteList Std_Terrain_Images[9]; - SpriteList LM_Terrain_Images[9]; - Sprite City_Images[80]; - Sprite Destroyed_City_Images[3]; - Sprite Resources[36]; - Sprite ResourcesShadows[36]; - Sprite Terrain_Buldings_Barbarian_Camp; - Sprite Terrain_Buldings_Mines; - Sprite Victory_Image; - Sprite Flood_Plains_Images[16]; - Sprite Fog_Of_War_Images[81]; - Sprite Polar_Icecaps_Images[32]; - Sprite Railroads_Images[272]; - Sprite Roads_Images[256]; - Sprite Minor_Roads_Images[256]; - Sprite Terrain_Buldings_Airfields[2]; - Sprite Terrain_Buldings_Airfields_Shadow[2]; - Sprite Terrain_Buldings_Camp[4]; - Sprite Terrain_Buldings_Fortress[4]; - Sprite Terrain_Buldings_Barricade[4]; - Sprite Goody_Huts_Images[8]; - Sprite Terrain_Buldings_Outposts[3]; - Sprite Terrain_Buldings_Outposts_Shadow[3]; - Sprite Pollution[25]; - Sprite Craters[25]; - Sprite Terrain_Buldings_Radar; - Sprite Terrain_Buldings_Radar_Shadow; - Sprite Tnt_Images[18]; - Sprite Waterfalls_Images[4]; - Sprite LM_Terrain[7]; - Sprite Marsh_Large[8]; - Sprite Marsh_Small[10]; - Sprite Volcanos_Images[16]; - Sprite Volcanos_Forests_Images[16]; - Sprite Volcanos_Jungles_Images[16]; - Sprite Volcanos_Snow_Images[16]; - Sprite Grassland_Forests_Large[8]; - Sprite Plains_Forests_Large[8]; - Sprite Tundra_Forests_Large[8]; - Sprite Grassland_Forests_Small[10]; - Sprite Plains_Forests_Small[10]; - Sprite Tundra_Forests_Small[10]; - Sprite Grassland_Forests_Pines[12]; - Sprite Plains_Forests_Pines[12]; - Sprite Tundra_Forests_Pines[12]; - Sprite Irrigation_Desert_Images[16]; - Sprite Irrigation_Plains_Images[16]; - Sprite Irrigation_Images[16]; - Sprite Irrigation_Tundra_Images[16]; - Sprite Grassland_Jungles_Large[8]; - Sprite Grassland_Jungles_Small[12]; - Sprite Mountains_Images[16]; - Sprite Mountains_Forests_Images[16]; - Sprite Mountains_Jungles_Images[16]; - Sprite Mountains_Snow_Images[16]; - Sprite Hills_Images[16]; - Sprite Hills_Forests_Images[16]; - Sprite Hills_Jungle_Images[16]; - Sprite Delta_Rivers_Images[16]; - Sprite Mountain_Rivers_Images[16]; - Sprite Territory_Images[8]; - Sprite LM_Mountains_Images[16]; - Sprite LM_Forests_Large_Images[8]; - Sprite LM_Forests_Small_Images[10]; - Sprite LM_Forests_Pines_Images[12]; - Sprite LM_Hills_Images[16]; - Sprite District_Images[COUNT_DISTRICT_TYPES][MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [district][variant][era][column] - Sprite Abandoned_District_Image; - Sprite Abandoned_Maritime_District_Image; - struct wonder_district_image_set Wonder_District_Images[MAX_WONDER_DISTRICT_TYPES]; - struct natural_wonder_district_image_set Natural_Wonder_Images[MAX_NATURAL_WONDER_DISTRICT_TYPES]; - } day_night_cycle_imgs[24]; - - // Districts - enum init_state dc_img_state; - enum init_state dc_btn_img_state; - enum init_state dc_icons_img_state; - - struct district_config district_configs[COUNT_DISTRICT_TYPES]; - struct wonder_district_config wonder_district_configs[MAX_WONDER_DISTRICT_TYPES]; - struct natural_wonder_district_config natural_wonder_configs[MAX_NATURAL_WONDER_DISTRICT_TYPES]; - -struct district_image_set { - Sprite imgs[MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [variant][era][column] -} district_img_sets[COUNT_DISTRICT_TYPES]; - Sprite abandoned_district_img; - Sprite abandoned_maritime_district_img; - -struct district_button_image_set { - Sprite imgs[4]; -} district_btn_img_sets[COUNT_DISTRICT_TYPES]; - - // Building ID keys -> district ID. If a building ID is present in the - // table that means that building can only be built if there is a corresponding district is present in the city radius. - struct table district_building_prereqs; - - // Tile pointer IDs -> district_instance pointer. Maps tiles to dynamically allocated - // district_instance structs tracking district type and state (UNDER_CONSTRUCTION or COMPLETED). - // For wonder districts, the wonder_info field tracks wonder-specific state (unused, reserved, completed, ruined), - // which city reserved/completed the wonder, and which wonder index is on this district. - struct table district_tile_map; - struct table named_tile_map; - - // Tracks per-turn airlift usage for aerodrome districts (tile pointer -> civ bitmask). - struct table aerodrome_airlift_usage; - - // Command ID keys -> district ID. Used to identify which district - // a unit command (e.g., build order) corresponds to. - struct table command_id_to_district_id; - - // Array of 32 tables (one per civ) of pending district requests keyed by city & district (values are struct pending_district_request pointers). - struct table city_pending_district_requests[32]; - - // City pointer keys -> improvement ID. Tracks which improvements (buildings/wonders) - // requiring districts a city has ordered to be built (pending district completion). - struct table city_pending_building_orders; - - // AI cache mapping city pointer keys -> AI_Order pointer. Stores the best feasible - // production order for AI cities to optimize decision-making. - struct table ai_best_feasible_orders; - - // String building/wonder name keys -> int building/improvement ID. - // Used to look up building IDs by their text names from the game data. - struct table building_name_to_id; - - struct district_infos { - int advance_prereq_ids[MAX_DISTRICT_DEPENDENTS]; // Tech IDs that enable the district (all required) - int advance_prereq_count; - int obsoleted_by_id; - int resource_prereq_ids[MAX_DISTRICT_DEPENDENTS]; - int resource_prereq_count; - int resource_prereq_on_tile_id; - int wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; - int wonder_prereq_count; - int natural_wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; - int natural_wonder_prereq_count; - int dependent_building_count; - int dependent_building_ids[MAX_DISTRICT_DEPENDENTS]; // Building types the district enables - } district_infos[COUNT_DISTRICT_TYPES]; - - // District tracking counters: total = special (hard-coded) + dynamic (from config/scenario) - // next_custom_dynamic_command_index assigns unique command IDs for custom dynamic commands - int district_count; - int special_district_count; - int dynamic_district_count; - int wonder_district_count; - int natural_wonder_count; - int next_custom_dynamic_command_index; - - // Distribution Hub tracking: records keyed by tile plus per-tile coverage counts; dirty/refresh flags - // control when totals are recalculated - struct table distribution_hub_records; - struct table distribution_hub_coverage_counts; - bool distribution_hub_totals_dirty; - bool distribution_hub_refresh_in_progress; - - // Distribution Hub UI sprites loaded from PCX files for rendering food/shield icons in city interface - // *_icons_remaining counters track how many icons to draw from each source (non-district, district, hub, corruption) - Sprite distribution_hub_shield_icon; - Sprite distribution_hub_corruption_icon; - Sprite distribution_hub_food_icon; - Sprite distribution_hub_eaten_food_icon; - Sprite distribution_hub_shield_icon_small; - Sprite distribution_hub_food_icon_small; - int non_district_shield_icons_remaining; - int corruption_shield_icons_remaining; - int district_shield_icons_remaining; - int distribution_hub_shield_icons_remaining; - int district_corruption_icons_remaining; - int distribution_hub_corruption_icons_remaining; - - // District UI sprites loaded from PCX files for rendering yield icons (science, commerce, shield, food, culture, happiness) - // Available in both regular and small sizes for different UI contexts in city interface - Sprite district_science_icon; - Sprite district_commerce_icon; - Sprite district_shield_icon; - Sprite district_corruption_icon; - Sprite district_food_icon; - Sprite district_food_eaten_icon; - Sprite district_happiness_icon_small; - Sprite district_shield_icon_small; - Sprite district_commerce_icon_small; - Sprite district_food_icon_small; - Sprite district_science_icon_small; - Sprite district_culture_icon_small; - Sprite district_unhappiness_icon_small; - Sprite district_negative_shield_icon_small; - Sprite district_negative_commerce_icon_small; - Sprite district_negative_food_icon_small; - Sprite district_negative_science_icon_small; - Sprite district_negative_culture_icon_small; - - // Guard to prevent recursive sharing when auto-adding buildings across cities - bool sharing_buildings_by_districts_in_progress; - - // Worker tracking: 32 tables (one per civ), each mapping unit_id -> district_worker_record pointer - struct table district_worker_tables[32]; - - // Natural Wonder labels: table mapping natural wonder name strings to their IDs, count of defined natural wonders, - struct table natural_wonder_name_to_id; - - struct ai_candidate_bridge_or_canal_entry * ai_candidate_bridge_or_canals; - int ai_candidate_bridge_or_canals_count; - int ai_candidate_bridge_or_canals_capacity; - bool ai_candidate_bridge_or_canals_initialized; - - // City work radius highlighting: flag to enable/disable, table mapping tile pointers to highlight_level for visual feedback - bool highlight_city_radii; - struct table highlighted_city_radius_tile_pointers; - - // Initialized to 0. Every time Main_Screen_Form::m82_handle_key_event receives an event with is_down == 0, the virtual key code is prepended - // to this list. - int last_main_screen_key_up_events[5]; - - // Stores the parameters to Unit::can_load while it's running, NULL otherwise. - Unit * can_load_transport, * can_load_passenger; - - // Current tile being rendered in Map_Renderer_m19_Draw_Tile_by_XY_and_Flags. For use within various Map_Renderer::impl_m*_Draw_* functions. Nulled out after the render function is complete - Tile * current_render_tile; - struct district_instance * current_render_tile_district; - int current_render_tile_x, current_render_tile_y; - - // Used in patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp and so on for flagging whether to draw forests over roads on the tile being rendered - bool draw_forests_over_roads_on_tile; - - // Set to true once the auto-build process for the Great Wall is complete to avoid running it again - enum great_wall_auto_build_state great_wall_auto_build; - Tile * focused_tile; - - // Stores the improve ID currently being evaluated inside patch_City_can_build_improvement. - int current_evaluating_improve_id; - - // Stores the index in the list of target civs currently being drawn on the espionage form. Used to replace the civ name with its era-specific alias. - int espionage_form_drawing_target_index; - - // Tracks information about the last unit that was selected. These fields are updated when a new unit is selected or when the selected unit - // moves or is destroyed. - struct { - int initial_x, initial_y; // Stores the unit's location when it was selected - int last_x, last_y, type_id; // Stores the unit's current or last available location and type id - Unit * ptr; // A pointer to the unit, may be NULL if the unit was destroyed - } last_selected_unit; - - // Maps unit IDs to the level at which they are waiting. Units with lower levels move first. Units that have not been set to wait are not in the table. - struct table waiting_units; - - // Set to true when waiting_units has been initialized by loading from the save. Causes the game to skip clearing the table when setting up - // unit cycling for the turn. - bool have_loaded_waiting_units; - - // Used in patch_Unit_do_capture_units and patch_Unit_despawn - Unit ** extra_capture_despawns; - int count_extra_capture_despawns; - int extra_capture_despawns_capacity; - - // ========== - // } - // ========== -}; - -enum object_job { - OJ_DEFINE = 0, - OJ_INLEAD, // Patch this function with an inlead - OJ_REPL_VPTR, // Patch this function by replacing a pointer to it. The address column is the addr of the VPTR not the function itself. - OJ_REPL_CALL, // Patch a single function call. The address column is the addr of the call instruction, name refers to the new target function, type is not used. - OJ_REPL_VIS, // Patch a cluster of four function calls that make up a check of tile visibility. See implementation for details. - OJ_EXT_WALUP, // "EXTend Work Area LuP" Patch a jump instruction at the end of a "lup" (loop) over a city's workable area to extend it - OJ_IGNORE -}; - -struct civ_prog_object { - enum object_job job; - int addr; - char const * name; - char const * type; -}; +#include + +#define NOVIRTUALKEYCODES // Keycodes defined in Civ3Conquests.h instead +#include "windows.h" + +typedef unsigned char byte; + +// Use fastcall as substitute for thiscall because TCC doesn't recognize thiscall +#define __fastcall __attribute__((fastcall)) +#include "Civ3Conquests.h" + +#define MOD_VERSION 2700 +#define MOD_PREVIEW_VERSION 2 + +#define COUNT_TILE_HIGHLIGHTS 11 +#define MAX_BUILDING_PREREQS_FOR_UNIT 10 + +#define COUNT_SPECIAL_DISTRICT_TYPES 10 +#define USED_SPECIAL_DISTRICT_TYPES 11 +#define MAX_DYNAMIC_DISTRICT_TYPES 22 +#define COUNT_DISTRICT_TYPES (COUNT_SPECIAL_DISTRICT_TYPES + MAX_DYNAMIC_DISTRICT_TYPES) +#define MAX_WONDER_DISTRICT_TYPES 32 +#define MAX_NATURAL_WONDER_DISTRICT_TYPES 32 +#define MAX_DISTRICT_VARIANT_COUNT 5 +#define MAX_DISTRICT_ERA_COUNT 4 +#define MAX_DISTRICT_COLUMN_COUNT 10 +#define C3X_DISTRICT_COMMAND_BASE (-11000000) + +// Initialize to zero. Implementation is in common.c +struct table { + void * block; + size_t capacity_exponent; // Actual capacity is 1 << capacity_exponent + size_t len; +}; + +// Initialize to zero. Implementation in common.c +struct buffer { + byte * contents; + int length; + int capacity; +}; + +// A mill is a city improvement that spawns a resource. These are read from the "buildings_generating_resources" key in the config but are called +// "mills" internally for brevity. +enum mill_flag { + MF_LOCAL = 1, + MF_NO_TECH_REQ = 2, + MF_YIELDS = 4, + MF_SHOW_BONUS = 8, + MF_HIDE_NON_BONUS = 16 +}; +struct mill { + short improv_id; + short resource_id; + short flags; +}; + +#define ERA_ALIAS_LIST_CAPACITY 4 // Must not exceed 32 so we can store all genders as bits in an int + +// A list of per-era aliases for a civ's noun, adjective, or formal name. +struct civ_era_alias_list { + char * key; + char * aliases[ERA_ALIAS_LIST_CAPACITY]; +}; + +// A list of per-era aliases for a civ's leader's name, including genders and (optionally) titles. +struct leader_era_alias_list { + char * key; + char * aliases[ERA_ALIAS_LIST_CAPACITY]; + int gender_bits; // Gender of each alias. Like LeaderGender in the Race object, 0 for male and 1 for female. + char * titles[ERA_ALIAS_LIST_CAPACITY]; // Title for each alias. May be NULL. +}; + +struct unit_type_limit { + int per_civ; + int per_city; + int cities_per; +}; + +struct work_area_improvement { + short improv_id; + int work_area_radius_limit; + int work_area_radius_bonus; +}; + +enum retreat_rules { + RR_STANDARD = 0, + RR_NONE, + RR_ALL_UNITS, + RR_IF_FASTER, + RR_IF_NOT_SLOWER, + RR_IF_FAST_AND_NOT_SLOWER, +}; + +enum line_drawing_override { + LDO_NEVER = 0, + LDO_WINE, + LDO_ALWAYS +}; + +enum minimap_doubling_mode { + MDM_NEVER = 0, + MDM_HIGH_DEF, + MDM_ALWAYS +}; + +enum unit_cycle_search_criteria { + UCSC_STANDARD = 0, + UCSC_SIMILAR_NEAR_START, + UCSC_SIMILAR_NEAR_DESTINATION +}; + +enum no_ai_patrol_override { + NAPO_ZERO = 0, + NAPO_ONE, + NAPO_NONE +}; + +enum barbarian_activity_override { + BAO_NONE = -2, + + // The values for these levels must match what the game uses internally for Map.World.Final_Barbarians_Activity + BAO_NO_BARBARIANS = -1, + BAO_SEDENTARY = 0, + BAO_ROAMING = 1, + BAO_RESTLESS = 2, + BAO_RAGING = 3, + BAO_RANDOM = 4 +}; + +enum special_defensive_bombard_rules { + SDBR_LETHAL = 1, + SDBR_NOT_INVISIBLE = 2, + SDBR_AERIAL = 4, + SDBR_BLITZ = 8, + SDBR_DOCKED_VS_LAND = 16, +}; + +enum special_zone_of_control_rules { + SZOCR_LETHAL = 1, + SZOCR_AERIAL = 2, + SZOCR_AMPHIBIOUS = 4, + SZOCR_NOT_FROM_INSIDE = 8, +}; + +enum land_transport_rules { + LTR_LOAD_ONTO_BOAT = 1, + LTR_JOIN_ARMY = 2, + LTR_NO_DEFENSE_FROM_INSIDE = 4, + LTR_NO_ESCAPE = 8, +}; + +enum special_helicopter_rules { + SHR_ALLOW_ON_CARRIERS = 1, + SHR_PASSENGER_AIRDROP = 2, + SHR_NO_DEFENSE_FROM_INSIDE = 4, + SHR_NO_ESCAPE = 8, +}; + +enum work_area_limit { + WAL_NONE = 0, + WAL_CULTURAL, + WAL_CULTURAL_MIN_2, + WAL_CULTURAL_OR_ADJACENT +}; + +enum day_night_cycle_mode { + DNCM_OFF = 0, + DNCM_TIMER, + DNCM_USER_TIME, + DNCM_EVERY_TURN, + DNCM_SPECIFIED +}; + +enum distribution_hub_yield_division_mode { + DHYDM_FLAT = 0, + DHYDM_SCALE_BY_CITY_COUNT +}; + +enum ai_distribution_hub_build_strategy { + ADHBS_AUTO = 0, + ADHBS_BY_CITY_COUNT +}; + +enum ai_auto_build_great_wall_strategy { + AAGWS_ALL_BORDERS = 0, + AAGWS_OTHER_CIV_BORDERED_ONLY +}; + +enum perfume_kind { + PK_PRODUCTION = 0, + PK_TECHNOLOGY, + PK_GOVERNMENT, + + COUNT_PERFUME_KINDS +}; + +struct unit_counter_group { + char * name; + int * type_ids; + int count_type_ids; +}; + +// Attacker/defender match modes +#define UCM_ANY -1 // * Any unit type +#define UCM_GROUP -2 // Match using the group_name field + +struct counter_rule { + // Attacker side + int attacker_match; // UnitTypeID, or UCM_ANY / UCM_GROUP + char * attacker_group; // Used when attacker_match == UCM_GROUP + + // Defender side + int defender_match; + char * defender_group; + + // Environment conditions (0 / false means no restriction) + unsigned int terrain_mask; // SquareTypes mask, 0 = no restriction + bool only_in_city; + int district_id; // -1 = no restriction + char * district_name; // Resolved after district configs are loaded + bool ignore_terrain; // true = set defender terrain defense to 0 + + // Effects (percent values, 100 = no change) + int self_atk_pct; + int self_def_pct; + int enemy_atk_pct; + int enemy_def_pct; +}; + +struct c3x_config { + bool enable_stack_bombard; + bool enable_disorder_warning; + bool allow_stealth_attack_against_single_unit; + bool show_detailed_city_production_info; + int limit_railroad_movement; + bool limited_railroads_work_like_fast_roads; + int limit_units_per_tile[3]; // Limits for land, sea, and air units respectively + bool exclude_cities_from_units_per_tile_limit; + struct table exclude_types_from_units_per_tile_limit; + bool enable_free_buildings_from_small_wonders; + bool enable_stack_unit_commands; + bool skip_repeated_tile_improv_replacement_asks; + bool autofill_best_gold_amount_when_trading; + int minimum_city_separation; + bool disallow_founding_next_to_foreign_city; + bool enable_trade_screen_scroll; + bool group_units_on_right_click_menu; + bool gray_out_units_on_menu_with_no_remaining_moves; + bool put_movement_icons_on_units_on_menu; + bool describe_states_of_units_on_menu; + int anarchy_length_percent; + bool show_golden_age_turns_remaining; + bool show_zoc_attacks_from_mid_stack; + bool show_armies_performing_defensive_bombard; + bool cut_research_spending_to_avoid_bankruptcy; + bool dont_pause_for_love_the_king_messages; + bool reverse_specialist_order_with_shift; + bool toggle_zoom_with_z_on_city_screen; + bool enable_mouse_wheel_zoom; + bool dont_give_king_names_in_non_regicide_games; + bool no_elvis_easter_egg; + bool disable_worker_automation; + bool enable_land_sea_intersections; + bool disallow_trespassing; + bool show_detailed_tile_info; + struct table perfume_specs[COUNT_PERFUME_KINDS]; // Each table maps strings to i31b's. Each i31b combines an amount and whether it's a percent + struct table building_unit_prereqs; // A mapping from int keys to int values. The keys are unit type IDs. If an ID is present as a key in the + // table that means that unit type has one or more prereq buildings. The associated value is either a + // pointer to a list of MAX_BUILDING_PREREQS_FOR_UNITS improvement IDs or a single encoded improv ID. The + // contents of the list are NOT encoded and unused slots store -1. Encoding an ID is done by left-shifting + // it one place then inserting a 1 in the LSB. This way encoded IDs can be told apart from list pointers + // by checking the LSB (1 => encoded improv ID, 0 => list pointer). + struct mill * mills; + int count_mills; + bool warn_about_unrecognized_names; + bool enable_ai_production_ranking; + bool enable_ai_city_location_desirability_display; + bool show_ai_city_location_desirability_if_settler; + bool zero_corruption_when_off; + bool disallow_land_units_from_affecting_water_tiles; + bool dont_end_units_turn_after_airdrop; + bool allow_airdrop_without_airport; + bool enable_negative_pop_pollution; + enum retreat_rules land_retreat_rules; + enum retreat_rules sea_retreat_rules; + bool allow_defensive_retreat_on_water; + struct table limit_defensive_retreat_on_water_to_types; // Table mapping unit type IDs to 1's; used as a hash set + int ai_multi_city_start; + int max_tries_to_place_fp_city; + int * ai_multi_start_extra_palaces; + int count_ai_multi_start_extra_palaces; + int ai_multi_start_extra_palaces_capacity; + bool promote_wonder_decorruption_effect; + bool allow_military_leaders_to_hurry_wonders; + bool allow_multiple_battle_created_units_per_player; + int ai_research_multiplier; + int ai_settler_perfume_on_founding; + int ai_settler_perfume_on_founding_duration; + bool aggressively_penalize_bankruptcy; + bool no_penalty_exception_for_agri_fresh_water_city_tiles; + bool suppress_hypertext_links_exceeded_popup; + bool indicate_non_upgradability_in_pedia; + bool show_message_after_dodging_sam; + bool include_stealth_attack_cancel_option; + bool intercept_recon_missions; + bool charge_one_move_for_recon_and_interception; + bool polish_precision_striking; + bool enable_stealth_attack_via_bombardment; + bool immunize_aircraft_against_bombardment; + bool replay_ai_moves_in_hotseat_games; + struct table ptw_arty_types; // Table mapping unit type IDs to 1's; used as a hash set + struct table can_bombard_only_sea_tiles; // Table mapping unit type IDs to 1's; used as a hash set + bool restore_unit_directions_on_game_load; + bool apply_grid_ini_setting_on_game_load; + bool charm_flag_triggers_ptw_like_targeting; + bool city_icons_show_unit_effects_not_trade; + bool ignore_king_ability_for_defense_priority; + bool show_untradable_techs_on_trade_screen; + bool disallow_useless_bombard_vs_airfields; + enum line_drawing_override draw_lines_using_gdi_plus; + bool compact_luxury_display_on_city_screen; + bool compact_strategic_resource_display_on_city_screen; + bool warn_when_chosen_building_would_replace_another; + bool do_not_unassign_workers_from_polluted_tiles; + bool do_not_make_capital_cities_appear_larger; + bool show_territory_colors_on_water_tiles_in_minimap; + bool convert_some_popups_into_online_mp_messages; + bool enable_debug_mode_switch; + bool accentuate_cities_on_minimap; + enum minimap_doubling_mode double_minimap_size; + bool allow_multipage_civilopedia_descriptions; + enum unit_cycle_search_criteria unit_cycle_search_criteria; + bool reformat_turns_remaining_on_domestic_advisor_screen; + bool expand_civilopedia_unit_stats; + bool enable_city_capture_by_barbarians; + bool share_visibility_in_hotseat; + bool share_wonders_in_hotseat; + bool allow_precision_strikes_against_tile_improvements; + bool dont_end_units_turn_after_bombarding_barricade; + bool remove_land_artillery_target_restrictions; + bool allow_bombard_of_other_improvs_on_occupied_airfield; + bool show_total_city_count; + bool strengthen_forbidden_palace_ocn_effect; + int extra_unit_maintenance_per_shields; + enum special_zone_of_control_rules special_zone_of_control_rules; + enum special_defensive_bombard_rules special_defensive_bombard_rules; + struct civ_era_alias_list * civ_era_alias_lists; + int count_civ_era_alias_lists; + struct leader_era_alias_list * leader_era_alias_lists; + int count_leader_era_alias_lists; + struct table unit_limits; // Maps unit type names (strings) to pointers to limit objects (struct unit_type_limit *) + bool allow_upgrades_in_any_city; + bool do_not_generate_volcanos; + bool do_not_pollute_impassable_tiles; + bool show_hp_of_stealth_attack_options; + bool exclude_invisible_units_from_stealth_attack; + bool exclude_passengers_from_stealth_attack; + bool convert_to_landmark_after_planting_forest; + int chance_for_nukes_to_destroy_max_one_hp_units; + bool allow_sale_of_aqueducts_and_hospitals; + bool no_cross_shore_detection; + int city_work_radius; + bool auto_zoom_city_screen_for_large_work_areas; + enum work_area_limit work_area_limit; + struct work_area_improvement * work_area_improvements; + int count_work_area_improvements; + int rebase_range_multiplier; + bool limit_unit_loading_to_one_transport_per_turn; + bool prevent_old_units_from_upgrading_past_ability_block; + bool introduce_all_human_players_at_start_of_hotseat_game; + bool allow_unload_from_army; + enum land_transport_rules land_transport_rules; + bool allow_adjacent_resources_of_different_types; + bool allow_corruption_in_capital; + int special_capital_decorruption_effect; + int luxury_randomized_appearance_rate_percent; + int tiles_per_non_luxury_resource; + bool no_land_anti_air_from_inside_naval_transport; + enum special_helicopter_rules special_helicopter_rules; + bool prevent_enslaving_by_bombardment; + int years_to_double_building_culture; + int tourism_time_scale_percent; + bool allow_sale_of_small_wonders; + enum no_ai_patrol_override override_no_ai_patrol; + enum barbarian_activity_override override_barbarian_activity_level_for_scenario_maps; + bool initialize_preplaced_scenario_leaders_as_mgls; + bool enable_unit_counters; + struct unit_counter_group * unit_counter_groups; + int count_unit_counter_groups; + struct counter_rule * counter_rules; + int count_counter_rules; + bool use_civ4_style_best_defender; + + bool enable_trade_net_x; + bool optimize_improvement_loops; + bool measure_turn_times; + + bool use_offensive_artillery_ai; + bool dont_escort_unflagged_units; + int ai_build_artillery_ratio; + int ai_artillery_value_damage_percent; + int ai_build_bomber_ratio; + bool replace_leader_unit_ai; + bool fix_ai_army_composition; + bool enable_pop_unit_ai; + bool enable_caravan_unit_ai; + int max_ai_naval_escorts; + int ai_worker_requirement_percent; + + bool remove_unit_limit; + bool remove_city_improvement_limit; + int city_limit; + bool remove_cap_on_turn_limit; + bool remove_era_limit; + + bool patch_submarine_bug; + bool patch_science_age_bug; + bool patch_pedia_texture_bug; + bool patch_blocked_disembark_freeze; + bool patch_houseboat_bug; + bool patch_intercept_lost_turn_bug; + bool patch_phantom_resource_bug; + bool patch_maintenance_persisting_for_obsolete_buildings; + bool patch_barbarian_diagonal_bug; + bool patch_disease_stopping_tech_flag_bug; + bool patch_division_by_zero_in_ai_alliance_eval; + bool patch_empty_army_movement; + bool patch_empty_army_combat_crash; + bool delete_off_map_ai_units; + bool fix_overlapping_specialist_yield_icons; + bool patch_premature_truncation_of_found_paths; + bool patch_zero_production_crash; + bool patch_ai_can_form_army_without_special_ability; + bool patch_ai_can_sacrifice_without_special_ability; + bool patch_crash_in_leader_unit_ai; + bool patch_failure_to_find_new_city_build; + bool patch_passengers_out_of_order_on_menu; + + bool prevent_autorazing; + bool prevent_razing_by_players; + + bool allow_extraterritorial_colonies; + int per_extraterritorial_colony_relation_penalty; + + bool draw_forests_over_roads_and_railroads; + + bool enable_named_tiles; + + char * aircraft_victory_animation; // NULL if set to "none" in config + + int day_night_cycle_mode; + int elapsed_minutes_per_day_night_hour_transition; + int fixed_hours_per_turn_for_day_night_cycle; + int pinned_hour_for_day_night_cycle; + + bool enable_natural_wonders; + bool add_natural_wonders_to_scenarios_if_none; + bool show_natural_wonder_name_on_map; + int minimum_natural_wonder_separation; + + bool enable_districts; + bool enable_neighborhood_districts; + bool enable_wonder_districts; + bool enable_distribution_hub_districts; + bool enable_aerodrome_districts; + bool enable_port_districts; + bool enable_bridge_districts; + bool enable_canal_districts; + bool enable_central_rail_hub_districts; + bool enable_energy_grid_districts; + bool enable_great_wall_districts; + + bool cities_with_mutual_district_receive_buildings; + bool cities_with_mutual_district_receive_wonders; + bool show_message_when_building_received_by_mutual_district; + bool show_message_when_building_lost_to_destroyed_district; + + bool air_units_use_aerodrome_districts_not_cities; + bool naval_units_use_port_districts_not_cities; + + int maximum_pop_before_neighborhood_needed; + int per_neighborhood_pop_growth_enabled; + int neighborhood_needed_message_frequency; + bool destroying_neighborhood_reduces_pop; + + bool completed_wonder_districts_can_be_destroyed; + bool destroyed_wonders_can_be_built_again; + + int distribution_hub_yield_division_mode; + int distribution_hub_food_yield_divisor; + int distribution_hub_shield_yield_divisor; + int ai_distribution_hub_build_strategy; + int ai_ideal_distribution_hub_count_per_100_cities; + int max_distribution_hub_count_per_100_cities; + int central_rail_hub_distribution_food_bonus_percent; + int central_rail_hub_distribution_shield_bonus_percent; + + bool workers_can_enter_coast; + bool expand_water_tile_checks_to_city_work_area; + int max_contiguous_bridge_districts; + int max_contiguous_canal_districts; + int ai_canal_eval_min_bisected_land_tiles; + int ai_bridge_canal_eval_block_size; + int ai_bridge_eval_lake_tile_threshold; + bool ai_can_replace_existing_districts_with_canals; + bool ai_builds_bridges; + bool ai_builds_canals; + + bool ai_defends_districts; + int ai_city_district_max_build_wait_turns; + + bool disable_great_wall_city_defense_bonus; + bool great_wall_districts_impassible_by_others; + bool auto_build_great_wall_around_territory; + char * great_wall_auto_build_wonder_name; + int great_wall_auto_build_wonder_improv_id; + int ai_auto_build_great_wall_strategy; + + bool enable_city_work_radii_highlights; +}; + +enum stackable_command { + SC_BOMBARD = 0, + SC_BOMB, + SC_FORTRESS, + SC_MINE, + SC_IRRIGATE, + SC_CHOP_FOREST, + SC_CHOP_JUNGLE, + SC_PLANT, + SC_CLEAN_POLLUTION, + SC_ROAD, + SC_RAILROAD, + SC_FORTIFY, + SC_UPGRADE, + SC_DISBAND, + COUNT_STACKABLE_COMMANDS +}; + +enum stackable_command_kind { + SCK_BOMBARD = 0, + SCK_TERRAFORM, + SCK_UNIT_MGMT, + COUNT_STACKABLE_COMMAND_KINDS +}; + +struct sc_button_info { + enum Unit_Command_Values command; + enum stackable_command_kind kind; + int tile_sheet_column, + tile_sheet_row; +} const sc_button_infos[COUNT_STACKABLE_COMMANDS] = { + /* Bombard */ { .command = UCV_Bombard , .kind = SCK_BOMBARD , .tile_sheet_column = 3, .tile_sheet_row = 1 }, + /* Bomb */ { .command = UCV_Bombing , .kind = SCK_BOMBARD , .tile_sheet_column = 5, .tile_sheet_row = 4 }, + /* Fortress */ { .command = UCV_Build_Fortress , .kind = SCK_TERRAFORM, .tile_sheet_column = 0, .tile_sheet_row = 3 }, + /* Mine */ { .command = UCV_Build_Mine , .kind = SCK_TERRAFORM, .tile_sheet_column = 1, .tile_sheet_row = 3 }, + /* Irrigate */ { .command = UCV_Irrigate , .kind = SCK_TERRAFORM, .tile_sheet_column = 2, .tile_sheet_row = 3 }, + /* Chop For. */ { .command = UCV_Clear_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 3, .tile_sheet_row = 3 }, + /* Chop Jun. */ { .command = UCV_Clear_Jungle , .kind = SCK_TERRAFORM, .tile_sheet_column = 4, .tile_sheet_row = 3 }, + /* Plant */ { .command = UCV_Plant_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 5, .tile_sheet_row = 3 }, + /* Clean Pol. */ { .command = UCV_Clear_Pollution, .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 3 }, + /* Road */ { .command = UCV_Build_Road , .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 2 }, + /* Railroad */ { .command = UCV_Build_Railroad , .kind = SCK_TERRAFORM, .tile_sheet_column = 7, .tile_sheet_row = 2 }, + /* Fortify */ { .command = UCV_Fortify , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 2, .tile_sheet_row = 0 }, + /* Upgrade */ { .command = UCV_Upgrade_Unit , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 7, .tile_sheet_row = 1 }, + /* Disband */ { .command = UCV_Disband , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 3, .tile_sheet_row = 0 }, +}; + +enum init_state { + IS_UNINITED = 0, + IS_OK, + IS_INIT_FAILED +}; + +enum c3x_label { + CL_NEVER_COMPLETES = 0, + CL_HALTED, + CL_SURPLUS, + CL_SURPLUS_NONE, + CL_SURPLUS_NA, + CL_SB_TOOLTIP, + CL_CHOPPED, + CL_OFF, + CL_MOD_INFO_BUTTON_TEXT, + CL_VERSION, + CL_CONFIG_FILES_LOADED, + CL_CREATING_CITIES, + CL_MCS_FAILED_SANITY_CHECK, + CL_MCS_ADJACENT_CITIES, + CL_MCS_MISSING_CITIES, + CL_OBSOLETED_BY, + CL_NO_STEALTH_ATTACK, + CL_DODGED_SAM, + CL_PREVIEW, + CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP, + CL_TOTAL_CITIES, + + // Offense, Defense, Artillery, etc. + CL_FIRST_UNIT_STRAT, + CL_LAST_UNIT_STRAT = CL_FIRST_UNIT_STRAT + 19, + + // Unit actions for right-click menu + CL_IDLE, + CL_FORTIFIED, + CL_SENTRY, + CL_MINING, + CL_IRRIGATING, + CL_BUILDING_FORTRESS, + CL_BUILDING_ROAD, + CL_BUILDING_RAILROAD, + CL_PLANTING_FOREST, + CL_CLEARING_FOREST, + CL_CLEARING_WETLANDS, + CL_CLEARING_DAMAGE, + CL_BUILDING_AIRFIELD, + CL_BUILDING_RADAR_TOWER, + CL_BUILDING_OUTPOST, + CL_BUILDING_BARRICADE, + CL_BUILDING_COLONY, + CL_INTERCEPTING, + CL_MOVING, + CL_AUTOMATED, + CL_EXPLORING, + CL_BOMBARDING, + + // Generic "Building" phrase for Districts right-click menu + CL_BUILDING, + + // Districts-related texts + CL_REQUIRES, + CL_TO_GROW, + CL_DISTRICT_DESTROYED_BY_VOLCANO, + CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT, + CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD, + + CL_RECEIVED, + CL_FROM_SHARED, + CL_WITH, + + CL_APOSTROPHE_S, + CL_AND, + CL_OTHER_BUILDINGS_HAVE_BEEN, + CL_LOST_DUE_TO_DESTROYED, + + // Districts config mismatch checked on game load + CL_DISTRICT_ID, + CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW, + CL_DISTRICT_NAME_MISMATCH, + CL_SAVE_FILE_HAD, + CL_CURRENT_CONFIG_HAS_ONLY, + CL_WARNING_DISTRICTS_CONFIG_MISMATCH, + CL_MAY_BE_OTHER_ERRORS_AS_WELL, + CL_DISTRICTS_IN_SAVE_FILE, + CL_CURRENTLY_CONFIGURED_DISTRICTS, + + // Tile naming + CL_NAME_TILE, + CL_RENAME_TILE, + + // "Action" for passenger units + CL_TRANSPORTED, + + CL_IN_STATE_27, + CL_IN_STATE_28, + CL_IN_STATE_29, + CL_IN_STATE_30, + CL_IN_STATE_33, + + // For unit stats on Civilopedia + CL_HP_BONUS, + CL_WORKER_STRENGTH, + + CL_AGRICULTURAL, + CL_COMMERCIAL, + CL_EXPANSIONIST, + CL_INDUSTRIOUS, + CL_MILITARISTIC, + CL_RELIGIOUS, + CL_SCIENTIFIC, + CL_SEAFARING, + + COUNT_C3X_LABELS +}; + +struct worker_job_and_location { + enum Worker_Jobs job; + int tile_x, tile_y; +}; + +struct ai_prod_valuation { + int order_type; + int order_id; + int point_value; +}; + +enum unit_rcm_icon { + URCMI_UNMOVED = 0, + URCMI_MOVED_CAN_ATTACK, + URCMI_MOVED_NO_ATTACK, + URCMI_CANT_MOVE, + + COUNT_UNIT_RCM_ICONS +}; + +enum unit_rcm_icon_set { + URCMIS_ATTACKER = 0, + URCMIS_NONCOMBAT, + URCMIS_BUSY_ATTACKER, + URCMIS_BUSY_NONCOMBAT, + + COUNT_UNIT_RCM_ICON_SETS +}; + +enum city_gain_reason { + CGR_FOUNDED = 0, + CGR_CONQUERED, + CGR_CONVERTED, // covers culture flips & bribes + CGR_TRADED, + CGR_POPPED_FROM_HUT, + CGR_PLACED_FOR_AI_RESPAWN, + CGR_PLACED_FOR_SCENARIO, + CGR_PLACED_FOR_AI_MULTI_CITY_START, +}; + +enum city_loss_reason { + CLR_DESTROYED = 0, // means city was razed for any reason (inc. by conqueror) + CLR_CONQUERED, + CLR_CONVERTED, // covers culture flips & bribes + CLR_TRADED +}; + +enum { + MAX_DISTRICT_DEPENDENTS = 64 +}; + +enum { + DEFAULT_DISTRICT_BUILDABLE_MASK = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain) | (1 << SQ_Hills) +}; + +enum { + MAX_DISTRICT_BONUS_ENTRIES = 16 +}; + +enum district_bonus_entry_type { + DBET_TILE = 0, + DBET_BUILDING = 1 +}; + +enum great_wall_auto_build_state { + GWABS_NOT_STARTED = 0, + GWABS_RUNNING, + GWABS_DONE +}; + +struct district_bonus_entry { + enum district_bonus_entry_type type; + int bonus; + enum SquareTypes tile_type; + int building_id; + char const * building_name; +}; + +struct district_bonus_list { + int count; + struct district_bonus_entry entries[MAX_DISTRICT_BONUS_ENTRIES]; +}; + +enum district_render_strategy { + DRS_BY_COUNT = 0, + DRS_BY_BUILDING = 1 +}; + +enum district_ai_build_strategy { + DABS_DISTRICT = 0, + DABS_TILE_IMPROVEMENT = 1 +}; + +struct district_config { + enum Unit_Command_Values command; + char const * name; + char const * display_name; + char const * tooltip; + char const * advance_prereqs[MAX_DISTRICT_DEPENDENTS]; + int advance_prereq_count; + char const * obsoleted_by; + char const * resource_prereqs[MAX_DISTRICT_DEPENDENTS]; + char const * resource_prereq_on_tile; + char const * dependent_improvements[MAX_DISTRICT_DEPENDENTS]; + char const * wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; + char const * natural_wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; + char const * buildable_on_districts[MAX_DISTRICT_DEPENDENTS]; + char const * buildable_adjacent_to_districts[MAX_DISTRICT_DEPENDENTS]; + char const * img_paths[10]; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_without_removal_mask; + unsigned int buildable_on_overlays_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + bool allow_multiple; + bool vary_img_by_era; + bool vary_img_by_culture; + enum district_render_strategy render_strategy; + enum district_ai_build_strategy ai_build_strategy; + bool is_dynamic; + bool align_to_coast; + bool draw_over_resources; + bool allow_irrigation_from; + bool auto_add_road; + bool auto_add_railroad; + int custom_width; + int custom_height; + int x_offset; + int y_offset; + int resource_prereq_count; + int dependent_improvement_max_index; + int wonder_prereq_count; + int natural_wonder_prereq_count; + int buildable_on_district_count; + int buildable_adjacent_to_district_count; + int img_path_count; + int img_column_count; + bool has_img_column_count_override; + int btn_tile_sheet_column; + int btn_tile_sheet_row; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + struct district_bonus_list culture_bonus_extras; + struct district_bonus_list science_bonus_extras; + struct district_bonus_list food_bonus_extras; + struct district_bonus_list gold_bonus_extras; + struct district_bonus_list shield_bonus_extras; + struct district_bonus_list happiness_bonus_extras; + struct district_bonus_list defense_bonus_extras; + int defense_bonus_percent; + bool heal_units_in_one_turn; + bool impassible; + bool impassible_to_wheeled; + char const * generated_resource; + int generated_resource_id; + short generated_resource_flags; + int buildable_on_district_ids[MAX_DISTRICT_DEPENDENTS]; + int buildable_on_district_id_count; + bool has_buildable_on_districts; + int buildable_adjacent_to_district_ids[MAX_DISTRICT_DEPENDENTS]; + int buildable_adjacent_to_district_id_count; + bool has_buildable_adjacent_to; + bool has_buildable_adjacent_to_districts; + bool has_buildable_without_removal; + bool has_buildable_on_overlays; + bool has_buildable_adjacent_to_overlays; + bool has_buildable_on_rivers; + char const * buildable_by_civs[32]; + int buildable_by_civ_count; + bool has_buildable_by_civs; + int buildable_by_civ_traits_ids[8]; + int buildable_by_civ_traits_id_count; + bool has_buildable_by_civ_traits; + int buildable_by_civ_govs_ids[5]; + int buildable_by_civ_govs_id_count; + bool has_buildable_by_civ_govs; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_buildable_by_civ_cultures; + bool buildable_by_war_allies; + bool buildable_by_pact_allies; +}; + +struct wonder_district_config { + char const * wonder_name; + char const * img_path; + int index, + img_row, + img_column, + img_construct_row, + img_construct_column, + img_alt_dir_construct_row, + img_alt_dir_construct_column, + img_alt_dir_row, + img_alt_dir_column, + custom_width, + custom_height; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + char const * buildable_by_civs[32]; + int buildable_by_civ_count; + bool has_buildable_by_civs; + int buildable_by_civ_traits_ids[8]; + int buildable_by_civ_traits_id_count; + bool has_buildable_by_civ_traits; + int buildable_by_civ_govs_ids[5]; + int buildable_by_civ_govs_id_count; + bool has_buildable_by_civ_govs; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_buildable_by_civ_cultures; + bool enable_img_alt_dir; + bool is_dynamic; + bool has_buildable_adjacent_to; + bool has_buildable_adjacent_to_overlays; +}; + +enum square_type_extras { + SQ_INVALID = -1, + SQ_RIVER = SQ_Ocean + 1, + SQ_SNOW_VOLCANO, + SQ_SNOW_FOREST, + SQ_SNOW_MOUNTAIN +}; + +enum district_overlay_mask_bits { + DOM_MINE = 1u << 0, + DOM_IRRIGATION = 1u << 1, + DOM_FORTRESS = 1u << 2, + DOM_BARRICADE = 1u << 3, + DOM_OUTPOST = 1u << 4, + DOM_RADAR_TOWER = 1u << 5, + DOM_JUNGLE = 1u << 6, + DOM_FOREST = 1u << 7, + DOM_SWAMP = 1u << 8, + DOM_RIVER = 1u << 9, + DOM_AIRFIELD = 1u << 10 +}; + +struct natural_wonder_district_config { + char const * name; + char const * img_path; + enum SquareTypes terrain_type; + enum SquareTypes adjacent_to; + enum direction adjacency_dir; + int index; + int img_row; + int img_column; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + bool impassible; + bool impassible_to_wheeled; + bool is_dynamic; +}; + +struct natural_wonder_candidate { + Tile * tile; + short x, y; +}; + +struct natural_wonder_candidate_list { + struct natural_wonder_candidate * entries; + int count; + int capacity; +}; + +struct wonder_location { + short x; + short y; +}; + +const struct district_config special_district_defaults[USED_SPECIAL_DISTRICT_TYPES] = { + { + .command = UCV_Build_Neighborhood, .name = "Neighborhood", .tooltip = "Build Neighborhood", .display_name = "Neighborhood", + .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = true, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {"Neighborhood_AMER.pcx", "Neighborhood_EURO.pcx", "Neighborhood_ROMAN.pcx", "Neighborhood_MIDEAST.pcx", "Neighborhood_ASIAN.pcx"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 5, .img_column_count = 4, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, + .culture_bonus = 1, .science_bonus = 1, .food_bonus = 0, .gold_bonus = 1, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 25, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + + }, + { + .command = UCV_Build_WonderDistrict, .name = "Wonder District", .tooltip = "Build Wonder District", .display_name = "Wonder District", + .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {"WonderDistrict.pcx"}, + .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Coast) | (1 << SQ_Mountains)), + .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 1, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + + }, + { + .command = UCV_Build_DistributionHub, .name = "Distribution Hub", .tooltip = "Build Distribution Hub", .display_name = "Distribution Hub", + .advance_prereqs = {"Construction"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {"DistributionHub.pcx"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 2, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + + }, + { + .command = UCV_Build_Aerodrome, .name = "Aerodrome", .tooltip = "Build Aerodrome", .display_name = "Aerodrome", + .advance_prereqs = {"Flight"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 1, + .img_paths = {"Aerodrome.pcx"}, .dependent_improvements = {"Airport"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 1, .img_column_count = 2, .btn_tile_sheet_column = 3, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = -1, .name = "Natural Wonder", .tooltip = NULL, .display_name = "Natural Wonder", + .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {0}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 0, .img_column_count = 0, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_Port, .name = "Port", .tooltip = "Build Port", .display_name = "Port", + .advance_prereqs = {"Map Making"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 2, .align_to_coast = true, + .img_paths = {"Port_NW.pcx", "Port_NE.pcx", "Port_SE.pcx", "Port_SW.pcx"}, .dependent_improvements = {"Harbor", "Commercial Dock"}, + .buildable_square_types_mask = (1 << SQ_Coast), + .img_path_count = 4, .img_column_count = 4, .btn_tile_sheet_column = 4, .btn_tile_sheet_row = 0, .align_to_coast = true, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_CentralRailHub, .name = "Central Rail Hub", .tooltip = "Build Central Rail Hub", .display_name = "Central Rail Hub", + .advance_prereqs = {"Steam Power"}, .advance_prereq_count = 1, .resource_prereqs = {"Iron", "Coal"}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 2, .dependent_improvement_max_index = 0, + .img_paths = {"CentralRailHub_AMER.pcx", "CentralRailHub_EURO.pcx", "CentralRailHub_ROMAN.pcx", "CentralRailHub_MIDEAST.pcx", "CentralRailHub_ASIAN.pcx"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .auto_add_road = true, .auto_add_railroad = true, + .img_path_count = 5, .img_column_count = 2, .btn_tile_sheet_column = 5, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_EnergyGrid, .name = "Energy Grid", .tooltip = "Build Energy Grid", .display_name = "Energy Grid", + .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 4, + .img_paths = {"EnergyGrid.pcx"}, .dependent_improvements = {"Coal Plant", "Hydro Plant", "Nuclear Plant", "Solar Plant"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .custom_height = 84, + .img_path_count = 1, .img_column_count = 5, .btn_tile_sheet_column = 6, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 2, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_Bridge, .name = "Bridge", .tooltip = "Build Bridge", .display_name = "Bridge", + .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, + .img_paths = {"Bridge.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, + .buildable_square_types_mask = (1 << SQ_Coast), .auto_add_road = true, + .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 7, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_Canal, .name = "Canal", .tooltip = "Build Canal", .display_name = "Canal", + .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, + .img_paths = {"Canal.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, + .buildable_square_types_mask = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain), + .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 8, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_GreatWall, .name = "Great Wall", .tooltip = "Build Great Wall", .display_name = "Great Wall", + .advance_prereqs = {0}, .advance_prereq_count = 0, .obsoleted_by = "Metallurgy", .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, + .img_paths = {"GreatWall.pcx"}, .dependent_improvements = {0}, .custom_height = 88, .wonder_prereqs = {"The Great Wall"}, .wonder_prereq_count = 1, + .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Mountains) | (1 << SQ_Forest) | (1 << SQ_Swamp) | (1 << SQ_Jungle) | (1 << SQ_Volcano)), .draw_over_resources = true, + .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 9, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 50, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + } +}; + +struct parsed_district_definition { + char * name; + char * display_name; + char * tooltip; + char * advance_prereqs[5]; + int advance_prereq_count; + char * obsoleted_by; + char * resource_prereqs[5]; + char * resource_prereq_on_tile; + char * dependent_improvements[5]; + char * wonder_prereqs[5]; + char * natural_wonder_prereqs[5]; + char * buildable_on_districts[5]; + char * buildable_adjacent_to_districts[5]; + char * img_paths[5]; + int resource_prereq_count; + int dependent_improvement_max_index; + int wonder_prereq_count; + int natural_wonder_prereq_count; + int buildable_on_district_count; + int buildable_adjacent_to_district_count; + int img_path_count; + int img_column_count; + bool allow_multiple; + bool vary_img_by_era; + bool vary_img_by_culture; + enum district_render_strategy render_strategy; + enum district_ai_build_strategy ai_build_strategy; + bool align_to_coast; + bool draw_over_resources; + bool allow_irrigation_from; + bool auto_add_road; + bool auto_add_railroad; + bool impassible; + bool impassible_to_wheeled; + int custom_width; + int custom_height; + int x_offset; + int y_offset; + int btn_tile_sheet_column; + int btn_tile_sheet_row; + int defense_bonus_percent; + bool heal_units_in_one_turn; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + struct district_bonus_list culture_bonus_extras; + struct district_bonus_list science_bonus_extras; + struct district_bonus_list food_bonus_extras; + struct district_bonus_list gold_bonus_extras; + struct district_bonus_list shield_bonus_extras; + struct district_bonus_list happiness_bonus_extras; + struct district_bonus_list defense_bonus_extras; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_without_removal_mask; + unsigned int buildable_on_overlays_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + char * buildable_by_civs[32]; + int buildable_by_civ_count; + bool buildable_by_war_allies; + bool buildable_by_pact_allies; + bool has_name; + bool has_tooltip; + bool has_advance_prereqs; + bool has_obsoleted_by; + bool has_resource_prereqs; + bool has_dependent_improvements; + bool has_wonder_prereqs; + bool has_natural_wonder_prereqs; + bool has_display_name; + bool has_img_paths; + bool has_img_column_count; + bool has_allow_multiple; + bool has_vary_img_by_era; + bool has_vary_img_by_culture; + bool has_render_strategy; + bool has_ai_build_strategy; + bool has_align_to_coast; + bool has_draw_over_resources; + bool has_custom_width; + bool has_custom_height; + bool has_x_offset; + bool has_y_offset; + bool has_btn_tile_sheet_column; + bool has_btn_tile_sheet_row; + bool has_defense_bonus_percent; + bool has_heal_units_in_one_turn; + bool has_culture_bonus; + bool has_science_bonus; + bool has_food_bonus; + bool has_gold_bonus; + bool has_shield_bonus; + bool has_happiness_bonus; + bool has_buildable_on; + bool has_buildable_adjacent_to; + bool has_buildable_without_removal; + bool has_buildable_on_overlays; + bool has_buildable_adjacent_to_overlays; + bool has_buildable_on_rivers; + bool has_resource_prereq_on_tile; + bool has_buildable_by_civs; + bool has_buildable_by_war_allies; + bool has_buildable_by_pact_allies; + char * generated_resource; + short generated_resource_flags; + bool has_generated_resource; + char * buildable_by_civ_traits[10]; + int buildable_by_civ_traits_count; + int buildable_by_civ_traits_ids[10]; + int buildable_by_civ_traits_id_count; + bool has_buildable_by_civ_traits; + char * buildable_by_civ_govs[10]; + int buildable_by_civ_govs_count; + int buildable_by_civ_govs_ids[32]; + int buildable_by_civ_govs_id_count; + bool has_buildable_by_civ_govs; + char * buildable_by_civ_cultures[5]; + int buildable_by_civ_cultures_count; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_buildable_by_civ_cultures; + bool has_buildable_on_districts; + bool has_buildable_adjacent_to_districts; + bool has_allow_irrigation_from; + bool has_auto_add_road; + bool has_auto_add_railroad; + bool has_impassible; + bool has_impassible_to_wheeled; +}; + +struct parsed_wonder_definition { + char * name; + char * img_path; + int img_row; + int img_column; + int img_construct_row; + int img_construct_column; + int img_alt_dir_construct_row; + int img_alt_dir_construct_column; + int img_alt_dir_row; + int img_alt_dir_column; + int custom_width; + int custom_height; + bool enable_img_alt_dir; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + char * buildable_by_civs[32]; + int buildable_by_civ_count; + char * buildable_by_civ_traits[10]; + int buildable_by_civ_traits_count; + int buildable_by_civ_traits_ids[10]; + int buildable_by_civ_traits_id_count; + char * buildable_by_civ_govs[10]; + int buildable_by_civ_govs_count; + int buildable_by_civ_govs_ids[32]; + int buildable_by_civ_govs_id_count; + char * buildable_by_civ_cultures[5]; + int buildable_by_civ_cultures_count; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_name; + bool has_img_path; + bool has_img_row; + bool has_img_column; + bool has_img_construct_row; + bool has_img_construct_column; + bool has_img_alt_dir_construct_row; + bool has_img_alt_dir_construct_column; + bool has_img_alt_dir_row; + bool has_img_alt_dir_column; + bool has_custom_width; + bool has_custom_height; + bool has_enable_img_alt_dir; + bool has_buildable_on; + bool has_buildable_adjacent_to; + bool has_buildable_adjacent_to_overlays; + bool has_buildable_on_rivers; + bool has_buildable_by_civs; + bool has_buildable_by_civ_traits; + bool has_buildable_by_civ_govs; + bool has_buildable_by_civ_cultures; +}; + +struct parsed_natural_wonder_definition { + char * name; + char * img_path; + enum SquareTypes terrain_type; + enum SquareTypes adjacent_to; + enum direction adjacency_dir; + int img_row; + int img_column; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + bool impassible; + bool impassible_to_wheeled; + bool has_name; + bool has_img_path; + bool has_img_row; + bool has_img_column; + bool has_terrain_type; + bool has_adjacent_to; + bool has_adjacency_dir; + bool has_culture_bonus; + bool has_science_bonus; + bool has_food_bonus; + bool has_gold_bonus; + bool has_shield_bonus; + bool has_happiness_bonus; + bool has_impassible; + bool has_impassible_to_wheeled; +}; + +struct scenario_district_entry { + int tile_x; + int tile_y; + int has_coordinates; + char * district_name; + int has_district_name; + char * wonder_city_name; + int has_wonder_city; + char * wonder_name; + int has_wonder_name; +}; + +struct scenario_named_tile_entry { + int tile_x; + int tile_y; + int has_coordinates; + char * name; + int has_name; +}; + +struct distribution_hub_record { + Tile * tile; + int tile_x; + int tile_y; + int civ_id; + int food_yield; + int shield_yield; + int raw_food_yield; + int raw_shield_yield; +}; + +struct ai_best_feasible_order { + City_Order order; + int value; +}; + +struct district_building_prereq_list { + int count; + int district_ids[MAX_DISTRICT_DEPENDENTS]; +}; + +struct pending_district_request { + City * city; + int city_id; + int civ_id; + int district_id; + int assigned_worker_id; + int target_x; + int target_y; + int worker_assigned_turn; +}; + +struct ai_candidate_bridge_or_canal_entry { + int district_id; + short owner_civ_id; + short * tile_x; + short * tile_y; + short tile_count; + short assigned_tile_index; + int assigned_worker_id; + bool completed; + struct pending_district_request pending_req; + int tile_capacity; +}; + +struct district_worker_record { + Unit * worker; + int unit_id; + int continent_id; + struct pending_district_request * pending_req; +}; + +enum wonder_district_state { + WDS_UNUSED = 0, // Wonder district built, no wonder assigned + WDS_UNDER_CONSTRUCTION, // Reserved by a city for wonder construction + WDS_COMPLETED, // Wonder completed on this district + WDS_RUINED // (Future) Wonder was destroyed +}; + +struct wonder_district_info { + enum wonder_district_state state; + City * city; // City that reserved/completed (NULL if unused) + int city_id; + int wonder_index; // Wonder index (-1 if unused/reserved, valid if completed) +}; + +struct natural_wonder_district_info { + int natural_wonder_id; +}; + +enum district_state { + DS_UNDER_CONSTRUCTION = 0, + DS_COMPLETED = 1 +}; + +struct district_instance { + enum district_state state; + int district_id; // Index into district_configs array + int tile_x; + int tile_y; + int built_by_civ_id; + int completed_turn; + struct wonder_district_info wonder_info; // Only used if district_id is a wonder district + struct natural_wonder_district_info natural_wonder_info; // Only used if district_id is a natural wonder district +}; + +enum extra_resource_tile_type { + ERT_MILL_RESOURCE = 0, + ERT_DISTRICT_RESOURCE +}; + +struct extra_resource_tile { + Tile * tile; + enum extra_resource_tile_type type; + union { + struct { + City * city; + struct mill * mill; + } mill_info; + struct { + struct district_instance * inst; + struct district_config * cfg; + } district_info; + }; +}; + +struct named_tile_entry { + int tile_x; + int tile_y; + char name[100]; +}; + +struct highlighted_city_radius_tile_info { + int highlight_level; +}; + +struct injected_state { + // ========== + // These fields are valid at any time in the injected code because they're set by the patcher { + // ========== + + int mod_version; + // "mod relative directory" is the mod dir relative to the conquests dir. Usually it's "C3X_Rn" but it might be deeper. + // It must be non-empty and must not have an ending backslash. + char mod_rel_dir[MAX_PATH]; + + enum init_state sc_img_state; + enum init_state tile_highlight_state; + enum init_state mod_info_button_images_state; + enum init_state disabled_command_img_state; + enum init_state unit_rcm_icon_state; + enum init_state red_food_icon_state; + enum init_state distribution_hub_icons_img_state; + enum init_state tile_already_worked_zoomed_out_sprite_init_state; + enum init_state day_night_cycle_img_state; + enum init_state large_minimap_frame_img_state; + + // ========== + // } These fields are valid at any time after patch_init_floating_point runs (which is at the program launch). { + // ========== + + struct c3x_config base_config; + + // Windows modules + HMODULE kernel32; + HMODULE user32; + HMODULE msvcrt; + HMODULE msimg32; + + // Win32 API functions + WINBOOL (WINAPI * VirtualProtect) (LPVOID, SIZE_T, DWORD, PDWORD); + WINBOOL (WINAPI * CloseHandle) (HANDLE); + HANDLE (WINAPI * CreateFileA) (LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); + DWORD (WINAPI * GetFileSize) (HANDLE, LPDWORD); + WINBOOL (WINAPI * ReadFile) (HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); + HMODULE (WINAPI * LoadLibraryA) (LPCSTR); + BOOL (WINAPI * FreeLibrary) (HMODULE); + int (WINAPI * MultiByteToWideChar) (UINT, DWORD, LPCCH, int, LPWSTR, int); + int (WINAPI * WideCharToMultiByte) (UINT, DWORD, LPCWCH, int, LPSTR, int, LPCCH, LPBOOL); + int (WINAPI * GetLastError) (); + BOOL (WINAPI * QueryPerformanceCounter) (LARGE_INTEGER *); + BOOL (WINAPI * QueryPerformanceFrequency) (LARGE_INTEGER *); + void (WINAPI * GetLocalTime) (LPSYSTEMTIME); + + // Win32 funcs from user32.dll + int (WINAPI * MessageBoxA) (HWND, LPCSTR, LPCSTR, UINT); + + // Win32 funcs from Msimg32.dll + BOOL (WINAPI * TransparentBlt) (HDC, int, int, int, int, HDC, int, int, int, int, UINT); + + // C standard library functions + int (* snprintf) (char *, size_t, char const *, ...); + void * (* malloc) (size_t); + void * (* calloc) (size_t, size_t); + void * (* realloc) (void *, size_t); + void (* free) (void *); + long (* strtol) (char const *, char **, int); + float (* strtof) (char const *, char **); + int (* strcmp) (char const *, char const *); + int (* strncmp) (char const *, char const *, size_t); + int (* _stricmp) (char const *, char const *); + size_t (* strlen) (char const *); + char * (* strncpy) (char *, char const *, size_t); + char * (* strcpy) (char *, char const *); + char * (* strdup) (char const *); + char * (* strstr) (char const *, char const *); + void (* qsort) (void *, size_t, size_t, int (*) (void const *, void const *)); + int (* memcmp) (void const *, void const *, size_t); + void * (* memcpy) (void *, void const *, size_t); + void * (* memmove) (void *, void const *, size_t); + int (* tolower) (int); + int (* toupper) (int); + + Unit * sb_next_up; // The unit currently doing a stack bombard or NULL otherwise. Gets set to NULL if the unit is despawned. + + Trade_Net * trade_net; // Pointer to the trade net object. If it hasn't been moved by the mod, this equals p_original_trade_net. + int city_limit; // Stores the current actual city limit. Not necessarily the same as the stride of the trade net matrix or the config setting. + + enum init_state trade_net_addrs_load_state; + int * trade_net_addrs; + + HMODULE trade_net_x; + void (__stdcall * set_exe_version) (int); + void * (__stdcall * create_tnx_cache) (Map *); + void (__stdcall * destroy_tnx_cache) (void *); + void (__stdcall * set_up_before_building_network) (void *); + int (__stdcall * get_move_cost_for_sea_trade) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags, int neighbor_index, Trade_Net_Distance_Info * dist_info); + void (__stdcall * flood_fill_road_network) (void * tnx_cache, int from_x, int from_y, int civ_id); + bool (__stdcall * try_drawing_sea_trade_route) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags); + + void * tnx_cache; // Cache object used by Trade Net X. Initially NULL, must be recreated every time a new map is loaded. + enum init_state tnx_init_state; + bool is_computing_city_connections; // Set to true only while Trade_Net::recompute_city_connections is running + bool keep_tnx_cache; + + // This flag gets set whenever a trade deal is signed or broken for a resource that's an input to a mill. It's necessary to call + // recompute_resources in that case since a mill may have been de/activated by the change. We can't call it right when the change happens as + // that can crash the game for reasons I don't completely understand. I believe it's because the recomputation can't be done while some other + // econ logic is running. Instead, we set this variable then recompute before obsolete data would be an issue. Specifically, this is done: + // - When any player or AI begins their production phase + // - When the player zooms to any city + // - When the player opens the shift + right-click production chooser menu + // - When the player visits any advisor + // - When the player selects any unit + bool must_recompute_resources_for_mill_inputs; + + bool is_placing_scenario_things; // Set to true only while Map::place_scenario_things is running + + bool paused_for_popup; // Set to true while a popup, map message, or the diplo screen is open + long long time_spent_paused_during_popup; // Tracks time spent waiting for the three things above + + // This variable is increased with the time elapsed during every call to Trade_Net::recompute_city_connections. Time is measured using + // Windows performance counter. + long long time_spent_computing_city_connections; + int count_calls_to_recompute_city_connections; + + long long time_spent_filling_roads; + + struct c3x_config current_config; + + // Keeps a record of all configs currently loaded. Useful to know. "name" is the file name for configs that come from files, which is all of + // them except for the base config, whose name is "(base)". + struct loaded_config_name { + char * name; + struct loaded_config_name * next; + } * loaded_config_names; + + char current_districts_config_path[MAX_PATH]; + + char mod_script_path[MAX_PATH]; + + char * c3x_labels[COUNT_C3X_LABELS]; + + int have_job_and_loc_to_skip; // 0 or 1 if the variable below has anything actionable in it. Gets cleared to 0 after every turn. + struct worker_job_and_location to_skip; + + struct table saved_code_areas; + + int * unit_menu_duplicates; // NULL initialized, allocated to an array of 0x100 ints when needed + bool named_tile_menu_active; + int named_tile_menu_tile_x; + int named_tile_menu_tile_y; + + // List of temporary ints. Initializes to NULL/0/0, used with functions "memoize" and "clear_memo" + int * memo; + int memo_len; + int memo_capacity; + + // Array mapping cultural neighbor indices to the standard indices that correspond to the same tiles. Generated at program start. + byte * cultural_ni_to_standard; + + // Array mapping standard neighbor indices to the smallest work radius that includes the corresponding tile. Ex., if a given n.i. corresponds + // to one of the adjacent tiles, maps to 1, if it's in the fat cross but not adjacent, maps to 2, and so forth, out into the extended area. + char ni_to_work_radius[256]; + + // The maximum number of tiles workable by cities including the city tile itself (21 under standard game rules). Updated whenever the + // city_work_radius config value gets changed. + int workable_tile_count; + + // The civ ID of the player from whose perspective we're currently showing city loc desirability, or -1 if none. Initialized to -1. + int city_loc_display_perspective; + + // These are all bit fields that run parallel to player bits. Each bit indicates whether or not that name was replaced with an era-specific + // version for that player. This allows us to tell the difference between custom names set by human players and replacements made by the mod. + int aliased_civ_noun_bits; + int aliased_civ_adjective_bits; + int aliased_civ_formal_name_bits; + int aliased_leader_name_bits; + int aliased_leader_title_bits; + + // Stores resource access bits for resources beyond the first 32, used to fix the phantom resource bug. Initialized to NULL/0 and allocated as + // necessary by get_extra_resource_bits. Contains an array of groups of unsigned ints. There is one group per city (allocated lazily so you + // must use the getter) and the number of ints in each group depends on the number of resources defined in the scenario, one for every 32 + // after the first 32. + unsigned * extra_available_resources; + int extra_available_resources_capacity; // In number of cities. + + // These lists store interception events per-player during the interturn so we can clear the interception state on fighters that have done so + // at the beginning of their next turn. The point of this is to imitate the base game behavior where fighters that perform an interception are + // knocked out of the interception state. We can't knock them out immediately b/c that will prevent them from doing multiple interceptions per + // turn, so instead we record the event in these lists and reset their state later. + struct interceptor_reset_list { + struct interception { + int unit_id; + int x, y; + } * items; + int count; + int capacity; + } interceptor_reset_lists[32]; + + // Records the turn number on which each player has most recently founded a city. This is intended to be used for the temp settler perfume + // after founding feature so it may not be set if that feature is not activated or applicable. Defaults to -1. + int turn_no_of_last_founding_for_settler_perfume[32]; + + // Stores the byte offsets into the c3x_config struct of all boolean/integer config options, accessible using the options' names as + // strings. Used when reading in a config INI file. + struct table boolean_config_offsets; + struct table integer_config_offsets; + + // Maps unit types IDs to AI strategy indices (0 = offense, 1 = defense, 2 = artillery, etc.). If a unit type ID is in this table, that means + // it's one of several duplicate types created to spread multiple AI strategies out so each type has only one. + struct table unit_type_alt_strategies; + + // Stores a linked list of unit type duplicates. Maps unit type IDs to the next duplicate ID. Use list_unit_type_duplicates to get the list of + // the duplicates of a particular type as an array. + struct table unit_type_duplicates; + + // Tracks the number of "extra" defensive bombards units have performed, by their IDs. If the "blitz" special defensive bombard rule is + // activated, units with blitz get an extra chance to perform DB for each movement point they have beyond the first. + struct table extra_defensive_bombards; + + // Table mapping unit IDs to how many times that unit has airdropped on the current turn. This is used to prevent units from airdropping + // multiple times. That doesn't matter for the base game but stops the dont-end-turn-after-airdrop setting from letting units airdrop an + // unlimited number of times. + struct table airdrops_this_turn; + + // Stores city improvement bits for improvs beyond the first 256 + struct table extra_city_improvs; + + // These variables store the number of units of each type that each player has + int unit_type_count_init_bits; // Player bits tracking which unit type count tables have been initialized. + struct table unit_type_counts[32]; // One table per player. Each one maps unit type ids (ints) to counts (ints) + + // ========== + // } These fields are valid only after init_stackable_command_buttons has been called. { + // ========== + + struct sc_button_image_set { + Sprite imgs[4]; + } sc_button_image_sets[COUNT_STACKABLE_COMMANDS]; + + int sb_activated_by_button; // Gets set to 1 when the player clicks on the SB button so that perform_action_on_tile knows + // to do stack instead of regular bombard. This is necessary since the SB button actually just activates regular bombard. + // The proper way to implement the SB button would be to give it its own mode action but that's difficult to do because + // the existing mode actions are baked into the code. Implementing it this way I estimate is less fragile and requires + // less patching. The hard part is knowing when to clear this flag so that the player doesn't activate SB, cancel it, then + // activate regular bombard and get SB instead. One trick to make this easier is to look for the change of cursor away + // from the little bomb indicator instead of trying to intercept every relevant UI event. This flag is changed in these + // circumstances: + // (1) At init, the flag is cleared, of course. + // (2) Pressing the SB button sets the flag and pressing another unit command button clears it. + // (3) If handle_cursor_change_in_jgl is called and the main_screen_form's Mode_Action isn't (air) bombard, the flag + // is cleared. That covers every case of switching off SB mode except one, when the player presses a key to switch + // off of SB to regular bombard, that's what case (4) is for. + // (4) The flag is cleared when the player presses the B key or (if the unit is capable of precision strikes) the P key. + // One final complication, that I only discovered after trying to implement this, is that when clicking on the map with a + // mode action, the cursor is cleared before the action is carried out. So we have to intercept that map click as well for + // a total of 4 UI functions patched to make this damn button work. I doubt this is optimal but it works and I've wasted + // enough time on this already. That click interceptor sets a flag value of 2 to indicate this annoying state. + + // ========== + // } This field is only valid after init_disabled_command_buttons has been called and disabled_command_img_state equals IS_OK { + // ========== + + Sprite disabled_build_city_button_img; + + // ========== + // } This field is only valid after init_unit_rcm_icons has been called and unit_rcm_icon_state equals IS_OK { + // ========== + + // Sprites are stored together as sets, so the first COUNT_UNIT_RCM_ICONS elements are those from the first set, then the same number from the + // second set, etc. + Sprite unit_rcm_icons[COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS]; + + // ========== + // } These fields are valid only after init_tile_highlights as been called. { + // ========== + + Sprite tile_highlights[COUNT_TILE_HIGHLIGHTS]; + + // ========== + // } This one is valid only if init_mod_info_button_images has been called and mod_info_button_images_state equals IS_OK { + // ========== + + Sprite mod_info_button_images[3]; + + // ========== + // } This one is valid only if init_red_food_icon has been called and red_food_icon_state equals IS_OK { + // ========== + + Sprite red_food_icon; + + // ========== + // } These are valid only if init_large_minimap_frame has been called and large_minimap_frame_img_state equals IS_OK { + // ========== + + Sprite double_size_box_left_color_pcx, double_size_box_left_alpha_pcx; + + // ========== + // } These fields are temporary/situational { + // ========== + + int saved_road_movement_rate; // Valid when railroad movement limit is applied (limit_railroad_movement > 0) and BIC data has been loaded + int road_mp_cost; // The cost of moving one tile along a road, in MP. Valid after BIC data was loaded. + int railroad_mp_cost_per_move; // The cost of moving one tile along a railroad, in MP, per move available to the unit. This is measured per + // move since the cost of moving along a railroad is scaled by the total number of moves available to the + // unit. Valid after BIC data was loaded. + + int saved_barb_culture_group; // Valid when barb city capturing is enabled and BIC data has been loaded + + Leader * leader_param_for_patch_get_wonder_city_id; // Valid in patch_get_wonder_city_id when called from + // Leader_recompute_auto_improvements + + int show_popup_was_called; // Set to 1 in show_popup. Used in patch_Leader_can_do_worker_job to check if the replacement + // popup was shown. + + // Used to control trade screen scroll + int open_diplo_form_straight_to_trade; // Initialized to 0, gets set to 1 by patch_DiploForm_do_diplomacy to signal + // to patch_DiploForm_m68_Show_Dialog to open the diplo form straight into trade mode. + int trade_screen_scroll_to_id; // Set by patch_DiploForm_m82_handle_key_event to signal to do_diplomacy that the form + // was closed in order to scroll to the civ with the set ID. -1 indicates no scrolling. + Button * trade_scroll_button_left; // initialized to NULL + Button * trade_scroll_button_right; // initialized to NULL + Sprite * trade_scroll_button_images; // inited to NULL, array of 6 images: normal, rollover, and highlight for left & right + enum init_state trade_scroll_button_state; + int eligible_for_trade_scroll; + + char ask_gold_default[32]; + + // Set in patch_ai_choose_production, used by the various bits of injected code that run during the AI production choosing process. + City * ai_considering_production_for_city; + + // This variable stores what improvement or unit the AI is evaluating inside ai_choose_production. It gets set inside two call replacements, + // first inside the loop over improvements then again inside a loop over unit types. The var is used by the intercept consideration functions + // which run at the end of each loop iteration. + City_Order ai_considering_order; + int handling_ai_district_fallback; + + // Used in the code that adds additional info to the tile info box + bool tile_info_open; + int viewing_tile_info_x, viewing_tile_info_y; + + // Used in patch_Tile_m43_Get_field_30_for_city_loc_eval to change how the AI evaluates overlap between cities + int ai_evaling_city_loc_x, ai_evaling_city_loc_y; + int ai_evaling_city_field_30_get_counter; + + // Stores a list of the production options in a given city and the point value the AI would assign to each. The list is populated by + // rank_ai_production_options, items are added by record_improv_val which gets called by some code injected into one of the loops in + // ai_choose_production. These vars are initialized to zero. + struct ai_prod_valuation * ai_prod_valuations; + int count_ai_prod_valuations; + int ai_prod_valuations_capacity; + + // Used for generating resources from buildings and districts + struct extra_resource_tile * resource_tiles; + int count_resource_tiles; + int resource_tiles_capacity; + struct extra_resource_tile * got_resource_tile; + int saved_tile_count; // Stores the actual tile count in case p_bic_data->Map.TileCount was temporarily overwritten. Set to -1 when empty. + byte * mill_input_resource_bits; // Array of bits, one for each resource. Stores whether or not each one is an input to any mill. + + // Used for displaying yields from generated resources on the city screen + int tourism_icon_counter; // Incremented each time a tourism yield icon (normally commerce) is drawn. Reset between improvs. + int convert_displayed_tourism_to_food, convert_displayed_tourism_to_shields; // Number of commerce tourism icons to convert to food, shields + int combined_tourism_and_mill_commerce; // Number of commerce tourism icons to display inc. from mills, maybe negative + + int drawing_icons_for_improv_id; // Stores the improv ID whose icons we're drawing. -1 while not drawing. + + PCX_Image * resources_sheet; // Sprite sheet of resource icons, i.e. resources.pcx + + Sprite tile_already_worked_zoomed_out_sprite; // Valid only if init state is OK + + // Only for use by patch_City_Form_draw_yields_on_worked_tiles and patch_Sprite_draw_already_worked_tile_img + bool do_not_draw_already_worked_tile_img; + + // Stores the trade offer object being modified when the user right-clicks on a gold offer/ask on the trade table. Gets set by a special + // function call replacement (see apply_machine_code_edits for details). + TradeOffer * modifying_gold_trade; + + // Initialized to NULL and reset to NULL after Unit::bombard_tile returns. Gets set just before the call to Unit::play_bombard_fire_animation + // from inside bombard_tile. The value is the unit on the bombarded tile specifically targeted by the attack, if applicable. + Unit * bombard_stealth_target; + + // Set to zero when Unit::select_stealth_attack_target is called then checked inside in the call to PopupSelection::add_item and set to + // 1. This variable lets the add_item replacement function run special code for only the first item added, in order to insert an additional + // first option to cancel the stealth attack. + int added_any_stealth_target; + + // Initialized to zero. Temporarily set to 1 across a call to patch_Unit_select_stealth_attack_target to request that the selected target must + // be suitable for attack via bombardment. + int selecting_stealth_target_for_bombard; + + // Set in rand_int_to_dodge_city_aa and read immediately after in Unit_get_defense_to_dodge_city_aa. Allows us to determine whether the dodge + // roll was successful in order to popup the message. + int result_of_roll_to_dodge_city_aa; + + // Initialized to NULL. If set to non-NULL, the next call to show_map_message will consume that value and use it as the text on the + // message. Used to implement show_map_specific_text. + char const * map_message_text_override; + + // Initialized to NULL. If set to non-NULL, the next call to do_load_game will consume this value and use it as the file path of the game to + // load instead of opening the file picker. + char const * load_file_path_override; + + // A set of player bits indicating which players should see a replay of the AI's moves. Normally all zero, gets filled in by + // patch_perform_interturn_in_main_loop only when/as appropriate. As replays are played (in patch_show_movement_phase_popup), the + // corresponding bits are cleared. + int replay_for_players; + + // Used by patch_perform_interturn_in_main_loop to determine which players need to see the replay. Clear before interturn processing, then + // every time an AI unit moves onto or bombards a tile, any players that have vision on that tile will have their bit set in this var. + int players_saw_ai_unit; + + // Initialized to 0. If set to non-zero, the next call to do_load_game will consume the value and skip the intro popup. + int suppress_intro_after_load_popup; + + struct improv_id_list { + int * items; + int count; + int capacity; + } water_trade_improvs, air_trade_improvs, combat_defense_improvs; + + // Used by the fix for the barbarian diagonal bug + int barb_diag_patch_dy_fix; + + // Initialized to 0. If 1, barbarian activity is force activated b/c there are barb cities on the map that need to do production. + int force_barb_activity_for_cities; + + // Used as a stand-in for an actual tile where needed. In particular, this object is returned from various get_tile and tile_at replacements + // when we need to override the visibility data to implement hotseat shared vis. + Tile * dummy_tile; + + // When the game checks visibility for a tile, it accesses all four visibility fields with separate calls to Map::get_tile and/or tile_at. We + // replace the first call, maybe altering its return to implement shared visibility, cache the return in this variable, then re-use the cached + // value for the next three calls. + Tile * tile_returned_for_visibility_check; + + // Initialized to all -1. If set, the unit with the specified ID will always be the top unit displayed on the specified tile. If the unit is + // not on that tile, there is no effect. This is only intended to be used on a temporary basis. + struct unit_display_override { + int unit_id, tile_x, tile_y; + } unit_display_override; + + // Set in patch_Fighter_get_odds_for_main_combat_loop, read by patch_Unit_get_attack/defense_strength. + // Stores counter multipliers for the current combat. Active only during Fighter_get_combat_odds call. + struct { + bool active; + Unit * attacker; + Unit * defender; + int attacker_atk_pct; // Attacker attack multiplier (combines forward self-atk and reverse enemy-atk) + int defender_def_pct; // Defender defense multiplier (combines forward enemy-def and reverse self-def) + bool ignore_terrain; + } counter_combat_ctx; + + // Used to extract which unit (if any) exerted zone of control from within Fighter::apply_zone_of_control. + Unit * zoc_interceptor; + + // Set when Fighter::apply_zone_of_control is called to store the defending unit, used by the injected filter and Unit::move_to_adjacent_tile. + // Cleared at each call to move_to_adjacent_tile and by Unit::despawn. + Unit * zoc_defender; + + // Set to the bombarding unit while Unit::bombard_tile is running. NULL otherwise. + Unit * bombarding_unit; + + // Normally set to NULL. When a unit bombards a tile (the tile itself, not something on it), set to point to that unit during the call to + // Unit::attack_tile. Used to stop the unit from losing all of its movement if configured. + Unit * unit_bombard_attacking_tile; + + // Set to the coords of the tile being attacked while Unit::attack_tile is running, -1 otherwise. + int attacking_tile_x, attacking_tile_y; + + // Cleared to false when Fighter::apply_zone_of_control is called. The interceptor must be unfortified to ensure it plays its animation. If + // that happens, this flag is set so that apply_zone_of_control knows to refortify the unit after the ZoC process is done. + bool refortify_interceptor_after_zoc; + + // These flags are used to turn off lethal ZoC for units that capture an enemy on the tile they're moving into. Without this rule, the unit + // might get killed by ZoC but the captured units will remain on a tile that was never actually entered (that tile might have an enemy city + // for extra weirdness). Here's how it works: + // 1. The moving_unit_to_adjacent_tile flag is set when Unit::move_to_adjacent_tile is called. + // 2. If that flag is set and a unit is captured (detected by intercepting the calls to Leader::spawn_unit inside Unit::do_capture_units) + // then temporarily_disallow_lethal_zoc is set. + // 3. If temporar... is set, the code to filter ZoC interceptors acts as if lethal ZoC were turned off. + // 4. Both flags are cleared when Unit::move_to_adjacent_tile returns. + bool temporarily_disallow_lethal_zoc; + bool moving_unit_to_adjacent_tile; + + // Tracks temporary transport bypass when letting workers step onto coast tiles without a boat + Unit * coast_walk_unit; + bool coast_walk_transport_override; + enum UnitStateType coast_walk_prev_state; + int coast_walk_prev_container; + bool coast_walk_restore_goto_path; + int coast_walk_prev_path_len; + int coast_walk_prev_path_dest_x; + int coast_walk_prev_path_dest_y; + Unit * move_spend_override_unit; + int move_spend_override_value; + + // Used to record info about a defensive bomardment event during Fighter::fight. Gets set by Fighter::damage_by_defensive_bombardment and + // cleared when Fighter::fight returns. + struct defensive_bombard_event { + Unit * bombarder; + Unit * defender; + bool damage_done, defender_was_destroyed, saved_animation_setting; + } dbe; + + // Set to true IFF we're showing a replay of AI moves in hotseat mode + bool showing_hotseat_replay; + + // Set to true only during the first call to get_tile_occupier_id from Trade_Net::get_movement_cost. While this is set, we need to edit unit + // visibility to patch the submarine bug. + bool getting_tile_occupier_for_ai_pathfinding; + + bool running_on_wine; // Set to 1 IFF we're running in Wine, as opposed to actual Windows + + // gdi_plus.init_state is valid any time after patch_init_floating_point. All the other fields are only valid after set_up_gdi_plus has been + // called and gdi_plus.init_state equals IS_OK. + struct gdi_plus { + enum init_state init_state; + HMODULE module; + ULONG_PTR token; + void * gp_graphics; + + int (__stdcall * CreateFromHDC) (HDC hdc, void ** p_gp_graphics); + int (__stdcall * DeleteGraphics) (void * gp_graphics); + int (__stdcall * SetSmoothingMode) (void * graphics, int smoothing_mode); + int (__stdcall * SetPenDashStyle) (void * gp_pen, int dash_style); + int (__stdcall * CreatePen1) (unsigned int argb_color, float width, int gp_unit, void ** p_gp_pen); + int (__stdcall * DeletePen) (void * gp_pen); + int (__stdcall * DrawLineI) (void * gp_graphics, void * gp_pen, int x1, int y1, int x2, int y2); + } gdi_plus; + + // These variables track the states of some OpenGL parameters. They're updated whenever methods like OpenGLRenderer::set_color are called. + unsigned int ogl_color; + int ogl_line_width; + bool ogl_line_stipple_enabled; + + // Records how many units of each type we're going to upgrade to during an upgrade-all. This info will be used to impose the unit type limit + // during the upgrade. Keep in mind units all get upgraded from the same type but might end up as different types after upgrade-all. + struct penciled_in_upgrade { + int unit_type_id; + int count; + } * penciled_in_upgrades; + int penciled_in_upgrade_count; + int penciled_in_upgrade_capacity; + + // While in Leader::do_capture_city, the city in question is stored in this var. Otherwise it's NULL. + City * currently_capturing_city; + + // While a game is being saved or loaded, this variable points to the save file's MappedFile object. Otherwise it's NULL. + MappedFile * accessing_save_file; + + // Used in patch_work_simple_job. If a method sets this variable while that method is running then at the end it sets the given tile as LM. + Tile * lmify_tile_after_working_simple_job; + + // Reset to zero every time City_Form::draw is called. Incremented everything a strategic resource is drawn on the city screen. + int drawn_strat_resource_count; + + int * charmed_types_converted_to_ptw_arty; + int count_charmed_types_converted_to_ptw_arty; + int charmed_types_converted_to_ptw_arty_capacity; + + // While Unit::is_visible_to_civ is running, this var is set to the unit in question. Otherwise it's NULL. + Unit * checking_visibility_for_unit; + + // Normally false. When true, calls to bounce_trespassing_units won't kick out invisible units even if they're revealed. + bool do_not_bounce_invisible_units; + + // Normally false. When true, Unit::despawn also despawns any passenger units inside instead of making exceptions in some cases. + bool always_despawn_passengers; + + // Normally false. When true, calls to Unit::score_kill will not enslave. + bool do_not_enslave_units; + + // If limit_unit_loading_to_one_transport_per_turn is on, maps unit IDs to the ID of the transport unit they're tied to for the current turn. + struct table unit_transport_ties; + + // Initialized to NULL/0, used in patch_City_add_happiness_from_buildings + short * saved_improv_counts; + int saved_improv_counts_capacity; + + // Used to de-overlap specialist yield icons (option name fix_overlapping_specialist_yield_icons) + int specialist_icon_drawing_running_x; + + // Initialized to 0, used to draw multipage descriptions in the Civilopedia + struct civilopedia_multipage_description { + bool drawing_lines; + int line_count; + int shown_page; // zero-based + int last_page; // also zero-based + Civilopedia_Article * article; + Button * effects_btn; + Button * previous_btn; + } cmpd; + + // When expand_civilopedia_unit_stats is on, all the game's calls to draw_and_wrap_text to draw the second column of unit stats are + // intercepted to draw nothing and store their strings here. Then we possible add some entries of our own. The game will add up to 6 entries + // and we'll add up to 4. + char * pedia_unit_stats_second_column_strs[10]; + + // Day-Night cycle data + int current_day_night_cycle; + bool day_night_cycle_unstarted; // If current_day_night_cycle has not been set, f.e. because it's the first turn of a new game. + bool day_night_cycle_img_proxies_indexed; + LARGE_INTEGER last_day_night_cycle_update_time; + + struct table day_night_sprite_proxy_by_hour[24]; + + struct wonder_district_image_set { + Sprite img; + Sprite construct_img; + Sprite alt_dir_img; + Sprite alt_dir_construct_img; + } wonder_district_img_sets[MAX_WONDER_DISTRICT_TYPES]; + + struct natural_wonder_district_image_set { + Sprite img; + } natural_wonder_img_sets[MAX_NATURAL_WONDER_DISTRICT_TYPES]; + struct natural_wonder_label_draw_info { + int text_left; + int text_top; + int text_width; + int font_size; + char const * text; + }; + + struct day_night_cycle_img_set + { + SpriteList Std_Terrain_Images[9]; + SpriteList LM_Terrain_Images[9]; + Sprite City_Images[80]; + Sprite Destroyed_City_Images[3]; + Sprite Resources[36]; + Sprite ResourcesShadows[36]; + Sprite Terrain_Buldings_Barbarian_Camp; + Sprite Terrain_Buldings_Mines; + Sprite Victory_Image; + Sprite Flood_Plains_Images[16]; + Sprite Fog_Of_War_Images[81]; + Sprite Polar_Icecaps_Images[32]; + Sprite Railroads_Images[272]; + Sprite Roads_Images[256]; + Sprite Minor_Roads_Images[256]; + Sprite Terrain_Buldings_Airfields[2]; + Sprite Terrain_Buldings_Airfields_Shadow[2]; + Sprite Terrain_Buldings_Camp[4]; + Sprite Terrain_Buldings_Fortress[4]; + Sprite Terrain_Buldings_Barricade[4]; + Sprite Goody_Huts_Images[8]; + Sprite Terrain_Buldings_Outposts[3]; + Sprite Terrain_Buldings_Outposts_Shadow[3]; + Sprite Pollution[25]; + Sprite Craters[25]; + Sprite Terrain_Buldings_Radar; + Sprite Terrain_Buldings_Radar_Shadow; + Sprite Tnt_Images[18]; + Sprite Waterfalls_Images[4]; + Sprite LM_Terrain[7]; + Sprite Marsh_Large[8]; + Sprite Marsh_Small[10]; + Sprite Volcanos_Images[16]; + Sprite Volcanos_Forests_Images[16]; + Sprite Volcanos_Jungles_Images[16]; + Sprite Volcanos_Snow_Images[16]; + Sprite Grassland_Forests_Large[8]; + Sprite Plains_Forests_Large[8]; + Sprite Tundra_Forests_Large[8]; + Sprite Grassland_Forests_Small[10]; + Sprite Plains_Forests_Small[10]; + Sprite Tundra_Forests_Small[10]; + Sprite Grassland_Forests_Pines[12]; + Sprite Plains_Forests_Pines[12]; + Sprite Tundra_Forests_Pines[12]; + Sprite Irrigation_Desert_Images[16]; + Sprite Irrigation_Plains_Images[16]; + Sprite Irrigation_Images[16]; + Sprite Irrigation_Tundra_Images[16]; + Sprite Grassland_Jungles_Large[8]; + Sprite Grassland_Jungles_Small[12]; + Sprite Mountains_Images[16]; + Sprite Mountains_Forests_Images[16]; + Sprite Mountains_Jungles_Images[16]; + Sprite Mountains_Snow_Images[16]; + Sprite Hills_Images[16]; + Sprite Hills_Forests_Images[16]; + Sprite Hills_Jungle_Images[16]; + Sprite Delta_Rivers_Images[16]; + Sprite Mountain_Rivers_Images[16]; + Sprite Territory_Images[8]; + Sprite LM_Mountains_Images[16]; + Sprite LM_Forests_Large_Images[8]; + Sprite LM_Forests_Small_Images[10]; + Sprite LM_Forests_Pines_Images[12]; + Sprite LM_Hills_Images[16]; + Sprite District_Images[COUNT_DISTRICT_TYPES][MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [district][variant][era][column] + Sprite Abandoned_District_Image; + Sprite Abandoned_Maritime_District_Image; + struct wonder_district_image_set Wonder_District_Images[MAX_WONDER_DISTRICT_TYPES]; + struct natural_wonder_district_image_set Natural_Wonder_Images[MAX_NATURAL_WONDER_DISTRICT_TYPES]; + } day_night_cycle_imgs[24]; + + // Districts + enum init_state dc_img_state; + enum init_state dc_btn_img_state; + enum init_state dc_icons_img_state; + + struct district_config district_configs[COUNT_DISTRICT_TYPES]; + struct wonder_district_config wonder_district_configs[MAX_WONDER_DISTRICT_TYPES]; + struct natural_wonder_district_config natural_wonder_configs[MAX_NATURAL_WONDER_DISTRICT_TYPES]; + +struct district_image_set { + Sprite imgs[MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [variant][era][column] +} district_img_sets[COUNT_DISTRICT_TYPES]; + Sprite abandoned_district_img; + Sprite abandoned_maritime_district_img; + +struct district_button_image_set { + Sprite imgs[4]; +} district_btn_img_sets[COUNT_DISTRICT_TYPES]; + + // Building ID keys -> district ID. If a building ID is present in the + // table that means that building can only be built if there is a corresponding district is present in the city radius. + struct table district_building_prereqs; + + // Tile pointer IDs -> district_instance pointer. Maps tiles to dynamically allocated + // district_instance structs tracking district type and state (UNDER_CONSTRUCTION or COMPLETED). + // For wonder districts, the wonder_info field tracks wonder-specific state (unused, reserved, completed, ruined), + // which city reserved/completed the wonder, and which wonder index is on this district. + struct table district_tile_map; + struct table named_tile_map; + + // Tracks per-turn airlift usage for aerodrome districts (tile pointer -> civ bitmask). + struct table aerodrome_airlift_usage; + + // Command ID keys -> district ID. Used to identify which district + // a unit command (e.g., build order) corresponds to. + struct table command_id_to_district_id; + + // Array of 32 tables (one per civ) of pending district requests keyed by city & district (values are struct pending_district_request pointers). + struct table city_pending_district_requests[32]; + + // City pointer keys -> improvement ID. Tracks which improvements (buildings/wonders) + // requiring districts a city has ordered to be built (pending district completion). + struct table city_pending_building_orders; + + // AI cache mapping city pointer keys -> AI_Order pointer. Stores the best feasible + // production order for AI cities to optimize decision-making. + struct table ai_best_feasible_orders; + + // String building/wonder name keys -> int building/improvement ID. + // Used to look up building IDs by their text names from the game data. + struct table building_name_to_id; + + struct district_infos { + int advance_prereq_ids[MAX_DISTRICT_DEPENDENTS]; // Tech IDs that enable the district (all required) + int advance_prereq_count; + int obsoleted_by_id; + int resource_prereq_ids[MAX_DISTRICT_DEPENDENTS]; + int resource_prereq_count; + int resource_prereq_on_tile_id; + int wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; + int wonder_prereq_count; + int natural_wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; + int natural_wonder_prereq_count; + int dependent_building_count; + int dependent_building_ids[MAX_DISTRICT_DEPENDENTS]; // Building types the district enables + } district_infos[COUNT_DISTRICT_TYPES]; + + // District tracking counters: total = special (hard-coded) + dynamic (from config/scenario) + // next_custom_dynamic_command_index assigns unique command IDs for custom dynamic commands + int district_count; + int special_district_count; + int dynamic_district_count; + int wonder_district_count; + int natural_wonder_count; + int next_custom_dynamic_command_index; + + // Distribution Hub tracking: records keyed by tile plus per-tile coverage counts; dirty/refresh flags + // control when totals are recalculated + struct table distribution_hub_records; + struct table distribution_hub_coverage_counts; + bool distribution_hub_totals_dirty; + bool distribution_hub_refresh_in_progress; + + // Distribution Hub UI sprites loaded from PCX files for rendering food/shield icons in city interface + // *_icons_remaining counters track how many icons to draw from each source (non-district, district, hub, corruption) + Sprite distribution_hub_shield_icon; + Sprite distribution_hub_corruption_icon; + Sprite distribution_hub_food_icon; + Sprite distribution_hub_eaten_food_icon; + Sprite distribution_hub_shield_icon_small; + Sprite distribution_hub_food_icon_small; + int non_district_shield_icons_remaining; + int corruption_shield_icons_remaining; + int district_shield_icons_remaining; + int distribution_hub_shield_icons_remaining; + int district_corruption_icons_remaining; + int distribution_hub_corruption_icons_remaining; + + // District UI sprites loaded from PCX files for rendering yield icons (science, commerce, shield, food, culture, happiness) + // Available in both regular and small sizes for different UI contexts in city interface + Sprite district_science_icon; + Sprite district_commerce_icon; + Sprite district_shield_icon; + Sprite district_corruption_icon; + Sprite district_food_icon; + Sprite district_food_eaten_icon; + Sprite district_happiness_icon_small; + Sprite district_shield_icon_small; + Sprite district_commerce_icon_small; + Sprite district_food_icon_small; + Sprite district_science_icon_small; + Sprite district_culture_icon_small; + Sprite district_unhappiness_icon_small; + Sprite district_negative_shield_icon_small; + Sprite district_negative_commerce_icon_small; + Sprite district_negative_food_icon_small; + Sprite district_negative_science_icon_small; + Sprite district_negative_culture_icon_small; + + // Guard to prevent recursive sharing when auto-adding buildings across cities + bool sharing_buildings_by_districts_in_progress; + + // Worker tracking: 32 tables (one per civ), each mapping unit_id -> district_worker_record pointer + struct table district_worker_tables[32]; + + // Natural Wonder labels: table mapping natural wonder name strings to their IDs, count of defined natural wonders, + struct table natural_wonder_name_to_id; + + struct ai_candidate_bridge_or_canal_entry * ai_candidate_bridge_or_canals; + int ai_candidate_bridge_or_canals_count; + int ai_candidate_bridge_or_canals_capacity; + bool ai_candidate_bridge_or_canals_initialized; + + // City work radius highlighting: flag to enable/disable, table mapping tile pointers to highlight_level for visual feedback + bool highlight_city_radii; + struct table highlighted_city_radius_tile_pointers; + + // Initialized to 0. Every time Main_Screen_Form::m82_handle_key_event receives an event with is_down == 0, the virtual key code is prepended + // to this list. + int last_main_screen_key_up_events[5]; + + // Stores the parameters to Unit::can_load while it's running, NULL otherwise. + Unit * can_load_transport, * can_load_passenger; + + // Current tile being rendered in Map_Renderer_m19_Draw_Tile_by_XY_and_Flags. For use within various Map_Renderer::impl_m*_Draw_* functions. Nulled out after the render function is complete + Tile * current_render_tile; + struct district_instance * current_render_tile_district; + int current_render_tile_x, current_render_tile_y; + + // Used in patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp and so on for flagging whether to draw forests over roads on the tile being rendered + bool draw_forests_over_roads_on_tile; + + // Set to true once the auto-build process for the Great Wall is complete to avoid running it again + enum great_wall_auto_build_state great_wall_auto_build; + Tile * focused_tile; + + // Stores the improve ID currently being evaluated inside patch_City_can_build_improvement. + int current_evaluating_improve_id; + + // Stores the index in the list of target civs currently being drawn on the espionage form. Used to replace the civ name with its era-specific alias. + int espionage_form_drawing_target_index; + + // Tracks information about the last unit that was selected. These fields are updated when a new unit is selected or when the selected unit + // moves or is destroyed. + struct { + int initial_x, initial_y; // Stores the unit's location when it was selected + int last_x, last_y, type_id; // Stores the unit's current or last available location and type id + Unit * ptr; // A pointer to the unit, may be NULL if the unit was destroyed + } last_selected_unit; + + // Maps unit IDs to the level at which they are waiting. Units with lower levels move first. Units that have not been set to wait are not in the table. + struct table waiting_units; + + // Set to true when waiting_units has been initialized by loading from the save. Causes the game to skip clearing the table when setting up + // unit cycling for the turn. + bool have_loaded_waiting_units; + + // Used in patch_Unit_do_capture_units and patch_Unit_despawn + Unit ** extra_capture_despawns; + int count_extra_capture_despawns; + int extra_capture_despawns_capacity; + + // ========== + // } + // ========== +}; + +enum object_job { + OJ_DEFINE = 0, + OJ_INLEAD, // Patch this function with an inlead + OJ_REPL_VPTR, // Patch this function by replacing a pointer to it. The address column is the addr of the VPTR not the function itself. + OJ_REPL_CALL, // Patch a single function call. The address column is the addr of the call instruction, name refers to the new target function, type is not used. + OJ_REPL_VIS, // Patch a cluster of four function calls that make up a check of tile visibility. See implementation for details. + OJ_EXT_WALUP, // "EXTend Work Area LuP" Patch a jump instruction at the end of a "lup" (loop) over a city's workable area to extend it + OJ_IGNORE +}; + +struct civ_prog_object { + enum object_job job; + int addr; + char const * name; + char const * type; +}; diff --git a/DayNight/civ3_city_lights.py b/DayNight/civ3_city_lights.py index 794f4637..55cfd5d7 100644 --- a/DayNight/civ3_city_lights.py +++ b/DayNight/civ3_city_lights.py @@ -1,521 +1,521 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -Civ 3 city lights compositor for *_lights.pcx -- Recursive over Data/1200 → writes siblings 0100..2400 -- Multiple --light-key values (union mask) -- **Per-light-key styles** via --light-style: per-key core/glow colors and optional overrides -- Night (19..24,1..6): also replaces non-lights file -- Pins magenta #ff00ff to palette index 255; removes #00ff00 from palette -""" - -import argparse, os, math, shutil -from typing import List, Tuple, Dict, Optional -from PIL import Image, ImageChops, ImageFilter -from argparse import RawTextHelpFormatter - -MAGENTA = (255, 0, 255) -GREEN = (0, 255, 0) - -# ---------- parsing ---------- - -def parse_rgb_one(s: str) -> Tuple[int,int,int]: - s = s.strip() - if s.startswith("#"): - s = s[1:]; assert len(s)==6, "Hex color must be #rrggbb" - return int(s[0:2],16), int(s[2:4],16), int(s[4:6],16) - if "," in s: - a = [int(p) for p in s.split(",")]; assert len(a)==3, "RGB must be R,G,B" - return tuple(max(0,min(255,v)) for v in a) # type: ignore - raise ValueError("Color must be '#rrggbb' or 'R,G,B'") - -def parse_rgb_list(values: List[str]) -> List[Tuple[int,int,int]]: - out: List[Tuple[int,int,int]] = [] - for raw in values or []: - tokens = [t for t in raw.replace(";", " ").split() if t] - for tok in tokens: - out.append(parse_rgb_one(tok)) - if not out: out = [(0,254,255)] - dedup, seen = [], set() - for c in out: - if c not in seen: seen.add(c); dedup.append(c) - return dedup - -def parse_styles(values: List[str]) -> Dict[Tuple[int,int,int], Dict[str,object]]: - """ - --light-style "key=#00feff; core=#fff87a; glow=#ff8a20; core_gain=1.6; halo_gain=4.0; halo_sep=0.75; halo_gamma=1.35; core_radius=1.2; halo_radius=14; highlight=0.6" - Accepts ';' or ',' separators. Only 'key' is required; others override globals for that key. - """ - styles: Dict[Tuple[int,int,int], Dict[str,object]] = {} - for raw in values or []: - parts = [p.strip() for p in raw.replace(",", ";").split(";") if p.strip()] - kv: Dict[str,str] = {} - for p in parts: - if "=" in p: - k,v = p.split("=",1); kv[k.strip().lower()] = v.strip() - if "key" not in kv: raise SystemExit("Each --light-style must include key=") - key_rgb = parse_rgb_one(kv["key"]) - entry: Dict[str,object] = {} - if "core" in kv: entry["core_color"] = parse_rgb_one(kv["core"]) - if "glow" in kv: entry["glow_color"] = parse_rgb_one(kv["glow"]) - for numk in ["core_gain","halo_gain","core_radius","halo_radius","halo_sep","halo_gamma","highlight","size_boost","size_radius","size_gamma"]: - if numk in kv: - entry[numk] = float(kv[numk]) - styles[key_rgb] = entry - return styles - -# ---------- time window ---------- - -def hour_weight_lights(hour_1_24: int, start: float = 18.0, end: float = 6.0, floor: float = 0.80) -> float: - h = float(hour_1_24) % 24.0 - inwin = (h >= start) or (h <= end) - if not inwin: return 0.0 - L = (24.0 - start) + end - p = (h - start) if (h >= start) else ((24.0 - start) + h) - mid = 0.5*L; t = abs(p - mid)/mid - w = floor + (1.0 - floor)*0.5*(1.0 + math.cos(math.pi * t)) - return max(0.0, min(1.0, w)) - -def is_night_hour(hour_1_24: int) -> bool: - return (18 <= hour_1_24 <= 24) or (1 <= hour_1_24 <= 6) - -# ---------- palette ---------- - -def get_palette(image: Image.Image) -> List[int]: - pal = image.getpalette() or [] - if len(pal) < 256*3: pal += [0]*(256*3 - len(pal)) - return pal[:256*3] - -def put_palette(image: Image.Image, palette: List[int]) -> None: - if len(palette) < 256*3: palette += [0]*(256*3 - len(palette)) - image.putpalette(palette[:256*3]) - -def ensure_palette_has_colors(image: Image.Image, colors: List[Tuple[int,int,int]]) -> List[int]: - pal = get_palette(image) - to_add = [c for c in colors if find_color_index(pal,c)==-1] - if not to_add: return pal - hist = image.histogram() if image.mode=='P' else None - candidates = sorted(range(256), key=(lambda i: hist[i])) if (hist and len(hist)==256) else list(range(255,-1,-1)) - protected=set() - for rgb in colors+[MAGENTA]: - idx = find_color_index(pal, rgb) - if idx!=-1: protected.add(idx) - replace=[] - for i in candidates: - if i in protected: continue - replace.append(i) - if len(replace)>=len(to_add): break - if len(replace) int: - r,g,b = rgb - for i in range(256): - if palette[3*i]==r and palette[3*i+1]==g and palette[3*i+2]==b: return i - return -1 - -def quantize_to_p_256(img: Image.Image) -> Image.Image: - try: - dnone = Image.Dither.NONE - except Exception: - dnone = getattr(Image, "NONE", 0) - rgb = img.convert('RGB') - try: - return rgb.quantize(colors=256, method=Image.FASTOCTREE, dither=dnone) - except Exception: - return rgb.quantize(colors=256, dither=dnone) - -def force_magenta_at_255(im: Image.Image) -> int: - pal = get_palette(im) - old255 = (pal[3*255], pal[3*255+1], pal[3*255+2]) - idx_mag = find_color_index(pal, MAGENTA) - if idx_mag == -1: - pal = ensure_palette_has_colors(im, [MAGENTA]); put_palette(im, pal) - pal = get_palette(im); idx_mag = find_color_index(pal, MAGENTA) - if idx_mag == 255: return 255 - pal[3*255:3*255+3]=list(MAGENTA); pal[3*idx_mag:3*idx_mag+3]=list(old255) - put_palette(im, pal); return idx_mag - -# ---------- image ops ---------- - -def color_equal(img_rgb: Image.Image, color: Tuple[int,int,int]) -> Image.Image: - w,h = img_rgb.size - solid = Image.new('RGB',(w,h),color) - diff = ImageChops.difference(img_rgb, solid) - return diff.convert('L').point(lambda v: 255 if v==0 else 0, mode='L') - -def apply_gamma_L(imgL: Image.Image, gamma: float) -> Image.Image: - gamma = max(0.05, float(gamma)) - lut = [min(255, int(round((i/255.0) ** gamma * 255))) for i in range(256)] - return imgL.point(lut, mode='L') - -def scale_L(imgL: Image.Image, factor: float) -> Image.Image: - factor = max(0.0, float(factor)) - return imgL.point(lambda v: 255 if v*factor >= 255 else int(v*factor)) - -def screen_blend(a: Image.Image, b: Image.Image) -> Image.Image: - try: - return ImageChops.screen(a,b) - except AttributeError: - return ImageChops.invert(ImageChops.multiply(ImageChops.invert(a), ImageChops.invert(b))) - -# ---------- masks & glows ---------- - -def build_interior_mask(base_bg: Image.Image, clip: bool, erode_px: int) -> Image.Image: - if not clip: return Image.new('L', base_bg.size, 255) - base_rgb = base_bg.convert('RGB') - mag = color_equal(base_rgb, MAGENTA) - grn = color_equal(base_rgb, GREEN) - interior = ImageChops.invert(ImageChops.add(mag, grn, scale=1.0)) - if erode_px>0: - k = max(1,int(erode_px)); interior = interior.filter(ImageFilter.MinFilter(2*k+1)) - return interior - -def build_glow_maps(mask_bin: Image.Image, interior_mask: Image.Image, wtime: float, - core_radius: float, halo_radius: float, - core_gain: float, halo_gain: float, - size_boost: float, size_radius: float, size_gamma: float, - halo_sep: float, halo_gamma: float): - blur_core = mask_bin.filter(ImageFilter.GaussianBlur(radius=core_radius)) - blur_halo = mask_bin.filter(ImageFilter.GaussianBlur(radius=halo_radius)) - - if size_boost>0.0 and size_radius>0: - density = mask_bin.filter(ImageFilter.BoxBlur(radius=size_radius)).convert('L') - density = apply_gamma_L(density, max(0.05, size_gamma)) - boost = scale_L(density, size_boost * wtime) - blur_core = ImageChops.add(blur_core, boost, scale=1.0) - blur_halo = ImageChops.add(blur_halo, boost, scale=1.0) - - halo_sep = max(0.0, min(1.0, halo_sep)) - halo_only = ImageChops.subtract(blur_halo, blur_core.point(lambda v:int(v*halo_sep)), scale=1.0, offset=0) if halo_sep>0 else blur_halo - halo_only = apply_gamma_L(halo_only, halo_gamma) - - core_alpha = scale_L(blur_core, wtime*max(0.0, core_gain)) - halo_alpha = scale_L(halo_only, wtime*max(0.0, halo_gain)) - core_alpha = ImageChops.multiply(core_alpha, interior_mask) - halo_alpha = ImageChops.multiply(halo_alpha, interior_mask) - return core_alpha, halo_alpha - -def layer_from_alpha(color: Tuple[int,int,int], alphaL: Image.Image) -> Image.Image: - w,h = alphaL.size - solid = Image.new('RGB',(w,h),color) - return Image.composite(solid, Image.new('RGB',(w,h),(0,0,0)), alphaL) - -# ---------- compositor with per-key styles ---------- - -def build_composite_with_styles(base_bg_rgba: Image.Image, - mask_source_rgb: Image.Image, - hour_1_24: int, - keys: List[Tuple[int,int,int]], - styles: Dict[Tuple[int,int,int], Dict[str,object]], - # global defaults: - core_radius: float, halo_radius: float, - core_gain: float, halo_gain: float, - core_color: Tuple[int,int,int], - glow_color: Tuple[int,int,int], - size_boost: float, size_radius: float, size_gamma: float, - clip_interior: bool, clip_erode: int, - highlight_gain: float, blend_mode: str, - halo_sep: float, halo_gamma: float) -> Image.Image: - wtime = hour_weight_lights(hour_1_24) - if wtime <= 0.0: # just return unchanged base (still save with palette fix later) - return base_bg_rgba.copy() - - interior = build_interior_mask(base_bg_rgba, clip_interior, clip_erode) - comp = base_bg_rgba.convert('RGB') - - # Ensure every styled key is included in keys - keys_set = {k for k in keys} - for k in styles.keys(): - keys_set.add(k) - keys_order = list(keys_set) - - for key_rgb in keys_order: - # Per-key mask - mask_bin = color_equal(mask_source_rgb, key_rgb) - if mask_bin.getbbox() is None: - continue - - st = styles.get(key_rgb, {}) - k_core_color = st.get("core_color", core_color) - k_glow_color = st.get("glow_color", glow_color) - k_core_gain = float(st.get("core_gain", core_gain)) - k_halo_gain = float(st.get("halo_gain", halo_gain)) - k_core_rad = float(st.get("core_radius", core_radius)) - k_halo_rad = float(st.get("halo_radius", halo_radius)) - k_halo_sep = float(st.get("halo_sep", halo_sep)) - k_halo_gamma = float(st.get("halo_gamma", halo_gamma)) - k_size_boost = float(st.get("size_boost", size_boost)) - k_size_radius= float(st.get("size_radius", size_radius)) - k_size_gamma = float(st.get("size_gamma", size_gamma)) - k_highlight = float(st.get("highlight", highlight_gain)) - - core_alpha, halo_alpha = build_glow_maps( - mask_bin, interior, wtime, - k_core_rad, k_halo_rad, - k_core_gain, k_halo_gain, - k_size_boost, k_size_radius, k_size_gamma, - k_halo_sep, k_halo_gamma - ) - core_layer = layer_from_alpha(k_core_color, core_alpha) - halo_layer = layer_from_alpha(k_glow_color, halo_alpha) - - if blend_mode == "add": - comp = ImageChops.add(comp, core_layer, scale=1.0) - comp = ImageChops.add(comp, halo_layer, scale=1.0) - else: - comp = screen_blend(comp, core_layer) - comp = screen_blend(comp, halo_layer) - - if k_highlight > 0.0: - hl = scale_L(core_alpha, k_highlight) - comp = ImageChops.add(comp, Image.composite(Image.new('RGB',comp.size,(255,255,255)), - Image.new('RGB',comp.size,(0,0,0)), hl), scale=1.0) - - return comp.convert('RGBA') - -# ---------- save with palette fixes ---------- - -def save_with_palette_and_magic(comp_rgba: Image.Image, out_path: str, base_for_magic_rgb: Image.Image) -> None: - imP = quantize_to_p_256(comp_rgba) - pal_after = ensure_palette_has_colors(imP, [MAGENTA]); put_palette(imP, pal_after) - replacement_idx = force_magenta_at_255(imP) - dst_px = imP.load(); src_px = base_for_magic_rgb.load(); w,h = imP.size - for y in range(h): - for x in range(w): - r,g,b = src_px[x,y]; cur = dst_px[x,y] - if (r,g,b)==MAGENTA: - dst_px[x,y]=255 - elif (r,g,b)==GREEN: - dst_px[x,y]=255 - elif cur==255 and replacement_idx!=255: - dst_px[x,y]=replacement_idx - # Remove #00ff00 from palette entirely if present. - pal_after = get_palette(imP) - for i in range(256): - if (pal_after[3*i], pal_after[3*i+1], pal_after[3*i+2]) == GREEN: - pal_after[3*i:3*i+3] = [0, 0, 0] - put_palette(imP, pal_after) - os.makedirs(os.path.dirname(out_path), exist_ok=True) - imP.save(out_path, format='PCX') - -# ---------- driver ---------- - -def process_tree(data_dir: str, noon_subfolder: str, - light_keys: List[Tuple[int,int,int]], - styles: Dict[Tuple[int,int,int], Dict[str,object]], - core_radius: float, halo_radius: float, - core_gain: float, halo_gain: float, - core_color: Tuple[int,int,int], glow_color: Tuple[int,int,int], - size_boost: float, size_radius: float, size_gamma: float, - clip_interior: bool, clip_erode: int, - highlight_gain: float, blend_mode: str, - halo_sep: float, halo_gamma: float, - only_hour: Optional[int]=None, only_file: Optional[str]=None) -> None: - - base_dir = os.path.join(data_dir, noon_subfolder) - if not os.path.isdir(base_dir): raise SystemExit(f"No such folder: {base_dir}") - - hours = [h for h in range(100, 2500, 100) if h != 1200] - if only_hour is not None: - if only_hour == 1200: raise SystemExit("1200 is the base. Choose another hour.") - if only_hour % 100 != 0 or only_hour < 100 or only_hour > 2400: - raise SystemExit("--only-hour must be one of 100,200,...,2400.") - hours = [only_hour] - - norm_only = os.path.normcase(only_file) if only_file else None - - # Ensure styled keys are included even if not explicitly listed in --light-key - for k in styles.keys(): - if k not in light_keys: - light_keys.append(k) - - for dirpath, _, filenames in os.walk(base_dir): - rel_dir = os.path.relpath(dirpath, base_dir); rel_dir = "" if rel_dir=="." else rel_dir - for hhh in hours: - os.makedirs(os.path.join(data_dir, f"{hhh:04d}", rel_dir), exist_ok=True) - - lights_files = [f for f in filenames if f.lower().endswith("_lights.pcx")] - for lights_name in lights_files: - if norm_only: - rel_file = os.path.normcase(os.path.join(rel_dir, lights_name)) - if norm_only != os.path.normcase(lights_name) and norm_only != rel_file: continue - - plain_name = lights_name[:-len("_lights.pcx")] + ".pcx" - noon_lights = os.path.join(dirpath, lights_name) - noon_plain = os.path.join(dirpath, plain_name) - - for hhh in hours: - hour_1_24 = hhh // 100 - hour_dir = os.path.join(data_dir, f"{hhh:04d}", rel_dir) - out_lights= os.path.join(hour_dir, lights_name) - out_plain = os.path.join(hour_dir, plain_name) - print(f"Processing {hhh:04d}: {lights_name} -> {out_lights}") - - if os.path.exists(out_plain): - base_bg = Image.open(out_plain).convert('RGBA'); base_rgb = Image.open(out_plain).convert('RGB') - elif os.path.exists(noon_plain): - base_bg = Image.open(noon_plain).convert('RGBA'); base_rgb = Image.open(noon_plain).convert('RGB') - else: - base_bg = Image.open(noon_lights).convert('RGBA'); base_rgb = Image.open(noon_lights).convert('RGB') - - mask_src = Image.open(noon_lights).convert('RGB') - - comp = build_composite_with_styles( - base_bg_rgba=base_bg, mask_source_rgb=mask_src, hour_1_24=hour_1_24, - keys=light_keys, styles=styles, - core_radius=core_radius, halo_radius=halo_radius, - core_gain=core_gain, halo_gain=halo_gain, - core_color=core_color, glow_color=glow_color, - size_boost=size_boost, size_radius=size_radius, size_gamma=size_gamma, - clip_interior=clip_interior, clip_erode=clip_erode, - highlight_gain=highlight_gain, blend_mode=blend_mode, - halo_sep=halo_sep, halo_gamma=halo_gamma - ) - - if is_night_hour(hour_1_24): - # At night, also write/replace the plain file with the composite - save_with_palette_and_magic(comp, out_plain, base_rgb) - - # ---- Night-only cleanup: remove the hour's *_lights.pcx copy ---- - if os.path.exists(out_lights) and ("annotations" not in out_lights.lower()): - try: - os.remove(out_lights) - except Exception as e: - print(f"WARNING: Could not delete {out_lights}: {e}") - else: - # Daytime: ensure a plain exists; prefer noon_plain if available - if not os.path.exists(out_plain): - if os.path.exists(noon_plain): - os.makedirs(os.path.dirname(out_plain), exist_ok=True) - shutil.copyfile(noon_plain, out_plain) - else: - save_with_palette_and_magic(base_bg, out_plain, base_rgb) - - -def main(): - parser = argparse.ArgumentParser( - description=( - "Render glowing city lights from *_lights.pcx files.\n" - "• Multiple light-keys supported (+ per-key styles)\n" - "• Night hours (19..24,1..6) also overwrite the paired non-lights file\n" - "• MAGENTA pinned to index 255; GREEN removed from palette if present" - ), - formatter_class=RawTextHelpFormatter, - epilog=( - "Examples:\n" - " Basic (one key):\n" - " python civ3_city_lights.py --data ./Data --noon 1200 \\\n" - " --light-key \"#00feff\" --core-color \"#fff87a\" --glow-color \"#ff8a20\"\n" - "\n" - " Multiple keys with per-key styles:\n" - " python civ3_city_lights.py --data ./Data --noon 1200 \\\n" - " --light-key \"#00feff\" --light-key \"#fe00ff\" \\\n" - " --light-style \"key=#00feff; core=#fff87a; glow=#ff9a2b; halo_gain=18; halo_radius=14\" \\\n" - " --light-style \"key=#fe00ff; core=#ffd0ff; glow=#e07aff; core_gain=1.4; halo_gain=12\"\n" - "\n" - " Make large light clusters pop more:\n" - " --size-boost 1.2 --size-radius 4 --size-gamma 0.8\n" - "\n" - "Notes:\n" - " • Increase --halo-radius and --halo-gain for a bigger, softer glow.\n" - " • If you see a dark ring between core/halo, reduce --halo-sep or increase --halo-gamma.\n" - " • 'screen' blend is safer for colors; 'add' is punchier but can clip highlights." - ) - ) - - # Required paths - parser.add_argument("--data", required=True, - help="Path to the Data root (contains the noon folder). Sibling hour folders 0100..2400 will be created here.") - parser.add_argument("--noon", default="1200", - help="Name of the noon subfolder under --data (default: 1200).") - - # Scope limiting - parser.add_argument("--only-hour", type=int, - help="Process a single hour (100..2400 step 100, excluding 1200). Example: --only-hour 2400") - parser.add_argument("--only-file", - help="Process a single *_lights.pcx (filename or relative path under the noon folder).") - - # Light keys & per-key styles - parser.add_argument("--light-key", action="append", default=["#00feff"], - help=( - "Placeholder color(s) in *_lights.pcx that mark light sources.\n" - "Repeat the flag for multiple keys. Accepts '#rrggbb' or 'R,G,B'.\n" - "Keys referenced in --light-style are auto-included; you don't need to repeat them." - )) - parser.add_argument("--light-style", action="append", default=[], - help=( - "Per-key overrides (tints/strengths/shapes). Format (use ';' or ',' between fields):\n" - " \"key=#00feff; core=#fff87a; glow=#ff8a20; core_gain=1.6; halo_gain=4.0;\n" - " halo_sep=0.75; halo_gamma=1.35; core_radius=1.2; halo_radius=14; highlight=0.6\"\n" - "Only 'key' is required. Any provided numeric field overrides the global default\n" - "for that key. Colors accept '#rrggbb' or 'R,G,B'." - )) - - # Global defaults (each can be overridden per-key via --light-style) - parser.add_argument("--core-radius", type=float, default=1.1, - help="Gaussian blur radius (pixels) of the bright core. Higher = wider/softer core.") - parser.add_argument("--halo-radius", type=float, default=13.0, - help="Gaussian blur radius (pixels) of the outer halo. Higher = glow spreads further outward.") - parser.add_argument("--core-gain", type=float, default=2.1, - help="Intensity multiplier for the core alpha (brightness/opacity of the center). Higher = brighter core.") - parser.add_argument("--halo-gain", type=float, default=20.0, - help="Intensity multiplier for the halo alpha (strength of the outer glow). Higher = stronger/fatter halo.") - parser.add_argument("--core-color", type=str, default="#ff8a20", - help="Tint color for the bright core (e.g., '#fff87a' for warm yellow).") - parser.add_argument("--glow-color", type=str, default="#dc6a00", - help="Tint color for the outer halo (e.g., '#ff8a20' for orange).") - parser.add_argument("--highlight-gain", type=float, default=0.6, - help="Extra white highlight added from the core mask (0..~1 typical). Higher = hotter specular highlight.") - - # Size-aware modulation (lets larger light clusters feel brighter/bigger) - parser.add_argument("--size-boost", type=float, default=1.1, - help="How much cluster size increases intensity (0 disables). Higher = large groups pop more.") - parser.add_argument("--size-radius", type=float, default=3.5, - help="Neighborhood radius (pixels) when measuring cluster size. Higher = smoother/broader size effect.") - parser.add_argument("--size-gamma", type=float, default=0.75, - help="Gamma on the size map. <1 emphasizes medium clusters; >1 favors only the largest clusters.") - - # Clipping against magenta/green background - parser.add_argument("--clip-interior", type=str, default="yes", choices=["yes","no"], - help="If 'yes', lights only affect non-transparent interior (avoids glow on MAGENTA/GREEN). Recommended: yes.") - parser.add_argument("--clip-erode", type=int, default=0, - help="Erode the interior mask by N pixels. Higher = more conservative (keeps glow off edges).") - - # Halo shaping & blend mode - parser.add_argument("--halo-sep", type=float, default=0.75, - help="0..1: subtracts a fraction of the core from the halo. 0 = seamless merge; 1 = distinct outer ring.") - parser.add_argument("--halo-gamma", type=float, default=1.4, - help="Gamma on the halo-only mask. >1 pushes energy outward (softer tail); <1 concentrates near source.") - parser.add_argument("--blend-mode", type=str, default="screen", choices=["screen","add"], - help="How layers combine. 'screen' (default) is safer; 'add' is punchier but can clip highlights.") - - args = parser.parse_args() - - light_keys = parse_rgb_list(args.light_key) - styles = parse_styles(args.light_style) - core_color = parse_rgb_one(args.core_color) - glow_color = parse_rgb_one(args.glow_color) - - process_tree( - data_dir=args.data, noon_subfolder=args.noon, - light_keys=light_keys, styles=styles, - core_radius=args.core_radius, halo_radius=args.halo_radius, - core_gain=args.core_gain, halo_gain=args.halo_gain, - core_color=core_color, glow_color=glow_color, - size_boost=args.size_boost, size_radius=args.size_radius, size_gamma=args.size_gamma, - clip_interior=(args.clip_interior=="yes"), - clip_erode=args.clip_erode, - highlight_gain=args.highlight_gain, blend_mode=args.blend_mode, - halo_sep=args.halo_sep, halo_gamma=args.halo_gamma, - only_hour=args.only_hour, only_file=args.only_file - ) - - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Civ 3 city lights compositor for *_lights.pcx +- Recursive over Data/1200 → writes siblings 0100..2400 +- Multiple --light-key values (union mask) +- **Per-light-key styles** via --light-style: per-key core/glow colors and optional overrides +- Night (19..24,1..6): also replaces non-lights file +- Pins magenta #ff00ff to palette index 255; removes #00ff00 from palette +""" + +import argparse, os, math, shutil +from typing import List, Tuple, Dict, Optional +from PIL import Image, ImageChops, ImageFilter +from argparse import RawTextHelpFormatter + +MAGENTA = (255, 0, 255) +GREEN = (0, 255, 0) + +# ---------- parsing ---------- + +def parse_rgb_one(s: str) -> Tuple[int,int,int]: + s = s.strip() + if s.startswith("#"): + s = s[1:]; assert len(s)==6, "Hex color must be #rrggbb" + return int(s[0:2],16), int(s[2:4],16), int(s[4:6],16) + if "," in s: + a = [int(p) for p in s.split(",")]; assert len(a)==3, "RGB must be R,G,B" + return tuple(max(0,min(255,v)) for v in a) # type: ignore + raise ValueError("Color must be '#rrggbb' or 'R,G,B'") + +def parse_rgb_list(values: List[str]) -> List[Tuple[int,int,int]]: + out: List[Tuple[int,int,int]] = [] + for raw in values or []: + tokens = [t for t in raw.replace(";", " ").split() if t] + for tok in tokens: + out.append(parse_rgb_one(tok)) + if not out: out = [(0,254,255)] + dedup, seen = [], set() + for c in out: + if c not in seen: seen.add(c); dedup.append(c) + return dedup + +def parse_styles(values: List[str]) -> Dict[Tuple[int,int,int], Dict[str,object]]: + """ + --light-style "key=#00feff; core=#fff87a; glow=#ff8a20; core_gain=1.6; halo_gain=4.0; halo_sep=0.75; halo_gamma=1.35; core_radius=1.2; halo_radius=14; highlight=0.6" + Accepts ';' or ',' separators. Only 'key' is required; others override globals for that key. + """ + styles: Dict[Tuple[int,int,int], Dict[str,object]] = {} + for raw in values or []: + parts = [p.strip() for p in raw.replace(",", ";").split(";") if p.strip()] + kv: Dict[str,str] = {} + for p in parts: + if "=" in p: + k,v = p.split("=",1); kv[k.strip().lower()] = v.strip() + if "key" not in kv: raise SystemExit("Each --light-style must include key=") + key_rgb = parse_rgb_one(kv["key"]) + entry: Dict[str,object] = {} + if "core" in kv: entry["core_color"] = parse_rgb_one(kv["core"]) + if "glow" in kv: entry["glow_color"] = parse_rgb_one(kv["glow"]) + for numk in ["core_gain","halo_gain","core_radius","halo_radius","halo_sep","halo_gamma","highlight","size_boost","size_radius","size_gamma"]: + if numk in kv: + entry[numk] = float(kv[numk]) + styles[key_rgb] = entry + return styles + +# ---------- time window ---------- + +def hour_weight_lights(hour_1_24: int, start: float = 18.0, end: float = 6.0, floor: float = 0.80) -> float: + h = float(hour_1_24) % 24.0 + inwin = (h >= start) or (h <= end) + if not inwin: return 0.0 + L = (24.0 - start) + end + p = (h - start) if (h >= start) else ((24.0 - start) + h) + mid = 0.5*L; t = abs(p - mid)/mid + w = floor + (1.0 - floor)*0.5*(1.0 + math.cos(math.pi * t)) + return max(0.0, min(1.0, w)) + +def is_night_hour(hour_1_24: int) -> bool: + return (18 <= hour_1_24 <= 24) or (1 <= hour_1_24 <= 6) + +# ---------- palette ---------- + +def get_palette(image: Image.Image) -> List[int]: + pal = image.getpalette() or [] + if len(pal) < 256*3: pal += [0]*(256*3 - len(pal)) + return pal[:256*3] + +def put_palette(image: Image.Image, palette: List[int]) -> None: + if len(palette) < 256*3: palette += [0]*(256*3 - len(palette)) + image.putpalette(palette[:256*3]) + +def ensure_palette_has_colors(image: Image.Image, colors: List[Tuple[int,int,int]]) -> List[int]: + pal = get_palette(image) + to_add = [c for c in colors if find_color_index(pal,c)==-1] + if not to_add: return pal + hist = image.histogram() if image.mode=='P' else None + candidates = sorted(range(256), key=(lambda i: hist[i])) if (hist and len(hist)==256) else list(range(255,-1,-1)) + protected=set() + for rgb in colors+[MAGENTA]: + idx = find_color_index(pal, rgb) + if idx!=-1: protected.add(idx) + replace=[] + for i in candidates: + if i in protected: continue + replace.append(i) + if len(replace)>=len(to_add): break + if len(replace) int: + r,g,b = rgb + for i in range(256): + if palette[3*i]==r and palette[3*i+1]==g and palette[3*i+2]==b: return i + return -1 + +def quantize_to_p_256(img: Image.Image) -> Image.Image: + try: + dnone = Image.Dither.NONE + except Exception: + dnone = getattr(Image, "NONE", 0) + rgb = img.convert('RGB') + try: + return rgb.quantize(colors=256, method=Image.FASTOCTREE, dither=dnone) + except Exception: + return rgb.quantize(colors=256, dither=dnone) + +def force_magenta_at_255(im: Image.Image) -> int: + pal = get_palette(im) + old255 = (pal[3*255], pal[3*255+1], pal[3*255+2]) + idx_mag = find_color_index(pal, MAGENTA) + if idx_mag == -1: + pal = ensure_palette_has_colors(im, [MAGENTA]); put_palette(im, pal) + pal = get_palette(im); idx_mag = find_color_index(pal, MAGENTA) + if idx_mag == 255: return 255 + pal[3*255:3*255+3]=list(MAGENTA); pal[3*idx_mag:3*idx_mag+3]=list(old255) + put_palette(im, pal); return idx_mag + +# ---------- image ops ---------- + +def color_equal(img_rgb: Image.Image, color: Tuple[int,int,int]) -> Image.Image: + w,h = img_rgb.size + solid = Image.new('RGB',(w,h),color) + diff = ImageChops.difference(img_rgb, solid) + return diff.convert('L').point(lambda v: 255 if v==0 else 0, mode='L') + +def apply_gamma_L(imgL: Image.Image, gamma: float) -> Image.Image: + gamma = max(0.05, float(gamma)) + lut = [min(255, int(round((i/255.0) ** gamma * 255))) for i in range(256)] + return imgL.point(lut, mode='L') + +def scale_L(imgL: Image.Image, factor: float) -> Image.Image: + factor = max(0.0, float(factor)) + return imgL.point(lambda v: 255 if v*factor >= 255 else int(v*factor)) + +def screen_blend(a: Image.Image, b: Image.Image) -> Image.Image: + try: + return ImageChops.screen(a,b) + except AttributeError: + return ImageChops.invert(ImageChops.multiply(ImageChops.invert(a), ImageChops.invert(b))) + +# ---------- masks & glows ---------- + +def build_interior_mask(base_bg: Image.Image, clip: bool, erode_px: int) -> Image.Image: + if not clip: return Image.new('L', base_bg.size, 255) + base_rgb = base_bg.convert('RGB') + mag = color_equal(base_rgb, MAGENTA) + grn = color_equal(base_rgb, GREEN) + interior = ImageChops.invert(ImageChops.add(mag, grn, scale=1.0)) + if erode_px>0: + k = max(1,int(erode_px)); interior = interior.filter(ImageFilter.MinFilter(2*k+1)) + return interior + +def build_glow_maps(mask_bin: Image.Image, interior_mask: Image.Image, wtime: float, + core_radius: float, halo_radius: float, + core_gain: float, halo_gain: float, + size_boost: float, size_radius: float, size_gamma: float, + halo_sep: float, halo_gamma: float): + blur_core = mask_bin.filter(ImageFilter.GaussianBlur(radius=core_radius)) + blur_halo = mask_bin.filter(ImageFilter.GaussianBlur(radius=halo_radius)) + + if size_boost>0.0 and size_radius>0: + density = mask_bin.filter(ImageFilter.BoxBlur(radius=size_radius)).convert('L') + density = apply_gamma_L(density, max(0.05, size_gamma)) + boost = scale_L(density, size_boost * wtime) + blur_core = ImageChops.add(blur_core, boost, scale=1.0) + blur_halo = ImageChops.add(blur_halo, boost, scale=1.0) + + halo_sep = max(0.0, min(1.0, halo_sep)) + halo_only = ImageChops.subtract(blur_halo, blur_core.point(lambda v:int(v*halo_sep)), scale=1.0, offset=0) if halo_sep>0 else blur_halo + halo_only = apply_gamma_L(halo_only, halo_gamma) + + core_alpha = scale_L(blur_core, wtime*max(0.0, core_gain)) + halo_alpha = scale_L(halo_only, wtime*max(0.0, halo_gain)) + core_alpha = ImageChops.multiply(core_alpha, interior_mask) + halo_alpha = ImageChops.multiply(halo_alpha, interior_mask) + return core_alpha, halo_alpha + +def layer_from_alpha(color: Tuple[int,int,int], alphaL: Image.Image) -> Image.Image: + w,h = alphaL.size + solid = Image.new('RGB',(w,h),color) + return Image.composite(solid, Image.new('RGB',(w,h),(0,0,0)), alphaL) + +# ---------- compositor with per-key styles ---------- + +def build_composite_with_styles(base_bg_rgba: Image.Image, + mask_source_rgb: Image.Image, + hour_1_24: int, + keys: List[Tuple[int,int,int]], + styles: Dict[Tuple[int,int,int], Dict[str,object]], + # global defaults: + core_radius: float, halo_radius: float, + core_gain: float, halo_gain: float, + core_color: Tuple[int,int,int], + glow_color: Tuple[int,int,int], + size_boost: float, size_radius: float, size_gamma: float, + clip_interior: bool, clip_erode: int, + highlight_gain: float, blend_mode: str, + halo_sep: float, halo_gamma: float) -> Image.Image: + wtime = hour_weight_lights(hour_1_24) + if wtime <= 0.0: # just return unchanged base (still save with palette fix later) + return base_bg_rgba.copy() + + interior = build_interior_mask(base_bg_rgba, clip_interior, clip_erode) + comp = base_bg_rgba.convert('RGB') + + # Ensure every styled key is included in keys + keys_set = {k for k in keys} + for k in styles.keys(): + keys_set.add(k) + keys_order = list(keys_set) + + for key_rgb in keys_order: + # Per-key mask + mask_bin = color_equal(mask_source_rgb, key_rgb) + if mask_bin.getbbox() is None: + continue + + st = styles.get(key_rgb, {}) + k_core_color = st.get("core_color", core_color) + k_glow_color = st.get("glow_color", glow_color) + k_core_gain = float(st.get("core_gain", core_gain)) + k_halo_gain = float(st.get("halo_gain", halo_gain)) + k_core_rad = float(st.get("core_radius", core_radius)) + k_halo_rad = float(st.get("halo_radius", halo_radius)) + k_halo_sep = float(st.get("halo_sep", halo_sep)) + k_halo_gamma = float(st.get("halo_gamma", halo_gamma)) + k_size_boost = float(st.get("size_boost", size_boost)) + k_size_radius= float(st.get("size_radius", size_radius)) + k_size_gamma = float(st.get("size_gamma", size_gamma)) + k_highlight = float(st.get("highlight", highlight_gain)) + + core_alpha, halo_alpha = build_glow_maps( + mask_bin, interior, wtime, + k_core_rad, k_halo_rad, + k_core_gain, k_halo_gain, + k_size_boost, k_size_radius, k_size_gamma, + k_halo_sep, k_halo_gamma + ) + core_layer = layer_from_alpha(k_core_color, core_alpha) + halo_layer = layer_from_alpha(k_glow_color, halo_alpha) + + if blend_mode == "add": + comp = ImageChops.add(comp, core_layer, scale=1.0) + comp = ImageChops.add(comp, halo_layer, scale=1.0) + else: + comp = screen_blend(comp, core_layer) + comp = screen_blend(comp, halo_layer) + + if k_highlight > 0.0: + hl = scale_L(core_alpha, k_highlight) + comp = ImageChops.add(comp, Image.composite(Image.new('RGB',comp.size,(255,255,255)), + Image.new('RGB',comp.size,(0,0,0)), hl), scale=1.0) + + return comp.convert('RGBA') + +# ---------- save with palette fixes ---------- + +def save_with_palette_and_magic(comp_rgba: Image.Image, out_path: str, base_for_magic_rgb: Image.Image) -> None: + imP = quantize_to_p_256(comp_rgba) + pal_after = ensure_palette_has_colors(imP, [MAGENTA]); put_palette(imP, pal_after) + replacement_idx = force_magenta_at_255(imP) + dst_px = imP.load(); src_px = base_for_magic_rgb.load(); w,h = imP.size + for y in range(h): + for x in range(w): + r,g,b = src_px[x,y]; cur = dst_px[x,y] + if (r,g,b)==MAGENTA: + dst_px[x,y]=255 + elif (r,g,b)==GREEN: + dst_px[x,y]=255 + elif cur==255 and replacement_idx!=255: + dst_px[x,y]=replacement_idx + # Remove #00ff00 from palette entirely if present. + pal_after = get_palette(imP) + for i in range(256): + if (pal_after[3*i], pal_after[3*i+1], pal_after[3*i+2]) == GREEN: + pal_after[3*i:3*i+3] = [0, 0, 0] + put_palette(imP, pal_after) + os.makedirs(os.path.dirname(out_path), exist_ok=True) + imP.save(out_path, format='PCX') + +# ---------- driver ---------- + +def process_tree(data_dir: str, noon_subfolder: str, + light_keys: List[Tuple[int,int,int]], + styles: Dict[Tuple[int,int,int], Dict[str,object]], + core_radius: float, halo_radius: float, + core_gain: float, halo_gain: float, + core_color: Tuple[int,int,int], glow_color: Tuple[int,int,int], + size_boost: float, size_radius: float, size_gamma: float, + clip_interior: bool, clip_erode: int, + highlight_gain: float, blend_mode: str, + halo_sep: float, halo_gamma: float, + only_hour: Optional[int]=None, only_file: Optional[str]=None) -> None: + + base_dir = os.path.join(data_dir, noon_subfolder) + if not os.path.isdir(base_dir): raise SystemExit(f"No such folder: {base_dir}") + + hours = [h for h in range(100, 2500, 100) if h != 1200] + if only_hour is not None: + if only_hour == 1200: raise SystemExit("1200 is the base. Choose another hour.") + if only_hour % 100 != 0 or only_hour < 100 or only_hour > 2400: + raise SystemExit("--only-hour must be one of 100,200,...,2400.") + hours = [only_hour] + + norm_only = os.path.normcase(only_file) if only_file else None + + # Ensure styled keys are included even if not explicitly listed in --light-key + for k in styles.keys(): + if k not in light_keys: + light_keys.append(k) + + for dirpath, _, filenames in os.walk(base_dir): + rel_dir = os.path.relpath(dirpath, base_dir); rel_dir = "" if rel_dir=="." else rel_dir + for hhh in hours: + os.makedirs(os.path.join(data_dir, f"{hhh:04d}", rel_dir), exist_ok=True) + + lights_files = [f for f in filenames if f.lower().endswith("_lights.pcx")] + for lights_name in lights_files: + if norm_only: + rel_file = os.path.normcase(os.path.join(rel_dir, lights_name)) + if norm_only != os.path.normcase(lights_name) and norm_only != rel_file: continue + + plain_name = lights_name[:-len("_lights.pcx")] + ".pcx" + noon_lights = os.path.join(dirpath, lights_name) + noon_plain = os.path.join(dirpath, plain_name) + + for hhh in hours: + hour_1_24 = hhh // 100 + hour_dir = os.path.join(data_dir, f"{hhh:04d}", rel_dir) + out_lights= os.path.join(hour_dir, lights_name) + out_plain = os.path.join(hour_dir, plain_name) + print(f"Processing {hhh:04d}: {lights_name} -> {out_lights}") + + if os.path.exists(out_plain): + base_bg = Image.open(out_plain).convert('RGBA'); base_rgb = Image.open(out_plain).convert('RGB') + elif os.path.exists(noon_plain): + base_bg = Image.open(noon_plain).convert('RGBA'); base_rgb = Image.open(noon_plain).convert('RGB') + else: + base_bg = Image.open(noon_lights).convert('RGBA'); base_rgb = Image.open(noon_lights).convert('RGB') + + mask_src = Image.open(noon_lights).convert('RGB') + + comp = build_composite_with_styles( + base_bg_rgba=base_bg, mask_source_rgb=mask_src, hour_1_24=hour_1_24, + keys=light_keys, styles=styles, + core_radius=core_radius, halo_radius=halo_radius, + core_gain=core_gain, halo_gain=halo_gain, + core_color=core_color, glow_color=glow_color, + size_boost=size_boost, size_radius=size_radius, size_gamma=size_gamma, + clip_interior=clip_interior, clip_erode=clip_erode, + highlight_gain=highlight_gain, blend_mode=blend_mode, + halo_sep=halo_sep, halo_gamma=halo_gamma + ) + + if is_night_hour(hour_1_24): + # At night, also write/replace the plain file with the composite + save_with_palette_and_magic(comp, out_plain, base_rgb) + + # ---- Night-only cleanup: remove the hour's *_lights.pcx copy ---- + if os.path.exists(out_lights) and ("annotations" not in out_lights.lower()): + try: + os.remove(out_lights) + except Exception as e: + print(f"WARNING: Could not delete {out_lights}: {e}") + else: + # Daytime: ensure a plain exists; prefer noon_plain if available + if not os.path.exists(out_plain): + if os.path.exists(noon_plain): + os.makedirs(os.path.dirname(out_plain), exist_ok=True) + shutil.copyfile(noon_plain, out_plain) + else: + save_with_palette_and_magic(base_bg, out_plain, base_rgb) + + +def main(): + parser = argparse.ArgumentParser( + description=( + "Render glowing city lights from *_lights.pcx files.\n" + "• Multiple light-keys supported (+ per-key styles)\n" + "• Night hours (19..24,1..6) also overwrite the paired non-lights file\n" + "• MAGENTA pinned to index 255; GREEN removed from palette if present" + ), + formatter_class=RawTextHelpFormatter, + epilog=( + "Examples:\n" + " Basic (one key):\n" + " python civ3_city_lights.py --data ./Data --noon 1200 \\\n" + " --light-key \"#00feff\" --core-color \"#fff87a\" --glow-color \"#ff8a20\"\n" + "\n" + " Multiple keys with per-key styles:\n" + " python civ3_city_lights.py --data ./Data --noon 1200 \\\n" + " --light-key \"#00feff\" --light-key \"#fe00ff\" \\\n" + " --light-style \"key=#00feff; core=#fff87a; glow=#ff9a2b; halo_gain=18; halo_radius=14\" \\\n" + " --light-style \"key=#fe00ff; core=#ffd0ff; glow=#e07aff; core_gain=1.4; halo_gain=12\"\n" + "\n" + " Make large light clusters pop more:\n" + " --size-boost 1.2 --size-radius 4 --size-gamma 0.8\n" + "\n" + "Notes:\n" + " • Increase --halo-radius and --halo-gain for a bigger, softer glow.\n" + " • If you see a dark ring between core/halo, reduce --halo-sep or increase --halo-gamma.\n" + " • 'screen' blend is safer for colors; 'add' is punchier but can clip highlights." + ) + ) + + # Required paths + parser.add_argument("--data", required=True, + help="Path to the Data root (contains the noon folder). Sibling hour folders 0100..2400 will be created here.") + parser.add_argument("--noon", default="1200", + help="Name of the noon subfolder under --data (default: 1200).") + + # Scope limiting + parser.add_argument("--only-hour", type=int, + help="Process a single hour (100..2400 step 100, excluding 1200). Example: --only-hour 2400") + parser.add_argument("--only-file", + help="Process a single *_lights.pcx (filename or relative path under the noon folder).") + + # Light keys & per-key styles + parser.add_argument("--light-key", action="append", default=["#00feff"], + help=( + "Placeholder color(s) in *_lights.pcx that mark light sources.\n" + "Repeat the flag for multiple keys. Accepts '#rrggbb' or 'R,G,B'.\n" + "Keys referenced in --light-style are auto-included; you don't need to repeat them." + )) + parser.add_argument("--light-style", action="append", default=[], + help=( + "Per-key overrides (tints/strengths/shapes). Format (use ';' or ',' between fields):\n" + " \"key=#00feff; core=#fff87a; glow=#ff8a20; core_gain=1.6; halo_gain=4.0;\n" + " halo_sep=0.75; halo_gamma=1.35; core_radius=1.2; halo_radius=14; highlight=0.6\"\n" + "Only 'key' is required. Any provided numeric field overrides the global default\n" + "for that key. Colors accept '#rrggbb' or 'R,G,B'." + )) + + # Global defaults (each can be overridden per-key via --light-style) + parser.add_argument("--core-radius", type=float, default=1.1, + help="Gaussian blur radius (pixels) of the bright core. Higher = wider/softer core.") + parser.add_argument("--halo-radius", type=float, default=13.0, + help="Gaussian blur radius (pixels) of the outer halo. Higher = glow spreads further outward.") + parser.add_argument("--core-gain", type=float, default=2.1, + help="Intensity multiplier for the core alpha (brightness/opacity of the center). Higher = brighter core.") + parser.add_argument("--halo-gain", type=float, default=20.0, + help="Intensity multiplier for the halo alpha (strength of the outer glow). Higher = stronger/fatter halo.") + parser.add_argument("--core-color", type=str, default="#ff8a20", + help="Tint color for the bright core (e.g., '#fff87a' for warm yellow).") + parser.add_argument("--glow-color", type=str, default="#dc6a00", + help="Tint color for the outer halo (e.g., '#ff8a20' for orange).") + parser.add_argument("--highlight-gain", type=float, default=0.6, + help="Extra white highlight added from the core mask (0..~1 typical). Higher = hotter specular highlight.") + + # Size-aware modulation (lets larger light clusters feel brighter/bigger) + parser.add_argument("--size-boost", type=float, default=1.1, + help="How much cluster size increases intensity (0 disables). Higher = large groups pop more.") + parser.add_argument("--size-radius", type=float, default=3.5, + help="Neighborhood radius (pixels) when measuring cluster size. Higher = smoother/broader size effect.") + parser.add_argument("--size-gamma", type=float, default=0.75, + help="Gamma on the size map. <1 emphasizes medium clusters; >1 favors only the largest clusters.") + + # Clipping against magenta/green background + parser.add_argument("--clip-interior", type=str, default="yes", choices=["yes","no"], + help="If 'yes', lights only affect non-transparent interior (avoids glow on MAGENTA/GREEN). Recommended: yes.") + parser.add_argument("--clip-erode", type=int, default=0, + help="Erode the interior mask by N pixels. Higher = more conservative (keeps glow off edges).") + + # Halo shaping & blend mode + parser.add_argument("--halo-sep", type=float, default=0.75, + help="0..1: subtracts a fraction of the core from the halo. 0 = seamless merge; 1 = distinct outer ring.") + parser.add_argument("--halo-gamma", type=float, default=1.4, + help="Gamma on the halo-only mask. >1 pushes energy outward (softer tail); <1 concentrates near source.") + parser.add_argument("--blend-mode", type=str, default="screen", choices=["screen","add"], + help="How layers combine. 'screen' (default) is safer; 'add' is punchier but can clip highlights.") + + args = parser.parse_args() + + light_keys = parse_rgb_list(args.light_key) + styles = parse_styles(args.light_style) + core_color = parse_rgb_one(args.core_color) + glow_color = parse_rgb_one(args.glow_color) + + process_tree( + data_dir=args.data, noon_subfolder=args.noon, + light_keys=light_keys, styles=styles, + core_radius=args.core_radius, halo_radius=args.halo_radius, + core_gain=args.core_gain, halo_gain=args.halo_gain, + core_color=core_color, glow_color=glow_color, + size_boost=args.size_boost, size_radius=args.size_radius, size_gamma=args.size_gamma, + clip_interior=(args.clip_interior=="yes"), + clip_erode=args.clip_erode, + highlight_gain=args.highlight_gain, blend_mode=args.blend_mode, + halo_sep=args.halo_sep, halo_gamma=args.halo_gamma, + only_hour=args.only_hour, only_file=args.only_file + ) + + +if __name__ == "__main__": + main() diff --git a/DayNight/civ3_day_night.py b/DayNight/civ3_day_night.py index bd76e3ac..d9e6ba23 100644 --- a/DayNight/civ3_day_night.py +++ b/DayNight/civ3_day_night.py @@ -1,946 +1,946 @@ -#!/usr/bin/env python3 -""" -civ3_daynight_pcx.py — v4.4 (remove #00FF00 from palette entirely) - -Highlights: -- Half-hour (or any divisor of an hour) time slices via --step-minutes. -- Green→Magenta pixel remap (on by default). -- NEW: After pixel remap, ANY palette entries exactly #00FF00 are replaced with black (#000000), - so #00FF00 no longer exists anywhere in the palette. -- Palette-only tinting; indices preserved (except the optional index remap). -- Noon-neutral zone keeps ~10:00–14:00 close to base 1200. -- Stronger nighttime blue response using the existing --blue knob, - with an additional night-only hue shift (blue up, red/green down). - -Tested knobs (your current favorites work unchanged): - --warmth 1.05 --blue 2.0 --darkness 1.1 --desat 0.85 --sat 1.2 --contrast 1.08 - --sunrise-center 5.0 --sunset-center 18.0 --twilight-width 3.0 - --noon-blend 0.7 --noon-sigma 1.0 -""" - -import argparse -import shutil -from pathlib import Path -from typing import Iterable, List, Sequence, Tuple, Set, Dict, Optional - -from PIL import Image -from civ3_city_lights import is_night_hour -from protected_pixels import PROTECTED_RANGES_ENT_COMPLEX - -# Fallback behavior if the palette is full and we cannot allocate a new index -PROTECTED_FALLBACK_NEIGHBOR_RADIUS = 1 # 1 => 3x3 window, 2 => 5x5, etc. -PROTECTED_GAP_BRIDGE = 1 - -from collections import defaultdict, Counter -from math import sqrt - - -# --------------------------- Helpers for protected ranges --------------------------- - -def _bridge_small_gaps( - ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], - max_gap: int, -) -> List[Tuple[Tuple[int, int], Tuple[int, int]]]: - """ - Merge/bridge adjacent horizontal ranges on the same scanline (same y) - when the gap between them is <= max_gap. Ranges are inclusive. - Input items are ((x1, y), (x2, y)). Non-horizontal ranges are kept as-is. - """ - if max_gap <= 0 or not ranges: - return list(ranges) - - by_y = defaultdict(list) - for (x1, y1), (x2, y2) in ranges: - if y1 != y2: - # Not horizontal; keep separate - by_y[(y1, y2, 'nonh')].append((min(x1, x2), max(x1, x2), y1, y2)) - continue - by_y[y1].append((min(x1, x2), max(x1, x2))) - - out: List[Tuple[Tuple[int, int], Tuple[int, int]]] = [] - - # Re-emit any non-horizontal entries unchanged - for key, spans in list(by_y.items()): - if isinstance(key, tuple) and key[-1] == 'nonh': - for x1, x2, y1, y2 in spans: - out.append(((x1, y1), (x2, y2))) - del by_y[key] - - # Bridge gaps on horizontal scanlines - for y, spans in by_y.items(): - spans.sort() - cur_x1, cur_x2 = spans[0] - for nx1, nx2 in spans[1:]: - gap = nx1 - cur_x2 - 1 # inclusive ranges - if gap <= max_gap: - cur_x2 = max(cur_x2, nx2) - else: - out.append(((cur_x1, y), (cur_x2, y))) - cur_x1, cur_x2 = nx1, nx2 - out.append(((cur_x1, y), (cur_x2, y))) - - return out - - -def clamp_byte(x: float) -> int: - return int(max(0, min(255, round(x)))) - - -def _nudge_if_reserved(nrgb, reserved_set, orig_rgb): - if nrgb in reserved_set: - # Nudge 1 toward original to avoid exact collision - r0, g0, b0 = orig_rgb - r, g, b = nrgb - - def nudge(c, c0): - return clamp_byte(c - 1 if c > c0 else c + 1 if c < c0 else c) - - return (nudge(r, r0), nudge(g, g0), nudge(b, b0)) - return nrgb - - -def _rgb_of_index(pal: List[int], idx: int) -> Tuple[int, int, int]: - return pal[3 * idx], pal[3 * idx + 1], pal[3 * idx + 2] - - -def _color_dist2(a: Tuple[int, int, int], b: Tuple[int, int, int]) -> float: - dr, dg, db = a[0] - b[0], a[1] - b[1], a[2] - b[2] - return dr * dr + dg * dg + db * db - - -def _index_pixel_counts(im: Image.Image) -> Dict[int, int]: - colors = im.getcolors(maxcolors=256 * 256) or [] - return {int(idx): int(cnt) for (cnt, idx) in colors} - - -def _indices_used_in_coords( - im: Image.Image, - ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], -) -> Set[int]: - w, h = im.size - px = im.load() - s: Set[int] = set() - for (x1, y1), (x2, y2) in ranges: - x_start, x_end = (x1, x2) if x1 <= x2 else (x2, x1) - y_start, y_end = (y1, y2) if y1 <= y2 else (y2, y1) - for y in range(max(0, y_start), min(h, y_end + 1)): - for x in range(max(0, x_start), min(w, x_end + 1)): - s.add(int(px[x, y])) - return s - - -def _find_nearest_index( - pal: List[int], - src_idx: int, - allowed: Iterable[int], -) -> Optional[int]: - src_rgb = _rgb_of_index(pal, src_idx) - best = None - best_d2 = 1e18 - for j in allowed: - if j == src_idx: - continue - d2 = _color_dist2(src_rgb, _rgb_of_index(pal, j)) - if d2 < best_d2: - best_d2 = d2 - best = int(j) - return best - - -def _used_palette_indices(im: Image.Image) -> Set[int]: - """ - Return the set of palette indices actually used by the image. - """ - colors = im.getcolors(maxcolors=256 * 256) or [] - used: Set[int] = set() - for _, idx in colors: - used.add(int(idx)) - return used - - -def _free_palette_slots( - im: Image.Image, - pal: List[int], - needed: int, - *, - protected_source_indices: Set[int], # indices that appear inside protected coords - reserved_by_color_rgbs: Set[Tuple[int, int, int]], # magenta/green/light-keys as RGB -) -> int: - """ - Try to free up to `needed` palette slots by remapping the *least-used* indices - (that are NOT protected and NOT reserved-by-color) to their nearest-color neighbors. - Returns the number of slots actually freed. Pixels are rewritten in-place. - """ - if needed <= 0: - return 0 - - w, h = im.size - px = im.load() - counts = _index_pixel_counts(im) - used_indices = set(counts.keys()) - - # Build sets for constraints - reserved_by_color_indices: Set[int] = set() - for i in range(256): - if i in used_indices: - rgb = (pal[3 * i], pal[3 * i + 1], pal[3 * i + 2]) - if rgb in reserved_by_color_rgbs: - reserved_by_color_indices.add(i) - - forbidden = set(protected_source_indices) | reserved_by_color_indices - - # Candidates we are allowed to merge away - candidates = [i for i in used_indices if i not in forbidden] - - if not candidates: - return 0 - - # Sort by ascending usage (least used first) - candidates.sort(key=lambda i: counts.get(i, 0)) - - freed = 0 - allowed_targets = set(used_indices) - forbidden - - for src_idx in candidates: - if freed >= needed: - break - if src_idx not in used_indices: - continue - - options = allowed_targets - {src_idx} - if not options: - continue - - tgt = _find_nearest_index(pal, src_idx, options) - if tgt is None: - continue - - # Remap all pixels from src_idx -> tgt - for y in range(h): - for x in range(w): - if px[x, y] == src_idx: - px[x, y] = tgt - - used_indices.discard(src_idx) - allowed_targets.discard(src_idx) - freed += 1 - - return freed - - -def _sample_neighbor_index(px, x: int, y: int, w: int, h: int, r: int) -> Optional[int]: - """ - Return the most common palette index in the (2r+1)x(2r+1) neighborhood - around (x,y), excluding the center pixel. If nothing valid, return None. - """ - if r <= 0: - return None - xs = range(max(0, x - r), min(w, x + r + 1)) - ys = range(max(0, y - r), min(h, y + r + 1)) - counts = Counter() - for yy in ys: - for xx in xs: - if xx == x and yy == y: - continue - counts[int(px[xx, yy])] += 1 - return counts.most_common(1)[0][0] if counts else None - - -def _protect_exact_pixels_by_index( - im: Image.Image, - pal: List[int], - ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], - reserved_by_color_rgbs: Set[Tuple[int, int, int]] = set(), -) -> Set[int]: - """ - Ensure protected coords keep their original (noon) colors by duplicating indices. - If the palette is full, first free slots by merging least-used non-protected indices - into nearest neighbors. If still short on slots, fall back to neighbor sampling. - Returns set of dedicated reserved indices. - """ - assert im.mode == "P", "Image must be paletted ('P')" - w, h = im.size - px = im.load() - - protected_src_indices = _indices_used_in_coords(im, ranges) - - used_now = _used_palette_indices(im) - free_now = [i for i in range(256) if i not in used_now] - need = max(0, len(protected_src_indices) - len(free_now)) - - if need > 0: - _ = _free_palette_slots( - im, - pal, - need, - protected_source_indices=protected_src_indices, - reserved_by_color_rgbs=reserved_by_color_rgbs, - ) - - # Recompute used/free after freeing - used = _used_palette_indices(im) - free_pool = [i for i in range(256) if i not in used] - - index_map: Dict[int, int] = {} - reserved_indices: Set[int] = set() - - radius = int(PROTECTED_FALLBACK_NEIGHBOR_RADIUS) - - # Duplicate on first encounter of a src index - for (x1, y1), (x2, y2) in ranges: - x_start, x_end = (x1, x2) if x1 <= x2 else (x2, x1) - y_start, y_end = (y1, y2) if y1 <= y2 else (y2, y1) - - for y in range(y_start, y_end + 1): - if not (0 <= y < h): - continue - for x in range(x_start, x_end + 1): - if not (0 <= x < w): - continue - - orig_idx = int(px[x, y]) - - dup = index_map.get(orig_idx) - if dup is not None: - px[x, y] = dup - continue - - if free_pool: - dup_idx = free_pool.pop(0) - r, g, b = pal[3 * orig_idx: 3 * orig_idx + 3] - pal[3 * dup_idx + 0] = r - pal[3 * dup_idx + 1] = g - pal[3 * dup_idx + 2] = b - index_map[orig_idx] = dup_idx - reserved_indices.add(dup_idx) - px[x, y] = dup_idx - continue - - # LAST RESORT: neighbor sampling - neighbor_idx = _sample_neighbor_index(px, x, y, w, h, radius) - if neighbor_idx is not None: - px[x, y] = int(neighbor_idx) - else: - print(f"WARNING: No palette slots and no neighbors for ({x},{y}).") - - return reserved_indices - - -# --------------------------- CLI & helpers --------------------------- - -def parse_rgb(s: str) -> Tuple[int, int, int]: - s = s.strip() - if s.startswith("#"): - s = s[1:] - if len(s) != 6: - raise ValueError(f"Bad hex color: #{s}") - return tuple(int(s[i:i + 2], 16) for i in (0, 2, 4)) # type: ignore - if "," in s: - parts = [p.strip() for p in s.split(",")] - if len(parts) != 3: - raise ValueError(f"Bad RGB list: {s}") - return tuple(int(p) for p in parts) # type: ignore - raise ValueError(f"Unrecognized color format: {s}") - - -def time_labels(step_minutes: int) -> List[str]: - """ - Generate HHMM labels from step to 23:59 stepwise; exclude 0000; add 2400. - For step=60: 0100..2300 + 2400 - For step=30: 0030, 0100, 0130..2330 + 2400 - """ - if step_minutes <= 0 or 60 % step_minutes != 0: - raise ValueError("--step-minutes must be a positive divisor of 60 (e.g., 5,10,15,20,30,60).") - labels: List[str] = [] - total_minutes = 24 * 60 - m = step_minutes - while m < total_minutes: - h = m // 60 - mm = m % 60 - labels.append(f"{h:02d}{mm:02d}") - m += step_minutes - labels.append("2400") - return labels - - -# --------------------------- TONEMAP MODEL --------------------------- - -def _gauss(x: float, mu: float, sigma: float) -> float: - from math import exp - if sigma <= 0.0: - return 0.0 - return exp(-0.5 * ((x - mu) / sigma) ** 2) - - -def hour_adjustments( - hour_value: float, - *, - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, -) -> dict: - """ - hour_value can be fractional (e.g., 19.5 for 19:30). Period is 24h. - Returns a dict with per-channel multipliers, gray blend, brightness, - and 'night' + 'blue_push' factors for night-only hue shift. - """ - from math import cos, pi - - h = hour_value % 24.0 - - # Daylight (cosine): 1 at noon, ~0 at midnight - daylight = max(0.0, cos(pi * (h - 12.0) / 12.0)) # 0..1 - night = 1.0 - daylight - - # Warmth around sunrise/sunset - warmth = 0.85 * (_gauss(h, sunrise_center, twilight_sigma) + - _gauss(h, sunset_center, twilight_sigma)) - warmth *= warmth_scale - - # Brightness: darker at night; scaled by darkness_scale (>1 = darker nights) - base_brightness = 0.60 + 0.40 * daylight - night_darkening = 1.0 - (0.12 * (darkness_scale - 1.0) * night) - brightness = base_brightness * night_darkening - - # Channel multipliers - r_mul = 0.97 + 0.12 * daylight + 0.30 * warmth - g_mul = 0.97 + 0.12 * daylight + 0.12 * warmth - b_mul = 0.97 + 0.12 * daylight - 0.18 * warmth + (0.28 * blue_scale) * night - - # Desaturation (toward gray) stronger at night; scaled by desat_scale - gray_blend = (0.10 + 0.50 * night) * desat_scale - gray_blend = min(max(gray_blend, 0.0), 0.85) - - # Night-only blue push factor (extra hue shift at night) - blue_push = max(0.0, blue_scale - 1.0) * night # 0 at day, up to (blue-1) at night - - # Clamp gentle bounds - r_mul = min(max(r_mul, 0.65), 1.45) - g_mul = min(max(g_mul, 0.65), 1.40) - b_mul = min(max(b_mul, 0.65), 1.55) - - return dict( - brightness=brightness, - r_mul=r_mul, - g_mul=g_mul, - b_mul=b_mul, - gray_blend=gray_blend, - night=night, - blue_push=blue_push, - ) - - -def _apply_saturation(rgb: Tuple[float, float, float], sat: float) -> Tuple[float, float, float]: - r, g, b = rgb - gray = (r + g + b) / 3.0 - r = gray + (r - gray) * sat - g = gray + (g - gray) * sat - b = gray + (b - gray) * sat - return r, g, b - - -def _apply_contrast(rgb: Tuple[float, float, float], contrast: float) -> Tuple[float, float, float]: - r, g, b = rgb - r = 128 + (r - 128) * contrast - g = 128 + (g - 128) * contrast - b = 128 + (b - 128) * contrast - return r, g, b - - -def _apply_night_blue_push( - rgb: Tuple[float, float, float], - blue_push: float, -) -> Tuple[float, float, float]: - """ - Extra night-only hue shift: - - Slightly reduces R and G - - Increases B - 'blue_push' is ~ (blue_scale - 1) * night, so this is zero in daytime. - """ - if blue_push <= 0.0: - return rgb - r, g, b = rgb - c = blue_push - r *= (1.0 - 0.15 * c) - g *= (1.0 - 0.10 * c) - b *= (1.0 + 0.35 * c) - return r, g, b - - -def tint_rgb( - rgb: Tuple[int, int, int], - params: dict, - *, - sat_boost: float, - contrast: float, -) -> Tuple[int, int, int]: - r, g, b = rgb - r_f = r * params["r_mul"] * params["brightness"] - g_f = g * params["g_mul"] * params["brightness"] - b_f = b * params["b_mul"] * params["brightness"] - - gray = (r_f + g_f + b_f) / 3.0 - t = params["gray_blend"] - r_f = (1 - t) * r_f + t * gray - g_f = (1 - t) * g_f + t * gray - b_f = (1 - t) * b_f + t * gray - - # Global saturation, then extra night-only blue hue push, then contrast - r_f, g_f, b_f = _apply_saturation((r_f, g_f, b_f), sat_boost) - r_f, g_f, b_f = _apply_night_blue_push((r_f, g_f, b_f), params.get("blue_push", 0.0)) - r_f, g_f, b_f = _apply_contrast((r_f, g_f, b_f), contrast) - - return (clamp_byte(r_f), clamp_byte(g_f), clamp_byte(b_f)) - - -# --------------------------- Noon-neutral weighting --------------------------- - -def _smoothstep01(t: float) -> float: - """Cubic smoothstep on [0,1].""" - if t <= 0.0: - return 0.0 - if t >= 1.0: - return 1.0 - return t * t * (3.0 - 2.0 * t) - - -def _interval_membership(x: float, a: float, b: float, soft: float) -> float: - """ - Smooth membership of time-of-day x (0..24) inside interval [a,b] (hours), - with soft edge width 'soft' (hours). Supports wrapped intervals (a>b). - Returns 0..1. - """ - x = x % 24.0 - a = a % 24.0 - b = b % 24.0 - soft = max(0.0, soft) - - def segment_membership(x: float, s: float, e: float, soft: float) -> float: - if soft <= 0.0: - return 1.0 if (s <= x <= e) else 0.0 - - if s - soft <= x < s: - t = (x - (s - soft)) / soft - return _smoothstep01(t) - - if s <= x <= e: - return 1.0 - - if e < x <= e + soft: - t = (x - e) / soft - return 1.0 - _smoothstep01(t) - - return 0.0 - - if a <= b: - return segment_membership(x, a, b, soft) - else: - m1 = segment_membership(x, a, 24.0, soft) - m2 = segment_membership(x, 0.0, b, soft) - return max(m1, m2) - - -def _noon_weight(hour_value: float, blend: float, sigma: float, - w_start: float, w_end: float, w_soft: float) -> float: - """ - Combined noon weight in 0..1: - - Gaussian around 12:00 with width 'sigma' (hours), scaled by 'blend'. - - Smooth interval window [w_start, w_end] with soft edges 'w_soft', - also scaled by 'blend'. - """ - try: - h = hour_value % 24.0 - except Exception: - h = 0.0 - blend = float(blend) if blend is not None else 0.0 - sigma = float(sigma) if sigma is not None else 0.0 - w_start = float(w_start) if w_start is not None else 10.0 - w_end = float(w_end) if w_end is not None else 14.0 - w_soft = max(0.0, float(w_soft) if w_soft is not None else 0.7) - - if blend <= 0.0: - return 0.0 - - from math import exp - d = abs(h - 12.0) - d = min(d, 24.0 - d) - g = exp(-0.5 * (d / sigma) ** 2) if sigma > 0.0 else 0.0 - g *= blend - - window_m = _interval_membership(h, w_start, w_end, w_soft) * blend - - w = max(g, window_m) - if w < 0.0: - return 0.0 - if w > 1.0: - return 1.0 - return w - - -# --------------------------- Palette helpers --------------------------- - -def get_palette(img: Image.Image) -> List[int]: - pal = img.getpalette() - if pal is None: - raise ValueError("Image has no palette (mode must be 'P').") - if len(pal) < 256 * 3: - pal = pal + [0] * (256 * 3 - len(pal)) - return pal[:256 * 3] - - -def set_palette(img: Image.Image, pal: Sequence[int]) -> None: - if len(pal) != 256 * 3: - raise ValueError("Palette must be exactly 256*3 entries.") - img.putpalette(list(pal)) - - -def find_color_index(pal: Sequence[int], color: Tuple[int, int, int]) -> int: - cr, cg, cb = color - for i in range(256): - r, g, b = pal[3 * i: 3 * i + 3] - if r == cr and g == cg and b == cb: - return i - return -1 - - -# --------------------------- Green removal (NEW) --------------------------- - -def remap_all_green_to_magenta_and_blacken_palette( - im: Image.Image, - pal: List[int], - *, - green: Tuple[int, int, int] = (0, 255, 0), - magenta: Tuple[int, int, int] = (255, 0, 255), - black: Tuple[int, int, int] = (0, 0, 0), -) -> Image.Image: - """ - 1) Remap pixels from ANY palette index that is exactly green -> magenta index. - 2) Replace ANY palette entry that is exactly green with black. - This removes #00FF00 from the palette entirely. - """ - magenta_idx = find_color_index(pal, magenta) - if magenta_idx < 0: - return im # can't remap without magenta entry - - green_indices: List[int] = [] - for i in range(256): - r, g, b = pal[3 * i: 3 * i + 3] - if (r, g, b) == green: - green_indices.append(i) - - if not green_indices: - return im - - # Remap pixels: any green index -> magenta index - lut = list(range(256)) - for gi in green_indices: - lut[gi] = magenta_idx - im = im.point(lut, mode="P") - - # Replace those palette entries with black - for gi in green_indices: - pal[3 * gi + 0] = black[0] - pal[3 * gi + 1] = black[1] - pal[3 * gi + 2] = black[2] - - return im - - -# --------------------------- Core operations --------------------------- - -def adjust_palette_for_time( - pal: List[int], - hour_value: float, - reserved_colors: Iterable[Tuple[int, int, int]], - *, - reserved_indices: Iterable[int] = (), - # look controls - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sat_boost: float, - contrast: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, - # noon neutral zone controls - noon_blend: float, - noon_sigma: float, - noon_window_start: float, - noon_window_end: float, - noon_window_soft: float, -) -> List[int]: - params = hour_adjustments( - hour_value, - warmth_scale=warmth_scale, - blue_scale=blue_scale, - darkness_scale=darkness_scale, - desat_scale=desat_scale, - sunrise_center=sunrise_center, - sunset_center=sunset_center, - twilight_sigma=twilight_sigma, - ) - reserved_color_set = set(reserved_colors) - reserved_index_set = set(int(i) for i in reserved_indices) - - noon_w = _noon_weight( - hour_value, noon_blend, noon_sigma, - noon_window_start, noon_window_end, noon_window_soft - ) - - sat_eff = 1.0 + (sat_boost - 1.0) * (1.0 - noon_w) - contrast_eff = 1.0 + (contrast - 1.0) * (1.0 - noon_w) - - out = pal[:] # copy - for i in range(256): - r, g, b = pal[3 * i: 3 * i + 3] - - # Skip EXACT indices first (highest priority) - if i in reserved_index_set: - out[3 * i + 0], out[3 * i + 1], out[3 * i + 2] = r, g, b - continue - - # Then skip by color (magenta + user light-keys) - if (r, g, b) in reserved_color_set: - out[3 * i + 0], out[3 * i + 1], out[3 * i + 2] = r, g, b - continue - - nr, ng, nb = tint_rgb((r, g, b), params, sat_boost=sat_eff, contrast=contrast_eff) - - if noon_w > 0.0: - nr = int(round((1.0 - noon_w) * nr + noon_w * r)) - ng = int(round((1.0 - noon_w) * ng + noon_w * g)) - nb = int(round((1.0 - noon_w) * nb + noon_w * b)) - - nr, ng, nb = _nudge_if_reserved((nr, ng, nb), reserved_color_set, (r, g, b)) - - out[3 * i + 0] = nr - out[3 * i + 1] = ng - out[3 * i + 2] = nb - - return out - - -# --------------------------- File ops --------------------------- - -def copy_noon_to_label(noon_dir: Path, label_dir: Path) -> List[Path]: - label_dir.mkdir(parents=True, exist_ok=True) - copied: List[Path] = [] - for src in noon_dir.iterdir(): - if not src.is_file() or src.suffix.lower() != ".pcx": - continue - dst = label_dir / src.name - shutil.copy2(src, dst) - copied.append(dst) - return copied - - -def label_to_hour_value(label: str) -> float: - """Convert 'HHMM' or '2400' to hour value (fractional hours).""" - if label == "2400": - return 0.0 - h = int(label[:2]) - m = int(label[2:]) - return (h % 24) + (m / 60.0) - - -def process_time_label( - label: str, - base_dir: Path, - noon_label: str, - reserved_colors: Iterable[Tuple[int, int, int]], - *, - do_index_remap: bool, - # look controls... - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sat_boost: float, - contrast: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, - # noon neutral controls... - noon_blend: float, - noon_sigma: float, - noon_window_start: float, - noon_window_end: float, - noon_window_soft: float, -) -> None: - noon_dir = base_dir / noon_label - out_dir = base_dir / label - hour_value = label_to_hour_value(label) - - copied_files = copy_noon_to_label(noon_dir, out_dir) - - for pcx_path in copied_files: - with Image.open(pcx_path) as im: - if im.mode != "P": - im = im.convert("P") - pal = get_palette(im) - - # Optional green→magenta pixel remap AND remove green from palette (set to black) - if do_index_remap: - im = remap_all_green_to_magenta_and_blacken_palette(im, pal) - - effective_reserved_colors: List[Tuple[int, int, int]] = list(reserved_colors) - reserved_by_color_rgbs = set(effective_reserved_colors) - - # Initialize to empty for non-EntertainmentComplex files - reserved_idx: Set[int] = set() - - # If this is an Entertainment Complex, protect EXACT pixels by duplicating indices - if "EntertainmentComplex" in pcx_path.name and is_night_hour(24 if int(hour_value) == 0 else int(hour_value)): - ranges = PROTECTED_RANGES_ENT_COMPLEX - ranges = _bridge_small_gaps(ranges, PROTECTED_GAP_BRIDGE) - reserved_idx = _protect_exact_pixels_by_index( - im, pal, ranges, reserved_by_color_rgbs=reserved_by_color_rgbs - ) - - new_pal = adjust_palette_for_time( - pal, hour_value, effective_reserved_colors, - reserved_indices=reserved_idx, - warmth_scale=warmth_scale, - blue_scale=blue_scale, - darkness_scale=darkness_scale, - desat_scale=desat_scale, - sat_boost=sat_boost, - contrast=contrast, - sunrise_center=sunrise_center, - sunset_center=sunset_center, - twilight_sigma=twilight_sigma, - noon_blend=noon_blend, - noon_sigma=noon_sigma, - noon_window_start=noon_window_start, - noon_window_end=noon_window_end, - noon_window_soft=noon_window_soft, - ) - - set_palette(im, new_pal) - im.save(pcx_path, format="PCX") - - -# --------------------------- Main --------------------------- - -def main(): - p = argparse.ArgumentParser(description="Civ3 PCX day/night generator with variable time steps and noon-neutral zone.") - p.add_argument("--data", required=True, - help="Parent folder containing the noon folder and sibling time folders (e.g., NightDay).") - p.add_argument("--noon", default="1200", - help="Name of the noon folder (default: 1200).") - p.add_argument("--only-hour", default=None, - help="Process only a single time label (e.g., 1900, 1930, or 2400).") - p.add_argument("--step-minutes", type=int, default=60, - help="Time step in minutes; must divide 60 (e.g., 5,10,15,20,30,60). Default: 60.") - - p.add_argument("--light-key", action="append", default=[], - help="Reserved color that must not change. Repeatable. '#RRGGBB' or 'R,G,B'.") - - # Look/feel controls - p.add_argument("--warmth", type=float, default=1.10, - help="Scale for sunrise/sunset warmth (1.0 = base).") - p.add_argument("--blue", type=float, default=1.12, - help="Scale for night-time blue emphasis (1.0 = base).") - p.add_argument("--darkness", type=float, default=1.08, - help="Scale for extra night darkening (1.0 = base).") - p.add_argument("--desat", type=float, default=0.85, - help="Scale for dusk/night desaturation toward gray (lower = richer).") - p.add_argument("--sat", type=float, default=1.05, - help="Global saturation multiplier after tint (1.0 = none).") - p.add_argument("--contrast", type=float, default=1.03, - help="Global contrast multiplier around mid 128 (1.0 = none).") - - # Curve placement/width - p.add_argument("--sunrise-center", type=float, default=6.0, - help="Hour center for sunrise warmth bump (0-23).") - p.add_argument("--sunset-center", type=float, default=18.0, - help="Hour center for sunset warmth bump (0-23).") - p.add_argument("--twilight-width", type=float, default=1.8, - help="Sigma for sunrise/sunset warmth spread (higher = broader).") - - # Noon-neutral zone controls - p.add_argument("--noon-blend", type=float, default=1.0, - help="0..1 strength to blend toward base palette near 12:00 (0=off).") - p.add_argument("--noon-sigma", type=float, default=1.1, - help="Gaussian width (hours) around 12:00 (larger = broader).") - p.add_argument("--noon-window-start", type=float, default=10.0, - help="Start hour of the noon-like window (default 10.0).") - p.add_argument("--noon-window-end", type=float, default=14.0, - help="End hour of the noon-like window (default 14.0).") - p.add_argument("--noon-window-soft", type=float, default=0.7, - help="Soft edge (hours) for window ramps (0=hard).") - - # Index remap control - g = p.add_mutually_exclusive_group() - g.add_argument("--keep-green-index", action="store_true", - help="Do NOT remap green pixels to magenta; also do NOT remove #00FF00 from the palette.") - g.add_argument("--map-green-index", dest="map_green_index", action="store_true", - help="Force remap green pixels to magenta and replace any #00FF00 palette entries with black (default behavior).") - - args = p.parse_args() - - base_dir = Path(args.data).expanduser().resolve() - noon_dir = base_dir / args.noon - if not noon_dir.is_dir(): - raise SystemExit(f"Noon folder not found: {noon_dir}") - - # Reserved colors: - # - Magenta is kept stable - # - Green is NOT reserved anymore because we remove it from the palette when remapping is enabled - reserved: List[Tuple[int, int, int]] = [(255, 0, 255)] - for s in args.light_key: - reserved.append(parse_rgb(s)) - - # Determine remap behavior (default ON) - do_index_remap = not args.keep_green_index or args.map_green_index - - labels = [lbl for lbl in time_labels(args.step_minutes) if lbl != args.noon] - - # only-hour (accept 0000 -> 2400) - if args.only_hour: - only = "2400" if args.only_hour == "0000" else args.only_hour - if only == args.noon: - print(f"--only-hour {only} is the noon source; nothing to do.") - return - if only not in labels: - raise SystemExit(f"--only-hour must be one of: {', '.join(labels)}") - labels = [only] - - print(f"Base: {base_dir}") - print(f"Noon source: {noon_dir}") - print(f"Time step: {args.step_minutes} minutes") - print(f"Green pixels→magenta + remove #00FF00 from palette: {'ON' if do_index_remap else 'OFF'}") - print(f"Generating labels: {', '.join(labels)}") - - for lbl in labels: - print(f" -> Generating {lbl} ...") - process_time_label( - lbl, base_dir, args.noon, reserved, - do_index_remap=do_index_remap, - warmth_scale=args.warmth, - blue_scale=args.blue, - darkness_scale=args.darkness, - desat_scale=args.desat, - sat_boost=args.sat, - contrast=args.contrast, - sunrise_center=args.sunrise_center, - sunset_center=args.sunset_center, - twilight_sigma=args.twilight_width, - noon_blend=args.noon_blend, - noon_sigma=args.noon_sigma, - noon_window_start=args.noon_window_start, - noon_window_end=args.noon_window_end, - noon_window_soft=args.noon_window_soft, - ) - - print("Done.") - - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +""" +civ3_daynight_pcx.py — v4.4 (remove #00FF00 from palette entirely) + +Highlights: +- Half-hour (or any divisor of an hour) time slices via --step-minutes. +- Green→Magenta pixel remap (on by default). +- NEW: After pixel remap, ANY palette entries exactly #00FF00 are replaced with black (#000000), + so #00FF00 no longer exists anywhere in the palette. +- Palette-only tinting; indices preserved (except the optional index remap). +- Noon-neutral zone keeps ~10:00–14:00 close to base 1200. +- Stronger nighttime blue response using the existing --blue knob, + with an additional night-only hue shift (blue up, red/green down). + +Tested knobs (your current favorites work unchanged): + --warmth 1.05 --blue 2.0 --darkness 1.1 --desat 0.85 --sat 1.2 --contrast 1.08 + --sunrise-center 5.0 --sunset-center 18.0 --twilight-width 3.0 + --noon-blend 0.7 --noon-sigma 1.0 +""" + +import argparse +import shutil +from pathlib import Path +from typing import Iterable, List, Sequence, Tuple, Set, Dict, Optional + +from PIL import Image +from civ3_city_lights import is_night_hour +from protected_pixels import PROTECTED_RANGES_ENT_COMPLEX + +# Fallback behavior if the palette is full and we cannot allocate a new index +PROTECTED_FALLBACK_NEIGHBOR_RADIUS = 1 # 1 => 3x3 window, 2 => 5x5, etc. +PROTECTED_GAP_BRIDGE = 1 + +from collections import defaultdict, Counter +from math import sqrt + + +# --------------------------- Helpers for protected ranges --------------------------- + +def _bridge_small_gaps( + ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], + max_gap: int, +) -> List[Tuple[Tuple[int, int], Tuple[int, int]]]: + """ + Merge/bridge adjacent horizontal ranges on the same scanline (same y) + when the gap between them is <= max_gap. Ranges are inclusive. + Input items are ((x1, y), (x2, y)). Non-horizontal ranges are kept as-is. + """ + if max_gap <= 0 or not ranges: + return list(ranges) + + by_y = defaultdict(list) + for (x1, y1), (x2, y2) in ranges: + if y1 != y2: + # Not horizontal; keep separate + by_y[(y1, y2, 'nonh')].append((min(x1, x2), max(x1, x2), y1, y2)) + continue + by_y[y1].append((min(x1, x2), max(x1, x2))) + + out: List[Tuple[Tuple[int, int], Tuple[int, int]]] = [] + + # Re-emit any non-horizontal entries unchanged + for key, spans in list(by_y.items()): + if isinstance(key, tuple) and key[-1] == 'nonh': + for x1, x2, y1, y2 in spans: + out.append(((x1, y1), (x2, y2))) + del by_y[key] + + # Bridge gaps on horizontal scanlines + for y, spans in by_y.items(): + spans.sort() + cur_x1, cur_x2 = spans[0] + for nx1, nx2 in spans[1:]: + gap = nx1 - cur_x2 - 1 # inclusive ranges + if gap <= max_gap: + cur_x2 = max(cur_x2, nx2) + else: + out.append(((cur_x1, y), (cur_x2, y))) + cur_x1, cur_x2 = nx1, nx2 + out.append(((cur_x1, y), (cur_x2, y))) + + return out + + +def clamp_byte(x: float) -> int: + return int(max(0, min(255, round(x)))) + + +def _nudge_if_reserved(nrgb, reserved_set, orig_rgb): + if nrgb in reserved_set: + # Nudge 1 toward original to avoid exact collision + r0, g0, b0 = orig_rgb + r, g, b = nrgb + + def nudge(c, c0): + return clamp_byte(c - 1 if c > c0 else c + 1 if c < c0 else c) + + return (nudge(r, r0), nudge(g, g0), nudge(b, b0)) + return nrgb + + +def _rgb_of_index(pal: List[int], idx: int) -> Tuple[int, int, int]: + return pal[3 * idx], pal[3 * idx + 1], pal[3 * idx + 2] + + +def _color_dist2(a: Tuple[int, int, int], b: Tuple[int, int, int]) -> float: + dr, dg, db = a[0] - b[0], a[1] - b[1], a[2] - b[2] + return dr * dr + dg * dg + db * db + + +def _index_pixel_counts(im: Image.Image) -> Dict[int, int]: + colors = im.getcolors(maxcolors=256 * 256) or [] + return {int(idx): int(cnt) for (cnt, idx) in colors} + + +def _indices_used_in_coords( + im: Image.Image, + ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], +) -> Set[int]: + w, h = im.size + px = im.load() + s: Set[int] = set() + for (x1, y1), (x2, y2) in ranges: + x_start, x_end = (x1, x2) if x1 <= x2 else (x2, x1) + y_start, y_end = (y1, y2) if y1 <= y2 else (y2, y1) + for y in range(max(0, y_start), min(h, y_end + 1)): + for x in range(max(0, x_start), min(w, x_end + 1)): + s.add(int(px[x, y])) + return s + + +def _find_nearest_index( + pal: List[int], + src_idx: int, + allowed: Iterable[int], +) -> Optional[int]: + src_rgb = _rgb_of_index(pal, src_idx) + best = None + best_d2 = 1e18 + for j in allowed: + if j == src_idx: + continue + d2 = _color_dist2(src_rgb, _rgb_of_index(pal, j)) + if d2 < best_d2: + best_d2 = d2 + best = int(j) + return best + + +def _used_palette_indices(im: Image.Image) -> Set[int]: + """ + Return the set of palette indices actually used by the image. + """ + colors = im.getcolors(maxcolors=256 * 256) or [] + used: Set[int] = set() + for _, idx in colors: + used.add(int(idx)) + return used + + +def _free_palette_slots( + im: Image.Image, + pal: List[int], + needed: int, + *, + protected_source_indices: Set[int], # indices that appear inside protected coords + reserved_by_color_rgbs: Set[Tuple[int, int, int]], # magenta/green/light-keys as RGB +) -> int: + """ + Try to free up to `needed` palette slots by remapping the *least-used* indices + (that are NOT protected and NOT reserved-by-color) to their nearest-color neighbors. + Returns the number of slots actually freed. Pixels are rewritten in-place. + """ + if needed <= 0: + return 0 + + w, h = im.size + px = im.load() + counts = _index_pixel_counts(im) + used_indices = set(counts.keys()) + + # Build sets for constraints + reserved_by_color_indices: Set[int] = set() + for i in range(256): + if i in used_indices: + rgb = (pal[3 * i], pal[3 * i + 1], pal[3 * i + 2]) + if rgb in reserved_by_color_rgbs: + reserved_by_color_indices.add(i) + + forbidden = set(protected_source_indices) | reserved_by_color_indices + + # Candidates we are allowed to merge away + candidates = [i for i in used_indices if i not in forbidden] + + if not candidates: + return 0 + + # Sort by ascending usage (least used first) + candidates.sort(key=lambda i: counts.get(i, 0)) + + freed = 0 + allowed_targets = set(used_indices) - forbidden + + for src_idx in candidates: + if freed >= needed: + break + if src_idx not in used_indices: + continue + + options = allowed_targets - {src_idx} + if not options: + continue + + tgt = _find_nearest_index(pal, src_idx, options) + if tgt is None: + continue + + # Remap all pixels from src_idx -> tgt + for y in range(h): + for x in range(w): + if px[x, y] == src_idx: + px[x, y] = tgt + + used_indices.discard(src_idx) + allowed_targets.discard(src_idx) + freed += 1 + + return freed + + +def _sample_neighbor_index(px, x: int, y: int, w: int, h: int, r: int) -> Optional[int]: + """ + Return the most common palette index in the (2r+1)x(2r+1) neighborhood + around (x,y), excluding the center pixel. If nothing valid, return None. + """ + if r <= 0: + return None + xs = range(max(0, x - r), min(w, x + r + 1)) + ys = range(max(0, y - r), min(h, y + r + 1)) + counts = Counter() + for yy in ys: + for xx in xs: + if xx == x and yy == y: + continue + counts[int(px[xx, yy])] += 1 + return counts.most_common(1)[0][0] if counts else None + + +def _protect_exact_pixels_by_index( + im: Image.Image, + pal: List[int], + ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], + reserved_by_color_rgbs: Set[Tuple[int, int, int]] = set(), +) -> Set[int]: + """ + Ensure protected coords keep their original (noon) colors by duplicating indices. + If the palette is full, first free slots by merging least-used non-protected indices + into nearest neighbors. If still short on slots, fall back to neighbor sampling. + Returns set of dedicated reserved indices. + """ + assert im.mode == "P", "Image must be paletted ('P')" + w, h = im.size + px = im.load() + + protected_src_indices = _indices_used_in_coords(im, ranges) + + used_now = _used_palette_indices(im) + free_now = [i for i in range(256) if i not in used_now] + need = max(0, len(protected_src_indices) - len(free_now)) + + if need > 0: + _ = _free_palette_slots( + im, + pal, + need, + protected_source_indices=protected_src_indices, + reserved_by_color_rgbs=reserved_by_color_rgbs, + ) + + # Recompute used/free after freeing + used = _used_palette_indices(im) + free_pool = [i for i in range(256) if i not in used] + + index_map: Dict[int, int] = {} + reserved_indices: Set[int] = set() + + radius = int(PROTECTED_FALLBACK_NEIGHBOR_RADIUS) + + # Duplicate on first encounter of a src index + for (x1, y1), (x2, y2) in ranges: + x_start, x_end = (x1, x2) if x1 <= x2 else (x2, x1) + y_start, y_end = (y1, y2) if y1 <= y2 else (y2, y1) + + for y in range(y_start, y_end + 1): + if not (0 <= y < h): + continue + for x in range(x_start, x_end + 1): + if not (0 <= x < w): + continue + + orig_idx = int(px[x, y]) + + dup = index_map.get(orig_idx) + if dup is not None: + px[x, y] = dup + continue + + if free_pool: + dup_idx = free_pool.pop(0) + r, g, b = pal[3 * orig_idx: 3 * orig_idx + 3] + pal[3 * dup_idx + 0] = r + pal[3 * dup_idx + 1] = g + pal[3 * dup_idx + 2] = b + index_map[orig_idx] = dup_idx + reserved_indices.add(dup_idx) + px[x, y] = dup_idx + continue + + # LAST RESORT: neighbor sampling + neighbor_idx = _sample_neighbor_index(px, x, y, w, h, radius) + if neighbor_idx is not None: + px[x, y] = int(neighbor_idx) + else: + print(f"WARNING: No palette slots and no neighbors for ({x},{y}).") + + return reserved_indices + + +# --------------------------- CLI & helpers --------------------------- + +def parse_rgb(s: str) -> Tuple[int, int, int]: + s = s.strip() + if s.startswith("#"): + s = s[1:] + if len(s) != 6: + raise ValueError(f"Bad hex color: #{s}") + return tuple(int(s[i:i + 2], 16) for i in (0, 2, 4)) # type: ignore + if "," in s: + parts = [p.strip() for p in s.split(",")] + if len(parts) != 3: + raise ValueError(f"Bad RGB list: {s}") + return tuple(int(p) for p in parts) # type: ignore + raise ValueError(f"Unrecognized color format: {s}") + + +def time_labels(step_minutes: int) -> List[str]: + """ + Generate HHMM labels from step to 23:59 stepwise; exclude 0000; add 2400. + For step=60: 0100..2300 + 2400 + For step=30: 0030, 0100, 0130..2330 + 2400 + """ + if step_minutes <= 0 or 60 % step_minutes != 0: + raise ValueError("--step-minutes must be a positive divisor of 60 (e.g., 5,10,15,20,30,60).") + labels: List[str] = [] + total_minutes = 24 * 60 + m = step_minutes + while m < total_minutes: + h = m // 60 + mm = m % 60 + labels.append(f"{h:02d}{mm:02d}") + m += step_minutes + labels.append("2400") + return labels + + +# --------------------------- TONEMAP MODEL --------------------------- + +def _gauss(x: float, mu: float, sigma: float) -> float: + from math import exp + if sigma <= 0.0: + return 0.0 + return exp(-0.5 * ((x - mu) / sigma) ** 2) + + +def hour_adjustments( + hour_value: float, + *, + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, +) -> dict: + """ + hour_value can be fractional (e.g., 19.5 for 19:30). Period is 24h. + Returns a dict with per-channel multipliers, gray blend, brightness, + and 'night' + 'blue_push' factors for night-only hue shift. + """ + from math import cos, pi + + h = hour_value % 24.0 + + # Daylight (cosine): 1 at noon, ~0 at midnight + daylight = max(0.0, cos(pi * (h - 12.0) / 12.0)) # 0..1 + night = 1.0 - daylight + + # Warmth around sunrise/sunset + warmth = 0.85 * (_gauss(h, sunrise_center, twilight_sigma) + + _gauss(h, sunset_center, twilight_sigma)) + warmth *= warmth_scale + + # Brightness: darker at night; scaled by darkness_scale (>1 = darker nights) + base_brightness = 0.60 + 0.40 * daylight + night_darkening = 1.0 - (0.12 * (darkness_scale - 1.0) * night) + brightness = base_brightness * night_darkening + + # Channel multipliers + r_mul = 0.97 + 0.12 * daylight + 0.30 * warmth + g_mul = 0.97 + 0.12 * daylight + 0.12 * warmth + b_mul = 0.97 + 0.12 * daylight - 0.18 * warmth + (0.28 * blue_scale) * night + + # Desaturation (toward gray) stronger at night; scaled by desat_scale + gray_blend = (0.10 + 0.50 * night) * desat_scale + gray_blend = min(max(gray_blend, 0.0), 0.85) + + # Night-only blue push factor (extra hue shift at night) + blue_push = max(0.0, blue_scale - 1.0) * night # 0 at day, up to (blue-1) at night + + # Clamp gentle bounds + r_mul = min(max(r_mul, 0.65), 1.45) + g_mul = min(max(g_mul, 0.65), 1.40) + b_mul = min(max(b_mul, 0.65), 1.55) + + return dict( + brightness=brightness, + r_mul=r_mul, + g_mul=g_mul, + b_mul=b_mul, + gray_blend=gray_blend, + night=night, + blue_push=blue_push, + ) + + +def _apply_saturation(rgb: Tuple[float, float, float], sat: float) -> Tuple[float, float, float]: + r, g, b = rgb + gray = (r + g + b) / 3.0 + r = gray + (r - gray) * sat + g = gray + (g - gray) * sat + b = gray + (b - gray) * sat + return r, g, b + + +def _apply_contrast(rgb: Tuple[float, float, float], contrast: float) -> Tuple[float, float, float]: + r, g, b = rgb + r = 128 + (r - 128) * contrast + g = 128 + (g - 128) * contrast + b = 128 + (b - 128) * contrast + return r, g, b + + +def _apply_night_blue_push( + rgb: Tuple[float, float, float], + blue_push: float, +) -> Tuple[float, float, float]: + """ + Extra night-only hue shift: + - Slightly reduces R and G + - Increases B + 'blue_push' is ~ (blue_scale - 1) * night, so this is zero in daytime. + """ + if blue_push <= 0.0: + return rgb + r, g, b = rgb + c = blue_push + r *= (1.0 - 0.15 * c) + g *= (1.0 - 0.10 * c) + b *= (1.0 + 0.35 * c) + return r, g, b + + +def tint_rgb( + rgb: Tuple[int, int, int], + params: dict, + *, + sat_boost: float, + contrast: float, +) -> Tuple[int, int, int]: + r, g, b = rgb + r_f = r * params["r_mul"] * params["brightness"] + g_f = g * params["g_mul"] * params["brightness"] + b_f = b * params["b_mul"] * params["brightness"] + + gray = (r_f + g_f + b_f) / 3.0 + t = params["gray_blend"] + r_f = (1 - t) * r_f + t * gray + g_f = (1 - t) * g_f + t * gray + b_f = (1 - t) * b_f + t * gray + + # Global saturation, then extra night-only blue hue push, then contrast + r_f, g_f, b_f = _apply_saturation((r_f, g_f, b_f), sat_boost) + r_f, g_f, b_f = _apply_night_blue_push((r_f, g_f, b_f), params.get("blue_push", 0.0)) + r_f, g_f, b_f = _apply_contrast((r_f, g_f, b_f), contrast) + + return (clamp_byte(r_f), clamp_byte(g_f), clamp_byte(b_f)) + + +# --------------------------- Noon-neutral weighting --------------------------- + +def _smoothstep01(t: float) -> float: + """Cubic smoothstep on [0,1].""" + if t <= 0.0: + return 0.0 + if t >= 1.0: + return 1.0 + return t * t * (3.0 - 2.0 * t) + + +def _interval_membership(x: float, a: float, b: float, soft: float) -> float: + """ + Smooth membership of time-of-day x (0..24) inside interval [a,b] (hours), + with soft edge width 'soft' (hours). Supports wrapped intervals (a>b). + Returns 0..1. + """ + x = x % 24.0 + a = a % 24.0 + b = b % 24.0 + soft = max(0.0, soft) + + def segment_membership(x: float, s: float, e: float, soft: float) -> float: + if soft <= 0.0: + return 1.0 if (s <= x <= e) else 0.0 + + if s - soft <= x < s: + t = (x - (s - soft)) / soft + return _smoothstep01(t) + + if s <= x <= e: + return 1.0 + + if e < x <= e + soft: + t = (x - e) / soft + return 1.0 - _smoothstep01(t) + + return 0.0 + + if a <= b: + return segment_membership(x, a, b, soft) + else: + m1 = segment_membership(x, a, 24.0, soft) + m2 = segment_membership(x, 0.0, b, soft) + return max(m1, m2) + + +def _noon_weight(hour_value: float, blend: float, sigma: float, + w_start: float, w_end: float, w_soft: float) -> float: + """ + Combined noon weight in 0..1: + - Gaussian around 12:00 with width 'sigma' (hours), scaled by 'blend'. + - Smooth interval window [w_start, w_end] with soft edges 'w_soft', + also scaled by 'blend'. + """ + try: + h = hour_value % 24.0 + except Exception: + h = 0.0 + blend = float(blend) if blend is not None else 0.0 + sigma = float(sigma) if sigma is not None else 0.0 + w_start = float(w_start) if w_start is not None else 10.0 + w_end = float(w_end) if w_end is not None else 14.0 + w_soft = max(0.0, float(w_soft) if w_soft is not None else 0.7) + + if blend <= 0.0: + return 0.0 + + from math import exp + d = abs(h - 12.0) + d = min(d, 24.0 - d) + g = exp(-0.5 * (d / sigma) ** 2) if sigma > 0.0 else 0.0 + g *= blend + + window_m = _interval_membership(h, w_start, w_end, w_soft) * blend + + w = max(g, window_m) + if w < 0.0: + return 0.0 + if w > 1.0: + return 1.0 + return w + + +# --------------------------- Palette helpers --------------------------- + +def get_palette(img: Image.Image) -> List[int]: + pal = img.getpalette() + if pal is None: + raise ValueError("Image has no palette (mode must be 'P').") + if len(pal) < 256 * 3: + pal = pal + [0] * (256 * 3 - len(pal)) + return pal[:256 * 3] + + +def set_palette(img: Image.Image, pal: Sequence[int]) -> None: + if len(pal) != 256 * 3: + raise ValueError("Palette must be exactly 256*3 entries.") + img.putpalette(list(pal)) + + +def find_color_index(pal: Sequence[int], color: Tuple[int, int, int]) -> int: + cr, cg, cb = color + for i in range(256): + r, g, b = pal[3 * i: 3 * i + 3] + if r == cr and g == cg and b == cb: + return i + return -1 + + +# --------------------------- Green removal (NEW) --------------------------- + +def remap_all_green_to_magenta_and_blacken_palette( + im: Image.Image, + pal: List[int], + *, + green: Tuple[int, int, int] = (0, 255, 0), + magenta: Tuple[int, int, int] = (255, 0, 255), + black: Tuple[int, int, int] = (0, 0, 0), +) -> Image.Image: + """ + 1) Remap pixels from ANY palette index that is exactly green -> magenta index. + 2) Replace ANY palette entry that is exactly green with black. + This removes #00FF00 from the palette entirely. + """ + magenta_idx = find_color_index(pal, magenta) + if magenta_idx < 0: + return im # can't remap without magenta entry + + green_indices: List[int] = [] + for i in range(256): + r, g, b = pal[3 * i: 3 * i + 3] + if (r, g, b) == green: + green_indices.append(i) + + if not green_indices: + return im + + # Remap pixels: any green index -> magenta index + lut = list(range(256)) + for gi in green_indices: + lut[gi] = magenta_idx + im = im.point(lut, mode="P") + + # Replace those palette entries with black + for gi in green_indices: + pal[3 * gi + 0] = black[0] + pal[3 * gi + 1] = black[1] + pal[3 * gi + 2] = black[2] + + return im + + +# --------------------------- Core operations --------------------------- + +def adjust_palette_for_time( + pal: List[int], + hour_value: float, + reserved_colors: Iterable[Tuple[int, int, int]], + *, + reserved_indices: Iterable[int] = (), + # look controls + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sat_boost: float, + contrast: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, + # noon neutral zone controls + noon_blend: float, + noon_sigma: float, + noon_window_start: float, + noon_window_end: float, + noon_window_soft: float, +) -> List[int]: + params = hour_adjustments( + hour_value, + warmth_scale=warmth_scale, + blue_scale=blue_scale, + darkness_scale=darkness_scale, + desat_scale=desat_scale, + sunrise_center=sunrise_center, + sunset_center=sunset_center, + twilight_sigma=twilight_sigma, + ) + reserved_color_set = set(reserved_colors) + reserved_index_set = set(int(i) for i in reserved_indices) + + noon_w = _noon_weight( + hour_value, noon_blend, noon_sigma, + noon_window_start, noon_window_end, noon_window_soft + ) + + sat_eff = 1.0 + (sat_boost - 1.0) * (1.0 - noon_w) + contrast_eff = 1.0 + (contrast - 1.0) * (1.0 - noon_w) + + out = pal[:] # copy + for i in range(256): + r, g, b = pal[3 * i: 3 * i + 3] + + # Skip EXACT indices first (highest priority) + if i in reserved_index_set: + out[3 * i + 0], out[3 * i + 1], out[3 * i + 2] = r, g, b + continue + + # Then skip by color (magenta + user light-keys) + if (r, g, b) in reserved_color_set: + out[3 * i + 0], out[3 * i + 1], out[3 * i + 2] = r, g, b + continue + + nr, ng, nb = tint_rgb((r, g, b), params, sat_boost=sat_eff, contrast=contrast_eff) + + if noon_w > 0.0: + nr = int(round((1.0 - noon_w) * nr + noon_w * r)) + ng = int(round((1.0 - noon_w) * ng + noon_w * g)) + nb = int(round((1.0 - noon_w) * nb + noon_w * b)) + + nr, ng, nb = _nudge_if_reserved((nr, ng, nb), reserved_color_set, (r, g, b)) + + out[3 * i + 0] = nr + out[3 * i + 1] = ng + out[3 * i + 2] = nb + + return out + + +# --------------------------- File ops --------------------------- + +def copy_noon_to_label(noon_dir: Path, label_dir: Path) -> List[Path]: + label_dir.mkdir(parents=True, exist_ok=True) + copied: List[Path] = [] + for src in noon_dir.iterdir(): + if not src.is_file() or src.suffix.lower() != ".pcx": + continue + dst = label_dir / src.name + shutil.copy2(src, dst) + copied.append(dst) + return copied + + +def label_to_hour_value(label: str) -> float: + """Convert 'HHMM' or '2400' to hour value (fractional hours).""" + if label == "2400": + return 0.0 + h = int(label[:2]) + m = int(label[2:]) + return (h % 24) + (m / 60.0) + + +def process_time_label( + label: str, + base_dir: Path, + noon_label: str, + reserved_colors: Iterable[Tuple[int, int, int]], + *, + do_index_remap: bool, + # look controls... + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sat_boost: float, + contrast: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, + # noon neutral controls... + noon_blend: float, + noon_sigma: float, + noon_window_start: float, + noon_window_end: float, + noon_window_soft: float, +) -> None: + noon_dir = base_dir / noon_label + out_dir = base_dir / label + hour_value = label_to_hour_value(label) + + copied_files = copy_noon_to_label(noon_dir, out_dir) + + for pcx_path in copied_files: + with Image.open(pcx_path) as im: + if im.mode != "P": + im = im.convert("P") + pal = get_palette(im) + + # Optional green→magenta pixel remap AND remove green from palette (set to black) + if do_index_remap: + im = remap_all_green_to_magenta_and_blacken_palette(im, pal) + + effective_reserved_colors: List[Tuple[int, int, int]] = list(reserved_colors) + reserved_by_color_rgbs = set(effective_reserved_colors) + + # Initialize to empty for non-EntertainmentComplex files + reserved_idx: Set[int] = set() + + # If this is an Entertainment Complex, protect EXACT pixels by duplicating indices + if "EntertainmentComplex" in pcx_path.name and is_night_hour(24 if int(hour_value) == 0 else int(hour_value)): + ranges = PROTECTED_RANGES_ENT_COMPLEX + ranges = _bridge_small_gaps(ranges, PROTECTED_GAP_BRIDGE) + reserved_idx = _protect_exact_pixels_by_index( + im, pal, ranges, reserved_by_color_rgbs=reserved_by_color_rgbs + ) + + new_pal = adjust_palette_for_time( + pal, hour_value, effective_reserved_colors, + reserved_indices=reserved_idx, + warmth_scale=warmth_scale, + blue_scale=blue_scale, + darkness_scale=darkness_scale, + desat_scale=desat_scale, + sat_boost=sat_boost, + contrast=contrast, + sunrise_center=sunrise_center, + sunset_center=sunset_center, + twilight_sigma=twilight_sigma, + noon_blend=noon_blend, + noon_sigma=noon_sigma, + noon_window_start=noon_window_start, + noon_window_end=noon_window_end, + noon_window_soft=noon_window_soft, + ) + + set_palette(im, new_pal) + im.save(pcx_path, format="PCX") + + +# --------------------------- Main --------------------------- + +def main(): + p = argparse.ArgumentParser(description="Civ3 PCX day/night generator with variable time steps and noon-neutral zone.") + p.add_argument("--data", required=True, + help="Parent folder containing the noon folder and sibling time folders (e.g., NightDay).") + p.add_argument("--noon", default="1200", + help="Name of the noon folder (default: 1200).") + p.add_argument("--only-hour", default=None, + help="Process only a single time label (e.g., 1900, 1930, or 2400).") + p.add_argument("--step-minutes", type=int, default=60, + help="Time step in minutes; must divide 60 (e.g., 5,10,15,20,30,60). Default: 60.") + + p.add_argument("--light-key", action="append", default=[], + help="Reserved color that must not change. Repeatable. '#RRGGBB' or 'R,G,B'.") + + # Look/feel controls + p.add_argument("--warmth", type=float, default=1.10, + help="Scale for sunrise/sunset warmth (1.0 = base).") + p.add_argument("--blue", type=float, default=1.12, + help="Scale for night-time blue emphasis (1.0 = base).") + p.add_argument("--darkness", type=float, default=1.08, + help="Scale for extra night darkening (1.0 = base).") + p.add_argument("--desat", type=float, default=0.85, + help="Scale for dusk/night desaturation toward gray (lower = richer).") + p.add_argument("--sat", type=float, default=1.05, + help="Global saturation multiplier after tint (1.0 = none).") + p.add_argument("--contrast", type=float, default=1.03, + help="Global contrast multiplier around mid 128 (1.0 = none).") + + # Curve placement/width + p.add_argument("--sunrise-center", type=float, default=6.0, + help="Hour center for sunrise warmth bump (0-23).") + p.add_argument("--sunset-center", type=float, default=18.0, + help="Hour center for sunset warmth bump (0-23).") + p.add_argument("--twilight-width", type=float, default=1.8, + help="Sigma for sunrise/sunset warmth spread (higher = broader).") + + # Noon-neutral zone controls + p.add_argument("--noon-blend", type=float, default=1.0, + help="0..1 strength to blend toward base palette near 12:00 (0=off).") + p.add_argument("--noon-sigma", type=float, default=1.1, + help="Gaussian width (hours) around 12:00 (larger = broader).") + p.add_argument("--noon-window-start", type=float, default=10.0, + help="Start hour of the noon-like window (default 10.0).") + p.add_argument("--noon-window-end", type=float, default=14.0, + help="End hour of the noon-like window (default 14.0).") + p.add_argument("--noon-window-soft", type=float, default=0.7, + help="Soft edge (hours) for window ramps (0=hard).") + + # Index remap control + g = p.add_mutually_exclusive_group() + g.add_argument("--keep-green-index", action="store_true", + help="Do NOT remap green pixels to magenta; also do NOT remove #00FF00 from the palette.") + g.add_argument("--map-green-index", dest="map_green_index", action="store_true", + help="Force remap green pixels to magenta and replace any #00FF00 palette entries with black (default behavior).") + + args = p.parse_args() + + base_dir = Path(args.data).expanduser().resolve() + noon_dir = base_dir / args.noon + if not noon_dir.is_dir(): + raise SystemExit(f"Noon folder not found: {noon_dir}") + + # Reserved colors: + # - Magenta is kept stable + # - Green is NOT reserved anymore because we remove it from the palette when remapping is enabled + reserved: List[Tuple[int, int, int]] = [(255, 0, 255)] + for s in args.light_key: + reserved.append(parse_rgb(s)) + + # Determine remap behavior (default ON) + do_index_remap = not args.keep_green_index or args.map_green_index + + labels = [lbl for lbl in time_labels(args.step_minutes) if lbl != args.noon] + + # only-hour (accept 0000 -> 2400) + if args.only_hour: + only = "2400" if args.only_hour == "0000" else args.only_hour + if only == args.noon: + print(f"--only-hour {only} is the noon source; nothing to do.") + return + if only not in labels: + raise SystemExit(f"--only-hour must be one of: {', '.join(labels)}") + labels = [only] + + print(f"Base: {base_dir}") + print(f"Noon source: {noon_dir}") + print(f"Time step: {args.step_minutes} minutes") + print(f"Green pixels→magenta + remove #00FF00 from palette: {'ON' if do_index_remap else 'OFF'}") + print(f"Generating labels: {', '.join(labels)}") + + for lbl in labels: + print(f" -> Generating {lbl} ...") + process_time_label( + lbl, base_dir, args.noon, reserved, + do_index_remap=do_index_remap, + warmth_scale=args.warmth, + blue_scale=args.blue, + darkness_scale=args.darkness, + desat_scale=args.desat, + sat_boost=args.sat, + contrast=args.contrast, + sunrise_center=args.sunrise_center, + sunset_center=args.sunset_center, + twilight_sigma=args.twilight_width, + noon_blend=args.noon_blend, + noon_sigma=args.noon_sigma, + noon_window_start=args.noon_window_start, + noon_window_end=args.noon_window_end, + noon_window_soft=args.noon_window_soft, + ) + + print("Done.") + + +if __name__ == "__main__": + main() diff --git a/DayNight/civ3_day_night_orig.py b/DayNight/civ3_day_night_orig.py index 81bd1805..10ee2ab6 100644 --- a/DayNight/civ3_day_night_orig.py +++ b/DayNight/civ3_day_night_orig.py @@ -1,602 +1,602 @@ -#!/usr/bin/env python3 -""" -civ3_daynight_pcx.py — v4.3 (stronger nighttime blue + stable noon-neutral zone) - -Highlights: -- Half-hour (or any divisor of an hour) time slices via --step-minutes. -- Green→Magenta index remap (on by default). -- Palette-only tinting; indices preserved (except the optional index remap). -- Noon-neutral zone keeps ~10:00–14:00 close to base 1200. -- NEW: Stronger nighttime blue response using the existing --blue knob, - with an additional night-only hue shift (blue up, red/green down). - -Tested knobs (your current favorites work unchanged): - --warmth 1.05 --blue 2.0 --darkness 1.1 --desat 0.85 --sat 1.2 --contrast 1.08 - --sunrise-center 5.0 --sunset-center 18.0 --twilight-width 3.0 - --noon-blend 0.7 --noon-sigma 1.0 -""" - -import argparse -import shutil -from pathlib import Path -from typing import Iterable, List, Sequence, Tuple - -from PIL import Image - - -# --------------------------- CLI & helpers --------------------------- - -def parse_rgb(s: str) -> Tuple[int, int, int]: - s = s.strip() - if s.startswith("#"): - s = s[1:] - if len(s) != 6: - raise ValueError(f"Bad hex color: #{s}") - return tuple(int(s[i:i+2], 16) for i in (0, 2, 4)) # type: ignore - if "," in s: - parts = [p.strip() for p in s.split(",")] - if len(parts) != 3: - raise ValueError(f"Bad RGB list: {s}") - return tuple(int(p) for p in parts) # type: ignore - raise ValueError(f"Unrecognized color format: {s}") - - -def time_labels(step_minutes: int) -> List[str]: - """ - Generate HHMM labels from step to 23:59 stepwise; exclude 0000; add 2400. - For step=60: 0100..2300 + 2400 - For step=30: 0030, 0100, 0130..2330 + 2400 - """ - if step_minutes <= 0 or 60 % step_minutes != 0: - raise ValueError("--step-minutes must be a positive divisor of 60 (e.g., 5,10,15,20,30,60).") - labels: List[str] = [] - total_minutes = 24 * 60 - m = step_minutes - while m < total_minutes: - h = m // 60 - mm = m % 60 - labels.append(f"{h:02d}{mm:02d}") - m += step_minutes - labels.append("2400") - return labels - - -def clamp_byte(x: float) -> int: - return int(max(0, min(255, round(x)))) - - -# --------------------------- TONEMAP MODEL --------------------------- - -def _gauss(x: float, mu: float, sigma: float) -> float: - from math import exp - if sigma <= 0.0: - return 0.0 - return exp(-0.5 * ((x - mu) / sigma) ** 2) - - -def hour_adjustments( - hour_value: float, - *, - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, -) -> dict: - """ - hour_value can be fractional (e.g., 19.5 for 19:30). Period is 24h. - Returns a dict with per-channel multipliers, gray blend, brightness, - and 'night' + 'blue_push' factors for night-only hue shift. - """ - from math import cos, pi - - h = hour_value % 24.0 - - # Daylight (cosine): 1 at noon, ~0 at midnight - daylight = max(0.0, cos(pi * (h - 12.0) / 12.0)) # 0..1 - night = 1.0 - daylight - - # Warmth around sunrise/sunset - warmth = 0.85 * (_gauss(h, sunrise_center, twilight_sigma) + - _gauss(h, sunset_center, twilight_sigma)) - warmth *= warmth_scale - - # Brightness: darker at night; scaled by darkness_scale (>1 = darker nights) - base_brightness = 0.60 + 0.40 * daylight - night_darkening = 1.0 - (0.12 * (darkness_scale - 1.0) * night) - brightness = base_brightness * night_darkening - - # Channel multipliers - r_mul = 0.97 + 0.12 * daylight + 0.30 * warmth - g_mul = 0.97 + 0.12 * daylight + 0.12 * warmth - b_mul = 0.97 + 0.12 * daylight - 0.18 * warmth + (0.28 * blue_scale) * night - - # Desaturation (toward gray) stronger at night; scaled by desat_scale - gray_blend = (0.10 + 0.50 * night) * desat_scale - gray_blend = min(max(gray_blend, 0.0), 0.85) - - # Night-only blue push factor (extra hue shift at night) - # - grows with (blue_scale - 1) and with 'night' - # - kept separate from b_mul so daytime remains unchanged - blue_push = max(0.0, blue_scale - 1.0) * night # 0 at day, up to (blue-1) at night - - # Clamp gentle bounds - r_mul = min(max(r_mul, 0.65), 1.45) - g_mul = min(max(g_mul, 0.65), 1.40) - b_mul = min(max(b_mul, 0.65), 1.55) - - return dict( - brightness=brightness, - r_mul=r_mul, - g_mul=g_mul, - b_mul=b_mul, - gray_blend=gray_blend, - night=night, - blue_push=blue_push, - ) - - -def _apply_saturation(rgb: Tuple[float, float, float], sat: float) -> Tuple[float, float, float]: - r, g, b = rgb - gray = (r + g + b) / 3.0 - r = gray + (r - gray) * sat - g = gray + (g - gray) * sat - b = gray + (b - gray) * sat - return r, g, b - - -def _apply_contrast(rgb: Tuple[float, float, float], contrast: float) -> Tuple[float, float, float]: - r, g, b = rgb - r = 128 + (r - 128) * contrast - g = 128 + (g - 128) * contrast - b = 128 + (b - 128) * contrast - return r, g, b - - -def _apply_night_blue_push( - rgb: Tuple[float, float, float], - blue_push: float, -) -> Tuple[float, float, float]: - """ - Extra night-only hue shift: - - Slightly reduces R and G - - Increases B - 'blue_push' is ~ (blue_scale - 1) * night, so this is zero in daytime. - Coefficients tuned to be visible but not cartoonish; adjust if needed. - """ - if blue_push <= 0.0: - return rgb - r, g, b = rgb - c = blue_push # c in [0..(blue-1)] scaled by night - # Gentle but noticeable: at c=1 (e.g., --blue 2.0 at full night) - r *= (1.0 - 0.15 * c) - g *= (1.0 - 0.10 * c) - b *= (1.0 + 0.35 * c) - return r, g, b - - -def tint_rgb( - rgb: Tuple[int, int, int], - params: dict, - *, - sat_boost: float, - contrast: float, -) -> Tuple[int, int, int]: - r, g, b = rgb - r_f = r * params["r_mul"] * params["brightness"] - g_f = g * params["g_mul"] * params["brightness"] - b_f = b * params["b_mul"] * params["brightness"] - - gray = (r_f + g_f + b_f) / 3.0 - t = params["gray_blend"] - r_f = (1 - t) * r_f + t * gray - g_f = (1 - t) * g_f + t * gray - b_f = (1 - t) * b_f + t * gray - - # Global saturation, then extra night-only blue hue push, then contrast - r_f, g_f, b_f = _apply_saturation((r_f, g_f, b_f), sat_boost) - r_f, g_f, b_f = _apply_night_blue_push((r_f, g_f, b_f), params.get("blue_push", 0.0)) - r_f, g_f, b_f = _apply_contrast((r_f, g_f, b_f), contrast) - - return (clamp_byte(r_f), clamp_byte(g_f), clamp_byte(b_f)) - - -# --------------------------- Noon-neutral weighting --------------------------- - -def _smoothstep01(t: float) -> float: - """Cubic smoothstep on [0,1].""" - if t <= 0.0: - return 0.0 - if t >= 1.0: - return 1.0 - return t * t * (3.0 - 2.0 * t) - - -def _interval_membership(x: float, a: float, b: float, soft: float) -> float: - """ - Smooth membership of time-of-day x (0..24) inside interval [a,b] (hours), - with soft edge width 'soft' (hours). Supports wrapped intervals (a>b). - Returns 0..1. - """ - x = x % 24.0 - a = a % 24.0 - b = b % 24.0 - soft = max(0.0, soft) - - def segment_membership(x: float, s: float, e: float, soft: float) -> float: - # Non-wrapped segment s <= e in [0,24] - if soft <= 0.0: - return 1.0 if (s <= x <= e) else 0.0 - - # Left ramp [s-soft, s] - if s - soft <= x < s: - t = (x - (s - soft)) / soft # 0..1 - return _smoothstep01(t) - - # Core [s, e] - if s <= x <= e: - return 1.0 - - # Right ramp [e, e+soft] - if e < x <= e + soft: - t = (x - e) / soft # 0..1 - return 1.0 - _smoothstep01(t) - - return 0.0 - - if a <= b: - return segment_membership(x, a, b, soft) - else: - # Wrapped interval: union of [a,24) and [0,b] - m1 = segment_membership(x, a, 24.0, soft) - m2 = segment_membership(x, 0.0, b, soft) - return max(m1, m2) - - -def _noon_weight(hour_value: float, blend: float, sigma: float, - w_start: float, w_end: float, w_soft: float) -> float: - """ - Combined noon weight in 0..1: - - Gaussian around 12:00 with width 'sigma' (hours), scaled by 'blend'. - - Smooth interval window [w_start, w_end] with soft edges 'w_soft', - also scaled by 'blend'. - - The final weight is max of both components, clamped 0..1. - """ - try: - h = hour_value % 24.0 - except Exception: - h = 0.0 - blend = float(blend) if blend is not None else 0.0 - sigma = float(sigma) if sigma is not None else 0.0 - w_start = float(w_start) if w_start is not None else 10.0 - w_end = float(w_end) if w_end is not None else 14.0 - w_soft = max(0.0, float(w_soft) if w_soft is not None else 0.7) - - if blend <= 0.0: - return 0.0 - - # Gaussian around noon - from math import exp - d = abs(h - 12.0) - d = min(d, 24.0 - d) - g = exp(-0.5 * (d / sigma) ** 2) if sigma > 0.0 else 0.0 - g *= blend - - # Smooth window - window_m = _interval_membership(h, w_start, w_end, w_soft) * blend - - w = max(g, window_m) - if w < 0.0: - return 0.0 - if w > 1.0: - return 1.0 - return w - - -# --------------------------- Palette helpers --------------------------- - -def get_palette(img: Image.Image) -> List[int]: - pal = img.getpalette() - if pal is None: - raise ValueError("Image has no palette (mode must be 'P').") - if len(pal) < 256 * 3: - pal = pal + [0] * (256 * 3 - len(pal)) - return pal[:256 * 3] - - -def set_palette(img: Image.Image, pal: Sequence[int]) -> None: - if len(pal) != 256 * 3: - raise ValueError("Palette must be exactly 256*3 entries.") - img.putpalette(list(pal)) - - -def find_color_index(pal: Sequence[int], color: Tuple[int, int, int]) -> int: - cr, cg, cb = color - for i in range(256): - r, g, b = pal[3*i:3*i+3] - if r == cr and g == cg and b == cb: - return i - return -1 - - -# --------------------------- Core operations --------------------------- - -def adjust_palette_for_time( - pal: List[int], - hour_value: float, - reserved_colors: Iterable[Tuple[int, int, int]], - *, - # look controls - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sat_boost: float, - contrast: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, - # noon neutral zone controls - noon_blend: float, - noon_sigma: float, - noon_window_start: float, - noon_window_end: float, - noon_window_soft: float, -) -> List[int]: - params = hour_adjustments( - hour_value, - warmth_scale=warmth_scale, - blue_scale=blue_scale, - darkness_scale=darkness_scale, - desat_scale=desat_scale, - sunrise_center=sunrise_center, - sunset_center=sunset_center, - twilight_sigma=twilight_sigma, - ) - reserved = set(reserved_colors) - - # Noon weight (0..1): stronger near 10:00–14:00, peak at 12:00 - noon_w = _noon_weight( - hour_value, noon_blend, noon_sigma, - noon_window_start, noon_window_end, noon_window_soft - ) - - # Damp sat/contrast near noon to avoid “pop” - sat_eff = 1.0 + (sat_boost - 1.0) * (1.0 - noon_w) - contrast_eff = 1.0 + (contrast - 1.0) * (1.0 - noon_w) - - out = pal[:] # copy - for i in range(256): - r, g, b = pal[3 * i:3 * i + 3] - rgb = (r, g, b) - - if rgb in reserved: - out[3 * i + 0] = r - out[3 * i + 1] = g - out[3 * i + 2] = b - continue - - nr, ng, nb = tint_rgb(rgb, params, sat_boost=sat_eff, contrast=contrast_eff) - - if noon_w > 0.0: - # Blend back toward the original (noon) palette color at the SAME index - nr = int(round((1.0 - noon_w) * nr + noon_w * r)) - ng = int(round((1.0 - noon_w) * ng + noon_w * g)) - nb = int(round((1.0 - noon_w) * nb + noon_w * b)) - - out[3 * i + 0] = nr - out[3 * i + 1] = ng - out[3 * i + 2] = nb - - return out - - -def remap_green_to_magenta_indices(img: Image.Image, pal: Sequence[int]) -> Image.Image: - green_idx = find_color_index(pal, (0, 255, 0)) - magenta_idx = find_color_index(pal, (255, 0, 255)) - if green_idx < 0 or magenta_idx < 0 or green_idx == magenta_idx: - return img - lut = [magenta_idx if i == green_idx else i for i in range(256)] - return img.point(lut, mode="P") - - -# --------------------------- File ops --------------------------- - -def copy_noon_to_label(noon_dir: Path, label_dir: Path) -> List[Path]: - label_dir.mkdir(parents=True, exist_ok=True) - copied: List[Path] = [] - for src in noon_dir.glob("*.pcx"): - dst = label_dir / src.name - shutil.copy2(src, dst) - copied.append(dst) - return copied - - -def label_to_hour_value(label: str) -> float: - """Convert 'HHMM' or '2400' to hour value (fractional hours).""" - if label == "2400": - return 0.0 - h = int(label[:2]) - m = int(label[2:]) - return (h % 24) + (m / 60.0) - - -def process_time_label( - label: str, - base_dir: Path, - noon_label: str, - reserved_colors: Iterable[Tuple[int, int, int]], - *, - do_index_remap: bool, - # look controls - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sat_boost: float, - contrast: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, - # noon neutral controls - noon_blend: float, - noon_sigma: float, - noon_window_start: float, - noon_window_end: float, - noon_window_soft: float, -) -> None: - noon_dir = base_dir / noon_label - out_dir = base_dir / label - hour_value = label_to_hour_value(label) - - copied_files = copy_noon_to_label(noon_dir, out_dir) - - for pcx_path in copied_files: - with Image.open(pcx_path) as im: - if im.mode != "P": - im = im.convert("P") - pal = get_palette(im) - - if do_index_remap: - im = remap_green_to_magenta_indices(im, pal) - - new_pal = adjust_palette_for_time( - pal, hour_value, reserved_colors, - warmth_scale=warmth_scale, - blue_scale=blue_scale, - darkness_scale=darkness_scale, - desat_scale=desat_scale, - sat_boost=sat_boost, - contrast=contrast, - sunrise_center=sunrise_center, - sunset_center=sunset_center, - twilight_sigma=twilight_sigma, - noon_blend=noon_blend, - noon_sigma=noon_sigma, - noon_window_start=noon_window_start, - noon_window_end=noon_window_end, - noon_window_soft=noon_window_soft, - ) - set_palette(im, new_pal) - im.save(pcx_path, format="PCX") - - -# --------------------------- Main --------------------------- - -def main(): - p = argparse.ArgumentParser(description="Civ3 PCX day/night generator with variable time steps and noon-neutral zone.") - p.add_argument("--data", required=True, - help="Parent folder containing the noon folder and sibling time folders (e.g., NightDay).") - p.add_argument("--noon", default="1200", - help="Name of the noon folder (default: 1200).") - p.add_argument("--only-hour", default=None, - help="Process only a single time label (e.g., 1900, 1930, or 2400).") - p.add_argument("--step-minutes", type=int, default=60, - help="Time step in minutes; must divide 60 (e.g., 5,10,15,20,30,60). Default: 60.") - - p.add_argument("--light-key", action="append", default=[], - help="Reserved color that must not change. Repeatable. '#RRGGBB' or 'R,G,B'.") - - # Look/feel controls - p.add_argument("--warmth", type=float, default=1.10, - help="Scale for sunrise/sunset warmth (1.0 = base).") - p.add_argument("--blue", type=float, default=1.12, - help="Scale for night-time blue emphasis (1.0 = base).") - p.add_argument("--darkness", type=float, default=1.08, - help="Scale for extra night darkening (1.0 = base).") - p.add_argument("--desat", type=float, default=0.85, - help="Scale for dusk/night desaturation toward gray (lower = richer).") - p.add_argument("--sat", type=float, default=1.05, - help="Global saturation multiplier after tint (1.0 = none).") - p.add_argument("--contrast", type=float, default=1.03, - help="Global contrast multiplier around mid 128 (1.0 = none).") - - # Curve placement/width - p.add_argument("--sunrise-center", type=float, default=6.0, - help="Hour center for sunrise warmth bump (0-23).") - p.add_argument("--sunset-center", type=float, default=18.0, - help="Hour center for sunset warmth bump (0-23).") - p.add_argument("--twilight-width", type=float, default=1.8, - help="Sigma for sunrise/sunset warmth spread (higher = broader).") - - # Noon-neutral zone controls (defaults keep ~10:00–14:00 close to noon) - p.add_argument("--noon-blend", type=float, default=0.85, - help="0..1 strength to blend toward base palette near 12:00 (0=off).") - p.add_argument("--noon-sigma", type=float, default=1.1, - help="Gaussian width (hours) around 12:00 (larger = broader).") - p.add_argument("--noon-window-start", type=float, default=10.0, - help="Start hour of the noon-like window (default 10.0).") - p.add_argument("--noon-window-end", type=float, default=14.0, - help="End hour of the noon-like window (default 14.0).") - p.add_argument("--noon-window-soft", type=float, default=0.7, - help="Soft edge (hours) for window ramps (0=hard).") - - # Index remap control - g = p.add_mutually_exclusive_group() - g.add_argument("--keep-green-index", action="store_true", - help="Do NOT remap green index to magenta; leave pixel indices unchanged.") - g.add_argument("--map-green-index", dest="map_green_index", action="store_true", - help="Force remap green index to magenta (default behavior).") - - args = p.parse_args() - - base_dir = Path(args.data).expanduser().resolve() - noon_dir = base_dir / args.noon - if not noon_dir.is_dir(): - raise SystemExit(f"Noon folder not found: {noon_dir}") - - # Reserved colors (Magenta + Green + user light-keys) - reserved: List[Tuple[int, int, int]] = [(255, 0, 255), (0, 255, 0)] - for s in args.light_key: - reserved.append(parse_rgb(s)) - - # Determine remap behavior (default ON) - do_index_remap = not args.keep_green_index or args.map_green_index - - # Build time labels for the given step, then exclude noon folder itself - labels = [lbl for lbl in time_labels(args.step_minutes) if lbl != args.noon] - - # only-hour (accept 0000 -> 2400) - if args.only_hour: - only = "2400" if args.only_hour == "0000" else args.only_hour - if only == args.noon: - print(f"--only-hour {only} is the noon source; nothing to do.") - return - if only not in labels: - raise SystemExit(f"--only-hour must be one of: {', '.join(labels)}") - labels = [only] - - print(f"Base: {base_dir}") - print(f"Noon source: {noon_dir}") - print(f"Time step: {args.step_minutes} minutes") - print(f"Index remap green→magenta: {'ON' if do_index_remap else 'OFF'}") - print(f"Generating labels: {', '.join(labels)}") - - for lbl in labels: - print(f" -> Generating {lbl} ...") - process_time_label( - lbl, base_dir, args.noon, reserved, - do_index_remap=do_index_remap, - warmth_scale=args.warmth, - blue_scale=args.blue, - darkness_scale=args.darkness, - desat_scale=args.desat, - sat_boost=args.sat, - contrast=args.contrast, - sunrise_center=args.sunrise_center, - sunset_center=args.sunset_center, - twilight_sigma=args.twilight_width, - noon_blend=args.noon_blend, - noon_sigma=args.noon_sigma, - noon_window_start=args.noon_window_start, - noon_window_end=args.noon_window_end, - noon_window_soft=args.noon_window_soft, - ) - - print("Done.") - - -if __name__ == "__main__": +#!/usr/bin/env python3 +""" +civ3_daynight_pcx.py — v4.3 (stronger nighttime blue + stable noon-neutral zone) + +Highlights: +- Half-hour (or any divisor of an hour) time slices via --step-minutes. +- Green→Magenta index remap (on by default). +- Palette-only tinting; indices preserved (except the optional index remap). +- Noon-neutral zone keeps ~10:00–14:00 close to base 1200. +- NEW: Stronger nighttime blue response using the existing --blue knob, + with an additional night-only hue shift (blue up, red/green down). + +Tested knobs (your current favorites work unchanged): + --warmth 1.05 --blue 2.0 --darkness 1.1 --desat 0.85 --sat 1.2 --contrast 1.08 + --sunrise-center 5.0 --sunset-center 18.0 --twilight-width 3.0 + --noon-blend 0.7 --noon-sigma 1.0 +""" + +import argparse +import shutil +from pathlib import Path +from typing import Iterable, List, Sequence, Tuple + +from PIL import Image + + +# --------------------------- CLI & helpers --------------------------- + +def parse_rgb(s: str) -> Tuple[int, int, int]: + s = s.strip() + if s.startswith("#"): + s = s[1:] + if len(s) != 6: + raise ValueError(f"Bad hex color: #{s}") + return tuple(int(s[i:i+2], 16) for i in (0, 2, 4)) # type: ignore + if "," in s: + parts = [p.strip() for p in s.split(",")] + if len(parts) != 3: + raise ValueError(f"Bad RGB list: {s}") + return tuple(int(p) for p in parts) # type: ignore + raise ValueError(f"Unrecognized color format: {s}") + + +def time_labels(step_minutes: int) -> List[str]: + """ + Generate HHMM labels from step to 23:59 stepwise; exclude 0000; add 2400. + For step=60: 0100..2300 + 2400 + For step=30: 0030, 0100, 0130..2330 + 2400 + """ + if step_minutes <= 0 or 60 % step_minutes != 0: + raise ValueError("--step-minutes must be a positive divisor of 60 (e.g., 5,10,15,20,30,60).") + labels: List[str] = [] + total_minutes = 24 * 60 + m = step_minutes + while m < total_minutes: + h = m // 60 + mm = m % 60 + labels.append(f"{h:02d}{mm:02d}") + m += step_minutes + labels.append("2400") + return labels + + +def clamp_byte(x: float) -> int: + return int(max(0, min(255, round(x)))) + + +# --------------------------- TONEMAP MODEL --------------------------- + +def _gauss(x: float, mu: float, sigma: float) -> float: + from math import exp + if sigma <= 0.0: + return 0.0 + return exp(-0.5 * ((x - mu) / sigma) ** 2) + + +def hour_adjustments( + hour_value: float, + *, + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, +) -> dict: + """ + hour_value can be fractional (e.g., 19.5 for 19:30). Period is 24h. + Returns a dict with per-channel multipliers, gray blend, brightness, + and 'night' + 'blue_push' factors for night-only hue shift. + """ + from math import cos, pi + + h = hour_value % 24.0 + + # Daylight (cosine): 1 at noon, ~0 at midnight + daylight = max(0.0, cos(pi * (h - 12.0) / 12.0)) # 0..1 + night = 1.0 - daylight + + # Warmth around sunrise/sunset + warmth = 0.85 * (_gauss(h, sunrise_center, twilight_sigma) + + _gauss(h, sunset_center, twilight_sigma)) + warmth *= warmth_scale + + # Brightness: darker at night; scaled by darkness_scale (>1 = darker nights) + base_brightness = 0.60 + 0.40 * daylight + night_darkening = 1.0 - (0.12 * (darkness_scale - 1.0) * night) + brightness = base_brightness * night_darkening + + # Channel multipliers + r_mul = 0.97 + 0.12 * daylight + 0.30 * warmth + g_mul = 0.97 + 0.12 * daylight + 0.12 * warmth + b_mul = 0.97 + 0.12 * daylight - 0.18 * warmth + (0.28 * blue_scale) * night + + # Desaturation (toward gray) stronger at night; scaled by desat_scale + gray_blend = (0.10 + 0.50 * night) * desat_scale + gray_blend = min(max(gray_blend, 0.0), 0.85) + + # Night-only blue push factor (extra hue shift at night) + # - grows with (blue_scale - 1) and with 'night' + # - kept separate from b_mul so daytime remains unchanged + blue_push = max(0.0, blue_scale - 1.0) * night # 0 at day, up to (blue-1) at night + + # Clamp gentle bounds + r_mul = min(max(r_mul, 0.65), 1.45) + g_mul = min(max(g_mul, 0.65), 1.40) + b_mul = min(max(b_mul, 0.65), 1.55) + + return dict( + brightness=brightness, + r_mul=r_mul, + g_mul=g_mul, + b_mul=b_mul, + gray_blend=gray_blend, + night=night, + blue_push=blue_push, + ) + + +def _apply_saturation(rgb: Tuple[float, float, float], sat: float) -> Tuple[float, float, float]: + r, g, b = rgb + gray = (r + g + b) / 3.0 + r = gray + (r - gray) * sat + g = gray + (g - gray) * sat + b = gray + (b - gray) * sat + return r, g, b + + +def _apply_contrast(rgb: Tuple[float, float, float], contrast: float) -> Tuple[float, float, float]: + r, g, b = rgb + r = 128 + (r - 128) * contrast + g = 128 + (g - 128) * contrast + b = 128 + (b - 128) * contrast + return r, g, b + + +def _apply_night_blue_push( + rgb: Tuple[float, float, float], + blue_push: float, +) -> Tuple[float, float, float]: + """ + Extra night-only hue shift: + - Slightly reduces R and G + - Increases B + 'blue_push' is ~ (blue_scale - 1) * night, so this is zero in daytime. + Coefficients tuned to be visible but not cartoonish; adjust if needed. + """ + if blue_push <= 0.0: + return rgb + r, g, b = rgb + c = blue_push # c in [0..(blue-1)] scaled by night + # Gentle but noticeable: at c=1 (e.g., --blue 2.0 at full night) + r *= (1.0 - 0.15 * c) + g *= (1.0 - 0.10 * c) + b *= (1.0 + 0.35 * c) + return r, g, b + + +def tint_rgb( + rgb: Tuple[int, int, int], + params: dict, + *, + sat_boost: float, + contrast: float, +) -> Tuple[int, int, int]: + r, g, b = rgb + r_f = r * params["r_mul"] * params["brightness"] + g_f = g * params["g_mul"] * params["brightness"] + b_f = b * params["b_mul"] * params["brightness"] + + gray = (r_f + g_f + b_f) / 3.0 + t = params["gray_blend"] + r_f = (1 - t) * r_f + t * gray + g_f = (1 - t) * g_f + t * gray + b_f = (1 - t) * b_f + t * gray + + # Global saturation, then extra night-only blue hue push, then contrast + r_f, g_f, b_f = _apply_saturation((r_f, g_f, b_f), sat_boost) + r_f, g_f, b_f = _apply_night_blue_push((r_f, g_f, b_f), params.get("blue_push", 0.0)) + r_f, g_f, b_f = _apply_contrast((r_f, g_f, b_f), contrast) + + return (clamp_byte(r_f), clamp_byte(g_f), clamp_byte(b_f)) + + +# --------------------------- Noon-neutral weighting --------------------------- + +def _smoothstep01(t: float) -> float: + """Cubic smoothstep on [0,1].""" + if t <= 0.0: + return 0.0 + if t >= 1.0: + return 1.0 + return t * t * (3.0 - 2.0 * t) + + +def _interval_membership(x: float, a: float, b: float, soft: float) -> float: + """ + Smooth membership of time-of-day x (0..24) inside interval [a,b] (hours), + with soft edge width 'soft' (hours). Supports wrapped intervals (a>b). + Returns 0..1. + """ + x = x % 24.0 + a = a % 24.0 + b = b % 24.0 + soft = max(0.0, soft) + + def segment_membership(x: float, s: float, e: float, soft: float) -> float: + # Non-wrapped segment s <= e in [0,24] + if soft <= 0.0: + return 1.0 if (s <= x <= e) else 0.0 + + # Left ramp [s-soft, s] + if s - soft <= x < s: + t = (x - (s - soft)) / soft # 0..1 + return _smoothstep01(t) + + # Core [s, e] + if s <= x <= e: + return 1.0 + + # Right ramp [e, e+soft] + if e < x <= e + soft: + t = (x - e) / soft # 0..1 + return 1.0 - _smoothstep01(t) + + return 0.0 + + if a <= b: + return segment_membership(x, a, b, soft) + else: + # Wrapped interval: union of [a,24) and [0,b] + m1 = segment_membership(x, a, 24.0, soft) + m2 = segment_membership(x, 0.0, b, soft) + return max(m1, m2) + + +def _noon_weight(hour_value: float, blend: float, sigma: float, + w_start: float, w_end: float, w_soft: float) -> float: + """ + Combined noon weight in 0..1: + - Gaussian around 12:00 with width 'sigma' (hours), scaled by 'blend'. + - Smooth interval window [w_start, w_end] with soft edges 'w_soft', + also scaled by 'blend'. + - The final weight is max of both components, clamped 0..1. + """ + try: + h = hour_value % 24.0 + except Exception: + h = 0.0 + blend = float(blend) if blend is not None else 0.0 + sigma = float(sigma) if sigma is not None else 0.0 + w_start = float(w_start) if w_start is not None else 10.0 + w_end = float(w_end) if w_end is not None else 14.0 + w_soft = max(0.0, float(w_soft) if w_soft is not None else 0.7) + + if blend <= 0.0: + return 0.0 + + # Gaussian around noon + from math import exp + d = abs(h - 12.0) + d = min(d, 24.0 - d) + g = exp(-0.5 * (d / sigma) ** 2) if sigma > 0.0 else 0.0 + g *= blend + + # Smooth window + window_m = _interval_membership(h, w_start, w_end, w_soft) * blend + + w = max(g, window_m) + if w < 0.0: + return 0.0 + if w > 1.0: + return 1.0 + return w + + +# --------------------------- Palette helpers --------------------------- + +def get_palette(img: Image.Image) -> List[int]: + pal = img.getpalette() + if pal is None: + raise ValueError("Image has no palette (mode must be 'P').") + if len(pal) < 256 * 3: + pal = pal + [0] * (256 * 3 - len(pal)) + return pal[:256 * 3] + + +def set_palette(img: Image.Image, pal: Sequence[int]) -> None: + if len(pal) != 256 * 3: + raise ValueError("Palette must be exactly 256*3 entries.") + img.putpalette(list(pal)) + + +def find_color_index(pal: Sequence[int], color: Tuple[int, int, int]) -> int: + cr, cg, cb = color + for i in range(256): + r, g, b = pal[3*i:3*i+3] + if r == cr and g == cg and b == cb: + return i + return -1 + + +# --------------------------- Core operations --------------------------- + +def adjust_palette_for_time( + pal: List[int], + hour_value: float, + reserved_colors: Iterable[Tuple[int, int, int]], + *, + # look controls + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sat_boost: float, + contrast: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, + # noon neutral zone controls + noon_blend: float, + noon_sigma: float, + noon_window_start: float, + noon_window_end: float, + noon_window_soft: float, +) -> List[int]: + params = hour_adjustments( + hour_value, + warmth_scale=warmth_scale, + blue_scale=blue_scale, + darkness_scale=darkness_scale, + desat_scale=desat_scale, + sunrise_center=sunrise_center, + sunset_center=sunset_center, + twilight_sigma=twilight_sigma, + ) + reserved = set(reserved_colors) + + # Noon weight (0..1): stronger near 10:00–14:00, peak at 12:00 + noon_w = _noon_weight( + hour_value, noon_blend, noon_sigma, + noon_window_start, noon_window_end, noon_window_soft + ) + + # Damp sat/contrast near noon to avoid “pop” + sat_eff = 1.0 + (sat_boost - 1.0) * (1.0 - noon_w) + contrast_eff = 1.0 + (contrast - 1.0) * (1.0 - noon_w) + + out = pal[:] # copy + for i in range(256): + r, g, b = pal[3 * i:3 * i + 3] + rgb = (r, g, b) + + if rgb in reserved: + out[3 * i + 0] = r + out[3 * i + 1] = g + out[3 * i + 2] = b + continue + + nr, ng, nb = tint_rgb(rgb, params, sat_boost=sat_eff, contrast=contrast_eff) + + if noon_w > 0.0: + # Blend back toward the original (noon) palette color at the SAME index + nr = int(round((1.0 - noon_w) * nr + noon_w * r)) + ng = int(round((1.0 - noon_w) * ng + noon_w * g)) + nb = int(round((1.0 - noon_w) * nb + noon_w * b)) + + out[3 * i + 0] = nr + out[3 * i + 1] = ng + out[3 * i + 2] = nb + + return out + + +def remap_green_to_magenta_indices(img: Image.Image, pal: Sequence[int]) -> Image.Image: + green_idx = find_color_index(pal, (0, 255, 0)) + magenta_idx = find_color_index(pal, (255, 0, 255)) + if green_idx < 0 or magenta_idx < 0 or green_idx == magenta_idx: + return img + lut = [magenta_idx if i == green_idx else i for i in range(256)] + return img.point(lut, mode="P") + + +# --------------------------- File ops --------------------------- + +def copy_noon_to_label(noon_dir: Path, label_dir: Path) -> List[Path]: + label_dir.mkdir(parents=True, exist_ok=True) + copied: List[Path] = [] + for src in noon_dir.glob("*.pcx"): + dst = label_dir / src.name + shutil.copy2(src, dst) + copied.append(dst) + return copied + + +def label_to_hour_value(label: str) -> float: + """Convert 'HHMM' or '2400' to hour value (fractional hours).""" + if label == "2400": + return 0.0 + h = int(label[:2]) + m = int(label[2:]) + return (h % 24) + (m / 60.0) + + +def process_time_label( + label: str, + base_dir: Path, + noon_label: str, + reserved_colors: Iterable[Tuple[int, int, int]], + *, + do_index_remap: bool, + # look controls + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sat_boost: float, + contrast: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, + # noon neutral controls + noon_blend: float, + noon_sigma: float, + noon_window_start: float, + noon_window_end: float, + noon_window_soft: float, +) -> None: + noon_dir = base_dir / noon_label + out_dir = base_dir / label + hour_value = label_to_hour_value(label) + + copied_files = copy_noon_to_label(noon_dir, out_dir) + + for pcx_path in copied_files: + with Image.open(pcx_path) as im: + if im.mode != "P": + im = im.convert("P") + pal = get_palette(im) + + if do_index_remap: + im = remap_green_to_magenta_indices(im, pal) + + new_pal = adjust_palette_for_time( + pal, hour_value, reserved_colors, + warmth_scale=warmth_scale, + blue_scale=blue_scale, + darkness_scale=darkness_scale, + desat_scale=desat_scale, + sat_boost=sat_boost, + contrast=contrast, + sunrise_center=sunrise_center, + sunset_center=sunset_center, + twilight_sigma=twilight_sigma, + noon_blend=noon_blend, + noon_sigma=noon_sigma, + noon_window_start=noon_window_start, + noon_window_end=noon_window_end, + noon_window_soft=noon_window_soft, + ) + set_palette(im, new_pal) + im.save(pcx_path, format="PCX") + + +# --------------------------- Main --------------------------- + +def main(): + p = argparse.ArgumentParser(description="Civ3 PCX day/night generator with variable time steps and noon-neutral zone.") + p.add_argument("--data", required=True, + help="Parent folder containing the noon folder and sibling time folders (e.g., NightDay).") + p.add_argument("--noon", default="1200", + help="Name of the noon folder (default: 1200).") + p.add_argument("--only-hour", default=None, + help="Process only a single time label (e.g., 1900, 1930, or 2400).") + p.add_argument("--step-minutes", type=int, default=60, + help="Time step in minutes; must divide 60 (e.g., 5,10,15,20,30,60). Default: 60.") + + p.add_argument("--light-key", action="append", default=[], + help="Reserved color that must not change. Repeatable. '#RRGGBB' or 'R,G,B'.") + + # Look/feel controls + p.add_argument("--warmth", type=float, default=1.10, + help="Scale for sunrise/sunset warmth (1.0 = base).") + p.add_argument("--blue", type=float, default=1.12, + help="Scale for night-time blue emphasis (1.0 = base).") + p.add_argument("--darkness", type=float, default=1.08, + help="Scale for extra night darkening (1.0 = base).") + p.add_argument("--desat", type=float, default=0.85, + help="Scale for dusk/night desaturation toward gray (lower = richer).") + p.add_argument("--sat", type=float, default=1.05, + help="Global saturation multiplier after tint (1.0 = none).") + p.add_argument("--contrast", type=float, default=1.03, + help="Global contrast multiplier around mid 128 (1.0 = none).") + + # Curve placement/width + p.add_argument("--sunrise-center", type=float, default=6.0, + help="Hour center for sunrise warmth bump (0-23).") + p.add_argument("--sunset-center", type=float, default=18.0, + help="Hour center for sunset warmth bump (0-23).") + p.add_argument("--twilight-width", type=float, default=1.8, + help="Sigma for sunrise/sunset warmth spread (higher = broader).") + + # Noon-neutral zone controls (defaults keep ~10:00–14:00 close to noon) + p.add_argument("--noon-blend", type=float, default=0.85, + help="0..1 strength to blend toward base palette near 12:00 (0=off).") + p.add_argument("--noon-sigma", type=float, default=1.1, + help="Gaussian width (hours) around 12:00 (larger = broader).") + p.add_argument("--noon-window-start", type=float, default=10.0, + help="Start hour of the noon-like window (default 10.0).") + p.add_argument("--noon-window-end", type=float, default=14.0, + help="End hour of the noon-like window (default 14.0).") + p.add_argument("--noon-window-soft", type=float, default=0.7, + help="Soft edge (hours) for window ramps (0=hard).") + + # Index remap control + g = p.add_mutually_exclusive_group() + g.add_argument("--keep-green-index", action="store_true", + help="Do NOT remap green index to magenta; leave pixel indices unchanged.") + g.add_argument("--map-green-index", dest="map_green_index", action="store_true", + help="Force remap green index to magenta (default behavior).") + + args = p.parse_args() + + base_dir = Path(args.data).expanduser().resolve() + noon_dir = base_dir / args.noon + if not noon_dir.is_dir(): + raise SystemExit(f"Noon folder not found: {noon_dir}") + + # Reserved colors (Magenta + Green + user light-keys) + reserved: List[Tuple[int, int, int]] = [(255, 0, 255), (0, 255, 0)] + for s in args.light_key: + reserved.append(parse_rgb(s)) + + # Determine remap behavior (default ON) + do_index_remap = not args.keep_green_index or args.map_green_index + + # Build time labels for the given step, then exclude noon folder itself + labels = [lbl for lbl in time_labels(args.step_minutes) if lbl != args.noon] + + # only-hour (accept 0000 -> 2400) + if args.only_hour: + only = "2400" if args.only_hour == "0000" else args.only_hour + if only == args.noon: + print(f"--only-hour {only} is the noon source; nothing to do.") + return + if only not in labels: + raise SystemExit(f"--only-hour must be one of: {', '.join(labels)}") + labels = [only] + + print(f"Base: {base_dir}") + print(f"Noon source: {noon_dir}") + print(f"Time step: {args.step_minutes} minutes") + print(f"Index remap green→magenta: {'ON' if do_index_remap else 'OFF'}") + print(f"Generating labels: {', '.join(labels)}") + + for lbl in labels: + print(f" -> Generating {lbl} ...") + process_time_label( + lbl, base_dir, args.noon, reserved, + do_index_remap=do_index_remap, + warmth_scale=args.warmth, + blue_scale=args.blue, + darkness_scale=args.darkness, + desat_scale=args.desat, + sat_boost=args.sat, + contrast=args.contrast, + sunrise_center=args.sunrise_center, + sunset_center=args.sunset_center, + twilight_sigma=args.twilight_width, + noon_blend=args.noon_blend, + noon_sigma=args.noon_sigma, + noon_window_start=args.noon_window_start, + noon_window_end=args.noon_window_end, + noon_window_soft=args.noon_window_soft, + ) + + print("Done.") + + +if __name__ == "__main__": main() \ No newline at end of file diff --git a/DayNight/civ3_postprocess_pixels.py b/DayNight/civ3_postprocess_pixels.py index eb8a26c0..c60ce452 100644 --- a/DayNight/civ3_postprocess_pixels.py +++ b/DayNight/civ3_postprocess_pixels.py @@ -1,280 +1,280 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -Civ3 post-process: remove GREEN (#00ff00) pixels from PCX outputs. - -Rules ------ -• Recursively scan under Data/*hour* folders (0100..2400 etc.), skipping the noon folder. -• Only touch files that have a corresponding "*_lights.pcx" in the same directory: - - For "NAME.pcx" → process only if "NAME_lights.pcx" exists. - - For "NAME_lights.pcx" → always process (it is the corresponding lights file). -• By default, only replace *isolated* green pixels: a green pixel whose neighbors within - --isolation-radius (default 1, i.e. the 8-connected ring) contain no other green pixels. -• With --remove-all-green, replace *all* green pixels. -• Replacement uses *neighbor palette indices* so the palette stays unchanged. - If no non-green neighbors exist, fall back to nearest palette color to local RGB average. - -Usage ------ - python civ3_fix_green.py --data ./Data --noon 1200 --verbose - # knobs: - # --isolation-radius 1 (1 = 8-neighborhood) - # --search-radius 3 - # --max-radius 5 - # --remove-all-green -""" - -import argparse, os, collections -from typing import Tuple, List, Set -from PIL import Image - -GREEN = (0, 255, 0) -MAGENTA = (255, 0, 255) - -# ---------- palette helpers ---------- - -def get_palette(im: Image.Image) -> List[int]: - pal = im.getpalette() or [] - if len(pal) < 256*3: - pal += [0]*(256*3 - len(pal)) - return pal[:256*3] - -def find_color_index(pal: List[int], rgb: Tuple[int,int,int]) -> int: - r,g,b = rgb - for i in range(256): - if pal[3*i] == r and pal[3*i+1] == g and pal[3*i+2] == b: - return i - return -1 - -def nearest_palette_index(target_rgb: Tuple[int,int,int], pal: List[int], banned: Set[int]) -> int: - """Choose the palette index (not in banned) whose RGB is nearest (Euclidean).""" - tr,tg,tb = target_rgb - best_i, best_d = None, 10**9 - for i in range(256): - if i in banned: continue - r,g,b = pal[3*i], pal[3*i+1], pal[3*i+2] - dr, dg, db = tr-r, tg-g, tb-b - d = dr*dr + dg*dg + db*db - if d < best_d: - best_d, best_i = d, i - return best_i if best_i is not None else 0 - -# ---------- neighborhood ops ---------- - -def has_green_neighbor(rgb_img: Image.Image, x: int, y: int, radius: int) -> bool: - """Return True if any neighbor within Chebyshev radius is GREEN (#00ff00).""" - w, h = rgb_img.size - px = rgb_img.load() - r = max(1, int(radius)) - for yy in range(max(0, y-r), min(h, y+r+1)): - for xx in range(max(0, x-r), min(w, x+r+1)): - if xx == x and yy == y: - continue - if px[xx,yy] == GREEN: - return True - return False - -def gather_neighbor_indices(idx_img: Image.Image, rgb_img: Image.Image, - x: int, y: int, radius: int, - green_idx: int, mag_idx: int) -> List[int]: - """Collect neighbor indices around (x,y) within Chebyshev radius; exclude green/magenta.""" - w, h = idx_img.size - px_idx = idx_img.load() - px_rgb = rgb_img.load() - out = [] - r = max(1, int(radius)) - for yy in range(max(0, y-r), min(h, y+r+1)): - for xx in range(max(0, x-r), min(w, x+r+1)): - if xx == x and yy == y: continue - i = px_idx[xx, yy] - r0,g0,b0 = px_rgb[xx, yy] - if (r0,g0,b0) == GREEN or (r0,g0,b0) == MAGENTA: - continue - if i == green_idx or i == mag_idx: - continue - out.append(i) - return out - -def local_average_rgb(rgb_img: Image.Image, x: int, y: int, radius: int, - skip_colors: Set[Tuple[int,int,int]]) -> Tuple[int,int,int]: - """Average RGB in a square window, skipping listed colors; falls back to (0,0,0).""" - w, h = rgb_img.size - px = rgb_img.load() - total = [0,0,0] - n = 0 - r = max(1, int(radius)) - for yy in range(max(0, y-r), min(h, y+r+1)): - for xx in range(max(0, x-r), min(w, x+r+1)): - c = px[xx, yy] - if c in skip_colors: - continue - total[0] += c[0]; total[1] += c[1]; total[2] += c[2] - n += 1 - if n == 0: - return (0,0,0) - return (total[0]//n, total[1]//n, total[2]//n) - -# ---------- core fixer ---------- - -def fix_green_in_image(path: str, isolation_radius: int, search_radius: int, max_radius: int, - remove_all_green: bool, verbose: bool=False) -> int: - """ - Returns number of pixels changed (only isolated greens are touched). - """ - try: - imP = Image.open(path) - except Exception: - return 0 - if imP.mode != 'P': - return 0 - - pal = get_palette(imP) - green_idx = find_color_index(pal, GREEN) - mag_idx = find_color_index(pal, MAGENTA) - - imRGB = imP.convert('RGB') - px = imRGB.load() - w, h = imRGB.size - - # Collect target green pixels - coords = [] - if remove_all_green: - for y in range(h): - for x in range(w): - if px[x, y] == GREEN: - coords.append((x, y)) - else: - for y in range(h): - for x in range(w): - if px[x, y] == GREEN and not has_green_neighbor(imRGB, x, y, isolation_radius): - coords.append((x, y)) - - if not coords: - return 0 - - outP = imP.copy() - out_px = outP.load() - banned_indices = set() - if green_idx != -1: banned_indices.add(green_idx) - if mag_idx != -1: banned_indices.add(mag_idx) - - changed = 0 - for (x,y) in coords: - if remove_all_green and mag_idx != -1: - out_px[x, y] = mag_idx - changed += 1 - continue - - picked_index = None - - # 1) Most frequent neighbor index (expand search out to max_radius if needed) - r = max(1, int(search_radius)) - m = max(r, int(max_radius)) - while r <= m and picked_index is None: - neigh = gather_neighbor_indices(imP, imRGB, x, y, r, green_idx, mag_idx) - if neigh: - cnt = collections.Counter(neigh) - picked_index = cnt.most_common(1)[0][0] - break - r += 1 - - # 2) Fallback: nearest palette color to local average (excluding banned) - if picked_index is None: - avg_rgb = local_average_rgb(imRGB, x, y, radius=m, skip_colors={GREEN, MAGENTA}) - picked_index = nearest_palette_index(avg_rgb, pal, banned_indices) - - if picked_index is not None: - out_px[x,y] = picked_index - changed += 1 - - if changed > 0: - outP.putpalette(pal) # keep palette exactly the same - outP.save(path, format='PCX') - if verbose: - if remove_all_green: - print(f"[fixed] {path}: {changed} green px") - else: - print(f"[fixed] {path}: {changed} isolated green px") - else: - if verbose: - print(f"[ok] {path}: no isolated green px") - - return changed - -# ---------- file selection logic ---------- - -def has_corresponding_lights(dirpath: str, fname: str) -> bool: - """ - Return True iff this file should be processed according to the rule: - • If fname ends with '_lights.pcx' → True. - • Else if a sibling '_lights.pcx' exists → True. - • Otherwise False. - """ - name_lower = fname.lower() - if name_lower.endswith("_lights.pcx"): - return True - if not name_lower.endswith(".pcx"): - return False - stem = fname[:-4] # remove '.pcx' - lights_name = stem + "_lights.pcx" - return os.path.exists(os.path.join(dirpath, lights_name)) - -def walk_and_fix(data_dir: str, noon_folder: str, - isolation_radius: int, search_radius: int, max_radius: int, - remove_all_green: bool, only_hour: int=None, verbose: bool=False) -> None: - noon_abs = os.path.normpath(os.path.join(data_dir, noon_folder)) - annotations_abs = os.path.normpath(os.path.join(data_dir, "Annotations")) - targets = [] - - if only_hour is not None: - hour_name = f"{only_hour:04d}" - hour_abs = os.path.normpath(os.path.join(data_dir, hour_name)) - if os.path.isdir(hour_abs): - targets.append(hour_abs) - else: - print(f"[warn] Hour folder not found: {hour_abs}") - else: - for name in os.listdir(data_dir): - sub = os.path.normpath(os.path.join(data_dir, name)) - if not os.path.isdir(sub): continue - if os.path.normcase(sub) == os.path.normcase(noon_abs): continue - if os.path.normcase(sub) == os.path.normcase(annotations_abs): continue - targets.append(sub) - - total_changed = 0 - for root in targets: - for dirpath, _, filenames in os.walk(root): - for fname in filenames: - if not fname.lower().endswith(".pcx"): - continue - if not has_corresponding_lights(dirpath, fname): - continue - path = os.path.join(dirpath, fname) - total_changed += fix_green_in_image( - path, isolation_radius, search_radius, max_radius, - remove_all_green, verbose=verbose - ) - - print(f"Done. Total isolated green pixels fixed: {total_changed}") - -def main(): - ap = argparse.ArgumentParser(description="Remove #00ff00 pixels from PCX outputs (only files with a matching _lights.pcx).") - ap.add_argument("--data", required=True, help="Path to Data root (contains noon + hour folders).") - ap.add_argument("--noon", default="1200", help="Name of noon folder to SKIP. Default: 1200") - ap.add_argument("--only-hour", type=int, help="Restrict to a single hour folder (e.g., 2400)") - ap.add_argument("--isolation-radius", type=int, default=1, help="Green is 'isolated' if no other green is found within this Chebyshev radius. Default: 1 (8-neighborhood)") - ap.add_argument("--search-radius", type=int, default=3, help="Neighbor radius (pixels) for index voting. Default: 3") - ap.add_argument("--max-radius", type=int, default=5, help="Max expansion radius if no neighbor found. Default: 5") - ap.add_argument("--remove-all-green", action="store_true", help="Replace all #00ff00 pixels (default: only isolated).") - ap.add_argument("--verbose", action="store_true", help="Print per-file changes.") - args = ap.parse_args() - - walk_and_fix( - args.data, args.noon, args.isolation_radius, args.search_radius, args.max_radius, - args.remove_all_green, args.only_hour, verbose=args.verbose - ) - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Civ3 post-process: remove GREEN (#00ff00) pixels from PCX outputs. + +Rules +----- +• Recursively scan under Data/*hour* folders (0100..2400 etc.), skipping the noon folder. +• Only touch files that have a corresponding "*_lights.pcx" in the same directory: + - For "NAME.pcx" → process only if "NAME_lights.pcx" exists. + - For "NAME_lights.pcx" → always process (it is the corresponding lights file). +• By default, only replace *isolated* green pixels: a green pixel whose neighbors within + --isolation-radius (default 1, i.e. the 8-connected ring) contain no other green pixels. +• With --remove-all-green, replace *all* green pixels. +• Replacement uses *neighbor palette indices* so the palette stays unchanged. + If no non-green neighbors exist, fall back to nearest palette color to local RGB average. + +Usage +----- + python civ3_fix_green.py --data ./Data --noon 1200 --verbose + # knobs: + # --isolation-radius 1 (1 = 8-neighborhood) + # --search-radius 3 + # --max-radius 5 + # --remove-all-green +""" + +import argparse, os, collections +from typing import Tuple, List, Set +from PIL import Image + +GREEN = (0, 255, 0) +MAGENTA = (255, 0, 255) + +# ---------- palette helpers ---------- + +def get_palette(im: Image.Image) -> List[int]: + pal = im.getpalette() or [] + if len(pal) < 256*3: + pal += [0]*(256*3 - len(pal)) + return pal[:256*3] + +def find_color_index(pal: List[int], rgb: Tuple[int,int,int]) -> int: + r,g,b = rgb + for i in range(256): + if pal[3*i] == r and pal[3*i+1] == g and pal[3*i+2] == b: + return i + return -1 + +def nearest_palette_index(target_rgb: Tuple[int,int,int], pal: List[int], banned: Set[int]) -> int: + """Choose the palette index (not in banned) whose RGB is nearest (Euclidean).""" + tr,tg,tb = target_rgb + best_i, best_d = None, 10**9 + for i in range(256): + if i in banned: continue + r,g,b = pal[3*i], pal[3*i+1], pal[3*i+2] + dr, dg, db = tr-r, tg-g, tb-b + d = dr*dr + dg*dg + db*db + if d < best_d: + best_d, best_i = d, i + return best_i if best_i is not None else 0 + +# ---------- neighborhood ops ---------- + +def has_green_neighbor(rgb_img: Image.Image, x: int, y: int, radius: int) -> bool: + """Return True if any neighbor within Chebyshev radius is GREEN (#00ff00).""" + w, h = rgb_img.size + px = rgb_img.load() + r = max(1, int(radius)) + for yy in range(max(0, y-r), min(h, y+r+1)): + for xx in range(max(0, x-r), min(w, x+r+1)): + if xx == x and yy == y: + continue + if px[xx,yy] == GREEN: + return True + return False + +def gather_neighbor_indices(idx_img: Image.Image, rgb_img: Image.Image, + x: int, y: int, radius: int, + green_idx: int, mag_idx: int) -> List[int]: + """Collect neighbor indices around (x,y) within Chebyshev radius; exclude green/magenta.""" + w, h = idx_img.size + px_idx = idx_img.load() + px_rgb = rgb_img.load() + out = [] + r = max(1, int(radius)) + for yy in range(max(0, y-r), min(h, y+r+1)): + for xx in range(max(0, x-r), min(w, x+r+1)): + if xx == x and yy == y: continue + i = px_idx[xx, yy] + r0,g0,b0 = px_rgb[xx, yy] + if (r0,g0,b0) == GREEN or (r0,g0,b0) == MAGENTA: + continue + if i == green_idx or i == mag_idx: + continue + out.append(i) + return out + +def local_average_rgb(rgb_img: Image.Image, x: int, y: int, radius: int, + skip_colors: Set[Tuple[int,int,int]]) -> Tuple[int,int,int]: + """Average RGB in a square window, skipping listed colors; falls back to (0,0,0).""" + w, h = rgb_img.size + px = rgb_img.load() + total = [0,0,0] + n = 0 + r = max(1, int(radius)) + for yy in range(max(0, y-r), min(h, y+r+1)): + for xx in range(max(0, x-r), min(w, x+r+1)): + c = px[xx, yy] + if c in skip_colors: + continue + total[0] += c[0]; total[1] += c[1]; total[2] += c[2] + n += 1 + if n == 0: + return (0,0,0) + return (total[0]//n, total[1]//n, total[2]//n) + +# ---------- core fixer ---------- + +def fix_green_in_image(path: str, isolation_radius: int, search_radius: int, max_radius: int, + remove_all_green: bool, verbose: bool=False) -> int: + """ + Returns number of pixels changed (only isolated greens are touched). + """ + try: + imP = Image.open(path) + except Exception: + return 0 + if imP.mode != 'P': + return 0 + + pal = get_palette(imP) + green_idx = find_color_index(pal, GREEN) + mag_idx = find_color_index(pal, MAGENTA) + + imRGB = imP.convert('RGB') + px = imRGB.load() + w, h = imRGB.size + + # Collect target green pixels + coords = [] + if remove_all_green: + for y in range(h): + for x in range(w): + if px[x, y] == GREEN: + coords.append((x, y)) + else: + for y in range(h): + for x in range(w): + if px[x, y] == GREEN and not has_green_neighbor(imRGB, x, y, isolation_radius): + coords.append((x, y)) + + if not coords: + return 0 + + outP = imP.copy() + out_px = outP.load() + banned_indices = set() + if green_idx != -1: banned_indices.add(green_idx) + if mag_idx != -1: banned_indices.add(mag_idx) + + changed = 0 + for (x,y) in coords: + if remove_all_green and mag_idx != -1: + out_px[x, y] = mag_idx + changed += 1 + continue + + picked_index = None + + # 1) Most frequent neighbor index (expand search out to max_radius if needed) + r = max(1, int(search_radius)) + m = max(r, int(max_radius)) + while r <= m and picked_index is None: + neigh = gather_neighbor_indices(imP, imRGB, x, y, r, green_idx, mag_idx) + if neigh: + cnt = collections.Counter(neigh) + picked_index = cnt.most_common(1)[0][0] + break + r += 1 + + # 2) Fallback: nearest palette color to local average (excluding banned) + if picked_index is None: + avg_rgb = local_average_rgb(imRGB, x, y, radius=m, skip_colors={GREEN, MAGENTA}) + picked_index = nearest_palette_index(avg_rgb, pal, banned_indices) + + if picked_index is not None: + out_px[x,y] = picked_index + changed += 1 + + if changed > 0: + outP.putpalette(pal) # keep palette exactly the same + outP.save(path, format='PCX') + if verbose: + if remove_all_green: + print(f"[fixed] {path}: {changed} green px") + else: + print(f"[fixed] {path}: {changed} isolated green px") + else: + if verbose: + print(f"[ok] {path}: no isolated green px") + + return changed + +# ---------- file selection logic ---------- + +def has_corresponding_lights(dirpath: str, fname: str) -> bool: + """ + Return True iff this file should be processed according to the rule: + • If fname ends with '_lights.pcx' → True. + • Else if a sibling '_lights.pcx' exists → True. + • Otherwise False. + """ + name_lower = fname.lower() + if name_lower.endswith("_lights.pcx"): + return True + if not name_lower.endswith(".pcx"): + return False + stem = fname[:-4] # remove '.pcx' + lights_name = stem + "_lights.pcx" + return os.path.exists(os.path.join(dirpath, lights_name)) + +def walk_and_fix(data_dir: str, noon_folder: str, + isolation_radius: int, search_radius: int, max_radius: int, + remove_all_green: bool, only_hour: int=None, verbose: bool=False) -> None: + noon_abs = os.path.normpath(os.path.join(data_dir, noon_folder)) + annotations_abs = os.path.normpath(os.path.join(data_dir, "Annotations")) + targets = [] + + if only_hour is not None: + hour_name = f"{only_hour:04d}" + hour_abs = os.path.normpath(os.path.join(data_dir, hour_name)) + if os.path.isdir(hour_abs): + targets.append(hour_abs) + else: + print(f"[warn] Hour folder not found: {hour_abs}") + else: + for name in os.listdir(data_dir): + sub = os.path.normpath(os.path.join(data_dir, name)) + if not os.path.isdir(sub): continue + if os.path.normcase(sub) == os.path.normcase(noon_abs): continue + if os.path.normcase(sub) == os.path.normcase(annotations_abs): continue + targets.append(sub) + + total_changed = 0 + for root in targets: + for dirpath, _, filenames in os.walk(root): + for fname in filenames: + if not fname.lower().endswith(".pcx"): + continue + if not has_corresponding_lights(dirpath, fname): + continue + path = os.path.join(dirpath, fname) + total_changed += fix_green_in_image( + path, isolation_radius, search_radius, max_radius, + remove_all_green, verbose=verbose + ) + + print(f"Done. Total isolated green pixels fixed: {total_changed}") + +def main(): + ap = argparse.ArgumentParser(description="Remove #00ff00 pixels from PCX outputs (only files with a matching _lights.pcx).") + ap.add_argument("--data", required=True, help="Path to Data root (contains noon + hour folders).") + ap.add_argument("--noon", default="1200", help="Name of noon folder to SKIP. Default: 1200") + ap.add_argument("--only-hour", type=int, help="Restrict to a single hour folder (e.g., 2400)") + ap.add_argument("--isolation-radius", type=int, default=1, help="Green is 'isolated' if no other green is found within this Chebyshev radius. Default: 1 (8-neighborhood)") + ap.add_argument("--search-radius", type=int, default=3, help="Neighbor radius (pixels) for index voting. Default: 3") + ap.add_argument("--max-radius", type=int, default=5, help="Max expansion radius if no neighbor found. Default: 5") + ap.add_argument("--remove-all-green", action="store_true", help="Replace all #00ff00 pixels (default: only isolated).") + ap.add_argument("--verbose", action="store_true", help="Print per-file changes.") + args = ap.parse_args() + + walk_and_fix( + args.data, args.noon, args.isolation_radius, args.search_radius, args.max_radius, + args.remove_all_green, args.only_hour, verbose=args.verbose + ) + +if __name__ == "__main__": + main() diff --git a/DayNight/find_least_used_colors.py b/DayNight/find_least_used_colors.py index 05a50c00..0895da6d 100644 --- a/DayNight/find_least_used_colors.py +++ b/DayNight/find_least_used_colors.py @@ -1,98 +1,98 @@ -#!/usr/bin/env python3 -""" -least_used_pcx_colors.py - -Reads a paletted (8-bit, mode 'P') PCX file and prints the top 5 least used -colors among indices [0..254] by default. - -Output columns: index, HTML color (#RRGGBB), count - -Usage: - python least_used_pcx_colors.py path/to/image.pcx - # include colors that never appear: - python least_used_pcx_colors.py image.pcx --include-zeros - # change the highest considered index: - python least_used_pcx_colors.py image.pcx --max-index 255 -""" - -import argparse -import sys -from PIL import Image - -def idx_to_hex(rgb_tuple): - r, g, b = rgb_tuple - return f"#{r:02X}{g:02X}{b:02X}" - -def main(): - parser = argparse.ArgumentParser(description="Find least-used colors in a paletted PCX.") - parser.add_argument("pcx_path", help="Path to the PCX file (8-bit paletted).") - parser.add_argument("--include-zeros", action="store_true", default=True, - help="Include palette indices that occur 0 times.") - parser.add_argument("--max-index", type=int, default=254, - help="Highest palette index to consider (default: 254).") - parser.add_argument("--top", type=int, default=10, - help="How many least-used colors to return (default: 10).") - args = parser.parse_args() - - # Open image - try: - im = Image.open(args.pcx_path) - except Exception as e: - print(f"Error: failed to open '{args.pcx_path}': {e}", file=sys.stderr) - sys.exit(1) - - # Require paletted image to avoid quantization changing counts - if im.mode != "P": - print(f"Error: '{args.pcx_path}' is mode '{im.mode}', not an 8-bit paletted image ('P').", file=sys.stderr) - sys.exit(2) - - # Get palette (list of [R, G, B, R, G, B, ...], up to 256*3 entries) - pal = im.getpalette() - if not pal: - print("Error: No palette data found.", file=sys.stderr) - sys.exit(3) - - # Build palette as list of (R,G,B) - palette_colors = [(pal[i], pal[i+1], pal[i+2]) for i in range(0, len(pal), 3)] - max_considered = min(args.max_index, len(palette_colors) - 1) - - # Histogram: for 'P' images, 256 bins (0..255) - hist = im.histogram() - if len(hist) < 256: - # Shouldn't happen for 'P', but guard anyway - hist += [0] * (256 - len(hist)) - - # Build (count, index, html) entries for chosen range - entries = [] - for idx in range(0, max_considered + 1): - count = hist[idx] if idx < len(hist) else 0 - # Some palettes might be shorter than 256 entries; guard for safety - if idx < len(palette_colors): - html = idx_to_hex(palette_colors[idx]) - else: - # If palette entry missing, treat as black (or skip); choose to skip - html = None - - if html is None: - continue # skip indices without a palette color - - if args.include_zeros or count > 0: - entries.append((count, idx, html)) - - if not entries: - print("No colors to report in the specified index range.") - sys.exit(0) - - # Sort by count ascending, then by index to stabilize ties - entries.sort(key=lambda t: (t[0], t[1])) - - # Take top N least-used - top_n = entries[:args.top] - - # Print header and results - print("index\thtml\tcount") - for count, idx, html in top_n: - print(f"{idx}\t{html}\t{count}") - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +""" +least_used_pcx_colors.py + +Reads a paletted (8-bit, mode 'P') PCX file and prints the top 5 least used +colors among indices [0..254] by default. + +Output columns: index, HTML color (#RRGGBB), count + +Usage: + python least_used_pcx_colors.py path/to/image.pcx + # include colors that never appear: + python least_used_pcx_colors.py image.pcx --include-zeros + # change the highest considered index: + python least_used_pcx_colors.py image.pcx --max-index 255 +""" + +import argparse +import sys +from PIL import Image + +def idx_to_hex(rgb_tuple): + r, g, b = rgb_tuple + return f"#{r:02X}{g:02X}{b:02X}" + +def main(): + parser = argparse.ArgumentParser(description="Find least-used colors in a paletted PCX.") + parser.add_argument("pcx_path", help="Path to the PCX file (8-bit paletted).") + parser.add_argument("--include-zeros", action="store_true", default=True, + help="Include palette indices that occur 0 times.") + parser.add_argument("--max-index", type=int, default=254, + help="Highest palette index to consider (default: 254).") + parser.add_argument("--top", type=int, default=10, + help="How many least-used colors to return (default: 10).") + args = parser.parse_args() + + # Open image + try: + im = Image.open(args.pcx_path) + except Exception as e: + print(f"Error: failed to open '{args.pcx_path}': {e}", file=sys.stderr) + sys.exit(1) + + # Require paletted image to avoid quantization changing counts + if im.mode != "P": + print(f"Error: '{args.pcx_path}' is mode '{im.mode}', not an 8-bit paletted image ('P').", file=sys.stderr) + sys.exit(2) + + # Get palette (list of [R, G, B, R, G, B, ...], up to 256*3 entries) + pal = im.getpalette() + if not pal: + print("Error: No palette data found.", file=sys.stderr) + sys.exit(3) + + # Build palette as list of (R,G,B) + palette_colors = [(pal[i], pal[i+1], pal[i+2]) for i in range(0, len(pal), 3)] + max_considered = min(args.max_index, len(palette_colors) - 1) + + # Histogram: for 'P' images, 256 bins (0..255) + hist = im.histogram() + if len(hist) < 256: + # Shouldn't happen for 'P', but guard anyway + hist += [0] * (256 - len(hist)) + + # Build (count, index, html) entries for chosen range + entries = [] + for idx in range(0, max_considered + 1): + count = hist[idx] if idx < len(hist) else 0 + # Some palettes might be shorter than 256 entries; guard for safety + if idx < len(palette_colors): + html = idx_to_hex(palette_colors[idx]) + else: + # If palette entry missing, treat as black (or skip); choose to skip + html = None + + if html is None: + continue # skip indices without a palette color + + if args.include_zeros or count > 0: + entries.append((count, idx, html)) + + if not entries: + print("No colors to report in the specified index range.") + sys.exit(0) + + # Sort by count ascending, then by index to stabilize ties + entries.sort(key=lambda t: (t[0], t[1])) + + # Take top N least-used + top_n = entries[:args.top] + + # Print header and results + print("index\thtml\tcount") + for count, idx, html in top_n: + print(f"{idx}\t{html}\t{count}") + +if __name__ == "__main__": + main() diff --git a/DayNight/find_unused_palette_indexes.py b/DayNight/find_unused_palette_indexes.py index 52bcb74c..edcaa816 100644 --- a/DayNight/find_unused_palette_indexes.py +++ b/DayNight/find_unused_palette_indexes.py @@ -1,107 +1,107 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -pcx_palette_unused.py — find unused palette slots in PCX files - -Usage: - python3 pcx_palette_unused.py --folder ./Data/1200 --exclude-255 yes - -What it prints: - • Per-file: which palette indexes are unused (and their RGB in that file) - • Intersection across all files (indexes unused everywhere) - • Top candidate RGBs that were unused most often across files -""" - -import argparse, os, collections -from PIL import Image - -def get_palette(im): - pal = im.getpalette() or [] - if len(pal) < 256*3: pal += [0]*(256*3 - len(pal)) - return pal[:256*3] - -def main(): - ap = argparse.ArgumentParser(description="List unused palette indexes/colors in PCX files") - ap.add_argument("--folder", required=True, help="Folder to scan (recursively)") - ap.add_argument("--exclude-255", default="yes", choices=["yes","no"], - help="Exclude index 255 (magenta) from 'unused' lists (default: yes)") - args = ap.parse_args() - exclude_255 = (args.exclude_255 == "yes") - - per_file_unused = [] - all_files = [] - - # Count how often a specific RGB appears in an unused slot across files - rgb_unused_counter = collections.Counter() - - # Intersection accumulator for indexes (0..254 if exclude_255 else 0..255) - index_domain = list(range(0, 255 if exclude_255 else 256)) - global_intersection = set(index_domain) - - for root, _, files in os.walk(args.folder): - for name in files: - if not name.lower().endswith(".pcx"): - continue - path = os.path.join(root, name) - try: - im = Image.open(path) - if im.mode != "P": - # Most Civ3 PCX files are 'P'; warn if not. - print(f"[warn] {path}: not paletted ('{im.mode}'); attempting to interpret anyway.") - im = im.convert("P") - pal = get_palette(im) - - # Which indexes are used in pixels? - used = set(im.getdata()) - domain = set(index_domain) - unused = sorted(domain - used) - - # Aggregate RGBs for unused slots (per-file) - for idx in unused: - r,g,b = pal[3*idx], pal[3*idx+1], pal[3*idx+2] - rgb_unused_counter[(r,g,b)] += 1 - - per_file_unused.append((path, unused, pal)) - all_files.append(path) - global_intersection &= set(unused) - - except Exception as e: - print(f"[error] {path}: {e}") - - # Output - print("\n=== Per-file unused palette indexes ===") - for path, unused, pal in per_file_unused: - print(f"\n{path}") - if not unused: - print(" (none)") - else: - print(f" {len(unused)} unused indexes:") - # show up to 32 entries to keep readable - preview = unused if len(unused) <= 32 else (unused[:16] + ["..."] + unused[-15:]) - print(" ", preview) - # show a few RGBs - rgb_preview = [] - for idx in unused[:12]: - r,g,b = pal[3*idx], pal[3*idx+1], pal[3*idx+2] - rgb_preview.append(f"{idx:3d}:#{r:02x}{g:02x}{b:02x}") - if rgb_preview: - print(" sample RGBs:", ", ".join(rgb_preview)) - - print("\n=== Indexes unused in EVERY scanned file ===") - if not all_files: - print(" (no files)") - else: - inter_sorted = sorted(global_intersection) - print(f" count={len(inter_sorted)}") - print(" ", inter_sorted[:64] if len(inter_sorted)<=64 else (inter_sorted[:32]+["..."]+inter_sorted[-31:])) - - print("\n=== Top candidate RGBs (unused across many files) ===") - if not rgb_unused_counter: - print(" (none)") - else: - for (r,g,b), cnt in rgb_unused_counter.most_common(20): - print(f" #{r:02x}{g:02x}{b:02x} unused-in-files={cnt}") - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +pcx_palette_unused.py — find unused palette slots in PCX files + +Usage: + python3 pcx_palette_unused.py --folder ./Data/1200 --exclude-255 yes + +What it prints: + • Per-file: which palette indexes are unused (and their RGB in that file) + • Intersection across all files (indexes unused everywhere) + • Top candidate RGBs that were unused most often across files +""" + +import argparse, os, collections +from PIL import Image + +def get_palette(im): + pal = im.getpalette() or [] + if len(pal) < 256*3: pal += [0]*(256*3 - len(pal)) + return pal[:256*3] + +def main(): + ap = argparse.ArgumentParser(description="List unused palette indexes/colors in PCX files") + ap.add_argument("--folder", required=True, help="Folder to scan (recursively)") + ap.add_argument("--exclude-255", default="yes", choices=["yes","no"], + help="Exclude index 255 (magenta) from 'unused' lists (default: yes)") + args = ap.parse_args() + exclude_255 = (args.exclude_255 == "yes") + + per_file_unused = [] + all_files = [] + + # Count how often a specific RGB appears in an unused slot across files + rgb_unused_counter = collections.Counter() + + # Intersection accumulator for indexes (0..254 if exclude_255 else 0..255) + index_domain = list(range(0, 255 if exclude_255 else 256)) + global_intersection = set(index_domain) + + for root, _, files in os.walk(args.folder): + for name in files: + if not name.lower().endswith(".pcx"): + continue + path = os.path.join(root, name) + try: + im = Image.open(path) + if im.mode != "P": + # Most Civ3 PCX files are 'P'; warn if not. + print(f"[warn] {path}: not paletted ('{im.mode}'); attempting to interpret anyway.") + im = im.convert("P") + pal = get_palette(im) + + # Which indexes are used in pixels? + used = set(im.getdata()) + domain = set(index_domain) + unused = sorted(domain - used) + + # Aggregate RGBs for unused slots (per-file) + for idx in unused: + r,g,b = pal[3*idx], pal[3*idx+1], pal[3*idx+2] + rgb_unused_counter[(r,g,b)] += 1 + + per_file_unused.append((path, unused, pal)) + all_files.append(path) + global_intersection &= set(unused) + + except Exception as e: + print(f"[error] {path}: {e}") + + # Output + print("\n=== Per-file unused palette indexes ===") + for path, unused, pal in per_file_unused: + print(f"\n{path}") + if not unused: + print(" (none)") + else: + print(f" {len(unused)} unused indexes:") + # show up to 32 entries to keep readable + preview = unused if len(unused) <= 32 else (unused[:16] + ["..."] + unused[-15:]) + print(" ", preview) + # show a few RGBs + rgb_preview = [] + for idx in unused[:12]: + r,g,b = pal[3*idx], pal[3*idx+1], pal[3*idx+2] + rgb_preview.append(f"{idx:3d}:#{r:02x}{g:02x}{b:02x}") + if rgb_preview: + print(" sample RGBs:", ", ".join(rgb_preview)) + + print("\n=== Indexes unused in EVERY scanned file ===") + if not all_files: + print(" (no files)") + else: + inter_sorted = sorted(global_intersection) + print(f" count={len(inter_sorted)}") + print(" ", inter_sorted[:64] if len(inter_sorted)<=64 else (inter_sorted[:32]+["..."]+inter_sorted[-31:])) + + print("\n=== Top candidate RGBs (unused across many files) ===") + if not rgb_unused_counter: + print(" (none)") + else: + for (r,g,b), cnt in rgb_unused_counter.most_common(20): + print(f" #{r:02x}{g:02x}{b:02x} unused-in-files={cnt}") + +if __name__ == "__main__": + main() diff --git a/DayNight/generate.sh b/DayNight/generate.sh index 15e9c8f0..02e69713 100644 --- a/DayNight/generate.sh +++ b/DayNight/generate.sh @@ -1,208 +1,208 @@ -#!/usr/bin/env bash - -set -euo pipefail - -### === CONFIG === -# Assumed to be run from DayNight/ directory - -DAYNIGHT_ANNOTATION_DIR="../Art/DayNight/Annotations" -DAYNIGHT_DATA_DIR="../Art/DayNight" -DISTRICT_ANNOTATION_DIR="../Art/Districts/Annotations" -DISTRICT_DATA_DIR="../Art/Districts" - -ANNOTATION_DIR="../Art/DayNight/Annotations" -DATA_DIR="../Art/DayNight" - -NOON_SUBFOLDER="1200" -ONLY_HOUR="" # set empty "" to process all hours - -# ---- Day/Night settings ---- -WARMTH=1.7 # Scale for sunrise/sunset warmth (1.0 = base) -BLUE=1.6 # Scale for night-time blue emphasis (1.0 = base) -DARKNESS=3.0 # Scale for extra night darkening (1.0 = base) -DESAT=0.8 # Scale for dusk/night desaturation toward gray (lower = richer) -SAT=1.1 # Global saturation multiplier after tint (1.0 = none) -CONTRAST=1.08 # Global contrast multiplier around mid 128 (1.0 = none) -SUNRISE_CENTER=6.0 # Hour center for sunrise warmth bump (0-23) -SUNSET_CENTER=18.0 # Hour center for sunset warmth bump (0-23) -TWILIGHT_WIDTH=2.6 # Sigma for sunrise/sunset warmth spread (higher = broader) -NOON_BLEND=0.5 # 0..1 strength to blend toward base palette near 12:00 (0=off) -NOON_SIGMA=1.0 # Gaussian width (hours) around 12:00 (larger = broader) - -# Examples -# --warmth 1.05 --blue 1.25 --darkness 1.15 --desat 0.9 --sat 1.02 --contrast 1.04 # Moody, cooler nights -# --warmth 1.3 --blue 1.05 --darkness 1.05 --desat 0.8 --sat 1.08 --contrast 1.04 # Warm, cinematic evenings -# --warmth 1.1 --blue 1.12 --darkness 1.08 --desat 0.85 --sat 1.05 --contrast 1.03 # Balanced -# --warmth 1.2 --blue 1.1 --darkness 1.05 --desat 0.7 --sat 1.1 --contrast 1.0 # Soft, painted look -# --warmth 1.15 --blue 1.2 --darkness 1.12 --desat 0.85 --sat 1.0 --contrast 1.08 # Crisp, high contrast nights - -# Light keys are the annotation colors used to indicate where lights should be at night. -# Each has a different configuration (LIGHT_STYLES, below). The light annotations are in -# /1200/*_light.pcx files. -LIGHT_KEYS=( - # Main colors - "#F6915E" # Orange - "#FEF500" # Yellow - - # Supporting colors, mostly on modern buildings - "#00feff" # Teal - "#E4080A" # Red - "#BD15D0" # Purple - "#2D9C01" # Green - "#FF25C8" # Pink - "#0A02EB" # Blue - "#8262ED" # Indigo -) - -LIGHT_STYLES=( - # Orange - softer, ambient lighting - "key=#F6915E; core=#ff8a20; glow=#dc6a00; core_gain=1.0; highlight_gain=0.0; size_radius=1.5; size_boost=0.05; halo_gain=6.0; halo_radius=1.0; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Yellow - intense, bright, focused lighting - "key=#FEF500; core=#ff8a20; glow=#dc6a00; core_gain=2.5; highlight_gain=1.0; size_radius=6.5; size_boost=1.5; halo_gain=20.0; halo_radius=0.1; core_radius=1.1; halo_gamma=1.3; size_gamma=0.75;" - - # Red - mostly modern building tops, individual pixels - "key=#E4080A; core=#E4080A; glow=#E4080A; core_gain=1.0; highlight_gain=0.0; size_radius=0.5; size_boost=0.0; halo_gain=6.0; halo_radius=1.0; core_radius=0.5; halo_gamma=0.9; size_gamma=0.0; blend_mode=add;" - - # Teal - "key=#00feff; core=#00feff; glow=#00feff; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Purple - "key=#BD15D0; core=#BD15D0; glow=#BD15D0; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Green - "key=#2D9C01; core=#2D9C01; glow=#2D9C01; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Pink - "key=#FF25C8; core=#FF25C8; glow=#FF25C8; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Blue - "key=#0A02EB; core=#0A02EB; glow=#0A02EB; core_gain=0.2; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Indigo - "key=#8262ED; core=#7521DC; glow=#7521DC; core_gain=0.2; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" -) - -# ---- City Lights settings ---- -CORE_COLOR="#ff8a20" # Tint color for the bright core (e.g., '#fff87a' for warm yellow) -GLOW_COLOR="#dc6a00" # Tint color for the outer halo (e.g., '#ff8a20' for orange) -CORE_RADIUS=1.1 # Gaussian blur radius (pixels) of the bright core. Higher = wider/softer core -CORE_GAIN=2.5 # Intensity multiplier for the core alpha (brightness/opacity of the center) -HALO_RADIUS=13 # Gaussian blur radius (pixels) of the outer halo. Higher = glow spreads further outward -HALO_GAIN=20.0 # Intensity multiplier for the halo alpha (strength of the outer glow) -HALO_SEP=0.75 # 0..1: subtracts a fraction of the core from the halo. 0 = seamless merge; 1 = distinct outer ring -HALO_GAMMA=1.3 # Gamma on the halo-only mask. >1 pushes energy outward (softer tail); <1 concentrates near source -HIGHLIGHT_GAIN=0.5 # Extra white highlight added from the core mask (0..~1 typical). Higher = hotter specular highlight -SIZE_BOOST=1.7 # How much cluster size increases intensity (0 disables). Higher = large groups pop more -SIZE_RADIUS=6.5 # Neighborhood radius (pixels) when measuring cluster size. Higher = smoother/broader size effect -SIZE_GAMMA=0.75 # Gamma on the size map. <1 emphasizes medium clusters; >1 favors only the largest clusters -CLIP_INTERIOR="yes" # If 'yes', lights only affect non-transparent interior (avoids glow on MAGENTA/GREEN). Recommended: yes. -CLIP_ERODE=0 # Erode the interior mask by N pixels. Higher = more conservative (keeps glow off edges) -BLEND_MODE="screen" # How layers combine. 'screen' (default) is safer; 'add' is punchier but can clip highlights - -# Notes: -# • Increase --halo-radius and --halo-gain for a bigger, softer glow. -# • If you see a dark ring between core/halo, reduce --halo-sep or increase --halo-gamma. -# • 'screen' blend is safer for colors; 'add' is punchier but can clip highlights." - -### === BUILD ARGS === -LK_ARGS=() -for c in "${LIGHT_KEYS[@]}"; do LK_ARGS+=( --light-key "$c" ); done - -STYLE_ARGS=() -for s in "${LIGHT_STYLES[@]}"; do STYLE_ARGS+=( --light-style "$s" ); done - -process_art_set() { - local data_dir="$1" - local annotation_dir="$2" - - if [[ ! -d "$data_dir" ]]; then - echo "Skipping missing data directory: $data_dir" >&2 - return - fi - if [[ ! -d "$annotation_dir" ]]; then - echo "Skipping missing annotation directory: $annotation_dir" >&2 - return - fi - - echo "Processing art set in $data_dir" - - mkdir -p "$data_dir/$NOON_SUBFOLDER" - shopt -s nullglob - local -a annotation_files=("$annotation_dir"/*) - shopt -u nullglob - if (( ${#annotation_files[@]} == 0 )); then - echo "No annotation files found in $annotation_dir" >&2 - else - cp "${annotation_files[@]}" "$data_dir/$NOON_SUBFOLDER" - fi - - local -a dn_args=( - --data "$data_dir" - --noon "$NOON_SUBFOLDER" - --warmth "$WARMTH" - --blue "$BLUE" - --darkness "$DARKNESS" - --desat "$DESAT" - --sat "$SAT" - --contrast "$CONTRAST" - --sunrise-center "$SUNRISE_CENTER" - --sunset-center "$SUNSET_CENTER" - --twilight-width "$TWILIGHT_WIDTH" - --noon-blend "$NOON_BLEND" - --noon-sigma "$NOON_SIGMA" - "${LK_ARGS[@]}" - ) - - local -a cl_args=( - --data "$data_dir" --noon "$NOON_SUBFOLDER" - "${LK_ARGS[@]}" "${STYLE_ARGS[@]}" - --core-color "$CORE_COLOR" --glow-color "$GLOW_COLOR" - --core-radius "$CORE_RADIUS" --halo-radius "$HALO_RADIUS" - --core-gain "$CORE_GAIN" --halo-gain "$HALO_GAIN" - --highlight-gain "$HIGHLIGHT_GAIN" - --size-boost "$SIZE_BOOST" --size-radius "$SIZE_RADIUS" --size-gamma "$SIZE_GAMMA" - --clip-interior "$CLIP_INTERIOR" --clip-erode "$CLIP_ERODE" - --halo-sep "$HALO_SEP" --halo-gamma "$HALO_GAMMA" - --blend-mode "$BLEND_MODE" - ) - - local -a pp_args=( - --data "$data_dir" - --noon "$NOON_SUBFOLDER" - --verbose - --remove-all-green - ) - - if [[ -n "${ONLY_HOUR}" ]]; then - dn_args+=( --only-hour "$ONLY_HOUR" ) - cl_args+=( --only-hour "$ONLY_HOUR" ) - pp_args+=( --only-hour "$ONLY_HOUR" ) - fi - - python civ3_day_night.py "${dn_args[@]}" - python civ3_city_lights.py "${cl_args[@]}" - python civ3_postprocess_pixels.py "${pp_args[@]}" - - ### === CLEANUP: remove *_lights.pcx from hour subfolders (excluding annotation dir) === - # If ONLY_HOUR is set, restrict cleanup to that single folder & noon folder; otherwise clean all 4-digit hour folders. - if [[ -n "${ONLY_HOUR}" ]]; then - # Only the specified hour - if [[ -d "$data_dir/$ONLY_HOUR" ]]; then - find "$data_dir/$ONLY_HOUR" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true - fi - # Also clean the noon folder - if [[ -d "$data_dir/$NOON_SUBFOLDER" ]]; then - find "$data_dir/$NOON_SUBFOLDER" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true - fi - else - # All hour-named subfolders under data_dir (e.g., 0000, 0100, ..., 2400) - # Do not touch the external $annotation_dir. - while IFS= read -r -d '' hour_dir; do - find "${hour_dir}" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true - done < <(find "$data_dir" -mindepth 1 -maxdepth 1 -type d -regex '.*/[0-9]{4}$' -print0) - fi -} - -process_art_set "$DAYNIGHT_DATA_DIR" "$DAYNIGHT_ANNOTATION_DIR" -process_art_set "$DISTRICT_DATA_DIR" "$DISTRICT_ANNOTATION_DIR" +#!/usr/bin/env bash + +set -euo pipefail + +### === CONFIG === +# Assumed to be run from DayNight/ directory + +DAYNIGHT_ANNOTATION_DIR="../Art/DayNight/Annotations" +DAYNIGHT_DATA_DIR="../Art/DayNight" +DISTRICT_ANNOTATION_DIR="../Art/Districts/Annotations" +DISTRICT_DATA_DIR="../Art/Districts" + +ANNOTATION_DIR="../Art/DayNight/Annotations" +DATA_DIR="../Art/DayNight" + +NOON_SUBFOLDER="1200" +ONLY_HOUR="" # set empty "" to process all hours + +# ---- Day/Night settings ---- +WARMTH=1.7 # Scale for sunrise/sunset warmth (1.0 = base) +BLUE=1.6 # Scale for night-time blue emphasis (1.0 = base) +DARKNESS=3.0 # Scale for extra night darkening (1.0 = base) +DESAT=0.8 # Scale for dusk/night desaturation toward gray (lower = richer) +SAT=1.1 # Global saturation multiplier after tint (1.0 = none) +CONTRAST=1.08 # Global contrast multiplier around mid 128 (1.0 = none) +SUNRISE_CENTER=6.0 # Hour center for sunrise warmth bump (0-23) +SUNSET_CENTER=18.0 # Hour center for sunset warmth bump (0-23) +TWILIGHT_WIDTH=2.6 # Sigma for sunrise/sunset warmth spread (higher = broader) +NOON_BLEND=0.5 # 0..1 strength to blend toward base palette near 12:00 (0=off) +NOON_SIGMA=1.0 # Gaussian width (hours) around 12:00 (larger = broader) + +# Examples +# --warmth 1.05 --blue 1.25 --darkness 1.15 --desat 0.9 --sat 1.02 --contrast 1.04 # Moody, cooler nights +# --warmth 1.3 --blue 1.05 --darkness 1.05 --desat 0.8 --sat 1.08 --contrast 1.04 # Warm, cinematic evenings +# --warmth 1.1 --blue 1.12 --darkness 1.08 --desat 0.85 --sat 1.05 --contrast 1.03 # Balanced +# --warmth 1.2 --blue 1.1 --darkness 1.05 --desat 0.7 --sat 1.1 --contrast 1.0 # Soft, painted look +# --warmth 1.15 --blue 1.2 --darkness 1.12 --desat 0.85 --sat 1.0 --contrast 1.08 # Crisp, high contrast nights + +# Light keys are the annotation colors used to indicate where lights should be at night. +# Each has a different configuration (LIGHT_STYLES, below). The light annotations are in +# /1200/*_light.pcx files. +LIGHT_KEYS=( + # Main colors + "#F6915E" # Orange + "#FEF500" # Yellow + + # Supporting colors, mostly on modern buildings + "#00feff" # Teal + "#E4080A" # Red + "#BD15D0" # Purple + "#2D9C01" # Green + "#FF25C8" # Pink + "#0A02EB" # Blue + "#8262ED" # Indigo +) + +LIGHT_STYLES=( + # Orange - softer, ambient lighting + "key=#F6915E; core=#ff8a20; glow=#dc6a00; core_gain=1.0; highlight_gain=0.0; size_radius=1.5; size_boost=0.05; halo_gain=6.0; halo_radius=1.0; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Yellow - intense, bright, focused lighting + "key=#FEF500; core=#ff8a20; glow=#dc6a00; core_gain=2.5; highlight_gain=1.0; size_radius=6.5; size_boost=1.5; halo_gain=20.0; halo_radius=0.1; core_radius=1.1; halo_gamma=1.3; size_gamma=0.75;" + + # Red - mostly modern building tops, individual pixels + "key=#E4080A; core=#E4080A; glow=#E4080A; core_gain=1.0; highlight_gain=0.0; size_radius=0.5; size_boost=0.0; halo_gain=6.0; halo_radius=1.0; core_radius=0.5; halo_gamma=0.9; size_gamma=0.0; blend_mode=add;" + + # Teal + "key=#00feff; core=#00feff; glow=#00feff; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Purple + "key=#BD15D0; core=#BD15D0; glow=#BD15D0; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Green + "key=#2D9C01; core=#2D9C01; glow=#2D9C01; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Pink + "key=#FF25C8; core=#FF25C8; glow=#FF25C8; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Blue + "key=#0A02EB; core=#0A02EB; glow=#0A02EB; core_gain=0.2; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Indigo + "key=#8262ED; core=#7521DC; glow=#7521DC; core_gain=0.2; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" +) + +# ---- City Lights settings ---- +CORE_COLOR="#ff8a20" # Tint color for the bright core (e.g., '#fff87a' for warm yellow) +GLOW_COLOR="#dc6a00" # Tint color for the outer halo (e.g., '#ff8a20' for orange) +CORE_RADIUS=1.1 # Gaussian blur radius (pixels) of the bright core. Higher = wider/softer core +CORE_GAIN=2.5 # Intensity multiplier for the core alpha (brightness/opacity of the center) +HALO_RADIUS=13 # Gaussian blur radius (pixels) of the outer halo. Higher = glow spreads further outward +HALO_GAIN=20.0 # Intensity multiplier for the halo alpha (strength of the outer glow) +HALO_SEP=0.75 # 0..1: subtracts a fraction of the core from the halo. 0 = seamless merge; 1 = distinct outer ring +HALO_GAMMA=1.3 # Gamma on the halo-only mask. >1 pushes energy outward (softer tail); <1 concentrates near source +HIGHLIGHT_GAIN=0.5 # Extra white highlight added from the core mask (0..~1 typical). Higher = hotter specular highlight +SIZE_BOOST=1.7 # How much cluster size increases intensity (0 disables). Higher = large groups pop more +SIZE_RADIUS=6.5 # Neighborhood radius (pixels) when measuring cluster size. Higher = smoother/broader size effect +SIZE_GAMMA=0.75 # Gamma on the size map. <1 emphasizes medium clusters; >1 favors only the largest clusters +CLIP_INTERIOR="yes" # If 'yes', lights only affect non-transparent interior (avoids glow on MAGENTA/GREEN). Recommended: yes. +CLIP_ERODE=0 # Erode the interior mask by N pixels. Higher = more conservative (keeps glow off edges) +BLEND_MODE="screen" # How layers combine. 'screen' (default) is safer; 'add' is punchier but can clip highlights + +# Notes: +# • Increase --halo-radius and --halo-gain for a bigger, softer glow. +# • If you see a dark ring between core/halo, reduce --halo-sep or increase --halo-gamma. +# • 'screen' blend is safer for colors; 'add' is punchier but can clip highlights." + +### === BUILD ARGS === +LK_ARGS=() +for c in "${LIGHT_KEYS[@]}"; do LK_ARGS+=( --light-key "$c" ); done + +STYLE_ARGS=() +for s in "${LIGHT_STYLES[@]}"; do STYLE_ARGS+=( --light-style "$s" ); done + +process_art_set() { + local data_dir="$1" + local annotation_dir="$2" + + if [[ ! -d "$data_dir" ]]; then + echo "Skipping missing data directory: $data_dir" >&2 + return + fi + if [[ ! -d "$annotation_dir" ]]; then + echo "Skipping missing annotation directory: $annotation_dir" >&2 + return + fi + + echo "Processing art set in $data_dir" + + mkdir -p "$data_dir/$NOON_SUBFOLDER" + shopt -s nullglob + local -a annotation_files=("$annotation_dir"/*) + shopt -u nullglob + if (( ${#annotation_files[@]} == 0 )); then + echo "No annotation files found in $annotation_dir" >&2 + else + cp "${annotation_files[@]}" "$data_dir/$NOON_SUBFOLDER" + fi + + local -a dn_args=( + --data "$data_dir" + --noon "$NOON_SUBFOLDER" + --warmth "$WARMTH" + --blue "$BLUE" + --darkness "$DARKNESS" + --desat "$DESAT" + --sat "$SAT" + --contrast "$CONTRAST" + --sunrise-center "$SUNRISE_CENTER" + --sunset-center "$SUNSET_CENTER" + --twilight-width "$TWILIGHT_WIDTH" + --noon-blend "$NOON_BLEND" + --noon-sigma "$NOON_SIGMA" + "${LK_ARGS[@]}" + ) + + local -a cl_args=( + --data "$data_dir" --noon "$NOON_SUBFOLDER" + "${LK_ARGS[@]}" "${STYLE_ARGS[@]}" + --core-color "$CORE_COLOR" --glow-color "$GLOW_COLOR" + --core-radius "$CORE_RADIUS" --halo-radius "$HALO_RADIUS" + --core-gain "$CORE_GAIN" --halo-gain "$HALO_GAIN" + --highlight-gain "$HIGHLIGHT_GAIN" + --size-boost "$SIZE_BOOST" --size-radius "$SIZE_RADIUS" --size-gamma "$SIZE_GAMMA" + --clip-interior "$CLIP_INTERIOR" --clip-erode "$CLIP_ERODE" + --halo-sep "$HALO_SEP" --halo-gamma "$HALO_GAMMA" + --blend-mode "$BLEND_MODE" + ) + + local -a pp_args=( + --data "$data_dir" + --noon "$NOON_SUBFOLDER" + --verbose + --remove-all-green + ) + + if [[ -n "${ONLY_HOUR}" ]]; then + dn_args+=( --only-hour "$ONLY_HOUR" ) + cl_args+=( --only-hour "$ONLY_HOUR" ) + pp_args+=( --only-hour "$ONLY_HOUR" ) + fi + + python civ3_day_night.py "${dn_args[@]}" + python civ3_city_lights.py "${cl_args[@]}" + python civ3_postprocess_pixels.py "${pp_args[@]}" + + ### === CLEANUP: remove *_lights.pcx from hour subfolders (excluding annotation dir) === + # If ONLY_HOUR is set, restrict cleanup to that single folder & noon folder; otherwise clean all 4-digit hour folders. + if [[ -n "${ONLY_HOUR}" ]]; then + # Only the specified hour + if [[ -d "$data_dir/$ONLY_HOUR" ]]; then + find "$data_dir/$ONLY_HOUR" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true + fi + # Also clean the noon folder + if [[ -d "$data_dir/$NOON_SUBFOLDER" ]]; then + find "$data_dir/$NOON_SUBFOLDER" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true + fi + else + # All hour-named subfolders under data_dir (e.g., 0000, 0100, ..., 2400) + # Do not touch the external $annotation_dir. + while IFS= read -r -d '' hour_dir; do + find "${hour_dir}" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true + done < <(find "$data_dir" -mindepth 1 -maxdepth 1 -type d -regex '.*/[0-9]{4}$' -print0) + fi +} + +process_art_set "$DAYNIGHT_DATA_DIR" "$DAYNIGHT_ANNOTATION_DIR" +process_art_set "$DISTRICT_DATA_DIR" "$DISTRICT_ANNOTATION_DIR" diff --git a/DayNight/protected_pixels.py b/DayNight/protected_pixels.py index 103ed5d7..15645f32 100644 --- a/DayNight/protected_pixels.py +++ b/DayNight/protected_pixels.py @@ -1,75 +1,75 @@ -# --------------------------- Config: protected coords --------------------------- -# Pixels in these ranges remain unchanged ONLY in files with "EntertainmentComplex" in the name. -# Each entry is ((x1, y1), (x2, y2)) inclusive, typically horizontal runs. -PROTECTED_RANGES_ENT_COMPLEX = [ - # Each row of pairs represents a horizontal line of pixels, giving the illusion of lit ground - - # Ancient colosseum - ((159, 18), (169, 18)), - ((157, 19), (170, 19)), - ((155, 20), (171, 20)), - ((153, 21), (172, 21)), - ((158, 22), (166, 22)), - - # Middle ages colosseum - ((159, 81), (169, 81)), - ((157, 82), (170, 82)), - ((155, 83), (171, 83)), - ((153, 84), (172, 84)), - ((158, 85), (166, 85)), - - # Industrial age stadium - ((165, 147), (171, 147)), - ((163, 148), (171, 148)), - ((161, 149), (175, 149)), - ((159, 150), (176, 150)), - ((158, 151), (178, 151)), - ((155, 152), (180, 152)), - ((157, 151), (178, 151)), - ((155, 152), (181, 152)), - ((154, 153), (182, 153)), - ((152, 154), (183, 154)), - ((151, 155), (184, 155)), - ((149, 156), (185, 156)), - ((148, 157), (184, 157)), - ((146, 158), (186, 158)), - ((146, 159), (186, 159)), - ((145, 160), (185, 160)), - ((146, 161), (185, 161)), - ((147, 162), (184, 162)), - ((148, 163), (183, 163)), - ((151, 164), (178, 164)), - ((155, 165), (176, 165)), - ((157, 166), (175, 166)), - - # Modern age stadium - ((161, 208), (163, 208)), - ((159, 209), (165, 209)), - ((157, 210), (167, 210)), - ((155, 211), (169, 211)), - ((153, 212), (171, 212)), - ((151, 213), (173, 213)), - ((149, 214), (175, 214)), - ((147, 215), (177, 215)), - ((146, 216), (179, 216)), - ((148, 217), (181, 217)), - ((151, 218), (183, 218)), - ((151, 219), (185, 219)), - ((150, 220), (186, 220)), - ((150, 221), (167, 221)), ((169, 221), (184, 221)), # Light key in the middle - ((148, 222), (165, 222)), ((173, 222), (183, 222)), # Stadium light in the middle - ((149, 223), (165, 223)), ((173, 223), (181, 223)), - ((151, 224), (165, 224)), ((173, 224), (179, 224)), - ((151, 225), (165, 225)), ((173, 225), (177, 225)), - ((152, 226), (168, 226)), ((170, 226), (175, 226)), - ((154, 227), (168, 227)), ((170, 227), (174, 227)), - ((155, 228), (168, 228)), ((170, 228), (172, 228)), - ((157, 229), (168, 229)), ((170, 229), (171, 229)), - ((161, 230), (168, 230)), ((170, 230), (172, 230)), - ((163, 231), (168, 231)), ((170, 231), (171, 231)), - ((161, 232), (168, 232)), - ((161, 233), (168, 233)), - ((162, 234), (167, 234)), - ((161, 235), (165, 235)), - ((161, 236), (163, 236)) +# --------------------------- Config: protected coords --------------------------- +# Pixels in these ranges remain unchanged ONLY in files with "EntertainmentComplex" in the name. +# Each entry is ((x1, y1), (x2, y2)) inclusive, typically horizontal runs. +PROTECTED_RANGES_ENT_COMPLEX = [ + # Each row of pairs represents a horizontal line of pixels, giving the illusion of lit ground + + # Ancient colosseum + ((159, 18), (169, 18)), + ((157, 19), (170, 19)), + ((155, 20), (171, 20)), + ((153, 21), (172, 21)), + ((158, 22), (166, 22)), + + # Middle ages colosseum + ((159, 81), (169, 81)), + ((157, 82), (170, 82)), + ((155, 83), (171, 83)), + ((153, 84), (172, 84)), + ((158, 85), (166, 85)), + + # Industrial age stadium + ((165, 147), (171, 147)), + ((163, 148), (171, 148)), + ((161, 149), (175, 149)), + ((159, 150), (176, 150)), + ((158, 151), (178, 151)), + ((155, 152), (180, 152)), + ((157, 151), (178, 151)), + ((155, 152), (181, 152)), + ((154, 153), (182, 153)), + ((152, 154), (183, 154)), + ((151, 155), (184, 155)), + ((149, 156), (185, 156)), + ((148, 157), (184, 157)), + ((146, 158), (186, 158)), + ((146, 159), (186, 159)), + ((145, 160), (185, 160)), + ((146, 161), (185, 161)), + ((147, 162), (184, 162)), + ((148, 163), (183, 163)), + ((151, 164), (178, 164)), + ((155, 165), (176, 165)), + ((157, 166), (175, 166)), + + # Modern age stadium + ((161, 208), (163, 208)), + ((159, 209), (165, 209)), + ((157, 210), (167, 210)), + ((155, 211), (169, 211)), + ((153, 212), (171, 212)), + ((151, 213), (173, 213)), + ((149, 214), (175, 214)), + ((147, 215), (177, 215)), + ((146, 216), (179, 216)), + ((148, 217), (181, 217)), + ((151, 218), (183, 218)), + ((151, 219), (185, 219)), + ((150, 220), (186, 220)), + ((150, 221), (167, 221)), ((169, 221), (184, 221)), # Light key in the middle + ((148, 222), (165, 222)), ((173, 222), (183, 222)), # Stadium light in the middle + ((149, 223), (165, 223)), ((173, 223), (181, 223)), + ((151, 224), (165, 224)), ((173, 224), (179, 224)), + ((151, 225), (165, 225)), ((173, 225), (177, 225)), + ((152, 226), (168, 226)), ((170, 226), (175, 226)), + ((154, 227), (168, 227)), ((170, 227), (174, 227)), + ((155, 228), (168, 228)), ((170, 228), (172, 228)), + ((157, 229), (168, 229)), ((170, 229), (171, 229)), + ((161, 230), (168, 230)), ((170, 230), (172, 230)), + ((163, 231), (168, 231)), ((170, 231), (171, 231)), + ((161, 232), (168, 232)), + ((161, 233), (168, 233)), + ((162, 234), (167, 234)), + ((161, 235), (165, 235)), + ((161, 236), (163, 236)) ] \ No newline at end of file diff --git a/DayNight/swap_green_magenta_indices.py b/DayNight/swap_green_magenta_indices.py index 8c71412d..f2cbf8ca 100644 --- a/DayNight/swap_green_magenta_indices.py +++ b/DayNight/swap_green_magenta_indices.py @@ -1,113 +1,113 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import argparse -from pathlib import Path -from typing import List, Tuple, Optional - -from PIL import Image - -GREEN = (0, 255, 0) # #00ff00 -MAGENTA = (255, 0, 255) # #ff00ff -GREEN_TARGET_IDX = 254 -MAGENTA_TARGET_IDX = 255 - -def chunk_palette(pal: List[int]) -> List[Tuple[int, int, int]]: - """Convert flat [r,g,b,...] list to list of 256 (r,g,b) tuples.""" - return [(pal[i], pal[i+1], pal[i+2]) for i in range(0, 256*3, 3)] - -def flatten_palette(pal_tuples: List[Tuple[int, int, int]]) -> List[int]: - """Convert list of (r,g,b) tuples back to flat list.""" - flat: List[int] = [] - for r, g, b in pal_tuples: - flat.extend([r, g, b]) - return flat - -def find_color_index(pal_tuples: List[Tuple[int, int, int]], color: Tuple[int, int, int]) -> Optional[int]: - """Return first index of exact color match, else None.""" - try: - return pal_tuples.index(color) - except ValueError: - return None - -def compute_mapping(idx_green: int, idx_magenta: int) -> List[int]: - """ - Build a 256-length LUT mapping old index -> new index so that: - - old idx_green goes to GREEN_TARGET_IDX - - old GREEN_TARGET_IDX goes to idx_green - - old idx_magenta goes to MAGENTA_TARGET_IDX - - old MAGENTA_TARGET_IDX goes to idx_magenta - Other indices map to themselves. - Handles overlap cases gracefully (e.g., green already at 254, magenta already at 255, - or the two are swapped). - """ - lut = list(range(256)) - # Swap pair for green <-> 254 - lut[idx_green] = GREEN_TARGET_IDX - lut[GREEN_TARGET_IDX] = idx_green - - # Swap pair for magenta <-> 255 - lut[idx_magenta] = MAGENTA_TARGET_IDX - lut[MAGENTA_TARGET_IDX] = idx_magenta - - return lut - -def remap_palette(old_pal: List[Tuple[int, int, int]], lut: List[int]) -> List[Tuple[int, int, int]]: - """ - Produce a new palette consistent with the index remap. - If pixels with old index i become new index lut[i], - then new_palette[lut[i]] should equal old_palette[i]. - """ - new_pal = [(0, 0, 0)] * 256 - for old_idx, rgb in enumerate(old_pal): - new_idx = lut[old_idx] - new_pal[new_idx] = rgb - return new_pal - -def process(path: Path) -> None: - with Image.open(path) as im: - if im.mode != "P": - raise ValueError(f"{path} is mode '{im.mode}', not paletted 'P'. Aborting to avoid altering colors.") - pal = im.getpalette() - if pal is None: - raise ValueError("Image has no palette.") - if len(pal) < 256 * 3: - raise ValueError(f"Palette has {len(pal)//3} colors, but 256 are required.") - pal_tuples = chunk_palette(pal) - - idx_green = find_color_index(pal_tuples, GREEN) - idx_magenta = find_color_index(pal_tuples, MAGENTA) - if idx_green is None: - raise ValueError("Exact green #00ff00 not found in palette.") - if idx_magenta is None: - raise ValueError("Exact magenta #ff00ff not found in palette.") - - # Build pixel index remap LUT (length 256) - lut = compute_mapping(idx_green, idx_magenta) - - # Remap pixel indices using Image.point(LUT) - # point() expects a 256-length sequence for 'P' images. - im_remapped = im.point(lut) - - # Reorder the palette to match the remapped indices - new_pal_tuples = remap_palette(pal_tuples, lut) - new_pal_flat = flatten_palette(new_pal_tuples) - im_remapped.putpalette(new_pal_flat) - - # Sanity check: confirm targets are now correct - final_pal = chunk_palette(im_remapped.getpalette()) - assert final_pal[GREEN_TARGET_IDX] == GREEN, "Post-remap sanity check failed for green at index 254." - assert final_pal[MAGENTA_TARGET_IDX] == MAGENTA, "Post-remap sanity check failed for magenta at index 255." - - # Overwrite the original file - im_remapped.save(path, format="PCX") - -def main(): - parser = argparse.ArgumentParser(description="Swap #00ff00 and #ff00ff into palette indices 254 and 255 in a 256-color PCX, remapping pixels and palette accordingly.") - parser.add_argument("pcx_path", type=Path, help="Path to the .pcx file") - args = parser.parse_args() - - process(args.pcx_path) - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import argparse +from pathlib import Path +from typing import List, Tuple, Optional + +from PIL import Image + +GREEN = (0, 255, 0) # #00ff00 +MAGENTA = (255, 0, 255) # #ff00ff +GREEN_TARGET_IDX = 254 +MAGENTA_TARGET_IDX = 255 + +def chunk_palette(pal: List[int]) -> List[Tuple[int, int, int]]: + """Convert flat [r,g,b,...] list to list of 256 (r,g,b) tuples.""" + return [(pal[i], pal[i+1], pal[i+2]) for i in range(0, 256*3, 3)] + +def flatten_palette(pal_tuples: List[Tuple[int, int, int]]) -> List[int]: + """Convert list of (r,g,b) tuples back to flat list.""" + flat: List[int] = [] + for r, g, b in pal_tuples: + flat.extend([r, g, b]) + return flat + +def find_color_index(pal_tuples: List[Tuple[int, int, int]], color: Tuple[int, int, int]) -> Optional[int]: + """Return first index of exact color match, else None.""" + try: + return pal_tuples.index(color) + except ValueError: + return None + +def compute_mapping(idx_green: int, idx_magenta: int) -> List[int]: + """ + Build a 256-length LUT mapping old index -> new index so that: + - old idx_green goes to GREEN_TARGET_IDX + - old GREEN_TARGET_IDX goes to idx_green + - old idx_magenta goes to MAGENTA_TARGET_IDX + - old MAGENTA_TARGET_IDX goes to idx_magenta + Other indices map to themselves. + Handles overlap cases gracefully (e.g., green already at 254, magenta already at 255, + or the two are swapped). + """ + lut = list(range(256)) + # Swap pair for green <-> 254 + lut[idx_green] = GREEN_TARGET_IDX + lut[GREEN_TARGET_IDX] = idx_green + + # Swap pair for magenta <-> 255 + lut[idx_magenta] = MAGENTA_TARGET_IDX + lut[MAGENTA_TARGET_IDX] = idx_magenta + + return lut + +def remap_palette(old_pal: List[Tuple[int, int, int]], lut: List[int]) -> List[Tuple[int, int, int]]: + """ + Produce a new palette consistent with the index remap. + If pixels with old index i become new index lut[i], + then new_palette[lut[i]] should equal old_palette[i]. + """ + new_pal = [(0, 0, 0)] * 256 + for old_idx, rgb in enumerate(old_pal): + new_idx = lut[old_idx] + new_pal[new_idx] = rgb + return new_pal + +def process(path: Path) -> None: + with Image.open(path) as im: + if im.mode != "P": + raise ValueError(f"{path} is mode '{im.mode}', not paletted 'P'. Aborting to avoid altering colors.") + pal = im.getpalette() + if pal is None: + raise ValueError("Image has no palette.") + if len(pal) < 256 * 3: + raise ValueError(f"Palette has {len(pal)//3} colors, but 256 are required.") + pal_tuples = chunk_palette(pal) + + idx_green = find_color_index(pal_tuples, GREEN) + idx_magenta = find_color_index(pal_tuples, MAGENTA) + if idx_green is None: + raise ValueError("Exact green #00ff00 not found in palette.") + if idx_magenta is None: + raise ValueError("Exact magenta #ff00ff not found in palette.") + + # Build pixel index remap LUT (length 256) + lut = compute_mapping(idx_green, idx_magenta) + + # Remap pixel indices using Image.point(LUT) + # point() expects a 256-length sequence for 'P' images. + im_remapped = im.point(lut) + + # Reorder the palette to match the remapped indices + new_pal_tuples = remap_palette(pal_tuples, lut) + new_pal_flat = flatten_palette(new_pal_tuples) + im_remapped.putpalette(new_pal_flat) + + # Sanity check: confirm targets are now correct + final_pal = chunk_palette(im_remapped.getpalette()) + assert final_pal[GREEN_TARGET_IDX] == GREEN, "Post-remap sanity check failed for green at index 254." + assert final_pal[MAGENTA_TARGET_IDX] == MAGENTA, "Post-remap sanity check failed for magenta at index 255." + + # Overwrite the original file + im_remapped.save(path, format="PCX") + +def main(): + parser = argparse.ArgumentParser(description="Swap #00ff00 and #ff00ff into palette indices 254 and 255 in a 256-color PCX, remapping pixels and palette accordingly.") + parser.add_argument("pcx_path", type=Path, help="Path to the .pcx file") + args = parser.parse_args() + + process(args.pcx_path) + +if __name__ == "__main__": + main() diff --git a/Ghidra scripts/Civ3TypesFromHeader.py b/Ghidra scripts/Civ3TypesFromHeader.py index cf9517cf..f493e034 100644 --- a/Ghidra scripts/Civ3TypesFromHeader.py +++ b/Ghidra scripts/Civ3TypesFromHeader.py @@ -1,300 +1,300 @@ -#Script to read in type info from Civ3Conquests.h -#@author -#@category _NEW_ -#@keybinding -#@menupath -#@toolbar - -# IMPORTANT NOTE if you're using this script for the first time in a new project. You need to copy certain -# Windows types (HBITMAP, etc.) from Ghidra's VS category into the Civ3Conquests.exe category otherwise -# getDataTypes won't be able to find them. Specifically, you need to copy over the subcategories "wingdi.h" -# and "WinDef.h". I took them from windows_vs12_32 but it probably works with other VS versions too. - -import re - -from ghidra.program.model.data import DataTypeManager, CategoryPath, ArrayDataType, PointerDataType, StructureDataType - -decl = re.compile (r"(\w+) (\w+);") -array_decl = re.compile (r"(\w+) (\w+)\[(\d+)\];") -ptr_decl = re.compile (r"(\w+) \*(\w+);") -ptr_ptr_decl = re.compile (r"(\w+) \*\*(\w+);") -arr_ptr_decl = re.compile (r"(\w+) \*(\w+)\[(\d+)\];") - -int_type = getDataTypes ("int")[0] -int_array_type = ArrayDataType (int_type, 5, 4) # DataType, NumElements, ElementLength -int_ptr_type = PointerDataType (int_type) -generic_ptr_type = PointerDataType () - -# If try_get_type is set to true, returns None instead of raising an exception on failure. -known_types = {} -def get_type (name, try_get_type=False): - if name in known_types: - return known_types[name] - else: - types = getDataTypes (name) - L = len (types) - if L == 1: - known_types[name] = types[0] - return types[0] - elif try_get_type: - return None - elif L > 1: - raise Exception ("Ambiguous type name: \"" + name + "\"") - else: - raise Exception ("Unknown type name: \"" + name + "\"") - -def get_pointer_type (name): - if name != "void": - return PointerDataType (get_type (name)) - else: - return PointerDataType () - -def trim_struct_name (name): - if name.startswith ("struct_"): - return name[7:] - elif name.startswith ("class_"): - return name[6:] - else: - return name - -# print (dir (currentProgram.getDataTypeManager ())) -# print (dir (currentProgram.getDataTypeManager ().getRootCategory ())) -# print (currentProgram.getDataTypeManager ().getRootCategory ().getCategories ()) -# print ("===") -# print (currentProgram.getDataTypeManager ().getDataTypes ("HBITMAP")) -# x = get_type ("HBITMAP") -dtm = currentProgram.getDataTypeManager () -# print (cat) -# for n in range (dtm.getCategoryCount ()): -# print (currentProgram.getDataTypeManager ().getCategory (n)) -# print (currentProgram.getDataTypeManager ().getDataType ("windows_vs12_32/", "HBITMAP")) - - -# dtm = currentProgram.getDataTypeManager () -# transaction = dtm.startTransaction ("Test categories") -# cat = dtm.createCategory (CategoryPath ("/TestCreateCategory")) -# ss = StructureDataType ("TestRecursiveStruct", 0) -# pss = PointerDataType (ss) -# ss.add (pss, "node", "recursive reference") -# cat.addDataType (ss, None) -# dtm.endTransaction (transaction, True) -# raise Exception ("stop here") - -# print (Array) -# print (len (getDataTypes ("Difficulty[5]"))) -# print (len (getDataTypes ("Difficulty *"))) - - - -# diff = getDataTypes ("Difficulty")[0] -# print (dir (diff)) -# newcomp = diff.add (generic_ptr_type, "testing_add_void_ptr_comp", "Hopefully this is a void *.") -# print (dir (newcomp)) -# raise Exception ("done now") - - -filepath = askString ("Enter path to file containing declarations", "Filepath:") -# cat_name = askString ("Enter name for destination category", "Category name:") - - -# Open file, split into lines, strip them, and discard empty and comment ones -lines = [] -with open (filepath, "r") as f: - for L in f.read ().split ("\n"): - L = L.strip () - if (len (L) > 0) and not L.startswith ("//"): - lines.append (L) - -# Each component is a tuple of four items: (kind, base, name, param). kind can be "simple", "array", -# "pointer", or "array of pointers". simple types only have a base type and name; pointer types -# use the 'param' to store the number of levels of indirection; arrays use 'param' to store the -# array count. Examples: -# int x; --> ("simple", "int", "x", None) -# char name[24]; --> ("array", "char", "name", 24) -# Foo *f; --> ("pointer", "Foo", "f", 1) -# Foo **f; --> ("pointer", "Foo", "f", 2) -# short *fs[2]; --> ("array of pointers", "short", "fs", 2) -# The point of parsing into this components form before creating the DataTypes is so that we can -# sort the list of struct by dependency. -def parse_components (lines): - tr = [] - for line in lines: - m = re.match (decl, line) - if m is not None: - # comps.append ((get_type (m.group (1)), m.group (2))) - tr.append (("simple", trim_struct_name (m.group (1)), m.group (2), None)) - continue - m = re.match (array_decl, line) - if m is not None: - # t = get_type (m.group (1)) - # comps.append ((ArrayDataType (t, int (m.group (3)), t.getLength ()), m.group (2))) - tr.append (("array", trim_struct_name (m.group (1)), m.group (2), int (m.group (3)))) - continue - m = re.match (ptr_decl, line) - if m is not None: - # t = PointerDataType (get_type (m.group (1))) if m.group (1) != "void" else PointerDataType () - # comps.append ((t, m.group (2))) - tr.append (("pointer", trim_struct_name (m.group (1)), m.group (2), 1)) - continue - m = re.match (ptr_ptr_decl, line) - if m is not None: - tr.append (("pointer", trim_struct_name (m.group (1)), m.group (2), 2)) - continue - m = re.match (arr_ptr_decl, line) - if m is not None: - tr.append (("array of pointers", trim_struct_name (m.group (1)), m.group (2), int (m.group (3)))) - continue - raise Exception ("The following line didn't match any pattern:\n\t" + line) - return tr - -# Find all structs in the file. Each entry in this list is a tuple of (name, is_union, components) -def extract_structs (lines): - tr = [] - n = 0 - while n < len (lines): - is_union = lines[n].startswith ("union ") - if lines[n].startswith ("struct ") or is_union: - struct_name = trim_struct_name (lines[n].split (" ")[1]) - if lines[n+1] != "{": raise Exception ("Expected '{' after struct") - n += 2 - struct_lines = [] - while lines[n] != "};": - struct_lines.append (lines[n]) - n += 1 - tr.append ((struct_name, is_union, parse_components (struct_lines))) - elif lines[n].startswith ("enum "): - # ignore enums for now - if lines[n+1] != "{": raise Exception ("Expected '{' after enum") - n += 2 - while lines[n] != "};": - n += 1 - else: - raise Exception ("Invalid line (expected struct or enum):\n\t" + lines[n]) - n += 1 - return tr - -structs = extract_structs (lines) - -def find_unknown_types (structs): - struct_names = {} - tr = [] - for s in structs: - struct_names[s[0]] = True - for s in structs: - struct_name, is_union, comps = s - for c in comps: - kind, base, comp_name, param = c - if (base != "void") and (base not in struct_names) and (get_type (base, True) is None): - tr.append (struct_name + "." + comp_name) - return tr - -unknown_types = find_unknown_types (structs) -if len (unknown_types) > 0: - print ("Couldn't get types for the following struct members:\n\t" + "\n\t".join (unknown_types)) - raise Exception ("Unknown or ambiguous types") - -# Returns list of structs sorted by dependency, i.e., the list reordered so that every struct B that's -# dependent on the definition of some struct A comes after A in the list. Assumes all structs are -# forward declared, i.e., if one refers to another through a pointer that doesn't count as a dependency. -def sort_structs_by_dependency (structs): - tr = [] - sorted_structs = {} - cant_satisfy_deps = lambda (sym): (sym != "void") and (sym not in sorted_structs) and (get_type (sym, True) is None) - while True: - sorted_any_this_pass = False - for s in structs: - struct_name, is_union, comps = s - if struct_name not in sorted_structs: - can_append = True - for c in comps: - kind, base, name, param = c - if (kind == "simple" or kind == "array") and cant_satisfy_deps (base): - can_append = False - break - if can_append: - tr.append (s) - sorted_structs[struct_name] = True - sorted_any_this_pass = True - # if done - if len (sorted_structs.keys ()) == len (structs): # done - break - # if not done and failed to sort any this pass - elif not sorted_any_this_pass: - raise Exception ("Some structs contain invalid (ambiguous, unknown) types or circular dependencies") - # else proceed to next pass - return tr - -structs = sort_structs_by_dependency (structs) - -# Quick and dirty code to just print the struct decls out in sorted order. Had to rewrite the sorting function -# because otherwise all dependencies are solved by the program's database (all these have already been imported -# after all). -# -# def sort_by_deps_2 (structs): -# tr = [] -# sorted_structs = {} -# unsorted_structs = {s[0] : True for s in structs} -# while True: -# sorted_any_this_pass = False -# for s in structs: -# struct_name, is_union, comps = s -# if struct_name not in sorted_structs: -# can_append = True -# for c in comps: -# kind, base, name, param = c -# if (kind == "simple" or kind == "array") and base in unsorted_structs: -# can_append = False -# break -# if can_append: -# tr.append (s) -# sorted_structs[struct_name] = True -# unsorted_structs.pop (struct_name) -# sorted_any_this_pass = True -# if len (tr) == len (structs): -# break -# elif not sorted_any_this_pass: -# raise Exception ("Failed to sort some structs") -# return tr -# structs = sort_by_deps_2 (structs) -# for s in structs: -# struct_name, is_union, comps = s -# t = "struct" if not is_union else "union" -# print (t + " " + struct_name) -# raise Exception ("Stop here") - -# Create all struct types first before filling them in so that recursive references work -struct_types = {} -for s in structs: - struct_name, is_union, comps = s - struct_types[struct_name] = StructureDataType (struct_name, 0) - known_types[struct_name] = struct_types[struct_name] - -# Fill in all struct components -for s in structs: - struct_name, is_union, comps = s - st = struct_types[struct_name] - for c in comps: - kind, base, comp_name, param = c - if kind == "simple": - st.add (get_type (base), comp_name, "") - elif kind == "array": - t = get_type (base) - st.add (ArrayDataType (t, param, t.getLength ()), comp_name, "") - elif kind == "pointer": - p = get_pointer_type (base) - for n in range (param - 1): - p = PointerDataType (p) - st.add (p, comp_name, "") - elif kind == "array of pointers": - p = get_pointer_type (base) - st.add (ArrayDataType (p, param, p.getLength ()), comp_name, "") - -# Add the structs to the type database -# Adding to a category doesn't work, it just dumps all the types in the main program category too. -# I can't be bothered to figure out how to make it work. -transaction = dtm.startTransaction ("Add structs from " + filepath) -# cat = dtm.createCategory (CategoryPath ("/" + cat_name)) -for s in struct_types.values (): - dtm.addDataType (s, None) -dtm.endTransaction (transaction, True) - +#Script to read in type info from Civ3Conquests.h +#@author +#@category _NEW_ +#@keybinding +#@menupath +#@toolbar + +# IMPORTANT NOTE if you're using this script for the first time in a new project. You need to copy certain +# Windows types (HBITMAP, etc.) from Ghidra's VS category into the Civ3Conquests.exe category otherwise +# getDataTypes won't be able to find them. Specifically, you need to copy over the subcategories "wingdi.h" +# and "WinDef.h". I took them from windows_vs12_32 but it probably works with other VS versions too. + +import re + +from ghidra.program.model.data import DataTypeManager, CategoryPath, ArrayDataType, PointerDataType, StructureDataType + +decl = re.compile (r"(\w+) (\w+);") +array_decl = re.compile (r"(\w+) (\w+)\[(\d+)\];") +ptr_decl = re.compile (r"(\w+) \*(\w+);") +ptr_ptr_decl = re.compile (r"(\w+) \*\*(\w+);") +arr_ptr_decl = re.compile (r"(\w+) \*(\w+)\[(\d+)\];") + +int_type = getDataTypes ("int")[0] +int_array_type = ArrayDataType (int_type, 5, 4) # DataType, NumElements, ElementLength +int_ptr_type = PointerDataType (int_type) +generic_ptr_type = PointerDataType () + +# If try_get_type is set to true, returns None instead of raising an exception on failure. +known_types = {} +def get_type (name, try_get_type=False): + if name in known_types: + return known_types[name] + else: + types = getDataTypes (name) + L = len (types) + if L == 1: + known_types[name] = types[0] + return types[0] + elif try_get_type: + return None + elif L > 1: + raise Exception ("Ambiguous type name: \"" + name + "\"") + else: + raise Exception ("Unknown type name: \"" + name + "\"") + +def get_pointer_type (name): + if name != "void": + return PointerDataType (get_type (name)) + else: + return PointerDataType () + +def trim_struct_name (name): + if name.startswith ("struct_"): + return name[7:] + elif name.startswith ("class_"): + return name[6:] + else: + return name + +# print (dir (currentProgram.getDataTypeManager ())) +# print (dir (currentProgram.getDataTypeManager ().getRootCategory ())) +# print (currentProgram.getDataTypeManager ().getRootCategory ().getCategories ()) +# print ("===") +# print (currentProgram.getDataTypeManager ().getDataTypes ("HBITMAP")) +# x = get_type ("HBITMAP") +dtm = currentProgram.getDataTypeManager () +# print (cat) +# for n in range (dtm.getCategoryCount ()): +# print (currentProgram.getDataTypeManager ().getCategory (n)) +# print (currentProgram.getDataTypeManager ().getDataType ("windows_vs12_32/", "HBITMAP")) + + +# dtm = currentProgram.getDataTypeManager () +# transaction = dtm.startTransaction ("Test categories") +# cat = dtm.createCategory (CategoryPath ("/TestCreateCategory")) +# ss = StructureDataType ("TestRecursiveStruct", 0) +# pss = PointerDataType (ss) +# ss.add (pss, "node", "recursive reference") +# cat.addDataType (ss, None) +# dtm.endTransaction (transaction, True) +# raise Exception ("stop here") + +# print (Array) +# print (len (getDataTypes ("Difficulty[5]"))) +# print (len (getDataTypes ("Difficulty *"))) + + + +# diff = getDataTypes ("Difficulty")[0] +# print (dir (diff)) +# newcomp = diff.add (generic_ptr_type, "testing_add_void_ptr_comp", "Hopefully this is a void *.") +# print (dir (newcomp)) +# raise Exception ("done now") + + +filepath = askString ("Enter path to file containing declarations", "Filepath:") +# cat_name = askString ("Enter name for destination category", "Category name:") + + +# Open file, split into lines, strip them, and discard empty and comment ones +lines = [] +with open (filepath, "r") as f: + for L in f.read ().split ("\n"): + L = L.strip () + if (len (L) > 0) and not L.startswith ("//"): + lines.append (L) + +# Each component is a tuple of four items: (kind, base, name, param). kind can be "simple", "array", +# "pointer", or "array of pointers". simple types only have a base type and name; pointer types +# use the 'param' to store the number of levels of indirection; arrays use 'param' to store the +# array count. Examples: +# int x; --> ("simple", "int", "x", None) +# char name[24]; --> ("array", "char", "name", 24) +# Foo *f; --> ("pointer", "Foo", "f", 1) +# Foo **f; --> ("pointer", "Foo", "f", 2) +# short *fs[2]; --> ("array of pointers", "short", "fs", 2) +# The point of parsing into this components form before creating the DataTypes is so that we can +# sort the list of struct by dependency. +def parse_components (lines): + tr = [] + for line in lines: + m = re.match (decl, line) + if m is not None: + # comps.append ((get_type (m.group (1)), m.group (2))) + tr.append (("simple", trim_struct_name (m.group (1)), m.group (2), None)) + continue + m = re.match (array_decl, line) + if m is not None: + # t = get_type (m.group (1)) + # comps.append ((ArrayDataType (t, int (m.group (3)), t.getLength ()), m.group (2))) + tr.append (("array", trim_struct_name (m.group (1)), m.group (2), int (m.group (3)))) + continue + m = re.match (ptr_decl, line) + if m is not None: + # t = PointerDataType (get_type (m.group (1))) if m.group (1) != "void" else PointerDataType () + # comps.append ((t, m.group (2))) + tr.append (("pointer", trim_struct_name (m.group (1)), m.group (2), 1)) + continue + m = re.match (ptr_ptr_decl, line) + if m is not None: + tr.append (("pointer", trim_struct_name (m.group (1)), m.group (2), 2)) + continue + m = re.match (arr_ptr_decl, line) + if m is not None: + tr.append (("array of pointers", trim_struct_name (m.group (1)), m.group (2), int (m.group (3)))) + continue + raise Exception ("The following line didn't match any pattern:\n\t" + line) + return tr + +# Find all structs in the file. Each entry in this list is a tuple of (name, is_union, components) +def extract_structs (lines): + tr = [] + n = 0 + while n < len (lines): + is_union = lines[n].startswith ("union ") + if lines[n].startswith ("struct ") or is_union: + struct_name = trim_struct_name (lines[n].split (" ")[1]) + if lines[n+1] != "{": raise Exception ("Expected '{' after struct") + n += 2 + struct_lines = [] + while lines[n] != "};": + struct_lines.append (lines[n]) + n += 1 + tr.append ((struct_name, is_union, parse_components (struct_lines))) + elif lines[n].startswith ("enum "): + # ignore enums for now + if lines[n+1] != "{": raise Exception ("Expected '{' after enum") + n += 2 + while lines[n] != "};": + n += 1 + else: + raise Exception ("Invalid line (expected struct or enum):\n\t" + lines[n]) + n += 1 + return tr + +structs = extract_structs (lines) + +def find_unknown_types (structs): + struct_names = {} + tr = [] + for s in structs: + struct_names[s[0]] = True + for s in structs: + struct_name, is_union, comps = s + for c in comps: + kind, base, comp_name, param = c + if (base != "void") and (base not in struct_names) and (get_type (base, True) is None): + tr.append (struct_name + "." + comp_name) + return tr + +unknown_types = find_unknown_types (structs) +if len (unknown_types) > 0: + print ("Couldn't get types for the following struct members:\n\t" + "\n\t".join (unknown_types)) + raise Exception ("Unknown or ambiguous types") + +# Returns list of structs sorted by dependency, i.e., the list reordered so that every struct B that's +# dependent on the definition of some struct A comes after A in the list. Assumes all structs are +# forward declared, i.e., if one refers to another through a pointer that doesn't count as a dependency. +def sort_structs_by_dependency (structs): + tr = [] + sorted_structs = {} + cant_satisfy_deps = lambda (sym): (sym != "void") and (sym not in sorted_structs) and (get_type (sym, True) is None) + while True: + sorted_any_this_pass = False + for s in structs: + struct_name, is_union, comps = s + if struct_name not in sorted_structs: + can_append = True + for c in comps: + kind, base, name, param = c + if (kind == "simple" or kind == "array") and cant_satisfy_deps (base): + can_append = False + break + if can_append: + tr.append (s) + sorted_structs[struct_name] = True + sorted_any_this_pass = True + # if done + if len (sorted_structs.keys ()) == len (structs): # done + break + # if not done and failed to sort any this pass + elif not sorted_any_this_pass: + raise Exception ("Some structs contain invalid (ambiguous, unknown) types or circular dependencies") + # else proceed to next pass + return tr + +structs = sort_structs_by_dependency (structs) + +# Quick and dirty code to just print the struct decls out in sorted order. Had to rewrite the sorting function +# because otherwise all dependencies are solved by the program's database (all these have already been imported +# after all). +# +# def sort_by_deps_2 (structs): +# tr = [] +# sorted_structs = {} +# unsorted_structs = {s[0] : True for s in structs} +# while True: +# sorted_any_this_pass = False +# for s in structs: +# struct_name, is_union, comps = s +# if struct_name not in sorted_structs: +# can_append = True +# for c in comps: +# kind, base, name, param = c +# if (kind == "simple" or kind == "array") and base in unsorted_structs: +# can_append = False +# break +# if can_append: +# tr.append (s) +# sorted_structs[struct_name] = True +# unsorted_structs.pop (struct_name) +# sorted_any_this_pass = True +# if len (tr) == len (structs): +# break +# elif not sorted_any_this_pass: +# raise Exception ("Failed to sort some structs") +# return tr +# structs = sort_by_deps_2 (structs) +# for s in structs: +# struct_name, is_union, comps = s +# t = "struct" if not is_union else "union" +# print (t + " " + struct_name) +# raise Exception ("Stop here") + +# Create all struct types first before filling them in so that recursive references work +struct_types = {} +for s in structs: + struct_name, is_union, comps = s + struct_types[struct_name] = StructureDataType (struct_name, 0) + known_types[struct_name] = struct_types[struct_name] + +# Fill in all struct components +for s in structs: + struct_name, is_union, comps = s + st = struct_types[struct_name] + for c in comps: + kind, base, comp_name, param = c + if kind == "simple": + st.add (get_type (base), comp_name, "") + elif kind == "array": + t = get_type (base) + st.add (ArrayDataType (t, param, t.getLength ()), comp_name, "") + elif kind == "pointer": + p = get_pointer_type (base) + for n in range (param - 1): + p = PointerDataType (p) + st.add (p, comp_name, "") + elif kind == "array of pointers": + p = get_pointer_type (base) + st.add (ArrayDataType (p, param, p.getLength ()), comp_name, "") + +# Add the structs to the type database +# Adding to a category doesn't work, it just dumps all the types in the main program category too. +# I can't be bothered to figure out how to make it work. +transaction = dtm.startTransaction ("Add structs from " + filepath) +# cat = dtm.createCategory (CategoryPath ("/" + cat_name)) +for s in struct_types.values (): + dtm.addDataType (s, None) +dtm.endTransaction (transaction, True) + diff --git a/Ghidra scripts/ExportProgForPython.py b/Ghidra scripts/ExportProgForPython.py index 124990d5..83791620 100644 --- a/Ghidra scripts/ExportProgForPython.py +++ b/Ghidra scripts/ExportProgForPython.py @@ -1,104 +1,104 @@ -# ExportProgForPython.py -# Exports all functions from a Ghidra project to a JSON file for easy consumption by Python scripts -#@author Claude -#@category Export -#@keybinding ctrl shift E -#@menupath Tools.Export.Functions For Python -#@toolbar - -import json -import os -from ghidra.program.model.listing import CodeUnit -from ghidra.util.task import TaskMonitor - -def get_function_bytes(func): - """Gets the raw bytes of a function""" - result = [] - minAddr = func.getEntryPoint() - maxAddr = func.getBody().getMaxAddress() - - currentAddr = minAddr - while currentAddr <= maxAddr and currentAddr is not None: - if func.getBody().contains(currentAddr): - byte_value = getByte(currentAddr) - result.append(byte_value & 0xff) # Convert to unsigned byte - currentAddr = currentAddr.next() - - return result - -def get_function_disassembly(func): - """Gets the disassembled instructions of a function""" - listing = currentProgram.getListing() - disasm = [] - - minAddr = func.getEntryPoint() - maxAddr = func.getBody().getMaxAddress() - - currentAddr = minAddr - while currentAddr <= maxAddr and currentAddr is not None: - if func.getBody().contains(currentAddr): - instr = listing.getCodeUnitAt(currentAddr) - if instr is not None: - disasm.append({ - "address": str(instr.getAddress()), - "instruction": instr.toString() - }) - if instr.getLength() > 1: - currentAddr = currentAddr.add(instr.getLength() - 1) - currentAddr = currentAddr.next() - - return disasm - -def count_references(func): - """Counts the references to a function""" - ref_count = 0 - refManager = currentProgram.getReferenceManager() - references = refManager.getReferencesTo(func.getEntryPoint()) - - for ref in references: - if ref.getReferenceType().isCall() or ref.getReferenceType().isJump(): - ref_count += 1 - - return ref_count - -def run(): - output_file = askFile("Select Output File", "Save") - - monitor.setMessage("Exporting functions...") - - # Get all functions - function_manager = currentProgram.getFunctionManager() - functions = function_manager.getFunctions(True) # True to get all functions - - results = [] - - for func in functions: - monitor.setMessage("Processing " + func.getName()) - - # Get function details - try: - function_data = { - "name": func.getName(), - "address": str(func.getEntryPoint()), - "raw_bytes": get_function_bytes(func), - "disassembly": get_function_disassembly(func), - "reference_count": count_references(func) - } - except: - print("Error processing function at {}".format(func.getEntryPoint())) - continue - - results.append(function_data) - - # Check if the task has been cancelled - if monitor.isCancelled(): - break - - # Write the results to a JSON file - with open(output_file.getAbsolutePath(), 'w') as f: - json.dump(results, f, indent=2) - - print("Exported {} functions to {}".format(len(results), output_file.getAbsolutePath())) - -# Run the script -run() +# ExportProgForPython.py +# Exports all functions from a Ghidra project to a JSON file for easy consumption by Python scripts +#@author Claude +#@category Export +#@keybinding ctrl shift E +#@menupath Tools.Export.Functions For Python +#@toolbar + +import json +import os +from ghidra.program.model.listing import CodeUnit +from ghidra.util.task import TaskMonitor + +def get_function_bytes(func): + """Gets the raw bytes of a function""" + result = [] + minAddr = func.getEntryPoint() + maxAddr = func.getBody().getMaxAddress() + + currentAddr = minAddr + while currentAddr <= maxAddr and currentAddr is not None: + if func.getBody().contains(currentAddr): + byte_value = getByte(currentAddr) + result.append(byte_value & 0xff) # Convert to unsigned byte + currentAddr = currentAddr.next() + + return result + +def get_function_disassembly(func): + """Gets the disassembled instructions of a function""" + listing = currentProgram.getListing() + disasm = [] + + minAddr = func.getEntryPoint() + maxAddr = func.getBody().getMaxAddress() + + currentAddr = minAddr + while currentAddr <= maxAddr and currentAddr is not None: + if func.getBody().contains(currentAddr): + instr = listing.getCodeUnitAt(currentAddr) + if instr is not None: + disasm.append({ + "address": str(instr.getAddress()), + "instruction": instr.toString() + }) + if instr.getLength() > 1: + currentAddr = currentAddr.add(instr.getLength() - 1) + currentAddr = currentAddr.next() + + return disasm + +def count_references(func): + """Counts the references to a function""" + ref_count = 0 + refManager = currentProgram.getReferenceManager() + references = refManager.getReferencesTo(func.getEntryPoint()) + + for ref in references: + if ref.getReferenceType().isCall() or ref.getReferenceType().isJump(): + ref_count += 1 + + return ref_count + +def run(): + output_file = askFile("Select Output File", "Save") + + monitor.setMessage("Exporting functions...") + + # Get all functions + function_manager = currentProgram.getFunctionManager() + functions = function_manager.getFunctions(True) # True to get all functions + + results = [] + + for func in functions: + monitor.setMessage("Processing " + func.getName()) + + # Get function details + try: + function_data = { + "name": func.getName(), + "address": str(func.getEntryPoint()), + "raw_bytes": get_function_bytes(func), + "disassembly": get_function_disassembly(func), + "reference_count": count_references(func) + } + except: + print("Error processing function at {}".format(func.getEntryPoint())) + continue + + results.append(function_data) + + # Check if the task has been cancelled + if monitor.isCancelled(): + break + + # Write the results to a JSON file + with open(output_file.getAbsolutePath(), 'w') as f: + json.dump(results, f, indent=2) + + print("Exported {} functions to {}".format(len(results), output_file.getAbsolutePath())) + +# Run the script +run() diff --git a/Ghidra scripts/ListReturnAddresses.py b/Ghidra scripts/ListReturnAddresses.py index 3df3983b..13e52479 100644 --- a/Ghidra scripts/ListReturnAddresses.py +++ b/Ghidra scripts/ListReturnAddresses.py @@ -1,61 +1,61 @@ -# List all return addresses for a given function -# @author Claude -# @category Analysis -# @keybinding -# @menupath -# @toolbar - -from ghidra.program.model.symbol import RefType - -def main(): - # Get the current function or prompt user to select one - current_function = getFunctionContaining(currentAddress) - - if current_function is None: - print("No function selected. Please place cursor in a function.") - return - - function_name = current_function.getName() - function_entry = current_function.getEntryPoint() - - print("Function: {} @ {}".format(function_name, function_entry)) - print("=" * 60) - print("") - - # Get all references to this function - references = getReferencesTo(function_entry) - - call_count = 0 - for ref in references: - ref_type = ref.getReferenceType() - - # Only process CALL references - if ref_type.isCall(): - call_count += 1 - from_address = ref.getFromAddress() - caller_function = getFunctionContaining(from_address) - - if caller_function is not None: - caller_name = caller_function.getName() - else: - caller_name = "" - - # Get the instruction at the call site - call_instruction = getInstructionAt(from_address) - - if call_instruction is not None: - # Return address is the address after the call instruction - return_address = from_address.add(call_instruction.getLength()) - - print("Call Site #{}: {}".format(call_count, from_address)) - print(" Caller Function: {}".format(caller_name)) - print(" Return Address: {}".format(return_address)) - print("") - else: - print("Warning: Could not find instruction at {}".format(from_address)) - - print("=" * 60) - print("Total calls found: {}".format(call_count)) - -if __name__ == "__main__": - main() +# List all return addresses for a given function +# @author Claude +# @category Analysis +# @keybinding +# @menupath +# @toolbar + +from ghidra.program.model.symbol import RefType + +def main(): + # Get the current function or prompt user to select one + current_function = getFunctionContaining(currentAddress) + + if current_function is None: + print("No function selected. Please place cursor in a function.") + return + + function_name = current_function.getName() + function_entry = current_function.getEntryPoint() + + print("Function: {} @ {}".format(function_name, function_entry)) + print("=" * 60) + print("") + + # Get all references to this function + references = getReferencesTo(function_entry) + + call_count = 0 + for ref in references: + ref_type = ref.getReferenceType() + + # Only process CALL references + if ref_type.isCall(): + call_count += 1 + from_address = ref.getFromAddress() + caller_function = getFunctionContaining(from_address) + + if caller_function is not None: + caller_name = caller_function.getName() + else: + caller_name = "" + + # Get the instruction at the call site + call_instruction = getInstructionAt(from_address) + + if call_instruction is not None: + # Return address is the address after the call instruction + return_address = from_address.add(call_instruction.getLength()) + + print("Call Site #{}: {}".format(call_count, from_address)) + print(" Caller Function: {}".format(caller_name)) + print(" Return Address: {}".format(return_address)) + print("") + else: + print("Warning: Could not find instruction at {}".format(from_address)) + + print("=" * 60) + print("Total calls found: {}".format(call_count)) + +if __name__ == "__main__": + main() diff --git a/README.md b/README.md index ba7ecab2..ca4e2e9f 100644 --- a/README.md +++ b/README.md @@ -1,277 +1,277 @@ - -**C3X** is a mod that makes many improvements to the Civ 3 Conquests EXE. It adds quality of life features including stack unit commands (shown below) and an end-of-turn warning for cities about to riot. C3X also fixes many long standing bugs, including the infamous submarine bug, deepens the AI's ability to fight by enabling it to use artillery and army units, and reduces turn times by correcting a major inefficiency in the game's trade network calculation. C3X also forms a platform for other mods by enabling various gameplay changes not possible through the editor. Examples include resource generation from buildings, era-specific names for leaders and civs, limited trespassing and railroad movement like in Civ 4, and a broad expansion of the zone of control and defensive bombard abilities. - -|![Demo of stack unit commands in C3X. Holding the control key causes all workers on a tile to build a railroad and causes all bombers to bombard a target.](Misc%20Images/new%20stack%20demo/output_gimp_with_msgs_optimized.gif)| -|:--:| -|Stack unit commands. Holding the control key converts most unit action buttons into stack buttons, which issue their commands to all units of the same type on the same tile. Similarly, holding control when selecting a tile to bombard performs a stack bombard. Also note the grouping of units and movement indicators on the right-click menus.| - -C3X's primary home is on CivFanatics, see: [main mod page](https://forums.civfanatics.com/resources/c3x.28759/), [releases](https://forums.civfanatics.com/resources/c3x.28759/updates), [discussion thread](https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/latest) - -## Video Overview -See this video by Suede for a demonstration of how to install the mod and of some of its convenience features. -[![C3X: Incredible Quality of Life mod for Civ 3, Video by Suede CivIII](http://img.youtube.com/vi/VxQ5dVABJcQ/0.jpg)](http://www.youtube.com/watch?v=VxQ5dVABJcQ) - -## Installation Details -Extract the mod, keeping it in its own folder, then copy that folder to your main Conquests directory (i.e. the folder containing Civ3Conquests.exe). Then activate the mod by double-clicking the INSTALL.bat script. You should get a message reporting that the installation was successful. You can also try RUN.bat, which launches a modded version of Civ 3 without installation, however I have received several reports that that script doesn't work for some people. - -Notes about installation: -1. If your Civ 3 is installed inside Program Files then it may be necessary to run INSTALL.bat as administrator due to Windows restrictions on editing the contents of Program Files. -2. When installing, the mod will create a backup of the original unmodded executable named "Civ3Conquests-Unmodded.exe". -3. To uninstall the mod, delete the modded executable then rename the backed up version mentioned above to "Civ3Conquests.exe". -4. It is not necessary to uninstall the mod before installing a different version. -5. Even after installation, the mod still depends on some files in the mod folder, so you need to keep it around. -6. R�mulo Prado reports that RUN.bat started working for him after he installed the MS Visual C++ Redistributables versions 2005 and 2019 (while installing GOG Galaxy). - -## Configuration -All aspects of C3X are configurable through INI text files. The basic INI file is called "default.c3x_config.ini" and is located in the mod folder. For example, if you want to turn off grouping of units on the right-click menu (that's what gives you "3x Spearman" instead of 3 identical Spearman entries), you could open that file in any text editor, find the line `group_units_on_right_click_menu = true`, and set it to `false`. - -However, because the default config file gets updated with each new release of the mod, it's recommended to put changes like the one above in a new file named "custom.c3x\_config.ini". C3X supports up to three different config files, the default config, a scenario config named "scenario.c3x\_config.ini" located in a scenario's search folder, and a custom config. They are loaded in that order. Scenario configs are intended to contain rule settings relevant to a particular scenario and custom configs are intended to function like user preferences. For a quick example of a scenario config, see [this post](https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-28#post-16212316). - -## Compatibility -C3X is compatible with the GOG and Steam versions of Civ 3 Complete and also with the DRM-free executable available through PCGames.de. If you have a CD version of the game, you can replace its EXE with the one from PCGames.de then install C3X on top of that. For more info about the PCGames.de executable, see this thread: [Civ 3, Windows Update KB3086255, & SafeDisc](https://forums.civfanatics.com/threads/civ-3-windows-update-kb3086255-safedisc.552308/). - -For info about running C3X on Mac, see this thread: [Installing, Playing and Modding C3C on Apple Silicon](https://forums.civfanatics.com/threads/installing-playing-and-modding-c3c-on-apple-silicon.681540/) - -C3X is compatible with existing saves and saves created with the mod active will still be loadable by the base game. - -Online multiplayer is not officially supported but some features of the mod will work. Others will not, including stack unit commands. I have also received reports that C3X can cause crashes in online MP. In general, online play is something I'd like to support but haven't gotten around to yet. - -## Feature Highlights -#### Disorder Warning: -![C3X disorder warning feature. The domestic advisor is popping up to warn about unhappy cities before the end of a turn.](Misc%20Images/disorder_warning.jpg) - -If you try to end the turn with unhappy cities, the domestic advisor will pop up to warn you and give you the option to continue that turn. - -#### AI Enhancements: -Numerous changes have been made to improve the AI's behavior, especially in combat. It can now use its artillery units in the field, i.e., it will take them out of its cities to bombard enemy cities or incoming enemy units. The AI's production of artillery has been significantly increased so that it can take advantage of this ability. The other major change is that the AI can now use armies properly, it builds them when it can and fills them with units, usually the strongest available. There are many smaller changes as well to fix bugs and improve heuristics. Some more details are available as comments in the config file. - -#### Trade Screen Improvements: -![C3X trade screen arrows. Shows the top of the leader window with arrows on either side.](Misc%20Images/c3x_trade_screen_arrows.jpg) - -When negotiating with the AI, you can quickly switch back and forth between civs using the added arrow buttons (arrow keys work as well). When asking for or offering gold, the set amount popup will appear with the best amount already filled in. Best amount means, when asking for gold on an acceptable trade, the most you could get, and when offering gold on an unacceptable trade, the least you need to pay. - -#### Optimization: -A major inefficiency in the game's sea trade computation has been fixed. This eliminates one major cause of slow turns in the late game, especially on large maps with many coastal cities and many wars. For details about the problem and how C3X solves it, see [this post](https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-83#post-16536108). - -#### Adjustable Movement Rules: -The functions governing unit movement have been modified to enable various adjustments to the game's movement rules not possible through the editor. As with all other engine extensions, the rules are not changed from vanilla Conquests unless the config file is edited. - -Unlimited railroad movement can be turned off. The non-unlimited railroads can function like they do in Civ 4, meaning that all units will move the same distance along them regardless of how many moves they have, or they can function like an upgraded version of regular roads that have a lower movement cost. The relevant config variables are "limit\_railroad\_movement" and "limited\_railroads\_work\_like\_fast\_roads". - -Enabling land/sea intersections allows sea units to travel over the thin isthmus that exists on the diagonal path between two land tiles. More specifically, imagine a diamond of four tiles with land terrain on the north & south tiles and water on the east & west ones. With land/sea intersections enabled, naval units can pass between the east and west tiles. - -It is possible to disallow trespassing, which will prevent units from entering another civ's borders without a right of passage agreement, similar to the rules in Civ 4. Invisible and hidden nationality units are allowed to trespass in any case. It is also possible to impose a stack limit, which will prevent units from entering tiles that already have more than a set number of units occupying them. The stack limit can be set separately for land, sea, and air units. - -#### Small Wonder Free Improvements: -The free improvements wonder effect (granaries from Pyramids etc.) now works on small wonders. Note to modders, to set this effect you must use a third party editor like Quintillus' ([thread link](https://forums.civfanatics.com/threads/cross-platform-editor-for-conquests-now-available.377188/)) because the option is grayed out in the standard editor. Even worse, if you set the effect then work on the BIQ in the standard editor, the effect won't be saved, so you'd need to set it every time or work exclusively in Quintillus' editor. - -#### No-Raze & Limit Removals: -The no-raze and no-unit-limit features of earlier modded EXEs have been re-implemented as part of C3X. To enable no-raze, edit the config. There are separate options to prevent autorazing (the forced destruction of size 1 cities) and razing by player's choice. In addition to removing the unit limit, C3X also removes the limit of 256 city improvement types, and lifts the city limit to 2048. - -## Full Feature List -All C3X features are listed below. See the default config (default.c3x\_config.ini) for descriptions. -
- Included in C3X - - #### Convenience features - - Stack unit commands - - Stack bombard - - Worker buttons (irrigate, road, etc.) become stack buttons by holding CTRL - - Stack fortify, upgrade, and disband also with CTRL - - Disorder warning - - Detailed city production info - - Buttons on trade screen to quickly switch between civs - - Ask/offer gold popup autofills best amount - - Skip repeated popups asking to replace a tile improvement - - Group units on right click menu - - Show coordinates and chopped status in tile info box - - Show golden age turns remaining - - No special king unit names in non-regicide games - - Option to disable worker automation - - On the city screen, hold shift when clicking a specialist to switch to the previous type - - Automatically cut research spending to avoid bankruptcy - - Remove pause for "we love the king" messages - - Suppress "maximum hypertext links exceeded" popup - - Civilopedia indicates when units go obsolete but cannot be upgraded - - Message appears after bomber dodges interception by air defense buildings - - Option to replay AI moves for all human players in hotseat mode - - Restore unit directions on game load - - Option to remove Elvis Easter egg - - Harbor/airport city icons indicate unit effects not trade abilities - - Disallow useless bombard attacks vs airfields - - Display total city count (disabled by default, appears on demographics screen) - - Fix graphical issues when running on Wine - - Option to pack the lists of luxuries and strategic resources more tightly into their boxes on the city screen - - Right-click menu enhancements - - Place icons next to units showing movement and combat status - - Replace Wake/Activate with descriptions of what the units are doing - - Gray out units if they have no remaining moves - - Apply GridOn setting from conquests.ini after loading a save - - Option to have a warning when the building you've selected to build would replace another already built in the city - - Option not to unassign workers from tiles that become polluted - - Pressing the Z key on the city screen toggles the zoom level of the map display - - Option not to draw capital cities larger than they really are - - Allow Civilopedia descriptions for units, civilizations, and game concepts to span multiple pages - - Double size of minimap when running in high definition (>= 1920 horizontal pixels) - - Option to show some popup messages as online-multiplayer-style notifications - - Option to switch debug mode on or off for games in progress - - Option to tint coast and sea tiles on minimap based on cultural borders - #### Optimization - - Optimize computation of trade networks - - For details, see the info text file in the Trade Net X folder - - Optimize improvement loops - - Option to measure turn times - #### AI Enhancements - - Allow AI to use artillery in the field - - Force AI to build more artillery and bombers - - Replace leader unit AI to fix bugs and improve behavior - - Fix bug preventing AI from filling its armies - - Improve AI army composition to discourage mixing types & exclude HN units - - AI routine for "pop units", which are modded units whose only purpose is to be joined into cities - - AI routine for "caravan units", which are modded units whose only purpose is to be disbanded for shields - - Can limit the number of escorts the AI assigns to its naval transports and carriers - - Adjustable AI worker requirement - - Option to stop AI from escorting units without the "requires escort" flag - - Option to draw small shadows underneath city dots on the minimap to make them more visible - #### Bugs Fixed - - AI pathfinding collides with invisible units (called the "submarine bug") - - Science age beakers not actually awarded - - Pink line in Civilopedia - - Crash when doing disembark-all on transport containing immobile unit(s) - - Crash possible when AI civ is left alive with only a settler on a transport (called the "houseboat bug") - - Resources beyond the first 32 share access records in cities not on the main trade network (called the "phantom resource bug") - - Air units lose a turn after being set to intercept - - Cached building maintenance amounts not updated when buildings are obsoleted - - Barbarian long-range search for targets is limited to tiles directly NW or SE - - "Disables Diseases From Flood Plains" tech flag hardcoded to tech #8 (off by default) - - Possible division by zero in AI logic to evaluate proposed alliances - - Available movement computed incorrectly for empty armies - - Off-map AI units may crash the game (fixed by deleting them at the start of their turns) - - Pathfinder improperly truncates long paths, sending AI units on nonsensical or invalid paths - - Cities with zero production crash the game due to division by zero - - Icons for different kinds of specialist yields are drawn on top of, instead of next to, one another - - AI players may sacrifice units without the "sacrifice" special ability - - AI players may build armies with leader units that don't have the "build army" special ability - - Possible crash in base game leader unit AI - #### AMB Editor - - A program for inspecting and modifying the special .amb sound files used by Civ 3. - - For more info, see README.txt in the AMB Editor folder - #### Limits Removed - - Removed unit limit - - Removed city improvement limit - - Lift city limit to 2048 and allow it to be configured - - Remove cap on turn limit - #### Engine Extensions - - Adjustable minimum city distance - - Option to limit railroad movement, as in Civ 4 or by converting them to fast roads - - Option to limit how many units can share each tile - - Enable free improvements from small wonders - - Option to share visibility among all human players in a hotseat game - - Option to prevent autoraze and razing by players - - Trespassing prevention - - Land/sea intersections - - Adjustable anarchy length - - Unit limits (stops players from producing units of a given type once they reach a maximum quantity) - - "Perfume" city production options, technologies, and governments to control how likely the AI is to choose them - - Reveal AI logic - - Press P in city screen to see AI point value for each available build - - Press L on map to see how desirable the AI finds each tile as a city location - - Corruption can be completely removed with "OFF" government setting - - Disallow land units from working or settling water tiles - - Option to let units move after airdropping - - Buildings can generate resources - - Buildings can be set as prerequisites for unit production - - Can cancel out pop pollution with negative pollution amount on building flagged as removing pop pollution - - Option to modify rules for retreat eligibility - - AI multi-city start - - Starter cities can begin with improvements, including "extra palaces" which respawn like the real palace - - Option to strengthen the corruption reducing effect of wonders to match the palace's - - Option to allow military great leaders to hurry wonders - - Option to multiply AI research rate by any amount - - Option to aggressively penalize bankrupt players - - Option to remove exception to tile penalty for city tiles with fresh water and Agri trait - - Artillery can be set to use PTW-like targeting against cities - - Recon missions can be made vulnerable to interception - - Option to charge one move for recon missions and interception - - Stealth attack changes - - Option to perform stealth attack even when there's only one target - - Enable stealth attacks via bombardment - - Allow players to opt out of stealth attacks - - Option to show unit hitpoints on the stealth attack target selection popup - - Option to prevent stealth attacks from targeting units that are invisible and unrevealed - - Polish precision striking by land or sea units - - Use regular bombard animation instead of flying animation - - Use bombard range instead of operational range - - Despawn unit if cruise missile - - Cannot be intercepted - - Option to immunize aircraft against bombardment - - Option to ignore king flag on defense, so kings aren't always last to defend in a stack - - Option to show untradable techs on trade screen - - Barbarian city capture & production (experimental) - - Option to allow land units to bombard aircraft and naval units in cities - - Zone of control changes - - Allow land-to-sea and sea-to-land attacks, only using bombard stat - - May be lethal - - May be exerted by air units - - Show attack animation even when attacker is not at the top of its stack - - Defensive bombard changes - - May be lethal - - May be performed by air units - - Invisible, undetected units may be made immune - - May be performed multiple times per turn with blitz - - Naval units in a city may perform defensive bombard vs land attackers - - Allow precision strikes to target tile improvements - - Option not to end a unit's turn after it bombards a barricade - - Option to allow bombardment of other improvements on a tile with an occupied airfield - - Option to boost OCN increase from forbidden palaces in non-communal governments - - Option to allow airdrops without airports - - Can increase unit maintenance costs based on their build costs - - Civ and leader names can vary by era - - Option to allow upgrades in any city - - Option to stop the map generator from placing volcanos - - Option to stop pollution from appearing on impassable tiles - - Option to make planting forests produce LM forest terrain - - Adjustable chance for max one HP units to be destroyed by nuclear strikes - - Option to allow sale of buildings like aqueducts that uncap population growth - - Option stopping non-sea detector units from revealing invisible sea units and vice-versa - - Adjustable city work area size - - Radius of area can be set from 1 to 7 tiles (2 is the standard) - - Area can also be limited by a city's cultural level or buildings - - Option to throttle AI's expansion by temporarily applying perfume to settlers each time it founds a city - - Option to block the galley chaining exploit by preventing units from loading into two different transports on the same turn - - Adjustable rebase range as multiple of operational range - - Option to share wonders among human players in hotseat mode - - Enable tile graphics to cycle over day and night, see "Day/Night Cycle" section of default config for details - - Can adjust time to double building culture - - Option to prevent units from upgrading past an intermediate type that does not have the upgrade ability - - Can adjust times to generate tourism gold - - Option to put all human players in contact with each other at the start of a hotseat game - - Enable districts, an elaborate change to the game's economy inspired by Civ 6 - - The districts feature is a large mod on its own. See its thread: https://forums.civfanatics.com/threads/c3x-districts.700590/ - - Land transport changes - - Land transports may be loaded into naval transports - - Empty LTs may join armies - - Units inside an LT may be prevented from defending their tile, performing defensive bombard, or intercepting air units - - Units inside an LT can be destroyed when the LT itself is destroyed or captured - - Resource placement changes - - Can relax the rule preventing resources from appearing next to others of a different type - - Adjust the overall appearance rate for luxuries that do not have a fixed rate set - - Control the overall appearance rate of bonus resources - - Option to allow sale of small wonders - - Option to allow units to be unloaded from armies - - Option to prevent land anti-air units from intercepting overflying aircraft while they're loaded in a naval transport - - Option to prevent units from being enslaved after being destroyed by lethal bombard named prevent_enslaving_by_bombardment -
- -## How It Works -Some parts of the mod (bug fixes, no-raze, no unit limit) are really just hex edits that are applied to the Civ program code. The real secret sauce is a system to compile and inject arbitrary C code into the process which makes it practical to implement new features in the game. The heart of the system is TCC (Tiny C Compiler) and much work puzzling out the functions and structs inside the executable. Much thanks to Antal1987 for figuring out most of the structs years before I came along, [his work is posted here](https://github.com/Antal1987/C3CPatchFramework)). - -C3X is open source. The C code that gets injected into the game's EXE is located in injected_code.c and the code to perform the injection is located in ep.c. You're invited to explore the source code if you're interested. - -## Special Thanks -1. Antal1987 for his work reverse engineering Civ3 -2. Rmulo Prado for his help testing the mod -3. Civinator for the German translation. See: https://www.civforum.de/showthread.php?113285-Der-Flintlock-Deutsch-Patch -4. Vaughn Parker for generously commissioning the port to the PCGames.de EXE and many other features -5. instafluff0 for contributing the districts and day/night cycle features -6. Philiquaz and dobragab for their contributions + +**C3X** is a mod that makes many improvements to the Civ 3 Conquests EXE. It adds quality of life features including stack unit commands (shown below) and an end-of-turn warning for cities about to riot. C3X also fixes many long standing bugs, including the infamous submarine bug, deepens the AI's ability to fight by enabling it to use artillery and army units, and reduces turn times by correcting a major inefficiency in the game's trade network calculation. C3X also forms a platform for other mods by enabling various gameplay changes not possible through the editor. Examples include resource generation from buildings, era-specific names for leaders and civs, limited trespassing and railroad movement like in Civ 4, and a broad expansion of the zone of control and defensive bombard abilities. + +|![Demo of stack unit commands in C3X. Holding the control key causes all workers on a tile to build a railroad and causes all bombers to bombard a target.](Misc%20Images/new%20stack%20demo/output_gimp_with_msgs_optimized.gif)| +|:--:| +|Stack unit commands. Holding the control key converts most unit action buttons into stack buttons, which issue their commands to all units of the same type on the same tile. Similarly, holding control when selecting a tile to bombard performs a stack bombard. Also note the grouping of units and movement indicators on the right-click menus.| + +C3X's primary home is on CivFanatics, see: [main mod page](https://forums.civfanatics.com/resources/c3x.28759/), [releases](https://forums.civfanatics.com/resources/c3x.28759/updates), [discussion thread](https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/latest) + +## Video Overview +See this video by Suede for a demonstration of how to install the mod and of some of its convenience features. +[![C3X: Incredible Quality of Life mod for Civ 3, Video by Suede CivIII](http://img.youtube.com/vi/VxQ5dVABJcQ/0.jpg)](http://www.youtube.com/watch?v=VxQ5dVABJcQ) + +## Installation Details +Extract the mod, keeping it in its own folder, then copy that folder to your main Conquests directory (i.e. the folder containing Civ3Conquests.exe). Then activate the mod by double-clicking the INSTALL.bat script. You should get a message reporting that the installation was successful. You can also try RUN.bat, which launches a modded version of Civ 3 without installation, however I have received several reports that that script doesn't work for some people. + +Notes about installation: +1. If your Civ 3 is installed inside Program Files then it may be necessary to run INSTALL.bat as administrator due to Windows restrictions on editing the contents of Program Files. +2. When installing, the mod will create a backup of the original unmodded executable named "Civ3Conquests-Unmodded.exe". +3. To uninstall the mod, delete the modded executable then rename the backed up version mentioned above to "Civ3Conquests.exe". +4. It is not necessary to uninstall the mod before installing a different version. +5. Even after installation, the mod still depends on some files in the mod folder, so you need to keep it around. +6. R�mulo Prado reports that RUN.bat started working for him after he installed the MS Visual C++ Redistributables versions 2005 and 2019 (while installing GOG Galaxy). + +## Configuration +All aspects of C3X are configurable through INI text files. The basic INI file is called "default.c3x_config.ini" and is located in the mod folder. For example, if you want to turn off grouping of units on the right-click menu (that's what gives you "3x Spearman" instead of 3 identical Spearman entries), you could open that file in any text editor, find the line `group_units_on_right_click_menu = true`, and set it to `false`. + +However, because the default config file gets updated with each new release of the mod, it's recommended to put changes like the one above in a new file named "custom.c3x\_config.ini". C3X supports up to three different config files, the default config, a scenario config named "scenario.c3x\_config.ini" located in a scenario's search folder, and a custom config. They are loaded in that order. Scenario configs are intended to contain rule settings relevant to a particular scenario and custom configs are intended to function like user preferences. For a quick example of a scenario config, see [this post](https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-28#post-16212316). + +## Compatibility +C3X is compatible with the GOG and Steam versions of Civ 3 Complete and also with the DRM-free executable available through PCGames.de. If you have a CD version of the game, you can replace its EXE with the one from PCGames.de then install C3X on top of that. For more info about the PCGames.de executable, see this thread: [Civ 3, Windows Update KB3086255, & SafeDisc](https://forums.civfanatics.com/threads/civ-3-windows-update-kb3086255-safedisc.552308/). + +For info about running C3X on Mac, see this thread: [Installing, Playing and Modding C3C on Apple Silicon](https://forums.civfanatics.com/threads/installing-playing-and-modding-c3c-on-apple-silicon.681540/) + +C3X is compatible with existing saves and saves created with the mod active will still be loadable by the base game. + +Online multiplayer is not officially supported but some features of the mod will work. Others will not, including stack unit commands. I have also received reports that C3X can cause crashes in online MP. In general, online play is something I'd like to support but haven't gotten around to yet. + +## Feature Highlights +#### Disorder Warning: +![C3X disorder warning feature. The domestic advisor is popping up to warn about unhappy cities before the end of a turn.](Misc%20Images/disorder_warning.jpg) + +If you try to end the turn with unhappy cities, the domestic advisor will pop up to warn you and give you the option to continue that turn. + +#### AI Enhancements: +Numerous changes have been made to improve the AI's behavior, especially in combat. It can now use its artillery units in the field, i.e., it will take them out of its cities to bombard enemy cities or incoming enemy units. The AI's production of artillery has been significantly increased so that it can take advantage of this ability. The other major change is that the AI can now use armies properly, it builds them when it can and fills them with units, usually the strongest available. There are many smaller changes as well to fix bugs and improve heuristics. Some more details are available as comments in the config file. + +#### Trade Screen Improvements: +![C3X trade screen arrows. Shows the top of the leader window with arrows on either side.](Misc%20Images/c3x_trade_screen_arrows.jpg) + +When negotiating with the AI, you can quickly switch back and forth between civs using the added arrow buttons (arrow keys work as well). When asking for or offering gold, the set amount popup will appear with the best amount already filled in. Best amount means, when asking for gold on an acceptable trade, the most you could get, and when offering gold on an unacceptable trade, the least you need to pay. + +#### Optimization: +A major inefficiency in the game's sea trade computation has been fixed. This eliminates one major cause of slow turns in the late game, especially on large maps with many coastal cities and many wars. For details about the problem and how C3X solves it, see [this post](https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-83#post-16536108). + +#### Adjustable Movement Rules: +The functions governing unit movement have been modified to enable various adjustments to the game's movement rules not possible through the editor. As with all other engine extensions, the rules are not changed from vanilla Conquests unless the config file is edited. + +Unlimited railroad movement can be turned off. The non-unlimited railroads can function like they do in Civ 4, meaning that all units will move the same distance along them regardless of how many moves they have, or they can function like an upgraded version of regular roads that have a lower movement cost. The relevant config variables are "limit\_railroad\_movement" and "limited\_railroads\_work\_like\_fast\_roads". + +Enabling land/sea intersections allows sea units to travel over the thin isthmus that exists on the diagonal path between two land tiles. More specifically, imagine a diamond of four tiles with land terrain on the north & south tiles and water on the east & west ones. With land/sea intersections enabled, naval units can pass between the east and west tiles. + +It is possible to disallow trespassing, which will prevent units from entering another civ's borders without a right of passage agreement, similar to the rules in Civ 4. Invisible and hidden nationality units are allowed to trespass in any case. It is also possible to impose a stack limit, which will prevent units from entering tiles that already have more than a set number of units occupying them. The stack limit can be set separately for land, sea, and air units. + +#### Small Wonder Free Improvements: +The free improvements wonder effect (granaries from Pyramids etc.) now works on small wonders. Note to modders, to set this effect you must use a third party editor like Quintillus' ([thread link](https://forums.civfanatics.com/threads/cross-platform-editor-for-conquests-now-available.377188/)) because the option is grayed out in the standard editor. Even worse, if you set the effect then work on the BIQ in the standard editor, the effect won't be saved, so you'd need to set it every time or work exclusively in Quintillus' editor. + +#### No-Raze & Limit Removals: +The no-raze and no-unit-limit features of earlier modded EXEs have been re-implemented as part of C3X. To enable no-raze, edit the config. There are separate options to prevent autorazing (the forced destruction of size 1 cities) and razing by player's choice. In addition to removing the unit limit, C3X also removes the limit of 256 city improvement types, and lifts the city limit to 2048. + +## Full Feature List +All C3X features are listed below. See the default config (default.c3x\_config.ini) for descriptions. +
+ Included in C3X + + #### Convenience features + - Stack unit commands + - Stack bombard + - Worker buttons (irrigate, road, etc.) become stack buttons by holding CTRL + - Stack fortify, upgrade, and disband also with CTRL + - Disorder warning + - Detailed city production info + - Buttons on trade screen to quickly switch between civs + - Ask/offer gold popup autofills best amount + - Skip repeated popups asking to replace a tile improvement + - Group units on right click menu + - Show coordinates and chopped status in tile info box + - Show golden age turns remaining + - No special king unit names in non-regicide games + - Option to disable worker automation + - On the city screen, hold shift when clicking a specialist to switch to the previous type + - Automatically cut research spending to avoid bankruptcy + - Remove pause for "we love the king" messages + - Suppress "maximum hypertext links exceeded" popup + - Civilopedia indicates when units go obsolete but cannot be upgraded + - Message appears after bomber dodges interception by air defense buildings + - Option to replay AI moves for all human players in hotseat mode + - Restore unit directions on game load + - Option to remove Elvis Easter egg + - Harbor/airport city icons indicate unit effects not trade abilities + - Disallow useless bombard attacks vs airfields + - Display total city count (disabled by default, appears on demographics screen) + - Fix graphical issues when running on Wine + - Option to pack the lists of luxuries and strategic resources more tightly into their boxes on the city screen + - Right-click menu enhancements + - Place icons next to units showing movement and combat status + - Replace Wake/Activate with descriptions of what the units are doing + - Gray out units if they have no remaining moves + - Apply GridOn setting from conquests.ini after loading a save + - Option to have a warning when the building you've selected to build would replace another already built in the city + - Option not to unassign workers from tiles that become polluted + - Pressing the Z key on the city screen toggles the zoom level of the map display + - Option not to draw capital cities larger than they really are + - Allow Civilopedia descriptions for units, civilizations, and game concepts to span multiple pages + - Double size of minimap when running in high definition (>= 1920 horizontal pixels) + - Option to show some popup messages as online-multiplayer-style notifications + - Option to switch debug mode on or off for games in progress + - Option to tint coast and sea tiles on minimap based on cultural borders + #### Optimization + - Optimize computation of trade networks + - For details, see the info text file in the Trade Net X folder + - Optimize improvement loops + - Option to measure turn times + #### AI Enhancements + - Allow AI to use artillery in the field + - Force AI to build more artillery and bombers + - Replace leader unit AI to fix bugs and improve behavior + - Fix bug preventing AI from filling its armies + - Improve AI army composition to discourage mixing types & exclude HN units + - AI routine for "pop units", which are modded units whose only purpose is to be joined into cities + - AI routine for "caravan units", which are modded units whose only purpose is to be disbanded for shields + - Can limit the number of escorts the AI assigns to its naval transports and carriers + - Adjustable AI worker requirement + - Option to stop AI from escorting units without the "requires escort" flag + - Option to draw small shadows underneath city dots on the minimap to make them more visible + #### Bugs Fixed + - AI pathfinding collides with invisible units (called the "submarine bug") + - Science age beakers not actually awarded + - Pink line in Civilopedia + - Crash when doing disembark-all on transport containing immobile unit(s) + - Crash possible when AI civ is left alive with only a settler on a transport (called the "houseboat bug") + - Resources beyond the first 32 share access records in cities not on the main trade network (called the "phantom resource bug") + - Air units lose a turn after being set to intercept + - Cached building maintenance amounts not updated when buildings are obsoleted + - Barbarian long-range search for targets is limited to tiles directly NW or SE + - "Disables Diseases From Flood Plains" tech flag hardcoded to tech #8 (off by default) + - Possible division by zero in AI logic to evaluate proposed alliances + - Available movement computed incorrectly for empty armies + - Off-map AI units may crash the game (fixed by deleting them at the start of their turns) + - Pathfinder improperly truncates long paths, sending AI units on nonsensical or invalid paths + - Cities with zero production crash the game due to division by zero + - Icons for different kinds of specialist yields are drawn on top of, instead of next to, one another + - AI players may sacrifice units without the "sacrifice" special ability + - AI players may build armies with leader units that don't have the "build army" special ability + - Possible crash in base game leader unit AI + #### AMB Editor + - A program for inspecting and modifying the special .amb sound files used by Civ 3. + - For more info, see README.txt in the AMB Editor folder + #### Limits Removed + - Removed unit limit + - Removed city improvement limit + - Lift city limit to 2048 and allow it to be configured + - Remove cap on turn limit + #### Engine Extensions + - Adjustable minimum city distance + - Option to limit railroad movement, as in Civ 4 or by converting them to fast roads + - Option to limit how many units can share each tile + - Enable free improvements from small wonders + - Option to share visibility among all human players in a hotseat game + - Option to prevent autoraze and razing by players + - Trespassing prevention + - Land/sea intersections + - Adjustable anarchy length + - Unit limits (stops players from producing units of a given type once they reach a maximum quantity) + - "Perfume" city production options, technologies, and governments to control how likely the AI is to choose them + - Reveal AI logic + - Press P in city screen to see AI point value for each available build + - Press L on map to see how desirable the AI finds each tile as a city location + - Corruption can be completely removed with "OFF" government setting + - Disallow land units from working or settling water tiles + - Option to let units move after airdropping + - Buildings can generate resources + - Buildings can be set as prerequisites for unit production + - Can cancel out pop pollution with negative pollution amount on building flagged as removing pop pollution + - Option to modify rules for retreat eligibility + - AI multi-city start + - Starter cities can begin with improvements, including "extra palaces" which respawn like the real palace + - Option to strengthen the corruption reducing effect of wonders to match the palace's + - Option to allow military great leaders to hurry wonders + - Option to multiply AI research rate by any amount + - Option to aggressively penalize bankrupt players + - Option to remove exception to tile penalty for city tiles with fresh water and Agri trait + - Artillery can be set to use PTW-like targeting against cities + - Recon missions can be made vulnerable to interception + - Option to charge one move for recon missions and interception + - Stealth attack changes + - Option to perform stealth attack even when there's only one target + - Enable stealth attacks via bombardment + - Allow players to opt out of stealth attacks + - Option to show unit hitpoints on the stealth attack target selection popup + - Option to prevent stealth attacks from targeting units that are invisible and unrevealed + - Polish precision striking by land or sea units + - Use regular bombard animation instead of flying animation + - Use bombard range instead of operational range + - Despawn unit if cruise missile + - Cannot be intercepted + - Option to immunize aircraft against bombardment + - Option to ignore king flag on defense, so kings aren't always last to defend in a stack + - Option to show untradable techs on trade screen + - Barbarian city capture & production (experimental) + - Option to allow land units to bombard aircraft and naval units in cities + - Zone of control changes + - Allow land-to-sea and sea-to-land attacks, only using bombard stat + - May be lethal + - May be exerted by air units + - Show attack animation even when attacker is not at the top of its stack + - Defensive bombard changes + - May be lethal + - May be performed by air units + - Invisible, undetected units may be made immune + - May be performed multiple times per turn with blitz + - Naval units in a city may perform defensive bombard vs land attackers + - Allow precision strikes to target tile improvements + - Option not to end a unit's turn after it bombards a barricade + - Option to allow bombardment of other improvements on a tile with an occupied airfield + - Option to boost OCN increase from forbidden palaces in non-communal governments + - Option to allow airdrops without airports + - Can increase unit maintenance costs based on their build costs + - Civ and leader names can vary by era + - Option to allow upgrades in any city + - Option to stop the map generator from placing volcanos + - Option to stop pollution from appearing on impassable tiles + - Option to make planting forests produce LM forest terrain + - Adjustable chance for max one HP units to be destroyed by nuclear strikes + - Option to allow sale of buildings like aqueducts that uncap population growth + - Option stopping non-sea detector units from revealing invisible sea units and vice-versa + - Adjustable city work area size + - Radius of area can be set from 1 to 7 tiles (2 is the standard) + - Area can also be limited by a city's cultural level or buildings + - Option to throttle AI's expansion by temporarily applying perfume to settlers each time it founds a city + - Option to block the galley chaining exploit by preventing units from loading into two different transports on the same turn + - Adjustable rebase range as multiple of operational range + - Option to share wonders among human players in hotseat mode + - Enable tile graphics to cycle over day and night, see "Day/Night Cycle" section of default config for details + - Can adjust time to double building culture + - Option to prevent units from upgrading past an intermediate type that does not have the upgrade ability + - Can adjust times to generate tourism gold + - Option to put all human players in contact with each other at the start of a hotseat game + - Enable districts, an elaborate change to the game's economy inspired by Civ 6 + - The districts feature is a large mod on its own. See its thread: https://forums.civfanatics.com/threads/c3x-districts.700590/ + - Land transport changes + - Land transports may be loaded into naval transports + - Empty LTs may join armies + - Units inside an LT may be prevented from defending their tile, performing defensive bombard, or intercepting air units + - Units inside an LT can be destroyed when the LT itself is destroyed or captured + - Resource placement changes + - Can relax the rule preventing resources from appearing next to others of a different type + - Adjust the overall appearance rate for luxuries that do not have a fixed rate set + - Control the overall appearance rate of bonus resources + - Option to allow sale of small wonders + - Option to allow units to be unloaded from armies + - Option to prevent land anti-air units from intercepting overflying aircraft while they're loaded in a naval transport + - Option to prevent units from being enslaved after being destroyed by lethal bombard named prevent_enslaving_by_bombardment +
+ +## How It Works +Some parts of the mod (bug fixes, no-raze, no unit limit) are really just hex edits that are applied to the Civ program code. The real secret sauce is a system to compile and inject arbitrary C code into the process which makes it practical to implement new features in the game. The heart of the system is TCC (Tiny C Compiler) and much work puzzling out the functions and structs inside the executable. Much thanks to Antal1987 for figuring out most of the structs years before I came along, [his work is posted here](https://github.com/Antal1987/C3CPatchFramework)). + +C3X is open source. The C code that gets injected into the game's EXE is located in injected_code.c and the code to perform the injection is located in ep.c. You're invited to explore the source code if you're interested. + +## Special Thanks +1. Antal1987 for his work reverse engineering Civ3 +2. Rmulo Prado for his help testing the mod +3. Civinator for the German translation. See: https://www.civforum.de/showthread.php?113285-Der-Flintlock-Deutsch-Patch +4. Vaughn Parker for generously commissioning the port to the PCGames.de EXE and many other features +5. instafluff0 for contributing the districts and day/night cycle features +6. Philiquaz and dobragab for their contributions diff --git a/Sound Test/BUILD_LINUX.sh b/Sound Test/BUILD_LINUX.sh index a952361f..8d2994f6 100644 --- a/Sound Test/BUILD_LINUX.sh +++ b/Sound Test/BUILD_LINUX.sh @@ -1 +1 @@ -i686-w64-mingw32-g++ --static sound_test.cpp -o sound_test.exe +i686-w64-mingw32-g++ --static sound_test.cpp -o sound_test.exe diff --git a/civ_prog_objects.csv b/civ_prog_objects.csv index 02f6830b..82c39193 100644 --- a/civ_prog_objects.csv +++ b/civ_prog_objects.csv @@ -1,964 +1,964 @@ -JOB, GOG ADDR, STEAM ADDR, PCG ADDR, NAME, TYPE -define, 0, 1, 2, "exe_version_index", "int" -define, 0x9C3508, 0x9E5D08, 0x9C34C8, "p_bic_data", "BIC *" -define, 0xA52E80, 0xA75680, 0xA52E40, "p_units", "Units *" -define, 0xA52DD4, 0xA755D0, 0xA52D94, "p_tile_units", "TileUnits *" -define, 0xA52E68, 0xA75668, 0xA52E28, "p_cities", "Cities *" -define, 0xA52E50, 0xA75650, 0xA52E10, "p_colonies", "Base_List *" -define, 0xA52E98, 0xA75698, 0xA52E58, "leaders", "Leader *" -define, 0xB3CEA0, 0xB5F6A0, 0xB3CE60, "city_sprites", "Sprite *" -define, 0xB3E7D0, 0xB60FD0, 0xB3E790, "destroyed_city_sprites", "Sprite *" -define, 0x9F8700, 0xA1AF00, 0x9F86C0, "p_main_screen_form", "Main_Screen_Form *" -define, 0xA52658, 0xA74E50, 0xA52618, "p_game", "Game *" -define, 0xCB8B38, 0xCDB440, 0xCB8AF8, "temp_ui_strs", "char[10][4096]" -define, 0x665188, 0x68219C, 0x665188, "ADDR_ADDR_OUTPUTDEBUGSTRINGA", "void *" -define, 0x665280, 0x6822E0, 0x665280, "ADDR_ADDR_GETASYNCKEYSTATE", "void *" -define, 0x665168, 0x682130, 0x665168, "ADDR_ADDR_GETPROCADDRESS", "void *" -define, 0x6650E4, 0x6820B8, 0x6650E4, "ADDR_ADDR_GETMODULEHANDLEA", "void *" -define, 0x66527C, 0x6822E4, 0x66527C, "ADDR_ADDR_MESSAGEBOXA", "void *" -repl vptr, 0x73A8FC, 0x756C74, 0x73A8D4, "init_floating_point", "void (__stdcall *) (void)" -define, 0x5B6B01, 0x5C5458, 0x5B6811, "ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK", "void *" -define, 0x569503, 0x575933, 0x5694B3, "ADDR_UNIT_COUNT_CHECK", "void *" -define, 0x594B35, 0x5A2357, 0x594855, "ADDR_ERA_COUNT_CHECK", "void *" -define, 0x5601EF, 0x56C2E3, 0x56019F, "ADDR_SCIENCE_AGE_BUG_PATCH", "void *" -define, 0x4CD0B1, 0x4D5151, 0x4CD171, "ADDR_PEDIA_TEXTURE_BUG_PATCH", "void *" -define, 0x5640AC, 0x570385, 0x56405C, "ADDR_AUTORAZE_BYPASS", "void *" -repl vptr, 0x66CB50, 0x689C3C, 0x66CB50, "Leader_impl_would_raze_city", "bool (__fastcall *) (Leader * this, int edx, City * city)" -repl vptr, 0x66B44C, 0x68854C, 0x66B44C, "Main_Screen_Form_handle_left_click_on_map_1", "void (__fastcall *) (Main_Screen_Form * this, int edx, int param_1, int param_2)" -inlead, 0x4EA210, 0x4F3000, 0x4EA2D0, "Main_Screen_Form_handle_right_click_on_tile", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" -inlead, 0x4E8850, 0x4F14E0, 0x4E8910, "Main_Screen_Form_open_right_click_menu", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" -define, 0x499FE0, 0x49F9F0, 0x49A070, "is_online_game", "char (__stdcall *) (void)" -define, 0x437A70, 0x439620, 0x437AF0, "tile_at", "Tile * (__cdecl *) (int x, int y)" -define, 0x426C80, 0x4283C0, 0x426D00, "TileUnits_TileUnitID_to_UnitID", "int (__fastcall *) (TileUnits * this, int edx, int tile_unit_id, int * out_UnitItem_field_0)" -inlead, 0x5C1410, 0x5CFFA0, 0x5C1120, "Unit_bombard_tile", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -inlead, 0x5BE820, 0x5CD420, 0x5BE530, "Unit_get_defense_strength", "int (__fastcall *) (Unit * this)" -inlead, 0x5BB650, 0x5CA190, 0x5BB360, "Unit_is_visible_to_civ", "char (__fastcall *) (Unit * this, int edx, int civ_id, int param_2)" -define, 0x5EA6C0, 0x5F9F10, 0x5EA5F0, "Tile_has_city", "char (__fastcall *) (Tile * this)" -define, 0x5EA6E0, 0x5F9F30, 0x5EA610, "Tile_has_colony", "bool (__fastcall *) (Tile * this)" -define, 0x5BE5B0, 0x5CD180, 0x5BE2C0, "Unit_get_max_hp", "int (__fastcall *) (Unit * this)" -define, 0x5E4EF0, 0x5F4750, 0x5E4E20, "UnitType_has_ability", "bool (__fastcall *) (UnitType * this, int edx, enum UnitTypeAbilities a)" -define, 0x5CDDF0, 0x5DCEB0, 0x5CDD10, "get_max_move_points", "int (__cdecl *) (UnitType * unit_type, int civ_id)" -inlead, 0x5BE470, 0x5CD030, 0x5BE180, "Unit_get_max_move_points", "int (__fastcall *) (Unit * this)" -define, 0x60B370, 0x625850, 0x60B290, "Button_set_tooltip", "int (__fastcall *) (Button * this, int edx, char * str)" -define, 0x5FC420, 0x60FC10, 0x5FC300, "PCX_Image_construct", "PCX_Image * (__fastcall *) (PCX_Image * this)" -define, 0x5FC820, 0x610360, 0x5FC700, "PCX_Image_read_file", "int (__fastcall *) (PCX_Image * this, int edx, char * file_path, PCX_Color_Table * out_color_table, int ct_start, int ct_count, unsigned flags)" -define, 0x5F7E50, 0x608170, 0x5F7D80, "Sprite_construct", "Sprite * (__fastcall *) (Sprite * this)" -define, 0x5F7F90, 0x6083D0, 0x5F7EC0, "Sprite_slice_pcx", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * img, int up_left_x, int up_left_y, int w, int h, int arg6, int arg7)" -define, 0x49FC50, 0x4A6790, 0x49FCE0, "get_popup_form", "PopupForm * (__stdcall *) ()" -define, 0x61C5A0, 0x63E390, 0x61C4D0, "set_popup_str_param", "int (__cdecl *) (int param_index, char * str, int param_3, int param_4)" -define, 0x61C570, 0x63E350, 0x61C4A0, "set_popup_int_param", "int (__cdecl *) (int param_index, int value)" -inlead, 0x611530, 0x62DAF0, 0x611460, "show_popup", "int (__fastcall *) (void * this, int edx, int param_1, int param_2)" -define, 0x4ACD20, 0x4B3CC0, 0x4ACDB0, "City_zoom_to", "void (__fastcall *) (City *this, int edx, int param_1)" -inlead, 0x4ACB50, 0x4B3AF0, 0x4ACBE0, "City_has_improvement", "char (__fastcall *) (City * this, int edx, int i_improvement, char include_auto_improvements)" -inlead, 0x4E6DB0, 0x4EF820, 0x4E6E70, "Main_Screen_Form_perform_action_on_tile", "void (__fastcall *) (Main_Screen_Form * this, int edx, enum Unit_Mode_Actions action, int x, int y)" -inlead, 0x550BB0, 0x55BCE0, 0x550B60, "Main_GUI_set_up_unit_command_buttons", "void (__fastcall *) (Main_GUI * this)" -inlead, 0x5577F0, 0x563600, 0x5577A0, "Main_GUI_handle_button_press", "void (__fastcall *) (Main_GUI * this, int edx, int button_id)" -inlead, 0x4E05F0, 0x4E8F90, 0x4E06B0, "Main_Screen_Form_handle_key_down", "int (__fastcall *) (Main_Screen_Form * this, int edx, int char_code, int virtual_key_code)" -inlead, 0x6268A0, 0x64B410, 0x624C00, "handle_cursor_change_in_jgl", "int (__stdcall *) ()" -inlead, 0x555F80, 0x561B90, 0x555F30, "Main_GUI_handle_click_in_status_panel", "void (__fastcall *) (Main_GUI * this, int edx, int mouse_x, int mouse_y)" -define, 0x54CAD0, 0x557980, 0x54CB30, "get_font", "Object_66C3FC * (__cdecl *) (int size, FontStyleFlags style)" -define, 0x5FD750, 0x611850, 0x5FD630, "PCX_Image_draw_centered_text", "int (__fastcall *) (PCX_Image *this, int edx, Object_66C3FC * font, char * str, int x, int y, int width, int str_len)" -inlead, 0x4196F0, 0x41A5D0, 0x419770, "City_Form_draw", "void (__fastcall *) (City_Form * this)" -inlead, 0x41B4C0, 0x41C610, 0x41B540, "City_Form_print_production_info", "void (__fastcall *) (City_Form *this, int edx, String256 * out_strs, int str_capacity)" -define, 0x4ACD70, 0x4B3D30, 0x4ACE00, "City_get_order_cost", "int (__fastcall *) (City * this)" -define, 0x4ACD40, 0x4B3CE0, 0x4ACDD0, "City_get_order_progress", "int (__fastcall *) (City * this)" -inlead, 0x57F360, 0x58C080, 0x57F0C0, "Trade_Net_get_movement_cost", "int (__fastcall *) (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned flags, int neighbor_index, Trade_Net_Distance_Info * dist_info)" -define, 0x57F0A0, 0x58BDB0, 0x57EE00, "Trade_Net_have_trade_connection", "bool (__fastcall *) (Trade_Net * this, int edx, City * a, City * b, int civ_id)" -define, 0x57F130, 0x58BE40, 0x57EE90, "Trade_Net_is_tile_connected_to_city", "bool (__fastcall *) (Trade_Net * this, int edx, City * city, int tile_x, int tile_y)" -inlead, 0x591BB0, 0x59F1D0, 0x5918D0, "do_save_game", "int (__cdecl *) (char const * file_path, char param_2, GUID * guid)" -define, 0x4BCFF0, 0x4C4660, 0x4BD080, "City_recompute_happiness", "void (__fastcall *) (City * this)" -define, 0x4B05D0, 0x4B7590, 0x4B0660, "City_recompute_production", "void (__fastcall *) (City * this)" -define, 0x4B07C0, 0x4B7770, 0x4B0850, "City_recompute_commerce", "void (__fastcall *) (City * this)" -inlead, 0x4B0B70, 0x4B7B20, 0x4B0C00, "City_recompute_culture_income", "void (__fastcall *) (City * this)" -inlead, 0x4B2680, 0x4B9600, 0x4B2710, "City_update_culture", "void (__fastcall *) (City * this)" -define, 0x4B0C60, 0x4B7C10, 0x4B0CF0, "City_recompute_cultural_level", "void (__fastcall *) (City *this, int edx, char param_1, char param_2, char param_3)" -define, 0x4B10F0, 0x4B80A0, 0x4B1180, "recompute_food_eaten_production_commerce_and_happiness", "void (__fastcall *) (City *this)" -inlead, 0x55A560, 0x566470, 0x55A510, "Leader_recompute_auto_improvements", "void (__fastcall *) (Leader * this)" -inlead, 0x539030, 0x543650, 0x5390B0, "Game_get_wonder_city_id", "int (__fastcall *) (Game * this, int edx, int wonder_improvement_id)" -define, 0x55A62E, 0x566538, 0x55A5DE, "ADDR_SMALL_WONDER_FREE_IMPROVS_RETURN", "int" -define, 0x55A5C6, 0x5664D4, 0x55A576, "ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER", "void *" -repl vptr, 0x66B46C, 0x68856C, 0x66B46C, "Main_Screen_Form_handle_key_up", "int (__fastcall *) (Main_Screen_Form * this, int edx, int virtual_key_code)" -define, 0x4DAA70, 0x4E3430, 0x4DAB30, "Main_Screen_Form_issue_command", "char (__fastcall *) (Main_Screen_Form * this, int edx, int command, Unit * unit)" -define, 0x609D60, 0x6233C0, 0x609C80, "clear_something_1", "void (__stdcall *) ()" -define, 0x6207B0, 0x644F10, 0x6206E0, "Timer_clear", "void (__fastcall *) (Timer * this)" -inlead, 0x55EFA0, 0x56B030, 0x55EF50, "Leader_can_do_worker_job", "char (__fastcall *) (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing)" -define, 0x56A7C0, 0x576C60, 0x56A770, "Leader_can_build_unit", "bool (__fastcall *) (Leader * this, int edx, int unit_type_id, int param_2, bool allow_kings)" -define, 0x455288, 0x457458, 0x455308, "ADDR_CHECK_ARTILLERY_IN_CITY", "void *" -inlead, 0x455140, 0x457310, 0x4551C0, "Unit_ai_move_artillery", "void (__fastcall *) (Unit * this)" -define, 0x5E6E50, 0x5F66A0, 0x5E6D80, "neighbor_index_to_diff", "void (__cdecl *) (int neighbor_index, int * out_x, int * out_y)" -define, 0x5B3040, 0x5C1970, 0x5B2D50, "Unit_set_state", "void (__fastcall *) (Unit * this, int edx, int new_state)" -define, 0x5B2F10, 0x5C1840, 0x5B2C20, "Unit_set_escortee", "void (__fastcall *) (Unit * this, int edx, int escortee)" -inlead, 0x44D980, 0x44F9E0, 0x44DA00, "Unit_seek_colony", "int (__fastcall *) (Unit *this, int edx, bool for_own_defense, int max_distance)" -repl call, 0x4527BE, 0x4548E3, 0x45283E, "Tile_has_district_or_colony", "" -define, 0xA526B4, 0xA74EAC, 0xA52674, "p_rand_object", "void *" -define, 0x60BAB0, 0x626440, 0x60B9E0, "rand_int", "int (__fastcall *) (void * this, int edx, int lim)" -inlead, 0x42C8A0, 0x42E430, 0x42C920, "City_ai_choose_production", "void (__fastcall *) (City * this, int edx, City_Order * out)" -inlead, 0x4C04E0, 0x4C7AB0, 0x4C0570, "City_can_build_unit", "bool (__fastcall *) (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings)" -repl call, 0x5C536C, 0x5D404D, 0x5C507C, "Unit_get_max_move_points_for_disembarking", "" -inlead, 0x5C5420, 0x5D4120, 0x5C5130, "Unit_disembark_passengers", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -define, 0xCAA330, 0xCCCB98, 0xCAA2F0, "p_null_tile", "Tile *" -define, 0x45A35F, 0x45C56F, 0x45A3DF, "ADDR_HOUSEBOAT_BUG_PATCH", "byte *" -define, 0x45A386, 0x45C596, 0x45A406, "ADDR_HOUSEBOAT_BUG_PATCH_END", "byte *" -define, 0xB72888, 0xB950A8, 0xB72848, "p_original_trade_net", "Trade_Net *" -inlead, 0x580540, 0x58D270, 0x5802A0, "Trade_Net_set_unit_path", "int (__fastcall *) (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp)" -define, 0x5B3290, 0x5C1BE0, 0x5B2FA0, "Unit_pop_next_move_from_path", "byte (__fastcall *) (Unit * this)" -inlead, 0x45FED0, 0x4622A0, 0x45FF50, "Unit_ai_move_leader", "void (__fastcall *) (Unit * this)" -define, 0x5B2B20, 0x5C1440, 0x5B2830, "Unit_next_escorter_id", "int (__fastcall *) (Unit * this, int edx, int * index, bool begin_iterating)" -define, 0x5BC300, 0x5CAE50, 0x5BC010, "Unit_disband", "void (__fastcall *) (Unit * this)" -inlead, 0x5C00A0, 0x5CEC20, 0x5BFDB0, "Unit_can_hurry_production", "bool (__fastcall *) (Unit * this, int edx, City * city, bool exclude_cheap_improvements)" -inlead, 0x5B3AB0, 0x5C2400, 0x5B37C0, "Unit_can_pillage", "bool (__fastcall *) (Unit *this, int edx, int tile_x, int tile_y)" -inlead, 0x5CCBB0, 0x5DBB50, 0x5CC8C0, "Unit_can_pass_between", "bool (__fastcall *) (Unit *this, int edx, int from_x, int from_y, int to_x, int to_y, byte param_5)" -define, 0x5C0420, 0x5CEFC0, 0x5C0130, "Unit_hurry_production", "void (__fastcall *) (Unit * this)" -define, 0x5C0300, 0x5CEE90, 0x5C0010, "Unit_ai_can_start_science_age", "bool (__fastcall *) (Unit * this)" -define, 0x5C03B0, 0x5CEF50, 0x5C00C0, "Unit_start_science_age", "void (__fastcall *) (Unit * this)" -inlead, 0x5BC980, 0x5CB510, 0x5BC690, "Unit_ai_can_form_army", "bool (__fastcall *) (Unit * this)" -define, 0x5BCA20, 0x5CB5B0, 0x5BC730, "Unit_form_army", "Unit * (__fastcall *) (Unit * this)" -repl vptr, 0x66DD28, 0x68AE08, 0x66DD28, "impl_ai_is_good_army_addition", "bool (__fastcall *) (Unit * this, int edx, Unit * candidate)" -repl vptr, 0x666578, 0x6835CC, 0x666578, "PopupForm_set_text_key_and_flags", "void (__fastcall *) (PopupForm * this, int edx, char * script_path, char * text_key, int param_3, int param_4, int param_5, int param_6)" -define, 0xA35200, 0xA57A00, 0xA351C0, "p_diplo_form", "DiploForm *" -define, 0x649A8B, 0x6683E1, 0x6499CF, "new", "void * (__cdecl *) (unsigned num_bytes)" -define, 0x666AC4, 0x683B1C, 0x666AC4, "p_trade_offer_vtable", "TradeOfferVTable *" -define, 0x440EE0, 0x442CD0, 0x440F60, "Leader_consider_trade", "DiploMessage (__fastcall *) (Leader * this, int edx, TradeOfferList * receiving, TradeOfferList * paying, int other_party_civ_id, byte param_4, bool param_5, byte param_6, byte param_7, int * out_advantage, int * param_9, int * param_10)" -define, 0x509325, 0x51334D, 0x5093C5, "ADDR_SETUP_INITIAL_GOLD_ASK_RETURN", "int" -define, 0x50BCC8, 0x515DA1, 0x50BD68, "ADDR_SETUP_MODIFY_GOLD_ASK_RETURN", "int" -define, 0x509669, 0x51366E, 0x509709, "ADDR_SETUP_INITIAL_GOLD_OFFER_RETURN", "int" -define, 0x50BF10, 0x516008, 0x50BFB0, "ADDR_SETUP_MODIFY_GOLD_OFFER_RETURN", "int" -define, 14, 14, 14, "TRADE_GOLD_SETTER_IS_LUMP_SUM_OFFSET", "int" -define, 0x50BEBD, 0x515FB4, 0x50BF5D, "ADDR_PRINT_GOLD_AMOUNT_1", "byte *" -define, 0x50BC75, 0x515D4D, 0x50BD15, "ADDR_PRINT_GOLD_AMOUNT_2", "byte *" -inlead, 0x5F3160, 0x603000, 0x5F3090, "Map_check_city_location", "CityLocValidity (__fastcall *) (Map *this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile)" -repl vptr, 0x66C1E8, 0x6892D8, 0x66C1E8, "DiploForm_m68_Show_Dialog", "int (__fastcall *) (DiploForm * this, int edx, int param_1, void * param_2, void * param_3)" -repl vptr, 0x66C220, 0x689310, 0x66C220, "DiploForm_m82_handle_key_event", "void (__fastcall *) (DiploForm * this, int edx, int virtual_key_code, int is_down)" -define, 0xA526C0, 0xA74EB8, 0xA52680, "p_player_bits", "unsigned *" -define, 0x50D830, 0x517970, 0x50D8D0, "DiploForm_close", "void (__fastcall *) (DiploForm *)" -inlead, 0x505F40, 0x50FD30, 0x505FE0, "DiploForm_do_diplomacy", "void (__fastcall *) (DiploForm * this, int edx, int diplo_message, int param_2, int civ_id, int do_not_request_audience, int war_negotiation, int disallow_proposal, TradeOfferList * our_offers, TradeOfferList * their_offers)" -define, 0x440E10, 0x442C00, 0x440E90, "Leader_ai_would_meet_with", "bool (__fastcall *) (Leader * this, int edx, int civ_id)" -repl vptr, 0x66C130, 0x689220, 0x66C130, "DiploForm_m22_Draw", "void (__fastcall *) (DiploForm * this)" -define, 0x609F50, 0x623C40, 0x609E70, "Button_construct", "Button * (__fastcall *) (Button * this)" -define, 0x60B050, 0x625450, 0x60AF70, "Button_initialize", "int (__fastcall *) (Button * this, int edx, char * text, int control_id, int x, int y, int width, int height, Base_Form * parent, int param_8)" -define, 0x5161C0, 0x51F9B0, 0x516260, "DiploForm_set_their_message", "int (__fastcall *) (DiploForm * this, int edx, DiploMessage msg, int message_arg, int param_3)" -define, 0x516260, 0x51FA50, 0x516300, "DiploForm_reset_our_message_choices", "void (__fastcall *) (DiploForm *)" -define, 0x649FA7, 0x6076E0, 0x649EEB, "civ_prog_malloc", "void * (__cdecl *) (unsigned _Size)" -define, 0x649EBE, 0x668816, 0x649E02, "civ_prog_free", "void (__cdecl *) (void * p)" -inlead, 0x61A480, 0x63B9F0, 0x61A3B0, "Context_Menu_open", "int (__fastcall *) (Context_Menu * this, int edx, int x, int y, int param_3)" -define, 0x4E993C, 0x4F273A, 0x4E99FC, "ADDR_OPEN_UNIT_MENU_RETURN", "int" -define, 0x61B0C0, 0x63C940, 0x61AFF0, "Context_Menu_widen_for_text", "void (__fastcall *) (Context_Menu * this, int edx, char * text)" -inlead, 0x61A110, 0x63B420, 0x61A040, "Context_Menu_add_item_and_set_color", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, char * text, int red)" -define, 0x61A160, 0x63B480, 0x61A090, "Context_Menu_add_separator", "int (__fastcall *) (Context_Menu * this, int edx, int item_id)" -inlead, 0x45C750, 0x45EA70, 0x45C7D0, "Unit_ai_move_terraformer", "void (__fastcall *) (Unit * this)" -inlead, 0x4B1DC0, 0x4B8D50, 0x4B1E50, "City_requires_improvement_to_grow", "int (__fastcall *) (City * this)" -inlead, 0x4DD530, 0x4E5F00, 0x4DD5F0, "maybe_show_improvement_needed_for_growth_dialog", "void (__fastcall *) (void * this, int edx, City * city, int * param_2)" -repl call, 0x5213E3, 0x52B3F3, 0x521483, "City_requires_improvement_to_grow_besides_neighborhood", "" -inlead, 0x5C1AD0, 0x5D0670, 0x5C17E0, "Unit_can_perform_command", "bool (__fastcall *) (Unit * this, int edx, int unit_command_value)" -inlead, 0x5B39D0, 0x5C2320, 0x5B36E0, "Unit_join_city", "void (__fastcall *) (Unit * this, int edx, City * city)" -define, 0x5C0740, 0x5CF2E0, 0x5C0450, "Unit_upgrade", "Unit * (__fastcall *) (Unit * this, int edx, bool ignore_cost)" -define, 0x5C04D0, 0x5CF070, 0x5C01E0, "Unit_get_upgrade_cost", "int (__fastcall *) (Unit * this)" -define, 0xCADC18, 0xCD0510, 0xCADBD8, "script_dot_txt_file_path", "char *" -inlead, 0x5B5CD0, 0x5C4620, 0x5B59E0, "Unit_can_move_to_adjacent_tile", "AdjacentMoveValidity (__fastcall *) (Unit * this, int edx, int neighbor_index, int param_2)" -define, 0x5F3F50, 0x603DD0, 0x5F3E80, "Map_compute_neighbor_index", "int (__fastcall *) (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim)" -repl call, 0x5CCC85, 0x5DBC1F, 0x5CC995, "Map_compute_neighbor_index_for_pass_between", "" -repl call, 0x42FC69, 0x43173F, 0x42FCE9, "Improvement_has_wonder_com_bonus_for_ai_prod", "" -define, 0x5FEF70, 0x613F70, 0x5FEE50, "PCX_Image_draw_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int str_len)" -repl call, 0x5AAB93, 0x5B9899, 0x5AA8A3, "PCX_Image_draw_no_tile_info", "" -repl call, 0x5AB00A, 0x5B97E8, 0x5AAD1A, "PCX_Image_draw_tile_info_terrain", "" -define, 0x4E3C60, 0x4EC4B0, 0x4E3D20, "Main_Screen_Form_get_tile_coords_under_mouse", "int (__fastcall *) (Main_Screen_Form * this, int edx, int mouse_x, int mouse_y, int * out_tile_x, int * out_tile_y)" -inlead, 0x5AA820, 0x5B8F40, 0x5AA530, "open_tile_info", "void (__fastcall *) (void * this, int edx, int mouse_x, int mouse_y, int civ_id)" -inlead, 0x53A860, 0x544B80, 0x53A8E0, "get_anarchy_length", "int (__stdcall *) (int leader_id)" -repl call, 0x5557DE, 0x56136E, 0x55578E, "PCX_Image_process_tech_ga_status", "" -define, 0x5FE560, 0x612F50, 0x5FE440, "PCX_Image_process_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str)" -define, 0xA526AC, 0xA74EA4, 0xA5266C, "p_current_turn_no", "int *" -define, 0xCADC0C, 0xCD0504, 0xCADBCC, "p_labels", "char ***" -define, 497, 498, 497, "LBL_GOLDEN_AGE", "int" -define, 0xA5267C, 0xA74E74, 0xA5263C, "p_toggleable_rules", "int *" -define, 0xA52680, 0xA74E78, 0xA52640, "p_debug_mode_bits", "unsigned *" -repl call, 0x569A10, 0x575E4A, 0x5699C0, "Unit_check_king_ability_while_spawning", "" -define, 0x5BC8B0, 0x5CB430, 0x5BC5C0, "Unit_has_ability", "bool (__fastcall *) (Unit * this, int edx, enum UnitTypeAbilities a)" -define, 0xA52658, 0xA74E50, 0xA52618, "p_match", "void *" -inlead, 0x442480, 0x444250, 0x442500, "Match_ai_eval_city_location", "int (__fastcall *) (void * this, int edx, int x, int y, int civ_id, bool param_4, int * out_breakdown)" -define, 0x430FBA, 0x432A6D, 0x43103A, "ADDR_INTERCEPT_AI_IMPROV_VALUE", "void *" -define, 7, 6, 7, "AI_CONSIDERATION_INTERCEPT_LEN", "int" -define, 0x433C7C, 0x435712, 0x433CFC, "ADDR_INTERCEPT_AI_UNIT_VALUE", "void *" -inlead, 0x4B1190, 0x4B8140, 0x4B1220, "City_compute_corrupted_yield", "int (__fastcall *) (City * this, int edx, int gross_yield, bool is_production)" -define, 0x610B30, 0x62CE00, 0x610A60, "PopupForm_add_text", "byte (__fastcall *) (PopupForm * this, int edx, char * text, bool param_2)" -define, 0x6193A0, 0x639AD0, 0x6192D0, "PopupSelection_add_item", "int (__fastcall *) (PopupSelection * this, int edx, char * text, int value)" -inlead, 0x59AB50, 0x5A8660, 0x59A870, "load_scenario", "unsigned (__fastcall *) (BIC * this, int edx, char * param_1, unsigned * param_2)" -define, 0x59B499, 0x5A8FD9, 0x59B1B9, "ADDR_LOAD_SCENARIO_PREVIEW_RETURN", "int" -define, 0x59AD27, 0x5A8872, 0x59AA47, "ADDR_LOAD_SCENARIO_RESUME_SAVE_2_RETURN", "int" -repl vptr, 0x6659F8, 0x682A5C, 0x6659F8, "City_Form_m82_handle_key_event", "void (__fastcall *) (City_Form * this, int edx, int virtual_key_code, int is_down)" -define, 0x437540, 0x4390F0, 0x4375C0, "Improvement_has_wonder_flag", "bool (__fastcall *) (Improvement * this, int edx, enum ImprovementTypeWonderFeatures flag)" -define, 0x437710, 0x4392F0, 0x437790, "UnitType_has_ai_strategy", "bool (__fastcall *) (UnitType * this, int edx, byte n)" -repl call, 0x431038, 0x432AE7, 0x4310B8, "UnitType_has_strat_0_for_ai_prod", "" -define, 0x44CE50, 0x44EE40, 0x44CED0, "Unit_find_transport", "Unit * (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C5F70, 0x5D4D50, 0x5C5C80, "Unit_select_transport", "Unit * (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, bool should_show_popup)" -inlead, 0x5C5110, 0x5D3DF0, 0x5C4E20, "Unit_load", "void (__fastcall *) (Unit * this, int edx, Unit * transport)" -define, 0xA526BC, 0xA74EB4, 0xA5267C, "p_human_player_bits", "int *" -inlead, 0x5F8130, 0x6085D0, 0x5F8060, "Sprite_draw_on_map", "int (__fastcall *) (Sprite * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7)" -repl vptr, 0x66A554, 0x687660, 0x66A554, "Map_Renderer_m19_Draw_Tile_by_XY_and_Flags", "void (__fastcall *) (Map_Renderer * this, int edx, int param_1, int pixel_x, int pixel_y, Map_Renderer * map_renderer, int param_5, int tile_x, int tile_y, int param_8)" -repl vptr, 0x66A624, 0x687730, 0x66A624, "Map_Renderer_m71_Draw_Tiles", "void (__fastcall *) (Map_Renderer * this, int edx, int param_1, int param_2, int param_3)" -repl vptr, 0x66B520, 0x688620, 0x66B520, "Main_Screen_Form_m82_handle_key_event", "void (__fastcall *) (Main_Screen_Form * this, int edx, int virtual_key_code, int is_down)" -repl call, 0x5C190B, 0x5D0493, 0x5C161B, "Unit_get_move_points_after_airdrop", "" -repl call, 0x4D93E0, 0x4E1D70, 0x4D94A0, "Unit_get_move_points_after_set_to_intercept", "" -repl vptr, 0x66E738, 0x68B810, 0x66E738, "Parameters_Form_m68_Show_Dialog", "int (__fastcall *) (Parameters_Form * this, int edx, int arg_1, void * arg_2, void * arg_3)" -define, 0x598580, 0x5A5E30, 0x5982A0, "BIC_get_asset_path", "char * (__fastcall *) (BIC * this, int edx, char * str, bool show_error_popup)" -define, 0x5F8080, 0x608500, 0x5F7FB0, "Sprite_slice_pcx_with_color_table", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * img, int up_left_x, int up_left_y, int w, int h, int arg6, int arg7)" -define, 0x5FD320, 0x611210, 0x5FD200, "PCX_Image_set_font", "int (__fastcall *) (PCX_Image * this, int edx, Object_66C3FC * font, int arg_2, int arg_3, int arg_4)" -define, 0x57EEC4, 0x58BBE8, 0x57EC24, "ADDR_INTERCEPT_SET_RESOURCE_BIT", "void *" -inlead, 0x4ADE30, 0x4B4E10, 0x4ADEC0, "City_has_resource", "bool (__fastcall *) (City * this, int edx, int resource_id)" -define, 0x4ADDC0, 0x4B4DA0, 0x4ADE50, "City_has_trade_connection_to_capital", "bool (__fastcall *) (City * this)" -define, 0x55EEB0, 0x56AF50, 0x55EE60, "Leader_has_resources_for_job_at", "bool (__fastcall *) (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y)" -inlead, 0x57E450, 0x58B1A0, 0x57E1B0, "Trade_Net_recompute_resources", "void (__fastcall *) (Trade_Net * this, int edx, bool skip_popups)" -define, 0x561440, 0x56D5A0, 0x5613F0, "Leader_has_tech", "bool (__fastcall *) (Leader * this, int edx, int id)" -inlead, 0x4BED80, 0x4C6350, 0x4BEE10, "City_cycle_specialist_type", "bool (__fastcall *) (City * this, int edx, int mouse_x, int mouse_y, Citizen * citizen, City_Form * city_form)" -inlead, 0x4B1C10, 0x4B8BC0, 0x4B1CA0, "City_get_total_pollution", "int (__fastcall *) (City * this)" -define, 0x4B1B40, 0x4B8B00, 0x4B1BD0, "City_get_pollution_from_buildings", "int (__fastcall *) (City * this)" -inlead, 0x4B1A50, 0x4B8A10, 0x4B1AE0, "City_get_pollution_from_pop", "int (__fastcall *) (City * this)" -inlead, 0x4ACF40, 0x4B3F20, 0x4ACFD0, "City_add_or_remove_improvement", "void (__fastcall *) (City * this, int edx, int improv_id, int add, bool param_3)" -define, 0x57E943, 0x58B68E, 0x57E6A3, "ADDR_RESOURCE_TILE_COUNT_MASK", "void *" -define, 0x57E5EB, 0x58B328, 0x57E34B, "ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE", "void *" -define, 0x5DA1A0, 0x5E9710, 0x5DA0D0, "Tile_get_resource_visible_to", "int (__fastcall *) (Tile * this, int edx, int civ_id)" -inlead, 0x5EA7F0, 0x5FA040, 0x5EA720, "Tile_m17_Check_Irrigation", "bool (__fastcall *) (Tile * this, int edx, int visible_to_civ_id)" -define, 0x5D16A0, 0x5E0900, 0x5D15D0, "Map_get_tile", "Tile * (__fastcall *) (Map * this, int edx, int index)" -repl call, 0x57E602, 0x58B345, 0x57E362, "Map_get_tile_when_recomputing_resources_1", "" -repl call, 0x57E629, 0x58B36C, 0x57E389, "Map_get_tile_when_recomputing_resources_2", "" -repl call, 0x57E618, 0x58B35B, 0x57E378, "Map_get_tile_when_recomputing_resources_3", "" -repl call, 0x57E64A, 0x58B397, 0x57E3AA, "Map_get_tile_when_recomputing_resources_4", "" -repl call, 0x57E672, 0x58B3B7, 0x57E3D2, "Map_get_tile_when_recomputing_resources_5", "" -repl call, 0x57E679, 0x58B3BE, 0x57E3D9, "Tile_get_visible_resource_when_recomputing", "" -inlead, 0x4A47C0, 0x4AB470, 0x4A4850, "Fighter_begin", "void (__fastcall *) (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender)" -define, 0x441ED0, 0x443CC0, 0x441F50, "Map_get_x_dist", "int (__fastcall *) (Map * this, int edx, int x1, int x2)" -define, 0x437970, 0x439520, 0x4379F0, "Map_get_y_dist", "int (__fastcall *) (Map * this, int edx, int y1, int y2)" -inlead, 0x5D7180, 0x5E65E0, 0x5D70B0, "Map_calc_food_yield_at", "int (__fastcall *) (Map * this, int edx, int tile_x, int tile_y, int tile_base_type, int civ_id, int imagine_fully_improved, City * city)" -inlead, 0x5D75F0, 0x5E6A20, 0x5D7520, "Map_calc_shield_yield_at", "int (__fastcall *) (Map *this, int edx, int tile_x, int tile_y, int civ_id, City *city, int param_5, int param_6)" -define, 0x5663C0, 0x572730, 0x566370, "Leader_create_city", "City * (__fastcall *) (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6)" -inlead, 0x5D3030, 0x5E2330, 0x5D2F60, "Map_process_after_placing", "void (__fastcall *) (Map * this, int edx, bool param_1)" -inlead, 0x5BBBC0, 0x5CA720, 0x5BB8D0, "Unit_despawn", "void (__fastcall *) (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7)" -inlead, 0x5BD220, 0x5CBDE0, 0x5BCF30, "Unit_move", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -define, 0x558700, 0x564590, 0x5586B0, "Main_GUI_label_loading_bar", "void (__fastcall *) (Main_GUI * this, int edx, int param_1, char *text)" -define, 0x48DE43, 0x4920E3, 0x48DED3, "ADDR_TURN_METALIMIT_1", "byte *" -define, 0x4946E1, 0x4990CA, 0x494771, "ADDR_TURN_METALIMIT_2", "byte *" -define, 0x54E2E0, 0x55925B, 0x54E340, "ADDR_TURN_METALIMIT_3", "byte *" -define, 0x54E2E7, 0x559262, 0x54E347, "ADDR_TURN_METALIMIT_4", "byte *" -define, 0x584163, 0x59100F, 0x583EC3, "ADDR_TURN_METALIMIT_5", "byte *" -define, 0x5817B2, 0x58E4E2, 0x581512, "ADDR_TURN_METALIMIT_6", "byte *" -define, 0x492100, 0x496751, 0x492190, "ADDR_TURN_METALIMIT_7", "byte *" -inlead, 0x4ACA50, 0x4B39F0, 0x4ACAE0, "City_get_net_commerce", "int (__fastcall *) (City * this, int edx, int kind, bool include_science_age)" -inlead, 0x55DFD0, 0x56A070, 0x55DF80, "Leader_pay_unit_maintenance", "void (__fastcall *) (Leader * this)" -define, 0x55CFB0, 0x569040, 0x55CF60, "Leader_sum_improvements_maintenance", "int (__fastcall *) (Leader * this, int edx, int govt_id)" -define, 0x560972, 0x56CA7F, 0x560922, "ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT", "byte *" -define, 0x55DD50, 0x569DF0, 0x55DD00, "Leader_compute_income", "int (__fastcall *) (Leader * this)" -define, 0x5612F0, 0x56D420, 0x5612A0, "Leader_recompute_economy", "void (__fastcall *) (Leader * this)" -repl call, 0x560C16, 0x56CD25, 0x560BC6, "Leader_sum_improv_maintenance_to_pay_1", "" -repl call, 0x560C64, 0x56CDA8, 0x560C14, "Leader_sum_improv_maintenance_to_pay_2", "" -inlead, 0x4ACDF0, 0x4B3DD0, 0x4ACE80, "City_get_improvement_maintenance", "int (__fastcall *) (City * this, int edx, int improv_id)" -define, 0x4C2350, 0x4C9B30, 0x4C2370, "Leader_set_treasury", "void (__fastcall *) (Leader * this, int edx, int amount)" -define, 0x4B3400, 0x4BA3A0, 0x4B3490, "City_sell_improvement", "void (__fastcall *) (City * this, int edx, int improv_id, bool set_status_bit)" -define, 0x9E85F0, 0xA0ADF0, 0x9E85B0, "p_civilopedia_form", "Civilopedia_Form *" -define, 0x4CBE10, 0x4D3E50, 0x4CBED0, "Civilopedia_open", "void (__fastcall *) (void * this, int edx, char * key, bool param_2)" -define, 0x53A960, 0x544C80, 0x53A9E0, "get_unit_support_info", "void (__stdcall *) (int civ_id, int govt_id, int * out_cost_per_unit, int * out_count_free_units)" -define, 0x55D2A0, 0x569330, 0x55D250, "Leader_get_free_unit_count", "int (__fastcall *) (Leader * this, int edx, int govt_id)" -inlead, 0x55D030, 0x5690C0, 0x55CFE0, "Leader_count_maintenance_free_units", "int (__fastcall *) (Leader * this)" -define, 0x56D7D0, 0x57A1B0, 0x56D740, "get_tile_occupier_id", "int (__cdecl *) (int x, int y, int pov_civ_id, bool respect_unit_invisibility)" -repl call, 0x4585F4, 0x45A7A2, 0x458674, "get_tile_occupier_id_in_Unit_ai_move_naval_power_unit", "" -inlead, 0x4ED220, 0x4F6140, 0x4ED2E0, "Main_Screen_Form_show_map_message", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause)" -repl call, 0x4BE664, 0x4C5C66, 0x4BE6F4, "Main_Screen_Form_show_wltk_message", "" -repl call, 0x4BE71B, 0x4C5D1D, 0x4BE7AB, "Main_Screen_Form_show_wltk_ended_message", "" -define, 0xA52678, 0xA74E70, 0xA52638, "p_preferences", "unsigned *" -inlead, 0x4AFAB0, 0x4B6A70, 0x4AFB40, "City_set_production", "void (__fastcall *) (City * this, int edx, int order_type, int order_id, bool ask_to_confirm)" -define, 0x4B0AC0, 0x4B7A70, 0x4B0B50, "City_get_income_from_wealth_build", "int (__fastcall *) (City * this)" -define, 0x64C91E, 0x66AFD7, 0x64C85E, "print_int", "char * (__cdecl *) (int val, char * str, unsigned base)" -repl call, 0x5D759A, 0x5E69D2, 0x5D74CA, "Tile_has_city_for_agri_penalty_exception", "" -repl call, 0x564528, 0x570873, 0x5644D8, "show_popup_option_1_razes", "" -repl call, 0x4DA1E6, 0x4E2B96, 0x4DA2A6, "show_popup_option_2_razes", "" -define, 0x619E70, 0x63B090, 0x619DA0, "Context_Menu_add_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, char * text, bool checkbox, Sprite * image)" -repl call, 0x4E9808, 0x4F25EF, 0x4E98C8, "Context_Menu_add_abandon_city", "" -define, 0x60F6A0, 0x62B460, 0x60F5D0, "TextBuffer_check_ptr", "char * (__fastcall *) (TextBuffer * this, int edx, char * str)" -repl call, 0x4D5525, 0x4DDCF6, 0x4D55E5, "TextBuffer_check_pedia_upgrades_to_ptr_1", "" -repl call, 0x4D5676, 0x4DDE50, 0x4D5736, "TextBuffer_check_pedia_upgrades_to_ptr_2", "" -define, 0x5C68A0, 0x5D5700, 0x5C65B0, "Unit_try_flying_over_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y)" -inlead, 0x5C74A0, 0x5D6330, 0x5C71B0, "Unit_perform_air_recon", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -repl call, 0x5C6E34, 0x5D5CBB, 0x5C6B44, "Unit_get_interceptor_max_moves", "" -repl call, 0x5C7108, 0x5D5FAA, 0x5C6E18, "Unit_get_moves_after_interception", "" -repl call, 0x5C7114, 0x5D5FB6, 0x5C6E24, "Unit_set_state_after_interception", "" -inlead, 0x561220, 0x56D350, 0x5611D0, "Leader_begin_unit_turns", "void (__fastcall *) (Leader * this)" -define, 0x4A1FA0, 0x4A8BB0, 0x4A2030, "Fighter_find_defender_against_bombardment", "Unit * (__fastcall *) (Fighter * this, int edx, Unit * bombarder, int tile_x, int tile_y, int bombarder_civ_id, bool land_lethal, bool sea_lethal)" -repl call, 0x4A3ED9, 0x4AAB85, 0x4A3F69, "Fighter_find_actual_bombard_defender", "" -repl call, 0x4A2BAA, 0x4A97F6, 0x4A2C3A, "Fighter_find_actual_bombard_defender", "" -define, 0x4A7280, 0x4ADF40, 0x4A7310, "Fighter_eval_tile_vulnerability", "int (__fastcall *) (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y)" -repl call, 0x45861F, 0x45A7CD, 0x45869F, "Fighter_eval_tile_vulnerability_in_Unit_ai_move_naval_power_unit", "" -inlead, 0x5C6290, 0x5D50E0, 0x5C5FA0, "Unit_select", "void (__fastcall *) (Unit *this)" -inlead, 0x5B6820, 0x5C5180, 0x5B6530, "Unit_select_stealth_attack_target", "bool (__fastcall *) (Unit * this, int edx, int target_civ_id, int x, int y, bool allow_popup, Unit ** out_selected_target)" -repl call, 0x5C73FF, 0x5D629C, 0x5C710F, "Unit_try_flying_for_precision_strike", "" -define, 0x5C1210, 0x5CFDA0, 0x5C0F20, "Unit_play_bombard_fire_animation", "int (__fastcall *) (Unit * this, int edx, int x, int y)" -define, 0x5CA860, 0x5D97A0, 0x5CA570, "Unit_play_bombing_animation", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -repl call, 0x5C7429, 0x5D62BA, 0x5C7139, "Unit_play_bombing_anim_for_precision_strike", "" -repl call, 0x5C143D, 0x5CFFCD, 0x5C114D, "Unit_play_anim_for_bombard_tile", "" -repl call, 0x5B6A1B, 0x5C5368, 0x5B672B, "PopupSelection_add_stealth_attack_target", "" -inlead, 0x4D94F0, 0x4E1E80, 0x4D95B0, "Main_Screen_Form_issue_precision_strike_cmd", "void (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit)" -repl call, 0x4A3E92, 0x4AAB40, 0x4A3F22, "rand_bombard_target", "" -repl call, 0x5B6549, 0x5C4EA9, 0x5B6259, "Tile_check_water_for_stealth_attack", "" -inlead, 0x5B64C0, 0x5C4E20, 0x5B61D0, "Unit_can_stealth_attack", "bool (__fastcall *) (Unit * this, int edx, Unit * target)" -define, 0x61BCA0, 0x63D770, 0x61BBD0, "process_text_snippet", "int (__cdecl *) (char * in, char * out)" -repl call, 0x4D788A, 0x4E01EA, 0x4D794A, "process_text_for_map_message", "" -repl call, 0x5C6997, 0x5D5812, 0x5C66A7, "rand_int_to_dodge_city_aa", "" -repl call, 0x5C69A7, 0x5D5822, 0x5C66B7, "Unit_get_defense_to_dodge_city_aa", "" -repl call, 0x4A2179, 0x4A8D8A, 0x4A2209, "Unit_get_defense_to_find_bombard_defender", "" -define, 0x585B00, 0x592D50, 0x585860, "get_int_from_conquests_ini", "int (__cdecl *) (LPCSTR key, int param_2, int param_3)" -repl call, 0x59301E, 0x5A0756, 0x592D3E, "get_WindowsFileBox_from_ini", "" -define, 0x4A0670, 0x4A71F0, 0x4A0700, "open_load_game_file_picker", "char const * (__fastcall *) (void * this)" -repl call, 0x593054, 0x5A078A, 0x592D74, "do_open_load_game_file_picker", "" -inlead, 0x592D90, 0x5A0490, 0x592AB0, "do_load_game", "void * (__cdecl *) (char * param_1)" -define, 0x4F5EF0, 0x4FF290, 0x4F5FB0, "perform_interturn", "void (__cdecl *) ()" -repl call, 0x4F6759, 0x4FFB21, 0x4F6819, "perform_interturn_in_main_loop", "" -repl call, 0x4F59E6, 0x4FED88, 0x4F5AA6, "show_movement_phase_popup", "" -repl call, 0x5936F3, 0x5A0E8C, 0x593413, "show_intro_after_load_popup", "" -define, 0xA527B4, 0xA74FAC, 0xA52774, "p_is_pbem_game", "byte *" -define, 0xA52991, 0xA75189, 0xA52951, "p_is_offline_mp_game", "byte *" -inlead, 0x4A3A70, 0x4AA6F0, 0x4A3B00, "Fighter_do_bombard_tile", "void (__fastcall *) (Fighter * this, int edx, Unit * unit, int neighbor_index, int param_3, int param_4)" -define, 0x74AF60, 0x765300, 0x74AF20, "p_mp_object", "void *" -define, 0x4697B0, 0x46BF90, 0x469830, "mp_check_current_combat", "bool (__fastcall *) (void * this, int edx, int mp_tile_x, int mp_tile_y)" -define, 0x4A2650, 0x4A9290, 0x4A26E0, "Fighter_damage_city_by_bombardment", "bool (__fastcall *) (Fighter * this, int edx, Unit * unit, City * city, int damage_kind, int min_fire_rate)" -define, 0x426BD0, 0x428310, 0x426C50, "Map_in_range", "bool (__fastcall *) (Map * this, int edx, int x, int y)" -inlead, 0x4AE030, 0x4B5010, 0x4AE0C0, "City_can_trade_via_water", "bool (__fastcall *) (City * this)" -repl call, 0x4E67f4, 0x4EF255, 0x4E68B4, "City_shows_harbor_icon", "" -inlead, 0x4ADF90, 0x4B4F70, 0x4AE020, "City_can_trade_via_air", "bool (__fastcall *) (City * this)" -repl call, 0x4E6842, 0x4EF2A7, 0x4E6902, "City_shows_airport_icon", "" -define, 0x4B1F90, 0x4B8F10, 0x4B2020, "City_count_improvements_with_flag", "int (__fastcall *) (City * this, int edx, enum ImprovementTypeFlags flag)" -repl call, 0x4A12EC, 0x4A7E9C, 0x4A137C, "Unit_check_king_for_defense_priority", "" -repl call, 0x4A131A, 0x4A7ECA, 0x4A13AA, "Unit_check_king_for_defense_priority", "" -repl call, 0x4A133D, 0x4A7EED, 0x4A13CD, "Unit_check_king_for_defense_priority", "" -repl call, 0x4A144C, 0x4A7FFC, 0x4A14DC, "Unit_check_king_for_defense_priority", "" -repl call, 0x4A1477, 0x4A8027, 0x4A1507, "Unit_check_king_for_defense_priority", "" -repl call, 0x4A149F, 0x4A804F, 0x4A152F, "Unit_check_king_for_defense_priority", "" -repl call, 0x598EC5, 0x5A686D, 0x598BE5, "get_local_time_for_unit_ini", "" -repl call, 0x598AEC, 0x5A63F8, 0x59880C, "get_local_time_for_unit_ini", "" -define, 0x581330, 0x58E060, 0x581090, "Trade_Net_get_direction_from_internal_map", "int (__fastcall *) (Trade_Net * this, int edx, int x, int y, bool use_data_2_else_4)" -inlead, 0x50EC10, 0x518F00, 0x50ECB0, "DiploForm_assemble_tradable_items", "void (__fastcall *) (DiploForm * this)" -repl call, 0x50FAD9, 0x519D8B, 0x50FB79, "Leader_could_buy_tech_for_trade_screen", "" -repl call, 0x50FB9C, 0x519E42, 0x50FC3C, "Leader_could_buy_tech_for_trade_screen", "" -inlead, 0x4C10B0, 0x4C86A0, 0x4C1140, "City_get_building_defense_bonus", "int (__fastcall *) (City * this)" -define, 0x55A8D0, 0x5667E0, 0x55A880, "Leader_count_wonders_with_flag", "int (__fastcall *) (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city)" -repl vptr, 0x66DD04, 0x68ADE4, 0x66DD04, "Unit_eval_escort_requirement", "int (__fastcall *) (Unit * this)" -inlead, 0x561860, 0x56D9E0, 0x561810, "Leader_unlock_technology", "void (__fastcall *) (Leader * this, int edx, int tech_id, bool param_2, bool param_3, bool param_4)" -define, 0x55CF10, 0x568F90, 0x55CEC0, "Leader_recompute_buildings_maintenance", "void (__fastcall *) (Leader *this)" -define, 0x5683F7, 0x5747F2, 0x5683A7, "ADDR_UNLOCK_TECH_AT_INIT_1", "int" -define, 0x56847F, 0x57487A, 0x56842F, "ADDR_UNLOCK_TECH_AT_INIT_3", "int" -define, 0x5688DC, 0x574CD6, 0x56888C, "ADDR_UNLOCK_TECH_AT_INIT_2", "int" -define, 0x5621DE, 0x56E33D, 0x56217E, "ADDR_UNLOCK_TECH_RECURSE", "int" -repl call, 0x4212E7, 0x422847, 0x421367, "City_get_improv_maintenance_for_ui", "" -define, 0x563473, 0x56F723, 0x563423, "ADDR_CAPTURE_CITY_BARB_BRANCH", "byte *" -define, 0x56082B, 0x56C938, 0x5607DB, "ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP", "byte *" -define, 0x560838, 0x56C945, 0x5607E8, "ADDR_PROD_PHASE_BARB_DONE_JUMP", "byte *" -define, 0x426C00, 0x428340, 0x426C80, "Map_wrap_horiz", "int (__fastcall *) (Map * this, int edx, int x)" -define, 0x426C40, 0x428380, 0x426CC0, "Map_wrap_vert", "int (__fastcall *) (Map * this, int edx, int y)" -repl call, 0x44FEC3, 0x451F64, 0x44FF43, "neighbor_index_to_diff_for_barb_ai", "" -repl call, 0x44FEF0, 0x451F91, 0x44FF70, "Map_wrap_vert_for_barb_ai", "" -inlead, 0x5604B0, 0x56C5A0, 0x560460, "Leader_do_production_phase", "void (__fastcall *) (Leader * this)" -define, 0x5DF900, 0x5EF150, 0x5DF830, "count_set_bits", "int (__cdecl *) (unsigned int bit_field)" -repl call, 0x5604F8, 0x56C5E8, 0x5604A8, "count_player_bits_for_barb_prod", "" -repl call, 0x4C5208, 0x4CCAC6, 0x4C5228, "Map_get_tile_to_check_visibility", "" -repl vis, 0x4C5289, 0x4CCB4D, 0x4C52A9, "", "" -repl call, 0x4C5333, 0x4CCBEE, 0x4C5353, "Map_get_tile_to_check_visibility", "" -repl call, 0x4C35E4, 0x4CAE49, 0x4C3604, "Map_get_tile_to_check_visibility", "" -repl call, 0x4C3577, 0x4CADDC, 0x4C3597, "Map_get_tile_to_check_visibility", "" -repl call, 0x578A67, 0x585B87, 0x5789D7, "Map_get_tile_to_check_visibility", "" -repl call, 0x4C37E2, 0x4CB062, 0x4C3802, "Map_get_tile_to_check_visibility", "" -repl call, 0x4EDEF4, 0x4F6E44, 0x4EDFB4, "Map_get_tile_to_check_visibility", "" -repl vis, 0x4F0D82, 0x4F9ED2, 0x4F0E42, "", "" -repl call, 0x5AAA7A, 0x5B9196, 0x5AA78A, "Map_get_tile_to_check_visibility", "" -repl vis, 0x4EA2C3, 0x4F30B4, 0x4EA383, "", "" -repl vis, 0x4A1E90, 0x4A8A9E, 0x4A1F20, "", "" -repl call, 0x449941, 0x44B891, 0x4499C1, "Map_get_tile_to_check_visibility", "" -repl vis, 0x44997D, 0x44B8CF, 0x4499FD, "", "" -repl vis, 0x4EFC7A, 0x4F8C6B, 0x4EFD3A, "", "" -repl vis, 0x5B71B2, 0x5C5B43, 0x5B6EC2, "", "" -repl vis, 0x5B75EF, 0x5C5F53, 0x5B72FF, "", "" -repl vis, 0x5B7883, 0x5C6255, 0x5B7593, "", "" -repl vis, 0x5B7CC0, 0x5c66a9, 0x5B79D0, "", "" -repl vis, 0x5B808E, 0x5c6a80, 0x5B7D9E, "", "" -repl vis, 0x5B95A2, 0x5c802a, 0x5B92B2, "", "" -repl vis, 0x5BFD8A, 0x5ce91c, 0x5BFA9A, "", "" -repl vis, 0x5C4863, 0x5d351b, 0x5C4573, "", "" -repl vis, 0x5C4A3E, 0x5d3722, 0x5C474E, "", "" -repl vis, 0x5C4AD4, 0x5D37C3, 0x5C47E4, "", "" -repl vis, 0x5C4B90, 0x5D3884, 0x5C48A0, "", "" -repl vis, 0x5C4C41, 0x5D3925, 0x5C4951, "", "" -repl vis, 0x5C6A62, 0x5D58D9, 0x5C6772, "", "" -repl vis, 0x5C6F21, 0x5D5DA7, 0x5C6C31, "", "" -repl vis, 0x5C7F40, 0x5D6E00, 0x5C7C50, "", "" -repl vis, 0x5C8614, 0x5D7521, 0x5C8324, "", "" -repl vis, 0x5C8752, 0x5D7666, 0x5C8462, "", "" -repl vis, 0x5C8F8B, 0x5D7ECE, 0x5C8C9B, "", "" -repl vis, 0x5B9878, 0x5C8330, 0x5B9588, "", "" -repl vis, 0x5B992A, 0x5C83E2, 0x5B963A, "", "" -repl vis, 0x5B99E6, 0x5C84A7, 0x5B96F6, "", "" -repl vis, 0x5B9A97, 0x5C8559, 0x5B97A7, "", "" -repl vis, 0x5B9E54, 0x5C892B, 0x5B9B64, "", "" -repl vis, 0x57F4E4, 0x58C20D, 0x57F244, "", "" -repl vis, 0x57FC67, 0x58C8E4, 0x57F9C7, "", "" -repl call, 0x57F9B6, 0x58C62B, 0x57F716, "Map_get_tile_to_check_visibility", "" -repl call, 0x57F9F2, 0x58C667, 0x57F752, "Map_get_tile_to_check_visibility", "" -inlead, 0x4ED120, 0x4F6040, 0x4ED1E0, "Main_Screen_Form_is_unit_visible_to_player", "bool (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * unit)" -repl vptr, 0x670270, 0x68D31C, 0x670270, "Tile_m42_Get_Overlays", "unsigned (__fastcall *) (Tile * this, int edx, byte visible_to_civ)" -repl vptr, 0x6702E4, 0x68D390, 0x6702E4, "Tile_m71_Check_Worker_Job", "int (__fastcall *) (Tile * this)" -inlead, 0x5DBF10, 0x5EB460, 0x5DBE40, "Tile_get_road_bonus", "int (__fastcall *) (Tile * this)" -define, 0x5DBEC0, 0x5EB410, 0x5DBDF0, "Tile_get_mining_bonus", "int (__fastcall *) (Tile * this)" -define, 0x4EDF20, 0x4F6E70, 0x4EDFE0, "Unit_check_contact_bit_6", "bool (__fastcall *) (Unit * this, int edx, int civ_id)" -repl call, 0x4E8942, 0x4F15D0, 0x4E8A02, "Unit_check_contact_bit_6_on_right_click", "" -repl call, 0x4EA330, 0x4F3121, 0x4EA3F0, "Unit_check_contact_bit_6_on_right_click", "" -inlead, 0x4A8350, 0x4AF030, 0x4A83E0, "Leader_is_tile_visible", "bool (__fastcall *) (Leader * this, int edx, int x, int y)" -repl call, 0x4A784E, 0x4AE509, 0x4a78DE, "Tile_check_water_for_sea_zoc", "" -define, 0x4A79C2, 0x4AE66D, 0x4A7A52, "ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC", "byte *" -define, 0x4A7CAA, 0x4AE962, 0x4A7D3A, "ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC", "byte *" -repl call, 0x4A7BF2, 0x4AE8AA, 0x4A7C82, "Tile_check_water_for_land_zoc", "" -inlead, 0x5BE6E0, 0x5CD2C0, 0x5BE3F0, "Unit_get_attack_strength", "int (__fastcall *) (Unit * this)" -repl call, 0x4A79CA, 0x4AE675, 0x4A7A5A, "Unit_get_attack_strength_for_sea_zoc", "" -repl call, 0x4A7B15, 0x4AE7BE, 0x4A7BA5, "Unit_get_attack_strength_for_sea_zoc", "" -repl call, 0x4A7B20, 0x4AE7C9, 0x4A7BB0, "Unit_get_attack_strength_for_sea_zoc", "" -repl call, 0x4A7CB2, 0x4AE96A, 0x4A7D42, "Unit_get_attack_strength_for_land_zoc", "" -repl call, 0x4A7DFD, 0x4AEAB3, 0x4A7E8D, "Unit_get_attack_strength_for_land_zoc", "" -repl call, 0x4A7E08, 0x4AEABE, 0x4A7E98, "Unit_get_attack_strength_for_land_zoc", "" -inlead, 0x4E3E90, 0x4EC6E0, 0x4E3F50, "Main_Screen_Form_find_visible_unit", "Unit * (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * excluded)" -define, 0x4F00F0, 0x4F9100, 0x4F01B0, "Animator_play_one_shot_unit_animation", "void (__fastcall *) (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3)" -repl call, 0x4A81A4, 0x4AEE83, 0x4A8234, "Animator_play_zoc_animation", "" -repl call, 0x4A81E2, 0x4AEEC1, 0x4A8272, "Animator_play_zoc_animation", "" -inlead, 0x4A76B0, 0x4AE370, 0x4A7740, "Fighter_apply_zone_of_control", "void (__fastcall *) (Fighter * this, int edx, Unit * unit, int from_x, int from_y, int to_x, int to_y)" -define, 0x4A1CD0, 0x4A88E0, 0x4A1D60, "Fighter_check_combat_anim_visibility", "bool (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender, bool param_3)" -repl call, 0x4A7F71, 0x4AEC36, 0x4A8001, "Fighter_check_zoc_anim_visibility", "" -define, 0x4A7F61, 0x4AEC26, 0x4A7FF1, "ADDR_ZOC_CHECK_ATTACKER_ANIM_FIELD_111", "byte *" -define, 0x4A770A, 0x4AE3CA, 0x4A779A, "ADDR_SKIP_ZOC_FOR_ONE_HP_LAND_UNIT", "byte *" -define, 0x4A7745, 0x4AE405, 0x4A77D5, "ADDR_SKIP_ZOC_FOR_ONE_HP_SEA_UNIT", "byte *" -inlead, 0x5B8FC0, 0x5C7A40, 0x5B8CD0, "Unit_move_to_adjacent_tile", "int (__fastcall *) (Unit * this, int edx, int neighbor_index, bool param_2, int param_3, byte param_4)" -repl call, 0x5B91B4, 0x5C7C32, 0x5B8EC4, "Tile_check_water_for_canal_move_to_adjacent_tile_dest", "" -repl call, 0x5B945B, 0x5C7EDE, 0x5B916B, "Trade_Net_get_move_cost_after_zoc", "" -repl call, 0x5B9471, 0x5C7EF4, 0x5B9181, "Unit_can_move_after_zoc", "" -repl call, 0x5B94E4, 0x5C7F67, 0x5B91F4, "Unit_get_max_move_points_for_bridge_exit", "" -repl vptr, 0x66DD40, 0x68AE20, 0x66DD40, "Unit_teleport", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad)" -define, 0x5BEF00, 0x5CDB10, 0x5BEC10, "Unit_score_kill", "void (__fastcall *) (Unit * this, int edx, Unit * victim, bool was_attacking)" -define, 0x5BF558, 0x5CE0EA, 0x5BF268, "ADDR_EXISTING_BATTLE_CREATED_UNIT_CHECK", "void *" -inlead, 0x4A1AE0, 0x4A86E0, 0x4A1B70, "Fighter_find_defensive_bombarder", "Unit * (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender)" -define, 0x5BCA90, 0x5CB620, 0x5BC7A0, "Unit_get_containing_army", "Unit * (__fastcall *) (Unit * this)" -define, 0x4A0ED0, 0x4A7A90, 0x4A0F60, "Fighter_get_combat_odds", "int (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses)" -repl call, 0x4A5AF9, 0x4AC799, 0x4A5B89, "Fighter_get_odds_for_main_combat_loop", "" -define, 0x4A3280, 0x4A9ED0, 0x4A3310, "Fighter_damage_by_defensive_bombard", "void (__fastcall *) (Fighter * this, int edx, Unit * bombarder, Unit * defender)" -repl call, 0x4A57C5, 0x4AC477, 0x4A5855, "Fighter_damage_by_db_in_main_loop", "" -inlead, 0x4A53A0, 0x4AC060, 0x4A5430, "Fighter_fight", "byte (__fastcall *) (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender_or_null)" -repl call, 0x4A6EB7, 0x4ADB60, 0x4A6F47, "Unit_score_kill_by_defender", "" -define, 0x5C8180, 0x5D7060, 0x5C7E90, "Unit_play_attack_animation", "void (__fastcall *) (Unit * this, int edx, int direction)" -repl call, 0x4A5791, 0x4AC443, 0x4A5821, "Unit_play_attack_anim_for_def_bombard", "" -define, 0x578780, 0x5858A0, 0x5786F0, "Navigator_Data_reset", "void (__fastcall *) (Navigator_Data * this)" -inlead, 0x536080, 0x540670, 0x536100, "initialize_map_music", "void (__cdecl *) (int civ_id, int era_id, bool param_3)" -inlead, 0x535FB0, 0x5405A0, 0x536030, "deinitialize_map_music", "void (__stdcall *) ()" -inlead, 0x5C7350, 0x5D61F0, 0x5C7060, "Unit_do_precision_strike", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -define, 0x5B5790, 0x5C40E0, 0x5B54A0, "Unit_confirm_war", "bool (__fastcall *) (Unit * this, int edx, int against_civ_id, bool allow_map_message)" -inlead, 0x5C37B0, 0x5D23F0, 0x5C34C0, "Unit_check_precision_strike_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5B5280, 0x5C3BF0, 0x5B4F90, "Unit_attack_tile", "void (__fastcall *) (Unit * this, int edx, int x, int y, int bombarding)" -repl call, 0x5C33F6, 0x5D2026, 0x5C3106, "Map_get_tile_to_check_visibility", "" -repl call, 0x52C39A, 0x5367DC, 0x52C42A, "Map_get_tile_to_check_visibility", "" -repl call, 0x52C146, 0x536586, 0x52C1D6, "Map_get_tile_to_check_visibility", "" -repl call, 0x52BED0, 0x536310, 0x52BF60, "Map_get_tile_to_check_visibility", "" -repl call, 0x5B555E, 0x5C3EBF, 0x5B526E, "Unit_get_max_moves_after_barricade_attack", "" -define, 0x56D2C0, 0x579C40, 0x56D230, "city_at", "City * (__cdecl *) (int x, int y)" -repl call, 0x4A2018, 0x4A8C28, 0x4A20A8, "city_at_in_find_bombard_defender", "" -inlead, 0x5C3510, 0x5D2140, 0x5C3220, "Unit_check_bombard_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C5160, 0x5D3E40, 0x5C4E70, "Unit_can_disembark_anything", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -repl call, 0x52C912, 0x536D92, 0x52C9A2, "Unit_get_defense_for_bombardable_unit_check", "" -repl call, 0x57F627, 0x58C356, 0x57F387, "get_tile_occupier_for_ai_path", "" -repl call, 0x56D9D1, 0x57A3C2, 0x56D941, "Unit_is_tile_occupier_visible", "" -repl vptr, 0x66BF68, 0x68905C, 0x66BF68, "Demographics_Form_m22_draw", "void (__fastcall *) (Demographics_Form * this)" -define, 0x600070, 0x615570, 0x5FFF50, "PCX_Image_fill_area", "int (__fastcall *) (PCX_Image * this, int edx, RECT * rect, int color)" -define, 0x5FD360, 0x611290, 0x5FD240, "PCX_Image_set_text_effects", "void (__fastcall *) (PCX_Image * this, int edx, int text_color, int shadow_color, int shadow_offset_x, int shadow_offset_y)" -inlead, 0x5676C0, 0x573AB0, 0x567670, "Leader_get_optimal_city_number", "int (__fastcall *) (Leader * this)" -inlead, 0x55AA10, 0x566930, 0x55A9C0, "Leader_count_wonders_with_small_flag", "int (__fastcall *) (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null)" -repl call, 0x567706, 0x573AF6, 0x5676B6, "Leader_count_forbidden_palaces_for_ocn", "" -repl call, 0x550F99, 0x55C0E1, 0x550F49, "Unit_can_do_worker_command_for_button_setup", "" -repl call, 0x55132D, 0x55C484, 0x5512DD, "Unit_can_do_worker_command_for_button_setup", "" -define, 0x55B1A0, 0x567100, 0x55B150, "Leader_reveal_tile", "void (__fastcall *) (Leader * this, int edx, int x, int y)" -define, 0x5FCB10, 0x610790, 0x5FC9F0, "PCX_Image_draw_onto", "int (__fastcall *) (PCX_Image * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y)" -define, 0x5DBF60, 0x5EB4B0, 0x5DBE90, "Tile_get_terrain_move_cost", "int (__fastcall *) (Tile * this)" -define, 0x56D340, 0x579CC0, 0x56D2B0, "get_combat_occupier", "int (__cdecl *) (int tile_x, int tile_y, int civ_id, byte ignore_visibility)" -repl call, 0x45871C, 0x45A8C9, 0x45879C, "get_combat_occupier_in_Unit_ai_move_naval_power_unit", "" -define, 0x561480, 0x56D5E0, 0x561430, "Leader_has_tech_with_flag", "bool (__fastcall *) (Leader * this, int edx, enum AdvanceTypeFlags flag)" -inlead, 0x57D980, 0x58A680, 0x57D6E0, "Trade_Net_recompute_city_connections", "void (__fastcall *) (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id)" -inlead, 0x62B1A0, 0x64E220, 0x6274B0, "OpenGLRenderer_initialize", "int (__fastcall *) (OpenGLRenderer * this, int edx, PCX_Image * texture)" -inlead, 0x62B450, 0x64E510, 0x627760, "OpenGLRenderer_draw_line", "void (__fastcall *) (OpenGLRenderer * this, int edx, int x1, int y1, int x2, int y2)" -inlead, 0x62B490, 0x64E560, 0x6277A0, "OpenGLRenderer_set_color", "void (__fastcall *) (OpenGLRenderer * this, int edx, unsigned int rgb555)" -inlead, 0x62B570, 0x64E600, 0x627880, "OpenGLRenderer_set_opacity", "void (__fastcall *) (OpenGLRenderer * this, int edx, unsigned int alpha)" -inlead, 0x62B5B0, 0x64E660, 0x6278C0, "OpenGLRenderer_set_line_width", "void (__fastcall *) (OpenGLRenderer * this, int edx, int width)" -inlead, 0x62B5D0, 0x64E690, 0x6278E0, "OpenGLRenderer_enable_line_dashing", "void (__fastcall *) (OpenGLRenderer * this)" -inlead, 0x62B5F0, 0x64E6C0, 0x627900, "OpenGLRenderer_disable_line_dashing", "void (__fastcall *) (OpenGLRenderer * this)" -repl call, 0x5BFBFF, 0x5CE79A, 0x5BF90F, "Tile_check_water_for_retreat_on_defense", "bool (__fastcall *) (Tile * this)" -inlead, 0x5D2150, 0x5E13F0, 0x5D2080, "Map_build_trade_network", "void (__fastcall *) (Map * this)" -inlead, 0x57DE90, 0x58ABD0, 0x57DBF0, "Trade_Net_recompute_city_cons_and_res", "void (__fastcall *) (Trade_Net * this, int edx, bool param_1)" -repl call, 0x57DAF1, 0x58A7F9, 0x57D851, "Trade_Net_set_unit_path_to_fill_road_net", "" -repl call, 0x57DE29, 0x58AB4E, 0x57DB89, "Trade_Net_set_unit_path_to_find_sea_route", "" -define, 0x5EA6E0, 0x5F9F30, 0x5EA610, "Tile_has_colony", "bool (__fastcall *) (Tile * this)" -repl call, 0x5C1559, 0x5D00ED, 0x5C1269, "City_count_airports_for_airdrop", "" -define, 0x437CF0, 0x4398A0, 0x437D70, "Leader_get_city_count_on_continent", "int (__fastcall *) (Leader * this, int edx, int cont_id)" -repl call, 0x42EB3F, 0x430615, 0x42EBBF, "Leader_get_cont_city_count_for_worker_req", "" -repl call, 0x42EBCA, 0x430698, 0x42EC4A, "Leader_get_cont_city_count_for_worker_req", "" -repl call, 0x42EAD2, 0x4305AE, 0x42EB52, "Leader_get_city_count_for_worker_prod_cap", "" -inlead, 0x55D310, 0x5693A0, 0x55D2C0, "Leader_sum_unit_maintenance", "int (__fastcall *) (Leader * this, int edx, int government_id)" -define, 0xA52684, 0xA74E7C, 0xA52644, "p_game_difficulty", "int *" -define, 0x5CD960, 0x5DC940, 0x5CD880, "Unit_is_terrain_impassable", "bool (__fastcall *) (Unit * this, int edx, int terrain_type_index)" -define, 0x41CD22, 0x41E04C, 0x41CDA2, "ADDR_LUXURY_BOX_ROW_HEIGHT", "byte *" -define, 0x30, 0x38, 0x30, "LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET", "int" -define, 0x740A00, 0x75ADA0, 0x7409C0, "p_city_form", "City_Form *" -inlead, 0x5F82E0, 0x6087E0, 0x5F8210, "Sprite_draw", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table)" -repl call, 0x421295, 0x4227F5, 0x421315, "Sprite_draw_improv_img_on_city_form", "" -inlead, 0x421240, 0x4227A0, 0x4212C0, "draw_improv_icons_on_city_screen", "void (__cdecl *) (Base_List_Control * control, int improv_id, int item_index, int offset_x, int offset_y)" -define, 0x4B0710, 0x4B76C0, 0x4B07A0, "City_get_tourism_amount", "int (__fastcall *) (City * this, int edx, int improv_id)" -repl call, 0x42138C, 0x4228EC, 0x42140C, "City_get_tourism_amount_to_draw", "" -repl call, 0x4213FF, 0x42295F, 0x42147F, "Sprite_draw_tourism_gold", "" -repl call, 0x4BA075, 0x4C16E5, 0x4BA105, "City_calc_tile_yield_while_gathering", "" -repl call, 0x4B0512, 0x4B74D2, 0x4B05A2, "City_calc_tile_yield_while_gathering", "" -repl call, 0x4ADA3F, 0x4B4A28, 0x4ADACF, "City_calc_tile_yield_while_gathering", "" -repl call, 0x4B0F04, 0x4B7EB4, 0x4B0F94, "City_calc_tile_yield_while_gathering", "" -repl call, 0x4B25EF, 0x4B9576, 0x4B267F, "City_calc_tile_yield_while_gathering", "" -repl call, 0x4BA645, 0x4C1CA4, 0x4BA6D5, "City_calc_tile_yield_while_gathering", "" -inlead, 0x4B0E80, 0x4B7E30, 0x4B0F10, "City_recompute_yields_and_happiness", "void (__fastcall *) (City * this)" -inlead, 0x55EC80, 0x56AD30, 0x55EC30, "Leader_record_export", "bool (__fastcall *) (Leader * this, int edx, int importer_civ_id, int resource_id)" -inlead, 0x55ED60, 0x56AE10, 0x55ED10, "Leader_erase_export", "bool (__fastcall *) (Leader * this, int edx, int importer_civ_id, int resource_id)" -inlead, 0x4216A0, 0x422BF0, 0x421720, "City_Form_open", "void (__fastcall *) (City_Form * this, int edx, City * city, int param_2)" -define, 0x4B0330, 0x4B72F0, 0x4B03C0, "City_calc_tile_yield_at", "int (__fastcall *) (City * this, int edx, int yield_type, int tile_x, int tile_y)" -repl vptr, 0x66dd10, 0x68adf0, 0x66dd10, "Unit_has_enough_escorters_present", "bool (__fastcall *) (Unit * this)" -repl vptr, 0x66dd14, 0x68adf4, 0x66dd14, "Unit_check_escorter_health", "void (__fastcall *) (Unit * this, int edx, bool * has_any_escort_present, bool * any_escorter_cant_heal)" -inlead, 0x5694D0, 0x575900, 0x569480, "Leader_spawn_unit", "Unit * (__fastcall *) (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id)" -repl call, 0x5B7BA8, 0x5C69B8, 0x5B78B8, "Leader_spawn_captured_unit", "" -repl call, 0x5B7FCA, 0x5C657E, 0x5B7CDA, "Leader_spawn_captured_unit", "" -repl call, 0x5B74D8, 0x5C5E41, 0x5B71E8, "Leader_spawn_captured_unit", "" -inlead, 0x55E190, 0x56A220, 0x55E140, "Leader_enter_new_era", "void (__fastcall *) (Leader * this, int edx, bool param_1, bool no_online_sync)" -define, 0x55A270, 0x566180, 0x55A220, "Leader_get_name", "char * (__fastcall *) (Leader * this)" -define, 0x55A370, 0x566280, 0x55A320, "Leader_get_gender", "int (__fastcall *) (Leader * this)" -define, 0x55A210, 0x566120, 0x55A1C0, "Leader_get_civ_adjective", "char * (__fastcall *) (Leader * this)" -define, 0x55A240, 0x566150, 0x55A1F0, "Leader_get_civ_noun", "char * (__fastcall *) (Leader * this)" -define, 0x55A340, 0x566250, 0x55A2F0, "Leader_get_civ_formal_name", "char * (__fastcall *) (Leader * this)" -define, 0x55A2C0, 0x5661D0, 0x55A270, "Leader_get_title", "char * (__fastcall *) (Leader * this)" -repl call, 0x593614, 0x5A0DAE, 0x593334, "Leader_get_player_title_for_intro_popup", "" -inlead, 0x4A8240, 0x4AEF20, 0x4A82D0, "Fighter_animate_start_of_combat", "void (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender)" -define, 0x61A2E0, 0x63B710, 0x61A210, "Context_Menu_disable_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id)" -define, 0x61A380, 0x63B7E0, 0x61A2B0, "Context_Menu_put_image_on_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, Sprite * image)" -inlead, 0x4B8BA0, 0x4C0210, 0x4B8C30, "City_spawn_unit_if_done", "void (__fastcall *) (City * this)" -inlead, 0x5C0620, 0x5CF1C0, 0x5C0330, "Unit_can_upgrade", "bool (__fastcall *) (Unit * this)" -define, 0x4C0690, 0x4C7C50, 0x4C0720, "City_get_upgraded_type_id", "int (__fastcall *) (City * this, int edx, int unit_type_id)" -inlead, 0x56AAE0, 0x576F90, 0x56AA90, "Leader_upgrade_all_units", "void (__fastcall *) (Leader * this, int edx, int type_id)" -inlead, 0x4DE8B0, 0x4E7290, 0x4DE970, "Main_Screen_Form_upgrade_all_units", "void (__fastcall *) (Main_Screen_Form * this, int edx, int type_id)" -repl call, 0x56AB65, 0x577017, 0x56AB15, "Unit_can_perform_upgrade_all", "" -repl call, 0x4DE93C, 0x4E7316, 0x4DE9FC, "Unit_can_perform_upgrade_all", "" -repl call, 0x4BE89A, 0x4C5E80, 0x4BE92A, "Leader_spawn_unit_from_building", "" -repl call, 0x5C0727, 0x5CF2C7, 0x5C0437, "City_count_improvs_enabling_upgrade", "" -repl call, 0x5C0700, 0x5CF2A0, 0x5C0410, "City_count_improvs_enabling_upgrade", "" -repl call, 0x5C0715, 0x5CF2B5, 0x5C0425, "City_count_improvs_enabling_upgrade", "" -inlead, 0x4AECC0, 0x4B5C80, 0x4AED50, "City_raze", "void (__fastcall *) (City * this, int edx, int civ_id_responsible, bool checking_elimination)" -define, 0x563410, 0x56F6C0, 0x5633C0, "Leader_capture_city", "bool (__fastcall *) (Leader * this, int edx, City * city, Unit * unit, bool involuntary, bool converted)" -repl call, 0x55BA76, 0x567D20, 0x55BA26, "Leader_create_city_from_hut", "" -repl call, 0x568F57, 0x57538A, 0x568F07, "Leader_create_city_for_ai_respawn", "" -repl call, 0x5B35D3, 0x5C1F22, 0x5B32E3, "Leader_create_city_for_founding", "" -repl call, 0x5D2B8F, 0x5E1E68, 0x5D2ABF, "Leader_create_city_for_scenario", "" -inlead, 0x564800, 0x570BB0, 0x5647B0, "Leader_do_capture_city", "bool (__fastcall *) (Leader * this, int edx, City * city, bool involuntary, bool converted)" -define, 0x4BB410, 0x4C2A60, 0x4BB4A0, "City_count_citizens_of_race", "int (__fastcall *) (City * this, int edx, int race_id)" -define, 0x5A6060, 0x5B4350, 0x5A5D60, "count_units_at", "int (__cdecl *) (int x, int y, enum unit_filter filter, int arg_a, int arg_b, int arg_c)" -inlead, 0x4B9C60, 0x4C12E0, 0x4B9CF0, "City_draw_hud_icon", "void (__fastcall *) (City * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y)" -inlead, 0x4B9BB0, 0x4C1230, 0x4B9C40, "City_has_hud_icon", "bool (__fastcall *) (City * this)" -inlead, 0x4BFBF0, 0x4C71B0, 0x4BFC80, "City_draw_on_map", "void (__fastcall *) (City * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7)" -inlead, 0x4E7E30, 0x4F08F0, 0x4E7EF0, "MenuUnitItem_write_text_to_temp_str", "void (__fastcall *) (MenuUnitItem * this)" -define, 0xCAB2D8, 0xCCDB88, 0xCAB298, "temp_str", "char[4096]" -repl call, 0x5EDD89, 0x5FD7BE, 0x5EDCB9, "Tile_m74_Set_Square_Type_for_hill_gen", "" -inlead, 0x5D1EA0, 0x5E1140, 0x5D1DD0, "Map_place_scenario_things", "void (__fastcall *) (Map * this)" -repl vptr, 0x66C3EC, 0x6894D8, 0x66C3EC, "Advisor_Base_Form_domestic_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -repl vptr, 0x66F8CC, 0x68C988, 0x66F8CC, "Advisor_Base_Form_trade_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -repl vptr, 0x66E0CC, 0x68B1B8, 0x66E0CC, "Advisor_Base_Form_military_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -repl vptr, 0x66CAAC, 0x689B9C, 0x66CAAC, "Advisor_Base_Form_foreign_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -repl vptr, 0x66BD3C, 0x688E34, 0x66BD3C, "Advisor_Base_Form_cultural_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -repl vptr, 0x66F59C, 0x68C658, 0x66F59C, "Advisor_Base_Form_science_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -inlead, 0x4E79B0, 0x4F0470, 0x4E7A70, "Main_Screen_Form_open_quick_build_chooser", "void (__fastcall *) (Main_Screen_Form * this, int edx, City * city, int mouse_x, int mouse_y)" -repl call, 0x4E9941, 0x4F273F, 0x4E9A01, "Context_Menu_get_selected_item_on_unit_rcm", "int (__fastcall *) (Context_Menu * this)" -define, 256, 257, 256, "LBL_WAKE", "int" -define, 255, 256, 255, "LBL_ACTIVATE", "int" -define, 0x4C1280, 0x4C8860, 0x4C1310, "City_sum_buildings_naval_power", "int (__fastcall *) (City * this)" -repl call, 0x4A78EE, 0x4AE5A5, 0x4A797E, "City_sum_buildings_naval_power_for_zoc", "" -define, 0x5BE9E0, 0x5CD600, 0x5BE6F0, "Unit_count_contained_units", "int (__fastcall *) (Unit * this)" -repl call, 0x4B3089, 0x4BA00B, 0x4B3119, "Tile_check_water_to_block_pollution", "" -repl call, 0x4F416E, 0x4FD448, 0x4F422E, "Tile_set_flag_for_eruption_damage", "" -inlead, 0x4AF5D0, 0x4B6590, 0x4AF660, "City_confirm_production_switch", "bool (__fastcall *) (City * this, int edx, int order_type, int order_id)" -define, 0x62AEE0, 0x64DE20, 0x6271F0, "MappedFile_open", "void * (__fastcall *) (MappedFile * this, int edx, char * file_name, int sequential_access)" -repl call, 0x592160, 0x59F790, 0x591E80, "MappedFile_open_to_load_game", "" -define, 0x62AFA0, 0x64DF40, 0x6272B0, "MappedFile_create_file", "void * (__fastcall *) (MappedFile * this, int edx, LPCSTR file_path, unsigned file_size, int is_shared)" -repl call, 0x591CF1, 0x59F321, 0x591A11, "MappedFile_create_file_to_save_game", "" -define, 0x62B0C0, 0x64E0B0, 0x6273D0, "MappedFile_deinit", "void (__fastcall *) (MappedFile * this)" -repl call, 0x592322, 0x59F973, 0x592042, "MappedFile_deinit_after_saving_or_loading", "" -repl call, 0x591D9F, 0x59F3D0, 0x591ABF, "MappedFile_deinit_after_saving_or_loading", "" -repl vptr, 0x6701E4, 0x68D290, 0x6701E4, "Tile_m7_Check_Barbarian_Camp", "bool (__fastcall *) (Tile * this, int edx, int visible_to_civ)" -define, 0x44FBA5, 0x451C45, 0x44FC25, "ADDR_CHECK_BARB_CAMP_TO_DEFEND_RETURN", "int" -inlead, 0x590030, 0x59D690, 0x58FD50, "move_game_data", "int (__cdecl *) (byte * buffer, bool save_else_load)" -inlead, 0x5C14B0, 0x5D0040, 0x5C11C0, "Unit_can_airdrop", "bool (__fastcall *) (Unit * this)" -inlead, 0x5DF8D0, 0x5EF120, 0x5DF800, "City_Improvements_contains", "bool (__fastcall *) (City_Improvements * this, int edx, int id)" -inlead, 0x5DF890, 0x5EF0E0, 0x5DF7C0, "City_Improvements_set", "void (__fastcall *) (City_Improvements * this, int edx, int id, bool add_else_remove)" -repl call, 0x4B47C9, 0x4BB7B9, 0x4B4859, "Leader_has_tech_to_stop_disease", "" -define, 0x5D59E0, 0x5E4E20, 0x5D5910, "Map_change_tile_terrain", "void (__fastcall *) (Map * this, int edx, enum SquareTypes new_terrain_type, int x, int y)" -repl call, 0x461833, 0x463CAF, 0x4618B3, "Map_change_tile_terrain_by_worker", "" -inlead, 0x461470, 0x4638C0, 0x4614F0, "Unit_work_simple_job", "void (__fastcall *) (Unit * this, int edx, int job_id)" -define, 0x5C8B30, 0x5D7A50, 0x5C8840, "Unit_animate_cruise_missile_strike", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -repl call, 0x5B550E, 0x5C3E6F, 0x5B521E, "Unit_play_attack_animation_vs_tile", "" -repl call, 0x5B4C0E, 0x5C355E, 0x5B491E, "Map_compute_neighbor_index_for_cm_strike", "" -define, 0x5FF0E0, 0x614190, 0x5FEFC0, "PCX_Image_do_draw_centered_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len)" -repl call, 0x41AF59, 0x41C067, 0x41AFD9, "PCX_Image_do_draw_cntd_text_for_strat_res", "" -repl call, 0x41AE9F, 0x41BFA9, 0x41AF1F, "Sprite_draw_strat_res_on_city_screen", "" -define, 0x41AE1B, 0x41BF23, 0x41AE9B, "ADDR_MOST_STRAT_RES_ON_CITY_SCREEN", "void *" -inlead, 0x5BEB60, 0x5CD780, 0x5BE870, "Unit_can_heal_at", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5BECE0, 0x5CD900, 0x5BE9F0, "Unit_heal_at_start_of_turn", "void (__fastcall *) (Unit * this)" -define, 0x469590, 0x46BD40, 0x469610, "check_online_skip_flag", "bool (__stdcall *) (int unit_id)" -inlead, 0x448BF0, 0x44AB10, 0x448C70, "Leader_ai_eval_technology", "int (__fastcall *) (Leader * this, int edx, int id, bool param_2, bool param_3)" -inlead, 0x4446C0, 0x4464C0, 0x444740, "Leader_ai_eval_government", "int (__fastcall *) (Leader * this, int edx, int id)" -define, 0x474140, 0x476F70, 0x4741C0, "mp_despawn", "void (__fastcall *) (void * this, int edx, int unit_id, int civ_id_responsible, byte param_3, byte param_4, byte param_5, byte param_6)" -repl call, 0x5B483F, 0x5C3199, 0x5B454F, "Unit_despawn_after_killed_by_nuke", "" -repl call, 0x5B4374, 0x5C2CC4, 0x5B4084, "Unit_despawn_after_killed_by_nuke", "" -repl call, 0x5B4832, 0x5C318C, 0x5B4542, "mp_despawn_after_killed_by_nuke", "" -repl call, 0x5B4367, 0x5C2CB7, 0x5B4077, "mp_despawn_after_killed_by_nuke", "" -define, 0x4B3290, 0x4BA210, 0x4B3320, "City_has_unprotected_improv", "bool (__fastcall *) (City * this, int edx, int id)" -repl call, 0x422BE5, 0x4241A5, 0x422C65, "City_has_unprotected_improv_to_sell", "" -repl call, 0x5BB966, 0x5CA4B6, 0x5BB676, "UnitType_has_detector_ability_for_vis_check", "" -repl call, 0x5BB938, 0x5CA47F, 0x5BB648, "UnitType_has_detector_ability_for_vis_check", "" -repl call, 0x0FF, 0x5CA49B, 0x0FF, "UnitType_has_detector_ability_for_vis_check", "" -inlead, 0x5C33A0, 0x5D1FD0, 0x5C30B0, "Unit_check_airdrop_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C3C80, 0x5D28B0, 0x5C3990, "Unit_find_telepad_on_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y, bool show_selection_popup, Unit ** out_unit_telepad)" -inlead, 0x44B870, 0x44D840, 0x44B8F0, "Unit_ai_eval_airdrop_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C3460, 0x5D2090, 0x5C3170, "Unit_check_airlift_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C4F60, 0x5D3C40, 0x5C4C70, "Unit_can_airlift", "bool (__fastcall *) (Unit * this)" -inlead, 0x5C5040, 0x5D3D20, 0x5C4D50, "Unit_airlift", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -repl call, 0x450C9C, 0x452D98, 0x450D1C, "City_count_airports_for_ai_airlift_target", "" -repl call, 0x452A3A, 0x454B5F, 0x452ABA, "City_count_airports_for_ai_airlift_target", "" -inlead, 0x44F040, 0x4510E0, 0x44F0C0, "Unit_ai_go_to_capital", "bool (__fastcall *) (Unit * this)" -inlead, 0x5C3900, 0x5D2540, 0x5C3610, "Unit_check_rebase_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C3860, 0x5D24A0, 0x5C3570, "Unit_is_in_rebase_range", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -define, 0x5C71C0, 0x5D6060, 0x5C6ED0, "Unit_rebase", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -define, 0x5E6D20, 0x5F6580, 0x5E6C50, "diff_to_neighbor_index", "int (__cdecl *) (int dx, int dy, int lim)" -repl call, 0x421060, 0x4225BA, 0x4210E0, "Map_compute_ni_for_work_area", "" -repl vptr, 0x670190, 0x68D240, 0x670190, "Map_m28_find_cnter_neigh_point_for_work_area", "int (__fastcall *) (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim)" -define, 0x4C538E, 0x4CCC47, 0x4C53AE, "ADDR_FIND_CENTER_NP_SPOTLIGHT_RET", "int" -define, 0x4DF9E0, 0x4E8390, 0x4DFAA0, "Main_Screen_Form_bring_tile_into_view", "void (__fastcall *) (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5)" -repl call, 0x421853, 0x422DC1, 0x4218D3, "Main_Screen_Form_bring_cnter_view_city_focus", "" -repl call, 0x41BBB1, 0x41CD89, 0x41BC31, "Main_Screen_Form_bring_cnter_view_city_arrow", "" -repl call, 0x41BDB5, 0x41CFCD, 0x41BE35, "Main_Screen_Form_bring_cnter_view_city_arrow", "" -define, 0x4BBC80, 0x4C32D0, 0x4BBD10, "City_stop_working_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" -define, 0x4BB6F0, 0x4C2D50, 0x4BB780, "City_start_working_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" -repl call, 0x4ADA69, 0x4B4A51, 0x4ADAF9, "ni_to_diff_for_work_area", "" -repl call, 0x4ADAF4, 0x4B4AD8, 0x4ADB84, "ni_to_diff_for_work_area", "" -ext walup, 0x4ADB6F, 0x4B4B53, 0x4ADBFF, "", "" -repl call, 0x4AE49F, 0x4B5485, 0x4AE52F, "ni_to_diff_for_work_area", "" -ext walup, 0x4AE525, 0x4B550B, 0x4AE5B5, "", "" -repl call, 0x4AE7C2, 0x4B57A1, 0x4AE852, "ni_to_diff_for_work_area", "" -define, 0x4B0470, 0x4B7430, 0x4B0500, "City_add_or_remove_tile_yield", "void (__fastcall *) (City * this, int edx, int neighbor_index, bool add_else_remove)" -repl call, 0x4AE831, 0x4B5806, 0x4AE8C1, "City_add_or_remove_tile_yield_conv_ni", "" -ext walup, 0x4AE842, 0x4B580F, 0x4AE8D2, "", "" -repl call, 0x4AEF35, 0x4B5F13, 0x4AEFC5, "ni_to_diff_for_work_area", "" -repl call, 0x4AEFAF, 0x4B5F83, 0x4AF03F, "ni_to_diff_for_work_area", "" -ext walup, 0x4AF034, 0x4B5FFF, 0x4AF0C4, "", "" -ext walup, 0x4AF0CE, 0x4B6099, 0x4AF15E, "", "" -repl call, 0x4AF355, 0x4B631E, 0x4AF3E5, "ni_to_diff_for_work_area", "" -ext walup, 0x4AF3D7, 0x4B63A0, 0x4AF467, "", "" -repl call, 0x4AF4F6, 0x4B64B9, 0x4AF586, "ni_to_diff_for_work_area", "" -ext walup, 0x4AF5A6, 0x4B656B, 0x4AF636, "", "" -repl call, 0x4B0F2D, 0x4B7EDD, 0x4B0FBD, "ni_to_diff_for_work_area", "" -repl call, 0x4B0FC3, 0x4B7F73, 0x4B1053, "ni_to_diff_for_work_area", "" -ext walup, 0x4B1047, 0x4B7FF7, 0x4B10D7, "", "" -repl call, 0x4B2414, 0x4B93AD, 0x4B24A4, "ni_to_diff_for_work_area", "" -repl call, 0x4B247D, 0x4B9412, 0x4B250D, "City_add_or_remove_tile_yield_conv_ni", "" -ext walup, 0x4B2490, 0x4B941B, 0x4B2520, "", "" -define, 0x4C2680, 0x4C9EB0, 0x4C26A0, "City_is_neighboring_tile_in_area", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" -repl call, 0x4B260C, 0x4B9593, 0x4B269C, "City_is_neighboring_tile_in_area_conv_ni", "" -repl call, 0x4B261A, 0x4B95A1, 0x4B26AA, "City_add_or_remove_tile_yield_conv_ni", "" -ext walup, 0x4B2623, 0x4B95AA, 0x4B26B3, "", "" -repl call, 0x4BA09E, 0x4C170E, 0x4BA12E, "ni_to_diff_for_work_area", "" -repl call, 0x4BA124, 0x4C1790, 0x4BA1B4, "ni_to_diff_for_work_area", "" -ext walup, 0x4BA19E, 0x4C180A, 0x4BA22E, "", "" -repl call, 0x435459, 0x436F39, 0x4354D9, "ni_to_diff_for_work_area", "" -ext walup, 0x43550D, 0x436FED, 0x43558D, "", "" -repl call, 0x43688D, 0x4382FD, 0x43690D, "ni_to_diff_for_work_area", "" -ext walup, 0x436988, 0x4383F8, 0x436A08, "", "" -inlead, 0x4BB4D0, 0x4C2B20, 0x4BB560, "City_controls_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index, bool consider_enemy_units)" -repl call, 0x43564F, 0x43712B, 0x4356CF, "City_controls_tile_conv_ni", "" -repl call, 0x435667, 0x437143, 0x4356E7, "ni_to_diff_for_work_area", "" -repl call, 0x4356E3, 0x4371B9, 0x435763, "City_stop_working_tile_conv_ni", "" -ext walup, 0x4356F6, 0x4371C2, 0x435776, "", "" -repl call, 0x435729, 0x4371F1, 0x4357A9, "ni_to_diff_for_work_area", "" -repl call, 0x4357A1, 0x437269, 0x435821, "City_controls_tile_conv_ni", "" -ext walup, 0x4357D7, 0x43728F, 0x435857, "", "" -repl call, 0x4357E8, 0x4372A0, 0x435868, "City_start_working_tile_conv_ni", "" -repl call, 0x435895, 0x43733F, 0x435915, "ni_to_diff_for_work_area", "" -repl call, 0x435925, 0x4373D1, 0x4359A5, "City_controls_tile_conv_ni", "" -ext walup, 0x43595B, 0x4373F7, 0x4359DB, "", "" -repl call, 0x43597C, 0x437418, 0x4359FC, "ni_to_diff_for_work_area", "" -repl call, 0x435A91, 0x43752D, 0x435B11, "City_start_working_tile_conv_ni", "" -repl call, 0x5BD837, 0x5CC412, 0x5BD547, "Map_compute_ni_for_work_area", "" -repl vptr, 0x66DCB8, 0x68AD9C, 0x66DCB8, "City_find_best_tile_to_work", "int (__fastcall *) (City * this, int edx, Unit * worker, bool param_2)" -repl call, 0x436328, 0x437DBB, 0x4363A8, "ni_to_diff_for_work_area", "" -ext walup, 0x436805, 0x438273, 0x436885, "", "" -repl call, 0x420CC5, 0x422219, 0x420D45, "ni_to_diff_for_work_area", "" -repl call, 0x420DD7, 0x422327, 0x420E57, "ni_to_diff_for_work_area", "" -ext walup, 0x420F05, 0x422466, 0x420F85, "", "" -repl call, 0x420F3A, 0x42249A, 0x420FBA, "ni_to_diff_for_work_area", "" -ext walup, 0x421182, 0x4226D7, 0x421202, "", "" -repl call, 0x4AFCE0, 0x4B6C9C, 0x4AFD70, "City_is_neighboring_tile_in_area_conv_ni", "" -repl call, 0x4AFCEE, 0x4B6CAA, 0x4AFD7E, "City_add_or_remove_tile_yield_conv_ni", "" -ext walup, 0x4AFCF7, 0x4B6CB3, 0x4AFD87, "", "" -repl call, 0x4BA663, 0x4C1CC2, 0x4BA6F3, "City_is_neighboring_tile_in_area_conv_ni", "" -repl call, 0x4BA671, 0x4C1CD0, 0x4BA701, "City_add_or_remove_tile_yield_conv_ni", "" -ext walup, 0x4BA67A, 0x4C1CD9, 0x4BA70A, "", "" -repl call, 0x42053D, 0x421A1D, 0x4205BD, "Map_compute_ni_for_work_area", "" -repl call, 0x435D78, 0x437802, 0x435DF8, "Map_compute_ni_for_work_area", "" -repl call, 0x5DA3B6, 0x5E9925, 0x5DA2E6, "Map_compute_ni_for_work_area", "" -repl vptr, 0x66DCAC, 0x68AD90, 0x66DCAC, "City_find_min_value_tile", "int (__fastcall *) (City * this)" -repl call, 0x420ECD, 0x422426, 0x420F4D, "Sprite_draw_already_worked_tile_img", "" -repl call, 0x420668, 0x421B48, 0x4206E8, "Map_compute_ni_for_work_area", "" -define, 0x420672, 0x421B52, 0x4206F2, "ADDR_REDUNDANT_CHECK_ON_WORK_AREA_HOVER", "byte *" -repl call, 0x5668EE, 0x572C9B, 0x56689E, "Map_compute_ni_for_work_area", "" -define, 0x420547, 0x421A27, 0x4205C7, "ADDR_CITY_FORM_LEFT_CLICK_JUMP", "byte *" -define, 0x4BB4EB, 0x4C2B3C, 0x4BB57B, "ADDR_CONTROLS_TILE_JUMP", "byte *" -repl call, 0x5DA4D1, 0x5E9A48, 0x5DA401, "ni_to_diff_for_work_area", "" -ext walup, 0x5DA555, 0x5E9ACC, 0x5DA485, "", "" -repl call, 0x4C0309, 0x4C78FE, 0x4C0399, "ni_to_diff_for_work_area", "" -ext walup, 0x4C03EA, 0x4C79D9, 0x4C047A, "", "" -repl call, 0x442603, 0x4443D2, 0x442683, "Tile_m43_Get_field_30_for_city_loc_eval", "" -repl call, 0x4427B9, 0x444585, 0x442839, "Tile_m43_Get_field_30_for_city_loc_eval", "" -repl call, 0x4B2FC1, 0x4B9F41, 0x4B3051, "rand_int_to_place_pollution", "" -repl call, 0x4B2FF4, 0x4B9F76, 0x4B3084, "ni_to_diff_for_work_area", "" -define, 0x4B2FEB, 0x4B9F6E, 0x4B307B, "ADDR_SPAWN_POLLUTION_MOD", "byte *" -ext walup, 0x4B309F, 0x4BA025, 0x4B312F, "", "" -repl call, 0x43535D, 0x436E49, 0x4353DD, "ni_to_diff_for_work_area", "" -repl call, 0x4353CA, 0x436EB6, 0x43544A, "City_controls_tile_conv_ni", "" -ext walup, 0x43540B, 0x436EEF, 0x43548B, "", "" -define, 0x4E3B10, 0x4EC360, 0x4E3BD0, "Main_Screen_Form_tile_to_screen_coords", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int * out_x, int * out_y)" -repl call, 0x420C68, 0x4221BC, 0x420CE8, "Main_Screen_Form_t2s_coords_to_draw_yields", "" -repl call, 0x420887, 0x421D88, 0x420907, "Main_Screen_Form_t2s_coords_to_draw_yields", "" -inlead, 0x420C40, 0x422190, 0x420CC0, "City_Form_draw_yields_on_worked_tiles", "void (__fastcall *) (City_Form * this)" -inlead, 0x420860, 0x421D60, 0x4208E0, "City_Form_draw_highlighted_yields", "bool (__fastcall *) (City_Form * this, int edx, int tile_x, int tile_y, int neighbor_index)" -inlead, 0x420F20, 0x422480, 0x420FA0, "City_Form_draw_border_around_workable_tiles", "void (__fastcall *) (City_Form * this)" -inlead, 0x4229F0, 0x423FA0, 0x422A70, "City_Form_draw_food_income_icons", "void (__fastcall *) (City_Form * this)" -inlead, 0x4BFAB0, 0x4C7070, 0x4BFB40, "City_draw_production_income_icons", "void (__fastcall *) (City * this, int edx, int canvas, int * rect_ptr)" -repl call, 0x4BFBB7, 0x4C7177, 0x4BFC47, "Sprite_draw_production_income_icon", "" -repl call, 0x421095, 0x4225EF, 0x421115, "Main_Screen_Form_t2s_coords_to_draw_yields", "" -repl call, 0x420FC5, 0x422525, 0x421045, "Map_get_tile_for_work_area_drawing", "" -repl call, 0x420DA2, 0x4222F8, 0x420E22, "Map_get_tile_for_work_area_drawing", "" -repl call, 0x5DA3BE, 0x5E992D, 0x5DA2EE, "City_stop_working_polluted_tile", "" -repl vptr, 0x66DCB0, 0x68AD94, 0x66DCB0, "City_manage_by_governor", "void (__fastcall *) (City * this, int edx, bool param_1)" -define, 0x5DA3CC, 0x5E993B, 0x5DA2FC, "ADDR_MANAGE_CITY_AFTER_POLLUTION_RETURN", "int" -define, 0x56D040, 0x5799C0, 0x56CFB0, "find_nearest_city", "City * (__cdecl *) (int tile_x, int tile_y, int owner_id, int continent_id, int ignore_owner_id, int perspective_id, City * ignore_city)" -repl call, 0x438A5B, 0x43A5E6, 0x438ADB, "find_nearest_city_for_ai_alliance_eval", "" -define, 0x9C34EC, 0x9E5CE4, 0x9C34AC, "p_nearest_city_distance", "int *" -define, 0x565400, 0x571790, 0x5653B0, "Leader_bounce_trespassing_units", "void (__fastcall *) (Leader * this, int edx, int against_civ_id)" -inlead, 0x446840, 0x448650, 0x4468C0, "Leader_begin_turn", "void (__fastcall *) (Leader * this)" -repl call, 0x5654AC, 0x571841, 0x56545C, "Unit_is_visible_to_civ_for_bouncing", "" -inlead, 0x5025B0, 0x50C230, 0x502650, "Leader_make_peace", "void (__fastcall *) (Leader * this, int edx, int civ_id)" -inlead, 0x5C5BD0, 0x5D4970, 0x5C58E0, "Unit_can_load", "bool (__fastcall *) (Unit * this, int edx, Unit * passenger)" -repl call, 0x5CDE34, 0x5DCEF4, 0x5CDD54, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x5CDE4C, 0x5DCF0C, 0x5CDD6C, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x5C7774, 0x5D6624, 0x5C7484, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x57F6F4, 0x58C41E, 0x57F454, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x57FF93, 0x58CCA6, 0x57FCF3, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x580486, 0x58D1B5, 0x5801E6, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x464BA9, 0x46715E, 0x464C29, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x46514C, 0x46771C, 0x4651CC, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x465560, 0x467B41, 0x4655E0, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x58067D, 0x58D39A, 0x5803DD, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x565693, 0x571A45, 0x565643, "Leader_count_any_shared_wonders_with_flag", "" -inlead, 0x4BD420, 0x4C4A80, 0x4BD4B0, "City_add_happiness_from_buildings", "void (__fastcall *) (City * this, int edx, int * inout_happiness, int * inout_unhappiness)" -define, 0x4BDDE0, 0x4C5410, 0x4BDE70, "City_count_other_buildings_on_continent", "int (__fastcall *) (City * this, int edx, int improv_id)" -repl call, 0x4BD5F0, 0x4C4C50, 0x4BD680, "City_count_other_cont_happiness_buildings", "" -repl call, 0x5C056D, 0x5CF10D, 0x5C027D, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4ACEFE, 0x4B3ED3, 0x4ACF8E, "Leader_count_any_shared_wonders_with_flag", "" -inlead, 0x562380, 0x56E4F0, 0x562330, "Leader_update_great_library_unlocks", "void (__fastcall *) (Leader * this)" -repl call, 0x562390, 0x56E4FB, 0x562340, "Leader_count_any_shared_wonders_with_flag", "" -define, 0x4B5050, 0x4BC030, 0x4B50E0, "City_can_take_outside_shields", "bool (__fastcall *) (City * this, int edx, int param_1)" -define, 0x56A210, 0x5766B0, 0x56A1C0, "Leader_get_unit_cost", "int (__fastcall *) (Leader * this, int edx, int id, bool ignore_difficulty)" -repl call, 0x4A101C, 0x4A7BDC, 0x4A10AC, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4A10B8, 0x4A7C70, 0x4A1148, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4C0D41, 0x4C8341, 0x4C0DD1, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4C0D87, 0x4C8387, 0x4C0E17, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4C118D, 0x4C8779, 0x4C121D, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4BD95E, 0x4C4FB4, 0x4BD9EE, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4B24E5, 0x4B946C, 0x4B2575, "Leader_count_any_shared_wonders_with_flag", "" -inlead, 0x55A7E0, 0x5666F0, 0x55A790, "Leader_has_wonder_doubling_happiness_from", "bool (__fastcall *) (Leader * this, int edx, int improv_id)" -inlead, 0x56A2A0, 0x576740, 0x56A250, "Leader_can_build_city_improvement", "bool (__fastcall *) (Leader * this, int edx, int i_improv, bool param_2)" -repl call, 0x4BF828, 0x4C6DD8, 0x4BF8B8, "Sprite_draw_citizen_head", "" -repl call, 0x4BF95D, 0x4C6F0D, 0x4BF9ED, "Sprite_draw_entertainer_yield_icon", "" -repl call, 0x4BF912, 0x4C6EC2, 0x4BF9A2, "Sprite_draw_scientist_yield_icon", "" -repl call, 0x4BF8C0, 0x4C6E70, 0x4BF950, "Sprite_draw_tax_collector_yield_icon", "" -repl call, 0x4BF9E1, 0x4C6FA1, 0x4BFA71, "Sprite_draw_civil_engineer_yield_icon", "" -repl call, 0x4BFA45, 0x4C7005, 0x4BFAD5, "Sprite_draw_police_officer_yield_icon", "" -inlead, 0x4B9270, 0x4C08E0, 0x4B9300, "City_add_building_if_done", "void (__fastcall *) (City * this)" -define, 0x9C34E4, 0x9E5CDC, 0x9C34A4, "p_zoom_to_city_after_update", "bool *" -define, 0x5812BA, 0x58DFE7, 0x58101A, "ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN", "byte *" -inlead, 0x4BFD40, 0x4C7300, 0x4BFDD0, "City_get_turns_to_build", "int (__fastcall *) (City * this, int edx, int order_type, int order_id, bool param_3)" -repl call, 0x4C06C0, 0x4C7C80, 0x4C0750, "City_can_build_upgrade_type", "" -define, 0x4C1F80, 0x4C96B0, 0x4C2010, "Hash_Table_look_up", "bool (__fastcall *) (Hash_Table * this, int edx, int key, int * out_value)" -inlead, 0x557720, 0x563530, 0x5576D0, "Main_GUI_position_elements", "void (__fastcall *) (Main_GUI * this)" -define, 0x5FE8A0, 0x613550, 0x5FE780, "PCX_Image_get_text_line_height", "int (__fastcall *) (PCX_Image * this)" -repl vptr, 0x66AFF0, 0x6880F0, 0x66AFF0, "Civilopedia_Article_m01_Draw_GCON_or_RACE", "void (__fastcall *) (Civilopedia_Article * this)" -repl vptr, 0x66AFA8, 0x6880A8, 0x66AFA8, "Civilopedia_Article_m01_Draw_UNIT", "void (__fastcall *) (Civilopedia_Article * this)" -repl call, 0x5FF8B5, 0X614B5D, 0x5FF795, "PCX_Image_do_draw_centered_text_in_wrap_func", "" -repl call, 0x5FF7E0, 0x614A5F, 0x5FF6C0, "PCX_Image_draw_text_in_wrap_func", "" -repl call, 0x0FF, 0x614A7A, 0x0FF, "PCX_Image_draw_text_no_len_in_wrap_func", "" -repl vptr, 0x66B1B8, 0x6882B8, 0x66B1B8, "Civilopedia_Form_m68_Show_Dialog", "int (__fastcall *) (Civilopedia_Form * this, int edx, int param_1, void * param_2, void * param_3)" -repl vptr, 0x66B17C, 0x68827C, 0x66B17C, "Civilopedia_Form_m53_On_Control_Click", "void (__fastcall *) (Civilopedia_Form * this, int edx, CivilopediaControlID control_id)" -repl vptr, 0x66B100, 0x688200, 0x66B100, "Civilopedia_Form_m22_Draw", "void (__fastcall *) (Civilopedia_Form * this)" -repl call, 0x4CC5AA, 0x4D462E, 0x4CC66A, "Button_initialize_civilopedia_description", "" -define, 0x179, 0x17A, 0x179, "LBL_EFFECTS", "int" -define, 0x17A, 0x17B, 0x17A, "LBL_PREVIOUS", "int" -define, 0x128, 0x129, 0x128, "LBL_MORE", "int" -define, 0x537700, 0x541D30, 0x537780, "play_sound_effect", "void (__cdecl *) (int sound_effect)" -repl call, 0x578CD9, 0x585DF3, 0x578C49, "Tile_check_water_for_navigator_cell_coloring", "" -inlead, 0x49F5C0, 0x4A6080, 0x49F650, "PopupForm_impl_begin_showing_popup", "int (__fastcall *) (PopupForm * this)" -repl call, 0x49F5CB, 0x4A608B, 0x49F65B, "is_online_game_for_show_popup", "" -define, 0x4EEC40, 0x4F7BE0, 0x4EED00, "Animator_update", "void (__fastcall *) (Animator * this)" -inlead, 0x5C32F0, 0x5D1F20, 0x5C3000, "Unit_ai_can_sacrifice", "bool (__fastcall *) (Unit * this, int edx, bool requires_city)" -inlead, 0x4C5A10, 0x4CD2C0, 0x4C5A30, "Map_Renderer_load_images", "void (__fastcall *) (Map_Renderer *this, int edx)" -define, 0x446114, 0x447EF6, 0x446194, "ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN", "byte *" -define, 0x5663F0, 0x57275D, 0x5663A0, "ADDR_CITY_LIM_CMP_IN_CREATE_CITY", "byte *" -define, 0x4F8D76, 0x5024E6, 0x4F8E36, "ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR", "byte *" -define, 0x4C2420, 0x4C9C10, 0x4C2440, "Buildings_Info_get_age_in_years", "int (__fastcall *) (Buildings_Info * this, int edx, int building_index)" -repl call, 0x4B073C, 0x4B76F0, 0x4B07CC, "Buildings_Info_get_age_in_years_for_tourism", "" -define, 0x501CD0, 0x50B960, 0x501D70, "Leader_make_contact", "void (__fastcall *) (Leader * this, int edx, int civ_id, bool no_online_sync)" -define, 0x5F83E0, 0x608910, 0x5F8310, "Sprite_draw_for_hud", "int (__fastcall *) (Sprite * this, int edx, Sprite * alpha, int param_2, PCX_Image * canvas, int x, int y, int param_6)" -repl call, 0x55374D, 0x55EDF8, 0x5536FD, "Sprite_draw_minimap_frame", "" -define, 0x5792AB, 0x5863CB, 0x57921B, "ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT", "byte *" -repl call, 0x44580E, 0x44760E, 0x44588E, "Unit_has_king_ability_for_find_unsupported", "" -define, 0x4BFD20, 0x4C72E0, 0x4BFDB0, "City_get_turns_to_build_2", "int (__fastcall *) (City * this, int edx, City_Order * order, bool param_2)" -repl call, 0x45FF66, 0x462336, 0x45FFE6, "City_get_turns_to_build_2_for_ai_move_leader", "" -repl call, 0x4600F8, 0x4624E5, 0x460178, "City_get_turns_to_build_2_for_ai_move_leader", "" -define, 0x50FDB3, 0x51A057, 0x50FE53, "ADDR_MAX_TRADABLE_CITY_ID", "byte *" -define, 0x505B21, 0x50F8EB, 0x505BC1, "ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR", "byte *" -define, 0x51000C, 0x51A2AC, 0x5100AC, "ADDR_MAX_TRADABLE_UNIT_ID", "byte *" -define, 0x505B67, 0x50F931, 0x505C07, "ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR", "byte *" -repl vptr, 0x66A52C, 0x687638, 0x66A52C, "Map_Renderer_m09_Draw_Tile_Resources", "void (__fastcall *) (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" -repl vptr, 0x66A538, 0x687644, 0x66A538, "Map_Renderer_m12_Draw_Tile_Buildings", "void (__fastcall *) (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" -inlead, 0x5F61A0, 0x605F50, 0x5F60D0, "Map_Renderer_m11_Draw_Tile_Irrigation", "void (__fastcall *) (Map_Renderer *this, int edx, int visible_to_civ, int tile_x, int tile_y, int param_4, int param_5, int param_6)" -repl call, 0x5F5580, 0x6053D2, 0x5F54B0, "Tile_has_city_or_district", "" -repl call, 0x5F5816, 0x605639, 0x5F5746, "Tile_has_city_or_district", "" -repl call, 0x5F5ABB, 0x6058AF, 0x5F59EB, "Tile_has_city_or_district", "" -repl call, 0x5F5D75, 0x605B31, 0x5F5CA5, "Tile_has_city_or_district", "" -inlead, 0x56CEB0, 0x579830, 0x56CE20, "get_building_defense_bonus_at", "int (__cdecl *) (int x, int y, int param_3)" -define, 0x4B0540, 0x4B7500, 0x4B05D0, "City_update_food_consumption", "void (__fastcall *) (City * this)" -define, 0x5660E0, 0x572460, 0x566090, "Leader_get_food_cost_factor", "int (__fastcall *) (Leader *this, int edx, bool ignore_difficulty)" -define, 0x427540, 0x428C90, 0x4275C0, "City_get_size_class", "int (__fastcall *) (City *this)" -inlead, 0x5B39A0, 0x5C22F0, 0x5B36B0, "is_not_pop_capped_or_starving", "bool (__stdcall *) (City * city)" -inlead, 0x4068E0, 0x406E40, 0x406910, "set_worker_animation", "void (__fastcall *) (void * this, int edx, Unit * unit, int job_id)" -define, 0x5C66D0, 0x5D5520, 0x5C63E0, "get_worker_remaining_turns_to_complete", "int (__fastcall *) (Unit * this, int edx, int job_id)" -inlead, 0x435BA0, 0x437630, 0x435C20, "City_instruct_worker", "bool (__fastcall *) (City * this, int edx, int tile_x, int tile_y, bool param_3, Unit * worker)" -repl vptr, 0x66A528, 0x687634, 0x66A528, "Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp", "void (__fastcall *) (Map_Renderer * this, int edx, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" -repl vptr, 0x66A5D8, 0x6876E4, 0x66A5D8, "Map_Renderer_m52_Draw_Roads", "void (__fastcall *) (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" -repl vptr, 0x66A5D0, 0x6876DC, 0x66A5D0, "Map_Renderer_m52_Draw_Railroads", "void (__fastcall *) (Map_Renderer * this, int edx, int sprite_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" -inlead, 0x5EB580, 0x5FADD0, 0x5EB4B0, "Map_impl_generate", "void (__fastcall *) (Map * this, int edx, int seed, bool is_multiplayer_game, int num_seafaring_civs)" -inlead, 0x4E5580, 0x4EDEB0, 0x4E5640, "Main_Screen_Form_draw_city_hud", "void (__fastcall *) (Main_Screen_Form * this, int edx, PCX_Image * canvas)" -inlead, 0x4BFF80, 0x4C7580, 0x4C0010, "City_can_build_improvement", "bool (__fastcall *) (City * this, int edx, int i_improv, bool apply_strict_rules)" -repl call, 0x5C1C53, 0x5D07F6, 0x5C1963, "Unit_has_army_ability_to_perform_unload", "" -inlead, 0x5C59B0, 0x5D4740, 0x5C56C0, "Unit_disembark", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -define, 0x4A12D0, 0x4A7E80, 0x4A1360, "Fighter_prefer_first_defender_1", "bool (__fastcall *) (Fighter * this, int edx, Unit * first, int first_strength, Unit * second, int second_strength, bool param_5)" -repl call, 0x5C5C82, 0x5D4A23, 0x5C5992, "Unit_has_ability_no_load_non_army_passengers", "" -repl call, 0x5C5C93, 0x5D4A34, 0x5C59A3, "Unit_has_ability_no_load_transport_into_army", "" -inlead, 0x4A1590, 0x4A8140, 0x4A1620, "Fighter_unit_can_defend", "bool (__fastcall *) (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y)" -define, 0x558F70, 0x564E30, 0x558F20, "Leader_is_enemy_unit", "bool (__fastcall *) (Leader * this, int edx, Unit * unit)" -repl call, 0x5C6C5B, 0x5D5AD4, 0x5C696B, "Leader_is_enemy_unit_for_ground_aa", "" -repl call, 0x5BC013, 0x5CAB6A, 0x5BBD23, "Unit_has_army_ability_for_passenger_despawn", "" -define, 0x4A63F4, 0x4AD09E, 0x4A6484, "DESPAWN_TO_FIGHT_1_RETURN", "int" -define, 0x4A6EF7, 0x4ADBAB, 0x4A6F87, "DESPAWN_TO_FIGHT_2_RETURN", "int" -define, 0x4A4436, 0x4AB104, 0x4A44C6, "DESPAWN_TO_DO_BOMBARD_TILE_RETURN", "int" -define, 0x4A31C6, 0x4A9E19, 0x4A3256, "DESPAWN_TO_CRUISE_MISSILE_DEFENDER_RETURN", "int" -define, 0x5659E2, 0x571D83, 0x565992, "DESPAWN_TO_BOUNCE_TRESPASSING_UNITS_RETURN", "int" -define, 0x5B4844, 0x5C319E, 0x5B4554, "DESPAWN_TO_NUKE_DAMAGE_RETURN", "int" -define, 0x5B8462, 0x5C6E78, 0x5B8172, "DESPAWN_TO_DO_CAPTURE_UNITS_RETURN", "int" -define, 0x5BC0A2, 0x5CABF1, 0x5BBDB2, "DESPAWN_RECURSIVE_RETURN", "int" -define, 0x5C7030, 0x5D5EBB, 0x5C6D40, "DESPAWN_TO_TRY_FLYING_OVER_TILE_RETURN", "int" -repl call, 0x5B8D95, 0x5C7801, 0x5B8AA5, "count_units_at_in_try_capturing", "" -define, 0x5F35C2, 0x603442, 0x5F34F2, "ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9", "byte *" -inlead, 0x5F22A0, 0x6020D0, 0x5F21D0, "Map_generate_resources", "void (__fastcall *) (Map * this, int edx, int secondary_seed)" -define, 0x5F2C25, 0x602AF6, 0x5F2B55, "ADDR_RESOURCE_GEN_TILE_COUNT_DIV", "byte *" -repl call, 0x5BFA0C, 0x5CE59E, 0x5BF71C, "rand_int_to_enslave", "" -repl call, 0x52A165, 0x53452B, 0x52A205, "Sprite_draw_espionage_screen_target_civ_bkg", "" -repl call, 0x52A1C1, 0x534587, 0x52A261, "Civilopedia_Article_get_name_for_esp_screen", "" -define, 0xA422F8, 0xA64AF8, 0xA422B8, "p_espionage_form", "Espionage_Form *" -define, 0x680758, 0x69D768, 0x680758, "animation_names", "char **" -define, 0x5BF2FB, 0x5CDE95, 0x5BF00B, "ADDR_SKIP_VICTORY_ANIM_IF_AIR", "byte *" -repl call, 0x5BF4D5, 0x5CE066, 0x5BF1E5, "Animator_play_one_shot_victory_animation", "" -inlead, 0x4DBFC0, 0x4E4990, 0x4DC080, "Main_Screen_Form_assemble_selectable_units", "void (__fastcall *) (Main_Screen_Form * this)" -inlead, 0x4DBA70, 0x4E4440, 0x4DBB30, "Main_Screen_Form_set_selected_unit", "void (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit, bool param_2)" -inlead, 0x4DBD70, 0x4E4740, 0x4DBE30, "Main_Screen_Form_find_next_unit_for_cycling", "Unit * (__fastcall *) (Main_Screen_Form * this)" -define, 0x4EDD40, 0x4F6C90, 0x4EDE00, "UnitIDList_insert_before", "void (__fastcall *) (UnitIDList * this, int edx, int id, UnitIDItem * item)" -define, 0x5BE970, 0x5CD590, 0x5BE680, "Unit_can_cycle_to", "bool (__fastcall *) (Unit * this)" -define, 0x4DABB2, 0x4E3570, 0x4DAC72, "SET_SELECTED_UNIT_TO_ISSUE_WAIT_COMMAND_RET", "int" -repl vptr, 0x66DCD0, 0x68ADB4, 0x66DCD0, "City_m22", "void (__fastcall *) (City * this, int edx, bool param_1)" -define, 0x4B95D7, 0x4C0C43, 0x4B9667, "CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_1", "int" -define, 0x4B96C9, 0x4C0D35, 0x4B9759, "CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_2", "int" -define, 0x4B90D6, 0x4C0743, 0x4B9166, "CITY_M22_TO_SPAWN_UNIT_IF_DONE_RETURN", "int" -inlead, 0x5B6CE0, 0x5C5670, 0x5B69F0, "Unit_do_capture_units", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, int owner_civ_id)" -define, 0xA38C18, 0xA5B418, 0xA38BD8, "p_advisor_internal_form", "Advisor_Internal_Form *" -repl call, 0x51DC54, 0x527A41, 0x51DCF4, "PCX_Image_process_dom_adv_turn_count_text", "" -define, 0x4B1205, 0x4B81B5, 0x4B1295, "ADDR_CORRUPTION_CAPITAL_CHECK", "byte *" -define, 0x4B12C0, 0x4B8272, 0x4B1350, "ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT", "byte *" -define, 0xCCF76C, 0xCF1DC4, 0xCCF724, "p_code_page", "unsigned *" -define, 0x4ED5F0, 0x4F6520, 0x4ED6B0, "MenuUnitList_get_length", "int (__fastcall *) (MenuUnitList * this)" -repl call, 0x4E8BD4, 0x4F1895, 0x4E8C94, "MenuUnitList_get_length_before_sorting", "" -define, 0x4E7E00, 0x4F08C0, 0x4E7EC0, "MenuUnitItem_should_appear_after", "bool (__fastcall *) (MenuUnitItem * this, int edx, MenuUnitItem * other)" -define, 0xA52B6C, 0xA75364, 0xA52B2C, "p_allow_ai_patrol", "bool *" -define, 0x5F1F50, 0x601D30, 0x5F1E80, "Map_finalize_params", "void (__fastcall *) (Map * this)" -repl call, 0x5D1888, 0x5E0B0E, 0x5D17B8, "Map_finalize_params_for_scenario_map", "" -define, 518, 519, 518, "LBL_NO_BARBARIANS", "int" -define, 545, 546, 545, "LBL_RANDOM_BARBS", "int" -define, 0x4BA230, 0x4C18A0, 0x4BA2C0, "City_remove_population", "void (__fastcall *) (City * this, int edx, int num_pops, int race_id, char param_3)" -define, 0x4AE280, 0x4B5260, 0x4AE310, "City_get_largest_adjacent_sea", "int (__fastcall *) (City * this)" -repl call, 0x4C008E, 0x4C7686, 0x4C011E, "City_get_largest_adjacent_sea_within_work_area", "" -repl call, 0x4C010F, 0x4C7707, 0x4C019F, "Map_impl_has_fresh_water_within_work_area", "" -repl call, 0x4C0173, 0x4C776C, 0x4C0203, "Map_impl_is_near_river_within_work_area", "" -repl call, 0x4C01AF, 0x4C77A8, 0x4C023F, "Map_impl_is_near_river_within_work_area", "" -repl call, 0x4C01CF, 0x4C77C8, 0x4C025F, "Map_impl_is_near_lake_within_work_area", "" -inlead, 0x458120, 0x45A2E0, 0x4581A0, "Unit_ai_move_naval_power_unit", "void (__fastcall *) (Unit * this)" -inlead, 0x45A170, 0x45C380, 0x45A1F0, "Unit_ai_move_naval_transport", "void (__fastcall *) (Unit * this)" -inlead, 0x460620, 0x462A20, 0x4606A0, "Unit_ai_move_naval_missile_transport", "void (__fastcall *) (Unit * this)" -inlead, 0x44C130, 0x44E110, 0x44C1B0, "Unit_ai_eval_pillage_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x456840, 0x458A50, 0x4568C0, "Unit_ai_move_air_bombard_unit", "void (__fastcall *) (Unit * this)" -inlead, 0x4579E0, 0x459BB0, 0x457A60, "Unit_ai_move_air_defense_unit", "void (__fastcall *) (Unit * this)" -inlead, 0x459CE0, 0x45BF00, 0x459D60, "Unit_ai_move_air_transport", "void (__fastcall *) (Unit * this)" -define, 0x5C1920, 0x5D04B0, 0x5C1630, "Unit_airdrop", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -repl call, 0x4C0D87, 0x4C8387, 0x4C0E17, "Leader_count_wonders_with_flag_ignore_great_wall", "" -repl call, 0x5D3D67, 0x5E30FC, 0x5D3C97, "Tile_has_colony_ignore_extraterritorial", "" -inlead, 0x440100, 0x441ED0, 0x440180, "Leader_get_attitude_toward", "int (__fastcall *) (Leader * this, int edx, int civ_id, int param_2)" -inlead, 0x5D7080, 0x5E64E0, 0x5D6FB0, "Map_check_colony_location", "int (__fastcall *) (Map * this, int edx, int tile_x, int tile_y, int civ_id)" -inlead, 0x5BCE60, 0x5CBA10, 0x5BCB70, "Unit_select_army_member_for_combat", "Unit * (__fastcall *) (Unit * this, int edx, int param_1, char param_2)" -inlead, 0x44C340, 0x44E330, 0x44C3C0, "Unit_ai_eval_bombard_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, int param_3)" -define, 0x5CD770, 0x5DC720, 0x5CD690, "UnitIDList_insert_after", "void (__fastcall *) (UnitIDList * this, int edx, int id, UnitIDItem * item)" -repl call, 0x5BBBA6, 0x5CA70C, 0x5BB8B6, "UnitIDList_insert_after_init", "" -define, 0x5BCC90, 0x5CB840, 0x5BC9A0, "Unit_load_into_army", "void (__fastcall *) (Unit * this, int edx, Unit * loadee)" -repl call, 0x5B9FEC, 0x5C8AB3, 0x5B9CFC, "Unit_load_into_army_after_move_to_adj_tile", "" -define, 0x5FF750, 0x6149E0, 0x5FF630, "PCX_Image_draw_and_wrap_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int width)" -repl call, 0x4D5283, 0x4DDA46, 0x4D5343, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -repl call, 0x4D52EA, 0x4DDAAE, 0x4D53AA, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -repl call, 0x4D5340, 0x4DDB05, 0x4D5400, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -repl call, 0x4D5396, 0x4DDB5C, 0x4D5456, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -repl call, 0x4D5400, 0x4DDBC5, 0x4D54C0, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -repl call, 0x4D5464, 0x4DDC29, 0x4D5524, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -define, 0x1A5, 0x1A6, 0x1A5, "LBL_OPERATIONAL_RANGE", "int" -define, 0x4D519C, 0x4DD953, 0x4D525C, "ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS", "byte *" -define, 0x1A8, 0x1A9, 0x1A8, "LBL_BOMBARD_RANGE", "int" -ignore, 0x5FC710, 0x0, 0x0, "PCX_Image_create_and_init_jgl_image", "int (__fastcall *) (PCX_Image * this, int edx, int width, int height, int bit_depth, int param_4, int param_5, int param_6)" -ignore, 0x5FCC50, 0x0, 0x0, "PCX_Image_draw_region_to_location", "void (__fastcall *) (PCX_Image * this, int edx, PCX_Image * canvas, int src_x, int src_y, int dest_x, int dest_y, int width, int height)" -ignore, 0x600050, 0x0, 0x0, "PCX_Image_fill", "void (__fastcall *) (PCX_Image * this, int edx, int color)" -ignore, 0x5FFF10, 0x0, 0x0, "PCX_Image_set_color_table", "int (__fastcall *) (PCX_Image * this, int edx, PCX_Color_Table * color_table)" -ignore, 0x4507B0, 0x452860, 0x0, "Unit_ai_move_offensive_unit", "void (__fastcall *) (Unit * this)" -ignore, 0x558F70, 0x0, 0x0, "Leader_is_enemy_unit", "char (__fastcall *) (Leader * this, int edx, Unit * unit)" -ignore, 0x4BFD40, 0x0, 0x0, "City_get_turns_to_build", "int (__fastcall *) (City * this, int edx, int order_type, int order_id, char param_3)" -ignore, 0x4E3D90, 0x0, 0x0, "Main_Screen_Form_is_unit_hidden_from_player", "bool (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit)" -ignore, 0x4E8850, 0x4F14E0, 0x4E8910, "Main_Screen_Form_open_right_click_unit_menu", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" -ignore, 0x5CCBB0, 0x0, 0x0, "Unit_can_pass_between", "PassBetweenValidity (__fastcall *) (Unit * this, int edx, int from_x, int from_y, int to_x, int to_y, byte param_5)" -ignore, 0x452510, 0x454600, 0x452590, "ai_move_defensive_unit", "void (__fastcall *) (Unit * this)" -ignore, 0x5E78E0, 0x5F7130, 0x0, "General_load", "void (__fastcall *) (General * this, int edx, byte ** buffer)" -ignore, 0x5E7020, 0x5F6870, 0x0, "General_clear", "void (__fastcall *) (General * this)" -ignore, 0x605010, 0x61C6A0, 0x604F00, "Base_Form_impl_m01_Show_Enabled", "void (__fastcall *) (Base_Form * this, int edx, byte flags)" -ignore, 0x74AF60, 0x0, 0x0, "p_sync_object", "void *" -ignore, 0x5C0E20, 0x5CF9C0, 0x5C0B30, "Unit_begin_bombarding_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y)" -ignore, 0x57F623, 0x58C352, 0x57F383, "ADDR_SUB_BUG_PATCH", "void *" -define, 0xCC2BB0, 0xCE54BC, 0xCC2B70, "p_got_leader_gender", "int *" -ignore, 0x49D070, 0x4A3AF0, 0x49D100, "Advisor_GUI_open", "void (__fastcall *) (Advisor_GUI * this, int edx, AdvisorKind kind)" -ignore, 0x4BF660, 0x4C6C10, 0x4BF6F0, "City_draw_citizens", "void (__fastcall *) (City * this, int edx, PCX_Image * canvas, RECT * rect, char param_3)" -ignore, 0x4B9F60, 0x4C15D0, 0x4B9FF0, "City_add_population", "void (__fastcall *) (City * this, int edx, int num, int race_id)" -ignore, 0x670234, 0x68D2E0, 0x670234, "Tile_m27_Check_Shield_Bonus", "bool (__fastcall *) (Tile * this)" -ignore, 0x5f3448, 0x6032DF, 0x5F3378, "CHECK_SHIELD_BONUS_TO_CAN_SPAWN_RES_RETURN", "int" - +JOB, GOG ADDR, STEAM ADDR, PCG ADDR, NAME, TYPE +define, 0, 1, 2, "exe_version_index", "int" +define, 0x9C3508, 0x9E5D08, 0x9C34C8, "p_bic_data", "BIC *" +define, 0xA52E80, 0xA75680, 0xA52E40, "p_units", "Units *" +define, 0xA52DD4, 0xA755D0, 0xA52D94, "p_tile_units", "TileUnits *" +define, 0xA52E68, 0xA75668, 0xA52E28, "p_cities", "Cities *" +define, 0xA52E50, 0xA75650, 0xA52E10, "p_colonies", "Base_List *" +define, 0xA52E98, 0xA75698, 0xA52E58, "leaders", "Leader *" +define, 0xB3CEA0, 0xB5F6A0, 0xB3CE60, "city_sprites", "Sprite *" +define, 0xB3E7D0, 0xB60FD0, 0xB3E790, "destroyed_city_sprites", "Sprite *" +define, 0x9F8700, 0xA1AF00, 0x9F86C0, "p_main_screen_form", "Main_Screen_Form *" +define, 0xA52658, 0xA74E50, 0xA52618, "p_game", "Game *" +define, 0xCB8B38, 0xCDB440, 0xCB8AF8, "temp_ui_strs", "char[10][4096]" +define, 0x665188, 0x68219C, 0x665188, "ADDR_ADDR_OUTPUTDEBUGSTRINGA", "void *" +define, 0x665280, 0x6822E0, 0x665280, "ADDR_ADDR_GETASYNCKEYSTATE", "void *" +define, 0x665168, 0x682130, 0x665168, "ADDR_ADDR_GETPROCADDRESS", "void *" +define, 0x6650E4, 0x6820B8, 0x6650E4, "ADDR_ADDR_GETMODULEHANDLEA", "void *" +define, 0x66527C, 0x6822E4, 0x66527C, "ADDR_ADDR_MESSAGEBOXA", "void *" +repl vptr, 0x73A8FC, 0x756C74, 0x73A8D4, "init_floating_point", "void (__stdcall *) (void)" +define, 0x5B6B01, 0x5C5458, 0x5B6811, "ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK", "void *" +define, 0x569503, 0x575933, 0x5694B3, "ADDR_UNIT_COUNT_CHECK", "void *" +define, 0x594B35, 0x5A2357, 0x594855, "ADDR_ERA_COUNT_CHECK", "void *" +define, 0x5601EF, 0x56C2E3, 0x56019F, "ADDR_SCIENCE_AGE_BUG_PATCH", "void *" +define, 0x4CD0B1, 0x4D5151, 0x4CD171, "ADDR_PEDIA_TEXTURE_BUG_PATCH", "void *" +define, 0x5640AC, 0x570385, 0x56405C, "ADDR_AUTORAZE_BYPASS", "void *" +repl vptr, 0x66CB50, 0x689C3C, 0x66CB50, "Leader_impl_would_raze_city", "bool (__fastcall *) (Leader * this, int edx, City * city)" +repl vptr, 0x66B44C, 0x68854C, 0x66B44C, "Main_Screen_Form_handle_left_click_on_map_1", "void (__fastcall *) (Main_Screen_Form * this, int edx, int param_1, int param_2)" +inlead, 0x4EA210, 0x4F3000, 0x4EA2D0, "Main_Screen_Form_handle_right_click_on_tile", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" +inlead, 0x4E8850, 0x4F14E0, 0x4E8910, "Main_Screen_Form_open_right_click_menu", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" +define, 0x499FE0, 0x49F9F0, 0x49A070, "is_online_game", "char (__stdcall *) (void)" +define, 0x437A70, 0x439620, 0x437AF0, "tile_at", "Tile * (__cdecl *) (int x, int y)" +define, 0x426C80, 0x4283C0, 0x426D00, "TileUnits_TileUnitID_to_UnitID", "int (__fastcall *) (TileUnits * this, int edx, int tile_unit_id, int * out_UnitItem_field_0)" +inlead, 0x5C1410, 0x5CFFA0, 0x5C1120, "Unit_bombard_tile", "void (__fastcall *) (Unit * this, int edx, int x, int y)" +inlead, 0x5BE820, 0x5CD420, 0x5BE530, "Unit_get_defense_strength", "int (__fastcall *) (Unit * this)" +inlead, 0x5BB650, 0x5CA190, 0x5BB360, "Unit_is_visible_to_civ", "char (__fastcall *) (Unit * this, int edx, int civ_id, int param_2)" +define, 0x5EA6C0, 0x5F9F10, 0x5EA5F0, "Tile_has_city", "char (__fastcall *) (Tile * this)" +define, 0x5EA6E0, 0x5F9F30, 0x5EA610, "Tile_has_colony", "bool (__fastcall *) (Tile * this)" +define, 0x5BE5B0, 0x5CD180, 0x5BE2C0, "Unit_get_max_hp", "int (__fastcall *) (Unit * this)" +define, 0x5E4EF0, 0x5F4750, 0x5E4E20, "UnitType_has_ability", "bool (__fastcall *) (UnitType * this, int edx, enum UnitTypeAbilities a)" +define, 0x5CDDF0, 0x5DCEB0, 0x5CDD10, "get_max_move_points", "int (__cdecl *) (UnitType * unit_type, int civ_id)" +inlead, 0x5BE470, 0x5CD030, 0x5BE180, "Unit_get_max_move_points", "int (__fastcall *) (Unit * this)" +define, 0x60B370, 0x625850, 0x60B290, "Button_set_tooltip", "int (__fastcall *) (Button * this, int edx, char * str)" +define, 0x5FC420, 0x60FC10, 0x5FC300, "PCX_Image_construct", "PCX_Image * (__fastcall *) (PCX_Image * this)" +define, 0x5FC820, 0x610360, 0x5FC700, "PCX_Image_read_file", "int (__fastcall *) (PCX_Image * this, int edx, char * file_path, PCX_Color_Table * out_color_table, int ct_start, int ct_count, unsigned flags)" +define, 0x5F7E50, 0x608170, 0x5F7D80, "Sprite_construct", "Sprite * (__fastcall *) (Sprite * this)" +define, 0x5F7F90, 0x6083D0, 0x5F7EC0, "Sprite_slice_pcx", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * img, int up_left_x, int up_left_y, int w, int h, int arg6, int arg7)" +define, 0x49FC50, 0x4A6790, 0x49FCE0, "get_popup_form", "PopupForm * (__stdcall *) ()" +define, 0x61C5A0, 0x63E390, 0x61C4D0, "set_popup_str_param", "int (__cdecl *) (int param_index, char * str, int param_3, int param_4)" +define, 0x61C570, 0x63E350, 0x61C4A0, "set_popup_int_param", "int (__cdecl *) (int param_index, int value)" +inlead, 0x611530, 0x62DAF0, 0x611460, "show_popup", "int (__fastcall *) (void * this, int edx, int param_1, int param_2)" +define, 0x4ACD20, 0x4B3CC0, 0x4ACDB0, "City_zoom_to", "void (__fastcall *) (City *this, int edx, int param_1)" +inlead, 0x4ACB50, 0x4B3AF0, 0x4ACBE0, "City_has_improvement", "char (__fastcall *) (City * this, int edx, int i_improvement, char include_auto_improvements)" +inlead, 0x4E6DB0, 0x4EF820, 0x4E6E70, "Main_Screen_Form_perform_action_on_tile", "void (__fastcall *) (Main_Screen_Form * this, int edx, enum Unit_Mode_Actions action, int x, int y)" +inlead, 0x550BB0, 0x55BCE0, 0x550B60, "Main_GUI_set_up_unit_command_buttons", "void (__fastcall *) (Main_GUI * this)" +inlead, 0x5577F0, 0x563600, 0x5577A0, "Main_GUI_handle_button_press", "void (__fastcall *) (Main_GUI * this, int edx, int button_id)" +inlead, 0x4E05F0, 0x4E8F90, 0x4E06B0, "Main_Screen_Form_handle_key_down", "int (__fastcall *) (Main_Screen_Form * this, int edx, int char_code, int virtual_key_code)" +inlead, 0x6268A0, 0x64B410, 0x624C00, "handle_cursor_change_in_jgl", "int (__stdcall *) ()" +inlead, 0x555F80, 0x561B90, 0x555F30, "Main_GUI_handle_click_in_status_panel", "void (__fastcall *) (Main_GUI * this, int edx, int mouse_x, int mouse_y)" +define, 0x54CAD0, 0x557980, 0x54CB30, "get_font", "Object_66C3FC * (__cdecl *) (int size, FontStyleFlags style)" +define, 0x5FD750, 0x611850, 0x5FD630, "PCX_Image_draw_centered_text", "int (__fastcall *) (PCX_Image *this, int edx, Object_66C3FC * font, char * str, int x, int y, int width, int str_len)" +inlead, 0x4196F0, 0x41A5D0, 0x419770, "City_Form_draw", "void (__fastcall *) (City_Form * this)" +inlead, 0x41B4C0, 0x41C610, 0x41B540, "City_Form_print_production_info", "void (__fastcall *) (City_Form *this, int edx, String256 * out_strs, int str_capacity)" +define, 0x4ACD70, 0x4B3D30, 0x4ACE00, "City_get_order_cost", "int (__fastcall *) (City * this)" +define, 0x4ACD40, 0x4B3CE0, 0x4ACDD0, "City_get_order_progress", "int (__fastcall *) (City * this)" +inlead, 0x57F360, 0x58C080, 0x57F0C0, "Trade_Net_get_movement_cost", "int (__fastcall *) (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned flags, int neighbor_index, Trade_Net_Distance_Info * dist_info)" +define, 0x57F0A0, 0x58BDB0, 0x57EE00, "Trade_Net_have_trade_connection", "bool (__fastcall *) (Trade_Net * this, int edx, City * a, City * b, int civ_id)" +define, 0x57F130, 0x58BE40, 0x57EE90, "Trade_Net_is_tile_connected_to_city", "bool (__fastcall *) (Trade_Net * this, int edx, City * city, int tile_x, int tile_y)" +inlead, 0x591BB0, 0x59F1D0, 0x5918D0, "do_save_game", "int (__cdecl *) (char const * file_path, char param_2, GUID * guid)" +define, 0x4BCFF0, 0x4C4660, 0x4BD080, "City_recompute_happiness", "void (__fastcall *) (City * this)" +define, 0x4B05D0, 0x4B7590, 0x4B0660, "City_recompute_production", "void (__fastcall *) (City * this)" +define, 0x4B07C0, 0x4B7770, 0x4B0850, "City_recompute_commerce", "void (__fastcall *) (City * this)" +inlead, 0x4B0B70, 0x4B7B20, 0x4B0C00, "City_recompute_culture_income", "void (__fastcall *) (City * this)" +inlead, 0x4B2680, 0x4B9600, 0x4B2710, "City_update_culture", "void (__fastcall *) (City * this)" +define, 0x4B0C60, 0x4B7C10, 0x4B0CF0, "City_recompute_cultural_level", "void (__fastcall *) (City *this, int edx, char param_1, char param_2, char param_3)" +define, 0x4B10F0, 0x4B80A0, 0x4B1180, "recompute_food_eaten_production_commerce_and_happiness", "void (__fastcall *) (City *this)" +inlead, 0x55A560, 0x566470, 0x55A510, "Leader_recompute_auto_improvements", "void (__fastcall *) (Leader * this)" +inlead, 0x539030, 0x543650, 0x5390B0, "Game_get_wonder_city_id", "int (__fastcall *) (Game * this, int edx, int wonder_improvement_id)" +define, 0x55A62E, 0x566538, 0x55A5DE, "ADDR_SMALL_WONDER_FREE_IMPROVS_RETURN", "int" +define, 0x55A5C6, 0x5664D4, 0x55A576, "ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER", "void *" +repl vptr, 0x66B46C, 0x68856C, 0x66B46C, "Main_Screen_Form_handle_key_up", "int (__fastcall *) (Main_Screen_Form * this, int edx, int virtual_key_code)" +define, 0x4DAA70, 0x4E3430, 0x4DAB30, "Main_Screen_Form_issue_command", "char (__fastcall *) (Main_Screen_Form * this, int edx, int command, Unit * unit)" +define, 0x609D60, 0x6233C0, 0x609C80, "clear_something_1", "void (__stdcall *) ()" +define, 0x6207B0, 0x644F10, 0x6206E0, "Timer_clear", "void (__fastcall *) (Timer * this)" +inlead, 0x55EFA0, 0x56B030, 0x55EF50, "Leader_can_do_worker_job", "char (__fastcall *) (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing)" +define, 0x56A7C0, 0x576C60, 0x56A770, "Leader_can_build_unit", "bool (__fastcall *) (Leader * this, int edx, int unit_type_id, int param_2, bool allow_kings)" +define, 0x455288, 0x457458, 0x455308, "ADDR_CHECK_ARTILLERY_IN_CITY", "void *" +inlead, 0x455140, 0x457310, 0x4551C0, "Unit_ai_move_artillery", "void (__fastcall *) (Unit * this)" +define, 0x5E6E50, 0x5F66A0, 0x5E6D80, "neighbor_index_to_diff", "void (__cdecl *) (int neighbor_index, int * out_x, int * out_y)" +define, 0x5B3040, 0x5C1970, 0x5B2D50, "Unit_set_state", "void (__fastcall *) (Unit * this, int edx, int new_state)" +define, 0x5B2F10, 0x5C1840, 0x5B2C20, "Unit_set_escortee", "void (__fastcall *) (Unit * this, int edx, int escortee)" +inlead, 0x44D980, 0x44F9E0, 0x44DA00, "Unit_seek_colony", "int (__fastcall *) (Unit *this, int edx, bool for_own_defense, int max_distance)" +repl call, 0x4527BE, 0x4548E3, 0x45283E, "Tile_has_district_or_colony", "" +define, 0xA526B4, 0xA74EAC, 0xA52674, "p_rand_object", "void *" +define, 0x60BAB0, 0x626440, 0x60B9E0, "rand_int", "int (__fastcall *) (void * this, int edx, int lim)" +inlead, 0x42C8A0, 0x42E430, 0x42C920, "City_ai_choose_production", "void (__fastcall *) (City * this, int edx, City_Order * out)" +inlead, 0x4C04E0, 0x4C7AB0, 0x4C0570, "City_can_build_unit", "bool (__fastcall *) (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings)" +repl call, 0x5C536C, 0x5D404D, 0x5C507C, "Unit_get_max_move_points_for_disembarking", "" +inlead, 0x5C5420, 0x5D4120, 0x5C5130, "Unit_disembark_passengers", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +define, 0xCAA330, 0xCCCB98, 0xCAA2F0, "p_null_tile", "Tile *" +define, 0x45A35F, 0x45C56F, 0x45A3DF, "ADDR_HOUSEBOAT_BUG_PATCH", "byte *" +define, 0x45A386, 0x45C596, 0x45A406, "ADDR_HOUSEBOAT_BUG_PATCH_END", "byte *" +define, 0xB72888, 0xB950A8, 0xB72848, "p_original_trade_net", "Trade_Net *" +inlead, 0x580540, 0x58D270, 0x5802A0, "Trade_Net_set_unit_path", "int (__fastcall *) (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp)" +define, 0x5B3290, 0x5C1BE0, 0x5B2FA0, "Unit_pop_next_move_from_path", "byte (__fastcall *) (Unit * this)" +inlead, 0x45FED0, 0x4622A0, 0x45FF50, "Unit_ai_move_leader", "void (__fastcall *) (Unit * this)" +define, 0x5B2B20, 0x5C1440, 0x5B2830, "Unit_next_escorter_id", "int (__fastcall *) (Unit * this, int edx, int * index, bool begin_iterating)" +define, 0x5BC300, 0x5CAE50, 0x5BC010, "Unit_disband", "void (__fastcall *) (Unit * this)" +inlead, 0x5C00A0, 0x5CEC20, 0x5BFDB0, "Unit_can_hurry_production", "bool (__fastcall *) (Unit * this, int edx, City * city, bool exclude_cheap_improvements)" +inlead, 0x5B3AB0, 0x5C2400, 0x5B37C0, "Unit_can_pillage", "bool (__fastcall *) (Unit *this, int edx, int tile_x, int tile_y)" +inlead, 0x5CCBB0, 0x5DBB50, 0x5CC8C0, "Unit_can_pass_between", "bool (__fastcall *) (Unit *this, int edx, int from_x, int from_y, int to_x, int to_y, byte param_5)" +define, 0x5C0420, 0x5CEFC0, 0x5C0130, "Unit_hurry_production", "void (__fastcall *) (Unit * this)" +define, 0x5C0300, 0x5CEE90, 0x5C0010, "Unit_ai_can_start_science_age", "bool (__fastcall *) (Unit * this)" +define, 0x5C03B0, 0x5CEF50, 0x5C00C0, "Unit_start_science_age", "void (__fastcall *) (Unit * this)" +inlead, 0x5BC980, 0x5CB510, 0x5BC690, "Unit_ai_can_form_army", "bool (__fastcall *) (Unit * this)" +define, 0x5BCA20, 0x5CB5B0, 0x5BC730, "Unit_form_army", "Unit * (__fastcall *) (Unit * this)" +repl vptr, 0x66DD28, 0x68AE08, 0x66DD28, "impl_ai_is_good_army_addition", "bool (__fastcall *) (Unit * this, int edx, Unit * candidate)" +repl vptr, 0x666578, 0x6835CC, 0x666578, "PopupForm_set_text_key_and_flags", "void (__fastcall *) (PopupForm * this, int edx, char * script_path, char * text_key, int param_3, int param_4, int param_5, int param_6)" +define, 0xA35200, 0xA57A00, 0xA351C0, "p_diplo_form", "DiploForm *" +define, 0x649A8B, 0x6683E1, 0x6499CF, "new", "void * (__cdecl *) (unsigned num_bytes)" +define, 0x666AC4, 0x683B1C, 0x666AC4, "p_trade_offer_vtable", "TradeOfferVTable *" +define, 0x440EE0, 0x442CD0, 0x440F60, "Leader_consider_trade", "DiploMessage (__fastcall *) (Leader * this, int edx, TradeOfferList * receiving, TradeOfferList * paying, int other_party_civ_id, byte param_4, bool param_5, byte param_6, byte param_7, int * out_advantage, int * param_9, int * param_10)" +define, 0x509325, 0x51334D, 0x5093C5, "ADDR_SETUP_INITIAL_GOLD_ASK_RETURN", "int" +define, 0x50BCC8, 0x515DA1, 0x50BD68, "ADDR_SETUP_MODIFY_GOLD_ASK_RETURN", "int" +define, 0x509669, 0x51366E, 0x509709, "ADDR_SETUP_INITIAL_GOLD_OFFER_RETURN", "int" +define, 0x50BF10, 0x516008, 0x50BFB0, "ADDR_SETUP_MODIFY_GOLD_OFFER_RETURN", "int" +define, 14, 14, 14, "TRADE_GOLD_SETTER_IS_LUMP_SUM_OFFSET", "int" +define, 0x50BEBD, 0x515FB4, 0x50BF5D, "ADDR_PRINT_GOLD_AMOUNT_1", "byte *" +define, 0x50BC75, 0x515D4D, 0x50BD15, "ADDR_PRINT_GOLD_AMOUNT_2", "byte *" +inlead, 0x5F3160, 0x603000, 0x5F3090, "Map_check_city_location", "CityLocValidity (__fastcall *) (Map *this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile)" +repl vptr, 0x66C1E8, 0x6892D8, 0x66C1E8, "DiploForm_m68_Show_Dialog", "int (__fastcall *) (DiploForm * this, int edx, int param_1, void * param_2, void * param_3)" +repl vptr, 0x66C220, 0x689310, 0x66C220, "DiploForm_m82_handle_key_event", "void (__fastcall *) (DiploForm * this, int edx, int virtual_key_code, int is_down)" +define, 0xA526C0, 0xA74EB8, 0xA52680, "p_player_bits", "unsigned *" +define, 0x50D830, 0x517970, 0x50D8D0, "DiploForm_close", "void (__fastcall *) (DiploForm *)" +inlead, 0x505F40, 0x50FD30, 0x505FE0, "DiploForm_do_diplomacy", "void (__fastcall *) (DiploForm * this, int edx, int diplo_message, int param_2, int civ_id, int do_not_request_audience, int war_negotiation, int disallow_proposal, TradeOfferList * our_offers, TradeOfferList * their_offers)" +define, 0x440E10, 0x442C00, 0x440E90, "Leader_ai_would_meet_with", "bool (__fastcall *) (Leader * this, int edx, int civ_id)" +repl vptr, 0x66C130, 0x689220, 0x66C130, "DiploForm_m22_Draw", "void (__fastcall *) (DiploForm * this)" +define, 0x609F50, 0x623C40, 0x609E70, "Button_construct", "Button * (__fastcall *) (Button * this)" +define, 0x60B050, 0x625450, 0x60AF70, "Button_initialize", "int (__fastcall *) (Button * this, int edx, char * text, int control_id, int x, int y, int width, int height, Base_Form * parent, int param_8)" +define, 0x5161C0, 0x51F9B0, 0x516260, "DiploForm_set_their_message", "int (__fastcall *) (DiploForm * this, int edx, DiploMessage msg, int message_arg, int param_3)" +define, 0x516260, 0x51FA50, 0x516300, "DiploForm_reset_our_message_choices", "void (__fastcall *) (DiploForm *)" +define, 0x649FA7, 0x6076E0, 0x649EEB, "civ_prog_malloc", "void * (__cdecl *) (unsigned _Size)" +define, 0x649EBE, 0x668816, 0x649E02, "civ_prog_free", "void (__cdecl *) (void * p)" +inlead, 0x61A480, 0x63B9F0, 0x61A3B0, "Context_Menu_open", "int (__fastcall *) (Context_Menu * this, int edx, int x, int y, int param_3)" +define, 0x4E993C, 0x4F273A, 0x4E99FC, "ADDR_OPEN_UNIT_MENU_RETURN", "int" +define, 0x61B0C0, 0x63C940, 0x61AFF0, "Context_Menu_widen_for_text", "void (__fastcall *) (Context_Menu * this, int edx, char * text)" +inlead, 0x61A110, 0x63B420, 0x61A040, "Context_Menu_add_item_and_set_color", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, char * text, int red)" +define, 0x61A160, 0x63B480, 0x61A090, "Context_Menu_add_separator", "int (__fastcall *) (Context_Menu * this, int edx, int item_id)" +inlead, 0x45C750, 0x45EA70, 0x45C7D0, "Unit_ai_move_terraformer", "void (__fastcall *) (Unit * this)" +inlead, 0x4B1DC0, 0x4B8D50, 0x4B1E50, "City_requires_improvement_to_grow", "int (__fastcall *) (City * this)" +inlead, 0x4DD530, 0x4E5F00, 0x4DD5F0, "maybe_show_improvement_needed_for_growth_dialog", "void (__fastcall *) (void * this, int edx, City * city, int * param_2)" +repl call, 0x5213E3, 0x52B3F3, 0x521483, "City_requires_improvement_to_grow_besides_neighborhood", "" +inlead, 0x5C1AD0, 0x5D0670, 0x5C17E0, "Unit_can_perform_command", "bool (__fastcall *) (Unit * this, int edx, int unit_command_value)" +inlead, 0x5B39D0, 0x5C2320, 0x5B36E0, "Unit_join_city", "void (__fastcall *) (Unit * this, int edx, City * city)" +define, 0x5C0740, 0x5CF2E0, 0x5C0450, "Unit_upgrade", "Unit * (__fastcall *) (Unit * this, int edx, bool ignore_cost)" +define, 0x5C04D0, 0x5CF070, 0x5C01E0, "Unit_get_upgrade_cost", "int (__fastcall *) (Unit * this)" +define, 0xCADC18, 0xCD0510, 0xCADBD8, "script_dot_txt_file_path", "char *" +inlead, 0x5B5CD0, 0x5C4620, 0x5B59E0, "Unit_can_move_to_adjacent_tile", "AdjacentMoveValidity (__fastcall *) (Unit * this, int edx, int neighbor_index, int param_2)" +define, 0x5F3F50, 0x603DD0, 0x5F3E80, "Map_compute_neighbor_index", "int (__fastcall *) (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim)" +repl call, 0x5CCC85, 0x5DBC1F, 0x5CC995, "Map_compute_neighbor_index_for_pass_between", "" +repl call, 0x42FC69, 0x43173F, 0x42FCE9, "Improvement_has_wonder_com_bonus_for_ai_prod", "" +define, 0x5FEF70, 0x613F70, 0x5FEE50, "PCX_Image_draw_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int str_len)" +repl call, 0x5AAB93, 0x5B9899, 0x5AA8A3, "PCX_Image_draw_no_tile_info", "" +repl call, 0x5AB00A, 0x5B97E8, 0x5AAD1A, "PCX_Image_draw_tile_info_terrain", "" +define, 0x4E3C60, 0x4EC4B0, 0x4E3D20, "Main_Screen_Form_get_tile_coords_under_mouse", "int (__fastcall *) (Main_Screen_Form * this, int edx, int mouse_x, int mouse_y, int * out_tile_x, int * out_tile_y)" +inlead, 0x5AA820, 0x5B8F40, 0x5AA530, "open_tile_info", "void (__fastcall *) (void * this, int edx, int mouse_x, int mouse_y, int civ_id)" +inlead, 0x53A860, 0x544B80, 0x53A8E0, "get_anarchy_length", "int (__stdcall *) (int leader_id)" +repl call, 0x5557DE, 0x56136E, 0x55578E, "PCX_Image_process_tech_ga_status", "" +define, 0x5FE560, 0x612F50, 0x5FE440, "PCX_Image_process_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str)" +define, 0xA526AC, 0xA74EA4, 0xA5266C, "p_current_turn_no", "int *" +define, 0xCADC0C, 0xCD0504, 0xCADBCC, "p_labels", "char ***" +define, 497, 498, 497, "LBL_GOLDEN_AGE", "int" +define, 0xA5267C, 0xA74E74, 0xA5263C, "p_toggleable_rules", "int *" +define, 0xA52680, 0xA74E78, 0xA52640, "p_debug_mode_bits", "unsigned *" +repl call, 0x569A10, 0x575E4A, 0x5699C0, "Unit_check_king_ability_while_spawning", "" +define, 0x5BC8B0, 0x5CB430, 0x5BC5C0, "Unit_has_ability", "bool (__fastcall *) (Unit * this, int edx, enum UnitTypeAbilities a)" +define, 0xA52658, 0xA74E50, 0xA52618, "p_match", "void *" +inlead, 0x442480, 0x444250, 0x442500, "Match_ai_eval_city_location", "int (__fastcall *) (void * this, int edx, int x, int y, int civ_id, bool param_4, int * out_breakdown)" +define, 0x430FBA, 0x432A6D, 0x43103A, "ADDR_INTERCEPT_AI_IMPROV_VALUE", "void *" +define, 7, 6, 7, "AI_CONSIDERATION_INTERCEPT_LEN", "int" +define, 0x433C7C, 0x435712, 0x433CFC, "ADDR_INTERCEPT_AI_UNIT_VALUE", "void *" +inlead, 0x4B1190, 0x4B8140, 0x4B1220, "City_compute_corrupted_yield", "int (__fastcall *) (City * this, int edx, int gross_yield, bool is_production)" +define, 0x610B30, 0x62CE00, 0x610A60, "PopupForm_add_text", "byte (__fastcall *) (PopupForm * this, int edx, char * text, bool param_2)" +define, 0x6193A0, 0x639AD0, 0x6192D0, "PopupSelection_add_item", "int (__fastcall *) (PopupSelection * this, int edx, char * text, int value)" +inlead, 0x59AB50, 0x5A8660, 0x59A870, "load_scenario", "unsigned (__fastcall *) (BIC * this, int edx, char * param_1, unsigned * param_2)" +define, 0x59B499, 0x5A8FD9, 0x59B1B9, "ADDR_LOAD_SCENARIO_PREVIEW_RETURN", "int" +define, 0x59AD27, 0x5A8872, 0x59AA47, "ADDR_LOAD_SCENARIO_RESUME_SAVE_2_RETURN", "int" +repl vptr, 0x6659F8, 0x682A5C, 0x6659F8, "City_Form_m82_handle_key_event", "void (__fastcall *) (City_Form * this, int edx, int virtual_key_code, int is_down)" +define, 0x437540, 0x4390F0, 0x4375C0, "Improvement_has_wonder_flag", "bool (__fastcall *) (Improvement * this, int edx, enum ImprovementTypeWonderFeatures flag)" +define, 0x437710, 0x4392F0, 0x437790, "UnitType_has_ai_strategy", "bool (__fastcall *) (UnitType * this, int edx, byte n)" +repl call, 0x431038, 0x432AE7, 0x4310B8, "UnitType_has_strat_0_for_ai_prod", "" +define, 0x44CE50, 0x44EE40, 0x44CED0, "Unit_find_transport", "Unit * (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C5F70, 0x5D4D50, 0x5C5C80, "Unit_select_transport", "Unit * (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, bool should_show_popup)" +inlead, 0x5C5110, 0x5D3DF0, 0x5C4E20, "Unit_load", "void (__fastcall *) (Unit * this, int edx, Unit * transport)" +define, 0xA526BC, 0xA74EB4, 0xA5267C, "p_human_player_bits", "int *" +inlead, 0x5F8130, 0x6085D0, 0x5F8060, "Sprite_draw_on_map", "int (__fastcall *) (Sprite * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7)" +repl vptr, 0x66A554, 0x687660, 0x66A554, "Map_Renderer_m19_Draw_Tile_by_XY_and_Flags", "void (__fastcall *) (Map_Renderer * this, int edx, int param_1, int pixel_x, int pixel_y, Map_Renderer * map_renderer, int param_5, int tile_x, int tile_y, int param_8)" +repl vptr, 0x66A624, 0x687730, 0x66A624, "Map_Renderer_m71_Draw_Tiles", "void (__fastcall *) (Map_Renderer * this, int edx, int param_1, int param_2, int param_3)" +repl vptr, 0x66B520, 0x688620, 0x66B520, "Main_Screen_Form_m82_handle_key_event", "void (__fastcall *) (Main_Screen_Form * this, int edx, int virtual_key_code, int is_down)" +repl call, 0x5C190B, 0x5D0493, 0x5C161B, "Unit_get_move_points_after_airdrop", "" +repl call, 0x4D93E0, 0x4E1D70, 0x4D94A0, "Unit_get_move_points_after_set_to_intercept", "" +repl vptr, 0x66E738, 0x68B810, 0x66E738, "Parameters_Form_m68_Show_Dialog", "int (__fastcall *) (Parameters_Form * this, int edx, int arg_1, void * arg_2, void * arg_3)" +define, 0x598580, 0x5A5E30, 0x5982A0, "BIC_get_asset_path", "char * (__fastcall *) (BIC * this, int edx, char * str, bool show_error_popup)" +define, 0x5F8080, 0x608500, 0x5F7FB0, "Sprite_slice_pcx_with_color_table", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * img, int up_left_x, int up_left_y, int w, int h, int arg6, int arg7)" +define, 0x5FD320, 0x611210, 0x5FD200, "PCX_Image_set_font", "int (__fastcall *) (PCX_Image * this, int edx, Object_66C3FC * font, int arg_2, int arg_3, int arg_4)" +define, 0x57EEC4, 0x58BBE8, 0x57EC24, "ADDR_INTERCEPT_SET_RESOURCE_BIT", "void *" +inlead, 0x4ADE30, 0x4B4E10, 0x4ADEC0, "City_has_resource", "bool (__fastcall *) (City * this, int edx, int resource_id)" +define, 0x4ADDC0, 0x4B4DA0, 0x4ADE50, "City_has_trade_connection_to_capital", "bool (__fastcall *) (City * this)" +define, 0x55EEB0, 0x56AF50, 0x55EE60, "Leader_has_resources_for_job_at", "bool (__fastcall *) (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y)" +inlead, 0x57E450, 0x58B1A0, 0x57E1B0, "Trade_Net_recompute_resources", "void (__fastcall *) (Trade_Net * this, int edx, bool skip_popups)" +define, 0x561440, 0x56D5A0, 0x5613F0, "Leader_has_tech", "bool (__fastcall *) (Leader * this, int edx, int id)" +inlead, 0x4BED80, 0x4C6350, 0x4BEE10, "City_cycle_specialist_type", "bool (__fastcall *) (City * this, int edx, int mouse_x, int mouse_y, Citizen * citizen, City_Form * city_form)" +inlead, 0x4B1C10, 0x4B8BC0, 0x4B1CA0, "City_get_total_pollution", "int (__fastcall *) (City * this)" +define, 0x4B1B40, 0x4B8B00, 0x4B1BD0, "City_get_pollution_from_buildings", "int (__fastcall *) (City * this)" +inlead, 0x4B1A50, 0x4B8A10, 0x4B1AE0, "City_get_pollution_from_pop", "int (__fastcall *) (City * this)" +inlead, 0x4ACF40, 0x4B3F20, 0x4ACFD0, "City_add_or_remove_improvement", "void (__fastcall *) (City * this, int edx, int improv_id, int add, bool param_3)" +define, 0x57E943, 0x58B68E, 0x57E6A3, "ADDR_RESOURCE_TILE_COUNT_MASK", "void *" +define, 0x57E5EB, 0x58B328, 0x57E34B, "ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE", "void *" +define, 0x5DA1A0, 0x5E9710, 0x5DA0D0, "Tile_get_resource_visible_to", "int (__fastcall *) (Tile * this, int edx, int civ_id)" +inlead, 0x5EA7F0, 0x5FA040, 0x5EA720, "Tile_m17_Check_Irrigation", "bool (__fastcall *) (Tile * this, int edx, int visible_to_civ_id)" +define, 0x5D16A0, 0x5E0900, 0x5D15D0, "Map_get_tile", "Tile * (__fastcall *) (Map * this, int edx, int index)" +repl call, 0x57E602, 0x58B345, 0x57E362, "Map_get_tile_when_recomputing_resources_1", "" +repl call, 0x57E629, 0x58B36C, 0x57E389, "Map_get_tile_when_recomputing_resources_2", "" +repl call, 0x57E618, 0x58B35B, 0x57E378, "Map_get_tile_when_recomputing_resources_3", "" +repl call, 0x57E64A, 0x58B397, 0x57E3AA, "Map_get_tile_when_recomputing_resources_4", "" +repl call, 0x57E672, 0x58B3B7, 0x57E3D2, "Map_get_tile_when_recomputing_resources_5", "" +repl call, 0x57E679, 0x58B3BE, 0x57E3D9, "Tile_get_visible_resource_when_recomputing", "" +inlead, 0x4A47C0, 0x4AB470, 0x4A4850, "Fighter_begin", "void (__fastcall *) (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender)" +define, 0x441ED0, 0x443CC0, 0x441F50, "Map_get_x_dist", "int (__fastcall *) (Map * this, int edx, int x1, int x2)" +define, 0x437970, 0x439520, 0x4379F0, "Map_get_y_dist", "int (__fastcall *) (Map * this, int edx, int y1, int y2)" +inlead, 0x5D7180, 0x5E65E0, 0x5D70B0, "Map_calc_food_yield_at", "int (__fastcall *) (Map * this, int edx, int tile_x, int tile_y, int tile_base_type, int civ_id, int imagine_fully_improved, City * city)" +inlead, 0x5D75F0, 0x5E6A20, 0x5D7520, "Map_calc_shield_yield_at", "int (__fastcall *) (Map *this, int edx, int tile_x, int tile_y, int civ_id, City *city, int param_5, int param_6)" +define, 0x5663C0, 0x572730, 0x566370, "Leader_create_city", "City * (__fastcall *) (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6)" +inlead, 0x5D3030, 0x5E2330, 0x5D2F60, "Map_process_after_placing", "void (__fastcall *) (Map * this, int edx, bool param_1)" +inlead, 0x5BBBC0, 0x5CA720, 0x5BB8D0, "Unit_despawn", "void (__fastcall *) (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7)" +inlead, 0x5BD220, 0x5CBDE0, 0x5BCF30, "Unit_move", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +define, 0x558700, 0x564590, 0x5586B0, "Main_GUI_label_loading_bar", "void (__fastcall *) (Main_GUI * this, int edx, int param_1, char *text)" +define, 0x48DE43, 0x4920E3, 0x48DED3, "ADDR_TURN_METALIMIT_1", "byte *" +define, 0x4946E1, 0x4990CA, 0x494771, "ADDR_TURN_METALIMIT_2", "byte *" +define, 0x54E2E0, 0x55925B, 0x54E340, "ADDR_TURN_METALIMIT_3", "byte *" +define, 0x54E2E7, 0x559262, 0x54E347, "ADDR_TURN_METALIMIT_4", "byte *" +define, 0x584163, 0x59100F, 0x583EC3, "ADDR_TURN_METALIMIT_5", "byte *" +define, 0x5817B2, 0x58E4E2, 0x581512, "ADDR_TURN_METALIMIT_6", "byte *" +define, 0x492100, 0x496751, 0x492190, "ADDR_TURN_METALIMIT_7", "byte *" +inlead, 0x4ACA50, 0x4B39F0, 0x4ACAE0, "City_get_net_commerce", "int (__fastcall *) (City * this, int edx, int kind, bool include_science_age)" +inlead, 0x55DFD0, 0x56A070, 0x55DF80, "Leader_pay_unit_maintenance", "void (__fastcall *) (Leader * this)" +define, 0x55CFB0, 0x569040, 0x55CF60, "Leader_sum_improvements_maintenance", "int (__fastcall *) (Leader * this, int edx, int govt_id)" +define, 0x560972, 0x56CA7F, 0x560922, "ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT", "byte *" +define, 0x55DD50, 0x569DF0, 0x55DD00, "Leader_compute_income", "int (__fastcall *) (Leader * this)" +define, 0x5612F0, 0x56D420, 0x5612A0, "Leader_recompute_economy", "void (__fastcall *) (Leader * this)" +repl call, 0x560C16, 0x56CD25, 0x560BC6, "Leader_sum_improv_maintenance_to_pay_1", "" +repl call, 0x560C64, 0x56CDA8, 0x560C14, "Leader_sum_improv_maintenance_to_pay_2", "" +inlead, 0x4ACDF0, 0x4B3DD0, 0x4ACE80, "City_get_improvement_maintenance", "int (__fastcall *) (City * this, int edx, int improv_id)" +define, 0x4C2350, 0x4C9B30, 0x4C2370, "Leader_set_treasury", "void (__fastcall *) (Leader * this, int edx, int amount)" +define, 0x4B3400, 0x4BA3A0, 0x4B3490, "City_sell_improvement", "void (__fastcall *) (City * this, int edx, int improv_id, bool set_status_bit)" +define, 0x9E85F0, 0xA0ADF0, 0x9E85B0, "p_civilopedia_form", "Civilopedia_Form *" +define, 0x4CBE10, 0x4D3E50, 0x4CBED0, "Civilopedia_open", "void (__fastcall *) (void * this, int edx, char * key, bool param_2)" +define, 0x53A960, 0x544C80, 0x53A9E0, "get_unit_support_info", "void (__stdcall *) (int civ_id, int govt_id, int * out_cost_per_unit, int * out_count_free_units)" +define, 0x55D2A0, 0x569330, 0x55D250, "Leader_get_free_unit_count", "int (__fastcall *) (Leader * this, int edx, int govt_id)" +inlead, 0x55D030, 0x5690C0, 0x55CFE0, "Leader_count_maintenance_free_units", "int (__fastcall *) (Leader * this)" +define, 0x56D7D0, 0x57A1B0, 0x56D740, "get_tile_occupier_id", "int (__cdecl *) (int x, int y, int pov_civ_id, bool respect_unit_invisibility)" +repl call, 0x4585F4, 0x45A7A2, 0x458674, "get_tile_occupier_id_in_Unit_ai_move_naval_power_unit", "" +inlead, 0x4ED220, 0x4F6140, 0x4ED2E0, "Main_Screen_Form_show_map_message", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause)" +repl call, 0x4BE664, 0x4C5C66, 0x4BE6F4, "Main_Screen_Form_show_wltk_message", "" +repl call, 0x4BE71B, 0x4C5D1D, 0x4BE7AB, "Main_Screen_Form_show_wltk_ended_message", "" +define, 0xA52678, 0xA74E70, 0xA52638, "p_preferences", "unsigned *" +inlead, 0x4AFAB0, 0x4B6A70, 0x4AFB40, "City_set_production", "void (__fastcall *) (City * this, int edx, int order_type, int order_id, bool ask_to_confirm)" +define, 0x4B0AC0, 0x4B7A70, 0x4B0B50, "City_get_income_from_wealth_build", "int (__fastcall *) (City * this)" +define, 0x64C91E, 0x66AFD7, 0x64C85E, "print_int", "char * (__cdecl *) (int val, char * str, unsigned base)" +repl call, 0x5D759A, 0x5E69D2, 0x5D74CA, "Tile_has_city_for_agri_penalty_exception", "" +repl call, 0x564528, 0x570873, 0x5644D8, "show_popup_option_1_razes", "" +repl call, 0x4DA1E6, 0x4E2B96, 0x4DA2A6, "show_popup_option_2_razes", "" +define, 0x619E70, 0x63B090, 0x619DA0, "Context_Menu_add_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, char * text, bool checkbox, Sprite * image)" +repl call, 0x4E9808, 0x4F25EF, 0x4E98C8, "Context_Menu_add_abandon_city", "" +define, 0x60F6A0, 0x62B460, 0x60F5D0, "TextBuffer_check_ptr", "char * (__fastcall *) (TextBuffer * this, int edx, char * str)" +repl call, 0x4D5525, 0x4DDCF6, 0x4D55E5, "TextBuffer_check_pedia_upgrades_to_ptr_1", "" +repl call, 0x4D5676, 0x4DDE50, 0x4D5736, "TextBuffer_check_pedia_upgrades_to_ptr_2", "" +define, 0x5C68A0, 0x5D5700, 0x5C65B0, "Unit_try_flying_over_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y)" +inlead, 0x5C74A0, 0x5D6330, 0x5C71B0, "Unit_perform_air_recon", "void (__fastcall *) (Unit * this, int edx, int x, int y)" +repl call, 0x5C6E34, 0x5D5CBB, 0x5C6B44, "Unit_get_interceptor_max_moves", "" +repl call, 0x5C7108, 0x5D5FAA, 0x5C6E18, "Unit_get_moves_after_interception", "" +repl call, 0x5C7114, 0x5D5FB6, 0x5C6E24, "Unit_set_state_after_interception", "" +inlead, 0x561220, 0x56D350, 0x5611D0, "Leader_begin_unit_turns", "void (__fastcall *) (Leader * this)" +define, 0x4A1FA0, 0x4A8BB0, 0x4A2030, "Fighter_find_defender_against_bombardment", "Unit * (__fastcall *) (Fighter * this, int edx, Unit * bombarder, int tile_x, int tile_y, int bombarder_civ_id, bool land_lethal, bool sea_lethal)" +repl call, 0x4A3ED9, 0x4AAB85, 0x4A3F69, "Fighter_find_actual_bombard_defender", "" +repl call, 0x4A2BAA, 0x4A97F6, 0x4A2C3A, "Fighter_find_actual_bombard_defender", "" +define, 0x4A7280, 0x4ADF40, 0x4A7310, "Fighter_eval_tile_vulnerability", "int (__fastcall *) (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y)" +repl call, 0x45861F, 0x45A7CD, 0x45869F, "Fighter_eval_tile_vulnerability_in_Unit_ai_move_naval_power_unit", "" +inlead, 0x5C6290, 0x5D50E0, 0x5C5FA0, "Unit_select", "void (__fastcall *) (Unit *this)" +inlead, 0x5B6820, 0x5C5180, 0x5B6530, "Unit_select_stealth_attack_target", "bool (__fastcall *) (Unit * this, int edx, int target_civ_id, int x, int y, bool allow_popup, Unit ** out_selected_target)" +repl call, 0x5C73FF, 0x5D629C, 0x5C710F, "Unit_try_flying_for_precision_strike", "" +define, 0x5C1210, 0x5CFDA0, 0x5C0F20, "Unit_play_bombard_fire_animation", "int (__fastcall *) (Unit * this, int edx, int x, int y)" +define, 0x5CA860, 0x5D97A0, 0x5CA570, "Unit_play_bombing_animation", "void (__fastcall *) (Unit * this, int edx, int x, int y)" +repl call, 0x5C7429, 0x5D62BA, 0x5C7139, "Unit_play_bombing_anim_for_precision_strike", "" +repl call, 0x5C143D, 0x5CFFCD, 0x5C114D, "Unit_play_anim_for_bombard_tile", "" +repl call, 0x5B6A1B, 0x5C5368, 0x5B672B, "PopupSelection_add_stealth_attack_target", "" +inlead, 0x4D94F0, 0x4E1E80, 0x4D95B0, "Main_Screen_Form_issue_precision_strike_cmd", "void (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit)" +repl call, 0x4A3E92, 0x4AAB40, 0x4A3F22, "rand_bombard_target", "" +repl call, 0x5B6549, 0x5C4EA9, 0x5B6259, "Tile_check_water_for_stealth_attack", "" +inlead, 0x5B64C0, 0x5C4E20, 0x5B61D0, "Unit_can_stealth_attack", "bool (__fastcall *) (Unit * this, int edx, Unit * target)" +define, 0x61BCA0, 0x63D770, 0x61BBD0, "process_text_snippet", "int (__cdecl *) (char * in, char * out)" +repl call, 0x4D788A, 0x4E01EA, 0x4D794A, "process_text_for_map_message", "" +repl call, 0x5C6997, 0x5D5812, 0x5C66A7, "rand_int_to_dodge_city_aa", "" +repl call, 0x5C69A7, 0x5D5822, 0x5C66B7, "Unit_get_defense_to_dodge_city_aa", "" +repl call, 0x4A2179, 0x4A8D8A, 0x4A2209, "Unit_get_defense_to_find_bombard_defender", "" +define, 0x585B00, 0x592D50, 0x585860, "get_int_from_conquests_ini", "int (__cdecl *) (LPCSTR key, int param_2, int param_3)" +repl call, 0x59301E, 0x5A0756, 0x592D3E, "get_WindowsFileBox_from_ini", "" +define, 0x4A0670, 0x4A71F0, 0x4A0700, "open_load_game_file_picker", "char const * (__fastcall *) (void * this)" +repl call, 0x593054, 0x5A078A, 0x592D74, "do_open_load_game_file_picker", "" +inlead, 0x592D90, 0x5A0490, 0x592AB0, "do_load_game", "void * (__cdecl *) (char * param_1)" +define, 0x4F5EF0, 0x4FF290, 0x4F5FB0, "perform_interturn", "void (__cdecl *) ()" +repl call, 0x4F6759, 0x4FFB21, 0x4F6819, "perform_interturn_in_main_loop", "" +repl call, 0x4F59E6, 0x4FED88, 0x4F5AA6, "show_movement_phase_popup", "" +repl call, 0x5936F3, 0x5A0E8C, 0x593413, "show_intro_after_load_popup", "" +define, 0xA527B4, 0xA74FAC, 0xA52774, "p_is_pbem_game", "byte *" +define, 0xA52991, 0xA75189, 0xA52951, "p_is_offline_mp_game", "byte *" +inlead, 0x4A3A70, 0x4AA6F0, 0x4A3B00, "Fighter_do_bombard_tile", "void (__fastcall *) (Fighter * this, int edx, Unit * unit, int neighbor_index, int param_3, int param_4)" +define, 0x74AF60, 0x765300, 0x74AF20, "p_mp_object", "void *" +define, 0x4697B0, 0x46BF90, 0x469830, "mp_check_current_combat", "bool (__fastcall *) (void * this, int edx, int mp_tile_x, int mp_tile_y)" +define, 0x4A2650, 0x4A9290, 0x4A26E0, "Fighter_damage_city_by_bombardment", "bool (__fastcall *) (Fighter * this, int edx, Unit * unit, City * city, int damage_kind, int min_fire_rate)" +define, 0x426BD0, 0x428310, 0x426C50, "Map_in_range", "bool (__fastcall *) (Map * this, int edx, int x, int y)" +inlead, 0x4AE030, 0x4B5010, 0x4AE0C0, "City_can_trade_via_water", "bool (__fastcall *) (City * this)" +repl call, 0x4E67f4, 0x4EF255, 0x4E68B4, "City_shows_harbor_icon", "" +inlead, 0x4ADF90, 0x4B4F70, 0x4AE020, "City_can_trade_via_air", "bool (__fastcall *) (City * this)" +repl call, 0x4E6842, 0x4EF2A7, 0x4E6902, "City_shows_airport_icon", "" +define, 0x4B1F90, 0x4B8F10, 0x4B2020, "City_count_improvements_with_flag", "int (__fastcall *) (City * this, int edx, enum ImprovementTypeFlags flag)" +repl call, 0x4A12EC, 0x4A7E9C, 0x4A137C, "Unit_check_king_for_defense_priority", "" +repl call, 0x4A131A, 0x4A7ECA, 0x4A13AA, "Unit_check_king_for_defense_priority", "" +repl call, 0x4A133D, 0x4A7EED, 0x4A13CD, "Unit_check_king_for_defense_priority", "" +repl call, 0x4A144C, 0x4A7FFC, 0x4A14DC, "Unit_check_king_for_defense_priority", "" +repl call, 0x4A1477, 0x4A8027, 0x4A1507, "Unit_check_king_for_defense_priority", "" +repl call, 0x4A149F, 0x4A804F, 0x4A152F, "Unit_check_king_for_defense_priority", "" +repl call, 0x598EC5, 0x5A686D, 0x598BE5, "get_local_time_for_unit_ini", "" +repl call, 0x598AEC, 0x5A63F8, 0x59880C, "get_local_time_for_unit_ini", "" +define, 0x581330, 0x58E060, 0x581090, "Trade_Net_get_direction_from_internal_map", "int (__fastcall *) (Trade_Net * this, int edx, int x, int y, bool use_data_2_else_4)" +inlead, 0x50EC10, 0x518F00, 0x50ECB0, "DiploForm_assemble_tradable_items", "void (__fastcall *) (DiploForm * this)" +repl call, 0x50FAD9, 0x519D8B, 0x50FB79, "Leader_could_buy_tech_for_trade_screen", "" +repl call, 0x50FB9C, 0x519E42, 0x50FC3C, "Leader_could_buy_tech_for_trade_screen", "" +inlead, 0x4C10B0, 0x4C86A0, 0x4C1140, "City_get_building_defense_bonus", "int (__fastcall *) (City * this)" +define, 0x55A8D0, 0x5667E0, 0x55A880, "Leader_count_wonders_with_flag", "int (__fastcall *) (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city)" +repl vptr, 0x66DD04, 0x68ADE4, 0x66DD04, "Unit_eval_escort_requirement", "int (__fastcall *) (Unit * this)" +inlead, 0x561860, 0x56D9E0, 0x561810, "Leader_unlock_technology", "void (__fastcall *) (Leader * this, int edx, int tech_id, bool param_2, bool param_3, bool param_4)" +define, 0x55CF10, 0x568F90, 0x55CEC0, "Leader_recompute_buildings_maintenance", "void (__fastcall *) (Leader *this)" +define, 0x5683F7, 0x5747F2, 0x5683A7, "ADDR_UNLOCK_TECH_AT_INIT_1", "int" +define, 0x56847F, 0x57487A, 0x56842F, "ADDR_UNLOCK_TECH_AT_INIT_3", "int" +define, 0x5688DC, 0x574CD6, 0x56888C, "ADDR_UNLOCK_TECH_AT_INIT_2", "int" +define, 0x5621DE, 0x56E33D, 0x56217E, "ADDR_UNLOCK_TECH_RECURSE", "int" +repl call, 0x4212E7, 0x422847, 0x421367, "City_get_improv_maintenance_for_ui", "" +define, 0x563473, 0x56F723, 0x563423, "ADDR_CAPTURE_CITY_BARB_BRANCH", "byte *" +define, 0x56082B, 0x56C938, 0x5607DB, "ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP", "byte *" +define, 0x560838, 0x56C945, 0x5607E8, "ADDR_PROD_PHASE_BARB_DONE_JUMP", "byte *" +define, 0x426C00, 0x428340, 0x426C80, "Map_wrap_horiz", "int (__fastcall *) (Map * this, int edx, int x)" +define, 0x426C40, 0x428380, 0x426CC0, "Map_wrap_vert", "int (__fastcall *) (Map * this, int edx, int y)" +repl call, 0x44FEC3, 0x451F64, 0x44FF43, "neighbor_index_to_diff_for_barb_ai", "" +repl call, 0x44FEF0, 0x451F91, 0x44FF70, "Map_wrap_vert_for_barb_ai", "" +inlead, 0x5604B0, 0x56C5A0, 0x560460, "Leader_do_production_phase", "void (__fastcall *) (Leader * this)" +define, 0x5DF900, 0x5EF150, 0x5DF830, "count_set_bits", "int (__cdecl *) (unsigned int bit_field)" +repl call, 0x5604F8, 0x56C5E8, 0x5604A8, "count_player_bits_for_barb_prod", "" +repl call, 0x4C5208, 0x4CCAC6, 0x4C5228, "Map_get_tile_to_check_visibility", "" +repl vis, 0x4C5289, 0x4CCB4D, 0x4C52A9, "", "" +repl call, 0x4C5333, 0x4CCBEE, 0x4C5353, "Map_get_tile_to_check_visibility", "" +repl call, 0x4C35E4, 0x4CAE49, 0x4C3604, "Map_get_tile_to_check_visibility", "" +repl call, 0x4C3577, 0x4CADDC, 0x4C3597, "Map_get_tile_to_check_visibility", "" +repl call, 0x578A67, 0x585B87, 0x5789D7, "Map_get_tile_to_check_visibility", "" +repl call, 0x4C37E2, 0x4CB062, 0x4C3802, "Map_get_tile_to_check_visibility", "" +repl call, 0x4EDEF4, 0x4F6E44, 0x4EDFB4, "Map_get_tile_to_check_visibility", "" +repl vis, 0x4F0D82, 0x4F9ED2, 0x4F0E42, "", "" +repl call, 0x5AAA7A, 0x5B9196, 0x5AA78A, "Map_get_tile_to_check_visibility", "" +repl vis, 0x4EA2C3, 0x4F30B4, 0x4EA383, "", "" +repl vis, 0x4A1E90, 0x4A8A9E, 0x4A1F20, "", "" +repl call, 0x449941, 0x44B891, 0x4499C1, "Map_get_tile_to_check_visibility", "" +repl vis, 0x44997D, 0x44B8CF, 0x4499FD, "", "" +repl vis, 0x4EFC7A, 0x4F8C6B, 0x4EFD3A, "", "" +repl vis, 0x5B71B2, 0x5C5B43, 0x5B6EC2, "", "" +repl vis, 0x5B75EF, 0x5C5F53, 0x5B72FF, "", "" +repl vis, 0x5B7883, 0x5C6255, 0x5B7593, "", "" +repl vis, 0x5B7CC0, 0x5c66a9, 0x5B79D0, "", "" +repl vis, 0x5B808E, 0x5c6a80, 0x5B7D9E, "", "" +repl vis, 0x5B95A2, 0x5c802a, 0x5B92B2, "", "" +repl vis, 0x5BFD8A, 0x5ce91c, 0x5BFA9A, "", "" +repl vis, 0x5C4863, 0x5d351b, 0x5C4573, "", "" +repl vis, 0x5C4A3E, 0x5d3722, 0x5C474E, "", "" +repl vis, 0x5C4AD4, 0x5D37C3, 0x5C47E4, "", "" +repl vis, 0x5C4B90, 0x5D3884, 0x5C48A0, "", "" +repl vis, 0x5C4C41, 0x5D3925, 0x5C4951, "", "" +repl vis, 0x5C6A62, 0x5D58D9, 0x5C6772, "", "" +repl vis, 0x5C6F21, 0x5D5DA7, 0x5C6C31, "", "" +repl vis, 0x5C7F40, 0x5D6E00, 0x5C7C50, "", "" +repl vis, 0x5C8614, 0x5D7521, 0x5C8324, "", "" +repl vis, 0x5C8752, 0x5D7666, 0x5C8462, "", "" +repl vis, 0x5C8F8B, 0x5D7ECE, 0x5C8C9B, "", "" +repl vis, 0x5B9878, 0x5C8330, 0x5B9588, "", "" +repl vis, 0x5B992A, 0x5C83E2, 0x5B963A, "", "" +repl vis, 0x5B99E6, 0x5C84A7, 0x5B96F6, "", "" +repl vis, 0x5B9A97, 0x5C8559, 0x5B97A7, "", "" +repl vis, 0x5B9E54, 0x5C892B, 0x5B9B64, "", "" +repl vis, 0x57F4E4, 0x58C20D, 0x57F244, "", "" +repl vis, 0x57FC67, 0x58C8E4, 0x57F9C7, "", "" +repl call, 0x57F9B6, 0x58C62B, 0x57F716, "Map_get_tile_to_check_visibility", "" +repl call, 0x57F9F2, 0x58C667, 0x57F752, "Map_get_tile_to_check_visibility", "" +inlead, 0x4ED120, 0x4F6040, 0x4ED1E0, "Main_Screen_Form_is_unit_visible_to_player", "bool (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * unit)" +repl vptr, 0x670270, 0x68D31C, 0x670270, "Tile_m42_Get_Overlays", "unsigned (__fastcall *) (Tile * this, int edx, byte visible_to_civ)" +repl vptr, 0x6702E4, 0x68D390, 0x6702E4, "Tile_m71_Check_Worker_Job", "int (__fastcall *) (Tile * this)" +inlead, 0x5DBF10, 0x5EB460, 0x5DBE40, "Tile_get_road_bonus", "int (__fastcall *) (Tile * this)" +define, 0x5DBEC0, 0x5EB410, 0x5DBDF0, "Tile_get_mining_bonus", "int (__fastcall *) (Tile * this)" +define, 0x4EDF20, 0x4F6E70, 0x4EDFE0, "Unit_check_contact_bit_6", "bool (__fastcall *) (Unit * this, int edx, int civ_id)" +repl call, 0x4E8942, 0x4F15D0, 0x4E8A02, "Unit_check_contact_bit_6_on_right_click", "" +repl call, 0x4EA330, 0x4F3121, 0x4EA3F0, "Unit_check_contact_bit_6_on_right_click", "" +inlead, 0x4A8350, 0x4AF030, 0x4A83E0, "Leader_is_tile_visible", "bool (__fastcall *) (Leader * this, int edx, int x, int y)" +repl call, 0x4A784E, 0x4AE509, 0x4a78DE, "Tile_check_water_for_sea_zoc", "" +define, 0x4A79C2, 0x4AE66D, 0x4A7A52, "ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC", "byte *" +define, 0x4A7CAA, 0x4AE962, 0x4A7D3A, "ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC", "byte *" +repl call, 0x4A7BF2, 0x4AE8AA, 0x4A7C82, "Tile_check_water_for_land_zoc", "" +inlead, 0x5BE6E0, 0x5CD2C0, 0x5BE3F0, "Unit_get_attack_strength", "int (__fastcall *) (Unit * this)" +repl call, 0x4A79CA, 0x4AE675, 0x4A7A5A, "Unit_get_attack_strength_for_sea_zoc", "" +repl call, 0x4A7B15, 0x4AE7BE, 0x4A7BA5, "Unit_get_attack_strength_for_sea_zoc", "" +repl call, 0x4A7B20, 0x4AE7C9, 0x4A7BB0, "Unit_get_attack_strength_for_sea_zoc", "" +repl call, 0x4A7CB2, 0x4AE96A, 0x4A7D42, "Unit_get_attack_strength_for_land_zoc", "" +repl call, 0x4A7DFD, 0x4AEAB3, 0x4A7E8D, "Unit_get_attack_strength_for_land_zoc", "" +repl call, 0x4A7E08, 0x4AEABE, 0x4A7E98, "Unit_get_attack_strength_for_land_zoc", "" +inlead, 0x4E3E90, 0x4EC6E0, 0x4E3F50, "Main_Screen_Form_find_visible_unit", "Unit * (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * excluded)" +define, 0x4F00F0, 0x4F9100, 0x4F01B0, "Animator_play_one_shot_unit_animation", "void (__fastcall *) (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3)" +repl call, 0x4A81A4, 0x4AEE83, 0x4A8234, "Animator_play_zoc_animation", "" +repl call, 0x4A81E2, 0x4AEEC1, 0x4A8272, "Animator_play_zoc_animation", "" +inlead, 0x4A76B0, 0x4AE370, 0x4A7740, "Fighter_apply_zone_of_control", "void (__fastcall *) (Fighter * this, int edx, Unit * unit, int from_x, int from_y, int to_x, int to_y)" +define, 0x4A1CD0, 0x4A88E0, 0x4A1D60, "Fighter_check_combat_anim_visibility", "bool (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender, bool param_3)" +repl call, 0x4A7F71, 0x4AEC36, 0x4A8001, "Fighter_check_zoc_anim_visibility", "" +define, 0x4A7F61, 0x4AEC26, 0x4A7FF1, "ADDR_ZOC_CHECK_ATTACKER_ANIM_FIELD_111", "byte *" +define, 0x4A770A, 0x4AE3CA, 0x4A779A, "ADDR_SKIP_ZOC_FOR_ONE_HP_LAND_UNIT", "byte *" +define, 0x4A7745, 0x4AE405, 0x4A77D5, "ADDR_SKIP_ZOC_FOR_ONE_HP_SEA_UNIT", "byte *" +inlead, 0x5B8FC0, 0x5C7A40, 0x5B8CD0, "Unit_move_to_adjacent_tile", "int (__fastcall *) (Unit * this, int edx, int neighbor_index, bool param_2, int param_3, byte param_4)" +repl call, 0x5B91B4, 0x5C7C32, 0x5B8EC4, "Tile_check_water_for_canal_move_to_adjacent_tile_dest", "" +repl call, 0x5B945B, 0x5C7EDE, 0x5B916B, "Trade_Net_get_move_cost_after_zoc", "" +repl call, 0x5B9471, 0x5C7EF4, 0x5B9181, "Unit_can_move_after_zoc", "" +repl call, 0x5B94E4, 0x5C7F67, 0x5B91F4, "Unit_get_max_move_points_for_bridge_exit", "" +repl vptr, 0x66DD40, 0x68AE20, 0x66DD40, "Unit_teleport", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad)" +define, 0x5BEF00, 0x5CDB10, 0x5BEC10, "Unit_score_kill", "void (__fastcall *) (Unit * this, int edx, Unit * victim, bool was_attacking)" +define, 0x5BF558, 0x5CE0EA, 0x5BF268, "ADDR_EXISTING_BATTLE_CREATED_UNIT_CHECK", "void *" +inlead, 0x4A1AE0, 0x4A86E0, 0x4A1B70, "Fighter_find_defensive_bombarder", "Unit * (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender)" +define, 0x5BCA90, 0x5CB620, 0x5BC7A0, "Unit_get_containing_army", "Unit * (__fastcall *) (Unit * this)" +define, 0x4A0ED0, 0x4A7A90, 0x4A0F60, "Fighter_get_combat_odds", "int (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses)" +repl call, 0x4A5AF9, 0x4AC799, 0x4A5B89, "Fighter_get_odds_for_main_combat_loop", "" +define, 0x4A3280, 0x4A9ED0, 0x4A3310, "Fighter_damage_by_defensive_bombard", "void (__fastcall *) (Fighter * this, int edx, Unit * bombarder, Unit * defender)" +repl call, 0x4A57C5, 0x4AC477, 0x4A5855, "Fighter_damage_by_db_in_main_loop", "" +inlead, 0x4A53A0, 0x4AC060, 0x4A5430, "Fighter_fight", "byte (__fastcall *) (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender_or_null)" +repl call, 0x4A6EB7, 0x4ADB60, 0x4A6F47, "Unit_score_kill_by_defender", "" +define, 0x5C8180, 0x5D7060, 0x5C7E90, "Unit_play_attack_animation", "void (__fastcall *) (Unit * this, int edx, int direction)" +repl call, 0x4A5791, 0x4AC443, 0x4A5821, "Unit_play_attack_anim_for_def_bombard", "" +define, 0x578780, 0x5858A0, 0x5786F0, "Navigator_Data_reset", "void (__fastcall *) (Navigator_Data * this)" +inlead, 0x536080, 0x540670, 0x536100, "initialize_map_music", "void (__cdecl *) (int civ_id, int era_id, bool param_3)" +inlead, 0x535FB0, 0x5405A0, 0x536030, "deinitialize_map_music", "void (__stdcall *) ()" +inlead, 0x5C7350, 0x5D61F0, 0x5C7060, "Unit_do_precision_strike", "void (__fastcall *) (Unit * this, int edx, int x, int y)" +define, 0x5B5790, 0x5C40E0, 0x5B54A0, "Unit_confirm_war", "bool (__fastcall *) (Unit * this, int edx, int against_civ_id, bool allow_map_message)" +inlead, 0x5C37B0, 0x5D23F0, 0x5C34C0, "Unit_check_precision_strike_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5B5280, 0x5C3BF0, 0x5B4F90, "Unit_attack_tile", "void (__fastcall *) (Unit * this, int edx, int x, int y, int bombarding)" +repl call, 0x5C33F6, 0x5D2026, 0x5C3106, "Map_get_tile_to_check_visibility", "" +repl call, 0x52C39A, 0x5367DC, 0x52C42A, "Map_get_tile_to_check_visibility", "" +repl call, 0x52C146, 0x536586, 0x52C1D6, "Map_get_tile_to_check_visibility", "" +repl call, 0x52BED0, 0x536310, 0x52BF60, "Map_get_tile_to_check_visibility", "" +repl call, 0x5B555E, 0x5C3EBF, 0x5B526E, "Unit_get_max_moves_after_barricade_attack", "" +define, 0x56D2C0, 0x579C40, 0x56D230, "city_at", "City * (__cdecl *) (int x, int y)" +repl call, 0x4A2018, 0x4A8C28, 0x4A20A8, "city_at_in_find_bombard_defender", "" +inlead, 0x5C3510, 0x5D2140, 0x5C3220, "Unit_check_bombard_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C5160, 0x5D3E40, 0x5C4E70, "Unit_can_disembark_anything", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +repl call, 0x52C912, 0x536D92, 0x52C9A2, "Unit_get_defense_for_bombardable_unit_check", "" +repl call, 0x57F627, 0x58C356, 0x57F387, "get_tile_occupier_for_ai_path", "" +repl call, 0x56D9D1, 0x57A3C2, 0x56D941, "Unit_is_tile_occupier_visible", "" +repl vptr, 0x66BF68, 0x68905C, 0x66BF68, "Demographics_Form_m22_draw", "void (__fastcall *) (Demographics_Form * this)" +define, 0x600070, 0x615570, 0x5FFF50, "PCX_Image_fill_area", "int (__fastcall *) (PCX_Image * this, int edx, RECT * rect, int color)" +define, 0x5FD360, 0x611290, 0x5FD240, "PCX_Image_set_text_effects", "void (__fastcall *) (PCX_Image * this, int edx, int text_color, int shadow_color, int shadow_offset_x, int shadow_offset_y)" +inlead, 0x5676C0, 0x573AB0, 0x567670, "Leader_get_optimal_city_number", "int (__fastcall *) (Leader * this)" +inlead, 0x55AA10, 0x566930, 0x55A9C0, "Leader_count_wonders_with_small_flag", "int (__fastcall *) (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null)" +repl call, 0x567706, 0x573AF6, 0x5676B6, "Leader_count_forbidden_palaces_for_ocn", "" +repl call, 0x550F99, 0x55C0E1, 0x550F49, "Unit_can_do_worker_command_for_button_setup", "" +repl call, 0x55132D, 0x55C484, 0x5512DD, "Unit_can_do_worker_command_for_button_setup", "" +define, 0x55B1A0, 0x567100, 0x55B150, "Leader_reveal_tile", "void (__fastcall *) (Leader * this, int edx, int x, int y)" +define, 0x5FCB10, 0x610790, 0x5FC9F0, "PCX_Image_draw_onto", "int (__fastcall *) (PCX_Image * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y)" +define, 0x5DBF60, 0x5EB4B0, 0x5DBE90, "Tile_get_terrain_move_cost", "int (__fastcall *) (Tile * this)" +define, 0x56D340, 0x579CC0, 0x56D2B0, "get_combat_occupier", "int (__cdecl *) (int tile_x, int tile_y, int civ_id, byte ignore_visibility)" +repl call, 0x45871C, 0x45A8C9, 0x45879C, "get_combat_occupier_in_Unit_ai_move_naval_power_unit", "" +define, 0x561480, 0x56D5E0, 0x561430, "Leader_has_tech_with_flag", "bool (__fastcall *) (Leader * this, int edx, enum AdvanceTypeFlags flag)" +inlead, 0x57D980, 0x58A680, 0x57D6E0, "Trade_Net_recompute_city_connections", "void (__fastcall *) (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id)" +inlead, 0x62B1A0, 0x64E220, 0x6274B0, "OpenGLRenderer_initialize", "int (__fastcall *) (OpenGLRenderer * this, int edx, PCX_Image * texture)" +inlead, 0x62B450, 0x64E510, 0x627760, "OpenGLRenderer_draw_line", "void (__fastcall *) (OpenGLRenderer * this, int edx, int x1, int y1, int x2, int y2)" +inlead, 0x62B490, 0x64E560, 0x6277A0, "OpenGLRenderer_set_color", "void (__fastcall *) (OpenGLRenderer * this, int edx, unsigned int rgb555)" +inlead, 0x62B570, 0x64E600, 0x627880, "OpenGLRenderer_set_opacity", "void (__fastcall *) (OpenGLRenderer * this, int edx, unsigned int alpha)" +inlead, 0x62B5B0, 0x64E660, 0x6278C0, "OpenGLRenderer_set_line_width", "void (__fastcall *) (OpenGLRenderer * this, int edx, int width)" +inlead, 0x62B5D0, 0x64E690, 0x6278E0, "OpenGLRenderer_enable_line_dashing", "void (__fastcall *) (OpenGLRenderer * this)" +inlead, 0x62B5F0, 0x64E6C0, 0x627900, "OpenGLRenderer_disable_line_dashing", "void (__fastcall *) (OpenGLRenderer * this)" +repl call, 0x5BFBFF, 0x5CE79A, 0x5BF90F, "Tile_check_water_for_retreat_on_defense", "bool (__fastcall *) (Tile * this)" +inlead, 0x5D2150, 0x5E13F0, 0x5D2080, "Map_build_trade_network", "void (__fastcall *) (Map * this)" +inlead, 0x57DE90, 0x58ABD0, 0x57DBF0, "Trade_Net_recompute_city_cons_and_res", "void (__fastcall *) (Trade_Net * this, int edx, bool param_1)" +repl call, 0x57DAF1, 0x58A7F9, 0x57D851, "Trade_Net_set_unit_path_to_fill_road_net", "" +repl call, 0x57DE29, 0x58AB4E, 0x57DB89, "Trade_Net_set_unit_path_to_find_sea_route", "" +define, 0x5EA6E0, 0x5F9F30, 0x5EA610, "Tile_has_colony", "bool (__fastcall *) (Tile * this)" +repl call, 0x5C1559, 0x5D00ED, 0x5C1269, "City_count_airports_for_airdrop", "" +define, 0x437CF0, 0x4398A0, 0x437D70, "Leader_get_city_count_on_continent", "int (__fastcall *) (Leader * this, int edx, int cont_id)" +repl call, 0x42EB3F, 0x430615, 0x42EBBF, "Leader_get_cont_city_count_for_worker_req", "" +repl call, 0x42EBCA, 0x430698, 0x42EC4A, "Leader_get_cont_city_count_for_worker_req", "" +repl call, 0x42EAD2, 0x4305AE, 0x42EB52, "Leader_get_city_count_for_worker_prod_cap", "" +inlead, 0x55D310, 0x5693A0, 0x55D2C0, "Leader_sum_unit_maintenance", "int (__fastcall *) (Leader * this, int edx, int government_id)" +define, 0xA52684, 0xA74E7C, 0xA52644, "p_game_difficulty", "int *" +define, 0x5CD960, 0x5DC940, 0x5CD880, "Unit_is_terrain_impassable", "bool (__fastcall *) (Unit * this, int edx, int terrain_type_index)" +define, 0x41CD22, 0x41E04C, 0x41CDA2, "ADDR_LUXURY_BOX_ROW_HEIGHT", "byte *" +define, 0x30, 0x38, 0x30, "LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET", "int" +define, 0x740A00, 0x75ADA0, 0x7409C0, "p_city_form", "City_Form *" +inlead, 0x5F82E0, 0x6087E0, 0x5F8210, "Sprite_draw", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table)" +repl call, 0x421295, 0x4227F5, 0x421315, "Sprite_draw_improv_img_on_city_form", "" +inlead, 0x421240, 0x4227A0, 0x4212C0, "draw_improv_icons_on_city_screen", "void (__cdecl *) (Base_List_Control * control, int improv_id, int item_index, int offset_x, int offset_y)" +define, 0x4B0710, 0x4B76C0, 0x4B07A0, "City_get_tourism_amount", "int (__fastcall *) (City * this, int edx, int improv_id)" +repl call, 0x42138C, 0x4228EC, 0x42140C, "City_get_tourism_amount_to_draw", "" +repl call, 0x4213FF, 0x42295F, 0x42147F, "Sprite_draw_tourism_gold", "" +repl call, 0x4BA075, 0x4C16E5, 0x4BA105, "City_calc_tile_yield_while_gathering", "" +repl call, 0x4B0512, 0x4B74D2, 0x4B05A2, "City_calc_tile_yield_while_gathering", "" +repl call, 0x4ADA3F, 0x4B4A28, 0x4ADACF, "City_calc_tile_yield_while_gathering", "" +repl call, 0x4B0F04, 0x4B7EB4, 0x4B0F94, "City_calc_tile_yield_while_gathering", "" +repl call, 0x4B25EF, 0x4B9576, 0x4B267F, "City_calc_tile_yield_while_gathering", "" +repl call, 0x4BA645, 0x4C1CA4, 0x4BA6D5, "City_calc_tile_yield_while_gathering", "" +inlead, 0x4B0E80, 0x4B7E30, 0x4B0F10, "City_recompute_yields_and_happiness", "void (__fastcall *) (City * this)" +inlead, 0x55EC80, 0x56AD30, 0x55EC30, "Leader_record_export", "bool (__fastcall *) (Leader * this, int edx, int importer_civ_id, int resource_id)" +inlead, 0x55ED60, 0x56AE10, 0x55ED10, "Leader_erase_export", "bool (__fastcall *) (Leader * this, int edx, int importer_civ_id, int resource_id)" +inlead, 0x4216A0, 0x422BF0, 0x421720, "City_Form_open", "void (__fastcall *) (City_Form * this, int edx, City * city, int param_2)" +define, 0x4B0330, 0x4B72F0, 0x4B03C0, "City_calc_tile_yield_at", "int (__fastcall *) (City * this, int edx, int yield_type, int tile_x, int tile_y)" +repl vptr, 0x66dd10, 0x68adf0, 0x66dd10, "Unit_has_enough_escorters_present", "bool (__fastcall *) (Unit * this)" +repl vptr, 0x66dd14, 0x68adf4, 0x66dd14, "Unit_check_escorter_health", "void (__fastcall *) (Unit * this, int edx, bool * has_any_escort_present, bool * any_escorter_cant_heal)" +inlead, 0x5694D0, 0x575900, 0x569480, "Leader_spawn_unit", "Unit * (__fastcall *) (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id)" +repl call, 0x5B7BA8, 0x5C69B8, 0x5B78B8, "Leader_spawn_captured_unit", "" +repl call, 0x5B7FCA, 0x5C657E, 0x5B7CDA, "Leader_spawn_captured_unit", "" +repl call, 0x5B74D8, 0x5C5E41, 0x5B71E8, "Leader_spawn_captured_unit", "" +inlead, 0x55E190, 0x56A220, 0x55E140, "Leader_enter_new_era", "void (__fastcall *) (Leader * this, int edx, bool param_1, bool no_online_sync)" +define, 0x55A270, 0x566180, 0x55A220, "Leader_get_name", "char * (__fastcall *) (Leader * this)" +define, 0x55A370, 0x566280, 0x55A320, "Leader_get_gender", "int (__fastcall *) (Leader * this)" +define, 0x55A210, 0x566120, 0x55A1C0, "Leader_get_civ_adjective", "char * (__fastcall *) (Leader * this)" +define, 0x55A240, 0x566150, 0x55A1F0, "Leader_get_civ_noun", "char * (__fastcall *) (Leader * this)" +define, 0x55A340, 0x566250, 0x55A2F0, "Leader_get_civ_formal_name", "char * (__fastcall *) (Leader * this)" +define, 0x55A2C0, 0x5661D0, 0x55A270, "Leader_get_title", "char * (__fastcall *) (Leader * this)" +repl call, 0x593614, 0x5A0DAE, 0x593334, "Leader_get_player_title_for_intro_popup", "" +inlead, 0x4A8240, 0x4AEF20, 0x4A82D0, "Fighter_animate_start_of_combat", "void (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender)" +define, 0x61A2E0, 0x63B710, 0x61A210, "Context_Menu_disable_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id)" +define, 0x61A380, 0x63B7E0, 0x61A2B0, "Context_Menu_put_image_on_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, Sprite * image)" +inlead, 0x4B8BA0, 0x4C0210, 0x4B8C30, "City_spawn_unit_if_done", "void (__fastcall *) (City * this)" +inlead, 0x5C0620, 0x5CF1C0, 0x5C0330, "Unit_can_upgrade", "bool (__fastcall *) (Unit * this)" +define, 0x4C0690, 0x4C7C50, 0x4C0720, "City_get_upgraded_type_id", "int (__fastcall *) (City * this, int edx, int unit_type_id)" +inlead, 0x56AAE0, 0x576F90, 0x56AA90, "Leader_upgrade_all_units", "void (__fastcall *) (Leader * this, int edx, int type_id)" +inlead, 0x4DE8B0, 0x4E7290, 0x4DE970, "Main_Screen_Form_upgrade_all_units", "void (__fastcall *) (Main_Screen_Form * this, int edx, int type_id)" +repl call, 0x56AB65, 0x577017, 0x56AB15, "Unit_can_perform_upgrade_all", "" +repl call, 0x4DE93C, 0x4E7316, 0x4DE9FC, "Unit_can_perform_upgrade_all", "" +repl call, 0x4BE89A, 0x4C5E80, 0x4BE92A, "Leader_spawn_unit_from_building", "" +repl call, 0x5C0727, 0x5CF2C7, 0x5C0437, "City_count_improvs_enabling_upgrade", "" +repl call, 0x5C0700, 0x5CF2A0, 0x5C0410, "City_count_improvs_enabling_upgrade", "" +repl call, 0x5C0715, 0x5CF2B5, 0x5C0425, "City_count_improvs_enabling_upgrade", "" +inlead, 0x4AECC0, 0x4B5C80, 0x4AED50, "City_raze", "void (__fastcall *) (City * this, int edx, int civ_id_responsible, bool checking_elimination)" +define, 0x563410, 0x56F6C0, 0x5633C0, "Leader_capture_city", "bool (__fastcall *) (Leader * this, int edx, City * city, Unit * unit, bool involuntary, bool converted)" +repl call, 0x55BA76, 0x567D20, 0x55BA26, "Leader_create_city_from_hut", "" +repl call, 0x568F57, 0x57538A, 0x568F07, "Leader_create_city_for_ai_respawn", "" +repl call, 0x5B35D3, 0x5C1F22, 0x5B32E3, "Leader_create_city_for_founding", "" +repl call, 0x5D2B8F, 0x5E1E68, 0x5D2ABF, "Leader_create_city_for_scenario", "" +inlead, 0x564800, 0x570BB0, 0x5647B0, "Leader_do_capture_city", "bool (__fastcall *) (Leader * this, int edx, City * city, bool involuntary, bool converted)" +define, 0x4BB410, 0x4C2A60, 0x4BB4A0, "City_count_citizens_of_race", "int (__fastcall *) (City * this, int edx, int race_id)" +define, 0x5A6060, 0x5B4350, 0x5A5D60, "count_units_at", "int (__cdecl *) (int x, int y, enum unit_filter filter, int arg_a, int arg_b, int arg_c)" +inlead, 0x4B9C60, 0x4C12E0, 0x4B9CF0, "City_draw_hud_icon", "void (__fastcall *) (City * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y)" +inlead, 0x4B9BB0, 0x4C1230, 0x4B9C40, "City_has_hud_icon", "bool (__fastcall *) (City * this)" +inlead, 0x4BFBF0, 0x4C71B0, 0x4BFC80, "City_draw_on_map", "void (__fastcall *) (City * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7)" +inlead, 0x4E7E30, 0x4F08F0, 0x4E7EF0, "MenuUnitItem_write_text_to_temp_str", "void (__fastcall *) (MenuUnitItem * this)" +define, 0xCAB2D8, 0xCCDB88, 0xCAB298, "temp_str", "char[4096]" +repl call, 0x5EDD89, 0x5FD7BE, 0x5EDCB9, "Tile_m74_Set_Square_Type_for_hill_gen", "" +inlead, 0x5D1EA0, 0x5E1140, 0x5D1DD0, "Map_place_scenario_things", "void (__fastcall *) (Map * this)" +repl vptr, 0x66C3EC, 0x6894D8, 0x66C3EC, "Advisor_Base_Form_domestic_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +repl vptr, 0x66F8CC, 0x68C988, 0x66F8CC, "Advisor_Base_Form_trade_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +repl vptr, 0x66E0CC, 0x68B1B8, 0x66E0CC, "Advisor_Base_Form_military_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +repl vptr, 0x66CAAC, 0x689B9C, 0x66CAAC, "Advisor_Base_Form_foreign_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +repl vptr, 0x66BD3C, 0x688E34, 0x66BD3C, "Advisor_Base_Form_cultural_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +repl vptr, 0x66F59C, 0x68C658, 0x66F59C, "Advisor_Base_Form_science_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +inlead, 0x4E79B0, 0x4F0470, 0x4E7A70, "Main_Screen_Form_open_quick_build_chooser", "void (__fastcall *) (Main_Screen_Form * this, int edx, City * city, int mouse_x, int mouse_y)" +repl call, 0x4E9941, 0x4F273F, 0x4E9A01, "Context_Menu_get_selected_item_on_unit_rcm", "int (__fastcall *) (Context_Menu * this)" +define, 256, 257, 256, "LBL_WAKE", "int" +define, 255, 256, 255, "LBL_ACTIVATE", "int" +define, 0x4C1280, 0x4C8860, 0x4C1310, "City_sum_buildings_naval_power", "int (__fastcall *) (City * this)" +repl call, 0x4A78EE, 0x4AE5A5, 0x4A797E, "City_sum_buildings_naval_power_for_zoc", "" +define, 0x5BE9E0, 0x5CD600, 0x5BE6F0, "Unit_count_contained_units", "int (__fastcall *) (Unit * this)" +repl call, 0x4B3089, 0x4BA00B, 0x4B3119, "Tile_check_water_to_block_pollution", "" +repl call, 0x4F416E, 0x4FD448, 0x4F422E, "Tile_set_flag_for_eruption_damage", "" +inlead, 0x4AF5D0, 0x4B6590, 0x4AF660, "City_confirm_production_switch", "bool (__fastcall *) (City * this, int edx, int order_type, int order_id)" +define, 0x62AEE0, 0x64DE20, 0x6271F0, "MappedFile_open", "void * (__fastcall *) (MappedFile * this, int edx, char * file_name, int sequential_access)" +repl call, 0x592160, 0x59F790, 0x591E80, "MappedFile_open_to_load_game", "" +define, 0x62AFA0, 0x64DF40, 0x6272B0, "MappedFile_create_file", "void * (__fastcall *) (MappedFile * this, int edx, LPCSTR file_path, unsigned file_size, int is_shared)" +repl call, 0x591CF1, 0x59F321, 0x591A11, "MappedFile_create_file_to_save_game", "" +define, 0x62B0C0, 0x64E0B0, 0x6273D0, "MappedFile_deinit", "void (__fastcall *) (MappedFile * this)" +repl call, 0x592322, 0x59F973, 0x592042, "MappedFile_deinit_after_saving_or_loading", "" +repl call, 0x591D9F, 0x59F3D0, 0x591ABF, "MappedFile_deinit_after_saving_or_loading", "" +repl vptr, 0x6701E4, 0x68D290, 0x6701E4, "Tile_m7_Check_Barbarian_Camp", "bool (__fastcall *) (Tile * this, int edx, int visible_to_civ)" +define, 0x44FBA5, 0x451C45, 0x44FC25, "ADDR_CHECK_BARB_CAMP_TO_DEFEND_RETURN", "int" +inlead, 0x590030, 0x59D690, 0x58FD50, "move_game_data", "int (__cdecl *) (byte * buffer, bool save_else_load)" +inlead, 0x5C14B0, 0x5D0040, 0x5C11C0, "Unit_can_airdrop", "bool (__fastcall *) (Unit * this)" +inlead, 0x5DF8D0, 0x5EF120, 0x5DF800, "City_Improvements_contains", "bool (__fastcall *) (City_Improvements * this, int edx, int id)" +inlead, 0x5DF890, 0x5EF0E0, 0x5DF7C0, "City_Improvements_set", "void (__fastcall *) (City_Improvements * this, int edx, int id, bool add_else_remove)" +repl call, 0x4B47C9, 0x4BB7B9, 0x4B4859, "Leader_has_tech_to_stop_disease", "" +define, 0x5D59E0, 0x5E4E20, 0x5D5910, "Map_change_tile_terrain", "void (__fastcall *) (Map * this, int edx, enum SquareTypes new_terrain_type, int x, int y)" +repl call, 0x461833, 0x463CAF, 0x4618B3, "Map_change_tile_terrain_by_worker", "" +inlead, 0x461470, 0x4638C0, 0x4614F0, "Unit_work_simple_job", "void (__fastcall *) (Unit * this, int edx, int job_id)" +define, 0x5C8B30, 0x5D7A50, 0x5C8840, "Unit_animate_cruise_missile_strike", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +repl call, 0x5B550E, 0x5C3E6F, 0x5B521E, "Unit_play_attack_animation_vs_tile", "" +repl call, 0x5B4C0E, 0x5C355E, 0x5B491E, "Map_compute_neighbor_index_for_cm_strike", "" +define, 0x5FF0E0, 0x614190, 0x5FEFC0, "PCX_Image_do_draw_centered_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len)" +repl call, 0x41AF59, 0x41C067, 0x41AFD9, "PCX_Image_do_draw_cntd_text_for_strat_res", "" +repl call, 0x41AE9F, 0x41BFA9, 0x41AF1F, "Sprite_draw_strat_res_on_city_screen", "" +define, 0x41AE1B, 0x41BF23, 0x41AE9B, "ADDR_MOST_STRAT_RES_ON_CITY_SCREEN", "void *" +inlead, 0x5BEB60, 0x5CD780, 0x5BE870, "Unit_can_heal_at", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5BECE0, 0x5CD900, 0x5BE9F0, "Unit_heal_at_start_of_turn", "void (__fastcall *) (Unit * this)" +define, 0x469590, 0x46BD40, 0x469610, "check_online_skip_flag", "bool (__stdcall *) (int unit_id)" +inlead, 0x448BF0, 0x44AB10, 0x448C70, "Leader_ai_eval_technology", "int (__fastcall *) (Leader * this, int edx, int id, bool param_2, bool param_3)" +inlead, 0x4446C0, 0x4464C0, 0x444740, "Leader_ai_eval_government", "int (__fastcall *) (Leader * this, int edx, int id)" +define, 0x474140, 0x476F70, 0x4741C0, "mp_despawn", "void (__fastcall *) (void * this, int edx, int unit_id, int civ_id_responsible, byte param_3, byte param_4, byte param_5, byte param_6)" +repl call, 0x5B483F, 0x5C3199, 0x5B454F, "Unit_despawn_after_killed_by_nuke", "" +repl call, 0x5B4374, 0x5C2CC4, 0x5B4084, "Unit_despawn_after_killed_by_nuke", "" +repl call, 0x5B4832, 0x5C318C, 0x5B4542, "mp_despawn_after_killed_by_nuke", "" +repl call, 0x5B4367, 0x5C2CB7, 0x5B4077, "mp_despawn_after_killed_by_nuke", "" +define, 0x4B3290, 0x4BA210, 0x4B3320, "City_has_unprotected_improv", "bool (__fastcall *) (City * this, int edx, int id)" +repl call, 0x422BE5, 0x4241A5, 0x422C65, "City_has_unprotected_improv_to_sell", "" +repl call, 0x5BB966, 0x5CA4B6, 0x5BB676, "UnitType_has_detector_ability_for_vis_check", "" +repl call, 0x5BB938, 0x5CA47F, 0x5BB648, "UnitType_has_detector_ability_for_vis_check", "" +repl call, 0x0FF, 0x5CA49B, 0x0FF, "UnitType_has_detector_ability_for_vis_check", "" +inlead, 0x5C33A0, 0x5D1FD0, 0x5C30B0, "Unit_check_airdrop_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C3C80, 0x5D28B0, 0x5C3990, "Unit_find_telepad_on_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y, bool show_selection_popup, Unit ** out_unit_telepad)" +inlead, 0x44B870, 0x44D840, 0x44B8F0, "Unit_ai_eval_airdrop_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C3460, 0x5D2090, 0x5C3170, "Unit_check_airlift_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C4F60, 0x5D3C40, 0x5C4C70, "Unit_can_airlift", "bool (__fastcall *) (Unit * this)" +inlead, 0x5C5040, 0x5D3D20, 0x5C4D50, "Unit_airlift", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +repl call, 0x450C9C, 0x452D98, 0x450D1C, "City_count_airports_for_ai_airlift_target", "" +repl call, 0x452A3A, 0x454B5F, 0x452ABA, "City_count_airports_for_ai_airlift_target", "" +inlead, 0x44F040, 0x4510E0, 0x44F0C0, "Unit_ai_go_to_capital", "bool (__fastcall *) (Unit * this)" +inlead, 0x5C3900, 0x5D2540, 0x5C3610, "Unit_check_rebase_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C3860, 0x5D24A0, 0x5C3570, "Unit_is_in_rebase_range", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +define, 0x5C71C0, 0x5D6060, 0x5C6ED0, "Unit_rebase", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +define, 0x5E6D20, 0x5F6580, 0x5E6C50, "diff_to_neighbor_index", "int (__cdecl *) (int dx, int dy, int lim)" +repl call, 0x421060, 0x4225BA, 0x4210E0, "Map_compute_ni_for_work_area", "" +repl vptr, 0x670190, 0x68D240, 0x670190, "Map_m28_find_cnter_neigh_point_for_work_area", "int (__fastcall *) (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim)" +define, 0x4C538E, 0x4CCC47, 0x4C53AE, "ADDR_FIND_CENTER_NP_SPOTLIGHT_RET", "int" +define, 0x4DF9E0, 0x4E8390, 0x4DFAA0, "Main_Screen_Form_bring_tile_into_view", "void (__fastcall *) (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5)" +repl call, 0x421853, 0x422DC1, 0x4218D3, "Main_Screen_Form_bring_cnter_view_city_focus", "" +repl call, 0x41BBB1, 0x41CD89, 0x41BC31, "Main_Screen_Form_bring_cnter_view_city_arrow", "" +repl call, 0x41BDB5, 0x41CFCD, 0x41BE35, "Main_Screen_Form_bring_cnter_view_city_arrow", "" +define, 0x4BBC80, 0x4C32D0, 0x4BBD10, "City_stop_working_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" +define, 0x4BB6F0, 0x4C2D50, 0x4BB780, "City_start_working_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" +repl call, 0x4ADA69, 0x4B4A51, 0x4ADAF9, "ni_to_diff_for_work_area", "" +repl call, 0x4ADAF4, 0x4B4AD8, 0x4ADB84, "ni_to_diff_for_work_area", "" +ext walup, 0x4ADB6F, 0x4B4B53, 0x4ADBFF, "", "" +repl call, 0x4AE49F, 0x4B5485, 0x4AE52F, "ni_to_diff_for_work_area", "" +ext walup, 0x4AE525, 0x4B550B, 0x4AE5B5, "", "" +repl call, 0x4AE7C2, 0x4B57A1, 0x4AE852, "ni_to_diff_for_work_area", "" +define, 0x4B0470, 0x4B7430, 0x4B0500, "City_add_or_remove_tile_yield", "void (__fastcall *) (City * this, int edx, int neighbor_index, bool add_else_remove)" +repl call, 0x4AE831, 0x4B5806, 0x4AE8C1, "City_add_or_remove_tile_yield_conv_ni", "" +ext walup, 0x4AE842, 0x4B580F, 0x4AE8D2, "", "" +repl call, 0x4AEF35, 0x4B5F13, 0x4AEFC5, "ni_to_diff_for_work_area", "" +repl call, 0x4AEFAF, 0x4B5F83, 0x4AF03F, "ni_to_diff_for_work_area", "" +ext walup, 0x4AF034, 0x4B5FFF, 0x4AF0C4, "", "" +ext walup, 0x4AF0CE, 0x4B6099, 0x4AF15E, "", "" +repl call, 0x4AF355, 0x4B631E, 0x4AF3E5, "ni_to_diff_for_work_area", "" +ext walup, 0x4AF3D7, 0x4B63A0, 0x4AF467, "", "" +repl call, 0x4AF4F6, 0x4B64B9, 0x4AF586, "ni_to_diff_for_work_area", "" +ext walup, 0x4AF5A6, 0x4B656B, 0x4AF636, "", "" +repl call, 0x4B0F2D, 0x4B7EDD, 0x4B0FBD, "ni_to_diff_for_work_area", "" +repl call, 0x4B0FC3, 0x4B7F73, 0x4B1053, "ni_to_diff_for_work_area", "" +ext walup, 0x4B1047, 0x4B7FF7, 0x4B10D7, "", "" +repl call, 0x4B2414, 0x4B93AD, 0x4B24A4, "ni_to_diff_for_work_area", "" +repl call, 0x4B247D, 0x4B9412, 0x4B250D, "City_add_or_remove_tile_yield_conv_ni", "" +ext walup, 0x4B2490, 0x4B941B, 0x4B2520, "", "" +define, 0x4C2680, 0x4C9EB0, 0x4C26A0, "City_is_neighboring_tile_in_area", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" +repl call, 0x4B260C, 0x4B9593, 0x4B269C, "City_is_neighboring_tile_in_area_conv_ni", "" +repl call, 0x4B261A, 0x4B95A1, 0x4B26AA, "City_add_or_remove_tile_yield_conv_ni", "" +ext walup, 0x4B2623, 0x4B95AA, 0x4B26B3, "", "" +repl call, 0x4BA09E, 0x4C170E, 0x4BA12E, "ni_to_diff_for_work_area", "" +repl call, 0x4BA124, 0x4C1790, 0x4BA1B4, "ni_to_diff_for_work_area", "" +ext walup, 0x4BA19E, 0x4C180A, 0x4BA22E, "", "" +repl call, 0x435459, 0x436F39, 0x4354D9, "ni_to_diff_for_work_area", "" +ext walup, 0x43550D, 0x436FED, 0x43558D, "", "" +repl call, 0x43688D, 0x4382FD, 0x43690D, "ni_to_diff_for_work_area", "" +ext walup, 0x436988, 0x4383F8, 0x436A08, "", "" +inlead, 0x4BB4D0, 0x4C2B20, 0x4BB560, "City_controls_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index, bool consider_enemy_units)" +repl call, 0x43564F, 0x43712B, 0x4356CF, "City_controls_tile_conv_ni", "" +repl call, 0x435667, 0x437143, 0x4356E7, "ni_to_diff_for_work_area", "" +repl call, 0x4356E3, 0x4371B9, 0x435763, "City_stop_working_tile_conv_ni", "" +ext walup, 0x4356F6, 0x4371C2, 0x435776, "", "" +repl call, 0x435729, 0x4371F1, 0x4357A9, "ni_to_diff_for_work_area", "" +repl call, 0x4357A1, 0x437269, 0x435821, "City_controls_tile_conv_ni", "" +ext walup, 0x4357D7, 0x43728F, 0x435857, "", "" +repl call, 0x4357E8, 0x4372A0, 0x435868, "City_start_working_tile_conv_ni", "" +repl call, 0x435895, 0x43733F, 0x435915, "ni_to_diff_for_work_area", "" +repl call, 0x435925, 0x4373D1, 0x4359A5, "City_controls_tile_conv_ni", "" +ext walup, 0x43595B, 0x4373F7, 0x4359DB, "", "" +repl call, 0x43597C, 0x437418, 0x4359FC, "ni_to_diff_for_work_area", "" +repl call, 0x435A91, 0x43752D, 0x435B11, "City_start_working_tile_conv_ni", "" +repl call, 0x5BD837, 0x5CC412, 0x5BD547, "Map_compute_ni_for_work_area", "" +repl vptr, 0x66DCB8, 0x68AD9C, 0x66DCB8, "City_find_best_tile_to_work", "int (__fastcall *) (City * this, int edx, Unit * worker, bool param_2)" +repl call, 0x436328, 0x437DBB, 0x4363A8, "ni_to_diff_for_work_area", "" +ext walup, 0x436805, 0x438273, 0x436885, "", "" +repl call, 0x420CC5, 0x422219, 0x420D45, "ni_to_diff_for_work_area", "" +repl call, 0x420DD7, 0x422327, 0x420E57, "ni_to_diff_for_work_area", "" +ext walup, 0x420F05, 0x422466, 0x420F85, "", "" +repl call, 0x420F3A, 0x42249A, 0x420FBA, "ni_to_diff_for_work_area", "" +ext walup, 0x421182, 0x4226D7, 0x421202, "", "" +repl call, 0x4AFCE0, 0x4B6C9C, 0x4AFD70, "City_is_neighboring_tile_in_area_conv_ni", "" +repl call, 0x4AFCEE, 0x4B6CAA, 0x4AFD7E, "City_add_or_remove_tile_yield_conv_ni", "" +ext walup, 0x4AFCF7, 0x4B6CB3, 0x4AFD87, "", "" +repl call, 0x4BA663, 0x4C1CC2, 0x4BA6F3, "City_is_neighboring_tile_in_area_conv_ni", "" +repl call, 0x4BA671, 0x4C1CD0, 0x4BA701, "City_add_or_remove_tile_yield_conv_ni", "" +ext walup, 0x4BA67A, 0x4C1CD9, 0x4BA70A, "", "" +repl call, 0x42053D, 0x421A1D, 0x4205BD, "Map_compute_ni_for_work_area", "" +repl call, 0x435D78, 0x437802, 0x435DF8, "Map_compute_ni_for_work_area", "" +repl call, 0x5DA3B6, 0x5E9925, 0x5DA2E6, "Map_compute_ni_for_work_area", "" +repl vptr, 0x66DCAC, 0x68AD90, 0x66DCAC, "City_find_min_value_tile", "int (__fastcall *) (City * this)" +repl call, 0x420ECD, 0x422426, 0x420F4D, "Sprite_draw_already_worked_tile_img", "" +repl call, 0x420668, 0x421B48, 0x4206E8, "Map_compute_ni_for_work_area", "" +define, 0x420672, 0x421B52, 0x4206F2, "ADDR_REDUNDANT_CHECK_ON_WORK_AREA_HOVER", "byte *" +repl call, 0x5668EE, 0x572C9B, 0x56689E, "Map_compute_ni_for_work_area", "" +define, 0x420547, 0x421A27, 0x4205C7, "ADDR_CITY_FORM_LEFT_CLICK_JUMP", "byte *" +define, 0x4BB4EB, 0x4C2B3C, 0x4BB57B, "ADDR_CONTROLS_TILE_JUMP", "byte *" +repl call, 0x5DA4D1, 0x5E9A48, 0x5DA401, "ni_to_diff_for_work_area", "" +ext walup, 0x5DA555, 0x5E9ACC, 0x5DA485, "", "" +repl call, 0x4C0309, 0x4C78FE, 0x4C0399, "ni_to_diff_for_work_area", "" +ext walup, 0x4C03EA, 0x4C79D9, 0x4C047A, "", "" +repl call, 0x442603, 0x4443D2, 0x442683, "Tile_m43_Get_field_30_for_city_loc_eval", "" +repl call, 0x4427B9, 0x444585, 0x442839, "Tile_m43_Get_field_30_for_city_loc_eval", "" +repl call, 0x4B2FC1, 0x4B9F41, 0x4B3051, "rand_int_to_place_pollution", "" +repl call, 0x4B2FF4, 0x4B9F76, 0x4B3084, "ni_to_diff_for_work_area", "" +define, 0x4B2FEB, 0x4B9F6E, 0x4B307B, "ADDR_SPAWN_POLLUTION_MOD", "byte *" +ext walup, 0x4B309F, 0x4BA025, 0x4B312F, "", "" +repl call, 0x43535D, 0x436E49, 0x4353DD, "ni_to_diff_for_work_area", "" +repl call, 0x4353CA, 0x436EB6, 0x43544A, "City_controls_tile_conv_ni", "" +ext walup, 0x43540B, 0x436EEF, 0x43548B, "", "" +define, 0x4E3B10, 0x4EC360, 0x4E3BD0, "Main_Screen_Form_tile_to_screen_coords", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int * out_x, int * out_y)" +repl call, 0x420C68, 0x4221BC, 0x420CE8, "Main_Screen_Form_t2s_coords_to_draw_yields", "" +repl call, 0x420887, 0x421D88, 0x420907, "Main_Screen_Form_t2s_coords_to_draw_yields", "" +inlead, 0x420C40, 0x422190, 0x420CC0, "City_Form_draw_yields_on_worked_tiles", "void (__fastcall *) (City_Form * this)" +inlead, 0x420860, 0x421D60, 0x4208E0, "City_Form_draw_highlighted_yields", "bool (__fastcall *) (City_Form * this, int edx, int tile_x, int tile_y, int neighbor_index)" +inlead, 0x420F20, 0x422480, 0x420FA0, "City_Form_draw_border_around_workable_tiles", "void (__fastcall *) (City_Form * this)" +inlead, 0x4229F0, 0x423FA0, 0x422A70, "City_Form_draw_food_income_icons", "void (__fastcall *) (City_Form * this)" +inlead, 0x4BFAB0, 0x4C7070, 0x4BFB40, "City_draw_production_income_icons", "void (__fastcall *) (City * this, int edx, int canvas, int * rect_ptr)" +repl call, 0x4BFBB7, 0x4C7177, 0x4BFC47, "Sprite_draw_production_income_icon", "" +repl call, 0x421095, 0x4225EF, 0x421115, "Main_Screen_Form_t2s_coords_to_draw_yields", "" +repl call, 0x420FC5, 0x422525, 0x421045, "Map_get_tile_for_work_area_drawing", "" +repl call, 0x420DA2, 0x4222F8, 0x420E22, "Map_get_tile_for_work_area_drawing", "" +repl call, 0x5DA3BE, 0x5E992D, 0x5DA2EE, "City_stop_working_polluted_tile", "" +repl vptr, 0x66DCB0, 0x68AD94, 0x66DCB0, "City_manage_by_governor", "void (__fastcall *) (City * this, int edx, bool param_1)" +define, 0x5DA3CC, 0x5E993B, 0x5DA2FC, "ADDR_MANAGE_CITY_AFTER_POLLUTION_RETURN", "int" +define, 0x56D040, 0x5799C0, 0x56CFB0, "find_nearest_city", "City * (__cdecl *) (int tile_x, int tile_y, int owner_id, int continent_id, int ignore_owner_id, int perspective_id, City * ignore_city)" +repl call, 0x438A5B, 0x43A5E6, 0x438ADB, "find_nearest_city_for_ai_alliance_eval", "" +define, 0x9C34EC, 0x9E5CE4, 0x9C34AC, "p_nearest_city_distance", "int *" +define, 0x565400, 0x571790, 0x5653B0, "Leader_bounce_trespassing_units", "void (__fastcall *) (Leader * this, int edx, int against_civ_id)" +inlead, 0x446840, 0x448650, 0x4468C0, "Leader_begin_turn", "void (__fastcall *) (Leader * this)" +repl call, 0x5654AC, 0x571841, 0x56545C, "Unit_is_visible_to_civ_for_bouncing", "" +inlead, 0x5025B0, 0x50C230, 0x502650, "Leader_make_peace", "void (__fastcall *) (Leader * this, int edx, int civ_id)" +inlead, 0x5C5BD0, 0x5D4970, 0x5C58E0, "Unit_can_load", "bool (__fastcall *) (Unit * this, int edx, Unit * passenger)" +repl call, 0x5CDE34, 0x5DCEF4, 0x5CDD54, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x5CDE4C, 0x5DCF0C, 0x5CDD6C, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x5C7774, 0x5D6624, 0x5C7484, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x57F6F4, 0x58C41E, 0x57F454, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x57FF93, 0x58CCA6, 0x57FCF3, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x580486, 0x58D1B5, 0x5801E6, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x464BA9, 0x46715E, 0x464C29, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x46514C, 0x46771C, 0x4651CC, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x465560, 0x467B41, 0x4655E0, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x58067D, 0x58D39A, 0x5803DD, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x565693, 0x571A45, 0x565643, "Leader_count_any_shared_wonders_with_flag", "" +inlead, 0x4BD420, 0x4C4A80, 0x4BD4B0, "City_add_happiness_from_buildings", "void (__fastcall *) (City * this, int edx, int * inout_happiness, int * inout_unhappiness)" +define, 0x4BDDE0, 0x4C5410, 0x4BDE70, "City_count_other_buildings_on_continent", "int (__fastcall *) (City * this, int edx, int improv_id)" +repl call, 0x4BD5F0, 0x4C4C50, 0x4BD680, "City_count_other_cont_happiness_buildings", "" +repl call, 0x5C056D, 0x5CF10D, 0x5C027D, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4ACEFE, 0x4B3ED3, 0x4ACF8E, "Leader_count_any_shared_wonders_with_flag", "" +inlead, 0x562380, 0x56E4F0, 0x562330, "Leader_update_great_library_unlocks", "void (__fastcall *) (Leader * this)" +repl call, 0x562390, 0x56E4FB, 0x562340, "Leader_count_any_shared_wonders_with_flag", "" +define, 0x4B5050, 0x4BC030, 0x4B50E0, "City_can_take_outside_shields", "bool (__fastcall *) (City * this, int edx, int param_1)" +define, 0x56A210, 0x5766B0, 0x56A1C0, "Leader_get_unit_cost", "int (__fastcall *) (Leader * this, int edx, int id, bool ignore_difficulty)" +repl call, 0x4A101C, 0x4A7BDC, 0x4A10AC, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4A10B8, 0x4A7C70, 0x4A1148, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4C0D41, 0x4C8341, 0x4C0DD1, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4C0D87, 0x4C8387, 0x4C0E17, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4C118D, 0x4C8779, 0x4C121D, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4BD95E, 0x4C4FB4, 0x4BD9EE, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4B24E5, 0x4B946C, 0x4B2575, "Leader_count_any_shared_wonders_with_flag", "" +inlead, 0x55A7E0, 0x5666F0, 0x55A790, "Leader_has_wonder_doubling_happiness_from", "bool (__fastcall *) (Leader * this, int edx, int improv_id)" +inlead, 0x56A2A0, 0x576740, 0x56A250, "Leader_can_build_city_improvement", "bool (__fastcall *) (Leader * this, int edx, int i_improv, bool param_2)" +repl call, 0x4BF828, 0x4C6DD8, 0x4BF8B8, "Sprite_draw_citizen_head", "" +repl call, 0x4BF95D, 0x4C6F0D, 0x4BF9ED, "Sprite_draw_entertainer_yield_icon", "" +repl call, 0x4BF912, 0x4C6EC2, 0x4BF9A2, "Sprite_draw_scientist_yield_icon", "" +repl call, 0x4BF8C0, 0x4C6E70, 0x4BF950, "Sprite_draw_tax_collector_yield_icon", "" +repl call, 0x4BF9E1, 0x4C6FA1, 0x4BFA71, "Sprite_draw_civil_engineer_yield_icon", "" +repl call, 0x4BFA45, 0x4C7005, 0x4BFAD5, "Sprite_draw_police_officer_yield_icon", "" +inlead, 0x4B9270, 0x4C08E0, 0x4B9300, "City_add_building_if_done", "void (__fastcall *) (City * this)" +define, 0x9C34E4, 0x9E5CDC, 0x9C34A4, "p_zoom_to_city_after_update", "bool *" +define, 0x5812BA, 0x58DFE7, 0x58101A, "ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN", "byte *" +inlead, 0x4BFD40, 0x4C7300, 0x4BFDD0, "City_get_turns_to_build", "int (__fastcall *) (City * this, int edx, int order_type, int order_id, bool param_3)" +repl call, 0x4C06C0, 0x4C7C80, 0x4C0750, "City_can_build_upgrade_type", "" +define, 0x4C1F80, 0x4C96B0, 0x4C2010, "Hash_Table_look_up", "bool (__fastcall *) (Hash_Table * this, int edx, int key, int * out_value)" +inlead, 0x557720, 0x563530, 0x5576D0, "Main_GUI_position_elements", "void (__fastcall *) (Main_GUI * this)" +define, 0x5FE8A0, 0x613550, 0x5FE780, "PCX_Image_get_text_line_height", "int (__fastcall *) (PCX_Image * this)" +repl vptr, 0x66AFF0, 0x6880F0, 0x66AFF0, "Civilopedia_Article_m01_Draw_GCON_or_RACE", "void (__fastcall *) (Civilopedia_Article * this)" +repl vptr, 0x66AFA8, 0x6880A8, 0x66AFA8, "Civilopedia_Article_m01_Draw_UNIT", "void (__fastcall *) (Civilopedia_Article * this)" +repl call, 0x5FF8B5, 0X614B5D, 0x5FF795, "PCX_Image_do_draw_centered_text_in_wrap_func", "" +repl call, 0x5FF7E0, 0x614A5F, 0x5FF6C0, "PCX_Image_draw_text_in_wrap_func", "" +repl call, 0x0FF, 0x614A7A, 0x0FF, "PCX_Image_draw_text_no_len_in_wrap_func", "" +repl vptr, 0x66B1B8, 0x6882B8, 0x66B1B8, "Civilopedia_Form_m68_Show_Dialog", "int (__fastcall *) (Civilopedia_Form * this, int edx, int param_1, void * param_2, void * param_3)" +repl vptr, 0x66B17C, 0x68827C, 0x66B17C, "Civilopedia_Form_m53_On_Control_Click", "void (__fastcall *) (Civilopedia_Form * this, int edx, CivilopediaControlID control_id)" +repl vptr, 0x66B100, 0x688200, 0x66B100, "Civilopedia_Form_m22_Draw", "void (__fastcall *) (Civilopedia_Form * this)" +repl call, 0x4CC5AA, 0x4D462E, 0x4CC66A, "Button_initialize_civilopedia_description", "" +define, 0x179, 0x17A, 0x179, "LBL_EFFECTS", "int" +define, 0x17A, 0x17B, 0x17A, "LBL_PREVIOUS", "int" +define, 0x128, 0x129, 0x128, "LBL_MORE", "int" +define, 0x537700, 0x541D30, 0x537780, "play_sound_effect", "void (__cdecl *) (int sound_effect)" +repl call, 0x578CD9, 0x585DF3, 0x578C49, "Tile_check_water_for_navigator_cell_coloring", "" +inlead, 0x49F5C0, 0x4A6080, 0x49F650, "PopupForm_impl_begin_showing_popup", "int (__fastcall *) (PopupForm * this)" +repl call, 0x49F5CB, 0x4A608B, 0x49F65B, "is_online_game_for_show_popup", "" +define, 0x4EEC40, 0x4F7BE0, 0x4EED00, "Animator_update", "void (__fastcall *) (Animator * this)" +inlead, 0x5C32F0, 0x5D1F20, 0x5C3000, "Unit_ai_can_sacrifice", "bool (__fastcall *) (Unit * this, int edx, bool requires_city)" +inlead, 0x4C5A10, 0x4CD2C0, 0x4C5A30, "Map_Renderer_load_images", "void (__fastcall *) (Map_Renderer *this, int edx)" +define, 0x446114, 0x447EF6, 0x446194, "ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN", "byte *" +define, 0x5663F0, 0x57275D, 0x5663A0, "ADDR_CITY_LIM_CMP_IN_CREATE_CITY", "byte *" +define, 0x4F8D76, 0x5024E6, 0x4F8E36, "ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR", "byte *" +define, 0x4C2420, 0x4C9C10, 0x4C2440, "Buildings_Info_get_age_in_years", "int (__fastcall *) (Buildings_Info * this, int edx, int building_index)" +repl call, 0x4B073C, 0x4B76F0, 0x4B07CC, "Buildings_Info_get_age_in_years_for_tourism", "" +define, 0x501CD0, 0x50B960, 0x501D70, "Leader_make_contact", "void (__fastcall *) (Leader * this, int edx, int civ_id, bool no_online_sync)" +define, 0x5F83E0, 0x608910, 0x5F8310, "Sprite_draw_for_hud", "int (__fastcall *) (Sprite * this, int edx, Sprite * alpha, int param_2, PCX_Image * canvas, int x, int y, int param_6)" +repl call, 0x55374D, 0x55EDF8, 0x5536FD, "Sprite_draw_minimap_frame", "" +define, 0x5792AB, 0x5863CB, 0x57921B, "ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT", "byte *" +repl call, 0x44580E, 0x44760E, 0x44588E, "Unit_has_king_ability_for_find_unsupported", "" +define, 0x4BFD20, 0x4C72E0, 0x4BFDB0, "City_get_turns_to_build_2", "int (__fastcall *) (City * this, int edx, City_Order * order, bool param_2)" +repl call, 0x45FF66, 0x462336, 0x45FFE6, "City_get_turns_to_build_2_for_ai_move_leader", "" +repl call, 0x4600F8, 0x4624E5, 0x460178, "City_get_turns_to_build_2_for_ai_move_leader", "" +define, 0x50FDB3, 0x51A057, 0x50FE53, "ADDR_MAX_TRADABLE_CITY_ID", "byte *" +define, 0x505B21, 0x50F8EB, 0x505BC1, "ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR", "byte *" +define, 0x51000C, 0x51A2AC, 0x5100AC, "ADDR_MAX_TRADABLE_UNIT_ID", "byte *" +define, 0x505B67, 0x50F931, 0x505C07, "ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR", "byte *" +repl vptr, 0x66A52C, 0x687638, 0x66A52C, "Map_Renderer_m09_Draw_Tile_Resources", "void (__fastcall *) (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" +repl vptr, 0x66A538, 0x687644, 0x66A538, "Map_Renderer_m12_Draw_Tile_Buildings", "void (__fastcall *) (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" +inlead, 0x5F61A0, 0x605F50, 0x5F60D0, "Map_Renderer_m11_Draw_Tile_Irrigation", "void (__fastcall *) (Map_Renderer *this, int edx, int visible_to_civ, int tile_x, int tile_y, int param_4, int param_5, int param_6)" +repl call, 0x5F5580, 0x6053D2, 0x5F54B0, "Tile_has_city_or_district", "" +repl call, 0x5F5816, 0x605639, 0x5F5746, "Tile_has_city_or_district", "" +repl call, 0x5F5ABB, 0x6058AF, 0x5F59EB, "Tile_has_city_or_district", "" +repl call, 0x5F5D75, 0x605B31, 0x5F5CA5, "Tile_has_city_or_district", "" +inlead, 0x56CEB0, 0x579830, 0x56CE20, "get_building_defense_bonus_at", "int (__cdecl *) (int x, int y, int param_3)" +define, 0x4B0540, 0x4B7500, 0x4B05D0, "City_update_food_consumption", "void (__fastcall *) (City * this)" +define, 0x5660E0, 0x572460, 0x566090, "Leader_get_food_cost_factor", "int (__fastcall *) (Leader *this, int edx, bool ignore_difficulty)" +define, 0x427540, 0x428C90, 0x4275C0, "City_get_size_class", "int (__fastcall *) (City *this)" +inlead, 0x5B39A0, 0x5C22F0, 0x5B36B0, "is_not_pop_capped_or_starving", "bool (__stdcall *) (City * city)" +inlead, 0x4068E0, 0x406E40, 0x406910, "set_worker_animation", "void (__fastcall *) (void * this, int edx, Unit * unit, int job_id)" +define, 0x5C66D0, 0x5D5520, 0x5C63E0, "get_worker_remaining_turns_to_complete", "int (__fastcall *) (Unit * this, int edx, int job_id)" +inlead, 0x435BA0, 0x437630, 0x435C20, "City_instruct_worker", "bool (__fastcall *) (City * this, int edx, int tile_x, int tile_y, bool param_3, Unit * worker)" +repl vptr, 0x66A528, 0x687634, 0x66A528, "Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp", "void (__fastcall *) (Map_Renderer * this, int edx, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" +repl vptr, 0x66A5D8, 0x6876E4, 0x66A5D8, "Map_Renderer_m52_Draw_Roads", "void (__fastcall *) (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" +repl vptr, 0x66A5D0, 0x6876DC, 0x66A5D0, "Map_Renderer_m52_Draw_Railroads", "void (__fastcall *) (Map_Renderer * this, int edx, int sprite_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" +inlead, 0x5EB580, 0x5FADD0, 0x5EB4B0, "Map_impl_generate", "void (__fastcall *) (Map * this, int edx, int seed, bool is_multiplayer_game, int num_seafaring_civs)" +inlead, 0x4E5580, 0x4EDEB0, 0x4E5640, "Main_Screen_Form_draw_city_hud", "void (__fastcall *) (Main_Screen_Form * this, int edx, PCX_Image * canvas)" +inlead, 0x4BFF80, 0x4C7580, 0x4C0010, "City_can_build_improvement", "bool (__fastcall *) (City * this, int edx, int i_improv, bool apply_strict_rules)" +repl call, 0x5C1C53, 0x5D07F6, 0x5C1963, "Unit_has_army_ability_to_perform_unload", "" +inlead, 0x5C59B0, 0x5D4740, 0x5C56C0, "Unit_disembark", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +define, 0x4A12D0, 0x4A7E80, 0x4A1360, "Fighter_prefer_first_defender_1", "bool (__fastcall *) (Fighter * this, int edx, Unit * first, int first_strength, Unit * second, int second_strength, bool param_5)" +repl call, 0x5C5C82, 0x5D4A23, 0x5C5992, "Unit_has_ability_no_load_non_army_passengers", "" +repl call, 0x5C5C93, 0x5D4A34, 0x5C59A3, "Unit_has_ability_no_load_transport_into_army", "" +inlead, 0x4A1590, 0x4A8140, 0x4A1620, "Fighter_unit_can_defend", "bool (__fastcall *) (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y)" +define, 0x558F70, 0x564E30, 0x558F20, "Leader_is_enemy_unit", "bool (__fastcall *) (Leader * this, int edx, Unit * unit)" +repl call, 0x5C6C5B, 0x5D5AD4, 0x5C696B, "Leader_is_enemy_unit_for_ground_aa", "" +repl call, 0x5BC013, 0x5CAB6A, 0x5BBD23, "Unit_has_army_ability_for_passenger_despawn", "" +define, 0x4A63F4, 0x4AD09E, 0x4A6484, "DESPAWN_TO_FIGHT_1_RETURN", "int" +define, 0x4A6EF7, 0x4ADBAB, 0x4A6F87, "DESPAWN_TO_FIGHT_2_RETURN", "int" +define, 0x4A4436, 0x4AB104, 0x4A44C6, "DESPAWN_TO_DO_BOMBARD_TILE_RETURN", "int" +define, 0x4A31C6, 0x4A9E19, 0x4A3256, "DESPAWN_TO_CRUISE_MISSILE_DEFENDER_RETURN", "int" +define, 0x5659E2, 0x571D83, 0x565992, "DESPAWN_TO_BOUNCE_TRESPASSING_UNITS_RETURN", "int" +define, 0x5B4844, 0x5C319E, 0x5B4554, "DESPAWN_TO_NUKE_DAMAGE_RETURN", "int" +define, 0x5B8462, 0x5C6E78, 0x5B8172, "DESPAWN_TO_DO_CAPTURE_UNITS_RETURN", "int" +define, 0x5BC0A2, 0x5CABF1, 0x5BBDB2, "DESPAWN_RECURSIVE_RETURN", "int" +define, 0x5C7030, 0x5D5EBB, 0x5C6D40, "DESPAWN_TO_TRY_FLYING_OVER_TILE_RETURN", "int" +repl call, 0x5B8D95, 0x5C7801, 0x5B8AA5, "count_units_at_in_try_capturing", "" +define, 0x5F35C2, 0x603442, 0x5F34F2, "ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9", "byte *" +inlead, 0x5F22A0, 0x6020D0, 0x5F21D0, "Map_generate_resources", "void (__fastcall *) (Map * this, int edx, int secondary_seed)" +define, 0x5F2C25, 0x602AF6, 0x5F2B55, "ADDR_RESOURCE_GEN_TILE_COUNT_DIV", "byte *" +repl call, 0x5BFA0C, 0x5CE59E, 0x5BF71C, "rand_int_to_enslave", "" +repl call, 0x52A165, 0x53452B, 0x52A205, "Sprite_draw_espionage_screen_target_civ_bkg", "" +repl call, 0x52A1C1, 0x534587, 0x52A261, "Civilopedia_Article_get_name_for_esp_screen", "" +define, 0xA422F8, 0xA64AF8, 0xA422B8, "p_espionage_form", "Espionage_Form *" +define, 0x680758, 0x69D768, 0x680758, "animation_names", "char **" +define, 0x5BF2FB, 0x5CDE95, 0x5BF00B, "ADDR_SKIP_VICTORY_ANIM_IF_AIR", "byte *" +repl call, 0x5BF4D5, 0x5CE066, 0x5BF1E5, "Animator_play_one_shot_victory_animation", "" +inlead, 0x4DBFC0, 0x4E4990, 0x4DC080, "Main_Screen_Form_assemble_selectable_units", "void (__fastcall *) (Main_Screen_Form * this)" +inlead, 0x4DBA70, 0x4E4440, 0x4DBB30, "Main_Screen_Form_set_selected_unit", "void (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit, bool param_2)" +inlead, 0x4DBD70, 0x4E4740, 0x4DBE30, "Main_Screen_Form_find_next_unit_for_cycling", "Unit * (__fastcall *) (Main_Screen_Form * this)" +define, 0x4EDD40, 0x4F6C90, 0x4EDE00, "UnitIDList_insert_before", "void (__fastcall *) (UnitIDList * this, int edx, int id, UnitIDItem * item)" +define, 0x5BE970, 0x5CD590, 0x5BE680, "Unit_can_cycle_to", "bool (__fastcall *) (Unit * this)" +define, 0x4DABB2, 0x4E3570, 0x4DAC72, "SET_SELECTED_UNIT_TO_ISSUE_WAIT_COMMAND_RET", "int" +repl vptr, 0x66DCD0, 0x68ADB4, 0x66DCD0, "City_m22", "void (__fastcall *) (City * this, int edx, bool param_1)" +define, 0x4B95D7, 0x4C0C43, 0x4B9667, "CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_1", "int" +define, 0x4B96C9, 0x4C0D35, 0x4B9759, "CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_2", "int" +define, 0x4B90D6, 0x4C0743, 0x4B9166, "CITY_M22_TO_SPAWN_UNIT_IF_DONE_RETURN", "int" +inlead, 0x5B6CE0, 0x5C5670, 0x5B69F0, "Unit_do_capture_units", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, int owner_civ_id)" +define, 0xA38C18, 0xA5B418, 0xA38BD8, "p_advisor_internal_form", "Advisor_Internal_Form *" +repl call, 0x51DC54, 0x527A41, 0x51DCF4, "PCX_Image_process_dom_adv_turn_count_text", "" +define, 0x4B1205, 0x4B81B5, 0x4B1295, "ADDR_CORRUPTION_CAPITAL_CHECK", "byte *" +define, 0x4B12C0, 0x4B8272, 0x4B1350, "ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT", "byte *" +define, 0xCCF76C, 0xCF1DC4, 0xCCF724, "p_code_page", "unsigned *" +define, 0x4ED5F0, 0x4F6520, 0x4ED6B0, "MenuUnitList_get_length", "int (__fastcall *) (MenuUnitList * this)" +repl call, 0x4E8BD4, 0x4F1895, 0x4E8C94, "MenuUnitList_get_length_before_sorting", "" +define, 0x4E7E00, 0x4F08C0, 0x4E7EC0, "MenuUnitItem_should_appear_after", "bool (__fastcall *) (MenuUnitItem * this, int edx, MenuUnitItem * other)" +define, 0xA52B6C, 0xA75364, 0xA52B2C, "p_allow_ai_patrol", "bool *" +define, 0x5F1F50, 0x601D30, 0x5F1E80, "Map_finalize_params", "void (__fastcall *) (Map * this)" +repl call, 0x5D1888, 0x5E0B0E, 0x5D17B8, "Map_finalize_params_for_scenario_map", "" +define, 518, 519, 518, "LBL_NO_BARBARIANS", "int" +define, 545, 546, 545, "LBL_RANDOM_BARBS", "int" +define, 0x4BA230, 0x4C18A0, 0x4BA2C0, "City_remove_population", "void (__fastcall *) (City * this, int edx, int num_pops, int race_id, char param_3)" +define, 0x4AE280, 0x4B5260, 0x4AE310, "City_get_largest_adjacent_sea", "int (__fastcall *) (City * this)" +repl call, 0x4C008E, 0x4C7686, 0x4C011E, "City_get_largest_adjacent_sea_within_work_area", "" +repl call, 0x4C010F, 0x4C7707, 0x4C019F, "Map_impl_has_fresh_water_within_work_area", "" +repl call, 0x4C0173, 0x4C776C, 0x4C0203, "Map_impl_is_near_river_within_work_area", "" +repl call, 0x4C01AF, 0x4C77A8, 0x4C023F, "Map_impl_is_near_river_within_work_area", "" +repl call, 0x4C01CF, 0x4C77C8, 0x4C025F, "Map_impl_is_near_lake_within_work_area", "" +inlead, 0x458120, 0x45A2E0, 0x4581A0, "Unit_ai_move_naval_power_unit", "void (__fastcall *) (Unit * this)" +inlead, 0x45A170, 0x45C380, 0x45A1F0, "Unit_ai_move_naval_transport", "void (__fastcall *) (Unit * this)" +inlead, 0x460620, 0x462A20, 0x4606A0, "Unit_ai_move_naval_missile_transport", "void (__fastcall *) (Unit * this)" +inlead, 0x44C130, 0x44E110, 0x44C1B0, "Unit_ai_eval_pillage_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x456840, 0x458A50, 0x4568C0, "Unit_ai_move_air_bombard_unit", "void (__fastcall *) (Unit * this)" +inlead, 0x4579E0, 0x459BB0, 0x457A60, "Unit_ai_move_air_defense_unit", "void (__fastcall *) (Unit * this)" +inlead, 0x459CE0, 0x45BF00, 0x459D60, "Unit_ai_move_air_transport", "void (__fastcall *) (Unit * this)" +define, 0x5C1920, 0x5D04B0, 0x5C1630, "Unit_airdrop", "void (__fastcall *) (Unit * this, int edx, int x, int y)" +repl call, 0x4C0D87, 0x4C8387, 0x4C0E17, "Leader_count_wonders_with_flag_ignore_great_wall", "" +repl call, 0x5D3D67, 0x5E30FC, 0x5D3C97, "Tile_has_colony_ignore_extraterritorial", "" +inlead, 0x440100, 0x441ED0, 0x440180, "Leader_get_attitude_toward", "int (__fastcall *) (Leader * this, int edx, int civ_id, int param_2)" +inlead, 0x5D7080, 0x5E64E0, 0x5D6FB0, "Map_check_colony_location", "int (__fastcall *) (Map * this, int edx, int tile_x, int tile_y, int civ_id)" +inlead, 0x5BCE60, 0x5CBA10, 0x5BCB70, "Unit_select_army_member_for_combat", "Unit * (__fastcall *) (Unit * this, int edx, int param_1, char param_2)" +inlead, 0x44C340, 0x44E330, 0x44C3C0, "Unit_ai_eval_bombard_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, int param_3)" +define, 0x5CD770, 0x5DC720, 0x5CD690, "UnitIDList_insert_after", "void (__fastcall *) (UnitIDList * this, int edx, int id, UnitIDItem * item)" +repl call, 0x5BBBA6, 0x5CA70C, 0x5BB8B6, "UnitIDList_insert_after_init", "" +define, 0x5BCC90, 0x5CB840, 0x5BC9A0, "Unit_load_into_army", "void (__fastcall *) (Unit * this, int edx, Unit * loadee)" +repl call, 0x5B9FEC, 0x5C8AB3, 0x5B9CFC, "Unit_load_into_army_after_move_to_adj_tile", "" +define, 0x5FF750, 0x6149E0, 0x5FF630, "PCX_Image_draw_and_wrap_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int width)" +repl call, 0x4D5283, 0x4DDA46, 0x4D5343, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +repl call, 0x4D52EA, 0x4DDAAE, 0x4D53AA, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +repl call, 0x4D5340, 0x4DDB05, 0x4D5400, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +repl call, 0x4D5396, 0x4DDB5C, 0x4D5456, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +repl call, 0x4D5400, 0x4DDBC5, 0x4D54C0, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +repl call, 0x4D5464, 0x4DDC29, 0x4D5524, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +define, 0x1A5, 0x1A6, 0x1A5, "LBL_OPERATIONAL_RANGE", "int" +define, 0x4D519C, 0x4DD953, 0x4D525C, "ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS", "byte *" +define, 0x1A8, 0x1A9, 0x1A8, "LBL_BOMBARD_RANGE", "int" +ignore, 0x5FC710, 0x0, 0x0, "PCX_Image_create_and_init_jgl_image", "int (__fastcall *) (PCX_Image * this, int edx, int width, int height, int bit_depth, int param_4, int param_5, int param_6)" +ignore, 0x5FCC50, 0x0, 0x0, "PCX_Image_draw_region_to_location", "void (__fastcall *) (PCX_Image * this, int edx, PCX_Image * canvas, int src_x, int src_y, int dest_x, int dest_y, int width, int height)" +ignore, 0x600050, 0x0, 0x0, "PCX_Image_fill", "void (__fastcall *) (PCX_Image * this, int edx, int color)" +ignore, 0x5FFF10, 0x0, 0x0, "PCX_Image_set_color_table", "int (__fastcall *) (PCX_Image * this, int edx, PCX_Color_Table * color_table)" +ignore, 0x4507B0, 0x452860, 0x0, "Unit_ai_move_offensive_unit", "void (__fastcall *) (Unit * this)" +ignore, 0x558F70, 0x0, 0x0, "Leader_is_enemy_unit", "char (__fastcall *) (Leader * this, int edx, Unit * unit)" +ignore, 0x4BFD40, 0x0, 0x0, "City_get_turns_to_build", "int (__fastcall *) (City * this, int edx, int order_type, int order_id, char param_3)" +ignore, 0x4E3D90, 0x0, 0x0, "Main_Screen_Form_is_unit_hidden_from_player", "bool (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit)" +ignore, 0x4E8850, 0x4F14E0, 0x4E8910, "Main_Screen_Form_open_right_click_unit_menu", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" +ignore, 0x5CCBB0, 0x0, 0x0, "Unit_can_pass_between", "PassBetweenValidity (__fastcall *) (Unit * this, int edx, int from_x, int from_y, int to_x, int to_y, byte param_5)" +ignore, 0x452510, 0x454600, 0x452590, "ai_move_defensive_unit", "void (__fastcall *) (Unit * this)" +ignore, 0x5E78E0, 0x5F7130, 0x0, "General_load", "void (__fastcall *) (General * this, int edx, byte ** buffer)" +ignore, 0x5E7020, 0x5F6870, 0x0, "General_clear", "void (__fastcall *) (General * this)" +ignore, 0x605010, 0x61C6A0, 0x604F00, "Base_Form_impl_m01_Show_Enabled", "void (__fastcall *) (Base_Form * this, int edx, byte flags)" +ignore, 0x74AF60, 0x0, 0x0, "p_sync_object", "void *" +ignore, 0x5C0E20, 0x5CF9C0, 0x5C0B30, "Unit_begin_bombarding_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y)" +ignore, 0x57F623, 0x58C352, 0x57F383, "ADDR_SUB_BUG_PATCH", "void *" +define, 0xCC2BB0, 0xCE54BC, 0xCC2B70, "p_got_leader_gender", "int *" +ignore, 0x49D070, 0x4A3AF0, 0x49D100, "Advisor_GUI_open", "void (__fastcall *) (Advisor_GUI * this, int edx, AdvisorKind kind)" +ignore, 0x4BF660, 0x4C6C10, 0x4BF6F0, "City_draw_citizens", "void (__fastcall *) (City * this, int edx, PCX_Image * canvas, RECT * rect, char param_3)" +ignore, 0x4B9F60, 0x4C15D0, 0x4B9FF0, "City_add_population", "void (__fastcall *) (City * this, int edx, int num, int race_id)" +ignore, 0x670234, 0x68D2E0, 0x670234, "Tile_m27_Check_Shield_Bonus", "bool (__fastcall *) (Tile * this)" +ignore, 0x5f3448, 0x6032DF, 0x5F3378, "CHECK_SHIELD_BONUS_TO_CAN_SPAWN_RES_RETURN", "int" + diff --git a/correlator/CLAUDE.md b/correlator/CLAUDE.md index d75c43b7..9488ead0 100644 --- a/correlator/CLAUDE.md +++ b/correlator/CLAUDE.md @@ -1,100 +1,100 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Codebase Overview - -This is the **correlator** subdirectory of the C3X project - a Python tool designed to correlate functions between different versions of the Civilization III: Conquests executable (GOG vs Steam versions). The correlator helps with reverse engineering by matching functions across different builds using multiple similarity metrics. - -### Main Components - -- **correlator.py**: Primary Python script that analyzes exported function data from Ghidra -- **gog.json** & **steam.json**: Large JSON files (90MB+) containing function exports from Ghidra analysis -- Located within the larger C3X project, which is a comprehensive mod for Civilization III: Conquests - -## How to Run - -### Basic Function Lookup -```bash -python correlator.py -``` -Example: `python correlator.py 00100400` - -### Test Mode (Validate Similarity Algorithm) -```bash -python correlator.py --test -``` - -### Address Analysis Mode -```bash -python correlator.py --analyze -``` -Analyzes address differences between functions with identical names in both executables. - -### Custom Similarity Weights -```bash -python correlator.py
-python correlator.py --test -``` -Examples: -- `python correlator.py 00100400 0.4 0.3 0.1 0.2` -- `python correlator.py --test 0.4 0.3 0.1 0.2` - -## Core Architecture - -### Input Data Format -The tool expects JSON files exported from Ghidra containing function metadata: -- `name`: Function name (real names vs auto-generated "FUN_" names) -- `address`: Memory address as hex string -- `raw_bytes`: Array of function bytecode -- `disassembly`: Array of instruction objects with addresses and instruction strings -- `reference_count`: Number of references to the function - -### Similarity Algorithm -The correlator uses a weighted combination of four metrics: -- **Size similarity**: Based on raw byte count (default weight: 0.35) -- **Reference similarity**: Based on reference count (default weight: 0.27) -- **Address similarity**: Based on address proximity (default weight: 0.03) -- **Opcode similarity**: Based on instruction pattern matching using n-grams (default weight: 0.35) - -### Key Functions -- `find_most_similar_function()`: Core matching algorithm -- `test_name_matching()`: Validation using functions with identical real names -- `load_ghidra_export()`: JSON data loader with feature preprocessing -- `analyze_address_differences()`: Address offset analysis -- `calculate_opcode_similarity()`: Instruction pattern matching using 2-grams and 3-grams - -### Performance Optimizations -- **Opcode preprocessing**: N-grams are precomputed during JSON loading to avoid repeated calculations -- **Progress reporting**: Shows preprocessing progress for large datasets -- **Cached features**: Stores `_bigrams` and `_trigrams` sets in function objects - -## Context - Parent C3X Project - -This correlator is part of the larger C3X mod project, which: -- Modifies the Civilization III: Conquests executable -- Uses TCC (Tiny C Compiler) for code injection -- Requires reverse engineering to match functions across game versions -- The correlator specifically helps identify corresponding functions between GOG and Steam builds - -## Dependencies - -- Python 3 (standard library only - json, sys, os, typing, collections) -- No external packages required -- Requires pre-generated JSON exports from Ghidra analysis - -## Usage Notes - -- JSON files are extremely large (90MB+) - initial loading includes preprocessing that takes 10-30 seconds -- Test mode validates the similarity algorithm against functions with identical real names (~82% accuracy with default weights) -- Address lookups are case-insensitive and handle "0x" prefixes -- The tool normalizes addresses by converting to integers to ignore leading zeros -- Real function names exclude auto-generated patterns: "FUN_", "thunk_", "Unwind@", "__", "FID_conflict:" -- Address analysis shows average absolute difference of ~86,852 bytes between matching functions - -## Current Performance - -With optimized default weights (0.35/0.27/0.03/0.35), the correlator achieves: -- ~82% correct matches on functions with real names -- Significantly improved accuracy through opcode pattern matching +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Codebase Overview + +This is the **correlator** subdirectory of the C3X project - a Python tool designed to correlate functions between different versions of the Civilization III: Conquests executable (GOG vs Steam versions). The correlator helps with reverse engineering by matching functions across different builds using multiple similarity metrics. + +### Main Components + +- **correlator.py**: Primary Python script that analyzes exported function data from Ghidra +- **gog.json** & **steam.json**: Large JSON files (90MB+) containing function exports from Ghidra analysis +- Located within the larger C3X project, which is a comprehensive mod for Civilization III: Conquests + +## How to Run + +### Basic Function Lookup +```bash +python correlator.py +``` +Example: `python correlator.py 00100400` + +### Test Mode (Validate Similarity Algorithm) +```bash +python correlator.py --test +``` + +### Address Analysis Mode +```bash +python correlator.py --analyze +``` +Analyzes address differences between functions with identical names in both executables. + +### Custom Similarity Weights +```bash +python correlator.py
+python correlator.py --test +``` +Examples: +- `python correlator.py 00100400 0.4 0.3 0.1 0.2` +- `python correlator.py --test 0.4 0.3 0.1 0.2` + +## Core Architecture + +### Input Data Format +The tool expects JSON files exported from Ghidra containing function metadata: +- `name`: Function name (real names vs auto-generated "FUN_" names) +- `address`: Memory address as hex string +- `raw_bytes`: Array of function bytecode +- `disassembly`: Array of instruction objects with addresses and instruction strings +- `reference_count`: Number of references to the function + +### Similarity Algorithm +The correlator uses a weighted combination of four metrics: +- **Size similarity**: Based on raw byte count (default weight: 0.35) +- **Reference similarity**: Based on reference count (default weight: 0.27) +- **Address similarity**: Based on address proximity (default weight: 0.03) +- **Opcode similarity**: Based on instruction pattern matching using n-grams (default weight: 0.35) + +### Key Functions +- `find_most_similar_function()`: Core matching algorithm +- `test_name_matching()`: Validation using functions with identical real names +- `load_ghidra_export()`: JSON data loader with feature preprocessing +- `analyze_address_differences()`: Address offset analysis +- `calculate_opcode_similarity()`: Instruction pattern matching using 2-grams and 3-grams + +### Performance Optimizations +- **Opcode preprocessing**: N-grams are precomputed during JSON loading to avoid repeated calculations +- **Progress reporting**: Shows preprocessing progress for large datasets +- **Cached features**: Stores `_bigrams` and `_trigrams` sets in function objects + +## Context - Parent C3X Project + +This correlator is part of the larger C3X mod project, which: +- Modifies the Civilization III: Conquests executable +- Uses TCC (Tiny C Compiler) for code injection +- Requires reverse engineering to match functions across game versions +- The correlator specifically helps identify corresponding functions between GOG and Steam builds + +## Dependencies + +- Python 3 (standard library only - json, sys, os, typing, collections) +- No external packages required +- Requires pre-generated JSON exports from Ghidra analysis + +## Usage Notes + +- JSON files are extremely large (90MB+) - initial loading includes preprocessing that takes 10-30 seconds +- Test mode validates the similarity algorithm against functions with identical real names (~82% accuracy with default weights) +- Address lookups are case-insensitive and handle "0x" prefixes +- The tool normalizes addresses by converting to integers to ignore leading zeros +- Real function names exclude auto-generated patterns: "FUN_", "thunk_", "Unwind@", "__", "FID_conflict:" +- Address analysis shows average absolute difference of ~86,852 bytes between matching functions + +## Current Performance + +With optimized default weights (0.35/0.27/0.03/0.35), the correlator achieves: +- ~82% correct matches on functions with real names +- Significantly improved accuracy through opcode pattern matching - Balanced approach using both structural (size/references) and algorithmic (opcodes) similarity \ No newline at end of file diff --git a/correlator/correlator.py b/correlator/correlator.py index bbe13688..b617ace9 100644 --- a/correlator/correlator.py +++ b/correlator/correlator.py @@ -1,784 +1,784 @@ -#!/usr/bin/env python3 - -import json -import sys -import os -from typing import List, Dict, Any - -def precompute_function_features(functions): - """Precompute expensive features for all functions""" - print(f"Precomputing opcode features for {len(functions)} functions...") - for i, func in enumerate(functions): - if i % 1000 == 0 and i > 0: - print(f" Processed {i}/{len(functions)} functions...") - - opcodes = extract_opcodes(func.get("disassembly", [])) - func['_bigrams'] = set(get_opcode_ngrams(opcodes, 2)) - func['_trigrams'] = set(get_opcode_ngrams(opcodes, 3)) - print(f" Completed preprocessing {len(functions)} functions") - -def load_ghidra_export(filepath: str) -> List[Dict[str, Any]]: - """ - Load function data exported from Ghidra by ExportProgForPython.py - - The expected JSON format is: - [ - { - "name": "function_name", # String: Name of the function - "address": "00100400", # String: Address of function entry point - "raw_bytes": [72, 131, 236, ...], # List[int]: Raw bytes of the function - "disassembly": [ # List[Dict]: Disassembled instructions - { - "address": "00100400", # String: Instruction address - "instruction": "SUB RSP, 0x20" # String: Disassembled instruction - }, - ... - ], - "reference_count": 5 # Int: Number of references to this function - }, - ... - ] - - Args: - filepath: Path to the exported JSON file - - Returns: - List of function data dictionaries - """ - try: - with open(filepath, 'r') as f: - data = json.load(f) - - print(f"Successfully loaded {len(data)} functions from {filepath}") - - # Precompute opcode features - precompute_function_features(data) - - return data - except json.JSONDecodeError: - print(f"Error: {filepath} contains invalid JSON") - return [] - except FileNotFoundError: - print(f"Error: File {filepath} not found") - return [] - -def find_function_by_address(functions, address): - """Find a function by its address, ignoring leading zeros and '0x' prefix""" - # Normalize the input address: remove '0x' prefix and convert to integer - if address.lower().startswith("0x"): - address = address[2:] - # Convert to integer to ignore leading zeros - normalized_address = int(address, 16) - - for function in functions: - func_addr = function["address"] - if func_addr.lower().startswith("0x"): - func_addr = func_addr[2:] - # Convert to integer to ignore leading zeros - func_addr_int = int(func_addr, 16) - - if func_addr_int == normalized_address: - return function - return None - -def calculate_size_similarity(func1, func2): - """Calculate similarity based on function size (number of bytes)""" - size1 = len(func1["raw_bytes"]) - size2 = len(func2["raw_bytes"]) - - # Calculate similarity score (1.0 is perfect match) - if size1 == 0 or size2 == 0: - return 0.0 - - # Use the ratio of the smaller to the larger size - return min(size1, size2) / max(size1, size2) - -def calculate_reference_similarity(func1, func2): - """Calculate similarity based on reference count""" - ref1 = func1["reference_count"] - ref2 = func2["reference_count"] - - # Calculate similarity score (1.0 is perfect match) - if ref1 == 0 and ref2 == 0: - return 1.0 # Both have 0 references, perfect match - elif ref1 == 0 or ref2 == 0: - return 0.0 # One has references, the other doesn't - - # Use the ratio of the smaller to the larger reference count - return min(ref1, ref2) / max(ref1, ref2) - -def extract_opcodes(disassembly): - """Extract just the instruction mnemonics from disassembly""" - if not disassembly: - return [] - return [instr["instruction"].split()[0] for instr in disassembly] - -def get_opcode_ngrams(opcodes, n=2): - """Generate n-grams from opcode sequence""" - if len(opcodes) < n: - return [] - return [tuple(opcodes[i:i+n]) for i in range(len(opcodes)-n+1)] - -def jaccard_similarity(set1, set2): - """Calculate Jaccard similarity between two sets""" - if not set1 and not set2: - return 1.0 - if not set1 or not set2: - return 0.0 - intersection = len(set1 & set2) - union = len(set1 | set2) - return intersection / union - -def calculate_opcode_similarity(func1, func2): - """Calculate similarity based on instruction opcode patterns using precomputed n-grams""" - # Use precomputed n-grams if available, otherwise compute on the fly - bigrams1 = func1.get('_bigrams') - bigrams2 = func2.get('_bigrams') - trigrams1 = func1.get('_trigrams') - trigrams2 = func2.get('_trigrams') - - if bigrams1 is None or bigrams2 is None or trigrams1 is None or trigrams2 is None: - # Fallback to computing on the fly (for backward compatibility) - opcodes1 = extract_opcodes(func1.get("disassembly", [])) - opcodes2 = extract_opcodes(func2.get("disassembly", [])) - - if not opcodes1 and not opcodes2: - return 1.0 - if not opcodes1 or not opcodes2: - return 0.0 - - bigrams1 = set(get_opcode_ngrams(opcodes1, 2)) - bigrams2 = set(get_opcode_ngrams(opcodes2, 2)) - trigrams1 = set(get_opcode_ngrams(opcodes1, 3)) - trigrams2 = set(get_opcode_ngrams(opcodes2, 3)) - - # Calculate similarities using precomputed or computed n-grams - bigram_sim = jaccard_similarity(bigrams1, bigrams2) - trigram_sim = jaccard_similarity(trigrams1, trigrams2) - - # Weight trigrams more heavily as they capture more specific patterns - return (bigram_sim * 0.4) + (trigram_sim * 0.6) - -def calculate_address_similarity(func1, func2, max_diff=86852): - """Calculate similarity based on address proximity""" - addr1 = int(func1["address"], 16) - addr2 = int(func2["address"], 16) - diff = abs(addr1 - addr2) - - # Convert to similarity score (1.0 is perfect match, 0.0 is max_diff or greater) - if diff >= max_diff: - return 0.0 - return 1.0 - (diff / max_diff) - -def calculate_combined_similarity(func1, func2, size_weight=0.35, ref_weight=0.27, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852): - """Calculate weighted combination of size, reference, address, and opcode similarity""" - size_sim = calculate_size_similarity(func1, func2) - ref_sim = calculate_reference_similarity(func1, func2) - addr_sim = calculate_address_similarity(func1, func2, max_addr_diff) - opcode_sim = calculate_opcode_similarity(func1, func2) - - # Apply weights - return (size_sim * size_weight) + (ref_sim * ref_weight) + (addr_sim * addr_weight) + (opcode_sim * opcode_weight) - -def find_most_similar_function(target_function, candidate_functions, size_weight=0.35, ref_weight=0.27, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852): - """Find the most similar function based on weighted combination of size, reference count, address, and opcodes""" - best_matches = [] - best_score = -1 - - # Calculate similarity threshold to consider a match almost identical - SIMILARITY_THRESHOLD = 0.999 - - for candidate in candidate_functions: - score = calculate_combined_similarity(target_function, candidate, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff) - - # Round to 4 decimal places to avoid floating point comparison issues - score = round(score, 4) - - if score > best_score: - # New best score, clear previous matches - best_score = score - best_matches = [candidate] - elif score == best_score: - # Same score, add to list of matches - best_matches.append(candidate) - - return best_matches, best_score - -def is_real_name(name): - """Check if a function has a real name or is an auto-generated name""" - return name and not any([name.startswith(x) for x in ["FUN_", "thunk_", "Unwind@", "__", "FID_conflict:"]]) - -def find_named_functions(functions): - """Return list of functions with real names (not auto-generated)""" - return [f for f in functions if is_real_name(f["name"])] - -def group_by_name(functions): - """Group functions by name, filtering out duplicates""" - name_groups = {} - for func in functions: - name = func["name"] - if name not in name_groups: - name_groups[name] = [] - name_groups[name].append(func) - - # Only keep names that have a single function - return {name: funcs[0] for name, funcs in name_groups.items() if len(funcs) == 1} - -# Global arrays to store match examples for inspection -correct_matches = [] -incorrect_matches = [] -ambiguous_matches = [] - -def test_name_matching(steam_functions, gog_functions, size_weight, ref_weight, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852, comparison_label="Steam"): - """Test how well our similarity metric matches already-named functions""" - global correct_matches, incorrect_matches, ambiguous_matches - - # Clear previous examples - correct_matches.clear() - incorrect_matches.clear() - ambiguous_matches.clear() - - print(f"Testing name matching between GOG and {comparison_label} with weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") - - # Get named functions from comparison file - named_steam_funcs = find_named_functions(steam_functions) - print(f"Found {len(named_steam_funcs)} named functions in comparison file ({comparison_label})") - - # Group by name, excluding duplicates - steam_name_map = group_by_name(named_steam_funcs) - print(f"After removing duplicates: {len(steam_name_map)} unique named functions") - - # Keep track of total for progress - total = 0 - - # Progress tracking - progress_step = max(1, len(steam_name_map) // 20) # Show progress in ~5% increments - - print(f"\nTesting matches for {len(steam_name_map)} functions...") - - for idx, (name, steam_func) in enumerate(steam_name_map.items()): - # Show progress - if idx % progress_step == 0: - print(f"Progress: {idx}/{len(steam_name_map)} ({idx/len(steam_name_map)*100:.1f}%)") - - # Find most similar functions in GOG - best_matches, similarity_score = find_most_similar_function( - steam_func, - gog_functions, - size_weight=size_weight, - ref_weight=ref_weight, - addr_weight=addr_weight, - opcode_weight=opcode_weight, - max_addr_diff=max_addr_diff - ) - - total += 1 - - # Check if best match has the same name - if len(best_matches) > 1: - # Ambiguous match (multiple with same score) - ambiguous_matches.append({ - 'steam_func': steam_func, - 'gog_matches': best_matches, - 'similarity_score': similarity_score - }) - else: - best_match = best_matches[0] - if best_match["name"] == name: - correct_matches.append({ - 'steam_func': steam_func, - 'gog_match': best_match, - 'similarity_score': similarity_score - }) - else: - incorrect_matches.append({ - 'steam_func': steam_func, - 'gog_match': best_match, - 'similarity_score': similarity_score - }) - - # Print final statistics - print("\nMatching Results:") - print(f"Total functions tested: {total}") - print(f"Correct matches: {len(correct_matches)} ({len(correct_matches)/total*100:.2f}%)") - print(f"Incorrect matches: {len(incorrect_matches)} ({len(incorrect_matches)/total*100:.2f}%)") - print(f"Ambiguous matches: {len(ambiguous_matches)} ({len(ambiguous_matches)/total*100:.2f}%)") - - return len(correct_matches) / total # Return success rate - -def analyze_address_differences(): - """Analyze address differences between functions with identical real names""" - global gog_functions, steam_functions - - if not gog_functions or not steam_functions: - print("Function data not loaded. Run main() first.") - return - - print("Finding functions with identical real names in both executables...") - - # Get functions with real names from both executables - steam_named = {f['name']: f for f in steam_functions if is_real_name(f['name'])} - gog_named = {f['name']: f for f in gog_functions if is_real_name(f['name'])} - - # Find functions that exist in both with identical names - common_names = set(steam_named.keys()) & set(gog_named.keys()) - print(f"Found {len(common_names)} functions with identical real names in both executables") - - if not common_names: - print("No matching named functions found.") - return - - address_diffs = [] - for name in common_names: - steam_func = steam_named[name] - gog_func = gog_named[name] - - steam_addr = int(steam_func['address'], 16) - gog_addr = int(gog_func['address'], 16) - diff = gog_addr - steam_addr - - address_diffs.append({ - 'function_name': name, - 'steam_addr': steam_addr, - 'gog_addr': gog_addr, - 'difference': diff, - 'abs_difference': abs(diff) - }) - - # Sort by absolute difference to see patterns - address_diffs.sort(key=lambda x: x['abs_difference']) - - # Calculate statistics - diffs = [item['abs_difference'] for item in address_diffs] - min_diff = min(diffs) - max_diff = max(diffs) - avg_diff = sum(diffs) / len(diffs) - - # Find most common difference - from collections import Counter - diff_counts = Counter(diffs) - most_common_diff = diff_counts.most_common(1)[0] - - print(f"\nAddress difference statistics:") - print(f" Min difference: 0x{min_diff:08x} ({min_diff})") - print(f" Max difference: 0x{max_diff:08x} ({max_diff})") - print(f" Average difference: 0x{int(avg_diff):08x} ({int(avg_diff)})") - print(f" Most common difference: 0x{most_common_diff[0]:08x} ({most_common_diff[0]}) - appears {most_common_diff[1]} times") - - # Show distribution of differences - print(f"\nTop 10 most common differences:") - for diff, count in diff_counts.most_common(10): - print(f" 0x{diff:08x} ({diff:8d}): {count:3d} functions") - - # Show some examples - print(f"\nFirst 10 examples (sorted by absolute difference):") - for i, item in enumerate(address_diffs[:10]): - print(f" {item['function_name']:30s} Steam: 0x{item['steam_addr']:08x} GOG: 0x{item['gog_addr']:08x} Diff: 0x{item['difference']:08x} (abs: 0x{item['abs_difference']:08x})") - - return address_diffs - -def generate_training_data(): - """Generate training data from functions with known matches and mismatches""" - global gog_functions, steam_functions - - if not gog_functions or not steam_functions: - print("Function data not loaded. Run main() first.") - return [], [] - - print("Generating training data for logistic regression...") - - # Get functions with real names from both executables - steam_named = {f['name']: f for f in steam_functions if is_real_name(f['name'])} - gog_named = {f['name']: f for f in gog_functions if is_real_name(f['name'])} - - # Find functions that exist in both with identical names (positive examples) - common_names = set(steam_named.keys()) & set(gog_named.keys()) - print(f"Found {len(common_names)} positive examples (identical names)") - - features = [] - labels = [] - - # Positive examples: functions with identical names - for name in common_names: - steam_func = steam_named[name] - gog_func = gog_named[name] - - # Calculate all similarity features - size_sim = calculate_size_similarity(steam_func, gog_func) - ref_sim = calculate_reference_similarity(steam_func, gog_func) - addr_sim = calculate_address_similarity(steam_func, gog_func) - opcode_sim = calculate_opcode_similarity(steam_func, gog_func) - - features.append([size_sim, ref_sim, addr_sim, opcode_sim]) - labels.append(1) # Correct match - - # Negative examples: generate mismatches - # For each positive example, find some functions that are NOT matches - print("Generating negative examples...") - import random - random.seed(42) # For reproducibility - - negative_count = 0 - target_negatives = len(common_names) * 2 # 2:1 ratio of negatives to positives - - steam_funcs_list = list(steam_named.values()) - gog_funcs_list = list(gog_named.values()) - - for _ in range(target_negatives): - if negative_count >= target_negatives: - break - - # Pick random functions that don't have the same name - steam_func = random.choice(steam_funcs_list) - gog_func = random.choice(gog_funcs_list) - - # Skip if they actually match - if steam_func['name'] == gog_func['name']: - continue - - # Calculate similarity features - size_sim = calculate_size_similarity(steam_func, gog_func) - ref_sim = calculate_reference_similarity(steam_func, gog_func) - addr_sim = calculate_address_similarity(steam_func, gog_func) - opcode_sim = calculate_opcode_similarity(steam_func, gog_func) - - features.append([size_sim, ref_sim, addr_sim, opcode_sim]) - labels.append(0) # Incorrect match - negative_count += 1 - - print(f"Generated {len([l for l in labels if l == 1])} positive and {len([l for l in labels if l == 0])} negative examples") - return features, labels - -def train_logistic_regression(): - """Train logistic regression model to learn optimal feature weights""" - try: - from sklearn.linear_model import LogisticRegression - from sklearn.model_selection import cross_val_score - from sklearn.preprocessing import StandardScaler - import numpy as np - except ImportError: - print("Error: scikit-learn not available. Install with: pip install scikit-learn") - return None - - # Generate training data - features, labels = generate_training_data() - if not features: - print("No training data generated") - return None - - features = np.array(features) - labels = np.array(labels) - - print(f"Training on {len(features)} examples...") - - # Standardize features (important for logistic regression) - scaler = StandardScaler() - features_scaled = scaler.fit_transform(features) - - # Train logistic regression with L2 regularization - model = LogisticRegression(random_state=42, max_iter=1000) - model.fit(features_scaled, labels) - - # Evaluate with cross-validation - cv_scores = cross_val_score(model, features_scaled, labels, cv=5) - print(f"Cross-validation accuracy: {cv_scores.mean():.3f} (+/- {cv_scores.std() * 2:.3f})") - - # Get feature importance (coefficients) - coefficients = model.coef_[0] - feature_names = ['Size', 'References', 'Address', 'Opcode'] - - print("\nLearned feature coefficients:") - for name, coef in zip(feature_names, coefficients): - print(f" {name}: {coef:.4f}") - - # Convert to normalized weights (positive, sum to 1) - # Take absolute values and normalize - abs_coefficients = np.abs(coefficients) - normalized_weights = abs_coefficients / np.sum(abs_coefficients) - - print("\nNormalized weights for correlator:") - for name, weight in zip(feature_names, normalized_weights): - print(f" {name}: {weight:.3f}") - - print(f"\nSuggested command line:") - print(f"python correlator.py --test {normalized_weights[0]:.3f} {normalized_weights[1]:.3f} {normalized_weights[2]:.3f} {normalized_weights[3]:.3f}") - - return { - 'model': model, - 'scaler': scaler, - 'weights': normalized_weights, - 'coefficients': coefficients, - 'cv_accuracy': cv_scores.mean() - } - -def process_multiple_addresses(addresses, gog_functions, steam_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label="Steam"): - """Process multiple addresses and find matches for each""" - results = [] - - print(f"Processing {len(addresses)} addresses with default weights...") - print(f"Using weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") - print("=" * 80) - - for i, address in enumerate(addresses): - print(f"\n[{i+1}/{len(addresses)}] Processing address: {address}") - print("-" * 40) - - # Find the target function in gog.json - target_function = find_function_by_address(gog_functions, address) - if not target_function: - print(f"No function found at address {address} in gog.json") - results.append({ - 'address': address, - 'found': False, - 'error': f"No function found at address {address}" - }) - continue - - target_size = len(target_function["raw_bytes"]) - print(f"Found target function: {target_function['name']} at {target_function['address']}") - print(f"Function size: {target_size} bytes, References: {target_function['reference_count']}") - - # Find the most similar function in comparison file - best_matches, similarity_score = find_most_similar_function( - target_function, - steam_functions, - size_weight=size_weight, - ref_weight=ref_weight, - addr_weight=addr_weight, - opcode_weight=opcode_weight, - max_addr_diff=max_addr_diff - ) - - print(f"Combined similarity score: {similarity_score:.4f}") - - # Store results - match_data = [] - for match in best_matches: - match_size = len(match['raw_bytes']) - size_sim = calculate_size_similarity(target_function, match) - ref_sim = calculate_reference_similarity(target_function, match) - addr_sim = calculate_address_similarity(target_function, match, max_addr_diff) - opcode_sim = calculate_opcode_similarity(target_function, match) - - match_info = { - 'name': match['name'], - 'address': match['address'], - 'size': match_size, - 'references': match['reference_count'], - 'size_similarity': size_sim, - 'ref_similarity': ref_sim, - 'addr_similarity': addr_sim, - 'opcode_similarity': opcode_sim - } - match_data.append(match_info) - - print(f"Best match in {comparison_label}: {match['name']} at {match['address']}") - print(f" Size: {match_size} bytes (similarity: {size_sim:.4f})") - print(f" References: {match['reference_count']} (similarity: {ref_sim:.4f})") - print(f" Address similarity: {addr_sim:.4f}") - print(f" Opcode similarity: {opcode_sim:.4f}") - - if len(best_matches) > 1: - print(f"WARNING: Found {len(best_matches)} functions with the same similarity score!") - - results.append({ - 'address': address, - 'found': True, - 'target_function': { - 'name': target_function['name'], - 'address': target_function['address'], - 'size': target_size, - 'references': target_function['reference_count'] - }, - 'matches': match_data, - 'similarity_score': similarity_score, - 'match_count': len(best_matches) - }) - - return results - -def main(): - global gog_functions, steam_functions - - # Check for --pcg flag first (before loading files) - use_pcg = "--pcg" in sys.argv - if use_pcg: - # Remove --pcg from argv so it doesn't interfere with other parsing - sys.argv = [arg for arg in sys.argv if arg != "--pcg"] - - # Set default weights - size_weight = 0.35 - ref_weight = 0.27 - addr_weight = 0.03 - opcode_weight = 0.35 - max_addr_diff = 86852 # Average from analysis - - # Load functions from both files - comparison_file = "pcg.json" if use_pcg else "steam.json" - comparison_label = "PCGames.de" if use_pcg else "Steam" - - gog_functions = load_ghidra_export("gog.json") - steam_functions = load_ghidra_export(comparison_file) - - if not gog_functions or not steam_functions: - print("Error loading function data. Exiting.") - sys.exit(1) - - # Check for analysis mode - if len(sys.argv) >= 2 and sys.argv[1] == "--analyze": - analyze_address_differences() - return - - # Check for ML training mode - if len(sys.argv) >= 2 and sys.argv[1] == "--train": - train_logistic_regression() - return - - # Check for list mode - if len(sys.argv) >= 2 and sys.argv[1] == "--list": - if len(sys.argv) < 3: - print("Error: --list requires at least one address") - sys.exit(1) - addresses = sys.argv[2:] - - results = process_multiple_addresses(addresses, gog_functions, steam_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label) - - # Print summary - print("\n" + "=" * 80) - print("SUMMARY") - print("=" * 80) - - found_count = sum(1 for r in results if r['found']) - print(f"Total addresses processed: {len(results)}") - print(f"Functions found: {found_count}") - print(f"Functions not found: {len(results) - found_count}") - - if found_count > 0: - avg_score = sum(r['similarity_score'] for r in results if r['found']) / found_count - print(f"Average similarity score: {avg_score:.4f}") - - ambiguous_count = sum(1 for r in results if r['found'] and r['match_count'] > 1) - if ambiguous_count > 0: - print(f"Ambiguous matches (multiple with same score): {ambiguous_count}") - - return - - # Check for test mode - if len(sys.argv) >= 2 and sys.argv[1] == "--test": - # If weights are provided, use them - if len(sys.argv) >= 4: - try: - size_weight = float(sys.argv[2]) - ref_weight = float(sys.argv[3]) - if len(sys.argv) >= 5: - addr_weight = float(sys.argv[4]) - if len(sys.argv) >= 6: - opcode_weight = float(sys.argv[5]) - # Normalize weights if they don't sum to 1 - total = size_weight + ref_weight + addr_weight + opcode_weight - if total != 1.0: - size_weight /= total - ref_weight /= total - addr_weight /= total - opcode_weight /= total - except ValueError: - print("Error: Weights must be numeric values") - sys.exit(1) - - # Run test mode - test_name_matching(steam_functions, gog_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label) - return - - # Normal mode - lookup a specific function - if len(sys.argv) < 2: - print("Usage:") - print(" python correlator.py [size_weight] [ref_weight] [addr_weight] [opcode_weight] [--pcg]") - print(" python correlator.py --list ... [--pcg]") - print(" python correlator.py --test [size_weight] [ref_weight] [addr_weight] [opcode_weight] [--pcg]") - print(" python correlator.py --analyze [--pcg]") - print(" python correlator.py --train [--pcg]") - print("\nOptions:") - print(" --pcg Use pcg.json (PCGames.de version) instead of steam.json for comparison") - print("\nExamples:") - print(" python correlator.py 00401000") - print(" python correlator.py 00401000 --pcg") - print(" python correlator.py 00401000 0.4 0.3 0.1 0.2") - print(" python correlator.py --list 00401000 00402000 00403000") - print(" python correlator.py --list 00401000 00402000 --pcg") - print(" python correlator.py --test") - print(" python correlator.py --test --pcg") - print(" python correlator.py --test 0.4 0.3 0.1 0.2 --pcg") - print(" python correlator.py --train # Learn optimal weights with ML") - return - - target_address = sys.argv[1] - - # Allow overriding weights through command line - if len(sys.argv) >= 4: - try: - size_weight = float(sys.argv[2]) - ref_weight = float(sys.argv[3]) - if len(sys.argv) >= 5: - addr_weight = float(sys.argv[4]) - if len(sys.argv) >= 6: - opcode_weight = float(sys.argv[5]) - # Normalize weights if they don't sum to 1 - total = size_weight + ref_weight + addr_weight + opcode_weight - if total != 1.0: - size_weight /= total - ref_weight /= total - addr_weight /= total - opcode_weight /= total - except ValueError: - print("Error: Weights must be numeric values") - sys.exit(1) - - # Find the target function in gog.json - target_function = find_function_by_address(gog_functions, target_address) - if not target_function: - print(f"No function found at address {target_address} in gog.json") - sys.exit(1) - - target_size = len(target_function["raw_bytes"]) - print(f"Found target function: {target_function['name']} at {target_function['address']}") - print(f"Function size: {target_size} bytes") - print(f"References: {target_function['reference_count']}") - print(f"Using weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") - - # Find the most similar function in comparison file - best_matches, similarity_score = find_most_similar_function( - target_function, - steam_functions, - size_weight=size_weight, - ref_weight=ref_weight, - addr_weight=addr_weight, - opcode_weight=opcode_weight, - max_addr_diff=max_addr_diff - ) - - print(f"\nBest matches in {comparison_label}:") - print(f"Combined similarity score: {similarity_score:.4f}") - - if len(best_matches) > 1: - print(f"\nWARNING: Found {len(best_matches)} functions with the same similarity score!") - - for i, match in enumerate(best_matches): - match_size = len(match['raw_bytes']) - size_sim = calculate_size_similarity(target_function, match) - ref_sim = calculate_reference_similarity(target_function, match) - addr_sim = calculate_address_similarity(target_function, match, max_addr_diff) - opcode_sim = calculate_opcode_similarity(target_function, match) - - print(f"\nMatch {i+1}:") - print(f"Function: {match['name']} at {match['address']}") - print(f"Size: {match_size} bytes (similarity: {size_sim:.4f})") - print(f"References: {match['reference_count']} (similarity: {ref_sim:.4f})") - print(f"Address similarity: {addr_sim:.4f}") - print(f"Opcode similarity: {opcode_sim:.4f}") - - # Show size difference as percentage - size_diff_pct = abs(target_size - match_size) / target_size * 100 - print(f"Size difference: {abs(target_size - match_size)} bytes ({size_diff_pct:.1f}%)") - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 + +import json +import sys +import os +from typing import List, Dict, Any + +def precompute_function_features(functions): + """Precompute expensive features for all functions""" + print(f"Precomputing opcode features for {len(functions)} functions...") + for i, func in enumerate(functions): + if i % 1000 == 0 and i > 0: + print(f" Processed {i}/{len(functions)} functions...") + + opcodes = extract_opcodes(func.get("disassembly", [])) + func['_bigrams'] = set(get_opcode_ngrams(opcodes, 2)) + func['_trigrams'] = set(get_opcode_ngrams(opcodes, 3)) + print(f" Completed preprocessing {len(functions)} functions") + +def load_ghidra_export(filepath: str) -> List[Dict[str, Any]]: + """ + Load function data exported from Ghidra by ExportProgForPython.py + + The expected JSON format is: + [ + { + "name": "function_name", # String: Name of the function + "address": "00100400", # String: Address of function entry point + "raw_bytes": [72, 131, 236, ...], # List[int]: Raw bytes of the function + "disassembly": [ # List[Dict]: Disassembled instructions + { + "address": "00100400", # String: Instruction address + "instruction": "SUB RSP, 0x20" # String: Disassembled instruction + }, + ... + ], + "reference_count": 5 # Int: Number of references to this function + }, + ... + ] + + Args: + filepath: Path to the exported JSON file + + Returns: + List of function data dictionaries + """ + try: + with open(filepath, 'r') as f: + data = json.load(f) + + print(f"Successfully loaded {len(data)} functions from {filepath}") + + # Precompute opcode features + precompute_function_features(data) + + return data + except json.JSONDecodeError: + print(f"Error: {filepath} contains invalid JSON") + return [] + except FileNotFoundError: + print(f"Error: File {filepath} not found") + return [] + +def find_function_by_address(functions, address): + """Find a function by its address, ignoring leading zeros and '0x' prefix""" + # Normalize the input address: remove '0x' prefix and convert to integer + if address.lower().startswith("0x"): + address = address[2:] + # Convert to integer to ignore leading zeros + normalized_address = int(address, 16) + + for function in functions: + func_addr = function["address"] + if func_addr.lower().startswith("0x"): + func_addr = func_addr[2:] + # Convert to integer to ignore leading zeros + func_addr_int = int(func_addr, 16) + + if func_addr_int == normalized_address: + return function + return None + +def calculate_size_similarity(func1, func2): + """Calculate similarity based on function size (number of bytes)""" + size1 = len(func1["raw_bytes"]) + size2 = len(func2["raw_bytes"]) + + # Calculate similarity score (1.0 is perfect match) + if size1 == 0 or size2 == 0: + return 0.0 + + # Use the ratio of the smaller to the larger size + return min(size1, size2) / max(size1, size2) + +def calculate_reference_similarity(func1, func2): + """Calculate similarity based on reference count""" + ref1 = func1["reference_count"] + ref2 = func2["reference_count"] + + # Calculate similarity score (1.0 is perfect match) + if ref1 == 0 and ref2 == 0: + return 1.0 # Both have 0 references, perfect match + elif ref1 == 0 or ref2 == 0: + return 0.0 # One has references, the other doesn't + + # Use the ratio of the smaller to the larger reference count + return min(ref1, ref2) / max(ref1, ref2) + +def extract_opcodes(disassembly): + """Extract just the instruction mnemonics from disassembly""" + if not disassembly: + return [] + return [instr["instruction"].split()[0] for instr in disassembly] + +def get_opcode_ngrams(opcodes, n=2): + """Generate n-grams from opcode sequence""" + if len(opcodes) < n: + return [] + return [tuple(opcodes[i:i+n]) for i in range(len(opcodes)-n+1)] + +def jaccard_similarity(set1, set2): + """Calculate Jaccard similarity between two sets""" + if not set1 and not set2: + return 1.0 + if not set1 or not set2: + return 0.0 + intersection = len(set1 & set2) + union = len(set1 | set2) + return intersection / union + +def calculate_opcode_similarity(func1, func2): + """Calculate similarity based on instruction opcode patterns using precomputed n-grams""" + # Use precomputed n-grams if available, otherwise compute on the fly + bigrams1 = func1.get('_bigrams') + bigrams2 = func2.get('_bigrams') + trigrams1 = func1.get('_trigrams') + trigrams2 = func2.get('_trigrams') + + if bigrams1 is None or bigrams2 is None or trigrams1 is None or trigrams2 is None: + # Fallback to computing on the fly (for backward compatibility) + opcodes1 = extract_opcodes(func1.get("disassembly", [])) + opcodes2 = extract_opcodes(func2.get("disassembly", [])) + + if not opcodes1 and not opcodes2: + return 1.0 + if not opcodes1 or not opcodes2: + return 0.0 + + bigrams1 = set(get_opcode_ngrams(opcodes1, 2)) + bigrams2 = set(get_opcode_ngrams(opcodes2, 2)) + trigrams1 = set(get_opcode_ngrams(opcodes1, 3)) + trigrams2 = set(get_opcode_ngrams(opcodes2, 3)) + + # Calculate similarities using precomputed or computed n-grams + bigram_sim = jaccard_similarity(bigrams1, bigrams2) + trigram_sim = jaccard_similarity(trigrams1, trigrams2) + + # Weight trigrams more heavily as they capture more specific patterns + return (bigram_sim * 0.4) + (trigram_sim * 0.6) + +def calculate_address_similarity(func1, func2, max_diff=86852): + """Calculate similarity based on address proximity""" + addr1 = int(func1["address"], 16) + addr2 = int(func2["address"], 16) + diff = abs(addr1 - addr2) + + # Convert to similarity score (1.0 is perfect match, 0.0 is max_diff or greater) + if diff >= max_diff: + return 0.0 + return 1.0 - (diff / max_diff) + +def calculate_combined_similarity(func1, func2, size_weight=0.35, ref_weight=0.27, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852): + """Calculate weighted combination of size, reference, address, and opcode similarity""" + size_sim = calculate_size_similarity(func1, func2) + ref_sim = calculate_reference_similarity(func1, func2) + addr_sim = calculate_address_similarity(func1, func2, max_addr_diff) + opcode_sim = calculate_opcode_similarity(func1, func2) + + # Apply weights + return (size_sim * size_weight) + (ref_sim * ref_weight) + (addr_sim * addr_weight) + (opcode_sim * opcode_weight) + +def find_most_similar_function(target_function, candidate_functions, size_weight=0.35, ref_weight=0.27, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852): + """Find the most similar function based on weighted combination of size, reference count, address, and opcodes""" + best_matches = [] + best_score = -1 + + # Calculate similarity threshold to consider a match almost identical + SIMILARITY_THRESHOLD = 0.999 + + for candidate in candidate_functions: + score = calculate_combined_similarity(target_function, candidate, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff) + + # Round to 4 decimal places to avoid floating point comparison issues + score = round(score, 4) + + if score > best_score: + # New best score, clear previous matches + best_score = score + best_matches = [candidate] + elif score == best_score: + # Same score, add to list of matches + best_matches.append(candidate) + + return best_matches, best_score + +def is_real_name(name): + """Check if a function has a real name or is an auto-generated name""" + return name and not any([name.startswith(x) for x in ["FUN_", "thunk_", "Unwind@", "__", "FID_conflict:"]]) + +def find_named_functions(functions): + """Return list of functions with real names (not auto-generated)""" + return [f for f in functions if is_real_name(f["name"])] + +def group_by_name(functions): + """Group functions by name, filtering out duplicates""" + name_groups = {} + for func in functions: + name = func["name"] + if name not in name_groups: + name_groups[name] = [] + name_groups[name].append(func) + + # Only keep names that have a single function + return {name: funcs[0] for name, funcs in name_groups.items() if len(funcs) == 1} + +# Global arrays to store match examples for inspection +correct_matches = [] +incorrect_matches = [] +ambiguous_matches = [] + +def test_name_matching(steam_functions, gog_functions, size_weight, ref_weight, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852, comparison_label="Steam"): + """Test how well our similarity metric matches already-named functions""" + global correct_matches, incorrect_matches, ambiguous_matches + + # Clear previous examples + correct_matches.clear() + incorrect_matches.clear() + ambiguous_matches.clear() + + print(f"Testing name matching between GOG and {comparison_label} with weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") + + # Get named functions from comparison file + named_steam_funcs = find_named_functions(steam_functions) + print(f"Found {len(named_steam_funcs)} named functions in comparison file ({comparison_label})") + + # Group by name, excluding duplicates + steam_name_map = group_by_name(named_steam_funcs) + print(f"After removing duplicates: {len(steam_name_map)} unique named functions") + + # Keep track of total for progress + total = 0 + + # Progress tracking + progress_step = max(1, len(steam_name_map) // 20) # Show progress in ~5% increments + + print(f"\nTesting matches for {len(steam_name_map)} functions...") + + for idx, (name, steam_func) in enumerate(steam_name_map.items()): + # Show progress + if idx % progress_step == 0: + print(f"Progress: {idx}/{len(steam_name_map)} ({idx/len(steam_name_map)*100:.1f}%)") + + # Find most similar functions in GOG + best_matches, similarity_score = find_most_similar_function( + steam_func, + gog_functions, + size_weight=size_weight, + ref_weight=ref_weight, + addr_weight=addr_weight, + opcode_weight=opcode_weight, + max_addr_diff=max_addr_diff + ) + + total += 1 + + # Check if best match has the same name + if len(best_matches) > 1: + # Ambiguous match (multiple with same score) + ambiguous_matches.append({ + 'steam_func': steam_func, + 'gog_matches': best_matches, + 'similarity_score': similarity_score + }) + else: + best_match = best_matches[0] + if best_match["name"] == name: + correct_matches.append({ + 'steam_func': steam_func, + 'gog_match': best_match, + 'similarity_score': similarity_score + }) + else: + incorrect_matches.append({ + 'steam_func': steam_func, + 'gog_match': best_match, + 'similarity_score': similarity_score + }) + + # Print final statistics + print("\nMatching Results:") + print(f"Total functions tested: {total}") + print(f"Correct matches: {len(correct_matches)} ({len(correct_matches)/total*100:.2f}%)") + print(f"Incorrect matches: {len(incorrect_matches)} ({len(incorrect_matches)/total*100:.2f}%)") + print(f"Ambiguous matches: {len(ambiguous_matches)} ({len(ambiguous_matches)/total*100:.2f}%)") + + return len(correct_matches) / total # Return success rate + +def analyze_address_differences(): + """Analyze address differences between functions with identical real names""" + global gog_functions, steam_functions + + if not gog_functions or not steam_functions: + print("Function data not loaded. Run main() first.") + return + + print("Finding functions with identical real names in both executables...") + + # Get functions with real names from both executables + steam_named = {f['name']: f for f in steam_functions if is_real_name(f['name'])} + gog_named = {f['name']: f for f in gog_functions if is_real_name(f['name'])} + + # Find functions that exist in both with identical names + common_names = set(steam_named.keys()) & set(gog_named.keys()) + print(f"Found {len(common_names)} functions with identical real names in both executables") + + if not common_names: + print("No matching named functions found.") + return + + address_diffs = [] + for name in common_names: + steam_func = steam_named[name] + gog_func = gog_named[name] + + steam_addr = int(steam_func['address'], 16) + gog_addr = int(gog_func['address'], 16) + diff = gog_addr - steam_addr + + address_diffs.append({ + 'function_name': name, + 'steam_addr': steam_addr, + 'gog_addr': gog_addr, + 'difference': diff, + 'abs_difference': abs(diff) + }) + + # Sort by absolute difference to see patterns + address_diffs.sort(key=lambda x: x['abs_difference']) + + # Calculate statistics + diffs = [item['abs_difference'] for item in address_diffs] + min_diff = min(diffs) + max_diff = max(diffs) + avg_diff = sum(diffs) / len(diffs) + + # Find most common difference + from collections import Counter + diff_counts = Counter(diffs) + most_common_diff = diff_counts.most_common(1)[0] + + print(f"\nAddress difference statistics:") + print(f" Min difference: 0x{min_diff:08x} ({min_diff})") + print(f" Max difference: 0x{max_diff:08x} ({max_diff})") + print(f" Average difference: 0x{int(avg_diff):08x} ({int(avg_diff)})") + print(f" Most common difference: 0x{most_common_diff[0]:08x} ({most_common_diff[0]}) - appears {most_common_diff[1]} times") + + # Show distribution of differences + print(f"\nTop 10 most common differences:") + for diff, count in diff_counts.most_common(10): + print(f" 0x{diff:08x} ({diff:8d}): {count:3d} functions") + + # Show some examples + print(f"\nFirst 10 examples (sorted by absolute difference):") + for i, item in enumerate(address_diffs[:10]): + print(f" {item['function_name']:30s} Steam: 0x{item['steam_addr']:08x} GOG: 0x{item['gog_addr']:08x} Diff: 0x{item['difference']:08x} (abs: 0x{item['abs_difference']:08x})") + + return address_diffs + +def generate_training_data(): + """Generate training data from functions with known matches and mismatches""" + global gog_functions, steam_functions + + if not gog_functions or not steam_functions: + print("Function data not loaded. Run main() first.") + return [], [] + + print("Generating training data for logistic regression...") + + # Get functions with real names from both executables + steam_named = {f['name']: f for f in steam_functions if is_real_name(f['name'])} + gog_named = {f['name']: f for f in gog_functions if is_real_name(f['name'])} + + # Find functions that exist in both with identical names (positive examples) + common_names = set(steam_named.keys()) & set(gog_named.keys()) + print(f"Found {len(common_names)} positive examples (identical names)") + + features = [] + labels = [] + + # Positive examples: functions with identical names + for name in common_names: + steam_func = steam_named[name] + gog_func = gog_named[name] + + # Calculate all similarity features + size_sim = calculate_size_similarity(steam_func, gog_func) + ref_sim = calculate_reference_similarity(steam_func, gog_func) + addr_sim = calculate_address_similarity(steam_func, gog_func) + opcode_sim = calculate_opcode_similarity(steam_func, gog_func) + + features.append([size_sim, ref_sim, addr_sim, opcode_sim]) + labels.append(1) # Correct match + + # Negative examples: generate mismatches + # For each positive example, find some functions that are NOT matches + print("Generating negative examples...") + import random + random.seed(42) # For reproducibility + + negative_count = 0 + target_negatives = len(common_names) * 2 # 2:1 ratio of negatives to positives + + steam_funcs_list = list(steam_named.values()) + gog_funcs_list = list(gog_named.values()) + + for _ in range(target_negatives): + if negative_count >= target_negatives: + break + + # Pick random functions that don't have the same name + steam_func = random.choice(steam_funcs_list) + gog_func = random.choice(gog_funcs_list) + + # Skip if they actually match + if steam_func['name'] == gog_func['name']: + continue + + # Calculate similarity features + size_sim = calculate_size_similarity(steam_func, gog_func) + ref_sim = calculate_reference_similarity(steam_func, gog_func) + addr_sim = calculate_address_similarity(steam_func, gog_func) + opcode_sim = calculate_opcode_similarity(steam_func, gog_func) + + features.append([size_sim, ref_sim, addr_sim, opcode_sim]) + labels.append(0) # Incorrect match + negative_count += 1 + + print(f"Generated {len([l for l in labels if l == 1])} positive and {len([l for l in labels if l == 0])} negative examples") + return features, labels + +def train_logistic_regression(): + """Train logistic regression model to learn optimal feature weights""" + try: + from sklearn.linear_model import LogisticRegression + from sklearn.model_selection import cross_val_score + from sklearn.preprocessing import StandardScaler + import numpy as np + except ImportError: + print("Error: scikit-learn not available. Install with: pip install scikit-learn") + return None + + # Generate training data + features, labels = generate_training_data() + if not features: + print("No training data generated") + return None + + features = np.array(features) + labels = np.array(labels) + + print(f"Training on {len(features)} examples...") + + # Standardize features (important for logistic regression) + scaler = StandardScaler() + features_scaled = scaler.fit_transform(features) + + # Train logistic regression with L2 regularization + model = LogisticRegression(random_state=42, max_iter=1000) + model.fit(features_scaled, labels) + + # Evaluate with cross-validation + cv_scores = cross_val_score(model, features_scaled, labels, cv=5) + print(f"Cross-validation accuracy: {cv_scores.mean():.3f} (+/- {cv_scores.std() * 2:.3f})") + + # Get feature importance (coefficients) + coefficients = model.coef_[0] + feature_names = ['Size', 'References', 'Address', 'Opcode'] + + print("\nLearned feature coefficients:") + for name, coef in zip(feature_names, coefficients): + print(f" {name}: {coef:.4f}") + + # Convert to normalized weights (positive, sum to 1) + # Take absolute values and normalize + abs_coefficients = np.abs(coefficients) + normalized_weights = abs_coefficients / np.sum(abs_coefficients) + + print("\nNormalized weights for correlator:") + for name, weight in zip(feature_names, normalized_weights): + print(f" {name}: {weight:.3f}") + + print(f"\nSuggested command line:") + print(f"python correlator.py --test {normalized_weights[0]:.3f} {normalized_weights[1]:.3f} {normalized_weights[2]:.3f} {normalized_weights[3]:.3f}") + + return { + 'model': model, + 'scaler': scaler, + 'weights': normalized_weights, + 'coefficients': coefficients, + 'cv_accuracy': cv_scores.mean() + } + +def process_multiple_addresses(addresses, gog_functions, steam_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label="Steam"): + """Process multiple addresses and find matches for each""" + results = [] + + print(f"Processing {len(addresses)} addresses with default weights...") + print(f"Using weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") + print("=" * 80) + + for i, address in enumerate(addresses): + print(f"\n[{i+1}/{len(addresses)}] Processing address: {address}") + print("-" * 40) + + # Find the target function in gog.json + target_function = find_function_by_address(gog_functions, address) + if not target_function: + print(f"No function found at address {address} in gog.json") + results.append({ + 'address': address, + 'found': False, + 'error': f"No function found at address {address}" + }) + continue + + target_size = len(target_function["raw_bytes"]) + print(f"Found target function: {target_function['name']} at {target_function['address']}") + print(f"Function size: {target_size} bytes, References: {target_function['reference_count']}") + + # Find the most similar function in comparison file + best_matches, similarity_score = find_most_similar_function( + target_function, + steam_functions, + size_weight=size_weight, + ref_weight=ref_weight, + addr_weight=addr_weight, + opcode_weight=opcode_weight, + max_addr_diff=max_addr_diff + ) + + print(f"Combined similarity score: {similarity_score:.4f}") + + # Store results + match_data = [] + for match in best_matches: + match_size = len(match['raw_bytes']) + size_sim = calculate_size_similarity(target_function, match) + ref_sim = calculate_reference_similarity(target_function, match) + addr_sim = calculate_address_similarity(target_function, match, max_addr_diff) + opcode_sim = calculate_opcode_similarity(target_function, match) + + match_info = { + 'name': match['name'], + 'address': match['address'], + 'size': match_size, + 'references': match['reference_count'], + 'size_similarity': size_sim, + 'ref_similarity': ref_sim, + 'addr_similarity': addr_sim, + 'opcode_similarity': opcode_sim + } + match_data.append(match_info) + + print(f"Best match in {comparison_label}: {match['name']} at {match['address']}") + print(f" Size: {match_size} bytes (similarity: {size_sim:.4f})") + print(f" References: {match['reference_count']} (similarity: {ref_sim:.4f})") + print(f" Address similarity: {addr_sim:.4f}") + print(f" Opcode similarity: {opcode_sim:.4f}") + + if len(best_matches) > 1: + print(f"WARNING: Found {len(best_matches)} functions with the same similarity score!") + + results.append({ + 'address': address, + 'found': True, + 'target_function': { + 'name': target_function['name'], + 'address': target_function['address'], + 'size': target_size, + 'references': target_function['reference_count'] + }, + 'matches': match_data, + 'similarity_score': similarity_score, + 'match_count': len(best_matches) + }) + + return results + +def main(): + global gog_functions, steam_functions + + # Check for --pcg flag first (before loading files) + use_pcg = "--pcg" in sys.argv + if use_pcg: + # Remove --pcg from argv so it doesn't interfere with other parsing + sys.argv = [arg for arg in sys.argv if arg != "--pcg"] + + # Set default weights + size_weight = 0.35 + ref_weight = 0.27 + addr_weight = 0.03 + opcode_weight = 0.35 + max_addr_diff = 86852 # Average from analysis + + # Load functions from both files + comparison_file = "pcg.json" if use_pcg else "steam.json" + comparison_label = "PCGames.de" if use_pcg else "Steam" + + gog_functions = load_ghidra_export("gog.json") + steam_functions = load_ghidra_export(comparison_file) + + if not gog_functions or not steam_functions: + print("Error loading function data. Exiting.") + sys.exit(1) + + # Check for analysis mode + if len(sys.argv) >= 2 and sys.argv[1] == "--analyze": + analyze_address_differences() + return + + # Check for ML training mode + if len(sys.argv) >= 2 and sys.argv[1] == "--train": + train_logistic_regression() + return + + # Check for list mode + if len(sys.argv) >= 2 and sys.argv[1] == "--list": + if len(sys.argv) < 3: + print("Error: --list requires at least one address") + sys.exit(1) + addresses = sys.argv[2:] + + results = process_multiple_addresses(addresses, gog_functions, steam_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label) + + # Print summary + print("\n" + "=" * 80) + print("SUMMARY") + print("=" * 80) + + found_count = sum(1 for r in results if r['found']) + print(f"Total addresses processed: {len(results)}") + print(f"Functions found: {found_count}") + print(f"Functions not found: {len(results) - found_count}") + + if found_count > 0: + avg_score = sum(r['similarity_score'] for r in results if r['found']) / found_count + print(f"Average similarity score: {avg_score:.4f}") + + ambiguous_count = sum(1 for r in results if r['found'] and r['match_count'] > 1) + if ambiguous_count > 0: + print(f"Ambiguous matches (multiple with same score): {ambiguous_count}") + + return + + # Check for test mode + if len(sys.argv) >= 2 and sys.argv[1] == "--test": + # If weights are provided, use them + if len(sys.argv) >= 4: + try: + size_weight = float(sys.argv[2]) + ref_weight = float(sys.argv[3]) + if len(sys.argv) >= 5: + addr_weight = float(sys.argv[4]) + if len(sys.argv) >= 6: + opcode_weight = float(sys.argv[5]) + # Normalize weights if they don't sum to 1 + total = size_weight + ref_weight + addr_weight + opcode_weight + if total != 1.0: + size_weight /= total + ref_weight /= total + addr_weight /= total + opcode_weight /= total + except ValueError: + print("Error: Weights must be numeric values") + sys.exit(1) + + # Run test mode + test_name_matching(steam_functions, gog_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label) + return + + # Normal mode - lookup a specific function + if len(sys.argv) < 2: + print("Usage:") + print(" python correlator.py [size_weight] [ref_weight] [addr_weight] [opcode_weight] [--pcg]") + print(" python correlator.py --list ... [--pcg]") + print(" python correlator.py --test [size_weight] [ref_weight] [addr_weight] [opcode_weight] [--pcg]") + print(" python correlator.py --analyze [--pcg]") + print(" python correlator.py --train [--pcg]") + print("\nOptions:") + print(" --pcg Use pcg.json (PCGames.de version) instead of steam.json for comparison") + print("\nExamples:") + print(" python correlator.py 00401000") + print(" python correlator.py 00401000 --pcg") + print(" python correlator.py 00401000 0.4 0.3 0.1 0.2") + print(" python correlator.py --list 00401000 00402000 00403000") + print(" python correlator.py --list 00401000 00402000 --pcg") + print(" python correlator.py --test") + print(" python correlator.py --test --pcg") + print(" python correlator.py --test 0.4 0.3 0.1 0.2 --pcg") + print(" python correlator.py --train # Learn optimal weights with ML") + return + + target_address = sys.argv[1] + + # Allow overriding weights through command line + if len(sys.argv) >= 4: + try: + size_weight = float(sys.argv[2]) + ref_weight = float(sys.argv[3]) + if len(sys.argv) >= 5: + addr_weight = float(sys.argv[4]) + if len(sys.argv) >= 6: + opcode_weight = float(sys.argv[5]) + # Normalize weights if they don't sum to 1 + total = size_weight + ref_weight + addr_weight + opcode_weight + if total != 1.0: + size_weight /= total + ref_weight /= total + addr_weight /= total + opcode_weight /= total + except ValueError: + print("Error: Weights must be numeric values") + sys.exit(1) + + # Find the target function in gog.json + target_function = find_function_by_address(gog_functions, target_address) + if not target_function: + print(f"No function found at address {target_address} in gog.json") + sys.exit(1) + + target_size = len(target_function["raw_bytes"]) + print(f"Found target function: {target_function['name']} at {target_function['address']}") + print(f"Function size: {target_size} bytes") + print(f"References: {target_function['reference_count']}") + print(f"Using weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") + + # Find the most similar function in comparison file + best_matches, similarity_score = find_most_similar_function( + target_function, + steam_functions, + size_weight=size_weight, + ref_weight=ref_weight, + addr_weight=addr_weight, + opcode_weight=opcode_weight, + max_addr_diff=max_addr_diff + ) + + print(f"\nBest matches in {comparison_label}:") + print(f"Combined similarity score: {similarity_score:.4f}") + + if len(best_matches) > 1: + print(f"\nWARNING: Found {len(best_matches)} functions with the same similarity score!") + + for i, match in enumerate(best_matches): + match_size = len(match['raw_bytes']) + size_sim = calculate_size_similarity(target_function, match) + ref_sim = calculate_reference_similarity(target_function, match) + addr_sim = calculate_address_similarity(target_function, match, max_addr_diff) + opcode_sim = calculate_opcode_similarity(target_function, match) + + print(f"\nMatch {i+1}:") + print(f"Function: {match['name']} at {match['address']}") + print(f"Size: {match_size} bytes (similarity: {size_sim:.4f})") + print(f"References: {match['reference_count']} (similarity: {ref_sim:.4f})") + print(f"Address similarity: {addr_sim:.4f}") + print(f"Opcode similarity: {opcode_sim:.4f}") + + # Show size difference as percentage + size_diff_pct = abs(target_size - match_size) / target_size * 100 + print(f"Size difference: {abs(target_size - match_size)} bytes ({size_diff_pct:.1f}%)") + +if __name__ == "__main__": + main() diff --git a/default.c3x_config.ini b/default.c3x_config.ini index 13d15a78..9b548f93 100644 --- a/default.c3x_config.ini +++ b/default.c3x_config.ini @@ -1,1177 +1,1177 @@ -[====================================================== C3X RELEASE 27 PREVIEW 2 DEFAULT CONFIG =====================================================] -[======================================================================= NOTE =======================================================================] -[Instead of editing this file, changes to the settings should be placed in either the scenario or custom config files. The scenario config file must ] -[be named scenario.c3x_config.ini and must be located in your scenario search folder. Of course it only applies if you are using a scenario. The ] -[custom config file must be named custom.c3x_config.ini and located in the C3X folder, which is the folder where this file is. When creating scenario] -[or custom configs, it is only necessary to include the settings you wish to change. ] -[====================================================================================================================================================] - -[============================] -[=== CONVENIENCE FEATURES ===] -[============================] - -enable_stack_bombard = true -enable_stack_unit_commands = true -enable_disorder_warning = true -show_detailed_city_production_info = true -enable_trade_screen_scroll = true -autofill_best_gold_amount_when_trading = true -skip_repeated_tile_improv_replacement_asks = true -group_units_on_right_click_menu = true - -; On the right click menu, units with no remaining moves will appear in gray text -gray_out_units_on_menu_with_no_remaining_moves = true - -; Places an icon next to units on the right-click menu showing their remaining moves & status. The icon is green for unmoved units, red for units that -; have exhausted all their moves, and yellow for those in between. Additionally it contains a little sword for units that can still attack and is -; colored blue for fighters set to intercept. -put_movement_icons_on_units_on_menu = true - -; Replaces the "Wake" or "Activate" text on the right-click menu with more descriptive words indicating what the unit is currently doing. For example, -; "Moving", "Intercepting", or "Working". -describe_states_of_units_on_menu = true - -show_detailed_tile_info = true -show_golden_age_turns_remaining = true - -; This option causes the game to show attack animations for units exerting zone of control from the middle of their tile's stack. Otherwise the game -; will only show such animations for units that are the top visible unit on their tiles. It was presumably an oversight by the original developers -; that units exerting zone of control do not temporarily become the visible unit on their tiles (unlike, for example, defensive bombard). -show_zoc_attacks_from_mid_stack = true - -; Fixes the defensive bombard animation being skipped when the unit performing defensive bombard is inside an army. -show_armies_performing_defensive_bombard = true - -cut_research_spending_to_avoid_bankruptcy = true -dont_pause_for_love_the_king_messages = true - -; Holding shift when clicking a specialist on the city screen will switch to the previous, instead of the next, specialist type -reverse_specialist_order_with_shift = true - -; Pressing the Z key on the city screen will zoom the map in/out -toggle_zoom_with_z_on_city_screen = true - -; When king units are spawned they're named after the leader of their civ. This is undesirable in modded games where the king flag is often used -; on units that aren't intended to be actual kings. This setting helps by bypassing the king unit naming logic when regicide is not enabled. -dont_give_king_names_in_non_regicide_games = true - -; One of the game's "Easter eggs" is that all king-flagged units appear as Elvis Presley on his birthday (Jan 8). This can be annoying when playing -; mods that make wide use of the king flag. -no_elvis_easter_egg = false - -; Removes option to automate workers from the human player. Useful for those who never want to use automation but sometimes accidentally activate it. -disable_worker_automation = false - -; There is a limit to how many links can appear on each Civilopedia page. Some mods exceed that limit. The problem is that the game throws up a popup -; when the limit is exceeded, one popup for each link beyond the limit. That can result in dozens of annoying, useless popups. This option stops them -; from appearing. Note: the game may also crash if the number of links far exceeds the limit. This option does not stop the crash, just the popups. -suppress_hypertext_links_exceeded_popup = true - -; Replaces the text "Upgrades To" with "Obsoleted By" in the Civilopedia for unit types that go obsolete but cannot be upgraded to their successors. -indicate_non_upgradability_in_pedia = true - -; Shows a message when a bomber gets intercepted by enemy air defense buildings but succeedes on its roll to avoid damage. Without this message, there -; is no indication that anything happened in that case except for the bomber losing one movement point. -show_message_after_dodging_sam = true - -; Normally only the last human player in a hotseat game gets to see the AIs move their units since the game processes the interturn while that player -; is still seated. This setting shows the AI moves to the other players in the game. It works by creating a save just before the interturn processing -; happens and then, at the start of the other players' turns, loads the save, sets that player as the seated one, reprocesses the interturn, then -; resumes the original game. -; Note: If the game is manually saved and reloaded, the replay will be lost. So it is recommended to save the game only after all human players have -; seen the replay, i.e. during the last or second to last human players' turns. -replay_ai_moves_in_hotseat_games = false - -; Normally, when you load a save, all units face southeast because the game didn't record which direction they were facing when the save was -; created. However, the game does record which tile they were on before their most recent move, so it is possible to deduce which direction they -; should be facing. That's what this option does. -restore_unit_directions_on_game_load = true - -; The game stores your map grid setting (on or off) in conquests.ini. It applies that setting after creating a new game, but not after loading a -; save. That was presumably an oversight and is corrected by this config option. -apply_grid_ini_setting_on_game_load = true - -; Causes cities to display harbor/airport icons if they have buildings that grant the relevant unit effects (produce veterans & heal in one turn) -; instead of buildings that grant sea/air trade. This makes no difference under the standard rules but is useful with mods that separate the unit -; effects and trade abilities into different buildings. -city_icons_show_unit_effects_not_trade = true - -; The game rules do not permit aircraft in an airfield to be damaged by bombardment. The interface allows players to order such bombardments anyway -; since its logic to check target validity is incomplete. This option completes the logic, causing the interface to reject attempts to bombard an -; airfield which would have no effect. -disallow_useless_bombard_vs_airfields = true - -; This option fixes a graphical bug that appears when the game is run on Linux using Wine. The bug is caused by the game using both Windows GDI and -; OpenGL to draw to the same canvas. Because the game only uses OpenGL to draw lines, it's relatively easy to solve this issue by reimplementing line -; drawing using Windows GDI+ instead. There are three possible settings for this option: -; never: Self-explanatory -; wine: This change will only be applied if the mod detects the game is running on Wine -; always: This change will always be applied, even on an actual Windows system -draw_lines_using_gdi_plus = wine - -; This option reduces the vertical distance between rows in the list of luxuries on the city screen. This allows up to 11 luxuries to be displayed -; neatly inside the box. -compact_luxury_display_on_city_screen = false - -; Similar to the option above, this one packs the strategic resources more tightly into the box on the upper left of the city screen. This allows up -; to 13 resources to be displayed there. -compact_strategic_resource_display_on_city_screen = false - -; Causes the domestic advisor to ask for confirmation before setting city production to a building that would replace another already built in the -; city. It's similar to how the domestic advisor warns you before a production switch would waste shields. Useful for modded games where you might not -; know which buildings replace which. -warn_when_chosen_building_would_replace_another = false - -; This option keeps citizens working the tiles they've been assigned to when pollution spawns there instead of converting them to specialists. This -; reduces micromanage but comes at the cost of the specialist yields. -do_not_unassign_workers_from_polluted_tiles = false - -; Normally the game draws capital cities one level larger than normal. I.e., a capital city at size 1 - 6 uses the graphic for cities at size 7 - 12, -; and a capital at size 7+ uses the graphic for cities 13+. This option turns that off, so capitals use the standard city graphics. -do_not_make_capital_cities_appear_larger = false - -; Tints coast and sea tiles on the minimap based on the culture that controls them, like is normally done for land tiles. -show_territory_colors_on_water_tiles_in_minimap = false - -; In offline games, shows some popup messages as online-multiplayer-style notes to the left of the screen instead of advisor popups that pause -; gameplay until dismissed. The point is to minimize interruptions during turn processing. Affects popups with the following text keys: -; SUMMARY_END_GOLDEN_AGE, SUMMARY_END_SCIENCE_AGE, SUMMARY_NEW_SMALL_WONDER, WONDERPRODUCE, MAKEPEACE, MUTUALPROTECTIONPACT, MILITARYALLIANCE, -; SUMMARY_DECLARE_WAR, TRADEEMBARGOENDS, SUMMARY_CIV_DESTROYED_BY_CIV, SUMMARY_CIV_DESTROYED, LOSTGOOD, TRADEEMBARGO, MILITARYALLIANCEWARONUS, -; MILITARYALLIANCEAGAINSTUS, and SUMMARY_TRAVELERS_REPORT. -convert_some_popups_into_online_mp_messages = false - -; If enabled, pressing the keys d e b u g to type "debug", in-game will allow you to activate debug mode for a game in progress. Typing that with -; debug mode already on will deactivate it. -enable_debug_mode_switch = true - -; Places a small shadow below city dots on the minimap to make them more easily visible especially against light-colored territory. This feature does -; not quite work properly so is left off by default. Its issues are (1) the shadows may not fully appear until you toggle the minimap from territory -; to geography mode and back again and (2) the shadows may appear in geography mode. -accentuate_cities_on_minimap = false - -; Makes the minimap twice as large. Possible values are "never", "always", and "high-def". The first two are self-explanatory; if set to "high-def", -; the minimap's size will be doubled when the game is run at a horizontal resolution of at least 1920 pixels. -double_minimap_size = high-def - -; Allows descriptions for units, civilizations, and game concepts to span multiple pages. If a DESC entry of one of those types is too long for one -; page, it will automatically be divided into multiple with buttons added for navigation. -allow_multipage_civilopedia_descriptions = true - -; Controls how the game searches for the next unit to autoselect. The possible choices are: -; standard: Base game behavior -; similar-near-start: The game will search for similar units near the starting point of the last selected unit. That means, when a unit is selected, -; the game remembers its location then searches out from there for a similar unit when cycling to the next one. Distance is prioritized over -; similarity, meaning the game will select all units on the starting tile no matter how dissimilar before any on nearby tiles. -; similar-near-destination: Like similar-near-start except the search goes outward from whatever tile the last selected unit was last on. -unit_cycle_search_criteria = standard - -; On the domestic advisor screen, tweaks how the number of turns remaining on each city build are displayed to improve readability. Instead of -; "(1turn)" or "(7turns)", the game will display "(1 Turn)" or "(7 Turns)" -reformat_turns_remaining_on_domestic_advisor_screen = true - -; On unit Civilopedia pages, shows the movement stat for aircraft, bombard range for tactical nukes, and HP bonus & worker strength if non-zero. -expand_civilopedia_unit_stats = true - -[====================] -[=== OPTIMIZATION ===] -[====================] - -; Rewrites the game's trade network computation logic to improve speed. On large maps with many cities, this computation takes up most of the -; interturn time so speeding it up greatly improves turn times. For more info, see the text file in the Trade Net X folder. -enable_trade_net_x = true - -; Rewrites parts of the game logic to improve efficiency. Those parts check every possible improvement defined in the scenario when they really only -; need to check a few. For example, to determine whether a city can trade via air, it's very wasteful to check every improvement since the vast -; majority of them do not enable air trade. This option can improve turn times very significantly in some circumstances. -optimize_improvement_loops = true - -; Displays a popup after each turn has been processed showing the time elapsed, including specifically how much time was spent recomputing trade -; networks. NOTE: Turning this on will skip all animations during the interturn so they don't contribute to the time. You aren't meant to play the -; game with this option left on. -measure_turn_times = false - -[=======================] -[=== AI ENHANCEMENTS ===] -[=======================] - -; Allows artillery unit AI to grab escorts from city defenders, causing the AI to use its artillery offensively instead of leaving it in its cities. -use_offensive_artillery_ai = true - -; If true, the AI will not escort its units unless they have the "requires escort" flag set in the editor. This allows modders to remove the escort -; requirement from certain types of units, for example artillery with non-zero defense. -dont_escort_unflagged_units = false - -; Set to a number to encourage the AI to build more artillery, set to false or <= 0 for no change in AI unit build choices. The number is how many -; artillery units the AI will try to keep around for every 100 non-artillery combat land units it has. The encouragement only applies if the AI is -; already above a minimum of one defensive unit per city and one offensive unit per two cities. Default: 16. -ai_build_artillery_ratio = 16 - -; The above option controls how many artillery the AI will keep around, this one controls how aggressively it builds up to that limit. More -; specifically it controls how valuable (in percent) the AI thinks artillery is as a damage dealer compared to attacking units. Default: 50. -ai_artillery_value_damage_percent = 50 - -; Like the artillery ratio, shifts the AI's build priority from fighters to bombers to keep around this many bombers per 100 fighters. Default: 70. -ai_build_bomber_ratio = 70 - -; Completely replaces the leader unit AI with custom code. The custom version is similar in spirit to the original but fixes several major issues: -; 1. It fixes a bug that allowed the AI to rush any kind of city production, including units and (with an MGL) wonders -; 2. Prioritizes army formation over rushing production when appropriate -; 3. When rushing, prioritizes wonders and costly improvements in high value cities -replace_leader_unit_ai = true - -; Replaces the AI code that determines whether a unit would be a good addition to an army. The replacement code fixes a major bug that prevented the -; AI from filling its armies, prevents the AI from including hidden nationality units in armies to avoid crashes, and removes some logic that -; encouraged the AI to mix unit types in armies. -fix_ai_army_composition = true - -; "Pop units" are special units whose only purpose is to be joined into cities to increase their population. Normally the AI does not know what to do -; with these units, so this option enables a routine that causes them to search for & join an appropriate city. Pop units only appear in some mods -; (for example Tides of Crimson). Under the standard game rules, this option has no effect. In order to function as a pop unit, a unit must use the -; terraform AI strategy, have no worker actions except join city, have a pop cost of at least 1, and have zero attack, defense, & bombard strengths. -enable_pop_unit_ai = true - -; "Caravan units" are special units whose only purpose is to be disbanded to contribute shields to a city. The name comes from the Civ 2 caravan. -; Caravan units may appear in some mods; under the standard game rules, this option has no effect. In order to function as a caravan unit, a unit must -; use the terraform AI strategy, have no worker actions enabled, have the ability to disband, and have zero attack, defense, & bombard strengths. -enable_caravan_unit_ai = true - -; In the base game, the AI will assign 1, 2, or 3 escort units to its naval transports and carriers depending in their shield cost and the number of -; units they're carrying. This option lets you reduce the upper limit on the number of escorts assigned. You can limit the number of escorts to 2, 1, -; or even 0. Setting this option >= 3 will result in base game behavior. The purpose of reducing the limit is to free up the AI's naval power units. -max_ai_naval_escorts = 3 - -; This controls how many workers the AI feels it needs as a percentage of the base amount. For example, if set to 150 (the default), the AI will build -; about 50% more workers than normal. Set to 100 for base game behavior. For more info, see: -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-95#post-16587093 -ai_worker_requirement_percent = 150 - -[=================] -[=== BUG FIXES ===] -[=================] - -; Descriptions of bugs and their fixes: -; SUBMARINE BUG -- The AI runs into invisible units (such as submarines) belonging to other players because it blindly follows paths produced for -; it by the game's pathfinder, which does not see invisible units. After colliding with an invisible unit, the AI initiates combat, declaring war if -; necessary. The mod fixes this bug by modifying the pathfinder so it sees invisible units belonging to other non-hostile players so it can route -; around them. -; SCIENCE AGE BUG -- The bonus science points generated by a scientific golden age are not actually counted towards research progress. They appear -; only on the interface. This is because of a small oversight in the code. There is a setting which controls whether or not science age bonus points -; are included while gathering all research points. It's turned off while gathering points to update research progress. The fix is to turn it on. -; PEDIA TEXTURE BUG -- There is a one pixel wide pink line on the right edge of the Civilopedia screen. This is because the width of the -; Civilopedia background texture is set one pixel too small inside the EXE. This is fixed simply by replacing the width with the correct value. -; BLOCKED DISEMBARK FREEZE -- When using "disembark all" (which the AI always does) on a boat containing units that can't be disembarked, the game -; may freeze as it endlessly tries to disembark them. The root of the problem is that the game's logic to check if there are any disembarkable units -; left on the boat is incomplete. There are two cases that it misses. First, it does not consider the "immobile" unit flag. This is fixed by making -; immobile units appear to have no remaining movement points for this bit of logic so they are correctly considered non-disembarkable. Second, it does -; not consider escort relationships (e.g. for settlers). If a unit has a non-disembarkable escorter then it also can't be disembarked because the game -; will always try to move its escorter ahead of it. The solution here is to clear all escort relationships for ship passengers before disembarking. -; HOUSEBOAT BUG -- The game may crash when an AI player is left alive with only a settler on a boat. This happens because the AI's logic tries to -; check the location of its capital city without considering that there may be no capital. The fix is to modify this logic so that when it looks up -; the location of a non-existent capital, it receives a valid "dummy" location that it can process without crashing. See also: -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16084386 -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16085242 -; INTERCEPT LOST TURN BUG -- When a human player sets a fighter to intercept mode, the game discards all of its remaining movement points, hence it -; cannot intercept during the next interturn. This bug does not affect the AI and is part of the interface logic, not the game logic. I presume it was -; inserted by a programmer who did not understand how the game's unit cycling works. The fix simply restores fighters' discarded moves. -; PHANTOM RESOURCE BUG -- The game only stores one full list of available resources per player. That list contains how many sources of each -; resource type are avaiable in that player's capital and all connected cities. Cities off the capital's network have reduced lists of just 32 bits, -; recording yes-or-no availability for up to 32 resources. Resources beyond the first 32 will share bits in those reduced lists. Specifically, the -; 33rd resource shares the same bit as the 1st, the 34th the same as the 2nd, and so forth. This causes "phantom" resources. For example, if a mod has -; horses set as the 1st resource and steel as the 33rd, then any city off its capital's trade network with access to horses will also have access to -; steel and vice-versa. The fix for this issue is straight forward but not simple. The jist is the mod allocates additional space for the reduced -; lists so they're not limited to 32 bits, rather have enough bits for every resource in the game. After that it's necessary to modify the code that -; accesses the reduced lists so it can make use of the additional space. -; MAINTENANCE PERSISTING FOR OBSOLETE BUILDINGS -- Players are not supposed to pay maintenance for obsolete city improvements however they often do -; because the game does not recompute maintenance after a player unlocks a technology that obsoletes a city improvement. There is a related exploit in -; that, after triggering a recomputation of maintenance, players can then sell their obsolete buildings to have the maintenance deducted again, -; effectively getting credited for the cost of maintenance. The mod fixes both issues. It recomputes maintenance costs when a player unlocks a -; technology that obsoletes a city improvement and it stops the game from deducting the maintenance cost of an obsolete city imp. when it's sold. -; BARBARIAN DIAGONAL BUG -- Barbarians can only search for targets on adjacent tiles or on tiles that are up to 12 steps directly SE or NW of their -; position. The intended behavior was for them to search for targets on all surrounding tiles up to 6 steps away. This bug was caused by a small, -; sloppy programming mistake that can be corrected with a small edit. For details, see: -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-70#post-16434678 -; DISEASE CURING TECH FLAG BUG -- In the base game, the tech flag "Disables Diseases From Flood Plains" (applied to Sanitation) does nothing and -; instead flood plains disease stops once players discover Writing. This happens because that flag is encoded as number 8 and, instead of checking if -; players have a tech with that flag, the code mistakenly checks if players have tech #8, which is Writing under the standard rules. Correcting this -; bug causes a lot more disease, which is a major annoyance, and so this bug fix is turned off by default. -; DIVISION BY ZERO IN AI ALLIANCE EVAL -- When considering whether to agree to a military alliance, the AI computes the distance from its capital to -; the nearest city belonging to the target of the alliance and divides by that distance. For unknown reasons, in rare cases that distance may be zero, -; which crashes the program due to division by zero. The mod fixes this issue by inserting a bit of logic after the distance is computed to check if -; it's zero and, if so, set it to one. -; EMPTY ARMY MOVEMENT -- Empty armies have one less than a full move's worth of movement points regardless of how many moves their unit type has set -; in the editor. Under the standard game rules, this means they can only move two tiles along roads. The cause is a small mistake in the logic that -; attempts to find the slowest member among units in the army. The mod fixes this bug by reimplementing the max movement point calculation for armies. -; PREMATURE TRUNCATION OF FOUND PATHS -- If the game attempts to find a path for a unit that's more than 256 tiles long, the path will not be -; returned properly from the pathfinder. That's because the pathfinder stops reconstructing the final path once it reaches a length of 256. That -; creates a serious problem for long paths because reconstruction works from the end of the path toward the start, so stopping early produces an -; incorrect path that begins in the middle. The fix is simply to multiply the maximum length by 10 (to 2560). Removing the limit entirely risks -; allowing infinite loops. This bug is rarely visible in-game, it usually appears as AI naval units following inappropriate or invalid paths. -; ZERO PRODUCTION CRASH -- If a city has zero production, which is possible using specialists modded to produce negative shields, the game will -; crash due to a division by zero. -; AI CAN SACRIFICE WITHOUT SPECIAL ABILITY -- The base game function that gates the AI's ability to sacrifice units does not check whether the unit -; in question has the sacrifice special ability set on its type. Thus, AIs are allowed to sacrifice any captured units as long as they have the -; required tech. The mod fixes this by patching the gating function to insert the missing condition. -; AI CAN FORM ARMY WITHOUT SPECIAL ABILITY -- Similar to the above issue, the AI's ability to form armies with leader units is not gated by those -; units having the "build army" special ability. -; CRASH IN LEADER UNIT AI -- The base game's AI routine for leader units may crash due to uninitialized variables. -; FAILURE TO FIND NEW CITY BUILD -- After a city completes production, the game searches for a new build for it. If that city is owned by the seated -; player, whatever the game finds will be filled in as the default option in the domestic advisor popup asking the player to choose a new build. If -; the search fails to find anything, there will be no default option, the dropdown selector will not be initialized, and the game will crash when it -; tries to open the popup. To fix this, the mod detects when the game has failed to find a new build option and fills in Wealth instead or, failing -; that, any unit or improvement that the city can build. -; PASSENGERS OUT OF ORDER ON MENU -- When there are multiple doubly-contained units (meaning units contained in other units that are themselves -; contained in something, like a unit in an army on a transport) on a tile, the game will not always show the passenger units in the correct locations -; on the right-click menu. To fix this, the mod double checks the order of the entries on the menu to make sure that passenger units are listed just -; after the unit they're contained in. -; PATCH EMPTY ARMY COMBAT CRASH -- Guards a crash in the army combat selection routine by returning the army unit itself if it has no contained -; units (prevents divide-by-zero in the vanilla selection loop). - -patch_submarine_bug = true -patch_science_age_bug = true -patch_pedia_texture_bug = true -patch_blocked_disembark_freeze = true -patch_houseboat_bug = true -patch_intercept_lost_turn_bug = true -patch_phantom_resource_bug = true -patch_maintenance_persisting_for_obsolete_buildings = true -patch_barbarian_diagonal_bug = true -patch_disease_stopping_tech_flag_bug = false -patch_division_by_zero_in_ai_alliance_eval = true -patch_empty_army_movement = true -patch_premature_truncation_of_found_paths = true -patch_zero_production_crash = true -patch_ai_can_sacrifice_without_special_ability = true -patch_ai_can_form_army_without_special_ability = true -patch_crash_in_leader_unit_ai = true -patch_failure_to_find_new_city_build = true -patch_passengers_out_of_order_on_menu = true -patch_empty_army_combat_crash = true - -; At the beginning of each AI player's turn, deletes any units of theirs that are not on a valid tile. This addresses a rare crash that can occur when -; the unit AI invokes the pathfinder for an off-map unit. I don't know how AI units can end up off the map in the first place. -delete_off_map_ai_units = true - -; On the city screen, the icons for different kinds of specialist yields get drawn over top of, instead of beside, one another. This setting fixes -; that so they are displayed properly. -fix_overlapping_specialist_yield_icons = true - -[======================] -[=== LIMITS REMOVED ===] -[======================] - -remove_unit_limit = true -remove_city_improvement_limit = true - -; The city limit can be configured up to a maximum of 2048 or down to a minimum of 0. For base game behavior, set to 512. -city_limit = 2048 - -; Increases the cap on the game turn limit from 1000 to 1000000 -remove_cap_on_turn_limit = true - -; Be warned: the no era limit feature is incomplete, untested, and not likely to work at this time -remove_era_limit = false - -[=========================] -[=== ENGINE EXTENSIONS ===] -[=========================] - -; These "NoRaze" options can stop cities from being destroyed. "Autorazing" refers to the automatic destruction of size one, cultureless cities. If -; autorazing is prevented, players will be given the option to keep the city. If razing by players is prevented, neither the human player nor AIs will -; be allowed to raze or abandon cities. -prevent_autorazing = false -prevent_razing_by_players = false - -; These options allow you to adjust the minimum allowed distance between cities. minimum_city_separation controls the minimum number of tiles between -; cities so, e.g, if it's set to 1, cities cannot be founded adjacent to one another, there must be at least one open tile separating them. A setting -; of 1 there corresponds to the standard game rules. disallow_founding_next_to_foreign_city is an optional additional restriction. If it's enabled, -; cities may not be founded adjacent to a city belonging to another civ regardless of the minimum separation. It is only relevant when the minimum -; separation is set to zero. -minimum_city_separation = 1 -disallow_founding_next_to_foreign_city = true - -; Set to a number to limit railroad movement to that many tiles per turn. To return to infinite railroad movement, set to false or a number <=0. By -; default, all units travel the same distance along limited rails like in Civ 4, but this can be changed by toggling the next option below. -; NOTE: For best results, the railroad limit should be a multiple of the "movement rate along roads" set in the editor (usually 3). The limitation -; will work in any case, but setting the limit this way helps avoid an integer overflow issue inside the pathfinder that may cause it to fail to find -; the shortest paths for units with a large number of available moves. -limit_railroad_movement = false - -; If set to true, limited railroads will work like fast roads instead of Civ 4 style railroads. The movement rate along fast roads is determined by -; the limit_railroad_movement setting above. If that setting is false or <= 0, this option does nothing. -limited_railroads_work_like_fast_roads = false - -; This option lets you put a limit on how many units may occupy each tile. The limit applies separately for land, sea, and air units. You may set the -; limit differently for each of those classes by setting this option to a list of three numbers. If you set it to a single number, that limit amount -; will apply to all three. If you set it to false or a number <= 0, no limit will apply, as in the base game. Some examples: -; To limit tiles to 5 land, 5 sea, and 5 air units: limit_units_per_tile = 5 -; To limit tiles to 5 land and sea units but 10 air units: limit_units_per_tile = [5 5 10] -; To limit only air units to 10 per tile: limit_units_per_tile = [false false 10] -; To have no limit (as in the standard game rules): limit_units_per_tile = false -; NOTE: The two options below let you exclude cities or certain unit types from the limit. -limit_units_per_tile = false - -; Allows an unlimited number of units to occupy tiles with cities when the unit limit is in force. When the limit (option above) is deactivated, this -; option does nothing. -exclude_cities_from_units_per_tile_limit = false - -; Allows certain unit types to be exempt from the stack limit. Units of these types will not be stopped by the limit and will not count toward it -; (will not stop others). This option is a space separated list of unit type names. Multi-word names must be wrapped in quotes. For example: -; [Worker Settler Flak "Mobile SAM"] -; This option does nothing if limit_units_per_tile is set to false. -exclude_types_from_units_per_tile_limit = [] - -enable_free_buildings_from_small_wonders = true -allow_stealth_attack_against_single_unit = false -disallow_trespassing = false -enable_land_sea_intersections = false - -; All anarchy lengths will be multiplied by this amount as a percent. For example, if set to 50, anarchy length will be reduced by half. Set to 100 -; for standard game behavior. There is a minimum anarchy length of 2 turns, but you can remove anarchy entirely by setting this option < 0. -anarchy_length_percent = 100 - -; Add perfume to an improvement or unit type to encourage the AI to build it more often. When choosing what to buld, the AI computes a point value for -; each of its options and the mod will add the perfume amount to the point total for each named option. For reference, point values are often in the -; hundreds for the most desirable options. You can see the point value the AI gives to every available build by pressing P while viewing one of its -; cities. Perfume amounts can also be specified as a percentage, ex. a perfume amount of 15% will increase the AI's evaluation by 15% and an amount of -; -50% will reduce it by half. -; production_perfume is a list of names and amounts, each one looks like "name": amount -; Here's an example: ["Granary": 15, "Colosseum": -20%, "Courthouse": 30] -; The quotation marks around a name are not necessary if the name is all one word (i.e. does not include spaces) and is made up of only letters, -; digits (0-9), periods, hyphens, or underscores. The category of letters includes the normal English a-z and A-Z as well as accented variants -; (e.g. ä, ö, ñ, ç) and all other non-English letters available in the Windows-1252 encoding (e.g. ß, þ, æ). -production_perfume = [] - -; Add perfume to a technology to change how valuable the AI judges the tech to be. Each point of perfume is worth roughly one gold in trade, and also -; affects what the AI chooses to research. The format matches production_perfume above, ex.: [Medicine: 500, Fascism: -50%, "Replacable Parts": 20%]. -technology_perfume = [] - -; Add perfume to a government to encourage or discourage the AI from switching to that type. The format follows the other perfume options, ex.: -; [Republic: 10%, Fascism: -30%]. Unfortunately I don't know how much each point is worth in this context. I also don't know how perfuming governments -; affects the AI's willingness to overthrow its current govt. The perfume for sure applies when the AI is selecting a new govt type after anarchy. -government_perfume = [] - -; The AI production ranking is the point value the AI gives to each available build in some city. To view it, press P while viewing an AI city. -enable_ai_production_ranking = true - -; Shades/highlights each tile to show how desirable the AI considers it as a city location. To activate, press L while in game. The scale goes from -; white (least desirable) to red (most desirable) with yellow in between. Also the exact number the AI gives any tile can be seen on its info box. -; If show_ai_city_location_desirability_if_settler is true, the desirability overlay will automatically appear when a settler is selected. -enable_ai_city_location_desirability_display = true -show_ai_city_location_desirability_if_settler = false - -; Setting a government's corruption level to "OFF" will remove all corruption, as expected, instead of maximizing it -zero_corruption_when_off = true - -; Prevents land settlers/workers on transports from settling/improving water tiles. This option does not affect the vanilla game but is useful for -; mods that enable city building or improvement of water tiles. -disallow_land_units_from_affecting_water_tiles = true - -; Allows units to move after airdropping by making airdrops cost no movement. Under the standard game rules, units lose all their remaining moves -; after airdropping. Units will be prevented from airdropping more than once in the same turn. -dont_end_units_turn_after_airdrop = false - -allow_airdrop_without_airport = false -enable_negative_pop_pollution = true - -; Here it's possible to set buildings as prerequisites for unit production. It's possible for a unit type to have multiple prereq buildings up to a -; maximum of 10, and all must be present in a city for the unit to be buildable. -; The format is a list of building names and unit type names, each one looks like "building name": "unit type 1" "unit type 2" ... -; Quotation marks around names can be omitted like in production_perfume (see above). -; Here's an example: -; [Factory: Tank "Modern Armor", -; Barracks: Swordsman Cavalry Tank "Modern Armor", -; Airport: Bomber] -building_prereqs_for_units = [] - -; Here it's possible to set buildings to generate resources. Those resources can be added to the trade network or limited to the building's city. The -; format is a list of building name and resource name pairs with optional "local", "no-tech-req", "yields", "show-bonus", and/or "hide-non-bonus" -; settings before each resource name. Example: -; ["Steel Mill": Steel, Terrace: yields show-bonus Rice, "Coal Liquefaction": local Oil, Supercollider: local no-tech-req Antimatter, -; "Hydro Plant": local "Electric Power"] -; Quotation marks around names can be omitted like in production_perfume (see above). -; The "local" setting means that the produced resource will not be added to the trade network, it will be available only in the building's city. -; The "no-tech-req" setting means that the resource will be produced even for players who do not have the technology to reveal it on the map. -; The "yields" setting means that the resource's tile yields will be added to the city as if it were on a worked tile. -; The "show-bonus" setting means that an icon for the generated resource will be displayed on the city screen even if it's a bonus resource. -; The "hide-non-bonus" setting is the opposite of show-bonus. It means an icon will NOT be shown if the resource is of strategic or luxury type. -; Buildings will not generate resources if the resource requirement for the building itself is not met. This makes it possible to set up resource -; production chains. Note for modders: Production chains require the input resources to be listed before the outputs in the scenario data, when the -; inputs also come from buildings. For example if you have iron ore on the map, a building that requires it and produces iron, and a building that -; requires iron and produces steel, iron must be listed before steel in the scenario data or the chain won't work. This is because building resource -; generation is calculated in the same order as the generated resources appear in the scenario data. This limitation does not apply to map resources -; (iron ore in the example) as access to all map resources is calculated first before any building resources. -buildings_generating_resources = [] - -; Shows a warning in case some of the unit, building, or resource names in this config file don't match anything in the scenario data. -warn_about_unrecognized_names = true - -; Overrides the rules for when units are eligible to retreat based on their movement. The possible options are: -; standard: No change from base game rules -; none: No units will ever retreat -; all-units: All non-immobile units may retreat, even if they have only one move or are up against a faster opponent -; if-faster: Units may retreat when they are faster than their opponent, for example a cavalry may retreat from a knight -; if-not-slower: Units may retreat when they are at least as fast as their opponent, for example a knight may retreat from another knight but not -; from a cavalry, and an infantry may retreat from another infantry -; if-fast-and-not-slower: Like if-not-slower but only fast (2+ move) units may retreat -; These settings don't change the fact that units cannot retreat when they start combat with 1 HP or are defending a city. They also do not change -; that naval units cannot retreat defensively (there is a separate option for that below). -land_retreat_rules = standard -sea_retreat_rules = standard - -; Under the base game rules, no unit may retreat defensively if it's located on a water tile. This option removes this special rule so naval units can -; retreat defensively like land units do. See also: the sea_retreat_rules option above and the limit_defensive_retreat_on_water_to_types option below. -allow_defensive_retreat_on_water = false - -; If any unit types are listed here, defensive retreat on water tiles will be limited to those types. Otherwise, all types may retreat that way. The -; list is separated by spaces and multi-word type names must be wrapped in quotation marks. For example, setting to: -; [Submarine "Nuclear Submarine"] -; would mean that only those submarine naval units could retreat defensively. This option does nothing if allow_defensive_retreat_on_water is false. -limit_defensive_retreat_on_water_to_types = [] - -; The multi-city start spawns in multiple cities for AI players at the start of the game instead of their usual one settler. This option controls the -; number of cities the AI starts with. E.g., if it's set to 2, the AI starts with 2 cities. If it's set <= 0, the game starts like normal. The mod can -; also add improvements to the AI's extra cities, which are intended to work like extra palaces, see ai_multi_start_extra_palaces. -ai_multi_city_start = 0 - -; This option only applies if ai_multi_city_start is set > 1. It controls how many tiles the mod will randomly check while searching for a suitable -; location for each of the AI's extra starter cities. Default: 10000. -max_tries_to_place_fp_city = 10000 - -; This option only applies if ai_multi_city_start is set > 1. It specifies a list of improvements to be added to the AI's additional cities. E.g: -; ["Forbidden Palace" Courthouse] -; If the AI multi-city start is set to 3+ with the above extra palaces, the AI players will start with 3+ cities and the first one will have the -; Palace like normal, the second will have the Forbidden Palace, and the third will have a courthouse, any after that will start empty. -; Additionally, any small wonders listed here with the "reduces corruption" effect will be considered "extra palaces" for the AI. They will respawn -; like the real Palace. In other words, if an AI loses a city with an extra palace, it will reappear in another one of its cities following the same -; logic the game uses to select a new Palace location. If the AI is missing an extra palace and acquires a new city, that extra palace will -; automatically be added to the new city. -ai_multi_start_extra_palaces = [] - -; Turning this on makes small or great wonders with the "reduces corruption" effect, such as the Forbidden Palace, as effective at reducing corruption -; as the palace itself. This reduces corruption not only in the city that contains such a wonder, it also reduces distance and rank corruption in -; nearby cities as if the city were an additional capital. -promote_wonder_decorruption_effect = false - -allow_military_leaders_to_hurry_wonders = false -allow_multiple_battle_created_units_per_player = false - -; The AI's beaker production will be multiplied by this amount, as a percent. A value of 100 gives you the standard game behavior, a value of 75 -; reduces AI research by 25%, a value of 200 doubles AI research, and so on. -ai_research_multiplier = 100 - -; Each time an AI player founds a city, the given amount of perfume will be applied to its settlers over the given duration in number of turns. The -; perfume effect declines steadily to zero over the duration. The perfume amount may be specified as a percentage. The purpose of these options is to -; slow the AI's expansion with negative perfume. -; NOTE: The AI has a very strong tendency to build settlers so you'll need to set these options quite high to slow it down significantly. For example, -; a perfume of -200% over a 30 turn duration left the AI with about half as many cities after 50 turns in my test. -ai_settler_perfume_on_founding = 0 -ai_settler_perfume_on_founding_duration = 0 - -; If a player can't afford to pay maintenance on their buildings and units, the game will forcibly lower expenses and raise money by (in order): -; 1. Selling buildings, excluding those that are maintenance-free or contribute to gold production even indirectly -; 2. Disbanding units, excluding free ones -; 3. Switching cities to building Wealth -; For AI players, the game alternates the order of (1) and (2) each turn. Also for AIs, on every third turn, the game will cut their research spending -; as much as necessary to avoid bankruptcy. -aggressively_penalize_bankruptcy = false - -; Under the standard game rules, the Despotism tile penalty does not apply to food yield from city tiles of Agricultural civs with fresh water. Set -; this option to true to remove that exception to the penalty. -no_penalty_exception_for_agri_fresh_water_city_tiles = false - -; Adds an option to the stealth attack target selection popup that allows the player to opt out of doing a stealth attack. If selected, the unit will -; attack normally, targeting the tile's top defender. Similarly, if stealth bombardment is canceled, the unit will bombard normally and may target -; buildings or population if attacking a city. -include_stealth_attack_cancel_option = false - -; Aircraft flying a recon mission can be intercepted by enemy fighters or ground AA as if they were flying a bombing mission -intercept_recon_missions = false - -; Under the standard rules, performing a recon mission or intercepting an attacker causes a unit to lose all of its remaining moves. Setting this -; option to true causes those actions to only consume one move. This makes them consistent with other air missions like bombing. Note: fighters will -; only be able to intercept multiple times in one turn if they have the blitz ability. -charge_one_move_for_recon_and_interception = false - -; In the base game, precision striking was only intended to be used by bombers. This option extends the precision strike logic to cover land & sea -; artillery and cruise missiles. Specifically what it does is: -; 1. Fixes the animations, so land & sea artillery will play their bombard animations and cruise missiles will play their strike animation -; 2. Makes it so that the strikable range depends on the bombard range for land & sea units instead of operational range -; 3. Despawns cruise missiles after they've performed a precision strike -polish_precision_striking = true - -; Enables units to perform stealth attacks when they bombard or bomb a target. Like regular stealth attacks this opens a popup allowing the player to -; choose a specific unit to target. The attacking unit must have the stealth attack special action checked, must have a list of stealth attack targets -; set, and the target tile must be visible. -enable_stealth_attack_via_bombardment = false - -; Prevents aircraft from being damaged by bombardment or bombing -immunize_aircraft_against_bombardment = false - -; Unit type names listed here will use PTW-like targeting when bombarding cities. PTW-like means there is a 1-in-3 chance they will target each of -; population, buildings, and units. This is unlike Conquests artillery targeting, which always goes after units first. Items in the list are separated -; by spaces and multi-word items must be wrapped in quotation marks like for perfume specs. Example: [Catapult Cannon Artillery "Radar Artillery"] -ptw_like_artillery_targeting = [] - -; Changes the meaning of the charm attack flag to indicate PTW-like targeting. This is a matter of convenience. It allows modders to specify PTW -; targeting using an editor, instead of the list above, at the cost of losing the charm attack function. -charm_flag_triggers_ptw_like_targeting = false - -; Unit types listed here won't be allowed to bombard land tiles. Same format as ptw_like_artillery_targeting, example: [Submarine "Torpedo Bomber"] -can_bombard_only_sea_tiles = [] - -; Units with the king ability will defend like normal, instead of always being the last to defend in a stack. Useful for mods that use the king flag -; for special purposes. Does not apply in regicide games. -ignore_king_ability_for_defense_priority = false - -; Untradable techs will appear grayed out on the trade screen. This lets you see which untradable techs the AI has just like for tradable -; ones. "Untradable" means techs that have been flagged as "cannot be traded" in the editor. This option only matters for modded games as there are no -; untradable techs in the standard game. -show_untradable_techs_on_trade_screen = false - -; Barbarians will capture cities instead of ransacking them. This option also modifies the game's production logic so barbarian cities can build -; things, grow, and even do research. -; This feature is EXPERIMENTAL at the moment. It basically works but hasn't been extensively tested. For example, I don't know what would happen if -; the barb player were to win the game. -; Because of how barb city production works under the hood, it requires barb activity to be turned on in order to work. The mod will handle this -; automatically. If this option is enabled, there is at least one barb city on the map, and the barb activity level is set to 0 (no barbarians), the -; level will be increased to 1 (sedentary) in order not to block barb city production. -enable_city_capture_by_barbarians = false - -; A list of modifications to the rules for defensive bombard. "Defensive bombard" is the free shot a bombard unit gets when the stack it's in is -; attacked. The possible options are: -; lethal: Attackers may be destroyed by defensive bombard if the bombarding unit has the appropriate lethal land/sea bombard ability. -; aerial: Air units may perform defensive bombard if they can perform bombing missions. -; not-invisible: Attacking units are immune to defensive bombard if they are invisible and not detected. -; blitz: Units with blitz may perform defensive bombard multiple times per turn, once for each move they have. -; docked-vs-land: Docked ships (i.e. in a city) can perform defensive bombard against land units attacking their city. -; For example, to activate all options, set to [lethal aerial not-invisible blitz docked-vs-land]. The order of items in the list does not matter. You -; can also activate all options by setting to [all] (with or without the brackets). -special_defensive_bombard_rules = [] - -; A list of modifications to the rules for zone of control, like above for defensive bombard. The possibilities are: -; amphibious: Land units may exert zone of control over sea units and vice-versa. This can only be done using bombard strength, not attack -; strength. It also requires non-zero bombard range. -; lethal: Units may be destroyed by zone of control. The intercepting unit must have the lethal bombard ability in order to do this, even if it's -; using its attack strength to exert ZoC. -; aerial: Air units can exert zone of control if their type has the "Zone of Control" option checked. Additionally, they must be able to perform the -; bombing mission, have non-zero bombard strength, and non-zero operational range. -; not-from-inside: Land units may not exert zone of control while inside a transport (armies do not count as transports) -; Like for defensive bombard, all options can be activated by setting to [all] (with or without the brackets), and order does not matter. -special_zone_of_control_rules = [] - -; All human players in a hotseat game will share visibility -share_visibility_in_hotseat = false - -; All human players in a hotseat game will share the effects of the wonders they've built, great or small. This applies to all civ-wide effects, for -; example if any human player builds Leonardo's Workshop, all human players get half price upgrades. Notes: -; 1. If a human player receiving the shared effect of a small wonder and that SW has no non-shared effects, it becomes unbuildable for that player. -; 2. Building and army requirements for wonders are shared as well. For example, all human players are allowed to build Battlefield Medicine once all -; of them combined have five hospitals. -; 3. For the Great Library effect, known AI civs are shared as well. If an AI has contact with any human player, it is considered to be in contact -; with all of them for the purpose of granting techs to human players. -share_wonders_in_hotseat = false - -allow_precision_strikes_against_tile_improvements = false -dont_end_units_turn_after_bombarding_barricade = false - -; Allows land units to bombard aircraft and naval units in cities -; This does not override the immunity of aircraft vs bombardment, if that option is also activated. -remove_land_artillery_target_restrictions = false - -; Allows tile improvements on a tile with an occupied airfield to be destroyed by bombardment, not including the airfield itself. For example, under -; the standard game rules, if you bombard a tile with a road, airfield, and fighter on it, you will do no damage because the attack will target the -; fighter which is invulnerable (aircraft in an airfield cannot be damaged by bombardment). This option allows such an attack to bypass the fighter -; and hit the tile instead, as long as that tile has an improvement other than the airfield. -allow_bombard_of_other_improvs_on_occupied_airfield = false - -; Displays the total number of cities in the game on the demographics screen (press F11). -show_total_city_count = false - -; Under the standard game rules, each forbidden-palace-like building in an empire increases its optimal city number (OCN) by 37.5% of the base number, -; except if the empire is running a government with communal corruption, in which case the increase is 100% of the base. With this option enabled, the -; communal corruption rule is always in force, so each forbidden palace always increases the OCN by an amount equal to the base number. -; NOTE: The "base" optimal city number comes from the map size. It's the number set on the "World Sizes" tab in the editor. -strengthen_forbidden_palace_ocn_effect = false - -; This option allows you to increase the maintenance cost of units depending on their shield cost. For every X shields that the unit costs to build -; (where X is the setting below), the unit's maintenance increases by one unit's worth. For example, if set to 100, units that cost 0-99 shields will -; have normal maintenace, units costing 100-199 shields will cost double, those costing 200-299 will cost triple, etc. (Note the final cost in GPT -; depends on gov't type). Set <= 0 to disable. -extra_unit_maintenance_per_shields = 0 - -; This option renames players' civs depending on their eras. The format is a list of names each associated with a list of replacements. There is one -; replacement for each era or, if the list is shorter than the number of eras, no replacement will be done in the later eras. Example: -; [Rome: Rome "Byzantine Empire" Italy Italy, -; Roman: Roman Byzantine Italian Italian, -; France: Gaul, French: Gaulic] -; In this example, Rome will be renamed to "Rome" in the first era, "Byzantine Empire" in the second, and "Italy" in the third and fourth. The -; adjectives will be replaced to match. France/French will be renamed to Gaul/Gaulic only in the first era. -; Spaces are used to separate words so if a name or replacement has multiple words it's necessary to use quotation marks to group them together like -; for "Byzantine Empire" in the example. -; The replacements apply to civ nouns, adjectives, and formal names. If a player has put in a custom name, that will not be replaced. -civ_aliases_by_era = [] - -; This option works like the one above except it replaces leader names instead of civ names. Each replacement name may be followed by (M) or (F) to -; specify gender. Example: -; ["Joan d'Arc": Vercingetorix (M) "Joan d'Arc" (F) Napoleon (M) "De Gaulle" (M)] -; If no gender is specified then the game will use whatever gender was set in the scenario data for that civ's leader. That means (F) could be omitted -; in the above example since the leader of France is already female. -; Additionally you can include a replacement title after the gender separated by a comma. Here's the example with titles added: -; ["Joan d'Arc": Vercingetorix (M, King) "Joan d'Arc" (F) Napoleon (M, Emperor) "De Gaulle" (M, President)] -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 -; 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. -; 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. -unit_limits = [] - -; Removes barracks/harbor/airport requirement from upgrades -allow_upgrades_in_any_city = false - -; Stops the game from placing volcanos during map generation. Any tiles that would have been volcanos will be mountains instead. -do_not_generate_volcanos = false - -; Stops the game from placing pollution on impassable tiles -do_not_pollute_impassable_tiles = false - -; Includes the hitpoints of each possible target on the stealth attack selection popup. This makes it easier to pick out weakened units. -show_hp_of_stealth_attack_options = false - -; Stops invisible units from being targeted by stealth attacks. They can still be targeted if they've been revealed by the attacking civ. -exclude_invisible_units_from_stealth_attack = false - -; Stops units from being targeted by stealth attack if they are contained in another unit such as a naval or land transport, or a helicopter. -exclude_passengers_from_stealth_attack = false - -; Normally planting a forest always produces the regular non-LM forest terrain. This option changes that so it instead produces LM forest. -convert_to_landmark_after_planting_forest = false - -; This option specifies how likely it is (in percent) for a combat land or sea unit with a maximum of one HP to be destroyed when struck by a -; nuke. Set to 100 for base game behavior. -chance_for_nukes_to_destroy_max_one_hp_units = 100 - -; Allows you to sell aqueducts and hospitals as well as any modded buildings that uncap population growth. A city must be below the pop cap for a sale -; to be allowed, i.e., under the standard rules, aqueducts may only be sold in cities of pop <= 6 and for hospitals pop <= 12. -allow_sale_of_aqueducts_and_hospitals = false - -; Allows you to sell Small Wonders. This may be useful to relocate Forbidden Palace-like Small Wonders. -allow_sale_of_small_wonders = false - -; This option makes it so that only sea units with the "detect invisible" ability can reveal invisible sea units, and likewise for non-sea units. -no_cross_shore_detection = false - -; Controls the size of the area in which cities can work tiles. The value corresponds to cultural border expansions. For example, setting this to 1 -; means cities would only be able to work tiles within their level 1 cultural borders, meaning the eight tiles neighboring the city's own -; tile. Setting to 2 gives you the game's standard rule that cities may work tiles within their level 2 cultural borders, which they attain after one -; expansion. Setting to 3 allows them to work within level 3 borders and so forth. -; Notes: (1) If the city can work tiles in the fourth ring or farther, the map view on the city screen will be zoomed out when you enter it if -; auto_zoom_city_screen_for_large_work_areas is true. Otherwise it's not possible to show the entire work area. You can zoom back in by pressing Z. -; (2) The next option below can limit cities' workable areas to be smaller than the radius set here, based on their culture. (3) This option has a -; minimum value of 1 and a maximum of 7. -city_work_radius = 2 -auto_zoom_city_screen_for_large_work_areas = true - -; This option can reduce the size of the area cities can work based on their cultural level. -; Possible values are: -; none: Standard game rules apply; cities can work any tile that's within the work radius and within their owner's borders. -; cultural: Cities may only work tiles that are within their direct cultural borders, e.g. a city with zero culture may only work the 8 surrounding -; tiles. After one expansion, it may work the standard 20, after a second expansion it may work the third ring, and so on. -; cultural-min-2: Like "cultural" except cities can always work their standard 20 tiles. -; cultural-or-adjacent: Cities can work tiles in their direct cultural borders plus any tiles adjacent to those. -work_area_limit = none - -; This option can also reduce the size of the area cities can work based on improvements present. -; This mechanic works in tandem with the above work_area_limit condition - tiles cannot be worked if the tiles do not also meet the cultural work area limit requirement. -; If left empty, this mechanic is not used. -; Improvements may be defined to grant a certain radius work area, and the highest radius present is used as the work radius for a city. eg ["Harbor": 3] -; Improvements may also grant a bonus radius, these are added on after the highest radius is found. [Factory: 3, "Mass Transit": 2 extra] -; An entry written as default or "default" will always be present for any given city, and represents an always-present virtual improvement. eg. ["default": 2] gives vanilla behaviour. -work_area_improvements = [] - -; The maximum distance it's possible to rebase an aircraft equals its operational range times this value. For standard game rules, set to 6. -rebase_range_multiplier = 6 - -; This option prevents units from loading into two different transports on the same turn. Once a unit has been loaded into a transport, it becomes -; tied to that transport for the remainder of the turn and cannot be loaded into any other. Loading into armies is not affected. The purpose of this -; option is to make the galley chaining exploit impossible. -limit_unit_loading_to_one_transport_per_turn = false - -; In the base game, if you set Cavalry to upgrade to Tank but don't give it the upgrade ability, intending to make Cavalry obsolete when Tanks become -; available but not upgradable to them, you'll be left with the strange situation that older units such as Knights are allowed to upgrade to Tanks -; even though Cavalry are not. This option makes it so that Knights upgrade to Cavalry in that case. In general, it makes it so that upgrade chains -; stop at the type along the chain that does not have the upgrade ability. -; NOTE: The chain is only stopped if the civ in question can build the unit type. The example above is simplified. In the actual rules, Cavalry -; upgrades to Sipahi, which upgrades to Cossack. Blocking the upgrade chain at Cavalry would prevent Ottomans and Russia from upgrading to their -; unique units, so the mod won't do that. You must clear the upgrade ability from Sipahi and Cossack as well to block those civs there instead. -prevent_old_units_from_upgrading_past_ability_block = false - -; Buildings double their culture production this many years after they were built. For standard game rules, set to 1000. -years_to_double_building_culture = 1000 - -; Controls how long it takes for wonders to produce tourism gold as a percent of the standard rate. For example, if set to 200, it would take 2000 -; years to begin generating 2 GPT tourism, instead of the standard 1000 years, and 3000 years for 4 GPT, instead of the standard 1500. This setting is -; effectively a scaling factor on the tourism time thresholds. For standard rules, set to 100. -tourism_time_scale_percent = 100 - -; On the first turn of a hotseat game, all human players will be given diplomatic contact with each other. -introduce_all_human_players_at_start_of_hotseat_game = false - -; Allows units to be unloaded from an army. The army type must have the "unload" ability set in the editor. -allow_unload_from_army = false - -; Allow colonies to be built on tiles inside another civ's territory (for strategic/luxury resources); applies a relation penalty with the other civ, per each colony. -allow_extraterritorial_colonies = false -per_extraterritorial_colony_relation_penalty = 3 - -; A list of rule modifications to make land transports more practical. Works like special_defensive_bombard_rules. The possibilities are: -; load-onto-boat: Allows land transports to be loaded into naval units -; join-army: Allows empty land transports to join armies -; no-defense-from-inside: Prevents units inside a land transport from defending their tile, performing defensive bombard, or intercepting air units -; no-escape: Destroys the passengers inside a land tranport when the transport itself is destroyed or captured -land_transport_rules = [] - -; Prevents land anti-air units from intercepting overflying units while they're loaded in a naval transport -no_land_anti_air_from_inside_naval_transport = false - -; A list of rule modifications for air units with transport capacity called "helicopters" for short. Works like special_defensive_bombard_rules. The -; possibilities are: -; allow-on-carriers: Allows helicopters to be rebased or loaded onto carriers -; passenger-airdrop: Allows paratroopers inside a helicopter on a carrier to perform airdrops -; no-defense-from-inside: Prevents units inside a helicopter from defending their tile, performing defensive bombard, or intercepting air -; units. Also destroys passengers when the helicopter is destroyed in most circumstances in order to avoid problems such as a helicopter being -; captured by a land unit leaving its passengers alive on the same tile. -; no-escape: In all circumstances, destroys the passengers inside a helicopter when the heli itself is destroyed or captured -special_helicopter_rules = [] - -; Stops units from enslaving a target they've destroyed by bombarding as opposed to direct combat -prevent_enslaving_by_bombardment = false - -; Relaxes a rule that prevents resources from appearing directly next to another resource of a different type -allow_adjacent_resources_of_different_types = false - -; Controls the overall number of luxury resources placed on the map for luxury types that don't have a fixed appearance rate set in the editor. Under -; the standard rules, no luxuries have appearance rates set. Without a set rate, the game randomly chooses a rate between 50 and 100, biased toward -; the middle (75). This setting is a percent scaling on that range, so setting it to 150 means luxuries would have their rate randomized between 75 -; and 150, setting to 50 means a range of 25 to 50, and so on. For base game behavior, set to 100. -luxury_randomized_appearance_rate_percent = 100 - -; During map generation, the game places bonus resources until the total number of strategic and bonus resources reaches the tile count divided by -; this number. Raising this setting causes fewer bonus resources to be generated and lowering it increases them. For the standard rate, set to 32. -tiles_per_non_luxury_resource = 32 - -; Normally the corruption rate in the capital is fixed at zero. Setting this to true removes that, allowing corruption to appear in the capital. The -; capital also has a strong inherent bonus reducing corruption so even when this setting is on, it will usually have zero corruption. To reduce that -; bonus, see the special_capital_decorruption_effect option below. -allow_corruption_in_capital = false - -; Controls the special decorruption bonus that's applied to the capital. This bonus is incorporated into the decorrupting effect from buildings in the -; city and each point is equivalent in strength to one courthouse. For standard game rules, set to 10. This option does nothing unless -; allow_corruption_in_capital is set to true. Min value 0, max 100. -special_capital_decorruption_effect = 10 - -; Overrides the NoAIPatrol setting from conquests.ini. Possible values are: -; none: No override, use the setting from the INI like normal -; one: Set NoAIPatrol to 1, disabling AI patrol behavior -; zero: Set NoAIPatrol to 0, allowing AI units to patrol -; The purpose of this option is to enable you to configure NoAIPatrol like a C3X setting instead of globally. In particlar, it allows you to configure -; NoAIPatrol on or off on a per-scenario basis. -override_no_ai_patrol = one - -; Overrides the barbarian activity level when starting a new game for a scenario with a custom map. Normally, in that case, the game will use the -; barbarian settings kept in conquests.ini, ignoring what was set for the map in the editor. This option allows you to set an activity level on a -; per-scenario basis like other C3X settings. -; The possible values are "none" for no override, i.e. base game behavior, or one of the selectable barbarian activity levels: "No Barbarians", -; Sedentary, Roaming, Restless, Raging, or Random. You can specify either the original English names just listed or the custom/translated names in -; labels.txt. The value is not case sensitive. -override_barbarian_activity_level_for_scenario_maps = none - -; Leader units placed on the map as part of a scenario do not have their leader types filled in properly, which means they behave differently than -; proper military leaders would. In particular, they are allowed to hurry production of great wonders and spaceship parts. This option fills in their -; types at the start of the game so they behave like normal MGLs spawned during a game. -initialize_preplaced_scenario_leaders_as_mgls = false - -enable_unit_counters = false - -; Civ 4 style best defender selection. -; When this is on (and enable_unit_counters is also true), every time an attack happens the engine picks the -; defender that is HARDEST for the current attacker to beat (the unit with the highest defender win rate -; once unit-counter rules are applied), instead of the vanilla "highest defense strength" rule. The same -; unit is also forced to the top of the enemy stack on the map whenever a player has an attacker selected, -; so the displayed unit stays in sync with what would actually fight. Re-targeting is automatic: switching -; the selected attacker (different counter match-ups) updates which enemy unit is shown as the best defender. -; Notes: -; - Has no effect when enable_unit_counters = false (then there's nothing to differentiate beyond defense). -; - Applies to both human and AI attackers, so the rule is consistent. -; - Does not change ranged-bombard or defensive-bombard target selection, only normal attacks. -use_civ4_style_best_defender = false - -; unit_group allows you gruop your units in a group,please refer to building_prereqs_for_units for the format. -; This function will not work if enable_unit_counters is false. -unit_group = [] -; ── counter_rule format ────────────────────────────────────────────────────────────── -; -; counter_rule = [Friendly vs Enemy Effect... Conditions...] -; -; 【Friendly / Enemy】 -; This can be one of the following three options: -; · The specific unit type, such as "Archer" (must match the name in BIQ exactly; names containing spaces must be enclosed in quotation marks) -; · A unit group name, such as melee (i.e. the group defined in the unit_group section above) -; · "*" represents any unit type (the asterisk must be enclosed in quotation marks) -; -; 【Effect】(Expressed as a percentage; when multiple rules apply to the same battle, their effects are multiplied.) -; -; "self" always refers to the first unit, and "enemy" always refers to the second unit, regardless of who is attacking whom: -; self-atk value — The unit’s attack power becomes N% of its original value -; Example: self-atk 150 = attack power ×1.5; self-atk 50 = attack power ×0.5 -; self-def value — Your defence becomes N% of the original value; -; enemy-atk value — The enemy’s attack becomes N% of the original value; -; enemy-def value — The enemy’s defence becomes N% of the original value; -; -; 【Conditions】(Optional; leaving blank indicates no restrictions; conditions take effect only when all are met simultaneously) -; in-city —— Takes effect only when the enemy is on a city tile -; terrain terrain_name -- Takes effect only when the enemy is on a tile of the specified terrain -; Uses the same lower-case English terrain tokens as districts_config buildable_on, not BIQ/localized names. -; Examples: grassland, hills, coast, snow-forest, snow-mountain, snow-volcano, lake -; ignore-terrain —— Ignores the enemy’s terrain defence bonus (sets their terrain bonus to zero) -; Can be used in conjunction with enemy-def; when used together, ignore-terrain takes precedence -; district district_name -- Only takes effect when the enemy is in a specified district (enable_districts must be enabled) -; District names are resolved after districts_config loads, so dynamic district names are supported. -; -; 【Examples】 -; counter_rule = [ranged vs melee self-atk 125] -; → When a ranged unit attacks a melee unit, its attack power is multiplied by 1.25 -; -; counter_rule = ["Knight" vs melee in-city enemy-def 150] -; → When knights attack melee units within a city, the enemy’s defence is multiplied by 1.5 -; -; counter_rule = ["Musketman" vs "Medival Infantry" terrain grassland self-atk 125] -; → When musketeers attack medieval infantry on grassland terrain, their attack power is multiplied by 1.25 -; -; counter_rule = ["Knight" vs "*" ignore-terrain self-atk 150] -; → When a Knight attacks any unit, its attack power is multiplied by 1.5 and it ignores the enemy’s terrain bonus. -; counter_rule = [Archer vs Swordsman self-atk 130 self-def 120] -; → When an archer attacks a swordsman: Archer’s attack power ×130% -; When a swordsman attacks an archer: Archer’s defence ×120% -; -; ───────────────────────────────────────────────────────────────────────────── - -counter_rule = [] - -[==================] -[=== AESTHETICS ===] -[==================] - -; If a tile has a forest, render it on top of roads and railroads, instead of underneath them. -draw_forests_over_roads_and_railroads = true - -; This allows you to set a victory animation for air units. Can be set to the name of any animation that is loaded by the game, specifically one of: -; blank, default, run, attack1, attack2, attack3, death, fortify, fidget, victory, capture, fortress, build, road, mine, irrigate, jungle, forest, plant -; Note that bomber units already have their bombing animations in the victory slot so "victory" is not a good choice here. For standard game behavior, -; set to "none". -aircraft_victory_animation = none - -; Enables naming tiles via the right-click menu and displays those names on the map. -enable_named_tiles = true - -[=======================] -[=== DAY/NIGHT CYCLE ===] -[=======================] - -; How the day/night cycle operates in the game. If enabled, terrain, cities, resources, landmarks and terrain buildings will change appearance based on -; the time of day, with 24 possible stages (one for each hour). The base game art is used for 12pm. If set to 'off', only base game art will be used. -; Day/night cycle should not be used if you are using non-standard terrain art or resources. Doing so may result in visual glitches or missing art. -; Note that day/night cycle art is not bundled directly with C3X and must be downloaded separately at https://forums.civfanatics.com/resources/day-night-cycle-in-civ-3-using-c3x.32520/ -; The possible values are: -; off: Only base game art used -; timer: Increment based on time elapsed since last hour transition (e.g., transition to next hour every 3 minutes) -; user-time: Match the user's system clock to determine hour of the day -; every-turn: Increment every turn by a fixed amount of hours -; specified: Pin the hour to a specific value (so hour of day is always the same) -day_night_cycle_mode = off - -; If day_night_cycle_mode is set to 'timer', minimum minutes of real time to elapse before transitioning to the next hour in the cycle. -; This is checked only at the end of the turn, so actual minutes may exceed this number. -elapsed_minutes_per_day_night_hour_transition = 3 - -; If day_night_cycle_mode is set to 'timer' or 'every-turn', the number of hours to transition. This should be a value between 1 and 12 inclusive. -fixed_hours_per_turn_for_day_night_cycle = 1 - -; If day_night_cycle_mode is set to 'specified', the hour of the day to pin the cycle to. This should be a value between 0 (midnight) and 23 (11pm) inclusive. -pinned_hour_for_day_night_cycle = 0 - -[=======================] -[=== NATURAL WONDERS ===] -[=======================] - -; Show or hide natural wonders on the map. When disabled, natural wonders will not appear on the map. -enable_natural_wonders = true - -; If a new scenario is loaded which has no natural wonders defined, add natural wonders. -add_natural_wonders_to_scenarios_if_none = false - -; Show the names of natural wonders on the map below their image. -show_natural_wonder_name_on_map = true - -; Minimum separation (in tiles) between natural wonders when generating the map. This helps prevent clustering of natural wonders. -minimum_natural_wonder_separation = 10 - -[=================] -[=== DISTRICTS ===] -[=================] - -; Districts are Civ6-inspired structures built by workers that enable buildings, provide bonuses, and make cities feel more alive. When enabled, -; districts appear on the map and can be required for certain buildings (configured in default.districts_config.txt). Districts occupy tiles within a -; city's work radius, making those tiles unworkable. They can provide bonuses (food, shields, gold, science, culture, defense) to all cities within -; their work radius. If multiple cities share a district, they can optionally share its buildings and wonders (see options below). Districts with -; pollution or enemy units yield no bonuses. Destroyed districts remove dependent buildings from affected cities unless they have another district of -; that type in range. The five district types below can be enabled independently: -; enable_districts: Enables standard configurable districts (by default: Encampment, Campus, Holy Site, Commercial Hub, Entertainment Complex, Industrial Zone). -; Configured is done in default.districts_config.txt, user.districts_config.txt, and scenario.districts_config.txt -; enable_neighborhood_districts: Enables population growth past a configurable limit (see maximum_pop_before_neighborhood_needed below) -; enable_wonder_districts: Wonders require a dedicated district tile, making them visible on the map and optionally destructible. -; Configured in default.districts_wonders_config.txt, user.districts_wonders_config.txt, and scenario.districts_wonders_config.txt -; enable_distribution_hub_districts: Special districts that distribute food/shields from surrounding tiles to all connected cities -; enable_aerodrome_districts: Air units can only be built/based at Aerodrome districts instead of cities (if air_units_use_aerodrome_districts_not_cities is true) -; enable_port_districts: Enables Port districts, which serve as coastal district tiles for naval production/basing when naval_units_use_port_districts_not_cities is on. -; enable_bridge_districts: Enables Bridge districts on coastal water; completed bridges let land units cross water tiles. -; enable_canal_districts: Enables Canal districts on land; completed canals let naval units traverse land tiles between water bodies. -; enable_central_rail_hub_districts: Enables Central Rail Hub districts used for rail-era infrastructure (e.g., Mass Transit). -; enable_energy_grid_districts: Enables Energy Grid districts associated with power plant infrastructure. -; enable_great_wall_districts: Enables Great Wall districts (wall-like tiles that can block others if great_wall_districts_impassible_by_others is on). -enable_districts = false -enable_neighborhood_districts = false -enable_wonder_districts = false -enable_distribution_hub_districts = false -enable_aerodrome_districts = false -enable_port_districts = false -enable_bridge_districts = false -enable_canal_districts = false -enable_central_rail_hub_districts = false -enable_energy_grid_districts = false -enable_great_wall_districts = false - -; When multiple cities share a district (i.e., the same district tile is within multiple cities' work radii), these options control whether those -; cities automatically share the benefits of buildings and wonders constructed in that district. For example, if Rome and Veii both have the same -; Encampment in their work radius and Rome builds a Barracks in that Encampment, enabling cities_with_mutual_district_receive_buildings will cause -; Veii to automatically receive a Barracks as well. Similarly, cities_with_mutual_district_receive_wonders extends this sharing to Great and Small -; Wonders. This encourages strategic district placement between cities and can reduce micromanagement in dense urban areas. -; Note: receiving buildings is only assessed twice: when a city completes a building, and when a city is founded nearby. A city receiving a building -; cannot in turn recursively share it with third, fourth, fifth, etc. cities in a chain. Only applies if enable_districts is set to true. -cities_with_mutual_district_receive_buildings = true -cities_with_mutual_district_receive_wonders = true -show_message_when_building_received_by_mutual_district = true -show_message_when_building_lost_to_destroyed_district = true - -; When enabled, air units can only be built in cities with an Aerodrome district in their work radius and must be based at Aerodrome districts instead -; of cities. Air units will spawn on Aerodromes and can only land on Aerodromes, vanilla airfields, or carriers. Airlifts and airdrops are similarly -; limited to Aerodromes. This adds strategic depth by requiring infrastructure for air power and making air bases visible and vulnerable on the map. -; Only applies when enable_aerodrome_districts is also set to true. -air_units_use_aerodrome_districts_not_cities = true - -; When enabled, naval units can only be built in cities with a Port district in their work radius and cannot enter city tiles directly. Naval unit -; healing must be done at Port districts, and travel between continents, lakes and so on can instead only be done via Canal districts (via enable_canal_districts), -; rather than cities on an isthmus. Additionally, a city cannot build naval units until it has a Port district in range. Only applies when enable_port_districts is set to true. -naval_units_use_port_districts_not_cities = true - -; Neighborhood district limit population growth. Once a city reaches maximum_pop_before_neighborhood_needed, it cannot -; grow further until it has at least one Neighborhood district in its work radius. Each Neighborhood then enables additional population growth equal to -; per_neighborhood_pop_growth_enabled. For example, with maximum set to 6 and per_neighborhood set to 2, a city can grow to pop 6 without -; Neighborhoods, requires 1 Neighborhood to reach pop 8, requires 2 Neighborhoods to reach pop 10, and so on. Neighborhood bonuses (+1 gold and +1 -; culture, by default) only apply if the city actually needs them based on its population. Periodic popups will remind you when a Neighborhood is needed. Only -; applies when enable_neighborhood_districts is set to true. neighborhood_needed_message_frequency sets how often (in turns) the reminder message appears; -; set to 0 to disable. -; If destroying_neighborhood_reduces_pop is true, losing a Neighborhood district reduces the city's population down to the new cap. -maximum_pop_before_neighborhood_needed = 6 -per_neighborhood_pop_growth_enabled = 3 -neighborhood_needed_message_frequency = 4 -destroying_neighborhood_reduces_pop = true - -; These options control the vulnerability and rebuildability of completed Wonders in Wonder districts. When completed_wonder_districts_can_be_destroyed -; is enabled, completed Wonders (both Great and Small) can be pillaged or destroyed by enemies, making them valuable strategic targets that must be -; defended. When destroyed_wonders_can_be_built_again is enabled, destroyed Wonders become available again for any civ to build, putting them back -; into play. Only applies when enable_wonder_districts is set to true. -completed_wonder_districts_can_be_destroyed = true -destroyed_wonders_can_be_built_again = true - -; Distribution Hubs work as "breadbaskets" and mining areas far from urban centers, minimizing local city potential but benefiting the entire civilization. -; Distribution Hubs make surrounding tiles unworkable and instead distribute their raw food and shield yields to ALL connected cities in your civilization. -; "Divisors" for food and shields multiply the sqrt-based divisor in scale-by-city-count mode, and are a straight divider in flat mode. Yields are subject -; to corruption as with regular shields. -; -; ai_ideal_distribution_hub_count_per_100_cities controls how many hubs the AI tries to maintain per 100 cities if distribution_hub_yield_division_mode -; is set to "flat" (e.g., 25 means the AI aims for 1 hub per 4 cities). -; -; distribution_hub_yield_division_mode controls how a hub splits its collected food/shields across connected cities: -; flat: Divide raw yields by the configured divisors (distribution_hub_food_yield_divisor & distribution_hub_shield_yield_divisor) -; scale-by-city-count: Bonuses gradually reduce as more cities plug into the hub. Formula: floor(raw_yield / (sqrt(connected_city_count) * divisor)) -; -; ai_distribution_hub_build_strategy controls how the AI decides to build distribution hubs: -; by-city-count: AI builds hubs based on its ideal hub count per 100 cities -; auto: AI dynamically assesses need based on city growth and food/shield deficits across civ -distribution_hub_yield_division_mode = scale-by-city-count -ai_distribution_hub_build_strategy = auto -distribution_hub_food_yield_divisor = 2 -distribution_hub_shield_yield_divisor = 2 -ai_ideal_distribution_hub_count_per_100_cities = 50 -max_distribution_hub_count_per_100_cities = 50 - -; Bonus percent applied to Distribution Hub food and shield yields for cities that have a Central Rail Hub district in their work radius. -central_rail_hub_distribution_food_bonus_percent = 25 -central_rail_hub_distribution_shield_bonus_percent = 25 - -; District placement and AI bridge/canal behavior: -; expand_water_tile_checks_to_city_work_area: Use the full city work radius (not just adjacent tiles) for river/lake/sea checks (e.g. to build a port if a -; city has coast within its work area, even if not adjacent to the sea). -; Note that this does not affect Aqueducts or Coastal Fortresses, which still require direct city adjacency. -; workers_can_enter_coast: Allow workers to move onto coast tiles without embarking. -; max_contiguous_bridge_districts: Maximum number of contiguous bridge district tiles allowed in a line (0 = no limit). -; max_contiguous_canal_districts: Maximum number of contiguous canal district tiles allowed in a line (0 = no limit). -; ai_canal_eval_min_bisected_land_tiles: Minimum land tiles required on each side for the AI to consider a canal candidate. -; ai_bridge_canal_eval_block_size: Map block size used when scanning for AI bridge/canal candidates. -; ai_bridge_eval_lake_tile_threshold: Water bodies at or below this size are treated as lakes for AI bridge evaluation. -; ai_can_replace_existing_districts_with_canals: Allow the AI to build canal/bridge districts over existing non-wonder districts. -; ai_builds_bridges: Allow the AI to construct bridge districts. -; ai_builds_canals: Allow the AI to construct canal districts. -expand_water_tile_checks_to_city_work_area = true -workers_can_enter_coast = true -max_contiguous_bridge_districts = 3 -max_contiguous_canal_districts = 5 -ai_canal_eval_min_bisected_land_tiles = 20 -ai_bridge_canal_eval_block_size = 10 -ai_bridge_eval_lake_tile_threshold = 5 -ai_can_replace_existing_districts_with_canals = true -ai_builds_bridges = true -ai_builds_canals = true - -; When enabled, AI defensive units will actively seek out and defend districts within their territory, treating them as valuable assets like colonies. -; The AI prioritizes defending Wonder districts (if destructible wonders are enabled) over regular districts, searching within a 20-tile radius for -; districts that need protection from nearby enemy units. This makes districts meaningful strategic targets and ensures the AI protects its -; infrastructure. Only applies when enable_districts is set to true. -ai_defends_districts = true - -; As AI cities queue up districts needed, the max number of turns to wait for a worker to build it before the request is dropped -; until the AI city is triggered to build the district again (e.g., by trying to build a building that depends on it) -ai_city_district_max_build_wait_turns = 20 - -; Great Wall behavior: -; disable_great_wall_city_defense_bonus: Disables the Great Wall wonder's city defense doubling effect. Only takes effect if districts and great wall districts are enabled. -; great_wall_districts_impassible_by_others: Great Wall district tiles block movement by other civs (unless obsolete). -; auto_build_great_wall_around_territory: Auto-place Great Wall districts along your borders when the specified wonder is built. -; great_wall_auto_build_wonder_name: Name of the wonder that triggers auto-building (empty disables auto-build). -; ai_auto_build_great_wall_strategy: How AI uses auto-built Great Wall: all-borders (any border tiles) or other-civ-bordered-only (only borders touching another civ). -disable_great_wall_city_defense_bonus = false -great_wall_districts_impassible_by_others = true -auto_build_great_wall_around_territory = true -great_wall_auto_build_wonder_name = "The Great Wall" -ai_auto_build_great_wall_strategy = other-civ-bordered-only - -; When enabled, holding down the Control key while a worker is selected will highlight all tiles within the work radii of nearby cities. City centers -; are highlighted more brightly, while tiles that fall within multiple cities' work radii are highlighted more intensely. This visual aid helps you -; strategically place districts and improvements by showing which cities will be affected. The highlights update dynamically as you move the worker -; around the map. Only applies when enable_districts is set to true. -enable_city_work_radii_highlights = true +[====================================================== C3X RELEASE 27 PREVIEW 2 DEFAULT CONFIG =====================================================] +[======================================================================= NOTE =======================================================================] +[Instead of editing this file, changes to the settings should be placed in either the scenario or custom config files. The scenario config file must ] +[be named scenario.c3x_config.ini and must be located in your scenario search folder. Of course it only applies if you are using a scenario. The ] +[custom config file must be named custom.c3x_config.ini and located in the C3X folder, which is the folder where this file is. When creating scenario] +[or custom configs, it is only necessary to include the settings you wish to change. ] +[====================================================================================================================================================] + +[============================] +[=== CONVENIENCE FEATURES ===] +[============================] + +enable_stack_bombard = true +enable_stack_unit_commands = true +enable_disorder_warning = true +show_detailed_city_production_info = true +enable_trade_screen_scroll = true +autofill_best_gold_amount_when_trading = true +skip_repeated_tile_improv_replacement_asks = true +group_units_on_right_click_menu = true + +; On the right click menu, units with no remaining moves will appear in gray text +gray_out_units_on_menu_with_no_remaining_moves = true + +; Places an icon next to units on the right-click menu showing their remaining moves & status. The icon is green for unmoved units, red for units that +; have exhausted all their moves, and yellow for those in between. Additionally it contains a little sword for units that can still attack and is +; colored blue for fighters set to intercept. +put_movement_icons_on_units_on_menu = true + +; Replaces the "Wake" or "Activate" text on the right-click menu with more descriptive words indicating what the unit is currently doing. For example, +; "Moving", "Intercepting", or "Working". +describe_states_of_units_on_menu = true + +show_detailed_tile_info = true +show_golden_age_turns_remaining = true + +; This option causes the game to show attack animations for units exerting zone of control from the middle of their tile's stack. Otherwise the game +; will only show such animations for units that are the top visible unit on their tiles. It was presumably an oversight by the original developers +; that units exerting zone of control do not temporarily become the visible unit on their tiles (unlike, for example, defensive bombard). +show_zoc_attacks_from_mid_stack = true + +; Fixes the defensive bombard animation being skipped when the unit performing defensive bombard is inside an army. +show_armies_performing_defensive_bombard = true + +cut_research_spending_to_avoid_bankruptcy = true +dont_pause_for_love_the_king_messages = true + +; Holding shift when clicking a specialist on the city screen will switch to the previous, instead of the next, specialist type +reverse_specialist_order_with_shift = true + +; Pressing the Z key on the city screen will zoom the map in/out +toggle_zoom_with_z_on_city_screen = true + +; When king units are spawned they're named after the leader of their civ. This is undesirable in modded games where the king flag is often used +; on units that aren't intended to be actual kings. This setting helps by bypassing the king unit naming logic when regicide is not enabled. +dont_give_king_names_in_non_regicide_games = true + +; One of the game's "Easter eggs" is that all king-flagged units appear as Elvis Presley on his birthday (Jan 8). This can be annoying when playing +; mods that make wide use of the king flag. +no_elvis_easter_egg = false + +; Removes option to automate workers from the human player. Useful for those who never want to use automation but sometimes accidentally activate it. +disable_worker_automation = false + +; There is a limit to how many links can appear on each Civilopedia page. Some mods exceed that limit. The problem is that the game throws up a popup +; when the limit is exceeded, one popup for each link beyond the limit. That can result in dozens of annoying, useless popups. This option stops them +; from appearing. Note: the game may also crash if the number of links far exceeds the limit. This option does not stop the crash, just the popups. +suppress_hypertext_links_exceeded_popup = true + +; Replaces the text "Upgrades To" with "Obsoleted By" in the Civilopedia for unit types that go obsolete but cannot be upgraded to their successors. +indicate_non_upgradability_in_pedia = true + +; Shows a message when a bomber gets intercepted by enemy air defense buildings but succeedes on its roll to avoid damage. Without this message, there +; is no indication that anything happened in that case except for the bomber losing one movement point. +show_message_after_dodging_sam = true + +; Normally only the last human player in a hotseat game gets to see the AIs move their units since the game processes the interturn while that player +; is still seated. This setting shows the AI moves to the other players in the game. It works by creating a save just before the interturn processing +; happens and then, at the start of the other players' turns, loads the save, sets that player as the seated one, reprocesses the interturn, then +; resumes the original game. +; Note: If the game is manually saved and reloaded, the replay will be lost. So it is recommended to save the game only after all human players have +; seen the replay, i.e. during the last or second to last human players' turns. +replay_ai_moves_in_hotseat_games = false + +; Normally, when you load a save, all units face southeast because the game didn't record which direction they were facing when the save was +; created. However, the game does record which tile they were on before their most recent move, so it is possible to deduce which direction they +; should be facing. That's what this option does. +restore_unit_directions_on_game_load = true + +; The game stores your map grid setting (on or off) in conquests.ini. It applies that setting after creating a new game, but not after loading a +; save. That was presumably an oversight and is corrected by this config option. +apply_grid_ini_setting_on_game_load = true + +; Causes cities to display harbor/airport icons if they have buildings that grant the relevant unit effects (produce veterans & heal in one turn) +; instead of buildings that grant sea/air trade. This makes no difference under the standard rules but is useful with mods that separate the unit +; effects and trade abilities into different buildings. +city_icons_show_unit_effects_not_trade = true + +; The game rules do not permit aircraft in an airfield to be damaged by bombardment. The interface allows players to order such bombardments anyway +; since its logic to check target validity is incomplete. This option completes the logic, causing the interface to reject attempts to bombard an +; airfield which would have no effect. +disallow_useless_bombard_vs_airfields = true + +; This option fixes a graphical bug that appears when the game is run on Linux using Wine. The bug is caused by the game using both Windows GDI and +; OpenGL to draw to the same canvas. Because the game only uses OpenGL to draw lines, it's relatively easy to solve this issue by reimplementing line +; drawing using Windows GDI+ instead. There are three possible settings for this option: +; never: Self-explanatory +; wine: This change will only be applied if the mod detects the game is running on Wine +; always: This change will always be applied, even on an actual Windows system +draw_lines_using_gdi_plus = wine + +; This option reduces the vertical distance between rows in the list of luxuries on the city screen. This allows up to 11 luxuries to be displayed +; neatly inside the box. +compact_luxury_display_on_city_screen = false + +; Similar to the option above, this one packs the strategic resources more tightly into the box on the upper left of the city screen. This allows up +; to 13 resources to be displayed there. +compact_strategic_resource_display_on_city_screen = false + +; Causes the domestic advisor to ask for confirmation before setting city production to a building that would replace another already built in the +; city. It's similar to how the domestic advisor warns you before a production switch would waste shields. Useful for modded games where you might not +; know which buildings replace which. +warn_when_chosen_building_would_replace_another = false + +; This option keeps citizens working the tiles they've been assigned to when pollution spawns there instead of converting them to specialists. This +; reduces micromanage but comes at the cost of the specialist yields. +do_not_unassign_workers_from_polluted_tiles = false + +; Normally the game draws capital cities one level larger than normal. I.e., a capital city at size 1 - 6 uses the graphic for cities at size 7 - 12, +; and a capital at size 7+ uses the graphic for cities 13+. This option turns that off, so capitals use the standard city graphics. +do_not_make_capital_cities_appear_larger = false + +; Tints coast and sea tiles on the minimap based on the culture that controls them, like is normally done for land tiles. +show_territory_colors_on_water_tiles_in_minimap = false + +; In offline games, shows some popup messages as online-multiplayer-style notes to the left of the screen instead of advisor popups that pause +; gameplay until dismissed. The point is to minimize interruptions during turn processing. Affects popups with the following text keys: +; SUMMARY_END_GOLDEN_AGE, SUMMARY_END_SCIENCE_AGE, SUMMARY_NEW_SMALL_WONDER, WONDERPRODUCE, MAKEPEACE, MUTUALPROTECTIONPACT, MILITARYALLIANCE, +; SUMMARY_DECLARE_WAR, TRADEEMBARGOENDS, SUMMARY_CIV_DESTROYED_BY_CIV, SUMMARY_CIV_DESTROYED, LOSTGOOD, TRADEEMBARGO, MILITARYALLIANCEWARONUS, +; MILITARYALLIANCEAGAINSTUS, and SUMMARY_TRAVELERS_REPORT. +convert_some_popups_into_online_mp_messages = false + +; If enabled, pressing the keys d e b u g to type "debug", in-game will allow you to activate debug mode for a game in progress. Typing that with +; debug mode already on will deactivate it. +enable_debug_mode_switch = true + +; Places a small shadow below city dots on the minimap to make them more easily visible especially against light-colored territory. This feature does +; not quite work properly so is left off by default. Its issues are (1) the shadows may not fully appear until you toggle the minimap from territory +; to geography mode and back again and (2) the shadows may appear in geography mode. +accentuate_cities_on_minimap = false + +; Makes the minimap twice as large. Possible values are "never", "always", and "high-def". The first two are self-explanatory; if set to "high-def", +; the minimap's size will be doubled when the game is run at a horizontal resolution of at least 1920 pixels. +double_minimap_size = high-def + +; Allows descriptions for units, civilizations, and game concepts to span multiple pages. If a DESC entry of one of those types is too long for one +; page, it will automatically be divided into multiple with buttons added for navigation. +allow_multipage_civilopedia_descriptions = true + +; Controls how the game searches for the next unit to autoselect. The possible choices are: +; standard: Base game behavior +; similar-near-start: The game will search for similar units near the starting point of the last selected unit. That means, when a unit is selected, +; the game remembers its location then searches out from there for a similar unit when cycling to the next one. Distance is prioritized over +; similarity, meaning the game will select all units on the starting tile no matter how dissimilar before any on nearby tiles. +; similar-near-destination: Like similar-near-start except the search goes outward from whatever tile the last selected unit was last on. +unit_cycle_search_criteria = standard + +; On the domestic advisor screen, tweaks how the number of turns remaining on each city build are displayed to improve readability. Instead of +; "(1turn)" or "(7turns)", the game will display "(1 Turn)" or "(7 Turns)" +reformat_turns_remaining_on_domestic_advisor_screen = true + +; On unit Civilopedia pages, shows the movement stat for aircraft, bombard range for tactical nukes, and HP bonus & worker strength if non-zero. +expand_civilopedia_unit_stats = true + +[====================] +[=== OPTIMIZATION ===] +[====================] + +; Rewrites the game's trade network computation logic to improve speed. On large maps with many cities, this computation takes up most of the +; interturn time so speeding it up greatly improves turn times. For more info, see the text file in the Trade Net X folder. +enable_trade_net_x = true + +; Rewrites parts of the game logic to improve efficiency. Those parts check every possible improvement defined in the scenario when they really only +; need to check a few. For example, to determine whether a city can trade via air, it's very wasteful to check every improvement since the vast +; majority of them do not enable air trade. This option can improve turn times very significantly in some circumstances. +optimize_improvement_loops = true + +; Displays a popup after each turn has been processed showing the time elapsed, including specifically how much time was spent recomputing trade +; networks. NOTE: Turning this on will skip all animations during the interturn so they don't contribute to the time. You aren't meant to play the +; game with this option left on. +measure_turn_times = false + +[=======================] +[=== AI ENHANCEMENTS ===] +[=======================] + +; Allows artillery unit AI to grab escorts from city defenders, causing the AI to use its artillery offensively instead of leaving it in its cities. +use_offensive_artillery_ai = true + +; If true, the AI will not escort its units unless they have the "requires escort" flag set in the editor. This allows modders to remove the escort +; requirement from certain types of units, for example artillery with non-zero defense. +dont_escort_unflagged_units = false + +; Set to a number to encourage the AI to build more artillery, set to false or <= 0 for no change in AI unit build choices. The number is how many +; artillery units the AI will try to keep around for every 100 non-artillery combat land units it has. The encouragement only applies if the AI is +; already above a minimum of one defensive unit per city and one offensive unit per two cities. Default: 16. +ai_build_artillery_ratio = 16 + +; The above option controls how many artillery the AI will keep around, this one controls how aggressively it builds up to that limit. More +; specifically it controls how valuable (in percent) the AI thinks artillery is as a damage dealer compared to attacking units. Default: 50. +ai_artillery_value_damage_percent = 50 + +; Like the artillery ratio, shifts the AI's build priority from fighters to bombers to keep around this many bombers per 100 fighters. Default: 70. +ai_build_bomber_ratio = 70 + +; Completely replaces the leader unit AI with custom code. The custom version is similar in spirit to the original but fixes several major issues: +; 1. It fixes a bug that allowed the AI to rush any kind of city production, including units and (with an MGL) wonders +; 2. Prioritizes army formation over rushing production when appropriate +; 3. When rushing, prioritizes wonders and costly improvements in high value cities +replace_leader_unit_ai = true + +; Replaces the AI code that determines whether a unit would be a good addition to an army. The replacement code fixes a major bug that prevented the +; AI from filling its armies, prevents the AI from including hidden nationality units in armies to avoid crashes, and removes some logic that +; encouraged the AI to mix unit types in armies. +fix_ai_army_composition = true + +; "Pop units" are special units whose only purpose is to be joined into cities to increase their population. Normally the AI does not know what to do +; with these units, so this option enables a routine that causes them to search for & join an appropriate city. Pop units only appear in some mods +; (for example Tides of Crimson). Under the standard game rules, this option has no effect. In order to function as a pop unit, a unit must use the +; terraform AI strategy, have no worker actions except join city, have a pop cost of at least 1, and have zero attack, defense, & bombard strengths. +enable_pop_unit_ai = true + +; "Caravan units" are special units whose only purpose is to be disbanded to contribute shields to a city. The name comes from the Civ 2 caravan. +; Caravan units may appear in some mods; under the standard game rules, this option has no effect. In order to function as a caravan unit, a unit must +; use the terraform AI strategy, have no worker actions enabled, have the ability to disband, and have zero attack, defense, & bombard strengths. +enable_caravan_unit_ai = true + +; In the base game, the AI will assign 1, 2, or 3 escort units to its naval transports and carriers depending in their shield cost and the number of +; units they're carrying. This option lets you reduce the upper limit on the number of escorts assigned. You can limit the number of escorts to 2, 1, +; or even 0. Setting this option >= 3 will result in base game behavior. The purpose of reducing the limit is to free up the AI's naval power units. +max_ai_naval_escorts = 3 + +; This controls how many workers the AI feels it needs as a percentage of the base amount. For example, if set to 150 (the default), the AI will build +; about 50% more workers than normal. Set to 100 for base game behavior. For more info, see: +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-95#post-16587093 +ai_worker_requirement_percent = 150 + +[=================] +[=== BUG FIXES ===] +[=================] + +; Descriptions of bugs and their fixes: +; SUBMARINE BUG -- The AI runs into invisible units (such as submarines) belonging to other players because it blindly follows paths produced for +; it by the game's pathfinder, which does not see invisible units. After colliding with an invisible unit, the AI initiates combat, declaring war if +; necessary. The mod fixes this bug by modifying the pathfinder so it sees invisible units belonging to other non-hostile players so it can route +; around them. +; SCIENCE AGE BUG -- The bonus science points generated by a scientific golden age are not actually counted towards research progress. They appear +; only on the interface. This is because of a small oversight in the code. There is a setting which controls whether or not science age bonus points +; are included while gathering all research points. It's turned off while gathering points to update research progress. The fix is to turn it on. +; PEDIA TEXTURE BUG -- There is a one pixel wide pink line on the right edge of the Civilopedia screen. This is because the width of the +; Civilopedia background texture is set one pixel too small inside the EXE. This is fixed simply by replacing the width with the correct value. +; BLOCKED DISEMBARK FREEZE -- When using "disembark all" (which the AI always does) on a boat containing units that can't be disembarked, the game +; may freeze as it endlessly tries to disembark them. The root of the problem is that the game's logic to check if there are any disembarkable units +; left on the boat is incomplete. There are two cases that it misses. First, it does not consider the "immobile" unit flag. This is fixed by making +; immobile units appear to have no remaining movement points for this bit of logic so they are correctly considered non-disembarkable. Second, it does +; not consider escort relationships (e.g. for settlers). If a unit has a non-disembarkable escorter then it also can't be disembarked because the game +; will always try to move its escorter ahead of it. The solution here is to clear all escort relationships for ship passengers before disembarking. +; HOUSEBOAT BUG -- The game may crash when an AI player is left alive with only a settler on a boat. This happens because the AI's logic tries to +; check the location of its capital city without considering that there may be no capital. The fix is to modify this logic so that when it looks up +; the location of a non-existent capital, it receives a valid "dummy" location that it can process without crashing. See also: +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16084386 +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16085242 +; INTERCEPT LOST TURN BUG -- When a human player sets a fighter to intercept mode, the game discards all of its remaining movement points, hence it +; cannot intercept during the next interturn. This bug does not affect the AI and is part of the interface logic, not the game logic. I presume it was +; inserted by a programmer who did not understand how the game's unit cycling works. The fix simply restores fighters' discarded moves. +; PHANTOM RESOURCE BUG -- The game only stores one full list of available resources per player. That list contains how many sources of each +; resource type are avaiable in that player's capital and all connected cities. Cities off the capital's network have reduced lists of just 32 bits, +; recording yes-or-no availability for up to 32 resources. Resources beyond the first 32 will share bits in those reduced lists. Specifically, the +; 33rd resource shares the same bit as the 1st, the 34th the same as the 2nd, and so forth. This causes "phantom" resources. For example, if a mod has +; horses set as the 1st resource and steel as the 33rd, then any city off its capital's trade network with access to horses will also have access to +; steel and vice-versa. The fix for this issue is straight forward but not simple. The jist is the mod allocates additional space for the reduced +; lists so they're not limited to 32 bits, rather have enough bits for every resource in the game. After that it's necessary to modify the code that +; accesses the reduced lists so it can make use of the additional space. +; MAINTENANCE PERSISTING FOR OBSOLETE BUILDINGS -- Players are not supposed to pay maintenance for obsolete city improvements however they often do +; because the game does not recompute maintenance after a player unlocks a technology that obsoletes a city improvement. There is a related exploit in +; that, after triggering a recomputation of maintenance, players can then sell their obsolete buildings to have the maintenance deducted again, +; effectively getting credited for the cost of maintenance. The mod fixes both issues. It recomputes maintenance costs when a player unlocks a +; technology that obsoletes a city improvement and it stops the game from deducting the maintenance cost of an obsolete city imp. when it's sold. +; BARBARIAN DIAGONAL BUG -- Barbarians can only search for targets on adjacent tiles or on tiles that are up to 12 steps directly SE or NW of their +; position. The intended behavior was for them to search for targets on all surrounding tiles up to 6 steps away. This bug was caused by a small, +; sloppy programming mistake that can be corrected with a small edit. For details, see: +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-70#post-16434678 +; DISEASE CURING TECH FLAG BUG -- In the base game, the tech flag "Disables Diseases From Flood Plains" (applied to Sanitation) does nothing and +; instead flood plains disease stops once players discover Writing. This happens because that flag is encoded as number 8 and, instead of checking if +; players have a tech with that flag, the code mistakenly checks if players have tech #8, which is Writing under the standard rules. Correcting this +; bug causes a lot more disease, which is a major annoyance, and so this bug fix is turned off by default. +; DIVISION BY ZERO IN AI ALLIANCE EVAL -- When considering whether to agree to a military alliance, the AI computes the distance from its capital to +; the nearest city belonging to the target of the alliance and divides by that distance. For unknown reasons, in rare cases that distance may be zero, +; which crashes the program due to division by zero. The mod fixes this issue by inserting a bit of logic after the distance is computed to check if +; it's zero and, if so, set it to one. +; EMPTY ARMY MOVEMENT -- Empty armies have one less than a full move's worth of movement points regardless of how many moves their unit type has set +; in the editor. Under the standard game rules, this means they can only move two tiles along roads. The cause is a small mistake in the logic that +; attempts to find the slowest member among units in the army. The mod fixes this bug by reimplementing the max movement point calculation for armies. +; PREMATURE TRUNCATION OF FOUND PATHS -- If the game attempts to find a path for a unit that's more than 256 tiles long, the path will not be +; returned properly from the pathfinder. That's because the pathfinder stops reconstructing the final path once it reaches a length of 256. That +; creates a serious problem for long paths because reconstruction works from the end of the path toward the start, so stopping early produces an +; incorrect path that begins in the middle. The fix is simply to multiply the maximum length by 10 (to 2560). Removing the limit entirely risks +; allowing infinite loops. This bug is rarely visible in-game, it usually appears as AI naval units following inappropriate or invalid paths. +; ZERO PRODUCTION CRASH -- If a city has zero production, which is possible using specialists modded to produce negative shields, the game will +; crash due to a division by zero. +; AI CAN SACRIFICE WITHOUT SPECIAL ABILITY -- The base game function that gates the AI's ability to sacrifice units does not check whether the unit +; in question has the sacrifice special ability set on its type. Thus, AIs are allowed to sacrifice any captured units as long as they have the +; required tech. The mod fixes this by patching the gating function to insert the missing condition. +; AI CAN FORM ARMY WITHOUT SPECIAL ABILITY -- Similar to the above issue, the AI's ability to form armies with leader units is not gated by those +; units having the "build army" special ability. +; CRASH IN LEADER UNIT AI -- The base game's AI routine for leader units may crash due to uninitialized variables. +; FAILURE TO FIND NEW CITY BUILD -- After a city completes production, the game searches for a new build for it. If that city is owned by the seated +; player, whatever the game finds will be filled in as the default option in the domestic advisor popup asking the player to choose a new build. If +; the search fails to find anything, there will be no default option, the dropdown selector will not be initialized, and the game will crash when it +; tries to open the popup. To fix this, the mod detects when the game has failed to find a new build option and fills in Wealth instead or, failing +; that, any unit or improvement that the city can build. +; PASSENGERS OUT OF ORDER ON MENU -- When there are multiple doubly-contained units (meaning units contained in other units that are themselves +; contained in something, like a unit in an army on a transport) on a tile, the game will not always show the passenger units in the correct locations +; on the right-click menu. To fix this, the mod double checks the order of the entries on the menu to make sure that passenger units are listed just +; after the unit they're contained in. +; PATCH EMPTY ARMY COMBAT CRASH -- Guards a crash in the army combat selection routine by returning the army unit itself if it has no contained +; units (prevents divide-by-zero in the vanilla selection loop). + +patch_submarine_bug = true +patch_science_age_bug = true +patch_pedia_texture_bug = true +patch_blocked_disembark_freeze = true +patch_houseboat_bug = true +patch_intercept_lost_turn_bug = true +patch_phantom_resource_bug = true +patch_maintenance_persisting_for_obsolete_buildings = true +patch_barbarian_diagonal_bug = true +patch_disease_stopping_tech_flag_bug = false +patch_division_by_zero_in_ai_alliance_eval = true +patch_empty_army_movement = true +patch_premature_truncation_of_found_paths = true +patch_zero_production_crash = true +patch_ai_can_sacrifice_without_special_ability = true +patch_ai_can_form_army_without_special_ability = true +patch_crash_in_leader_unit_ai = true +patch_failure_to_find_new_city_build = true +patch_passengers_out_of_order_on_menu = true +patch_empty_army_combat_crash = true + +; At the beginning of each AI player's turn, deletes any units of theirs that are not on a valid tile. This addresses a rare crash that can occur when +; the unit AI invokes the pathfinder for an off-map unit. I don't know how AI units can end up off the map in the first place. +delete_off_map_ai_units = true + +; On the city screen, the icons for different kinds of specialist yields get drawn over top of, instead of beside, one another. This setting fixes +; that so they are displayed properly. +fix_overlapping_specialist_yield_icons = true + +[======================] +[=== LIMITS REMOVED ===] +[======================] + +remove_unit_limit = true +remove_city_improvement_limit = true + +; The city limit can be configured up to a maximum of 2048 or down to a minimum of 0. For base game behavior, set to 512. +city_limit = 2048 + +; Increases the cap on the game turn limit from 1000 to 1000000 +remove_cap_on_turn_limit = true + +; Be warned: the no era limit feature is incomplete, untested, and not likely to work at this time +remove_era_limit = false + +[=========================] +[=== ENGINE EXTENSIONS ===] +[=========================] + +; These "NoRaze" options can stop cities from being destroyed. "Autorazing" refers to the automatic destruction of size one, cultureless cities. If +; autorazing is prevented, players will be given the option to keep the city. If razing by players is prevented, neither the human player nor AIs will +; be allowed to raze or abandon cities. +prevent_autorazing = false +prevent_razing_by_players = false + +; These options allow you to adjust the minimum allowed distance between cities. minimum_city_separation controls the minimum number of tiles between +; cities so, e.g, if it's set to 1, cities cannot be founded adjacent to one another, there must be at least one open tile separating them. A setting +; of 1 there corresponds to the standard game rules. disallow_founding_next_to_foreign_city is an optional additional restriction. If it's enabled, +; cities may not be founded adjacent to a city belonging to another civ regardless of the minimum separation. It is only relevant when the minimum +; separation is set to zero. +minimum_city_separation = 1 +disallow_founding_next_to_foreign_city = true + +; Set to a number to limit railroad movement to that many tiles per turn. To return to infinite railroad movement, set to false or a number <=0. By +; default, all units travel the same distance along limited rails like in Civ 4, but this can be changed by toggling the next option below. +; NOTE: For best results, the railroad limit should be a multiple of the "movement rate along roads" set in the editor (usually 3). The limitation +; will work in any case, but setting the limit this way helps avoid an integer overflow issue inside the pathfinder that may cause it to fail to find +; the shortest paths for units with a large number of available moves. +limit_railroad_movement = false + +; If set to true, limited railroads will work like fast roads instead of Civ 4 style railroads. The movement rate along fast roads is determined by +; the limit_railroad_movement setting above. If that setting is false or <= 0, this option does nothing. +limited_railroads_work_like_fast_roads = false + +; This option lets you put a limit on how many units may occupy each tile. The limit applies separately for land, sea, and air units. You may set the +; limit differently for each of those classes by setting this option to a list of three numbers. If you set it to a single number, that limit amount +; will apply to all three. If you set it to false or a number <= 0, no limit will apply, as in the base game. Some examples: +; To limit tiles to 5 land, 5 sea, and 5 air units: limit_units_per_tile = 5 +; To limit tiles to 5 land and sea units but 10 air units: limit_units_per_tile = [5 5 10] +; To limit only air units to 10 per tile: limit_units_per_tile = [false false 10] +; To have no limit (as in the standard game rules): limit_units_per_tile = false +; NOTE: The two options below let you exclude cities or certain unit types from the limit. +limit_units_per_tile = false + +; Allows an unlimited number of units to occupy tiles with cities when the unit limit is in force. When the limit (option above) is deactivated, this +; option does nothing. +exclude_cities_from_units_per_tile_limit = false + +; Allows certain unit types to be exempt from the stack limit. Units of these types will not be stopped by the limit and will not count toward it +; (will not stop others). This option is a space separated list of unit type names. Multi-word names must be wrapped in quotes. For example: +; [Worker Settler Flak "Mobile SAM"] +; This option does nothing if limit_units_per_tile is set to false. +exclude_types_from_units_per_tile_limit = [] + +enable_free_buildings_from_small_wonders = true +allow_stealth_attack_against_single_unit = false +disallow_trespassing = false +enable_land_sea_intersections = false + +; All anarchy lengths will be multiplied by this amount as a percent. For example, if set to 50, anarchy length will be reduced by half. Set to 100 +; for standard game behavior. There is a minimum anarchy length of 2 turns, but you can remove anarchy entirely by setting this option < 0. +anarchy_length_percent = 100 + +; Add perfume to an improvement or unit type to encourage the AI to build it more often. When choosing what to buld, the AI computes a point value for +; each of its options and the mod will add the perfume amount to the point total for each named option. For reference, point values are often in the +; hundreds for the most desirable options. You can see the point value the AI gives to every available build by pressing P while viewing one of its +; cities. Perfume amounts can also be specified as a percentage, ex. a perfume amount of 15% will increase the AI's evaluation by 15% and an amount of +; -50% will reduce it by half. +; production_perfume is a list of names and amounts, each one looks like "name": amount +; Here's an example: ["Granary": 15, "Colosseum": -20%, "Courthouse": 30] +; The quotation marks around a name are not necessary if the name is all one word (i.e. does not include spaces) and is made up of only letters, +; digits (0-9), periods, hyphens, or underscores. The category of letters includes the normal English a-z and A-Z as well as accented variants +; (e.g. ä, ö, ñ, ç) and all other non-English letters available in the Windows-1252 encoding (e.g. ß, þ, æ). +production_perfume = [] + +; Add perfume to a technology to change how valuable the AI judges the tech to be. Each point of perfume is worth roughly one gold in trade, and also +; affects what the AI chooses to research. The format matches production_perfume above, ex.: [Medicine: 500, Fascism: -50%, "Replacable Parts": 20%]. +technology_perfume = [] + +; Add perfume to a government to encourage or discourage the AI from switching to that type. The format follows the other perfume options, ex.: +; [Republic: 10%, Fascism: -30%]. Unfortunately I don't know how much each point is worth in this context. I also don't know how perfuming governments +; affects the AI's willingness to overthrow its current govt. The perfume for sure applies when the AI is selecting a new govt type after anarchy. +government_perfume = [] + +; The AI production ranking is the point value the AI gives to each available build in some city. To view it, press P while viewing an AI city. +enable_ai_production_ranking = true + +; Shades/highlights each tile to show how desirable the AI considers it as a city location. To activate, press L while in game. The scale goes from +; white (least desirable) to red (most desirable) with yellow in between. Also the exact number the AI gives any tile can be seen on its info box. +; If show_ai_city_location_desirability_if_settler is true, the desirability overlay will automatically appear when a settler is selected. +enable_ai_city_location_desirability_display = true +show_ai_city_location_desirability_if_settler = false + +; Setting a government's corruption level to "OFF" will remove all corruption, as expected, instead of maximizing it +zero_corruption_when_off = true + +; Prevents land settlers/workers on transports from settling/improving water tiles. This option does not affect the vanilla game but is useful for +; mods that enable city building or improvement of water tiles. +disallow_land_units_from_affecting_water_tiles = true + +; Allows units to move after airdropping by making airdrops cost no movement. Under the standard game rules, units lose all their remaining moves +; after airdropping. Units will be prevented from airdropping more than once in the same turn. +dont_end_units_turn_after_airdrop = false + +allow_airdrop_without_airport = false +enable_negative_pop_pollution = true + +; Here it's possible to set buildings as prerequisites for unit production. It's possible for a unit type to have multiple prereq buildings up to a +; maximum of 10, and all must be present in a city for the unit to be buildable. +; The format is a list of building names and unit type names, each one looks like "building name": "unit type 1" "unit type 2" ... +; Quotation marks around names can be omitted like in production_perfume (see above). +; Here's an example: +; [Factory: Tank "Modern Armor", +; Barracks: Swordsman Cavalry Tank "Modern Armor", +; Airport: Bomber] +building_prereqs_for_units = [] + +; Here it's possible to set buildings to generate resources. Those resources can be added to the trade network or limited to the building's city. The +; format is a list of building name and resource name pairs with optional "local", "no-tech-req", "yields", "show-bonus", and/or "hide-non-bonus" +; settings before each resource name. Example: +; ["Steel Mill": Steel, Terrace: yields show-bonus Rice, "Coal Liquefaction": local Oil, Supercollider: local no-tech-req Antimatter, +; "Hydro Plant": local "Electric Power"] +; Quotation marks around names can be omitted like in production_perfume (see above). +; The "local" setting means that the produced resource will not be added to the trade network, it will be available only in the building's city. +; The "no-tech-req" setting means that the resource will be produced even for players who do not have the technology to reveal it on the map. +; The "yields" setting means that the resource's tile yields will be added to the city as if it were on a worked tile. +; The "show-bonus" setting means that an icon for the generated resource will be displayed on the city screen even if it's a bonus resource. +; The "hide-non-bonus" setting is the opposite of show-bonus. It means an icon will NOT be shown if the resource is of strategic or luxury type. +; Buildings will not generate resources if the resource requirement for the building itself is not met. This makes it possible to set up resource +; production chains. Note for modders: Production chains require the input resources to be listed before the outputs in the scenario data, when the +; inputs also come from buildings. For example if you have iron ore on the map, a building that requires it and produces iron, and a building that +; requires iron and produces steel, iron must be listed before steel in the scenario data or the chain won't work. This is because building resource +; generation is calculated in the same order as the generated resources appear in the scenario data. This limitation does not apply to map resources +; (iron ore in the example) as access to all map resources is calculated first before any building resources. +buildings_generating_resources = [] + +; Shows a warning in case some of the unit, building, or resource names in this config file don't match anything in the scenario data. +warn_about_unrecognized_names = true + +; Overrides the rules for when units are eligible to retreat based on their movement. The possible options are: +; standard: No change from base game rules +; none: No units will ever retreat +; all-units: All non-immobile units may retreat, even if they have only one move or are up against a faster opponent +; if-faster: Units may retreat when they are faster than their opponent, for example a cavalry may retreat from a knight +; if-not-slower: Units may retreat when they are at least as fast as their opponent, for example a knight may retreat from another knight but not +; from a cavalry, and an infantry may retreat from another infantry +; if-fast-and-not-slower: Like if-not-slower but only fast (2+ move) units may retreat +; These settings don't change the fact that units cannot retreat when they start combat with 1 HP or are defending a city. They also do not change +; that naval units cannot retreat defensively (there is a separate option for that below). +land_retreat_rules = standard +sea_retreat_rules = standard + +; Under the base game rules, no unit may retreat defensively if it's located on a water tile. This option removes this special rule so naval units can +; retreat defensively like land units do. See also: the sea_retreat_rules option above and the limit_defensive_retreat_on_water_to_types option below. +allow_defensive_retreat_on_water = false + +; If any unit types are listed here, defensive retreat on water tiles will be limited to those types. Otherwise, all types may retreat that way. The +; list is separated by spaces and multi-word type names must be wrapped in quotation marks. For example, setting to: +; [Submarine "Nuclear Submarine"] +; would mean that only those submarine naval units could retreat defensively. This option does nothing if allow_defensive_retreat_on_water is false. +limit_defensive_retreat_on_water_to_types = [] + +; The multi-city start spawns in multiple cities for AI players at the start of the game instead of their usual one settler. This option controls the +; number of cities the AI starts with. E.g., if it's set to 2, the AI starts with 2 cities. If it's set <= 0, the game starts like normal. The mod can +; also add improvements to the AI's extra cities, which are intended to work like extra palaces, see ai_multi_start_extra_palaces. +ai_multi_city_start = 0 + +; This option only applies if ai_multi_city_start is set > 1. It controls how many tiles the mod will randomly check while searching for a suitable +; location for each of the AI's extra starter cities. Default: 10000. +max_tries_to_place_fp_city = 10000 + +; This option only applies if ai_multi_city_start is set > 1. It specifies a list of improvements to be added to the AI's additional cities. E.g: +; ["Forbidden Palace" Courthouse] +; If the AI multi-city start is set to 3+ with the above extra palaces, the AI players will start with 3+ cities and the first one will have the +; Palace like normal, the second will have the Forbidden Palace, and the third will have a courthouse, any after that will start empty. +; Additionally, any small wonders listed here with the "reduces corruption" effect will be considered "extra palaces" for the AI. They will respawn +; like the real Palace. In other words, if an AI loses a city with an extra palace, it will reappear in another one of its cities following the same +; logic the game uses to select a new Palace location. If the AI is missing an extra palace and acquires a new city, that extra palace will +; automatically be added to the new city. +ai_multi_start_extra_palaces = [] + +; Turning this on makes small or great wonders with the "reduces corruption" effect, such as the Forbidden Palace, as effective at reducing corruption +; as the palace itself. This reduces corruption not only in the city that contains such a wonder, it also reduces distance and rank corruption in +; nearby cities as if the city were an additional capital. +promote_wonder_decorruption_effect = false + +allow_military_leaders_to_hurry_wonders = false +allow_multiple_battle_created_units_per_player = false + +; The AI's beaker production will be multiplied by this amount, as a percent. A value of 100 gives you the standard game behavior, a value of 75 +; reduces AI research by 25%, a value of 200 doubles AI research, and so on. +ai_research_multiplier = 100 + +; Each time an AI player founds a city, the given amount of perfume will be applied to its settlers over the given duration in number of turns. The +; perfume effect declines steadily to zero over the duration. The perfume amount may be specified as a percentage. The purpose of these options is to +; slow the AI's expansion with negative perfume. +; NOTE: The AI has a very strong tendency to build settlers so you'll need to set these options quite high to slow it down significantly. For example, +; a perfume of -200% over a 30 turn duration left the AI with about half as many cities after 50 turns in my test. +ai_settler_perfume_on_founding = 0 +ai_settler_perfume_on_founding_duration = 0 + +; If a player can't afford to pay maintenance on their buildings and units, the game will forcibly lower expenses and raise money by (in order): +; 1. Selling buildings, excluding those that are maintenance-free or contribute to gold production even indirectly +; 2. Disbanding units, excluding free ones +; 3. Switching cities to building Wealth +; For AI players, the game alternates the order of (1) and (2) each turn. Also for AIs, on every third turn, the game will cut their research spending +; as much as necessary to avoid bankruptcy. +aggressively_penalize_bankruptcy = false + +; Under the standard game rules, the Despotism tile penalty does not apply to food yield from city tiles of Agricultural civs with fresh water. Set +; this option to true to remove that exception to the penalty. +no_penalty_exception_for_agri_fresh_water_city_tiles = false + +; Adds an option to the stealth attack target selection popup that allows the player to opt out of doing a stealth attack. If selected, the unit will +; attack normally, targeting the tile's top defender. Similarly, if stealth bombardment is canceled, the unit will bombard normally and may target +; buildings or population if attacking a city. +include_stealth_attack_cancel_option = false + +; Aircraft flying a recon mission can be intercepted by enemy fighters or ground AA as if they were flying a bombing mission +intercept_recon_missions = false + +; Under the standard rules, performing a recon mission or intercepting an attacker causes a unit to lose all of its remaining moves. Setting this +; option to true causes those actions to only consume one move. This makes them consistent with other air missions like bombing. Note: fighters will +; only be able to intercept multiple times in one turn if they have the blitz ability. +charge_one_move_for_recon_and_interception = false + +; In the base game, precision striking was only intended to be used by bombers. This option extends the precision strike logic to cover land & sea +; artillery and cruise missiles. Specifically what it does is: +; 1. Fixes the animations, so land & sea artillery will play their bombard animations and cruise missiles will play their strike animation +; 2. Makes it so that the strikable range depends on the bombard range for land & sea units instead of operational range +; 3. Despawns cruise missiles after they've performed a precision strike +polish_precision_striking = true + +; Enables units to perform stealth attacks when they bombard or bomb a target. Like regular stealth attacks this opens a popup allowing the player to +; choose a specific unit to target. The attacking unit must have the stealth attack special action checked, must have a list of stealth attack targets +; set, and the target tile must be visible. +enable_stealth_attack_via_bombardment = false + +; Prevents aircraft from being damaged by bombardment or bombing +immunize_aircraft_against_bombardment = false + +; Unit type names listed here will use PTW-like targeting when bombarding cities. PTW-like means there is a 1-in-3 chance they will target each of +; population, buildings, and units. This is unlike Conquests artillery targeting, which always goes after units first. Items in the list are separated +; by spaces and multi-word items must be wrapped in quotation marks like for perfume specs. Example: [Catapult Cannon Artillery "Radar Artillery"] +ptw_like_artillery_targeting = [] + +; Changes the meaning of the charm attack flag to indicate PTW-like targeting. This is a matter of convenience. It allows modders to specify PTW +; targeting using an editor, instead of the list above, at the cost of losing the charm attack function. +charm_flag_triggers_ptw_like_targeting = false + +; Unit types listed here won't be allowed to bombard land tiles. Same format as ptw_like_artillery_targeting, example: [Submarine "Torpedo Bomber"] +can_bombard_only_sea_tiles = [] + +; Units with the king ability will defend like normal, instead of always being the last to defend in a stack. Useful for mods that use the king flag +; for special purposes. Does not apply in regicide games. +ignore_king_ability_for_defense_priority = false + +; Untradable techs will appear grayed out on the trade screen. This lets you see which untradable techs the AI has just like for tradable +; ones. "Untradable" means techs that have been flagged as "cannot be traded" in the editor. This option only matters for modded games as there are no +; untradable techs in the standard game. +show_untradable_techs_on_trade_screen = false + +; Barbarians will capture cities instead of ransacking them. This option also modifies the game's production logic so barbarian cities can build +; things, grow, and even do research. +; This feature is EXPERIMENTAL at the moment. It basically works but hasn't been extensively tested. For example, I don't know what would happen if +; the barb player were to win the game. +; Because of how barb city production works under the hood, it requires barb activity to be turned on in order to work. The mod will handle this +; automatically. If this option is enabled, there is at least one barb city on the map, and the barb activity level is set to 0 (no barbarians), the +; level will be increased to 1 (sedentary) in order not to block barb city production. +enable_city_capture_by_barbarians = false + +; A list of modifications to the rules for defensive bombard. "Defensive bombard" is the free shot a bombard unit gets when the stack it's in is +; attacked. The possible options are: +; lethal: Attackers may be destroyed by defensive bombard if the bombarding unit has the appropriate lethal land/sea bombard ability. +; aerial: Air units may perform defensive bombard if they can perform bombing missions. +; not-invisible: Attacking units are immune to defensive bombard if they are invisible and not detected. +; blitz: Units with blitz may perform defensive bombard multiple times per turn, once for each move they have. +; docked-vs-land: Docked ships (i.e. in a city) can perform defensive bombard against land units attacking their city. +; For example, to activate all options, set to [lethal aerial not-invisible blitz docked-vs-land]. The order of items in the list does not matter. You +; can also activate all options by setting to [all] (with or without the brackets). +special_defensive_bombard_rules = [] + +; A list of modifications to the rules for zone of control, like above for defensive bombard. The possibilities are: +; amphibious: Land units may exert zone of control over sea units and vice-versa. This can only be done using bombard strength, not attack +; strength. It also requires non-zero bombard range. +; lethal: Units may be destroyed by zone of control. The intercepting unit must have the lethal bombard ability in order to do this, even if it's +; using its attack strength to exert ZoC. +; aerial: Air units can exert zone of control if their type has the "Zone of Control" option checked. Additionally, they must be able to perform the +; bombing mission, have non-zero bombard strength, and non-zero operational range. +; not-from-inside: Land units may not exert zone of control while inside a transport (armies do not count as transports) +; Like for defensive bombard, all options can be activated by setting to [all] (with or without the brackets), and order does not matter. +special_zone_of_control_rules = [] + +; All human players in a hotseat game will share visibility +share_visibility_in_hotseat = false + +; All human players in a hotseat game will share the effects of the wonders they've built, great or small. This applies to all civ-wide effects, for +; example if any human player builds Leonardo's Workshop, all human players get half price upgrades. Notes: +; 1. If a human player receiving the shared effect of a small wonder and that SW has no non-shared effects, it becomes unbuildable for that player. +; 2. Building and army requirements for wonders are shared as well. For example, all human players are allowed to build Battlefield Medicine once all +; of them combined have five hospitals. +; 3. For the Great Library effect, known AI civs are shared as well. If an AI has contact with any human player, it is considered to be in contact +; with all of them for the purpose of granting techs to human players. +share_wonders_in_hotseat = false + +allow_precision_strikes_against_tile_improvements = false +dont_end_units_turn_after_bombarding_barricade = false + +; Allows land units to bombard aircraft and naval units in cities +; This does not override the immunity of aircraft vs bombardment, if that option is also activated. +remove_land_artillery_target_restrictions = false + +; Allows tile improvements on a tile with an occupied airfield to be destroyed by bombardment, not including the airfield itself. For example, under +; the standard game rules, if you bombard a tile with a road, airfield, and fighter on it, you will do no damage because the attack will target the +; fighter which is invulnerable (aircraft in an airfield cannot be damaged by bombardment). This option allows such an attack to bypass the fighter +; and hit the tile instead, as long as that tile has an improvement other than the airfield. +allow_bombard_of_other_improvs_on_occupied_airfield = false + +; Displays the total number of cities in the game on the demographics screen (press F11). +show_total_city_count = false + +; Under the standard game rules, each forbidden-palace-like building in an empire increases its optimal city number (OCN) by 37.5% of the base number, +; except if the empire is running a government with communal corruption, in which case the increase is 100% of the base. With this option enabled, the +; communal corruption rule is always in force, so each forbidden palace always increases the OCN by an amount equal to the base number. +; NOTE: The "base" optimal city number comes from the map size. It's the number set on the "World Sizes" tab in the editor. +strengthen_forbidden_palace_ocn_effect = false + +; This option allows you to increase the maintenance cost of units depending on their shield cost. For every X shields that the unit costs to build +; (where X is the setting below), the unit's maintenance increases by one unit's worth. For example, if set to 100, units that cost 0-99 shields will +; have normal maintenace, units costing 100-199 shields will cost double, those costing 200-299 will cost triple, etc. (Note the final cost in GPT +; depends on gov't type). Set <= 0 to disable. +extra_unit_maintenance_per_shields = 0 + +; This option renames players' civs depending on their eras. The format is a list of names each associated with a list of replacements. There is one +; replacement for each era or, if the list is shorter than the number of eras, no replacement will be done in the later eras. Example: +; [Rome: Rome "Byzantine Empire" Italy Italy, +; Roman: Roman Byzantine Italian Italian, +; France: Gaul, French: Gaulic] +; In this example, Rome will be renamed to "Rome" in the first era, "Byzantine Empire" in the second, and "Italy" in the third and fourth. The +; adjectives will be replaced to match. France/French will be renamed to Gaul/Gaulic only in the first era. +; Spaces are used to separate words so if a name or replacement has multiple words it's necessary to use quotation marks to group them together like +; for "Byzantine Empire" in the example. +; The replacements apply to civ nouns, adjectives, and formal names. If a player has put in a custom name, that will not be replaced. +civ_aliases_by_era = [] + +; This option works like the one above except it replaces leader names instead of civ names. Each replacement name may be followed by (M) or (F) to +; specify gender. Example: +; ["Joan d'Arc": Vercingetorix (M) "Joan d'Arc" (F) Napoleon (M) "De Gaulle" (M)] +; If no gender is specified then the game will use whatever gender was set in the scenario data for that civ's leader. That means (F) could be omitted +; in the above example since the leader of France is already female. +; Additionally you can include a replacement title after the gender separated by a comma. Here's the example with titles added: +; ["Joan d'Arc": Vercingetorix (M, King) "Joan d'Arc" (F) Napoleon (M, Emperor) "De Gaulle" (M, President)] +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 +; 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. +; 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. +unit_limits = [] + +; Removes barracks/harbor/airport requirement from upgrades +allow_upgrades_in_any_city = false + +; Stops the game from placing volcanos during map generation. Any tiles that would have been volcanos will be mountains instead. +do_not_generate_volcanos = false + +; Stops the game from placing pollution on impassable tiles +do_not_pollute_impassable_tiles = false + +; Includes the hitpoints of each possible target on the stealth attack selection popup. This makes it easier to pick out weakened units. +show_hp_of_stealth_attack_options = false + +; Stops invisible units from being targeted by stealth attacks. They can still be targeted if they've been revealed by the attacking civ. +exclude_invisible_units_from_stealth_attack = false + +; Stops units from being targeted by stealth attack if they are contained in another unit such as a naval or land transport, or a helicopter. +exclude_passengers_from_stealth_attack = false + +; Normally planting a forest always produces the regular non-LM forest terrain. This option changes that so it instead produces LM forest. +convert_to_landmark_after_planting_forest = false + +; This option specifies how likely it is (in percent) for a combat land or sea unit with a maximum of one HP to be destroyed when struck by a +; nuke. Set to 100 for base game behavior. +chance_for_nukes_to_destroy_max_one_hp_units = 100 + +; Allows you to sell aqueducts and hospitals as well as any modded buildings that uncap population growth. A city must be below the pop cap for a sale +; to be allowed, i.e., under the standard rules, aqueducts may only be sold in cities of pop <= 6 and for hospitals pop <= 12. +allow_sale_of_aqueducts_and_hospitals = false + +; Allows you to sell Small Wonders. This may be useful to relocate Forbidden Palace-like Small Wonders. +allow_sale_of_small_wonders = false + +; This option makes it so that only sea units with the "detect invisible" ability can reveal invisible sea units, and likewise for non-sea units. +no_cross_shore_detection = false + +; Controls the size of the area in which cities can work tiles. The value corresponds to cultural border expansions. For example, setting this to 1 +; means cities would only be able to work tiles within their level 1 cultural borders, meaning the eight tiles neighboring the city's own +; tile. Setting to 2 gives you the game's standard rule that cities may work tiles within their level 2 cultural borders, which they attain after one +; expansion. Setting to 3 allows them to work within level 3 borders and so forth. +; Notes: (1) If the city can work tiles in the fourth ring or farther, the map view on the city screen will be zoomed out when you enter it if +; auto_zoom_city_screen_for_large_work_areas is true. Otherwise it's not possible to show the entire work area. You can zoom back in by pressing Z. +; (2) The next option below can limit cities' workable areas to be smaller than the radius set here, based on their culture. (3) This option has a +; minimum value of 1 and a maximum of 7. +city_work_radius = 2 +auto_zoom_city_screen_for_large_work_areas = true + +; This option can reduce the size of the area cities can work based on their cultural level. +; Possible values are: +; none: Standard game rules apply; cities can work any tile that's within the work radius and within their owner's borders. +; cultural: Cities may only work tiles that are within their direct cultural borders, e.g. a city with zero culture may only work the 8 surrounding +; tiles. After one expansion, it may work the standard 20, after a second expansion it may work the third ring, and so on. +; cultural-min-2: Like "cultural" except cities can always work their standard 20 tiles. +; cultural-or-adjacent: Cities can work tiles in their direct cultural borders plus any tiles adjacent to those. +work_area_limit = none + +; This option can also reduce the size of the area cities can work based on improvements present. +; This mechanic works in tandem with the above work_area_limit condition - tiles cannot be worked if the tiles do not also meet the cultural work area limit requirement. +; If left empty, this mechanic is not used. +; Improvements may be defined to grant a certain radius work area, and the highest radius present is used as the work radius for a city. eg ["Harbor": 3] +; Improvements may also grant a bonus radius, these are added on after the highest radius is found. [Factory: 3, "Mass Transit": 2 extra] +; An entry written as default or "default" will always be present for any given city, and represents an always-present virtual improvement. eg. ["default": 2] gives vanilla behaviour. +work_area_improvements = [] + +; The maximum distance it's possible to rebase an aircraft equals its operational range times this value. For standard game rules, set to 6. +rebase_range_multiplier = 6 + +; This option prevents units from loading into two different transports on the same turn. Once a unit has been loaded into a transport, it becomes +; tied to that transport for the remainder of the turn and cannot be loaded into any other. Loading into armies is not affected. The purpose of this +; option is to make the galley chaining exploit impossible. +limit_unit_loading_to_one_transport_per_turn = false + +; In the base game, if you set Cavalry to upgrade to Tank but don't give it the upgrade ability, intending to make Cavalry obsolete when Tanks become +; available but not upgradable to them, you'll be left with the strange situation that older units such as Knights are allowed to upgrade to Tanks +; even though Cavalry are not. This option makes it so that Knights upgrade to Cavalry in that case. In general, it makes it so that upgrade chains +; stop at the type along the chain that does not have the upgrade ability. +; NOTE: The chain is only stopped if the civ in question can build the unit type. The example above is simplified. In the actual rules, Cavalry +; upgrades to Sipahi, which upgrades to Cossack. Blocking the upgrade chain at Cavalry would prevent Ottomans and Russia from upgrading to their +; unique units, so the mod won't do that. You must clear the upgrade ability from Sipahi and Cossack as well to block those civs there instead. +prevent_old_units_from_upgrading_past_ability_block = false + +; Buildings double their culture production this many years after they were built. For standard game rules, set to 1000. +years_to_double_building_culture = 1000 + +; Controls how long it takes for wonders to produce tourism gold as a percent of the standard rate. For example, if set to 200, it would take 2000 +; years to begin generating 2 GPT tourism, instead of the standard 1000 years, and 3000 years for 4 GPT, instead of the standard 1500. This setting is +; effectively a scaling factor on the tourism time thresholds. For standard rules, set to 100. +tourism_time_scale_percent = 100 + +; On the first turn of a hotseat game, all human players will be given diplomatic contact with each other. +introduce_all_human_players_at_start_of_hotseat_game = false + +; Allows units to be unloaded from an army. The army type must have the "unload" ability set in the editor. +allow_unload_from_army = false + +; Allow colonies to be built on tiles inside another civ's territory (for strategic/luxury resources); applies a relation penalty with the other civ, per each colony. +allow_extraterritorial_colonies = false +per_extraterritorial_colony_relation_penalty = 3 + +; A list of rule modifications to make land transports more practical. Works like special_defensive_bombard_rules. The possibilities are: +; load-onto-boat: Allows land transports to be loaded into naval units +; join-army: Allows empty land transports to join armies +; no-defense-from-inside: Prevents units inside a land transport from defending their tile, performing defensive bombard, or intercepting air units +; no-escape: Destroys the passengers inside a land tranport when the transport itself is destroyed or captured +land_transport_rules = [] + +; Prevents land anti-air units from intercepting overflying units while they're loaded in a naval transport +no_land_anti_air_from_inside_naval_transport = false + +; A list of rule modifications for air units with transport capacity called "helicopters" for short. Works like special_defensive_bombard_rules. The +; possibilities are: +; allow-on-carriers: Allows helicopters to be rebased or loaded onto carriers +; passenger-airdrop: Allows paratroopers inside a helicopter on a carrier to perform airdrops +; no-defense-from-inside: Prevents units inside a helicopter from defending their tile, performing defensive bombard, or intercepting air +; units. Also destroys passengers when the helicopter is destroyed in most circumstances in order to avoid problems such as a helicopter being +; captured by a land unit leaving its passengers alive on the same tile. +; no-escape: In all circumstances, destroys the passengers inside a helicopter when the heli itself is destroyed or captured +special_helicopter_rules = [] + +; Stops units from enslaving a target they've destroyed by bombarding as opposed to direct combat +prevent_enslaving_by_bombardment = false + +; Relaxes a rule that prevents resources from appearing directly next to another resource of a different type +allow_adjacent_resources_of_different_types = false + +; Controls the overall number of luxury resources placed on the map for luxury types that don't have a fixed appearance rate set in the editor. Under +; the standard rules, no luxuries have appearance rates set. Without a set rate, the game randomly chooses a rate between 50 and 100, biased toward +; the middle (75). This setting is a percent scaling on that range, so setting it to 150 means luxuries would have their rate randomized between 75 +; and 150, setting to 50 means a range of 25 to 50, and so on. For base game behavior, set to 100. +luxury_randomized_appearance_rate_percent = 100 + +; During map generation, the game places bonus resources until the total number of strategic and bonus resources reaches the tile count divided by +; this number. Raising this setting causes fewer bonus resources to be generated and lowering it increases them. For the standard rate, set to 32. +tiles_per_non_luxury_resource = 32 + +; Normally the corruption rate in the capital is fixed at zero. Setting this to true removes that, allowing corruption to appear in the capital. The +; capital also has a strong inherent bonus reducing corruption so even when this setting is on, it will usually have zero corruption. To reduce that +; bonus, see the special_capital_decorruption_effect option below. +allow_corruption_in_capital = false + +; Controls the special decorruption bonus that's applied to the capital. This bonus is incorporated into the decorrupting effect from buildings in the +; city and each point is equivalent in strength to one courthouse. For standard game rules, set to 10. This option does nothing unless +; allow_corruption_in_capital is set to true. Min value 0, max 100. +special_capital_decorruption_effect = 10 + +; Overrides the NoAIPatrol setting from conquests.ini. Possible values are: +; none: No override, use the setting from the INI like normal +; one: Set NoAIPatrol to 1, disabling AI patrol behavior +; zero: Set NoAIPatrol to 0, allowing AI units to patrol +; The purpose of this option is to enable you to configure NoAIPatrol like a C3X setting instead of globally. In particlar, it allows you to configure +; NoAIPatrol on or off on a per-scenario basis. +override_no_ai_patrol = one + +; Overrides the barbarian activity level when starting a new game for a scenario with a custom map. Normally, in that case, the game will use the +; barbarian settings kept in conquests.ini, ignoring what was set for the map in the editor. This option allows you to set an activity level on a +; per-scenario basis like other C3X settings. +; The possible values are "none" for no override, i.e. base game behavior, or one of the selectable barbarian activity levels: "No Barbarians", +; Sedentary, Roaming, Restless, Raging, or Random. You can specify either the original English names just listed or the custom/translated names in +; labels.txt. The value is not case sensitive. +override_barbarian_activity_level_for_scenario_maps = none + +; Leader units placed on the map as part of a scenario do not have their leader types filled in properly, which means they behave differently than +; proper military leaders would. In particular, they are allowed to hurry production of great wonders and spaceship parts. This option fills in their +; types at the start of the game so they behave like normal MGLs spawned during a game. +initialize_preplaced_scenario_leaders_as_mgls = false + +enable_unit_counters = false + +; Civ 4 style best defender selection. +; When this is on (and enable_unit_counters is also true), every time an attack happens the engine picks the +; defender that is HARDEST for the current attacker to beat (the unit with the highest defender win rate +; once unit-counter rules are applied), instead of the vanilla "highest defense strength" rule. The same +; unit is also forced to the top of the enemy stack on the map whenever a player has an attacker selected, +; so the displayed unit stays in sync with what would actually fight. Re-targeting is automatic: switching +; the selected attacker (different counter match-ups) updates which enemy unit is shown as the best defender. +; Notes: +; - Has no effect when enable_unit_counters = false (then there's nothing to differentiate beyond defense). +; - Applies to both human and AI attackers, so the rule is consistent. +; - Does not change ranged-bombard or defensive-bombard target selection, only normal attacks. +use_civ4_style_best_defender = false + +; unit_group allows you gruop your units in a group,please refer to building_prereqs_for_units for the format. +; This function will not work if enable_unit_counters is false. +unit_group = [] +; ── counter_rule format ────────────────────────────────────────────────────────────── +; +; counter_rule = [Friendly vs Enemy Effect... Conditions...] +; +; 【Friendly / Enemy】 +; This can be one of the following three options: +; · The specific unit type, such as "Archer" (must match the name in BIQ exactly; names containing spaces must be enclosed in quotation marks) +; · A unit group name, such as melee (i.e. the group defined in the unit_group section above) +; · "*" represents any unit type (the asterisk must be enclosed in quotation marks) +; +; 【Effect】(Expressed as a percentage; when multiple rules apply to the same battle, their effects are multiplied.) +; +; "self" always refers to the first unit, and "enemy" always refers to the second unit, regardless of who is attacking whom: +; self-atk value — The unit’s attack power becomes N% of its original value +; Example: self-atk 150 = attack power ×1.5; self-atk 50 = attack power ×0.5 +; self-def value — Your defence becomes N% of the original value; +; enemy-atk value — The enemy’s attack becomes N% of the original value; +; enemy-def value — The enemy’s defence becomes N% of the original value; +; +; 【Conditions】(Optional; leaving blank indicates no restrictions; conditions take effect only when all are met simultaneously) +; in-city —— Takes effect only when the enemy is on a city tile +; terrain terrain_name -- Takes effect only when the enemy is on a tile of the specified terrain +; Uses the same lower-case English terrain tokens as districts_config buildable_on, not BIQ/localized names. +; Examples: grassland, hills, coast, snow-forest, snow-mountain, snow-volcano, lake +; ignore-terrain —— Ignores the enemy’s terrain defence bonus (sets their terrain bonus to zero) +; Can be used in conjunction with enemy-def; when used together, ignore-terrain takes precedence +; district district_name -- Only takes effect when the enemy is in a specified district (enable_districts must be enabled) +; District names are resolved after districts_config loads, so dynamic district names are supported. +; +; 【Examples】 +; counter_rule = [ranged vs melee self-atk 125] +; → When a ranged unit attacks a melee unit, its attack power is multiplied by 1.25 +; +; counter_rule = ["Knight" vs melee in-city enemy-def 150] +; → When knights attack melee units within a city, the enemy’s defence is multiplied by 1.5 +; +; counter_rule = ["Musketman" vs "Medival Infantry" terrain grassland self-atk 125] +; → When musketeers attack medieval infantry on grassland terrain, their attack power is multiplied by 1.25 +; +; counter_rule = ["Knight" vs "*" ignore-terrain self-atk 150] +; → When a Knight attacks any unit, its attack power is multiplied by 1.5 and it ignores the enemy’s terrain bonus. +; counter_rule = [Archer vs Swordsman self-atk 130 self-def 120] +; → When an archer attacks a swordsman: Archer’s attack power ×130% +; When a swordsman attacks an archer: Archer’s defence ×120% +; +; ───────────────────────────────────────────────────────────────────────────── + +counter_rule = [] + +[==================] +[=== AESTHETICS ===] +[==================] + +; If a tile has a forest, render it on top of roads and railroads, instead of underneath them. +draw_forests_over_roads_and_railroads = true + +; This allows you to set a victory animation for air units. Can be set to the name of any animation that is loaded by the game, specifically one of: +; blank, default, run, attack1, attack2, attack3, death, fortify, fidget, victory, capture, fortress, build, road, mine, irrigate, jungle, forest, plant +; Note that bomber units already have their bombing animations in the victory slot so "victory" is not a good choice here. For standard game behavior, +; set to "none". +aircraft_victory_animation = none + +; Enables naming tiles via the right-click menu and displays those names on the map. +enable_named_tiles = true + +[=======================] +[=== DAY/NIGHT CYCLE ===] +[=======================] + +; How the day/night cycle operates in the game. If enabled, terrain, cities, resources, landmarks and terrain buildings will change appearance based on +; the time of day, with 24 possible stages (one for each hour). The base game art is used for 12pm. If set to 'off', only base game art will be used. +; Day/night cycle should not be used if you are using non-standard terrain art or resources. Doing so may result in visual glitches or missing art. +; Note that day/night cycle art is not bundled directly with C3X and must be downloaded separately at https://forums.civfanatics.com/resources/day-night-cycle-in-civ-3-using-c3x.32520/ +; The possible values are: +; off: Only base game art used +; timer: Increment based on time elapsed since last hour transition (e.g., transition to next hour every 3 minutes) +; user-time: Match the user's system clock to determine hour of the day +; every-turn: Increment every turn by a fixed amount of hours +; specified: Pin the hour to a specific value (so hour of day is always the same) +day_night_cycle_mode = off + +; If day_night_cycle_mode is set to 'timer', minimum minutes of real time to elapse before transitioning to the next hour in the cycle. +; This is checked only at the end of the turn, so actual minutes may exceed this number. +elapsed_minutes_per_day_night_hour_transition = 3 + +; If day_night_cycle_mode is set to 'timer' or 'every-turn', the number of hours to transition. This should be a value between 1 and 12 inclusive. +fixed_hours_per_turn_for_day_night_cycle = 1 + +; If day_night_cycle_mode is set to 'specified', the hour of the day to pin the cycle to. This should be a value between 0 (midnight) and 23 (11pm) inclusive. +pinned_hour_for_day_night_cycle = 0 + +[=======================] +[=== NATURAL WONDERS ===] +[=======================] + +; Show or hide natural wonders on the map. When disabled, natural wonders will not appear on the map. +enable_natural_wonders = true + +; If a new scenario is loaded which has no natural wonders defined, add natural wonders. +add_natural_wonders_to_scenarios_if_none = false + +; Show the names of natural wonders on the map below their image. +show_natural_wonder_name_on_map = true + +; Minimum separation (in tiles) between natural wonders when generating the map. This helps prevent clustering of natural wonders. +minimum_natural_wonder_separation = 10 + +[=================] +[=== DISTRICTS ===] +[=================] + +; Districts are Civ6-inspired structures built by workers that enable buildings, provide bonuses, and make cities feel more alive. When enabled, +; districts appear on the map and can be required for certain buildings (configured in default.districts_config.txt). Districts occupy tiles within a +; city's work radius, making those tiles unworkable. They can provide bonuses (food, shields, gold, science, culture, defense) to all cities within +; their work radius. If multiple cities share a district, they can optionally share its buildings and wonders (see options below). Districts with +; pollution or enemy units yield no bonuses. Destroyed districts remove dependent buildings from affected cities unless they have another district of +; that type in range. The five district types below can be enabled independently: +; enable_districts: Enables standard configurable districts (by default: Encampment, Campus, Holy Site, Commercial Hub, Entertainment Complex, Industrial Zone). +; Configured is done in default.districts_config.txt, user.districts_config.txt, and scenario.districts_config.txt +; enable_neighborhood_districts: Enables population growth past a configurable limit (see maximum_pop_before_neighborhood_needed below) +; enable_wonder_districts: Wonders require a dedicated district tile, making them visible on the map and optionally destructible. +; Configured in default.districts_wonders_config.txt, user.districts_wonders_config.txt, and scenario.districts_wonders_config.txt +; enable_distribution_hub_districts: Special districts that distribute food/shields from surrounding tiles to all connected cities +; enable_aerodrome_districts: Air units can only be built/based at Aerodrome districts instead of cities (if air_units_use_aerodrome_districts_not_cities is true) +; enable_port_districts: Enables Port districts, which serve as coastal district tiles for naval production/basing when naval_units_use_port_districts_not_cities is on. +; enable_bridge_districts: Enables Bridge districts on coastal water; completed bridges let land units cross water tiles. +; enable_canal_districts: Enables Canal districts on land; completed canals let naval units traverse land tiles between water bodies. +; enable_central_rail_hub_districts: Enables Central Rail Hub districts used for rail-era infrastructure (e.g., Mass Transit). +; enable_energy_grid_districts: Enables Energy Grid districts associated with power plant infrastructure. +; enable_great_wall_districts: Enables Great Wall districts (wall-like tiles that can block others if great_wall_districts_impassible_by_others is on). +enable_districts = false +enable_neighborhood_districts = false +enable_wonder_districts = false +enable_distribution_hub_districts = false +enable_aerodrome_districts = false +enable_port_districts = false +enable_bridge_districts = false +enable_canal_districts = false +enable_central_rail_hub_districts = false +enable_energy_grid_districts = false +enable_great_wall_districts = false + +; When multiple cities share a district (i.e., the same district tile is within multiple cities' work radii), these options control whether those +; cities automatically share the benefits of buildings and wonders constructed in that district. For example, if Rome and Veii both have the same +; Encampment in their work radius and Rome builds a Barracks in that Encampment, enabling cities_with_mutual_district_receive_buildings will cause +; Veii to automatically receive a Barracks as well. Similarly, cities_with_mutual_district_receive_wonders extends this sharing to Great and Small +; Wonders. This encourages strategic district placement between cities and can reduce micromanagement in dense urban areas. +; Note: receiving buildings is only assessed twice: when a city completes a building, and when a city is founded nearby. A city receiving a building +; cannot in turn recursively share it with third, fourth, fifth, etc. cities in a chain. Only applies if enable_districts is set to true. +cities_with_mutual_district_receive_buildings = true +cities_with_mutual_district_receive_wonders = true +show_message_when_building_received_by_mutual_district = true +show_message_when_building_lost_to_destroyed_district = true + +; When enabled, air units can only be built in cities with an Aerodrome district in their work radius and must be based at Aerodrome districts instead +; of cities. Air units will spawn on Aerodromes and can only land on Aerodromes, vanilla airfields, or carriers. Airlifts and airdrops are similarly +; limited to Aerodromes. This adds strategic depth by requiring infrastructure for air power and making air bases visible and vulnerable on the map. +; Only applies when enable_aerodrome_districts is also set to true. +air_units_use_aerodrome_districts_not_cities = true + +; When enabled, naval units can only be built in cities with a Port district in their work radius and cannot enter city tiles directly. Naval unit +; healing must be done at Port districts, and travel between continents, lakes and so on can instead only be done via Canal districts (via enable_canal_districts), +; rather than cities on an isthmus. Additionally, a city cannot build naval units until it has a Port district in range. Only applies when enable_port_districts is set to true. +naval_units_use_port_districts_not_cities = true + +; Neighborhood district limit population growth. Once a city reaches maximum_pop_before_neighborhood_needed, it cannot +; grow further until it has at least one Neighborhood district in its work radius. Each Neighborhood then enables additional population growth equal to +; per_neighborhood_pop_growth_enabled. For example, with maximum set to 6 and per_neighborhood set to 2, a city can grow to pop 6 without +; Neighborhoods, requires 1 Neighborhood to reach pop 8, requires 2 Neighborhoods to reach pop 10, and so on. Neighborhood bonuses (+1 gold and +1 +; culture, by default) only apply if the city actually needs them based on its population. Periodic popups will remind you when a Neighborhood is needed. Only +; applies when enable_neighborhood_districts is set to true. neighborhood_needed_message_frequency sets how often (in turns) the reminder message appears; +; set to 0 to disable. +; If destroying_neighborhood_reduces_pop is true, losing a Neighborhood district reduces the city's population down to the new cap. +maximum_pop_before_neighborhood_needed = 6 +per_neighborhood_pop_growth_enabled = 3 +neighborhood_needed_message_frequency = 4 +destroying_neighborhood_reduces_pop = true + +; These options control the vulnerability and rebuildability of completed Wonders in Wonder districts. When completed_wonder_districts_can_be_destroyed +; is enabled, completed Wonders (both Great and Small) can be pillaged or destroyed by enemies, making them valuable strategic targets that must be +; defended. When destroyed_wonders_can_be_built_again is enabled, destroyed Wonders become available again for any civ to build, putting them back +; into play. Only applies when enable_wonder_districts is set to true. +completed_wonder_districts_can_be_destroyed = true +destroyed_wonders_can_be_built_again = true + +; Distribution Hubs work as "breadbaskets" and mining areas far from urban centers, minimizing local city potential but benefiting the entire civilization. +; Distribution Hubs make surrounding tiles unworkable and instead distribute their raw food and shield yields to ALL connected cities in your civilization. +; "Divisors" for food and shields multiply the sqrt-based divisor in scale-by-city-count mode, and are a straight divider in flat mode. Yields are subject +; to corruption as with regular shields. +; +; ai_ideal_distribution_hub_count_per_100_cities controls how many hubs the AI tries to maintain per 100 cities if distribution_hub_yield_division_mode +; is set to "flat" (e.g., 25 means the AI aims for 1 hub per 4 cities). +; +; distribution_hub_yield_division_mode controls how a hub splits its collected food/shields across connected cities: +; flat: Divide raw yields by the configured divisors (distribution_hub_food_yield_divisor & distribution_hub_shield_yield_divisor) +; scale-by-city-count: Bonuses gradually reduce as more cities plug into the hub. Formula: floor(raw_yield / (sqrt(connected_city_count) * divisor)) +; +; ai_distribution_hub_build_strategy controls how the AI decides to build distribution hubs: +; by-city-count: AI builds hubs based on its ideal hub count per 100 cities +; auto: AI dynamically assesses need based on city growth and food/shield deficits across civ +distribution_hub_yield_division_mode = scale-by-city-count +ai_distribution_hub_build_strategy = auto +distribution_hub_food_yield_divisor = 2 +distribution_hub_shield_yield_divisor = 2 +ai_ideal_distribution_hub_count_per_100_cities = 50 +max_distribution_hub_count_per_100_cities = 50 + +; Bonus percent applied to Distribution Hub food and shield yields for cities that have a Central Rail Hub district in their work radius. +central_rail_hub_distribution_food_bonus_percent = 25 +central_rail_hub_distribution_shield_bonus_percent = 25 + +; District placement and AI bridge/canal behavior: +; expand_water_tile_checks_to_city_work_area: Use the full city work radius (not just adjacent tiles) for river/lake/sea checks (e.g. to build a port if a +; city has coast within its work area, even if not adjacent to the sea). +; Note that this does not affect Aqueducts or Coastal Fortresses, which still require direct city adjacency. +; workers_can_enter_coast: Allow workers to move onto coast tiles without embarking. +; max_contiguous_bridge_districts: Maximum number of contiguous bridge district tiles allowed in a line (0 = no limit). +; max_contiguous_canal_districts: Maximum number of contiguous canal district tiles allowed in a line (0 = no limit). +; ai_canal_eval_min_bisected_land_tiles: Minimum land tiles required on each side for the AI to consider a canal candidate. +; ai_bridge_canal_eval_block_size: Map block size used when scanning for AI bridge/canal candidates. +; ai_bridge_eval_lake_tile_threshold: Water bodies at or below this size are treated as lakes for AI bridge evaluation. +; ai_can_replace_existing_districts_with_canals: Allow the AI to build canal/bridge districts over existing non-wonder districts. +; ai_builds_bridges: Allow the AI to construct bridge districts. +; ai_builds_canals: Allow the AI to construct canal districts. +expand_water_tile_checks_to_city_work_area = true +workers_can_enter_coast = true +max_contiguous_bridge_districts = 3 +max_contiguous_canal_districts = 5 +ai_canal_eval_min_bisected_land_tiles = 20 +ai_bridge_canal_eval_block_size = 10 +ai_bridge_eval_lake_tile_threshold = 5 +ai_can_replace_existing_districts_with_canals = true +ai_builds_bridges = true +ai_builds_canals = true + +; When enabled, AI defensive units will actively seek out and defend districts within their territory, treating them as valuable assets like colonies. +; The AI prioritizes defending Wonder districts (if destructible wonders are enabled) over regular districts, searching within a 20-tile radius for +; districts that need protection from nearby enemy units. This makes districts meaningful strategic targets and ensures the AI protects its +; infrastructure. Only applies when enable_districts is set to true. +ai_defends_districts = true + +; As AI cities queue up districts needed, the max number of turns to wait for a worker to build it before the request is dropped +; until the AI city is triggered to build the district again (e.g., by trying to build a building that depends on it) +ai_city_district_max_build_wait_turns = 20 + +; Great Wall behavior: +; disable_great_wall_city_defense_bonus: Disables the Great Wall wonder's city defense doubling effect. Only takes effect if districts and great wall districts are enabled. +; great_wall_districts_impassible_by_others: Great Wall district tiles block movement by other civs (unless obsolete). +; auto_build_great_wall_around_territory: Auto-place Great Wall districts along your borders when the specified wonder is built. +; great_wall_auto_build_wonder_name: Name of the wonder that triggers auto-building (empty disables auto-build). +; ai_auto_build_great_wall_strategy: How AI uses auto-built Great Wall: all-borders (any border tiles) or other-civ-bordered-only (only borders touching another civ). +disable_great_wall_city_defense_bonus = false +great_wall_districts_impassible_by_others = true +auto_build_great_wall_around_territory = true +great_wall_auto_build_wonder_name = "The Great Wall" +ai_auto_build_great_wall_strategy = other-civ-bordered-only + +; When enabled, holding down the Control key while a worker is selected will highlight all tiles within the work radii of nearby cities. City centers +; are highlighted more brightly, while tiles that fall within multiple cities' work radii are highlighted more intensely. This visual aid helps you +; strategically place districts and improvements by showing which cities will be affected. The highlights update dynamically as you move the worker +; around the map. Only applies when enable_districts is set to true. +enable_city_work_radii_highlights = true diff --git a/default.districts_config.txt b/default.districts_config.txt index da740387..0e174808 100644 --- a/default.districts_config.txt +++ b/default.districts_config.txt @@ -1,471 +1,471 @@ -[======================================================================= NOTE =======================================================================] -[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] -[be named scenario.districts_config.txt and must be located in your scenario search folder. Of course it only applies if you are using a scenario. ] -[The user config file must be named user.districts_config.txt and located in the C3X folder, which is the folder where this file is. When creating ] -[scenario or user configs, note that all districts defined here will be removed and only your scenario or user-defined districts will be used ] -[====================================================================================================================================================] - -[ - ; District config fields (each District block begins with "#District") - ; - name : Text (required). Internal district name; must be unique. - ; - display_name : Text. Name shown to user; defaults to name. - ; - tooltip : Text. Shown when hovering over build action button. - ; - img_paths : Comma-separated PCX filenames under Art/Districts/1200/. - 1 for single image, 5 for culture variants (AMER, EURO, ROMAN, MIDEAST, ASIAN). Order matters. - ; - img_column_count : Number. Overrides the number of sprite columns per image (derived from dependent_improvs if omitted). - ; - render_strategy : "by-count" | "by-building". Whether the PCX files show all buildings together, or one building per column. (default: "by-count") - ; - draw_over_resources : 0 or 1. If a resource is also on the tile, draw the district on top. (default: 0) - ; - vary_img_by_era : 0 or 1. If 1, each PCX image must have 4 rows, 1 for each era. - ; - vary_img_by_culture : 0 or 1. If 1, img_paths should list 5 files (AMER, EURO, ROMAN, MIDEAST, ASIAN). - ; - btn_tile_sheet_row : Number. Row index in the district button tile sheet (0-based). - ; - btn_tile_sheet_column : Number. Column index in the district button tile sheet (0-based). - ; - dependent_improvs : Comma-separated city improvement names. Cities can't build these improvements until they have this district. - ; - generated_resource : Resource name plus optional flags: local, yields, no-tech-req. District generates resource if tile connected by road. - ; - advance_prereqs : Comma-separated tech names. District cannot be built unless all techs are discovered. - ; - obsoleted_by : Tech name that obsoletes this district. District cannot built after discovery. - ; - resource_prereqs : Comma-separated resource names. The tile must be connected to cities with all required resources to be built. - ; - resource_prereq_on_tile : Resource name required on the district tile. District cannot be built unless resource is on same tile. - ; - wonder_prereqs : Comma-separated wonder names. District cannot be built unless all Wonders are built by same civ. - ; - natural_wonder_prereqs : Comma-separated natural wonder names. District cannot be built unless all Natural Wonders are within civ's territory. - ; - buildable_on : Comma-separated tile types: desert, plains, grassland, tundra, floodplain, hill, mountain, volcano, - ; coast, sea, ocean, snow-forest, snow-mountain, snow-volcano, lake. (tile must be one of these) - ; - buildable_on_overlays : Comma-separated overlays: irrigation, mine, fortress, barricade, jungle, forest, marsh, airfield. (optional; tile must be one of these). - ; - buildable_on_districts : Comma-separated district names (tile must already have a completed district of any of these types, which it would replace). - ; - buildable_on_rivers : 0 or 1. If 1, district tile must be on a river. - ; - buildable_without_removal : Comma-separated overlays: jungle, forest, marsh. (optional; tile *may* have these, workers don't need to remove them first). - ; - buildable_adjacent_to : Same as buildable_on, plus "city". - ; - buildable_adjacent_to_overlays : Same as buildable_on_overlays. - ; - buildable_adjacent_to_districts : Comma-separated district names (adjacent tile must have a completed district of any of these types). - ; - buildable_by_civs : Comma-separated civ names (e.g., Romans, Egyptians). - ; - buildable_by_civ_traits : Comma-separated trait names (e.g., Commercial, Militaristic). - ; - buildable_by_civ_govs : Comma-separated government names (e.g., Republic, Monarchy). - ; - buildable_by_civ_cultures : Comma-separated culture names (e.g., EURO, ASIAN). - ; - buildable_by_war_allies : 0 or 1. Can build if war allied with a civ that can build it. - ; - buildable_by_pact_allies : 0 or 1. Can build if mutual defense pact allied with a civ that can build it. - ; - ai_build_strategy : "district" | "tile-improvement". If "tile_improvement", the AI may build many. (default: "district") - ; - defense_bonus_percent : Number, with optional "Name: bonus" entries (Name = building or tile type, each added to base bonus if true. Negative values allowed). - ; - culture_bonus : Number, with optional "Name: bonus" entries (same pattern as defense_bonus_percent). - ; - science_bonus : Number, with optional "Name: bonus" entries. - ; - food_bonus : Number, with optional "Name: bonus" entries. - ; - gold_bonus : Number, with optional "Name: bonus" entries. - ; - shield_bonus : Number, with optional "Name: bonus" entries. - ; - happiness_bonus : Number, with optional "Name: bonus" entries. - ; - custom_width : Number (pixels). Override sprite width. (default: 128) - ; - custom_height : Number (pixels). Override sprite height. (default: 64) - ; - x_offset : Number (pixels). Push the sprite farther to the right (or left, if negative). (default: 0) - ; - y_offset : Number (pixels). Push the sprite farther down (or up, if negative). (default: 0) - ; - align_to_coast : 0 or 1. Aligns art to coastline, slightly adjusting x & y pixels. (default: 0) - ; - auto_add_road : 0 or 1. Auto-add road on completion. (default: 0) - ; - auto_add_railroad : 0 or 1. Auto-add railroad on completion. (default: 0) - ; - impassible : 0 or 1. If 1, completed district tile is impassible to units. (default: 0) - ; - impassible_to_wheeled : 0 or 1. If 1, completed district tile is impassible to wheeled units unless connected by road. (default: 0) - ; - allow_irrigation_from : 0 or 1. District can act as an irrigation source. (default: 0) - ; - allow_multiple : 0 or 1. If 1, multiple copies can exist per city. (default: 0) - ; - heal_units_in_one_turn : 0 or 1. Friendly units fully heal when ending turn here. (default: 0) -] - -[=========================================================================] -[=========================STANDARD DISTRICTS==============================] -[=========================================================================] - -#District -name = Encampment -tooltip = Build Encampment -img_paths = Encampment.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 0 -vary_img_by_era = 1 -vary_img_by_culture = 0 -advance_prereqs = Warrior Code -dependent_improvs = Barracks,"SAM Missile Battery" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -heal_units_in_one_turn = 1 -defense_bonus_percent = 50, Barracks: 25, hill: 25 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 1, Barracks: 1 -happiness_bonus = 0 - -#District -name = Holy Site -tooltip = Build Holy Site -img_paths = HolySite_AMER.pcx, HolySite_EURO.pcx, HolySite_ROMAN.pcx, HolySite_MIDEAST.pcx, HolySite_ASIAN.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 1 -vary_img_by_era = 0 -vary_img_by_culture = 1 -advance_prereqs = "Ceremonial Burial" -dependent_improvs = Temple,Cathedral -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 2, Temple: 2, Cathedral: 2 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Campus -tooltip = Build Campus -img_paths = Campus.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 2 -vary_img_by_era = 1 -vary_img_by_culture = 0 -advance_prereqs = Literature -dependent_improvs = Library, University -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 1, Library: 2, University: 2 -science_bonus = 1, Library: 2, University: 2 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Entertainment Complex -tooltip = Build Entertainment Complex -img_paths = EntertainmentComplex_AMER.pcx, EntertainmentComplex_EURO.pcx, EntertainmentComplex_ROMAN.pcx, EntertainmentComplex_MIDEAST.pcx, EntertainmentComplex_ASIAN.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 3 -vary_img_by_era = 1 -vary_img_by_culture = 1 -advance_prereqs = Construction -dependent_improvs = Colosseum -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 1, Colosseum: 1 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 2, Colosseum: 1 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Commercial Hub -tooltip = Build Commercial Hub -img_paths = CommercialHub_AMER.pcx, CommercialHub_EURO.pcx, CommercialHub_ROMAN.pcx, CommercialHub_MIDEAST.pcx, CommercialHub_ASIAN.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 4 -vary_img_by_era = 1 -vary_img_by_culture = 1 -advance_prereqs = Currency -dependent_improvs = Marketplace, Bank, "Stock Exchange" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0, Marketplace: 1 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 2, Marketplace: 1, Bank: 1, "Stock Exchange": 1, river: 2 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Industrial Zone -tooltip = Build Industrial Zone -img_paths = IndustrialZone.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 5 -vary_img_by_era = 1 -vary_img_by_culture = 0 -advance_prereqs = Industrialization -dependent_improvs = Factory, "Manufacturing Plant" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 2, Factory: 2, "Manufacturing Plant": 2, river: 2 -happiness_bonus = 0 - -#District -name = Data Center -tooltip = Build Data Center -img_paths = DataCenter.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 6 -vary_img_by_era = 1 -vary_img_by_culture = 0 -advance_prereqs = Computers -dependent_improvs = "Research Lab" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 4, "Research Lab": 4 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = -2 - -#District -name = Offshore Extraction Zone -tooltip = Build Offshore Extraction Zone -img_paths = OffshoreExtractionZone.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 7 -vary_img_by_era = 0 -vary_img_by_culture = 0 -advance_prereqs = Miniaturization -dependent_improvs = Offshore Platform -buildable_on = coast -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 2 -happiness_bonus = 0 - -#District -name = Park -tooltip = Build Park -img_paths = Park.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 8 -vary_img_by_era = 1 -vary_img_by_culture = 0 -advance_prereqs = Engineering -dependent_improvs = -buildable_on_overlays = forest -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 2 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 2 - -#District -name = Ski Resort -tooltip = Build Ski Resort -img_paths = SkiResort.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 9 -vary_img_by_era = 0 -vary_img_by_culture = 0 -advance_prereqs = Electricity -dependent_improvs = -buildable_on = snow-mountain -custom_height = 88 -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 2 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 4 -shield_bonus = 0 -happiness_bonus = 2 - -#District -name = Water Park -tooltip = Build Water Park -img_paths = WaterPark.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 10 -vary_img_by_era = 0 -vary_img_by_culture = 0 -advance_prereqs = Miniaturization -dependent_improvs = -buildable_on = coast -custom_height = 88 -defense_bonus_percent = 0 -allow_multiple = 0 -culture_bonus = 2 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 4 -shield_bonus = -2 -happiness_bonus = 2 - -[========================================================================] -[=========================SPECIAL DISTRICTS==============================] -[========================================================================] - -#District -name = Neighborhood -tooltip = Build Neighborhood -buildable_on = desert,plains,grassland,tundra,floodplain,hill -advance_prereqs = -auto_add_road = 1 -defense_bonus_percent = 25 -allow_multiple = 1 -culture_bonus = 1 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 1 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Wonder District -tooltip = Build Wonder District -buildable_on = desert,plains,grassland,tundra,floodplain,hill,coast,mountain -advance_prereqs = -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Distribution Hub -tooltip = Build Distribution Hub -buildable_on = desert,plains,grassland,tundra,floodplain,hill -advance_prereqs = Construction -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Aerodrome -tooltip = Build Aerodrome -buildable_on = desert,plains,grassland,tundra,floodplain,hill -advance_prereqs = Flight -dependent_improvs = Airport -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Port -tooltip = Build Port -buildable_on = coast -advance_prereqs = Map Making -dependent_improvs = Harbor, "Commercial Dock" -heal_units_in_one_turn = 1 -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 2 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Central Rail Hub -tooltip = Build Central Rail Hub -btn_tile_sheet_row = 0 -btn_tile_sheet_column = 5 -vary_img_by_era = 1 -vary_img_by_culture = 1 -advance_prereqs = Steam Power -resource_prereqs = Iron, Coal -dependent_improvs = "Mass Transit System" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -auto_add_railroad = 1 -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 4 -happiness_bonus = 0 - -#District -name = Energy Grid -tooltip = Build Energy Grid -btn_tile_sheet_row = 0 -btn_tile_sheet_column = 6 -vary_img_by_era = 1 -vary_img_by_culture = 0 -custom_height = 88 -advance_prereqs = Industrialization -dependent_improvs = "Coal Plant", "Hydro Plant", "Nuclear Plant", "Solar Plant" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 2 -happiness_bonus = 0 - -#District -name = Bridge -tooltip = Build Bridge -btn_tile_sheet_row = 0 -btn_tile_sheet_column = 7 -custom_height = 112 -custom_width = 176 -y_offset = 24 -x_offset = 0 -advance_prereqs = Industrialization -buildable_on = coast -auto_add_road = 1 -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Canal -tooltip = Build Canal -btn_tile_sheet_row = 0 -btn_tile_sheet_column = 8 -custom_height = 112 -custom_width = 176 -y_offset = 24 -x_offset = 0 -advance_prereqs = Industrialization -buildable_on = desert,plains,grassland,tundra,floodplain -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Great Wall -btn_tile_sheet_row = 0 -btn_tile_sheet_column = 9 -tooltip = Build Great Wall -obsoleted_by = Metallurgy -wonder_prereqs = "The Great Wall" -buildable_on = desert,plains,grassland,tundra,floodplain,mountain,hill,volcano -buildable_without_removal = forest,marsh,jungle -draw_over_resources = 1 -defense_bonus_percent = 50 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 +[======================================================================= NOTE =======================================================================] +[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] +[be named scenario.districts_config.txt and must be located in your scenario search folder. Of course it only applies if you are using a scenario. ] +[The user config file must be named user.districts_config.txt and located in the C3X folder, which is the folder where this file is. When creating ] +[scenario or user configs, note that all districts defined here will be removed and only your scenario or user-defined districts will be used ] +[====================================================================================================================================================] + +[ + ; District config fields (each District block begins with "#District") + ; - name : Text (required). Internal district name; must be unique. + ; - display_name : Text. Name shown to user; defaults to name. + ; - tooltip : Text. Shown when hovering over build action button. + ; - img_paths : Comma-separated PCX filenames under Art/Districts/1200/. + 1 for single image, 5 for culture variants (AMER, EURO, ROMAN, MIDEAST, ASIAN). Order matters. + ; - img_column_count : Number. Overrides the number of sprite columns per image (derived from dependent_improvs if omitted). + ; - render_strategy : "by-count" | "by-building". Whether the PCX files show all buildings together, or one building per column. (default: "by-count") + ; - draw_over_resources : 0 or 1. If a resource is also on the tile, draw the district on top. (default: 0) + ; - vary_img_by_era : 0 or 1. If 1, each PCX image must have 4 rows, 1 for each era. + ; - vary_img_by_culture : 0 or 1. If 1, img_paths should list 5 files (AMER, EURO, ROMAN, MIDEAST, ASIAN). + ; - btn_tile_sheet_row : Number. Row index in the district button tile sheet (0-based). + ; - btn_tile_sheet_column : Number. Column index in the district button tile sheet (0-based). + ; - dependent_improvs : Comma-separated city improvement names. Cities can't build these improvements until they have this district. + ; - generated_resource : Resource name plus optional flags: local, yields, no-tech-req. District generates resource if tile connected by road. + ; - advance_prereqs : Comma-separated tech names. District cannot be built unless all techs are discovered. + ; - obsoleted_by : Tech name that obsoletes this district. District cannot built after discovery. + ; - resource_prereqs : Comma-separated resource names. The tile must be connected to cities with all required resources to be built. + ; - resource_prereq_on_tile : Resource name required on the district tile. District cannot be built unless resource is on same tile. + ; - wonder_prereqs : Comma-separated wonder names. District cannot be built unless all Wonders are built by same civ. + ; - natural_wonder_prereqs : Comma-separated natural wonder names. District cannot be built unless all Natural Wonders are within civ's territory. + ; - buildable_on : Comma-separated tile types: desert, plains, grassland, tundra, floodplain, hill, mountain, volcano, + ; coast, sea, ocean, snow-forest, snow-mountain, snow-volcano, lake. (tile must be one of these) + ; - buildable_on_overlays : Comma-separated overlays: irrigation, mine, fortress, barricade, jungle, forest, marsh, airfield. (optional; tile must be one of these). + ; - buildable_on_districts : Comma-separated district names (tile must already have a completed district of any of these types, which it would replace). + ; - buildable_on_rivers : 0 or 1. If 1, district tile must be on a river. + ; - buildable_without_removal : Comma-separated overlays: jungle, forest, marsh. (optional; tile *may* have these, workers don't need to remove them first). + ; - buildable_adjacent_to : Same as buildable_on, plus "city". + ; - buildable_adjacent_to_overlays : Same as buildable_on_overlays. + ; - buildable_adjacent_to_districts : Comma-separated district names (adjacent tile must have a completed district of any of these types). + ; - buildable_by_civs : Comma-separated civ names (e.g., Romans, Egyptians). + ; - buildable_by_civ_traits : Comma-separated trait names (e.g., Commercial, Militaristic). + ; - buildable_by_civ_govs : Comma-separated government names (e.g., Republic, Monarchy). + ; - buildable_by_civ_cultures : Comma-separated culture names (e.g., EURO, ASIAN). + ; - buildable_by_war_allies : 0 or 1. Can build if war allied with a civ that can build it. + ; - buildable_by_pact_allies : 0 or 1. Can build if mutual defense pact allied with a civ that can build it. + ; - ai_build_strategy : "district" | "tile-improvement". If "tile_improvement", the AI may build many. (default: "district") + ; - defense_bonus_percent : Number, with optional "Name: bonus" entries (Name = building or tile type, each added to base bonus if true. Negative values allowed). + ; - culture_bonus : Number, with optional "Name: bonus" entries (same pattern as defense_bonus_percent). + ; - science_bonus : Number, with optional "Name: bonus" entries. + ; - food_bonus : Number, with optional "Name: bonus" entries. + ; - gold_bonus : Number, with optional "Name: bonus" entries. + ; - shield_bonus : Number, with optional "Name: bonus" entries. + ; - happiness_bonus : Number, with optional "Name: bonus" entries. + ; - custom_width : Number (pixels). Override sprite width. (default: 128) + ; - custom_height : Number (pixels). Override sprite height. (default: 64) + ; - x_offset : Number (pixels). Push the sprite farther to the right (or left, if negative). (default: 0) + ; - y_offset : Number (pixels). Push the sprite farther down (or up, if negative). (default: 0) + ; - align_to_coast : 0 or 1. Aligns art to coastline, slightly adjusting x & y pixels. (default: 0) + ; - auto_add_road : 0 or 1. Auto-add road on completion. (default: 0) + ; - auto_add_railroad : 0 or 1. Auto-add railroad on completion. (default: 0) + ; - impassible : 0 or 1. If 1, completed district tile is impassible to units. (default: 0) + ; - impassible_to_wheeled : 0 or 1. If 1, completed district tile is impassible to wheeled units unless connected by road. (default: 0) + ; - allow_irrigation_from : 0 or 1. District can act as an irrigation source. (default: 0) + ; - allow_multiple : 0 or 1. If 1, multiple copies can exist per city. (default: 0) + ; - heal_units_in_one_turn : 0 or 1. Friendly units fully heal when ending turn here. (default: 0) +] + +[=========================================================================] +[=========================STANDARD DISTRICTS==============================] +[=========================================================================] + +#District +name = Encampment +tooltip = Build Encampment +img_paths = Encampment.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 0 +vary_img_by_era = 1 +vary_img_by_culture = 0 +advance_prereqs = Warrior Code +dependent_improvs = Barracks,"SAM Missile Battery" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +heal_units_in_one_turn = 1 +defense_bonus_percent = 50, Barracks: 25, hill: 25 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 1, Barracks: 1 +happiness_bonus = 0 + +#District +name = Holy Site +tooltip = Build Holy Site +img_paths = HolySite_AMER.pcx, HolySite_EURO.pcx, HolySite_ROMAN.pcx, HolySite_MIDEAST.pcx, HolySite_ASIAN.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 1 +vary_img_by_era = 0 +vary_img_by_culture = 1 +advance_prereqs = "Ceremonial Burial" +dependent_improvs = Temple,Cathedral +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 2, Temple: 2, Cathedral: 2 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Campus +tooltip = Build Campus +img_paths = Campus.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 2 +vary_img_by_era = 1 +vary_img_by_culture = 0 +advance_prereqs = Literature +dependent_improvs = Library, University +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 1, Library: 2, University: 2 +science_bonus = 1, Library: 2, University: 2 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Entertainment Complex +tooltip = Build Entertainment Complex +img_paths = EntertainmentComplex_AMER.pcx, EntertainmentComplex_EURO.pcx, EntertainmentComplex_ROMAN.pcx, EntertainmentComplex_MIDEAST.pcx, EntertainmentComplex_ASIAN.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 3 +vary_img_by_era = 1 +vary_img_by_culture = 1 +advance_prereqs = Construction +dependent_improvs = Colosseum +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 1, Colosseum: 1 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 2, Colosseum: 1 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Commercial Hub +tooltip = Build Commercial Hub +img_paths = CommercialHub_AMER.pcx, CommercialHub_EURO.pcx, CommercialHub_ROMAN.pcx, CommercialHub_MIDEAST.pcx, CommercialHub_ASIAN.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 4 +vary_img_by_era = 1 +vary_img_by_culture = 1 +advance_prereqs = Currency +dependent_improvs = Marketplace, Bank, "Stock Exchange" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0, Marketplace: 1 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 2, Marketplace: 1, Bank: 1, "Stock Exchange": 1, river: 2 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Industrial Zone +tooltip = Build Industrial Zone +img_paths = IndustrialZone.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 5 +vary_img_by_era = 1 +vary_img_by_culture = 0 +advance_prereqs = Industrialization +dependent_improvs = Factory, "Manufacturing Plant" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 2, Factory: 2, "Manufacturing Plant": 2, river: 2 +happiness_bonus = 0 + +#District +name = Data Center +tooltip = Build Data Center +img_paths = DataCenter.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 6 +vary_img_by_era = 1 +vary_img_by_culture = 0 +advance_prereqs = Computers +dependent_improvs = "Research Lab" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 4, "Research Lab": 4 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = -2 + +#District +name = Offshore Extraction Zone +tooltip = Build Offshore Extraction Zone +img_paths = OffshoreExtractionZone.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 7 +vary_img_by_era = 0 +vary_img_by_culture = 0 +advance_prereqs = Miniaturization +dependent_improvs = Offshore Platform +buildable_on = coast +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 2 +happiness_bonus = 0 + +#District +name = Park +tooltip = Build Park +img_paths = Park.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 8 +vary_img_by_era = 1 +vary_img_by_culture = 0 +advance_prereqs = Engineering +dependent_improvs = +buildable_on_overlays = forest +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 2 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 2 + +#District +name = Ski Resort +tooltip = Build Ski Resort +img_paths = SkiResort.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 9 +vary_img_by_era = 0 +vary_img_by_culture = 0 +advance_prereqs = Electricity +dependent_improvs = +buildable_on = snow-mountain +custom_height = 88 +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 2 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 4 +shield_bonus = 0 +happiness_bonus = 2 + +#District +name = Water Park +tooltip = Build Water Park +img_paths = WaterPark.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 10 +vary_img_by_era = 0 +vary_img_by_culture = 0 +advance_prereqs = Miniaturization +dependent_improvs = +buildable_on = coast +custom_height = 88 +defense_bonus_percent = 0 +allow_multiple = 0 +culture_bonus = 2 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 4 +shield_bonus = -2 +happiness_bonus = 2 + +[========================================================================] +[=========================SPECIAL DISTRICTS==============================] +[========================================================================] + +#District +name = Neighborhood +tooltip = Build Neighborhood +buildable_on = desert,plains,grassland,tundra,floodplain,hill +advance_prereqs = +auto_add_road = 1 +defense_bonus_percent = 25 +allow_multiple = 1 +culture_bonus = 1 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 1 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Wonder District +tooltip = Build Wonder District +buildable_on = desert,plains,grassland,tundra,floodplain,hill,coast,mountain +advance_prereqs = +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Distribution Hub +tooltip = Build Distribution Hub +buildable_on = desert,plains,grassland,tundra,floodplain,hill +advance_prereqs = Construction +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Aerodrome +tooltip = Build Aerodrome +buildable_on = desert,plains,grassland,tundra,floodplain,hill +advance_prereqs = Flight +dependent_improvs = Airport +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Port +tooltip = Build Port +buildable_on = coast +advance_prereqs = Map Making +dependent_improvs = Harbor, "Commercial Dock" +heal_units_in_one_turn = 1 +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 2 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Central Rail Hub +tooltip = Build Central Rail Hub +btn_tile_sheet_row = 0 +btn_tile_sheet_column = 5 +vary_img_by_era = 1 +vary_img_by_culture = 1 +advance_prereqs = Steam Power +resource_prereqs = Iron, Coal +dependent_improvs = "Mass Transit System" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +auto_add_railroad = 1 +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 4 +happiness_bonus = 0 + +#District +name = Energy Grid +tooltip = Build Energy Grid +btn_tile_sheet_row = 0 +btn_tile_sheet_column = 6 +vary_img_by_era = 1 +vary_img_by_culture = 0 +custom_height = 88 +advance_prereqs = Industrialization +dependent_improvs = "Coal Plant", "Hydro Plant", "Nuclear Plant", "Solar Plant" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 2 +happiness_bonus = 0 + +#District +name = Bridge +tooltip = Build Bridge +btn_tile_sheet_row = 0 +btn_tile_sheet_column = 7 +custom_height = 112 +custom_width = 176 +y_offset = 24 +x_offset = 0 +advance_prereqs = Industrialization +buildable_on = coast +auto_add_road = 1 +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Canal +tooltip = Build Canal +btn_tile_sheet_row = 0 +btn_tile_sheet_column = 8 +custom_height = 112 +custom_width = 176 +y_offset = 24 +x_offset = 0 +advance_prereqs = Industrialization +buildable_on = desert,plains,grassland,tundra,floodplain +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Great Wall +btn_tile_sheet_row = 0 +btn_tile_sheet_column = 9 +tooltip = Build Great Wall +obsoleted_by = Metallurgy +wonder_prereqs = "The Great Wall" +buildable_on = desert,plains,grassland,tundra,floodplain,mountain,hill,volcano +buildable_without_removal = forest,marsh,jungle +draw_over_resources = 1 +defense_bonus_percent = 50 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 diff --git a/default.districts_natural_wonders_config.txt b/default.districts_natural_wonders_config.txt index e09ed806..1d43b444 100644 --- a/default.districts_natural_wonders_config.txt +++ b/default.districts_natural_wonders_config.txt @@ -1,279 +1,279 @@ -[======================================================================= NOTE =======================================================================] -[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] -[be named scenario.districts_natural_wonders_config.txt and must be located in your scenario search folder. Of course it only applies if you are ] -[using a scenario. The user config file must be named user.districts_natural_wonders_config.txt and located in the C3X folder, which is the folder ] -[where this file is. When creating scenario or user configs, note that all natural wonders defined here will be removed and only your scenario or ] -[user-defined districts will be used. ] -[====================================================================================================================================================] - -[ - ; Natural Wonder config fields (each Wonder block begins with "#Wonder") - ; - name : Text (required). Internal natural wonder name; must be unique. - ; - terrain_type : Text (required). Base terrain: desert, plains, grassland, jungle, tundra, floodplain, marsh, hill, mountain, - forest, volcano, snow-forest, snow-mountain, snow-volcano, coast, sea, ocean. - ; - adjacent_to : Text. Optional adjacency requirement: same list as buildable square types plus river, any (no requirement). - ; - adjacency_dir : Text. Optional direction filter for adjacent_to (northeast, east, southeast, south, southwest, west, northwest, north). - ; - img_path : Text (required). PCX filename (under Art/Districts/1200/). - ; - img_row : Number (required). Row index in the PCX (0-based). - ; - img_column : Number (required). Column index in the PCX (0-based). - ; - culture_bonus : Number. Culture yield bonus when worked. - ; - science_bonus : Number. Science yield bonus when worked. - ; - food_bonus : Number. Food yield bonus when worked. - ; - gold_bonus : Number. Gold yield bonus when worked. - ; - shield_bonus : Number. Shield yield bonus when worked. - ; - happiness_bonus : Number. Happiness bonus when worked. - ; - impassible : 0 or 1. If 1, completed natural wonder tile is impassible to units. (default: 0) - ; - impassible_to_wheeled : 0 or 1. If 1, completed natural wonder tile is impassible to wheeled units unless connected by road. (default: 0) -] - -#Wonder -name = Angel Falls -terrain_type = grassland -adjacent_to = river -adjacency_dir = southeast -img_path = NaturalWonders.pcx -img_row = 0 -img_column = 0 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Yosemite -terrain_type = grassland -adjacent_to = forest -img_path = NaturalWonders.pcx -img_row = 0 -img_column = 1 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Mount Fuji -terrain_type = grassland -img_path = NaturalWonders.pcx -img_row = 0 -img_column = 2 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Yellowstone -terrain_type = grassland -adjacent_to = forest -img_path = NaturalWonders.pcx -img_row = 0 -img_column = 3 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Mount Everest -terrain_type = grassland -adjacent_to = snow-mountains -img_path = NaturalWonders.pcx -img_row = 1 -img_column = 0 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Zhangjiajie Mountains -terrain_type = jungle -adjacent_to = jungle -img_path = NaturalWonders.pcx -img_row = 1 -img_column = 1 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Mount Kilimanjaro -terrain_type = grassland -img_path = NaturalWonders.pcx -img_row = 1 -img_column = 2 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Great Barrier Reef -terrain_type = sea -adjacent_to = coast -img_path = NaturalWonders.pcx -img_row = 1 -img_column = 3 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Matterhorn -terrain_type = grassland -adjacent_to = snow-mountains -img_path = NaturalWonders.pcx -img_row = 2 -img_column = 0 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Moraine Lake -terrain_type = grassland -adjacent_to = mountains -img_path = NaturalWonders.pcx -img_row = 2 -img_column = 1 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Tropical Rainforest -terrain_type = jungle -adjacent_to = jungle -img_path = NaturalWonders.pcx -img_row = 2 -img_column = 2 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Wadi Rum -terrain_type = desert -adjacent_to = desert -img_path = NaturalWonders.pcx -img_row = 2 -img_column = 3 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Eyjafjallajokull -terrain_type = tundra -adjacent_to = tundra -img_path = NaturalWonders.pcx -img_row = 3 -img_column = 0 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Ha Long Bay -terrain_type = coast -adjacent_to = sea -img_path = NaturalWonders.pcx -img_row = 3 -img_column = 1 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Lofoten Skerries -terrain_type = coast -adjacent_to = tundra -img_path = NaturalWonders.pcx -img_row = 3 -img_column = 2 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Geirangerfjord -terrain_type = tundra -adjacent_to = coast -adjacency_dir = south -img_path = NaturalWonders.pcx -img_row = 3 -img_column = 3 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Delicate Arch -terrain_type = desert -adjacent_to = desert -img_path = NaturalWonders.pcx -img_row = 4 -img_column = 0 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Savanna -terrain_type = plains -adjacent_to = plains -img_path = NaturalWonders.pcx -img_row = 4 -img_column = 1 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 +[======================================================================= NOTE =======================================================================] +[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] +[be named scenario.districts_natural_wonders_config.txt and must be located in your scenario search folder. Of course it only applies if you are ] +[using a scenario. The user config file must be named user.districts_natural_wonders_config.txt and located in the C3X folder, which is the folder ] +[where this file is. When creating scenario or user configs, note that all natural wonders defined here will be removed and only your scenario or ] +[user-defined districts will be used. ] +[====================================================================================================================================================] + +[ + ; Natural Wonder config fields (each Wonder block begins with "#Wonder") + ; - name : Text (required). Internal natural wonder name; must be unique. + ; - terrain_type : Text (required). Base terrain: desert, plains, grassland, jungle, tundra, floodplain, marsh, hill, mountain, + forest, volcano, snow-forest, snow-mountain, snow-volcano, coast, sea, ocean. + ; - adjacent_to : Text. Optional adjacency requirement: same list as buildable square types plus river, any (no requirement). + ; - adjacency_dir : Text. Optional direction filter for adjacent_to (northeast, east, southeast, south, southwest, west, northwest, north). + ; - img_path : Text (required). PCX filename (under Art/Districts/1200/). + ; - img_row : Number (required). Row index in the PCX (0-based). + ; - img_column : Number (required). Column index in the PCX (0-based). + ; - culture_bonus : Number. Culture yield bonus when worked. + ; - science_bonus : Number. Science yield bonus when worked. + ; - food_bonus : Number. Food yield bonus when worked. + ; - gold_bonus : Number. Gold yield bonus when worked. + ; - shield_bonus : Number. Shield yield bonus when worked. + ; - happiness_bonus : Number. Happiness bonus when worked. + ; - impassible : 0 or 1. If 1, completed natural wonder tile is impassible to units. (default: 0) + ; - impassible_to_wheeled : 0 or 1. If 1, completed natural wonder tile is impassible to wheeled units unless connected by road. (default: 0) +] + +#Wonder +name = Angel Falls +terrain_type = grassland +adjacent_to = river +adjacency_dir = southeast +img_path = NaturalWonders.pcx +img_row = 0 +img_column = 0 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Yosemite +terrain_type = grassland +adjacent_to = forest +img_path = NaturalWonders.pcx +img_row = 0 +img_column = 1 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Mount Fuji +terrain_type = grassland +img_path = NaturalWonders.pcx +img_row = 0 +img_column = 2 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Yellowstone +terrain_type = grassland +adjacent_to = forest +img_path = NaturalWonders.pcx +img_row = 0 +img_column = 3 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Mount Everest +terrain_type = grassland +adjacent_to = snow-mountains +img_path = NaturalWonders.pcx +img_row = 1 +img_column = 0 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Zhangjiajie Mountains +terrain_type = jungle +adjacent_to = jungle +img_path = NaturalWonders.pcx +img_row = 1 +img_column = 1 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Mount Kilimanjaro +terrain_type = grassland +img_path = NaturalWonders.pcx +img_row = 1 +img_column = 2 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Great Barrier Reef +terrain_type = sea +adjacent_to = coast +img_path = NaturalWonders.pcx +img_row = 1 +img_column = 3 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Matterhorn +terrain_type = grassland +adjacent_to = snow-mountains +img_path = NaturalWonders.pcx +img_row = 2 +img_column = 0 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Moraine Lake +terrain_type = grassland +adjacent_to = mountains +img_path = NaturalWonders.pcx +img_row = 2 +img_column = 1 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Tropical Rainforest +terrain_type = jungle +adjacent_to = jungle +img_path = NaturalWonders.pcx +img_row = 2 +img_column = 2 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Wadi Rum +terrain_type = desert +adjacent_to = desert +img_path = NaturalWonders.pcx +img_row = 2 +img_column = 3 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Eyjafjallajokull +terrain_type = tundra +adjacent_to = tundra +img_path = NaturalWonders.pcx +img_row = 3 +img_column = 0 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Ha Long Bay +terrain_type = coast +adjacent_to = sea +img_path = NaturalWonders.pcx +img_row = 3 +img_column = 1 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Lofoten Skerries +terrain_type = coast +adjacent_to = tundra +img_path = NaturalWonders.pcx +img_row = 3 +img_column = 2 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Geirangerfjord +terrain_type = tundra +adjacent_to = coast +adjacency_dir = south +img_path = NaturalWonders.pcx +img_row = 3 +img_column = 3 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Delicate Arch +terrain_type = desert +adjacent_to = desert +img_path = NaturalWonders.pcx +img_row = 4 +img_column = 0 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Savanna +terrain_type = plains +adjacent_to = plains +img_path = NaturalWonders.pcx +img_row = 4 +img_column = 1 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 happiness_bonus = 1 \ No newline at end of file diff --git a/default.districts_wonders_config.txt b/default.districts_wonders_config.txt index 36478d22..48d5bca1 100644 --- a/default.districts_wonders_config.txt +++ b/default.districts_wonders_config.txt @@ -1,233 +1,233 @@ -[======================================================================= NOTE =======================================================================] -[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] -[be named scenario.districts_wonders_config.txt and must be located in your scenario search folder. Of course it only applies if you are using a ] -[scenario. The user config file must be named user.districts_wonders_config.txt and located in the C3X folder, which is the folder where this file ] -[is. When creating scenario or user configs, note that all wonders defined here will be removed and only your scenario or user-defined districts will] -[be used. ] -[====================================================================================================================================================] - -[ - ; Wonder config fields (each Wonder block begins with "#Wonder") - ; - name : Text (required). Must match the in-game Wonder improvement name. - ; - buildable_on : Comma-separated tile types: desert, plains, grassland, tundra, floodplain, hills, mountains, volcano, - coast, sea, ocean, snow-forest, snow-mountains, snow-volcano, lake. - ; - buildable_on_rivers : 0 or 1. If 1, Wonder can only be built if tile has river. - ; - buildable_adjacent_to : Same as buildable_on, plus "city". - ; - buildable_adjacent_to_overlays : Same overlay list as districts. - ; - buildable_by_civs : Comma-separated civ names (e.g., Romans, Egyptians). - ; - buildable_by_civ_traits : Comma-separated trait names (e.g., Commercial, Militaristic). - ; - buildable_by_civ_govs : Comma-separated government names (e.g., Republic, Monarchy). - ; - buildable_by_civ_cultures : Comma-separated culture names (e.g., EURO, ASIAN). - ; - img_path : Text. PCX filename (under Art/Districts/1200/). Defaults to Wonders.pcx if omitted. - ; - img_construct_row : Number (required). Row index in the PCX for the "under construction" wonder art (0-based). - ; - img_construct_column : Number (required). Column index in the PCX for the "under construction" wonder art (0-based). - ; - img_row : Number (required). Row index in the PCX for the completed wonder art (0-based). - ; - img_column : Number (required). Column index in the PCX for the completed wonder art (0-based). - ; - enable_img_alt_dir : 0 or 1. If 1, use alternate art when river/city direction implies a flip (see img_alt_dir_* fields). - ; - img_alt_dir_construct_row : Number. Row index for alternate "under construction" art (0-based). - ; - img_alt_dir_construct_column : Number. Column index for alternate "under construction" art (0-based). - ; - img_alt_dir_row : Number. Row index for alternate completed art (0-based). - ; - img_alt_dir_column : Number. Column index for alternate completed art (0-based). - ; - custom_width : Number (pixels). Override wonder sprite width. (default: 128) - ; - custom_height : Number (pixels). Override wonder sprite height. (default: 64) -] - -#Wonder -name = The Pyramids -buildable_on = desert -img_path = Wonders.pcx -img_construct_row = 0 -img_construct_column = 0 -img_row = 0 -img_column = 1 - -#Wonder -name = The Hanging Gardens -img_path = Wonders.pcx -img_construct_row = 0 -img_construct_column = 2 -img_row = 0 -img_column = 3 - -#Wonder -name = The Oracle -buildable_on = hills -img_path = Wonders.pcx -img_construct_row = 1 -img_construct_column = 0 -img_row = 1 -img_column = 1 - -#Wonder -name = The Temple of Artemis -img_path = Wonders.pcx -img_construct_row = 1 -img_construct_column = 2 -img_row = 1 -img_column = 3 - -#Wonder -name = The Mausoleum of Mausollos -img_path = Wonders.pcx -img_construct_row = 2 -img_construct_column = 0 -img_row = 2 -img_column = 1 - -#Wonder -name = The Statue of Zeus -img_path = Wonders.pcx -img_construct_row = 2 -img_construct_column = 2 -img_row = 2 -img_column = 3 - -#Wonder -name = The Great Library -img_path = Wonders.pcx -img_construct_row = 3 -img_construct_column = 0 -img_row = 3 -img_column = 1 - -#Wonder -name = Copernicus' Observatory -img_path = Wonders.pcx -img_construct_row = 3 -img_construct_column = 2 -img_row = 3 -img_column = 3 - -#Wonder -name = JS Bach's Cathedral -img_path = Wonders_2.pcx -img_construct_row = 0 -img_construct_column = 0 -img_row = 0 -img_column = 1 - -#Wonder -name = Newton's University -img_path = Wonders_2.pcx -img_construct_row = 0 -img_construct_column = 2 -img_row = 0 -img_column = 3 - -#Wonder -name = SETI program -img_path = Wonders_2.pcx -img_construct_row = 1 -img_construct_column = 0 -img_row = 1 -img_column = 1 - -#Wonder -name = Shakespeare's Theater -img_path = Wonders_2.pcx -img_construct_row = 1 -img_construct_column = 2 -img_row = 1 -img_column = 3 - -#Wonder -name = Sistine Chapel -img_path = Wonders_2.pcx -img_construct_row = 2 -img_construct_column = 0 -img_row = 2 -img_column = 1 - -#Wonder -name = The Great Lighthouse -buildable_on = coast -img_path = Wonders_2.pcx -img_construct_row = 2 -img_construct_column = 2 -img_row = 2 -img_column = 3 - -#Wonder -name = The Colossus -buildable_on = coast -enable_img_alt_dir = 1 -img_path = Wonders_2.pcx -img_construct_row = 3 -img_construct_column = 0 -img_row = 3 -img_column = 1 -img_alt_dir_construct_row = 3 -img_alt_dir_construct_column = 2 -img_alt_dir_row = 3 -img_alt_dir_column = 3 - -#Wonder -name = Hoover Dam -buildable_on = mountains -buildable_on_rivers = 1 -enable_img_alt_dir = 1 -img_path = Wonders_3.pcx -img_construct_row = 0 -img_construct_column = 0 -img_row = 0 -img_column = 1 -img_alt_dir_construct_row = 0 -img_alt_dir_construct_column = 2 -img_alt_dir_row = 0 -img_alt_dir_column = 3 - -#Wonder -name = Apollo Program -img_path = SmallWonders.pcx -img_construct_row = 0 -img_construct_column = 0 -img_row = 0 -img_column = 1 - -#Wonder -name = Forbidden Palace -img_path = SmallWonders.pcx -img_construct_row = 0 -img_construct_column = 2 -img_row = 0 -img_column = 3 - -#Wonder -name = Intelligence Agency -img_path = SmallWonders.pcx -img_construct_row = 1 -img_construct_column = 0 -img_row = 1 -img_column = 1 - -#Wonder -name = The Pentagon -img_path = SmallWonders.pcx -img_construct_row = 1 -img_construct_column = 2 -img_row = 1 -img_column = 3 - -#Wonder -name = Military Academy -img_path = SmallWonders.pcx -img_construct_row = 2 -img_construct_column = 0 -img_row = 2 -img_column = 1 - -#Wonder -name = Iron Works -img_path = SmallWonders.pcx -img_construct_row = 2 -img_construct_column = 2 -img_row = 2 -img_column = 3 - -#Wonder -name = Wall Street -img_path = SmallWonders.pcx -img_construct_row = 3 -img_construct_column = 0 -img_row = 3 -img_column = 1 +[======================================================================= NOTE =======================================================================] +[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] +[be named scenario.districts_wonders_config.txt and must be located in your scenario search folder. Of course it only applies if you are using a ] +[scenario. The user config file must be named user.districts_wonders_config.txt and located in the C3X folder, which is the folder where this file ] +[is. When creating scenario or user configs, note that all wonders defined here will be removed and only your scenario or user-defined districts will] +[be used. ] +[====================================================================================================================================================] + +[ + ; Wonder config fields (each Wonder block begins with "#Wonder") + ; - name : Text (required). Must match the in-game Wonder improvement name. + ; - buildable_on : Comma-separated tile types: desert, plains, grassland, tundra, floodplain, hills, mountains, volcano, + coast, sea, ocean, snow-forest, snow-mountains, snow-volcano, lake. + ; - buildable_on_rivers : 0 or 1. If 1, Wonder can only be built if tile has river. + ; - buildable_adjacent_to : Same as buildable_on, plus "city". + ; - buildable_adjacent_to_overlays : Same overlay list as districts. + ; - buildable_by_civs : Comma-separated civ names (e.g., Romans, Egyptians). + ; - buildable_by_civ_traits : Comma-separated trait names (e.g., Commercial, Militaristic). + ; - buildable_by_civ_govs : Comma-separated government names (e.g., Republic, Monarchy). + ; - buildable_by_civ_cultures : Comma-separated culture names (e.g., EURO, ASIAN). + ; - img_path : Text. PCX filename (under Art/Districts/1200/). Defaults to Wonders.pcx if omitted. + ; - img_construct_row : Number (required). Row index in the PCX for the "under construction" wonder art (0-based). + ; - img_construct_column : Number (required). Column index in the PCX for the "under construction" wonder art (0-based). + ; - img_row : Number (required). Row index in the PCX for the completed wonder art (0-based). + ; - img_column : Number (required). Column index in the PCX for the completed wonder art (0-based). + ; - enable_img_alt_dir : 0 or 1. If 1, use alternate art when river/city direction implies a flip (see img_alt_dir_* fields). + ; - img_alt_dir_construct_row : Number. Row index for alternate "under construction" art (0-based). + ; - img_alt_dir_construct_column : Number. Column index for alternate "under construction" art (0-based). + ; - img_alt_dir_row : Number. Row index for alternate completed art (0-based). + ; - img_alt_dir_column : Number. Column index for alternate completed art (0-based). + ; - custom_width : Number (pixels). Override wonder sprite width. (default: 128) + ; - custom_height : Number (pixels). Override wonder sprite height. (default: 64) +] + +#Wonder +name = The Pyramids +buildable_on = desert +img_path = Wonders.pcx +img_construct_row = 0 +img_construct_column = 0 +img_row = 0 +img_column = 1 + +#Wonder +name = The Hanging Gardens +img_path = Wonders.pcx +img_construct_row = 0 +img_construct_column = 2 +img_row = 0 +img_column = 3 + +#Wonder +name = The Oracle +buildable_on = hills +img_path = Wonders.pcx +img_construct_row = 1 +img_construct_column = 0 +img_row = 1 +img_column = 1 + +#Wonder +name = The Temple of Artemis +img_path = Wonders.pcx +img_construct_row = 1 +img_construct_column = 2 +img_row = 1 +img_column = 3 + +#Wonder +name = The Mausoleum of Mausollos +img_path = Wonders.pcx +img_construct_row = 2 +img_construct_column = 0 +img_row = 2 +img_column = 1 + +#Wonder +name = The Statue of Zeus +img_path = Wonders.pcx +img_construct_row = 2 +img_construct_column = 2 +img_row = 2 +img_column = 3 + +#Wonder +name = The Great Library +img_path = Wonders.pcx +img_construct_row = 3 +img_construct_column = 0 +img_row = 3 +img_column = 1 + +#Wonder +name = Copernicus' Observatory +img_path = Wonders.pcx +img_construct_row = 3 +img_construct_column = 2 +img_row = 3 +img_column = 3 + +#Wonder +name = JS Bach's Cathedral +img_path = Wonders_2.pcx +img_construct_row = 0 +img_construct_column = 0 +img_row = 0 +img_column = 1 + +#Wonder +name = Newton's University +img_path = Wonders_2.pcx +img_construct_row = 0 +img_construct_column = 2 +img_row = 0 +img_column = 3 + +#Wonder +name = SETI program +img_path = Wonders_2.pcx +img_construct_row = 1 +img_construct_column = 0 +img_row = 1 +img_column = 1 + +#Wonder +name = Shakespeare's Theater +img_path = Wonders_2.pcx +img_construct_row = 1 +img_construct_column = 2 +img_row = 1 +img_column = 3 + +#Wonder +name = Sistine Chapel +img_path = Wonders_2.pcx +img_construct_row = 2 +img_construct_column = 0 +img_row = 2 +img_column = 1 + +#Wonder +name = The Great Lighthouse +buildable_on = coast +img_path = Wonders_2.pcx +img_construct_row = 2 +img_construct_column = 2 +img_row = 2 +img_column = 3 + +#Wonder +name = The Colossus +buildable_on = coast +enable_img_alt_dir = 1 +img_path = Wonders_2.pcx +img_construct_row = 3 +img_construct_column = 0 +img_row = 3 +img_column = 1 +img_alt_dir_construct_row = 3 +img_alt_dir_construct_column = 2 +img_alt_dir_row = 3 +img_alt_dir_column = 3 + +#Wonder +name = Hoover Dam +buildable_on = mountains +buildable_on_rivers = 1 +enable_img_alt_dir = 1 +img_path = Wonders_3.pcx +img_construct_row = 0 +img_construct_column = 0 +img_row = 0 +img_column = 1 +img_alt_dir_construct_row = 0 +img_alt_dir_construct_column = 2 +img_alt_dir_row = 0 +img_alt_dir_column = 3 + +#Wonder +name = Apollo Program +img_path = SmallWonders.pcx +img_construct_row = 0 +img_construct_column = 0 +img_row = 0 +img_column = 1 + +#Wonder +name = Forbidden Palace +img_path = SmallWonders.pcx +img_construct_row = 0 +img_construct_column = 2 +img_row = 0 +img_column = 3 + +#Wonder +name = Intelligence Agency +img_path = SmallWonders.pcx +img_construct_row = 1 +img_construct_column = 0 +img_row = 1 +img_column = 1 + +#Wonder +name = The Pentagon +img_path = SmallWonders.pcx +img_construct_row = 1 +img_construct_column = 2 +img_row = 1 +img_column = 3 + +#Wonder +name = Military Academy +img_path = SmallWonders.pcx +img_construct_row = 2 +img_construct_column = 0 +img_row = 2 +img_column = 1 + +#Wonder +name = Iron Works +img_path = SmallWonders.pcx +img_construct_row = 2 +img_construct_column = 2 +img_row = 2 +img_column = 3 + +#Wonder +name = Wall Street +img_path = SmallWonders.pcx +img_construct_row = 3 +img_construct_column = 0 +img_row = 3 +img_column = 1 diff --git a/injected_code.c b/injected_code.c index b83a38de..730d9d07 100644 --- a/injected_code.c +++ b/injected_code.c @@ -1,37115 +1,37113 @@ -#include "stdlib.h" -#include "stdio.h" - -#include "C3X.h" - -void (WINAPI ** p_OutputDebugStringA) (char * lpOutputString) = ADDR_ADDR_OUTPUTDEBUGSTRINGA; -short (WINAPI ** p_GetAsyncKeyState) (int vKey) = ADDR_ADDR_GETASYNCKEYSTATE; -FARPROC (WINAPI ** p_GetProcAddress) (HMODULE hModule, char const * lpProcName) = ADDR_ADDR_GETPROCADDRESS; -HMODULE (WINAPI ** p_GetModuleHandleA) (char const * lpModuleName) = ADDR_ADDR_GETMODULEHANDLEA; -int (WINAPI ** p_MessageBoxA) (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) = ADDR_ADDR_MESSAGEBOXA; - -struct injected_state * is = ADDR_INJECTED_STATE; - -// To be used as placeholder second argument so that we can imitate thiscall convention with fastcall -#define __ 0 - -// Many Windows and C standard library functions have to be loaded dynamically with GetProcAddress and the addresses are stored in the injected -// state. This is covered up with macros, which is not something I would normally do, but in this case it's very useful because it means the code in -// common.c can be shared by the patcher and the injected code. -#define VirtualProtect is->VirtualProtect -#define CloseHandle is->CloseHandle -#define CreateFileA is->CreateFileA -#define GetFileSize is->GetFileSize -#define ReadFile is->ReadFile -#define LoadLibraryA is->LoadLibraryA -#define FreeLibrary is->FreeLibrary -#define MessageBoxA is->MessageBoxA -#define MultiByteToWideChar is->MultiByteToWideChar -#define WideCharToMultiByte is->WideCharToMultiByte -#define GetLastError is->GetLastError -#define QueryPerformanceCounter is->QueryPerformanceCounter -#define QueryPerformanceFrequency is->QueryPerformanceFrequency -#define GetLocalTime is->GetLocalTime -#define TransparentBlt is->TransparentBlt -#define snprintf is->snprintf -#define malloc is->malloc -#define calloc is->calloc -#define realloc is->realloc -#define free is->free -#define strtol is->strtol -#define strtof is->strtof -#define strncmp is->strncmp -#define strcmp is->strcmp -#define _stricmp is->_stricmp -#define strlen is->strlen -#define strncpy is->strncpy -#define strcpy is->strcpy -#define strdup is->strdup -#define strstr is->strstr -#define qsort is->qsort -#define memcmp is->memcmp -#define memcpy is->memcpy -#define tolower is->tolower -#define toupper is->toupper - -#include "common.c" - -#define TRADE_SCROLL_BUTTON_ID_LEFT 0x222001 -#define TRADE_SCROLL_BUTTON_ID_RIGHT 0x222002 - -// Must match size of button images in descbox.pcx -#define MOD_INFO_BUTTON_WIDTH 102 -#define MOD_INFO_BUTTON_HEIGHT 17 - -#define MOD_INFO_BUTTON_ID 0x222003 - -#define PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID 0x222004 -#define PEDIA_MULTIPAGE_PREV_BUTTON_ID 0x222005 - -#define TILE_FLAG_ROAD 0x1 -#define TILE_FLAG_RAILROAD 0x2 -#define TILE_FLAG_MINE 0x4 -#define TILE_FLAG_IRRIGATION 0x8 - -#define NEIGHBORHOOD_DISTRICT_ID 0 -#define WONDER_DISTRICT_ID 1 -#define DISTRIBUTION_HUB_DISTRICT_ID 2 -#define AERODROME_DISTRICT_ID 3 -#define NATURAL_WONDER_DISTRICT_ID 4 -#define PORT_DISTRICT_ID 5 -#define CENTRAL_RAIL_HUB_DISTRICT_ID 6 -#define ENERGY_GRID_DISTRICT_ID 7 -#define BRIDGE_DISTRICT_ID 8 -#define CANAL_DISTRICT_ID 9 -#define GREAT_WALL_DISTRICT_ID 10 - -#define MAX_DISTRICT_VARIANT_COUNT 5 -#define MAX_DISTRICT_ERA_COUNT 4 -#define MAX_DISTRICT_COLUMN_COUNT 10 - -// Max grid of tiles that an AI will evaluate a candidate bridge or canal for, -// used to limit computational complexity -#define AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES 10 - -enum { NAMED_TILE_MENU_ID = 0x90 }; - -char const * const hotseat_replay_save_path = "Saves\\Auto\\ai-move-replay-before-interturn.SAV"; -char const * const hotseat_resume_save_path = "Saves\\Auto\\ai-move-replay-resume.SAV"; - -// Need to define memmove for use by TCC when generated code for functions that return a struct -void * -memmove (void * dest, void const * src, size_t size) -{ - return is->memmove (dest, src, size); -} - -// Also need to define memset for some reason -void * -memset (void * dest, int ch, size_t count) -{ - for (size_t n = 0; n < count; n++) - ((char *)dest)[n] = ch; - return dest; -} - -// Computes num/denom randomly rounded off so that E[rand_div (x,y)] = (float)x/y -// As an example: E[rand_div (6, 5)] = 1.2, it will return 1 with 80% probability and 2 with 20% prob. -int -rand_div (int num, int denom) -{ - int q = num / denom, - r = num % denom; - return q + (rand_int (p_rand_object, __, denom) < r); -} - -bool -are_tiles_adjacent (int ax, int ay, int bx, int by) -{ - int x_dist = int_abs (ax - bx), - y_dist = int_abs (ay - by); - - // Handle edge wrapping by counting from the opposite direction if it would be shorter - if (p_bic_data->Map.Flags & 1) { // if map wraps horizontally - int width = p_bic_data->Map.Width; - if (x_dist > (width>>1)) - x_dist = width - x_dist; - } - if (p_bic_data->Map.Flags & 2) { // if map wraps vertically - int height = p_bic_data->Map.Height; - if (y_dist > (height>>1)) - y_dist = height - y_dist; - } - - return (x_dist + y_dist) == 2; -} - -int -compute_wrapped_component (int diff, int size, bool wraps) -{ - if (! wraps || (size <= 0)) - return diff; - - int half = size >> 1; - if (diff > half) - diff = size - diff; - return diff; -} - -void -compute_wrapped_deltas (int ax, int ay, int bx, int by, int * out_dx, int * out_dy) -{ - int dx = int_abs (ax - bx); - int dy = int_abs (ay - by); - bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; - bool wraps_vert = (p_bic_data->Map.Flags & 2) != 0; - dx = compute_wrapped_component (dx, p_bic_data->Map.Width, wraps_horiz); - dy = compute_wrapped_component (dy, p_bic_data->Map.Height, wraps_vert); - if (out_dx != NULL) - *out_dx = dx; - if (out_dy != NULL) - *out_dy = dy; -} - -int -compute_wrapped_manhattan_distance (int ax, int ay, int bx, int by) -{ - int dx, dy; - compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); - return dx + dy; -} - -int -compute_wrapped_chebyshev_distance (int ax, int ay, int bx, int by) -{ - int dx, dy; - compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); - return (dx > dy) ? dx : dy; -} - -bool -tile_has_resource (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - int resource_type = tile->vtable->m39_Get_Resource_Type (tile); - return (resource_type >= 0) && (resource_type < p_bic_data->ResourceTypeCount); -} - -City * -get_city_ptr (int id) -{ - if ((p_cities->Cities != NULL) && - (id >= 0) && (id <= p_cities->LastIndex)) { - City_Body * body = p_cities->Cities[id].City; - if (body != NULL) { - City * city = (City *)((char *)body - offsetof (City, Body)); - if (city != NULL) - return city; - } - } - return NULL; -} - -// Forward declarations for unit counter system (defined after their dependencies) -enum recognizable_parse_result parse_unit_counter_group (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_group); -enum recognizable_parse_result parse_counter_rule (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_rule); - -// Declare various functions needed for districts and hard to untangle and reorder here -void __fastcall patch_City_recompute_yields_and_happiness (City * this); -void __fastcall patch_Map_build_trade_network (Map * this); -bool __fastcall patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value); -bool __fastcall patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y); -bool __fastcall patch_City_has_resource (City * this, int edx, int resource_id); -bool __fastcall patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2); -char __fastcall patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing); -void __fastcall patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7); -bool can_build_district_on_tile (Tile * tile, int district_id, int civ_id); -bool city_can_build_district (City * city, int district_id); -bool leader_can_build_district (Leader * leader, int district_id); -bool wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id); -bool find_civ_trait_id_by_name (struct string_slice const * name, int * out_id); -bool find_civ_culture_id_by_name (struct string_slice const * name, int * out_id); -Tile * find_tile_for_district (City * city, int district_id, int * out_x, int * out_y); -struct district_instance * get_district_instance (Tile * tile); -struct named_tile_entry * get_named_tile_entry (Tile * tile); -bool city_has_required_district (City * city, int district_id); -bool district_is_complete (Tile * tile, int district_id); -bool city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id); -void clear_city_district_request (City * city, int district_id); -void set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y); -bool city_radius_contains_tile (City * city, int tile_x, int tile_y); -void on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y); -bool ai_move_district_worker (Unit * worker, struct district_worker_record * rec); -bool has_active_building (City * city, int improv_id); -bool tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv); -void recompute_distribution_hub_totals (); -void get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y); -void wrap_tile_coords (Map * map, int * x, int * y); -int count_neighborhoods_in_city_radius (City * city); -int count_utilized_neighborhoods_in_city_radius (City * city); -char * copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes); -bool city_has_resource_r (City * city, int resource_id, int max_generated_resource_id); - -struct pause_for_popup { - bool done; // Set to true to exit for loop - bool redundant; // If true, this pause would overlap a previous one and so should not be counted - long long ts_before; -}; - -struct pause_for_popup -pfp_init () -{ - struct pause_for_popup tr; - tr.done = false; - tr.redundant = is->paused_for_popup; - if (! tr.redundant) { - is->paused_for_popup = true; - QueryPerformanceCounter ((LARGE_INTEGER *)&tr.ts_before); - } - return tr; -} - -void -pfp_finish (struct pause_for_popup * pfp) -{ - if ((! pfp->redundant) && (! pfp->done)) { - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - is->time_spent_paused_during_popup += ts_after - pfp->ts_before; - is->paused_for_popup = false; - } - pfp->done = true; -} - -#define WITH_PAUSE_FOR_POPUP for (struct pause_for_popup pfp = pfp_init (); ! pfp.done; pfp_finish (&pfp)) - -int __fastcall -patch_show_popup (void * this, int edx, int param_1, int param_2) -{ - int tr; - WITH_PAUSE_FOR_POPUP { - is->show_popup_was_called = 1; - tr = show_popup (this, __, param_1, param_2); - } - return tr; -} - -void -pop_up_in_game_error (char const * msg) -{ - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); - PopupForm_add_text (popup, __, (char *)msg, false); - patch_show_popup (popup, __, 0, 0); -} - -void -memoize (int val) -{ - if (is->memo_len < is->memo_capacity) - is->memo[is->memo_len++] = val; - else { - int new_capacity = not_below (100, 2 * is->memo_capacity); - int * new_memo = malloc (new_capacity * sizeof is->memo[0]); - if (new_memo != NULL) { - for (int n = 0; n < is->memo_len; n++) - new_memo[n] = is->memo[n]; - free (is->memo); - is->memo = new_memo; - is->memo_capacity = new_capacity; - is->memo[is->memo_len++] = val; - } - } - -} - -void -clear_memo () -{ - is->memo_len = 0; -} - -// The maximum possible cultural neighbor index. We don't bother dealing with indices beyond this b/c it's the last tile in the seventh ring. Also -// equals one less than the tile count up to & inc. the seventh ring b/c of the zeroth tile. -#define MAX_CULTURAL_NI 192 - -// Number of workable tiles including the city center for each workable radius -unsigned char const workable_tile_counts[8] = {1, 9, 21, 37, 61, 89, 137, 193}; - -char const cultural_ni_to_diffs[(MAX_CULTURAL_NI + 1) * 2] = -{ - 0, 0, - -// first ring - 1, -1, 2, 0, 1, 1, 0, 2, -1, 1, -2, 0, -1, -1, - 0, -2, - -// second ring - 1, -3, 2, -2, 3, -1, 3, 1, 2, 2, 1, 3, -1, 3, -2, 2, - -3, 1, -3, -1, -2, -2, -1, -3, - -// third ring - 0, -4, 4, 0, 0, 4, -4, 0, 2, -4, 3, -3, 4, -2, 4, 2, - 3, 3, 2, 4, -2, 4, -3, 3, -4, 2, -4, -2, -3, -3, -2, -4, - -// fourth ring - 1, -5, 5, -1, 5, 1, 1, 5, -1, 5, -5, 1, -5, -1, -1, -5, - 0, -6, 6, 0, 0, 6, -6, 0, 3, -5, 4, -4, 5, -3, 5, 3, - 4, 4, 3, 5, -3, 5, -4, 4, -5, 3, -5, -3, -4, -4, -3, -5, - -// fifth ring - 1, -7, 2, -6, 6, -2, 7, -1, 7, 1, 6, 2, 2, 6, 1, 7, - -1, 7, -2, 6, -6, 2, -7, 1, -7, -1, -6, -2, -2, -6, -1, -7, - 4, -6, 5, -5, 6, -4, 6, 4, 5, 5, 4, 6, -4, 6, -5, 5, - -6, 4, -6, -4, -5, -5, -4, -6, - -// sixth ring - 0, -8, 8, 0, 0, 8, -8, 0, 1, -9, 2, -8, 3, -7, 7, -3, - 8, -2, 9, -1, 9, 1, 8, 2, 7, 3, 3, 7, 2, 8, 1, 9, - -1, 9, -2, 8, -3, 7, -7, 3, -8, 2, -9, 1, -9, -1, -8, -2, - -7, -3, -3, -7, -2, -8, -1, -9, 4, -8, 5, -7, 6, -6, 7, -5, - 8, -4, 8, 4, 7, 5, 6, 6, 5, 7, 4, 8, -4, 8, -5, 7, - -6, 6, -7, 5, -8, 4, -8, -4, -7, -5, -6, -6, -5, -7, -4, -8, - -// seventh ring - 0, -10, 10, 0, 0, 10, -10, 0, 1, -11, 2, -10, 3, -9, 9, -3, - 10, -2, 11, -1, 11, 1, 10, 2, 9, 3, 3, 9, 2, 10, 1, 11, - -1, 11, -2, 10, -3, 9, -9, 3, -10, 2, -11, 1, -11, -1, -10, -2, - -9, -3, -3, -9, -2, -10, -1, -11, 4, -10, 5, -9, 6, -8, 7, -7, - 8, -6, 9, -5, 10, -4, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, - 5, 9, 4, 10, -4, 10, -5, 9, -6, 8, -7, 7, -8, 6, -9, 5, - -10, 4, -10, -4, -9, -5, -8, -6, -7, -7, -6, -8, -5, -9, -4, -10 -}; - -// Like neighbor_index_to_diff, but enumerates tiles in an order that matches cultural border expansion. Only valid for 0 <= neighbor_index <= MAX_CULTURAL_NI. -void __cdecl -patch_ni_to_diff_for_work_area (int neighbor_index, int * x_disp, int * y_disp) -{ - if (neighbor_index <= 0) { - *x_disp = *y_disp = 0; - return; - } else if (neighbor_index > MAX_CULTURAL_NI) - neighbor_index = neighbor_index % (MAX_CULTURAL_NI + 1); - - int i = neighbor_index << 1; - char const * p = &cultural_ni_to_diffs[neighbor_index << 1]; - *x_disp = p[0]; - *y_disp = p[1]; -} - -int __fastcall -patch_City_find_min_value_tile (City * this) -{ - int tr = City_find_min_value_tile (this); - - // The original function has been edited to enumerate tiles in our custom order matching cultural borders instead of the game's original - // order. It returns a neighbor index from that enumeration. We must convert it to standard order if it's beyond the range where the two - // enumerations overlap. - if (tr >= 21) - tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; - - return tr; -} - -int __fastcall -patch_City_find_best_tile_to_work (City * this, int edx, Unit * worker, bool param_2) -{ - int tr = City_find_best_tile_to_work (this, __, worker, param_2); - if (tr >= 21) - tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; - return tr; -} - -bool __fastcall -City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 21) && (neighbor_index <= MAX_CULTURAL_NI)) - neighbor_index = is->cultural_ni_to_standard[neighbor_index]; - return City_stop_working_tile (this, __, neighbor_index); -} - -int __fastcall -patch_Map_compute_ni_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - // Within the first two rings, there's no difference b/w the standard and custom "work area" neighbor indices so fall back to the base game's - // function in that case. - if (is->workable_tile_count <= 21) - return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); - - // If the work area has been expanded, compute the neighbor index then check that it's within the area. Ignore the limit we were passed and - // instead use the number of tiles in the workable area, doubled to cover the difference between cultural vs standard enumeration. - else { - int ni = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, 2 * is->workable_tile_count); - if ((ni >= 0) && (ni <= ARRAY_LEN (is->ni_to_work_radius)) && - (is->ni_to_work_radius[ni] >= 0) && - (is->ni_to_work_radius[ni] <= is->current_config.city_work_radius)) - return ni; - else - return -1; - } -} - -int __fastcall -patch_Map_m28_find_cnter_neigh_point_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - int ret_addr = ((int *)&x_home)[-1]; - if (ret_addr != ADDR_FIND_CENTER_NP_SPOTLIGHT_RET) - return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); - else - return patch_Map_compute_ni_for_work_area (this, __, x_home, y_home, x_neigh, y_neigh, 500); -} - -int -get_work_ring_limit_by_culture (City * city) -{ - if (is->current_config.work_area_limit == WAL_NONE) - return INT_MAX; - else { - int lower_lim = (is->current_config.work_area_limit == WAL_CULTURAL_MIN_2) ? 2 : 1; - return not_below (lower_lim, city->Body.cultural_level); - } -} - -int -get_work_ring_limit_by_improvements (City * city) -{ - if (is->current_config.count_work_area_improvements == 0) - return INT_MAX; - else { - int maxRadius = 0; - int bonusRadius = 0; - for (int n = 0; n < is->current_config.count_work_area_improvements; n++) { - struct work_area_improvement * work_area_improvement = &is->current_config.work_area_improvements[n]; - if (work_area_improvement->work_area_radius_limit > maxRadius && - (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { - maxRadius = work_area_improvement->work_area_radius_limit; - } - if (work_area_improvement->work_area_radius_bonus > 0 && - (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { - bonusRadius += work_area_improvement->work_area_radius_bonus; - } - } - return maxRadius + bonusRadius; - } -} - -int -get_work_ring_limit_total (City * city) -{ - int cultureLimit = get_work_ring_limit_by_culture(city); - int improvementLimit = get_work_ring_limit_by_improvements(city); - if (cultureLimit < improvementLimit) - return cultureLimit; - return improvementLimit; -} - -bool __fastcall -patch_City_controls_tile (City * this, int edx, int neighbor_index, bool consider_enemy_units) -{ - // Check that this tile is not outside the city's work area. We've deleted a check from the base game code that verifies the n.i. is within 21 - // tiles so we can replicate it here in a way that also works for an expanded work area. - int work_radius = ((neighbor_index >= 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) ? is->ni_to_work_radius[neighbor_index] : -1; - if ((work_radius > is->current_config.city_work_radius) || (work_radius < 0)) - return false; - - int work_ring_limit = get_work_ring_limit_total (this); - if (work_radius > work_ring_limit) { - - // May consider this tile within the limit if any adjacent tiles are within the limit & within borders - bool exempt_from_limit; - if (is->current_config.work_area_limit != WAL_CULTURAL_OR_ADJACENT) - exempt_from_limit = false; - else if (neighbor_index >= 9) { - exempt_from_limit = false; - int center_x, center_y; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, ¢er_x, ¢er_y); - int neighbors_checked = 0; - for (int ni = 1; ni < ARRAY_LEN (is->ni_to_work_radius); ni++) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, ni, &nx, &ny); - if (are_tiles_adjacent (center_x, center_y, nx, ny)) { - neighbors_checked++; - int wr = is->ni_to_work_radius[ni]; - Tile * neighbor; - if (((wr >= 0) && (wr <= work_ring_limit)) && - (neighbor = tile_at (nx, ny)) && - (neighbor->vtable->m38_Get_Territory_OwnerID (neighbor) == this->Body.CivID)) { - exempt_from_limit = true; - break; - } - } - if (neighbors_checked == 8) - break; - } - } else - exempt_from_limit = true; - - if (! exempt_from_limit) - return false; - } - - if (neighbor_index >= 0) { - int tile_x, tile_y; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - // Check if the tile itself is a completed district (includes natural wonders) - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id)) - return false; - - // Check if the tile is covered by a distribution hub - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - return false; - } - } - } - } - - return City_controls_tile (this, __, neighbor_index, consider_enemy_units); -} - -bool __fastcall -patch_City_controls_tile_conv_ni (City * this, int edx, int neighbor_index, bool consider_enemy_units) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return patch_City_controls_tile (this, __, is->cultural_ni_to_standard[neighbor_index], consider_enemy_units); - else - return false; -} - -bool __fastcall -patch_City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return City_stop_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); - else - return false; -} - -bool __fastcall -patch_City_start_working_tile_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return City_start_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); - else - return false; -} - -void __fastcall -patch_City_add_or_remove_tile_yield_conv_ni (City * this, int edx, int neighbor_index, bool add_else_remove) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - City_add_or_remove_tile_yield (this, __, is->cultural_ni_to_standard[neighbor_index], add_else_remove); -} - -bool __fastcall -patch_City_is_neighboring_tile_in_area_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return City_is_neighboring_tile_in_area (this, __, is->cultural_ni_to_standard[neighbor_index]); - else - return false; -} - -int -get_city_screen_center_y (City * city) -{ - int y = city->Body.Y; - if (p_bic_data->is_zoomed_out) - return y + 7; // when zoomed out, shift map up to center city - else if (is->current_config.city_work_radius >= 3) - return y + 4; // when work radius is 3, shift map up one extra tile so as not to overlap citizen heads - else - return y + 2; // base game behavior -} - -void __fastcall -patch_Main_Screen_Form_bring_cnter_view_city_focus (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) -{ - // If the city we're viewing can work tiles in the 4+ ring then zoom out the map display to show them - int effective_radius = not_above (get_work_ring_limit_total (p_city_form->CurrentCity), is->current_config.city_work_radius); - if (is->current_config.work_area_limit == WAL_CULTURAL_OR_ADJACENT) - effective_radius = not_above (is->current_config.city_work_radius, effective_radius + 1); - if (effective_radius >= 4 && is->current_config.auto_zoom_city_screen_for_large_work_areas) - p_bic_data->is_zoomed_out = true; - - Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); -} - -void __fastcall -patch_Main_Screen_Form_bring_cnter_view_city_arrow (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) -{ - Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); -} - -void tile_index_to_coords (Map * map, int index, int * out_x, int * out_y); - -Tile * __fastcall -patch_Map_get_tile_for_work_area_drawing (Map * this, int edx, int index) -{ - Tile * tr = Map_get_tile (this, __, index); - - if (tr != p_null_tile) { - int x, y; - tile_index_to_coords (this, index, &x, &y); - City * viewing_city = p_city_form->CurrentCity; - int ni = Map_compute_neighbor_index (this, __, viewing_city->Body.X, viewing_city->Body.Y, x, y, 1000); - if ((ni > 0) && ! patch_City_controls_tile (viewing_city, __, ni, false)) - tr = p_null_tile; - } - - return tr; -} - -// Resets is->current_config to the base config and updates the list of config names. Does NOT re-apply machine code edits. -void -reset_to_base_config () -{ - struct c3x_config * cc = &is->current_config; - - for (int n = 0; n < ARRAY_LEN (cc->limit_units_per_tile); n++) - cc->limit_units_per_tile[n] = 0; - - table_deinit (&cc->exclude_types_from_units_per_tile_limit); - - for (int n = 0; n < COUNT_PERFUME_KINDS; n++) - stable_deinit (&cc->perfume_specs[n]); - - // Free building-unit prereqs table - FOR_TABLE_ENTRIES (tei, &cc->building_unit_prereqs) { - if ((tei.value & 1) == 0) - free ((void *)tei.value); - } - table_deinit (&cc->building_unit_prereqs); - - // Free list of mills - if (cc->mills != NULL) { - free (cc->mills); - cc->mills = NULL; - cc->count_mills = 0; - } - - // Free list of AI multi-city start extra palaces - if (cc->ai_multi_start_extra_palaces != NULL) { - free (cc->ai_multi_start_extra_palaces); - cc->ai_multi_start_extra_palaces = NULL; - cc->count_ai_multi_start_extra_palaces = 0; - cc->ai_multi_start_extra_palaces_capacity = 0; - } - - table_deinit (&cc->limit_defensive_retreat_on_water_to_types); - table_deinit (&cc->can_bombard_only_sea_tiles); - - // Free set of PTW artillery types and list of converted types - table_deinit (&cc->ptw_arty_types); - if (is->charmed_types_converted_to_ptw_arty != NULL) { - free (is->charmed_types_converted_to_ptw_arty); - is->charmed_types_converted_to_ptw_arty = NULL; - is->count_charmed_types_converted_to_ptw_arty = 0; - is->charmed_types_converted_to_ptw_arty_capacity = 0; - } - - // Free era alias lists - if (cc->civ_era_alias_lists != NULL) { - for (int n = 0; n < cc->count_civ_era_alias_lists; n++) { - struct civ_era_alias_list * list = &cc->civ_era_alias_lists[n]; - free (list->key); - for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) - free (list->aliases[k]); - } - free (cc->civ_era_alias_lists); - cc->civ_era_alias_lists = NULL; - cc->count_civ_era_alias_lists = 0; - } - if (cc->leader_era_alias_lists != NULL) { - for (int n = 0; n < cc->count_leader_era_alias_lists; n++) { - struct leader_era_alias_list * list = &cc->leader_era_alias_lists[n]; - free (list->key); - for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) { - free (list->aliases[k]); - free (list->titles[k]); - } - } - free (cc->leader_era_alias_lists); - cc->leader_era_alias_lists = NULL; - cc->count_leader_era_alias_lists = 0; - } - - // Free list of work_area_improvements - if (cc->work_area_improvements != NULL) { - free (cc->work_area_improvements); - cc->work_area_improvements = NULL; - cc->count_work_area_improvements = 0; - } - - // Free aircraft victory animation string - if (cc->aircraft_victory_animation != NULL) { - free (cc->aircraft_victory_animation); - cc->aircraft_victory_animation = NULL; - } - - if (cc->great_wall_auto_build_wonder_name != NULL) { - free (cc->great_wall_auto_build_wonder_name); - cc->great_wall_auto_build_wonder_name = NULL; - } - - if (cc->unit_counter_groups != NULL) { - for (int n = 0; n < cc->count_unit_counter_groups; n++) { - free (cc->unit_counter_groups[n].name); - free (cc->unit_counter_groups[n].type_ids); - } - free (cc->unit_counter_groups); - cc->unit_counter_groups = NULL; - cc->count_unit_counter_groups = 0; - } - - if (cc->counter_rules != NULL) { - for (int n = 0; n < cc->count_counter_rules; n++) { - free (cc->counter_rules[n].attacker_group); - free (cc->counter_rules[n].defender_group); - free (cc->counter_rules[n].district_name); - } - free (cc->counter_rules); - cc->counter_rules = NULL; - cc->count_counter_rules = 0; - } - - // Free unit limits table - FOR_TABLE_ENTRIES (tei, &cc->unit_limits) - free ((void *)tei.value); - stable_deinit (&cc->unit_limits); - - // Free the linked list of loaded config names and the string name contained in each one - if (is->loaded_config_names != NULL) { - struct loaded_config_name * next = is->loaded_config_names; - while (next != NULL) { - struct loaded_config_name * to_free = next; - next = next->next; - free (to_free->name); - free (to_free); - } - } - - // Overwrite the current config with the base config - memcpy (&is->current_config, &is->base_config, sizeof is->current_config); - - // These fields are heap-allocated and must not be inherited from base_config - // (base_config never owns valid pointers for them) - is->current_config.unit_counter_groups = NULL; - is->current_config.count_unit_counter_groups = 0; - is->current_config.counter_rules = NULL; - is->current_config.count_counter_rules = 0; - - // Recreate loaded config names list with just the base config - is->loaded_config_names = malloc (sizeof *is->loaded_config_names); - is->loaded_config_names->name = strdup ("(base)"); - is->loaded_config_names->next = NULL; - - // Update IS variable that's tied to a config value - is->workable_tile_count = workable_tile_counts[is->current_config.city_work_radius]; -} - -struct id_list { - int length; - int capacity; - int ids[0]; -}; - -struct id_list * -alloc_id_list (int capacity, struct id_list const * copy) -{ - struct id_list * tr = malloc ((sizeof *tr) + capacity * sizeof(tr->ids[0])); - tr->length = 0; - tr->capacity = capacity; - if (copy != NULL) { - int new_len = not_above (capacity, copy->length); - for (int n = 0; n < new_len; n++) - tr->ids[n] = copy->ids[n]; - tr->length = new_len; - } - return tr; -} - -// This is the largest ID that will be stored inline inside sidtables. The amount here must be smaller than any pointer we'd get from malloc since the -// sidtable code compares values against this amount to determine which are inlined values versus pointers. -#define SID_TABLE_MAX_INLINE_ID 10000 - -void -sidtable_deinit (struct table * t) -{ - FOR_TABLE_ENTRIES (tei, t) { - free ((void *)tei.key); - if (tei.value > SID_TABLE_MAX_INLINE_ID) - free ((void *)tei.value); - } - table_deinit (t); -} - -void -sidtable_append (struct table * t, struct string_slice const * key, int id) -{ - // Expand or allocate table as needed - if (t->len >= table_capacity (t) / 2) - table__expand (t, hash_str, compare_str_keys); - - size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); - int * entry = &((int *)TABLE__BASE (t))[2*index]; - if (table__is_occupied (t, index)) { // If key is already in the table - int prev_val = entry[1]; - if (prev_val <= SID_TABLE_MAX_INLINE_ID) { // If prev value is an id, convert it to a list - struct id_list * new_list = alloc_id_list (2, NULL); - new_list->ids[0] = prev_val; - new_list->ids[1] = id; - new_list->length = 2; - entry[1] = (int)new_list; - } else { // Else, prev value is a list so append the new ID to it - struct id_list * list = (void *)prev_val; - if (list->length >= list->capacity) { // Expand list if necessary - struct id_list * new_list = alloc_id_list (2 * list->capacity, list); - entry[1] = (int)new_list; - free (list); - list = new_list; - } - list->ids[list->length] = id; - list->length++; - } - } else { // Key is not in the table, add it for the first time - entry[0] = (int)extract_slice (key); - if (id <= SID_TABLE_MAX_INLINE_ID) // Write ID inline if possible - entry[1] = id; - else { // Otherwise create a list for this one ID - struct id_list * new_list = alloc_id_list (2, NULL); - new_list->ids[0] = id; - new_list->length = 1; - entry[1] = (int)new_list; - } - table__set_occupation (t, index, 1); - t->len++; - } -} - -bool -sidtable_get_by_index (struct table const * t, size_t index, int ** out_ids, int * out_count) -{ - size_t capacity = table_capacity (t); - if ((capacity > 0) && (index < capacity) && table__is_occupied (t, index)) { - int * entry = &((int *)TABLE__BASE (t))[2*index]; - int val = entry[1]; - if (val <= SID_TABLE_MAX_INLINE_ID) { // Value is an ID - *out_ids = &entry[1]; - *out_count = 1; - } else { - struct id_list * list = (void *)val; - *out_ids = &list->ids[0]; - *out_count = list->length; - } - return true; - } else - return false; -} - -bool -sidtable_look_up (struct table const * t, char const * key, int ** out_ids, int * out_count) -{ - if (t->len > 0) { - size_t index = table__place (t, compare_str_keys, (int)key, hash_str ((int)key)); - return sidtable_get_by_index (t, index, out_ids, out_count); - } else - return false; -} - -bool -sidtable_look_up_slice (struct table const * t, struct string_slice const * key, int ** out_ids, int * out_count) -{ - if (t->len > 0) { - size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); - return sidtable_get_by_index (t, index, out_ids, out_count); - } else - return false; -} - -struct error_line { - char text[200]; - struct error_line * next; -}; - -struct error_line * -add_error_line (struct error_line ** p_lines) -{ - struct error_line * tr = calloc (1, sizeof *tr); - - struct error_line ** p_prev = p_lines; - while (*p_prev != NULL) - p_prev = &(*p_prev)->next; - *p_prev = tr; - - return tr; -} - -void -add_unrecognized_line (struct error_line ** p_lines, struct string_slice const * name) -{ - struct error_line * line = add_error_line (p_lines); - char s[100]; - snprintf (line->text, sizeof line->text, "^ %.*s", name->len, name->str); - line->text[(sizeof line->text) - 1] = '\0'; -} - -void -free_error_lines (struct error_line * lines) -{ - while (lines != NULL) { - struct error_line * next = lines->next; - free (lines); - lines = next; - } -} - -bool -find_improv_id_by_name (struct string_slice const * name, int * out) -{ - Improvement * improv; - if (name->len <= sizeof improv->Name) - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { - *out = n; - return true; - } - return false; -} - -// start_id specifies where the search will start. It's useful for finding multiple type IDs with the same name, which commonly happens due to the -// game duplicating unit types. -bool -find_unit_type_id_by_name (struct string_slice const * name, int start_id, int * out) -{ - UnitType * unit_type; - if (name->len <= sizeof unit_type->Name) - for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) - if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { - *out = n; - return true; - } - return false; -} - -bool -find_resource_id_by_name (struct string_slice const * name, int * out) -{ - Resource_Type * res_type; - if (name->len <= sizeof res_type->Name) - for (int n = 0; n < p_bic_data->ResourceTypeCount; n++) - if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { - *out = n; - return true; - } - return false; -} - -bool -find_animation_type_by_name (struct string_slice const * name, bool lower_case, AnimationType * out) -{ - for (int n_anim = 0; n_anim < COUNT_ANIMATION_TYPES; n_anim++) - if (strlen (animation_names[n_anim]) == name->len) { - bool all_chars_match = true; - for (int k = 0; k < name->len; k++) { - int c = animation_names[n_anim][k]; - if (lower_case) - c = tolower (c); - if (c != name->str[k]) { - all_chars_match = false; - break; - } - } - if (all_chars_match) { - *out = n_anim; - return true; - } - } - return false; -} - -enum game_object_kind { - GOK_UNIT_TYPE = 0, - GOK_BUILDING, - GOK_RESOURCE, - GOK_TECHNOLOGY, - GOK_GOVERNMENT, - - COUNT_GAME_OBJECT_KINDS -}; - -bool -find_game_object_id_by_name (enum game_object_kind kind, struct string_slice const * name, int start_id, int * out) -{ - switch (kind) { - case GOK_UNIT_TYPE: { - UnitType * unit_type; - if (name->len <= sizeof unit_type->Name) - for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) - if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { - *out = n; - return true; - } - return false; - } - case GOK_BUILDING: { - Improvement * improv; - if (name->len <= sizeof improv->Name) - for (int n = start_id; n < p_bic_data->ImprovementsCount; n++) - if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { - *out = n; - return true; - } - return false; - } - case GOK_RESOURCE: { - Resource_Type * res_type; - if (name->len <= sizeof res_type->Name) - for (int n = start_id; n < p_bic_data->ResourceTypeCount; n++) - if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { - *out = n; - return true; - } - return false; - } - case GOK_TECHNOLOGY: { - Advance * adv; - if (name->len <= sizeof adv->Name) - for (int n = start_id; n < p_bic_data->AdvanceCount; n++) - if (slice_matches_str (name, p_bic_data->Advances[n].Name)) { - *out = n; - return true; - } - return false; - } - case GOK_GOVERNMENT: { - Government * govt; - if (name->len <= sizeof govt->Name) - for (int n = start_id; n < p_bic_data->GovernmentsCount; n++) - if (slice_matches_str (name, p_bic_data->Governments[n].Name.S)) { - *out = n; - return true; - } - return false; - } - default: - return false; - } -} - -// Converts a build name (like "Spearman" or "Granary") into a City_Order struct. Returns whether or not any improvement or unit type was found under -// the given name. -bool -find_city_order_by_name (struct string_slice const * name, City_Order * out) -{ - int id; - if (find_improv_id_by_name (name, &id)) { - out->OrderID = id; - out->OrderType = COT_Improvement; - return true; - } else if (find_unit_type_id_by_name (name, 0, &id)) { - out->OrderID = id; - out->OrderType = COT_Unit; - return true; - } else - return false; -} - -// Returns a list of AI strat duplicates of the unit type with the given id. This means a list of all other unit types that are identical to the given -// one except were separated out so each can have only one AI strategy. Returns the total number of duplicates, which may be greater than dup_ids_len. -int -list_unit_type_duplicates (int type_id, int * out_dup_ids, int dup_ids_len) -{ - // type_id may be a duplicate itself. Find the base type so we can start assembling the array from there. Otherwise we may miss some. - int alt_for_id = p_bic_data->UnitTypes[type_id].alternate_strategy_for_id; - int base_type_id = (alt_for_id >= 0) ? alt_for_id : type_id; - - int tr = 0, current = base_type_id; - while (1) { - if (current != type_id) { - if (tr < dup_ids_len) - out_dup_ids[tr] = current; - tr++; - } - int next; - if (itable_look_up (&is->unit_type_duplicates, current, &next)) - current = next; - else - break; - } - - return tr; -} - -// A "recognizable" is something that contains the name of a unit, building, etc. When parsing one, it's possible for it to be grammatically valid but -// contain a name that doesn't match anything in the scenario data. That's a special kind of error. In that case, we record the error to report in a -// popup and continue parsing. -enum recognizable_parse_result { - RPR_OK = 0, - RPR_UNRECOGNIZED, - RPR_PARSE_ERROR -}; - -struct perfume_spec { - char name[36]; // Must be large enough to fit the name of a unit type or improvement - i31b value; // Int component stores amount, bool stores whether it's a percentage or not -}; - -enum recognizable_parse_result -parse_perfume_spec (char ** p_cursor, enum perfume_kind kind, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - char * cur = *p_cursor; - struct string_slice name; - City_Order unused_city_order; - int unused_id; - i31b value; - if (parse_string (&cur, &name) && - skip_punctuation (&cur, ':') && - parse_i31b (&cur, &value)) { - *p_cursor = cur; - - if (((kind == PK_PRODUCTION) && find_city_order_by_name (&name, &unused_city_order)) || - ((kind == PK_TECHNOLOGY) && find_game_object_id_by_name (GOK_TECHNOLOGY, &name, 0, &unused_id)) || - ((kind == PK_GOVERNMENT) && find_game_object_id_by_name (GOK_GOVERNMENT, &name, 0, &unused_id))) { - struct perfume_spec * out = out_perfume_spec; - snprintf (out->name, sizeof out->name, "%.*s", name.len, name.str); - out->name[(sizeof out->name) - 1] = '\0'; - out->value = value; - return RPR_OK; - } else { - add_unrecognized_line (p_unrecognized_lines, &name); - return RPR_UNRECOGNIZED; - } - } else - return RPR_PARSE_ERROR; -} - -enum recognizable_parse_result -parse_production_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - return parse_perfume_spec (p_cursor, PK_PRODUCTION, p_unrecognized_lines, out_perfume_spec); -} - -enum recognizable_parse_result -parse_technology_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - return parse_perfume_spec (p_cursor, PK_TECHNOLOGY, p_unrecognized_lines, out_perfume_spec); -} - -enum recognizable_parse_result -parse_government_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - return parse_perfume_spec (p_cursor, PK_GOVERNMENT, p_unrecognized_lines, out_perfume_spec); -} - -enum recognizable_parse_result -parse_mill (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_mill) -{ - char * cur = *p_cursor; - struct string_slice improv_name; - if (parse_string (&cur, &improv_name) && - skip_punctuation (&cur, ':')) { - - short flags = 0; - struct string_slice resource_name; - while (1) { - if (! parse_string (&cur, &resource_name)) - return RPR_PARSE_ERROR; - else if (slice_matches_str (&resource_name, "local")) flags |= MF_LOCAL; - else if (slice_matches_str (&resource_name, "no-tech-req")) flags |= MF_NO_TECH_REQ; - else if (slice_matches_str (&resource_name, "yields")) flags |= MF_YIELDS; - else if (slice_matches_str (&resource_name, "show-bonus")) flags |= MF_SHOW_BONUS; - else if (slice_matches_str (&resource_name, "hide-non-bonus")) flags |= MF_HIDE_NON_BONUS; - else - break; - } - - *p_cursor = cur; - int improv_id, resource_id; - int any_unrecognized = 0; - if (! find_improv_id_by_name (&improv_name, &improv_id)) { - add_unrecognized_line (p_unrecognized_lines, &improv_name); - any_unrecognized = 1; - } - if (! find_resource_id_by_name (&resource_name, &resource_id)) { - add_unrecognized_line (p_unrecognized_lines, &resource_name); - any_unrecognized = 1; - } - if (any_unrecognized) - return RPR_UNRECOGNIZED; - else { - struct mill * out = out_mill; - out->improv_id = improv_id; - out->resource_id = resource_id; - out->flags = flags; - return RPR_OK; - } - } else - return RPR_PARSE_ERROR; -} - -enum recognizable_parse_result -parse_era_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_or_civ_alias_list, bool leader_else_civ_name) -{ - char * cur = *p_cursor; - struct string_slice key; - if (parse_string (&cur, &key) && - skip_punctuation (&cur, ':')) { - - char * aliases[ERA_ALIAS_LIST_CAPACITY] = {0}; - char * titles[ERA_ALIAS_LIST_CAPACITY] = {0}; - int alias_count = 0, - female_bits = 0, - gender_specified_bits = 0; // For each alias, set to 1 if a gender was specified - struct string_slice alias; - while (1) { - if (parse_string (&cur, &alias)) { - if (alias_count < ERA_ALIAS_LIST_CAPACITY) - aliases[alias_count] = extract_slice (&alias); - - // If we're parsing a list of leader names, read in the gender & title if present - if (leader_else_civ_name) { - char * inner_cur = cur; - struct string_slice gender; - struct string_slice title = {0}; - if ( skip_punctuation (&inner_cur, '(') - && parse_string (&inner_cur, &gender) - && ( skip_punctuation (&inner_cur, ')') - || ( skip_punctuation (&inner_cur, ',') - && parse_string (&inner_cur, &title) - && skip_punctuation (&inner_cur, ')'))) - && ( slice_matches_str (&gender, "M") - || slice_matches_str (&gender, "m") - || slice_matches_str (&gender, "F") - || slice_matches_str (&gender, "f"))) { - if (alias_count < 32) { - if (slice_matches_str (&gender, "F") || slice_matches_str (&gender, "f")) - female_bits |= 1 << alias_count; - gender_specified_bits |= 1 << alias_count; - } - if (title.len > 0) - titles[alias_count] = extract_slice (&title); - cur = inner_cur; - } - } - - alias_count++; - } else - break; - } - if (alias_count == 0) - return RPR_PARSE_ERROR; - - *p_cursor = cur; - - // Check that "key" matches a noun, adjective, or formal name of any civ ("race") in the scenario data. Store that civ. - Race * race_matching_key = NULL; { - for (int n = 0; n < p_bic_data->RacesCount; n++) { - Race * race = &p_bic_data->Races[n]; - if ( ( leader_else_civ_name - && slice_matches_str (&key, race->LeaderName)) - || ( (! leader_else_civ_name) - && ( slice_matches_str (&key, race->AdjectiveName) - || slice_matches_str (&key, race->CountryName) - || slice_matches_str (&key, race->SingularName)))) { - race_matching_key = race; - break; - } - } - } - if (race_matching_key == NULL) { - add_unrecognized_line (p_unrecognized_lines, &key); - return RPR_UNRECOGNIZED; - } - - if (leader_else_civ_name) { - struct leader_era_alias_list * out = out_leader_or_civ_alias_list; - memset (out, 0, sizeof *out); // Make sure unspecified aliases & titles are NULL - out->key = extract_slice (&key); - for (int n = 0; n < alias_count; n++) { - out->aliases[n] = aliases[n]; - out->titles[n] = titles[n]; - } - - // Set gender bits - int unreplaced_bits = (race_matching_key->LeaderGender == 0) ? 0 : ~0; - out->gender_bits = (unreplaced_bits & ~gender_specified_bits) | female_bits; - - - } else { - struct civ_era_alias_list * out = out_leader_or_civ_alias_list; - memset (out, 0, sizeof *out); - out->key = extract_slice (&key); - for (int n = 0; n < alias_count; n++) - out->aliases[n] = aliases[n]; - } - - return RPR_OK; - } else - return RPR_PARSE_ERROR; -} - - -enum recognizable_parse_result -parse_civ_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_civ_era_alias_list) -{ - return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_civ_era_alias_list, false); -} - -enum recognizable_parse_result -parse_leader_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_era_alias_list) -{ - return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_leader_era_alias_list, true); -} - -struct parsed_unit_type_limit { - char name[32]; // Same length as Name in Unit_Type - struct unit_type_limit limit; -}; - -enum recognizable_parse_result -parse_unit_type_limit (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_unit_type_limit) -{ - char * cur = *p_cursor; - struct parsed_unit_type_limit * out = out_parsed_unit_type_limit; - - struct string_slice name; - struct unit_type_limit limit = {0}; - if (skip_white_space (&cur) && - parse_string (&cur, &name) && - (name.len < (sizeof out->name)) && - skip_punctuation (&cur, ':')) { - - do { - int num; - if (! parse_int (&cur, &num)) - return RPR_PARSE_ERROR; - - struct string_slice ss; - if (parse_string (&cur, &ss)) { - if (slice_matches_str (&ss, "per-city")) - limit.per_city += num; - else if (slice_matches_str (&ss, "cities-per")) - limit.cities_per += num; - else - return RPR_PARSE_ERROR; - } else - limit.per_civ += num; - - } 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 { - add_unrecognized_line (p_unrecognized_lines, &name); - *p_cursor = cur; - return RPR_UNRECOGNIZED; - } - - } else - return RPR_PARSE_ERROR; -} - -enum recognizable_parse_result -parse_work_area_improvement (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_work_area_improvement) -{ - char * cur = *p_cursor; - struct work_area_improvement * out = out_parsed_work_area_improvement; - out->improv_id = -1; - out->work_area_radius_limit = 0; - out->work_area_radius_bonus = 0; - - struct string_slice improv_name; - if (skip_white_space (&cur) && - parse_string (&cur, &improv_name) && - skip_punctuation (&cur, ':')) { - - int num; - if (! parse_int (&cur, &num)) - return RPR_PARSE_ERROR; - - struct string_slice ss; - if (parse_string (&cur, &ss)) { - if (slice_matches_str (&ss, "extra")) - out->work_area_radius_bonus = num; - else - return RPR_PARSE_ERROR; - } else - out->work_area_radius_limit = num; - - int improv_id; - if (slice_matches_str (&improv_name, "default")) { - out->improv_id = -1; - *p_cursor = cur; - return RPR_OK; - } else if (find_improv_id_by_name (&improv_name, &improv_id)) { - out->improv_id = improv_id; - *p_cursor = cur; - return RPR_OK; - } else { - add_unrecognized_line (p_unrecognized_lines, &improv_name); - *p_cursor = cur; - return RPR_UNRECOGNIZED; - } - - } else - return RPR_PARSE_ERROR; -} - -// Recognizable items are appended to out_list/count, which must have been previously initialized (NULL/0 is valid for an empty list). -// If an error occurs while reading, returns the location of the error inside the slice, specifically the number of characters before the unreadable -// item. If no error occurs, returns -1. -int -read_recognizables (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - int item_size, - enum recognizable_parse_result (* parse_item) (char **, struct error_line **, void *), - void ** inout_list, - int * inout_count) -{ - if (s->len <= 0) - return -1; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - - bool success = false; - void * new_items = NULL; - int count_new_items = 0; - int new_items_capacity = 0; - void * temp_item = malloc (item_size); - - while (1) { - enum recognizable_parse_result result = parse_item (&cursor, p_unrecognized_lines, temp_item); - if (result != RPR_PARSE_ERROR) { - if (result == RPR_OK) { - reserve (item_size, &new_items, &new_items_capacity, count_new_items); - memcpy ((byte *)new_items + count_new_items * item_size, temp_item, item_size); - count_new_items++; - } - - if (skip_punctuation (&cursor, ',') && skip_white_space (&cursor)) - continue; - else if (skip_horiz_space (&cursor) && (*cursor == '\0')) { - success = true; - break; - } else - break; - } else - break; - } - - if (success && (count_new_items > 0)) { - *inout_list = realloc (*inout_list, (*inout_count + count_new_items) * item_size); - memcpy ((byte *)*inout_list + *inout_count * item_size, new_items, count_new_items * item_size); - *inout_count += count_new_items; - } - free (temp_item); - free (new_items); - free (extracted_slice); - return success ? -1 : cursor - extracted_slice; -} - -// Reads a "sidtable" from text. A sidtable maps strings to IDs of scenario objects. The string keys are also expected to be a type of scenario -// object. This method reads text such as: -// Factory: Battleship, Stable: Horseman Knight Cavalry, "Siege Workshop": Catapult Trebuchet -// and converts it to a table mapping "Factory", "Stable", and "Siege Workshop" to the corresponding unit type IDs. All new entries are appended to -// the given table; existing entries are not removed. -// Like read_recognizables, this method returns -1 for success or the location of an error if there is one. -int -read_sidtable (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - enum game_object_kind key_kind, - enum game_object_kind list_elem_kind, - struct table * sidtable) -{ - if (s->len <= 0) - return -1; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - while (1) { - struct string_slice key; - if (skip_white_space (&cursor) && parse_string (&cursor, &key)) { - int unused; - bool recognized_key = find_game_object_id_by_name (key_kind, &key, 0, &unused); - if (! recognized_key) - add_unrecognized_line (p_unrecognized_lines, &key); - if (! skip_punctuation (&cursor, ':')) - break; - struct string_slice elem_name; - while (skip_white_space (&cursor) && parse_string (&cursor, &elem_name)) { - bool recognized_elem = false; - int elem_id = -1; - while (find_game_object_id_by_name (list_elem_kind, &elem_name, elem_id + 1, &elem_id)) { - recognized_elem = true; - if (recognized_key) - sidtable_append (sidtable, &key, elem_id); - } - if (! recognized_elem) - add_unrecognized_line (p_unrecognized_lines, &elem_name); - } - skip_punctuation (&cursor, ','); - } else { - success = (*cursor == '\0'); - break; - } - } - - free (extracted_slice); - return success ? -1 : cursor - extracted_slice; -} - -// Like read_recognizables, returns -1 for success or the location of an error if there is one -int -read_building_unit_prereqs (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - struct table * building_unit_prereqs) -{ - if (s->len <= 0) - return -1; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - struct prereq { - int building_id; - struct string_slice unit_type_name; - } * new_prereqs = NULL; - int new_prereqs_capacity = 0; - int count_new_prereqs = 0; - - while (1) { - struct string_slice building_name; - if (skip_white_space (&cursor) && parse_string (&cursor, &building_name)) { - int building_id; - bool have_building_id = find_improv_id_by_name (&building_name, &building_id); - if (! have_building_id) - add_unrecognized_line (p_unrecognized_lines, &building_name); - if (! skip_punctuation (&cursor, ':')) - break; - struct string_slice unit_type_name; - while (skip_white_space (&cursor) && parse_string (&cursor, &unit_type_name)) { - int unused; - if (find_unit_type_id_by_name (&unit_type_name, 0, &unused)) { // if there is any by this name, later we'll deal with the possibility of multiple - if (have_building_id) { - reserve (sizeof new_prereqs[0], (void **)&new_prereqs, &new_prereqs_capacity, count_new_prereqs); - new_prereqs[count_new_prereqs++] = (struct prereq) { .building_id = building_id, .unit_type_name = unit_type_name }; - } - } else - add_unrecognized_line (p_unrecognized_lines, &unit_type_name); - } - skip_punctuation (&cursor, ','); - } else { - success = (*cursor == '\0'); - break; - } - } - - // If parsing succeeded, add the new prereq rules to the table - if (success) - for (int n = 0; n < count_new_prereqs; n++) { - struct prereq * prereq = &new_prereqs[n]; - - int unit_type_id = -1; - while (find_unit_type_id_by_name (&prereq->unit_type_name, unit_type_id + 1, &unit_type_id)) { - - // If this unit type ID is not already in the table, insert it paired with the encoded building ID - int prev_val; - if (! itable_look_up (building_unit_prereqs, unit_type_id, &prev_val)) - itable_insert (building_unit_prereqs, unit_type_id, (prereq->building_id << 1) | 1); - - // If the unit type ID is already associated with a building ID, create a list for both the old and new building IDs - else if (prev_val & 1) { - int * list = malloc (MAX_BUILDING_PREREQS_FOR_UNIT * sizeof *list); - for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) - list[n] = -1; - list[0] = prev_val >> 1; // Decode - list[1] = prereq->building_id; - itable_insert (building_unit_prereqs, unit_type_id, (int)list); - - // Otherwise, it's already associated with a list. Search the list for a free spot and fill it with the new building ID - } else { - int * list = (int *)prev_val; - for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) - if (list[n] < 0) { - list[n] = prereq->building_id; - break; - } - } - } - } - - - free (new_prereqs); - free (extracted_slice); - return success ? -1 : cursor - extracted_slice; -} - -// Reads a space-separated list of unit types like: -// Worker Galley "Gallic Swordsman" -// Looks up the type ID(s) for each name and inserts them into the unit_types table associated with a value of 1. -bool -read_unit_type_list (struct string_slice const * s, struct error_line ** p_unrecognized_lines, struct table * unit_types) -{ - if (s->len <= 0) - return true; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - while (1) { - struct string_slice name; - if (parse_string (&cursor, &name)) { - - int id = -1; - bool matched_any = false; - while (find_unit_type_id_by_name (&name, id + 1, &id)) { - itable_insert (unit_types, id, 1); - matched_any = true; - } - - if (! matched_any) - add_unrecognized_line (p_unrecognized_lines, &name); - - } else { - skip_white_space (&cursor); - success = *cursor == '\0'; - break; - } - } - - free (extracted_slice); - return success; -} - -bool -read_ai_multi_start_extra_palaces (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - int ** p_ai_multi_start_extra_palaces, - int * p_count_ai_multi_start_extra_palaces, - int * p_ai_multi_start_extra_palaces_capacity) -{ - if (s->len <= 0) - return true; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - while (1) { - struct string_slice name; - if (parse_string (&cursor, &name)) { - int id; - if (find_improv_id_by_name (&name, &id)) { - int count = *p_count_ai_multi_start_extra_palaces; - reserve (sizeof **p_ai_multi_start_extra_palaces, (void **)p_ai_multi_start_extra_palaces, p_ai_multi_start_extra_palaces_capacity, count); - (*p_ai_multi_start_extra_palaces)[count] = id; - *p_count_ai_multi_start_extra_palaces = count + 1; - } else - add_unrecognized_line (p_unrecognized_lines, &name); - - } else { - skip_white_space (&cursor); - success = *cursor == '\0'; - break; - } - } - - free (extracted_slice); - return success; -} - -bool -read_retreat_rules (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "standard" )) { *out_val = RR_STANDARD; return true; } - else if (slice_matches_str (&trimmed, "none" )) { *out_val = RR_NONE; return true; } - else if (slice_matches_str (&trimmed, "all-units" )) { *out_val = RR_ALL_UNITS; return true; } - else if (slice_matches_str (&trimmed, "if-faster" )) { *out_val = RR_IF_FASTER; return true; } - else if (slice_matches_str (&trimmed, "if-not-slower" )) { *out_val = RR_IF_NOT_SLOWER; return true; } - else if (slice_matches_str (&trimmed, "if-fast-and-not-slower")) { *out_val = RR_IF_FAST_AND_NOT_SLOWER; return true; } - else - return false; -} - -bool -read_line_drawing_override (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "never" )) { *out_val = LDO_NEVER; return true; } - else if (slice_matches_str (&trimmed, "wine" )) { *out_val = LDO_WINE; return true; } - else if (slice_matches_str (&trimmed, "always")) { *out_val = LDO_ALWAYS; return true; } - else - return false; -} - -bool -read_minimap_doubling_mode (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "never" )) { *out_val = MDM_NEVER; return true; } - else if (slice_matches_str (&trimmed, "high-def")) { *out_val = MDM_HIGH_DEF; return true; } - else if (slice_matches_str (&trimmed, "always" )) { *out_val = MDM_ALWAYS; return true; } - else - return false; -} - -bool -read_unit_cycle_search_criteria (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "standard" )) { *out_val = UCSC_STANDARD; return true; } - else if (slice_matches_str (&trimmed, "similar-near-start" )) { *out_val = UCSC_SIMILAR_NEAR_START; return true; } - else if (slice_matches_str (&trimmed, "similar-near-destination")) { *out_val = UCSC_SIMILAR_NEAR_DESTINATION; return true; } - else - return false; -} - -bool -read_no_ai_patrol_override (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "zero")) { *out_val = NAPO_ZERO; return true; } - else if (slice_matches_str (&trimmed, "one" )) { *out_val = NAPO_ONE; return true; } - else if (slice_matches_str (&trimmed, "none")) { *out_val = NAPO_NONE; return true; } - else - return false; -} - -bool -read_work_area_limit (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "none" )) { *out_val = WAL_NONE; return true; } - else if (slice_matches_str (&trimmed, "cultural" )) { *out_val = WAL_CULTURAL; return true; } - else if (slice_matches_str (&trimmed, "cultural-min-2" )) { *out_val = WAL_CULTURAL_MIN_2; return true; } - else if (slice_matches_str (&trimmed, "cultural-or-adjacent")) { *out_val = WAL_CULTURAL_OR_ADJACENT; return true; } - else - return false; -} - -bool -read_day_night_cycle_mode (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "off" )) { *out_val = DNCM_OFF; return true; } - else if (slice_matches_str (&trimmed, "timer" )) { *out_val = DNCM_TIMER; return true; } - else if (slice_matches_str (&trimmed, "user-time" )) { *out_val = DNCM_USER_TIME; return true; } - else if (slice_matches_str (&trimmed, "every-turn")) { *out_val = DNCM_EVERY_TURN; return true; } - else if (slice_matches_str (&trimmed, "specified" )) { *out_val = DNCM_SPECIFIED; return true; } - else - return false; -} - -bool -read_distribution_hub_yield_division_mode (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "flat" )) { *out_val = DHYDM_FLAT; return true; } - else if (slice_matches_str (&trimmed, "scale-by-city-count" )) { *out_val = DHYDM_SCALE_BY_CITY_COUNT; return true; } - else - return false; -} - -bool -read_ai_distribution_hub_build_strategy (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "auto" )) { *out_val = ADHBS_AUTO; return true; } - else if (slice_matches_str (&trimmed, "by-city-count" )) { *out_val = ADHBS_BY_CITY_COUNT; return true; } - else - return false; -} - -bool -read_ai_auto_build_great_wall_strategy (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "all-borders" )) { *out_val = AAGWS_ALL_BORDERS; return true; } - else if (slice_matches_str (&trimmed, "other-civ-bordered-only")) { *out_val = AAGWS_OTHER_CIV_BORDERED_ONLY; return true; } - else - return false; -} - -bool -read_tile_terrain_type_value (struct string_slice const * s, enum SquareTypes * out_type) -{ - if (s == NULL || out_type == NULL) - return false; - - struct string_slice trimmed = trim_string_slice (s, 1); - if (trimmed.len <= 0) - return false; - - struct { - char const * name; - int value; - } const entries[] = { - {"desert", SQ_Desert}, - {"deserts", SQ_Desert}, - {"plain", SQ_Plains}, - {"plains", SQ_Plains}, - {"grassland", SQ_Grassland}, - {"grasslands", SQ_Grassland}, - {"tundra", SQ_Tundra}, - {"tundras", SQ_Tundra}, - {"floodplain", SQ_FloodPlain}, - {"floodplains", SQ_FloodPlain}, - {"hill", SQ_Hills}, - {"hills", SQ_Hills}, - {"mountain", SQ_Mountains}, - {"mountains", SQ_Mountains}, - {"forest", SQ_Forest}, - {"forests", SQ_Forest}, - {"jungle", SQ_Jungle}, - {"jungles", SQ_Jungle}, - {"marsh", SQ_Swamp}, - {"marshes", SQ_Swamp}, - {"swamp", SQ_Swamp}, - {"swamps", SQ_Swamp}, - {"volcano", SQ_Volcano}, - {"volcanos", SQ_Volcano}, - {"coast", SQ_Coast}, - {"coasts", SQ_Coast}, - {"sea", SQ_Sea}, - {"seas", SQ_Sea}, - {"ocean", SQ_Ocean}, - {"oceans", SQ_Ocean}, - {"river", SQ_RIVER}, - {"rivers", SQ_RIVER}, - {"snow-volcano", SQ_SNOW_VOLCANO}, - {"snow-volcanos", SQ_SNOW_VOLCANO}, - {"snow-forest", SQ_SNOW_FOREST}, - {"snow-forests", SQ_SNOW_FOREST}, - {"snow-mountain", SQ_SNOW_MOUNTAIN}, - {"snow-mountains", SQ_SNOW_MOUNTAIN}, - {"any", SQ_INVALID} - }; - - for (int i = 0; i < (int)ARRAY_LEN (entries); i++) { - if (slice_matches_str (&trimmed, entries[i].name)) { - *out_type = (enum SquareTypes)entries[i].value; - return true; - } - } - - return false; -} - -unsigned int -square_type_mask_bit (enum SquareTypes type) -{ - if ((int)type < 0 || type > SQ_SNOW_MOUNTAIN) - return 0; - return (unsigned int)(1u << type); -} - -unsigned int -district_buildable_mine_mask_bit (void) -{ - return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 1)); -} - -unsigned int -district_buildable_irrigation_mask_bit (void) -{ - return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 2)); -} - -unsigned int -district_buildable_lake_mask_bit (void) -{ - return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 3)); -} - -unsigned int -all_square_types_mask (void) -{ - return (unsigned int)((1u << (SQ_SNOW_MOUNTAIN + 1)) - 1); -} - -unsigned int -district_default_buildable_mask (void) -{ - return (unsigned int)DEFAULT_DISTRICT_BUILDABLE_MASK; -} - -bool -tile_has_snow_mountain (Tile * tile) -{ - return (tile != NULL) && (tile != p_null_tile) && tile->vtable->m29_Check_Mountain_Snowcap (tile); -} - -bool -tile_is_lake (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (! tile->vtable->m35_Check_Is_Water (tile)) - return false; - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - return false; - - int lake_size_threshold = 21; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - return continent->Body.TileCount <= lake_size_threshold; -} - -bool -tile_has_snow_volcano (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Volcano) - return false; - - int overlays = tile->vtable->m43_Get_field_30 (tile); - return (overlays & 0x100000) != 0; -} - -bool -tile_has_snow_forest (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Forest) - return false; - - int overlays = tile->vtable->m43_Get_field_30 (tile); - return (overlays & 0x100000) != 0; -} - -bool -tile_matches_square_type (Tile * tile, enum SquareTypes type) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - switch (type) { - case SQ_SNOW_MOUNTAIN: - return tile_has_snow_mountain (tile); - case SQ_SNOW_VOLCANO: - return tile_has_snow_volcano (tile); - case SQ_SNOW_FOREST: - return tile_has_snow_forest (tile); - case SQ_RIVER: - return tile->vtable->m37_Get_River_Code (tile) != 0; - default: - return tile->vtable->m50_Get_Square_BaseType (tile) == type; - } -} - -bool -tile_matches_square_type_mask (Tile * tile, unsigned int mask) -{ - if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) - return false; - - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - unsigned int base_bit = square_type_mask_bit (base_type); - if ((base_bit != 0) && ((mask & base_bit) != 0)) - return true; - - enum SquareTypes const special_types[] = {SQ_RIVER, SQ_SNOW_MOUNTAIN, SQ_SNOW_VOLCANO, SQ_SNOW_FOREST}; - for (int i = 0; i < (int)ARRAY_LEN (special_types); i++) { - enum SquareTypes stype = special_types[i]; - unsigned int bit = square_type_mask_bit (stype); - if ((mask & bit) && tile_matches_square_type (tile, stype)) - return true; - } - - unsigned int mine_bit = district_buildable_mine_mask_bit (); - if ((mask & mine_bit) && tile->vtable->m18_Check_Mines (tile, __, 0)) - return true; - - unsigned int irrigation_bit = district_buildable_irrigation_mask_bit (); - if ((mask & irrigation_bit) && tile->vtable->m17_Check_Irrigation (tile, __, 0)) - return true; - - unsigned int lake_bit = district_buildable_lake_mask_bit (); - if ((mask & lake_bit) && tile_is_lake (tile)) - return true; - - return false; -} - -bool -tile_matches_overlay_mask (Tile * tile, unsigned int mask) -{ - if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) - return false; - - unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); - if ((mask & DOM_MINE) && ((overlays & TILE_FLAG_MINE) != 0)) - return true; - if ((mask & DOM_IRRIGATION) && ((overlays & 0x00000008) != 0)) - return true; - if ((mask & DOM_FORTRESS) && ((overlays & 0x00000010) != 0)) - return true; - if ((mask & DOM_BARRICADE) && ((overlays & 0x10000000) != 0)) - return true; - if ((mask & DOM_OUTPOST) && ((overlays & 0x80000000) != 0)) - return true; - if ((mask & DOM_RADAR_TOWER) && ((overlays & 0x40000000) != 0)) - return true; - if ((mask & DOM_AIRFIELD) && ((overlays & 0x20000000) != 0)) - return true; - if ((mask & DOM_JUNGLE) && tile_matches_square_type (tile, SQ_Jungle)) - return true; - if ((mask & DOM_FOREST) && tile_matches_square_type (tile, SQ_Forest)) - return true; - if ((mask & DOM_SWAMP) && tile_matches_square_type (tile, SQ_Swamp)) - return true; - if ((mask & DOM_RIVER) && tile_matches_square_type (tile, SQ_RIVER)) - return true; - - return false; -} - -bool -read_natural_wonder_terrain_type (struct string_slice const * s, enum SquareTypes * out_type) -{ - enum SquareTypes parsed; - if (! read_tile_terrain_type_value (s, &parsed)) - return false; - - switch (parsed) { - case SQ_Desert: - case SQ_Plains: - case SQ_Grassland: - case SQ_Jungle: - case SQ_Tundra: - case SQ_FloodPlain: - case SQ_Swamp: - case SQ_Hills: - case SQ_Mountains: - case SQ_Forest: - case SQ_Volcano: - case SQ_SNOW_MOUNTAIN: - case SQ_SNOW_FOREST: - case SQ_SNOW_VOLCANO: - case SQ_Coast: - case SQ_Sea: - case SQ_Ocean: - *out_type = parsed; - return true; - - default: - return false; - } -} - -bool -read_direction_value (struct string_slice const * s, enum direction * out_dir) -{ - if (s == NULL || out_dir == NULL) - return false; - - struct string_slice trimmed = trim_string_slice (s, 1); - if (trimmed.len <= 0) - return false; - - if (slice_matches_str (&trimmed, "northeast")) { *out_dir = DIR_NE; return true; } - else if (slice_matches_str (&trimmed, "east" )) { *out_dir = DIR_E; return true; } - else if (slice_matches_str (&trimmed, "southeast")) { *out_dir = DIR_SE; return true; } - else if (slice_matches_str (&trimmed, "south" )) { *out_dir = DIR_S; return true; } - else if (slice_matches_str (&trimmed, "southwest")) { *out_dir = DIR_SW; return true; } - else if (slice_matches_str (&trimmed, "west" )) { *out_dir = DIR_W; return true; } - else if (slice_matches_str (&trimmed, "northwest")) { *out_dir = DIR_NW; return true; } - else if (slice_matches_str (&trimmed, "north" )) { *out_dir = DIR_N; return true; } - else - return false; -} - -bool -read_barbarian_activity_override (struct string_slice const * s, enum barbarian_activity_override * out) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (trimmed.len <= 0) - return false; - - bool found = false; - char * extracted = extract_slice (s); - - struct { - char * str; - enum barbarian_activity_override value; - } possibilities[] = {{ .str = "none" , .value = BAO_NONE }, - { .str = (*p_labels)[LBL_NO_BARBARIANS ], .value = BAO_NO_BARBARIANS }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 1], .value = BAO_SEDENTARY }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 2], .value = BAO_ROAMING }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 3], .value = BAO_RESTLESS }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 4], .value = BAO_RAGING }, - { .str = (*p_labels)[LBL_RANDOM_BARBS] , .value = BAO_RANDOM }, - { .str = "No Barbarians" , .value = BAO_NO_BARBARIANS }, - { .str = "Sedentary" , .value = BAO_SEDENTARY }, - { .str = "Roaming" , .value = BAO_ROAMING }, - { .str = "Restless" , .value = BAO_RESTLESS }, - { .str = "Raging" , .value = BAO_RAGING }, - { .str = "Random" , .value = BAO_RANDOM }}; - - // Check for exact match - for (int n = 0; n < ARRAY_LEN (possibilities); n++) - if (0 == strcmp (extracted, possibilities[n].str)) { - *out = possibilities[n].value; - found = true; - break; - } - - // If not found, check again ignoring case - if (! found) - for (int n = 0; n < ARRAY_LEN (possibilities); n++) - if (0 == _stricmp (extracted, possibilities[n].str)) { - *out = possibilities[n].value; - found = true; - break; - } - - free (extracted); - return found; -} - -struct parsable_field_bit { - char * name; - int bit_value; -}; - -bool -read_bit_field (struct string_slice const * s, struct parsable_field_bit const * bits, int count_bits, int * out_field) -{ - struct string_slice trimmed = trim_string_slice (s, 0); - s = &trimmed; - - int tr; - if (s->len <= 0) - tr = 0; - else if (slice_matches_str (s, "all")) - tr = ~0; - else { - tr = 0; - char * cursor = &s->str[0]; - char * s_end = &s->str[s->len]; - while (1) { - struct string_slice name; - - if (cursor >= s_end) - break; - else if (! parse_string (&cursor, &name)) { - skip_white_space (&cursor); - if (cursor >= s_end) - break; - else - return false; // Invalid character in value - } - - bool matched_any = false; - for (int n = 0; n < count_bits; n++) - if (slice_matches_str (&name, bits[n].name)) { - tr |= bits[n].bit_value; - matched_any = true; - break; - } - if (! matched_any) - return false; - } - } - *out_field = tr; - return true; -} - -int -read_units_per_tile_limit (struct string_slice const * s, int * out_limits) -{ - int single_val; - if (read_int (s, &single_val)) { - out_limits[0] = out_limits[1] = out_limits[2] = single_val; - return true; - - } else { - bool success = false; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - int vals[3]; - if (parse_int (&cursor, &vals[0]) && parse_int (&cursor, &vals[1]) && parse_int (&cursor, &vals[2]) && - skip_horiz_space (&cursor) && (*cursor == '\0')) { - for (int n = 0; n < ARRAY_LEN (vals); n++) - out_limits[n] = vals[n]; - success = true; - } - free (extracted_slice); - return success; - } -} - -struct config_parsing { - char * file_path; - char * text; - char * cursor; - struct string_slice key; - int displayed_error_message; -}; - -enum config_parse_error { - CPE_GENERIC, - CPE_BAD_VALUE, - CPE_BAD_BOOL_VALUE, - CPE_BAD_INT_VALUE, - CPE_BAD_STACK_LIMIT_VALUE, - CPE_BAD_KEY -}; - -void -handle_config_error_at (struct config_parsing * p, char * error_loc, enum config_parse_error err) -{ - char err_msg[1000]; - if (! p->displayed_error_message) { - int line_no = 1; - for (char * c = p->text; c < error_loc; c++) - line_no += *c == '\n'; - - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); - snprintf (err_msg, sizeof err_msg, "Error reading \"%s\" on line %d.", p->file_path, line_no); - err_msg[(sizeof err_msg) - 1] = '\0'; - PopupForm_add_text (popup, __, err_msg, false); - - if (err == CPE_GENERIC) { - if (p->key.str != NULL) - snprintf (err_msg, sizeof err_msg, "^The last key successfully read was \"%.*s\".", p->key.len, p->key.str); - else - snprintf (err_msg, sizeof err_msg, "^Error occurred before any keys could be read."); - } else if (err == CPE_BAD_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid.", p->key.len, p->key.str); - else if (err == CPE_BAD_BOOL_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"true\" or \"false\".", p->key.len, p->key.str); - else if (err == CPE_BAD_INT_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected an integer.", p->key.len, p->key.str); - else if (err == CPE_BAD_STACK_LIMIT_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"false\", an integer, or a list of exactly three of those.", p->key.len, p->key.str); - else if (err == CPE_BAD_KEY) - snprintf (err_msg, sizeof err_msg, "^The key name \"%.*s\" is not recognized.", p->key.len, p->key.str); - err_msg[(sizeof err_msg) - 1] = '\0'; - PopupForm_add_text (popup, __, err_msg, false); - - patch_show_popup (popup, __, 0, 0); - p->displayed_error_message = 1; - } -} - -void -handle_config_error (struct config_parsing * p, enum config_parse_error err) -{ - handle_config_error_at (p, p->cursor, err); -} - -// Loads a config from the given file, layering it on top of is->current_config and appending its name to the list of loaded configs. Does NOT -// re-apply machine code edits. -void -load_config (char const * file_path, int path_is_relative_to_mod_dir) -{ - char err_msg[1000]; - struct c3x_config * cfg = &is->current_config; - - int full_path_size = 2 * MAX_PATH; - char * full_path = malloc (full_path_size); - if (path_is_relative_to_mod_dir) - snprintf (full_path, full_path_size, "%s\\%s", is->mod_rel_dir, file_path); - else - strncpy (full_path, file_path, full_path_size); - full_path[full_path_size - 1] = '\0'; - - char * text; { - char * utf8_text = file_to_string (full_path); - if (utf8_text == NULL) { - free (full_path); - return; - } - text = convert_from_utf8 (utf8_text, *p_code_page); - free (utf8_text); - if (text == NULL) { - snprintf (err_msg, sizeof err_msg, "Failed to re-encode contents of \"%s\". This file must contain UTF-8 text and only characters usable by Civ 3.", full_path); - err_msg[(sizeof err_msg) - 1] = '\0'; - pop_up_in_game_error (err_msg); - free (full_path); - return; - } - } - - struct perfume_spec_list { - struct perfume_spec * items; - int count; - } perfume_spec_lists[COUNT_PERFUME_KINDS] = {0}; - - struct parsed_unit_type_limit * parsed_unit_type_limits = NULL; - int parsed_unit_type_limit_count = 0; - - struct config_parsing p = { .file_path = full_path, .text = text, .cursor = text, .key = {0}, .displayed_error_message = 0 }; - struct error_line * unrecognized_lines = NULL; - while (1) { - skip_horiz_space (&p.cursor); - if (*p.cursor == '\0') - break; - else if (*p.cursor == '\n') - p.cursor++; // Continue to next line - else if (*p.cursor == ';') - skip_to_line_end (&p.cursor); // Skip comment line - else if (*p.cursor == '[') - skip_to_line_end (&p.cursor); // Skip section line - else if (parse_string (&p.cursor, &p.key) && skip_punctuation (&p.cursor, '=')) { // Parse key and equals sign - - struct string_slice value; - if (parse_string (&p.cursor, &value) || parse_bracketed_block (&p.cursor, &value)) { // Parse value - int ival, offset, recog_err_offset; - - // if key is for a boolean option - if (stable_look_up_slice (&is->boolean_config_offsets, &p.key, &offset)) { - if (read_int (&value, &ival)) - *((char *)cfg + offset) = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - - // if key is for an integer option - } else if (stable_look_up_slice (&is->integer_config_offsets, &p.key, &offset)) { - if (read_int (&value, &ival)) - *(int *)((byte *)cfg + offset) = ival; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - - // Handle city_work_radius separately from the other int options so we can clamp it and update the count var - } else if (slice_matches_str (&p.key, "city_work_radius")) { - if (read_int (&value, &ival)) { - cfg->city_work_radius = clamp (1, 7, ival); - is->workable_tile_count = workable_tile_counts[cfg->city_work_radius]; - } else - handle_config_error (&p, CPE_BAD_INT_VALUE); - - // if key is for something special - } else if (slice_matches_str (&p.key, "limit_units_per_tile")) { - if (! read_units_per_tile_limit (&value, &cfg->limit_units_per_tile[0])) - handle_config_error (&p, CPE_BAD_STACK_LIMIT_VALUE); - } else if (slice_matches_str (&p.key, "production_perfume") || slice_matches_str (&p.key, "perfume_specs")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct perfume_spec), - parse_production_perfume_spec, - (void **)&perfume_spec_lists[PK_PRODUCTION].items, - &perfume_spec_lists[PK_PRODUCTION].count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "technology_perfume")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct perfume_spec), - parse_technology_perfume_spec, - (void **)&perfume_spec_lists[PK_TECHNOLOGY].items, - &perfume_spec_lists[PK_TECHNOLOGY].count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "government_perfume")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct perfume_spec), - parse_government_perfume_spec, - (void **)&perfume_spec_lists[PK_GOVERNMENT].items, - &perfume_spec_lists[PK_GOVERNMENT].count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "building_prereqs_for_units")) { - if (0 <= (recog_err_offset = read_building_unit_prereqs (&value, &unrecognized_lines, &cfg->building_unit_prereqs))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "buildings_generating_resources")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct mill), - parse_mill, - (void **)&cfg->mills, - &cfg->count_mills))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_multi_start_extra_palaces")) { - if (! read_ai_multi_start_extra_palaces (&value, - &unrecognized_lines, - &cfg->ai_multi_start_extra_palaces, - &cfg->count_ai_multi_start_extra_palaces, - &cfg->ai_multi_start_extra_palaces_capacity)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_settler_perfume_on_founding")) { - if (! read_i31b (&value, &cfg->ai_settler_perfume_on_founding)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "land_retreat_rules")) { - if (! read_retreat_rules (&value, (int *)&cfg->land_retreat_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "sea_retreat_rules")) { - if (! read_retreat_rules (&value, (int *)&cfg->sea_retreat_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "draw_lines_using_gdi_plus")) { - if (! read_line_drawing_override (&value, (int *)&cfg->draw_lines_using_gdi_plus)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "double_minimap_size")) { - if (! read_minimap_doubling_mode (&value, (int *)&cfg->double_minimap_size)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "unit_cycle_search_criteria")) { - if (! read_unit_cycle_search_criteria (&value, (int *)&cfg->unit_cycle_search_criteria)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "override_no_ai_patrol")) { - if (! read_no_ai_patrol_override (&value, (int *)&cfg->override_no_ai_patrol)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "override_barbarian_activity_level_for_scenario_maps")) { - if (! read_barbarian_activity_override (&value, &cfg->override_barbarian_activity_level_for_scenario_maps)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "special_defensive_bombard_rules")) { - struct parsable_field_bit bits[] = { - {"lethal" , SDBR_LETHAL}, - {"not-invisible" , SDBR_NOT_INVISIBLE}, - {"aerial" , SDBR_AERIAL}, - {"blitz" , SDBR_BLITZ}, - {"docked-vs-land", SDBR_DOCKED_VS_LAND}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_defensive_bombard_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "special_zone_of_control_rules")) { - struct parsable_field_bit bits[] = { - {"lethal" , SZOCR_LETHAL}, - {"aerial" , SZOCR_AERIAL}, - {"amphibious" , SZOCR_AMPHIBIOUS}, - {"not-from-inside", SZOCR_NOT_FROM_INSIDE}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_zone_of_control_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "land_transport_rules")) { - struct parsable_field_bit bits[] = { - {"load-onto-boat" , LTR_LOAD_ONTO_BOAT}, - {"join-army" , LTR_JOIN_ARMY}, - {"no-defense-from-inside", LTR_NO_DEFENSE_FROM_INSIDE}, - {"no-escape" , LTR_NO_ESCAPE}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->land_transport_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "special_helicopter_rules")) { - struct parsable_field_bit bits[] = { - {"allow-on-carriers" , SHR_ALLOW_ON_CARRIERS}, - {"passenger-airdrop" , SHR_PASSENGER_AIRDROP}, - {"no-defense-from-inside", SHR_NO_DEFENSE_FROM_INSIDE}, - {"no-escape" , SHR_NO_ESCAPE}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_helicopter_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "work_area_limit")) { - if (! read_work_area_limit (&value, (int *)&cfg->work_area_limit)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "work_area_improvements")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct work_area_improvement), - parse_work_area_improvement, - (void **)&cfg->work_area_improvements, - &cfg->count_work_area_improvements))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "day_night_cycle_mode")) { - if (! read_day_night_cycle_mode (&value, (int *)&cfg->day_night_cycle_mode)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "distribution_hub_yield_division_mode")) { - if (! read_distribution_hub_yield_division_mode (&value, (int *)&cfg->distribution_hub_yield_division_mode)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_distribution_hub_build_strategy")) { - if (! read_ai_distribution_hub_build_strategy (&value, (int *)&cfg->ai_distribution_hub_build_strategy)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_auto_build_great_wall_strategy")) { - if (! read_ai_auto_build_great_wall_strategy (&value, (int *)&cfg->ai_auto_build_great_wall_strategy)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "great_wall_auto_build_wonder_name")) { - if (cfg->great_wall_auto_build_wonder_name != NULL) { - free (cfg->great_wall_auto_build_wonder_name); - cfg->great_wall_auto_build_wonder_name = NULL; - } - cfg->great_wall_auto_build_wonder_name = copy_trimmed_string_or_null (&value, 1); - cfg->great_wall_auto_build_wonder_improv_id = -1; - } else if (slice_matches_str (&p.key, "exclude_types_from_units_per_tile_limit")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->exclude_types_from_units_per_tile_limit)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "limit_defensive_retreat_on_water_to_types")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->limit_defensive_retreat_on_water_to_types)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ptw_like_artillery_targeting")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->ptw_arty_types)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "can_bombard_only_sea_tiles")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->can_bombard_only_sea_tiles)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "civ_aliases_by_era")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct civ_era_alias_list), - parse_civ_name_alias_list, - (void **)&cfg->civ_era_alias_lists, - &cfg->count_civ_era_alias_lists))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "leader_aliases_by_era")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct leader_era_alias_list), - parse_leader_name_alias_list, - (void **)&cfg->leader_era_alias_lists, - &cfg->count_leader_era_alias_lists))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "unit_limits")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct parsed_unit_type_limit), - parse_unit_type_limit, - (void **)&parsed_unit_type_limits, - &parsed_unit_type_limit_count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "aircraft_victory_animation")) { - struct string_slice trimmed = trim_string_slice (&value, 1); - bool value_ok = false; - if (slice_matches_str (&trimmed, "none")) { - if (cfg->aircraft_victory_animation != NULL) { - free (cfg->aircraft_victory_animation); - cfg->aircraft_victory_animation = NULL; - } - value_ok = true; - } else if (trimmed.len > 0) { - AnimationType unused; - if (find_animation_type_by_name (&trimmed, true, &unused)) { - if (cfg->aircraft_victory_animation != NULL) - free (cfg->aircraft_victory_animation); - cfg->aircraft_victory_animation = extract_slice (&trimmed); - value_ok = true; - } - } - if (! value_ok) - handle_config_error (&p, CPE_BAD_VALUE); - - // if key is for an obsolete option - } else if (slice_matches_str (&p.key, "patch_disembark_immobile_bug")) { - if (read_int (&value, &ival)) - cfg->patch_blocked_disembark_freeze = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "anarchy_length_reduction_percent")) { - if (read_int (&value, &ival)) - cfg->anarchy_length_percent = 100 - ival; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - } else if (slice_matches_str (&p.key, "adjust_minimum_city_separation")) { - if (read_int (&value, &ival)) - cfg->minimum_city_separation = ival + 1; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - } else if (slice_matches_str (&p.key, "reduce_max_escorts_per_ai_transport")) { - if (read_int (&value, &ival)) - cfg->max_ai_naval_escorts = 3 - ival; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - } else if (slice_matches_str (&p.key, "retreat_rules")) { - int rules; - if (read_retreat_rules (&value, &rules)) { - cfg->land_retreat_rules = rules; - cfg->sea_retreat_rules = rules; - } else - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "halve_ai_research_rate")) { - if (read_int (&value, &ival)) { - if (ival) // halving = true => set multiplier to 50, otherwise do nothing - cfg->ai_research_multiplier = 50; - } else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "enable_ai_two_city_start")) { - if (read_int (&value, &ival)) - cfg->ai_multi_city_start = (ival != 0) ? 2 : 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "polish_non_air_precision_striking")) { - if (read_int (&value, &ival)) - cfg->polish_precision_striking = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "promote_forbidden_palace_decorruption")) { - if (read_int (&value, &ival)) - cfg->promote_wonder_decorruption_effect = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "move_trade_net_object")) { - ; // No nothing. This setting no longer serves any purpose. - - // if key was previously misspelled - } else if (slice_matches_str (&p.key, "share_visibility_in_hoseat")) { - if (read_int (&value, &ival)) - cfg->share_visibility_in_hotseat = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "unit_group")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct unit_counter_group), - parse_unit_counter_group, - (void **)&cfg->unit_counter_groups, - &cfg->count_unit_counter_groups))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "counter_rule")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct counter_rule), - parse_counter_rule, - (void **)&cfg->counter_rules, - &cfg->count_counter_rules))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - - } else { - handle_config_error (&p, CPE_BAD_KEY); - } - - - } else { // Failed to parse value - handle_config_error (&p, CPE_BAD_VALUE); - skip_to_line_end (&p.cursor); - } - - } else { // Failed to categorize line - handle_config_error (&p, CPE_GENERIC); - skip_to_line_end (&p.cursor); - } - } - - if (cfg->warn_about_unrecognized_names && (unrecognized_lines != NULL)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "Unrecognized names in %s:", full_path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - for (struct error_line * line = unrecognized_lines; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - patch_show_popup (popup, __, 0, 0); - } - - // Copy perfume specs from lists to tables - for (int n = 0; n < COUNT_PERFUME_KINDS; n++) { - struct table * table = &cfg->perfume_specs[n]; - struct perfume_spec_list * list = &perfume_spec_lists[n]; - if (list->items != NULL) { - for (int k = 0; k < list->count; k++) { - struct perfume_spec * ps = &list->items[k]; - stable_insert (table, ps->name, ps->value); - } - free (list->items); - } - } - - // Copy unit type limits from list to table - if (parsed_unit_type_limits != NULL) { - for (int n = 0; n < parsed_unit_type_limit_count; n++) { - struct parsed_unit_type_limit * parsed_lim = &parsed_unit_type_limits[n]; - struct unit_type_limit * lim_values = malloc (sizeof *lim_values); - *lim_values = parsed_lim->limit; - stable_insert (&cfg->unit_limits, parsed_lim->name, (int)lim_values); - } - free (parsed_unit_type_limits); - } - - free (text); - free_error_lines (unrecognized_lines); - - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = full_path; - new_lcn->next = NULL; - - top_lcn->next = new_lcn; -} - -bool -tile_coords_from_ptr (Map * map, Tile * tile, int * out_x, int * out_y) -{ - if ((tile == NULL) || (tile == p_null_tile) || (map == NULL)) - return false; - - int tile_count = map->TileCount; - for (int index = 0; index < tile_count; index++) { - Tile * candidate = Map_get_tile (map, __, index); - if (candidate == tile) { - tile_index_to_coords (map, index, out_x, out_y); - return true; - } - } - - return false; -} - -int -get_pending_district_request_key (int city_id, int district_id) -{ - if ((city_id < 0) || (district_id < 0)) - return -1; - unsigned int key = ((unsigned int)city_id << 16) | (unsigned int)(district_id & 0xffff); - return (int)key; -} - -struct pending_district_request * -find_pending_district_request (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0)) - return NULL; - - int civ_id = city->Body.CivID; - int city_id = city->Body.ID; - int key = get_pending_district_request_key (city_id, district_id); - if (key < 0) - return NULL; - - int stored; - if (itable_look_up (&is->city_pending_district_requests[civ_id], key, &stored)) { - struct pending_district_request * req = (struct pending_district_request *)stored; - if ((req != NULL) && (req->civ_id == civ_id) && (req->city_id == city_id) && (req->district_id == district_id)) { - if (req->city != city) - req->city = city; - return req; - } - } - return NULL; -} - -struct pending_district_request * -create_pending_district_request (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return NULL; - - struct pending_district_request * existing = find_pending_district_request (city, district_id); - if (existing != NULL) - return existing; - - int civ_id = city->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) - return NULL; - - struct pending_district_request * req = (struct pending_district_request *)calloc (1, sizeof *req); - if (req == NULL) - return NULL; - - req->city = city; - req->city_id = city->Body.ID; - req->civ_id = civ_id; - req->district_id = district_id; - req->assigned_worker_id = -1; - req->target_x = -1; - req->target_y = -1; - req->worker_assigned_turn = 0; - - int key = get_pending_district_request_key (req->city_id, district_id); - if (key < 0) { - free (req); - return NULL; - } - - char ss[200]; - snprintf (ss, sizeof ss, "create_pending_district_request: Creating pending district request for city %s (ID %d) district ID %d with key %d\n", - city->Body.CityName, city->Body.ID, district_id, key); - (*p_OutputDebugStringA) (ss); - - itable_insert (&is->city_pending_district_requests[civ_id], key, (int)req); - return req; -} - -struct pending_district_request * -find_pending_district_request_by_coords (City * city_or_null, int tile_x, int tile_y, int district_id) -{ - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - - int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((civ_id < 0) || (civ_id >= 32)) - return NULL; - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req == NULL) continue; - if (req->district_id != district_id) continue; - if (city_or_null != NULL) { - int city_id = city_or_null->Body.ID; - if (req->city_id != city_id) - continue; - req->city = city_or_null; - req->civ_id = city_or_null->Body.CivID; - } - if ((req->target_x == tile_x) && (req->target_y == tile_y)) - return req; - } - return NULL; -} - -bool -is_tile_earmarked_for_district (int tile_x, int tile_y) -{ - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req == NULL) continue; - if ((req->target_x == tile_x) && (req->target_y == tile_y)) - return true; - } - return false; -} - -struct district_instance * -get_district_instance (Tile * tile) -{ - if (tile == NULL || tile == p_null_tile) - return NULL; - - int stored_ptr; - if (! itable_look_up (&is->district_tile_map, (int)tile, &stored_ptr)) - return NULL; - - struct district_instance * inst = (struct district_instance *)stored_ptr; - - if ((inst == NULL) || (inst->district_id < 0) || (inst->district_id >= is->district_count)) - return NULL; - - return inst; -} - -struct wonder_district_info * -get_wonder_district_info (Tile * tile) -{ - if (tile == NULL || tile == p_null_tile) - return NULL; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return NULL; - - return &inst->wonder_info; -} - -void -remove_district_instance (Tile * tile) -{ - if (tile == NULL || tile == p_null_tile) - return; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - free (inst); - itable_remove (&is->district_tile_map, (int)tile); - } -} - -void -district_instance_set_coords (struct district_instance * inst, int tile_x, int tile_y) -{ - if (inst == NULL) - return; - - // Normalize coordinates to map bounds for consistency - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - inst->tile_x = tile_x; - inst->tile_y = tile_y; -} - -struct district_instance * -ensure_district_instance (Tile * tile, int district_id, int tile_x, int tile_y) -{ - if (tile == NULL || tile == p_null_tile) - return NULL; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - return inst; - } - - inst = (struct district_instance *)calloc (1, sizeof(struct district_instance)); - if (inst == NULL) - return NULL; - - inst->state = DS_UNDER_CONSTRUCTION; - inst->district_id = district_id; - inst->built_by_civ_id = -1; - inst->completed_turn = -1; - - // Initialize wonder_info (only relevant for wonder districts) - inst->wonder_info.state = WDS_UNUSED; - inst->wonder_info.city = NULL; - inst->wonder_info.city_id = -1; - inst->wonder_info.wonder_index = -1; - inst->natural_wonder_info.natural_wonder_id = -1; - - district_instance_set_coords (inst, tile_x, tile_y); - itable_insert (&is->district_tile_map, (int)tile, (int)inst); - return inst; -} - -bool -district_instance_get_coords (struct district_instance * inst, Tile * tile, int * out_x, int * out_y) -{ - if ((inst == NULL) || (out_x == NULL) || (out_y == NULL)) - return false; - - int x = inst->tile_x; - int y = inst->tile_y; - if ((x >= 0) && (y >= 0)) { - *out_x = x; - *out_y = y; - return true; - } - - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile_coords_from_ptr (&p_bic_data->Map, tile, &x, &y)) { - district_instance_set_coords (inst, x, y); - *out_x = x; - *out_y = y; - return true; - } - - return false; -} - -struct natural_wonder_district_config const * -get_natural_wonder_config_by_id (int natural_wonder_id) -{ - if (! is->current_config.enable_natural_wonders) - return NULL; - if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) - return NULL; - return &is->natural_wonder_configs[natural_wonder_id]; -} - -void -assign_natural_wonder_to_tile (Tile * tile, int tile_x, int tile_y, int natural_wonder_id) -{ - if (! is->current_config.enable_natural_wonders) - return; - if ((tile == NULL) || (tile == p_null_tile)) - return; - if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) - return; - - if (get_natural_wonder_config_by_id (natural_wonder_id) == NULL) - return; - - struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, tile_x, tile_y); - if (inst == NULL) - return; - - inst->district_id = NATURAL_WONDER_DISTRICT_ID; - inst->state = DS_COMPLETED; - inst->natural_wonder_info.natural_wonder_id = natural_wonder_id; - set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); -} - -int -apply_district_bonus_entries (struct district_instance * inst, - struct district_bonus_list const * extras, - int district_id) -{ - if ((inst == NULL) || (extras == NULL) || (extras->count <= 0)) - return 0; - - int tile_x = inst->tile_x; - int tile_y = inst->tile_y; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return 0; - - int bonus = 0; - for (int i = 0; i < extras->count; i++) { - struct district_bonus_entry const * entry = &extras->entries[i]; - if (entry->type == DBET_TILE) { - if (tile_matches_square_type (tile, entry->tile_type)) - bonus += entry->bonus; - } else if (entry->type == DBET_BUILDING) { - if (entry->building_id >= 0 && - tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, entry->building_id)) - bonus += entry->bonus; - } - } - - return bonus; -} - -void -get_effective_district_yields (struct district_instance * inst, - struct district_config const * cfg, - int * out_food, - int * out_shields, - int * out_gold, - int * out_science, - int * out_culture, - int * out_happiness) -{ - int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; - - if (cfg != NULL && is->current_config.enable_districts) { - food = cfg->food_bonus; - shields = cfg->shield_bonus; - gold = cfg->gold_bonus; - science = cfg->science_bonus; - culture = cfg->culture_bonus; - happiness = cfg->happiness_bonus; - - int district_id = (inst != NULL) ? inst->district_id : -1; - food += apply_district_bonus_entries (inst, &cfg->food_bonus_extras, district_id); - shields += apply_district_bonus_entries (inst, &cfg->shield_bonus_extras, district_id); - gold += apply_district_bonus_entries (inst, &cfg->gold_bonus_extras, district_id); - science += apply_district_bonus_entries (inst, &cfg->science_bonus_extras, district_id); - culture += apply_district_bonus_entries (inst, &cfg->culture_bonus_extras, district_id); - happiness += apply_district_bonus_entries (inst, &cfg->happiness_bonus_extras, district_id); - } - - if (inst != NULL && is->current_config.enable_natural_wonders && inst->district_id == NATURAL_WONDER_DISTRICT_ID) { - struct natural_wonder_district_config const * nwcfg = get_natural_wonder_config_by_id (inst->natural_wonder_info.natural_wonder_id); - if (nwcfg != NULL) { - food += nwcfg->food_bonus; - shields += nwcfg->shield_bonus; - gold += nwcfg->gold_bonus; - science += nwcfg->science_bonus; - culture += nwcfg->culture_bonus; - happiness += nwcfg->happiness_bonus; - } - } - - if (out_food != NULL) - *out_food = food; - if (out_shields != NULL) - *out_shields = shields; - if (out_gold != NULL) - *out_gold = gold; - if (out_science != NULL) - *out_science = science; - if (out_culture != NULL) - *out_culture = culture; - if (out_happiness != NULL) - *out_happiness = happiness; -} - -int -natural_wonder_min_distance_sq (int x, - int y, - struct wonder_location const * placements, - int placement_count) -{ - if ((placements == NULL) || (placement_count <= 0)) - return INT_MAX; - - int best = INT_MAX; - for (int i = 0; i < placement_count; i++) { - int dx, dy; - compute_wrapped_deltas (x, y, placements[i].x, placements[i].y, &dx, &dy); - int dist_sq = dx * dx + dy * dy; - if (dist_sq < best) - best = dist_sq; - } - return best; -} - -bool -continent_has_natural_wonder (int continent_id, - struct wonder_location const * placements, - int placement_count) -{ - if (continent_id < 0) - return false; - if ((placements == NULL) || (placement_count <= 0)) - return false; - - for (int i = 0; i < placement_count; i++) { - Tile * placed_tile = tile_at (placements[i].x, placements[i].y); - if ((placed_tile == NULL) || (placed_tile == p_null_tile)) - continue; - int placed_continent_id = placed_tile->vtable->m46_Get_ContinentID (placed_tile); - if (placed_continent_id == continent_id) - return true; - } - - return false; -} - -bool -natural_wonder_candidate_list_push (struct natural_wonder_candidate_list * list, Tile * tile, int tile_x, int tile_y) -{ - if (list == NULL) - return false; - - if (list->count >= list->capacity) { - int new_capacity = (list->capacity > 0) ? (list->capacity * 2) : 8; - struct natural_wonder_candidate * grown = - (struct natural_wonder_candidate *)realloc (list->entries, new_capacity * sizeof *grown); - if (grown == NULL) - return false; - list->entries = grown; - list->capacity = new_capacity; - } - - struct natural_wonder_candidate * entry = &list->entries[list->count++]; - entry->tile = tile; - entry->x = (short)tile_x; - entry->y = (short)tile_y; - return true; -} - -bool -natural_wonder_tile_is_clear (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (tile->CityID >= 0) return false; - if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return false; - if (tile->vtable->m15_Check_Goody_Hut (tile, __, 0)) return false; - if (tile->vtable->m39_Get_Resource_Type (tile) >= 0) return false; - if (tile->vtable->m18_Check_Mines (tile, __, 0)) return false; - if (get_district_instance (tile) != NULL) return false; - - // Check if this tile is a starting location for any civ - int tile_index = (p_bic_data->Map.Width >> 1) * tile_y + ((tile_x >> 1) & 0x7FFF); - for (int civ = 0; civ < p_bic_data->Map.Civ_Count; civ++) { - if (p_bic_data->Map.Starting_Locations[civ] == tile_index) { - return false; - } - } - - return true; -} - -bool -district_exists_within_distance (int tile_x, int tile_y, int district_id, int civ_id, int min_distance) -{ - if ((district_id < 0) || (district_id >= is->district_count) || (min_distance < 0)) - return false; - - for (int dist = 0; dist <= min_distance; dist++) { - struct vertex { - int x, y; - } vertices[4] = { - {tile_x , tile_y - 2*dist}, - {tile_x + 2*dist, tile_y }, - {tile_x , tile_y + 2*dist}, - {tile_x - 2*dist, tile_y } - }; - - int edge_dirs[4] = {3, 5, 7, 1}; - int edge_len = (dist == 0) ? 1 : 2 * dist; - - for (int vert = 0; vert < 4; vert++) { - wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); - int dx, dy; - neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); - for (int j = 0; j < edge_len; j++) { - int cx = vertices[vert].x + j * dx; - int cy = vertices[vert].y + j * dy; - wrap_tile_coords (&p_bic_data->Map, &cx, &cy); - - Tile * tile = tile_at (cx, cy); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if ((civ_id >= 0) && (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id)) - continue; - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == district_id)) - return true; - } - } - } - - return false; -} - -void -detach_workers_from_request (struct pending_district_request * req) -{ - if (req == NULL) - return; - - int civ_id = req->civ_id; - if ((civ_id < 0) || (civ_id >= 32)) { - for (int civ = 0; civ < 32; civ++) { - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - if ((rec != NULL) && (rec->pending_req == req)) - rec->pending_req = NULL; - } - } - return; - } - - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - if ((rec != NULL) && (rec->pending_req == req)) - rec->pending_req = NULL; - } -} - -void -remove_pending_district_request (struct pending_district_request * req) -{ - if (req == NULL) - return; - - int civ_id = req->civ_id; - if ((civ_id < 0) || (civ_id >= 32)) - return; - - int key = get_pending_district_request_key (req->city_id, req->district_id); - - detach_workers_from_request (req); - - if ((req->target_x >= 0) && (req->target_y >= 0)) { - Tile * tile = tile_at (req->target_x, req->target_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && - (inst->district_id == req->district_id) && - (inst->state != DS_COMPLETED)) - remove_district_instance (tile); - } - } - - if (key >= 0) - itable_remove (&is->city_pending_district_requests[civ_id], key); - req->city = NULL; - req->city_id = -1; - req->civ_id = -1; - free (req); -} - -bool __fastcall -patch_Leader_impl_would_raze_city (Leader * this, int edx, City * city) -{ - return is->current_config.prevent_razing_by_players ? false : Leader_impl_would_raze_city (this, __, city); -} - -int __fastcall patch_Unit_get_max_move_points (Unit * this); - -// This function is used to fix a bug where the game would freeze when using disembark all on a transport that contained an immobile unit. The bug -// comes from the fact that the function to disembark all units loops continuously over units in the transport until there are none left that -// can be disembarked. The problem is the logic to check disembarkability erroneously reports immobile units as disembarkable when they're not, -// so the program gets stuck in an infinite loop. The fix affects the function that checks disembarkability, replacing a call to -// Unit_get_max_move_points with a call to the function below. This function returns zero for immobile units, causing the caller to report -// (correctly) that the unit cannot be disembarked. -int __fastcall -patch_Unit_get_max_move_points_for_disembarking (Unit * this) -{ - if (is->current_config.patch_blocked_disembark_freeze && - UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Immobile)) - return 0; - else - return patch_Unit_get_max_move_points (this); -} - -// Unit::move_to_adjacent_tile uses a separate "spend all remaining movement when disembarking" branch for land units moving from water to land. -// Bridge districts still look like water tiles to that stock logic, so stepping off a bridge can incorrectly consume the whole turn. When the -// wrapper around move_to_adjacent_tile detects bridge->land movement, it precomputes the correct spent-moves total and exposes it here. -int __fastcall -patch_Unit_get_max_move_points_for_bridge_exit (Unit * this) -{ - if ((this != NULL) && (this == is->move_spend_override_unit)) - return is->move_spend_override_value; - else - return patch_Unit_get_max_move_points (this); -} - -// This func implements GA remaining turns indicator. It intercepts a call to some kind of text processing function when it's called to process the -// text in the lower right (containing current research, GA status, & mobilization) and splices in the number of remaining GA turns if in a GA. -int __fastcall -patch_PCX_Image_process_tech_ga_status (PCX_Image * this, int edx, char * str) -{ - Leader * player = &leaders[p_main_screen_form->Player_CivID]; - if (is->current_config.show_golden_age_turns_remaining && - (*p_current_turn_no < player->Golden_Age_End)) { - int turns_left = player->Golden_Age_End - *p_current_turn_no; - char const * ga_label = (*p_labels)[LBL_GOLDEN_AGE]; - char const * ga_str_start = strstr (str, ga_label); - if (ga_str_start != NULL) { - char s[250]; - char const * ga_str_end = ga_str_start + strlen (ga_label); - snprintf (s, sizeof s, "%.*s (%d)%s", ga_str_end - str, str, turns_left, ga_str_end); - s[(sizeof s) - 1] = '\0'; - strncpy (str, s, sizeof s); - } - } - return PCX_Image_process_text (this, __, str); -} - -bool __fastcall -patch_Leader_is_tile_visible (Leader * this, int edx, int x, int y) -{ - Tile_Body * tile = &tile_at (x, y)->Body; - unsigned vis_bits = tile->FOWStatus | tile->V3 | tile->Visibility | tile->field_D0_Visibility; - if (vis_bits & (1 << this->ID)) - return true; - else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND - ((1 << this->ID) & *p_human_player_bits) && // "this" is a human player AND - (vis_bits & *p_human_player_bits)) // any human player has visibility on the tile - return true; - else - return false; -} - -bool __fastcall -patch_Main_Screen_Form_is_unit_visible_to_player (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * unit) -{ - return (unit->Body.CivID == this->Player_CivID) || patch_Leader_is_tile_visible (&leaders[this->Player_CivID], __, tile_x, tile_y); -} - -enum direction -reverse_dir (enum direction dir) -{ - enum direction const reversed[] = { - DIR_ZERO, // DIR_ZERO - DIR_SW , // DIR_NE - DIR_W , // DIR_E - DIR_NW , // DIR_SE - DIR_N , // DIR_S - DIR_NE , // DIR_SW - DIR_E , // DIR_W - DIR_SE , // DIR_NW - DIR_S , // DIR_N - }; - int n = (int)dir; - if ((n >= 0) && (n < ARRAY_LEN (reversed))) - return reversed[n]; - else - return DIR_ZERO; -} - -bool -direction_to_offset (enum direction dir, int * out_dx, int * out_dy) -{ - int dx = 0, dy = 0; - - switch (dir) { - case DIR_NE: dx = 1; dy = -1; break; - case DIR_E: dx = 2; dy = 0; break; - case DIR_SE: dx = 1; dy = 1; break; - case DIR_S: dx = 0; dy = 2; break; - case DIR_SW: dx = -1; dy = 1; break; - case DIR_W: dx = -2; dy = 0; break; - case DIR_NW: dx = -1; dy = -1; break; - case DIR_N: dx = 0; dy = -2; break; - case DIR_ZERO: - default: - return false; - } - - if (out_dx != NULL) - *out_dx = dx; - if (out_dy != NULL) - *out_dy = dy; - return true; -} - -int -direction_to_neighbor_bit (enum direction dir) -{ - switch (dir) { - case DIR_NE: return 1; - case DIR_E: return 2; - case DIR_SE: return 3; - case DIR_S: return 4; - case DIR_SW: return 5; - case DIR_W: return 6; - case DIR_NW: return 7; - case DIR_N: return 0; // Matches engine behaviour where neighbor index 8 maps to 0 - default: - return -1; - } -} - -bool -get_primary_river_direction (Tile * tile, enum direction * out_dir) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - char river_bits = tile->vtable->m37_Get_River_Code (tile); - if (river_bits == 0) - return false; - - enum direction dirs[] = {DIR_E, DIR_W, DIR_SE, DIR_NE, DIR_SW, DIR_NW, DIR_S, DIR_N}; - for (int i = 0; i < (int)ARRAY_LEN (dirs); i++) { - int bit = direction_to_neighbor_bit (dirs[i]); - if ((bit >= 0) && ((river_bits & (1 << bit)) != 0)) { - if (out_dir != NULL) - *out_dir = dirs[i]; - return true; - } - } - - return false; -} - -void -wrap_tile_coords (Map * map, int * x, int * y) -{ - if (map->Flags & 1) { - if (*x < 0) *x += map->Width; - else if (*x >= map->Width) *x -= map->Width; - } - if (map->Flags & 2) { - if (*y < 0) *y += map->Height; - else if (*y >= map->Height) *y -= map->Height; - } -} - -void -tile_index_to_coords (Map * map, int index, int * out_x, int * out_y) -{ - if ((index >= 0) && (index < map->TileCount)) { - int width = map->Width; - int double_row = index / width, double_row_rem = index % width; - if (double_row_rem < width/2) { - *out_x = 2 * double_row_rem; - *out_y = 2 * double_row; - } else { - *out_x = 1 + 2 * (double_row_rem - width/2); - *out_y = 2 * double_row + 1; - } - } else - *out_x = *out_y = -1; -} - -int -tile_coords_to_index (Map * map, int x, int y) -{ - if ((map == NULL) || (x < 0) || (y < 0) || (x >= map->Width) || (y >= map->Height)) - return -1; - - int width = map->Width; - int row = y / 2; - if ((y & 1) == 0) { - return row * width + (x / 2); - } else { - return row * width + (width / 2) + (x / 2); - } -} - -Tile * -tile_at_index (Map * map, int i) -{ - int x, y; - tile_index_to_coords (map, i, &x, &y); - return tile_at (x, y); -} - -void -get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y) -{ - int dx, dy; - neighbor_index_to_diff (neighbor_index, &dx, &dy); - *out_x = x + dx; - *out_y = y + dy; - wrap_tile_coords (map, out_x, out_y); -} - -Tile * __stdcall -tile_at_city_or_null (City * city_or_null) -{ - if (city_or_null) - return tile_at (city_or_null->Body.X, city_or_null->Body.Y); - else - return p_null_tile; -} - -Unit * -get_unit_ptr (int id) -{ - if ((p_units->Units != NULL) && - (id >= 0) && (id <= p_units->LastIndex)) { - Unit_Body * body = p_units->Units[id].Unit; - if (body != NULL) { - Unit * unit = (Unit *)((char *)body - offsetof (Unit, Body)); - if (unit != NULL) - return unit; - } - } - return NULL; -} - -bool -is_land_transport (Unit * unit) -{ - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - return type->Unit_Class == UTC_Land && type->Transport_Capacity > 0 && ! Unit_has_ability (unit, __, UTA_Army); -} - -bool -is_in_land_transport (Unit * unit) -{ - Unit * container = get_unit_ptr (unit->Body.Container_Unit); - return container != NULL && is_land_transport (container); -} - -// Checks if the unit is inside a transport (either helicopter or land transport) from which it is not allowed to defend according to the mod config. -bool -cannot_defend_inside_transport (Unit * unit) -{ - Unit * container = get_unit_ptr (unit->Body.Container_Unit); - if (container != NULL) { - if ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && is_land_transport (container)) - return true; - - if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return true; - } - return false; -} - -struct unit_tile_iter { - int id; - int item_index; - Unit * unit; -}; - -void -uti_next (struct unit_tile_iter * uti) -{ - if (((p_tile_units->Base.Items == NULL) || (uti->item_index < 0)) || - (uti->item_index > p_tile_units->Base.LastIndex)) { - uti->item_index = -1; - uti->id = p_tile_units->DefaultValue; - } else { - Base_List_Item * item = &p_tile_units->Base.Items[uti->item_index]; - uti->item_index = item->V; - uti->id = (int)item->Object; - } - uti->unit = get_unit_ptr (uti->id); -} - -struct unit_tile_iter -uti_init (Tile * tile) -{ - struct unit_tile_iter tr; - int tile_unit_id = tile->vtable->m40_get_TileUnit_ID (tile); - tr.id = TileUnits_TileUnitID_to_UnitID (p_tile_units, __, tile_unit_id, &tr.item_index); - tr.unit = get_unit_ptr (tr.id); - return tr; -} - -#define FOR_UNITS_ON(uti_name, tile) for (struct unit_tile_iter uti_name = uti_init (tile); uti_name.id != -1; uti_next (&uti_name)) - -bool -tile_has_enemy_unit (Tile * tile, int civ_id) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - if ((civ_id < 0) || (civ_id >= 32)) - return false; - - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit == NULL) || (unit->Body.Container_Unit >= 0)) - continue; - if (unit->Body.CivID == civ_id) - continue; - if (unit->vtable->is_enemy_of_civ (unit, __, civ_id, 0)) - return true; - } - - return false; -} - -struct citizen_iter { - int index; - Citizens * list; - Citizen_Base * ctzn; -}; - -void -ci_next (struct citizen_iter * ci) -{ - while (1) { - ci->index++; - if (ci->index > ci->list->LastIndex) { - ci->ctzn = NULL; - break; - } else { - Citizen_Body * body = ci->list->Items[ci->index].Body; - if ((body != NULL) && ((int)body != offsetof (Citizen_Base, Body))) { - ci->ctzn = (Citizen_Base *)((int)body - offsetof (Citizen_Base, Body)); - break; - } - } - } -} - -struct citizen_iter -ci_init (City * city) -{ - struct citizen_iter tr; - tr.index = -1; - tr.list = &city->Body.Citizens; - tr.ctzn = NULL; - if (city->Body.Citizens.Items != NULL) - ci_next (&tr); - return tr; -} - -#define FOR_CITIZENS_IN(ci_name, city) for (struct citizen_iter ci_name = ci_init (city); (ci_name.list->Items != NULL) && (ci_name.index <= ci.list->LastIndex); ci_next (&ci_name)) - -struct city_of_iter { - int city_id; - int civ_id; - City * city; -}; - -void -coi_next (struct city_of_iter * coi) -{ - coi->city_id++; - while (coi->city_id <= p_cities->LastIndex) { - City_Body * body = p_cities->Cities[coi->city_id].City; - if ((body != NULL) && ((int)body != offsetof (City, Body)) && (body->CivID == coi->civ_id)) { - coi->city = (City *)((char *)body - offsetof (City, Body)); - break; - } - coi->city_id++; - } -} - -struct city_of_iter -coi_init (int civ_id) -{ - struct city_of_iter tr = { .city_id = -1, .civ_id = civ_id, .city = NULL }; - if (p_cities->Cities != NULL) - coi_next (&tr); - else - tr.city_id = p_cities->LastIndex + 1; - return tr; -} - -#define FOR_CITIES_OF(coi_name, civ_id) for (struct city_of_iter coi_name = coi_init (civ_id); coi_name.city_id <= p_cities->LastIndex; coi_next (&coi_name)) - -struct tiles_around_iter { - int center_x, center_y; - int n, num_tiles; - Tile * tile; - int tile_x, tile_y; -}; - -void -tai_next (struct tiles_around_iter * tai) -{ - tai->tile = p_null_tile; - while ((tai->n < tai->num_tiles) && (tai->tile == p_null_tile)) { - tai->n += 1; - int tx, ty; - get_neighbor_coords (&p_bic_data->Map, tai->center_x, tai->center_y, tai->n, &tx, &ty); - if ((tx >= 0) && (tx < p_bic_data->Map.Width) && (ty >= 0) && (ty < p_bic_data->Map.Height)) { - tai->tile = tile_at (tx, ty); - tai->tile_x = tx; - tai->tile_y = ty; - } - } -} - -struct tiles_around_iter -tai_init (int num_tiles, int x, int y) -{ - struct tiles_around_iter tr; - tr.center_x = x; - tr.center_y = y; - tr.n = 0; - tr.num_tiles = num_tiles; - tr.tile = tile_at (x, y); - tr.tile_x = x; - tr.tile_y = y; - return tr; -} - -#define FOR_TILES_AROUND(tai_name, _num_tiles, _x, _y) for (struct tiles_around_iter tai_name = tai_init (_num_tiles, _x, _y); (tai_name.n < tai_name.num_tiles); tai_next (&tai_name)) - -enum work_area_iter_output_type { - WAIO_ANY, - WAIO_DISTRICTS, - WAIO_CITIES, -}; - -struct work_area_iter { - int center_x, center_y; - int n, num_tiles; - int civ_id; - int dx, dy; - int tile_x, tile_y; - Tile * tile; - City * city; - struct district_instance * district_inst; - enum work_area_iter_output_type output_type; - bool completed_districts_only; -}; - -void -wai_next (struct work_area_iter * wai) -{ - wai->tile = p_null_tile; - wai->district_inst = NULL; - while ((wai->n + 1) < wai->num_tiles) { - wai->n += 1; - patch_ni_to_diff_for_work_area (wai->n, &wai->dx, &wai->dy); - wai->tile_x = wai->center_x + wai->dx; - wai->tile_y = wai->center_y + wai->dy; - wrap_tile_coords (&p_bic_data->Map, &wai->tile_x, &wai->tile_y); - Tile * candidate = tile_at (wai->tile_x, wai->tile_y); - if ((candidate == NULL) || (candidate == p_null_tile)) - continue; - if ((wai->civ_id < 0) || (candidate->vtable->m38_Get_Territory_OwnerID (candidate) != wai->civ_id)) - continue; - if (tile_has_enemy_unit (candidate, wai->civ_id)) - continue; - if (candidate->vtable->m20_Check_Pollution (candidate, __, 0)) - continue; - City * city; - if (wai->output_type == WAIO_CITIES) { - if (candidate->CityID < 0) - continue; - city = get_city_ptr (candidate->vtable->m45_Get_City_ID (candidate)); - if (city == NULL || city->Body.CivID != wai->civ_id) - continue; - } - struct district_instance * inst = get_district_instance (candidate); - if (wai->output_type == WAIO_DISTRICTS) { - if (inst == NULL) - continue; - int district_id = inst->district_id; - if (wai->completed_districts_only && (! district_is_complete (candidate, district_id))) - continue; - } - wai->city = city; - wai->district_inst = inst; - wai->tile = candidate; - break; - } - if (wai->tile == p_null_tile) - wai->n = wai->num_tiles; -} - -struct work_area_iter -wai_init_common (int x, int y, enum work_area_iter_output_type output, bool completed_districts_only) -{ - struct work_area_iter tr; - tr.center_x = x; - tr.center_y = y; - tr.n = -1; - tr.num_tiles = is->workable_tile_count; - Tile * center_tile = tile_at (x, y); - if ((center_tile == NULL) || (center_tile == p_null_tile)) - tr.civ_id = -1; - else - tr.civ_id = center_tile->vtable->m38_Get_Territory_OwnerID (center_tile); - tr.tile = p_null_tile; - tr.district_inst = NULL; - tr.dx = 0; - tr.dy = 0; - tr.tile_x = 0; - tr.tile_y = 0; - tr.output_type = output; - tr.completed_districts_only = completed_districts_only; - wai_next (&tr); - return tr; -} - -struct work_area_iter -wai_init (int x, int y) -{ - return wai_init_common (x, y, false, false); -} - -struct work_area_iter -wai_init_districts (int x, int y, bool completed_only) -{ - return wai_init_common (x, y, WAIO_DISTRICTS, completed_only); -} - -struct work_area_iter -wai_init_cities (int x, int y) -{ - struct work_area_iter tr = wai_init_common (x, y, WAIO_CITIES, false); - return tr; -} - -#define FOR_WORK_AREA_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) -#define FOR_DISTRICTS_AROUND(wai_name, _x, _y, _completed_only) for (struct work_area_iter wai_name = wai_init_districts (_x, _y, _completed_only); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) -#define FOR_CITIES_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init_cities (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) -#define FOR_AERODROMES_AROUND(unit_ptr) \ - for (struct table_entry_iter _tei = tei_init (&is->district_tile_map); \ - _tei.index < _tei.capacity; \ - tei_next (&_tei)) \ - for (Tile * aerodrome_tile = (Tile *)_tei.key; \ - (aerodrome_tile != NULL) && (aerodrome_tile != p_null_tile); \ - aerodrome_tile = NULL) \ - for (struct district_instance * aerodrome_inst = (struct district_instance *)_tei.value; \ - (aerodrome_inst != NULL) && \ - (aerodrome_inst->district_id == AERODROME_DISTRICT_ID) && \ - district_is_complete (aerodrome_tile, AERODROME_DISTRICT_ID); \ - aerodrome_inst = NULL) \ - for (int aerodrome_x = 0, aerodrome_y = 0; \ - district_instance_get_coords (aerodrome_inst, aerodrome_tile, &aerodrome_x, &aerodrome_y) && \ - (aerodrome_tile->vtable->m38_Get_Territory_OwnerID (aerodrome_tile) == (unit_ptr)->Body.CivID) && \ - patch_Unit_is_in_rebase_range ((unit_ptr), __, aerodrome_x, aerodrome_y); \ - aerodrome_x = 0, aerodrome_y = 0) - -struct tile_rings_iter { - int center_x, center_y; - int const * rings; - int ring_count; - int r_idx; - int ni; - int tile_x, tile_y; - int current_ring; - Tile * tile; -}; - -void -tri_next (struct tile_rings_iter * tri) -{ - tri->tile = p_null_tile; - while (tri->r_idx < tri->ring_count) { - int ring_no = tri->rings[tri->r_idx]; - if ((ring_no <= 0) || (ring_no >= 8)) { - tri->r_idx += 1; - tri->ni = -1; - continue; - } - int start_ni = workable_tile_counts[ring_no - 1]; - int end_ni = workable_tile_counts[ring_no]; - if (tri->ni < start_ni) - tri->ni = start_ni; - else if ((tri->ni + 1) < end_ni) - tri->ni += 1; - else { - tri->r_idx += 1; - tri->ni = -1; - continue; - } - tri->current_ring = ring_no; - int dx, dy; - patch_ni_to_diff_for_work_area (tri->ni, &dx, &dy); - int tx = tri->center_x + dx; - int ty = tri->center_y + dy; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - tri->tile_x = tx; - tri->tile_y = ty; - Tile * candidate = tile_at (tx, ty); - if ((candidate == NULL) || (candidate == p_null_tile)) - continue; - tri->tile = candidate; - break; - } - if (tri->tile == p_null_tile) { - tri->r_idx = tri->ring_count; - tri->ni = -1; - } -} - -struct tile_rings_iter -tri_init (int x, int y, int const * rings, int ring_count) -{ - struct tile_rings_iter tr; - tr.center_x = x; - tr.center_y = y; - tr.rings = rings; - tr.ring_count = ring_count; - tr.r_idx = 0; - tr.ni = -1; - tr.tile_x = 0; - tr.tile_y = 0; - tr.current_ring = 0; - tr.tile = p_null_tile; - tri_next (&tr); - return tr; -} - -#define FOR_TILE_RINGS_AROUND(tri_name, _x, _y, _rings, _ring_count) for (struct tile_rings_iter tri_name = tri_init (_x, _y, _rings, _ring_count); (tri_name.r_idx < tri_name.ring_count); tri_next (&tri_name)) - -bool -tile_square_type_is (Tile * tile, enum SquareTypes type) -{ - return tile_matches_square_type (tile, type); -} - -bool -district_is_buildable_on_tile (struct district_config const * cfg, Tile * tile) -{ - if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - unsigned int mask = cfg->buildable_square_types_mask; - if (mask == 0) - mask = district_default_buildable_mask (); - - bool square_matches = tile_matches_square_type_mask (tile, mask); - bool overlay_allowed = false; - bool overlay_required = false; - - if (cfg->has_buildable_without_removal) - overlay_allowed = tile_matches_overlay_mask (tile, cfg->buildable_without_removal_mask); - - if (cfg->has_buildable_on_overlays) { - overlay_required = tile_matches_overlay_mask (tile, cfg->buildable_on_overlays_mask); - if (! overlay_required) - return false; - } - if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) - return false; - - if (! square_matches && ! overlay_allowed && ! overlay_required) - return false; - - if (cfg->has_buildable_on_districts) { - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - - int existing_district_id = inst->district_id; - if (! district_is_complete (tile, existing_district_id)) - return false; - - bool matches = false; - for (int i = 0; i < cfg->buildable_on_district_id_count; i++) { - if (cfg->buildable_on_district_ids[i] == existing_district_id) { - matches = true; - break; - } - } - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to || cfg->has_buildable_adjacent_to_districts || cfg->has_buildable_adjacent_to_overlays) { - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - return false; - - if (cfg->has_buildable_adjacent_to) { - bool matches = false; - bool city_adjacent = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (Tile_has_city (tai.tile)) { - city_adjacent = true; - if (cfg->buildable_adjacent_to_allows_city) - matches = true; - } - if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) - matches = true; - if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) - break; - } - if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) - return false; - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to_overlays) { - bool matches = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { - matches = true; - break; - } - } - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to_districts) { - bool matches = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - struct district_instance * adj_inst = get_district_instance (tai.tile); - if (adj_inst == NULL) - continue; - int adj_district_id = adj_inst->district_id; - if (! district_is_complete (tai.tile, adj_district_id)) - continue; - for (int i = 0; i < cfg->buildable_adjacent_to_district_id_count; i++) { - if (cfg->buildable_adjacent_to_district_ids[i] == adj_district_id) { - matches = true; - break; - } - } - if (matches) - break; - } - if (! matches) - return false; - } - } - - return true; -} - -bool -is_coastal_island (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile->vtable->m35_Check_Is_Water (tile)) - return false; - - bool has_neighbor = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - return false; - - has_neighbor = true; - if (! adj->vtable->m35_Check_Is_Water (adj)) - return false; - - if (adj->vtable->m50_Get_Square_BaseType (adj) != SQ_Coast) - return false; - } - - return has_neighbor; -} - -bool -natural_wonder_adjacent_requirement_met (struct natural_wonder_district_config const * cfg, - Tile * tile, - int tile_x, - int tile_y) -{ - enum SquareTypes required = cfg->adjacent_to; - if (required == (enum SquareTypes)SQ_INVALID) - return true; - - if (required == SQ_RIVER) { - char river_bits = tile->vtable->m37_Get_River_Code (tile); - if (cfg->adjacency_dir != DIR_ZERO) { - int bit = direction_to_neighbor_bit (cfg->adjacency_dir); - if (bit < 0) - return false; - return (river_bits & (1 << bit)) != 0; - } else - return river_bits != 0; - } - - if (cfg->adjacency_dir != DIR_ZERO) { - int dx, dy; - if (! direction_to_offset (cfg->adjacency_dir, &dx, &dy)) - return false; - int nx = tile_x + dx; - int ny = tile_y + dy; - wrap_tile_coords (&p_bic_data->Map, &nx, &ny); - Tile * neighbor = tile_at (nx, ny); - return tile_square_type_is (neighbor, required); - } - - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_square_type_is (tai.tile, required)) - return true; - } - - return false; -} - -int -count_diagonal_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) -{ - if (type == (enum SquareTypes)SQ_INVALID) - return 0; - - enum direction dirs[4] = {DIR_NE, DIR_NW, DIR_SE, DIR_SW}; - int count = 0; - for (int i = 0; i < 4; i++) { - int dx, dy; - if (! direction_to_offset (dirs[i], &dx, &dy)) - continue; - int nx = tile_x + dx; - int ny = tile_y + dy; - wrap_tile_coords (&p_bic_data->Map, &nx, &ny); - Tile * neighbor = tile_at (nx, ny); - if (tile_square_type_is (neighbor, type)) - count += 1; - } - return count; -} - -int -count_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) -{ - if (type == (enum SquareTypes)SQ_INVALID) - return 0; - - int count = 0; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_square_type_is (tai.tile, type)) - count += 1; - } - return count; -} - -bool -natural_wonder_terrain_matches (struct natural_wonder_district_config const * cfg, Tile * tile, int tile_x, int tile_y) -{ - if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - if (! tile_matches_square_type (tile, cfg->terrain_type)) - return false; - - if (cfg->terrain_type == SQ_Coast) { - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - return false; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - if ((continent == NULL) || (continent->Body.TileCount <= 5)) - return false; - } - - if (is_coastal_island (tile, tile_x, tile_y)) - return false; - - if ((cfg->adjacent_to != SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 0)) - return false; - - if ((cfg->adjacent_to == SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 4)) - return false; - - if (! natural_wonder_adjacent_requirement_met (cfg, tile, tile_x, tile_y)) - return false; - - return true; -} - -struct district_worker_record * -get_tracked_worker_record (Unit * worker) -{ - if (worker == NULL) return NULL; - int civ_id = worker->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) return NULL; - - int value; - if (itable_look_up (&is->district_worker_tables[civ_id], worker->Body.ID, &value)) - return (struct district_worker_record *)value; - return NULL; -} - -struct district_worker_record * -ensure_tracked_worker_record (Unit * worker) -{ - if (worker == NULL) return NULL; - int civ_id = worker->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) return NULL; - - struct district_worker_record * rec = get_tracked_worker_record (worker); - if (rec != NULL) return rec; - - rec = (struct district_worker_record *)calloc (1, sizeof *rec); - if (rec == NULL) return NULL; - - rec->worker = worker; - rec->unit_id = worker->Body.ID; - Tile * tile = tile_at (worker->Body.X, worker->Body.Y); - rec->continent_id = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m46_Get_ContinentID (tile) : -1; - rec->pending_req = NULL; - - itable_insert (&is->district_worker_tables[civ_id], worker->Body.ID, (int)rec); - return rec; -} - -void -remove_tracked_worker_record (int civ_id, int unit_id) -{ - if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) - return; - - int value; - if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) - return; - - struct district_worker_record * rec = (struct district_worker_record *)value; - if (rec->pending_req != NULL) { - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - } - - itable_remove (&is->district_worker_tables[civ_id], unit_id); - free (rec); -} - -void -clear_tracked_worker_assignment (struct district_worker_record * rec) -{ - if (rec == NULL) - return; - - if (rec->pending_req != NULL) { - if (rec->pending_req->assigned_worker_id == rec->unit_id) - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - } -} - -void -clear_tracked_worker_assignment_by_id (int civ_id, int unit_id) -{ - if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) - return; - - int value; - if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) - return; - - struct district_worker_record * rec = (struct district_worker_record *)value; - if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == unit_id)) - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - if ((rec->worker == NULL) || (get_unit_ptr (unit_id) == NULL)) - remove_tracked_worker_record (civ_id, unit_id); -} - -void -clear_all_tracked_workers (void) -{ - for (int civ = 0; civ < 32; civ++) { - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - if (rec == NULL) - continue; - if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == rec->unit_id)) - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - free (rec); - } - is->district_worker_tables[civ].len = 0; - if (is->district_worker_tables[civ].block != NULL) { - free (is->district_worker_tables[civ].block); - is->district_worker_tables[civ].block = NULL; - } - is->district_worker_tables[civ].capacity_exponent = 0; - } -} - -bool is_worker (Unit * unit) -{ - if (unit == NULL) - return false; - - int unit_type_id = unit->Body.UnitTypeID; - int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; - - if (worker_actions == 0 || !(worker_actions & (UCV_Build_Road | UCV_Build_Mine | UCV_Irrigate))) { - return false; - } - - return true; -} - -void -update_tracked_worker_for_unit (Unit * worker) -{ - if (worker == NULL || ! is->current_config.enable_districts) return; - - int civ_id = worker->Body.CivID; - int type_id = worker->Body.UnitTypeID; - if ((civ_id < 0) || (civ_id >= 32)) return; - if ((*p_human_player_bits & (1 << civ_id)) != 0) return; - - char ss[200]; - snprintf (ss, sizeof ss, "Updating tracked worker for unit %d of type %d\n", worker->Body.ID, type_id); - (*p_OutputDebugStringA) (ss); - - if (! is_worker (worker)) { - remove_tracked_worker_record(worker->Body.CivID, worker->Body.ID); - return; - } - - ensure_tracked_worker_record (worker); -} - -bool -assign_worker_to_district (struct pending_district_request * req, Unit * worker, City * city, int district_id, int tile_x, int tile_y) -{ - if (worker == NULL || city == NULL) - return false; - if (req == NULL) - return false; - - req->city = city; - req->city_id = city->Body.ID; - req->civ_id = city->Body.CivID; - req->assigned_worker_id = worker->Body.ID; - req->worker_assigned_turn = *p_current_turn_no; - req->target_x = tile_x; - req->target_y = tile_y; - worker->Body.Auto_CityID = city->Body.ID; - - char ss[200]; - snprintf (ss, sizeof ss, "assign_worker_to_district: Assigned worker unit %d to build district %d in city %s at (%d,%d)\n", - worker->Body.ID, district_id, city->Body.CityName, tile_x, tile_y); - (*p_OutputDebugStringA) (ss); - - struct district_worker_record * record = ensure_tracked_worker_record (worker); - if (record != NULL) { - record->pending_req = req; - } - - return ai_move_district_worker (worker, record); -} - -bool -worker_is_available_for_district (Unit * worker) -{ - if (worker == NULL) - return false; - - int civ_id = worker->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) return false; - if ((*p_human_player_bits & (1 << civ_id)) != 0) return false; - - int type_id = worker->Body.UnitTypeID; - if ((type_id < 0) || (type_id >= p_bic_data->UnitTypeCount)) return false; - - struct district_worker_record * record = get_tracked_worker_record (worker); - if (record == NULL) - return false; - - return record->pending_req == NULL; -} - -Unit * -find_best_worker_for_district (Leader * leader, City * city, int district_id, int target_x, int target_y) -{ - char ss[200]; - - if ((leader == NULL) || (city == NULL)) { - snprintf (ss, sizeof ss, "Invalid leader or city when finding best worker for district %d\n", district_id); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - int civ_id = leader->ID; - if ((civ_id < 0) || (civ_id >= 32)) { - snprintf (ss, sizeof ss, "Invalid civ_id %d when finding best worker for district %d\n", civ_id, district_id); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - if (is->district_worker_tables[civ_id].len == 0) { - snprintf (ss, sizeof ss, "No tracked workers for civ %d when finding best worker for district %d\n", civ_id, district_id); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - Tile * target_tile = tile_at (target_x, target_y); - if ((target_tile == NULL) || (target_tile == p_null_tile)) { - snprintf (ss, sizeof ss, "Invalid target tile (%d,%d) when finding best worker for district %d in city %s\n", - target_x, target_y, district_id, city->Body.CityName); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - int target_continent_id = target_tile->vtable->m46_Get_ContinentID (target_tile); - Unit * best_worker = NULL; - int best_dist = INT_MAX; - - snprintf (ss, sizeof ss, "Finding best worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); - (*p_OutputDebugStringA) (ss); - - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - - if (rec == NULL) { - continue; - } - - Unit * candidate_worker = get_unit_ptr (rec->unit_id); - if ((candidate_worker == NULL) || (candidate_worker->Body.CivID != civ_id)) { - remove_tracked_worker_record (civ_id, rec->unit_id); - continue; - } - rec->worker = candidate_worker; - - if (! worker_is_available_for_district (candidate_worker)) { - continue; - } - - Tile * worker_tile = tile_at (candidate_worker->Body.X, candidate_worker->Body.Y); - if ((worker_tile == NULL) || (worker_tile == p_null_tile)) { - continue; - } - - int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); - if ((target_continent_id >= 0) && (worker_continent_id != target_continent_id)) { - continue; - } - - int dist = compute_wrapped_chebyshev_distance (candidate_worker->Body.X, candidate_worker->Body.Y, target_x, target_y); - - if (dist < best_dist) { - best_worker = candidate_worker; - best_dist = dist; - if (dist == 0) - return best_worker; - } - } - - return best_worker; -} - -void -process_pending_district_request (Leader * leader, struct pending_district_request * req) -{ - if ((leader == NULL) || (req == NULL)) - return; - - City * city = get_city_ptr (req->city_id); - if (city == NULL) { - remove_pending_district_request (req); - return; - } - req->city = city; - - int district_id = req->district_id; - int civ_id = req->civ_id; - - if (city->Body.CivID != civ_id) { - clear_city_district_request (city, district_id); - return; - } - - if (district_id < 0 || district_id >= is->district_count) return; - - // Check if city already has the district if not a neighborhood or distribution hub - if (district_id != NEIGHBORHOOD_DISTRICT_ID && - district_id != DISTRIBUTION_HUB_DISTRICT_ID && - is->district_configs[district_id].allow_multiple == false && - city_has_required_district (city, district_id)) { - - // Clear the request - clear_city_district_request (city, district_id); - return; - } - - // Assigned worker is no longer valid; clear assignment - if (req->assigned_worker_id >= 0) { - Unit * assigned = get_unit_ptr (req->assigned_worker_id); - if (assigned != NULL) { - // Check if more than allowed turns have elapsed since assignment and worker is not at target tile - bool worker_at_target = (assigned->Body.X == req->target_x) && (assigned->Body.Y == req->target_y); - if ((*p_current_turn_no - req->worker_assigned_turn) > is->current_config.ai_city_district_max_build_wait_turns && !worker_at_target) { - clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); - req->assigned_worker_id = -1; - req->worker_assigned_turn = *p_current_turn_no; - } else { - return; - } - } else { - // Assigned worker is null, make sure we get a new one - clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); - req->assigned_worker_id = -1; - } - } - - struct district_instance * inst = NULL; - int target_x = 0; - int target_y = 0; - Tile * tile = find_tile_for_district (city, district_id, &target_x, &target_y); - if ((tile == NULL) || (tile == p_null_tile)) { - clear_city_district_request (city, district_id); - return; - } - wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); - - char ss[200]; - snprintf (ss, sizeof ss, "Assigning worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); - (*p_OutputDebugStringA) (ss); - - Unit * worker = find_best_worker_for_district (leader, city, district_id, target_x, target_y); - if (worker == NULL) - return; - - snprintf (ss, sizeof ss, "Found worker %d for district %d in city %s at (%d,%d)\n", - worker->Body.ID, district_id, city->Body.CityName, target_x, target_y); - (*p_OutputDebugStringA) (ss); - - assign_worker_to_district (req, worker, city, district_id, target_x, target_y); -} - -void -assign_workers_for_pending_districts (Leader * leader) -{ - if ((leader == NULL) || ! is->current_config.enable_districts) - return; - - int civ_id = leader->ID; - if ((civ_id < 0) || (civ_id >= 32)) - return; - - if ((*p_human_player_bits & (1 << civ_id)) != 0) - return; - - int pending_count = is->city_pending_district_requests[civ_id].len; - if (pending_count <= 0) - return; - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req == NULL) - continue; - - City * city = get_city_ptr (req->city_id); - if (city == NULL) { - remove_pending_district_request (req); - continue; - } - - req->city = city; - if (city->Body.CivID != req->civ_id) { - remove_pending_district_request (req); - continue; - } - - process_pending_district_request (leader, req); - } -} - -City * -find_closest_owned_city_for_tile (int civ_id, int tile_x, int tile_y) -{ - City * best_city = NULL; - int best_dist = INT_MAX; - - FOR_CITIES_OF (coi, civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - - int dist = compute_wrapped_chebyshev_distance (city->Body.X, city->Body.Y, tile_x, tile_y); - if (dist < best_dist) { - best_dist = dist; - best_city = city; - } - } - - return best_city; -} - -bool -ai_candidate_bridge_or_canal_is_buildable_for_civ (struct ai_candidate_bridge_or_canal_entry * entry, int civ_id, int * out_tile_index) -{ - if ((entry == NULL) || (entry->tile_count <= 0)) - return false; - - int pending_index = -1; - for (int ti = 0; ti < entry->tile_count; ti++) { - int tx = entry->tile_x[ti]; - int ty = entry->tile_y[ti]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (owner != civ_id) - return false; - if (tile->CityID >= 0) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - if (inst->district_id == entry->district_id) - continue; - if (inst->district_id == WONDER_DISTRICT_ID) - return false; - if (! is->current_config.ai_can_replace_existing_districts_with_canals) { - return false; - } - } - - if (pending_index < 0) - pending_index = ti; - } - - if (pending_index < 0) { - entry->completed = true; - return false; - } - - if (out_tile_index != NULL) - *out_tile_index = pending_index; - - return true; -} - -void -release_ai_candidate_bridge_or_canal_worker (struct ai_candidate_bridge_or_canal_entry * entry) -{ - if ((entry == NULL) || (entry->assigned_worker_id < 0)) - return; - - int civ_id = entry->pending_req.civ_id; - if ((civ_id >= 0) && (civ_id < 32)) - clear_tracked_worker_assignment_by_id (civ_id, entry->assigned_worker_id); - - entry->assigned_worker_id = -1; - entry->assigned_tile_index = -1; - entry->pending_req.city = NULL; - entry->pending_req.city_id = -1; - entry->pending_req.civ_id = -1; - entry->pending_req.district_id = -1; - entry->pending_req.assigned_worker_id = -1; - entry->pending_req.target_x = -1; - entry->pending_req.target_y = -1; - entry->pending_req.worker_assigned_turn = 0; -} - -void -reset_ai_candidate_bridge_or_canals (void) -{ - if (is->ai_candidate_bridge_or_canals != NULL) { - for (int i = 0; i < is->ai_candidate_bridge_or_canals_capacity; i++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[i]; - if (entry->tile_x != NULL) - free (entry->tile_x); - if (entry->tile_y != NULL) - free (entry->tile_y); - } - free (is->ai_candidate_bridge_or_canals); - is->ai_candidate_bridge_or_canals = NULL; - } - is->ai_candidate_bridge_or_canals_capacity = 0; - is->ai_candidate_bridge_or_canals_count = 0; - is->ai_candidate_bridge_or_canals_initialized = false; -} - -bool -tile_has_district_at (int tile_x, int tile_y, int district_id) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - return (inst != NULL) && (inst->district_id == district_id) && (district_is_complete (tile, district_id)); -} - -bool -tile_is_land (int civ_id, int tile_x, int tile_y, bool must_be_same_owner) -{ - if (must_be_same_owner && (civ_id <= 0)) - return false; - - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - return (tile != NULL) && (tile != p_null_tile) && (! tile->vtable->m35_Check_Is_Water (tile)) && - ((! must_be_same_owner) || (tile->Territory_OwnerID == civ_id)); -} - -bool -tile_is_water (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - return (tile != NULL) && (tile != p_null_tile) && (tile->vtable->m35_Check_Is_Water (tile)); -} - -bool -ensure_ai_candidate_bridge_or_canals_capacity (int required) -{ - if (required <= 0) - return true; - if (required <= is->ai_candidate_bridge_or_canals_capacity) - return true; - int new_capacity = (is->ai_candidate_bridge_or_canals_capacity > 0) ? is->ai_candidate_bridge_or_canals_capacity * 2 : 4; - if (new_capacity < required) - new_capacity = required; - struct ai_candidate_bridge_or_canal_entry * larger = (struct ai_candidate_bridge_or_canal_entry *)realloc ( - is->ai_candidate_bridge_or_canals, new_capacity * sizeof *larger); - if (larger == NULL) - return false; - for (int i = is->ai_candidate_bridge_or_canals_capacity; i < new_capacity; i++) { - struct ai_candidate_bridge_or_canal_entry * entry = &larger[i]; - entry->tile_x = NULL; - entry->tile_y = NULL; - entry->tile_capacity = 0; - entry->district_id = -1; - entry->owner_civ_id = -1; - entry->tile_count = 0; - entry->assigned_tile_index = -1; - entry->assigned_worker_id = -1; - entry->completed = false; - struct pending_district_request * req = &entry->pending_req; - req->city = NULL; - req->city_id = -1; - req->civ_id = -1; - req->district_id = -1; - req->assigned_worker_id = -1; - req->target_x = -1; - req->target_y = -1; - req->worker_assigned_turn = 0; - } - is->ai_candidate_bridge_or_canals = larger; - is->ai_candidate_bridge_or_canals_capacity = new_capacity; - return true; -} - -bool -canal_has_different_adjacent_seas (int tile_x, int tile_y, int civ_id) -{ - struct water_pair { - int dx1, dy1; - int dx2, dy2; - }; - - const struct water_pair pairs[] = { - { 1, -1, -1, 1 }, // NE + SW - { 1, 1, -1, -1 }, // SE + NW - }; - - Map * map = &p_bic_data->Map; - bool require_owner = (civ_id >= 0); - - for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { - int ax = tile_x + pairs[i].dx1; - int ay = tile_y + pairs[i].dy1; - wrap_tile_coords (map, &ax, &ay); - Tile * first = tile_at (ax, ay); - if ((first == NULL) || (first == p_null_tile)) - continue; - if (! first->vtable->m35_Check_Is_Water (first)) - continue; - if (require_owner && (first->vtable->m38_Get_Territory_OwnerID (first) != civ_id)) - continue; - - int bx = tile_x + pairs[i].dx2; - int by = tile_y + pairs[i].dy2; - wrap_tile_coords (map, &bx, &by); - Tile * second = tile_at (bx, by); - if ((second == NULL) || (second == p_null_tile)) - continue; - if (! second->vtable->m35_Check_Is_Water (second)) - continue; - if (require_owner && (second->vtable->m38_Get_Territory_OwnerID (second) != civ_id)) - continue; - - int sea_a = first->vtable->m46_Get_ContinentID (first); - int sea_b = second->vtable->m46_Get_ContinentID (second); - if ((sea_a >= 0) && (sea_b >= 0) && (sea_a != sea_b)) - return true; - } - - return false; -} - -// Check if two water tiles can reach each other via water within a radius, excluding a blocked tile -bool -water_tiles_connected_within_radius (int start_x, int start_y, int target_x, int target_y, int block_x, int block_y, int radius) -{ - // Simple BFS using a fixed-size visited array for tiles within radius - // workable_tile_counts[6] = 137 tiles for radius 6 - int max_tiles = 137; - int visited_x[137]; - int visited_y[137]; - int visited_count = 0; - int queue_x[137]; - int queue_y[137]; - int queue_head = 0; - int queue_tail = 0; - - queue_x[queue_tail] = start_x; - queue_y[queue_tail] = start_y; - queue_tail++; - visited_x[visited_count] = start_x; - visited_y[visited_count] = start_y; - visited_count++; - - while (queue_head < queue_tail) { - int cx = queue_x[queue_head]; - int cy = queue_y[queue_head]; - queue_head++; - - // Check 8 adjacent tiles - FOR_TILES_AROUND (tai, 9, cx, cy) { - if (tai.n == 0) - continue; - int nx = tai.tile_x; - int ny = tai.tile_y; - - // Found target - if (nx == target_x && ny == target_y) - return true; - - // Skip blocked tile (the isthmus) - if (nx == block_x && ny == block_y) - continue; - - // Check if within radius of original start - int dx = nx - start_x; - int dy = ny - start_y; - if (dx < 0) dx = -dx; - if (dy < 0) dy = -dy; - // Use Chebyshev distance approximation for hex grid - int dist = (dx + dy + ((dx > dy) ? dx : dy)) / 2; - if (dist > radius) - continue; - - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (! adj->vtable->m35_Check_Is_Water (adj)) - continue; - - // Check if already visited - bool already_visited = false; - for (int i = 0; i < visited_count; i++) { - if (visited_x[i] == nx && visited_y[i] == ny) { - already_visited = true; - break; - } - } - if (already_visited) - continue; - - // Add to queue and visited - if (visited_count < max_tiles && queue_tail < max_tiles) { - visited_x[visited_count] = nx; - visited_y[visited_count] = ny; - visited_count++; - queue_x[queue_tail] = nx; - queue_y[queue_tail] = ny; - queue_tail++; - } - } - } - return false; -} - -// Check if tile separates adjacent water tiles that are not connected within a small radius -bool -canal_has_same_sea_isthmus (int tile_x, int tile_y, int civ_id, int check_radius) -{ - // If another canal exists nearby, this isn't a unique isthmus target. - FOR_TILES_AROUND (tai, workable_tile_counts[2], tile_x, tile_y) { - if (tai.n == 0) - continue; - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - continue; - struct district_instance * adj_inst = get_district_instance (adj); - if ((adj_inst != NULL) && (adj_inst->district_id == CANAL_DISTRICT_ID)) - return false; - } - - // Check opposite diagonal water tiles that are not connected within radius 2 - struct water_pair { - int dx1, dy1; - int dx2, dy2; - }; - - const struct water_pair pairs[] = { - { 1, -1, -1, 1 }, // NE + SW - { 1, 1, -1, -1 }, // SE + NW - }; - - for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { - int ax = tile_x + pairs[i].dx1; - int ay = tile_y + pairs[i].dy1; - wrap_tile_coords (&p_bic_data->Map, &ax, &ay); - Tile * first = tile_at (ax, ay); - if ((first == NULL) || (first == p_null_tile)) - continue; - if (! first->vtable->m35_Check_Is_Water (first)) - continue; - - int bx = tile_x + pairs[i].dx2; - int by = tile_y + pairs[i].dy2; - wrap_tile_coords (&p_bic_data->Map, &bx, &by); - Tile * second = tile_at (bx, by); - if ((second == NULL) || (second == p_null_tile)) - continue; - if (! second->vtable->m35_Check_Is_Water (second)) - continue; - - if (! water_tiles_connected_within_radius ( - ax, ay, - bx, by, - tile_x, tile_y, 2)) { - return true; - } - } - return false; -} - -bool -bridge_tile_connects_two_continents (int tile_x, int tile_y, int civ_id) -{ - struct bridge_pair { - int dx1, dy1; - int dx2, dy2; - }; - - Map * map = &p_bic_data->Map; - const struct bridge_pair pairs[] = { - {0, -2, 0, 2}, - {-2, 0, 2, 0}, - {-1, -1, 1, 1}, - {-1, 1, 1, -1}, - }; - - bool require_owner = (civ_id >= 0); - - for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { - int ax = tile_x + pairs[i].dx1; - int ay = tile_y + pairs[i].dy1; - wrap_tile_coords (map, &ax, &ay); - if (! tile_is_land (civ_id, ax, ay, require_owner)) - continue; - Tile * first = tile_at (ax, ay); - if ((first == NULL) || (first == p_null_tile)) - continue; - - int bx = tile_x + pairs[i].dx2; - int by = tile_y + pairs[i].dy2; - wrap_tile_coords (map, &bx, &by); - if (! tile_is_land (civ_id, bx, by, require_owner)) - continue; - Tile * second = tile_at (bx, by); - if ((second == NULL) || (second == p_null_tile)) - continue; - - int cont_a = first->vtable->m46_Get_ContinentID (first); - int cont_b = second->vtable->m46_Get_ContinentID (second); - if ((cont_a >= 0) && (cont_b >= 0) && (cont_a != cont_b)) - return true; - } - - return false; -} - -bool -tile_point_in_block (int tile_x, int tile_y, int block_x0, int block_y0, int block_x1, int block_y1) -{ - return (tile_x >= block_x0) && (tile_x < block_x1) && (tile_y >= block_y0) && (tile_y < block_y1); -} - -bool -tile_is_coastal_water (int tile_x, int tile_y) -{ - Map * map = &p_bic_data->Map; - wrap_tile_coords (map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - if (! tile->vtable->m35_Check_Is_Water (tile)) - return false; - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - return base_type == SQ_Coast; -} - -bool -tile_exists_at (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - return (tile != NULL) && (tile != p_null_tile); -} - -bool -tile_is_reserved_in_district_tile_map (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - int existing = 0; - return itable_look_up (&is->district_tile_map, (int)tile, &existing); -} - -bool -tile_has_diagonal_water (int tile_x, int tile_y) -{ - Map * map = &p_bic_data->Map; - int const adj_dx[4] = { 1, 1, -1, -1 }; - int const adj_dy[4] = { -1, 1, -1, 1 }; - - for (int i = 0; i < 4; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * tile = tile_at (nx, ny); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m35_Check_Is_Water (tile)) - return true; - } - return false; -} - -bool -tile_part_of_existing_candidate (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if (entry->tile_count <= 0) - continue; - for (int ti = 0; ti < entry->tile_count; ti++) { - if ((entry->tile_x[ti] == tile_x) && (entry->tile_y[ti] == tile_y)) - return true; - } - } - return false; -} - -bool -tile_has_bridge_or_canal_nearby (int tile_x, int tile_y) -{ - FOR_TILES_AROUND (tai, workable_tile_counts[1], tile_x, tile_y) { - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - continue; - struct district_instance * inst = get_district_instance (adj); - if ((inst != NULL) && - ((inst->district_id == BRIDGE_DISTRICT_ID) || (inst->district_id == CANAL_DISTRICT_ID))) - return true; - if (tile_part_of_existing_candidate (tai.tile_x, tai.tile_y)) - return true; - } - return false; -} - -bool -add_ai_candidate_entry (int district_id, short owner_civ_id, short * xs, short * ys, int count) -{ - if (count <= 0) - return false; - if (! ensure_ai_candidate_bridge_or_canals_capacity (is->ai_candidate_bridge_or_canals_count + 1)) - return false; - - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[is->ai_candidate_bridge_or_canals_count]; - entry->tile_x = (short *)malloc (sizeof *entry->tile_x * count); - entry->tile_y = (short *)malloc (sizeof *entry->tile_y * count); - if ((entry->tile_x == NULL) || (entry->tile_y == NULL)) { - if (entry->tile_x != NULL) - free (entry->tile_x); - if (entry->tile_y != NULL) - free (entry->tile_y); - return false; - } - - entry->district_id = district_id; - entry->owner_civ_id = owner_civ_id; - entry->tile_count = (short)count; - entry->tile_capacity = count; - entry->assigned_tile_index = -1; - entry->assigned_worker_id = -1; - entry->completed = false; - for (int ti = 0; ti < count; ti++) { - entry->tile_x[ti] = xs[ti]; - entry->tile_y[ti] = ys[ti]; - } - - struct pending_district_request * req = &entry->pending_req; - req->city = NULL; - req->city_id = -1; - req->civ_id = owner_civ_id; - req->district_id = district_id; - req->assigned_worker_id = -1; - req->target_x = -1; - req->target_y = -1; - req->worker_assigned_turn = 0; - - is->ai_candidate_bridge_or_canals_count++; - return true; -} - -int -find_bridge_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, - int contiguous_limit, int candidate_capacity, - short * out_x, short * out_y, short * out_owner) -{ - const int dirs[4][2] = { - { 0, -2 }, { -2, 0 }, { -1, -1 }, { -1, 1 } - }; - - int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - if (candidate_capacity > 0 && max_len > candidate_capacity) - max_len = candidate_capacity; - - for (int length = 1; length <= max_len; length++) { - for (int ti = 0; ti < map->TileCount; ti++) { - int tx = -1; - int ty = -1; - tile_index_to_coords (map, ti, &tx, &ty); - if (! tile_point_in_block (tx, ty, block_x0, block_y0, block_x1, block_y1)) - continue; - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile_has_resource (tile)) - continue; - if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], tile)) - continue; - if (tile_is_reserved_in_district_tile_map (tx, ty)) - continue; - short owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - for (int di = 0; di < (int)(sizeof (dirs) / sizeof (dirs[0])); di++) { - int dx = dirs[di][0]; - int dy = dirs[di][1]; - int end_x = tx + dx * (length - 1); - int end_y = ty + dy * (length - 1); - wrap_tile_coords (map, &end_x, &end_y); - if (! tile_point_in_block (end_x, end_y, block_x0, block_y0, block_x1, block_y1)) - continue; - - bool ok = true; - for (int step = 0; step < length; step++) { - int cx = tx + dx * step; - int cy = ty + dy * step; - wrap_tile_coords (map, &cx, &cy); - if (! tile_point_in_block (cx, cy, block_x0, block_y0, block_x1, block_y1)) { - ok = false; - break; - } - if (! tile_exists_at (cx, cy)) { - ok = false; - break; - } - if (! tile_is_coastal_water (cx, cy)) { - ok = false; - break; - } - Tile * bridge_tile = tile_at (cx, cy); - if ((bridge_tile == NULL) || (bridge_tile == p_null_tile)) { - ok = false; - break; - } - if (tile_has_resource (bridge_tile)) { - ok = false; - break; - } - if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], bridge_tile)) { - ok = false; - break; - } - if (tile_has_bridge_or_canal_nearby (cx, cy)) { - ok = false; - break; - } - if (tile_is_reserved_in_district_tile_map (cx, cy)) { - ok = false; - break; - } - if (tile_part_of_existing_candidate (cx, cy)) { - ok = false; - break; - } - } - if (! ok) - continue; - - int land_ax = tx - dx; - int land_ay = ty - dy; - wrap_tile_coords (map, &land_ax, &land_ay); - if (! tile_point_in_block (land_ax, land_ay, block_x0, block_y0, block_x1, block_y1)) - continue; - if (! tile_exists_at (land_ax, land_ay)) - continue; - if (! tile_is_land (-1, land_ax, land_ay, false)) - continue; - Tile * land_a = tile_at (land_ax, land_ay); - if ((land_a == NULL) || (land_a == p_null_tile)) - continue; - - int land_bx = tx + dx * length; - int land_by = ty + dy * length; - wrap_tile_coords (map, &land_bx, &land_by); - if (! tile_point_in_block (land_bx, land_by, block_x0, block_y0, block_x1, block_y1)) - continue; - if (! tile_exists_at (land_bx, land_by)) - continue; - if (! tile_is_land (-1, land_bx, land_by, false)) - continue; - Tile * land_b = tile_at (land_bx, land_by); - if ((land_b == NULL) || (land_b == p_null_tile)) - continue; - - int cont_a = land_a->vtable->m46_Get_ContinentID (land_a); - int cont_b = land_b->vtable->m46_Get_ContinentID (land_b); - if ((cont_a < 0) || (cont_b < 0) || (cont_a == cont_b)) - continue; - - for (int step = 0; step < length; step++) { - int cx = tx + dx * step; - int cy = ty + dy * step; - wrap_tile_coords (map, &cx, &cy); - out_x[step] = (short)cx; - out_y[step] = (short)cy; - } - *out_owner = owner; - return length; - } - } - } - return 0; -} - -int -gather_canal_line (int start_x, int start_y, int dx, int dy, int limit, - int block_x0, int block_y0, int block_x1, int block_y1, - short * out_x, short * out_y) -{ - int effective_limit = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, limit); - - if (! tile_is_land (-1, start_x, start_y, false)) - return 0; - if (tile_part_of_existing_candidate (start_x, start_y)) - return 0; - - short back_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - short back_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - short forward_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - short forward_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - int back_count = 0; - int forward_count = 0; - int remaining = effective_limit - 1; - Map * map = &p_bic_data->Map; - - int cx = start_x; - int cy = start_y; - while ((remaining > 0) && (back_count < effective_limit)) { - int nx = cx - dx; - int ny = cy - dy; - wrap_tile_coords (map, &nx, &ny); - if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) - break; - if (! tile_is_land (-1, nx, ny, false)) - break; - if (tile_part_of_existing_candidate (nx, ny)) - break; - back_x[back_count] = (short)nx; - back_y[back_count] = (short)ny; - back_count++; - remaining--; - cx = nx; - cy = ny; - } - - cx = start_x; - cy = start_y; - while ((remaining > 0) && (forward_count < effective_limit)) { - int nx = cx + dx; - int ny = cy + dy; - wrap_tile_coords (map, &nx, &ny); - if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) - break; - if (! tile_is_land (-1, nx, ny, false)) - break; - if (tile_part_of_existing_candidate (nx, ny)) - break; - forward_x[forward_count] = (short)nx; - forward_y[forward_count] = (short)ny; - forward_count++; - remaining--; - cx = nx; - cy = ny; - } - - int write = 0; - for (int bi = back_count - 1; bi >= 0; bi--) { - out_x[write] = back_x[bi]; - out_y[write] = back_y[bi]; - write++; - } - out_x[write] = (short)start_x; - out_y[write] = (short)start_y; - write++; - for (int fi = 0; fi < forward_count; fi++) { - out_x[write] = forward_x[fi]; - out_y[write] = forward_y[fi]; - write++; - } - - return write; -} - -bool -cluster_connects_two_seas_or_isthmus (short * xs, short * ys, int count) -{ - for (int i = 0; i < count; i++) { - if (canal_has_different_adjacent_seas (xs[i], ys[i], -1)) - return true; - if (canal_has_same_sea_isthmus (xs[i], ys[i], -1, 2)) - return true; - } - return false; -} - -int -find_canal_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, - int contiguous_limit, int candidate_capacity, - short * out_x, short * out_y, short * out_owner) -{ - const int dir_dx[8] = { 0, 1, 2, 1, 0, -1, -2, -1 }; - const int dir_dy[8] = { -2, -1, 0, 1, 2, 1, 0, -1 }; - - int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - if (candidate_capacity > 0 && max_len > candidate_capacity) - max_len = candidate_capacity; - - int tile_count = map->TileCount; - int * visit = (int *)malloc (sizeof (*visit) * tile_count); - int * queue_x = (int *)malloc (sizeof (*queue_x) * tile_count); - int * queue_y = (int *)malloc (sizeof (*queue_y) * tile_count); - if ((visit == NULL) || (queue_x == NULL) || (queue_y == NULL)) { - if (visit != NULL) - free (visit); - if (queue_x != NULL) - free (queue_x); - if (queue_y != NULL) - free (queue_y); - return 0; - } - for (int i = 0; i < tile_count; i++) - visit[i] = 0; - - int visit_mark = 1; - - for (int length = 1; length <= max_len; length++) { - for (int ti = 0; ti < map->TileCount; ti++) { - int start_x = -1; - int start_y = -1; - tile_index_to_coords (map, ti, &start_x, &start_y); - if (! tile_point_in_block (start_x, start_y, block_x0, block_y0, block_x1, block_y1)) - continue; - if (! tile_is_land (-1, start_x, start_y, false)) - continue; - if (tile_part_of_existing_candidate (start_x, start_y)) - continue; - if (tile_has_bridge_or_canal_nearby (start_x, start_y)) - continue; - if (tile_is_reserved_in_district_tile_map (start_x, start_y)) - continue; - Tile * start_tile = tile_at (start_x, start_y); - if ((start_tile == NULL) || (start_tile == p_null_tile)) - continue; - if (tile_has_resource (start_tile)) - continue; - if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], start_tile)) - continue; - int continent_id = start_tile->vtable->m46_Get_ContinentID (start_tile); - if (continent_id < 0) - continue; - short owner = start_tile->vtable->m38_Get_Territory_OwnerID (start_tile); - - int stack_len = 1; - int dir_stack[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - int path_dir[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - out_x[0] = (short)start_x; - out_y[0] = (short)start_y; - dir_stack[0] = -1; - path_dir[0] = -1; - - while (stack_len > 0) { - int depth = stack_len - 1; - int cx = out_x[depth]; - int cy = out_y[depth]; - - if (depth + 1 == length) { - bool endpoints_ok = false; - if (length == 1) { - int ex = out_x[0]; - int ey = out_y[0]; - bool pair_ok = false; - if (tile_is_water (ex, ey - 2) && tile_is_water (ex, ey + 2)) pair_ok = true; - if (tile_is_water (ex - 2, ey) && tile_is_water (ex + 2, ey)) pair_ok = true; - if (tile_is_water (ex - 1, ey - 1) && tile_is_water (ex + 1, ey + 1)) pair_ok = true; - if (tile_is_water (ex - 1, ey + 1) && tile_is_water (ex + 1, ey - 1)) pair_ok = true; - if (pair_ok && tile_has_diagonal_water (ex, ey)) - endpoints_ok = true; - } else { - int first_dir = path_dir[1]; - int last_dir = path_dir[length - 1]; - int sx = out_x[0]; - int sy = out_y[0]; - int ex = out_x[length - 1]; - int ey = out_y[length - 1]; - bool start_water = tile_is_water (sx - dir_dx[first_dir], sy - dir_dy[first_dir]); - bool end_water = tile_is_water (ex + dir_dx[last_dir], ey + dir_dy[last_dir]); - if (start_water && end_water && - tile_has_diagonal_water (sx, sy) && - tile_has_diagonal_water (ex, ey)) - endpoints_ok = true; - } - - bool buildable = true; - if (endpoints_ok) { - for (int pi = 0; pi < length; pi++) { - Tile * path_tile = tile_at (out_x[pi], out_y[pi]); - if ((path_tile == NULL) || (path_tile == p_null_tile) || - tile_has_resource (path_tile) || - (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], path_tile)) || - tile_is_reserved_in_district_tile_map (out_x[pi], out_y[pi])) { - buildable = false; - break; - } - if (tile_has_bridge_or_canal_nearby (out_x[pi], out_y[pi])) { - buildable = false; - break; - } - } - } else { - buildable = false; - } - - if (buildable) { - // Collect adjacent land tiles for component checks - int adj_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; - int adj_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; - int adj_count = 0; - for (int pi = 0; pi < length; pi++) { - int px = out_x[pi]; - int py = out_y[pi]; - for (int di = 0; di < 8; di++) { - int nx = px + dir_dx[di]; - int ny = py + dir_dy[di]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_is_land (-1, nx, ny, false)) - continue; - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) - continue; - bool in_path = false; - for (int pj = 0; pj < length; pj++) { - if ((out_x[pj] == nx) && (out_y[pj] == ny)) { - in_path = true; - break; - } - } - if (in_path) - continue; - bool seen = false; - for (int aj = 0; aj < adj_count; aj++) { - if ((adj_x[aj] == nx) && (adj_y[aj] == ny)) { - seen = true; - break; - } - } - if (! seen && (adj_count < (int)(sizeof (adj_x) / sizeof (adj_x[0])))) { - adj_x[adj_count] = nx; - adj_y[adj_count] = ny; - adj_count++; - } - } - } - - if (adj_count >= 2) { - int best1 = 0; - int best2 = 0; - int min_land = is->current_config.ai_canal_eval_min_bisected_land_tiles; - if (min_land < 1) - min_land = 1; - visit_mark++; - if (visit_mark == 0) { - visit_mark = 1; - for (int i = 0; i < tile_count; i++) - visit[i] = 0; - } - - for (int ai = 0; ai < adj_count; ai++) { - int aidx = tile_coords_to_index (map, adj_x[ai], adj_y[ai]); - if ((aidx < 0) || (visit[aidx] == visit_mark)) - continue; - - int comp_size = 0; - int head = 0; - int tail = 0; - visit[aidx] = visit_mark; - queue_x[tail] = adj_x[ai]; - queue_y[tail] = adj_y[ai]; - tail++; - - while (head < tail) { - int qx = queue_x[head]; - int qy = queue_y[head]; - head++; - comp_size++; - for (int di = 0; di < 8; di++) { - int nx = qx + dir_dx[di]; - int ny = qy + dir_dy[di]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_is_land (-1, nx, ny, false)) - continue; - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) - continue; - bool blocked = false; - for (int pj = 0; pj < length; pj++) { - if ((out_x[pj] == nx) && (out_y[pj] == ny)) { - blocked = true; - break; - } - } - if (blocked) - continue; - int nidx = tile_coords_to_index (map, nx, ny); - if ((nidx < 0) || (visit[nidx] == visit_mark)) - continue; - visit[nidx] = visit_mark; - queue_x[tail] = nx; - queue_y[tail] = ny; - tail++; - } - } - - if (comp_size > best1) { - best2 = best1; - best1 = comp_size; - } else if (comp_size > best2) { - best2 = comp_size; - } - } - - if ((best1 >= min_land) && (best2 >= min_land)) { - *out_owner = owner; - free (visit); - free (queue_x); - free (queue_y); - return length; - } - } - } - dir_stack[depth] = -1; - stack_len--; - continue; - } - - int next_dir = dir_stack[depth] + 1; - bool advanced = false; - while (next_dir < 8) { - int ndx = dir_dx[next_dir]; - int ndy = dir_dy[next_dir]; - int nx = cx + ndx; - int ny = cy + ndy; - wrap_tile_coords (map, &nx, &ny); - dir_stack[depth] = next_dir; - - if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) { - next_dir++; - continue; - } - if (! tile_is_land (-1, nx, ny, false)) { - next_dir++; - continue; - } - if (tile_part_of_existing_candidate (nx, ny)) { - next_dir++; - continue; - } - if (tile_is_reserved_in_district_tile_map (nx, ny)) { - next_dir++; - continue; - } - Tile * next_tile = tile_at (nx, ny); - if ((next_tile == NULL) || (next_tile == p_null_tile)) { - next_dir++; - continue; - } - if (tile_has_resource (next_tile)) { - next_dir++; - continue; - } - if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], next_tile)) { - next_dir++; - continue; - } - if (tile_has_bridge_or_canal_nearby (nx, ny)) { - next_dir++; - continue; - } - if (next_tile->vtable->m46_Get_ContinentID (next_tile) != continent_id) { - next_dir++; - continue; - } - bool dup = false; - for (int pi = 0; pi < depth + 1; pi++) { - if ((out_x[pi] == nx) && (out_y[pi] == ny)) { - dup = true; - break; - } - } - if (dup) { - next_dir++; - continue; - } - - if (depth >= 1) { - int prev_dir = dir_stack[depth - 1]; - int diff = next_dir - prev_dir; - if (diff < 0) - diff += 8; - if (diff > 4) - diff = 8 - diff; - if (diff > 1) { - next_dir++; - continue; - } - } - - out_x[depth + 1] = (short)nx; - out_y[depth + 1] = (short)ny; - dir_stack[depth + 1] = -1; - path_dir[depth + 1] = next_dir; - stack_len++; - advanced = true; - break; - } - - if (! advanced) { - dir_stack[depth] = -1; - stack_len--; - } - } - } - } - - free (visit); - free (queue_x); - free (queue_y); - return 0; -} - -void -generate_ai_bridge_candidates_by_block (Map * map, int block_size, int contiguous_limit) -{ - if ((map == NULL) || (block_size <= 0)) - return; - - int width = map->Width; - int height = map->Height; - if ((width <= 0) || (height <= 0)) - return; - - if (block_size < 1) - block_size = 1; - - int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - - short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); - short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); - if ((candidate_x == NULL) || (candidate_y == NULL)) { - if (candidate_x != NULL) - free (candidate_x); - if (candidate_y != NULL) - free (candidate_y); - return; - } - - for (int base_y = 0; base_y < height; base_y += block_size) { - int block_y1 = base_y + block_size; - if (block_y1 > height) - block_y1 = height; - for (int base_x = 0; base_x < width; base_x += block_size) { - int block_x1 = base_x + block_size; - if (block_x1 > width) - block_x1 = width; - short owner = -1; - int count = find_bridge_candidate_in_block ( - map, base_x, base_y, block_x1, block_y1, - contiguous_limit, candidate_capacity, - candidate_x, candidate_y, &owner); - if (count <= 0) - continue; - if (! add_ai_candidate_entry (BRIDGE_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { - free (candidate_x); - free (candidate_y); - return; - } - } - } - - free (candidate_x); - free (candidate_y); -} - -void -generate_ai_canal_candidates_by_block (Map * map, int block_size, int contiguous_limit) -{ - if ((map == NULL) || (block_size <= 0)) - return; - - int width = map->Width; - int height = map->Height; - if ((width <= 0) || (height <= 0)) - return; - - if (block_size < 1) - block_size = 1; - - int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - - short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); - short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); - if ((candidate_x == NULL) || (candidate_y == NULL)) { - if (candidate_x != NULL) - free (candidate_x); - if (candidate_y != NULL) - free (candidate_y); - return; - } - - for (int base_y = 0; base_y < height; base_y += block_size) { - int block_y1 = base_y + block_size; - if (block_y1 > height) - block_y1 = height; - for (int base_x = 0; base_x < width; base_x += block_size) { - int block_x1 = base_x + block_size; - if (block_x1 > width) - block_x1 = width; - short owner = -1; - int count = find_canal_candidate_in_block ( - map, base_x, base_y, block_x1, block_y1, - contiguous_limit, candidate_capacity, - candidate_x, candidate_y, &owner); - if (count <= 0) - continue; - if (! add_ai_candidate_entry (CANAL_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { - free (candidate_x); - free (candidate_y); - return; - } - } - } - - free (candidate_x); - free (candidate_y); -} - -void -generate_ai_canal_and_bridge_targets () -{ - if (is->ai_candidate_bridge_or_canals_initialized) - return; - if ((! is->current_config.enable_canal_districts) && (! is->current_config.enable_bridge_districts)) - return; - - Map * map = &p_bic_data->Map; - int width = map->Width; - int height = map->Height; - if ((width <= 0) || (height <= 0)) - return; - - int block_size = is->current_config.ai_bridge_canal_eval_block_size; - if (block_size <= 0) - block_size = 10; - - if (is->current_config.enable_bridge_districts && is->current_config.ai_builds_bridges) { - generate_ai_bridge_candidates_by_block ( - map, - block_size, - is->current_config.max_contiguous_bridge_districts); - } - - if (is->current_config.enable_canal_districts && is->current_config.ai_builds_canals) { - generate_ai_canal_candidates_by_block ( - map, - block_size, - is->current_config.max_contiguous_canal_districts); - } - - is->ai_candidate_bridge_or_canals_initialized = true; -} - -void -assign_workers_for_ai_candidate_bridge_or_canals (Leader * leader) -{ - if ((leader == NULL) || (is->ai_candidate_bridge_or_canals_count <= 0)) - return; - - int civ_id = leader->ID; - if ((*p_human_player_bits & (1 << civ_id)) != 0) - return; - - if (! leader_can_build_district (leader, CANAL_DISTRICT_ID) && ! leader_can_build_district (leader, BRIDGE_DISTRICT_ID)) - return; - - if (! is->ai_candidate_bridge_or_canals_initialized) { - reset_ai_candidate_bridge_or_canals (); - generate_ai_canal_and_bridge_targets (); - } - - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if (entry->completed) - continue; - - int district_id = entry->district_id; - if ((district_id == CANAL_DISTRICT_ID) && (! is->current_config.enable_canal_districts)) continue; - if ((district_id == BRIDGE_DISTRICT_ID) && (! is->current_config.enable_bridge_districts)) continue; - if (! leader_can_build_district (leader, district_id)) continue; - - if (entry->assigned_worker_id >= 0) { - Unit * worker = get_unit_ptr (entry->assigned_worker_id); - if (worker == NULL) { - release_ai_candidate_bridge_or_canal_worker (entry); - } else if ((entry->assigned_tile_index >= 0) && (entry->assigned_tile_index < entry->tile_count)) { - int tx = entry->tile_x[entry->assigned_tile_index]; - int ty = entry->tile_y[entry->assigned_tile_index]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - Tile * tile = tile_at (tx, ty); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && inst->district_id == district_id && district_is_complete (tile, district_id)) { - release_ai_candidate_bridge_or_canal_worker (entry); - } - } - } - if (entry->assigned_worker_id >= 0) - continue; - } - - int target_idx = -1; - if (! ai_candidate_bridge_or_canal_is_buildable_for_civ (entry, civ_id, &target_idx)) { - release_ai_candidate_bridge_or_canal_worker (entry); - continue; - } - - if (target_idx < 0) - continue; - - City * city = find_closest_owned_city_for_tile (civ_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); - if (city == NULL) - continue; - - Unit * worker = find_best_worker_for_district (leader, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); - if (worker == NULL) - continue; - - memset (&entry->pending_req, 0, sizeof entry->pending_req); - entry->pending_req.district_id = district_id; - entry->pending_req.civ_id = civ_id; - if (! assign_worker_to_district (&entry->pending_req, worker, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx])) - continue; - - entry->assigned_worker_id = worker->Body.ID; - entry->assigned_tile_index = target_idx; - } -} - -void -recompute_city_yields_with_districts (City * city) -{ - if (city == NULL) - return; - - bool prev_flag = is->distribution_hub_refresh_in_progress; - is->distribution_hub_refresh_in_progress = true; - patch_City_recompute_yields_and_happiness (city); - is->distribution_hub_refresh_in_progress = prev_flag; -} - -enum UnitStateType __fastcall -patch_City_instruct_worker (City * this, int edx, int tile_x, int tile_y, bool param_3, Unit * worker) -{ - return City_instruct_worker (this, __, tile_x, tile_y, param_3, worker); -} - -int -find_wonder_config_index_by_improvement_id (int improv_id) -{ - if (improv_id < 0) - return -1; - - char ss[200]; - - for (int wi = 0; wi < is->wonder_district_count; wi++) { - int bid = -1; - if (stable_look_up (&is->building_name_to_id, is->wonder_district_configs[wi].wonder_name, &bid) && - (bid == improv_id)) { - return wi; - } - } - - return -1; -} - -void set_wonder_built_flag (int improv_id, bool is_built); - -unsigned int -wonder_buildable_square_type_mask (struct wonder_district_config const * cfg) -{ - if (cfg == NULL) - return district_default_buildable_mask (); - - unsigned int mask = cfg->buildable_square_types_mask; - if (mask == 0) - mask = district_default_buildable_mask (); - return mask; -} - -unsigned int -wonder_buildable_mask_for_improvement (int improv_id) -{ - int windex = find_wonder_config_index_by_improvement_id (improv_id); - if (windex < 0) - return district_default_buildable_mask (); - return wonder_buildable_square_type_mask (&is->wonder_district_configs[windex]); -} - -bool -wonder_is_buildable_on_square_type (struct wonder_district_config const * cfg, Tile * tile) -{ - if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - if (! tile_matches_square_type_mask (tile, wonder_buildable_square_type_mask (cfg))) - return false; - - if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) - return false; - - if (cfg->has_buildable_adjacent_to) { - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - return false; - - bool matches = false; - bool city_adjacent = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (Tile_has_city (tai.tile)) { - city_adjacent = true; - if (cfg->buildable_adjacent_to_allows_city) - matches = true; - } - if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) - matches = true; - if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) - break; - } - if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) - return false; - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to_overlays) { - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - return false; - - bool matches = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { - matches = true; - break; - } - } - if (! matches) - return false; - } - - return true; -} - -bool -wonder_is_buildable_on_tile (Tile * tile, int wonder_improv_id) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); - if (windex < 0) - return tile_matches_square_type_mask (tile, district_default_buildable_mask ()); - - return wonder_is_buildable_on_square_type (&is->wonder_district_configs[windex], tile); -} - -bool -wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id) -{ - if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) - return false; - if ((civ_id < 0) || (civ_id >= 32)) - return false; - - int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); - if (windex < 0) - return true; - - struct wonder_district_config const * cfg = &is->wonder_district_configs[windex]; - Leader * leader = &leaders[civ_id]; - - if (cfg->has_buildable_by_civs) { - bool civ_match = false; - if (cfg->buildable_by_civ_count > 0) { - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - for (int i = 0; i < cfg->buildable_by_civ_count; i++) { - char const * civ_name = cfg->buildable_by_civs[i]; - if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; - if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; - if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; - if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; - if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; - } - } - if (! civ_match) - return false; - } - - if (cfg->has_buildable_by_civ_traits) { - if (cfg->buildable_by_civ_traits_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL || race->vtable == NULL) - return false; - bool trait_match = false; - for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { - int trait_id = cfg->buildable_by_civ_traits_ids[i]; - if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { - trait_match = true; - break; - } - } - if (! trait_match) - return false; - } - - if (cfg->has_buildable_by_civ_govs) { - if (cfg->buildable_by_civ_govs_id_count <= 0) - return false; - int gov_id = leader->GovernmentType; - bool gov_match = false; - for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { - if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { - gov_match = true; - break; - } - } - if (! gov_match) - return false; - } - - if (cfg->has_buildable_by_civ_cultures) { - if (cfg->buildable_by_civ_cultures_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - int culture_id = race->CultureGroupID; - bool culture_match = false; - for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { - if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { - culture_match = true; - break; - } - } - if (! culture_match) - return false; - } - - return true; -} - -int -get_wonder_improvement_id_from_index (int windex) -{ - if ((windex < 0) || (windex >= is->wonder_district_count)) - return -1; - - char const * wonder_name = is->wonder_district_configs[windex].wonder_name; - if ((wonder_name == NULL) || (wonder_name[0] == '\0')) - return -1; - - int improv_id; - if (stable_look_up (&is->building_name_to_id, (char *)wonder_name, &improv_id)) - return improv_id; - else - return -1; -} - -void -remember_pending_building_order (City * city, int improvement_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (improvement_id < 0)) - return; - - if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) - return; - - itable_insert (&is->city_pending_building_orders, (int)city, improvement_id); -} - -bool -look_up_pending_building_order (City * city, int * out_improv_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (out_improv_id == NULL)) - return false; - - return itable_look_up (&is->city_pending_building_orders, (int)city, out_improv_id); -} - -void -forget_pending_building_order (City * city) -{ - if (! is->current_config.enable_districts || - (city == NULL)) - return; - - itable_remove (&is->city_pending_building_orders, (int)city); -} - -bool -is_wonder_or_small_wonder_already_being_built (City * city, int improv_id) -{ - if ((city == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) - return false; - - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) - return false; - - int civ_id = city->Body.CivID; - FOR_CITIES_OF (coi, civ_id) { - City * other_city = coi.city; - if ((other_city == NULL) || (other_city == city)) - continue; - - if ((other_city->Body.Order_Type == COT_Improvement) && - (other_city->Body.Order_ID == improv_id)) - return true; - } - - return false; -} - -struct district_building_prereq_list * -get_district_building_prereq_list (int improv_id) -{ - if (improv_id < 0) - return NULL; - - int stored = 0; - if (! itable_look_up (&is->district_building_prereqs, improv_id, &stored)) - return NULL; - return (struct district_building_prereq_list *)stored; -} - -bool -district_building_prereq_list_contains (struct district_building_prereq_list * list, int district_id) -{ - if ((list == NULL) || (district_id < 0)) - return false; - for (int i = 0; i < list->count; i++) { - if (list->district_ids[i] == district_id) - return true; - } - return false; -} - -void -add_district_building_prereq (int improv_id, int district_id) -{ - if ((improv_id < 0) || (district_id < 0)) - return; - - struct district_building_prereq_list * list = get_district_building_prereq_list (improv_id); - if (list == NULL) { - list = calloc (1, sizeof *list); - if (list == NULL) - return; - list->count = 0; - itable_insert (&is->district_building_prereqs, improv_id, (int)list); - } - - if (district_building_prereq_list_contains (list, district_id)) - return; - - if (list->count >= ARRAY_LEN (list->district_ids)) - return; - - list->district_ids[list->count++] = district_id; -} - -bool -city_has_river_district (City * city, int district_id) -{ - if (city == NULL) - return false; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if (wai.district_inst->district_id != district_id) - continue; - if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) - return true; - } - return false; -} - -bool -city_has_any_prereq_district_for_improvement (City * city, - struct district_building_prereq_list * list, - bool requires_river, - bool allow_wonder_district) -{ - if ((city == NULL) || (list == NULL)) - return false; - - for (int i = 0; i < list->count; i++) { - int district_id = list->district_ids[i]; - if (district_id < 0) - continue; - if (! allow_wonder_district && district_id == WONDER_DISTRICT_ID) - continue; - if (requires_river) { - if (city_has_river_district (city, district_id)) - return true; - } else if (city_has_required_district (city, district_id)) { - return true; - } - } - return false; -} - -int -pick_missing_district_for_improvement (City * city, struct district_building_prereq_list * list) -{ - if ((list == NULL) || (list->count <= 0)) - return -1; - - int fallback = -1; - for (int i = 0; i < list->count; i++) { - int district_id = list->district_ids[i]; - if (district_id < 0) - continue; - if (fallback < 0) - fallback = district_id; - if ((city != NULL) && leader_can_build_district (&leaders[city->Body.CivID], district_id)) - return district_id; - } - return fallback; -} - - -bool -district_is_complete(Tile * tile, int district_id) -{ - if ((tile == NULL) || (tile == p_null_tile) || - (district_id < 0) || (district_id >= is->district_count)) - return false; - - bool is_natural_wonder = (district_id == NATURAL_WONDER_DISTRICT_ID); - bool districts_disabled = ! is->current_config.enable_districts; - bool natural_wonders_disabled = ! is->current_config.enable_natural_wonders; - struct district_config const * cfg = &is->district_configs[district_id]; - - if (districts_disabled && (!is_natural_wonder || natural_wonders_disabled)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != district_id) - return false; - - // If already marked COMPLETED, just return true - if (inst->state == DS_COMPLETED) - return true; - - // State is UNDER_CONSTRUCTION - check if tile has mines now - bool has_mines = tile->vtable->m18_Check_Mines (tile, __, 0) != 0; - - if (! has_mines) { - // Still under construction - check if we should clean it up - bool worker_present = false; - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit != NULL) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { - worker_present = true; - break; - } - } - if (! worker_present) { - remove_district_instance (tile); - } - return false; - } - - // Mark as completed and run one-time side effects - inst->state = DS_COMPLETED; - inst->completed_turn = *p_current_turn_no; - - int tile_x, tile_y; - if (district_instance_get_coords (inst, tile, &tile_x, &tile_y)) { - set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - if (cfg->auto_add_road) { - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - if (! has_road) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_ROAD, tile_x, tile_y); - } - - if (cfg->auto_add_railroad) { - bool has_railroad = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; - if (! has_railroad) { - if ((territory_owner >= 0) && patch_Leader_can_do_worker_job (&leaders[territory_owner], __, WJ_Build_Railroad, tile_x, tile_y, 0)) { - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_RAILROAD, tile_x, tile_y); - } - } - } - - // Activate distribution hub if applicable - if (is->current_config.enable_distribution_hub_districts && - (district_id == DISTRIBUTION_HUB_DISTRICT_ID)) { - on_distribution_hub_completed (tile, tile_x, tile_y); - } - - // Remove forest/swamp if applicable - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - if ((base_type == SQ_Forest) || (base_type == SQ_Swamp)) { - int new_terrain_type = tile->vtable->m71_Check_Worker_Job (tile); - if (new_terrain_type >= 0) - Map_change_tile_terrain (&p_bic_data->Map, __, (enum SquareTypes)new_terrain_type, tile_x, tile_y); - } - - char ss[200]; - snprintf (ss, sizeof ss, "District %d completed at tile (%d,%d)\n", district_id, tile_x, tile_y); - (*p_OutputDebugStringA) (ss); - - // Check if this was an AI-requested district - struct pending_district_request * req = find_pending_district_request_by_coords (NULL, tile_x, tile_y, district_id); - if (req != NULL) { - City * requesting_city = get_city_ptr (req->city_id); - if (requesting_city != NULL) { - req->city = requesting_city; - snprintf (ss, sizeof ss, "District %d at tile (%d,%d) was ordered by city %s\n", - district_id, tile_x, tile_y, requesting_city->Body.CityName); - (*p_OutputDebugStringA) (ss); - - // Check if city has pending building order that depends on this district - int pending_improv_id; - if (look_up_pending_building_order (requesting_city, &pending_improv_id)) { - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (pending_improv_id); - if (district_building_prereq_list_contains (prereq_list, district_id)) { - snprintf (ss, sizeof ss, "City %s setting production to improvement %d\n", - requesting_city->Body.CityName, pending_improv_id); - (*p_OutputDebugStringA) (ss); - - // Check if another city is already building this wonder/small wonder - bool can_set_production = true; - if (is_wonder_or_small_wonder_already_being_built (requesting_city, pending_improv_id)) { - snprintf (ss, sizeof ss, "City %s cannot build improvement %d - already being built elsewhere\n", - requesting_city->Body.CityName, pending_improv_id); - (*p_OutputDebugStringA) (ss); - can_set_production = false; - } - - // Set city production to the pending improvement - if (can_set_production && City_can_build_improvement (requesting_city, __, pending_improv_id, false)) { - snprintf (ss, sizeof ss, "City %s can now build improvement %d\n", - requesting_city->Body.CityName, pending_improv_id); - (*p_OutputDebugStringA) (ss); - City_set_production (requesting_city, __, COT_Improvement, pending_improv_id, false); - } - - // Clear the pending building order - forget_pending_building_order (requesting_city); - } - } - - // Clear worker assignment so worker is freed up for other tasks - if (req->assigned_worker_id >= 0) { - snprintf (ss, sizeof ss, "Clearing worker assignment for unit %d\n", req->assigned_worker_id); - (*p_OutputDebugStringA) (ss); - int civ_id = req->civ_id; - clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); - } - } - - // Remove the pending district request - remove_pending_district_request (req); - } - } - - return true; -} - -void -mark_city_needs_district (City * city, int district_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (district_id < 0) || (district_id >= is->district_count)) - return; - - create_pending_district_request (city, district_id); -} - -void -set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return; - - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - - City * assigned_city = NULL; - int assigned_city_id = tile->Body.CityAreaID; - if (assigned_city_id >= 0) - assigned_city = get_city_ptr (assigned_city_id); - - if (assigned_city != NULL) { - int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, - assigned_city->Body.X, assigned_city->Body.Y, tile_x, tile_y, 1000); - bool removed_assignment = false; - if ((neighbor_index > 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) - removed_assignment = City_stop_working_tile (assigned_city, __, neighbor_index); - if (! removed_assignment) - tile->Body.CityAreaID = -1; - if (! removed_assignment) - recompute_city_yields_with_districts (assigned_city); - } else - tile->Body.CityAreaID = -1; - - if (p_cities->Cities != NULL) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city == NULL) || (city == assigned_city)) - continue; - int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, - city->Body.X, city->Body.Y, tile_x, tile_y, 1000); - if ((neighbor_index <= 0) || (neighbor_index >= ARRAY_LEN (is->ni_to_work_radius))) - continue; - int work_radius = is->ni_to_work_radius[neighbor_index]; - if ((work_radius < 0) || (work_radius > is->current_config.city_work_radius)) - continue; - recompute_city_yields_with_districts (city); - } - } -} - -struct distribution_hub_record * -get_distribution_hub_record (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - - int stored; - if (itable_look_up (&is->distribution_hub_records, (int)tile, &stored)) - return (struct distribution_hub_record *)stored; - else - return NULL; -} - -City * -get_connected_city_for_distribution_hub (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return NULL; - - Tile * tile = rec->tile; - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - - City * best_city = NULL; - int best_distance = INT_MAX; - int best_y = INT_MAX; - int best_x = INT_MAX; - int best_id = INT_MAX; - - FOR_CITIES_OF (coi, rec->civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, city, rec->tile_x, rec->tile_y)) - continue; - - int distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, city->Body.X, city->Body.Y); - if ((best_city == NULL) || - (distance < best_distance) || - ((distance == best_distance) && (city->Body.Y < best_y)) || - ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X < best_x)) || - ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X == best_x) && (city->Body.ID < best_id))) { - best_city = city; - best_distance = distance; - best_y = city->Body.Y; - best_x = city->Body.X; - best_id = city->Body.ID; - } - } - - return best_city; -} - -bool -distribution_hub_accessible_to_city (struct distribution_hub_record * rec, City * city) -{ - if ((rec == NULL) || (city == NULL)) - return false; - - if (city->Body.CivID != rec->civ_id) - return false; - - City * anchor_city = get_connected_city_for_distribution_hub (rec); - if (anchor_city == NULL) - return false; - - if (anchor_city == city) - return true; - - return Trade_Net_have_trade_connection (is->trade_net, __, anchor_city, city, rec->civ_id); -} - -void -get_distribution_hub_yields_for_city (City * city, int * out_food, int * out_shields) -{ - int food = 0; - int shields = 0; - - if ((city != NULL) && - is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts) { - if (is->distribution_hub_totals_dirty && - ! is->distribution_hub_refresh_in_progress) - recompute_distribution_hub_totals (); - - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (distribution_hub_accessible_to_city (rec, city)) { - food += rec->food_yield; - shields += rec->shield_yield; - } - } - } - - if (city_has_required_district (city, CENTRAL_RAIL_HUB_DISTRICT_ID)) { - food += (food * is->current_config.central_rail_hub_distribution_food_bonus_percent) / 100; - shields += (shields * is->current_config.central_rail_hub_distribution_shield_bonus_percent) / 100; - } - - if (out_food != NULL) - *out_food = food; - if (out_shields != NULL) - *out_shields = shields; -} - -void -adjust_distribution_hub_coverage (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return; - - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if ((area_tile == NULL) || (area_tile == p_null_tile)) - continue; - int tx = tai.tile_x; - int ty = tai.tile_y; - - if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) - continue; - if (Tile_has_city (area_tile)) - continue; - if (get_district_instance (area_tile) != NULL) - continue; - - struct wonder_district_info * area_info = get_wonder_district_info (area_tile); - if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) - continue; - - int key = (int)area_tile; - int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); - itable_insert (&is->distribution_hub_coverage_counts, key, prev + 1); - - if (area_tile->Body.CityAreaID >= 0) { - set_tile_unworkable_for_all_cities (area_tile, tx, ty); - area_tile->Body.CityAreaID = -1; - } - } -} - -void -release_distribution_hub_coverage (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return; - - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if ((area_tile == NULL) || (area_tile == p_null_tile)) - continue; - - int key = (int)area_tile; - int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); - if (prev <= 0) - continue; - - if (prev == 1) - itable_remove (&is->distribution_hub_coverage_counts, key); - else - itable_insert (&is->distribution_hub_coverage_counts, key, prev - 1); - } -} - -void -clear_distribution_hub_tables (void) -{ - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - free (rec); - } - table_deinit (&is->distribution_hub_records); - table_deinit (&is->distribution_hub_coverage_counts); - is->distribution_hub_totals_dirty = true; -} - -bool -city_radius_contains_tile (City * city, int tile_x, int tile_y) -{ - if (city == NULL) - return false; - - int ni = patch_Map_compute_ni_for_work_area (&p_bic_data->Map, __, city->Body.X, city->Body.Y, tile_x, tile_y, is->workable_tile_count); - return ni >= 0; -} - -void -recompute_distribution_hub_yields (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return; - - Tile * tile = tile_at (rec->tile_x, rec->tile_y); - rec->tile = tile; - - if ((tile == NULL) || - (tile == p_null_tile) || - ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID) || - tile->vtable->m20_Check_Pollution (tile, __, 0) || - tile_has_enemy_unit (tile, rec->civ_id)) { - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - return; - } - - int food_sum = 0; - int shield_sum = 0; - City * anchor_city = get_connected_city_for_distribution_hub (rec); - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if (area_tile == p_null_tile) - continue; - int tx = tai.tile_x; - int ty = tai.tile_y; - - // Only include tiles that belong to the distribution hub owner - if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) - continue; - - // Skip city tiles - if (Tile_has_city (area_tile)) - continue; - - // Skip tiles with enemy units - if (tile_has_enemy_unit (area_tile, rec->civ_id)) - continue; - - // Skip tiles with pollution - if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) - continue; - - // Skip tiles that are other districts (but not this hub itself) - struct district_instance * area_district = get_district_instance (area_tile); - if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) - continue; - - // Skip tiles with completed wonders - struct wonder_district_info * area_info = get_wonder_district_info (area_tile); - if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) - continue; - - // Check if another hub of the same civ is closer to this tile - int my_distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, tx, ty); - bool tile_belongs_to_me = true; - - FOR_TABLE_ENTRIES (other_tei, &is->distribution_hub_records) { - struct distribution_hub_record * other_rec = (struct distribution_hub_record *)other_tei.value; - if ((other_rec == NULL) || (other_rec == rec)) - continue; - if (other_rec->civ_id != rec->civ_id) - continue; - - int other_distance = compute_wrapped_manhattan_distance (other_rec->tile_x, other_rec->tile_y, tx, ty); - if (other_distance < my_distance) { - tile_belongs_to_me = false; - break; - } - if (other_distance == my_distance) { - // Tie-breaking: prefer hub with lower Y, then lower X - if (other_rec->tile_y < rec->tile_y) { - tile_belongs_to_me = false; - break; - } - if ((other_rec->tile_y == rec->tile_y) && (other_rec->tile_x < rec->tile_x)) { - tile_belongs_to_me = false; - break; - } - } - } - - if (! tile_belongs_to_me) - continue; - - food_sum += City_calc_tile_yield_at (anchor_city, __, 0, tx, ty); - shield_sum += City_calc_tile_yield_at (anchor_city, __, 1, tx, ty); - } - - rec->raw_food_yield = food_sum; - rec->raw_shield_yield = shield_sum; - - int food_div = is->current_config.distribution_hub_food_yield_divisor; - int shield_div = is->current_config.distribution_hub_shield_yield_divisor; - if (food_div <= 0) - food_div = 1; - if (shield_div <= 0) - shield_div = 1; - - int connected_city_count = 0; - if (anchor_city != NULL) { - FOR_CITIES_OF (coi, rec->civ_id) { - City * other_city = coi.city; - if ((other_city != NULL) && distribution_hub_accessible_to_city (rec, other_city)) - connected_city_count++; - } - } - if (connected_city_count <= 0) - connected_city_count = 1; - - if (is->current_config.distribution_hub_yield_division_mode == DHYDM_SCALE_BY_CITY_COUNT) { - int city_root = 1; - while ((city_root + 1) * (city_root + 1) <= connected_city_count) - city_root++; - int city_food_divisor = city_root * food_div; - int city_shield_divisor = city_root * shield_div; - if (city_food_divisor < 1) city_food_divisor = 1; - if (city_shield_divisor < 1) city_shield_divisor = 1; - rec->food_yield = food_sum / city_food_divisor; - rec->shield_yield = shield_sum / city_shield_divisor; - } else { - rec->food_yield = food_sum / food_div; - rec->shield_yield = shield_sum / shield_div; - } -} - -void -remove_distribution_hub_record (Tile * tile) -{ - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec == NULL) - return; - - int affected_civ_id = rec->civ_id; - release_distribution_hub_coverage (rec); - itable_remove (&is->distribution_hub_records, (int)tile); - free (rec); - is->distribution_hub_totals_dirty = true; - recompute_distribution_hub_totals (); - - // Recalculate yields for all cities of this civ - if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * target_city = get_city_ptr (city_index); - if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) - recompute_city_yields_with_districts (target_city); - } - } -} - -void -recompute_distribution_hub_totals () -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_distribution_hub_districts) { - is->distribution_hub_totals_dirty = false; - return; - } - - struct table new_coverage_counts = {0}; - struct table newly_covered_tiles = {0}; - - clear_memo (); - int civs_needing_recalc[32] = {0}; - - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - Tile * tile = (Tile *)tei.key; - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (rec == NULL) - continue; - - Tile * current_tile = tile_at (rec->tile_x, rec->tile_y); - if ((current_tile == NULL) || - (current_tile == p_null_tile) || - ! district_is_complete (current_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { - memoize (tei.key); - continue; - } - - rec->tile = current_tile; - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - - int old_civ_id = rec->civ_id; - rec->civ_id = current_tile->vtable->m38_Get_Territory_OwnerID (current_tile); - - if (old_civ_id != rec->civ_id) - civs_needing_recalc[old_civ_id] = 1; - civs_needing_recalc[rec->civ_id] = 1; - - City * anchor = get_connected_city_for_distribution_hub (rec); - - if ((anchor == NULL) || - current_tile->vtable->m20_Check_Pollution (current_tile, __, 0) || - tile_has_enemy_unit (current_tile, rec->civ_id)) - continue; - - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if (area_tile == p_null_tile) - continue; - int tx = tai.tile_x; - int ty = tai.tile_y; - - if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) - continue; - if (Tile_has_city (area_tile)) - continue; - if (tile_has_enemy_unit (area_tile, rec->civ_id)) - continue; - if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) - continue; - - struct district_instance * area_district = get_district_instance (area_tile); - if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) - continue; - - struct wonder_district_info * area_info = get_wonder_district_info (area_tile); - if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) - continue; - - int key = (int)area_tile; - int prev_cover_pass = itable_look_up_or (&new_coverage_counts, key, 0); - int prev_cover_old = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); - itable_insert (&new_coverage_counts, key, prev_cover_pass + 1); - if ((prev_cover_pass == 0) && (prev_cover_old <= 0)) - itable_insert (&newly_covered_tiles, key, 1); - } - } - - for (int i = 0; i < is->memo_len; i++) - remove_distribution_hub_record ((Tile *)is->memo[i]); - clear_memo (); - - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (rec == NULL) - continue; - - City * anchor = get_connected_city_for_distribution_hub (rec); - if (anchor == NULL) { - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - continue; - } - - recompute_distribution_hub_yields (rec); - } - - table_deinit (&is->distribution_hub_coverage_counts); - is->distribution_hub_coverage_counts = new_coverage_counts; - memset (&new_coverage_counts, 0, sizeof new_coverage_counts); - - FOR_TABLE_ENTRIES (tei, &newly_covered_tiles) { - Tile * covered_tile = (Tile *)tei.key; - if ((covered_tile == NULL) || (covered_tile == p_null_tile)) - continue; - int tx, ty; - if (! tile_coords_from_ptr (&p_bic_data->Map, covered_tile, &tx, &ty)) - continue; - set_tile_unworkable_for_all_cities (covered_tile, tx, ty); - covered_tile->Body.CityAreaID = -1; - } - table_deinit (&newly_covered_tiles); - - // Recalculate yields for cities of civs whose distribution hub ownership changed - for (int civ_id = 0; civ_id < 32; civ_id++) { - if (civs_needing_recalc[civ_id] && (p_cities->Cities != NULL)) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city != NULL) && (city->Body.CivID == civ_id)) - recompute_city_yields_with_districts (city); - } - } - } - - is->distribution_hub_totals_dirty = false; -} - -void -on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y) -{ - if (! is->current_config.enable_districts || ! is->current_config.enable_distribution_hub_districts) - return; - - int tile_owner = -1; - if ((tile != NULL) && (tile != p_null_tile)) - tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec != NULL) { - int old_civ_id = rec->civ_id; - rec->tile = tile; - rec->tile_x = tile_x; - rec->tile_y = tile_y; - - release_distribution_hub_coverage (rec); - rec->civ_id = tile_owner; - is->distribution_hub_totals_dirty = true; - recompute_distribution_hub_totals (); - - if (old_civ_id != tile_owner) { - // Recompute for old civ - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * target_city = get_city_ptr (city_index); - if ((target_city != NULL) && (target_city->Body.CivID == old_civ_id)) - recompute_city_yields_with_districts (target_city); - } - } - } - - rec = malloc (sizeof *rec); - if (rec == NULL) - return; - rec->tile = tile; - rec->tile_x = tile_x; - rec->tile_y = tile_y; - rec->civ_id = tile_owner; - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - itable_insert (&is->distribution_hub_records, (int)tile, (int)rec); - adjust_distribution_hub_coverage (rec); - - is->distribution_hub_totals_dirty = true; - recompute_distribution_hub_totals (); - - // Recalculate yields for all cities of this civ - int affected_civ_id = rec->civ_id; - if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * target_city = get_city_ptr (city_index); - if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) - recompute_city_yields_with_districts (target_city); - } - } -} - -void -refresh_distribution_hubs_for_city (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_distribution_hub_districts || - (city == NULL)) - return; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int tx = wai.tile_x, ty = wai.tile_y; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID) - continue; - on_distribution_hub_completed (tile, tx, ty); - } -} - -bool -is_space_char (char c) -{ - switch (c) { - case ' ': - case '\t': - case '\n': - case '\r': - case '\f': - case '\v': - return true; - default: - return false; - } -} - -enum key_value_parse_status { - KVP_SUCCESS, - KVP_NO_EQUALS, - KVP_EMPTY_KEY -}; - -enum key_value_parse_status -parse_trimmed_key_value (struct string_slice const * trimmed, - struct string_slice * out_key, - struct string_slice * out_value) -{ - if ((trimmed == NULL) || (trimmed->len <= 0)) - return KVP_NO_EQUALS; - - char * equals = NULL; - for (int i = 0; i < trimmed->len; i++) { - if (trimmed->str[i] == '=') { - equals = trimmed->str + i; - break; - } - } - if (equals == NULL) - return KVP_NO_EQUALS; - - struct string_slice key = { .str = trimmed->str, .len = (int)(equals - trimmed->str) }; - key = trim_string_slice (&key, 0); - if (key.len == 0) - return KVP_EMPTY_KEY; - - struct string_slice value = { .str = equals + 1, .len = (int)((trimmed->str + trimmed->len) - (equals + 1)) }; - *out_key = key; - *out_value = trim_string_slice (&value, 0); - return KVP_SUCCESS; -} - -void -add_key_parse_error (struct error_line ** parse_errors, - int line_number, - struct string_slice const * key, - struct string_slice const * value, - char const * message_suffix) -{ - struct error_line * err = add_error_line (parse_errors); - char * key_str = extract_slice (key); - char * value_str = (value != NULL) ? extract_slice (value) : NULL; - if (value_str != NULL) - snprintf (err->text, sizeof err->text, "^ Line %d: %s \"%s\" %s", line_number, key_str, value_str, message_suffix); - else - snprintf (err->text, sizeof err->text, "^ Line %d: %s %s", line_number, key_str, message_suffix); - err->text[(sizeof err->text) - 1] = '\0'; - if (value_str != NULL) - free (value_str); - free (key_str); -} - -void -add_unrecognized_key_error (struct error_line ** unrecognized_keys, - int line_number, - struct string_slice const * key) -{ - struct error_line * err_line = add_error_line (unrecognized_keys); - char * key_str = extract_slice (key); - snprintf (err_line->text, sizeof err_line->text, "^ Line %d: %s", line_number, key_str); - err_line->text[(sizeof err_line->text) - 1] = '\0'; - free (key_str); -} - -char * -copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes) -{ - struct string_slice trimmed = trim_string_slice (slice, remove_quotes); - if (trimmed.len == 0) - return NULL; - return extract_slice (&trimmed); -} - -void -free_bonus_entry_list (struct district_bonus_list * list) -{ - if (list == NULL) - return; - - for (int i = 0; i < list->count; i++) { - if (list->entries[i].type == DBET_BUILDING && - list->entries[i].building_name != NULL) { - free ((void *)list->entries[i].building_name); - list->entries[i].building_name = NULL; - } - } - list->count = 0; -} - -void -free_bonus_entry_list_override (struct district_bonus_list * list, - struct district_bonus_list const * defaults) -{ - if (list == NULL) - return; - - for (int i = 0; i < list->count; i++) { - if (list->entries[i].type == DBET_BUILDING && - list->entries[i].building_name != NULL) { - char const * default_name = NULL; - if ((defaults != NULL) && (i < defaults->count)) - default_name = defaults->entries[i].building_name; - if (list->entries[i].building_name != default_name) - free ((void *)list->entries[i].building_name); - list->entries[i].building_name = NULL; - } - } - list->count = (defaults != NULL) ? defaults->count : 0; -} - -void -move_bonus_entry_list (struct district_bonus_list * dest, - struct district_bonus_list * src) -{ - if ((dest == NULL) || (src == NULL)) - return; - - dest->count = src->count; - for (int i = 0; i < src->count; i++) { - dest->entries[i] = src->entries[i]; - src->entries[i].building_name = NULL; - } - src->count = 0; -} - -void -free_dynamic_district_config (struct district_config * cfg) -{ - if (cfg == NULL) - return; - - if (! cfg->is_dynamic) - return; - - char const * name_ptr = cfg->name; - if (cfg->name != NULL) { - free ((void *)cfg->name); - cfg->name = NULL; - } - if ((cfg->display_name != NULL) && - (cfg->display_name != name_ptr)) { - free ((void *)cfg->display_name); - cfg->display_name = NULL; - } - if (cfg->tooltip != NULL) { - free ((void *)cfg->tooltip); - cfg->tooltip = NULL; - } - for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { - if (cfg->advance_prereqs[i] != NULL) { - free ((void *)cfg->advance_prereqs[i]); - cfg->advance_prereqs[i] = NULL; - } - } - cfg->advance_prereq_count = 0; - if (cfg->obsoleted_by != NULL) { - free ((void *)cfg->obsoleted_by); - cfg->obsoleted_by = NULL; - } - - for (int i = 0; i < 5; i++) { - if (cfg->resource_prereqs[i] != NULL) { - free ((void *)cfg->resource_prereqs[i]); - cfg->resource_prereqs[i] = NULL; - } - } - - if (cfg->resource_prereq_on_tile != NULL) { - free ((void *)cfg->resource_prereq_on_tile); - cfg->resource_prereq_on_tile = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { - if (cfg->wonder_prereqs[i] != NULL) { - free ((void *)cfg->wonder_prereqs[i]); - cfg->wonder_prereqs[i] = NULL; - } - } - cfg->wonder_prereq_count = 0; - - for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { - if (cfg->natural_wonder_prereqs[i] != NULL) { - free ((void *)cfg->natural_wonder_prereqs[i]); - cfg->natural_wonder_prereqs[i] = NULL; - } - } - cfg->natural_wonder_prereq_count = 0; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { - if (cfg->buildable_on_districts[i] != NULL) { - free ((void *)cfg->buildable_on_districts[i]); - cfg->buildable_on_districts[i] = NULL; - } - } - cfg->buildable_on_district_count = 0; - cfg->buildable_on_district_id_count = 0; - cfg->has_buildable_on_districts = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { - if (cfg->buildable_adjacent_to_districts[i] != NULL) { - free ((void *)cfg->buildable_adjacent_to_districts[i]); - cfg->buildable_adjacent_to_districts[i] = NULL; - } - } - cfg->buildable_adjacent_to_district_count = 0; - cfg->buildable_adjacent_to_district_id_count = 0; - cfg->has_buildable_adjacent_to = false; - cfg->has_buildable_adjacent_to_districts = false; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - if (cfg->buildable_by_civs[i] != NULL) { - free ((void *)cfg->buildable_by_civs[i]); - cfg->buildable_by_civs[i] = NULL; - } - } - cfg->buildable_by_civ_count = 0; - cfg->has_buildable_by_civs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) - cfg->buildable_by_civ_traits_ids[i] = -1; - cfg->buildable_by_civ_traits_id_count = 0; - cfg->has_buildable_by_civ_traits = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) - cfg->buildable_by_civ_govs_ids[i] = -1; - cfg->buildable_by_civ_govs_id_count = 0; - cfg->has_buildable_by_civ_govs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) - cfg->buildable_by_civ_cultures_ids[i] = -1; - cfg->buildable_by_civ_cultures_id_count = 0; - cfg->has_buildable_by_civ_cultures = false; - - for (int i = 0; i < 5; i++) { - if (cfg->dependent_improvements[i] != NULL) { - free ((void *)cfg->dependent_improvements[i]); - cfg->dependent_improvements[i] = NULL; - } - } - - for (int i = 0; i < 10; i++) { - if (cfg->img_paths[i] != NULL) { - free ((void *)cfg->img_paths[i]); - cfg->img_paths[i] = NULL; - } - } - - free_bonus_entry_list (&cfg->culture_bonus_extras); - free_bonus_entry_list (&cfg->science_bonus_extras); - free_bonus_entry_list (&cfg->food_bonus_extras); - free_bonus_entry_list (&cfg->gold_bonus_extras); - free_bonus_entry_list (&cfg->shield_bonus_extras); - free_bonus_entry_list (&cfg->happiness_bonus_extras); - free_bonus_entry_list (&cfg->defense_bonus_extras); - - memset (cfg, 0, sizeof *cfg); -} - -void -free_dynamic_wonder_config (struct wonder_district_config * cfg) -{ - if (cfg == NULL) - return; - - if (! cfg->is_dynamic) - return; - - if (cfg->wonder_name != NULL) { - free ((void *)cfg->wonder_name); - cfg->wonder_name = NULL; - } - - if (cfg->img_path != NULL) { - free ((void *)cfg->img_path); - cfg->img_path = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - if (cfg->buildable_by_civs[i] != NULL) { - free ((void *)cfg->buildable_by_civs[i]); - cfg->buildable_by_civs[i] = NULL; - } - } - cfg->buildable_by_civ_count = 0; - cfg->has_buildable_by_civs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) - cfg->buildable_by_civ_traits_ids[i] = -1; - cfg->buildable_by_civ_traits_id_count = 0; - cfg->has_buildable_by_civ_traits = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) - cfg->buildable_by_civ_govs_ids[i] = -1; - cfg->buildable_by_civ_govs_id_count = 0; - cfg->has_buildable_by_civ_govs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) - cfg->buildable_by_civ_cultures_ids[i] = -1; - cfg->buildable_by_civ_cultures_id_count = 0; - cfg->has_buildable_by_civ_cultures = false; - - memset (cfg, 0, sizeof *cfg); -} - -void -free_dynamic_natural_wonder_config (struct natural_wonder_district_config * cfg) -{ - if (cfg == NULL) - return; - - if (! cfg->is_dynamic) - return; - - if (cfg->name != NULL) { - free ((void *)cfg->name); - cfg->name = NULL; - } - - if (cfg->img_path != NULL) { - free ((void *)cfg->img_path); - cfg->img_path = NULL; - } - - memset (cfg, 0, sizeof *cfg); - cfg->adjacent_to = (enum SquareTypes)SQ_INVALID; - cfg->adjacency_dir = DIR_ZERO; -} - -enum Unit_Command_Values -allocate_dynamic_district_command (char const * name) -{ - int offset = is->next_custom_dynamic_command_index; - is->next_custom_dynamic_command_index += 1; - int value = C3X_DISTRICT_COMMAND_BASE - (offset + 1); - return (enum Unit_Command_Values)value; -} - -void -free_special_district_override_strings (struct district_config * cfg, struct district_config const * defaults) -{ - if (cfg == NULL || defaults == NULL) - return; - - if ((cfg->display_name != NULL) && - (cfg->display_name != cfg->name) && - (cfg->display_name != defaults->display_name)) { - free ((void *)cfg->display_name); - cfg->display_name = NULL; - } - if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) { - free ((void *)cfg->tooltip); - cfg->tooltip = NULL; - } - for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { - char const * default_value = (defaults != NULL && i < defaults->advance_prereq_count) - ? defaults->advance_prereqs[i] - : NULL; - if ((cfg->advance_prereqs[i] != NULL) && - (cfg->advance_prereqs[i] != default_value)) { - free ((void *)cfg->advance_prereqs[i]); - } - cfg->advance_prereqs[i] = NULL; - } - cfg->advance_prereq_count = 0; - if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) { - free ((void *)cfg->obsoleted_by); - cfg->obsoleted_by = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { - char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; - if ((cfg->resource_prereqs[i] != NULL) && - (cfg->resource_prereqs[i] != default_value)) - free ((void *)cfg->resource_prereqs[i]); - cfg->resource_prereqs[i] = NULL; - } - cfg->resource_prereq_count = defaults->resource_prereq_count; - - if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) { - free ((void *)cfg->resource_prereq_on_tile); - cfg->resource_prereq_on_tile = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { - char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; - if ((cfg->wonder_prereqs[i] != NULL) && - (cfg->wonder_prereqs[i] != default_value)) - free ((void *)cfg->wonder_prereqs[i]); - cfg->wonder_prereqs[i] = NULL; - } - cfg->wonder_prereq_count = defaults->wonder_prereq_count; - - for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { - char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; - if ((cfg->natural_wonder_prereqs[i] != NULL) && - (cfg->natural_wonder_prereqs[i] != default_value)) - free ((void *)cfg->natural_wonder_prereqs[i]); - cfg->natural_wonder_prereqs[i] = NULL; - } - cfg->natural_wonder_prereq_count = defaults->natural_wonder_prereq_count; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { - char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; - if ((cfg->buildable_on_districts[i] != NULL) && - (cfg->buildable_on_districts[i] != default_value)) { - free ((void *)cfg->buildable_on_districts[i]); - } - cfg->buildable_on_districts[i] = NULL; - } - cfg->buildable_on_district_count = defaults->buildable_on_district_count; - cfg->buildable_on_district_id_count = defaults->buildable_on_district_id_count; - cfg->has_buildable_on_districts = defaults->has_buildable_on_districts; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { - char const * default_value = (i < defaults->buildable_adjacent_to_district_count) - ? defaults->buildable_adjacent_to_districts[i] - : NULL; - if ((cfg->buildable_adjacent_to_districts[i] != NULL) && - (cfg->buildable_adjacent_to_districts[i] != default_value)) { - free ((void *)cfg->buildable_adjacent_to_districts[i]); - } - cfg->buildable_adjacent_to_districts[i] = NULL; - } - cfg->buildable_adjacent_to_district_count = defaults->buildable_adjacent_to_district_count; - cfg->buildable_adjacent_to_district_id_count = defaults->buildable_adjacent_to_district_id_count; - cfg->has_buildable_adjacent_to = defaults->has_buildable_adjacent_to; - cfg->has_buildable_adjacent_to_districts = defaults->has_buildable_adjacent_to_districts; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; - if ((cfg->buildable_by_civs[i] != NULL) && - (cfg->buildable_by_civs[i] != default_value)) { - free ((void *)cfg->buildable_by_civs[i]); - } - cfg->buildable_by_civs[i] = NULL; - } - cfg->buildable_by_civ_count = defaults->buildable_by_civ_count; - cfg->has_buildable_by_civs = defaults->has_buildable_by_civs; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) - cfg->buildable_by_civ_traits_ids[i] = -1; - cfg->buildable_by_civ_traits_id_count = defaults->buildable_by_civ_traits_id_count; - cfg->has_buildable_by_civ_traits = defaults->has_buildable_by_civ_traits; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) - cfg->buildable_by_civ_govs_ids[i] = -1; - cfg->buildable_by_civ_govs_id_count = defaults->buildable_by_civ_govs_id_count; - cfg->has_buildable_by_civ_govs = defaults->has_buildable_by_civ_govs; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) - cfg->buildable_by_civ_cultures_ids[i] = -1; - cfg->buildable_by_civ_cultures_id_count = defaults->buildable_by_civ_cultures_id_count; - cfg->has_buildable_by_civ_cultures = defaults->has_buildable_by_civ_cultures; - cfg->buildable_by_war_allies = defaults->buildable_by_war_allies; - cfg->buildable_by_pact_allies = defaults->buildable_by_pact_allies; - - for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { - char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; - if ((cfg->dependent_improvements[i] != NULL) && - (cfg->dependent_improvements[i] != default_value)) { - free ((void *)cfg->dependent_improvements[i]); - } - cfg->dependent_improvements[i] = NULL; - } - cfg->dependent_improvement_max_index = defaults->dependent_improvement_max_index; - - for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { - char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; - if ((cfg->img_paths[i] != NULL) && - (cfg->img_paths[i] != default_value)) { - free ((void *)cfg->img_paths[i]); - } - cfg->img_paths[i] = NULL; - } - cfg->img_path_count = defaults->img_path_count; - - free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); - free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); - free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); - free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); - free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); - free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); - free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); -} - -void -reset_regular_district_configs (void) -{ - for (int i = USED_SPECIAL_DISTRICT_TYPES; i < COUNT_DISTRICT_TYPES; i++) { - if (is->district_configs[i].is_dynamic) - free_dynamic_district_config (&is->district_configs[i]); - } - - for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) - free_special_district_override_strings (&is->district_configs[i], &special_district_defaults[i]); - - memset (is->district_configs, 0, sizeof is->district_configs); - for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) - is->district_configs[i] = special_district_defaults[i]; - - is->special_district_count = USED_SPECIAL_DISTRICT_TYPES; - is->dynamic_district_count = 0; - is->district_count = is->special_district_count; - is->next_custom_dynamic_command_index = 0; -} - -void -reset_wonder_district_configs (void) -{ - for (int i = 0; i < MAX_WONDER_DISTRICT_TYPES; i++) { - if (is->wonder_district_configs[i].is_dynamic) - free_dynamic_wonder_config (&is->wonder_district_configs[i]); - } - - memset (is->wonder_district_configs, 0, sizeof is->wonder_district_configs); - is->wonder_district_count = 0; -} - -void -reset_natural_wonder_configs (void) -{ - for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { - if (is->natural_wonder_configs[i].is_dynamic) - free_dynamic_natural_wonder_config (&is->natural_wonder_configs[i]); - } - - memset (is->natural_wonder_configs, 0, sizeof is->natural_wonder_configs); - for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { - is->natural_wonder_configs[i].adjacent_to = (enum SquareTypes)SQ_INVALID; - is->natural_wonder_configs[i].adjacency_dir = DIR_ZERO; - } - for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) - is->natural_wonder_img_sets[i].img.vtable = NULL; - stable_deinit (&is->natural_wonder_name_to_id); - is->natural_wonder_count = 0; -} - -void -clear_dynamic_district_definitions (void) -{ - reset_regular_district_configs (); - reset_wonder_district_configs (); - reset_natural_wonder_configs (); - reset_ai_candidate_bridge_or_canals (); -} - -void -init_parsed_district_definition (struct parsed_district_definition * def) -{ - memset (def, 0, sizeof *def); - def->img_path_count = -1; - def->defense_bonus_percent = 0; - def->render_strategy = DRS_BY_COUNT; - def->ai_build_strategy = DABS_DISTRICT; - def->buildable_square_types_mask = district_default_buildable_mask (); - def->buildable_adjacent_to_square_types_mask = 0; - def->buildable_without_removal_mask = 0; - def->buildable_on_overlays_mask = 0; - def->buildable_adjacent_to_overlays_mask = 0; - def->buildable_on_rivers = false; - def->buildable_adjacent_to_allows_city = false; -} - -void -free_parsed_district_definition (struct parsed_district_definition * def) -{ - if (def == NULL) - return; - - if (def->display_name != NULL) { - free (def->display_name); - def->display_name = NULL; - } - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - if (def->tooltip != NULL) { - free (def->tooltip); - def->tooltip = NULL; - } - for (int i = 0; i < def->advance_prereq_count; i++) { - if (def->advance_prereqs[i] != NULL) { - free (def->advance_prereqs[i]); - def->advance_prereqs[i] = NULL; - } - } - def->advance_prereq_count = 0; - for (int i = 0; i < ARRAY_LEN (def->buildable_on_districts); i++) { - if (def->buildable_on_districts[i] != NULL) { - free (def->buildable_on_districts[i]); - def->buildable_on_districts[i] = NULL; - } - } - for (int i = 0; i < ARRAY_LEN (def->buildable_adjacent_to_districts); i++) { - if (def->buildable_adjacent_to_districts[i] != NULL) { - free (def->buildable_adjacent_to_districts[i]); - def->buildable_adjacent_to_districts[i] = NULL; - } - } - if (def->obsoleted_by != NULL) { - free (def->obsoleted_by); - def->obsoleted_by = NULL; - } - - for (int i = 0; i < def->resource_prereq_count; i++) { - if (def->resource_prereqs[i] != NULL) { - free (def->resource_prereqs[i]); - def->resource_prereqs[i] = NULL; - } - } - def->resource_prereq_count = 0; - - if (def->resource_prereq_on_tile != NULL) { - free (def->resource_prereq_on_tile); - def->resource_prereq_on_tile = NULL; - } - - for (int i = 0; i < def->wonder_prereq_count; i++) { - if (def->wonder_prereqs[i] != NULL) { - free (def->wonder_prereqs[i]); - def->wonder_prereqs[i] = NULL; - } - } - def->wonder_prereq_count = 0; - - for (int i = 0; i < def->natural_wonder_prereq_count; i++) { - if (def->natural_wonder_prereqs[i] != NULL) { - free (def->natural_wonder_prereqs[i]); - def->natural_wonder_prereqs[i] = NULL; - } - } - def->natural_wonder_prereq_count = 0; - def->buildable_adjacent_to_district_count = 0; - - for (int i = 0; i < def->buildable_by_civ_count; i++) { - if (def->buildable_by_civs[i] != NULL) { - free (def->buildable_by_civs[i]); - def->buildable_by_civs[i] = NULL; - } - } - def->buildable_by_civ_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - - for (int i = 0; i < def->dependent_improvement_max_index; i++) { - if (def->dependent_improvements[i] != NULL) { - free (def->dependent_improvements[i]); - def->dependent_improvements[i] = NULL; - } - } - def->dependent_improvement_max_index = 0; - - for (int i = 0; i < def->img_path_count; i++) { - if (def->img_paths[i] != NULL) { - free (def->img_paths[i]); - def->img_paths[i] = NULL; - } - } - def->img_path_count = 0; - - if (def->generated_resource != NULL) { - free (def->generated_resource); - def->generated_resource = NULL; - } - - free_bonus_entry_list (&def->culture_bonus_extras); - free_bonus_entry_list (&def->science_bonus_extras); - free_bonus_entry_list (&def->food_bonus_extras); - free_bonus_entry_list (&def->gold_bonus_extras); - free_bonus_entry_list (&def->shield_bonus_extras); - free_bonus_entry_list (&def->happiness_bonus_extras); - free_bonus_entry_list (&def->defense_bonus_extras); - - init_parsed_district_definition (def); -} - -int -find_special_district_index_by_name (char const * name) -{ - if (name == NULL) - return -1; - - for (int i = 0; i < is->special_district_count; i++) { - if ((is->district_configs[i].name != NULL) && - (strcmp (is->district_configs[i].name, name) == 0)) - return i; - } - return -1; -} - - -// --------------------------------------------------------------- -// Unit counter system -// --------------------------------------------------------------- - -bool -read_counter_rule_terrain_mask (struct string_slice const * terrain_name, unsigned int * out_mask) -{ - if ((terrain_name == NULL) || (out_mask == NULL)) - return false; - - struct string_slice trimmed = trim_string_slice (terrain_name, 1); - if (trimmed.len <= 0) - return false; - - if (slice_matches_str (&trimmed, "lake") || slice_matches_str (&trimmed, "lakes")) { - *out_mask = district_buildable_lake_mask_bit (); - return true; - } - - enum SquareTypes parsed; - if (! read_tile_terrain_type_value (&trimmed, &parsed)) - return false; - - if (parsed == (enum SquareTypes)SQ_INVALID) - *out_mask = all_square_types_mask () | district_buildable_lake_mask_bit (); - else - *out_mask = square_type_mask_bit (parsed); - - return *out_mask != 0; -} - -struct unit_counter_group * -find_unit_counter_group_by_name (struct c3x_config * cfg, char const * name) -{ - for (int i = 0; i < cfg->count_unit_counter_groups; i++) { - struct unit_counter_group * g = &cfg->unit_counter_groups[i]; - if (g->name && strcmp (g->name, name) == 0) - return g; - } - return NULL; -} - -bool -unit_type_in_group (struct unit_counter_group * g, int type_id) -{ - char const * name = p_bic_data->UnitTypes[type_id].Name; - for (int i = 0; i < g->count_type_ids; i++) - if (strcmp (p_bic_data->UnitTypes[g->type_ids[i]].Name, name) == 0) - return true; - return false; -} - -bool -unit_matches_counter_side (struct c3x_config * cfg, int type_id, - int match, char * group_name) -{ - if (match == UCM_ANY) - return true; - if (match == UCM_GROUP) { - struct unit_counter_group * g = - find_unit_counter_group_by_name (cfg, group_name); - return g && unit_type_in_group (g, type_id); - } - // Direct unit type match: compare by name rather than exact ID so that - // AI strategy duplicates (same name, different ID) are also matched. - return strcmp (p_bic_data->UnitTypes[match].Name, - p_bic_data->UnitTypes[type_id].Name) == 0; -} - -enum recognizable_parse_result -parse_unit_counter_group (char ** p_cursor, - struct error_line ** p_unrecognized_lines, - void * out_group) -{ - char * cur = *p_cursor; - struct string_slice group_name; - if (! (parse_string (&cur, &group_name) && skip_punctuation (&cur, ':'))) - return RPR_PARSE_ERROR; - - struct unit_counter_group * g = out_group; - g->name = extract_slice (&group_name); - g->type_ids = NULL; - g->count_type_ids = 0; - - int any_unrecognized = 0; - struct string_slice type_name; - while (parse_string (&cur, &type_name)) { - // Loop through all unit types with this name, including AI strategy - // duplicates (same name, different ID), which the game creates internally. - int type_id = 0; - bool found_any = false; - while (find_unit_type_id_by_name (&type_name, type_id, &type_id)) { - g->type_ids = realloc (g->type_ids, - (g->count_type_ids + 1) * sizeof (int)); - g->type_ids[g->count_type_ids++] = type_id; - found_any = true; - type_id++; // continue search from next index - } - if (! found_any) { - add_unrecognized_line (p_unrecognized_lines, &type_name); - any_unrecognized = 1; - } - if (! skip_punctuation (&cur, ',')) - break; - } - *p_cursor = cur; - return any_unrecognized ? RPR_UNRECOGNIZED : RPR_OK; -} - -enum recognizable_parse_result -parse_counter_rule (char ** p_cursor, - struct error_line ** p_unrecognized_lines, - void * out_rule) -{ - char * cur = *p_cursor; - struct string_slice attacker_name, vs_token, defender_name; - - if (! parse_string (&cur, &attacker_name)) - return RPR_PARSE_ERROR; - if (! (parse_string (&cur, &vs_token) && - slice_matches_str (&vs_token, "vs"))) - return RPR_PARSE_ERROR; - if (! parse_string (&cur, &defender_name)) - return RPR_PARSE_ERROR; - - struct counter_rule * r = out_rule; - *r = (struct counter_rule) { - .attacker_match = UCM_ANY, - .defender_match = UCM_ANY, - .terrain_mask = 0, - .district_id = -1, - .district_name = NULL, - .self_atk_pct = 100, - .self_def_pct = 100, - .enemy_atk_pct = 100, - .enemy_def_pct = 100, - }; - - if (! slice_matches_str (&attacker_name, "*")) { - int type_id; - if (find_unit_type_id_by_name (&attacker_name, 0, &type_id)) - r->attacker_match = type_id; - else { - r->attacker_match = UCM_GROUP; - r->attacker_group = extract_slice (&attacker_name); - } - } - - if (! slice_matches_str (&defender_name, "*")) { - int type_id; - if (find_unit_type_id_by_name (&defender_name, 0, &type_id)) - r->defender_match = type_id; - else { - r->defender_match = UCM_GROUP; - r->defender_group = extract_slice (&defender_name); - } - } - - struct string_slice token; - while (parse_string (&cur, &token)) { - if (slice_matches_str (&token, "in-city")) { - r->only_in_city = true; - } else if (slice_matches_str (&token, "ignore-terrain")) { - r->ignore_terrain = true; - } else if (slice_matches_str (&token, "self-atk")) { - if (! parse_int (&cur, &r->self_atk_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "self-def")) { - if (! parse_int (&cur, &r->self_def_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "enemy-atk")) { - if (! parse_int (&cur, &r->enemy_atk_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "enemy-def")) { - if (! parse_int (&cur, &r->enemy_def_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "terrain")) { - struct string_slice terrain_name; - if (! parse_string (&cur, &terrain_name)) - return RPR_PARSE_ERROR; - if (! read_counter_rule_terrain_mask (&terrain_name, &r->terrain_mask)) { - add_unrecognized_line (p_unrecognized_lines, &terrain_name); - return RPR_UNRECOGNIZED; - } - } else if (slice_matches_str (&token, "district")) { - struct string_slice district_name; - if (! parse_string (&cur, &district_name)) - return RPR_PARSE_ERROR; - free (r->district_name); - r->district_name = extract_slice (&district_name); - r->district_id = -1; - } else { - break; - } - } - - *p_cursor = cur; - return RPR_OK; -} - -void -apply_counter_rules (struct c3x_config * cfg, - Unit * attacker, Unit * defender, Tile * def_tile, - int * out_attacker_atk, int * out_defender_def, - bool * out_ignore_terrain) -{ - int a_type = attacker->Body.UnitTypeID; - int d_type = defender->Body.UnitTypeID; - bool in_city = Tile_has_city (def_tile); - - int aa = 100, dd = 100; - bool ignore = false; - - for (int i = 0; i < cfg->count_counter_rules; i++) { - struct counter_rule * r = &cfg->counter_rules[i]; - - // Check forward match (attacker=rule attacker side, defender=rule defender side) - // Applied fields: self-atk (attacker attack), enemy-def (defender defense) - bool forward = unit_matches_counter_side (cfg, a_type, - r->attacker_match, r->attacker_group) && - unit_matches_counter_side (cfg, d_type, - r->defender_match, r->defender_group); - - // Check reverse match (attacker=rule defender side, defender=rule attacker side) - // Applied fields: self-def (rule attacker side is now defending), enemy-atk (rule defender side is now attacking) - bool reverse = unit_matches_counter_side (cfg, a_type, - r->defender_match, r->defender_group) && - unit_matches_counter_side (cfg, d_type, - r->attacker_match, r->attacker_group); - - if (! forward && ! reverse) - continue; - - // Environment checks are based on the defender's tile - if (r->only_in_city && ! in_city) - continue; - if (r->terrain_mask != 0 && - ! tile_matches_square_type_mask (def_tile, r->terrain_mask)) - continue; - if (r->district_name != NULL && - ! ((r->district_id != -1) && - cfg->enable_districts && - district_is_complete (def_tile, r->district_id))) - continue; - - if (forward) { - aa = aa * r->self_atk_pct / 100; // self-atk: attacker attack - dd = dd * r->enemy_def_pct / 100; // enemy-def: defender defense - } - if (reverse) { - aa = aa * r->enemy_atk_pct / 100; // enemy-atk: rule defender side now acts as attacker - dd = dd * r->self_def_pct / 100; // self-def: rule attacker side now acts as defender - } - if (forward || reverse) - ignore = ignore || r->ignore_terrain; - } - - *out_attacker_atk = aa; - *out_defender_def = dd; - *out_ignore_terrain = ignore; -} - -bool -district_is_included_by_final_config (int district_id) -{ - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - if (! is->current_config.enable_districts) - return false; - - switch (district_id) { - case NEIGHBORHOOD_DISTRICT_ID: return is->current_config.enable_neighborhood_districts; - case WONDER_DISTRICT_ID: return is->current_config.enable_wonder_districts; - case DISTRIBUTION_HUB_DISTRICT_ID: return is->current_config.enable_distribution_hub_districts; - case AERODROME_DISTRICT_ID: return is->current_config.enable_aerodrome_districts; - case PORT_DISTRICT_ID: return is->current_config.enable_port_districts; - case CENTRAL_RAIL_HUB_DISTRICT_ID: return is->current_config.enable_central_rail_hub_districts; - case ENERGY_GRID_DISTRICT_ID: return is->current_config.enable_energy_grid_districts; - case BRIDGE_DISTRICT_ID: return is->current_config.enable_bridge_districts; - case CANAL_DISTRICT_ID: return is->current_config.enable_canal_districts; - case GREAT_WALL_DISTRICT_ID: return is->current_config.enable_great_wall_districts; - default: return true; - } -} - -bool -ensure_culture_variant_art (struct district_config * cfg, int section_start_line) -{ - if ((cfg == NULL) || (! cfg->vary_img_by_culture)) - return true; - - const int required_variants = 5; - const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); - if (cfg->img_path_count <= 0) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] load_dynamic_district_configs: district \"%s\" requires culture-specific art but none provided (line %d)\n", cfg->name, section_start_line); - (*p_OutputDebugStringA) (ss); - return false; - } - - while ((cfg->img_path_count < required_variants) && - (cfg->img_path_count < max_img_paths)) { - cfg->img_paths[cfg->img_path_count] = strdup (cfg->img_paths[0]); - cfg->img_path_count += 1; - } - - return true; -} - -bool -parse_config_string_list (char * value_text, - char ** dest, - int capacity, - int * out_count, - struct error_line ** parse_errors, - int line_number, - char const * key) -{ - for (int i = 0; i < capacity; i++) { - if (dest[i] != NULL) { - free (dest[i]); - dest[i] = NULL; - } - } - *out_count = 0; - - if (value_text == NULL || *value_text == '\0') - return true; - - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - if (*cursor == '\0') - break; - - char * item_start; - char * item_end; - if (*cursor == '"') { - cursor++; - item_start = cursor; - while ((*cursor != '\0') && (*cursor != '"')) - cursor++; - if (*cursor != '"') { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (missing closing quote)", line_number, key); - err->text[(sizeof err->text) - 1] = '\0'; - for (int j = 0; j < capacity; j++) { - if (dest[j] != NULL) { - free (dest[j]); - dest[j] = NULL; - } - } - *out_count = 0; - return false; - } - item_end = cursor; - cursor++; - } else { - item_start = cursor; - while ((*cursor != '\0') && (*cursor != ',')) - cursor++; - item_end = cursor; - } - - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - - int item_len = item_end - item_start; - if (item_len > 0) { - if (*out_count < capacity) { - char * copy = malloc (item_len + 1); - if (copy == NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (out of memory)", line_number, key); - err->text[(sizeof err->text) - 1] = '\0'; - for (int j = 0; j < capacity; j++) { - if (dest[j] != NULL) { - free (dest[j]); - dest[j] = NULL; - } - } - *out_count = 0; - return false; - } - memcpy (copy, item_start, item_len); - copy[item_len] = '\0'; - dest[*out_count] = copy; - *out_count += 1; - } - } - - while (is_space_char (*cursor)) - cursor++; - - if (*cursor == ',') { - cursor++; - continue; - } - if (*cursor == '\0') - break; - } - - return true; -} - -bool -parse_buildable_square_type_mask (struct string_slice const * value, - unsigned int * out_mask, - struct error_line ** parse_errors, - int line_number, - char const * key_name, - bool * out_allow_city) -{ - char * value_text = trim_and_extract_slice (value, 0); - unsigned int mask = 0; - int entry_count = 0; - bool allow_city = false; - bool allow_city_token = (key_name != NULL) && (strcmp (key_name, "buildable_adjacent_to") == 0); - if (key_name == NULL) - key_name = "buildable_on"; - - if (value_text != NULL) { - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - char * item_start = cursor; - while ((*cursor != '\0') && (*cursor != ',')) - cursor++; - - char * item_end = cursor; - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - - struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; - if (item_slice.len > 0) { - if (slice_matches_str (&item_slice, "city")) { - if (! allow_city_token) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - allow_city = true; - entry_count += 1; - } else if (slice_matches_str (&item_slice, "lake")) { - mask |= district_buildable_lake_mask_bit (); - entry_count += 1; - } else { - enum SquareTypes parsed; - if (read_tile_terrain_type_value (&item_slice, &parsed)) { - if ((parsed == SQ_RIVER) || - (parsed == SQ_Forest) || - (parsed == SQ_Jungle) || - (parsed == SQ_Swamp)) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - if (parsed == (enum SquareTypes)SQ_INVALID) { - mask = all_square_types_mask (); - mask &= ~(square_type_mask_bit (SQ_Forest) | - square_type_mask_bit (SQ_Jungle) | - square_type_mask_bit (SQ_Swamp)); - } else - mask |= square_type_mask_bit (parsed); - entry_count += 1; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - } - } - - if (*cursor == ',') { - cursor++; - continue; - } - break; - } - } - - if (value_text != NULL) - free (value_text); - - if ((entry_count == 0) || ((mask == 0) && ! allow_city)) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one tile terrain type)", line_number, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - return false; - } - - *out_mask = mask; - if (out_allow_city != NULL) - *out_allow_city = allow_city; - return true; -} - -bool -parse_buildable_overlay_mask (struct string_slice const * value, - unsigned int * out_mask, - struct error_line ** parse_errors, - int line_number, - char const * key_name) -{ - char * value_text = trim_and_extract_slice (value, 0); - unsigned int mask = 0; - unsigned int allowed_mask = (DOM_MINE | DOM_IRRIGATION | DOM_FORTRESS | DOM_BARRICADE | - DOM_OUTPOST | DOM_RADAR_TOWER | DOM_JUNGLE | DOM_FOREST | - DOM_SWAMP | DOM_RIVER | DOM_AIRFIELD); - int entry_count = 0; - - if (key_name == NULL) - key_name = "buildable_without_removal"; - if (strcmp (key_name, "buildable_without_removal") == 0) - allowed_mask = (DOM_JUNGLE | DOM_FOREST | DOM_SWAMP); - else if (strcmp (key_name, "buildable_on_overlays") == 0) - allowed_mask &= ~DOM_RIVER; - - if (value_text != NULL) { - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - char * item_start = cursor; - while ((*cursor != '\0') && (*cursor != ',')) - cursor++; - - char * item_end = cursor; - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - - struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; - if (item_slice.len > 0) { - unsigned int bit = 0; - if (slice_matches_str (&item_slice, "mine")) { - bit = DOM_MINE; - } else if (slice_matches_str (&item_slice, "irrigation")) { - bit = DOM_IRRIGATION; - } else if (slice_matches_str (&item_slice, "fortress")) { - bit = DOM_FORTRESS; - } else if (slice_matches_str (&item_slice, "barricade")) { - bit = DOM_BARRICADE; - } else if (slice_matches_str (&item_slice, "outpost")) { - bit = DOM_OUTPOST; - } else if (slice_matches_str (&item_slice, "radar-tower")) { - bit = DOM_RADAR_TOWER; - } else if (slice_matches_str (&item_slice, "airfield")) { - bit = DOM_AIRFIELD; - } else if (slice_matches_str (&item_slice, "jungle")) { - bit = DOM_JUNGLE; - } else if (slice_matches_str (&item_slice, "jungles")) { - bit = DOM_JUNGLE; - } else if (slice_matches_str (&item_slice, "forest")) { - bit = DOM_FOREST; - } else if (slice_matches_str (&item_slice, "forests")) { - bit = DOM_FOREST; - } else if (slice_matches_str (&item_slice, "marsh")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "marshes")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "swamp")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "swamps")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "river")) { - bit = DOM_RIVER; - } else if (slice_matches_str (&item_slice, "rivers")) { - bit = DOM_RIVER; - } - - if (bit != 0) { - if ((allowed_mask & bit) == 0) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - mask |= bit; - entry_count += 1; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - } - - if (*cursor == ',') { - cursor++; - continue; - } - break; - } - } - - if (value_text != NULL) - free (value_text); - - if ((entry_count == 0) || (mask == 0)) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one overlay)", line_number, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - return false; - } - - *out_mask = mask; - return true; -} - -bool -parse_district_bonus_entries (struct string_slice const * value, - int * out_base_bonus, - struct district_bonus_list * out_extras, - struct error_line ** parse_errors, - int line_number, - struct string_slice const * key) -{ - if ((out_base_bonus == NULL) || (out_extras == NULL)) { - add_key_parse_error (parse_errors, line_number, key, value, "(invalid bonus target)"); - return false; - } - - char * value_text = trim_and_extract_slice (value, 0); - free_bonus_entry_list (out_extras); - *out_base_bonus = 0; - - if ((value_text == NULL) || (*value_text == '\0')) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); - free (value_text); - return false; - } - - bool got_base = false; - int base_bonus = 0; - - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - if (*cursor == '\0') - break; - - char * item_start = cursor; - bool in_quotes = false; - while (*cursor != '\0') { - if (*cursor == '"') - in_quotes = ! in_quotes; - if ((! in_quotes) && (*cursor == ',')) - break; - cursor++; - } - - char * item_end = cursor; - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - while ((item_start < item_end) && is_space_char (*item_start)) - item_start++; - - if (item_end > item_start) { - struct string_slice item = { .str = item_start, .len = (int)(item_end - item_start) }; - - if (! got_base) { - struct string_slice base_slice = trim_string_slice (&item, 0); - if (! read_int (&base_slice, &base_bonus)) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - got_base = true; - } else { - char * colon = NULL; - in_quotes = false; - for (char * p = item_start; p < item_end; p++) { - if (*p == '"') - in_quotes = ! in_quotes; - if ((! in_quotes) && (*p == ':')) { - colon = p; - break; - } - } - - if (colon == NULL) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected \"name: bonus\" entry)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - struct string_slice name_slice = { .str = item_start, .len = (int)(colon - item_start) }; - struct string_slice bonus_slice = { .str = colon + 1, .len = (int)(item_end - (colon + 1)) }; - struct string_slice trimmed_name = trim_string_slice (&name_slice, 1); - struct string_slice trimmed_bonus = trim_string_slice (&bonus_slice, 0); - - if (trimmed_name.len <= 0) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus name)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - int bonus_value = 0; - if (! read_int (&trimmed_bonus, &bonus_value)) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus value)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - if (out_extras->count >= MAX_DISTRICT_BONUS_ENTRIES) { - add_key_parse_error (parse_errors, line_number, key, value, "(too many bonus entries)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - struct district_bonus_entry * entry = &out_extras->entries[out_extras->count++]; - entry->bonus = bonus_value; - entry->building_id = -1; - entry->building_name = NULL; - - enum SquareTypes parsed_type; - if (read_tile_terrain_type_value (&trimmed_name, &parsed_type)) { - entry->type = DBET_TILE; - entry->tile_type = parsed_type; - } else { - entry->type = DBET_BUILDING; - entry->tile_type = (enum SquareTypes)SQ_INVALID; - entry->building_name = extract_slice (&trimmed_name); - } - } - } - - if (*cursor == ',') { - cursor++; - continue; - } - if (*cursor == '\0') - break; - } - - free (value_text); - - if (! got_base) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); - free_bonus_entry_list (out_extras); - return false; - } - - *out_base_bonus = base_bonus; - return true; -} - -bool -override_special_district_from_definition (struct parsed_district_definition * def, int section_start_line) -{ - if ((! def->has_name) || (def->name == NULL)) - return false; - - int index = find_special_district_index_by_name (def->name); - if (index < 0) - return false; - - struct district_config * cfg = &is->district_configs[index]; - struct district_config const * defaults = &special_district_defaults[index]; - - free (def->name); - def->name = NULL; - def->has_name = false; - - if (def->has_display_name) { - if ((cfg->display_name != NULL) && - (cfg->display_name != cfg->name) && - (cfg->display_name != defaults->display_name)) - free ((void *)cfg->display_name); - cfg->display_name = def->display_name; - def->display_name = NULL; - } - - if (def->has_tooltip) { - if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) - free ((void *)cfg->tooltip); - cfg->tooltip = def->tooltip; - def->tooltip = NULL; - } - - if (def->has_advance_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { - char const * default_value = (i < defaults->advance_prereq_count) ? defaults->advance_prereqs[i] : NULL; - if ((cfg->advance_prereqs[i] != NULL) && - (cfg->advance_prereqs[i] != default_value)) - free ((void *)cfg->advance_prereqs[i]); - cfg->advance_prereqs[i] = NULL; - } - - cfg->advance_prereq_count = def->advance_prereq_count; - const int max_entries = ARRAY_LEN (cfg->advance_prereqs); - if (cfg->advance_prereq_count > max_entries) - cfg->advance_prereq_count = max_entries; - for (int i = 0; i < cfg->advance_prereq_count; i++) { - cfg->advance_prereqs[i] = def->advance_prereqs[i]; - def->advance_prereqs[i] = NULL; - } - def->advance_prereq_count = 0; - } - - if (def->has_obsoleted_by) { - if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) - free ((void *)cfg->obsoleted_by); - cfg->obsoleted_by = def->obsoleted_by; - def->obsoleted_by = NULL; - } - - if (def->has_resource_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { - char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; - if ((cfg->resource_prereqs[i] != NULL) && - (cfg->resource_prereqs[i] != default_value)) - free ((void *)cfg->resource_prereqs[i]); - cfg->resource_prereqs[i] = NULL; - } - - cfg->resource_prereq_count = def->resource_prereq_count; - const int max_entries = ARRAY_LEN (cfg->resource_prereqs); - if (cfg->resource_prereq_count > max_entries) - cfg->resource_prereq_count = max_entries; - for (int i = 0; i < cfg->resource_prereq_count; i++) { - cfg->resource_prereqs[i] = def->resource_prereqs[i]; - def->resource_prereqs[i] = NULL; - } - } - - if (def->has_resource_prereq_on_tile) { - if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) - free ((void *)cfg->resource_prereq_on_tile); - cfg->resource_prereq_on_tile = def->resource_prereq_on_tile; - def->resource_prereq_on_tile = NULL; - } - - if (def->has_wonder_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { - char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; - if ((cfg->wonder_prereqs[i] != NULL) && - (cfg->wonder_prereqs[i] != default_value)) - free ((void *)cfg->wonder_prereqs[i]); - cfg->wonder_prereqs[i] = NULL; - } - - cfg->wonder_prereq_count = def->wonder_prereq_count; - const int max_entries = ARRAY_LEN (cfg->wonder_prereqs); - if (cfg->wonder_prereq_count > max_entries) - cfg->wonder_prereq_count = max_entries; - for (int i = 0; i < cfg->wonder_prereq_count; i++) { - cfg->wonder_prereqs[i] = def->wonder_prereqs[i]; - def->wonder_prereqs[i] = NULL; - } - } - - if (def->has_natural_wonder_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { - char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; - if ((cfg->natural_wonder_prereqs[i] != NULL) && - (cfg->natural_wonder_prereqs[i] != default_value)) - free ((void *)cfg->natural_wonder_prereqs[i]); - cfg->natural_wonder_prereqs[i] = NULL; - } - - cfg->natural_wonder_prereq_count = def->natural_wonder_prereq_count; - const int max_entries = ARRAY_LEN (cfg->natural_wonder_prereqs); - if (cfg->natural_wonder_prereq_count > max_entries) - cfg->natural_wonder_prereq_count = max_entries; - for (int i = 0; i < cfg->natural_wonder_prereq_count; i++) { - cfg->natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; - def->natural_wonder_prereqs[i] = NULL; - } - } - - if (def->has_buildable_on_districts) { - for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { - char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; - if ((cfg->buildable_on_districts[i] != NULL) && - (cfg->buildable_on_districts[i] != default_value)) - free ((void *)cfg->buildable_on_districts[i]); - cfg->buildable_on_districts[i] = NULL; - } - - cfg->buildable_on_district_count = def->buildable_on_district_count; - const int max_entries = ARRAY_LEN (cfg->buildable_on_districts); - if (cfg->buildable_on_district_count > max_entries) - cfg->buildable_on_district_count = max_entries; - for (int i = 0; i < cfg->buildable_on_district_count; i++) { - cfg->buildable_on_districts[i] = def->buildable_on_districts[i]; - def->buildable_on_districts[i] = NULL; - } - cfg->buildable_on_district_id_count = 0; - cfg->has_buildable_on_districts = true; - } - - if (def->has_buildable_adjacent_to_districts) { - for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { - char const * default_value = (i < defaults->buildable_adjacent_to_district_count) - ? defaults->buildable_adjacent_to_districts[i] - : NULL; - if ((cfg->buildable_adjacent_to_districts[i] != NULL) && - (cfg->buildable_adjacent_to_districts[i] != default_value)) - free ((void *)cfg->buildable_adjacent_to_districts[i]); - cfg->buildable_adjacent_to_districts[i] = NULL; - } - - cfg->buildable_adjacent_to_district_count = def->buildable_adjacent_to_district_count; - const int max_entries = ARRAY_LEN (cfg->buildable_adjacent_to_districts); - if (cfg->buildable_adjacent_to_district_count > max_entries) - cfg->buildable_adjacent_to_district_count = max_entries; - for (int i = 0; i < cfg->buildable_adjacent_to_district_count; i++) { - cfg->buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; - def->buildable_adjacent_to_districts[i] = NULL; - } - cfg->buildable_adjacent_to_district_id_count = 0; - cfg->has_buildable_adjacent_to_districts = true; - } - - if (def->has_buildable_by_civs) { - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; - if ((cfg->buildable_by_civs[i] != NULL) && - (cfg->buildable_by_civs[i] != default_value)) - free ((void *)cfg->buildable_by_civs[i]); - cfg->buildable_by_civs[i] = NULL; - } - cfg->buildable_by_civ_count = def->buildable_by_civ_count; - const int max_civ_names = ARRAY_LEN (cfg->buildable_by_civs); - if (cfg->buildable_by_civ_count > max_civ_names) - cfg->buildable_by_civ_count = max_civ_names; - for (int i = 0; i < cfg->buildable_by_civ_count; i++) { - cfg->buildable_by_civs[i] = def->buildable_by_civs[i]; - def->buildable_by_civs[i] = NULL; - } - cfg->has_buildable_by_civs = true; - } - - if (def->has_buildable_by_civ_traits) { - cfg->buildable_by_civ_traits_id_count = def->buildable_by_civ_traits_id_count; - const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_traits_ids); - if (cfg->buildable_by_civ_traits_id_count > max_entries) - cfg->buildable_by_civ_traits_id_count = max_entries; - for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) - cfg->buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; - cfg->has_buildable_by_civ_traits = true; - } - - if (def->has_buildable_by_civ_govs) { - cfg->buildable_by_civ_govs_id_count = def->buildable_by_civ_govs_id_count; - const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_govs_ids); - if (cfg->buildable_by_civ_govs_id_count > max_entries) - cfg->buildable_by_civ_govs_id_count = max_entries; - for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) - cfg->buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; - cfg->has_buildable_by_civ_govs = true; - } - - if (def->has_buildable_by_civ_cultures) { - cfg->buildable_by_civ_cultures_id_count = def->buildable_by_civ_cultures_id_count; - const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); - if (cfg->buildable_by_civ_cultures_id_count > max_entries) - cfg->buildable_by_civ_cultures_id_count = max_entries; - for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) - cfg->buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; - cfg->has_buildable_by_civ_cultures = true; - } - - if (def->has_buildable_by_war_allies) - cfg->buildable_by_war_allies = def->buildable_by_war_allies; - if (def->has_buildable_by_pact_allies) - cfg->buildable_by_pact_allies = def->buildable_by_pact_allies; - - if (def->has_allow_multiple) - cfg->allow_multiple = def->allow_multiple; - if (def->has_vary_img_by_era) - cfg->vary_img_by_era = def->vary_img_by_era; - if (def->has_vary_img_by_culture) - cfg->vary_img_by_culture = def->vary_img_by_culture; - if (def->has_render_strategy) - cfg->render_strategy = def->render_strategy; - if (def->has_ai_build_strategy) - cfg->ai_build_strategy = def->ai_build_strategy; - if (def->has_align_to_coast) - cfg->align_to_coast = def->align_to_coast; - if (def->has_draw_over_resources) - cfg->draw_over_resources = def->draw_over_resources; - if (def->has_allow_irrigation_from) - cfg->allow_irrigation_from = def->allow_irrigation_from; - if (def->has_auto_add_road) - cfg->auto_add_road = def->auto_add_road; - if (def->has_auto_add_railroad) - cfg->auto_add_railroad = def->auto_add_railroad; - if (def->has_custom_width) - cfg->custom_width = def->custom_width; - if (def->has_custom_height) - cfg->custom_height = def->custom_height; - if (def->has_x_offset) - cfg->x_offset = def->x_offset; - if (def->has_y_offset) - cfg->y_offset = def->y_offset; - if (def->has_btn_tile_sheet_column) - cfg->btn_tile_sheet_column = def->btn_tile_sheet_column; - if (def->has_btn_tile_sheet_row) - cfg->btn_tile_sheet_row = def->btn_tile_sheet_row; - if (def->has_defense_bonus_percent) { - cfg->defense_bonus_percent = def->defense_bonus_percent; - free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); - move_bonus_entry_list (&cfg->defense_bonus_extras, &def->defense_bonus_extras); - } - if (def->has_heal_units_in_one_turn) - cfg->heal_units_in_one_turn = def->heal_units_in_one_turn; - if (def->has_impassible) - cfg->impassible = def->impassible; - if (def->has_impassible_to_wheeled) - cfg->impassible_to_wheeled = def->impassible_to_wheeled; - if (def->has_culture_bonus) { - cfg->culture_bonus = def->culture_bonus; - free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); - move_bonus_entry_list (&cfg->culture_bonus_extras, &def->culture_bonus_extras); - } - if (def->has_science_bonus) { - cfg->science_bonus = def->science_bonus; - free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); - move_bonus_entry_list (&cfg->science_bonus_extras, &def->science_bonus_extras); - } - if (def->has_food_bonus) { - cfg->food_bonus = def->food_bonus; - free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); - move_bonus_entry_list (&cfg->food_bonus_extras, &def->food_bonus_extras); - } - if (def->has_gold_bonus) { - cfg->gold_bonus = def->gold_bonus; - free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); - move_bonus_entry_list (&cfg->gold_bonus_extras, &def->gold_bonus_extras); - } - if (def->has_shield_bonus) { - cfg->shield_bonus = def->shield_bonus; - free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); - move_bonus_entry_list (&cfg->shield_bonus_extras, &def->shield_bonus_extras); - } - if (def->has_happiness_bonus) { - cfg->happiness_bonus = def->happiness_bonus; - free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); - move_bonus_entry_list (&cfg->happiness_bonus_extras, &def->happiness_bonus_extras); - } - if (def->has_buildable_on) - cfg->buildable_square_types_mask = def->buildable_square_types_mask; - if (def->has_buildable_adjacent_to) { - cfg->buildable_adjacent_to_square_types_mask = def->buildable_adjacent_to_square_types_mask; - cfg->has_buildable_adjacent_to = true; - cfg->buildable_adjacent_to_allows_city = def->buildable_adjacent_to_allows_city; - } - if (def->has_buildable_without_removal) { - cfg->buildable_without_removal_mask = def->buildable_without_removal_mask; - cfg->has_buildable_without_removal = true; - } - if (def->has_buildable_on_overlays) { - cfg->buildable_on_overlays_mask = def->buildable_on_overlays_mask; - cfg->has_buildable_on_overlays = true; - } - if (def->has_buildable_on_rivers) - cfg->buildable_on_rivers = def->buildable_on_rivers; - if (def->has_buildable_adjacent_to_overlays) { - cfg->buildable_adjacent_to_overlays_mask = def->buildable_adjacent_to_overlays_mask; - cfg->has_buildable_adjacent_to_overlays = true; - } - - if (def->has_generated_resource) { - if ((cfg->generated_resource != NULL) && (cfg->generated_resource != defaults->generated_resource)) - free ((void *)cfg->generated_resource); - cfg->generated_resource = def->generated_resource; - def->generated_resource = NULL; - cfg->generated_resource_flags = def->generated_resource_flags; - cfg->generated_resource_id = -1; - } - - if (def->has_dependent_improvements) { - for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { - char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; - if ((cfg->dependent_improvements[i] != NULL) && - (cfg->dependent_improvements[i] != default_value)) - free ((void *)cfg->dependent_improvements[i]); - cfg->dependent_improvements[i] = NULL; - } - - cfg->dependent_improvement_max_index = def->dependent_improvement_max_index; - const int max_entries = ARRAY_LEN (cfg->dependent_improvements); - if (cfg->dependent_improvement_max_index > max_entries) - cfg->dependent_improvement_max_index = max_entries; - for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { - cfg->dependent_improvements[i] = def->dependent_improvements[i]; - def->dependent_improvements[i] = NULL; - } - if (! def->has_img_column_count) { - cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->dependent_improvement_max_index + 1); - cfg->has_img_column_count_override = false; - } - } - - if (def->has_img_paths) { - for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { - char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; - if ((cfg->img_paths[i] != NULL) && - (cfg->img_paths[i] != default_value)) - free ((void *)cfg->img_paths[i]); - cfg->img_paths[i] = NULL; - } - - cfg->img_path_count = def->img_path_count; - const int max_img_paths = ARRAY_LEN (cfg->img_paths); - if (cfg->img_path_count > max_img_paths) - cfg->img_path_count = max_img_paths; - for (int i = 0; i < cfg->img_path_count; i++) { - cfg->img_paths[i] = def->img_paths[i]; - def->img_paths[i] = NULL; - } - } - - if (def->has_img_column_count) { - cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->img_column_count); - cfg->has_img_column_count_override = true; - } - - if (! ensure_culture_variant_art (cfg, section_start_line)) { - free_special_district_override_strings (cfg, defaults); - *cfg = *defaults; - return false; - } - - return true; -} - -bool -add_dynamic_district_from_definition (struct parsed_district_definition * def, int section_start_line) -{ - if ((! def->has_name) || (def->name == NULL)) - return false; - - if ((! def->has_img_paths) || (def->img_path_count <= 0)) - return false; - - int existing_index = -1; - for (int i = is->special_district_count; i < is->district_count; i++) { - if ((is->district_configs[i].name != NULL) && - (strcmp (is->district_configs[i].name, def->name) == 0)) { - existing_index = i; - break; - } - } - - bool reusing_existing = existing_index >= 0; - int dest_index = reusing_existing ? existing_index : (is->special_district_count + is->dynamic_district_count); - - if ((! reusing_existing) && (dest_index >= COUNT_DISTRICT_TYPES)) - return false; - - enum Unit_Command_Values preserved_command = 0; - if (reusing_existing) - preserved_command = is->district_configs[dest_index].command; - - struct district_config new_cfg; - memset (&new_cfg, 0, sizeof new_cfg); - new_cfg.is_dynamic = true; - - new_cfg.name = def->name; - def->name = NULL; - if (def->has_display_name) { - new_cfg.display_name = def->display_name; - if (new_cfg.display_name == NULL) - new_cfg.display_name = new_cfg.name; - def->display_name = NULL; - } else { - new_cfg.display_name = new_cfg.name; - } - - if (def->has_tooltip) { - new_cfg.tooltip = def->tooltip; - def->tooltip = NULL; - } else if (new_cfg.name != NULL) { - char buffer[128]; - snprintf (buffer, sizeof buffer, "Build %s", new_cfg.name); - new_cfg.tooltip = strdup (buffer); - } - - if (def->has_advance_prereqs) { - new_cfg.advance_prereq_count = def->advance_prereq_count; - const int max_entries = ARRAY_LEN (new_cfg.advance_prereqs); - if (new_cfg.advance_prereq_count > max_entries) - new_cfg.advance_prereq_count = max_entries; - for (int i = 0; i < new_cfg.advance_prereq_count; i++) { - new_cfg.advance_prereqs[i] = def->advance_prereqs[i]; - def->advance_prereqs[i] = NULL; - } - def->advance_prereq_count = 0; - } - - if (def->has_obsoleted_by) { - new_cfg.obsoleted_by = def->obsoleted_by; - def->obsoleted_by = NULL; - } - - new_cfg.resource_prereq_count = def->has_resource_prereqs ? def->resource_prereq_count : 0; - const int max_resource_entries = ARRAY_LEN (new_cfg.resource_prereqs); - if (new_cfg.resource_prereq_count > max_resource_entries) - new_cfg.resource_prereq_count = max_resource_entries; - for (int i = 0; i < new_cfg.resource_prereq_count; i++) { - new_cfg.resource_prereqs[i] = def->resource_prereqs[i]; - def->resource_prereqs[i] = NULL; - } - - if (def->has_resource_prereq_on_tile) { - new_cfg.resource_prereq_on_tile = def->resource_prereq_on_tile; - def->resource_prereq_on_tile = NULL; - } - - new_cfg.wonder_prereq_count = def->has_wonder_prereqs ? def->wonder_prereq_count : 0; - const int max_required_wonders = ARRAY_LEN (new_cfg.wonder_prereqs); - if (new_cfg.wonder_prereq_count > max_required_wonders) - new_cfg.wonder_prereq_count = max_required_wonders; - for (int i = 0; i < new_cfg.wonder_prereq_count; i++) { - new_cfg.wonder_prereqs[i] = def->wonder_prereqs[i]; - def->wonder_prereqs[i] = NULL; - } - - new_cfg.natural_wonder_prereq_count = def->has_natural_wonder_prereqs ? def->natural_wonder_prereq_count : 0; - const int max_required_natural_wonders = ARRAY_LEN (new_cfg.natural_wonder_prereqs); - if (new_cfg.natural_wonder_prereq_count > max_required_natural_wonders) - new_cfg.natural_wonder_prereq_count = max_required_natural_wonders; - for (int i = 0; i < new_cfg.natural_wonder_prereq_count; i++) { - new_cfg.natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; - def->natural_wonder_prereqs[i] = NULL; - } - - new_cfg.buildable_on_district_count = def->has_buildable_on_districts ? def->buildable_on_district_count : 0; - const int max_buildable_on_districts = ARRAY_LEN (new_cfg.buildable_on_districts); - if (new_cfg.buildable_on_district_count > max_buildable_on_districts) - new_cfg.buildable_on_district_count = max_buildable_on_districts; - for (int i = 0; i < new_cfg.buildable_on_district_count; i++) { - new_cfg.buildable_on_districts[i] = def->buildable_on_districts[i]; - def->buildable_on_districts[i] = NULL; - } - new_cfg.buildable_on_district_id_count = 0; - new_cfg.has_buildable_on_districts = def->has_buildable_on_districts; - - new_cfg.buildable_adjacent_to_district_count = def->has_buildable_adjacent_to_districts ? def->buildable_adjacent_to_district_count : 0; - const int max_adjacent_to_districts = ARRAY_LEN (new_cfg.buildable_adjacent_to_districts); - if (new_cfg.buildable_adjacent_to_district_count > max_adjacent_to_districts) - new_cfg.buildable_adjacent_to_district_count = max_adjacent_to_districts; - for (int i = 0; i < new_cfg.buildable_adjacent_to_district_count; i++) { - new_cfg.buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; - def->buildable_adjacent_to_districts[i] = NULL; - } - new_cfg.buildable_adjacent_to_district_id_count = 0; - new_cfg.has_buildable_adjacent_to_districts = def->has_buildable_adjacent_to_districts; - - new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; - const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); - if (new_cfg.buildable_by_civ_count > max_civ_names) - new_cfg.buildable_by_civ_count = max_civ_names; - for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { - new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; - def->buildable_by_civs[i] = NULL; - } - - new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; - - new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; - const int max_buildable_traits = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); - if (new_cfg.buildable_by_civ_traits_id_count > max_buildable_traits) - new_cfg.buildable_by_civ_traits_id_count = max_buildable_traits; - for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) - new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; - new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; - - new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; - const int max_buildable_govs = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); - if (new_cfg.buildable_by_civ_govs_id_count > max_buildable_govs) - new_cfg.buildable_by_civ_govs_id_count = max_buildable_govs; - for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) - new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; - new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; - - new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; - const int max_buildable_cultures = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); - if (new_cfg.buildable_by_civ_cultures_id_count > max_buildable_cultures) - new_cfg.buildable_by_civ_cultures_id_count = max_buildable_cultures; - for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) - new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; - new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; - - new_cfg.buildable_by_war_allies = def->has_buildable_by_war_allies ? def->buildable_by_war_allies : false; - new_cfg.buildable_by_pact_allies = def->has_buildable_by_pact_allies ? def->buildable_by_pact_allies : false; - - new_cfg.allow_multiple = def->has_allow_multiple ? def->allow_multiple : false; - new_cfg.vary_img_by_era = def->has_vary_img_by_era ? def->vary_img_by_era : false; - new_cfg.vary_img_by_culture = def->has_vary_img_by_culture ? def->vary_img_by_culture : false; - new_cfg.render_strategy = def->has_render_strategy ? def->render_strategy : DRS_BY_COUNT; - new_cfg.ai_build_strategy = def->has_ai_build_strategy ? def->ai_build_strategy : DABS_DISTRICT; - new_cfg.align_to_coast = def->has_align_to_coast ? def->align_to_coast : false; - new_cfg.draw_over_resources = def->has_draw_over_resources ? def->draw_over_resources : false; - new_cfg.allow_irrigation_from = def->has_allow_irrigation_from ? def->allow_irrigation_from : false; - new_cfg.auto_add_road = def->has_auto_add_road ? def->auto_add_road : false; - new_cfg.auto_add_railroad = def->has_auto_add_railroad ? def->auto_add_railroad : false; - new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; - new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; - new_cfg.x_offset = def->has_x_offset ? def->x_offset : 0; - new_cfg.y_offset = def->has_y_offset ? def->y_offset : 0; - new_cfg.btn_tile_sheet_column = def->has_btn_tile_sheet_column ? def->btn_tile_sheet_column : 0; - new_cfg.btn_tile_sheet_row = def->has_btn_tile_sheet_row ? def->btn_tile_sheet_row : 0; - new_cfg.defense_bonus_percent = def->has_defense_bonus_percent ? def->defense_bonus_percent : 0; - new_cfg.heal_units_in_one_turn = def->has_heal_units_in_one_turn ? def->heal_units_in_one_turn : false; - new_cfg.impassible = def->has_impassible ? def->impassible : false; - new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; - new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; - new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; - new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; - new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; - new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; - new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; - new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); - new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; - new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; - new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; - new_cfg.buildable_without_removal_mask = def->has_buildable_without_removal ? def->buildable_without_removal_mask : 0; - new_cfg.has_buildable_without_removal = def->has_buildable_without_removal; - new_cfg.buildable_on_overlays_mask = def->has_buildable_on_overlays ? def->buildable_on_overlays_mask : 0; - new_cfg.has_buildable_on_overlays = def->has_buildable_on_overlays; - new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; - new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; - new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; - - if (def->has_culture_bonus) - move_bonus_entry_list (&new_cfg.culture_bonus_extras, &def->culture_bonus_extras); - if (def->has_science_bonus) - move_bonus_entry_list (&new_cfg.science_bonus_extras, &def->science_bonus_extras); - if (def->has_food_bonus) - move_bonus_entry_list (&new_cfg.food_bonus_extras, &def->food_bonus_extras); - if (def->has_gold_bonus) - move_bonus_entry_list (&new_cfg.gold_bonus_extras, &def->gold_bonus_extras); - if (def->has_shield_bonus) - move_bonus_entry_list (&new_cfg.shield_bonus_extras, &def->shield_bonus_extras); - if (def->has_happiness_bonus) - move_bonus_entry_list (&new_cfg.happiness_bonus_extras, &def->happiness_bonus_extras); - if (def->has_defense_bonus_percent) - move_bonus_entry_list (&new_cfg.defense_bonus_extras, &def->defense_bonus_extras); - - if (def->has_generated_resource) { - new_cfg.generated_resource = def->generated_resource; - def->generated_resource = NULL; - new_cfg.generated_resource_flags = def->generated_resource_flags; - new_cfg.generated_resource_id = -1; - } else { - new_cfg.generated_resource = NULL; - new_cfg.generated_resource_id = -1; - new_cfg.generated_resource_flags = 0; - } - - new_cfg.dependent_improvement_max_index = def->has_dependent_improvements ? def->dependent_improvement_max_index : 0; - const int max_dependent_entries = ARRAY_LEN (is->district_configs[0].dependent_improvements); - if (new_cfg.dependent_improvement_max_index > max_dependent_entries) - new_cfg.dependent_improvement_max_index = max_dependent_entries; - for (int i = 0; i < new_cfg.dependent_improvement_max_index; i++) { - new_cfg.dependent_improvements[i] = def->dependent_improvements[i]; - def->dependent_improvements[i] = NULL; - } - - new_cfg.img_path_count = def->img_path_count; - const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); - if (new_cfg.img_path_count > max_img_paths) - new_cfg.img_path_count = max_img_paths; - for (int i = 0; i < new_cfg.img_path_count; i++) { - new_cfg.img_paths[i] = def->img_paths[i]; - def->img_paths[i] = NULL; - } - - if (! ensure_culture_variant_art (&new_cfg, section_start_line)) { - free_dynamic_district_config (&new_cfg); - return false; - } - - new_cfg.img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, def->has_img_column_count ? def->img_column_count : new_cfg.dependent_improvement_max_index + 1); - new_cfg.has_img_column_count_override = def->has_img_column_count; - - if (reusing_existing) - new_cfg.command = preserved_command; - else - new_cfg.command = allocate_dynamic_district_command (new_cfg.name); - - struct district_config * dest_cfg = &is->district_configs[dest_index]; - if (reusing_existing) { - enum Unit_Command_Values saved_command = preserved_command; - free_dynamic_district_config (dest_cfg); - *dest_cfg = new_cfg; - dest_cfg->command = saved_command; - } else { - free_dynamic_district_config (dest_cfg); - *dest_cfg = new_cfg; - is->dynamic_district_count += 1; - is->district_count = is->special_district_count + is->dynamic_district_count; - } - - return true; -} - -void -finalize_parsed_district_definition (struct parsed_district_definition * def, int section_start_line) -{ - if ((! def->has_name) || (def->name == NULL)) - return; - - if (! override_special_district_from_definition (def, section_start_line)) - add_dynamic_district_from_definition (def, section_start_line); - - free_parsed_district_definition (def); -} - -void -handle_district_definition_key (struct parsed_district_definition * def, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if (slice_matches_str (key, "name")) { - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - char * name_copy = copy_trimmed_string_or_null (value, 1); - if (name_copy == NULL) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else { - def->name = name_copy; - def->has_name = true; - } - - } else if (slice_matches_str (key, "display_name")) { - if (def->display_name != NULL) { - free (def->display_name); - def->display_name = NULL; - } - def->display_name = copy_trimmed_string_or_null (value, 1); - def->has_display_name = true; - - } else if (slice_matches_str (key, "tooltip")) { - if (def->tooltip != NULL) { - free (def->tooltip); - def->tooltip = NULL; - } - def->tooltip = copy_trimmed_string_or_null (value, 1); - def->has_tooltip = true; - - } else if (slice_matches_str (key, "advance_prereqs") || slice_matches_str (key, "advance_prereq")) { - for (int i = 0; i < def->advance_prereq_count; i++) { - if (def->advance_prereqs[i] != NULL) { - free (def->advance_prereqs[i]); - def->advance_prereqs[i] = NULL; - } - } - def->advance_prereq_count = 0; - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->advance_prereqs, - ARRAY_LEN (def->advance_prereqs), - &list_count, - parse_errors, - line_number, - "advance_prereqs")) { - def->advance_prereq_count = list_count; - def->has_advance_prereqs = true; - } else { - def->advance_prereq_count = 0; - def->has_advance_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "obsoleted_by")) { - if (def->obsoleted_by != NULL) { - free (def->obsoleted_by); - def->obsoleted_by = NULL; - } - def->obsoleted_by = copy_trimmed_string_or_null (value, 1); - def->has_obsoleted_by = true; - - } else if (slice_matches_str (key, "resource_prereqs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->resource_prereqs, - ARRAY_LEN (def->resource_prereqs), - &list_count, - parse_errors, - line_number, - "resource_prereqs")) { - def->resource_prereq_count = list_count; - def->has_resource_prereqs = true; - } else { - def->resource_prereq_count = 0; - def->has_resource_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "resource_prereq_on_tile")) { - if (def->resource_prereq_on_tile != NULL) { - free (def->resource_prereq_on_tile); - def->resource_prereq_on_tile = NULL; - } - def->resource_prereq_on_tile = copy_trimmed_string_or_null (value, 1); - def->has_resource_prereq_on_tile = true; - - } else if (slice_matches_str (key, "wonder_prereqs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->wonder_prereqs, - ARRAY_LEN (def->wonder_prereqs), - &list_count, - parse_errors, - line_number, - "wonder_prereqs")) { - def->wonder_prereq_count = list_count; - def->has_wonder_prereqs = true; - } else { - def->wonder_prereq_count = 0; - def->has_wonder_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "natural_wonder_prereqs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->natural_wonder_prereqs, - ARRAY_LEN (def->natural_wonder_prereqs), - &list_count, - parse_errors, - line_number, - "natural_wonder_prereqs")) { - def->natural_wonder_prereq_count = list_count; - def->has_natural_wonder_prereqs = true; - } else { - def->natural_wonder_prereq_count = 0; - def->has_natural_wonder_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_on_districts")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_on_districts, - ARRAY_LEN (def->buildable_on_districts), - &list_count, - parse_errors, - line_number, - "buildable_on_districts")) { - def->buildable_on_district_count = list_count; - def->has_buildable_on_districts = true; - } else { - def->buildable_on_district_count = 0; - def->has_buildable_on_districts = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_adjacent_to_districts")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_adjacent_to_districts, - ARRAY_LEN (def->buildable_adjacent_to_districts), - &list_count, - parse_errors, - line_number, - "buildable_adjacent_to_districts")) { - def->buildable_adjacent_to_district_count = list_count; - def->has_buildable_adjacent_to_districts = true; - } else { - def->buildable_adjacent_to_district_count = 0; - def->has_buildable_adjacent_to_districts = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civs, - ARRAY_LEN (def->buildable_by_civs), - &list_count, - parse_errors, - line_number, - "buildable_by_civs")) { - def->buildable_by_civ_count = list_count; - def->has_buildable_by_civs = true; - } else { - def->buildable_by_civ_count = 0; - def->has_buildable_by_civs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_traits")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_traits, - ARRAY_LEN (def->buildable_by_civ_traits), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_traits")) { - def->buildable_by_civ_traits_count = list_count; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - char const * trait_name = def->buildable_by_civ_traits[i]; - if ((trait_name == NULL) || (trait_name[0] == '\0')) - continue; - int trait_id = -1; - struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; - if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { - if (def->buildable_by_civ_traits_ids[k] == trait_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) - def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->has_buildable_by_civ_traits = true; - } else { - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - def->has_buildable_by_civ_traits = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_govs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_govs, - ARRAY_LEN (def->buildable_by_civ_govs), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_govs")) { - def->buildable_by_civ_govs_count = list_count; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - char const * gov_name = def->buildable_by_civ_govs[i]; - if ((gov_name == NULL) || (gov_name[0] == '\0')) - continue; - int gov_id = -1; - struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; - if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { - if (def->buildable_by_civ_govs_ids[k] == gov_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) - def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->has_buildable_by_civ_govs = true; - } else { - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - def->has_buildable_by_civ_govs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_cultures, - ARRAY_LEN (def->buildable_by_civ_cultures), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_cultures")) { - def->buildable_by_civ_cultures_count = list_count; - def->buildable_by_civ_cultures_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - char const * culture_name = def->buildable_by_civ_cultures[i]; - if ((culture_name == NULL) || (culture_name[0] == '\0')) - continue; - int culture_id = -1; - struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; - if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { - if (def->buildable_by_civ_cultures_ids[k] == culture_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) - def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->has_buildable_by_civ_cultures = true; - } else { - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - def->has_buildable_by_civ_cultures = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_war_allies")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_by_war_allies = (ival != 0); - def->has_buildable_by_war_allies = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "buildable_by_pact_allies")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_by_pact_allies = (ival != 0); - def->has_buildable_by_pact_allies = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "img_paths")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->img_paths, - ARRAY_LEN (def->img_paths), - &list_count, - parse_errors, - line_number, - "img_paths")) { - def->img_path_count = list_count; - def->has_img_paths = true; - } else { - def->img_path_count = 0; - def->has_img_paths = false; - } - free (value_text); - - } else if (slice_matches_str (key, "img_column_count")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_column_count = ival; - def->has_img_column_count = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "dependent_improvs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->dependent_improvements, - ARRAY_LEN (def->dependent_improvements), - &list_count, - parse_errors, - line_number, - "dependent_improvs")) { - def->dependent_improvement_max_index = list_count; - def->has_dependent_improvements = true; - } else { - def->dependent_improvement_max_index = 0; - def->has_dependent_improvements = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_on")) { - unsigned int mask; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { - def->buildable_square_types_mask = mask; - def->has_buildable_on = true; - } - - } else if (slice_matches_str (key, "buildable_without_removal")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_without_removal")) { - def->buildable_without_removal_mask = mask; - def->has_buildable_without_removal = true; - } else { - def->has_buildable_without_removal = false; - } - - } else if (slice_matches_str (key, "buildable_on_overlays")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_on_overlays")) { - def->buildable_on_overlays_mask = mask; - def->has_buildable_on_overlays = true; - } else { - def->has_buildable_on_overlays = false; - } - - } else if (slice_matches_str (key, "buildable_on_rivers")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_on_rivers = (ival != 0); - def->has_buildable_on_rivers = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "buildable_adjacent_to")) { - unsigned int mask; - def->buildable_adjacent_to_allows_city = false; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { - def->buildable_adjacent_to_square_types_mask = mask; - def->has_buildable_adjacent_to = true; - } - - } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { - def->buildable_adjacent_to_overlays_mask = mask; - def->has_buildable_adjacent_to_overlays = true; - } else { - def->has_buildable_adjacent_to_overlays = false; - } - - } else if (slice_matches_str (key, "allow_multiple")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->allow_multiple = (ival != 0); - def->has_allow_multiple = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "vary_img_by_era")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->vary_img_by_era = (ival != 0); - def->has_vary_img_by_era = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "vary_img_by_culture")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->vary_img_by_culture = (ival != 0); - def->has_vary_img_by_culture = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "render_strategy")) { - char * strategy = copy_trimmed_string_or_null (value, 1); - if (strategy == NULL) { - def->has_render_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else if (strcmp (strategy, "by-count") == 0) { - def->render_strategy = DRS_BY_COUNT; - def->has_render_strategy = true; - } else if (strcmp (strategy, "by-building") == 0) { - def->render_strategy = DRS_BY_BUILDING; - def->has_render_strategy = true; - } else { - def->has_render_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected \"by-count\" or \"by-building\")"); - } - if (strategy != NULL) - free (strategy); - - } else if (slice_matches_str (key, "ai_build_strategy")) { - char * strategy = copy_trimmed_string_or_null (value, 1); - if (strategy == NULL) { - def->has_ai_build_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else if (strcmp (strategy, "district") == 0) { - def->ai_build_strategy = DABS_DISTRICT; - def->has_ai_build_strategy = true; - } else if (strcmp (strategy, "tile-improvement") == 0) { - def->ai_build_strategy = DABS_TILE_IMPROVEMENT; - def->has_ai_build_strategy = true; - } else { - def->has_ai_build_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected \"district\" or \"tile-improvement\")"); - } - if (strategy != NULL) - free (strategy); - - } else if (slice_matches_str (key, "align_to_coast")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->align_to_coast = (ival != 0); - def->has_align_to_coast = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "draw_over_resources")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->draw_over_resources = (ival != 0); - def->has_draw_over_resources = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "allow_irrigation_from")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->allow_irrigation_from = (ival != 0); - def->has_allow_irrigation_from = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "auto_add_road")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->auto_add_road = (ival != 0); - def->has_auto_add_road = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "auto_add_railroad")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->auto_add_railroad = (ival != 0); - def->has_auto_add_railroad = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "impassible")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible = (ival != 0); - def->has_impassible = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "impassible_to_wheeled")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible_to_wheeled = (ival != 0); - def->has_impassible_to_wheeled = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "custom_width")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_width = ival; - def->has_custom_width = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "custom_height")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_height = ival; - def->has_custom_height = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "x_offset")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->x_offset = ival; - def->has_x_offset = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "y_offset")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->y_offset = ival; - def->has_y_offset = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "btn_tile_sheet_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->btn_tile_sheet_column = ival; - def->has_btn_tile_sheet_column = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "btn_tile_sheet_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->btn_tile_sheet_row = ival; - def->has_btn_tile_sheet_row = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "defense_bonus_percent")) { - if (parse_district_bonus_entries (value, &def->defense_bonus_percent, &def->defense_bonus_extras, parse_errors, line_number, key)) { - def->has_defense_bonus_percent = true; - } else { - def->has_defense_bonus_percent = false; - } - - } else if (slice_matches_str (key, "heal_units_in_one_turn")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->heal_units_in_one_turn = (ival != 0); - def->has_heal_units_in_one_turn = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "culture_bonus")) { - if (parse_district_bonus_entries (value, &def->culture_bonus, &def->culture_bonus_extras, parse_errors, line_number, key)) { - def->has_culture_bonus = true; - } else { - def->has_culture_bonus = false; - } - - } else if (slice_matches_str (key, "science_bonus")) { - if (parse_district_bonus_entries (value, &def->science_bonus, &def->science_bonus_extras, parse_errors, line_number, key)) { - def->has_science_bonus = true; - } else { - def->has_science_bonus = false; - } - - } else if (slice_matches_str (key, "food_bonus")) { - if (parse_district_bonus_entries (value, &def->food_bonus, &def->food_bonus_extras, parse_errors, line_number, key)) { - def->has_food_bonus = true; - } else { - def->has_food_bonus = false; - } - - } else if (slice_matches_str (key, "gold_bonus")) { - if (parse_district_bonus_entries (value, &def->gold_bonus, &def->gold_bonus_extras, parse_errors, line_number, key)) { - def->has_gold_bonus = true; - } else { - def->has_gold_bonus = false; - } - - } else if (slice_matches_str (key, "shield_bonus")) { - if (parse_district_bonus_entries (value, &def->shield_bonus, &def->shield_bonus_extras, parse_errors, line_number, key)) { - def->has_shield_bonus = true; - } else { - def->has_shield_bonus = false; - } - - } else if (slice_matches_str (key, "happiness_bonus")) { - if (parse_district_bonus_entries (value, &def->happiness_bonus, &def->happiness_bonus_extras, parse_errors, line_number, key)) { - def->has_happiness_bonus = true; - } else { - def->has_happiness_bonus = false; - } - - } else if (slice_matches_str (key, "generated_resource")) { - if (def->generated_resource != NULL) { - free (def->generated_resource); - def->generated_resource = NULL; - } - def->generated_resource_flags = 0; - - char * value_text = trim_and_extract_slice (value, 0); - if ((value_text == NULL) || (*value_text == '\0')) { - def->generated_resource = NULL; - def->has_generated_resource = true; - } else { - char * cursor = value_text; - struct string_slice resource_name = {0}; - struct string_slice token; - bool ok = true; - while (skip_white_space (&cursor) && parse_string (&cursor, &token)) { - if (slice_matches_str (&token, "local")) - def->generated_resource_flags |= MF_LOCAL; - else if (slice_matches_str (&token, "no-tech-req")) - def->generated_resource_flags |= MF_NO_TECH_REQ; - else if (slice_matches_str (&token, "yields")) - def->generated_resource_flags |= MF_YIELDS; - else if (resource_name.str == NULL) - resource_name = token; - else { - ok = false; - break; - } - } - - if (! ok || (resource_name.str == NULL)) { - def->generated_resource = NULL; - def->has_generated_resource = false; - def->generated_resource_flags = 0; - add_key_parse_error (parse_errors, line_number, key, value, - "(expected resource name plus optional flags: local, yields, no-tech-req)"); - } else { - def->generated_resource = extract_slice (&resource_name); - def->has_generated_resource = true; - } - } - free (value_text); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -bool -line_is_empty_or_comment (struct string_slice const * trimmed) -{ - return ((trimmed == NULL) || (trimmed->len == 0) || (trimmed->str[0] == ';') || (trimmed->str[0] == '[')); -} - -bool -file_exists_at_path (char const * path) -{ - if ((path == NULL) || (path[0] == '\0')) - return false; - - HANDLE file = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (file == INVALID_HANDLE_VALUE) - return false; - - CloseHandle (file); - return true; -} - -void -load_dynamic_district_config_file (char const * file_path, - int path_is_relative_to_mod_dir, - int log_missing, - int drop_existing_configs) -{ - char path[MAX_PATH]; - if (path_is_relative_to_mod_dir) { - if (is->mod_rel_dir == NULL) - return; - snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); - } else { - strncpy (path, file_path, sizeof path); - } - path[(sizeof path) - 1] = '\0'; - - char * text = file_to_string (path); - if (text == NULL) { - if (log_missing) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] Districts config file not found: %s", path); - (*p_OutputDebugStringA) (ss); - } - return; - } - - if (drop_existing_configs) - reset_regular_district_configs (); - - struct parsed_district_definition def; - init_parsed_district_definition (&def); - bool in_section = false; - int section_start_line = 0; - int line_number = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - bool has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if ((directive.len > 0) && slice_matches_str (&directive, "District")) { - if (in_section) - finalize_parsed_district_definition (&def, section_start_line); - in_section = true; - section_start_line = line_number; - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); - if (status == KVP_NO_EQUALS) { - char * line_text = extract_slice (&trimmed); - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); - err->text[(sizeof err->text) - 1] = '\0'; - free (line_text); - cursor = has_newline ? line_end + 1 : line_end; - continue; - } else if (status == KVP_EMPTY_KEY) { - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); - err->text[(sizeof err->text) - 1] = '\0'; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - handle_district_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) - finalize_parsed_district_definition (&def, section_start_line); - - free_parsed_district_definition (&def); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - snprintf (is->current_districts_config_path, sizeof is->current_districts_config_path, path); - - if (parse_errors != NULL || unrecognized_keys != NULL) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "District Config errors in %s:", path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - if (parse_errors != NULL) { - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", false); - PopupForm_add_text (popup, __, "Unrecognized keys:", false); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - patch_show_popup (popup, __, 0, 0); - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); - } -} - -void -load_dynamic_district_configs () -{ - char * scenario_filename = "scenario.districts_config.txt"; - char * scenario_district_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - if ((scenario_district_config_path != NULL) && - (0 != strcmp (scenario_filename, scenario_district_config_path)) && - file_exists_at_path (scenario_district_config_path)) { - load_dynamic_district_config_file (scenario_district_config_path, 0, 0, 1); - return; - } - - if (is->mod_rel_dir != NULL) { - char user_path[MAX_PATH]; - snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_config.txt"); - user_path[(sizeof user_path) - 1] = '\0'; - if (file_exists_at_path (user_path)) { - load_dynamic_district_config_file ("user.districts_config.txt", 1, 0, 1); - return; - } - } - - load_dynamic_district_config_file ("default.districts_config.txt", 1, 1, 1); -} - -void -init_parsed_wonder_definition (struct parsed_wonder_definition * def) -{ - memset (def, 0, sizeof *def); - def->buildable_square_types_mask = district_default_buildable_mask (); - def->buildable_adjacent_to_square_types_mask = 0; - def->buildable_adjacent_to_overlays_mask = 0; - def->buildable_on_rivers = false; - def->buildable_adjacent_to_allows_city = false; - for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_traits_ids); i++) - def->buildable_by_civ_traits_ids[i] = -1; - for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_govs_ids); i++) - def->buildable_by_civ_govs_ids[i] = -1; - for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_cultures_ids); i++) - def->buildable_by_civ_cultures_ids[i] = -1; -} - -void -free_parsed_wonder_definition (struct parsed_wonder_definition * def) -{ - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - - for (int i = 0; i < def->buildable_by_civ_count; i++) { - if (def->buildable_by_civs[i] != NULL) { - free (def->buildable_by_civs[i]); - def->buildable_by_civs[i] = NULL; - } - } - def->buildable_by_civ_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - - init_parsed_wonder_definition (def); -} - -bool -add_dynamic_wonder_from_definition (struct parsed_wonder_definition * def, int section_start_line) -{ - int existing_index = -1; - for (int i = 0; i < is->wonder_district_count; i++) { - if ((is->wonder_district_configs[i].wonder_name != NULL) && - (strcmp (is->wonder_district_configs[i].wonder_name, def->name) == 0)) { - existing_index = i; - break; - } - } - - int dest = (existing_index >= 0) ? existing_index : is->wonder_district_count; - if ((dest < 0) || (dest >= MAX_WONDER_DISTRICT_TYPES)) - return false; - - struct wonder_district_config new_cfg; - memset (&new_cfg, 0, sizeof new_cfg); - new_cfg.index = dest; - new_cfg.is_dynamic = true; - new_cfg.wonder_name = strdup (def->name); - new_cfg.img_path = (def->img_path != NULL) ? strdup (def->img_path) : strdup ("Wonders.pcx"); - new_cfg.img_row = def->img_row; - new_cfg.img_column = def->img_column; - new_cfg.img_construct_row = def->img_construct_row; - new_cfg.img_construct_column = def->img_construct_column; - new_cfg.img_alt_dir_construct_row = def->img_alt_dir_construct_row; - new_cfg.img_alt_dir_construct_column = def->img_alt_dir_construct_column; - new_cfg.img_alt_dir_row = def->img_alt_dir_row; - new_cfg.img_alt_dir_column = def->img_alt_dir_column; - new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; - new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; - new_cfg.enable_img_alt_dir = def->enable_img_alt_dir; - new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); - new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; - new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; - new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; - new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; - new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; - const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); - if (new_cfg.buildable_by_civ_count > max_civ_names) - new_cfg.buildable_by_civ_count = max_civ_names; - for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { - new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; - def->buildable_by_civs[i] = NULL; - } - new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; - new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; - const int max_trait_entries = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); - if (new_cfg.buildable_by_civ_traits_id_count > max_trait_entries) - new_cfg.buildable_by_civ_traits_id_count = max_trait_entries; - for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) - new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; - new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; - new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; - const int max_gov_entries = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); - if (new_cfg.buildable_by_civ_govs_id_count > max_gov_entries) - new_cfg.buildable_by_civ_govs_id_count = max_gov_entries; - for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) - new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; - new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; - new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; - const int max_culture_entries = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); - if (new_cfg.buildable_by_civ_cultures_id_count > max_culture_entries) - new_cfg.buildable_by_civ_cultures_id_count = max_culture_entries; - for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) - new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; - new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; - new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; - new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; - - if (existing_index >= 0) { - struct wonder_district_config * cfg = &is->wonder_district_configs[existing_index]; - free_dynamic_wonder_config (cfg); - *cfg = new_cfg; - cfg->index = existing_index; - } else { - struct wonder_district_config * cfg = &is->wonder_district_configs[dest]; - free_dynamic_wonder_config (cfg); - *cfg = new_cfg; - is->wonder_district_count += 1; - } - - return true; -} - -void -finalize_parsed_wonder_definition (struct parsed_wonder_definition * def, - int section_start_line, - struct error_line ** parse_errors) -{ - bool ok = true; - - if ((! def->has_name) || (def->name == NULL)) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_construct_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_row (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_construct_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_column (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (def->enable_img_alt_dir) { - if (! def->has_img_alt_dir_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_row (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_alt_dir_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_column (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_alt_dir_construct_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_row (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_alt_dir_construct_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_column (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - } - - if (ok) - add_dynamic_wonder_from_definition (def, section_start_line); - - free_parsed_wonder_definition (def); -} - -void -handle_wonder_definition_key (struct parsed_wonder_definition * def, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if (slice_matches_str (key, "name")) { - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else { - char * name_copy = extract_slice (&unquoted); - if (name_copy == NULL) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); - } else { - def->name = name_copy; - def->has_name = true; - } - } - - } else if (slice_matches_str (key, "img_path")) { - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_img_path = false; - } else { - char * path_copy = extract_slice (&unquoted); - if (path_copy == NULL) { - def->has_img_path = false; - } else { - def->img_path = path_copy; - def->has_img_path = true; - } - } - - } else if (slice_matches_str (key, "img_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_row = ival; - def->has_img_row = true; - } else { - def->has_img_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_column = ival; - def->has_img_column = true; - } else { - def->has_img_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_construct_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_construct_row = ival; - def->has_img_construct_row = true; - } else { - def->has_img_construct_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_construct_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_construct_column = ival; - def->has_img_construct_column = true; - } else { - def->has_img_construct_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_construct_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_construct_row = ival; - def->has_img_alt_dir_construct_row = true; - } else { - def->has_img_alt_dir_construct_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_construct_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_construct_column = ival; - def->has_img_alt_dir_construct_column = true; - } else { - def->has_img_alt_dir_construct_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_row = ival; - def->has_img_alt_dir_row = true; - } else { - def->has_img_alt_dir_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_column = ival; - def->has_img_alt_dir_column = true; - } else { - def->has_img_alt_dir_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "custom_width")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_width = ival; - def->has_custom_width = true; - } else { - def->has_custom_width = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "custom_height")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_height = ival; - def->has_custom_height = true; - } else { - def->has_custom_height = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "enable_img_alt_dir")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->enable_img_alt_dir = (ival != 0); - def->has_enable_img_alt_dir = true; - } else { - def->has_enable_img_alt_dir = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "buildable_on")) { - unsigned int mask; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { - def->buildable_square_types_mask = mask; - def->has_buildable_on = true; - } else { - def->has_buildable_on = false; - } - - } else if (slice_matches_str (key, "buildable_on_rivers")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_on_rivers = (ival != 0); - def->has_buildable_on_rivers = true; - } else { - def->has_buildable_on_rivers = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "buildable_adjacent_to")) { - unsigned int mask; - def->buildable_adjacent_to_allows_city = false; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { - def->buildable_adjacent_to_square_types_mask = mask; - def->has_buildable_adjacent_to = true; - } else { - def->has_buildable_adjacent_to = false; - } - - } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { - def->buildable_adjacent_to_overlays_mask = mask; - def->has_buildable_adjacent_to_overlays = true; - } else { - def->has_buildable_adjacent_to_overlays = false; - } - - } else if (slice_matches_str (key, "buildable_by_civs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civs, - ARRAY_LEN (def->buildable_by_civs), - &list_count, - parse_errors, - line_number, - "buildable_by_civs")) { - def->buildable_by_civ_count = list_count; - def->has_buildable_by_civs = true; - } else { - def->buildable_by_civ_count = 0; - def->has_buildable_by_civs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_traits")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_traits, - ARRAY_LEN (def->buildable_by_civ_traits), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_traits")) { - def->buildable_by_civ_traits_count = list_count; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - char const * trait_name = def->buildable_by_civ_traits[i]; - if ((trait_name == NULL) || (trait_name[0] == '\0')) - continue; - int trait_id = -1; - struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; - if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { - if (def->buildable_by_civ_traits_ids[k] == trait_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) - def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->has_buildable_by_civ_traits = true; - } else { - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - def->has_buildable_by_civ_traits = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_govs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_govs, - ARRAY_LEN (def->buildable_by_civ_govs), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_govs")) { - def->buildable_by_civ_govs_count = list_count; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - char const * gov_name = def->buildable_by_civ_govs[i]; - if ((gov_name == NULL) || (gov_name[0] == '\0')) - continue; - int gov_id = -1; - struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; - if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { - if (def->buildable_by_civ_govs_ids[k] == gov_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) - def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->has_buildable_by_civ_govs = true; - } else { - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - def->has_buildable_by_civ_govs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_cultures, - ARRAY_LEN (def->buildable_by_civ_cultures), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_cultures")) { - def->buildable_by_civ_cultures_count = list_count; - def->buildable_by_civ_cultures_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - char const * culture_name = def->buildable_by_civ_cultures[i]; - if ((culture_name == NULL) || (culture_name[0] == '\0')) - continue; - int culture_id = -1; - struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; - if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { - if (def->buildable_by_civ_cultures_ids[k] == culture_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) - def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->has_buildable_by_civ_cultures = true; - } else { - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - def->has_buildable_by_civ_cultures = false; - } - free (value_text); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -void -load_dynamic_wonder_config_file (char const * file_path, - int path_is_relative_to_mod_dir, - int log_missing, - int drop_existing_configs) -{ - char path[MAX_PATH]; - if (path_is_relative_to_mod_dir) { - if (is->mod_rel_dir == NULL) - return; - snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); - } else { - strncpy (path, file_path, sizeof path); - } - path[(sizeof path) - 1] = '\0'; - - char * text = file_to_string (path); - if (text == NULL) { - if (log_missing) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] Wonders config file not found: %s", path); - (*p_OutputDebugStringA) (ss); - } - return; - } - - if (drop_existing_configs) - reset_wonder_district_configs (); - - struct parsed_wonder_definition def; - init_parsed_wonder_definition (&def); - bool in_section = false; - int section_start_line = 0; - int line_number = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - bool has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { - if (in_section) - finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); - in_section = true; - section_start_line = line_number; - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); - if (status == KVP_NO_EQUALS) { - char * line_text = extract_slice (&trimmed); - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); - err->text[(sizeof err->text) - 1] = '\0'; - free (line_text); - cursor = has_newline ? line_end + 1 : line_end; - continue; - } else if (status == KVP_EMPTY_KEY) { - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); - err->text[(sizeof err->text) - 1] = '\0'; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - handle_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) - finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); - - free_parsed_wonder_definition (&def); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - - if (parse_errors != NULL || unrecognized_keys != NULL) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "Wonder District Config errors in %s:", path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - if (parse_errors != NULL) { - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", false); - PopupForm_add_text (popup, __, "Unrecognized keys:", false); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - patch_show_popup (popup, __, 0, 0); - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); - } -} - -void -load_dynamic_wonder_configs () -{ - char * scenario_filename = "scenario.districts_wonders_config.txt"; - char * scenario_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - if ((scenario_wonder_config_path != NULL) && - (0 != strcmp (scenario_filename, scenario_wonder_config_path)) && - file_exists_at_path (scenario_wonder_config_path)) { - load_dynamic_wonder_config_file (scenario_wonder_config_path, 0, 0, 1); - return; - } - - if (is->mod_rel_dir != NULL) { - char user_path[MAX_PATH]; - snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_wonders_config.txt"); - user_path[(sizeof user_path) - 1] = '\0'; - if (file_exists_at_path (user_path)) { - load_dynamic_wonder_config_file ("user.districts_wonders_config.txt", 1, 0, 1); - return; - } - } - - load_dynamic_wonder_config_file ("default.districts_wonders_config.txt", 1, 1, 1); -} - -void -init_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) -{ - memset (def, 0, sizeof *def); - def->terrain_type = SQ_Grassland; - def->adjacent_to = (enum SquareTypes)SQ_INVALID; - def->adjacency_dir = DIR_ZERO; -} - -void -free_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) -{ - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - init_parsed_natural_wonder_definition (def); -} - -bool -add_natural_wonder_from_definition (struct parsed_natural_wonder_definition * def, int section_start_line) -{ - if ((def == NULL) || (def->name == NULL)) - return false; - - int existing_index; - bool has_existing = stable_look_up (&is->natural_wonder_name_to_id, def->name, &existing_index); - - int dest = has_existing ? existing_index : is->natural_wonder_count; - if ((dest < 0) || (dest >= MAX_NATURAL_WONDER_DISTRICT_TYPES)) - return false; - - struct natural_wonder_district_config new_cfg; - memset (&new_cfg, 0, sizeof new_cfg); - new_cfg.index = dest; - new_cfg.is_dynamic = true; - new_cfg.adjacent_to = (enum SquareTypes)SQ_INVALID; - new_cfg.adjacency_dir = DIR_ZERO; - - char * name_copy = strdup (def->name); - if (name_copy == NULL) - return false; - new_cfg.name = name_copy; - - char const * img_path_src = def->img_path; - char * img_copy = strdup (img_path_src); - if (img_copy == NULL) { - free (name_copy); - return false; - } - new_cfg.img_path = img_copy; - new_cfg.img_row = def->img_row; - new_cfg.img_column = def->img_column; - new_cfg.terrain_type = def->terrain_type; - new_cfg.adjacent_to = def->adjacent_to; - new_cfg.adjacency_dir = def->adjacency_dir; - new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; - new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; - new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; - new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; - new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; - new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; - new_cfg.impassible = def->has_impassible ? def->impassible : false; - new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; - - if (has_existing) { - struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[existing_index]; - free_dynamic_natural_wonder_config (cfg); - *cfg = new_cfg; - } else { - struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[dest]; - free_dynamic_natural_wonder_config (cfg); - *cfg = new_cfg; - is->natural_wonder_count = dest + 1; - stable_insert (&is->natural_wonder_name_to_id, new_cfg.name, dest); - } - - return true; -} - -void -finalize_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def, - int section_start_line, - struct error_line ** parse_errors) -{ - bool ok = true; - - if ((! def->has_name) || (def->name == NULL)) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_terrain_type) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: terrain_type (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - if (ok) - add_natural_wonder_from_definition (def, section_start_line); - - free_parsed_natural_wonder_definition (def); -} - -void -handle_natural_wonder_definition_key (struct parsed_natural_wonder_definition * def, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if (slice_matches_str (key, "name")) { - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else { - char * name_copy = extract_slice (&unquoted); - if (name_copy == NULL) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); - } else { - def->name = name_copy; - def->has_name = true; - } - } - - } else if (slice_matches_str (key, "terrain_type")) { - enum SquareTypes terrain; - if (read_natural_wonder_terrain_type (value, &terrain)) { - def->terrain_type = terrain; - def->has_terrain_type = true; - } else { - def->has_terrain_type = false; - add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized terrain type)"); - } - - } else if (slice_matches_str (key, "adjacent_to")) { - enum SquareTypes adj; - if (read_tile_terrain_type_value (value, &adj)) { - def->adjacent_to = adj; - def->has_adjacent_to = true; - } else { - def->adjacent_to = (enum SquareTypes)SQ_INVALID; - def->has_adjacent_to = false; - add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized tile terrain type)"); - } - - } else if (slice_matches_str (key, "adjacency_dir")) { - enum direction dir; - if (read_direction_value (value, &dir)) { - def->adjacency_dir = dir; - def->has_adjacency_dir = true; - } else { - def->adjacency_dir = DIR_ZERO; - def->has_adjacency_dir = false; - add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized direction)"); - } - - } else if (slice_matches_str (key, "img_path")) { - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_img_path = false; - } else { - char * path_copy = extract_slice (&unquoted); - if (path_copy == NULL) { - def->has_img_path = false; - } else { - def->img_path = path_copy; - def->has_img_path = true; - } - } - - } else if (slice_matches_str (key, "img_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_row = ival; - def->has_img_row = true; - } else { - def->has_img_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_column = ival; - def->has_img_column = true; - } else { - def->has_img_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "culture_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->culture_bonus = ival; - def->has_culture_bonus = true; - } else { - def->has_culture_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "science_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->science_bonus = ival; - def->has_science_bonus = true; - } else { - def->has_science_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "food_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->food_bonus = ival; - def->has_food_bonus = true; - } else { - def->has_food_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "gold_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->gold_bonus = ival; - def->has_gold_bonus = true; - } else { - def->has_gold_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "shield_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->shield_bonus = ival; - def->has_shield_bonus = true; - } else { - def->has_shield_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "happiness_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->happiness_bonus = ival; - def->has_happiness_bonus = true; - } else { - def->has_happiness_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "impassible")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible = (ival != 0); - def->has_impassible = true; - } else { - def->has_impassible = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "impassible_to_wheeled")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible_to_wheeled = (ival != 0); - def->has_impassible_to_wheeled = true; - } else { - def->has_impassible_to_wheeled = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -void -load_natural_wonder_config_file (char const * file_path, - int path_is_relative_to_mod_dir, - int log_missing, - int drop_existing_configs) -{ - char path[MAX_PATH]; - if (path_is_relative_to_mod_dir) { - if (is->mod_rel_dir == NULL) - return; - snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); - } else { - strncpy (path, file_path, sizeof path); - } - path[(sizeof path) - 1] = '\0'; - - char * text = file_to_string (path); - if (text == NULL) { - if (log_missing) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] Natural wonders config file not found: %s", path); - (*p_OutputDebugStringA) (ss); - } - return; - } - - if (drop_existing_configs) - reset_natural_wonder_configs (); - - struct parsed_natural_wonder_definition def; - init_parsed_natural_wonder_definition (&def); - bool in_section = false; - int section_start_line = 0; - int line_number = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - bool has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { - if (in_section) - finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); - in_section = true; - section_start_line = line_number; - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); - if (status == KVP_NO_EQUALS) { - char * line_text = extract_slice (&trimmed); - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); - err->text[(sizeof err->text) - 1] = '\0'; - free (line_text); - cursor = has_newline ? line_end + 1 : line_end; - continue; - } else if (status == KVP_EMPTY_KEY) { - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); - err->text[(sizeof err->text) - 1] = '\0'; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - handle_natural_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) - finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); - - free_parsed_natural_wonder_definition (&def); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - - if (parse_errors != NULL || unrecognized_keys != NULL) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "Natural Wonder Config errors in %s:", path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - if (parse_errors != NULL) { - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", false); - PopupForm_add_text (popup, __, "Unrecognized keys:", false); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - patch_show_popup (popup, __, 0, 0); - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); - } -} - -void -load_natural_wonder_configs () -{ - char * scenario_filename = "scenario.districts_natural_wonders_config.txt"; - char * scenario_natural_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - if ((scenario_natural_wonder_config_path != NULL) && - (0 != strcmp (scenario_filename, scenario_natural_wonder_config_path)) && - file_exists_at_path (scenario_natural_wonder_config_path)) { - load_natural_wonder_config_file (scenario_natural_wonder_config_path, 0, 0, 1); - return; - } - - if (is->mod_rel_dir != NULL) { - char user_path[MAX_PATH]; - snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_natural_wonders_config.txt"); - user_path[(sizeof user_path) - 1] = '\0'; - if (file_exists_at_path (user_path)) { - load_natural_wonder_config_file ("user.districts_natural_wonders_config.txt", 1, 0, 1); - return; - } - } - - load_natural_wonder_config_file ("default.districts_natural_wonders_config.txt", 1, 1, 1); -} - -bool -district_config_has_dependent_improvement (struct district_config * cfg, char const * name) -{ - if ((cfg == NULL) || (name == NULL) || (name[0] == '\0')) - return false; - - for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { - char const * existing = cfg->dependent_improvements[i]; - if ((existing != NULL) && (strcmp (existing, name) == 0)) - return true; - } - return false; -} - -bool -find_civ_trait_id_by_name (struct string_slice const * name, int * out_id) -{ - if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) - return false; - - struct trait_entry { enum c3x_label label; char const * fallback_name; int id; } traits[] = { - {CL_AGRICULTURAL, "Agricultural", 6}, - {CL_COMMERCIAL, "Commercial", 1}, - {CL_EXPANSIONIST, "Expansionist", 2}, - {CL_INDUSTRIOUS, "Industrious", 5}, - {CL_MILITARISTIC, "Militaristic", 0}, - {CL_RELIGIOUS, "Religious", 4}, - {CL_SCIENTIFIC, "Scientific", 3}, - {CL_SEAFARING, "Seafaring", 7} - }; - - for (int i = 0; i < ARRAY_LEN (traits); i++) { - char const * localized_name = is->c3x_labels[traits[i].label]; - if (((localized_name != NULL) && (localized_name[0] != '\0') && slice_matches_str (name, localized_name)) - || slice_matches_str (name, traits[i].fallback_name)) { - *out_id = traits[i].id; - return true; - } - } - - return false; -} - -bool -find_civ_culture_id_by_name (struct string_slice const * name, int * out_id) -{ - if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) - return false; - - struct culture_entry { char const * name; int id; } cultures[] = { - {"American", 0}, - {"AMERICAN", 0}, - {"AMER", 0}, - {"European", 1}, - {"EUROPEAN", 1}, - {"EURO", 1}, - {"Roman", 2}, - {"ROMAN", 2}, - {"Mid East", 3}, - {"Mideast", 3}, - {"MIDEAST", 3}, - {"Asian", 4}, - {"ASIAN", 4} - }; - - for (int i = 0; i < ARRAY_LEN (cultures); i++) { - if (slice_matches_str (name, cultures[i].name)) { - *out_id = cultures[i].id; - return true; - } - } - - return false; -} - -int -find_district_index_by_name (char const * name) -{ - if ((name == NULL) || (name[0] == '\0')) - return -1; - - for (int i = 0; i < is->district_count; i++) { - char const * existing = is->district_configs[i].name; - if ((existing != NULL) && (strcmp (existing, name) == 0)) - return i; - } - - return -1; -} - -void -resolve_counter_rule_districts (struct error_line ** parse_errors) -{ - struct c3x_config * cfg = &is->current_config; - - for (int i = 0; i < cfg->count_counter_rules; i++) { - struct counter_rule * rule = &cfg->counter_rules[i]; - rule->district_id = -1; - - if ((rule->district_name == NULL) || (rule->district_name[0] == '\0')) - continue; - - int district_id = find_district_index_by_name (rule->district_name); - if (district_id >= 0) { - rule->district_id = district_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ counter_rule district \"%s\" not found", rule->district_name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } -} - -int -find_wonder_district_index_by_name (char const * name) -{ - if ((name == NULL) || (name[0] == '\0')) - return -1; - - int improv_id; - if (! stable_look_up (&is->building_name_to_id, (char *)name, &improv_id)) - return -1; - - return find_wonder_config_index_by_improvement_id (improv_id); -} - -int -find_natural_wonder_index_by_name (char const * name) -{ - if ((name == NULL) || (name[0] == '\0') || (is == NULL)) - return -1; - - for (int i = 0; i < is->natural_wonder_count; i++) { - char const * existing = is->natural_wonder_configs[i].name; - if ((existing != NULL) && (strcmp (existing, name) == 0)) - return i; - } - return -1; -} - -void -set_wonders_dependent_on_wonder_district (void) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_wonder_districts) - return; - - struct district_config * cfg = &is->district_configs[WONDER_DISTRICT_ID]; - for (int wi = 0; wi < is->wonder_district_count; wi++) { - char const * wonder_name = is->wonder_district_configs[wi].wonder_name; - if ((wonder_name == NULL) || (wonder_name[0] == '\0')) - continue; - if (district_config_has_dependent_improvement (cfg, wonder_name)) - continue; - - int dest = cfg->dependent_improvement_max_index; - if (dest >= ARRAY_LEN (cfg->dependent_improvements)) { - continue; - } - - char * copy = strdup (wonder_name); - if (copy == NULL) { - continue; - } - - cfg->dependent_improvements[dest] = copy; - cfg->dependent_improvement_max_index = dest + 1; - } - - if (! cfg->has_img_column_count_override && - (cfg->img_column_count < cfg->dependent_improvement_max_index + 1)) - cfg->img_column_count = cfg->dependent_improvement_max_index + 1; -} - -void -resolve_district_bonus_building_entries (struct district_bonus_list * list, - char const * district_name, - char const * bonus_name, - struct error_line ** parse_errors) -{ - if (list == NULL) - return; - - for (int i = 0; i < list->count; i++) { - struct district_bonus_entry * entry = &list->entries[i]; - if (entry->type != DBET_BUILDING) - continue; - if ((entry->building_name == NULL) || (entry->building_name[0] == '\0')) { - entry->building_id = -1; - continue; - } - - int improv_id; - struct string_slice improv_name = { .str = (char *)entry->building_name, .len = (int)strlen (entry->building_name) }; - if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { - entry->building_id = improv_id; - stable_insert (&is->building_name_to_id, improv_name.str, improv_id); - } else { - entry->building_id = -1; - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": %s entry \"%.*s\" not found", - district_name, bonus_name, improv_name.len, improv_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } -} - -void parse_building_and_tech_ids () -{ - struct c3x_config * cfg = &is->current_config; - char ss[200]; - struct error_line * district_parse_errors = NULL; - struct error_line * wonder_parse_errors = NULL; - - cfg->great_wall_auto_build_wonder_improv_id = -1; - if (cfg->enable_districts && - cfg->enable_great_wall_districts && - cfg->auto_build_great_wall_around_territory && - cfg->great_wall_auto_build_wonder_name != NULL && - cfg->great_wall_auto_build_wonder_name[0] != '\0') { - struct string_slice wonder_name = { - .str = cfg->great_wall_auto_build_wonder_name, - .len = strlen (cfg->great_wall_auto_build_wonder_name) - }; - if (! find_improv_id_by_name (&wonder_name, &cfg->great_wall_auto_build_wonder_improv_id)) { - snprintf (ss, sizeof ss, - "Error reading config: The value for \"great_wall_auto_build_wonder_name\" is invalid: \"%s\"", - cfg->great_wall_auto_build_wonder_name); - ss[(sizeof ss) - 1] = '\0'; - pop_up_in_game_error (ss); - } - } - - for (int i = 0; i < is->district_count; i++) { - char const * district_name = (is->district_configs[i].name != NULL) ? is->district_configs[i].name : "District"; - if (! district_is_included_by_final_config (i)) { - is->district_infos[i].advance_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) - is->district_infos[i].advance_prereq_ids[j] = -1; - is->district_infos[i].obsoleted_by_id = -1; - is->district_infos[i].resource_prereq_count = 0; - for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) - is->district_infos[i].resource_prereq_ids[j] = -1; - is->district_infos[i].resource_prereq_on_tile_id = -1; - is->district_infos[i].wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) - is->district_infos[i].wonder_prereq_ids[j] = -1; - is->district_infos[i].natural_wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) - is->district_infos[i].natural_wonder_prereq_ids[j] = -1; - is->district_infos[i].dependent_building_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) - is->district_infos[i].dependent_building_ids[j] = -1; - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) - is->district_configs[i].buildable_on_district_ids[j] = -1; - is->district_configs[i].buildable_on_district_id_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) - is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; - is->district_configs[i].buildable_adjacent_to_district_id_count = 0; - is->district_configs[i].generated_resource_id = -1; - continue; - } - if ((is->district_configs[i].name != NULL) && - (is->district_configs[i].command != 0) && - (is->district_configs[i].command != -1)) - itable_insert (&is->command_id_to_district_id, is->district_configs[i].command, i); - is->district_infos[i].advance_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) - is->district_infos[i].advance_prereq_ids[j] = -1; - is->district_infos[i].obsoleted_by_id = -1; - is->district_infos[i].resource_prereq_count = 0; - for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) - is->district_infos[i].resource_prereq_ids[j] = -1; - is->district_infos[i].resource_prereq_on_tile_id = -1; - is->district_infos[i].wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) - is->district_infos[i].wonder_prereq_ids[j] = -1; - is->district_infos[i].natural_wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) - is->district_infos[i].natural_wonder_prereq_ids[j] = -1; - - // Map advance prereqs to districts - int stored_tech_count = 0; - for (int j = 0; j < is->district_configs[i].advance_prereq_count; j++) { - char const * prereq = is->district_configs[i].advance_prereqs[j]; - if (prereq == NULL || prereq[0] == '\0') - continue; - int tech_id; - struct string_slice tech_name = { .str = (char *)prereq, .len = (int)strlen (prereq) }; - if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { - snprintf (ss, sizeof ss, "Found tech prereq \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); - (*p_OutputDebugStringA) (ss); - if (stored_tech_count < ARRAY_LEN (is->district_infos[i].advance_prereq_ids)) { - is->district_infos[i].advance_prereq_ids[stored_tech_count] = tech_id; - stored_tech_count++; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": advance_prereqs entry \"%.*s\" not found", district_name, tech_name.len, tech_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].advance_prereq_count = stored_tech_count; - - // Map obsoleted_by to tech ID - if (is->district_configs[i].obsoleted_by != NULL && is->district_configs[i].obsoleted_by != "") { - int tech_id; - struct string_slice tech_name = { .str = (char *)is->district_configs[i].obsoleted_by, .len = (int)strlen (is->district_configs[i].obsoleted_by) }; - if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { - snprintf (ss, sizeof ss, "Found tech obsoleted_by \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); - (*p_OutputDebugStringA) (ss); - is->district_infos[i].obsoleted_by_id = tech_id; - } else { - is->district_infos[i].obsoleted_by_id = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": obsoleted_by \"%.*s\" not found", district_name, tech_name.len, tech_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - // Map resource prereqs to districts (multiple resources now supported) - int stored_res_count = 0; - for (int j = 0; j < is->district_configs[i].resource_prereq_count; j++) { - if (is->district_configs[i].resource_prereqs[j] == "" || is->district_configs[i].resource_prereqs[j] == NULL) - continue; - int res_id; - struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereqs[j], .len = (int)strlen (is->district_configs[i].resource_prereqs[j]) }; - if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { - snprintf (ss, sizeof ss, "Found resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); - (*p_OutputDebugStringA) (ss); - if (stored_res_count < ARRAY_LEN (is->district_infos[i].resource_prereq_ids)) { - is->district_infos[i].resource_prereq_ids[stored_res_count] = res_id; - stored_res_count++; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq \"%.*s\" not found", district_name, res_name.len, res_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].resource_prereq_count = stored_res_count; - if (is->district_configs[i].resource_prereq_on_tile != NULL && is->district_configs[i].resource_prereq_on_tile != "") { - int res_id; - struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereq_on_tile, .len = (int)strlen (is->district_configs[i].resource_prereq_on_tile) }; - if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { - snprintf (ss, sizeof ss, "Found on-tile resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); - (*p_OutputDebugStringA) (ss); - is->district_infos[i].resource_prereq_on_tile_id = res_id; - } else { - is->district_infos[i].resource_prereq_on_tile_id = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq_on_tile \"%.*s\" not found", district_name, res_name.len, res_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - int stored_wonder_count = 0; - for (int j = 0; j < is->district_configs[i].wonder_prereq_count; j++) { - if (is->district_configs[i].wonder_prereqs[j] == "" || is->district_configs[i].wonder_prereqs[j] == NULL) - continue; - int improv_id; - struct string_slice wonder_name = { .str = (char *)is->district_configs[i].wonder_prereqs[j], .len = (int)strlen (is->district_configs[i].wonder_prereqs[j]) }; - if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { - if (stored_wonder_count < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids)) { - is->district_infos[i].wonder_prereq_ids[stored_wonder_count] = improv_id; - stored_wonder_count += 1; - } - stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": wonder_prereqs entry \"%.*s\" not found", district_name, wonder_name.len, wonder_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].wonder_prereq_count = stored_wonder_count; - - int stored_natural_wonder_count = 0; - for (int j = 0; j < is->district_configs[i].natural_wonder_prereq_count; j++) { - if (is->district_configs[i].natural_wonder_prereqs[j] == "" || is->district_configs[i].natural_wonder_prereqs[j] == NULL) - continue; - int natural_wonder_id = -1; - char const * name = is->district_configs[i].natural_wonder_prereqs[j]; - if (stable_look_up (&is->natural_wonder_name_to_id, (char *)name, &natural_wonder_id)) { - if (stored_natural_wonder_count < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids)) { - is->district_infos[i].natural_wonder_prereq_ids[stored_natural_wonder_count] = natural_wonder_id; - stored_natural_wonder_count += 1; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": natural_wonder_prereqs entry \"%s\" not found", district_name, name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].natural_wonder_prereq_count = stored_natural_wonder_count; - - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) - is->district_configs[i].buildable_on_district_ids[j] = -1; - is->district_configs[i].buildable_on_district_id_count = 0; - - if (is->district_configs[i].has_buildable_on_districts) { - int stored_buildable_on_count = 0; - for (int j = 0; j < is->district_configs[i].buildable_on_district_count; j++) { - char const * name = is->district_configs[i].buildable_on_districts[j]; - if (name == NULL || name[0] == '\0') - continue; - int other_district_id = find_district_index_by_name (name); - if (other_district_id >= 0) { - if (stored_buildable_on_count < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids)) { - is->district_configs[i].buildable_on_district_ids[stored_buildable_on_count] = other_district_id; - stored_buildable_on_count += 1; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_on_districts entry \"%s\" not found", district_name, name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_configs[i].buildable_on_district_id_count = stored_buildable_on_count; - } - - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) - is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; - is->district_configs[i].buildable_adjacent_to_district_id_count = 0; - - if (is->district_configs[i].has_buildable_adjacent_to_districts) { - int stored_adjacent_count = 0; - for (int j = 0; j < is->district_configs[i].buildable_adjacent_to_district_count; j++) { - char const * name = is->district_configs[i].buildable_adjacent_to_districts[j]; - if (name == NULL || name[0] == '\0') - continue; - int other_district_id = find_district_index_by_name (name); - if (other_district_id >= 0) { - if (stored_adjacent_count < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids)) { - is->district_configs[i].buildable_adjacent_to_district_ids[stored_adjacent_count] = other_district_id; - stored_adjacent_count += 1; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_adjacent_to_districts entry \"%s\" not found", district_name, name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_configs[i].buildable_adjacent_to_district_id_count = stored_adjacent_count; - } - - // Resolve generated resource name to ID - if (is->district_configs[i].generated_resource != NULL && is->district_configs[i].generated_resource != "") { - int res_id; - struct string_slice res_name = { .str = (char *)is->district_configs[i].generated_resource, .len = (int)strlen (is->district_configs[i].generated_resource) }; - if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { - snprintf (ss, sizeof ss, "Found generated resource \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); - (*p_OutputDebugStringA) (ss); - is->district_configs[i].generated_resource_id = res_id; - } else { - is->district_configs[i].generated_resource_id = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": generated_resource \"%.*s\" not found", district_name, res_name.len, res_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - // Map improvement prereqs to districts - int stored_count = 0; - for (int j = 0; j < is->district_configs[i].dependent_improvement_max_index; j++) { - int improv_id; - if (is->district_configs[i].dependent_improvements[j] == "" || is->district_configs[i].dependent_improvements[j] == NULL) - continue; - - // Gate wonder district prereqs behind enable_wonder_districts - if ((is->district_configs[i].command == UCV_Build_WonderDistrict) && (! cfg->enable_wonder_districts)) - continue; - - struct string_slice improv_name = { .str = (char *)is->district_configs[i].dependent_improvements[j], .len = (int)strlen (is->district_configs[i].dependent_improvements[j]) }; - if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { - snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for district \"%s\", ID %d\n", improv_name.len, improv_name.str, district_name, improv_id); - (*p_OutputDebugStringA) (ss); - if (stored_count < ARRAY_LEN (is->district_infos[i].dependent_building_ids)) { - is->district_infos[i].dependent_building_ids[stored_count] = improv_id; - stored_count += 1; - } - add_district_building_prereq (improv_id, i); - stable_insert (&is->building_name_to_id, improv_name.str, improv_id); - } else { - is->district_infos[i].dependent_building_ids[j] = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": dependent_improvs entry \"%.*s\" not found", district_name, improv_name.len, improv_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - is->district_infos[i].dependent_building_count = stored_count; - } - - resolve_district_bonus_building_entries (&is->district_configs[i].culture_bonus_extras, district_name, "culture_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].science_bonus_extras, district_name, "science_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].food_bonus_extras, district_name, "food_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].gold_bonus_extras, district_name, "gold_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].shield_bonus_extras, district_name, "shield_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].happiness_bonus_extras, district_name, "happiness_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].defense_bonus_extras, district_name, "defense_bonus_percent", &district_parse_errors); - } - - resolve_counter_rule_districts (&district_parse_errors); - - // Map wonder names to their improvement IDs for rendering under-construction wonders - for (int wi = 0; wi < is->wonder_district_count; wi++) { - if (is->wonder_district_configs[wi].wonder_name == NULL || is->wonder_district_configs[wi].wonder_name[0] == '\0') - continue; - - int improv_id; - struct string_slice wonder_name = { .str = (char *)is->wonder_district_configs[wi].wonder_name, .len = (int)strlen (is->wonder_district_configs[wi].wonder_name) }; - if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { - snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for wonder district \"%s\", ID %d\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name, improv_id); - (*p_OutputDebugStringA) (ss); - stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); - } else { - snprintf (ss, sizeof ss, "Could not find improvement prereq \"%.*s\" for wonder district \"%s\"\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name); - (*p_OutputDebugStringA) (ss); - struct error_line * err = add_error_line (&wonder_parse_errors); - snprintf (err->text, sizeof err->text, "^ Wonder district \"%s\": improvement \"%.*s\" not found", (is->wonder_district_configs[wi].wonder_name != NULL) ? is->wonder_district_configs[wi].wonder_name : "Wonder District", wonder_name.len, wonder_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - if ((district_parse_errors != NULL) || (wonder_parse_errors != NULL)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - - if (district_parse_errors != NULL) { - char header[256]; - if (is->current_districts_config_path[0] != '\0') - snprintf (header, sizeof header, "District Config errors in %s:", is->current_districts_config_path); - else - snprintf (header, sizeof header, "District Config lookup errors:"); - header[(sizeof header) - 1] = '\0'; - PopupForm_add_text (popup, __, header, false); - for (struct error_line * line = district_parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - - if ((district_parse_errors != NULL) && (wonder_parse_errors != NULL)) - PopupForm_add_text (popup, __, "", false); - - if (wonder_parse_errors != NULL) { - char header[256]; - snprintf (header, sizeof header, "Wonder District Config lookup errors:"); - header[(sizeof header) - 1] = '\0'; - PopupForm_add_text (popup, __, header, false); - for (struct error_line * line = wonder_parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - - patch_show_popup (popup, __, 0, 0); - free_error_lines (district_parse_errors); - free_error_lines (wonder_parse_errors); - } -} - -void -load_districts_config () -{ - clear_dynamic_district_definitions (); - load_dynamic_district_configs (); - load_dynamic_wonder_configs (); - load_natural_wonder_configs (); - is->district_count = is->special_district_count + is->dynamic_district_count; - - set_wonders_dependent_on_wonder_district (); - parse_building_and_tech_ids (); -} - -void -place_natural_wonders_on_map (void) -{ - if (! is->current_config.enable_natural_wonders) - return; - - int wonder_count = is->natural_wonder_count; - if (wonder_count <= 0) - return; - - struct natural_wonder_candidate_list * candidate_lists = (struct natural_wonder_candidate_list *)calloc (wonder_count, sizeof *candidate_lists); - bool * already_placed = (bool *)calloc (wonder_count, sizeof *already_placed); - - if ((candidate_lists == NULL) || (already_placed == NULL)) { - if (candidate_lists != NULL) free (candidate_lists); - if (already_placed != NULL) free (already_placed); - return; - } - - struct wonder_location * placements = NULL; - int placement_count = 0; - int placement_capacity = 0; - int existing_count = 0; - - // Record existing natural wonders - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - - int wonder_id = inst->natural_wonder_info.natural_wonder_id; - if ((wonder_id < 0) || (wonder_id >= wonder_count)) - continue; - - already_placed[wonder_id] = true; - - Tile * tile = (Tile *)tei.key; - int tile_x, tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - continue; - - if (placement_count >= placement_capacity) { - int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; - struct wonder_location * grown = - (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); - if (grown == NULL) - continue; - placements = grown; - placement_capacity = new_capacity; - } - - if (placements != NULL) { - placements[placement_count++] = (struct wonder_location){ - .x = (short)tile_x, - .y = (short)tile_y - }; - existing_count += 1; - } - } - - // Build candidate lists - int map_width = p_bic_data->Map.Width; - int map_height = p_bic_data->Map.Height; - int minimum_separation = is->current_config.minimum_natural_wonder_separation; - - for (int y = 0; y < map_height; y++) { - for (int x = 0; x < map_width; x++) { - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - if (! natural_wonder_tile_is_clear (tile, x, y)) continue; - if (district_exists_within_distance (x, y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; - - for (int ni = 0; ni < wonder_count; ni++) { - if (already_placed[ni]) - continue; - - struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; - if (cfg->name == NULL) - continue; - - if (! natural_wonder_terrain_matches (cfg, tile, x, y)) - continue; - - natural_wonder_candidate_list_push (&candidate_lists[ni], tile, x, y); - } - } - } - - bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; - int newly_placed = 0; - int * wonder_order = (int *)malloc (wonder_count * sizeof *wonder_order); - if (wonder_order != NULL) { - for (int i = 0; i < wonder_count; i++) - wonder_order[i] = i; - for (int i = wonder_count - 1; i > 0; i--) { - int swap_index = rand_int (p_rand_object, __, i + 1); - int temp = wonder_order[i]; - wonder_order[i] = wonder_order[swap_index]; - wonder_order[swap_index] = temp; - } - } - - for (int order_index = 0; order_index < wonder_count; order_index++) { - int ni = (wonder_order != NULL) ? wonder_order[order_index] : order_index; - if (already_placed[ni]) - continue; - - struct natural_wonder_candidate_list * list = &candidate_lists[ni]; - if (list->count == 0) { - char msg[256]; - snprintf (msg, sizeof msg, "[C3X] No valid tiles to place natural wonder \"%s\".\n", - (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); - (*p_OutputDebugStringA) (msg); - continue; - } - - int best_index = -1; - int best_dist = -1; - int best_adjacent_count = -1; - int best_target_diff = INT_MAX; - int best_rand = INT_MAX; - int best_same_type_count = -1; - int best_continent_priority = INT_MAX; - int target_x = (wonder_count > 0) - ? (int)(((long long)(2 * ni + 1) * map_width) / (2 * wonder_count)) - : (map_width >> 1); - - for (int ci = 0; ci < list->count; ci++) { - struct natural_wonder_candidate * cand = &list->entries[ci]; - Tile * tile = cand->tile; - if ((tile == NULL) || (tile == p_null_tile)) continue; - if (get_district_instance (tile) != NULL) continue; - if (! natural_wonder_tile_is_clear (tile, cand->x, cand->y)) continue; - if (! natural_wonder_terrain_matches (&is->natural_wonder_configs[ni], tile, cand->x, cand->y)) continue; - if (district_exists_within_distance (cand->x, cand->y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; - - int min_dist_sq = natural_wonder_min_distance_sq (cand->x, cand->y, placements, placement_count); - if (min_dist_sq == INT_MAX) { - int span = (map_width * map_width) + (map_height * map_height); - if (span <= 0) - span = INT_MAX; - min_dist_sq = span; - } - - int dx_raw = int_abs (cand->x - target_x); - int dx_adjusted = compute_wrapped_component (dx_raw, map_width, wraps_horiz); - int rand_val = rand_int (p_rand_object, __, 0x7FFF); - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - int continent_priority = 1; - if ((continent_id >= 0) && ! continent_has_natural_wonder (continent_id, placements, placement_count)) - continent_priority = 0; - - bool adjacency_bonus_active = - (is->natural_wonder_configs[ni].adjacent_to != (enum SquareTypes)SQ_INVALID) && - (is->natural_wonder_configs[ni].adjacency_dir == DIR_ZERO); - int adjacency_count = -1; - if (adjacency_bonus_active) - adjacency_count = count_adjacent_tiles_of_type (cand->x, cand->y, - is->natural_wonder_configs[ni].adjacent_to); - - int same_type_count = count_adjacent_tiles_of_type (cand->x, cand->y, - is->natural_wonder_configs[ni].terrain_type); - - bool better = false; - if (continent_priority < best_continent_priority) - better = true; - else if (continent_priority > best_continent_priority) - continue; - - if (! better && adjacency_bonus_active) { - if (adjacency_count > best_adjacent_count) - better = true; - else if (adjacency_count < best_adjacent_count) - continue; - } - - if (! better) { - if (same_type_count > best_same_type_count) - better = true; - else if (same_type_count < best_same_type_count) - continue; - } - - if (! better) { - if ((min_dist_sq > best_dist) || - ((min_dist_sq == best_dist) && (dx_adjusted < best_target_diff)) || - ((min_dist_sq == best_dist) && (dx_adjusted == best_target_diff) && (rand_val < best_rand))) - better = true; - else - continue; - } - - best_dist = min_dist_sq; - best_target_diff = dx_adjusted; - best_rand = rand_val; - best_index = ci; - best_continent_priority = continent_priority; - if (adjacency_bonus_active) - best_adjacent_count = adjacency_count; - best_same_type_count = same_type_count; - } - - if (best_index < 0) { - char msg[256]; - snprintf (msg, sizeof msg, "[C3X] Could not find a suitable tile for natural wonder \"%s\" after filtering.\n", - (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); - (*p_OutputDebugStringA) (msg); - continue; - } - - struct natural_wonder_candidate * chosen = &list->entries[best_index]; - assign_natural_wonder_to_tile (chosen->tile, chosen->x, chosen->y, ni); - - if (placement_count >= placement_capacity) { - int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; - struct wonder_location * grown = - (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); - if (grown != NULL) { - placements = grown; - placement_capacity = new_capacity; - } - } - - if ((placements != NULL) && (placement_count < placement_capacity)) { - placements[placement_count++] = (struct wonder_location){ - .x = chosen->x, - .y = chosen->y - }; - } - - newly_placed += 1; - - char msg[256]; - snprintf (msg, sizeof msg, "[C3X] Placed natural wonder \"%s\" at (%d,%d).\n", - (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder", - chosen->x, chosen->y); - (*p_OutputDebugStringA) (msg); - } - - char summary[256]; - snprintf (summary, sizeof summary, "[C3X] Natural wonder placement complete. Newly placed: %d, already present: %d.\n", - newly_placed, existing_count); - (*p_OutputDebugStringA) (summary); - - for (int ni = 0; ni < wonder_count; ni++) - free (candidate_lists[ni].entries); - free (wonder_order); - free (candidate_lists); - free (already_placed); - free (placements); -} - -void -init_scenario_district_entry (struct scenario_district_entry * entry) -{ - if (entry == NULL) - return; - - memset (entry, 0, sizeof *entry); -} - -void -init_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) -{ - if (entry == NULL) - return; - - memset (entry, 0, sizeof *entry); -} - -void -free_scenario_district_entry (struct scenario_district_entry * entry) -{ - if (entry == NULL) - return; - - if (entry->district_name != NULL) { - free (entry->district_name); - entry->district_name = NULL; - } - if (entry->wonder_city_name != NULL) { - free (entry->wonder_city_name); - entry->wonder_city_name = NULL; - } - if (entry->wonder_name != NULL) { - free (entry->wonder_name); - entry->wonder_name = NULL; - } - entry->has_coordinates = 0; - entry->has_district_name = 0; - entry->has_wonder_city = 0; - entry->has_wonder_name = 0; -} - -void -free_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) -{ - if (entry == NULL) - return; - - if (entry->name != NULL) { - free (entry->name); - entry->name = NULL; - } - entry->has_coordinates = 0; - entry->has_name = 0; -} - -void -add_scenario_district_error (struct error_line ** parse_errors, - int line_number, - char const * message) -{ - if (message == NULL) - return; - - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s", line_number, message); - err->text[(sizeof err->text) - 1] = '\0'; -} - -int -parse_scenario_district_coordinates (struct string_slice const * value, int * out_x, int * out_y) -{ - if ((value == NULL) || (out_x == NULL) || (out_y == NULL)) - return 0; - - char * text = trim_and_extract_slice (value, 0); - if (text == NULL) - return 0; - - char * cursor = text; - int success = 0; - int x, y; - if (parse_int (&cursor, &x) && - skip_punctuation (&cursor, ',') && - parse_int (&cursor, &y)) { - skip_horiz_space (&cursor); - success = (*cursor == '\0'); - if (success) { - *out_x = x; - *out_y = y; - } - } - - free (text); - return success; -} - -int -finalize_scenario_district_entry (struct scenario_district_entry * entry, - int section_start_line, - struct error_line ** parse_errors) -{ - int success = 1; - if ((entry == NULL) || (parse_errors == NULL)) - return 0; - - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return 1; - } - - if (! entry->has_coordinates) - add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); - if ((! entry->has_district_name) || (entry->district_name == NULL) || (entry->district_name[0] == '\0')) - add_scenario_district_error (parse_errors, section_start_line, "district (value is required)"); - - if ((! entry->has_coordinates) || (! entry->has_district_name) || - (entry->district_name == NULL) || (entry->district_name[0] == '\0')) - success = 0; - - int map_x = entry->tile_x; - int map_y = entry->tile_y; - if (success) { - wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); - Tile * tile = tile_at (map_x, map_y); - if ((tile == NULL) || (tile == p_null_tile)) { - add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); - success = 0; - } else { - int district_id = find_district_index_by_name (entry->district_name); - if ((district_id < 0) || (district_id >= is->district_count)) { - char msg[200]; - snprintf (msg, sizeof msg, "district (unrecognized name: \"%s\")", entry->district_name); - add_scenario_district_error (parse_errors, section_start_line, msg); - success = 0; - } else { - if ((district_id == NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_natural_wonders) { - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return 1; - } - if ((district_id != NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_districts) { - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return 1; - } - struct district_instance * inst = ensure_district_instance (tile, district_id, map_x, map_y); - if (inst == NULL) { - add_scenario_district_error (parse_errors, section_start_line, "Failed to create district instance"); - success = 0; - } else { - inst->district_id = district_id; - district_instance_set_coords (inst, map_x, map_y); - inst->state = DS_COMPLETED; - inst->wonder_info.state = WDS_UNUSED; - inst->wonder_info.city = NULL; - inst->wonder_info.city_id = -1; - inst->wonder_info.wonder_index = -1; - inst->natural_wonder_info.natural_wonder_id = -1; - - if (district_id == WONDER_DISTRICT_ID) { - int has_city = entry->has_wonder_city && - (entry->wonder_city_name != NULL) && (entry->wonder_city_name[0] != '\0'); - int has_wonder = entry->has_wonder_name && - (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); - if (! has_city || ! has_wonder) { - add_scenario_district_error (parse_errors, section_start_line, "Wonder district requires both wonder_city and wonder_name"); - success = 0; - } else { - int wonder_index = find_wonder_district_index_by_name (entry->wonder_name); - if (wonder_index < 0) { - char msg[200]; - snprintf (msg, sizeof msg, "wonder_name (unrecognized wonder: \"%s\")", entry->wonder_name); - add_scenario_district_error (parse_errors, section_start_line, msg); - success = 0; - } else { - inst->wonder_info.city = NULL; - inst->wonder_info.city_id = -1; - inst->wonder_info.state = WDS_COMPLETED; - inst->wonder_info.wonder_index = wonder_index; - } - } - } else if (district_id == NATURAL_WONDER_DISTRICT_ID) { - int has_name = entry->has_wonder_name && - (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); - if (! has_name) { - add_scenario_district_error (parse_errors, section_start_line, "Natural Wonder district requires wonder_name"); - success = 0; - } else { - int natural_index = find_natural_wonder_index_by_name (entry->wonder_name); - if (natural_index < 0) { - char msg[200]; - snprintf (msg, sizeof msg, "wonder_name (unrecognized natural wonder: \"%s\")", entry->wonder_name); - add_scenario_district_error (parse_errors, section_start_line, msg); - success = 0; - } else - inst->natural_wonder_info.natural_wonder_id = natural_index; - } - if (entry->has_wonder_city) - add_scenario_district_error (parse_errors, section_start_line, "wonder_city ignored for Natural Wonder district entries"); - } else if (entry->has_wonder_city || entry->has_wonder_name) { - add_scenario_district_error (parse_errors, section_start_line, "wonder_* fields only valid for Wonder or Natural Wonder district entries"); - } - - if (success) { - if (district_id != NATURAL_WONDER_DISTRICT_ID && !tile->vtable->m18_Check_Mines (tile, __, 0)) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, map_x, map_y); - set_tile_unworkable_for_all_cities (tile, map_x, map_y); - } - } - } - } - } - - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return success; -} - -bool -tile_can_be_named (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) - return false; - return true; -} - -void -remove_named_tile_entry (Tile * tile) -{ - struct named_tile_entry * entry = get_named_tile_entry (tile); - if (entry == NULL) - return; - itable_remove (&is->named_tile_map, (int)tile); - free (entry); -} - -void -set_named_tile_entry (Tile * tile, int tile_x, int tile_y, char const * name) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return; - if ((name == NULL) || (name[0] == '\0')) { - remove_named_tile_entry (tile); - return; - } - - struct named_tile_entry * entry = get_named_tile_entry (tile); - if (entry == NULL) { - entry = calloc (1, sizeof *entry); - if (entry == NULL) - return; - itable_insert (&is->named_tile_map, (int)tile, (int)entry); - } - entry->tile_x = tile_x; - entry->tile_y = tile_y; - strncpy (entry->name, name, sizeof entry->name); - entry->name[(sizeof entry->name) - 1] = '\0'; -} - -int -finalize_scenario_named_tile_entry (struct scenario_named_tile_entry * entry, - int section_start_line, - struct error_line ** parse_errors) -{ - int success = 1; - if ((entry == NULL) || (parse_errors == NULL)) - return 0; - - if (! is->current_config.enable_named_tiles) { - free_scenario_named_tile_entry (entry); - init_scenario_named_tile_entry (entry); - return 1; - } - - if (! entry->has_coordinates) - add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); - if ((! entry->has_name) || (entry->name == NULL) || (entry->name[0] == '\0')) - add_scenario_district_error (parse_errors, section_start_line, "name (value is required)"); - - if ((! entry->has_coordinates) || (! entry->has_name) || - (entry->name == NULL) || (entry->name[0] == '\0')) - success = 0; - - int map_x = entry->tile_x; - int map_y = entry->tile_y; - if (success) { - wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); - Tile * tile = tile_at (map_x, map_y); - if ((tile == NULL) || (tile == p_null_tile)) { - add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); - success = 0; - } else if (! tile_can_be_named (tile, map_x, map_y)) { - add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile cannot be named)"); - success = 0; - } else { - set_named_tile_entry (tile, map_x, map_y, entry->name); - } - } - - free_scenario_named_tile_entry (entry); - init_scenario_named_tile_entry (entry); - return success; -} - -void -handle_scenario_district_key (struct scenario_district_entry * entry, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if ((entry == NULL) || (key == NULL) || (value == NULL)) - return; - - if (slice_matches_str (key, "coordinates")) { - int x, y; - if (parse_scenario_district_coordinates (value, &x, &y)) { - entry->tile_x = x; - entry->tile_y = y; - entry->has_coordinates = 1; - } else - add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); - - } else if (slice_matches_str (key, "district")) { - if (entry->district_name != NULL) { - free (entry->district_name); - entry->district_name = NULL; - } - entry->district_name = copy_trimmed_string_or_null (value, 1); - entry->has_district_name = (entry->district_name != NULL); - if (! entry->has_district_name) - add_scenario_district_error (parse_errors, line_number, "district (value is required)"); - - } else if (slice_matches_str (key, "wonder_city")) { - if (entry->wonder_city_name != NULL) { - free (entry->wonder_city_name); - entry->wonder_city_name = NULL; - } - entry->wonder_city_name = copy_trimmed_string_or_null (value, 1); - entry->has_wonder_city = (entry->wonder_city_name != NULL); - - } else if (slice_matches_str (key, "wonder_name")) { - if (entry->wonder_name != NULL) { - free (entry->wonder_name); - entry->wonder_name = NULL; - } - entry->wonder_name = copy_trimmed_string_or_null (value, 1); - entry->has_wonder_name = (entry->wonder_name != NULL); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -void -handle_scenario_named_tile_key (struct scenario_named_tile_entry * entry, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if ((entry == NULL) || (key == NULL) || (value == NULL)) - return; - - if (slice_matches_str (key, "coordinates")) { - int x, y; - if (parse_scenario_district_coordinates (value, &x, &y)) { - entry->tile_x = x; - entry->tile_y = y; - entry->has_coordinates = 1; - } else - add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); - - } else if (slice_matches_str (key, "name")) { - if (entry->name != NULL) { - free (entry->name); - entry->name = NULL; - } - entry->name = copy_trimmed_string_or_null (value, 1); - entry->has_name = (entry->name != NULL); - if (! entry->has_name) - add_scenario_district_error (parse_errors, line_number, "name (value is required)"); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -// Parses a .c3x.txt file corresponding to the given scenario file path, loading district instances as specified. -// -// The expected file format itself is very simple. Example: -// -// ``` -// DISTRICTS -// -// #District -// coordinates = 12,28 -// district = Entertainment Complex -// -// #District -// coordinates = 9,23 -// district = Wonder District -// wonder_city = Rome -// wonder_name = The Pyramids -// -// #District -// coordinates = 10,30 -// district = Natural Wonder -// wonder_name = Mount Everest -// -// #NamedTile -// coordinates = 41,23 -// name = Tiber River -// ``` -// -// Details at https://github.com/instafluff0/Civ3_Editor_Fork_for_C3X_Districts -void -load_scenario_districts_from_file () -{ - char * scenario_filename = "scenario.districts.txt"; - char * scenario_districts_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - - // BIC_get_asset_path returns the file name when it can't find the file - if ((scenario_districts_path == NULL) || (0 == strcmp (scenario_filename, scenario_districts_path))) - return; - - char * text = file_to_string (scenario_districts_path); - if (text == NULL) - return; - - struct scenario_district_entry entry; - struct scenario_named_tile_entry named_entry; - init_scenario_district_entry (&entry); - init_scenario_named_tile_entry (&named_entry); - int in_section = 0; - int section_start_line = 0; - int section_type = 0; - int line_number = 0; - int header_seen = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - int has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - // Keep support for legacy header, technically not needed - if (! header_seen) { - if (slice_matches_str (&trimmed, "DISTRICTS")) { - header_seen = 1; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if (slice_matches_str (&directive, "District")) { - if (in_section) { - if (section_type == 1) - finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); - else if (section_type == 2) - finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); - } - in_section = 1; - section_type = 1; - section_start_line = line_number; - free_scenario_district_entry (&entry); - init_scenario_district_entry (&entry); - } else if (slice_matches_str (&directive, "NamedTile")) { - if (in_section) { - if (section_type == 1) - finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); - else if (section_type == 2) - finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); - } - in_section = 1; - section_type = 2; - section_start_line = line_number; - free_scenario_named_tile_entry (&named_entry); - init_scenario_named_tile_entry (&named_entry); - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - switch (parse_trimmed_key_value (&trimmed, &key_slice, &value_slice)) { - case KVP_NO_EQUALS: - add_scenario_district_error (&parse_errors, line_number, "(expected '=')"); - break; - case KVP_EMPTY_KEY: - add_scenario_district_error (&parse_errors, line_number, "(missing key)"); - break; - case KVP_SUCCESS: - if (section_type == 1) - handle_scenario_district_key (&entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - else if (section_type == 2) - handle_scenario_named_tile_key (&named_entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - break; - } - - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) { - if (section_type == 1) - finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); - else if (section_type == 2) - finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); - } - - free_scenario_district_entry (&entry); - free_scenario_named_tile_entry (&named_entry); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (scenario_districts_path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - - if ((parse_errors != NULL) || (unrecognized_keys != NULL)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char header[256]; - snprintf (header, sizeof header, "District scenario file issues in %s:", scenario_districts_path); - header[(sizeof header) - 1] = '\0'; - PopupForm_add_text (popup, __, header, 0); - if (parse_errors != NULL) - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, 0); - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", 0); - PopupForm_add_text (popup, __, "Unrecognized keys:", 0); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, 0); - } - patch_show_popup (popup, __, 0, 0); - } - - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); -} - -void -deinit_district_images (void) -{ - if (is->dc_img_state == IS_OK) { - for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) { - for (int variant = 0; variant < ARRAY_LEN (is->district_img_sets[dc].imgs); variant++) - for (int era = 0; era < 4; era++) - for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc].imgs[variant][era]); col++) { - Sprite * sprite = &is->district_img_sets[dc].imgs[variant][era][col]; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - } - - for (int wi = 0; wi < MAX_WONDER_DISTRICT_TYPES; wi++) { - struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; - if (set->img.vtable != NULL) - set->img.vtable->destruct (&set->img, __, 0); - if (set->construct_img.vtable != NULL) - set->construct_img.vtable->destruct (&set->construct_img, __, 0); - if (set->alt_dir_img.vtable != NULL) - set->alt_dir_img.vtable->destruct (&set->alt_dir_img, __, 0); - if (set->alt_dir_construct_img.vtable != NULL) - set->alt_dir_construct_img.vtable->destruct (&set->alt_dir_construct_img, __, 0); - } - - for (int ni = 0; ni < MAX_NATURAL_WONDER_DISTRICT_TYPES; ni++) { - Sprite * sprite = &is->natural_wonder_img_sets[ni].img; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - - if (is->abandoned_district_img.vtable != NULL) - is->abandoned_district_img.vtable->destruct (&is->abandoned_district_img, __, 0); - if (is->abandoned_maritime_district_img.vtable != NULL) - is->abandoned_maritime_district_img.vtable->destruct (&is->abandoned_maritime_district_img, __, 0); - } - - is->dc_img_state = IS_UNINITED; -} - -void -clear_highlighted_worker_tiles_for_districts () -{ - FOR_TABLE_ENTRIES (tei, &is->highlighted_city_radius_tile_pointers) { - struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)tei.value; - if (info != NULL) - free (info); - } - table_deinit (&is->highlighted_city_radius_tile_pointers); -} - - -void -reset_district_state (bool reset_tile_map) -{ - clear_all_tracked_workers (); - deinit_district_images (); - deinit_district_command_buttons (); - clear_highlighted_worker_tiles_for_districts (); - - FOR_TABLE_ENTRIES (tei, &is->district_building_prereqs) { - struct district_building_prereq_list * list = (struct district_building_prereq_list *)tei.value; - if (list != NULL) - free (list); - } - table_deinit (&is->district_building_prereqs); - table_deinit (&is->command_id_to_district_id); - stable_deinit (&is->building_name_to_id); - if (reset_tile_map) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst != NULL) - free (inst); - } - table_deinit (&is->district_tile_map); - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if (entry != NULL) - free (entry); - } - table_deinit (&is->named_tile_map); - } - - clear_distribution_hub_tables (); - - is->distribution_hub_totals_dirty = true; - - clear_dynamic_district_definitions (); - is->district_count = is->special_district_count; - - for (int i = 0; i < COUNT_DISTRICT_TYPES; i++) { - is->district_infos[i].advance_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) - is->district_infos[i].advance_prereq_ids[j] = -1; - is->district_infos[i].obsoleted_by_id = -1; - is->district_infos[i].resource_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].resource_prereq_ids); j++) - is->district_infos[i].resource_prereq_ids[j] = -1; - is->district_infos[i].resource_prereq_on_tile_id = -1; - is->district_infos[i].wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) - is->district_infos[i].wonder_prereq_ids[j] = -1; - is->district_infos[i].natural_wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) - is->district_infos[i].natural_wonder_prereq_ids[j] = -1; - is->district_infos[i].dependent_building_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) - is->district_infos[i].dependent_building_ids[j] = -1; - } - - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req != NULL) - free (req); - } - table_deinit (&is->city_pending_district_requests[civ_id]); - } - table_deinit (&is->city_pending_building_orders); - - is->great_wall_auto_build = GWABS_NOT_STARTED; -} - -void -clear_city_district_request (City * city, int district_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (district_id < 0) || (district_id >= is->district_count)) - return; - - struct pending_district_request * req = find_pending_district_request (city, district_id); - if (req == NULL) - return; - - remove_pending_district_request (req); - - int pending_improv_id; - if (look_up_pending_building_order (city, &pending_improv_id)) { - int required_district_id; - if (city_requires_district_for_improvement (city, pending_improv_id, &required_district_id)) { - if (required_district_id == district_id) - forget_pending_building_order (city); - } - } -} - -bool -district_resource_prereqs_met_r (Tile * tile, int tile_x, int tile_y, int district_id, int max_req_resource_id) -{ - if ((tile == NULL) || (tile == p_null_tile) || - (district_id < 0) || (district_id >= is->district_count)) - return false; - - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - struct district_infos * info = &is->district_infos[district_id]; - int on_tile_req = info->resource_prereq_on_tile_id; - if (on_tile_req >= 0) { - int res_here = (owner >= 0) ? Tile_get_resource_visible_to (tile, __, owner) : -1; - if (res_here != on_tile_req) - return false; - } - - // If no resource prereqs, then the check passes - if (info->resource_prereq_count <= 0) - return true; - - if (owner < 0) - return false; - - // Check resource prereqs - ALL must be present - for (int i = 0; i < info->resource_prereq_count; i++) { - int resource_req = info->resource_prereq_ids[i]; - if (resource_req < 0) - continue; - if (resource_req > max_req_resource_id) - return false; - - bool has_resource = false; - bool is_bonus_resource = p_bic_data->ResourceTypes[resource_req].Class == RC_Bonus; - - FOR_CITIES_OF (coi, owner) { - City * req_city = coi.city; - if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, req_city, tile_x, tile_y)) - continue; - if (! city_has_resource_r (req_city, resource_req, max_req_resource_id)) - if (! is_bonus_resource) - continue; - else { - int civ_id = req_city->Body.CivID; - FOR_TILES_AROUND (tai, is->workable_tile_count, req_city->Body.X, req_city->Body.Y) { - Tile * radius_tile = tai.tile; - if ((radius_tile == NULL) || (radius_tile == p_null_tile)) - continue; - if (radius_tile->vtable->m38_Get_Territory_OwnerID (radius_tile) != civ_id) - continue; - if (Tile_get_resource_visible_to (radius_tile, __, civ_id) == resource_req) { - has_resource = true; - break; - } - } - if (has_resource) - break; - continue; - } - - has_resource = true; - break; - } - - // If this required resource is not available, the check fails - if (!has_resource) - return false; - } - - return true; -} - -bool -district_resource_prereqs_met (Tile * tile, int tile_x, int tile_y, int district_id) -{ - return district_resource_prereqs_met_r (tile, tile_x, tile_y, district_id, INT_MAX); -} - -int -count_contiguous_bridge_districts (int tile_x, int tile_y, int dx, int dy) -{ - Map * map = &p_bic_data->Map; - int nx = tile_x + dx; - int ny = tile_y + dy; - int count = 0; - int max_steps = map->Width + map->Height; - - for (int step = 0; step < max_steps; step++) { - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) - break; - count++; - nx += dx; - ny += dy; - } - - return count; -} - -int -count_contiguous_canal_districts (int tile_x, int tile_y, int max_count) -{ - if (max_count <= 0) - return 0; - - Map * map = &p_bic_data->Map; - int limit = max_count + 1; - int capacity = limit; - if (capacity < 1) - capacity = 1; - - int * xs = malloc (sizeof (*xs) * capacity); - int * ys = malloc (sizeof (*ys) * capacity); - if ((xs == NULL) || (ys == NULL)) { - if (xs != NULL) - free (xs); - if (ys != NULL) - free (ys); - return limit; - } - - int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; - int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; - int head = 0; - int tail = 0; - int count = 0; - - xs[tail] = tile_x; - ys[tail] = tile_y; - tail++; - - while (head < tail) { - int cx = xs[head]; - int cy = ys[head]; - head++; - count++; - if (count >= limit) - break; - - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) - continue; - - bool seen = false; - for (int j = 0; j < tail; j++) { - if ((xs[j] == nx) && (ys[j] == ny)) { - seen = true; - break; - } - } - if (seen) - continue; - - if (tail < capacity) { - xs[tail] = nx; - ys[tail] = ny; - tail++; - } else { - count = limit; - head = tail; - break; - } - } - } - - free (xs); - free (ys); - - return count; -} - -bool -district_line_is_straight (int tile_x, int tile_y, int district_id) -{ - Map * map = &p_bic_data->Map; - int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; - int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; - - for (int i = 0; i < 8; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, district_id)) - continue; - - int cand_dx = -adj_dx[i]; - int cand_dy = -adj_dy[i]; - - for (int j = 0; j < 8; j++) { - int ox = nx + adj_dx[j]; - int oy = ny + adj_dy[j]; - wrap_tile_coords (map, &ox, &oy); - if ((ox == tile_x) && (oy == tile_y)) - continue; - if (! tile_has_district_at (ox, oy, district_id)) - continue; - - if (! ((adj_dx[j] == cand_dx) && (adj_dy[j] == cand_dy)) && - ! ((adj_dx[j] == -cand_dx) && (adj_dy[j] == -cand_dy))) - return false; - } - } - - return true; -} - -bool -bridge_district_tile_is_valid (int tile_x, int tile_y) -{ - if (! tile_is_coastal_water (tile_x, tile_y)) - return false; - - bool has_adjacent_land_or_bridge = false; - Map * map = &p_bic_data->Map; - int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; - int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; - - for (int i = 0; i < 8; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (tile_is_land (-1, nx, ny, false) || tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) { - has_adjacent_land_or_bridge = true; - break; - } - } - if (! has_adjacent_land_or_bridge) - return false; - - if (is->current_config.max_contiguous_bridge_districts > 0) { - int max_bridges = is->current_config.max_contiguous_bridge_districts; - - int ns_count = count_contiguous_bridge_districts (tile_x, tile_y, 0, -2) + - count_contiguous_bridge_districts (tile_x, tile_y, 0, 2); - if (ns_count >= max_bridges) - return false; - - int we_count = count_contiguous_bridge_districts (tile_x, tile_y, -2, 0) + - count_contiguous_bridge_districts (tile_x, tile_y, 2, 0); - if (we_count >= max_bridges) - return false; - - int swne_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, 1) + - count_contiguous_bridge_districts (tile_x, tile_y, 1, -1); - if (swne_count >= max_bridges) - return false; - - int nwse_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, -1) + - count_contiguous_bridge_districts (tile_x, tile_y, 1, 1); - if (nwse_count >= max_bridges) - return false; - } - - return district_line_is_straight (tile_x, tile_y, BRIDGE_DISTRICT_ID); -} - -bool -canal_district_tile_is_valid (int tile_x, int tile_y) -{ - if (tile_is_water (tile_x, tile_y)) - return false; - - if (is->current_config.max_contiguous_canal_districts > 0) { - int count = count_contiguous_canal_districts (tile_x, tile_y, is->current_config.max_contiguous_canal_districts); - if (count > is->current_config.max_contiguous_canal_districts) - return false; - } - - Map * map = &p_bic_data->Map; - int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; - int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; - - for (int i = 0; i < 8; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * tile = tile_at (nx, ny); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m35_Check_Is_Water (tile)) - return true; - - if (tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && - district_is_complete (tile, CANAL_DISTRICT_ID)) - return true; - } - } - - return false; -} - -bool -can_build_district_on_tile (Tile * tile, int district_id, int civ_id) -{ - if ((! is->current_config.enable_districts) || - (tile == NULL) || (tile == p_null_tile) || - (tile->CityID >= 0) || - tile->vtable->m21_Check_Crates (tile, __, 0) || - tile->vtable->m20_Check_Pollution (tile, __, 0) || - (district_id < 0) || (district_id >= is->district_count)) - return false; - - struct district_config const * cfg = &is->district_configs[district_id]; - if (cfg->command == -1) - return false; - - if ((cfg->command == UCV_Build_Neighborhood) && !is->current_config.enable_neighborhood_districts) return false; - if ((cfg->command == UCV_Build_WonderDistrict) && !is->current_config.enable_wonder_districts) return false; - if ((cfg->command == UCV_Build_DistributionHub) && !is->current_config.enable_distribution_hub_districts) return false; - if ((cfg->command == UCV_Build_Aerodrome) && !is->current_config.enable_aerodrome_districts) return false; - if ((cfg->command == UCV_Build_Port) && !is->current_config.enable_port_districts) return false; - if ((cfg->command == UCV_Build_Bridge) && !is->current_config.enable_bridge_districts) return false; - if ((cfg->command == UCV_Build_CentralRailHub) && !is->current_config.enable_central_rail_hub_districts) return false; - if ((cfg->command == UCV_Build_EnergyGrid) && !is->current_config.enable_energy_grid_districts) return false; - if ((cfg->command == UCV_Build_GreatWall) && !is->current_config.enable_great_wall_districts) return false; - - if (! district_is_buildable_on_tile (cfg, tile)) - return false; - - int tile_x = 0, tile_y = 0; - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - - if (! leader_can_build_district (&leaders[civ_id], district_id)) - return false; - - if (! district_resource_prereqs_met (tile, tile_x, tile_y, district_id)) - return false; - - if ((district_id == CANAL_DISTRICT_ID) && (! canal_district_tile_is_valid (tile_x, tile_y))) - return false; - - if ((district_id == BRIDGE_DISTRICT_ID) && (! bridge_district_tile_is_valid (tile_x, tile_y))) - return false; - - struct district_instance * existing_inst = get_district_instance (tile); - struct district_infos const * info = &is->district_infos[district_id]; - int existing_district_id = (existing_inst != NULL) ? existing_inst->district_id : -1; - bool district_completed = district_is_complete (tile, existing_district_id); - - if ((existing_district_id == district_id) && district_completed) - return false; - if ((existing_district_id >= 0) && (existing_district_id != district_id) && (! district_completed)) - return false; - - if (! cfg->allow_multiple) { - if (district_exists_within_distance (tile_x, tile_y, district_id, civ_id, is->current_config.city_work_radius)) - return false; - } - - return true; -} - -bool -district_is_obsolete_for_civ (int district_id, int civ_id) -{ - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - int obsolete_id = is->district_infos[district_id].obsoleted_by_id; - if (obsolete_id < 0) - return false; - - return Leader_has_tech (&leaders[civ_id], __, obsolete_id); -} - -bool -tile_has_obsolete_district_for_civ (Tile * tile, int civ_id) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - - int district_id = inst->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - if (! district_is_complete (tile, district_id)) - return false; - - return district_is_obsolete_for_civ (district_id, civ_id); -} - -bool -tile_suitable_for_district (Tile * tile, int district_id, City * city, bool * out_has_resource) -{ - bool has_resource = false; - if ((tile != NULL) && (tile != p_null_tile)) - has_resource = tile_has_resource (tile); - if (out_has_resource != NULL) - *out_has_resource = has_resource; - - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (tile->CityID >= 0) return false; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) return false; - if (! can_build_district_on_tile (tile, district_id, city->Body.CivID)) return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - if (tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - return true; - - // Unused wonder districts can be repurposed, completed cannot - if (district_id == WONDER_DISTRICT_ID && inst->state == DS_COMPLETED) { - struct wonder_district_info * winfo = &inst->wonder_info; - if (winfo->state == WDS_COMPLETED) - return false; - } - - return false; - } - - return true; -} - -bool -can_generate_resource (int for_civ_id, struct mill * mill) -{ - int req_tech_id = (mill->flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[mill->resource_id].RequireID; - return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); -} - -bool -district_can_generate_resource (int for_civ_id, struct district_config * dc) -{ - if (dc->generated_resource_id < 0) - return false; - int req_tech_id = (dc->generated_resource_flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[dc->generated_resource_id].RequireID; - return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); -} - -bool -district_generates_resource_for_civ (Tile * tile, struct district_instance * inst, struct district_config * dc, int civ_id) -{ - if ((tile == NULL) || (tile == p_null_tile) || (inst == NULL) || (dc == NULL)) - return false; - if (inst->state != DS_COMPLETED) - return false; - if (dc->generated_resource_id < 0) - return false; - if (! district_can_generate_resource (civ_id, dc)) - return false; - - int tile_x = 0, tile_y = 0; - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - return district_resource_prereqs_met_r (tile, tile_x, tile_y, inst->district_id, dc->generated_resource_id - 1); -} - -void -calculate_city_center_district_bonus (City * city, int * out_food, int * out_shields, int * out_gold) -{ - if (out_food != NULL) - *out_food = 0; - if (out_shields != NULL) - *out_shields = 0; - if (out_gold != NULL) - *out_gold = 0; - - if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) - return; - - int bonus_food = 0; - int bonus_shields = 0; - int bonus_gold = 0; - - int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - int neighborhoods_counted = 0; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) - continue; - Tile * tile = wai.tile; - - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - if (is->current_config.enable_neighborhood_districts && - (district_id == NEIGHBORHOOD_DISTRICT_ID)) { - if (neighborhoods_counted >= utilized_neighborhoods) - continue; - neighborhoods_counted++; - } - - struct district_config * cfg = &is->district_configs[district_id]; - int food_bonus = 0, shield_bonus = 0, gold_bonus = 0; - get_effective_district_yields (inst, cfg, &food_bonus, &shield_bonus, &gold_bonus, NULL, NULL, NULL); - bonus_food += food_bonus; - bonus_shields += shield_bonus; - bonus_gold += gold_bonus; - - if ((cfg->generated_resource_id >= 0) && (cfg->generated_resource_flags & MF_YIELDS)) { - int res_id = cfg->generated_resource_id; - if (district_generates_resource_for_civ (tile, inst, cfg, city->Body.CivID)) { - Resource_Type * res = &p_bic_data->ResourceTypes[res_id]; - bonus_food += res->Food; - bonus_shields += res->Shield; - bonus_gold += res->Commerce; - } - } - } - - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { - int hub_food = 0; - int hub_shields = 0; - get_distribution_hub_yields_for_city (city, &hub_food, &hub_shields); - bonus_food += hub_food; - bonus_shields += hub_shields; - } - - if (out_food != NULL) - *out_food = bonus_food; - if (out_shields != NULL) - *out_shields = bonus_shields; - if (out_gold != NULL) - *out_gold = bonus_gold; -} - -int __fastcall -patch_Map_calc_food_yield_at (Map * this, int edx, int tile_x, int tile_y, int tile_base_type, int civ_id, int imagine_fully_improved, City * city) -{ - if (! is->current_config.enable_districts) - return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id)) { - return 0; - } - } - - return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); -} - -int __fastcall -patch_Map_calc_shield_yield_at (Map * this, int edx, int tile_x, int tile_y, int civ_id, City * city, int param_5, int param_6) -{ - if (! is->current_config.enable_districts) - return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id)) { - return 0; - } - } - - return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); -} - -int -compute_city_tile_yield_sum (City * city, int tile_x, int tile_y) -{ - if (city == NULL) - return 0; - int food = City_calc_tile_yield_at (city, __, YK_FOOD, tile_x, tile_y); - int shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, tile_x, tile_y); - int commerce = City_calc_tile_yield_at (city, __, YK_COMMERCE, tile_x, tile_y); - return food + shields + commerce; -} - -int * -get_water_continent_ids_connected_via_canal (Tile * tile, int * out_count) -{ - if (out_count != NULL) - *out_count = 0; - if (! is->current_config.enable_canal_districts) - return NULL; - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - if (! tile->vtable->m35_Check_Is_Water (tile)) - return NULL; - - int origin_continent_id = tile->vtable->m46_Get_ContinentID (tile); - int continent_count = p_bic_data->Map.Continent_Count; - if ((origin_continent_id < 0) || (origin_continent_id >= continent_count)) - return NULL; - - Map * map = &p_bic_data->Map; - int tile_count = map->TileCount; - if (tile_count <= 0) - return NULL; - - // Use a BFS over completed canal tiles, starting from those touching the origin water body. - int * queue_xs = malloc (sizeof (*queue_xs) * tile_count); - int * queue_ys = malloc (sizeof (*queue_ys) * tile_count); - int * ids = malloc (sizeof (*ids) * continent_count); - bool * seen = calloc (continent_count, sizeof (*seen)); - if ((queue_xs == NULL) || (queue_ys == NULL) || (ids == NULL) || (seen == NULL)) { - if (queue_xs != NULL) - free (queue_xs); - if (queue_ys != NULL) - free (queue_ys); - if (ids != NULL) - free (ids); - if (seen != NULL) - free (seen); - return NULL; - } - - seen[origin_continent_id] = true; - - int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; - int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; - int head = 0; - int tail = 0; - - // Seed queue with completed canal districts adjacent to the origin water body. - for (int index = 0; index < tile_count; index++) { - Tile * cand = Map_get_tile (map, __, index); - if ((cand == NULL) || (cand == p_null_tile)) - continue; - - int cx = 0, cy = 0; - tile_index_to_coords (map, index, &cx, &cy); - if (! tile_has_district_at (cx, cy, CANAL_DISTRICT_ID)) - continue; - - struct district_instance * inst = get_district_instance (cand); - if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || - (! district_is_complete (cand, CANAL_DISTRICT_ID))) - continue; - - bool adjacent_to_origin = false; - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (! adj->vtable->m35_Check_Is_Water (adj)) - continue; - int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); - if (adj_continent_id == origin_continent_id) { - adjacent_to_origin = true; - break; - } - } - if (! adjacent_to_origin) - continue; - - bool seen_canal = false; - for (int j = 0; j < tail; j++) { - if ((queue_xs[j] == cx) && (queue_ys[j] == cy)) { - seen_canal = true; - break; - } - } - if (! seen_canal && (tail < tile_count)) { - queue_xs[tail] = cx; - queue_ys[tail] = cy; - tail++; - } - } - - int id_count = 0; - - while (head < tail) { - int cx = queue_xs[head]; - int cy = queue_ys[head]; - head++; - - // Record all water bodies adjacent to this canal tile. - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (! adj->vtable->m35_Check_Is_Water (adj)) - continue; - - int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); - if ((adj_continent_id < 0) || (adj_continent_id >= continent_count)) - continue; - if (! seen[adj_continent_id]) { - seen[adj_continent_id] = true; - ids[id_count] = adj_continent_id; - id_count++; - } - } - - // Traverse to neighboring completed canal districts. - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) - continue; - - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (adj); - if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || (! district_is_complete (adj, CANAL_DISTRICT_ID))) - continue; - - bool seen_canal = false; - for (int j = 0; j < tail; j++) { - if ((queue_xs[j] == nx) && (queue_ys[j] == ny)) { - seen_canal = true; - break; - } - } - if (! seen_canal && (tail < tile_count)) { - queue_xs[tail] = nx; - queue_ys[tail] = ny; - tail++; - } - } - } - - free (queue_xs); - free (queue_ys); - free (seen); - - if (out_count != NULL) - *out_count = id_count; - if (id_count <= 0) { - free (ids); - return NULL; - } - - return ids; -} - -Tile * -find_tile_for_neighborhood_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - - // Search in order: ring 1, then rings 2..N - // Ring order array: 1, 2, 3, ..., city_work_radius - int ring_order[8]; - int ring_count = 0; - for (int r = 1; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - - Tile * best_tile = NULL; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - bool has_resource = false; - if (is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - continue; - } - - if (! tile_suitable_for_district (tile, NEIGHBORHOOD_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - if (get_district_instance (tile) != NULL && - ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -find_tile_for_port_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - int threshold_for_body_of_water = 21; // Mimic vanilla behavior so AI doesn't build ports in small lakes - - // Search in order: ring 1, then rings 2..N - int ring_order[8]; - int ring_count = 0; - for (int r = 1; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - - Tile * best_tile = NULL; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - bool has_resource = false; - if (is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - continue; - } - - if (! tile_suitable_for_district (tile, PORT_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - if (get_district_instance (tile) != NULL && - ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - continue; - if (! tile->vtable->m35_Check_Is_Water (tile)) - continue; - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - bool large_enough_body = (continent->Body.TileCount >= threshold_for_body_of_water); - if (! large_enough_body) { - int connected_count = 0; - int * connected_ids = get_water_continent_ids_connected_via_canal (tile, &connected_count); - for (int i = 0; i < connected_count; i++) { - int connected_id = connected_ids[i]; - if ((connected_id < 0) || (connected_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * connected_continent = &p_bic_data->Map.Continents[connected_id]; - if (connected_continent->Body.TileCount >= threshold_for_body_of_water) { - large_enough_body = true; - break; - } - } - if (connected_ids != NULL) - free (connected_ids); - } - if (! large_enough_body) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -find_tile_for_wonder_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - int target_improv_id = -1; - if (look_up_pending_building_order (city, &target_improv_id)) { - if ((target_improv_id < 0) || - (target_improv_id >= p_bic_data->ImprovementsCount) || - ((p_bic_data->Improvements[target_improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0)) - target_improv_id = -1; - } - if (target_improv_id < 0) { - int order_id = city->Body.Order_ID; - if ((city->Body.Order_Type == COT_Improvement) && - (order_id >= 0) && - (order_id < p_bic_data->ImprovementsCount)) { - Improvement * order = &p_bic_data->Improvements[order_id]; - if (order->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - target_improv_id = order_id; - } - } - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - - // Search in order: ring 2, then rings 3..N, then ring 1 as last resort - int ring_order[8]; - int ring_count = 0; - ring_order[ring_count++] = 2; - for (int r = 3; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - ring_order[ring_count++] = 1; - - Tile * best_tile = NULL; - bool has_resource = false; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - if (! tile_suitable_for_district (tile, WONDER_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - if (! wonder_is_buildable_on_tile (tile, target_improv_id)) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -find_tile_for_distribution_hub_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - const int resource_penalty = 100; - const int yield_weight = 40; - const int city_distance_weight = 8; - const int capital_distance_weight = 45; - const int desired_min_capital_distance = 8; - const int proximity_penalty_scale = 300; - const int different_continent_bonus = 500; - - Tile * best_tile = NULL; - int best_score = INT_MIN; - int best_adjusted_yield = INT_MIN; - int best_distance = -1; - int best_distance_to_capital = -1; - bool best_has_resource = true; - - int civ_id = city->Body.CivID; - bool has_capital = false; - int capital_x = 0; - int capital_y = 0; - int capital_continent_id = -1; - - City * capital = get_city_ptr (leaders[civ_id].CapitalID); - if (capital != NULL) { - has_capital = true; - capital_x = capital->Body.X; - capital_y = capital->Body.Y; - Tile * capital_tile = tile_at (capital_x, capital_y); - if ((capital_tile != NULL) && (capital_tile != p_null_tile)) - capital_continent_id = capital_tile->vtable->m46_Get_ContinentID (capital_tile); - } - - FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { - int tx = wai.tile_x, ty = wai.tile_y; - Tile * tile = wai.tile; - bool has_resource; - if (! tile_suitable_for_district (tile, DISTRIBUTION_HUB_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - - int chebyshev = compute_wrapped_chebyshev_distance (tx, ty, city->Body.X, city->Body.Y); - if (chebyshev <= 1) - continue; - - bool too_close_to_existing_hub_or_city = false; - for (int m = 0; m < workable_tile_counts[2]; m++) { - int ndx, ndy; - patch_ni_to_diff_for_work_area (m, &ndx, &ndy); - int nx = tx + ndx, ny = ty + ndy; - wrap_tile_coords (&p_bic_data->Map, &nx, &ny); - Tile * nearby_tile = tile_at (nx, ny); - if ((nearby_tile != NULL) && (nearby_tile != p_null_tile)) { - struct district_instance * nearby_inst = get_district_instance (nearby_tile); - if ((nearby_inst != NULL) && - (nearby_inst->district_id == DISTRIBUTION_HUB_DISTRICT_ID) && - district_is_complete (nearby_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { - too_close_to_existing_hub_or_city = true; - break; - } - else if (nearby_tile->CityID >= 0) { - too_close_to_existing_hub_or_city = true; - break; - } - } - } - if (too_close_to_existing_hub_or_city) - continue; - - int raw_yield = compute_city_tile_yield_sum (city, tx, ty); - int adjusted_yield = raw_yield - (has_resource ? resource_penalty : 0); - int distance = compute_wrapped_manhattan_distance (tx, ty, city->Body.X, city->Body.Y); - int distance_to_capital = has_capital - ? compute_wrapped_manhattan_distance (tx, ty, capital_x, capital_y) - : 0; - - int proximity_penalty = 0; - if (has_capital && (distance_to_capital < desired_min_capital_distance)) - proximity_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; - - int continent_bonus = 0; - if ((capital_continent_id >= 0) && (tile != NULL) && (tile != p_null_tile)) { - int tile_continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((tile_continent_id >= 0) && (tile_continent_id != capital_continent_id)) - continent_bonus = different_continent_bonus; - } - - int score = - adjusted_yield * yield_weight + - distance * city_distance_weight + - distance_to_capital * capital_distance_weight - - proximity_penalty + - continent_bonus; - - if ((score > best_score) || - ((score == best_score) && (distance_to_capital > best_distance_to_capital)) || - ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield > best_adjusted_yield)) || - ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance > best_distance)) || - ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance == best_distance) && (! has_resource && best_has_resource))) { - best_tile = tile; - best_score = score; - best_adjusted_yield = adjusted_yield; - best_distance = distance; - best_distance_to_capital = distance_to_capital; - best_has_resource = has_resource; - *out_x = tx; - *out_y = ty; - } - } - - return best_tile; -} - -bool -city_can_build_district (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos const * info = &is->district_infos[district_id]; - - if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) - return false; - - if ((info->resource_prereq_count > 0) || (info->resource_prereq_on_tile_id >= 0)) { - bool resource_prereqs_met = false; - - FOR_TILES_AROUND (tai, is->workable_tile_count, city->Body.X, city->Body.Y) { - Tile * tile = tai.tile; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) - continue; - if (! district_resource_prereqs_met_r (tile, tai.tile_x, tai.tile_y, district_id, INT_MAX)) - continue; - - resource_prereqs_met = true; - break; - } - - if (! resource_prereqs_met) - return false; - } - - // Check if district does not allow multiple and city already has one - if (! cfg->allow_multiple && city_has_required_district (city, district_id)) - return false; - - return true; -} - -bool -leader_has_wonder_prereq (Leader * leader, struct district_infos const * info) -{ - if (info == NULL) - return false; - if (info->wonder_prereq_count <= 0) - return true; - if ((leader == NULL) || (leader->Improvement_Counts == NULL)) - return false; - - for (int i = 0; i < info->wonder_prereq_count; i++) { - int improv_id = info->wonder_prereq_ids[i]; - if (improv_id >= 0 && leader->Improvement_Counts[improv_id] > 0) - return true; - } - - return false; -} - -bool -leader_has_natural_wonder_prereq_in_territory (int civ_id, struct district_infos const * info) -{ - if (info == NULL) - return false; - if (info->natural_wonder_prereq_count <= 0) - return true; - if (! is->current_config.enable_natural_wonders) - return false; - - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - - int wonder_id = inst->natural_wonder_info.natural_wonder_id; - if (wonder_id < 0) - continue; - - bool matches = false; - for (int i = 0; i < info->natural_wonder_prereq_count; i++) { - if (info->natural_wonder_prereq_ids[i] == wonder_id) { - matches = true; - break; - } - } - if (! matches) - continue; - - Tile * tile = (Tile *)tei.key; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; - } - - return false; -} - -int -count_distribution_hubs_for_civ (int civ_id) -{ - int current = 0; - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if ((rec != NULL) && (rec->civ_id == civ_id)) - current++; - } - return current; -} - -bool -leader_can_natively_build_district (Leader * leader, int district_id) -{ - if ((leader == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos const * info = &is->district_infos[district_id]; - - for (int i = 0; i < info->advance_prereq_count; i++) { - int prereq_id = info->advance_prereq_ids[i]; - if ((prereq_id >= 0) && ! Leader_has_tech (leader, __, prereq_id)) - return false; - } - int obsolete_id = info->obsoleted_by_id; - if ((obsolete_id >= 0) && Leader_has_tech (leader, __, obsolete_id)) - return false; - - if (! leader_has_wonder_prereq (leader, info)) - return false; - - if (! leader_has_natural_wonder_prereq_in_territory (leader->ID, info)) - return false; - - if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) { - int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; - if (max_per_100 > 0) { - int city_count = leader->Cities_Count; - int max_allowed = (city_count * max_per_100 + 99) / 100; - if (max_allowed <= 0) - return false; - - int current = count_distribution_hubs_for_civ (leader->ID); - if (current >= max_allowed) - return false; - } - } - - if (cfg->has_buildable_by_civs) { - bool civ_match = false; - if (cfg->buildable_by_civ_count > 0) { - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - for (int i = 0; i < cfg->buildable_by_civ_count; i++) { - char const * civ_name = cfg->buildable_by_civs[i]; - if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; - if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; - if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; - if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; - if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; - } - } - if (! civ_match) - return false; - } - - if (cfg->has_buildable_by_civ_traits) { - if (cfg->buildable_by_civ_traits_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL || race->vtable == NULL) - return false; - bool trait_match = false; - for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { - int trait_id = cfg->buildable_by_civ_traits_ids[i]; - if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { - trait_match = true; - break; - } - } - if (! trait_match) - return false; - } - - if (cfg->has_buildable_by_civ_govs) { - if (cfg->buildable_by_civ_govs_id_count <= 0) - return false; - int gov_id = leader->GovernmentType; - bool gov_match = false; - for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { - if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { - gov_match = true; - break; - } - } - if (! gov_match) - return false; - } - - if (cfg->has_buildable_by_civ_cultures) { - if (cfg->buildable_by_civ_cultures_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - int culture_id = race->CultureGroupID; - bool culture_match = false; - for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { - if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { - culture_match = true; - break; - } - } - if (! culture_match) - return false; - } - - return true; -} - -bool -leader_has_war_ally_district_access (Leader * leader, int district_id) -{ - if (leader == NULL) - return false; - - int self_id = leader->ID; - for (int civ_id = 0; civ_id < 32; civ_id++) { - if (civ_id == self_id) - continue; - Leader * other = &leaders[civ_id]; - if (other->Military_Allies[self_id] != 0 && leader_can_natively_build_district (other, district_id)) - return true; - } - - return false; -} - -bool -leader_has_pact_ally_district_access (Leader * leader, int district_id) -{ - if (leader == NULL) - return false; - - int self_id = leader->ID; - for (int civ_id = 0; civ_id < 32; civ_id++) { - if (civ_id == self_id) - continue; - Leader * other = &leaders[civ_id]; - if (((leader->Relation_Treaties[civ_id] & 1) != 0 && // 1 = peace treaty - (leader->Relation_Treaties[civ_id] & 4) != 0) && // 4 = mutual protection pact - leader_can_natively_build_district (other, district_id)) { - return true; - } - } - - return false; -} - -bool -leader_can_build_district (Leader * leader, int district_id) -{ - bool can_natively_build = leader_can_natively_build_district (leader, district_id); - - if (can_natively_build) - return true; - - struct district_config const * cfg = &is->district_configs[district_id]; - if (cfg->buildable_by_war_allies && leader_has_war_ally_district_access (leader, district_id)) - return true; - if (cfg->buildable_by_pact_allies && leader_has_pact_ally_district_access (leader, district_id)) - return true; - - return can_natively_build; -} - -Tile * -find_tile_for_district (City * city, int district_id, int * out_x, int * out_y) -{ - if ((city == NULL) || (out_x == NULL) || (out_y == NULL)) - return NULL; - if ((district_id < 0) || (district_id >= is->district_count)) - return NULL; - - // Check if city can build this district at all - if (! city_can_build_district (city, district_id)) - return NULL; - - if (district_id == NEIGHBORHOOD_DISTRICT_ID) - return find_tile_for_neighborhood_district (city, out_x, out_y); - if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) - return find_tile_for_distribution_hub_district (city, out_x, out_y); - if (district_id == PORT_DISTRICT_ID) - return find_tile_for_port_district (city, out_x, out_y); - if (district_id == WONDER_DISTRICT_ID) - return find_tile_for_wonder_district (city, out_x, out_y); - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - - // Search in order: ring 2, then rings 3..N, then ring 1 as last resort - // Ring order array: 2, 3, 4, ..., city_work_radius, 1 - int ring_order[8]; - int ring_count = 0; - ring_order[ring_count++] = 2; - for (int r = 3; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - ring_order[ring_count++] = 1; - - Tile * best_tile = NULL; - struct district_config * cfg = &is->district_configs[district_id]; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - bool has_resource = false; - if (is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - continue; - } - - if (! tile_suitable_for_district (tile, district_id, city, &has_resource)) - continue; - if (cfg->resource_prereq_on_tile < 0 && has_resource) - continue; - if (get_district_instance (tile) != NULL && ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -get_completed_district_tile_for_city (City * city, int district_id, int * out_x, int * out_y) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return NULL; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - struct district_instance * inst = wai.district_inst; - - if (inst->district_id != district_id) - continue; - - // For wonder districts, filter based on wonder_district_state - if (district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = &inst->wonder_info; - // Must be either unused or under construction by this city - if (info->state == WDS_COMPLETED) - continue; - if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) - continue; - if (info->state == WDS_UNDER_CONSTRUCTION) { - info->city = city; - info->city_id = city->Body.ID; - } - } - - if (out_x != NULL) - *out_x = x; - if (out_y != NULL) - *out_y = y; - return candidate; - } - - return NULL; -} - -bool -tile_has_friendly_aerodrome_district (Tile * tile, int civ_id, bool require_available) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_aerodrome_districts || - (tile == NULL) || - (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != AERODROME_DISTRICT_ID) - return false; - - if (! district_is_complete (tile, AERODROME_DISTRICT_ID)) - return false; - - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (territory_owner != civ_id) - return false; - - if (require_available) { - int usage_mask; - if (itable_look_up (&is->aerodrome_airlift_usage, (int)tile, &usage_mask) && - (usage_mask & (1 << civ_id))) - return false; - } - - return true; -} - -bool -tile_has_friendly_port_district (Tile * tile, int civ_id) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - (tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != PORT_DISTRICT_ID)) - return false; - - if (! district_is_complete (tile, PORT_DISTRICT_ID)) - return false; - - return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; -} - -bool -city_has_required_district (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - if (get_completed_district_tile_for_city (city, district_id, NULL, NULL) != NULL) { - clear_city_district_request (city, district_id); - return true; - } - return false; -} - -bool -city_has_wonder_district_with_no_completed_wonder (City * city, int wonder_improv_id) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - Tile * candidate = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - - struct wonder_district_info * info = get_wonder_district_info (candidate); - bool buildable = wonder_is_buildable_on_tile (candidate, wonder_improv_id); - if (info == NULL) return true; - if (info->state == WDS_COMPLETED) continue; - if (info->state == WDS_UNUSED && buildable) return true; - if (info->state == WDS_UNDER_CONSTRUCTION && buildable && info->city_id == city->Body.ID) { - info->city = city; - return true; // Reserved by this city - } - } - - return false; -} - -int __fastcall patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city); -int __fastcall patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null); -void __fastcall patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3); - - -void __fastcall -patch_Main_Screen_Form_show_map_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) -{ - WITH_PAUSE_FOR_POPUP { - Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, pause); - } -} - -int __cdecl -patch_process_text_for_map_message (char * in, char * out) -{ - if (is->map_message_text_override != NULL) { - strcpy (out, is->map_message_text_override); - is->map_message_text_override = NULL; - return 0; - } else - return process_text_snippet (in, out); -} - -// Works like show_map_message but takes a bit of text to display instead of a key for script.txt -void -show_map_specific_text (int tile_x, int tile_y, char const * text, bool pause) -{ - is->map_message_text_override = text; - patch_Main_Screen_Form_show_map_message (p_main_screen_form, __, tile_x, tile_y, "LANDCONQUER", pause); // Use any key here. It will be overridden. -} - -bool __fastcall -patch_City_has_improvement (City * this, int edx, int improv_id, bool include_auto_improvements) -{ - bool tr = City_has_improvement (this, __, improv_id, include_auto_improvements); - - // Check if the improvement is provided for free by another human player's wonder if we're in a hotseat game and the config option is on - if ((! tr) && - include_auto_improvements && - is->current_config.share_wonders_in_hotseat && - ((1 << this->Body.CivID) & *p_human_player_bits) && - (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // if we're in a hotseat game - - // Loop over every other human player in the game and check if the city would have the improv if they were its owner - int actual_owner_id = this->Body.CivID; - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != actual_owner_id)) { - this->Body.CivID = n_player; - if (City_has_improvement (this, __, improv_id, include_auto_improvements)) { - tr = true; - break; - } - } - player_bits >>= 1; - n_player++; - } - this->Body.CivID = actual_owner_id; - - } - - return tr; -} - -int -count_neighborhoods_in_city_radius (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return 0; - - int count = 0; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - struct district_instance * inst = wai.district_inst; - if (inst != NULL && - inst->district_id >= 0 && inst->district_id < is->district_count && - inst->district_id == NEIGHBORHOOD_DISTRICT_ID) - count++; - } - return count; -} - -int -count_utilized_neighborhoods_in_city_radius (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return 0; - - int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; - if (base_cap <= 0) - return 0; - - int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; - if (per_neighborhood <= 0) - return 0; - - int pop = city->Body.Population.Size; - if (pop <= base_cap) - return 0; - - int excess_pop = pop - base_cap; - int utilized = (excess_pop + per_neighborhood - 1) / per_neighborhood; - int total_neighborhoods = count_neighborhoods_in_city_radius (city); - - if (utilized > total_neighborhoods) - utilized = total_neighborhoods; - - return utilized; -} - -int -get_neighborhood_pop_cap (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return -1; - - int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; - if (base_cap <= 0) - return -1; - - int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; - if (per_neighborhood < 0) - per_neighborhood = 0; - - int neighborhoods = count_neighborhoods_in_city_radius (city); - long long cap = (long long)base_cap + (long long)per_neighborhood * neighborhoods; - if (cap < base_cap) - cap = base_cap; - - return (int)cap; -} - -bool -city_is_at_neighborhood_cap (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return false; - - int cap = get_neighborhood_pop_cap (city); - if (cap <= 0) - return false; - - return city->Body.Population.Size >= cap; -} - -void -ensure_neighborhood_request_for_city (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return; - - if (! leader_can_build_district (&leaders[city->Body.CivID], NEIGHBORHOOD_DISTRICT_ID)) - return; - - mark_city_needs_district (city, NEIGHBORHOOD_DISTRICT_ID); -} - -void -calculate_district_culture_science_bonuses (City * city, int * culture_bonus, int * science_bonus) -{ - if (culture_bonus != NULL) - *culture_bonus = 0; - if (science_bonus != NULL) - *science_bonus = 0; - - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders) || (city == NULL)) - return; - - int total_culture = 0; - int total_science = 0; - int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) - continue; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - struct district_config const * cfg = &is->district_configs[district_id]; - int district_culture_bonus = 0; - int district_science_bonus = 0; - get_effective_district_yields (inst, cfg, NULL, NULL, NULL, &district_science_bonus, &district_culture_bonus, NULL); - - bool is_neighborhood = (cfg->command == UCV_Build_Neighborhood); - if (is_neighborhood) { - if (utilized_neighborhoods > 0) { - total_culture += district_culture_bonus; - total_science += district_science_bonus; - utilized_neighborhoods--; - } - } else { - total_culture += district_culture_bonus; - total_science += district_science_bonus; - } - } - - if (culture_bonus != NULL) - *culture_bonus = total_culture; - if (science_bonus != NULL) - *science_bonus = total_science; -} - -void -calculate_district_happiness_bonus (City * city, int * happiness_bonus) -{ - if (happiness_bonus != NULL) - *happiness_bonus = 0; - - if (! is->current_config.enable_districts || (city == NULL)) - return; - - int total_happy = 0; - int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) - continue; - - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - struct district_config const * cfg = &is->district_configs[district_id]; - - bool is_neighborhood = district_id == NEIGHBORHOOD_DISTRICT_ID; - if (is_neighborhood && (utilized_neighborhoods <= 0)) - continue; - - if (is_neighborhood) - utilized_neighborhoods--; - - int district_happy = 0; - get_effective_district_yields (inst, cfg, NULL, NULL, NULL, NULL, NULL, &district_happy); - if (district_happy != 0) - total_happy += district_happy; - } - - if (happiness_bonus != NULL) - *happiness_bonus = total_happy; -} - -int __fastcall -patch_City_requires_improvement_to_grow (City * this) -{ - int required_improv = City_requires_improvement_to_grow (this); - if ((required_improv == -1) && - (this != NULL) && - is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - city_is_at_neighborhood_cap (this)) { - return 0; // Neighborhood sentinel - } - - return required_improv; -} - -// Replacement check specifically for stalled growth check function, -// where we can't pass through the neighborhood sentinel. That function itself -// doesn't block growth, it just triggers the dialog, so safe to skip it if -// neighborhoods are needed. -int __fastcall -patch_City_requires_improvement_to_grow_besides_neighborhood (City * this) -{ - return City_requires_improvement_to_grow (this); -} - -void __fastcall -patch_maybe_show_improvement_needed_for_growth_dialog (void * this, int edx, City * city, int * param_2) -{ - int required_improv_id = (int)param_2; - if (is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - (required_improv_id == 0)) // Neighborhood sentinel - return; - - maybe_show_improvement_needed_for_growth_dialog (this, __, city, param_2); -} - -void -maybe_show_neighborhood_growth_warning (City * city) -{ - if ((city == NULL) || ! (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts)) return; - int requirement = patch_City_requires_improvement_to_grow (city); - if (requirement != 0) return; // Neighborhood sentinel not present - if (city->Body.FoodIncome <= 0) return; // Not growing - if (is_online_game ()) return; - int civ_id = city->Body.CivID; - if (civ_id != p_main_screen_form->Player_CivID) return; - if ((*p_human_player_bits & (1u << civ_id)) == 0) return; - - unsigned int turn_no = (unsigned int)*p_current_turn_no; - unsigned int throttle = ((unsigned int)city->Body.X << 5) ^ (unsigned int)city->Body.Y; - int frequency = is->current_config.neighborhood_needed_message_frequency; - if ((frequency <= 0) || (((turn_no + throttle) % frequency) != 0)) - return; - - char msg[160]; - char const * city_name = city->Body.CityName; - snprintf (msg, sizeof msg, "%s %s %s %s", - city_name, - is->c3x_labels[CL_REQUIRES], - is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name, - is->c3x_labels[CL_TO_GROW] - ); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); -} - -bool __stdcall -patch_is_not_pop_capped_or_starving (City * city) -{ - bool tr = is_not_pop_capped_or_starving (city); - if (! tr) return false; - - if (is->current_config.enable_districts) { - if (city_is_at_neighborhood_cap (city)) - return false; - } - - return true; -} - -bool -remove_building_if_no_district (City * city, int district_id, int building_id) -{ - if ((city == NULL) || (building_id < 0)) return false; - if (! patch_City_has_improvement (city, __, building_id, false)) return false; - if (city_has_required_district (city, district_id)) return false; - - patch_City_add_or_remove_improvement (city, __, building_id, 0, false); - return true; -} - -bool -city_has_other_completed_wonder_district_for_improvement (City * city, int wonder_improv_id, int removed_x, int removed_y) -{ - if (! (is->current_config.enable_districts && is->current_config.enable_wonder_districts) || - (city == NULL) || (wonder_improv_id < 0)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - if ((x == removed_x) && (y == removed_y)) - continue; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if (info->state != WDS_COMPLETED) - continue; - - int candidate_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); - if (candidate_improv_id != wonder_improv_id) - continue; - - return true; - } - - return false; -} - -void -remove_shared_wonder_if_no_other_district (City * city, int wonder_improv_id, int removed_x, int removed_y) -{ - if ((city == NULL) || (wonder_improv_id < 0)) - return; - - if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) - return; - - if (leaders[city->Body.CivID].Small_Wonders[wonder_improv_id] == city->Body.ID) - return; - - if (city_has_other_completed_wonder_district_for_improvement (city, wonder_improv_id, removed_x, removed_y)) - return; - - patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); -} - -void -reduce_city_population_due_to_lost_neighborhood (City * city) -{ - if (city == NULL) - return; - - if (! (is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - is->current_config.destroying_neighborhood_reduces_pop)) - return; - - int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; - int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; - if ((base_cap <= 0) || (per_neighborhood <= 0)) - return; - - int neighborhoods = count_neighborhoods_in_city_radius (city); - int cap = base_cap + (per_neighborhood * neighborhoods); - if (cap < base_cap) - cap = base_cap; - - int pop = city->Body.Population.Size; - if (pop <= cap) - return; - - int to_remove = pop - cap; - int removed = 0; - while (to_remove-- > 0) { - City_remove_population (city, __, 1, -1, '\0'); - removed++; - } - - if ((removed > 0) && - ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && - (city->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[160]; - snprintf (msg, sizeof msg, "%s %s %s", - city->Body.CityName, - is->c3x_labels[CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD], - is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name - ); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } -} - -bool -city_has_other_completed_district (City * city, int district_id, int removed_x, int removed_y) -{ - if (! is->current_config.enable_districts || - (city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - if ((x == removed_x) && (y == removed_y)) - continue; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != district_id) - continue; - - return true; - } - - return false; -} - -bool -district_instance_is_redundant (struct district_instance * inst, Tile * tile) -{ - if (! is->current_config.enable_districts || - (inst == NULL) || - (tile == NULL) || (tile == p_null_tile)) - return false; - - int district_id = inst->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - if (! district_is_complete (tile, district_id)) - return false; - - if (district_id == NEIGHBORHOOD_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID) - return false; - - int tile_x = inst->tile_x; - int tile_y = inst->tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - return false; - - int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - - if (district_id == WONDER_DISTRICT_ID) - return inst->wonder_info.state == WDS_UNUSED; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - if (! city_has_other_completed_district (wai.city, district_id, tile_x, tile_y)) - return false; - } - - return true; -} - -bool -any_nearby_city_would_lose_district_benefits (int district_id, int civ_id, int removed_x, int removed_y) -{ - if (! is->current_config.enable_districts) - return false; - - if (district_id < 0 || district_id >= is->district_count) - return false; - - struct district_infos * info = &is->district_infos[district_id]; - - // If there are no dependent buildings, no city can lose benefits - if (info->dependent_building_count == 0) - return false; - - // Check all cities within work radius of the removed district - FOR_CITIES_AROUND (wai, removed_x, removed_y) { - City * city = wai.city; - - // Check if this city has another completed district of the same type nearby (excluding the one being removed) - if (city_has_other_completed_district (city, district_id, removed_x, removed_y)) - continue; - - // This city doesn't have another district, check if it has any dependent buildings - for (int i = 0; i < info->dependent_building_count; i++) { - int building_id = info->dependent_building_ids[i]; - if (building_id >= 0 && patch_City_has_improvement (city, __, building_id, false)) - return true; - } - } - - return false; -} - -void -remove_dependent_buildings_for_district (int district_id, int center_x, int center_y) -{ - if (! is->current_config.enable_districts || (district_id < 0) || (district_id >= is->district_count)) - return; - - struct district_infos * info = &is->district_infos[district_id]; - - if ((center_x < 0) || (center_y < 0) || - (center_x >= p_bic_data->Map.Width) || (center_y >= p_bic_data->Map.Height)) - return; - - FOR_CITIES_AROUND (wai, center_x, center_y) { - City * city = wai.city; - - if (city_has_other_completed_district (city, district_id, center_x, center_y)) - continue; - - int removed_count = 0; - int first_building_id = -1; - - for (int i = 0; i < info->dependent_building_count; i++) { - int building_id = info->dependent_building_ids[i]; - if (building_id >= 0) { - // This also loops through tiles around the city but is not redundant, as the city - // may have multiple districts of the same type in its radius (eg outside radius of this particular district) - if (remove_building_if_no_district (city, district_id, building_id)) { - if (removed_count == 0) - first_building_id = building_id; - removed_count++; - } - } - } - - if ((removed_count > 0) && - is->current_config.show_message_when_building_lost_to_destroyed_district && - ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && - (city->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[200]; - char const * district_name = is->district_configs[district_id].name; - char const * building_name = (first_building_id >= 0) ? p_bic_data->Improvements[first_building_id].Name.S : ""; - - if (removed_count == 1) - snprintf (msg, sizeof msg, "%s%s %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_APOSTROPHE_S], - building_name, - is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], - district_name); - else - snprintf (msg, sizeof msg, "%s%s %s %s %d %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_APOSTROPHE_S], - building_name, - is->c3x_labels[CL_AND], - removed_count - 1, - is->c3x_labels[CL_OTHER_BUILDINGS_HAVE_BEEN], - is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], - district_name); - - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - } -} - -void -remove_wonder_improvement_for_destroyed_district (int wonder_improv_id) -{ - if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) - return; - - if ((p_cities == NULL) || (p_cities->Cities == NULL)) - return; - - for (int idx = 0; idx <= p_cities->LastIndex; idx++) { - City * city = get_city_ptr (idx); - if (city == NULL) - continue; - if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) - continue; - - patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); - } -} - -void -handle_district_removed (Tile * tile, int district_id, int center_x, int center_y, bool leave_ruins) -{ - if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.enable_districts) - return; - - int wonder_windex = -1; - int wonder_improv_id = -1; - - // Get wonder district info before removing - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info != NULL && info->state == WDS_COMPLETED) - wonder_windex = info->wonder_index; - - int actual_district_id = district_id; - if (actual_district_id < 0) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) - actual_district_id = inst->district_id; - } - - remove_district_instance (tile); - - bool removed_neighborhood = actual_district_id == NEIGHBORHOOD_DISTRICT_ID; - - if (is->current_config.enable_wonder_districts && - (actual_district_id == WONDER_DISTRICT_ID) && - (wonder_windex >= 0)) - wonder_improv_id = get_wonder_improvement_id_from_index (wonder_windex); - - if (wonder_improv_id >= 0 && is->current_config.completed_wonder_districts_can_be_destroyed) - remove_wonder_improvement_for_destroyed_district (wonder_improv_id); - - if (is->current_config.enable_distribution_hub_districts && - (actual_district_id == DISTRIBUTION_HUB_DISTRICT_ID)) - remove_distribution_hub_record (tile); - - if (district_id >= 0) - remove_dependent_buildings_for_district (district_id, center_x, center_y); - - // Make the tile workable again by resetting CityAreaID and recomputing yields for nearby cities - tile->Body.CityAreaID = -1; - - int tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - FOR_CITIES_AROUND (wai, center_x, center_y) { - if (removed_neighborhood) - reduce_city_population_due_to_lost_neighborhood (wai.city); - recompute_city_yields_with_districts (wai.city); - } - - if (leave_ruins && (tile->vtable->m60_Set_Ruins != NULL)) { - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, center_x, center_y); - tile->vtable->m60_Set_Ruins (tile, __, 1); - } - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -bool -city_has_active_wonder_for_district (City * city) -{ - struct district_infos * info = &is->district_infos[WONDER_DISTRICT_ID]; - for (int n = 0; n < ARRAY_LEN (info->dependent_building_ids); n++) { - int building_id = info->dependent_building_ids[n]; - if ((building_id >= 0) && has_active_building (city, building_id)) - return true; - } - return false; -} - -bool -city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id) -{ - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); - if ((prereq_list == NULL) || (prereq_list->count <= 0)) - return false; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder = false; - - // Special logic for handling rivers - bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; - bool has_prereq = false; - - if (is->current_config.enable_wonder_districts && - district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) { - is_wonder = true; - if (! wonder_is_buildable_by_civ (improv_id, city->Body.CivID)) { - if (out_district_id != NULL) - *out_district_id = -1; - return false; - } - if (requires_river) { - bool has_river_wonder_district = false; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if (wai.district_inst->district_id != WONDER_DISTRICT_ID) - continue; - if (wai.tile->vtable->m37_Get_River_Code (wai.tile) == 0) - continue; - if (! wonder_is_buildable_on_tile (wai.tile, improv_id)) - continue; - struct wonder_district_info * info = get_wonder_district_info (wai.tile); - if (info == NULL) { - has_river_wonder_district = true; - break; - } - if (info->state == WDS_COMPLETED) - continue; - if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) - continue; - has_river_wonder_district = true; - break; - } - if (has_river_wonder_district) - has_prereq = true; - } else if (city_has_wonder_district_with_no_completed_wonder (city, improv_id)) { - has_prereq = true; - } - } - - if (! has_prereq && city_has_any_prereq_district_for_improvement (city, prereq_list, requires_river, !is_wonder)) - has_prereq = true; - - if (has_prereq) - return false; - - if (out_district_id != NULL) - *out_district_id = pick_missing_district_for_improvement (city, prereq_list); - return true; -} - -void -clear_best_feasible_order (City * city) -{ - int key = (int)city; - int stored_int; - if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) { - struct ai_best_feasible_order * stored = (struct ai_best_feasible_order *)stored_int; - free (stored); - itable_remove (&is->ai_best_feasible_orders, key); - } -} - -void -record_best_feasible_order (City * city, City_Order const * order, int value) -{ - int key = (int)city; - int stored_int; - struct ai_best_feasible_order * stored; - if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) - stored = (struct ai_best_feasible_order *)stored_int; - else { - stored = malloc (sizeof *stored); - if (stored == NULL) - return; - stored->order = *order; - stored->value = value; - itable_insert (&is->ai_best_feasible_orders, key, (int)stored); - return; - } - - if (value > stored->value) { - stored->order = *order; - stored->value = value; - } -} - -struct ai_best_feasible_order * -get_best_feasible_order (City * city) -{ - int stored_int; - if (itable_look_up (&is->ai_best_feasible_orders, (int)city, &stored_int)) - return (struct ai_best_feasible_order *)stored_int; - else - return NULL; -} - -bool -city_is_currently_building_wonder (City * city) -{ - if ((city == NULL) || (city->Body.Order_Type != COT_Improvement)) - return false; - int order_id = city->Body.Order_ID; - if ((order_id < 0) || (order_id >= p_bic_data->ImprovementsCount)) - return false; - return (p_bic_data->Improvements[order_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; -} - -bool -wonder_district_tile_under_construction (Tile * tile, int tile_x, int tile_y, int * out_windex) -{ - if (! is->current_config.enable_wonder_districts || - (tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != WONDER_DISTRICT_ID) - return false; - - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info == NULL || info->state != WDS_UNDER_CONSTRUCTION) - return false; - - City * reserved_city = get_city_ptr (info->city_id); - if (reserved_city == NULL) - return false; - info->city = reserved_city; - info->city_id = reserved_city->Body.ID; - - // Verify the reserved city is still building a wonder - if (! city_is_currently_building_wonder (reserved_city)) - return false; - - // Verify this tile is within the reserved city's radius - if (! city_radius_contains_tile (reserved_city, tile_x, tile_y)) - return false; - - // Get the wonder index for the wonder being built - if (out_windex != NULL) { - int order_id = reserved_city->Body.Order_ID; - int windex = find_wonder_config_index_by_improvement_id (order_id); - *out_windex = windex; - } - - return true; -} - -bool -city_needs_wonder_district (City * city) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - - int pending_improv_id; - if (look_up_pending_building_order (city, &pending_improv_id)) { - // Check if it's actually a wonder - if ((pending_improv_id >= 0) && (pending_improv_id < p_bic_data->ImprovementsCount)) { - Improvement * improv = &p_bic_data->Improvements[pending_improv_id]; - if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - return true; - } - } - if (city_is_currently_building_wonder (city)) - return true; - if (city_has_active_wonder_for_district (city)) - return true; - return false; -} - -bool -city_has_assigned_wonder_district (City * city, Tile * ignore_tile, int wonder_improv_id) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - if (candidate == ignore_tile) - continue; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = inst ? &inst->wonder_info : NULL; - if ((info != NULL) && - (info->state == WDS_UNDER_CONSTRUCTION) && - (info->city_id == city->Body.ID)) { - info->city = city; - if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) { - info->state = WDS_UNUSED; - info->city = NULL; - info->city_id = -1; - info->wonder_index = -1; - continue; - } - return true; - } - } - - return false; -} - -bool -free_wonder_district_for_city (City * city) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) - return false; - if (city_needs_wonder_district (city)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { - int x = wai.tile_x, y = wai.tile_y; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info != NULL && info->state == WDS_COMPLETED) - continue; // Don't remove completed wonder districts - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - continue; - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - - handle_district_removed (tile, WONDER_DISTRICT_ID, city->Body.X, city->Body.Y, false); - return true; - } - - return false; -} - -bool -reserve_wonder_district_for_city (City * city, int wonder_improv_id) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) - return false; - - if (city_has_assigned_wonder_district (city, NULL, wonder_improv_id)) - return true; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if (info->state == WDS_COMPLETED) continue; - if (info->state == WDS_UNDER_CONSTRUCTION) { - if (info->city_id == city->Body.ID) { - info->city = city; - return true; - } - continue; - } - if (city_has_assigned_wonder_district (city, candidate, wonder_improv_id)) - return true; - - // Reserve this Wonder district for this city - info->state = WDS_UNDER_CONSTRUCTION; - info->city = city; - info->city_id = city->Body.ID; - info->wonder_index = -1; - return true; - } - - return false; -} - -void -release_wonder_district_reservation (City * city) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return; - - // Find and remove any reservations for this city - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if ((info != NULL) && - (info->state == WDS_UNDER_CONSTRUCTION) && - (info->city_id == city->Body.ID)) { - info->city = city; - info->state = WDS_UNUSED; - info->city = NULL; - info->city_id = -1; - info->wonder_index = -1; - } - } -} - -void -handle_district_destroyed_by_attack (Tile * tile, int tile_x, int tile_y, bool leave_ruins) -{ - if (! is->current_config.enable_districts || tile == NULL || tile == p_null_tile) - return; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - int district_id = inst->district_id; - - // If this is a Wonder District with a completed wonder and wonders can't be destroyed, restore overlay and keep district - if (is->current_config.enable_wonder_districts) { - struct wonder_district_info * info = get_wonder_district_info (tile); - if ((district_id == WONDER_DISTRICT_ID) && - (info != NULL && info->state == WDS_COMPLETED) && - (! is->current_config.completed_wonder_districts_can_be_destroyed)) { - unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); - if ((overlays & TILE_FLAG_MINE) == 0) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - return; - } - } - if (district_id == BRIDGE_DISTRICT_ID || district_id == CANAL_DISTRICT_ID) { - enum UnitTypeClasses target_class = (district_id == BRIDGE_DISTRICT_ID) ? UTC_Land : UTC_Sea; - clear_memo (); - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if (unit == NULL) - continue; - int unit_type_id = unit->Body.UnitTypeID; - if ((unit_type_id < 0) || (unit_type_id >= p_bic_data->UnitTypeCount)) - continue; - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - bool matches = (type->Unit_Class == target_class); - if (! matches && unit->Body.Container_Unit >= 0) { - Unit * container = get_unit_ptr (unit->Body.Container_Unit); - if (container != NULL) { - int container_type_id = container->Body.UnitTypeID; - if ((container_type_id >= 0) && (container_type_id < p_bic_data->UnitTypeCount)) { - UnitType * container_type = &p_bic_data->UnitTypes[container_type_id]; - matches = (container_type->Unit_Class == target_class); - } - } - } - if (matches) { - bool already = false; - for (int n = 0; n < is->memo_len; n++) - if (is->memo[n] == unit->Body.ID) { - already = true; - break; - } - if (! already) - memoize (unit->Body.ID); - } - } - for (int n = 0; n < is->memo_len; n++) { - Unit * to_despawn = get_unit_ptr (is->memo[n]); - if (to_despawn != NULL) - patch_Unit_despawn (to_despawn, __, 0, 1, 0, 0, 0, 0, 0); - } - clear_memo (); - } - handle_district_removed (tile, district_id, tile_x, tile_y, leave_ruins); - } -} - -bool -has_active_building (City * city, int improv_id) -{ - Leader * owner = &leaders[city->Body.CivID]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - return patch_City_has_improvement (city, __, improv_id, 1) && // building is physically present in city AND - ((improv->ObsoleteID < 0) || (! Leader_has_tech (owner, __, improv->ObsoleteID))) && // building is not obsolete AND - ((improv->GovernmentID < 0) || (improv->GovernmentID == owner->GovernmentType)); // building is not restricted to a different govt -} - -void -init_unit_type_count (Leader * leader) -{ - int id = leader->ID; - struct table * counts = &is->unit_type_counts[id]; - - if (counts->len > 0) - table_deinit (counts); - - if (p_units->Units != NULL) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit_Body * body = p_units->Units[n].Unit; - if ((body != NULL) && ((int)body != offsetof (Unit, Body)) && (body->CivID == id)) { - int prev_count = itable_look_up_or (counts, body->UnitTypeID, 0); - itable_insert (counts, body->UnitTypeID, prev_count + 1); - } - } - - is->unit_type_count_init_bits |= 1 << id; -} - -int -get_unit_type_count (Leader * leader, int unit_type_id) -{ - int id = leader->ID; - struct table * counts = &is->unit_type_counts[id]; - - if ((is->unit_type_count_init_bits & 1<ID; - struct table * counts = &is->unit_type_counts[id]; - if ((is->unit_type_count_init_bits & (1 << id)) == 0) - init_unit_type_count (leader); - - int prev_amount = itable_look_up_or (counts, unit_type_id, 0); - itable_insert (counts, unit_type_id, prev_amount + amount); -} - -// If this unit type is limited, returns true and writes how many units of the type the given player is allowed to "out_limit". If the type is not -// limited, returns false. -bool -get_unit_limit (Leader * leader, int unit_type_id, int * out_limit) -{ - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - struct unit_type_limit * lim; - 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; - if (lim->cities_per != 0) - tr += city_count / lim->cities_per; - *out_limit = tr; - return true; - } else - return false; -} - -// This this unit type is limited, returns true and writes to "out_available" how many units the given player can add before reaching the limit. If -// the type is not limited, returns false. -bool -get_available_unit_count (Leader * leader, int unit_type_id, int * out_available) -{ - int limit; - if (get_unit_limit (leader, unit_type_id, &limit)) { - int count = get_unit_type_count (leader, unit_type_id); - int dups[30]; - int dups_count = list_unit_type_duplicates (unit_type_id, dups, ARRAY_LEN (dups)); - for (int n = 0; n < dups_count; n++) - count += get_unit_type_count (leader, dups[n]); - - *out_available = limit - count; - return true; - } else - return false; -} - -int -add_i31b_to_int (int base, i31b addition) -{ - int amount; - bool percent; - i31b_unpack (addition, &amount, &percent); - if (! percent) - return base + amount; - else { - int fraction = (base * int_abs (amount) + 50) / 100; - return (amount >= 0) ? base + fraction : base - fraction; - } -} - -int -apply_perfume (enum perfume_kind kind, char const * name, int base_amount) -{ - i31b perfume_value; - if (stable_look_up (&is->current_config.perfume_specs[kind], name, &perfume_value)) - return add_i31b_to_int (base_amount, perfume_value); - else - return base_amount; -} - -int __stdcall -intercept_consideration (int valuation) -{ - City * city = is->ai_considering_production_for_city; - City_Order * order = &is->ai_considering_order; - - // Apply perfume - char * order_name; { - if (order->OrderType == COT_Improvement) - order_name = p_bic_data->Improvements[order->OrderID].Name.S; - else - order_name = p_bic_data->UnitTypes[order->OrderID].Name; - } - valuation = apply_perfume (PK_PRODUCTION, order_name, valuation); - - // Apply temp AI settler perfume - if ((order->OrderType == COT_Unit) && - (p_bic_data->UnitTypes[order->OrderID].AI_Strategy & UTAI_Settle) && - (is->current_config.ai_settler_perfume_on_founding != 0) && - (is->current_config.ai_settler_perfume_on_founding_duration != 0) && - (is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID] >= 0)) { - int turns_since_founding = *p_current_turn_no - is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID]; - int duration = is->current_config.ai_settler_perfume_on_founding_duration; - if (turns_since_founding < duration) { - i31b perfume = is->current_config.ai_settler_perfume_on_founding; - - // Scale amount by turns remaining - { - int amount; - bool percent; - i31b_unpack (perfume, &amount, &percent); - - int percent_remaining = (100 * (duration - turns_since_founding)) / duration; - amount = (amount * percent_remaining + 50) / 100; - - perfume = i31b_pack (amount, percent); - } - - valuation = add_i31b_to_int (valuation, perfume); - } - } - - if (is->current_config.enable_districts && - (city != NULL) && - ((*p_human_player_bits & (1 << city->Body.CivID)) == 0)) { - bool feasible = false; - switch (order->OrderType) { - case COT_Improvement: - if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->ImprovementsCount) && - (! city_requires_district_for_improvement (city, order->OrderID, NULL))) - feasible = true; - break; - case COT_Unit: - if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->UnitTypeCount)) - feasible = true; - break; - default: - break; - } - if (feasible) - record_best_feasible_order (city, order, valuation); - } - - // Expand the list of valuations if necessary - reserve (sizeof is->ai_prod_valuations[0], (void **)&is->ai_prod_valuations, &is->ai_prod_valuations_capacity, is->count_ai_prod_valuations); - - // Record this valuation - int n = is->count_ai_prod_valuations++; - is->ai_prod_valuations[n] = (struct ai_prod_valuation) { - .order_type = order->OrderType, - .order_id = order->OrderID, - .point_value = valuation - }; - - return valuation; -} - -// Returns a pointer to a bitfield that can be used to record resource access for resource IDs >= 32. This procedure can work with any city ID since -// it allocates and zero-initializes these bit fields as necessary. The given resource ID must be at least 32. The index of the bit for that resource -// within the field is resource_id%32. -unsigned * -get_extra_resource_bits (int city_id, int resource_id) -{ - int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); - int ints_per_city = 1 + extra_resource_count/32; - if (city_id >= is->extra_available_resources_capacity) { - int new_capacity = city_id + 100; - unsigned * new_array = calloc (new_capacity * ints_per_city, sizeof new_array[0]); - if (is->extra_available_resources != NULL) { - memcpy (new_array, is->extra_available_resources, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); - free (is->extra_available_resources); - } - is->extra_available_resources = new_array; - is->extra_available_resources_capacity = new_capacity; - } - return &is->extra_available_resources[city_id * ints_per_city + (resource_id-32)/32]; -} - -void __stdcall -intercept_set_resource_bit (City * city, int resource_id) -{ - if (resource_id < 32) - city->Body.Available_Resources |= 1 << resource_id; - else - *get_extra_resource_bits (city->Body.ID, resource_id) |= 1 << (resource_id&31); -} - -// Must forward declare this function since there's a circular dependency between it and patch_City_has_resource -bool has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id); - -bool __fastcall -patch_City_has_resource (City * this, int edx, int resource_id) -{ - return city_has_resource_r (this, resource_id, INT_MAX); -} - -bool -city_has_resource_r (City * this, int resource_id, int max_generated_resource_id) -{ - bool tr; - if ((this == NULL) || (resource_id < 0) || (resource_id >= p_bic_data->ResourceTypeCount)) - return false; - if (resource_id > max_generated_resource_id) - return false; - - if (is->current_config.patch_phantom_resource_bug && - (resource_id >= 32) && (resource_id < p_bic_data->ResourceTypeCount) && - (! City_has_trade_connection_to_capital (this))) { - unsigned bits = (this->Body.ID < is->extra_available_resources_capacity) ? *get_extra_resource_bits (this->Body.ID, resource_id) : 0; - tr = (bits >> (resource_id&31)) & 1; - } else - tr = City_has_resource (this, __, resource_id); - - // Check if access to this resource is provided by a building in the city - if (! tr) - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if ((mill->resource_id == resource_id) && - (mill->flags & MF_LOCAL) && - can_generate_resource (this->Body.CivID, mill) && - has_active_building (this, mill->improv_id) && - has_resources_required_by_building_r (this, mill->improv_id, mill->resource_id - 1)) { - tr = true; - break; - } - } - - // Check if access to this resource is provided by a district in the city's work radius - if ((! tr) && is->current_config.enable_districts) { - FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { - struct district_instance * di = wai.district_inst; - int district_id = di->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - continue; - - struct district_config * dc = &is->district_configs[district_id]; - if ((dc->generated_resource_id == resource_id) && - (dc->generated_resource_flags & MF_LOCAL) && - district_generates_resource_for_civ (wai.tile, di, dc, this->Body.CivID)) { - tr = true; - break; - } - } - } - - return tr; -} - -// Checks if the resource requirements for an improvement are satisfied in a given city. The "max_req_resource_id" parameter is to guard against -// infinite loops in case of circular resource dependencies due to mills. The way it works is that resource requirements can only be satisfied if -// their ID is not greater than that limit. This function is called recursively by patch_City_has_resource and in the recursive calls, the limit is -// set to be below the resource ID provided by the mill being considered. So, when considering resource production chains, the limit approaches zero -// with each recursive call, hence infinite loops are not possible. -bool -has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id) -{ - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if (! (improv->ImprovementFlags & ITF_Required_Goods_Must_Be_In_City_Radius)) { - for (int n = 0; n < 2; n++) { - int res_id = (&improv->Resource1ID)[n]; - if ((res_id >= 0) && - ((res_id > max_req_resource_id) || (! city_has_resource_r (city, res_id, max_req_resource_id)))) - return false; - } - return true; - } else { - int * targets = &improv->Resource1ID; - if ((targets[0] < 0) && (targets[1] < 0)) - return true; - int finds[2] = {0, 0}; - - int civ_id = city->Body.CivID; - for (int n = 0; n < is->workable_tile_count; n++) { - int dx, dy; - patch_ni_to_diff_for_work_area (n, &dx, &dy); - int x = city->Body.X + dx, y = city->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &x, &y); - Tile * tile = tile_at (x, y); - if (tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id) { - int res_here = Tile_get_resource_visible_to (tile, __, civ_id); - if (res_here >= 0) { - finds[0] |= targets[0] == res_here; - finds[1] |= targets[1] == res_here; - } - } - } - - return ((targets[0] < 0) || finds[0]) && ((targets[1] < 0) || finds[1]); - } -} - -bool -has_resources_required_by_building (City * city, int improv_id) -{ - return has_resources_required_by_building_r (city, improv_id, INT_MAX); -} - -void __fastcall -patch_City_recompute_commerce (City * this) -{ - City_recompute_commerce (this); - - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - int science_bonus = 0; - calculate_district_culture_science_bonuses (this, NULL, &science_bonus); - - if (science_bonus != 0) { - this->Body.Science += science_bonus; - if (this->Body.Science < 0) - this->Body.Science = 0; - } -} - -void __fastcall -patch_City_recompute_yields_and_happiness (City * this) -{ - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts && - ! is->distribution_hub_refresh_in_progress && - is->distribution_hub_totals_dirty) - recompute_distribution_hub_totals (); - - City_recompute_yields_and_happiness (this); -} - -void __fastcall -patch_City_update_culture (City * this) -{ - City_update_culture (this); - - if ((this == NULL) || ! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - int culture_bonus = 0; - calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); - - if (culture_bonus == 0) - return; - - int culture_income = this->Body.CultureIncome + culture_bonus; - if (culture_income < 0) - culture_income = 0; - this->Body.CultureIncome = culture_income; - - int civ_id = this->Body.CivID; - int total_culture = this->Body.Total_Cultures[civ_id] + culture_bonus; - if (total_culture < 0) - total_culture = 0; - this->Body.Total_Cultures[civ_id] = total_culture; - - City_recompute_cultural_level (this, __, '\0', '\0', '\0'); -} - -void __fastcall -patch_City_recompute_culture_income (City * this) -{ - City_recompute_culture_income (this); - - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - int culture_bonus = 0; - calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); - - if (culture_bonus != 0) { - this->Body.CultureIncome += culture_bonus; - if (this->Body.CultureIncome < 0) - this->Body.CultureIncome = 0; - } -} - -// Recomputes yields in cities with active mills that depend on input resources. Intended to be called when an input resource has been potentially -// gained or lost. Recomputes only for the cities of a given leader or, if NULL, for all cities on the map. -void -recompute_mill_yields_after_resource_change (Leader * leader_or_null) -{ - if (p_cities->Cities != NULL) - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city != NULL) && - ((leader_or_null == NULL) || (city->Body.CivID == leader_or_null->ID))) { - bool any_relevant_mills = false; - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - Improvement * mill_improv = &p_bic_data->Improvements[mill->improv_id]; - if ((mill->flags & MF_YIELDS) && - ((mill_improv->Resource1ID >= 0) || (mill_improv->Resource2ID >= 0)) && - has_active_building (city, mill->improv_id)) { - any_relevant_mills = true; - break; - } - } - if (any_relevant_mills) - patch_City_recompute_yields_and_happiness (city); - } - } -} - - -int -resource_tile_resource_id (struct extra_resource_tile const * rt) -{ - if (rt == NULL) - return -1; - if (rt->type == ERT_MILL_RESOURCE) { - return (rt->mill_info.mill != NULL) ? rt->mill_info.mill->resource_id : -1; - } else if (rt->district_info.cfg != NULL) { - return rt->district_info.cfg->generated_resource_id; - } - return -1; -} - -int -compare_resource_tiles (void const * vp_a, void const * vp_b) -{ - struct extra_resource_tile const * a = vp_a, * b = vp_b; - return resource_tile_resource_id (a) - resource_tile_resource_id (b); -} - -void __fastcall -patch_Trade_Net_recompute_resources (Trade_Net * this, int edx, bool skip_popups) -{ - int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); - int ints_per_city = 1 + extra_resource_count/32; - memset (is->extra_available_resources, 0, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); - - // Assemble list of mill tiles - is->count_resource_tiles = 0; - if (p_cities->Cities != NULL) - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if (city != NULL) - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if (((mill->flags & MF_LOCAL) == 0) && - has_active_building (city, mill->improv_id) && - can_generate_resource (city->Body.CivID, mill)) { - Tile * resource_tile = tile_at (city->Body.X, city->Body.Y); - if ((resource_tile == NULL) || (resource_tile == p_null_tile)) - continue; - reserve (sizeof is->resource_tiles[0], - (void **)&is->resource_tiles, - &is->resource_tiles_capacity, - is->count_resource_tiles); - is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { - .tile = resource_tile, - .type = ERT_MILL_RESOURCE, - .mill_info = { - .city = city, - .mill = mill - } - }; - } - } - } - if (is->current_config.enable_districts) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * district_tile = (Tile *)tei.key; - struct district_instance * inst = (struct district_instance *)tei.value; - if ((district_tile == NULL) || (district_tile == p_null_tile) || (inst == NULL) || (inst->state != DS_COMPLETED)) - continue; - - int district_id = inst->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - continue; - - struct district_config * cfg = &is->district_configs[district_id]; - if ((cfg == NULL) || (cfg->generated_resource_id < 0)) - continue; - - int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); - if (owner_id < 0) - continue; - if ((cfg->generated_resource_flags & MF_LOCAL) != 0) - continue; - if (! district_can_generate_resource (owner_id, cfg)) - continue; - - reserve (sizeof is->resource_tiles[0], - (void **)&is->resource_tiles, - &is->resource_tiles_capacity, - is->count_resource_tiles); - is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { - .tile = district_tile, - .type = ERT_DISTRICT_RESOURCE, - .district_info = { - .inst = inst, - .cfg = cfg - } - }; - } - } - qsort (is->resource_tiles, is->count_resource_tiles, sizeof is->resource_tiles[0], compare_resource_tiles); - - is->got_resource_tile = NULL; - is->saved_tile_count = p_bic_data->Map.TileCount; - p_bic_data->Map.TileCount += is->count_resource_tiles; - Trade_Net_recompute_resources (this, __, skip_popups); - - // Restore the tile count if necessary. It may have already been restored by patch_Map_Renderer_m71_Draw_Tiles. This happens when the call to - // recompute_resources above opens a popup message about connecting a resource for the first time, which triggers redraw of the map. - if (is->saved_tile_count >= 0) { - p_bic_data->Map.TileCount = is->saved_tile_count; - is->saved_tile_count = -1; - } - - recompute_mill_yields_after_resource_change (NULL); - - is->must_recompute_resources_for_mill_inputs = false; -} - -Tile * -get_resource_tile (int index) -{ - struct extra_resource_tile * rt = &is->resource_tiles[index]; - is->got_resource_tile = rt; - return rt->tile; -} - -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_1 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_2 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_3 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_4 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_5 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } - -int __fastcall -patch_Tile_get_visible_resource_when_recomputing (Tile * tile, int edx, int civ_id) -{ - if (is->got_resource_tile != NULL) { - struct extra_resource_tile * rt = is->got_resource_tile; - is->got_resource_tile = NULL; - if (rt->type == ERT_MILL_RESOURCE) { - if ((rt->mill_info.city != NULL) && (rt->mill_info.mill != NULL) && - has_resources_required_by_building (rt->mill_info.city, rt->mill_info.mill->improv_id)) - return rt->mill_info.mill->resource_id; - else - return -1; - } else { - Tile * district_tile = rt->tile; - struct district_instance * inst = rt->district_info.inst; - struct district_config * cfg = rt->district_info.cfg; - if ((district_tile != NULL) && (district_tile != p_null_tile) && (inst != NULL) && - (cfg != NULL) && (inst->state == DS_COMPLETED)) { - int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); - if ((owner_id == civ_id) && district_generates_resource_for_civ (district_tile, inst, cfg, owner_id)) - return cfg->generated_resource_id; - } - return -1; - } - } - - int base_resource = Tile_get_resource_visible_to (tile, __, civ_id); - return base_resource; -} - -int WINAPI -patch_MessageBoxA (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) -{ - if (is->current_config.suppress_hypertext_links_exceeded_popup && - (strcmp (lpText, "Maximum hypertext links exceeded!") == 0)) - return IDOK; - else - return MessageBoxA (hWnd, lpText, lpCaption, uType); -} - -char * __fastcall -do_capture_modified_gold_trade (TradeOffer * trade_offer, int edx, int val, char * str, unsigned base) -{ - is->modifying_gold_trade = trade_offer; - return print_int (val, str, base); -} - -// Here the order of the registers matches the order that they're pushed by the pusha instruction -struct register_set { - int edi, esi, ebp, esp, ebx, edx, ecx, eax; -}; - -// Return 1 to allow the candidate unit to exert ZoC, 0 to exclude it. A pointer to the candidate is in esi. -int __stdcall -filter_zoc_candidate (struct register_set * reg) -{ - Unit * candidate = (Unit *)reg->esi, - * defender = is->zoc_defender; - - UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID], - * defender_type = &p_bic_data->UnitTypes[defender ->Body.UnitTypeID]; - - enum UnitTypeClasses candidate_class = candidate_type->Unit_Class, - defender_class = defender_type ->Unit_Class; - - bool lethal = ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) != 0) && (! is->temporarily_disallow_lethal_zoc); - bool aerial = (is->current_config.special_zone_of_control_rules & SZOCR_AERIAL ) != 0, - amphibious = (is->current_config.special_zone_of_control_rules & SZOCR_AMPHIBIOUS) != 0; - - // Exclude air units if aerial ZoC is not enabled and exclude land-to-sea & sea-to-land ZoC if amphibious is not enabled - if ((! aerial) && (candidate_class == UTC_Air)) - return 0; - if ((! amphibious) && - (((candidate_class == UTC_Land) && (defender_class == UTC_Sea )) || - ((candidate_class == UTC_Sea ) && (defender_class == UTC_Land)))) - return 0; - - // In case of cross-domain ZoC, filter out units with zero bombard strength or range. They can't use their attack strength in this case, so - // without bombard they can be ruled out. Don't forget units may have non-zero bombard strength and zero range for defensive bombard. - int range = (candidate_class != UTC_Air) ? candidate_type->Bombard_Range : candidate_type->OperationalRange; - if ((candidate_class != defender_class) && ((candidate_type->Bombard_Strength <= 0) || (range <= 0))) - return 0; - - // Require lethal config option & lethal bombard against one HP defender - if ((Unit_get_max_hp (defender) - defender->Body.Damage <= 1) && - ((! lethal) || - ((defender_class == UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Sea_Bombardment)) || - ((defender_class != UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Land_Bombardment)))) - return 0; - - // Air units require the bombing action to perform ZoC - if ((candidate_class == UTC_Air) && ! (candidate_type->Air_Missions & UCV_Bombing)) - return 0; - - // Exclude land units in transports if configured - if ((is->current_config.special_zone_of_control_rules & SZOCR_NOT_FROM_INSIDE) && candidate_class == UTC_Land) { - Unit * container = get_unit_ptr (candidate->Body.Container_Unit); - if ((container != NULL) && ! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)) - return 0; - } - - return 1; -} - -#define TRADE_NET_REF_COUNT 315 -#define TRADE_NET_INSTR_COUNT_GOG 22 -#define TRADE_NET_INSTR_COUNT_STEAM 23 -#define TRADE_NET_INSTR_COUNT_PCG 22 -#define TRADE_NET_ADDR_TOTAL_COUNT ((TRADE_NET_REF_COUNT * 3) + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM + TRADE_NET_INSTR_COUNT_PCG) - -int * -load_trade_net_addrs () -{ - if (is->trade_net_addrs_load_state == IS_OK) - return is->trade_net_addrs; - else if (is->trade_net_addrs_load_state == IS_INIT_FAILED) - return NULL; - - bool success = false; - char err_msg[300] = {0}; - - is->trade_net_addrs = calloc (3 * TRADE_NET_ADDR_TOTAL_COUNT, sizeof is->trade_net_addrs[0]); - if (! is->trade_net_addrs) { - snprintf (err_msg, (sizeof err_msg) - 1, "Bad alloc"); - goto done; - } - - char file_path[MAX_PATH] = {0}; - snprintf (file_path, (sizeof file_path) - 1, "%s\\trade_net_addresses.txt", is->mod_rel_dir); - char * refs_file = file_to_string (file_path); - if (! refs_file) { - snprintf (err_msg, (sizeof err_msg) - 1, "Couldn't load %s", file_path); - goto done; - } - - char * cursor = refs_file; - int loaded_count = 0; - while (true) { - if (*cursor == '#') { // comment line - skip_line (&cursor); - continue; - } - - skip_horiz_space (&cursor); - if (*cursor == '\n') { // empty line - cursor++; - continue; - } else if (*cursor == '\0') // end of file - break; - - // otherwise we must be on a line with some addresses - int ref; - bool got_any_addresses = false; - while (parse_int (&cursor, &ref)) { - if (loaded_count >= TRADE_NET_ADDR_TOTAL_COUNT) { - snprintf (err_msg, (sizeof err_msg) - 1, "Too many values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); - goto done; - } - is->trade_net_addrs[loaded_count] = ref; - loaded_count++; - got_any_addresses = true; - } - - if (! got_any_addresses) { - snprintf (err_msg, (sizeof err_msg) - 1, "Parse error"); - goto done; - } - } - - if (loaded_count < TRADE_NET_ADDR_TOTAL_COUNT) { - snprintf (err_msg, (sizeof err_msg) - 1, "Too few values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); - goto done; - } - - success = true; - -done: - free (refs_file); - if (! success) { - char full_err_msg[300] = {0}; - snprintf (full_err_msg, (sizeof full_err_msg) - 1, "Failed to load trade net refs: %s", err_msg); - MessageBox (NULL, full_err_msg, NULL, MB_ICONERROR); - is->trade_net_addrs_load_state = IS_INIT_FAILED; - return NULL; - } else { - is->trade_net_addrs_load_state = IS_OK; - return is->trade_net_addrs; - } -} - -unsigned short * __fastcall -patch_get_pixel_to_draw_city_dot (JGL_Image * this, int edx, int x, int y) -{ - unsigned short * tr = this->vtable->m07_m05_Get_Pixel (this, __, x, y); - - if ((x + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Width2) && (y + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Height2)) { - unsigned short * below = this->vtable->m07_m05_Get_Pixel (this, __, x + 1, y + 1); - if (below != NULL) - *below = 0; - } - - return tr; -} - -enum branch_kind { BK_CALL, BK_JUMP }; - -byte * -emit_branch (enum branch_kind kind, byte * cursor, void const * target) -{ - int offset = (int)target - ((int)cursor + 5); - *cursor++ = (kind == BK_CALL) ? 0xE8 : 0xE9; - return int_to_bytes (cursor, offset); -} - -// Just calls VirtualProtect and displays an error message if it fails. Made for use by the WITH_MEM_PROTECTION macro. -bool -check_virtual_protect (LPVOID addr, SIZE_T size, DWORD flags, PDWORD old_protect) -{ - if (VirtualProtect (addr, size, flags, old_protect)) - return true; - else { - char err_msg[1000]; - snprintf (err_msg, sizeof err_msg, "VirtualProtect failed! Args:\n Address: 0x%p\n Size: %d\n Flags: 0x%x", addr, size, flags); - err_msg[(sizeof err_msg) - 1] = '\0'; - MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); - return false; - } -} - -#define WITH_MEM_PROTECTION(addr, size, flags) \ - for (DWORD old_protect, unused, iter_count = 0; \ - (iter_count == 0) && check_virtual_protect (addr, size, flags, &old_protect); \ - VirtualProtect (addr, size, old_protect, &unused), iter_count++) - -void __fastcall adjust_sliders_preproduction (Leader * this); - -struct saved_code_area { - int size; - byte original_contents[]; -}; - -// Saves an area of base game code and optionally replaces it with no-ops. The area can be restored with restore_code_area. This method assumes that -// the necessary memory protection has already been set on the area, specifically that it can be written to. The method will do nothing if the area -// has already been saved with the same size. It's an error to re-save an address with a different size or overlap two saved areas. -void -save_code_area (byte * addr, int size, bool nopify) -{ - struct saved_code_area * sca; - if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { - if (sca->size != 0) { - if (sca->size != size) { - char s[200]; - snprintf (s, sizeof s, "Save code area conflict: address %p was already saved with size %d, conflicting with new size %d.", addr, sca->size, size); - s[(sizeof s) - 1] = '\0'; - pop_up_in_game_error (s); - } - return; - } - } else { - sca = malloc (size + sizeof *sca); - itable_insert (&is->saved_code_areas, (int)addr, (int)sca); - } - sca->size = size; - memcpy (&sca->original_contents, addr, size); - if (nopify) - memset (addr, 0x90, size); -} - -// Restores a saved chunk of code to its original contents. Does nothing if the area hasn't been saved. Assumes the appropriate memory protection has -// already been set. -void -restore_code_area (byte * addr) -{ - struct saved_code_area * sca; - if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { - memcpy (addr, &sca->original_contents, sca->size); - sca->size = 0; - } -} - -bool -is_code_area_saved (byte * addr) -{ - struct saved_code_area * sca; - return itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca) && (sca->size > 0); -} - -// Nopifies or restores an area depending on if yes_or_no is 1 or 0. Sets the necessary memory protections. -void -set_nopification (int yes_or_no, byte * addr, int size) -{ - WITH_MEM_PROTECTION (addr, size, PAGE_EXECUTE_READWRITE) { - if (yes_or_no) - save_code_area (addr, size, true); - else - restore_code_area (addr); - } -} - -void -apply_machine_code_edits (struct c3x_config const * cfg, bool at_program_start) -{ - DWORD old_protect, unused; - - // Allow stealth attack against single unit - WITH_MEM_PROTECTION (ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK = cfg->allow_stealth_attack_against_single_unit ? 0 : 1; - - // Enable small wonders providing free buildings - WITH_MEM_PROTECTION (ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER, 10, PAGE_EXECUTE_READWRITE) { - byte normal[8] = {0x83, 0xE1, 0x04, 0x80, 0xF9, 0x04, 0x0F, 0x85}; // and ecx, 4; cmp ecx, 4; jnz [offset] - byte modded[8] = {0x83, 0xE1, 0x0C, 0x80, 0xF9, 0x00, 0x0F, 0x84}; // and ecx, 12; cmp ecx, 0; jz [offset] - for (int n = 0; n < 8; n++) - ((byte *)ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER)[n] = cfg->enable_free_buildings_from_small_wonders ? modded[n] : normal[n]; - } - - // Bypass artillery in city check - // replacing 0x74 (= jump if [city ptr is] zero) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_CHECK_ARTILLERY_IN_CITY, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_CHECK_ARTILLERY_IN_CITY = cfg->use_offensive_artillery_ai ? 0xEB : 0x74; - - // Remove unit limit - if (! at_program_start) { - // Replace 0x7C (= jump if less than [unit limit]) with 0xEB (= uncond. jump) in Leader::spawn_unit - WITH_MEM_PROTECTION (ADDR_UNIT_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_UNIT_COUNT_CHECK = cfg->remove_unit_limit ? 0xEB : 0x7C; - - // Increase max ID to search for tradable units by 10x if limit removed - WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_UNIT_ID, 4, PAGE_EXECUTE_READWRITE) - int_to_bytes (ADDR_MAX_TRADABLE_UNIT_ID, cfg->remove_unit_limit ? 81920 : 8192); - - // Reallocate diplo_form->tradable_units array so it's 10x long if limit removed - civ_prog_free (p_diplo_form->tradable_units); - int tradable_units_len = cfg->remove_unit_limit ? 81920 : 8192, - tradable_units_size = tradable_units_len * sizeof (TradableItem); - p_diplo_form->tradable_units = new (tradable_units_size); - for (int n = 0; n < tradable_units_len; n++) - p_diplo_form->tradable_units[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 - - // Patch the size limit on some code that clears the tradable units array when starting a new game - WITH_MEM_PROTECTION (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) - int_to_bytes (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, tradable_units_size); - } - - // Remove the standard rule that blocks battle-created units while the player already has one - set_nopification (cfg->allow_multiple_battle_created_units_per_player, ADDR_EXISTING_BATTLE_CREATED_UNIT_CHECK, 6); - - // Bypass air unit check when drawing pedia stats. If it passes, the check will draw the op. range instead of movement in the first column. - // replacing 0x75 (= jnz) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS, 1, PAGE_EXECUTE_READWRITE) - *ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS = is->current_config.expand_civilopedia_unit_stats ? 0xEB : 0x75; - - // Remove era limit - // replacing 0x74 (= jump if zero [after cmp'ing era count with 4]) with 0xEB - WITH_MEM_PROTECTION (ADDR_ERA_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_ERA_COUNT_CHECK = cfg->remove_era_limit ? 0xEB : 0x74; - - // Fix science age bug - // Similar in nature to the sub bug, the function that measures a city's research output accepts a flag that determines whether or not it - // takes science ages into account. It's mistakenly not set by the code that gathers all research points to increment tech progress (but it - // is set elsewhere in code for the interface). The patch simply sets this flag. - WITH_MEM_PROTECTION (ADDR_SCIENCE_AGE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_SCIENCE_AGE_BUG_PATCH = cfg->patch_science_age_bug ? 1 : 0; - - // Pedia pink line bug fix - // The size of the pedia background texture is hard-coded into the EXE and in the base game it's one pixel too small. This shows up in game as - // a one pixel wide pink line along the right edge of the civilopedia. This patch simply increases the texture width by one. - WITH_MEM_PROTECTION (ADDR_PEDIA_TEXTURE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_PEDIA_TEXTURE_BUG_PATCH = cfg->patch_pedia_texture_bug ? 0xA6 : 0xA5; - - // Fix for houseboat bug - // See my posts on CFC for an explanation of the bug and its fix: - // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16084386 - // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16085242 - WITH_MEM_PROTECTION (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, PAGE_EXECUTE_READWRITE) { - if (cfg->patch_houseboat_bug) { - save_code_area (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, true); - byte * cursor = ADDR_HOUSEBOAT_BUG_PATCH; - *cursor++ = 0x50; // push eax - int call_offset = (int)&tile_at_city_or_null - ((int)cursor + 5); - *cursor++ = 0xE8; // call - cursor = int_to_bytes (cursor, call_offset); - } else - restore_code_area (ADDR_HOUSEBOAT_BUG_PATCH); - } - - // NoRaze - WITH_MEM_PROTECTION (ADDR_AUTORAZE_BYPASS, 2, PAGE_EXECUTE_READWRITE) { - byte normal[2] = {0x0F, 0x85}; // jnz - byte bypass[2] = {0x90, 0xE9}; // nop, jmp - for (int n = 0; n < 2; n++) - ((byte *)ADDR_AUTORAZE_BYPASS)[n] = cfg->prevent_autorazing ? bypass[n] : normal[n]; - } - - // Overwrite the instruction(s) where the AI's production choosing code compares the value of what it's currently considering to the best - // option so far. This is done twice since improvements and units are handled in separate loops. The instr(s) are overwritten with a jump to - // an "airlock", which is a bit of code that wraps the call to intercept_consideration. The contents of the airlocks are prepared by the - // patcher in init_consideration_airlocks. - // TODO: This instruction replacement could be done in the patcher too and that might be a better place for it. Think about this. - for (int n = 0; n < 2; n++) { - void * addr_intercept = (n == 0) ? ADDR_INTERCEPT_AI_IMPROV_VALUE : ADDR_INTERCEPT_AI_UNIT_VALUE; - void * addr_airlock = (n == 0) ? ADDR_IMPROV_CONSIDERATION_AIRLOCK : ADDR_UNIT_CONSIDERATION_AIRLOCK; - - WITH_MEM_PROTECTION (addr_intercept, AI_CONSIDERATION_INTERCEPT_LEN, PAGE_EXECUTE_READWRITE) { - byte * cursor = addr_intercept; - - // write jump to airlock - *cursor++ = 0xE9; - int offset = (int)addr_airlock - ((int)addr_intercept + 5); - cursor = int_to_bytes (cursor, offset); - - // fill the rest of the space with NOPs - while (cursor < (byte *)addr_intercept + AI_CONSIDERATION_INTERCEPT_LEN) - *cursor++ = 0x90; // nop - } - } - - // Overwrite instruction that sets bits in City.Body.Available_Resources with a jump to the airlock - WITH_MEM_PROTECTION (ADDR_INTERCEPT_SET_RESOURCE_BIT, 6, PAGE_EXECUTE_READWRITE) { - byte * cursor = ADDR_INTERCEPT_SET_RESOURCE_BIT; - if (cfg->patch_phantom_resource_bug) { - *cursor++ = 0xE9; - int offset = (int)ADDR_SET_RESOURCE_BIT_AIRLOCK - ((int)ADDR_INTERCEPT_SET_RESOURCE_BIT + 5); - cursor = int_to_bytes (cursor, offset); - *cursor++ = 0x90; // nop - } else { - byte original[6] = {0x09, 0xB0, 0x9C, 0x00, 0x00, 0x00}; // or dword ptr [eax+0x9C], esi - for (int n = 0; n < 6; n++) - cursor[n] = original[n]; - } - } - - // Enlarge the mask that's applied to p_bic_data->Map.TileCount in the loop over lines in Trade_Net::recompute_resources. This lets us loop - // over more than 0xFFFF tiles. - WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_MASK, 1, PAGE_EXECUTE_READWRITE) { - *(byte *)ADDR_RESOURCE_TILE_COUNT_MASK = (cfg->count_mills > 0) ? 0xFF : 0x00; - } - // Similarly, enlarge the cmp instruction that jumps over the entire loop when the tile count is zero. Do this by simply removing the operand - // override prefix byte (0x66), overwriting it with a nop (0x90). This converts the instruction "cmp word ptr [bic_data.Map.TileCount], di" - // into "nop; cmp dword ptr [bic_data.Map.TileCount], edi" - WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE, 1, PAGE_EXECUTE_READWRITE) { - *(byte *)ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE = 0x90; - } - - byte * addr_turn_metalimits[] = {ADDR_TURN_METALIMIT_1, ADDR_TURN_METALIMIT_2, ADDR_TURN_METALIMIT_3, ADDR_TURN_METALIMIT_4, - ADDR_TURN_METALIMIT_5, ADDR_TURN_METALIMIT_6, ADDR_TURN_METALIMIT_7}; - for (int n = 0; n < ARRAY_LEN (addr_turn_metalimits); n++) { - byte * addr = addr_turn_metalimits[n]; - WITH_MEM_PROTECTION (addr, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (addr, cfg->remove_cap_on_turn_limit ? 1000000 : 1000); - } - } - - // Overwrite the human-ness test and call to Leader::ai_adjust_sliders that happens during the preproduction player update method. The new - // code calls adjust_sliders_preproduction for all players. - WITH_MEM_PROTECTION (ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT, 9, PAGE_EXECUTE_READWRITE) { - byte * cursor = ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT; - *cursor++ = 0x8B; *cursor++ = 0xCE; // mov ecx, esi - cursor = emit_branch (BK_CALL, cursor, adjust_sliders_preproduction); - for (; cursor < ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT + 9; cursor++) - *cursor = 0x90; // nop - } - - // Set up a special intercept of the base game's calls to print_int in order to grab a pointer to a gold TradeOffer object being modified. The - // calls to print_int happen in the context of creating the default text to be placed in the set-gold-amount popup. Conveniently, a pointer to - // the TradeOffer object is always stored in register ecx when this call happens. It's not easily accessible since print_int uses the cdecl - // convention so we must use an airlock-like thing to effectively convert the calling convention to fastcall. The first part of this code - // simply replaces the call to print_int with a call to the airlock-like thing, and the second part initializes its contents. - byte * addr_print_gold_amounts[] = {ADDR_PRINT_GOLD_AMOUNT_1, ADDR_PRINT_GOLD_AMOUNT_2}; - for (int n = 0; n < ARRAY_LEN (addr_print_gold_amounts); n++) { - byte * addr = addr_print_gold_amounts[n]; - WITH_MEM_PROTECTION (addr, 5, PAGE_EXECUTE_READWRITE) - emit_branch (BK_CALL, addr, ADDR_CAPTURE_MODIFIED_GOLD_TRADE); - } - WITH_MEM_PROTECTION (ADDR_CAPTURE_MODIFIED_GOLD_TRADE, 32, PAGE_EXECUTE_READWRITE) { - byte * cursor = ADDR_CAPTURE_MODIFIED_GOLD_TRADE; - - // Repush all of the arguments to print_int onto the stack, they will be consumed by do_capture_modified_gold_trade since it's - // fastcall. The original args don't need to be removed b/c we're replacing a cdecl function so that's the caller's - // responsibility. The TradeOffer pointer is already in ECX, so that's fine as long as we don't touch that register. - byte repush[] = {0xFF, 0x74, 0x24, 0x0C}; // push [esp+0xC] - for (int n = 0; n < 3; n++) - for (int k = 0; k < ARRAY_LEN (repush); k++) - *cursor++ = repush[k]; - - cursor = emit_branch (BK_CALL, cursor, do_capture_modified_gold_trade); // call do_capture_modified_gold_trade - *cursor++ = 0xC3; // ret - } - - // Edit branch in capture_city to never run code for barbs, this allows barbs to capture cities - WITH_MEM_PROTECTION (ADDR_CAPTURE_CITY_BARB_BRANCH, 2, PAGE_EXECUTE_READWRITE) { - byte normal[2] = {0x0F, 0x85}; // jnz - byte bypass[2] = {0x90, 0xE9}; // nop, jmp - for (int n = 0; n < 2; n++) - ((byte *)ADDR_CAPTURE_CITY_BARB_BRANCH)[n] = cfg->enable_city_capture_by_barbarians ? bypass[n] : normal[n]; - } - - // After the production phase is done for the barb player, there are two jump instructions skipping the production code for civs. Replacing - // those jumps lets us run the civ production code for the barbs as well. - WITH_MEM_PROTECTION (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, PAGE_EXECUTE_READWRITE) { - if (cfg->enable_city_capture_by_barbarians) { - save_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, true); - byte jump_to_civ[6] = {0x0F, 0x8D, 0x0C, 0x00, 0x00, 0x00}; // jge +0x12 - for (int n = 0; n < 6; n++) - ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP[n] = jump_to_civ[n]; - } else - restore_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP); - } - set_nopification (cfg->enable_city_capture_by_barbarians, ADDR_PROD_PHASE_BARB_DONE_JUMP, 5); - - for (int domain = 0; domain < 2; domain++) { - byte * addr_skip = (domain == 0) ? ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC : ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC, - * addr_airlock = (domain == 0) ? ADDR_SEA_ZOC_FILTER_AIRLOCK : ADDR_LAND_ZOC_FILTER_AIRLOCK; - - WITH_MEM_PROTECTION (addr_skip, 6, PAGE_EXECUTE_READWRITE) { - if ((cfg->special_zone_of_control_rules != 0) && ! is_code_area_saved (addr_skip)) { - byte * original_target = addr_skip + 6 + int_from_bytes (addr_skip + 2); // target addr of jump instr we're replacing - save_code_area (addr_skip, 6, true); - - // Initialize airlock. The airlock preserves all registers and calls filter_zoc_candidate then either follows or skips the - // original jump depending on what it returns. If zero is returned, follows the jump, skipping a bunch of code and filtering - // out the unit as a candidate for ZoC. - WITH_MEM_PROTECTION (addr_airlock, INLEAD_SIZE, PAGE_READWRITE) { - byte * cursor = addr_airlock; - *cursor++ = 0x60; // pusha - *cursor++ = 0x54; // push esp - cursor = emit_branch (BK_CALL, cursor, filter_zoc_candidate); - *cursor++ = 0x83; *cursor++ = 0xF8; *cursor++ = 0x01; // cmp eax, 1 - *cursor++ = 0x75; *cursor++ = 0x06; // jne 6 - *cursor++ = 0x61; // popa - cursor = emit_branch (BK_JUMP, cursor, addr_skip + 6); - *cursor++ = 0x61; // popa - cursor = emit_branch (BK_JUMP, cursor, original_target); - } - - // Write jump to airlock - emit_branch (BK_JUMP, addr_skip, addr_airlock); - } else if (cfg->special_zone_of_control_rules == 0) - restore_code_area (addr_skip); - } - } - - set_nopification ( cfg->special_zone_of_control_rules != 0, ADDR_ZOC_CHECK_ATTACKER_ANIM_FIELD_111, 6); - set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_LAND_UNIT , 6); - set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_SEA_UNIT , 6); - - WITH_MEM_PROTECTION (ADDR_LUXURY_BOX_ROW_HEIGHT, 4, PAGE_EXECUTE_READWRITE) { - byte normal [4] = {0x8B, 0x44, 0x24, LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET}; // mov eax, dword ptr [esp + LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET] - byte compact[4] = {0x31, 0xC0, 0xB0, 0x10}; // xor eax, eax; mov al, 0x10 - for (int n = 0; n < 4; n++) - ADDR_LUXURY_BOX_ROW_HEIGHT[n] = cfg->compact_luxury_display_on_city_screen ? compact[n] : normal[n]; - } - - WITH_MEM_PROTECTION (ADDR_MOST_STRAT_RES_ON_CITY_SCREEN, 1, PAGE_EXECUTE_READWRITE) { - *(byte *)ADDR_MOST_STRAT_RES_ON_CITY_SCREEN = cfg->compact_strategic_resource_display_on_city_screen ? 13 : 8; - } - - // Remove a check that a returned neighbor index is within the 21 tile work area in code related to hoving the mouse over the work area on the - // city screen. This check is redundant and could be removed always, but only do so if work area is expanded. - set_nopification (cfg->city_work_radius > 2, ADDR_REDUNDANT_CHECK_ON_WORK_AREA_HOVER, 6); - - // Skip redundant check of clicked tile's neighbor index in City_Form::handle_left_click. - WITH_MEM_PROTECTION (ADDR_CITY_FORM_LEFT_CLICK_JUMP, 1, PAGE_EXECUTE_READWRITE) { - *ADDR_CITY_FORM_LEFT_CLICK_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) - } - - // Skip check that neighbor index passed to City::controls_tile is within work radius. This check is now implemented in the patch func. - WITH_MEM_PROTECTION (ADDR_CONTROLS_TILE_JUMP, 1, PAGE_EXECUTE_READWRITE) { - *ADDR_CONTROLS_TILE_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) - } - - // When searching for a tile on which to spawn pollution, the game wraps its search around by using remainder after division. Here, we replace - // the dividend to match a potentially expanded city work area. - WITH_MEM_PROTECTION (ADDR_SPAWN_POLLUTION_MOD, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_SPAWN_POLLUTION_MOD, is->workable_tile_count - 1); - } - - WITH_MEM_PROTECTION (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, cfg->patch_premature_truncation_of_found_paths ? 2560 : 256); - } - - int * trade_net_addrs; - bool already_moved_trade_net = is->trade_net != p_original_trade_net, - want_moved_trade_net = cfg->city_limit > 512; - int lifted_city_limit_exp = 11; - int lifted_city_limit = 1 << lifted_city_limit_exp; - if ((! at_program_start) && - ((trade_net_addrs = load_trade_net_addrs ()) != NULL) && - ((already_moved_trade_net && ! want_moved_trade_net) || (want_moved_trade_net && ! already_moved_trade_net))) { - // Allocate a new trade net object if necessary. To construct it, all we have to do is zero a few fields and set the vptr. Otherwise, - // set the allocated object aside for deletion later. Also set new & old addresses to the locations we're moving to & from. - Trade_Net * to_free = NULL; - int p_old, p_new; - if (want_moved_trade_net) { - is->trade_net = calloc (1, (sizeof (Trade_Net)) - (4 * 512 * 512) + (4 * lifted_city_limit * lifted_city_limit)); - is->city_limit = lifted_city_limit; - is->trade_net->vtable = p_original_trade_net->vtable; - p_old = (int)p_original_trade_net; - p_new = (int)is->trade_net; - } else { - to_free = is->trade_net; - is->city_limit = 512; - p_old = (int)is->trade_net; - p_new = (int)p_original_trade_net; - is->trade_net = p_original_trade_net; - } - already_moved_trade_net = is->trade_net != p_original_trade_net; // Keep this variable up to date - - // Patch all references from the "old" object to the "new" one - int offset; - bool popped_up_error = false; - char err_msg[200] = {0}; - int * refs; { - if (exe_version_index == 0) - refs = trade_net_addrs; - else if (exe_version_index == 1) // Steam version, skip refs and instructions for GOG - refs = &trade_net_addrs[TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; - else // PCGames.de version, skip two sets of refs and instrs for GOG & Steam - refs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; - } - for (int n_ref = 0; n_ref < TRADE_NET_REF_COUNT; n_ref++) { - int addr = refs[n_ref]; - WITH_MEM_PROTECTION ((void *)(addr - 10), 20, PAGE_EXECUTE_READWRITE) { - byte * instr = (byte *)addr; - if ((instr[0] == 0xB9) && (int_from_bytes (&instr[1]) == p_old)) // move trade net ptr to ecx - int_to_bytes (&instr[1], p_new); - else if ((instr[0] == 0xC7) && (instr[1] == 0x05) && (int_from_bytes (&instr[2]) == p_old)) // write trade net vtable ptr - int_to_bytes (&instr[2], p_new); - else if ((instr[0] == 0x81) && (instr[1] == 0xFE) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp esi, trade net location - ; // Do not patch this location because it's the upper limit for a memcpy - else if ((instr[0] == 0x81) && (instr[1] == 0xFF) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp edi, trade net location - ; // Same - else if ((instr[0] == 0x81) && (instr[1] == 0xFA) && (int_from_bytes (&instr[2]) == (int)&p_original_trade_net->Data2)) // cmp edx, trade net data2 location - ; // Same - else if (((instr[0] == 0xA3) || (instr[0] == 0xA1)) && // move eax to field or vice-versa - (offset = int_from_bytes (&instr[1]) - p_old, (offset >= 0) && (offset < 100))) - int_to_bytes (&instr[1], p_new + offset); - else if ((instr[0] == 0x89) && ((instr[1] >= 0x0D) && (instr[1] <= 0x3D)) && // move other regs to field - (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) - int_to_bytes (&instr[2], p_new + offset); - else if ((instr[0] == 0x8B) && ((instr[1] == 0x35) || (instr[1] == 0x3D) || (instr[1] == 0x0D)) && // mov field to esi, edi or ecx - (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) - int_to_bytes (&instr[2], p_new + offset); - else if (! popped_up_error) { - snprintf (err_msg, (sizeof err_msg) - 1, "Can't move trade net object from address 0x%x. Pattern doesn't match.", addr); - MessageBox (NULL, err_msg, NULL, MB_ICONERROR); - popped_up_error = true; - } - } - } - - // Patch all instructions that involve the stride of Trade_Net.Matrix - int * addrs, addr_count; { - if (exe_version_index == 0) { - addrs = &trade_net_addrs[TRADE_NET_REF_COUNT]; - addr_count = TRADE_NET_INSTR_COUNT_GOG; - } else if (exe_version_index == 1) { - addrs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; - addr_count = TRADE_NET_INSTR_COUNT_STEAM; - } else { - addrs = &trade_net_addrs[3 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; - addr_count = TRADE_NET_INSTR_COUNT_GOG; - } - for (int n = 0; n < addr_count; n++) { - byte * instr = (byte *)addrs[n]; - WITH_MEM_PROTECTION (instr, 10, PAGE_EXECUTE_READWRITE) { - if (! want_moved_trade_net) - restore_code_area (instr); - - else { - if ((instr[0] == 0xC1) && (instr[1] >= 0xE0) && (instr[1] <= 0xE7)) { // shl - save_code_area (instr, 3, false); - // shift amount is either 9 (1<<9 == 512) or 11 (1<<11 == 4*512, stride in bytes) - // in the second case, replace with lifted_exp + 2 to convert to bytes - instr[2] = lifted_city_limit_exp + ((instr[2] == 11) ? 2 : 0); - - } else if ((instr[0] == 0x81) && (instr[1] >= 0xC0) && (instr[1] <= 0xC7)) { // add - save_code_area (instr, 6, false); - int amount = int_from_bytes (&instr[2]); - // amount is either 512 or 4*512, replace with lifted_lim or 4*lifted_lim - int_to_bytes (&instr[2], (amount == 512) ? lifted_city_limit : 4*lifted_city_limit); - - } else if ((instr[0] == 0x8D) && (instr[1] == 0x9C) && (instr[2] == 0x90)) { // lea - save_code_area (instr, 7, false); - int offset = 4 * lifted_city_limit + 0x38; // stride in bytes plus 0x38 offset to Matrix in Trade_Net object - int_to_bytes (&instr[3], offset); - - } else if (instr[0] == 0xB9) { // mov - save_code_area (instr, 5, false); - int_to_bytes (&instr[1], lifted_city_limit * lifted_city_limit); - - } else if (! popped_up_error) { - snprintf (err_msg, (sizeof err_msg) - 1, "Can't patch matrix stride at address 0x%x. Pattern doesn't match.", (int)instr); - MessageBox (NULL, err_msg, NULL, MB_ICONERROR); - popped_up_error = true; - } - } - } - } - } - - // Reallocate diplo_form->tradable_cities array so it matches the city limit - civ_prog_free (p_diplo_form->tradable_cities); - int tradable_cities_len = want_moved_trade_net ? lifted_city_limit : 512, - tradable_cities_size = tradable_cities_len * sizeof (TradableItem); - p_diplo_form->tradable_cities = new (tradable_cities_size); - for (int n = 0; n < tradable_cities_len; n++) - p_diplo_form->tradable_cities[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 - - // Patch the size limit on some code that clears the tradable cities array when starting a new game - WITH_MEM_PROTECTION (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, tradable_cities_size); - } - - if (to_free) { - to_free->vtable->destruct (to_free, __, 0); - free (to_free); - } - } - - // Set is->city_limit and patch two instructions that contain the limit - is->city_limit = clamp (0, already_moved_trade_net ? lifted_city_limit : 512, cfg->city_limit); - WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN, 6, PAGE_EXECUTE_READWRITE) { - int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN[2], is->city_limit); - } - WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CREATE_CITY, 5, PAGE_EXECUTE_READWRITE) { - int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CREATE_CITY[1], is->city_limit); - } - WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_CITY_ID, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_MAX_TRADABLE_CITY_ID, already_moved_trade_net ? lifted_city_limit : 512); - } - - WITH_MEM_PROTECTION (ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR, 6, PAGE_EXECUTE_READWRITE) { - byte * instr = ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR; - if (cfg->years_to_double_building_culture == 1000) - restore_code_area (instr); - else { - if (instr[0] == 0x3D) { // in GOG and PCG EXEs, instr is cmp eax, 0x3E8 - save_code_area (instr, 5, false); - int_to_bytes (&instr[1], cfg->years_to_double_building_culture); - } else if (instr[0] == 0x3B) { // in Steam EXE, instr is cmp eax, dword ptr 0x688C9C - save_code_area (instr, 6, true); - instr[0] = 0x3D; - int_to_bytes (&instr[1], cfg->years_to_double_building_culture); - } - } - } - - WITH_MEM_PROTECTION (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, PAGE_EXECUTE_READWRITE) { - if (cfg->accentuate_cities_on_minimap) { - save_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, false); - emit_branch (BK_JUMP, ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL); - } else - restore_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT); - } - WITH_MEM_PROTECTION (ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { - byte * code = ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL; - code[0] = 0x55; code[1] = 0x53; // write push ebp and push ebx, two overwritten instrs before the call - emit_branch (BK_CALL, &code[2], &patch_get_pixel_to_draw_city_dot); // call patch func - emit_branch (BK_JUMP, &code[7], ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT + 5); // jump back to original code - } - - // Bypass adjacent resource of different type check - // replacing 0x7D (= jge) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9 = cfg->allow_adjacent_resources_of_different_types ? 0xEB : 0x7D; - - WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, PAGE_EXECUTE_READWRITE) { - if (cfg->tiles_per_non_luxury_resource == 32) - restore_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV); - else { - save_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, true); - - // Jump to replacement division logic, kept in an inlead because it doesn't fit in 7 bytes - emit_branch (BK_JUMP, ADDR_RESOURCE_GEN_TILE_COUNT_DIV, ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL); - - // Fill in the replacement division logic. Instead of computing tile_count>>5, compute tile_count/cfg->tiles_per_non_luxury_resource. - WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { - int d = not_below (1, cfg->tiles_per_non_luxury_resource); - byte d0 = d & 0xFF, - d1 = (d >> 8) & 0xFF, - d2 = (d >> 16) & 0xFF, - d3 = d >> 24; - - byte * cursor = ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL; - - // In the Steam EXE, the limit (tile_count/32 by default) must be left in ecx. For the other EXEs, edx. - if (exe_version_index == 1) { - byte new_div[] = { - 0x50, // push eax - 0x52, // push edx - 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count - 0x0F, 0xB7, 0xD2, // movzx edx, dx - 0x89, 0xD0, // mov eax, edx - 0x31, 0xD2, // xor edx, edx - 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} - 0xF7, 0xF1, // div ecx - 0x89, 0xC1, // mov ecx, eax - 0x5A, // pop edx - 0x58 // pop eax - }; - for (int n = 0; n < ARRAY_LEN (new_div); n++) - *cursor++ = new_div[n]; - - } else { - byte new_div[] = { - 0x50, // push eax - 0x51, // push ecx - 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count - 0x0F, 0xB7, 0xD2, // movzx edx, dx - 0x89, 0xD0, // mov eax, edx - 0x31, 0xD2, // xor edx, edx - 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} - 0xF7, 0xF1, // div ecx - 0x89, 0xC2, // mov edx, eax - 0x59, // pop ecx - 0x58 // pop eax - }; - for (int n = 0; n < ARRAY_LEN (new_div); n++) - *cursor++ = new_div[n]; - } - - cursor = emit_branch (BK_JUMP, cursor, ADDR_RESOURCE_GEN_TILE_COUNT_DIV + 7); - } - } - } - - // Disable a jump that skips playing victory animations for air units if they've been configured to have a victory anim - set_nopification (cfg->aircraft_victory_animation != NULL, ADDR_SKIP_VICTORY_ANIM_IF_AIR, 6); - - // Bypass capital check to return zero corruption - // replacing 0x75 (= jnz) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_CORRUPTION_CAPITAL_CHECK, 1, PAGE_EXECUTE_READWRITE) - *ADDR_CORRUPTION_CAPITAL_CHECK = cfg->allow_corruption_in_capital ? 0xEB : 0x75; - - // Insert amount added to building decorruption effect just for the capital - WITH_MEM_PROTECTION (ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT, 3, PAGE_EXECUTE_READWRITE) - *(ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT + 2) = clamp (0, 100, cfg->special_capital_decorruption_effect); -} - -void -get_mod_art_path (char const * file_name, char * out_path, int path_buf_size) -{ - char s[1000]; - snprintf (s, sizeof s, "Art\\%s", file_name); - s[(sizeof s) - 1] = '\0'; - - char * scenario_path = BIC_get_asset_path (p_bic_data, __, s, false); - if (0 != strcmp (scenario_path, s)) // get_asset_path returns its input when the file is not found - snprintf (out_path, path_buf_size, "%s", scenario_path); - else - snprintf (out_path, path_buf_size, "%s\\Art\\%s", is->mod_rel_dir, file_name); - out_path[path_buf_size - 1] = '\0'; -} - - -Sprite* -SpriteList_at(SpriteList *list, int i) { - return &list->field_0[i]; -} - -void -set_path(String260 *dst, const char *p) { - snprintf(dst->S, sizeof(dst->S), "%s", p); -} - -void -slice_grid(Sprite *out, PCX_Image *img, - int tile_w, int tile_h, int full_w, int full_h) -{ - for (int y = 0; y < full_h; y += tile_h) - for (int x = 0; x < full_w; x += tile_w) - Sprite_slice_pcx(out++, __, img, x, y, tile_w, tile_h, 1, 1); -} - -void -slice_grid_into_list(SpriteList *bucket, PCX_Image *img, - int tile_w, int tile_h, int full_w, int full_h) -{ - int k = 0; - for (int y = 0; y < full_h; y += tile_h) - for (int x = 0; x < full_w; x += tile_w) - Sprite_slice_pcx(SpriteList_at(bucket, k++), __, img, x, y, tile_w, tile_h, 1, 1); -} - -void -join_path(char *out, size_t out_sz, const char *dir, const char *file) -{ - size_t n = strlen(dir); - int need_sep = (n > 0 && dir[n-1] != '/' && dir[n-1] != '\\'); - snprintf(out, out_sz, "%s%s%s", dir, need_sep ? "\\" : "", file); -} - -void -read_in_dir(PCX_Image *img, - const char *art_dir, - const char *filename, - String260 *store) { - char pbuf[512]; - join_path(pbuf, sizeof pbuf, art_dir, filename); - if (store) { - // assumes: typedef struct { char S[260]; } String260; - snprintf(store->S, sizeof store->S, "%s", pbuf); - } - - char temp_path[2*MAX_PATH]; - - snprintf(temp_path, sizeof temp_path, "%s\\%s", art_dir, filename); - PCX_Image_read_file(img, __, temp_path, NULL, 0, 0x100, 2); -} - -bool load_day_night_hour_images(struct day_night_cycle_img_set *this, const char *art_dir, const char *hour) -{ - char ss[200]; - PCX_Image img; - PCX_Image_construct(&img); - - // Std terrain (9 sheets): 6x9 of 128x64 over 0x480x0x240 - const char *STD_SHEETS[9] = { - "xtgc.pcx", "xpgc.pcx", "xdgc.pcx", "xdpc.pcx", "xdgp.pcx", "xggc.pcx", - "wCSO.pcx", "wSSS.pcx", "wOOO.pcx" - }; - for (int i = 0; i < 9; ++i) { - read_in_dir(&img, art_dir, STD_SHEETS[i], NULL); - if (img.JGL.Image == NULL) return false; - slice_grid_into_list(&this->Std_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); - } - - // LM terrain (9): same slicing - const char *LMT_SHEETS[9] = { - "lxtgc.pcx", "lxpgc.pcx", "lxdgc.pcx", "lxdpc.pcx", "lxdgp.pcx", "lxggc.pcx", - "lwCSO.pcx", "lwSSS.pcx", "lwOOO.pcx" - }; - for (int i = 0; i < 9; ++i) { - read_in_dir(&img, art_dir, LMT_SHEETS[i], NULL); - if (img.JGL.Image == NULL) return false; - slice_grid_into_list(&this->LM_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); - } - - // Polar icecaps: 8x4 of 128x64 - read_in_dir(&img, art_dir, "polarICEcaps-final.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Polar_Icecaps_Images, &img, 0x80, 0x40, 0x400, 0x100); - - // Hills / LM Hills: 4x3 of 128x72 - read_in_dir(&img, art_dir, "xhills.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); - read_in_dir(&img, art_dir, "hill forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Hills_Forests_Images, &img, 0x80, 0x48, 0x200, 0x120); - read_in_dir(&img, art_dir, "hill jungle.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Hills_Jungle_Images, &img, 0x80, 0x48, 0x200, 0x120); - read_in_dir(&img, art_dir, "LMHills.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->LM_Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); - - // Flood plains: 4x4 of 128x64 - read_in_dir(&img, art_dir, "floodplains.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Flood_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); - - // Delta + Mountain rivers: 4x4 each, interleaved across one contiguous block - { - const char *RIV_SHEETS[2] = { "deltaRivers.pcx", "mtnRivers.pcx" }; - Sprite *contig = this->Delta_Rivers_Images; // Mountain_Rivers_Images follows - for (int s = 0; s < 2; ++s) { - read_in_dir(&img, art_dir, RIV_SHEETS[s], NULL); - if (img.JGL.Image == NULL) return false; - Sprite *p = contig + s; // even=delta, odd=mountain - for (int y = 0; y < 0x100; y += 0x40) - for (int x = 0; x < 0x200; x += 0x80) { - Sprite_slice_pcx(p, __, &img, x, y, 0x80, 0x40, 1, 1); - p += 2; - } - } - } - - // Waterfalls: 4x1 of 128x64 - read_in_dir(&img, art_dir, "waterfalls.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Waterfalls_Images, &img, 0x80, 0x40, 0x200, 0x40); - - // Irrigation (desert/plains/normal/tundra): each 4x4 of 128x64 - read_in_dir(&img, art_dir, "irrigation DESETT.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Desert_Images, &img, 0x80, 0x40, 0x200, 0x100); - read_in_dir(&img, art_dir, "irrigation PLAINS.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); - read_in_dir(&img, art_dir, "irrigation.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Images, &img, 0x80, 0x40, 0x200, 0x100); - read_in_dir(&img, art_dir, "irrigation TUNDRA.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Tundra_Images, &img, 0x80, 0x40, 0x200, 0x100); - - // Volcanos (plain/forests/jungles/snow): 4x4 of 128x88 - read_in_dir(&img, art_dir, "Volcanos.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Volcanos forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Volcanos jungles.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Volcanos-snow.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); - - // Marsh: Large band then Small band (tiles 128x88) - read_in_dir(&img, art_dir, "marsh.pcx", NULL); - if (img.JGL.Image == NULL) return false; - // Large (2 rows, 4 cols) - { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Marsh_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - // Small (2 rows, 5 cols) - { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Marsh_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - // LM mountains + standard mountains (plain/forests/jungles/snow): 4x4 of 128x88 - read_in_dir(&img, art_dir, "LMMountains.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->LM_Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Mountains.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "mountain forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "mountain jungles.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Mountains-snow.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); - - // Roads (16x16) and Railroads (16x17), tiles 128x64 - read_in_dir(&img, art_dir, "roads.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Roads_Images, &img, 0x80, 0x40, 0x800, 0x400); - read_in_dir(&img, art_dir, "railroads.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Railroads_Images, &img, 0x80, 0x40, 0x800, 0x440); - - // LM Forests (Large 2x4, Small 2x6, Pines 2x6), tiles 128x88 - read_in_dir(&img, art_dir, "LMForests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->LM_Forests_Large_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->LM_Forests_Small_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->LM_Forests_Pines_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - // Grassland/Plains/Tundra forests & jungles (bands; tiles 128x88) — order is important - read_in_dir(&img, art_dir, "grassland forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - // Jungles Large, Small - { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Jungles_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Jungles_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - // Forests Large, Small, Pines - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - read_in_dir(&img, art_dir, "plains forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Plains_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Plains_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Plains_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - read_in_dir(&img, art_dir, "tundra forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Tundra_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Tundra_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Tundra_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - // LM Terrain (7 single 128x64, vertical strip) - read_in_dir(&img, art_dir, "landmark_terrain.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i = 0, y = 0; i < 7; ++i, y += 0x40) - Sprite_slice_pcx(&this->LM_Terrain[i], __, &img, 0, y, 0x80, 0x40, 1, 1); - - // TNT (same odd ordering as original) - read_in_dir(&img, art_dir, "tnt.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[6+i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[9+i], __, &img, x, 0x40, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[12+i], __, &img, x, 0x80, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[0+i], __, &img, x, 0xC0, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[15+i], __, &img, x, 0x100, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[3+i], __, &img, x, 0x140, 0x80, 0x40, 1, 1); - - // Goody huts: 8 tiles, x=(i%3)*0x80, y=(i/3)*0x40 - read_in_dir(&img, art_dir, "goodyhuts.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i = 0; i < 8; ++i) { - int x = (i % 3) << 7; - int y = (i / 3) << 6; - Sprite_slice_pcx(&this->Goody_Huts_Images[i], __, &img, x, y, 0x80, 0x40, 1, 1); - } - - // Terrain buildings (fortress/camp/barbarian camp/mines/barricade) - read_in_dir(&img, art_dir, "TerrainBuildings.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Fortress[i], __, &img, 0x00, y, 0x80, 0x40, 1, 1); - for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Camp[i], __, &img, 0x80, y, 0x80, 0x40, 1, 1); - Sprite_slice_pcx(&this->Terrain_Buldings_Barbarian_Camp, __, &img, 0x100, 0x00, 0x80, 0x40, 1, 1); - Sprite_slice_pcx(&this->Terrain_Buldings_Mines, __, &img, 0x100, 0x40, 0x80, 0x40, 1, 1); - for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Barricade[i], __, &img, 0x180, y, 0x80, 0x40, 1, 1); - - // Pollution & Craters (5x5 of 128x64) - read_in_dir(&img, art_dir, "pollution.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Pollution, &img, 0x80, 0x40, 0x280, 0x140); - read_in_dir(&img, art_dir, "craters.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Craters, &img, 0x80, 0x40, 0x280, 0x140); - - // Airfields / Outposts / Radar - read_in_dir(&img, art_dir, "x_airfields and detect.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i=0, x=0; i<2; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Airfields[i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Outposts[i], __, &img, x, 0x40, 0x80, 0x80, 1, 1); - Sprite_slice_pcx(&this->Terrain_Buldings_Radar, __, &img, 0x00, 0xC0, 0x80, 0x80, 1, 1); - - // Victory (single 128x64) - read_in_dir(&img, art_dir, "x_victory.pcx", NULL); - if (img.JGL.Image == NULL) return false; - Sprite_slice_pcx(&this->Victory_Image, __, &img, 0, 0, 0x80, 0x40, 1, 1); - - // Resources - read_in_dir(&img, art_dir, "resources.pcx", NULL); - if (img.JGL.Image == NULL) return false; - size_t k = 0; - for (int r = 0, y = 1; r < 6; ++r, y += 50) { - for (int c = 0, x = 1; c < 6; ++c, x += 50) { - Sprite_slice_pcx(&this->Resources[k++], __, &img, x, y, 49, 49, 1, 1); - } - } - - // Base cities - static const char *CITY_BASE[5] = { - "rAMER.pcx", "rEURO.pcx", "rROMAN.pcx", "rMIDEAST.pcx", "rASIAN.pcx" - }; - for (int culture = 0; culture < 5; culture++) { - read_in_dir(&img, art_dir, CITY_BASE[culture], NULL); - if (img.JGL.Image == NULL) return false; - int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; - int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; - int y = 0; - for (int era = 0; era < 4; ++era, y += sprite_h) { - int x = 0; - for (int size = 0; size < 3; ++size, x += sprite_w) { - const int idx = culture + 5*era + 20*size; - Sprite_slice_pcx(&this->City_Images[idx], __, &img, x, y, sprite_w, sprite_h, 1, 1); - } - } - } - - // Walled cities - static const char *CITY_WALL[5] = { - "AMERWALL.pcx", "EUROWALL.pcx", "ROMANWALL.pcx", "MIDEASTWALL.pcx", "ASIANWALL.pcx" - }; - for (int culture = 0; culture < 5; ++culture) { - read_in_dir(&img, art_dir, CITY_WALL[culture], NULL); - if (img.JGL.Image == NULL) return false; - int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image); - int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; - int y = 0; - for (int era = 0; era < 4; ++era, y += sprite_h) { - const int size = 3; // walled towns are a special category - const int idx = culture + 5*era + 20*size; - Sprite_slice_pcx(&this->City_Images[idx], __, &img, 0, y, sprite_w, sprite_h, 1, 1); - } - } - - // Destroyed cities - read_in_dir(&img, art_dir, "DESTROY.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { - int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; - int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image); - int x = 0; - for (int i = 0; i < 3; ++i, x += sprite_w) - Sprite_slice_pcx(&this->Destroyed_City_Images[i], __, &img, x, 0, sprite_w, sprite_h, 1, 1); - } - - // Districts (if enabled) - if (is->current_config.enable_districts) { - char art_dir[200]; - char temp_path[2*MAX_PATH]; - snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - for (int dc = 0; dc < is->district_count; dc++) { - struct district_config const * cfg = &is->district_configs[dc]; - int variant_capacity = ARRAY_LEN (this->District_Images[dc]); - int variant_count = cfg->img_path_count; - if (variant_count <= 0) - continue; - if (variant_count > variant_capacity) - variant_count = variant_capacity; - - int era_count = cfg->vary_img_by_era ? 4 : 1; - int column_count = cfg->img_column_count; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - - for (int variant_i = 0; variant_i < variant_count; variant_i++) { - const char * img_path = cfg->img_paths[variant_i]; - if ((img_path == NULL) || (img_path[0] == '\0')) - continue; - - read_in_dir (&img, temp_path, img_path, NULL); - if (img.JGL.Image == NULL) - return false; - - for (int era = 0; era < era_count; era++) { - for (int col = 0; col < column_count; col++) { - int tile_x = sprite_width * col; - int tile_y = sprite_height * era; - Sprite_slice_pcx (&this->District_Images[dc][variant_i][era][col], __, &img, tile_x, tile_y, sprite_width, sprite_height, 1, 1); - } - } - } - } - - // Abandoned district art (land + maritime) for this hour - read_in_dir (&img, temp_path, "Abandoned.pcx", NULL); - if (img.JGL.Image == NULL) - return false; - Sprite_slice_pcx (&this->Abandoned_District_Image, __, &img, 0, 0, 128, 64, 1, 1); - Sprite_slice_pcx (&this->Abandoned_Maritime_District_Image, __, &img, 128, 0, 128, 64, 1, 1); - - // Load wonder district images (dynamically per wonder) for this hour - if (is->current_config.enable_wonder_districts) { - char const * last_img_path = NULL; - PCX_Image wpcx; - PCX_Image_construct (&wpcx); - bool pcx_loaded = false; - - for (int wi = 0; wi < is->wonder_district_count; wi++) { - struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; - char const * img_path = cfg->img_path; - if (img_path == NULL) - img_path = "Wonders.pcx"; - - // Load new image file if different from previous - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - - read_in_dir (&wpcx, temp_path, img_path, NULL); - - if (wpcx.JGL.Image == NULL) { - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - struct wonder_district_image_set * set = &this->Wonder_District_Images[wi]; - - Sprite_construct (&set->img); - int x = 128 * cfg->img_column; - int y = 64 * cfg->img_row; - Sprite_slice_pcx (&set->img, __, &wpcx, x, y, 128, 64, 1, 1); - - Sprite_construct (&set->construct_img); - int cx = 128 * cfg->img_construct_column; - int cy = 64 * cfg->img_construct_row; - Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, 128, 64, 1, 1); - - if (cfg->enable_img_alt_dir) { - Sprite_construct (&set->alt_dir_img); - int ax = 128 * cfg->img_alt_dir_column; - int ay = 64 * cfg->img_alt_dir_row; - Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, 128, 64, 1, 1); - - Sprite_construct (&set->alt_dir_construct_img); - int acx = 128 * cfg->img_alt_dir_construct_column; - int acy = 64 * cfg->img_alt_dir_construct_row; - Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, 128, 64, 1, 1); - } - } - - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - wpcx.vtable->destruct (&wpcx, __, 0); - } - - } - - if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { - char art_dir[200]; - char temp_path[2*MAX_PATH]; - snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - - char const * last_img_path = NULL; - PCX_Image nwpcx; - PCX_Image_construct (&nwpcx); - bool pcx_loaded = false; - - for (int ni = 0; ni < is->natural_wonder_count; ni++) { - struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; - if ((cfg->img_path == NULL) || (cfg->img_path[0] == '\0')) - continue; - - char const * img_path = cfg->img_path; - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - - read_in_dir (&nwpcx, temp_path, img_path, NULL); - - if (nwpcx.JGL.Image == NULL) { - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - Sprite_construct (&this->Natural_Wonder_Images[ni].img); - int x = 128 * cfg->img_column; - int y = 88 * cfg->img_row; - Sprite_slice_pcx (&this->Natural_Wonder_Images[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); - } - - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - nwpcx.vtable->destruct (&nwpcx, __, 0); - } - - img.vtable->destruct (&img, __, 0); - - return true; -} - -Sprite * -get_sprite_proxy_for_current_hour(Sprite *s) { - int v; - int hour = is->current_day_night_cycle; // 0..23 - if (itable_look_up(&is->day_night_sprite_proxy_by_hour[hour], (int)s, &v)) - return (Sprite *)v; - return NULL; // not proxied, fall back to s -} - -void -insert_spritelist_proxies(SpriteList *ss, SpriteList *ps, int hour, int len1, int len2) { - for (int i = 0; i < len1; i++) { - for (int j = 0; j < len2; j++) { - Sprite *s = &ss[i].field_0[j]; - Sprite *p = &ps[i].field_0[j]; - if (s && p) { - itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); - } - } - } -} - -void -insert_sprite_proxies(Sprite *ss, Sprite *ps, int hour, int len) { - for (int i = 0; i < len; i++) { - Sprite *s = &ss[i]; - Sprite *p = &ps[i]; - if (s && p) { - itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); - } - } -} - -void -insert_sprite_proxy(Sprite *s, Sprite *p, int hour) { - if (s && p) { - itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); - } -} - -void -build_sprite_proxies_24(Map_Renderer *mr) { - for (int h = 0; h < 24; ++h) { - insert_sprite_proxies(city_sprites, is->day_night_cycle_imgs[h].City_Images, h, 80); - insert_sprite_proxies(destroyed_city_sprites, is->day_night_cycle_imgs[h].Destroyed_City_Images, h, 3); - insert_sprite_proxies(mr->Resources, is->day_night_cycle_imgs[h].Resources, h, 36); - insert_spritelist_proxies(mr->Std_Terrain_Images, is->day_night_cycle_imgs[h].Std_Terrain_Images, h, 9, 81); - insert_spritelist_proxies(mr->LM_Terrain_Images, is->day_night_cycle_imgs[h].LM_Terrain_Images, h, 9, 81); - insert_sprite_proxy(&mr->Terrain_Buldings_Barbarian_Camp, &is->day_night_cycle_imgs[h].Terrain_Buldings_Barbarian_Camp, h); - insert_sprite_proxy(&mr->Terrain_Buldings_Mines, &is->day_night_cycle_imgs[h].Terrain_Buldings_Mines, h); - insert_sprite_proxy(&mr->Victory_Image, &is->day_night_cycle_imgs[h].Victory_Image, h); - insert_sprite_proxy(&mr->Terrain_Buldings_Radar, &is->day_night_cycle_imgs[h].Terrain_Buldings_Radar, h); - insert_sprite_proxies(mr->Flood_Plains_Images, is->day_night_cycle_imgs[h].Flood_Plains_Images, h, 16); - insert_sprite_proxies(mr->Polar_Icecaps_Images, is->day_night_cycle_imgs[h].Polar_Icecaps_Images, h, 32); - insert_sprite_proxies(mr->Roads_Images, is->day_night_cycle_imgs[h].Roads_Images, h, 256); - insert_sprite_proxies(mr->Railroads_Images, is->day_night_cycle_imgs[h].Railroads_Images, h, 272); - insert_sprite_proxies(mr->Terrain_Buldings_Airfields, is->day_night_cycle_imgs[h].Terrain_Buldings_Airfields, h, 2); - insert_sprite_proxies(mr->Terrain_Buldings_Camp, is->day_night_cycle_imgs[h].Terrain_Buldings_Camp, h, 4); - insert_sprite_proxies(mr->Terrain_Buldings_Fortress, is->day_night_cycle_imgs[h].Terrain_Buldings_Fortress, h, 4); - insert_sprite_proxies(mr->Terrain_Buldings_Barricade, is->day_night_cycle_imgs[h].Terrain_Buldings_Barricade, h, 4); - insert_sprite_proxies(mr->Goody_Huts_Images, is->day_night_cycle_imgs[h].Goody_Huts_Images, h, 8); - insert_sprite_proxies(mr->Terrain_Buldings_Outposts, is->day_night_cycle_imgs[h].Terrain_Buldings_Outposts, h, 3); - insert_sprite_proxies(mr->Pollution, is->day_night_cycle_imgs[h].Pollution, h, 25); - insert_sprite_proxies(mr->Craters, is->day_night_cycle_imgs[h].Craters, h, 25); - insert_sprite_proxies(mr->Tnt_Images, is->day_night_cycle_imgs[h].Tnt_Images, h, 18); - insert_sprite_proxies(mr->Waterfalls_Images, is->day_night_cycle_imgs[h].Waterfalls_Images, h, 4); - insert_sprite_proxies(mr->LM_Terrain, is->day_night_cycle_imgs[h].LM_Terrain, h, 7); - insert_sprite_proxies(mr->Marsh_Large, is->day_night_cycle_imgs[h].Marsh_Large, h, 8); - insert_sprite_proxies(mr->Marsh_Small, is->day_night_cycle_imgs[h].Marsh_Small, h, 10); - insert_sprite_proxies(mr->Volcanos_Images, is->day_night_cycle_imgs[h].Volcanos_Images, h, 16); - insert_sprite_proxies(mr->Volcanos_Forests_Images, is->day_night_cycle_imgs[h].Volcanos_Forests_Images, h, 16); - insert_sprite_proxies(mr->Volcanos_Jungles_Images, is->day_night_cycle_imgs[h].Volcanos_Jungles_Images, h, 16); - insert_sprite_proxies(mr->Volcanos_Snow_Images, is->day_night_cycle_imgs[h].Volcanos_Snow_Images, h, 16); - insert_sprite_proxies(mr->Grassland_Forests_Large, is->day_night_cycle_imgs[h].Grassland_Forests_Large, h, 8); - insert_sprite_proxies(mr->Plains_Forests_Large, is->day_night_cycle_imgs[h].Plains_Forests_Large, h, 8); - insert_sprite_proxies(mr->Tundra_Forests_Large, is->day_night_cycle_imgs[h].Tundra_Forests_Large, h, 8); - insert_sprite_proxies(mr->Grassland_Forests_Small, is->day_night_cycle_imgs[h].Grassland_Forests_Small, h, 10); - insert_sprite_proxies(mr->Plains_Forests_Small, is->day_night_cycle_imgs[h].Plains_Forests_Small, h, 10); - insert_sprite_proxies(mr->Tundra_Forests_Small, is->day_night_cycle_imgs[h].Tundra_Forests_Small, h, 10); - insert_sprite_proxies(mr->Grassland_Forests_Pines, is->day_night_cycle_imgs[h].Grassland_Forests_Pines, h, 12); - insert_sprite_proxies(mr->Plains_Forests_Pines, is->day_night_cycle_imgs[h].Plains_Forests_Pines, h, 12); - insert_sprite_proxies(mr->Tundra_Forests_Pines, is->day_night_cycle_imgs[h].Tundra_Forests_Pines, h, 12); - insert_sprite_proxies(mr->Irrigation_Desert_Images, is->day_night_cycle_imgs[h].Irrigation_Desert_Images, h, 16); - insert_sprite_proxies(mr->Irrigation_Plains_Images, is->day_night_cycle_imgs[h].Irrigation_Plains_Images, h, 16); - insert_sprite_proxies(mr->Irrigation_Images, is->day_night_cycle_imgs[h].Irrigation_Images, h, 16); - insert_sprite_proxies(mr->Irrigation_Tundra_Images, is->day_night_cycle_imgs[h].Irrigation_Tundra_Images, h, 16); - insert_sprite_proxies(mr->Grassland_Jungles_Large, is->day_night_cycle_imgs[h].Grassland_Jungles_Large, h, 8); - insert_sprite_proxies(mr->Grassland_Jungles_Small, is->day_night_cycle_imgs[h].Grassland_Jungles_Small, h, 12); - insert_sprite_proxies(mr->Mountains_Images, is->day_night_cycle_imgs[h].Mountains_Images, h, 16); - insert_sprite_proxies(mr->Mountains_Forests_Images, is->day_night_cycle_imgs[h].Mountains_Forests_Images, h, 16); - insert_sprite_proxies(mr->Mountains_Jungles_Images, is->day_night_cycle_imgs[h].Mountains_Jungles_Images, h, 16); - insert_sprite_proxies(mr->Mountains_Snow_Images, is->day_night_cycle_imgs[h].Mountains_Snow_Images, h, 16); - insert_sprite_proxies(mr->Hills_Images, is->day_night_cycle_imgs[h].Hills_Images, h, 16); - insert_sprite_proxies(mr->Hills_Forests_Images, is->day_night_cycle_imgs[h].Hills_Forests_Images, h, 16); - insert_sprite_proxies(mr->Hills_Jungle_Images, is->day_night_cycle_imgs[h].Hills_Jungle_Images, h, 16); - insert_sprite_proxies(mr->Delta_Rivers_Images, is->day_night_cycle_imgs[h].Delta_Rivers_Images, h, 16); - insert_sprite_proxies(mr->Mountain_Rivers_Images, is->day_night_cycle_imgs[h].Mountain_Rivers_Images, h, 16); - insert_sprite_proxies(mr->LM_Mountains_Images, is->day_night_cycle_imgs[h].LM_Mountains_Images, h, 16); - insert_sprite_proxies(mr->LM_Forests_Large_Images, is->day_night_cycle_imgs[h].LM_Forests_Large_Images, h, 8); - insert_sprite_proxies(mr->LM_Forests_Small_Images, is->day_night_cycle_imgs[h].LM_Forests_Small_Images, h, 10); - insert_sprite_proxies(mr->LM_Forests_Pines_Images, is->day_night_cycle_imgs[h].LM_Forests_Pines_Images, h, 12); - insert_sprite_proxies(mr->LM_Hills_Images, is->day_night_cycle_imgs[h].LM_Hills_Images, h, 16); - - if (is->current_config.enable_districts) { - for (int dc = 0; dc < is->district_count; dc++) { - struct district_config const * cfg = &is->district_configs[dc]; - int variant_capacity = ARRAY_LEN (is->district_img_sets[dc].imgs); - int variant_count = cfg->img_path_count; - if (variant_count <= 0) - continue; - if (variant_count > variant_capacity) - variant_count = variant_capacity; - - int era_count = cfg->vary_img_by_era ? 4 : 1; - int column_count = cfg->img_column_count; - - for (int variant_i = 0; variant_i < variant_count; variant_i++) { - if ((cfg->img_paths[variant_i] == NULL) || (cfg->img_paths[variant_i][0] == '\0')) - continue; - for (int era = 0; era < era_count; era++) { - for (int col = 0; col < column_count; col++) { - Sprite * base = &is->district_img_sets[dc].imgs[variant_i][era][col]; - Sprite * proxy = &is->day_night_cycle_imgs[h].District_Images[dc][variant_i][era][col]; - insert_sprite_proxy (base, proxy, h); - } - } - } - } - - insert_sprite_proxy (&is->abandoned_district_img, &is->day_night_cycle_imgs[h].Abandoned_District_Image, h); - insert_sprite_proxy (&is->abandoned_maritime_district_img, &is->day_night_cycle_imgs[h].Abandoned_Maritime_District_Image, h); - - // Wonder districts - if (is->current_config.enable_wonder_districts) { - for (int wi = 0; wi < is->wonder_district_count; wi++) { - Sprite * base_img = &is->wonder_district_img_sets[wi].img; - Sprite * proxy_img = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].img; - insert_sprite_proxy (base_img, proxy_img, h); - - Sprite * base_construct = &is->wonder_district_img_sets[wi].construct_img; - Sprite * proxy_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].construct_img; - insert_sprite_proxy (base_construct, proxy_construct, h); - - if (is->wonder_district_img_sets[wi].alt_dir_img.vtable != NULL) { - Sprite * base_alt = &is->wonder_district_img_sets[wi].alt_dir_img; - Sprite * proxy_alt = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_img; - insert_sprite_proxy (base_alt, proxy_alt, h); - } - - if (is->wonder_district_img_sets[wi].alt_dir_construct_img.vtable != NULL) { - Sprite * base_alt_construct = &is->wonder_district_img_sets[wi].alt_dir_construct_img; - Sprite * proxy_alt_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_construct_img; - insert_sprite_proxy (base_alt_construct, proxy_alt_construct, h); - } - } - } - } - - // Natural wonders - if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { - for (int ni = 0; ni < is->natural_wonder_count; ni++) { - Sprite * base_nw = &is->natural_wonder_img_sets[ni].img; - Sprite * proxy_nw = &is->day_night_cycle_imgs[h].Natural_Wonder_Images[ni].img; - insert_sprite_proxy (base_nw, proxy_nw, h); - } - } - } - is->day_night_cycle_img_proxies_indexed = true; -} - -void -init_day_night_images() -{ - if (is->day_night_cycle_img_state != IS_UNINITED) - return; - - const char *hour_strs[24] = { - "2400", "0100", "0200", "0300", "0400", "0500", "0600", "0700", - "0800", "0900", "1000", "1100", "1200", "1300", "1400", "1500", - "1600", "1700", "1800", "1900", "2000", "2100", "2200", "2300" - }; - - for (int i = 0; i < 24; i++) { - - char art_dir[200]; - char temp_path[2*MAX_PATH]; - snprintf (art_dir, sizeof art_dir, "DayNight/%s", hour_strs[i]); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - bool success = load_day_night_hour_images (&is->day_night_cycle_imgs[i], temp_path, hour_strs[i]); - - if (!success) { - char ss[200]; - snprintf(ss, sizeof ss, "Failed to load day/night cycle images for hour %s, reverting to base game art.", hour_strs[i]); - pop_up_in_game_error (ss); - - is->day_night_cycle_img_state = IS_INIT_FAILED; - return; - } - } - - Map_Renderer * mr = &p_bic_data->Map.Renderer; - build_sprite_proxies_24(mr); - - is->day_night_cycle_img_state = IS_OK; -} - -void -deindex_day_night_image_proxies() -{ - if (!is->day_night_cycle_img_proxies_indexed) - return; - - for (int i = 0; i < 24; i++) { - table_deinit (&is->day_night_sprite_proxy_by_hour[i]); - } - is->day_night_cycle_img_proxies_indexed = false; -} - -int -calculate_current_day_night_cycle_hour () -{ - int output = 12; // Default to noon - int increment = is->current_config.fixed_hours_per_turn_for_day_night_cycle; - - switch (is->current_config.day_night_cycle_mode) { - - // Disabled. This shouldn't be possible, but default to noon to be safe - case DNCM_OFF: - return output; - - // Time elapsed since last update - case DNCM_TIMER: { - LARGE_INTEGER perf_freq; - QueryPerformanceFrequency(&perf_freq); - - if (is->day_night_cycle_unstarted) { - is->current_day_night_cycle = output; - QueryPerformanceCounter(&is->last_day_night_cycle_update_time); - } - - LARGE_INTEGER time_now; - QueryPerformanceCounter(&time_now); - - double elapsed_seconds = - (double)(time_now.QuadPart - is->last_day_night_cycle_update_time.QuadPart) / - (double)perf_freq.QuadPart; - - if (elapsed_seconds > (double)is->current_config.elapsed_minutes_per_day_night_hour_transition * 60.0) { - output = is->current_day_night_cycle + increment; - is->last_day_night_cycle_update_time = time_now; - } else { - output = is->current_day_night_cycle; - } - break; - } - - // Match user's current time - case DNCM_USER_TIME: { - LPSYSTEMTIME lpSystemTime = (LPSYSTEMTIME)malloc(sizeof(SYSTEMTIME)); - GetLocalTime (lpSystemTime); - output = lpSystemTime->wHour; - free (lpSystemTime); - break; - } - - // Increment fixed amount each interturn - case DNCM_EVERY_TURN: { - if (is->day_night_cycle_unstarted) { - increment = 0; - is->current_day_night_cycle = output; - } - output = is->current_day_night_cycle + increment; - break; - } - - // Pin the hour to a specific value - case DNCM_SPECIFIED: { - output = is->current_config.pinned_hour_for_day_night_cycle; - break; - } - } - - // If midnight or over, restart at 0 or later - if (output > 23) output = output - 24; - - // Clamp to valid range of 0-23 in case of weird config values - output = clamp (0, 23, output); - is->day_night_cycle_unstarted = false; - - return output; -} - -void __fastcall -patch_Map_Renderer_load_images (Map_Renderer *this, int edx) -{ - Map_Renderer_load_images(this, __); - - // Initialize day/night cycle and re-calculate hour, if applicable - if (is->current_config.day_night_cycle_mode != DNCM_OFF) { - is->current_day_night_cycle = calculate_current_day_night_cycle_hour (); - - if (is->day_night_cycle_img_state == IS_UNINITED) { - init_day_night_images (); - } - - if (is->day_night_cycle_img_state == IS_OK) { - - // Sprite proxies are deindexed during each load event as sprite instances (really only Resources, which are reloaded) may change. - if (!is->day_night_cycle_img_proxies_indexed) { - build_sprite_proxies_24(this); - } - } - } -} - -void -patch_init_floating_point () -{ - init_floating_point (); - - // NOTE: At this point the program is done with the CRT initialization stuff and will start calling constructors for global - // objects as soon as this function returns. This is a good place to inject code that will run at program start. - - // Specify metadata about all boolean options on the mod config. We'll use this info to set up the table of offsets (for easy parsing) and to - // fill out the base config. - struct boolean_config_option { - char * name; - bool base_val; - int offset; - } boolean_config_options[] = { - {"enable_stack_bombard" , true , offsetof (struct c3x_config, enable_stack_bombard)}, - {"enable_disorder_warning" , true , offsetof (struct c3x_config, enable_disorder_warning)}, - {"allow_stealth_attack_against_single_unit" , false, offsetof (struct c3x_config, allow_stealth_attack_against_single_unit)}, - {"show_detailed_city_production_info" , true , offsetof (struct c3x_config, show_detailed_city_production_info)}, - {"limited_railroads_work_like_fast_roads" , false, offsetof (struct c3x_config, limited_railroads_work_like_fast_roads)}, - {"exclude_cities_from_units_per_tile_limit" , false, offsetof (struct c3x_config, exclude_cities_from_units_per_tile_limit)}, - {"enable_free_buildings_from_small_wonders" , true , offsetof (struct c3x_config, enable_free_buildings_from_small_wonders)}, - {"enable_stack_unit_commands" , true , offsetof (struct c3x_config, enable_stack_unit_commands)}, - {"skip_repeated_tile_improv_replacement_asks" , true , offsetof (struct c3x_config, skip_repeated_tile_improv_replacement_asks)}, - {"autofill_best_gold_amount_when_trading" , true , offsetof (struct c3x_config, autofill_best_gold_amount_when_trading)}, - {"disallow_founding_next_to_foreign_city" , true , offsetof (struct c3x_config, disallow_founding_next_to_foreign_city)}, - {"enable_trade_screen_scroll" , true , offsetof (struct c3x_config, enable_trade_screen_scroll)}, - {"group_units_on_right_click_menu" , true , offsetof (struct c3x_config, group_units_on_right_click_menu)}, - {"gray_out_units_on_menu_with_no_remaining_moves" , true , offsetof (struct c3x_config, gray_out_units_on_menu_with_no_remaining_moves)}, - {"put_movement_icons_on_units_on_menu" , true , offsetof (struct c3x_config, put_movement_icons_on_units_on_menu)}, - {"describe_states_of_units_on_menu" , true , offsetof (struct c3x_config, describe_states_of_units_on_menu)}, - {"show_golden_age_turns_remaining" , true , offsetof (struct c3x_config, show_golden_age_turns_remaining)}, - {"show_zoc_attacks_from_mid_stack" , true , offsetof (struct c3x_config, show_zoc_attacks_from_mid_stack)}, - {"show_armies_performing_defensive_bombard" , true , offsetof (struct c3x_config, show_armies_performing_defensive_bombard)}, - {"cut_research_spending_to_avoid_bankruptcy" , true , offsetof (struct c3x_config, cut_research_spending_to_avoid_bankruptcy)}, - {"dont_pause_for_love_the_king_messages" , true , offsetof (struct c3x_config, dont_pause_for_love_the_king_messages)}, - {"reverse_specialist_order_with_shift" , true , offsetof (struct c3x_config, reverse_specialist_order_with_shift)}, - {"toggle_zoom_with_z_on_city_screen" , true , offsetof (struct c3x_config, toggle_zoom_with_z_on_city_screen)}, - {"dont_give_king_names_in_non_regicide_games" , true , offsetof (struct c3x_config, dont_give_king_names_in_non_regicide_games)}, - {"no_elvis_easter_egg" , false, offsetof (struct c3x_config, no_elvis_easter_egg)}, - {"disable_worker_automation" , false, offsetof (struct c3x_config, disable_worker_automation)}, - {"enable_land_sea_intersections" , false, offsetof (struct c3x_config, enable_land_sea_intersections)}, - {"disallow_trespassing" , false, offsetof (struct c3x_config, disallow_trespassing)}, - {"show_detailed_tile_info" , true , offsetof (struct c3x_config, show_detailed_tile_info)}, - {"warn_about_unrecognized_names" , true , offsetof (struct c3x_config, warn_about_unrecognized_names)}, - {"enable_ai_production_ranking" , true , offsetof (struct c3x_config, enable_ai_production_ranking)}, - {"enable_ai_city_location_desirability_display" , true, offsetof (struct c3x_config, enable_ai_city_location_desirability_display)}, - {"show_ai_city_location_desirability_if_settler" , false, offsetof (struct c3x_config, show_ai_city_location_desirability_if_settler)}, - {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, - {"zero_corruption_when_off" , true , offsetof (struct c3x_config, zero_corruption_when_off)}, - {"disallow_land_units_from_affecting_water_tiles" , true , offsetof (struct c3x_config, disallow_land_units_from_affecting_water_tiles)}, - {"dont_end_units_turn_after_airdrop" , false, offsetof (struct c3x_config, dont_end_units_turn_after_airdrop)}, - {"allow_airdrop_without_airport" , false, offsetof (struct c3x_config, allow_airdrop_without_airport)}, - {"enable_negative_pop_pollution" , true , offsetof (struct c3x_config, enable_negative_pop_pollution)}, - {"allow_defensive_retreat_on_water" , false, offsetof (struct c3x_config, allow_defensive_retreat_on_water)}, - {"promote_wonder_decorruption_effect" , false, offsetof (struct c3x_config, promote_wonder_decorruption_effect)}, - {"allow_military_leaders_to_hurry_wonders" , false, offsetof (struct c3x_config, allow_military_leaders_to_hurry_wonders)}, - {"allow_multiple_battle_created_units_per_player" , false, offsetof (struct c3x_config, allow_multiple_battle_created_units_per_player)}, - {"aggressively_penalize_bankruptcy" , false, offsetof (struct c3x_config, aggressively_penalize_bankruptcy)}, - {"no_penalty_exception_for_agri_fresh_water_city_tiles" , false, offsetof (struct c3x_config, no_penalty_exception_for_agri_fresh_water_city_tiles)}, - {"use_offensive_artillery_ai" , true , offsetof (struct c3x_config, use_offensive_artillery_ai)}, - {"dont_escort_unflagged_units" , false, offsetof (struct c3x_config, dont_escort_unflagged_units)}, - {"replace_leader_unit_ai" , true , offsetof (struct c3x_config, replace_leader_unit_ai)}, - {"fix_ai_army_composition" , true , offsetof (struct c3x_config, fix_ai_army_composition)}, - {"enable_pop_unit_ai" , true , offsetof (struct c3x_config, enable_pop_unit_ai)}, - {"enable_caravan_unit_ai" , true , offsetof (struct c3x_config, enable_caravan_unit_ai)}, - {"remove_unit_limit" , true , offsetof (struct c3x_config, remove_unit_limit)}, - {"remove_city_improvement_limit" , true , offsetof (struct c3x_config, remove_city_improvement_limit)}, - {"remove_cap_on_turn_limit" , true , offsetof (struct c3x_config, remove_cap_on_turn_limit)}, - {"remove_era_limit" , false, offsetof (struct c3x_config, remove_era_limit)}, - {"patch_submarine_bug" , true , offsetof (struct c3x_config, patch_submarine_bug)}, - {"patch_science_age_bug" , true , offsetof (struct c3x_config, patch_science_age_bug)}, - {"patch_pedia_texture_bug" , true , offsetof (struct c3x_config, patch_pedia_texture_bug)}, - {"patch_blocked_disembark_freeze" , true , offsetof (struct c3x_config, patch_blocked_disembark_freeze)}, - {"patch_houseboat_bug" , true , offsetof (struct c3x_config, patch_houseboat_bug)}, - {"patch_intercept_lost_turn_bug" , true , offsetof (struct c3x_config, patch_intercept_lost_turn_bug)}, - {"patch_phantom_resource_bug" , true , offsetof (struct c3x_config, patch_phantom_resource_bug)}, - {"patch_maintenance_persisting_for_obsolete_buildings" , true , offsetof (struct c3x_config, patch_maintenance_persisting_for_obsolete_buildings)}, - {"patch_barbarian_diagonal_bug" , true , offsetof (struct c3x_config, patch_barbarian_diagonal_bug)}, - {"patch_disease_stopping_tech_flag_bug" , false, offsetof (struct c3x_config, patch_disease_stopping_tech_flag_bug)}, - {"patch_division_by_zero_in_ai_alliance_eval" , true , offsetof (struct c3x_config, patch_division_by_zero_in_ai_alliance_eval)}, - {"patch_empty_army_movement" , true , offsetof (struct c3x_config, patch_empty_army_movement)}, - {"patch_empty_army_combat_crash" , true , offsetof (struct c3x_config, patch_empty_army_combat_crash)}, - {"patch_premature_truncation_of_found_paths" , true , offsetof (struct c3x_config, patch_premature_truncation_of_found_paths)}, - {"patch_zero_production_crash" , true , offsetof (struct c3x_config, patch_zero_production_crash)}, - {"patch_ai_can_form_army_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_form_army_without_special_ability)}, - {"patch_ai_can_sacrifice_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_sacrifice_without_special_ability)}, - {"patch_crash_in_leader_unit_ai" , true , offsetof (struct c3x_config, patch_crash_in_leader_unit_ai)}, - {"patch_failure_to_find_new_city_build" , true , offsetof (struct c3x_config, patch_failure_to_find_new_city_build)}, - {"patch_passengers_out_of_order_on_menu" , true , offsetof (struct c3x_config, patch_passengers_out_of_order_on_menu)}, - {"delete_off_map_ai_units" , true , offsetof (struct c3x_config, delete_off_map_ai_units)}, - {"fix_overlapping_specialist_yield_icons" , true , offsetof (struct c3x_config, fix_overlapping_specialist_yield_icons)}, - {"prevent_autorazing" , false, offsetof (struct c3x_config, prevent_autorazing)}, - {"prevent_razing_by_players" , false, offsetof (struct c3x_config, prevent_razing_by_players)}, - {"suppress_hypertext_links_exceeded_popup" , true , offsetof (struct c3x_config, suppress_hypertext_links_exceeded_popup)}, - {"indicate_non_upgradability_in_pedia" , true , offsetof (struct c3x_config, indicate_non_upgradability_in_pedia)}, - {"show_message_after_dodging_sam" , true , offsetof (struct c3x_config, show_message_after_dodging_sam)}, - {"include_stealth_attack_cancel_option" , false, offsetof (struct c3x_config, include_stealth_attack_cancel_option)}, - {"intercept_recon_missions" , false, offsetof (struct c3x_config, intercept_recon_missions)}, - {"charge_one_move_for_recon_and_interception" , false, offsetof (struct c3x_config, charge_one_move_for_recon_and_interception)}, - {"polish_precision_striking" , true , offsetof (struct c3x_config, polish_precision_striking)}, - {"enable_stealth_attack_via_bombardment" , false, offsetof (struct c3x_config, enable_stealth_attack_via_bombardment)}, - {"immunize_aircraft_against_bombardment" , false, offsetof (struct c3x_config, immunize_aircraft_against_bombardment)}, - {"replay_ai_moves_in_hotseat_games" , false, offsetof (struct c3x_config, replay_ai_moves_in_hotseat_games)}, - {"restore_unit_directions_on_game_load" , true , offsetof (struct c3x_config, restore_unit_directions_on_game_load)}, - {"apply_grid_ini_setting_on_game_load" , true , offsetof (struct c3x_config, apply_grid_ini_setting_on_game_load)}, - {"charm_flag_triggers_ptw_like_targeting" , false, offsetof (struct c3x_config, charm_flag_triggers_ptw_like_targeting)}, - {"city_icons_show_unit_effects_not_trade" , true , offsetof (struct c3x_config, city_icons_show_unit_effects_not_trade)}, - {"ignore_king_ability_for_defense_priority" , false, offsetof (struct c3x_config, ignore_king_ability_for_defense_priority)}, - {"show_untradable_techs_on_trade_screen" , false, offsetof (struct c3x_config, show_untradable_techs_on_trade_screen)}, - {"disallow_useless_bombard_vs_airfields" , true , offsetof (struct c3x_config, disallow_useless_bombard_vs_airfields)}, - {"compact_luxury_display_on_city_screen" , false, offsetof (struct c3x_config, compact_luxury_display_on_city_screen)}, - {"compact_strategic_resource_display_on_city_screen" , false, offsetof (struct c3x_config, compact_strategic_resource_display_on_city_screen)}, - {"warn_when_chosen_building_would_replace_another" , false, offsetof (struct c3x_config, warn_when_chosen_building_would_replace_another)}, - {"do_not_unassign_workers_from_polluted_tiles" , false, offsetof (struct c3x_config, do_not_unassign_workers_from_polluted_tiles)}, - {"do_not_make_capital_cities_appear_larger" , false, offsetof (struct c3x_config, do_not_make_capital_cities_appear_larger)}, - {"show_territory_colors_on_water_tiles_in_minimap" , false, offsetof (struct c3x_config, show_territory_colors_on_water_tiles_in_minimap)}, - {"convert_some_popups_into_online_mp_messages" , false, offsetof (struct c3x_config, convert_some_popups_into_online_mp_messages)}, - {"enable_debug_mode_switch" , false, offsetof (struct c3x_config, enable_debug_mode_switch)}, - {"accentuate_cities_on_minimap" , false, offsetof (struct c3x_config, accentuate_cities_on_minimap)}, - {"allow_multipage_civilopedia_descriptions" , true , offsetof (struct c3x_config, allow_multipage_civilopedia_descriptions)}, - {"reformat_turns_remaining_on_domestic_advisor_screen" , true , offsetof (struct c3x_config, reformat_turns_remaining_on_domestic_advisor_screen)}, - {"expand_civilopedia_unit_stats" , true , offsetof (struct c3x_config, expand_civilopedia_unit_stats)}, - {"enable_trade_net_x" , true , offsetof (struct c3x_config, enable_trade_net_x)}, - {"optimize_improvement_loops" , true , offsetof (struct c3x_config, optimize_improvement_loops)}, - {"measure_turn_times" , false, offsetof (struct c3x_config, measure_turn_times)}, - {"enable_city_capture_by_barbarians" , false, offsetof (struct c3x_config, enable_city_capture_by_barbarians)}, - {"share_visibility_in_hotseat" , false, offsetof (struct c3x_config, share_visibility_in_hotseat)}, - {"share_wonders_in_hotseat" , false, offsetof (struct c3x_config, share_wonders_in_hotseat)}, - {"allow_precision_strikes_against_tile_improvements" , false, offsetof (struct c3x_config, allow_precision_strikes_against_tile_improvements)}, - {"dont_end_units_turn_after_bombarding_barricade" , false, offsetof (struct c3x_config, dont_end_units_turn_after_bombarding_barricade)}, - {"remove_land_artillery_target_restrictions" , false, offsetof (struct c3x_config, remove_land_artillery_target_restrictions)}, - {"allow_bombard_of_other_improvs_on_occupied_airfield" , false, offsetof (struct c3x_config, allow_bombard_of_other_improvs_on_occupied_airfield)}, - {"show_total_city_count" , false, offsetof (struct c3x_config, show_total_city_count)}, - {"strengthen_forbidden_palace_ocn_effect" , false, offsetof (struct c3x_config, strengthen_forbidden_palace_ocn_effect)}, - {"allow_upgrades_in_any_city" , false, offsetof (struct c3x_config, allow_upgrades_in_any_city)}, - {"do_not_generate_volcanos" , false, offsetof (struct c3x_config, do_not_generate_volcanos)}, - {"do_not_pollute_impassable_tiles" , false, offsetof (struct c3x_config, do_not_pollute_impassable_tiles)}, - {"show_hp_of_stealth_attack_options" , false, offsetof (struct c3x_config, show_hp_of_stealth_attack_options)}, - {"exclude_invisible_units_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_invisible_units_from_stealth_attack)}, - {"exclude_passengers_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_passengers_from_stealth_attack)}, - {"convert_to_landmark_after_planting_forest" , false, offsetof (struct c3x_config, convert_to_landmark_after_planting_forest)}, - {"allow_sale_of_aqueducts_and_hospitals" , false, offsetof (struct c3x_config, allow_sale_of_aqueducts_and_hospitals)}, - {"no_cross_shore_detection" , false, offsetof (struct c3x_config, no_cross_shore_detection)}, - {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, - {"limit_unit_loading_to_one_transport_per_turn" , false, offsetof (struct c3x_config, limit_unit_loading_to_one_transport_per_turn)}, - {"prevent_old_units_from_upgrading_past_ability_block" , false, offsetof (struct c3x_config, prevent_old_units_from_upgrading_past_ability_block)}, - {"allow_extraterritorial_colonies" , false, offsetof (struct c3x_config, allow_extraterritorial_colonies)}, - {"draw_forests_over_roads_and_railroads" , false, offsetof (struct c3x_config, draw_forests_over_roads_and_railroads)}, - {"enable_districts" , false, offsetof (struct c3x_config, enable_districts)}, - {"enable_neighborhood_districts" , false, offsetof (struct c3x_config, enable_neighborhood_districts)}, - {"enable_wonder_districts" , false, offsetof (struct c3x_config, enable_wonder_districts)}, - {"enable_natural_wonders" , false, offsetof (struct c3x_config, enable_natural_wonders)}, - {"add_natural_wonders_to_scenarios_if_none" , false, offsetof (struct c3x_config, add_natural_wonders_to_scenarios_if_none)}, - {"enable_named_tiles" , false, offsetof (struct c3x_config, enable_named_tiles)}, - {"enable_distribution_hub_districts" , false, offsetof (struct c3x_config, enable_distribution_hub_districts)}, - {"enable_aerodrome_districts" , false, offsetof (struct c3x_config, enable_aerodrome_districts)}, - {"enable_port_districts" , false, offsetof (struct c3x_config, enable_port_districts)}, - {"enable_bridge_districts" , false, offsetof (struct c3x_config, enable_bridge_districts)}, - {"enable_canal_districts" , false, offsetof (struct c3x_config, enable_canal_districts)}, - {"enable_central_rail_hub_districts" , false, offsetof (struct c3x_config, enable_central_rail_hub_districts)}, - {"enable_energy_grid_districts" , false, offsetof (struct c3x_config, enable_energy_grid_districts)}, - {"enable_great_wall_districts" , false, offsetof (struct c3x_config, enable_great_wall_districts)}, - {"completed_wonder_districts_can_be_destroyed" , false, offsetof (struct c3x_config, completed_wonder_districts_can_be_destroyed)}, - {"destroyed_wonders_can_be_built_again" , false, offsetof (struct c3x_config, destroyed_wonders_can_be_built_again)}, - {"cities_with_mutual_district_receive_buildings" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_buildings)}, - {"cities_with_mutual_district_receive_wonders" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_wonders)}, - {"show_message_when_building_received_by_mutual_district", false, offsetof (struct c3x_config, show_message_when_building_received_by_mutual_district)}, - {"show_message_when_building_lost_to_destroyed_district" , false, offsetof (struct c3x_config, show_message_when_building_lost_to_destroyed_district)}, - {"destroying_neighborhood_reduces_pop" , false, offsetof (struct c3x_config, destroying_neighborhood_reduces_pop)}, - {"air_units_use_aerodrome_districts_not_cities" , false, offsetof (struct c3x_config, air_units_use_aerodrome_districts_not_cities)}, - {"naval_units_use_port_districts_not_cities" , false, offsetof (struct c3x_config, naval_units_use_port_districts_not_cities)}, - {"show_natural_wonder_name_on_map" , false, offsetof (struct c3x_config, show_natural_wonder_name_on_map)}, - {"ai_defends_districts" , false, offsetof (struct c3x_config, ai_defends_districts)}, - {"great_wall_districts_impassible_by_others" , false, offsetof (struct c3x_config, great_wall_districts_impassible_by_others)}, - {"auto_build_great_wall_around_territory" , false, offsetof (struct c3x_config, auto_build_great_wall_around_territory)}, - {"disable_great_wall_city_defense_bonus" , false, offsetof (struct c3x_config, disable_great_wall_city_defense_bonus)}, - {"expand_water_tile_checks_to_city_work_area" , false, offsetof (struct c3x_config, expand_water_tile_checks_to_city_work_area)}, - {"ai_can_replace_existing_districts_with_canals" , false, offsetof (struct c3x_config, ai_can_replace_existing_districts_with_canals)}, - {"ai_builds_bridges" , false, offsetof (struct c3x_config, ai_builds_bridges)}, - {"ai_builds_canals" , false, offsetof (struct c3x_config, ai_builds_canals)}, - {"workers_can_enter_coast" , false, offsetof (struct c3x_config, workers_can_enter_coast)}, - {"enable_city_work_radii_highlights" , false, offsetof (struct c3x_config, enable_city_work_radii_highlights)}, - {"introduce_all_human_players_at_start_of_hotseat_game" , false, offsetof (struct c3x_config, introduce_all_human_players_at_start_of_hotseat_game)}, - {"allow_unload_from_army" , false, offsetof (struct c3x_config, allow_unload_from_army)}, - {"no_land_anti_air_from_inside_naval_transport" , false, offsetof (struct c3x_config, no_land_anti_air_from_inside_naval_transport)}, - {"prevent_enslaving_by_bombardment" , false, offsetof (struct c3x_config, prevent_enslaving_by_bombardment)}, - {"allow_adjacent_resources_of_different_types" , false, offsetof (struct c3x_config, allow_adjacent_resources_of_different_types)}, - {"allow_corruption_in_capital" , false, offsetof (struct c3x_config, allow_corruption_in_capital)}, - {"allow_sale_of_small_wonders" , false, offsetof (struct c3x_config, allow_sale_of_small_wonders)}, - {"initialize_preplaced_scenario_leaders_as_mgls" , false, offsetof (struct c3x_config, initialize_preplaced_scenario_leaders_as_mgls)}, - {"enable_unit_counters" , false, offsetof (struct c3x_config, enable_unit_counters)}, - {"use_civ4_style_best_defender" , false, offsetof (struct c3x_config, use_civ4_style_best_defender)}, - }; - - struct integer_config_option { - char * name; - int base_val; - int offset; - } integer_config_options[] = { - {"limit_railroad_movement" , 0, offsetof (struct c3x_config, limit_railroad_movement)}, - {"minimum_city_separation" , 1, offsetof (struct c3x_config, minimum_city_separation)}, - {"anarchy_length_percent" , 100, offsetof (struct c3x_config, anarchy_length_percent)}, - {"ai_multi_city_start" , 0, offsetof (struct c3x_config, ai_multi_city_start)}, - {"max_tries_to_place_fp_city" , 10000, offsetof (struct c3x_config, max_tries_to_place_fp_city)}, - {"ai_research_multiplier" , 100, offsetof (struct c3x_config, ai_research_multiplier)}, - {"ai_settler_perfume_on_founding_duration" , 0, offsetof (struct c3x_config, ai_settler_perfume_on_founding_duration)}, - {"extra_unit_maintenance_per_shields" , 0, offsetof (struct c3x_config, extra_unit_maintenance_per_shields)}, - {"ai_build_artillery_ratio" , 16, offsetof (struct c3x_config, ai_build_artillery_ratio)}, - {"ai_artillery_value_damage_percent" , 50, offsetof (struct c3x_config, ai_artillery_value_damage_percent)}, - {"ai_build_bomber_ratio" , 70, offsetof (struct c3x_config, ai_build_bomber_ratio)}, - {"max_ai_naval_escorts" , 3, offsetof (struct c3x_config, max_ai_naval_escorts)}, - {"ai_worker_requirement_percent" , 150, offsetof (struct c3x_config, ai_worker_requirement_percent)}, - {"chance_for_nukes_to_destroy_max_one_hp_units" , 100, offsetof (struct c3x_config, chance_for_nukes_to_destroy_max_one_hp_units)}, - {"rebase_range_multiplier" , 6, offsetof (struct c3x_config, rebase_range_multiplier)}, - {"elapsed_minutes_per_day_night_hour_transition" , 3, offsetof (struct c3x_config, elapsed_minutes_per_day_night_hour_transition)}, - {"fixed_hours_per_turn_for_day_night_cycle" , 1, offsetof (struct c3x_config, fixed_hours_per_turn_for_day_night_cycle)}, - {"pinned_hour_for_day_night_cycle" , 0, offsetof (struct c3x_config, pinned_hour_for_day_night_cycle)}, - {"years_to_double_building_culture" , 1000, offsetof (struct c3x_config, years_to_double_building_culture)}, - {"tourism_time_scale_percent" , 100, offsetof (struct c3x_config, tourism_time_scale_percent)}, - {"luxury_randomized_appearance_rate_percent" , 100, offsetof (struct c3x_config, luxury_randomized_appearance_rate_percent)}, - {"tiles_per_non_luxury_resource" , 32, offsetof (struct c3x_config, tiles_per_non_luxury_resource)}, - {"special_capital_decorruption_effect" , 10, offsetof (struct c3x_config, special_capital_decorruption_effect)}, - {"city_limit" , 2048, offsetof (struct c3x_config, city_limit)}, - {"maximum_pop_before_neighborhood_needed" , 8, offsetof (struct c3x_config, maximum_pop_before_neighborhood_needed)}, - {"per_neighborhood_pop_growth_enabled" , 2, offsetof (struct c3x_config, per_neighborhood_pop_growth_enabled)}, - {"minimum_natural_wonder_separation" , 10, offsetof (struct c3x_config, minimum_natural_wonder_separation)}, - {"distribution_hub_food_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_food_yield_divisor)}, - {"distribution_hub_shield_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_shield_yield_divisor)}, - {"ai_ideal_distribution_hub_count_per_100_cities" , 1, offsetof (struct c3x_config, ai_ideal_distribution_hub_count_per_100_cities)}, - {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, - {"max_distribution_hub_count_per_100_cities" , 50, offsetof (struct c3x_config, max_distribution_hub_count_per_100_cities)}, - {"central_rail_hub_distribution_food_bonus_percent" , 25, offsetof (struct c3x_config, central_rail_hub_distribution_food_bonus_percent)}, - {"central_rail_hub_distribution_shield_bonus_percent", 25, offsetof (struct c3x_config, central_rail_hub_distribution_shield_bonus_percent)}, - {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, - {"max_contiguous_bridge_districts" , 3, offsetof (struct c3x_config, max_contiguous_bridge_districts)}, - {"max_contiguous_canal_districts" , 5, offsetof (struct c3x_config, max_contiguous_canal_districts)}, - {"ai_canal_eval_min_bisected_land_tiles" , 10, offsetof (struct c3x_config, ai_canal_eval_min_bisected_land_tiles)}, - {"ai_bridge_canal_eval_block_size" , 20, offsetof (struct c3x_config, ai_bridge_canal_eval_block_size)}, - {"ai_bridge_eval_lake_tile_threshold" , 6, offsetof (struct c3x_config, ai_bridge_eval_lake_tile_threshold)}, - {"ai_city_district_max_build_wait_turns" , 20, offsetof (struct c3x_config, ai_city_district_max_build_wait_turns)}, - {"per_extraterritorial_colony_relation_penalty" , 0, offsetof (struct c3x_config, per_extraterritorial_colony_relation_penalty)}, - }; - - is->kernel32 = (*p_GetModuleHandleA) ("kernel32.dll"); - is->user32 = (*p_GetModuleHandleA) ("user32.dll"); - is->msvcrt = (*p_GetModuleHandleA) ("msvcrt.dll"); - - // Remember the function names here are macros that expand to is->... - VirtualProtect = (void *)(*p_GetProcAddress) (is->kernel32, "VirtualProtect"); - CloseHandle = (void *)(*p_GetProcAddress) (is->kernel32, "CloseHandle"); - CreateFileA = (void *)(*p_GetProcAddress) (is->kernel32, "CreateFileA"); - GetFileSize = (void *)(*p_GetProcAddress) (is->kernel32, "GetFileSize"); - ReadFile = (void *)(*p_GetProcAddress) (is->kernel32, "ReadFile"); - LoadLibraryA = (void *)(*p_GetProcAddress) (is->kernel32, "LoadLibraryA"); - FreeLibrary = (void *)(*p_GetProcAddress) (is->kernel32, "FreeLibrary"); - MultiByteToWideChar = (void *)(*p_GetProcAddress) (is->kernel32, "MultiByteToWideChar"); - WideCharToMultiByte = (void *)(*p_GetProcAddress) (is->kernel32, "WideCharToMultiByte"); - GetLastError = (void *)(*p_GetProcAddress) (is->kernel32, "GetLastError"); - QueryPerformanceCounter = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceCounter"); - QueryPerformanceFrequency = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceFrequency"); - GetLocalTime = (void *)(*p_GetProcAddress) (is->kernel32, "GetLocalTime"); - MessageBoxA = (void *)(*p_GetProcAddress) (is->user32, "MessageBoxA"); - is->msimg32 = LoadLibraryA ("Msimg32.dll"); - TransparentBlt = (void *)(*p_GetProcAddress) (is->msimg32, "TransparentBlt"); - snprintf = (void *)(*p_GetProcAddress) (is->msvcrt, "_snprintf"); - malloc = (void *)(*p_GetProcAddress) (is->msvcrt, "malloc"); - calloc = (void *)(*p_GetProcAddress) (is->msvcrt, "calloc"); - realloc = (void *)(*p_GetProcAddress) (is->msvcrt, "realloc"); - free = (void *)(*p_GetProcAddress) (is->msvcrt, "free"); - strtol = (void *)(*p_GetProcAddress) (is->msvcrt, "strtol"); - strcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strcmp"); - strncmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strncmp"); - _stricmp = (void *)(*p_GetProcAddress) (is->msvcrt, "_stricmp"); - strlen = (void *)(*p_GetProcAddress) (is->msvcrt, "strlen"); - strncpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strncpy"); - strcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strcpy"); - strdup = (void *)(*p_GetProcAddress) (is->msvcrt, "_strdup"); - strstr = (void *)(*p_GetProcAddress) (is->msvcrt, "strstr"); - qsort = (void *)(*p_GetProcAddress) (is->msvcrt, "qsort"); - memcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "memcmp"); - memcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "memcpy"); - tolower = (void *)(*p_GetProcAddress) (is->msvcrt, "tolower"); - toupper = (void *)(*p_GetProcAddress) (is->msvcrt, "toupper"); - is->memmove = (void *)(*p_GetProcAddress) (is->msvcrt, "memmove"); // No #define for this one, instead it has a wrapper func - - // Intercept the game's calls to MessageBoxA. We can't do this through the patcher since that would interfere with the runtime loader. - WITH_MEM_PROTECTION (p_MessageBoxA, 4, PAGE_READWRITE) - *p_MessageBoxA = patch_MessageBoxA; - - // Set file path to mod's script.txt - snprintf (is->mod_script_path, sizeof is->mod_script_path, "%s\\Text\\c3x-script.txt", is->mod_rel_dir); - is->mod_script_path[(sizeof is->mod_script_path) - 1] = '\0'; - - // Fill in base config - struct c3x_config base_config = {0}; - base_config.land_retreat_rules = RR_STANDARD; - base_config.sea_retreat_rules = RR_STANDARD; - base_config.ai_settler_perfume_on_founding = 0; - base_config.work_area_limit = WAL_NONE; - base_config.draw_lines_using_gdi_plus = LDO_WINE; - base_config.double_minimap_size = MDM_HIGH_DEF; - base_config.override_no_ai_patrol = NAPO_NONE; - base_config.override_barbarian_activity_level_for_scenario_maps = BAO_NONE; - base_config.unit_cycle_search_criteria = UCSC_STANDARD; - base_config.city_work_radius = 2; - base_config.day_night_cycle_mode = DNCM_OFF; - base_config.distribution_hub_yield_division_mode = DHYDM_FLAT; - base_config.ai_distribution_hub_build_strategy = ADHBS_BY_CITY_COUNT; - base_config.ai_auto_build_great_wall_strategy = AAGWS_ALL_BORDERS; - base_config.great_wall_auto_build_wonder_improv_id = -1; - for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) - *((char *)&base_config + boolean_config_options[n].offset) = boolean_config_options[n].base_val; - for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) - *(int *)((byte *)&base_config + integer_config_options[n].offset) = integer_config_options[n].base_val; - memcpy (&is->base_config, &base_config, sizeof base_config); - - // Load labels - { - for (int n = 0; n < COUNT_C3X_LABELS; n++) - is->c3x_labels[n] = ""; - - char labels_path[MAX_PATH]; - snprintf (labels_path, sizeof labels_path, "%s\\Text\\c3x-labels.txt", is->mod_rel_dir); - labels_path[(sizeof labels_path) - 1] = '\0'; - char * labels_file_contents = file_to_string (labels_path); - - if (labels_file_contents != NULL) { - char * cursor = labels_file_contents; - int n = 0; - while ((n < COUNT_C3X_LABELS) && (*cursor != '\0')) { - if (*cursor == '\n') - cursor++; - else if ((cursor[0] == '\r') && (cursor[1] == '\n')) - cursor += 2; - else if (*cursor == ';') { - while ((*cursor != '\0') && (*cursor != '\n')) - cursor++; - } else { - char * line_start = cursor; - while ((*cursor != '\0') && (*cursor != '\r') && (*cursor != '\n')) - cursor++; - int line_len = cursor - line_start; - if (NULL != (is->c3x_labels[n] = malloc (line_len + 1))) { - strncpy (is->c3x_labels[n], line_start, line_len); - is->c3x_labels[n][line_len] = '\0'; - } - n++; - } - } - free (labels_file_contents); - - } else { - char err_msg[500]; - snprintf (err_msg, sizeof err_msg, "Couldn't read labels from %s\nPlease make sure the file exists. If you moved the modded EXE you must move the mod folder after it.", labels_path); - err_msg[(sizeof err_msg) - 1] = '\0'; - MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); - } - } - - is->sb_next_up = NULL; - is->trade_net = p_original_trade_net; - is->city_limit = 512; - is->trade_net_addrs_load_state = IS_UNINITED; - is->trade_net_addrs = NULL; - is->tnx_cache = NULL; - is->is_computing_city_connections = false; - is->keep_tnx_cache = false; - is->must_recompute_resources_for_mill_inputs = false; - is->is_placing_scenario_things = false; - is->paused_for_popup = false; - is->time_spent_paused_during_popup = 0; - is->time_spent_computing_city_connections = 0; - is->count_calls_to_recompute_city_connections = 0; - - is->have_job_and_loc_to_skip = 0; - - // Initialize trade screen scroll vars - is->open_diplo_form_straight_to_trade = 0; - is->trade_screen_scroll_to_id = -1; - is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; - is->trade_scroll_button_images = NULL; - is->trade_scroll_button_state = IS_UNINITED; - is->eligible_for_trade_scroll = 0; - - memset (&is->saved_code_areas, 0, sizeof is->saved_code_areas); - - is->unit_menu_duplicates = NULL; - - is->memo = NULL; - is->memo_len = 0; - is->memo_capacity = 0; - - // Fill in array mapping cultural NIs to standard ones. - is->cultural_ni_to_standard = malloc (MAX_CULTURAL_NI + 1); - for (int n = 0; n <= MAX_CULTURAL_NI; n++) { - char const * p = &cultural_ni_to_diffs[n << 1]; - is->cultural_ni_to_standard[n] = diff_to_neighbor_index (p[0], p[1], 1000); - } - - // Fill in array mapping standard NIs to work radii AKA work ring numbers - for (int n = 0; n < ARRAY_LEN (is->ni_to_work_radius); n++) { - int work_radius = -1; - int dx, dy; - neighbor_index_to_diff (n, &dx, &dy); - for (int ring_no = 0; ring_no <= 7; ring_no++) { - for (int k = workable_tile_counts[ring_no-1]; k < workable_tile_counts[ring_no]; k++) { - char const * p = &cultural_ni_to_diffs[k<<1]; - if ((p[0] == dx) && (p[1] == dy)) { - work_radius = ring_no; - break; - } - } - if (work_radius != -1) - break; - } - is->ni_to_work_radius[n] = work_radius; - } - - is->city_loc_display_perspective = -1; - - is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; - - is->extra_available_resources = NULL; - is->extra_available_resources_capacity = 0; - - memset (is->interceptor_reset_lists, 0, sizeof is->interceptor_reset_lists); - - is->ai_prod_valuations = NULL; - is->count_ai_prod_valuations = 0; - is->ai_prod_valuations_capacity = 0; - - is->resource_tiles = NULL; - is->count_resource_tiles = 0; - is->resource_tiles_capacity = 0; - is->got_resource_tile = NULL; - is->saved_tile_count = -1; - is->mill_input_resource_bits = NULL; - - is->drawing_icons_for_improv_id = -1; - - is->resources_sheet = NULL; - - is->modifying_gold_trade = NULL; - - is->bombard_stealth_target = NULL; - is->selecting_stealth_target_for_bombard = 0; - - is->map_message_text_override = NULL; - - is->load_file_path_override = NULL; - - is->replay_for_players = 0; - - is->suppress_intro_after_load_popup = 0; - - is->force_barb_activity_for_cities = 0; - - is->dummy_tile = calloc (1, sizeof *is->dummy_tile); - - is->bombarding_unit = NULL; - - is->unit_bombard_attacking_tile = NULL; - is->attacking_tile_x = is->attacking_tile_y = -1; - - is->temporarily_disallow_lethal_zoc = false; - is->moving_unit_to_adjacent_tile = false; - is->showing_hotseat_replay = false; - is->getting_tile_occupier_for_ai_pathfinding = false; - - is->running_on_wine = false; { - HMODULE ntdll = (*p_GetModuleHandleA) ("ntdll.dll"); - is->running_on_wine = (ntdll != NULL) && ((*p_GetProcAddress) (ntdll, "wine_get_version") != NULL); - } - - is->gdi_plus.init_state = IS_UNINITED; - - is->water_trade_improvs = (struct improv_id_list) {0}; - is->air_trade_improvs = (struct improv_id_list) {0}; - is->combat_defense_improvs = (struct improv_id_list) {0}; - - is->unit_display_override = (struct unit_display_override) {-1, -1, -1}; - - is->dbe = (struct defensive_bombard_event) {0}; - - memset (&is->boolean_config_offsets, 0, sizeof is->boolean_config_offsets); - for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) - stable_insert (&is->boolean_config_offsets, boolean_config_options[n].name, boolean_config_options[n].offset); - memset (&is->integer_config_offsets, 0, sizeof is->integer_config_offsets); - for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) - stable_insert (&is->integer_config_offsets, integer_config_options[n].name, integer_config_options[n].offset); - - memset (&is->unit_type_alt_strategies, 0, sizeof is->unit_type_alt_strategies); - memset (&is->unit_type_duplicates , 0, sizeof is->unit_type_duplicates); - memset (&is->extra_defensive_bombards, 0, sizeof is->extra_defensive_bombards); - memset (&is->airdrops_this_turn , 0, sizeof is->airdrops_this_turn); - memset (&is->unit_transport_ties , 0, sizeof is->unit_transport_ties); - memset (&is->extra_city_improvs , 0, sizeof is->extra_city_improvs); - - is->unit_type_count_init_bits = 0; - for (int n = 0; n < 32; n++) - memset (&is->unit_type_counts[n], 0, sizeof is->unit_type_counts[n]); - - is->penciled_in_upgrades = NULL; - is->penciled_in_upgrade_count = is->penciled_in_upgrade_capacity = 0; - - is->currently_capturing_city = NULL; - is->accessing_save_file = NULL; - - is->drawn_strat_resource_count = 0; - - is->charmed_types_converted_to_ptw_arty = NULL; - is->count_charmed_types_converted_to_ptw_arty = 0; - is->charmed_types_converted_to_ptw_arty_capacity = 0; - - is->checking_visibility_for_unit = NULL; - - is->do_not_bounce_invisible_units = false; - is->always_despawn_passengers = false; - is->do_not_enslave_units = false; - - is->saved_improv_counts = NULL; - is->saved_improv_counts_capacity = 0; - - memset (is->last_main_screen_key_up_events, 0, sizeof is->last_main_screen_key_up_events); - - reset_district_state (true); - - is->natural_wonder_count = 0; - - is->sharing_buildings_by_districts_in_progress = false; - is->can_load_transport = is->can_load_passenger = NULL; - - is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; - is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; - is->last_selected_unit.ptr = NULL; - - is->waiting_units = (struct table) {0}; - is->have_loaded_waiting_units = false; - - is->extra_capture_despawns = NULL; - is->count_extra_capture_despawns = 0; - is->extra_capture_despawns_capacity = 0; - - is->loaded_config_names = NULL; - reset_to_base_config (); - apply_machine_code_edits (&is->current_config, true); -} - -void -init_stackable_command_buttons () -{ - if (is->sc_img_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - for (int n = 0; n < 4; n++) - Sprite_construct (&is->sc_button_image_sets[sc].imgs[n]); - - char temp_path[2*MAX_PATH]; - - is->sb_activated_by_button = 0; - is->sc_img_state = IS_INIT_FAILED; - - char const * filenames[4] = {"StackedNormButtons.pcx", "StackedRolloverButtons.pcx", "StackedHighlightedButtons.pcx", "StackedButtonsAlpha.pcx"}; - for (int n = 0; n < 4; n++) { - get_mod_art_path (filenames[n], temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - for (int k = 0; k < 4; k++) { - Sprite * sprite = &is->sc_button_image_sets[sc].imgs[k]; - sprite->vtable->destruct (sprite, __, 0); - } - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) { - int x = 32 * sc_button_infos[sc].tile_sheet_column, - y = 32 * sc_button_infos[sc].tile_sheet_row; - Sprite_slice_pcx (&is->sc_button_image_sets[sc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); - } - - pcx.vtable->clear_JGL (&pcx); - } - - is->sc_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -void -init_disabled_command_buttons () -{ - if (is->disabled_command_img_state != IS_UNINITED) - return; - - is->disabled_command_img_state = IS_INIT_FAILED; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("DisabledButtons.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load disabled command buttons sprite sheet.\n"); - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - Sprite_construct (&is->disabled_build_city_button_img); - Sprite_slice_pcx (&is->disabled_build_city_button_img, __, &pcx, 32*5, 32*2, 32, 32, 1, 0); - - is->disabled_command_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_stackable_command_buttons () -{ - if (is->sc_img_state == IS_OK) - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - for (int n = 0; n < 4; n++) { - Sprite * sprite = &is->sc_button_image_sets[sc].imgs[n]; - sprite->vtable->destruct (sprite, __, 0); - } - is->sc_img_state = IS_UNINITED; -} - -void -deinit_disabled_command_buttons () -{ - Sprite * sprite = &is->disabled_build_city_button_img; - if (is->disabled_command_img_state == IS_OK) - sprite->vtable->destruct (sprite, __, 0); - memset (sprite, 0, sizeof *sprite); - is->disabled_command_img_state = IS_UNINITED; -} - -void -init_tile_highlights () -{ - if (is->tile_highlight_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - - is->tile_highlight_state = IS_INIT_FAILED; - - snprintf (temp_path, sizeof temp_path, "%s\\Art\\TileHighlights.pcx", is->mod_rel_dir); - temp_path[(sizeof temp_path) - 1] = '\0'; - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); - goto cleanup; - } - - for (int n = 0; n < COUNT_TILE_HIGHLIGHTS; n++) - Sprite_slice_pcx (&is->tile_highlights[n], __, &pcx, 128*n, 0, 128, 64, 1, 0); - - is->tile_highlight_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -init_unit_rcm_icons () -{ - if (is->unit_rcm_icon_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("UnitRCMIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image == NULL) || - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 57) || - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 64)) { - (*p_OutputDebugStringA) ("[C3X] PCX file for unit RCM icons failed to load or is too small.\n"); - goto cleanup; - } - - for (int set = 0; set < COUNT_UNIT_RCM_ICON_SETS; set++) { - Sprite * icons = &is->unit_rcm_icons[set * COUNT_UNIT_RCM_ICONS]; - for (int n = 0; n < COUNT_UNIT_RCM_ICONS; n++) { - Sprite_construct (&icons[n]); - Sprite_slice_pcx (&icons[n], __, &pcx, 1 + 14*set, 1 + 16*n, 14, 15, 1, 0); - } - } - - is->unit_rcm_icon_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_unit_rcm_icons () -{ - if (is->unit_rcm_icon_state == IS_OK) { - int total_icon_count = COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS; - for (int n = 0; n < total_icon_count; n++) { - Sprite * sprite = &is->unit_rcm_icons[n]; - sprite->vtable->destruct (sprite, __, 0); - } - is->unit_rcm_icon_state = IS_UNINITED; - } -} - -void -init_red_food_icon () -{ - if (is->red_food_icon_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("MoreCityIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image != NULL) && - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) >= 32) && - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) == 32)) { - Sprite_construct (&is->red_food_icon); - Sprite_slice_pcx (&is->red_food_icon, __, &pcx, 1, 1, 30, 30, 1, 1); - is->red_food_icon_state = IS_OK; - } else { - (*p_OutputDebugStringA) ("[C3X] PCX file for red food icon failed to load or is not the correct size.\n"); - is->red_food_icon_state = IS_INIT_FAILED; - } - - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_red_food_icon () -{ - if (is->red_food_icon_state == IS_OK) - is->red_food_icon.vtable->destruct (&is->red_food_icon, __, 0); - is->red_food_icon_state = IS_UNINITED; -} - -enum init_state -init_large_minimap_frame () -{ - if (is->large_minimap_frame_img_state != IS_UNINITED) - return is->large_minimap_frame_img_state; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - - get_mod_art_path ("interface\\DoubleSizeBoxLeftColor.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image != NULL) { - Sprite_construct (&is->double_size_box_left_color_pcx); - int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), - height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); - Sprite_slice_pcx (&is->double_size_box_left_color_pcx, __, &pcx, 0, 0, width, height, 1, 1); - } else { - pcx.vtable->destruct (&pcx, __, 0); - return is->large_minimap_frame_img_state = IS_INIT_FAILED; - } - - get_mod_art_path ("interface\\DoubleSizeBoxLeftAlpha.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image != NULL) { - Sprite_construct (&is->double_size_box_left_alpha_pcx); - int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), - height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); - Sprite_slice_pcx (&is->double_size_box_left_alpha_pcx, __, &pcx, 0, 0, width, height, 1, 1); - } else { - is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); - pcx.vtable->destruct (&pcx, __, 0); - return is->large_minimap_frame_img_state = IS_INIT_FAILED;; - } - - pcx.vtable->destruct (&pcx, __, 0); - return is->large_minimap_frame_img_state = IS_OK; -} - -void -deinit_large_minimap_frame () -{ - if (is->large_minimap_frame_img_state == IS_OK) { - is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); - is->double_size_box_left_alpha_pcx.vtable->destruct (&is->double_size_box_left_alpha_pcx, __, 0); - } - is->large_minimap_frame_img_state = IS_UNINITED; -} - -int __cdecl -patch_get_tile_occupier_for_ai_path (int x, int y, int pov_civ_id, bool respect_unit_invisibility) -{ - is->getting_tile_occupier_for_ai_pathfinding = true; - return get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); - is->getting_tile_occupier_for_ai_pathfinding = false; -} - -char __fastcall patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2); - -char __fastcall -patch_Unit_is_tile_occupier_visible (Unit * this, int edx, int civ_id, int param_2) -{ - // Here's the fix for the submarine bug: If we're constructing a path for an AI unit, ignore unit invisibility so the pathfinder will path - // around instead of over other civ's units. We must carve out an exception if the AI is at war with the unit in question. In that case if it - // "accidentally" paths over the unit, it should get stuck in combat like the human player would. - if (is->current_config.patch_submarine_bug && - is->getting_tile_occupier_for_ai_pathfinding && - ! this->vtable->is_enemy_of_civ (this, __, civ_id, 0)) - return 1; - else - return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); -} - -void do_trade_scroll (DiploForm * diplo, int forward); - -void __cdecl -activate_trade_scroll_button (int control_id) -{ - do_trade_scroll (p_diplo_form, control_id == TRADE_SCROLL_BUTTON_ID_RIGHT); -} - -void -init_trade_scroll_buttons (DiploForm * diplo_form) -{ - if (is->trade_scroll_button_state != IS_UNINITED) - return; - - char temp_path[2*MAX_PATH]; - PCX_Image pcx; - PCX_Image_construct (&pcx); - get_mod_art_path ("TradeScrollButtons.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - is->trade_scroll_button_state = IS_INIT_FAILED; - (*p_OutputDebugStringA) ("[C3X] Failed to load TradeScrollButtons.pcx\n"); - goto cleanup; - } - - // Stores normal, rollover, and highlight images, in that order, first for the left button then for the right - is->trade_scroll_button_images = calloc (6, sizeof is->trade_scroll_button_images[0]); - for (int n = 0; n < 6; n++) - Sprite_construct (&is->trade_scroll_button_images[n]); - Sprite * imgs = is->trade_scroll_button_images; - - for (int right = 0; right < 2; right++) - for (int n = 0; n < 3; n++) - Sprite_slice_pcx (&imgs[n + 3*right], __, &pcx, right ? 44 : 0, 1 + 48*n, 43, 47, 1, 1); - - for (int right = 0; right < 2; right++) { - Button * b = new (sizeof *b); - - Button_construct (b); - int id = right ? TRADE_SCROLL_BUTTON_ID_RIGHT : TRADE_SCROLL_BUTTON_ID_LEFT; - Button_initialize (b, __, NULL, id, right ? 622 : 358, 50, 43, 47, (Base_Form *)diplo_form, 0); - for (int n = 0; n < 3; n++) - b->Images[n] = &imgs[n + 3*right]; - - b->activation_handler = &activate_trade_scroll_button; - b->field_630[0] = 0; // TODO: Is this necessary? It's done by the base game code when creating the city screen scroll buttons - - if (! right) - is->trade_scroll_button_left = b; - else - is->trade_scroll_button_right = b; - } - - is->trade_scroll_button_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_trade_scroll_buttons () -{ - if (is->trade_scroll_button_state == IS_OK) { - is->trade_scroll_button_left ->vtable->destruct ((Base_Form *)is->trade_scroll_button_left , __, 0); - is->trade_scroll_button_right->vtable->destruct ((Base_Form *)is->trade_scroll_button_right, __, 0); - is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; - for (int n = 0; n < 6; n++) { - Sprite * sprite = &is->trade_scroll_button_images[n]; - sprite->vtable->destruct (sprite, __, 0); - } - free (is->trade_scroll_button_images); - is->trade_scroll_button_images = NULL; - } - is->trade_scroll_button_state = IS_UNINITED; -} - -void -init_mod_info_button_images () -{ - if (is->mod_info_button_images_state != IS_UNINITED) - return; - - is->mod_info_button_images_state = IS_INIT_FAILED; - - PCX_Image * descbox_pcx = new (sizeof *descbox_pcx); - PCX_Image_construct (descbox_pcx); - char * descbox_path = BIC_get_asset_path (p_bic_data, __, "art\\civilopedia\\descbox.pcx", true); - PCX_Image_read_file (descbox_pcx, __, descbox_path, NULL, 0, 0x100, 1); - if (descbox_pcx->JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load descbox.pcx\n"); - return; - } - - for (int n = 0; n < 3; n++) { - Sprite_construct (&is->mod_info_button_images[n]); - Sprite_slice_pcx_with_color_table (&is->mod_info_button_images[n], __, descbox_pcx, 1 + n * 103, 1, MOD_INFO_BUTTON_WIDTH, - MOD_INFO_BUTTON_HEIGHT, 1, 1); - } - - is->mod_info_button_images_state = IS_OK; -} - -int -count_escorters (Unit * unit) -{ - IDLS * idls = &unit->Body.IDLS; - if (idls->escorters.contents != NULL) { - int tr = 0; - for (int * p_escorter_id = idls->escorters.contents; p_escorter_id < idls->escorters.contents_end; p_escorter_id++) - tr += NULL != get_unit_ptr (*p_escorter_id); - return tr; - } else - return 0; -} - -// If "unit" belongs to the AI, records that all players that have visibility on (x, y) have seen an AI unit -void -record_ai_unit_seen (Unit * unit, int x, int y) -{ - if (0 == (*p_human_player_bits & 1<Body.CivID)) { - Tile * tile = tile_at (x, y); - if ((tile != NULL) && (tile != p_null_tile)) { - Tile_Body * body = &tile->Body; - is->players_saw_ai_unit |= body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility; - } - } -} - -void -recompute_resources_if_necessary () -{ - if (is->must_recompute_resources_for_mill_inputs) - patch_Trade_Net_recompute_resources (is->trade_net, __, false); -} - -void __fastcall -patch_Unit_bombard_tile (Unit * this, int edx, int x, int y) -{ - Tile * target_tile = NULL; - bool had_district_before = false; - int tile_x = x; - int tile_y = y; - struct district_instance * inst; - - if (is->current_config.enable_districts) { - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - target_tile = tile_at (tile_x, tile_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - inst = get_district_instance (target_tile); - had_district_before = (inst != NULL); - } - } - - is->bombarding_unit = this; - record_ai_unit_seen (this, x, y); - Unit_bombard_tile (this, __, x, y); - is->bombard_stealth_target = NULL; - is->bombarding_unit = NULL; - - if (had_district_before && target_tile != NULL && target_tile != p_null_tile && inst->district_id != NATURAL_WONDER_DISTRICT_ID) { - unsigned int overlays = target_tile->vtable->m42_Get_Overlays (target_tile, __, 0); - if ((overlays & TILE_FLAG_MINE) == 0) - handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, false); - } -} - -void __fastcall -patch_Unit_move (Unit * this, int edx, int tile_x, int tile_y) -{ - record_ai_unit_seen (this, tile_x, tile_y); - - Unit_move (this, __, tile_x, tile_y); - - if (this == is->last_selected_unit.ptr) { - is->last_selected_unit.last_x = this->Body.X; - is->last_selected_unit.last_y = this->Body.Y; - } -} - -// Returns true if the unit has attacked & does not have blitz or if it's run out of movement points for the turn -bool -has_exhausted_attack (Unit * unit) -{ - return (unit->Body.Moves >= patch_Unit_get_max_move_points (unit)) || - ((unit->Body.Status & USF_USED_ATTACK) && ! UnitType_has_ability (&p_bic_data->UnitTypes[unit->Body.UnitTypeID], __, UTA_Blitz)); -} - -// Returns whether or not the unit type is a combat type and can do damage on offense (as opposed to only being able to defend). This includes units -// that can only do damage by bombarding and nuclear weapons. -bool -is_offensive_combat_type (UnitType * unit_type) -{ - return (unit_type->Attack > 0) || - ((((unit_type->Special_Actions & UCV_Bombard) | (unit_type->Air_Missions & UCV_Bombing)) & 0x0FFFFFFF) && // (type can perform bombard or bombing AND - ((unit_type->Bombard_Strength > 0) || UnitType_has_ability (unit_type, __, UTA_Nuclear_Weapon))); // (unit has bombard strength OR is a nuclear weapon)) -} - -bool -can_damage_bombarding (UnitType * attacker_type, Unit * defender, Tile * defender_tile) -{ - Unit * container; - if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - (container = get_unit_ptr (defender->Body.Container_Unit)) != NULL && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return false; - - UnitType * defender_type = &p_bic_data->UnitTypes[defender->Body.UnitTypeID]; - if (defender_type->Unit_Class == UTC_Land) { - int has_lethal_land_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Land_Bombardment); - return defender->Body.Damage + (! has_lethal_land_bombard) < Unit_get_max_hp (defender); - } else if (defender_type->Unit_Class == UTC_Sea) { - // Land artillery can't normally damage ships in port - if ((attacker_type->Unit_Class == UTC_Land) && (! is->current_config.remove_land_artillery_target_restrictions) && Tile_has_city (defender_tile)) - return false; - int has_lethal_sea_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Sea_Bombardment); - return defender->Body.Damage + (! has_lethal_sea_bombard) < Unit_get_max_hp (defender); - } else if (defender_type->Unit_Class == UTC_Air) { - if (is->current_config.immunize_aircraft_against_bombardment) - return false; - // Can't damage aircraft in an airfield by bombarding, the attack doesn't even go off - if ((defender_tile->vtable->m42_Get_Overlays (defender_tile, __, 0) & 0x20000000) != 0) - return false; - // Land artillery can't normally damage aircraft but naval artillery and other aircraft can. Lethal bombard doesn't apply; anything - // that can damage can kill. - return (attacker_type->Unit_Class != UTC_Land) || is->current_config.remove_land_artillery_target_restrictions; - } else // UTC_Space? UTC_Alternate_Dimension??? - return false; -} - -char __fastcall -patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2) -{ - // Save the previous value here b/c this function gets called recursively - Unit * prev_checking = is->checking_visibility_for_unit; - is->checking_visibility_for_unit = this; - - char base_vis = Unit_is_visible_to_civ (this, __, civ_id, param_2); - if ((! base_vis) && // if unit is not visible to civ_id AND - is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND - ((1 << civ_id) & *p_human_player_bits) && // civ_id is a human player AND - (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game - - // Check if the unit is visible to any other human player in the game - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && - (n_player != civ_id) && - Unit_is_visible_to_civ (this, __, n_player, param_2)) - return 1; - player_bits >>= 1; - n_player++; - } - } - - is->checking_visibility_for_unit = prev_checking; - return base_vis; -} - -bool -has_any_destructible_improvements (City * city) -{ - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * improv = &p_bic_data->Improvements[n]; - if (((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) && // if improv is not a wonder AND - ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && // it's not the palace AND - (improv->SpaceshipPart < 0) && // it's not a spaceship part AND - patch_City_has_improvement (city, __, n, 0)) // it's present in the city ignoring free improvements - return true; - } - return false; -} - -int const destructible_overlays = - 0x00000003 | // road, railroad - 0x00000004 | // mine - 0x00000008 | // irrigation - 0x00000010 | // fortress - 0x10000000 | // barricade - 0x20000000 | // airfield - 0x40000000 | // radar - 0x80000000; // outpost - -bool -has_any_destructible_overlays (Tile * tile, bool precision_strike) -{ - int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); - if ((overlays & destructible_overlays) == 0) - return false; - else { - if (! precision_strike) - return true; - else { - if (overlays == 0x20000000) { // if tile ONLY has an airfield - int any_aircraft_on_tile = 0; { - FOR_UNITS_ON (uti, tile) - if (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class == UTC_Air) { - any_aircraft_on_tile = 1; - break; - } - } - return ! any_aircraft_on_tile; - } else - return true; - } - } -} - -void __fastcall -patch_Main_Screen_Form_perform_action_on_tile (Main_Screen_Form * this, int edx, enum Unit_Mode_Actions action, int x, int y) -{ - if ((! is->current_config.enable_stack_bombard) || // if stack bombard is disabled OR - (! ((action == UMA_Bombard) || (action == UMA_Air_Bombard))) || // action is not bombard OR - ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) && // (control key is not down AND - ((is->sc_img_state != IS_UNINITED) && (is->sb_activated_by_button == 0))) || // (button flag is valid AND not set)) OR - is_online_game ()) { // is online game - Main_Screen_Form_perform_action_on_tile (this, __, action, x, y); - return; - } - - // Save preferences so we can restore them at the end of the stack bombard operation. We might change them to turn off combat animations. - unsigned init_prefs = *p_preferences; - - clear_memo (); - - wrap_tile_coords (&p_bic_data->Map, &x, &y); - Tile * base_tile = tile_at (this->Current_Unit->Body.X, this->Current_Unit->Body.Y); - Tile * target_tile = tile_at (x, y); - int attacker_type_id = this->Current_Unit->Body.UnitTypeID; - UnitType * attacker_type = &p_bic_data->UnitTypes[attacker_type_id]; - int civ_id = this->Current_Unit->Body.CivID; - - // Count & memoize attackers - int selected_unit_id = this->Current_Unit->Body.ID; - FOR_UNITS_ON (uti, base_tile) - if ((uti.id != selected_unit_id) && - (uti.unit->Body.CivID == civ_id) && - (uti.unit->Body.UnitTypeID == attacker_type_id) && - ((uti.unit->Body.Container_Unit < 0) || (attacker_type->Unit_Class == UTC_Air)) && - (uti.unit->Body.UnitState == 0) && - ! has_exhausted_attack (uti.unit)) - memoize (uti.id); - int count_attackers = is->memo_len; - - // Count & memoize targets (also count air units while we're at it) - int num_air_units_on_target_tile = 0; - FOR_UNITS_ON (uti, target_tile) { - num_air_units_on_target_tile += UTC_Air == p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; - if ((uti.unit->Body.CivID != civ_id) && - (Unit_get_defense_strength (uti.unit) > 0) && - (uti.unit->Body.Container_Unit < 0) && - patch_Unit_is_visible_to_civ (uti.unit, __, civ_id, 0) && - can_damage_bombarding (attacker_type, uti.unit, target_tile)) - memoize (uti.id); - } - int count_targets = is->memo_len - count_attackers; - - // Now our attackers and targets arrays will just be pointers into the memo - int * attackers = &is->memo[0], * targets = &is->memo[count_attackers]; - - int attacking_units = 0, attacking_tile = 0; - City * target_city = NULL; - if (count_targets > 0) - attacking_units = 1; - else if (Tile_has_city (target_tile)) - target_city = get_city_ptr (target_tile->vtable->m45_Get_City_ID (target_tile)); - else { - // Make sure not to set attacking_tile when the tile has an airfield and air units (but no land units) on - // it. In that case we can't damage the airfield and if we try to anyway, the units will waste their moves - // without attacking. - int has_airfield = (target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & 0x20000000) != 0; - attacking_tile = (! has_airfield) || (num_air_units_on_target_tile == 0); - } - - is->sb_next_up = this->Current_Unit; - int i_next_attacker = 0; - int anything_left_to_attack; - int last_attack_didnt_happen; - do { - // If combat animations were enabled when the stack bombard operation started, reset the preference according to the state of the - // shift key (down => skip animations, up => show them). - if (init_prefs & P_ANIMATE_BATTLES) { - if ((*p_GetAsyncKeyState) (VK_SHIFT) >> 8) - *p_preferences &= ~P_ANIMATE_BATTLES; - else - *p_preferences |= P_ANIMATE_BATTLES; - } - - int moves_before_bombard = is->sb_next_up->Body.Moves; - - patch_Unit_bombard_tile (is->sb_next_up, __, x, y); - // At this point sb_next_up may have become NULL if the unit was a bomber that got shot down. - - // Check if the last unit sent into battle actually did anything. If it didn't we should at least skip over - // it to avoid an infinite loop, but actually the only time this should happen is if the player is not at - // war with the targeted civ and chose not to declare when prompted. In this case it's better to just stop - // trying to attack so as to not spam the player with prompts. - last_attack_didnt_happen = (is->sb_next_up == NULL) || (is->sb_next_up->Body.Moves == moves_before_bombard); - - if ((is->sb_next_up == NULL) || has_exhausted_attack (is->sb_next_up)) { - is->sb_next_up = NULL; - while ((i_next_attacker < count_attackers) && (is->sb_next_up == NULL)) - is->sb_next_up = get_unit_ptr (attackers[i_next_attacker++]); - } - - if (attacking_units) { - anything_left_to_attack = 0; - for (int n = 0; n < count_targets; n++) { - Unit * unit = get_unit_ptr (targets[n]); - - // Make sure this unit is still a valid target. Keep in mind it's possible for new units to be created during the - // stack bombard operation if the attackers have lethal bombard and the enslave ability. - if ((unit != NULL) && (unit->Body.X == x) && (unit->Body.Y == y) && (unit->Body.CivID != civ_id)) { - - if (can_damage_bombarding (attacker_type, unit, target_tile)) { - anything_left_to_attack = 1; - break; - } - } - } - } else if (target_city != NULL) - anything_left_to_attack = (target_city->Body.Population.Size > 1) || has_any_destructible_improvements (target_city); - else if (attacking_tile) - anything_left_to_attack = has_any_destructible_overlays (target_tile, false); - else - anything_left_to_attack = 0; - } while ((is->sb_next_up != NULL) && anything_left_to_attack && (! last_attack_didnt_happen)); - - is->sb_activated_by_button = 0; - is->sb_next_up = NULL; - *p_preferences = init_prefs; - this->GUI.Base.vtable->m73_call_m22_Draw ((Base_Form *)&this->GUI); -} - -void -set_up_stack_bombard_buttons (Main_GUI * this) -{ - if (is_online_game () || (! is->current_config.enable_stack_bombard)) - return; - - init_stackable_command_buttons (); - if (is->sc_img_state != IS_OK) - return; - - // Find button that the original method set to (air) bombard, then find the next unused button after that. - Command_Button * bombard_button = NULL, * free_button = NULL; { - int i_bombard_button; - for (int n = 0; n < 42; n++) - if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && - (this->Unit_Command_Buttons[n].Command == UCV_Bombard || this->Unit_Command_Buttons[n].Command == UCV_Bombing)) { - bombard_button = &this->Unit_Command_Buttons[n]; - i_bombard_button = n; - break; - } - if (bombard_button != NULL) - for (int n = i_bombard_button + 1; n < 42; n++) - if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { - free_button = &this->Unit_Command_Buttons[n]; - break; - } - } - - if ((bombard_button == NULL) || (free_button == NULL)) - return; - - // Set up free button for stack bombard - free_button->Command = bombard_button->Command; - free_button->field_6D8 = bombard_button->field_6D8; - struct sc_button_image_set * img_set = - (bombard_button->Command == UCV_Bombing) ? &is->sc_button_image_sets[SC_BOMB] : &is->sc_button_image_sets[SC_BOMBARD]; - for (int n = 0; n < 4; n++) - free_button->Button.Images[n] = &img_set->imgs[n]; - free_button->Button.field_664 = bombard_button->Button.field_664; - // FUN_005559E0 is also called in the original code. I don't know what it actually does but I'm pretty sure it doesn't - // matter for our purposes. - Button_set_tooltip (&free_button->Button, __, is->c3x_labels[CL_SB_TOOLTIP]); - free_button->Button.field_5FC[13] = bombard_button->Button.field_5FC[13]; - free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); -} - -void -init_district_command_buttons () -{ - if (is_online_game () || is->dc_btn_img_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) - for (int n = 0; n < 4; n++) - Sprite_construct (&is->district_btn_img_sets[dc].imgs[n]); - - char temp_path[2*MAX_PATH]; - - is->dc_btn_img_state = IS_INIT_FAILED; - - // For each button sprite type (normal, rollover, highlighted, alpha) - char const * filenames[4] = { - "Districts\\WorkerDistrictButtonsNorm.pcx", "Districts\\WorkerDistrictButtonsRollover.pcx", - "Districts\\WorkerDistrictButtonsHighlighted.pcx", "Districts\\WorkerDistrictButtonsAlpha.pcx" - }; - for (int n = 0; n < 4; n++) { - get_mod_art_path (filenames[n], temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load work district command buttons sprite sheet.\n"); - for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) - for (int k = 0; k < 4; k++) { - Sprite * sprite = &is->district_btn_img_sets[dc].imgs[k]; - sprite->vtable->destruct (sprite, __, 0); - } - pcx.vtable->destruct (&pcx, __, 0); - - char ss[200]; - snprintf (ss, sizeof ss, "[C3X] Failed to load district command button images from %s", temp_path); - pop_up_in_game_error (ss); - - return; - } - - // For each district type - int district_count = is->district_count; - if (district_count > COUNT_DISTRICT_TYPES) - district_count = COUNT_DISTRICT_TYPES; - for (int dc = 0; dc < district_count; dc++) { - int x = 32 * is->district_configs[dc].btn_tile_sheet_column, - y = 32 * is->district_configs[dc].btn_tile_sheet_row; - Sprite_slice_pcx (&is->district_btn_img_sets[dc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); - } - - pcx.vtable->clear_JGL (&pcx); - } - - is->dc_btn_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -int -parse_turns_from_tooltip (char const * tooltip) -{ - if ((tooltip == NULL) || (*tooltip == '\0')) - return -1; - - char const * last_paren = NULL; - for (char const * cursor = tooltip; *cursor != '\0'; cursor++) - if (*cursor == '(') - last_paren = cursor; - if (last_paren == NULL) - return -1; - - char const * digit_ptr = last_paren + 1; - while (*digit_ptr == ' ') - digit_ptr++; - - int turns = 0; - bool have_digit = false; - while ((*digit_ptr >= '0') && (*digit_ptr <= '9')) { - have_digit = true; - turns = (turns * 10) + (*digit_ptr - '0'); - digit_ptr++; - } - return have_digit ? turns : -1; -} - -void -compute_highlighted_worker_tiles_for_districts () -{ - if (is_online_game () - || ! is->current_config.enable_districts - || ! is->current_config.enable_city_work_radii_highlights) - return; - - Unit * selected_unit = p_main_screen_form->Current_Unit; - if (selected_unit == NULL) - return; - - int unit_type_id = selected_unit->Body.UnitTypeID; - if (p_bic_data->UnitTypes[unit_type_id].Worker_Actions == 0) - return; - - if (is->tile_highlight_state == IS_UNINITED) - init_tile_highlights (); - if (is->tile_highlight_state != IS_OK) - return; - - int worker_civ_id = selected_unit->Body.CivID; - if ((p_cities == NULL) || (p_cities->Cities == NULL)) - return; - - // Loop over all cities owned by this civ and tally their workable tiles - FOR_CITIES_OF (coi, worker_civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - - // Highlight city center so players can easily see which cities contribute - Tile * city_center_tile = tile_at (city->Body.X, city->Body.Y); - if ((city_center_tile != NULL) && (city_center_tile != p_null_tile)) { - int stored_ptr; - if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, &stored_ptr)) { - struct highlighted_city_radius_tile_info * info = malloc (sizeof (struct highlighted_city_radius_tile_info)); - info->highlight_level = 0; - itable_insert (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, (int)info); - } - } - - // Add all workable tiles around the city (excluding city center) - for (int n = 1; n < is->workable_tile_count; n++) { - int dx, dy; - patch_ni_to_diff_for_work_area (n, &dx, &dy); - int tile_x = city->Body.X + dx; - int tile_y = city->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - - Tile * workable_tile = tile_at (tile_x, tile_y); - if ((workable_tile == NULL) || (workable_tile == p_null_tile)) continue; - if (workable_tile->vtable->m38_Get_Territory_OwnerID (workable_tile) != worker_civ_id) continue; - - // Upsert into highlighted_city_radius_tile_pointers - int stored_ptr; - struct highlighted_city_radius_tile_info * info; - if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, &stored_ptr)) { - info = malloc (sizeof (struct highlighted_city_radius_tile_info)); - info->highlight_level = 0; - itable_insert (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, (int)info); - } else { - info = (struct highlighted_city_radius_tile_info *)stored_ptr; - info->highlight_level += 3; - } - } - } -} - -void -set_up_district_buttons (Main_GUI * this) -{ - if (is_online_game () || ! is->current_config.enable_districts) return; - if (is->dc_btn_img_state == IS_UNINITED) init_district_command_buttons (); - if (is->dc_btn_img_state != IS_OK) return; - - Unit * selected_unit = p_main_screen_form->Current_Unit; - if (selected_unit == NULL || ! is_worker(selected_unit)) return; - - Tile * tile = tile_at (selected_unit->Body.X, selected_unit->Body.Y); - if ((tile == NULL) || (tile == p_null_tile) || (tile->CityID >= 0)) return; - - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - if (tile->vtable->m21_Check_Crates (tile, __, 0)) return; - if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return; - - Command_Button * fortify_button = NULL; - int i_starting_button; - int mine_turns = -1; - for (int n = 0; n < 42; n++) { - if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && - (this->Unit_Command_Buttons[n].Command == UCV_Fortify)) { - fortify_button = &this->Unit_Command_Buttons[n]; - i_starting_button = n; - } - if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { - mine_turns = parse_turns_from_tooltip (this->Unit_Command_Buttons[n].Button.ToolTip); - } - if (fortify_button != NULL && mine_turns >= 0) - break; - } - - if (fortify_button == NULL) - return; - - i_starting_button = -1; - - // Check if there's already a district on this tile. If so, and the unit can build mines, - // ensure the mine button is enabled so the worker can continue construction. - int existing_district_id = -1; - struct district_instance * existing_inst = get_district_instance (tile); - if (existing_inst != NULL) { - existing_district_id = existing_inst->district_id; - if (is->current_config.enable_natural_wonders && existing_inst->district_id == NATURAL_WONDER_DISTRICT_ID) { - return; - } - if (patch_Unit_can_perform_command(selected_unit, __, UCV_Build_Mine)) { - for (int n = 0; n < 42; n++) { - if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { - Command_Button * mine_button = &this->Unit_Command_Buttons[n]; - if (base_type == SQ_Coast) { - mine_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&mine_button->Button); - break; - } - if ((mine_button->Button.Base_Data.Status2 & 1) == 0) { - mine_button->Button.field_5FC[13] = 0; - mine_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&mine_button->Button, __, 0); - } - break; - } - } - } - } - - bool district_completed = district_is_complete (tile, existing_district_id); - - // First pass: collect which district types should be shown - int active_districts[COUNT_DISTRICT_TYPES]; - int active_count = 0; - - for (int dc = 0; dc < is->district_count; dc++) { - - if (is->district_configs[dc].command == -1) - continue; - - bool already_building = false; - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if (unit != NULL && is_worker(unit) && existing_inst != NULL && existing_inst->district_id == dc) { - // If there's a worker on the tile and it's building this district, - // show the button so more workers can contribute. This works around an - // issue where a specific district requiring irrigation no longer - // is buildable by other workers because initial construction removes the - // required irrigation overlay upon construction start - already_building = true; - break; - } - } - - if (existing_district_id == dc && district_completed) continue; - if ((existing_district_id >= 0) && (existing_district_id != dc) && (! district_completed)) continue; - - if (! can_build_district_on_tile (tile, dc, selected_unit->Body.CivID) && ! already_building) - continue; - - // This district should be shown - active_districts[active_count++] = dc; - } - - - if (active_count == 0) - return; - - // Calculate centered starting position - // For odd counts, center perfectly; for even counts, favor left of center - int center_pos = 6; - i_starting_button = center_pos - (active_count / 2); - if (i_starting_button < 0) - i_starting_button = 0; - - // Second pass: render the buttons - for (int idx = 0; idx < active_count; idx++) { - int dc = active_districts[idx]; - - Command_Button * free_button = NULL; - for (int n = i_starting_button; n < 42; n++) { - if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { - free_button = &this->Unit_Command_Buttons[n]; - i_starting_button = n + 1; - break; - } - } - - if (free_button == NULL) - return; - - // Set up free button for creating district - free_button->Command = is->district_configs[dc].command; - - // Replace the button's image with the district image. Disabling & re-enabling and - // clearing field_5FC[13] are all necessary to trigger a redraw. - free_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&free_button->Button); - free_button->field_6D8 = fortify_button->field_6D8; - for (int k = 0; k < 4; k++) - free_button->Button.Images[k] = &is->district_btn_img_sets[dc].imgs[k]; - free_button->Button.field_664 = fortify_button->Button.field_664; - if (mine_turns >= 0) { - char tooltip[256]; - char const * turn_word = (mine_turns == 1) ? "turn" : "turns"; - snprintf (tooltip, sizeof tooltip, "%s (%d %s)", is->district_configs[dc].tooltip, mine_turns, turn_word); - tooltip[(sizeof tooltip) - 1] = '\0'; - Button_set_tooltip (&free_button->Button, __, tooltip); - } else - Button_set_tooltip (&free_button->Button, __, (char *)is->district_configs[dc].tooltip); - free_button->Button.field_5FC[13] = 0; - free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); - } -} - -void -set_up_stack_worker_buttons (Main_GUI * this) -{ - if ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // (control key is not down OR - (! is->current_config.enable_stack_unit_commands) || // stack worker commands not enabled OR - is_online_game ()) // is online game - return; - - init_stackable_command_buttons (); - if (is->sc_img_state != IS_OK) - return; - - // For each unit command button - for (int n = 0; n < 42; n++) { - Command_Button * cb = &this->Unit_Command_Buttons[n]; - - // If it's enabled and not a bombard button (those are handled in the function above) - if (((cb->Button.Base_Data.Status2 & 1) != 0) && - (cb->Command != UCV_Bombard) && (cb->Command != UCV_Bombing)) { - - // Find the stackable worker command that this button controls, if there is one, and check that - // the button isn't already showing the stack image for that command. Note: this check is important - // b/c this function gets called repeatedly while the CTRL key is held down. - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - if ((cb->Command == sc_button_infos[sc].command) && - (cb->Button.Images[0] != &is->sc_button_image_sets[sc].imgs[0])) { - - // Replace the button's image with the stack image. Disabling & re-enabling and - // clearing field_5FC[13] are all necessary to trigger a redraw. - cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); - for (int k = 0; k < 4; k++) - cb->Button.Images[k] = &is->sc_button_image_sets[sc].imgs[k]; - cb->Button.field_5FC[13] = 0; - cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); - - break; - } - } - } -} - -CityLocValidity __fastcall patch_Map_check_city_location (Map * this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile); - -void __fastcall -patch_Main_GUI_set_up_unit_command_buttons (Main_GUI * this) -{ - // Recompute resources now if needed because of a trade deal involving mill inputs. In rare cases the change in deals might affect a mill that - // produces a resource that's used for a worker job. - recompute_resources_if_necessary (); - - Main_GUI_set_up_unit_command_buttons (this); - set_up_stack_bombard_buttons (this); - set_up_stack_worker_buttons (this); - - if (is->current_config.enable_districts) { - set_up_district_buttons (this); - } - - // If the minimum city separation is increased, then gray out the found city button if we're too close to another city. - if ((is->current_config.minimum_city_separation > 1) && (p_main_screen_form->Current_Unit != NULL) && (is->disabled_command_img_state == IS_OK)) { - Unit_Body * selected_unit = &p_main_screen_form->Current_Unit->Body; - - // For each unit command button - for (int n = 0; n < 42; n++) { - Command_Button * cb = &this->Unit_Command_Buttons[n]; - - // If it's enabled, set to city founding, and the current city location is too close to another city - if (((cb->Button.Base_Data.Status2 & 1) != 0) && - (cb->Command == UCV_Build_City) && - (patch_Map_check_city_location (&p_bic_data->Map, __, selected_unit->X, selected_unit->Y, selected_unit->CivID, false) == CLV_CITY_TOO_CLOSE)) { - - // Replace the button's image with the disabled image, as in set_up_stack_worker_buttons. - cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); - for (int k = 0; k < 3; k++) - cb->Button.Images[k] = &is->disabled_build_city_button_img; - cb->Button.field_5FC[13] = 0; - - char tooltip[200]; { - memset (tooltip, 0, sizeof tooltip); - char * label = is->c3x_labels[CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP], - * to_replace = "$NUM0", - * replace_location = strstr (label, to_replace); - if (replace_location != NULL) - snprintf (tooltip, sizeof tooltip, "%.*s%d%s", replace_location - label, label, is->current_config.minimum_city_separation, replace_location + strlen (to_replace)); - else - snprintf (tooltip, sizeof tooltip, "%s", label); - tooltip[(sizeof tooltip) - 1] = '\0'; - } - Button_set_tooltip (&cb->Button, __, tooltip); - - cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); - - } - } - } -} - -void -clear_highlighted_worker_tiles_and_redraw () -{ - clear_highlighted_worker_tiles_for_districts (); - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -void -check_happiness_at_end_of_turn () -{ - int num_unhappy_cities = 0; - City * first_unhappy_city = NULL; - FOR_CITIES_OF (coi, p_main_screen_form->Player_CivID) { - City_recompute_happiness (coi.city); - int num_happy = 0, num_unhappy = 0; - FOR_CITIZENS_IN (ci, coi.city) { - num_happy += ci.ctzn->Body.Mood == CMT_Happy; - num_unhappy += ci.ctzn->Body.Mood == CMT_Unhappy; - } - if (num_unhappy > num_happy) { - num_unhappy_cities++; - if (first_unhappy_city == NULL) - first_unhappy_city = coi.city; - } - } - - if (first_unhappy_city != NULL) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, first_unhappy_city->Body.CityName, -1, -1); - if (num_unhappy_cities > 1) - set_popup_int_param (1, num_unhappy_cities - 1); - char * key = (num_unhappy_cities > 1) ? "C3X_DISORDER_WARNING_MULTIPLE" : "C3X_DISORDER_WARNING_ONE"; - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, key, -1, 0, 0, 0); - int response = patch_show_popup (popup, __, 0, 0); - - if (response == 2) { // zoom to city - p_main_screen_form->turn_end_flag = 1; - City_zoom_to (first_unhappy_city, __, 0); - } else if (response == 1) // just cancel turn end - p_main_screen_form->turn_end_flag = 1; - // else do nothing, let turn end - - } -} - -void -do_trade_scroll (DiploForm * diplo, int forward) -{ - int increment = forward ? 1 : -1; - int id = -1; - for (int n = (diplo->other_party_civ_id + increment) & 31; n != diplo->other_party_civ_id; n = (n + increment) & 31) - if ((n != 0) && // if N is not barbs AND - (n != p_main_screen_form->Player_CivID) && // N is not the player's AND - (*p_player_bits & (1U << n)) && // N belongs to an active player AND - (leaders[p_main_screen_form->Player_CivID].Contacts[n] & 1) && // N has contact with the player AND - Leader_ai_would_meet_with (&leaders[n], __, p_main_screen_form->Player_CivID)) { // AI is willing to meet - id = n; - break; - } - - if (id >= 0) { - is->trade_screen_scroll_to_id = id; - DiploForm_close (diplo); - // Note extra code needs to get run here if the other player is not an AI - } -} - -void __fastcall -patch_DiploForm_m82_handle_key_event (DiploForm * this, int edx, int virtual_key_code, int is_down) -{ - if (is->eligible_for_trade_scroll && - (this->mode == 2) && - ((virtual_key_code == VK_LEFT) || (virtual_key_code == VK_RIGHT)) && - (! is_down)) - do_trade_scroll (this, virtual_key_code == VK_RIGHT); - else - DiploForm_m82_handle_key_event (this, __, virtual_key_code, is_down); -} - -int __fastcall -patch_DiploForm_m68_Show_Dialog (DiploForm * this, int edx, int param_1, void * param_2, void * param_3) -{ - if (is->open_diplo_form_straight_to_trade) { - is->open_diplo_form_straight_to_trade = 0; - - // Done by the base game but not necessary as far as I can tell - // void (__cdecl * FUN_00537700) (int) = 0x537700; - // FUN_00537700 (0x15); - // this->field_E9C[0] = this->field_E9C[0] + 1; - - // Set diplo screen mode to two-way trade negotation - this->mode = 2; - - // Set AI's diplo message to something like "what did you have in mind" - int iVar35 = DiploForm_set_their_message (this, __, DM_AI_PROPOSAL_RESPONSE, 0, 0x1A8); - this->field_1390[0] = DM_AI_PROPOSAL_RESPONSE; - this->field_1390[1] = 0; - this->field_1390[2] = iVar35; - - // Reset player message options. This will replace the propose deal, declare war, and leave options with the usual "nevermind" option - // that appears for negotiations. - DiploForm_reset_our_message_choices (this); - - // Done by the base game but not necessary as far as I can tell - // void (__fastcall * FUN_004C89A0) (void *) = 0x4C89A0; - // FUN_004C89A0 (&this->field_1BF4[0]); - - } - - return DiploForm_m68_Show_Dialog (this, __, param_1, param_2, param_3); -} - -void __fastcall -patch_DiploForm_do_diplomacy (DiploForm * this, int edx, int diplo_message, int param_2, int civ_id, int do_not_request_audience, int war_negotiation, int disallow_proposal, TradeOfferList * our_offers, TradeOfferList * their_offers) -{ - is->open_diplo_form_straight_to_trade = 0; - is->trade_screen_scroll_to_id = -1; - - // Trade screen scroll is disabled in online games b/c there's extra synchronization we'd need to do to open or close the diplo screen with - // a human player. - is->eligible_for_trade_scroll = is->current_config.enable_trade_screen_scroll && (! is_online_game ()); - - if (is->eligible_for_trade_scroll && (is->trade_scroll_button_state == IS_UNINITED)) - init_trade_scroll_buttons (this); - - WITH_PAUSE_FOR_POPUP { - DiploForm_do_diplomacy (this, __, diplo_message, param_2, civ_id, do_not_request_audience, war_negotiation, disallow_proposal, our_offers, their_offers); - - while (is->trade_screen_scroll_to_id >= 0) { - int scroll_to_id = is->trade_screen_scroll_to_id; - is->trade_screen_scroll_to_id = -1; - is->open_diplo_form_straight_to_trade = 1; - DiploForm_do_diplomacy (this, __, DM_AI_COUNTER, 0, scroll_to_id, 1, 0, 0, NULL, NULL); - } - } - - is->open_diplo_form_straight_to_trade = 0; - is->eligible_for_trade_scroll = 0; -} - -void __fastcall -patch_DiploForm_m22_Draw (DiploForm * this) -{ - if (is->trade_scroll_button_state == IS_OK) { - Button * left = is->trade_scroll_button_left, - * right = is->trade_scroll_button_right; - if (is->eligible_for_trade_scroll && (this->mode == 2)) { - left ->vtable->m01_Show_Enabled ((Base_Form *)left , __, 0); - right->vtable->m01_Show_Enabled ((Base_Form *)right, __, 0); - left ->vtable->m73_call_m22_Draw ((Base_Form *)left); - right->vtable->m73_call_m22_Draw ((Base_Form *)right); - } else { - left ->vtable->m02_Show_Disabled ((Base_Form *)left); - right->vtable->m02_Show_Disabled ((Base_Form *)right); - } - } - - DiploForm_m22_Draw (this); -} - -void -intercept_end_of_turn () -{ - if (is->current_config.enable_disorder_warning) { - check_happiness_at_end_of_turn (); - if (p_main_screen_form->turn_end_flag == 1) // Check if player cancelled turn ending in the disorder warning popup - return; - } - - // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - - if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { - is->city_loc_display_perspective = -1; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw - } - - // Clear things that don't apply across turns - is->have_job_and_loc_to_skip = 0; -} - -bool -is_worker_or_settler_command (int unit_command_value) -{ - return (unit_command_value & 0x20000000) || - ((unit_command_value >= UCV_Build_Remote_Colony) && (unit_command_value <= UCV_Auto_Save_Tiles)); -} - -bool -command_would_replace_district (int unit_command_value) -{ - // Note: Roads & railroads, etc. can coexist with the district - return (unit_command_value == UCV_Build_Mine) || - (unit_command_value == UCV_Irrigate) || - (unit_command_value == UCV_Plant_Forest) || - (unit_command_value == UCV_Build_Outpost) || - (unit_command_value == UCV_Build_Fortress) || - (unit_command_value == UCV_Build_Barricade) || - (unit_command_value == UCV_Build_Airfield) || - (unit_command_value == UCV_Build_Radar_Tower) || - (unit_command_value == UCV_Build_Colony); -} - -bool -handle_worker_command_that_may_replace_district (Unit * unit, int unit_command_value, bool * removed_existing) -{ - if (removed_existing != NULL) - *removed_existing = false; - - if ((! is->current_config.enable_districts) || (unit == NULL)) return true; - if (! is_worker_or_settler_command (unit_command_value)) return true; - if (! command_would_replace_district (unit_command_value)) return true; - if (! patch_Unit_can_perform_command (unit, __, unit_command_value)) return true; - - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - if ((tile == NULL) || (tile == p_null_tile)) - return true; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (! district_is_complete (tile, inst->district_id))) - return true; - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - return false; - - int district_id = inst->district_id; - int civ_id = unit->Body.CivID; - bool redundant_district = district_instance_is_redundant (inst, tile); - bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (district_id, civ_id, tile_x, tile_y); - if (redundant_district) - would_lose_buildings = false; - - bool remove_existing = redundant_district; - if (inst != NULL && district_id >= 0 && district_id < is->district_count) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char *)is->district_configs[district_id].display_name, -1, -1); - set_popup_str_param (1, (char *)is->district_configs[district_id].display_name, -1, -1); - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - would_lose_buildings - ? "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT" - : "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT_SAFE", - -1, 0, 0, 0); - int sel = patch_show_popup (popup, __, 0, 0); - if (sel != 0) - return false; - remove_existing = true; - } - - if (remove_existing) { - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - handle_district_removed (tile, district_id, tile_x, tile_y, false); - if (removed_existing != NULL) - *removed_existing = true; - } - - return true; -} - -bool __fastcall - patch_Unit_can_upgrade (Unit * this) -{ - bool base = Unit_can_upgrade (this); - int available; - City * city = city_at (this->Body.X, this->Body.Y); - if (base && - (city != NULL) && - get_available_unit_count (&leaders[this->Body.CivID], City_get_upgraded_type_id (city, __, this->Body.UnitTypeID), &available) && - (available <= 0)) - return false; - else - return base; -} - -bool -is_district_command (int unit_command_value) -{ - int district_id = -1; - if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) - return false; - - return district_id != NATURAL_WONDER_DISTRICT_ID; -} - -int __fastcall -patch_Map_check_colony_location (Map * this, int edx, int tile_x, int tile_y, int civ_id) -{ - int base = Map_check_colony_location (this, __, tile_x, tile_y, civ_id); - Tile * tile = tile_at (tile_x, tile_y); - - if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.allow_extraterritorial_colonies) - return base; - - if (tile->vtable->m35_Check_Is_Water (tile)) return base; - if (Tile_has_city (tile) || Tile_has_colony (tile)) return base; - - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_id < 0) || (owner_id == civ_id)) return base; - - int resource_type = Tile_get_resource_visible_to (tile, __, civ_id); - if ((resource_type < 0) || (resource_type >= p_bic_data->ResourceTypeCount)) return base; - - int req_tech = p_bic_data->ResourceTypes[resource_type].RequireID; - if ((req_tech >= 0) && (! Leader_has_tech (&leaders[civ_id], __, req_tech))) return base; - - int res_class = p_bic_data->ResourceTypes[resource_type].Class; - if ((res_class != RC_Strategic) && (res_class != RC_Luxury)) return base; - if (tile->vtable->m26_Check_Tile_Building (tile)) - return 6; - - return 0; -} - -bool __fastcall -patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value) -{ - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - // No worker or settler commands allowed on natural wonders - if ((tile != NULL) && (tile != p_null_tile) && is->current_config.enable_natural_wonders) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && - (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) { - if (is_worker_or_settler_command (unit_command_value) || is_district_command (unit_command_value)) - return false; - } - } - - if (is_district_command (unit_command_value)) { - int district_id; - if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) - return false; - - return is_worker (this) && can_build_district_on_tile (tile, district_id, this->Body.CivID); - } - // Extra check for colony founding if extraterritorial colonies allowed - else if (unit_command_value == UCV_Build_Colony || unit_command_value == UCV_Build_Remote_Colony) { - if (is->current_config.allow_extraterritorial_colonies && is_worker (this)) { - return patch_Map_check_colony_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID) == 0; - } - } - // Extra check for road building if bridge districts allowed - else if (unit_command_value == UCV_Build_Road) { - struct district_instance * inst = get_district_instance (tile); - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - if (!has_road && (inst != NULL) && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) - return true; - } - // Extra check for railroad building if bridge districts allowed - else if (unit_command_value == UCV_Build_Railroad) { - struct district_instance * inst = get_district_instance (tile); - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; - if ((inst != NULL) && is_worker (this) && has_road && - ! has_rail && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) { - int req_tech = p_bic_data->WorkerJobs[WJ_Build_Railroad].RequireID; - if ((req_tech < 0) || - ((req_tech != p_bic_data->AdvanceCount) && - Leader_has_tech (&leaders[this->Body.CivID], __, req_tech))) { - if (Leader_has_resources_for_job_at (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y)) - return true; - } - } - } - else if (unit_command_value == UCV_Build_Mine) { - bool has_district = (tile != NULL) && (tile != p_null_tile) && (get_district_instance (tile) != NULL); - - if (has_district) { - return Tile_get_mining_bonus (tile) > 0; - } - } else if (unit_command_value == UCV_Pillage) { - return patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y); - } - } - if (is->current_config.disable_worker_automation && - (this->Body.CivID == p_main_screen_form->Player_CivID) && - (unit_command_value == UCV_Automate)) - return false; - else if (is->current_config.disallow_land_units_from_affecting_water_tiles && - is_worker_or_settler_command (unit_command_value)) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - enum UnitTypeClasses class = p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class; - return ((class != UTC_Land) || (! tile->vtable->m35_Check_Is_Water (tile))) && - Unit_can_perform_command (this, __, unit_command_value); - } - - return Unit_can_perform_command (this, __, unit_command_value); -} - -void __fastcall -patch_Unit_join_city (Unit * this, int edx, City * city) -{ - if (is->current_config.enable_districts && is_worker (this)) { - int civ_id = this->Body.CivID; - bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; - if (! is_human) { - struct district_worker_record * rec = get_tracked_worker_record (this); - if ((rec != NULL) && (rec->pending_req != NULL)) { - ai_move_district_worker (this, rec); - return; - } - - Tile * worker_tile = tile_at (this->Body.X, this->Body.Y); - if ((worker_tile != NULL) && (worker_tile != p_null_tile)) { - int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); - - if ((civ_id >= 0) && (civ_id < 32)) { - struct pending_district_request * same_city_req = NULL; - struct pending_district_request * same_continent_req = NULL; - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req == NULL) || (req->assigned_worker_id >= 0)) - continue; - if ((req->civ_id != civ_id) || (req->city_id < 0)) - continue; - - City * req_city = get_city_ptr (req->city_id); - if (req_city == NULL) - continue; - - if (city != NULL && req_city->Body.ID == city->Body.ID) { - same_city_req = req; - break; - } - - Tile * req_city_tile = tile_at (req_city->Body.X, req_city->Body.Y); - if ((req_city_tile != NULL) && (req_city_tile != p_null_tile)) { - int req_continent_id = req_city_tile->vtable->m46_Get_ContinentID (req_city_tile); - if (req_continent_id == worker_continent_id) { - same_continent_req = req; - } - } - } - - struct pending_district_request * chosen_req = (same_city_req != NULL) ? same_city_req : same_continent_req; - if (chosen_req != NULL) { - City * req_city = get_city_ptr (chosen_req->city_id); - if (req_city != NULL) { - int target_x = 0; - int target_y = 0; - Tile * target_tile = find_tile_for_district (req_city, chosen_req->district_id, &target_x, &target_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); - assign_worker_to_district (chosen_req, this, req_city, chosen_req->district_id, target_x, target_y); - return; - } - } - } - } - } - } - } - - Unit_join_city (this, __, city); -} - -bool __fastcall -patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y) -{ - bool base = Unit_can_pillage (this, __, tile_x, tile_y); - - if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return base; - - int district_id = inst->district_id; - if (is->current_config.enable_natural_wonders && - (district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) - return false; - - if (! district_is_complete (tile, district_id)) - return true; - - if (district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info == NULL || info->state != WDS_COMPLETED) - return true; - return is->current_config.completed_wonder_districts_can_be_destroyed; - } - - return true; -} - -bool __fastcall -patch_Unit_can_do_worker_command_for_button_setup (Unit * this, int edx, int unit_command_value) -{ - bool base = patch_Unit_can_perform_command (this, __, unit_command_value); - - // If the command is to build a city and it can't be done because another city is already too close, and the minimum separation was changed - // from its standard value, then return true here so that the build city button will be added anyway. We'll gray it out later. Check that the - // grayed out button image is initialized now so we don't activate the build city button then find out later we can't gray it out. - if ((! base) && - (unit_command_value == UCV_Build_City) && - (is->current_config.minimum_city_separation > 1) && - (patch_Map_check_city_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID, false) == CLV_CITY_TOO_CLOSE) && - (init_disabled_command_buttons (), is->disabled_command_img_state == IS_OK)) - return true; - - else - return base; -} - -int -compare_helpers (void const * vp_a, void const * vp_b) -{ - Unit * a = get_unit_ptr (*(int *)vp_a), - * b = get_unit_ptr (*(int *)vp_b); - if ((a != NULL) && (b != NULL)) { - // Compute how many movement points each has left (ML = moves left) - int ml_a = patch_Unit_get_max_move_points (a) - a->Body.Moves, - ml_b = patch_Unit_get_max_move_points (b) - b->Body.Moves; - - // Whichever one has more MP left comes first in the array - if (ml_a > ml_b) return 1; - else if (ml_b > ml_a) return -1; - else return 0; - } else - // If at least one of the unit ids is invalid, might as well sort it later in the array - return (a != NULL) ? -1 : ((b != NULL) ? 1 : 0); -} - -void -issue_stack_worker_command (Unit * unit, int command) -{ - int tile_x = unit->Body.X; - int tile_y = unit->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - int unit_type_id = unit->Body.UnitTypeID; - int unit_id = unit->Body.ID; - - // Put together a list of helpers and store it on the memo. Helpers are just other workers on the same tile that can be issued the same command. - clear_memo (); - FOR_UNITS_ON (uti, tile) - if ((uti.id != unit_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) { - // check if the clicked command is among worker actions that this unit type can perform - int actions = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Worker_Actions; - int command_without_category = command & 0x0FFFFFFF; - if ((actions & command_without_category) == command_without_category) - memoize (uti.id); - } - - // Sort the list of helpers so that the ones with the fewest remaining movement points are listed first. - qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_helpers); - - Unit * next_up = unit; - int i_next_helper = 0; - int last_action_didnt_happen; - do { - int state_before_action = next_up->Body.UnitState; - Main_Screen_Form_issue_command (p_main_screen_form, __, command, next_up); - last_action_didnt_happen = (next_up->Body.UnitState == state_before_action); - - // Call this update function to cause the worker to actually perform the action. Otherwise - // it only gets queued, the worker keeps is movement points, and the action doesn't get done - // until the interturn. - if (! last_action_didnt_happen) - next_up->vtable->update_while_active (next_up); - - next_up = NULL; - while ((i_next_helper < is->memo_len) && (next_up == NULL)) - next_up = get_unit_ptr (is->memo[i_next_helper++]); - } while ((next_up != NULL) && (! last_action_didnt_happen)); -} - -void -issue_district_worker_command (Unit * unit, int command) -{ - if (! is->current_config.enable_districts) - return; - - if (unit == NULL) - return; - - int tile_x = unit->Body.X; - int tile_y = unit->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return; - - if (! is_worker(unit)) - return; - - int district_id = -1; - if (! itable_look_up (&is->command_id_to_district_id, command, &district_id)) - return; - if ((district_id < 0) || (district_id >= is->district_count)) - return; - - if (! leader_can_build_district (&leaders[unit->Body.CivID], district_id)) - return; - - // Disallow placing districts on invalid terrain, pollution, or cratered tiles - if (tile->vtable->m21_Check_Crates (tile, __, 0)) - return; - if (tile->vtable->m20_Check_Pollution (tile, __, 0)) - return; - - if (! district_is_buildable_on_tile (&is->district_configs[district_id], tile)) - return; - - // If District will be replaced by another District - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete(tile, inst->district_id)) { - int existing_district_id = inst->district_id; - int inst_x, inst_y; - if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) - return; - - int civ_id = unit->Body.CivID; - bool redundant_district = district_instance_is_redundant (inst, tile); - bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, inst_x, inst_y); - if (redundant_district) - would_lose_buildings = false; - - bool remove_existing = false; - - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char*)is->district_configs[existing_district_id].display_name, -1, -1); - set_popup_str_param (1, (char*)is->district_configs[existing_district_id].display_name, -1, -1); - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - would_lose_buildings - ? "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT" - : "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT_SAFE", - -1, 0, 0, 0 - ); - - int sel = patch_show_popup (popup, __, 0, 0); - if (sel == 0) - remove_existing = true; - else - return; - - if (remove_existing) { - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); - handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); - } - } - - // If District will replace an improvement - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); - - if (removable_flags != 0) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_BUILD_DISTRICT_OVER_IMPROVEMENT", -1, 0, 0, 0); - int sel = patch_show_popup (popup, __, 0, 0); - if (sel != 0) - return; - } - - if (removable_flags != 0) - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - - inst = ensure_district_instance (tile, district_id, tile_x, tile_y); - inst->built_by_civ_id = unit->Body.CivID; - if (inst != NULL) - inst->state = DS_UNDER_CONSTRUCTION; - - Unit_set_state (unit, __, UnitState_Build_Mines); - unit->Body.Job_ID = WJ_Build_Mines; -} - -void -issue_stack_unit_mgmt_command (Unit * unit, int command) -{ - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - int unit_type_id = unit->Body.UnitTypeID; - int unit_id = unit->Body.ID; - - PopupForm * popup = get_popup_form (); - - clear_memo (); - - if (command == UCV_Fortify) { - // This probably won't work for online games since "fortify all" does additional work in that case. See Main_Screen_Form::fortify_all. - // I don't like how this method doesn't place units in the fortified pose. One workaround is so use - // Main_Screen_Form::issue_fortify_command, but that plays the entire fortify animation for each unit which is a major annoyance for - // large stacks. The base game's "fortify all" function also doesn't set the pose so I don't see any easy way to fix this. - FOR_UNITS_ON (uti, tile) - if ((uti.unit->Body.UnitTypeID == unit_type_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - (uti.unit->Body.CivID == unit->Body.CivID) && - (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) - Unit_set_state (uti.unit, __, UnitState_Fortifying); - - } else if (command == UCV_Upgrade_Unit) { - int our_treasury = leaders[unit->Body.CivID].Gold_Encoded + leaders[unit->Body.CivID].Gold_Decrement; - - // If the unit type we're upgrading to is limited, find out how many we can add. Keep that in "available". If the type is not limited, - // leave available set to INT_MAX. - int available = INT_MAX; { - City * city; - int upgrade_id; - if ((is->current_config.unit_limits.len > 0) && - patch_Unit_can_perform_command (unit, __, UCV_Upgrade_Unit) && - (NULL != (city = city_at (unit->Body.X, unit->Body.Y))) && - (0 < (upgrade_id = City_get_upgraded_type_id (city, __, unit_type_id)))) - get_available_unit_count (&leaders[unit->Body.CivID], upgrade_id, &available); - } - - int cost = 0; - FOR_UNITS_ON (uti, tile) - if ((available > 0) && - (uti.unit->Body.UnitTypeID == unit_type_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - patch_Unit_can_perform_command (uti.unit, __, UCV_Upgrade_Unit)) { - cost += Unit_get_upgrade_cost (uti.unit); - available--; - memoize (uti.id); - } - - if (cost <= our_treasury) { - set_popup_str_param (0, p_bic_data->UnitTypes[unit_type_id].Name, -1, -1); - set_popup_int_param (0, is->memo_len); - set_popup_int_param (1, cost); - popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "UPGRADE_ALL", -1, 0, 0, 0); - if (patch_show_popup (popup, __, 0, 0) == 0) - for (int n = 0; n < is->memo_len; n++) { - Unit * to_upgrade = get_unit_ptr (is->memo[n]); - if (to_upgrade != NULL) - Unit_upgrade (to_upgrade, __, false); - } - - } else { - set_popup_int_param (0, cost); - int param_5 = is_online_game () ? 0x4000 : 0; // As in base code - popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "NO_GOLD_TO_UPGRADE_ALL", -1, 0, param_5, 0); - patch_show_popup (popup, __, 0, 0); - } - - } else if (command == UCV_Disband) { - FOR_UNITS_ON (uti, tile) - if ((uti.unit->Body.UnitTypeID == unit_type_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) - memoize (uti.id); - - if (is->memo_len > 0) { - set_popup_int_param (0, is->memo_len); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_STACK_DISBAND", -1, 0, 0, 0); - if (patch_show_popup (popup, __, 0, 0) == 0) { - for (int n = 0; n < is->memo_len; n++) { - Unit * to_disband = get_unit_ptr (is->memo[n]); - if (to_disband) - Unit_disband (to_disband); - } - } - } - } -} - -void __fastcall -patch_Main_GUI_handle_button_press (Main_GUI * this, int edx, int button_id) -{ - // Set SB flag according to case (2) - if (button_id < 42) { - if ((is->sc_img_state == IS_OK) && - ((this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMBARD].imgs[0]) || - (this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMB ].imgs[0]))) - is->sb_activated_by_button = 1; - else - is->sb_activated_by_button = 0; - } - - int command = this->Unit_Command_Buttons[button_id].Command; - - // Clear any highlighted tiles - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - - if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { - is->city_loc_display_perspective = -1; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw - } - - // If a district, run district build logic - if (is->current_config.enable_districts && is_district_command (command)) { - clear_something_1 (); - Timer_clear (&this->timer_1); - issue_district_worker_command (p_main_screen_form->Current_Unit, command); - return; - } - - // Check if command is a worker build command (not a district) and a district exists on the tile - if (is->current_config.enable_districts && p_main_screen_form->Current_Unit != NULL) { - - bool removed_existing = false; - if (! handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) - return; - if (removed_existing) { - clear_something_1 (); - Timer_clear (&this->timer_1); - Main_GUI_handle_button_press (this, __, button_id); - return; - } - } - - struct sc_button_info const * stack_button_info; { - stack_button_info = NULL; - if (button_id < 42) // If button pressed was a unit command button - for (int n = 0; n < COUNT_STACKABLE_COMMANDS; n++) - if (command == sc_button_infos[n].command) { - stack_button_info = &sc_button_infos[n]; - break; - } - } - - if ((stack_button_info == NULL) || // If there's no stack command for the pressed button OR - (! is->current_config.enable_stack_unit_commands) || // stack unit commands are not enabled OR - (((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // CTRL key is not down OR - (p_main_screen_form->Current_Unit == NULL) || // no unit is selected OR - is_online_game ()) { // is online game - Main_GUI_handle_button_press (this, __, button_id); - return; - } - - enum stackable_command_kind kind = stack_button_info->kind; - if ((kind == SCK_TERRAFORM) || (kind == SCK_UNIT_MGMT)) { - // Replicate behavior of function we're replacing - clear_something_1 (); - Timer_clear (&this->timer_1); - - if (kind == SCK_TERRAFORM) - issue_stack_worker_command (p_main_screen_form->Current_Unit, stack_button_info->command); - else if (kind == SCK_UNIT_MGMT) - issue_stack_unit_mgmt_command (p_main_screen_form->Current_Unit, stack_button_info->command); - } else - Main_GUI_handle_button_press (this, __, button_id); -} - -bool __fastcall -patch_Main_Screen_Form_issue_command (Main_Screen_Form * this, int edx, int command, Unit * unit) -{ - Unit * target_unit = unit; - if (target_unit == NULL) - target_unit = this->Current_Unit; - - if (is->current_config.enable_districts) { - bool removed_existing = false; - if (! handle_worker_command_that_may_replace_district (target_unit, command, &removed_existing)) - return false; - } - - return Main_Screen_Form_issue_command (this, __, command, unit); -} - -bool -is_command_button_active (Main_GUI * main_gui, enum Unit_Command_Values command) -{ - Command_Button * buttons = main_gui->Unit_Command_Buttons; - for (int n = 0; n < 42; n++) - if (((buttons[n].Button.Base_Data.Status2 & 1) != 0) && (buttons[n].Command == command)) - return true; - return false; -} - -int __fastcall -patch_Main_Screen_Form_handle_key_down (Main_Screen_Form * this, int edx, int char_code, int virtual_key_code) -{ - // Set SB flag according to case (4) - int precision_strike_is_available = is_command_button_active (&this->GUI, UCV_Precision_Bombing); - if ((virtual_key_code == VK_B) || (precision_strike_is_available && (virtual_key_code == VK_P))) - is->sb_activated_by_button = 0; - - if ((virtual_key_code & 0xFF) == VK_CONTROL) { - set_up_stack_worker_buttons (&this->GUI); - - if (is->current_config.enable_city_work_radii_highlights && - ! is->highlight_city_radii) { - Unit * unit = p_main_screen_form->Current_Unit; - if (unit != NULL) { - is->highlight_city_radii = true; - compute_highlighted_worker_tiles_for_districts (); - this->vtable->m73_call_m22_Draw ((Base_Form *)this); - } - } - } else { - if (is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - } - - char original_turn_end_flag = this->turn_end_flag; - int tr = Main_Screen_Form_handle_key_down (this, __, char_code, virtual_key_code); - if ((original_turn_end_flag == 1) && (this->turn_end_flag == 0)) - intercept_end_of_turn (); - - return tr; -} - -int -patch_handle_cursor_change_in_jgl () -{ - // Set SB flag according to case (3) and the annoying state - if ((is->sb_activated_by_button != 2) && - (p_main_screen_form->Mode_Action != UMA_Bombard) && - (p_main_screen_form->Mode_Action != UMA_Air_Bombard)) - is->sb_activated_by_button = 0; - - return handle_cursor_change_in_jgl (); -} - -void __fastcall -patch_Main_Screen_Form_handle_left_click_on_map_1 (Main_Screen_Form * this, int edx, int param_1, int param_2) -{ - if (is->sb_activated_by_button == 1) - is->sb_activated_by_button = 2; - Main_Screen_Form_handle_left_click_on_map_1 (this, __, param_1, param_2); - is->sb_activated_by_button = 0; -} - - -void __fastcall -patch_Main_GUI_handle_click_in_status_panel (Main_GUI * this, int edx, int mouse_x, int mouse_y) -{ - char original_turn_end_flag = p_main_screen_form->turn_end_flag; - Main_GUI_handle_click_in_status_panel (this, __, mouse_x, mouse_y); - if ((original_turn_end_flag == 1) && (p_main_screen_form->turn_end_flag == 0)) - intercept_end_of_turn (); -} - -// Gets effective shields generated per turn, including civil engineers, disorder, and anarchy. -int -get_city_production_rate (City * city, enum City_Order_Types order_type, int order_id) -{ - int in_disorder = city->Body.Status & CSF_Civil_Disorder, - in_anarchy = p_bic_data->Governments[leaders[city->Body.CivID].GovernmentType].b_Transition_Type, - getting_tile_shields = (! in_disorder) && (! in_anarchy); - - if (order_type == COT_Improvement) { - int building_wealth = (p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0; - int specialist_shields = 0; - FOR_CITIZENS_IN (ci, city) - if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) // I don't know what is check is for but it's done in the base code - specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; - return (getting_tile_shields ? city->Body.ProductionIncome : 0) + ((! building_wealth) ? specialist_shields : 0); - } else if ((order_type == COT_Unit) && getting_tile_shields) - return city->Body.ProductionIncome; - else - return 0; -} - -void __fastcall -patch_City_Form_open (City_Form * this, int edx, City * city, int param_2) -{ - recompute_resources_if_necessary (); - - WITH_PAUSE_FOR_POPUP { - City_Form_open (this, __, city, param_2); - } -} - -void -init_district_icons () -{ - if (is->dc_icons_img_state != IS_UNINITED) - return; - - char ss[200]; - snprintf (ss, sizeof ss, "[C3X] init_district_icons: state=%d\n", is->dc_icons_img_state); - (*p_OutputDebugStringA) (ss); - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("Districts/DistrictIncomeIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image == NULL) || - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { - (*p_OutputDebugStringA) ("[C3X] PCX file for district icons failed to load or is too small.\n"); - is->dc_icons_img_state = IS_INIT_FAILED; - goto cleanup; - } - - // Extract science icon (index 1) - Sprite_construct (&is->district_science_icon); - Sprite_slice_pcx (&is->district_science_icon, __, &pcx, 1 + 1*31, 1, 30, 30, 1, 1); - - // Extract commerce icon (index 2) - Sprite_construct (&is->district_commerce_icon); - Sprite_slice_pcx (&is->district_commerce_icon, __, &pcx, 1 + 2*31, 1, 30, 30, 1, 1); - - // Extract shield icon (index 4) - Sprite_construct (&is->district_shield_icon); - Sprite_slice_pcx (&is->district_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); - - // Extract corruption icon (index 5) - Sprite_construct (&is->district_corruption_icon); - Sprite_slice_pcx (&is->district_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); - - // Extract food icon (index 6) - Sprite_construct (&is->district_food_icon); - Sprite_slice_pcx (&is->district_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); - - // Extract food eaten icon (index 7) - Sprite_construct (&is->district_food_eaten_icon); - Sprite_slice_pcx (&is->district_food_eaten_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); - - // Extract small happiness icon (index 12) - Sprite_construct (&is->district_happiness_icon_small); - Sprite_slice_pcx (&is->district_happiness_icon_small, __, &pcx, 1 + 12*31, 1, 30, 30, 1, 1); - - // Extract small shield icon (index 13) - Sprite_construct (&is->district_shield_icon_small); - Sprite_slice_pcx (&is->district_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); - - // Extract small commerce icon (index 14) - Sprite_construct (&is->district_commerce_icon_small); - Sprite_slice_pcx (&is->district_commerce_icon_small, __, &pcx, 1 + 14*31, 1, 30, 30, 1, 1); - - // Extract small food icon (index 15: x = 1 + 15*31 = 466, width 30) - Sprite_construct (&is->district_food_icon_small); - Sprite_slice_pcx (&is->district_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); - - // Extract small science icon (index 16) - Sprite_construct (&is->district_science_icon_small); - Sprite_slice_pcx (&is->district_science_icon_small, __, &pcx, 1 + 16*31, 1, 30, 30, 1, 1); - - // Extract small culture icon (index 18) - Sprite_construct (&is->district_culture_icon_small); - Sprite_slice_pcx (&is->district_culture_icon_small, __, &pcx, 1 + 18*31, 1, 30, 30, 1, 1); - - // Load Negatives (mostly red) from here - - // Extract negative small commerce icon (index 17) - Sprite_construct (&is->district_negative_commerce_icon_small); - Sprite_slice_pcx (&is->district_negative_commerce_icon_small, __, &pcx, 1 + 17*31, 1, 30, 30, 1, 1); - - // Extract small unhappiness icon (index 19) - Sprite_construct (&is->district_unhappiness_icon_small); - Sprite_slice_pcx (&is->district_unhappiness_icon_small, __, &pcx, 1 + 19*31, 1, 30, 30, 1, 1); - - // Extract negative small shield icon (index 20) - Sprite_construct (&is->district_negative_shield_icon_small); - Sprite_slice_pcx (&is->district_negative_shield_icon_small, __, &pcx, 1 + 20*31, 1, 30, 30, 1, 1); - - // Extract negative small culture icon (index 21) - Sprite_construct (&is->district_negative_culture_icon_small); - Sprite_slice_pcx (&is->district_negative_culture_icon_small, __, &pcx, 1 + 21*31, 1, 30, 30, 1, 1); - - // Extract negative small culture icon (index 22) - Sprite_construct (&is->district_negative_food_icon_small); - Sprite_slice_pcx (&is->district_negative_food_icon_small, __, &pcx, 1 + 22*31, 1, 30, 30, 1, 1); - - // Extract negative small science icon (index 23) - Sprite_construct (&is->district_negative_science_icon_small); - Sprite_slice_pcx (&is->district_negative_science_icon_small, __, &pcx, 1 + 23*31, 1, 30, 30, 1, 1); - - is->dc_icons_img_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void __fastcall -patch_City_Form_draw (City_Form * this) -{ - // Recompute city form production rect location every time because the config might have changed. Doing it here is also easier than - // patching the constructor. - int form_top = (p_bic_data->ScreenHeight - this->Background_Image.Height) / 2; - this->Production_Storage_Indicator.top = form_top + 621 + (is->current_config.show_detailed_city_production_info ? 34 : 0); - - is->drawn_strat_resource_count = 0; - - // Make sure culture income (including from districts) is up to date before the draw event - if (is->current_config.enable_districts) - patch_City_recompute_culture_income(this->CurrentCity); - - City_Form_draw (this); - - if (is->current_config.show_detailed_city_production_info) { - City * city = this->CurrentCity; - int order_type = city->Body.Order_Type, - order_id = city->Body.Order_ID, - order_progress = City_get_order_progress (city), - order_cost = City_get_order_cost (city), - prod_rate = get_city_production_rate (city, order_type, order_id), - building_wealth = (order_type == COT_Improvement) && ((p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0); - - int turns_left, surplus; { - if (prod_rate > 0) { - turns_left = (order_cost - order_progress) / prod_rate; - if ((order_cost - order_progress) % prod_rate != 0) - turns_left++; - if (turns_left < 1) - turns_left = 1; - surplus = (turns_left * prod_rate) - (order_cost - order_progress); - } else { - turns_left = 9999; - surplus = 0; - } - } - - char line1[100]; { - if (prod_rate > 0) { - if (! building_wealth) - snprintf (line1, sizeof line1, "%s %d %s", this->Labels.To_Build, turns_left, (turns_left == 1) ? this->Labels.Single_Turn : this->Labels.Multiple_Turns); - else - snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_NEVER_COMPLETES]); - } else - snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_HALTED]); - line1[(sizeof line1) - 1] = '\0'; - } - - char line2[100]; { - if (! building_wealth) { - int percent_complete = order_cost > 0 ? ((10000 * order_progress) / order_cost + 50) / 100 : 100; - snprintf (line2, sizeof line2, "%d / %d (%d%s)", order_progress, order_cost, percent_complete, this->Labels.Percent); - } else - snprintf (line2, sizeof line2, "---"); - line2[(sizeof line2) - 1] = '\0'; - } - - char line3[100]; { - if ((! building_wealth) && (prod_rate > 0)) { - int s_per, s_rem; { - if (turns_left > 1) { - s_per = surplus / turns_left; - s_rem = surplus % turns_left; - } else { - s_per = surplus; - s_rem = 0; - } - } - char * s_lab = is->c3x_labels[CL_SURPLUS]; - if ((s_per != 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d + %d %s", s_lab, s_rem, s_per, this->Labels.Per_Turn); - else if ((s_per == 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d", s_lab, s_rem); - else if ((s_per != 0) && (s_rem == 0)) snprintf (line3, sizeof line3, "%s: %d %s", s_lab, s_per, this->Labels.Per_Turn); - else snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NONE]); - } else - snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NA]); - line3[(sizeof line3) - 1] = '\0'; - } - - Object_66C3FC * font = get_font (10, FSF_NONE); - int left = this->Production_Storage_Indicator.left, - top = this->Production_Storage_Indicator.top, - width = this->Production_Storage_Indicator.right - left; - PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line1, left, top - 42, width, strlen (line1)); - PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line2, left, top - 28, width, strlen (line2)); - PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line3, left, top - 14, width, strlen (line3)); - } - - // Draw district commerce bonuses (gold and science) - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - // Lazy load district icons - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - if (is->dc_icons_img_state != IS_OK) - return; - - City * city = this->CurrentCity; - if (city == NULL) - return; - - // Calculate district gold and science bonuses by iterating workable tiles - int district_gold = 0; - int city_civ_id = city->Body.CivID; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) continue; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - struct district_config const * cfg = &is->district_configs[district_id]; - int gold_bonus = 0; - get_effective_district_yields (inst, cfg, NULL, NULL, &gold_bonus, NULL, NULL, NULL); - district_gold += gold_bonus; - } - - Leader * leader = &leaders[city_civ_id]; - int gold_proportion = (district_gold * leader->gold_slider) / 10; - int science_proportion = (district_gold * leader->science_slider) / 10; - - // Draw district gold icons - if (gold_proportion > 0) { - Sprite * gold_sprite = &is->district_commerce_icon; - int sprite_width = gold_sprite->Width; - int sprite_height = gold_sprite->Height; - - struct tagRECT * gold_rect = &this->Gold_Income_Rect; - int total_gold = City_get_net_commerce (city, __, 2, true); - - // Calculate spacing - int spacing = sprite_width; - if ((total_gold > 1) && (total_gold * sprite_width != (gold_rect->right - gold_rect->left))) { - int rect_width = gold_rect->right - gold_rect->left; - if (rect_width <= total_gold * sprite_width) { - spacing = (rect_width - sprite_width) / (total_gold - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > sprite_width) - spacing = sprite_width; - } - } - - // Draw from right to left - int x_offset = 0; - int y_offset = 5; - for (int i = 0; i < gold_proportion && i < total_gold; i++) { - int x = gold_rect->right - x_offset - sprite_width; - int y = gold_rect->top + ((gold_rect->bottom - gold_rect->top >> 1) - - (sprite_height >> 1)) + y_offset; - - Sprite_draw (gold_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); - x_offset += spacing; - } - } - - // Draw district science icons - if (science_proportion > 0) { - Sprite * science_sprite = &is->district_commerce_icon; - int sprite_width = science_sprite->Width; - int sprite_height = science_sprite->Height; - - struct tagRECT * science_rect = &this->Science_Income_Rect; - int total_science = City_get_net_commerce (city, __, 1, true); - - // Calculate spacing - int spacing = sprite_width; - if ((total_science > 1) && (total_science * sprite_width != (science_rect->right - science_rect->left))) { - int rect_width = science_rect->right - science_rect->left; - if (rect_width <= total_science * sprite_width) { - spacing = (rect_width - sprite_width) / (total_science - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > sprite_width) - spacing = sprite_width; - } - } - - // Draw from right to left - int x_offset = 0; - int y_offset = 5; - for (int i = 0; i < science_proportion && i < total_science; i++) { - int x = science_rect->right - x_offset - sprite_width; - int y = science_rect->top + ((science_rect->bottom - science_rect->top >> 1) - - (sprite_height >> 1)) + y_offset; - - Sprite_draw (science_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); - x_offset += spacing; - } - } -} - -void __fastcall -patch_City_Form_print_production_info (City_Form *this, int edx, String256 * out_strs, int str_capacity) -{ - City_Form_print_production_info (this, __, out_strs, str_capacity); - if (is->current_config.show_detailed_city_production_info) - out_strs[1].S[0] = '\0'; -} - -int __fastcall -patch_Sprite_draw_strat_res_on_city_screen (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - if (is->current_config.compact_strategic_resource_display_on_city_screen) - pixel_x -= 13 * is->drawn_strat_resource_count + 17; - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -int __fastcall -patch_PCX_Image_do_draw_cntd_text_for_strat_res (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) -{ - if (is->current_config.compact_strategic_resource_display_on_city_screen) - x -= 13 * is->drawn_strat_resource_count + 17; - int tr = PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); - is->drawn_strat_resource_count++; - return tr; -} - -int __fastcall -patch_City_get_turns_to_build (City * this, int edx, enum City_Order_Types order_type, int order_id, bool param_3) -{ - // To fix the zero production crash, return 9999 when the city's total production rate is zero, avoiding a division by zero. That's only - // possible when producing an improvement due to negative shields from specialists. The original logic attempts to return 9999 in case of zero - // production but checks for that before including shields from specialists. - if (is->current_config.patch_zero_production_crash && (order_type == COT_Improvement)) { - - int specialist_shields = 0; - FOR_CITIZENS_IN (ci, this) - if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) - specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; - - // Return 9999 if the denominator in the base function's calculation would be zero. Note the base calc is incorrect in that it - // considers specialist shields to count toward Wealth, however we're not going to address that issue here, just stop the crash. - if (this->Body.ProductionIncome + specialist_shields <= 0) - return 9999; - } - - return City_get_turns_to_build (this, __, order_type, order_id, param_3); -} - -bool -is_below_stack_limit (Tile * tile, int civ_id, int type_id) -{ - enum UnitTypeClasses class = p_bic_data->UnitTypes[type_id].Unit_Class; - - int stack_limit = is->current_config.limit_units_per_tile[class]; - if (stack_limit <= 0) - return true; - - if (is->current_config.exclude_cities_from_units_per_tile_limit && - get_city_ptr (tile->CityID) != NULL) - return true; - - if (itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, type_id, 0)) - return true; - - FOR_UNITS_ON (uti, tile) { - // If there is a foreign unit on the tile then consider it as being below the stack limit. This ensures that the stack limit doesn't - // block combat between players. - if (uti.unit->Body.CivID != civ_id) - return true; - - int uti_type_id = uti.unit->Body.UnitTypeID; - if ((uti.unit->Body.Container_Unit < 0) && - (class == p_bic_data->UnitTypes[uti_type_id].Unit_Class) && - ! itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, uti_type_id, 0)) { - stack_limit -= 1; - if (stack_limit <= 0) - return false; - } - } - return true; -} - -// Returns the ID of the civ this move is trespassing against, or 0 if it's not trespassing. -int -check_trespassing (int civ_id, Tile * from, Tile * to) -{ - int from_territory_id = from->vtable->m38_Get_Territory_OwnerID (from), - to_territory_id = to ->vtable->m38_Get_Territory_OwnerID (to); - if ((civ_id > 0) && - (to_territory_id != civ_id) && - (to_territory_id > 0) && - (to_territory_id != from_territory_id) && - (! leaders[civ_id].At_War[to_territory_id]) && - ((leaders[civ_id].Relation_Treaties[to_territory_id] & 2) == 0)) // Check right of passage - return to_territory_id; - else - return 0; -} - -bool -is_allowed_to_trespass (Unit * unit) -{ - int type_id = unit->Body.UnitTypeID; - if ((type_id >= 0) && (type_id < p_bic_data->UnitTypeCount)) { - UnitType * type = &p_bic_data->UnitTypes[type_id]; - return UnitType_has_ability (type, __, UTA_Hidden_Nationality) || UnitType_has_ability (type, __, UTA_Invisible); - } else - return false; -} - -bool -get_tile_district_impassibility (Tile * tile, bool * out_impassible, bool * out_impassible_to_wheeled) -{ - if (out_impassible != NULL) - *out_impassible = false; - if (out_impassible_to_wheeled != NULL) - *out_impassible_to_wheeled = false; - - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - if (! district_is_complete (tile, inst->district_id)) - return false; - - if (inst->district_id == NATURAL_WONDER_DISTRICT_ID) { - if (! is->current_config.enable_natural_wonders) - return false; - int natural_id = inst->natural_wonder_info.natural_wonder_id; - if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) - return false; - if (out_impassible != NULL) - *out_impassible = is->natural_wonder_configs[natural_id].impassible; - if (out_impassible_to_wheeled != NULL) - *out_impassible_to_wheeled = is->natural_wonder_configs[natural_id].impassible_to_wheeled; - return true; - } - - if (! is->current_config.enable_districts) - return false; - if ((inst->district_id < 0) || (inst->district_id >= is->district_count)) - return false; - - if (out_impassible != NULL) - *out_impassible = is->district_configs[inst->district_id].impassible; - if (out_impassible_to_wheeled != NULL) - *out_impassible_to_wheeled = is->district_configs[inst->district_id].impassible_to_wheeled; - return true; -} - -AdjacentMoveValidity __fastcall -patch_Unit_can_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, int param_2) -{ - AdjacentMoveValidity base_validity = Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2); - - if (is->current_config.enable_districts) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - Tile * dest = tile_at (nx, ny); - - // Let workers step onto coast tiles when the config flag is enabled (base logic treats this as an invalid sea move) - if (is->current_config.workers_can_enter_coast && is_worker (this) && - ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { - if ((dest != NULL) && - dest->vtable->m35_Check_Is_Water (dest) && - (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) - base_validity = AMV_OK; - } - - // Allow land units to enter bridge tiles - if (is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && - ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { - if ((dest != NULL) && (dest != p_null_tile)) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { - base_validity = AMV_OK; - } - } - } - - // Allow naval units to enter completed canal tiles - if (is->current_config.enable_canal_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && - ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { - if ((dest != NULL) && (dest != p_null_tile)) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { - base_validity = AMV_OK; - } - } - } - - if ((base_validity == AMV_OK) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { - if ((dest != NULL) && (dest != p_null_tile) && Tile_has_city (dest)) - return AMV_INVALID_SEA_MOVE; - } - } - - // Apply unit count per tile limit - int type_id = this->Body.UnitTypeID; - if ((base_validity == AMV_OK) && (is->current_config.limit_units_per_tile[p_bic_data->UnitTypes[type_id].Unit_Class] > 0)) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - if (! is_below_stack_limit (tile_at (nx, ny), this->Body.CivID, type_id)) - return AMV_CANNOT_PASS_BETWEEN; - } - - // Apply trespassing restriction - if (is->current_config.disallow_trespassing && (base_validity == AMV_OK)) { - Tile * from = tile_at (this->Body.X, this->Body.Y); - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - int trespasses_against_civ_id = check_trespassing (this->Body.CivID, from, tile_at (nx, ny)); - if ((trespasses_against_civ_id > 0) && (! is_allowed_to_trespass (this))) - // The tile might be occupied by a unit belonging to a civ other than the one that owns the territory (against whom we'd be - // trespassing). In this case we must forbid the move entirely since TRIGGERS_WAR will not stop it if we're at war with the - // occupying civ. This fixes a bug where units could trespass by attacking an enemy unit across a border. They would then get - // stuck halfway between tiles if they won. - return (trespasses_against_civ_id == get_tile_occupier_id (nx, ny, this->Body.CivID, false)) ? AMV_TRIGGERS_WAR : AMV_CANNOT_PASS_BETWEEN; - } - - return base_validity; -} - -bool -great_wall_blocks_civ (Tile * tile, int civ_id) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_great_wall_districts || - ! is->current_config.great_wall_districts_impassible_by_others) - return false; - - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (owner_id <= 0) - return false; - if (owner_id == civ_id) - return false; - if ((civ_id > 0) && ((leaders[civ_id].Relation_Treaties[owner_id] & 2) != 0)) // 2 = right of passage - return false; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID)) - return false; - - if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) - return false; - - if (district_is_obsolete_for_civ (GREAT_WALL_DISTRICT_ID, civ_id)) - return false; - - return true; -} - -int __fastcall -patch_Trade_Net_get_movement_cost (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned flags, int neighbor_index, Trade_Net_Distance_Info * dist_info) -{ - if (is->is_computing_city_connections && // if this call came while rebuilding the trade network AND - (is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL) && // Trade Net X is set up AND - (unit == NULL) && ((flags == 0x1009) || (flags == 0x9))) // this call can be accelerated by TNX - return is->get_move_cost_for_sea_trade (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags, neighbor_index, dist_info); - - int base_cost = Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, neighbor_index, dist_info); - - bool districts_enabled = is->current_config.enable_districts; - if (districts_enabled) { - Tile * to = tile_at (to_x, to_y); - bool to_valid = (to != NULL) && (to != p_null_tile); - struct district_instance * to_inst = NULL; - bool to_inst_complete = false; - if (to_valid) { - to_inst = get_district_instance (to); - if (to_inst != NULL) - to_inst_complete = district_is_complete (to, to_inst->district_id); - } - - if ((unit != NULL) && great_wall_blocks_civ (to, unit->Body.CivID)) - return -1; - if ((unit != NULL) && to_valid) { - bool impassible = false; - bool impassible_to_wheeled = false; - if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { - if (impassible) - return -1; - if (impassible_to_wheeled && Unit_has_ability (unit, __, UTA_Wheeled)) { - Tile * from = tile_at (from_x, from_y); - bool connected_by_road = (from != NULL) && (to != NULL) && - (from->vtable->m25_Check_Roads (from, __, 0) != 0) && - (to->vtable->m25_Check_Roads (to, __, 0) != 0); - if (! connected_by_road) - return -1; - } - } - } - - // Let the pathfinder consider coastal tiles reachable for workers when the config flag is on - if (is->current_config.workers_can_enter_coast && - (base_cost < 0) && (unit != NULL) && is_worker (unit) && - to_valid && - to->vtable->m35_Check_Is_Water (to) && - (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) - base_cost = Unit_get_max_move_points (unit); - - // Let the pathfinder consider bridge tiles reachable for land units - if (is->current_config.enable_bridge_districts && - (base_cost < 0) && (unit != NULL) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == BRIDGE_DISTRICT_ID)) - base_cost = Unit_get_max_move_points (unit); - - // Let the pathfinder consider canal tiles reachable for naval units - if (is->current_config.enable_canal_districts && - (base_cost < 0) && (unit != NULL) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == CANAL_DISTRICT_ID)) - base_cost = Unit_get_max_move_points (unit); - - // Treat roads/rails on bridge districts like land roads/rails for movement cost. - if ((unit != NULL) && - is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land)) { - Tile * from = tile_at (from_x, from_y); - if ((from != NULL) && (from != p_null_tile) && to_valid) { - struct district_instance * from_inst = get_district_instance (from); - bool from_bridge = (from_inst != NULL) && - (from_inst->district_id == BRIDGE_DISTRICT_ID) && - district_is_complete (from, from_inst->district_id); - bool to_bridge = (to_inst != NULL) && - to_inst_complete && - (to_inst->district_id == BRIDGE_DISTRICT_ID); - if (from_bridge || to_bridge) { - bool from_rail = from->vtable->m23_Check_Railroads (from, __, 0) != 0; - bool to_rail = to->vtable->m23_Check_Railroads (to, __, 0) != 0; - bool from_road = from->vtable->m25_Check_Roads (from, __, 0) != 0; - bool to_road = to->vtable->m25_Check_Roads (to, __, 0) != 0; - if (from_rail && to_rail) - base_cost = 0; - else if (from_road && to_road) - base_cost = 1; - } - } - } - - if ((unit != NULL) && - (base_cost >= 0) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && - to_valid && Tile_has_city (to)) - return -1; - } - - // Apply unit count per tile limit - if ((unit != NULL) && ! is_below_stack_limit (tile_at (to_x, to_y), unit->Body.CivID, unit->Body.UnitTypeID)) - return -1; - - // Apply trespassing restriction - if (is->current_config.disallow_trespassing && - check_trespassing (civ_id, tile_at (from_x, from_y), tile_at (to_x, to_y)) && - ((unit == NULL) || (! is_allowed_to_trespass (unit)))) - return -1; - - // Adjust movement cost to enforce limited railroad movement - if ((is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0)) { - if ((unit != NULL) && (base_cost == 0)) { // Railroad move - if (! is->current_config.limited_railroads_work_like_fast_roads) { // If Civ 4 style RR, scale cost by type's moves - int type_moves_available = patch_Unit_get_max_move_points (unit) / p_bic_data->General.RoadsMovementRate; - return type_moves_available * is->railroad_mp_cost_per_move; - } else - return is->railroad_mp_cost_per_move; - } else if (base_cost == 1) // Road move - return is->road_mp_cost; - } - - return base_cost; -} - -int __fastcall -patch_Trade_Net_set_unit_path (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) -{ - int tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); - - bool may_require_length_fix = (is->current_config.limit_railroad_movement > 0) && // if railroad movement is limited AND - (tr > 0) && (out_path_length_in_mp != NULL) && // path was found AND caller wants to know its length AND - (unit != NULL); // the path is for an actual unit - - // We might have to correct the path length returned by the base game's pathfinder. This occurs when railroad movement is limited and the - // unit's total MP exceeds what can be stored in a one-byte integer. The cause of the incorrect length is that the pathfinder internally - // stores the remaining moves at each node of the search in a single byte. This correction fixes the bug (reported several times) that ETAs - // shown in the interface are wrong. - if (may_require_length_fix && (patch_Unit_get_max_move_points (unit) > 255)) { // Need to recompute path length if unit's total MP can overflow a uint8 - - // First memoize the cost of taking each step along the path. This must be done separately because the pathfinder's internal data only - // lets us traverse the path backwards. - { - // Must pass cached "distance info" to Trade_Net::get_movement_cost. Trade_Net stores two sets of cached data, which one was - // used depends on the flags. I believe one is intended to be used for city trade connections and the other for unit movement. - Trade_Net_Distance_Info * dist_info = (flags & 1) ? this->Data2 : this->Data4; - - clear_memo (); - int x = to_x, y = to_y; - do { - // "flags & 1" again determines whether Data2 or Data4 was used. - enum direction dir = Trade_Net_get_direction_from_internal_map (this, __, x, y, flags & 1); - if (dir == DIR_ZERO) - break; - - int prev_x, prev_y; { - int dx, dy; - neighbor_index_to_diff (dir, &dx, &dy); - prev_x = x + dx; prev_y = y + dy; - wrap_tile_coords (&p_bic_data->Map, &prev_x, &prev_y); - } - - memoize (patch_Trade_Net_get_movement_cost (this, __, prev_x, prev_y, x, y, unit, civ_id, flags, reverse_dir (dir), dist_info)); - x = prev_x; y = prev_y; - } while (! ((x == from_x) && (y == from_y))); - } - - // Now walk the path forwards tracking how much MP the unit would spend. We must be aware that the unit can't spend more MP than it - // has. For example, if a unit with 1 move walks onto an unimproved mountain, that effectively costs only 1 move, not 3. - int mp_remaining = patch_Unit_get_max_move_points (unit) - unit->Body.Moves, - mp_spent = 0; - for (int n = is->memo_len - 1; n >= 0; n--) { - int cost = is->memo[n]; - if (cost < mp_remaining) { - mp_spent += cost; - mp_remaining -= cost; - } else { - mp_spent += mp_remaining; - mp_remaining = patch_Unit_get_max_move_points (unit); - } - } - *out_path_length_in_mp = mp_spent; - - // Also, if this is a move between adjacent tiles, make sure the path length doesn't exceed the unit's remaining MP. Otherwise, the game may - // erroneously show an ETA of >1 turn. - } else if (may_require_length_fix && are_tiles_adjacent (from_x, from_y, to_x, to_y)) - *out_path_length_in_mp = not_above (patch_Unit_get_max_move_points (unit) - unit->Body.Moves, *out_path_length_in_mp); - - return tr; -} - -int __fastcall -patch_Trade_Net_set_unit_path_to_find_sea_route (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) -{ - // Accelerate this call with TNX if possible - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { - bool route_exists = is->try_drawing_sea_trade_route (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags); - return route_exists ? 1 : 0; - } else - return Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); -} - -// Renames this leader and their civ based on their era. Era-specific names come from the config file. If this leader has a custom name set by the -// human player, this method does nothing. -void -apply_era_specific_names (Leader * leader) -{ - int leader_bit = 1 << leader->ID; - Race * race = &p_bic_data->Races[leader->RaceID]; - - struct replaceable_name { - char * base_name; - int * tracking_bits; - char * buf; - int buf_size; - } replaceable_names[] = { - {race->vtable->GetAdjectiveName (race), &is->aliased_civ_adjective_bits , leader->tribe_customization.civ_adjective , sizeof leader->tribe_customization.civ_adjective}, - {race->vtable->GetSingularName (race) , &is->aliased_civ_noun_bits , leader->tribe_customization.civ_noun , sizeof leader->tribe_customization.civ_noun}, - {race->vtable->GetCountryName (race) , &is->aliased_civ_formal_name_bits, leader->tribe_customization.civ_formal_name, sizeof leader->tribe_customization.civ_formal_name} - }; - - // Apply replacements to civ noun, adjective, and formal name - for (int n = 0; n < ARRAY_LEN (replaceable_names); n++) { - struct replaceable_name * repl = &replaceable_names[n]; - if ((*repl->tracking_bits & leader_bit) || (repl->buf[0] == '\0')) { - char * replacement = NULL; - if (leader->Era < ERA_ALIAS_LIST_CAPACITY) - // Search through the list of aliases in reverse order so that, if the same key was listed multiple times, the last - // appearance overrides the earlier ones. This is important b/c when configs are loaded, their aliases get appended to - // the list. - for (int k = is->current_config.count_civ_era_alias_lists - 1; k >= 0; k--) { - struct civ_era_alias_list * list = &is->current_config.civ_era_alias_lists[k]; - if (strcmp (list->key, repl->base_name) == 0) { - replacement = list->aliases[leader->Era]; - break; - } - } - if (replacement != NULL) { - strncpy (repl->buf, replacement, repl->buf_size); - repl->buf[repl->buf_size - 1] = '\0'; - *repl->tracking_bits |= leader_bit; - } else { - repl->buf[0] = '\0'; - *repl->tracking_bits &= ~leader_bit; - } - } - } - - // Apply replacement to leader name, gender, and title - if ((is->aliased_leader_name_bits & leader_bit) || (leader->tribe_customization.leader_name[0] == '\0')) { - char * base_name = race->vtable->GetLeaderName (race); - char * replacement_name = NULL; - char * replacement_title = NULL; - int replacement_gender; // Only used if replacement_name is - if (leader->Era < ERA_ALIAS_LIST_CAPACITY) - for (int k = is->current_config.count_leader_era_alias_lists - 1; k >= 0; k--) { - struct leader_era_alias_list * list = &is->current_config.leader_era_alias_lists[k]; - if (strcmp (list->key, base_name) == 0) { - replacement_name = list->aliases[leader->Era]; - replacement_title = list->titles[leader->Era]; - replacement_gender = (list->gender_bits >> leader->Era) & 1; - break; - } - } - if (replacement_name != NULL) { - TribeCustomization * tc = &leader->tribe_customization; - strncpy (tc->leader_name, replacement_name, sizeof tc->leader_name); - tc->leader_name[(sizeof tc->leader_name) - 1] = '\0'; - tc->leader_gender = replacement_gender; - is->aliased_leader_name_bits |= leader_bit; - - // If this replacement name has a special title and this player does not have a custom title set, replace the title. - if ((replacement_title != NULL) && ((is->aliased_leader_title_bits & leader_bit) || (tc->leader_title[0] == '\0'))) { - strncpy (tc->leader_title, replacement_title, sizeof tc->leader_title); - tc->leader_title[(sizeof tc->leader_title) - 1] = '\0'; - is->aliased_leader_title_bits |= leader_bit; - - // If the current name has no title and the player's title was previously replaced, undo the replacement. - } else if ((replacement_title == NULL) && (is->aliased_leader_title_bits & leader_bit)) { - leader->tribe_customization.leader_title[0] = '\0'; - is->aliased_leader_title_bits &= ~leader_bit; - } - } else { - leader->tribe_customization.leader_name[0] = '\0'; - // Don't need to clear custom leader gender since it's not used unless a custom name was set - is->aliased_leader_name_bits &= ~leader_bit; - - // Remove title replacement if present - if (is->aliased_leader_title_bits & leader_bit) { - leader->tribe_customization.leader_title[0] = '\0'; - is->aliased_leader_title_bits &= ~leader_bit; - } - } - } -} - -int __cdecl -patch_do_save_game (char const * file_path, char param_2, GUID * guid) -{ - // Do not save the modified road movement rate, if it was modified to limit railroad movement - int restore_rmr = (is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0); - int rmr; - if (restore_rmr) { - rmr = p_bic_data->General.RoadsMovementRate; - p_bic_data->General.RoadsMovementRate = is->saved_road_movement_rate; - } - - // Do not save the modified barb culture group ID - int restore_barb_culture_group = is->current_config.enable_city_capture_by_barbarians && (is->saved_barb_culture_group >= 0); - int barb_culture; - if (restore_barb_culture_group) { - barb_culture = p_bic_data->Races[leaders[0].RaceID].CultureGroupID; - p_bic_data->Races[leaders[0].RaceID].CultureGroupID = is->saved_barb_culture_group; - } - - // Do not save names that were replaced with era-specific versions - for (int n = 0; n < 32; n++) { - Leader * leader = &leaders[n]; - int leader_bit = 1 << leader->ID; - if (is->aliased_civ_noun_bits & leader_bit) leader->tribe_customization.civ_noun [0] = '\0'; - if (is->aliased_civ_adjective_bits & leader_bit) leader->tribe_customization.civ_adjective [0] = '\0'; - if (is->aliased_civ_formal_name_bits & leader_bit) leader->tribe_customization.civ_formal_name[0] = '\0'; - if (is->aliased_leader_name_bits & leader_bit) leader->tribe_customization.leader_name [0] = '\0'; - if (is->aliased_leader_title_bits & leader_bit) leader->tribe_customization.leader_title [0] = '\0'; - } - is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; - - // Do not save unit types with the charm bits cleared if they were cleared by convertion to PTW targeting. The special actions field must not - // include the top category bits that are part of the UCV_* enum - for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { - UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; - converted_type->Special_Actions |= (0x00FFFFFF & UCV_Charm_Bombard); - } - - int tr = do_save_game (file_path, param_2, guid); - - if (restore_rmr) - p_bic_data->General.RoadsMovementRate = rmr; - if (restore_barb_culture_group) - p_bic_data->Races[leaders[0].RaceID].CultureGroupID = barb_culture; - - // Reapply era aliases - for (int n = 0; n < 32; n++) - if (*p_player_bits & (1 << n)) - apply_era_specific_names (&leaders[n]); - - // Reclear charm bits on converted types - for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { - UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; - converted_type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); - } - - return tr; -} - -void -record_unit_type_alt_strategy (int type_id) -{ - int ai_strat_index; { - int ai_strat_bits = p_bic_data->UnitTypes[type_id].AI_Strategy; - if ((ai_strat_bits & ai_strat_bits - 1) != 0) // Sanity check: must only have one strat (one bit) set - return; - ai_strat_index = 0; - while ((ai_strat_bits & 1) == 0) { - ai_strat_index++; - ai_strat_bits >>= 1; - } - } - - itable_insert (&is->unit_type_alt_strategies, type_id, ai_strat_index); -} - -void -append_improv_id_to_list (struct improv_id_list * list, int id) -{ - reserve (sizeof list->items[0], (void **)&list->items, &list->capacity, list->count); - list->items[list->count] = id; - list->count += 1; -} - -unsigned __fastcall -patch_load_scenario (BIC * this, int edx, char * param_1, unsigned * param_2) -{ - int ret_addr = ((int *)¶m_1)[-1]; - - // Destroy TNX cache from previous map. A new one will be created when needed. - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { - is->destroy_tnx_cache (is->tnx_cache); - is->tnx_cache = NULL; - } - - unsigned tr = load_scenario (this, __, param_1, param_2); - char * scenario_path = param_1; - - // There are two cases when load_scenario is called that we don't want to run our own code. These are (1) when the scenario is loaded to - // generate a preview (map, etc.) for the "Civ Content" or "Conquests" menu and (2) when the function is called recursively. The recursive - // call is done, I believe, only when loading saves using the default rules. The game first tries to load custom rules then falls back on - // loading the default rules. In any case, we want to ignore that call so we don't run the same code twice. - if ((ret_addr == ADDR_LOAD_SCENARIO_PREVIEW_RETURN) || (ret_addr == ADDR_LOAD_SCENARIO_RESUME_SAVE_2_RETURN)) - return tr; - - reset_to_base_config (); - load_config ("default.c3x_config.ini", 1); - char * scenario_config_file_name = "scenario.c3x_config.ini"; - char * scenario_config_path = BIC_get_asset_path (p_bic_data, __, scenario_config_file_name, false); - - // BIC_get_asset_path returns the file name when it can't find the file - if (0 != strcmp (scenario_config_file_name, scenario_config_path)) { - load_config (scenario_config_path, 0); - } - load_config ("custom.c3x_config.ini", 1); - apply_machine_code_edits (&is->current_config, false); - - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - reset_district_state (true); - load_districts_config (); - } - - // Initialize Trade Net X - if (is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_UNINITED)) { - char path[MAX_PATH]; - snprintf (path, sizeof path, "%s\\Trade Net X\\TradeNetX.dll", is->mod_rel_dir); - path[(sizeof path) - 1] = '\0'; - is->trade_net_x = LoadLibraryA (path); - if (is->trade_net_x != NULL) { - is->set_exe_version = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_exe_version"); - is->create_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "create_tnx_cache"); - is->destroy_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "destroy_tnx_cache"); - is->set_up_before_building_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_up_before_building_network"); - is->get_move_cost_for_sea_trade = (void *)(*p_GetProcAddress) (is->trade_net_x, "get_move_cost_for_sea_trade"); - is->flood_fill_road_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "flood_fill_road_network"); - is->try_drawing_sea_trade_route = (void *)(*p_GetProcAddress) (is->trade_net_x, "try_drawing_sea_trade_route"); - - is->set_exe_version (exe_version_index); - - // Run tests - if (0) { - int (__stdcall * test) () = (void *)(*p_GetProcAddress) (is->trade_net_x, "test"); - int failed_test_count = test (); - if (failed_test_count > 0) - MessageBoxA (NULL, "Failed some tests in Trade Net X!", NULL, MB_ICONWARNING); - else - MessageBoxA (NULL, "All tests in Trade Net X passed.", "Success", MB_ICONINFORMATION); - } - - is->tnx_init_state = IS_OK; - } else { - MessageBoxA (NULL, "Failed to load Trade Net X!", NULL, MB_ICONERROR); - is->tnx_init_state = IS_INIT_FAILED; - } - - // Deinitialize Trade Net X - } else if ((! is->current_config.enable_trade_net_x) && (is->tnx_init_state == IS_OK)) { - FreeLibrary (is->trade_net_x); - is->trade_net_x = NULL; - is->tnx_init_state = IS_UNINITED; - } - - // This scenario might use different mod art assets than the old one - deinit_stackable_command_buttons (); - deinit_district_command_buttons (); - deinit_disabled_command_buttons (); - deinit_trade_scroll_buttons (); - deinit_unit_rcm_icons (); - deinit_red_food_icon (); - deinit_large_minimap_frame (); - if (is->tile_already_worked_zoomed_out_sprite_init_state != IS_UNINITED) { - enum init_state * state = &is->tile_already_worked_zoomed_out_sprite_init_state; - if (*state == IS_OK) { - Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; - sprite->vtable->destruct (sprite, __, 0); - } - *state = IS_UNINITED; - } - - // Need to clear this since the resource count might have changed - if (is->extra_available_resources != NULL) { - free (is->extra_available_resources); - is->extra_available_resources = NULL; - is->extra_available_resources_capacity = 0; - } - - // Similarly, these don't carry over between games - for (int n = 0; n < 32; n++) - is->interceptor_reset_lists[n].count = 0; - is->replay_for_players = 0; - table_deinit (&is->extra_defensive_bombards); - table_deinit (&is->airdrops_this_turn); - table_deinit (&is->unit_transport_ties); - is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; - is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; - is->last_selected_unit.ptr = NULL; - table_deinit (&is->waiting_units); - is->have_loaded_waiting_units = false; - - // Clear extra city improvement bits - FOR_TABLE_ENTRIES (tei, &is->extra_city_improvs) - free ((void *)tei.value); - table_deinit (&is->extra_city_improvs); - - // Clear unit type counts - for (int n = 0; n < 32; n++) - table_deinit (&is->unit_type_counts[n]); - is->unit_type_count_init_bits = 0; - - // Clear last city founding turn numbers - for (int n = 0; n < 32; n++) - is->turn_no_of_last_founding_for_settler_perfume[n] = -1; - - // Load resources.pcx - { - PCX_Image * rs = is->resources_sheet; - if (rs != NULL) - rs->vtable->destruct (rs, __, 0); - else - rs = malloc (sizeof *rs); - memset (rs, 0, sizeof *rs); - PCX_Image_construct (rs); - - char * resources_pcx_path = BIC_get_asset_path (p_bic_data, __, "Art\\resources.pcx", true); - PCX_Image_read_file (rs, __, resources_pcx_path, NULL, 0, 0x100, 2); - is->resources_sheet = rs; - } - - // Recreate table of alt strategies mapping duplicates to their strategies - table_deinit (&is->unit_type_alt_strategies); - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; - if (alt_for_id >= 0) { - record_unit_type_alt_strategy (n); - record_unit_type_alt_strategy (alt_for_id); // Record the original too so we know it has alternatives - } - } - - // Recreate table of duplicates mapping unit types to the next duplicate - table_deinit (&is->unit_type_duplicates); - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; - if (alt_for_id >= 0) { - - // Find the type ID of the last duplicate in the list. alt_for_id refers to the original unit that was duplicated possibly - // multiple times. Begin searching there and, each time we find another duplicate, use its ID to continue the search. When - // we're done last_dup_id will be set to whichever ID in the list of duplicates is not already associated with another. - int last_dup_id = alt_for_id; { - int next; - while (itable_look_up (&is->unit_type_duplicates, last_dup_id, &next)) - last_dup_id = next; - } - - // Add this unit type to the end of the list of duplicates - itable_insert (&is->unit_type_duplicates, last_dup_id, n); - } - } - - // Convert charm-flagged units to using PTW targeting if necessary - if (is->current_config.charm_flag_triggers_ptw_like_targeting) { - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if (type->Special_Actions & UCV_Charm_Bombard) { - // Also add it to the list of converted types - reserve (sizeof is->charmed_types_converted_to_ptw_arty[0], // item size - (void **)&is->charmed_types_converted_to_ptw_arty, // ptr to items - &is->charmed_types_converted_to_ptw_arty_capacity, // ptr to capacity - is->count_charmed_types_converted_to_ptw_arty); // count - is->charmed_types_converted_to_ptw_arty[is->count_charmed_types_converted_to_ptw_arty] = n; - is->count_charmed_types_converted_to_ptw_arty += 1; - - // Add this type ID to the table - itable_insert (&is->current_config.ptw_arty_types, n, 1); - - // Clear the charm flag, taking care not to clear the category bit. This is necessary for the PTW targeting to work - // since the logic to implement it only applies to the non-charm code path. It wouldn't make sense to have both charm - // attack and PTW targeting anyway, since charm attack already works that way vs cities. - type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); - } - } - } - - // Pick out which resources are used as mill inputs - if (is->mill_input_resource_bits) - free (is->mill_input_resource_bits); - is->mill_input_resource_bits = calloc (1, 1 + p_bic_data->ResourceTypeCount / 8); - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - for (int k = 0; k < 2; k++) { - int resource_id = (&p_bic_data->Improvements[mill->improv_id].Resource1ID)[k]; - if ((resource_id >= 0) && (resource_id < p_bic_data->ResourceTypeCount)) { - byte bit = 1 << (resource_id & 7); - is->mill_input_resource_bits[resource_id>>3] |= bit; - } - } - } - - // Recreate lists of water & air trade improvements - is->water_trade_improvs .count = 0; - is->air_trade_improvs .count = 0; - is->combat_defense_improvs.count = 0; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - enum ImprovementTypeFlags flags = p_bic_data->Improvements[n].ImprovementFlags; - if (flags & ITF_Allows_Water_Trade) append_improv_id_to_list (&is->water_trade_improvs , n); - if (flags & ITF_Allows_Air_Trade) append_improv_id_to_list (&is->air_trade_improvs , n); - if (p_bic_data->Improvements[n].Combat_Defence != 0) append_improv_id_to_list (&is->combat_defense_improvs, n); - } - - // Set up for limiting railroad movement - if (is->current_config.limit_railroad_movement > 0) { - // Bit 0x200 of field_484 indicates whether or not the last call to load_scenario loaded the General section of the BIQ. The game will - // skip loading of that section and many others when loading a game with the same standard scenario as the then-current one, common - // when loading an autosave. - bool loaded_general = (this->field_848 & 0x200) != 0; - - // For the base RMR, use the saved rate if it's valid and we haven't loaded a new rate as part of the General section. Otherwise, use - // the rate from that section. - int base_rmr = (loaded_general || is->saved_road_movement_rate <= 0) ? p_bic_data->General.RoadsMovementRate : is->saved_road_movement_rate; - - int g = gcd (base_rmr, is->current_config.limit_railroad_movement); // Scale down all MP costs by this common divisor to help against - // overflow of 8-bit integers inside the pathfinder. - is->saved_road_movement_rate = base_rmr; - p_bic_data->General.RoadsMovementRate = base_rmr * is->current_config.limit_railroad_movement / g; // Full move in MP - is->road_mp_cost = is->current_config.limit_railroad_movement / g; - is->railroad_mp_cost_per_move = base_rmr / g; - } else { - is->saved_road_movement_rate = -1; - is->road_mp_cost = 1; - is->railroad_mp_cost_per_move = 0; - } - - // If barb city capturing is enabled and the barbs have the non-existent "none" culture group (index -1), switch them to the first real - // culture group. The "none" group produces corrupt graphics and crashes. - int * barb_culture_group = &p_bic_data->Races[leaders[0].RaceID].CultureGroupID; - if (is->current_config.enable_city_capture_by_barbarians && (*barb_culture_group < 0)) { - is->saved_barb_culture_group = *barb_culture_group; - *barb_culture_group = 0; - } else - is->saved_barb_culture_group = -1; - - // Clear old alias bits - is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; - - // Apply no AI patrol override - if (is->current_config.override_no_ai_patrol == NAPO_ZERO) - *p_allow_ai_patrol = true; - else if (is->current_config.override_no_ai_patrol == NAPO_ONE) - *p_allow_ai_patrol = false; - else if (is->current_config.override_no_ai_patrol == NAPO_NONE) - *p_allow_ai_patrol = 0 == get_int_from_conquests_ini ("NoAIPatrol", 1, 0); - - // Clear day/night cycle vars and deindex sprite proxies, if necessary. - if (is->current_config.day_night_cycle_mode != DNCM_OFF) { - is->day_night_cycle_unstarted = true; - is->current_day_night_cycle = 12; - if (is->day_night_cycle_img_proxies_indexed) { - deindex_day_night_image_proxies (); - } - } - - return tr; -} - -void __fastcall -patch_Leader_recompute_auto_improvements (Leader * this) -{ - is->leader_param_for_patch_get_wonder_city_id = this; - Leader_recompute_auto_improvements (this); -} - -int __fastcall -patch_Game_get_wonder_city_id (Game * this, int edx, int wonder_improvement_id) -{ - int ret_addr = ((int *)&wonder_improvement_id)[-1]; - if ((is->current_config.enable_free_buildings_from_small_wonders) && (ret_addr == ADDR_SMALL_WONDER_FREE_IMPROVS_RETURN)) { - Leader * leader = is->leader_param_for_patch_get_wonder_city_id; - Improvement * improv = &p_bic_data->Improvements[wonder_improvement_id]; - if ((improv->Characteristics & ITC_Small_Wonder) != 0) { - // Need to check if Small_Wonders array is NULL b/c recompute_auto_improvements gets called with leaders that are absent/dead. - return (leader->Small_Wonders != NULL) ? leader->Small_Wonders[wonder_improvement_id] : -1; - } - } - return Game_get_wonder_city_id (this, __, wonder_improvement_id); -} - -int __fastcall -patch_Main_Screen_Form_handle_key_up (Main_Screen_Form * this, int edx, int virtual_key_code) -{ - if ((virtual_key_code & 0xFF) == VK_CONTROL) { - patch_Main_GUI_set_up_unit_command_buttons (&this->GUI); - - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - } - - return Main_Screen_Form_handle_key_up (this, __, virtual_key_code); -} - -char __fastcall -patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing) -{ - char tr; - bool is_ai = ((*p_human_player_bits & (1 << this->ID)) == 0); - bool skip_replacement_logic = - (p_main_screen_form->Player_CivID == this->ID) && is->current_config.skip_repeated_tile_improv_replacement_asks; - - Tile * tile = tile_at (tile_x, tile_y); - - // If districts on, short-circuit any potential AI workers accidentally building in another civ's territory. - if (is->current_config.enable_districts && is_ai && (tile != NULL) && (tile != p_null_tile)) { - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (territory_owner > 0 && territory_owner != this->ID) - return 0; - } - - // Check if AI is trying to change a district tile (before calling vanilla logic) - if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && - is_ai) { - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { - int district_id = inst->district_id; - bool allow_ai_change = false; - - // Allow AI to modify obsolete districts - if (district_is_obsolete_for_civ (district_id, this->ID)) - allow_ai_change = true; - - // Allow if district could be used as a prerequisite for other buildable districts - if (! allow_ai_change) { - for (int other_id = 0; other_id < is->district_count; other_id++) { - if (other_id == district_id) - continue; - struct district_config const * other_cfg = &is->district_configs[other_id]; - if (! other_cfg->has_buildable_on_districts) - continue; - for (int i = 0; i < other_cfg->buildable_on_district_id_count; i++) { - if (other_cfg->buildable_on_district_ids[i] == district_id) { - if (leader_can_build_district (this, other_id)) - allow_ai_change = true; - break; - } - } - if (allow_ai_change) - break; - } - } - - // Allow AI to build roads/rails on bridge districts - if (! allow_ai_change && (district_id == BRIDGE_DISTRICT_ID) && - (job == WJ_Build_Road || job == WJ_Build_Railroad)) - allow_ai_change = true; - - // For Wonder Districts: check if unused (can be replaced) - if (! allow_ai_change && is->current_config.enable_wonder_districts && (district_id == WONDER_DISTRICT_ID)) { - struct wonder_district_info * info = get_wonder_district_info (tile); - - // If there's a reservation (wonder being built) or completed wonder, block replacement - if (info != NULL && info->state != WDS_UNUSED) - return 0; - - // Wonder district is unused - fall through to normal tech checks - } - else if (! allow_ai_change && is->current_config.enable_natural_wonders && (district_id == NATURAL_WONDER_DISTRICT_ID)) { - return 0; - } - else if (! allow_ai_change) { - // For all other district types: AI should not change them - return 0; - } - } - } - } - - if (! skip_replacement_logic) - tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); - else if (is->have_job_and_loc_to_skip && - (is->to_skip.job == job) && (is->to_skip.tile_x == tile_x) && (is->to_skip.tile_y == tile_y)) - tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, 0); - else { - is->show_popup_was_called = 0; - tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); - if (is->show_popup_was_called && tr) { // Check that the popup was shown and the player chose to replace - is->to_skip = (struct worker_job_and_location) { .job = job, .tile_x = tile_x, .tile_y = tile_y }; - is->have_job_and_loc_to_skip = 1; - } - } - - if (! tr && is->current_config.enable_districts && (job == WJ_Build_Mines)) { - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && - inst->district_id >= 0 && inst->district_id < is->district_count && - ! tile->vtable->m35_Check_Is_Water (tile) && - (tile->CityID < 0) && - ! tile->vtable->m18_Check_Mines (tile, __, 0)) { - int tile_x = 0, tile_y = 0; - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - int owner_civ = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_civ == this->ID) || (owner_civ == 0)) { - if (leader_can_build_district (this, inst->district_id) && - district_resource_prereqs_met (tile, tile_x, tile_y, inst->district_id)) - tr = 1; - } - } - } - } - - if (! tr && is->current_config.enable_districts && is->current_config.enable_bridge_districts && - (job == WJ_Build_Road || job == WJ_Build_Railroad)) { - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - if (job == WJ_Build_Road) { - if (! has_road) - tr = 1; - } else { - bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; - if (has_road && ! has_rail) { - int req_tech = p_bic_data->WorkerJobs[job].RequireID; - if ((req_tech < 0) || - ((req_tech != p_bic_data->AdvanceCount) && - Leader_has_tech (&leaders[this->ID], __, req_tech))) { - if (Leader_has_resources_for_job_at (&leaders[this->ID], __, job, tile_x, tile_y)) - tr = 1; - } - } - } - } - } - } - - return tr; -} - -bool __fastcall -patch_Unit_can_hurry_production (Unit * this, int edx, City * city, bool exclude_cheap_improvements) -{ - if (is->current_config.allow_military_leaders_to_hurry_wonders && Unit_has_ability (this, __, UTA_Leader)) { - LeaderKind actual_kind = this->Body.leader_kind; - this->Body.leader_kind = LK_Scientific; - bool tr = Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); - this->Body.leader_kind = actual_kind; - return tr; - } else - return Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); -} - -bool __fastcall -patch_Unit_can_load (Unit * this, int edx, Unit * passenger) -{ - is->can_load_transport = this; - is->can_load_passenger = passenger; - bool tr; - - // If this potential passenger is tied to a different transport, do not allow it to load into this one - int tied_transport_id = -1; - if (is->current_config.limit_unit_loading_to_one_transport_per_turn && - (! Unit_has_ability (this, __, UTA_Army)) && - itable_look_up (&is->unit_transport_ties, passenger->Body.ID, &tied_transport_id) && - (this->Body.ID != tied_transport_id)) - tr = false; - - else - tr = Unit_can_load (this, __, passenger); - - is->can_load_transport = is->can_load_passenger = NULL; - return tr; -} - -void __fastcall -patch_Unit_load (Unit * this, int edx, Unit * transport) -{ - Unit_load (this, __, transport); - - // Tie the unit to the transport if configured to do so - if (is->current_config.limit_unit_loading_to_one_transport_per_turn && ! Unit_has_ability (transport, __, UTA_Army)) - itable_insert (&is->unit_transport_ties, this->Body.ID, transport->Body.ID); -} - -bool -any_enemies_near (Leader const * me, int tile_x, int tile_y, enum UnitTypeClasses class, int num_tiles) -{ - bool tr = false; - FOR_TILES_AROUND (tai, num_tiles, tile_x, tile_y) { - int enemy_on_this_tile = 0; - FOR_UNITS_ON (uti, tai.tile) { - UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; - if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0) && - (((int)class < 0) || (unit_type->Unit_Class == class))) { - if (me->At_War[uti.unit->Body.CivID]) { - if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { - enemy_on_this_tile = 1; - break; - } - } else - break; - } - } - if (enemy_on_this_tile) { - tr = true; - break; - } - } - return tr; -} - -bool -any_enemies_near_unit (Unit * unit, int num_tiles) -{ - UnitType * unit_type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - return any_enemies_near (&leaders[unit->Body.CivID], unit->Body.X, unit->Body.Y, unit_type->Unit_Class, num_tiles); -} - -void __fastcall -patch_Unit_ai_move_artillery (Unit * this) -{ - if ((! is->current_config.use_offensive_artillery_ai) || - ((this->Body.UnitTypeID < 0) || (this->Body.UnitTypeID >= p_bic_data->UnitTypeCount))) // Check for invalid unit type id which appears sometimes, IDK why - goto base_impl; - - Tile * on_tile = tile_at (this->Body.X, this->Body.Y); - City * in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); - UnitType const * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - int num_escorters_req = this->vtable->eval_escort_requirement (this); - - if ((in_city == NULL) || (count_escorters (this) >= num_escorters_req)) - goto base_impl; - - // Don't assign escort if there are any enemies around because in that case it might be a serious mistake to take a defender out of the city - if (any_enemies_near_unit (this, 37)) - goto base_impl; - - // Find the strongest healthy defender the city has and assign that unit as an escort but make sure doing so doesn't leave the city - // defenseless. I think picking the strongest defender is the right choice here because the artillery pair is more likely to come under - // attack than a city and also leaving obsolete units in the city gives them a chance to upgrade. - int num_defenders = 0; - Unit * best_defender = NULL; - int best_defender_strength = -1; - FOR_UNITS_ON (uti, on_tile) { - Unit_Body * body = &uti.unit->Body; - UnitType * type = &p_bic_data->UnitTypes[body->UnitTypeID]; - if ((type->AI_Strategy & UTAI_Defence) && - (! UnitType_has_ability (type, __, UTA_Immobile)) && - (body->Damage == 0) && - ((body->UnitState == 0) || (body->UnitState == UnitState_Fortifying)) && - (body->escortee < 0)) { - num_defenders++; - int str = type->Defence * Unit_get_max_hp (uti.unit); - if (str > best_defender_strength) { - best_defender = uti.unit; - best_defender_strength = str; - } - } - } - if ((num_defenders >= 2) && (best_defender != NULL)) { - Unit_set_state (best_defender, __, 0); - Unit_set_escortee (best_defender, __, this->Body.ID); - } - -base_impl: - Unit_ai_move_artillery (this); - - // Recompute these since the unit might have moved - on_tile = tile_at (this->Body.X, this->Body.Y); - in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); - - // Load the unit into a transport for a naval invasion if it's just sitting in a city with nothing else to do - if (is->current_config.use_offensive_artillery_ai && - (in_city != NULL) && - (this->Body.Moves == 0) && - (this->Body.UnitState == UnitState_Fortifying) && - (this->Body.Container_Unit < 0)) { - Unit * transport = Unit_find_transport (this, __, this->Body.X, this->Body.Y); - if (transport != NULL) { - - int transport_capacity = p_bic_data->UnitTypes[transport->Body.UnitTypeID].Transport_Capacity; - int units_in_transport, arty_in_transport; { - units_in_transport = arty_in_transport = 0; - FOR_UNITS_ON (uti, on_tile) - if (uti.unit->Body.Container_Unit == transport->Body.ID) { - units_in_transport++; - arty_in_transport += (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].AI_Strategy & UTAI_Artillery) != 0; - } - } - - // Check that there's space for the arty unit and an escort, and that the transport does not have more than one arty per three - // spaces so we're less likely to assemble invasion forces composed of nothing but artillery. - if ((units_in_transport + 2 <= transport_capacity) && - (arty_in_transport < not_below (1, transport_capacity / 3))) { - Unit_set_escortee (this, __, -1); - patch_Unit_load (this, __, transport); - } - } - } -} - -// Estimates the number of turns necessary to move the given unit to the given tile and writes it to *out_num_turns. Returns 0 if there is no path -// from the unit's current position to the given tile, 1 otherwise. -int -estimate_travel_time (Unit * unit, int to_tile_x, int to_tile_y, int * out_num_turns) -{ - int dist_in_mp; - patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, to_tile_x, to_tile_y, unit, unit->Body.CivID, 1, &dist_in_mp); - dist_in_mp += unit->Body.Moves; // Add MP already spent this turn to the distance - int max_mp = patch_Unit_get_max_move_points (unit); - if ((dist_in_mp >= 0) && (max_mp > 0)) { - *out_num_turns = dist_in_mp / max_mp; - return 1; - } else - return 0; // No path or unit cannot move -} - -City * -find_nearest_established_city (Unit * unit, int continent_id) -{ - int lowest_unattractiveness = INT_MAX; - City * least_unattractive_city = NULL; - FOR_CITIES_OF (coi,unit->Body.CivID) { - Tile * city_tile = tile_at (coi.city->Body.X, coi.city->Body.Y); - if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { - int dist_in_turns; - if (! estimate_travel_time (unit, coi.city->Body.X, coi.city->Body.Y, &dist_in_turns)) - continue; - int unattractiveness = 10 * dist_in_turns; - unattractiveness = (10 + unattractiveness) / (10 + coi.city->Body.Population.Size); - if (coi.city->Body.CultureIncome > 0) - unattractiveness /= 5; - if (unattractiveness < lowest_unattractiveness) { - lowest_unattractiveness = unattractiveness; - least_unattractive_city = coi.city; - } - } - } - return least_unattractive_city; -} - -bool __fastcall -patch_Unit_ai_can_form_army (Unit * this) -{ - int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.patch_ai_can_form_army_without_special_ability && ((type->Special_Actions & build_army_action) == 0)) - return false; - else - return Unit_ai_can_form_army (this); -} - -void __fastcall -patch_Unit_ai_move_leader (Unit * this) -{ - if (! is->current_config.replace_leader_unit_ai) { - Unit_ai_move_leader (this); - return; - } - - Tile * tile = tile_at (this->Body.X, this->Body.Y); - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - - // Disband the unit if it's on a continent with no cities of its civ. This is what the original logic does. - if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { - Unit_disband (this); - return; - } - - // Flee if the unit is near an enemy without adequate escort - int has_adequate_escort; { - int escorter_count = 0; - int any_healthy_escorters = 0; - int index; - for (int escorter_id = Unit_next_escorter_id (this, __, &index, true); escorter_id >= 0; escorter_id = Unit_next_escorter_id (this, __, &index, false)) { - Unit * escorter = get_unit_ptr (escorter_id); - if ((escorter != NULL) && (escorter->Body.X == this->Body.X) && (escorter->Body.Y == this->Body.Y)) { - escorter_count++; - int remaining_health = Unit_get_max_hp (escorter) - escorter->Body.Damage; - any_healthy_escorters |= (remaining_health >= 3) || (escorter->Body.Damage == 0); - } - } - has_adequate_escort = (escorter_count > 0) && any_healthy_escorters; - } - if ((! has_adequate_escort) && any_enemies_near_unit (this, 49)) { - Unit_set_state (this, __, UnitState_Fleeing); - bool done = this->vtable->work (this); - if (done || (this->Body.UnitState != 0)) - return; - } - - // Move along path if the unit already has one set - byte next_move = Unit_pop_next_move_from_path (this); - if (next_move > 0) { - this->vtable->Move (this, __, next_move, 0); - return; - } - - // Start a science age if we can - // It would be nice to compute a value for this and compare it to the option of rushing production but it's hard to come up with a valuation - if (is->current_config.patch_science_age_bug && Unit_ai_can_start_science_age (this)) { - Unit_start_science_age (this); - return; - } - - // Estimate the value of creating an army. First test if that's even a possiblity and if not leave the value at -1 so rushing production is - // always preferable (note we can't use Unit_ai_can_form_army for this b/c it returns false for units not in a city). The value of forming - // an army is "infinite" if we don't already have one and otherwise it depends on the army unit's shield cost +/- 25% for each point of - // aggression divided by the number of armies already in the field. - int num_armies = leaders[this->Body.CivID].Armies_Count; - int form_army_value = -1; - int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits - if ((this->Body.leader_kind & LK_Military) && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & build_army_action) && - ((num_armies + 1) * p_bic_data->General.ArmySupportCities <= leaders[this->Body.CivID].Cities_Count) && - (p_bic_data->General.BuildArmyUnitID >= 0) && - (p_bic_data->General.BuildArmyUnitID < p_bic_data->UnitTypeCount)) { - if (num_armies < 1) - form_army_value = INT_MAX; - else { - form_army_value = p_bic_data->UnitTypes[p_bic_data->General.BuildArmyUnitID].Cost; - int aggression_level = p_bic_data->Races[leaders[this->Body.CivID].RaceID].AggressionLevel; // aggression level varies between -2 and +2 - form_army_value = (form_army_value * (4 + aggression_level)) / 4; - if (num_armies > 1) - form_army_value /= num_armies; - } - } - - // Estimate the value of rushing production in every city on this continent and remember the highest one - City * best_rush_loc = NULL; - int best_rush_value = -1; - FOR_CITIES_OF (coi, this->Body.CivID) { - City * city = coi.city; - Tile * city_tile = tile_at (city->Body.X, city->Body.Y); - if ((continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) && - patch_Unit_can_hurry_production (this, __, city, false)) { - // Base value is equal to the number of shields rushing would save - int value = City_get_order_cost (city) - City_get_order_progress (city) - city->Body.ProductionIncome; - if (value <= 0) - continue; - - // Consider distance: Reduce the value by the number of shields produced while the leader is en route to rush. - int dist_in_turns; - if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) - continue; // no path or unit cannot move - value -= dist_in_turns * city->Body.ProductionIncome; - if (value <= 0) - continue; - - // Consider corruption: Scale down the value of rushing an improvement by the corruption rate of the city. - // This is to reflect the fact that infrastructure is more valuable in less corrupt cities. But do not apply - // this to wonders since their benefit is in most cases not lessened by local corruption. - Improvement * improv = (city->Body.Order_Type == COT_Improvement) ? &p_bic_data->Improvements[city->Body.Order_ID] : NULL; - int is_wonder = (improv != NULL) && (0 != (improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder))); - if ((improv != NULL) && (! is_wonder)) { - int good_shields = city->Body.ProductionIncome; - int corrupt_shields = city->Body.ProductionLoss; - if (good_shields + corrupt_shields > 0) - value = (value * good_shields) / (good_shields + corrupt_shields); - else - continue; - } - - if ((value > 0) && (value > best_rush_value)) { - best_rush_loc = city; - best_rush_value = value; - } - } - } - - // Hurry production or form an army depending on the estimated values of doing so. We might have to move to a (different) city if that's where - // we want to rush production or if we want to form an army but aren't already in a city. - City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); - City * moving_to_city = NULL; - if ((best_rush_loc != NULL) && (best_rush_value > form_army_value)) { - if (best_rush_loc == in_city) { - Unit_hurry_production (this); - return; - } else - moving_to_city = best_rush_loc; - } else if ((form_army_value > -1) && patch_Unit_ai_can_form_army (this)) { - Unit_form_army (this); - return; - } else if (in_city == NULL) { - // Nothing to do. Try to find a close, established city to move to & wait in. - moving_to_city = find_nearest_established_city (this, continent_id); - } - if (moving_to_city) { - int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); - if (first_move > 0) { - Unit_set_escortee (this, __, -1); - this->vtable->Move (this, __, first_move, 0); - return; - } - } - - // Nothing to do, nowhere to go, just fortify in place. - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -int -measure_strength_in_army (UnitType * type) -{ - return ((type->Attack + type->Defence) * (4 + type->Hit_Point_Bonus)) / 4; -} - -bool __fastcall -patch_impl_ai_is_good_army_addition (Unit * this, int edx, Unit * candidate) -{ - if (! is->current_config.fix_ai_army_composition) - return impl_ai_is_good_army_addition (this, __, candidate); - - UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - if (((candidate_type->AI_Strategy & UTAI_Offence) == 0) || - UnitType_has_ability (candidate_type, __, UTA_Hidden_Nationality)) - return false; - - int num_units_in_army = 0, - army_min_speed = INT_MAX, - army_min_strength = INT_MAX; - FOR_UNITS_ON (uti, tile) { - if (uti.unit->Body.Container_Unit == this->Body.ID) { - num_units_in_army++; - int movement = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Movement; - if (movement < army_min_speed) - army_min_speed = movement; - int member_strength = measure_strength_in_army (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]); - if (member_strength < army_min_strength) - army_min_strength = member_strength; - } - } - - return (num_units_in_army == 0) || - ((candidate_type->Movement >= army_min_speed) && - (measure_strength_in_army (candidate_type) >= army_min_strength)); -} - -int -rate_artillery (UnitType * type) -{ - int tr = type->Attack + type->Defence + 2 * type->Bombard_Strength * type->FireRate; - - // include movement - int moves = type->Movement; - if (moves >= 2) - tr = tr * (moves + 1) / 2; - - // include range - int range = type->Bombard_Range; - if (range >= 2) - tr = tr * (range + 1) / 2; - - // include extra hp - if (type->Hit_Point_Bonus > 0) - tr = tr * (4 + type->Hit_Point_Bonus) / 4; - - return tr; -} - -int -rate_bomber (UnitType * type) -{ - int tr = type->Bombard_Strength * type->FireRate + type->Defence; - - // include range - tr = tr * (10 + type->OperationalRange) / 10; - - // include cost - tr = (tr * 100) / (100 + type->Cost); - - // include abilities - if (UnitType_has_ability (type, __, UTA_Blitz)) - tr = tr * (type->Movement + 1) / 2; - if (UnitType_has_ability (type, __, UTA_Lethal_Land_Bombardment)) - tr = tr * 3 / 2; - if (UnitType_has_ability (type, __, UTA_Lethal_Sea_Bombardment)) - tr = tr * 5 / 4; - if (UnitType_has_ability (type, __, UTA_Stealth)) - tr = tr * 3 / 2; - - // include extra hp - if (type->Hit_Point_Bonus > 0) - tr = tr * (4 + type->Hit_Point_Bonus) / 4; - - return tr; -} - -bool __fastcall -patch_City_can_build_unit (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) -{ - bool base = City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); - - if (base) { - // Apply building prereqs - int building_prereq; - if (itable_look_up (&is->current_config.building_unit_prereqs, unit_type_id, &building_prereq)) { - // If the prereq is an encoded building ID - if (building_prereq & 1) { - if (! has_active_building (this, building_prereq >> 1)) - return false; - - // Else it's a pointer to a list of building IDs - } else { - int * list = (int *)building_prereq; - for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) - if ((list[n] >= 0) && ! has_active_building (this, list[n])) - return false; - } - } - - // Apply unit type limit - int available; - if (get_available_unit_count (&leaders[this->Body.CivID], unit_type_id, &available) && (available <= 0)) - return false; - } - - if (is->current_config.enable_districts) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - - // Bail if tech reqs are not met - int prereq_id = type->AdvReq; - if (prereq_id >= 0 && ! Leader_has_tech (&leaders[this->Body.CivID], __, prereq_id)) - return false; - - if (! Leader_can_build_unit (&leaders[this->Body.CivID], __, unit_type_id, 1, false)) - return false; - - // Superficially allow the AI to choose the unit for scoring and production. - // If a disallowed air/naval unit is chosen in ai_choose_production, we'll swap it out for a feasible fallback later - // after prioritizing the aerodrome/port to be built - if (! is_human && ( - (type->Unit_Class == UTC_Air || city_can_build_district (this, AERODROME_DISTRICT_ID)) || - (type->Unit_Class == UTC_Sea || city_can_build_district (this, PORT_DISTRICT_ID))) - ) - return base; - - // Air units - if (type->Unit_Class == UTC_Air) { - if (is->current_config.enable_aerodrome_districts && is->current_config.air_units_use_aerodrome_districts_not_cities) { - if (find_pending_district_request (this, AERODROME_DISTRICT_ID) != NULL) - return false; - if (! city_can_build_district (this, AERODROME_DISTRICT_ID)) - return false; - return city_has_required_district (this, AERODROME_DISTRICT_ID); - } - // Naval units - } else if (type->Unit_Class == UTC_Sea) { - if (is->current_config.enable_port_districts && is->current_config.naval_units_use_port_districts_not_cities) { - if (find_pending_district_request (this, PORT_DISTRICT_ID) != NULL) - return false; - if (! city_can_build_district (this, PORT_DISTRICT_ID)) - return false; - return city_has_required_district (this, PORT_DISTRICT_ID); - } - } - } - - return base; -} - -int __fastcall -patch_City_get_largest_adjacent_sea_within_work_area (City * this) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - int improv_id = is->current_evaluating_improve_id; - if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { - - // If Coastal Fortress, default to original logic (city must be next to coast) - if (p_bic_data->Improvements[improv_id].Naval_Bombard_Defence > 0) - return City_get_largest_adjacent_sea (this); - } - int lake_size_threshold = 21; - int largest_size = 0; - int largest_continent_id = -1; - FOR_WORK_AREA_AROUND (wai, this->Body.X, this->Body.Y) { - if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { - int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - if (continent->Body.TileCount <= lake_size_threshold && ! is->current_config.enable_canal_districts) - continue; - if (p_bic_data->Map.Continents[continent_id].Body.TileCount > largest_size) { - largest_size = p_bic_data->Map.Continents[continent_id].Body.TileCount; - largest_continent_id = continent_id; - } - } - } - return largest_continent_id; - } - return City_get_largest_adjacent_sea (this); -} - -bool __fastcall -patch_Map_impl_is_near_river_within_work_area (Map * this, int edx, int x, int y, int num_tiles) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - FOR_WORK_AREA_AROUND (wai, x, y) { - if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) { - return true; - } - } - return false; - } - - return this->vtable->is_near_river (this, __, x, y, num_tiles); -} - -bool __fastcall -patch_Map_impl_is_near_lake_within_work_area (Map * this, int edx, int x, int y, int num_tiles) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - int lake_size_threshold = 21; - FOR_WORK_AREA_AROUND (wai, x, y) { - if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { - int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - if (continent->Body.TileCount <= lake_size_threshold) - return true; - } - } - return false; - } - - return this->vtable->is_near_lake (this, __, x, y, num_tiles); -} - -bool __fastcall -patch_Map_impl_has_fresh_water_within_work_area (Map * this, int edx, int tile_x, int tile_y) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - int improv_id = is->current_evaluating_improve_id; - if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { - - // If an Aqueduct, default to original logic (city must be next to coast) - if ((p_bic_data->Improvements[improv_id].ImprovementFlags & ITF_Allows_City_Level_2) != 0) - return this->vtable->has_fresh_water (this, __, tile_x, tile_y); - } - if (patch_Map_impl_is_near_river_within_work_area (this, __, tile_x, tile_y, 1)) - return true; - if (patch_Map_impl_is_near_lake_within_work_area (this, __, tile_x, tile_y, 1)) - return true; - return false; - } - - return this->vtable->has_fresh_water (this, __, tile_x, tile_y); -} - -bool -city_meets_district_prereqs_to_build_improvement (City * city, int i_improv, bool apply_strict_rules) -{ - // Different logic for human vs AI players - bool is_human = (*p_human_player_bits & (1 << city->Body.CivID)) != 0; - - Improvement * improv = &p_bic_data->Improvements[i_improv]; - bool is_wonder = is->current_config.enable_wonder_districts && (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)); - if (is_wonder && ! wonder_is_buildable_by_civ (i_improv, city->Body.CivID)) - return false; - - bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; - - // Check if the improvement requires a district - bool needs_district = city_requires_district_for_improvement (city, i_improv, NULL); - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); - - // District is either not needed or already built - if (! needs_district) - return true; - - if (prereq_list == NULL) - return false; - - bool has_buildable_candidate = false; - bool has_wonder_candidate = false; - bool has_non_wonder_candidate = false; - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) - continue; - has_buildable_candidate = true; - if (district_id == WONDER_DISTRICT_ID) - has_wonder_candidate = true; - else - has_non_wonder_candidate = true; - } - if (! has_buildable_candidate) - return false; - - // Check that we have the necessary terrain - bool has_terrain_for_district = false; - bool has_terrain_for_wonder = false; - bool has_river_terrain_for_district = false; - FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { - Tile * tile = wai.tile; - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) - continue; - if (! tile_suitable_for_district (tile, district_id, city, NULL)) - continue; - - if (is_wonder && district_id == WONDER_DISTRICT_ID) { - if (! wonder_is_buildable_on_tile (tile, i_improv)) - continue; - } - - has_terrain_for_district = true; - if (requires_river && tile->vtable->m37_Get_River_Code (tile) != 0) - has_river_terrain_for_district = true; - - if (is_wonder && district_id == WONDER_DISTRICT_ID) { - if (! requires_river || tile->vtable->m37_Get_River_Code (tile) != 0) { - has_terrain_for_wonder = true; - } - } - } - } - - bool requires_wonder_terrain = is_wonder && has_wonder_candidate && ! has_non_wonder_candidate; - if (! has_terrain_for_district || - (requires_river && ! has_river_terrain_for_district) || - (requires_wonder_terrain && ! has_terrain_for_wonder)) { - return false; - } - - // If human has everything needed except a built district (which is buildable), allow relaxed checks so UI can gray entry out - if (is_human) { - return ! apply_strict_rules; - } - - // If AI already has a pending district request for this required district, return false - // to prevent wasting a turn trying to choose this improvement - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - if (find_pending_district_request (city, district_id) != NULL) - return false; - } - - // Superficially allow the AI to choose the improvement for scoring and production. - // If a disallowed improvement is chosen in ai_choose_production, we'll swap it out for a feasible fallback later - // after prioritizing the district to be built - return true; -} - -bool __fastcall -patch_City_can_build_improvement (City * this, int edx, int i_improv, bool apply_strict_rules) -{ - is->current_evaluating_improve_id = i_improv; - - char ss[200]; - snprintf (ss, sizeof ss, "patch_City_can_build_improvement:evaluating improvement %s (%d)\n", - p_bic_data->Improvements[i_improv].Name.S, i_improv); - (*p_OutputDebugStringA) (ss); - - // First defer to the base game's logic - bool base = City_can_build_improvement (this, __, i_improv, apply_strict_rules); - if (! base) return false; - if (! is->current_config.enable_districts) return base; - - bool can_build = city_meets_district_prereqs_to_build_improvement (this, i_improv, apply_strict_rules); - is->current_evaluating_improve_id = -1; - - return can_build; -} - -bool -ai_handle_district_production_requirements (City * city, City_Order * out) -{ - clear_best_feasible_order (city); - bool swapped_to_fallback = false; - City_Order fallback_order = {0}; - int required_district_id = -1; - bool should_mark_district = false; - - char ss[200]; - - if (is->current_config.enable_districts && - (out->OrderID >= 0)) { - bool needs_wonder_district = false; - bool requires_district = false; - bool needs_district = false; - - if ((out->OrderType == COT_Unit) && - (out->OrderID < p_bic_data->UnitTypeCount)) { - UnitType * type = &p_bic_data->UnitTypes[out->OrderID]; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { - required_district_id = AERODROME_DISTRICT_ID; - needs_district = true; - should_mark_district = true; - } else if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (city, PORT_DISTRICT_ID))) { - required_district_id = PORT_DISTRICT_ID; - needs_district = true; - should_mark_district = true; - } - } else if ((out->OrderType == COT_Improvement) && - (out->OrderID < p_bic_data->ImprovementsCount)) { - // Check if AI is trying to build a wonder without an incomplete wonder district - requires_district = city_requires_district_for_improvement (city, out->OrderID, &required_district_id); - if (is->current_config.enable_wonder_districts) { - Improvement * improv = &p_bic_data->Improvements[out->OrderID]; - if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && - (! city_has_wonder_district_with_no_completed_wonder (city, out->OrderID))) { - snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: City %d (%s) needs wonder district to build wonder improvement %d\n", - city->Body.ID, city->Body.CityName, out->OrderID); - (*p_OutputDebugStringA) (ss); - needs_wonder_district = true; - if (required_district_id < 0) { - required_district_id = WONDER_DISTRICT_ID; - } - } - } - needs_district = needs_wonder_district || requires_district; - } - - if (needs_district) { - struct ai_best_feasible_order * stored = get_best_feasible_order (city); - if (stored != NULL) { - bool fallback_is_feasible = true; - if (stored->order.OrderType == COT_Improvement) { - if ((stored->order.OrderID < 0) || - (stored->order.OrderID >= p_bic_data->ImprovementsCount)) - fallback_is_feasible = false; - - // Check if fallback requires a district the city doesn't have - if (fallback_is_feasible && - city_requires_district_for_improvement (city, stored->order.OrderID, NULL)) - fallback_is_feasible = false; - - // If original order was a wonder, ensure fallback is not also a wonder - if (fallback_is_feasible && needs_wonder_district) { - Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; - if (fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - fallback_is_feasible = false; - } - - // If fallback is a wonder, check if it has an incomplete wonder district - if (fallback_is_feasible && is->current_config.enable_wonder_districts) { - Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; - if ((fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && - (! city_has_wonder_district_with_no_completed_wonder (city, stored->order.OrderID))) - fallback_is_feasible = false; - } - } else if (stored->order.OrderType == COT_Unit) { - if ((stored->order.OrderID < 0) || - (stored->order.OrderID >= p_bic_data->UnitTypeCount)) - fallback_is_feasible = false; - if (fallback_is_feasible) { - UnitType * type = &p_bic_data->UnitTypes[stored->order.OrderID]; - if (type->Unit_Class != UTC_Land) - fallback_is_feasible = false; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (city, AERODROME_DISTRICT_ID))) - fallback_is_feasible = false; - if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (city, PORT_DISTRICT_ID))) - fallback_is_feasible = false; - } - } else - fallback_is_feasible = false; - - if (fallback_is_feasible) { - if (out->OrderType == COT_Improvement) { - // Remember pending building order for any improvement that requires a district - snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: Remembering fallback pending building order for city %d (%s): order type %d id %d\n", - city->Body.ID, city->Body.CityName, out->OrderType, out->OrderID); - (*p_OutputDebugStringA) (ss); - remember_pending_building_order (city, out->OrderID); - } - - fallback_order = stored->order; - swapped_to_fallback = true; - } - } - } - } - - if (swapped_to_fallback) { - *out = fallback_order; - } - if ((swapped_to_fallback || should_mark_district) && (required_district_id >= 0)) - mark_city_needs_district (city, required_district_id); - - clear_best_feasible_order (city); - return swapped_to_fallback; -} - -void __fastcall -patch_City_ai_choose_production (City * this, int edx, City_Order * out) -{ - is->ai_considering_production_for_city = this; - City_ai_choose_production (this, __, out); - - char ss[200]; - snprintf (ss, sizeof ss, "patch_City_ai_choose_production: City %d (%s) chose order type %d id %d\n", - this->Body.ID, this->Body.CityName, out->OrderType, out->OrderID); - (*p_OutputDebugStringA) (ss); - - if (is->current_config.enable_districts) { - if (ai_handle_district_production_requirements (this, out)) { - return; - } - } - - Leader * me = &leaders[this->Body.CivID]; - int arty_ratio = is->current_config.ai_build_artillery_ratio; - int bomber_ratio = is->current_config.ai_build_bomber_ratio; - - // Check if AI-build-more-artillery mod option is activated and this city is building something that we might want to switch to artillery - if ((arty_ratio > 0) && - (out->OrderType == COT_Unit) && - (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && - (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & (UTAI_Offence | UTAI_Defence))) { - - // Check how many offense/defense/artillery units this AI has already built. We'll only force it to build arty if it has a minimum - // of one defender per city, one attacker per two cities, and of course if it's below the ratio limit. - int num_attackers = me->AI_Strategy_Unit_Counts[0], - num_defenders = me->AI_Strategy_Unit_Counts[1], - num_artillery = me->AI_Strategy_Unit_Counts[2]; - if ((num_attackers > me->Cities_Count / 2) && - (num_defenders > me->Cities_Count) && - (100*num_artillery < arty_ratio*(num_attackers + num_defenders))) { - - // Loop over all build options to determine the best artillery unit available. Record its attack power and also find & record - // the highest attack power available from any offensive unit so we can compare them. - int best_arty_type_id = -1, - best_arty_rating = -1, - best_arty_strength = -1, - best_attacker_strength = -1; - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if ((type->AI_Strategy & (UTAI_Artillery | UTAI_Offence)) && - patch_City_can_build_unit (this, __, n, 1, 0, 0)) { - if (type->AI_Strategy & UTAI_Artillery) { - int this_rating = rate_artillery (&p_bic_data->UnitTypes[n]); - if (this_rating > best_arty_rating) { - best_arty_type_id = n; - best_arty_rating = this_rating; - best_arty_strength = type->Bombard_Strength * type->FireRate; - } - } else { // attacker - int this_strength = (type->Attack * (4 + type->Hit_Point_Bonus)) / 4; - if (this_strength > best_attacker_strength) - best_attacker_strength = this_strength; - } - } - } - - // Randomly switch city production to the artillery unit if we found one - if (best_arty_type_id >= 0) { - int chance = 12 * arty_ratio / 10; - - // Scale the chance of switching by the ratio of the attack power the artillery would provide to the attack power - // of the strongest offensive unit. This way the AI will rapidly build artillery up to the ratio limit only when - // artillery are its best way of dealing damage. - // Some example numbers: - // | Best attacker (str) | Best arty (str) | Chance w/ ratio = 20, damage% = 50 - // | Swordsman (3) | Catapult (4) | 16 - // | Knight (4) | Trebuchet (6) | 18 - // | Cavalry (6) | Cannon (8) | 16 - // | Cavalry (6) | Artillery (24) | 48 - // | Tank (16) | Artillery (24) | 18 - if (best_attacker_strength > 0) - chance = (chance * best_arty_strength * is->current_config.ai_artillery_value_damage_percent) / (best_attacker_strength * 100); - - if (rand_int (p_rand_object, __, 100) < chance) - out->OrderID = best_arty_type_id; - } - } - - } else if ((bomber_ratio > 0) && - (out->OrderType == COT_Unit) && - (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && - (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & UTAI_Air_Defence)) { - int num_fighters = me->AI_Strategy_Unit_Counts[7], - num_bombers = me->AI_Strategy_Unit_Counts[6]; - if (100 * num_bombers < bomber_ratio * num_fighters) { - int best_bomber_type_id = -1, - best_bomber_rating = -1; - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if ((type->AI_Strategy & UTAI_Air_Bombard) && - patch_City_can_build_unit (this, __, n, 1, 0, 0)) { - int this_rating = rate_bomber (&p_bic_data->UnitTypes[n]); - if (this_rating > best_bomber_rating) { - best_bomber_type_id = n; - best_bomber_rating = this_rating; - } - } - } - - if (best_bomber_type_id >= 0) { - int chance = 12 * bomber_ratio / 10; - if (rand_int (p_rand_object, __, 100) < chance) - out->OrderID = best_bomber_type_id; - } - } - } - - is->ai_considering_production_for_city = NULL; -} - -int __fastcall -patch_Unit_disembark_passengers (Unit * this, int edx, int tile_x, int tile_y) -{ - // Break any escort relationships if the escorting unit can't move onto the target tile. This prevents a freeze where the game continues - // trying to disembark units because an escortee looks like it could be disembarked except it can't because it won't move if its escorter - // can't be moved first. - Tile * tile = tile_at (this->Body.X, this->Body.Y), - * target = tile_at (tile_x , tile_y); - if (is->current_config.patch_blocked_disembark_freeze && (tile != NULL) && (target != NULL)) { - enum SquareTypes target_terrain = target->vtable->m50_Get_Square_BaseType (target); - FOR_UNITS_ON (uti, tile) { - Unit * escortee = get_unit_ptr (uti.unit->Body.escortee); - if ( (escortee != NULL) - && (uti.unit->Body.Container_Unit == this->Body.ID) - && (escortee->Body.Container_Unit == this->Body.ID) - && ( UnitType_has_ability (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID], __, UTA_Immobile) - || ( is->current_config.disallow_trespassing - && check_trespassing (uti.unit->Body.CivID, tile, target) - && ! is_allowed_to_trespass (uti.unit)) - || Unit_is_terrain_impassable (uti.unit, __, target_terrain))) - Unit_set_escortee (uti.unit, __, -1); - } - } - - return Unit_disembark_passengers (this, __, tile_x, tile_y); -} - -// Returns whether or not the current deal being offered to the AI on the trade screen would be accepted. How advantageous the AI thinks the -// trade is for itself is stored in out_their_advantage if it's not NULL. This advantage is measured in gold, if it's positive it means the -// AI thinks it's gaining that much value from the trade and if it's negative it thinks it would be losing that much. I don't know what would -// happen if this function were called while the trade screen is not active. -bool -is_current_offer_acceptable (int * out_their_advantage) -{ - int their_id = p_diplo_form->other_party_civ_id; - - DiploMessage consideration = Leader_consider_trade ( - &leaders[their_id], - __, - &p_diplo_form->our_offer_lists[their_id], - &p_diplo_form->their_offer_lists[their_id], - p_main_screen_form->Player_CivID, - 0, true, 0, 0, - out_their_advantage, - NULL, NULL); - - return consideration == DM_AI_ACCEPT; -} - -// Adds an offer of gold to the list and returns it. If one already exists in the list, returns a pointer to it. -TradeOffer * -offer_gold (TradeOfferList * list, int is_lump_sum, int * is_new_offer) -{ - if (list->length > 0) - for (TradeOffer * offer = list->first; offer != NULL; offer = offer->next) - if ((offer->kind == 7) && (offer->param_1 == is_lump_sum)) { - *is_new_offer = 0; - return offer; - } - - TradeOffer * tr = new (sizeof *tr); - *tr = (struct TradeOffer) { - .vtable = p_trade_offer_vtable, - .kind = 7, // TODO: Replace with enum - .param_1 = is_lump_sum, - .param_2 = 0, - .next = NULL, - .prev = NULL - }; - - if (list->length > 0) { - tr->prev = list->last; - list->last->next = tr; - list->last = tr; - list->length += 1; - } else { - list->last = list->first = tr; - list->length = 1; - } - - *is_new_offer = 1; - return tr; -} - -// Removes offer from list of offers but does not free it. Assumes offer is in the list. -void -remove_offer (TradeOfferList * list, TradeOffer * offer) -{ - if (list->length == 1) { - list->first = list->last = NULL; - list->length = 0; - } else if (list->length > 1) { - TradeOffer * prev = offer->prev, * next = offer->next; - if (prev) - prev->next = next; - if (next) - next->prev = prev; - if (list->first == offer) - list->first = next; - if (list->last == offer) - list->last = prev; - list->length -= 1; - } - offer->prev = offer->next = NULL; -} - -void __fastcall -patch_PopupForm_set_text_key_and_flags (PopupForm * this, int edx, char * script_path, char * text_key, int param_3, int param_4, int param_5, int param_6) -{ - int * p_stack = (int *)&script_path; - int ret_addr = p_stack[-1]; - - int is_initial_gold_trade = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_INITIAL_GOLD_OFFER_RETURN), - is_modifying_gold_trade = (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN ) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_OFFER_RETURN); - - // This function gets called from all over the place, check that it's being called to setup the set gold amount popup in the trade screen - if (is->current_config.autofill_best_gold_amount_when_trading && (is_initial_gold_trade || is_modifying_gold_trade)) { - int asking = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN); - int is_lump_sum = is_initial_gold_trade ? - p_stack[TRADE_GOLD_SETTER_IS_LUMP_SUM_OFFSET] : // Read this variable from the caller's frame - is->modifying_gold_trade->param_1; - - int their_id = p_diplo_form->other_party_civ_id, - our_id = p_main_screen_form->Player_CivID; - - // This variable will store the result of the optimization process and it's what will be used as the final amount presented to the - // player in the popup and left in the TradeOffer object (if applicable). Default to zero for new offers and the previous amount when - // modifying an offer. When modifying, we also zero the amount on the table b/c the optimization process only works properly from that - // starting point. - int best_amount = 0; - if (is_modifying_gold_trade) { - best_amount = is->modifying_gold_trade->param_2; - is->modifying_gold_trade->param_2 = 0; - } - - int their_advantage; - bool is_original_acceptable = is_current_offer_acceptable (&their_advantage); - - // if (we're asking for money on an acceptable trade and are offering something) OR (we're offering money on an unacceptable trade and - // are asking for something) - if (( asking && is_original_acceptable && (p_diplo_form->our_offer_lists[their_id] .length > 0)) || - ((! asking) && (! is_original_acceptable) && (p_diplo_form->their_offer_lists[their_id].length > 0))) { - - TradeOfferList * offers = asking ? &p_diplo_form->their_offer_lists[their_id] : &p_diplo_form->our_offer_lists[their_id]; - int test_offer_is_new; - TradeOffer * test_offer = offer_gold (offers, is_lump_sum, &test_offer_is_new); - - // When asking for gold, start at zero and work upwards. When offering gold it's more complicated. For lump sum - // offers, start with our entire treasury and work downward. For GPT offers, start with an upper bound and work - // downward. The upper bound depends on how much the AI thinks it's losing on the trade (in gold) divided by 20 - // (b/c 20 turn deal) with a lot of extra headroom just to make sure. - int starting_amount; { - if (asking) - starting_amount = 0; - else { - if (is_lump_sum) - starting_amount = leaders[our_id].Gold_Encoded + leaders[our_id].Gold_Decrement; - else { - int guess = not_below (0, 0 - their_advantage) / 20; - starting_amount = 10 + guess * 2; - } - } - } - - // Check if optimization is still possible. It's not if we're offering gold and our maximum offer is unacceptable - test_offer->param_2 = starting_amount; - if (asking || is_current_offer_acceptable (NULL)) { - - best_amount = starting_amount; - for (int step_size = asking ? 1000 : -1000; step_size != 0; step_size /= 10) { - test_offer->param_2 = best_amount; - while (1) { - test_offer->param_2 += step_size; - if (test_offer->param_2 < 0) - break; - else if (is_current_offer_acceptable (NULL)) - best_amount = test_offer->param_2; - else - break; - } - } - } - - // Annoying little edge case: The limitation on AIs not to trade more than their entire treasury is handled in the - // interface not the trade evaluation logic so we have to limit our gold request here to their treasury (otherwise - // the amount will default to how much they would pay if they had infinite money). - int their_treasury = leaders[their_id].Gold_Encoded + leaders[their_id].Gold_Decrement; - if (asking && is_lump_sum && (best_amount > their_treasury)) - best_amount = their_treasury; - - // Restore the trade table to its original state. Remove & free test_offer if it was newly created, otherwise put back its - // original amount. - if (test_offer_is_new) { - remove_offer (offers, test_offer); - test_offer->vtable->destruct (test_offer, __, 1); - } - - // If we're offering gold on a trade that's already acceptable, the optimal amount is zero. We must handle this explicitly in case - // we're modifying an amount already on the table. If we didn't, the above condition wouldn't optimize the amount and we'd default to - // the original amount. - } else if ((! asking) && is_original_acceptable) - best_amount = 0; - - if (is_modifying_gold_trade) - is->modifying_gold_trade->param_2 = best_amount; - snprintf (is->ask_gold_default, sizeof is->ask_gold_default, "%d", best_amount); - is->ask_gold_default[(sizeof is->ask_gold_default) - 1] = '\0'; - PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, (int)is->ask_gold_default, param_5, param_6); - } else - PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, param_4, param_5, param_6); -} - -CityLocValidity __fastcall -patch_Map_check_city_location (Map *this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile) -{ - if (is->current_config.enable_natural_wonders) { - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { - return CLV_BLOCKED; - } - } - } - - int min_sep = is->current_config.minimum_city_separation; - CityLocValidity base_result = Map_check_city_location (this, __, tile_x, tile_y, civ_id, check_for_city_on_tile); - - // If minimum separation is one, make no change - if (min_sep == 1) - return base_result; - - // If minimum separation is <= 0, ignore the CITY_TOO_CLOSE objection to city placement unless the location is next to a city belonging to - // another civ and the settings forbid founding there. - else if ((min_sep <= 0) && (base_result == CLV_CITY_TOO_CLOSE)) { - if (is->current_config.disallow_founding_next_to_foreign_city) - for (int n = 1; n <= 8; n++) { - int x, y; - get_neighbor_coords (&p_bic_data->Map, tile_x, tile_y, n, &x, &y); - City * city = city_at (x, y); - if ((city != NULL) && (city->Body.CivID != civ_id)) - return CLV_CITY_TOO_CLOSE; - } - return CLV_OK; - - // If we have an increased separation we might have to exclude some locations the base code allows. - } else if ((min_sep > 1) && (base_result == CLV_OK)) { - // Check tiles around (x, y) for a city. Because the base result is CLV_OK, we don't have to check neighboring tiles, just those at - // distance 2, 3, ... up to (an including) the minimum separation - for (int dist = 2; dist <= min_sep; dist++) { - - // vertices stores the unwrapped coords of the tiles at the vertices of the square of tiles at distance "dist" around - // (tile_x, tile_y). The order of the vertices is north, east, south, west. - struct vertex { - int x, y; - } vertices[4] = { - {tile_x , tile_y - 2*dist}, - {tile_x + 2*dist, tile_y }, - {tile_x , tile_y + 2*dist}, - {tile_x - 2*dist, tile_y } - }; - - // neighbor index for direction of tiles along edge starting from each vertex - // values correspond to directions: southeast, southwest, northwest, northeast - int edge_dirs[4] = {3, 5, 7, 1}; - - // Loop over verts and check tiles along their associated edges. The N vert is associated with the NE edge, the E vert with - // the SE edge, etc. - for (int vert = 0; vert < 4; vert++) { - wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); - int dx, dy; - neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); - for (int j = 0; j < 2*dist; j++) { // loop over tiles along this edge - int cx = vertices[vert].x + j * dx, - cy = vertices[vert].y + j * dy; - wrap_tile_coords (&p_bic_data->Map, &cx, &cy); - if (city_at (cx, cy)) - return CLV_CITY_TOO_CLOSE; - } - } - - } - return base_result; - - } else - return base_result; -} - -bool -is_zero_strength (UnitType * ut) -{ - return (ut->Attack == 0) && (ut->Defence == 0); -} - -bool -is_captured (Unit_Body * u) -{ - return (u->RaceID >= 0) && (u->CivID >= 0) && (u->CivID < 32) && leaders[u->CivID].RaceID != u->RaceID; -} - -// Decides whether or not units "a" and "b" are duplicates, i.e., whether they are interchangeable. -// If surface_only is set, the function checks only surface-level characteristics, meaning those that are visible to other players. -bool -are_units_duplicate (Unit_Body * a, Unit_Body * b, bool surface_only) -{ - UnitType * a_type = &p_bic_data->UnitTypes[a->UnitTypeID], - * b_type = &p_bic_data->UnitTypes[b->UnitTypeID]; - - // If only doing a surface comparison, look through the alternate strategy types to the base types. The difference b/w the alt types is only - // their AI strategies, and that isn't considered a surface feature. - if (surface_only) { - while (a_type->alternate_strategy_for_id >= 0) - a_type = &p_bic_data->UnitTypes[a_type->alternate_strategy_for_id]; - while (b_type->alternate_strategy_for_id >= 0) - b_type = &p_bic_data->UnitTypes[b_type->alternate_strategy_for_id]; - } - - // a and b are duplicates "on the surface" if... - bool are_surface_duplicates = - // ... they belong to the same player ... - (a->CivID == b->CivID) && - - // ... they have the same type that is not [a leader OR army] AND not a transport AND ... - (a_type == b_type) && - (! (UnitType_has_ability (a_type, __, UTA_Leader) || UnitType_has_ability (a_type, __, UTA_Army))) && - (a_type->Transport_Capacity == 0) && - - // ... they've taken the same amount of damage AND have the same charm status AND ... - (a->Damage == b->Damage) && (a->charmed == b->charmed) && - - // ... they're either both fortified or both not AND ... - (! (a->UnitState == UnitState_Fortifying) ^ (b->UnitState == UnitState_Fortifying)) && - - // ... [they have the same experience level OR are zero strength units] AND ... - ((a->Combat_Experience == b->Combat_Experience) || is_zero_strength (a_type)) && - - // ... [they are both not contained in any unit OR they are both contained in the same unit] AND ... - (((a->Container_Unit < 0) && (b->Container_Unit < 0)) || (a->Container_Unit == b->Container_Unit)) && - - // ... neither one is carrying a princess AND ... - ((a->carrying_princess_of_race < 0) && (b->carrying_princess_of_race < 0)) && - - // ... [they are both captured units OR are both native units] AND ... - (! (is_captured (a) ^ is_captured (b))) && - - // ... their custom names are identical. - (0 == strncmp (a->Custom_Name.S, b->Custom_Name.S, sizeof (a->Custom_Name))); - - if ((! are_surface_duplicates) || surface_only) - return are_surface_duplicates; - - // a and b are additionally "deep", i.e. in all ways, duplicates if... - bool are_deep_duplicates = - // ... they've used up the same number of moves AND ... - (a->Moves == b->Moves) && - - // ... they have matching statuses (has attacked this turn, etc.) AND states (is fortified, is doing worker action, etc.) AND automation status AND ... - (a->Status == b->Status) && (a->UnitState == b->UnitState) && (a->automated == b->automated) && - - // ... they have both done the same number of airdrops this turn. - (itable_look_up_or (&is->airdrops_this_turn, a->ID, 0) == itable_look_up_or (&is->airdrops_this_turn, b->ID, 0)); - - return are_deep_duplicates; -} - -bool -is_busy (Unit * unit) -{ - int state = unit->Body.UnitState; - return ((state >= UnitState_Build_Mines) && (state <= UnitState_Explore)) || - (state == UnitState_Auto_Bombard) || (state == UnitState_Auto_Air_Bombard) || - unit->Body.automated; -} - -int __fastcall -patch_Context_Menu_add_item_and_set_color (Context_Menu * this, int edx, int item_id, char * text, int red) -{ - // Initialize the array of duplicate counts. The array is 0x100 items long because that's the maximum number of items a menu can have. - if (is->current_config.group_units_on_right_click_menu && - (is->unit_menu_duplicates == NULL)) { - unsigned dups_size = 0x100 * sizeof is->unit_menu_duplicates[0]; - is->unit_menu_duplicates = malloc (dups_size); - memset (is->unit_menu_duplicates, 0, dups_size); - } - - // Check if this menu item is a valid unit and grab pointers to its info - int unit_id; - Unit_Body * unit_body; - bool disable = false, put_icon = false; - int icon_index = 0; - if ((0 <= (unit_id = item_id - (0x13 + p_bic_data->UnitTypeCount))) && - (NULL != (unit_body = p_units->Units[unit_id].Unit)) && - (unit_body->UnitTypeID >= 0) && (unit_body->UnitTypeID < p_bic_data->UnitTypeCount)) { - - if (is->current_config.group_units_on_right_click_menu) { - // Loop over all existing menu items and check if any of them is a unit that's a duplicate of the one being added - for (int n = 0; n < this->Item_Count; n++) { - Context_Menu_Item * item = &this->Items[n]; - int dup_unit_id = this->Items[n].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount); - Unit_Body * dup_body; - if ((dup_unit_id >= 0) && - (NULL != (dup_body = p_units->Units[dup_unit_id].Unit)) && - are_units_duplicate (unit_body, dup_body, unit_body->CivID != p_main_screen_form->Player_CivID)) { - // The new item is a duplicate of the nth. Mark that in the duplicate counts array and return without actually - // adding the item. It doesn't matter what value we return because the caller doesn't use it. - is->unit_menu_duplicates[n] += 1; - return 0; - } - } - } - - if (unit_body->CivID == p_main_screen_form->Player_CivID) { - Unit * unit = (Unit *)((int)unit_body - offsetof (Unit, Body)); - UnitType * unit_type = &p_bic_data->UnitTypes[unit_body->UnitTypeID]; - bool no_moves_left = unit_body->Moves >= patch_Unit_get_max_move_points (unit); - if (no_moves_left && is->current_config.gray_out_units_on_menu_with_no_remaining_moves) - disable = true; - - // Put an icon next to this unit if we're configured to do so and it's not in an army - Unit * container; - if (is->current_config.put_movement_icons_on_units_on_menu && - ((NULL == (container = get_unit_ptr (unit_body->Container_Unit))) || - (! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)))) { - put_icon = true; - - bool attacker = is_offensive_combat_type (unit_type) || (Unit_has_ability (unit, __, UTA_Army) && (Unit_count_contained_units (unit) >= 1)), - busy = is_busy (unit); - - int icon_set_index = ((int)busy << 1) + (int)(! attacker); - - int icon_row; { - if (no_moves_left) - icon_row = URCMI_CANT_MOVE; - else if (unit_body->Moves == 0) - icon_row = URCMI_UNMOVED; - else if (! attacker) - icon_row = URCMI_MOVED_NO_ATTACK; - else - icon_row = (! has_exhausted_attack (unit)) ? URCMI_MOVED_CAN_ATTACK : URCMI_MOVED_NO_ATTACK; - } - - icon_index = icon_set_index * COUNT_UNIT_RCM_ICONS + icon_row; - } - } - } - - int tr = Context_Menu_add_item_and_set_color (this, __, item_id, text, red); - - if (disable) - Context_Menu_disable_item (this, __, item_id); - - if (put_icon) { - init_unit_rcm_icons (); - if (is->unit_rcm_icon_state == IS_OK) - Context_Menu_put_image_on_item (this, __, item_id, &is->unit_rcm_icons[icon_index]); - } - - return tr; -} - -int __fastcall -patch_Context_Menu_open (Context_Menu * this, int edx, int x, int y, int param_3) -{ - int * p_stack = (int *)&x; - int ret_addr = p_stack[-1]; - - if (is->current_config.enable_named_tiles && - is->named_tile_menu_active) { - int tile_x = is->named_tile_menu_tile_x; - int tile_y = is->named_tile_menu_tile_y; - Tile * tile = tile_at (tile_x, tile_y); - if (tile_can_be_named (tile, tile_x, tile_y)) { - struct named_tile_entry * entry = get_named_tile_entry (tile); - char menu_text[64]; - if ((entry != NULL) && (entry->name[0] != '\0')) - snprintf (menu_text, sizeof menu_text, "%s %s", is->c3x_labels[CL_RENAME_TILE], entry->name); - else - strcpy (menu_text,is->c3x_labels[CL_NAME_TILE]); - if (this->Item_Count > 0) - Context_Menu_add_separator (this, __, 0); - Context_Menu_add_item (this, __, NAMED_TILE_MENU_ID, menu_text, false, (Sprite *)0x0); - } - } - - if (is->current_config.group_units_on_right_click_menu && - (ret_addr == ADDR_OPEN_UNIT_MENU_RETURN) && - (is->unit_menu_duplicates != NULL)) { - - // Change the menu text to include the duplicate counts. This is pretty straight forward except for a couple little issues: we must - // use the game's internal malloc & free for compatibility with the base code and must call a function that widens the menu form, - // as necessary, to accommodate the longer strings. - for (int n = 0; n < this->Item_Count; n++) - if (is->unit_menu_duplicates[n] > 0) { - Context_Menu_Item * item = &this->Items[n]; - unsigned new_text_len = strlen (item->Text) + 20; - char * new_text = civ_prog_malloc (new_text_len); - - // Print entry text including dup count to new_text. Biggest complication here is that we want to print the dup count - // after any leading spaces to preserve indentation. - { - int num_spaces = 0; - while (item->Text[num_spaces] == ' ') - num_spaces++; - snprintf (new_text, new_text_len, "%.*s%dx %s", num_spaces, item->Text, is->unit_menu_duplicates[n] + 1, &item->Text[num_spaces]); - new_text[new_text_len - 1] = '\0'; - } - - civ_prog_free (item->Text); - item->Text = new_text; - Context_Menu_widen_for_text (this, __, new_text); - } - - // Clear the duplicate counts - memset (is->unit_menu_duplicates, 0, 0x100 * sizeof is->unit_menu_duplicates[0]); - } - - return Context_Menu_open (this, __, x, y, param_3); -} - -bool -is_material_unit (UnitType const * type, bool * out_is_pop_else_caravan) -{ - int join_city_action = UCV_Join_City & 0x0FFFFFFF; // To get the join city action code, use the command value and mask out the top 4 category bits - int disband_action = UCV_Disband & 0x0FFFFFFF; - if ((type->Attack | type->Defence | type->Bombard_Strength) == 0) { // if non-combat unit - if ((type->PopulationCost > 0) && (type->Worker_Actions == join_city_action)) { - *out_is_pop_else_caravan = true; - return true; - } else if ((type->Standard_Actions & disband_action) && (type->Worker_Actions == 0)) { - *out_is_pop_else_caravan = false; - return true; - } else - return false; - } else - return false; -} - -void -ai_move_material_unit (Unit * this) -{ - int type_id = this->Body.UnitTypeID; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - UnitType * type = &p_bic_data->UnitTypes[type_id]; - - // Determine whether this is a pop unit (will search for a city to join) or a caravan (will search for a city to disband) - int join_city_action = UCV_Join_City & 0x0FFFFFFF; - bool pop_else_caravan = type->Worker_Actions == join_city_action; - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - - // This part of the code follows how the replacement leader AI works. Basically it disbands the unit if it's on a continent with no - // friendly cities, then flees if it's in danger, then moves it along a set path if it has one. - if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { - Unit_disband (this); - return; - } - if (any_enemies_near_unit (this, 49)) { - Unit_set_state (this, __, UnitState_Fleeing); - bool done = this->vtable->work (this); - if (done || (this->Body.UnitState != 0)) - return; - } - byte next_move = Unit_pop_next_move_from_path (this); - if (next_move > 0) { - this->vtable->Move (this, __, next_move, 0); - return; - } - - // Find the best city to act on - City * best_city = NULL; - int best_city_value = pop_else_caravan ? -1 : 0; // min value to act is 0 for pop units, 1 for caravans - FOR_CITIES_OF (coi, this->Body.CivID) { - City * city = coi.city; - Tile * city_tile = tile_at (city->Body.X, city->Body.Y); - if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { - - if (pop_else_caravan) { - // Skip this city if it can't support another citizen - if ((city->Body.FoodIncome <= 0) || - (City_requires_improvement_to_grow (city) > -1)) - continue; - } else { - // Skip this city if its current build can't be rushed - if (! City_can_take_outside_shields (city, __, 0)) - continue; - } - - // Consider distance. - int dist_in_turns; - if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) - continue; // No path or unit cannot move - - int value; - if (pop_else_caravan) - value = 1000 / (10 + dist_in_turns); // Base value of 100 * 10 / (10 + dist_in_turn) - else { - // value is number of useful shields we'd get by moving to this city and disbanding there - int shields_per_turn = get_city_production_rate (city, city->Body.Order_Type, city->Body.Order_ID), - shields_to_complete_build = City_get_order_cost (city) - City_get_order_progress (city) - shields_per_turn, - disband_value = Leader_get_unit_cost (&leaders[city->Body.CivID], __, type_id, false) >> 2; - value = not_above (shields_to_complete_build, disband_value) - shields_per_turn * dist_in_turns; - } - - // Scale value by city corruption rate for pop units or caravan units targeting cities building improvs - if (pop_else_caravan || (city->Body.Order_Type == COT_Improvement)) { - int good_shields = city->Body.ProductionIncome, - corrupt_shields = city->Body.ProductionLoss; - if (good_shields + corrupt_shields > 0) - value = (value * good_shields) / (good_shields + corrupt_shields); - else - value = -1; - } - - if (value > best_city_value) { - best_city = city; - best_city_value = value; - } - } - } - - // Join city if we're already in the city we want to join, otherwise move to that city. If we couldn't find a city to join, go to the - // nearest established city and wait. - City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); - City * moving_to_city = NULL; - if (best_city != NULL) { - if (best_city == in_city) { - if (pop_else_caravan && patch_Unit_can_perform_command (this, __, UCV_Join_City)) { - Unit_join_city (this, __, in_city); - return; - } else if ((! pop_else_caravan) && patch_Unit_can_perform_command (this, __, UCV_Disband)) { - Unit_disband (this); - return; - } - } else - moving_to_city = best_city; - } else if (in_city == NULL) - moving_to_city = find_nearest_established_city (this, continent_id); - - if (moving_to_city) { - int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); - if (first_move > 0) { - Unit_set_escortee (this, __, -1); - this->vtable->Move (this, __, first_move, 0); - return; - } - } - - // Nothing to do, nowhere to go, just fortify in place. - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -int __stdcall -patch_get_anarchy_length (int leader_id) -{ - int base = get_anarchy_length (leader_id); - int multiplier = is->current_config.anarchy_length_percent; - if (multiplier != 100) { - // Anarchy cannot be less than 2 turns or you'll get an instant government switch. Only let that happen when the percent multiplier is - // set below zero, indicating a desire for no anarchy. Otherwise we can't reduce anarchy below 2 turns. - if (multiplier < 0) - return 1; - else if (base <= 2) - return base; - else - return not_below (2, rand_div (base * multiplier, 100)); - } else - return base; -} - -bool __fastcall -patch_Unit_check_king_ability_while_spawning (Unit * this, int edx, enum UnitTypeAbilities a) -{ - if (is->current_config.dont_give_king_names_in_non_regicide_games && - ((*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) == 0)) - return false; - else - return Unit_has_ability (this, __, a); -} - -int __fastcall -patch_Map_compute_neighbor_index_for_pass_between (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - if (is->current_config.enable_land_sea_intersections) - return 0; - else - return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); -} - -// This call replacement used to be part of improvement perfuming but now its only purpose is to set ai_considering_order when -// ai_choose_production is looping over improvements. -bool __fastcall -patch_Improvement_has_wonder_com_bonus_for_ai_prod (Improvement * this, int edx, enum ImprovementTypeWonderFeatures flag) -{ - is->ai_considering_order.OrderID = this - p_bic_data->Improvements; - is->ai_considering_order.OrderType = COT_Improvement; - return Improvement_has_wonder_flag (this, __, flag); -} - -// Similarly, this one sets the var when looping over unit types. -bool __fastcall -patch_UnitType_has_strat_0_for_ai_prod (UnitType * this, int edx, byte n) -{ - is->ai_considering_order.OrderID = this - p_bic_data->UnitTypes; - is->ai_considering_order.OrderType = COT_Unit; - return UnitType_has_ai_strategy (this, __, n); -} - -int -compare_ai_prod_valuations (void const * vp_a, void const * vp_b) -{ - struct ai_prod_valuation const * a = vp_a, - * b = vp_b; - if (a->point_value > b->point_value) return -1; - else if (b->point_value > a->point_value) return 1; - else return 0; -} - -void -rank_ai_production_options (City * city) -{ - is->count_ai_prod_valuations = 0; - City_Order unused; - patch_City_ai_choose_production (city, __, &unused); // records valuations in is->ai_prod_valuations - qsort (is->ai_prod_valuations, is->count_ai_prod_valuations, sizeof is->ai_prod_valuations[0], compare_ai_prod_valuations); -} - -void __fastcall -patch_City_Form_m82_handle_key_event (City_Form * this, int edx, int virtual_key_code, int is_down) -{ - if (is->current_config.enable_ai_production_ranking && - (~*p_human_player_bits & (1 << this->CurrentCity->Body.CivID)) && - (virtual_key_code == VK_P) && is_down) { - rank_ai_production_options (this->CurrentCity); - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_AI_PROD_RANKING", -1, 0, 0, 0); - char s[200]; - for (int n = 0; n < is->count_ai_prod_valuations; n++) { - struct ai_prod_valuation const * val = &is->ai_prod_valuations[n]; - char * name = (val->order_type == COT_Improvement) ? p_bic_data->Improvements[val->order_id].Name.S : p_bic_data->UnitTypes[val->order_id].Name; - - int show_strategy = -1; - if (val->order_type == COT_Unit) - itable_look_up (&is->unit_type_alt_strategies, val->order_id, &show_strategy); - - if ((show_strategy >= 0) && (show_strategy <= CL_LAST_UNIT_STRAT - CL_FIRST_UNIT_STRAT)) - snprintf (s, sizeof s, "^%d %s (%s)", val->point_value, name, is->c3x_labels[CL_FIRST_UNIT_STRAT + show_strategy]); - else - snprintf (s, sizeof s, "^%d %s", val->point_value, name); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - patch_show_popup (popup, __, 0, 0); - - } else if (is->current_config.toggle_zoom_with_z_on_city_screen && - (virtual_key_code == VK_Z) && is_down) { - p_bic_data->is_zoomed_out = ! p_bic_data->is_zoomed_out; - Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, this->CurrentCity->Body.X, get_city_screen_center_y (this->CurrentCity), 0, true, false); // also redraws map - this->Base.vtable->m73_call_m22_Draw ((Base_Form *)this); - } - - City_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); -} - -bool -can_harvest_shields_from_forest (Tile * tile) -{ - int flags = tile->vtable->m43_Get_field_30 (tile); - return (flags & 0x10000000) == 0; -} - -void __fastcall -patch_open_tile_info (void * this, int edx, int mouse_x, int mouse_y, int civ_id) -{ - int tx, ty; - if (is->current_config.show_detailed_tile_info && - (! Main_Screen_Form_get_tile_coords_under_mouse (p_main_screen_form, __, mouse_x, mouse_y, &tx, &ty))) { - is->viewing_tile_info_x = tx; - is->viewing_tile_info_y = ty; - is->tile_info_open = true; - } else - is->viewing_tile_info_x = is->viewing_tile_info_y = -1; - - open_tile_info (this, __, mouse_x, mouse_y, civ_id); - - is->tile_info_open = false; -} - -int __fastcall -patch_Match_ai_eval_city_location (void * this, int edx, int x, int y, int civ_id, bool param_4, int * out_breakdown) -{ - is->ai_evaling_city_loc_x = x; - is->ai_evaling_city_loc_y = y; - is->ai_evaling_city_field_30_get_counter = 0; - - return Match_ai_eval_city_location (this, __, x, y, civ_id, param_4, out_breakdown); -} - -bool -is_explored (Tile * tile, int civ_id) -{ - unsigned explored_bits = tile->Body.Fog_Of_War; - int in_debug_mode = (*p_debug_mode_bits & 8) != 0; // checking bit 3 here b/c that's how resource visibility is checked in open_tile_info - if (in_debug_mode || (explored_bits & (1 << civ_id))) - return true; - else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND - ((1 << civ_id) & *p_human_player_bits) && // "civ_id" is a human player AND - (explored_bits & *p_human_player_bits)) // any human player has visibility on the tile - return true; - else - return false; -} - -// On the GOG executable, this function intercepts the call to draw the "No information available" text on a unexplored (black) tile. In that case we -// replace that text with the coords. But on the Steam EXE this func also intercepts the call that draws the resource name on the visible tile info -// box b/c the call site is reused via a jump. So we must check that the tile is actually unexplored before replacing the text so that the resource -// name doesn't get overwritten. -int __fastcall -patch_PCX_Image_draw_no_tile_info (PCX_Image * this, int edx, char * str, int x, int y, int str_len) -{ - Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if ((tile != p_null_tile) && ! is_explored (tile, p_main_screen_form->Player_CivID)) { - char s[100]; - snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); - s[(sizeof s) - 1] = '\0'; - return PCX_Image_draw_text (this, __, s, x, y, strlen (s)); - } else - return PCX_Image_draw_text (this, __, str, x, y, str_len); -} - -int __fastcall -patch_PCX_Image_draw_tile_info_terrain (PCX_Image * this, int edx, char * str, int x, int y, int str_len) -{ - Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if (tile != p_null_tile) { - bool show_district_name = false; - - char s[200]; - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - // Draw district name to the right of terrain name if tile has one - struct district_instance * dist = get_district_instance (tile); - - if (dist != NULL) { - show_district_name = true; - char const * display_name = is->district_configs[dist->district_id].display_name; - if ((display_name == NULL) || (display_name[0] == '\0')) - display_name = is->district_configs[dist->district_id].name; - - // If it's a wonder district with a completed wonder, show the wonder name instead - if ((dist->district_id == WONDER_DISTRICT_ID) && - (dist->wonder_info.state == WDS_COMPLETED) && - (dist->wonder_info.wonder_index >= 0) && - (dist->wonder_info.wonder_index < is->wonder_district_count)) { - char const * wonder_name = is->wonder_district_configs[dist->wonder_info.wonder_index].wonder_name; - if ((wonder_name != NULL) && (wonder_name[0] != '\0')) { - display_name = wonder_name; - } - } else if ((dist->district_id == NATURAL_WONDER_DISTRICT_ID) && - (dist->natural_wonder_info.natural_wonder_id >= 0) && - (dist->natural_wonder_info.natural_wonder_id < is->natural_wonder_count)) { - int natural_id = dist->natural_wonder_info.natural_wonder_id; - char const * natural_name = is->natural_wonder_configs[natural_id].name; - if ((natural_name != NULL) && (natural_name[0] != '\0')) { - display_name = natural_name; - } - } - - snprintf (s, sizeof s, "%s", display_name); - PCX_Image_draw_text (this, __, s, x + 68, y, strlen (s)); - } - } - - // Show sprites & sheet indexes if in debug mode - int is_debug_mode = (*p_debug_mode_bits & 4) != 0; - if (is_debug_mode) { - int sheet_index = (tile->SquareParts >> 8) & 0xFF; - int sprite_index = tile->SquareParts & 0xFF; - snprintf (s, sizeof s, "%d, %d", sheet_index, sprite_index); - PCX_Image_draw_text (this, __, s, x, y - 18, strlen (s)); - } - - // Draw tile coords on line below terrain name - snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); - PCX_Image_draw_text (this, __, s, x, y + 14, strlen (s)); - - if ((is->city_loc_display_perspective >= 0) && - ((1 << is->city_loc_display_perspective) & *p_player_bits)) { - int eval = patch_Match_ai_eval_city_location (p_match, __, is->viewing_tile_info_x, is->viewing_tile_info_y, is->city_loc_display_perspective, false, NULL); - if (eval > 0) { - snprintf (s, sizeof s, "%d", eval - 1000000); - PCX_Image_draw_text (this, __, s, x + 95, y, strlen (s)); - } - } - - // If tile has been chopped and district name not shown (uses same space), indicate that to the right of the terrain name - if (! can_harvest_shields_from_forest (tile) && !show_district_name) - PCX_Image_draw_text (this, __, is->c3x_labels[CL_CHOPPED], x + 145, y, strlen (is->c3x_labels[CL_CHOPPED])); - } - return PCX_Image_draw_text (this, __, str, x, y, str_len); -} - -int __fastcall -patch_City_compute_corrupted_yield (City * this, int edx, int gross_yield, bool is_production) -{ - Leader * leader = &leaders[this->Body.CivID]; - - if (is->current_config.zero_corruption_when_off && - (p_bic_data->Governments[leader->GovernmentType].CorruptionAndWaste == CWT_Off)) - return 0; - - int tr = City_compute_corrupted_yield (this, __, gross_yield, is_production); - - if (is->current_config.promote_wonder_decorruption_effect) { - int actual_capital_id = leader->CapitalID; - for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { - Improvement * improv = &p_bic_data->Improvements[improv_id]; - City * pseudo_capital = NULL; - if (improv->SmallWonderFlags & ITSW_Reduces_Corruption) { - if (improv->Characteristics & ITC_Small_Wonder) { - pseudo_capital = get_city_ptr (leader->Small_Wonders[improv_id]); - } else if (improv->Characteristics & ITC_Wonder) { - pseudo_capital = get_city_ptr (Game_get_wonder_city_id(p_game, __, improv_id)); - } - - if (pseudo_capital != NULL && pseudo_capital->Body.CivID == this->Body.CivID && pseudo_capital->Body.ID != actual_capital_id) { - leader->CapitalID = pseudo_capital->Body.ID; - int fp_corrupted_yield = City_compute_corrupted_yield (this, __, gross_yield, is_production); - if (fp_corrupted_yield < tr) - tr = fp_corrupted_yield; - } - } - } - leader->CapitalID = actual_capital_id; - } - - return tr; -} - -int __fastcall -patch_Sprite_draw (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - Sprite * to_draw = get_sprite_proxy_for_current_hour(this); - return Sprite_draw(to_draw ? to_draw : this, __, canvas, pixel_x, pixel_y, color_table); -} - -int __fastcall -patch_Sprite_draw_on_map (Sprite * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) -{ - Sprite * to_draw = get_sprite_proxy_for_current_hour(this); - return Sprite_draw_on_map(to_draw ? to_draw : this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); -} - -bool -is_or_could_become_grassland (Tile * tile) -{ - enum SquareTypes sq_type = tile->vtable->m50_Get_Square_BaseType (tile), - underlying_type = tile->vtable->m49_Get_Square_RealType (tile); - int worker_job_id = p_bic_data->TileTypes[sq_type].WorkerJobID; - return sq_type == SQ_Grassland || - (underlying_type == SQ_Grassland && (worker_job_id == WJ_Clean_Forest || worker_job_id == WJ_Clear_Swamp)) || - tile->vtable->m72_Get_Pollution_Effect (tile) == SQ_Grassland; -} - -void __fastcall -patch_Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (Map_Renderer * this, int edx, int param_1, int pixel_x, int pixel_y, Map_Renderer * map_renderer, int param_5, int tile_x, int tile_y, int param_8) -{ - Map * map = &p_bic_data->Map; - Tile * tile = tile_at (tile_x, tile_y); - - is->current_render_tile = tile; - is->current_render_tile_x = tile_x; - is->current_render_tile_y = tile_y; - is->current_render_tile_district = get_district_instance (tile); - - Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (this, __, param_1, pixel_x, pixel_y, map_renderer, param_5, tile_x, tile_y, param_8); - - is->current_render_tile = NULL; - is->current_render_tile_x = -1; - is->current_render_tile_y = -1; - is->current_render_tile_district = NULL; - - if ((is->city_loc_display_perspective >= 0) && - (! map->vtable->m10_Get_Map_Zoom (map)) && // Turn off display when zoomed out. Need another set of highlight images for that. - ((1 << is->city_loc_display_perspective) & *p_player_bits) && - (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. - - init_tile_highlights (); - if (is->tile_highlight_state == IS_OK) { - int eval = patch_Match_ai_eval_city_location (p_match, __, tile_x, tile_y, is->city_loc_display_perspective, false, NULL); - if (eval > 0) { - int step_size = 10; - int midpoint = (COUNT_TILE_HIGHLIGHTS % 2 == 0) ? 1000000 : (1000000 - step_size/2); - int grade = (eval >= midpoint) ? (eval - midpoint) / step_size : (eval - midpoint) / step_size - 1; - int i_highlight = clamp (0, COUNT_TILE_HIGHLIGHTS - 1, COUNT_TILE_HIGHLIGHTS/2 + grade); - Sprite_draw_on_map (&is->tile_highlights[i_highlight], __, this, pixel_x, pixel_y, 1, 1, 1, 0); - } - } - } - - // Districts-related highlights - if (is->current_config.enable_districts && - (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. - init_tile_highlights (); - if (is->tile_highlight_state == IS_OK) { - - // Draw city work radius highlights for selected worker - if (is->current_config.enable_city_work_radii_highlights && - is->highlight_city_radii) { - - if ((tile != NULL) && (tile != p_null_tile)) { - int stored_ptr; - if (itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)tile, &stored_ptr)) { - struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)stored_ptr; - Sprite_draw_on_map (&is->tile_highlights[clamp(0, COUNT_TILE_HIGHLIGHTS - 1, info->highlight_level)], __, this, pixel_x, pixel_y, 1, 1, 1, 0); - } - } - } - - // If focusing on a tile after Great Wall completed, highlight the tile while getting user confirmation - if (is->focused_tile != NULL && is->focused_tile == tile) { - Sprite_draw_on_map (&is->tile_highlights[10], __, this, pixel_x, pixel_y, 1, 1, 1, 0); - } - } - } -} - -// We determine at the start of the game where *any* AI player might want to build canals and bridges. -// This is done up front in a single pass, as re-assessing every single turn per AI is wasteful and the -// geography of the map doesn't change. This function adds all the candidates as districts, effectively -// drawing them directly on the map. We don't use it in a normal game, but this is extremely useful for -// debugging so good to keep it around. For debugging, just call it immediately after -// generate_ai_canal_and_bridge_targets () -void -insert_ai_candidate_bridge_or_canals_into_district_tile_map () -{ - if ((is->ai_candidate_bridge_or_canals_count <= 0) || (! is->ai_candidate_bridge_or_canals_initialized)) - return; - - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if (entry == NULL) - continue; - - char ss[256]; - snprintf (ss, sizeof ss, "Entry %d: district %d owner %d tiles %d completed %d\n", - ei, entry->district_id, entry->owner_civ_id, entry->tile_count, entry->completed ? 1 : 0); - (*p_OutputDebugStringA)(ss); - - for (int ti = 0; ti < entry->tile_count; ti++) { - int tx = entry->tile_x[ti]; - int ty = entry->tile_y[ti]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - snprintf (ss, sizeof ss, " (%d,%d)%s\n", tx, ty, (ti == entry->assigned_tile_index) ? " [assigned]" : ""); - (*p_OutputDebugStringA)(ss); - } - } - - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if ((entry == NULL) || (entry->completed)) - continue; - - for (int ti = 0; ti < entry->tile_count; ti++) { - int tx = entry->tile_x[ti]; - int ty = entry->tile_y[ti]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int key = (int)tile; - int existing; - if (itable_look_up (&is->district_tile_map, key, &existing)) - continue; - - struct district_instance * inst = (struct district_instance *)calloc (1, sizeof *inst); - if (inst == NULL) - continue; - inst->state = DS_COMPLETED; - inst->district_id = entry->district_id; - inst->tile_x = tx; - inst->tile_y = ty; - - itable_insert (&is->district_tile_map, key, (int)inst); - } - } -} - -void __fastcall -patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (Map_Renderer * this, int edx, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (! is->current_config.draw_forests_over_roads_and_railroads) { - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - Tile * tile = is->current_render_tile; - if ((tile == NULL) || (tile == p_null_tile)) - return; - - if ((tile->vtable->m50_Get_Square_BaseType (tile) == SQ_Forest) && - (*tile->vtable->m25_Check_Roads)(tile, __, 0)) { - is->draw_forests_over_roads_on_tile = true; - return; - } - - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Map_Renderer_m52_Draw_Roads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - // Don't draw roads if a bridge is here - if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { - Tile * tile = is->current_render_tile; - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * dist = get_district_instance (tile); - if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { - return; - } - } - } - - Map_Renderer_m52_Draw_Roads (this, __, image_index, map_renderer, pixel_x, pixel_y); - - if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) - return; - - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Map_Renderer_m52_Draw_Railroads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - // Don't draw railroads if a bridge is here - if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { - Tile * tile = is->current_render_tile; - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * dist = get_district_instance (tile); - if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { - return; - } - } - } - - Map_Renderer_m52_Draw_Railroads (this, __, image_index, map_renderer, pixel_x, pixel_y); - - if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) - return; - - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Main_Screen_Form_m82_handle_key_event (Main_Screen_Form * this, int edx, int virtual_key_code, int is_down) -{ - char s[200]; - int * last_events = is->last_main_screen_key_up_events; - bool in_game = *p_player_bits != 0; // Player bits all zero indicates we aren't currently in a game. Need to check for this because UI events - // on the main menu also pass through this function. - - if (! is_down) { - for (int n = ARRAY_LEN (is->last_main_screen_key_up_events) - 1; n > 0; n--) - last_events[n] = last_events[n - 1]; - last_events[0] = virtual_key_code; - } - - if (is->current_config.enable_ai_city_location_desirability_display && - (virtual_key_code == VK_L) && is_down && - (! (is_command_button_active (&this->GUI, UCV_Load) || is_command_button_active (&this->GUI, UCV_Unload))) && - in_game) { - int is_debug_mode = (*p_debug_mode_bits & 4) != 0; // This is how the check is done in open_tile_info. Actually there are two debug - // mode bits (4 and 8) and I don't know what the difference is. - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CITY_LOC_HIGHLIGHTS", -1, 0, 0x40, 0); - snprintf (s, sizeof s, " %s", is->c3x_labels[CL_OFF]); - s[(sizeof s) - 1] = '\0'; - PopupSelection_add_item (&popup->selection, __, s, 0); - for (int n = 1; n < 32; n++) - if ((*p_player_bits & (1 << n)) && - (is_debug_mode || (n == p_main_screen_form->Player_CivID))) { - Race * race = &p_bic_data->Races[leaders[n].RaceID]; - snprintf (s, sizeof s, " (%d) %s", n, race->vtable->GetLeaderName (race)); - s[(sizeof s) - 1] = '\0'; - PopupSelection_add_item (&popup->selection, __, s, n); - } - int sel = patch_show_popup (popup, __, 0, 0); - if (sel >= 0) { // -1 indicates popup was closed without making a selection - is->city_loc_display_perspective = (sel >= 1) ? sel : -1; - this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw - } - - } else if (is->current_config.enable_debug_mode_switch && - (in_game && ! is_down) && - (last_events[4] == VK_D) && (last_events[3] == VK_E) && (last_events[2] == VK_B) && (last_events[1] == VK_U) && (last_events[0] == VK_G)) { - PopupForm * popup = get_popup_form (); - if ((*p_debug_mode_bits & 0xC) != 0) { // Consider debug mode on if either bit is set - *p_debug_mode_bits &= ~0xC; - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - PopupForm_add_text (popup, __, "Debug mode deactivated.", 0); - patch_show_popup (popup, __, 0, 0); - } else { - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_DEBUG_ACTIVATION", -1, 0, 0, 0); - int sel = patch_show_popup (popup, __, 0, 0); - if (sel == 0) { - *p_debug_mode_bits |= 0xC; - *(bool *)((int)p_human_player_bits + 37) = true; // Set MegaTrainerXL flag indicating edited save - } - } - this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw - - // Worker keyboard shortcuts that would normally go to patch_Main_Screen_Form_issue_command - // unfortunately get short-circuited if a district is on a tile and the default popup to replace a "mine" is shown. - // The only way to catch these beforehand I've found it is to intercept the key event here. - } else if (is->current_config.enable_districts && - p_main_screen_form->Current_Unit != NULL && - is_down && - is_worker (p_main_screen_form->Current_Unit)) { - int command = -1; - bool removed_existing = false; - if (virtual_key_code == VK_M && is_command_button_active (&this->GUI, UCV_Build_Mine)) command = UCV_Build_Mine; - else if (virtual_key_code == VK_I && is_command_button_active (&this->GUI, UCV_Irrigate)) command = UCV_Irrigate; - else if (virtual_key_code == VK_N && is_command_button_active (&this->GUI, UCV_Plant_Forest)) command = UCV_Plant_Forest; - - if (handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) { - Main_Screen_Form_issue_command (this, __, command, p_main_screen_form->Current_Unit); - } - } - -after_district_key_handling: - Main_Screen_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); -} - -int __fastcall -patch_Unit_get_move_points_after_airdrop (Unit * this) -{ - int prev_airdrop_count = itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0); - itable_insert (&is->airdrops_this_turn, this->Body.ID, prev_airdrop_count + 1); - - return is->current_config.dont_end_units_turn_after_airdrop ? this->Body.Moves : patch_Unit_get_max_move_points (this); -} - -int __fastcall -patch_Unit_get_move_points_after_set_to_intercept (Unit * this) -{ - return is->current_config.patch_intercept_lost_turn_bug ? this->Body.Moves : patch_Unit_get_max_move_points (this); -} - -void __cdecl -activate_mod_info_button (int control_id) -{ - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - char s[500]; - char version_letter = 'A' + MOD_VERSION%100; - - if (MOD_PREVIEW_VERSION == 0) - snprintf (s, sizeof s, "%s: %d%c", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' '); - else - snprintf (s, sizeof s, "%s: %d%c%s %d", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' ', is->c3x_labels[CL_PREVIEW], MOD_PREVIEW_VERSION); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_CONFIG_FILES_LOADED]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - int n = 1; - for (struct loaded_config_name * lcn = is->loaded_config_names; lcn != NULL; lcn = lcn->next) { - snprintf (s, sizeof s, "^ %d. %s", n, lcn->name); - s[(sizeof s) - 1] = '\0'; - n++; - PopupForm_add_text (popup, __, s, 0); - } - - patch_show_popup (popup, __, 0, 0); -} - -int __fastcall -patch_Parameters_Form_m68_Show_Dialog (Parameters_Form * this, int edx, int param_1, void * param_2, void * param_3) -{ - init_mod_info_button_images (); - - // "b" is the mod info button. It's created each time the preferences form (or "parameters" form as Antal called it) is opened and destroyed - // every time the form is closed. This is the easiest way since it matches how the base game works. At first I tried creating the button once - // but then it will only appear once since its attachment to the prefs form is lost when the form is destroyed on closure. I tried reattaching - // the button to each newly created form but wasn't able to make that work. - Button * b = NULL; - if (is->mod_info_button_images_state == IS_OK) { - b = malloc (sizeof *b); - Button_construct (b); - - Button_initialize (b, __, - is->c3x_labels[CL_MOD_INFO_BUTTON_TEXT], // text - MOD_INFO_BUTTON_ID, // control ID - (p_bic_data->ScreenWidth - 1024) / 2 + 891, // location x - (p_bic_data->ScreenHeight - 768) / 2 + 31, // location y - MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height - (Base_Form *)this, // parent - 0); // ? - - for (int n = 0; n < 3; n++) - b->Images[n] = &is->mod_info_button_images[n]; - PCX_Image_set_font (&b->Base_Data.Canvas, __, get_font (15, FSF_NONE), 0, 0, 0); - b->activation_handler = &activate_mod_info_button; - - // Need to draw once manually or the button won't look right - b->vtable->m73_call_m22_Draw ((Base_Form *)b); - } - - int tr = Parameters_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); - - if (b != NULL) { - b->vtable->destruct ((Base_Form *)b, __, 0); - free (b); - } - - return tr; -} - -bool __fastcall -patch_City_cycle_specialist_type (City * this, int edx, int mouse_x, int mouse_y, Citizen * citizen, City_Form * city_form) -{ - int specialist_count = 0; { - Leader * city_owner = &leaders[this->Body.CivID]; - for (int n = 0; n < p_bic_data->CitizenTypeCount; n++) - specialist_count += (n != p_bic_data->default_citizen_type) && - Leader_has_tech (city_owner, __, p_bic_data->CitizenTypes[n].RequireID); - } - int shift_down = (*p_GetAsyncKeyState) (VK_SHIFT) >> 8; - int original_worker_type = citizen->WorkerType; - - // The return value of this function is not actually used by either of the two original callers. - bool tr = City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); - - // Cycle all the way around back to the previous specialist type, if appropriate. - // If the worker type was not changed after the first call to cycle_specialist_type, that indicates that the player was asked to disable - // governor management and chose not to. Do not try to cycle backwards in that case or else we'll spam the player with more popups. - if (is->current_config.reverse_specialist_order_with_shift && - shift_down && (specialist_count > 2) && (citizen->WorkerType != original_worker_type)) { - for (int n = 0; n < specialist_count - 2; n++) - City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); - } - - return tr; -} - -int __fastcall -patch_City_get_pollution_from_pop (City * this) -{ - if (! is->current_config.enable_negative_pop_pollution) - return City_get_pollution_from_pop (this); - - int base_pollution = this->Body.Population.Size - p_bic_data->General.MaximumSize_City; - if (base_pollution <= 0) - return 0; - - // Consider improvements - int net_pollution = base_pollution; - int any_cleaning_improvs = 0; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * improv = &p_bic_data->Improvements[n]; - if ((improv->ImprovementFlags & ITF_Removes_Population_Pollution) && has_active_building (this, n)) { - any_cleaning_improvs = 1; - if (improv->Pollution < 0) - net_pollution += improv->Pollution; - } - } - - if (net_pollution <= 0) - return 0; - else if (any_cleaning_improvs) - return 1; - else - return net_pollution; -} - -// The original version of this function in the base game contains a duplicate of the logic that computes the total pollution from buildings and -// pop. By re-implementing it to use the get_pollution_from_* functions, we ensure that our changes to get_pollution_from_pop will be accounted for. -// Note: This function is called from two places, one is the city screen and the other I'm not sure about. The pollution spawning logic works by -// calling the get_pollution_from_* funcs directly. -int __fastcall -patch_City_get_total_pollution (City * this) -{ - return City_get_pollution_from_buildings (this) + patch_City_get_pollution_from_pop (this); -} - -void remove_extra_palaces (City * city, City * excluded_destination); - -void -set_wonder_built_flag (int improv_id, bool is_built) -{ - if ((p_match == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) - return; - - byte * built_flags = *(byte **)((byte *)p_match + 0x4fc); - if (built_flags == NULL) - return; - - built_flags[improv_id] = is_built; -} - -bool -choose_defensive_unit_order (City * city, City_Order * out_order) -{ - if ((city == NULL) || (out_order == NULL)) - return false; - - for (int pass = 0; pass < 3; pass++) { - int best_unit_id = -1; - int best_defence = -1; - - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if (! patch_City_can_build_unit (city, __, n, 1, 0, 0)) - continue; - - int defence = type->Defence; - if ((pass < 2) && (defence <= 0)) - continue; - if ((pass <= 1) && (type->Unit_Class != UTC_Land)) - continue; - if ((pass == 0) && ((type->AI_Strategy & UTAI_Defence) == 0)) - continue; - - if (defence > best_defence) { - best_defence = defence; - best_unit_id = n; - } - } - - if (best_unit_id >= 0) { - out_order->OrderType = COT_Unit; - out_order->OrderID = best_unit_id; - return true; - } - } - - return false; -} - -// When a city adds a building that depends on a district, optionally mirror that -// building to all other same-civ cities that can also work the district tile. -void -copy_building_with_cities_in_radius (City * source, int improv_id, int required_district_id, int tile_x, int tile_y) -{ - if (! is->current_config.enable_districts) return; - if (source == NULL) return; - - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - - if (is_wonder) { - if (! is->current_config.cities_with_mutual_district_receive_wonders) - return; - } else if (! is->current_config.cities_with_mutual_district_receive_buildings) - return; - - // If a Wonder, we know the specific tile it is at, so determine which other cities have that in work radius. - if (is_wonder) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile == p_null_tile) return; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != source->Body.CivID) return; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != required_district_id) return; - if (! district_is_complete (tile, required_district_id)) return; - - FOR_CITIES_OF (coi, source->Body.CivID) { - City * city = coi.city; - if (city == NULL) continue; - if (city == source) continue; - - if (! city_radius_contains_tile (city, tile_x, tile_y)) - continue; - - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) - continue; - - if (! patch_City_has_improvement (city, __, improv_id, false)) { - City_add_or_remove_improvement (city, __, improv_id, 1, false); - } - } - } - // Else there may be multiple district instances of this type, so check each tile around the city - else { - FOR_DISTRICTS_AROUND (wai, source->Body.X, source->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != required_district_id) continue; - - FOR_CITIES_OF (coi, source->Body.CivID) { - City * city = coi.city; - if (city == NULL) continue; - if (city == source) continue; - - if (! city_radius_contains_tile (city, x, y)) - continue; - - if (! patch_City_has_improvement (city, __, improv_id, false)) { - City_add_or_remove_improvement (city, __, improv_id, 1, false); - - // If city already building it, switch to a defensive unit instead - int current_improv_id = city->Body.Order_ID; - if (current_improv_id == improv_id) { - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - // Show message to user - if (is->current_config.show_message_when_building_received_by_mutual_district && - city->Body.CivID == p_main_screen_form->Player_CivID) { - char msg[300]; - snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_RECEIVED], - p_bic_data->Improvements[improv_id].Name.S, - is->c3x_labels[CL_FROM_SHARED], - is->district_configs[required_district_id].name, - is->c3x_labels[CL_WITH], - source->Body.CityName); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - } - } - } - } -} - -void -grant_existing_district_buildings_to_city (City * city) -{ - if (! is->current_config.enable_districts || - (! is->current_config.cities_with_mutual_district_receive_buildings && - ! is->current_config.cities_with_mutual_district_receive_wonders) || - (city == NULL)) - return; - - int civ_id = city->Body.CivID; - int current_improv_id = city->Body.Order_ID; - bool prev_flag = is->sharing_buildings_by_districts_in_progress; - is->sharing_buildings_by_districts_in_progress = true; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - Tile * tile = wai.tile; - - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - struct district_infos * info = &is->district_infos[district_id]; - if (info->dependent_building_count <= 0) - continue; - - FOR_CITIES_OF (coi, civ_id) { - City * other = coi.city; - if ((other == NULL) || (other == city)) - continue; - - if (! city_radius_contains_tile (other, wai.tile_x, wai.tile_y)) - continue; - - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != other->Body.CivID) - continue; - - for (int i = 0; i < info->dependent_building_count; i++) { - int building_id = info->dependent_building_ids[i]; - if (building_id < 0) - continue; - - Improvement * building = &p_bic_data->Improvements[building_id]; - bool is_wonder = (building->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - - if (is_wonder) - continue; - - if (! patch_City_has_improvement (other, __, building_id, false)) - continue; - - if (patch_City_has_improvement (city, __, building_id, false)) - continue; - - City_add_or_remove_improvement (city, __, building_id, 1, false); - - // If city already building it, switch to a defensive unit instead - if (current_improv_id == building_id) { - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - if (is->current_config.show_message_when_building_received_by_mutual_district && - city->Body.CivID == p_main_screen_form->Player_CivID) { - char msg[300]; - snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_RECEIVED], - p_bic_data->Improvements[building_id].Name.S, - is->c3x_labels[CL_FROM_SHARED], - is->district_configs[district_id].name, - is->c3x_labels[CL_WITH], - other->Body.CityName); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - } - } - } - - is->sharing_buildings_by_districts_in_progress = prev_flag; -} - -void -auto_build_great_wall_districts_for_civ (int civ_id) -{ - if ((! is->current_config.enable_districts) || - (! is->current_config.enable_great_wall_districts) || - (! is->current_config.auto_build_great_wall_around_territory) || - (is->great_wall_auto_build == GWABS_DONE) || - (civ_id < 0) || - is->is_placing_scenario_things) - return; - - bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; - - if ((GREAT_WALL_DISTRICT_ID < 0) || (GREAT_WALL_DISTRICT_ID >= is->district_count)) { - is->great_wall_auto_build = GWABS_DONE; - return; - } - - init_tile_highlights (); - - struct district_config const * cfg = &is->district_configs[GREAT_WALL_DISTRICT_ID]; - if ((cfg->command == -1) || (! leader_can_build_district (&leaders[civ_id], GREAT_WALL_DISTRICT_ID))) { - is->great_wall_auto_build = GWABS_DONE; - return; - } - - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_BEGIN_GREAT_WALL_AUTO_BUILD", -1, 0, 0, 0); - if (civ_id == p_main_screen_form->Player_CivID) - patch_show_popup (popup, __, 0, 0); - - is->great_wall_auto_build = GWABS_RUNNING; - - unsigned int const replaceable_flags = TILE_FLAG_MINE | TILE_FLAG_IRRIGATION; - bool require_other_civ_border = (! is_human) && is->current_config.ai_auto_build_great_wall_strategy == AAGWS_OTHER_CIV_BORDERED_ONLY; - - for (int index = 0; index < p_bic_data->Map.TileCount; index++) { - int x, y; - tile_index_to_coords (&p_bic_data->Map, index, &x, &y); - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->CityID >= 0) - continue; - if (tile->vtable->m35_Check_Is_Water (tile)) - continue; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) - continue; - - bool has_border = false; - bool has_other_civ_border = false; - FOR_TILES_AROUND (tai, 9, x, y) { - if (tai.n == 0) - continue; - Tile * neighbor = tai.tile; - if (neighbor->vtable->m35_Check_Is_Water (neighbor)) - continue; - int owner_id = neighbor->vtable->m38_Get_Territory_OwnerID (neighbor); - if (owner_id != civ_id) { - has_border = true; - if (owner_id > 0) { - has_other_civ_border = true; - break; - } - } - } - if (! has_border) - continue; - if (require_other_civ_border && (! has_other_civ_border)) - continue; - - if (! district_is_buildable_on_tile (cfg, tile)) - continue; - if (! district_resource_prereqs_met (tile, x, y, GREAT_WALL_DISTRICT_ID)) - continue; - - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == GREAT_WALL_DISTRICT_ID)) { - if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) { - inst->state = DS_COMPLETED; - if (! tile->vtable->m18_Check_Mines (tile, __, 0)) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); - set_tile_unworkable_for_all_cities (tile, x, y); - } - continue; - } - - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int replace_flags = overlay_flags & replaceable_flags; - bool has_district = (inst != NULL); - int existing_district_id = -1; - if (has_district) - existing_district_id = inst->district_id; - - if (is_human && civ_id == p_main_screen_form->Player_CivID) { - is->focused_tile = tile; - Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, x, y, 0, true, false); - - char * popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL"; - set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); - - if (has_district) { - bool redundant_district = district_instance_is_redundant (inst, tile); - bool would_lose_buildings; - would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, x, y); - if (redundant_district) - would_lose_buildings = false; - if ((existing_district_id >= 0) && (existing_district_id < is->district_count)) { - set_popup_str_param (1, (char *)is->district_configs[existing_district_id].display_name, -1, -1); - } - popup_key = would_lose_buildings - ? "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT" - : "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT_SAFE"; - } else if (replace_flags != 0) { - popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_IMPROVEMENT"; - } - - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - popup_key, - -1, 0, 0, 0); - - int sel = patch_show_popup (popup, __, 0, 0); - if (sel != 0) - continue; - } - - if (has_district || (replace_flags != 0)) { - if (has_district) { - int inst_x = x, inst_y = y; - if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) - continue; - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); - handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); - } - - if (replace_flags != 0) - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, replace_flags, x, y); - } - - if (get_district_instance (tile) != NULL) - continue; - - inst = ensure_district_instance (tile, GREAT_WALL_DISTRICT_ID, x, y); - if (inst == NULL) - continue; - - inst->district_id = GREAT_WALL_DISTRICT_ID; - district_instance_set_coords (inst, x, y); - inst->state = DS_COMPLETED; - if (! tile->vtable->m18_Check_Mines (tile, __, 0)) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); - set_tile_unworkable_for_all_cities (tile, x, y); - } - - is->great_wall_auto_build = GWABS_DONE; - is->focused_tile = NULL; -} - -//We need to forwards-declare this -void __fastcall -patch_City_manage_by_governor (City * this, int edx, bool manage_professions); - -void __fastcall -patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3) -{ - int init_maintenance = this->Body.Improvements_Maintenance; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder_removal = (! add) && - ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && - (! is->is_placing_scenario_things); - int init_work_area_radius = get_work_ring_limit_total(this); - - // The enable_negative_pop_pollution feature changes the rules so that improvements flagged as removing pop pollution and having a negative - // pollution amount contribute to the city's pop pollution instead of building pollution. Here we make sure that such improvements do not - // contribute to building pollution by temporarily zeroing out their pollution stat when they're added to or removed from a city. - if (is->current_config.enable_negative_pop_pollution && - (improv->ImprovementFlags & ITF_Removes_Population_Pollution) && - (improv->Pollution < 0)) { - int saved_pollution_amount = improv->Pollution; - improv->Pollution = 0; - City_add_or_remove_improvement (this, __, improv_id, add, param_3); - improv->Pollution = saved_pollution_amount; - } else - City_add_or_remove_improvement (this, __, improv_id, add, param_3); - - if (is->current_config.enable_districts && is_wonder_removal && ((improv->Characteristics & ITC_Wonder) != 0)) { - if (is->current_config.destroyed_wonders_can_be_built_again) - set_wonder_built_flag (improv_id, false); - - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, improv->Name.S, -1, -1); - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - is->current_config.destroyed_wonders_can_be_built_again ? "C3X_DISTRICT_WONDER_DESTROYED_REBUILD" : "C3X_DISTRICT_WONDER_DESTROYED", - -1, 0, 0, 0 - ); - patch_show_popup (popup, __, 0, 0); - } - - // If the city just finished a wonder and was using a wonder district for that, set the wonder - // as completed (which switches the art over and prevents the tile from being used again) - int x, y; - if (add && is->current_config.enable_districts && is->current_config.enable_wonder_districts) { - if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { - int matched_windex = find_wonder_config_index_by_improvement_id (improv_id); - - if (matched_windex >= 0) { - FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { - x = wai.tile_x; - y = wai.tile_y; - Tile * t = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - if (! wonder_is_buildable_on_tile (t, improv_id)) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if (info->state != WDS_UNDER_CONSTRUCTION) continue; - if (info->city_id != this->Body.ID) continue; - - // Mark this wonder district as completed with the wonder - info->city = this; - info->city_id = this->Body.ID; - info->state = WDS_COMPLETED; - info->wonder_index = matched_windex; - break; - } - } - } - } - - int gw_auto_build_improv_id = is->current_config.great_wall_auto_build_wonder_improv_id; - if (add && is->current_config.enable_districts && - is->current_config.auto_build_great_wall_around_territory && - (gw_auto_build_improv_id >= 0) && (improv_id == gw_auto_build_improv_id)) - auto_build_great_wall_districts_for_civ (this->Body.CivID); - - //Calculate if work_area has shrunk, and if so, redistribute citizens. - int post_work_area_radius = get_work_ring_limit_total(this); - if (post_work_area_radius < init_work_area_radius) { - patch_City_manage_by_governor(this, __, false); - } - - // Update things in case we've added or removed a mill. This is only necessary while in-game. If the game is still loading the scenario, it - // will recompute resources after it's done and we'll recompute yields and happiness ourselves. - if (! is->is_placing_scenario_things) { - // Collect info about this mill, if in fact the added or removed improvement is a mill. If it's not, all these vars will be left - // false. "generates_input" tracks whether or not the mill generates a resource that's an input for another mill. - bool is_non_local_mill, is_yielding_mill, generates_input; { - is_non_local_mill = is_yielding_mill = generates_input = false; - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if (mill->improv_id == improv_id) { - is_non_local_mill |= (mill->flags & MF_LOCAL) == 0; - is_yielding_mill |= (mill->flags & MF_YIELDS) != 0; - generates_input |= (is->mill_input_resource_bits[mill->resource_id >> 3] & (1 << (mill->resource_id & 7))) != 0; - } - } - } - - // If the mill generates a resource that's added to the trade network or it's generating an input (potentially used locally to - // generate a traded resource) then rebuild the resource network. This is not necessary if the improvement also affects trade routes - // since the base method will have already done this recomputation. - if ((is_non_local_mill || generates_input) && - ((improv->ImprovementFlags & ITF_Allows_Water_Trade) == 0) && - ((improv->ImprovementFlags & ITF_Allows_Air_Trade) == 0) && - ((improv->WonderFlags & ITW_Safe_Sea_Travel) == 0)) - patch_Trade_Net_recompute_resources (is->trade_net, __, 0); - - // If the mill adds yields or might be a link in a resource production chain that does, recompute yields in the city. - if (is_yielding_mill || generates_input) - patch_City_recompute_yields_and_happiness (this); - } - - // Adding or removing an obsolete improvement should not change the total maintenance since obsolete improvs shouldn't cost maintenance. In - // the base game, they usually do since the game doesn't update maintenance costs when buildings are obsoleted, but with that bug patched we - // can enforce the correct behavior. - if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && - (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) - this->Body.Improvements_Maintenance = init_maintenance; - - // If AI MCS is enabled and we've added the Palace to a city, then remove any extra palaces from that city. If we're in the process of - // capturing a city, it's necessary to exclude that city as a possible destination for removed extra palaces. - if ((is->current_config.ai_multi_city_start > 1) && - (! is->is_placing_scenario_things) && - add && (improv->ImprovementFlags & ITF_Center_of_Empire) && - ((*p_human_player_bits & (1 << this->Body.CivID)) == 0)) - remove_extra_palaces (this, is->currently_capturing_city); - - // If sharing wonders in hotseat mode, we must recompute improvement maintenance for all human players when any one of them gains or loses a - // wonder that grants free improvements. - if ((! is->is_placing_scenario_things) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->Body.CivID) & *p_human_player_bits)) { // is this city owned by a human player - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->Body.CivID)) - Leader_recompute_buildings_maintenance (&leaders[n_player]); - player_bits >>= 1; - n_player++; - } - } - - // Optionally share district-dependent buildings or wonders to other cities in range of the same district - bool allow_wonder_sharing = is->current_config.cities_with_mutual_district_receive_wonders; - bool allow_building_sharing = is->current_config.cities_with_mutual_district_receive_buildings; - - if ((! is->is_placing_scenario_things) && add && - is->current_config.enable_districts && (allow_building_sharing || allow_wonder_sharing) && - (! is->sharing_buildings_by_districts_in_progress)) { - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); - if (prereq_list != NULL) { - bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - if ((! is_wonder && allow_building_sharing) || (is_wonder && allow_wonder_sharing)) { - is->sharing_buildings_by_districts_in_progress = true; - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - copy_building_with_cities_in_radius (this, improv_id, district_id, x, y); - } - is->sharing_buildings_by_districts_in_progress = false; - } - } - } -} - -void __fastcall -patch_Fighter_begin (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender) -{ - Fighter_begin (this, __, attacker, attack_direction, defender); - - // Apply override of retreat eligibility - // Must use this->defender instead of the defender argument since the argument is often NULL, in which case Fighter_begin finds a defender on - // the target tile and stores it in this->defender. Also must check that against NULL since Fighter_begin might fail to find a defender. - enum UnitTypeClasses class = p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID].Unit_Class; - if ((this->defender != NULL) && ((class == UTC_Land) || (class == UTC_Sea))) { - enum retreat_rules retreat_rules = (class == UTC_Land) ? is->current_config.land_retreat_rules : is->current_config.sea_retreat_rules; - if (retreat_rules != RR_STANDARD) { - int attacker_max_mp = patch_Unit_get_max_move_points (this->attacker), - defender_max_mp = patch_Unit_get_max_move_points (this->defender); - - if (retreat_rules == RR_NONE) - this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 0; - else if (retreat_rules == RR_ALL_UNITS) - this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 1; - else if (retreat_rules == RR_IF_FASTER) { - this->attacker_eligible_to_retreat = attacker_max_mp > defender_max_mp; - this->defender_eligible_to_retreat = defender_max_mp > attacker_max_mp; - } else if (retreat_rules == RR_IF_NOT_SLOWER) { - this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp; - this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp; - } else if (retreat_rules == RR_IF_FAST_AND_NOT_SLOWER) { - this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp && attacker_max_mp > p_bic_data->General.RoadsMovementRate; - this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp && defender_max_mp > p_bic_data->General.RoadsMovementRate; - } - - // Prevent immobile units from retreating - this->attacker_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID], __, UTA_Immobile); - this->defender_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->defender->Body.UnitTypeID], __, UTA_Immobile); - - // Prevent defender from retreating if in a city - this->defender_eligible_to_retreat &= city_at (this->defender_location_x, this->defender_location_y) == NULL; - } - } -} - -void __fastcall -patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) -{ - // Determine whether this despawn happened involuntarily, i.e. whether it's because of the actions of a player other than its owner. This - // includes cases where the unit was destroyed in combat, captured, kicked from territory with nowhere to go, etc. - int ret_addr = ((int *)&civ_id_responsible)[-1]; - bool involuntary = - ret_addr == DESPAWN_TO_FIGHT_1_RETURN || ret_addr == DESPAWN_TO_FIGHT_2_RETURN - || ret_addr == DESPAWN_TO_DO_BOMBARD_TILE_RETURN || ret_addr == DESPAWN_TO_CRUISE_MISSILE_DEFENDER_RETURN - || ret_addr == DESPAWN_TO_BOUNCE_TRESPASSING_UNITS_RETURN || ret_addr == DESPAWN_TO_NUKE_DAMAGE_RETURN - || ret_addr == DESPAWN_RECURSIVE_RETURN || ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN - || ret_addr == DESPAWN_TO_TRY_FLYING_OVER_TILE_RETURN; - - int owner_id = this->Body.CivID; - int type_id = this->Body.UnitTypeID; - UnitType * type = &p_bic_data->UnitTypes[type_id]; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - // Clear extra DBs, airdrops, wait records, and transport ties used by this unit - itable_remove (&is->extra_defensive_bombards, this->Body.ID); - itable_remove (&is->airdrops_this_turn, this->Body.ID); - itable_remove (&is->waiting_units, this->Body.ID); - itable_remove (&is->unit_transport_ties, this->Body.ID); - - // If we're despawning the stored ZoC defender, clear that variable so we don't despawn it again in check_life_after_zoc - if (this == is->zoc_defender) - is->zoc_defender = NULL; - - if (this == is->sb_next_up) - is->sb_next_up = NULL; - - if (this == is->last_selected_unit.ptr) - is->last_selected_unit.ptr = NULL; - - // Remove this unit from the list of extra units to despawn after capturing - int original_count = is->count_extra_capture_despawns; - for (int n_src = 0, n_dest = 0; n_src < original_count; n_src++) { - if (is->extra_capture_despawns[n_src] != this) { - is->extra_capture_despawns[n_dest] = is->extra_capture_despawns[n_src]; - n_dest++; - } else - is->count_extra_capture_despawns -= 1; - } - - // If the unit being despawned is a land transport or helicopter, we may have to make sure to despawn its passengers as well because the base - // game won't. In general, the passengers are lost if the transport was despawned involuntarily, i.e. because of another player's attack or - // something like that, or if the passengers couldn't survive outside the transport, specifically because it's a helicopter at sea. - bool must_despawn_passengers = false; { - if (is_land_transport (this)) - must_despawn_passengers = involuntary && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); - - else if (type->Unit_Class == UTC_Air && type->Transport_Capacity > 0) { // if "this" is a helicopter - Unit * container = get_unit_ptr (this->Body.Container_Unit); - bool on_carrier = container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea && - Unit_has_ability (container, __, UTA_Transports_Only_Aircraft); - bool passengers_could_survive = Tile_has_city (tile) || ! tile->vtable->m35_Check_Is_Water (tile); - - // If no-defense-from-inside is off, passengers in helicopters will fight to defend their tile, so they wouldn't be left - // inside the helicopter when their tile is taken. If it's on, an occupied heli can be destroyed or captured by a land unit, - // and we must make sure to despawn the passengers in that case because they can't remain on the tile. Hence, - // no-defense-from-inside implies no-escape in almost all circumstances (nukes are the exception). - enum special_helicopter_rules special_rules = is->current_config.special_helicopter_rules; - if (((special_rules & SHR_ALLOW_ON_CARRIERS) && on_carrier) || (special_rules & (SHR_NO_DEFENSE_FROM_INSIDE | SHR_NO_ESCAPE))) - must_despawn_passengers = involuntary || ! passengers_could_survive; - } - } - - bool prev_always_despawn_passengers = is->always_despawn_passengers; - - if (must_despawn_passengers) { - // If we've been called from do_capture_units, record the passengers in the list of units to be despawned after do_capture_units - // returns. We can't simply despawn the units now even by setting always_despawn_passengers because the despawning messes up an - // iterator over tile units inside do_capture_units. - if (ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN) { - FOR_UNITS_ON (uti, tile) - if (uti.unit->Body.Container_Unit == this->Body.ID) { - reserve (sizeof is->extra_capture_despawns[0], // item size - (void **)&is->extra_capture_despawns, // ptr to items - &is->extra_capture_despawns_capacity, // ptr to capacity - is->count_extra_capture_despawns); // count - is->extra_capture_despawns[is->count_extra_capture_despawns] = uti.unit; - is->count_extra_capture_despawns += 1; - } - - } else - is->always_despawn_passengers = true; - } - - Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); - - is->always_despawn_passengers = prev_always_despawn_passengers; - - change_unit_type_count (&leaders[owner_id], type_id, -1); -} - -bool __fastcall -patch_Unit_do_capture_units (Unit * this, int edx, int tile_x, int tile_y, int owner_civ_id) -{ - is->count_extra_capture_despawns = 0; - - bool tr = Unit_do_capture_units (this, __, tile_x, tile_y, owner_civ_id); - - // Here we rely on patch_Unit_despawn to remove despawned units from the list - while (is->count_extra_capture_despawns > 0) - patch_Unit_despawn (is->extra_capture_despawns[0], __, this->Body.ID, 0, 0, 0, 0, 0, 0); - - return tr; -} - -void __fastcall -patch_Map_Renderer_m71_Draw_Tiles (Map_Renderer * this, int edx, int param_1, int param_2, int param_3) -{ - // Restore the tile count if it was saved by recompute_resources. This is necessary because the Draw_Tiles method loops over all tiles. - if (is->saved_tile_count >= 0) { - p_bic_data->Map.TileCount = is->saved_tile_count; - is->saved_tile_count = -1; - } - - Map_Renderer_m71_Draw_Tiles (this, __, param_1, param_2, param_3); -} - -struct named_tile_entry * -get_named_tile_entry (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - int stored_ptr = 0; - if (! itable_look_up (&is->named_tile_map, (int)tile, &stored_ptr)) - return NULL; - return (struct named_tile_entry *)stored_ptr; -} - -bool -prompt_for_named_tile (char const * seed_name, char * out_name, int out_len) -{ - if ((out_name == NULL) || (out_len <= 0)) - return false; - out_name[0] = '\0'; - - PopupForm * popup = get_popup_form (); - if (popup == NULL) - return false; - - char seed_buf[101]; - if (seed_name == NULL) - seed_name = ""; - strncpy (seed_buf, seed_name, sizeof seed_buf); - seed_buf[(sizeof seed_buf) - 1] = '\0'; - if (seed_buf[0] == '\0') - strncpy (seed_buf, "Tile", sizeof seed_buf); - - set_popup_str_param (0, seed_buf, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "RENAME_CITY", 0x64, (int)seed_buf, 0x44, 0); - int sel = patch_show_popup (popup, __, 0, 0); - is->focused_tile = NULL; - if (sel != 0) - return false; - - if (temp_ui_strs[0][0] == '\0') - return true; - - strncpy (out_name, temp_ui_strs[0], out_len); - out_name[out_len - 1] = '\0'; - return true; -} - -void -handle_named_tile_menu_selection (void) -{ - int tile_x = is->named_tile_menu_tile_x; - int tile_y = is->named_tile_menu_tile_y; - Tile * tile = tile_at (tile_x, tile_y); - if (! tile_can_be_named (tile, tile_x, tile_y)) - return; - - init_tile_highlights (); - - struct named_tile_entry * entry = get_named_tile_entry (tile); - char const * current_name = (entry != NULL) ? entry->name : ""; - char new_name[100]; - is->focused_tile = tile; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - bool got_name = prompt_for_named_tile (current_name, new_name, sizeof new_name); - is->focused_tile = NULL; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - if (! got_name) - return; - - set_named_tile_entry (tile, tile_x, tile_y, new_name); - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -void __fastcall -patch_Main_Screen_Form_handle_right_click_on_tile (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) -{ - if (is->current_config.enable_named_tiles) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile_can_be_named (tile, tile_x, tile_y) && ! Tile_has_city (tile)) { - is->named_tile_menu_active = true; - is->named_tile_menu_tile_x = tile_x; - is->named_tile_menu_tile_y = tile_y; - Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); - is->named_tile_menu_active = false; - return; - } - } - - Main_Screen_Form_handle_right_click_on_tile (this, __, tile_x, tile_y, mouse_x, mouse_y); -} - -void __fastcall -patch_Main_Screen_Form_open_right_click_menu (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) -{ - bool set_active = false; - if (!is->named_tile_menu_active && is->current_config.enable_named_tiles) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile_can_be_named (tile, tile_x, tile_y)) { - is->named_tile_menu_active = true; - is->named_tile_menu_tile_x = tile_x; - is->named_tile_menu_tile_y = tile_y; - set_active = true; - } - } - Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); - if (set_active) - is->named_tile_menu_active = false; -} - -void -draw_map_tile_text (Main_Screen_Form * this, PCX_Image * canvas, char * text, int screen_x, int screen_y, int base_screen_height, int y_offset) -{ - int is_zoomed_out = (p_bic_data->is_zoomed_out != false); - int scale = is_zoomed_out ? 2 : 1; - int screen_width = 128 / scale; - int screen_height = base_screen_height / scale; - int text_width = screen_width - (is_zoomed_out ? 4 : 8); - if (text_width < 12) - text_width = screen_width; - - int text_left = screen_x + (screen_width - text_width) / 2; - int draw_y = screen_y - y_offset; - int text_top = draw_y + screen_height + (is_zoomed_out ? 2 : 4); - - Object_66C3FC * font = get_font (10, FSF_NONE); - if (font != NULL) { - PCX_Image_set_text_effects (canvas, __, 0x80FFFFFF, 0x80000000, 1, 1); - PCX_Image_draw_centered_text (canvas, __, font, text, text_left, text_top - 10, text_width, strlen (text)); - } -} - -void __fastcall -patch_Main_Screen_Form_draw_city_hud (Main_Screen_Form * this, int edx, PCX_Image * canvas) -{ - Main_Screen_Form_draw_city_hud (this, __, canvas); - - bool draw_natural_wonders = is->current_config.enable_natural_wonders && - is->current_config.show_natural_wonder_name_on_map; - bool draw_named_tiles = is->current_config.enable_named_tiles; - if (!draw_natural_wonders && !draw_named_tiles) - return; - - if (canvas == NULL) - canvas = &this->Base_Data.Canvas; - - if ((canvas == NULL) || (canvas->JGL.Image == NULL)) - return; - - if (draw_natural_wonders) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - - int natural_id = inst->natural_wonder_info.natural_wonder_id; - if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) - continue; - - struct natural_wonder_district_config const * nw_cfg = &is->natural_wonder_configs[natural_id]; - if ((nw_cfg == NULL) || (nw_cfg->name == NULL) || (nw_cfg->name[0] == '\0')) - continue; - - Tile * tile = (Tile *)tei.key; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int tile_x, tile_y; - if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - continue; - - int screen_x, screen_y; - Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); - - draw_map_tile_text (this, canvas, (char *)nw_cfg->name, screen_x, screen_y, 88, 88 - 64); - } - } - - if (draw_named_tiles) { - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if ((entry == NULL) || (entry->name[0] == '\0')) - continue; - - Tile * tile = (Tile *)tei.key; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int tile_x, tile_y; - if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) { - tile_x = entry->tile_x; - tile_y = entry->tile_y; - tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - } - - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) - continue; - - int screen_x, screen_y; - Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); - - draw_map_tile_text (this, canvas, entry->name, screen_x, screen_y, 64, 3); - } - } -} - -// Returns whether or not city has an "extra palace", a concept used by the AI multi-city start. Extra palaces are small wonders that reduce -// corruption (e.g. forbidden palace) that are listed under the ai_multi_start_extra_palaces config option. -bool -has_extra_palace (City * city) -{ - for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { - int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) && - (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && - (leaders[city->Body.CivID].Small_Wonders[improv_id] == city->Body.ID)) { - return true; - } - } - return false; -} - -// Removes any extra palaces from this city to other cities owned by the same player (if possible). Does not check that the city belongs to an AI or -// that AI MCS is enabled. -void -remove_extra_palaces (City * city, City * excluded_destination) -{ - Leader * leader = &leaders[city->Body.CivID]; - int extra_palace_lost; - do { - // Search for an extra palace in the city and delete it. Remember its ID so we can put it elsewhere. - extra_palace_lost = -1; - for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { - int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) && - (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && - (leader->Small_Wonders[improv_id] == city->Body.ID)) { - patch_City_add_or_remove_improvement (city, __, improv_id, 0, false); - extra_palace_lost = improv_id; - break; - } - } - - // Replace the lost extra palace like what happens to the real palace - if (extra_palace_lost >= 0) { - int best_rating = -1; - City * best_location = NULL; - FOR_CITIES_OF (coi, leader->ID) { - City * candidate = coi.city; - if ((candidate != city) && - (candidate->Body.ID != leader->CapitalID) && - (candidate != excluded_destination) && - ! has_extra_palace (candidate)) { - - // Rate this candidate as a possible (extra) palace location. The criteria we use to rate it are identical to - // what the base game uses to find a new location for the palace. - int rating = 0; - rating += candidate->Body.Population.Size; - rating += count_units_at (candidate->Body.X, candidate->Body.Y, UF_4, -1, 0, -1); - rating += 2 * City_count_citizens_of_race (candidate, __, leader->RaceID); - FOR_TILES_AROUND (tai, 0x121, candidate->Body.X, candidate->Body.Y) { - if (tai.n == 0) - continue; - City * neighbor = get_city_ptr (tai.tile->CityID); - if ((neighbor != NULL) && (neighbor != city) && (neighbor->Body.CivID == leader->ID)) { - int size = neighbor->Body.Population.Size; - if (size > p_bic_data->General.MaximumSize_City) rating += 3; - else if (size > p_bic_data->General.MaximumSize_Town) rating += 2; - else rating += 1; - } - } - - if (rating > best_rating) { - best_rating = rating; - best_location = candidate; - } - } - } - - if (best_location != NULL) - City_add_or_remove_improvement (best_location, __, extra_palace_lost, 1, false); - } - } while (extra_palace_lost >= 0); -} - -// Give a city any completed wonder districts in work radius, if cities_with_mutual_district_receive_wonders is true. -// This is essentially for cases where the original Wonder-constructing city is lost and a new city is built -// that can work the same wonder district tile. -void -grant_nearby_wonders_to_city (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_wonder_districts || - ! is->current_config.cities_with_mutual_district_receive_wonders || - (city == NULL)) - return; - - bool prev_flag = is->sharing_buildings_by_districts_in_progress; - is->sharing_buildings_by_districts_in_progress = true; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * tile = wai.tile; - - // Make sure Wonder is completed - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - struct wonder_district_info * info = &inst->wonder_info; - if ((info == NULL) || (info->state != WDS_COMPLETED)) continue; - - // Check that city doesn't already have the Wonder - int improv_id = get_wonder_improvement_id_from_index (info->wonder_index); - if (improv_id < 0) continue; - - if (patch_City_has_improvement (city, __, improv_id, false)) continue; - - // Small wonders use Leader.Small_Wonders as their canonical owner record. If the city - // just changed hands and the new owner already has that small wonder elsewhere, do not - // re-grant it from the nearby district or the capture can recreate a duplicate. - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) != 0) { - City * owning_city = get_city_ptr (leaders[city->Body.CivID].Small_Wonders[improv_id]); - if ((owning_city != NULL) && - (owning_city->Body.CivID == city->Body.CivID) && - ! city_radius_contains_tile (owning_city, x, y)) - continue; - } - - // Add the Wonder to the city - patch_City_add_or_remove_improvement (city, __, improv_id, 1, false); - } - - is->sharing_buildings_by_districts_in_progress = prev_flag; -} - -void -on_gain_city (Leader * leader, City * city, enum city_gain_reason reason) -{ - if (reason == CGR_FOUNDED) - is->turn_no_of_last_founding_for_settler_perfume[leader->ID] = *p_current_turn_no; - - // Handle extra palaces for AI multi-city start - if (((*p_human_player_bits & (1<ID)) == 0) && // If leader is an AI AND - (is->current_config.ai_multi_city_start > 1) && // AI multi-city start is enabled AND - (leader->Cities_Count > 1) && // city is not the only one the AI has (i.e. it's not the capital) AND - (reason != CGR_PLACED_FOR_SCENARIO) && (reason != CGR_PLACED_FOR_AI_MULTI_CITY_START)) { // city was not placed before the game started - - // Find an extra palace that this player does not already have - int free_extra_palace = -1; - for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { - int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) && - (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && - (NULL == get_city_ptr (leader->Small_Wonders[improv_id]))) { - free_extra_palace = improv_id; - break; - } - } - - // Place that extra palace here - if (free_extra_palace >= 0) - City_add_or_remove_improvement (city, __, free_extra_palace, 1, false); - } - - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - patch_City_recompute_yields_and_happiness (city); - patch_City_recompute_culture_income (city); - } - - if (is->current_config.enable_districts) { - - // Remove any district previously on the tile, if city just founded - if (reason == CGR_FOUNDED) { - Tile * city_tile = tile_at (city->Body.X, city->Body.Y); - if ((city_tile != NULL) && (city_tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (city_tile); - if (inst != NULL) - handle_district_removed (city_tile, inst->district_id, city->Body.X, city->Body.Y, false); - } - } - - bool receive_buildings = is->current_config.cities_with_mutual_district_receive_buildings; - bool receive_wonders = is->current_config.cities_with_mutual_district_receive_wonders; - - // Grant buildings and wonders from nearby completed districts owned by other cities of same civ, if enabled - if (receive_buildings) { - grant_existing_district_buildings_to_city (city); - } - - // Grant wonders nearby in same territory, regardless of city (i.e., orphaned wonders from destroyed cities), if enabled - if (receive_wonders) { - grant_nearby_wonders_to_city (city); - } - - if (is->current_config.enable_distribution_hub_districts) { - refresh_distribution_hubs_for_city (city); - } - } -} - -void -on_lose_city (Leader * leader, City * city, enum city_loss_reason reason) -{ - // If leader is an AI and AI MCS is enabled, remove any extra palaces the city has - if (((*p_human_player_bits & (1<ID)) == 0) && - (is->current_config.ai_multi_city_start > 1)) - remove_extra_palaces (city, NULL); - - if (is->current_config.enable_districts) { - if (is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; - - forget_pending_building_order (city); - for (int district_id = 0; district_id < is->district_count; district_id++) - clear_city_district_request (city, district_id); - - if (is->current_config.enable_wonder_districts) - release_wonder_district_reservation (city); - } else if (is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; -} - -// Returns -1 if the location is unusable, 0-9 if it's usable but doesn't satisfy all criteria, and 10 if it couldn't be better -int -eval_starting_location (Map * map, int const * alt_starting_locs, int alt_starting_loc_count, int tile_x, int tile_y, int civ_id) -{ - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != p_null_tile) && - (patch_Map_check_city_location (map, __, tile_x, tile_y, civ_id, true) == CLV_OK) && - (tile->vtable->m15_Check_Goody_Hut (tile, __, 0) == 0) && - (tile->vtable->m40_get_TileUnit_ID (tile) == -1)) { - int tr = 0; - - // Avoid this location if it's too close to another starting location. If it's much too close, it's ruled out entirely. - int closest_dist = INT_MAX; - for (int n = 1; n <= map->Civ_Count; n++) - if (map->Starting_Locations[n] >= 0) { - int other_x, other_y; - tile_index_to_coords (map, map->Starting_Locations[n], &other_x, &other_y); - int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); - if (dist < closest_dist) - closest_dist = dist; - } - for (int n = 0; n < alt_starting_loc_count; n++) - if (alt_starting_locs[n] >= 0) { - int other_x, other_y; - tile_index_to_coords (map, alt_starting_locs[n], &other_x, &other_y); - int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); - if (dist < closest_dist) - closest_dist = dist; - } - if (closest_dist < map->Civ_Distance/3) - return -1; - else if (closest_dist >= 2*map->Civ_Distance/3) - tr += 1; - - // Avoid tiny islands - // tr += map->vtable->m33_Get_Continent (map, __, tile->ContinentID)->Body.TileCount >= 20; - - // Avoid garbage terrain, e.g. all desert or tundra - int break_even_food_tiles = 0; - FOR_TILES_AROUND (tai, 21, tile_x, tile_y) { - if (tai.n == 0) - continue; // Skip tile that would be covered by the city - int tile_food = patch_Map_calc_food_yield_at (map, __, tai.tile_x, tai.tile_y, tai.tile->vtable->m50_Get_Square_BaseType (tai.tile), civ_id, 0, NULL); - int food_required = p_bic_data->General.FoodPerCitizen + (tai.tile->vtable->m35_Check_Is_Water (tai.tile) ? 1 : 0); - break_even_food_tiles += tile_food >= food_required; - } - tr += break_even_food_tiles >= 2; - - // Avoid wasting a food bonus - tr += (tile->ResourceType < 0) || (tile->ResourceType >= p_bic_data->ResourceTypeCount) || - (p_bic_data->ResourceTypes[tile->ResourceType].Food == 0); - - int max_score = 3; - return (10*tr)/max_score; - } else - return -1; -} - -City * -create_starter_city (Map * map, int civ_id, int tile_index) -{ - int x, y; - tile_index_to_coords (map, tile_index, &x, &y); - City * tr = Leader_create_city (&leaders[civ_id], __, x, y, leaders[civ_id].RaceID, -1, NULL, true); - if (tr != NULL) - on_gain_city (&leaders[civ_id], tr, CGR_PLACED_FOR_AI_MULTI_CITY_START); - return tr; -} - -void -set_up_ai_multi_city_start (Map * map, int city_count) -{ - // Set of bits determining which players are eligible for the two-city start - int eligibility_bits = 0, - count_eligible_civs = 0; - for (int n = 1; n < 32; n++) - if ((*p_player_bits & 1<Starting_Locations[n]) != p_null_tile)) { // has a valid starting location - eligibility_bits |= 1 << n; - count_eligible_civs++; - } - - if ((city_count < 1) || (count_eligible_civs == 0)) // if we have nothing to do - return; - - char load_text[50]; - snprintf (load_text, sizeof load_text, "%s...", is->c3x_labels[CL_CREATING_CITIES]); - load_text[(sizeof load_text) - 1] = '\0'; - Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); - - // Generate alternate sets of starting locations. We need one set for each extra city we're going to create per player. Each set only needs to - // include starting locations for eligible players, all others will be left as -1. - int alt_starting_loc_count = 32 * (city_count - 1); - int * alt_starting_locs = malloc (alt_starting_loc_count * sizeof *alt_starting_locs); { - for (int n = 0; n < alt_starting_loc_count; n++) - alt_starting_locs[n] = -1; - - for (int i_loc = 0; i_loc < alt_starting_loc_count; i_loc++) { - int civ_id = i_loc % 32; - if ((civ_id != 0) && (eligibility_bits & 1<current_config.max_tries_to_place_fp_city; try++) { - int i_loc = rand_int (p_rand_object, __, map->TileCount); - int x_loc, y_loc; - tile_index_to_coords (map, i_loc, &x_loc, &y_loc); - if ((x_loc >= 0) && (y_loc >= 0)) { - int val = eval_starting_location (map, alt_starting_locs, alt_starting_loc_count, x_loc, y_loc, civ_id); - if (val >= 10) { - best_loc_index = i_loc; - break; - } else if (val > best_loc_val) { - best_loc_val = val; - best_loc_index = i_loc; - } - } - } - - if (best_loc_index >= 0) - alt_starting_locs[i_loc] = best_loc_index; - } - } - } - - int count_cities_created = 0; - int count_eligible_civs_handled = 0; - for (int civ_id = 1; civ_id < 32; civ_id++) - if (eligibility_bits & 1<Starting_Locations[civ_id]; - - // Create the first starting city for the AI. This one is its capital and is located at its actual starting - // location. Afterward, delete its starting settler so it's as if the settler founded the city. - { - Unit * starting_settler = NULL; - FOR_UNITS_ON (tai, tile_at_index (map, sloc)) { - if (p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].AI_Strategy & UTAI_Settle) { - starting_settler = tai.unit; - break; - } - } - - create_starter_city (map, civ_id, sloc); - count_cities_created++; - - if (starting_settler != NULL) - patch_Unit_despawn (starting_settler, __, 0, 1, 0, 0, 0, 0, 0); - - } - - // Memoize all of the AI's starting units - clear_memo (); - FOR_UNITS_ON (tai, tile_at_index (map, sloc)) - memoize ((int)tai.unit); - - int extra_city_count = 0; - for (int i_city = 1; i_city < city_count; i_city++) { - int loc = alt_starting_locs[(i_city-1)*32 + civ_id]; - City * city; - if ((loc >= 0) && - (NULL != (city = create_starter_city (map, civ_id, loc)))) { - count_cities_created++; - extra_city_count++; - - // Spawn palace substitute in new city - if (extra_city_count-1 < is->current_config.count_ai_multi_start_extra_palaces) - patch_City_add_or_remove_improvement (city, __, is->current_config.ai_multi_start_extra_palaces[extra_city_count - 1], 1, true); - - // Move starting units over to the new city. Do this by moving every Nth unit where N is the number of extra - // cities we've founded so far plus one. ("Extra" cities are the ones created after the capital.) E.g., if - // this is the 1st city after the capital, move every 2nd unit to it. If it's the 2nd, move every 3rd, etc. - for (int n = 0; n < is->memo_len; n++) - if (n % (extra_city_count+1) == extra_city_count) - patch_Unit_move ((Unit *)is->memo[n], __, city->Body.X, city->Body.Y); - - } - } - - // Update progress report - count_eligible_civs_handled++; - int progress = 100 * count_eligible_civs_handled / count_eligible_civs; - snprintf (load_text, sizeof load_text, "%s %d%%", is->c3x_labels[CL_CREATING_CITIES], progress); - load_text[(sizeof load_text) - 1] = '\0'; - Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); - - } - - free (alt_starting_locs); - - // Sanity check - int any_adjacent_cities = 0; { - if (p_cities->Cities != NULL) - for (int city_index = 0; (city_index <= p_cities->LastIndex) && ! any_adjacent_cities; city_index++) { - City * city = get_city_ptr (city_index); - if (city != NULL) - FOR_TILES_AROUND (tai, 9, city->Body.X, city->Body.Y) - if ((tai.n > 0) && (NULL != get_city_ptr (tai.tile->vtable->m45_Get_City_ID (tai.tile)))) { - any_adjacent_cities = 1; - break; - } - } - } - int any_missing_fp_cities = (count_cities_created < city_count * count_eligible_civs); - if (any_adjacent_cities || any_missing_fp_cities) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[100]; - snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_FAILED_SANITY_CHECK]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - if (any_adjacent_cities) { - snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_ADJACENT_CITIES]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - if (any_missing_fp_cities) { - snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_MISSING_CITIES]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - patch_show_popup (popup, __, 0, 0); - } -} - -void __fastcall -patch_Map_process_after_placing (Map * this, int edx, bool param_1) -{ - if ((is->current_config.ai_multi_city_start > 0) && (*p_current_turn_no == 0)) - set_up_ai_multi_city_start (this, is->current_config.ai_multi_city_start); - - Map_process_after_placing (this, __, param_1); -} - -void __fastcall -patch_Map_impl_generate (Map * this, int edx, int seed, bool is_multiplayer_game, int num_seafaring_civs) -{ - Map_impl_generate (this, __, seed, is_multiplayer_game, num_seafaring_civs); - - if (is->current_config.enable_natural_wonders) - place_natural_wonders_on_map (); -} - -int __fastcall -patch_City_get_net_commerce (City * this, int edx, int kind, bool include_science_age) -{ - int base = City_get_net_commerce (this, __, kind, include_science_age); - - if ((kind == 1) && // beakers, as opposed to 2 which is gold - (is->current_config.ai_research_multiplier != 100) && - ((*p_human_player_bits & 1<Body.CivID) == 0)) - return (base * is->current_config.ai_research_multiplier + 50) / 100; - else - return base; -} - -// Cuts research spending while total expenditures > treasury. Returns whether spending has been cut. -bool -cut_unaffordable_research_spending (Leader * leader, bool skip_popup) -{ - // The rate cap limits AI players' spending on the gold slider (in Leader::ai_adjust_sliders) however it does not apply to human players when - // adjusting sliders manually on the domestic advisor screen. - int gold_rate_cap = ((*p_human_player_bits & 1<ID) != 0) ? 10 : p_bic_data->Governments[leader->GovernmentType].RateCap; - - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - bool reduced_spending = false; - while (leader->science_slider > 0 && - leader->gold_slider < gold_rate_cap && - treasury + Leader_compute_income (leader) < 0) { - leader->science_slider -= 1; - leader->gold_slider += 1; - Leader_recompute_economy (leader); - reduced_spending = true; - } - if (reduced_spending && ! skip_popup && leader->ID == p_main_screen_form->Player_CivID) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_CUT_RESEARCH_SPENDING", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - return reduced_spending; -} - -void __fastcall -adjust_sliders_preproduction (Leader * this) -{ - if ((*p_human_player_bits & 1<ID) == 0) { - // Replicate the behavior of the original code for AI players. (apply_machine_code_edits overwrites an equivalent branch & call in the - // original code with a call to this method.) - this->vtable->ai_adjust_sliders (this); - - // If aggressively penalize bankruptcy is on, cut the AI's research spending if it can't afford it. This may be redundant as - // ai_adjust_sliders will already cut AI spending but maybe not all the way to zero. Do this only every third turn so the AI is not - // completely prevented from researching. - if (is->current_config.aggressively_penalize_bankruptcy && (*p_current_turn_no + this->ID) % 3 == 0) - cut_unaffordable_research_spending (this, true); - - // If human player would go bankrupt, try reducing their research spending to avoid that - } else if (is->current_config.cut_research_spending_to_avoid_bankruptcy) - cut_unaffordable_research_spending (this, false); -} - -int __fastcall -patch_City_get_improvement_maintenance (City * this, int edx, int improv_id) -{ - // Check if this improvment is provided for free by another player via shared wonder effects - int civ_id = this->Body.CivID; - bool free_from_sharing = false; - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << civ_id) & *p_human_player_bits)) { // is this city owned by a human player - - // Check if any other human player in the game has this improv in their auto improvs table, including for this city's continent - bool has_free_improv = false; - Tile * city_tile = tile_at (this->Body.X, this->Body.Y); - int continent_id = city_tile->vtable->m46_Get_ContinentID (city_tile); - int cont_coded_key = (continent_id + 1) * p_bic_data->ImprovementsCount + improv_id;; - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != civ_id)) - if (Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, improv_id , NULL) || - Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, cont_coded_key, NULL)) { - free_from_sharing = true; - break; - } - player_bits >>= 1; - n_player++; - } - } - - if (! free_from_sharing) - return City_get_improvement_maintenance (this, __, improv_id); - else - return 0; -} - -int __fastcall -patch_Leader_count_maintenance_free_units (Leader * this) -{ - if ((is->current_config.extra_unit_maintenance_per_shields <= 0) && (this->ID != 0)) - return Leader_count_maintenance_free_units (this); - else { - int tr = 0; - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if ((unit != NULL) && (unit->Body.CivID == this->ID)) { - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - - // If this is a free unit - if ((unit->Body.RaceID != this->RaceID) || (type->requires_support == 0)) - tr++; - - // If this unit belongs to the barbs and has a tribe ID set (indicating it was spawned in a barb camp) then count it - // as a free unit in order not to bankrupt the barb player if the barb player controls any cities. A tribe ID of 75 is - // the generic ID that's assigned to barb units when they're spawned with no specific tribe ID. - else if ((unit->Body.CivID == 0) && (unit->Body.barb_tribe_id >= 0) && (unit->Body.barb_tribe_id < 75)) - tr++; - - // Otherwise, if we're configured to apply extra maintenance based on shield cost, reduce the free unit count by - // however many times this unit's cost is above the threshold for extra maintenace. It's alright if the resulting free - // unit count is negative since all callers of this function subtract its return value from the total unit count to - // obtain the count of units that must be paid for. - else if (is->current_config.extra_unit_maintenance_per_shields > 0) - tr -= type->Cost / is->current_config.extra_unit_maintenance_per_shields; - } - } - return tr; - } -} - -int __fastcall -patch_Leader_sum_unit_maintenance (Leader * this, int edx, int government_id) -{ - if (is->current_config.extra_unit_maintenance_per_shields <= 0) - return Leader_sum_unit_maintenance (this, __, government_id); - else if (this->Cities_Count > 0) { - int maint_free_count = patch_Leader_count_maintenance_free_units (this); - int cost_per_unit, base_free_count; - get_unit_support_info (this->ID, government_id, &cost_per_unit, &base_free_count); - int ai_free_count; { - if (*p_human_player_bits & 1<ID) - ai_free_count = 0; - else { - Difficulty_Level * difficulty = &p_bic_data->DifficultyLevels[*p_game_difficulty]; - ai_free_count = difficulty->Bonus_For_Each_City * this->Cities_Count + difficulty->Additional_Free_Support; - } - } - return not_below (0, (this->Unit_Count - base_free_count - ai_free_count - maint_free_count) * cost_per_unit); - } else - return 0; -} - -int -sum_improvements_maintenance_to_pay (Leader * leader, int govt_id) -{ - if (is->current_config.aggressively_penalize_bankruptcy) - // We're going to replace the logic that charges maintenance, and the replacement will charge both unit & building maintenance b/c - // they're intertwined under the new rules. Return zero here so the base game code doesn't charge any building maintenance on its own. - return 0; - else - return Leader_sum_improvements_maintenance (leader, __, govt_id); -} - -// The sum_improvements_maintenance function is called in two places as part of the randomization of whether improv or unit maintenance gets paid -// first. Redirect both of these calls to one function of our own. -int __fastcall patch_Leader_sum_improv_maintenance_to_pay_1 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } -int __fastcall patch_Leader_sum_improv_maintenance_to_pay_2 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } - -int -compare_buildings_to_sell (void const * a, void const * b) -{ - int maint_a = (*(int const *)a >> 26) & 31, - maint_b = (*(int const *)b >> 26) & 31; - return maint_b - maint_a; -} - -// Returns the final improv cost after buildings were sold -int -sell_unaffordable_buildings (Leader * leader, int improv_cost, int unit_cost) -{ - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - - clear_memo (); - - // Memoize all buildings this player owns that we might potentially sell. B/c the memo can only contain ints, we must pack the maintenance - // cost, improv ID, and city ID all into one int. The city ID is stored in the lowest 13 bits, then the improv ID in the next 13, and finally - // the maintenance amount in the 5 above those. - FOR_CITIES_OF (coi, leader->ID) - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * improv = &p_bic_data->Improvements[n]; - - int unsellable_flags = - ITF_Center_of_Empire | - ITF_50_Luxury_Output | - ITF_50_Tax_Output | - ITF_Reduces_Corruption | - ITF_Increases_Luxury_Trade | - ITF_Allows_City_Level_2 | - ITF_Allows_City_Level_3 | - ITF_Capitalization | - ITF_Allows_Water_Trade | - ITF_Allows_Air_Trade | - ITF_Increases_Shields_In_Water | - ITF_Increases_Food_In_Water | - ITF_Increases_Trade_In_Water; - - // Only sell improvements that aren't contributing gold, even indirectly through e.g. happiness or boosting shield production - // for Wealth - bool sellable = - ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) == 0) && - ((improv->ImprovementFlags & unsellable_flags) == 0) && - (improv->Happy_Faces_All <= 0) && (improv->Happy_Faces <= 0) && - (improv->Production <= 0); - - if (sellable && patch_City_has_improvement (coi.city, __, n, 0)) { - int maint = patch_City_get_improvement_maintenance (coi.city, __, n); - if (maint > 0) - memoize ((not_above (31, maint) << 26) | (n << 13) | coi.city_id); - } - } - - // Sort the list of buildings so the highest maintenance ones come first - qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_buildings_to_sell); - - // Sell buildings until we can cover maintenance costs or until we run out of ones to sell - int count_sold = 0; - while ((improv_cost + unit_cost > treasury) && (count_sold < is->memo_len)) { - int improv_id = ((1<<13) - 1) & (is->memo[count_sold] >> 13), - city_id = ((1<<13) - 1) & is->memo[count_sold]; - City * city = get_city_ptr (city_id); - improv_cost -= patch_City_get_improvement_maintenance (city, __, improv_id); - City_sell_improvement (city, __, improv_id, false); - treasury = leader->Gold_Encoded + leader->Gold_Decrement; - count_sold++; - } - - // Show popup informing the player that their buildings were force sold - if ((leader->ID == p_main_screen_form->Player_CivID) && ! is_online_game ()) { - PopupForm * popup = get_popup_form (); - if (count_sold == 1) { - int improv_id = ((1<<13) - 1) & (is->memo[0] >> 13), - city_id = ((1<<13) - 1) & is->memo[0]; - set_popup_str_param (0, get_city_ptr (city_id)->Body.CityName , -1, -1); - set_popup_str_param (1, p_bic_data->Improvements[improv_id].Name.S, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_SINGLE_IMPROV", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } else if (count_sold > 1) { - set_popup_int_param (0, count_sold); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_MULTIPLE_IMPROVS", -1, 0, 0, 0); - - // Add list of sold improvements to popup - for (int n = 0; n < count_sold; n++) { - int improv_id = ((1<<13) - 1) & (is->memo[n] >> 13), - city_id = ((1<<13) - 1) & is->memo[n]; - char s[200]; - snprintf (s, sizeof s, "^ %s in %s", - p_bic_data->Improvements[improv_id].Name.S, - get_city_ptr (city_id)->Body.CityName); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - - patch_show_popup (popup, __, 0, 0); - } - } - - return improv_cost; -} - -// Returns the final unit cost after disbanding -int -disband_unaffordable_units (Leader * leader, int improv_cost, int unit_cost, int cost_per_unit) -{ - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - int count_disbanded = 0; - Unit * to_disband; - char first_disbanded_name[32]; - while ((improv_cost + unit_cost > treasury) && - (unit_cost > 0) && - (NULL != (to_disband = leader->vtable->find_unsupported_unit (leader)))) { - if (count_disbanded == 0) { - char const * name_src = (to_disband->Body.Custom_Name.S[0] == '\0') - ? p_bic_data->UnitTypes[to_disband->Body.UnitTypeID].Name - : to_disband->Body.Custom_Name.S; - strncpy (first_disbanded_name, name_src, sizeof first_disbanded_name); - first_disbanded_name[(sizeof first_disbanded_name) - 1] = '\0'; - } - Unit_disband (to_disband); - count_disbanded++; - unit_cost -= cost_per_unit; - } - - // Show popup informing the player that their units were disbanded - if (leader->ID == p_main_screen_form->Player_CivID) { - PopupForm * popup = get_popup_form (); - if (count_disbanded == 1) { - set_popup_str_param (0, first_disbanded_name, -1, -1); - int online_flag = is_online_game () ? 0x4000 : 0; - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_SINGLE_UNIT", -1, 0, online_flag, 0); - patch_show_popup (popup, __, 0, 0); - } else if ((count_disbanded > 1) && ! is_online_game ()) { - set_popup_int_param (0, count_disbanded); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_MULTIPLE_UNITS", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - } - - return unit_cost; -} - -int -compare_cities_by_production (void const * vp_id_a, void const * vp_id_b) -{ - City * a = get_city_ptr (*(int const *)vp_id_a), - * b = get_city_ptr (*(int const *)vp_id_b); - return a->Body.ProductionIncome - b->Body.ProductionIncome; -} - -void -charge_maintenance_with_aggressive_penalties (Leader * leader) -{ - int cost_per_unit; - get_unit_support_info (leader->ID, leader->GovernmentType, &cost_per_unit, NULL); - - int improv_cost = Leader_sum_improvements_maintenance (leader, __, leader->GovernmentType); - - int unit_cost = 0; { - if (leader->Cities_Count > 0) // Players with no cities don't pay unit maintenance, per the original game rules - if (cost_per_unit > 0) { - int count_free_units = Leader_get_free_unit_count (leader, __, leader->GovernmentType) + patch_Leader_count_maintenance_free_units (leader); - unit_cost += not_below (0, (leader->Unit_Count - count_free_units) * cost_per_unit); - } - } - - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - if (improv_cost + unit_cost > treasury) { - - // For AIs, alternate between selling buildings and disbanding units when maintenance can't be paid - if (((1<ID & *p_human_player_bits) != 0) || ((leader->ID + *p_current_turn_no) % 2 == 0)) { - improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); - unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); - } else { - unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); - improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); - } - - treasury = leader->Gold_Encoded + leader->Gold_Decrement; // Update b/c selling buildings recovers some gold - - // If the player still can't afford maintenance, even after all that, start switching their cities to Wealth - int wealth_income = 0; - if (improv_cost + unit_cost > treasury + wealth_income) { - // Memoize all cities not already building wealth and sort by production (lowest first) - clear_memo (); - FOR_CITIES_OF (coi, leader->ID) - if ((coi.city->Body.Status & CSF_Capitalization) == 0) - memoize (coi.city_id); - qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_cities_by_production); - - int wealth_improv_id = -1; { - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { - wealth_improv_id = n; - break; - } - } - - if (wealth_improv_id >= 0) { - int n = 0, - switched_any = 0; - - while ((n < is->memo_len) && (improv_cost + unit_cost > treasury + wealth_income)) { - City * city = get_city_ptr (is->memo[n]); - City_set_production (city, __, COT_Improvement, wealth_improv_id, false); - switched_any = 1; - wealth_income += City_get_income_from_wealth_build (city); - n++; - } - - if (switched_any && (leader->ID == p_main_screen_form->Player_CivID)) { - PopupForm * popup = get_popup_form (); - Improvement * wealth = &p_bic_data->Improvements[wealth_improv_id]; - set_popup_str_param (0, wealth->Name.S, -1, -1); - set_popup_str_param (1, wealth->CivilopediaEntry.S, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_BUILD_WEALTH", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - } - } - } - - Leader_set_treasury (leader, __, treasury - improv_cost - unit_cost); -} - -bool __fastcall -patch_Unit_has_king_ability_for_find_unsupported (Unit * this, int edx, enum UnitTypeAbilities king_ability) -{ - // If we're set to aggressively penalize bankruptcy and this unit doesn't require support, return that it is a king so it doesn't get - // disbanded. - if (is->current_config.aggressively_penalize_bankruptcy && ! p_bic_data->UnitTypes[this->Body.UnitTypeID].requires_support) - return true; - - else - return Unit_has_ability (this, __, king_ability); -} - -void __fastcall -patch_Leader_pay_unit_maintenance (Leader * this) -{ - if (! is->current_config.aggressively_penalize_bankruptcy) - Leader_pay_unit_maintenance (this); - else - charge_maintenance_with_aggressive_penalties (this); -} - -void __fastcall -patch_Main_Screen_Form_show_wltk_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) -{ - patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); -} - -void __fastcall -patch_Main_Screen_Form_show_wltk_ended_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) -{ - patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); -} - -char __fastcall -patch_Tile_has_city_for_agri_penalty_exception (Tile * this) -{ - return is->current_config.no_penalty_exception_for_agri_fresh_water_city_tiles ? 0 : Tile_has_city (this); -} - -int -show_razing_popup (void * popup_object, int popup_param_1, int popup_param_2, int razing_option) -{ - int response = patch_show_popup (popup_object, __, popup_param_1, popup_param_2); - if (is->current_config.prevent_razing_by_players && (response == razing_option)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_RAZE", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - return 0; - } - return response; -} - -int __fastcall patch_show_popup_option_1_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 1); } -int __fastcall patch_show_popup_option_2_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 2); } - -int __fastcall -patch_Context_Menu_add_abandon_city (Context_Menu * this, int edx, int item_id, char * text, bool checkbox, Sprite * image) -{ - if (is->current_config.prevent_razing_by_players) - return 0; // Return value is ignored by the caller - else - return Context_Menu_add_item (this, __, item_id, text, checkbox, image); -} - -char * -check_pedia_upgrades_to_ptr (TextBuffer * this, char * str) -{ - Civilopedia_Form * pedia = p_civilopedia_form; - UnitType * unit_type = NULL; - if (is->current_config.indicate_non_upgradability_in_pedia && - (pedia->Current_Article_ID >= 0) && (pedia->Current_Article_ID <= pedia->Max_Article_ID) && - (NULL != (unit_type = pedia->Articles[pedia->Current_Article_ID]->unit_type)) && - ((unit_type->Special_Actions & UCV_Upgrade_Unit) == 0)) - return is->c3x_labels[CL_OBSOLETED_BY]; - else - return TextBuffer_check_ptr (this, __, str); -} - -char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_1 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } -char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_2 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } - -bool __fastcall -patch_Unit_select_stealth_attack_target (Unit * this, int edx, int target_civ_id, int x, int y, bool allow_popup, Unit ** out_selected_target) -{ - is->added_any_stealth_target = 0; - return Unit_select_stealth_attack_target (this, __, target_civ_id, x, y, allow_popup, out_selected_target); -} - -bool __fastcall -patch_Unit_can_stealth_attack (Unit * this, int edx, Unit * target) -{ - bool tr = Unit_can_stealth_attack (this, __, target); - - // If we're selecting a target for stealth attack via bombardment, we must filter out candidates we can't damage that way - if (tr && is->selecting_stealth_target_for_bombard && - ! can_damage_bombarding (&p_bic_data->UnitTypes[this->Body.UnitTypeID], target, tile_at (target->Body.X, target->Body.Y))) - return false; - - else if (tr && is->current_config.exclude_invisible_units_from_stealth_attack && ! patch_Unit_is_visible_to_civ (target, __, this->Body.CivID, 1)) - return false; - - else if (tr && is->current_config.exclude_passengers_from_stealth_attack && get_unit_ptr (target->Body.Container_Unit) != NULL) - return false; - - else - return tr; -} - -int __fastcall -patch_Tile_check_water_for_stealth_attack (Tile * this) -{ - // When stealth attack bombard is enabled, remove a special rule inside can_stealth_attack that prevents land units from stealth attacking - // onto sea tiles. This allows land artillery to stealth attack naval units. - return is->current_config.enable_stealth_attack_via_bombardment ? 0 : this->vtable->m35_Check_Is_Water (this); -} - -int __fastcall -patch_PopupSelection_add_stealth_attack_target (PopupSelection * this, int edx, char * text, int value) -{ - if (is->current_config.include_stealth_attack_cancel_option && (! is->added_any_stealth_target)) { - PopupSelection_add_item (this, __, is->c3x_labels[CL_NO_STEALTH_ATTACK], -1); - is->added_any_stealth_target = 1; - } - - Unit * unit; - if (is->current_config.show_hp_of_stealth_attack_options && - ((unit = get_unit_ptr (value)) != NULL)) { - char s[500]; - int max_hp = Unit_get_max_hp (unit); - snprintf (s, sizeof s, "(%d/%d) %s", max_hp - unit->Body.Damage, max_hp, text); - s[(sizeof s) - 1] = '\0'; - return PopupSelection_add_item (this, __, s, value); - } else - return PopupSelection_add_item (this, __, text, value); -} - -void __fastcall -patch_Unit_perform_air_recon (Unit * this, int edx, int x, int y) -{ - int moves_plus_one = this->Body.Moves + p_bic_data->General.RoadsMovementRate; - - bool was_intercepted = false; - if (is->current_config.intercept_recon_missions) { - // Temporarily add vision on the target tile so the game plays the animation if the unit is show down by ground AA - Tile_Body * tile = &tile_at (x, y)->Body; - int saved_vis = tile->Visibility; - tile->Visibility |= 1 << this->Body.CivID; - was_intercepted = Unit_try_flying_over_tile (this, __, x, y); - tile->Visibility = saved_vis; - } - - if (! was_intercepted) { - Unit_perform_air_recon (this, __, x, y); - if (is->current_config.charge_one_move_for_recon_and_interception) - this->Body.Moves = moves_plus_one; - } -} - -int __fastcall -patch_Unit_get_interceptor_max_moves (Unit * this) -{ - // Stop fighters from intercepting multiple times per turn without blitz - if (is->current_config.charge_one_move_for_recon_and_interception && - (this->Body.Status & USF_USED_ATTACK != 0) && ! UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Blitz)) - return 0; - - else - return patch_Unit_get_max_move_points (this); -} - -int __fastcall -patch_Unit_get_moves_after_interception (Unit * this) -{ - if (is->current_config.charge_one_move_for_recon_and_interception) { - this->Body.Status |= USF_USED_ATTACK; // Set status bit indicating that the interceptor has attacked this turn - return this->Body.Moves + p_bic_data->General.RoadsMovementRate; - } else - return patch_Unit_get_max_move_points (this); -} - -void __fastcall -patch_Unit_set_state_after_interception (Unit * this, int edx, int new_state) -{ - if (! is->current_config.charge_one_move_for_recon_and_interception) - Unit_set_state (this, __, new_state); - - // If fighters are supposed to be able to intercept multiple times per turn, then we can't knock them out of the interception state as soon as - // they intercept something like in the base game. Instead, record this interception event so that we can clear their state at the start of - // their next turn. - else { - struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->Body.CivID]; - reserve (sizeof irl->items[0], (void **)&irl->items, &irl->capacity, irl->count); - irl->items[irl->count++] = (struct interception) { - .unit_id = this->Body.ID, - .x = this->Body.X, - .y = this->Body.Y - }; - } -} - -// Goes through every entry in a table with unit IDs as keys and filters out any that belong to the given owner (or are invalid). -void -remove_unit_id_entries_owned_by (struct table * t, int owner_id) -{ - if (t->len > 0) { - clear_memo (); - FOR_TABLE_ENTRIES (tei, t) { - Unit * unit = get_unit_ptr (tei.key); - if ((unit == NULL) || (unit->Body.CivID == owner_id)) - memoize (tei.key); - } - for (int n = 0; n < is->memo_len; n++) - itable_remove (t, is->memo[n]); - } -} - -void __fastcall -patch_Leader_begin_turn (Leader * this) -{ - if (is->aerodrome_airlift_usage.len > 0) { - int civ_bit = 1 << this->ID; - clear_memo (); - FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { - int mask = tei.value; - if (mask & civ_bit) { - int new_mask = mask & ~civ_bit; - memoize (tei.key); - memoize (new_mask); - } - } - for (int n = 0; n < is->memo_len; n += 2) { - int key = is->memo[n]; - int new_mask = is->memo[n + 1]; - if (new_mask == 0) - itable_remove (&is->aerodrome_airlift_usage, key); - else - itable_insert (&is->aerodrome_airlift_usage, key, new_mask); - } - clear_memo (); - } - - // Eject trespassers - is->do_not_bounce_invisible_units = true; - if (is->current_config.disallow_trespassing && (*p_current_turn_no > 0)) - for (int n = 1; n < 32; n++) - if ((*p_player_bits & (1 << n)) && - (n != this->ID) && - (! this->At_War[n]) && - ((this->Relation_Treaties[n] & 2) == 0)) // Check right of passage - Leader_bounce_trespassing_units (&leaders[n], __, this->ID); - is->do_not_bounce_invisible_units = false; - - if (is->current_config.introduce_all_human_players_at_start_of_hotseat_game && - (*p_current_turn_no == 0) && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((*p_human_player_bits & (1 << this->ID)) != 0)) - for (int n = 0; n < 32; n++) - if (*p_human_player_bits & (1 << n)) - Leader_make_contact (this, __, n, false); - - Leader_begin_turn (this); -} - -void __fastcall -patch_Leader_begin_unit_turns (Leader * this) -{ - // Reset the states of all fighters that performed an interception on the previous turn. - struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->ID]; - for (int n = 0; n < irl->count; n++) { - struct interception * record = &irl->items[n]; - Unit * interceptor = get_unit_ptr (record->unit_id); - if ((interceptor != NULL) && - (interceptor->Body.CivID == this->ID) && - (interceptor->Body.X == record->x) && - (interceptor->Body.Y == record->y) && - (interceptor->Body.UnitState == UnitState_Intercept)) - Unit_set_state (interceptor, __, 0); - } - irl->count = 0; - - // Reset extra defensive bombard and airdrop counters - remove_unit_id_entries_owned_by (&is->extra_defensive_bombards, this->ID); - remove_unit_id_entries_owned_by (&is->airdrops_this_turn , this->ID); - remove_unit_id_entries_owned_by (&is->unit_transport_ties , this->ID); - - clear_memo (); - if (is->current_config.delete_off_map_ai_units && - ((*p_human_player_bits & (1 << this->ID)) == 0) && - (p_units->Units != NULL)) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit_Body * body = p_units->Units[n].Unit; - if ((body != NULL) && - ((int)body != offsetof (Unit, Body)) && - (body->CivID == this->ID) && - ! Map_in_range (&p_bic_data->Map, __, body->X, body->Y)) - memoize (body->ID); - } - for (int n = 0; n < is->memo_len; n++) - patch_Unit_despawn (get_unit_ptr (is->memo[n]), __, 0, 1, 0, 0, 0, 0, 0); - - Leader_begin_unit_turns (this); -} - -Unit * __fastcall -patch_Fighter_find_actual_bombard_defender (Fighter * this, int edx, Unit * bombarder, int tile_x, int tile_y, int bombarder_civ_id, bool land_lethal, bool sea_lethal) -{ - if (is->bombard_stealth_target == NULL) - return Fighter_find_defender_against_bombardment (this, __, bombarder, tile_x, tile_y, bombarder_civ_id, land_lethal, sea_lethal); - else - return is->bombard_stealth_target; -} - -Unit * -select_stealth_attack_bombard_target (Unit * unit, int tile_x, int tile_y) -{ - bool land_lethal = Unit_has_ability (unit, __, UTA_Lethal_Land_Bombardment), - sea_lethal = Unit_has_ability (unit, __, UTA_Lethal_Sea_Bombardment); - Unit * defender = Fighter_find_defender_against_bombardment (&p_bic_data->fighter, __, unit, tile_x, tile_y, unit->Body.CivID, land_lethal, sea_lethal); - if (defender != NULL) { - Unit * target; - is->selecting_stealth_target_for_bombard = 1; - bool got_one = patch_Unit_select_stealth_attack_target (unit, __, defender->Body.CivID, tile_x, tile_y, true, &target); - is->selecting_stealth_target_for_bombard = 0; - return got_one ? target : NULL; - } else - return NULL; -} - -bool __fastcall -patch_Unit_try_flying_for_precision_strike (Unit * this, int edx, int x, int y) -{ - bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); - if (is->current_config.polish_precision_striking && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) && - ! is_cruise_missile) - // This method returns -1 when some kind of error occurs. In that case, return true implying the unit was shot down so the caller - // doesn't do anything more. Otherwise, return false so it goes ahead and applies damage. - return Unit_play_bombard_fire_animation (this, __, x, y) == -1; - - else if (is->current_config.polish_precision_striking && is_cruise_missile) { - Unit_animate_cruise_missile_strike (this, __, x, y); - return false; - - } else - return Unit_try_flying_over_tile (this, __, x, y); -} - -void __fastcall -patch_Unit_play_bombing_anim_for_precision_strike (Unit * this, int edx, int x, int y) -{ - // Only play the bombing animation here if we haven't already played an animation in the above method. We don't want to play all animations - // here since the bombard fire animation can fail for whatever reason but this method can't handle failure. - bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); - if ((! is->current_config.polish_precision_striking) || - ((p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && ! is_cruise_missile)) - Unit_play_bombing_animation (this, __, x, y); -} - -int __fastcall -patch_Unit_play_anim_for_bombard_tile (Unit * this, int edx, int x, int y) -{ - Unit * stealth_attack_target = NULL; - if (((p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && - is->current_config.enable_stealth_attack_via_bombardment && - (! is_online_game ()) && - patch_Leader_is_tile_visible (&leaders[this->Body.CivID], __, x, y)) - is->bombard_stealth_target = select_stealth_attack_bombard_target (this, x, y); - - return Unit_play_bombard_fire_animation (this, __, x, y); -} - -void __fastcall -patch_Main_Screen_Form_issue_precision_strike_cmd (Main_Screen_Form * this, int edx, Unit * unit) -{ - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - if ((! is->current_config.polish_precision_striking) || (type->Unit_Class == UTC_Air)) - Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); - else { - // issue_precision_strike_cmd will use the unit type's operational range. To make it use bombard range instead, place that value in - // the operational range field temporarily. Conveniently, it's only necessary to do this temporary switch once, here, because the main - // screen form stores a copy of the range for its own use and the method to actually perform the strike doesn't check the range. - int saved_op_range = type->OperationalRange; - type->OperationalRange = type->Bombard_Range; - Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); - type->OperationalRange = saved_op_range; - } -} - -int __fastcall -patch_Map_compute_neighbor_index_for_cm_strike (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - int tr = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); - - if ((tr >= 0) && - (is->bombarding_unit != NULL) && - ((p_bic_data->UnitTypes[is->bombarding_unit->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && - is->current_config.enable_stealth_attack_via_bombardment && - (! is_online_game ()) && - patch_Leader_is_tile_visible (&leaders[is->bombarding_unit->Body.CivID], __, x_neigh, y_neigh)) - is->bombard_stealth_target = select_stealth_attack_bombard_target (is->bombarding_unit, x_neigh, y_neigh); - - return tr; -} - -int __fastcall -patch_rand_bombard_target (void * this, int edx, int lim) -{ - // If we have a bombard stealth attack target set then return 2 so that the bombard damage will be applied to units not pop or buildings. - return (is->bombard_stealth_target == NULL) ? rand_int (this, __, lim) : 2; -} - -int __fastcall -patch_rand_int_to_dodge_city_aa (void * this, int edx, int lim) -{ - int tr = rand_int (this, __, lim); - is->result_of_roll_to_dodge_city_aa = tr; - return tr; -} - -int __fastcall -patch_Unit_get_defense_to_dodge_city_aa (Unit * this) -{ - int defense = Unit_get_defense_strength (this); - if (is->current_config.show_message_after_dodging_sam && - (defense > is->result_of_roll_to_dodge_city_aa) && - (this->Body.CivID == p_main_screen_form->Player_CivID)) - show_map_specific_text (this->Body.X, this->Body.Y, is->c3x_labels[CL_DODGED_SAM], 0); - return defense; -} - -int __fastcall -patch_Unit_get_defense_to_find_bombard_defender (Unit * this) -{ - // The caller is filtering out candidates with zero defense strength as possible targets to receive damage from bombardment. We can return 0 - // here to make sure "this" unit is not targeted. - - Unit * container; - - if (is->current_config.immunize_aircraft_against_bombardment && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air)) - return 0; - - else if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return 0; - - else - return Unit_get_defense_strength (this); -} - -int __cdecl -patch_get_WindowsFileBox_from_ini (LPCSTR key, int param_2, int param_3) -{ - // If the file path has already been determined, then avoid using the Windows file picker. This makes the later code to insert the path easier - // since we only have to intercept the opening of the civ-style file picker instead of both that and the Windows one. - if (is->load_file_path_override == NULL) - return get_int_from_conquests_ini (key, param_2, param_3); - else - return 0; -} - -char const * __fastcall -patch_do_open_load_game_file_picker (void * this) -{ - if (is->load_file_path_override != NULL) { - char const * tr = is->load_file_path_override; - is->load_file_path_override = NULL; - return tr; - } else - return open_load_game_file_picker (this); -} - -int __fastcall -patch_show_intro_after_load_popup (void * this, int edx, int param_1, int param_2) -{ - if (! is->suppress_intro_after_load_popup) - return patch_show_popup (this, __, param_1, param_2); - else { - is->suppress_intro_after_load_popup = 0; - return 0; - } -} - -void __fastcall patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id); - -void * __cdecl -patch_do_load_game (char * param_1) -{ - void * tr = do_load_game (param_1); - - if (is->current_config.restore_unit_directions_on_game_load && (p_units->Units != NULL)) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if ((unit != NULL) && (unit->Body.UnitState != UnitState_Fortifying)) { - if (Map_in_range (&p_bic_data->Map, __, unit->Body.X, unit->Body.Y) && - Map_in_range (&p_bic_data->Map, __, unit->Body.PrevMoveX, unit->Body.PrevMoveY)) { - int dx = unit->Body.X - unit->Body.PrevMoveX, dy = unit->Body.Y - unit->Body.PrevMoveY; - int dir = -1; - if ((dx == 1) && (dy == -1)) dir = DIR_NE; - else if ((dx == 2) && (dy == 0)) dir = DIR_E; - else if ((dx == 1) && (dy == 1)) dir = DIR_SE; - else if ((dx == 0) && (dy == 2)) dir = DIR_S; - else if ((dx == -1) && (dy == 1)) dir = DIR_SW; - else if ((dx == -2) && (dy == 0)) dir = DIR_W; - else if ((dx == -1) && (dy == -1)) dir = DIR_NW; - else if ((dx == 0) && (dy == -2)) dir = DIR_N; - if (dir >= 0) - unit->Body.Animation.summary.direction = dir; - } - } - } - - // Apply era aliases - for (int n = 0; n < 32; n++) - if (*p_player_bits & (1 << n)) - apply_era_specific_names (&leaders[n]); - - if (is->current_config.apply_grid_ini_setting_on_game_load) { - int grid_on = get_int_from_conquests_ini ("GridOn", 0, 0); - Map_Renderer * mr = &p_bic_data->Map.Renderer; - if (grid_on && ! mr->MapGrid_Flag) - mr->vtable->m68_Toggle_Grid (mr); - } - - return tr; -} - -void * -load_game_ex (char const * file_path, int suppress_intro_popup) -{ - is->suppress_intro_after_load_popup = suppress_intro_popup; - is->load_file_path_override = file_path; - return patch_do_load_game (NULL); -} - -int __fastcall -patch_show_movement_phase_popup (void * this, int edx, int param_1, int param_2) -{ - int tr = patch_show_popup (this, __, param_1, param_2); - - int player_civ_id = p_main_screen_form->Player_CivID; - int replay_for_players = is->replay_for_players; // Store this b/c it gets reset on game load - if (replay_for_players & 1<showing_hotseat_replay = true; - - patch_do_save_game (hotseat_resume_save_path, 1, 0); - load_game_ex (hotseat_replay_save_path, 1); - p_main_screen_form->Player_CivID = player_civ_id; - - // Re-enable the GUI so the minimap is visible during the replay. We must also reset the minimap & redraw it so that it reflects the - // player we just seated (above) instead of leftover data from the last player. - Main_GUI * main_gui = &p_main_screen_form->GUI; - main_gui->is_enabled = 1; - Navigator_Data_reset (&main_gui->Navigator_Data); - main_gui->Base.vtable->m73_call_m22_Draw ((Base_Form *)main_gui); - - perform_interturn (); - load_game_ex (hotseat_resume_save_path, 1); - p_main_screen_form->is_now_loading_game = 0; - - // Restore the replay_for_players variable b/c it gets cleared when loading a game. Also mask out the bit for the player we just - // showed the replay to. - is->replay_for_players = replay_for_players & ~(1<showing_hotseat_replay = false; - } - - return tr; -} - -// Returns a set of player bits containing only those players that are human and can see at least one AI unit. For speed and simplicity, does not -// account for units' invisibility ability, units are considered visible as long as they're on a visible tile. -int -find_human_players_seeing_ai_units () -{ - int tr = 0; - Map * map = &p_bic_data->Map; - if (map->Tiles != NULL) - for (int n_tile = 0; n_tile < map->TileCount; n_tile++) { - Tile * tile = map->Tiles[n_tile]; - Tile_Body * body = &tile->Body; - int human_vis_bits = (body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility) & *p_human_player_bits; - if (human_vis_bits != 0) // If any human players can see this tile - for (int n_player = 0; n_player < 32; n_player++) - if (human_vis_bits & 1<TileUnitID, &unused); - Unit * unit = get_unit_ptr (unit_id); - if ((unit != NULL) && - ((*p_human_player_bits & 1<Body.CivID) == 0)) { - tr |= 1<current_config.replay_ai_moves_in_hotseat_games && - (*p_is_offline_mp_game && ! *p_is_pbem_game); // offline MP but not PBEM => we're in a hotseat game - int ai_unit_vis_before; - if (save_replay) { - ai_unit_vis_before = find_human_players_seeing_ai_units (); - int toggleable_rules = *p_toggleable_rules; - *p_toggleable_rules |= TR_PRESERVE_RANDOM_SEED; // Make sure preserve random seed is on for the replay save - patch_do_save_game (hotseat_replay_save_path, 1, 0); - *p_toggleable_rules = toggleable_rules; - } - - is->players_saw_ai_unit = 0; // Clear bits. After perform_interturn, each set bit will indicate a player that has seen an AI unit move - long long ts_before; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); - is->time_spent_paused_during_popup = 0; - is->time_spent_computing_city_connections = 0; - is->count_calls_to_recompute_city_connections = 0; - unsigned saved_prefs = *p_preferences; - if (is->current_config.measure_turn_times) - *p_preferences &= ~(P_ANIMATE_BATTLES | P_SHOW_FRIEND_MOVES | P_SHOW_ENEMY_MOVES); - - perform_interturn (); - - if (is->current_config.day_night_cycle_mode) { - if (is->day_night_cycle_img_state == IS_OK) { - int new_hour = calculate_current_day_night_cycle_hour (); - if (new_hour != is->current_day_night_cycle) { - is->current_day_night_cycle = new_hour; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - } - } - } - - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_for_districts (); - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - } - - if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { - is->city_loc_display_perspective = -1; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw - } - - if (is->current_config.measure_turn_times) { - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - long long perf_freq; - QueryPerformanceFrequency ((LARGE_INTEGER *)&perf_freq); - int turn_time_in_ms = 1000 * (ts_after - ts_before - is->time_spent_paused_during_popup) / perf_freq; - int city_con_time_in_ms = 1000 * is->time_spent_computing_city_connections / perf_freq; - int road_time_in_ms = 1000 * is->time_spent_filling_roads / perf_freq; - - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - char msg[1000]; - - struct c3x_opt { - bool is_active; - char * name; - } opts[] = {{is->current_config.optimize_improvement_loops, "improv. loops"}, - {is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_OK), "trade net x"}}; - char opt_list[1000]; - memset (opt_list, 0, sizeof opt_list); - strncpy (opt_list, "^C3X optimizations: ", sizeof opt_list); - bool any_active_opts = false; - for (int n = 0; n < ARRAY_LEN (opts); n++) - if (opts[n].is_active) { - char * cursor = &opt_list[strlen (opt_list)]; - snprintf (cursor, opt_list + (sizeof opt_list) - cursor, "%s%s", any_active_opts ? ", " : "", opts[n].name); - any_active_opts = true; - } - if (! any_active_opts) { - char * cursor = &opt_list[strlen (opt_list)]; - strncpy (cursor, "None", opt_list + (sizeof opt_list) - cursor); - } - PopupForm_add_text (popup, __, (char *)opt_list, false); - - snprintf (msg, sizeof msg, "^Turn time: %d.%03d sec", turn_time_in_ms/1000, turn_time_in_ms%1000); - PopupForm_add_text (popup, __, (char *)msg, false); - snprintf (msg, sizeof msg, "^ Recomputing city connections: %d.%03d sec (%d calls)", - city_con_time_in_ms/1000, city_con_time_in_ms%1000, - is->count_calls_to_recompute_city_connections); - PopupForm_add_text (popup, __, (char *)msg, false); - snprintf (msg, sizeof msg, "^ Flood filling road network: %d.%03d sec", - road_time_in_ms/1000, road_time_in_ms%1000); - PopupForm_add_text (popup, __, (char *)msg, false); - patch_show_popup (popup, __, 0, 0); - - *p_preferences = saved_prefs; - } - - if (save_replay) { - int last_human_player_bit = 0; { - for (int n = 0; n < 32; n++) - if (*p_human_player_bits & 1<replay_for_players = (ai_unit_vis_before | (is->players_saw_ai_unit & *p_human_player_bits)) & ~last_human_player_bit; - } -} - -void __cdecl -patch_initialize_map_music (int civ_id, int era_id, bool param_3) -{ - if (! is->showing_hotseat_replay) - initialize_map_music (civ_id, era_id, param_3); -} - -void __stdcall -patch_deinitialize_map_music () -{ - if (! is->showing_hotseat_replay) - deinitialize_map_music (); -} - -void __fastcall -patch_Fighter_do_bombard_tile (Fighter * this, int edx, Unit * unit, int neighbor_index, int mp_tile_x, int mp_tile_y) -{ - // Unit::score_kill will be called if the bombarder destroys its target, and that is the only way score_kill can be called while this method - // is running. So if we're configured to stop enslaving from bombard, turn off enslaving while it's running. - is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; - - // Check if we're going to do PTW-like targeting, if not fall back on the base game's do_bombard_tile method. We'll also fall back on that - // method in the case where we're in an online game and the bombard can't happen b/c the tile is occupied by another battle. In that case, no - // bombard is possible but we'll call the base method anyway since it will show a little message saying as much. - if (itable_look_up_or (&is->current_config.ptw_arty_types, unit->Body.UnitTypeID, 0) && - (is->bombard_stealth_target == NULL) && - ! (is_online_game () && mp_check_current_combat (p_mp_object, __, mp_tile_x, mp_tile_y))) { - - City * city; { - int dx, dy; - neighbor_index_to_diff (neighbor_index, &dx, &dy); - int tile_x = unit->Body.X + dx, tile_y = unit->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - city = city_at (tile_x, tile_y); - } - - int rv; - if ((city != NULL) && ((rv = rand_int (p_rand_object, __, 3)) < 2)) - Fighter_damage_city_by_bombardment (this, __, unit, city, rv, 0); - else - Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); - - } else - Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); - - is->do_not_enslave_units = false; -} - -bool __fastcall -patch_Unit_check_king_for_defense_priority (Unit * this, int edx, enum UnitTypeAbilities king_ability) -{ - return (! is->current_config.ignore_king_ability_for_defense_priority) || (*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) ? - Unit_has_ability (this, __, king_ability) : - false; -} - -void WINAPI -patch_get_local_time_for_unit_ini (LPSYSTEMTIME lpSystemTime) -{ - GetLocalTime (lpSystemTime); - if (is->current_config.no_elvis_easter_egg && (lpSystemTime->wMonth == 1) && (lpSystemTime->wDay == 8)) - lpSystemTime->wDay = 9; -} - -bool __fastcall -patch_Leader_could_buy_tech_for_trade_screen (Leader * this, int edx, int tech_id, int from_civ_id) -{ - // Temporarily remove the untradable flag so this tech is listed on the screen instead of skipped over. After all the items have been - // assembled, we'll go back and disable the untradable techs. - if (is->current_config.show_untradable_techs_on_trade_screen) { - int saved_flags = p_bic_data->Advances[tech_id].Flags; - p_bic_data->Advances[tech_id].Flags &= ~ATF_Cannot_Be_Traded; - bool tr = this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); - p_bic_data->Advances[tech_id].Flags = saved_flags; - return tr; - - } else - return this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); -} - -void __fastcall -patch_DiploForm_assemble_tradable_items (DiploForm * this) -{ - DiploForm_assemble_tradable_items (this); - - // Disable (gray out) all untradable techs - if (is->current_config.show_untradable_techs_on_trade_screen) - for (int n = 0; n < p_bic_data->AdvanceCount; n++) - if (p_bic_data->Advances[n].Flags & ATF_Cannot_Be_Traded) { - this->tradable_technologies[n].can_be_bought = 0; - this->tradable_technologies[n].can_be_sold = 0; - } -} - -bool __fastcall -patch_City_can_trade_via_water (City * this) -{ - if (is->current_config.optimize_improvement_loops) { - for (int n = 0; n < is->water_trade_improvs.count; n++) - if (has_active_building (this, is->water_trade_improvs.items[n])) - return true; - return false; - } else - return City_can_trade_via_water (this); -} - -bool __fastcall -patch_City_can_trade_via_air (City * this) -{ - if (is->current_config.optimize_improvement_loops) { - for (int n = 0; n < is->air_trade_improvs.count; n++) - if (has_active_building (this, is->air_trade_improvs.items[n])) - return true; - return false; - } else - return City_can_trade_via_air (this); -} - -int __fastcall -patch_City_get_building_defense_bonus (City * this) -{ - bool cancel_great_wall_boost = is->current_config.enable_districts && - is->current_config.enable_great_wall_districts && - is->current_config.disable_great_wall_city_defense_bonus; - - if (is->current_config.optimize_improvement_loops || cancel_great_wall_boost) { - int tr = 0; - int is_size_level_1 = (this->Body.Population.Size <= p_bic_data->General.MaximumSize_City) && - (this->Body.Population.Size <= p_bic_data->General.MaximumSize_Town); - for (int n = 0; n < is->combat_defense_improvs.count; n++) { - int improv_id = is->combat_defense_improvs.items[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((is_size_level_1 || (improv->Combat_Bombard == 0)) && has_active_building (this, improv_id)) { - int multiplier; - if ((improv->Combat_Bombard > 0) && - (! cancel_great_wall_boost) && - (patch_Leader_count_any_shared_wonders_with_flag (&leaders[(this->Body).CivID], __, ITW_Doubles_City_Defenses, NULL) > 0)) - multiplier = 2; - else - multiplier = 1; - - int building_defense = multiplier * improv->Combat_Defence; - if (building_defense > tr) - tr = building_defense; - } - } - return tr; - } else - return City_get_building_defense_bonus (this); -} - -bool __fastcall -patch_City_shows_harbor_icon (City * this) -{ - return is->current_config.city_icons_show_unit_effects_not_trade ? - City_count_improvements_with_flag (this, __, ITF_Veteran_Sea_Units) > 0 : - patch_City_can_trade_via_water (this); -} - -bool __fastcall -patch_City_shows_airport_icon (City * this) -{ - return is->current_config.city_icons_show_unit_effects_not_trade ? - City_count_improvements_with_flag (this, __, ITF_Veteran_Air_Units) > 0 : - patch_City_can_trade_via_air (this); -} - -int __fastcall -patch_Unit_eval_escort_requirement (Unit * this) -{ - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - int ai_strat = type->AI_Strategy; - bool owned_by_ai = (*p_human_player_bits & 1<Body.CivID) == 0; // We must not reduce the escort requirement for human-owned units - // because that will interfere with group movement of units. - - // Apply special escort rules - if (owned_by_ai && is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) - return 0; - else if (owned_by_ai && is->current_config.use_offensive_artillery_ai && (ai_strat & UTAI_Artillery)) - return 1; - - else { - int base = Unit_eval_escort_requirement (this); - if (owned_by_ai && (ai_strat & (UTAI_Naval_Transport | UTAI_Naval_Carrier | UTAI_Naval_Missile_Transport))) - return not_above (is->current_config.max_ai_naval_escorts, base); - else - return base; - } -} - -bool __fastcall -patch_Unit_has_enough_escorters_present (Unit * this) -{ - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) - return true; - else - return Unit_has_enough_escorters_present (this); -} - -void __fastcall -patch_Unit_check_escorter_health (Unit * this, int edx, bool * has_any_escort_present, bool * any_escorter_cant_heal) -{ - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) { - *has_any_escort_present = true; - *any_escorter_cant_heal = true; // Returning true here indicates the unit should not stop to wait for its escorter(s) to heal. - } else - Unit_check_escorter_health (this, __, has_any_escort_present, any_escorter_cant_heal); -} - -void __fastcall -patch_Leader_unlock_technology (Leader * this, int edx, int tech_id, bool param_2, bool param_3, bool param_4) -{ - int * p_stack = (int *)&tech_id; - int ret_addr = p_stack[-1]; - - Leader_unlock_technology (this, __, tech_id, param_2, param_3, param_4); - - // If this method was not called during game initialization - if ((ret_addr != ADDR_UNLOCK_TECH_AT_INIT_1) && - (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_2) && - (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_3)) { - - // If this tech obsoletes some building and we're configured to fix the maintenance bug then recompute city maintenance. - if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings) { - bool obsoletes_anything = false; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (p_bic_data->Improvements[n].ObsoleteID == tech_id) { - obsoletes_anything = true; - break; - } - if (obsoletes_anything) - Leader_recompute_buildings_maintenance (this); - } - } -} - -int __fastcall -patch_City_get_improv_maintenance_for_ui (City * this, int edx, int improv_id) -{ - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && - (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) - return 0; - else - return patch_City_get_improvement_maintenance (this, __, improv_id); -} - -// Patch for barbarian diagonal bug. This bug is a small mistake in the original code, maybe a copy+paste error. The original code tries to loop over -// tiles around the barb unit by incrementing a neighbor index and coverting it to tile coords (like normal). The problem is that after it converts -// the neighbor index to dx and dy, it adds dx to both coords of the unit's position instead of using dy. The fix is simply to subtract off dx and add -// in dy when the Y coord is passed to Map::wrap_vert. -void __cdecl -patch_neighbor_index_to_diff_for_barb_ai (int neighbor_index, int * out_x, int * out_y) -{ - neighbor_index_to_diff (neighbor_index, out_x, out_y); - is->barb_diag_patch_dy_fix = *out_y - *out_x; -} -int __fastcall -patch_Map_wrap_vert_for_barb_ai (Map * this, int edx, int y) -{ - return Map_wrap_vert (this, __, is->current_config.patch_barbarian_diagonal_bug ? (y + is->barb_diag_patch_dy_fix) : y); -} - -int -count_workable_tiles_for_city (City * city) -{ - if (city == NULL) - return 0; - - int workable = 0; - FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { - Tile * tile = wai.tile; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - if (tile->Body.CityAreaID != city->Body.ID) - continue; - - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && district_is_complete (tile, inst->district_id)) - continue; - - workable++; - } - return workable; -} - -int -compute_auto_distribution_hub_goal (Leader * leader, int city_count) -{ - int total_unused_tiles = 0; - int stagnating_cities = 0; - int slow_growth_cities = 0; - int very_low_production_cities = 0; - int low_production_cities = 0; - - FOR_CITIES_OF (coi, leader->ID) { - City * city = coi.city; - if (city == NULL) - continue; - - int pop_size = city->Body.Population.Size; - int workable_tiles = count_workable_tiles_for_city (city); - if ((workable_tiles > 0) && (pop_size < workable_tiles)) - total_unused_tiles += workable_tiles - pop_size; - - int net_food = city->Body.FoodIncome; - if (net_food <= 0) - stagnating_cities++; - else if (net_food <= 2) - slow_growth_cities++; - - int net_shields = city->Body.ProductionIncome + city->Body.ProductionLoss; - if (net_shields < 0) - net_shields = 0; - if (net_shields <= 3) - very_low_production_cities++; - else if (net_shields <= 6) - low_production_cities++; - } - - int base_desired = (city_count + 3) / 4; - - int tiles_per_chunk = is->workable_tile_count; - if (tiles_per_chunk <= 0) - tiles_per_chunk = 1; - int unused_bonus = (total_unused_tiles + tiles_per_chunk * 3 - 1) / (tiles_per_chunk * 3); - - int food_pressure = stagnating_cities * 2 + slow_growth_cities; - int food_bonus = (food_pressure + 2) / 3; - - int production_pressure = very_low_production_cities * 2 + low_production_cities; - int production_bonus = (production_pressure + 2) / 3; - - int desired = base_desired + unused_bonus + food_bonus + production_bonus; - int max_reasonable = (city_count + 1) / 2; - int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; - if (max_per_100 > 0) { - int capped = (city_count * max_per_100 + 99) / 100; - if (capped >= 0) - max_reasonable = capped; - } - if (desired > max_reasonable) - desired = max_reasonable; - if (desired < 1) - desired = 1; - - return desired; -} - -void -ai_update_distribution_hub_goal_for_leader (Leader * leader) -{ - if (leader == NULL) - return; - if (! is->current_config.enable_districts || - ! is->current_config.enable_distribution_hub_districts) - return; - - int civ_id = leader->ID; - if ((1 << civ_id) & *p_human_player_bits) - return; - - int city_count = leader->Cities_Count; - if (city_count <= 0) - return; - - int desired = 0; - if (is->current_config.ai_distribution_hub_build_strategy == ADHBS_AUTO) - desired = compute_auto_distribution_hub_goal (leader, city_count); - else { - int ideal_per_100 = is->current_config.ai_ideal_distribution_hub_count_per_100_cities; - if (ideal_per_100 <= 0) - return; - desired = (city_count * ideal_per_100) / 100; - } - if (desired <= 0) - return; - - int current = 0; - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if ((rec != NULL) && (rec->civ_id == civ_id)) - current++; - } - - int in_progress = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * tile = (Tile *)tei.key; - int mapped_district_id = tei.value; - if ((tile != NULL) && - (mapped_district_id == DISTRIBUTION_HUB_DISTRICT_ID) && - ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID)) { - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (owner == civ_id) - in_progress++; - } - } - - int pending = 0; - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req != NULL) && (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID)) - pending++; - } - - int planned = current + in_progress + pending; - if (planned >= desired) - return; - - City * capital = get_city_ptr (leader->CapitalID); - bool has_capital = (capital != NULL); - int capital_x = has_capital ? capital->Body.X : 0; - int capital_y = has_capital ? capital->Body.Y : 0; - - const int yield_weight = 40; - const int capital_distance_weight = 45; - const int desired_min_capital_distance = 8; - const int proximity_penalty_scale = 300; - - while (planned < desired) { - City * best_city = NULL; - int best_tile_x = 0; - int best_tile_y = 0; - int best_score = INT_MIN; - - FOR_CITIES_OF (coi, civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - if (city_has_required_district (city, DISTRIBUTION_HUB_DISTRICT_ID)) - continue; - - if (find_pending_district_request (city, DISTRIBUTION_HUB_DISTRICT_ID) != NULL) - continue; - - int tile_x, tile_y; - Tile * candidate = find_tile_for_district (city, DISTRIBUTION_HUB_DISTRICT_ID, &tile_x, &tile_y); - if (candidate == NULL) - continue; - - int yield_sum = compute_city_tile_yield_sum (city, tile_x, tile_y); - int distance_to_capital = 0; - if (has_capital) - distance_to_capital = compute_wrapped_manhattan_distance (city->Body.X, city->Body.Y, capital_x, capital_y); - - int closeness_penalty = 0; - if (has_capital && (distance_to_capital < desired_min_capital_distance)) - closeness_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; - - int score = yield_sum * yield_weight + distance_to_capital * capital_distance_weight - closeness_penalty; - if (tile_has_resource (candidate)) - score -= 500; - - if (score > best_score) { - best_score = score; - best_city = city; - best_tile_x = tile_x; - best_tile_y = tile_y; - } - } - - if (best_city == NULL) - break; - - mark_city_needs_district (best_city, DISTRIBUTION_HUB_DISTRICT_ID); - planned++; - } -} - -bool -assign_ai_fallback_production (City * city, int disallowed_improvement_id) -{ - if (city == NULL) - return false; - - City_Order new_order = { .OrderID = -1, .OrderType = 0 }; - patch_City_ai_choose_production (city, __, &new_order); - - bool order_ok = false; - if (new_order.OrderType == COT_Improvement) { - if ((new_order.OrderID >= 0) && - (new_order.OrderID < p_bic_data->ImprovementsCount) && - (new_order.OrderID != disallowed_improvement_id) && - ! city_requires_district_for_improvement (city, new_order.OrderID, NULL) && - ! is_wonder_or_small_wonder_already_being_built (city, new_order.OrderID)) - order_ok = true; - } else if (new_order.OrderType == COT_Unit) { - if ((new_order.OrderID >= 0) && - (new_order.OrderID < p_bic_data->UnitTypeCount) && - (p_bic_data->UnitTypes[new_order.OrderID].Unit_Class == UTC_Land) && - patch_City_can_build_unit (city, __, new_order.OrderID, 1, 0, 0)) - order_ok = true; - } - - char ss[200]; - snprintf (ss, sizeof ss, "assign_ai_fallback_production: Remembering fallback pending building order for city %d (%s): id %d\n", - city->Body.ID, city->Body.CityName, disallowed_improvement_id); - (*p_OutputDebugStringA) (ss); - remember_pending_building_order (city, disallowed_improvement_id); - - if (order_ok) { - City_set_production (city, __, new_order.OrderType, new_order.OrderID, false); - return true; - } - - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) { - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - return true; - } - } - - return false; -} - -void __fastcall -patch_Leader_do_production_phase (Leader * this) -{ - recompute_resources_if_necessary (); - - if (is->current_config.enable_districts) { - assign_workers_for_pending_districts (this); - - if ((is->current_config.enable_canal_districts || is->current_config.enable_bridge_districts) && - (is->current_config.ai_builds_bridges || is->current_config.ai_builds_canals)) - assign_workers_for_ai_candidate_bridge_or_canals (this); - - bool ai_player = ((*p_human_player_bits & (1 << this->ID)) == 0); - int auto_dynamic_district_ids[COUNT_DISTRICT_TYPES]; - int auto_dynamic_district_count = 0; - - // For dynamic districts, the AI will never be triggered to build them if they have no dependent buildings. - // Determine which dynamic districts the AI could build. In the city loop after, mark which cities need them - if (ai_player) { - for (int district_id = is->special_district_count; district_id < is->district_count; district_id++) { - struct district_config * cfg = &is->district_configs[district_id]; - struct district_infos * info = &is->district_infos[district_id]; - - if (info->dependent_building_count > 0) continue; - if (cfg->command == -1) continue; - - if (! leader_can_build_district (this, district_id)) - continue; - - if (auto_dynamic_district_count < ARRAY_LEN (auto_dynamic_district_ids)) - auto_dynamic_district_ids[auto_dynamic_district_count++] = district_id; - } - } - - // Special exception for AI to build Central Rail Hub, which is available in Industrial era but Mass Transit, - // the only building dependent on it, is in the Modern era. Without this the AI wouldn't build in Industrial era. - if (is->current_config.enable_central_rail_hub_districts) { - if (leader_can_build_district (this, CENTRAL_RAIL_HUB_DISTRICT_ID)) - auto_dynamic_district_ids[auto_dynamic_district_count++] = CENTRAL_RAIL_HUB_DISTRICT_ID; - } - - if (is->current_config.enable_distribution_hub_districts) { - if (leader_can_build_district (this, DISTRIBUTION_HUB_DISTRICT_ID)) - ai_update_distribution_hub_goal_for_leader (this); - } - - FOR_CITIES_OF (coi, this->ID) { - City * city = coi.city; - if (city == NULL) continue; - - bool at_neighborhood_cap = is->current_config.enable_neighborhood_districts && city_is_at_neighborhood_cap (city); - - // Mark any needed dynamic districts for AI players. This isn't the most intelligent approach (we're not weighing district benefits), - // but it's simple and works reasonably well - if (ai_player && (auto_dynamic_district_count > 0)) { - for (int i = 0; i < auto_dynamic_district_count; i++) { - int district_id = auto_dynamic_district_ids[i]; - - if (city_has_required_district (city, district_id)) continue; - if (! city_can_build_district (city, district_id)) continue; - if (find_pending_district_request (city, district_id) != NULL) continue; - - int target_x = 0, target_y = 0; - if (find_tile_for_district (city, district_id, &target_x, &target_y) == NULL) - continue; - - mark_city_needs_district (city, district_id); - } - } - - if (at_neighborhood_cap) { - if (! ai_player) - maybe_show_neighborhood_growth_warning (city); - else - ensure_neighborhood_request_for_city (city); - } - - if (city->Body.Order_Type == COT_Unit) { - int unit_id = city->Body.Order_ID; - int req_district_id = -1; - bool needs_halt = false; - - if ((unit_id >= 0) && (unit_id < p_bic_data->UnitTypeCount)) { - UnitType * type = &p_bic_data->UnitTypes[unit_id]; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { - req_district_id = AERODROME_DISTRICT_ID; - needs_halt = true; - } else if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (city, PORT_DISTRICT_ID))) { - req_district_id = PORT_DISTRICT_ID; - needs_halt = true; - } - } - - if (needs_halt) { - char ss[200]; - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting unit %d due to missing district %d\n", - city->Body.ID, city->Body.CityName, unit_id, req_district_id); - (*p_OutputDebugStringA) (ss); - - if (ai_player) - mark_city_needs_district (city, req_district_id); - - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - - continue; - } - } - - if (city->Body.Order_Type != COT_Improvement) continue; - int i_improv = city->Body.Order_ID; - - // Check if production needs to be halted due to missing district - int req_district_id = -1; - char const * district_description = NULL; - bool needs_halt = false; - - // Check buildings & wonders dependent on districts - if (city_requires_district_for_improvement (city, i_improv, &req_district_id)) { - if (req_district_id >= 0) { - needs_halt = true; - district_description = is->district_configs[req_district_id].name; - } - } - - // Wonders - char ss[200]; - if (is->current_config.enable_wonder_districts) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: Checking wonder improv %d for city %d (%s)\n", - i_improv, city->Body.ID, city->Body.CityName); - (*p_OutputDebugStringA) (ss); - if (city_is_currently_building_wonder (city)) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) is building wonder improv %d\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - bool wonder_requires_district = false; - if (i_improv >= 0) { - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); - if (district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) - wonder_requires_district = true; - } - - if (wonder_requires_district) { - bool has_wonder_district = reserve_wonder_district_for_city (city, i_improv); - if (! has_wonder_district) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) lacks Wonder District for wonder improv %d\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - needs_halt = true; - req_district_id = WONDER_DISTRICT_ID; - district_description = "Wonder District"; - } - } else { - release_wonder_district_reservation (city); - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) wonder improv %d does not require Wonder District\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - } - } else { - release_wonder_district_reservation (city); - } - } - - // If production needs to be halted, handle the reassignment and messaging - if (needs_halt) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting improv %d due to missing district %d\n", - city->Body.ID, city->Body.CityName, i_improv, req_district_id); - (*p_OutputDebugStringA) (ss); - // Switch production to another option - if (ai_player) { - mark_city_needs_district (city, req_district_id); - assign_ai_fallback_production (city, i_improv); - } else { - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - // Show message to human player - if (! ai_player && (city->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[160]; - char const * bname = p_bic_data->Improvements[i_improv].Name.S; - snprintf (msg, sizeof msg, "%s %s %s", bname, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_description); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - continue; - } - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) improv %d passed missing district check\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - } - } - - // Force-activate the barbs if there are any barb cities on the map and barb city capturing is enabled. This is necessary for barb city - // production to work given how it's currently implemented. - if (is->current_config.enable_city_capture_by_barbarians && (this->ID == 0)) { - int any_barb_cities = 0; - FOR_CITIES_OF (coi, this->ID) { - any_barb_cities = 1; - break; - } - if (any_barb_cities) - is->force_barb_activity_for_cities = 1; - } - - // If barbs are force-activated, make sure their activity level is at least 1 (sedentary). - int * p_barb_activity = &p_bic_data->Map.World.Final_Barbarians_Activity; - int saved_barb_activity = *p_barb_activity; - if (is->force_barb_activity_for_cities && (*p_barb_activity <= 0)) - *p_barb_activity = 1; - - Leader_do_production_phase (this); - - if (is->force_barb_activity_for_cities) { - *p_barb_activity = saved_barb_activity; - is->force_barb_activity_for_cities = 0; - } -} - -// This function counts the number of players in the game. The return value will be compared to the number of cities on the map to determine if there -// are enough cities (per player) to unlock barb production. If barb activity is forced on, return zero so that the check always passes. -int __cdecl -patch_count_player_bits_for_barb_prod (unsigned int bit_field) -{ - return is->force_barb_activity_for_cities ? 0 : count_set_bits (bit_field); -} - -Tile * __fastcall -patch_Map_get_tile_to_check_visibility (Map * this, int edx, int index) -{ - Tile * tr = Map_get_tile (this, __, index); - int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; - if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { - int human_bits = *p_human_player_bits; - is->dummy_tile->Body.Fog_Of_War = tr->Body.Fog_Of_War | ((tr->Body.Fog_Of_War & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.FOWStatus = tr->Body.FOWStatus | ((tr->Body.FOWStatus & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.V3 = tr->Body.V3 | ((tr->Body.V3 & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.Visibility = tr->Body.Visibility | ((tr->Body.Visibility & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.field_D0_Visibility = tr->Body.field_D0_Visibility | ((tr->Body.field_D0_Visibility & human_bits) != 0 ? human_bits : 0); - tr = is->dummy_tile; - } - is->tile_returned_for_visibility_check = tr; - return tr; -} - -Tile * __fastcall -patch_Map_get_tile_to_check_visibility_again (Map * this, int edx, int index) -{ - return is->tile_returned_for_visibility_check; -} - -// Same as above except this method uses the FOWStatus field instead of Fog_Of_War -Tile * __fastcall -patch_Map_get_tile_for_fow_status_check (Map * this, int edx, int index) -{ - Tile * tile = Map_get_tile (this, __, index); - int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; - if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { - is->dummy_tile->Body.FOWStatus = ((tile->Body.FOWStatus & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; - return is->dummy_tile; - } else - return tile; -} - -Tile * __cdecl -patch_tile_at_to_check_visibility (int x, int y) -{ - return patch_Map_get_tile_to_check_visibility (&p_bic_data->Map, __, (p_bic_data->Map.Width >> 1) * y + (x >> 1)); -} - -Tile * __cdecl -patch_tile_at_to_check_visibility_again (int x, int y) -{ - return is->tile_returned_for_visibility_check; -} - -unsigned __fastcall -patch_Tile_m42_Get_Overlays (Tile * this, int edx, byte visible_to_civ) -{ - unsigned base_vis_overlays = Tile_m42_Get_Overlays (this, __, visible_to_civ); - if ((visible_to_civ != 0) && // if we're seeing from a player's persp. instead of seeing the actual overlays AND - is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND - ((1 << visible_to_civ) & *p_human_player_bits) && // the perspective is of a human player AND - (base_vis_overlays != this->Overlays) && // that player can't already see all the actual overlays AND - (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game - - // Check if there's another human player that can see the actual overlays. If so, give that info to this player and return it. - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != visible_to_civ) && - (Tile_m42_Get_Overlays (this, __, n_player) == this->Overlays)) { - this->Body.Visibile_Overlays[visible_to_civ] = this->Overlays; - return this->Overlays; - } - player_bits >>= 1; - n_player++; - } - - return base_vis_overlays; - } else - return base_vis_overlays; -} - -int __fastcall -patch_Tile_check_water_for_sea_zoc (Tile * this) -{ - if ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) - return this->vtable->m35_Check_Is_Water (this); - else - return 1; // The caller will skip ZoC logic if this is a land tile without a city because the targeted unit is a sea unit. Instead - // return 1, so all tiles are considered sea tiles, so we can run the ZoC logic for land units or air units on land. -} - -int __fastcall -patch_Tile_check_water_for_land_zoc (Tile * this) -{ - // Same as above except this time we want to consider all tiles to be land - return ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) ? - this->vtable->m35_Check_Is_Water (this) : - 0; -} - - -int __fastcall -patch_Unit_get_attack_strength_for_sea_zoc (Unit * this) -{ - return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) ? Unit_get_attack_strength (this) : 0; -} - -int __fastcall -patch_Unit_get_attack_strength_for_land_zoc (Unit * this) -{ - return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) ? Unit_get_attack_strength (this) : 0; -} - -// Forward declaration; defined further below near patch_Fighter_get_odds_for_main_combat_loop -// where its dependencies (apply_counter_rules, Fighter_get_combat_odds, counter_combat_ctx) live. -Unit * find_civ4_best_defender_against (Unit * attacker, Tile * tile, int tile_x, int tile_y); - -Unit * __fastcall -patch_Main_Screen_Form_find_visible_unit (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * excluded) -{ - struct unit_display_override * override = &is->unit_display_override; - if ((override->unit_id >= 0) && (override->tile_x == tile_x) && (override->tile_y == tile_y)) { - Unit * unit = get_unit_ptr (override->unit_id); - if (unit != NULL) { - if ((unit->Body.X == tile_x) && (unit->Body.Y == tile_y)) - return unit; - } - } - - // Civ 4-style 'best defender' display: when a player selects an attacker, the unit at the top of the enemy stack - // should be the one with the lowest win rate against that attacker. - // Only takes effect when both `use_civ4_style_best_defender` and `enable_unit_counters` are enabled, - // and provided the currently selected unit belongs to the local player and there is an enemy unit on the target square. - // - if (is->current_config.use_civ4_style_best_defender && - is->current_config.enable_unit_counters && - (this->Current_Unit != NULL) && - (this->Current_Unit->Body.CivID == this->Player_CivID) && - ((this->Current_Unit->Body.X != tile_x) || (this->Current_Unit->Body.Y != tile_y))) { - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile) && - tile_has_enemy_unit (tile, this->Current_Unit->Body.CivID)) { - Unit * best = find_civ4_best_defender_against (this->Current_Unit, tile, tile_x, tile_y); - if ((best != NULL) && (best != excluded)) - return best; - } - } - - return Main_Screen_Form_find_visible_unit (this, __, tile_x, tile_y, excluded); -} - -void __fastcall -patch_Animator_play_zoc_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) -{ - if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Air) - Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); -} - -bool __fastcall -patch_Fighter_check_zoc_anim_visibility (Fighter * this, int edx, Unit * attacker, Unit * defender, bool param_3) -{ - // If we've reached this point in the code (in the calling method) then a unit has been selected to exert zone of control and it has passed - // its dice roll to cause damage. Stash its pointer for possible use later. - is->zoc_interceptor = attacker; - - // If an air unit was selected, pre-emptively undo the damage from ZoC since we'll want to run our own bit of logic to do that (the air unit - // may still get shot down). Return false from this function to skip over all of the animation logic in the caller since it wouldn't work for - // aircraft. - if (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Air) { - defender->Body.Damage -= 1; - return false; - - // Repeat a check done by the caller. We've deleted this check to ensure that this function always gets called so we can grab the interceptor. - } else if (attacker->Body.Animation.field_111 == 0) - return false; - - else { - bool tr = Fighter_check_combat_anim_visibility (this, __, attacker, defender, param_3); - - // If necessary, set up to ensure the unit's attack animation is visible. This means forcing it to the top of its stack and - // temporarily unfortifying it if it's fortified. (If it's fortified, the animation is occasionally not visible. Don't know why.) - if (tr && is->current_config.show_zoc_attacks_from_mid_stack) { - is->unit_display_override = (struct unit_display_override) { attacker->Body.ID, attacker->Body.X, attacker->Body.Y }; - if (attacker->Body.UnitState == UnitState_Fortifying) { - Unit_set_state (attacker, __, 0); - is->refortify_interceptor_after_zoc = true; - } - } - - return tr; - } -} - -int __fastcall -patch_City_sum_buildings_naval_power_for_zoc (City * this) -{ - // Cancel out city's naval power if the unit has only one HP left. This prevents coastal fortresses from knocking that last hit point off - // passing units when lethal ZoC is enabled, because to make that work we delete an earlier check excusing 1-HP units from ZoC. - if ((is->zoc_defender != NULL) && - ((Unit_get_max_hp (is->zoc_defender) - is->zoc_defender->Body.Damage) <= 1)) - return 0; - - else - return City_sum_buildings_naval_power (this); -} - -void __fastcall -patch_Fighter_apply_zone_of_control (Fighter * this, int edx, Unit * unit, int from_x, int from_y, int to_x, int to_y) -{ - is->zoc_interceptor = NULL; - is->zoc_defender = unit; - is->refortify_interceptor_after_zoc = false; - struct unit_display_override saved_udo = is->unit_display_override; - Fighter_apply_zone_of_control (this, __, unit, from_x, from_y, to_x, to_y); - - // Actually exert ZoC if an air unit managed to do so. - if ((is->zoc_interceptor != NULL) && (p_bic_data->UnitTypes[is->zoc_interceptor->Body.UnitTypeID].Unit_Class == UTC_Air)) { - bool intercepted = Unit_try_flying_over_tile (is->zoc_interceptor, __, from_x, from_y); - if (! intercepted) { - Unit_play_bombing_animation (is->zoc_interceptor, __, from_x, from_y); - unit->Body.Damage = not_below (0, unit->Body.Damage + 1); - } - } - - if (is->refortify_interceptor_after_zoc) - Unit_set_state (is->zoc_interceptor, __, UnitState_Fortifying); - is->unit_display_override = saved_udo; -} - -// These two patches replace two function calls in Unit::move_to_adjacent_tile that come immediately after the unit has been subjected to zone of -// control. These calls recheck that the move is valid, not sure why. Here they're patched to indicate that the move in invalid when the unit was -// previously killed by ZoC. This causes move_to_adjacent_tile to return early without running the code that would place the unit on the destination -// tile and, for example, capturing an enemy city there. -int __fastcall -patch_Trade_Net_get_move_cost_after_zoc (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned param_7, int neighbor_index, Trade_Net_Distance_Info * dist_info) -{ - return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (unit) - unit->Body.Damage) > 0) ? - patch_Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, param_7, neighbor_index, dist_info) : - -1; -} - -AdjacentMoveValidity __fastcall -patch_Unit_can_move_after_zoc (Unit * this, int edx, int neighbor_index, int param_2) -{ - return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (this) - this->Body.Damage) > 0) ? - patch_Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2) : - AMV_1; -} - -// Checks unit's HP after it was possibly hit by ZoC and deals with the consequences if it's dead. Does nothing if config option to make ZoC lethal -// isn't set or if interceptor is NULL. Returns true if the unit was killed, false otherwise. -bool -check_life_after_zoc (Unit * unit, Unit * interceptor) -{ - if ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) && (interceptor != NULL) && - ((Unit_get_max_hp (unit) - unit->Body.Damage) <= 0)) { - - // Call Unit::score_kill but turn off enslaving if we're configured to stop enslaving after bombardment and the ZoC was performed by - // bombardment, which is always the case for cross-domain ZoC or when bombard str > attack. - UnitType * interceptor_type = &p_bic_data->UnitTypes[interceptor->Body.UnitTypeID]; - if (is->current_config.prevent_enslaving_by_bombardment && - ((p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != interceptor_type->Unit_Class) || - (interceptor_type->Bombard_Strength >= Unit_get_attack_strength (interceptor)))) - is->do_not_enslave_units = true; - Unit_score_kill (interceptor, __, unit, false); - is->do_not_enslave_units = false; - - if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (&p_bic_data->fighter, __, interceptor, unit, true)) - Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, unit, AT_DEATH, false); - - bool prev_always_despawn_passengers = is->always_despawn_passengers; - is->always_despawn_passengers = is_land_transport (unit) && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); - patch_Unit_despawn (unit, __, interceptor->Body.CivID, 0, 0, 0, 0, 0, 0); - is->always_despawn_passengers = prev_always_despawn_passengers; - - return true; - } else - return false; -} - -int __fastcall -patch_Unit_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, bool param_2, int param_3, byte param_4) -{ - is->moving_unit_to_adjacent_tile = true; - is->move_spend_override_unit = NULL; - is->move_spend_override_value = 0; - - bool const allow_worker_coast = is->current_config.enable_districts && is->current_config.workers_can_enter_coast && is_worker (this); - bool const allow_bridge_walk = is->current_config.enable_districts && - is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land); - bool const allow_canal_sail = is->current_config.enable_districts && - is->current_config.enable_canal_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea); - bool coast_override_active = false; - enum UnitStateType prev_state = this->Body.UnitState; - int prev_container = this->Body.Container_Unit; - bool restore_goto_path = prev_state == UnitState_Go_To; - int prev_path_len = this->Body.path_len; - int prev_path_dest_x = this->Body.path_dest_x; - int prev_path_dest_y = this->Body.path_dest_y; - - if (allow_worker_coast || allow_bridge_walk || allow_canal_sail) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - Tile * dest = tile_at (nx, ny); - if (dest != NULL) { - if (allow_bridge_walk && ! dest->vtable->m35_Check_Is_Water (dest)) { - Tile * src = tile_at (this->Body.X, this->Body.Y); - if ((src != NULL) && (src != p_null_tile)) { - struct district_instance * src_inst = get_district_instance (src); - bool from_bridge = (src_inst != NULL) && - (src_inst->district_id == BRIDGE_DISTRICT_ID) && - district_is_complete (src, src_inst->district_id); - if (from_bridge) { - int move_cost = patch_Trade_Net_get_movement_cost ( - is->trade_net, __, - this->Body.X, this->Body.Y, nx, ny, - this, this->Body.CivID, 0, neighbor_index, NULL); - if (move_cost >= 0) { - int spent_moves = this->Body.Moves + move_cost; - is->move_spend_override_unit = this; - is->move_spend_override_value = not_above (spent_moves, patch_Unit_get_max_move_points (this)); - } - } - } - } - - bool should_override = false; - if (allow_worker_coast && - dest->vtable->m35_Check_Is_Water (dest) && - (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - if (is_human) { - should_override = true; - } else { - struct district_worker_record * rec = get_tracked_worker_record (this); - struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; - if (req != NULL) { - City * req_city = (req->city != NULL) ? req->city : get_city_ptr (req->city_id); - if ((req->district_id >= 0) && - (req->district_id < is->district_count) && - (req_city != NULL) && - city_radius_contains_tile (req_city, nx, ny) && - (req->target_x == nx) && (req->target_y == ny)) { - struct district_config const * cfg = &is->district_configs[req->district_id]; - if ((cfg->buildable_square_types_mask & (1 << SQ_Coast)) != 0) - should_override = true; - } - } - } - } - - if (! should_override && allow_bridge_walk) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && - (inst->district_id == BRIDGE_DISTRICT_ID) && - district_is_complete (dest, inst->district_id)) - should_override = true; - } - - if (! should_override && allow_canal_sail) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && - (inst->district_id == CANAL_DISTRICT_ID) && - district_is_complete (dest, inst->district_id)) - should_override = true; - } - - if (should_override) { - coast_override_active = true; - is->coast_walk_unit = this; - is->coast_walk_transport_override = false; - is->coast_walk_prev_state = prev_state; - is->coast_walk_prev_container = prev_container; - is->coast_walk_restore_goto_path = restore_goto_path; - is->coast_walk_prev_path_len = prev_path_len; - is->coast_walk_prev_path_dest_x = prev_path_dest_x; - is->coast_walk_prev_path_dest_y = prev_path_dest_y; - } - } - } - - is->zoc_interceptor = is->zoc_defender = NULL; - int tr = Unit_move_to_adjacent_tile (this, __, neighbor_index, param_2, param_3, param_4); - if ((this == is->zoc_defender) && check_life_after_zoc (this, is->zoc_interceptor)) - tr = ! is_online_game (); // This is what the original method returns when the unit was destroyed in combat - - if (coast_override_active) { - is->coast_walk_unit = NULL; - is->coast_walk_transport_override = false; - - if (this->Body.Container_Unit == this->Body.ID) { - this->Body.Container_Unit = is->coast_walk_prev_container; - Unit_set_state (this, __, is->coast_walk_prev_state); - if (is->coast_walk_restore_goto_path) { - this->Body.path_len = is->coast_walk_prev_path_len; - this->Body.path_dest_x = is->coast_walk_prev_path_dest_x; - this->Body.path_dest_y = is->coast_walk_prev_path_dest_y; - } - } - } - - is->temporarily_disallow_lethal_zoc = false; - is->moving_unit_to_adjacent_tile = false; - is->move_spend_override_unit = NULL; - is->move_spend_override_value = 0; - return tr; -} - -void __fastcall -patch_Unit_load_into_army_after_move_to_adj_tile (Unit * this, int edx, Unit * loadee) -{ - // Take care not to load an army into itself b/c that will cause the game to crash. The game may attempt to do that at the end of - // move_to_adjacent_tile b/c we return the unit itself as a transport target when we want to allow it to move onto coast. - if (is->coast_walk_transport_override && this == loadee) - return; - - Unit_load_into_army (this, __, loadee); -} - -int __fastcall -patch_Unit_teleport (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad) -{ - is->zoc_interceptor = NULL; - int tr = Unit_teleport (this, __, tile_x, tile_y, unit_telepad); - check_life_after_zoc (this, is->zoc_interceptor); - return tr; -} - -bool -can_do_defensive_bombard (Unit * unit, UnitType * type) -{ - if ((type->Bombard_Strength > 0) && (! Unit_has_ability (unit, __, UTA_Cruise_Missile))) { - if (cannot_defend_inside_transport (unit)) - return false; - - if ((unit->Body.Status & USF_USED_DEFENSIVE_BOMBARD) == 0) // has not already done DB this turn - return true; - - // If the "blitz" special DB rule is activated and this unit has blitz, check if it still has an extra DB to use - else if ((is->current_config.special_defensive_bombard_rules & SDBR_BLITZ) && UnitType_has_ability (type, __, UTA_Blitz)) { - int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, unit->Body.ID, 0); - return type->Movement > extra_dbs + 1; - - } else - return false; - } else - return false; -} - -Unit * __fastcall -patch_Fighter_find_defensive_bombarder (Fighter * this, int edx, Unit * attacker, Unit * defender) -{ - int special_db_rules = is->current_config.special_defensive_bombard_rules; - if ((special_db_rules == 0) && - ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) == 0) && - ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) == 0)) - return Fighter_find_defensive_bombarder (this, __, attacker, defender); - else { - enum UnitTypeClasses attacker_class = p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class; - int attacker_has_one_hp = Unit_get_max_hp (attacker) - attacker->Body.Damage <= 1; - - Tile * defender_tile = tile_at (defender->Body.X, defender->Body.Y); - if ((Unit_get_defense_strength (attacker) < 1) || // if attacker cannot defend OR - (defender_tile == NULL) || (defender_tile == p_null_tile) || // defender tile is invalid OR - (((special_db_rules & SDBR_LETHAL) == 0) && attacker_has_one_hp) || // (DB is non-lethal AND attacker has one HP remaining) OR - ((special_db_rules & SDBR_NOT_INVISIBLE) && ! patch_Unit_is_visible_to_civ (attacker, __, defender->Body.CivID, 1))) // (invisible units are immune to DB AND attacker is invisible) - return NULL; - - Unit * tr = NULL; - int highest_strength = -1; - enum UnitTypeAbilities lethal_bombard_req = (attacker_class == UTC_Sea) ? UTA_Lethal_Sea_Bombardment : UTA_Lethal_Land_Bombardment; - FOR_UNITS_ON (uti, defender_tile) { - Unit * candidate = uti.unit; - UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; - if (can_do_defensive_bombard (candidate, candidate_type) && - (candidate_type->Bombard_Strength > highest_strength) && - (candidate != defender) && - (Unit_get_containing_army (candidate) != defender) && - ((attacker_class == candidate_type->Unit_Class) || - ((special_db_rules & SDBR_AERIAL) && - (candidate_type->Unit_Class == UTC_Air) && - (candidate_type->Air_Missions & UCV_Bombing)) || - ((special_db_rules & SDBR_DOCKED_VS_LAND) && - (candidate_type->Unit_Class == UTC_Sea) && - (get_city_ptr (defender_tile->CityID) != NULL))) && - ((! attacker_has_one_hp) || UnitType_has_ability (candidate_type, __, lethal_bombard_req))) { - tr = candidate; - highest_strength = candidate_type->Bombard_Strength; - } - } - return tr; - } -} - -void __fastcall -patch_Fighter_damage_by_db_in_main_loop (Fighter * this, int edx, Unit * bombarder, Unit * defender) -{ - if (p_bic_data->UnitTypes[bombarder->Body.UnitTypeID].Unit_Class == UTC_Air) { - if (Unit_try_flying_over_tile (bombarder, __, defender->Body.X, defender->Body.Y)) - return; // intercepted - else if (patch_Main_Screen_Form_is_unit_visible_to_player (p_main_screen_form, __, defender->Body.X, defender->Body.Y, bombarder)) - Unit_play_bombing_animation (bombarder, __, defender->Body.X, defender->Body.Y); - } - - // If the unit has already performed DB this turn, then record that it's consumed one of its extra DBs - if (bombarder->Body.Status & USF_USED_DEFENSIVE_BOMBARD) { - int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, bombarder->Body.ID, 0); - itable_insert (&is->extra_defensive_bombards, bombarder->Body.ID, extra_dbs + 1); - } - - int damage_before = defender->Body.Damage; - Fighter_damage_by_defensive_bombard (this, __, bombarder, defender); - int damage_after = defender->Body.Damage; - - is->dbe.bombarder = bombarder; - is->dbe.defender = defender; - if (damage_after > damage_before) { - is->dbe.damage_done = true; - int max_hp = Unit_get_max_hp (defender); - int dead_before = damage_before >= max_hp, dead_after = damage_after >= max_hp; - - // If the unit was killed by defensive bombard, play its death animation then toggle off animations for the rest of the combat so it - // doesn't look like anything else happens. Technically, the combat continues and the dead unit is guarantted to lose because the - // patch to get_combat_odds ensures the dead unit has no chance of winning a round. - if (dead_before ^ dead_after) { - is->dbe.defender_was_destroyed = true; - if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (this, __, bombarder, defender, true)) - Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, defender, AT_DEATH, false); - is->dbe.saved_animation_setting = this->play_animations; - this->play_animations = 0; - } - } -} - -int __fastcall -patch_Fighter_get_odds_for_main_combat_loop (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses) -{ - if (is->dbe.defender_was_destroyed) - return 1025; - - struct c3x_config * cfg = &is->current_config; - // Only OR in counter-rule terrain skipping when we actually ran apply_counter_rules for this - // call. Otherwise counter_combat_ctx.ignore_terrain can be stale from an earlier probe (e.g. - // find_civ4_best_defender_against) or an earlier combat round — especially risky after - // merges that add new odds call sites. - bool ignore_terrain_for_odds = ignore_defensive_bonuses; - if (cfg->enable_unit_counters && attacker != NULL && defender != NULL) { - Tile * def_tile = tile_at (this->defender_location_x, - this->defender_location_y); - int aa, dd; - bool ignore_terrain; - apply_counter_rules (cfg, attacker, defender, def_tile, - &aa, &dd, &ignore_terrain); - - is->counter_combat_ctx.active = true; - is->counter_combat_ctx.attacker = attacker; - is->counter_combat_ctx.defender = defender; - is->counter_combat_ctx.attacker_atk_pct = aa; - is->counter_combat_ctx.defender_def_pct = dd; - is->counter_combat_ctx.ignore_terrain = ignore_terrain; - ignore_terrain_for_odds = ignore_defensive_bonuses || ignore_terrain; - } - - int result = Fighter_get_combat_odds (this, __, attacker, defender, bombarding, - ignore_terrain_for_odds); - is->counter_combat_ctx.active = false; - return result; -} - -// Civ 4-style best defender: On the specified tile, pick the defender that is hardest for the -// attacker to beat (i.e. the one with the highest *defender* win rate against the attacker). -// Takes unit counter rules into account. Returns NULL if there is no suitable defender. -// -// IMPORTANT — odds semantics: vanilla Fighter_get_combat_odds returns the *defender*'s win -// chance (out of ~1024), not the attacker's. Confirmed by the existing patch at -// patch_Fighter_get_odds_for_main_combat_loop: when the attacker has been killed by defensive -// bombardment ("defender_was_destroyed"), the patch returns 1025 so the still-running combat -// loop sees ~100% defender win chance and finishes off the doomed attacker. Therefore "hardest -// to beat" = "highest defender win chance" = max odds. -// -// Notes: -// - Skips units with Container_Unit >= 0 (units inside armies/transports; only the top unit represents the group). -// - Skips units not visible to the attacker's civ, avoiding revealing invisible units. -// - Skips units of the same civ as the attacker (they cannot defend). -// - Skips units with defense strength <= 0 (incapable of combat). -// - Temporarily overwrites is->counter_combat_ctx internally and saves/restores the context before/after execution, -// to avoid disrupting the actual combat odds context. -Unit * -find_civ4_best_defender_against (Unit * attacker, Tile * tile, int tile_x, int tile_y) -{ - if ((attacker == NULL) || (tile == NULL) || (tile == p_null_tile)) - return NULL; - - // Defensive: validate attacker shape before we deref any of its fields downstream. If the - // pointer is stale or refers to a half-initialized unit, UnitTypeID will be out of range and - // we bail out instead of crashing inside Fighter_get_combat_odds / vtable calls. - int atk_tid = attacker->Body.UnitTypeID; - if ((atk_tid < 0) || (atk_tid >= p_bic_data->UnitTypeCount)) - return NULL; - - struct c3x_config * cfg = &is->current_config; - int attacker_civ = attacker->Body.CivID; - - // Backup the current counter ctx, as we'll be repeatedly overwriting it within the loop. - bool saved_active = is->counter_combat_ctx.active; - Unit * saved_attacker = is->counter_combat_ctx.attacker; - Unit * saved_defender = is->counter_combat_ctx.defender; - int saved_attacker_atk = is->counter_combat_ctx.attacker_atk_pct; - int saved_defender_def = is->counter_combat_ctx.defender_def_pct; - bool saved_ignore_terrain = is->counter_combat_ctx.ignore_terrain; - - // Backup the live Fighter struct fields. Vanilla Fighter_get_combat_odds may consult - // fighter.attacker / fighter.defender / fighter.defender_location_x/y to fetch terrain or - // state; if those still point at units from a previous combat (or are NULL during init), the - // vanilla code can dereference garbage and crash. We point them at the current candidate - // inside the loop and restore the originals at the end. - Unit * saved_fighter_attacker = p_bic_data->fighter.attacker; - Unit * saved_fighter_defender = p_bic_data->fighter.defender; - int saved_fighter_atk_x = p_bic_data->fighter.attacker_location_x; - int saved_fighter_atk_y = p_bic_data->fighter.attacker_location_y; - int saved_fighter_def_x = p_bic_data->fighter.defender_location_x; - int saved_fighter_def_y = p_bic_data->fighter.defender_location_y; - - Unit * best = NULL; - // We track the maximum defender win rate. Start below any possible result so the first - // eligible candidate always becomes the initial best. - int best_odds = -1; - - FOR_UNITS_ON (uti, tile) { - Unit * d = uti.unit; - if ((d == NULL) || (d == attacker)) - continue; - // Defensive: a unit on the tile_units linked list with an out-of-range type id is almost - // certainly stale or in some half-initialized state — skip it entirely so we never pass it - // to anything that dereferences UnitType. - int dtid = d->Body.UnitTypeID; - if ((dtid < 0) || (dtid >= p_bic_data->UnitTypeCount)) - continue; - if (d->Body.Container_Unit >= 0) - continue; - if (d->Body.CivID == attacker_civ) - continue; - // Must be a true enemy of the attacker (allies/peace treaties). - if (! d->vtable->is_enemy_of_civ (d, __, attacker_civ, 0)) - continue; - if (Unit_get_defense_strength (d) <= 0) - continue; - if (! patch_Unit_is_visible_to_civ (d, __, attacker_civ, 0)) - continue; - - // Apply unit counter multipliers (100 if unit counters are disabled, equivalent to vanilla win rate formula). - int aa = 100, dd = 100; - bool ignore_terrain = false; - if (cfg->enable_unit_counters) - apply_counter_rules (cfg, attacker, d, tile, &aa, &dd, &ignore_terrain); - - is->counter_combat_ctx.active = true; - is->counter_combat_ctx.attacker = attacker; - is->counter_combat_ctx.defender = d; - is->counter_combat_ctx.attacker_atk_pct = aa; - is->counter_combat_ctx.defender_def_pct = dd; - is->counter_combat_ctx.ignore_terrain = ignore_terrain; - - // Point the live Fighter struct at the (attacker, d) pair so the vanilla odds function - // reads valid pointers instead of stale ones. - p_bic_data->fighter.attacker = attacker; - p_bic_data->fighter.defender = d; - p_bic_data->fighter.attacker_location_x = attacker->Body.X; - p_bic_data->fighter.attacker_location_y = attacker->Body.Y; - p_bic_data->fighter.defender_location_x = tile_x; - p_bic_data->fighter.defender_location_y = tile_y; - - // IMPORTANT: vanilla Fighter_get_combat_odds reads attack/defense values directly from - // UnitType.Attack and UnitType.Defence — it does NOT route through Unit_get_attack/defense_strength - // in a way that this mod has hooked (Unit_get_defense_strength is not registered in - // civ_prog_objects.csv as an inlead, so patch_Unit_get_defense_strength never gets called from - // inside vanilla odds computation). To make our counter multipliers actually affect the odds we - // compute here, we monkey-patch the UnitType fields for the duration of the call and restore - // them immediately after. This is single-threaded mod code and the call window is microseconds, - // so no other reader can observe the temporary values. - UnitType * a_type = &p_bic_data->UnitTypes[atk_tid]; - UnitType * d_type = &p_bic_data->UnitTypes[dtid]; - int saved_a_attack = a_type->Attack; - int saved_d_defence = d_type->Defence; - if (aa != 100) - a_type->Attack = (saved_a_attack * aa) / 100; - if (dd != 100) - d_type->Defence = (saved_d_defence * dd) / 100; - - int odds = Fighter_get_combat_odds (&p_bic_data->fighter, __, attacker, d, false, ignore_terrain); - - a_type->Attack = saved_a_attack; - d_type->Defence = saved_d_defence; - - // odds = defender's win chance (see comment above the function). We want the candidate - // that is hardest for the attacker to beat, i.e. the one with the *highest* odds. - bool replace; - if (best == NULL) { - replace = true; - } else if (odds > best_odds) { - replace = true; - } else if (odds < best_odds) { - replace = false; - } else { - // Odds tie. Defer to vanilla's own defender comparator (cheaper-cost-defends-first - // etc.) — but we must give it the *effective* defense of each candidate against - // this attacker, otherwise it would compare base defenses (e.g. Swordsman base 2 vs - // Musketman base 4) and pick Musketman immediately, never reaching the cost - // tie-break that should decide between two units that are effectively equally hard - // to beat (Swordsman with a x2 counter has effective def 4, equal to Musketman's - // base 4 — vanilla's tie-break should then prefer the cheaper Swordsman). - // - // We can't rely on counter_combat_ctx flowing through Unit_get_defense_strength - // here (see the long comment above the odds call: the patch isn't actually hooked - // into vanilla code). So we apply the multiplier ourselves on top of whatever - // Unit_get_defense_strength returns for each candidate. - int best_aa = 100, best_dd = 100; - bool best_ignore = false; - if (cfg->enable_unit_counters) - apply_counter_rules (cfg, attacker, best, tile, &best_aa, &best_dd, &best_ignore); - - int d_def = (Unit_get_defense_strength (d) * dd ) / 100; - int best_def = (Unit_get_defense_strength (best) * best_dd) / 100; - - replace = Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, - d, d_def, best, best_def, true); - } - if (replace) { - best = d; - best_odds = odds; - } - } - - is->counter_combat_ctx.active = saved_active; - is->counter_combat_ctx.attacker = saved_attacker; - is->counter_combat_ctx.defender = saved_defender; - is->counter_combat_ctx.attacker_atk_pct = saved_attacker_atk; - is->counter_combat_ctx.defender_def_pct = saved_defender_def; - is->counter_combat_ctx.ignore_terrain = saved_ignore_terrain; - - // Restore the live Fighter struct so we don't leave it pointing at our probe values when a - // real combat (or other code path that reads it) starts. - p_bic_data->fighter.attacker = saved_fighter_attacker; - p_bic_data->fighter.defender = saved_fighter_defender; - p_bic_data->fighter.attacker_location_x = saved_fighter_atk_x; - p_bic_data->fighter.attacker_location_y = saved_fighter_atk_y; - p_bic_data->fighter.defender_location_x = saved_fighter_def_x; - p_bic_data->fighter.defender_location_y = saved_fighter_def_y; - - return best; -} - -byte __fastcall -patch_Fighter_fight (Fighter * this, int edx, Unit * attacker, - int attack_direction, Unit * defender_or_null) -{ - // Civ 4-style best defender: compute the defender from the target tile (neighbor of the - // attacker) using counter-aware odds, then use that unit for combat. - // - // Vanilla usually *pre-resolves* a defender and passes it non-NULL. That selection uses base - // UnitType stats (and cost tie-breaks), not our counter rules — so combat could hit Musketman - // while Main_Screen_Form_find_visible_unit (which always calls find_civ4_best_defender_against) - // showed Swordsman. We therefore apply our pick whenever the attack is a normal 8-neighbor - // strike and either no defender was passed, or the passed defender still sits on the target - // tile (vanilla's stack defender). If vanilla passes a defender on some other tile, leave it - // alone (unusual / non-adjacent paths). - if (is->current_config.use_civ4_style_best_defender && - is->current_config.enable_unit_counters && - (attacker != NULL) && - // Strict guard: attack_direction must be a valid 8-neighbor index. Some non-combat code - // paths call Fighter_fight with sentinel values (-1 etc.); forwarding those into - // neighbor_index_to_diff would produce a junk target tile and crash. - (attack_direction >= 0) && (attack_direction < 8)) { - int dx = 0, dy = 0; - neighbor_index_to_diff (attack_direction, &dx, &dy); - // Belt-and-braces: dx/dy must lie on the 8-neighbor lattice. - if ((dx >= -1) && (dx <= 1) && (dy >= -1) && (dy <= 1) && ((dx != 0) || (dy != 0))) { - int target_x = attacker->Body.X + dx; - int target_y = attacker->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); - Tile * target_tile = tile_at (target_x, target_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - bool vanilla_defender_on_target = - (defender_or_null != NULL) && - (defender_or_null->Body.X == target_x) && - (defender_or_null->Body.Y == target_y); - if ((defender_or_null == NULL) || vanilla_defender_on_target) { - Unit * picked = find_civ4_best_defender_against (attacker, target_tile, target_x, target_y); - if (picked != NULL) - defender_or_null = picked; - } - } - } - } - - byte tr = Fighter_fight (this, __, attacker, attack_direction, - defender_or_null); - is->dbe = (struct defensive_bombard_event) {0}; - is->counter_combat_ctx.active = false; - return tr; -} - -int __fastcall -patch_Unit_get_attack_strength (Unit * this) -{ - int base = Unit_get_attack_strength (this); - if (! is->counter_combat_ctx.active) - return base; - if (this == is->counter_combat_ctx.attacker) - return base * is->counter_combat_ctx.attacker_atk_pct / 100; - return base; -} - -int __fastcall -patch_Unit_get_defense_strength (Unit * this) -{ - int base = Unit_get_defense_strength (this); - if (! is->counter_combat_ctx.active) - return base; - if (this == is->counter_combat_ctx.defender) - return base * is->counter_combat_ctx.defender_def_pct / 100; - return base; -} - -void __fastcall -patch_Unit_score_kill_by_defender (Unit * this, int edx, Unit * victim, bool was_attacking) -{ - // This function is called when the defender wins in combat. If the attacker was actually killed by defensive bombardment, then award credit - // for that kill to the defensive bombarder not the defender in combat. - if (is->dbe.defender_was_destroyed) { - is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; - Unit_score_kill (is->dbe.bombarder, __, victim, was_attacking); - is->do_not_enslave_units = false; - p_bic_data->fighter.play_animations = is->dbe.saved_animation_setting; - - } else - Unit_score_kill (this, __, victim, was_attacking); -} - -void __fastcall -patch_Unit_play_attack_anim_for_def_bombard (Unit * this, int edx, int direction) -{ - // Don't play any animation for air units, the animations are instead handled in the patch for damage_by_defensive_bombard - if (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) { - - // Make sure the unit is displayed if it's in an army and we're configured for that - struct unit_display_override saved_udo = is->unit_display_override; - Unit * container; - if (is->current_config.show_armies_performing_defensive_bombard && - (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && - Unit_has_ability (container, __, UTA_Army)) - is->unit_display_override = (struct unit_display_override) { this->Body.ID, this->Body.X, this->Body.Y }; - - Unit_play_attack_animation (this, __, direction); - - is->unit_display_override = saved_udo; - } -} - -bool -can_precision_strike_tile_improv_at (Unit * unit, int x, int y) -{ - Tile * tile; - return is->current_config.allow_precision_strikes_against_tile_improvements && // we're configured to allow prec. strikes vs tiles AND - ((tile = tile_at (x, y)) != p_null_tile) && // get tile, make sure it's valid AND - is_explored (tile, unit->Body.CivID) && // tile has been explored by attacker AND - has_any_destructible_overlays (tile, true); // it has something that can be destroyed by prec. strike -} - -// Same as above function except this one applies to the V3 field instead of FOWStatus -Tile * __cdecl -patch_tile_at_for_v3_check (int x, int y) -{ - Tile * tile = tile_at (x, y); - int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; - if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { - is->dummy_tile->Body.V3 = ((tile->Body.V3 & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; - return is->dummy_tile; - } else - return tile; -} - -bool __fastcall -patch_Unit_check_contact_bit_6_on_right_click (Unit * this, int edx, int civ_id) -{ - bool tr = Unit_check_contact_bit_6 (this, __, civ_id); - if ((! tr) && - is->current_config.share_visibility_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << civ_id) & *p_human_player_bits)) { // is civ_id a human player - if ((1 << this->Body.CivID) & *p_human_player_bits) - tr = true; - - else { - // Check if any other human player has contact - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != civ_id) && - Unit_check_contact_bit_6 (this, __, n_player)) { - tr = true; - break; - } - player_bits >>= 1; - n_player++; - } - } - } - return tr; -} - -bool __fastcall -patch_Unit_check_precision_strike_target (Unit * this, int edx, int tile_x, int tile_y) -{ - return Unit_check_precision_strike_target (this, __, tile_x, tile_y) || can_precision_strike_tile_improv_at (this, tile_x, tile_y); -} - -void __fastcall -patch_Unit_play_attack_animation_vs_tile (Unit * this, int edx, int direction) -{ - if (is->current_config.polish_precision_striking && - UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile) && - (is->attacking_tile_x != this->Body.X) && (is->attacking_tile_y != this->Body.Y)) - Unit_animate_cruise_missile_strike (this, __, is->attacking_tile_x, is->attacking_tile_y); - else - Unit_play_attack_animation (this, __, direction); -} - -void __fastcall -patch_Unit_attack_tile (Unit * this, int edx, int x, int y, int bombarding) -{ - Tile * target_tile = NULL; - bool had_district_before = false; - int district_id_before = -1; - int tile_x = x; - int tile_y = y; - - if (is->current_config.enable_districts) { - - // Check if this is a completed wonder district that cannot be destroyed - if (is->current_config.enable_wonder_districts && - !is->current_config.completed_wonder_districts_can_be_destroyed) { - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - target_tile = tile_at (tile_x, tile_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - struct wonder_district_info * info = get_wonder_district_info (target_tile); - if (info != NULL && info->state == WDS_COMPLETED) { - // This tile has a completed wonder district and they can't be destroyed - if (((*p_human_player_bits & (1 << this->Body.CivID)) != 0) && - (this->Body.CivID == p_main_screen_form->Player_CivID)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_PILLAGE", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - return; - } - } - } - - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - target_tile = tile_at (tile_x, tile_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (target_tile); - if (inst != NULL) { - had_district_before = true; - district_id_before = inst->district_id; - } - } - } - - is->attacking_tile_x = x; - is->attacking_tile_y = y; - if (bombarding) - is->unit_bombard_attacking_tile = this; - - Unit_attack_tile (this, __, x, y, bombarding); - - // Check if the district was destroyed by the attack - if (had_district_before && (target_tile != NULL) && (target_tile != p_null_tile) && district_id_before != NATURAL_WONDER_DISTRICT_ID) { - struct district_instance * inst_after = get_district_instance (target_tile); - bool has_district_after = (inst_after != NULL); - int district_id_after = (inst_after != NULL) ? inst_after->district_id : -1; - - // If the district existed before but not after, or the tile no longer has a mine, the district was destroyed - if (!has_district_after || !(target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & TILE_FLAG_MINE)) { - bool is_water_tile = target_tile != NULL && target_tile->vtable->m35_Check_Is_Water (target_tile); - handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, ! is_water_tile); - } - } - - is->unit_bombard_attacking_tile = NULL; - is->attacking_tile_x = is->attacking_tile_y = -1; -} - -void __fastcall -patch_Unit_do_precision_strike (Unit * this, int edx, int x, int y) -{ - if ((city_at (x, y) == NULL) && can_precision_strike_tile_improv_at (this, x, y)) - patch_Unit_attack_tile (this, __, x, y, 1); - else - Unit_do_precision_strike (this, __, x, y); - - if (is->current_config.polish_precision_striking && - UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile)) - patch_Unit_despawn (this, __, 0, false, false, 0, 0, 0, 0); -} - -int __fastcall -patch_Unit_get_max_moves_after_barricade_attack (Unit * this) -{ - if (is->current_config.dont_end_units_turn_after_bombarding_barricade && (this == is->unit_bombard_attacking_tile)) - return this->Body.Moves + p_bic_data->General.RoadsMovementRate; - else - return patch_Unit_get_max_move_points (this); -} - -City * __cdecl -patch_city_at_in_find_bombard_defender (int x, int y) -{ - // The caller (Fighter::find_defender_against_bombardment) has a set of lists of bombard priority/eligibility in its stack memory. The list - // for land units bombarding land tiles normally restricts the targets to land units by containing [UTC_Land, -1, -1]. If we're configured to - // remove that restriction, modify the list so it contains instead [UTC_Land, UTC_Sea, UTC_Air]. Conveniently, the offset from this function's - // first parameter to the list is 0x40 bytes in all executables. - if (is->current_config.remove_land_artillery_target_restrictions) { - enum UnitTypeClasses * list = (void *)((byte *)&x + 0x40); - list[1] = UTC_Sea; - list[2] = UTC_Air; - } - - return city_at (x, y); -} - -bool __fastcall -patch_Unit_check_bombard_target (Unit * this, int edx, int tile_x, int tile_y) -{ - bool base = Unit_check_bombard_target (this, __, tile_x, tile_y); - Tile * tile = tile_at (tile_x, tile_y); - int overlays; - - if (base && - itable_look_up_or (&is->current_config.can_bombard_only_sea_tiles, this->Body.UnitTypeID, 0) && - ! tile->vtable->m35_Check_Is_Water (tile)) - return false; - - else if (base && - is->current_config.disallow_useless_bombard_vs_airfields && - ! Unit_has_ability (this, __, UTA_Nuclear_Weapon) && - ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // if tile has an airfield AND - (overlays == 0x20000000)) { // tile only has an airfield - UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - - // Check that a bombard attack vs this tile would not be wasted. It won't be if either (1) there are no units on the tile, (2) there - // is a unit that can be damaged by bombarding, or (3) there are no units that can be damaged and no air units. The rules for - // bombardment are that you can't damage aircraft in an airfield and you also can't destroy an airfield from underneath aircraft. - int any_units = 0, - any_vulnerable_units = 0, - any_air_units = 0; - FOR_UNITS_ON (uti, tile) { - enum UnitTypeClasses class = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; - any_units = 1; - any_air_units |= class == UTC_Air; - any_vulnerable_units |= (class != UTC_Air) && (Unit_get_defense_strength (uti.unit) > 0) && - can_damage_bombarding (this_type, uti.unit, tile); - } - return (! any_units) || // case (1) above - any_vulnerable_units || // case (2) - ((! any_air_units) && (! any_vulnerable_units)); // case (3) - - } else - return base; -} - -bool __fastcall -patch_Unit_can_disembark_anything (Unit * this, int edx, int tile_x, int tile_y) -{ - Tile * this_tile = tile_at (this->Body.X, this->Body.Y); - Tile * target_tile = tile_at (tile_x, tile_y); - bool base = Unit_can_disembark_anything (this, __, tile_x, tile_y); - - // Apply units per tile limit - if (base) { - bool stack_limited_for_all = true; - FOR_UNITS_ON (uti, this_tile) - if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_below_stack_limit (target_tile, this->Body.CivID, uti.unit->Body.UnitTypeID)) { - stack_limited_for_all = false; - break; - } - if (stack_limited_for_all) - return false; - } - - // Apply trespassing restriction. First check if this civ may move into (tile_x, tile_y) without trespassing. If it would be trespassing, then - // we can only disembark anything if this transport has a passenger that can ignore the restriction. Without this check, the game can enter an - // infinite loop under rare circumstances. - if (base && - is->current_config.disallow_trespassing && - check_trespassing (this->Body.CivID, this_tile, target_tile)) { - bool any_exempt_passengers = false; - FOR_UNITS_ON (uti, this_tile) - if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_allowed_to_trespass (uti.unit)) { - any_exempt_passengers = true; - break; - } - return any_exempt_passengers; - - } else - return base; -} - -int __fastcall -patch_Unit_get_defense_for_bombardable_unit_check (Unit * this) -{ - // Returning a defense value of zero indicates this unit is not a target for bombardment. If configured, exclude all air units from - // bombardment so the attacks target tile improvements instead. Do this only if the tile has another improvement in addition to an airfield, - // or we could destroy the airfield itself. - Tile * tile; - int overlays; - if (is->current_config.allow_bombard_of_other_improvs_on_occupied_airfield && // If configured AND - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && // "this" is an air unit AND - ((tile = tile_at (this->Body.X, this->Body.Y)) != p_null_tile) && // "this" is on a valid tile AND - ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // tile has an airfield AND - (overlays != 0x20000000)) // tile does not only have an airfield - return 0; - - else - return Unit_get_defense_strength (this); -} - -void __fastcall -patch_Demographics_Form_m22_draw (Demographics_Form * this) -{ - Demographics_Form_m22_draw (this); - - if (is->current_config.show_total_city_count) { - // There's proably a better way to get the city count, but better safe than sorry. I don't know if it's possible for the city list to - // contain holes so the surest thing is to check every possible ID. - int city_count = 0; { - if (p_cities->Cities != NULL) - for (int n = 0; n <= p_cities->LastIndex; n++) { - City_Body * body = p_cities->Cities[n].City; - city_count += (body != NULL) && ((int)body != offsetof (City, Body)); - } - } - - PCX_Image * canvas = &this->Base.Data.Canvas; - - // Draw backdrop - { - char temp_path[2*MAX_PATH]; - PCX_Image backdrop; - PCX_Image_construct (&backdrop); - get_mod_art_path ("CityCountBackdrop.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&backdrop, __, temp_path, NULL, 0, 0x100, 2); - if (backdrop.JGL.Image != NULL) { - int w = backdrop.JGL.Image->vtable->m54_Get_Width (backdrop.JGL.Image); - PCX_Image_draw_onto (&backdrop, __, canvas, (1024 - w) / 2, 720); - } - backdrop.vtable->destruct (&backdrop, __, 0); - } - - // Draw text on top of the backdrop - char s[100]; - snprintf (s, sizeof s, "%s %d / %d", is->c3x_labels[CL_TOTAL_CITIES], city_count, is->city_limit); - s[(sizeof s) - 1] = '\0'; - PCX_Image_set_text_effects (canvas, __, 0x80000000, -1, 2, 2); // Set text color to black - PCX_Image_draw_centered_text (canvas, __, get_font (14, FSF_NONE), s, 1024/2 - 100, 730, 200, strlen (s)); - } -} - -int __fastcall -patch_Leader_get_optimal_city_number (Leader * this) -{ - if (! is->current_config.strengthen_forbidden_palace_ocn_effect) - return Leader_get_optimal_city_number (this); - else { - int num_sans_fp = Leader_get_optimal_city_number (this), // OCN w/o contrib from num of FPs - fp_count = patch_Leader_count_wonders_with_small_flag (this, __, ITSW_Reduces_Corruption, NULL), - s_diff = p_bic_data->DifficultyLevels[this->player_difficulty].Optimal_Cities, // Difficulty scaling, called "percentage of optimal cities" in the editor - base_ocn = p_bic_data->WorldSizes[p_bic_data->Map.World.World_Size].OptimalCityCount; - return num_sans_fp + (s_diff * fp_count * base_ocn + 50) / 100; // Add 50 to round off - } -} - -int __fastcall -patch_Leader_count_forbidden_palaces_for_ocn (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) -{ - if (! is->current_config.strengthen_forbidden_palace_ocn_effect) - return patch_Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); - else - return 0; // We'll add in the FP effect later with a different weight -} - -void __fastcall -patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id) -{ - is->is_computing_city_connections = true; - long long ts_before; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); - - if (is->tnx_init_state == IS_OK) { - if (is->tnx_cache == NULL) { - is->tnx_cache = is->create_tnx_cache (&p_bic_data->Map); - is->set_up_before_building_network (is->tnx_cache); - } else if (! is->keep_tnx_cache) - is->set_up_before_building_network (is->tnx_cache); - } - - Trade_Net_recompute_city_connections (this, __, civ_id, redo_road_network, param_3, redo_roads_for_city_id); - - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; - - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - is->time_spent_computing_city_connections += ts_after - ts_before; - is->count_calls_to_recompute_city_connections++; - is->is_computing_city_connections = false; -} - -void __fastcall -patch_Map_build_trade_network (Map * this) -{ - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) - is->set_up_before_building_network (is->tnx_cache); - is->keep_tnx_cache = true; - Map_build_trade_network (this); - is->keep_tnx_cache = false; - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; -} - -void __fastcall -patch_Trade_Net_recompute_city_cons_and_res (Trade_Net * this, int edx, bool param_1) -{ - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) - is->set_up_before_building_network (is->tnx_cache); - - is->keep_tnx_cache = true; - Trade_Net_recompute_city_cons_and_res (this, __, param_1); - is->keep_tnx_cache = false; - - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; -} - -int __fastcall -patch_Trade_Net_set_unit_path_to_fill_road_net (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) -{ - int tr; - long long ts_before; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); - - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { - is->flood_fill_road_network (is->tnx_cache, from_x, from_y, civ_id); - tr = 0; // Return value is not used by caller anyway - } else - tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); - - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - is->time_spent_filling_roads += ts_after - ts_before; - return tr; -} - -bool -set_up_gdi_plus () -{ - if (is->gdi_plus.init_state == IS_UNINITED) { - is->gdi_plus.init_state = IS_INIT_FAILED; - is->gdi_plus.gp_graphics = NULL; - - struct startup_input { - UINT32 GdiplusVersion; - void * DebugEventCallback; - BOOL SuppressBackgroundThread; - BOOL SuppressExternalCodecs; - } startup_input = {1, NULL, FALSE, FALSE}; - - is->gdi_plus.module = LoadLibraryA ("gdiplus.dll"); - if (is->gdi_plus.module == NULL) { - MessageBoxA (NULL, "Failed to load gdiplus.dll!", "Error", MB_ICONERROR); - goto end_init; - } - - int (WINAPI * GdiplusStartup) (ULONG_PTR * out_token, struct startup_input *, void * startup_output) = - (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdiplusStartup"); - - is->gdi_plus.CreateFromHDC = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreateFromHDC"); - is->gdi_plus.DeleteGraphics = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeleteGraphics"); - is->gdi_plus.SetSmoothingMode = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetSmoothingMode"); - is->gdi_plus.SetPenDashStyle = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetPenDashStyle"); - is->gdi_plus.CreatePen1 = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreatePen1"); - is->gdi_plus.DeletePen = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeletePen"); - is->gdi_plus.DrawLineI = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDrawLineI"); - if ((is->gdi_plus.CreateFromHDC == NULL) || (is->gdi_plus.DeleteGraphics == NULL) || - (is->gdi_plus.SetSmoothingMode == NULL) || (is->gdi_plus.SetPenDashStyle == NULL) || - (is->gdi_plus.CreatePen1 == NULL) || (is->gdi_plus.DeletePen == NULL) || - (is->gdi_plus.DrawLineI == NULL)) { - MessageBoxA (NULL, "Failed to get GDI+ proc addresses!", "Error", MB_ICONERROR); - goto end_init; - } - - int status = GdiplusStartup (&is->gdi_plus.token, &startup_input, NULL); - if (status != 0) { - char s[200]; - snprintf (s, sizeof s, "Failed to initialize GDI+! Startup status: %d", status); - MessageBoxA (NULL, s, "Error", MB_ICONERROR); - goto end_init; - } - - is->gdi_plus.init_state = IS_OK; - end_init: - ; - } - - return is->gdi_plus.init_state == IS_OK; -} - -int __fastcall -patch_OpenGLRenderer_initialize (OpenGLRenderer * this, int edx, PCX_Image * texture) -{ - if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || - ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) - return OpenGLRenderer_initialize (this, __, texture); - - // Initialize GDI+ instead - else { - if (! set_up_gdi_plus ()) - return 2; - if (is->gdi_plus.gp_graphics != NULL) { - is->gdi_plus.DeleteGraphics (is->gdi_plus.gp_graphics); - is->gdi_plus.gp_graphics = NULL; - } - int status = is->gdi_plus.CreateFromHDC (texture->JGL.Image->DC, &is->gdi_plus.gp_graphics); - if (status == 0) { - is->gdi_plus.SetSmoothingMode (is->gdi_plus.gp_graphics, 4); // 4 = SmoothingModeAntiAlias from GdiPlusEnums.h - return 0; - } else - return 2; - } -} - -void __fastcall -patch_OpenGLRenderer_set_color (OpenGLRenderer * this, int edx, unsigned int rgb555) -{ - // Convert rgb555 to rgb888 - unsigned int rgb888 = 0; { - unsigned int mask = 31; - int shift = 3; - for (int n = 0; n < 3; n++) { - rgb888 |= (rgb555 & mask) << shift; - mask <<= 5; - shift += 3; - } - } - - is->ogl_color = (is->ogl_color & 0xFF000000) | rgb888; - OpenGLRenderer_set_color (this, __, rgb555); -} - -void __fastcall -patch_OpenGLRenderer_set_opacity (OpenGLRenderer * this, int edx, unsigned int alpha) -{ - is->ogl_color = (is->ogl_color & 0x00FFFFFF) | (alpha << 24); - OpenGLRenderer_set_opacity (this, __, alpha); -} - -void __fastcall -patch_OpenGLRenderer_set_line_width (OpenGLRenderer * this, int edx, int width) -{ - is->ogl_line_width = width; - OpenGLRenderer_set_line_width (this, __, width); -} - -void __fastcall -patch_OpenGLRenderer_enable_line_dashing (OpenGLRenderer * this) -{ - is->ogl_line_stipple_enabled = true; - OpenGLRenderer_enable_line_dashing (this); -} - -void __fastcall -patch_OpenGLRenderer_disable_line_dashing (OpenGLRenderer * this) -{ - is->ogl_line_stipple_enabled = false; - OpenGLRenderer_disable_line_dashing (this); -} - -void __fastcall -patch_OpenGLRenderer_draw_line (OpenGLRenderer * this, int edx, int x1, int y1, int x2, int y2) -{ - if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || - ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) - OpenGLRenderer_draw_line (this, __, x1, y1, x2, y2); - - else if ((is->gdi_plus.init_state == IS_OK) && (is->gdi_plus.gp_graphics != NULL)) { - void * gp_pen; - int unit_world = 0; // = UnitWorld from gdiplusenums.h - int status = is->gdi_plus.CreatePen1 (is->ogl_color, (float)is->ogl_line_width, unit_world, &gp_pen); - if (status == 0) { - if (is->ogl_line_stipple_enabled) - is->gdi_plus.SetPenDashStyle (gp_pen, 1); // 1 = DashStyleDash from GdiPlusEnums.h - is->gdi_plus.DrawLineI (is->gdi_plus.gp_graphics, gp_pen, x1, y1, x2, y2); - is->gdi_plus.DeletePen (gp_pen); - } - } -} - -int __fastcall -patch_Tile_check_water_for_retreat_on_defense (Tile * this) -{ - Unit * defender = p_bic_data->fighter.defender; - - // Under the standard game rules, defensively retreating onto a water tile is not allowed. Set retreat_blocked to true if "this" is a water - // tile and we're not configured to allow retreating onto water tiles. - bool retreat_blocked; { - if (this->vtable->m35_Check_Is_Water (this)) { - if ( is->current_config.allow_defensive_retreat_on_water - && defender != NULL - && p_bic_data->UnitTypes[defender->Body.UnitTypeID].Unit_Class == UTC_Sea - && ( is->current_config.limit_defensive_retreat_on_water_to_types.len == 0 - || (bool)itable_look_up_or (&is->current_config.limit_defensive_retreat_on_water_to_types, defender->Body.UnitTypeID, 0))) - retreat_blocked = false; - else - retreat_blocked = true; - } else - retreat_blocked = false; - } - - // Check stack limit - if ((! retreat_blocked) && - (defender != NULL) && - ! is_below_stack_limit (this, defender->Body.CivID, defender->Body.UnitTypeID)) - retreat_blocked = true; - - // The return from this call is only used to filter the given tile as a possible retreat destination based on whether it's water or not - return (int)retreat_blocked; -} - -int __fastcall -patch_City_count_airports_for_airdrop (City * this, int edx, enum ImprovementTypeFlags airport_flag) -{ - if (is->current_config.allow_airdrop_without_airport) - return 1; - else - return City_count_improvements_with_flag (this, __, airport_flag); -} - -int __fastcall -patch_Leader_get_cont_city_count_for_worker_req (Leader * this, int edx, int cont_id) -{ - int tr = Leader_get_city_count_on_continent (this, __, cont_id); - if (is->current_config.ai_worker_requirement_percent != 100) - tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; - return tr; -} - -int __fastcall -patch_Leader_get_city_count_for_worker_prod_cap (Leader * this) -{ - int tr = this->Cities_Count; - // Don't scale down the cap since it's pretty low to begin with - if (is->current_config.ai_worker_requirement_percent > 100) - tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; - return tr; -} - -// If "only_improv_id" is >= 0, will only return yields from mills attached to that improv, otherwise returns all yields from all improvs -void -gather_mill_yields (City * city, int only_improv_id, int * out_food, int * out_shields, int * out_commerce) -{ - int food = 0, shields = 0, commerce = 0; - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if ((mill->flags & MF_YIELDS) && - ((only_improv_id < 0) || (mill->improv_id == only_improv_id)) && - can_generate_resource (city->Body.CivID, mill) && - has_active_building (city, mill->improv_id) && - has_resources_required_by_building (city, mill->improv_id)) { - Resource_Type * res = &p_bic_data->ResourceTypes[mill->resource_id]; - food += res->Food; - shields += res->Shield; - commerce += res->Commerce; - } - } - *out_food = food; - *out_shields = shields; - *out_commerce = commerce; -} - -int __fastcall -patch_City_calc_tile_yield_while_gathering (City * this, int edx, YieldKind kind, int tile_x, int tile_y) -{ - int tr = City_calc_tile_yield_at (this, __, kind, tile_x, tile_y); - - // Include yields from generated resources - if ((this->Body.X == tile_x) && (this->Body.Y == tile_y)) { - int mill_food, mill_shields, mill_commerce; - gather_mill_yields (this, -1, &mill_food, &mill_shields, &mill_commerce); - if (kind == YK_FOOD) tr += mill_food; - else if (kind == YK_SHIELDS) tr += mill_shields; - else if (kind == YK_COMMERCE) tr += mill_commerce; - - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - int bonus_food = 0, bonus_shields = 0, bonus_gold = 0; - calculate_city_center_district_bonus (this, &bonus_food, &bonus_shields, &bonus_gold); - if (kind == YK_FOOD) tr += bonus_food; - else if (kind == YK_SHIELDS) tr += bonus_shields; - else if (kind == YK_COMMERCE) tr += bonus_gold; - } - } - - return tr; -} - -bool __fastcall -patch_Leader_record_export (Leader * this, int edx, int importer_civ_id, int resource_id) -{ - bool exported = Leader_record_export (this, __, importer_civ_id, resource_id); - if (exported && - (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill - is->must_recompute_resources_for_mill_inputs = true; - return exported; -} - -bool __fastcall -patch_Leader_erase_export (Leader * this, int edx, int importer_civ_id, int resource_id) -{ - bool erased = Leader_erase_export (this, __, importer_civ_id, resource_id); - if (erased && - (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill - is->must_recompute_resources_for_mill_inputs = true; - return erased; -} - -int __fastcall -patch_Sprite_draw_improv_img_on_city_form (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int tr = Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); - - int generated_resources[16]; - int generated_resource_count = 0; - for (int n = 0; (n < is->current_config.count_mills) && (generated_resource_count < ARRAY_LEN (generated_resources)); n++) { - struct mill * mill = &is->current_config.mills[n]; - if ((mill->improv_id == is->drawing_icons_for_improv_id) && - ((mill->flags & MF_SHOW_BONUS) || (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus)) && - (! ((mill->flags & MF_HIDE_NON_BONUS) && (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus))) && - can_generate_resource (p_city_form->CurrentCity->Body.CivID, mill) && - has_active_building (p_city_form->CurrentCity, mill->improv_id) && - has_resources_required_by_building (p_city_form->CurrentCity, mill->improv_id)) - generated_resources[generated_resource_count++] = mill->resource_id; - } - - if ((generated_resource_count > 0) && (is->resources_sheet != NULL) && (is->resources_sheet->JGL.Image != NULL) && (TransparentBlt != NULL)) { - JGL_Image * jgl_canvas = canvas->JGL.Image, - * jgl_sheet = is->resources_sheet->JGL.Image; - - HDC canvas_dc = jgl_canvas->vtable->acquire_dc (jgl_canvas); - if (canvas_dc != NULL) { - HDC sheet_dc = jgl_sheet->vtable->acquire_dc (jgl_sheet); - if (sheet_dc != NULL) { - - for (int n = 0; n < generated_resource_count; n++) { - int icon_id = p_bic_data->ResourceTypes[generated_resources[n]].IconID, - sheet_row = icon_id / 6, - sheet_col = icon_id % 6; - - int dy = (n * 160 / not_below (1, generated_resource_count - 1) + 5) / 10; - TransparentBlt (canvas_dc, // dest DC - pixel_x + 15, pixel_y + dy, 24, 24, // dest x, y, width, height - sheet_dc, // src DC - 9 + 50*sheet_col, 9 + 50*sheet_row, 33, 33, // src x, y, width, height - 0xFF00FF); // transparent color (RGB) - } - - jgl_sheet->vtable->release_dc (jgl_sheet, __, 1); - } - jgl_canvas->vtable->release_dc (jgl_canvas, __, 1); - } - } - return tr; -} - -void __cdecl -patch_draw_improv_icons_on_city_screen (Base_List_Control * control, int improv_id, int item_index, int offset_x, int offset_y) -{ - is->drawing_icons_for_improv_id = improv_id; - draw_improv_icons_on_city_screen (control, improv_id, item_index, offset_x, offset_y); - is->drawing_icons_for_improv_id = -1; -} - -int __fastcall -patch_City_get_tourism_amount_to_draw (City * this, int edx, int improv_id) -{ - is->tourism_icon_counter = 0; - - int mill_food, mill_shields, mill_commerce; - gather_mill_yields (this, improv_id, &mill_food, &mill_shields, &mill_commerce); - int combined_commerce = mill_commerce + City_get_tourism_amount (this, __, improv_id); - - is->convert_displayed_tourism_to_food = mill_food; - is->convert_displayed_tourism_to_shields = mill_shields; - is->combined_tourism_and_mill_commerce = combined_commerce; - return int_abs (mill_food) + int_abs (mill_shields) + int_abs (combined_commerce); -} - -int __fastcall -patch_Sprite_draw_tourism_gold (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - // Replace the yield sprite we're drawing with food or a shield if needed. - Sprite * sprite = NULL; { - if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food)) { - if (is->convert_displayed_tourism_to_food >= 0) - sprite = &p_city_form->City_Icons_Images.Icon_15_Food; - else { - init_red_food_icon (); - if (is->red_food_icon_state == IS_OK) - sprite = &is->red_food_icon; - } - } else if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food) + int_abs (is->convert_displayed_tourism_to_shields)) - sprite = (is->convert_displayed_tourism_to_shields >= 0) ? &p_city_form->City_Icons_Images.Icon_13_Shield : &p_city_form->City_Icons_Images.Icon_05_Shield_Outcome; - else if (is->combined_tourism_and_mill_commerce < 0) - sprite = &p_city_form->City_Icons_Images.Icon_17_Gold_Outcome; - else - sprite = this; - } - - int tr = 0; // return value is not used by caller - if (sprite != NULL) - tr = Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, color_table); - is->tourism_icon_counter++; - return tr; -} - -Unit * __fastcall -patch_Leader_spawn_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) -{ - int spawn_x = tile_x, - spawn_y = tile_y; - - if (is->current_config.enable_districts) { - UnitType * type = &p_bic_data->UnitTypes[type_id]; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities) { - City * spawn_city = city_at (tile_x, tile_y); - if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { - int district_x, district_y; - Tile * district_tile = get_completed_district_tile_for_city (spawn_city, AERODROME_DISTRICT_ID, &district_x, &district_y); - if ((district_tile != NULL) && (district_tile != p_null_tile) && - (district_tile->Territory_OwnerID == this->ID) && - is_below_stack_limit (district_tile, this->ID, type_id)) { - spawn_x = district_x; - spawn_y = district_y; - } - } - } - - if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities) { - City * spawn_city = city_at (tile_x, tile_y); - if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { - int district_x, district_y; - Tile * district_tile = get_completed_district_tile_for_city (spawn_city, PORT_DISTRICT_ID, &district_x, &district_y); - if ((district_tile != NULL) && (district_tile != p_null_tile) && - (district_tile->Territory_OwnerID == this->ID) && - is_below_stack_limit (district_tile, this->ID, type_id)) { - spawn_x = district_x; - spawn_y = district_y; - } - } - } - } - - Unit * tr = Leader_spawn_unit (this, __, type_id, spawn_x, spawn_y, barb_tribe_id, id, param_6, leader_kind, race_id); - if (tr != NULL) - change_unit_type_count (this, type_id, 1); - return tr; -} - -Unit * __fastcall -patch_Leader_spawn_captured_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) -{ - Unit * tr = patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); - if ((tr != NULL) && is->moving_unit_to_adjacent_tile) - is->temporarily_disallow_lethal_zoc = true; - return tr; -} - -void __fastcall -patch_Leader_enter_new_era (Leader * this, int edx, bool param_1, bool no_online_sync) -{ - Leader_enter_new_era (this, __, param_1, no_online_sync); - apply_era_specific_names (this); -} - -char * __fastcall -patch_Leader_get_player_title_for_intro_popup (Leader * this) -{ - // Normally the era-specific names are applied later, after game loading is finished, but in this case we apply the player's names ahead of - // time so they appear on the intro popup. "this" will always refer to the human player in this call. - apply_era_specific_names (this); - return Leader_get_title (this); -} - -void __fastcall -patch_City_spawn_unit_if_done (City * this) -{ - bool skip_spawn = false; - - // Apply unit limit. If this city's owner has reached the limit for the unit type it's building then force it to build something else. - int available; - if ((this->Body.Order_Type == COT_Unit) && - get_available_unit_count (&leaders[this->Body.CivID], this->Body.Order_ID, &available) && - (available <= 0)) { - int limited_unit_type_id = this->Body.Order_ID; - - if (*p_human_player_bits & 1<Body.CivID) { - // Find another type ID to build instead of the limited one - int replacement_type_id = -1; { - int limited_unit_strat = p_bic_data->UnitTypes[limited_unit_type_id].AI_Strategy, - shields_in_box = this->Body.StoredProduction; - UnitType * replacement_type; - for (int can_type_id = 0; can_type_id < p_bic_data->UnitTypeCount; can_type_id++) - if (patch_City_can_build_unit (this, __, can_type_id, 1, 0, 0)) { - UnitType * candidate_type = &p_bic_data->UnitTypes[can_type_id]; - - // If we haven't found a replacement yet, use this one - if (replacement_type_id < 0) { - replacement_type_id = can_type_id; - replacement_type = candidate_type; - - // Keep the prev replacement if it doesn't waste shields but this candidate would - } else if ((replacement_type->Cost >= shields_in_box) && (candidate_type->Cost < shields_in_box)) - continue; - - // Keep the prev if it shares an AI strategy with the limited unit but this candidate doesn't - else if (((replacement_type->AI_Strategy & limited_unit_strat) != 0) && - ((candidate_type ->AI_Strategy & limited_unit_strat) == 0)) - continue; - - // At this point we know switching to the candidate would not cause us to waste shields and would not - // give us a worse match role-wise to the original limited unit. So pick it if it's better somehow, - // either a better role match or more expensive. - else if ((candidate_type->Cost > replacement_type->Cost) || - (((replacement_type->AI_Strategy & limited_unit_strat) == 0) && - ((candidate_type ->AI_Strategy & limited_unit_strat) != 0))) { - replacement_type_id = can_type_id; - replacement_type = candidate_type; - } - } - } - - if (replacement_type_id >= 0) { - City_set_production (this, __, COT_Unit, replacement_type_id, false); - if (this->Body.CivID == p_main_screen_form->Player_CivID) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, this->Body.CityName, -1, -1); - set_popup_str_param (1, p_bic_data->UnitTypes[limited_unit_type_id].Name, -1, -1); - int limit = -1; - get_unit_limit (&leaders[this->Body.CivID], limited_unit_type_id, &limit); - set_popup_int_param (2, limit); - set_popup_str_param (3, p_bic_data->UnitTypes[replacement_type_id].Name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_LIMITED_UNIT_CHANGE", -1, 0, 0, 0); - int response = patch_show_popup (popup, __, 0, 0); - if (response == 0) - *p_zoom_to_city_after_update = true; - } - } - - } else { - City_Order order; - patch_City_ai_choose_production (this, __, &order); - City_set_production (this, __, order.OrderType, order.OrderID, false); - } - - // If the player changed production to something other than a unit, don't spawn anything - if (this->Body.Order_Type != COT_Unit) - skip_spawn = true; - - // Just as a final check, if we weren't able to switch production off the limited unit, prevent it from being spawned so the limit - // doesn't get violated. - if ((this->Body.Order_Type == COT_Unit) && (this->Body.Order_ID == limited_unit_type_id)) - skip_spawn = true; - } - - // Check district requirements for air and naval units - if ((! skip_spawn) && (this->Body.Order_Type == COT_Unit) && is->current_config.enable_districts) { - int unit_id = this->Body.Order_ID; - UnitType * type = &p_bic_data->UnitTypes[unit_id]; - bool needs_district = false; - int required_district_id = -1; - - // Air units require aerodrome - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (this, AERODROME_DISTRICT_ID))) { - needs_district = true; - required_district_id = AERODROME_DISTRICT_ID; - } - // Naval units require port - else if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (this, PORT_DISTRICT_ID))) { - needs_district = true; - required_district_id = PORT_DISTRICT_ID; - } - - if (needs_district) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - - // For AI, redirect to a safe fallback and queue the missing district. - // For humans, this late hook should only veto the spawn and show a warning, - // otherwise the city gets switched off the intended build with no unit spawned. - if (! is_human) { - mark_city_needs_district (this, required_district_id); - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (this, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - // Show message to human player - if (is_human && (this->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[160]; - char const * unit_name = type->Name; - char const * district_name = is->district_configs[required_district_id].name; - snprintf (msg, sizeof msg, "%s %s %s", unit_name, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_name); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (this->Body.X, this->Body.Y, msg, true); - } - - skip_spawn = true; - } - } - - if (! skip_spawn) - City_spawn_unit_if_done (this); -} - -void __fastcall -patch_Leader_upgrade_all_units (Leader * this, int edx, int type_id) -{ - is->penciled_in_upgrade_count = 0; - Leader_upgrade_all_units (this, __, type_id); -} - -void __fastcall -patch_Main_Screen_Form_upgrade_all_units (Main_Screen_Form * this, int edx, int type_id) -{ - is->penciled_in_upgrade_count = 0; - Main_Screen_Form_upgrade_all_units (this, __, type_id); -} - -bool __fastcall -patch_Unit_can_perform_upgrade_all (Unit * this, int edx, int unit_command_value) -{ - bool base = patch_Unit_can_perform_command (this, __, unit_command_value); - - // Deal with unit limits. If the unit type we're upgrading to is limited, we need to pencil in the upgrade to make sure that we don't queue up - // so many upgrades that we exceed the limit. - City * city; - int upgrade_id, available; - if (base && - (is->current_config.unit_limits.len > 0) && - (NULL != (city = city_at (this->Body.X, this->Body.Y))) && - (0 <= (upgrade_id = City_get_upgraded_type_id (city, __, this->Body.UnitTypeID))) && - get_available_unit_count (&leaders[this->Body.CivID], upgrade_id, &available)) { - - // Find penciled in upgrade. Add a new one if we don't already have one. - struct penciled_in_upgrade * piu = NULL; { - for (int n = 0; n < is->penciled_in_upgrade_count; n++) - if (is->penciled_in_upgrades[n].unit_type_id == upgrade_id) { - piu = &is->penciled_in_upgrades[n]; - break; - } - if (piu == NULL) { - reserve (sizeof is->penciled_in_upgrades[0], (void **)&is->penciled_in_upgrades, &is->penciled_in_upgrade_capacity, is->penciled_in_upgrade_count); - piu = &is->penciled_in_upgrades[is->penciled_in_upgrade_count]; - is->penciled_in_upgrade_count += 1; - piu->unit_type_id = upgrade_id; - piu->count = 0; - } - } - - // If we can have more units of the type we're upgrading to, pencil in another upgrade and return true. Otherwise return false so this - // unit isn't considered one of the upgradable ones. - if (piu->count < available) { - piu->count += 1; - return true; - } else - return false; - - } else - return base; -} - -void __fastcall -patch_Fighter_animate_start_of_combat (Fighter * this, int edx, Unit * attacker, Unit * defender) -{ - // Temporarily clear the attacker retreat eligibility flag when needed so naval units are rotated and animated properly. Normally the game - // does not use ranged animations when the attacker can retreat and, worse, not using ranged anims means it also ignores the - // rotate-before-attack setting. - bool restore_attacker_retreat_eligibility = false; - if ((is->current_config.sea_retreat_rules != RR_STANDARD) && - (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Sea) && - Unit_has_ability (attacker, __, UTA_Ranged_Attack_Animation) && - Unit_has_ability (defender, __, UTA_Ranged_Attack_Animation) && - this->attacker_eligible_to_retreat) { - this->attacker_eligible_to_retreat = false; - restore_attacker_retreat_eligibility = true; - } - - Fighter_animate_start_of_combat (this, __, attacker, defender); - - if (restore_attacker_retreat_eligibility) - this->attacker_eligible_to_retreat = true; -} - -Unit * __fastcall -patch_Leader_spawn_unit_from_building (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) -{ - int available; - if (get_available_unit_count (this, type_id, &available) && (available <= 0)) - return NULL; - else - return patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); -} - -int __fastcall -patch_City_count_improvs_enabling_upgrade (City * this, int edx, enum ImprovementTypeFlags flag) -{ - return is->current_config.allow_upgrades_in_any_city ? 1 : City_count_improvements_with_flag (this, __, flag); -} - -City * __fastcall -patch_Leader_create_city_from_hut (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_POPPED_FROM_HUT); - return tr; -} - -City * __fastcall -patch_Leader_create_city_for_ai_respawn (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_PLACED_FOR_AI_RESPAWN); - return tr; -} - -City * __fastcall -patch_Leader_create_city_for_founding (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_FOUNDED); - return tr; -} - -City * __fastcall -patch_Leader_create_city_for_scenario (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_PLACED_FOR_SCENARIO); - return tr; -} - -City * -find_city_to_inherit_shared_small_wonder (Leader * leader, int wonder_improv_id) -{ - if ((leader == NULL) || - (! is->current_config.enable_districts) || - (! is->current_config.enable_wonder_districts) || - (! is->current_config.cities_with_mutual_district_receive_wonders)) - return NULL; - - FOR_CITIES_OF (coi, leader->ID) { - City * city = coi.city; - if ((city == NULL) || (! patch_City_has_improvement (city, __, wonder_improv_id, false))) - continue; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - Tile * tile = wai.tile; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if ((info == NULL) || (info->state != WDS_COMPLETED)) - continue; - - int nearby_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); - if (nearby_improv_id == wonder_improv_id) - return city; - } - } - - return NULL; -} - -void -collect_small_wonders_present_in_city (City * city, int * lost_small_wonders, int * lost_small_wonder_count, int max_lost_small_wonders) -{ - if ((city == NULL) || - (lost_small_wonders == NULL) || - (lost_small_wonder_count == NULL) || - (max_lost_small_wonders <= 0)) - return; - - *lost_small_wonder_count = 0; - - if (! is->current_config.enable_districts || - ! is->current_config.enable_wonder_districts || - ! is->current_config.cities_with_mutual_district_receive_wonders) - return; - - for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) == 0) - continue; - if (! patch_City_has_improvement (city, __, improv_id, false)) - continue; - if (*lost_small_wonder_count >= max_lost_small_wonders) - break; - lost_small_wonders[(*lost_small_wonder_count)++] = improv_id; - } -} - -void -reassign_shared_small_wonder_owners_after_city_loss (Leader * leader, int const * lost_small_wonders, int lost_small_wonder_count) -{ - if ((! is->current_config.enable_districts) || - (leader == NULL) || - (! is->current_config.enable_wonder_districts) || - (! is->current_config.cities_with_mutual_district_receive_wonders) || - (lost_small_wonders == NULL) || - (lost_small_wonder_count <= 0)) - return; - - for (int n = 0; n < lost_small_wonder_count; n++) { - int improv_id = lost_small_wonders[n]; - if ((improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) - continue; - - if (leader->Small_Wonders[improv_id] != -1) - continue; - - // Vanilla clears Leader.Small_Wonders when the recorded owner city loses the building during - // capture. Only repair the small wonders that were actually present in the lost city before - // capture, and if another city of the same civ still legitimately shares the wonder district, - // promote that city to be the new canonical owner so the small wonder's effects still work. - City * replacement = find_city_to_inherit_shared_small_wonder (leader, improv_id); - if (replacement != NULL) - leader->Small_Wonders[improv_id] = replacement->Body.ID; - } -} - -bool __fastcall -patch_Leader_do_capture_city (Leader * this, int edx, City * city, bool involuntary, bool converted) -{ - Leader * previous_owner = &leaders[city->Body.CivID]; - int lost_small_wonders[32]; - int lost_small_wonder_count; - - // Record which small wonders were physically present in the city before capture so any - // post-capture ownership repair only touches wonders actually affected. - collect_small_wonders_present_in_city (city, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); - - is->currently_capturing_city = city; - on_lose_city (previous_owner, city, converted ? CLR_CONVERTED : (involuntary ? CLR_CONQUERED : CLR_TRADED)); - bool tr = Leader_do_capture_city (this, __, city, involuntary, converted); - - // The game clears the losing civ's canonical Small_Wonders owner when the recorded city loses - // the building. Reassign that ownership here if another same-civ city still legitimately shares the wonder district. - if (is->current_config.enable_districts && - is->current_config.enable_wonder_districts && - is->current_config.cities_with_mutual_district_receive_wonders && - lost_small_wonder_count > 0) { - reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); - } - - on_gain_city (this, city, converted ? CGR_CONVERTED : (involuntary ? CGR_CONQUERED : CGR_TRADED)); - is->currently_capturing_city = NULL; - return tr; -} - -void __fastcall -patch_City_raze (City * this, int edx, int civ_id_responsible, bool checking_elimination) -{ - Leader * previous_owner = &leaders[this->Body.CivID]; - int lost_small_wonders[32]; - int lost_small_wonder_count; - - collect_small_wonders_present_in_city (this, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); - on_lose_city (previous_owner, this, CLR_DESTROYED); - City_raze (this, __, civ_id_responsible, checking_elimination); - - if (lost_small_wonder_count > 0) - reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); - - // Delete the extra improvement bits records for this city - City_Improvements * improv_lists[2] = {&this->Body.Improvements_1, &this->Body.Improvements_2}; - for (int n = 0; n < ARRAY_LEN (improv_lists); n++) { - City_Improvements * improv_list = improv_lists[n]; - byte * extra_bits; - if (itable_look_up (&is->extra_city_improvs, (int)improv_list, (int *)&extra_bits)) { - free (extra_bits); - itable_remove (&is->extra_city_improvs, (int)improv_list); - } - } -} - -void __fastcall -patch_City_draw_hud_icon (City * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y) -{ - Leader * owner = &leaders[this->Body.CivID]; - int restore_capital = owner->CapitalID; - - // Temporarily set this city as the capital if it has an extra palace so it gets the capital star icon - if ((is->current_config.ai_multi_city_start > 1) && - ((*p_human_player_bits & (1 << owner->ID)) == 0) && - has_extra_palace (this)) - owner->CapitalID = this->Body.ID; - - City_draw_hud_icon (this, __, canvas, pixel_x, pixel_y); - owner->CapitalID = restore_capital; -} - -bool __fastcall -patch_City_has_hud_icon (City * this) -{ - return City_has_hud_icon (this) - || ( (is->current_config.ai_multi_city_start > 1) - && ((*p_human_player_bits & (1 << this->Body.CivID)) == 0) - && has_extra_palace (this)); -} - -void __fastcall -patch_City_draw_on_map (City * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) -{ - Leader * owner = &leaders[this->Body.CivID]; - int restore_capital = owner->CapitalID; - - if (is->current_config.do_not_make_capital_cities_appear_larger) - owner->CapitalID = -1; - - // Temporarily set this city as the capital if it has an extra palace so it gets drawn with the next larger size - else if ((is->current_config.ai_multi_city_start > 1) && - ((*p_human_player_bits & (1 << owner->ID)) == 0) && - has_extra_palace (this)) - owner->CapitalID = this->Body.ID; - - City_draw_on_map (this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); - owner->CapitalID = restore_capital; -} - -// Writes a string to replace "Wake" or "Activate" on the right-click menu entry for the given unit. Some units might not have a replacement, in which -// case the function writes nothing and returns false. The string is written to out_str which must point to a buffer of at least str_capacity bytes. -bool -get_menu_verb_for_unit (Unit * unit, char * out_str, int str_capacity) -{ - struct state_desc { - enum c3x_label label; - bool is_doing_worker_job; - } state_descs[35] = { - {CL_IDLE , false}, // [No state] = 0x0 - {CL_FORTIFIED , false}, // Fortifying = 0x1 - {CL_MINING , true }, // Build_Mines = 0x2 - {CL_IRRIGATING , true }, // Irrigate = 0x3 - {CL_BUILDING_FORTRESS , true }, // Build_Fortress = 0x4 - {CL_BUILDING_ROAD , true }, // Build_Road = 0x5 - {CL_BUILDING_RAILROAD , true }, // Build_Railroad = 0x6 - {CL_PLANTING_FOREST , true }, // Plant_Forest = 0x7 - {CL_CLEARING_FOREST , true }, // Clear_Forest = 0x8 - {CL_CLEARING_WETLANDS , true }, // Clear_Wetlands = 0x9 - {CL_CLEARING_DAMAGE , true }, // Clear_Damage = 0xA - {CL_BUILDING_AIRFIELD , true }, // Build_Airfield = 0xB - {CL_BUILDING_RADAR_TOWER, true }, // Build_Radar_Tower = 0xC - {CL_BUILDING_OUTPOST , true }, // Build_Outpost = 0xD - {CL_BUILDING_BARRICADE , true }, // Build_Barricade = 0xE - {CL_INTERCEPTING , false}, // Intercept = 0xF - {CL_MOVING , false}, // Go_To = 0x10 - {CL_BUILDING_ROAD , true }, // Road_To_Tile = 0x11 - {CL_BUILDING_RAILROAD , true }, // Railroad_To_Tile = 0x12 - {CL_BUILDING_COLONY , true }, // Build_Colony = 0x13 - {CL_AUTOMATED , true }, // Auto_Irrigate = 0x14 - {CL_AUTOMATED , true }, // Build_Trade_Routes = 0x15 - {CL_AUTOMATED , true }, // Auto_Clear_Forest = 0x16 - {CL_AUTOMATED , true }, // Auto_Clear_Swamp = 0x17 - {CL_AUTOMATED , true }, // Auto_Clear_Pollution = 0x18 - {CL_AUTOMATED , true }, // Auto_Save_City_Tiles = 0x19 - {CL_EXPLORING , false}, // Explore = 0x1A - {CL_IN_STATE_27 , false}, // ? = 0x1B - {CL_IN_STATE_28 , false}, // Fleeing = 0x1C - {CL_IN_STATE_29 , false}, // ? = 0x1D - {CL_IN_STATE_30 , false}, // ? = 0x1E - {CL_BOMBARDING , false}, // Auto_Bombard = 0x1F - {CL_BOMBARDING , false}, // Auto_Air_Bombard = 0x20 - {CL_BOMBARDING , false}, // Auto_Precision_Strike = 0x21 - {CL_IDLE , false}, // Exhausted = 0x22 - }; - enum UnitStateType state = unit->Body.UnitState; - struct state_desc const * desc; - if ((state >= 0) && (state < ARRAY_LEN (state_descs)) && (desc = &state_descs[state]) && (desc->label >= 0) && (desc->label < COUNT_C3X_LABELS)) { - enum c3x_label label = desc->label; - Unit * container; - if (((label == CL_IDLE) || (label == CL_MOVING) || (label == CL_IN_STATE_29) || desc->is_doing_worker_job) && unit->Body.automated) - label = CL_AUTOMATED; - else if ((label == CL_FORTIFIED) && (NULL != (container = get_unit_ptr (unit->Body.Container_Unit))) && ! Unit_has_ability (container, __, UTA_Army)) - label = CL_TRANSPORTED; - else if ((label == CL_FORTIFIED) && (unit->Body.Status & (USF_SENTRY | USF_SENTRY_ENEMY_ONLY))) - label = CL_SENTRY; - else if ((label == CL_MINING) && is->current_config.enable_districts) { - - // Check if this unit is actually building a district instead of a mine - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - struct district_instance * inst = get_district_instance (tile); - if ((tile != NULL) && (tile != p_null_tile) && inst != NULL) { - char const * district_name = is->district_configs[inst->district_id].name; - snprintf (out_str, str_capacity, "%s %s", is->c3x_labels[CL_BUILDING], district_name); - out_str[str_capacity - 1] = '\0'; - return true; - } - } - - strncpy (out_str, is->c3x_labels[label], str_capacity); - out_str[str_capacity - 1] = '\0'; - return true; - } else - return false; -} - -void __fastcall -patch_MenuUnitItem_write_text_to_temp_str (MenuUnitItem * this) -{ - MenuUnitItem_write_text_to_temp_str (this); - - Unit * unit = this->unit; - char repl_verb[32]; - if (is->current_config.describe_states_of_units_on_menu && - (unit->Body.CivID == p_main_screen_form->Player_CivID) && - (Unit_get_containing_army (unit) == NULL) && - get_menu_verb_for_unit (unit, repl_verb, sizeof repl_verb)) { - char * verb = (unit->Body.UnitState == UnitState_Fortifying) ? (*p_labels)[LBL_WAKE] : (*p_labels)[LBL_ACTIVATE]; - char * verb_str_start = strstr (temp_str, verb); - if (verb_str_start != NULL) { - char s[500]; - char * verb_str_end = verb_str_start + strlen (verb); - snprintf (s, sizeof s, "%.*s%s%s", verb_str_start - temp_str, temp_str, repl_verb, verb_str_end); - s[(sizeof s) - 1] = '\0'; - strncpy (temp_str, s, sizeof s); - } - } -} - -void __fastcall -patch_Tile_m74_Set_Square_Type_for_hill_gen (Tile * this, int edx, enum SquareTypes sq, int tile_x, int tile_y) -{ - if ((sq == SQ_Volcano) && is->current_config.do_not_generate_volcanos) - sq = SQ_Mountains; - this->vtable->m74_Set_Square_Type (this, __, sq, tile_x, tile_y); -} - -void __fastcall -patch_Map_place_scenario_things (Map * this) -{ - is->is_placing_scenario_things = true; - - Map_place_scenario_things (this); - - // If there are any mills in the config then recompute yields & happiness in all cities. This must be done because we avoid doing this as - // mills are added to cities while placing scenario things. - if (is->current_config.count_mills > 0) - for (int n = 0; n <= p_cities->LastIndex; n++) { - City * city = get_city_ptr (n); - if (city != NULL) - patch_City_recompute_yields_and_happiness (city); - } - - if (is->current_config.enable_districts || - is->current_config.enable_natural_wonders || - is->current_config.enable_named_tiles) - load_scenario_districts_from_file (); - - if (is->current_config.enable_natural_wonders && - is->current_config.add_natural_wonders_to_scenarios_if_none) { - bool any_natural_wonders = false; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst != NULL) && - (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) { - any_natural_wonders = true; - break; - } - } - if (! any_natural_wonders) - place_natural_wonders_on_map (); - } - is->is_placing_scenario_things = false; -} - -void -on_open_advisor (AdvisorKind kind) -{ - recompute_resources_if_necessary (); -} - -bool __fastcall patch_Advisor_Base_Form_domestic_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_DOMESTIC); return Advisor_Base_Form_domestic_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_trade_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_TRADE) ; return Advisor_Base_Form_trade_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_military_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_MILITARY); return Advisor_Base_Form_military_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_foreign_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_FOREIGN) ; return Advisor_Base_Form_foreign_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_cultural_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_CULTURAL); return Advisor_Base_Form_cultural_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_science_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_SCIENCE) ; return Advisor_Base_Form_science_m95 (this); } - -void __fastcall -patch_Main_Screen_Form_open_quick_build_chooser (Main_Screen_Form * this, int edx, City * city, int mouse_x, int mouse_y) -{ - recompute_resources_if_necessary (); - Main_Screen_Form_open_quick_build_chooser (this, __, city, mouse_x, mouse_y); -} - -int __fastcall -patch_Context_Menu_get_selected_item_on_unit_rcm (Context_Menu * this) -{ - // In the base game, this method returns -1 for any disabled item which prevents the player from clicking those. We want players to be able to - // click unit items which have been disabled by the mod so they can interrupt the queued actions of units that have no moves left. - int index = this->Selected_Item; - if (index >= 0) { - if (is->current_config.enable_named_tiles && is->named_tile_menu_active) { - Context_Menu_Item * item = &this->Items[index]; - if (item->Menu_Item_ID == NAMED_TILE_MENU_ID) { - handle_named_tile_menu_selection (); - return -1; - } - } - bool is_enabled = (this->Items[index].Status & 2) == 0; - bool is_unit_item = (this->Items[index].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount)) >= 0; - return (is_enabled || is_unit_item) ? index : -1; - } - return -1; -} - -int __fastcall -patch_Tile_check_water_to_block_pollution (Tile * this) -{ - if (this->vtable->m35_Check_Is_Water (this)) - return 1; - else if (is->current_config.do_not_pollute_impassable_tiles) { - enum SquareTypes terrain_type = this->vtable->m50_Get_Square_BaseType (this); - return p_bic_data->TileTypes[terrain_type].Flags.Impassable; - } else - return 0; -} - -void __fastcall -patch_Tile_set_flag_for_eruption_damage (Tile * this, int edx, int param_1, int param_2, int x, int y) -{ - if (is->current_config.enable_districts) { - struct district_instance * inst = get_district_instance (this); - if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { - // District found - handle removal - int district_id = inst->district_id; - - // Notify human player if this tile is in their territory - int territory_owner = this->vtable->m38_Get_Territory_OwnerID (this); - if (territory_owner == p_main_screen_form->Player_CivID) { - char msg[160]; - char const * district_name = is->district_configs[district_id].name; - snprintf (msg, sizeof msg, "%s %s", district_name, is->c3x_labels[CL_DISTRICT_DESTROYED_BY_VOLCANO]); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (x, y, msg, true); - } - - // Remove the district - handle_district_removed (this, district_id, x, y, false); - - // Clear the mine flags - this->vtable->m62_Set_Tile_BuildingID (this, __, -1); - this->vtable->m51_Unset_Tile_Flags (this, __, 0, TILE_FLAG_MINE, x, y); - } - } - - // Apply the normal eruption damage (lava flag) if allowed - if (! (is->current_config.do_not_pollute_impassable_tiles && - p_bic_data->TileTypes[this->vtable->m50_Get_Square_BaseType (this)].Flags.Impassable)) - this->vtable->m56_Set_Tile_Flags (this, __, param_1, param_2, x, y); -} - -bool __fastcall -patch_City_confirm_production_switch (City * this, int edx, int order_type, int order_id) -{ - bool tr = City_confirm_production_switch (this, __, order_type, order_id); - if (tr && - (order_type == COT_Improvement) && (order_id >= 0) && (order_id < p_bic_data->ImprovementsCount) && - (this->Body.CivID == p_main_screen_form->Player_CivID) && - is->current_config.warn_when_chosen_building_would_replace_another) { - Improvement * improv = &p_bic_data->Improvements[order_id]; - if (improv->ImprovementFlags & ITF_Replaces_Other_Buildings) { - Improvement * replaced = NULL; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * other = &p_bic_data->Improvements[n]; - if ((other->ImprovementFlags & ITF_Replaces_Other_Buildings) && - patch_City_has_improvement (this, __, n, false)) { - replaced = other; - break; - } - } - if (replaced != NULL) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, improv->Name.S, -1, -1); - set_popup_str_param (1, replaced->Name.S, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARN_ABOUT_BUILDING_REPLACEMENT", -1, 0, 0, 0); - if (patch_show_popup (popup, __, 0, 0) == 1) - return false; - } - } - } - return tr; -} - -byte const c3x_save_segment_bookend[4] = {0x22, 'C', '3', 'X'}; - -// Writes a string to the buffer and pads the end so it's four-byte aligned (assuming the existing contents is already so aligned). -void -serialize_aligned_text (char const * text, struct buffer * b) -{ - int len = strlen (text); - if (len > 0) { - int padded_len = (len + 4) & ~3; // +1 for null terminator then +3 & ~3 for alignment - byte * p = buffer_allocate (b, padded_len); - strcpy (p, text); - for (int n = 0; n < padded_len - len; n++) - p[len + n] = (byte)0; - } -} - -void * __fastcall -patch_MappedFile_open_to_load_game (MappedFile * this, int edx, char * file_name, int sequential_access) -{ - void * tr = MappedFile_open (this, __, file_name, sequential_access); - if (tr != NULL) - is->accessing_save_file = this; - return tr; -} - -void * __fastcall -patch_MappedFile_create_file_to_save_game (MappedFile * this, int edx, LPCSTR file_path, unsigned file_size, int is_shared) -{ - // Determine if we're currently applying settler perfume to any AI player - bool any_current_settler_perfume = false; - if (is->current_config.ai_settler_perfume_on_founding != 0) { - int duration = is->current_config.ai_settler_perfume_on_founding_duration; - for (int n = 0; n < 32; n++) { - int last_founding_turn = is->turn_no_of_last_founding_for_settler_perfume[n]; - if ((last_founding_turn != -1) && ((*p_current_turn_no - last_founding_turn) < duration)) - any_current_settler_perfume = true; - } - } - - // Assemble mod save data - struct buffer mod_data = {0}; { - if (is->extra_defensive_bombards.len > 0) { - serialize_aligned_text ("extra_defensive_bombards", &mod_data); - itable_serialize (&is->extra_defensive_bombards, &mod_data); - } - if (is->airdrops_this_turn.len > 0) { - serialize_aligned_text ("airdrops_this_turn", &mod_data); - itable_serialize (&is->airdrops_this_turn, &mod_data); - } - if (is->unit_transport_ties.len > 0) { - serialize_aligned_text ("unit_transport_ties", &mod_data); - itable_serialize (&is->unit_transport_ties, &mod_data); - } - if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && is->waiting_units.len > 0) { - serialize_aligned_text ("waiting_units", &mod_data); - itable_serialize (&is->waiting_units, &mod_data); - } - if ((p_bic_data->ImprovementsCount > 256) && (p_cities->Cities != NULL) && (is->extra_city_improvs.len > 0)) { - serialize_aligned_text ("extra_city_improvs", &mod_data); - int extra_improv_count = p_bic_data->ImprovementsCount - 256; - *(int *)buffer_allocate (&mod_data, sizeof(int)) = extra_improv_count; - - int count_entries = 0; { - for (int n = 0; n <= p_cities->LastIndex; n++) { - City_Body * body = p_cities->Cities[n].City; - if ((body != NULL) && ((int)body != offsetof (City, Body))) { - int unused; - if (itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_1, &unused) || - itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_2, &unused)) - count_entries++; - } - } - } - *(int *)buffer_allocate (&mod_data, sizeof(int)) = count_entries; - - int ints_per_list = (extra_improv_count + 31) / 32; - int bytes_per_list = (extra_improv_count + 7) / 8; - for (int n = 0; n <= p_cities->LastIndex; n++) { - City_Body * body = p_cities->Cities[n].City; - if ((body != NULL) && ((int)body != offsetof (City, Body))) { - byte * extra_bit_lists[2]; - extra_bit_lists[0] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_1, 0); - extra_bit_lists[1] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_2, 0); - if ((extra_bit_lists[0] != NULL) || (extra_bit_lists[1] != NULL)) { - *(int *)buffer_allocate (&mod_data, sizeof(int)) = body->ID; - for (int k = 0; k < 2; k++) { - int list_size = sizeof(int) * ints_per_list; - int * list = (int *)buffer_allocate (&mod_data, list_size); - memset (list, 0, list_size); - if (extra_bit_lists[k] != NULL) - memcpy (list, extra_bit_lists[k], bytes_per_list); - } - } - } - } - } - if (any_current_settler_perfume) { - serialize_aligned_text ("turn_no_of_last_founding_for_settler_perfume", &mod_data); - void * area = buffer_allocate (&mod_data, sizeof is->turn_no_of_last_founding_for_settler_perfume); - memcpy (area, is->turn_no_of_last_founding_for_settler_perfume, sizeof is->turn_no_of_last_founding_for_settler_perfume); - } - if (is->current_config.day_night_cycle_mode != DNCM_OFF) { - serialize_aligned_text ("current_day_night_cycle", &mod_data); - int_to_bytes (buffer_allocate (&mod_data, sizeof is->current_day_night_cycle), is->current_day_night_cycle); - } - if (is->current_config.enable_districts && (is->district_count > 0)) { - serialize_aligned_text ("district_config_names", &mod_data); - int * entry_count = (int *)buffer_allocate (&mod_data, sizeof(int)); - *entry_count = is->district_count; - for (int district_id = 0; district_id < is->district_count; district_id++) { - *(int *)buffer_allocate (&mod_data, sizeof(int)) = district_id; - char const * name = is->district_configs[district_id].name; - if (name == NULL) - name = ""; - serialize_aligned_text (name, &mod_data); - } - } - - if (is->current_config.enable_districts) { - int entry_count = 0; - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req != NULL) && (req->city_id >= 0)) - entry_count++; - } - } - if (entry_count > 0) { - serialize_aligned_text ("district_pending_requests", &mod_data); - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 5 * entry_count)); - int * out = chunk + 1; - chunk[0] = entry_count; - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req == NULL) || (req->city_id < 0)) - continue; - out[0] = req->city_id; - out[1] = req->district_id; - out[2] = req->assigned_worker_id; - out[3] = req->target_x; - out[4] = req->target_y; - out += 5; - } - } - } - } - - if (is->current_config.enable_districts && - (is->city_pending_building_orders.len > 0)) { - int entry_count = 0; - FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { - City * city = (City *)tei.key; - int improv_id = tei.value; - if ((city != NULL) && (improv_id >= 0)) - entry_count++; - } - if (entry_count > 0) { - serialize_aligned_text ("building_pending_orders", &mod_data); - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 2 * entry_count)); - int * out = chunk + 1; - chunk[0] = entry_count; - FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { - City * city = (City *)tei.key; - int improv_id = tei.value; - if ((city == NULL) || (improv_id < 0)) - continue; - out[0] = city->Body.ID; - out[1] = improv_id; - out += 2; - } - } - } - - if (is->current_config.enable_districts && (is->district_tile_map.len > 0)) { - serialize_aligned_text ("district_tile_map", &mod_data); - int entry_capacity = is->district_tile_map.len; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 9 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * tile = (Tile *)tei.key; - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst == NULL) - continue; - int x, y; - if (! district_instance_get_coords (inst, tile, &x, &y)) - continue; - int wonder_city_id = inst->wonder_info.city_id; - if (wonder_city_id >= 0) { - City * info_city = get_city_ptr (wonder_city_id); - inst->wonder_info.city = info_city; - if (info_city == NULL) - wonder_city_id = -1; - } else - inst->wonder_info.city = NULL; - out[0] = x; - out[1] = y; - out[2] = inst->district_id; - out[3] = (int)inst->state; - out[4] = inst->built_by_civ_id; - out[5] = inst->completed_turn; - out[6] = (int)inst->wonder_info.state; - out[7] = wonder_city_id; - out[8] = inst->wonder_info.wonder_index; - out += 9; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 9 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - - if (is->current_config.enable_natural_wonders && (is->district_tile_map.len > 0)) { - int entry_capacity = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - if (inst->natural_wonder_info.natural_wonder_id < 0) - continue; - entry_capacity++; - } - if (entry_capacity > 0) { - serialize_aligned_text ("natural_wonder_districts", &mod_data); - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * tile = (Tile *)tei.key; - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || - (inst->district_id != NATURAL_WONDER_DISTRICT_ID) || - (inst->natural_wonder_info.natural_wonder_id < 0)) - continue; - int x, y; - if (! district_instance_get_coords (inst, tile, &x, &y)) - continue; - out[0] = x; - out[1] = y; - out[2] = inst->natural_wonder_info.natural_wonder_id; - out += 3; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - } - - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts && - (is->distribution_hub_records.len > 0)) { - serialize_aligned_text ("distribution_hub_records", &mod_data); - int entry_capacity = is->distribution_hub_records.len; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (rec == NULL) - continue; - out[0] = rec->tile_x; - out[1] = rec->tile_y; - out[2] = rec->civ_id; - out += 3; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - - if (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (is->aerodrome_airlift_usage.len > 0)) { - serialize_aligned_text ("aerodrome_airlift_usage", &mod_data); - int entry_capacity = is->aerodrome_airlift_usage.len; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { - Tile * tile = (Tile *)tei.key; - int mask = tei.value; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - continue; - - out[0] = tile_x; - out[1] = tile_y; - out[2] = mask; - out += 3; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - - if (is->current_config.enable_named_tiles && (is->named_tile_map.len > 0)) { - serialize_aligned_text ("named_tiles", &mod_data); - int entry_capacity = is->named_tile_map.len; - int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); - byte * chunk = (byte *)buffer_allocate (&mod_data, (int)sizeof(int) + bytes_per_entry * entry_capacity); - int * count = (int *)chunk; - byte * out = (byte *)(count + 1); - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if ((entry == NULL) || (entry->name[0] == '\0')) - continue; - Tile * tile = (Tile *)tei.key; - int tile_x = entry->tile_x; - int tile_y = entry->tile_y; - if ((tile != NULL) && (tile != p_null_tile)) - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - ((int *)out)[0] = tile_x; - ((int *)out)[1] = tile_y; - out += sizeof(int) * 2; - memcpy (out, entry->name, sizeof entry->name); - out += sizeof entry->name; - written++; - } - *count = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * bytes_per_entry; - mod_data.length -= trimmed_bytes; - } - } - - if (is->great_wall_auto_build != GWABS_NOT_STARTED) { - serialize_aligned_text ("great_wall_auto_build_state", &mod_data); - *(int *)buffer_allocate (&mod_data, sizeof(int)) = (int)is->great_wall_auto_build; - } - - if (is->ai_candidate_bridge_or_canals_initialized || (is->ai_candidate_bridge_or_canals_count > 0)) { - serialize_aligned_text ("ai_candidate_bridge_or_canals", &mod_data); - int * header = (int *)buffer_allocate (&mod_data, sizeof(int) * 3); - header[0] = is->ai_candidate_bridge_or_canals_initialized ? 1 : 0; - header[1] = is->ai_candidate_bridge_or_canals_count; - header[2] = is->ai_candidate_bridge_or_canals_capacity; - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - int tile_count = (int)entry->tile_count; - if ((tile_count <= 0) || (entry->tile_x == NULL) || (entry->tile_y == NULL)) - tile_count = 0; - - int field_count = 14; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (field_count + tile_count * 2)); - int pending_city_id = entry->pending_req.city_id; - if ((pending_city_id < 0) && (entry->pending_req.city != NULL)) - pending_city_id = entry->pending_req.city->Body.ID; - - chunk[0] = entry->district_id; - chunk[1] = (int)entry->owner_civ_id; - chunk[2] = tile_count; - chunk[3] = (entry->tile_capacity > 0) ? entry->tile_capacity : tile_count; - chunk[4] = entry->assigned_tile_index; - chunk[5] = entry->assigned_worker_id; - chunk[6] = entry->completed ? 1 : 0; - chunk[7] = pending_city_id; - chunk[8] = entry->pending_req.civ_id; - chunk[9] = entry->pending_req.district_id; - chunk[10] = entry->pending_req.assigned_worker_id; - chunk[11] = entry->pending_req.target_x; - chunk[12] = entry->pending_req.target_y; - chunk[13] = entry->pending_req.worker_assigned_turn; - - int * out = chunk + field_count; - for (int ti = 0; ti < tile_count; ti++) { - out[0] = entry->tile_x[ti]; - out[1] = entry->tile_y[ti]; - out += 2; - } - } - } - } - - int metadata_size = (mod_data.length > 0) ? 12 : 0; // Two four-byte bookends plus one four-byte size, only written if there's any mod data - - void * tr = MappedFile_create_file (this, __, file_path, file_size + mod_data.length + metadata_size, is_shared); - if (tr != NULL) { - is->accessing_save_file = this; - if ((mod_data.length > 0) && (mod_data.length + metadata_size <= this->size)) { - // Write first bookend to mod's segment in the save data - byte * seg_start = (byte *)tr + file_size; - for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) - seg_start[n] = c3x_save_segment_bookend[n]; - - // Write actual mod game data - memcpy ((byte *)tr + file_size + 4, mod_data.contents, mod_data.length); - - // Write size of mod data - byte * seg_end = (byte *)tr + file_size + 4 + mod_data.length; - int_to_bytes (seg_end, mod_data.length); - - // Finish off with another bookend - for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) - seg_end[4+n] = c3x_save_segment_bookend[n]; - } - } - buffer_deinit (&mod_data); - return tr; -} - -bool -match_save_chunk_name (byte ** cursor, char const * name) -{ - if (strcmp (name, *cursor) == 0) { - // Move cursor past the string if it matched. Also move past any padding that was added to ensure alignment (see serialize_aligned_text). - *cursor = (byte *)((int)*cursor + strlen (name) + 4 & ~3); - return true; - } else - return false; -} - -bool -match_save_segment_bookend (byte * b) -{ - return memcmp (c3x_save_segment_bookend, b, ARRAY_LEN (c3x_save_segment_bookend)) == 0; -} - -int __cdecl -patch_move_game_data (byte * buffer, bool save_else_load) -{ - int tr = move_game_data (buffer, save_else_load); - - if (! save_else_load) { - // Free all district_instance structs first - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst != NULL) - free (inst); - } - table_deinit (&is->district_tile_map); - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if (entry != NULL) - free (entry); - } - table_deinit (&is->named_tile_map); - clear_all_tracked_workers (); - reset_ai_candidate_bridge_or_canals (); - } - - // Check for a mod save data section and load it if present - MappedFile * save; - int seg_size; - byte * seg; - if ((! save_else_load) && - ((save = is->accessing_save_file) != NULL) && - (save->size >= 8) && - match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - 4)) && - ((seg_size = int_from_bytes ((byte *)((int)save->base_addr + save->size - 8))) > 0) && - (save->size >= seg_size + 12) && - match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - seg_size - 12)) && - ((seg = malloc (seg_size)) != NULL)) { - memcpy (seg, (void *)((int)save->base_addr + save->size - seg_size - 8), seg_size); - - byte * cursor = seg; - char * error_chunk_name = NULL; - while (cursor < seg + seg_size) { - if (match_save_chunk_name (&cursor, "special save message")) { - char * msg = (char *)cursor; - cursor = (byte *)((int)cursor + strlen (msg) + 4 & ~3); - - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - PopupForm_add_text (popup, __, "This save contains a special message:", 0); - PopupForm_add_text (popup, __, msg, 0); - patch_show_popup (popup, __, 0, 0); - - } else if (match_save_chunk_name (&cursor, "extra_defensive_bombards")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->extra_defensive_bombards); - if (bytes_read > 0) - cursor += bytes_read; - else { - error_chunk_name = "extra_defensive_bombards"; - break; - } - - } else if (match_save_chunk_name (&cursor, "airdrops_this_turn")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->airdrops_this_turn); - if (bytes_read > 0) - cursor += bytes_read; - else { - error_chunk_name = "airdrops_this_turn"; - break; - } - - } else if (match_save_chunk_name (&cursor, "unit_transport_ties")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->unit_transport_ties); - if (bytes_read > 0) - cursor += bytes_read; - else { - error_chunk_name = "unit_transport_ties"; - break; - } - - } else if (match_save_chunk_name (&cursor, "waiting_units")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->waiting_units); - if (bytes_read > 0) { - cursor += bytes_read; - is->have_loaded_waiting_units = true; - } else { - error_chunk_name = "waiting_units"; - break; - } - - } else if (match_save_chunk_name (&cursor, "extra_city_improvs")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - - // Read two int vars from this save chunk - int file_extra_improv_count, count_entries; - if (remaining_bytes >= 8) { - file_extra_improv_count = *((int *)cursor)++; - count_entries = *((int *)cursor)++; - remaining_bytes -= 8; - } else - goto done_with_extra_city_improvs; - - // Check that the extra improv counts are valid. They must be greater than zero and what was stored in the save must - // match what we got from the current scenario data. - int extra_improv_count = not_below (0, p_bic_data->ImprovementsCount - 256); - if ((file_extra_improv_count <= 0) || (extra_improv_count != file_extra_improv_count)) - goto done_with_extra_city_improvs; - - // The extra bits data in the save is stored in 32-bit chunks, "ints", to maintain alignment. Compute how many ints we - // need for each list of bits and check that reading all entries won't overrun the buffer. - int ints_per_list = (extra_improv_count + 31) / 32, - ints_per_entry = 1 + 2 * ints_per_list; - if (count_entries * ints_per_entry * sizeof(int) > remaining_bytes) - goto done_with_extra_city_improvs; - - // Main loop reading the extra bits data - for (int n = 0; n < count_entries; n++) { - City * city = get_city_ptr (*((int *)cursor)++); - if (city == NULL) - goto done_with_extra_city_improvs; - - byte * extra_bits_1 = calloc (sizeof (int), ints_per_list); - for (int k = 0; k < ints_per_list; k++) - ((int *)extra_bits_1)[k] = *((int *)cursor)++; - itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_1, (int)extra_bits_1); - - byte * extra_bits_2 = calloc (sizeof (int), ints_per_list); - for (int k = 0; k < ints_per_list; k++) - ((int *)extra_bits_2)[k] = *((int *)cursor)++; - itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_2, (int)extra_bits_2); - } - - // Rebuild the trade network since it may have changed as a result of the additional buildings. This method also - // refreshes the free improvement tables and recomputes city happiness. - patch_Map_build_trade_network (&p_bic_data->Map); - - success = true; - - done_with_extra_city_improvs: - if (! success) { - error_chunk_name = "extra_city_improvs";; - break; - } - - } else if (match_save_chunk_name (&cursor, "turn_no_of_last_founding_for_settler_perfume")) { - for (int n = 0; n < 32; n++) - is->turn_no_of_last_founding_for_settler_perfume[n] = *((int *)cursor)++; - - } else if (match_save_chunk_name (&cursor, "current_day_night_cycle")) { - is->current_day_night_cycle = *((int *)cursor)++; - is->day_night_cycle_unstarted = false; - - // The day/night cycle sprite proxies will have been cleared in patch_load_scenario. They will not necessarily be set - // up again in the usual way because Map_Renderer::load_images is not necessarily called when loading a save. The game - // skips reloading all graphics when loading a save while in-game with another that uses the same graphics (possibly - // only the standard graphics; I didn't test). If day/night cycle mode is active, restore the proxies now if they - // haven't already been. - if ((is->day_night_cycle_img_state == IS_OK) && ! is->day_night_cycle_img_proxies_indexed) - build_sprite_proxies_24 (&p_bic_data->Map.Renderer); - - // Because we've restored current_day_night_cycle from the save, set that is is not the first turn so the cycle - // doesn't get restarted. - is->day_night_cycle_unstarted = false; - - } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_state")) { - int state = *((int *)cursor)++; - if ((state >= GWABS_NOT_STARTED) && (state <= GWABS_DONE)) - is->great_wall_auto_build = (enum great_wall_auto_build_state)state; - else - is->great_wall_auto_build = GWABS_NOT_STARTED; - - } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_is_done")) { - bool was_done = (*((int *)cursor)++ != 0); - is->great_wall_auto_build = was_done ? GWABS_DONE : GWABS_NOT_STARTED; - - } else if (match_save_chunk_name (&cursor, "district_pending_requests")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && - (remaining_bytes >= entry_count * 5 * (int)sizeof(int))) { - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req != NULL) - free (req); - } - table_deinit (&is->city_pending_district_requests[civ_id]); - } - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 5 * (int)sizeof(int)) { - success = false; - break; - } - int city_id = *ints++; - int district_id = *ints++; - int assigned_worker_id = *ints++; - int target_x = *ints++; - int target_y = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 5 * (int)sizeof(int); - City * city = get_city_ptr (city_id); - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - continue; - struct pending_district_request * req = create_pending_district_request (city, district_id); - if (req == NULL) - continue; - if ((assigned_worker_id >= 0) && (get_unit_ptr (assigned_worker_id) == NULL)) - assigned_worker_id = -1; - req->assigned_worker_id = assigned_worker_id; - req->target_x = target_x; - req->target_y = target_y; - } - if (! success) { - for (int civ_id = 0; civ_id < 32; civ_id++) - table_deinit (&is->city_pending_district_requests[civ_id]); - } - } - } - if (! success) { - error_chunk_name = "district_pending_requests"; - break; - } - } else if (match_save_chunk_name (&cursor, "building_pending_orders")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && - (remaining_bytes >= entry_count * 2 * (int)sizeof(int))) { - table_deinit (&is->city_pending_building_orders); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 2 * (int)sizeof(int)) { - success = false; - break; - } - int city_id = *ints++; - int improv_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 2 * (int)sizeof(int); - if (improv_id < 0) - continue; - City * city = get_city_ptr (city_id); - if (city == NULL) - continue; - itable_insert (&is->city_pending_building_orders, (int)city, improv_id); - } - if (! success) - table_deinit (&is->city_pending_building_orders); - } - } - if (! success) { - error_chunk_name = "building_pending_orders"; - break; - } - } else if (match_save_chunk_name (&cursor, "district_tile_map")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if (entry_count >= 0) { - int ints_per_entry = 9; - success = true; - int required_bytes = entry_count * ints_per_entry * (int)sizeof(int); - if (success && remaining_bytes >= required_bytes) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst != NULL) - free (inst); - } - table_deinit (&is->district_tile_map); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < ints_per_entry * (int)sizeof(int)) { - success = false; - break; - } - int x = *ints++; - int y = *ints++; - int district_id = *ints++; - int state_val = *ints++; - int built_by_civ_id = *ints++; - int completed_turn = *ints++; - int wonder_state = *ints++; - int wonder_city_id = *ints++; - int wonder_index = *ints++; - cursor = (byte *)ints; - remaining_bytes -= ints_per_entry * (int)sizeof(int); - if ((district_id < 0) || (district_id >= is->district_count)) - continue; - Tile * tile = tile_at (x, y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = ensure_district_instance (tile, district_id, x, y); - if (inst != NULL) { - enum district_state new_state; - switch (state_val) { - case DS_COMPLETED: - new_state = DS_COMPLETED; - break; - case DS_UNDER_CONSTRUCTION: - new_state = DS_UNDER_CONSTRUCTION; - break; - default: - new_state = DS_UNDER_CONSTRUCTION; - break; - } - inst->state = new_state; - inst->built_by_civ_id = built_by_civ_id; - inst->completed_turn = completed_turn; - - inst->wonder_info.state = (enum wonder_district_state)wonder_state; - inst->wonder_info.city_id = (wonder_city_id >= 0) ? wonder_city_id : -1; - City * info_city = (wonder_city_id >= 0) ? get_city_ptr (wonder_city_id) : NULL; - inst->wonder_info.city = info_city; - if (info_city == NULL) - inst->wonder_info.city_id = -1; - inst->wonder_info.wonder_index = wonder_index; - set_tile_unworkable_for_all_cities (tile, x, y); - } - } - } - } - else - success = false; - } - } - if (! success) { - error_chunk_name = "district_tile_map"; - break; - } - } else if (match_save_chunk_name (&cursor, "natural_wonder_districts")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 3 * (int)sizeof(int)) { - success = false; - break; - } - int x = *ints++; - int y = *ints++; - int natural_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 3 * (int)sizeof(int); - if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) - continue; - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, x, y); - if (inst == NULL) - continue; - inst->district_id = NATURAL_WONDER_DISTRICT_ID; - inst->state = DS_COMPLETED; - inst->natural_wonder_info.natural_wonder_id = natural_id; - set_tile_unworkable_for_all_cities (tile, x, y); - } - } - } - if (! success) { - error_chunk_name = "natural_wonder_districts"; - break; - } - } else if (match_save_chunk_name (&cursor, "distribution_hub_records")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { - clear_distribution_hub_tables (); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 3 * (int)sizeof(int)) { - success = false; - break; - } - int x = *ints++; - int y = *ints++; - int civ_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 3 * (int)sizeof(int); - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - on_distribution_hub_completed (tile, x, y); - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec != NULL) - rec->civ_id = civ_id; - } - } - } - if (! success) { - error_chunk_name = "distribution_hub_records"; - break; - } - } else if (match_save_chunk_name (&cursor, "aerodrome_airlift_usage")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && - (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { - table_deinit (&is->aerodrome_airlift_usage); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 3 * (int)sizeof(int)) { - success = false; - break; - } - int tile_x = *ints++; - int tile_y = *ints++; - int mask = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 3 * (int)sizeof(int); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - itable_insert (&is->aerodrome_airlift_usage, (int)tile, mask); - } - if (! success) - table_deinit (&is->aerodrome_airlift_usage); - } - } - if (! success) { - error_chunk_name = "aerodrome_airlift_usage"; - break; - } - - } else if (match_save_chunk_name (&cursor, "named_tiles")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); - if ((entry_count >= 0) && (remaining_bytes >= entry_count * bytes_per_entry)) { - table_deinit (&is->named_tile_map); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < bytes_per_entry) { - success = false; - break; - } - int tile_x = *ints++; - int tile_y = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int) * 2; - - char name_buf[101]; - memcpy (name_buf, cursor, sizeof name_buf); - name_buf[(sizeof name_buf) - 1] = '\0'; - cursor += sizeof name_buf; - remaining_bytes -= sizeof name_buf; - ints = (int *)cursor; - - if (name_buf[0] == '\0') - continue; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - struct named_tile_entry * entry = calloc (1, sizeof *entry); - if (entry == NULL) { - success = false; - break; - } - entry->tile_x = tile_x; - entry->tile_y = tile_y; - strncpy (entry->name, name_buf, sizeof entry->name); - entry->name[(sizeof entry->name) - 1] = '\0'; - itable_insert (&is->named_tile_map, (int)tile, (int)entry); - } - if (! success) { - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if (entry != NULL) - free (entry); - } - table_deinit (&is->named_tile_map); - } - } - } - if (! success) { - error_chunk_name = "named_tiles"; - break; - } - - } else if (match_save_chunk_name (&cursor, "ai_candidate_bridge_or_canals")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int) * 3) { - int * ints = (int *)cursor; - int saved_initialized = *ints++; - int saved_count = *ints++; - int saved_capacity = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int) * 3; - - if ((saved_count >= 0) && (saved_capacity >= 0)) { - reset_ai_candidate_bridge_or_canals (); - success = true; - - int alloc_capacity = saved_capacity; - if (alloc_capacity < saved_count) - alloc_capacity = saved_count; - if (alloc_capacity > 0) { - is->ai_candidate_bridge_or_canals = (struct ai_candidate_bridge_or_canal_entry *)calloc (alloc_capacity, sizeof *is->ai_candidate_bridge_or_canals); - if (is->ai_candidate_bridge_or_canals == NULL) { - success = false; - alloc_capacity = 0; - } else - is->ai_candidate_bridge_or_canals_capacity = alloc_capacity; - } - - is->ai_candidate_bridge_or_canals_initialized = (saved_initialized != 0); - int loaded_count = 0; - for (int ei = 0; ei < saved_count; ei++) { - if (remaining_bytes < (int)sizeof(int) * 14) { - success = false; - break; - } - int district_id = *ints++; - int owner_civ_id = *ints++; - int tile_count = *ints++; - int tile_capacity = *ints++; - int assigned_tile_index = *ints++; - int assigned_worker_id = *ints++; - int completed = *ints++; - int pending_city_id = *ints++; - int pending_civ_id = *ints++; - int pending_district_id = *ints++; - int pending_assigned_worker_id = *ints++; - int pending_target_x = *ints++; - int pending_target_y = *ints++; - int pending_worker_assigned_turn = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int) * 14; - - if (tile_count < 0) { - success = false; - break; - } - if (remaining_bytes < tile_count * 2 * (int)sizeof(int)) { - success = false; - break; - } - - int stored_tile_count = tile_count; - if (tile_count > AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES) - tile_count = AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES; - if (tile_capacity < tile_count) - tile_capacity = tile_count; - - struct ai_candidate_bridge_or_canal_entry * entry = NULL; - if ((alloc_capacity > 0) && (loaded_count < alloc_capacity)) - entry = &is->ai_candidate_bridge_or_canals[loaded_count]; - - if (entry != NULL) { - entry->district_id = district_id; - entry->owner_civ_id = (short)owner_civ_id; - entry->tile_count = (short)tile_count; - entry->tile_capacity = tile_capacity; - entry->assigned_tile_index = assigned_tile_index; - entry->assigned_worker_id = assigned_worker_id; - entry->completed = (completed != 0); - - entry->tile_x = (short *)calloc (sizeof *entry->tile_x, tile_count); - entry->tile_y = (short *)calloc (sizeof *entry->tile_y, tile_count); - if ((tile_count > 0) && ((entry->tile_x == NULL) || (entry->tile_y == NULL))) { - if (entry->tile_x != NULL) - free (entry->tile_x); - if (entry->tile_y != NULL) - free (entry->tile_y); - entry->tile_x = NULL; - entry->tile_y = NULL; - entry->tile_count = 0; - entry->tile_capacity = 0; - } - - for (int ti = 0; ti < stored_tile_count; ti++) { - int tx = *ints++; - int ty = *ints++; - if ((entry->tile_x != NULL) && (ti < tile_count)) { - entry->tile_x[ti] = (short)tx; - entry->tile_y[ti] = (short)ty; - } - } - - entry->pending_req.city = (pending_city_id >= 0) ? get_city_ptr (pending_city_id) : NULL; - entry->pending_req.city_id = (entry->pending_req.city != NULL) ? pending_city_id : -1; - entry->pending_req.civ_id = pending_civ_id; - entry->pending_req.district_id = pending_district_id; - entry->pending_req.assigned_worker_id = pending_assigned_worker_id; - entry->pending_req.target_x = pending_target_x; - entry->pending_req.target_y = pending_target_y; - entry->pending_req.worker_assigned_turn = pending_worker_assigned_turn; - - if ((entry->assigned_worker_id >= 0) && (get_unit_ptr (entry->assigned_worker_id) == NULL)) - entry->assigned_worker_id = -1; - if ((entry->pending_req.assigned_worker_id >= 0) && (get_unit_ptr (entry->pending_req.assigned_worker_id) == NULL)) - entry->pending_req.assigned_worker_id = -1; - if ((entry->assigned_tile_index < 0) || (entry->assigned_tile_index >= entry->tile_count)) - entry->assigned_tile_index = -1; - - loaded_count++; - } else { - for (int ti = 0; ti < stored_tile_count; ti++) { - ints += 2; - } - } - - cursor = (byte *)ints; - remaining_bytes -= stored_tile_count * 2 * (int)sizeof(int); - } - if (success) - is->ai_candidate_bridge_or_canals_count = loaded_count; - } - } - if (! success) { - error_chunk_name = "ai_candidate_bridge_or_canals"; - break; - } - - } else if (match_save_chunk_name (&cursor, "district_config_names")) { - bool success = false; - bool mismatch_found = false; - bool count_mismatch = false; - char first_mismatch[200]; - first_mismatch[0] = '\0'; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int saved_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if (saved_count >= 0) { - success = true; - count_mismatch = (saved_count != is->district_count); - char * saved_names[saved_count]; - for (int n = 0; n < saved_count; n++) { - if (remaining_bytes < (int)sizeof(int)) { - success = false; - break; - } - ints = (int *)cursor; - int saved_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - - int name_len = -1; - for (int k = 0; k < remaining_bytes; k++) { - if (cursor[k] == '\0') { - name_len = k; - break; - } - } - if (name_len < 0) { - success = false; - break; - } - int padded_len = (name_len + 4) & ~3; - if (padded_len > remaining_bytes) { - success = false; - break; - } - - char * saved_name = (char *)cursor; - saved_names[n] = saved_name; - if (! mismatch_found) { - if ((saved_id < 0) || (saved_id >= is->district_count)) { - snprintf (first_mismatch, sizeof first_mismatch, "%s %d (\"%s\") %s", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW]); - first_mismatch[(sizeof first_mismatch) - 1] = '\0'; - mismatch_found = true; - } else { - char const * current_name = is->district_configs[saved_id].name; - if (current_name == NULL) - current_name = ""; - if (strcmp (current_name, saved_name) != 0) { - snprintf (first_mismatch, sizeof first_mismatch, "%s %d \"%s\" %s \"%s\"", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_NAME_MISMATCH], current_name); - first_mismatch[(sizeof first_mismatch) - 1] = '\0'; - mismatch_found = true; - } - } - } - - cursor += padded_len; - remaining_bytes -= padded_len; - } - if (success && count_mismatch && (first_mismatch[0] == '\0')) { - snprintf (first_mismatch, sizeof first_mismatch, "%s %d %s %d", is->c3x_labels[CL_SAVE_FILE_HAD], saved_count, is->c3x_labels[CL_CURRENT_CONFIG_HAS_ONLY], is->district_count); - first_mismatch[(sizeof first_mismatch) - 1] = '\0'; - mismatch_found = true; - } - if (success && mismatch_found) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); - - char s[1000]; - snprintf (s, sizeof s, "%s %s", is->c3x_labels[CL_WARNING_DISTRICTS_CONFIG_MISMATCH], first_mismatch); - snprintf (s, sizeof s, "%s. %s", s, is->c3x_labels[CL_MAY_BE_OTHER_ERRORS_AS_WELL]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^"); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_DISTRICTS_IN_SAVE_FILE]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - for (int n = 0; n < saved_count; n++) { - snprintf (s, sizeof s, "^ (%d) %s", n, saved_names[n]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - - snprintf (s, sizeof s, "^"); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^%s \"%s\":", is->c3x_labels[CL_CURRENTLY_CONFIGURED_DISTRICTS], is->current_districts_config_path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - for (int n = 0; n < is->district_count; n++) { - snprintf (s, sizeof s, "^ (%d) %s", n, is->district_configs[n].name); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - - patch_show_popup (popup, __, 0, 0); - } - } - } - if (! success) { - error_chunk_name = "district_config_names"; - break; - } - - } else { - error_chunk_name = "N/A"; - break; - } - } - - if (error_chunk_name != NULL) { - char s[200]; - snprintf (s, sizeof s, "Failed to read mod save data. Error occured in chunk: %s", error_chunk_name); - s[(sizeof s) - 1] = '\0'; - pop_up_in_game_error (s); - } - - free (seg); - } - - return tr; -} - -void __fastcall -patch_MappedFile_deinit_after_saving_or_loading (MappedFile * this) -{ - is->accessing_save_file = NULL; - MappedFile_deinit (this); -} - -bool __fastcall -patch_Tile_m7_Check_Barbarian_Camp (Tile * this, int edx, int visible_to_civ) -{ - int * p_stack = (int *)&visible_to_civ; - int ret_addr = p_stack[-1]; - - // If the barb unit AI is calling this method to check if there's a camp to defend, return true if we're allowing barb city capture and the - // tile has a city. This causes barb units to defend cities they've captured, otherwise they'll ignore them. - if ((ret_addr == ADDR_CHECK_BARB_CAMP_TO_DEFEND_RETURN) && - is->current_config.enable_city_capture_by_barbarians && - Tile_has_city (this)) - return true; - else - return Tile_m7_Check_Barbarian_Camp (this, __, visible_to_civ); -} - -bool __fastcall -patch_Unit_can_heal_at (Unit * this, int edx, int tile_x, int tile_y) -{ - if (is->current_config.enable_districts && - is->current_config.enable_port_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile_has_friendly_port_district (tile, this->Body.CivID)) { - int occupier_id = get_tile_occupier_id (tile_x, tile_y, -1, true); - return (occupier_id == -1) || (occupier_id == this->Body.CivID); - } - } - - return Unit_can_heal_at (this, __, tile_x, tile_y); -} - -bool __fastcall -patch_Unit_can_airdrop (Unit * this) -{ - UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - - bool allowed = Unit_can_airdrop (this); - - bool require_aerodrome = (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities); - - if (require_aerodrome) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - bool has_aerodrome = false; - - if ((tile != NULL) && (tile != p_null_tile)) - has_aerodrome = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); - - if (! has_aerodrome) - allowed = false; - else if (! allowed) { - if ((this_type->Unit_Class != UTC_Air) && - (this_type->Air_Missions & UCV_Airdrop) && - (this->Body.Moves == 0)) - allowed = true; - } - } - - // Possibly rule in this airdrop as allowed if it's by a paratrooper in a helicopter on a carrier and we're configured to allow airdrops under - // those circumstances. - if ((! allowed) && (is->current_config.special_helicopter_rules & SHR_PASSENGER_AIRDROP)) { - Unit * container = get_unit_ptr (this->Body.Container_Unit); - if (container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) { // if in helicopter - Unit * metacontainer = get_unit_ptr (container->Body.Container_Unit); - if (metacontainer != NULL && p_bic_data->UnitTypes[metacontainer->Body.UnitTypeID].Unit_Class == UTC_Sea && - Unit_has_ability (metacontainer, __, UTA_Transports_Only_Aircraft)) { // if that helicopter is on a carrier - // Allow the airdrop under the same restrictions as from an airfield - allowed = this_type->Unit_Class != UTC_Air && this->Body.Moves == 0; - } - } - } - - if (! allowed) - return false; - - return itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0) == 0; -} - -bool __fastcall -patch_City_Improvements_contains (City_Improvements * this, int edx, int id) -{ - byte * extra_bits; - if ((id < 256) || ! is->current_config.remove_city_improvement_limit) - return City_Improvements_contains (this, __, id); - else if (itable_look_up (&is->extra_city_improvs, (int)this, (int *)&extra_bits)) { - int extra_id = id - 256; - return (extra_bits[extra_id>>3] >> (extra_id & 7)) & 1; - } else - return false; -} - -void __fastcall -patch_City_Improvements_set (City_Improvements * this, int edx, int id, bool add_else_remove) -{ - if ((id < 256) || ! is->current_config.remove_city_improvement_limit) - return City_Improvements_set (this, __, id, add_else_remove); - else { - byte * extra_bits = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)this, 0); - int extra_id = id - 256; - byte mask = 1 << (extra_id & 7); - if (add_else_remove) { - if (! extra_bits) { - int extra_bits_size = (not_below (0, p_bic_data->ImprovementsCount - 256) >> 3) + 1; - extra_bits = calloc (1, extra_bits_size); - itable_insert (&is->extra_city_improvs, (int)this, (int)extra_bits); - } - extra_bits[extra_id>>3] |= mask; - } else if ((! add_else_remove) && (extra_bits != NULL)) - extra_bits[extra_id>>3] &= ~mask; - } -} - -bool __fastcall -patch_Leader_has_tech_to_stop_disease (Leader * this, int edx, int id) -{ - if (! is->current_config.patch_disease_stopping_tech_flag_bug) - return Leader_has_tech (this, __, id); - else - return Leader_has_tech_with_flag (this, __, ATF_Disabled_Deseases_From_Flood_Plains); -} - -void __fastcall -patch_set_worker_animation (void * this, int edx, Unit * unit, int job_id) -{ - AnimationType anim_type; - - // If districts disabled or unit is null or job is not building mines, use base logic - if ((! is->current_config.enable_districts) || - (unit == NULL) || - (job_id != WJ_Build_Mines)) { - set_worker_animation(this, __, unit, job_id); - return; - } - - // If tile has a district under construction - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && - ! district_is_complete (tile, inst->district_id) && job_id == WJ_Build_Mines) { - - // Override and ensure build animation is used - job_id = AT_BUILD; - } - - set_worker_animation(this, __, unit, job_id); -} - -void __fastcall -patch_Unit_work_simple_job (Unit * this, int edx, int job_id) -{ - is->lmify_tile_after_working_simple_job = NULL; - - // Check if districts are enabled - if (is->current_config.enable_districts) { - int tile_x = this->Body.X; - int tile_y = this->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - - if (tile != NULL && tile != p_null_tile) { - // Check if there's a completed district on this tile - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete(tile, inst->district_id)) { - int district_id = inst->district_id; - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - - // AI players only (human removal is handled via issue_district_worker_command) - if (!is_human) { - bool allow_removal = false; - if (district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = &inst->wonder_info; - allow_removal = (info->state == WDS_UNUSED); - } - - if (allow_removal) { - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - handle_district_removed (tile, district_id, tile_x, tile_y, false); - } - } - } - } - } - - Unit_work_simple_job (this, __, job_id); - - if (is->lmify_tile_after_working_simple_job != NULL) - is->lmify_tile_after_working_simple_job->vtable->m31_set_landmark (is->lmify_tile_after_working_simple_job, __, true); -} - -void __fastcall -patch_Map_change_tile_terrain_by_worker (Map * this, int edx, enum SquareTypes new_terrain_type, int x, int y) -{ - Map_change_tile_terrain (this, __, new_terrain_type, x, y); - - if (is->current_config.convert_to_landmark_after_planting_forest && (new_terrain_type == SQ_Forest)) - is->lmify_tile_after_working_simple_job = tile_at (x, y); -} - -int __fastcall -patch_Leader_ai_eval_technology (Leader * this, int edx, int id, bool param_2, bool param_3) -{ - int base = Leader_ai_eval_technology (this, __, id, param_2, param_3); - return apply_perfume (PK_TECHNOLOGY, p_bic_data->Advances[id].Name, base); -} - -int __fastcall -patch_Leader_ai_eval_government (Leader * this, int edx, int id) -{ - int base = Leader_ai_eval_government (this, __, id); - return apply_perfume (PK_GOVERNMENT, p_bic_data->Governments[id].Name.S, base); -} - -bool -roll_to_spare_unit_from_nuke (Unit * unit) -{ - int one_hp_destroy_chance = is->current_config.chance_for_nukes_to_destroy_max_one_hp_units; - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - if ((one_hp_destroy_chance < 100) && - (Unit_get_max_hp (unit) <= 1) && - (type->Defence > 0) && - ((type->Unit_Class == UTC_Land) || (type->Unit_Class == UTC_Sea))) - return ! (rand_int (p_rand_object, __, 100) < one_hp_destroy_chance); - else - return false; -} - -void __fastcall -patch_Unit_despawn_after_killed_by_nuke (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) -{ - if (roll_to_spare_unit_from_nuke (this)) - this->Body.Damage = Unit_get_max_hp (this) - 1; - else { - bool prev_always_despawn_passengers = is->always_despawn_passengers; - if ((is->current_config.land_transport_rules & LTR_NO_ESCAPE) && is_land_transport (this)) - is->always_despawn_passengers = true; - else if ((is->current_config.special_helicopter_rules & SHR_NO_ESCAPE) && p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air && - p_bic_data->UnitTypes[this->Body.UnitTypeID].Transport_Capacity > 0) - is->always_despawn_passengers = true; - patch_Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); - is->always_despawn_passengers = prev_always_despawn_passengers; - } -} - -void __fastcall -patch_mp_despawn_after_killed_by_nuke (void * this, int edx, int unit_id, int civ_id_responsible, byte param_3, byte param_4, byte param_5, byte param_6) -{ - Unit * unit = get_unit_ptr (unit_id); - if ((unit != NULL) && roll_to_spare_unit_from_nuke (unit)) - unit->Body.Damage = Unit_get_max_hp (unit) - 1; - else - mp_despawn (this, __, unit_id, civ_id_responsible, param_3, param_4, param_5, param_6); -} - -bool __fastcall -patch_City_has_unprotected_improv_to_sell (City * this, int edx, int id) -{ - // Fall back to original logic only if the config doesn't alter the behavior. - if (! is->current_config.allow_sale_of_aqueducts_and_hospitals && !is->current_config.allow_sale_of_small_wonders) - return City_has_unprotected_improv (this, __, id); - - else if (patch_City_has_improvement (this, __, id, false)) { - Improvement * improv = &p_bic_data->Improvements[id]; - int max_pop_to_sell = INT_MAX; // By default, population-based sell isn't restricted - if (improv->ImprovementFlags & (ITF_Allows_City_Level_2 | ITF_Allows_City_Level_3)) { // Aqueduct/Hospital? - if (is->current_config.allow_sale_of_aqueducts_and_hospitals) { - if (improv->ImprovementFlags & ITF_Allows_City_Level_2) - max_pop_to_sell = p_bic_data->General.MaximumSize_Town; - else if (improv->ImprovementFlags & ITF_Allows_City_Level_3) - max_pop_to_sell = p_bic_data->General.MaximumSize_City; - } else { - // Do not allow selling these. - max_pop_to_sell = 0; - } - } - - // Can't sell: - // - Great Wonders - // - Small Wonders, unless the config allows it - // - Capital - // - Aqueduct/Hospital if the city is too big for that population - return ((improv->Characteristics & ITC_Wonder) == 0) && - (is->current_config.allow_sale_of_small_wonders || ((improv->Characteristics & ITC_Small_Wonder) == 0)) && - ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && - (this->Body.Population.Size <= max_pop_to_sell); - - } else - return false; -} - -bool __fastcall -patch_UnitType_has_detector_ability_for_vis_check (UnitType * this, int edx, enum UnitTypeAbilities a) -{ - bool tr = UnitType_has_ability (this, __, a); - - // Restrict detection by sea units to other sea units and non-sea units to other non-sea units - if (tr && - is->current_config.no_cross_shore_detection && - (is->checking_visibility_for_unit != NULL) && - ((this->Unit_Class == UTC_Sea) ^ (p_bic_data->UnitTypes[is->checking_visibility_for_unit->Body.UnitTypeID].Unit_Class == UTC_Sea))) - tr = false; - - return tr; -} - -bool -is_airdrop_trespassing (Unit * unit, int target_x, int target_y) -{ - if (is->current_config.disallow_trespassing && - check_trespassing (unit->Body.CivID, tile_at (unit->Body.X, unit->Body.Y), tile_at (target_x, target_y))) { - bool allowed = is_allowed_to_trespass (unit); - - // If "unit" is an air unit that can carry others, like helicopters, then this airdrop is only allowed if all of its passengers are - // allowed to trespass. - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - if (allowed && (type->Unit_Class == UTC_Air) && (type->Transport_Capacity > 0)) - FOR_UNITS_ON (uti, tile_at (unit->Body.X, unit->Body.Y)) - if ((uti.unit->Body.Container_Unit == unit->Body.ID) && - (! is_allowed_to_trespass (uti.unit))) { - allowed = false; - break; - } - - return ! allowed; - } else - return false; -} - -bool __fastcall -patch_Unit_check_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) -{ - return Unit_check_airdrop_target (this, __, tile_x, tile_y) && - is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID) && - ! is_airdrop_trespassing (this, tile_x, tile_y); -} - -bool __fastcall -patch_Unit_can_airlift (Unit * this) -{ - bool base = Unit_can_airlift (this); - - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) - return base; - - Tile * tile = tile_at (this->Body.X, this->Body.Y); - if ((tile == NULL) || (tile == p_null_tile)) - return base; - - bool allow_from_non_city = false; - if (base) { - City * city = city_at (this->Body.X, this->Body.Y); - if ((city == NULL) || (city->Body.CivID != this->Body.CivID)) - allow_from_non_city = true; - } - - if (allow_from_non_city) - return true; - - return tile_has_friendly_aerodrome_district (tile, this->Body.CivID, true); -} - -bool __fastcall -patch_Unit_check_airlift_target (Unit * this, int edx, int tile_x, int tile_y) -{ - bool base = Unit_check_airlift_target (this, __, tile_x, tile_y); - bool allowed = base; - - Tile * tile = tile_at (tile_x, tile_y); - - if (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities) { - if ((tile == NULL) || (tile == p_null_tile)) { - allowed = false; - } else { - City * target_city = city_at (tile_x, tile_y); - if (allowed && - (target_city != NULL) && - (target_city->Body.CivID == this->Body.CivID)) - allowed = false; - - if (! allowed) - allowed = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); - } - } - - if (! allowed) - return false; - - return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); -} - -void __fastcall -patch_Unit_airlift (Unit * this, int edx, int tile_x, int tile_y) -{ - Tile * source_tile = NULL; - bool mark_usage = false; - - if (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities) { - source_tile = tile_at (this->Body.X, this->Body.Y); - if (tile_has_friendly_aerodrome_district (source_tile, this->Body.CivID, true)) - mark_usage = true; - } - - Unit_airlift (this, __, tile_x, tile_y); - - if (mark_usage && (source_tile != NULL) && (source_tile != p_null_tile)) { - int mask = itable_look_up_or (&is->aerodrome_airlift_usage, (int)source_tile, 0); - mask |= (1 << this->Body.CivID); - itable_insert (&is->aerodrome_airlift_usage, (int)source_tile, mask); - } -} - -int __fastcall -patch_City_count_airports_for_ai_airlift_target (City * this, int edx, enum ImprovementTypeFlags airport_flag) -{ - // When this function is called, the AI unit being moved is stored in register ESI. - Unit * unit; - __asm__ __volatile__("mov %%esi, %0" : "=r" (unit)); - - int tr = City_count_improvements_with_flag (this, __, airport_flag); - - // Check the stack limit here. If the city's tile is at the limit, return that it has no airport so the AI can't airlift there. - if ((tr > 0) && ! is_below_stack_limit (tile_at (this->Body.X, this->Body.Y), this->Body.CivID, unit->Body.UnitTypeID)) - return 0; - - else - return tr; -} - -int __fastcall -patch_Unit_ai_eval_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) -{ - int tr = Unit_ai_eval_airdrop_target (this, __, tile_x, tile_y); - - // Prevent the AI from airdropping onto tiles in violation of the stack limit or trespassing restriction - if ((tr > 0) && - ((! is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID)) || - is_airdrop_trespassing (this, tile_x, tile_y))) - tr = 0; - - return tr; -} - -bool __fastcall -patch_Unit_find_telepad_on_tile (Unit * this, int edx, int x, int y, bool show_selection_popup, Unit ** out_unit_telepad) -{ - if (! is_below_stack_limit (tile_at (x, y), this->Body.CivID, this->Body.UnitTypeID)) { - *out_unit_telepad = NULL; - return false; - } else - return Unit_find_telepad_on_tile (this, __, x, y, show_selection_popup, out_unit_telepad); -} - -bool __fastcall -patch_Unit_ai_go_to_capital (Unit * this) -{ - City * capital = get_city_ptr (leaders[this->Body.CivID].CapitalID); - - // Block going to capital if the capital's tile is at the stack limit. This stops the AI from airlifting there (would violate the limit) and - // saves it from trying to pathfind there. - if ((capital != NULL) && - ! is_below_stack_limit (tile_at (capital->Body.X, capital->Body.Y), this->Body.CivID, this->Body.UnitTypeID)) - return false; - - return Unit_ai_go_to_capital (this); -} - -bool __fastcall -patch_Unit_is_in_rebase_range (Unit * this, int edx, int tile_x, int tile_y) -{ - bool in_range; - - // 6 is the game's standard value, so fall back on the base game logic in that case - if (is->current_config.rebase_range_multiplier == 6) - in_range = Unit_is_in_rebase_range (this, __, tile_x, tile_y); - - else { - int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - if (op_range < 1) - op_range = 500; - - int x_dist = Map_get_x_dist (&p_bic_data->Map, __, tile_x, this->Body.X), - y_dist = Map_get_y_dist (&p_bic_data->Map, __, tile_y, this->Body.Y); - - in_range = ((x_dist + y_dist) >> 1) <= (op_range * is->current_config.rebase_range_multiplier); - } - - return in_range && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); -} - -bool __fastcall -patch_Unit_check_rebase_target (Unit * this, int edx, int tile_x, int tile_y) -{ - // Check if this is an air unit - bool is_air_unit = (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air); - - // If districts are enabled and this is an air unit, check for aerodrome districts - if (is_air_unit && is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts) { - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - // Check if tile has a district - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - int district_id = inst->district_id; - // Check if this is an aerodrome district owned by this unit's civ - if ((district_id == AERODROME_DISTRICT_ID) && (tile->Territory_OwnerID == this->Body.CivID)) { - // Check if aerodrome is complete - if (district_is_complete (tile, district_id)) { - // Perform range check - bool in_range = patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y); - if (in_range) { - return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); - } - } - } - } - - // If air_units_use_aerodrome_districts_not_cities is enabled, check if there's a city and disallow it - if (is->current_config.air_units_use_aerodrome_districts_not_cities) { - City * target_city = city_at (tile_x, tile_y); - if (target_city != NULL && target_city->Body.CivID == this->Body.CivID) { - // There's a friendly city here - disallow landing since configured to use aerodromes/airfields/carriers only - return false; - } - } - } - } - - // 6 is the game's standard value, so fall back on the base game logic in that case - if (is->current_config.rebase_range_multiplier == 6) { - return Unit_check_rebase_target (this, __, tile_x, tile_y) && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); - - // Otherwise, we have to redo the range check. Unlike Unit::is_in_rebase_range, the base method here does more than just check the range so we - // want to make sure to call it even if we determine that the target is in range. In that case, set the range to unlimited temporarily so the - // base game's range check passes. - } else { - if (patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y)) { - int * p_op_range = &p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - int original_op_range = *p_op_range; - *p_op_range = 0; - bool tr = Unit_check_rebase_target (this, __, tile_x, tile_y); - *p_op_range = original_op_range; - return tr; - } else - return false; - } -} - -int __fastcall -patch_Sprite_draw_already_worked_tile_img (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - Sprite * to_draw = this; - - if (is->do_not_draw_already_worked_tile_img) - return 0; - - if (is->current_config.toggle_zoom_with_z_on_city_screen && p_bic_data->is_zoomed_out) { - - // Load sprite if necessary - if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_UNINITED) { - is->tile_already_worked_zoomed_out_sprite_init_state = IS_INIT_FAILED; - PCX_Image * pcx = malloc (sizeof *pcx); - if (pcx != NULL) { - memset (pcx, 0, sizeof *pcx); - PCX_Image_construct (pcx); - char path[2*MAX_PATH]; - get_mod_art_path ("TileAlreadyWorkedZoomedOut.pcx", path, sizeof path); - PCX_Image_read_file (pcx, __, path, NULL, 0, 0x100, 2); - if (pcx->JGL.Image != NULL) { - Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; - memset (sprite, 0, sizeof *sprite); - Sprite_construct (sprite); - Sprite_slice_pcx (sprite, __, pcx, 0, 0, 64, 32, 1, 1); - is->tile_already_worked_zoomed_out_sprite_init_state = IS_OK; - } - pcx->vtable->destruct (pcx, __, 0); - free (pcx); - } - } - - if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_OK) - to_draw = &is->tile_already_worked_zoomed_out_sprite; - } - - return Sprite_draw (to_draw, __, canvas, pixel_x, pixel_y, color_table); -} - -int __fastcall -patch_Tile_m43_Get_field_30_for_city_loc_eval (Tile * this) -{ - int tr = this->vtable->m43_Get_field_30 (this); - - // This patch function replaces two places where ai_eval_city_location calls Tile::m43_Get_field_30 to check the 18th bit, which indicates - // whether the tile is in the workable area of any city. If it is but the work area has been expanded, check that it's actually within the - // normal 20-tile area. This prevents work area expansion from causing AIs to space their cities further apart. - // The field_30_get_counter is a crazy workaround for the fact that the game doesn't have any way to determine a tile's coordinates given a - // pointer to its object. So we track the initial (x, y) for the tile we're evaluating and then count calls to this func to know what - // neighboring coords "this" corresponds to. - int get_counter = is->ai_evaling_city_field_30_get_counter; - if (((tr >> 17) & 1) && (is->current_config.city_work_radius >= 3)) { - bool found_city = false; - int this_x, this_y; { - int dx, dy; - patch_ni_to_diff_for_work_area (get_counter, &dx, &dy); - this_x = is->ai_evaling_city_loc_x + dx; - this_y = is->ai_evaling_city_loc_y + dy; - wrap_tile_coords (&p_bic_data->Map, &this_x, &this_y); - } - FOR_TILES_AROUND (tai, 21, this_x, this_y) - if (Tile_has_city (tai.tile)) { - found_city = true; - break; - } - if (! found_city) - tr &= ~(1 << 17); - } - get_counter++; - if (get_counter >= 21) - get_counter = 0; - is->ai_evaling_city_field_30_get_counter = get_counter; - - return tr; - -} - -// Intercept the call where the game gets a random index at which to start searching for a suitable tile to become polluted. Normally, it passes 20 as -// the limit here. We must replace that to cover a potentially modded work area. -int __fastcall -patch_rand_int_to_place_pollution (void * this, int edx, int lim) -{ - return rand_int (this, __, is->workable_tile_count - 1); -} - -void __fastcall -patch_Main_Screen_Form_t2s_coords_to_draw_yields (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int * out_x, int * out_y) -{ - Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, out_x, out_y); - - // If we've zoomed out the map on the city screen, we may end up drawing the tile yields off screen depending on the map size. If this is the - // case, detected by negative screen coords, then shift the coords over by one map-screen back onto the actual screen. The shift amounts are - // 64*map_width/2 and 32*map_height/2 for x and y because (64, 32) is the size of a zoomed out tile and /2 is for overlap (I think). - if (p_bic_data->is_zoomed_out && (*out_x < 0)) - *out_x += p_bic_data->Map.Width << 5; - if (p_bic_data->is_zoomed_out && (*out_y < 0)) - *out_y += p_bic_data->Map.Height << 4; -} - -void -set_clip_area_to_map_view (City_Form * city_form) -{ - int left_margin = (p_bic_data->ScreenWidth - city_form->Background_Image.Width) / 2, - top_margin = (p_bic_data->ScreenHeight - city_form->Background_Image.Height) / 2; - RECT map_view_on_screen = { .left = left_margin, .top = top_margin + 92, .right = left_margin + 1024, .bottom = top_margin + 508 }; - JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; - jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &map_view_on_screen); -} - -void -clear_clip_area (City_Form * city_form) -{ - JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; - jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &jgl_canvas->Image_Rect); -} - -void -init_distribution_hub_icons () -{ - if (is->distribution_hub_icons_img_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char ss[200]; - snprintf (ss, sizeof ss, "[C3X] init_distribution_hub_icons: state=%d\n", is->distribution_hub_icons_img_state); - (*p_OutputDebugStringA) (ss); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("Districts/DistributionHubIncomeIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image == NULL) || - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { - (*p_OutputDebugStringA) ("[C3X] PCX file for distribution hub icons failed to load or is too small.\n"); - is->distribution_hub_icons_img_state = IS_INIT_FAILED; - goto cleanup; - } - - // Extract shield icon (index 4: x = 1 + 4*31 = 125, width 30) - Sprite_construct (&is->distribution_hub_shield_icon); - Sprite_slice_pcx (&is->distribution_hub_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); - - // Extract shield corruption icon (index 5: x = 1 + 5*31 = 156, width 30) - Sprite_construct (&is->distribution_hub_corruption_icon); - Sprite_slice_pcx (&is->distribution_hub_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); - - // Extract small shield icon (index 13) - Sprite_construct (&is->distribution_hub_shield_icon_small); - Sprite_slice_pcx (&is->distribution_hub_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); - - // Extract surplus food icon (index 6: x = 1 + 6*31 = 187, width 30) - Sprite_construct (&is->distribution_hub_food_icon); - Sprite_slice_pcx (&is->distribution_hub_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); - - // Extract small surplus food icon (index 15) - Sprite_construct (&is->distribution_hub_food_icon_small); - Sprite_slice_pcx (&is->distribution_hub_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); - - // Extract eaten food icon (index 7: x = 1 + 7*31 = 218, width 30) - Sprite_construct (&is->distribution_hub_eaten_food_icon); - Sprite_slice_pcx (&is->distribution_hub_eaten_food_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); - - is->distribution_hub_icons_img_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -draw_district_yields (City_Form * city_form, Tile * tile, int district_id, int screen_x, int screen_y) -{ - // Lazy load district icons - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - if (is->dc_icons_img_state != IS_OK) - return; - - if (district_id < 0 || district_id >= is->district_count) - return; - - // Get district configuration - struct district_config * config = &is->district_configs[district_id]; - struct district_instance * inst = get_district_instance (tile); - - // Count total yields from bonuses - int food_bonus = 0, shield_bonus = 0, gold_bonus = 0, science_bonus = 0, culture_bonus = 0, happiness_bonus = 0; - get_effective_district_yields (inst, config, &food_bonus, &shield_bonus, &gold_bonus, &science_bonus, &culture_bonus, &happiness_bonus); - if ((config->generated_resource_id >= 0) && - (config->generated_resource_flags & MF_YIELDS) && - (city_form->CurrentCity != NULL) && - district_generates_resource_for_civ (tile, inst, config, city_form->CurrentCity->Body.CivID)) { - Resource_Type * res = &p_bic_data->ResourceTypes[config->generated_resource_id]; - food_bonus += res->Food; - shield_bonus += res->Shield; - gold_bonus += res->Commerce; - } - - int food_pos = food_bonus > 0 ? food_bonus : 0; - int food_neg = food_bonus < 0 ? -food_bonus : 0; - int shield_pos = shield_bonus > 0 ? shield_bonus : 0; - int shield_neg = shield_bonus < 0 ? -shield_bonus : 0; - int gold_pos = gold_bonus > 0 ? gold_bonus : 0; - int gold_neg = gold_bonus < 0 ? -gold_bonus : 0; - int science_pos = science_bonus > 0 ? science_bonus : 0; - int science_neg = science_bonus < 0 ? -science_bonus : 0; - int culture_pos = culture_bonus > 0 ? culture_bonus : 0; - int culture_neg = culture_bonus < 0 ? -culture_bonus : 0; - int happiness_pos = happiness_bonus > 0 ? happiness_bonus : 0; - int happiness_neg = happiness_bonus < 0 ? -happiness_bonus : 0; - - int total_yield = 0; - total_yield += food_pos + food_neg; - total_yield += shield_pos + shield_neg; - total_yield += gold_pos + gold_neg; - total_yield += science_pos + science_neg; - total_yield += culture_pos + culture_neg; - total_yield += happiness_pos + happiness_neg; - - if (total_yield <= 0) - return; - - // Get sprites - Sprite * food_sprite = &is->district_food_icon_small; - Sprite * shield_sprite = &is->district_shield_icon_small; - Sprite * commerce_sprite = &is->district_commerce_icon_small; - Sprite * science_sprite = &is->district_science_icon_small; - Sprite * culture_sprite = &is->district_culture_icon_small; - Sprite * happiness_sprite = &is->district_happiness_icon_small; - Sprite * food_negative_sprite = &is->district_negative_food_icon_small; - Sprite * shield_negative_sprite = &is->district_negative_shield_icon_small; - Sprite * commerce_negative_sprite = &is->district_negative_commerce_icon_small; - Sprite * science_negative_sprite = &is->district_negative_science_icon_small; - Sprite * culture_negative_sprite = &is->district_negative_culture_icon_small; - Sprite * happiness_negative_sprite = &is->district_unhappiness_icon_small; - - // Determine sprite dimensions - int sprite_width = food_sprite->Width3; - int sprite_height = food_sprite->Height; - - // Calculate total width of all icons - int total_width = total_yield * sprite_width; - - // Center the icons horizontally - int half_width = total_width >> 1; - int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; - int max_offset = (tile_width >> 1) - 5; - if (half_width > max_offset) - half_width = max_offset; - - int pixel_x = screen_x - half_width; - int pixel_y = screen_y - (sprite_height >> 1); - - // Adjust spacing if icons would exceed tile width - int spacing = sprite_width; - if (total_width > tile_width - 10) { - if (total_yield > 1) { - spacing = (tile_width - 10 - sprite_width) / (total_yield - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > sprite_width) - spacing = sprite_width; - } - } - - // Draw icons in order: shields, food, science, commerce, culture - for (int i = 0; i < shield_pos; i++) { - Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < shield_neg; i++) { - Sprite_draw (shield_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < food_pos; i++) { - Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < food_neg; i++) { - Sprite_draw (food_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < science_pos; i++) { - Sprite_draw (science_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < science_neg; i++) { - Sprite_draw (science_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < gold_pos; i++) { - Sprite_draw (commerce_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < gold_neg; i++) { - Sprite_draw (commerce_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < culture_pos; i++) { - Sprite_draw (culture_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < culture_neg; i++) { - Sprite_draw (culture_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < happiness_pos; i++) { - Sprite_draw (happiness_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < happiness_neg; i++) { - Sprite_draw (happiness_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } -} - -void -draw_distribution_hub_yields (City_Form * city_form, Tile * tile, int tile_x, int tile_y, int screen_x, int screen_y) -{ - // Get the distribution hub record for this tile - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec == NULL) - return; - - City * anchor_city = get_connected_city_for_distribution_hub (rec); - if (! distribution_hub_accessible_to_city (rec, city_form->CurrentCity)) - return; - - int food_yield = rec->food_yield; - int shield_yield = rec->shield_yield; - int total_yield = food_yield + shield_yield; - - if (total_yield <= 0) - return; - - // Lazy load distribution hub icons - if (is->distribution_hub_icons_img_state == IS_UNINITED) - init_distribution_hub_icons (); - if (is->distribution_hub_icons_img_state != IS_OK) - return; - - Sprite * food_sprite = &is->distribution_hub_food_icon_small; - Sprite * shield_sprite = &is->distribution_hub_shield_icon_small; - - if (food_sprite->Width3 == 0) food_sprite = &is->distribution_hub_food_icon; - if (shield_sprite->Width3 == 0) shield_sprite = &is->distribution_hub_shield_icon; - - int sprite_height = food_sprite->Height; - if (sprite_height == 0) sprite_height = shield_sprite->Height; - - int food_width = food_sprite->Width3; - int shield_width = shield_sprite->Width3; - if ((food_width <= 0) && (shield_width > 0)) food_width = shield_width; - if ((shield_width <= 0) && (food_width > 0)) shield_width = food_width; - - // Calculate total width of all icons - int total_width = 0; - if (food_yield > 0) total_width += food_width * food_yield; - if (shield_yield > 0) total_width += shield_width * shield_yield; - - // Center the icons horizontally - int half_width = total_width >> 1; - int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; - int max_offset = (tile_width >> 1) - 5; - if (half_width > max_offset) half_width = max_offset; - - int pixel_x = screen_x - half_width; - int pixel_y = screen_y - (sprite_height >> 1); - - // Adjust spacing if icons would exceed tile width - int spacing_food = food_width; - int spacing_shield = shield_width; - - if (total_width > tile_width - 10) { - if (total_yield > 1) { - int spacing = (tile_width - 10 - food_width) / (total_yield - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > food_width) - spacing = food_width; - spacing_food = spacing; - spacing_shield = spacing; - } - } - - // Draw food icons first - for (int i = 0; i < food_yield; i++) { - Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing_food; - } - - // Draw shield icons - for (int i = 0; i < shield_yield; i++) { - Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing_shield; - } -} - -void __fastcall -patch_City_Form_draw_yields_on_worked_tiles (City_Form * this) -{ - // If we're zoomed in and the city work radius is at least 4 then it's likely we'll end up drawing things outside of the city screen's usual - // map area. Set the clip area to the map area so none of those draws are visible. - bool changed_clip_area = false; - if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { - set_clip_area_to_map_view (this); - changed_clip_area = true; - } - - if (is->current_config.enable_districts && this->CurrentCity != NULL) { - recompute_city_yields_with_districts (this->CurrentCity); - } - - is->do_not_draw_already_worked_tile_img = false; - City_Form_draw_yields_on_worked_tiles (this); - - // If we're zoomed out then draw the yields again but this time skip drawing of the tile-already-worked sprites. This is because the - // transparent regions of those sprites get drawn overtop of the yield sprites when zoomed out, and that overdrawing deletes parts of the - // yields, i.e., it overwrites their colored pixels with transparent ones. The simplest solution is to draw the yields again after the - // already-worked sprites to ensure the former get drawn overtop of the latter. - if (p_bic_data->is_zoomed_out) { - is->do_not_draw_already_worked_tile_img = true; - City_Form_draw_yields_on_worked_tiles (this); - } - - // Draw district bonuses on district tiles - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - City * city = this->CurrentCity; - if (city == NULL) - goto skip_district_yields; - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int civ_id = city->Body.CivID; - - // Calculate screen coordinates for city center - int center_screen_x, center_screen_y; - Main_Screen_Form_tile_to_screen_coords (p_main_screen_form, __, city_x, city_y, ¢er_screen_x, ¢er_screen_y); - - int tile_half_width = p_bic_data->is_zoomed_out ? 32 : 64; - int tile_half_height = p_bic_data->is_zoomed_out ? 16 : 32; - center_screen_x += tile_half_width; - if (center_screen_x < 0) - center_screen_x += p_bic_data->Map.Width * tile_half_width; - center_screen_y += tile_half_height; - if (center_screen_y < 0) - center_screen_y += p_bic_data->Map.Height * tile_half_height; - - int remaining_utilized_neighborhoods = 0; - if (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts) - remaining_utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - - FOR_DISTRICTS_AROUND (wai, city_x, city_y, true) { - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - bool is_distribution_hub = district_id == DISTRIBUTION_HUB_DISTRICT_ID; - bool is_natural_wonder = district_id == NATURAL_WONDER_DISTRICT_ID; - - if (is_natural_wonder && (!is->current_config.enable_natural_wonders)) - continue; - - // Distribution hubs are drawn in the dedicated wider-radius pass below. - if (is_distribution_hub) - continue; - - if (!is_natural_wonder && (!is->current_config.enable_districts)) - continue; - - // For neighborhood districts, check if population is high enough to utilize them - if (is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - district_id == NEIGHBORHOOD_DISTRICT_ID) { - // Only draw yields if this neighborhood is utilized - if (remaining_utilized_neighborhoods <= 0) - continue; - remaining_utilized_neighborhoods--; - } - - // Calculate screen coordinates for this tile - int screen_x = center_screen_x + (wai.dx * tile_half_width); - int screen_y = center_screen_y + (wai.dy * tile_half_height); - - // Call the appropriate drawing function - draw_district_yields (this, wai.tile, district_id, screen_x, screen_y); - } - - // Draw distribution hub yields around a larger radius so connected hubs outside the work area are shown - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { - int const max_tiles = workable_tile_counts[7]; - - for (int ni = 0; ni < max_tiles; ni++) { - int dx, dy; - patch_ni_to_diff_for_work_area (ni, &dx, &dy); - - int tile_x = city_x + dx; - int tile_y = city_y + dy; - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID)) - continue; - - int screen_x = center_screen_x + (dx * tile_half_width); - int screen_y = center_screen_y + (dy * tile_half_height); - draw_distribution_hub_yields (this, tile, tile_x, tile_y, screen_x, screen_y); - } - } - } - -skip_district_yields: - if (changed_clip_area) - clear_clip_area (this); -} - -bool __fastcall -patch_City_Form_draw_highlighted_yields (City_Form * this, int edx, int tile_x, int tile_y, int neighbor_index) -{ - // Make sure we don't draw outside the map area - bool changed_clip_area = false; - if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { - set_clip_area_to_map_view (this); - changed_clip_area = true; - } - - bool tr = City_Form_draw_highlighted_yields (this, __, tile_x, tile_y, neighbor_index); - - if (changed_clip_area) - clear_clip_area (this); - return tr; -} - -void __fastcall -patch_City_Form_draw_border_around_workable_tiles (City_Form * this) -{ - // Make sure we don't draw outside the map area - bool changed_clip_area = false; - if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { - set_clip_area_to_map_view (this); - changed_clip_area = true; - } - - City_Form_draw_border_around_workable_tiles (this); - - if (changed_clip_area) - clear_clip_area (this); -} - -bool __fastcall -patch_City_stop_working_polluted_tile (City * this, int edx, int neighbor_index) -{ - if (is->current_config.do_not_unassign_workers_from_polluted_tiles && - (*p_human_player_bits & (1 << this->Body.CivID))) - return false; // do nothing; return value is not used - else - return City_stop_working_tile (this, __, neighbor_index); -} - -void __fastcall -patch_City_manage_by_governor (City * this, int edx, bool manage_professions) -{ - int * p_stack = (int *)&manage_professions; - int ret_addr = p_stack[-1]; - - // Do nothing if called after spawning pollution but didn't unassign worker - if ((ret_addr == ADDR_MANAGE_CITY_AFTER_POLLUTION_RETURN) && - is->current_config.do_not_unassign_workers_from_polluted_tiles && - (*p_human_player_bits & (1 << this->Body.CivID))) - return; - - City_manage_by_governor (this, __, manage_professions); -} - -City * __cdecl -patch_find_nearest_city_for_ai_alliance_eval (int tile_x, int tile_y, int owner_id, int continent_id, int ignore_owner_id, int perspective_id, City * ignore_city) -{ - City * tr = find_nearest_city (tile_x, tile_y, owner_id, continent_id, ignore_owner_id, perspective_id, ignore_city); - if (is->current_config.patch_division_by_zero_in_ai_alliance_eval && (*p_nearest_city_distance == 0)) - *p_nearest_city_distance = 1; - return tr; -} - -int __fastcall -patch_Unit_get_max_move_points (Unit * this) -{ - if (Unit_has_ability (this, __, UTA_Army) && is->current_config.patch_empty_army_movement) { - int slowest_member_mp = INT_MAX; - bool any_units_in_army = false; - FOR_UNITS_ON (uti, tile_at (this->Body.X, this->Body.Y)) { - if (uti.unit->Body.Container_Unit == this->Body.ID) { - any_units_in_army = true; - slowest_member_mp = not_above (Unit_get_max_move_points (uti.unit), slowest_member_mp); - } - } - if (any_units_in_army) - return slowest_member_mp + p_bic_data->General.RoadsMovementRate; - else - return get_max_move_points (&p_bic_data->UnitTypes[this->Body.UnitTypeID], this->Body.CivID); - } else - return Unit_get_max_move_points (this); -} - -char __fastcall -patch_Unit_is_visible_to_civ_for_bouncing (Unit * this, int edx, int civ_id, int param_2) -{ - // If we're set not to kick out invisible units and this one is invis. then report that it's not seen so it's left alone - if (is->do_not_bounce_invisible_units && Unit_has_ability (this, __, UTA_Invisible)) - return 0; - else - return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); -} - -void __fastcall -patch_Leader_make_peace (Leader * this, int edx, int civ_id) -{ - Leader_make_peace (this, __, civ_id); - - if (is->current_config.disallow_trespassing && - (! this->At_War[civ_id]) && // Make sure the war actually ended - ((this->Relation_Treaties[civ_id] & 2) == 0)) { // Check right of passage (just in case) - is->do_not_bounce_invisible_units = true; - Leader_bounce_trespassing_units (&leaders[civ_id], __, this->ID); - is->do_not_bounce_invisible_units = false; - } -} - -// This patch function replaces calls to Leader::count_wonders_with_flag but is only valid in cases where it only matters whether the return value is -// zero or non-zero. This function will not return the actual count, just zero if no wonders are present and some >0 value if there is at least one. -int __fastcall -patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) -{ - int tr = Leader_count_wonders_with_flag (this, __, flag, only_in_city); - - if ((tr == 0) && - (only_in_city == NULL) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player - - // Sum up wonders owned by other human players - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->ID)) - if (Leader_count_wonders_with_flag (&leaders[n_player], __, flag, only_in_city) > 0) { - tr = 1; - break; - } - player_bits >>= 1; - n_player++; - } - } - - return tr; -} - -int __fastcall -patch_Leader_count_wonders_with_flag_ignore_great_wall (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) -{ - if (is->current_config.enable_districts && - is->current_config.enable_great_wall_districts && - is->current_config.disable_great_wall_city_defense_bonus && - flag == ITW_Doubles_City_Defenses) - return 0; - - return patch_Leader_count_any_shared_wonders_with_flag (this, __, flag, only_in_city); -} - -int const shared_small_wonder_flags = - ITSW_Increases_Chance_of_Leader_Appearance | - ITSW_Build_Larger_Armies | - ITSW_Treasury_Earns_5_Percent | - ITSW_Decreases_Success_Of_Missile_Attacks | - ITSW_Allows_Spy_Missions | - ITSW_Allows_Healing_In_Enemy_Territory | - ITSW_Requires_Victorous_Army | - ITSE_Requires_Elite_Naval_Units; - - -int __fastcall -patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) -{ - int tr = Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); - - // If "this" is a human player who's sharing wonders in hotseat and the flag is one of the ones that gets shared, include the wonders owned by - // all other humans in the game - if ((city_or_null == NULL) && - (flag & shared_small_wonder_flags) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player - - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->ID)) - tr += Leader_count_wonders_with_small_flag (&leaders[n_player], __, flag, city_or_null); - player_bits >>= 1; - n_player++; - } - } - - return tr; -} - -int -find_human_player_with_small_wonder (int improv_id) -{ - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if (player_bits & 1) - if (leaders[n_player].Small_Wonders[improv_id] != -1) - return n_player; - player_bits >>= 1; - n_player++; - } - return -1; -} - -bool __fastcall -patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2) -{ - Improvement * improv = &p_bic_data->Improvements[i_improv]; - bool restore = false; - bool already_shared = false; - int saved_status, saved_required_building_count, saved_armies_count; - if ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) && // if the improv in question is a great or small wonder - is->current_config.share_wonders_in_hotseat && // if we're configured to share wonder effects - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // if in a hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // if "this" is a human player - - // If another human player has already built this small wonder and it has no non-shared effects, then make it unbuildable - if ((improv->Characteristics & ITC_Small_Wonder) && - (find_human_player_with_small_wonder (i_improv) != -1) && - ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) - already_shared = true; - - else { - restore = true; - saved_status = this->Status; - if (improv->RequiredBuildingID != -1) - saved_required_building_count = this->Improvement_Counts[improv->RequiredBuildingID]; - saved_armies_count = this->Armies_Count; - - // Loop over all other human players in the game - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->ID)) { - - // Combine status bits - this->Status |= leaders[n_player].Status & (LSF_HAS_VICTORIOUS_ARMY | LSF_HAS_ELITE_NAVAL_UNIT); - - // Combine building counts for the required building if there is one - if (improv->RequiredBuildingID != -1) - this->Improvement_Counts[improv->RequiredBuildingID] += leaders[n_player].Improvement_Counts[improv->RequiredBuildingID]; - - // Combine army counts - this->Armies_Count += leaders[n_player].Armies_Count; - - } - player_bits >>= 1; - n_player++; - } - } - } - - bool tr = (! already_shared) && Leader_can_build_city_improvement (this, __, i_improv, param_2); - - if (restore) { - this->Status = saved_status; - if (improv->RequiredBuildingID != -1) - this->Improvement_Counts[improv->RequiredBuildingID] = saved_required_building_count; - - this->Armies_Count = saved_armies_count; - } - return tr; - -} - -void __fastcall -patch_City_add_happiness_from_buildings (City * this, int edx, int * inout_happiness, int * inout_unhappiness) -{ - // If we're in a hotseat game with shared wonder effects, merge all human player's improvement counts together so the base function checks for - // happiness from improvements owned by other human players. - Leader * owner = &leaders[this->Body.CivID]; - bool restore_improv_counts = false; - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->Body.CivID) & *p_human_player_bits)) { // "this" is owned by a human player - - // Ensure the space we've set aside for saving the real improv counts is large enough - if ((is->saved_improv_counts == NULL) || (is->saved_improv_counts_capacity < p_bic_data->ImprovementsCount)) { - free (is->saved_improv_counts); - is->saved_improv_counts = calloc (p_bic_data->ImprovementsCount, sizeof is->saved_improv_counts[0]); - is->saved_improv_counts_capacity = (is->saved_improv_counts != NULL) ? p_bic_data->ImprovementsCount : 0; - } - - - if (is->saved_improv_counts != NULL) { - // Save the owner's real improv counts and remember to restore them before returning - restore_improv_counts = true; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - is->saved_improv_counts[n] = owner->Improvement_Counts[n]; - - // Add in improv counts for wonders from all other human players in the game - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != owner->ID)) - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (p_bic_data->Improvements[n].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - owner->Improvement_Counts[n] += leaders[n_player].Improvement_Counts[n]; - player_bits >>= 1; - n_player++; - } - } - - } - - City_add_happiness_from_buildings (this, __, inout_happiness, inout_unhappiness); - - if (is->current_config.enable_districts) { - int district_happy = 0; - calculate_district_happiness_bonus (this, &district_happy); - - if (district_happy != 0) - *inout_happiness += district_happy; - } - - if (restore_improv_counts) { - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - owner->Improvement_Counts[n] = is->saved_improv_counts[n]; - } -} - -int __fastcall -patch_City_count_other_cont_happiness_buildings (City * this, int edx, int improv_id) -{ - int tr = City_count_other_buildings_on_continent (this, __, improv_id); - - // If it's a hotseat game where we're sharing wonders, "improv_id" refers to a wonder, and "this" is owned by a human player - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((p_bic_data->Improvements[improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && - ((1 << this->Body.CivID) & *p_human_player_bits)) { - - // Add in instances of this improvment on this continent owned by other human players - Tile * this_city_tile = tile_at (this->Body.X, this->Body.Y); - int this_cont_id = this_city_tile->vtable->m46_Get_ContinentID (this_city_tile); - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city != NULL) && (city != this) && - (city->Body.CivID != this->Body.CivID) && // if city is owned by a different player AND - ((1 << city->Body.CivID) & *p_human_player_bits)) { // that player is a human - Tile * that_city_tile = tile_at (city->Body.X, city->Body.Y); - int that_cont_id = that_city_tile->vtable->m46_Get_ContinentID (that_city_tile); - if ((this_cont_id == that_cont_id) && patch_City_has_improvement (city, __, improv_id, true)) - tr++; - } - } - - } - - return tr; -} - -void __fastcall -patch_Leader_update_great_library_unlocks (Leader * this) -{ - // If it's a hotseat game with shared wonder effects and "this" is a human player, share contacts among all human players so that "this" gets - // techs from civs known to any human player in the game. Save the real contact info and restore it afterward. NOTE: Contact info has to go - // two ways here; we must mark that "this" has contacted the AIs and vice-versa otherwise the techs won't be granted. That's why we must save - // & restore all contact bits for all players. - bool restore_contacts = false; - struct contact_set { - int contacts[32]; - } saved_contact_sets[32]; - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player - - restore_contacts = true; - for (int n = 0; n < 32; n++) - for (int k = 0; k < 32; k++) - saved_contact_sets[n].contacts[k] = leaders[n].Contacts[k]; - - unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_human = 1; - while (human_player_bits != 0) { - if ((human_player_bits & 1) && (n_human != this->ID)) // n_human is ID of a human player other than "this" - for (int n_ai = 0; n_ai < 32; n_ai++) - if ((*p_player_bits & (1 << n_ai)) && ((*p_human_player_bits & (1 << n_ai)) == 0)) { - // If the human and AI players have contact, mark "this" as having contact with the AI and vice-versa - if (leaders[n_human].Contacts[n_ai] & 1) { - this->Contacts[n_ai] |= 1; - leaders[n_ai].Contacts[this->ID] |= 1; - } - } - human_player_bits >>= 1; - n_human++; - } - } - - Leader_update_great_library_unlocks (this); - - if (restore_contacts) - for (int n = 0; n < 32; n++) - for (int k = 0; k < 32; k++) - leaders[n].Contacts[k] = saved_contact_sets[n].contacts[k]; -} - -bool __fastcall -patch_Leader_has_wonder_doubling_happiness_from (Leader * this, int edx, int improv_id) -{ - bool tr = Leader_has_wonder_doubling_happiness_from (this, __, improv_id); - - // If we're sharing wonder effects in a hotseat game and "this" is a human player, return true when another human player in the game has a - // wonder doubling happiness - if ((! tr) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player - unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_human = 1; - while (human_player_bits != 0) { - if ((human_player_bits & 1) && - (n_human != this->ID) && - Leader_has_wonder_doubling_happiness_from (&leaders[n_human], __, improv_id)) { - tr = true; - break; - } - human_player_bits >>= 1; - n_human++; - } - } - - return tr; -} - -int __fastcall -patch_Sprite_draw_citizen_head (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - // Reset variable - is->specialist_icon_drawing_running_x = INT_MIN; - - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -int -adjust_specialist_yield_icon_x (int pixel_x, int width) -{ - if (is->current_config.fix_overlapping_specialist_yield_icons) { - if (is->specialist_icon_drawing_running_x == INT_MIN) // first icon drawn - is->specialist_icon_drawing_running_x = pixel_x; - int tr = is->specialist_icon_drawing_running_x; - is->specialist_icon_drawing_running_x += width; - return tr; - } else - return pixel_x; -} - -int __fastcall -patch_Sprite_draw_entertainer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_12_Happy_Faces.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_scientist_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_16_Science.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_tax_collector_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_14_Gold.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_civil_engineer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_13_Shield.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_police_officer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_17_Gold_Outcome.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} - -void __fastcall -patch_City_add_building_if_done (City * this) -{ - // If sharing small wonders in hotseat, check whether the city is building a small wonder that's no longer available to the player b/c its - // effects are provided from another. - int improv_id = this->Body.Order_ID; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - int already_built_by_id; - if ((improv->Characteristics & ITC_Small_Wonder) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->Body.CivID) & *p_human_player_bits) && // city owned by a human player - ((already_built_by_id = find_human_player_with_small_wonder (improv_id)) != -1) && // SW already built by another human player - ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) { // SW has no non-shared effects - - // Switch city production to something else and notify the player - this->vtable->set_production_to_most_expensive_option (this); - if ((this->Body.CivID == p_main_screen_form->Player_CivID) && (already_built_by_id != p_main_screen_form->Player_CivID)) { - char * new_build_name = (this->Body.Order_Type == COT_Improvement) ? - p_bic_data->Improvements[this->Body.Order_ID].Name.S : - p_bic_data->UnitTypes[this->Body.Order_ID].Name; - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, this->Body.CityName, -1, -1); - set_popup_str_param (1, improv->Name.S, -1, -1); - set_popup_str_param (2, Leader_get_civ_noun (&leaders[already_built_by_id]), -1, -1); - set_popup_str_param (3, new_build_name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_SHARED_WONDER_CHANGE", -1, 0, 0, 0); - int response = patch_show_popup (popup, __, 0, 0); - if (response == 0) - *p_zoom_to_city_after_update = true; - } - - // As in the base logic, if production gets switched, the game doesn't check if it might still complete on the same turn. - return; - } - - // If production ended up on a wonder, make sure the city can actually build it; otherwise fall back to a defensive unit. - int order_type = this->Body.Order_Type; - int order_id = this->Body.Order_ID; - if (is->current_config.enable_districts && order_type == COT_Improvement) { - Improvement * new_improv = &p_bic_data->Improvements[order_id]; // Improvement might have changed - if (new_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { - if (! (City_can_build_improvement (this, __, order_id, false) && city_meets_district_prereqs_to_build_improvement (this, order_id, true))) { - char ss[256]; - snprintf (ss, sizeof ss, "patch_City_add_building_if_done: City '%s' cannot complete building of wonder '%s'; switching to defensive unit.\n", - this->Body.CityName, - new_improv->Name.S); - (*p_OutputDebugStringA) (ss); - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (this, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) { - City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); - return; - } - } - } - } - } - - City_add_building_if_done (this); -} - -bool __fastcall -patch_City_can_build_upgrade_type (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) -{ - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - if (is->current_config.prevent_old_units_from_upgrading_past_ability_block && - ((type->Special_Actions & UCV_Upgrade_Unit) == 0) && - (type->Available_To & (1 << leaders[this->Body.CivID].RaceID))) - exclude_upgradable = false; - - return patch_City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); -} - -void __fastcall -patch_Main_GUI_position_elements (Main_GUI * this) -{ - Main_GUI_position_elements (this); - - // Double size of minimap if configured - bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || - ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); - if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) { - this->Mini_Map_Click_Rect.top -= 105; - this->Mini_Map_Click_Rect.right += 229; - } -} - -#define PEDIA_DESC_LINES_PER_PAGE 38 - -// Returns whether or not the line should be drawn -bool -do_next_line_for_pedia_desc (PCX_Image * canvas, int * inout_y) -{ - if (is->cmpd.drawing_lines && is->current_config.allow_multipage_civilopedia_descriptions) { - int first_line_on_shown_page = is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE; - int page = is->cmpd.line_count / PEDIA_DESC_LINES_PER_PAGE; - is->cmpd.line_count += 1; - is->cmpd.last_page = (page > is->cmpd.last_page) ? page : is->cmpd.last_page; - - if (page == is->cmpd.shown_page) { - *inout_y -= is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE * PCX_Image_get_text_line_height (canvas); - return true; - } else - return false; - } - return true; -} - -int __fastcall -patch_PCX_Image_do_draw_centered_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) -{ - if (do_next_line_for_pedia_desc (this, &y)) - return PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); - else - return 0; // Caller does not use return value -} - -int __fastcall -patch_PCX_Image_draw_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int str_len) -{ - if (do_next_line_for_pedia_desc (this, &y)) - return PCX_Image_draw_text (this, __, str, x, y, str_len); - else - return PCX_Image_draw_text (this, __, " ", x, y, 1); // Caller uses the return value here so draw an empty string isntead of doing nothing -} - -// Steam code is slightly different; this no-len version of draw_text gets called sometimes. It's the same as draw_text instead it computes the string -// length itself instead of taking it in as a parameter. -int __fastcall -patch_PCX_Image_draw_text_no_len_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y) -{ - return patch_PCX_Image_draw_text_in_wrap_func (this, __, str, x, y, strlen (str)); -} - -void -draw_civilopedia_article (void (__fastcall * base) (Civilopedia_Article *), Civilopedia_Article * article) -{ - // If the article changed then clear things from the old one - if (is->cmpd.article != article) { - is->cmpd.last_page = 0; - is->cmpd.shown_page = 0; - is->cmpd.article = article; - } - - is->cmpd.line_count = 0; - is->cmpd.drawing_lines = article->show_description; - - base (article); - - is->cmpd.drawing_lines = false; -} - -void __fastcall -patch_Civilopedia_Article_m01_Draw_GCON_or_RACE (Civilopedia_Article * this) -{ - draw_civilopedia_article (Civilopedia_Article_m01_Draw_GCON_or_RACE, this); -} - -void -print_pedia_unit_stats (PCX_Image * canvas, int x, char ** entries, int entry_count) -{ - // Same forumula as the base game. Shifts entries upward if 4 or more. - int y = (entry_count > 3) ? 4 * (3 * entry_count - 9) : 0; - y = 449 - y; - - for (int n = 0; n < entry_count; n++) - y = PCX_Image_draw_and_wrap_text (canvas, __, entries[n], x, y, 150); -} - -void __fastcall -patch_Civilopedia_Article_m01_Draw_UNIT (Civilopedia_Article * this) -{ - // Make sure list of second column stat strings is clear before drawing - char ** entries = is->pedia_unit_stats_second_column_strs; - int capacity = ARRAY_LEN (is->pedia_unit_stats_second_column_strs); - if (is->current_config.expand_civilopedia_unit_stats) - for (int n = 0; n < capacity; n++) { - free (entries[n]); - entries[n] = NULL; - } - - draw_civilopedia_article (Civilopedia_Article_m01_Draw_UNIT, this); - - bool drew_stats = this->show_description == false || this->more_text_line_count == 0; - if (is->current_config.expand_civilopedia_unit_stats && drew_stats) { - // By this point entries have been filled in for the second column of unit stats (see ...draw_pedia_unit_stats_2nd_column), which has - // not actually been drawn. - int entry_count = 0; - for (int n = 0; n < capacity; n++) - if (entries[n] != NULL) - entry_count++; - - char s[100] = {0}; - - // Add entry for op range if aircraft. The original game shows movement instead of op range in the first column but we patch that to - // show movement always. - if (entry_count < capacity && this->unit_type->Unit_Class == UTC_Air) { - // Reserve spot at entries[0] to prepend new item - for (int n = capacity - 1; n > 0; n--) - entries[n] = entries[n-1]; - entry_count++; - - snprintf (s, (sizeof s) - 1, "%s: %d", (*p_labels)[LBL_OPERATIONAL_RANGE], this->unit_type->OperationalRange); - entries[0] = strdup (s); - } - - // Add bombard range if tactical nuke with bombard strength == 0 because the base game won't display it - if (entry_count < capacity && - this->unit_type->Unit_Class == UTC_Land && - this->unit_type->Bombard_Strength == 0 && - UnitType_has_ability (this->unit_type, __, UTA_Nuclear_Weapon) && - UnitType_has_ability (this->unit_type, __, UTA_Tacticle_Missile)) { - snprintf (s, (sizeof s) - 1, "%s: %d", (*p_labels)[LBL_BOMBARD_RANGE], this->unit_type->Bombard_Range); - entries[entry_count++] = strdup (s); - } - - // Add HP Bonus - if (entry_count < capacity && this->unit_type->Hit_Point_Bonus != 0) { - snprintf (s, (sizeof s) - 1, "%s: %d", is->c3x_labels[CL_HP_BONUS], this->unit_type->Hit_Point_Bonus); - entries[entry_count++] = strdup (s); - } - - // Add worker strength - int rounded_worker_strength = ((int)(this->unit_type->WorkerStrength * 10000.0f) + 50) / 100; - if (entry_count < capacity && rounded_worker_strength != 0) { - snprintf (s, (sizeof s) - 1, "%s: %d%%", is->c3x_labels[CL_WORKER_STRENGTH], rounded_worker_strength); - entries[entry_count++] = strdup (s); - } - - if (entry_count <= 6) - print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 213, entries, entry_count); - else { // If more than 6 entries, split some off into a third column - int third_count = entry_count / 2, - second_count = entry_count - third_count; - print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 198, entries, second_count); - print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 355, &entries[second_count], third_count); - } - } -} - -int __fastcall -patch_PCX_Image_draw_pedia_unit_stats_2nd_column (PCX_Image * this, int edx, char * str, int x, int y, int width) -{ - if (is->current_config.expand_civilopedia_unit_stats) - for (int n = 0; n < ARRAY_LEN (is->pedia_unit_stats_second_column_strs); n++) - if (is->pedia_unit_stats_second_column_strs[n] == NULL) { - is->pedia_unit_stats_second_column_strs[n] = strdup (str); // Record what would have been drawn here - str = " "; // Draw empty string. Can't skip draw call entirely b/c we need the return value - break; - } - - return PCX_Image_draw_and_wrap_text (this, __, str, x, y, width); -} - -void __fastcall -patch_Civilopedia_Form_m53_On_Control_Click (Civilopedia_Form * this, int edx, CivilopediaControlID control_id) -{ - Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; - - // "Effects" button leaves description mode, returns to showing effects - if ((control_id == PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID) && (current_article != NULL)) { - current_article->show_description = false; - is->cmpd.shown_page = 0; - play_sound_effect (26); // 26 = SE_SELECT - p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); - - // "Previous" button shows the previous page of a multi-page description or switches to effects mode if on the first page - } else if (control_id == PEDIA_MULTIPAGE_PREV_BUTTON_ID) { - if (is->cmpd.shown_page > 0) - is->cmpd.shown_page -= 1; - else - current_article->show_description = false; - play_sound_effect (26); - p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); - - } else if ((control_id == CCID_DESCRIPTION_BTN) && // if description/more/prev button was clicked AND - (current_article != NULL) && current_article->show_description && // currently showing a description of an article AND - (is->cmpd.last_page > 0)) { // this is a multi-page description - - // Show the next page of the multi-page description unless it's a two-page description and we're on the second page, in which case go - // back to the first. - if ((is->cmpd.last_page == 1) && (is->cmpd.shown_page == 1)) - is->cmpd.shown_page = 0; - else - is->cmpd.shown_page = not_above (is->cmpd.last_page, is->cmpd.shown_page + 1); - play_sound_effect (26); - p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); - - } else - Civilopedia_Form_m53_On_Control_Click (this, __, control_id); -} - -void __fastcall -patch_Civilopedia_Form_m22_Draw (Civilopedia_Form * this) -{ - // Make sure the new buttons are not visible and the multipage variables are cleared when we exit description mode - if ((this->Current_Article_ID < 0) || ! this->Articles[this->Current_Article_ID]->show_description) { - is->cmpd.shown_page = is->cmpd.last_page = 0; - if (is->cmpd.effects_btn != NULL) - is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); - if (is->cmpd.previous_btn != NULL) - is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); - } - - Civilopedia_Form_m22_Draw (this); -} - -int __fastcall -patch_Button_initialize_civilopedia_description (Button * this, int edx, char * text, int control_id, int x, int y, int width, int height, Base_Form * parent, int param_8) -{ - Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; - if (current_article == NULL) - return Button_initialize (this, __, text, control_id, x, y, width, height, parent, param_8); - - // Set button visibility for multi-page descriptions if we're showing such a thing right now - bool show_desc_btn = true, show_effects_btn = false, show_previous_btn = false; - char * desc_btn_text = text; - if (current_article->show_description && (is->cmpd.last_page > 0)) { - - // Tribe articles act like one long descripton. - if ((current_article->article_kind == CAK_TRIBE) || (current_article->article_kind == CAK_GAME_CONCEPT)) { - - // Show the more button as long as we're not on the last page. Show the previous always since we're in description mode. - show_previous_btn = true; - desc_btn_text = (*p_labels)[LBL_MORE]; - if (is->cmpd.shown_page >= is->cmpd.last_page) - show_desc_btn = false; - - // Unit articles have separate description/effects modes. - } else if (current_article->article_kind == CAK_UNIT) { - - // For a two-page description, show the effects button and the description button which will act as a next/previous button - if (is->cmpd.last_page == 1) { - show_effects_btn = true; - desc_btn_text = is->cmpd.shown_page == 0 ? (*p_labels)[LBL_MORE] : (*p_labels)[LBL_PREVIOUS]; - - // For a three or more page description, show the effects button, and show the description button only if we're not on the - // last page (b/c it's the next button), and show the previous button only if we're not on the first page. If the desc button - // is visible, make it say "More". - } else { - show_effects_btn = true; - if (is->cmpd.shown_page >= is->cmpd.last_page) - show_desc_btn = false; - else - desc_btn_text = (*p_labels)[LBL_MORE]; - show_previous_btn = is->cmpd.shown_page > 0; - } - } - } - - int tr = Button_initialize (this, __, desc_btn_text, control_id, x, y, width, height, parent, param_8); - - if (! show_desc_btn) - this->vtable->m02_Show_Disabled ((Base_Form *)this); - - if (is->cmpd.effects_btn != NULL) { - if (show_effects_btn) - is->cmpd.effects_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.effects_btn, __, 0); - else - is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); - } - - if (is->cmpd.previous_btn != NULL) { - if (show_previous_btn) - is->cmpd.previous_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.previous_btn, __, 0); - else - is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); - } - - return tr; -} - -int __fastcall -patch_Civilopedia_Form_m68_Show_Dialog (Civilopedia_Form * this, int edx, int param_1, void * param_2, void * param_3) -{ - memset (&is->cmpd, 0, sizeof is->cmpd); - - Button * bs[] = {malloc (sizeof Button), malloc (sizeof Button)}; - for (int n = 0; n < ARRAY_LEN (bs); n++) { - if (bs[n] == NULL) - continue; - Button_construct (bs[n]); - - int desc_btn_x = 535, desc_btn_y = 222, desc_btn_height = 17; - - Button_initialize (bs[n], __, - n == 0 ? (*p_labels)[LBL_EFFECTS] : (*p_labels)[LBL_PREVIOUS], - n == 0 ? PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID : PEDIA_MULTIPAGE_PREV_BUTTON_ID, // control ID - desc_btn_x, // location x - desc_btn_y + (n == 0 ? -2 : 2) * desc_btn_height, // location y - MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height - (Base_Form *)this, // parent - 0); // ? - - for (int k = 0; k < 3; k++) - bs[n]->Images[k] = &this->Description_Btn_Images[k]; - - // Do now draw the button until needed - bs[n]->vtable->m02_Show_Disabled ((Base_Form *)bs[n]); - } - is->cmpd.effects_btn = bs[0]; - is->cmpd.previous_btn = bs[1]; - - int tr = Civilopedia_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); - - for (int n = 0; n < ARRAY_LEN (bs); n++) - if (bs[n] != NULL) { - bs[n]->vtable->destruct ((Base_Form *)bs[n], __, 0); - free (bs[n]); - } - is->cmpd.effects_btn = is->cmpd.previous_btn = NULL; - - return tr; -} - -void -init_district_images () -{ - if (is_online_game () || is->dc_img_state != IS_UNINITED) - return; - - char art_dir[200]; - char temp_path[2*MAX_PATH]; - - is->dc_img_state = IS_INIT_FAILED; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - // For each district type - for (int dc = 0; dc < is->district_count; dc++) { - struct district_config const * cfg = &is->district_configs[dc]; - int variant_count = cfg->img_path_count; - if (variant_count <= 0) - continue; - - int era_count = cfg->vary_img_by_era ? 4 : 1; - int column_count = cfg->img_column_count; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - - // For each cultural variant - for (int variant_i = 0; variant_i < variant_count; variant_i++) { - if (cfg->img_paths[variant_i] == NULL) - continue; - - // Read PCX file - snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", cfg->img_paths[variant_i]); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - - if (pcx.JGL.Image == NULL) { - - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load district images from %s", temp_path); - pop_up_in_game_error (ss); - - (*p_OutputDebugStringA) ("[C3X] Failed to load districts sprite sheet.\n"); - for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) - for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) - for (int era_i = 0; era_i < 4; era_i++) { - for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { - Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - } - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - // For each era - for (int era_i = 0; era_i < era_count; era_i++) { - - // For each column in the image (variations on the district image for that era) - for (int col_i = 0; col_i < column_count; col_i++) { - Sprite_construct (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i]); - - int x = sprite_width * col_i, - y = sprite_height * era_i; - Sprite_slice_pcx (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i], __, &pcx, x, y, sprite_width, sprite_height, 1, 1); - } - } - - pcx.vtable->clear_JGL (&pcx); - } - } - // Load abandoned district images (land + maritime) - get_mod_art_path ("Districts/1200/Abandoned.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - - if (pcx.JGL.Image == NULL) { - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load abandoned district images from %s", temp_path); - pop_up_in_game_error (ss); - for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) - for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) - for (int era_i = 0; era_i < 4; era_i++) { - for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { - Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - } - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - Sprite_construct (&is->abandoned_district_img); - Sprite_slice_pcx (&is->abandoned_district_img, __, &pcx, 0, 0, 128, 64, 1, 1); - - Sprite_construct (&is->abandoned_maritime_district_img); - Sprite_slice_pcx (&is->abandoned_maritime_district_img, __, &pcx, 128, 0, 128, 64, 1, 1); - pcx.vtable->clear_JGL (&pcx); - - // Load wonder district images (dynamically per wonder) - if (is->current_config.enable_wonder_districts) { - char const * last_img_path = NULL; - PCX_Image wpcx; - PCX_Image_construct (&wpcx); - bool pcx_loaded = false; - - for (int wi = 0; wi < is->wonder_district_count; wi++) { - struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; - char const * img_path = cfg->img_path; - if (img_path == NULL) - img_path = "Wonders.pcx"; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - - // Load new image file if different from previous - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - - snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - PCX_Image_read_file (&wpcx, __, temp_path, NULL, 0, 0x100, 2); - - if (wpcx.JGL.Image == NULL) { - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load wonder district images from %s", temp_path); - pop_up_in_game_error (ss); - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; - - Sprite_construct (&set->img); - int x = sprite_width * cfg->img_column; - int y = sprite_height * cfg->img_row; - Sprite_slice_pcx (&set->img, __, &wpcx, x, y, sprite_width, sprite_height, 1, 1); - - Sprite_construct (&set->construct_img); - int cx = sprite_width * cfg->img_construct_column; - int cy = sprite_height * cfg->img_construct_row; - Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, sprite_width, sprite_height, 1, 1); - - if (cfg->enable_img_alt_dir) { - Sprite_construct (&set->alt_dir_img); - int ax = sprite_width * cfg->img_alt_dir_column; - int ay = sprite_height * cfg->img_alt_dir_row; - Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, sprite_width, sprite_height, 1, 1); - - Sprite_construct (&set->alt_dir_construct_img); - int acx = sprite_width * cfg->img_alt_dir_construct_column; - int acy = sprite_height * cfg->img_alt_dir_construct_row; - Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, sprite_width, sprite_height, 1, 1); - } - } - - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - wpcx.vtable->destruct (&wpcx, __, 0); - } - - if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { - char const * last_img_path = NULL; - PCX_Image nwpcx; - PCX_Image_construct (&nwpcx); - bool pcx_loaded = false; - - for (int ni = 0; ni < is->natural_wonder_count; ni++) { - struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[ni]; - if (cfg->name == NULL) - continue; - - char const * img_path = cfg->img_path; - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - - snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - PCX_Image_read_file (&nwpcx, __, temp_path, NULL, 0, 0x100, 2); - - if (nwpcx.JGL.Image == NULL) { - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load natural wonder images from %s", temp_path); - pop_up_in_game_error (ss); - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - Sprite_construct (&is->natural_wonder_img_sets[ni].img); - int x = 128 * cfg->img_column; - int y = 88 * cfg->img_row; - Sprite_slice_pcx (&is->natural_wonder_img_sets[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); - } - - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - nwpcx.vtable->destruct (&nwpcx, __, 0); - } - - is->dc_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -bool -tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv) -{ - Tile * center = tile_at (tile_x, tile_y); - - if ((center == NULL) || (center == p_null_tile)) return false; - int owner_id = center->Territory_OwnerID; - if (owner_id <= 0) return false; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - if (has_active_building (wai.city, i_improv)) - return true; - } - - return false; -} - -bool -wonder_requires_river (struct wonder_district_config const * cfg) -{ - unsigned int build_mask = wonder_buildable_square_type_mask (cfg); - if (build_mask == 0) - build_mask = district_default_buildable_mask (); - if ((build_mask & square_type_mask_bit (SQ_RIVER)) != 0) - return true; - if (cfg->buildable_on_rivers) - return true; - return false; -} - -Tile * -get_tile_sprite_indices (int tile_x, int tile_y, int * out_sheet_index, int * out_sprite_index) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - - if (tile != NULL && tile != p_null_tile) { - *out_sheet_index = (tile->SquareParts >> 8) & 0xFF; - *out_sprite_index = tile->SquareParts & 0xFF; - } else { - *out_sheet_index = -1; - *out_sprite_index = -1; - } - - return tile; -} - -void -align_district_with_river (Tile * tile, int * out_pixel_x, int * out_pixel_y, enum direction * out_dir) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return; - - enum direction dir = DIR_ZERO; - if (! get_primary_river_direction (tile, &dir)) - return; - - int dx, dy; - int offset = 36; - direction_to_offset (dir, &dx, &dy); - - dy = 0; - switch (dir) { - case DIR_N: dy = -offset; break; - case DIR_NE: dy = -offset/2; break; - case DIR_E: dy = 0; break; - case DIR_SE: dy = offset/2; break; - case DIR_S: dy = offset; break; - case DIR_SW: dy = offset/2; break; - case DIR_W: dy = 0; break; - case DIR_NW: dy = -offset/2; break; - default: break; - } - - if (out_pixel_x != NULL) - *out_pixel_x += dx; - if (out_pixel_y != NULL) - *out_pixel_y += dy; - if (out_dir != NULL) - *out_dir = dir; -} - -void -align_variant_and_pixel_offsets_with_coastline (Tile * tile, int * out_variant, int * out_pixel_x, int * out_pixel_y) -{ - if ((tile == NULL) || (tile == p_null_tile) || (out_variant == NULL)) - return; - - int owner_id = tile->Territory_OwnerID; - if (owner_id <= 0) - return; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return; - - int tile_x = inst->tile_x; - int tile_y = inst->tile_y; - Map * map = &p_bic_data->Map; - - City * closest_city = NULL; - int closest_dx = 0, closest_dy = 0; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - City * city = wai.city; - int ndx = city->Body.X - tile_x; - int ndy = city->Body.Y - tile_y; - - if (map->Flags & 1) { - int half_width = map->Width / 2; - if (ndx > half_width) - ndx -= map->Width; - else if (ndx < -half_width) - ndx += map->Width; - } - if (map->Flags & 2) { - int half_height = map->Height / 2; - if (ndy > half_height) - ndy -= map->Height; - else if (ndy < -half_height) - ndy += map->Height; - } - - closest_city = city; - closest_dx = ndx; - closest_dy = ndy; - break; - } - - if (closest_city == NULL) - return; - - bool city_is_directly_above_port = (closest_dx == 0) && (closest_dy == -2); - bool city_is_directly_below_port = (closest_dx == 0) && (closest_dy == 2); - bool city_is_directly_west_of_port = (closest_dx < 0) && (closest_dy == 0); - bool city_is_directly_east_of_port = (closest_dx > 0) && (closest_dy == 0); - bool city_is_directly_northeast_of_port = (closest_dx == 1) && (closest_dy == -1); - bool city_is_directly_southeast_of_port = (closest_dx == 1) && (closest_dy == 1); - bool city_is_directly_southwest_of_port = (closest_dx == -1) && (closest_dy == 1); - bool city_is_directly_northwest_of_port = (closest_dx == -1) && (closest_dy == -1); - - // Variant indices; can't use direction enum as values are slightly different - int NONE = -1; - int NW = 0; - int NE = 1; - int SE = 2; - int SW = 3; - *out_variant = NONE; - - enum direction anchor = NONE; - bool direct_diagonal = false; - - // Direct diagonals - if (city_is_directly_northeast_of_port) { *out_variant = SW; anchor = DIR_NE; direct_diagonal = true; } - else if (city_is_directly_southeast_of_port) { *out_variant = NW; anchor = DIR_SE; direct_diagonal = true; } - else if (city_is_directly_southwest_of_port) { *out_variant = NE; anchor = DIR_SW; direct_diagonal = true; } - else if (city_is_directly_northwest_of_port) { *out_variant = SE; anchor = DIR_NW; direct_diagonal = true; } - - // City either in a direct cardinal direction or not adjacent, check relative directions - else { - bool city_is_west_of_port = (closest_dx < 0); - bool city_is_east_of_port = (closest_dx > 0); - bool city_is_north_of_port = (closest_dy < 0); - bool city_is_south_of_port = (closest_dy > 0); - bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, true); - bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, true); - bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); - bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); - bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); - bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, true); - bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, true); - bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, true); - - if (city_is_directly_above_port) { - if (northwest_tile_is_land && ! tile_is_land (owner_id, tile_x + 1, tile_y + 1, true)) { - *out_variant = SE; anchor = DIR_NW; - } else if (northeast_tile_is_land && ! tile_is_land (owner_id, tile_x - 1, tile_y + 1, true)) { - *out_variant = SW; anchor = DIR_NE; - } else { - *out_variant = SW; anchor = DIR_NE; - *out_pixel_x -= 4; *out_pixel_y -= 4; - } - } else if (city_is_directly_below_port) { - if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else { - *out_variant = NE; anchor = DIR_SW; - *out_pixel_x += 4; *out_pixel_y += 4; - } - } else if (city_is_directly_west_of_port) { - if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else { - *out_variant = SE; anchor = DIR_NW; - *out_pixel_x -= 30; *out_pixel_y += 24; - } - } else if (city_is_directly_east_of_port) { - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else { - *out_variant = SW; anchor = DIR_NE; - *out_pixel_x += 30; *out_pixel_y -= 24; - } - } else if (city_is_north_of_port && city_is_west_of_port) { - if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - } else if (city_is_north_of_port && city_is_east_of_port) { - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - } else if (city_is_south_of_port && city_is_east_of_port) { - if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - } else if (city_is_south_of_port && city_is_west_of_port) { - if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - } - - // No ideal direction, pick based on any owner land tiles around port - if (*out_variant == NONE) { - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } - else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } - else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } - else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } - } - - // Same civ doesn't own any adjacent land tiles, pick based on *any* land tiles - if (*out_variant == NONE) { - bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); - bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); - bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); - bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); - bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); - bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); - bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); - bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } - else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } - else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } - else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } - else { *out_variant = SW; anchor = DIR_NE; } // Somehow no land tiles at all? Default to NE - } - } - - Tile * anchor_tile; - int anchor_sheet_index, anchor_sprite_index; - switch (anchor) { - case DIR_N: anchor_tile = get_tile_sprite_indices (tile_x, tile_y - 2, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_NE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_E: anchor_tile = get_tile_sprite_indices (tile_x + 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_SE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_S: anchor_tile = get_tile_sprite_indices (tile_x, tile_y + 2, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_SW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_W: anchor_tile = get_tile_sprite_indices (tile_x - 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_NW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; - default: anchor_sheet_index = -1; anchor_sprite_index = -1; break; - } - - bool anchor_is_hill = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Hills; - bool anchor_is_mountain = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Mountains; - - // Determine general pixel offsets based on direction & anchor - if (*out_variant == SW && anchor == DIR_NE) { *out_pixel_x -= 0; *out_pixel_y += 6; } - else if (*out_variant == SE && anchor == DIR_NW) { *out_pixel_x -= 2; *out_pixel_y += 6; } - else if (*out_variant == NW && anchor == DIR_SE) { *out_pixel_x -= 0; *out_pixel_y -= 2; } - else if (*out_variant == SW && anchor == DIR_N) { *out_pixel_x -= 56; *out_pixel_y -= 26; } - else if (*out_variant == SW && anchor == DIR_E) { *out_pixel_x += 36; *out_pixel_y += 18; } - else if (*out_variant == NE && anchor == DIR_S) { *out_pixel_x += 70; *out_pixel_y += 30; } - else if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 14; } - - // Handle edge cases. Tedious, but looks quite a bit better so worth it - if (! (anchor_is_hill || anchor_is_mountain) && ! direct_diagonal) { - if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 20; } - - // Sheet 0 - if (anchor_sheet_index == 0) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 32; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 32; } - - if ((*out_variant == NE || *out_variant == NW) && anchor == DIR_S && anchor_sprite_index == 26) { *out_pixel_x -= 4; *out_pixel_y += 30; } - else if (*out_variant == NE && anchor == DIR_SW && anchor_sprite_index == 20) { *out_pixel_x -= 2; *out_pixel_y += 4; } - - if (*out_variant == SW && (anchor_sprite_index == 0 || anchor_sprite_index == 4 || anchor_sprite_index == 10 || anchor_sprite_index == 1)) { *out_pixel_x +=2; *out_pixel_y -= 8; } - else if (*out_variant == SW && anchor == DIR_N && (anchor_sprite_index == 6)) { *out_pixel_x -= 6; *out_pixel_y -= 8; } - else if (*out_variant == SE && anchor == DIR_W && (anchor_sprite_index == 18)) { *out_pixel_x += 6; *out_pixel_y += 4; } - else if (*out_variant == NE && anchor == DIR_SW && (anchor_sprite_index == 51)) { *out_pixel_x += 20; *out_pixel_y -= 20; } - else if (*out_variant == SW && anchor == DIR_NE && (anchor_sprite_index == 0)) { *out_pixel_x -= 4; *out_pixel_y += 4; } - else if (*out_variant == NW && anchor == DIR_SE && (anchor_sprite_index == 44)) { *out_pixel_x -= 8; *out_pixel_y -= 12; } - } - // Sheet 1 - else if (anchor_sheet_index == 1) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 10; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 10; } - - if (*out_variant == SW && (anchor_sprite_index == 7 || anchor_sprite_index == 17 || anchor_sprite_index == 16)) { *out_pixel_x +=10; *out_pixel_y -= 8; } - } - // Sheet 3 - else if (anchor_sheet_index == 2) { - if (*out_variant == SW && (anchor_sprite_index == 6)) { *out_pixel_x +=2; *out_pixel_y -= 8; } - } - // Sheet 3 - else if (anchor_sheet_index == 3) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 16; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 16; } - - if (*out_variant == SW && (anchor_sprite_index == 43 || anchor_sprite_index == 40)) { *out_pixel_x +=6; *out_pixel_y -= 12; } - else if (*out_variant == SW && (anchor_sprite_index == 35 || anchor_sprite_index == 39)) { *out_pixel_x +=6; *out_pixel_y -= 12; } - else if (*out_variant == SE && (anchor_sprite_index == 50)) { *out_pixel_x -=6; *out_pixel_y -= 12; } - else if (*out_variant == SE && (anchor_sprite_index == 26)) { *out_pixel_x += 50; *out_pixel_y -= 2; } - } - // Sheet 4 - else if (anchor_sheet_index == 4) { - if (*out_variant == SW && (anchor_sprite_index == 71)) { *out_pixel_x +=2; *out_pixel_y -= 8; } - } - // Sheet 5 - else if (anchor_sheet_index == 5) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 18; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 18; } - - if ((*out_variant == SW || *out_variant == SE) && anchor_sprite_index == 18) { *out_pixel_y -= 10; } - else if (*out_variant == SW && anchor_sprite_index == 73) { *out_pixel_x -=4; *out_pixel_y -= 10; } - else if (*out_variant == NW && anchor == DIR_SE && anchor_sprite_index == 42) { *out_pixel_y -= 8; } - else if ((*out_variant == NW || *out_variant == SW) && anchor_sprite_index == 6) { *out_pixel_x += 12; *out_pixel_y -= 6; } - else if ((*out_variant == SW) && anchor_sprite_index == 16) { *out_pixel_x -=8; *out_pixel_y -= 10; } - } - } - else if (direct_diagonal && *out_variant == SW && anchor == DIR_NE) { *out_pixel_x -=8; *out_pixel_y -= 8; } - else if (direct_diagonal && *out_variant == SE && anchor == DIR_NW) { *out_pixel_x -=8; *out_pixel_y -= 8; } - else if (direct_diagonal && *out_variant == NW && anchor == DIR_SE) { *out_pixel_x +=6; *out_pixel_y += 6; } - else if (direct_diagonal && *out_variant == NE && anchor == DIR_SW) { *out_pixel_x +=6; *out_pixel_y += 6; } -} - -bool -wonder_should_use_alternative_direction_image (int tile_x, int tile_y, int owner_id, struct wonder_district_config const * cfg) -{ - if (owner_id <= 0) - return false; - - // We only care about the nearest same-civ city in the work area around the tile. - // Assumes the base wonder art (img_row/column) faces west and the alt art faces east. - // To "face away" from the nearest city, we pick the alt art when that city lies to the east. - Tile * center = is->current_render_tile; - if ((center == NULL) || (center == p_null_tile)) - return false; - - // If on a river and the wonder allows river alignment, make sure we face the river instead - bool allow_river = wonder_requires_river (cfg); - if (allow_river) { - enum direction river_dir = DIR_ZERO; - if (get_primary_river_direction (center, &river_dir)) { - int dx, dy; - - if (direction_to_offset (river_dir, &dx, &dy)) { - // I'm not completely sure of the logic here, but this seems to match the vanilla behavior - // in terms of having the wonder face the general direction of the river flow - if (dx == 2) - return false; - - return dx > 0; - } - } - } - - // Else face away from the nearest same-civ city - Map * map = &p_bic_data->Map; - int best_dist = INT_MAX; - int best_dx = 0; - int city_dx = 0; - int city_dy = 0; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - City * city = wai.city; - if ((city == NULL) || (city->Body.CivID != owner_id)) - continue; - - int dx = city->Body.X - tile_x; - int dy = city->Body.Y - tile_y; - - if (map->Flags & 1) { - int half_width = map->Width >> 1; - if (dx > half_width) - dx -= map->Width; - else if (dx < -half_width) - dx += map->Width; - } - if (map->Flags & 2) { - int half_height = map->Height >> 1; - if (dy > half_height) - dy -= map->Height; - else if (dy < -half_height) - dy += map->Height; - } - - int dist = int_abs (dx) + int_abs (dy); - // Pick the closest city; if tied, favor the one with a clearer east/west offset so we know which way to face. - if ((dist < best_dist) || - ((dist == best_dist) && ((int_abs (dx) < int_abs (best_dx)) || (best_dx == 0)))) { - best_dist = dist; - best_dx = dx; - city_dx = city->Body.X; - city_dy = city->Body.Y; - } - } - - bool city_is_directly_above_port = city_dx == tile_x && city_dy == tile_y - 2; - bool city_is_directly_below_port = city_dx == tile_x && city_dy == tile_y + 2; - - if (city_is_directly_above_port || city_is_directly_below_port) { - bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); - bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); - bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); - - if (northeast_tile_is_land || east_tile_is_land || southeast_tile_is_land) - return true; - } - - if ((best_dist == INT_MAX) || (best_dx == 0)) - return false; - - return best_dx > 0; -} - -void -draw_district_on_map_or_canvas(Sprite * sprite, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (is->tile_info_open) { - PCX_Image * canvas = (PCX_Image *)map_renderer; - patch_Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, NULL); - return; - } - - patch_Sprite_draw_on_map (sprite, __, map_renderer, pixel_x, pixel_y, 1, 1, (p_bic_data->is_zoomed_out != false) + 1, 0); -} - -int -get_energy_grid_image_index (int tile_x, int tile_y) -{ - struct district_infos * info = &is->district_infos[ENERGY_GRID_DISTRICT_ID]; - for (int i = 0; i < info->dependent_building_count; i++) { - // Zero is "no building"; Buildings start from index one - int column_index = i + 1; - int building_id = info->dependent_building_ids[i]; - if (tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) - return column_index; - } - - return 0; -} - -int -get_bridge_image_index (Tile * tile, int tile_x, int tile_y) -{ - int SW_NE = 0; - int NW_SE = 1; - int N_S = 2; - int W_E = 3; - - if ((tile->vtable->m42_Get_Overlays (tile, __, 0) & TILE_FLAG_RAILROAD) != 0) { - SW_NE += 4; - NW_SE += 4; - N_S += 4; - W_E += 4; - } - - bool bridge_n = tile_has_district_at (tile_x, tile_y - 2, BRIDGE_DISTRICT_ID); - bool bridge_s = tile_has_district_at (tile_x, tile_y + 2, BRIDGE_DISTRICT_ID); - bool bridge_w = tile_has_district_at (tile_x - 2, tile_y, BRIDGE_DISTRICT_ID); - bool bridge_e = tile_has_district_at (tile_x + 2, tile_y, BRIDGE_DISTRICT_ID); - bool bridge_ne = tile_has_district_at (tile_x + 1, tile_y - 1, BRIDGE_DISTRICT_ID); - bool bridge_nw = tile_has_district_at (tile_x - 1, tile_y - 1, BRIDGE_DISTRICT_ID); - bool bridge_se = tile_has_district_at (tile_x + 1, tile_y + 1, BRIDGE_DISTRICT_ID); - bool bridge_sw = tile_has_district_at (tile_x - 1, tile_y + 1, BRIDGE_DISTRICT_ID); - - if (bridge_n || bridge_s || bridge_w || bridge_e || bridge_ne || bridge_nw || bridge_se || bridge_sw) { - int ns_count = (bridge_n ? 1 : 0) + (bridge_s ? 1 : 0); - int we_count = (bridge_w ? 1 : 0) + (bridge_e ? 1 : 0); - int swne_count = (bridge_sw ? 1 : 0) + (bridge_ne ? 1 : 0); - int nwse_count = (bridge_nw ? 1 : 0) + (bridge_se ? 1 : 0); - - if (swne_count == 2) return SW_NE; - if (nwse_count == 2) return NW_SE; - if (ns_count == 2) return N_S; - if (we_count == 2) return W_E; - - if (bridge_ne || bridge_sw) return SW_NE; - if (bridge_nw || bridge_se) return NW_SE; - if (bridge_n || bridge_s) return N_S; - if (bridge_w || bridge_e) return W_E; - } - - int owner_id = tile->Territory_OwnerID; - bool north_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); - bool south_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); - bool west_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); - bool east_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); - bool ne_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); - bool nw_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); - bool se_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); - bool sw_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); - - bool north_link = north_land || bridge_n; - bool south_link = south_land || bridge_s; - bool west_link = west_land || bridge_w; - bool east_link = east_land || bridge_e; - bool ne_link = ne_land || bridge_ne; - bool nw_link = nw_land || bridge_nw; - bool se_link = se_land || bridge_se; - bool sw_link = sw_land || bridge_sw; - - if (sw_link && ne_link) return SW_NE; - if (nw_link && se_link) return NW_SE; - if (north_link && south_link) return N_S; - if (west_link && east_link) return W_E; - - if (ne_link || sw_link) return SW_NE; - if (nw_link || se_link) return NW_SE; - if (north_link || south_link) return N_S; - if (west_link || east_link) return W_E; - - return SW_NE; -} - -void -get_bridge_directions (Tile * tile, int tile_x, int tile_y, int * out_dir1, int * out_dir2) -{ - int dir1 = -1; - int dir2 = -1; - int index = get_bridge_image_index (tile, tile_x, tile_y); - - switch (index) { - case 0: dir1 = DIR_SW; dir2 = DIR_NE; break; - case 1: dir1 = DIR_NW; dir2 = DIR_SE; break; - case 2: dir1 = DIR_N; dir2 = DIR_S; break; - case 3: dir1 = DIR_W; dir2 = DIR_E; break; - default: break; - } - - *out_dir1 = dir1; - *out_dir2 = dir2; -} - -void -get_canal_directions (Tile * tile, int tile_x, int tile_y, bool out_water_dirs[9], int * out_dir1, int * out_dir2) -{ - bool canal_at_n = tile_has_district_at (tile_x, tile_y - 2, CANAL_DISTRICT_ID); - bool canal_at_s = tile_has_district_at (tile_x, tile_y + 2, CANAL_DISTRICT_ID); - bool canal_at_w = tile_has_district_at (tile_x - 2, tile_y, CANAL_DISTRICT_ID); - bool canal_at_e = tile_has_district_at (tile_x + 2, tile_y, CANAL_DISTRICT_ID); - bool canal_at_ne = tile_has_district_at (tile_x + 1, tile_y - 1, CANAL_DISTRICT_ID); - bool canal_at_nw = tile_has_district_at (tile_x - 1, tile_y - 1, CANAL_DISTRICT_ID); - bool canal_at_se = tile_has_district_at (tile_x + 1, tile_y + 1, CANAL_DISTRICT_ID); - bool canal_at_sw = tile_has_district_at (tile_x - 1, tile_y + 1, CANAL_DISTRICT_ID); - bool water_n = tile_is_water (tile_x, tile_y - 2); - bool water_s = tile_is_water (tile_x, tile_y + 2); - bool water_w = tile_is_water (tile_x - 2, tile_y); - bool water_e = tile_is_water (tile_x + 2, tile_y); - bool water_ne = tile_is_water (tile_x + 1, tile_y - 1); - bool water_nw = tile_is_water (tile_x - 1, tile_y - 1); - bool water_se = tile_is_water (tile_x + 1, tile_y + 1); - bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); - bool canal_or_water_n = canal_at_n || water_n; - bool canal_or_water_s = canal_at_s || water_s; - bool canal_or_water_w = canal_at_w || water_w; - bool canal_or_water_e = canal_at_e || water_e; - bool canal_or_water_ne = canal_at_ne || water_ne; - bool canal_or_water_nw = canal_at_nw || water_nw; - bool canal_or_water_se = canal_at_se || water_se; - bool canal_or_water_sw = canal_at_sw || water_sw; - - bool canal_dirs[9] = { - false, canal_at_ne, canal_at_e, canal_at_se, - canal_at_s, canal_at_sw, canal_at_w, canal_at_nw, canal_at_n - }; - bool water_dirs[9] = { - false, water_ne, water_e, water_se, - water_s, water_sw, water_w, water_nw, water_n - }; - bool available_dirs[9] = { - false, canal_or_water_ne, canal_or_water_e, canal_or_water_se, - canal_or_water_s, canal_or_water_sw, canal_or_water_w, canal_or_water_nw, canal_or_water_n - }; - - // Avoid acute angles (adjacent directions) that look cramped. - int disallowed_pairs[][2] = { - { DIR_N, DIR_NE }, { DIR_NE, DIR_E }, { DIR_E, DIR_SE }, { DIR_SE, DIR_S }, - { DIR_S, DIR_SW }, { DIR_SW, DIR_W }, { DIR_W, DIR_NW }, { DIR_NW, DIR_N } - }; - int disallowed_pair_count = sizeof(disallowed_pairs) / sizeof(disallowed_pairs[0]); - int pref_dirs[8] = { DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_N, DIR_E, DIR_S, DIR_W }; - - int dir1 = -1; - int dir2 = -1; - - bool has_canal_dir = canal_dirs[DIR_N] || canal_dirs[DIR_NE] || canal_dirs[DIR_E] || canal_dirs[DIR_SE] || - canal_dirs[DIR_S] || canal_dirs[DIR_SW] || canal_dirs[DIR_W] || canal_dirs[DIR_NW]; - - if (has_canal_dir) { - for (int i = 0; i < 8 && dir1 == -1; i++) { - int d = pref_dirs[i]; - if (canal_dirs[d]) - dir1 = d; - } - } else { - for (int i = 0; i < 8 && dir1 == -1; i++) { - int d = pref_dirs[i]; - if (available_dirs[d]) - dir1 = d; - } - } - - if (dir1 >= 0) { - for (int pass = 0; pass < 2 && dir2 == -1; pass++) { - bool * dirs = (pass == 0) ? canal_dirs : available_dirs; - for (int i = 0; i < 8; i++) { - int d = pref_dirs[i]; - if (d == dir1 || ! dirs[d]) - continue; - bool pair_is_too_close = false; - for (int k = 0; k < disallowed_pair_count; k++) { - if ((dir1 == disallowed_pairs[k][0] && d == disallowed_pairs[k][1]) || - (dir1 == disallowed_pairs[k][1] && d == disallowed_pairs[k][0])) { - pair_is_too_close = true; - break; - } - } - if (pair_is_too_close) - continue; - dir2 = d; - break; - } - } - } - - int draw_dir1 = dir1; - int draw_dir2 = dir2; - if ((draw_dir1 >= 0) && (draw_dir2 >= 0)) { - int weight1 = 0; - int weight2 = 0; - - if (draw_dir1 == DIR_S) weight1 = 2; - else if ((draw_dir1 == DIR_SE) || (draw_dir1 == DIR_SW)) weight1 = 1; - else if ((draw_dir1 == DIR_NE) || (draw_dir1 == DIR_NW) || (draw_dir1 == DIR_N)) weight1 = -1; - - if (draw_dir2 == DIR_S) weight2 = 2; - else if ((draw_dir2 == DIR_SE) || (draw_dir2 == DIR_SW)) weight2 = 1; - else if ((draw_dir2 == DIR_NE) || (draw_dir2 == DIR_NW) || (draw_dir2 == DIR_N)) weight2 = -1; - - if (weight1 > weight2) { - int tmp = draw_dir1; - draw_dir1 = draw_dir2; - draw_dir2 = tmp; - } - } - - // Manual overrides - overall algorithm works pretty well, but handle corner cases - if (!has_canal_dir && water_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir1 = DIR_NE; draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && water_dirs[DIR_N] && water_dirs[DIR_NE]) { draw_dir1 = DIR_N; draw_dir2 = DIR_S; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_SE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_NE] && water_dirs[DIR_N]) { draw_dir1 = DIR_N; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && water_dirs[DIR_S]) { draw_dir2 = DIR_S; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && canal_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && canal_dirs[DIR_NE] && water_dirs[DIR_S]) { draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NW && draw_dir2 == DIR_NE && canal_dirs[DIR_NW] && water_dirs[DIR_SE]) { draw_dir2 = DIR_SE; } - if (draw_dir1 == DIR_NW && draw_dir2 == DIR_S && canal_dirs[DIR_NW] && water_dirs[DIR_S]) { draw_dir2 = DIR_SE; } - - *out_dir1 = draw_dir1; - *out_dir2 = draw_dir2; - for (int i = 0; i < 9; i++) - out_water_dirs[i] = water_dirs[i]; -} - -void -draw_canal_on_map_or_canvas(Sprite * sprite, int tile_x, int tile_y, int dir, bool water_dirs[9], Map_Renderer * map_renderer, int draw_x, int draw_y) -{ - int y_offset = 9; - int x_offset = y_offset * 2; - - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y); - - // In certain cases, add an additional draw if adjacent to water so that the canal appears to extend far enough - if (dir == DIR_N && water_dirs[DIR_N]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y - y_offset); - else if (dir == DIR_NE && water_dirs[DIR_NE]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y - y_offset); - else if (dir == DIR_E && water_dirs[DIR_E]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y); - else if (dir == DIR_SE && water_dirs[DIR_SE]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y + y_offset); - else if (dir == DIR_S && water_dirs[DIR_S]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y + y_offset); - else if (dir == DIR_SW && water_dirs[DIR_SW]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y + y_offset); - else if (dir == DIR_W && water_dirs[DIR_W]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y); - else if (dir == DIR_NW && water_dirs[DIR_NW]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y - y_offset); -} - -void -draw_canal_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int era) -{ - struct district_config const * cfg = &is->district_configs[CANAL_DISTRICT_ID]; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - int offset_x = pixel_x + cfg->x_offset; - int offset_y = pixel_y + cfg->y_offset; - int dir1_draw_x = offset_x - ((sprite_width - 128) / 2); - int dir1_draw_y = offset_y - (sprite_height - 64); - int dir2_draw_x = dir1_draw_x; - int dir2_draw_y = dir1_draw_y; - - int draw_dir1 = -1; - int draw_dir2 = -1; - bool water_dirs[9] = { false, false, false, false, false, false, false, false, false }; - get_canal_directions (tile, tile_x, tile_y, water_dirs, &draw_dir1, &draw_dir2); - - // Set offsets based on directions for (literal) edge cases - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S) { dir1_draw_x += 7; dir1_draw_y -= 2; } - else if (draw_dir1 == DIR_N && draw_dir2 == DIR_W) { dir2_draw_x -= 12; } - else if (draw_dir1 == DIR_N && draw_dir2 == DIR_SE) { dir2_draw_x += 4; } - - if (draw_dir1 >= 0) { - Sprite * sprite1 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir1]; - draw_canal_on_map_or_canvas(sprite1, tile_x, tile_y, draw_dir1, water_dirs, map_renderer, dir1_draw_x, dir1_draw_y); - } - - if (draw_dir2 >= 0) { - Sprite * sprite2 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir2]; - draw_canal_on_map_or_canvas(sprite2, tile_x, tile_y, draw_dir2, water_dirs, map_renderer, dir2_draw_x, dir2_draw_y); - } -} - -void -draw_great_wall_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - bool wall_nw = tile_has_district_at (tile_x - 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); - bool wall_ne = tile_has_district_at (tile_x + 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); - bool wall_se = tile_has_district_at (tile_x + 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); - bool wall_sw = tile_has_district_at (tile_x - 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); - bool wall_s = tile_has_district_at (tile_x, tile_y + 2, GREAT_WALL_DISTRICT_ID); - bool wall_n = tile_has_district_at (tile_x, tile_y - 2, GREAT_WALL_DISTRICT_ID); - - bool water_ne = tile_is_water (tile_x - 1, tile_y - 1); - bool water_nw = tile_is_water (tile_x + 1, tile_y - 1); - bool water_w = tile_is_water (tile_x - 2, tile_y); - bool water_n = tile_is_water (tile_x, tile_y + 2); - bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); - bool water_se = tile_is_water (tile_x + 1, tile_y + 1); - - Sprite * sprites = is->district_img_sets[GREAT_WALL_DISTRICT_ID].imgs[0][0]; - Sprite * base = &sprites[0]; - - // Rotate around clockwise NW -> SW to get the perspective right - if (wall_nw) draw_district_on_map_or_canvas(&sprites[DIR_NW], map_renderer, pixel_x, pixel_y); - if (wall_ne) draw_district_on_map_or_canvas(&sprites[DIR_NE], map_renderer, pixel_x, pixel_y); - - // Base pillar - draw_district_on_map_or_canvas(base, map_renderer, pixel_x, pixel_y); - - if (wall_sw) draw_district_on_map_or_canvas(&sprites[DIR_SW], map_renderer, pixel_x, pixel_y); - if (wall_se) draw_district_on_map_or_canvas(&sprites[DIR_SE], map_renderer, pixel_x, pixel_y); -} - -void -draw_district_generated_resource_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, - int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) -{ - int base_resource = Tile_get_resource_visible_to (tile, __, visible_to_civ_id); - int district_resource = -1; - - if (inst->state == DS_COMPLETED) { - int district_id = inst->district_id; - if ((district_id >= 0) && (district_id < is->district_count)) { - struct district_config * cfg = &is->district_configs[district_id]; - if (cfg->generated_resource_id >= 0) { - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_id >= 0) && ((visible_to_civ_id < 0) || (owner_id == visible_to_civ_id))) { - int res_id = cfg->generated_resource_id; - if (district_generates_resource_for_civ (tile, inst, cfg, owner_id)) - district_resource = res_id; - } - } - } - } - - if (district_resource < 0) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; - int offset = tile_width >> 2; - int left_x = pixel_x - (offset >> 1); - int right_x = pixel_x + (offset >> 1); - - int icon_id = p_bic_data->ResourceTypes[district_resource].IconID; - Sprite * sprite = NULL; - Map_Renderer * resource_renderer = is->tile_info_open ? &p_bic_data->Map.Renderer : map_renderer; - int resource_sprite_count = 0; - if ((resource_renderer != NULL) && (resource_renderer->Resources != NULL)) - // The renderer allocates Resources as a counted heap array: the int stored just before the - // first Sprite is the number of entries loaded from resources.pcx. - resource_sprite_count = ((int *)resource_renderer->Resources)[-1]; - if ((icon_id < 0) || (icon_id >= resource_sprite_count)) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - sprite = &resource_renderer->Resources[icon_id]; - if (sprite == NULL) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - if (base_resource >= 0) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, left_x, pixel_y); - } - - int tile_height = tile_width >> 1; - int sprite_width = sprite->Width; - int sprite_height = sprite->Height; - if (sprite_width <= 0) sprite_width = sprite->Width3; - if (sprite_height <= 0) sprite_height = sprite->Height3; - int center_x = (tile_width - sprite_width) >> 1; - int center_y = (tile_height - sprite_height) >> 1; - int draw_x = (base_resource >= 0) ? right_x : pixel_x; - draw_x += center_x; - int draw_y = pixel_y + center_y; - if (is->tile_info_open) { - PCX_Image * canvas = (PCX_Image *)map_renderer; - patch_Sprite_draw (sprite, __, canvas, draw_x, draw_y, NULL); - } else { - int draw_scale = (p_bic_data->is_zoomed_out != false) + 1; - patch_Sprite_draw_on_map (sprite, __, map_renderer, draw_x, draw_y, 1, 1, draw_scale, 0); - } -} - -int -count_completed_buildings_in_district_radius (int tile_x, int tile_y, int district_id) -{ - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos * district_info = &is->district_infos[district_id]; - int completed_count = 0; - for (int i = 0; i < district_info->dependent_building_count; i++) { - int building_id = district_info->dependent_building_ids[i]; - if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) - completed_count++; - } - return completed_count; -} - -void -draw_district_on_map_or_canvas_by_buildings (Sprite * base_sprite, Map_Renderer * map_renderer, int district_id, int variant, int era, int tile_x, int tile_y, int draw_x, int draw_y) -{ - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos * district_info = &is->district_infos[district_id]; - - draw_district_on_map_or_canvas(base_sprite, map_renderer, draw_x, draw_y); - - for (int i = 0; i < district_info->dependent_building_count; i++) { - // Zero is "base texture"; Actual building column art starts from index one - int column_index = i + 1; - int building_id = district_info->dependent_building_ids[i]; - if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) { - Sprite * district_sprite = &is->district_img_sets[district_id].imgs[variant][era][column_index]; - draw_district_on_map_or_canvas(district_sprite, map_renderer, draw_x, draw_y); - } - } -} - -void -draw_district_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) -{ - int district_id = inst->district_id; - if (is->dc_img_state == IS_UNINITED) - init_district_images (); - - if (is->dc_img_state != IS_OK) - return; - - // Natural Wonder - if (district_id == NATURAL_WONDER_DISTRICT_ID) { - if (! is->current_config.enable_natural_wonders) - return; - - int natural_id = inst->natural_wonder_info.natural_wonder_id; - if ((natural_id >= 0) && (natural_id < is->natural_wonder_count)) { - Sprite * nsprite = &is->natural_wonder_img_sets[natural_id].img; - int y_offset = 88 - 64; // Height of wonder img minus height of tile - int draw_y = pixel_y - y_offset; - - draw_district_on_map_or_canvas(nsprite, map_renderer, pixel_x, draw_y); - } - return; - } - - // Districts - if (is->current_config.enable_districts) { - if (district_id < 0 || district_id >= is->district_count) return; - bool completed = district_is_complete (tile, district_id); - - if (! completed) - return; - - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos * district_info = &is->district_infos[district_id]; - int territory_owner_id = tile->Territory_OwnerID; - int variant = 0; - int era = 0; - int culture = 0; - int buildings = 0; - int draw_pixel_x = pixel_x; - int draw_pixel_y = pixel_y; - enum direction river_dir = DIR_ZERO; - - // If in a territory, use owner's culture/era - if (territory_owner_id > 0) { - Leader * leader = &leaders[territory_owner_id]; - culture = p_bic_data->Races[leader->RaceID].CultureGroupID; - if (cfg->vary_img_by_culture) - variant = culture; - if (cfg->vary_img_by_era) - era = leader->Era; - if (cfg->align_to_coast) - align_variant_and_pixel_offsets_with_coastline (tile, &variant, &draw_pixel_x, &draw_pixel_y); - - // Else render abandoned if not a Wonder, Natural Wonder, Bridge, or Canal - } else if (district_id != WONDER_DISTRICT_ID && district_id != NATURAL_WONDER_DISTRICT_ID && district_id != BRIDGE_DISTRICT_ID && district_id != CANAL_DISTRICT_ID) { - Sprite * abandoned_sprite = &is->abandoned_district_img; - if (tile->vtable->m35_Check_Is_Water (tile) && is->abandoned_maritime_district_img.vtable != NULL) - abandoned_sprite = &is->abandoned_maritime_district_img; - if (abandoned_sprite->vtable != NULL) { - draw_district_on_map_or_canvas(abandoned_sprite, map_renderer, draw_pixel_x + cfg->x_offset, draw_pixel_y + cfg->y_offset); - } - return; - } - - // If out of a territory (and not abandoned) but builder is known, use builder's era & culture - if (territory_owner_id < 0 && inst->built_by_civ_id >= 0) { - Leader * builder = &leaders[inst->built_by_civ_id]; - culture = p_bic_data->Races[builder->RaceID].CultureGroupID; - if (cfg->vary_img_by_culture) - variant = culture; - if (cfg->vary_img_by_era) - era = builder->Era; - } - - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - int offset_x = draw_pixel_x + cfg->x_offset; - int offset_y = draw_pixel_y + cfg->y_offset; - int draw_x = offset_x - ((sprite_width - 128) / 2); - int draw_y = offset_y - (sprite_height - 64); - Sprite (*sprites)[MAX_DISTRICT_ERA_COUNT][MAX_DISTRICT_COLUMN_COUNT] = is->district_img_sets[district_id].imgs; - - // Render - switch (district_id) { - case WONDER_DISTRICT_ID: - { - if (! is->current_config.enable_wonder_districts) - return; - - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info == NULL) - return; - - int construct_windex = -1; - Sprite * wsprite = NULL; - - struct wonder_district_config * wcfg = NULL; - struct wonder_district_image_set * set = NULL; - - // Completed - if (info->state == WDS_COMPLETED) { - int windex = info->wonder_index; - if ((windex < 0) || (windex >= is->wonder_district_count)) - return; - wcfg = &is->wonder_district_configs[windex]; - set = &is->wonder_district_img_sets[windex]; - // Under construction - } else if (wonder_district_tile_under_construction (tile, tile_x, tile_y, &construct_windex) && (construct_windex >= 0)) { - if (construct_windex >= is->wonder_district_count) - return; - wcfg = &is->wonder_district_configs[construct_windex]; - set = &is->wonder_district_img_sets[construct_windex]; - // Unused - } else { - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - - if (wonder_requires_river(wcfg)) - align_district_with_river (tile, &draw_pixel_x, &draw_pixel_y, &river_dir); - - int wonder_width = (wcfg->custom_width > 0) ? wcfg->custom_width : 128; - int wonder_height = (wcfg->custom_height > 0) ? wcfg->custom_height : 64; - int wonder_offset_x = draw_pixel_x + cfg->x_offset; - int wonder_offset_y = draw_pixel_y + cfg->y_offset; - int wonder_draw_x = wonder_offset_x - ((wonder_width - 128) / 2); - int wonder_draw_y = wonder_offset_y - (wonder_height - 64); - - bool use_alt_dir = wcfg->enable_img_alt_dir && wonder_should_use_alternative_direction_image (tile_x, tile_y, territory_owner_id, wcfg); - if (info->state == WDS_COMPLETED) - wsprite = (use_alt_dir && (set->alt_dir_img.vtable != NULL)) ? &set->alt_dir_img : &set->img; - else - wsprite = (use_alt_dir && (set->alt_dir_construct_img.vtable != NULL)) ? &set->alt_dir_construct_img : &set->construct_img; - - draw_district_on_map_or_canvas(wsprite, map_renderer, wonder_draw_x, wonder_draw_y); - return; - } - case NEIGHBORHOOD_DISTRICT_ID: - { - if (! is->current_config.enable_neighborhood_districts) - return; - - unsigned v = (unsigned)tile_x * 0x9E3779B1u + (unsigned)tile_y * 0x85EBCA6Bu; - v ^= v >> 16; - v *= 0x7FEB352Du; - v ^= v >> 15; - v *= 0x846CA68Bu; - v ^= v >> 16; - buildings = clamp(0, 3, (int)(v & 3u)); /* final 0..3 */ - variant = culture; - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - case DISTRIBUTION_HUB_DISTRICT_ID: - if (! is->current_config.enable_distribution_hub_districts) - return; - - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - case ENERGY_GRID_DISTRICT_ID: - { - if (! is->current_config.enable_energy_grid_districts) - return; - - buildings = get_energy_grid_image_index (tile_x, tile_y); - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - case BRIDGE_DISTRICT_ID: - { - if (! is->current_config.enable_bridge_districts) - return; - - buildings = get_bridge_image_index (tile, tile_x, tile_y); - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - case CANAL_DISTRICT_ID: - { - if (! is->current_config.enable_canal_districts) - return; - - draw_canal_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y, era); - return; - } - case GREAT_WALL_DISTRICT_ID: - { - if (! is->current_config.enable_great_wall_districts) - return; - - draw_great_wall_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - default: - { - // Draw by counting number of completed buildings in radius - if (cfg->render_strategy == DRS_BY_COUNT) { - buildings = count_completed_buildings_in_district_radius (tile_x, tile_y, district_id); - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - // Draw by checking each building individually and layering images - else if (cfg->render_strategy == DRS_BY_BUILDING) { - Sprite * base_sprite = &is->district_img_sets[district_id].imgs[variant][era][0]; - draw_district_on_map_or_canvas_by_buildings(base_sprite, map_renderer, district_id, variant, era, tile_x, tile_y, draw_x, draw_y); - return; - } - } - } - } - - Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Map_Renderer_m12_Draw_Tile_Buildings(Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { - Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - Tile * tile = is->current_render_tile; - if (is->tile_info_open) - tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if ((tile == NULL) || (tile == p_null_tile)) - return; - - struct district_instance * inst = is->current_render_tile_district; - if (is->tile_info_open) - inst = get_district_instance (tile); - if (inst == NULL) { - Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - // Draw resources first if needed - if (is->district_configs[inst->district_id].draw_over_resources) - draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); - - draw_district_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); -} - -void __fastcall -patch_Map_Renderer_m09_Draw_Tile_Resources (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (! is->current_config.enable_districts) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - Tile * tile = is->current_render_tile; - if (is->tile_info_open) - tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if ((tile == NULL) || (tile == p_null_tile)) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - struct district_instance * inst = is->current_render_tile_district; - if (is->tile_info_open) - inst = get_district_instance (tile); - if (inst == NULL) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - // Resources that should be drawn below district are already drawn, skip in that case - if (is->district_configs[inst->district_id].draw_over_resources) - return; - - draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); -} - -void __fastcall -patch_Map_Renderer_m11_Draw_Tile_Irrigation (Map_Renderer *this, int edx, int visible_to_civ, int tile_x, int tile_y, int param_4, int param_5, int param_6) -{ - if (! is->current_config.enable_districts) { - Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); - return; - } - - struct district_instance * inst = is->current_render_tile_district; - if (inst == NULL) { - Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); - return; - } - - // If it has a completed district that serves as pseudo-irrigation source, suppress drawing irrigation - if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (is->current_render_tile, inst->district_id)) - return; - - Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); -} - -bool __fastcall -patch_Tile_has_city_or_district (Tile * this) -{ - bool has_city = Tile_has_city (this); - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - return has_city || (get_district_instance (this) != NULL); - } - return has_city; -} - -int __fastcall -patch_Tile_check_water_for_navigator_cell_coloring (Tile * this) -{ - if (! is->current_config.show_territory_colors_on_water_tiles_in_minimap) - return this->vtable->m35_Check_Is_Water (this); - else - return 0; -} - -bool -is_skippable_popup (char * text_key) -{ - char * skippable_keys[] = {"SUMMARY_END_GOLDEN_AGE", "SUMMARY_END_SCIENCE_AGE", "SUMMARY_NEW_SMALL_WONDER", // unimportant domestic things - "WONDERPRODUCE", // another civ completed a wonder - "MAKEPEACE", "MUTUALPROTECTIONPACT", "MILITARYALLIANCE", "SUMMARY_DECLARE_WAR", // diplo events not involving the player - "TRADEEMBARGOENDS", // embargo vs player ends - "SUMMARY_CIV_DESTROYED_BY_CIV", "SUMMARY_CIV_DESTROYED", // foreign civs destroyed not by player - "LOSTGOOD", // 'We lost our supply of ...!' - "TRADEEMBARGO", "MILITARYALLIANCEWARONUS", "MILITARYALLIANCEAGAINSTUS", // trade embargo or alliance vs player - "SUMMARY_TRAVELERS_REPORT"}; // another civs starts a wonder - - for (int n = 0; n < ARRAY_LEN (skippable_keys); n++) - if (strcmp (text_key, skippable_keys[n]) == 0) - return true; - return false; -} - -int __fastcall -patch_PopupForm_impl_begin_showing_popup (PopupForm * this) -{ - if (is_online_game () || - (! is->current_config.convert_some_popups_into_online_mp_messages) || - (! is_skippable_popup (this->text_key))) - return PopupForm_impl_begin_showing_popup (this); - - else { - unsigned saved_prefs = *p_preferences; - int saved_flags = this->field_1BF0[0xE4]; - - *p_preferences |= P_SHOW_FEWER_MP_POPUPS; - this->field_1BF0[0xE4] |= 0x4000; - int tr = PopupForm_impl_begin_showing_popup (this); - - *(bool *)(p_main_screen_form->animator.field_18E4 + 10) = true; // Set what must be a dirty flag - Animator_update (&p_main_screen_form->animator); // Make sure message appears - - this->field_1BF0[0xE4] = saved_flags; - *p_preferences = saved_prefs; - - return tr; - } -} - -bool __stdcall -patch_is_online_game_for_show_popup () -{ - return is->current_config.convert_some_popups_into_online_mp_messages ? true : is_online_game (); -} - -bool -ai_move_district_worker (Unit * worker, struct district_worker_record * rec) -{ - if ((worker == NULL) || (rec == NULL)) - return false; - - char ss[200]; - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d assigned to build district\n", worker->Body.ID); - (*p_OutputDebugStringA) (ss); - - // Check the original request city made for district - struct pending_district_request * req = rec->pending_req; - if ((req == NULL) || - (req->assigned_worker_id != worker->Body.ID) || - (req->target_x < 0) || (req->target_y < 0)) - return false; - - int district_id = req->district_id; - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d moving to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); - (*p_OutputDebugStringA) (ss); - - City * request_city = get_city_ptr (req->city_id); - if (request_city == NULL) { - clear_tracked_worker_assignment (rec); - remove_pending_district_request (req); - return false; - } - req->city = request_city; - struct district_config * cfg = &is->district_configs[district_id]; - Tile * target_tile = tile_at (req->target_x, req->target_y); - if ((target_tile == NULL) || (target_tile == p_null_tile) || - (target_tile->vtable->m38_Get_Territory_OwnerID (target_tile) != worker->Body.CivID) || - (! city_radius_contains_tile (request_city, req->target_x, req->target_y))) { - clear_city_district_request (request_city, req->district_id); - return false; - } - - // If the worker has arrived - if ((worker->Body.X == req->target_x) && (worker->Body.Y == req->target_y)) { - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d arrived at (%d,%d) to build district\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - Tile * tile = tile_at (worker->Body.X, worker->Body.Y); - struct district_instance * inst = get_district_instance (tile); - bool do_replacement = false; - - // If there is a completed district here already - if ((inst != NULL) && district_is_complete (tile, inst->district_id)) { - int existing_district_id = inst->district_id; - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d found existing district ID %d at (%d,%d)\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - if (existing_district_id == req->district_id) { - clear_city_district_request (request_city, req->district_id); - clear_tracked_worker_assignment (rec); - return false; - } - - // Allow replacement of unused wonder districts - if (existing_district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = &inst->wonder_info; - if (info->state == WDS_UNUSED) - do_replacement = true; - } else if (district_is_obsolete_for_civ (existing_district_id, request_city->Body.CivID)) { - do_replacement = true; - } else { - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d cannot replace existing district ID %d at (%d,%d), cancelling request\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - clear_city_district_request (request_city, req->district_id); - return false; - } - - if (!do_replacement) { - return false; // Nothing left to do here - } - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for duplicate districts near city at (%d,%d)\n", request_city->Body.X, request_city->Body.Y); - (*p_OutputDebugStringA) (ss); - - // One final check: do we still need the district? Check for any dupes nearby - if (req->district_id != DISTRIBUTION_HUB_DISTRICT_ID && req->district_id != NEIGHBORHOOD_DISTRICT_ID) { - FOR_DISTRICTS_AROUND (wai, request_city->Body.X, request_city->Body.Y, false) { - if (wai.tile == tile) - continue; - - if (wai.district_inst->district_id == req->district_id) { - snprintf (ss, sizeof ss, "ai_move_district_worker: Found duplicate district ID %d near city at (%d,%d), cancelling request\n", req->district_id, request_city->Body.X, request_city->Body.Y); - (*p_OutputDebugStringA) (ss); - clear_city_district_request (request_city, req->district_id); - return false; - } - } - } - - // Need to make sure distro hubs get roads. If this will be one, build the road first to be sure - if (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID) { - bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); - if (! has_road && ! cfg->auto_add_road) { - Unit_set_state(worker, __, UnitState_Build_Road); - worker->Body.Job_ID = WJ_Build_Road; - return true; - } - } - - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); - bool district_buildable_here = district_is_buildable_on_tile (&is->district_configs[req->district_id], tile); - - // Remove any existing improvements - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); - if (do_replacement) { - remove_district_instance (tile); - handle_district_removed (tile, req->district_id, worker->Body.X, worker->Body.Y, false); - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for craters or pollution at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - if (tile->vtable->m21_Check_Crates (tile, __, 0) || tile->vtable->m20_Check_Pollution (tile, __, 0)) { - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d clearing craters or pollution at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - Unit_set_state(worker, __, UnitState_Clear_Damage); - worker->Body.Job_ID = WJ_Clean_Pollution; - return true; - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for forest or wetlands at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - // Clear any forest/wetlands - if (! district_buildable_here && base_type == SQ_Forest) { - Unit_set_state(worker, __, UnitState_Clear_Forest); - worker->Body.Job_ID = WJ_Clean_Forest; - return true; - } else if (! district_buildable_here && ((base_type == SQ_Jungle) || (base_type == SQ_Swamp))) { - Unit_set_state(worker, __, UnitState_Clear_Wetlands); - worker->Body.Job_ID = WJ_Clear_Swamp; - return true; - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d starting construction of district at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - // Clear any existing improvements (irrigation and mines) - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); - - // Start construction of district - inst = ensure_district_instance (tile, req->district_id, req->target_x, req->target_y); - inst->built_by_civ_id = worker->Body.CivID; - Unit_set_state(worker, __, UnitState_Build_Mines); - worker->Body.Job_ID = WJ_Build_Mines; // Build district - return true; - - // Else if the worker needs to be sent - } else { - if ((worker->Body.UnitState != UnitState_Go_To) || - (worker->Body.path_dest_x != req->target_x) || - (worker->Body.path_dest_y != req->target_y)) { - int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, - worker->Body.X, worker->Body.Y, req->target_x, req->target_y, - worker, worker->Body.CivID, 0x41, NULL); - if (path_result > 0) { - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d path set to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); - (*p_OutputDebugStringA) (ss); - - Unit_set_escortee (worker, __, -1); - Unit_set_state (worker, __, UnitState_Go_To); - worker->Body.path_dest_x = req->target_x; - worker->Body.path_dest_y = req->target_y; - } else { - clear_tracked_worker_assignment (rec); - return false; - } - } - } - return false; -} - -bool -ai_worker_try_tile_improvement_district (Unit * worker) -{ - if (! is->current_config.enable_districts || worker == NULL) return false; - if (! is_worker (worker)) return false; - if (worker->Body.Auto_CityID < 0) return false; - - City * city = get_city_ptr (worker->Body.Auto_CityID); - if (city == NULL) return false; - if (city->Body.CivID != worker->Body.CivID) return false; - - int civ_id = worker->Body.CivID; - int tile_x = worker->Body.X; - int tile_y = worker->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (tile->CityID >= 0) return false; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; - if (! city_radius_contains_tile (city, tile_x, tile_y)) return false; - if (get_district_instance (tile) != NULL) return false; - - // Evaluate whether the best improvement here is irrigation, mines, or a district, using heuristics based on city needs - int food_weight = (city->Body.FoodIncome < city->Body.FoodRequired) ? 3 : 1; - int shield_weight = (city->Body.ProductionIncome < city->Body.Population.Size) ? 2 : 1; - int unhappy_percent = - city->Body.UnhappyNoReasonPercent + - city->Body.UnhappyCrowdedPercent + - city->Body.UnhappyWarWearinessPercent + - city->Body.UnhappyAgresssionPercent + - city->Body.UnhappyPropagandaPercent + - city->Body.UnhappyDraftPercent + - city->Body.UnhappyOppressionPercent + - city->Body.UnhappyThisCityImprovementsPercent + - city->Body.UnhappyOtherCityImprovementsPercent; - int happiness_weight = (unhappy_percent > 0) ? 2 : 1; - int gold_weight = 1; - int resource_boost = 5 * (food_weight + shield_weight + gold_weight + happiness_weight); - - int irrigation_score = INT_MIN; - if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Irrigate, tile_x, tile_y, 0) && - ! tile->vtable->m17_Check_Irrigation (tile, __, 0)) { - int base_type = tile->vtable->m50_Get_Square_BaseType (tile); - int bonus = p_bic_data->TileTypes[base_type].IrrigationBonus; - if (bonus < 0) - bonus = 0; - irrigation_score = bonus * food_weight; - } - - int mine_score = INT_MIN; - if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Build_Mines, tile_x, tile_y, 0) && - ! tile->vtable->m18_Check_Mines (tile, __, 0)) { - int base_type = tile->vtable->m50_Get_Square_BaseType (tile); - int bonus = p_bic_data->TileTypes[base_type].MiningBonus; - if (bonus < 0) - bonus = 0; - mine_score = bonus * shield_weight; - } - - int best_score = INT_MIN; - int best_district_id = -1; - for (int i = 0; i < is->district_count; i++) { - struct district_config const * cfg = &is->district_configs[i]; - if (cfg->ai_build_strategy != DABS_TILE_IMPROVEMENT) - continue; - if (! can_build_district_on_tile (tile, i, civ_id)) - continue; - - struct district_instance temp = {0}; - temp.district_id = i; - temp.tile_x = (short)tile_x; - temp.tile_y = (short)tile_y; - - int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; - get_effective_district_yields (&temp, cfg, &food, &shields, &gold, &science, &culture, &happiness); - - int score = food * food_weight + shields * shield_weight + gold * gold_weight; - score += (science + culture) / 2; - score += happiness * happiness_weight; - if ((cfg->generated_resource_id >= 0) && - ! patch_City_has_resource (city, __, cfg->generated_resource_id)) - score += resource_boost; - - if (score > best_score) { - best_score = score; - best_district_id = i; - } - } - - if ((best_district_id >= 0) && - (best_score >= irrigation_score) && - (best_score >= mine_score)) { - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - if (removable_flags != 0) - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); - ensure_district_instance (tile, best_district_id, tile_x, tile_y); - Unit_set_state (worker, __, UnitState_Build_Mines); - worker->Body.Job_ID = WJ_Build_Mines; - return true; - } - - return false; -} - -void __fastcall -patch_Unit_ai_move_terraformer (Unit * this) -{ - Map * map = &p_bic_data->Map; - int type_id = this->Body.UnitTypeID; - int civ_id = this->Body.CivID; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - int territory_owner = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m38_Get_Territory_OwnerID (tile) : -1; - - - if (is->current_config.enable_districts && ! is_human && is_worker (this)) { - update_tracked_worker_for_unit (this); - struct district_instance * inst = get_district_instance (tile); - - if ((territory_owner == civ_id) && - inst != NULL && inst->district_id != NATURAL_WONDER_DISTRICT_ID && - tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Coast) { - // Roads should be made after district builds. The district is complete but - // worker is still likely on the tile, so check here and build road if needed - struct district_config * cfg = &is->district_configs[inst->district_id]; - bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); - if (! has_road && ! cfg->auto_add_road) { - Unit_set_state(this, __, UnitState_Build_Road); - this->Body.Job_ID = WJ_Build_Road; - return; - } - - // Same check for railroads - bool can_build_railroad = Leader_can_do_worker_job (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y, 0); - bool has_railroad = (*tile->vtable->m23_Check_Railroads)(tile, __, 0); - if (can_build_railroad && !has_railroad && ! cfg->auto_add_railroad) { - Unit_set_state(this, __, UnitState_Build_Railroad); - this->Body.Job_ID = WJ_Build_Railroad; - return; - } - } - - struct district_worker_record * rec = get_tracked_worker_record (this); - if (rec != NULL && rec->pending_req != NULL) { - if (ai_move_district_worker (this, rec)) - return; - } - - if ((this->Body.Auto_CityID >= 0) && ai_worker_try_tile_improvement_district (this)) - return; - } - - bool pop_else_caravan; - if ((tile != NULL) && (tile != p_null_tile) && - (type_id >= 0) && (type_id < p_bic_data->UnitTypeCount) && - is_material_unit (&p_bic_data->UnitTypes[type_id], &pop_else_caravan) && - ((pop_else_caravan && is->current_config.enable_pop_unit_ai) || - ((! pop_else_caravan) && is->current_config.enable_caravan_unit_ai))) { - ai_move_material_unit (this); - return; - } - - Unit_ai_move_terraformer (this); -} - -bool __fastcall -patch_Unit_ai_can_sacrifice (Unit * this, int edx, bool requires_city) -{ - int sacrifice_action = UCV_Sacrifice & 0x0FFFFFFF; // Mask out top four category bits - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.patch_ai_can_sacrifice_without_special_ability && ((type->Special_Actions & sacrifice_action) == 0)) - return false; - else - return Unit_ai_can_sacrifice (this, __, requires_city); -} - -int __cdecl -patch_get_building_defense_bonus_at (int x, int y, int param_3) -{ - // Get base building defense bonus first - int base = get_building_defense_bonus_at (x, y, param_3); - - // If districts are disabled, return base - if (!is->current_config.enable_districts) - return base; - - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - struct district_config const * cfg = &is->district_configs[inst->district_id]; - int bonus = cfg->defense_bonus_percent; - bonus += apply_district_bonus_entries (inst, &cfg->defense_bonus_extras, inst->district_id); - return bonus; - } - - return base; -} - -void __fastcall -patch_Unit_select (Unit * this) -{ - if (is->current_config.enable_districts) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && is_worker(this) && inst->district_id >= 0 && inst->district_id <= is->district_count && - ! district_is_complete (tile, inst->district_id)) { - int district_id = inst->district_id; - PopupForm * popup = get_popup_form (); - int remaining_turns = get_worker_remaining_turns_to_complete (this, __, 0); - set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); - set_popup_int_param (1, remaining_turns); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_CANCEL_BUILD_DISTRICT", -1, 0, 0, 0); - - int sel = patch_show_popup (popup, __, 0, 0); - if (sel == 0) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, 0); - - bool other_workers_present = false; - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit != NULL) && (unit != this) && - (unit->Body.UnitState == UnitState_Build_Mines) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { - other_workers_present = true; - break; - } - } - if (! other_workers_present) { - remove_district_instance (tile); - } - } else { - return; - } - } - } - - // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - - Unit_select (this); -} - -void __fastcall -patch_City_Form_draw_food_income_icons (City_Form * this) -{ - // Call original function first - City_Form_draw_food_income_icons (this); - - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) - return; - - // Get current city - City * city = this->CurrentCity; - if (city == NULL) - return; - - // Calculate standard district food bonus - int standard_district_food = 0; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int district_id = wai.district_inst->district_id; - int food_bonus = 0; - get_effective_district_yields (wai.district_inst, &is->district_configs[district_id], &food_bonus, NULL, NULL, NULL, NULL, NULL); - standard_district_food += food_bonus; - } - - // Get distribution hub food bonus - int distribution_hub_food = 0; - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) - get_distribution_hub_yields_for_city (city, &distribution_hub_food, NULL); - - // Total district food - int total_district_food = standard_district_food + distribution_hub_food; - if (total_district_food <= 0) - return; - - // Lazy load icons - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { - if (is->distribution_hub_icons_img_state == IS_UNINITED) - init_distribution_hub_icons (); - if (is->distribution_hub_icons_img_state != IS_OK) - return; - } - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - if (is->dc_icons_img_state != IS_OK) - return; - - int food_income = city->Body.FoodIncome; - int food_required = city->Body.FoodRequired; - - // Calculate how standard district food icons are distributed - int standard_food_eaten = 0; - int standard_food_surplus = 0; - if (standard_district_food > 0) { - if (standard_district_food >= food_income) { - standard_food_surplus = food_income; - standard_food_eaten = standard_district_food - food_income; - } else { - standard_food_surplus = standard_district_food; - standard_food_eaten = 0; - } - } - - // Calculate how distribution hub food icons are distributed - int hub_food_eaten = 0; - int hub_food_surplus = 0; - int remaining_income = food_income - standard_food_surplus; - if (distribution_hub_food > 0) { - if (distribution_hub_food >= remaining_income) { - hub_food_surplus = remaining_income; - hub_food_eaten = distribution_hub_food - remaining_income; - } else { - hub_food_surplus = distribution_hub_food; - hub_food_eaten = 0; - } - } - - // Draw eaten district food icons (left side, from right to left) - int total_eaten = standard_food_eaten + hub_food_eaten; - if (total_eaten > 0) { - Sprite * base_eaten_sprite = &(this->City_Icons_Images).Icon_07; - int eaten_sprite_width = base_eaten_sprite->Width; - int eaten_sprite_height = base_eaten_sprite->Height; - struct tagRECT * eaten_rect = &this->Food_Consumption_Rect; - int eaten_rect_width = eaten_rect->right - eaten_rect->left; - - int eaten_spacing = eaten_sprite_width; - if ((food_required > 1) && (food_required * eaten_sprite_width - eaten_rect_width != 0) && - (eaten_rect_width <= food_required * eaten_sprite_width)) { - eaten_spacing = (eaten_rect_width - eaten_sprite_width) / (food_required - 1); - if (eaten_spacing < 1) - eaten_spacing = 1; - else if (eaten_spacing > eaten_sprite_width) - eaten_spacing = eaten_sprite_width; - } - - int eaten_x_offset = eaten_spacing * (food_required - 1); - // Draw standard district eaten first - for (int i = 0; i < standard_food_eaten && i < food_required; i++) { - int x = eaten_rect->left + eaten_x_offset; - int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - - (eaten_sprite_height >> 1)); - Sprite_draw (&is->district_food_eaten_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - eaten_x_offset -= eaten_spacing; - } - // Draw distribution hub eaten - for (int i = 0; i < hub_food_eaten && eaten_x_offset >= 0; i++) { - int x = eaten_rect->left + eaten_x_offset; - int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - - (eaten_sprite_height >> 1)); - Sprite_draw (&is->distribution_hub_eaten_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - eaten_x_offset -= eaten_spacing; - } - } - - // Draw surplus district food icons (right side, from right to left) - int total_surplus = standard_food_surplus + hub_food_surplus; - if (total_surplus > 0) { - Sprite * base_surplus_sprite = &(this->City_Icons_Images).Icon_06; - int surplus_sprite_width = base_surplus_sprite->Width; - int surplus_sprite_height = base_surplus_sprite->Height; - struct tagRECT * surplus_rect = &this->Food_Storage_Rect; - int surplus_rect_width = surplus_rect->right - surplus_rect->left; - - int surplus_spacing = surplus_sprite_width; - if ((food_income > 1) && (food_income * surplus_sprite_width - surplus_rect_width != 0) && - (surplus_rect_width <= food_income * surplus_sprite_width)) { - surplus_spacing = (surplus_rect_width - surplus_sprite_width) / (food_income - 1); - if (surplus_spacing < 1) - surplus_spacing = 1; - else if (surplus_spacing > surplus_sprite_width) - surplus_spacing = surplus_sprite_width; - } - - int surplus_x_offset = 0; - // Draw standard district surplus first - for (int i = 0; i < standard_food_surplus && i < food_income; i++) { - int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; - int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - - (surplus_sprite_height >> 1)) - 1; - Sprite_draw (&is->district_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - surplus_x_offset += surplus_spacing; - } - // Draw distribution hub surplus - for (int i = 0; i < hub_food_surplus && surplus_x_offset < surplus_rect_width; i++) { - int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; - int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - - (surplus_sprite_height >> 1)) - 1; - Sprite_draw (&is->distribution_hub_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - surplus_x_offset += surplus_spacing; - } - } -} - -void -recompute_district_and_distribution_hub_shields_for_city_view (City * city) -{ - if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) - return; - - int city_id = city->Body.ID; - int city_x = city->Body.X; - int city_y = city->Body.Y; - - // District yields are injected through the city center tile in patch_City_calc_tile_yield_while_gathering. - // Grab the base yield (no districts) directly from the original function, then compute the - // district bonus that calculate_city_center_district_bonus will layer on afterward. - int city_center_base_shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, city_x, city_y); - int total_district_shield_bonus = 0; - calculate_city_center_district_bonus (city, NULL, &total_district_shield_bonus, NULL); - - // Distribution hub contribution is tracked separately for icon rendering. - int distribution_hub_shields = 0; - if (is->current_config.enable_distribution_hub_districts) - get_distribution_hub_yields_for_city (city, NULL, &distribution_hub_shields); - if (distribution_hub_shields < 0) - distribution_hub_shields = 0; - if (distribution_hub_shields > total_district_shield_bonus) - distribution_hub_shields = total_district_shield_bonus; - - int standard_district_shields = total_district_shield_bonus - distribution_hub_shields; - if (standard_district_shields < 0) - standard_district_shields = 0; - - // Recompute yields with districts active so ProductionIncome/Loss reflect the city view. - recompute_city_yields_with_districts (city); - int total_production_income = city->Body.ProductionIncome; - int total_production_loss = city->Body.ProductionLoss; - int total_net_shields = total_production_income + total_production_loss; // ProductionLoss stored as negative - - // Remove the district bonus from the gross tile production and recompute corruption on that base value. - int city_center_with_districts = city_center_base_shields + total_district_shield_bonus; - int gross_without_specials = city->Body.Tiles_Production - (city_center_with_districts - city_center_base_shields); - if (gross_without_specials < 0) - gross_without_specials = 0; - - int base_corruption_abs = patch_City_compute_corrupted_yield (city, __, gross_without_specials, true); - if (base_corruption_abs < 0) - base_corruption_abs = 0; - int base_production_loss = -base_corruption_abs; - - // Corruption becomes more negative as it increases. - int additional_corruption = total_production_loss - base_production_loss; - - int district_shields_remaining = standard_district_shields; - int hub_shields_remaining = distribution_hub_shields; - - if (additional_corruption < 0) { - int extra_loss = -additional_corruption; - - if (district_shields_remaining > 0) { - int from_districts = (extra_loss < district_shields_remaining) ? extra_loss : district_shields_remaining; - district_shields_remaining -= from_districts; - extra_loss -= from_districts; - } - - if ((extra_loss > 0) && (hub_shields_remaining > 0)) { - int from_hub = (extra_loss < hub_shields_remaining) ? extra_loss : hub_shields_remaining; - hub_shields_remaining -= from_hub; - extra_loss -= from_hub; - } - } - - int non_district_shields_remaining = total_net_shields - district_shields_remaining - hub_shields_remaining; - if (non_district_shields_remaining < 0) - non_district_shields_remaining = 0; - - int total_corruption = -total_production_loss; - if (total_corruption < 0) - total_corruption = 0; - int district_corruption = standard_district_shields - district_shields_remaining; - int hub_corruption = distribution_hub_shields - hub_shields_remaining; - int base_corruption = total_corruption - district_corruption - hub_corruption; - if (base_corruption < 0) - base_corruption = 0; - - is->non_district_shield_icons_remaining = non_district_shields_remaining; - is->district_shield_icons_remaining = district_shields_remaining; - is->distribution_hub_shield_icons_remaining = hub_shields_remaining; - - is->corruption_shield_icons_remaining = base_corruption; - is->district_corruption_icons_remaining = district_corruption; - is->distribution_hub_corruption_icons_remaining = hub_corruption; -} - -void __fastcall -patch_City_draw_production_income_icons (City * this, int edx, int canvas, int * rect_ptr) -{ - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { - City_draw_production_income_icons (this, __, canvas, rect_ptr); - return; - } - - recompute_district_and_distribution_hub_shields_for_city_view (this); - City_draw_production_income_icons (this, __, canvas, rect_ptr); - - is->corruption_shield_icons_remaining = 0; - is->district_corruption_icons_remaining = 0; - is->distribution_hub_corruption_icons_remaining = 0; - - is->non_district_shield_icons_remaining = 0; - is->district_shield_icons_remaining = 0; - is->distribution_hub_shield_icons_remaining = 0; -} - -int __fastcall -patch_Sprite_draw_production_income_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - if (is->distribution_hub_icons_img_state == IS_UNINITED) - init_distribution_hub_icons (); - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - - if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && is->dc_icons_img_state == IS_OK) { - Sprite to_draw = *this; - if (is->corruption_shield_icons_remaining > 0 || - is->district_corruption_icons_remaining > 0 || - is->distribution_hub_corruption_icons_remaining > 0) { - - if (is->corruption_shield_icons_remaining > 0) { - is->corruption_shield_icons_remaining--; - } else if (is->district_corruption_icons_remaining > 0) { - to_draw = is->district_corruption_icon; - is->district_corruption_icons_remaining--; - } else if (is->distribution_hub_icons_img_state == IS_OK) { - to_draw = is->distribution_hub_corruption_icon; - is->distribution_hub_corruption_icons_remaining--; - } - } - else if (is->non_district_shield_icons_remaining > 0 || - is->district_shield_icons_remaining > 0 || - is->distribution_hub_shield_icons_remaining > 0) { - - if (is->non_district_shield_icons_remaining > 0) { - is->non_district_shield_icons_remaining--; - } else if (is->district_shield_icons_remaining > 0) { - to_draw = is->district_shield_icon; - is->district_shield_icons_remaining--; - } else if (is->distribution_hub_icons_img_state == IS_OK) { - to_draw = is->distribution_hub_shield_icon; - is->distribution_hub_shield_icons_remaining--; - } - - } - return Sprite_draw (&to_draw, __, canvas, pixel_x, pixel_y, color_table); - } - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -bool -district_tile_needs_defense (Tile * tile, int tile_x, int tile_y, struct district_instance * inst, int civ_id, int work_radius) -{ - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (inst == NULL) return false; - - int district_id = inst->district_id; - struct district_config const * cfg = &is->district_configs[district_id]; - if (! district_is_complete (tile, district_id)) return false; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; - - // Check if already has enough defenders (2 for aerodromes, distribution hubs, destroyable completed wonders) - int defender_count = count_units_at (tile_x, tile_y, UF_DEFENDER_VIS_TO_A_OF_CLASS_B, civ_id, 0, -1); - int max_defenders = - (district_id == AERODROME_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID || - (cfg->defense_bonus_percent > 0 && district_id != NEIGHBORHOOD_DISTRICT_ID) || - (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed)) - ? 2 : 1; - if (defender_count >= max_defenders) - return false; - - // Distribution hubs always need defense - if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) - return true; - - // Wonder districts need defense if under construction or completed (not unused) - if (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed) { - enum wonder_district_state state = inst->wonder_info.state; - if (state == WDS_UNDER_CONSTRUCTION || state == WDS_COMPLETED) - return true; - // Unused wonder districts don't need defense - return false; - } - - return any_enemies_near (&leaders[civ_id], tile_x, tile_y, -1, work_radius); -} - -int -compute_turns_required_for_path (Unit * unit, int path_length) -{ - if (path_length < 1) - return 0; - - int max_mp = patch_Unit_get_max_move_points (unit); - if (max_mp <= 0) - return 9999; - - int moves_used_this_turn = max_mp - unit->Body.Moves; - moves_used_this_turn = not_below (0, moves_used_this_turn); - moves_used_this_turn = not_above (moves_used_this_turn, 9999); - - int remaining_mp = path_length - moves_used_this_turn; - if (remaining_mp < 0) - remaining_mp = 0; - - return (max_mp - 1 + remaining_mp) / max_mp + 1; -} - -void -maybe_update_best_district_target (Unit * unit, - int civ_id, - int max_distance, - int unit_x, - int unit_y, - int tile_x, - int tile_y, - int base_score, - int * best_score, - int * best_x, - int * best_y, - int * best_path_length, - int * evaluated_paths, - int max_path_checks) -{ - if (*evaluated_paths >= max_path_checks) - return; - - int path_length; - int path_result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, tile_x, tile_y, - unit, civ_id, 0x81, &path_length); - *evaluated_paths += 1; - if (path_result <= 0) - return; - - if (max_distance > 0) { - int turns = compute_turns_required_for_path (unit, path_length); - if (turns > max_distance) - return; - } - - int score = base_score - path_length; - if ((score > *best_score) || ((score == *best_score) && (path_length < *best_path_length))) { - *best_score = score; - *best_x = tile_x; - *best_y = tile_y; - *best_path_length = path_length; - } -} - -// Patch seek_colony to actively search for undefended districts -int __fastcall -patch_Unit_seek_colony (Unit * this, int edx, bool for_own_defense, int max_distance) -{ - // Only intercept if defending own assets and districts are enabled - if (!for_own_defense || - !is->current_config.enable_districts || - !is->current_config.ai_defends_districts) - return Unit_seek_colony (this, __, for_own_defense, max_distance); - - int civ_id = this->Body.CivID; - int unit_x = this->Body.X; - int unit_y = this->Body.Y; - - Tile * current_tile = tile_at (unit_x, unit_y); - if ((current_tile == NULL) || (current_tile == p_null_tile)) - return Unit_seek_colony (this, __, for_own_defense, max_distance); - - int continent_id = current_tile->vtable->m46_Get_ContinentID (current_tile); - - const int search_radius = 20; - const int max_path_checks = 64; - const int wonder_base_score = 1000; - const int regular_base_score = 500; - - int best_x = -1; - int best_y = -1; - int best_score = INT_MIN; - int best_path_length = INT_MAX; - int evaluated_paths = 0; - - bool abort_search = false; - - if ((is->current_config.enable_wonder_districts && is->current_config.completed_wonder_districts_can_be_destroyed) || - is->current_config.enable_distribution_hub_districts) { - for (int dx = -search_radius; (dx <= search_radius) && !abort_search; dx++) { - for (int dy = -search_radius; dy <= search_radius; dy++) { - if (evaluated_paths >= max_path_checks) { - abort_search = true; - break; - } - - int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); - int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); - Tile * district_tile = tile_at (target_x, target_y); - if ((district_tile == NULL) || (district_tile == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (district_tile); - if (inst == NULL) - continue; - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) - continue; - if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) - continue; - if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) - continue; - - maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, - tile_x, tile_y, wonder_base_score, - &best_score, &best_x, &best_y, - &best_path_length, &evaluated_paths, - max_path_checks); - } - } - } - - if ((best_x < 0) && (evaluated_paths < max_path_checks)) { - for (int dx = -search_radius; (dx <= search_radius) && (evaluated_paths < max_path_checks); dx++) { - for (int dy = -search_radius; dy <= search_radius; dy++) { - if (evaluated_paths >= max_path_checks) - break; - - int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); - int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); - Tile * district_tile = tile_at (target_x, target_y); - if ((district_tile == NULL) || (district_tile == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (district_tile); - if ((inst == NULL) || (inst->district_id == WONDER_DISTRICT_ID)) - continue; - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) - continue; - if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) - continue; - if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) - continue; - - maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, - tile_x, tile_y, regular_base_score, - &best_score, &best_x, &best_y, - &best_path_length, &evaluated_paths, - max_path_checks); - } - } - } - - if ((best_x >= 0) && (best_y >= 0)) { - int result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, best_x, best_y, - this, civ_id, 0x181, NULL); - return result; - } - - return Unit_seek_colony (this, __, for_own_defense, max_distance); -} - -// Patch has_colony to make units stay on districts, only patches within Unit::ai_move_defensive_unit -bool __fastcall -patch_Tile_has_district_or_colony (Tile * this) -{ - if (is->current_config.enable_districts && - is->current_config.ai_defends_districts) { - - struct district_instance * inst = get_district_instance (this); - return (inst != NULL) && district_is_complete (this, inst->district_id); - } - - // Fallback to original has_colony logic - return Tile_has_colony (this); -} - -int __fastcall -patch_Buildings_Info_get_age_in_years_for_tourism (Buildings_Info * this, int edx, int building_index) -{ - int base = Buildings_Info_get_age_in_years (this, __, building_index); - if (is->current_config.tourism_time_scale_percent == 100) - return base; - else if (is->current_config.tourism_time_scale_percent <= 0) - return INT_MAX; - else - return (base * 100 + 50) / is->current_config.tourism_time_scale_percent; -} - -int __fastcall -patch_Sprite_draw_minimap_frame (Sprite * this, int edx, Sprite * alpha, int param_2, PCX_Image * canvas, int x, int y, int param_6) -{ - bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || - ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); - if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) - return Sprite_draw_for_hud (&is->double_size_box_left_color_pcx, __, &is->double_size_box_left_alpha_pcx, param_2, canvas, x, y, param_6); - else - return Sprite_draw_for_hud (this, __, alpha, param_2, canvas, x, y, param_6); -} - -int __fastcall -patch_City_get_turns_to_build_2_for_ai_move_leader (City * this, int edx, City_Order * order, bool param_2) -{ - // Initialize order variable to city's current build. This is not done in the base logic and can cause crashes. - City_Order current_order = { .OrderID = this->Body.Order_ID, .OrderType = this->Body.Order_Type }; - if (is->current_config.patch_crash_in_leader_unit_ai) - order = ¤t_order; - - return City_get_turns_to_build_2 (this, __, order, param_2); -} - -void __fastcall -patch_City_set_production (City * this, int edx, int order_type, int order_id, bool ask_to_confirm) -{ - City_set_production (this, __, order_type, order_id, ask_to_confirm); - - if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) - return; - - // If the human player, we need to set/unset a wonder district for this city, depending - // on what is being built. The human player wouldn't be able to choose a wonder if a wonder - // district wasn't available, so we don't need to worry about feasibility here. - // The AI uses a different mechanism to reserve wonder districts via patch_Leader_do_production_phase. - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - if (! is_human) - return; - - char ss[256]; - bool release_reservation = true; - if (this->Body.Order_Type == COT_Improvement) { - Improvement * improv = &p_bic_data->Improvements[this->Body.Order_ID]; - if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { - if (reserve_wonder_district_for_city (this, this->Body.Order_ID)) { - release_reservation = false; - } - } - } - - if (release_reservation) { - release_wonder_district_reservation (this); - } -} - -int __fastcall -patch_Tile_m71_Check_Worker_Job (Tile * this) -{ - if (is->current_config.enable_natural_wonders) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && - (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) { - return -1; // No worker job allowed on natural wonders - } - } - return Tile_m71_Check_Worker_Job (this); -} - -int __fastcall -patch_Tile_get_road_bonus (Tile * this) -{ - if (is->current_config.enable_natural_wonders) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { - return 0; - } - } - if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { - return 1; - } - } - return Tile_get_road_bonus (this); -} - -bool __fastcall -patch_Unit_has_army_ability_to_perform_unload (Unit * this, int edx, enum UnitTypeAbilities a) -{ - return is->current_config.allow_unload_from_army ? false : Unit_has_ability (this, __, a); -} - -void __fastcall -patch_Unit_disembark (Unit * this, int edx, int tile_x, int tile_y) -{ - Unit * container = get_unit_ptr (this->Body.Container_Unit); - bool unloading_from_army = is->current_config.allow_unload_from_army && container != NULL && Unit_has_ability (container, __, UTA_Army); - - // If removing a unit from an army, transfer a proportional amount of damage to the unit removed - int damage_transferred = 0; - if (unloading_from_army) { - int army_damage_percent = container->Body.Damage * 100 / Unit_get_max_hp (container), - max_damage = Unit_get_max_hp (this) - 1 - this->Body.Damage; - damage_transferred = clamp (0, max_damage, (army_damage_percent * Unit_get_max_hp (this) + 50) / 100); - } - - Unit_disembark (this, __, tile_x, tile_y); - - if (unloading_from_army) { - this->Body.Damage = not_above (Unit_get_max_hp (this) - 1, this->Body.Damage + damage_transferred); - container->Body.Damage = not_below (0, container->Body.Damage - damage_transferred); - - if (this->Body.ID == container->Body.army_top_defender_id) { - Unit * new_top_defender = NULL; - FOR_UNITS_ON (uti, tile_at (container->Body.X, container->Body.Y)) - if (uti.unit->Body.Container_Unit == container->Body.ID) { - if (new_top_defender == NULL) - new_top_defender = uti.unit; - else if (Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, uti.unit, Unit_get_defense_strength (uti.unit), new_top_defender, Unit_get_defense_strength (new_top_defender), true)) - new_top_defender = uti.unit; - } - container->Body.army_top_defender_id = (new_top_defender != NULL) ? new_top_defender->Body.ID : -1; - } - } -} - -bool __fastcall -patch_Unit_has_ability_no_load_non_army_passengers (Unit * this, int edx, enum UnitTypeAbilities army_ability) -{ - UnitType * transport_type = &p_bic_data->UnitTypes[is->can_load_transport->Body.UnitTypeID], - * passenger_type = &p_bic_data->UnitTypes[this ->Body.UnitTypeID]; - - // This call comes from Unit::can_load at the point where it's determined that the passenger (this) has transport capacity > 0 and is checking - // whether it's an army. If not, it can't be loaded. Add two exceptions here for land transports, if configured, one to allow LTs to load into - // naval units and another to allow empty LTs to load into armies. - if (is->current_config.land_transport_rules != 0) - if ((passenger_type->Unit_Class == UTC_Land) && ! Unit_has_ability (this, __, army_ability)) { // if it's a land transport - if ((is->current_config.land_transport_rules & LTR_LOAD_ONTO_BOAT) && (transport_type->Unit_Class == UTC_Sea)) - return true; - if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && - Unit_has_ability (is->can_load_transport, __, army_ability) && (Unit_count_contained_units (this) == 0)) - return true; - } - - // Similarly, allow helicopters to be loaded onto carriers if so configured - if ((is->current_config.special_helicopter_rules & SHR_ALLOW_ON_CARRIERS) && - passenger_type->Unit_Class == UTC_Air && - transport_type->Unit_Class == UTC_Sea && - Unit_has_ability (is->can_load_transport, __, UTA_Transports_Only_Aircraft)) - return true; - - return Unit_has_ability (this, __, army_ability); -} - -bool __fastcall -patch_Unit_has_ability_no_load_transport_into_army (Unit * this, int edx, enum UnitTypeAbilities army_ability) -{ - // Similar to above, here it checks if the target unit is an army and rejects the load if it is (again, already determined that the passenger - // has transport capacity). Modify this rule to return false for land transports trying to join armies if configured. We don't have to check - // that the LT is empty since that is already disallowed by the modified check above. - bool is_army = Unit_has_ability (this, __, army_ability); - if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && is_army && - (p_bic_data->UnitTypes[is->can_load_passenger->Body.UnitTypeID].Unit_Class == UTC_Land)) - return false; - - else - return is_army; -} - -bool __fastcall -patch_Fighter_unit_can_defend (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) -{ - if (cannot_defend_inside_transport (unit)) - return false; - else - return Fighter_unit_can_defend (this, __, unit, tile_x, tile_y); -} - -bool __fastcall -patch_Leader_is_enemy_unit_for_ground_aa (Leader * this, int edx, Unit * bomber) -{ - // When this function is called, the potential interceptor unit is stored in register ESI. - Unit * interceptor; - __asm__ __volatile__("mov %%esi, %0" : "=r" (interceptor)); - - Unit * container = get_unit_ptr (interceptor->Body.Container_Unit); - bool in_transport = (container != NULL) && ! Unit_has_ability (container, __, UTA_Army); - if (in_transport && - (is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Land) - return false; - else if (in_transport && - (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return false; - else if (in_transport && - is->current_config.no_land_anti_air_from_inside_naval_transport && - (p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea)) - return false; - else - return Leader_is_enemy_unit (this, __, bomber); -} - -bool __fastcall -patch_Unit_has_army_ability_for_passenger_despawn (Unit * this, int edx, enum UnitTypeAbilities army_ability) -{ - // If the unit has the army ability, the game will always despawn the passengers. Otherwise there are exceptions like land unit passengers - // won't be despawned if the transport is on a land tile. - return is->always_despawn_passengers || Unit_has_ability (this, __, army_ability); -} - -int __cdecl -patch_count_units_at_in_try_capturing (int x, int y, enum unit_filter filter, int arg_a, int arg_b, int arg_c) -{ - Tile * tile = tile_at (x, y); - - // If one of the no-defense-from-inside rules is in force, count units like the function normally would except skip units that are inside - // transports from which they can't defend. Otherwise, if those transports have 0 defense, the passengers will prevent them from being - // captured but not fight themselves, making movement onto their tile impossible. - if (tile->vtable->m35_Check_Is_Water (tile) == 0 && - ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) || (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE))) { - int tr = 0; - FOR_UNITS_ON (tai, tile) { - if ((arg_b == -1 || p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].Unit_Class == arg_b) && - (arg_a == -1 || patch_Unit_is_visible_to_civ (tai.unit, __, arg_a, 1)) && - (Unit_get_defense_strength (tai.unit) > 0) && - ! cannot_defend_inside_transport (tai.unit)) - tr++; - } - return tr; - - } else - return count_units_at (x, y, filter, arg_a, arg_b, arg_c); -} - -void __fastcall -patch_Map_generate_resources (Map * this, int edx, int secondary_seed) -{ - int const bic_tag_good = 0x444f4f47; // = 'GOOD' - int resource_type_count = this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, -1, NULL); - bool * ratios_to_clear = NULL; - int lux_percent = is->current_config.luxury_randomized_appearance_rate_percent; - int seed = (this->Seed + 0x180E3) * secondary_seed; - - // To change the randomized appearance rate for luxuries, fill in an appearance rate for any that would be randomized (rate set == 0) using - // the same process the game would to randomize the rate but with different limits. That process involves taking two random numbers from 0 to - // 25 then adding them together and to 50 to produce a random rate from 50 to 100 biased toward the middle of that range. - if (lux_percent != 100 && - (ratios_to_clear = calloc (1, resource_type_count)) != NULL) { - for (int n = 0; n < resource_type_count; n++) { - Resource_Type * res; - this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); - if (res->Class == RC_Luxury && res->AppearanceRatio == 0) { - ratios_to_clear[n] = true; - int half_lux_percent = (lux_percent * 50 + 50) / 100, - quarter_lux_percent = (lux_percent * 25 + 50) / 100; - res->AppearanceRatio = not_below (1, half_lux_percent + rand_int (&seed, __, quarter_lux_percent) + rand_int (&seed, __, quarter_lux_percent)); - } - } - } - - Map_generate_resources (this, __, secondary_seed); - - if (ratios_to_clear != NULL) { - for (int n = 0; n < resource_type_count; n++) - if (ratios_to_clear[n]) { - Resource_Type * res; - this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); - res->AppearanceRatio = 0; - } - free (ratios_to_clear); - } -} - -PassBetweenValidity __fastcall -patch_Unit_can_pass_between (Unit * this, int edx, int from_x, int from_y, int to_x, int to_y, int param_5) -{ - PassBetweenValidity base = Unit_can_pass_between (this, __, from_x, from_y, to_x, to_y, param_5); - - if (is->current_config.enable_districts) { - Tile * to = tile_at (to_x, to_y); - bool to_valid = (to != NULL) && (to != p_null_tile); - struct district_instance * to_inst = NULL; - bool to_inst_complete = false; - if (to_valid) { - to_inst = get_district_instance (to); - if (to_inst != NULL) - to_inst_complete = district_is_complete (to, to_inst->district_id); - } - if (great_wall_blocks_civ (to, this->Body.CivID)) - return PBV_GENERIC_INVALID_MOVE; - if (to_valid) { - bool impassible = false; - bool impassible_to_wheeled = false; - if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { - if (impassible) - return PBV_GENERIC_INVALID_MOVE; - if (impassible_to_wheeled && Unit_has_ability (this, __, UTA_Wheeled)) { - Tile * from = tile_at (from_x, from_y); - bool connected_by_road = (from != NULL) && (to != NULL) && - (from->vtable->m25_Check_Roads (from, __, 0) != 0) && - (to->vtable->m25_Check_Roads (to, __, 0) != 0); - if (! connected_by_road) - return PBV_REQUIRES_ROAD; - } - } - } - - if (is->current_config.workers_can_enter_coast && - base != PBV_OK && is_worker(this)) { - Tile * source = tile_at (from_x, from_y); - if (source != NULL && - source->vtable->m35_Check_Is_Water (source) && - (source->vtable->m50_Get_Square_BaseType (source) == SQ_Coast)) - return PBV_OK; - - if (to_valid && - to->vtable->m35_Check_Is_Water (to) && - (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - - // If human, okay to enter coast tile - if (is_human) - return PBV_OK; - - struct district_worker_record * rec = get_tracked_worker_record (this); - struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; - if (req != NULL) - return PBV_OK; - } - } - - if (is->current_config.enable_bridge_districts && - base != PBV_OK && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == BRIDGE_DISTRICT_ID)) - return PBV_OK; - - if (is->current_config.enable_canal_districts && - base != PBV_OK && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == CANAL_DISTRICT_ID)) - return PBV_OK; - } - - return base; -} - -Unit * __fastcall -patch_Unit_select_transport (Unit * this, int edx, int tile_x, int tile_y, bool do_show_popup) -{ - Unit * transport = Unit_select_transport (this, __, tile_x, tile_y, do_show_popup); - - if (is->current_config.enable_districts && - (transport == NULL) && (this == is->coast_walk_unit)) { - Tile * dest = tile_at (tile_x, tile_y); - if (dest != NULL) { - bool allow_move = false; - if (is->current_config.workers_can_enter_coast && is_worker (this) && - dest->vtable->m35_Check_Is_Water (dest) && - (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) - allow_move = true; - - if (! allow_move && is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land)) { - struct district_instance * inst = get_district_instance (dest); - if (inst != NULL && inst->district_id == BRIDGE_DISTRICT_ID && - district_is_complete (dest, inst->district_id)) { - allow_move = true; - } - } - - if (allow_move) { - is->coast_walk_transport_override = true; - return this; // Fake a transport so the move logic proceeds - } - } - } - - return transport; -} - -// Returns true if the given tile is a water district owned by an enemy of the unit -bool -is_enemy_maritime_district_tile (Unit * unit, Tile * tile) -{ - if ((unit == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - if (! is->current_config.enable_districts) - return false; - - if (! tile->vtable->m35_Check_Is_Water (tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner <= 0) || (owner == unit->Body.CivID)) - return false; - - Leader * leader = &leaders[unit->Body.CivID]; - return leader->At_War[owner]; -} - -// Boost pillage desirability for maritime districts -int __fastcall -patch_Unit_ai_eval_pillage_target (Unit * this, int edx, int tile_x, int tile_y) -{ - int base = Unit_ai_eval_pillage_target (this, __, tile_x, tile_y); - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if (is_enemy_maritime_district_tile (this, tile)) { - // Double the base score so districts outrank generic coast targets - base += base + 0x300; - } - - return base; -} - -// Light-weight hunt for nearby friendly ports; returns true if a path/command was issued -bool -try_path_to_friendly_port_district (Unit * unit, bool require_damaged, bool require_undefended) -{ - if ((unit == NULL) || - ! is->current_config.enable_districts || - ! is->current_config.enable_port_districts) - return false; - - if (unit->Body.Container_Unit >= 0) // Don't redirect cargo - return false; - - if (unit->Body.Moves <= 0) - return false; - - if (require_damaged && (unit->Body.Damage <= 0)) - return false; - - if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Sea) - return false; - - int sea_id = unit->vtable->get_sea_id (unit); - if (sea_id < 0) - return false; - - int best_x = -1, best_y = -1, best_path_len = INT_MAX; - const int search_radius = 10; - for (int dy = -search_radius; dy <= search_radius; dy++) { - for (int dx = -search_radius; dx <= search_radius; dx++) { - int tx = unit->Body.X + dx, ty = unit->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - if ((short)tile->vtable->m46_Get_ContinentID (tile) != sea_id) - continue; - - if (! tile_has_friendly_port_district (tile, unit->Body.CivID)) - continue; - - int occupier_id = get_tile_occupier_id (tx, ty, -1, true); - if ((occupier_id != -1) && (occupier_id != unit->Body.CivID)) - continue; - - if (require_undefended) { - bool has_friendly_sea_unit = false; - FOR_UNITS_ON (uti, tile) { - Unit * on_tile = uti.unit; - if ((on_tile == NULL) || (on_tile->Body.Container_Unit >= 0)) - continue; - if (on_tile->Body.CivID != unit->Body.CivID) - continue; - if (p_bic_data->UnitTypes[on_tile->Body.UnitTypeID].Unit_Class != UTC_Sea) - continue; - if (on_tile->Body.ID == unit->Body.ID) - continue; - has_friendly_sea_unit = true; - break; - } - if (has_friendly_sea_unit) - continue; - } - - if (! is_below_stack_limit (tile, unit->Body.CivID, UTC_Sea)) - continue; - - int path_len = 0; - int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, - tx, ty, unit, unit->Body.CivID, 0x81, &path_len); - if (path_result <= 0) - continue; - - if (path_len < best_path_len) { - best_path_len = path_len; - best_x = tx; - best_y = ty; - } - } - } - - if (unit->Body.X == best_x && unit->Body.Y == best_y) { - Unit_set_escortee (unit, __, -1); - Unit_set_state (unit, __, UnitState_Fortifying); - return true; - } - else if (best_x >= 0) { - patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, best_x, best_y, - unit, unit->Body.CivID, 0x81, NULL); - Unit_set_escortee (unit, __, -1); - Unit_set_state (unit, __, UnitState_Go_To); - unit->Body.path_dest_x = best_x; - unit->Body.path_dest_y = best_y; - return true; - } - - return false; -} - -void __fastcall -patch_Unit_ai_move_naval_power_unit (Unit * this) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - ! is->current_config.naval_units_use_port_districts_not_cities) { - Unit_ai_move_naval_power_unit (this); - return; - } - - Tile * here = tile_at (this->Body.X, this->Body.Y); - if (here == NULL) { - Unit_ai_move_naval_power_unit (this); - return; - } - - // If we're on a port and the sole unit, fortify - if (is->current_config.ai_defends_districts && - tile_has_friendly_port_district (here, this->Body.CivID) && - count_units_at (this->Body.X, this->Body.Y, UF_0, this->Body.CivID, 0, -1) == 1) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If we're already sitting on an enemy maritime district, pillage it immediately - if (this->Body.Container_Unit < 0) { - if (is_enemy_maritime_district_tile (this, here) && - patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y) && - (patch_Unit_ai_eval_pillage_target (this, __, this->Body.X, this->Body.Y) > 0)) { - patch_Unit_attack_tile (this, __, this->Body.X, this->Body.Y, false); - return; - } - } - - // If damaged and CAN heal at current location (e.g. port district), fortify to heal - if (this->Body.Damage > 0 && patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If damaged and cannot heal here, try to path to a friendly port district - if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) - return; - - Unit_ai_move_naval_power_unit (this); - return; -} - -void __fastcall -patch_Unit_ai_move_naval_transport (Unit * this) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - ! is->current_config.naval_units_use_port_districts_not_cities) { - Unit_ai_move_naval_transport (this); - return; - } - - // If damaged and CAN heal at current location (e.g. port district), fortify to heal - if ((this->Body.Damage > 0) && - patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If damaged and cannot heal here, try to path to a friendly port district - if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) - return; - - Unit_ai_move_naval_transport (this); -} - -void __fastcall -patch_Unit_ai_move_naval_missile_transport (Unit * this) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - ! is->current_config.naval_units_use_port_districts_not_cities) { - patch_Unit_ai_move_naval_missile_transport (this); - return; - } - - // If damaged and CAN heal at current location (e.g. port district), fortify to heal - if ((this->Body.Damage > 0) && - patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If damaged and cannot heal here, try to path to a friendly port district - if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) - return; - - Unit_ai_move_naval_missile_transport (this); -} - -void __fastcall -patch_Unit_ai_move_air_bombard_unit (Unit * this) -{ - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) { - Unit_ai_move_air_bombard_unit (this); - return; - } - - if (this->Body.Damage > 0) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - int best_target = 0; - int target_x = -1, target_y = -1; - int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - int grid = op_range * 2 + 1; - if (1 < grid * grid) { - for (int n = 1; n < grid * grid; n++) { - int dx, dy; - neighbor_index_to_diff (n, &dx, &dy); - int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); - int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); - if (Map_in_range (&p_bic_data->Map, __, x, y)) { - int score = Unit_ai_eval_bombard_target (this, __, x, y, 1); - if (score > best_target) { - best_target = score; - target_x = x; - target_y = y; - } - } - } - } - - int best_base_score = 0x7fffffff; - int base_x = -1, base_y = -1; - FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, - p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) - continue; - - int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 6, -1, -1); - int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); - int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); - int score = (count * 10) + ((x_dist + y_dist) >> 1); - if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) - score -= 20; - - if (score < best_base_score) { - best_base_score = score; - base_x = aerodrome_x; - base_y = aerodrome_y; - } - } - - if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { - Unit_set_escortee (this, __, -1); - Unit_rebase (this, __, base_x, base_y); - return; - } - - if ((target_x >= 0) && (target_y >= 0)) { - Unit_set_escortee (this, __, -1); - patch_Unit_bombard_tile (this, __, target_x, target_y); - return; - } - - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -void __fastcall -patch_Unit_ai_move_air_defense_unit (Unit * this) -{ - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) { - Unit_ai_move_air_defense_unit (this); - return; - } - - Unit_ai_move_air_defense_unit (this); - - Unit_set_state (this, __, 0); - if (this->Body.Damage > 0) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - int best_base_score = 0x7fffffff; - int base_x = -1, base_y = -1; - FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, - p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) - continue; - - int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 7, -1, -1); - int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); - int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); - int score = (count * 10) + ((x_dist + y_dist) >> 1); - if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) - score -= 20; - - if (score < best_base_score) { - best_base_score = score; - base_x = aerodrome_x; - base_y = aerodrome_y; - } - } - - if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { - Unit_set_escortee (this, __, -1); - Unit_rebase (this, __, base_x, base_y); - return; - } - - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Intercept); -} - -void __fastcall -patch_Unit_ai_move_air_transport (Unit * this) -{ - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) { - Unit_ai_move_air_transport (this); - return; - } - - Unit_ai_move_air_transport (this); - - if (this->Body.Damage < 1) { - if (Unit_can_airdrop (this)) { - int best_score = 0; - int best_x = -1, best_y = -1; - int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - int grid = op_range * 2 + 1; - if (1 < grid * grid) { - for (int n = 1; n < grid * grid; n++) { - int dx, dy; - neighbor_index_to_diff (n, &dx, &dy); - int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); - int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); - if (Map_in_range (&p_bic_data->Map, __, x, y)) { - int score = Unit_ai_eval_airdrop_target (this, __, x, y); - if (score > best_score) { - best_score = score; - best_x = x; - best_y = y; - } - } - } - if ((best_x >= 0) && (best_y >= 0)) { - Unit_set_escortee (this, __, -1); - Unit_airdrop (this, __, best_x, best_y); - return; - } - } - } - - int best_score = -1; - int base_x = -1, base_y = -1; - FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, - p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) - continue; - - int score = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 0, -1, -1) + - count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 1, -1, -1) + 1; - if (count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 9, -1, -1) == 0) - score *= 2; - int cont_id = aerodrome_tile->vtable->m46_Get_ContinentID (aerodrome_tile); - if ((cont_id >= 0) && (cont_id < p_bic_data->Map.Continent_Count) && - (p_bic_data->Map.Continents[cont_id].Body.TileCount > 0x15)) - score *= 2; - - if (score > best_score) { - best_score = score; - base_x = aerodrome_x; - base_y = aerodrome_y; - } - } - - if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { - Unit_set_escortee (this, __, -1); - Unit_rebase (this, __, base_x, base_y); - if (Unit_count_contained_units (this) > 0) { - patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); - } - return; - } - } - - if (Unit_count_contained_units (this) > 0) - patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); - - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -bool __fastcall -patch_Tile_has_colony_ignore_extraterritorial (Tile * tile) -{ - if (!Tile_has_colony (tile)) - return false; - - if (!is->current_config.allow_extraterritorial_colonies) - return true; - - if ((tile == NULL) || (tile == p_null_tile)) - return true; - - int tile_building_id = tile->vtable->m47_Get_Tile_BuildingID (tile); - if ((tile_building_id < 0) || (p_colonies == NULL) || (p_colonies->Items == NULL) || - (tile_building_id > p_colonies->LastIndex)) - return true; - - Tile_Building_Body * colony_body = p_colonies->Items[tile_building_id].Object; - if ((colony_body == NULL) || ((int)colony_body == offsetof (Tile_Building, Body))) - return true; - - return colony_body->OwnerID == tile->vtable->m38_Get_Territory_OwnerID (tile); -} - -int __fastcall -patch_Leader_get_attitude_toward (Leader * this, int edx, int civ_id, int param_2) -{ - int score = Leader_get_attitude_toward (this, __, civ_id, param_2); - if (!is->current_config.allow_extraterritorial_colonies) - return score; - - int penalty = is->current_config.per_extraterritorial_colony_relation_penalty; - if (penalty != 0) { - int this_civ_id = this->ID; - if ((p_colonies != NULL) && (p_colonies->Items != NULL)) { - for (int n = 0; n <= p_colonies->LastIndex; n++) { - Tile_Building_Body * colony_body = p_colonies->Items[n].Object; - if ((colony_body == NULL) || - ((int)colony_body == offsetof (Tile_Building, Body))) - continue; - - Tile * tile = tile_at (colony_body->X, colony_body->Y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != this_civ_id) - continue; - if (colony_body->OwnerID != civ_id) - continue; - score -= penalty; - } - } - } - return score; -} - -void __fastcall -patch_UnitIDList_insert_after_init (UnitIDList * this, int edx, int id, UnitIDItem * item) -{ - // If using non-standard unit cycling, avoid calling this method b/c it sometimes causes a crash - if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) - UnitIDList_insert_after (this, __, id, item); -} - -bool __fastcall -patch_Tile_m17_Check_Irrigation (Tile * this, int edx, int visible_to_civ_id) -{ - bool base = Tile_m17_Check_Irrigation (this, __, visible_to_civ_id); - if (base) - return true; - - if (! is->current_config.enable_districts) - return base; - - struct district_instance * inst = get_district_instance (this); - if (inst == NULL) - return base; - - if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (this, inst->district_id)) - return true; - - return base; -} - -int __fastcall -patch_Unit_ai_eval_bombard_target (Unit * this, int edx, int tile_x, int tile_y, int param_3) -{ - int score = Unit_ai_eval_bombard_target (this, __, tile_x, tile_y, param_3); - - if (! (is->current_config.enable_districts && - is->current_config.enable_great_wall_districts)) - return score; - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return score; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID) || (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID))) - return score; - - int obsolete_id = is->district_infos[GREAT_WALL_DISTRICT_ID].obsoleted_by_id; - if ((obsolete_id >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, obsolete_id)) - return score; - - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_id <= 0) || (owner_id == this->Body.CivID)) - return score; - if (! this->vtable->is_enemy_of_civ (this, __, owner_id, false)) - return score; - - bool has_unit_on_tile = false; - bool has_enemy_on_tile = false; - Leader * me = &leaders[this->Body.CivID]; - FOR_UNITS_ON (uti, tile) { - UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; - if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0)) { - has_unit_on_tile = true; - if (me->At_War[uti.unit->Body.CivID]) { - if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { - has_enemy_on_tile = true; - break; - } - } else - break; - } - } - - if (has_unit_on_tile && ! has_enemy_on_tile) - return score; - - // Boost score to prioritize Great Wall targets - if (score < 0x6000) - score = 0x6000; - - // Additional boost if there is no unit on it, more likely to destroy it - if (! has_enemy_on_tile) - score += 0x200; - - return score; -} - -void __fastcall -patch_Unit_heal_at_start_of_turn (Unit * this) -{ - if (is->current_config.enable_districts) { - Tile * tile = tile_at ((this->Body).X, (this->Body).Y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id) && - is->district_configs[inst->district_id].heal_units_in_one_turn) { - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (territory_owner == this->Body.CivID) { - (this->Body).Damage = 0; - return; - } - } - } - } - - Unit_heal_at_start_of_turn (this); -} - -// Makes naval AI treat enemy port districts as valid targets to path toward. -int __cdecl -patch_get_tile_occupier_id_in_Unit_ai_move_naval_power_unit (int x, int y, int pov_civ_id, bool respect_unit_invisibility) -{ - int base = get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); - if (base != -1) - return base; - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return -1; - - Tile * tile = tile_at (x, y); - if (tile == NULL || tile == p_null_tile) - return -1; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return -1; - - return (*tile->vtable->m38_Get_Territory_OwnerID) (tile); -} - -// Returns a non-zero score for enemy port district tiles so they pass the threshold check and are bombard targets -int __fastcall -patch_Fighter_eval_tile_vulnerability_in_Unit_ai_move_naval_power_unit (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) -{ - int base = Fighter_eval_tile_vulnerability (this, __, unit, tile_x, tile_y); - if (base > 0) - return base; - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if (tile == NULL || tile == p_null_tile) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return base; - - int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); - if (owner <= 0 || owner == unit->Body.CivID) - return base; - - if (! leaders[unit->Body.CivID].At_War[owner]) - return base; - - // Return a score high enough to pass threshold (iVar13 * 8 + 0x100) - // 0x300 should be sufficient for most cases - return 0x300; -} - -// Returns the territory owner for enemy port districts so the score isn't reduced and naval units move to enemy ports -// (to subsequently pillage them) -int __cdecl -patch_get_combat_occupier_in_Unit_ai_move_naval_power_unit (int tile_x, int tile_y, int civ_id, byte ignore_visibility) -{ - int base = get_combat_occupier (tile_x, tile_y, civ_id, ignore_visibility); - if (base != -1) - return base; - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if (tile == NULL || tile == p_null_tile) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return base; - - int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); - if (owner <= 0 || owner == civ_id) - return base; - - if (! leaders[civ_id].At_War[owner]) - return base; - - return owner; -} - -int __fastcall -patch_rand_int_to_enslave (void * this, int edx, int lim) -{ - // lim is 100, enslaving happens if the return value is < 33 - int r = rand_int (this, __, lim); - return is->do_not_enslave_units ? 100 : r; -} - -int __fastcall -patch_Sprite_draw_espionage_screen_target_civ_bkg (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - // Figure out which of the potential target civs we're drawing by working backwards from the Y location - int top = (p_bic_data->ScreenHeight - p_espionage_form->Image.Height) / 2; - is->espionage_form_drawing_target_index = (pixel_y - top - 0x5C) / 0x3a + p_espionage_form->field_1584; - - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -char * __fastcall -patch_Civilopedia_Article_get_name_for_esp_screen (Civilopedia_Article * this) -{ - // Ensure that we have captured a valid civ ID being drawn then, if that civ has an era-specific formal name, return that so that the - // era-specific names apply on the espionage screen. - int target_civ_id; - if (is->espionage_form_drawing_target_index >= 0 && - is->espionage_form_drawing_target_index < p_espionage_form->target_civ_id_count && - (target_civ_id = p_espionage_form->target_civ_ids[is->espionage_form_drawing_target_index]) >= 0 && - target_civ_id < 32 && - is->aliased_civ_formal_name_bits & 1<Name.S; -} - -void __fastcall -patch_Animator_play_one_shot_victory_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) -{ - if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Air && is->current_config.aircraft_victory_animation != NULL) { - struct string_slice slice = {.str = is->current_config.aircraft_victory_animation, .len = strlen (is->current_config.aircraft_victory_animation)}; - find_animation_type_by_name (&slice, true, &anim_type); - } - - Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); -} - -void -clear_selectable_units_list (Main_Screen_Form * main_screen_form, bool include_unit_objects) -{ - // This is what the base game does to clear things at the start of assemble_selectable_units - if (include_unit_objects && p_units->Units != NULL) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if (unit != NULL) - unit->Body.in_selectable_units_list = false; - } - UnitIDItem * item = main_screen_form->selectable_units.first; - while (item != NULL) { - UnitIDItem * next = item->next; - item->vtable->destruct (item, __, 1); - item = next; - } - main_screen_form->selectable_units.first = main_screen_form->selectable_units.last = NULL; - main_screen_form->selectable_units.length = 0; -} - -void __fastcall -patch_Main_Screen_Form_assemble_selectable_units (Main_Screen_Form * this) -{ - if (is->have_loaded_waiting_units) - is->have_loaded_waiting_units = false; - else - table_deinit (&is->waiting_units); - - if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) - Main_Screen_Form_assemble_selectable_units (this); - else { - clear_selectable_units_list (this, true); - this->unit_cycle_cursor = NULL; - this->completed_unit_cycle = false; - } -} - -void __fastcall -patch_Main_Screen_Form_set_selected_unit (Main_Screen_Form * this, int edx, Unit * unit, bool param_2) -{ - // To set a unit to wait, Main_Screen_Form::issue_command calls this method with unit == NULL and param_2 == false. Detect when that's - // happened and record that the unit's been set to wait so we can reimplement the wait command when replacing the base unit cycling logic. - int * p_stack = (int *)&unit; - int ret_addr = p_stack[-1]; - if (ret_addr == SET_SELECTED_UNIT_TO_ISSUE_WAIT_COMMAND_RET && unit == NULL && this->Current_Unit != NULL) { - // Give the unit a waiting level higher than the minimum among all units already set to wait. This ensures that this unit does not get - // immediately picked up again by the cycling logic unless it's the only selectable unit left. This also means that the first unit set - // to wait will be the first cycled to once all the non-waiting units have been moved (it's the only one at level 1). I consider that - // an advantage. - int min_others_waiting_level = INT_MAX; - bool any_others_waiting = false; - FOR_TABLE_ENTRIES (tei, &is->waiting_units) - if (tei.key != this->Current_Unit->Body.ID) { - any_others_waiting = true; - if (tei.value < min_others_waiting_level) - min_others_waiting_level = tei.value; - } - itable_insert (&is->waiting_units, this->Current_Unit->Body.ID, any_others_waiting ? min_others_waiting_level + 1 : 1); - } - - if (unit != NULL) { - is->last_selected_unit.initial_x = is->last_selected_unit.last_x = unit->Body.X; - is->last_selected_unit.initial_y = is->last_selected_unit.last_y = unit->Body.Y; - is->last_selected_unit.type_id = unit->Body.UnitTypeID; - is->last_selected_unit.ptr = unit; - itable_remove (&is->waiting_units, unit->Body.ID); // Clear waiting record when waiting unit is selected - } - - if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD) - clear_selectable_units_list (this, false); - - bool redraw = false; - if (is->current_config.show_ai_city_location_desirability_if_settler) { - int new_perspective = -1; - if (unit != NULL) { - int unit_type_id = unit->Body.UnitTypeID; - int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; - new_perspective = (worker_actions >= 1 && (worker_actions & (UCV_Build_City)) && !is_worker(unit)) ? p_main_screen_form->Player_CivID : -1; - } - - if (new_perspective != is->city_loc_display_perspective) { - is->city_loc_display_perspective = new_perspective; - redraw = true; - } - } - - Main_Screen_Form_set_selected_unit (this, __, unit, param_2); - - // If selecting a new unit, must insert it into the list to ensure it's actually selected. - if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && unit != NULL) { - UnitIDList_insert_before (&this->selectable_units, __, unit->Body.ID, NULL); - this->unit_cycle_cursor = this->selectable_units.first; - } - - if (redraw && ! this->is_now_loading_game) - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -Unit * __fastcall -patch_Main_Screen_Form_find_next_unit_for_cycling (Main_Screen_Form * this) -{ - if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) - return Main_Screen_Form_find_next_unit_for_cycling (this); - - else { - int least_difference = INT_MAX; - Unit * least_different_unit = NULL; - int sx = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_x : is->last_selected_unit.last_x, - sy = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_y : is->last_selected_unit.last_y; - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if (unit != NULL && unit->Body.CivID == this->Player_CivID && Unit_can_cycle_to (unit)) { - int distance = not_above (1<<15, int_abs (unit->Body.X - sx) + int_abs (unit->Body.Y - sy)); - - bool other_type, not_duplicate; { - if (is->last_selected_unit.type_id == unit->Body.UnitTypeID) { - other_type = false; - if (is->last_selected_unit.ptr != NULL) - not_duplicate = ! are_units_duplicate (&is->last_selected_unit.ptr->Body, &unit->Body, false); - else - not_duplicate = true; - } else - other_type = not_duplicate = true; - } - - int wait_level = itable_look_up_or (&is->waiting_units, unit->Body.ID, 0); - - int difference = ((int)wait_level << 20) + (distance << 2) + ((int)other_type << 1) + (int)not_duplicate; - if (difference < least_difference) { - least_difference = difference; - least_different_unit = unit; - } - } - } - this->completed_unit_cycle = least_different_unit == NULL; - return least_different_unit; - } -} - -void __fastcall -patch_City_m22 (City * this, int edx, bool param_1) -{ - int * p_stack = (int *)¶m_1; - int ret_addr = p_stack[-1]; - - City_m22 (this, __, param_1); - - // If the base game method failed to find a new thing for city to build, we've been called by the methods that complete a previous build, and - // the city is owned by the UI controller, the game will crash because there will be no default option for the build selector popup. If we're - // configured to fix that, suggest Wealth for the new build or, failing that, any buildable unit or improvement. - if ( this->Body.Order_Type == 0 - && is->current_config.patch_failure_to_find_new_city_build - && this->Body.CivID == p_main_screen_form->Player_CivID - && ( ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_1 - || ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_2 - || ret_addr == CITY_M22_TO_SPAWN_UNIT_IF_DONE_RETURN)) { - - // Search for an improvement-type order we can build. Choose Wealth if possible, otherwise just pick the first thing that can be built - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (patch_City_can_build_improvement (this, __, n, true)) { - if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { - this->Body.Order_Type = COT_Improvement; - this->Body.Order_ID = n; - break; - } else if (this->Body.Order_Type == 0) { - this->Body.Order_Type = COT_Improvement; - this->Body.Order_ID = n; - } - } - - // If we still don't have a build, pick the first buildable unit - if (this->Body.Order_Type == 0) - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) - if (patch_City_can_build_unit (this, __, n, true, 0, false)) { - this->Body.Order_Type = COT_Unit; - this->Body.Order_ID = n; - break; - } - } -} - -int __fastcall -patch_PCX_Image_process_dom_adv_turn_count_text (PCX_Image * this, int edx, char * str) -{ - if (is->current_config.reformat_turns_remaining_on_domestic_advisor_screen) { - char * start = strstr (str, p_advisor_internal_form->Labels[16].S); // Search for "turns" - if (start == NULL) - start = strstr (str, p_advisor_internal_form->Labels[17].S); // Search for "turn" - - if (start != NULL) { - *start = toupper (*start); // Upcase first letter of "turn/s" - - char s[64]; // Must be same size as "str" param, which is a 64-byte stack-allocated string - snprintf (s, sizeof s, "%.*s %s", start - str, str, start); // Reprint string with space before "Turn/s" - s[(sizeof s) - 1] = '\0'; - memcpy (str, s, sizeof s); - } - } - - return PCX_Image_process_text (this, __, str); -} - -int -compare_menu_unit_items (void const * a, void const * b) -{ - return MenuUnitItem_should_appear_after ((MenuUnitItem *)a, __, (MenuUnitItem *)b) ? 1 : -1; -} - -int __fastcall -patch_MenuUnitList_get_length_before_sorting (MenuUnitList * this) -{ - int length = MenuUnitList_get_length (this); - - if (is->current_config.patch_passengers_out_of_order_on_menu && length > 0) { - qsort (this->items, length, sizeof this->items[0], compare_menu_unit_items); - - // Fix any units not being listed immediately after the unit they're contained in - // First, loop over all units in the list, stopping at each that might contain others - for (int n = 0; n < length - 1; n++) { - Unit * container = this->items[n].unit; - if ((int)container > 1 && // original code checks if unit ptrs are NULL or equal to 1 - p_bic_data->UnitTypes[container->Body.UnitTypeID].Transport_Capacity > 0) { - - // Advance iterator "j" past the container and past any empty slots or correctly positioned units right after it - int j = n + 1; - while (j < length && ((int)this->items[j].unit <= 1 || this->items[j].unit->Body.Container_Unit == container->Body.ID)) - j++; - - // Check the rest of the list for out-of-place passengers - for (int k = j + 1; k < length; k++) { - if ((int)this->items[k].unit > 1 && this->items[k].unit->Body.Container_Unit == container->Body.ID) { - - // Move item from index "k" to index "j" and advance "j" past it - MenuUnitItem moved = this->items[k]; - memmove (&this->items[j + 1], &this->items[j], (k - j) * sizeof this->items[0]); - this->items[j] = moved; - j++; - } - } - } - } - - // The caller is checking if the length is > 0 before sorting the list. Since we've already sorted it, return 0. - return 0; - } else - return length; -} - -void __fastcall -patch_Map_finalize_params_for_scenario_map (Map * this) -{ - Map_finalize_params (this); - - enum barbarian_activity_override barb_override = is->current_config.override_barbarian_activity_level_for_scenario_maps; - if (barb_override != BAO_NONE) { - if (barb_override == BAO_RANDOM) { - LARGE_INTEGER time; - QueryPerformanceCounter (&time); - int r = this->Seed ^ time.u.LowPart; // The map seed will be the same every time so incorporate some entropy - this->World.Final_Barbarians_Activity = rand_int (&r, __, 5) - 1; - } else - this->World.Final_Barbarians_Activity = clamp (-1, 3, barb_override); - } -} - -Unit * __fastcall -patch_Unit_select_army_member_for_combat (Unit * this, int edx, int param_1, char param_2) -{ - if (is->current_config.patch_empty_army_combat_crash) { - int unit_count = 0; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - if (tile != NULL && tile != p_null_tile) { - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit != NULL) && (unit->Body.Container_Unit == this->Body.ID)) - unit_count += Unit_count_contained_units (unit) + 1; - } - } - if (unit_count == 0) - return this; - } - - return Unit_select_army_member_for_combat (this, __, param_1, param_2); -} - -int __fastcall -patch_Tile_check_water_for_canal_move_to_adjacent_tile_dest (Tile * this) -{ - if ((this != NULL) && (this != p_null_tile) && - is->current_config.enable_districts && - is->current_config.enable_canal_districts && - (is->coast_walk_unit != NULL) && - (p_bic_data->UnitTypes[is->coast_walk_unit->Body.UnitTypeID].Unit_Class == UTC_Sea)) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && - (inst->district_id == CANAL_DISTRICT_ID) && - district_is_complete (this, inst->district_id)) - return 1; - } - - return this->vtable->m35_Check_Is_Water (this); -} - -// TCC requires a main function be defined even though it's never used. -int main () { return 0; } +#include "stdlib.h" +#include "stdio.h" + +#include "C3X.h" + +void (WINAPI ** p_OutputDebugStringA) (char * lpOutputString) = ADDR_ADDR_OUTPUTDEBUGSTRINGA; +short (WINAPI ** p_GetAsyncKeyState) (int vKey) = ADDR_ADDR_GETASYNCKEYSTATE; +FARPROC (WINAPI ** p_GetProcAddress) (HMODULE hModule, char const * lpProcName) = ADDR_ADDR_GETPROCADDRESS; +HMODULE (WINAPI ** p_GetModuleHandleA) (char const * lpModuleName) = ADDR_ADDR_GETMODULEHANDLEA; +int (WINAPI ** p_MessageBoxA) (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) = ADDR_ADDR_MESSAGEBOXA; + +struct injected_state * is = ADDR_INJECTED_STATE; + +// To be used as placeholder second argument so that we can imitate thiscall convention with fastcall +#define __ 0 + +// Many Windows and C standard library functions have to be loaded dynamically with GetProcAddress and the addresses are stored in the injected +// state. This is covered up with macros, which is not something I would normally do, but in this case it's very useful because it means the code in +// common.c can be shared by the patcher and the injected code. +#define VirtualProtect is->VirtualProtect +#define CloseHandle is->CloseHandle +#define CreateFileA is->CreateFileA +#define GetFileSize is->GetFileSize +#define ReadFile is->ReadFile +#define LoadLibraryA is->LoadLibraryA +#define FreeLibrary is->FreeLibrary +#define MessageBoxA is->MessageBoxA +#define MultiByteToWideChar is->MultiByteToWideChar +#define WideCharToMultiByte is->WideCharToMultiByte +#define GetLastError is->GetLastError +#define QueryPerformanceCounter is->QueryPerformanceCounter +#define QueryPerformanceFrequency is->QueryPerformanceFrequency +#define GetLocalTime is->GetLocalTime +#define TransparentBlt is->TransparentBlt +#define snprintf is->snprintf +#define malloc is->malloc +#define calloc is->calloc +#define realloc is->realloc +#define free is->free +#define strtol is->strtol +#define strtof is->strtof +#define strncmp is->strncmp +#define strcmp is->strcmp +#define _stricmp is->_stricmp +#define strlen is->strlen +#define strncpy is->strncpy +#define strcpy is->strcpy +#define strdup is->strdup +#define strstr is->strstr +#define qsort is->qsort +#define memcmp is->memcmp +#define memcpy is->memcpy +#define tolower is->tolower +#define toupper is->toupper + +#include "common.c" + +#define TRADE_SCROLL_BUTTON_ID_LEFT 0x222001 +#define TRADE_SCROLL_BUTTON_ID_RIGHT 0x222002 + +// Must match size of button images in descbox.pcx +#define MOD_INFO_BUTTON_WIDTH 102 +#define MOD_INFO_BUTTON_HEIGHT 17 + +#define MOD_INFO_BUTTON_ID 0x222003 + +#define PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID 0x222004 +#define PEDIA_MULTIPAGE_PREV_BUTTON_ID 0x222005 + +#define TILE_FLAG_ROAD 0x1 +#define TILE_FLAG_RAILROAD 0x2 +#define TILE_FLAG_MINE 0x4 +#define TILE_FLAG_IRRIGATION 0x8 + +#define NEIGHBORHOOD_DISTRICT_ID 0 +#define WONDER_DISTRICT_ID 1 +#define DISTRIBUTION_HUB_DISTRICT_ID 2 +#define AERODROME_DISTRICT_ID 3 +#define NATURAL_WONDER_DISTRICT_ID 4 +#define PORT_DISTRICT_ID 5 +#define CENTRAL_RAIL_HUB_DISTRICT_ID 6 +#define ENERGY_GRID_DISTRICT_ID 7 +#define BRIDGE_DISTRICT_ID 8 +#define CANAL_DISTRICT_ID 9 +#define GREAT_WALL_DISTRICT_ID 10 + +#define MAX_DISTRICT_VARIANT_COUNT 5 +#define MAX_DISTRICT_ERA_COUNT 4 +#define MAX_DISTRICT_COLUMN_COUNT 10 + +// Max grid of tiles that an AI will evaluate a candidate bridge or canal for, +// used to limit computational complexity +#define AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES 10 + +enum { NAMED_TILE_MENU_ID = 0x90 }; + +char const * const hotseat_replay_save_path = "Saves\\Auto\\ai-move-replay-before-interturn.SAV"; +char const * const hotseat_resume_save_path = "Saves\\Auto\\ai-move-replay-resume.SAV"; + +// Need to define memmove for use by TCC when generated code for functions that return a struct +void * +memmove (void * dest, void const * src, size_t size) +{ + return is->memmove (dest, src, size); +} + +// Also need to define memset for some reason +void * +memset (void * dest, int ch, size_t count) +{ + for (size_t n = 0; n < count; n++) + ((char *)dest)[n] = ch; + return dest; +} + +// Computes num/denom randomly rounded off so that E[rand_div (x,y)] = (float)x/y +// As an example: E[rand_div (6, 5)] = 1.2, it will return 1 with 80% probability and 2 with 20% prob. +int +rand_div (int num, int denom) +{ + int q = num / denom, + r = num % denom; + return q + (rand_int (p_rand_object, __, denom) < r); +} + +bool +are_tiles_adjacent (int ax, int ay, int bx, int by) +{ + int x_dist = int_abs (ax - bx), + y_dist = int_abs (ay - by); + + // Handle edge wrapping by counting from the opposite direction if it would be shorter + if (p_bic_data->Map.Flags & 1) { // if map wraps horizontally + int width = p_bic_data->Map.Width; + if (x_dist > (width>>1)) + x_dist = width - x_dist; + } + if (p_bic_data->Map.Flags & 2) { // if map wraps vertically + int height = p_bic_data->Map.Height; + if (y_dist > (height>>1)) + y_dist = height - y_dist; + } + + return (x_dist + y_dist) == 2; +} + +int +compute_wrapped_component (int diff, int size, bool wraps) +{ + if (! wraps || (size <= 0)) + return diff; + + int half = size >> 1; + if (diff > half) + diff = size - diff; + return diff; +} + +void +compute_wrapped_deltas (int ax, int ay, int bx, int by, int * out_dx, int * out_dy) +{ + int dx = int_abs (ax - bx); + int dy = int_abs (ay - by); + bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; + bool wraps_vert = (p_bic_data->Map.Flags & 2) != 0; + dx = compute_wrapped_component (dx, p_bic_data->Map.Width, wraps_horiz); + dy = compute_wrapped_component (dy, p_bic_data->Map.Height, wraps_vert); + if (out_dx != NULL) + *out_dx = dx; + if (out_dy != NULL) + *out_dy = dy; +} + +int +compute_wrapped_manhattan_distance (int ax, int ay, int bx, int by) +{ + int dx, dy; + compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); + return dx + dy; +} + +int +compute_wrapped_chebyshev_distance (int ax, int ay, int bx, int by) +{ + int dx, dy; + compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); + return (dx > dy) ? dx : dy; +} + +bool +tile_has_resource (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + int resource_type = tile->vtable->m39_Get_Resource_Type (tile); + return (resource_type >= 0) && (resource_type < p_bic_data->ResourceTypeCount); +} + +City * +get_city_ptr (int id) +{ + if ((p_cities->Cities != NULL) && + (id >= 0) && (id <= p_cities->LastIndex)) { + City_Body * body = p_cities->Cities[id].City; + if (body != NULL) { + City * city = (City *)((char *)body - offsetof (City, Body)); + if (city != NULL) + return city; + } + } + return NULL; +} + +// Forward declarations for unit counter system (defined after their dependencies) +enum recognizable_parse_result parse_unit_counter_group (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_group); +enum recognizable_parse_result parse_counter_rule (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_rule); + +// Declare various functions needed for districts and hard to untangle and reorder here +void __fastcall patch_City_recompute_yields_and_happiness (City * this); +void __fastcall patch_Map_build_trade_network (Map * this); +bool __fastcall patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value); +bool __fastcall patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y); +bool __fastcall patch_City_has_resource (City * this, int edx, int resource_id); +bool __fastcall patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2); +char __fastcall patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing); +void __fastcall patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7); +bool can_build_district_on_tile (Tile * tile, int district_id, int civ_id); +bool city_can_build_district (City * city, int district_id); +bool leader_can_build_district (Leader * leader, int district_id); +bool wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id); +bool find_civ_trait_id_by_name (struct string_slice const * name, int * out_id); +bool find_civ_culture_id_by_name (struct string_slice const * name, int * out_id); +Tile * find_tile_for_district (City * city, int district_id, int * out_x, int * out_y); +struct district_instance * get_district_instance (Tile * tile); +struct named_tile_entry * get_named_tile_entry (Tile * tile); +bool city_has_required_district (City * city, int district_id); +bool district_is_complete (Tile * tile, int district_id); +bool city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id); +void clear_city_district_request (City * city, int district_id); +void set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y); +bool city_radius_contains_tile (City * city, int tile_x, int tile_y); +void on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y); +bool ai_move_district_worker (Unit * worker, struct district_worker_record * rec); +bool has_active_building (City * city, int improv_id); +bool tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv); +void recompute_distribution_hub_totals (); +void get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y); +void wrap_tile_coords (Map * map, int * x, int * y); +int count_neighborhoods_in_city_radius (City * city); +int count_utilized_neighborhoods_in_city_radius (City * city); +char * copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes); +bool city_has_resource_r (City * city, int resource_id, int max_generated_resource_id); + +struct pause_for_popup { + bool done; // Set to true to exit for loop + bool redundant; // If true, this pause would overlap a previous one and so should not be counted + long long ts_before; +}; + +struct pause_for_popup +pfp_init () +{ + struct pause_for_popup tr; + tr.done = false; + tr.redundant = is->paused_for_popup; + if (! tr.redundant) { + is->paused_for_popup = true; + QueryPerformanceCounter ((LARGE_INTEGER *)&tr.ts_before); + } + return tr; +} + +void +pfp_finish (struct pause_for_popup * pfp) +{ + if ((! pfp->redundant) && (! pfp->done)) { + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + is->time_spent_paused_during_popup += ts_after - pfp->ts_before; + is->paused_for_popup = false; + } + pfp->done = true; +} + +#define WITH_PAUSE_FOR_POPUP for (struct pause_for_popup pfp = pfp_init (); ! pfp.done; pfp_finish (&pfp)) + +int __fastcall +patch_show_popup (void * this, int edx, int param_1, int param_2) +{ + int tr; + WITH_PAUSE_FOR_POPUP { + is->show_popup_was_called = 1; + tr = show_popup (this, __, param_1, param_2); + } + return tr; +} + +void +pop_up_in_game_error (char const * msg) +{ + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); + PopupForm_add_text (popup, __, (char *)msg, false); + patch_show_popup (popup, __, 0, 0); +} + +void +memoize (int val) +{ + if (is->memo_len < is->memo_capacity) + is->memo[is->memo_len++] = val; + else { + int new_capacity = not_below (100, 2 * is->memo_capacity); + int * new_memo = malloc (new_capacity * sizeof is->memo[0]); + if (new_memo != NULL) { + for (int n = 0; n < is->memo_len; n++) + new_memo[n] = is->memo[n]; + free (is->memo); + is->memo = new_memo; + is->memo_capacity = new_capacity; + is->memo[is->memo_len++] = val; + } + } + +} + +void +clear_memo () +{ + is->memo_len = 0; +} + +// The maximum possible cultural neighbor index. We don't bother dealing with indices beyond this b/c it's the last tile in the seventh ring. Also +// equals one less than the tile count up to & inc. the seventh ring b/c of the zeroth tile. +#define MAX_CULTURAL_NI 192 + +// Number of workable tiles including the city center for each workable radius +unsigned char const workable_tile_counts[8] = {1, 9, 21, 37, 61, 89, 137, 193}; + +char const cultural_ni_to_diffs[(MAX_CULTURAL_NI + 1) * 2] = +{ + 0, 0, + +// first ring + 1, -1, 2, 0, 1, 1, 0, 2, -1, 1, -2, 0, -1, -1, + 0, -2, + +// second ring + 1, -3, 2, -2, 3, -1, 3, 1, 2, 2, 1, 3, -1, 3, -2, 2, + -3, 1, -3, -1, -2, -2, -1, -3, + +// third ring + 0, -4, 4, 0, 0, 4, -4, 0, 2, -4, 3, -3, 4, -2, 4, 2, + 3, 3, 2, 4, -2, 4, -3, 3, -4, 2, -4, -2, -3, -3, -2, -4, + +// fourth ring + 1, -5, 5, -1, 5, 1, 1, 5, -1, 5, -5, 1, -5, -1, -1, -5, + 0, -6, 6, 0, 0, 6, -6, 0, 3, -5, 4, -4, 5, -3, 5, 3, + 4, 4, 3, 5, -3, 5, -4, 4, -5, 3, -5, -3, -4, -4, -3, -5, + +// fifth ring + 1, -7, 2, -6, 6, -2, 7, -1, 7, 1, 6, 2, 2, 6, 1, 7, + -1, 7, -2, 6, -6, 2, -7, 1, -7, -1, -6, -2, -2, -6, -1, -7, + 4, -6, 5, -5, 6, -4, 6, 4, 5, 5, 4, 6, -4, 6, -5, 5, + -6, 4, -6, -4, -5, -5, -4, -6, + +// sixth ring + 0, -8, 8, 0, 0, 8, -8, 0, 1, -9, 2, -8, 3, -7, 7, -3, + 8, -2, 9, -1, 9, 1, 8, 2, 7, 3, 3, 7, 2, 8, 1, 9, + -1, 9, -2, 8, -3, 7, -7, 3, -8, 2, -9, 1, -9, -1, -8, -2, + -7, -3, -3, -7, -2, -8, -1, -9, 4, -8, 5, -7, 6, -6, 7, -5, + 8, -4, 8, 4, 7, 5, 6, 6, 5, 7, 4, 8, -4, 8, -5, 7, + -6, 6, -7, 5, -8, 4, -8, -4, -7, -5, -6, -6, -5, -7, -4, -8, + +// seventh ring + 0, -10, 10, 0, 0, 10, -10, 0, 1, -11, 2, -10, 3, -9, 9, -3, + 10, -2, 11, -1, 11, 1, 10, 2, 9, 3, 3, 9, 2, 10, 1, 11, + -1, 11, -2, 10, -3, 9, -9, 3, -10, 2, -11, 1, -11, -1, -10, -2, + -9, -3, -3, -9, -2, -10, -1, -11, 4, -10, 5, -9, 6, -8, 7, -7, + 8, -6, 9, -5, 10, -4, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, + 5, 9, 4, 10, -4, 10, -5, 9, -6, 8, -7, 7, -8, 6, -9, 5, + -10, 4, -10, -4, -9, -5, -8, -6, -7, -7, -6, -8, -5, -9, -4, -10 +}; + +// Like neighbor_index_to_diff, but enumerates tiles in an order that matches cultural border expansion. Only valid for 0 <= neighbor_index <= MAX_CULTURAL_NI. +void __cdecl +patch_ni_to_diff_for_work_area (int neighbor_index, int * x_disp, int * y_disp) +{ + if (neighbor_index <= 0) { + *x_disp = *y_disp = 0; + return; + } else if (neighbor_index > MAX_CULTURAL_NI) + neighbor_index = neighbor_index % (MAX_CULTURAL_NI + 1); + + int i = neighbor_index << 1; + char const * p = &cultural_ni_to_diffs[neighbor_index << 1]; + *x_disp = p[0]; + *y_disp = p[1]; +} + +int __fastcall +patch_City_find_min_value_tile (City * this) +{ + int tr = City_find_min_value_tile (this); + + // The original function has been edited to enumerate tiles in our custom order matching cultural borders instead of the game's original + // order. It returns a neighbor index from that enumeration. We must convert it to standard order if it's beyond the range where the two + // enumerations overlap. + if (tr >= 21) + tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; + + return tr; +} + +int __fastcall +patch_City_find_best_tile_to_work (City * this, int edx, Unit * worker, bool param_2) +{ + int tr = City_find_best_tile_to_work (this, __, worker, param_2); + if (tr >= 21) + tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; + return tr; +} + +bool __fastcall +City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 21) && (neighbor_index <= MAX_CULTURAL_NI)) + neighbor_index = is->cultural_ni_to_standard[neighbor_index]; + return City_stop_working_tile (this, __, neighbor_index); +} + +int __fastcall +patch_Map_compute_ni_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + // Within the first two rings, there's no difference b/w the standard and custom "work area" neighbor indices so fall back to the base game's + // function in that case. + if (is->workable_tile_count <= 21) + return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); + + // If the work area has been expanded, compute the neighbor index then check that it's within the area. Ignore the limit we were passed and + // instead use the number of tiles in the workable area, doubled to cover the difference between cultural vs standard enumeration. + else { + int ni = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, 2 * is->workable_tile_count); + if ((ni >= 0) && (ni <= ARRAY_LEN (is->ni_to_work_radius)) && + (is->ni_to_work_radius[ni] >= 0) && + (is->ni_to_work_radius[ni] <= is->current_config.city_work_radius)) + return ni; + else + return -1; + } +} + +int __fastcall +patch_Map_m28_find_cnter_neigh_point_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + int ret_addr = ((int *)&x_home)[-1]; + if (ret_addr != ADDR_FIND_CENTER_NP_SPOTLIGHT_RET) + return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); + else + return patch_Map_compute_ni_for_work_area (this, __, x_home, y_home, x_neigh, y_neigh, 500); +} + +int +get_work_ring_limit_by_culture (City * city) +{ + if (is->current_config.work_area_limit == WAL_NONE) + return INT_MAX; + else { + int lower_lim = (is->current_config.work_area_limit == WAL_CULTURAL_MIN_2) ? 2 : 1; + return not_below (lower_lim, city->Body.cultural_level); + } +} + +int +get_work_ring_limit_by_improvements (City * city) +{ + if (is->current_config.count_work_area_improvements == 0) + return INT_MAX; + else { + int maxRadius = 0; + int bonusRadius = 0; + for (int n = 0; n < is->current_config.count_work_area_improvements; n++) { + struct work_area_improvement * work_area_improvement = &is->current_config.work_area_improvements[n]; + if (work_area_improvement->work_area_radius_limit > maxRadius && + (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { + maxRadius = work_area_improvement->work_area_radius_limit; + } + if (work_area_improvement->work_area_radius_bonus > 0 && + (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { + bonusRadius += work_area_improvement->work_area_radius_bonus; + } + } + return maxRadius + bonusRadius; + } +} + +int +get_work_ring_limit_total (City * city) +{ + int cultureLimit = get_work_ring_limit_by_culture(city); + int improvementLimit = get_work_ring_limit_by_improvements(city); + if (cultureLimit < improvementLimit) + return cultureLimit; + return improvementLimit; +} + +bool __fastcall +patch_City_controls_tile (City * this, int edx, int neighbor_index, bool consider_enemy_units) +{ + // Check that this tile is not outside the city's work area. We've deleted a check from the base game code that verifies the n.i. is within 21 + // tiles so we can replicate it here in a way that also works for an expanded work area. + int work_radius = ((neighbor_index >= 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) ? is->ni_to_work_radius[neighbor_index] : -1; + if ((work_radius > is->current_config.city_work_radius) || (work_radius < 0)) + return false; + + int work_ring_limit = get_work_ring_limit_total (this); + if (work_radius > work_ring_limit) { + + // May consider this tile within the limit if any adjacent tiles are within the limit & within borders + bool exempt_from_limit; + if (is->current_config.work_area_limit != WAL_CULTURAL_OR_ADJACENT) + exempt_from_limit = false; + else if (neighbor_index >= 9) { + exempt_from_limit = false; + int center_x, center_y; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, ¢er_x, ¢er_y); + int neighbors_checked = 0; + for (int ni = 1; ni < ARRAY_LEN (is->ni_to_work_radius); ni++) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, ni, &nx, &ny); + if (are_tiles_adjacent (center_x, center_y, nx, ny)) { + neighbors_checked++; + int wr = is->ni_to_work_radius[ni]; + Tile * neighbor; + if (((wr >= 0) && (wr <= work_ring_limit)) && + (neighbor = tile_at (nx, ny)) && + (neighbor->vtable->m38_Get_Territory_OwnerID (neighbor) == this->Body.CivID)) { + exempt_from_limit = true; + break; + } + } + if (neighbors_checked == 8) + break; + } + } else + exempt_from_limit = true; + + if (! exempt_from_limit) + return false; + } + + if (neighbor_index >= 0) { + int tile_x, tile_y; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + // Check if the tile itself is a completed district (includes natural wonders) + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id)) + return false; + + // Check if the tile is covered by a distribution hub + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + return false; + } + } + } + } + + return City_controls_tile (this, __, neighbor_index, consider_enemy_units); +} + +bool __fastcall +patch_City_controls_tile_conv_ni (City * this, int edx, int neighbor_index, bool consider_enemy_units) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return patch_City_controls_tile (this, __, is->cultural_ni_to_standard[neighbor_index], consider_enemy_units); + else + return false; +} + +bool __fastcall +patch_City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return City_stop_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); + else + return false; +} + +bool __fastcall +patch_City_start_working_tile_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return City_start_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); + else + return false; +} + +void __fastcall +patch_City_add_or_remove_tile_yield_conv_ni (City * this, int edx, int neighbor_index, bool add_else_remove) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + City_add_or_remove_tile_yield (this, __, is->cultural_ni_to_standard[neighbor_index], add_else_remove); +} + +bool __fastcall +patch_City_is_neighboring_tile_in_area_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return City_is_neighboring_tile_in_area (this, __, is->cultural_ni_to_standard[neighbor_index]); + else + return false; +} + +int +get_city_screen_center_y (City * city) +{ + int y = city->Body.Y; + if (p_bic_data->is_zoomed_out) + return y + 7; // when zoomed out, shift map up to center city + else if (is->current_config.city_work_radius >= 3) + return y + 4; // when work radius is 3, shift map up one extra tile so as not to overlap citizen heads + else + return y + 2; // base game behavior +} + +void __fastcall +patch_Main_Screen_Form_bring_cnter_view_city_focus (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) +{ + // If the city we're viewing can work tiles in the 4+ ring then zoom out the map display to show them + int effective_radius = not_above (get_work_ring_limit_total (p_city_form->CurrentCity), is->current_config.city_work_radius); + if (is->current_config.work_area_limit == WAL_CULTURAL_OR_ADJACENT) + effective_radius = not_above (is->current_config.city_work_radius, effective_radius + 1); + if (effective_radius >= 4 && is->current_config.auto_zoom_city_screen_for_large_work_areas) + p_bic_data->is_zoomed_out = true; + + Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); +} + +void __fastcall +patch_Main_Screen_Form_bring_cnter_view_city_arrow (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) +{ + Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); +} + +void tile_index_to_coords (Map * map, int index, int * out_x, int * out_y); + +Tile * __fastcall +patch_Map_get_tile_for_work_area_drawing (Map * this, int edx, int index) +{ + Tile * tr = Map_get_tile (this, __, index); + + if (tr != p_null_tile) { + int x, y; + tile_index_to_coords (this, index, &x, &y); + City * viewing_city = p_city_form->CurrentCity; + int ni = Map_compute_neighbor_index (this, __, viewing_city->Body.X, viewing_city->Body.Y, x, y, 1000); + if ((ni > 0) && ! patch_City_controls_tile (viewing_city, __, ni, false)) + tr = p_null_tile; + } + + return tr; +} + +// Resets is->current_config to the base config and updates the list of config names. Does NOT re-apply machine code edits. +void +reset_to_base_config () +{ + struct c3x_config * cc = &is->current_config; + + for (int n = 0; n < ARRAY_LEN (cc->limit_units_per_tile); n++) + cc->limit_units_per_tile[n] = 0; + + table_deinit (&cc->exclude_types_from_units_per_tile_limit); + + for (int n = 0; n < COUNT_PERFUME_KINDS; n++) + stable_deinit (&cc->perfume_specs[n]); + + // Free building-unit prereqs table + FOR_TABLE_ENTRIES (tei, &cc->building_unit_prereqs) { + if ((tei.value & 1) == 0) + free ((void *)tei.value); + } + table_deinit (&cc->building_unit_prereqs); + + // Free list of mills + if (cc->mills != NULL) { + free (cc->mills); + cc->mills = NULL; + cc->count_mills = 0; + } + + // Free list of AI multi-city start extra palaces + if (cc->ai_multi_start_extra_palaces != NULL) { + free (cc->ai_multi_start_extra_palaces); + cc->ai_multi_start_extra_palaces = NULL; + cc->count_ai_multi_start_extra_palaces = 0; + cc->ai_multi_start_extra_palaces_capacity = 0; + } + + table_deinit (&cc->limit_defensive_retreat_on_water_to_types); + table_deinit (&cc->can_bombard_only_sea_tiles); + + // Free set of PTW artillery types and list of converted types + table_deinit (&cc->ptw_arty_types); + if (is->charmed_types_converted_to_ptw_arty != NULL) { + free (is->charmed_types_converted_to_ptw_arty); + is->charmed_types_converted_to_ptw_arty = NULL; + is->count_charmed_types_converted_to_ptw_arty = 0; + is->charmed_types_converted_to_ptw_arty_capacity = 0; + } + + // Free era alias lists + if (cc->civ_era_alias_lists != NULL) { + for (int n = 0; n < cc->count_civ_era_alias_lists; n++) { + struct civ_era_alias_list * list = &cc->civ_era_alias_lists[n]; + free (list->key); + for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) + free (list->aliases[k]); + } + free (cc->civ_era_alias_lists); + cc->civ_era_alias_lists = NULL; + cc->count_civ_era_alias_lists = 0; + } + if (cc->leader_era_alias_lists != NULL) { + for (int n = 0; n < cc->count_leader_era_alias_lists; n++) { + struct leader_era_alias_list * list = &cc->leader_era_alias_lists[n]; + free (list->key); + for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) { + free (list->aliases[k]); + free (list->titles[k]); + } + } + free (cc->leader_era_alias_lists); + cc->leader_era_alias_lists = NULL; + cc->count_leader_era_alias_lists = 0; + } + + // Free list of work_area_improvements + if (cc->work_area_improvements != NULL) { + free (cc->work_area_improvements); + cc->work_area_improvements = NULL; + cc->count_work_area_improvements = 0; + } + + // Free aircraft victory animation string + if (cc->aircraft_victory_animation != NULL) { + free (cc->aircraft_victory_animation); + cc->aircraft_victory_animation = NULL; + } + + if (cc->great_wall_auto_build_wonder_name != NULL) { + free (cc->great_wall_auto_build_wonder_name); + cc->great_wall_auto_build_wonder_name = NULL; + } + + if (cc->unit_counter_groups != NULL) { + for (int n = 0; n < cc->count_unit_counter_groups; n++) { + free (cc->unit_counter_groups[n].name); + free (cc->unit_counter_groups[n].type_ids); + } + free (cc->unit_counter_groups); + cc->unit_counter_groups = NULL; + cc->count_unit_counter_groups = 0; + } + + if (cc->counter_rules != NULL) { + for (int n = 0; n < cc->count_counter_rules; n++) { + free (cc->counter_rules[n].attacker_group); + free (cc->counter_rules[n].defender_group); + free (cc->counter_rules[n].district_name); + } + free (cc->counter_rules); + cc->counter_rules = NULL; + cc->count_counter_rules = 0; + } + + // Free unit limits table + FOR_TABLE_ENTRIES (tei, &cc->unit_limits) + free ((void *)tei.value); + stable_deinit (&cc->unit_limits); + + // Free the linked list of loaded config names and the string name contained in each one + if (is->loaded_config_names != NULL) { + struct loaded_config_name * next = is->loaded_config_names; + while (next != NULL) { + struct loaded_config_name * to_free = next; + next = next->next; + free (to_free->name); + free (to_free); + } + } + + // Overwrite the current config with the base config + memcpy (&is->current_config, &is->base_config, sizeof is->current_config); + + // These fields are heap-allocated and must not be inherited from base_config + // (base_config never owns valid pointers for them) + is->current_config.unit_counter_groups = NULL; + is->current_config.count_unit_counter_groups = 0; + is->current_config.counter_rules = NULL; + is->current_config.count_counter_rules = 0; + + // Recreate loaded config names list with just the base config + is->loaded_config_names = malloc (sizeof *is->loaded_config_names); + is->loaded_config_names->name = strdup ("(base)"); + is->loaded_config_names->next = NULL; + + // Update IS variable that's tied to a config value + is->workable_tile_count = workable_tile_counts[is->current_config.city_work_radius]; +} + +struct id_list { + int length; + int capacity; + int ids[0]; +}; + +struct id_list * +alloc_id_list (int capacity, struct id_list const * copy) +{ + struct id_list * tr = malloc ((sizeof *tr) + capacity * sizeof(tr->ids[0])); + tr->length = 0; + tr->capacity = capacity; + if (copy != NULL) { + int new_len = not_above (capacity, copy->length); + for (int n = 0; n < new_len; n++) + tr->ids[n] = copy->ids[n]; + tr->length = new_len; + } + return tr; +} + +// This is the largest ID that will be stored inline inside sidtables. The amount here must be smaller than any pointer we'd get from malloc since the +// sidtable code compares values against this amount to determine which are inlined values versus pointers. +#define SID_TABLE_MAX_INLINE_ID 10000 + +void +sidtable_deinit (struct table * t) +{ + FOR_TABLE_ENTRIES (tei, t) { + free ((void *)tei.key); + if (tei.value > SID_TABLE_MAX_INLINE_ID) + free ((void *)tei.value); + } + table_deinit (t); +} + +void +sidtable_append (struct table * t, struct string_slice const * key, int id) +{ + // Expand or allocate table as needed + if (t->len >= table_capacity (t) / 2) + table__expand (t, hash_str, compare_str_keys); + + size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); + int * entry = &((int *)TABLE__BASE (t))[2*index]; + if (table__is_occupied (t, index)) { // If key is already in the table + int prev_val = entry[1]; + if (prev_val <= SID_TABLE_MAX_INLINE_ID) { // If prev value is an id, convert it to a list + struct id_list * new_list = alloc_id_list (2, NULL); + new_list->ids[0] = prev_val; + new_list->ids[1] = id; + new_list->length = 2; + entry[1] = (int)new_list; + } else { // Else, prev value is a list so append the new ID to it + struct id_list * list = (void *)prev_val; + if (list->length >= list->capacity) { // Expand list if necessary + struct id_list * new_list = alloc_id_list (2 * list->capacity, list); + entry[1] = (int)new_list; + free (list); + list = new_list; + } + list->ids[list->length] = id; + list->length++; + } + } else { // Key is not in the table, add it for the first time + entry[0] = (int)extract_slice (key); + if (id <= SID_TABLE_MAX_INLINE_ID) // Write ID inline if possible + entry[1] = id; + else { // Otherwise create a list for this one ID + struct id_list * new_list = alloc_id_list (2, NULL); + new_list->ids[0] = id; + new_list->length = 1; + entry[1] = (int)new_list; + } + table__set_occupation (t, index, 1); + t->len++; + } +} + +bool +sidtable_get_by_index (struct table const * t, size_t index, int ** out_ids, int * out_count) +{ + size_t capacity = table_capacity (t); + if ((capacity > 0) && (index < capacity) && table__is_occupied (t, index)) { + int * entry = &((int *)TABLE__BASE (t))[2*index]; + int val = entry[1]; + if (val <= SID_TABLE_MAX_INLINE_ID) { // Value is an ID + *out_ids = &entry[1]; + *out_count = 1; + } else { + struct id_list * list = (void *)val; + *out_ids = &list->ids[0]; + *out_count = list->length; + } + return true; + } else + return false; +} + +bool +sidtable_look_up (struct table const * t, char const * key, int ** out_ids, int * out_count) +{ + if (t->len > 0) { + size_t index = table__place (t, compare_str_keys, (int)key, hash_str ((int)key)); + return sidtable_get_by_index (t, index, out_ids, out_count); + } else + return false; +} + +bool +sidtable_look_up_slice (struct table const * t, struct string_slice const * key, int ** out_ids, int * out_count) +{ + if (t->len > 0) { + size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); + return sidtable_get_by_index (t, index, out_ids, out_count); + } else + return false; +} + +struct error_line { + char text[200]; + struct error_line * next; +}; + +struct error_line * +add_error_line (struct error_line ** p_lines) +{ + struct error_line * tr = calloc (1, sizeof *tr); + + struct error_line ** p_prev = p_lines; + while (*p_prev != NULL) + p_prev = &(*p_prev)->next; + *p_prev = tr; + + return tr; +} + +void +add_unrecognized_line (struct error_line ** p_lines, struct string_slice const * name) +{ + struct error_line * line = add_error_line (p_lines); + char s[100]; + snprintf (line->text, sizeof line->text, "^ %.*s", name->len, name->str); + line->text[(sizeof line->text) - 1] = '\0'; +} + +void +free_error_lines (struct error_line * lines) +{ + while (lines != NULL) { + struct error_line * next = lines->next; + free (lines); + lines = next; + } +} + +bool +find_improv_id_by_name (struct string_slice const * name, int * out) +{ + Improvement * improv; + if (name->len <= sizeof improv->Name) + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { + *out = n; + return true; + } + return false; +} + +// start_id specifies where the search will start. It's useful for finding multiple type IDs with the same name, which commonly happens due to the +// game duplicating unit types. +bool +find_unit_type_id_by_name (struct string_slice const * name, int start_id, int * out) +{ + UnitType * unit_type; + if (name->len <= sizeof unit_type->Name) + for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) + if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { + *out = n; + return true; + } + return false; +} + +bool +find_resource_id_by_name (struct string_slice const * name, int * out) +{ + Resource_Type * res_type; + if (name->len <= sizeof res_type->Name) + for (int n = 0; n < p_bic_data->ResourceTypeCount; n++) + if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { + *out = n; + return true; + } + return false; +} + +bool +find_animation_type_by_name (struct string_slice const * name, bool lower_case, AnimationType * out) +{ + for (int n_anim = 0; n_anim < COUNT_ANIMATION_TYPES; n_anim++) + if (strlen (animation_names[n_anim]) == name->len) { + bool all_chars_match = true; + for (int k = 0; k < name->len; k++) { + int c = animation_names[n_anim][k]; + if (lower_case) + c = tolower (c); + if (c != name->str[k]) { + all_chars_match = false; + break; + } + } + if (all_chars_match) { + *out = n_anim; + return true; + } + } + return false; +} + +enum game_object_kind { + GOK_UNIT_TYPE = 0, + GOK_BUILDING, + GOK_RESOURCE, + GOK_TECHNOLOGY, + GOK_GOVERNMENT, + + COUNT_GAME_OBJECT_KINDS +}; + +bool +find_game_object_id_by_name (enum game_object_kind kind, struct string_slice const * name, int start_id, int * out) +{ + switch (kind) { + case GOK_UNIT_TYPE: { + UnitType * unit_type; + if (name->len <= sizeof unit_type->Name) + for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) + if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { + *out = n; + return true; + } + return false; + } + case GOK_BUILDING: { + Improvement * improv; + if (name->len <= sizeof improv->Name) + for (int n = start_id; n < p_bic_data->ImprovementsCount; n++) + if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { + *out = n; + return true; + } + return false; + } + case GOK_RESOURCE: { + Resource_Type * res_type; + if (name->len <= sizeof res_type->Name) + for (int n = start_id; n < p_bic_data->ResourceTypeCount; n++) + if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { + *out = n; + return true; + } + return false; + } + case GOK_TECHNOLOGY: { + Advance * adv; + if (name->len <= sizeof adv->Name) + for (int n = start_id; n < p_bic_data->AdvanceCount; n++) + if (slice_matches_str (name, p_bic_data->Advances[n].Name)) { + *out = n; + return true; + } + return false; + } + case GOK_GOVERNMENT: { + Government * govt; + if (name->len <= sizeof govt->Name) + for (int n = start_id; n < p_bic_data->GovernmentsCount; n++) + if (slice_matches_str (name, p_bic_data->Governments[n].Name.S)) { + *out = n; + return true; + } + return false; + } + default: + return false; + } +} + +// Converts a build name (like "Spearman" or "Granary") into a City_Order struct. Returns whether or not any improvement or unit type was found under +// the given name. +bool +find_city_order_by_name (struct string_slice const * name, City_Order * out) +{ + int id; + if (find_improv_id_by_name (name, &id)) { + out->OrderID = id; + out->OrderType = COT_Improvement; + return true; + } else if (find_unit_type_id_by_name (name, 0, &id)) { + out->OrderID = id; + out->OrderType = COT_Unit; + return true; + } else + return false; +} + +// Returns a list of AI strat duplicates of the unit type with the given id. This means a list of all other unit types that are identical to the given +// one except were separated out so each can have only one AI strategy. Returns the total number of duplicates, which may be greater than dup_ids_len. +int +list_unit_type_duplicates (int type_id, int * out_dup_ids, int dup_ids_len) +{ + // type_id may be a duplicate itself. Find the base type so we can start assembling the array from there. Otherwise we may miss some. + int alt_for_id = p_bic_data->UnitTypes[type_id].alternate_strategy_for_id; + int base_type_id = (alt_for_id >= 0) ? alt_for_id : type_id; + + int tr = 0, current = base_type_id; + while (1) { + if (current != type_id) { + if (tr < dup_ids_len) + out_dup_ids[tr] = current; + tr++; + } + int next; + if (itable_look_up (&is->unit_type_duplicates, current, &next)) + current = next; + else + break; + } + + return tr; +} + +// A "recognizable" is something that contains the name of a unit, building, etc. When parsing one, it's possible for it to be grammatically valid but +// contain a name that doesn't match anything in the scenario data. That's a special kind of error. In that case, we record the error to report in a +// popup and continue parsing. +enum recognizable_parse_result { + RPR_OK = 0, + RPR_UNRECOGNIZED, + RPR_PARSE_ERROR +}; + +struct perfume_spec { + char name[36]; // Must be large enough to fit the name of a unit type or improvement + i31b value; // Int component stores amount, bool stores whether it's a percentage or not +}; + +enum recognizable_parse_result +parse_perfume_spec (char ** p_cursor, enum perfume_kind kind, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + char * cur = *p_cursor; + struct string_slice name; + City_Order unused_city_order; + int unused_id; + i31b value; + if (parse_string (&cur, &name) && + skip_punctuation (&cur, ':') && + parse_i31b (&cur, &value)) { + *p_cursor = cur; + + if (((kind == PK_PRODUCTION) && find_city_order_by_name (&name, &unused_city_order)) || + ((kind == PK_TECHNOLOGY) && find_game_object_id_by_name (GOK_TECHNOLOGY, &name, 0, &unused_id)) || + ((kind == PK_GOVERNMENT) && find_game_object_id_by_name (GOK_GOVERNMENT, &name, 0, &unused_id))) { + struct perfume_spec * out = out_perfume_spec; + snprintf (out->name, sizeof out->name, "%.*s", name.len, name.str); + out->name[(sizeof out->name) - 1] = '\0'; + out->value = value; + return RPR_OK; + } else { + add_unrecognized_line (p_unrecognized_lines, &name); + return RPR_UNRECOGNIZED; + } + } else + return RPR_PARSE_ERROR; +} + +enum recognizable_parse_result +parse_production_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + return parse_perfume_spec (p_cursor, PK_PRODUCTION, p_unrecognized_lines, out_perfume_spec); +} + +enum recognizable_parse_result +parse_technology_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + return parse_perfume_spec (p_cursor, PK_TECHNOLOGY, p_unrecognized_lines, out_perfume_spec); +} + +enum recognizable_parse_result +parse_government_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + return parse_perfume_spec (p_cursor, PK_GOVERNMENT, p_unrecognized_lines, out_perfume_spec); +} + +enum recognizable_parse_result +parse_mill (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_mill) +{ + char * cur = *p_cursor; + struct string_slice improv_name; + if (parse_string (&cur, &improv_name) && + skip_punctuation (&cur, ':')) { + + short flags = 0; + struct string_slice resource_name; + while (1) { + if (! parse_string (&cur, &resource_name)) + return RPR_PARSE_ERROR; + else if (slice_matches_str (&resource_name, "local")) flags |= MF_LOCAL; + else if (slice_matches_str (&resource_name, "no-tech-req")) flags |= MF_NO_TECH_REQ; + else if (slice_matches_str (&resource_name, "yields")) flags |= MF_YIELDS; + else if (slice_matches_str (&resource_name, "show-bonus")) flags |= MF_SHOW_BONUS; + else if (slice_matches_str (&resource_name, "hide-non-bonus")) flags |= MF_HIDE_NON_BONUS; + else + break; + } + + *p_cursor = cur; + int improv_id, resource_id; + int any_unrecognized = 0; + if (! find_improv_id_by_name (&improv_name, &improv_id)) { + add_unrecognized_line (p_unrecognized_lines, &improv_name); + any_unrecognized = 1; + } + if (! find_resource_id_by_name (&resource_name, &resource_id)) { + add_unrecognized_line (p_unrecognized_lines, &resource_name); + any_unrecognized = 1; + } + if (any_unrecognized) + return RPR_UNRECOGNIZED; + else { + struct mill * out = out_mill; + out->improv_id = improv_id; + out->resource_id = resource_id; + out->flags = flags; + return RPR_OK; + } + } else + return RPR_PARSE_ERROR; +} + +enum recognizable_parse_result +parse_era_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_or_civ_alias_list, bool leader_else_civ_name) +{ + char * cur = *p_cursor; + struct string_slice key; + if (parse_string (&cur, &key) && + skip_punctuation (&cur, ':')) { + + char * aliases[ERA_ALIAS_LIST_CAPACITY] = {0}; + char * titles[ERA_ALIAS_LIST_CAPACITY] = {0}; + int alias_count = 0, + female_bits = 0, + gender_specified_bits = 0; // For each alias, set to 1 if a gender was specified + struct string_slice alias; + while (1) { + if (parse_string (&cur, &alias)) { + if (alias_count < ERA_ALIAS_LIST_CAPACITY) + aliases[alias_count] = extract_slice (&alias); + + // If we're parsing a list of leader names, read in the gender & title if present + if (leader_else_civ_name) { + char * inner_cur = cur; + struct string_slice gender; + struct string_slice title = {0}; + if ( skip_punctuation (&inner_cur, '(') + && parse_string (&inner_cur, &gender) + && ( skip_punctuation (&inner_cur, ')') + || ( skip_punctuation (&inner_cur, ',') + && parse_string (&inner_cur, &title) + && skip_punctuation (&inner_cur, ')'))) + && ( slice_matches_str (&gender, "M") + || slice_matches_str (&gender, "m") + || slice_matches_str (&gender, "F") + || slice_matches_str (&gender, "f"))) { + if (alias_count < 32) { + if (slice_matches_str (&gender, "F") || slice_matches_str (&gender, "f")) + female_bits |= 1 << alias_count; + gender_specified_bits |= 1 << alias_count; + } + if (title.len > 0) + titles[alias_count] = extract_slice (&title); + cur = inner_cur; + } + } + + alias_count++; + } else + break; + } + if (alias_count == 0) + return RPR_PARSE_ERROR; + + *p_cursor = cur; + + // Check that "key" matches a noun, adjective, or formal name of any civ ("race") in the scenario data. Store that civ. + Race * race_matching_key = NULL; { + for (int n = 0; n < p_bic_data->RacesCount; n++) { + Race * race = &p_bic_data->Races[n]; + if ( ( leader_else_civ_name + && slice_matches_str (&key, race->LeaderName)) + || ( (! leader_else_civ_name) + && ( slice_matches_str (&key, race->AdjectiveName) + || slice_matches_str (&key, race->CountryName) + || slice_matches_str (&key, race->SingularName)))) { + race_matching_key = race; + break; + } + } + } + if (race_matching_key == NULL) { + add_unrecognized_line (p_unrecognized_lines, &key); + return RPR_UNRECOGNIZED; + } + + if (leader_else_civ_name) { + struct leader_era_alias_list * out = out_leader_or_civ_alias_list; + memset (out, 0, sizeof *out); // Make sure unspecified aliases & titles are NULL + out->key = extract_slice (&key); + for (int n = 0; n < alias_count; n++) { + out->aliases[n] = aliases[n]; + out->titles[n] = titles[n]; + } + + // Set gender bits + int unreplaced_bits = (race_matching_key->LeaderGender == 0) ? 0 : ~0; + out->gender_bits = (unreplaced_bits & ~gender_specified_bits) | female_bits; + + + } else { + struct civ_era_alias_list * out = out_leader_or_civ_alias_list; + memset (out, 0, sizeof *out); + out->key = extract_slice (&key); + for (int n = 0; n < alias_count; n++) + out->aliases[n] = aliases[n]; + } + + return RPR_OK; + } else + return RPR_PARSE_ERROR; +} + + +enum recognizable_parse_result +parse_civ_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_civ_era_alias_list) +{ + return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_civ_era_alias_list, false); +} + +enum recognizable_parse_result +parse_leader_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_era_alias_list) +{ + return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_leader_era_alias_list, true); +} + +struct parsed_unit_type_limit { + char name[32]; // Same length as Name in Unit_Type + struct unit_type_limit limit; +}; + +enum recognizable_parse_result +parse_unit_type_limit (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_unit_type_limit) +{ + char * cur = *p_cursor; + struct parsed_unit_type_limit * out = out_parsed_unit_type_limit; + + struct string_slice name; + struct unit_type_limit limit = {0}; + if (skip_white_space (&cur) && + parse_string (&cur, &name) && + (name.len < (sizeof out->name)) && + skip_punctuation (&cur, ':')) { + + do { + int num; + if (! parse_int (&cur, &num)) + return RPR_PARSE_ERROR; + + struct string_slice ss; + if (parse_string (&cur, &ss)) { + if (slice_matches_str (&ss, "per-city")) + limit.per_city += num; + else if (slice_matches_str (&ss, "cities-per")) + limit.cities_per += num; + else + return RPR_PARSE_ERROR; + } else + limit.per_civ += num; + + } 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 { + add_unrecognized_line (p_unrecognized_lines, &name); + *p_cursor = cur; + return RPR_UNRECOGNIZED; + } + + } else + return RPR_PARSE_ERROR; +} + +enum recognizable_parse_result +parse_work_area_improvement (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_work_area_improvement) +{ + char * cur = *p_cursor; + struct work_area_improvement * out = out_parsed_work_area_improvement; + out->improv_id = -1; + out->work_area_radius_limit = 0; + out->work_area_radius_bonus = 0; + + struct string_slice improv_name; + if (skip_white_space (&cur) && + parse_string (&cur, &improv_name) && + skip_punctuation (&cur, ':')) { + + int num; + if (! parse_int (&cur, &num)) + return RPR_PARSE_ERROR; + + struct string_slice ss; + if (parse_string (&cur, &ss)) { + if (slice_matches_str (&ss, "extra")) + out->work_area_radius_bonus = num; + else + return RPR_PARSE_ERROR; + } else + out->work_area_radius_limit = num; + + int improv_id; + if (slice_matches_str (&improv_name, "default")) { + out->improv_id = -1; + *p_cursor = cur; + return RPR_OK; + } else if (find_improv_id_by_name (&improv_name, &improv_id)) { + out->improv_id = improv_id; + *p_cursor = cur; + return RPR_OK; + } else { + add_unrecognized_line (p_unrecognized_lines, &improv_name); + *p_cursor = cur; + return RPR_UNRECOGNIZED; + } + + } else + return RPR_PARSE_ERROR; +} + +// Recognizable items are appended to out_list/count, which must have been previously initialized (NULL/0 is valid for an empty list). +// If an error occurs while reading, returns the location of the error inside the slice, specifically the number of characters before the unreadable +// item. If no error occurs, returns -1. +int +read_recognizables (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + int item_size, + enum recognizable_parse_result (* parse_item) (char **, struct error_line **, void *), + void ** inout_list, + int * inout_count) +{ + if (s->len <= 0) + return -1; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + + bool success = false; + void * new_items = NULL; + int count_new_items = 0; + int new_items_capacity = 0; + void * temp_item = malloc (item_size); + + while (1) { + enum recognizable_parse_result result = parse_item (&cursor, p_unrecognized_lines, temp_item); + if (result != RPR_PARSE_ERROR) { + if (result == RPR_OK) { + reserve (item_size, &new_items, &new_items_capacity, count_new_items); + memcpy ((byte *)new_items + count_new_items * item_size, temp_item, item_size); + count_new_items++; + } + + if (skip_punctuation (&cursor, ',') && skip_white_space (&cursor)) + continue; + else if (skip_horiz_space (&cursor) && (*cursor == '\0')) { + success = true; + break; + } else + break; + } else + break; + } + + if (success && (count_new_items > 0)) { + *inout_list = realloc (*inout_list, (*inout_count + count_new_items) * item_size); + memcpy ((byte *)*inout_list + *inout_count * item_size, new_items, count_new_items * item_size); + *inout_count += count_new_items; + } + free (temp_item); + free (new_items); + free (extracted_slice); + return success ? -1 : cursor - extracted_slice; +} + +// Reads a "sidtable" from text. A sidtable maps strings to IDs of scenario objects. The string keys are also expected to be a type of scenario +// object. This method reads text such as: +// Factory: Battleship, Stable: Horseman Knight Cavalry, "Siege Workshop": Catapult Trebuchet +// and converts it to a table mapping "Factory", "Stable", and "Siege Workshop" to the corresponding unit type IDs. All new entries are appended to +// the given table; existing entries are not removed. +// Like read_recognizables, this method returns -1 for success or the location of an error if there is one. +int +read_sidtable (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + enum game_object_kind key_kind, + enum game_object_kind list_elem_kind, + struct table * sidtable) +{ + if (s->len <= 0) + return -1; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + while (1) { + struct string_slice key; + if (skip_white_space (&cursor) && parse_string (&cursor, &key)) { + int unused; + bool recognized_key = find_game_object_id_by_name (key_kind, &key, 0, &unused); + if (! recognized_key) + add_unrecognized_line (p_unrecognized_lines, &key); + if (! skip_punctuation (&cursor, ':')) + break; + struct string_slice elem_name; + while (skip_white_space (&cursor) && parse_string (&cursor, &elem_name)) { + bool recognized_elem = false; + int elem_id = -1; + while (find_game_object_id_by_name (list_elem_kind, &elem_name, elem_id + 1, &elem_id)) { + recognized_elem = true; + if (recognized_key) + sidtable_append (sidtable, &key, elem_id); + } + if (! recognized_elem) + add_unrecognized_line (p_unrecognized_lines, &elem_name); + } + skip_punctuation (&cursor, ','); + } else { + success = (*cursor == '\0'); + break; + } + } + + free (extracted_slice); + return success ? -1 : cursor - extracted_slice; +} + +// Like read_recognizables, returns -1 for success or the location of an error if there is one +int +read_building_unit_prereqs (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + struct table * building_unit_prereqs) +{ + if (s->len <= 0) + return -1; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + struct prereq { + int building_id; + struct string_slice unit_type_name; + } * new_prereqs = NULL; + int new_prereqs_capacity = 0; + int count_new_prereqs = 0; + + while (1) { + struct string_slice building_name; + if (skip_white_space (&cursor) && parse_string (&cursor, &building_name)) { + int building_id; + bool have_building_id = find_improv_id_by_name (&building_name, &building_id); + if (! have_building_id) + add_unrecognized_line (p_unrecognized_lines, &building_name); + if (! skip_punctuation (&cursor, ':')) + break; + struct string_slice unit_type_name; + while (skip_white_space (&cursor) && parse_string (&cursor, &unit_type_name)) { + int unused; + if (find_unit_type_id_by_name (&unit_type_name, 0, &unused)) { // if there is any by this name, later we'll deal with the possibility of multiple + if (have_building_id) { + reserve (sizeof new_prereqs[0], (void **)&new_prereqs, &new_prereqs_capacity, count_new_prereqs); + new_prereqs[count_new_prereqs++] = (struct prereq) { .building_id = building_id, .unit_type_name = unit_type_name }; + } + } else + add_unrecognized_line (p_unrecognized_lines, &unit_type_name); + } + skip_punctuation (&cursor, ','); + } else { + success = (*cursor == '\0'); + break; + } + } + + // If parsing succeeded, add the new prereq rules to the table + if (success) + for (int n = 0; n < count_new_prereqs; n++) { + struct prereq * prereq = &new_prereqs[n]; + + int unit_type_id = -1; + while (find_unit_type_id_by_name (&prereq->unit_type_name, unit_type_id + 1, &unit_type_id)) { + + // If this unit type ID is not already in the table, insert it paired with the encoded building ID + int prev_val; + if (! itable_look_up (building_unit_prereqs, unit_type_id, &prev_val)) + itable_insert (building_unit_prereqs, unit_type_id, (prereq->building_id << 1) | 1); + + // If the unit type ID is already associated with a building ID, create a list for both the old and new building IDs + else if (prev_val & 1) { + int * list = malloc (MAX_BUILDING_PREREQS_FOR_UNIT * sizeof *list); + for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) + list[n] = -1; + list[0] = prev_val >> 1; // Decode + list[1] = prereq->building_id; + itable_insert (building_unit_prereqs, unit_type_id, (int)list); + + // Otherwise, it's already associated with a list. Search the list for a free spot and fill it with the new building ID + } else { + int * list = (int *)prev_val; + for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) + if (list[n] < 0) { + list[n] = prereq->building_id; + break; + } + } + } + } + + + free (new_prereqs); + free (extracted_slice); + return success ? -1 : cursor - extracted_slice; +} + +// Reads a space-separated list of unit types like: +// Worker Galley "Gallic Swordsman" +// Looks up the type ID(s) for each name and inserts them into the unit_types table associated with a value of 1. +bool +read_unit_type_list (struct string_slice const * s, struct error_line ** p_unrecognized_lines, struct table * unit_types) +{ + if (s->len <= 0) + return true; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + while (1) { + struct string_slice name; + if (parse_string (&cursor, &name)) { + + int id = -1; + bool matched_any = false; + while (find_unit_type_id_by_name (&name, id + 1, &id)) { + itable_insert (unit_types, id, 1); + matched_any = true; + } + + if (! matched_any) + add_unrecognized_line (p_unrecognized_lines, &name); + + } else { + skip_white_space (&cursor); + success = *cursor == '\0'; + break; + } + } + + free (extracted_slice); + return success; +} + +bool +read_ai_multi_start_extra_palaces (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + int ** p_ai_multi_start_extra_palaces, + int * p_count_ai_multi_start_extra_palaces, + int * p_ai_multi_start_extra_palaces_capacity) +{ + if (s->len <= 0) + return true; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + while (1) { + struct string_slice name; + if (parse_string (&cursor, &name)) { + int id; + if (find_improv_id_by_name (&name, &id)) { + int count = *p_count_ai_multi_start_extra_palaces; + reserve (sizeof **p_ai_multi_start_extra_palaces, (void **)p_ai_multi_start_extra_palaces, p_ai_multi_start_extra_palaces_capacity, count); + (*p_ai_multi_start_extra_palaces)[count] = id; + *p_count_ai_multi_start_extra_palaces = count + 1; + } else + add_unrecognized_line (p_unrecognized_lines, &name); + + } else { + skip_white_space (&cursor); + success = *cursor == '\0'; + break; + } + } + + free (extracted_slice); + return success; +} + +bool +read_retreat_rules (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "standard" )) { *out_val = RR_STANDARD; return true; } + else if (slice_matches_str (&trimmed, "none" )) { *out_val = RR_NONE; return true; } + else if (slice_matches_str (&trimmed, "all-units" )) { *out_val = RR_ALL_UNITS; return true; } + else if (slice_matches_str (&trimmed, "if-faster" )) { *out_val = RR_IF_FASTER; return true; } + else if (slice_matches_str (&trimmed, "if-not-slower" )) { *out_val = RR_IF_NOT_SLOWER; return true; } + else if (slice_matches_str (&trimmed, "if-fast-and-not-slower")) { *out_val = RR_IF_FAST_AND_NOT_SLOWER; return true; } + else + return false; +} + +bool +read_line_drawing_override (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "never" )) { *out_val = LDO_NEVER; return true; } + else if (slice_matches_str (&trimmed, "wine" )) { *out_val = LDO_WINE; return true; } + else if (slice_matches_str (&trimmed, "always")) { *out_val = LDO_ALWAYS; return true; } + else + return false; +} + +bool +read_minimap_doubling_mode (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "never" )) { *out_val = MDM_NEVER; return true; } + else if (slice_matches_str (&trimmed, "high-def")) { *out_val = MDM_HIGH_DEF; return true; } + else if (slice_matches_str (&trimmed, "always" )) { *out_val = MDM_ALWAYS; return true; } + else + return false; +} + +bool +read_unit_cycle_search_criteria (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "standard" )) { *out_val = UCSC_STANDARD; return true; } + else if (slice_matches_str (&trimmed, "similar-near-start" )) { *out_val = UCSC_SIMILAR_NEAR_START; return true; } + else if (slice_matches_str (&trimmed, "similar-near-destination")) { *out_val = UCSC_SIMILAR_NEAR_DESTINATION; return true; } + else + return false; +} + +bool +read_no_ai_patrol_override (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "zero")) { *out_val = NAPO_ZERO; return true; } + else if (slice_matches_str (&trimmed, "one" )) { *out_val = NAPO_ONE; return true; } + else if (slice_matches_str (&trimmed, "none")) { *out_val = NAPO_NONE; return true; } + else + return false; +} + +bool +read_work_area_limit (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "none" )) { *out_val = WAL_NONE; return true; } + else if (slice_matches_str (&trimmed, "cultural" )) { *out_val = WAL_CULTURAL; return true; } + else if (slice_matches_str (&trimmed, "cultural-min-2" )) { *out_val = WAL_CULTURAL_MIN_2; return true; } + else if (slice_matches_str (&trimmed, "cultural-or-adjacent")) { *out_val = WAL_CULTURAL_OR_ADJACENT; return true; } + else + return false; +} + +bool +read_day_night_cycle_mode (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "off" )) { *out_val = DNCM_OFF; return true; } + else if (slice_matches_str (&trimmed, "timer" )) { *out_val = DNCM_TIMER; return true; } + else if (slice_matches_str (&trimmed, "user-time" )) { *out_val = DNCM_USER_TIME; return true; } + else if (slice_matches_str (&trimmed, "every-turn")) { *out_val = DNCM_EVERY_TURN; return true; } + else if (slice_matches_str (&trimmed, "specified" )) { *out_val = DNCM_SPECIFIED; return true; } + else + return false; +} + +bool +read_distribution_hub_yield_division_mode (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "flat" )) { *out_val = DHYDM_FLAT; return true; } + else if (slice_matches_str (&trimmed, "scale-by-city-count" )) { *out_val = DHYDM_SCALE_BY_CITY_COUNT; return true; } + else + return false; +} + +bool +read_ai_distribution_hub_build_strategy (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "auto" )) { *out_val = ADHBS_AUTO; return true; } + else if (slice_matches_str (&trimmed, "by-city-count" )) { *out_val = ADHBS_BY_CITY_COUNT; return true; } + else + return false; +} + +bool +read_ai_auto_build_great_wall_strategy (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "all-borders" )) { *out_val = AAGWS_ALL_BORDERS; return true; } + else if (slice_matches_str (&trimmed, "other-civ-bordered-only")) { *out_val = AAGWS_OTHER_CIV_BORDERED_ONLY; return true; } + else + return false; +} + +bool +read_tile_terrain_type_value (struct string_slice const * s, enum SquareTypes * out_type) +{ + if (s == NULL || out_type == NULL) + return false; + + struct string_slice trimmed = trim_string_slice (s, 1); + if (trimmed.len <= 0) + return false; + + struct { + char const * name; + int value; + } const entries[] = { + {"desert", SQ_Desert}, + {"deserts", SQ_Desert}, + {"plain", SQ_Plains}, + {"plains", SQ_Plains}, + {"grassland", SQ_Grassland}, + {"grasslands", SQ_Grassland}, + {"tundra", SQ_Tundra}, + {"tundras", SQ_Tundra}, + {"floodplain", SQ_FloodPlain}, + {"floodplains", SQ_FloodPlain}, + {"hill", SQ_Hills}, + {"hills", SQ_Hills}, + {"mountain", SQ_Mountains}, + {"mountains", SQ_Mountains}, + {"forest", SQ_Forest}, + {"forests", SQ_Forest}, + {"jungle", SQ_Jungle}, + {"jungles", SQ_Jungle}, + {"marsh", SQ_Swamp}, + {"marshes", SQ_Swamp}, + {"swamp", SQ_Swamp}, + {"swamps", SQ_Swamp}, + {"volcano", SQ_Volcano}, + {"volcanos", SQ_Volcano}, + {"coast", SQ_Coast}, + {"coasts", SQ_Coast}, + {"sea", SQ_Sea}, + {"seas", SQ_Sea}, + {"ocean", SQ_Ocean}, + {"oceans", SQ_Ocean}, + {"river", SQ_RIVER}, + {"rivers", SQ_RIVER}, + {"snow-volcano", SQ_SNOW_VOLCANO}, + {"snow-volcanos", SQ_SNOW_VOLCANO}, + {"snow-forest", SQ_SNOW_FOREST}, + {"snow-forests", SQ_SNOW_FOREST}, + {"snow-mountain", SQ_SNOW_MOUNTAIN}, + {"snow-mountains", SQ_SNOW_MOUNTAIN}, + {"any", SQ_INVALID} + }; + + for (int i = 0; i < (int)ARRAY_LEN (entries); i++) { + if (slice_matches_str (&trimmed, entries[i].name)) { + *out_type = (enum SquareTypes)entries[i].value; + return true; + } + } + + return false; +} + +unsigned int +square_type_mask_bit (enum SquareTypes type) +{ + if ((int)type < 0 || type > SQ_SNOW_MOUNTAIN) + return 0; + return (unsigned int)(1u << type); +} + +unsigned int +district_buildable_mine_mask_bit (void) +{ + return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 1)); +} + +unsigned int +district_buildable_irrigation_mask_bit (void) +{ + return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 2)); +} + +unsigned int +district_buildable_lake_mask_bit (void) +{ + return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 3)); +} + +unsigned int +all_square_types_mask (void) +{ + return (unsigned int)((1u << (SQ_SNOW_MOUNTAIN + 1)) - 1); +} + +unsigned int +district_default_buildable_mask (void) +{ + return (unsigned int)DEFAULT_DISTRICT_BUILDABLE_MASK; +} + +bool +tile_has_snow_mountain (Tile * tile) +{ + return (tile != NULL) && (tile != p_null_tile) && tile->vtable->m29_Check_Mountain_Snowcap (tile); +} + +bool +tile_is_lake (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (! tile->vtable->m35_Check_Is_Water (tile)) + return false; + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + return false; + + int lake_size_threshold = 21; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + return continent->Body.TileCount <= lake_size_threshold; +} + +bool +tile_has_snow_volcano (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Volcano) + return false; + + int overlays = tile->vtable->m43_Get_field_30 (tile); + return (overlays & 0x100000) != 0; +} + +bool +tile_has_snow_forest (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Forest) + return false; + + int overlays = tile->vtable->m43_Get_field_30 (tile); + return (overlays & 0x100000) != 0; +} + +bool +tile_matches_square_type (Tile * tile, enum SquareTypes type) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + switch (type) { + case SQ_SNOW_MOUNTAIN: + return tile_has_snow_mountain (tile); + case SQ_SNOW_VOLCANO: + return tile_has_snow_volcano (tile); + case SQ_SNOW_FOREST: + return tile_has_snow_forest (tile); + case SQ_RIVER: + return tile->vtable->m37_Get_River_Code (tile) != 0; + default: + return tile->vtable->m50_Get_Square_BaseType (tile) == type; + } +} + +bool +tile_matches_square_type_mask (Tile * tile, unsigned int mask) +{ + if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) + return false; + + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + unsigned int base_bit = square_type_mask_bit (base_type); + if ((base_bit != 0) && ((mask & base_bit) != 0)) + return true; + + enum SquareTypes const special_types[] = {SQ_RIVER, SQ_SNOW_MOUNTAIN, SQ_SNOW_VOLCANO, SQ_SNOW_FOREST}; + for (int i = 0; i < (int)ARRAY_LEN (special_types); i++) { + enum SquareTypes stype = special_types[i]; + unsigned int bit = square_type_mask_bit (stype); + if ((mask & bit) && tile_matches_square_type (tile, stype)) + return true; + } + + unsigned int mine_bit = district_buildable_mine_mask_bit (); + if ((mask & mine_bit) && tile->vtable->m18_Check_Mines (tile, __, 0)) + return true; + + unsigned int irrigation_bit = district_buildable_irrigation_mask_bit (); + if ((mask & irrigation_bit) && tile->vtable->m17_Check_Irrigation (tile, __, 0)) + return true; + + unsigned int lake_bit = district_buildable_lake_mask_bit (); + if ((mask & lake_bit) && tile_is_lake (tile)) + return true; + + return false; +} + +bool +tile_matches_overlay_mask (Tile * tile, unsigned int mask) +{ + if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) + return false; + + unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); + if ((mask & DOM_MINE) && ((overlays & TILE_FLAG_MINE) != 0)) + return true; + if ((mask & DOM_IRRIGATION) && ((overlays & 0x00000008) != 0)) + return true; + if ((mask & DOM_FORTRESS) && ((overlays & 0x00000010) != 0)) + return true; + if ((mask & DOM_BARRICADE) && ((overlays & 0x10000000) != 0)) + return true; + if ((mask & DOM_OUTPOST) && ((overlays & 0x80000000) != 0)) + return true; + if ((mask & DOM_RADAR_TOWER) && ((overlays & 0x40000000) != 0)) + return true; + if ((mask & DOM_AIRFIELD) && ((overlays & 0x20000000) != 0)) + return true; + if ((mask & DOM_JUNGLE) && tile_matches_square_type (tile, SQ_Jungle)) + return true; + if ((mask & DOM_FOREST) && tile_matches_square_type (tile, SQ_Forest)) + return true; + if ((mask & DOM_SWAMP) && tile_matches_square_type (tile, SQ_Swamp)) + return true; + if ((mask & DOM_RIVER) && tile_matches_square_type (tile, SQ_RIVER)) + return true; + + return false; +} + +bool +read_natural_wonder_terrain_type (struct string_slice const * s, enum SquareTypes * out_type) +{ + enum SquareTypes parsed; + if (! read_tile_terrain_type_value (s, &parsed)) + return false; + + switch (parsed) { + case SQ_Desert: + case SQ_Plains: + case SQ_Grassland: + case SQ_Jungle: + case SQ_Tundra: + case SQ_FloodPlain: + case SQ_Swamp: + case SQ_Hills: + case SQ_Mountains: + case SQ_Forest: + case SQ_Volcano: + case SQ_SNOW_MOUNTAIN: + case SQ_SNOW_FOREST: + case SQ_SNOW_VOLCANO: + case SQ_Coast: + case SQ_Sea: + case SQ_Ocean: + *out_type = parsed; + return true; + + default: + return false; + } +} + +bool +read_direction_value (struct string_slice const * s, enum direction * out_dir) +{ + if (s == NULL || out_dir == NULL) + return false; + + struct string_slice trimmed = trim_string_slice (s, 1); + if (trimmed.len <= 0) + return false; + + if (slice_matches_str (&trimmed, "northeast")) { *out_dir = DIR_NE; return true; } + else if (slice_matches_str (&trimmed, "east" )) { *out_dir = DIR_E; return true; } + else if (slice_matches_str (&trimmed, "southeast")) { *out_dir = DIR_SE; return true; } + else if (slice_matches_str (&trimmed, "south" )) { *out_dir = DIR_S; return true; } + else if (slice_matches_str (&trimmed, "southwest")) { *out_dir = DIR_SW; return true; } + else if (slice_matches_str (&trimmed, "west" )) { *out_dir = DIR_W; return true; } + else if (slice_matches_str (&trimmed, "northwest")) { *out_dir = DIR_NW; return true; } + else if (slice_matches_str (&trimmed, "north" )) { *out_dir = DIR_N; return true; } + else + return false; +} + +bool +read_barbarian_activity_override (struct string_slice const * s, enum barbarian_activity_override * out) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (trimmed.len <= 0) + return false; + + bool found = false; + char * extracted = extract_slice (s); + + struct { + char * str; + enum barbarian_activity_override value; + } possibilities[] = {{ .str = "none" , .value = BAO_NONE }, + { .str = (*p_labels)[LBL_NO_BARBARIANS ], .value = BAO_NO_BARBARIANS }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 1], .value = BAO_SEDENTARY }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 2], .value = BAO_ROAMING }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 3], .value = BAO_RESTLESS }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 4], .value = BAO_RAGING }, + { .str = (*p_labels)[LBL_RANDOM_BARBS] , .value = BAO_RANDOM }, + { .str = "No Barbarians" , .value = BAO_NO_BARBARIANS }, + { .str = "Sedentary" , .value = BAO_SEDENTARY }, + { .str = "Roaming" , .value = BAO_ROAMING }, + { .str = "Restless" , .value = BAO_RESTLESS }, + { .str = "Raging" , .value = BAO_RAGING }, + { .str = "Random" , .value = BAO_RANDOM }}; + + // Check for exact match + for (int n = 0; n < ARRAY_LEN (possibilities); n++) + if (0 == strcmp (extracted, possibilities[n].str)) { + *out = possibilities[n].value; + found = true; + break; + } + + // If not found, check again ignoring case + if (! found) + for (int n = 0; n < ARRAY_LEN (possibilities); n++) + if (0 == _stricmp (extracted, possibilities[n].str)) { + *out = possibilities[n].value; + found = true; + break; + } + + free (extracted); + return found; +} + +struct parsable_field_bit { + char * name; + int bit_value; +}; + +bool +read_bit_field (struct string_slice const * s, struct parsable_field_bit const * bits, int count_bits, int * out_field) +{ + struct string_slice trimmed = trim_string_slice (s, 0); + s = &trimmed; + + int tr; + if (s->len <= 0) + tr = 0; + else if (slice_matches_str (s, "all")) + tr = ~0; + else { + tr = 0; + char * cursor = &s->str[0]; + char * s_end = &s->str[s->len]; + while (1) { + struct string_slice name; + + if (cursor >= s_end) + break; + else if (! parse_string (&cursor, &name)) { + skip_white_space (&cursor); + if (cursor >= s_end) + break; + else + return false; // Invalid character in value + } + + bool matched_any = false; + for (int n = 0; n < count_bits; n++) + if (slice_matches_str (&name, bits[n].name)) { + tr |= bits[n].bit_value; + matched_any = true; + break; + } + if (! matched_any) + return false; + } + } + *out_field = tr; + return true; +} + +int +read_units_per_tile_limit (struct string_slice const * s, int * out_limits) +{ + int single_val; + if (read_int (s, &single_val)) { + out_limits[0] = out_limits[1] = out_limits[2] = single_val; + return true; + + } else { + bool success = false; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + int vals[3]; + if (parse_int (&cursor, &vals[0]) && parse_int (&cursor, &vals[1]) && parse_int (&cursor, &vals[2]) && + skip_horiz_space (&cursor) && (*cursor == '\0')) { + for (int n = 0; n < ARRAY_LEN (vals); n++) + out_limits[n] = vals[n]; + success = true; + } + free (extracted_slice); + return success; + } +} + +struct config_parsing { + char * file_path; + char * text; + char * cursor; + struct string_slice key; + int displayed_error_message; +}; + +enum config_parse_error { + CPE_GENERIC, + CPE_BAD_VALUE, + CPE_BAD_BOOL_VALUE, + CPE_BAD_INT_VALUE, + CPE_BAD_STACK_LIMIT_VALUE, + CPE_BAD_KEY +}; + +void +handle_config_error_at (struct config_parsing * p, char * error_loc, enum config_parse_error err) +{ + char err_msg[1000]; + if (! p->displayed_error_message) { + int line_no = 1; + for (char * c = p->text; c < error_loc; c++) + line_no += *c == '\n'; + + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); + snprintf (err_msg, sizeof err_msg, "Error reading \"%s\" on line %d.", p->file_path, line_no); + err_msg[(sizeof err_msg) - 1] = '\0'; + PopupForm_add_text (popup, __, err_msg, false); + + if (err == CPE_GENERIC) { + if (p->key.str != NULL) + snprintf (err_msg, sizeof err_msg, "^The last key successfully read was \"%.*s\".", p->key.len, p->key.str); + else + snprintf (err_msg, sizeof err_msg, "^Error occurred before any keys could be read."); + } else if (err == CPE_BAD_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid.", p->key.len, p->key.str); + else if (err == CPE_BAD_BOOL_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"true\" or \"false\".", p->key.len, p->key.str); + else if (err == CPE_BAD_INT_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected an integer.", p->key.len, p->key.str); + else if (err == CPE_BAD_STACK_LIMIT_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"false\", an integer, or a list of exactly three of those.", p->key.len, p->key.str); + else if (err == CPE_BAD_KEY) + snprintf (err_msg, sizeof err_msg, "^The key name \"%.*s\" is not recognized.", p->key.len, p->key.str); + err_msg[(sizeof err_msg) - 1] = '\0'; + PopupForm_add_text (popup, __, err_msg, false); + + patch_show_popup (popup, __, 0, 0); + p->displayed_error_message = 1; + } +} + +void +handle_config_error (struct config_parsing * p, enum config_parse_error err) +{ + handle_config_error_at (p, p->cursor, err); +} + +// Loads a config from the given file, layering it on top of is->current_config and appending its name to the list of loaded configs. Does NOT +// re-apply machine code edits. +void +load_config (char const * file_path, int path_is_relative_to_mod_dir) +{ + char err_msg[1000]; + struct c3x_config * cfg = &is->current_config; + + int full_path_size = 2 * MAX_PATH; + char * full_path = malloc (full_path_size); + if (path_is_relative_to_mod_dir) + snprintf (full_path, full_path_size, "%s\\%s", is->mod_rel_dir, file_path); + else + strncpy (full_path, file_path, full_path_size); + full_path[full_path_size - 1] = '\0'; + + char * text; { + char * utf8_text = file_to_string (full_path); + if (utf8_text == NULL) { + free (full_path); + return; + } + text = convert_from_utf8 (utf8_text, *p_code_page); + free (utf8_text); + if (text == NULL) { + snprintf (err_msg, sizeof err_msg, "Failed to re-encode contents of \"%s\". This file must contain UTF-8 text and only characters usable by Civ 3.", full_path); + err_msg[(sizeof err_msg) - 1] = '\0'; + pop_up_in_game_error (err_msg); + free (full_path); + return; + } + } + + struct perfume_spec_list { + struct perfume_spec * items; + int count; + } perfume_spec_lists[COUNT_PERFUME_KINDS] = {0}; + + struct parsed_unit_type_limit * parsed_unit_type_limits = NULL; + int parsed_unit_type_limit_count = 0; + + struct config_parsing p = { .file_path = full_path, .text = text, .cursor = text, .key = {0}, .displayed_error_message = 0 }; + struct error_line * unrecognized_lines = NULL; + while (1) { + skip_horiz_space (&p.cursor); + if (*p.cursor == '\0') + break; + else if (*p.cursor == '\n') + p.cursor++; // Continue to next line + else if (*p.cursor == ';') + skip_to_line_end (&p.cursor); // Skip comment line + else if (*p.cursor == '[') + skip_to_line_end (&p.cursor); // Skip section line + else if (parse_string (&p.cursor, &p.key) && skip_punctuation (&p.cursor, '=')) { // Parse key and equals sign + + struct string_slice value; + if (parse_string (&p.cursor, &value) || parse_bracketed_block (&p.cursor, &value)) { // Parse value + int ival, offset, recog_err_offset; + + // if key is for a boolean option + if (stable_look_up_slice (&is->boolean_config_offsets, &p.key, &offset)) { + if (read_int (&value, &ival)) + *((char *)cfg + offset) = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + + // if key is for an integer option + } else if (stable_look_up_slice (&is->integer_config_offsets, &p.key, &offset)) { + if (read_int (&value, &ival)) + *(int *)((byte *)cfg + offset) = ival; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + + // Handle city_work_radius separately from the other int options so we can clamp it and update the count var + } else if (slice_matches_str (&p.key, "city_work_radius")) { + if (read_int (&value, &ival)) { + cfg->city_work_radius = clamp (1, 7, ival); + is->workable_tile_count = workable_tile_counts[cfg->city_work_radius]; + } else + handle_config_error (&p, CPE_BAD_INT_VALUE); + + // if key is for something special + } else if (slice_matches_str (&p.key, "limit_units_per_tile")) { + if (! read_units_per_tile_limit (&value, &cfg->limit_units_per_tile[0])) + handle_config_error (&p, CPE_BAD_STACK_LIMIT_VALUE); + } else if (slice_matches_str (&p.key, "production_perfume") || slice_matches_str (&p.key, "perfume_specs")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct perfume_spec), + parse_production_perfume_spec, + (void **)&perfume_spec_lists[PK_PRODUCTION].items, + &perfume_spec_lists[PK_PRODUCTION].count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "technology_perfume")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct perfume_spec), + parse_technology_perfume_spec, + (void **)&perfume_spec_lists[PK_TECHNOLOGY].items, + &perfume_spec_lists[PK_TECHNOLOGY].count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "government_perfume")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct perfume_spec), + parse_government_perfume_spec, + (void **)&perfume_spec_lists[PK_GOVERNMENT].items, + &perfume_spec_lists[PK_GOVERNMENT].count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "building_prereqs_for_units")) { + if (0 <= (recog_err_offset = read_building_unit_prereqs (&value, &unrecognized_lines, &cfg->building_unit_prereqs))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "buildings_generating_resources")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct mill), + parse_mill, + (void **)&cfg->mills, + &cfg->count_mills))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_multi_start_extra_palaces")) { + if (! read_ai_multi_start_extra_palaces (&value, + &unrecognized_lines, + &cfg->ai_multi_start_extra_palaces, + &cfg->count_ai_multi_start_extra_palaces, + &cfg->ai_multi_start_extra_palaces_capacity)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_settler_perfume_on_founding")) { + if (! read_i31b (&value, &cfg->ai_settler_perfume_on_founding)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "land_retreat_rules")) { + if (! read_retreat_rules (&value, (int *)&cfg->land_retreat_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "sea_retreat_rules")) { + if (! read_retreat_rules (&value, (int *)&cfg->sea_retreat_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "draw_lines_using_gdi_plus")) { + if (! read_line_drawing_override (&value, (int *)&cfg->draw_lines_using_gdi_plus)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "double_minimap_size")) { + if (! read_minimap_doubling_mode (&value, (int *)&cfg->double_minimap_size)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "unit_cycle_search_criteria")) { + if (! read_unit_cycle_search_criteria (&value, (int *)&cfg->unit_cycle_search_criteria)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "override_no_ai_patrol")) { + if (! read_no_ai_patrol_override (&value, (int *)&cfg->override_no_ai_patrol)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "override_barbarian_activity_level_for_scenario_maps")) { + if (! read_barbarian_activity_override (&value, &cfg->override_barbarian_activity_level_for_scenario_maps)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "special_defensive_bombard_rules")) { + struct parsable_field_bit bits[] = { + {"lethal" , SDBR_LETHAL}, + {"not-invisible" , SDBR_NOT_INVISIBLE}, + {"aerial" , SDBR_AERIAL}, + {"blitz" , SDBR_BLITZ}, + {"docked-vs-land", SDBR_DOCKED_VS_LAND}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_defensive_bombard_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "special_zone_of_control_rules")) { + struct parsable_field_bit bits[] = { + {"lethal" , SZOCR_LETHAL}, + {"aerial" , SZOCR_AERIAL}, + {"amphibious" , SZOCR_AMPHIBIOUS}, + {"not-from-inside", SZOCR_NOT_FROM_INSIDE}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_zone_of_control_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "land_transport_rules")) { + struct parsable_field_bit bits[] = { + {"load-onto-boat" , LTR_LOAD_ONTO_BOAT}, + {"join-army" , LTR_JOIN_ARMY}, + {"no-defense-from-inside", LTR_NO_DEFENSE_FROM_INSIDE}, + {"no-escape" , LTR_NO_ESCAPE}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->land_transport_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "special_helicopter_rules")) { + struct parsable_field_bit bits[] = { + {"allow-on-carriers" , SHR_ALLOW_ON_CARRIERS}, + {"passenger-airdrop" , SHR_PASSENGER_AIRDROP}, + {"no-defense-from-inside", SHR_NO_DEFENSE_FROM_INSIDE}, + {"no-escape" , SHR_NO_ESCAPE}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_helicopter_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "work_area_limit")) { + if (! read_work_area_limit (&value, (int *)&cfg->work_area_limit)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "work_area_improvements")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct work_area_improvement), + parse_work_area_improvement, + (void **)&cfg->work_area_improvements, + &cfg->count_work_area_improvements))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "day_night_cycle_mode")) { + if (! read_day_night_cycle_mode (&value, (int *)&cfg->day_night_cycle_mode)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "distribution_hub_yield_division_mode")) { + if (! read_distribution_hub_yield_division_mode (&value, (int *)&cfg->distribution_hub_yield_division_mode)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_distribution_hub_build_strategy")) { + if (! read_ai_distribution_hub_build_strategy (&value, (int *)&cfg->ai_distribution_hub_build_strategy)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_auto_build_great_wall_strategy")) { + if (! read_ai_auto_build_great_wall_strategy (&value, (int *)&cfg->ai_auto_build_great_wall_strategy)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "great_wall_auto_build_wonder_name")) { + if (cfg->great_wall_auto_build_wonder_name != NULL) { + free (cfg->great_wall_auto_build_wonder_name); + cfg->great_wall_auto_build_wonder_name = NULL; + } + cfg->great_wall_auto_build_wonder_name = copy_trimmed_string_or_null (&value, 1); + cfg->great_wall_auto_build_wonder_improv_id = -1; + } else if (slice_matches_str (&p.key, "exclude_types_from_units_per_tile_limit")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->exclude_types_from_units_per_tile_limit)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "limit_defensive_retreat_on_water_to_types")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->limit_defensive_retreat_on_water_to_types)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ptw_like_artillery_targeting")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->ptw_arty_types)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "can_bombard_only_sea_tiles")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->can_bombard_only_sea_tiles)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "civ_aliases_by_era")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct civ_era_alias_list), + parse_civ_name_alias_list, + (void **)&cfg->civ_era_alias_lists, + &cfg->count_civ_era_alias_lists))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "leader_aliases_by_era")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct leader_era_alias_list), + parse_leader_name_alias_list, + (void **)&cfg->leader_era_alias_lists, + &cfg->count_leader_era_alias_lists))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "unit_limits")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct parsed_unit_type_limit), + parse_unit_type_limit, + (void **)&parsed_unit_type_limits, + &parsed_unit_type_limit_count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "aircraft_victory_animation")) { + struct string_slice trimmed = trim_string_slice (&value, 1); + bool value_ok = false; + if (slice_matches_str (&trimmed, "none")) { + if (cfg->aircraft_victory_animation != NULL) { + free (cfg->aircraft_victory_animation); + cfg->aircraft_victory_animation = NULL; + } + value_ok = true; + } else if (trimmed.len > 0) { + AnimationType unused; + if (find_animation_type_by_name (&trimmed, true, &unused)) { + if (cfg->aircraft_victory_animation != NULL) + free (cfg->aircraft_victory_animation); + cfg->aircraft_victory_animation = extract_slice (&trimmed); + value_ok = true; + } + } + if (! value_ok) + handle_config_error (&p, CPE_BAD_VALUE); + + // if key is for an obsolete option + } else if (slice_matches_str (&p.key, "patch_disembark_immobile_bug")) { + if (read_int (&value, &ival)) + cfg->patch_blocked_disembark_freeze = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "anarchy_length_reduction_percent")) { + if (read_int (&value, &ival)) + cfg->anarchy_length_percent = 100 - ival; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + } else if (slice_matches_str (&p.key, "adjust_minimum_city_separation")) { + if (read_int (&value, &ival)) + cfg->minimum_city_separation = ival + 1; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + } else if (slice_matches_str (&p.key, "reduce_max_escorts_per_ai_transport")) { + if (read_int (&value, &ival)) + cfg->max_ai_naval_escorts = 3 - ival; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + } else if (slice_matches_str (&p.key, "retreat_rules")) { + int rules; + if (read_retreat_rules (&value, &rules)) { + cfg->land_retreat_rules = rules; + cfg->sea_retreat_rules = rules; + } else + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "halve_ai_research_rate")) { + if (read_int (&value, &ival)) { + if (ival) // halving = true => set multiplier to 50, otherwise do nothing + cfg->ai_research_multiplier = 50; + } else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "enable_ai_two_city_start")) { + if (read_int (&value, &ival)) + cfg->ai_multi_city_start = (ival != 0) ? 2 : 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "polish_non_air_precision_striking")) { + if (read_int (&value, &ival)) + cfg->polish_precision_striking = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "promote_forbidden_palace_decorruption")) { + if (read_int (&value, &ival)) + cfg->promote_wonder_decorruption_effect = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "move_trade_net_object")) { + ; // No nothing. This setting no longer serves any purpose. + + // if key was previously misspelled + } else if (slice_matches_str (&p.key, "share_visibility_in_hoseat")) { + if (read_int (&value, &ival)) + cfg->share_visibility_in_hotseat = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "unit_group")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct unit_counter_group), + parse_unit_counter_group, + (void **)&cfg->unit_counter_groups, + &cfg->count_unit_counter_groups))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "counter_rule")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct counter_rule), + parse_counter_rule, + (void **)&cfg->counter_rules, + &cfg->count_counter_rules))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + + } else { + handle_config_error (&p, CPE_BAD_KEY); + } + + + } else { // Failed to parse value + handle_config_error (&p, CPE_BAD_VALUE); + skip_to_line_end (&p.cursor); + } + + } else { // Failed to categorize line + handle_config_error (&p, CPE_GENERIC); + skip_to_line_end (&p.cursor); + } + } + + if (cfg->warn_about_unrecognized_names && (unrecognized_lines != NULL)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "Unrecognized names in %s:", full_path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + for (struct error_line * line = unrecognized_lines; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + patch_show_popup (popup, __, 0, 0); + } + + // Copy perfume specs from lists to tables + for (int n = 0; n < COUNT_PERFUME_KINDS; n++) { + struct table * table = &cfg->perfume_specs[n]; + struct perfume_spec_list * list = &perfume_spec_lists[n]; + if (list->items != NULL) { + for (int k = 0; k < list->count; k++) { + struct perfume_spec * ps = &list->items[k]; + stable_insert (table, ps->name, ps->value); + } + free (list->items); + } + } + + // Copy unit type limits from list to table + if (parsed_unit_type_limits != NULL) { + for (int n = 0; n < parsed_unit_type_limit_count; n++) { + struct parsed_unit_type_limit * parsed_lim = &parsed_unit_type_limits[n]; + struct unit_type_limit * lim_values = malloc (sizeof *lim_values); + *lim_values = parsed_lim->limit; + stable_insert (&cfg->unit_limits, parsed_lim->name, (int)lim_values); + } + free (parsed_unit_type_limits); + } + + free (text); + free_error_lines (unrecognized_lines); + + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = full_path; + new_lcn->next = NULL; + + top_lcn->next = new_lcn; +} + +bool +tile_coords_from_ptr (Map * map, Tile * tile, int * out_x, int * out_y) +{ + if ((tile == NULL) || (tile == p_null_tile) || (map == NULL)) + return false; + + int tile_count = map->TileCount; + for (int index = 0; index < tile_count; index++) { + Tile * candidate = Map_get_tile (map, __, index); + if (candidate == tile) { + tile_index_to_coords (map, index, out_x, out_y); + return true; + } + } + + return false; +} + +int +get_pending_district_request_key (int city_id, int district_id) +{ + if ((city_id < 0) || (district_id < 0)) + return -1; + unsigned int key = ((unsigned int)city_id << 16) | (unsigned int)(district_id & 0xffff); + return (int)key; +} + +struct pending_district_request * +find_pending_district_request (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0)) + return NULL; + + int civ_id = city->Body.CivID; + int city_id = city->Body.ID; + int key = get_pending_district_request_key (city_id, district_id); + if (key < 0) + return NULL; + + int stored; + if (itable_look_up (&is->city_pending_district_requests[civ_id], key, &stored)) { + struct pending_district_request * req = (struct pending_district_request *)stored; + if ((req != NULL) && (req->civ_id == civ_id) && (req->city_id == city_id) && (req->district_id == district_id)) { + if (req->city != city) + req->city = city; + return req; + } + } + return NULL; +} + +struct pending_district_request * +create_pending_district_request (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return NULL; + + struct pending_district_request * existing = find_pending_district_request (city, district_id); + if (existing != NULL) + return existing; + + int civ_id = city->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) + return NULL; + + struct pending_district_request * req = (struct pending_district_request *)calloc (1, sizeof *req); + if (req == NULL) + return NULL; + + req->city = city; + req->city_id = city->Body.ID; + req->civ_id = civ_id; + req->district_id = district_id; + req->assigned_worker_id = -1; + req->target_x = -1; + req->target_y = -1; + req->worker_assigned_turn = 0; + + int key = get_pending_district_request_key (req->city_id, district_id); + if (key < 0) { + free (req); + return NULL; + } + + char ss[200]; + snprintf (ss, sizeof ss, "create_pending_district_request: Creating pending district request for city %s (ID %d) district ID %d with key %d\n", + city->Body.CityName, city->Body.ID, district_id, key); + (*p_OutputDebugStringA) (ss); + + itable_insert (&is->city_pending_district_requests[civ_id], key, (int)req); + return req; +} + +struct pending_district_request * +find_pending_district_request_by_coords (City * city_or_null, int tile_x, int tile_y, int district_id) +{ + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + + int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((civ_id < 0) || (civ_id >= 32)) + return NULL; + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req == NULL) continue; + if (req->district_id != district_id) continue; + if (city_or_null != NULL) { + int city_id = city_or_null->Body.ID; + if (req->city_id != city_id) + continue; + req->city = city_or_null; + req->civ_id = city_or_null->Body.CivID; + } + if ((req->target_x == tile_x) && (req->target_y == tile_y)) + return req; + } + return NULL; +} + +bool +is_tile_earmarked_for_district (int tile_x, int tile_y) +{ + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req == NULL) continue; + if ((req->target_x == tile_x) && (req->target_y == tile_y)) + return true; + } + return false; +} + +struct district_instance * +get_district_instance (Tile * tile) +{ + if (tile == NULL || tile == p_null_tile) + return NULL; + + int stored_ptr; + if (! itable_look_up (&is->district_tile_map, (int)tile, &stored_ptr)) + return NULL; + + struct district_instance * inst = (struct district_instance *)stored_ptr; + + if ((inst == NULL) || (inst->district_id < 0) || (inst->district_id >= is->district_count)) + return NULL; + + return inst; +} + +struct wonder_district_info * +get_wonder_district_info (Tile * tile) +{ + if (tile == NULL || tile == p_null_tile) + return NULL; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return NULL; + + return &inst->wonder_info; +} + +void +remove_district_instance (Tile * tile) +{ + if (tile == NULL || tile == p_null_tile) + return; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + free (inst); + itable_remove (&is->district_tile_map, (int)tile); + } +} + +void +district_instance_set_coords (struct district_instance * inst, int tile_x, int tile_y) +{ + if (inst == NULL) + return; + + // Normalize coordinates to map bounds for consistency + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + inst->tile_x = tile_x; + inst->tile_y = tile_y; +} + +struct district_instance * +ensure_district_instance (Tile * tile, int district_id, int tile_x, int tile_y) +{ + if (tile == NULL || tile == p_null_tile) + return NULL; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + return inst; + } + + inst = (struct district_instance *)calloc (1, sizeof(struct district_instance)); + if (inst == NULL) + return NULL; + + inst->state = DS_UNDER_CONSTRUCTION; + inst->district_id = district_id; + inst->built_by_civ_id = -1; + inst->completed_turn = -1; + + // Initialize wonder_info (only relevant for wonder districts) + inst->wonder_info.state = WDS_UNUSED; + inst->wonder_info.city = NULL; + inst->wonder_info.city_id = -1; + inst->wonder_info.wonder_index = -1; + inst->natural_wonder_info.natural_wonder_id = -1; + + district_instance_set_coords (inst, tile_x, tile_y); + itable_insert (&is->district_tile_map, (int)tile, (int)inst); + return inst; +} + +bool +district_instance_get_coords (struct district_instance * inst, Tile * tile, int * out_x, int * out_y) +{ + if ((inst == NULL) || (out_x == NULL) || (out_y == NULL)) + return false; + + int x = inst->tile_x; + int y = inst->tile_y; + if ((x >= 0) && (y >= 0)) { + *out_x = x; + *out_y = y; + return true; + } + + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile_coords_from_ptr (&p_bic_data->Map, tile, &x, &y)) { + district_instance_set_coords (inst, x, y); + *out_x = x; + *out_y = y; + return true; + } + + return false; +} + +struct natural_wonder_district_config const * +get_natural_wonder_config_by_id (int natural_wonder_id) +{ + if (! is->current_config.enable_natural_wonders) + return NULL; + if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) + return NULL; + return &is->natural_wonder_configs[natural_wonder_id]; +} + +void +assign_natural_wonder_to_tile (Tile * tile, int tile_x, int tile_y, int natural_wonder_id) +{ + if (! is->current_config.enable_natural_wonders) + return; + if ((tile == NULL) || (tile == p_null_tile)) + return; + if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) + return; + + if (get_natural_wonder_config_by_id (natural_wonder_id) == NULL) + return; + + struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, tile_x, tile_y); + if (inst == NULL) + return; + + inst->district_id = NATURAL_WONDER_DISTRICT_ID; + inst->state = DS_COMPLETED; + inst->natural_wonder_info.natural_wonder_id = natural_wonder_id; + set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); +} + +int +apply_district_bonus_entries (struct district_instance * inst, + struct district_bonus_list const * extras, + int district_id) +{ + if ((inst == NULL) || (extras == NULL) || (extras->count <= 0)) + return 0; + + int tile_x = inst->tile_x; + int tile_y = inst->tile_y; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return 0; + + int bonus = 0; + for (int i = 0; i < extras->count; i++) { + struct district_bonus_entry const * entry = &extras->entries[i]; + if (entry->type == DBET_TILE) { + if (tile_matches_square_type (tile, entry->tile_type)) + bonus += entry->bonus; + } else if (entry->type == DBET_BUILDING) { + if (entry->building_id >= 0 && + tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, entry->building_id)) + bonus += entry->bonus; + } + } + + return bonus; +} + +void +get_effective_district_yields (struct district_instance * inst, + struct district_config const * cfg, + int * out_food, + int * out_shields, + int * out_gold, + int * out_science, + int * out_culture, + int * out_happiness) +{ + int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; + + if (cfg != NULL && is->current_config.enable_districts) { + food = cfg->food_bonus; + shields = cfg->shield_bonus; + gold = cfg->gold_bonus; + science = cfg->science_bonus; + culture = cfg->culture_bonus; + happiness = cfg->happiness_bonus; + + int district_id = (inst != NULL) ? inst->district_id : -1; + food += apply_district_bonus_entries (inst, &cfg->food_bonus_extras, district_id); + shields += apply_district_bonus_entries (inst, &cfg->shield_bonus_extras, district_id); + gold += apply_district_bonus_entries (inst, &cfg->gold_bonus_extras, district_id); + science += apply_district_bonus_entries (inst, &cfg->science_bonus_extras, district_id); + culture += apply_district_bonus_entries (inst, &cfg->culture_bonus_extras, district_id); + happiness += apply_district_bonus_entries (inst, &cfg->happiness_bonus_extras, district_id); + } + + if (inst != NULL && is->current_config.enable_natural_wonders && inst->district_id == NATURAL_WONDER_DISTRICT_ID) { + struct natural_wonder_district_config const * nwcfg = get_natural_wonder_config_by_id (inst->natural_wonder_info.natural_wonder_id); + if (nwcfg != NULL) { + food += nwcfg->food_bonus; + shields += nwcfg->shield_bonus; + gold += nwcfg->gold_bonus; + science += nwcfg->science_bonus; + culture += nwcfg->culture_bonus; + happiness += nwcfg->happiness_bonus; + } + } + + if (out_food != NULL) + *out_food = food; + if (out_shields != NULL) + *out_shields = shields; + if (out_gold != NULL) + *out_gold = gold; + if (out_science != NULL) + *out_science = science; + if (out_culture != NULL) + *out_culture = culture; + if (out_happiness != NULL) + *out_happiness = happiness; +} + +int +natural_wonder_min_distance_sq (int x, + int y, + struct wonder_location const * placements, + int placement_count) +{ + if ((placements == NULL) || (placement_count <= 0)) + return INT_MAX; + + int best = INT_MAX; + for (int i = 0; i < placement_count; i++) { + int dx, dy; + compute_wrapped_deltas (x, y, placements[i].x, placements[i].y, &dx, &dy); + int dist_sq = dx * dx + dy * dy; + if (dist_sq < best) + best = dist_sq; + } + return best; +} + +bool +continent_has_natural_wonder (int continent_id, + struct wonder_location const * placements, + int placement_count) +{ + if (continent_id < 0) + return false; + if ((placements == NULL) || (placement_count <= 0)) + return false; + + for (int i = 0; i < placement_count; i++) { + Tile * placed_tile = tile_at (placements[i].x, placements[i].y); + if ((placed_tile == NULL) || (placed_tile == p_null_tile)) + continue; + int placed_continent_id = placed_tile->vtable->m46_Get_ContinentID (placed_tile); + if (placed_continent_id == continent_id) + return true; + } + + return false; +} + +bool +natural_wonder_candidate_list_push (struct natural_wonder_candidate_list * list, Tile * tile, int tile_x, int tile_y) +{ + if (list == NULL) + return false; + + if (list->count >= list->capacity) { + int new_capacity = (list->capacity > 0) ? (list->capacity * 2) : 8; + struct natural_wonder_candidate * grown = + (struct natural_wonder_candidate *)realloc (list->entries, new_capacity * sizeof *grown); + if (grown == NULL) + return false; + list->entries = grown; + list->capacity = new_capacity; + } + + struct natural_wonder_candidate * entry = &list->entries[list->count++]; + entry->tile = tile; + entry->x = (short)tile_x; + entry->y = (short)tile_y; + return true; +} + +bool +natural_wonder_tile_is_clear (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (tile->CityID >= 0) return false; + if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return false; + if (tile->vtable->m15_Check_Goody_Hut (tile, __, 0)) return false; + if (tile->vtable->m39_Get_Resource_Type (tile) >= 0) return false; + if (tile->vtable->m18_Check_Mines (tile, __, 0)) return false; + if (get_district_instance (tile) != NULL) return false; + + // Check if this tile is a starting location for any civ + int tile_index = (p_bic_data->Map.Width >> 1) * tile_y + ((tile_x >> 1) & 0x7FFF); + for (int civ = 0; civ < p_bic_data->Map.Civ_Count; civ++) { + if (p_bic_data->Map.Starting_Locations[civ] == tile_index) { + return false; + } + } + + return true; +} + +bool +district_exists_within_distance (int tile_x, int tile_y, int district_id, int civ_id, int min_distance) +{ + if ((district_id < 0) || (district_id >= is->district_count) || (min_distance < 0)) + return false; + + for (int dist = 0; dist <= min_distance; dist++) { + struct vertex { + int x, y; + } vertices[4] = { + {tile_x , tile_y - 2*dist}, + {tile_x + 2*dist, tile_y }, + {tile_x , tile_y + 2*dist}, + {tile_x - 2*dist, tile_y } + }; + + int edge_dirs[4] = {3, 5, 7, 1}; + int edge_len = (dist == 0) ? 1 : 2 * dist; + + for (int vert = 0; vert < 4; vert++) { + wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); + int dx, dy; + neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); + for (int j = 0; j < edge_len; j++) { + int cx = vertices[vert].x + j * dx; + int cy = vertices[vert].y + j * dy; + wrap_tile_coords (&p_bic_data->Map, &cx, &cy); + + Tile * tile = tile_at (cx, cy); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if ((civ_id >= 0) && (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id)) + continue; + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == district_id)) + return true; + } + } + } + + return false; +} + +void +detach_workers_from_request (struct pending_district_request * req) +{ + if (req == NULL) + return; + + int civ_id = req->civ_id; + if ((civ_id < 0) || (civ_id >= 32)) { + for (int civ = 0; civ < 32; civ++) { + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + if ((rec != NULL) && (rec->pending_req == req)) + rec->pending_req = NULL; + } + } + return; + } + + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + if ((rec != NULL) && (rec->pending_req == req)) + rec->pending_req = NULL; + } +} + +void +remove_pending_district_request (struct pending_district_request * req) +{ + if (req == NULL) + return; + + int civ_id = req->civ_id; + if ((civ_id < 0) || (civ_id >= 32)) + return; + + int key = get_pending_district_request_key (req->city_id, req->district_id); + + detach_workers_from_request (req); + + if ((req->target_x >= 0) && (req->target_y >= 0)) { + Tile * tile = tile_at (req->target_x, req->target_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && + (inst->district_id == req->district_id) && + (inst->state != DS_COMPLETED)) + remove_district_instance (tile); + } + } + + if (key >= 0) + itable_remove (&is->city_pending_district_requests[civ_id], key); + req->city = NULL; + req->city_id = -1; + req->civ_id = -1; + free (req); +} + +bool __fastcall +patch_Leader_impl_would_raze_city (Leader * this, int edx, City * city) +{ + return is->current_config.prevent_razing_by_players ? false : Leader_impl_would_raze_city (this, __, city); +} + +int __fastcall patch_Unit_get_max_move_points (Unit * this); + +// This function is used to fix a bug where the game would freeze when using disembark all on a transport that contained an immobile unit. The bug +// comes from the fact that the function to disembark all units loops continuously over units in the transport until there are none left that +// can be disembarked. The problem is the logic to check disembarkability erroneously reports immobile units as disembarkable when they're not, +// so the program gets stuck in an infinite loop. The fix affects the function that checks disembarkability, replacing a call to +// Unit_get_max_move_points with a call to the function below. This function returns zero for immobile units, causing the caller to report +// (correctly) that the unit cannot be disembarked. +int __fastcall +patch_Unit_get_max_move_points_for_disembarking (Unit * this) +{ + if (is->current_config.patch_blocked_disembark_freeze && + UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Immobile)) + return 0; + else + return patch_Unit_get_max_move_points (this); +} + +// Unit::move_to_adjacent_tile uses a separate "spend all remaining movement when disembarking" branch for land units moving from water to land. +// Bridge districts still look like water tiles to that stock logic, so stepping off a bridge can incorrectly consume the whole turn. When the +// wrapper around move_to_adjacent_tile detects bridge->land movement, it precomputes the correct spent-moves total and exposes it here. +int __fastcall +patch_Unit_get_max_move_points_for_bridge_exit (Unit * this) +{ + if ((this != NULL) && (this == is->move_spend_override_unit)) + return is->move_spend_override_value; + else + return patch_Unit_get_max_move_points (this); +} + +// This func implements GA remaining turns indicator. It intercepts a call to some kind of text processing function when it's called to process the +// text in the lower right (containing current research, GA status, & mobilization) and splices in the number of remaining GA turns if in a GA. +int __fastcall +patch_PCX_Image_process_tech_ga_status (PCX_Image * this, int edx, char * str) +{ + Leader * player = &leaders[p_main_screen_form->Player_CivID]; + if (is->current_config.show_golden_age_turns_remaining && + (*p_current_turn_no < player->Golden_Age_End)) { + int turns_left = player->Golden_Age_End - *p_current_turn_no; + char const * ga_label = (*p_labels)[LBL_GOLDEN_AGE]; + char const * ga_str_start = strstr (str, ga_label); + if (ga_str_start != NULL) { + char s[250]; + char const * ga_str_end = ga_str_start + strlen (ga_label); + snprintf (s, sizeof s, "%.*s (%d)%s", ga_str_end - str, str, turns_left, ga_str_end); + s[(sizeof s) - 1] = '\0'; + strncpy (str, s, sizeof s); + } + } + return PCX_Image_process_text (this, __, str); +} + +bool __fastcall +patch_Leader_is_tile_visible (Leader * this, int edx, int x, int y) +{ + Tile_Body * tile = &tile_at (x, y)->Body; + unsigned vis_bits = tile->FOWStatus | tile->V3 | tile->Visibility | tile->field_D0_Visibility; + if (vis_bits & (1 << this->ID)) + return true; + else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND + ((1 << this->ID) & *p_human_player_bits) && // "this" is a human player AND + (vis_bits & *p_human_player_bits)) // any human player has visibility on the tile + return true; + else + return false; +} + +bool __fastcall +patch_Main_Screen_Form_is_unit_visible_to_player (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * unit) +{ + return (unit->Body.CivID == this->Player_CivID) || patch_Leader_is_tile_visible (&leaders[this->Player_CivID], __, tile_x, tile_y); +} + +enum direction +reverse_dir (enum direction dir) +{ + enum direction const reversed[] = { + DIR_ZERO, // DIR_ZERO + DIR_SW , // DIR_NE + DIR_W , // DIR_E + DIR_NW , // DIR_SE + DIR_N , // DIR_S + DIR_NE , // DIR_SW + DIR_E , // DIR_W + DIR_SE , // DIR_NW + DIR_S , // DIR_N + }; + int n = (int)dir; + if ((n >= 0) && (n < ARRAY_LEN (reversed))) + return reversed[n]; + else + return DIR_ZERO; +} + +bool +direction_to_offset (enum direction dir, int * out_dx, int * out_dy) +{ + int dx = 0, dy = 0; + + switch (dir) { + case DIR_NE: dx = 1; dy = -1; break; + case DIR_E: dx = 2; dy = 0; break; + case DIR_SE: dx = 1; dy = 1; break; + case DIR_S: dx = 0; dy = 2; break; + case DIR_SW: dx = -1; dy = 1; break; + case DIR_W: dx = -2; dy = 0; break; + case DIR_NW: dx = -1; dy = -1; break; + case DIR_N: dx = 0; dy = -2; break; + case DIR_ZERO: + default: + return false; + } + + if (out_dx != NULL) + *out_dx = dx; + if (out_dy != NULL) + *out_dy = dy; + return true; +} + +int +direction_to_neighbor_bit (enum direction dir) +{ + switch (dir) { + case DIR_NE: return 1; + case DIR_E: return 2; + case DIR_SE: return 3; + case DIR_S: return 4; + case DIR_SW: return 5; + case DIR_W: return 6; + case DIR_NW: return 7; + case DIR_N: return 0; // Matches engine behaviour where neighbor index 8 maps to 0 + default: + return -1; + } +} + +bool +get_primary_river_direction (Tile * tile, enum direction * out_dir) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + char river_bits = tile->vtable->m37_Get_River_Code (tile); + if (river_bits == 0) + return false; + + enum direction dirs[] = {DIR_E, DIR_W, DIR_SE, DIR_NE, DIR_SW, DIR_NW, DIR_S, DIR_N}; + for (int i = 0; i < (int)ARRAY_LEN (dirs); i++) { + int bit = direction_to_neighbor_bit (dirs[i]); + if ((bit >= 0) && ((river_bits & (1 << bit)) != 0)) { + if (out_dir != NULL) + *out_dir = dirs[i]; + return true; + } + } + + return false; +} + +void +wrap_tile_coords (Map * map, int * x, int * y) +{ + if (map->Flags & 1) { + if (*x < 0) *x += map->Width; + else if (*x >= map->Width) *x -= map->Width; + } + if (map->Flags & 2) { + if (*y < 0) *y += map->Height; + else if (*y >= map->Height) *y -= map->Height; + } +} + +void +tile_index_to_coords (Map * map, int index, int * out_x, int * out_y) +{ + if ((index >= 0) && (index < map->TileCount)) { + int width = map->Width; + int double_row = index / width, double_row_rem = index % width; + if (double_row_rem < width/2) { + *out_x = 2 * double_row_rem; + *out_y = 2 * double_row; + } else { + *out_x = 1 + 2 * (double_row_rem - width/2); + *out_y = 2 * double_row + 1; + } + } else + *out_x = *out_y = -1; +} + +int +tile_coords_to_index (Map * map, int x, int y) +{ + if ((map == NULL) || (x < 0) || (y < 0) || (x >= map->Width) || (y >= map->Height)) + return -1; + + int width = map->Width; + int row = y / 2; + if ((y & 1) == 0) { + return row * width + (x / 2); + } else { + return row * width + (width / 2) + (x / 2); + } +} + +Tile * +tile_at_index (Map * map, int i) +{ + int x, y; + tile_index_to_coords (map, i, &x, &y); + return tile_at (x, y); +} + +void +get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y) +{ + int dx, dy; + neighbor_index_to_diff (neighbor_index, &dx, &dy); + *out_x = x + dx; + *out_y = y + dy; + wrap_tile_coords (map, out_x, out_y); +} + +Tile * __stdcall +tile_at_city_or_null (City * city_or_null) +{ + if (city_or_null) + return tile_at (city_or_null->Body.X, city_or_null->Body.Y); + else + return p_null_tile; +} + +Unit * +get_unit_ptr (int id) +{ + if ((p_units->Units != NULL) && + (id >= 0) && (id <= p_units->LastIndex)) { + Unit_Body * body = p_units->Units[id].Unit; + if (body != NULL) { + Unit * unit = (Unit *)((char *)body - offsetof (Unit, Body)); + if (unit != NULL) + return unit; + } + } + return NULL; +} + +bool +is_land_transport (Unit * unit) +{ + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + return type->Unit_Class == UTC_Land && type->Transport_Capacity > 0 && ! Unit_has_ability (unit, __, UTA_Army); +} + +bool +is_in_land_transport (Unit * unit) +{ + Unit * container = get_unit_ptr (unit->Body.Container_Unit); + return container != NULL && is_land_transport (container); +} + +// Checks if the unit is inside a transport (either helicopter or land transport) from which it is not allowed to defend according to the mod config. +bool +cannot_defend_inside_transport (Unit * unit) +{ + Unit * container = get_unit_ptr (unit->Body.Container_Unit); + if (container != NULL) { + if ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && is_land_transport (container)) + return true; + + if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return true; + } + return false; +} + +struct unit_tile_iter { + int id; + int item_index; + Unit * unit; +}; + +void +uti_next (struct unit_tile_iter * uti) +{ + if (((p_tile_units->Base.Items == NULL) || (uti->item_index < 0)) || + (uti->item_index > p_tile_units->Base.LastIndex)) { + uti->item_index = -1; + uti->id = p_tile_units->DefaultValue; + } else { + Base_List_Item * item = &p_tile_units->Base.Items[uti->item_index]; + uti->item_index = item->V; + uti->id = (int)item->Object; + } + uti->unit = get_unit_ptr (uti->id); +} + +struct unit_tile_iter +uti_init (Tile * tile) +{ + struct unit_tile_iter tr; + int tile_unit_id = tile->vtable->m40_get_TileUnit_ID (tile); + tr.id = TileUnits_TileUnitID_to_UnitID (p_tile_units, __, tile_unit_id, &tr.item_index); + tr.unit = get_unit_ptr (tr.id); + return tr; +} + +#define FOR_UNITS_ON(uti_name, tile) for (struct unit_tile_iter uti_name = uti_init (tile); uti_name.id != -1; uti_next (&uti_name)) + +bool +tile_has_enemy_unit (Tile * tile, int civ_id) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + if ((civ_id < 0) || (civ_id >= 32)) + return false; + + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit == NULL) || (unit->Body.Container_Unit >= 0)) + continue; + if (unit->Body.CivID == civ_id) + continue; + if (unit->vtable->is_enemy_of_civ (unit, __, civ_id, 0)) + return true; + } + + return false; +} + +struct citizen_iter { + int index; + Citizens * list; + Citizen_Base * ctzn; +}; + +void +ci_next (struct citizen_iter * ci) +{ + while (1) { + ci->index++; + if (ci->index > ci->list->LastIndex) { + ci->ctzn = NULL; + break; + } else { + Citizen_Body * body = ci->list->Items[ci->index].Body; + if ((body != NULL) && ((int)body != offsetof (Citizen_Base, Body))) { + ci->ctzn = (Citizen_Base *)((int)body - offsetof (Citizen_Base, Body)); + break; + } + } + } +} + +struct citizen_iter +ci_init (City * city) +{ + struct citizen_iter tr; + tr.index = -1; + tr.list = &city->Body.Citizens; + tr.ctzn = NULL; + if (city->Body.Citizens.Items != NULL) + ci_next (&tr); + return tr; +} + +#define FOR_CITIZENS_IN(ci_name, city) for (struct citizen_iter ci_name = ci_init (city); (ci_name.list->Items != NULL) && (ci_name.index <= ci.list->LastIndex); ci_next (&ci_name)) + +struct city_of_iter { + int city_id; + int civ_id; + City * city; +}; + +void +coi_next (struct city_of_iter * coi) +{ + coi->city_id++; + while (coi->city_id <= p_cities->LastIndex) { + City_Body * body = p_cities->Cities[coi->city_id].City; + if ((body != NULL) && ((int)body != offsetof (City, Body)) && (body->CivID == coi->civ_id)) { + coi->city = (City *)((char *)body - offsetof (City, Body)); + break; + } + coi->city_id++; + } +} + +struct city_of_iter +coi_init (int civ_id) +{ + struct city_of_iter tr = { .city_id = -1, .civ_id = civ_id, .city = NULL }; + if (p_cities->Cities != NULL) + coi_next (&tr); + else + tr.city_id = p_cities->LastIndex + 1; + return tr; +} + +#define FOR_CITIES_OF(coi_name, civ_id) for (struct city_of_iter coi_name = coi_init (civ_id); coi_name.city_id <= p_cities->LastIndex; coi_next (&coi_name)) + +struct tiles_around_iter { + int center_x, center_y; + int n, num_tiles; + Tile * tile; + int tile_x, tile_y; +}; + +void +tai_next (struct tiles_around_iter * tai) +{ + tai->tile = p_null_tile; + while ((tai->n < tai->num_tiles) && (tai->tile == p_null_tile)) { + tai->n += 1; + int tx, ty; + get_neighbor_coords (&p_bic_data->Map, tai->center_x, tai->center_y, tai->n, &tx, &ty); + if ((tx >= 0) && (tx < p_bic_data->Map.Width) && (ty >= 0) && (ty < p_bic_data->Map.Height)) { + tai->tile = tile_at (tx, ty); + tai->tile_x = tx; + tai->tile_y = ty; + } + } +} + +struct tiles_around_iter +tai_init (int num_tiles, int x, int y) +{ + struct tiles_around_iter tr; + tr.center_x = x; + tr.center_y = y; + tr.n = 0; + tr.num_tiles = num_tiles; + tr.tile = tile_at (x, y); + tr.tile_x = x; + tr.tile_y = y; + return tr; +} + +#define FOR_TILES_AROUND(tai_name, _num_tiles, _x, _y) for (struct tiles_around_iter tai_name = tai_init (_num_tiles, _x, _y); (tai_name.n < tai_name.num_tiles); tai_next (&tai_name)) + +enum work_area_iter_output_type { + WAIO_ANY, + WAIO_DISTRICTS, + WAIO_CITIES, +}; + +struct work_area_iter { + int center_x, center_y; + int n, num_tiles; + int civ_id; + int dx, dy; + int tile_x, tile_y; + Tile * tile; + City * city; + struct district_instance * district_inst; + enum work_area_iter_output_type output_type; + bool completed_districts_only; +}; + +void +wai_next (struct work_area_iter * wai) +{ + wai->tile = p_null_tile; + wai->district_inst = NULL; + while ((wai->n + 1) < wai->num_tiles) { + wai->n += 1; + patch_ni_to_diff_for_work_area (wai->n, &wai->dx, &wai->dy); + wai->tile_x = wai->center_x + wai->dx; + wai->tile_y = wai->center_y + wai->dy; + wrap_tile_coords (&p_bic_data->Map, &wai->tile_x, &wai->tile_y); + Tile * candidate = tile_at (wai->tile_x, wai->tile_y); + if ((candidate == NULL) || (candidate == p_null_tile)) + continue; + if ((wai->civ_id < 0) || (candidate->vtable->m38_Get_Territory_OwnerID (candidate) != wai->civ_id)) + continue; + if (tile_has_enemy_unit (candidate, wai->civ_id)) + continue; + if (candidate->vtable->m20_Check_Pollution (candidate, __, 0)) + continue; + City * city; + if (wai->output_type == WAIO_CITIES) { + if (candidate->CityID < 0) + continue; + city = get_city_ptr (candidate->vtable->m45_Get_City_ID (candidate)); + if (city == NULL || city->Body.CivID != wai->civ_id) + continue; + } + struct district_instance * inst = get_district_instance (candidate); + if (wai->output_type == WAIO_DISTRICTS) { + if (inst == NULL) + continue; + int district_id = inst->district_id; + if (wai->completed_districts_only && (! district_is_complete (candidate, district_id))) + continue; + } + wai->city = city; + wai->district_inst = inst; + wai->tile = candidate; + break; + } + if (wai->tile == p_null_tile) + wai->n = wai->num_tiles; +} + +struct work_area_iter +wai_init_common (int x, int y, enum work_area_iter_output_type output, bool completed_districts_only) +{ + struct work_area_iter tr; + tr.center_x = x; + tr.center_y = y; + tr.n = -1; + tr.num_tiles = is->workable_tile_count; + Tile * center_tile = tile_at (x, y); + if ((center_tile == NULL) || (center_tile == p_null_tile)) + tr.civ_id = -1; + else + tr.civ_id = center_tile->vtable->m38_Get_Territory_OwnerID (center_tile); + tr.tile = p_null_tile; + tr.district_inst = NULL; + tr.dx = 0; + tr.dy = 0; + tr.tile_x = 0; + tr.tile_y = 0; + tr.output_type = output; + tr.completed_districts_only = completed_districts_only; + wai_next (&tr); + return tr; +} + +struct work_area_iter +wai_init (int x, int y) +{ + return wai_init_common (x, y, false, false); +} + +struct work_area_iter +wai_init_districts (int x, int y, bool completed_only) +{ + return wai_init_common (x, y, WAIO_DISTRICTS, completed_only); +} + +struct work_area_iter +wai_init_cities (int x, int y) +{ + struct work_area_iter tr = wai_init_common (x, y, WAIO_CITIES, false); + return tr; +} + +#define FOR_WORK_AREA_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) +#define FOR_DISTRICTS_AROUND(wai_name, _x, _y, _completed_only) for (struct work_area_iter wai_name = wai_init_districts (_x, _y, _completed_only); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) +#define FOR_CITIES_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init_cities (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) +#define FOR_AERODROMES_AROUND(unit_ptr) \ + for (struct table_entry_iter _tei = tei_init (&is->district_tile_map); \ + _tei.index < _tei.capacity; \ + tei_next (&_tei)) \ + for (Tile * aerodrome_tile = (Tile *)_tei.key; \ + (aerodrome_tile != NULL) && (aerodrome_tile != p_null_tile); \ + aerodrome_tile = NULL) \ + for (struct district_instance * aerodrome_inst = (struct district_instance *)_tei.value; \ + (aerodrome_inst != NULL) && \ + (aerodrome_inst->district_id == AERODROME_DISTRICT_ID) && \ + district_is_complete (aerodrome_tile, AERODROME_DISTRICT_ID); \ + aerodrome_inst = NULL) \ + for (int aerodrome_x = 0, aerodrome_y = 0; \ + district_instance_get_coords (aerodrome_inst, aerodrome_tile, &aerodrome_x, &aerodrome_y) && \ + (aerodrome_tile->vtable->m38_Get_Territory_OwnerID (aerodrome_tile) == (unit_ptr)->Body.CivID) && \ + patch_Unit_is_in_rebase_range ((unit_ptr), __, aerodrome_x, aerodrome_y); \ + aerodrome_x = 0, aerodrome_y = 0) + +struct tile_rings_iter { + int center_x, center_y; + int const * rings; + int ring_count; + int r_idx; + int ni; + int tile_x, tile_y; + int current_ring; + Tile * tile; +}; + +void +tri_next (struct tile_rings_iter * tri) +{ + tri->tile = p_null_tile; + while (tri->r_idx < tri->ring_count) { + int ring_no = tri->rings[tri->r_idx]; + if ((ring_no <= 0) || (ring_no >= 8)) { + tri->r_idx += 1; + tri->ni = -1; + continue; + } + int start_ni = workable_tile_counts[ring_no - 1]; + int end_ni = workable_tile_counts[ring_no]; + if (tri->ni < start_ni) + tri->ni = start_ni; + else if ((tri->ni + 1) < end_ni) + tri->ni += 1; + else { + tri->r_idx += 1; + tri->ni = -1; + continue; + } + tri->current_ring = ring_no; + int dx, dy; + patch_ni_to_diff_for_work_area (tri->ni, &dx, &dy); + int tx = tri->center_x + dx; + int ty = tri->center_y + dy; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + tri->tile_x = tx; + tri->tile_y = ty; + Tile * candidate = tile_at (tx, ty); + if ((candidate == NULL) || (candidate == p_null_tile)) + continue; + tri->tile = candidate; + break; + } + if (tri->tile == p_null_tile) { + tri->r_idx = tri->ring_count; + tri->ni = -1; + } +} + +struct tile_rings_iter +tri_init (int x, int y, int const * rings, int ring_count) +{ + struct tile_rings_iter tr; + tr.center_x = x; + tr.center_y = y; + tr.rings = rings; + tr.ring_count = ring_count; + tr.r_idx = 0; + tr.ni = -1; + tr.tile_x = 0; + tr.tile_y = 0; + tr.current_ring = 0; + tr.tile = p_null_tile; + tri_next (&tr); + return tr; +} + +#define FOR_TILE_RINGS_AROUND(tri_name, _x, _y, _rings, _ring_count) for (struct tile_rings_iter tri_name = tri_init (_x, _y, _rings, _ring_count); (tri_name.r_idx < tri_name.ring_count); tri_next (&tri_name)) + +bool +tile_square_type_is (Tile * tile, enum SquareTypes type) +{ + return tile_matches_square_type (tile, type); +} + +bool +district_is_buildable_on_tile (struct district_config const * cfg, Tile * tile) +{ + if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + unsigned int mask = cfg->buildable_square_types_mask; + if (mask == 0) + mask = district_default_buildable_mask (); + + bool square_matches = tile_matches_square_type_mask (tile, mask); + bool overlay_allowed = false; + bool overlay_required = false; + + if (cfg->has_buildable_without_removal) + overlay_allowed = tile_matches_overlay_mask (tile, cfg->buildable_without_removal_mask); + + if (cfg->has_buildable_on_overlays) { + overlay_required = tile_matches_overlay_mask (tile, cfg->buildable_on_overlays_mask); + if (! overlay_required) + return false; + } + if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) + return false; + + if (! square_matches && ! overlay_allowed && ! overlay_required) + return false; + + if (cfg->has_buildable_on_districts) { + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + + int existing_district_id = inst->district_id; + if (! district_is_complete (tile, existing_district_id)) + return false; + + bool matches = false; + for (int i = 0; i < cfg->buildable_on_district_id_count; i++) { + if (cfg->buildable_on_district_ids[i] == existing_district_id) { + matches = true; + break; + } + } + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to || cfg->has_buildable_adjacent_to_districts || cfg->has_buildable_adjacent_to_overlays) { + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + return false; + + if (cfg->has_buildable_adjacent_to) { + bool matches = false; + bool city_adjacent = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (Tile_has_city (tai.tile)) { + city_adjacent = true; + if (cfg->buildable_adjacent_to_allows_city) + matches = true; + } + if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) + matches = true; + if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) + break; + } + if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) + return false; + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to_overlays) { + bool matches = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { + matches = true; + break; + } + } + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to_districts) { + bool matches = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + struct district_instance * adj_inst = get_district_instance (tai.tile); + if (adj_inst == NULL) + continue; + int adj_district_id = adj_inst->district_id; + if (! district_is_complete (tai.tile, adj_district_id)) + continue; + for (int i = 0; i < cfg->buildable_adjacent_to_district_id_count; i++) { + if (cfg->buildable_adjacent_to_district_ids[i] == adj_district_id) { + matches = true; + break; + } + } + if (matches) + break; + } + if (! matches) + return false; + } + } + + return true; +} + +bool +is_coastal_island (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile->vtable->m35_Check_Is_Water (tile)) + return false; + + bool has_neighbor = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + return false; + + has_neighbor = true; + if (! adj->vtable->m35_Check_Is_Water (adj)) + return false; + + if (adj->vtable->m50_Get_Square_BaseType (adj) != SQ_Coast) + return false; + } + + return has_neighbor; +} + +bool +natural_wonder_adjacent_requirement_met (struct natural_wonder_district_config const * cfg, + Tile * tile, + int tile_x, + int tile_y) +{ + enum SquareTypes required = cfg->adjacent_to; + if (required == (enum SquareTypes)SQ_INVALID) + return true; + + if (required == SQ_RIVER) { + char river_bits = tile->vtable->m37_Get_River_Code (tile); + if (cfg->adjacency_dir != DIR_ZERO) { + int bit = direction_to_neighbor_bit (cfg->adjacency_dir); + if (bit < 0) + return false; + return (river_bits & (1 << bit)) != 0; + } else + return river_bits != 0; + } + + if (cfg->adjacency_dir != DIR_ZERO) { + int dx, dy; + if (! direction_to_offset (cfg->adjacency_dir, &dx, &dy)) + return false; + int nx = tile_x + dx; + int ny = tile_y + dy; + wrap_tile_coords (&p_bic_data->Map, &nx, &ny); + Tile * neighbor = tile_at (nx, ny); + return tile_square_type_is (neighbor, required); + } + + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_square_type_is (tai.tile, required)) + return true; + } + + return false; +} + +int +count_diagonal_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) +{ + if (type == (enum SquareTypes)SQ_INVALID) + return 0; + + enum direction dirs[4] = {DIR_NE, DIR_NW, DIR_SE, DIR_SW}; + int count = 0; + for (int i = 0; i < 4; i++) { + int dx, dy; + if (! direction_to_offset (dirs[i], &dx, &dy)) + continue; + int nx = tile_x + dx; + int ny = tile_y + dy; + wrap_tile_coords (&p_bic_data->Map, &nx, &ny); + Tile * neighbor = tile_at (nx, ny); + if (tile_square_type_is (neighbor, type)) + count += 1; + } + return count; +} + +int +count_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) +{ + if (type == (enum SquareTypes)SQ_INVALID) + return 0; + + int count = 0; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_square_type_is (tai.tile, type)) + count += 1; + } + return count; +} + +bool +natural_wonder_terrain_matches (struct natural_wonder_district_config const * cfg, Tile * tile, int tile_x, int tile_y) +{ + if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + if (! tile_matches_square_type (tile, cfg->terrain_type)) + return false; + + if (cfg->terrain_type == SQ_Coast) { + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + return false; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + if ((continent == NULL) || (continent->Body.TileCount <= 5)) + return false; + } + + if (is_coastal_island (tile, tile_x, tile_y)) + return false; + + if ((cfg->adjacent_to != SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 0)) + return false; + + if ((cfg->adjacent_to == SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 4)) + return false; + + if (! natural_wonder_adjacent_requirement_met (cfg, tile, tile_x, tile_y)) + return false; + + return true; +} + +struct district_worker_record * +get_tracked_worker_record (Unit * worker) +{ + if (worker == NULL) return NULL; + int civ_id = worker->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) return NULL; + + int value; + if (itable_look_up (&is->district_worker_tables[civ_id], worker->Body.ID, &value)) + return (struct district_worker_record *)value; + return NULL; +} + +struct district_worker_record * +ensure_tracked_worker_record (Unit * worker) +{ + if (worker == NULL) return NULL; + int civ_id = worker->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) return NULL; + + struct district_worker_record * rec = get_tracked_worker_record (worker); + if (rec != NULL) return rec; + + rec = (struct district_worker_record *)calloc (1, sizeof *rec); + if (rec == NULL) return NULL; + + rec->worker = worker; + rec->unit_id = worker->Body.ID; + Tile * tile = tile_at (worker->Body.X, worker->Body.Y); + rec->continent_id = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m46_Get_ContinentID (tile) : -1; + rec->pending_req = NULL; + + itable_insert (&is->district_worker_tables[civ_id], worker->Body.ID, (int)rec); + return rec; +} + +void +remove_tracked_worker_record (int civ_id, int unit_id) +{ + if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) + return; + + int value; + if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) + return; + + struct district_worker_record * rec = (struct district_worker_record *)value; + if (rec->pending_req != NULL) { + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + } + + itable_remove (&is->district_worker_tables[civ_id], unit_id); + free (rec); +} + +void +clear_tracked_worker_assignment (struct district_worker_record * rec) +{ + if (rec == NULL) + return; + + if (rec->pending_req != NULL) { + if (rec->pending_req->assigned_worker_id == rec->unit_id) + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + } +} + +void +clear_tracked_worker_assignment_by_id (int civ_id, int unit_id) +{ + if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) + return; + + int value; + if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) + return; + + struct district_worker_record * rec = (struct district_worker_record *)value; + if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == unit_id)) + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + if ((rec->worker == NULL) || (get_unit_ptr (unit_id) == NULL)) + remove_tracked_worker_record (civ_id, unit_id); +} + +void +clear_all_tracked_workers (void) +{ + for (int civ = 0; civ < 32; civ++) { + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + if (rec == NULL) + continue; + if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == rec->unit_id)) + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + free (rec); + } + is->district_worker_tables[civ].len = 0; + if (is->district_worker_tables[civ].block != NULL) { + free (is->district_worker_tables[civ].block); + is->district_worker_tables[civ].block = NULL; + } + is->district_worker_tables[civ].capacity_exponent = 0; + } +} + +bool is_worker (Unit * unit) +{ + if (unit == NULL) + return false; + + int unit_type_id = unit->Body.UnitTypeID; + int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; + + if (worker_actions == 0 || !(worker_actions & (UCV_Build_Road | UCV_Build_Mine | UCV_Irrigate))) { + return false; + } + + return true; +} + +void +update_tracked_worker_for_unit (Unit * worker) +{ + if (worker == NULL || ! is->current_config.enable_districts) return; + + int civ_id = worker->Body.CivID; + int type_id = worker->Body.UnitTypeID; + if ((civ_id < 0) || (civ_id >= 32)) return; + if ((*p_human_player_bits & (1 << civ_id)) != 0) return; + + char ss[200]; + snprintf (ss, sizeof ss, "Updating tracked worker for unit %d of type %d\n", worker->Body.ID, type_id); + (*p_OutputDebugStringA) (ss); + + if (! is_worker (worker)) { + remove_tracked_worker_record(worker->Body.CivID, worker->Body.ID); + return; + } + + ensure_tracked_worker_record (worker); +} + +bool +assign_worker_to_district (struct pending_district_request * req, Unit * worker, City * city, int district_id, int tile_x, int tile_y) +{ + if (worker == NULL || city == NULL) + return false; + if (req == NULL) + return false; + + req->city = city; + req->city_id = city->Body.ID; + req->civ_id = city->Body.CivID; + req->assigned_worker_id = worker->Body.ID; + req->worker_assigned_turn = *p_current_turn_no; + req->target_x = tile_x; + req->target_y = tile_y; + worker->Body.Auto_CityID = city->Body.ID; + + char ss[200]; + snprintf (ss, sizeof ss, "assign_worker_to_district: Assigned worker unit %d to build district %d in city %s at (%d,%d)\n", + worker->Body.ID, district_id, city->Body.CityName, tile_x, tile_y); + (*p_OutputDebugStringA) (ss); + + struct district_worker_record * record = ensure_tracked_worker_record (worker); + if (record != NULL) { + record->pending_req = req; + } + + return ai_move_district_worker (worker, record); +} + +bool +worker_is_available_for_district (Unit * worker) +{ + if (worker == NULL) + return false; + + int civ_id = worker->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) return false; + if ((*p_human_player_bits & (1 << civ_id)) != 0) return false; + + int type_id = worker->Body.UnitTypeID; + if ((type_id < 0) || (type_id >= p_bic_data->UnitTypeCount)) return false; + + struct district_worker_record * record = get_tracked_worker_record (worker); + if (record == NULL) + return false; + + return record->pending_req == NULL; +} + +Unit * +find_best_worker_for_district (Leader * leader, City * city, int district_id, int target_x, int target_y) +{ + char ss[200]; + + if ((leader == NULL) || (city == NULL)) { + snprintf (ss, sizeof ss, "Invalid leader or city when finding best worker for district %d\n", district_id); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + int civ_id = leader->ID; + if ((civ_id < 0) || (civ_id >= 32)) { + snprintf (ss, sizeof ss, "Invalid civ_id %d when finding best worker for district %d\n", civ_id, district_id); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + if (is->district_worker_tables[civ_id].len == 0) { + snprintf (ss, sizeof ss, "No tracked workers for civ %d when finding best worker for district %d\n", civ_id, district_id); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + Tile * target_tile = tile_at (target_x, target_y); + if ((target_tile == NULL) || (target_tile == p_null_tile)) { + snprintf (ss, sizeof ss, "Invalid target tile (%d,%d) when finding best worker for district %d in city %s\n", + target_x, target_y, district_id, city->Body.CityName); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + int target_continent_id = target_tile->vtable->m46_Get_ContinentID (target_tile); + Unit * best_worker = NULL; + int best_dist = INT_MAX; + + snprintf (ss, sizeof ss, "Finding best worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); + (*p_OutputDebugStringA) (ss); + + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + + if (rec == NULL) { + continue; + } + + Unit * candidate_worker = get_unit_ptr (rec->unit_id); + if ((candidate_worker == NULL) || (candidate_worker->Body.CivID != civ_id)) { + remove_tracked_worker_record (civ_id, rec->unit_id); + continue; + } + rec->worker = candidate_worker; + + if (! worker_is_available_for_district (candidate_worker)) { + continue; + } + + Tile * worker_tile = tile_at (candidate_worker->Body.X, candidate_worker->Body.Y); + if ((worker_tile == NULL) || (worker_tile == p_null_tile)) { + continue; + } + + int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); + if ((target_continent_id >= 0) && (worker_continent_id != target_continent_id)) { + continue; + } + + int dist = compute_wrapped_chebyshev_distance (candidate_worker->Body.X, candidate_worker->Body.Y, target_x, target_y); + + if (dist < best_dist) { + best_worker = candidate_worker; + best_dist = dist; + if (dist == 0) + return best_worker; + } + } + + return best_worker; +} + +void +process_pending_district_request (Leader * leader, struct pending_district_request * req) +{ + if ((leader == NULL) || (req == NULL)) + return; + + City * city = get_city_ptr (req->city_id); + if (city == NULL) { + remove_pending_district_request (req); + return; + } + req->city = city; + + int district_id = req->district_id; + int civ_id = req->civ_id; + + if (city->Body.CivID != civ_id) { + clear_city_district_request (city, district_id); + return; + } + + if (district_id < 0 || district_id >= is->district_count) return; + + // Check if city already has the district if not a neighborhood or distribution hub + if (district_id != NEIGHBORHOOD_DISTRICT_ID && + district_id != DISTRIBUTION_HUB_DISTRICT_ID && + is->district_configs[district_id].allow_multiple == false && + city_has_required_district (city, district_id)) { + + // Clear the request + clear_city_district_request (city, district_id); + return; + } + + // Assigned worker is no longer valid; clear assignment + if (req->assigned_worker_id >= 0) { + Unit * assigned = get_unit_ptr (req->assigned_worker_id); + if (assigned != NULL) { + // Check if more than allowed turns have elapsed since assignment and worker is not at target tile + bool worker_at_target = (assigned->Body.X == req->target_x) && (assigned->Body.Y == req->target_y); + if ((*p_current_turn_no - req->worker_assigned_turn) > is->current_config.ai_city_district_max_build_wait_turns && !worker_at_target) { + clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); + req->assigned_worker_id = -1; + req->worker_assigned_turn = *p_current_turn_no; + } else { + return; + } + } else { + // Assigned worker is null, make sure we get a new one + clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); + req->assigned_worker_id = -1; + } + } + + struct district_instance * inst = NULL; + int target_x = 0; + int target_y = 0; + Tile * tile = find_tile_for_district (city, district_id, &target_x, &target_y); + if ((tile == NULL) || (tile == p_null_tile)) { + clear_city_district_request (city, district_id); + return; + } + wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); + + char ss[200]; + snprintf (ss, sizeof ss, "Assigning worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); + (*p_OutputDebugStringA) (ss); + + Unit * worker = find_best_worker_for_district (leader, city, district_id, target_x, target_y); + if (worker == NULL) + return; + + snprintf (ss, sizeof ss, "Found worker %d for district %d in city %s at (%d,%d)\n", + worker->Body.ID, district_id, city->Body.CityName, target_x, target_y); + (*p_OutputDebugStringA) (ss); + + assign_worker_to_district (req, worker, city, district_id, target_x, target_y); +} + +void +assign_workers_for_pending_districts (Leader * leader) +{ + if ((leader == NULL) || ! is->current_config.enable_districts) + return; + + int civ_id = leader->ID; + if ((civ_id < 0) || (civ_id >= 32)) + return; + + if ((*p_human_player_bits & (1 << civ_id)) != 0) + return; + + int pending_count = is->city_pending_district_requests[civ_id].len; + if (pending_count <= 0) + return; + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req == NULL) + continue; + + City * city = get_city_ptr (req->city_id); + if (city == NULL) { + remove_pending_district_request (req); + continue; + } + + req->city = city; + if (city->Body.CivID != req->civ_id) { + remove_pending_district_request (req); + continue; + } + + process_pending_district_request (leader, req); + } +} + +City * +find_closest_owned_city_for_tile (int civ_id, int tile_x, int tile_y) +{ + City * best_city = NULL; + int best_dist = INT_MAX; + + FOR_CITIES_OF (coi, civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + + int dist = compute_wrapped_chebyshev_distance (city->Body.X, city->Body.Y, tile_x, tile_y); + if (dist < best_dist) { + best_dist = dist; + best_city = city; + } + } + + return best_city; +} + +bool +ai_candidate_bridge_or_canal_is_buildable_for_civ (struct ai_candidate_bridge_or_canal_entry * entry, int civ_id, int * out_tile_index) +{ + if ((entry == NULL) || (entry->tile_count <= 0)) + return false; + + int pending_index = -1; + for (int ti = 0; ti < entry->tile_count; ti++) { + int tx = entry->tile_x[ti]; + int ty = entry->tile_y[ti]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (owner != civ_id) + return false; + if (tile->CityID >= 0) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + if (inst->district_id == entry->district_id) + continue; + if (inst->district_id == WONDER_DISTRICT_ID) + return false; + if (! is->current_config.ai_can_replace_existing_districts_with_canals) { + return false; + } + } + + if (pending_index < 0) + pending_index = ti; + } + + if (pending_index < 0) { + entry->completed = true; + return false; + } + + if (out_tile_index != NULL) + *out_tile_index = pending_index; + + return true; +} + +void +release_ai_candidate_bridge_or_canal_worker (struct ai_candidate_bridge_or_canal_entry * entry) +{ + if ((entry == NULL) || (entry->assigned_worker_id < 0)) + return; + + int civ_id = entry->pending_req.civ_id; + if ((civ_id >= 0) && (civ_id < 32)) + clear_tracked_worker_assignment_by_id (civ_id, entry->assigned_worker_id); + + entry->assigned_worker_id = -1; + entry->assigned_tile_index = -1; + entry->pending_req.city = NULL; + entry->pending_req.city_id = -1; + entry->pending_req.civ_id = -1; + entry->pending_req.district_id = -1; + entry->pending_req.assigned_worker_id = -1; + entry->pending_req.target_x = -1; + entry->pending_req.target_y = -1; + entry->pending_req.worker_assigned_turn = 0; +} + +void +reset_ai_candidate_bridge_or_canals (void) +{ + if (is->ai_candidate_bridge_or_canals != NULL) { + for (int i = 0; i < is->ai_candidate_bridge_or_canals_capacity; i++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[i]; + if (entry->tile_x != NULL) + free (entry->tile_x); + if (entry->tile_y != NULL) + free (entry->tile_y); + } + free (is->ai_candidate_bridge_or_canals); + is->ai_candidate_bridge_or_canals = NULL; + } + is->ai_candidate_bridge_or_canals_capacity = 0; + is->ai_candidate_bridge_or_canals_count = 0; + is->ai_candidate_bridge_or_canals_initialized = false; +} + +bool +tile_has_district_at (int tile_x, int tile_y, int district_id) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + return (inst != NULL) && (inst->district_id == district_id) && (district_is_complete (tile, district_id)); +} + +bool +tile_is_land (int civ_id, int tile_x, int tile_y, bool must_be_same_owner) +{ + if (must_be_same_owner && (civ_id <= 0)) + return false; + + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + return (tile != NULL) && (tile != p_null_tile) && (! tile->vtable->m35_Check_Is_Water (tile)) && + ((! must_be_same_owner) || (tile->Territory_OwnerID == civ_id)); +} + +bool +tile_is_water (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + return (tile != NULL) && (tile != p_null_tile) && (tile->vtable->m35_Check_Is_Water (tile)); +} + +bool +ensure_ai_candidate_bridge_or_canals_capacity (int required) +{ + if (required <= 0) + return true; + if (required <= is->ai_candidate_bridge_or_canals_capacity) + return true; + int new_capacity = (is->ai_candidate_bridge_or_canals_capacity > 0) ? is->ai_candidate_bridge_or_canals_capacity * 2 : 4; + if (new_capacity < required) + new_capacity = required; + struct ai_candidate_bridge_or_canal_entry * larger = (struct ai_candidate_bridge_or_canal_entry *)realloc ( + is->ai_candidate_bridge_or_canals, new_capacity * sizeof *larger); + if (larger == NULL) + return false; + for (int i = is->ai_candidate_bridge_or_canals_capacity; i < new_capacity; i++) { + struct ai_candidate_bridge_or_canal_entry * entry = &larger[i]; + entry->tile_x = NULL; + entry->tile_y = NULL; + entry->tile_capacity = 0; + entry->district_id = -1; + entry->owner_civ_id = -1; + entry->tile_count = 0; + entry->assigned_tile_index = -1; + entry->assigned_worker_id = -1; + entry->completed = false; + struct pending_district_request * req = &entry->pending_req; + req->city = NULL; + req->city_id = -1; + req->civ_id = -1; + req->district_id = -1; + req->assigned_worker_id = -1; + req->target_x = -1; + req->target_y = -1; + req->worker_assigned_turn = 0; + } + is->ai_candidate_bridge_or_canals = larger; + is->ai_candidate_bridge_or_canals_capacity = new_capacity; + return true; +} + +bool +canal_has_different_adjacent_seas (int tile_x, int tile_y, int civ_id) +{ + struct water_pair { + int dx1, dy1; + int dx2, dy2; + }; + + const struct water_pair pairs[] = { + { 1, -1, -1, 1 }, // NE + SW + { 1, 1, -1, -1 }, // SE + NW + }; + + Map * map = &p_bic_data->Map; + bool require_owner = (civ_id >= 0); + + for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { + int ax = tile_x + pairs[i].dx1; + int ay = tile_y + pairs[i].dy1; + wrap_tile_coords (map, &ax, &ay); + Tile * first = tile_at (ax, ay); + if ((first == NULL) || (first == p_null_tile)) + continue; + if (! first->vtable->m35_Check_Is_Water (first)) + continue; + if (require_owner && (first->vtable->m38_Get_Territory_OwnerID (first) != civ_id)) + continue; + + int bx = tile_x + pairs[i].dx2; + int by = tile_y + pairs[i].dy2; + wrap_tile_coords (map, &bx, &by); + Tile * second = tile_at (bx, by); + if ((second == NULL) || (second == p_null_tile)) + continue; + if (! second->vtable->m35_Check_Is_Water (second)) + continue; + if (require_owner && (second->vtable->m38_Get_Territory_OwnerID (second) != civ_id)) + continue; + + int sea_a = first->vtable->m46_Get_ContinentID (first); + int sea_b = second->vtable->m46_Get_ContinentID (second); + if ((sea_a >= 0) && (sea_b >= 0) && (sea_a != sea_b)) + return true; + } + + return false; +} + +// Check if two water tiles can reach each other via water within a radius, excluding a blocked tile +bool +water_tiles_connected_within_radius (int start_x, int start_y, int target_x, int target_y, int block_x, int block_y, int radius) +{ + // Simple BFS using a fixed-size visited array for tiles within radius + // workable_tile_counts[6] = 137 tiles for radius 6 + int max_tiles = 137; + int visited_x[137]; + int visited_y[137]; + int visited_count = 0; + int queue_x[137]; + int queue_y[137]; + int queue_head = 0; + int queue_tail = 0; + + queue_x[queue_tail] = start_x; + queue_y[queue_tail] = start_y; + queue_tail++; + visited_x[visited_count] = start_x; + visited_y[visited_count] = start_y; + visited_count++; + + while (queue_head < queue_tail) { + int cx = queue_x[queue_head]; + int cy = queue_y[queue_head]; + queue_head++; + + // Check 8 adjacent tiles + FOR_TILES_AROUND (tai, 9, cx, cy) { + if (tai.n == 0) + continue; + int nx = tai.tile_x; + int ny = tai.tile_y; + + // Found target + if (nx == target_x && ny == target_y) + return true; + + // Skip blocked tile (the isthmus) + if (nx == block_x && ny == block_y) + continue; + + // Check if within radius of original start + int dx = nx - start_x; + int dy = ny - start_y; + if (dx < 0) dx = -dx; + if (dy < 0) dy = -dy; + // Use Chebyshev distance approximation for hex grid + int dist = (dx + dy + ((dx > dy) ? dx : dy)) / 2; + if (dist > radius) + continue; + + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (! adj->vtable->m35_Check_Is_Water (adj)) + continue; + + // Check if already visited + bool already_visited = false; + for (int i = 0; i < visited_count; i++) { + if (visited_x[i] == nx && visited_y[i] == ny) { + already_visited = true; + break; + } + } + if (already_visited) + continue; + + // Add to queue and visited + if (visited_count < max_tiles && queue_tail < max_tiles) { + visited_x[visited_count] = nx; + visited_y[visited_count] = ny; + visited_count++; + queue_x[queue_tail] = nx; + queue_y[queue_tail] = ny; + queue_tail++; + } + } + } + return false; +} + +// Check if tile separates adjacent water tiles that are not connected within a small radius +bool +canal_has_same_sea_isthmus (int tile_x, int tile_y, int civ_id, int check_radius) +{ + // If another canal exists nearby, this isn't a unique isthmus target. + FOR_TILES_AROUND (tai, workable_tile_counts[2], tile_x, tile_y) { + if (tai.n == 0) + continue; + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + continue; + struct district_instance * adj_inst = get_district_instance (adj); + if ((adj_inst != NULL) && (adj_inst->district_id == CANAL_DISTRICT_ID)) + return false; + } + + // Check opposite diagonal water tiles that are not connected within radius 2 + struct water_pair { + int dx1, dy1; + int dx2, dy2; + }; + + const struct water_pair pairs[] = { + { 1, -1, -1, 1 }, // NE + SW + { 1, 1, -1, -1 }, // SE + NW + }; + + for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { + int ax = tile_x + pairs[i].dx1; + int ay = tile_y + pairs[i].dy1; + wrap_tile_coords (&p_bic_data->Map, &ax, &ay); + Tile * first = tile_at (ax, ay); + if ((first == NULL) || (first == p_null_tile)) + continue; + if (! first->vtable->m35_Check_Is_Water (first)) + continue; + + int bx = tile_x + pairs[i].dx2; + int by = tile_y + pairs[i].dy2; + wrap_tile_coords (&p_bic_data->Map, &bx, &by); + Tile * second = tile_at (bx, by); + if ((second == NULL) || (second == p_null_tile)) + continue; + if (! second->vtable->m35_Check_Is_Water (second)) + continue; + + if (! water_tiles_connected_within_radius ( + ax, ay, + bx, by, + tile_x, tile_y, 2)) { + return true; + } + } + return false; +} + +bool +bridge_tile_connects_two_continents (int tile_x, int tile_y, int civ_id) +{ + struct bridge_pair { + int dx1, dy1; + int dx2, dy2; + }; + + Map * map = &p_bic_data->Map; + const struct bridge_pair pairs[] = { + {0, -2, 0, 2}, + {-2, 0, 2, 0}, + {-1, -1, 1, 1}, + {-1, 1, 1, -1}, + }; + + bool require_owner = (civ_id >= 0); + + for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { + int ax = tile_x + pairs[i].dx1; + int ay = tile_y + pairs[i].dy1; + wrap_tile_coords (map, &ax, &ay); + if (! tile_is_land (civ_id, ax, ay, require_owner)) + continue; + Tile * first = tile_at (ax, ay); + if ((first == NULL) || (first == p_null_tile)) + continue; + + int bx = tile_x + pairs[i].dx2; + int by = tile_y + pairs[i].dy2; + wrap_tile_coords (map, &bx, &by); + if (! tile_is_land (civ_id, bx, by, require_owner)) + continue; + Tile * second = tile_at (bx, by); + if ((second == NULL) || (second == p_null_tile)) + continue; + + int cont_a = first->vtable->m46_Get_ContinentID (first); + int cont_b = second->vtable->m46_Get_ContinentID (second); + if ((cont_a >= 0) && (cont_b >= 0) && (cont_a != cont_b)) + return true; + } + + return false; +} + +bool +tile_point_in_block (int tile_x, int tile_y, int block_x0, int block_y0, int block_x1, int block_y1) +{ + return (tile_x >= block_x0) && (tile_x < block_x1) && (tile_y >= block_y0) && (tile_y < block_y1); +} + +bool +tile_is_coastal_water (int tile_x, int tile_y) +{ + Map * map = &p_bic_data->Map; + wrap_tile_coords (map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + if (! tile->vtable->m35_Check_Is_Water (tile)) + return false; + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + return base_type == SQ_Coast; +} + +bool +tile_exists_at (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + return (tile != NULL) && (tile != p_null_tile); +} + +bool +tile_is_reserved_in_district_tile_map (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + int existing = 0; + return itable_look_up (&is->district_tile_map, (int)tile, &existing); +} + +bool +tile_has_diagonal_water (int tile_x, int tile_y) +{ + Map * map = &p_bic_data->Map; + int const adj_dx[4] = { 1, 1, -1, -1 }; + int const adj_dy[4] = { -1, 1, -1, 1 }; + + for (int i = 0; i < 4; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * tile = tile_at (nx, ny); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m35_Check_Is_Water (tile)) + return true; + } + return false; +} + +bool +tile_part_of_existing_candidate (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if (entry->tile_count <= 0) + continue; + for (int ti = 0; ti < entry->tile_count; ti++) { + if ((entry->tile_x[ti] == tile_x) && (entry->tile_y[ti] == tile_y)) + return true; + } + } + return false; +} + +bool +tile_has_bridge_or_canal_nearby (int tile_x, int tile_y) +{ + FOR_TILES_AROUND (tai, workable_tile_counts[1], tile_x, tile_y) { + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + continue; + struct district_instance * inst = get_district_instance (adj); + if ((inst != NULL) && + ((inst->district_id == BRIDGE_DISTRICT_ID) || (inst->district_id == CANAL_DISTRICT_ID))) + return true; + if (tile_part_of_existing_candidate (tai.tile_x, tai.tile_y)) + return true; + } + return false; +} + +bool +add_ai_candidate_entry (int district_id, short owner_civ_id, short * xs, short * ys, int count) +{ + if (count <= 0) + return false; + if (! ensure_ai_candidate_bridge_or_canals_capacity (is->ai_candidate_bridge_or_canals_count + 1)) + return false; + + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[is->ai_candidate_bridge_or_canals_count]; + entry->tile_x = (short *)malloc (sizeof *entry->tile_x * count); + entry->tile_y = (short *)malloc (sizeof *entry->tile_y * count); + if ((entry->tile_x == NULL) || (entry->tile_y == NULL)) { + if (entry->tile_x != NULL) + free (entry->tile_x); + if (entry->tile_y != NULL) + free (entry->tile_y); + return false; + } + + entry->district_id = district_id; + entry->owner_civ_id = owner_civ_id; + entry->tile_count = (short)count; + entry->tile_capacity = count; + entry->assigned_tile_index = -1; + entry->assigned_worker_id = -1; + entry->completed = false; + for (int ti = 0; ti < count; ti++) { + entry->tile_x[ti] = xs[ti]; + entry->tile_y[ti] = ys[ti]; + } + + struct pending_district_request * req = &entry->pending_req; + req->city = NULL; + req->city_id = -1; + req->civ_id = owner_civ_id; + req->district_id = district_id; + req->assigned_worker_id = -1; + req->target_x = -1; + req->target_y = -1; + req->worker_assigned_turn = 0; + + is->ai_candidate_bridge_or_canals_count++; + return true; +} + +int +find_bridge_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, + int contiguous_limit, int candidate_capacity, + short * out_x, short * out_y, short * out_owner) +{ + const int dirs[4][2] = { + { 0, -2 }, { -2, 0 }, { -1, -1 }, { -1, 1 } + }; + + int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + if (candidate_capacity > 0 && max_len > candidate_capacity) + max_len = candidate_capacity; + + for (int length = 1; length <= max_len; length++) { + for (int ti = 0; ti < map->TileCount; ti++) { + int tx = -1; + int ty = -1; + tile_index_to_coords (map, ti, &tx, &ty); + if (! tile_point_in_block (tx, ty, block_x0, block_y0, block_x1, block_y1)) + continue; + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile_has_resource (tile)) + continue; + if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], tile)) + continue; + if (tile_is_reserved_in_district_tile_map (tx, ty)) + continue; + short owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + for (int di = 0; di < (int)(sizeof (dirs) / sizeof (dirs[0])); di++) { + int dx = dirs[di][0]; + int dy = dirs[di][1]; + int end_x = tx + dx * (length - 1); + int end_y = ty + dy * (length - 1); + wrap_tile_coords (map, &end_x, &end_y); + if (! tile_point_in_block (end_x, end_y, block_x0, block_y0, block_x1, block_y1)) + continue; + + bool ok = true; + for (int step = 0; step < length; step++) { + int cx = tx + dx * step; + int cy = ty + dy * step; + wrap_tile_coords (map, &cx, &cy); + if (! tile_point_in_block (cx, cy, block_x0, block_y0, block_x1, block_y1)) { + ok = false; + break; + } + if (! tile_exists_at (cx, cy)) { + ok = false; + break; + } + if (! tile_is_coastal_water (cx, cy)) { + ok = false; + break; + } + Tile * bridge_tile = tile_at (cx, cy); + if ((bridge_tile == NULL) || (bridge_tile == p_null_tile)) { + ok = false; + break; + } + if (tile_has_resource (bridge_tile)) { + ok = false; + break; + } + if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], bridge_tile)) { + ok = false; + break; + } + if (tile_has_bridge_or_canal_nearby (cx, cy)) { + ok = false; + break; + } + if (tile_is_reserved_in_district_tile_map (cx, cy)) { + ok = false; + break; + } + if (tile_part_of_existing_candidate (cx, cy)) { + ok = false; + break; + } + } + if (! ok) + continue; + + int land_ax = tx - dx; + int land_ay = ty - dy; + wrap_tile_coords (map, &land_ax, &land_ay); + if (! tile_point_in_block (land_ax, land_ay, block_x0, block_y0, block_x1, block_y1)) + continue; + if (! tile_exists_at (land_ax, land_ay)) + continue; + if (! tile_is_land (-1, land_ax, land_ay, false)) + continue; + Tile * land_a = tile_at (land_ax, land_ay); + if ((land_a == NULL) || (land_a == p_null_tile)) + continue; + + int land_bx = tx + dx * length; + int land_by = ty + dy * length; + wrap_tile_coords (map, &land_bx, &land_by); + if (! tile_point_in_block (land_bx, land_by, block_x0, block_y0, block_x1, block_y1)) + continue; + if (! tile_exists_at (land_bx, land_by)) + continue; + if (! tile_is_land (-1, land_bx, land_by, false)) + continue; + Tile * land_b = tile_at (land_bx, land_by); + if ((land_b == NULL) || (land_b == p_null_tile)) + continue; + + int cont_a = land_a->vtable->m46_Get_ContinentID (land_a); + int cont_b = land_b->vtable->m46_Get_ContinentID (land_b); + if ((cont_a < 0) || (cont_b < 0) || (cont_a == cont_b)) + continue; + + for (int step = 0; step < length; step++) { + int cx = tx + dx * step; + int cy = ty + dy * step; + wrap_tile_coords (map, &cx, &cy); + out_x[step] = (short)cx; + out_y[step] = (short)cy; + } + *out_owner = owner; + return length; + } + } + } + return 0; +} + +int +gather_canal_line (int start_x, int start_y, int dx, int dy, int limit, + int block_x0, int block_y0, int block_x1, int block_y1, + short * out_x, short * out_y) +{ + int effective_limit = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, limit); + + if (! tile_is_land (-1, start_x, start_y, false)) + return 0; + if (tile_part_of_existing_candidate (start_x, start_y)) + return 0; + + short back_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + short back_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + short forward_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + short forward_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + int back_count = 0; + int forward_count = 0; + int remaining = effective_limit - 1; + Map * map = &p_bic_data->Map; + + int cx = start_x; + int cy = start_y; + while ((remaining > 0) && (back_count < effective_limit)) { + int nx = cx - dx; + int ny = cy - dy; + wrap_tile_coords (map, &nx, &ny); + if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) + break; + if (! tile_is_land (-1, nx, ny, false)) + break; + if (tile_part_of_existing_candidate (nx, ny)) + break; + back_x[back_count] = (short)nx; + back_y[back_count] = (short)ny; + back_count++; + remaining--; + cx = nx; + cy = ny; + } + + cx = start_x; + cy = start_y; + while ((remaining > 0) && (forward_count < effective_limit)) { + int nx = cx + dx; + int ny = cy + dy; + wrap_tile_coords (map, &nx, &ny); + if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) + break; + if (! tile_is_land (-1, nx, ny, false)) + break; + if (tile_part_of_existing_candidate (nx, ny)) + break; + forward_x[forward_count] = (short)nx; + forward_y[forward_count] = (short)ny; + forward_count++; + remaining--; + cx = nx; + cy = ny; + } + + int write = 0; + for (int bi = back_count - 1; bi >= 0; bi--) { + out_x[write] = back_x[bi]; + out_y[write] = back_y[bi]; + write++; + } + out_x[write] = (short)start_x; + out_y[write] = (short)start_y; + write++; + for (int fi = 0; fi < forward_count; fi++) { + out_x[write] = forward_x[fi]; + out_y[write] = forward_y[fi]; + write++; + } + + return write; +} + +bool +cluster_connects_two_seas_or_isthmus (short * xs, short * ys, int count) +{ + for (int i = 0; i < count; i++) { + if (canal_has_different_adjacent_seas (xs[i], ys[i], -1)) + return true; + if (canal_has_same_sea_isthmus (xs[i], ys[i], -1, 2)) + return true; + } + return false; +} + +int +find_canal_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, + int contiguous_limit, int candidate_capacity, + short * out_x, short * out_y, short * out_owner) +{ + const int dir_dx[8] = { 0, 1, 2, 1, 0, -1, -2, -1 }; + const int dir_dy[8] = { -2, -1, 0, 1, 2, 1, 0, -1 }; + + int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + if (candidate_capacity > 0 && max_len > candidate_capacity) + max_len = candidate_capacity; + + int tile_count = map->TileCount; + int * visit = (int *)malloc (sizeof (*visit) * tile_count); + int * queue_x = (int *)malloc (sizeof (*queue_x) * tile_count); + int * queue_y = (int *)malloc (sizeof (*queue_y) * tile_count); + if ((visit == NULL) || (queue_x == NULL) || (queue_y == NULL)) { + if (visit != NULL) + free (visit); + if (queue_x != NULL) + free (queue_x); + if (queue_y != NULL) + free (queue_y); + return 0; + } + for (int i = 0; i < tile_count; i++) + visit[i] = 0; + + int visit_mark = 1; + + for (int length = 1; length <= max_len; length++) { + for (int ti = 0; ti < map->TileCount; ti++) { + int start_x = -1; + int start_y = -1; + tile_index_to_coords (map, ti, &start_x, &start_y); + if (! tile_point_in_block (start_x, start_y, block_x0, block_y0, block_x1, block_y1)) + continue; + if (! tile_is_land (-1, start_x, start_y, false)) + continue; + if (tile_part_of_existing_candidate (start_x, start_y)) + continue; + if (tile_has_bridge_or_canal_nearby (start_x, start_y)) + continue; + if (tile_is_reserved_in_district_tile_map (start_x, start_y)) + continue; + Tile * start_tile = tile_at (start_x, start_y); + if ((start_tile == NULL) || (start_tile == p_null_tile)) + continue; + if (tile_has_resource (start_tile)) + continue; + if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], start_tile)) + continue; + int continent_id = start_tile->vtable->m46_Get_ContinentID (start_tile); + if (continent_id < 0) + continue; + short owner = start_tile->vtable->m38_Get_Territory_OwnerID (start_tile); + + int stack_len = 1; + int dir_stack[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + int path_dir[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + out_x[0] = (short)start_x; + out_y[0] = (short)start_y; + dir_stack[0] = -1; + path_dir[0] = -1; + + while (stack_len > 0) { + int depth = stack_len - 1; + int cx = out_x[depth]; + int cy = out_y[depth]; + + if (depth + 1 == length) { + bool endpoints_ok = false; + if (length == 1) { + int ex = out_x[0]; + int ey = out_y[0]; + bool pair_ok = false; + if (tile_is_water (ex, ey - 2) && tile_is_water (ex, ey + 2)) pair_ok = true; + if (tile_is_water (ex - 2, ey) && tile_is_water (ex + 2, ey)) pair_ok = true; + if (tile_is_water (ex - 1, ey - 1) && tile_is_water (ex + 1, ey + 1)) pair_ok = true; + if (tile_is_water (ex - 1, ey + 1) && tile_is_water (ex + 1, ey - 1)) pair_ok = true; + if (pair_ok && tile_has_diagonal_water (ex, ey)) + endpoints_ok = true; + } else { + int first_dir = path_dir[1]; + int last_dir = path_dir[length - 1]; + int sx = out_x[0]; + int sy = out_y[0]; + int ex = out_x[length - 1]; + int ey = out_y[length - 1]; + bool start_water = tile_is_water (sx - dir_dx[first_dir], sy - dir_dy[first_dir]); + bool end_water = tile_is_water (ex + dir_dx[last_dir], ey + dir_dy[last_dir]); + if (start_water && end_water && + tile_has_diagonal_water (sx, sy) && + tile_has_diagonal_water (ex, ey)) + endpoints_ok = true; + } + + bool buildable = true; + if (endpoints_ok) { + for (int pi = 0; pi < length; pi++) { + Tile * path_tile = tile_at (out_x[pi], out_y[pi]); + if ((path_tile == NULL) || (path_tile == p_null_tile) || + tile_has_resource (path_tile) || + (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], path_tile)) || + tile_is_reserved_in_district_tile_map (out_x[pi], out_y[pi])) { + buildable = false; + break; + } + if (tile_has_bridge_or_canal_nearby (out_x[pi], out_y[pi])) { + buildable = false; + break; + } + } + } else { + buildable = false; + } + + if (buildable) { + // Collect adjacent land tiles for component checks + int adj_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; + int adj_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; + int adj_count = 0; + for (int pi = 0; pi < length; pi++) { + int px = out_x[pi]; + int py = out_y[pi]; + for (int di = 0; di < 8; di++) { + int nx = px + dir_dx[di]; + int ny = py + dir_dy[di]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_is_land (-1, nx, ny, false)) + continue; + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) + continue; + bool in_path = false; + for (int pj = 0; pj < length; pj++) { + if ((out_x[pj] == nx) && (out_y[pj] == ny)) { + in_path = true; + break; + } + } + if (in_path) + continue; + bool seen = false; + for (int aj = 0; aj < adj_count; aj++) { + if ((adj_x[aj] == nx) && (adj_y[aj] == ny)) { + seen = true; + break; + } + } + if (! seen && (adj_count < (int)(sizeof (adj_x) / sizeof (adj_x[0])))) { + adj_x[adj_count] = nx; + adj_y[adj_count] = ny; + adj_count++; + } + } + } + + if (adj_count >= 2) { + int best1 = 0; + int best2 = 0; + int min_land = is->current_config.ai_canal_eval_min_bisected_land_tiles; + if (min_land < 1) + min_land = 1; + visit_mark++; + if (visit_mark == 0) { + visit_mark = 1; + for (int i = 0; i < tile_count; i++) + visit[i] = 0; + } + + for (int ai = 0; ai < adj_count; ai++) { + int aidx = tile_coords_to_index (map, adj_x[ai], adj_y[ai]); + if ((aidx < 0) || (visit[aidx] == visit_mark)) + continue; + + int comp_size = 0; + int head = 0; + int tail = 0; + visit[aidx] = visit_mark; + queue_x[tail] = adj_x[ai]; + queue_y[tail] = adj_y[ai]; + tail++; + + while (head < tail) { + int qx = queue_x[head]; + int qy = queue_y[head]; + head++; + comp_size++; + for (int di = 0; di < 8; di++) { + int nx = qx + dir_dx[di]; + int ny = qy + dir_dy[di]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_is_land (-1, nx, ny, false)) + continue; + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) + continue; + bool blocked = false; + for (int pj = 0; pj < length; pj++) { + if ((out_x[pj] == nx) && (out_y[pj] == ny)) { + blocked = true; + break; + } + } + if (blocked) + continue; + int nidx = tile_coords_to_index (map, nx, ny); + if ((nidx < 0) || (visit[nidx] == visit_mark)) + continue; + visit[nidx] = visit_mark; + queue_x[tail] = nx; + queue_y[tail] = ny; + tail++; + } + } + + if (comp_size > best1) { + best2 = best1; + best1 = comp_size; + } else if (comp_size > best2) { + best2 = comp_size; + } + } + + if ((best1 >= min_land) && (best2 >= min_land)) { + *out_owner = owner; + free (visit); + free (queue_x); + free (queue_y); + return length; + } + } + } + dir_stack[depth] = -1; + stack_len--; + continue; + } + + int next_dir = dir_stack[depth] + 1; + bool advanced = false; + while (next_dir < 8) { + int ndx = dir_dx[next_dir]; + int ndy = dir_dy[next_dir]; + int nx = cx + ndx; + int ny = cy + ndy; + wrap_tile_coords (map, &nx, &ny); + dir_stack[depth] = next_dir; + + if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) { + next_dir++; + continue; + } + if (! tile_is_land (-1, nx, ny, false)) { + next_dir++; + continue; + } + if (tile_part_of_existing_candidate (nx, ny)) { + next_dir++; + continue; + } + if (tile_is_reserved_in_district_tile_map (nx, ny)) { + next_dir++; + continue; + } + Tile * next_tile = tile_at (nx, ny); + if ((next_tile == NULL) || (next_tile == p_null_tile)) { + next_dir++; + continue; + } + if (tile_has_resource (next_tile)) { + next_dir++; + continue; + } + if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], next_tile)) { + next_dir++; + continue; + } + if (tile_has_bridge_or_canal_nearby (nx, ny)) { + next_dir++; + continue; + } + if (next_tile->vtable->m46_Get_ContinentID (next_tile) != continent_id) { + next_dir++; + continue; + } + bool dup = false; + for (int pi = 0; pi < depth + 1; pi++) { + if ((out_x[pi] == nx) && (out_y[pi] == ny)) { + dup = true; + break; + } + } + if (dup) { + next_dir++; + continue; + } + + if (depth >= 1) { + int prev_dir = dir_stack[depth - 1]; + int diff = next_dir - prev_dir; + if (diff < 0) + diff += 8; + if (diff > 4) + diff = 8 - diff; + if (diff > 1) { + next_dir++; + continue; + } + } + + out_x[depth + 1] = (short)nx; + out_y[depth + 1] = (short)ny; + dir_stack[depth + 1] = -1; + path_dir[depth + 1] = next_dir; + stack_len++; + advanced = true; + break; + } + + if (! advanced) { + dir_stack[depth] = -1; + stack_len--; + } + } + } + } + + free (visit); + free (queue_x); + free (queue_y); + return 0; +} + +void +generate_ai_bridge_candidates_by_block (Map * map, int block_size, int contiguous_limit) +{ + if ((map == NULL) || (block_size <= 0)) + return; + + int width = map->Width; + int height = map->Height; + if ((width <= 0) || (height <= 0)) + return; + + if (block_size < 1) + block_size = 1; + + int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + + short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); + short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); + if ((candidate_x == NULL) || (candidate_y == NULL)) { + if (candidate_x != NULL) + free (candidate_x); + if (candidate_y != NULL) + free (candidate_y); + return; + } + + for (int base_y = 0; base_y < height; base_y += block_size) { + int block_y1 = base_y + block_size; + if (block_y1 > height) + block_y1 = height; + for (int base_x = 0; base_x < width; base_x += block_size) { + int block_x1 = base_x + block_size; + if (block_x1 > width) + block_x1 = width; + short owner = -1; + int count = find_bridge_candidate_in_block ( + map, base_x, base_y, block_x1, block_y1, + contiguous_limit, candidate_capacity, + candidate_x, candidate_y, &owner); + if (count <= 0) + continue; + if (! add_ai_candidate_entry (BRIDGE_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { + free (candidate_x); + free (candidate_y); + return; + } + } + } + + free (candidate_x); + free (candidate_y); +} + +void +generate_ai_canal_candidates_by_block (Map * map, int block_size, int contiguous_limit) +{ + if ((map == NULL) || (block_size <= 0)) + return; + + int width = map->Width; + int height = map->Height; + if ((width <= 0) || (height <= 0)) + return; + + if (block_size < 1) + block_size = 1; + + int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + + short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); + short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); + if ((candidate_x == NULL) || (candidate_y == NULL)) { + if (candidate_x != NULL) + free (candidate_x); + if (candidate_y != NULL) + free (candidate_y); + return; + } + + for (int base_y = 0; base_y < height; base_y += block_size) { + int block_y1 = base_y + block_size; + if (block_y1 > height) + block_y1 = height; + for (int base_x = 0; base_x < width; base_x += block_size) { + int block_x1 = base_x + block_size; + if (block_x1 > width) + block_x1 = width; + short owner = -1; + int count = find_canal_candidate_in_block ( + map, base_x, base_y, block_x1, block_y1, + contiguous_limit, candidate_capacity, + candidate_x, candidate_y, &owner); + if (count <= 0) + continue; + if (! add_ai_candidate_entry (CANAL_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { + free (candidate_x); + free (candidate_y); + return; + } + } + } + + free (candidate_x); + free (candidate_y); +} + +void +generate_ai_canal_and_bridge_targets () +{ + if (is->ai_candidate_bridge_or_canals_initialized) + return; + if ((! is->current_config.enable_canal_districts) && (! is->current_config.enable_bridge_districts)) + return; + + Map * map = &p_bic_data->Map; + int width = map->Width; + int height = map->Height; + if ((width <= 0) || (height <= 0)) + return; + + int block_size = is->current_config.ai_bridge_canal_eval_block_size; + if (block_size <= 0) + block_size = 10; + + if (is->current_config.enable_bridge_districts && is->current_config.ai_builds_bridges) { + generate_ai_bridge_candidates_by_block ( + map, + block_size, + is->current_config.max_contiguous_bridge_districts); + } + + if (is->current_config.enable_canal_districts && is->current_config.ai_builds_canals) { + generate_ai_canal_candidates_by_block ( + map, + block_size, + is->current_config.max_contiguous_canal_districts); + } + + is->ai_candidate_bridge_or_canals_initialized = true; +} + +void +assign_workers_for_ai_candidate_bridge_or_canals (Leader * leader) +{ + if ((leader == NULL) || (is->ai_candidate_bridge_or_canals_count <= 0)) + return; + + int civ_id = leader->ID; + if ((*p_human_player_bits & (1 << civ_id)) != 0) + return; + + if (! leader_can_build_district (leader, CANAL_DISTRICT_ID) && ! leader_can_build_district (leader, BRIDGE_DISTRICT_ID)) + return; + + if (! is->ai_candidate_bridge_or_canals_initialized) { + reset_ai_candidate_bridge_or_canals (); + generate_ai_canal_and_bridge_targets (); + } + + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if (entry->completed) + continue; + + int district_id = entry->district_id; + if ((district_id == CANAL_DISTRICT_ID) && (! is->current_config.enable_canal_districts)) continue; + if ((district_id == BRIDGE_DISTRICT_ID) && (! is->current_config.enable_bridge_districts)) continue; + if (! leader_can_build_district (leader, district_id)) continue; + + if (entry->assigned_worker_id >= 0) { + Unit * worker = get_unit_ptr (entry->assigned_worker_id); + if (worker == NULL) { + release_ai_candidate_bridge_or_canal_worker (entry); + } else if ((entry->assigned_tile_index >= 0) && (entry->assigned_tile_index < entry->tile_count)) { + int tx = entry->tile_x[entry->assigned_tile_index]; + int ty = entry->tile_y[entry->assigned_tile_index]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + Tile * tile = tile_at (tx, ty); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && inst->district_id == district_id && district_is_complete (tile, district_id)) { + release_ai_candidate_bridge_or_canal_worker (entry); + } + } + } + if (entry->assigned_worker_id >= 0) + continue; + } + + int target_idx = -1; + if (! ai_candidate_bridge_or_canal_is_buildable_for_civ (entry, civ_id, &target_idx)) { + release_ai_candidate_bridge_or_canal_worker (entry); + continue; + } + + if (target_idx < 0) + continue; + + City * city = find_closest_owned_city_for_tile (civ_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); + if (city == NULL) + continue; + + Unit * worker = find_best_worker_for_district (leader, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); + if (worker == NULL) + continue; + + memset (&entry->pending_req, 0, sizeof entry->pending_req); + entry->pending_req.district_id = district_id; + entry->pending_req.civ_id = civ_id; + if (! assign_worker_to_district (&entry->pending_req, worker, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx])) + continue; + + entry->assigned_worker_id = worker->Body.ID; + entry->assigned_tile_index = target_idx; + } +} + +void +recompute_city_yields_with_districts (City * city) +{ + if (city == NULL) + return; + + bool prev_flag = is->distribution_hub_refresh_in_progress; + is->distribution_hub_refresh_in_progress = true; + patch_City_recompute_yields_and_happiness (city); + is->distribution_hub_refresh_in_progress = prev_flag; +} + +enum UnitStateType __fastcall +patch_City_instruct_worker (City * this, int edx, int tile_x, int tile_y, bool param_3, Unit * worker) +{ + return City_instruct_worker (this, __, tile_x, tile_y, param_3, worker); +} + +int +find_wonder_config_index_by_improvement_id (int improv_id) +{ + if (improv_id < 0) + return -1; + + char ss[200]; + + for (int wi = 0; wi < is->wonder_district_count; wi++) { + int bid = -1; + if (stable_look_up (&is->building_name_to_id, is->wonder_district_configs[wi].wonder_name, &bid) && + (bid == improv_id)) { + return wi; + } + } + + return -1; +} + +void set_wonder_built_flag (int improv_id, bool is_built); + +unsigned int +wonder_buildable_square_type_mask (struct wonder_district_config const * cfg) +{ + if (cfg == NULL) + return district_default_buildable_mask (); + + unsigned int mask = cfg->buildable_square_types_mask; + if (mask == 0) + mask = district_default_buildable_mask (); + return mask; +} + +unsigned int +wonder_buildable_mask_for_improvement (int improv_id) +{ + int windex = find_wonder_config_index_by_improvement_id (improv_id); + if (windex < 0) + return district_default_buildable_mask (); + return wonder_buildable_square_type_mask (&is->wonder_district_configs[windex]); +} + +bool +wonder_is_buildable_on_square_type (struct wonder_district_config const * cfg, Tile * tile) +{ + if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + if (! tile_matches_square_type_mask (tile, wonder_buildable_square_type_mask (cfg))) + return false; + + if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) + return false; + + if (cfg->has_buildable_adjacent_to) { + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + return false; + + bool matches = false; + bool city_adjacent = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (Tile_has_city (tai.tile)) { + city_adjacent = true; + if (cfg->buildable_adjacent_to_allows_city) + matches = true; + } + if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) + matches = true; + if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) + break; + } + if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) + return false; + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to_overlays) { + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + return false; + + bool matches = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { + matches = true; + break; + } + } + if (! matches) + return false; + } + + return true; +} + +bool +wonder_is_buildable_on_tile (Tile * tile, int wonder_improv_id) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); + if (windex < 0) + return tile_matches_square_type_mask (tile, district_default_buildable_mask ()); + + return wonder_is_buildable_on_square_type (&is->wonder_district_configs[windex], tile); +} + +bool +wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id) +{ + if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) + return false; + if ((civ_id < 0) || (civ_id >= 32)) + return false; + + int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); + if (windex < 0) + return true; + + struct wonder_district_config const * cfg = &is->wonder_district_configs[windex]; + Leader * leader = &leaders[civ_id]; + + if (cfg->has_buildable_by_civs) { + bool civ_match = false; + if (cfg->buildable_by_civ_count > 0) { + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + for (int i = 0; i < cfg->buildable_by_civ_count; i++) { + char const * civ_name = cfg->buildable_by_civs[i]; + if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; + if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; + if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; + if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; + if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; + } + } + if (! civ_match) + return false; + } + + if (cfg->has_buildable_by_civ_traits) { + if (cfg->buildable_by_civ_traits_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL || race->vtable == NULL) + return false; + bool trait_match = false; + for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { + int trait_id = cfg->buildable_by_civ_traits_ids[i]; + if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { + trait_match = true; + break; + } + } + if (! trait_match) + return false; + } + + if (cfg->has_buildable_by_civ_govs) { + if (cfg->buildable_by_civ_govs_id_count <= 0) + return false; + int gov_id = leader->GovernmentType; + bool gov_match = false; + for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { + if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { + gov_match = true; + break; + } + } + if (! gov_match) + return false; + } + + if (cfg->has_buildable_by_civ_cultures) { + if (cfg->buildable_by_civ_cultures_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + int culture_id = race->CultureGroupID; + bool culture_match = false; + for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { + if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { + culture_match = true; + break; + } + } + if (! culture_match) + return false; + } + + return true; +} + +int +get_wonder_improvement_id_from_index (int windex) +{ + if ((windex < 0) || (windex >= is->wonder_district_count)) + return -1; + + char const * wonder_name = is->wonder_district_configs[windex].wonder_name; + if ((wonder_name == NULL) || (wonder_name[0] == '\0')) + return -1; + + int improv_id; + if (stable_look_up (&is->building_name_to_id, (char *)wonder_name, &improv_id)) + return improv_id; + else + return -1; +} + +void +remember_pending_building_order (City * city, int improvement_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (improvement_id < 0)) + return; + + if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) + return; + + itable_insert (&is->city_pending_building_orders, (int)city, improvement_id); +} + +bool +look_up_pending_building_order (City * city, int * out_improv_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (out_improv_id == NULL)) + return false; + + return itable_look_up (&is->city_pending_building_orders, (int)city, out_improv_id); +} + +void +forget_pending_building_order (City * city) +{ + if (! is->current_config.enable_districts || + (city == NULL)) + return; + + itable_remove (&is->city_pending_building_orders, (int)city); +} + +bool +is_wonder_or_small_wonder_already_being_built (City * city, int improv_id) +{ + if ((city == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) + return false; + + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) + return false; + + int civ_id = city->Body.CivID; + FOR_CITIES_OF (coi, civ_id) { + City * other_city = coi.city; + if ((other_city == NULL) || (other_city == city)) + continue; + + if ((other_city->Body.Order_Type == COT_Improvement) && + (other_city->Body.Order_ID == improv_id)) + return true; + } + + return false; +} + +struct district_building_prereq_list * +get_district_building_prereq_list (int improv_id) +{ + if (improv_id < 0) + return NULL; + + int stored = 0; + if (! itable_look_up (&is->district_building_prereqs, improv_id, &stored)) + return NULL; + return (struct district_building_prereq_list *)stored; +} + +bool +district_building_prereq_list_contains (struct district_building_prereq_list * list, int district_id) +{ + if ((list == NULL) || (district_id < 0)) + return false; + for (int i = 0; i < list->count; i++) { + if (list->district_ids[i] == district_id) + return true; + } + return false; +} + +void +add_district_building_prereq (int improv_id, int district_id) +{ + if ((improv_id < 0) || (district_id < 0)) + return; + + struct district_building_prereq_list * list = get_district_building_prereq_list (improv_id); + if (list == NULL) { + list = calloc (1, sizeof *list); + if (list == NULL) + return; + list->count = 0; + itable_insert (&is->district_building_prereqs, improv_id, (int)list); + } + + if (district_building_prereq_list_contains (list, district_id)) + return; + + if (list->count >= ARRAY_LEN (list->district_ids)) + return; + + list->district_ids[list->count++] = district_id; +} + +bool +city_has_river_district (City * city, int district_id) +{ + if (city == NULL) + return false; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if (wai.district_inst->district_id != district_id) + continue; + if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) + return true; + } + return false; +} + +bool +city_has_any_prereq_district_for_improvement (City * city, + struct district_building_prereq_list * list, + bool requires_river, + bool allow_wonder_district) +{ + if ((city == NULL) || (list == NULL)) + return false; + + for (int i = 0; i < list->count; i++) { + int district_id = list->district_ids[i]; + if (district_id < 0) + continue; + if (! allow_wonder_district && district_id == WONDER_DISTRICT_ID) + continue; + if (requires_river) { + if (city_has_river_district (city, district_id)) + return true; + } else if (city_has_required_district (city, district_id)) { + return true; + } + } + return false; +} + +int +pick_missing_district_for_improvement (City * city, struct district_building_prereq_list * list) +{ + if ((list == NULL) || (list->count <= 0)) + return -1; + + int fallback = -1; + for (int i = 0; i < list->count; i++) { + int district_id = list->district_ids[i]; + if (district_id < 0) + continue; + if (fallback < 0) + fallback = district_id; + if ((city != NULL) && leader_can_build_district (&leaders[city->Body.CivID], district_id)) + return district_id; + } + return fallback; +} + + +bool +district_is_complete(Tile * tile, int district_id) +{ + if ((tile == NULL) || (tile == p_null_tile) || + (district_id < 0) || (district_id >= is->district_count)) + return false; + + bool is_natural_wonder = (district_id == NATURAL_WONDER_DISTRICT_ID); + bool districts_disabled = ! is->current_config.enable_districts; + bool natural_wonders_disabled = ! is->current_config.enable_natural_wonders; + struct district_config const * cfg = &is->district_configs[district_id]; + + if (districts_disabled && (!is_natural_wonder || natural_wonders_disabled)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != district_id) + return false; + + // If already marked COMPLETED, just return true + if (inst->state == DS_COMPLETED) + return true; + + // State is UNDER_CONSTRUCTION - check if tile has mines now + bool has_mines = tile->vtable->m18_Check_Mines (tile, __, 0) != 0; + + if (! has_mines) { + // Still under construction - check if we should clean it up + bool worker_present = false; + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit != NULL) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { + worker_present = true; + break; + } + } + if (! worker_present) { + remove_district_instance (tile); + } + return false; + } + + // Mark as completed and run one-time side effects + inst->state = DS_COMPLETED; + inst->completed_turn = *p_current_turn_no; + + int tile_x, tile_y; + if (district_instance_get_coords (inst, tile, &tile_x, &tile_y)) { + set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + if (cfg->auto_add_road) { + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + if (! has_road) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_ROAD, tile_x, tile_y); + } + + if (cfg->auto_add_railroad) { + bool has_railroad = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; + if (! has_railroad) { + if ((territory_owner >= 0) && patch_Leader_can_do_worker_job (&leaders[territory_owner], __, WJ_Build_Railroad, tile_x, tile_y, 0)) { + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_RAILROAD, tile_x, tile_y); + } + } + } + + // Activate distribution hub if applicable + if (is->current_config.enable_distribution_hub_districts && + (district_id == DISTRIBUTION_HUB_DISTRICT_ID)) { + on_distribution_hub_completed (tile, tile_x, tile_y); + } + + // Remove forest/swamp if applicable + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + if ((base_type == SQ_Forest) || (base_type == SQ_Swamp)) { + int new_terrain_type = tile->vtable->m71_Check_Worker_Job (tile); + if (new_terrain_type >= 0) + Map_change_tile_terrain (&p_bic_data->Map, __, (enum SquareTypes)new_terrain_type, tile_x, tile_y); + } + + char ss[200]; + snprintf (ss, sizeof ss, "District %d completed at tile (%d,%d)\n", district_id, tile_x, tile_y); + (*p_OutputDebugStringA) (ss); + + // Check if this was an AI-requested district + struct pending_district_request * req = find_pending_district_request_by_coords (NULL, tile_x, tile_y, district_id); + if (req != NULL) { + City * requesting_city = get_city_ptr (req->city_id); + if (requesting_city != NULL) { + req->city = requesting_city; + snprintf (ss, sizeof ss, "District %d at tile (%d,%d) was ordered by city %s\n", + district_id, tile_x, tile_y, requesting_city->Body.CityName); + (*p_OutputDebugStringA) (ss); + + // Check if city has pending building order that depends on this district + int pending_improv_id; + if (look_up_pending_building_order (requesting_city, &pending_improv_id)) { + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (pending_improv_id); + if (district_building_prereq_list_contains (prereq_list, district_id)) { + snprintf (ss, sizeof ss, "City %s setting production to improvement %d\n", + requesting_city->Body.CityName, pending_improv_id); + (*p_OutputDebugStringA) (ss); + + // Check if another city is already building this wonder/small wonder + bool can_set_production = true; + if (is_wonder_or_small_wonder_already_being_built (requesting_city, pending_improv_id)) { + snprintf (ss, sizeof ss, "City %s cannot build improvement %d - already being built elsewhere\n", + requesting_city->Body.CityName, pending_improv_id); + (*p_OutputDebugStringA) (ss); + can_set_production = false; + } + + // Set city production to the pending improvement + if (can_set_production && City_can_build_improvement (requesting_city, __, pending_improv_id, false)) { + snprintf (ss, sizeof ss, "City %s can now build improvement %d\n", + requesting_city->Body.CityName, pending_improv_id); + (*p_OutputDebugStringA) (ss); + City_set_production (requesting_city, __, COT_Improvement, pending_improv_id, false); + } + + // Clear the pending building order + forget_pending_building_order (requesting_city); + } + } + + // Clear worker assignment so worker is freed up for other tasks + if (req->assigned_worker_id >= 0) { + snprintf (ss, sizeof ss, "Clearing worker assignment for unit %d\n", req->assigned_worker_id); + (*p_OutputDebugStringA) (ss); + int civ_id = req->civ_id; + clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); + } + } + + // Remove the pending district request + remove_pending_district_request (req); + } + } + + return true; +} + +void +mark_city_needs_district (City * city, int district_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (district_id < 0) || (district_id >= is->district_count)) + return; + + create_pending_district_request (city, district_id); +} + +void +set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return; + + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + + City * assigned_city = NULL; + int assigned_city_id = tile->Body.CityAreaID; + if (assigned_city_id >= 0) + assigned_city = get_city_ptr (assigned_city_id); + + if (assigned_city != NULL) { + int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, + assigned_city->Body.X, assigned_city->Body.Y, tile_x, tile_y, 1000); + bool removed_assignment = false; + if ((neighbor_index > 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) + removed_assignment = City_stop_working_tile (assigned_city, __, neighbor_index); + if (! removed_assignment) + tile->Body.CityAreaID = -1; + if (! removed_assignment) + recompute_city_yields_with_districts (assigned_city); + } else + tile->Body.CityAreaID = -1; + + if (p_cities->Cities != NULL) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city == NULL) || (city == assigned_city)) + continue; + int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, + city->Body.X, city->Body.Y, tile_x, tile_y, 1000); + if ((neighbor_index <= 0) || (neighbor_index >= ARRAY_LEN (is->ni_to_work_radius))) + continue; + int work_radius = is->ni_to_work_radius[neighbor_index]; + if ((work_radius < 0) || (work_radius > is->current_config.city_work_radius)) + continue; + recompute_city_yields_with_districts (city); + } + } +} + +struct distribution_hub_record * +get_distribution_hub_record (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + + int stored; + if (itable_look_up (&is->distribution_hub_records, (int)tile, &stored)) + return (struct distribution_hub_record *)stored; + else + return NULL; +} + +City * +get_connected_city_for_distribution_hub (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return NULL; + + Tile * tile = rec->tile; + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + + City * best_city = NULL; + int best_distance = INT_MAX; + int best_y = INT_MAX; + int best_x = INT_MAX; + int best_id = INT_MAX; + + FOR_CITIES_OF (coi, rec->civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, city, rec->tile_x, rec->tile_y)) + continue; + + int distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, city->Body.X, city->Body.Y); + if ((best_city == NULL) || + (distance < best_distance) || + ((distance == best_distance) && (city->Body.Y < best_y)) || + ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X < best_x)) || + ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X == best_x) && (city->Body.ID < best_id))) { + best_city = city; + best_distance = distance; + best_y = city->Body.Y; + best_x = city->Body.X; + best_id = city->Body.ID; + } + } + + return best_city; +} + +bool +distribution_hub_accessible_to_city (struct distribution_hub_record * rec, City * city) +{ + if ((rec == NULL) || (city == NULL)) + return false; + + if (city->Body.CivID != rec->civ_id) + return false; + + City * anchor_city = get_connected_city_for_distribution_hub (rec); + if (anchor_city == NULL) + return false; + + if (anchor_city == city) + return true; + + return Trade_Net_have_trade_connection (is->trade_net, __, anchor_city, city, rec->civ_id); +} + +void +get_distribution_hub_yields_for_city (City * city, int * out_food, int * out_shields) +{ + int food = 0; + int shields = 0; + + if ((city != NULL) && + is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts) { + if (is->distribution_hub_totals_dirty && + ! is->distribution_hub_refresh_in_progress) + recompute_distribution_hub_totals (); + + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (distribution_hub_accessible_to_city (rec, city)) { + food += rec->food_yield; + shields += rec->shield_yield; + } + } + } + + if (city_has_required_district (city, CENTRAL_RAIL_HUB_DISTRICT_ID)) { + food += (food * is->current_config.central_rail_hub_distribution_food_bonus_percent) / 100; + shields += (shields * is->current_config.central_rail_hub_distribution_shield_bonus_percent) / 100; + } + + if (out_food != NULL) + *out_food = food; + if (out_shields != NULL) + *out_shields = shields; +} + +void +adjust_distribution_hub_coverage (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return; + + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if ((area_tile == NULL) || (area_tile == p_null_tile)) + continue; + int tx = tai.tile_x; + int ty = tai.tile_y; + + if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) + continue; + if (Tile_has_city (area_tile)) + continue; + if (get_district_instance (area_tile) != NULL) + continue; + + struct wonder_district_info * area_info = get_wonder_district_info (area_tile); + if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) + continue; + + int key = (int)area_tile; + int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); + itable_insert (&is->distribution_hub_coverage_counts, key, prev + 1); + + if (area_tile->Body.CityAreaID >= 0) { + set_tile_unworkable_for_all_cities (area_tile, tx, ty); + area_tile->Body.CityAreaID = -1; + } + } +} + +void +release_distribution_hub_coverage (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return; + + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if ((area_tile == NULL) || (area_tile == p_null_tile)) + continue; + + int key = (int)area_tile; + int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); + if (prev <= 0) + continue; + + if (prev == 1) + itable_remove (&is->distribution_hub_coverage_counts, key); + else + itable_insert (&is->distribution_hub_coverage_counts, key, prev - 1); + } +} + +void +clear_distribution_hub_tables (void) +{ + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + free (rec); + } + table_deinit (&is->distribution_hub_records); + table_deinit (&is->distribution_hub_coverage_counts); + is->distribution_hub_totals_dirty = true; +} + +bool +city_radius_contains_tile (City * city, int tile_x, int tile_y) +{ + if (city == NULL) + return false; + + int ni = patch_Map_compute_ni_for_work_area (&p_bic_data->Map, __, city->Body.X, city->Body.Y, tile_x, tile_y, is->workable_tile_count); + return ni >= 0; +} + +void +recompute_distribution_hub_yields (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return; + + Tile * tile = tile_at (rec->tile_x, rec->tile_y); + rec->tile = tile; + + if ((tile == NULL) || + (tile == p_null_tile) || + ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID) || + tile->vtable->m20_Check_Pollution (tile, __, 0) || + tile_has_enemy_unit (tile, rec->civ_id)) { + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + return; + } + + int food_sum = 0; + int shield_sum = 0; + City * anchor_city = get_connected_city_for_distribution_hub (rec); + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if (area_tile == p_null_tile) + continue; + int tx = tai.tile_x; + int ty = tai.tile_y; + + // Only include tiles that belong to the distribution hub owner + if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) + continue; + + // Skip city tiles + if (Tile_has_city (area_tile)) + continue; + + // Skip tiles with enemy units + if (tile_has_enemy_unit (area_tile, rec->civ_id)) + continue; + + // Skip tiles with pollution + if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) + continue; + + // Skip tiles that are other districts (but not this hub itself) + struct district_instance * area_district = get_district_instance (area_tile); + if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) + continue; + + // Skip tiles with completed wonders + struct wonder_district_info * area_info = get_wonder_district_info (area_tile); + if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) + continue; + + // Check if another hub of the same civ is closer to this tile + int my_distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, tx, ty); + bool tile_belongs_to_me = true; + + FOR_TABLE_ENTRIES (other_tei, &is->distribution_hub_records) { + struct distribution_hub_record * other_rec = (struct distribution_hub_record *)other_tei.value; + if ((other_rec == NULL) || (other_rec == rec)) + continue; + if (other_rec->civ_id != rec->civ_id) + continue; + + int other_distance = compute_wrapped_manhattan_distance (other_rec->tile_x, other_rec->tile_y, tx, ty); + if (other_distance < my_distance) { + tile_belongs_to_me = false; + break; + } + if (other_distance == my_distance) { + // Tie-breaking: prefer hub with lower Y, then lower X + if (other_rec->tile_y < rec->tile_y) { + tile_belongs_to_me = false; + break; + } + if ((other_rec->tile_y == rec->tile_y) && (other_rec->tile_x < rec->tile_x)) { + tile_belongs_to_me = false; + break; + } + } + } + + if (! tile_belongs_to_me) + continue; + + food_sum += City_calc_tile_yield_at (anchor_city, __, 0, tx, ty); + shield_sum += City_calc_tile_yield_at (anchor_city, __, 1, tx, ty); + } + + rec->raw_food_yield = food_sum; + rec->raw_shield_yield = shield_sum; + + int food_div = is->current_config.distribution_hub_food_yield_divisor; + int shield_div = is->current_config.distribution_hub_shield_yield_divisor; + if (food_div <= 0) + food_div = 1; + if (shield_div <= 0) + shield_div = 1; + + int connected_city_count = 0; + if (anchor_city != NULL) { + FOR_CITIES_OF (coi, rec->civ_id) { + City * other_city = coi.city; + if ((other_city != NULL) && distribution_hub_accessible_to_city (rec, other_city)) + connected_city_count++; + } + } + if (connected_city_count <= 0) + connected_city_count = 1; + + if (is->current_config.distribution_hub_yield_division_mode == DHYDM_SCALE_BY_CITY_COUNT) { + int city_root = 1; + while ((city_root + 1) * (city_root + 1) <= connected_city_count) + city_root++; + int city_food_divisor = city_root * food_div; + int city_shield_divisor = city_root * shield_div; + if (city_food_divisor < 1) city_food_divisor = 1; + if (city_shield_divisor < 1) city_shield_divisor = 1; + rec->food_yield = food_sum / city_food_divisor; + rec->shield_yield = shield_sum / city_shield_divisor; + } else { + rec->food_yield = food_sum / food_div; + rec->shield_yield = shield_sum / shield_div; + } +} + +void +remove_distribution_hub_record (Tile * tile) +{ + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec == NULL) + return; + + int affected_civ_id = rec->civ_id; + release_distribution_hub_coverage (rec); + itable_remove (&is->distribution_hub_records, (int)tile); + free (rec); + is->distribution_hub_totals_dirty = true; + recompute_distribution_hub_totals (); + + // Recalculate yields for all cities of this civ + if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * target_city = get_city_ptr (city_index); + if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) + recompute_city_yields_with_districts (target_city); + } + } +} + +void +recompute_distribution_hub_totals () +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_distribution_hub_districts) { + is->distribution_hub_totals_dirty = false; + return; + } + + struct table new_coverage_counts = {0}; + struct table newly_covered_tiles = {0}; + + clear_memo (); + int civs_needing_recalc[32] = {0}; + + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + Tile * tile = (Tile *)tei.key; + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (rec == NULL) + continue; + + Tile * current_tile = tile_at (rec->tile_x, rec->tile_y); + if ((current_tile == NULL) || + (current_tile == p_null_tile) || + ! district_is_complete (current_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { + memoize (tei.key); + continue; + } + + rec->tile = current_tile; + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + + int old_civ_id = rec->civ_id; + rec->civ_id = current_tile->vtable->m38_Get_Territory_OwnerID (current_tile); + + if (old_civ_id != rec->civ_id) + civs_needing_recalc[old_civ_id] = 1; + civs_needing_recalc[rec->civ_id] = 1; + + City * anchor = get_connected_city_for_distribution_hub (rec); + + if ((anchor == NULL) || + current_tile->vtable->m20_Check_Pollution (current_tile, __, 0) || + tile_has_enemy_unit (current_tile, rec->civ_id)) + continue; + + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if (area_tile == p_null_tile) + continue; + int tx = tai.tile_x; + int ty = tai.tile_y; + + if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) + continue; + if (Tile_has_city (area_tile)) + continue; + if (tile_has_enemy_unit (area_tile, rec->civ_id)) + continue; + if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) + continue; + + struct district_instance * area_district = get_district_instance (area_tile); + if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) + continue; + + struct wonder_district_info * area_info = get_wonder_district_info (area_tile); + if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) + continue; + + int key = (int)area_tile; + int prev_cover_pass = itable_look_up_or (&new_coverage_counts, key, 0); + int prev_cover_old = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); + itable_insert (&new_coverage_counts, key, prev_cover_pass + 1); + if ((prev_cover_pass == 0) && (prev_cover_old <= 0)) + itable_insert (&newly_covered_tiles, key, 1); + } + } + + for (int i = 0; i < is->memo_len; i++) + remove_distribution_hub_record ((Tile *)is->memo[i]); + clear_memo (); + + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (rec == NULL) + continue; + + City * anchor = get_connected_city_for_distribution_hub (rec); + if (anchor == NULL) { + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + continue; + } + + recompute_distribution_hub_yields (rec); + } + + table_deinit (&is->distribution_hub_coverage_counts); + is->distribution_hub_coverage_counts = new_coverage_counts; + memset (&new_coverage_counts, 0, sizeof new_coverage_counts); + + FOR_TABLE_ENTRIES (tei, &newly_covered_tiles) { + Tile * covered_tile = (Tile *)tei.key; + if ((covered_tile == NULL) || (covered_tile == p_null_tile)) + continue; + int tx, ty; + if (! tile_coords_from_ptr (&p_bic_data->Map, covered_tile, &tx, &ty)) + continue; + set_tile_unworkable_for_all_cities (covered_tile, tx, ty); + covered_tile->Body.CityAreaID = -1; + } + table_deinit (&newly_covered_tiles); + + // Recalculate yields for cities of civs whose distribution hub ownership changed + for (int civ_id = 0; civ_id < 32; civ_id++) { + if (civs_needing_recalc[civ_id] && (p_cities->Cities != NULL)) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city != NULL) && (city->Body.CivID == civ_id)) + recompute_city_yields_with_districts (city); + } + } + } + + is->distribution_hub_totals_dirty = false; +} + +void +on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y) +{ + if (! is->current_config.enable_districts || ! is->current_config.enable_distribution_hub_districts) + return; + + int tile_owner = -1; + if ((tile != NULL) && (tile != p_null_tile)) + tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec != NULL) { + int old_civ_id = rec->civ_id; + rec->tile = tile; + rec->tile_x = tile_x; + rec->tile_y = tile_y; + + release_distribution_hub_coverage (rec); + rec->civ_id = tile_owner; + is->distribution_hub_totals_dirty = true; + recompute_distribution_hub_totals (); + + if (old_civ_id != tile_owner) { + // Recompute for old civ + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * target_city = get_city_ptr (city_index); + if ((target_city != NULL) && (target_city->Body.CivID == old_civ_id)) + recompute_city_yields_with_districts (target_city); + } + } + } + + rec = malloc (sizeof *rec); + if (rec == NULL) + return; + rec->tile = tile; + rec->tile_x = tile_x; + rec->tile_y = tile_y; + rec->civ_id = tile_owner; + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + itable_insert (&is->distribution_hub_records, (int)tile, (int)rec); + adjust_distribution_hub_coverage (rec); + + is->distribution_hub_totals_dirty = true; + recompute_distribution_hub_totals (); + + // Recalculate yields for all cities of this civ + int affected_civ_id = rec->civ_id; + if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * target_city = get_city_ptr (city_index); + if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) + recompute_city_yields_with_districts (target_city); + } + } +} + +void +refresh_distribution_hubs_for_city (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_distribution_hub_districts || + (city == NULL)) + return; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int tx = wai.tile_x, ty = wai.tile_y; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID) + continue; + on_distribution_hub_completed (tile, tx, ty); + } +} + +bool +is_space_char (char c) +{ + switch (c) { + case ' ': + case '\t': + case '\n': + case '\r': + case '\f': + case '\v': + return true; + default: + return false; + } +} + +enum key_value_parse_status { + KVP_SUCCESS, + KVP_NO_EQUALS, + KVP_EMPTY_KEY +}; + +enum key_value_parse_status +parse_trimmed_key_value (struct string_slice const * trimmed, + struct string_slice * out_key, + struct string_slice * out_value) +{ + if ((trimmed == NULL) || (trimmed->len <= 0)) + return KVP_NO_EQUALS; + + char * equals = NULL; + for (int i = 0; i < trimmed->len; i++) { + if (trimmed->str[i] == '=') { + equals = trimmed->str + i; + break; + } + } + if (equals == NULL) + return KVP_NO_EQUALS; + + struct string_slice key = { .str = trimmed->str, .len = (int)(equals - trimmed->str) }; + key = trim_string_slice (&key, 0); + if (key.len == 0) + return KVP_EMPTY_KEY; + + struct string_slice value = { .str = equals + 1, .len = (int)((trimmed->str + trimmed->len) - (equals + 1)) }; + *out_key = key; + *out_value = trim_string_slice (&value, 0); + return KVP_SUCCESS; +} + +void +add_key_parse_error (struct error_line ** parse_errors, + int line_number, + struct string_slice const * key, + struct string_slice const * value, + char const * message_suffix) +{ + struct error_line * err = add_error_line (parse_errors); + char * key_str = extract_slice (key); + char * value_str = (value != NULL) ? extract_slice (value) : NULL; + if (value_str != NULL) + snprintf (err->text, sizeof err->text, "^ Line %d: %s \"%s\" %s", line_number, key_str, value_str, message_suffix); + else + snprintf (err->text, sizeof err->text, "^ Line %d: %s %s", line_number, key_str, message_suffix); + err->text[(sizeof err->text) - 1] = '\0'; + if (value_str != NULL) + free (value_str); + free (key_str); +} + +void +add_unrecognized_key_error (struct error_line ** unrecognized_keys, + int line_number, + struct string_slice const * key) +{ + struct error_line * err_line = add_error_line (unrecognized_keys); + char * key_str = extract_slice (key); + snprintf (err_line->text, sizeof err_line->text, "^ Line %d: %s", line_number, key_str); + err_line->text[(sizeof err_line->text) - 1] = '\0'; + free (key_str); +} + +char * +copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes) +{ + struct string_slice trimmed = trim_string_slice (slice, remove_quotes); + if (trimmed.len == 0) + return NULL; + return extract_slice (&trimmed); +} + +void +free_bonus_entry_list (struct district_bonus_list * list) +{ + if (list == NULL) + return; + + for (int i = 0; i < list->count; i++) { + if (list->entries[i].type == DBET_BUILDING && + list->entries[i].building_name != NULL) { + free ((void *)list->entries[i].building_name); + list->entries[i].building_name = NULL; + } + } + list->count = 0; +} + +void +free_bonus_entry_list_override (struct district_bonus_list * list, + struct district_bonus_list const * defaults) +{ + if (list == NULL) + return; + + for (int i = 0; i < list->count; i++) { + if (list->entries[i].type == DBET_BUILDING && + list->entries[i].building_name != NULL) { + char const * default_name = NULL; + if ((defaults != NULL) && (i < defaults->count)) + default_name = defaults->entries[i].building_name; + if (list->entries[i].building_name != default_name) + free ((void *)list->entries[i].building_name); + list->entries[i].building_name = NULL; + } + } + list->count = (defaults != NULL) ? defaults->count : 0; +} + +void +move_bonus_entry_list (struct district_bonus_list * dest, + struct district_bonus_list * src) +{ + if ((dest == NULL) || (src == NULL)) + return; + + dest->count = src->count; + for (int i = 0; i < src->count; i++) { + dest->entries[i] = src->entries[i]; + src->entries[i].building_name = NULL; + } + src->count = 0; +} + +void +free_dynamic_district_config (struct district_config * cfg) +{ + if (cfg == NULL) + return; + + if (! cfg->is_dynamic) + return; + + char const * name_ptr = cfg->name; + if (cfg->name != NULL) { + free ((void *)cfg->name); + cfg->name = NULL; + } + if ((cfg->display_name != NULL) && + (cfg->display_name != name_ptr)) { + free ((void *)cfg->display_name); + cfg->display_name = NULL; + } + if (cfg->tooltip != NULL) { + free ((void *)cfg->tooltip); + cfg->tooltip = NULL; + } + for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { + if (cfg->advance_prereqs[i] != NULL) { + free ((void *)cfg->advance_prereqs[i]); + cfg->advance_prereqs[i] = NULL; + } + } + cfg->advance_prereq_count = 0; + if (cfg->obsoleted_by != NULL) { + free ((void *)cfg->obsoleted_by); + cfg->obsoleted_by = NULL; + } + + for (int i = 0; i < 5; i++) { + if (cfg->resource_prereqs[i] != NULL) { + free ((void *)cfg->resource_prereqs[i]); + cfg->resource_prereqs[i] = NULL; + } + } + + if (cfg->resource_prereq_on_tile != NULL) { + free ((void *)cfg->resource_prereq_on_tile); + cfg->resource_prereq_on_tile = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { + if (cfg->wonder_prereqs[i] != NULL) { + free ((void *)cfg->wonder_prereqs[i]); + cfg->wonder_prereqs[i] = NULL; + } + } + cfg->wonder_prereq_count = 0; + + for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { + if (cfg->natural_wonder_prereqs[i] != NULL) { + free ((void *)cfg->natural_wonder_prereqs[i]); + cfg->natural_wonder_prereqs[i] = NULL; + } + } + cfg->natural_wonder_prereq_count = 0; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { + if (cfg->buildable_on_districts[i] != NULL) { + free ((void *)cfg->buildable_on_districts[i]); + cfg->buildable_on_districts[i] = NULL; + } + } + cfg->buildable_on_district_count = 0; + cfg->buildable_on_district_id_count = 0; + cfg->has_buildable_on_districts = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { + if (cfg->buildable_adjacent_to_districts[i] != NULL) { + free ((void *)cfg->buildable_adjacent_to_districts[i]); + cfg->buildable_adjacent_to_districts[i] = NULL; + } + } + cfg->buildable_adjacent_to_district_count = 0; + cfg->buildable_adjacent_to_district_id_count = 0; + cfg->has_buildable_adjacent_to = false; + cfg->has_buildable_adjacent_to_districts = false; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + if (cfg->buildable_by_civs[i] != NULL) { + free ((void *)cfg->buildable_by_civs[i]); + cfg->buildable_by_civs[i] = NULL; + } + } + cfg->buildable_by_civ_count = 0; + cfg->has_buildable_by_civs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) + cfg->buildable_by_civ_traits_ids[i] = -1; + cfg->buildable_by_civ_traits_id_count = 0; + cfg->has_buildable_by_civ_traits = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) + cfg->buildable_by_civ_govs_ids[i] = -1; + cfg->buildable_by_civ_govs_id_count = 0; + cfg->has_buildable_by_civ_govs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) + cfg->buildable_by_civ_cultures_ids[i] = -1; + cfg->buildable_by_civ_cultures_id_count = 0; + cfg->has_buildable_by_civ_cultures = false; + + for (int i = 0; i < 5; i++) { + if (cfg->dependent_improvements[i] != NULL) { + free ((void *)cfg->dependent_improvements[i]); + cfg->dependent_improvements[i] = NULL; + } + } + + for (int i = 0; i < 10; i++) { + if (cfg->img_paths[i] != NULL) { + free ((void *)cfg->img_paths[i]); + cfg->img_paths[i] = NULL; + } + } + + free_bonus_entry_list (&cfg->culture_bonus_extras); + free_bonus_entry_list (&cfg->science_bonus_extras); + free_bonus_entry_list (&cfg->food_bonus_extras); + free_bonus_entry_list (&cfg->gold_bonus_extras); + free_bonus_entry_list (&cfg->shield_bonus_extras); + free_bonus_entry_list (&cfg->happiness_bonus_extras); + free_bonus_entry_list (&cfg->defense_bonus_extras); + + memset (cfg, 0, sizeof *cfg); +} + +void +free_dynamic_wonder_config (struct wonder_district_config * cfg) +{ + if (cfg == NULL) + return; + + if (! cfg->is_dynamic) + return; + + if (cfg->wonder_name != NULL) { + free ((void *)cfg->wonder_name); + cfg->wonder_name = NULL; + } + + if (cfg->img_path != NULL) { + free ((void *)cfg->img_path); + cfg->img_path = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + if (cfg->buildable_by_civs[i] != NULL) { + free ((void *)cfg->buildable_by_civs[i]); + cfg->buildable_by_civs[i] = NULL; + } + } + cfg->buildable_by_civ_count = 0; + cfg->has_buildable_by_civs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) + cfg->buildable_by_civ_traits_ids[i] = -1; + cfg->buildable_by_civ_traits_id_count = 0; + cfg->has_buildable_by_civ_traits = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) + cfg->buildable_by_civ_govs_ids[i] = -1; + cfg->buildable_by_civ_govs_id_count = 0; + cfg->has_buildable_by_civ_govs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) + cfg->buildable_by_civ_cultures_ids[i] = -1; + cfg->buildable_by_civ_cultures_id_count = 0; + cfg->has_buildable_by_civ_cultures = false; + + memset (cfg, 0, sizeof *cfg); +} + +void +free_dynamic_natural_wonder_config (struct natural_wonder_district_config * cfg) +{ + if (cfg == NULL) + return; + + if (! cfg->is_dynamic) + return; + + if (cfg->name != NULL) { + free ((void *)cfg->name); + cfg->name = NULL; + } + + if (cfg->img_path != NULL) { + free ((void *)cfg->img_path); + cfg->img_path = NULL; + } + + memset (cfg, 0, sizeof *cfg); + cfg->adjacent_to = (enum SquareTypes)SQ_INVALID; + cfg->adjacency_dir = DIR_ZERO; +} + +enum Unit_Command_Values +allocate_dynamic_district_command (char const * name) +{ + int offset = is->next_custom_dynamic_command_index; + is->next_custom_dynamic_command_index += 1; + int value = C3X_DISTRICT_COMMAND_BASE - (offset + 1); + return (enum Unit_Command_Values)value; +} + +void +free_special_district_override_strings (struct district_config * cfg, struct district_config const * defaults) +{ + if (cfg == NULL || defaults == NULL) + return; + + if ((cfg->display_name != NULL) && + (cfg->display_name != cfg->name) && + (cfg->display_name != defaults->display_name)) { + free ((void *)cfg->display_name); + cfg->display_name = NULL; + } + if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) { + free ((void *)cfg->tooltip); + cfg->tooltip = NULL; + } + for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { + char const * default_value = (defaults != NULL && i < defaults->advance_prereq_count) + ? defaults->advance_prereqs[i] + : NULL; + if ((cfg->advance_prereqs[i] != NULL) && + (cfg->advance_prereqs[i] != default_value)) { + free ((void *)cfg->advance_prereqs[i]); + } + cfg->advance_prereqs[i] = NULL; + } + cfg->advance_prereq_count = 0; + if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) { + free ((void *)cfg->obsoleted_by); + cfg->obsoleted_by = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { + char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; + if ((cfg->resource_prereqs[i] != NULL) && + (cfg->resource_prereqs[i] != default_value)) + free ((void *)cfg->resource_prereqs[i]); + cfg->resource_prereqs[i] = NULL; + } + cfg->resource_prereq_count = defaults->resource_prereq_count; + + if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) { + free ((void *)cfg->resource_prereq_on_tile); + cfg->resource_prereq_on_tile = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { + char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; + if ((cfg->wonder_prereqs[i] != NULL) && + (cfg->wonder_prereqs[i] != default_value)) + free ((void *)cfg->wonder_prereqs[i]); + cfg->wonder_prereqs[i] = NULL; + } + cfg->wonder_prereq_count = defaults->wonder_prereq_count; + + for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { + char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; + if ((cfg->natural_wonder_prereqs[i] != NULL) && + (cfg->natural_wonder_prereqs[i] != default_value)) + free ((void *)cfg->natural_wonder_prereqs[i]); + cfg->natural_wonder_prereqs[i] = NULL; + } + cfg->natural_wonder_prereq_count = defaults->natural_wonder_prereq_count; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { + char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; + if ((cfg->buildable_on_districts[i] != NULL) && + (cfg->buildable_on_districts[i] != default_value)) { + free ((void *)cfg->buildable_on_districts[i]); + } + cfg->buildable_on_districts[i] = NULL; + } + cfg->buildable_on_district_count = defaults->buildable_on_district_count; + cfg->buildable_on_district_id_count = defaults->buildable_on_district_id_count; + cfg->has_buildable_on_districts = defaults->has_buildable_on_districts; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { + char const * default_value = (i < defaults->buildable_adjacent_to_district_count) + ? defaults->buildable_adjacent_to_districts[i] + : NULL; + if ((cfg->buildable_adjacent_to_districts[i] != NULL) && + (cfg->buildable_adjacent_to_districts[i] != default_value)) { + free ((void *)cfg->buildable_adjacent_to_districts[i]); + } + cfg->buildable_adjacent_to_districts[i] = NULL; + } + cfg->buildable_adjacent_to_district_count = defaults->buildable_adjacent_to_district_count; + cfg->buildable_adjacent_to_district_id_count = defaults->buildable_adjacent_to_district_id_count; + cfg->has_buildable_adjacent_to = defaults->has_buildable_adjacent_to; + cfg->has_buildable_adjacent_to_districts = defaults->has_buildable_adjacent_to_districts; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; + if ((cfg->buildable_by_civs[i] != NULL) && + (cfg->buildable_by_civs[i] != default_value)) { + free ((void *)cfg->buildable_by_civs[i]); + } + cfg->buildable_by_civs[i] = NULL; + } + cfg->buildable_by_civ_count = defaults->buildable_by_civ_count; + cfg->has_buildable_by_civs = defaults->has_buildable_by_civs; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) + cfg->buildable_by_civ_traits_ids[i] = -1; + cfg->buildable_by_civ_traits_id_count = defaults->buildable_by_civ_traits_id_count; + cfg->has_buildable_by_civ_traits = defaults->has_buildable_by_civ_traits; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) + cfg->buildable_by_civ_govs_ids[i] = -1; + cfg->buildable_by_civ_govs_id_count = defaults->buildable_by_civ_govs_id_count; + cfg->has_buildable_by_civ_govs = defaults->has_buildable_by_civ_govs; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) + cfg->buildable_by_civ_cultures_ids[i] = -1; + cfg->buildable_by_civ_cultures_id_count = defaults->buildable_by_civ_cultures_id_count; + cfg->has_buildable_by_civ_cultures = defaults->has_buildable_by_civ_cultures; + cfg->buildable_by_war_allies = defaults->buildable_by_war_allies; + cfg->buildable_by_pact_allies = defaults->buildable_by_pact_allies; + + for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { + char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; + if ((cfg->dependent_improvements[i] != NULL) && + (cfg->dependent_improvements[i] != default_value)) { + free ((void *)cfg->dependent_improvements[i]); + } + cfg->dependent_improvements[i] = NULL; + } + cfg->dependent_improvement_max_index = defaults->dependent_improvement_max_index; + + for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { + char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; + if ((cfg->img_paths[i] != NULL) && + (cfg->img_paths[i] != default_value)) { + free ((void *)cfg->img_paths[i]); + } + cfg->img_paths[i] = NULL; + } + cfg->img_path_count = defaults->img_path_count; + + free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); + free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); + free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); + free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); + free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); + free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); + free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); +} + +void +reset_regular_district_configs (void) +{ + for (int i = USED_SPECIAL_DISTRICT_TYPES; i < COUNT_DISTRICT_TYPES; i++) { + if (is->district_configs[i].is_dynamic) + free_dynamic_district_config (&is->district_configs[i]); + } + + for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) + free_special_district_override_strings (&is->district_configs[i], &special_district_defaults[i]); + + memset (is->district_configs, 0, sizeof is->district_configs); + for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) + is->district_configs[i] = special_district_defaults[i]; + + is->special_district_count = USED_SPECIAL_DISTRICT_TYPES; + is->dynamic_district_count = 0; + is->district_count = is->special_district_count; + is->next_custom_dynamic_command_index = 0; +} + +void +reset_wonder_district_configs (void) +{ + for (int i = 0; i < MAX_WONDER_DISTRICT_TYPES; i++) { + if (is->wonder_district_configs[i].is_dynamic) + free_dynamic_wonder_config (&is->wonder_district_configs[i]); + } + + memset (is->wonder_district_configs, 0, sizeof is->wonder_district_configs); + is->wonder_district_count = 0; +} + +void +reset_natural_wonder_configs (void) +{ + for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { + if (is->natural_wonder_configs[i].is_dynamic) + free_dynamic_natural_wonder_config (&is->natural_wonder_configs[i]); + } + + memset (is->natural_wonder_configs, 0, sizeof is->natural_wonder_configs); + for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { + is->natural_wonder_configs[i].adjacent_to = (enum SquareTypes)SQ_INVALID; + is->natural_wonder_configs[i].adjacency_dir = DIR_ZERO; + } + for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) + is->natural_wonder_img_sets[i].img.vtable = NULL; + stable_deinit (&is->natural_wonder_name_to_id); + is->natural_wonder_count = 0; +} + +void +clear_dynamic_district_definitions (void) +{ + reset_regular_district_configs (); + reset_wonder_district_configs (); + reset_natural_wonder_configs (); + reset_ai_candidate_bridge_or_canals (); +} + +void +init_parsed_district_definition (struct parsed_district_definition * def) +{ + memset (def, 0, sizeof *def); + def->img_path_count = -1; + def->defense_bonus_percent = 0; + def->render_strategy = DRS_BY_COUNT; + def->ai_build_strategy = DABS_DISTRICT; + def->buildable_square_types_mask = district_default_buildable_mask (); + def->buildable_adjacent_to_square_types_mask = 0; + def->buildable_without_removal_mask = 0; + def->buildable_on_overlays_mask = 0; + def->buildable_adjacent_to_overlays_mask = 0; + def->buildable_on_rivers = false; + def->buildable_adjacent_to_allows_city = false; +} + +void +free_parsed_district_definition (struct parsed_district_definition * def) +{ + if (def == NULL) + return; + + if (def->display_name != NULL) { + free (def->display_name); + def->display_name = NULL; + } + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + if (def->tooltip != NULL) { + free (def->tooltip); + def->tooltip = NULL; + } + for (int i = 0; i < def->advance_prereq_count; i++) { + if (def->advance_prereqs[i] != NULL) { + free (def->advance_prereqs[i]); + def->advance_prereqs[i] = NULL; + } + } + def->advance_prereq_count = 0; + for (int i = 0; i < ARRAY_LEN (def->buildable_on_districts); i++) { + if (def->buildable_on_districts[i] != NULL) { + free (def->buildable_on_districts[i]); + def->buildable_on_districts[i] = NULL; + } + } + for (int i = 0; i < ARRAY_LEN (def->buildable_adjacent_to_districts); i++) { + if (def->buildable_adjacent_to_districts[i] != NULL) { + free (def->buildable_adjacent_to_districts[i]); + def->buildable_adjacent_to_districts[i] = NULL; + } + } + if (def->obsoleted_by != NULL) { + free (def->obsoleted_by); + def->obsoleted_by = NULL; + } + + for (int i = 0; i < def->resource_prereq_count; i++) { + if (def->resource_prereqs[i] != NULL) { + free (def->resource_prereqs[i]); + def->resource_prereqs[i] = NULL; + } + } + def->resource_prereq_count = 0; + + if (def->resource_prereq_on_tile != NULL) { + free (def->resource_prereq_on_tile); + def->resource_prereq_on_tile = NULL; + } + + for (int i = 0; i < def->wonder_prereq_count; i++) { + if (def->wonder_prereqs[i] != NULL) { + free (def->wonder_prereqs[i]); + def->wonder_prereqs[i] = NULL; + } + } + def->wonder_prereq_count = 0; + + for (int i = 0; i < def->natural_wonder_prereq_count; i++) { + if (def->natural_wonder_prereqs[i] != NULL) { + free (def->natural_wonder_prereqs[i]); + def->natural_wonder_prereqs[i] = NULL; + } + } + def->natural_wonder_prereq_count = 0; + def->buildable_adjacent_to_district_count = 0; + + for (int i = 0; i < def->buildable_by_civ_count; i++) { + if (def->buildable_by_civs[i] != NULL) { + free (def->buildable_by_civs[i]); + def->buildable_by_civs[i] = NULL; + } + } + def->buildable_by_civ_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + + for (int i = 0; i < def->dependent_improvement_max_index; i++) { + if (def->dependent_improvements[i] != NULL) { + free (def->dependent_improvements[i]); + def->dependent_improvements[i] = NULL; + } + } + def->dependent_improvement_max_index = 0; + + for (int i = 0; i < def->img_path_count; i++) { + if (def->img_paths[i] != NULL) { + free (def->img_paths[i]); + def->img_paths[i] = NULL; + } + } + def->img_path_count = 0; + + if (def->generated_resource != NULL) { + free (def->generated_resource); + def->generated_resource = NULL; + } + + free_bonus_entry_list (&def->culture_bonus_extras); + free_bonus_entry_list (&def->science_bonus_extras); + free_bonus_entry_list (&def->food_bonus_extras); + free_bonus_entry_list (&def->gold_bonus_extras); + free_bonus_entry_list (&def->shield_bonus_extras); + free_bonus_entry_list (&def->happiness_bonus_extras); + free_bonus_entry_list (&def->defense_bonus_extras); + + init_parsed_district_definition (def); +} + +int +find_special_district_index_by_name (char const * name) +{ + if (name == NULL) + return -1; + + for (int i = 0; i < is->special_district_count; i++) { + if ((is->district_configs[i].name != NULL) && + (strcmp (is->district_configs[i].name, name) == 0)) + return i; + } + return -1; +} + + +// --------------------------------------------------------------- +// Unit counter system +// --------------------------------------------------------------- + +bool +read_counter_rule_terrain_mask (struct string_slice const * terrain_name, unsigned int * out_mask) +{ + if ((terrain_name == NULL) || (out_mask == NULL)) + return false; + + struct string_slice trimmed = trim_string_slice (terrain_name, 1); + if (trimmed.len <= 0) + return false; + + if (slice_matches_str (&trimmed, "lake") || slice_matches_str (&trimmed, "lakes")) { + *out_mask = district_buildable_lake_mask_bit (); + return true; + } + + enum SquareTypes parsed; + if (! read_tile_terrain_type_value (&trimmed, &parsed)) + return false; + + if (parsed == (enum SquareTypes)SQ_INVALID) + *out_mask = all_square_types_mask () | district_buildable_lake_mask_bit (); + else + *out_mask = square_type_mask_bit (parsed); + + return *out_mask != 0; +} + +struct unit_counter_group * +find_unit_counter_group_by_name (struct c3x_config * cfg, char const * name) +{ + for (int i = 0; i < cfg->count_unit_counter_groups; i++) { + struct unit_counter_group * g = &cfg->unit_counter_groups[i]; + if (g->name && strcmp (g->name, name) == 0) + return g; + } + return NULL; +} + +bool +unit_type_in_group (struct unit_counter_group * g, int type_id) +{ + char const * name = p_bic_data->UnitTypes[type_id].Name; + for (int i = 0; i < g->count_type_ids; i++) + if (strcmp (p_bic_data->UnitTypes[g->type_ids[i]].Name, name) == 0) + return true; + return false; +} + +bool +unit_matches_counter_side (struct c3x_config * cfg, int type_id, + int match, char * group_name) +{ + if (match == UCM_ANY) + return true; + if (match == UCM_GROUP) { + struct unit_counter_group * g = + find_unit_counter_group_by_name (cfg, group_name); + return g && unit_type_in_group (g, type_id); + } + // Direct unit type match: compare by name rather than exact ID so that + // AI strategy duplicates (same name, different ID) are also matched. + return strcmp (p_bic_data->UnitTypes[match].Name, + p_bic_data->UnitTypes[type_id].Name) == 0; +} + +enum recognizable_parse_result +parse_unit_counter_group (char ** p_cursor, + struct error_line ** p_unrecognized_lines, + void * out_group) +{ + char * cur = *p_cursor; + struct string_slice group_name; + if (! (parse_string (&cur, &group_name) && skip_punctuation (&cur, ':'))) + return RPR_PARSE_ERROR; + + struct unit_counter_group * g = out_group; + g->name = extract_slice (&group_name); + g->type_ids = NULL; + g->count_type_ids = 0; + + int any_unrecognized = 0; + struct string_slice type_name; + while (parse_string (&cur, &type_name)) { + // Loop through all unit types with this name, including AI strategy + // duplicates (same name, different ID), which the game creates internally. + int type_id = 0; + bool found_any = false; + while (find_unit_type_id_by_name (&type_name, type_id, &type_id)) { + g->type_ids = realloc (g->type_ids, + (g->count_type_ids + 1) * sizeof (int)); + g->type_ids[g->count_type_ids++] = type_id; + found_any = true; + type_id++; // continue search from next index + } + if (! found_any) { + add_unrecognized_line (p_unrecognized_lines, &type_name); + any_unrecognized = 1; + } + if (! skip_punctuation (&cur, ',')) + break; + } + *p_cursor = cur; + return any_unrecognized ? RPR_UNRECOGNIZED : RPR_OK; +} + +enum recognizable_parse_result +parse_counter_rule (char ** p_cursor, + struct error_line ** p_unrecognized_lines, + void * out_rule) +{ + char * cur = *p_cursor; + struct string_slice attacker_name, vs_token, defender_name; + + if (! parse_string (&cur, &attacker_name)) + return RPR_PARSE_ERROR; + if (! (parse_string (&cur, &vs_token) && + slice_matches_str (&vs_token, "vs"))) + return RPR_PARSE_ERROR; + if (! parse_string (&cur, &defender_name)) + return RPR_PARSE_ERROR; + + struct counter_rule * r = out_rule; + *r = (struct counter_rule) { + .attacker_match = UCM_ANY, + .defender_match = UCM_ANY, + .terrain_mask = 0, + .district_id = -1, + .district_name = NULL, + .self_atk_pct = 100, + .self_def_pct = 100, + .enemy_atk_pct = 100, + .enemy_def_pct = 100, + }; + + if (! slice_matches_str (&attacker_name, "*")) { + int type_id; + if (find_unit_type_id_by_name (&attacker_name, 0, &type_id)) + r->attacker_match = type_id; + else { + r->attacker_match = UCM_GROUP; + r->attacker_group = extract_slice (&attacker_name); + } + } + + if (! slice_matches_str (&defender_name, "*")) { + int type_id; + if (find_unit_type_id_by_name (&defender_name, 0, &type_id)) + r->defender_match = type_id; + else { + r->defender_match = UCM_GROUP; + r->defender_group = extract_slice (&defender_name); + } + } + + struct string_slice token; + while (parse_string (&cur, &token)) { + if (slice_matches_str (&token, "in-city")) { + r->only_in_city = true; + } else if (slice_matches_str (&token, "ignore-terrain")) { + r->ignore_terrain = true; + } else if (slice_matches_str (&token, "self-atk")) { + if (! parse_int (&cur, &r->self_atk_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "self-def")) { + if (! parse_int (&cur, &r->self_def_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "enemy-atk")) { + if (! parse_int (&cur, &r->enemy_atk_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "enemy-def")) { + if (! parse_int (&cur, &r->enemy_def_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "terrain")) { + struct string_slice terrain_name; + if (! parse_string (&cur, &terrain_name)) + return RPR_PARSE_ERROR; + if (! read_counter_rule_terrain_mask (&terrain_name, &r->terrain_mask)) { + add_unrecognized_line (p_unrecognized_lines, &terrain_name); + return RPR_UNRECOGNIZED; + } + } else if (slice_matches_str (&token, "district")) { + struct string_slice district_name; + if (! parse_string (&cur, &district_name)) + return RPR_PARSE_ERROR; + free (r->district_name); + r->district_name = extract_slice (&district_name); + r->district_id = -1; + } else { + break; + } + } + + *p_cursor = cur; + return RPR_OK; +} + +void +apply_counter_rules (struct c3x_config * cfg, + Unit * attacker, Unit * defender, Tile * def_tile, + int * out_attacker_atk, int * out_defender_def, + bool * out_ignore_terrain) +{ + int a_type = attacker->Body.UnitTypeID; + int d_type = defender->Body.UnitTypeID; + bool in_city = Tile_has_city (def_tile); + + int aa = 100, dd = 100; + bool ignore = false; + + for (int i = 0; i < cfg->count_counter_rules; i++) { + struct counter_rule * r = &cfg->counter_rules[i]; + + // Check forward match (attacker=rule attacker side, defender=rule defender side) + // Applied fields: self-atk (attacker attack), enemy-def (defender defense) + bool forward = unit_matches_counter_side (cfg, a_type, + r->attacker_match, r->attacker_group) && + unit_matches_counter_side (cfg, d_type, + r->defender_match, r->defender_group); + + // Check reverse match (attacker=rule defender side, defender=rule attacker side) + // Applied fields: self-def (rule attacker side is now defending), enemy-atk (rule defender side is now attacking) + bool reverse = unit_matches_counter_side (cfg, a_type, + r->defender_match, r->defender_group) && + unit_matches_counter_side (cfg, d_type, + r->attacker_match, r->attacker_group); + + if (! forward && ! reverse) + continue; + + // Environment checks are based on the defender's tile + if (r->only_in_city && ! in_city) + continue; + if (r->terrain_mask != 0 && + ! tile_matches_square_type_mask (def_tile, r->terrain_mask)) + continue; + if (r->district_name != NULL && + ! ((r->district_id != -1) && + cfg->enable_districts && + district_is_complete (def_tile, r->district_id))) + continue; + + if (forward) { + aa = aa * r->self_atk_pct / 100; // self-atk: attacker attack + dd = dd * r->enemy_def_pct / 100; // enemy-def: defender defense + } + if (reverse) { + aa = aa * r->enemy_atk_pct / 100; // enemy-atk: rule defender side now acts as attacker + dd = dd * r->self_def_pct / 100; // self-def: rule attacker side now acts as defender + } + if (forward || reverse) + ignore = ignore || r->ignore_terrain; + } + + *out_attacker_atk = aa; + *out_defender_def = dd; + *out_ignore_terrain = ignore; +} + +bool +district_is_included_by_final_config (int district_id) +{ + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + if (! is->current_config.enable_districts) + return false; + + switch (district_id) { + case NEIGHBORHOOD_DISTRICT_ID: return is->current_config.enable_neighborhood_districts; + case WONDER_DISTRICT_ID: return is->current_config.enable_wonder_districts; + case DISTRIBUTION_HUB_DISTRICT_ID: return is->current_config.enable_distribution_hub_districts; + case AERODROME_DISTRICT_ID: return is->current_config.enable_aerodrome_districts; + case PORT_DISTRICT_ID: return is->current_config.enable_port_districts; + case CENTRAL_RAIL_HUB_DISTRICT_ID: return is->current_config.enable_central_rail_hub_districts; + case ENERGY_GRID_DISTRICT_ID: return is->current_config.enable_energy_grid_districts; + case BRIDGE_DISTRICT_ID: return is->current_config.enable_bridge_districts; + case CANAL_DISTRICT_ID: return is->current_config.enable_canal_districts; + case GREAT_WALL_DISTRICT_ID: return is->current_config.enable_great_wall_districts; + default: return true; + } +} + +bool +ensure_culture_variant_art (struct district_config * cfg, int section_start_line) +{ + if ((cfg == NULL) || (! cfg->vary_img_by_culture)) + return true; + + const int required_variants = 5; + const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); + if (cfg->img_path_count <= 0) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] load_dynamic_district_configs: district \"%s\" requires culture-specific art but none provided (line %d)\n", cfg->name, section_start_line); + (*p_OutputDebugStringA) (ss); + return false; + } + + while ((cfg->img_path_count < required_variants) && + (cfg->img_path_count < max_img_paths)) { + cfg->img_paths[cfg->img_path_count] = strdup (cfg->img_paths[0]); + cfg->img_path_count += 1; + } + + return true; +} + +bool +parse_config_string_list (char * value_text, + char ** dest, + int capacity, + int * out_count, + struct error_line ** parse_errors, + int line_number, + char const * key) +{ + for (int i = 0; i < capacity; i++) { + if (dest[i] != NULL) { + free (dest[i]); + dest[i] = NULL; + } + } + *out_count = 0; + + if (value_text == NULL || *value_text == '\0') + return true; + + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + if (*cursor == '\0') + break; + + char * item_start; + char * item_end; + if (*cursor == '"') { + cursor++; + item_start = cursor; + while ((*cursor != '\0') && (*cursor != '"')) + cursor++; + if (*cursor != '"') { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (missing closing quote)", line_number, key); + err->text[(sizeof err->text) - 1] = '\0'; + for (int j = 0; j < capacity; j++) { + if (dest[j] != NULL) { + free (dest[j]); + dest[j] = NULL; + } + } + *out_count = 0; + return false; + } + item_end = cursor; + cursor++; + } else { + item_start = cursor; + while ((*cursor != '\0') && (*cursor != ',')) + cursor++; + item_end = cursor; + } + + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + + int item_len = item_end - item_start; + if (item_len > 0) { + if (*out_count < capacity) { + char * copy = malloc (item_len + 1); + if (copy == NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (out of memory)", line_number, key); + err->text[(sizeof err->text) - 1] = '\0'; + for (int j = 0; j < capacity; j++) { + if (dest[j] != NULL) { + free (dest[j]); + dest[j] = NULL; + } + } + *out_count = 0; + return false; + } + memcpy (copy, item_start, item_len); + copy[item_len] = '\0'; + dest[*out_count] = copy; + *out_count += 1; + } + } + + while (is_space_char (*cursor)) + cursor++; + + if (*cursor == ',') { + cursor++; + continue; + } + if (*cursor == '\0') + break; + } + + return true; +} + +bool +parse_buildable_square_type_mask (struct string_slice const * value, + unsigned int * out_mask, + struct error_line ** parse_errors, + int line_number, + char const * key_name, + bool * out_allow_city) +{ + char * value_text = trim_and_extract_slice (value, 0); + unsigned int mask = 0; + int entry_count = 0; + bool allow_city = false; + bool allow_city_token = (key_name != NULL) && (strcmp (key_name, "buildable_adjacent_to") == 0); + if (key_name == NULL) + key_name = "buildable_on"; + + if (value_text != NULL) { + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + char * item_start = cursor; + while ((*cursor != '\0') && (*cursor != ',')) + cursor++; + + char * item_end = cursor; + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + + struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; + if (item_slice.len > 0) { + if (slice_matches_str (&item_slice, "city")) { + if (! allow_city_token) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + allow_city = true; + entry_count += 1; + } else if (slice_matches_str (&item_slice, "lake")) { + mask |= district_buildable_lake_mask_bit (); + entry_count += 1; + } else { + enum SquareTypes parsed; + if (read_tile_terrain_type_value (&item_slice, &parsed)) { + if ((parsed == SQ_RIVER) || + (parsed == SQ_Forest) || + (parsed == SQ_Jungle) || + (parsed == SQ_Swamp)) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + if (parsed == (enum SquareTypes)SQ_INVALID) { + mask = all_square_types_mask (); + mask &= ~(square_type_mask_bit (SQ_Forest) | + square_type_mask_bit (SQ_Jungle) | + square_type_mask_bit (SQ_Swamp)); + } else + mask |= square_type_mask_bit (parsed); + entry_count += 1; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + } + } + + if (*cursor == ',') { + cursor++; + continue; + } + break; + } + } + + if (value_text != NULL) + free (value_text); + + if ((entry_count == 0) || ((mask == 0) && ! allow_city)) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one tile terrain type)", line_number, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + return false; + } + + *out_mask = mask; + if (out_allow_city != NULL) + *out_allow_city = allow_city; + return true; +} + +bool +parse_buildable_overlay_mask (struct string_slice const * value, + unsigned int * out_mask, + struct error_line ** parse_errors, + int line_number, + char const * key_name) +{ + char * value_text = trim_and_extract_slice (value, 0); + unsigned int mask = 0; + unsigned int allowed_mask = (DOM_MINE | DOM_IRRIGATION | DOM_FORTRESS | DOM_BARRICADE | + DOM_OUTPOST | DOM_RADAR_TOWER | DOM_JUNGLE | DOM_FOREST | + DOM_SWAMP | DOM_RIVER | DOM_AIRFIELD); + int entry_count = 0; + + if (key_name == NULL) + key_name = "buildable_without_removal"; + if (strcmp (key_name, "buildable_without_removal") == 0) + allowed_mask = (DOM_JUNGLE | DOM_FOREST | DOM_SWAMP); + else if (strcmp (key_name, "buildable_on_overlays") == 0) + allowed_mask &= ~DOM_RIVER; + + if (value_text != NULL) { + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + char * item_start = cursor; + while ((*cursor != '\0') && (*cursor != ',')) + cursor++; + + char * item_end = cursor; + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + + struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; + if (item_slice.len > 0) { + unsigned int bit = 0; + if (slice_matches_str (&item_slice, "mine")) { + bit = DOM_MINE; + } else if (slice_matches_str (&item_slice, "irrigation")) { + bit = DOM_IRRIGATION; + } else if (slice_matches_str (&item_slice, "fortress")) { + bit = DOM_FORTRESS; + } else if (slice_matches_str (&item_slice, "barricade")) { + bit = DOM_BARRICADE; + } else if (slice_matches_str (&item_slice, "outpost")) { + bit = DOM_OUTPOST; + } else if (slice_matches_str (&item_slice, "radar-tower")) { + bit = DOM_RADAR_TOWER; + } else if (slice_matches_str (&item_slice, "airfield")) { + bit = DOM_AIRFIELD; + } else if (slice_matches_str (&item_slice, "jungle")) { + bit = DOM_JUNGLE; + } else if (slice_matches_str (&item_slice, "jungles")) { + bit = DOM_JUNGLE; + } else if (slice_matches_str (&item_slice, "forest")) { + bit = DOM_FOREST; + } else if (slice_matches_str (&item_slice, "forests")) { + bit = DOM_FOREST; + } else if (slice_matches_str (&item_slice, "marsh")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "marshes")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "swamp")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "swamps")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "river")) { + bit = DOM_RIVER; + } else if (slice_matches_str (&item_slice, "rivers")) { + bit = DOM_RIVER; + } + + if (bit != 0) { + if ((allowed_mask & bit) == 0) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + mask |= bit; + entry_count += 1; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + } + + if (*cursor == ',') { + cursor++; + continue; + } + break; + } + } + + if (value_text != NULL) + free (value_text); + + if ((entry_count == 0) || (mask == 0)) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one overlay)", line_number, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + return false; + } + + *out_mask = mask; + return true; +} + +bool +parse_district_bonus_entries (struct string_slice const * value, + int * out_base_bonus, + struct district_bonus_list * out_extras, + struct error_line ** parse_errors, + int line_number, + struct string_slice const * key) +{ + if ((out_base_bonus == NULL) || (out_extras == NULL)) { + add_key_parse_error (parse_errors, line_number, key, value, "(invalid bonus target)"); + return false; + } + + char * value_text = trim_and_extract_slice (value, 0); + free_bonus_entry_list (out_extras); + *out_base_bonus = 0; + + if ((value_text == NULL) || (*value_text == '\0')) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); + free (value_text); + return false; + } + + bool got_base = false; + int base_bonus = 0; + + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + if (*cursor == '\0') + break; + + char * item_start = cursor; + bool in_quotes = false; + while (*cursor != '\0') { + if (*cursor == '"') + in_quotes = ! in_quotes; + if ((! in_quotes) && (*cursor == ',')) + break; + cursor++; + } + + char * item_end = cursor; + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + while ((item_start < item_end) && is_space_char (*item_start)) + item_start++; + + if (item_end > item_start) { + struct string_slice item = { .str = item_start, .len = (int)(item_end - item_start) }; + + if (! got_base) { + struct string_slice base_slice = trim_string_slice (&item, 0); + if (! read_int (&base_slice, &base_bonus)) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + got_base = true; + } else { + char * colon = NULL; + in_quotes = false; + for (char * p = item_start; p < item_end; p++) { + if (*p == '"') + in_quotes = ! in_quotes; + if ((! in_quotes) && (*p == ':')) { + colon = p; + break; + } + } + + if (colon == NULL) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected \"name: bonus\" entry)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + struct string_slice name_slice = { .str = item_start, .len = (int)(colon - item_start) }; + struct string_slice bonus_slice = { .str = colon + 1, .len = (int)(item_end - (colon + 1)) }; + struct string_slice trimmed_name = trim_string_slice (&name_slice, 1); + struct string_slice trimmed_bonus = trim_string_slice (&bonus_slice, 0); + + if (trimmed_name.len <= 0) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus name)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + int bonus_value = 0; + if (! read_int (&trimmed_bonus, &bonus_value)) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus value)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + if (out_extras->count >= MAX_DISTRICT_BONUS_ENTRIES) { + add_key_parse_error (parse_errors, line_number, key, value, "(too many bonus entries)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + struct district_bonus_entry * entry = &out_extras->entries[out_extras->count++]; + entry->bonus = bonus_value; + entry->building_id = -1; + entry->building_name = NULL; + + enum SquareTypes parsed_type; + if (read_tile_terrain_type_value (&trimmed_name, &parsed_type)) { + entry->type = DBET_TILE; + entry->tile_type = parsed_type; + } else { + entry->type = DBET_BUILDING; + entry->tile_type = (enum SquareTypes)SQ_INVALID; + entry->building_name = extract_slice (&trimmed_name); + } + } + } + + if (*cursor == ',') { + cursor++; + continue; + } + if (*cursor == '\0') + break; + } + + free (value_text); + + if (! got_base) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); + free_bonus_entry_list (out_extras); + return false; + } + + *out_base_bonus = base_bonus; + return true; +} + +bool +override_special_district_from_definition (struct parsed_district_definition * def, int section_start_line) +{ + if ((! def->has_name) || (def->name == NULL)) + return false; + + int index = find_special_district_index_by_name (def->name); + if (index < 0) + return false; + + struct district_config * cfg = &is->district_configs[index]; + struct district_config const * defaults = &special_district_defaults[index]; + + free (def->name); + def->name = NULL; + def->has_name = false; + + if (def->has_display_name) { + if ((cfg->display_name != NULL) && + (cfg->display_name != cfg->name) && + (cfg->display_name != defaults->display_name)) + free ((void *)cfg->display_name); + cfg->display_name = def->display_name; + def->display_name = NULL; + } + + if (def->has_tooltip) { + if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) + free ((void *)cfg->tooltip); + cfg->tooltip = def->tooltip; + def->tooltip = NULL; + } + + if (def->has_advance_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { + char const * default_value = (i < defaults->advance_prereq_count) ? defaults->advance_prereqs[i] : NULL; + if ((cfg->advance_prereqs[i] != NULL) && + (cfg->advance_prereqs[i] != default_value)) + free ((void *)cfg->advance_prereqs[i]); + cfg->advance_prereqs[i] = NULL; + } + + cfg->advance_prereq_count = def->advance_prereq_count; + const int max_entries = ARRAY_LEN (cfg->advance_prereqs); + if (cfg->advance_prereq_count > max_entries) + cfg->advance_prereq_count = max_entries; + for (int i = 0; i < cfg->advance_prereq_count; i++) { + cfg->advance_prereqs[i] = def->advance_prereqs[i]; + def->advance_prereqs[i] = NULL; + } + def->advance_prereq_count = 0; + } + + if (def->has_obsoleted_by) { + if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) + free ((void *)cfg->obsoleted_by); + cfg->obsoleted_by = def->obsoleted_by; + def->obsoleted_by = NULL; + } + + if (def->has_resource_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { + char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; + if ((cfg->resource_prereqs[i] != NULL) && + (cfg->resource_prereqs[i] != default_value)) + free ((void *)cfg->resource_prereqs[i]); + cfg->resource_prereqs[i] = NULL; + } + + cfg->resource_prereq_count = def->resource_prereq_count; + const int max_entries = ARRAY_LEN (cfg->resource_prereqs); + if (cfg->resource_prereq_count > max_entries) + cfg->resource_prereq_count = max_entries; + for (int i = 0; i < cfg->resource_prereq_count; i++) { + cfg->resource_prereqs[i] = def->resource_prereqs[i]; + def->resource_prereqs[i] = NULL; + } + } + + if (def->has_resource_prereq_on_tile) { + if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) + free ((void *)cfg->resource_prereq_on_tile); + cfg->resource_prereq_on_tile = def->resource_prereq_on_tile; + def->resource_prereq_on_tile = NULL; + } + + if (def->has_wonder_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { + char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; + if ((cfg->wonder_prereqs[i] != NULL) && + (cfg->wonder_prereqs[i] != default_value)) + free ((void *)cfg->wonder_prereqs[i]); + cfg->wonder_prereqs[i] = NULL; + } + + cfg->wonder_prereq_count = def->wonder_prereq_count; + const int max_entries = ARRAY_LEN (cfg->wonder_prereqs); + if (cfg->wonder_prereq_count > max_entries) + cfg->wonder_prereq_count = max_entries; + for (int i = 0; i < cfg->wonder_prereq_count; i++) { + cfg->wonder_prereqs[i] = def->wonder_prereqs[i]; + def->wonder_prereqs[i] = NULL; + } + } + + if (def->has_natural_wonder_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { + char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; + if ((cfg->natural_wonder_prereqs[i] != NULL) && + (cfg->natural_wonder_prereqs[i] != default_value)) + free ((void *)cfg->natural_wonder_prereqs[i]); + cfg->natural_wonder_prereqs[i] = NULL; + } + + cfg->natural_wonder_prereq_count = def->natural_wonder_prereq_count; + const int max_entries = ARRAY_LEN (cfg->natural_wonder_prereqs); + if (cfg->natural_wonder_prereq_count > max_entries) + cfg->natural_wonder_prereq_count = max_entries; + for (int i = 0; i < cfg->natural_wonder_prereq_count; i++) { + cfg->natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; + def->natural_wonder_prereqs[i] = NULL; + } + } + + if (def->has_buildable_on_districts) { + for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { + char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; + if ((cfg->buildable_on_districts[i] != NULL) && + (cfg->buildable_on_districts[i] != default_value)) + free ((void *)cfg->buildable_on_districts[i]); + cfg->buildable_on_districts[i] = NULL; + } + + cfg->buildable_on_district_count = def->buildable_on_district_count; + const int max_entries = ARRAY_LEN (cfg->buildable_on_districts); + if (cfg->buildable_on_district_count > max_entries) + cfg->buildable_on_district_count = max_entries; + for (int i = 0; i < cfg->buildable_on_district_count; i++) { + cfg->buildable_on_districts[i] = def->buildable_on_districts[i]; + def->buildable_on_districts[i] = NULL; + } + cfg->buildable_on_district_id_count = 0; + cfg->has_buildable_on_districts = true; + } + + if (def->has_buildable_adjacent_to_districts) { + for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { + char const * default_value = (i < defaults->buildable_adjacent_to_district_count) + ? defaults->buildable_adjacent_to_districts[i] + : NULL; + if ((cfg->buildable_adjacent_to_districts[i] != NULL) && + (cfg->buildable_adjacent_to_districts[i] != default_value)) + free ((void *)cfg->buildable_adjacent_to_districts[i]); + cfg->buildable_adjacent_to_districts[i] = NULL; + } + + cfg->buildable_adjacent_to_district_count = def->buildable_adjacent_to_district_count; + const int max_entries = ARRAY_LEN (cfg->buildable_adjacent_to_districts); + if (cfg->buildable_adjacent_to_district_count > max_entries) + cfg->buildable_adjacent_to_district_count = max_entries; + for (int i = 0; i < cfg->buildable_adjacent_to_district_count; i++) { + cfg->buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; + def->buildable_adjacent_to_districts[i] = NULL; + } + cfg->buildable_adjacent_to_district_id_count = 0; + cfg->has_buildable_adjacent_to_districts = true; + } + + if (def->has_buildable_by_civs) { + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; + if ((cfg->buildable_by_civs[i] != NULL) && + (cfg->buildable_by_civs[i] != default_value)) + free ((void *)cfg->buildable_by_civs[i]); + cfg->buildable_by_civs[i] = NULL; + } + cfg->buildable_by_civ_count = def->buildable_by_civ_count; + const int max_civ_names = ARRAY_LEN (cfg->buildable_by_civs); + if (cfg->buildable_by_civ_count > max_civ_names) + cfg->buildable_by_civ_count = max_civ_names; + for (int i = 0; i < cfg->buildable_by_civ_count; i++) { + cfg->buildable_by_civs[i] = def->buildable_by_civs[i]; + def->buildable_by_civs[i] = NULL; + } + cfg->has_buildable_by_civs = true; + } + + if (def->has_buildable_by_civ_traits) { + cfg->buildable_by_civ_traits_id_count = def->buildable_by_civ_traits_id_count; + const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_traits_ids); + if (cfg->buildable_by_civ_traits_id_count > max_entries) + cfg->buildable_by_civ_traits_id_count = max_entries; + for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) + cfg->buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; + cfg->has_buildable_by_civ_traits = true; + } + + if (def->has_buildable_by_civ_govs) { + cfg->buildable_by_civ_govs_id_count = def->buildable_by_civ_govs_id_count; + const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_govs_ids); + if (cfg->buildable_by_civ_govs_id_count > max_entries) + cfg->buildable_by_civ_govs_id_count = max_entries; + for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) + cfg->buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; + cfg->has_buildable_by_civ_govs = true; + } + + if (def->has_buildable_by_civ_cultures) { + cfg->buildable_by_civ_cultures_id_count = def->buildable_by_civ_cultures_id_count; + const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); + if (cfg->buildable_by_civ_cultures_id_count > max_entries) + cfg->buildable_by_civ_cultures_id_count = max_entries; + for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) + cfg->buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; + cfg->has_buildable_by_civ_cultures = true; + } + + if (def->has_buildable_by_war_allies) + cfg->buildable_by_war_allies = def->buildable_by_war_allies; + if (def->has_buildable_by_pact_allies) + cfg->buildable_by_pact_allies = def->buildable_by_pact_allies; + + if (def->has_allow_multiple) + cfg->allow_multiple = def->allow_multiple; + if (def->has_vary_img_by_era) + cfg->vary_img_by_era = def->vary_img_by_era; + if (def->has_vary_img_by_culture) + cfg->vary_img_by_culture = def->vary_img_by_culture; + if (def->has_render_strategy) + cfg->render_strategy = def->render_strategy; + if (def->has_ai_build_strategy) + cfg->ai_build_strategy = def->ai_build_strategy; + if (def->has_align_to_coast) + cfg->align_to_coast = def->align_to_coast; + if (def->has_draw_over_resources) + cfg->draw_over_resources = def->draw_over_resources; + if (def->has_allow_irrigation_from) + cfg->allow_irrigation_from = def->allow_irrigation_from; + if (def->has_auto_add_road) + cfg->auto_add_road = def->auto_add_road; + if (def->has_auto_add_railroad) + cfg->auto_add_railroad = def->auto_add_railroad; + if (def->has_custom_width) + cfg->custom_width = def->custom_width; + if (def->has_custom_height) + cfg->custom_height = def->custom_height; + if (def->has_x_offset) + cfg->x_offset = def->x_offset; + if (def->has_y_offset) + cfg->y_offset = def->y_offset; + if (def->has_btn_tile_sheet_column) + cfg->btn_tile_sheet_column = def->btn_tile_sheet_column; + if (def->has_btn_tile_sheet_row) + cfg->btn_tile_sheet_row = def->btn_tile_sheet_row; + if (def->has_defense_bonus_percent) { + cfg->defense_bonus_percent = def->defense_bonus_percent; + free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); + move_bonus_entry_list (&cfg->defense_bonus_extras, &def->defense_bonus_extras); + } + if (def->has_heal_units_in_one_turn) + cfg->heal_units_in_one_turn = def->heal_units_in_one_turn; + if (def->has_impassible) + cfg->impassible = def->impassible; + if (def->has_impassible_to_wheeled) + cfg->impassible_to_wheeled = def->impassible_to_wheeled; + if (def->has_culture_bonus) { + cfg->culture_bonus = def->culture_bonus; + free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); + move_bonus_entry_list (&cfg->culture_bonus_extras, &def->culture_bonus_extras); + } + if (def->has_science_bonus) { + cfg->science_bonus = def->science_bonus; + free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); + move_bonus_entry_list (&cfg->science_bonus_extras, &def->science_bonus_extras); + } + if (def->has_food_bonus) { + cfg->food_bonus = def->food_bonus; + free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); + move_bonus_entry_list (&cfg->food_bonus_extras, &def->food_bonus_extras); + } + if (def->has_gold_bonus) { + cfg->gold_bonus = def->gold_bonus; + free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); + move_bonus_entry_list (&cfg->gold_bonus_extras, &def->gold_bonus_extras); + } + if (def->has_shield_bonus) { + cfg->shield_bonus = def->shield_bonus; + free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); + move_bonus_entry_list (&cfg->shield_bonus_extras, &def->shield_bonus_extras); + } + if (def->has_happiness_bonus) { + cfg->happiness_bonus = def->happiness_bonus; + free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); + move_bonus_entry_list (&cfg->happiness_bonus_extras, &def->happiness_bonus_extras); + } + if (def->has_buildable_on) + cfg->buildable_square_types_mask = def->buildable_square_types_mask; + if (def->has_buildable_adjacent_to) { + cfg->buildable_adjacent_to_square_types_mask = def->buildable_adjacent_to_square_types_mask; + cfg->has_buildable_adjacent_to = true; + cfg->buildable_adjacent_to_allows_city = def->buildable_adjacent_to_allows_city; + } + if (def->has_buildable_without_removal) { + cfg->buildable_without_removal_mask = def->buildable_without_removal_mask; + cfg->has_buildable_without_removal = true; + } + if (def->has_buildable_on_overlays) { + cfg->buildable_on_overlays_mask = def->buildable_on_overlays_mask; + cfg->has_buildable_on_overlays = true; + } + if (def->has_buildable_on_rivers) + cfg->buildable_on_rivers = def->buildable_on_rivers; + if (def->has_buildable_adjacent_to_overlays) { + cfg->buildable_adjacent_to_overlays_mask = def->buildable_adjacent_to_overlays_mask; + cfg->has_buildable_adjacent_to_overlays = true; + } + + if (def->has_generated_resource) { + if ((cfg->generated_resource != NULL) && (cfg->generated_resource != defaults->generated_resource)) + free ((void *)cfg->generated_resource); + cfg->generated_resource = def->generated_resource; + def->generated_resource = NULL; + cfg->generated_resource_flags = def->generated_resource_flags; + cfg->generated_resource_id = -1; + } + + if (def->has_dependent_improvements) { + for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { + char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; + if ((cfg->dependent_improvements[i] != NULL) && + (cfg->dependent_improvements[i] != default_value)) + free ((void *)cfg->dependent_improvements[i]); + cfg->dependent_improvements[i] = NULL; + } + + cfg->dependent_improvement_max_index = def->dependent_improvement_max_index; + const int max_entries = ARRAY_LEN (cfg->dependent_improvements); + if (cfg->dependent_improvement_max_index > max_entries) + cfg->dependent_improvement_max_index = max_entries; + for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { + cfg->dependent_improvements[i] = def->dependent_improvements[i]; + def->dependent_improvements[i] = NULL; + } + if (! def->has_img_column_count) { + cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->dependent_improvement_max_index + 1); + cfg->has_img_column_count_override = false; + } + } + + if (def->has_img_paths) { + for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { + char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; + if ((cfg->img_paths[i] != NULL) && + (cfg->img_paths[i] != default_value)) + free ((void *)cfg->img_paths[i]); + cfg->img_paths[i] = NULL; + } + + cfg->img_path_count = def->img_path_count; + const int max_img_paths = ARRAY_LEN (cfg->img_paths); + if (cfg->img_path_count > max_img_paths) + cfg->img_path_count = max_img_paths; + for (int i = 0; i < cfg->img_path_count; i++) { + cfg->img_paths[i] = def->img_paths[i]; + def->img_paths[i] = NULL; + } + } + + if (def->has_img_column_count) { + cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->img_column_count); + cfg->has_img_column_count_override = true; + } + + if (! ensure_culture_variant_art (cfg, section_start_line)) { + free_special_district_override_strings (cfg, defaults); + *cfg = *defaults; + return false; + } + + return true; +} + +bool +add_dynamic_district_from_definition (struct parsed_district_definition * def, int section_start_line) +{ + if ((! def->has_name) || (def->name == NULL)) + return false; + + if ((! def->has_img_paths) || (def->img_path_count <= 0)) + return false; + + int existing_index = -1; + for (int i = is->special_district_count; i < is->district_count; i++) { + if ((is->district_configs[i].name != NULL) && + (strcmp (is->district_configs[i].name, def->name) == 0)) { + existing_index = i; + break; + } + } + + bool reusing_existing = existing_index >= 0; + int dest_index = reusing_existing ? existing_index : (is->special_district_count + is->dynamic_district_count); + + if ((! reusing_existing) && (dest_index >= COUNT_DISTRICT_TYPES)) + return false; + + enum Unit_Command_Values preserved_command = 0; + if (reusing_existing) + preserved_command = is->district_configs[dest_index].command; + + struct district_config new_cfg; + memset (&new_cfg, 0, sizeof new_cfg); + new_cfg.is_dynamic = true; + + new_cfg.name = def->name; + def->name = NULL; + if (def->has_display_name) { + new_cfg.display_name = def->display_name; + if (new_cfg.display_name == NULL) + new_cfg.display_name = new_cfg.name; + def->display_name = NULL; + } else { + new_cfg.display_name = new_cfg.name; + } + + if (def->has_tooltip) { + new_cfg.tooltip = def->tooltip; + def->tooltip = NULL; + } else if (new_cfg.name != NULL) { + char buffer[128]; + snprintf (buffer, sizeof buffer, "Build %s", new_cfg.name); + new_cfg.tooltip = strdup (buffer); + } + + if (def->has_advance_prereqs) { + new_cfg.advance_prereq_count = def->advance_prereq_count; + const int max_entries = ARRAY_LEN (new_cfg.advance_prereqs); + if (new_cfg.advance_prereq_count > max_entries) + new_cfg.advance_prereq_count = max_entries; + for (int i = 0; i < new_cfg.advance_prereq_count; i++) { + new_cfg.advance_prereqs[i] = def->advance_prereqs[i]; + def->advance_prereqs[i] = NULL; + } + def->advance_prereq_count = 0; + } + + if (def->has_obsoleted_by) { + new_cfg.obsoleted_by = def->obsoleted_by; + def->obsoleted_by = NULL; + } + + new_cfg.resource_prereq_count = def->has_resource_prereqs ? def->resource_prereq_count : 0; + const int max_resource_entries = ARRAY_LEN (new_cfg.resource_prereqs); + if (new_cfg.resource_prereq_count > max_resource_entries) + new_cfg.resource_prereq_count = max_resource_entries; + for (int i = 0; i < new_cfg.resource_prereq_count; i++) { + new_cfg.resource_prereqs[i] = def->resource_prereqs[i]; + def->resource_prereqs[i] = NULL; + } + + if (def->has_resource_prereq_on_tile) { + new_cfg.resource_prereq_on_tile = def->resource_prereq_on_tile; + def->resource_prereq_on_tile = NULL; + } + + new_cfg.wonder_prereq_count = def->has_wonder_prereqs ? def->wonder_prereq_count : 0; + const int max_required_wonders = ARRAY_LEN (new_cfg.wonder_prereqs); + if (new_cfg.wonder_prereq_count > max_required_wonders) + new_cfg.wonder_prereq_count = max_required_wonders; + for (int i = 0; i < new_cfg.wonder_prereq_count; i++) { + new_cfg.wonder_prereqs[i] = def->wonder_prereqs[i]; + def->wonder_prereqs[i] = NULL; + } + + new_cfg.natural_wonder_prereq_count = def->has_natural_wonder_prereqs ? def->natural_wonder_prereq_count : 0; + const int max_required_natural_wonders = ARRAY_LEN (new_cfg.natural_wonder_prereqs); + if (new_cfg.natural_wonder_prereq_count > max_required_natural_wonders) + new_cfg.natural_wonder_prereq_count = max_required_natural_wonders; + for (int i = 0; i < new_cfg.natural_wonder_prereq_count; i++) { + new_cfg.natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; + def->natural_wonder_prereqs[i] = NULL; + } + + new_cfg.buildable_on_district_count = def->has_buildable_on_districts ? def->buildable_on_district_count : 0; + const int max_buildable_on_districts = ARRAY_LEN (new_cfg.buildable_on_districts); + if (new_cfg.buildable_on_district_count > max_buildable_on_districts) + new_cfg.buildable_on_district_count = max_buildable_on_districts; + for (int i = 0; i < new_cfg.buildable_on_district_count; i++) { + new_cfg.buildable_on_districts[i] = def->buildable_on_districts[i]; + def->buildable_on_districts[i] = NULL; + } + new_cfg.buildable_on_district_id_count = 0; + new_cfg.has_buildable_on_districts = def->has_buildable_on_districts; + + new_cfg.buildable_adjacent_to_district_count = def->has_buildable_adjacent_to_districts ? def->buildable_adjacent_to_district_count : 0; + const int max_adjacent_to_districts = ARRAY_LEN (new_cfg.buildable_adjacent_to_districts); + if (new_cfg.buildable_adjacent_to_district_count > max_adjacent_to_districts) + new_cfg.buildable_adjacent_to_district_count = max_adjacent_to_districts; + for (int i = 0; i < new_cfg.buildable_adjacent_to_district_count; i++) { + new_cfg.buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; + def->buildable_adjacent_to_districts[i] = NULL; + } + new_cfg.buildable_adjacent_to_district_id_count = 0; + new_cfg.has_buildable_adjacent_to_districts = def->has_buildable_adjacent_to_districts; + + new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; + const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); + if (new_cfg.buildable_by_civ_count > max_civ_names) + new_cfg.buildable_by_civ_count = max_civ_names; + for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { + new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; + def->buildable_by_civs[i] = NULL; + } + + new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; + + new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; + const int max_buildable_traits = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); + if (new_cfg.buildable_by_civ_traits_id_count > max_buildable_traits) + new_cfg.buildable_by_civ_traits_id_count = max_buildable_traits; + for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) + new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; + new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; + + new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; + const int max_buildable_govs = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); + if (new_cfg.buildable_by_civ_govs_id_count > max_buildable_govs) + new_cfg.buildable_by_civ_govs_id_count = max_buildable_govs; + for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) + new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; + new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; + + new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; + const int max_buildable_cultures = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); + if (new_cfg.buildable_by_civ_cultures_id_count > max_buildable_cultures) + new_cfg.buildable_by_civ_cultures_id_count = max_buildable_cultures; + for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) + new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; + new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; + + new_cfg.buildable_by_war_allies = def->has_buildable_by_war_allies ? def->buildable_by_war_allies : false; + new_cfg.buildable_by_pact_allies = def->has_buildable_by_pact_allies ? def->buildable_by_pact_allies : false; + + new_cfg.allow_multiple = def->has_allow_multiple ? def->allow_multiple : false; + new_cfg.vary_img_by_era = def->has_vary_img_by_era ? def->vary_img_by_era : false; + new_cfg.vary_img_by_culture = def->has_vary_img_by_culture ? def->vary_img_by_culture : false; + new_cfg.render_strategy = def->has_render_strategy ? def->render_strategy : DRS_BY_COUNT; + new_cfg.ai_build_strategy = def->has_ai_build_strategy ? def->ai_build_strategy : DABS_DISTRICT; + new_cfg.align_to_coast = def->has_align_to_coast ? def->align_to_coast : false; + new_cfg.draw_over_resources = def->has_draw_over_resources ? def->draw_over_resources : false; + new_cfg.allow_irrigation_from = def->has_allow_irrigation_from ? def->allow_irrigation_from : false; + new_cfg.auto_add_road = def->has_auto_add_road ? def->auto_add_road : false; + new_cfg.auto_add_railroad = def->has_auto_add_railroad ? def->auto_add_railroad : false; + new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; + new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; + new_cfg.x_offset = def->has_x_offset ? def->x_offset : 0; + new_cfg.y_offset = def->has_y_offset ? def->y_offset : 0; + new_cfg.btn_tile_sheet_column = def->has_btn_tile_sheet_column ? def->btn_tile_sheet_column : 0; + new_cfg.btn_tile_sheet_row = def->has_btn_tile_sheet_row ? def->btn_tile_sheet_row : 0; + new_cfg.defense_bonus_percent = def->has_defense_bonus_percent ? def->defense_bonus_percent : 0; + new_cfg.heal_units_in_one_turn = def->has_heal_units_in_one_turn ? def->heal_units_in_one_turn : false; + new_cfg.impassible = def->has_impassible ? def->impassible : false; + new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; + new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; + new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; + new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; + new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; + new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; + new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; + new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); + new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; + new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; + new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; + new_cfg.buildable_without_removal_mask = def->has_buildable_without_removal ? def->buildable_without_removal_mask : 0; + new_cfg.has_buildable_without_removal = def->has_buildable_without_removal; + new_cfg.buildable_on_overlays_mask = def->has_buildable_on_overlays ? def->buildable_on_overlays_mask : 0; + new_cfg.has_buildable_on_overlays = def->has_buildable_on_overlays; + new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; + new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; + new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; + + if (def->has_culture_bonus) + move_bonus_entry_list (&new_cfg.culture_bonus_extras, &def->culture_bonus_extras); + if (def->has_science_bonus) + move_bonus_entry_list (&new_cfg.science_bonus_extras, &def->science_bonus_extras); + if (def->has_food_bonus) + move_bonus_entry_list (&new_cfg.food_bonus_extras, &def->food_bonus_extras); + if (def->has_gold_bonus) + move_bonus_entry_list (&new_cfg.gold_bonus_extras, &def->gold_bonus_extras); + if (def->has_shield_bonus) + move_bonus_entry_list (&new_cfg.shield_bonus_extras, &def->shield_bonus_extras); + if (def->has_happiness_bonus) + move_bonus_entry_list (&new_cfg.happiness_bonus_extras, &def->happiness_bonus_extras); + if (def->has_defense_bonus_percent) + move_bonus_entry_list (&new_cfg.defense_bonus_extras, &def->defense_bonus_extras); + + if (def->has_generated_resource) { + new_cfg.generated_resource = def->generated_resource; + def->generated_resource = NULL; + new_cfg.generated_resource_flags = def->generated_resource_flags; + new_cfg.generated_resource_id = -1; + } else { + new_cfg.generated_resource = NULL; + new_cfg.generated_resource_id = -1; + new_cfg.generated_resource_flags = 0; + } + + new_cfg.dependent_improvement_max_index = def->has_dependent_improvements ? def->dependent_improvement_max_index : 0; + const int max_dependent_entries = ARRAY_LEN (is->district_configs[0].dependent_improvements); + if (new_cfg.dependent_improvement_max_index > max_dependent_entries) + new_cfg.dependent_improvement_max_index = max_dependent_entries; + for (int i = 0; i < new_cfg.dependent_improvement_max_index; i++) { + new_cfg.dependent_improvements[i] = def->dependent_improvements[i]; + def->dependent_improvements[i] = NULL; + } + + new_cfg.img_path_count = def->img_path_count; + const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); + if (new_cfg.img_path_count > max_img_paths) + new_cfg.img_path_count = max_img_paths; + for (int i = 0; i < new_cfg.img_path_count; i++) { + new_cfg.img_paths[i] = def->img_paths[i]; + def->img_paths[i] = NULL; + } + + if (! ensure_culture_variant_art (&new_cfg, section_start_line)) { + free_dynamic_district_config (&new_cfg); + return false; + } + + new_cfg.img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, def->has_img_column_count ? def->img_column_count : new_cfg.dependent_improvement_max_index + 1); + new_cfg.has_img_column_count_override = def->has_img_column_count; + + if (reusing_existing) + new_cfg.command = preserved_command; + else + new_cfg.command = allocate_dynamic_district_command (new_cfg.name); + + struct district_config * dest_cfg = &is->district_configs[dest_index]; + if (reusing_existing) { + enum Unit_Command_Values saved_command = preserved_command; + free_dynamic_district_config (dest_cfg); + *dest_cfg = new_cfg; + dest_cfg->command = saved_command; + } else { + free_dynamic_district_config (dest_cfg); + *dest_cfg = new_cfg; + is->dynamic_district_count += 1; + is->district_count = is->special_district_count + is->dynamic_district_count; + } + + return true; +} + +void +finalize_parsed_district_definition (struct parsed_district_definition * def, int section_start_line) +{ + if ((! def->has_name) || (def->name == NULL)) + return; + + if (! override_special_district_from_definition (def, section_start_line)) + add_dynamic_district_from_definition (def, section_start_line); + + free_parsed_district_definition (def); +} + +void +handle_district_definition_key (struct parsed_district_definition * def, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if (slice_matches_str (key, "name")) { + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + char * name_copy = copy_trimmed_string_or_null (value, 1); + if (name_copy == NULL) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else { + def->name = name_copy; + def->has_name = true; + } + + } else if (slice_matches_str (key, "display_name")) { + if (def->display_name != NULL) { + free (def->display_name); + def->display_name = NULL; + } + def->display_name = copy_trimmed_string_or_null (value, 1); + def->has_display_name = true; + + } else if (slice_matches_str (key, "tooltip")) { + if (def->tooltip != NULL) { + free (def->tooltip); + def->tooltip = NULL; + } + def->tooltip = copy_trimmed_string_or_null (value, 1); + def->has_tooltip = true; + + } else if (slice_matches_str (key, "advance_prereqs") || slice_matches_str (key, "advance_prereq")) { + for (int i = 0; i < def->advance_prereq_count; i++) { + if (def->advance_prereqs[i] != NULL) { + free (def->advance_prereqs[i]); + def->advance_prereqs[i] = NULL; + } + } + def->advance_prereq_count = 0; + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->advance_prereqs, + ARRAY_LEN (def->advance_prereqs), + &list_count, + parse_errors, + line_number, + "advance_prereqs")) { + def->advance_prereq_count = list_count; + def->has_advance_prereqs = true; + } else { + def->advance_prereq_count = 0; + def->has_advance_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "obsoleted_by")) { + if (def->obsoleted_by != NULL) { + free (def->obsoleted_by); + def->obsoleted_by = NULL; + } + def->obsoleted_by = copy_trimmed_string_or_null (value, 1); + def->has_obsoleted_by = true; + + } else if (slice_matches_str (key, "resource_prereqs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->resource_prereqs, + ARRAY_LEN (def->resource_prereqs), + &list_count, + parse_errors, + line_number, + "resource_prereqs")) { + def->resource_prereq_count = list_count; + def->has_resource_prereqs = true; + } else { + def->resource_prereq_count = 0; + def->has_resource_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "resource_prereq_on_tile")) { + if (def->resource_prereq_on_tile != NULL) { + free (def->resource_prereq_on_tile); + def->resource_prereq_on_tile = NULL; + } + def->resource_prereq_on_tile = copy_trimmed_string_or_null (value, 1); + def->has_resource_prereq_on_tile = true; + + } else if (slice_matches_str (key, "wonder_prereqs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->wonder_prereqs, + ARRAY_LEN (def->wonder_prereqs), + &list_count, + parse_errors, + line_number, + "wonder_prereqs")) { + def->wonder_prereq_count = list_count; + def->has_wonder_prereqs = true; + } else { + def->wonder_prereq_count = 0; + def->has_wonder_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "natural_wonder_prereqs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->natural_wonder_prereqs, + ARRAY_LEN (def->natural_wonder_prereqs), + &list_count, + parse_errors, + line_number, + "natural_wonder_prereqs")) { + def->natural_wonder_prereq_count = list_count; + def->has_natural_wonder_prereqs = true; + } else { + def->natural_wonder_prereq_count = 0; + def->has_natural_wonder_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_on_districts")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_on_districts, + ARRAY_LEN (def->buildable_on_districts), + &list_count, + parse_errors, + line_number, + "buildable_on_districts")) { + def->buildable_on_district_count = list_count; + def->has_buildable_on_districts = true; + } else { + def->buildable_on_district_count = 0; + def->has_buildable_on_districts = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_adjacent_to_districts")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_adjacent_to_districts, + ARRAY_LEN (def->buildable_adjacent_to_districts), + &list_count, + parse_errors, + line_number, + "buildable_adjacent_to_districts")) { + def->buildable_adjacent_to_district_count = list_count; + def->has_buildable_adjacent_to_districts = true; + } else { + def->buildable_adjacent_to_district_count = 0; + def->has_buildable_adjacent_to_districts = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civs, + ARRAY_LEN (def->buildable_by_civs), + &list_count, + parse_errors, + line_number, + "buildable_by_civs")) { + def->buildable_by_civ_count = list_count; + def->has_buildable_by_civs = true; + } else { + def->buildable_by_civ_count = 0; + def->has_buildable_by_civs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_traits")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_traits, + ARRAY_LEN (def->buildable_by_civ_traits), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_traits")) { + def->buildable_by_civ_traits_count = list_count; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + char const * trait_name = def->buildable_by_civ_traits[i]; + if ((trait_name == NULL) || (trait_name[0] == '\0')) + continue; + int trait_id = -1; + struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; + if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { + if (def->buildable_by_civ_traits_ids[k] == trait_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) + def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->has_buildable_by_civ_traits = true; + } else { + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + def->has_buildable_by_civ_traits = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_govs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_govs, + ARRAY_LEN (def->buildable_by_civ_govs), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_govs")) { + def->buildable_by_civ_govs_count = list_count; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + char const * gov_name = def->buildable_by_civ_govs[i]; + if ((gov_name == NULL) || (gov_name[0] == '\0')) + continue; + int gov_id = -1; + struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; + if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { + if (def->buildable_by_civ_govs_ids[k] == gov_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) + def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->has_buildable_by_civ_govs = true; + } else { + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + def->has_buildable_by_civ_govs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_cultures, + ARRAY_LEN (def->buildable_by_civ_cultures), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_cultures")) { + def->buildable_by_civ_cultures_count = list_count; + def->buildable_by_civ_cultures_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + char const * culture_name = def->buildable_by_civ_cultures[i]; + if ((culture_name == NULL) || (culture_name[0] == '\0')) + continue; + int culture_id = -1; + struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; + if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { + if (def->buildable_by_civ_cultures_ids[k] == culture_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) + def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->has_buildable_by_civ_cultures = true; + } else { + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + def->has_buildable_by_civ_cultures = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_war_allies")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_by_war_allies = (ival != 0); + def->has_buildable_by_war_allies = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "buildable_by_pact_allies")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_by_pact_allies = (ival != 0); + def->has_buildable_by_pact_allies = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "img_paths")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->img_paths, + ARRAY_LEN (def->img_paths), + &list_count, + parse_errors, + line_number, + "img_paths")) { + def->img_path_count = list_count; + def->has_img_paths = true; + } else { + def->img_path_count = 0; + def->has_img_paths = false; + } + free (value_text); + + } else if (slice_matches_str (key, "img_column_count")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_column_count = ival; + def->has_img_column_count = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "dependent_improvs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->dependent_improvements, + ARRAY_LEN (def->dependent_improvements), + &list_count, + parse_errors, + line_number, + "dependent_improvs")) { + def->dependent_improvement_max_index = list_count; + def->has_dependent_improvements = true; + } else { + def->dependent_improvement_max_index = 0; + def->has_dependent_improvements = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_on")) { + unsigned int mask; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { + def->buildable_square_types_mask = mask; + def->has_buildable_on = true; + } + + } else if (slice_matches_str (key, "buildable_without_removal")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_without_removal")) { + def->buildable_without_removal_mask = mask; + def->has_buildable_without_removal = true; + } else { + def->has_buildable_without_removal = false; + } + + } else if (slice_matches_str (key, "buildable_on_overlays")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_on_overlays")) { + def->buildable_on_overlays_mask = mask; + def->has_buildable_on_overlays = true; + } else { + def->has_buildable_on_overlays = false; + } + + } else if (slice_matches_str (key, "buildable_on_rivers")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_on_rivers = (ival != 0); + def->has_buildable_on_rivers = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "buildable_adjacent_to")) { + unsigned int mask; + def->buildable_adjacent_to_allows_city = false; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { + def->buildable_adjacent_to_square_types_mask = mask; + def->has_buildable_adjacent_to = true; + } + + } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { + def->buildable_adjacent_to_overlays_mask = mask; + def->has_buildable_adjacent_to_overlays = true; + } else { + def->has_buildable_adjacent_to_overlays = false; + } + + } else if (slice_matches_str (key, "allow_multiple")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->allow_multiple = (ival != 0); + def->has_allow_multiple = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "vary_img_by_era")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->vary_img_by_era = (ival != 0); + def->has_vary_img_by_era = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "vary_img_by_culture")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->vary_img_by_culture = (ival != 0); + def->has_vary_img_by_culture = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "render_strategy")) { + char * strategy = copy_trimmed_string_or_null (value, 1); + if (strategy == NULL) { + def->has_render_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else if (strcmp (strategy, "by-count") == 0) { + def->render_strategy = DRS_BY_COUNT; + def->has_render_strategy = true; + } else if (strcmp (strategy, "by-building") == 0) { + def->render_strategy = DRS_BY_BUILDING; + def->has_render_strategy = true; + } else { + def->has_render_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected \"by-count\" or \"by-building\")"); + } + if (strategy != NULL) + free (strategy); + + } else if (slice_matches_str (key, "ai_build_strategy")) { + char * strategy = copy_trimmed_string_or_null (value, 1); + if (strategy == NULL) { + def->has_ai_build_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else if (strcmp (strategy, "district") == 0) { + def->ai_build_strategy = DABS_DISTRICT; + def->has_ai_build_strategy = true; + } else if (strcmp (strategy, "tile-improvement") == 0) { + def->ai_build_strategy = DABS_TILE_IMPROVEMENT; + def->has_ai_build_strategy = true; + } else { + def->has_ai_build_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected \"district\" or \"tile-improvement\")"); + } + if (strategy != NULL) + free (strategy); + + } else if (slice_matches_str (key, "align_to_coast")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->align_to_coast = (ival != 0); + def->has_align_to_coast = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "draw_over_resources")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->draw_over_resources = (ival != 0); + def->has_draw_over_resources = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "allow_irrigation_from")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->allow_irrigation_from = (ival != 0); + def->has_allow_irrigation_from = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "auto_add_road")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->auto_add_road = (ival != 0); + def->has_auto_add_road = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "auto_add_railroad")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->auto_add_railroad = (ival != 0); + def->has_auto_add_railroad = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "impassible")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible = (ival != 0); + def->has_impassible = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "impassible_to_wheeled")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible_to_wheeled = (ival != 0); + def->has_impassible_to_wheeled = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "custom_width")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_width = ival; + def->has_custom_width = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "custom_height")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_height = ival; + def->has_custom_height = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "x_offset")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->x_offset = ival; + def->has_x_offset = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "y_offset")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->y_offset = ival; + def->has_y_offset = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "btn_tile_sheet_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->btn_tile_sheet_column = ival; + def->has_btn_tile_sheet_column = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "btn_tile_sheet_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->btn_tile_sheet_row = ival; + def->has_btn_tile_sheet_row = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "defense_bonus_percent")) { + if (parse_district_bonus_entries (value, &def->defense_bonus_percent, &def->defense_bonus_extras, parse_errors, line_number, key)) { + def->has_defense_bonus_percent = true; + } else { + def->has_defense_bonus_percent = false; + } + + } else if (slice_matches_str (key, "heal_units_in_one_turn")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->heal_units_in_one_turn = (ival != 0); + def->has_heal_units_in_one_turn = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "culture_bonus")) { + if (parse_district_bonus_entries (value, &def->culture_bonus, &def->culture_bonus_extras, parse_errors, line_number, key)) { + def->has_culture_bonus = true; + } else { + def->has_culture_bonus = false; + } + + } else if (slice_matches_str (key, "science_bonus")) { + if (parse_district_bonus_entries (value, &def->science_bonus, &def->science_bonus_extras, parse_errors, line_number, key)) { + def->has_science_bonus = true; + } else { + def->has_science_bonus = false; + } + + } else if (slice_matches_str (key, "food_bonus")) { + if (parse_district_bonus_entries (value, &def->food_bonus, &def->food_bonus_extras, parse_errors, line_number, key)) { + def->has_food_bonus = true; + } else { + def->has_food_bonus = false; + } + + } else if (slice_matches_str (key, "gold_bonus")) { + if (parse_district_bonus_entries (value, &def->gold_bonus, &def->gold_bonus_extras, parse_errors, line_number, key)) { + def->has_gold_bonus = true; + } else { + def->has_gold_bonus = false; + } + + } else if (slice_matches_str (key, "shield_bonus")) { + if (parse_district_bonus_entries (value, &def->shield_bonus, &def->shield_bonus_extras, parse_errors, line_number, key)) { + def->has_shield_bonus = true; + } else { + def->has_shield_bonus = false; + } + + } else if (slice_matches_str (key, "happiness_bonus")) { + if (parse_district_bonus_entries (value, &def->happiness_bonus, &def->happiness_bonus_extras, parse_errors, line_number, key)) { + def->has_happiness_bonus = true; + } else { + def->has_happiness_bonus = false; + } + + } else if (slice_matches_str (key, "generated_resource")) { + if (def->generated_resource != NULL) { + free (def->generated_resource); + def->generated_resource = NULL; + } + def->generated_resource_flags = 0; + + char * value_text = trim_and_extract_slice (value, 0); + if ((value_text == NULL) || (*value_text == '\0')) { + def->generated_resource = NULL; + def->has_generated_resource = true; + } else { + char * cursor = value_text; + struct string_slice resource_name = {0}; + struct string_slice token; + bool ok = true; + while (skip_white_space (&cursor) && parse_string (&cursor, &token)) { + if (slice_matches_str (&token, "local")) + def->generated_resource_flags |= MF_LOCAL; + else if (slice_matches_str (&token, "no-tech-req")) + def->generated_resource_flags |= MF_NO_TECH_REQ; + else if (slice_matches_str (&token, "yields")) + def->generated_resource_flags |= MF_YIELDS; + else if (resource_name.str == NULL) + resource_name = token; + else { + ok = false; + break; + } + } + + if (! ok || (resource_name.str == NULL)) { + def->generated_resource = NULL; + def->has_generated_resource = false; + def->generated_resource_flags = 0; + add_key_parse_error (parse_errors, line_number, key, value, + "(expected resource name plus optional flags: local, yields, no-tech-req)"); + } else { + def->generated_resource = extract_slice (&resource_name); + def->has_generated_resource = true; + } + } + free (value_text); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +bool +line_is_empty_or_comment (struct string_slice const * trimmed) +{ + return ((trimmed == NULL) || (trimmed->len == 0) || (trimmed->str[0] == ';') || (trimmed->str[0] == '[')); +} + +bool +file_exists_at_path (char const * path) +{ + if ((path == NULL) || (path[0] == '\0')) + return false; + + HANDLE file = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + return false; + + CloseHandle (file); + return true; +} + +void +load_dynamic_district_config_file (char const * file_path, + int path_is_relative_to_mod_dir, + int log_missing, + int drop_existing_configs) +{ + char path[MAX_PATH]; + if (path_is_relative_to_mod_dir) { + if (is->mod_rel_dir == NULL) + return; + snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); + } else { + strncpy (path, file_path, sizeof path); + } + path[(sizeof path) - 1] = '\0'; + + char * text = file_to_string (path); + if (text == NULL) { + if (log_missing) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] Districts config file not found: %s", path); + (*p_OutputDebugStringA) (ss); + } + return; + } + + if (drop_existing_configs) + reset_regular_district_configs (); + + struct parsed_district_definition def; + init_parsed_district_definition (&def); + bool in_section = false; + int section_start_line = 0; + int line_number = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + bool has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if ((directive.len > 0) && slice_matches_str (&directive, "District")) { + if (in_section) + finalize_parsed_district_definition (&def, section_start_line); + in_section = true; + section_start_line = line_number; + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); + if (status == KVP_NO_EQUALS) { + char * line_text = extract_slice (&trimmed); + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); + err->text[(sizeof err->text) - 1] = '\0'; + free (line_text); + cursor = has_newline ? line_end + 1 : line_end; + continue; + } else if (status == KVP_EMPTY_KEY) { + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); + err->text[(sizeof err->text) - 1] = '\0'; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + handle_district_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) + finalize_parsed_district_definition (&def, section_start_line); + + free_parsed_district_definition (&def); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + snprintf (is->current_districts_config_path, sizeof is->current_districts_config_path, path); + + if (parse_errors != NULL || unrecognized_keys != NULL) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "District Config errors in %s:", path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + if (parse_errors != NULL) { + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", false); + PopupForm_add_text (popup, __, "Unrecognized keys:", false); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + patch_show_popup (popup, __, 0, 0); + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); + } +} + +void +load_dynamic_district_configs () +{ + char * scenario_filename = "scenario.districts_config.txt"; + char * scenario_district_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + if ((scenario_district_config_path != NULL) && + (0 != strcmp (scenario_filename, scenario_district_config_path)) && + file_exists_at_path (scenario_district_config_path)) { + load_dynamic_district_config_file (scenario_district_config_path, 0, 0, 1); + return; + } + + if (is->mod_rel_dir != NULL) { + char user_path[MAX_PATH]; + snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_config.txt"); + user_path[(sizeof user_path) - 1] = '\0'; + if (file_exists_at_path (user_path)) { + load_dynamic_district_config_file ("user.districts_config.txt", 1, 0, 1); + return; + } + } + + load_dynamic_district_config_file ("default.districts_config.txt", 1, 1, 1); +} + +void +init_parsed_wonder_definition (struct parsed_wonder_definition * def) +{ + memset (def, 0, sizeof *def); + def->buildable_square_types_mask = district_default_buildable_mask (); + def->buildable_adjacent_to_square_types_mask = 0; + def->buildable_adjacent_to_overlays_mask = 0; + def->buildable_on_rivers = false; + def->buildable_adjacent_to_allows_city = false; + for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_traits_ids); i++) + def->buildable_by_civ_traits_ids[i] = -1; + for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_govs_ids); i++) + def->buildable_by_civ_govs_ids[i] = -1; + for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_cultures_ids); i++) + def->buildable_by_civ_cultures_ids[i] = -1; +} + +void +free_parsed_wonder_definition (struct parsed_wonder_definition * def) +{ + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + + for (int i = 0; i < def->buildable_by_civ_count; i++) { + if (def->buildable_by_civs[i] != NULL) { + free (def->buildable_by_civs[i]); + def->buildable_by_civs[i] = NULL; + } + } + def->buildable_by_civ_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + + init_parsed_wonder_definition (def); +} + +bool +add_dynamic_wonder_from_definition (struct parsed_wonder_definition * def, int section_start_line) +{ + int existing_index = -1; + for (int i = 0; i < is->wonder_district_count; i++) { + if ((is->wonder_district_configs[i].wonder_name != NULL) && + (strcmp (is->wonder_district_configs[i].wonder_name, def->name) == 0)) { + existing_index = i; + break; + } + } + + int dest = (existing_index >= 0) ? existing_index : is->wonder_district_count; + if ((dest < 0) || (dest >= MAX_WONDER_DISTRICT_TYPES)) + return false; + + struct wonder_district_config new_cfg; + memset (&new_cfg, 0, sizeof new_cfg); + new_cfg.index = dest; + new_cfg.is_dynamic = true; + new_cfg.wonder_name = strdup (def->name); + new_cfg.img_path = (def->img_path != NULL) ? strdup (def->img_path) : strdup ("Wonders.pcx"); + new_cfg.img_row = def->img_row; + new_cfg.img_column = def->img_column; + new_cfg.img_construct_row = def->img_construct_row; + new_cfg.img_construct_column = def->img_construct_column; + new_cfg.img_alt_dir_construct_row = def->img_alt_dir_construct_row; + new_cfg.img_alt_dir_construct_column = def->img_alt_dir_construct_column; + new_cfg.img_alt_dir_row = def->img_alt_dir_row; + new_cfg.img_alt_dir_column = def->img_alt_dir_column; + new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; + new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; + new_cfg.enable_img_alt_dir = def->enable_img_alt_dir; + new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); + new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; + new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; + new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; + new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; + new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; + const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); + if (new_cfg.buildable_by_civ_count > max_civ_names) + new_cfg.buildable_by_civ_count = max_civ_names; + for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { + new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; + def->buildable_by_civs[i] = NULL; + } + new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; + new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; + const int max_trait_entries = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); + if (new_cfg.buildable_by_civ_traits_id_count > max_trait_entries) + new_cfg.buildable_by_civ_traits_id_count = max_trait_entries; + for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) + new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; + new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; + new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; + const int max_gov_entries = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); + if (new_cfg.buildable_by_civ_govs_id_count > max_gov_entries) + new_cfg.buildable_by_civ_govs_id_count = max_gov_entries; + for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) + new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; + new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; + new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; + const int max_culture_entries = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); + if (new_cfg.buildable_by_civ_cultures_id_count > max_culture_entries) + new_cfg.buildable_by_civ_cultures_id_count = max_culture_entries; + for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) + new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; + new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; + new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; + new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; + + if (existing_index >= 0) { + struct wonder_district_config * cfg = &is->wonder_district_configs[existing_index]; + free_dynamic_wonder_config (cfg); + *cfg = new_cfg; + cfg->index = existing_index; + } else { + struct wonder_district_config * cfg = &is->wonder_district_configs[dest]; + free_dynamic_wonder_config (cfg); + *cfg = new_cfg; + is->wonder_district_count += 1; + } + + return true; +} + +void +finalize_parsed_wonder_definition (struct parsed_wonder_definition * def, + int section_start_line, + struct error_line ** parse_errors) +{ + bool ok = true; + + if ((! def->has_name) || (def->name == NULL)) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_construct_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_row (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_construct_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_column (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (def->enable_img_alt_dir) { + if (! def->has_img_alt_dir_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_row (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_alt_dir_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_column (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_alt_dir_construct_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_row (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_alt_dir_construct_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_column (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + } + + if (ok) + add_dynamic_wonder_from_definition (def, section_start_line); + + free_parsed_wonder_definition (def); +} + +void +handle_wonder_definition_key (struct parsed_wonder_definition * def, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if (slice_matches_str (key, "name")) { + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else { + char * name_copy = extract_slice (&unquoted); + if (name_copy == NULL) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); + } else { + def->name = name_copy; + def->has_name = true; + } + } + + } else if (slice_matches_str (key, "img_path")) { + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_img_path = false; + } else { + char * path_copy = extract_slice (&unquoted); + if (path_copy == NULL) { + def->has_img_path = false; + } else { + def->img_path = path_copy; + def->has_img_path = true; + } + } + + } else if (slice_matches_str (key, "img_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_row = ival; + def->has_img_row = true; + } else { + def->has_img_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_column = ival; + def->has_img_column = true; + } else { + def->has_img_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_construct_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_construct_row = ival; + def->has_img_construct_row = true; + } else { + def->has_img_construct_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_construct_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_construct_column = ival; + def->has_img_construct_column = true; + } else { + def->has_img_construct_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_construct_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_construct_row = ival; + def->has_img_alt_dir_construct_row = true; + } else { + def->has_img_alt_dir_construct_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_construct_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_construct_column = ival; + def->has_img_alt_dir_construct_column = true; + } else { + def->has_img_alt_dir_construct_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_row = ival; + def->has_img_alt_dir_row = true; + } else { + def->has_img_alt_dir_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_column = ival; + def->has_img_alt_dir_column = true; + } else { + def->has_img_alt_dir_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "custom_width")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_width = ival; + def->has_custom_width = true; + } else { + def->has_custom_width = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "custom_height")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_height = ival; + def->has_custom_height = true; + } else { + def->has_custom_height = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "enable_img_alt_dir")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->enable_img_alt_dir = (ival != 0); + def->has_enable_img_alt_dir = true; + } else { + def->has_enable_img_alt_dir = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "buildable_on")) { + unsigned int mask; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { + def->buildable_square_types_mask = mask; + def->has_buildable_on = true; + } else { + def->has_buildable_on = false; + } + + } else if (slice_matches_str (key, "buildable_on_rivers")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_on_rivers = (ival != 0); + def->has_buildable_on_rivers = true; + } else { + def->has_buildable_on_rivers = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "buildable_adjacent_to")) { + unsigned int mask; + def->buildable_adjacent_to_allows_city = false; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { + def->buildable_adjacent_to_square_types_mask = mask; + def->has_buildable_adjacent_to = true; + } else { + def->has_buildable_adjacent_to = false; + } + + } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { + def->buildable_adjacent_to_overlays_mask = mask; + def->has_buildable_adjacent_to_overlays = true; + } else { + def->has_buildable_adjacent_to_overlays = false; + } + + } else if (slice_matches_str (key, "buildable_by_civs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civs, + ARRAY_LEN (def->buildable_by_civs), + &list_count, + parse_errors, + line_number, + "buildable_by_civs")) { + def->buildable_by_civ_count = list_count; + def->has_buildable_by_civs = true; + } else { + def->buildable_by_civ_count = 0; + def->has_buildable_by_civs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_traits")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_traits, + ARRAY_LEN (def->buildable_by_civ_traits), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_traits")) { + def->buildable_by_civ_traits_count = list_count; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + char const * trait_name = def->buildable_by_civ_traits[i]; + if ((trait_name == NULL) || (trait_name[0] == '\0')) + continue; + int trait_id = -1; + struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; + if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { + if (def->buildable_by_civ_traits_ids[k] == trait_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) + def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->has_buildable_by_civ_traits = true; + } else { + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + def->has_buildable_by_civ_traits = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_govs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_govs, + ARRAY_LEN (def->buildable_by_civ_govs), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_govs")) { + def->buildable_by_civ_govs_count = list_count; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + char const * gov_name = def->buildable_by_civ_govs[i]; + if ((gov_name == NULL) || (gov_name[0] == '\0')) + continue; + int gov_id = -1; + struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; + if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { + if (def->buildable_by_civ_govs_ids[k] == gov_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) + def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->has_buildable_by_civ_govs = true; + } else { + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + def->has_buildable_by_civ_govs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_cultures, + ARRAY_LEN (def->buildable_by_civ_cultures), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_cultures")) { + def->buildable_by_civ_cultures_count = list_count; + def->buildable_by_civ_cultures_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + char const * culture_name = def->buildable_by_civ_cultures[i]; + if ((culture_name == NULL) || (culture_name[0] == '\0')) + continue; + int culture_id = -1; + struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; + if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { + if (def->buildable_by_civ_cultures_ids[k] == culture_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) + def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->has_buildable_by_civ_cultures = true; + } else { + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + def->has_buildable_by_civ_cultures = false; + } + free (value_text); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +void +load_dynamic_wonder_config_file (char const * file_path, + int path_is_relative_to_mod_dir, + int log_missing, + int drop_existing_configs) +{ + char path[MAX_PATH]; + if (path_is_relative_to_mod_dir) { + if (is->mod_rel_dir == NULL) + return; + snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); + } else { + strncpy (path, file_path, sizeof path); + } + path[(sizeof path) - 1] = '\0'; + + char * text = file_to_string (path); + if (text == NULL) { + if (log_missing) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] Wonders config file not found: %s", path); + (*p_OutputDebugStringA) (ss); + } + return; + } + + if (drop_existing_configs) + reset_wonder_district_configs (); + + struct parsed_wonder_definition def; + init_parsed_wonder_definition (&def); + bool in_section = false; + int section_start_line = 0; + int line_number = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + bool has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { + if (in_section) + finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); + in_section = true; + section_start_line = line_number; + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); + if (status == KVP_NO_EQUALS) { + char * line_text = extract_slice (&trimmed); + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); + err->text[(sizeof err->text) - 1] = '\0'; + free (line_text); + cursor = has_newline ? line_end + 1 : line_end; + continue; + } else if (status == KVP_EMPTY_KEY) { + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); + err->text[(sizeof err->text) - 1] = '\0'; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + handle_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) + finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); + + free_parsed_wonder_definition (&def); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + + if (parse_errors != NULL || unrecognized_keys != NULL) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "Wonder District Config errors in %s:", path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + if (parse_errors != NULL) { + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", false); + PopupForm_add_text (popup, __, "Unrecognized keys:", false); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + patch_show_popup (popup, __, 0, 0); + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); + } +} + +void +load_dynamic_wonder_configs () +{ + char * scenario_filename = "scenario.districts_wonders_config.txt"; + char * scenario_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + if ((scenario_wonder_config_path != NULL) && + (0 != strcmp (scenario_filename, scenario_wonder_config_path)) && + file_exists_at_path (scenario_wonder_config_path)) { + load_dynamic_wonder_config_file (scenario_wonder_config_path, 0, 0, 1); + return; + } + + if (is->mod_rel_dir != NULL) { + char user_path[MAX_PATH]; + snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_wonders_config.txt"); + user_path[(sizeof user_path) - 1] = '\0'; + if (file_exists_at_path (user_path)) { + load_dynamic_wonder_config_file ("user.districts_wonders_config.txt", 1, 0, 1); + return; + } + } + + load_dynamic_wonder_config_file ("default.districts_wonders_config.txt", 1, 1, 1); +} + +void +init_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) +{ + memset (def, 0, sizeof *def); + def->terrain_type = SQ_Grassland; + def->adjacent_to = (enum SquareTypes)SQ_INVALID; + def->adjacency_dir = DIR_ZERO; +} + +void +free_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) +{ + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + init_parsed_natural_wonder_definition (def); +} + +bool +add_natural_wonder_from_definition (struct parsed_natural_wonder_definition * def, int section_start_line) +{ + if ((def == NULL) || (def->name == NULL)) + return false; + + int existing_index; + bool has_existing = stable_look_up (&is->natural_wonder_name_to_id, def->name, &existing_index); + + int dest = has_existing ? existing_index : is->natural_wonder_count; + if ((dest < 0) || (dest >= MAX_NATURAL_WONDER_DISTRICT_TYPES)) + return false; + + struct natural_wonder_district_config new_cfg; + memset (&new_cfg, 0, sizeof new_cfg); + new_cfg.index = dest; + new_cfg.is_dynamic = true; + new_cfg.adjacent_to = (enum SquareTypes)SQ_INVALID; + new_cfg.adjacency_dir = DIR_ZERO; + + char * name_copy = strdup (def->name); + if (name_copy == NULL) + return false; + new_cfg.name = name_copy; + + char const * img_path_src = def->img_path; + char * img_copy = strdup (img_path_src); + if (img_copy == NULL) { + free (name_copy); + return false; + } + new_cfg.img_path = img_copy; + new_cfg.img_row = def->img_row; + new_cfg.img_column = def->img_column; + new_cfg.terrain_type = def->terrain_type; + new_cfg.adjacent_to = def->adjacent_to; + new_cfg.adjacency_dir = def->adjacency_dir; + new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; + new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; + new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; + new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; + new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; + new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; + new_cfg.impassible = def->has_impassible ? def->impassible : false; + new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; + + if (has_existing) { + struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[existing_index]; + free_dynamic_natural_wonder_config (cfg); + *cfg = new_cfg; + } else { + struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[dest]; + free_dynamic_natural_wonder_config (cfg); + *cfg = new_cfg; + is->natural_wonder_count = dest + 1; + stable_insert (&is->natural_wonder_name_to_id, new_cfg.name, dest); + } + + return true; +} + +void +finalize_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def, + int section_start_line, + struct error_line ** parse_errors) +{ + bool ok = true; + + if ((! def->has_name) || (def->name == NULL)) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_terrain_type) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: terrain_type (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + if (ok) + add_natural_wonder_from_definition (def, section_start_line); + + free_parsed_natural_wonder_definition (def); +} + +void +handle_natural_wonder_definition_key (struct parsed_natural_wonder_definition * def, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if (slice_matches_str (key, "name")) { + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else { + char * name_copy = extract_slice (&unquoted); + if (name_copy == NULL) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); + } else { + def->name = name_copy; + def->has_name = true; + } + } + + } else if (slice_matches_str (key, "terrain_type")) { + enum SquareTypes terrain; + if (read_natural_wonder_terrain_type (value, &terrain)) { + def->terrain_type = terrain; + def->has_terrain_type = true; + } else { + def->has_terrain_type = false; + add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized terrain type)"); + } + + } else if (slice_matches_str (key, "adjacent_to")) { + enum SquareTypes adj; + if (read_tile_terrain_type_value (value, &adj)) { + def->adjacent_to = adj; + def->has_adjacent_to = true; + } else { + def->adjacent_to = (enum SquareTypes)SQ_INVALID; + def->has_adjacent_to = false; + add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized tile terrain type)"); + } + + } else if (slice_matches_str (key, "adjacency_dir")) { + enum direction dir; + if (read_direction_value (value, &dir)) { + def->adjacency_dir = dir; + def->has_adjacency_dir = true; + } else { + def->adjacency_dir = DIR_ZERO; + def->has_adjacency_dir = false; + add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized direction)"); + } + + } else if (slice_matches_str (key, "img_path")) { + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_img_path = false; + } else { + char * path_copy = extract_slice (&unquoted); + if (path_copy == NULL) { + def->has_img_path = false; + } else { + def->img_path = path_copy; + def->has_img_path = true; + } + } + + } else if (slice_matches_str (key, "img_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_row = ival; + def->has_img_row = true; + } else { + def->has_img_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_column = ival; + def->has_img_column = true; + } else { + def->has_img_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "culture_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->culture_bonus = ival; + def->has_culture_bonus = true; + } else { + def->has_culture_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "science_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->science_bonus = ival; + def->has_science_bonus = true; + } else { + def->has_science_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "food_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->food_bonus = ival; + def->has_food_bonus = true; + } else { + def->has_food_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "gold_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->gold_bonus = ival; + def->has_gold_bonus = true; + } else { + def->has_gold_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "shield_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->shield_bonus = ival; + def->has_shield_bonus = true; + } else { + def->has_shield_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "happiness_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->happiness_bonus = ival; + def->has_happiness_bonus = true; + } else { + def->has_happiness_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "impassible")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible = (ival != 0); + def->has_impassible = true; + } else { + def->has_impassible = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "impassible_to_wheeled")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible_to_wheeled = (ival != 0); + def->has_impassible_to_wheeled = true; + } else { + def->has_impassible_to_wheeled = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +void +load_natural_wonder_config_file (char const * file_path, + int path_is_relative_to_mod_dir, + int log_missing, + int drop_existing_configs) +{ + char path[MAX_PATH]; + if (path_is_relative_to_mod_dir) { + if (is->mod_rel_dir == NULL) + return; + snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); + } else { + strncpy (path, file_path, sizeof path); + } + path[(sizeof path) - 1] = '\0'; + + char * text = file_to_string (path); + if (text == NULL) { + if (log_missing) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] Natural wonders config file not found: %s", path); + (*p_OutputDebugStringA) (ss); + } + return; + } + + if (drop_existing_configs) + reset_natural_wonder_configs (); + + struct parsed_natural_wonder_definition def; + init_parsed_natural_wonder_definition (&def); + bool in_section = false; + int section_start_line = 0; + int line_number = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + bool has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { + if (in_section) + finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); + in_section = true; + section_start_line = line_number; + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); + if (status == KVP_NO_EQUALS) { + char * line_text = extract_slice (&trimmed); + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); + err->text[(sizeof err->text) - 1] = '\0'; + free (line_text); + cursor = has_newline ? line_end + 1 : line_end; + continue; + } else if (status == KVP_EMPTY_KEY) { + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); + err->text[(sizeof err->text) - 1] = '\0'; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + handle_natural_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) + finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); + + free_parsed_natural_wonder_definition (&def); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + + if (parse_errors != NULL || unrecognized_keys != NULL) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "Natural Wonder Config errors in %s:", path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + if (parse_errors != NULL) { + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", false); + PopupForm_add_text (popup, __, "Unrecognized keys:", false); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + patch_show_popup (popup, __, 0, 0); + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); + } +} + +void +load_natural_wonder_configs () +{ + char * scenario_filename = "scenario.districts_natural_wonders_config.txt"; + char * scenario_natural_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + if ((scenario_natural_wonder_config_path != NULL) && + (0 != strcmp (scenario_filename, scenario_natural_wonder_config_path)) && + file_exists_at_path (scenario_natural_wonder_config_path)) { + load_natural_wonder_config_file (scenario_natural_wonder_config_path, 0, 0, 1); + return; + } + + if (is->mod_rel_dir != NULL) { + char user_path[MAX_PATH]; + snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_natural_wonders_config.txt"); + user_path[(sizeof user_path) - 1] = '\0'; + if (file_exists_at_path (user_path)) { + load_natural_wonder_config_file ("user.districts_natural_wonders_config.txt", 1, 0, 1); + return; + } + } + + load_natural_wonder_config_file ("default.districts_natural_wonders_config.txt", 1, 1, 1); +} + +bool +district_config_has_dependent_improvement (struct district_config * cfg, char const * name) +{ + if ((cfg == NULL) || (name == NULL) || (name[0] == '\0')) + return false; + + for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { + char const * existing = cfg->dependent_improvements[i]; + if ((existing != NULL) && (strcmp (existing, name) == 0)) + return true; + } + return false; +} + +bool +find_civ_trait_id_by_name (struct string_slice const * name, int * out_id) +{ + if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) + return false; + + struct trait_entry { enum c3x_label label; char const * fallback_name; int id; } traits[] = { + {CL_AGRICULTURAL, "Agricultural", 6}, + {CL_COMMERCIAL, "Commercial", 1}, + {CL_EXPANSIONIST, "Expansionist", 2}, + {CL_INDUSTRIOUS, "Industrious", 5}, + {CL_MILITARISTIC, "Militaristic", 0}, + {CL_RELIGIOUS, "Religious", 4}, + {CL_SCIENTIFIC, "Scientific", 3}, + {CL_SEAFARING, "Seafaring", 7} + }; + + for (int i = 0; i < ARRAY_LEN (traits); i++) { + char const * localized_name = is->c3x_labels[traits[i].label]; + if (((localized_name != NULL) && (localized_name[0] != '\0') && slice_matches_str (name, localized_name)) + || slice_matches_str (name, traits[i].fallback_name)) { + *out_id = traits[i].id; + return true; + } + } + + return false; +} + +bool +find_civ_culture_id_by_name (struct string_slice const * name, int * out_id) +{ + if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) + return false; + + struct culture_entry { char const * name; int id; } cultures[] = { + {"American", 0}, + {"AMERICAN", 0}, + {"AMER", 0}, + {"European", 1}, + {"EUROPEAN", 1}, + {"EURO", 1}, + {"Roman", 2}, + {"ROMAN", 2}, + {"Mid East", 3}, + {"Mideast", 3}, + {"MIDEAST", 3}, + {"Asian", 4}, + {"ASIAN", 4} + }; + + for (int i = 0; i < ARRAY_LEN (cultures); i++) { + if (slice_matches_str (name, cultures[i].name)) { + *out_id = cultures[i].id; + return true; + } + } + + return false; +} + +int +find_district_index_by_name (char const * name) +{ + if ((name == NULL) || (name[0] == '\0')) + return -1; + + for (int i = 0; i < is->district_count; i++) { + char const * existing = is->district_configs[i].name; + if ((existing != NULL) && (strcmp (existing, name) == 0)) + return i; + } + + return -1; +} + +void +resolve_counter_rule_districts (struct error_line ** parse_errors) +{ + struct c3x_config * cfg = &is->current_config; + + for (int i = 0; i < cfg->count_counter_rules; i++) { + struct counter_rule * rule = &cfg->counter_rules[i]; + rule->district_id = -1; + + if ((rule->district_name == NULL) || (rule->district_name[0] == '\0')) + continue; + + int district_id = find_district_index_by_name (rule->district_name); + if (district_id >= 0) { + rule->district_id = district_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ counter_rule district \"%s\" not found", rule->district_name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } +} + +int +find_wonder_district_index_by_name (char const * name) +{ + if ((name == NULL) || (name[0] == '\0')) + return -1; + + int improv_id; + if (! stable_look_up (&is->building_name_to_id, (char *)name, &improv_id)) + return -1; + + return find_wonder_config_index_by_improvement_id (improv_id); +} + +int +find_natural_wonder_index_by_name (char const * name) +{ + if ((name == NULL) || (name[0] == '\0') || (is == NULL)) + return -1; + + for (int i = 0; i < is->natural_wonder_count; i++) { + char const * existing = is->natural_wonder_configs[i].name; + if ((existing != NULL) && (strcmp (existing, name) == 0)) + return i; + } + return -1; +} + +void +set_wonders_dependent_on_wonder_district (void) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_wonder_districts) + return; + + struct district_config * cfg = &is->district_configs[WONDER_DISTRICT_ID]; + for (int wi = 0; wi < is->wonder_district_count; wi++) { + char const * wonder_name = is->wonder_district_configs[wi].wonder_name; + if ((wonder_name == NULL) || (wonder_name[0] == '\0')) + continue; + if (district_config_has_dependent_improvement (cfg, wonder_name)) + continue; + + int dest = cfg->dependent_improvement_max_index; + if (dest >= ARRAY_LEN (cfg->dependent_improvements)) { + continue; + } + + char * copy = strdup (wonder_name); + if (copy == NULL) { + continue; + } + + cfg->dependent_improvements[dest] = copy; + cfg->dependent_improvement_max_index = dest + 1; + } + + if (! cfg->has_img_column_count_override && + (cfg->img_column_count < cfg->dependent_improvement_max_index + 1)) + cfg->img_column_count = cfg->dependent_improvement_max_index + 1; +} + +void +resolve_district_bonus_building_entries (struct district_bonus_list * list, + char const * district_name, + char const * bonus_name, + struct error_line ** parse_errors) +{ + if (list == NULL) + return; + + for (int i = 0; i < list->count; i++) { + struct district_bonus_entry * entry = &list->entries[i]; + if (entry->type != DBET_BUILDING) + continue; + if ((entry->building_name == NULL) || (entry->building_name[0] == '\0')) { + entry->building_id = -1; + continue; + } + + int improv_id; + struct string_slice improv_name = { .str = (char *)entry->building_name, .len = (int)strlen (entry->building_name) }; + if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { + entry->building_id = improv_id; + stable_insert (&is->building_name_to_id, improv_name.str, improv_id); + } else { + entry->building_id = -1; + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": %s entry \"%.*s\" not found", + district_name, bonus_name, improv_name.len, improv_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } +} + +void parse_building_and_tech_ids () +{ + struct c3x_config * cfg = &is->current_config; + char ss[200]; + struct error_line * district_parse_errors = NULL; + struct error_line * wonder_parse_errors = NULL; + + cfg->great_wall_auto_build_wonder_improv_id = -1; + if (cfg->enable_districts && + cfg->enable_great_wall_districts && + cfg->auto_build_great_wall_around_territory && + cfg->great_wall_auto_build_wonder_name != NULL && + cfg->great_wall_auto_build_wonder_name[0] != '\0') { + struct string_slice wonder_name = { + .str = cfg->great_wall_auto_build_wonder_name, + .len = strlen (cfg->great_wall_auto_build_wonder_name) + }; + if (! find_improv_id_by_name (&wonder_name, &cfg->great_wall_auto_build_wonder_improv_id)) { + snprintf (ss, sizeof ss, + "Error reading config: The value for \"great_wall_auto_build_wonder_name\" is invalid: \"%s\"", + cfg->great_wall_auto_build_wonder_name); + ss[(sizeof ss) - 1] = '\0'; + pop_up_in_game_error (ss); + } + } + + for (int i = 0; i < is->district_count; i++) { + char const * district_name = (is->district_configs[i].name != NULL) ? is->district_configs[i].name : "District"; + if (! district_is_included_by_final_config (i)) { + is->district_infos[i].advance_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) + is->district_infos[i].advance_prereq_ids[j] = -1; + is->district_infos[i].obsoleted_by_id = -1; + is->district_infos[i].resource_prereq_count = 0; + for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) + is->district_infos[i].resource_prereq_ids[j] = -1; + is->district_infos[i].resource_prereq_on_tile_id = -1; + is->district_infos[i].wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) + is->district_infos[i].wonder_prereq_ids[j] = -1; + is->district_infos[i].natural_wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) + is->district_infos[i].natural_wonder_prereq_ids[j] = -1; + is->district_infos[i].dependent_building_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) + is->district_infos[i].dependent_building_ids[j] = -1; + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) + is->district_configs[i].buildable_on_district_ids[j] = -1; + is->district_configs[i].buildable_on_district_id_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) + is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; + is->district_configs[i].buildable_adjacent_to_district_id_count = 0; + is->district_configs[i].generated_resource_id = -1; + continue; + } + if ((is->district_configs[i].name != NULL) && + (is->district_configs[i].command != 0) && + (is->district_configs[i].command != -1)) + itable_insert (&is->command_id_to_district_id, is->district_configs[i].command, i); + is->district_infos[i].advance_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) + is->district_infos[i].advance_prereq_ids[j] = -1; + is->district_infos[i].obsoleted_by_id = -1; + is->district_infos[i].resource_prereq_count = 0; + for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) + is->district_infos[i].resource_prereq_ids[j] = -1; + is->district_infos[i].resource_prereq_on_tile_id = -1; + is->district_infos[i].wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) + is->district_infos[i].wonder_prereq_ids[j] = -1; + is->district_infos[i].natural_wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) + is->district_infos[i].natural_wonder_prereq_ids[j] = -1; + + // Map advance prereqs to districts + int stored_tech_count = 0; + for (int j = 0; j < is->district_configs[i].advance_prereq_count; j++) { + char const * prereq = is->district_configs[i].advance_prereqs[j]; + if (prereq == NULL || prereq[0] == '\0') + continue; + int tech_id; + struct string_slice tech_name = { .str = (char *)prereq, .len = (int)strlen (prereq) }; + if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { + snprintf (ss, sizeof ss, "Found tech prereq \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); + (*p_OutputDebugStringA) (ss); + if (stored_tech_count < ARRAY_LEN (is->district_infos[i].advance_prereq_ids)) { + is->district_infos[i].advance_prereq_ids[stored_tech_count] = tech_id; + stored_tech_count++; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": advance_prereqs entry \"%.*s\" not found", district_name, tech_name.len, tech_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].advance_prereq_count = stored_tech_count; + + // Map obsoleted_by to tech ID + if (is->district_configs[i].obsoleted_by != NULL && is->district_configs[i].obsoleted_by != "") { + int tech_id; + struct string_slice tech_name = { .str = (char *)is->district_configs[i].obsoleted_by, .len = (int)strlen (is->district_configs[i].obsoleted_by) }; + if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { + snprintf (ss, sizeof ss, "Found tech obsoleted_by \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); + (*p_OutputDebugStringA) (ss); + is->district_infos[i].obsoleted_by_id = tech_id; + } else { + is->district_infos[i].obsoleted_by_id = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": obsoleted_by \"%.*s\" not found", district_name, tech_name.len, tech_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + // Map resource prereqs to districts (multiple resources now supported) + int stored_res_count = 0; + for (int j = 0; j < is->district_configs[i].resource_prereq_count; j++) { + if (is->district_configs[i].resource_prereqs[j] == "" || is->district_configs[i].resource_prereqs[j] == NULL) + continue; + int res_id; + struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereqs[j], .len = (int)strlen (is->district_configs[i].resource_prereqs[j]) }; + if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { + snprintf (ss, sizeof ss, "Found resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); + (*p_OutputDebugStringA) (ss); + if (stored_res_count < ARRAY_LEN (is->district_infos[i].resource_prereq_ids)) { + is->district_infos[i].resource_prereq_ids[stored_res_count] = res_id; + stored_res_count++; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq \"%.*s\" not found", district_name, res_name.len, res_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].resource_prereq_count = stored_res_count; + if (is->district_configs[i].resource_prereq_on_tile != NULL && is->district_configs[i].resource_prereq_on_tile != "") { + int res_id; + struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereq_on_tile, .len = (int)strlen (is->district_configs[i].resource_prereq_on_tile) }; + if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { + snprintf (ss, sizeof ss, "Found on-tile resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); + (*p_OutputDebugStringA) (ss); + is->district_infos[i].resource_prereq_on_tile_id = res_id; + } else { + is->district_infos[i].resource_prereq_on_tile_id = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq_on_tile \"%.*s\" not found", district_name, res_name.len, res_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + int stored_wonder_count = 0; + for (int j = 0; j < is->district_configs[i].wonder_prereq_count; j++) { + if (is->district_configs[i].wonder_prereqs[j] == "" || is->district_configs[i].wonder_prereqs[j] == NULL) + continue; + int improv_id; + struct string_slice wonder_name = { .str = (char *)is->district_configs[i].wonder_prereqs[j], .len = (int)strlen (is->district_configs[i].wonder_prereqs[j]) }; + if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { + if (stored_wonder_count < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids)) { + is->district_infos[i].wonder_prereq_ids[stored_wonder_count] = improv_id; + stored_wonder_count += 1; + } + stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": wonder_prereqs entry \"%.*s\" not found", district_name, wonder_name.len, wonder_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].wonder_prereq_count = stored_wonder_count; + + int stored_natural_wonder_count = 0; + for (int j = 0; j < is->district_configs[i].natural_wonder_prereq_count; j++) { + if (is->district_configs[i].natural_wonder_prereqs[j] == "" || is->district_configs[i].natural_wonder_prereqs[j] == NULL) + continue; + int natural_wonder_id = -1; + char const * name = is->district_configs[i].natural_wonder_prereqs[j]; + if (stable_look_up (&is->natural_wonder_name_to_id, (char *)name, &natural_wonder_id)) { + if (stored_natural_wonder_count < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids)) { + is->district_infos[i].natural_wonder_prereq_ids[stored_natural_wonder_count] = natural_wonder_id; + stored_natural_wonder_count += 1; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": natural_wonder_prereqs entry \"%s\" not found", district_name, name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].natural_wonder_prereq_count = stored_natural_wonder_count; + + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) + is->district_configs[i].buildable_on_district_ids[j] = -1; + is->district_configs[i].buildable_on_district_id_count = 0; + + if (is->district_configs[i].has_buildable_on_districts) { + int stored_buildable_on_count = 0; + for (int j = 0; j < is->district_configs[i].buildable_on_district_count; j++) { + char const * name = is->district_configs[i].buildable_on_districts[j]; + if (name == NULL || name[0] == '\0') + continue; + int other_district_id = find_district_index_by_name (name); + if (other_district_id >= 0) { + if (stored_buildable_on_count < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids)) { + is->district_configs[i].buildable_on_district_ids[stored_buildable_on_count] = other_district_id; + stored_buildable_on_count += 1; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_on_districts entry \"%s\" not found", district_name, name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_configs[i].buildable_on_district_id_count = stored_buildable_on_count; + } + + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) + is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; + is->district_configs[i].buildable_adjacent_to_district_id_count = 0; + + if (is->district_configs[i].has_buildable_adjacent_to_districts) { + int stored_adjacent_count = 0; + for (int j = 0; j < is->district_configs[i].buildable_adjacent_to_district_count; j++) { + char const * name = is->district_configs[i].buildable_adjacent_to_districts[j]; + if (name == NULL || name[0] == '\0') + continue; + int other_district_id = find_district_index_by_name (name); + if (other_district_id >= 0) { + if (stored_adjacent_count < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids)) { + is->district_configs[i].buildable_adjacent_to_district_ids[stored_adjacent_count] = other_district_id; + stored_adjacent_count += 1; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_adjacent_to_districts entry \"%s\" not found", district_name, name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_configs[i].buildable_adjacent_to_district_id_count = stored_adjacent_count; + } + + // Resolve generated resource name to ID + if (is->district_configs[i].generated_resource != NULL && is->district_configs[i].generated_resource != "") { + int res_id; + struct string_slice res_name = { .str = (char *)is->district_configs[i].generated_resource, .len = (int)strlen (is->district_configs[i].generated_resource) }; + if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { + snprintf (ss, sizeof ss, "Found generated resource \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); + (*p_OutputDebugStringA) (ss); + is->district_configs[i].generated_resource_id = res_id; + } else { + is->district_configs[i].generated_resource_id = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": generated_resource \"%.*s\" not found", district_name, res_name.len, res_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + // Map improvement prereqs to districts + int stored_count = 0; + for (int j = 0; j < is->district_configs[i].dependent_improvement_max_index; j++) { + int improv_id; + if (is->district_configs[i].dependent_improvements[j] == "" || is->district_configs[i].dependent_improvements[j] == NULL) + continue; + + // Gate wonder district prereqs behind enable_wonder_districts + if ((is->district_configs[i].command == UCV_Build_WonderDistrict) && (! cfg->enable_wonder_districts)) + continue; + + struct string_slice improv_name = { .str = (char *)is->district_configs[i].dependent_improvements[j], .len = (int)strlen (is->district_configs[i].dependent_improvements[j]) }; + if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { + snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for district \"%s\", ID %d\n", improv_name.len, improv_name.str, district_name, improv_id); + (*p_OutputDebugStringA) (ss); + if (stored_count < ARRAY_LEN (is->district_infos[i].dependent_building_ids)) { + is->district_infos[i].dependent_building_ids[stored_count] = improv_id; + stored_count += 1; + } + add_district_building_prereq (improv_id, i); + stable_insert (&is->building_name_to_id, improv_name.str, improv_id); + } else { + is->district_infos[i].dependent_building_ids[j] = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": dependent_improvs entry \"%.*s\" not found", district_name, improv_name.len, improv_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + is->district_infos[i].dependent_building_count = stored_count; + } + + resolve_district_bonus_building_entries (&is->district_configs[i].culture_bonus_extras, district_name, "culture_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].science_bonus_extras, district_name, "science_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].food_bonus_extras, district_name, "food_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].gold_bonus_extras, district_name, "gold_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].shield_bonus_extras, district_name, "shield_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].happiness_bonus_extras, district_name, "happiness_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].defense_bonus_extras, district_name, "defense_bonus_percent", &district_parse_errors); + } + + resolve_counter_rule_districts (&district_parse_errors); + + // Map wonder names to their improvement IDs for rendering under-construction wonders + for (int wi = 0; wi < is->wonder_district_count; wi++) { + if (is->wonder_district_configs[wi].wonder_name == NULL || is->wonder_district_configs[wi].wonder_name[0] == '\0') + continue; + + int improv_id; + struct string_slice wonder_name = { .str = (char *)is->wonder_district_configs[wi].wonder_name, .len = (int)strlen (is->wonder_district_configs[wi].wonder_name) }; + if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { + snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for wonder district \"%s\", ID %d\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name, improv_id); + (*p_OutputDebugStringA) (ss); + stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); + } else { + snprintf (ss, sizeof ss, "Could not find improvement prereq \"%.*s\" for wonder district \"%s\"\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name); + (*p_OutputDebugStringA) (ss); + struct error_line * err = add_error_line (&wonder_parse_errors); + snprintf (err->text, sizeof err->text, "^ Wonder district \"%s\": improvement \"%.*s\" not found", (is->wonder_district_configs[wi].wonder_name != NULL) ? is->wonder_district_configs[wi].wonder_name : "Wonder District", wonder_name.len, wonder_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + if ((district_parse_errors != NULL) || (wonder_parse_errors != NULL)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + + if (district_parse_errors != NULL) { + char header[256]; + if (is->current_districts_config_path[0] != '\0') + snprintf (header, sizeof header, "District Config errors in %s:", is->current_districts_config_path); + else + snprintf (header, sizeof header, "District Config lookup errors:"); + header[(sizeof header) - 1] = '\0'; + PopupForm_add_text (popup, __, header, false); + for (struct error_line * line = district_parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + + if ((district_parse_errors != NULL) && (wonder_parse_errors != NULL)) + PopupForm_add_text (popup, __, "", false); + + if (wonder_parse_errors != NULL) { + char header[256]; + snprintf (header, sizeof header, "Wonder District Config lookup errors:"); + header[(sizeof header) - 1] = '\0'; + PopupForm_add_text (popup, __, header, false); + for (struct error_line * line = wonder_parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + + patch_show_popup (popup, __, 0, 0); + free_error_lines (district_parse_errors); + free_error_lines (wonder_parse_errors); + } +} + +void +load_districts_config () +{ + clear_dynamic_district_definitions (); + load_dynamic_district_configs (); + load_dynamic_wonder_configs (); + load_natural_wonder_configs (); + is->district_count = is->special_district_count + is->dynamic_district_count; + + set_wonders_dependent_on_wonder_district (); + parse_building_and_tech_ids (); +} + +void +place_natural_wonders_on_map (void) +{ + if (! is->current_config.enable_natural_wonders) + return; + + int wonder_count = is->natural_wonder_count; + if (wonder_count <= 0) + return; + + struct natural_wonder_candidate_list * candidate_lists = (struct natural_wonder_candidate_list *)calloc (wonder_count, sizeof *candidate_lists); + bool * already_placed = (bool *)calloc (wonder_count, sizeof *already_placed); + + if ((candidate_lists == NULL) || (already_placed == NULL)) { + if (candidate_lists != NULL) free (candidate_lists); + if (already_placed != NULL) free (already_placed); + return; + } + + struct wonder_location * placements = NULL; + int placement_count = 0; + int placement_capacity = 0; + int existing_count = 0; + + // Record existing natural wonders + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + + int wonder_id = inst->natural_wonder_info.natural_wonder_id; + if ((wonder_id < 0) || (wonder_id >= wonder_count)) + continue; + + already_placed[wonder_id] = true; + + Tile * tile = (Tile *)tei.key; + int tile_x, tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + continue; + + if (placement_count >= placement_capacity) { + int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; + struct wonder_location * grown = + (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); + if (grown == NULL) + continue; + placements = grown; + placement_capacity = new_capacity; + } + + if (placements != NULL) { + placements[placement_count++] = (struct wonder_location){ + .x = (short)tile_x, + .y = (short)tile_y + }; + existing_count += 1; + } + } + + // Build candidate lists + int map_width = p_bic_data->Map.Width; + int map_height = p_bic_data->Map.Height; + int minimum_separation = is->current_config.minimum_natural_wonder_separation; + + for (int y = 0; y < map_height; y++) { + for (int x = 0; x < map_width; x++) { + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + if (! natural_wonder_tile_is_clear (tile, x, y)) continue; + if (district_exists_within_distance (x, y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; + + for (int ni = 0; ni < wonder_count; ni++) { + if (already_placed[ni]) + continue; + + struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; + if (cfg->name == NULL) + continue; + + if (! natural_wonder_terrain_matches (cfg, tile, x, y)) + continue; + + natural_wonder_candidate_list_push (&candidate_lists[ni], tile, x, y); + } + } + } + + bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; + int newly_placed = 0; + int * wonder_order = (int *)malloc (wonder_count * sizeof *wonder_order); + if (wonder_order != NULL) { + for (int i = 0; i < wonder_count; i++) + wonder_order[i] = i; + for (int i = wonder_count - 1; i > 0; i--) { + int swap_index = rand_int (p_rand_object, __, i + 1); + int temp = wonder_order[i]; + wonder_order[i] = wonder_order[swap_index]; + wonder_order[swap_index] = temp; + } + } + + for (int order_index = 0; order_index < wonder_count; order_index++) { + int ni = (wonder_order != NULL) ? wonder_order[order_index] : order_index; + if (already_placed[ni]) + continue; + + struct natural_wonder_candidate_list * list = &candidate_lists[ni]; + if (list->count == 0) { + char msg[256]; + snprintf (msg, sizeof msg, "[C3X] No valid tiles to place natural wonder \"%s\".\n", + (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); + (*p_OutputDebugStringA) (msg); + continue; + } + + int best_index = -1; + int best_dist = -1; + int best_adjacent_count = -1; + int best_target_diff = INT_MAX; + int best_rand = INT_MAX; + int best_same_type_count = -1; + int best_continent_priority = INT_MAX; + int target_x = (wonder_count > 0) + ? (int)(((long long)(2 * ni + 1) * map_width) / (2 * wonder_count)) + : (map_width >> 1); + + for (int ci = 0; ci < list->count; ci++) { + struct natural_wonder_candidate * cand = &list->entries[ci]; + Tile * tile = cand->tile; + if ((tile == NULL) || (tile == p_null_tile)) continue; + if (get_district_instance (tile) != NULL) continue; + if (! natural_wonder_tile_is_clear (tile, cand->x, cand->y)) continue; + if (! natural_wonder_terrain_matches (&is->natural_wonder_configs[ni], tile, cand->x, cand->y)) continue; + if (district_exists_within_distance (cand->x, cand->y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; + + int min_dist_sq = natural_wonder_min_distance_sq (cand->x, cand->y, placements, placement_count); + if (min_dist_sq == INT_MAX) { + int span = (map_width * map_width) + (map_height * map_height); + if (span <= 0) + span = INT_MAX; + min_dist_sq = span; + } + + int dx_raw = int_abs (cand->x - target_x); + int dx_adjusted = compute_wrapped_component (dx_raw, map_width, wraps_horiz); + int rand_val = rand_int (p_rand_object, __, 0x7FFF); + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + int continent_priority = 1; + if ((continent_id >= 0) && ! continent_has_natural_wonder (continent_id, placements, placement_count)) + continent_priority = 0; + + bool adjacency_bonus_active = + (is->natural_wonder_configs[ni].adjacent_to != (enum SquareTypes)SQ_INVALID) && + (is->natural_wonder_configs[ni].adjacency_dir == DIR_ZERO); + int adjacency_count = -1; + if (adjacency_bonus_active) + adjacency_count = count_adjacent_tiles_of_type (cand->x, cand->y, + is->natural_wonder_configs[ni].adjacent_to); + + int same_type_count = count_adjacent_tiles_of_type (cand->x, cand->y, + is->natural_wonder_configs[ni].terrain_type); + + bool better = false; + if (continent_priority < best_continent_priority) + better = true; + else if (continent_priority > best_continent_priority) + continue; + + if (! better && adjacency_bonus_active) { + if (adjacency_count > best_adjacent_count) + better = true; + else if (adjacency_count < best_adjacent_count) + continue; + } + + if (! better) { + if (same_type_count > best_same_type_count) + better = true; + else if (same_type_count < best_same_type_count) + continue; + } + + if (! better) { + if ((min_dist_sq > best_dist) || + ((min_dist_sq == best_dist) && (dx_adjusted < best_target_diff)) || + ((min_dist_sq == best_dist) && (dx_adjusted == best_target_diff) && (rand_val < best_rand))) + better = true; + else + continue; + } + + best_dist = min_dist_sq; + best_target_diff = dx_adjusted; + best_rand = rand_val; + best_index = ci; + best_continent_priority = continent_priority; + if (adjacency_bonus_active) + best_adjacent_count = adjacency_count; + best_same_type_count = same_type_count; + } + + if (best_index < 0) { + char msg[256]; + snprintf (msg, sizeof msg, "[C3X] Could not find a suitable tile for natural wonder \"%s\" after filtering.\n", + (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); + (*p_OutputDebugStringA) (msg); + continue; + } + + struct natural_wonder_candidate * chosen = &list->entries[best_index]; + assign_natural_wonder_to_tile (chosen->tile, chosen->x, chosen->y, ni); + + if (placement_count >= placement_capacity) { + int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; + struct wonder_location * grown = + (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); + if (grown != NULL) { + placements = grown; + placement_capacity = new_capacity; + } + } + + if ((placements != NULL) && (placement_count < placement_capacity)) { + placements[placement_count++] = (struct wonder_location){ + .x = chosen->x, + .y = chosen->y + }; + } + + newly_placed += 1; + + char msg[256]; + snprintf (msg, sizeof msg, "[C3X] Placed natural wonder \"%s\" at (%d,%d).\n", + (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder", + chosen->x, chosen->y); + (*p_OutputDebugStringA) (msg); + } + + char summary[256]; + snprintf (summary, sizeof summary, "[C3X] Natural wonder placement complete. Newly placed: %d, already present: %d.\n", + newly_placed, existing_count); + (*p_OutputDebugStringA) (summary); + + for (int ni = 0; ni < wonder_count; ni++) + free (candidate_lists[ni].entries); + free (wonder_order); + free (candidate_lists); + free (already_placed); + free (placements); +} + +void +init_scenario_district_entry (struct scenario_district_entry * entry) +{ + if (entry == NULL) + return; + + memset (entry, 0, sizeof *entry); +} + +void +init_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) +{ + if (entry == NULL) + return; + + memset (entry, 0, sizeof *entry); +} + +void +free_scenario_district_entry (struct scenario_district_entry * entry) +{ + if (entry == NULL) + return; + + if (entry->district_name != NULL) { + free (entry->district_name); + entry->district_name = NULL; + } + if (entry->wonder_city_name != NULL) { + free (entry->wonder_city_name); + entry->wonder_city_name = NULL; + } + if (entry->wonder_name != NULL) { + free (entry->wonder_name); + entry->wonder_name = NULL; + } + entry->has_coordinates = 0; + entry->has_district_name = 0; + entry->has_wonder_city = 0; + entry->has_wonder_name = 0; +} + +void +free_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) +{ + if (entry == NULL) + return; + + if (entry->name != NULL) { + free (entry->name); + entry->name = NULL; + } + entry->has_coordinates = 0; + entry->has_name = 0; +} + +void +add_scenario_district_error (struct error_line ** parse_errors, + int line_number, + char const * message) +{ + if (message == NULL) + return; + + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s", line_number, message); + err->text[(sizeof err->text) - 1] = '\0'; +} + +int +parse_scenario_district_coordinates (struct string_slice const * value, int * out_x, int * out_y) +{ + if ((value == NULL) || (out_x == NULL) || (out_y == NULL)) + return 0; + + char * text = trim_and_extract_slice (value, 0); + if (text == NULL) + return 0; + + char * cursor = text; + int success = 0; + int x, y; + if (parse_int (&cursor, &x) && + skip_punctuation (&cursor, ',') && + parse_int (&cursor, &y)) { + skip_horiz_space (&cursor); + success = (*cursor == '\0'); + if (success) { + *out_x = x; + *out_y = y; + } + } + + free (text); + return success; +} + +int +finalize_scenario_district_entry (struct scenario_district_entry * entry, + int section_start_line, + struct error_line ** parse_errors) +{ + int success = 1; + if ((entry == NULL) || (parse_errors == NULL)) + return 0; + + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return 1; + } + + if (! entry->has_coordinates) + add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); + if ((! entry->has_district_name) || (entry->district_name == NULL) || (entry->district_name[0] == '\0')) + add_scenario_district_error (parse_errors, section_start_line, "district (value is required)"); + + if ((! entry->has_coordinates) || (! entry->has_district_name) || + (entry->district_name == NULL) || (entry->district_name[0] == '\0')) + success = 0; + + int map_x = entry->tile_x; + int map_y = entry->tile_y; + if (success) { + wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); + Tile * tile = tile_at (map_x, map_y); + if ((tile == NULL) || (tile == p_null_tile)) { + add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); + success = 0; + } else { + int district_id = find_district_index_by_name (entry->district_name); + if ((district_id < 0) || (district_id >= is->district_count)) { + char msg[200]; + snprintf (msg, sizeof msg, "district (unrecognized name: \"%s\")", entry->district_name); + add_scenario_district_error (parse_errors, section_start_line, msg); + success = 0; + } else { + if ((district_id == NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_natural_wonders) { + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return 1; + } + if ((district_id != NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_districts) { + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return 1; + } + struct district_instance * inst = ensure_district_instance (tile, district_id, map_x, map_y); + if (inst == NULL) { + add_scenario_district_error (parse_errors, section_start_line, "Failed to create district instance"); + success = 0; + } else { + inst->district_id = district_id; + district_instance_set_coords (inst, map_x, map_y); + inst->state = DS_COMPLETED; + inst->wonder_info.state = WDS_UNUSED; + inst->wonder_info.city = NULL; + inst->wonder_info.city_id = -1; + inst->wonder_info.wonder_index = -1; + inst->natural_wonder_info.natural_wonder_id = -1; + + if (district_id == WONDER_DISTRICT_ID) { + int has_city = entry->has_wonder_city && + (entry->wonder_city_name != NULL) && (entry->wonder_city_name[0] != '\0'); + int has_wonder = entry->has_wonder_name && + (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); + if (! has_city || ! has_wonder) { + add_scenario_district_error (parse_errors, section_start_line, "Wonder district requires both wonder_city and wonder_name"); + success = 0; + } else { + int wonder_index = find_wonder_district_index_by_name (entry->wonder_name); + if (wonder_index < 0) { + char msg[200]; + snprintf (msg, sizeof msg, "wonder_name (unrecognized wonder: \"%s\")", entry->wonder_name); + add_scenario_district_error (parse_errors, section_start_line, msg); + success = 0; + } else { + inst->wonder_info.city = NULL; + inst->wonder_info.city_id = -1; + inst->wonder_info.state = WDS_COMPLETED; + inst->wonder_info.wonder_index = wonder_index; + } + } + } else if (district_id == NATURAL_WONDER_DISTRICT_ID) { + int has_name = entry->has_wonder_name && + (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); + if (! has_name) { + add_scenario_district_error (parse_errors, section_start_line, "Natural Wonder district requires wonder_name"); + success = 0; + } else { + int natural_index = find_natural_wonder_index_by_name (entry->wonder_name); + if (natural_index < 0) { + char msg[200]; + snprintf (msg, sizeof msg, "wonder_name (unrecognized natural wonder: \"%s\")", entry->wonder_name); + add_scenario_district_error (parse_errors, section_start_line, msg); + success = 0; + } else + inst->natural_wonder_info.natural_wonder_id = natural_index; + } + if (entry->has_wonder_city) + add_scenario_district_error (parse_errors, section_start_line, "wonder_city ignored for Natural Wonder district entries"); + } else if (entry->has_wonder_city || entry->has_wonder_name) { + add_scenario_district_error (parse_errors, section_start_line, "wonder_* fields only valid for Wonder or Natural Wonder district entries"); + } + + if (success) { + if (district_id != NATURAL_WONDER_DISTRICT_ID && !tile->vtable->m18_Check_Mines (tile, __, 0)) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, map_x, map_y); + set_tile_unworkable_for_all_cities (tile, map_x, map_y); + } + } + } + } + } + + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return success; +} + +bool +tile_can_be_named (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) + return false; + return true; +} + +void +remove_named_tile_entry (Tile * tile) +{ + struct named_tile_entry * entry = get_named_tile_entry (tile); + if (entry == NULL) + return; + itable_remove (&is->named_tile_map, (int)tile); + free (entry); +} + +void +set_named_tile_entry (Tile * tile, int tile_x, int tile_y, char const * name) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return; + if ((name == NULL) || (name[0] == '\0')) { + remove_named_tile_entry (tile); + return; + } + + struct named_tile_entry * entry = get_named_tile_entry (tile); + if (entry == NULL) { + entry = calloc (1, sizeof *entry); + if (entry == NULL) + return; + itable_insert (&is->named_tile_map, (int)tile, (int)entry); + } + entry->tile_x = tile_x; + entry->tile_y = tile_y; + strncpy (entry->name, name, sizeof entry->name); + entry->name[(sizeof entry->name) - 1] = '\0'; +} + +int +finalize_scenario_named_tile_entry (struct scenario_named_tile_entry * entry, + int section_start_line, + struct error_line ** parse_errors) +{ + int success = 1; + if ((entry == NULL) || (parse_errors == NULL)) + return 0; + + if (! is->current_config.enable_named_tiles) { + free_scenario_named_tile_entry (entry); + init_scenario_named_tile_entry (entry); + return 1; + } + + if (! entry->has_coordinates) + add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); + if ((! entry->has_name) || (entry->name == NULL) || (entry->name[0] == '\0')) + add_scenario_district_error (parse_errors, section_start_line, "name (value is required)"); + + if ((! entry->has_coordinates) || (! entry->has_name) || + (entry->name == NULL) || (entry->name[0] == '\0')) + success = 0; + + int map_x = entry->tile_x; + int map_y = entry->tile_y; + if (success) { + wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); + Tile * tile = tile_at (map_x, map_y); + if ((tile == NULL) || (tile == p_null_tile)) { + add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); + success = 0; + } else if (! tile_can_be_named (tile, map_x, map_y)) { + add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile cannot be named)"); + success = 0; + } else { + set_named_tile_entry (tile, map_x, map_y, entry->name); + } + } + + free_scenario_named_tile_entry (entry); + init_scenario_named_tile_entry (entry); + return success; +} + +void +handle_scenario_district_key (struct scenario_district_entry * entry, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if ((entry == NULL) || (key == NULL) || (value == NULL)) + return; + + if (slice_matches_str (key, "coordinates")) { + int x, y; + if (parse_scenario_district_coordinates (value, &x, &y)) { + entry->tile_x = x; + entry->tile_y = y; + entry->has_coordinates = 1; + } else + add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); + + } else if (slice_matches_str (key, "district")) { + if (entry->district_name != NULL) { + free (entry->district_name); + entry->district_name = NULL; + } + entry->district_name = copy_trimmed_string_or_null (value, 1); + entry->has_district_name = (entry->district_name != NULL); + if (! entry->has_district_name) + add_scenario_district_error (parse_errors, line_number, "district (value is required)"); + + } else if (slice_matches_str (key, "wonder_city")) { + if (entry->wonder_city_name != NULL) { + free (entry->wonder_city_name); + entry->wonder_city_name = NULL; + } + entry->wonder_city_name = copy_trimmed_string_or_null (value, 1); + entry->has_wonder_city = (entry->wonder_city_name != NULL); + + } else if (slice_matches_str (key, "wonder_name")) { + if (entry->wonder_name != NULL) { + free (entry->wonder_name); + entry->wonder_name = NULL; + } + entry->wonder_name = copy_trimmed_string_or_null (value, 1); + entry->has_wonder_name = (entry->wonder_name != NULL); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +void +handle_scenario_named_tile_key (struct scenario_named_tile_entry * entry, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if ((entry == NULL) || (key == NULL) || (value == NULL)) + return; + + if (slice_matches_str (key, "coordinates")) { + int x, y; + if (parse_scenario_district_coordinates (value, &x, &y)) { + entry->tile_x = x; + entry->tile_y = y; + entry->has_coordinates = 1; + } else + add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); + + } else if (slice_matches_str (key, "name")) { + if (entry->name != NULL) { + free (entry->name); + entry->name = NULL; + } + entry->name = copy_trimmed_string_or_null (value, 1); + entry->has_name = (entry->name != NULL); + if (! entry->has_name) + add_scenario_district_error (parse_errors, line_number, "name (value is required)"); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +// Parses a .c3x.txt file corresponding to the given scenario file path, loading district instances as specified. +// +// The expected file format itself is very simple. Example: +// +// ``` +// DISTRICTS +// +// #District +// coordinates = 12,28 +// district = Entertainment Complex +// +// #District +// coordinates = 9,23 +// district = Wonder District +// wonder_city = Rome +// wonder_name = The Pyramids +// +// #District +// coordinates = 10,30 +// district = Natural Wonder +// wonder_name = Mount Everest +// +// #NamedTile +// coordinates = 41,23 +// name = Tiber River +// ``` +// +// Details at https://github.com/instafluff0/Civ3_Editor_Fork_for_C3X_Districts +void +load_scenario_districts_from_file () +{ + char * scenario_filename = "scenario.districts.txt"; + char * scenario_districts_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + + // BIC_get_asset_path returns the file name when it can't find the file + if ((scenario_districts_path == NULL) || (0 == strcmp (scenario_filename, scenario_districts_path))) + return; + + char * text = file_to_string (scenario_districts_path); + if (text == NULL) + return; + + struct scenario_district_entry entry; + struct scenario_named_tile_entry named_entry; + init_scenario_district_entry (&entry); + init_scenario_named_tile_entry (&named_entry); + int in_section = 0; + int section_start_line = 0; + int section_type = 0; + int line_number = 0; + int header_seen = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + int has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + // Keep support for legacy header, technically not needed + if (! header_seen) { + if (slice_matches_str (&trimmed, "DISTRICTS")) { + header_seen = 1; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if (slice_matches_str (&directive, "District")) { + if (in_section) { + if (section_type == 1) + finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); + else if (section_type == 2) + finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); + } + in_section = 1; + section_type = 1; + section_start_line = line_number; + free_scenario_district_entry (&entry); + init_scenario_district_entry (&entry); + } else if (slice_matches_str (&directive, "NamedTile")) { + if (in_section) { + if (section_type == 1) + finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); + else if (section_type == 2) + finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); + } + in_section = 1; + section_type = 2; + section_start_line = line_number; + free_scenario_named_tile_entry (&named_entry); + init_scenario_named_tile_entry (&named_entry); + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + switch (parse_trimmed_key_value (&trimmed, &key_slice, &value_slice)) { + case KVP_NO_EQUALS: + add_scenario_district_error (&parse_errors, line_number, "(expected '=')"); + break; + case KVP_EMPTY_KEY: + add_scenario_district_error (&parse_errors, line_number, "(missing key)"); + break; + case KVP_SUCCESS: + if (section_type == 1) + handle_scenario_district_key (&entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + else if (section_type == 2) + handle_scenario_named_tile_key (&named_entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + break; + } + + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) { + if (section_type == 1) + finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); + else if (section_type == 2) + finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); + } + + free_scenario_district_entry (&entry); + free_scenario_named_tile_entry (&named_entry); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (scenario_districts_path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + + if ((parse_errors != NULL) || (unrecognized_keys != NULL)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char header[256]; + snprintf (header, sizeof header, "District scenario file issues in %s:", scenario_districts_path); + header[(sizeof header) - 1] = '\0'; + PopupForm_add_text (popup, __, header, 0); + if (parse_errors != NULL) + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, 0); + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", 0); + PopupForm_add_text (popup, __, "Unrecognized keys:", 0); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, 0); + } + patch_show_popup (popup, __, 0, 0); + } + + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); +} + +void +deinit_district_images (void) +{ + if (is->dc_img_state == IS_OK) { + for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) { + for (int variant = 0; variant < ARRAY_LEN (is->district_img_sets[dc].imgs); variant++) + for (int era = 0; era < 4; era++) + for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc].imgs[variant][era]); col++) { + Sprite * sprite = &is->district_img_sets[dc].imgs[variant][era][col]; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + } + + for (int wi = 0; wi < MAX_WONDER_DISTRICT_TYPES; wi++) { + struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; + if (set->img.vtable != NULL) + set->img.vtable->destruct (&set->img, __, 0); + if (set->construct_img.vtable != NULL) + set->construct_img.vtable->destruct (&set->construct_img, __, 0); + if (set->alt_dir_img.vtable != NULL) + set->alt_dir_img.vtable->destruct (&set->alt_dir_img, __, 0); + if (set->alt_dir_construct_img.vtable != NULL) + set->alt_dir_construct_img.vtable->destruct (&set->alt_dir_construct_img, __, 0); + } + + for (int ni = 0; ni < MAX_NATURAL_WONDER_DISTRICT_TYPES; ni++) { + Sprite * sprite = &is->natural_wonder_img_sets[ni].img; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + + if (is->abandoned_district_img.vtable != NULL) + is->abandoned_district_img.vtable->destruct (&is->abandoned_district_img, __, 0); + if (is->abandoned_maritime_district_img.vtable != NULL) + is->abandoned_maritime_district_img.vtable->destruct (&is->abandoned_maritime_district_img, __, 0); + } + + is->dc_img_state = IS_UNINITED; +} + +void +clear_highlighted_worker_tiles_for_districts () +{ + FOR_TABLE_ENTRIES (tei, &is->highlighted_city_radius_tile_pointers) { + struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)tei.value; + if (info != NULL) + free (info); + } + table_deinit (&is->highlighted_city_radius_tile_pointers); +} + + +void +reset_district_state (bool reset_tile_map) +{ + clear_all_tracked_workers (); + deinit_district_images (); + clear_highlighted_worker_tiles_for_districts (); + + FOR_TABLE_ENTRIES (tei, &is->district_building_prereqs) { + struct district_building_prereq_list * list = (struct district_building_prereq_list *)tei.value; + if (list != NULL) + free (list); + } + table_deinit (&is->district_building_prereqs); + table_deinit (&is->command_id_to_district_id); + stable_deinit (&is->building_name_to_id); + if (reset_tile_map) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst != NULL) + free (inst); + } + table_deinit (&is->district_tile_map); + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if (entry != NULL) + free (entry); + } + table_deinit (&is->named_tile_map); + } + + clear_distribution_hub_tables (); + + is->distribution_hub_totals_dirty = true; + + clear_dynamic_district_definitions (); + is->district_count = is->special_district_count; + + for (int i = 0; i < COUNT_DISTRICT_TYPES; i++) { + is->district_infos[i].advance_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) + is->district_infos[i].advance_prereq_ids[j] = -1; + is->district_infos[i].obsoleted_by_id = -1; + is->district_infos[i].resource_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].resource_prereq_ids); j++) + is->district_infos[i].resource_prereq_ids[j] = -1; + is->district_infos[i].resource_prereq_on_tile_id = -1; + is->district_infos[i].wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) + is->district_infos[i].wonder_prereq_ids[j] = -1; + is->district_infos[i].natural_wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) + is->district_infos[i].natural_wonder_prereq_ids[j] = -1; + is->district_infos[i].dependent_building_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) + is->district_infos[i].dependent_building_ids[j] = -1; + } + + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req != NULL) + free (req); + } + table_deinit (&is->city_pending_district_requests[civ_id]); + } + table_deinit (&is->city_pending_building_orders); + + is->great_wall_auto_build = GWABS_NOT_STARTED; +} + +void +clear_city_district_request (City * city, int district_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (district_id < 0) || (district_id >= is->district_count)) + return; + + struct pending_district_request * req = find_pending_district_request (city, district_id); + if (req == NULL) + return; + + remove_pending_district_request (req); + + int pending_improv_id; + if (look_up_pending_building_order (city, &pending_improv_id)) { + int required_district_id; + if (city_requires_district_for_improvement (city, pending_improv_id, &required_district_id)) { + if (required_district_id == district_id) + forget_pending_building_order (city); + } + } +} + +bool +district_resource_prereqs_met_r (Tile * tile, int tile_x, int tile_y, int district_id, int max_req_resource_id) +{ + if ((tile == NULL) || (tile == p_null_tile) || + (district_id < 0) || (district_id >= is->district_count)) + return false; + + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + struct district_infos * info = &is->district_infos[district_id]; + int on_tile_req = info->resource_prereq_on_tile_id; + if (on_tile_req >= 0) { + int res_here = (owner >= 0) ? Tile_get_resource_visible_to (tile, __, owner) : -1; + if (res_here != on_tile_req) + return false; + } + + // If no resource prereqs, then the check passes + if (info->resource_prereq_count <= 0) + return true; + + if (owner < 0) + return false; + + // Check resource prereqs - ALL must be present + for (int i = 0; i < info->resource_prereq_count; i++) { + int resource_req = info->resource_prereq_ids[i]; + if (resource_req < 0) + continue; + if (resource_req > max_req_resource_id) + return false; + + bool has_resource = false; + bool is_bonus_resource = p_bic_data->ResourceTypes[resource_req].Class == RC_Bonus; + + FOR_CITIES_OF (coi, owner) { + City * req_city = coi.city; + if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, req_city, tile_x, tile_y)) + continue; + if (! city_has_resource_r (req_city, resource_req, max_req_resource_id)) + if (! is_bonus_resource) + continue; + else { + int civ_id = req_city->Body.CivID; + FOR_TILES_AROUND (tai, is->workable_tile_count, req_city->Body.X, req_city->Body.Y) { + Tile * radius_tile = tai.tile; + if ((radius_tile == NULL) || (radius_tile == p_null_tile)) + continue; + if (radius_tile->vtable->m38_Get_Territory_OwnerID (radius_tile) != civ_id) + continue; + if (Tile_get_resource_visible_to (radius_tile, __, civ_id) == resource_req) { + has_resource = true; + break; + } + } + if (has_resource) + break; + continue; + } + + has_resource = true; + break; + } + + // If this required resource is not available, the check fails + if (!has_resource) + return false; + } + + return true; +} + +bool +district_resource_prereqs_met (Tile * tile, int tile_x, int tile_y, int district_id) +{ + return district_resource_prereqs_met_r (tile, tile_x, tile_y, district_id, INT_MAX); +} + +int +count_contiguous_bridge_districts (int tile_x, int tile_y, int dx, int dy) +{ + Map * map = &p_bic_data->Map; + int nx = tile_x + dx; + int ny = tile_y + dy; + int count = 0; + int max_steps = map->Width + map->Height; + + for (int step = 0; step < max_steps; step++) { + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) + break; + count++; + nx += dx; + ny += dy; + } + + return count; +} + +int +count_contiguous_canal_districts (int tile_x, int tile_y, int max_count) +{ + if (max_count <= 0) + return 0; + + Map * map = &p_bic_data->Map; + int limit = max_count + 1; + int capacity = limit; + if (capacity < 1) + capacity = 1; + + int * xs = malloc (sizeof (*xs) * capacity); + int * ys = malloc (sizeof (*ys) * capacity); + if ((xs == NULL) || (ys == NULL)) { + if (xs != NULL) + free (xs); + if (ys != NULL) + free (ys); + return limit; + } + + int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; + int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; + int head = 0; + int tail = 0; + int count = 0; + + xs[tail] = tile_x; + ys[tail] = tile_y; + tail++; + + while (head < tail) { + int cx = xs[head]; + int cy = ys[head]; + head++; + count++; + if (count >= limit) + break; + + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) + continue; + + bool seen = false; + for (int j = 0; j < tail; j++) { + if ((xs[j] == nx) && (ys[j] == ny)) { + seen = true; + break; + } + } + if (seen) + continue; + + if (tail < capacity) { + xs[tail] = nx; + ys[tail] = ny; + tail++; + } else { + count = limit; + head = tail; + break; + } + } + } + + free (xs); + free (ys); + + return count; +} + +bool +district_line_is_straight (int tile_x, int tile_y, int district_id) +{ + Map * map = &p_bic_data->Map; + int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; + int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; + + for (int i = 0; i < 8; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, district_id)) + continue; + + int cand_dx = -adj_dx[i]; + int cand_dy = -adj_dy[i]; + + for (int j = 0; j < 8; j++) { + int ox = nx + adj_dx[j]; + int oy = ny + adj_dy[j]; + wrap_tile_coords (map, &ox, &oy); + if ((ox == tile_x) && (oy == tile_y)) + continue; + if (! tile_has_district_at (ox, oy, district_id)) + continue; + + if (! ((adj_dx[j] == cand_dx) && (adj_dy[j] == cand_dy)) && + ! ((adj_dx[j] == -cand_dx) && (adj_dy[j] == -cand_dy))) + return false; + } + } + + return true; +} + +bool +bridge_district_tile_is_valid (int tile_x, int tile_y) +{ + if (! tile_is_coastal_water (tile_x, tile_y)) + return false; + + bool has_adjacent_land_or_bridge = false; + Map * map = &p_bic_data->Map; + int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; + int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; + + for (int i = 0; i < 8; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (tile_is_land (-1, nx, ny, false) || tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) { + has_adjacent_land_or_bridge = true; + break; + } + } + if (! has_adjacent_land_or_bridge) + return false; + + if (is->current_config.max_contiguous_bridge_districts > 0) { + int max_bridges = is->current_config.max_contiguous_bridge_districts; + + int ns_count = count_contiguous_bridge_districts (tile_x, tile_y, 0, -2) + + count_contiguous_bridge_districts (tile_x, tile_y, 0, 2); + if (ns_count >= max_bridges) + return false; + + int we_count = count_contiguous_bridge_districts (tile_x, tile_y, -2, 0) + + count_contiguous_bridge_districts (tile_x, tile_y, 2, 0); + if (we_count >= max_bridges) + return false; + + int swne_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, 1) + + count_contiguous_bridge_districts (tile_x, tile_y, 1, -1); + if (swne_count >= max_bridges) + return false; + + int nwse_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, -1) + + count_contiguous_bridge_districts (tile_x, tile_y, 1, 1); + if (nwse_count >= max_bridges) + return false; + } + + return district_line_is_straight (tile_x, tile_y, BRIDGE_DISTRICT_ID); +} + +bool +canal_district_tile_is_valid (int tile_x, int tile_y) +{ + if (tile_is_water (tile_x, tile_y)) + return false; + + if (is->current_config.max_contiguous_canal_districts > 0) { + int count = count_contiguous_canal_districts (tile_x, tile_y, is->current_config.max_contiguous_canal_districts); + if (count > is->current_config.max_contiguous_canal_districts) + return false; + } + + Map * map = &p_bic_data->Map; + int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; + int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; + + for (int i = 0; i < 8; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * tile = tile_at (nx, ny); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m35_Check_Is_Water (tile)) + return true; + + if (tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && + district_is_complete (tile, CANAL_DISTRICT_ID)) + return true; + } + } + + return false; +} + +bool +can_build_district_on_tile (Tile * tile, int district_id, int civ_id) +{ + if ((! is->current_config.enable_districts) || + (tile == NULL) || (tile == p_null_tile) || + (tile->CityID >= 0) || + tile->vtable->m21_Check_Crates (tile, __, 0) || + tile->vtable->m20_Check_Pollution (tile, __, 0) || + (district_id < 0) || (district_id >= is->district_count)) + return false; + + struct district_config const * cfg = &is->district_configs[district_id]; + if (cfg->command == -1) + return false; + + if ((cfg->command == UCV_Build_Neighborhood) && !is->current_config.enable_neighborhood_districts) return false; + if ((cfg->command == UCV_Build_WonderDistrict) && !is->current_config.enable_wonder_districts) return false; + if ((cfg->command == UCV_Build_DistributionHub) && !is->current_config.enable_distribution_hub_districts) return false; + if ((cfg->command == UCV_Build_Aerodrome) && !is->current_config.enable_aerodrome_districts) return false; + if ((cfg->command == UCV_Build_Port) && !is->current_config.enable_port_districts) return false; + if ((cfg->command == UCV_Build_Bridge) && !is->current_config.enable_bridge_districts) return false; + if ((cfg->command == UCV_Build_CentralRailHub) && !is->current_config.enable_central_rail_hub_districts) return false; + if ((cfg->command == UCV_Build_EnergyGrid) && !is->current_config.enable_energy_grid_districts) return false; + if ((cfg->command == UCV_Build_GreatWall) && !is->current_config.enable_great_wall_districts) return false; + + if (! district_is_buildable_on_tile (cfg, tile)) + return false; + + int tile_x = 0, tile_y = 0; + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + + if (! leader_can_build_district (&leaders[civ_id], district_id)) + return false; + + if (! district_resource_prereqs_met (tile, tile_x, tile_y, district_id)) + return false; + + if ((district_id == CANAL_DISTRICT_ID) && (! canal_district_tile_is_valid (tile_x, tile_y))) + return false; + + if ((district_id == BRIDGE_DISTRICT_ID) && (! bridge_district_tile_is_valid (tile_x, tile_y))) + return false; + + struct district_instance * existing_inst = get_district_instance (tile); + struct district_infos const * info = &is->district_infos[district_id]; + int existing_district_id = (existing_inst != NULL) ? existing_inst->district_id : -1; + bool district_completed = district_is_complete (tile, existing_district_id); + + if ((existing_district_id == district_id) && district_completed) + return false; + if ((existing_district_id >= 0) && (existing_district_id != district_id) && (! district_completed)) + return false; + + if (! cfg->allow_multiple) { + if (district_exists_within_distance (tile_x, tile_y, district_id, civ_id, is->current_config.city_work_radius)) + return false; + } + + return true; +} + +bool +district_is_obsolete_for_civ (int district_id, int civ_id) +{ + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + int obsolete_id = is->district_infos[district_id].obsoleted_by_id; + if (obsolete_id < 0) + return false; + + return Leader_has_tech (&leaders[civ_id], __, obsolete_id); +} + +bool +tile_has_obsolete_district_for_civ (Tile * tile, int civ_id) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + + int district_id = inst->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + if (! district_is_complete (tile, district_id)) + return false; + + return district_is_obsolete_for_civ (district_id, civ_id); +} + +bool +tile_suitable_for_district (Tile * tile, int district_id, City * city, bool * out_has_resource) +{ + bool has_resource = false; + if ((tile != NULL) && (tile != p_null_tile)) + has_resource = tile_has_resource (tile); + if (out_has_resource != NULL) + *out_has_resource = has_resource; + + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (tile->CityID >= 0) return false; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) return false; + if (! can_build_district_on_tile (tile, district_id, city->Body.CivID)) return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + if (tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + return true; + + // Unused wonder districts can be repurposed, completed cannot + if (district_id == WONDER_DISTRICT_ID && inst->state == DS_COMPLETED) { + struct wonder_district_info * winfo = &inst->wonder_info; + if (winfo->state == WDS_COMPLETED) + return false; + } + + return false; + } + + return true; +} + +bool +can_generate_resource (int for_civ_id, struct mill * mill) +{ + int req_tech_id = (mill->flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[mill->resource_id].RequireID; + return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); +} + +bool +district_can_generate_resource (int for_civ_id, struct district_config * dc) +{ + if (dc->generated_resource_id < 0) + return false; + int req_tech_id = (dc->generated_resource_flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[dc->generated_resource_id].RequireID; + return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); +} + +bool +district_generates_resource_for_civ (Tile * tile, struct district_instance * inst, struct district_config * dc, int civ_id) +{ + if ((tile == NULL) || (tile == p_null_tile) || (inst == NULL) || (dc == NULL)) + return false; + if (inst->state != DS_COMPLETED) + return false; + if (dc->generated_resource_id < 0) + return false; + if (! district_can_generate_resource (civ_id, dc)) + return false; + + int tile_x = 0, tile_y = 0; + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + return district_resource_prereqs_met_r (tile, tile_x, tile_y, inst->district_id, dc->generated_resource_id - 1); +} + +void +calculate_city_center_district_bonus (City * city, int * out_food, int * out_shields, int * out_gold) +{ + if (out_food != NULL) + *out_food = 0; + if (out_shields != NULL) + *out_shields = 0; + if (out_gold != NULL) + *out_gold = 0; + + if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) + return; + + int bonus_food = 0; + int bonus_shields = 0; + int bonus_gold = 0; + + int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + int neighborhoods_counted = 0; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) + continue; + Tile * tile = wai.tile; + + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + if (is->current_config.enable_neighborhood_districts && + (district_id == NEIGHBORHOOD_DISTRICT_ID)) { + if (neighborhoods_counted >= utilized_neighborhoods) + continue; + neighborhoods_counted++; + } + + struct district_config * cfg = &is->district_configs[district_id]; + int food_bonus = 0, shield_bonus = 0, gold_bonus = 0; + get_effective_district_yields (inst, cfg, &food_bonus, &shield_bonus, &gold_bonus, NULL, NULL, NULL); + bonus_food += food_bonus; + bonus_shields += shield_bonus; + bonus_gold += gold_bonus; + + if ((cfg->generated_resource_id >= 0) && (cfg->generated_resource_flags & MF_YIELDS)) { + int res_id = cfg->generated_resource_id; + if (district_generates_resource_for_civ (tile, inst, cfg, city->Body.CivID)) { + Resource_Type * res = &p_bic_data->ResourceTypes[res_id]; + bonus_food += res->Food; + bonus_shields += res->Shield; + bonus_gold += res->Commerce; + } + } + } + + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { + int hub_food = 0; + int hub_shields = 0; + get_distribution_hub_yields_for_city (city, &hub_food, &hub_shields); + bonus_food += hub_food; + bonus_shields += hub_shields; + } + + if (out_food != NULL) + *out_food = bonus_food; + if (out_shields != NULL) + *out_shields = bonus_shields; + if (out_gold != NULL) + *out_gold = bonus_gold; +} + +int __fastcall +patch_Map_calc_food_yield_at (Map * this, int edx, int tile_x, int tile_y, int tile_base_type, int civ_id, int imagine_fully_improved, City * city) +{ + if (! is->current_config.enable_districts) + return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id)) { + return 0; + } + } + + return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); +} + +int __fastcall +patch_Map_calc_shield_yield_at (Map * this, int edx, int tile_x, int tile_y, int civ_id, City * city, int param_5, int param_6) +{ + if (! is->current_config.enable_districts) + return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id)) { + return 0; + } + } + + return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); +} + +int +compute_city_tile_yield_sum (City * city, int tile_x, int tile_y) +{ + if (city == NULL) + return 0; + int food = City_calc_tile_yield_at (city, __, YK_FOOD, tile_x, tile_y); + int shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, tile_x, tile_y); + int commerce = City_calc_tile_yield_at (city, __, YK_COMMERCE, tile_x, tile_y); + return food + shields + commerce; +} + +int * +get_water_continent_ids_connected_via_canal (Tile * tile, int * out_count) +{ + if (out_count != NULL) + *out_count = 0; + if (! is->current_config.enable_canal_districts) + return NULL; + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + if (! tile->vtable->m35_Check_Is_Water (tile)) + return NULL; + + int origin_continent_id = tile->vtable->m46_Get_ContinentID (tile); + int continent_count = p_bic_data->Map.Continent_Count; + if ((origin_continent_id < 0) || (origin_continent_id >= continent_count)) + return NULL; + + Map * map = &p_bic_data->Map; + int tile_count = map->TileCount; + if (tile_count <= 0) + return NULL; + + // Use a BFS over completed canal tiles, starting from those touching the origin water body. + int * queue_xs = malloc (sizeof (*queue_xs) * tile_count); + int * queue_ys = malloc (sizeof (*queue_ys) * tile_count); + int * ids = malloc (sizeof (*ids) * continent_count); + bool * seen = calloc (continent_count, sizeof (*seen)); + if ((queue_xs == NULL) || (queue_ys == NULL) || (ids == NULL) || (seen == NULL)) { + if (queue_xs != NULL) + free (queue_xs); + if (queue_ys != NULL) + free (queue_ys); + if (ids != NULL) + free (ids); + if (seen != NULL) + free (seen); + return NULL; + } + + seen[origin_continent_id] = true; + + int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; + int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; + int head = 0; + int tail = 0; + + // Seed queue with completed canal districts adjacent to the origin water body. + for (int index = 0; index < tile_count; index++) { + Tile * cand = Map_get_tile (map, __, index); + if ((cand == NULL) || (cand == p_null_tile)) + continue; + + int cx = 0, cy = 0; + tile_index_to_coords (map, index, &cx, &cy); + if (! tile_has_district_at (cx, cy, CANAL_DISTRICT_ID)) + continue; + + struct district_instance * inst = get_district_instance (cand); + if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || + (! district_is_complete (cand, CANAL_DISTRICT_ID))) + continue; + + bool adjacent_to_origin = false; + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (! adj->vtable->m35_Check_Is_Water (adj)) + continue; + int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); + if (adj_continent_id == origin_continent_id) { + adjacent_to_origin = true; + break; + } + } + if (! adjacent_to_origin) + continue; + + bool seen_canal = false; + for (int j = 0; j < tail; j++) { + if ((queue_xs[j] == cx) && (queue_ys[j] == cy)) { + seen_canal = true; + break; + } + } + if (! seen_canal && (tail < tile_count)) { + queue_xs[tail] = cx; + queue_ys[tail] = cy; + tail++; + } + } + + int id_count = 0; + + while (head < tail) { + int cx = queue_xs[head]; + int cy = queue_ys[head]; + head++; + + // Record all water bodies adjacent to this canal tile. + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (! adj->vtable->m35_Check_Is_Water (adj)) + continue; + + int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); + if ((adj_continent_id < 0) || (adj_continent_id >= continent_count)) + continue; + if (! seen[adj_continent_id]) { + seen[adj_continent_id] = true; + ids[id_count] = adj_continent_id; + id_count++; + } + } + + // Traverse to neighboring completed canal districts. + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) + continue; + + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (adj); + if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || (! district_is_complete (adj, CANAL_DISTRICT_ID))) + continue; + + bool seen_canal = false; + for (int j = 0; j < tail; j++) { + if ((queue_xs[j] == nx) && (queue_ys[j] == ny)) { + seen_canal = true; + break; + } + } + if (! seen_canal && (tail < tile_count)) { + queue_xs[tail] = nx; + queue_ys[tail] = ny; + tail++; + } + } + } + + free (queue_xs); + free (queue_ys); + free (seen); + + if (out_count != NULL) + *out_count = id_count; + if (id_count <= 0) { + free (ids); + return NULL; + } + + return ids; +} + +Tile * +find_tile_for_neighborhood_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + + // Search in order: ring 1, then rings 2..N + // Ring order array: 1, 2, 3, ..., city_work_radius + int ring_order[8]; + int ring_count = 0; + for (int r = 1; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + + Tile * best_tile = NULL; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + bool has_resource = false; + if (is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + continue; + } + + if (! tile_suitable_for_district (tile, NEIGHBORHOOD_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + if (get_district_instance (tile) != NULL && + ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +find_tile_for_port_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + int threshold_for_body_of_water = 21; // Mimic vanilla behavior so AI doesn't build ports in small lakes + + // Search in order: ring 1, then rings 2..N + int ring_order[8]; + int ring_count = 0; + for (int r = 1; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + + Tile * best_tile = NULL; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + bool has_resource = false; + if (is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + continue; + } + + if (! tile_suitable_for_district (tile, PORT_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + if (get_district_instance (tile) != NULL && + ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + continue; + if (! tile->vtable->m35_Check_Is_Water (tile)) + continue; + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + bool large_enough_body = (continent->Body.TileCount >= threshold_for_body_of_water); + if (! large_enough_body) { + int connected_count = 0; + int * connected_ids = get_water_continent_ids_connected_via_canal (tile, &connected_count); + for (int i = 0; i < connected_count; i++) { + int connected_id = connected_ids[i]; + if ((connected_id < 0) || (connected_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * connected_continent = &p_bic_data->Map.Continents[connected_id]; + if (connected_continent->Body.TileCount >= threshold_for_body_of_water) { + large_enough_body = true; + break; + } + } + if (connected_ids != NULL) + free (connected_ids); + } + if (! large_enough_body) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +find_tile_for_wonder_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + int target_improv_id = -1; + if (look_up_pending_building_order (city, &target_improv_id)) { + if ((target_improv_id < 0) || + (target_improv_id >= p_bic_data->ImprovementsCount) || + ((p_bic_data->Improvements[target_improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0)) + target_improv_id = -1; + } + if (target_improv_id < 0) { + int order_id = city->Body.Order_ID; + if ((city->Body.Order_Type == COT_Improvement) && + (order_id >= 0) && + (order_id < p_bic_data->ImprovementsCount)) { + Improvement * order = &p_bic_data->Improvements[order_id]; + if (order->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + target_improv_id = order_id; + } + } + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + + // Search in order: ring 2, then rings 3..N, then ring 1 as last resort + int ring_order[8]; + int ring_count = 0; + ring_order[ring_count++] = 2; + for (int r = 3; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + ring_order[ring_count++] = 1; + + Tile * best_tile = NULL; + bool has_resource = false; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + if (! tile_suitable_for_district (tile, WONDER_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + if (! wonder_is_buildable_on_tile (tile, target_improv_id)) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +find_tile_for_distribution_hub_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + const int resource_penalty = 100; + const int yield_weight = 40; + const int city_distance_weight = 8; + const int capital_distance_weight = 45; + const int desired_min_capital_distance = 8; + const int proximity_penalty_scale = 300; + const int different_continent_bonus = 500; + + Tile * best_tile = NULL; + int best_score = INT_MIN; + int best_adjusted_yield = INT_MIN; + int best_distance = -1; + int best_distance_to_capital = -1; + bool best_has_resource = true; + + int civ_id = city->Body.CivID; + bool has_capital = false; + int capital_x = 0; + int capital_y = 0; + int capital_continent_id = -1; + + City * capital = get_city_ptr (leaders[civ_id].CapitalID); + if (capital != NULL) { + has_capital = true; + capital_x = capital->Body.X; + capital_y = capital->Body.Y; + Tile * capital_tile = tile_at (capital_x, capital_y); + if ((capital_tile != NULL) && (capital_tile != p_null_tile)) + capital_continent_id = capital_tile->vtable->m46_Get_ContinentID (capital_tile); + } + + FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { + int tx = wai.tile_x, ty = wai.tile_y; + Tile * tile = wai.tile; + bool has_resource; + if (! tile_suitable_for_district (tile, DISTRIBUTION_HUB_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + + int chebyshev = compute_wrapped_chebyshev_distance (tx, ty, city->Body.X, city->Body.Y); + if (chebyshev <= 1) + continue; + + bool too_close_to_existing_hub_or_city = false; + for (int m = 0; m < workable_tile_counts[2]; m++) { + int ndx, ndy; + patch_ni_to_diff_for_work_area (m, &ndx, &ndy); + int nx = tx + ndx, ny = ty + ndy; + wrap_tile_coords (&p_bic_data->Map, &nx, &ny); + Tile * nearby_tile = tile_at (nx, ny); + if ((nearby_tile != NULL) && (nearby_tile != p_null_tile)) { + struct district_instance * nearby_inst = get_district_instance (nearby_tile); + if ((nearby_inst != NULL) && + (nearby_inst->district_id == DISTRIBUTION_HUB_DISTRICT_ID) && + district_is_complete (nearby_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { + too_close_to_existing_hub_or_city = true; + break; + } + else if (nearby_tile->CityID >= 0) { + too_close_to_existing_hub_or_city = true; + break; + } + } + } + if (too_close_to_existing_hub_or_city) + continue; + + int raw_yield = compute_city_tile_yield_sum (city, tx, ty); + int adjusted_yield = raw_yield - (has_resource ? resource_penalty : 0); + int distance = compute_wrapped_manhattan_distance (tx, ty, city->Body.X, city->Body.Y); + int distance_to_capital = has_capital + ? compute_wrapped_manhattan_distance (tx, ty, capital_x, capital_y) + : 0; + + int proximity_penalty = 0; + if (has_capital && (distance_to_capital < desired_min_capital_distance)) + proximity_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; + + int continent_bonus = 0; + if ((capital_continent_id >= 0) && (tile != NULL) && (tile != p_null_tile)) { + int tile_continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((tile_continent_id >= 0) && (tile_continent_id != capital_continent_id)) + continent_bonus = different_continent_bonus; + } + + int score = + adjusted_yield * yield_weight + + distance * city_distance_weight + + distance_to_capital * capital_distance_weight - + proximity_penalty + + continent_bonus; + + if ((score > best_score) || + ((score == best_score) && (distance_to_capital > best_distance_to_capital)) || + ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield > best_adjusted_yield)) || + ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance > best_distance)) || + ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance == best_distance) && (! has_resource && best_has_resource))) { + best_tile = tile; + best_score = score; + best_adjusted_yield = adjusted_yield; + best_distance = distance; + best_distance_to_capital = distance_to_capital; + best_has_resource = has_resource; + *out_x = tx; + *out_y = ty; + } + } + + return best_tile; +} + +bool +city_can_build_district (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos const * info = &is->district_infos[district_id]; + + if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) + return false; + + if ((info->resource_prereq_count > 0) || (info->resource_prereq_on_tile_id >= 0)) { + bool resource_prereqs_met = false; + + FOR_TILES_AROUND (tai, is->workable_tile_count, city->Body.X, city->Body.Y) { + Tile * tile = tai.tile; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) + continue; + if (! district_resource_prereqs_met_r (tile, tai.tile_x, tai.tile_y, district_id, INT_MAX)) + continue; + + resource_prereqs_met = true; + break; + } + + if (! resource_prereqs_met) + return false; + } + + // Check if district does not allow multiple and city already has one + if (! cfg->allow_multiple && city_has_required_district (city, district_id)) + return false; + + return true; +} + +bool +leader_has_wonder_prereq (Leader * leader, struct district_infos const * info) +{ + if (info == NULL) + return false; + if (info->wonder_prereq_count <= 0) + return true; + if ((leader == NULL) || (leader->Improvement_Counts == NULL)) + return false; + + for (int i = 0; i < info->wonder_prereq_count; i++) { + int improv_id = info->wonder_prereq_ids[i]; + if (improv_id >= 0 && leader->Improvement_Counts[improv_id] > 0) + return true; + } + + return false; +} + +bool +leader_has_natural_wonder_prereq_in_territory (int civ_id, struct district_infos const * info) +{ + if (info == NULL) + return false; + if (info->natural_wonder_prereq_count <= 0) + return true; + if (! is->current_config.enable_natural_wonders) + return false; + + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + + int wonder_id = inst->natural_wonder_info.natural_wonder_id; + if (wonder_id < 0) + continue; + + bool matches = false; + for (int i = 0; i < info->natural_wonder_prereq_count; i++) { + if (info->natural_wonder_prereq_ids[i] == wonder_id) { + matches = true; + break; + } + } + if (! matches) + continue; + + Tile * tile = (Tile *)tei.key; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; + } + + return false; +} + +int +count_distribution_hubs_for_civ (int civ_id) +{ + int current = 0; + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if ((rec != NULL) && (rec->civ_id == civ_id)) + current++; + } + return current; +} + +bool +leader_can_natively_build_district (Leader * leader, int district_id) +{ + if ((leader == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos const * info = &is->district_infos[district_id]; + + for (int i = 0; i < info->advance_prereq_count; i++) { + int prereq_id = info->advance_prereq_ids[i]; + if ((prereq_id >= 0) && ! Leader_has_tech (leader, __, prereq_id)) + return false; + } + int obsolete_id = info->obsoleted_by_id; + if ((obsolete_id >= 0) && Leader_has_tech (leader, __, obsolete_id)) + return false; + + if (! leader_has_wonder_prereq (leader, info)) + return false; + + if (! leader_has_natural_wonder_prereq_in_territory (leader->ID, info)) + return false; + + if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) { + int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; + if (max_per_100 > 0) { + int city_count = leader->Cities_Count; + int max_allowed = (city_count * max_per_100 + 99) / 100; + if (max_allowed <= 0) + return false; + + int current = count_distribution_hubs_for_civ (leader->ID); + if (current >= max_allowed) + return false; + } + } + + if (cfg->has_buildable_by_civs) { + bool civ_match = false; + if (cfg->buildable_by_civ_count > 0) { + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + for (int i = 0; i < cfg->buildable_by_civ_count; i++) { + char const * civ_name = cfg->buildable_by_civs[i]; + if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; + if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; + if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; + if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; + if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; + } + } + if (! civ_match) + return false; + } + + if (cfg->has_buildable_by_civ_traits) { + if (cfg->buildable_by_civ_traits_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL || race->vtable == NULL) + return false; + bool trait_match = false; + for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { + int trait_id = cfg->buildable_by_civ_traits_ids[i]; + if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { + trait_match = true; + break; + } + } + if (! trait_match) + return false; + } + + if (cfg->has_buildable_by_civ_govs) { + if (cfg->buildable_by_civ_govs_id_count <= 0) + return false; + int gov_id = leader->GovernmentType; + bool gov_match = false; + for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { + if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { + gov_match = true; + break; + } + } + if (! gov_match) + return false; + } + + if (cfg->has_buildable_by_civ_cultures) { + if (cfg->buildable_by_civ_cultures_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + int culture_id = race->CultureGroupID; + bool culture_match = false; + for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { + if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { + culture_match = true; + break; + } + } + if (! culture_match) + return false; + } + + return true; +} + +bool +leader_has_war_ally_district_access (Leader * leader, int district_id) +{ + if (leader == NULL) + return false; + + int self_id = leader->ID; + for (int civ_id = 0; civ_id < 32; civ_id++) { + if (civ_id == self_id) + continue; + Leader * other = &leaders[civ_id]; + if (other->Military_Allies[self_id] != 0 && leader_can_natively_build_district (other, district_id)) + return true; + } + + return false; +} + +bool +leader_has_pact_ally_district_access (Leader * leader, int district_id) +{ + if (leader == NULL) + return false; + + int self_id = leader->ID; + for (int civ_id = 0; civ_id < 32; civ_id++) { + if (civ_id == self_id) + continue; + Leader * other = &leaders[civ_id]; + if (((leader->Relation_Treaties[civ_id] & 1) != 0 && // 1 = peace treaty + (leader->Relation_Treaties[civ_id] & 4) != 0) && // 4 = mutual protection pact + leader_can_natively_build_district (other, district_id)) { + return true; + } + } + + return false; +} + +bool +leader_can_build_district (Leader * leader, int district_id) +{ + bool can_natively_build = leader_can_natively_build_district (leader, district_id); + + if (can_natively_build) + return true; + + struct district_config const * cfg = &is->district_configs[district_id]; + if (cfg->buildable_by_war_allies && leader_has_war_ally_district_access (leader, district_id)) + return true; + if (cfg->buildable_by_pact_allies && leader_has_pact_ally_district_access (leader, district_id)) + return true; + + return can_natively_build; +} + +Tile * +find_tile_for_district (City * city, int district_id, int * out_x, int * out_y) +{ + if ((city == NULL) || (out_x == NULL) || (out_y == NULL)) + return NULL; + if ((district_id < 0) || (district_id >= is->district_count)) + return NULL; + + // Check if city can build this district at all + if (! city_can_build_district (city, district_id)) + return NULL; + + if (district_id == NEIGHBORHOOD_DISTRICT_ID) + return find_tile_for_neighborhood_district (city, out_x, out_y); + if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) + return find_tile_for_distribution_hub_district (city, out_x, out_y); + if (district_id == PORT_DISTRICT_ID) + return find_tile_for_port_district (city, out_x, out_y); + if (district_id == WONDER_DISTRICT_ID) + return find_tile_for_wonder_district (city, out_x, out_y); + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + + // Search in order: ring 2, then rings 3..N, then ring 1 as last resort + // Ring order array: 2, 3, 4, ..., city_work_radius, 1 + int ring_order[8]; + int ring_count = 0; + ring_order[ring_count++] = 2; + for (int r = 3; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + ring_order[ring_count++] = 1; + + Tile * best_tile = NULL; + struct district_config * cfg = &is->district_configs[district_id]; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + bool has_resource = false; + if (is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + continue; + } + + if (! tile_suitable_for_district (tile, district_id, city, &has_resource)) + continue; + if (cfg->resource_prereq_on_tile < 0 && has_resource) + continue; + if (get_district_instance (tile) != NULL && ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +get_completed_district_tile_for_city (City * city, int district_id, int * out_x, int * out_y) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return NULL; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + struct district_instance * inst = wai.district_inst; + + if (inst->district_id != district_id) + continue; + + // For wonder districts, filter based on wonder_district_state + if (district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = &inst->wonder_info; + // Must be either unused or under construction by this city + if (info->state == WDS_COMPLETED) + continue; + if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) + continue; + if (info->state == WDS_UNDER_CONSTRUCTION) { + info->city = city; + info->city_id = city->Body.ID; + } + } + + if (out_x != NULL) + *out_x = x; + if (out_y != NULL) + *out_y = y; + return candidate; + } + + return NULL; +} + +bool +tile_has_friendly_aerodrome_district (Tile * tile, int civ_id, bool require_available) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_aerodrome_districts || + (tile == NULL) || + (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != AERODROME_DISTRICT_ID) + return false; + + if (! district_is_complete (tile, AERODROME_DISTRICT_ID)) + return false; + + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (territory_owner != civ_id) + return false; + + if (require_available) { + int usage_mask; + if (itable_look_up (&is->aerodrome_airlift_usage, (int)tile, &usage_mask) && + (usage_mask & (1 << civ_id))) + return false; + } + + return true; +} + +bool +tile_has_friendly_port_district (Tile * tile, int civ_id) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + (tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != PORT_DISTRICT_ID)) + return false; + + if (! district_is_complete (tile, PORT_DISTRICT_ID)) + return false; + + return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; +} + +bool +city_has_required_district (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + if (get_completed_district_tile_for_city (city, district_id, NULL, NULL) != NULL) { + clear_city_district_request (city, district_id); + return true; + } + return false; +} + +bool +city_has_wonder_district_with_no_completed_wonder (City * city, int wonder_improv_id) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + Tile * candidate = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + + struct wonder_district_info * info = get_wonder_district_info (candidate); + bool buildable = wonder_is_buildable_on_tile (candidate, wonder_improv_id); + if (info == NULL) return true; + if (info->state == WDS_COMPLETED) continue; + if (info->state == WDS_UNUSED && buildable) return true; + if (info->state == WDS_UNDER_CONSTRUCTION && buildable && info->city_id == city->Body.ID) { + info->city = city; + return true; // Reserved by this city + } + } + + return false; +} + +int __fastcall patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city); +int __fastcall patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null); +void __fastcall patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3); + + +void __fastcall +patch_Main_Screen_Form_show_map_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) +{ + WITH_PAUSE_FOR_POPUP { + Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, pause); + } +} + +int __cdecl +patch_process_text_for_map_message (char * in, char * out) +{ + if (is->map_message_text_override != NULL) { + strcpy (out, is->map_message_text_override); + is->map_message_text_override = NULL; + return 0; + } else + return process_text_snippet (in, out); +} + +// Works like show_map_message but takes a bit of text to display instead of a key for script.txt +void +show_map_specific_text (int tile_x, int tile_y, char const * text, bool pause) +{ + is->map_message_text_override = text; + patch_Main_Screen_Form_show_map_message (p_main_screen_form, __, tile_x, tile_y, "LANDCONQUER", pause); // Use any key here. It will be overridden. +} + +bool __fastcall +patch_City_has_improvement (City * this, int edx, int improv_id, bool include_auto_improvements) +{ + bool tr = City_has_improvement (this, __, improv_id, include_auto_improvements); + + // Check if the improvement is provided for free by another human player's wonder if we're in a hotseat game and the config option is on + if ((! tr) && + include_auto_improvements && + is->current_config.share_wonders_in_hotseat && + ((1 << this->Body.CivID) & *p_human_player_bits) && + (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // if we're in a hotseat game + + // Loop over every other human player in the game and check if the city would have the improv if they were its owner + int actual_owner_id = this->Body.CivID; + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != actual_owner_id)) { + this->Body.CivID = n_player; + if (City_has_improvement (this, __, improv_id, include_auto_improvements)) { + tr = true; + break; + } + } + player_bits >>= 1; + n_player++; + } + this->Body.CivID = actual_owner_id; + + } + + return tr; +} + +int +count_neighborhoods_in_city_radius (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return 0; + + int count = 0; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + struct district_instance * inst = wai.district_inst; + if (inst != NULL && + inst->district_id >= 0 && inst->district_id < is->district_count && + inst->district_id == NEIGHBORHOOD_DISTRICT_ID) + count++; + } + return count; +} + +int +count_utilized_neighborhoods_in_city_radius (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return 0; + + int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; + if (base_cap <= 0) + return 0; + + int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; + if (per_neighborhood <= 0) + return 0; + + int pop = city->Body.Population.Size; + if (pop <= base_cap) + return 0; + + int excess_pop = pop - base_cap; + int utilized = (excess_pop + per_neighborhood - 1) / per_neighborhood; + int total_neighborhoods = count_neighborhoods_in_city_radius (city); + + if (utilized > total_neighborhoods) + utilized = total_neighborhoods; + + return utilized; +} + +int +get_neighborhood_pop_cap (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return -1; + + int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; + if (base_cap <= 0) + return -1; + + int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; + if (per_neighborhood < 0) + per_neighborhood = 0; + + int neighborhoods = count_neighborhoods_in_city_radius (city); + long long cap = (long long)base_cap + (long long)per_neighborhood * neighborhoods; + if (cap < base_cap) + cap = base_cap; + + return (int)cap; +} + +bool +city_is_at_neighborhood_cap (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return false; + + int cap = get_neighborhood_pop_cap (city); + if (cap <= 0) + return false; + + return city->Body.Population.Size >= cap; +} + +void +ensure_neighborhood_request_for_city (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return; + + if (! leader_can_build_district (&leaders[city->Body.CivID], NEIGHBORHOOD_DISTRICT_ID)) + return; + + mark_city_needs_district (city, NEIGHBORHOOD_DISTRICT_ID); +} + +void +calculate_district_culture_science_bonuses (City * city, int * culture_bonus, int * science_bonus) +{ + if (culture_bonus != NULL) + *culture_bonus = 0; + if (science_bonus != NULL) + *science_bonus = 0; + + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders) || (city == NULL)) + return; + + int total_culture = 0; + int total_science = 0; + int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) + continue; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + struct district_config const * cfg = &is->district_configs[district_id]; + int district_culture_bonus = 0; + int district_science_bonus = 0; + get_effective_district_yields (inst, cfg, NULL, NULL, NULL, &district_science_bonus, &district_culture_bonus, NULL); + + bool is_neighborhood = (cfg->command == UCV_Build_Neighborhood); + if (is_neighborhood) { + if (utilized_neighborhoods > 0) { + total_culture += district_culture_bonus; + total_science += district_science_bonus; + utilized_neighborhoods--; + } + } else { + total_culture += district_culture_bonus; + total_science += district_science_bonus; + } + } + + if (culture_bonus != NULL) + *culture_bonus = total_culture; + if (science_bonus != NULL) + *science_bonus = total_science; +} + +void +calculate_district_happiness_bonus (City * city, int * happiness_bonus) +{ + if (happiness_bonus != NULL) + *happiness_bonus = 0; + + if (! is->current_config.enable_districts || (city == NULL)) + return; + + int total_happy = 0; + int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) + continue; + + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + struct district_config const * cfg = &is->district_configs[district_id]; + + bool is_neighborhood = district_id == NEIGHBORHOOD_DISTRICT_ID; + if (is_neighborhood && (utilized_neighborhoods <= 0)) + continue; + + if (is_neighborhood) + utilized_neighborhoods--; + + int district_happy = 0; + get_effective_district_yields (inst, cfg, NULL, NULL, NULL, NULL, NULL, &district_happy); + if (district_happy != 0) + total_happy += district_happy; + } + + if (happiness_bonus != NULL) + *happiness_bonus = total_happy; +} + +int __fastcall +patch_City_requires_improvement_to_grow (City * this) +{ + int required_improv = City_requires_improvement_to_grow (this); + if ((required_improv == -1) && + (this != NULL) && + is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + city_is_at_neighborhood_cap (this)) { + return 0; // Neighborhood sentinel + } + + return required_improv; +} + +// Replacement check specifically for stalled growth check function, +// where we can't pass through the neighborhood sentinel. That function itself +// doesn't block growth, it just triggers the dialog, so safe to skip it if +// neighborhoods are needed. +int __fastcall +patch_City_requires_improvement_to_grow_besides_neighborhood (City * this) +{ + return City_requires_improvement_to_grow (this); +} + +void __fastcall +patch_maybe_show_improvement_needed_for_growth_dialog (void * this, int edx, City * city, int * param_2) +{ + int required_improv_id = (int)param_2; + if (is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + (required_improv_id == 0)) // Neighborhood sentinel + return; + + maybe_show_improvement_needed_for_growth_dialog (this, __, city, param_2); +} + +void +maybe_show_neighborhood_growth_warning (City * city) +{ + if ((city == NULL) || ! (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts)) return; + int requirement = patch_City_requires_improvement_to_grow (city); + if (requirement != 0) return; // Neighborhood sentinel not present + if (city->Body.FoodIncome <= 0) return; // Not growing + if (is_online_game ()) return; + int civ_id = city->Body.CivID; + if (civ_id != p_main_screen_form->Player_CivID) return; + if ((*p_human_player_bits & (1u << civ_id)) == 0) return; + + unsigned int turn_no = (unsigned int)*p_current_turn_no; + unsigned int throttle = ((unsigned int)city->Body.X << 5) ^ (unsigned int)city->Body.Y; + int frequency = is->current_config.neighborhood_needed_message_frequency; + if ((frequency <= 0) || (((turn_no + throttle) % frequency) != 0)) + return; + + char msg[160]; + char const * city_name = city->Body.CityName; + snprintf (msg, sizeof msg, "%s %s %s %s", + city_name, + is->c3x_labels[CL_REQUIRES], + is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name, + is->c3x_labels[CL_TO_GROW] + ); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); +} + +bool __stdcall +patch_is_not_pop_capped_or_starving (City * city) +{ + bool tr = is_not_pop_capped_or_starving (city); + if (! tr) return false; + + if (is->current_config.enable_districts) { + if (city_is_at_neighborhood_cap (city)) + return false; + } + + return true; +} + +bool +remove_building_if_no_district (City * city, int district_id, int building_id) +{ + if ((city == NULL) || (building_id < 0)) return false; + if (! patch_City_has_improvement (city, __, building_id, false)) return false; + if (city_has_required_district (city, district_id)) return false; + + patch_City_add_or_remove_improvement (city, __, building_id, 0, false); + return true; +} + +bool +city_has_other_completed_wonder_district_for_improvement (City * city, int wonder_improv_id, int removed_x, int removed_y) +{ + if (! (is->current_config.enable_districts && is->current_config.enable_wonder_districts) || + (city == NULL) || (wonder_improv_id < 0)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + if ((x == removed_x) && (y == removed_y)) + continue; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if (info->state != WDS_COMPLETED) + continue; + + int candidate_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); + if (candidate_improv_id != wonder_improv_id) + continue; + + return true; + } + + return false; +} + +void +remove_shared_wonder_if_no_other_district (City * city, int wonder_improv_id, int removed_x, int removed_y) +{ + if ((city == NULL) || (wonder_improv_id < 0)) + return; + + if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) + return; + + if (leaders[city->Body.CivID].Small_Wonders[wonder_improv_id] == city->Body.ID) + return; + + if (city_has_other_completed_wonder_district_for_improvement (city, wonder_improv_id, removed_x, removed_y)) + return; + + patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); +} + +void +reduce_city_population_due_to_lost_neighborhood (City * city) +{ + if (city == NULL) + return; + + if (! (is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + is->current_config.destroying_neighborhood_reduces_pop)) + return; + + int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; + int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; + if ((base_cap <= 0) || (per_neighborhood <= 0)) + return; + + int neighborhoods = count_neighborhoods_in_city_radius (city); + int cap = base_cap + (per_neighborhood * neighborhoods); + if (cap < base_cap) + cap = base_cap; + + int pop = city->Body.Population.Size; + if (pop <= cap) + return; + + int to_remove = pop - cap; + int removed = 0; + while (to_remove-- > 0) { + City_remove_population (city, __, 1, -1, '\0'); + removed++; + } + + if ((removed > 0) && + ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && + (city->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[160]; + snprintf (msg, sizeof msg, "%s %s %s", + city->Body.CityName, + is->c3x_labels[CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD], + is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name + ); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } +} + +bool +city_has_other_completed_district (City * city, int district_id, int removed_x, int removed_y) +{ + if (! is->current_config.enable_districts || + (city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + if ((x == removed_x) && (y == removed_y)) + continue; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != district_id) + continue; + + return true; + } + + return false; +} + +bool +district_instance_is_redundant (struct district_instance * inst, Tile * tile) +{ + if (! is->current_config.enable_districts || + (inst == NULL) || + (tile == NULL) || (tile == p_null_tile)) + return false; + + int district_id = inst->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + if (! district_is_complete (tile, district_id)) + return false; + + if (district_id == NEIGHBORHOOD_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID) + return false; + + int tile_x = inst->tile_x; + int tile_y = inst->tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + return false; + + int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + + if (district_id == WONDER_DISTRICT_ID) + return inst->wonder_info.state == WDS_UNUSED; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + if (! city_has_other_completed_district (wai.city, district_id, tile_x, tile_y)) + return false; + } + + return true; +} + +bool +any_nearby_city_would_lose_district_benefits (int district_id, int civ_id, int removed_x, int removed_y) +{ + if (! is->current_config.enable_districts) + return false; + + if (district_id < 0 || district_id >= is->district_count) + return false; + + struct district_infos * info = &is->district_infos[district_id]; + + // If there are no dependent buildings, no city can lose benefits + if (info->dependent_building_count == 0) + return false; + + // Check all cities within work radius of the removed district + FOR_CITIES_AROUND (wai, removed_x, removed_y) { + City * city = wai.city; + + // Check if this city has another completed district of the same type nearby (excluding the one being removed) + if (city_has_other_completed_district (city, district_id, removed_x, removed_y)) + continue; + + // This city doesn't have another district, check if it has any dependent buildings + for (int i = 0; i < info->dependent_building_count; i++) { + int building_id = info->dependent_building_ids[i]; + if (building_id >= 0 && patch_City_has_improvement (city, __, building_id, false)) + return true; + } + } + + return false; +} + +void +remove_dependent_buildings_for_district (int district_id, int center_x, int center_y) +{ + if (! is->current_config.enable_districts || (district_id < 0) || (district_id >= is->district_count)) + return; + + struct district_infos * info = &is->district_infos[district_id]; + + if ((center_x < 0) || (center_y < 0) || + (center_x >= p_bic_data->Map.Width) || (center_y >= p_bic_data->Map.Height)) + return; + + FOR_CITIES_AROUND (wai, center_x, center_y) { + City * city = wai.city; + + if (city_has_other_completed_district (city, district_id, center_x, center_y)) + continue; + + int removed_count = 0; + int first_building_id = -1; + + for (int i = 0; i < info->dependent_building_count; i++) { + int building_id = info->dependent_building_ids[i]; + if (building_id >= 0) { + // This also loops through tiles around the city but is not redundant, as the city + // may have multiple districts of the same type in its radius (eg outside radius of this particular district) + if (remove_building_if_no_district (city, district_id, building_id)) { + if (removed_count == 0) + first_building_id = building_id; + removed_count++; + } + } + } + + if ((removed_count > 0) && + is->current_config.show_message_when_building_lost_to_destroyed_district && + ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && + (city->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[200]; + char const * district_name = is->district_configs[district_id].name; + char const * building_name = (first_building_id >= 0) ? p_bic_data->Improvements[first_building_id].Name.S : ""; + + if (removed_count == 1) + snprintf (msg, sizeof msg, "%s%s %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_APOSTROPHE_S], + building_name, + is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], + district_name); + else + snprintf (msg, sizeof msg, "%s%s %s %s %d %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_APOSTROPHE_S], + building_name, + is->c3x_labels[CL_AND], + removed_count - 1, + is->c3x_labels[CL_OTHER_BUILDINGS_HAVE_BEEN], + is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], + district_name); + + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + } +} + +void +remove_wonder_improvement_for_destroyed_district (int wonder_improv_id) +{ + if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) + return; + + if ((p_cities == NULL) || (p_cities->Cities == NULL)) + return; + + for (int idx = 0; idx <= p_cities->LastIndex; idx++) { + City * city = get_city_ptr (idx); + if (city == NULL) + continue; + if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) + continue; + + patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); + } +} + +void +handle_district_removed (Tile * tile, int district_id, int center_x, int center_y, bool leave_ruins) +{ + if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.enable_districts) + return; + + int wonder_windex = -1; + int wonder_improv_id = -1; + + // Get wonder district info before removing + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info != NULL && info->state == WDS_COMPLETED) + wonder_windex = info->wonder_index; + + int actual_district_id = district_id; + if (actual_district_id < 0) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) + actual_district_id = inst->district_id; + } + + remove_district_instance (tile); + + bool removed_neighborhood = actual_district_id == NEIGHBORHOOD_DISTRICT_ID; + + if (is->current_config.enable_wonder_districts && + (actual_district_id == WONDER_DISTRICT_ID) && + (wonder_windex >= 0)) + wonder_improv_id = get_wonder_improvement_id_from_index (wonder_windex); + + if (wonder_improv_id >= 0 && is->current_config.completed_wonder_districts_can_be_destroyed) + remove_wonder_improvement_for_destroyed_district (wonder_improv_id); + + if (is->current_config.enable_distribution_hub_districts && + (actual_district_id == DISTRIBUTION_HUB_DISTRICT_ID)) + remove_distribution_hub_record (tile); + + if (district_id >= 0) + remove_dependent_buildings_for_district (district_id, center_x, center_y); + + // Make the tile workable again by resetting CityAreaID and recomputing yields for nearby cities + tile->Body.CityAreaID = -1; + + int tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + FOR_CITIES_AROUND (wai, center_x, center_y) { + if (removed_neighborhood) + reduce_city_population_due_to_lost_neighborhood (wai.city); + recompute_city_yields_with_districts (wai.city); + } + + if (leave_ruins && (tile->vtable->m60_Set_Ruins != NULL)) { + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, center_x, center_y); + tile->vtable->m60_Set_Ruins (tile, __, 1); + } + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +bool +city_has_active_wonder_for_district (City * city) +{ + struct district_infos * info = &is->district_infos[WONDER_DISTRICT_ID]; + for (int n = 0; n < ARRAY_LEN (info->dependent_building_ids); n++) { + int building_id = info->dependent_building_ids[n]; + if ((building_id >= 0) && has_active_building (city, building_id)) + return true; + } + return false; +} + +bool +city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id) +{ + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); + if ((prereq_list == NULL) || (prereq_list->count <= 0)) + return false; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder = false; + + // Special logic for handling rivers + bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; + bool has_prereq = false; + + if (is->current_config.enable_wonder_districts && + district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) { + is_wonder = true; + if (! wonder_is_buildable_by_civ (improv_id, city->Body.CivID)) { + if (out_district_id != NULL) + *out_district_id = -1; + return false; + } + if (requires_river) { + bool has_river_wonder_district = false; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if (wai.district_inst->district_id != WONDER_DISTRICT_ID) + continue; + if (wai.tile->vtable->m37_Get_River_Code (wai.tile) == 0) + continue; + if (! wonder_is_buildable_on_tile (wai.tile, improv_id)) + continue; + struct wonder_district_info * info = get_wonder_district_info (wai.tile); + if (info == NULL) { + has_river_wonder_district = true; + break; + } + if (info->state == WDS_COMPLETED) + continue; + if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) + continue; + has_river_wonder_district = true; + break; + } + if (has_river_wonder_district) + has_prereq = true; + } else if (city_has_wonder_district_with_no_completed_wonder (city, improv_id)) { + has_prereq = true; + } + } + + if (! has_prereq && city_has_any_prereq_district_for_improvement (city, prereq_list, requires_river, !is_wonder)) + has_prereq = true; + + if (has_prereq) + return false; + + if (out_district_id != NULL) + *out_district_id = pick_missing_district_for_improvement (city, prereq_list); + return true; +} + +void +clear_best_feasible_order (City * city) +{ + int key = (int)city; + int stored_int; + if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) { + struct ai_best_feasible_order * stored = (struct ai_best_feasible_order *)stored_int; + free (stored); + itable_remove (&is->ai_best_feasible_orders, key); + } +} + +void +record_best_feasible_order (City * city, City_Order const * order, int value) +{ + int key = (int)city; + int stored_int; + struct ai_best_feasible_order * stored; + if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) + stored = (struct ai_best_feasible_order *)stored_int; + else { + stored = malloc (sizeof *stored); + if (stored == NULL) + return; + stored->order = *order; + stored->value = value; + itable_insert (&is->ai_best_feasible_orders, key, (int)stored); + return; + } + + if (value > stored->value) { + stored->order = *order; + stored->value = value; + } +} + +struct ai_best_feasible_order * +get_best_feasible_order (City * city) +{ + int stored_int; + if (itable_look_up (&is->ai_best_feasible_orders, (int)city, &stored_int)) + return (struct ai_best_feasible_order *)stored_int; + else + return NULL; +} + +bool +city_is_currently_building_wonder (City * city) +{ + if ((city == NULL) || (city->Body.Order_Type != COT_Improvement)) + return false; + int order_id = city->Body.Order_ID; + if ((order_id < 0) || (order_id >= p_bic_data->ImprovementsCount)) + return false; + return (p_bic_data->Improvements[order_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; +} + +bool +wonder_district_tile_under_construction (Tile * tile, int tile_x, int tile_y, int * out_windex) +{ + if (! is->current_config.enable_wonder_districts || + (tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != WONDER_DISTRICT_ID) + return false; + + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info == NULL || info->state != WDS_UNDER_CONSTRUCTION) + return false; + + City * reserved_city = get_city_ptr (info->city_id); + if (reserved_city == NULL) + return false; + info->city = reserved_city; + info->city_id = reserved_city->Body.ID; + + // Verify the reserved city is still building a wonder + if (! city_is_currently_building_wonder (reserved_city)) + return false; + + // Verify this tile is within the reserved city's radius + if (! city_radius_contains_tile (reserved_city, tile_x, tile_y)) + return false; + + // Get the wonder index for the wonder being built + if (out_windex != NULL) { + int order_id = reserved_city->Body.Order_ID; + int windex = find_wonder_config_index_by_improvement_id (order_id); + *out_windex = windex; + } + + return true; +} + +bool +city_needs_wonder_district (City * city) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + + int pending_improv_id; + if (look_up_pending_building_order (city, &pending_improv_id)) { + // Check if it's actually a wonder + if ((pending_improv_id >= 0) && (pending_improv_id < p_bic_data->ImprovementsCount)) { + Improvement * improv = &p_bic_data->Improvements[pending_improv_id]; + if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + return true; + } + } + if (city_is_currently_building_wonder (city)) + return true; + if (city_has_active_wonder_for_district (city)) + return true; + return false; +} + +bool +city_has_assigned_wonder_district (City * city, Tile * ignore_tile, int wonder_improv_id) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + if (candidate == ignore_tile) + continue; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = inst ? &inst->wonder_info : NULL; + if ((info != NULL) && + (info->state == WDS_UNDER_CONSTRUCTION) && + (info->city_id == city->Body.ID)) { + info->city = city; + if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) { + info->state = WDS_UNUSED; + info->city = NULL; + info->city_id = -1; + info->wonder_index = -1; + continue; + } + return true; + } + } + + return false; +} + +bool +free_wonder_district_for_city (City * city) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) + return false; + if (city_needs_wonder_district (city)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { + int x = wai.tile_x, y = wai.tile_y; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info != NULL && info->state == WDS_COMPLETED) + continue; // Don't remove completed wonder districts + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + continue; + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + + handle_district_removed (tile, WONDER_DISTRICT_ID, city->Body.X, city->Body.Y, false); + return true; + } + + return false; +} + +bool +reserve_wonder_district_for_city (City * city, int wonder_improv_id) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) + return false; + + if (city_has_assigned_wonder_district (city, NULL, wonder_improv_id)) + return true; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if (info->state == WDS_COMPLETED) continue; + if (info->state == WDS_UNDER_CONSTRUCTION) { + if (info->city_id == city->Body.ID) { + info->city = city; + return true; + } + continue; + } + if (city_has_assigned_wonder_district (city, candidate, wonder_improv_id)) + return true; + + // Reserve this Wonder district for this city + info->state = WDS_UNDER_CONSTRUCTION; + info->city = city; + info->city_id = city->Body.ID; + info->wonder_index = -1; + return true; + } + + return false; +} + +void +release_wonder_district_reservation (City * city) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return; + + // Find and remove any reservations for this city + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if ((info != NULL) && + (info->state == WDS_UNDER_CONSTRUCTION) && + (info->city_id == city->Body.ID)) { + info->city = city; + info->state = WDS_UNUSED; + info->city = NULL; + info->city_id = -1; + info->wonder_index = -1; + } + } +} + +void +handle_district_destroyed_by_attack (Tile * tile, int tile_x, int tile_y, bool leave_ruins) +{ + if (! is->current_config.enable_districts || tile == NULL || tile == p_null_tile) + return; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + int district_id = inst->district_id; + + // If this is a Wonder District with a completed wonder and wonders can't be destroyed, restore overlay and keep district + if (is->current_config.enable_wonder_districts) { + struct wonder_district_info * info = get_wonder_district_info (tile); + if ((district_id == WONDER_DISTRICT_ID) && + (info != NULL && info->state == WDS_COMPLETED) && + (! is->current_config.completed_wonder_districts_can_be_destroyed)) { + unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); + if ((overlays & TILE_FLAG_MINE) == 0) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + return; + } + } + if (district_id == BRIDGE_DISTRICT_ID || district_id == CANAL_DISTRICT_ID) { + enum UnitTypeClasses target_class = (district_id == BRIDGE_DISTRICT_ID) ? UTC_Land : UTC_Sea; + clear_memo (); + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if (unit == NULL) + continue; + int unit_type_id = unit->Body.UnitTypeID; + if ((unit_type_id < 0) || (unit_type_id >= p_bic_data->UnitTypeCount)) + continue; + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + bool matches = (type->Unit_Class == target_class); + if (! matches && unit->Body.Container_Unit >= 0) { + Unit * container = get_unit_ptr (unit->Body.Container_Unit); + if (container != NULL) { + int container_type_id = container->Body.UnitTypeID; + if ((container_type_id >= 0) && (container_type_id < p_bic_data->UnitTypeCount)) { + UnitType * container_type = &p_bic_data->UnitTypes[container_type_id]; + matches = (container_type->Unit_Class == target_class); + } + } + } + if (matches) { + bool already = false; + for (int n = 0; n < is->memo_len; n++) + if (is->memo[n] == unit->Body.ID) { + already = true; + break; + } + if (! already) + memoize (unit->Body.ID); + } + } + for (int n = 0; n < is->memo_len; n++) { + Unit * to_despawn = get_unit_ptr (is->memo[n]); + if (to_despawn != NULL) + patch_Unit_despawn (to_despawn, __, 0, 1, 0, 0, 0, 0, 0); + } + clear_memo (); + } + handle_district_removed (tile, district_id, tile_x, tile_y, leave_ruins); + } +} + +bool +has_active_building (City * city, int improv_id) +{ + Leader * owner = &leaders[city->Body.CivID]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + return patch_City_has_improvement (city, __, improv_id, 1) && // building is physically present in city AND + ((improv->ObsoleteID < 0) || (! Leader_has_tech (owner, __, improv->ObsoleteID))) && // building is not obsolete AND + ((improv->GovernmentID < 0) || (improv->GovernmentID == owner->GovernmentType)); // building is not restricted to a different govt +} + +void +init_unit_type_count (Leader * leader) +{ + int id = leader->ID; + struct table * counts = &is->unit_type_counts[id]; + + if (counts->len > 0) + table_deinit (counts); + + if (p_units->Units != NULL) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit_Body * body = p_units->Units[n].Unit; + if ((body != NULL) && ((int)body != offsetof (Unit, Body)) && (body->CivID == id)) { + int prev_count = itable_look_up_or (counts, body->UnitTypeID, 0); + itable_insert (counts, body->UnitTypeID, prev_count + 1); + } + } + + is->unit_type_count_init_bits |= 1 << id; +} + +int +get_unit_type_count (Leader * leader, int unit_type_id) +{ + int id = leader->ID; + struct table * counts = &is->unit_type_counts[id]; + + if ((is->unit_type_count_init_bits & 1<ID; + struct table * counts = &is->unit_type_counts[id]; + if ((is->unit_type_count_init_bits & (1 << id)) == 0) + init_unit_type_count (leader); + + int prev_amount = itable_look_up_or (counts, unit_type_id, 0); + itable_insert (counts, unit_type_id, prev_amount + amount); +} + +// If this unit type is limited, returns true and writes how many units of the type the given player is allowed to "out_limit". If the type is not +// limited, returns false. +bool +get_unit_limit (Leader * leader, int unit_type_id, int * out_limit) +{ + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + struct unit_type_limit * lim; + 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; + if (lim->cities_per != 0) + tr += city_count / lim->cities_per; + *out_limit = tr; + return true; + } else + return false; +} + +// This this unit type is limited, returns true and writes to "out_available" how many units the given player can add before reaching the limit. If +// the type is not limited, returns false. +bool +get_available_unit_count (Leader * leader, int unit_type_id, int * out_available) +{ + int limit; + if (get_unit_limit (leader, unit_type_id, &limit)) { + int count = get_unit_type_count (leader, unit_type_id); + int dups[30]; + int dups_count = list_unit_type_duplicates (unit_type_id, dups, ARRAY_LEN (dups)); + for (int n = 0; n < dups_count; n++) + count += get_unit_type_count (leader, dups[n]); + + *out_available = limit - count; + return true; + } else + return false; +} + +int +add_i31b_to_int (int base, i31b addition) +{ + int amount; + bool percent; + i31b_unpack (addition, &amount, &percent); + if (! percent) + return base + amount; + else { + int fraction = (base * int_abs (amount) + 50) / 100; + return (amount >= 0) ? base + fraction : base - fraction; + } +} + +int +apply_perfume (enum perfume_kind kind, char const * name, int base_amount) +{ + i31b perfume_value; + if (stable_look_up (&is->current_config.perfume_specs[kind], name, &perfume_value)) + return add_i31b_to_int (base_amount, perfume_value); + else + return base_amount; +} + +int __stdcall +intercept_consideration (int valuation) +{ + City * city = is->ai_considering_production_for_city; + City_Order * order = &is->ai_considering_order; + + // Apply perfume + char * order_name; { + if (order->OrderType == COT_Improvement) + order_name = p_bic_data->Improvements[order->OrderID].Name.S; + else + order_name = p_bic_data->UnitTypes[order->OrderID].Name; + } + valuation = apply_perfume (PK_PRODUCTION, order_name, valuation); + + // Apply temp AI settler perfume + if ((order->OrderType == COT_Unit) && + (p_bic_data->UnitTypes[order->OrderID].AI_Strategy & UTAI_Settle) && + (is->current_config.ai_settler_perfume_on_founding != 0) && + (is->current_config.ai_settler_perfume_on_founding_duration != 0) && + (is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID] >= 0)) { + int turns_since_founding = *p_current_turn_no - is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID]; + int duration = is->current_config.ai_settler_perfume_on_founding_duration; + if (turns_since_founding < duration) { + i31b perfume = is->current_config.ai_settler_perfume_on_founding; + + // Scale amount by turns remaining + { + int amount; + bool percent; + i31b_unpack (perfume, &amount, &percent); + + int percent_remaining = (100 * (duration - turns_since_founding)) / duration; + amount = (amount * percent_remaining + 50) / 100; + + perfume = i31b_pack (amount, percent); + } + + valuation = add_i31b_to_int (valuation, perfume); + } + } + + if (is->current_config.enable_districts && + (city != NULL) && + ((*p_human_player_bits & (1 << city->Body.CivID)) == 0)) { + bool feasible = false; + switch (order->OrderType) { + case COT_Improvement: + if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->ImprovementsCount) && + (! city_requires_district_for_improvement (city, order->OrderID, NULL))) + feasible = true; + break; + case COT_Unit: + if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->UnitTypeCount)) + feasible = true; + break; + default: + break; + } + if (feasible) + record_best_feasible_order (city, order, valuation); + } + + // Expand the list of valuations if necessary + reserve (sizeof is->ai_prod_valuations[0], (void **)&is->ai_prod_valuations, &is->ai_prod_valuations_capacity, is->count_ai_prod_valuations); + + // Record this valuation + int n = is->count_ai_prod_valuations++; + is->ai_prod_valuations[n] = (struct ai_prod_valuation) { + .order_type = order->OrderType, + .order_id = order->OrderID, + .point_value = valuation + }; + + return valuation; +} + +// Returns a pointer to a bitfield that can be used to record resource access for resource IDs >= 32. This procedure can work with any city ID since +// it allocates and zero-initializes these bit fields as necessary. The given resource ID must be at least 32. The index of the bit for that resource +// within the field is resource_id%32. +unsigned * +get_extra_resource_bits (int city_id, int resource_id) +{ + int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); + int ints_per_city = 1 + extra_resource_count/32; + if (city_id >= is->extra_available_resources_capacity) { + int new_capacity = city_id + 100; + unsigned * new_array = calloc (new_capacity * ints_per_city, sizeof new_array[0]); + if (is->extra_available_resources != NULL) { + memcpy (new_array, is->extra_available_resources, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); + free (is->extra_available_resources); + } + is->extra_available_resources = new_array; + is->extra_available_resources_capacity = new_capacity; + } + return &is->extra_available_resources[city_id * ints_per_city + (resource_id-32)/32]; +} + +void __stdcall +intercept_set_resource_bit (City * city, int resource_id) +{ + if (resource_id < 32) + city->Body.Available_Resources |= 1 << resource_id; + else + *get_extra_resource_bits (city->Body.ID, resource_id) |= 1 << (resource_id&31); +} + +// Must forward declare this function since there's a circular dependency between it and patch_City_has_resource +bool has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id); + +bool __fastcall +patch_City_has_resource (City * this, int edx, int resource_id) +{ + return city_has_resource_r (this, resource_id, INT_MAX); +} + +bool +city_has_resource_r (City * this, int resource_id, int max_generated_resource_id) +{ + bool tr; + if ((this == NULL) || (resource_id < 0) || (resource_id >= p_bic_data->ResourceTypeCount)) + return false; + if (resource_id > max_generated_resource_id) + return false; + + if (is->current_config.patch_phantom_resource_bug && + (resource_id >= 32) && (resource_id < p_bic_data->ResourceTypeCount) && + (! City_has_trade_connection_to_capital (this))) { + unsigned bits = (this->Body.ID < is->extra_available_resources_capacity) ? *get_extra_resource_bits (this->Body.ID, resource_id) : 0; + tr = (bits >> (resource_id&31)) & 1; + } else + tr = City_has_resource (this, __, resource_id); + + // Check if access to this resource is provided by a building in the city + if (! tr) + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if ((mill->resource_id == resource_id) && + (mill->flags & MF_LOCAL) && + can_generate_resource (this->Body.CivID, mill) && + has_active_building (this, mill->improv_id) && + has_resources_required_by_building_r (this, mill->improv_id, mill->resource_id - 1)) { + tr = true; + break; + } + } + + // Check if access to this resource is provided by a district in the city's work radius + if ((! tr) && is->current_config.enable_districts) { + FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { + struct district_instance * di = wai.district_inst; + int district_id = di->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + continue; + + struct district_config * dc = &is->district_configs[district_id]; + if ((dc->generated_resource_id == resource_id) && + (dc->generated_resource_flags & MF_LOCAL) && + district_generates_resource_for_civ (wai.tile, di, dc, this->Body.CivID)) { + tr = true; + break; + } + } + } + + return tr; +} + +// Checks if the resource requirements for an improvement are satisfied in a given city. The "max_req_resource_id" parameter is to guard against +// infinite loops in case of circular resource dependencies due to mills. The way it works is that resource requirements can only be satisfied if +// their ID is not greater than that limit. This function is called recursively by patch_City_has_resource and in the recursive calls, the limit is +// set to be below the resource ID provided by the mill being considered. So, when considering resource production chains, the limit approaches zero +// with each recursive call, hence infinite loops are not possible. +bool +has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id) +{ + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if (! (improv->ImprovementFlags & ITF_Required_Goods_Must_Be_In_City_Radius)) { + for (int n = 0; n < 2; n++) { + int res_id = (&improv->Resource1ID)[n]; + if ((res_id >= 0) && + ((res_id > max_req_resource_id) || (! city_has_resource_r (city, res_id, max_req_resource_id)))) + return false; + } + return true; + } else { + int * targets = &improv->Resource1ID; + if ((targets[0] < 0) && (targets[1] < 0)) + return true; + int finds[2] = {0, 0}; + + int civ_id = city->Body.CivID; + for (int n = 0; n < is->workable_tile_count; n++) { + int dx, dy; + patch_ni_to_diff_for_work_area (n, &dx, &dy); + int x = city->Body.X + dx, y = city->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &x, &y); + Tile * tile = tile_at (x, y); + if (tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id) { + int res_here = Tile_get_resource_visible_to (tile, __, civ_id); + if (res_here >= 0) { + finds[0] |= targets[0] == res_here; + finds[1] |= targets[1] == res_here; + } + } + } + + return ((targets[0] < 0) || finds[0]) && ((targets[1] < 0) || finds[1]); + } +} + +bool +has_resources_required_by_building (City * city, int improv_id) +{ + return has_resources_required_by_building_r (city, improv_id, INT_MAX); +} + +void __fastcall +patch_City_recompute_commerce (City * this) +{ + City_recompute_commerce (this); + + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + int science_bonus = 0; + calculate_district_culture_science_bonuses (this, NULL, &science_bonus); + + if (science_bonus != 0) { + this->Body.Science += science_bonus; + if (this->Body.Science < 0) + this->Body.Science = 0; + } +} + +void __fastcall +patch_City_recompute_yields_and_happiness (City * this) +{ + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts && + ! is->distribution_hub_refresh_in_progress && + is->distribution_hub_totals_dirty) + recompute_distribution_hub_totals (); + + City_recompute_yields_and_happiness (this); +} + +void __fastcall +patch_City_update_culture (City * this) +{ + City_update_culture (this); + + if ((this == NULL) || ! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + int culture_bonus = 0; + calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); + + if (culture_bonus == 0) + return; + + int culture_income = this->Body.CultureIncome + culture_bonus; + if (culture_income < 0) + culture_income = 0; + this->Body.CultureIncome = culture_income; + + int civ_id = this->Body.CivID; + int total_culture = this->Body.Total_Cultures[civ_id] + culture_bonus; + if (total_culture < 0) + total_culture = 0; + this->Body.Total_Cultures[civ_id] = total_culture; + + City_recompute_cultural_level (this, __, '\0', '\0', '\0'); +} + +void __fastcall +patch_City_recompute_culture_income (City * this) +{ + City_recompute_culture_income (this); + + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + int culture_bonus = 0; + calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); + + if (culture_bonus != 0) { + this->Body.CultureIncome += culture_bonus; + if (this->Body.CultureIncome < 0) + this->Body.CultureIncome = 0; + } +} + +// Recomputes yields in cities with active mills that depend on input resources. Intended to be called when an input resource has been potentially +// gained or lost. Recomputes only for the cities of a given leader or, if NULL, for all cities on the map. +void +recompute_mill_yields_after_resource_change (Leader * leader_or_null) +{ + if (p_cities->Cities != NULL) + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city != NULL) && + ((leader_or_null == NULL) || (city->Body.CivID == leader_or_null->ID))) { + bool any_relevant_mills = false; + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + Improvement * mill_improv = &p_bic_data->Improvements[mill->improv_id]; + if ((mill->flags & MF_YIELDS) && + ((mill_improv->Resource1ID >= 0) || (mill_improv->Resource2ID >= 0)) && + has_active_building (city, mill->improv_id)) { + any_relevant_mills = true; + break; + } + } + if (any_relevant_mills) + patch_City_recompute_yields_and_happiness (city); + } + } +} + + +int +resource_tile_resource_id (struct extra_resource_tile const * rt) +{ + if (rt == NULL) + return -1; + if (rt->type == ERT_MILL_RESOURCE) { + return (rt->mill_info.mill != NULL) ? rt->mill_info.mill->resource_id : -1; + } else if (rt->district_info.cfg != NULL) { + return rt->district_info.cfg->generated_resource_id; + } + return -1; +} + +int +compare_resource_tiles (void const * vp_a, void const * vp_b) +{ + struct extra_resource_tile const * a = vp_a, * b = vp_b; + return resource_tile_resource_id (a) - resource_tile_resource_id (b); +} + +void __fastcall +patch_Trade_Net_recompute_resources (Trade_Net * this, int edx, bool skip_popups) +{ + int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); + int ints_per_city = 1 + extra_resource_count/32; + memset (is->extra_available_resources, 0, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); + + // Assemble list of mill tiles + is->count_resource_tiles = 0; + if (p_cities->Cities != NULL) + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if (city != NULL) + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if (((mill->flags & MF_LOCAL) == 0) && + has_active_building (city, mill->improv_id) && + can_generate_resource (city->Body.CivID, mill)) { + Tile * resource_tile = tile_at (city->Body.X, city->Body.Y); + if ((resource_tile == NULL) || (resource_tile == p_null_tile)) + continue; + reserve (sizeof is->resource_tiles[0], + (void **)&is->resource_tiles, + &is->resource_tiles_capacity, + is->count_resource_tiles); + is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { + .tile = resource_tile, + .type = ERT_MILL_RESOURCE, + .mill_info = { + .city = city, + .mill = mill + } + }; + } + } + } + if (is->current_config.enable_districts) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * district_tile = (Tile *)tei.key; + struct district_instance * inst = (struct district_instance *)tei.value; + if ((district_tile == NULL) || (district_tile == p_null_tile) || (inst == NULL) || (inst->state != DS_COMPLETED)) + continue; + + int district_id = inst->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + continue; + + struct district_config * cfg = &is->district_configs[district_id]; + if ((cfg == NULL) || (cfg->generated_resource_id < 0)) + continue; + + int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); + if (owner_id < 0) + continue; + if ((cfg->generated_resource_flags & MF_LOCAL) != 0) + continue; + if (! district_can_generate_resource (owner_id, cfg)) + continue; + + reserve (sizeof is->resource_tiles[0], + (void **)&is->resource_tiles, + &is->resource_tiles_capacity, + is->count_resource_tiles); + is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { + .tile = district_tile, + .type = ERT_DISTRICT_RESOURCE, + .district_info = { + .inst = inst, + .cfg = cfg + } + }; + } + } + qsort (is->resource_tiles, is->count_resource_tiles, sizeof is->resource_tiles[0], compare_resource_tiles); + + is->got_resource_tile = NULL; + is->saved_tile_count = p_bic_data->Map.TileCount; + p_bic_data->Map.TileCount += is->count_resource_tiles; + Trade_Net_recompute_resources (this, __, skip_popups); + + // Restore the tile count if necessary. It may have already been restored by patch_Map_Renderer_m71_Draw_Tiles. This happens when the call to + // recompute_resources above opens a popup message about connecting a resource for the first time, which triggers redraw of the map. + if (is->saved_tile_count >= 0) { + p_bic_data->Map.TileCount = is->saved_tile_count; + is->saved_tile_count = -1; + } + + recompute_mill_yields_after_resource_change (NULL); + + is->must_recompute_resources_for_mill_inputs = false; +} + +Tile * +get_resource_tile (int index) +{ + struct extra_resource_tile * rt = &is->resource_tiles[index]; + is->got_resource_tile = rt; + return rt->tile; +} + +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_1 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_2 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_3 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_4 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_5 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } + +int __fastcall +patch_Tile_get_visible_resource_when_recomputing (Tile * tile, int edx, int civ_id) +{ + if (is->got_resource_tile != NULL) { + struct extra_resource_tile * rt = is->got_resource_tile; + is->got_resource_tile = NULL; + if (rt->type == ERT_MILL_RESOURCE) { + if ((rt->mill_info.city != NULL) && (rt->mill_info.mill != NULL) && + has_resources_required_by_building (rt->mill_info.city, rt->mill_info.mill->improv_id)) + return rt->mill_info.mill->resource_id; + else + return -1; + } else { + Tile * district_tile = rt->tile; + struct district_instance * inst = rt->district_info.inst; + struct district_config * cfg = rt->district_info.cfg; + if ((district_tile != NULL) && (district_tile != p_null_tile) && (inst != NULL) && + (cfg != NULL) && (inst->state == DS_COMPLETED)) { + int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); + if ((owner_id == civ_id) && district_generates_resource_for_civ (district_tile, inst, cfg, owner_id)) + return cfg->generated_resource_id; + } + return -1; + } + } + + int base_resource = Tile_get_resource_visible_to (tile, __, civ_id); + return base_resource; +} + +int WINAPI +patch_MessageBoxA (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) +{ + if (is->current_config.suppress_hypertext_links_exceeded_popup && + (strcmp (lpText, "Maximum hypertext links exceeded!") == 0)) + return IDOK; + else + return MessageBoxA (hWnd, lpText, lpCaption, uType); +} + +char * __fastcall +do_capture_modified_gold_trade (TradeOffer * trade_offer, int edx, int val, char * str, unsigned base) +{ + is->modifying_gold_trade = trade_offer; + return print_int (val, str, base); +} + +// Here the order of the registers matches the order that they're pushed by the pusha instruction +struct register_set { + int edi, esi, ebp, esp, ebx, edx, ecx, eax; +}; + +// Return 1 to allow the candidate unit to exert ZoC, 0 to exclude it. A pointer to the candidate is in esi. +int __stdcall +filter_zoc_candidate (struct register_set * reg) +{ + Unit * candidate = (Unit *)reg->esi, + * defender = is->zoc_defender; + + UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID], + * defender_type = &p_bic_data->UnitTypes[defender ->Body.UnitTypeID]; + + enum UnitTypeClasses candidate_class = candidate_type->Unit_Class, + defender_class = defender_type ->Unit_Class; + + bool lethal = ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) != 0) && (! is->temporarily_disallow_lethal_zoc); + bool aerial = (is->current_config.special_zone_of_control_rules & SZOCR_AERIAL ) != 0, + amphibious = (is->current_config.special_zone_of_control_rules & SZOCR_AMPHIBIOUS) != 0; + + // Exclude air units if aerial ZoC is not enabled and exclude land-to-sea & sea-to-land ZoC if amphibious is not enabled + if ((! aerial) && (candidate_class == UTC_Air)) + return 0; + if ((! amphibious) && + (((candidate_class == UTC_Land) && (defender_class == UTC_Sea )) || + ((candidate_class == UTC_Sea ) && (defender_class == UTC_Land)))) + return 0; + + // In case of cross-domain ZoC, filter out units with zero bombard strength or range. They can't use their attack strength in this case, so + // without bombard they can be ruled out. Don't forget units may have non-zero bombard strength and zero range for defensive bombard. + int range = (candidate_class != UTC_Air) ? candidate_type->Bombard_Range : candidate_type->OperationalRange; + if ((candidate_class != defender_class) && ((candidate_type->Bombard_Strength <= 0) || (range <= 0))) + return 0; + + // Require lethal config option & lethal bombard against one HP defender + if ((Unit_get_max_hp (defender) - defender->Body.Damage <= 1) && + ((! lethal) || + ((defender_class == UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Sea_Bombardment)) || + ((defender_class != UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Land_Bombardment)))) + return 0; + + // Air units require the bombing action to perform ZoC + if ((candidate_class == UTC_Air) && ! (candidate_type->Air_Missions & UCV_Bombing)) + return 0; + + // Exclude land units in transports if configured + if ((is->current_config.special_zone_of_control_rules & SZOCR_NOT_FROM_INSIDE) && candidate_class == UTC_Land) { + Unit * container = get_unit_ptr (candidate->Body.Container_Unit); + if ((container != NULL) && ! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)) + return 0; + } + + return 1; +} + +#define TRADE_NET_REF_COUNT 315 +#define TRADE_NET_INSTR_COUNT_GOG 22 +#define TRADE_NET_INSTR_COUNT_STEAM 23 +#define TRADE_NET_INSTR_COUNT_PCG 22 +#define TRADE_NET_ADDR_TOTAL_COUNT ((TRADE_NET_REF_COUNT * 3) + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM + TRADE_NET_INSTR_COUNT_PCG) + +int * +load_trade_net_addrs () +{ + if (is->trade_net_addrs_load_state == IS_OK) + return is->trade_net_addrs; + else if (is->trade_net_addrs_load_state == IS_INIT_FAILED) + return NULL; + + bool success = false; + char err_msg[300] = {0}; + + is->trade_net_addrs = calloc (3 * TRADE_NET_ADDR_TOTAL_COUNT, sizeof is->trade_net_addrs[0]); + if (! is->trade_net_addrs) { + snprintf (err_msg, (sizeof err_msg) - 1, "Bad alloc"); + goto done; + } + + char file_path[MAX_PATH] = {0}; + snprintf (file_path, (sizeof file_path) - 1, "%s\\trade_net_addresses.txt", is->mod_rel_dir); + char * refs_file = file_to_string (file_path); + if (! refs_file) { + snprintf (err_msg, (sizeof err_msg) - 1, "Couldn't load %s", file_path); + goto done; + } + + char * cursor = refs_file; + int loaded_count = 0; + while (true) { + if (*cursor == '#') { // comment line + skip_line (&cursor); + continue; + } + + skip_horiz_space (&cursor); + if (*cursor == '\n') { // empty line + cursor++; + continue; + } else if (*cursor == '\0') // end of file + break; + + // otherwise we must be on a line with some addresses + int ref; + bool got_any_addresses = false; + while (parse_int (&cursor, &ref)) { + if (loaded_count >= TRADE_NET_ADDR_TOTAL_COUNT) { + snprintf (err_msg, (sizeof err_msg) - 1, "Too many values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); + goto done; + } + is->trade_net_addrs[loaded_count] = ref; + loaded_count++; + got_any_addresses = true; + } + + if (! got_any_addresses) { + snprintf (err_msg, (sizeof err_msg) - 1, "Parse error"); + goto done; + } + } + + if (loaded_count < TRADE_NET_ADDR_TOTAL_COUNT) { + snprintf (err_msg, (sizeof err_msg) - 1, "Too few values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); + goto done; + } + + success = true; + +done: + free (refs_file); + if (! success) { + char full_err_msg[300] = {0}; + snprintf (full_err_msg, (sizeof full_err_msg) - 1, "Failed to load trade net refs: %s", err_msg); + MessageBox (NULL, full_err_msg, NULL, MB_ICONERROR); + is->trade_net_addrs_load_state = IS_INIT_FAILED; + return NULL; + } else { + is->trade_net_addrs_load_state = IS_OK; + return is->trade_net_addrs; + } +} + +unsigned short * __fastcall +patch_get_pixel_to_draw_city_dot (JGL_Image * this, int edx, int x, int y) +{ + unsigned short * tr = this->vtable->m07_m05_Get_Pixel (this, __, x, y); + + if ((x + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Width2) && (y + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Height2)) { + unsigned short * below = this->vtable->m07_m05_Get_Pixel (this, __, x + 1, y + 1); + if (below != NULL) + *below = 0; + } + + return tr; +} + +enum branch_kind { BK_CALL, BK_JUMP }; + +byte * +emit_branch (enum branch_kind kind, byte * cursor, void const * target) +{ + int offset = (int)target - ((int)cursor + 5); + *cursor++ = (kind == BK_CALL) ? 0xE8 : 0xE9; + return int_to_bytes (cursor, offset); +} + +// Just calls VirtualProtect and displays an error message if it fails. Made for use by the WITH_MEM_PROTECTION macro. +bool +check_virtual_protect (LPVOID addr, SIZE_T size, DWORD flags, PDWORD old_protect) +{ + if (VirtualProtect (addr, size, flags, old_protect)) + return true; + else { + char err_msg[1000]; + snprintf (err_msg, sizeof err_msg, "VirtualProtect failed! Args:\n Address: 0x%p\n Size: %d\n Flags: 0x%x", addr, size, flags); + err_msg[(sizeof err_msg) - 1] = '\0'; + MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); + return false; + } +} + +#define WITH_MEM_PROTECTION(addr, size, flags) \ + for (DWORD old_protect, unused, iter_count = 0; \ + (iter_count == 0) && check_virtual_protect (addr, size, flags, &old_protect); \ + VirtualProtect (addr, size, old_protect, &unused), iter_count++) + +void __fastcall adjust_sliders_preproduction (Leader * this); + +struct saved_code_area { + int size; + byte original_contents[]; +}; + +// Saves an area of base game code and optionally replaces it with no-ops. The area can be restored with restore_code_area. This method assumes that +// the necessary memory protection has already been set on the area, specifically that it can be written to. The method will do nothing if the area +// has already been saved with the same size. It's an error to re-save an address with a different size or overlap two saved areas. +void +save_code_area (byte * addr, int size, bool nopify) +{ + struct saved_code_area * sca; + if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { + if (sca->size != 0) { + if (sca->size != size) { + char s[200]; + snprintf (s, sizeof s, "Save code area conflict: address %p was already saved with size %d, conflicting with new size %d.", addr, sca->size, size); + s[(sizeof s) - 1] = '\0'; + pop_up_in_game_error (s); + } + return; + } + } else { + sca = malloc (size + sizeof *sca); + itable_insert (&is->saved_code_areas, (int)addr, (int)sca); + } + sca->size = size; + memcpy (&sca->original_contents, addr, size); + if (nopify) + memset (addr, 0x90, size); +} + +// Restores a saved chunk of code to its original contents. Does nothing if the area hasn't been saved. Assumes the appropriate memory protection has +// already been set. +void +restore_code_area (byte * addr) +{ + struct saved_code_area * sca; + if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { + memcpy (addr, &sca->original_contents, sca->size); + sca->size = 0; + } +} + +bool +is_code_area_saved (byte * addr) +{ + struct saved_code_area * sca; + return itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca) && (sca->size > 0); +} + +// Nopifies or restores an area depending on if yes_or_no is 1 or 0. Sets the necessary memory protections. +void +set_nopification (int yes_or_no, byte * addr, int size) +{ + WITH_MEM_PROTECTION (addr, size, PAGE_EXECUTE_READWRITE) { + if (yes_or_no) + save_code_area (addr, size, true); + else + restore_code_area (addr); + } +} + +void +apply_machine_code_edits (struct c3x_config const * cfg, bool at_program_start) +{ + DWORD old_protect, unused; + + // Allow stealth attack against single unit + WITH_MEM_PROTECTION (ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK = cfg->allow_stealth_attack_against_single_unit ? 0 : 1; + + // Enable small wonders providing free buildings + WITH_MEM_PROTECTION (ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER, 10, PAGE_EXECUTE_READWRITE) { + byte normal[8] = {0x83, 0xE1, 0x04, 0x80, 0xF9, 0x04, 0x0F, 0x85}; // and ecx, 4; cmp ecx, 4; jnz [offset] + byte modded[8] = {0x83, 0xE1, 0x0C, 0x80, 0xF9, 0x00, 0x0F, 0x84}; // and ecx, 12; cmp ecx, 0; jz [offset] + for (int n = 0; n < 8; n++) + ((byte *)ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER)[n] = cfg->enable_free_buildings_from_small_wonders ? modded[n] : normal[n]; + } + + // Bypass artillery in city check + // replacing 0x74 (= jump if [city ptr is] zero) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_CHECK_ARTILLERY_IN_CITY, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_CHECK_ARTILLERY_IN_CITY = cfg->use_offensive_artillery_ai ? 0xEB : 0x74; + + // Remove unit limit + if (! at_program_start) { + // Replace 0x7C (= jump if less than [unit limit]) with 0xEB (= uncond. jump) in Leader::spawn_unit + WITH_MEM_PROTECTION (ADDR_UNIT_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_UNIT_COUNT_CHECK = cfg->remove_unit_limit ? 0xEB : 0x7C; + + // Increase max ID to search for tradable units by 10x if limit removed + WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_UNIT_ID, 4, PAGE_EXECUTE_READWRITE) + int_to_bytes (ADDR_MAX_TRADABLE_UNIT_ID, cfg->remove_unit_limit ? 81920 : 8192); + + // Reallocate diplo_form->tradable_units array so it's 10x long if limit removed + civ_prog_free (p_diplo_form->tradable_units); + int tradable_units_len = cfg->remove_unit_limit ? 81920 : 8192, + tradable_units_size = tradable_units_len * sizeof (TradableItem); + p_diplo_form->tradable_units = new (tradable_units_size); + for (int n = 0; n < tradable_units_len; n++) + p_diplo_form->tradable_units[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 + + // Patch the size limit on some code that clears the tradable units array when starting a new game + WITH_MEM_PROTECTION (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) + int_to_bytes (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, tradable_units_size); + } + + // Remove the standard rule that blocks battle-created units while the player already has one + set_nopification (cfg->allow_multiple_battle_created_units_per_player, ADDR_EXISTING_BATTLE_CREATED_UNIT_CHECK, 6); + + // Bypass air unit check when drawing pedia stats. If it passes, the check will draw the op. range instead of movement in the first column. + // replacing 0x75 (= jnz) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS, 1, PAGE_EXECUTE_READWRITE) + *ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS = is->current_config.expand_civilopedia_unit_stats ? 0xEB : 0x75; + + // Remove era limit + // replacing 0x74 (= jump if zero [after cmp'ing era count with 4]) with 0xEB + WITH_MEM_PROTECTION (ADDR_ERA_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_ERA_COUNT_CHECK = cfg->remove_era_limit ? 0xEB : 0x74; + + // Fix science age bug + // Similar in nature to the sub bug, the function that measures a city's research output accepts a flag that determines whether or not it + // takes science ages into account. It's mistakenly not set by the code that gathers all research points to increment tech progress (but it + // is set elsewhere in code for the interface). The patch simply sets this flag. + WITH_MEM_PROTECTION (ADDR_SCIENCE_AGE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_SCIENCE_AGE_BUG_PATCH = cfg->patch_science_age_bug ? 1 : 0; + + // Pedia pink line bug fix + // The size of the pedia background texture is hard-coded into the EXE and in the base game it's one pixel too small. This shows up in game as + // a one pixel wide pink line along the right edge of the civilopedia. This patch simply increases the texture width by one. + WITH_MEM_PROTECTION (ADDR_PEDIA_TEXTURE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_PEDIA_TEXTURE_BUG_PATCH = cfg->patch_pedia_texture_bug ? 0xA6 : 0xA5; + + // Fix for houseboat bug + // See my posts on CFC for an explanation of the bug and its fix: + // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16084386 + // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16085242 + WITH_MEM_PROTECTION (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, PAGE_EXECUTE_READWRITE) { + if (cfg->patch_houseboat_bug) { + save_code_area (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, true); + byte * cursor = ADDR_HOUSEBOAT_BUG_PATCH; + *cursor++ = 0x50; // push eax + int call_offset = (int)&tile_at_city_or_null - ((int)cursor + 5); + *cursor++ = 0xE8; // call + cursor = int_to_bytes (cursor, call_offset); + } else + restore_code_area (ADDR_HOUSEBOAT_BUG_PATCH); + } + + // NoRaze + WITH_MEM_PROTECTION (ADDR_AUTORAZE_BYPASS, 2, PAGE_EXECUTE_READWRITE) { + byte normal[2] = {0x0F, 0x85}; // jnz + byte bypass[2] = {0x90, 0xE9}; // nop, jmp + for (int n = 0; n < 2; n++) + ((byte *)ADDR_AUTORAZE_BYPASS)[n] = cfg->prevent_autorazing ? bypass[n] : normal[n]; + } + + // Overwrite the instruction(s) where the AI's production choosing code compares the value of what it's currently considering to the best + // option so far. This is done twice since improvements and units are handled in separate loops. The instr(s) are overwritten with a jump to + // an "airlock", which is a bit of code that wraps the call to intercept_consideration. The contents of the airlocks are prepared by the + // patcher in init_consideration_airlocks. + // TODO: This instruction replacement could be done in the patcher too and that might be a better place for it. Think about this. + for (int n = 0; n < 2; n++) { + void * addr_intercept = (n == 0) ? ADDR_INTERCEPT_AI_IMPROV_VALUE : ADDR_INTERCEPT_AI_UNIT_VALUE; + void * addr_airlock = (n == 0) ? ADDR_IMPROV_CONSIDERATION_AIRLOCK : ADDR_UNIT_CONSIDERATION_AIRLOCK; + + WITH_MEM_PROTECTION (addr_intercept, AI_CONSIDERATION_INTERCEPT_LEN, PAGE_EXECUTE_READWRITE) { + byte * cursor = addr_intercept; + + // write jump to airlock + *cursor++ = 0xE9; + int offset = (int)addr_airlock - ((int)addr_intercept + 5); + cursor = int_to_bytes (cursor, offset); + + // fill the rest of the space with NOPs + while (cursor < (byte *)addr_intercept + AI_CONSIDERATION_INTERCEPT_LEN) + *cursor++ = 0x90; // nop + } + } + + // Overwrite instruction that sets bits in City.Body.Available_Resources with a jump to the airlock + WITH_MEM_PROTECTION (ADDR_INTERCEPT_SET_RESOURCE_BIT, 6, PAGE_EXECUTE_READWRITE) { + byte * cursor = ADDR_INTERCEPT_SET_RESOURCE_BIT; + if (cfg->patch_phantom_resource_bug) { + *cursor++ = 0xE9; + int offset = (int)ADDR_SET_RESOURCE_BIT_AIRLOCK - ((int)ADDR_INTERCEPT_SET_RESOURCE_BIT + 5); + cursor = int_to_bytes (cursor, offset); + *cursor++ = 0x90; // nop + } else { + byte original[6] = {0x09, 0xB0, 0x9C, 0x00, 0x00, 0x00}; // or dword ptr [eax+0x9C], esi + for (int n = 0; n < 6; n++) + cursor[n] = original[n]; + } + } + + // Enlarge the mask that's applied to p_bic_data->Map.TileCount in the loop over lines in Trade_Net::recompute_resources. This lets us loop + // over more than 0xFFFF tiles. + WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_MASK, 1, PAGE_EXECUTE_READWRITE) { + *(byte *)ADDR_RESOURCE_TILE_COUNT_MASK = (cfg->count_mills > 0) ? 0xFF : 0x00; + } + // Similarly, enlarge the cmp instruction that jumps over the entire loop when the tile count is zero. Do this by simply removing the operand + // override prefix byte (0x66), overwriting it with a nop (0x90). This converts the instruction "cmp word ptr [bic_data.Map.TileCount], di" + // into "nop; cmp dword ptr [bic_data.Map.TileCount], edi" + WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE, 1, PAGE_EXECUTE_READWRITE) { + *(byte *)ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE = 0x90; + } + + byte * addr_turn_metalimits[] = {ADDR_TURN_METALIMIT_1, ADDR_TURN_METALIMIT_2, ADDR_TURN_METALIMIT_3, ADDR_TURN_METALIMIT_4, + ADDR_TURN_METALIMIT_5, ADDR_TURN_METALIMIT_6, ADDR_TURN_METALIMIT_7}; + for (int n = 0; n < ARRAY_LEN (addr_turn_metalimits); n++) { + byte * addr = addr_turn_metalimits[n]; + WITH_MEM_PROTECTION (addr, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (addr, cfg->remove_cap_on_turn_limit ? 1000000 : 1000); + } + } + + // Overwrite the human-ness test and call to Leader::ai_adjust_sliders that happens during the preproduction player update method. The new + // code calls adjust_sliders_preproduction for all players. + WITH_MEM_PROTECTION (ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT, 9, PAGE_EXECUTE_READWRITE) { + byte * cursor = ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT; + *cursor++ = 0x8B; *cursor++ = 0xCE; // mov ecx, esi + cursor = emit_branch (BK_CALL, cursor, adjust_sliders_preproduction); + for (; cursor < ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT + 9; cursor++) + *cursor = 0x90; // nop + } + + // Set up a special intercept of the base game's calls to print_int in order to grab a pointer to a gold TradeOffer object being modified. The + // calls to print_int happen in the context of creating the default text to be placed in the set-gold-amount popup. Conveniently, a pointer to + // the TradeOffer object is always stored in register ecx when this call happens. It's not easily accessible since print_int uses the cdecl + // convention so we must use an airlock-like thing to effectively convert the calling convention to fastcall. The first part of this code + // simply replaces the call to print_int with a call to the airlock-like thing, and the second part initializes its contents. + byte * addr_print_gold_amounts[] = {ADDR_PRINT_GOLD_AMOUNT_1, ADDR_PRINT_GOLD_AMOUNT_2}; + for (int n = 0; n < ARRAY_LEN (addr_print_gold_amounts); n++) { + byte * addr = addr_print_gold_amounts[n]; + WITH_MEM_PROTECTION (addr, 5, PAGE_EXECUTE_READWRITE) + emit_branch (BK_CALL, addr, ADDR_CAPTURE_MODIFIED_GOLD_TRADE); + } + WITH_MEM_PROTECTION (ADDR_CAPTURE_MODIFIED_GOLD_TRADE, 32, PAGE_EXECUTE_READWRITE) { + byte * cursor = ADDR_CAPTURE_MODIFIED_GOLD_TRADE; + + // Repush all of the arguments to print_int onto the stack, they will be consumed by do_capture_modified_gold_trade since it's + // fastcall. The original args don't need to be removed b/c we're replacing a cdecl function so that's the caller's + // responsibility. The TradeOffer pointer is already in ECX, so that's fine as long as we don't touch that register. + byte repush[] = {0xFF, 0x74, 0x24, 0x0C}; // push [esp+0xC] + for (int n = 0; n < 3; n++) + for (int k = 0; k < ARRAY_LEN (repush); k++) + *cursor++ = repush[k]; + + cursor = emit_branch (BK_CALL, cursor, do_capture_modified_gold_trade); // call do_capture_modified_gold_trade + *cursor++ = 0xC3; // ret + } + + // Edit branch in capture_city to never run code for barbs, this allows barbs to capture cities + WITH_MEM_PROTECTION (ADDR_CAPTURE_CITY_BARB_BRANCH, 2, PAGE_EXECUTE_READWRITE) { + byte normal[2] = {0x0F, 0x85}; // jnz + byte bypass[2] = {0x90, 0xE9}; // nop, jmp + for (int n = 0; n < 2; n++) + ((byte *)ADDR_CAPTURE_CITY_BARB_BRANCH)[n] = cfg->enable_city_capture_by_barbarians ? bypass[n] : normal[n]; + } + + // After the production phase is done for the barb player, there are two jump instructions skipping the production code for civs. Replacing + // those jumps lets us run the civ production code for the barbs as well. + WITH_MEM_PROTECTION (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, PAGE_EXECUTE_READWRITE) { + if (cfg->enable_city_capture_by_barbarians) { + save_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, true); + byte jump_to_civ[6] = {0x0F, 0x8D, 0x0C, 0x00, 0x00, 0x00}; // jge +0x12 + for (int n = 0; n < 6; n++) + ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP[n] = jump_to_civ[n]; + } else + restore_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP); + } + set_nopification (cfg->enable_city_capture_by_barbarians, ADDR_PROD_PHASE_BARB_DONE_JUMP, 5); + + for (int domain = 0; domain < 2; domain++) { + byte * addr_skip = (domain == 0) ? ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC : ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC, + * addr_airlock = (domain == 0) ? ADDR_SEA_ZOC_FILTER_AIRLOCK : ADDR_LAND_ZOC_FILTER_AIRLOCK; + + WITH_MEM_PROTECTION (addr_skip, 6, PAGE_EXECUTE_READWRITE) { + if ((cfg->special_zone_of_control_rules != 0) && ! is_code_area_saved (addr_skip)) { + byte * original_target = addr_skip + 6 + int_from_bytes (addr_skip + 2); // target addr of jump instr we're replacing + save_code_area (addr_skip, 6, true); + + // Initialize airlock. The airlock preserves all registers and calls filter_zoc_candidate then either follows or skips the + // original jump depending on what it returns. If zero is returned, follows the jump, skipping a bunch of code and filtering + // out the unit as a candidate for ZoC. + WITH_MEM_PROTECTION (addr_airlock, INLEAD_SIZE, PAGE_READWRITE) { + byte * cursor = addr_airlock; + *cursor++ = 0x60; // pusha + *cursor++ = 0x54; // push esp + cursor = emit_branch (BK_CALL, cursor, filter_zoc_candidate); + *cursor++ = 0x83; *cursor++ = 0xF8; *cursor++ = 0x01; // cmp eax, 1 + *cursor++ = 0x75; *cursor++ = 0x06; // jne 6 + *cursor++ = 0x61; // popa + cursor = emit_branch (BK_JUMP, cursor, addr_skip + 6); + *cursor++ = 0x61; // popa + cursor = emit_branch (BK_JUMP, cursor, original_target); + } + + // Write jump to airlock + emit_branch (BK_JUMP, addr_skip, addr_airlock); + } else if (cfg->special_zone_of_control_rules == 0) + restore_code_area (addr_skip); + } + } + + set_nopification ( cfg->special_zone_of_control_rules != 0, ADDR_ZOC_CHECK_ATTACKER_ANIM_FIELD_111, 6); + set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_LAND_UNIT , 6); + set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_SEA_UNIT , 6); + + WITH_MEM_PROTECTION (ADDR_LUXURY_BOX_ROW_HEIGHT, 4, PAGE_EXECUTE_READWRITE) { + byte normal [4] = {0x8B, 0x44, 0x24, LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET}; // mov eax, dword ptr [esp + LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET] + byte compact[4] = {0x31, 0xC0, 0xB0, 0x10}; // xor eax, eax; mov al, 0x10 + for (int n = 0; n < 4; n++) + ADDR_LUXURY_BOX_ROW_HEIGHT[n] = cfg->compact_luxury_display_on_city_screen ? compact[n] : normal[n]; + } + + WITH_MEM_PROTECTION (ADDR_MOST_STRAT_RES_ON_CITY_SCREEN, 1, PAGE_EXECUTE_READWRITE) { + *(byte *)ADDR_MOST_STRAT_RES_ON_CITY_SCREEN = cfg->compact_strategic_resource_display_on_city_screen ? 13 : 8; + } + + // Remove a check that a returned neighbor index is within the 21 tile work area in code related to hoving the mouse over the work area on the + // city screen. This check is redundant and could be removed always, but only do so if work area is expanded. + set_nopification (cfg->city_work_radius > 2, ADDR_REDUNDANT_CHECK_ON_WORK_AREA_HOVER, 6); + + // Skip redundant check of clicked tile's neighbor index in City_Form::handle_left_click. + WITH_MEM_PROTECTION (ADDR_CITY_FORM_LEFT_CLICK_JUMP, 1, PAGE_EXECUTE_READWRITE) { + *ADDR_CITY_FORM_LEFT_CLICK_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) + } + + // Skip check that neighbor index passed to City::controls_tile is within work radius. This check is now implemented in the patch func. + WITH_MEM_PROTECTION (ADDR_CONTROLS_TILE_JUMP, 1, PAGE_EXECUTE_READWRITE) { + *ADDR_CONTROLS_TILE_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) + } + + // When searching for a tile on which to spawn pollution, the game wraps its search around by using remainder after division. Here, we replace + // the dividend to match a potentially expanded city work area. + WITH_MEM_PROTECTION (ADDR_SPAWN_POLLUTION_MOD, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_SPAWN_POLLUTION_MOD, is->workable_tile_count - 1); + } + + WITH_MEM_PROTECTION (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, cfg->patch_premature_truncation_of_found_paths ? 2560 : 256); + } + + int * trade_net_addrs; + bool already_moved_trade_net = is->trade_net != p_original_trade_net, + want_moved_trade_net = cfg->city_limit > 512; + int lifted_city_limit_exp = 11; + int lifted_city_limit = 1 << lifted_city_limit_exp; + if ((! at_program_start) && + ((trade_net_addrs = load_trade_net_addrs ()) != NULL) && + ((already_moved_trade_net && ! want_moved_trade_net) || (want_moved_trade_net && ! already_moved_trade_net))) { + // Allocate a new trade net object if necessary. To construct it, all we have to do is zero a few fields and set the vptr. Otherwise, + // set the allocated object aside for deletion later. Also set new & old addresses to the locations we're moving to & from. + Trade_Net * to_free = NULL; + int p_old, p_new; + if (want_moved_trade_net) { + is->trade_net = calloc (1, (sizeof (Trade_Net)) - (4 * 512 * 512) + (4 * lifted_city_limit * lifted_city_limit)); + is->city_limit = lifted_city_limit; + is->trade_net->vtable = p_original_trade_net->vtable; + p_old = (int)p_original_trade_net; + p_new = (int)is->trade_net; + } else { + to_free = is->trade_net; + is->city_limit = 512; + p_old = (int)is->trade_net; + p_new = (int)p_original_trade_net; + is->trade_net = p_original_trade_net; + } + already_moved_trade_net = is->trade_net != p_original_trade_net; // Keep this variable up to date + + // Patch all references from the "old" object to the "new" one + int offset; + bool popped_up_error = false; + char err_msg[200] = {0}; + int * refs; { + if (exe_version_index == 0) + refs = trade_net_addrs; + else if (exe_version_index == 1) // Steam version, skip refs and instructions for GOG + refs = &trade_net_addrs[TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; + else // PCGames.de version, skip two sets of refs and instrs for GOG & Steam + refs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; + } + for (int n_ref = 0; n_ref < TRADE_NET_REF_COUNT; n_ref++) { + int addr = refs[n_ref]; + WITH_MEM_PROTECTION ((void *)(addr - 10), 20, PAGE_EXECUTE_READWRITE) { + byte * instr = (byte *)addr; + if ((instr[0] == 0xB9) && (int_from_bytes (&instr[1]) == p_old)) // move trade net ptr to ecx + int_to_bytes (&instr[1], p_new); + else if ((instr[0] == 0xC7) && (instr[1] == 0x05) && (int_from_bytes (&instr[2]) == p_old)) // write trade net vtable ptr + int_to_bytes (&instr[2], p_new); + else if ((instr[0] == 0x81) && (instr[1] == 0xFE) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp esi, trade net location + ; // Do not patch this location because it's the upper limit for a memcpy + else if ((instr[0] == 0x81) && (instr[1] == 0xFF) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp edi, trade net location + ; // Same + else if ((instr[0] == 0x81) && (instr[1] == 0xFA) && (int_from_bytes (&instr[2]) == (int)&p_original_trade_net->Data2)) // cmp edx, trade net data2 location + ; // Same + else if (((instr[0] == 0xA3) || (instr[0] == 0xA1)) && // move eax to field or vice-versa + (offset = int_from_bytes (&instr[1]) - p_old, (offset >= 0) && (offset < 100))) + int_to_bytes (&instr[1], p_new + offset); + else if ((instr[0] == 0x89) && ((instr[1] >= 0x0D) && (instr[1] <= 0x3D)) && // move other regs to field + (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) + int_to_bytes (&instr[2], p_new + offset); + else if ((instr[0] == 0x8B) && ((instr[1] == 0x35) || (instr[1] == 0x3D) || (instr[1] == 0x0D)) && // mov field to esi, edi or ecx + (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) + int_to_bytes (&instr[2], p_new + offset); + else if (! popped_up_error) { + snprintf (err_msg, (sizeof err_msg) - 1, "Can't move trade net object from address 0x%x. Pattern doesn't match.", addr); + MessageBox (NULL, err_msg, NULL, MB_ICONERROR); + popped_up_error = true; + } + } + } + + // Patch all instructions that involve the stride of Trade_Net.Matrix + int * addrs, addr_count; { + if (exe_version_index == 0) { + addrs = &trade_net_addrs[TRADE_NET_REF_COUNT]; + addr_count = TRADE_NET_INSTR_COUNT_GOG; + } else if (exe_version_index == 1) { + addrs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; + addr_count = TRADE_NET_INSTR_COUNT_STEAM; + } else { + addrs = &trade_net_addrs[3 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; + addr_count = TRADE_NET_INSTR_COUNT_GOG; + } + for (int n = 0; n < addr_count; n++) { + byte * instr = (byte *)addrs[n]; + WITH_MEM_PROTECTION (instr, 10, PAGE_EXECUTE_READWRITE) { + if (! want_moved_trade_net) + restore_code_area (instr); + + else { + if ((instr[0] == 0xC1) && (instr[1] >= 0xE0) && (instr[1] <= 0xE7)) { // shl + save_code_area (instr, 3, false); + // shift amount is either 9 (1<<9 == 512) or 11 (1<<11 == 4*512, stride in bytes) + // in the second case, replace with lifted_exp + 2 to convert to bytes + instr[2] = lifted_city_limit_exp + ((instr[2] == 11) ? 2 : 0); + + } else if ((instr[0] == 0x81) && (instr[1] >= 0xC0) && (instr[1] <= 0xC7)) { // add + save_code_area (instr, 6, false); + int amount = int_from_bytes (&instr[2]); + // amount is either 512 or 4*512, replace with lifted_lim or 4*lifted_lim + int_to_bytes (&instr[2], (amount == 512) ? lifted_city_limit : 4*lifted_city_limit); + + } else if ((instr[0] == 0x8D) && (instr[1] == 0x9C) && (instr[2] == 0x90)) { // lea + save_code_area (instr, 7, false); + int offset = 4 * lifted_city_limit + 0x38; // stride in bytes plus 0x38 offset to Matrix in Trade_Net object + int_to_bytes (&instr[3], offset); + + } else if (instr[0] == 0xB9) { // mov + save_code_area (instr, 5, false); + int_to_bytes (&instr[1], lifted_city_limit * lifted_city_limit); + + } else if (! popped_up_error) { + snprintf (err_msg, (sizeof err_msg) - 1, "Can't patch matrix stride at address 0x%x. Pattern doesn't match.", (int)instr); + MessageBox (NULL, err_msg, NULL, MB_ICONERROR); + popped_up_error = true; + } + } + } + } + } + + // Reallocate diplo_form->tradable_cities array so it matches the city limit + civ_prog_free (p_diplo_form->tradable_cities); + int tradable_cities_len = want_moved_trade_net ? lifted_city_limit : 512, + tradable_cities_size = tradable_cities_len * sizeof (TradableItem); + p_diplo_form->tradable_cities = new (tradable_cities_size); + for (int n = 0; n < tradable_cities_len; n++) + p_diplo_form->tradable_cities[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 + + // Patch the size limit on some code that clears the tradable cities array when starting a new game + WITH_MEM_PROTECTION (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, tradable_cities_size); + } + + if (to_free) { + to_free->vtable->destruct (to_free, __, 0); + free (to_free); + } + } + + // Set is->city_limit and patch two instructions that contain the limit + is->city_limit = clamp (0, already_moved_trade_net ? lifted_city_limit : 512, cfg->city_limit); + WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN, 6, PAGE_EXECUTE_READWRITE) { + int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN[2], is->city_limit); + } + WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CREATE_CITY, 5, PAGE_EXECUTE_READWRITE) { + int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CREATE_CITY[1], is->city_limit); + } + WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_CITY_ID, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_MAX_TRADABLE_CITY_ID, already_moved_trade_net ? lifted_city_limit : 512); + } + + WITH_MEM_PROTECTION (ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR, 6, PAGE_EXECUTE_READWRITE) { + byte * instr = ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR; + if (cfg->years_to_double_building_culture == 1000) + restore_code_area (instr); + else { + if (instr[0] == 0x3D) { // in GOG and PCG EXEs, instr is cmp eax, 0x3E8 + save_code_area (instr, 5, false); + int_to_bytes (&instr[1], cfg->years_to_double_building_culture); + } else if (instr[0] == 0x3B) { // in Steam EXE, instr is cmp eax, dword ptr 0x688C9C + save_code_area (instr, 6, true); + instr[0] = 0x3D; + int_to_bytes (&instr[1], cfg->years_to_double_building_culture); + } + } + } + + WITH_MEM_PROTECTION (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, PAGE_EXECUTE_READWRITE) { + if (cfg->accentuate_cities_on_minimap) { + save_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, false); + emit_branch (BK_JUMP, ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL); + } else + restore_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT); + } + WITH_MEM_PROTECTION (ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { + byte * code = ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL; + code[0] = 0x55; code[1] = 0x53; // write push ebp and push ebx, two overwritten instrs before the call + emit_branch (BK_CALL, &code[2], &patch_get_pixel_to_draw_city_dot); // call patch func + emit_branch (BK_JUMP, &code[7], ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT + 5); // jump back to original code + } + + // Bypass adjacent resource of different type check + // replacing 0x7D (= jge) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9 = cfg->allow_adjacent_resources_of_different_types ? 0xEB : 0x7D; + + WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, PAGE_EXECUTE_READWRITE) { + if (cfg->tiles_per_non_luxury_resource == 32) + restore_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV); + else { + save_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, true); + + // Jump to replacement division logic, kept in an inlead because it doesn't fit in 7 bytes + emit_branch (BK_JUMP, ADDR_RESOURCE_GEN_TILE_COUNT_DIV, ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL); + + // Fill in the replacement division logic. Instead of computing tile_count>>5, compute tile_count/cfg->tiles_per_non_luxury_resource. + WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { + int d = not_below (1, cfg->tiles_per_non_luxury_resource); + byte d0 = d & 0xFF, + d1 = (d >> 8) & 0xFF, + d2 = (d >> 16) & 0xFF, + d3 = d >> 24; + + byte * cursor = ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL; + + // In the Steam EXE, the limit (tile_count/32 by default) must be left in ecx. For the other EXEs, edx. + if (exe_version_index == 1) { + byte new_div[] = { + 0x50, // push eax + 0x52, // push edx + 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count + 0x0F, 0xB7, 0xD2, // movzx edx, dx + 0x89, 0xD0, // mov eax, edx + 0x31, 0xD2, // xor edx, edx + 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} + 0xF7, 0xF1, // div ecx + 0x89, 0xC1, // mov ecx, eax + 0x5A, // pop edx + 0x58 // pop eax + }; + for (int n = 0; n < ARRAY_LEN (new_div); n++) + *cursor++ = new_div[n]; + + } else { + byte new_div[] = { + 0x50, // push eax + 0x51, // push ecx + 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count + 0x0F, 0xB7, 0xD2, // movzx edx, dx + 0x89, 0xD0, // mov eax, edx + 0x31, 0xD2, // xor edx, edx + 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} + 0xF7, 0xF1, // div ecx + 0x89, 0xC2, // mov edx, eax + 0x59, // pop ecx + 0x58 // pop eax + }; + for (int n = 0; n < ARRAY_LEN (new_div); n++) + *cursor++ = new_div[n]; + } + + cursor = emit_branch (BK_JUMP, cursor, ADDR_RESOURCE_GEN_TILE_COUNT_DIV + 7); + } + } + } + + // Disable a jump that skips playing victory animations for air units if they've been configured to have a victory anim + set_nopification (cfg->aircraft_victory_animation != NULL, ADDR_SKIP_VICTORY_ANIM_IF_AIR, 6); + + // Bypass capital check to return zero corruption + // replacing 0x75 (= jnz) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_CORRUPTION_CAPITAL_CHECK, 1, PAGE_EXECUTE_READWRITE) + *ADDR_CORRUPTION_CAPITAL_CHECK = cfg->allow_corruption_in_capital ? 0xEB : 0x75; + + // Insert amount added to building decorruption effect just for the capital + WITH_MEM_PROTECTION (ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT, 3, PAGE_EXECUTE_READWRITE) + *(ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT + 2) = clamp (0, 100, cfg->special_capital_decorruption_effect); +} + +void +get_mod_art_path (char const * file_name, char * out_path, int path_buf_size) +{ + char s[1000]; + snprintf (s, sizeof s, "Art\\%s", file_name); + s[(sizeof s) - 1] = '\0'; + + char * scenario_path = BIC_get_asset_path (p_bic_data, __, s, false); + if (0 != strcmp (scenario_path, s)) // get_asset_path returns its input when the file is not found + snprintf (out_path, path_buf_size, "%s", scenario_path); + else + snprintf (out_path, path_buf_size, "%s\\Art\\%s", is->mod_rel_dir, file_name); + out_path[path_buf_size - 1] = '\0'; +} + + +Sprite* +SpriteList_at(SpriteList *list, int i) { + return &list->field_0[i]; +} + +void +set_path(String260 *dst, const char *p) { + snprintf(dst->S, sizeof(dst->S), "%s", p); +} + +void +slice_grid(Sprite *out, PCX_Image *img, + int tile_w, int tile_h, int full_w, int full_h) +{ + for (int y = 0; y < full_h; y += tile_h) + for (int x = 0; x < full_w; x += tile_w) + Sprite_slice_pcx(out++, __, img, x, y, tile_w, tile_h, 1, 1); +} + +void +slice_grid_into_list(SpriteList *bucket, PCX_Image *img, + int tile_w, int tile_h, int full_w, int full_h) +{ + int k = 0; + for (int y = 0; y < full_h; y += tile_h) + for (int x = 0; x < full_w; x += tile_w) + Sprite_slice_pcx(SpriteList_at(bucket, k++), __, img, x, y, tile_w, tile_h, 1, 1); +} + +void +join_path(char *out, size_t out_sz, const char *dir, const char *file) +{ + size_t n = strlen(dir); + int need_sep = (n > 0 && dir[n-1] != '/' && dir[n-1] != '\\'); + snprintf(out, out_sz, "%s%s%s", dir, need_sep ? "\\" : "", file); +} + +void +read_in_dir(PCX_Image *img, + const char *art_dir, + const char *filename, + String260 *store) { + char pbuf[512]; + join_path(pbuf, sizeof pbuf, art_dir, filename); + if (store) { + // assumes: typedef struct { char S[260]; } String260; + snprintf(store->S, sizeof store->S, "%s", pbuf); + } + + char temp_path[2*MAX_PATH]; + + snprintf(temp_path, sizeof temp_path, "%s\\%s", art_dir, filename); + PCX_Image_read_file(img, __, temp_path, NULL, 0, 0x100, 2); +} + +bool load_day_night_hour_images(struct day_night_cycle_img_set *this, const char *art_dir, const char *hour) +{ + char ss[200]; + PCX_Image img; + PCX_Image_construct(&img); + + // Std terrain (9 sheets): 6x9 of 128x64 over 0x480x0x240 + const char *STD_SHEETS[9] = { + "xtgc.pcx", "xpgc.pcx", "xdgc.pcx", "xdpc.pcx", "xdgp.pcx", "xggc.pcx", + "wCSO.pcx", "wSSS.pcx", "wOOO.pcx" + }; + for (int i = 0; i < 9; ++i) { + read_in_dir(&img, art_dir, STD_SHEETS[i], NULL); + if (img.JGL.Image == NULL) return false; + slice_grid_into_list(&this->Std_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); + } + + // LM terrain (9): same slicing + const char *LMT_SHEETS[9] = { + "lxtgc.pcx", "lxpgc.pcx", "lxdgc.pcx", "lxdpc.pcx", "lxdgp.pcx", "lxggc.pcx", + "lwCSO.pcx", "lwSSS.pcx", "lwOOO.pcx" + }; + for (int i = 0; i < 9; ++i) { + read_in_dir(&img, art_dir, LMT_SHEETS[i], NULL); + if (img.JGL.Image == NULL) return false; + slice_grid_into_list(&this->LM_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); + } + + // Polar icecaps: 8x4 of 128x64 + read_in_dir(&img, art_dir, "polarICEcaps-final.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Polar_Icecaps_Images, &img, 0x80, 0x40, 0x400, 0x100); + + // Hills / LM Hills: 4x3 of 128x72 + read_in_dir(&img, art_dir, "xhills.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); + read_in_dir(&img, art_dir, "hill forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Hills_Forests_Images, &img, 0x80, 0x48, 0x200, 0x120); + read_in_dir(&img, art_dir, "hill jungle.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Hills_Jungle_Images, &img, 0x80, 0x48, 0x200, 0x120); + read_in_dir(&img, art_dir, "LMHills.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->LM_Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); + + // Flood plains: 4x4 of 128x64 + read_in_dir(&img, art_dir, "floodplains.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Flood_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); + + // Delta + Mountain rivers: 4x4 each, interleaved across one contiguous block + { + const char *RIV_SHEETS[2] = { "deltaRivers.pcx", "mtnRivers.pcx" }; + Sprite *contig = this->Delta_Rivers_Images; // Mountain_Rivers_Images follows + for (int s = 0; s < 2; ++s) { + read_in_dir(&img, art_dir, RIV_SHEETS[s], NULL); + if (img.JGL.Image == NULL) return false; + Sprite *p = contig + s; // even=delta, odd=mountain + for (int y = 0; y < 0x100; y += 0x40) + for (int x = 0; x < 0x200; x += 0x80) { + Sprite_slice_pcx(p, __, &img, x, y, 0x80, 0x40, 1, 1); + p += 2; + } + } + } + + // Waterfalls: 4x1 of 128x64 + read_in_dir(&img, art_dir, "waterfalls.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Waterfalls_Images, &img, 0x80, 0x40, 0x200, 0x40); + + // Irrigation (desert/plains/normal/tundra): each 4x4 of 128x64 + read_in_dir(&img, art_dir, "irrigation DESETT.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Desert_Images, &img, 0x80, 0x40, 0x200, 0x100); + read_in_dir(&img, art_dir, "irrigation PLAINS.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); + read_in_dir(&img, art_dir, "irrigation.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Images, &img, 0x80, 0x40, 0x200, 0x100); + read_in_dir(&img, art_dir, "irrigation TUNDRA.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Tundra_Images, &img, 0x80, 0x40, 0x200, 0x100); + + // Volcanos (plain/forests/jungles/snow): 4x4 of 128x88 + read_in_dir(&img, art_dir, "Volcanos.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Volcanos forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Volcanos jungles.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Volcanos-snow.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); + + // Marsh: Large band then Small band (tiles 128x88) + read_in_dir(&img, art_dir, "marsh.pcx", NULL); + if (img.JGL.Image == NULL) return false; + // Large (2 rows, 4 cols) + { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Marsh_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + // Small (2 rows, 5 cols) + { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Marsh_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + // LM mountains + standard mountains (plain/forests/jungles/snow): 4x4 of 128x88 + read_in_dir(&img, art_dir, "LMMountains.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->LM_Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Mountains.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "mountain forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "mountain jungles.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Mountains-snow.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); + + // Roads (16x16) and Railroads (16x17), tiles 128x64 + read_in_dir(&img, art_dir, "roads.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Roads_Images, &img, 0x80, 0x40, 0x800, 0x400); + read_in_dir(&img, art_dir, "railroads.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Railroads_Images, &img, 0x80, 0x40, 0x800, 0x440); + + // LM Forests (Large 2x4, Small 2x6, Pines 2x6), tiles 128x88 + read_in_dir(&img, art_dir, "LMForests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->LM_Forests_Large_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->LM_Forests_Small_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->LM_Forests_Pines_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + // Grassland/Plains/Tundra forests & jungles (bands; tiles 128x88) — order is important + read_in_dir(&img, art_dir, "grassland forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + // Jungles Large, Small + { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Jungles_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Jungles_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + // Forests Large, Small, Pines + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + read_in_dir(&img, art_dir, "plains forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Plains_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Plains_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Plains_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + read_in_dir(&img, art_dir, "tundra forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Tundra_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Tundra_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Tundra_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + // LM Terrain (7 single 128x64, vertical strip) + read_in_dir(&img, art_dir, "landmark_terrain.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i = 0, y = 0; i < 7; ++i, y += 0x40) + Sprite_slice_pcx(&this->LM_Terrain[i], __, &img, 0, y, 0x80, 0x40, 1, 1); + + // TNT (same odd ordering as original) + read_in_dir(&img, art_dir, "tnt.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[6+i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[9+i], __, &img, x, 0x40, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[12+i], __, &img, x, 0x80, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[0+i], __, &img, x, 0xC0, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[15+i], __, &img, x, 0x100, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[3+i], __, &img, x, 0x140, 0x80, 0x40, 1, 1); + + // Goody huts: 8 tiles, x=(i%3)*0x80, y=(i/3)*0x40 + read_in_dir(&img, art_dir, "goodyhuts.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i = 0; i < 8; ++i) { + int x = (i % 3) << 7; + int y = (i / 3) << 6; + Sprite_slice_pcx(&this->Goody_Huts_Images[i], __, &img, x, y, 0x80, 0x40, 1, 1); + } + + // Terrain buildings (fortress/camp/barbarian camp/mines/barricade) + read_in_dir(&img, art_dir, "TerrainBuildings.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Fortress[i], __, &img, 0x00, y, 0x80, 0x40, 1, 1); + for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Camp[i], __, &img, 0x80, y, 0x80, 0x40, 1, 1); + Sprite_slice_pcx(&this->Terrain_Buldings_Barbarian_Camp, __, &img, 0x100, 0x00, 0x80, 0x40, 1, 1); + Sprite_slice_pcx(&this->Terrain_Buldings_Mines, __, &img, 0x100, 0x40, 0x80, 0x40, 1, 1); + for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Barricade[i], __, &img, 0x180, y, 0x80, 0x40, 1, 1); + + // Pollution & Craters (5x5 of 128x64) + read_in_dir(&img, art_dir, "pollution.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Pollution, &img, 0x80, 0x40, 0x280, 0x140); + read_in_dir(&img, art_dir, "craters.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Craters, &img, 0x80, 0x40, 0x280, 0x140); + + // Airfields / Outposts / Radar + read_in_dir(&img, art_dir, "x_airfields and detect.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i=0, x=0; i<2; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Airfields[i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Outposts[i], __, &img, x, 0x40, 0x80, 0x80, 1, 1); + Sprite_slice_pcx(&this->Terrain_Buldings_Radar, __, &img, 0x00, 0xC0, 0x80, 0x80, 1, 1); + + // Victory (single 128x64) + read_in_dir(&img, art_dir, "x_victory.pcx", NULL); + if (img.JGL.Image == NULL) return false; + Sprite_slice_pcx(&this->Victory_Image, __, &img, 0, 0, 0x80, 0x40, 1, 1); + + // Resources + read_in_dir(&img, art_dir, "resources.pcx", NULL); + if (img.JGL.Image == NULL) return false; + size_t k = 0; + for (int r = 0, y = 1; r < 6; ++r, y += 50) { + for (int c = 0, x = 1; c < 6; ++c, x += 50) { + Sprite_slice_pcx(&this->Resources[k++], __, &img, x, y, 49, 49, 1, 1); + } + } + + // Base cities + static const char *CITY_BASE[5] = { + "rAMER.pcx", "rEURO.pcx", "rROMAN.pcx", "rMIDEAST.pcx", "rASIAN.pcx" + }; + for (int culture = 0; culture < 5; culture++) { + read_in_dir(&img, art_dir, CITY_BASE[culture], NULL); + if (img.JGL.Image == NULL) return false; + int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; + int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; + int y = 0; + for (int era = 0; era < 4; ++era, y += sprite_h) { + int x = 0; + for (int size = 0; size < 3; ++size, x += sprite_w) { + const int idx = culture + 5*era + 20*size; + Sprite_slice_pcx(&this->City_Images[idx], __, &img, x, y, sprite_w, sprite_h, 1, 1); + } + } + } + + // Walled cities + static const char *CITY_WALL[5] = { + "AMERWALL.pcx", "EUROWALL.pcx", "ROMANWALL.pcx", "MIDEASTWALL.pcx", "ASIANWALL.pcx" + }; + for (int culture = 0; culture < 5; ++culture) { + read_in_dir(&img, art_dir, CITY_WALL[culture], NULL); + if (img.JGL.Image == NULL) return false; + int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image); + int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; + int y = 0; + for (int era = 0; era < 4; ++era, y += sprite_h) { + const int size = 3; // walled towns are a special category + const int idx = culture + 5*era + 20*size; + Sprite_slice_pcx(&this->City_Images[idx], __, &img, 0, y, sprite_w, sprite_h, 1, 1); + } + } + + // Destroyed cities + read_in_dir(&img, art_dir, "DESTROY.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { + int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; + int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image); + int x = 0; + for (int i = 0; i < 3; ++i, x += sprite_w) + Sprite_slice_pcx(&this->Destroyed_City_Images[i], __, &img, x, 0, sprite_w, sprite_h, 1, 1); + } + + // Districts (if enabled) + if (is->current_config.enable_districts) { + char art_dir[200]; + char temp_path[2*MAX_PATH]; + snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + for (int dc = 0; dc < is->district_count; dc++) { + struct district_config const * cfg = &is->district_configs[dc]; + int variant_capacity = ARRAY_LEN (this->District_Images[dc]); + int variant_count = cfg->img_path_count; + if (variant_count <= 0) + continue; + if (variant_count > variant_capacity) + variant_count = variant_capacity; + + int era_count = cfg->vary_img_by_era ? 4 : 1; + int column_count = cfg->img_column_count; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + + for (int variant_i = 0; variant_i < variant_count; variant_i++) { + const char * img_path = cfg->img_paths[variant_i]; + if ((img_path == NULL) || (img_path[0] == '\0')) + continue; + + read_in_dir (&img, temp_path, img_path, NULL); + if (img.JGL.Image == NULL) + return false; + + for (int era = 0; era < era_count; era++) { + for (int col = 0; col < column_count; col++) { + int tile_x = sprite_width * col; + int tile_y = sprite_height * era; + Sprite_slice_pcx (&this->District_Images[dc][variant_i][era][col], __, &img, tile_x, tile_y, sprite_width, sprite_height, 1, 1); + } + } + } + } + + // Abandoned district art (land + maritime) for this hour + read_in_dir (&img, temp_path, "Abandoned.pcx", NULL); + if (img.JGL.Image == NULL) + return false; + Sprite_slice_pcx (&this->Abandoned_District_Image, __, &img, 0, 0, 128, 64, 1, 1); + Sprite_slice_pcx (&this->Abandoned_Maritime_District_Image, __, &img, 128, 0, 128, 64, 1, 1); + + // Load wonder district images (dynamically per wonder) for this hour + if (is->current_config.enable_wonder_districts) { + char const * last_img_path = NULL; + PCX_Image wpcx; + PCX_Image_construct (&wpcx); + bool pcx_loaded = false; + + for (int wi = 0; wi < is->wonder_district_count; wi++) { + struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; + char const * img_path = cfg->img_path; + if (img_path == NULL) + img_path = "Wonders.pcx"; + + // Load new image file if different from previous + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + + read_in_dir (&wpcx, temp_path, img_path, NULL); + + if (wpcx.JGL.Image == NULL) { + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + struct wonder_district_image_set * set = &this->Wonder_District_Images[wi]; + + Sprite_construct (&set->img); + int x = 128 * cfg->img_column; + int y = 64 * cfg->img_row; + Sprite_slice_pcx (&set->img, __, &wpcx, x, y, 128, 64, 1, 1); + + Sprite_construct (&set->construct_img); + int cx = 128 * cfg->img_construct_column; + int cy = 64 * cfg->img_construct_row; + Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, 128, 64, 1, 1); + + if (cfg->enable_img_alt_dir) { + Sprite_construct (&set->alt_dir_img); + int ax = 128 * cfg->img_alt_dir_column; + int ay = 64 * cfg->img_alt_dir_row; + Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, 128, 64, 1, 1); + + Sprite_construct (&set->alt_dir_construct_img); + int acx = 128 * cfg->img_alt_dir_construct_column; + int acy = 64 * cfg->img_alt_dir_construct_row; + Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, 128, 64, 1, 1); + } + } + + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + wpcx.vtable->destruct (&wpcx, __, 0); + } + + } + + if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { + char art_dir[200]; + char temp_path[2*MAX_PATH]; + snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + + char const * last_img_path = NULL; + PCX_Image nwpcx; + PCX_Image_construct (&nwpcx); + bool pcx_loaded = false; + + for (int ni = 0; ni < is->natural_wonder_count; ni++) { + struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; + if ((cfg->img_path == NULL) || (cfg->img_path[0] == '\0')) + continue; + + char const * img_path = cfg->img_path; + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + + read_in_dir (&nwpcx, temp_path, img_path, NULL); + + if (nwpcx.JGL.Image == NULL) { + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + Sprite_construct (&this->Natural_Wonder_Images[ni].img); + int x = 128 * cfg->img_column; + int y = 88 * cfg->img_row; + Sprite_slice_pcx (&this->Natural_Wonder_Images[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); + } + + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + nwpcx.vtable->destruct (&nwpcx, __, 0); + } + + img.vtable->destruct (&img, __, 0); + + return true; +} + +Sprite * +get_sprite_proxy_for_current_hour(Sprite *s) { + int v; + int hour = is->current_day_night_cycle; // 0..23 + if (itable_look_up(&is->day_night_sprite_proxy_by_hour[hour], (int)s, &v)) + return (Sprite *)v; + return NULL; // not proxied, fall back to s +} + +void +insert_spritelist_proxies(SpriteList *ss, SpriteList *ps, int hour, int len1, int len2) { + for (int i = 0; i < len1; i++) { + for (int j = 0; j < len2; j++) { + Sprite *s = &ss[i].field_0[j]; + Sprite *p = &ps[i].field_0[j]; + if (s && p) { + itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); + } + } + } +} + +void +insert_sprite_proxies(Sprite *ss, Sprite *ps, int hour, int len) { + for (int i = 0; i < len; i++) { + Sprite *s = &ss[i]; + Sprite *p = &ps[i]; + if (s && p) { + itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); + } + } +} + +void +insert_sprite_proxy(Sprite *s, Sprite *p, int hour) { + if (s && p) { + itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); + } +} + +void +build_sprite_proxies_24(Map_Renderer *mr) { + for (int h = 0; h < 24; ++h) { + insert_sprite_proxies(city_sprites, is->day_night_cycle_imgs[h].City_Images, h, 80); + insert_sprite_proxies(destroyed_city_sprites, is->day_night_cycle_imgs[h].Destroyed_City_Images, h, 3); + insert_sprite_proxies(mr->Resources, is->day_night_cycle_imgs[h].Resources, h, 36); + insert_spritelist_proxies(mr->Std_Terrain_Images, is->day_night_cycle_imgs[h].Std_Terrain_Images, h, 9, 81); + insert_spritelist_proxies(mr->LM_Terrain_Images, is->day_night_cycle_imgs[h].LM_Terrain_Images, h, 9, 81); + insert_sprite_proxy(&mr->Terrain_Buldings_Barbarian_Camp, &is->day_night_cycle_imgs[h].Terrain_Buldings_Barbarian_Camp, h); + insert_sprite_proxy(&mr->Terrain_Buldings_Mines, &is->day_night_cycle_imgs[h].Terrain_Buldings_Mines, h); + insert_sprite_proxy(&mr->Victory_Image, &is->day_night_cycle_imgs[h].Victory_Image, h); + insert_sprite_proxy(&mr->Terrain_Buldings_Radar, &is->day_night_cycle_imgs[h].Terrain_Buldings_Radar, h); + insert_sprite_proxies(mr->Flood_Plains_Images, is->day_night_cycle_imgs[h].Flood_Plains_Images, h, 16); + insert_sprite_proxies(mr->Polar_Icecaps_Images, is->day_night_cycle_imgs[h].Polar_Icecaps_Images, h, 32); + insert_sprite_proxies(mr->Roads_Images, is->day_night_cycle_imgs[h].Roads_Images, h, 256); + insert_sprite_proxies(mr->Railroads_Images, is->day_night_cycle_imgs[h].Railroads_Images, h, 272); + insert_sprite_proxies(mr->Terrain_Buldings_Airfields, is->day_night_cycle_imgs[h].Terrain_Buldings_Airfields, h, 2); + insert_sprite_proxies(mr->Terrain_Buldings_Camp, is->day_night_cycle_imgs[h].Terrain_Buldings_Camp, h, 4); + insert_sprite_proxies(mr->Terrain_Buldings_Fortress, is->day_night_cycle_imgs[h].Terrain_Buldings_Fortress, h, 4); + insert_sprite_proxies(mr->Terrain_Buldings_Barricade, is->day_night_cycle_imgs[h].Terrain_Buldings_Barricade, h, 4); + insert_sprite_proxies(mr->Goody_Huts_Images, is->day_night_cycle_imgs[h].Goody_Huts_Images, h, 8); + insert_sprite_proxies(mr->Terrain_Buldings_Outposts, is->day_night_cycle_imgs[h].Terrain_Buldings_Outposts, h, 3); + insert_sprite_proxies(mr->Pollution, is->day_night_cycle_imgs[h].Pollution, h, 25); + insert_sprite_proxies(mr->Craters, is->day_night_cycle_imgs[h].Craters, h, 25); + insert_sprite_proxies(mr->Tnt_Images, is->day_night_cycle_imgs[h].Tnt_Images, h, 18); + insert_sprite_proxies(mr->Waterfalls_Images, is->day_night_cycle_imgs[h].Waterfalls_Images, h, 4); + insert_sprite_proxies(mr->LM_Terrain, is->day_night_cycle_imgs[h].LM_Terrain, h, 7); + insert_sprite_proxies(mr->Marsh_Large, is->day_night_cycle_imgs[h].Marsh_Large, h, 8); + insert_sprite_proxies(mr->Marsh_Small, is->day_night_cycle_imgs[h].Marsh_Small, h, 10); + insert_sprite_proxies(mr->Volcanos_Images, is->day_night_cycle_imgs[h].Volcanos_Images, h, 16); + insert_sprite_proxies(mr->Volcanos_Forests_Images, is->day_night_cycle_imgs[h].Volcanos_Forests_Images, h, 16); + insert_sprite_proxies(mr->Volcanos_Jungles_Images, is->day_night_cycle_imgs[h].Volcanos_Jungles_Images, h, 16); + insert_sprite_proxies(mr->Volcanos_Snow_Images, is->day_night_cycle_imgs[h].Volcanos_Snow_Images, h, 16); + insert_sprite_proxies(mr->Grassland_Forests_Large, is->day_night_cycle_imgs[h].Grassland_Forests_Large, h, 8); + insert_sprite_proxies(mr->Plains_Forests_Large, is->day_night_cycle_imgs[h].Plains_Forests_Large, h, 8); + insert_sprite_proxies(mr->Tundra_Forests_Large, is->day_night_cycle_imgs[h].Tundra_Forests_Large, h, 8); + insert_sprite_proxies(mr->Grassland_Forests_Small, is->day_night_cycle_imgs[h].Grassland_Forests_Small, h, 10); + insert_sprite_proxies(mr->Plains_Forests_Small, is->day_night_cycle_imgs[h].Plains_Forests_Small, h, 10); + insert_sprite_proxies(mr->Tundra_Forests_Small, is->day_night_cycle_imgs[h].Tundra_Forests_Small, h, 10); + insert_sprite_proxies(mr->Grassland_Forests_Pines, is->day_night_cycle_imgs[h].Grassland_Forests_Pines, h, 12); + insert_sprite_proxies(mr->Plains_Forests_Pines, is->day_night_cycle_imgs[h].Plains_Forests_Pines, h, 12); + insert_sprite_proxies(mr->Tundra_Forests_Pines, is->day_night_cycle_imgs[h].Tundra_Forests_Pines, h, 12); + insert_sprite_proxies(mr->Irrigation_Desert_Images, is->day_night_cycle_imgs[h].Irrigation_Desert_Images, h, 16); + insert_sprite_proxies(mr->Irrigation_Plains_Images, is->day_night_cycle_imgs[h].Irrigation_Plains_Images, h, 16); + insert_sprite_proxies(mr->Irrigation_Images, is->day_night_cycle_imgs[h].Irrigation_Images, h, 16); + insert_sprite_proxies(mr->Irrigation_Tundra_Images, is->day_night_cycle_imgs[h].Irrigation_Tundra_Images, h, 16); + insert_sprite_proxies(mr->Grassland_Jungles_Large, is->day_night_cycle_imgs[h].Grassland_Jungles_Large, h, 8); + insert_sprite_proxies(mr->Grassland_Jungles_Small, is->day_night_cycle_imgs[h].Grassland_Jungles_Small, h, 12); + insert_sprite_proxies(mr->Mountains_Images, is->day_night_cycle_imgs[h].Mountains_Images, h, 16); + insert_sprite_proxies(mr->Mountains_Forests_Images, is->day_night_cycle_imgs[h].Mountains_Forests_Images, h, 16); + insert_sprite_proxies(mr->Mountains_Jungles_Images, is->day_night_cycle_imgs[h].Mountains_Jungles_Images, h, 16); + insert_sprite_proxies(mr->Mountains_Snow_Images, is->day_night_cycle_imgs[h].Mountains_Snow_Images, h, 16); + insert_sprite_proxies(mr->Hills_Images, is->day_night_cycle_imgs[h].Hills_Images, h, 16); + insert_sprite_proxies(mr->Hills_Forests_Images, is->day_night_cycle_imgs[h].Hills_Forests_Images, h, 16); + insert_sprite_proxies(mr->Hills_Jungle_Images, is->day_night_cycle_imgs[h].Hills_Jungle_Images, h, 16); + insert_sprite_proxies(mr->Delta_Rivers_Images, is->day_night_cycle_imgs[h].Delta_Rivers_Images, h, 16); + insert_sprite_proxies(mr->Mountain_Rivers_Images, is->day_night_cycle_imgs[h].Mountain_Rivers_Images, h, 16); + insert_sprite_proxies(mr->LM_Mountains_Images, is->day_night_cycle_imgs[h].LM_Mountains_Images, h, 16); + insert_sprite_proxies(mr->LM_Forests_Large_Images, is->day_night_cycle_imgs[h].LM_Forests_Large_Images, h, 8); + insert_sprite_proxies(mr->LM_Forests_Small_Images, is->day_night_cycle_imgs[h].LM_Forests_Small_Images, h, 10); + insert_sprite_proxies(mr->LM_Forests_Pines_Images, is->day_night_cycle_imgs[h].LM_Forests_Pines_Images, h, 12); + insert_sprite_proxies(mr->LM_Hills_Images, is->day_night_cycle_imgs[h].LM_Hills_Images, h, 16); + + if (is->current_config.enable_districts) { + for (int dc = 0; dc < is->district_count; dc++) { + struct district_config const * cfg = &is->district_configs[dc]; + int variant_capacity = ARRAY_LEN (is->district_img_sets[dc].imgs); + int variant_count = cfg->img_path_count; + if (variant_count <= 0) + continue; + if (variant_count > variant_capacity) + variant_count = variant_capacity; + + int era_count = cfg->vary_img_by_era ? 4 : 1; + int column_count = cfg->img_column_count; + + for (int variant_i = 0; variant_i < variant_count; variant_i++) { + if ((cfg->img_paths[variant_i] == NULL) || (cfg->img_paths[variant_i][0] == '\0')) + continue; + for (int era = 0; era < era_count; era++) { + for (int col = 0; col < column_count; col++) { + Sprite * base = &is->district_img_sets[dc].imgs[variant_i][era][col]; + Sprite * proxy = &is->day_night_cycle_imgs[h].District_Images[dc][variant_i][era][col]; + insert_sprite_proxy (base, proxy, h); + } + } + } + } + + insert_sprite_proxy (&is->abandoned_district_img, &is->day_night_cycle_imgs[h].Abandoned_District_Image, h); + insert_sprite_proxy (&is->abandoned_maritime_district_img, &is->day_night_cycle_imgs[h].Abandoned_Maritime_District_Image, h); + + // Wonder districts + if (is->current_config.enable_wonder_districts) { + for (int wi = 0; wi < is->wonder_district_count; wi++) { + Sprite * base_img = &is->wonder_district_img_sets[wi].img; + Sprite * proxy_img = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].img; + insert_sprite_proxy (base_img, proxy_img, h); + + Sprite * base_construct = &is->wonder_district_img_sets[wi].construct_img; + Sprite * proxy_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].construct_img; + insert_sprite_proxy (base_construct, proxy_construct, h); + + if (is->wonder_district_img_sets[wi].alt_dir_img.vtable != NULL) { + Sprite * base_alt = &is->wonder_district_img_sets[wi].alt_dir_img; + Sprite * proxy_alt = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_img; + insert_sprite_proxy (base_alt, proxy_alt, h); + } + + if (is->wonder_district_img_sets[wi].alt_dir_construct_img.vtable != NULL) { + Sprite * base_alt_construct = &is->wonder_district_img_sets[wi].alt_dir_construct_img; + Sprite * proxy_alt_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_construct_img; + insert_sprite_proxy (base_alt_construct, proxy_alt_construct, h); + } + } + } + } + + // Natural wonders + if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { + for (int ni = 0; ni < is->natural_wonder_count; ni++) { + Sprite * base_nw = &is->natural_wonder_img_sets[ni].img; + Sprite * proxy_nw = &is->day_night_cycle_imgs[h].Natural_Wonder_Images[ni].img; + insert_sprite_proxy (base_nw, proxy_nw, h); + } + } + } + is->day_night_cycle_img_proxies_indexed = true; +} + +void +init_day_night_images() +{ + if (is->day_night_cycle_img_state != IS_UNINITED) + return; + + const char *hour_strs[24] = { + "2400", "0100", "0200", "0300", "0400", "0500", "0600", "0700", + "0800", "0900", "1000", "1100", "1200", "1300", "1400", "1500", + "1600", "1700", "1800", "1900", "2000", "2100", "2200", "2300" + }; + + for (int i = 0; i < 24; i++) { + + char art_dir[200]; + char temp_path[2*MAX_PATH]; + snprintf (art_dir, sizeof art_dir, "DayNight/%s", hour_strs[i]); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + bool success = load_day_night_hour_images (&is->day_night_cycle_imgs[i], temp_path, hour_strs[i]); + + if (!success) { + char ss[200]; + snprintf(ss, sizeof ss, "Failed to load day/night cycle images for hour %s, reverting to base game art.", hour_strs[i]); + pop_up_in_game_error (ss); + + is->day_night_cycle_img_state = IS_INIT_FAILED; + return; + } + } + + Map_Renderer * mr = &p_bic_data->Map.Renderer; + build_sprite_proxies_24(mr); + + is->day_night_cycle_img_state = IS_OK; +} + +void +deindex_day_night_image_proxies() +{ + if (!is->day_night_cycle_img_proxies_indexed) + return; + + for (int i = 0; i < 24; i++) { + table_deinit (&is->day_night_sprite_proxy_by_hour[i]); + } + is->day_night_cycle_img_proxies_indexed = false; +} + +int +calculate_current_day_night_cycle_hour () +{ + int output = 12; // Default to noon + int increment = is->current_config.fixed_hours_per_turn_for_day_night_cycle; + + switch (is->current_config.day_night_cycle_mode) { + + // Disabled. This shouldn't be possible, but default to noon to be safe + case DNCM_OFF: + return output; + + // Time elapsed since last update + case DNCM_TIMER: { + LARGE_INTEGER perf_freq; + QueryPerformanceFrequency(&perf_freq); + + if (is->day_night_cycle_unstarted) { + is->current_day_night_cycle = output; + QueryPerformanceCounter(&is->last_day_night_cycle_update_time); + } + + LARGE_INTEGER time_now; + QueryPerformanceCounter(&time_now); + + double elapsed_seconds = + (double)(time_now.QuadPart - is->last_day_night_cycle_update_time.QuadPart) / + (double)perf_freq.QuadPart; + + if (elapsed_seconds > (double)is->current_config.elapsed_minutes_per_day_night_hour_transition * 60.0) { + output = is->current_day_night_cycle + increment; + is->last_day_night_cycle_update_time = time_now; + } else { + output = is->current_day_night_cycle; + } + break; + } + + // Match user's current time + case DNCM_USER_TIME: { + LPSYSTEMTIME lpSystemTime = (LPSYSTEMTIME)malloc(sizeof(SYSTEMTIME)); + GetLocalTime (lpSystemTime); + output = lpSystemTime->wHour; + free (lpSystemTime); + break; + } + + // Increment fixed amount each interturn + case DNCM_EVERY_TURN: { + if (is->day_night_cycle_unstarted) { + increment = 0; + is->current_day_night_cycle = output; + } + output = is->current_day_night_cycle + increment; + break; + } + + // Pin the hour to a specific value + case DNCM_SPECIFIED: { + output = is->current_config.pinned_hour_for_day_night_cycle; + break; + } + } + + // If midnight or over, restart at 0 or later + if (output > 23) output = output - 24; + + // Clamp to valid range of 0-23 in case of weird config values + output = clamp (0, 23, output); + is->day_night_cycle_unstarted = false; + + return output; +} + +void __fastcall +patch_Map_Renderer_load_images (Map_Renderer *this, int edx) +{ + Map_Renderer_load_images(this, __); + + // Initialize day/night cycle and re-calculate hour, if applicable + if (is->current_config.day_night_cycle_mode != DNCM_OFF) { + is->current_day_night_cycle = calculate_current_day_night_cycle_hour (); + + if (is->day_night_cycle_img_state == IS_UNINITED) { + init_day_night_images (); + } + + if (is->day_night_cycle_img_state == IS_OK) { + + // Sprite proxies are deindexed during each load event as sprite instances (really only Resources, which are reloaded) may change. + if (!is->day_night_cycle_img_proxies_indexed) { + build_sprite_proxies_24(this); + } + } + } +} + +void +patch_init_floating_point () +{ + init_floating_point (); + + // NOTE: At this point the program is done with the CRT initialization stuff and will start calling constructors for global + // objects as soon as this function returns. This is a good place to inject code that will run at program start. + + // Specify metadata about all boolean options on the mod config. We'll use this info to set up the table of offsets (for easy parsing) and to + // fill out the base config. + struct boolean_config_option { + char * name; + bool base_val; + int offset; + } boolean_config_options[] = { + {"enable_stack_bombard" , true , offsetof (struct c3x_config, enable_stack_bombard)}, + {"enable_disorder_warning" , true , offsetof (struct c3x_config, enable_disorder_warning)}, + {"allow_stealth_attack_against_single_unit" , false, offsetof (struct c3x_config, allow_stealth_attack_against_single_unit)}, + {"show_detailed_city_production_info" , true , offsetof (struct c3x_config, show_detailed_city_production_info)}, + {"limited_railroads_work_like_fast_roads" , false, offsetof (struct c3x_config, limited_railroads_work_like_fast_roads)}, + {"exclude_cities_from_units_per_tile_limit" , false, offsetof (struct c3x_config, exclude_cities_from_units_per_tile_limit)}, + {"enable_free_buildings_from_small_wonders" , true , offsetof (struct c3x_config, enable_free_buildings_from_small_wonders)}, + {"enable_stack_unit_commands" , true , offsetof (struct c3x_config, enable_stack_unit_commands)}, + {"skip_repeated_tile_improv_replacement_asks" , true , offsetof (struct c3x_config, skip_repeated_tile_improv_replacement_asks)}, + {"autofill_best_gold_amount_when_trading" , true , offsetof (struct c3x_config, autofill_best_gold_amount_when_trading)}, + {"disallow_founding_next_to_foreign_city" , true , offsetof (struct c3x_config, disallow_founding_next_to_foreign_city)}, + {"enable_trade_screen_scroll" , true , offsetof (struct c3x_config, enable_trade_screen_scroll)}, + {"group_units_on_right_click_menu" , true , offsetof (struct c3x_config, group_units_on_right_click_menu)}, + {"gray_out_units_on_menu_with_no_remaining_moves" , true , offsetof (struct c3x_config, gray_out_units_on_menu_with_no_remaining_moves)}, + {"put_movement_icons_on_units_on_menu" , true , offsetof (struct c3x_config, put_movement_icons_on_units_on_menu)}, + {"describe_states_of_units_on_menu" , true , offsetof (struct c3x_config, describe_states_of_units_on_menu)}, + {"show_golden_age_turns_remaining" , true , offsetof (struct c3x_config, show_golden_age_turns_remaining)}, + {"show_zoc_attacks_from_mid_stack" , true , offsetof (struct c3x_config, show_zoc_attacks_from_mid_stack)}, + {"show_armies_performing_defensive_bombard" , true , offsetof (struct c3x_config, show_armies_performing_defensive_bombard)}, + {"cut_research_spending_to_avoid_bankruptcy" , true , offsetof (struct c3x_config, cut_research_spending_to_avoid_bankruptcy)}, + {"dont_pause_for_love_the_king_messages" , true , offsetof (struct c3x_config, dont_pause_for_love_the_king_messages)}, + {"reverse_specialist_order_with_shift" , true , offsetof (struct c3x_config, reverse_specialist_order_with_shift)}, + {"toggle_zoom_with_z_on_city_screen" , true , offsetof (struct c3x_config, toggle_zoom_with_z_on_city_screen)}, + {"dont_give_king_names_in_non_regicide_games" , true , offsetof (struct c3x_config, dont_give_king_names_in_non_regicide_games)}, + {"no_elvis_easter_egg" , false, offsetof (struct c3x_config, no_elvis_easter_egg)}, + {"disable_worker_automation" , false, offsetof (struct c3x_config, disable_worker_automation)}, + {"enable_land_sea_intersections" , false, offsetof (struct c3x_config, enable_land_sea_intersections)}, + {"disallow_trespassing" , false, offsetof (struct c3x_config, disallow_trespassing)}, + {"show_detailed_tile_info" , true , offsetof (struct c3x_config, show_detailed_tile_info)}, + {"warn_about_unrecognized_names" , true , offsetof (struct c3x_config, warn_about_unrecognized_names)}, + {"enable_ai_production_ranking" , true , offsetof (struct c3x_config, enable_ai_production_ranking)}, + {"enable_ai_city_location_desirability_display" , true, offsetof (struct c3x_config, enable_ai_city_location_desirability_display)}, + {"show_ai_city_location_desirability_if_settler" , false, offsetof (struct c3x_config, show_ai_city_location_desirability_if_settler)}, + {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, + {"zero_corruption_when_off" , true , offsetof (struct c3x_config, zero_corruption_when_off)}, + {"disallow_land_units_from_affecting_water_tiles" , true , offsetof (struct c3x_config, disallow_land_units_from_affecting_water_tiles)}, + {"dont_end_units_turn_after_airdrop" , false, offsetof (struct c3x_config, dont_end_units_turn_after_airdrop)}, + {"allow_airdrop_without_airport" , false, offsetof (struct c3x_config, allow_airdrop_without_airport)}, + {"enable_negative_pop_pollution" , true , offsetof (struct c3x_config, enable_negative_pop_pollution)}, + {"allow_defensive_retreat_on_water" , false, offsetof (struct c3x_config, allow_defensive_retreat_on_water)}, + {"promote_wonder_decorruption_effect" , false, offsetof (struct c3x_config, promote_wonder_decorruption_effect)}, + {"allow_military_leaders_to_hurry_wonders" , false, offsetof (struct c3x_config, allow_military_leaders_to_hurry_wonders)}, + {"allow_multiple_battle_created_units_per_player" , false, offsetof (struct c3x_config, allow_multiple_battle_created_units_per_player)}, + {"aggressively_penalize_bankruptcy" , false, offsetof (struct c3x_config, aggressively_penalize_bankruptcy)}, + {"no_penalty_exception_for_agri_fresh_water_city_tiles" , false, offsetof (struct c3x_config, no_penalty_exception_for_agri_fresh_water_city_tiles)}, + {"use_offensive_artillery_ai" , true , offsetof (struct c3x_config, use_offensive_artillery_ai)}, + {"dont_escort_unflagged_units" , false, offsetof (struct c3x_config, dont_escort_unflagged_units)}, + {"replace_leader_unit_ai" , true , offsetof (struct c3x_config, replace_leader_unit_ai)}, + {"fix_ai_army_composition" , true , offsetof (struct c3x_config, fix_ai_army_composition)}, + {"enable_pop_unit_ai" , true , offsetof (struct c3x_config, enable_pop_unit_ai)}, + {"enable_caravan_unit_ai" , true , offsetof (struct c3x_config, enable_caravan_unit_ai)}, + {"remove_unit_limit" , true , offsetof (struct c3x_config, remove_unit_limit)}, + {"remove_city_improvement_limit" , true , offsetof (struct c3x_config, remove_city_improvement_limit)}, + {"remove_cap_on_turn_limit" , true , offsetof (struct c3x_config, remove_cap_on_turn_limit)}, + {"remove_era_limit" , false, offsetof (struct c3x_config, remove_era_limit)}, + {"patch_submarine_bug" , true , offsetof (struct c3x_config, patch_submarine_bug)}, + {"patch_science_age_bug" , true , offsetof (struct c3x_config, patch_science_age_bug)}, + {"patch_pedia_texture_bug" , true , offsetof (struct c3x_config, patch_pedia_texture_bug)}, + {"patch_blocked_disembark_freeze" , true , offsetof (struct c3x_config, patch_blocked_disembark_freeze)}, + {"patch_houseboat_bug" , true , offsetof (struct c3x_config, patch_houseboat_bug)}, + {"patch_intercept_lost_turn_bug" , true , offsetof (struct c3x_config, patch_intercept_lost_turn_bug)}, + {"patch_phantom_resource_bug" , true , offsetof (struct c3x_config, patch_phantom_resource_bug)}, + {"patch_maintenance_persisting_for_obsolete_buildings" , true , offsetof (struct c3x_config, patch_maintenance_persisting_for_obsolete_buildings)}, + {"patch_barbarian_diagonal_bug" , true , offsetof (struct c3x_config, patch_barbarian_diagonal_bug)}, + {"patch_disease_stopping_tech_flag_bug" , false, offsetof (struct c3x_config, patch_disease_stopping_tech_flag_bug)}, + {"patch_division_by_zero_in_ai_alliance_eval" , true , offsetof (struct c3x_config, patch_division_by_zero_in_ai_alliance_eval)}, + {"patch_empty_army_movement" , true , offsetof (struct c3x_config, patch_empty_army_movement)}, + {"patch_empty_army_combat_crash" , true , offsetof (struct c3x_config, patch_empty_army_combat_crash)}, + {"patch_premature_truncation_of_found_paths" , true , offsetof (struct c3x_config, patch_premature_truncation_of_found_paths)}, + {"patch_zero_production_crash" , true , offsetof (struct c3x_config, patch_zero_production_crash)}, + {"patch_ai_can_form_army_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_form_army_without_special_ability)}, + {"patch_ai_can_sacrifice_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_sacrifice_without_special_ability)}, + {"patch_crash_in_leader_unit_ai" , true , offsetof (struct c3x_config, patch_crash_in_leader_unit_ai)}, + {"patch_failure_to_find_new_city_build" , true , offsetof (struct c3x_config, patch_failure_to_find_new_city_build)}, + {"patch_passengers_out_of_order_on_menu" , true , offsetof (struct c3x_config, patch_passengers_out_of_order_on_menu)}, + {"delete_off_map_ai_units" , true , offsetof (struct c3x_config, delete_off_map_ai_units)}, + {"fix_overlapping_specialist_yield_icons" , true , offsetof (struct c3x_config, fix_overlapping_specialist_yield_icons)}, + {"prevent_autorazing" , false, offsetof (struct c3x_config, prevent_autorazing)}, + {"prevent_razing_by_players" , false, offsetof (struct c3x_config, prevent_razing_by_players)}, + {"suppress_hypertext_links_exceeded_popup" , true , offsetof (struct c3x_config, suppress_hypertext_links_exceeded_popup)}, + {"indicate_non_upgradability_in_pedia" , true , offsetof (struct c3x_config, indicate_non_upgradability_in_pedia)}, + {"show_message_after_dodging_sam" , true , offsetof (struct c3x_config, show_message_after_dodging_sam)}, + {"include_stealth_attack_cancel_option" , false, offsetof (struct c3x_config, include_stealth_attack_cancel_option)}, + {"intercept_recon_missions" , false, offsetof (struct c3x_config, intercept_recon_missions)}, + {"charge_one_move_for_recon_and_interception" , false, offsetof (struct c3x_config, charge_one_move_for_recon_and_interception)}, + {"polish_precision_striking" , true , offsetof (struct c3x_config, polish_precision_striking)}, + {"enable_stealth_attack_via_bombardment" , false, offsetof (struct c3x_config, enable_stealth_attack_via_bombardment)}, + {"immunize_aircraft_against_bombardment" , false, offsetof (struct c3x_config, immunize_aircraft_against_bombardment)}, + {"replay_ai_moves_in_hotseat_games" , false, offsetof (struct c3x_config, replay_ai_moves_in_hotseat_games)}, + {"restore_unit_directions_on_game_load" , true , offsetof (struct c3x_config, restore_unit_directions_on_game_load)}, + {"apply_grid_ini_setting_on_game_load" , true , offsetof (struct c3x_config, apply_grid_ini_setting_on_game_load)}, + {"charm_flag_triggers_ptw_like_targeting" , false, offsetof (struct c3x_config, charm_flag_triggers_ptw_like_targeting)}, + {"city_icons_show_unit_effects_not_trade" , true , offsetof (struct c3x_config, city_icons_show_unit_effects_not_trade)}, + {"ignore_king_ability_for_defense_priority" , false, offsetof (struct c3x_config, ignore_king_ability_for_defense_priority)}, + {"show_untradable_techs_on_trade_screen" , false, offsetof (struct c3x_config, show_untradable_techs_on_trade_screen)}, + {"disallow_useless_bombard_vs_airfields" , true , offsetof (struct c3x_config, disallow_useless_bombard_vs_airfields)}, + {"compact_luxury_display_on_city_screen" , false, offsetof (struct c3x_config, compact_luxury_display_on_city_screen)}, + {"compact_strategic_resource_display_on_city_screen" , false, offsetof (struct c3x_config, compact_strategic_resource_display_on_city_screen)}, + {"warn_when_chosen_building_would_replace_another" , false, offsetof (struct c3x_config, warn_when_chosen_building_would_replace_another)}, + {"do_not_unassign_workers_from_polluted_tiles" , false, offsetof (struct c3x_config, do_not_unassign_workers_from_polluted_tiles)}, + {"do_not_make_capital_cities_appear_larger" , false, offsetof (struct c3x_config, do_not_make_capital_cities_appear_larger)}, + {"show_territory_colors_on_water_tiles_in_minimap" , false, offsetof (struct c3x_config, show_territory_colors_on_water_tiles_in_minimap)}, + {"convert_some_popups_into_online_mp_messages" , false, offsetof (struct c3x_config, convert_some_popups_into_online_mp_messages)}, + {"enable_debug_mode_switch" , false, offsetof (struct c3x_config, enable_debug_mode_switch)}, + {"accentuate_cities_on_minimap" , false, offsetof (struct c3x_config, accentuate_cities_on_minimap)}, + {"allow_multipage_civilopedia_descriptions" , true , offsetof (struct c3x_config, allow_multipage_civilopedia_descriptions)}, + {"reformat_turns_remaining_on_domestic_advisor_screen" , true , offsetof (struct c3x_config, reformat_turns_remaining_on_domestic_advisor_screen)}, + {"expand_civilopedia_unit_stats" , true , offsetof (struct c3x_config, expand_civilopedia_unit_stats)}, + {"enable_trade_net_x" , true , offsetof (struct c3x_config, enable_trade_net_x)}, + {"optimize_improvement_loops" , true , offsetof (struct c3x_config, optimize_improvement_loops)}, + {"measure_turn_times" , false, offsetof (struct c3x_config, measure_turn_times)}, + {"enable_city_capture_by_barbarians" , false, offsetof (struct c3x_config, enable_city_capture_by_barbarians)}, + {"share_visibility_in_hotseat" , false, offsetof (struct c3x_config, share_visibility_in_hotseat)}, + {"share_wonders_in_hotseat" , false, offsetof (struct c3x_config, share_wonders_in_hotseat)}, + {"allow_precision_strikes_against_tile_improvements" , false, offsetof (struct c3x_config, allow_precision_strikes_against_tile_improvements)}, + {"dont_end_units_turn_after_bombarding_barricade" , false, offsetof (struct c3x_config, dont_end_units_turn_after_bombarding_barricade)}, + {"remove_land_artillery_target_restrictions" , false, offsetof (struct c3x_config, remove_land_artillery_target_restrictions)}, + {"allow_bombard_of_other_improvs_on_occupied_airfield" , false, offsetof (struct c3x_config, allow_bombard_of_other_improvs_on_occupied_airfield)}, + {"show_total_city_count" , false, offsetof (struct c3x_config, show_total_city_count)}, + {"strengthen_forbidden_palace_ocn_effect" , false, offsetof (struct c3x_config, strengthen_forbidden_palace_ocn_effect)}, + {"allow_upgrades_in_any_city" , false, offsetof (struct c3x_config, allow_upgrades_in_any_city)}, + {"do_not_generate_volcanos" , false, offsetof (struct c3x_config, do_not_generate_volcanos)}, + {"do_not_pollute_impassable_tiles" , false, offsetof (struct c3x_config, do_not_pollute_impassable_tiles)}, + {"show_hp_of_stealth_attack_options" , false, offsetof (struct c3x_config, show_hp_of_stealth_attack_options)}, + {"exclude_invisible_units_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_invisible_units_from_stealth_attack)}, + {"exclude_passengers_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_passengers_from_stealth_attack)}, + {"convert_to_landmark_after_planting_forest" , false, offsetof (struct c3x_config, convert_to_landmark_after_planting_forest)}, + {"allow_sale_of_aqueducts_and_hospitals" , false, offsetof (struct c3x_config, allow_sale_of_aqueducts_and_hospitals)}, + {"no_cross_shore_detection" , false, offsetof (struct c3x_config, no_cross_shore_detection)}, + {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, + {"limit_unit_loading_to_one_transport_per_turn" , false, offsetof (struct c3x_config, limit_unit_loading_to_one_transport_per_turn)}, + {"prevent_old_units_from_upgrading_past_ability_block" , false, offsetof (struct c3x_config, prevent_old_units_from_upgrading_past_ability_block)}, + {"allow_extraterritorial_colonies" , false, offsetof (struct c3x_config, allow_extraterritorial_colonies)}, + {"draw_forests_over_roads_and_railroads" , false, offsetof (struct c3x_config, draw_forests_over_roads_and_railroads)}, + {"enable_districts" , false, offsetof (struct c3x_config, enable_districts)}, + {"enable_neighborhood_districts" , false, offsetof (struct c3x_config, enable_neighborhood_districts)}, + {"enable_wonder_districts" , false, offsetof (struct c3x_config, enable_wonder_districts)}, + {"enable_natural_wonders" , false, offsetof (struct c3x_config, enable_natural_wonders)}, + {"add_natural_wonders_to_scenarios_if_none" , false, offsetof (struct c3x_config, add_natural_wonders_to_scenarios_if_none)}, + {"enable_named_tiles" , false, offsetof (struct c3x_config, enable_named_tiles)}, + {"enable_distribution_hub_districts" , false, offsetof (struct c3x_config, enable_distribution_hub_districts)}, + {"enable_aerodrome_districts" , false, offsetof (struct c3x_config, enable_aerodrome_districts)}, + {"enable_port_districts" , false, offsetof (struct c3x_config, enable_port_districts)}, + {"enable_bridge_districts" , false, offsetof (struct c3x_config, enable_bridge_districts)}, + {"enable_canal_districts" , false, offsetof (struct c3x_config, enable_canal_districts)}, + {"enable_central_rail_hub_districts" , false, offsetof (struct c3x_config, enable_central_rail_hub_districts)}, + {"enable_energy_grid_districts" , false, offsetof (struct c3x_config, enable_energy_grid_districts)}, + {"enable_great_wall_districts" , false, offsetof (struct c3x_config, enable_great_wall_districts)}, + {"completed_wonder_districts_can_be_destroyed" , false, offsetof (struct c3x_config, completed_wonder_districts_can_be_destroyed)}, + {"destroyed_wonders_can_be_built_again" , false, offsetof (struct c3x_config, destroyed_wonders_can_be_built_again)}, + {"cities_with_mutual_district_receive_buildings" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_buildings)}, + {"cities_with_mutual_district_receive_wonders" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_wonders)}, + {"show_message_when_building_received_by_mutual_district", false, offsetof (struct c3x_config, show_message_when_building_received_by_mutual_district)}, + {"show_message_when_building_lost_to_destroyed_district" , false, offsetof (struct c3x_config, show_message_when_building_lost_to_destroyed_district)}, + {"destroying_neighborhood_reduces_pop" , false, offsetof (struct c3x_config, destroying_neighborhood_reduces_pop)}, + {"air_units_use_aerodrome_districts_not_cities" , false, offsetof (struct c3x_config, air_units_use_aerodrome_districts_not_cities)}, + {"naval_units_use_port_districts_not_cities" , false, offsetof (struct c3x_config, naval_units_use_port_districts_not_cities)}, + {"show_natural_wonder_name_on_map" , false, offsetof (struct c3x_config, show_natural_wonder_name_on_map)}, + {"ai_defends_districts" , false, offsetof (struct c3x_config, ai_defends_districts)}, + {"great_wall_districts_impassible_by_others" , false, offsetof (struct c3x_config, great_wall_districts_impassible_by_others)}, + {"auto_build_great_wall_around_territory" , false, offsetof (struct c3x_config, auto_build_great_wall_around_territory)}, + {"disable_great_wall_city_defense_bonus" , false, offsetof (struct c3x_config, disable_great_wall_city_defense_bonus)}, + {"expand_water_tile_checks_to_city_work_area" , false, offsetof (struct c3x_config, expand_water_tile_checks_to_city_work_area)}, + {"ai_can_replace_existing_districts_with_canals" , false, offsetof (struct c3x_config, ai_can_replace_existing_districts_with_canals)}, + {"ai_builds_bridges" , false, offsetof (struct c3x_config, ai_builds_bridges)}, + {"ai_builds_canals" , false, offsetof (struct c3x_config, ai_builds_canals)}, + {"workers_can_enter_coast" , false, offsetof (struct c3x_config, workers_can_enter_coast)}, + {"enable_city_work_radii_highlights" , false, offsetof (struct c3x_config, enable_city_work_radii_highlights)}, + {"introduce_all_human_players_at_start_of_hotseat_game" , false, offsetof (struct c3x_config, introduce_all_human_players_at_start_of_hotseat_game)}, + {"allow_unload_from_army" , false, offsetof (struct c3x_config, allow_unload_from_army)}, + {"no_land_anti_air_from_inside_naval_transport" , false, offsetof (struct c3x_config, no_land_anti_air_from_inside_naval_transport)}, + {"prevent_enslaving_by_bombardment" , false, offsetof (struct c3x_config, prevent_enslaving_by_bombardment)}, + {"allow_adjacent_resources_of_different_types" , false, offsetof (struct c3x_config, allow_adjacent_resources_of_different_types)}, + {"allow_corruption_in_capital" , false, offsetof (struct c3x_config, allow_corruption_in_capital)}, + {"allow_sale_of_small_wonders" , false, offsetof (struct c3x_config, allow_sale_of_small_wonders)}, + {"initialize_preplaced_scenario_leaders_as_mgls" , false, offsetof (struct c3x_config, initialize_preplaced_scenario_leaders_as_mgls)}, + {"enable_unit_counters" , false, offsetof (struct c3x_config, enable_unit_counters)}, + {"use_civ4_style_best_defender" , false, offsetof (struct c3x_config, use_civ4_style_best_defender)}, + }; + + struct integer_config_option { + char * name; + int base_val; + int offset; + } integer_config_options[] = { + {"limit_railroad_movement" , 0, offsetof (struct c3x_config, limit_railroad_movement)}, + {"minimum_city_separation" , 1, offsetof (struct c3x_config, minimum_city_separation)}, + {"anarchy_length_percent" , 100, offsetof (struct c3x_config, anarchy_length_percent)}, + {"ai_multi_city_start" , 0, offsetof (struct c3x_config, ai_multi_city_start)}, + {"max_tries_to_place_fp_city" , 10000, offsetof (struct c3x_config, max_tries_to_place_fp_city)}, + {"ai_research_multiplier" , 100, offsetof (struct c3x_config, ai_research_multiplier)}, + {"ai_settler_perfume_on_founding_duration" , 0, offsetof (struct c3x_config, ai_settler_perfume_on_founding_duration)}, + {"extra_unit_maintenance_per_shields" , 0, offsetof (struct c3x_config, extra_unit_maintenance_per_shields)}, + {"ai_build_artillery_ratio" , 16, offsetof (struct c3x_config, ai_build_artillery_ratio)}, + {"ai_artillery_value_damage_percent" , 50, offsetof (struct c3x_config, ai_artillery_value_damage_percent)}, + {"ai_build_bomber_ratio" , 70, offsetof (struct c3x_config, ai_build_bomber_ratio)}, + {"max_ai_naval_escorts" , 3, offsetof (struct c3x_config, max_ai_naval_escorts)}, + {"ai_worker_requirement_percent" , 150, offsetof (struct c3x_config, ai_worker_requirement_percent)}, + {"chance_for_nukes_to_destroy_max_one_hp_units" , 100, offsetof (struct c3x_config, chance_for_nukes_to_destroy_max_one_hp_units)}, + {"rebase_range_multiplier" , 6, offsetof (struct c3x_config, rebase_range_multiplier)}, + {"elapsed_minutes_per_day_night_hour_transition" , 3, offsetof (struct c3x_config, elapsed_minutes_per_day_night_hour_transition)}, + {"fixed_hours_per_turn_for_day_night_cycle" , 1, offsetof (struct c3x_config, fixed_hours_per_turn_for_day_night_cycle)}, + {"pinned_hour_for_day_night_cycle" , 0, offsetof (struct c3x_config, pinned_hour_for_day_night_cycle)}, + {"years_to_double_building_culture" , 1000, offsetof (struct c3x_config, years_to_double_building_culture)}, + {"tourism_time_scale_percent" , 100, offsetof (struct c3x_config, tourism_time_scale_percent)}, + {"luxury_randomized_appearance_rate_percent" , 100, offsetof (struct c3x_config, luxury_randomized_appearance_rate_percent)}, + {"tiles_per_non_luxury_resource" , 32, offsetof (struct c3x_config, tiles_per_non_luxury_resource)}, + {"special_capital_decorruption_effect" , 10, offsetof (struct c3x_config, special_capital_decorruption_effect)}, + {"city_limit" , 2048, offsetof (struct c3x_config, city_limit)}, + {"maximum_pop_before_neighborhood_needed" , 8, offsetof (struct c3x_config, maximum_pop_before_neighborhood_needed)}, + {"per_neighborhood_pop_growth_enabled" , 2, offsetof (struct c3x_config, per_neighborhood_pop_growth_enabled)}, + {"minimum_natural_wonder_separation" , 10, offsetof (struct c3x_config, minimum_natural_wonder_separation)}, + {"distribution_hub_food_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_food_yield_divisor)}, + {"distribution_hub_shield_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_shield_yield_divisor)}, + {"ai_ideal_distribution_hub_count_per_100_cities" , 1, offsetof (struct c3x_config, ai_ideal_distribution_hub_count_per_100_cities)}, + {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, + {"max_distribution_hub_count_per_100_cities" , 50, offsetof (struct c3x_config, max_distribution_hub_count_per_100_cities)}, + {"central_rail_hub_distribution_food_bonus_percent" , 25, offsetof (struct c3x_config, central_rail_hub_distribution_food_bonus_percent)}, + {"central_rail_hub_distribution_shield_bonus_percent", 25, offsetof (struct c3x_config, central_rail_hub_distribution_shield_bonus_percent)}, + {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, + {"max_contiguous_bridge_districts" , 3, offsetof (struct c3x_config, max_contiguous_bridge_districts)}, + {"max_contiguous_canal_districts" , 5, offsetof (struct c3x_config, max_contiguous_canal_districts)}, + {"ai_canal_eval_min_bisected_land_tiles" , 10, offsetof (struct c3x_config, ai_canal_eval_min_bisected_land_tiles)}, + {"ai_bridge_canal_eval_block_size" , 20, offsetof (struct c3x_config, ai_bridge_canal_eval_block_size)}, + {"ai_bridge_eval_lake_tile_threshold" , 6, offsetof (struct c3x_config, ai_bridge_eval_lake_tile_threshold)}, + {"ai_city_district_max_build_wait_turns" , 20, offsetof (struct c3x_config, ai_city_district_max_build_wait_turns)}, + {"per_extraterritorial_colony_relation_penalty" , 0, offsetof (struct c3x_config, per_extraterritorial_colony_relation_penalty)}, + }; + + is->kernel32 = (*p_GetModuleHandleA) ("kernel32.dll"); + is->user32 = (*p_GetModuleHandleA) ("user32.dll"); + is->msvcrt = (*p_GetModuleHandleA) ("msvcrt.dll"); + + // Remember the function names here are macros that expand to is->... + VirtualProtect = (void *)(*p_GetProcAddress) (is->kernel32, "VirtualProtect"); + CloseHandle = (void *)(*p_GetProcAddress) (is->kernel32, "CloseHandle"); + CreateFileA = (void *)(*p_GetProcAddress) (is->kernel32, "CreateFileA"); + GetFileSize = (void *)(*p_GetProcAddress) (is->kernel32, "GetFileSize"); + ReadFile = (void *)(*p_GetProcAddress) (is->kernel32, "ReadFile"); + LoadLibraryA = (void *)(*p_GetProcAddress) (is->kernel32, "LoadLibraryA"); + FreeLibrary = (void *)(*p_GetProcAddress) (is->kernel32, "FreeLibrary"); + MultiByteToWideChar = (void *)(*p_GetProcAddress) (is->kernel32, "MultiByteToWideChar"); + WideCharToMultiByte = (void *)(*p_GetProcAddress) (is->kernel32, "WideCharToMultiByte"); + GetLastError = (void *)(*p_GetProcAddress) (is->kernel32, "GetLastError"); + QueryPerformanceCounter = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceCounter"); + QueryPerformanceFrequency = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceFrequency"); + GetLocalTime = (void *)(*p_GetProcAddress) (is->kernel32, "GetLocalTime"); + MessageBoxA = (void *)(*p_GetProcAddress) (is->user32, "MessageBoxA"); + is->msimg32 = LoadLibraryA ("Msimg32.dll"); + TransparentBlt = (void *)(*p_GetProcAddress) (is->msimg32, "TransparentBlt"); + snprintf = (void *)(*p_GetProcAddress) (is->msvcrt, "_snprintf"); + malloc = (void *)(*p_GetProcAddress) (is->msvcrt, "malloc"); + calloc = (void *)(*p_GetProcAddress) (is->msvcrt, "calloc"); + realloc = (void *)(*p_GetProcAddress) (is->msvcrt, "realloc"); + free = (void *)(*p_GetProcAddress) (is->msvcrt, "free"); + strtol = (void *)(*p_GetProcAddress) (is->msvcrt, "strtol"); + strcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strcmp"); + strncmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strncmp"); + _stricmp = (void *)(*p_GetProcAddress) (is->msvcrt, "_stricmp"); + strlen = (void *)(*p_GetProcAddress) (is->msvcrt, "strlen"); + strncpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strncpy"); + strcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strcpy"); + strdup = (void *)(*p_GetProcAddress) (is->msvcrt, "_strdup"); + strstr = (void *)(*p_GetProcAddress) (is->msvcrt, "strstr"); + qsort = (void *)(*p_GetProcAddress) (is->msvcrt, "qsort"); + memcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "memcmp"); + memcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "memcpy"); + tolower = (void *)(*p_GetProcAddress) (is->msvcrt, "tolower"); + toupper = (void *)(*p_GetProcAddress) (is->msvcrt, "toupper"); + is->memmove = (void *)(*p_GetProcAddress) (is->msvcrt, "memmove"); // No #define for this one, instead it has a wrapper func + + // Intercept the game's calls to MessageBoxA. We can't do this through the patcher since that would interfere with the runtime loader. + WITH_MEM_PROTECTION (p_MessageBoxA, 4, PAGE_READWRITE) + *p_MessageBoxA = patch_MessageBoxA; + + // Set file path to mod's script.txt + snprintf (is->mod_script_path, sizeof is->mod_script_path, "%s\\Text\\c3x-script.txt", is->mod_rel_dir); + is->mod_script_path[(sizeof is->mod_script_path) - 1] = '\0'; + + // Fill in base config + struct c3x_config base_config = {0}; + base_config.land_retreat_rules = RR_STANDARD; + base_config.sea_retreat_rules = RR_STANDARD; + base_config.ai_settler_perfume_on_founding = 0; + base_config.work_area_limit = WAL_NONE; + base_config.draw_lines_using_gdi_plus = LDO_WINE; + base_config.double_minimap_size = MDM_HIGH_DEF; + base_config.override_no_ai_patrol = NAPO_NONE; + base_config.override_barbarian_activity_level_for_scenario_maps = BAO_NONE; + base_config.unit_cycle_search_criteria = UCSC_STANDARD; + base_config.city_work_radius = 2; + base_config.day_night_cycle_mode = DNCM_OFF; + base_config.distribution_hub_yield_division_mode = DHYDM_FLAT; + base_config.ai_distribution_hub_build_strategy = ADHBS_BY_CITY_COUNT; + base_config.ai_auto_build_great_wall_strategy = AAGWS_ALL_BORDERS; + base_config.great_wall_auto_build_wonder_improv_id = -1; + for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) + *((char *)&base_config + boolean_config_options[n].offset) = boolean_config_options[n].base_val; + for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) + *(int *)((byte *)&base_config + integer_config_options[n].offset) = integer_config_options[n].base_val; + memcpy (&is->base_config, &base_config, sizeof base_config); + + // Load labels + { + for (int n = 0; n < COUNT_C3X_LABELS; n++) + is->c3x_labels[n] = ""; + + char labels_path[MAX_PATH]; + snprintf (labels_path, sizeof labels_path, "%s\\Text\\c3x-labels.txt", is->mod_rel_dir); + labels_path[(sizeof labels_path) - 1] = '\0'; + char * labels_file_contents = file_to_string (labels_path); + + if (labels_file_contents != NULL) { + char * cursor = labels_file_contents; + int n = 0; + while ((n < COUNT_C3X_LABELS) && (*cursor != '\0')) { + if (*cursor == '\n') + cursor++; + else if ((cursor[0] == '\r') && (cursor[1] == '\n')) + cursor += 2; + else if (*cursor == ';') { + while ((*cursor != '\0') && (*cursor != '\n')) + cursor++; + } else { + char * line_start = cursor; + while ((*cursor != '\0') && (*cursor != '\r') && (*cursor != '\n')) + cursor++; + int line_len = cursor - line_start; + if (NULL != (is->c3x_labels[n] = malloc (line_len + 1))) { + strncpy (is->c3x_labels[n], line_start, line_len); + is->c3x_labels[n][line_len] = '\0'; + } + n++; + } + } + free (labels_file_contents); + + } else { + char err_msg[500]; + snprintf (err_msg, sizeof err_msg, "Couldn't read labels from %s\nPlease make sure the file exists. If you moved the modded EXE you must move the mod folder after it.", labels_path); + err_msg[(sizeof err_msg) - 1] = '\0'; + MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); + } + } + + is->sb_next_up = NULL; + is->trade_net = p_original_trade_net; + is->city_limit = 512; + is->trade_net_addrs_load_state = IS_UNINITED; + is->trade_net_addrs = NULL; + is->tnx_cache = NULL; + is->is_computing_city_connections = false; + is->keep_tnx_cache = false; + is->must_recompute_resources_for_mill_inputs = false; + is->is_placing_scenario_things = false; + is->paused_for_popup = false; + is->time_spent_paused_during_popup = 0; + is->time_spent_computing_city_connections = 0; + is->count_calls_to_recompute_city_connections = 0; + + is->have_job_and_loc_to_skip = 0; + + // Initialize trade screen scroll vars + is->open_diplo_form_straight_to_trade = 0; + is->trade_screen_scroll_to_id = -1; + is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; + is->trade_scroll_button_images = NULL; + is->trade_scroll_button_state = IS_UNINITED; + is->eligible_for_trade_scroll = 0; + + memset (&is->saved_code_areas, 0, sizeof is->saved_code_areas); + + is->unit_menu_duplicates = NULL; + + is->memo = NULL; + is->memo_len = 0; + is->memo_capacity = 0; + + // Fill in array mapping cultural NIs to standard ones. + is->cultural_ni_to_standard = malloc (MAX_CULTURAL_NI + 1); + for (int n = 0; n <= MAX_CULTURAL_NI; n++) { + char const * p = &cultural_ni_to_diffs[n << 1]; + is->cultural_ni_to_standard[n] = diff_to_neighbor_index (p[0], p[1], 1000); + } + + // Fill in array mapping standard NIs to work radii AKA work ring numbers + for (int n = 0; n < ARRAY_LEN (is->ni_to_work_radius); n++) { + int work_radius = -1; + int dx, dy; + neighbor_index_to_diff (n, &dx, &dy); + for (int ring_no = 0; ring_no <= 7; ring_no++) { + for (int k = workable_tile_counts[ring_no-1]; k < workable_tile_counts[ring_no]; k++) { + char const * p = &cultural_ni_to_diffs[k<<1]; + if ((p[0] == dx) && (p[1] == dy)) { + work_radius = ring_no; + break; + } + } + if (work_radius != -1) + break; + } + is->ni_to_work_radius[n] = work_radius; + } + + is->city_loc_display_perspective = -1; + + is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; + + is->extra_available_resources = NULL; + is->extra_available_resources_capacity = 0; + + memset (is->interceptor_reset_lists, 0, sizeof is->interceptor_reset_lists); + + is->ai_prod_valuations = NULL; + is->count_ai_prod_valuations = 0; + is->ai_prod_valuations_capacity = 0; + + is->resource_tiles = NULL; + is->count_resource_tiles = 0; + is->resource_tiles_capacity = 0; + is->got_resource_tile = NULL; + is->saved_tile_count = -1; + is->mill_input_resource_bits = NULL; + + is->drawing_icons_for_improv_id = -1; + + is->resources_sheet = NULL; + + is->modifying_gold_trade = NULL; + + is->bombard_stealth_target = NULL; + is->selecting_stealth_target_for_bombard = 0; + + is->map_message_text_override = NULL; + + is->load_file_path_override = NULL; + + is->replay_for_players = 0; + + is->suppress_intro_after_load_popup = 0; + + is->force_barb_activity_for_cities = 0; + + is->dummy_tile = calloc (1, sizeof *is->dummy_tile); + + is->bombarding_unit = NULL; + + is->unit_bombard_attacking_tile = NULL; + is->attacking_tile_x = is->attacking_tile_y = -1; + + is->temporarily_disallow_lethal_zoc = false; + is->moving_unit_to_adjacent_tile = false; + is->showing_hotseat_replay = false; + is->getting_tile_occupier_for_ai_pathfinding = false; + + is->running_on_wine = false; { + HMODULE ntdll = (*p_GetModuleHandleA) ("ntdll.dll"); + is->running_on_wine = (ntdll != NULL) && ((*p_GetProcAddress) (ntdll, "wine_get_version") != NULL); + } + + is->gdi_plus.init_state = IS_UNINITED; + + is->water_trade_improvs = (struct improv_id_list) {0}; + is->air_trade_improvs = (struct improv_id_list) {0}; + is->combat_defense_improvs = (struct improv_id_list) {0}; + + is->unit_display_override = (struct unit_display_override) {-1, -1, -1}; + + is->dbe = (struct defensive_bombard_event) {0}; + + memset (&is->boolean_config_offsets, 0, sizeof is->boolean_config_offsets); + for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) + stable_insert (&is->boolean_config_offsets, boolean_config_options[n].name, boolean_config_options[n].offset); + memset (&is->integer_config_offsets, 0, sizeof is->integer_config_offsets); + for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) + stable_insert (&is->integer_config_offsets, integer_config_options[n].name, integer_config_options[n].offset); + + memset (&is->unit_type_alt_strategies, 0, sizeof is->unit_type_alt_strategies); + memset (&is->unit_type_duplicates , 0, sizeof is->unit_type_duplicates); + memset (&is->extra_defensive_bombards, 0, sizeof is->extra_defensive_bombards); + memset (&is->airdrops_this_turn , 0, sizeof is->airdrops_this_turn); + memset (&is->unit_transport_ties , 0, sizeof is->unit_transport_ties); + memset (&is->extra_city_improvs , 0, sizeof is->extra_city_improvs); + + is->unit_type_count_init_bits = 0; + for (int n = 0; n < 32; n++) + memset (&is->unit_type_counts[n], 0, sizeof is->unit_type_counts[n]); + + is->penciled_in_upgrades = NULL; + is->penciled_in_upgrade_count = is->penciled_in_upgrade_capacity = 0; + + is->currently_capturing_city = NULL; + is->accessing_save_file = NULL; + + is->drawn_strat_resource_count = 0; + + is->charmed_types_converted_to_ptw_arty = NULL; + is->count_charmed_types_converted_to_ptw_arty = 0; + is->charmed_types_converted_to_ptw_arty_capacity = 0; + + is->checking_visibility_for_unit = NULL; + + is->do_not_bounce_invisible_units = false; + is->always_despawn_passengers = false; + is->do_not_enslave_units = false; + + is->saved_improv_counts = NULL; + is->saved_improv_counts_capacity = 0; + + memset (is->last_main_screen_key_up_events, 0, sizeof is->last_main_screen_key_up_events); + + reset_district_state (true); + + is->natural_wonder_count = 0; + + is->sharing_buildings_by_districts_in_progress = false; + is->can_load_transport = is->can_load_passenger = NULL; + + is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; + is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; + is->last_selected_unit.ptr = NULL; + + is->waiting_units = (struct table) {0}; + is->have_loaded_waiting_units = false; + + is->extra_capture_despawns = NULL; + is->count_extra_capture_despawns = 0; + is->extra_capture_despawns_capacity = 0; + + is->loaded_config_names = NULL; + reset_to_base_config (); + apply_machine_code_edits (&is->current_config, true); +} + +void +init_stackable_command_buttons () +{ + if (is->sc_img_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + for (int n = 0; n < 4; n++) + Sprite_construct (&is->sc_button_image_sets[sc].imgs[n]); + + char temp_path[2*MAX_PATH]; + + is->sb_activated_by_button = 0; + is->sc_img_state = IS_INIT_FAILED; + + char const * filenames[4] = {"StackedNormButtons.pcx", "StackedRolloverButtons.pcx", "StackedHighlightedButtons.pcx", "StackedButtonsAlpha.pcx"}; + for (int n = 0; n < 4; n++) { + get_mod_art_path (filenames[n], temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + for (int k = 0; k < 4; k++) { + Sprite * sprite = &is->sc_button_image_sets[sc].imgs[k]; + sprite->vtable->destruct (sprite, __, 0); + } + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) { + int x = 32 * sc_button_infos[sc].tile_sheet_column, + y = 32 * sc_button_infos[sc].tile_sheet_row; + Sprite_slice_pcx (&is->sc_button_image_sets[sc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); + } + + pcx.vtable->clear_JGL (&pcx); + } + + is->sc_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +void +init_disabled_command_buttons () +{ + if (is->disabled_command_img_state != IS_UNINITED) + return; + + is->disabled_command_img_state = IS_INIT_FAILED; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("DisabledButtons.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load disabled command buttons sprite sheet.\n"); + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + Sprite_construct (&is->disabled_build_city_button_img); + Sprite_slice_pcx (&is->disabled_build_city_button_img, __, &pcx, 32*5, 32*2, 32, 32, 1, 0); + + is->disabled_command_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_stackable_command_buttons () +{ + if (is->sc_img_state == IS_OK) + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + for (int n = 0; n < 4; n++) { + Sprite * sprite = &is->sc_button_image_sets[sc].imgs[n]; + sprite->vtable->destruct (sprite, __, 0); + } + is->sc_img_state = IS_UNINITED; +} + +void +deinit_disabled_command_buttons () +{ + Sprite * sprite = &is->disabled_build_city_button_img; + if (is->disabled_command_img_state == IS_OK) + sprite->vtable->destruct (sprite, __, 0); + memset (sprite, 0, sizeof *sprite); + is->disabled_command_img_state = IS_UNINITED; +} + +void +init_tile_highlights () +{ + if (is->tile_highlight_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + + is->tile_highlight_state = IS_INIT_FAILED; + + snprintf (temp_path, sizeof temp_path, "%s\\Art\\TileHighlights.pcx", is->mod_rel_dir); + temp_path[(sizeof temp_path) - 1] = '\0'; + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); + goto cleanup; + } + + for (int n = 0; n < COUNT_TILE_HIGHLIGHTS; n++) + Sprite_slice_pcx (&is->tile_highlights[n], __, &pcx, 128*n, 0, 128, 64, 1, 0); + + is->tile_highlight_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +init_unit_rcm_icons () +{ + if (is->unit_rcm_icon_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("UnitRCMIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image == NULL) || + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 57) || + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 64)) { + (*p_OutputDebugStringA) ("[C3X] PCX file for unit RCM icons failed to load or is too small.\n"); + goto cleanup; + } + + for (int set = 0; set < COUNT_UNIT_RCM_ICON_SETS; set++) { + Sprite * icons = &is->unit_rcm_icons[set * COUNT_UNIT_RCM_ICONS]; + for (int n = 0; n < COUNT_UNIT_RCM_ICONS; n++) { + Sprite_construct (&icons[n]); + Sprite_slice_pcx (&icons[n], __, &pcx, 1 + 14*set, 1 + 16*n, 14, 15, 1, 0); + } + } + + is->unit_rcm_icon_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_unit_rcm_icons () +{ + if (is->unit_rcm_icon_state == IS_OK) { + int total_icon_count = COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS; + for (int n = 0; n < total_icon_count; n++) { + Sprite * sprite = &is->unit_rcm_icons[n]; + sprite->vtable->destruct (sprite, __, 0); + } + is->unit_rcm_icon_state = IS_UNINITED; + } +} + +void +init_red_food_icon () +{ + if (is->red_food_icon_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("MoreCityIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image != NULL) && + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) >= 32) && + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) == 32)) { + Sprite_construct (&is->red_food_icon); + Sprite_slice_pcx (&is->red_food_icon, __, &pcx, 1, 1, 30, 30, 1, 1); + is->red_food_icon_state = IS_OK; + } else { + (*p_OutputDebugStringA) ("[C3X] PCX file for red food icon failed to load or is not the correct size.\n"); + is->red_food_icon_state = IS_INIT_FAILED; + } + + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_red_food_icon () +{ + if (is->red_food_icon_state == IS_OK) + is->red_food_icon.vtable->destruct (&is->red_food_icon, __, 0); + is->red_food_icon_state = IS_UNINITED; +} + +enum init_state +init_large_minimap_frame () +{ + if (is->large_minimap_frame_img_state != IS_UNINITED) + return is->large_minimap_frame_img_state; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + + get_mod_art_path ("interface\\DoubleSizeBoxLeftColor.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image != NULL) { + Sprite_construct (&is->double_size_box_left_color_pcx); + int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), + height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); + Sprite_slice_pcx (&is->double_size_box_left_color_pcx, __, &pcx, 0, 0, width, height, 1, 1); + } else { + pcx.vtable->destruct (&pcx, __, 0); + return is->large_minimap_frame_img_state = IS_INIT_FAILED; + } + + get_mod_art_path ("interface\\DoubleSizeBoxLeftAlpha.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image != NULL) { + Sprite_construct (&is->double_size_box_left_alpha_pcx); + int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), + height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); + Sprite_slice_pcx (&is->double_size_box_left_alpha_pcx, __, &pcx, 0, 0, width, height, 1, 1); + } else { + is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); + pcx.vtable->destruct (&pcx, __, 0); + return is->large_minimap_frame_img_state = IS_INIT_FAILED;; + } + + pcx.vtable->destruct (&pcx, __, 0); + return is->large_minimap_frame_img_state = IS_OK; +} + +void +deinit_large_minimap_frame () +{ + if (is->large_minimap_frame_img_state == IS_OK) { + is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); + is->double_size_box_left_alpha_pcx.vtable->destruct (&is->double_size_box_left_alpha_pcx, __, 0); + } + is->large_minimap_frame_img_state = IS_UNINITED; +} + +int __cdecl +patch_get_tile_occupier_for_ai_path (int x, int y, int pov_civ_id, bool respect_unit_invisibility) +{ + is->getting_tile_occupier_for_ai_pathfinding = true; + return get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); + is->getting_tile_occupier_for_ai_pathfinding = false; +} + +char __fastcall patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2); + +char __fastcall +patch_Unit_is_tile_occupier_visible (Unit * this, int edx, int civ_id, int param_2) +{ + // Here's the fix for the submarine bug: If we're constructing a path for an AI unit, ignore unit invisibility so the pathfinder will path + // around instead of over other civ's units. We must carve out an exception if the AI is at war with the unit in question. In that case if it + // "accidentally" paths over the unit, it should get stuck in combat like the human player would. + if (is->current_config.patch_submarine_bug && + is->getting_tile_occupier_for_ai_pathfinding && + ! this->vtable->is_enemy_of_civ (this, __, civ_id, 0)) + return 1; + else + return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); +} + +void do_trade_scroll (DiploForm * diplo, int forward); + +void __cdecl +activate_trade_scroll_button (int control_id) +{ + do_trade_scroll (p_diplo_form, control_id == TRADE_SCROLL_BUTTON_ID_RIGHT); +} + +void +init_trade_scroll_buttons (DiploForm * diplo_form) +{ + if (is->trade_scroll_button_state != IS_UNINITED) + return; + + char temp_path[2*MAX_PATH]; + PCX_Image pcx; + PCX_Image_construct (&pcx); + get_mod_art_path ("TradeScrollButtons.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + is->trade_scroll_button_state = IS_INIT_FAILED; + (*p_OutputDebugStringA) ("[C3X] Failed to load TradeScrollButtons.pcx\n"); + goto cleanup; + } + + // Stores normal, rollover, and highlight images, in that order, first for the left button then for the right + is->trade_scroll_button_images = calloc (6, sizeof is->trade_scroll_button_images[0]); + for (int n = 0; n < 6; n++) + Sprite_construct (&is->trade_scroll_button_images[n]); + Sprite * imgs = is->trade_scroll_button_images; + + for (int right = 0; right < 2; right++) + for (int n = 0; n < 3; n++) + Sprite_slice_pcx (&imgs[n + 3*right], __, &pcx, right ? 44 : 0, 1 + 48*n, 43, 47, 1, 1); + + for (int right = 0; right < 2; right++) { + Button * b = new (sizeof *b); + + Button_construct (b); + int id = right ? TRADE_SCROLL_BUTTON_ID_RIGHT : TRADE_SCROLL_BUTTON_ID_LEFT; + Button_initialize (b, __, NULL, id, right ? 622 : 358, 50, 43, 47, (Base_Form *)diplo_form, 0); + for (int n = 0; n < 3; n++) + b->Images[n] = &imgs[n + 3*right]; + + b->activation_handler = &activate_trade_scroll_button; + b->field_630[0] = 0; // TODO: Is this necessary? It's done by the base game code when creating the city screen scroll buttons + + if (! right) + is->trade_scroll_button_left = b; + else + is->trade_scroll_button_right = b; + } + + is->trade_scroll_button_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_trade_scroll_buttons () +{ + if (is->trade_scroll_button_state == IS_OK) { + is->trade_scroll_button_left ->vtable->destruct ((Base_Form *)is->trade_scroll_button_left , __, 0); + is->trade_scroll_button_right->vtable->destruct ((Base_Form *)is->trade_scroll_button_right, __, 0); + is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; + for (int n = 0; n < 6; n++) { + Sprite * sprite = &is->trade_scroll_button_images[n]; + sprite->vtable->destruct (sprite, __, 0); + } + free (is->trade_scroll_button_images); + is->trade_scroll_button_images = NULL; + } + is->trade_scroll_button_state = IS_UNINITED; +} + +void +init_mod_info_button_images () +{ + if (is->mod_info_button_images_state != IS_UNINITED) + return; + + is->mod_info_button_images_state = IS_INIT_FAILED; + + PCX_Image * descbox_pcx = new (sizeof *descbox_pcx); + PCX_Image_construct (descbox_pcx); + char * descbox_path = BIC_get_asset_path (p_bic_data, __, "art\\civilopedia\\descbox.pcx", true); + PCX_Image_read_file (descbox_pcx, __, descbox_path, NULL, 0, 0x100, 1); + if (descbox_pcx->JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load descbox.pcx\n"); + return; + } + + for (int n = 0; n < 3; n++) { + Sprite_construct (&is->mod_info_button_images[n]); + Sprite_slice_pcx_with_color_table (&is->mod_info_button_images[n], __, descbox_pcx, 1 + n * 103, 1, MOD_INFO_BUTTON_WIDTH, + MOD_INFO_BUTTON_HEIGHT, 1, 1); + } + + is->mod_info_button_images_state = IS_OK; +} + +int +count_escorters (Unit * unit) +{ + IDLS * idls = &unit->Body.IDLS; + if (idls->escorters.contents != NULL) { + int tr = 0; + for (int * p_escorter_id = idls->escorters.contents; p_escorter_id < idls->escorters.contents_end; p_escorter_id++) + tr += NULL != get_unit_ptr (*p_escorter_id); + return tr; + } else + return 0; +} + +// If "unit" belongs to the AI, records that all players that have visibility on (x, y) have seen an AI unit +void +record_ai_unit_seen (Unit * unit, int x, int y) +{ + if (0 == (*p_human_player_bits & 1<Body.CivID)) { + Tile * tile = tile_at (x, y); + if ((tile != NULL) && (tile != p_null_tile)) { + Tile_Body * body = &tile->Body; + is->players_saw_ai_unit |= body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility; + } + } +} + +void +recompute_resources_if_necessary () +{ + if (is->must_recompute_resources_for_mill_inputs) + patch_Trade_Net_recompute_resources (is->trade_net, __, false); +} + +void __fastcall +patch_Unit_bombard_tile (Unit * this, int edx, int x, int y) +{ + Tile * target_tile = NULL; + bool had_district_before = false; + int tile_x = x; + int tile_y = y; + struct district_instance * inst; + + if (is->current_config.enable_districts) { + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + target_tile = tile_at (tile_x, tile_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + inst = get_district_instance (target_tile); + had_district_before = (inst != NULL); + } + } + + is->bombarding_unit = this; + record_ai_unit_seen (this, x, y); + Unit_bombard_tile (this, __, x, y); + is->bombard_stealth_target = NULL; + is->bombarding_unit = NULL; + + if (had_district_before && target_tile != NULL && target_tile != p_null_tile && inst->district_id != NATURAL_WONDER_DISTRICT_ID) { + unsigned int overlays = target_tile->vtable->m42_Get_Overlays (target_tile, __, 0); + if ((overlays & TILE_FLAG_MINE) == 0) + handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, false); + } +} + +void __fastcall +patch_Unit_move (Unit * this, int edx, int tile_x, int tile_y) +{ + record_ai_unit_seen (this, tile_x, tile_y); + + Unit_move (this, __, tile_x, tile_y); + + if (this == is->last_selected_unit.ptr) { + is->last_selected_unit.last_x = this->Body.X; + is->last_selected_unit.last_y = this->Body.Y; + } +} + +// Returns true if the unit has attacked & does not have blitz or if it's run out of movement points for the turn +bool +has_exhausted_attack (Unit * unit) +{ + return (unit->Body.Moves >= patch_Unit_get_max_move_points (unit)) || + ((unit->Body.Status & USF_USED_ATTACK) && ! UnitType_has_ability (&p_bic_data->UnitTypes[unit->Body.UnitTypeID], __, UTA_Blitz)); +} + +// Returns whether or not the unit type is a combat type and can do damage on offense (as opposed to only being able to defend). This includes units +// that can only do damage by bombarding and nuclear weapons. +bool +is_offensive_combat_type (UnitType * unit_type) +{ + return (unit_type->Attack > 0) || + ((((unit_type->Special_Actions & UCV_Bombard) | (unit_type->Air_Missions & UCV_Bombing)) & 0x0FFFFFFF) && // (type can perform bombard or bombing AND + ((unit_type->Bombard_Strength > 0) || UnitType_has_ability (unit_type, __, UTA_Nuclear_Weapon))); // (unit has bombard strength OR is a nuclear weapon)) +} + +bool +can_damage_bombarding (UnitType * attacker_type, Unit * defender, Tile * defender_tile) +{ + Unit * container; + if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + (container = get_unit_ptr (defender->Body.Container_Unit)) != NULL && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return false; + + UnitType * defender_type = &p_bic_data->UnitTypes[defender->Body.UnitTypeID]; + if (defender_type->Unit_Class == UTC_Land) { + int has_lethal_land_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Land_Bombardment); + return defender->Body.Damage + (! has_lethal_land_bombard) < Unit_get_max_hp (defender); + } else if (defender_type->Unit_Class == UTC_Sea) { + // Land artillery can't normally damage ships in port + if ((attacker_type->Unit_Class == UTC_Land) && (! is->current_config.remove_land_artillery_target_restrictions) && Tile_has_city (defender_tile)) + return false; + int has_lethal_sea_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Sea_Bombardment); + return defender->Body.Damage + (! has_lethal_sea_bombard) < Unit_get_max_hp (defender); + } else if (defender_type->Unit_Class == UTC_Air) { + if (is->current_config.immunize_aircraft_against_bombardment) + return false; + // Can't damage aircraft in an airfield by bombarding, the attack doesn't even go off + if ((defender_tile->vtable->m42_Get_Overlays (defender_tile, __, 0) & 0x20000000) != 0) + return false; + // Land artillery can't normally damage aircraft but naval artillery and other aircraft can. Lethal bombard doesn't apply; anything + // that can damage can kill. + return (attacker_type->Unit_Class != UTC_Land) || is->current_config.remove_land_artillery_target_restrictions; + } else // UTC_Space? UTC_Alternate_Dimension??? + return false; +} + +char __fastcall +patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2) +{ + // Save the previous value here b/c this function gets called recursively + Unit * prev_checking = is->checking_visibility_for_unit; + is->checking_visibility_for_unit = this; + + char base_vis = Unit_is_visible_to_civ (this, __, civ_id, param_2); + if ((! base_vis) && // if unit is not visible to civ_id AND + is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND + ((1 << civ_id) & *p_human_player_bits) && // civ_id is a human player AND + (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game + + // Check if the unit is visible to any other human player in the game + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && + (n_player != civ_id) && + Unit_is_visible_to_civ (this, __, n_player, param_2)) + return 1; + player_bits >>= 1; + n_player++; + } + } + + is->checking_visibility_for_unit = prev_checking; + return base_vis; +} + +bool +has_any_destructible_improvements (City * city) +{ + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * improv = &p_bic_data->Improvements[n]; + if (((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) && // if improv is not a wonder AND + ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && // it's not the palace AND + (improv->SpaceshipPart < 0) && // it's not a spaceship part AND + patch_City_has_improvement (city, __, n, 0)) // it's present in the city ignoring free improvements + return true; + } + return false; +} + +int const destructible_overlays = + 0x00000003 | // road, railroad + 0x00000004 | // mine + 0x00000008 | // irrigation + 0x00000010 | // fortress + 0x10000000 | // barricade + 0x20000000 | // airfield + 0x40000000 | // radar + 0x80000000; // outpost + +bool +has_any_destructible_overlays (Tile * tile, bool precision_strike) +{ + int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); + if ((overlays & destructible_overlays) == 0) + return false; + else { + if (! precision_strike) + return true; + else { + if (overlays == 0x20000000) { // if tile ONLY has an airfield + int any_aircraft_on_tile = 0; { + FOR_UNITS_ON (uti, tile) + if (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class == UTC_Air) { + any_aircraft_on_tile = 1; + break; + } + } + return ! any_aircraft_on_tile; + } else + return true; + } + } +} + +void __fastcall +patch_Main_Screen_Form_perform_action_on_tile (Main_Screen_Form * this, int edx, enum Unit_Mode_Actions action, int x, int y) +{ + if ((! is->current_config.enable_stack_bombard) || // if stack bombard is disabled OR + (! ((action == UMA_Bombard) || (action == UMA_Air_Bombard))) || // action is not bombard OR + ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) && // (control key is not down AND + ((is->sc_img_state != IS_UNINITED) && (is->sb_activated_by_button == 0))) || // (button flag is valid AND not set)) OR + is_online_game ()) { // is online game + Main_Screen_Form_perform_action_on_tile (this, __, action, x, y); + return; + } + + // Save preferences so we can restore them at the end of the stack bombard operation. We might change them to turn off combat animations. + unsigned init_prefs = *p_preferences; + + clear_memo (); + + wrap_tile_coords (&p_bic_data->Map, &x, &y); + Tile * base_tile = tile_at (this->Current_Unit->Body.X, this->Current_Unit->Body.Y); + Tile * target_tile = tile_at (x, y); + int attacker_type_id = this->Current_Unit->Body.UnitTypeID; + UnitType * attacker_type = &p_bic_data->UnitTypes[attacker_type_id]; + int civ_id = this->Current_Unit->Body.CivID; + + // Count & memoize attackers + int selected_unit_id = this->Current_Unit->Body.ID; + FOR_UNITS_ON (uti, base_tile) + if ((uti.id != selected_unit_id) && + (uti.unit->Body.CivID == civ_id) && + (uti.unit->Body.UnitTypeID == attacker_type_id) && + ((uti.unit->Body.Container_Unit < 0) || (attacker_type->Unit_Class == UTC_Air)) && + (uti.unit->Body.UnitState == 0) && + ! has_exhausted_attack (uti.unit)) + memoize (uti.id); + int count_attackers = is->memo_len; + + // Count & memoize targets (also count air units while we're at it) + int num_air_units_on_target_tile = 0; + FOR_UNITS_ON (uti, target_tile) { + num_air_units_on_target_tile += UTC_Air == p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; + if ((uti.unit->Body.CivID != civ_id) && + (Unit_get_defense_strength (uti.unit) > 0) && + (uti.unit->Body.Container_Unit < 0) && + patch_Unit_is_visible_to_civ (uti.unit, __, civ_id, 0) && + can_damage_bombarding (attacker_type, uti.unit, target_tile)) + memoize (uti.id); + } + int count_targets = is->memo_len - count_attackers; + + // Now our attackers and targets arrays will just be pointers into the memo + int * attackers = &is->memo[0], * targets = &is->memo[count_attackers]; + + int attacking_units = 0, attacking_tile = 0; + City * target_city = NULL; + if (count_targets > 0) + attacking_units = 1; + else if (Tile_has_city (target_tile)) + target_city = get_city_ptr (target_tile->vtable->m45_Get_City_ID (target_tile)); + else { + // Make sure not to set attacking_tile when the tile has an airfield and air units (but no land units) on + // it. In that case we can't damage the airfield and if we try to anyway, the units will waste their moves + // without attacking. + int has_airfield = (target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & 0x20000000) != 0; + attacking_tile = (! has_airfield) || (num_air_units_on_target_tile == 0); + } + + is->sb_next_up = this->Current_Unit; + int i_next_attacker = 0; + int anything_left_to_attack; + int last_attack_didnt_happen; + do { + // If combat animations were enabled when the stack bombard operation started, reset the preference according to the state of the + // shift key (down => skip animations, up => show them). + if (init_prefs & P_ANIMATE_BATTLES) { + if ((*p_GetAsyncKeyState) (VK_SHIFT) >> 8) + *p_preferences &= ~P_ANIMATE_BATTLES; + else + *p_preferences |= P_ANIMATE_BATTLES; + } + + int moves_before_bombard = is->sb_next_up->Body.Moves; + + patch_Unit_bombard_tile (is->sb_next_up, __, x, y); + // At this point sb_next_up may have become NULL if the unit was a bomber that got shot down. + + // Check if the last unit sent into battle actually did anything. If it didn't we should at least skip over + // it to avoid an infinite loop, but actually the only time this should happen is if the player is not at + // war with the targeted civ and chose not to declare when prompted. In this case it's better to just stop + // trying to attack so as to not spam the player with prompts. + last_attack_didnt_happen = (is->sb_next_up == NULL) || (is->sb_next_up->Body.Moves == moves_before_bombard); + + if ((is->sb_next_up == NULL) || has_exhausted_attack (is->sb_next_up)) { + is->sb_next_up = NULL; + while ((i_next_attacker < count_attackers) && (is->sb_next_up == NULL)) + is->sb_next_up = get_unit_ptr (attackers[i_next_attacker++]); + } + + if (attacking_units) { + anything_left_to_attack = 0; + for (int n = 0; n < count_targets; n++) { + Unit * unit = get_unit_ptr (targets[n]); + + // Make sure this unit is still a valid target. Keep in mind it's possible for new units to be created during the + // stack bombard operation if the attackers have lethal bombard and the enslave ability. + if ((unit != NULL) && (unit->Body.X == x) && (unit->Body.Y == y) && (unit->Body.CivID != civ_id)) { + + if (can_damage_bombarding (attacker_type, unit, target_tile)) { + anything_left_to_attack = 1; + break; + } + } + } + } else if (target_city != NULL) + anything_left_to_attack = (target_city->Body.Population.Size > 1) || has_any_destructible_improvements (target_city); + else if (attacking_tile) + anything_left_to_attack = has_any_destructible_overlays (target_tile, false); + else + anything_left_to_attack = 0; + } while ((is->sb_next_up != NULL) && anything_left_to_attack && (! last_attack_didnt_happen)); + + is->sb_activated_by_button = 0; + is->sb_next_up = NULL; + *p_preferences = init_prefs; + this->GUI.Base.vtable->m73_call_m22_Draw ((Base_Form *)&this->GUI); +} + +void +set_up_stack_bombard_buttons (Main_GUI * this) +{ + if (is_online_game () || (! is->current_config.enable_stack_bombard)) + return; + + init_stackable_command_buttons (); + if (is->sc_img_state != IS_OK) + return; + + // Find button that the original method set to (air) bombard, then find the next unused button after that. + Command_Button * bombard_button = NULL, * free_button = NULL; { + int i_bombard_button; + for (int n = 0; n < 42; n++) + if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && + (this->Unit_Command_Buttons[n].Command == UCV_Bombard || this->Unit_Command_Buttons[n].Command == UCV_Bombing)) { + bombard_button = &this->Unit_Command_Buttons[n]; + i_bombard_button = n; + break; + } + if (bombard_button != NULL) + for (int n = i_bombard_button + 1; n < 42; n++) + if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { + free_button = &this->Unit_Command_Buttons[n]; + break; + } + } + + if ((bombard_button == NULL) || (free_button == NULL)) + return; + + // Set up free button for stack bombard + free_button->Command = bombard_button->Command; + free_button->field_6D8 = bombard_button->field_6D8; + struct sc_button_image_set * img_set = + (bombard_button->Command == UCV_Bombing) ? &is->sc_button_image_sets[SC_BOMB] : &is->sc_button_image_sets[SC_BOMBARD]; + for (int n = 0; n < 4; n++) + free_button->Button.Images[n] = &img_set->imgs[n]; + free_button->Button.field_664 = bombard_button->Button.field_664; + // FUN_005559E0 is also called in the original code. I don't know what it actually does but I'm pretty sure it doesn't + // matter for our purposes. + Button_set_tooltip (&free_button->Button, __, is->c3x_labels[CL_SB_TOOLTIP]); + free_button->Button.field_5FC[13] = bombard_button->Button.field_5FC[13]; + free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); +} + +void +init_district_command_buttons () +{ + if (is_online_game () || is->dc_btn_img_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) + for (int n = 0; n < 4; n++) + Sprite_construct (&is->district_btn_img_sets[dc].imgs[n]); + + char temp_path[2*MAX_PATH]; + + is->dc_btn_img_state = IS_INIT_FAILED; + + // For each button sprite type (normal, rollover, highlighted, alpha) + char const * filenames[4] = { + "Districts\\WorkerDistrictButtonsNorm.pcx", "Districts\\WorkerDistrictButtonsRollover.pcx", + "Districts\\WorkerDistrictButtonsHighlighted.pcx", "Districts\\WorkerDistrictButtonsAlpha.pcx" + }; + for (int n = 0; n < 4; n++) { + get_mod_art_path (filenames[n], temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load work district command buttons sprite sheet.\n"); + for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) + for (int k = 0; k < 4; k++) { + Sprite * sprite = &is->district_btn_img_sets[dc].imgs[k]; + sprite->vtable->destruct (sprite, __, 0); + } + pcx.vtable->destruct (&pcx, __, 0); + + char ss[200]; + snprintf (ss, sizeof ss, "[C3X] Failed to load district command button images from %s", temp_path); + pop_up_in_game_error (ss); + + return; + } + + // For each district type + int district_count = is->district_count; + if (district_count > COUNT_DISTRICT_TYPES) + district_count = COUNT_DISTRICT_TYPES; + for (int dc = 0; dc < district_count; dc++) { + int x = 32 * is->district_configs[dc].btn_tile_sheet_column, + y = 32 * is->district_configs[dc].btn_tile_sheet_row; + Sprite_slice_pcx (&is->district_btn_img_sets[dc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); + } + + pcx.vtable->clear_JGL (&pcx); + } + + is->dc_btn_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +int +parse_turns_from_tooltip (char const * tooltip) +{ + if ((tooltip == NULL) || (*tooltip == '\0')) + return -1; + + char const * last_paren = NULL; + for (char const * cursor = tooltip; *cursor != '\0'; cursor++) + if (*cursor == '(') + last_paren = cursor; + if (last_paren == NULL) + return -1; + + char const * digit_ptr = last_paren + 1; + while (*digit_ptr == ' ') + digit_ptr++; + + int turns = 0; + bool have_digit = false; + while ((*digit_ptr >= '0') && (*digit_ptr <= '9')) { + have_digit = true; + turns = (turns * 10) + (*digit_ptr - '0'); + digit_ptr++; + } + return have_digit ? turns : -1; +} + +void +compute_highlighted_worker_tiles_for_districts () +{ + if (is_online_game () + || ! is->current_config.enable_districts + || ! is->current_config.enable_city_work_radii_highlights) + return; + + Unit * selected_unit = p_main_screen_form->Current_Unit; + if (selected_unit == NULL) + return; + + int unit_type_id = selected_unit->Body.UnitTypeID; + if (p_bic_data->UnitTypes[unit_type_id].Worker_Actions == 0) + return; + + if (is->tile_highlight_state == IS_UNINITED) + init_tile_highlights (); + if (is->tile_highlight_state != IS_OK) + return; + + int worker_civ_id = selected_unit->Body.CivID; + if ((p_cities == NULL) || (p_cities->Cities == NULL)) + return; + + // Loop over all cities owned by this civ and tally their workable tiles + FOR_CITIES_OF (coi, worker_civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + + // Highlight city center so players can easily see which cities contribute + Tile * city_center_tile = tile_at (city->Body.X, city->Body.Y); + if ((city_center_tile != NULL) && (city_center_tile != p_null_tile)) { + int stored_ptr; + if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, &stored_ptr)) { + struct highlighted_city_radius_tile_info * info = malloc (sizeof (struct highlighted_city_radius_tile_info)); + info->highlight_level = 0; + itable_insert (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, (int)info); + } + } + + // Add all workable tiles around the city (excluding city center) + for (int n = 1; n < is->workable_tile_count; n++) { + int dx, dy; + patch_ni_to_diff_for_work_area (n, &dx, &dy); + int tile_x = city->Body.X + dx; + int tile_y = city->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + + Tile * workable_tile = tile_at (tile_x, tile_y); + if ((workable_tile == NULL) || (workable_tile == p_null_tile)) continue; + if (workable_tile->vtable->m38_Get_Territory_OwnerID (workable_tile) != worker_civ_id) continue; + + // Upsert into highlighted_city_radius_tile_pointers + int stored_ptr; + struct highlighted_city_radius_tile_info * info; + if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, &stored_ptr)) { + info = malloc (sizeof (struct highlighted_city_radius_tile_info)); + info->highlight_level = 0; + itable_insert (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, (int)info); + } else { + info = (struct highlighted_city_radius_tile_info *)stored_ptr; + info->highlight_level += 3; + } + } + } +} + +void +set_up_district_buttons (Main_GUI * this) +{ + if (is_online_game () || ! is->current_config.enable_districts) return; + if (is->dc_btn_img_state == IS_UNINITED) init_district_command_buttons (); + if (is->dc_btn_img_state != IS_OK) return; + + Unit * selected_unit = p_main_screen_form->Current_Unit; + if (selected_unit == NULL || ! is_worker(selected_unit)) return; + + Tile * tile = tile_at (selected_unit->Body.X, selected_unit->Body.Y); + if ((tile == NULL) || (tile == p_null_tile) || (tile->CityID >= 0)) return; + + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + if (tile->vtable->m21_Check_Crates (tile, __, 0)) return; + if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return; + + Command_Button * fortify_button = NULL; + int i_starting_button; + int mine_turns = -1; + for (int n = 0; n < 42; n++) { + if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && + (this->Unit_Command_Buttons[n].Command == UCV_Fortify)) { + fortify_button = &this->Unit_Command_Buttons[n]; + i_starting_button = n; + } + if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { + mine_turns = parse_turns_from_tooltip (this->Unit_Command_Buttons[n].Button.ToolTip); + } + if (fortify_button != NULL && mine_turns >= 0) + break; + } + + if (fortify_button == NULL) + return; + + i_starting_button = -1; + + // Check if there's already a district on this tile. If so, and the unit can build mines, + // ensure the mine button is enabled so the worker can continue construction. + int existing_district_id = -1; + struct district_instance * existing_inst = get_district_instance (tile); + if (existing_inst != NULL) { + existing_district_id = existing_inst->district_id; + if (is->current_config.enable_natural_wonders && existing_inst->district_id == NATURAL_WONDER_DISTRICT_ID) { + return; + } + if (patch_Unit_can_perform_command(selected_unit, __, UCV_Build_Mine)) { + for (int n = 0; n < 42; n++) { + if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { + Command_Button * mine_button = &this->Unit_Command_Buttons[n]; + if (base_type == SQ_Coast) { + mine_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&mine_button->Button); + break; + } + if ((mine_button->Button.Base_Data.Status2 & 1) == 0) { + mine_button->Button.field_5FC[13] = 0; + mine_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&mine_button->Button, __, 0); + } + break; + } + } + } + } + + bool district_completed = district_is_complete (tile, existing_district_id); + + // First pass: collect which district types should be shown + int active_districts[COUNT_DISTRICT_TYPES]; + int active_count = 0; + + for (int dc = 0; dc < is->district_count; dc++) { + + if (is->district_configs[dc].command == -1) + continue; + + bool already_building = false; + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if (unit != NULL && is_worker(unit) && existing_inst != NULL && existing_inst->district_id == dc) { + // If there's a worker on the tile and it's building this district, + // show the button so more workers can contribute. This works around an + // issue where a specific district requiring irrigation no longer + // is buildable by other workers because initial construction removes the + // required irrigation overlay upon construction start + already_building = true; + break; + } + } + + if (existing_district_id == dc && district_completed) continue; + if ((existing_district_id >= 0) && (existing_district_id != dc) && (! district_completed)) continue; + + if (! can_build_district_on_tile (tile, dc, selected_unit->Body.CivID) && ! already_building) + continue; + + // This district should be shown + active_districts[active_count++] = dc; + } + + + if (active_count == 0) + return; + + // Calculate centered starting position + // For odd counts, center perfectly; for even counts, favor left of center + int center_pos = 6; + i_starting_button = center_pos - (active_count / 2); + if (i_starting_button < 0) + i_starting_button = 0; + + // Second pass: render the buttons + for (int idx = 0; idx < active_count; idx++) { + int dc = active_districts[idx]; + + Command_Button * free_button = NULL; + for (int n = i_starting_button; n < 42; n++) { + if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { + free_button = &this->Unit_Command_Buttons[n]; + i_starting_button = n + 1; + break; + } + } + + if (free_button == NULL) + return; + + // Set up free button for creating district + free_button->Command = is->district_configs[dc].command; + + // Replace the button's image with the district image. Disabling & re-enabling and + // clearing field_5FC[13] are all necessary to trigger a redraw. + free_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&free_button->Button); + free_button->field_6D8 = fortify_button->field_6D8; + for (int k = 0; k < 4; k++) + free_button->Button.Images[k] = &is->district_btn_img_sets[dc].imgs[k]; + free_button->Button.field_664 = fortify_button->Button.field_664; + if (mine_turns >= 0) { + char tooltip[256]; + char const * turn_word = (mine_turns == 1) ? "turn" : "turns"; + snprintf (tooltip, sizeof tooltip, "%s (%d %s)", is->district_configs[dc].tooltip, mine_turns, turn_word); + tooltip[(sizeof tooltip) - 1] = '\0'; + Button_set_tooltip (&free_button->Button, __, tooltip); + } else + Button_set_tooltip (&free_button->Button, __, (char *)is->district_configs[dc].tooltip); + free_button->Button.field_5FC[13] = 0; + free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); + } +} + +void +set_up_stack_worker_buttons (Main_GUI * this) +{ + if ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // (control key is not down OR + (! is->current_config.enable_stack_unit_commands) || // stack worker commands not enabled OR + is_online_game ()) // is online game + return; + + init_stackable_command_buttons (); + if (is->sc_img_state != IS_OK) + return; + + // For each unit command button + for (int n = 0; n < 42; n++) { + Command_Button * cb = &this->Unit_Command_Buttons[n]; + + // If it's enabled and not a bombard button (those are handled in the function above) + if (((cb->Button.Base_Data.Status2 & 1) != 0) && + (cb->Command != UCV_Bombard) && (cb->Command != UCV_Bombing)) { + + // Find the stackable worker command that this button controls, if there is one, and check that + // the button isn't already showing the stack image for that command. Note: this check is important + // b/c this function gets called repeatedly while the CTRL key is held down. + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + if ((cb->Command == sc_button_infos[sc].command) && + (cb->Button.Images[0] != &is->sc_button_image_sets[sc].imgs[0])) { + + // Replace the button's image with the stack image. Disabling & re-enabling and + // clearing field_5FC[13] are all necessary to trigger a redraw. + cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); + for (int k = 0; k < 4; k++) + cb->Button.Images[k] = &is->sc_button_image_sets[sc].imgs[k]; + cb->Button.field_5FC[13] = 0; + cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); + + break; + } + } + } +} + +CityLocValidity __fastcall patch_Map_check_city_location (Map * this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile); + +void __fastcall +patch_Main_GUI_set_up_unit_command_buttons (Main_GUI * this) +{ + // Recompute resources now if needed because of a trade deal involving mill inputs. In rare cases the change in deals might affect a mill that + // produces a resource that's used for a worker job. + recompute_resources_if_necessary (); + + Main_GUI_set_up_unit_command_buttons (this); + set_up_stack_bombard_buttons (this); + set_up_stack_worker_buttons (this); + + if (is->current_config.enable_districts) { + set_up_district_buttons (this); + } + + // If the minimum city separation is increased, then gray out the found city button if we're too close to another city. + if ((is->current_config.minimum_city_separation > 1) && (p_main_screen_form->Current_Unit != NULL) && (is->disabled_command_img_state == IS_OK)) { + Unit_Body * selected_unit = &p_main_screen_form->Current_Unit->Body; + + // For each unit command button + for (int n = 0; n < 42; n++) { + Command_Button * cb = &this->Unit_Command_Buttons[n]; + + // If it's enabled, set to city founding, and the current city location is too close to another city + if (((cb->Button.Base_Data.Status2 & 1) != 0) && + (cb->Command == UCV_Build_City) && + (patch_Map_check_city_location (&p_bic_data->Map, __, selected_unit->X, selected_unit->Y, selected_unit->CivID, false) == CLV_CITY_TOO_CLOSE)) { + + // Replace the button's image with the disabled image, as in set_up_stack_worker_buttons. + cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); + for (int k = 0; k < 3; k++) + cb->Button.Images[k] = &is->disabled_build_city_button_img; + cb->Button.field_5FC[13] = 0; + + char tooltip[200]; { + memset (tooltip, 0, sizeof tooltip); + char * label = is->c3x_labels[CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP], + * to_replace = "$NUM0", + * replace_location = strstr (label, to_replace); + if (replace_location != NULL) + snprintf (tooltip, sizeof tooltip, "%.*s%d%s", replace_location - label, label, is->current_config.minimum_city_separation, replace_location + strlen (to_replace)); + else + snprintf (tooltip, sizeof tooltip, "%s", label); + tooltip[(sizeof tooltip) - 1] = '\0'; + } + Button_set_tooltip (&cb->Button, __, tooltip); + + cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); + + } + } + } +} + +void +clear_highlighted_worker_tiles_and_redraw () +{ + clear_highlighted_worker_tiles_for_districts (); + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +void +check_happiness_at_end_of_turn () +{ + int num_unhappy_cities = 0; + City * first_unhappy_city = NULL; + FOR_CITIES_OF (coi, p_main_screen_form->Player_CivID) { + City_recompute_happiness (coi.city); + int num_happy = 0, num_unhappy = 0; + FOR_CITIZENS_IN (ci, coi.city) { + num_happy += ci.ctzn->Body.Mood == CMT_Happy; + num_unhappy += ci.ctzn->Body.Mood == CMT_Unhappy; + } + if (num_unhappy > num_happy) { + num_unhappy_cities++; + if (first_unhappy_city == NULL) + first_unhappy_city = coi.city; + } + } + + if (first_unhappy_city != NULL) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, first_unhappy_city->Body.CityName, -1, -1); + if (num_unhappy_cities > 1) + set_popup_int_param (1, num_unhappy_cities - 1); + char * key = (num_unhappy_cities > 1) ? "C3X_DISORDER_WARNING_MULTIPLE" : "C3X_DISORDER_WARNING_ONE"; + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, key, -1, 0, 0, 0); + int response = patch_show_popup (popup, __, 0, 0); + + if (response == 2) { // zoom to city + p_main_screen_form->turn_end_flag = 1; + City_zoom_to (first_unhappy_city, __, 0); + } else if (response == 1) // just cancel turn end + p_main_screen_form->turn_end_flag = 1; + // else do nothing, let turn end + + } +} + +void +do_trade_scroll (DiploForm * diplo, int forward) +{ + int increment = forward ? 1 : -1; + int id = -1; + for (int n = (diplo->other_party_civ_id + increment) & 31; n != diplo->other_party_civ_id; n = (n + increment) & 31) + if ((n != 0) && // if N is not barbs AND + (n != p_main_screen_form->Player_CivID) && // N is not the player's AND + (*p_player_bits & (1U << n)) && // N belongs to an active player AND + (leaders[p_main_screen_form->Player_CivID].Contacts[n] & 1) && // N has contact with the player AND + Leader_ai_would_meet_with (&leaders[n], __, p_main_screen_form->Player_CivID)) { // AI is willing to meet + id = n; + break; + } + + if (id >= 0) { + is->trade_screen_scroll_to_id = id; + DiploForm_close (diplo); + // Note extra code needs to get run here if the other player is not an AI + } +} + +void __fastcall +patch_DiploForm_m82_handle_key_event (DiploForm * this, int edx, int virtual_key_code, int is_down) +{ + if (is->eligible_for_trade_scroll && + (this->mode == 2) && + ((virtual_key_code == VK_LEFT) || (virtual_key_code == VK_RIGHT)) && + (! is_down)) + do_trade_scroll (this, virtual_key_code == VK_RIGHT); + else + DiploForm_m82_handle_key_event (this, __, virtual_key_code, is_down); +} + +int __fastcall +patch_DiploForm_m68_Show_Dialog (DiploForm * this, int edx, int param_1, void * param_2, void * param_3) +{ + if (is->open_diplo_form_straight_to_trade) { + is->open_diplo_form_straight_to_trade = 0; + + // Done by the base game but not necessary as far as I can tell + // void (__cdecl * FUN_00537700) (int) = 0x537700; + // FUN_00537700 (0x15); + // this->field_E9C[0] = this->field_E9C[0] + 1; + + // Set diplo screen mode to two-way trade negotation + this->mode = 2; + + // Set AI's diplo message to something like "what did you have in mind" + int iVar35 = DiploForm_set_their_message (this, __, DM_AI_PROPOSAL_RESPONSE, 0, 0x1A8); + this->field_1390[0] = DM_AI_PROPOSAL_RESPONSE; + this->field_1390[1] = 0; + this->field_1390[2] = iVar35; + + // Reset player message options. This will replace the propose deal, declare war, and leave options with the usual "nevermind" option + // that appears for negotiations. + DiploForm_reset_our_message_choices (this); + + // Done by the base game but not necessary as far as I can tell + // void (__fastcall * FUN_004C89A0) (void *) = 0x4C89A0; + // FUN_004C89A0 (&this->field_1BF4[0]); + + } + + return DiploForm_m68_Show_Dialog (this, __, param_1, param_2, param_3); +} + +void __fastcall +patch_DiploForm_do_diplomacy (DiploForm * this, int edx, int diplo_message, int param_2, int civ_id, int do_not_request_audience, int war_negotiation, int disallow_proposal, TradeOfferList * our_offers, TradeOfferList * their_offers) +{ + is->open_diplo_form_straight_to_trade = 0; + is->trade_screen_scroll_to_id = -1; + + // Trade screen scroll is disabled in online games b/c there's extra synchronization we'd need to do to open or close the diplo screen with + // a human player. + is->eligible_for_trade_scroll = is->current_config.enable_trade_screen_scroll && (! is_online_game ()); + + if (is->eligible_for_trade_scroll && (is->trade_scroll_button_state == IS_UNINITED)) + init_trade_scroll_buttons (this); + + WITH_PAUSE_FOR_POPUP { + DiploForm_do_diplomacy (this, __, diplo_message, param_2, civ_id, do_not_request_audience, war_negotiation, disallow_proposal, our_offers, their_offers); + + while (is->trade_screen_scroll_to_id >= 0) { + int scroll_to_id = is->trade_screen_scroll_to_id; + is->trade_screen_scroll_to_id = -1; + is->open_diplo_form_straight_to_trade = 1; + DiploForm_do_diplomacy (this, __, DM_AI_COUNTER, 0, scroll_to_id, 1, 0, 0, NULL, NULL); + } + } + + is->open_diplo_form_straight_to_trade = 0; + is->eligible_for_trade_scroll = 0; +} + +void __fastcall +patch_DiploForm_m22_Draw (DiploForm * this) +{ + if (is->trade_scroll_button_state == IS_OK) { + Button * left = is->trade_scroll_button_left, + * right = is->trade_scroll_button_right; + if (is->eligible_for_trade_scroll && (this->mode == 2)) { + left ->vtable->m01_Show_Enabled ((Base_Form *)left , __, 0); + right->vtable->m01_Show_Enabled ((Base_Form *)right, __, 0); + left ->vtable->m73_call_m22_Draw ((Base_Form *)left); + right->vtable->m73_call_m22_Draw ((Base_Form *)right); + } else { + left ->vtable->m02_Show_Disabled ((Base_Form *)left); + right->vtable->m02_Show_Disabled ((Base_Form *)right); + } + } + + DiploForm_m22_Draw (this); +} + +void +intercept_end_of_turn () +{ + if (is->current_config.enable_disorder_warning) { + check_happiness_at_end_of_turn (); + if (p_main_screen_form->turn_end_flag == 1) // Check if player cancelled turn ending in the disorder warning popup + return; + } + + // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + + if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { + is->city_loc_display_perspective = -1; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw + } + + // Clear things that don't apply across turns + is->have_job_and_loc_to_skip = 0; +} + +bool +is_worker_or_settler_command (int unit_command_value) +{ + return (unit_command_value & 0x20000000) || + ((unit_command_value >= UCV_Build_Remote_Colony) && (unit_command_value <= UCV_Auto_Save_Tiles)); +} + +bool +command_would_replace_district (int unit_command_value) +{ + // Note: Roads & railroads, etc. can coexist with the district + return (unit_command_value == UCV_Build_Mine) || + (unit_command_value == UCV_Irrigate) || + (unit_command_value == UCV_Plant_Forest) || + (unit_command_value == UCV_Build_Outpost) || + (unit_command_value == UCV_Build_Fortress) || + (unit_command_value == UCV_Build_Barricade) || + (unit_command_value == UCV_Build_Airfield) || + (unit_command_value == UCV_Build_Radar_Tower) || + (unit_command_value == UCV_Build_Colony); +} + +bool +handle_worker_command_that_may_replace_district (Unit * unit, int unit_command_value, bool * removed_existing) +{ + if (removed_existing != NULL) + *removed_existing = false; + + if ((! is->current_config.enable_districts) || (unit == NULL)) return true; + if (! is_worker_or_settler_command (unit_command_value)) return true; + if (! command_would_replace_district (unit_command_value)) return true; + if (! patch_Unit_can_perform_command (unit, __, unit_command_value)) return true; + + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + if ((tile == NULL) || (tile == p_null_tile)) + return true; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (! district_is_complete (tile, inst->district_id))) + return true; + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + return false; + + int district_id = inst->district_id; + int civ_id = unit->Body.CivID; + bool redundant_district = district_instance_is_redundant (inst, tile); + bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (district_id, civ_id, tile_x, tile_y); + if (redundant_district) + would_lose_buildings = false; + + bool remove_existing = redundant_district; + if (inst != NULL && district_id >= 0 && district_id < is->district_count) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char *)is->district_configs[district_id].display_name, -1, -1); + set_popup_str_param (1, (char *)is->district_configs[district_id].display_name, -1, -1); + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + would_lose_buildings + ? "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT" + : "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT_SAFE", + -1, 0, 0, 0); + int sel = patch_show_popup (popup, __, 0, 0); + if (sel != 0) + return false; + remove_existing = true; + } + + if (remove_existing) { + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + handle_district_removed (tile, district_id, tile_x, tile_y, false); + if (removed_existing != NULL) + *removed_existing = true; + } + + return true; +} + +bool __fastcall + patch_Unit_can_upgrade (Unit * this) +{ + bool base = Unit_can_upgrade (this); + int available; + City * city = city_at (this->Body.X, this->Body.Y); + if (base && + (city != NULL) && + get_available_unit_count (&leaders[this->Body.CivID], City_get_upgraded_type_id (city, __, this->Body.UnitTypeID), &available) && + (available <= 0)) + return false; + else + return base; +} + +bool +is_district_command (int unit_command_value) +{ + int district_id = -1; + if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) + return false; + + return district_id != NATURAL_WONDER_DISTRICT_ID; +} + +int __fastcall +patch_Map_check_colony_location (Map * this, int edx, int tile_x, int tile_y, int civ_id) +{ + int base = Map_check_colony_location (this, __, tile_x, tile_y, civ_id); + Tile * tile = tile_at (tile_x, tile_y); + + if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.allow_extraterritorial_colonies) + return base; + + if (tile->vtable->m35_Check_Is_Water (tile)) return base; + if (Tile_has_city (tile) || Tile_has_colony (tile)) return base; + + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_id < 0) || (owner_id == civ_id)) return base; + + int resource_type = Tile_get_resource_visible_to (tile, __, civ_id); + if ((resource_type < 0) || (resource_type >= p_bic_data->ResourceTypeCount)) return base; + + int req_tech = p_bic_data->ResourceTypes[resource_type].RequireID; + if ((req_tech >= 0) && (! Leader_has_tech (&leaders[civ_id], __, req_tech))) return base; + + int res_class = p_bic_data->ResourceTypes[resource_type].Class; + if ((res_class != RC_Strategic) && (res_class != RC_Luxury)) return base; + if (tile->vtable->m26_Check_Tile_Building (tile)) + return 6; + + return 0; +} + +bool __fastcall +patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value) +{ + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + // No worker or settler commands allowed on natural wonders + if ((tile != NULL) && (tile != p_null_tile) && is->current_config.enable_natural_wonders) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && + (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) { + if (is_worker_or_settler_command (unit_command_value) || is_district_command (unit_command_value)) + return false; + } + } + + if (is_district_command (unit_command_value)) { + int district_id; + if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) + return false; + + return is_worker (this) && can_build_district_on_tile (tile, district_id, this->Body.CivID); + } + // Extra check for colony founding if extraterritorial colonies allowed + else if (unit_command_value == UCV_Build_Colony || unit_command_value == UCV_Build_Remote_Colony) { + if (is->current_config.allow_extraterritorial_colonies && is_worker (this)) { + return patch_Map_check_colony_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID) == 0; + } + } + // Extra check for road building if bridge districts allowed + else if (unit_command_value == UCV_Build_Road) { + struct district_instance * inst = get_district_instance (tile); + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + if (!has_road && (inst != NULL) && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) + return true; + } + // Extra check for railroad building if bridge districts allowed + else if (unit_command_value == UCV_Build_Railroad) { + struct district_instance * inst = get_district_instance (tile); + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; + if ((inst != NULL) && is_worker (this) && has_road && + ! has_rail && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) { + int req_tech = p_bic_data->WorkerJobs[WJ_Build_Railroad].RequireID; + if ((req_tech < 0) || + ((req_tech != p_bic_data->AdvanceCount) && + Leader_has_tech (&leaders[this->Body.CivID], __, req_tech))) { + if (Leader_has_resources_for_job_at (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y)) + return true; + } + } + } + else if (unit_command_value == UCV_Build_Mine) { + bool has_district = (tile != NULL) && (tile != p_null_tile) && (get_district_instance (tile) != NULL); + + if (has_district) { + return Tile_get_mining_bonus (tile) > 0; + } + } else if (unit_command_value == UCV_Pillage) { + return patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y); + } + } + if (is->current_config.disable_worker_automation && + (this->Body.CivID == p_main_screen_form->Player_CivID) && + (unit_command_value == UCV_Automate)) + return false; + else if (is->current_config.disallow_land_units_from_affecting_water_tiles && + is_worker_or_settler_command (unit_command_value)) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + enum UnitTypeClasses class = p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class; + return ((class != UTC_Land) || (! tile->vtable->m35_Check_Is_Water (tile))) && + Unit_can_perform_command (this, __, unit_command_value); + } + + return Unit_can_perform_command (this, __, unit_command_value); +} + +void __fastcall +patch_Unit_join_city (Unit * this, int edx, City * city) +{ + if (is->current_config.enable_districts && is_worker (this)) { + int civ_id = this->Body.CivID; + bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; + if (! is_human) { + struct district_worker_record * rec = get_tracked_worker_record (this); + if ((rec != NULL) && (rec->pending_req != NULL)) { + ai_move_district_worker (this, rec); + return; + } + + Tile * worker_tile = tile_at (this->Body.X, this->Body.Y); + if ((worker_tile != NULL) && (worker_tile != p_null_tile)) { + int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); + + if ((civ_id >= 0) && (civ_id < 32)) { + struct pending_district_request * same_city_req = NULL; + struct pending_district_request * same_continent_req = NULL; + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req == NULL) || (req->assigned_worker_id >= 0)) + continue; + if ((req->civ_id != civ_id) || (req->city_id < 0)) + continue; + + City * req_city = get_city_ptr (req->city_id); + if (req_city == NULL) + continue; + + if (city != NULL && req_city->Body.ID == city->Body.ID) { + same_city_req = req; + break; + } + + Tile * req_city_tile = tile_at (req_city->Body.X, req_city->Body.Y); + if ((req_city_tile != NULL) && (req_city_tile != p_null_tile)) { + int req_continent_id = req_city_tile->vtable->m46_Get_ContinentID (req_city_tile); + if (req_continent_id == worker_continent_id) { + same_continent_req = req; + } + } + } + + struct pending_district_request * chosen_req = (same_city_req != NULL) ? same_city_req : same_continent_req; + if (chosen_req != NULL) { + City * req_city = get_city_ptr (chosen_req->city_id); + if (req_city != NULL) { + int target_x = 0; + int target_y = 0; + Tile * target_tile = find_tile_for_district (req_city, chosen_req->district_id, &target_x, &target_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); + assign_worker_to_district (chosen_req, this, req_city, chosen_req->district_id, target_x, target_y); + return; + } + } + } + } + } + } + } + + Unit_join_city (this, __, city); +} + +bool __fastcall +patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y) +{ + bool base = Unit_can_pillage (this, __, tile_x, tile_y); + + if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return base; + + int district_id = inst->district_id; + if (is->current_config.enable_natural_wonders && + (district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) + return false; + + if (! district_is_complete (tile, district_id)) + return true; + + if (district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info == NULL || info->state != WDS_COMPLETED) + return true; + return is->current_config.completed_wonder_districts_can_be_destroyed; + } + + return true; +} + +bool __fastcall +patch_Unit_can_do_worker_command_for_button_setup (Unit * this, int edx, int unit_command_value) +{ + bool base = patch_Unit_can_perform_command (this, __, unit_command_value); + + // If the command is to build a city and it can't be done because another city is already too close, and the minimum separation was changed + // from its standard value, then return true here so that the build city button will be added anyway. We'll gray it out later. Check that the + // grayed out button image is initialized now so we don't activate the build city button then find out later we can't gray it out. + if ((! base) && + (unit_command_value == UCV_Build_City) && + (is->current_config.minimum_city_separation > 1) && + (patch_Map_check_city_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID, false) == CLV_CITY_TOO_CLOSE) && + (init_disabled_command_buttons (), is->disabled_command_img_state == IS_OK)) + return true; + + else + return base; +} + +int +compare_helpers (void const * vp_a, void const * vp_b) +{ + Unit * a = get_unit_ptr (*(int *)vp_a), + * b = get_unit_ptr (*(int *)vp_b); + if ((a != NULL) && (b != NULL)) { + // Compute how many movement points each has left (ML = moves left) + int ml_a = patch_Unit_get_max_move_points (a) - a->Body.Moves, + ml_b = patch_Unit_get_max_move_points (b) - b->Body.Moves; + + // Whichever one has more MP left comes first in the array + if (ml_a > ml_b) return 1; + else if (ml_b > ml_a) return -1; + else return 0; + } else + // If at least one of the unit ids is invalid, might as well sort it later in the array + return (a != NULL) ? -1 : ((b != NULL) ? 1 : 0); +} + +void +issue_stack_worker_command (Unit * unit, int command) +{ + int tile_x = unit->Body.X; + int tile_y = unit->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + int unit_type_id = unit->Body.UnitTypeID; + int unit_id = unit->Body.ID; + + // Put together a list of helpers and store it on the memo. Helpers are just other workers on the same tile that can be issued the same command. + clear_memo (); + FOR_UNITS_ON (uti, tile) + if ((uti.id != unit_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) { + // check if the clicked command is among worker actions that this unit type can perform + int actions = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Worker_Actions; + int command_without_category = command & 0x0FFFFFFF; + if ((actions & command_without_category) == command_without_category) + memoize (uti.id); + } + + // Sort the list of helpers so that the ones with the fewest remaining movement points are listed first. + qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_helpers); + + Unit * next_up = unit; + int i_next_helper = 0; + int last_action_didnt_happen; + do { + int state_before_action = next_up->Body.UnitState; + Main_Screen_Form_issue_command (p_main_screen_form, __, command, next_up); + last_action_didnt_happen = (next_up->Body.UnitState == state_before_action); + + // Call this update function to cause the worker to actually perform the action. Otherwise + // it only gets queued, the worker keeps is movement points, and the action doesn't get done + // until the interturn. + if (! last_action_didnt_happen) + next_up->vtable->update_while_active (next_up); + + next_up = NULL; + while ((i_next_helper < is->memo_len) && (next_up == NULL)) + next_up = get_unit_ptr (is->memo[i_next_helper++]); + } while ((next_up != NULL) && (! last_action_didnt_happen)); +} + +void +issue_district_worker_command (Unit * unit, int command) +{ + if (! is->current_config.enable_districts) + return; + + if (unit == NULL) + return; + + int tile_x = unit->Body.X; + int tile_y = unit->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return; + + if (! is_worker(unit)) + return; + + int district_id = -1; + if (! itable_look_up (&is->command_id_to_district_id, command, &district_id)) + return; + if ((district_id < 0) || (district_id >= is->district_count)) + return; + + if (! leader_can_build_district (&leaders[unit->Body.CivID], district_id)) + return; + + // Disallow placing districts on invalid terrain, pollution, or cratered tiles + if (tile->vtable->m21_Check_Crates (tile, __, 0)) + return; + if (tile->vtable->m20_Check_Pollution (tile, __, 0)) + return; + + if (! district_is_buildable_on_tile (&is->district_configs[district_id], tile)) + return; + + // If District will be replaced by another District + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete(tile, inst->district_id)) { + int existing_district_id = inst->district_id; + int inst_x, inst_y; + if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) + return; + + int civ_id = unit->Body.CivID; + bool redundant_district = district_instance_is_redundant (inst, tile); + bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, inst_x, inst_y); + if (redundant_district) + would_lose_buildings = false; + + bool remove_existing = false; + + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char*)is->district_configs[existing_district_id].display_name, -1, -1); + set_popup_str_param (1, (char*)is->district_configs[existing_district_id].display_name, -1, -1); + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + would_lose_buildings + ? "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT" + : "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT_SAFE", + -1, 0, 0, 0 + ); + + int sel = patch_show_popup (popup, __, 0, 0); + if (sel == 0) + remove_existing = true; + else + return; + + if (remove_existing) { + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); + handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); + } + } + + // If District will replace an improvement + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); + + if (removable_flags != 0) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_BUILD_DISTRICT_OVER_IMPROVEMENT", -1, 0, 0, 0); + int sel = patch_show_popup (popup, __, 0, 0); + if (sel != 0) + return; + } + + if (removable_flags != 0) + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + + inst = ensure_district_instance (tile, district_id, tile_x, tile_y); + inst->built_by_civ_id = unit->Body.CivID; + if (inst != NULL) + inst->state = DS_UNDER_CONSTRUCTION; + + Unit_set_state (unit, __, UnitState_Build_Mines); + unit->Body.Job_ID = WJ_Build_Mines; +} + +void +issue_stack_unit_mgmt_command (Unit * unit, int command) +{ + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + int unit_type_id = unit->Body.UnitTypeID; + int unit_id = unit->Body.ID; + + PopupForm * popup = get_popup_form (); + + clear_memo (); + + if (command == UCV_Fortify) { + // This probably won't work for online games since "fortify all" does additional work in that case. See Main_Screen_Form::fortify_all. + // I don't like how this method doesn't place units in the fortified pose. One workaround is so use + // Main_Screen_Form::issue_fortify_command, but that plays the entire fortify animation for each unit which is a major annoyance for + // large stacks. The base game's "fortify all" function also doesn't set the pose so I don't see any easy way to fix this. + FOR_UNITS_ON (uti, tile) + if ((uti.unit->Body.UnitTypeID == unit_type_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + (uti.unit->Body.CivID == unit->Body.CivID) && + (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) + Unit_set_state (uti.unit, __, UnitState_Fortifying); + + } else if (command == UCV_Upgrade_Unit) { + int our_treasury = leaders[unit->Body.CivID].Gold_Encoded + leaders[unit->Body.CivID].Gold_Decrement; + + // If the unit type we're upgrading to is limited, find out how many we can add. Keep that in "available". If the type is not limited, + // leave available set to INT_MAX. + int available = INT_MAX; { + City * city; + int upgrade_id; + if ((is->current_config.unit_limits.len > 0) && + patch_Unit_can_perform_command (unit, __, UCV_Upgrade_Unit) && + (NULL != (city = city_at (unit->Body.X, unit->Body.Y))) && + (0 < (upgrade_id = City_get_upgraded_type_id (city, __, unit_type_id)))) + get_available_unit_count (&leaders[unit->Body.CivID], upgrade_id, &available); + } + + int cost = 0; + FOR_UNITS_ON (uti, tile) + if ((available > 0) && + (uti.unit->Body.UnitTypeID == unit_type_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + patch_Unit_can_perform_command (uti.unit, __, UCV_Upgrade_Unit)) { + cost += Unit_get_upgrade_cost (uti.unit); + available--; + memoize (uti.id); + } + + if (cost <= our_treasury) { + set_popup_str_param (0, p_bic_data->UnitTypes[unit_type_id].Name, -1, -1); + set_popup_int_param (0, is->memo_len); + set_popup_int_param (1, cost); + popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "UPGRADE_ALL", -1, 0, 0, 0); + if (patch_show_popup (popup, __, 0, 0) == 0) + for (int n = 0; n < is->memo_len; n++) { + Unit * to_upgrade = get_unit_ptr (is->memo[n]); + if (to_upgrade != NULL) + Unit_upgrade (to_upgrade, __, false); + } + + } else { + set_popup_int_param (0, cost); + int param_5 = is_online_game () ? 0x4000 : 0; // As in base code + popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "NO_GOLD_TO_UPGRADE_ALL", -1, 0, param_5, 0); + patch_show_popup (popup, __, 0, 0); + } + + } else if (command == UCV_Disband) { + FOR_UNITS_ON (uti, tile) + if ((uti.unit->Body.UnitTypeID == unit_type_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) + memoize (uti.id); + + if (is->memo_len > 0) { + set_popup_int_param (0, is->memo_len); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_STACK_DISBAND", -1, 0, 0, 0); + if (patch_show_popup (popup, __, 0, 0) == 0) { + for (int n = 0; n < is->memo_len; n++) { + Unit * to_disband = get_unit_ptr (is->memo[n]); + if (to_disband) + Unit_disband (to_disband); + } + } + } + } +} + +void __fastcall +patch_Main_GUI_handle_button_press (Main_GUI * this, int edx, int button_id) +{ + // Set SB flag according to case (2) + if (button_id < 42) { + if ((is->sc_img_state == IS_OK) && + ((this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMBARD].imgs[0]) || + (this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMB ].imgs[0]))) + is->sb_activated_by_button = 1; + else + is->sb_activated_by_button = 0; + } + + int command = this->Unit_Command_Buttons[button_id].Command; + + // Clear any highlighted tiles + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + + if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { + is->city_loc_display_perspective = -1; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw + } + + // If a district, run district build logic + if (is->current_config.enable_districts && is_district_command (command)) { + clear_something_1 (); + Timer_clear (&this->timer_1); + issue_district_worker_command (p_main_screen_form->Current_Unit, command); + return; + } + + // Check if command is a worker build command (not a district) and a district exists on the tile + if (is->current_config.enable_districts && p_main_screen_form->Current_Unit != NULL) { + + bool removed_existing = false; + if (! handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) + return; + if (removed_existing) { + clear_something_1 (); + Timer_clear (&this->timer_1); + Main_GUI_handle_button_press (this, __, button_id); + return; + } + } + + struct sc_button_info const * stack_button_info; { + stack_button_info = NULL; + if (button_id < 42) // If button pressed was a unit command button + for (int n = 0; n < COUNT_STACKABLE_COMMANDS; n++) + if (command == sc_button_infos[n].command) { + stack_button_info = &sc_button_infos[n]; + break; + } + } + + if ((stack_button_info == NULL) || // If there's no stack command for the pressed button OR + (! is->current_config.enable_stack_unit_commands) || // stack unit commands are not enabled OR + (((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // CTRL key is not down OR + (p_main_screen_form->Current_Unit == NULL) || // no unit is selected OR + is_online_game ()) { // is online game + Main_GUI_handle_button_press (this, __, button_id); + return; + } + + enum stackable_command_kind kind = stack_button_info->kind; + if ((kind == SCK_TERRAFORM) || (kind == SCK_UNIT_MGMT)) { + // Replicate behavior of function we're replacing + clear_something_1 (); + Timer_clear (&this->timer_1); + + if (kind == SCK_TERRAFORM) + issue_stack_worker_command (p_main_screen_form->Current_Unit, stack_button_info->command); + else if (kind == SCK_UNIT_MGMT) + issue_stack_unit_mgmt_command (p_main_screen_form->Current_Unit, stack_button_info->command); + } else + Main_GUI_handle_button_press (this, __, button_id); +} + +bool __fastcall +patch_Main_Screen_Form_issue_command (Main_Screen_Form * this, int edx, int command, Unit * unit) +{ + Unit * target_unit = unit; + if (target_unit == NULL) + target_unit = this->Current_Unit; + + if (is->current_config.enable_districts) { + bool removed_existing = false; + if (! handle_worker_command_that_may_replace_district (target_unit, command, &removed_existing)) + return false; + } + + return Main_Screen_Form_issue_command (this, __, command, unit); +} + +bool +is_command_button_active (Main_GUI * main_gui, enum Unit_Command_Values command) +{ + Command_Button * buttons = main_gui->Unit_Command_Buttons; + for (int n = 0; n < 42; n++) + if (((buttons[n].Button.Base_Data.Status2 & 1) != 0) && (buttons[n].Command == command)) + return true; + return false; +} + +int __fastcall +patch_Main_Screen_Form_handle_key_down (Main_Screen_Form * this, int edx, int char_code, int virtual_key_code) +{ + // Set SB flag according to case (4) + int precision_strike_is_available = is_command_button_active (&this->GUI, UCV_Precision_Bombing); + if ((virtual_key_code == VK_B) || (precision_strike_is_available && (virtual_key_code == VK_P))) + is->sb_activated_by_button = 0; + + if ((virtual_key_code & 0xFF) == VK_CONTROL) { + set_up_stack_worker_buttons (&this->GUI); + + if (is->current_config.enable_city_work_radii_highlights && + ! is->highlight_city_radii) { + Unit * unit = p_main_screen_form->Current_Unit; + if (unit != NULL) { + is->highlight_city_radii = true; + compute_highlighted_worker_tiles_for_districts (); + this->vtable->m73_call_m22_Draw ((Base_Form *)this); + } + } + } else { + if (is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + } + + char original_turn_end_flag = this->turn_end_flag; + int tr = Main_Screen_Form_handle_key_down (this, __, char_code, virtual_key_code); + if ((original_turn_end_flag == 1) && (this->turn_end_flag == 0)) + intercept_end_of_turn (); + + return tr; +} + +int +patch_handle_cursor_change_in_jgl () +{ + // Set SB flag according to case (3) and the annoying state + if ((is->sb_activated_by_button != 2) && + (p_main_screen_form->Mode_Action != UMA_Bombard) && + (p_main_screen_form->Mode_Action != UMA_Air_Bombard)) + is->sb_activated_by_button = 0; + + return handle_cursor_change_in_jgl (); +} + +void __fastcall +patch_Main_Screen_Form_handle_left_click_on_map_1 (Main_Screen_Form * this, int edx, int param_1, int param_2) +{ + if (is->sb_activated_by_button == 1) + is->sb_activated_by_button = 2; + Main_Screen_Form_handle_left_click_on_map_1 (this, __, param_1, param_2); + is->sb_activated_by_button = 0; +} + + +void __fastcall +patch_Main_GUI_handle_click_in_status_panel (Main_GUI * this, int edx, int mouse_x, int mouse_y) +{ + char original_turn_end_flag = p_main_screen_form->turn_end_flag; + Main_GUI_handle_click_in_status_panel (this, __, mouse_x, mouse_y); + if ((original_turn_end_flag == 1) && (p_main_screen_form->turn_end_flag == 0)) + intercept_end_of_turn (); +} + +// Gets effective shields generated per turn, including civil engineers, disorder, and anarchy. +int +get_city_production_rate (City * city, enum City_Order_Types order_type, int order_id) +{ + int in_disorder = city->Body.Status & CSF_Civil_Disorder, + in_anarchy = p_bic_data->Governments[leaders[city->Body.CivID].GovernmentType].b_Transition_Type, + getting_tile_shields = (! in_disorder) && (! in_anarchy); + + if (order_type == COT_Improvement) { + int building_wealth = (p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0; + int specialist_shields = 0; + FOR_CITIZENS_IN (ci, city) + if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) // I don't know what is check is for but it's done in the base code + specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; + return (getting_tile_shields ? city->Body.ProductionIncome : 0) + ((! building_wealth) ? specialist_shields : 0); + } else if ((order_type == COT_Unit) && getting_tile_shields) + return city->Body.ProductionIncome; + else + return 0; +} + +void __fastcall +patch_City_Form_open (City_Form * this, int edx, City * city, int param_2) +{ + recompute_resources_if_necessary (); + + WITH_PAUSE_FOR_POPUP { + City_Form_open (this, __, city, param_2); + } +} + +void +init_district_icons () +{ + if (is->dc_icons_img_state != IS_UNINITED) + return; + + char ss[200]; + snprintf (ss, sizeof ss, "[C3X] init_district_icons: state=%d\n", is->dc_icons_img_state); + (*p_OutputDebugStringA) (ss); + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("Districts/DistrictIncomeIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image == NULL) || + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { + (*p_OutputDebugStringA) ("[C3X] PCX file for district icons failed to load or is too small.\n"); + is->dc_icons_img_state = IS_INIT_FAILED; + goto cleanup; + } + + // Extract science icon (index 1) + Sprite_construct (&is->district_science_icon); + Sprite_slice_pcx (&is->district_science_icon, __, &pcx, 1 + 1*31, 1, 30, 30, 1, 1); + + // Extract commerce icon (index 2) + Sprite_construct (&is->district_commerce_icon); + Sprite_slice_pcx (&is->district_commerce_icon, __, &pcx, 1 + 2*31, 1, 30, 30, 1, 1); + + // Extract shield icon (index 4) + Sprite_construct (&is->district_shield_icon); + Sprite_slice_pcx (&is->district_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); + + // Extract corruption icon (index 5) + Sprite_construct (&is->district_corruption_icon); + Sprite_slice_pcx (&is->district_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); + + // Extract food icon (index 6) + Sprite_construct (&is->district_food_icon); + Sprite_slice_pcx (&is->district_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); + + // Extract food eaten icon (index 7) + Sprite_construct (&is->district_food_eaten_icon); + Sprite_slice_pcx (&is->district_food_eaten_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); + + // Extract small happiness icon (index 12) + Sprite_construct (&is->district_happiness_icon_small); + Sprite_slice_pcx (&is->district_happiness_icon_small, __, &pcx, 1 + 12*31, 1, 30, 30, 1, 1); + + // Extract small shield icon (index 13) + Sprite_construct (&is->district_shield_icon_small); + Sprite_slice_pcx (&is->district_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); + + // Extract small commerce icon (index 14) + Sprite_construct (&is->district_commerce_icon_small); + Sprite_slice_pcx (&is->district_commerce_icon_small, __, &pcx, 1 + 14*31, 1, 30, 30, 1, 1); + + // Extract small food icon (index 15: x = 1 + 15*31 = 466, width 30) + Sprite_construct (&is->district_food_icon_small); + Sprite_slice_pcx (&is->district_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); + + // Extract small science icon (index 16) + Sprite_construct (&is->district_science_icon_small); + Sprite_slice_pcx (&is->district_science_icon_small, __, &pcx, 1 + 16*31, 1, 30, 30, 1, 1); + + // Extract small culture icon (index 18) + Sprite_construct (&is->district_culture_icon_small); + Sprite_slice_pcx (&is->district_culture_icon_small, __, &pcx, 1 + 18*31, 1, 30, 30, 1, 1); + + // Load Negatives (mostly red) from here + + // Extract negative small commerce icon (index 17) + Sprite_construct (&is->district_negative_commerce_icon_small); + Sprite_slice_pcx (&is->district_negative_commerce_icon_small, __, &pcx, 1 + 17*31, 1, 30, 30, 1, 1); + + // Extract small unhappiness icon (index 19) + Sprite_construct (&is->district_unhappiness_icon_small); + Sprite_slice_pcx (&is->district_unhappiness_icon_small, __, &pcx, 1 + 19*31, 1, 30, 30, 1, 1); + + // Extract negative small shield icon (index 20) + Sprite_construct (&is->district_negative_shield_icon_small); + Sprite_slice_pcx (&is->district_negative_shield_icon_small, __, &pcx, 1 + 20*31, 1, 30, 30, 1, 1); + + // Extract negative small culture icon (index 21) + Sprite_construct (&is->district_negative_culture_icon_small); + Sprite_slice_pcx (&is->district_negative_culture_icon_small, __, &pcx, 1 + 21*31, 1, 30, 30, 1, 1); + + // Extract negative small culture icon (index 22) + Sprite_construct (&is->district_negative_food_icon_small); + Sprite_slice_pcx (&is->district_negative_food_icon_small, __, &pcx, 1 + 22*31, 1, 30, 30, 1, 1); + + // Extract negative small science icon (index 23) + Sprite_construct (&is->district_negative_science_icon_small); + Sprite_slice_pcx (&is->district_negative_science_icon_small, __, &pcx, 1 + 23*31, 1, 30, 30, 1, 1); + + is->dc_icons_img_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void __fastcall +patch_City_Form_draw (City_Form * this) +{ + // Recompute city form production rect location every time because the config might have changed. Doing it here is also easier than + // patching the constructor. + int form_top = (p_bic_data->ScreenHeight - this->Background_Image.Height) / 2; + this->Production_Storage_Indicator.top = form_top + 621 + (is->current_config.show_detailed_city_production_info ? 34 : 0); + + is->drawn_strat_resource_count = 0; + + // Make sure culture income (including from districts) is up to date before the draw event + if (is->current_config.enable_districts) + patch_City_recompute_culture_income(this->CurrentCity); + + City_Form_draw (this); + + if (is->current_config.show_detailed_city_production_info) { + City * city = this->CurrentCity; + int order_type = city->Body.Order_Type, + order_id = city->Body.Order_ID, + order_progress = City_get_order_progress (city), + order_cost = City_get_order_cost (city), + prod_rate = get_city_production_rate (city, order_type, order_id), + building_wealth = (order_type == COT_Improvement) && ((p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0); + + int turns_left, surplus; { + if (prod_rate > 0) { + turns_left = (order_cost - order_progress) / prod_rate; + if ((order_cost - order_progress) % prod_rate != 0) + turns_left++; + if (turns_left < 1) + turns_left = 1; + surplus = (turns_left * prod_rate) - (order_cost - order_progress); + } else { + turns_left = 9999; + surplus = 0; + } + } + + char line1[100]; { + if (prod_rate > 0) { + if (! building_wealth) + snprintf (line1, sizeof line1, "%s %d %s", this->Labels.To_Build, turns_left, (turns_left == 1) ? this->Labels.Single_Turn : this->Labels.Multiple_Turns); + else + snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_NEVER_COMPLETES]); + } else + snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_HALTED]); + line1[(sizeof line1) - 1] = '\0'; + } + + char line2[100]; { + if (! building_wealth) { + int percent_complete = order_cost > 0 ? ((10000 * order_progress) / order_cost + 50) / 100 : 100; + snprintf (line2, sizeof line2, "%d / %d (%d%s)", order_progress, order_cost, percent_complete, this->Labels.Percent); + } else + snprintf (line2, sizeof line2, "---"); + line2[(sizeof line2) - 1] = '\0'; + } + + char line3[100]; { + if ((! building_wealth) && (prod_rate > 0)) { + int s_per, s_rem; { + if (turns_left > 1) { + s_per = surplus / turns_left; + s_rem = surplus % turns_left; + } else { + s_per = surplus; + s_rem = 0; + } + } + char * s_lab = is->c3x_labels[CL_SURPLUS]; + if ((s_per != 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d + %d %s", s_lab, s_rem, s_per, this->Labels.Per_Turn); + else if ((s_per == 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d", s_lab, s_rem); + else if ((s_per != 0) && (s_rem == 0)) snprintf (line3, sizeof line3, "%s: %d %s", s_lab, s_per, this->Labels.Per_Turn); + else snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NONE]); + } else + snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NA]); + line3[(sizeof line3) - 1] = '\0'; + } + + Object_66C3FC * font = get_font (10, FSF_NONE); + int left = this->Production_Storage_Indicator.left, + top = this->Production_Storage_Indicator.top, + width = this->Production_Storage_Indicator.right - left; + PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line1, left, top - 42, width, strlen (line1)); + PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line2, left, top - 28, width, strlen (line2)); + PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line3, left, top - 14, width, strlen (line3)); + } + + // Draw district commerce bonuses (gold and science) + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + // Lazy load district icons + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + if (is->dc_icons_img_state != IS_OK) + return; + + City * city = this->CurrentCity; + if (city == NULL) + return; + + // Calculate district gold and science bonuses by iterating workable tiles + int district_gold = 0; + int city_civ_id = city->Body.CivID; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) continue; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + struct district_config const * cfg = &is->district_configs[district_id]; + int gold_bonus = 0; + get_effective_district_yields (inst, cfg, NULL, NULL, &gold_bonus, NULL, NULL, NULL); + district_gold += gold_bonus; + } + + Leader * leader = &leaders[city_civ_id]; + int gold_proportion = (district_gold * leader->gold_slider) / 10; + int science_proportion = (district_gold * leader->science_slider) / 10; + + // Draw district gold icons + if (gold_proportion > 0) { + Sprite * gold_sprite = &is->district_commerce_icon; + int sprite_width = gold_sprite->Width; + int sprite_height = gold_sprite->Height; + + struct tagRECT * gold_rect = &this->Gold_Income_Rect; + int total_gold = City_get_net_commerce (city, __, 2, true); + + // Calculate spacing + int spacing = sprite_width; + if ((total_gold > 1) && (total_gold * sprite_width != (gold_rect->right - gold_rect->left))) { + int rect_width = gold_rect->right - gold_rect->left; + if (rect_width <= total_gold * sprite_width) { + spacing = (rect_width - sprite_width) / (total_gold - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > sprite_width) + spacing = sprite_width; + } + } + + // Draw from right to left + int x_offset = 0; + int y_offset = 5; + for (int i = 0; i < gold_proportion && i < total_gold; i++) { + int x = gold_rect->right - x_offset - sprite_width; + int y = gold_rect->top + ((gold_rect->bottom - gold_rect->top >> 1) - + (sprite_height >> 1)) + y_offset; + + Sprite_draw (gold_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); + x_offset += spacing; + } + } + + // Draw district science icons + if (science_proportion > 0) { + Sprite * science_sprite = &is->district_commerce_icon; + int sprite_width = science_sprite->Width; + int sprite_height = science_sprite->Height; + + struct tagRECT * science_rect = &this->Science_Income_Rect; + int total_science = City_get_net_commerce (city, __, 1, true); + + // Calculate spacing + int spacing = sprite_width; + if ((total_science > 1) && (total_science * sprite_width != (science_rect->right - science_rect->left))) { + int rect_width = science_rect->right - science_rect->left; + if (rect_width <= total_science * sprite_width) { + spacing = (rect_width - sprite_width) / (total_science - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > sprite_width) + spacing = sprite_width; + } + } + + // Draw from right to left + int x_offset = 0; + int y_offset = 5; + for (int i = 0; i < science_proportion && i < total_science; i++) { + int x = science_rect->right - x_offset - sprite_width; + int y = science_rect->top + ((science_rect->bottom - science_rect->top >> 1) - + (sprite_height >> 1)) + y_offset; + + Sprite_draw (science_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); + x_offset += spacing; + } + } +} + +void __fastcall +patch_City_Form_print_production_info (City_Form *this, int edx, String256 * out_strs, int str_capacity) +{ + City_Form_print_production_info (this, __, out_strs, str_capacity); + if (is->current_config.show_detailed_city_production_info) + out_strs[1].S[0] = '\0'; +} + +int __fastcall +patch_Sprite_draw_strat_res_on_city_screen (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + if (is->current_config.compact_strategic_resource_display_on_city_screen) + pixel_x -= 13 * is->drawn_strat_resource_count + 17; + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +int __fastcall +patch_PCX_Image_do_draw_cntd_text_for_strat_res (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) +{ + if (is->current_config.compact_strategic_resource_display_on_city_screen) + x -= 13 * is->drawn_strat_resource_count + 17; + int tr = PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); + is->drawn_strat_resource_count++; + return tr; +} + +int __fastcall +patch_City_get_turns_to_build (City * this, int edx, enum City_Order_Types order_type, int order_id, bool param_3) +{ + // To fix the zero production crash, return 9999 when the city's total production rate is zero, avoiding a division by zero. That's only + // possible when producing an improvement due to negative shields from specialists. The original logic attempts to return 9999 in case of zero + // production but checks for that before including shields from specialists. + if (is->current_config.patch_zero_production_crash && (order_type == COT_Improvement)) { + + int specialist_shields = 0; + FOR_CITIZENS_IN (ci, this) + if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) + specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; + + // Return 9999 if the denominator in the base function's calculation would be zero. Note the base calc is incorrect in that it + // considers specialist shields to count toward Wealth, however we're not going to address that issue here, just stop the crash. + if (this->Body.ProductionIncome + specialist_shields <= 0) + return 9999; + } + + return City_get_turns_to_build (this, __, order_type, order_id, param_3); +} + +bool +is_below_stack_limit (Tile * tile, int civ_id, int type_id) +{ + enum UnitTypeClasses class = p_bic_data->UnitTypes[type_id].Unit_Class; + + int stack_limit = is->current_config.limit_units_per_tile[class]; + if (stack_limit <= 0) + return true; + + if (is->current_config.exclude_cities_from_units_per_tile_limit && + get_city_ptr (tile->CityID) != NULL) + return true; + + if (itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, type_id, 0)) + return true; + + FOR_UNITS_ON (uti, tile) { + // If there is a foreign unit on the tile then consider it as being below the stack limit. This ensures that the stack limit doesn't + // block combat between players. + if (uti.unit->Body.CivID != civ_id) + return true; + + int uti_type_id = uti.unit->Body.UnitTypeID; + if ((uti.unit->Body.Container_Unit < 0) && + (class == p_bic_data->UnitTypes[uti_type_id].Unit_Class) && + ! itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, uti_type_id, 0)) { + stack_limit -= 1; + if (stack_limit <= 0) + return false; + } + } + return true; +} + +// Returns the ID of the civ this move is trespassing against, or 0 if it's not trespassing. +int +check_trespassing (int civ_id, Tile * from, Tile * to) +{ + int from_territory_id = from->vtable->m38_Get_Territory_OwnerID (from), + to_territory_id = to ->vtable->m38_Get_Territory_OwnerID (to); + if ((civ_id > 0) && + (to_territory_id != civ_id) && + (to_territory_id > 0) && + (to_territory_id != from_territory_id) && + (! leaders[civ_id].At_War[to_territory_id]) && + ((leaders[civ_id].Relation_Treaties[to_territory_id] & 2) == 0)) // Check right of passage + return to_territory_id; + else + return 0; +} + +bool +is_allowed_to_trespass (Unit * unit) +{ + int type_id = unit->Body.UnitTypeID; + if ((type_id >= 0) && (type_id < p_bic_data->UnitTypeCount)) { + UnitType * type = &p_bic_data->UnitTypes[type_id]; + return UnitType_has_ability (type, __, UTA_Hidden_Nationality) || UnitType_has_ability (type, __, UTA_Invisible); + } else + return false; +} + +bool +get_tile_district_impassibility (Tile * tile, bool * out_impassible, bool * out_impassible_to_wheeled) +{ + if (out_impassible != NULL) + *out_impassible = false; + if (out_impassible_to_wheeled != NULL) + *out_impassible_to_wheeled = false; + + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + if (! district_is_complete (tile, inst->district_id)) + return false; + + if (inst->district_id == NATURAL_WONDER_DISTRICT_ID) { + if (! is->current_config.enable_natural_wonders) + return false; + int natural_id = inst->natural_wonder_info.natural_wonder_id; + if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) + return false; + if (out_impassible != NULL) + *out_impassible = is->natural_wonder_configs[natural_id].impassible; + if (out_impassible_to_wheeled != NULL) + *out_impassible_to_wheeled = is->natural_wonder_configs[natural_id].impassible_to_wheeled; + return true; + } + + if (! is->current_config.enable_districts) + return false; + if ((inst->district_id < 0) || (inst->district_id >= is->district_count)) + return false; + + if (out_impassible != NULL) + *out_impassible = is->district_configs[inst->district_id].impassible; + if (out_impassible_to_wheeled != NULL) + *out_impassible_to_wheeled = is->district_configs[inst->district_id].impassible_to_wheeled; + return true; +} + +AdjacentMoveValidity __fastcall +patch_Unit_can_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, int param_2) +{ + AdjacentMoveValidity base_validity = Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2); + + if (is->current_config.enable_districts) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + Tile * dest = tile_at (nx, ny); + + // Let workers step onto coast tiles when the config flag is enabled (base logic treats this as an invalid sea move) + if (is->current_config.workers_can_enter_coast && is_worker (this) && + ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { + if ((dest != NULL) && + dest->vtable->m35_Check_Is_Water (dest) && + (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) + base_validity = AMV_OK; + } + + // Allow land units to enter bridge tiles + if (is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && + ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { + if ((dest != NULL) && (dest != p_null_tile)) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { + base_validity = AMV_OK; + } + } + } + + // Allow naval units to enter completed canal tiles + if (is->current_config.enable_canal_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && + ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { + if ((dest != NULL) && (dest != p_null_tile)) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { + base_validity = AMV_OK; + } + } + } + + if ((base_validity == AMV_OK) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { + if ((dest != NULL) && (dest != p_null_tile) && Tile_has_city (dest)) + return AMV_INVALID_SEA_MOVE; + } + } + + // Apply unit count per tile limit + int type_id = this->Body.UnitTypeID; + if ((base_validity == AMV_OK) && (is->current_config.limit_units_per_tile[p_bic_data->UnitTypes[type_id].Unit_Class] > 0)) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + if (! is_below_stack_limit (tile_at (nx, ny), this->Body.CivID, type_id)) + return AMV_CANNOT_PASS_BETWEEN; + } + + // Apply trespassing restriction + if (is->current_config.disallow_trespassing && (base_validity == AMV_OK)) { + Tile * from = tile_at (this->Body.X, this->Body.Y); + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + int trespasses_against_civ_id = check_trespassing (this->Body.CivID, from, tile_at (nx, ny)); + if ((trespasses_against_civ_id > 0) && (! is_allowed_to_trespass (this))) + // The tile might be occupied by a unit belonging to a civ other than the one that owns the territory (against whom we'd be + // trespassing). In this case we must forbid the move entirely since TRIGGERS_WAR will not stop it if we're at war with the + // occupying civ. This fixes a bug where units could trespass by attacking an enemy unit across a border. They would then get + // stuck halfway between tiles if they won. + return (trespasses_against_civ_id == get_tile_occupier_id (nx, ny, this->Body.CivID, false)) ? AMV_TRIGGERS_WAR : AMV_CANNOT_PASS_BETWEEN; + } + + return base_validity; +} + +bool +great_wall_blocks_civ (Tile * tile, int civ_id) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_great_wall_districts || + ! is->current_config.great_wall_districts_impassible_by_others) + return false; + + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (owner_id <= 0) + return false; + if (owner_id == civ_id) + return false; + if ((civ_id > 0) && ((leaders[civ_id].Relation_Treaties[owner_id] & 2) != 0)) // 2 = right of passage + return false; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID)) + return false; + + if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) + return false; + + if (district_is_obsolete_for_civ (GREAT_WALL_DISTRICT_ID, civ_id)) + return false; + + return true; +} + +int __fastcall +patch_Trade_Net_get_movement_cost (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned flags, int neighbor_index, Trade_Net_Distance_Info * dist_info) +{ + if (is->is_computing_city_connections && // if this call came while rebuilding the trade network AND + (is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL) && // Trade Net X is set up AND + (unit == NULL) && ((flags == 0x1009) || (flags == 0x9))) // this call can be accelerated by TNX + return is->get_move_cost_for_sea_trade (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags, neighbor_index, dist_info); + + int base_cost = Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, neighbor_index, dist_info); + + bool districts_enabled = is->current_config.enable_districts; + if (districts_enabled) { + Tile * to = tile_at (to_x, to_y); + bool to_valid = (to != NULL) && (to != p_null_tile); + struct district_instance * to_inst = NULL; + bool to_inst_complete = false; + if (to_valid) { + to_inst = get_district_instance (to); + if (to_inst != NULL) + to_inst_complete = district_is_complete (to, to_inst->district_id); + } + + if ((unit != NULL) && great_wall_blocks_civ (to, unit->Body.CivID)) + return -1; + if ((unit != NULL) && to_valid) { + bool impassible = false; + bool impassible_to_wheeled = false; + if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { + if (impassible) + return -1; + if (impassible_to_wheeled && Unit_has_ability (unit, __, UTA_Wheeled)) { + Tile * from = tile_at (from_x, from_y); + bool connected_by_road = (from != NULL) && (to != NULL) && + (from->vtable->m25_Check_Roads (from, __, 0) != 0) && + (to->vtable->m25_Check_Roads (to, __, 0) != 0); + if (! connected_by_road) + return -1; + } + } + } + + // Let the pathfinder consider coastal tiles reachable for workers when the config flag is on + if (is->current_config.workers_can_enter_coast && + (base_cost < 0) && (unit != NULL) && is_worker (unit) && + to_valid && + to->vtable->m35_Check_Is_Water (to) && + (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) + base_cost = Unit_get_max_move_points (unit); + + // Let the pathfinder consider bridge tiles reachable for land units + if (is->current_config.enable_bridge_districts && + (base_cost < 0) && (unit != NULL) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == BRIDGE_DISTRICT_ID)) + base_cost = Unit_get_max_move_points (unit); + + // Let the pathfinder consider canal tiles reachable for naval units + if (is->current_config.enable_canal_districts && + (base_cost < 0) && (unit != NULL) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == CANAL_DISTRICT_ID)) + base_cost = Unit_get_max_move_points (unit); + + // Treat roads/rails on bridge districts like land roads/rails for movement cost. + if ((unit != NULL) && + is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land)) { + Tile * from = tile_at (from_x, from_y); + if ((from != NULL) && (from != p_null_tile) && to_valid) { + struct district_instance * from_inst = get_district_instance (from); + bool from_bridge = (from_inst != NULL) && + (from_inst->district_id == BRIDGE_DISTRICT_ID) && + district_is_complete (from, from_inst->district_id); + bool to_bridge = (to_inst != NULL) && + to_inst_complete && + (to_inst->district_id == BRIDGE_DISTRICT_ID); + if (from_bridge || to_bridge) { + bool from_rail = from->vtable->m23_Check_Railroads (from, __, 0) != 0; + bool to_rail = to->vtable->m23_Check_Railroads (to, __, 0) != 0; + bool from_road = from->vtable->m25_Check_Roads (from, __, 0) != 0; + bool to_road = to->vtable->m25_Check_Roads (to, __, 0) != 0; + if (from_rail && to_rail) + base_cost = 0; + else if (from_road && to_road) + base_cost = 1; + } + } + } + + if ((unit != NULL) && + (base_cost >= 0) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && + to_valid && Tile_has_city (to)) + return -1; + } + + // Apply unit count per tile limit + if ((unit != NULL) && ! is_below_stack_limit (tile_at (to_x, to_y), unit->Body.CivID, unit->Body.UnitTypeID)) + return -1; + + // Apply trespassing restriction + if (is->current_config.disallow_trespassing && + check_trespassing (civ_id, tile_at (from_x, from_y), tile_at (to_x, to_y)) && + ((unit == NULL) || (! is_allowed_to_trespass (unit)))) + return -1; + + // Adjust movement cost to enforce limited railroad movement + if ((is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0)) { + if ((unit != NULL) && (base_cost == 0)) { // Railroad move + if (! is->current_config.limited_railroads_work_like_fast_roads) { // If Civ 4 style RR, scale cost by type's moves + int type_moves_available = patch_Unit_get_max_move_points (unit) / p_bic_data->General.RoadsMovementRate; + return type_moves_available * is->railroad_mp_cost_per_move; + } else + return is->railroad_mp_cost_per_move; + } else if (base_cost == 1) // Road move + return is->road_mp_cost; + } + + return base_cost; +} + +int __fastcall +patch_Trade_Net_set_unit_path (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) +{ + int tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); + + bool may_require_length_fix = (is->current_config.limit_railroad_movement > 0) && // if railroad movement is limited AND + (tr > 0) && (out_path_length_in_mp != NULL) && // path was found AND caller wants to know its length AND + (unit != NULL); // the path is for an actual unit + + // We might have to correct the path length returned by the base game's pathfinder. This occurs when railroad movement is limited and the + // unit's total MP exceeds what can be stored in a one-byte integer. The cause of the incorrect length is that the pathfinder internally + // stores the remaining moves at each node of the search in a single byte. This correction fixes the bug (reported several times) that ETAs + // shown in the interface are wrong. + if (may_require_length_fix && (patch_Unit_get_max_move_points (unit) > 255)) { // Need to recompute path length if unit's total MP can overflow a uint8 + + // First memoize the cost of taking each step along the path. This must be done separately because the pathfinder's internal data only + // lets us traverse the path backwards. + { + // Must pass cached "distance info" to Trade_Net::get_movement_cost. Trade_Net stores two sets of cached data, which one was + // used depends on the flags. I believe one is intended to be used for city trade connections and the other for unit movement. + Trade_Net_Distance_Info * dist_info = (flags & 1) ? this->Data2 : this->Data4; + + clear_memo (); + int x = to_x, y = to_y; + do { + // "flags & 1" again determines whether Data2 or Data4 was used. + enum direction dir = Trade_Net_get_direction_from_internal_map (this, __, x, y, flags & 1); + if (dir == DIR_ZERO) + break; + + int prev_x, prev_y; { + int dx, dy; + neighbor_index_to_diff (dir, &dx, &dy); + prev_x = x + dx; prev_y = y + dy; + wrap_tile_coords (&p_bic_data->Map, &prev_x, &prev_y); + } + + memoize (patch_Trade_Net_get_movement_cost (this, __, prev_x, prev_y, x, y, unit, civ_id, flags, reverse_dir (dir), dist_info)); + x = prev_x; y = prev_y; + } while (! ((x == from_x) && (y == from_y))); + } + + // Now walk the path forwards tracking how much MP the unit would spend. We must be aware that the unit can't spend more MP than it + // has. For example, if a unit with 1 move walks onto an unimproved mountain, that effectively costs only 1 move, not 3. + int mp_remaining = patch_Unit_get_max_move_points (unit) - unit->Body.Moves, + mp_spent = 0; + for (int n = is->memo_len - 1; n >= 0; n--) { + int cost = is->memo[n]; + if (cost < mp_remaining) { + mp_spent += cost; + mp_remaining -= cost; + } else { + mp_spent += mp_remaining; + mp_remaining = patch_Unit_get_max_move_points (unit); + } + } + *out_path_length_in_mp = mp_spent; + + // Also, if this is a move between adjacent tiles, make sure the path length doesn't exceed the unit's remaining MP. Otherwise, the game may + // erroneously show an ETA of >1 turn. + } else if (may_require_length_fix && are_tiles_adjacent (from_x, from_y, to_x, to_y)) + *out_path_length_in_mp = not_above (patch_Unit_get_max_move_points (unit) - unit->Body.Moves, *out_path_length_in_mp); + + return tr; +} + +int __fastcall +patch_Trade_Net_set_unit_path_to_find_sea_route (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) +{ + // Accelerate this call with TNX if possible + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { + bool route_exists = is->try_drawing_sea_trade_route (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags); + return route_exists ? 1 : 0; + } else + return Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); +} + +// Renames this leader and their civ based on their era. Era-specific names come from the config file. If this leader has a custom name set by the +// human player, this method does nothing. +void +apply_era_specific_names (Leader * leader) +{ + int leader_bit = 1 << leader->ID; + Race * race = &p_bic_data->Races[leader->RaceID]; + + struct replaceable_name { + char * base_name; + int * tracking_bits; + char * buf; + int buf_size; + } replaceable_names[] = { + {race->vtable->GetAdjectiveName (race), &is->aliased_civ_adjective_bits , leader->tribe_customization.civ_adjective , sizeof leader->tribe_customization.civ_adjective}, + {race->vtable->GetSingularName (race) , &is->aliased_civ_noun_bits , leader->tribe_customization.civ_noun , sizeof leader->tribe_customization.civ_noun}, + {race->vtable->GetCountryName (race) , &is->aliased_civ_formal_name_bits, leader->tribe_customization.civ_formal_name, sizeof leader->tribe_customization.civ_formal_name} + }; + + // Apply replacements to civ noun, adjective, and formal name + for (int n = 0; n < ARRAY_LEN (replaceable_names); n++) { + struct replaceable_name * repl = &replaceable_names[n]; + if ((*repl->tracking_bits & leader_bit) || (repl->buf[0] == '\0')) { + char * replacement = NULL; + if (leader->Era < ERA_ALIAS_LIST_CAPACITY) + // Search through the list of aliases in reverse order so that, if the same key was listed multiple times, the last + // appearance overrides the earlier ones. This is important b/c when configs are loaded, their aliases get appended to + // the list. + for (int k = is->current_config.count_civ_era_alias_lists - 1; k >= 0; k--) { + struct civ_era_alias_list * list = &is->current_config.civ_era_alias_lists[k]; + if (strcmp (list->key, repl->base_name) == 0) { + replacement = list->aliases[leader->Era]; + break; + } + } + if (replacement != NULL) { + strncpy (repl->buf, replacement, repl->buf_size); + repl->buf[repl->buf_size - 1] = '\0'; + *repl->tracking_bits |= leader_bit; + } else { + repl->buf[0] = '\0'; + *repl->tracking_bits &= ~leader_bit; + } + } + } + + // Apply replacement to leader name, gender, and title + if ((is->aliased_leader_name_bits & leader_bit) || (leader->tribe_customization.leader_name[0] == '\0')) { + char * base_name = race->vtable->GetLeaderName (race); + char * replacement_name = NULL; + char * replacement_title = NULL; + int replacement_gender; // Only used if replacement_name is + if (leader->Era < ERA_ALIAS_LIST_CAPACITY) + for (int k = is->current_config.count_leader_era_alias_lists - 1; k >= 0; k--) { + struct leader_era_alias_list * list = &is->current_config.leader_era_alias_lists[k]; + if (strcmp (list->key, base_name) == 0) { + replacement_name = list->aliases[leader->Era]; + replacement_title = list->titles[leader->Era]; + replacement_gender = (list->gender_bits >> leader->Era) & 1; + break; + } + } + if (replacement_name != NULL) { + TribeCustomization * tc = &leader->tribe_customization; + strncpy (tc->leader_name, replacement_name, sizeof tc->leader_name); + tc->leader_name[(sizeof tc->leader_name) - 1] = '\0'; + tc->leader_gender = replacement_gender; + is->aliased_leader_name_bits |= leader_bit; + + // If this replacement name has a special title and this player does not have a custom title set, replace the title. + if ((replacement_title != NULL) && ((is->aliased_leader_title_bits & leader_bit) || (tc->leader_title[0] == '\0'))) { + strncpy (tc->leader_title, replacement_title, sizeof tc->leader_title); + tc->leader_title[(sizeof tc->leader_title) - 1] = '\0'; + is->aliased_leader_title_bits |= leader_bit; + + // If the current name has no title and the player's title was previously replaced, undo the replacement. + } else if ((replacement_title == NULL) && (is->aliased_leader_title_bits & leader_bit)) { + leader->tribe_customization.leader_title[0] = '\0'; + is->aliased_leader_title_bits &= ~leader_bit; + } + } else { + leader->tribe_customization.leader_name[0] = '\0'; + // Don't need to clear custom leader gender since it's not used unless a custom name was set + is->aliased_leader_name_bits &= ~leader_bit; + + // Remove title replacement if present + if (is->aliased_leader_title_bits & leader_bit) { + leader->tribe_customization.leader_title[0] = '\0'; + is->aliased_leader_title_bits &= ~leader_bit; + } + } + } +} + +int __cdecl +patch_do_save_game (char const * file_path, char param_2, GUID * guid) +{ + // Do not save the modified road movement rate, if it was modified to limit railroad movement + int restore_rmr = (is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0); + int rmr; + if (restore_rmr) { + rmr = p_bic_data->General.RoadsMovementRate; + p_bic_data->General.RoadsMovementRate = is->saved_road_movement_rate; + } + + // Do not save the modified barb culture group ID + int restore_barb_culture_group = is->current_config.enable_city_capture_by_barbarians && (is->saved_barb_culture_group >= 0); + int barb_culture; + if (restore_barb_culture_group) { + barb_culture = p_bic_data->Races[leaders[0].RaceID].CultureGroupID; + p_bic_data->Races[leaders[0].RaceID].CultureGroupID = is->saved_barb_culture_group; + } + + // Do not save names that were replaced with era-specific versions + for (int n = 0; n < 32; n++) { + Leader * leader = &leaders[n]; + int leader_bit = 1 << leader->ID; + if (is->aliased_civ_noun_bits & leader_bit) leader->tribe_customization.civ_noun [0] = '\0'; + if (is->aliased_civ_adjective_bits & leader_bit) leader->tribe_customization.civ_adjective [0] = '\0'; + if (is->aliased_civ_formal_name_bits & leader_bit) leader->tribe_customization.civ_formal_name[0] = '\0'; + if (is->aliased_leader_name_bits & leader_bit) leader->tribe_customization.leader_name [0] = '\0'; + if (is->aliased_leader_title_bits & leader_bit) leader->tribe_customization.leader_title [0] = '\0'; + } + is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; + + // Do not save unit types with the charm bits cleared if they were cleared by convertion to PTW targeting. The special actions field must not + // include the top category bits that are part of the UCV_* enum + for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { + UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; + converted_type->Special_Actions |= (0x00FFFFFF & UCV_Charm_Bombard); + } + + int tr = do_save_game (file_path, param_2, guid); + + if (restore_rmr) + p_bic_data->General.RoadsMovementRate = rmr; + if (restore_barb_culture_group) + p_bic_data->Races[leaders[0].RaceID].CultureGroupID = barb_culture; + + // Reapply era aliases + for (int n = 0; n < 32; n++) + if (*p_player_bits & (1 << n)) + apply_era_specific_names (&leaders[n]); + + // Reclear charm bits on converted types + for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { + UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; + converted_type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); + } + + return tr; +} + +void +record_unit_type_alt_strategy (int type_id) +{ + int ai_strat_index; { + int ai_strat_bits = p_bic_data->UnitTypes[type_id].AI_Strategy; + if ((ai_strat_bits & ai_strat_bits - 1) != 0) // Sanity check: must only have one strat (one bit) set + return; + ai_strat_index = 0; + while ((ai_strat_bits & 1) == 0) { + ai_strat_index++; + ai_strat_bits >>= 1; + } + } + + itable_insert (&is->unit_type_alt_strategies, type_id, ai_strat_index); +} + +void +append_improv_id_to_list (struct improv_id_list * list, int id) +{ + reserve (sizeof list->items[0], (void **)&list->items, &list->capacity, list->count); + list->items[list->count] = id; + list->count += 1; +} + +unsigned __fastcall +patch_load_scenario (BIC * this, int edx, char * param_1, unsigned * param_2) +{ + int ret_addr = ((int *)¶m_1)[-1]; + + // Destroy TNX cache from previous map. A new one will be created when needed. + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { + is->destroy_tnx_cache (is->tnx_cache); + is->tnx_cache = NULL; + } + + unsigned tr = load_scenario (this, __, param_1, param_2); + char * scenario_path = param_1; + + // There are two cases when load_scenario is called that we don't want to run our own code. These are (1) when the scenario is loaded to + // generate a preview (map, etc.) for the "Civ Content" or "Conquests" menu and (2) when the function is called recursively. The recursive + // call is done, I believe, only when loading saves using the default rules. The game first tries to load custom rules then falls back on + // loading the default rules. In any case, we want to ignore that call so we don't run the same code twice. + if ((ret_addr == ADDR_LOAD_SCENARIO_PREVIEW_RETURN) || (ret_addr == ADDR_LOAD_SCENARIO_RESUME_SAVE_2_RETURN)) + return tr; + + reset_to_base_config (); + load_config ("default.c3x_config.ini", 1); + char * scenario_config_file_name = "scenario.c3x_config.ini"; + char * scenario_config_path = BIC_get_asset_path (p_bic_data, __, scenario_config_file_name, false); + + // BIC_get_asset_path returns the file name when it can't find the file + if (0 != strcmp (scenario_config_file_name, scenario_config_path)) { + load_config (scenario_config_path, 0); + } + load_config ("custom.c3x_config.ini", 1); + apply_machine_code_edits (&is->current_config, false); + + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + reset_district_state (true); + load_districts_config (); + } + + // Initialize Trade Net X + if (is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_UNINITED)) { + char path[MAX_PATH]; + snprintf (path, sizeof path, "%s\\Trade Net X\\TradeNetX.dll", is->mod_rel_dir); + path[(sizeof path) - 1] = '\0'; + is->trade_net_x = LoadLibraryA (path); + if (is->trade_net_x != NULL) { + is->set_exe_version = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_exe_version"); + is->create_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "create_tnx_cache"); + is->destroy_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "destroy_tnx_cache"); + is->set_up_before_building_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_up_before_building_network"); + is->get_move_cost_for_sea_trade = (void *)(*p_GetProcAddress) (is->trade_net_x, "get_move_cost_for_sea_trade"); + is->flood_fill_road_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "flood_fill_road_network"); + is->try_drawing_sea_trade_route = (void *)(*p_GetProcAddress) (is->trade_net_x, "try_drawing_sea_trade_route"); + + is->set_exe_version (exe_version_index); + + // Run tests + if (0) { + int (__stdcall * test) () = (void *)(*p_GetProcAddress) (is->trade_net_x, "test"); + int failed_test_count = test (); + if (failed_test_count > 0) + MessageBoxA (NULL, "Failed some tests in Trade Net X!", NULL, MB_ICONWARNING); + else + MessageBoxA (NULL, "All tests in Trade Net X passed.", "Success", MB_ICONINFORMATION); + } + + is->tnx_init_state = IS_OK; + } else { + MessageBoxA (NULL, "Failed to load Trade Net X!", NULL, MB_ICONERROR); + is->tnx_init_state = IS_INIT_FAILED; + } + + // Deinitialize Trade Net X + } else if ((! is->current_config.enable_trade_net_x) && (is->tnx_init_state == IS_OK)) { + FreeLibrary (is->trade_net_x); + is->trade_net_x = NULL; + is->tnx_init_state = IS_UNINITED; + } + + // This scenario might use different mod art assets than the old one + deinit_stackable_command_buttons (); + deinit_disabled_command_buttons (); + deinit_trade_scroll_buttons (); + deinit_unit_rcm_icons (); + deinit_red_food_icon (); + deinit_large_minimap_frame (); + if (is->tile_already_worked_zoomed_out_sprite_init_state != IS_UNINITED) { + enum init_state * state = &is->tile_already_worked_zoomed_out_sprite_init_state; + if (*state == IS_OK) { + Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; + sprite->vtable->destruct (sprite, __, 0); + } + *state = IS_UNINITED; + } + + // Need to clear this since the resource count might have changed + if (is->extra_available_resources != NULL) { + free (is->extra_available_resources); + is->extra_available_resources = NULL; + is->extra_available_resources_capacity = 0; + } + + // Similarly, these don't carry over between games + for (int n = 0; n < 32; n++) + is->interceptor_reset_lists[n].count = 0; + is->replay_for_players = 0; + table_deinit (&is->extra_defensive_bombards); + table_deinit (&is->airdrops_this_turn); + table_deinit (&is->unit_transport_ties); + is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; + is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; + is->last_selected_unit.ptr = NULL; + table_deinit (&is->waiting_units); + is->have_loaded_waiting_units = false; + + // Clear extra city improvement bits + FOR_TABLE_ENTRIES (tei, &is->extra_city_improvs) + free ((void *)tei.value); + table_deinit (&is->extra_city_improvs); + + // Clear unit type counts + for (int n = 0; n < 32; n++) + table_deinit (&is->unit_type_counts[n]); + is->unit_type_count_init_bits = 0; + + // Clear last city founding turn numbers + for (int n = 0; n < 32; n++) + is->turn_no_of_last_founding_for_settler_perfume[n] = -1; + + // Load resources.pcx + { + PCX_Image * rs = is->resources_sheet; + if (rs != NULL) + rs->vtable->destruct (rs, __, 0); + else + rs = malloc (sizeof *rs); + memset (rs, 0, sizeof *rs); + PCX_Image_construct (rs); + + char * resources_pcx_path = BIC_get_asset_path (p_bic_data, __, "Art\\resources.pcx", true); + PCX_Image_read_file (rs, __, resources_pcx_path, NULL, 0, 0x100, 2); + is->resources_sheet = rs; + } + + // Recreate table of alt strategies mapping duplicates to their strategies + table_deinit (&is->unit_type_alt_strategies); + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; + if (alt_for_id >= 0) { + record_unit_type_alt_strategy (n); + record_unit_type_alt_strategy (alt_for_id); // Record the original too so we know it has alternatives + } + } + + // Recreate table of duplicates mapping unit types to the next duplicate + table_deinit (&is->unit_type_duplicates); + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; + if (alt_for_id >= 0) { + + // Find the type ID of the last duplicate in the list. alt_for_id refers to the original unit that was duplicated possibly + // multiple times. Begin searching there and, each time we find another duplicate, use its ID to continue the search. When + // we're done last_dup_id will be set to whichever ID in the list of duplicates is not already associated with another. + int last_dup_id = alt_for_id; { + int next; + while (itable_look_up (&is->unit_type_duplicates, last_dup_id, &next)) + last_dup_id = next; + } + + // Add this unit type to the end of the list of duplicates + itable_insert (&is->unit_type_duplicates, last_dup_id, n); + } + } + + // Convert charm-flagged units to using PTW targeting if necessary + if (is->current_config.charm_flag_triggers_ptw_like_targeting) { + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if (type->Special_Actions & UCV_Charm_Bombard) { + // Also add it to the list of converted types + reserve (sizeof is->charmed_types_converted_to_ptw_arty[0], // item size + (void **)&is->charmed_types_converted_to_ptw_arty, // ptr to items + &is->charmed_types_converted_to_ptw_arty_capacity, // ptr to capacity + is->count_charmed_types_converted_to_ptw_arty); // count + is->charmed_types_converted_to_ptw_arty[is->count_charmed_types_converted_to_ptw_arty] = n; + is->count_charmed_types_converted_to_ptw_arty += 1; + + // Add this type ID to the table + itable_insert (&is->current_config.ptw_arty_types, n, 1); + + // Clear the charm flag, taking care not to clear the category bit. This is necessary for the PTW targeting to work + // since the logic to implement it only applies to the non-charm code path. It wouldn't make sense to have both charm + // attack and PTW targeting anyway, since charm attack already works that way vs cities. + type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); + } + } + } + + // Pick out which resources are used as mill inputs + if (is->mill_input_resource_bits) + free (is->mill_input_resource_bits); + is->mill_input_resource_bits = calloc (1, 1 + p_bic_data->ResourceTypeCount / 8); + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + for (int k = 0; k < 2; k++) { + int resource_id = (&p_bic_data->Improvements[mill->improv_id].Resource1ID)[k]; + if ((resource_id >= 0) && (resource_id < p_bic_data->ResourceTypeCount)) { + byte bit = 1 << (resource_id & 7); + is->mill_input_resource_bits[resource_id>>3] |= bit; + } + } + } + + // Recreate lists of water & air trade improvements + is->water_trade_improvs .count = 0; + is->air_trade_improvs .count = 0; + is->combat_defense_improvs.count = 0; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + enum ImprovementTypeFlags flags = p_bic_data->Improvements[n].ImprovementFlags; + if (flags & ITF_Allows_Water_Trade) append_improv_id_to_list (&is->water_trade_improvs , n); + if (flags & ITF_Allows_Air_Trade) append_improv_id_to_list (&is->air_trade_improvs , n); + if (p_bic_data->Improvements[n].Combat_Defence != 0) append_improv_id_to_list (&is->combat_defense_improvs, n); + } + + // Set up for limiting railroad movement + if (is->current_config.limit_railroad_movement > 0) { + // Bit 0x200 of field_484 indicates whether or not the last call to load_scenario loaded the General section of the BIQ. The game will + // skip loading of that section and many others when loading a game with the same standard scenario as the then-current one, common + // when loading an autosave. + bool loaded_general = (this->field_848 & 0x200) != 0; + + // For the base RMR, use the saved rate if it's valid and we haven't loaded a new rate as part of the General section. Otherwise, use + // the rate from that section. + int base_rmr = (loaded_general || is->saved_road_movement_rate <= 0) ? p_bic_data->General.RoadsMovementRate : is->saved_road_movement_rate; + + int g = gcd (base_rmr, is->current_config.limit_railroad_movement); // Scale down all MP costs by this common divisor to help against + // overflow of 8-bit integers inside the pathfinder. + is->saved_road_movement_rate = base_rmr; + p_bic_data->General.RoadsMovementRate = base_rmr * is->current_config.limit_railroad_movement / g; // Full move in MP + is->road_mp_cost = is->current_config.limit_railroad_movement / g; + is->railroad_mp_cost_per_move = base_rmr / g; + } else { + is->saved_road_movement_rate = -1; + is->road_mp_cost = 1; + is->railroad_mp_cost_per_move = 0; + } + + // If barb city capturing is enabled and the barbs have the non-existent "none" culture group (index -1), switch them to the first real + // culture group. The "none" group produces corrupt graphics and crashes. + int * barb_culture_group = &p_bic_data->Races[leaders[0].RaceID].CultureGroupID; + if (is->current_config.enable_city_capture_by_barbarians && (*barb_culture_group < 0)) { + is->saved_barb_culture_group = *barb_culture_group; + *barb_culture_group = 0; + } else + is->saved_barb_culture_group = -1; + + // Clear old alias bits + is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; + + // Apply no AI patrol override + if (is->current_config.override_no_ai_patrol == NAPO_ZERO) + *p_allow_ai_patrol = true; + else if (is->current_config.override_no_ai_patrol == NAPO_ONE) + *p_allow_ai_patrol = false; + else if (is->current_config.override_no_ai_patrol == NAPO_NONE) + *p_allow_ai_patrol = 0 == get_int_from_conquests_ini ("NoAIPatrol", 1, 0); + + // Clear day/night cycle vars and deindex sprite proxies, if necessary. + if (is->current_config.day_night_cycle_mode != DNCM_OFF) { + is->day_night_cycle_unstarted = true; + is->current_day_night_cycle = 12; + if (is->day_night_cycle_img_proxies_indexed) { + deindex_day_night_image_proxies (); + } + } + + return tr; +} + +void __fastcall +patch_Leader_recompute_auto_improvements (Leader * this) +{ + is->leader_param_for_patch_get_wonder_city_id = this; + Leader_recompute_auto_improvements (this); +} + +int __fastcall +patch_Game_get_wonder_city_id (Game * this, int edx, int wonder_improvement_id) +{ + int ret_addr = ((int *)&wonder_improvement_id)[-1]; + if ((is->current_config.enable_free_buildings_from_small_wonders) && (ret_addr == ADDR_SMALL_WONDER_FREE_IMPROVS_RETURN)) { + Leader * leader = is->leader_param_for_patch_get_wonder_city_id; + Improvement * improv = &p_bic_data->Improvements[wonder_improvement_id]; + if ((improv->Characteristics & ITC_Small_Wonder) != 0) { + // Need to check if Small_Wonders array is NULL b/c recompute_auto_improvements gets called with leaders that are absent/dead. + return (leader->Small_Wonders != NULL) ? leader->Small_Wonders[wonder_improvement_id] : -1; + } + } + return Game_get_wonder_city_id (this, __, wonder_improvement_id); +} + +int __fastcall +patch_Main_Screen_Form_handle_key_up (Main_Screen_Form * this, int edx, int virtual_key_code) +{ + if ((virtual_key_code & 0xFF) == VK_CONTROL) { + patch_Main_GUI_set_up_unit_command_buttons (&this->GUI); + + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + } + + return Main_Screen_Form_handle_key_up (this, __, virtual_key_code); +} + +char __fastcall +patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing) +{ + char tr; + bool is_ai = ((*p_human_player_bits & (1 << this->ID)) == 0); + bool skip_replacement_logic = + (p_main_screen_form->Player_CivID == this->ID) && is->current_config.skip_repeated_tile_improv_replacement_asks; + + Tile * tile = tile_at (tile_x, tile_y); + + // If districts on, short-circuit any potential AI workers accidentally building in another civ's territory. + if (is->current_config.enable_districts && is_ai && (tile != NULL) && (tile != p_null_tile)) { + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (territory_owner > 0 && territory_owner != this->ID) + return 0; + } + + // Check if AI is trying to change a district tile (before calling vanilla logic) + if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && + is_ai) { + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { + int district_id = inst->district_id; + bool allow_ai_change = false; + + // Allow AI to modify obsolete districts + if (district_is_obsolete_for_civ (district_id, this->ID)) + allow_ai_change = true; + + // Allow if district could be used as a prerequisite for other buildable districts + if (! allow_ai_change) { + for (int other_id = 0; other_id < is->district_count; other_id++) { + if (other_id == district_id) + continue; + struct district_config const * other_cfg = &is->district_configs[other_id]; + if (! other_cfg->has_buildable_on_districts) + continue; + for (int i = 0; i < other_cfg->buildable_on_district_id_count; i++) { + if (other_cfg->buildable_on_district_ids[i] == district_id) { + if (leader_can_build_district (this, other_id)) + allow_ai_change = true; + break; + } + } + if (allow_ai_change) + break; + } + } + + // Allow AI to build roads/rails on bridge districts + if (! allow_ai_change && (district_id == BRIDGE_DISTRICT_ID) && + (job == WJ_Build_Road || job == WJ_Build_Railroad)) + allow_ai_change = true; + + // For Wonder Districts: check if unused (can be replaced) + if (! allow_ai_change && is->current_config.enable_wonder_districts && (district_id == WONDER_DISTRICT_ID)) { + struct wonder_district_info * info = get_wonder_district_info (tile); + + // If there's a reservation (wonder being built) or completed wonder, block replacement + if (info != NULL && info->state != WDS_UNUSED) + return 0; + + // Wonder district is unused - fall through to normal tech checks + } + else if (! allow_ai_change && is->current_config.enable_natural_wonders && (district_id == NATURAL_WONDER_DISTRICT_ID)) { + return 0; + } + else if (! allow_ai_change) { + // For all other district types: AI should not change them + return 0; + } + } + } + } + + if (! skip_replacement_logic) + tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); + else if (is->have_job_and_loc_to_skip && + (is->to_skip.job == job) && (is->to_skip.tile_x == tile_x) && (is->to_skip.tile_y == tile_y)) + tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, 0); + else { + is->show_popup_was_called = 0; + tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); + if (is->show_popup_was_called && tr) { // Check that the popup was shown and the player chose to replace + is->to_skip = (struct worker_job_and_location) { .job = job, .tile_x = tile_x, .tile_y = tile_y }; + is->have_job_and_loc_to_skip = 1; + } + } + + if (! tr && is->current_config.enable_districts && (job == WJ_Build_Mines)) { + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && + inst->district_id >= 0 && inst->district_id < is->district_count && + ! tile->vtable->m35_Check_Is_Water (tile) && + (tile->CityID < 0) && + ! tile->vtable->m18_Check_Mines (tile, __, 0)) { + int tile_x = 0, tile_y = 0; + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + int owner_civ = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_civ == this->ID) || (owner_civ == 0)) { + if (leader_can_build_district (this, inst->district_id) && + district_resource_prereqs_met (tile, tile_x, tile_y, inst->district_id)) + tr = 1; + } + } + } + } + + if (! tr && is->current_config.enable_districts && is->current_config.enable_bridge_districts && + (job == WJ_Build_Road || job == WJ_Build_Railroad)) { + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + if (job == WJ_Build_Road) { + if (! has_road) + tr = 1; + } else { + bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; + if (has_road && ! has_rail) { + int req_tech = p_bic_data->WorkerJobs[job].RequireID; + if ((req_tech < 0) || + ((req_tech != p_bic_data->AdvanceCount) && + Leader_has_tech (&leaders[this->ID], __, req_tech))) { + if (Leader_has_resources_for_job_at (&leaders[this->ID], __, job, tile_x, tile_y)) + tr = 1; + } + } + } + } + } + } + + return tr; +} + +bool __fastcall +patch_Unit_can_hurry_production (Unit * this, int edx, City * city, bool exclude_cheap_improvements) +{ + if (is->current_config.allow_military_leaders_to_hurry_wonders && Unit_has_ability (this, __, UTA_Leader)) { + LeaderKind actual_kind = this->Body.leader_kind; + this->Body.leader_kind = LK_Scientific; + bool tr = Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); + this->Body.leader_kind = actual_kind; + return tr; + } else + return Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); +} + +bool __fastcall +patch_Unit_can_load (Unit * this, int edx, Unit * passenger) +{ + is->can_load_transport = this; + is->can_load_passenger = passenger; + bool tr; + + // If this potential passenger is tied to a different transport, do not allow it to load into this one + int tied_transport_id = -1; + if (is->current_config.limit_unit_loading_to_one_transport_per_turn && + (! Unit_has_ability (this, __, UTA_Army)) && + itable_look_up (&is->unit_transport_ties, passenger->Body.ID, &tied_transport_id) && + (this->Body.ID != tied_transport_id)) + tr = false; + + else + tr = Unit_can_load (this, __, passenger); + + is->can_load_transport = is->can_load_passenger = NULL; + return tr; +} + +void __fastcall +patch_Unit_load (Unit * this, int edx, Unit * transport) +{ + Unit_load (this, __, transport); + + // Tie the unit to the transport if configured to do so + if (is->current_config.limit_unit_loading_to_one_transport_per_turn && ! Unit_has_ability (transport, __, UTA_Army)) + itable_insert (&is->unit_transport_ties, this->Body.ID, transport->Body.ID); +} + +bool +any_enemies_near (Leader const * me, int tile_x, int tile_y, enum UnitTypeClasses class, int num_tiles) +{ + bool tr = false; + FOR_TILES_AROUND (tai, num_tiles, tile_x, tile_y) { + int enemy_on_this_tile = 0; + FOR_UNITS_ON (uti, tai.tile) { + UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; + if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0) && + (((int)class < 0) || (unit_type->Unit_Class == class))) { + if (me->At_War[uti.unit->Body.CivID]) { + if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { + enemy_on_this_tile = 1; + break; + } + } else + break; + } + } + if (enemy_on_this_tile) { + tr = true; + break; + } + } + return tr; +} + +bool +any_enemies_near_unit (Unit * unit, int num_tiles) +{ + UnitType * unit_type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + return any_enemies_near (&leaders[unit->Body.CivID], unit->Body.X, unit->Body.Y, unit_type->Unit_Class, num_tiles); +} + +void __fastcall +patch_Unit_ai_move_artillery (Unit * this) +{ + if ((! is->current_config.use_offensive_artillery_ai) || + ((this->Body.UnitTypeID < 0) || (this->Body.UnitTypeID >= p_bic_data->UnitTypeCount))) // Check for invalid unit type id which appears sometimes, IDK why + goto base_impl; + + Tile * on_tile = tile_at (this->Body.X, this->Body.Y); + City * in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); + UnitType const * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + int num_escorters_req = this->vtable->eval_escort_requirement (this); + + if ((in_city == NULL) || (count_escorters (this) >= num_escorters_req)) + goto base_impl; + + // Don't assign escort if there are any enemies around because in that case it might be a serious mistake to take a defender out of the city + if (any_enemies_near_unit (this, 37)) + goto base_impl; + + // Find the strongest healthy defender the city has and assign that unit as an escort but make sure doing so doesn't leave the city + // defenseless. I think picking the strongest defender is the right choice here because the artillery pair is more likely to come under + // attack than a city and also leaving obsolete units in the city gives them a chance to upgrade. + int num_defenders = 0; + Unit * best_defender = NULL; + int best_defender_strength = -1; + FOR_UNITS_ON (uti, on_tile) { + Unit_Body * body = &uti.unit->Body; + UnitType * type = &p_bic_data->UnitTypes[body->UnitTypeID]; + if ((type->AI_Strategy & UTAI_Defence) && + (! UnitType_has_ability (type, __, UTA_Immobile)) && + (body->Damage == 0) && + ((body->UnitState == 0) || (body->UnitState == UnitState_Fortifying)) && + (body->escortee < 0)) { + num_defenders++; + int str = type->Defence * Unit_get_max_hp (uti.unit); + if (str > best_defender_strength) { + best_defender = uti.unit; + best_defender_strength = str; + } + } + } + if ((num_defenders >= 2) && (best_defender != NULL)) { + Unit_set_state (best_defender, __, 0); + Unit_set_escortee (best_defender, __, this->Body.ID); + } + +base_impl: + Unit_ai_move_artillery (this); + + // Recompute these since the unit might have moved + on_tile = tile_at (this->Body.X, this->Body.Y); + in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); + + // Load the unit into a transport for a naval invasion if it's just sitting in a city with nothing else to do + if (is->current_config.use_offensive_artillery_ai && + (in_city != NULL) && + (this->Body.Moves == 0) && + (this->Body.UnitState == UnitState_Fortifying) && + (this->Body.Container_Unit < 0)) { + Unit * transport = Unit_find_transport (this, __, this->Body.X, this->Body.Y); + if (transport != NULL) { + + int transport_capacity = p_bic_data->UnitTypes[transport->Body.UnitTypeID].Transport_Capacity; + int units_in_transport, arty_in_transport; { + units_in_transport = arty_in_transport = 0; + FOR_UNITS_ON (uti, on_tile) + if (uti.unit->Body.Container_Unit == transport->Body.ID) { + units_in_transport++; + arty_in_transport += (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].AI_Strategy & UTAI_Artillery) != 0; + } + } + + // Check that there's space for the arty unit and an escort, and that the transport does not have more than one arty per three + // spaces so we're less likely to assemble invasion forces composed of nothing but artillery. + if ((units_in_transport + 2 <= transport_capacity) && + (arty_in_transport < not_below (1, transport_capacity / 3))) { + Unit_set_escortee (this, __, -1); + patch_Unit_load (this, __, transport); + } + } + } +} + +// Estimates the number of turns necessary to move the given unit to the given tile and writes it to *out_num_turns. Returns 0 if there is no path +// from the unit's current position to the given tile, 1 otherwise. +int +estimate_travel_time (Unit * unit, int to_tile_x, int to_tile_y, int * out_num_turns) +{ + int dist_in_mp; + patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, to_tile_x, to_tile_y, unit, unit->Body.CivID, 1, &dist_in_mp); + dist_in_mp += unit->Body.Moves; // Add MP already spent this turn to the distance + int max_mp = patch_Unit_get_max_move_points (unit); + if ((dist_in_mp >= 0) && (max_mp > 0)) { + *out_num_turns = dist_in_mp / max_mp; + return 1; + } else + return 0; // No path or unit cannot move +} + +City * +find_nearest_established_city (Unit * unit, int continent_id) +{ + int lowest_unattractiveness = INT_MAX; + City * least_unattractive_city = NULL; + FOR_CITIES_OF (coi,unit->Body.CivID) { + Tile * city_tile = tile_at (coi.city->Body.X, coi.city->Body.Y); + if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { + int dist_in_turns; + if (! estimate_travel_time (unit, coi.city->Body.X, coi.city->Body.Y, &dist_in_turns)) + continue; + int unattractiveness = 10 * dist_in_turns; + unattractiveness = (10 + unattractiveness) / (10 + coi.city->Body.Population.Size); + if (coi.city->Body.CultureIncome > 0) + unattractiveness /= 5; + if (unattractiveness < lowest_unattractiveness) { + lowest_unattractiveness = unattractiveness; + least_unattractive_city = coi.city; + } + } + } + return least_unattractive_city; +} + +bool __fastcall +patch_Unit_ai_can_form_army (Unit * this) +{ + int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.patch_ai_can_form_army_without_special_ability && ((type->Special_Actions & build_army_action) == 0)) + return false; + else + return Unit_ai_can_form_army (this); +} + +void __fastcall +patch_Unit_ai_move_leader (Unit * this) +{ + if (! is->current_config.replace_leader_unit_ai) { + Unit_ai_move_leader (this); + return; + } + + Tile * tile = tile_at (this->Body.X, this->Body.Y); + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + + // Disband the unit if it's on a continent with no cities of its civ. This is what the original logic does. + if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { + Unit_disband (this); + return; + } + + // Flee if the unit is near an enemy without adequate escort + int has_adequate_escort; { + int escorter_count = 0; + int any_healthy_escorters = 0; + int index; + for (int escorter_id = Unit_next_escorter_id (this, __, &index, true); escorter_id >= 0; escorter_id = Unit_next_escorter_id (this, __, &index, false)) { + Unit * escorter = get_unit_ptr (escorter_id); + if ((escorter != NULL) && (escorter->Body.X == this->Body.X) && (escorter->Body.Y == this->Body.Y)) { + escorter_count++; + int remaining_health = Unit_get_max_hp (escorter) - escorter->Body.Damage; + any_healthy_escorters |= (remaining_health >= 3) || (escorter->Body.Damage == 0); + } + } + has_adequate_escort = (escorter_count > 0) && any_healthy_escorters; + } + if ((! has_adequate_escort) && any_enemies_near_unit (this, 49)) { + Unit_set_state (this, __, UnitState_Fleeing); + bool done = this->vtable->work (this); + if (done || (this->Body.UnitState != 0)) + return; + } + + // Move along path if the unit already has one set + byte next_move = Unit_pop_next_move_from_path (this); + if (next_move > 0) { + this->vtable->Move (this, __, next_move, 0); + return; + } + + // Start a science age if we can + // It would be nice to compute a value for this and compare it to the option of rushing production but it's hard to come up with a valuation + if (is->current_config.patch_science_age_bug && Unit_ai_can_start_science_age (this)) { + Unit_start_science_age (this); + return; + } + + // Estimate the value of creating an army. First test if that's even a possiblity and if not leave the value at -1 so rushing production is + // always preferable (note we can't use Unit_ai_can_form_army for this b/c it returns false for units not in a city). The value of forming + // an army is "infinite" if we don't already have one and otherwise it depends on the army unit's shield cost +/- 25% for each point of + // aggression divided by the number of armies already in the field. + int num_armies = leaders[this->Body.CivID].Armies_Count; + int form_army_value = -1; + int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits + if ((this->Body.leader_kind & LK_Military) && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & build_army_action) && + ((num_armies + 1) * p_bic_data->General.ArmySupportCities <= leaders[this->Body.CivID].Cities_Count) && + (p_bic_data->General.BuildArmyUnitID >= 0) && + (p_bic_data->General.BuildArmyUnitID < p_bic_data->UnitTypeCount)) { + if (num_armies < 1) + form_army_value = INT_MAX; + else { + form_army_value = p_bic_data->UnitTypes[p_bic_data->General.BuildArmyUnitID].Cost; + int aggression_level = p_bic_data->Races[leaders[this->Body.CivID].RaceID].AggressionLevel; // aggression level varies between -2 and +2 + form_army_value = (form_army_value * (4 + aggression_level)) / 4; + if (num_armies > 1) + form_army_value /= num_armies; + } + } + + // Estimate the value of rushing production in every city on this continent and remember the highest one + City * best_rush_loc = NULL; + int best_rush_value = -1; + FOR_CITIES_OF (coi, this->Body.CivID) { + City * city = coi.city; + Tile * city_tile = tile_at (city->Body.X, city->Body.Y); + if ((continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) && + patch_Unit_can_hurry_production (this, __, city, false)) { + // Base value is equal to the number of shields rushing would save + int value = City_get_order_cost (city) - City_get_order_progress (city) - city->Body.ProductionIncome; + if (value <= 0) + continue; + + // Consider distance: Reduce the value by the number of shields produced while the leader is en route to rush. + int dist_in_turns; + if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) + continue; // no path or unit cannot move + value -= dist_in_turns * city->Body.ProductionIncome; + if (value <= 0) + continue; + + // Consider corruption: Scale down the value of rushing an improvement by the corruption rate of the city. + // This is to reflect the fact that infrastructure is more valuable in less corrupt cities. But do not apply + // this to wonders since their benefit is in most cases not lessened by local corruption. + Improvement * improv = (city->Body.Order_Type == COT_Improvement) ? &p_bic_data->Improvements[city->Body.Order_ID] : NULL; + int is_wonder = (improv != NULL) && (0 != (improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder))); + if ((improv != NULL) && (! is_wonder)) { + int good_shields = city->Body.ProductionIncome; + int corrupt_shields = city->Body.ProductionLoss; + if (good_shields + corrupt_shields > 0) + value = (value * good_shields) / (good_shields + corrupt_shields); + else + continue; + } + + if ((value > 0) && (value > best_rush_value)) { + best_rush_loc = city; + best_rush_value = value; + } + } + } + + // Hurry production or form an army depending on the estimated values of doing so. We might have to move to a (different) city if that's where + // we want to rush production or if we want to form an army but aren't already in a city. + City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); + City * moving_to_city = NULL; + if ((best_rush_loc != NULL) && (best_rush_value > form_army_value)) { + if (best_rush_loc == in_city) { + Unit_hurry_production (this); + return; + } else + moving_to_city = best_rush_loc; + } else if ((form_army_value > -1) && patch_Unit_ai_can_form_army (this)) { + Unit_form_army (this); + return; + } else if (in_city == NULL) { + // Nothing to do. Try to find a close, established city to move to & wait in. + moving_to_city = find_nearest_established_city (this, continent_id); + } + if (moving_to_city) { + int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); + if (first_move > 0) { + Unit_set_escortee (this, __, -1); + this->vtable->Move (this, __, first_move, 0); + return; + } + } + + // Nothing to do, nowhere to go, just fortify in place. + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +int +measure_strength_in_army (UnitType * type) +{ + return ((type->Attack + type->Defence) * (4 + type->Hit_Point_Bonus)) / 4; +} + +bool __fastcall +patch_impl_ai_is_good_army_addition (Unit * this, int edx, Unit * candidate) +{ + if (! is->current_config.fix_ai_army_composition) + return impl_ai_is_good_army_addition (this, __, candidate); + + UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + if (((candidate_type->AI_Strategy & UTAI_Offence) == 0) || + UnitType_has_ability (candidate_type, __, UTA_Hidden_Nationality)) + return false; + + int num_units_in_army = 0, + army_min_speed = INT_MAX, + army_min_strength = INT_MAX; + FOR_UNITS_ON (uti, tile) { + if (uti.unit->Body.Container_Unit == this->Body.ID) { + num_units_in_army++; + int movement = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Movement; + if (movement < army_min_speed) + army_min_speed = movement; + int member_strength = measure_strength_in_army (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]); + if (member_strength < army_min_strength) + army_min_strength = member_strength; + } + } + + return (num_units_in_army == 0) || + ((candidate_type->Movement >= army_min_speed) && + (measure_strength_in_army (candidate_type) >= army_min_strength)); +} + +int +rate_artillery (UnitType * type) +{ + int tr = type->Attack + type->Defence + 2 * type->Bombard_Strength * type->FireRate; + + // include movement + int moves = type->Movement; + if (moves >= 2) + tr = tr * (moves + 1) / 2; + + // include range + int range = type->Bombard_Range; + if (range >= 2) + tr = tr * (range + 1) / 2; + + // include extra hp + if (type->Hit_Point_Bonus > 0) + tr = tr * (4 + type->Hit_Point_Bonus) / 4; + + return tr; +} + +int +rate_bomber (UnitType * type) +{ + int tr = type->Bombard_Strength * type->FireRate + type->Defence; + + // include range + tr = tr * (10 + type->OperationalRange) / 10; + + // include cost + tr = (tr * 100) / (100 + type->Cost); + + // include abilities + if (UnitType_has_ability (type, __, UTA_Blitz)) + tr = tr * (type->Movement + 1) / 2; + if (UnitType_has_ability (type, __, UTA_Lethal_Land_Bombardment)) + tr = tr * 3 / 2; + if (UnitType_has_ability (type, __, UTA_Lethal_Sea_Bombardment)) + tr = tr * 5 / 4; + if (UnitType_has_ability (type, __, UTA_Stealth)) + tr = tr * 3 / 2; + + // include extra hp + if (type->Hit_Point_Bonus > 0) + tr = tr * (4 + type->Hit_Point_Bonus) / 4; + + return tr; +} + +bool __fastcall +patch_City_can_build_unit (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) +{ + bool base = City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); + + if (base) { + // Apply building prereqs + int building_prereq; + if (itable_look_up (&is->current_config.building_unit_prereqs, unit_type_id, &building_prereq)) { + // If the prereq is an encoded building ID + if (building_prereq & 1) { + if (! has_active_building (this, building_prereq >> 1)) + return false; + + // Else it's a pointer to a list of building IDs + } else { + int * list = (int *)building_prereq; + for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) + if ((list[n] >= 0) && ! has_active_building (this, list[n])) + return false; + } + } + + // Apply unit type limit + int available; + if (get_available_unit_count (&leaders[this->Body.CivID], unit_type_id, &available) && (available <= 0)) + return false; + } + + if (is->current_config.enable_districts) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + + // Bail if tech reqs are not met + int prereq_id = type->AdvReq; + if (prereq_id >= 0 && ! Leader_has_tech (&leaders[this->Body.CivID], __, prereq_id)) + return false; + + if (! Leader_can_build_unit (&leaders[this->Body.CivID], __, unit_type_id, 1, false)) + return false; + + // Superficially allow the AI to choose the unit for scoring and production. + // If a disallowed air/naval unit is chosen in ai_choose_production, we'll swap it out for a feasible fallback later + // after prioritizing the aerodrome/port to be built + if (! is_human && ( + (type->Unit_Class == UTC_Air || city_can_build_district (this, AERODROME_DISTRICT_ID)) || + (type->Unit_Class == UTC_Sea || city_can_build_district (this, PORT_DISTRICT_ID))) + ) + return base; + + // Air units + if (type->Unit_Class == UTC_Air) { + if (is->current_config.enable_aerodrome_districts && is->current_config.air_units_use_aerodrome_districts_not_cities) { + if (find_pending_district_request (this, AERODROME_DISTRICT_ID) != NULL) + return false; + if (! city_can_build_district (this, AERODROME_DISTRICT_ID)) + return false; + return city_has_required_district (this, AERODROME_DISTRICT_ID); + } + // Naval units + } else if (type->Unit_Class == UTC_Sea) { + if (is->current_config.enable_port_districts && is->current_config.naval_units_use_port_districts_not_cities) { + if (find_pending_district_request (this, PORT_DISTRICT_ID) != NULL) + return false; + if (! city_can_build_district (this, PORT_DISTRICT_ID)) + return false; + return city_has_required_district (this, PORT_DISTRICT_ID); + } + } + } + + return base; +} + +int __fastcall +patch_City_get_largest_adjacent_sea_within_work_area (City * this) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + int improv_id = is->current_evaluating_improve_id; + if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { + + // If Coastal Fortress, default to original logic (city must be next to coast) + if (p_bic_data->Improvements[improv_id].Naval_Bombard_Defence > 0) + return City_get_largest_adjacent_sea (this); + } + int lake_size_threshold = 21; + int largest_size = 0; + int largest_continent_id = -1; + FOR_WORK_AREA_AROUND (wai, this->Body.X, this->Body.Y) { + if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { + int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + if (continent->Body.TileCount <= lake_size_threshold && ! is->current_config.enable_canal_districts) + continue; + if (p_bic_data->Map.Continents[continent_id].Body.TileCount > largest_size) { + largest_size = p_bic_data->Map.Continents[continent_id].Body.TileCount; + largest_continent_id = continent_id; + } + } + } + return largest_continent_id; + } + return City_get_largest_adjacent_sea (this); +} + +bool __fastcall +patch_Map_impl_is_near_river_within_work_area (Map * this, int edx, int x, int y, int num_tiles) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + FOR_WORK_AREA_AROUND (wai, x, y) { + if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) { + return true; + } + } + return false; + } + + return this->vtable->is_near_river (this, __, x, y, num_tiles); +} + +bool __fastcall +patch_Map_impl_is_near_lake_within_work_area (Map * this, int edx, int x, int y, int num_tiles) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + int lake_size_threshold = 21; + FOR_WORK_AREA_AROUND (wai, x, y) { + if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { + int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + if (continent->Body.TileCount <= lake_size_threshold) + return true; + } + } + return false; + } + + return this->vtable->is_near_lake (this, __, x, y, num_tiles); +} + +bool __fastcall +patch_Map_impl_has_fresh_water_within_work_area (Map * this, int edx, int tile_x, int tile_y) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + int improv_id = is->current_evaluating_improve_id; + if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { + + // If an Aqueduct, default to original logic (city must be next to coast) + if ((p_bic_data->Improvements[improv_id].ImprovementFlags & ITF_Allows_City_Level_2) != 0) + return this->vtable->has_fresh_water (this, __, tile_x, tile_y); + } + if (patch_Map_impl_is_near_river_within_work_area (this, __, tile_x, tile_y, 1)) + return true; + if (patch_Map_impl_is_near_lake_within_work_area (this, __, tile_x, tile_y, 1)) + return true; + return false; + } + + return this->vtable->has_fresh_water (this, __, tile_x, tile_y); +} + +bool +city_meets_district_prereqs_to_build_improvement (City * city, int i_improv, bool apply_strict_rules) +{ + // Different logic for human vs AI players + bool is_human = (*p_human_player_bits & (1 << city->Body.CivID)) != 0; + + Improvement * improv = &p_bic_data->Improvements[i_improv]; + bool is_wonder = is->current_config.enable_wonder_districts && (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)); + if (is_wonder && ! wonder_is_buildable_by_civ (i_improv, city->Body.CivID)) + return false; + + bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; + + // Check if the improvement requires a district + bool needs_district = city_requires_district_for_improvement (city, i_improv, NULL); + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); + + // District is either not needed or already built + if (! needs_district) + return true; + + if (prereq_list == NULL) + return false; + + bool has_buildable_candidate = false; + bool has_wonder_candidate = false; + bool has_non_wonder_candidate = false; + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) + continue; + has_buildable_candidate = true; + if (district_id == WONDER_DISTRICT_ID) + has_wonder_candidate = true; + else + has_non_wonder_candidate = true; + } + if (! has_buildable_candidate) + return false; + + // Check that we have the necessary terrain + bool has_terrain_for_district = false; + bool has_terrain_for_wonder = false; + bool has_river_terrain_for_district = false; + FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { + Tile * tile = wai.tile; + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) + continue; + if (! tile_suitable_for_district (tile, district_id, city, NULL)) + continue; + + if (is_wonder && district_id == WONDER_DISTRICT_ID) { + if (! wonder_is_buildable_on_tile (tile, i_improv)) + continue; + } + + has_terrain_for_district = true; + if (requires_river && tile->vtable->m37_Get_River_Code (tile) != 0) + has_river_terrain_for_district = true; + + if (is_wonder && district_id == WONDER_DISTRICT_ID) { + if (! requires_river || tile->vtable->m37_Get_River_Code (tile) != 0) { + has_terrain_for_wonder = true; + } + } + } + } + + bool requires_wonder_terrain = is_wonder && has_wonder_candidate && ! has_non_wonder_candidate; + if (! has_terrain_for_district || + (requires_river && ! has_river_terrain_for_district) || + (requires_wonder_terrain && ! has_terrain_for_wonder)) { + return false; + } + + // If human has everything needed except a built district (which is buildable), allow relaxed checks so UI can gray entry out + if (is_human) { + return ! apply_strict_rules; + } + + // If AI already has a pending district request for this required district, return false + // to prevent wasting a turn trying to choose this improvement + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + if (find_pending_district_request (city, district_id) != NULL) + return false; + } + + // Superficially allow the AI to choose the improvement for scoring and production. + // If a disallowed improvement is chosen in ai_choose_production, we'll swap it out for a feasible fallback later + // after prioritizing the district to be built + return true; +} + +bool __fastcall +patch_City_can_build_improvement (City * this, int edx, int i_improv, bool apply_strict_rules) +{ + is->current_evaluating_improve_id = i_improv; + + char ss[200]; + snprintf (ss, sizeof ss, "patch_City_can_build_improvement:evaluating improvement %s (%d)\n", + p_bic_data->Improvements[i_improv].Name.S, i_improv); + (*p_OutputDebugStringA) (ss); + + // First defer to the base game's logic + bool base = City_can_build_improvement (this, __, i_improv, apply_strict_rules); + if (! base) return false; + if (! is->current_config.enable_districts) return base; + + bool can_build = city_meets_district_prereqs_to_build_improvement (this, i_improv, apply_strict_rules); + is->current_evaluating_improve_id = -1; + + return can_build; +} + +bool +ai_handle_district_production_requirements (City * city, City_Order * out) +{ + clear_best_feasible_order (city); + bool swapped_to_fallback = false; + City_Order fallback_order = {0}; + int required_district_id = -1; + bool should_mark_district = false; + + char ss[200]; + + if (is->current_config.enable_districts && + (out->OrderID >= 0)) { + bool needs_wonder_district = false; + bool requires_district = false; + bool needs_district = false; + + if ((out->OrderType == COT_Unit) && + (out->OrderID < p_bic_data->UnitTypeCount)) { + UnitType * type = &p_bic_data->UnitTypes[out->OrderID]; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { + required_district_id = AERODROME_DISTRICT_ID; + needs_district = true; + should_mark_district = true; + } else if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (city, PORT_DISTRICT_ID))) { + required_district_id = PORT_DISTRICT_ID; + needs_district = true; + should_mark_district = true; + } + } else if ((out->OrderType == COT_Improvement) && + (out->OrderID < p_bic_data->ImprovementsCount)) { + // Check if AI is trying to build a wonder without an incomplete wonder district + requires_district = city_requires_district_for_improvement (city, out->OrderID, &required_district_id); + if (is->current_config.enable_wonder_districts) { + Improvement * improv = &p_bic_data->Improvements[out->OrderID]; + if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && + (! city_has_wonder_district_with_no_completed_wonder (city, out->OrderID))) { + snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: City %d (%s) needs wonder district to build wonder improvement %d\n", + city->Body.ID, city->Body.CityName, out->OrderID); + (*p_OutputDebugStringA) (ss); + needs_wonder_district = true; + if (required_district_id < 0) { + required_district_id = WONDER_DISTRICT_ID; + } + } + } + needs_district = needs_wonder_district || requires_district; + } + + if (needs_district) { + struct ai_best_feasible_order * stored = get_best_feasible_order (city); + if (stored != NULL) { + bool fallback_is_feasible = true; + if (stored->order.OrderType == COT_Improvement) { + if ((stored->order.OrderID < 0) || + (stored->order.OrderID >= p_bic_data->ImprovementsCount)) + fallback_is_feasible = false; + + // Check if fallback requires a district the city doesn't have + if (fallback_is_feasible && + city_requires_district_for_improvement (city, stored->order.OrderID, NULL)) + fallback_is_feasible = false; + + // If original order was a wonder, ensure fallback is not also a wonder + if (fallback_is_feasible && needs_wonder_district) { + Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; + if (fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + fallback_is_feasible = false; + } + + // If fallback is a wonder, check if it has an incomplete wonder district + if (fallback_is_feasible && is->current_config.enable_wonder_districts) { + Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; + if ((fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && + (! city_has_wonder_district_with_no_completed_wonder (city, stored->order.OrderID))) + fallback_is_feasible = false; + } + } else if (stored->order.OrderType == COT_Unit) { + if ((stored->order.OrderID < 0) || + (stored->order.OrderID >= p_bic_data->UnitTypeCount)) + fallback_is_feasible = false; + if (fallback_is_feasible) { + UnitType * type = &p_bic_data->UnitTypes[stored->order.OrderID]; + if (type->Unit_Class != UTC_Land) + fallback_is_feasible = false; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (city, AERODROME_DISTRICT_ID))) + fallback_is_feasible = false; + if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (city, PORT_DISTRICT_ID))) + fallback_is_feasible = false; + } + } else + fallback_is_feasible = false; + + if (fallback_is_feasible) { + if (out->OrderType == COT_Improvement) { + // Remember pending building order for any improvement that requires a district + snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: Remembering fallback pending building order for city %d (%s): order type %d id %d\n", + city->Body.ID, city->Body.CityName, out->OrderType, out->OrderID); + (*p_OutputDebugStringA) (ss); + remember_pending_building_order (city, out->OrderID); + } + + fallback_order = stored->order; + swapped_to_fallback = true; + } + } + } + } + + if (swapped_to_fallback) { + *out = fallback_order; + } + if ((swapped_to_fallback || should_mark_district) && (required_district_id >= 0)) + mark_city_needs_district (city, required_district_id); + + clear_best_feasible_order (city); + return swapped_to_fallback; +} + +void __fastcall +patch_City_ai_choose_production (City * this, int edx, City_Order * out) +{ + is->ai_considering_production_for_city = this; + City_ai_choose_production (this, __, out); + + char ss[200]; + snprintf (ss, sizeof ss, "patch_City_ai_choose_production: City %d (%s) chose order type %d id %d\n", + this->Body.ID, this->Body.CityName, out->OrderType, out->OrderID); + (*p_OutputDebugStringA) (ss); + + if (is->current_config.enable_districts) { + if (ai_handle_district_production_requirements (this, out)) { + return; + } + } + + Leader * me = &leaders[this->Body.CivID]; + int arty_ratio = is->current_config.ai_build_artillery_ratio; + int bomber_ratio = is->current_config.ai_build_bomber_ratio; + + // Check if AI-build-more-artillery mod option is activated and this city is building something that we might want to switch to artillery + if ((arty_ratio > 0) && + (out->OrderType == COT_Unit) && + (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && + (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & (UTAI_Offence | UTAI_Defence))) { + + // Check how many offense/defense/artillery units this AI has already built. We'll only force it to build arty if it has a minimum + // of one defender per city, one attacker per two cities, and of course if it's below the ratio limit. + int num_attackers = me->AI_Strategy_Unit_Counts[0], + num_defenders = me->AI_Strategy_Unit_Counts[1], + num_artillery = me->AI_Strategy_Unit_Counts[2]; + if ((num_attackers > me->Cities_Count / 2) && + (num_defenders > me->Cities_Count) && + (100*num_artillery < arty_ratio*(num_attackers + num_defenders))) { + + // Loop over all build options to determine the best artillery unit available. Record its attack power and also find & record + // the highest attack power available from any offensive unit so we can compare them. + int best_arty_type_id = -1, + best_arty_rating = -1, + best_arty_strength = -1, + best_attacker_strength = -1; + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if ((type->AI_Strategy & (UTAI_Artillery | UTAI_Offence)) && + patch_City_can_build_unit (this, __, n, 1, 0, 0)) { + if (type->AI_Strategy & UTAI_Artillery) { + int this_rating = rate_artillery (&p_bic_data->UnitTypes[n]); + if (this_rating > best_arty_rating) { + best_arty_type_id = n; + best_arty_rating = this_rating; + best_arty_strength = type->Bombard_Strength * type->FireRate; + } + } else { // attacker + int this_strength = (type->Attack * (4 + type->Hit_Point_Bonus)) / 4; + if (this_strength > best_attacker_strength) + best_attacker_strength = this_strength; + } + } + } + + // Randomly switch city production to the artillery unit if we found one + if (best_arty_type_id >= 0) { + int chance = 12 * arty_ratio / 10; + + // Scale the chance of switching by the ratio of the attack power the artillery would provide to the attack power + // of the strongest offensive unit. This way the AI will rapidly build artillery up to the ratio limit only when + // artillery are its best way of dealing damage. + // Some example numbers: + // | Best attacker (str) | Best arty (str) | Chance w/ ratio = 20, damage% = 50 + // | Swordsman (3) | Catapult (4) | 16 + // | Knight (4) | Trebuchet (6) | 18 + // | Cavalry (6) | Cannon (8) | 16 + // | Cavalry (6) | Artillery (24) | 48 + // | Tank (16) | Artillery (24) | 18 + if (best_attacker_strength > 0) + chance = (chance * best_arty_strength * is->current_config.ai_artillery_value_damage_percent) / (best_attacker_strength * 100); + + if (rand_int (p_rand_object, __, 100) < chance) + out->OrderID = best_arty_type_id; + } + } + + } else if ((bomber_ratio > 0) && + (out->OrderType == COT_Unit) && + (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && + (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & UTAI_Air_Defence)) { + int num_fighters = me->AI_Strategy_Unit_Counts[7], + num_bombers = me->AI_Strategy_Unit_Counts[6]; + if (100 * num_bombers < bomber_ratio * num_fighters) { + int best_bomber_type_id = -1, + best_bomber_rating = -1; + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if ((type->AI_Strategy & UTAI_Air_Bombard) && + patch_City_can_build_unit (this, __, n, 1, 0, 0)) { + int this_rating = rate_bomber (&p_bic_data->UnitTypes[n]); + if (this_rating > best_bomber_rating) { + best_bomber_type_id = n; + best_bomber_rating = this_rating; + } + } + } + + if (best_bomber_type_id >= 0) { + int chance = 12 * bomber_ratio / 10; + if (rand_int (p_rand_object, __, 100) < chance) + out->OrderID = best_bomber_type_id; + } + } + } + + is->ai_considering_production_for_city = NULL; +} + +int __fastcall +patch_Unit_disembark_passengers (Unit * this, int edx, int tile_x, int tile_y) +{ + // Break any escort relationships if the escorting unit can't move onto the target tile. This prevents a freeze where the game continues + // trying to disembark units because an escortee looks like it could be disembarked except it can't because it won't move if its escorter + // can't be moved first. + Tile * tile = tile_at (this->Body.X, this->Body.Y), + * target = tile_at (tile_x , tile_y); + if (is->current_config.patch_blocked_disembark_freeze && (tile != NULL) && (target != NULL)) { + enum SquareTypes target_terrain = target->vtable->m50_Get_Square_BaseType (target); + FOR_UNITS_ON (uti, tile) { + Unit * escortee = get_unit_ptr (uti.unit->Body.escortee); + if ( (escortee != NULL) + && (uti.unit->Body.Container_Unit == this->Body.ID) + && (escortee->Body.Container_Unit == this->Body.ID) + && ( UnitType_has_ability (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID], __, UTA_Immobile) + || ( is->current_config.disallow_trespassing + && check_trespassing (uti.unit->Body.CivID, tile, target) + && ! is_allowed_to_trespass (uti.unit)) + || Unit_is_terrain_impassable (uti.unit, __, target_terrain))) + Unit_set_escortee (uti.unit, __, -1); + } + } + + return Unit_disembark_passengers (this, __, tile_x, tile_y); +} + +// Returns whether or not the current deal being offered to the AI on the trade screen would be accepted. How advantageous the AI thinks the +// trade is for itself is stored in out_their_advantage if it's not NULL. This advantage is measured in gold, if it's positive it means the +// AI thinks it's gaining that much value from the trade and if it's negative it thinks it would be losing that much. I don't know what would +// happen if this function were called while the trade screen is not active. +bool +is_current_offer_acceptable (int * out_their_advantage) +{ + int their_id = p_diplo_form->other_party_civ_id; + + DiploMessage consideration = Leader_consider_trade ( + &leaders[their_id], + __, + &p_diplo_form->our_offer_lists[their_id], + &p_diplo_form->their_offer_lists[their_id], + p_main_screen_form->Player_CivID, + 0, true, 0, 0, + out_their_advantage, + NULL, NULL); + + return consideration == DM_AI_ACCEPT; +} + +// Adds an offer of gold to the list and returns it. If one already exists in the list, returns a pointer to it. +TradeOffer * +offer_gold (TradeOfferList * list, int is_lump_sum, int * is_new_offer) +{ + if (list->length > 0) + for (TradeOffer * offer = list->first; offer != NULL; offer = offer->next) + if ((offer->kind == 7) && (offer->param_1 == is_lump_sum)) { + *is_new_offer = 0; + return offer; + } + + TradeOffer * tr = new (sizeof *tr); + *tr = (struct TradeOffer) { + .vtable = p_trade_offer_vtable, + .kind = 7, // TODO: Replace with enum + .param_1 = is_lump_sum, + .param_2 = 0, + .next = NULL, + .prev = NULL + }; + + if (list->length > 0) { + tr->prev = list->last; + list->last->next = tr; + list->last = tr; + list->length += 1; + } else { + list->last = list->first = tr; + list->length = 1; + } + + *is_new_offer = 1; + return tr; +} + +// Removes offer from list of offers but does not free it. Assumes offer is in the list. +void +remove_offer (TradeOfferList * list, TradeOffer * offer) +{ + if (list->length == 1) { + list->first = list->last = NULL; + list->length = 0; + } else if (list->length > 1) { + TradeOffer * prev = offer->prev, * next = offer->next; + if (prev) + prev->next = next; + if (next) + next->prev = prev; + if (list->first == offer) + list->first = next; + if (list->last == offer) + list->last = prev; + list->length -= 1; + } + offer->prev = offer->next = NULL; +} + +void __fastcall +patch_PopupForm_set_text_key_and_flags (PopupForm * this, int edx, char * script_path, char * text_key, int param_3, int param_4, int param_5, int param_6) +{ + int * p_stack = (int *)&script_path; + int ret_addr = p_stack[-1]; + + int is_initial_gold_trade = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_INITIAL_GOLD_OFFER_RETURN), + is_modifying_gold_trade = (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN ) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_OFFER_RETURN); + + // This function gets called from all over the place, check that it's being called to setup the set gold amount popup in the trade screen + if (is->current_config.autofill_best_gold_amount_when_trading && (is_initial_gold_trade || is_modifying_gold_trade)) { + int asking = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN); + int is_lump_sum = is_initial_gold_trade ? + p_stack[TRADE_GOLD_SETTER_IS_LUMP_SUM_OFFSET] : // Read this variable from the caller's frame + is->modifying_gold_trade->param_1; + + int their_id = p_diplo_form->other_party_civ_id, + our_id = p_main_screen_form->Player_CivID; + + // This variable will store the result of the optimization process and it's what will be used as the final amount presented to the + // player in the popup and left in the TradeOffer object (if applicable). Default to zero for new offers and the previous amount when + // modifying an offer. When modifying, we also zero the amount on the table b/c the optimization process only works properly from that + // starting point. + int best_amount = 0; + if (is_modifying_gold_trade) { + best_amount = is->modifying_gold_trade->param_2; + is->modifying_gold_trade->param_2 = 0; + } + + int their_advantage; + bool is_original_acceptable = is_current_offer_acceptable (&their_advantage); + + // if (we're asking for money on an acceptable trade and are offering something) OR (we're offering money on an unacceptable trade and + // are asking for something) + if (( asking && is_original_acceptable && (p_diplo_form->our_offer_lists[their_id] .length > 0)) || + ((! asking) && (! is_original_acceptable) && (p_diplo_form->their_offer_lists[their_id].length > 0))) { + + TradeOfferList * offers = asking ? &p_diplo_form->their_offer_lists[their_id] : &p_diplo_form->our_offer_lists[their_id]; + int test_offer_is_new; + TradeOffer * test_offer = offer_gold (offers, is_lump_sum, &test_offer_is_new); + + // When asking for gold, start at zero and work upwards. When offering gold it's more complicated. For lump sum + // offers, start with our entire treasury and work downward. For GPT offers, start with an upper bound and work + // downward. The upper bound depends on how much the AI thinks it's losing on the trade (in gold) divided by 20 + // (b/c 20 turn deal) with a lot of extra headroom just to make sure. + int starting_amount; { + if (asking) + starting_amount = 0; + else { + if (is_lump_sum) + starting_amount = leaders[our_id].Gold_Encoded + leaders[our_id].Gold_Decrement; + else { + int guess = not_below (0, 0 - their_advantage) / 20; + starting_amount = 10 + guess * 2; + } + } + } + + // Check if optimization is still possible. It's not if we're offering gold and our maximum offer is unacceptable + test_offer->param_2 = starting_amount; + if (asking || is_current_offer_acceptable (NULL)) { + + best_amount = starting_amount; + for (int step_size = asking ? 1000 : -1000; step_size != 0; step_size /= 10) { + test_offer->param_2 = best_amount; + while (1) { + test_offer->param_2 += step_size; + if (test_offer->param_2 < 0) + break; + else if (is_current_offer_acceptable (NULL)) + best_amount = test_offer->param_2; + else + break; + } + } + } + + // Annoying little edge case: The limitation on AIs not to trade more than their entire treasury is handled in the + // interface not the trade evaluation logic so we have to limit our gold request here to their treasury (otherwise + // the amount will default to how much they would pay if they had infinite money). + int their_treasury = leaders[their_id].Gold_Encoded + leaders[their_id].Gold_Decrement; + if (asking && is_lump_sum && (best_amount > their_treasury)) + best_amount = their_treasury; + + // Restore the trade table to its original state. Remove & free test_offer if it was newly created, otherwise put back its + // original amount. + if (test_offer_is_new) { + remove_offer (offers, test_offer); + test_offer->vtable->destruct (test_offer, __, 1); + } + + // If we're offering gold on a trade that's already acceptable, the optimal amount is zero. We must handle this explicitly in case + // we're modifying an amount already on the table. If we didn't, the above condition wouldn't optimize the amount and we'd default to + // the original amount. + } else if ((! asking) && is_original_acceptable) + best_amount = 0; + + if (is_modifying_gold_trade) + is->modifying_gold_trade->param_2 = best_amount; + snprintf (is->ask_gold_default, sizeof is->ask_gold_default, "%d", best_amount); + is->ask_gold_default[(sizeof is->ask_gold_default) - 1] = '\0'; + PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, (int)is->ask_gold_default, param_5, param_6); + } else + PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, param_4, param_5, param_6); +} + +CityLocValidity __fastcall +patch_Map_check_city_location (Map *this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile) +{ + if (is->current_config.enable_natural_wonders) { + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { + return CLV_BLOCKED; + } + } + } + + int min_sep = is->current_config.minimum_city_separation; + CityLocValidity base_result = Map_check_city_location (this, __, tile_x, tile_y, civ_id, check_for_city_on_tile); + + // If minimum separation is one, make no change + if (min_sep == 1) + return base_result; + + // If minimum separation is <= 0, ignore the CITY_TOO_CLOSE objection to city placement unless the location is next to a city belonging to + // another civ and the settings forbid founding there. + else if ((min_sep <= 0) && (base_result == CLV_CITY_TOO_CLOSE)) { + if (is->current_config.disallow_founding_next_to_foreign_city) + for (int n = 1; n <= 8; n++) { + int x, y; + get_neighbor_coords (&p_bic_data->Map, tile_x, tile_y, n, &x, &y); + City * city = city_at (x, y); + if ((city != NULL) && (city->Body.CivID != civ_id)) + return CLV_CITY_TOO_CLOSE; + } + return CLV_OK; + + // If we have an increased separation we might have to exclude some locations the base code allows. + } else if ((min_sep > 1) && (base_result == CLV_OK)) { + // Check tiles around (x, y) for a city. Because the base result is CLV_OK, we don't have to check neighboring tiles, just those at + // distance 2, 3, ... up to (an including) the minimum separation + for (int dist = 2; dist <= min_sep; dist++) { + + // vertices stores the unwrapped coords of the tiles at the vertices of the square of tiles at distance "dist" around + // (tile_x, tile_y). The order of the vertices is north, east, south, west. + struct vertex { + int x, y; + } vertices[4] = { + {tile_x , tile_y - 2*dist}, + {tile_x + 2*dist, tile_y }, + {tile_x , tile_y + 2*dist}, + {tile_x - 2*dist, tile_y } + }; + + // neighbor index for direction of tiles along edge starting from each vertex + // values correspond to directions: southeast, southwest, northwest, northeast + int edge_dirs[4] = {3, 5, 7, 1}; + + // Loop over verts and check tiles along their associated edges. The N vert is associated with the NE edge, the E vert with + // the SE edge, etc. + for (int vert = 0; vert < 4; vert++) { + wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); + int dx, dy; + neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); + for (int j = 0; j < 2*dist; j++) { // loop over tiles along this edge + int cx = vertices[vert].x + j * dx, + cy = vertices[vert].y + j * dy; + wrap_tile_coords (&p_bic_data->Map, &cx, &cy); + if (city_at (cx, cy)) + return CLV_CITY_TOO_CLOSE; + } + } + + } + return base_result; + + } else + return base_result; +} + +bool +is_zero_strength (UnitType * ut) +{ + return (ut->Attack == 0) && (ut->Defence == 0); +} + +bool +is_captured (Unit_Body * u) +{ + return (u->RaceID >= 0) && (u->CivID >= 0) && (u->CivID < 32) && leaders[u->CivID].RaceID != u->RaceID; +} + +// Decides whether or not units "a" and "b" are duplicates, i.e., whether they are interchangeable. +// If surface_only is set, the function checks only surface-level characteristics, meaning those that are visible to other players. +bool +are_units_duplicate (Unit_Body * a, Unit_Body * b, bool surface_only) +{ + UnitType * a_type = &p_bic_data->UnitTypes[a->UnitTypeID], + * b_type = &p_bic_data->UnitTypes[b->UnitTypeID]; + + // If only doing a surface comparison, look through the alternate strategy types to the base types. The difference b/w the alt types is only + // their AI strategies, and that isn't considered a surface feature. + if (surface_only) { + while (a_type->alternate_strategy_for_id >= 0) + a_type = &p_bic_data->UnitTypes[a_type->alternate_strategy_for_id]; + while (b_type->alternate_strategy_for_id >= 0) + b_type = &p_bic_data->UnitTypes[b_type->alternate_strategy_for_id]; + } + + // a and b are duplicates "on the surface" if... + bool are_surface_duplicates = + // ... they belong to the same player ... + (a->CivID == b->CivID) && + + // ... they have the same type that is not [a leader OR army] AND not a transport AND ... + (a_type == b_type) && + (! (UnitType_has_ability (a_type, __, UTA_Leader) || UnitType_has_ability (a_type, __, UTA_Army))) && + (a_type->Transport_Capacity == 0) && + + // ... they've taken the same amount of damage AND have the same charm status AND ... + (a->Damage == b->Damage) && (a->charmed == b->charmed) && + + // ... they're either both fortified or both not AND ... + (! (a->UnitState == UnitState_Fortifying) ^ (b->UnitState == UnitState_Fortifying)) && + + // ... [they have the same experience level OR are zero strength units] AND ... + ((a->Combat_Experience == b->Combat_Experience) || is_zero_strength (a_type)) && + + // ... [they are both not contained in any unit OR they are both contained in the same unit] AND ... + (((a->Container_Unit < 0) && (b->Container_Unit < 0)) || (a->Container_Unit == b->Container_Unit)) && + + // ... neither one is carrying a princess AND ... + ((a->carrying_princess_of_race < 0) && (b->carrying_princess_of_race < 0)) && + + // ... [they are both captured units OR are both native units] AND ... + (! (is_captured (a) ^ is_captured (b))) && + + // ... their custom names are identical. + (0 == strncmp (a->Custom_Name.S, b->Custom_Name.S, sizeof (a->Custom_Name))); + + if ((! are_surface_duplicates) || surface_only) + return are_surface_duplicates; + + // a and b are additionally "deep", i.e. in all ways, duplicates if... + bool are_deep_duplicates = + // ... they've used up the same number of moves AND ... + (a->Moves == b->Moves) && + + // ... they have matching statuses (has attacked this turn, etc.) AND states (is fortified, is doing worker action, etc.) AND automation status AND ... + (a->Status == b->Status) && (a->UnitState == b->UnitState) && (a->automated == b->automated) && + + // ... they have both done the same number of airdrops this turn. + (itable_look_up_or (&is->airdrops_this_turn, a->ID, 0) == itable_look_up_or (&is->airdrops_this_turn, b->ID, 0)); + + return are_deep_duplicates; +} + +bool +is_busy (Unit * unit) +{ + int state = unit->Body.UnitState; + return ((state >= UnitState_Build_Mines) && (state <= UnitState_Explore)) || + (state == UnitState_Auto_Bombard) || (state == UnitState_Auto_Air_Bombard) || + unit->Body.automated; +} + +int __fastcall +patch_Context_Menu_add_item_and_set_color (Context_Menu * this, int edx, int item_id, char * text, int red) +{ + // Initialize the array of duplicate counts. The array is 0x100 items long because that's the maximum number of items a menu can have. + if (is->current_config.group_units_on_right_click_menu && + (is->unit_menu_duplicates == NULL)) { + unsigned dups_size = 0x100 * sizeof is->unit_menu_duplicates[0]; + is->unit_menu_duplicates = malloc (dups_size); + memset (is->unit_menu_duplicates, 0, dups_size); + } + + // Check if this menu item is a valid unit and grab pointers to its info + int unit_id; + Unit_Body * unit_body; + bool disable = false, put_icon = false; + int icon_index = 0; + if ((0 <= (unit_id = item_id - (0x13 + p_bic_data->UnitTypeCount))) && + (NULL != (unit_body = p_units->Units[unit_id].Unit)) && + (unit_body->UnitTypeID >= 0) && (unit_body->UnitTypeID < p_bic_data->UnitTypeCount)) { + + if (is->current_config.group_units_on_right_click_menu) { + // Loop over all existing menu items and check if any of them is a unit that's a duplicate of the one being added + for (int n = 0; n < this->Item_Count; n++) { + Context_Menu_Item * item = &this->Items[n]; + int dup_unit_id = this->Items[n].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount); + Unit_Body * dup_body; + if ((dup_unit_id >= 0) && + (NULL != (dup_body = p_units->Units[dup_unit_id].Unit)) && + are_units_duplicate (unit_body, dup_body, unit_body->CivID != p_main_screen_form->Player_CivID)) { + // The new item is a duplicate of the nth. Mark that in the duplicate counts array and return without actually + // adding the item. It doesn't matter what value we return because the caller doesn't use it. + is->unit_menu_duplicates[n] += 1; + return 0; + } + } + } + + if (unit_body->CivID == p_main_screen_form->Player_CivID) { + Unit * unit = (Unit *)((int)unit_body - offsetof (Unit, Body)); + UnitType * unit_type = &p_bic_data->UnitTypes[unit_body->UnitTypeID]; + bool no_moves_left = unit_body->Moves >= patch_Unit_get_max_move_points (unit); + if (no_moves_left && is->current_config.gray_out_units_on_menu_with_no_remaining_moves) + disable = true; + + // Put an icon next to this unit if we're configured to do so and it's not in an army + Unit * container; + if (is->current_config.put_movement_icons_on_units_on_menu && + ((NULL == (container = get_unit_ptr (unit_body->Container_Unit))) || + (! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)))) { + put_icon = true; + + bool attacker = is_offensive_combat_type (unit_type) || (Unit_has_ability (unit, __, UTA_Army) && (Unit_count_contained_units (unit) >= 1)), + busy = is_busy (unit); + + int icon_set_index = ((int)busy << 1) + (int)(! attacker); + + int icon_row; { + if (no_moves_left) + icon_row = URCMI_CANT_MOVE; + else if (unit_body->Moves == 0) + icon_row = URCMI_UNMOVED; + else if (! attacker) + icon_row = URCMI_MOVED_NO_ATTACK; + else + icon_row = (! has_exhausted_attack (unit)) ? URCMI_MOVED_CAN_ATTACK : URCMI_MOVED_NO_ATTACK; + } + + icon_index = icon_set_index * COUNT_UNIT_RCM_ICONS + icon_row; + } + } + } + + int tr = Context_Menu_add_item_and_set_color (this, __, item_id, text, red); + + if (disable) + Context_Menu_disable_item (this, __, item_id); + + if (put_icon) { + init_unit_rcm_icons (); + if (is->unit_rcm_icon_state == IS_OK) + Context_Menu_put_image_on_item (this, __, item_id, &is->unit_rcm_icons[icon_index]); + } + + return tr; +} + +int __fastcall +patch_Context_Menu_open (Context_Menu * this, int edx, int x, int y, int param_3) +{ + int * p_stack = (int *)&x; + int ret_addr = p_stack[-1]; + + if (is->current_config.enable_named_tiles && + is->named_tile_menu_active) { + int tile_x = is->named_tile_menu_tile_x; + int tile_y = is->named_tile_menu_tile_y; + Tile * tile = tile_at (tile_x, tile_y); + if (tile_can_be_named (tile, tile_x, tile_y)) { + struct named_tile_entry * entry = get_named_tile_entry (tile); + char menu_text[64]; + if ((entry != NULL) && (entry->name[0] != '\0')) + snprintf (menu_text, sizeof menu_text, "%s %s", is->c3x_labels[CL_RENAME_TILE], entry->name); + else + strcpy (menu_text,is->c3x_labels[CL_NAME_TILE]); + if (this->Item_Count > 0) + Context_Menu_add_separator (this, __, 0); + Context_Menu_add_item (this, __, NAMED_TILE_MENU_ID, menu_text, false, (Sprite *)0x0); + } + } + + if (is->current_config.group_units_on_right_click_menu && + (ret_addr == ADDR_OPEN_UNIT_MENU_RETURN) && + (is->unit_menu_duplicates != NULL)) { + + // Change the menu text to include the duplicate counts. This is pretty straight forward except for a couple little issues: we must + // use the game's internal malloc & free for compatibility with the base code and must call a function that widens the menu form, + // as necessary, to accommodate the longer strings. + for (int n = 0; n < this->Item_Count; n++) + if (is->unit_menu_duplicates[n] > 0) { + Context_Menu_Item * item = &this->Items[n]; + unsigned new_text_len = strlen (item->Text) + 20; + char * new_text = civ_prog_malloc (new_text_len); + + // Print entry text including dup count to new_text. Biggest complication here is that we want to print the dup count + // after any leading spaces to preserve indentation. + { + int num_spaces = 0; + while (item->Text[num_spaces] == ' ') + num_spaces++; + snprintf (new_text, new_text_len, "%.*s%dx %s", num_spaces, item->Text, is->unit_menu_duplicates[n] + 1, &item->Text[num_spaces]); + new_text[new_text_len - 1] = '\0'; + } + + civ_prog_free (item->Text); + item->Text = new_text; + Context_Menu_widen_for_text (this, __, new_text); + } + + // Clear the duplicate counts + memset (is->unit_menu_duplicates, 0, 0x100 * sizeof is->unit_menu_duplicates[0]); + } + + return Context_Menu_open (this, __, x, y, param_3); +} + +bool +is_material_unit (UnitType const * type, bool * out_is_pop_else_caravan) +{ + int join_city_action = UCV_Join_City & 0x0FFFFFFF; // To get the join city action code, use the command value and mask out the top 4 category bits + int disband_action = UCV_Disband & 0x0FFFFFFF; + if ((type->Attack | type->Defence | type->Bombard_Strength) == 0) { // if non-combat unit + if ((type->PopulationCost > 0) && (type->Worker_Actions == join_city_action)) { + *out_is_pop_else_caravan = true; + return true; + } else if ((type->Standard_Actions & disband_action) && (type->Worker_Actions == 0)) { + *out_is_pop_else_caravan = false; + return true; + } else + return false; + } else + return false; +} + +void +ai_move_material_unit (Unit * this) +{ + int type_id = this->Body.UnitTypeID; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + UnitType * type = &p_bic_data->UnitTypes[type_id]; + + // Determine whether this is a pop unit (will search for a city to join) or a caravan (will search for a city to disband) + int join_city_action = UCV_Join_City & 0x0FFFFFFF; + bool pop_else_caravan = type->Worker_Actions == join_city_action; + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + + // This part of the code follows how the replacement leader AI works. Basically it disbands the unit if it's on a continent with no + // friendly cities, then flees if it's in danger, then moves it along a set path if it has one. + if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { + Unit_disband (this); + return; + } + if (any_enemies_near_unit (this, 49)) { + Unit_set_state (this, __, UnitState_Fleeing); + bool done = this->vtable->work (this); + if (done || (this->Body.UnitState != 0)) + return; + } + byte next_move = Unit_pop_next_move_from_path (this); + if (next_move > 0) { + this->vtable->Move (this, __, next_move, 0); + return; + } + + // Find the best city to act on + City * best_city = NULL; + int best_city_value = pop_else_caravan ? -1 : 0; // min value to act is 0 for pop units, 1 for caravans + FOR_CITIES_OF (coi, this->Body.CivID) { + City * city = coi.city; + Tile * city_tile = tile_at (city->Body.X, city->Body.Y); + if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { + + if (pop_else_caravan) { + // Skip this city if it can't support another citizen + if ((city->Body.FoodIncome <= 0) || + (City_requires_improvement_to_grow (city) > -1)) + continue; + } else { + // Skip this city if its current build can't be rushed + if (! City_can_take_outside_shields (city, __, 0)) + continue; + } + + // Consider distance. + int dist_in_turns; + if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) + continue; // No path or unit cannot move + + int value; + if (pop_else_caravan) + value = 1000 / (10 + dist_in_turns); // Base value of 100 * 10 / (10 + dist_in_turn) + else { + // value is number of useful shields we'd get by moving to this city and disbanding there + int shields_per_turn = get_city_production_rate (city, city->Body.Order_Type, city->Body.Order_ID), + shields_to_complete_build = City_get_order_cost (city) - City_get_order_progress (city) - shields_per_turn, + disband_value = Leader_get_unit_cost (&leaders[city->Body.CivID], __, type_id, false) >> 2; + value = not_above (shields_to_complete_build, disband_value) - shields_per_turn * dist_in_turns; + } + + // Scale value by city corruption rate for pop units or caravan units targeting cities building improvs + if (pop_else_caravan || (city->Body.Order_Type == COT_Improvement)) { + int good_shields = city->Body.ProductionIncome, + corrupt_shields = city->Body.ProductionLoss; + if (good_shields + corrupt_shields > 0) + value = (value * good_shields) / (good_shields + corrupt_shields); + else + value = -1; + } + + if (value > best_city_value) { + best_city = city; + best_city_value = value; + } + } + } + + // Join city if we're already in the city we want to join, otherwise move to that city. If we couldn't find a city to join, go to the + // nearest established city and wait. + City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); + City * moving_to_city = NULL; + if (best_city != NULL) { + if (best_city == in_city) { + if (pop_else_caravan && patch_Unit_can_perform_command (this, __, UCV_Join_City)) { + Unit_join_city (this, __, in_city); + return; + } else if ((! pop_else_caravan) && patch_Unit_can_perform_command (this, __, UCV_Disband)) { + Unit_disband (this); + return; + } + } else + moving_to_city = best_city; + } else if (in_city == NULL) + moving_to_city = find_nearest_established_city (this, continent_id); + + if (moving_to_city) { + int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); + if (first_move > 0) { + Unit_set_escortee (this, __, -1); + this->vtable->Move (this, __, first_move, 0); + return; + } + } + + // Nothing to do, nowhere to go, just fortify in place. + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +int __stdcall +patch_get_anarchy_length (int leader_id) +{ + int base = get_anarchy_length (leader_id); + int multiplier = is->current_config.anarchy_length_percent; + if (multiplier != 100) { + // Anarchy cannot be less than 2 turns or you'll get an instant government switch. Only let that happen when the percent multiplier is + // set below zero, indicating a desire for no anarchy. Otherwise we can't reduce anarchy below 2 turns. + if (multiplier < 0) + return 1; + else if (base <= 2) + return base; + else + return not_below (2, rand_div (base * multiplier, 100)); + } else + return base; +} + +bool __fastcall +patch_Unit_check_king_ability_while_spawning (Unit * this, int edx, enum UnitTypeAbilities a) +{ + if (is->current_config.dont_give_king_names_in_non_regicide_games && + ((*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) == 0)) + return false; + else + return Unit_has_ability (this, __, a); +} + +int __fastcall +patch_Map_compute_neighbor_index_for_pass_between (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + if (is->current_config.enable_land_sea_intersections) + return 0; + else + return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); +} + +// This call replacement used to be part of improvement perfuming but now its only purpose is to set ai_considering_order when +// ai_choose_production is looping over improvements. +bool __fastcall +patch_Improvement_has_wonder_com_bonus_for_ai_prod (Improvement * this, int edx, enum ImprovementTypeWonderFeatures flag) +{ + is->ai_considering_order.OrderID = this - p_bic_data->Improvements; + is->ai_considering_order.OrderType = COT_Improvement; + return Improvement_has_wonder_flag (this, __, flag); +} + +// Similarly, this one sets the var when looping over unit types. +bool __fastcall +patch_UnitType_has_strat_0_for_ai_prod (UnitType * this, int edx, byte n) +{ + is->ai_considering_order.OrderID = this - p_bic_data->UnitTypes; + is->ai_considering_order.OrderType = COT_Unit; + return UnitType_has_ai_strategy (this, __, n); +} + +int +compare_ai_prod_valuations (void const * vp_a, void const * vp_b) +{ + struct ai_prod_valuation const * a = vp_a, + * b = vp_b; + if (a->point_value > b->point_value) return -1; + else if (b->point_value > a->point_value) return 1; + else return 0; +} + +void +rank_ai_production_options (City * city) +{ + is->count_ai_prod_valuations = 0; + City_Order unused; + patch_City_ai_choose_production (city, __, &unused); // records valuations in is->ai_prod_valuations + qsort (is->ai_prod_valuations, is->count_ai_prod_valuations, sizeof is->ai_prod_valuations[0], compare_ai_prod_valuations); +} + +void __fastcall +patch_City_Form_m82_handle_key_event (City_Form * this, int edx, int virtual_key_code, int is_down) +{ + if (is->current_config.enable_ai_production_ranking && + (~*p_human_player_bits & (1 << this->CurrentCity->Body.CivID)) && + (virtual_key_code == VK_P) && is_down) { + rank_ai_production_options (this->CurrentCity); + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_AI_PROD_RANKING", -1, 0, 0, 0); + char s[200]; + for (int n = 0; n < is->count_ai_prod_valuations; n++) { + struct ai_prod_valuation const * val = &is->ai_prod_valuations[n]; + char * name = (val->order_type == COT_Improvement) ? p_bic_data->Improvements[val->order_id].Name.S : p_bic_data->UnitTypes[val->order_id].Name; + + int show_strategy = -1; + if (val->order_type == COT_Unit) + itable_look_up (&is->unit_type_alt_strategies, val->order_id, &show_strategy); + + if ((show_strategy >= 0) && (show_strategy <= CL_LAST_UNIT_STRAT - CL_FIRST_UNIT_STRAT)) + snprintf (s, sizeof s, "^%d %s (%s)", val->point_value, name, is->c3x_labels[CL_FIRST_UNIT_STRAT + show_strategy]); + else + snprintf (s, sizeof s, "^%d %s", val->point_value, name); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + patch_show_popup (popup, __, 0, 0); + + } else if (is->current_config.toggle_zoom_with_z_on_city_screen && + (virtual_key_code == VK_Z) && is_down) { + p_bic_data->is_zoomed_out = ! p_bic_data->is_zoomed_out; + Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, this->CurrentCity->Body.X, get_city_screen_center_y (this->CurrentCity), 0, true, false); // also redraws map + this->Base.vtable->m73_call_m22_Draw ((Base_Form *)this); + } + + City_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); +} + +bool +can_harvest_shields_from_forest (Tile * tile) +{ + int flags = tile->vtable->m43_Get_field_30 (tile); + return (flags & 0x10000000) == 0; +} + +void __fastcall +patch_open_tile_info (void * this, int edx, int mouse_x, int mouse_y, int civ_id) +{ + int tx, ty; + if (is->current_config.show_detailed_tile_info && + (! Main_Screen_Form_get_tile_coords_under_mouse (p_main_screen_form, __, mouse_x, mouse_y, &tx, &ty))) { + is->viewing_tile_info_x = tx; + is->viewing_tile_info_y = ty; + is->tile_info_open = true; + } else + is->viewing_tile_info_x = is->viewing_tile_info_y = -1; + + open_tile_info (this, __, mouse_x, mouse_y, civ_id); + + is->tile_info_open = false; +} + +int __fastcall +patch_Match_ai_eval_city_location (void * this, int edx, int x, int y, int civ_id, bool param_4, int * out_breakdown) +{ + is->ai_evaling_city_loc_x = x; + is->ai_evaling_city_loc_y = y; + is->ai_evaling_city_field_30_get_counter = 0; + + return Match_ai_eval_city_location (this, __, x, y, civ_id, param_4, out_breakdown); +} + +bool +is_explored (Tile * tile, int civ_id) +{ + unsigned explored_bits = tile->Body.Fog_Of_War; + int in_debug_mode = (*p_debug_mode_bits & 8) != 0; // checking bit 3 here b/c that's how resource visibility is checked in open_tile_info + if (in_debug_mode || (explored_bits & (1 << civ_id))) + return true; + else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND + ((1 << civ_id) & *p_human_player_bits) && // "civ_id" is a human player AND + (explored_bits & *p_human_player_bits)) // any human player has visibility on the tile + return true; + else + return false; +} + +// On the GOG executable, this function intercepts the call to draw the "No information available" text on a unexplored (black) tile. In that case we +// replace that text with the coords. But on the Steam EXE this func also intercepts the call that draws the resource name on the visible tile info +// box b/c the call site is reused via a jump. So we must check that the tile is actually unexplored before replacing the text so that the resource +// name doesn't get overwritten. +int __fastcall +patch_PCX_Image_draw_no_tile_info (PCX_Image * this, int edx, char * str, int x, int y, int str_len) +{ + Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if ((tile != p_null_tile) && ! is_explored (tile, p_main_screen_form->Player_CivID)) { + char s[100]; + snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); + s[(sizeof s) - 1] = '\0'; + return PCX_Image_draw_text (this, __, s, x, y, strlen (s)); + } else + return PCX_Image_draw_text (this, __, str, x, y, str_len); +} + +int __fastcall +patch_PCX_Image_draw_tile_info_terrain (PCX_Image * this, int edx, char * str, int x, int y, int str_len) +{ + Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if (tile != p_null_tile) { + bool show_district_name = false; + + char s[200]; + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + // Draw district name to the right of terrain name if tile has one + struct district_instance * dist = get_district_instance (tile); + + if (dist != NULL) { + show_district_name = true; + char const * display_name = is->district_configs[dist->district_id].display_name; + if ((display_name == NULL) || (display_name[0] == '\0')) + display_name = is->district_configs[dist->district_id].name; + + // If it's a wonder district with a completed wonder, show the wonder name instead + if ((dist->district_id == WONDER_DISTRICT_ID) && + (dist->wonder_info.state == WDS_COMPLETED) && + (dist->wonder_info.wonder_index >= 0) && + (dist->wonder_info.wonder_index < is->wonder_district_count)) { + char const * wonder_name = is->wonder_district_configs[dist->wonder_info.wonder_index].wonder_name; + if ((wonder_name != NULL) && (wonder_name[0] != '\0')) { + display_name = wonder_name; + } + } else if ((dist->district_id == NATURAL_WONDER_DISTRICT_ID) && + (dist->natural_wonder_info.natural_wonder_id >= 0) && + (dist->natural_wonder_info.natural_wonder_id < is->natural_wonder_count)) { + int natural_id = dist->natural_wonder_info.natural_wonder_id; + char const * natural_name = is->natural_wonder_configs[natural_id].name; + if ((natural_name != NULL) && (natural_name[0] != '\0')) { + display_name = natural_name; + } + } + + snprintf (s, sizeof s, "%s", display_name); + PCX_Image_draw_text (this, __, s, x + 68, y, strlen (s)); + } + } + + // Show sprites & sheet indexes if in debug mode + int is_debug_mode = (*p_debug_mode_bits & 4) != 0; + if (is_debug_mode) { + int sheet_index = (tile->SquareParts >> 8) & 0xFF; + int sprite_index = tile->SquareParts & 0xFF; + snprintf (s, sizeof s, "%d, %d", sheet_index, sprite_index); + PCX_Image_draw_text (this, __, s, x, y - 18, strlen (s)); + } + + // Draw tile coords on line below terrain name + snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); + PCX_Image_draw_text (this, __, s, x, y + 14, strlen (s)); + + if ((is->city_loc_display_perspective >= 0) && + ((1 << is->city_loc_display_perspective) & *p_player_bits)) { + int eval = patch_Match_ai_eval_city_location (p_match, __, is->viewing_tile_info_x, is->viewing_tile_info_y, is->city_loc_display_perspective, false, NULL); + if (eval > 0) { + snprintf (s, sizeof s, "%d", eval - 1000000); + PCX_Image_draw_text (this, __, s, x + 95, y, strlen (s)); + } + } + + // If tile has been chopped and district name not shown (uses same space), indicate that to the right of the terrain name + if (! can_harvest_shields_from_forest (tile) && !show_district_name) + PCX_Image_draw_text (this, __, is->c3x_labels[CL_CHOPPED], x + 145, y, strlen (is->c3x_labels[CL_CHOPPED])); + } + return PCX_Image_draw_text (this, __, str, x, y, str_len); +} + +int __fastcall +patch_City_compute_corrupted_yield (City * this, int edx, int gross_yield, bool is_production) +{ + Leader * leader = &leaders[this->Body.CivID]; + + if (is->current_config.zero_corruption_when_off && + (p_bic_data->Governments[leader->GovernmentType].CorruptionAndWaste == CWT_Off)) + return 0; + + int tr = City_compute_corrupted_yield (this, __, gross_yield, is_production); + + if (is->current_config.promote_wonder_decorruption_effect) { + int actual_capital_id = leader->CapitalID; + for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { + Improvement * improv = &p_bic_data->Improvements[improv_id]; + City * pseudo_capital = NULL; + if (improv->SmallWonderFlags & ITSW_Reduces_Corruption) { + if (improv->Characteristics & ITC_Small_Wonder) { + pseudo_capital = get_city_ptr (leader->Small_Wonders[improv_id]); + } else if (improv->Characteristics & ITC_Wonder) { + pseudo_capital = get_city_ptr (Game_get_wonder_city_id(p_game, __, improv_id)); + } + + if (pseudo_capital != NULL && pseudo_capital->Body.CivID == this->Body.CivID && pseudo_capital->Body.ID != actual_capital_id) { + leader->CapitalID = pseudo_capital->Body.ID; + int fp_corrupted_yield = City_compute_corrupted_yield (this, __, gross_yield, is_production); + if (fp_corrupted_yield < tr) + tr = fp_corrupted_yield; + } + } + } + leader->CapitalID = actual_capital_id; + } + + return tr; +} + +int __fastcall +patch_Sprite_draw (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + Sprite * to_draw = get_sprite_proxy_for_current_hour(this); + return Sprite_draw(to_draw ? to_draw : this, __, canvas, pixel_x, pixel_y, color_table); +} + +int __fastcall +patch_Sprite_draw_on_map (Sprite * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) +{ + Sprite * to_draw = get_sprite_proxy_for_current_hour(this); + return Sprite_draw_on_map(to_draw ? to_draw : this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); +} + +bool +is_or_could_become_grassland (Tile * tile) +{ + enum SquareTypes sq_type = tile->vtable->m50_Get_Square_BaseType (tile), + underlying_type = tile->vtable->m49_Get_Square_RealType (tile); + int worker_job_id = p_bic_data->TileTypes[sq_type].WorkerJobID; + return sq_type == SQ_Grassland || + (underlying_type == SQ_Grassland && (worker_job_id == WJ_Clean_Forest || worker_job_id == WJ_Clear_Swamp)) || + tile->vtable->m72_Get_Pollution_Effect (tile) == SQ_Grassland; +} + +void __fastcall +patch_Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (Map_Renderer * this, int edx, int param_1, int pixel_x, int pixel_y, Map_Renderer * map_renderer, int param_5, int tile_x, int tile_y, int param_8) +{ + Map * map = &p_bic_data->Map; + Tile * tile = tile_at (tile_x, tile_y); + + is->current_render_tile = tile; + is->current_render_tile_x = tile_x; + is->current_render_tile_y = tile_y; + is->current_render_tile_district = get_district_instance (tile); + + Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (this, __, param_1, pixel_x, pixel_y, map_renderer, param_5, tile_x, tile_y, param_8); + + is->current_render_tile = NULL; + is->current_render_tile_x = -1; + is->current_render_tile_y = -1; + is->current_render_tile_district = NULL; + + if ((is->city_loc_display_perspective >= 0) && + (! map->vtable->m10_Get_Map_Zoom (map)) && // Turn off display when zoomed out. Need another set of highlight images for that. + ((1 << is->city_loc_display_perspective) & *p_player_bits) && + (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. + + init_tile_highlights (); + if (is->tile_highlight_state == IS_OK) { + int eval = patch_Match_ai_eval_city_location (p_match, __, tile_x, tile_y, is->city_loc_display_perspective, false, NULL); + if (eval > 0) { + int step_size = 10; + int midpoint = (COUNT_TILE_HIGHLIGHTS % 2 == 0) ? 1000000 : (1000000 - step_size/2); + int grade = (eval >= midpoint) ? (eval - midpoint) / step_size : (eval - midpoint) / step_size - 1; + int i_highlight = clamp (0, COUNT_TILE_HIGHLIGHTS - 1, COUNT_TILE_HIGHLIGHTS/2 + grade); + Sprite_draw_on_map (&is->tile_highlights[i_highlight], __, this, pixel_x, pixel_y, 1, 1, 1, 0); + } + } + } + + // Districts-related highlights + if (is->current_config.enable_districts && + (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. + init_tile_highlights (); + if (is->tile_highlight_state == IS_OK) { + + // Draw city work radius highlights for selected worker + if (is->current_config.enable_city_work_radii_highlights && + is->highlight_city_radii) { + + if ((tile != NULL) && (tile != p_null_tile)) { + int stored_ptr; + if (itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)tile, &stored_ptr)) { + struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)stored_ptr; + Sprite_draw_on_map (&is->tile_highlights[clamp(0, COUNT_TILE_HIGHLIGHTS - 1, info->highlight_level)], __, this, pixel_x, pixel_y, 1, 1, 1, 0); + } + } + } + + // If focusing on a tile after Great Wall completed, highlight the tile while getting user confirmation + if (is->focused_tile != NULL && is->focused_tile == tile) { + Sprite_draw_on_map (&is->tile_highlights[10], __, this, pixel_x, pixel_y, 1, 1, 1, 0); + } + } + } +} + +// We determine at the start of the game where *any* AI player might want to build canals and bridges. +// This is done up front in a single pass, as re-assessing every single turn per AI is wasteful and the +// geography of the map doesn't change. This function adds all the candidates as districts, effectively +// drawing them directly on the map. We don't use it in a normal game, but this is extremely useful for +// debugging so good to keep it around. For debugging, just call it immediately after +// generate_ai_canal_and_bridge_targets () +void +insert_ai_candidate_bridge_or_canals_into_district_tile_map () +{ + if ((is->ai_candidate_bridge_or_canals_count <= 0) || (! is->ai_candidate_bridge_or_canals_initialized)) + return; + + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if (entry == NULL) + continue; + + char ss[256]; + snprintf (ss, sizeof ss, "Entry %d: district %d owner %d tiles %d completed %d\n", + ei, entry->district_id, entry->owner_civ_id, entry->tile_count, entry->completed ? 1 : 0); + (*p_OutputDebugStringA)(ss); + + for (int ti = 0; ti < entry->tile_count; ti++) { + int tx = entry->tile_x[ti]; + int ty = entry->tile_y[ti]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + snprintf (ss, sizeof ss, " (%d,%d)%s\n", tx, ty, (ti == entry->assigned_tile_index) ? " [assigned]" : ""); + (*p_OutputDebugStringA)(ss); + } + } + + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if ((entry == NULL) || (entry->completed)) + continue; + + for (int ti = 0; ti < entry->tile_count; ti++) { + int tx = entry->tile_x[ti]; + int ty = entry->tile_y[ti]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int key = (int)tile; + int existing; + if (itable_look_up (&is->district_tile_map, key, &existing)) + continue; + + struct district_instance * inst = (struct district_instance *)calloc (1, sizeof *inst); + if (inst == NULL) + continue; + inst->state = DS_COMPLETED; + inst->district_id = entry->district_id; + inst->tile_x = tx; + inst->tile_y = ty; + + itable_insert (&is->district_tile_map, key, (int)inst); + } + } +} + +void __fastcall +patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (Map_Renderer * this, int edx, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (! is->current_config.draw_forests_over_roads_and_railroads) { + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + Tile * tile = is->current_render_tile; + if ((tile == NULL) || (tile == p_null_tile)) + return; + + if ((tile->vtable->m50_Get_Square_BaseType (tile) == SQ_Forest) && + (*tile->vtable->m25_Check_Roads)(tile, __, 0)) { + is->draw_forests_over_roads_on_tile = true; + return; + } + + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Map_Renderer_m52_Draw_Roads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + // Don't draw roads if a bridge is here + if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { + Tile * tile = is->current_render_tile; + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * dist = get_district_instance (tile); + if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { + return; + } + } + } + + Map_Renderer_m52_Draw_Roads (this, __, image_index, map_renderer, pixel_x, pixel_y); + + if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) + return; + + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Map_Renderer_m52_Draw_Railroads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + // Don't draw railroads if a bridge is here + if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { + Tile * tile = is->current_render_tile; + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * dist = get_district_instance (tile); + if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { + return; + } + } + } + + Map_Renderer_m52_Draw_Railroads (this, __, image_index, map_renderer, pixel_x, pixel_y); + + if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) + return; + + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Main_Screen_Form_m82_handle_key_event (Main_Screen_Form * this, int edx, int virtual_key_code, int is_down) +{ + char s[200]; + int * last_events = is->last_main_screen_key_up_events; + bool in_game = *p_player_bits != 0; // Player bits all zero indicates we aren't currently in a game. Need to check for this because UI events + // on the main menu also pass through this function. + + if (! is_down) { + for (int n = ARRAY_LEN (is->last_main_screen_key_up_events) - 1; n > 0; n--) + last_events[n] = last_events[n - 1]; + last_events[0] = virtual_key_code; + } + + if (is->current_config.enable_ai_city_location_desirability_display && + (virtual_key_code == VK_L) && is_down && + (! (is_command_button_active (&this->GUI, UCV_Load) || is_command_button_active (&this->GUI, UCV_Unload))) && + in_game) { + int is_debug_mode = (*p_debug_mode_bits & 4) != 0; // This is how the check is done in open_tile_info. Actually there are two debug + // mode bits (4 and 8) and I don't know what the difference is. + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CITY_LOC_HIGHLIGHTS", -1, 0, 0x40, 0); + snprintf (s, sizeof s, " %s", is->c3x_labels[CL_OFF]); + s[(sizeof s) - 1] = '\0'; + PopupSelection_add_item (&popup->selection, __, s, 0); + for (int n = 1; n < 32; n++) + if ((*p_player_bits & (1 << n)) && + (is_debug_mode || (n == p_main_screen_form->Player_CivID))) { + Race * race = &p_bic_data->Races[leaders[n].RaceID]; + snprintf (s, sizeof s, " (%d) %s", n, race->vtable->GetLeaderName (race)); + s[(sizeof s) - 1] = '\0'; + PopupSelection_add_item (&popup->selection, __, s, n); + } + int sel = patch_show_popup (popup, __, 0, 0); + if (sel >= 0) { // -1 indicates popup was closed without making a selection + is->city_loc_display_perspective = (sel >= 1) ? sel : -1; + this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw + } + + } else if (is->current_config.enable_debug_mode_switch && + (in_game && ! is_down) && + (last_events[4] == VK_D) && (last_events[3] == VK_E) && (last_events[2] == VK_B) && (last_events[1] == VK_U) && (last_events[0] == VK_G)) { + PopupForm * popup = get_popup_form (); + if ((*p_debug_mode_bits & 0xC) != 0) { // Consider debug mode on if either bit is set + *p_debug_mode_bits &= ~0xC; + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + PopupForm_add_text (popup, __, "Debug mode deactivated.", 0); + patch_show_popup (popup, __, 0, 0); + } else { + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_DEBUG_ACTIVATION", -1, 0, 0, 0); + int sel = patch_show_popup (popup, __, 0, 0); + if (sel == 0) { + *p_debug_mode_bits |= 0xC; + *(bool *)((int)p_human_player_bits + 37) = true; // Set MegaTrainerXL flag indicating edited save + } + } + this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw + + // Worker keyboard shortcuts that would normally go to patch_Main_Screen_Form_issue_command + // unfortunately get short-circuited if a district is on a tile and the default popup to replace a "mine" is shown. + // The only way to catch these beforehand I've found it is to intercept the key event here. + } else if (is->current_config.enable_districts && + p_main_screen_form->Current_Unit != NULL && + is_down && + is_worker (p_main_screen_form->Current_Unit)) { + int command = -1; + bool removed_existing = false; + if (virtual_key_code == VK_M && is_command_button_active (&this->GUI, UCV_Build_Mine)) command = UCV_Build_Mine; + else if (virtual_key_code == VK_I && is_command_button_active (&this->GUI, UCV_Irrigate)) command = UCV_Irrigate; + else if (virtual_key_code == VK_N && is_command_button_active (&this->GUI, UCV_Plant_Forest)) command = UCV_Plant_Forest; + + if (handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) { + Main_Screen_Form_issue_command (this, __, command, p_main_screen_form->Current_Unit); + } + } + +after_district_key_handling: + Main_Screen_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); +} + +int __fastcall +patch_Unit_get_move_points_after_airdrop (Unit * this) +{ + int prev_airdrop_count = itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0); + itable_insert (&is->airdrops_this_turn, this->Body.ID, prev_airdrop_count + 1); + + return is->current_config.dont_end_units_turn_after_airdrop ? this->Body.Moves : patch_Unit_get_max_move_points (this); +} + +int __fastcall +patch_Unit_get_move_points_after_set_to_intercept (Unit * this) +{ + return is->current_config.patch_intercept_lost_turn_bug ? this->Body.Moves : patch_Unit_get_max_move_points (this); +} + +void __cdecl +activate_mod_info_button (int control_id) +{ + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + char s[500]; + char version_letter = 'A' + MOD_VERSION%100; + + if (MOD_PREVIEW_VERSION == 0) + snprintf (s, sizeof s, "%s: %d%c", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' '); + else + snprintf (s, sizeof s, "%s: %d%c%s %d", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' ', is->c3x_labels[CL_PREVIEW], MOD_PREVIEW_VERSION); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_CONFIG_FILES_LOADED]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + int n = 1; + for (struct loaded_config_name * lcn = is->loaded_config_names; lcn != NULL; lcn = lcn->next) { + snprintf (s, sizeof s, "^ %d. %s", n, lcn->name); + s[(sizeof s) - 1] = '\0'; + n++; + PopupForm_add_text (popup, __, s, 0); + } + + patch_show_popup (popup, __, 0, 0); +} + +int __fastcall +patch_Parameters_Form_m68_Show_Dialog (Parameters_Form * this, int edx, int param_1, void * param_2, void * param_3) +{ + init_mod_info_button_images (); + + // "b" is the mod info button. It's created each time the preferences form (or "parameters" form as Antal called it) is opened and destroyed + // every time the form is closed. This is the easiest way since it matches how the base game works. At first I tried creating the button once + // but then it will only appear once since its attachment to the prefs form is lost when the form is destroyed on closure. I tried reattaching + // the button to each newly created form but wasn't able to make that work. + Button * b = NULL; + if (is->mod_info_button_images_state == IS_OK) { + b = malloc (sizeof *b); + Button_construct (b); + + Button_initialize (b, __, + is->c3x_labels[CL_MOD_INFO_BUTTON_TEXT], // text + MOD_INFO_BUTTON_ID, // control ID + (p_bic_data->ScreenWidth - 1024) / 2 + 891, // location x + (p_bic_data->ScreenHeight - 768) / 2 + 31, // location y + MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height + (Base_Form *)this, // parent + 0); // ? + + for (int n = 0; n < 3; n++) + b->Images[n] = &is->mod_info_button_images[n]; + PCX_Image_set_font (&b->Base_Data.Canvas, __, get_font (15, FSF_NONE), 0, 0, 0); + b->activation_handler = &activate_mod_info_button; + + // Need to draw once manually or the button won't look right + b->vtable->m73_call_m22_Draw ((Base_Form *)b); + } + + int tr = Parameters_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); + + if (b != NULL) { + b->vtable->destruct ((Base_Form *)b, __, 0); + free (b); + } + + return tr; +} + +bool __fastcall +patch_City_cycle_specialist_type (City * this, int edx, int mouse_x, int mouse_y, Citizen * citizen, City_Form * city_form) +{ + int specialist_count = 0; { + Leader * city_owner = &leaders[this->Body.CivID]; + for (int n = 0; n < p_bic_data->CitizenTypeCount; n++) + specialist_count += (n != p_bic_data->default_citizen_type) && + Leader_has_tech (city_owner, __, p_bic_data->CitizenTypes[n].RequireID); + } + int shift_down = (*p_GetAsyncKeyState) (VK_SHIFT) >> 8; + int original_worker_type = citizen->WorkerType; + + // The return value of this function is not actually used by either of the two original callers. + bool tr = City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); + + // Cycle all the way around back to the previous specialist type, if appropriate. + // If the worker type was not changed after the first call to cycle_specialist_type, that indicates that the player was asked to disable + // governor management and chose not to. Do not try to cycle backwards in that case or else we'll spam the player with more popups. + if (is->current_config.reverse_specialist_order_with_shift && + shift_down && (specialist_count > 2) && (citizen->WorkerType != original_worker_type)) { + for (int n = 0; n < specialist_count - 2; n++) + City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); + } + + return tr; +} + +int __fastcall +patch_City_get_pollution_from_pop (City * this) +{ + if (! is->current_config.enable_negative_pop_pollution) + return City_get_pollution_from_pop (this); + + int base_pollution = this->Body.Population.Size - p_bic_data->General.MaximumSize_City; + if (base_pollution <= 0) + return 0; + + // Consider improvements + int net_pollution = base_pollution; + int any_cleaning_improvs = 0; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * improv = &p_bic_data->Improvements[n]; + if ((improv->ImprovementFlags & ITF_Removes_Population_Pollution) && has_active_building (this, n)) { + any_cleaning_improvs = 1; + if (improv->Pollution < 0) + net_pollution += improv->Pollution; + } + } + + if (net_pollution <= 0) + return 0; + else if (any_cleaning_improvs) + return 1; + else + return net_pollution; +} + +// The original version of this function in the base game contains a duplicate of the logic that computes the total pollution from buildings and +// pop. By re-implementing it to use the get_pollution_from_* functions, we ensure that our changes to get_pollution_from_pop will be accounted for. +// Note: This function is called from two places, one is the city screen and the other I'm not sure about. The pollution spawning logic works by +// calling the get_pollution_from_* funcs directly. +int __fastcall +patch_City_get_total_pollution (City * this) +{ + return City_get_pollution_from_buildings (this) + patch_City_get_pollution_from_pop (this); +} + +void remove_extra_palaces (City * city, City * excluded_destination); + +void +set_wonder_built_flag (int improv_id, bool is_built) +{ + if ((p_match == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) + return; + + byte * built_flags = *(byte **)((byte *)p_match + 0x4fc); + if (built_flags == NULL) + return; + + built_flags[improv_id] = is_built; +} + +bool +choose_defensive_unit_order (City * city, City_Order * out_order) +{ + if ((city == NULL) || (out_order == NULL)) + return false; + + for (int pass = 0; pass < 3; pass++) { + int best_unit_id = -1; + int best_defence = -1; + + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if (! patch_City_can_build_unit (city, __, n, 1, 0, 0)) + continue; + + int defence = type->Defence; + if ((pass < 2) && (defence <= 0)) + continue; + if ((pass <= 1) && (type->Unit_Class != UTC_Land)) + continue; + if ((pass == 0) && ((type->AI_Strategy & UTAI_Defence) == 0)) + continue; + + if (defence > best_defence) { + best_defence = defence; + best_unit_id = n; + } + } + + if (best_unit_id >= 0) { + out_order->OrderType = COT_Unit; + out_order->OrderID = best_unit_id; + return true; + } + } + + return false; +} + +// When a city adds a building that depends on a district, optionally mirror that +// building to all other same-civ cities that can also work the district tile. +void +copy_building_with_cities_in_radius (City * source, int improv_id, int required_district_id, int tile_x, int tile_y) +{ + if (! is->current_config.enable_districts) return; + if (source == NULL) return; + + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + + if (is_wonder) { + if (! is->current_config.cities_with_mutual_district_receive_wonders) + return; + } else if (! is->current_config.cities_with_mutual_district_receive_buildings) + return; + + // If a Wonder, we know the specific tile it is at, so determine which other cities have that in work radius. + if (is_wonder) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile == p_null_tile) return; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != source->Body.CivID) return; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != required_district_id) return; + if (! district_is_complete (tile, required_district_id)) return; + + FOR_CITIES_OF (coi, source->Body.CivID) { + City * city = coi.city; + if (city == NULL) continue; + if (city == source) continue; + + if (! city_radius_contains_tile (city, tile_x, tile_y)) + continue; + + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) + continue; + + if (! patch_City_has_improvement (city, __, improv_id, false)) { + City_add_or_remove_improvement (city, __, improv_id, 1, false); + } + } + } + // Else there may be multiple district instances of this type, so check each tile around the city + else { + FOR_DISTRICTS_AROUND (wai, source->Body.X, source->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != required_district_id) continue; + + FOR_CITIES_OF (coi, source->Body.CivID) { + City * city = coi.city; + if (city == NULL) continue; + if (city == source) continue; + + if (! city_radius_contains_tile (city, x, y)) + continue; + + if (! patch_City_has_improvement (city, __, improv_id, false)) { + City_add_or_remove_improvement (city, __, improv_id, 1, false); + + // If city already building it, switch to a defensive unit instead + int current_improv_id = city->Body.Order_ID; + if (current_improv_id == improv_id) { + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + // Show message to user + if (is->current_config.show_message_when_building_received_by_mutual_district && + city->Body.CivID == p_main_screen_form->Player_CivID) { + char msg[300]; + snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_RECEIVED], + p_bic_data->Improvements[improv_id].Name.S, + is->c3x_labels[CL_FROM_SHARED], + is->district_configs[required_district_id].name, + is->c3x_labels[CL_WITH], + source->Body.CityName); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + } + } + } + } +} + +void +grant_existing_district_buildings_to_city (City * city) +{ + if (! is->current_config.enable_districts || + (! is->current_config.cities_with_mutual_district_receive_buildings && + ! is->current_config.cities_with_mutual_district_receive_wonders) || + (city == NULL)) + return; + + int civ_id = city->Body.CivID; + int current_improv_id = city->Body.Order_ID; + bool prev_flag = is->sharing_buildings_by_districts_in_progress; + is->sharing_buildings_by_districts_in_progress = true; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + Tile * tile = wai.tile; + + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + struct district_infos * info = &is->district_infos[district_id]; + if (info->dependent_building_count <= 0) + continue; + + FOR_CITIES_OF (coi, civ_id) { + City * other = coi.city; + if ((other == NULL) || (other == city)) + continue; + + if (! city_radius_contains_tile (other, wai.tile_x, wai.tile_y)) + continue; + + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != other->Body.CivID) + continue; + + for (int i = 0; i < info->dependent_building_count; i++) { + int building_id = info->dependent_building_ids[i]; + if (building_id < 0) + continue; + + Improvement * building = &p_bic_data->Improvements[building_id]; + bool is_wonder = (building->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + + if (is_wonder) + continue; + + if (! patch_City_has_improvement (other, __, building_id, false)) + continue; + + if (patch_City_has_improvement (city, __, building_id, false)) + continue; + + City_add_or_remove_improvement (city, __, building_id, 1, false); + + // If city already building it, switch to a defensive unit instead + if (current_improv_id == building_id) { + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + if (is->current_config.show_message_when_building_received_by_mutual_district && + city->Body.CivID == p_main_screen_form->Player_CivID) { + char msg[300]; + snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_RECEIVED], + p_bic_data->Improvements[building_id].Name.S, + is->c3x_labels[CL_FROM_SHARED], + is->district_configs[district_id].name, + is->c3x_labels[CL_WITH], + other->Body.CityName); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + } + } + } + + is->sharing_buildings_by_districts_in_progress = prev_flag; +} + +void +auto_build_great_wall_districts_for_civ (int civ_id) +{ + if ((! is->current_config.enable_districts) || + (! is->current_config.enable_great_wall_districts) || + (! is->current_config.auto_build_great_wall_around_territory) || + (is->great_wall_auto_build == GWABS_DONE) || + (civ_id < 0) || + is->is_placing_scenario_things) + return; + + bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; + + if ((GREAT_WALL_DISTRICT_ID < 0) || (GREAT_WALL_DISTRICT_ID >= is->district_count)) { + is->great_wall_auto_build = GWABS_DONE; + return; + } + + init_tile_highlights (); + + struct district_config const * cfg = &is->district_configs[GREAT_WALL_DISTRICT_ID]; + if ((cfg->command == -1) || (! leader_can_build_district (&leaders[civ_id], GREAT_WALL_DISTRICT_ID))) { + is->great_wall_auto_build = GWABS_DONE; + return; + } + + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_BEGIN_GREAT_WALL_AUTO_BUILD", -1, 0, 0, 0); + if (civ_id == p_main_screen_form->Player_CivID) + patch_show_popup (popup, __, 0, 0); + + is->great_wall_auto_build = GWABS_RUNNING; + + unsigned int const replaceable_flags = TILE_FLAG_MINE | TILE_FLAG_IRRIGATION; + bool require_other_civ_border = (! is_human) && is->current_config.ai_auto_build_great_wall_strategy == AAGWS_OTHER_CIV_BORDERED_ONLY; + + for (int index = 0; index < p_bic_data->Map.TileCount; index++) { + int x, y; + tile_index_to_coords (&p_bic_data->Map, index, &x, &y); + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->CityID >= 0) + continue; + if (tile->vtable->m35_Check_Is_Water (tile)) + continue; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) + continue; + + bool has_border = false; + bool has_other_civ_border = false; + FOR_TILES_AROUND (tai, 9, x, y) { + if (tai.n == 0) + continue; + Tile * neighbor = tai.tile; + if (neighbor->vtable->m35_Check_Is_Water (neighbor)) + continue; + int owner_id = neighbor->vtable->m38_Get_Territory_OwnerID (neighbor); + if (owner_id != civ_id) { + has_border = true; + if (owner_id > 0) { + has_other_civ_border = true; + break; + } + } + } + if (! has_border) + continue; + if (require_other_civ_border && (! has_other_civ_border)) + continue; + + if (! district_is_buildable_on_tile (cfg, tile)) + continue; + if (! district_resource_prereqs_met (tile, x, y, GREAT_WALL_DISTRICT_ID)) + continue; + + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == GREAT_WALL_DISTRICT_ID)) { + if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) { + inst->state = DS_COMPLETED; + if (! tile->vtable->m18_Check_Mines (tile, __, 0)) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); + set_tile_unworkable_for_all_cities (tile, x, y); + } + continue; + } + + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int replace_flags = overlay_flags & replaceable_flags; + bool has_district = (inst != NULL); + int existing_district_id = -1; + if (has_district) + existing_district_id = inst->district_id; + + if (is_human && civ_id == p_main_screen_form->Player_CivID) { + is->focused_tile = tile; + Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, x, y, 0, true, false); + + char * popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL"; + set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); + + if (has_district) { + bool redundant_district = district_instance_is_redundant (inst, tile); + bool would_lose_buildings; + would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, x, y); + if (redundant_district) + would_lose_buildings = false; + if ((existing_district_id >= 0) && (existing_district_id < is->district_count)) { + set_popup_str_param (1, (char *)is->district_configs[existing_district_id].display_name, -1, -1); + } + popup_key = would_lose_buildings + ? "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT" + : "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT_SAFE"; + } else if (replace_flags != 0) { + popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_IMPROVEMENT"; + } + + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + popup_key, + -1, 0, 0, 0); + + int sel = patch_show_popup (popup, __, 0, 0); + if (sel != 0) + continue; + } + + if (has_district || (replace_flags != 0)) { + if (has_district) { + int inst_x = x, inst_y = y; + if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) + continue; + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); + handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); + } + + if (replace_flags != 0) + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, replace_flags, x, y); + } + + if (get_district_instance (tile) != NULL) + continue; + + inst = ensure_district_instance (tile, GREAT_WALL_DISTRICT_ID, x, y); + if (inst == NULL) + continue; + + inst->district_id = GREAT_WALL_DISTRICT_ID; + district_instance_set_coords (inst, x, y); + inst->state = DS_COMPLETED; + if (! tile->vtable->m18_Check_Mines (tile, __, 0)) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); + set_tile_unworkable_for_all_cities (tile, x, y); + } + + is->great_wall_auto_build = GWABS_DONE; + is->focused_tile = NULL; +} + +//We need to forwards-declare this +void __fastcall +patch_City_manage_by_governor (City * this, int edx, bool manage_professions); + +void __fastcall +patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3) +{ + int init_maintenance = this->Body.Improvements_Maintenance; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder_removal = (! add) && + ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && + (! is->is_placing_scenario_things); + int init_work_area_radius = get_work_ring_limit_total(this); + + // The enable_negative_pop_pollution feature changes the rules so that improvements flagged as removing pop pollution and having a negative + // pollution amount contribute to the city's pop pollution instead of building pollution. Here we make sure that such improvements do not + // contribute to building pollution by temporarily zeroing out their pollution stat when they're added to or removed from a city. + if (is->current_config.enable_negative_pop_pollution && + (improv->ImprovementFlags & ITF_Removes_Population_Pollution) && + (improv->Pollution < 0)) { + int saved_pollution_amount = improv->Pollution; + improv->Pollution = 0; + City_add_or_remove_improvement (this, __, improv_id, add, param_3); + improv->Pollution = saved_pollution_amount; + } else + City_add_or_remove_improvement (this, __, improv_id, add, param_3); + + if (is->current_config.enable_districts && is_wonder_removal && ((improv->Characteristics & ITC_Wonder) != 0)) { + if (is->current_config.destroyed_wonders_can_be_built_again) + set_wonder_built_flag (improv_id, false); + + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, improv->Name.S, -1, -1); + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + is->current_config.destroyed_wonders_can_be_built_again ? "C3X_DISTRICT_WONDER_DESTROYED_REBUILD" : "C3X_DISTRICT_WONDER_DESTROYED", + -1, 0, 0, 0 + ); + patch_show_popup (popup, __, 0, 0); + } + + // If the city just finished a wonder and was using a wonder district for that, set the wonder + // as completed (which switches the art over and prevents the tile from being used again) + int x, y; + if (add && is->current_config.enable_districts && is->current_config.enable_wonder_districts) { + if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { + int matched_windex = find_wonder_config_index_by_improvement_id (improv_id); + + if (matched_windex >= 0) { + FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { + x = wai.tile_x; + y = wai.tile_y; + Tile * t = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + if (! wonder_is_buildable_on_tile (t, improv_id)) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if (info->state != WDS_UNDER_CONSTRUCTION) continue; + if (info->city_id != this->Body.ID) continue; + + // Mark this wonder district as completed with the wonder + info->city = this; + info->city_id = this->Body.ID; + info->state = WDS_COMPLETED; + info->wonder_index = matched_windex; + break; + } + } + } + } + + int gw_auto_build_improv_id = is->current_config.great_wall_auto_build_wonder_improv_id; + if (add && is->current_config.enable_districts && + is->current_config.auto_build_great_wall_around_territory && + (gw_auto_build_improv_id >= 0) && (improv_id == gw_auto_build_improv_id)) + auto_build_great_wall_districts_for_civ (this->Body.CivID); + + //Calculate if work_area has shrunk, and if so, redistribute citizens. + int post_work_area_radius = get_work_ring_limit_total(this); + if (post_work_area_radius < init_work_area_radius) { + patch_City_manage_by_governor(this, __, false); + } + + // Update things in case we've added or removed a mill. This is only necessary while in-game. If the game is still loading the scenario, it + // will recompute resources after it's done and we'll recompute yields and happiness ourselves. + if (! is->is_placing_scenario_things) { + // Collect info about this mill, if in fact the added or removed improvement is a mill. If it's not, all these vars will be left + // false. "generates_input" tracks whether or not the mill generates a resource that's an input for another mill. + bool is_non_local_mill, is_yielding_mill, generates_input; { + is_non_local_mill = is_yielding_mill = generates_input = false; + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if (mill->improv_id == improv_id) { + is_non_local_mill |= (mill->flags & MF_LOCAL) == 0; + is_yielding_mill |= (mill->flags & MF_YIELDS) != 0; + generates_input |= (is->mill_input_resource_bits[mill->resource_id >> 3] & (1 << (mill->resource_id & 7))) != 0; + } + } + } + + // If the mill generates a resource that's added to the trade network or it's generating an input (potentially used locally to + // generate a traded resource) then rebuild the resource network. This is not necessary if the improvement also affects trade routes + // since the base method will have already done this recomputation. + if ((is_non_local_mill || generates_input) && + ((improv->ImprovementFlags & ITF_Allows_Water_Trade) == 0) && + ((improv->ImprovementFlags & ITF_Allows_Air_Trade) == 0) && + ((improv->WonderFlags & ITW_Safe_Sea_Travel) == 0)) + patch_Trade_Net_recompute_resources (is->trade_net, __, 0); + + // If the mill adds yields or might be a link in a resource production chain that does, recompute yields in the city. + if (is_yielding_mill || generates_input) + patch_City_recompute_yields_and_happiness (this); + } + + // Adding or removing an obsolete improvement should not change the total maintenance since obsolete improvs shouldn't cost maintenance. In + // the base game, they usually do since the game doesn't update maintenance costs when buildings are obsoleted, but with that bug patched we + // can enforce the correct behavior. + if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && + (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) + this->Body.Improvements_Maintenance = init_maintenance; + + // If AI MCS is enabled and we've added the Palace to a city, then remove any extra palaces from that city. If we're in the process of + // capturing a city, it's necessary to exclude that city as a possible destination for removed extra palaces. + if ((is->current_config.ai_multi_city_start > 1) && + (! is->is_placing_scenario_things) && + add && (improv->ImprovementFlags & ITF_Center_of_Empire) && + ((*p_human_player_bits & (1 << this->Body.CivID)) == 0)) + remove_extra_palaces (this, is->currently_capturing_city); + + // If sharing wonders in hotseat mode, we must recompute improvement maintenance for all human players when any one of them gains or loses a + // wonder that grants free improvements. + if ((! is->is_placing_scenario_things) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->Body.CivID) & *p_human_player_bits)) { // is this city owned by a human player + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->Body.CivID)) + Leader_recompute_buildings_maintenance (&leaders[n_player]); + player_bits >>= 1; + n_player++; + } + } + + // Optionally share district-dependent buildings or wonders to other cities in range of the same district + bool allow_wonder_sharing = is->current_config.cities_with_mutual_district_receive_wonders; + bool allow_building_sharing = is->current_config.cities_with_mutual_district_receive_buildings; + + if ((! is->is_placing_scenario_things) && add && + is->current_config.enable_districts && (allow_building_sharing || allow_wonder_sharing) && + (! is->sharing_buildings_by_districts_in_progress)) { + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); + if (prereq_list != NULL) { + bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + if ((! is_wonder && allow_building_sharing) || (is_wonder && allow_wonder_sharing)) { + is->sharing_buildings_by_districts_in_progress = true; + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + copy_building_with_cities_in_radius (this, improv_id, district_id, x, y); + } + is->sharing_buildings_by_districts_in_progress = false; + } + } + } +} + +void __fastcall +patch_Fighter_begin (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender) +{ + Fighter_begin (this, __, attacker, attack_direction, defender); + + // Apply override of retreat eligibility + // Must use this->defender instead of the defender argument since the argument is often NULL, in which case Fighter_begin finds a defender on + // the target tile and stores it in this->defender. Also must check that against NULL since Fighter_begin might fail to find a defender. + enum UnitTypeClasses class = p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID].Unit_Class; + if ((this->defender != NULL) && ((class == UTC_Land) || (class == UTC_Sea))) { + enum retreat_rules retreat_rules = (class == UTC_Land) ? is->current_config.land_retreat_rules : is->current_config.sea_retreat_rules; + if (retreat_rules != RR_STANDARD) { + int attacker_max_mp = patch_Unit_get_max_move_points (this->attacker), + defender_max_mp = patch_Unit_get_max_move_points (this->defender); + + if (retreat_rules == RR_NONE) + this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 0; + else if (retreat_rules == RR_ALL_UNITS) + this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 1; + else if (retreat_rules == RR_IF_FASTER) { + this->attacker_eligible_to_retreat = attacker_max_mp > defender_max_mp; + this->defender_eligible_to_retreat = defender_max_mp > attacker_max_mp; + } else if (retreat_rules == RR_IF_NOT_SLOWER) { + this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp; + this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp; + } else if (retreat_rules == RR_IF_FAST_AND_NOT_SLOWER) { + this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp && attacker_max_mp > p_bic_data->General.RoadsMovementRate; + this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp && defender_max_mp > p_bic_data->General.RoadsMovementRate; + } + + // Prevent immobile units from retreating + this->attacker_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID], __, UTA_Immobile); + this->defender_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->defender->Body.UnitTypeID], __, UTA_Immobile); + + // Prevent defender from retreating if in a city + this->defender_eligible_to_retreat &= city_at (this->defender_location_x, this->defender_location_y) == NULL; + } + } +} + +void __fastcall +patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) +{ + // Determine whether this despawn happened involuntarily, i.e. whether it's because of the actions of a player other than its owner. This + // includes cases where the unit was destroyed in combat, captured, kicked from territory with nowhere to go, etc. + int ret_addr = ((int *)&civ_id_responsible)[-1]; + bool involuntary = + ret_addr == DESPAWN_TO_FIGHT_1_RETURN || ret_addr == DESPAWN_TO_FIGHT_2_RETURN + || ret_addr == DESPAWN_TO_DO_BOMBARD_TILE_RETURN || ret_addr == DESPAWN_TO_CRUISE_MISSILE_DEFENDER_RETURN + || ret_addr == DESPAWN_TO_BOUNCE_TRESPASSING_UNITS_RETURN || ret_addr == DESPAWN_TO_NUKE_DAMAGE_RETURN + || ret_addr == DESPAWN_RECURSIVE_RETURN || ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN + || ret_addr == DESPAWN_TO_TRY_FLYING_OVER_TILE_RETURN; + + int owner_id = this->Body.CivID; + int type_id = this->Body.UnitTypeID; + UnitType * type = &p_bic_data->UnitTypes[type_id]; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + // Clear extra DBs, airdrops, wait records, and transport ties used by this unit + itable_remove (&is->extra_defensive_bombards, this->Body.ID); + itable_remove (&is->airdrops_this_turn, this->Body.ID); + itable_remove (&is->waiting_units, this->Body.ID); + itable_remove (&is->unit_transport_ties, this->Body.ID); + + // If we're despawning the stored ZoC defender, clear that variable so we don't despawn it again in check_life_after_zoc + if (this == is->zoc_defender) + is->zoc_defender = NULL; + + if (this == is->sb_next_up) + is->sb_next_up = NULL; + + if (this == is->last_selected_unit.ptr) + is->last_selected_unit.ptr = NULL; + + // Remove this unit from the list of extra units to despawn after capturing + int original_count = is->count_extra_capture_despawns; + for (int n_src = 0, n_dest = 0; n_src < original_count; n_src++) { + if (is->extra_capture_despawns[n_src] != this) { + is->extra_capture_despawns[n_dest] = is->extra_capture_despawns[n_src]; + n_dest++; + } else + is->count_extra_capture_despawns -= 1; + } + + // If the unit being despawned is a land transport or helicopter, we may have to make sure to despawn its passengers as well because the base + // game won't. In general, the passengers are lost if the transport was despawned involuntarily, i.e. because of another player's attack or + // something like that, or if the passengers couldn't survive outside the transport, specifically because it's a helicopter at sea. + bool must_despawn_passengers = false; { + if (is_land_transport (this)) + must_despawn_passengers = involuntary && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); + + else if (type->Unit_Class == UTC_Air && type->Transport_Capacity > 0) { // if "this" is a helicopter + Unit * container = get_unit_ptr (this->Body.Container_Unit); + bool on_carrier = container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea && + Unit_has_ability (container, __, UTA_Transports_Only_Aircraft); + bool passengers_could_survive = Tile_has_city (tile) || ! tile->vtable->m35_Check_Is_Water (tile); + + // If no-defense-from-inside is off, passengers in helicopters will fight to defend their tile, so they wouldn't be left + // inside the helicopter when their tile is taken. If it's on, an occupied heli can be destroyed or captured by a land unit, + // and we must make sure to despawn the passengers in that case because they can't remain on the tile. Hence, + // no-defense-from-inside implies no-escape in almost all circumstances (nukes are the exception). + enum special_helicopter_rules special_rules = is->current_config.special_helicopter_rules; + if (((special_rules & SHR_ALLOW_ON_CARRIERS) && on_carrier) || (special_rules & (SHR_NO_DEFENSE_FROM_INSIDE | SHR_NO_ESCAPE))) + must_despawn_passengers = involuntary || ! passengers_could_survive; + } + } + + bool prev_always_despawn_passengers = is->always_despawn_passengers; + + if (must_despawn_passengers) { + // If we've been called from do_capture_units, record the passengers in the list of units to be despawned after do_capture_units + // returns. We can't simply despawn the units now even by setting always_despawn_passengers because the despawning messes up an + // iterator over tile units inside do_capture_units. + if (ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN) { + FOR_UNITS_ON (uti, tile) + if (uti.unit->Body.Container_Unit == this->Body.ID) { + reserve (sizeof is->extra_capture_despawns[0], // item size + (void **)&is->extra_capture_despawns, // ptr to items + &is->extra_capture_despawns_capacity, // ptr to capacity + is->count_extra_capture_despawns); // count + is->extra_capture_despawns[is->count_extra_capture_despawns] = uti.unit; + is->count_extra_capture_despawns += 1; + } + + } else + is->always_despawn_passengers = true; + } + + Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); + + is->always_despawn_passengers = prev_always_despawn_passengers; + + change_unit_type_count (&leaders[owner_id], type_id, -1); +} + +bool __fastcall +patch_Unit_do_capture_units (Unit * this, int edx, int tile_x, int tile_y, int owner_civ_id) +{ + is->count_extra_capture_despawns = 0; + + bool tr = Unit_do_capture_units (this, __, tile_x, tile_y, owner_civ_id); + + // Here we rely on patch_Unit_despawn to remove despawned units from the list + while (is->count_extra_capture_despawns > 0) + patch_Unit_despawn (is->extra_capture_despawns[0], __, this->Body.ID, 0, 0, 0, 0, 0, 0); + + return tr; +} + +void __fastcall +patch_Map_Renderer_m71_Draw_Tiles (Map_Renderer * this, int edx, int param_1, int param_2, int param_3) +{ + // Restore the tile count if it was saved by recompute_resources. This is necessary because the Draw_Tiles method loops over all tiles. + if (is->saved_tile_count >= 0) { + p_bic_data->Map.TileCount = is->saved_tile_count; + is->saved_tile_count = -1; + } + + Map_Renderer_m71_Draw_Tiles (this, __, param_1, param_2, param_3); +} + +struct named_tile_entry * +get_named_tile_entry (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + int stored_ptr = 0; + if (! itable_look_up (&is->named_tile_map, (int)tile, &stored_ptr)) + return NULL; + return (struct named_tile_entry *)stored_ptr; +} + +bool +prompt_for_named_tile (char const * seed_name, char * out_name, int out_len) +{ + if ((out_name == NULL) || (out_len <= 0)) + return false; + out_name[0] = '\0'; + + PopupForm * popup = get_popup_form (); + if (popup == NULL) + return false; + + char seed_buf[101]; + if (seed_name == NULL) + seed_name = ""; + strncpy (seed_buf, seed_name, sizeof seed_buf); + seed_buf[(sizeof seed_buf) - 1] = '\0'; + if (seed_buf[0] == '\0') + strncpy (seed_buf, "Tile", sizeof seed_buf); + + set_popup_str_param (0, seed_buf, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "RENAME_CITY", 0x64, (int)seed_buf, 0x44, 0); + int sel = patch_show_popup (popup, __, 0, 0); + is->focused_tile = NULL; + if (sel != 0) + return false; + + if (temp_ui_strs[0][0] == '\0') + return true; + + strncpy (out_name, temp_ui_strs[0], out_len); + out_name[out_len - 1] = '\0'; + return true; +} + +void +handle_named_tile_menu_selection (void) +{ + int tile_x = is->named_tile_menu_tile_x; + int tile_y = is->named_tile_menu_tile_y; + Tile * tile = tile_at (tile_x, tile_y); + if (! tile_can_be_named (tile, tile_x, tile_y)) + return; + + init_tile_highlights (); + + struct named_tile_entry * entry = get_named_tile_entry (tile); + char const * current_name = (entry != NULL) ? entry->name : ""; + char new_name[100]; + is->focused_tile = tile; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + bool got_name = prompt_for_named_tile (current_name, new_name, sizeof new_name); + is->focused_tile = NULL; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + if (! got_name) + return; + + set_named_tile_entry (tile, tile_x, tile_y, new_name); + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +void __fastcall +patch_Main_Screen_Form_handle_right_click_on_tile (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) +{ + if (is->current_config.enable_named_tiles) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile_can_be_named (tile, tile_x, tile_y) && ! Tile_has_city (tile)) { + is->named_tile_menu_active = true; + is->named_tile_menu_tile_x = tile_x; + is->named_tile_menu_tile_y = tile_y; + Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); + is->named_tile_menu_active = false; + return; + } + } + + Main_Screen_Form_handle_right_click_on_tile (this, __, tile_x, tile_y, mouse_x, mouse_y); +} + +void __fastcall +patch_Main_Screen_Form_open_right_click_menu (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) +{ + bool set_active = false; + if (!is->named_tile_menu_active && is->current_config.enable_named_tiles) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile_can_be_named (tile, tile_x, tile_y)) { + is->named_tile_menu_active = true; + is->named_tile_menu_tile_x = tile_x; + is->named_tile_menu_tile_y = tile_y; + set_active = true; + } + } + Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); + if (set_active) + is->named_tile_menu_active = false; +} + +void +draw_map_tile_text (Main_Screen_Form * this, PCX_Image * canvas, char * text, int screen_x, int screen_y, int base_screen_height, int y_offset) +{ + int is_zoomed_out = (p_bic_data->is_zoomed_out != false); + int scale = is_zoomed_out ? 2 : 1; + int screen_width = 128 / scale; + int screen_height = base_screen_height / scale; + int text_width = screen_width - (is_zoomed_out ? 4 : 8); + if (text_width < 12) + text_width = screen_width; + + int text_left = screen_x + (screen_width - text_width) / 2; + int draw_y = screen_y - y_offset; + int text_top = draw_y + screen_height + (is_zoomed_out ? 2 : 4); + + Object_66C3FC * font = get_font (10, FSF_NONE); + if (font != NULL) { + PCX_Image_set_text_effects (canvas, __, 0x80FFFFFF, 0x80000000, 1, 1); + PCX_Image_draw_centered_text (canvas, __, font, text, text_left, text_top - 10, text_width, strlen (text)); + } +} + +void __fastcall +patch_Main_Screen_Form_draw_city_hud (Main_Screen_Form * this, int edx, PCX_Image * canvas) +{ + Main_Screen_Form_draw_city_hud (this, __, canvas); + + bool draw_natural_wonders = is->current_config.enable_natural_wonders && + is->current_config.show_natural_wonder_name_on_map; + bool draw_named_tiles = is->current_config.enable_named_tiles; + if (!draw_natural_wonders && !draw_named_tiles) + return; + + if (canvas == NULL) + canvas = &this->Base_Data.Canvas; + + if ((canvas == NULL) || (canvas->JGL.Image == NULL)) + return; + + if (draw_natural_wonders) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + + int natural_id = inst->natural_wonder_info.natural_wonder_id; + if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) + continue; + + struct natural_wonder_district_config const * nw_cfg = &is->natural_wonder_configs[natural_id]; + if ((nw_cfg == NULL) || (nw_cfg->name == NULL) || (nw_cfg->name[0] == '\0')) + continue; + + Tile * tile = (Tile *)tei.key; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int tile_x, tile_y; + if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + continue; + + int screen_x, screen_y; + Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); + + draw_map_tile_text (this, canvas, (char *)nw_cfg->name, screen_x, screen_y, 88, 88 - 64); + } + } + + if (draw_named_tiles) { + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if ((entry == NULL) || (entry->name[0] == '\0')) + continue; + + Tile * tile = (Tile *)tei.key; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int tile_x, tile_y; + if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) { + tile_x = entry->tile_x; + tile_y = entry->tile_y; + tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + } + + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) + continue; + + int screen_x, screen_y; + Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); + + draw_map_tile_text (this, canvas, entry->name, screen_x, screen_y, 64, 3); + } + } +} + +// Returns whether or not city has an "extra palace", a concept used by the AI multi-city start. Extra palaces are small wonders that reduce +// corruption (e.g. forbidden palace) that are listed under the ai_multi_start_extra_palaces config option. +bool +has_extra_palace (City * city) +{ + for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { + int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) && + (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && + (leaders[city->Body.CivID].Small_Wonders[improv_id] == city->Body.ID)) { + return true; + } + } + return false; +} + +// Removes any extra palaces from this city to other cities owned by the same player (if possible). Does not check that the city belongs to an AI or +// that AI MCS is enabled. +void +remove_extra_palaces (City * city, City * excluded_destination) +{ + Leader * leader = &leaders[city->Body.CivID]; + int extra_palace_lost; + do { + // Search for an extra palace in the city and delete it. Remember its ID so we can put it elsewhere. + extra_palace_lost = -1; + for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { + int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) && + (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && + (leader->Small_Wonders[improv_id] == city->Body.ID)) { + patch_City_add_or_remove_improvement (city, __, improv_id, 0, false); + extra_palace_lost = improv_id; + break; + } + } + + // Replace the lost extra palace like what happens to the real palace + if (extra_palace_lost >= 0) { + int best_rating = -1; + City * best_location = NULL; + FOR_CITIES_OF (coi, leader->ID) { + City * candidate = coi.city; + if ((candidate != city) && + (candidate->Body.ID != leader->CapitalID) && + (candidate != excluded_destination) && + ! has_extra_palace (candidate)) { + + // Rate this candidate as a possible (extra) palace location. The criteria we use to rate it are identical to + // what the base game uses to find a new location for the palace. + int rating = 0; + rating += candidate->Body.Population.Size; + rating += count_units_at (candidate->Body.X, candidate->Body.Y, UF_4, -1, 0, -1); + rating += 2 * City_count_citizens_of_race (candidate, __, leader->RaceID); + FOR_TILES_AROUND (tai, 0x121, candidate->Body.X, candidate->Body.Y) { + if (tai.n == 0) + continue; + City * neighbor = get_city_ptr (tai.tile->CityID); + if ((neighbor != NULL) && (neighbor != city) && (neighbor->Body.CivID == leader->ID)) { + int size = neighbor->Body.Population.Size; + if (size > p_bic_data->General.MaximumSize_City) rating += 3; + else if (size > p_bic_data->General.MaximumSize_Town) rating += 2; + else rating += 1; + } + } + + if (rating > best_rating) { + best_rating = rating; + best_location = candidate; + } + } + } + + if (best_location != NULL) + City_add_or_remove_improvement (best_location, __, extra_palace_lost, 1, false); + } + } while (extra_palace_lost >= 0); +} + +// Give a city any completed wonder districts in work radius, if cities_with_mutual_district_receive_wonders is true. +// This is essentially for cases where the original Wonder-constructing city is lost and a new city is built +// that can work the same wonder district tile. +void +grant_nearby_wonders_to_city (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_wonder_districts || + ! is->current_config.cities_with_mutual_district_receive_wonders || + (city == NULL)) + return; + + bool prev_flag = is->sharing_buildings_by_districts_in_progress; + is->sharing_buildings_by_districts_in_progress = true; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * tile = wai.tile; + + // Make sure Wonder is completed + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + struct wonder_district_info * info = &inst->wonder_info; + if ((info == NULL) || (info->state != WDS_COMPLETED)) continue; + + // Check that city doesn't already have the Wonder + int improv_id = get_wonder_improvement_id_from_index (info->wonder_index); + if (improv_id < 0) continue; + + if (patch_City_has_improvement (city, __, improv_id, false)) continue; + + // Small wonders use Leader.Small_Wonders as their canonical owner record. If the city + // just changed hands and the new owner already has that small wonder elsewhere, do not + // re-grant it from the nearby district or the capture can recreate a duplicate. + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) != 0) { + City * owning_city = get_city_ptr (leaders[city->Body.CivID].Small_Wonders[improv_id]); + if ((owning_city != NULL) && + (owning_city->Body.CivID == city->Body.CivID) && + ! city_radius_contains_tile (owning_city, x, y)) + continue; + } + + // Add the Wonder to the city + patch_City_add_or_remove_improvement (city, __, improv_id, 1, false); + } + + is->sharing_buildings_by_districts_in_progress = prev_flag; +} + +void +on_gain_city (Leader * leader, City * city, enum city_gain_reason reason) +{ + if (reason == CGR_FOUNDED) + is->turn_no_of_last_founding_for_settler_perfume[leader->ID] = *p_current_turn_no; + + // Handle extra palaces for AI multi-city start + if (((*p_human_player_bits & (1<ID)) == 0) && // If leader is an AI AND + (is->current_config.ai_multi_city_start > 1) && // AI multi-city start is enabled AND + (leader->Cities_Count > 1) && // city is not the only one the AI has (i.e. it's not the capital) AND + (reason != CGR_PLACED_FOR_SCENARIO) && (reason != CGR_PLACED_FOR_AI_MULTI_CITY_START)) { // city was not placed before the game started + + // Find an extra palace that this player does not already have + int free_extra_palace = -1; + for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { + int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) && + (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && + (NULL == get_city_ptr (leader->Small_Wonders[improv_id]))) { + free_extra_palace = improv_id; + break; + } + } + + // Place that extra palace here + if (free_extra_palace >= 0) + City_add_or_remove_improvement (city, __, free_extra_palace, 1, false); + } + + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + patch_City_recompute_yields_and_happiness (city); + patch_City_recompute_culture_income (city); + } + + if (is->current_config.enable_districts) { + + // Remove any district previously on the tile, if city just founded + if (reason == CGR_FOUNDED) { + Tile * city_tile = tile_at (city->Body.X, city->Body.Y); + if ((city_tile != NULL) && (city_tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (city_tile); + if (inst != NULL) + handle_district_removed (city_tile, inst->district_id, city->Body.X, city->Body.Y, false); + } + } + + bool receive_buildings = is->current_config.cities_with_mutual_district_receive_buildings; + bool receive_wonders = is->current_config.cities_with_mutual_district_receive_wonders; + + // Grant buildings and wonders from nearby completed districts owned by other cities of same civ, if enabled + if (receive_buildings) { + grant_existing_district_buildings_to_city (city); + } + + // Grant wonders nearby in same territory, regardless of city (i.e., orphaned wonders from destroyed cities), if enabled + if (receive_wonders) { + grant_nearby_wonders_to_city (city); + } + + if (is->current_config.enable_distribution_hub_districts) { + refresh_distribution_hubs_for_city (city); + } + } +} + +void +on_lose_city (Leader * leader, City * city, enum city_loss_reason reason) +{ + // If leader is an AI and AI MCS is enabled, remove any extra palaces the city has + if (((*p_human_player_bits & (1<ID)) == 0) && + (is->current_config.ai_multi_city_start > 1)) + remove_extra_palaces (city, NULL); + + if (is->current_config.enable_districts) { + if (is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; + + forget_pending_building_order (city); + for (int district_id = 0; district_id < is->district_count; district_id++) + clear_city_district_request (city, district_id); + + if (is->current_config.enable_wonder_districts) + release_wonder_district_reservation (city); + } else if (is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; +} + +// Returns -1 if the location is unusable, 0-9 if it's usable but doesn't satisfy all criteria, and 10 if it couldn't be better +int +eval_starting_location (Map * map, int const * alt_starting_locs, int alt_starting_loc_count, int tile_x, int tile_y, int civ_id) +{ + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != p_null_tile) && + (patch_Map_check_city_location (map, __, tile_x, tile_y, civ_id, true) == CLV_OK) && + (tile->vtable->m15_Check_Goody_Hut (tile, __, 0) == 0) && + (tile->vtable->m40_get_TileUnit_ID (tile) == -1)) { + int tr = 0; + + // Avoid this location if it's too close to another starting location. If it's much too close, it's ruled out entirely. + int closest_dist = INT_MAX; + for (int n = 1; n <= map->Civ_Count; n++) + if (map->Starting_Locations[n] >= 0) { + int other_x, other_y; + tile_index_to_coords (map, map->Starting_Locations[n], &other_x, &other_y); + int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); + if (dist < closest_dist) + closest_dist = dist; + } + for (int n = 0; n < alt_starting_loc_count; n++) + if (alt_starting_locs[n] >= 0) { + int other_x, other_y; + tile_index_to_coords (map, alt_starting_locs[n], &other_x, &other_y); + int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); + if (dist < closest_dist) + closest_dist = dist; + } + if (closest_dist < map->Civ_Distance/3) + return -1; + else if (closest_dist >= 2*map->Civ_Distance/3) + tr += 1; + + // Avoid tiny islands + // tr += map->vtable->m33_Get_Continent (map, __, tile->ContinentID)->Body.TileCount >= 20; + + // Avoid garbage terrain, e.g. all desert or tundra + int break_even_food_tiles = 0; + FOR_TILES_AROUND (tai, 21, tile_x, tile_y) { + if (tai.n == 0) + continue; // Skip tile that would be covered by the city + int tile_food = patch_Map_calc_food_yield_at (map, __, tai.tile_x, tai.tile_y, tai.tile->vtable->m50_Get_Square_BaseType (tai.tile), civ_id, 0, NULL); + int food_required = p_bic_data->General.FoodPerCitizen + (tai.tile->vtable->m35_Check_Is_Water (tai.tile) ? 1 : 0); + break_even_food_tiles += tile_food >= food_required; + } + tr += break_even_food_tiles >= 2; + + // Avoid wasting a food bonus + tr += (tile->ResourceType < 0) || (tile->ResourceType >= p_bic_data->ResourceTypeCount) || + (p_bic_data->ResourceTypes[tile->ResourceType].Food == 0); + + int max_score = 3; + return (10*tr)/max_score; + } else + return -1; +} + +City * +create_starter_city (Map * map, int civ_id, int tile_index) +{ + int x, y; + tile_index_to_coords (map, tile_index, &x, &y); + City * tr = Leader_create_city (&leaders[civ_id], __, x, y, leaders[civ_id].RaceID, -1, NULL, true); + if (tr != NULL) + on_gain_city (&leaders[civ_id], tr, CGR_PLACED_FOR_AI_MULTI_CITY_START); + return tr; +} + +void +set_up_ai_multi_city_start (Map * map, int city_count) +{ + // Set of bits determining which players are eligible for the two-city start + int eligibility_bits = 0, + count_eligible_civs = 0; + for (int n = 1; n < 32; n++) + if ((*p_player_bits & 1<Starting_Locations[n]) != p_null_tile)) { // has a valid starting location + eligibility_bits |= 1 << n; + count_eligible_civs++; + } + + if ((city_count < 1) || (count_eligible_civs == 0)) // if we have nothing to do + return; + + char load_text[50]; + snprintf (load_text, sizeof load_text, "%s...", is->c3x_labels[CL_CREATING_CITIES]); + load_text[(sizeof load_text) - 1] = '\0'; + Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); + + // Generate alternate sets of starting locations. We need one set for each extra city we're going to create per player. Each set only needs to + // include starting locations for eligible players, all others will be left as -1. + int alt_starting_loc_count = 32 * (city_count - 1); + int * alt_starting_locs = malloc (alt_starting_loc_count * sizeof *alt_starting_locs); { + for (int n = 0; n < alt_starting_loc_count; n++) + alt_starting_locs[n] = -1; + + for (int i_loc = 0; i_loc < alt_starting_loc_count; i_loc++) { + int civ_id = i_loc % 32; + if ((civ_id != 0) && (eligibility_bits & 1<current_config.max_tries_to_place_fp_city; try++) { + int i_loc = rand_int (p_rand_object, __, map->TileCount); + int x_loc, y_loc; + tile_index_to_coords (map, i_loc, &x_loc, &y_loc); + if ((x_loc >= 0) && (y_loc >= 0)) { + int val = eval_starting_location (map, alt_starting_locs, alt_starting_loc_count, x_loc, y_loc, civ_id); + if (val >= 10) { + best_loc_index = i_loc; + break; + } else if (val > best_loc_val) { + best_loc_val = val; + best_loc_index = i_loc; + } + } + } + + if (best_loc_index >= 0) + alt_starting_locs[i_loc] = best_loc_index; + } + } + } + + int count_cities_created = 0; + int count_eligible_civs_handled = 0; + for (int civ_id = 1; civ_id < 32; civ_id++) + if (eligibility_bits & 1<Starting_Locations[civ_id]; + + // Create the first starting city for the AI. This one is its capital and is located at its actual starting + // location. Afterward, delete its starting settler so it's as if the settler founded the city. + { + Unit * starting_settler = NULL; + FOR_UNITS_ON (tai, tile_at_index (map, sloc)) { + if (p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].AI_Strategy & UTAI_Settle) { + starting_settler = tai.unit; + break; + } + } + + create_starter_city (map, civ_id, sloc); + count_cities_created++; + + if (starting_settler != NULL) + patch_Unit_despawn (starting_settler, __, 0, 1, 0, 0, 0, 0, 0); + + } + + // Memoize all of the AI's starting units + clear_memo (); + FOR_UNITS_ON (tai, tile_at_index (map, sloc)) + memoize ((int)tai.unit); + + int extra_city_count = 0; + for (int i_city = 1; i_city < city_count; i_city++) { + int loc = alt_starting_locs[(i_city-1)*32 + civ_id]; + City * city; + if ((loc >= 0) && + (NULL != (city = create_starter_city (map, civ_id, loc)))) { + count_cities_created++; + extra_city_count++; + + // Spawn palace substitute in new city + if (extra_city_count-1 < is->current_config.count_ai_multi_start_extra_palaces) + patch_City_add_or_remove_improvement (city, __, is->current_config.ai_multi_start_extra_palaces[extra_city_count - 1], 1, true); + + // Move starting units over to the new city. Do this by moving every Nth unit where N is the number of extra + // cities we've founded so far plus one. ("Extra" cities are the ones created after the capital.) E.g., if + // this is the 1st city after the capital, move every 2nd unit to it. If it's the 2nd, move every 3rd, etc. + for (int n = 0; n < is->memo_len; n++) + if (n % (extra_city_count+1) == extra_city_count) + patch_Unit_move ((Unit *)is->memo[n], __, city->Body.X, city->Body.Y); + + } + } + + // Update progress report + count_eligible_civs_handled++; + int progress = 100 * count_eligible_civs_handled / count_eligible_civs; + snprintf (load_text, sizeof load_text, "%s %d%%", is->c3x_labels[CL_CREATING_CITIES], progress); + load_text[(sizeof load_text) - 1] = '\0'; + Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); + + } + + free (alt_starting_locs); + + // Sanity check + int any_adjacent_cities = 0; { + if (p_cities->Cities != NULL) + for (int city_index = 0; (city_index <= p_cities->LastIndex) && ! any_adjacent_cities; city_index++) { + City * city = get_city_ptr (city_index); + if (city != NULL) + FOR_TILES_AROUND (tai, 9, city->Body.X, city->Body.Y) + if ((tai.n > 0) && (NULL != get_city_ptr (tai.tile->vtable->m45_Get_City_ID (tai.tile)))) { + any_adjacent_cities = 1; + break; + } + } + } + int any_missing_fp_cities = (count_cities_created < city_count * count_eligible_civs); + if (any_adjacent_cities || any_missing_fp_cities) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[100]; + snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_FAILED_SANITY_CHECK]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + if (any_adjacent_cities) { + snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_ADJACENT_CITIES]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + if (any_missing_fp_cities) { + snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_MISSING_CITIES]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + patch_show_popup (popup, __, 0, 0); + } +} + +void __fastcall +patch_Map_process_after_placing (Map * this, int edx, bool param_1) +{ + if ((is->current_config.ai_multi_city_start > 0) && (*p_current_turn_no == 0)) + set_up_ai_multi_city_start (this, is->current_config.ai_multi_city_start); + + Map_process_after_placing (this, __, param_1); +} + +void __fastcall +patch_Map_impl_generate (Map * this, int edx, int seed, bool is_multiplayer_game, int num_seafaring_civs) +{ + Map_impl_generate (this, __, seed, is_multiplayer_game, num_seafaring_civs); + + if (is->current_config.enable_natural_wonders) + place_natural_wonders_on_map (); +} + +int __fastcall +patch_City_get_net_commerce (City * this, int edx, int kind, bool include_science_age) +{ + int base = City_get_net_commerce (this, __, kind, include_science_age); + + if ((kind == 1) && // beakers, as opposed to 2 which is gold + (is->current_config.ai_research_multiplier != 100) && + ((*p_human_player_bits & 1<Body.CivID) == 0)) + return (base * is->current_config.ai_research_multiplier + 50) / 100; + else + return base; +} + +// Cuts research spending while total expenditures > treasury. Returns whether spending has been cut. +bool +cut_unaffordable_research_spending (Leader * leader, bool skip_popup) +{ + // The rate cap limits AI players' spending on the gold slider (in Leader::ai_adjust_sliders) however it does not apply to human players when + // adjusting sliders manually on the domestic advisor screen. + int gold_rate_cap = ((*p_human_player_bits & 1<ID) != 0) ? 10 : p_bic_data->Governments[leader->GovernmentType].RateCap; + + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + bool reduced_spending = false; + while (leader->science_slider > 0 && + leader->gold_slider < gold_rate_cap && + treasury + Leader_compute_income (leader) < 0) { + leader->science_slider -= 1; + leader->gold_slider += 1; + Leader_recompute_economy (leader); + reduced_spending = true; + } + if (reduced_spending && ! skip_popup && leader->ID == p_main_screen_form->Player_CivID) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_CUT_RESEARCH_SPENDING", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + return reduced_spending; +} + +void __fastcall +adjust_sliders_preproduction (Leader * this) +{ + if ((*p_human_player_bits & 1<ID) == 0) { + // Replicate the behavior of the original code for AI players. (apply_machine_code_edits overwrites an equivalent branch & call in the + // original code with a call to this method.) + this->vtable->ai_adjust_sliders (this); + + // If aggressively penalize bankruptcy is on, cut the AI's research spending if it can't afford it. This may be redundant as + // ai_adjust_sliders will already cut AI spending but maybe not all the way to zero. Do this only every third turn so the AI is not + // completely prevented from researching. + if (is->current_config.aggressively_penalize_bankruptcy && (*p_current_turn_no + this->ID) % 3 == 0) + cut_unaffordable_research_spending (this, true); + + // If human player would go bankrupt, try reducing their research spending to avoid that + } else if (is->current_config.cut_research_spending_to_avoid_bankruptcy) + cut_unaffordable_research_spending (this, false); +} + +int __fastcall +patch_City_get_improvement_maintenance (City * this, int edx, int improv_id) +{ + // Check if this improvment is provided for free by another player via shared wonder effects + int civ_id = this->Body.CivID; + bool free_from_sharing = false; + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << civ_id) & *p_human_player_bits)) { // is this city owned by a human player + + // Check if any other human player in the game has this improv in their auto improvs table, including for this city's continent + bool has_free_improv = false; + Tile * city_tile = tile_at (this->Body.X, this->Body.Y); + int continent_id = city_tile->vtable->m46_Get_ContinentID (city_tile); + int cont_coded_key = (continent_id + 1) * p_bic_data->ImprovementsCount + improv_id;; + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != civ_id)) + if (Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, improv_id , NULL) || + Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, cont_coded_key, NULL)) { + free_from_sharing = true; + break; + } + player_bits >>= 1; + n_player++; + } + } + + if (! free_from_sharing) + return City_get_improvement_maintenance (this, __, improv_id); + else + return 0; +} + +int __fastcall +patch_Leader_count_maintenance_free_units (Leader * this) +{ + if ((is->current_config.extra_unit_maintenance_per_shields <= 0) && (this->ID != 0)) + return Leader_count_maintenance_free_units (this); + else { + int tr = 0; + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if ((unit != NULL) && (unit->Body.CivID == this->ID)) { + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + + // If this is a free unit + if ((unit->Body.RaceID != this->RaceID) || (type->requires_support == 0)) + tr++; + + // If this unit belongs to the barbs and has a tribe ID set (indicating it was spawned in a barb camp) then count it + // as a free unit in order not to bankrupt the barb player if the barb player controls any cities. A tribe ID of 75 is + // the generic ID that's assigned to barb units when they're spawned with no specific tribe ID. + else if ((unit->Body.CivID == 0) && (unit->Body.barb_tribe_id >= 0) && (unit->Body.barb_tribe_id < 75)) + tr++; + + // Otherwise, if we're configured to apply extra maintenance based on shield cost, reduce the free unit count by + // however many times this unit's cost is above the threshold for extra maintenace. It's alright if the resulting free + // unit count is negative since all callers of this function subtract its return value from the total unit count to + // obtain the count of units that must be paid for. + else if (is->current_config.extra_unit_maintenance_per_shields > 0) + tr -= type->Cost / is->current_config.extra_unit_maintenance_per_shields; + } + } + return tr; + } +} + +int __fastcall +patch_Leader_sum_unit_maintenance (Leader * this, int edx, int government_id) +{ + if (is->current_config.extra_unit_maintenance_per_shields <= 0) + return Leader_sum_unit_maintenance (this, __, government_id); + else if (this->Cities_Count > 0) { + int maint_free_count = patch_Leader_count_maintenance_free_units (this); + int cost_per_unit, base_free_count; + get_unit_support_info (this->ID, government_id, &cost_per_unit, &base_free_count); + int ai_free_count; { + if (*p_human_player_bits & 1<ID) + ai_free_count = 0; + else { + Difficulty_Level * difficulty = &p_bic_data->DifficultyLevels[*p_game_difficulty]; + ai_free_count = difficulty->Bonus_For_Each_City * this->Cities_Count + difficulty->Additional_Free_Support; + } + } + return not_below (0, (this->Unit_Count - base_free_count - ai_free_count - maint_free_count) * cost_per_unit); + } else + return 0; +} + +int +sum_improvements_maintenance_to_pay (Leader * leader, int govt_id) +{ + if (is->current_config.aggressively_penalize_bankruptcy) + // We're going to replace the logic that charges maintenance, and the replacement will charge both unit & building maintenance b/c + // they're intertwined under the new rules. Return zero here so the base game code doesn't charge any building maintenance on its own. + return 0; + else + return Leader_sum_improvements_maintenance (leader, __, govt_id); +} + +// The sum_improvements_maintenance function is called in two places as part of the randomization of whether improv or unit maintenance gets paid +// first. Redirect both of these calls to one function of our own. +int __fastcall patch_Leader_sum_improv_maintenance_to_pay_1 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } +int __fastcall patch_Leader_sum_improv_maintenance_to_pay_2 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } + +int +compare_buildings_to_sell (void const * a, void const * b) +{ + int maint_a = (*(int const *)a >> 26) & 31, + maint_b = (*(int const *)b >> 26) & 31; + return maint_b - maint_a; +} + +// Returns the final improv cost after buildings were sold +int +sell_unaffordable_buildings (Leader * leader, int improv_cost, int unit_cost) +{ + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + + clear_memo (); + + // Memoize all buildings this player owns that we might potentially sell. B/c the memo can only contain ints, we must pack the maintenance + // cost, improv ID, and city ID all into one int. The city ID is stored in the lowest 13 bits, then the improv ID in the next 13, and finally + // the maintenance amount in the 5 above those. + FOR_CITIES_OF (coi, leader->ID) + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * improv = &p_bic_data->Improvements[n]; + + int unsellable_flags = + ITF_Center_of_Empire | + ITF_50_Luxury_Output | + ITF_50_Tax_Output | + ITF_Reduces_Corruption | + ITF_Increases_Luxury_Trade | + ITF_Allows_City_Level_2 | + ITF_Allows_City_Level_3 | + ITF_Capitalization | + ITF_Allows_Water_Trade | + ITF_Allows_Air_Trade | + ITF_Increases_Shields_In_Water | + ITF_Increases_Food_In_Water | + ITF_Increases_Trade_In_Water; + + // Only sell improvements that aren't contributing gold, even indirectly through e.g. happiness or boosting shield production + // for Wealth + bool sellable = + ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) == 0) && + ((improv->ImprovementFlags & unsellable_flags) == 0) && + (improv->Happy_Faces_All <= 0) && (improv->Happy_Faces <= 0) && + (improv->Production <= 0); + + if (sellable && patch_City_has_improvement (coi.city, __, n, 0)) { + int maint = patch_City_get_improvement_maintenance (coi.city, __, n); + if (maint > 0) + memoize ((not_above (31, maint) << 26) | (n << 13) | coi.city_id); + } + } + + // Sort the list of buildings so the highest maintenance ones come first + qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_buildings_to_sell); + + // Sell buildings until we can cover maintenance costs or until we run out of ones to sell + int count_sold = 0; + while ((improv_cost + unit_cost > treasury) && (count_sold < is->memo_len)) { + int improv_id = ((1<<13) - 1) & (is->memo[count_sold] >> 13), + city_id = ((1<<13) - 1) & is->memo[count_sold]; + City * city = get_city_ptr (city_id); + improv_cost -= patch_City_get_improvement_maintenance (city, __, improv_id); + City_sell_improvement (city, __, improv_id, false); + treasury = leader->Gold_Encoded + leader->Gold_Decrement; + count_sold++; + } + + // Show popup informing the player that their buildings were force sold + if ((leader->ID == p_main_screen_form->Player_CivID) && ! is_online_game ()) { + PopupForm * popup = get_popup_form (); + if (count_sold == 1) { + int improv_id = ((1<<13) - 1) & (is->memo[0] >> 13), + city_id = ((1<<13) - 1) & is->memo[0]; + set_popup_str_param (0, get_city_ptr (city_id)->Body.CityName , -1, -1); + set_popup_str_param (1, p_bic_data->Improvements[improv_id].Name.S, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_SINGLE_IMPROV", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } else if (count_sold > 1) { + set_popup_int_param (0, count_sold); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_MULTIPLE_IMPROVS", -1, 0, 0, 0); + + // Add list of sold improvements to popup + for (int n = 0; n < count_sold; n++) { + int improv_id = ((1<<13) - 1) & (is->memo[n] >> 13), + city_id = ((1<<13) - 1) & is->memo[n]; + char s[200]; + snprintf (s, sizeof s, "^ %s in %s", + p_bic_data->Improvements[improv_id].Name.S, + get_city_ptr (city_id)->Body.CityName); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + + patch_show_popup (popup, __, 0, 0); + } + } + + return improv_cost; +} + +// Returns the final unit cost after disbanding +int +disband_unaffordable_units (Leader * leader, int improv_cost, int unit_cost, int cost_per_unit) +{ + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + int count_disbanded = 0; + Unit * to_disband; + char first_disbanded_name[32]; + while ((improv_cost + unit_cost > treasury) && + (unit_cost > 0) && + (NULL != (to_disband = leader->vtable->find_unsupported_unit (leader)))) { + if (count_disbanded == 0) { + char const * name_src = (to_disband->Body.Custom_Name.S[0] == '\0') + ? p_bic_data->UnitTypes[to_disband->Body.UnitTypeID].Name + : to_disband->Body.Custom_Name.S; + strncpy (first_disbanded_name, name_src, sizeof first_disbanded_name); + first_disbanded_name[(sizeof first_disbanded_name) - 1] = '\0'; + } + Unit_disband (to_disband); + count_disbanded++; + unit_cost -= cost_per_unit; + } + + // Show popup informing the player that their units were disbanded + if (leader->ID == p_main_screen_form->Player_CivID) { + PopupForm * popup = get_popup_form (); + if (count_disbanded == 1) { + set_popup_str_param (0, first_disbanded_name, -1, -1); + int online_flag = is_online_game () ? 0x4000 : 0; + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_SINGLE_UNIT", -1, 0, online_flag, 0); + patch_show_popup (popup, __, 0, 0); + } else if ((count_disbanded > 1) && ! is_online_game ()) { + set_popup_int_param (0, count_disbanded); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_MULTIPLE_UNITS", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + } + + return unit_cost; +} + +int +compare_cities_by_production (void const * vp_id_a, void const * vp_id_b) +{ + City * a = get_city_ptr (*(int const *)vp_id_a), + * b = get_city_ptr (*(int const *)vp_id_b); + return a->Body.ProductionIncome - b->Body.ProductionIncome; +} + +void +charge_maintenance_with_aggressive_penalties (Leader * leader) +{ + int cost_per_unit; + get_unit_support_info (leader->ID, leader->GovernmentType, &cost_per_unit, NULL); + + int improv_cost = Leader_sum_improvements_maintenance (leader, __, leader->GovernmentType); + + int unit_cost = 0; { + if (leader->Cities_Count > 0) // Players with no cities don't pay unit maintenance, per the original game rules + if (cost_per_unit > 0) { + int count_free_units = Leader_get_free_unit_count (leader, __, leader->GovernmentType) + patch_Leader_count_maintenance_free_units (leader); + unit_cost += not_below (0, (leader->Unit_Count - count_free_units) * cost_per_unit); + } + } + + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + if (improv_cost + unit_cost > treasury) { + + // For AIs, alternate between selling buildings and disbanding units when maintenance can't be paid + if (((1<ID & *p_human_player_bits) != 0) || ((leader->ID + *p_current_turn_no) % 2 == 0)) { + improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); + unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); + } else { + unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); + improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); + } + + treasury = leader->Gold_Encoded + leader->Gold_Decrement; // Update b/c selling buildings recovers some gold + + // If the player still can't afford maintenance, even after all that, start switching their cities to Wealth + int wealth_income = 0; + if (improv_cost + unit_cost > treasury + wealth_income) { + // Memoize all cities not already building wealth and sort by production (lowest first) + clear_memo (); + FOR_CITIES_OF (coi, leader->ID) + if ((coi.city->Body.Status & CSF_Capitalization) == 0) + memoize (coi.city_id); + qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_cities_by_production); + + int wealth_improv_id = -1; { + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { + wealth_improv_id = n; + break; + } + } + + if (wealth_improv_id >= 0) { + int n = 0, + switched_any = 0; + + while ((n < is->memo_len) && (improv_cost + unit_cost > treasury + wealth_income)) { + City * city = get_city_ptr (is->memo[n]); + City_set_production (city, __, COT_Improvement, wealth_improv_id, false); + switched_any = 1; + wealth_income += City_get_income_from_wealth_build (city); + n++; + } + + if (switched_any && (leader->ID == p_main_screen_form->Player_CivID)) { + PopupForm * popup = get_popup_form (); + Improvement * wealth = &p_bic_data->Improvements[wealth_improv_id]; + set_popup_str_param (0, wealth->Name.S, -1, -1); + set_popup_str_param (1, wealth->CivilopediaEntry.S, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_BUILD_WEALTH", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + } + } + } + + Leader_set_treasury (leader, __, treasury - improv_cost - unit_cost); +} + +bool __fastcall +patch_Unit_has_king_ability_for_find_unsupported (Unit * this, int edx, enum UnitTypeAbilities king_ability) +{ + // If we're set to aggressively penalize bankruptcy and this unit doesn't require support, return that it is a king so it doesn't get + // disbanded. + if (is->current_config.aggressively_penalize_bankruptcy && ! p_bic_data->UnitTypes[this->Body.UnitTypeID].requires_support) + return true; + + else + return Unit_has_ability (this, __, king_ability); +} + +void __fastcall +patch_Leader_pay_unit_maintenance (Leader * this) +{ + if (! is->current_config.aggressively_penalize_bankruptcy) + Leader_pay_unit_maintenance (this); + else + charge_maintenance_with_aggressive_penalties (this); +} + +void __fastcall +patch_Main_Screen_Form_show_wltk_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) +{ + patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); +} + +void __fastcall +patch_Main_Screen_Form_show_wltk_ended_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) +{ + patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); +} + +char __fastcall +patch_Tile_has_city_for_agri_penalty_exception (Tile * this) +{ + return is->current_config.no_penalty_exception_for_agri_fresh_water_city_tiles ? 0 : Tile_has_city (this); +} + +int +show_razing_popup (void * popup_object, int popup_param_1, int popup_param_2, int razing_option) +{ + int response = patch_show_popup (popup_object, __, popup_param_1, popup_param_2); + if (is->current_config.prevent_razing_by_players && (response == razing_option)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_RAZE", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + return 0; + } + return response; +} + +int __fastcall patch_show_popup_option_1_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 1); } +int __fastcall patch_show_popup_option_2_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 2); } + +int __fastcall +patch_Context_Menu_add_abandon_city (Context_Menu * this, int edx, int item_id, char * text, bool checkbox, Sprite * image) +{ + if (is->current_config.prevent_razing_by_players) + return 0; // Return value is ignored by the caller + else + return Context_Menu_add_item (this, __, item_id, text, checkbox, image); +} + +char * +check_pedia_upgrades_to_ptr (TextBuffer * this, char * str) +{ + Civilopedia_Form * pedia = p_civilopedia_form; + UnitType * unit_type = NULL; + if (is->current_config.indicate_non_upgradability_in_pedia && + (pedia->Current_Article_ID >= 0) && (pedia->Current_Article_ID <= pedia->Max_Article_ID) && + (NULL != (unit_type = pedia->Articles[pedia->Current_Article_ID]->unit_type)) && + ((unit_type->Special_Actions & UCV_Upgrade_Unit) == 0)) + return is->c3x_labels[CL_OBSOLETED_BY]; + else + return TextBuffer_check_ptr (this, __, str); +} + +char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_1 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } +char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_2 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } + +bool __fastcall +patch_Unit_select_stealth_attack_target (Unit * this, int edx, int target_civ_id, int x, int y, bool allow_popup, Unit ** out_selected_target) +{ + is->added_any_stealth_target = 0; + return Unit_select_stealth_attack_target (this, __, target_civ_id, x, y, allow_popup, out_selected_target); +} + +bool __fastcall +patch_Unit_can_stealth_attack (Unit * this, int edx, Unit * target) +{ + bool tr = Unit_can_stealth_attack (this, __, target); + + // If we're selecting a target for stealth attack via bombardment, we must filter out candidates we can't damage that way + if (tr && is->selecting_stealth_target_for_bombard && + ! can_damage_bombarding (&p_bic_data->UnitTypes[this->Body.UnitTypeID], target, tile_at (target->Body.X, target->Body.Y))) + return false; + + else if (tr && is->current_config.exclude_invisible_units_from_stealth_attack && ! patch_Unit_is_visible_to_civ (target, __, this->Body.CivID, 1)) + return false; + + else if (tr && is->current_config.exclude_passengers_from_stealth_attack && get_unit_ptr (target->Body.Container_Unit) != NULL) + return false; + + else + return tr; +} + +int __fastcall +patch_Tile_check_water_for_stealth_attack (Tile * this) +{ + // When stealth attack bombard is enabled, remove a special rule inside can_stealth_attack that prevents land units from stealth attacking + // onto sea tiles. This allows land artillery to stealth attack naval units. + return is->current_config.enable_stealth_attack_via_bombardment ? 0 : this->vtable->m35_Check_Is_Water (this); +} + +int __fastcall +patch_PopupSelection_add_stealth_attack_target (PopupSelection * this, int edx, char * text, int value) +{ + if (is->current_config.include_stealth_attack_cancel_option && (! is->added_any_stealth_target)) { + PopupSelection_add_item (this, __, is->c3x_labels[CL_NO_STEALTH_ATTACK], -1); + is->added_any_stealth_target = 1; + } + + Unit * unit; + if (is->current_config.show_hp_of_stealth_attack_options && + ((unit = get_unit_ptr (value)) != NULL)) { + char s[500]; + int max_hp = Unit_get_max_hp (unit); + snprintf (s, sizeof s, "(%d/%d) %s", max_hp - unit->Body.Damage, max_hp, text); + s[(sizeof s) - 1] = '\0'; + return PopupSelection_add_item (this, __, s, value); + } else + return PopupSelection_add_item (this, __, text, value); +} + +void __fastcall +patch_Unit_perform_air_recon (Unit * this, int edx, int x, int y) +{ + int moves_plus_one = this->Body.Moves + p_bic_data->General.RoadsMovementRate; + + bool was_intercepted = false; + if (is->current_config.intercept_recon_missions) { + // Temporarily add vision on the target tile so the game plays the animation if the unit is show down by ground AA + Tile_Body * tile = &tile_at (x, y)->Body; + int saved_vis = tile->Visibility; + tile->Visibility |= 1 << this->Body.CivID; + was_intercepted = Unit_try_flying_over_tile (this, __, x, y); + tile->Visibility = saved_vis; + } + + if (! was_intercepted) { + Unit_perform_air_recon (this, __, x, y); + if (is->current_config.charge_one_move_for_recon_and_interception) + this->Body.Moves = moves_plus_one; + } +} + +int __fastcall +patch_Unit_get_interceptor_max_moves (Unit * this) +{ + // Stop fighters from intercepting multiple times per turn without blitz + if (is->current_config.charge_one_move_for_recon_and_interception && + (this->Body.Status & USF_USED_ATTACK != 0) && ! UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Blitz)) + return 0; + + else + return patch_Unit_get_max_move_points (this); +} + +int __fastcall +patch_Unit_get_moves_after_interception (Unit * this) +{ + if (is->current_config.charge_one_move_for_recon_and_interception) { + this->Body.Status |= USF_USED_ATTACK; // Set status bit indicating that the interceptor has attacked this turn + return this->Body.Moves + p_bic_data->General.RoadsMovementRate; + } else + return patch_Unit_get_max_move_points (this); +} + +void __fastcall +patch_Unit_set_state_after_interception (Unit * this, int edx, int new_state) +{ + if (! is->current_config.charge_one_move_for_recon_and_interception) + Unit_set_state (this, __, new_state); + + // If fighters are supposed to be able to intercept multiple times per turn, then we can't knock them out of the interception state as soon as + // they intercept something like in the base game. Instead, record this interception event so that we can clear their state at the start of + // their next turn. + else { + struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->Body.CivID]; + reserve (sizeof irl->items[0], (void **)&irl->items, &irl->capacity, irl->count); + irl->items[irl->count++] = (struct interception) { + .unit_id = this->Body.ID, + .x = this->Body.X, + .y = this->Body.Y + }; + } +} + +// Goes through every entry in a table with unit IDs as keys and filters out any that belong to the given owner (or are invalid). +void +remove_unit_id_entries_owned_by (struct table * t, int owner_id) +{ + if (t->len > 0) { + clear_memo (); + FOR_TABLE_ENTRIES (tei, t) { + Unit * unit = get_unit_ptr (tei.key); + if ((unit == NULL) || (unit->Body.CivID == owner_id)) + memoize (tei.key); + } + for (int n = 0; n < is->memo_len; n++) + itable_remove (t, is->memo[n]); + } +} + +void __fastcall +patch_Leader_begin_turn (Leader * this) +{ + if (is->aerodrome_airlift_usage.len > 0) { + int civ_bit = 1 << this->ID; + clear_memo (); + FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { + int mask = tei.value; + if (mask & civ_bit) { + int new_mask = mask & ~civ_bit; + memoize (tei.key); + memoize (new_mask); + } + } + for (int n = 0; n < is->memo_len; n += 2) { + int key = is->memo[n]; + int new_mask = is->memo[n + 1]; + if (new_mask == 0) + itable_remove (&is->aerodrome_airlift_usage, key); + else + itable_insert (&is->aerodrome_airlift_usage, key, new_mask); + } + clear_memo (); + } + + // Eject trespassers + is->do_not_bounce_invisible_units = true; + if (is->current_config.disallow_trespassing && (*p_current_turn_no > 0)) + for (int n = 1; n < 32; n++) + if ((*p_player_bits & (1 << n)) && + (n != this->ID) && + (! this->At_War[n]) && + ((this->Relation_Treaties[n] & 2) == 0)) // Check right of passage + Leader_bounce_trespassing_units (&leaders[n], __, this->ID); + is->do_not_bounce_invisible_units = false; + + if (is->current_config.introduce_all_human_players_at_start_of_hotseat_game && + (*p_current_turn_no == 0) && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((*p_human_player_bits & (1 << this->ID)) != 0)) + for (int n = 0; n < 32; n++) + if (*p_human_player_bits & (1 << n)) + Leader_make_contact (this, __, n, false); + + Leader_begin_turn (this); +} + +void __fastcall +patch_Leader_begin_unit_turns (Leader * this) +{ + // Reset the states of all fighters that performed an interception on the previous turn. + struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->ID]; + for (int n = 0; n < irl->count; n++) { + struct interception * record = &irl->items[n]; + Unit * interceptor = get_unit_ptr (record->unit_id); + if ((interceptor != NULL) && + (interceptor->Body.CivID == this->ID) && + (interceptor->Body.X == record->x) && + (interceptor->Body.Y == record->y) && + (interceptor->Body.UnitState == UnitState_Intercept)) + Unit_set_state (interceptor, __, 0); + } + irl->count = 0; + + // Reset extra defensive bombard and airdrop counters + remove_unit_id_entries_owned_by (&is->extra_defensive_bombards, this->ID); + remove_unit_id_entries_owned_by (&is->airdrops_this_turn , this->ID); + remove_unit_id_entries_owned_by (&is->unit_transport_ties , this->ID); + + clear_memo (); + if (is->current_config.delete_off_map_ai_units && + ((*p_human_player_bits & (1 << this->ID)) == 0) && + (p_units->Units != NULL)) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit_Body * body = p_units->Units[n].Unit; + if ((body != NULL) && + ((int)body != offsetof (Unit, Body)) && + (body->CivID == this->ID) && + ! Map_in_range (&p_bic_data->Map, __, body->X, body->Y)) + memoize (body->ID); + } + for (int n = 0; n < is->memo_len; n++) + patch_Unit_despawn (get_unit_ptr (is->memo[n]), __, 0, 1, 0, 0, 0, 0, 0); + + Leader_begin_unit_turns (this); +} + +Unit * __fastcall +patch_Fighter_find_actual_bombard_defender (Fighter * this, int edx, Unit * bombarder, int tile_x, int tile_y, int bombarder_civ_id, bool land_lethal, bool sea_lethal) +{ + if (is->bombard_stealth_target == NULL) + return Fighter_find_defender_against_bombardment (this, __, bombarder, tile_x, tile_y, bombarder_civ_id, land_lethal, sea_lethal); + else + return is->bombard_stealth_target; +} + +Unit * +select_stealth_attack_bombard_target (Unit * unit, int tile_x, int tile_y) +{ + bool land_lethal = Unit_has_ability (unit, __, UTA_Lethal_Land_Bombardment), + sea_lethal = Unit_has_ability (unit, __, UTA_Lethal_Sea_Bombardment); + Unit * defender = Fighter_find_defender_against_bombardment (&p_bic_data->fighter, __, unit, tile_x, tile_y, unit->Body.CivID, land_lethal, sea_lethal); + if (defender != NULL) { + Unit * target; + is->selecting_stealth_target_for_bombard = 1; + bool got_one = patch_Unit_select_stealth_attack_target (unit, __, defender->Body.CivID, tile_x, tile_y, true, &target); + is->selecting_stealth_target_for_bombard = 0; + return got_one ? target : NULL; + } else + return NULL; +} + +bool __fastcall +patch_Unit_try_flying_for_precision_strike (Unit * this, int edx, int x, int y) +{ + bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); + if (is->current_config.polish_precision_striking && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) && + ! is_cruise_missile) + // This method returns -1 when some kind of error occurs. In that case, return true implying the unit was shot down so the caller + // doesn't do anything more. Otherwise, return false so it goes ahead and applies damage. + return Unit_play_bombard_fire_animation (this, __, x, y) == -1; + + else if (is->current_config.polish_precision_striking && is_cruise_missile) { + Unit_animate_cruise_missile_strike (this, __, x, y); + return false; + + } else + return Unit_try_flying_over_tile (this, __, x, y); +} + +void __fastcall +patch_Unit_play_bombing_anim_for_precision_strike (Unit * this, int edx, int x, int y) +{ + // Only play the bombing animation here if we haven't already played an animation in the above method. We don't want to play all animations + // here since the bombard fire animation can fail for whatever reason but this method can't handle failure. + bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); + if ((! is->current_config.polish_precision_striking) || + ((p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && ! is_cruise_missile)) + Unit_play_bombing_animation (this, __, x, y); +} + +int __fastcall +patch_Unit_play_anim_for_bombard_tile (Unit * this, int edx, int x, int y) +{ + Unit * stealth_attack_target = NULL; + if (((p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && + is->current_config.enable_stealth_attack_via_bombardment && + (! is_online_game ()) && + patch_Leader_is_tile_visible (&leaders[this->Body.CivID], __, x, y)) + is->bombard_stealth_target = select_stealth_attack_bombard_target (this, x, y); + + return Unit_play_bombard_fire_animation (this, __, x, y); +} + +void __fastcall +patch_Main_Screen_Form_issue_precision_strike_cmd (Main_Screen_Form * this, int edx, Unit * unit) +{ + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + if ((! is->current_config.polish_precision_striking) || (type->Unit_Class == UTC_Air)) + Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); + else { + // issue_precision_strike_cmd will use the unit type's operational range. To make it use bombard range instead, place that value in + // the operational range field temporarily. Conveniently, it's only necessary to do this temporary switch once, here, because the main + // screen form stores a copy of the range for its own use and the method to actually perform the strike doesn't check the range. + int saved_op_range = type->OperationalRange; + type->OperationalRange = type->Bombard_Range; + Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); + type->OperationalRange = saved_op_range; + } +} + +int __fastcall +patch_Map_compute_neighbor_index_for_cm_strike (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + int tr = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); + + if ((tr >= 0) && + (is->bombarding_unit != NULL) && + ((p_bic_data->UnitTypes[is->bombarding_unit->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && + is->current_config.enable_stealth_attack_via_bombardment && + (! is_online_game ()) && + patch_Leader_is_tile_visible (&leaders[is->bombarding_unit->Body.CivID], __, x_neigh, y_neigh)) + is->bombard_stealth_target = select_stealth_attack_bombard_target (is->bombarding_unit, x_neigh, y_neigh); + + return tr; +} + +int __fastcall +patch_rand_bombard_target (void * this, int edx, int lim) +{ + // If we have a bombard stealth attack target set then return 2 so that the bombard damage will be applied to units not pop or buildings. + return (is->bombard_stealth_target == NULL) ? rand_int (this, __, lim) : 2; +} + +int __fastcall +patch_rand_int_to_dodge_city_aa (void * this, int edx, int lim) +{ + int tr = rand_int (this, __, lim); + is->result_of_roll_to_dodge_city_aa = tr; + return tr; +} + +int __fastcall +patch_Unit_get_defense_to_dodge_city_aa (Unit * this) +{ + int defense = Unit_get_defense_strength (this); + if (is->current_config.show_message_after_dodging_sam && + (defense > is->result_of_roll_to_dodge_city_aa) && + (this->Body.CivID == p_main_screen_form->Player_CivID)) + show_map_specific_text (this->Body.X, this->Body.Y, is->c3x_labels[CL_DODGED_SAM], 0); + return defense; +} + +int __fastcall +patch_Unit_get_defense_to_find_bombard_defender (Unit * this) +{ + // The caller is filtering out candidates with zero defense strength as possible targets to receive damage from bombardment. We can return 0 + // here to make sure "this" unit is not targeted. + + Unit * container; + + if (is->current_config.immunize_aircraft_against_bombardment && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air)) + return 0; + + else if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return 0; + + else + return Unit_get_defense_strength (this); +} + +int __cdecl +patch_get_WindowsFileBox_from_ini (LPCSTR key, int param_2, int param_3) +{ + // If the file path has already been determined, then avoid using the Windows file picker. This makes the later code to insert the path easier + // since we only have to intercept the opening of the civ-style file picker instead of both that and the Windows one. + if (is->load_file_path_override == NULL) + return get_int_from_conquests_ini (key, param_2, param_3); + else + return 0; +} + +char const * __fastcall +patch_do_open_load_game_file_picker (void * this) +{ + if (is->load_file_path_override != NULL) { + char const * tr = is->load_file_path_override; + is->load_file_path_override = NULL; + return tr; + } else + return open_load_game_file_picker (this); +} + +int __fastcall +patch_show_intro_after_load_popup (void * this, int edx, int param_1, int param_2) +{ + if (! is->suppress_intro_after_load_popup) + return patch_show_popup (this, __, param_1, param_2); + else { + is->suppress_intro_after_load_popup = 0; + return 0; + } +} + +void __fastcall patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id); + +void * __cdecl +patch_do_load_game (char * param_1) +{ + void * tr = do_load_game (param_1); + + if (is->current_config.restore_unit_directions_on_game_load && (p_units->Units != NULL)) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if ((unit != NULL) && (unit->Body.UnitState != UnitState_Fortifying)) { + if (Map_in_range (&p_bic_data->Map, __, unit->Body.X, unit->Body.Y) && + Map_in_range (&p_bic_data->Map, __, unit->Body.PrevMoveX, unit->Body.PrevMoveY)) { + int dx = unit->Body.X - unit->Body.PrevMoveX, dy = unit->Body.Y - unit->Body.PrevMoveY; + int dir = -1; + if ((dx == 1) && (dy == -1)) dir = DIR_NE; + else if ((dx == 2) && (dy == 0)) dir = DIR_E; + else if ((dx == 1) && (dy == 1)) dir = DIR_SE; + else if ((dx == 0) && (dy == 2)) dir = DIR_S; + else if ((dx == -1) && (dy == 1)) dir = DIR_SW; + else if ((dx == -2) && (dy == 0)) dir = DIR_W; + else if ((dx == -1) && (dy == -1)) dir = DIR_NW; + else if ((dx == 0) && (dy == -2)) dir = DIR_N; + if (dir >= 0) + unit->Body.Animation.summary.direction = dir; + } + } + } + + // Apply era aliases + for (int n = 0; n < 32; n++) + if (*p_player_bits & (1 << n)) + apply_era_specific_names (&leaders[n]); + + if (is->current_config.apply_grid_ini_setting_on_game_load) { + int grid_on = get_int_from_conquests_ini ("GridOn", 0, 0); + Map_Renderer * mr = &p_bic_data->Map.Renderer; + if (grid_on && ! mr->MapGrid_Flag) + mr->vtable->m68_Toggle_Grid (mr); + } + + return tr; +} + +void * +load_game_ex (char const * file_path, int suppress_intro_popup) +{ + is->suppress_intro_after_load_popup = suppress_intro_popup; + is->load_file_path_override = file_path; + return patch_do_load_game (NULL); +} + +int __fastcall +patch_show_movement_phase_popup (void * this, int edx, int param_1, int param_2) +{ + int tr = patch_show_popup (this, __, param_1, param_2); + + int player_civ_id = p_main_screen_form->Player_CivID; + int replay_for_players = is->replay_for_players; // Store this b/c it gets reset on game load + if (replay_for_players & 1<showing_hotseat_replay = true; + + patch_do_save_game (hotseat_resume_save_path, 1, 0); + load_game_ex (hotseat_replay_save_path, 1); + p_main_screen_form->Player_CivID = player_civ_id; + + // Re-enable the GUI so the minimap is visible during the replay. We must also reset the minimap & redraw it so that it reflects the + // player we just seated (above) instead of leftover data from the last player. + Main_GUI * main_gui = &p_main_screen_form->GUI; + main_gui->is_enabled = 1; + Navigator_Data_reset (&main_gui->Navigator_Data); + main_gui->Base.vtable->m73_call_m22_Draw ((Base_Form *)main_gui); + + perform_interturn (); + load_game_ex (hotseat_resume_save_path, 1); + p_main_screen_form->is_now_loading_game = 0; + + // Restore the replay_for_players variable b/c it gets cleared when loading a game. Also mask out the bit for the player we just + // showed the replay to. + is->replay_for_players = replay_for_players & ~(1<showing_hotseat_replay = false; + } + + return tr; +} + +// Returns a set of player bits containing only those players that are human and can see at least one AI unit. For speed and simplicity, does not +// account for units' invisibility ability, units are considered visible as long as they're on a visible tile. +int +find_human_players_seeing_ai_units () +{ + int tr = 0; + Map * map = &p_bic_data->Map; + if (map->Tiles != NULL) + for (int n_tile = 0; n_tile < map->TileCount; n_tile++) { + Tile * tile = map->Tiles[n_tile]; + Tile_Body * body = &tile->Body; + int human_vis_bits = (body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility) & *p_human_player_bits; + if (human_vis_bits != 0) // If any human players can see this tile + for (int n_player = 0; n_player < 32; n_player++) + if (human_vis_bits & 1<TileUnitID, &unused); + Unit * unit = get_unit_ptr (unit_id); + if ((unit != NULL) && + ((*p_human_player_bits & 1<Body.CivID) == 0)) { + tr |= 1<current_config.replay_ai_moves_in_hotseat_games && + (*p_is_offline_mp_game && ! *p_is_pbem_game); // offline MP but not PBEM => we're in a hotseat game + int ai_unit_vis_before; + if (save_replay) { + ai_unit_vis_before = find_human_players_seeing_ai_units (); + int toggleable_rules = *p_toggleable_rules; + *p_toggleable_rules |= TR_PRESERVE_RANDOM_SEED; // Make sure preserve random seed is on for the replay save + patch_do_save_game (hotseat_replay_save_path, 1, 0); + *p_toggleable_rules = toggleable_rules; + } + + is->players_saw_ai_unit = 0; // Clear bits. After perform_interturn, each set bit will indicate a player that has seen an AI unit move + long long ts_before; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); + is->time_spent_paused_during_popup = 0; + is->time_spent_computing_city_connections = 0; + is->count_calls_to_recompute_city_connections = 0; + unsigned saved_prefs = *p_preferences; + if (is->current_config.measure_turn_times) + *p_preferences &= ~(P_ANIMATE_BATTLES | P_SHOW_FRIEND_MOVES | P_SHOW_ENEMY_MOVES); + + perform_interturn (); + + if (is->current_config.day_night_cycle_mode) { + if (is->day_night_cycle_img_state == IS_OK) { + int new_hour = calculate_current_day_night_cycle_hour (); + if (new_hour != is->current_day_night_cycle) { + is->current_day_night_cycle = new_hour; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + } + } + } + + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_for_districts (); + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + } + + if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { + is->city_loc_display_perspective = -1; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw + } + + if (is->current_config.measure_turn_times) { + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + long long perf_freq; + QueryPerformanceFrequency ((LARGE_INTEGER *)&perf_freq); + int turn_time_in_ms = 1000 * (ts_after - ts_before - is->time_spent_paused_during_popup) / perf_freq; + int city_con_time_in_ms = 1000 * is->time_spent_computing_city_connections / perf_freq; + int road_time_in_ms = 1000 * is->time_spent_filling_roads / perf_freq; + + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + char msg[1000]; + + struct c3x_opt { + bool is_active; + char * name; + } opts[] = {{is->current_config.optimize_improvement_loops, "improv. loops"}, + {is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_OK), "trade net x"}}; + char opt_list[1000]; + memset (opt_list, 0, sizeof opt_list); + strncpy (opt_list, "^C3X optimizations: ", sizeof opt_list); + bool any_active_opts = false; + for (int n = 0; n < ARRAY_LEN (opts); n++) + if (opts[n].is_active) { + char * cursor = &opt_list[strlen (opt_list)]; + snprintf (cursor, opt_list + (sizeof opt_list) - cursor, "%s%s", any_active_opts ? ", " : "", opts[n].name); + any_active_opts = true; + } + if (! any_active_opts) { + char * cursor = &opt_list[strlen (opt_list)]; + strncpy (cursor, "None", opt_list + (sizeof opt_list) - cursor); + } + PopupForm_add_text (popup, __, (char *)opt_list, false); + + snprintf (msg, sizeof msg, "^Turn time: %d.%03d sec", turn_time_in_ms/1000, turn_time_in_ms%1000); + PopupForm_add_text (popup, __, (char *)msg, false); + snprintf (msg, sizeof msg, "^ Recomputing city connections: %d.%03d sec (%d calls)", + city_con_time_in_ms/1000, city_con_time_in_ms%1000, + is->count_calls_to_recompute_city_connections); + PopupForm_add_text (popup, __, (char *)msg, false); + snprintf (msg, sizeof msg, "^ Flood filling road network: %d.%03d sec", + road_time_in_ms/1000, road_time_in_ms%1000); + PopupForm_add_text (popup, __, (char *)msg, false); + patch_show_popup (popup, __, 0, 0); + + *p_preferences = saved_prefs; + } + + if (save_replay) { + int last_human_player_bit = 0; { + for (int n = 0; n < 32; n++) + if (*p_human_player_bits & 1<replay_for_players = (ai_unit_vis_before | (is->players_saw_ai_unit & *p_human_player_bits)) & ~last_human_player_bit; + } +} + +void __cdecl +patch_initialize_map_music (int civ_id, int era_id, bool param_3) +{ + if (! is->showing_hotseat_replay) + initialize_map_music (civ_id, era_id, param_3); +} + +void __stdcall +patch_deinitialize_map_music () +{ + if (! is->showing_hotseat_replay) + deinitialize_map_music (); +} + +void __fastcall +patch_Fighter_do_bombard_tile (Fighter * this, int edx, Unit * unit, int neighbor_index, int mp_tile_x, int mp_tile_y) +{ + // Unit::score_kill will be called if the bombarder destroys its target, and that is the only way score_kill can be called while this method + // is running. So if we're configured to stop enslaving from bombard, turn off enslaving while it's running. + is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; + + // Check if we're going to do PTW-like targeting, if not fall back on the base game's do_bombard_tile method. We'll also fall back on that + // method in the case where we're in an online game and the bombard can't happen b/c the tile is occupied by another battle. In that case, no + // bombard is possible but we'll call the base method anyway since it will show a little message saying as much. + if (itable_look_up_or (&is->current_config.ptw_arty_types, unit->Body.UnitTypeID, 0) && + (is->bombard_stealth_target == NULL) && + ! (is_online_game () && mp_check_current_combat (p_mp_object, __, mp_tile_x, mp_tile_y))) { + + City * city; { + int dx, dy; + neighbor_index_to_diff (neighbor_index, &dx, &dy); + int tile_x = unit->Body.X + dx, tile_y = unit->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + city = city_at (tile_x, tile_y); + } + + int rv; + if ((city != NULL) && ((rv = rand_int (p_rand_object, __, 3)) < 2)) + Fighter_damage_city_by_bombardment (this, __, unit, city, rv, 0); + else + Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); + + } else + Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); + + is->do_not_enslave_units = false; +} + +bool __fastcall +patch_Unit_check_king_for_defense_priority (Unit * this, int edx, enum UnitTypeAbilities king_ability) +{ + return (! is->current_config.ignore_king_ability_for_defense_priority) || (*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) ? + Unit_has_ability (this, __, king_ability) : + false; +} + +void WINAPI +patch_get_local_time_for_unit_ini (LPSYSTEMTIME lpSystemTime) +{ + GetLocalTime (lpSystemTime); + if (is->current_config.no_elvis_easter_egg && (lpSystemTime->wMonth == 1) && (lpSystemTime->wDay == 8)) + lpSystemTime->wDay = 9; +} + +bool __fastcall +patch_Leader_could_buy_tech_for_trade_screen (Leader * this, int edx, int tech_id, int from_civ_id) +{ + // Temporarily remove the untradable flag so this tech is listed on the screen instead of skipped over. After all the items have been + // assembled, we'll go back and disable the untradable techs. + if (is->current_config.show_untradable_techs_on_trade_screen) { + int saved_flags = p_bic_data->Advances[tech_id].Flags; + p_bic_data->Advances[tech_id].Flags &= ~ATF_Cannot_Be_Traded; + bool tr = this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); + p_bic_data->Advances[tech_id].Flags = saved_flags; + return tr; + + } else + return this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); +} + +void __fastcall +patch_DiploForm_assemble_tradable_items (DiploForm * this) +{ + DiploForm_assemble_tradable_items (this); + + // Disable (gray out) all untradable techs + if (is->current_config.show_untradable_techs_on_trade_screen) + for (int n = 0; n < p_bic_data->AdvanceCount; n++) + if (p_bic_data->Advances[n].Flags & ATF_Cannot_Be_Traded) { + this->tradable_technologies[n].can_be_bought = 0; + this->tradable_technologies[n].can_be_sold = 0; + } +} + +bool __fastcall +patch_City_can_trade_via_water (City * this) +{ + if (is->current_config.optimize_improvement_loops) { + for (int n = 0; n < is->water_trade_improvs.count; n++) + if (has_active_building (this, is->water_trade_improvs.items[n])) + return true; + return false; + } else + return City_can_trade_via_water (this); +} + +bool __fastcall +patch_City_can_trade_via_air (City * this) +{ + if (is->current_config.optimize_improvement_loops) { + for (int n = 0; n < is->air_trade_improvs.count; n++) + if (has_active_building (this, is->air_trade_improvs.items[n])) + return true; + return false; + } else + return City_can_trade_via_air (this); +} + +int __fastcall +patch_City_get_building_defense_bonus (City * this) +{ + bool cancel_great_wall_boost = is->current_config.enable_districts && + is->current_config.enable_great_wall_districts && + is->current_config.disable_great_wall_city_defense_bonus; + + if (is->current_config.optimize_improvement_loops || cancel_great_wall_boost) { + int tr = 0; + int is_size_level_1 = (this->Body.Population.Size <= p_bic_data->General.MaximumSize_City) && + (this->Body.Population.Size <= p_bic_data->General.MaximumSize_Town); + for (int n = 0; n < is->combat_defense_improvs.count; n++) { + int improv_id = is->combat_defense_improvs.items[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((is_size_level_1 || (improv->Combat_Bombard == 0)) && has_active_building (this, improv_id)) { + int multiplier; + if ((improv->Combat_Bombard > 0) && + (! cancel_great_wall_boost) && + (patch_Leader_count_any_shared_wonders_with_flag (&leaders[(this->Body).CivID], __, ITW_Doubles_City_Defenses, NULL) > 0)) + multiplier = 2; + else + multiplier = 1; + + int building_defense = multiplier * improv->Combat_Defence; + if (building_defense > tr) + tr = building_defense; + } + } + return tr; + } else + return City_get_building_defense_bonus (this); +} + +bool __fastcall +patch_City_shows_harbor_icon (City * this) +{ + return is->current_config.city_icons_show_unit_effects_not_trade ? + City_count_improvements_with_flag (this, __, ITF_Veteran_Sea_Units) > 0 : + patch_City_can_trade_via_water (this); +} + +bool __fastcall +patch_City_shows_airport_icon (City * this) +{ + return is->current_config.city_icons_show_unit_effects_not_trade ? + City_count_improvements_with_flag (this, __, ITF_Veteran_Air_Units) > 0 : + patch_City_can_trade_via_air (this); +} + +int __fastcall +patch_Unit_eval_escort_requirement (Unit * this) +{ + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + int ai_strat = type->AI_Strategy; + bool owned_by_ai = (*p_human_player_bits & 1<Body.CivID) == 0; // We must not reduce the escort requirement for human-owned units + // because that will interfere with group movement of units. + + // Apply special escort rules + if (owned_by_ai && is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) + return 0; + else if (owned_by_ai && is->current_config.use_offensive_artillery_ai && (ai_strat & UTAI_Artillery)) + return 1; + + else { + int base = Unit_eval_escort_requirement (this); + if (owned_by_ai && (ai_strat & (UTAI_Naval_Transport | UTAI_Naval_Carrier | UTAI_Naval_Missile_Transport))) + return not_above (is->current_config.max_ai_naval_escorts, base); + else + return base; + } +} + +bool __fastcall +patch_Unit_has_enough_escorters_present (Unit * this) +{ + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) + return true; + else + return Unit_has_enough_escorters_present (this); +} + +void __fastcall +patch_Unit_check_escorter_health (Unit * this, int edx, bool * has_any_escort_present, bool * any_escorter_cant_heal) +{ + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) { + *has_any_escort_present = true; + *any_escorter_cant_heal = true; // Returning true here indicates the unit should not stop to wait for its escorter(s) to heal. + } else + Unit_check_escorter_health (this, __, has_any_escort_present, any_escorter_cant_heal); +} + +void __fastcall +patch_Leader_unlock_technology (Leader * this, int edx, int tech_id, bool param_2, bool param_3, bool param_4) +{ + int * p_stack = (int *)&tech_id; + int ret_addr = p_stack[-1]; + + Leader_unlock_technology (this, __, tech_id, param_2, param_3, param_4); + + // If this method was not called during game initialization + if ((ret_addr != ADDR_UNLOCK_TECH_AT_INIT_1) && + (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_2) && + (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_3)) { + + // If this tech obsoletes some building and we're configured to fix the maintenance bug then recompute city maintenance. + if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings) { + bool obsoletes_anything = false; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (p_bic_data->Improvements[n].ObsoleteID == tech_id) { + obsoletes_anything = true; + break; + } + if (obsoletes_anything) + Leader_recompute_buildings_maintenance (this); + } + } +} + +int __fastcall +patch_City_get_improv_maintenance_for_ui (City * this, int edx, int improv_id) +{ + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && + (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) + return 0; + else + return patch_City_get_improvement_maintenance (this, __, improv_id); +} + +// Patch for barbarian diagonal bug. This bug is a small mistake in the original code, maybe a copy+paste error. The original code tries to loop over +// tiles around the barb unit by incrementing a neighbor index and coverting it to tile coords (like normal). The problem is that after it converts +// the neighbor index to dx and dy, it adds dx to both coords of the unit's position instead of using dy. The fix is simply to subtract off dx and add +// in dy when the Y coord is passed to Map::wrap_vert. +void __cdecl +patch_neighbor_index_to_diff_for_barb_ai (int neighbor_index, int * out_x, int * out_y) +{ + neighbor_index_to_diff (neighbor_index, out_x, out_y); + is->barb_diag_patch_dy_fix = *out_y - *out_x; +} +int __fastcall +patch_Map_wrap_vert_for_barb_ai (Map * this, int edx, int y) +{ + return Map_wrap_vert (this, __, is->current_config.patch_barbarian_diagonal_bug ? (y + is->barb_diag_patch_dy_fix) : y); +} + +int +count_workable_tiles_for_city (City * city) +{ + if (city == NULL) + return 0; + + int workable = 0; + FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { + Tile * tile = wai.tile; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + if (tile->Body.CityAreaID != city->Body.ID) + continue; + + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && district_is_complete (tile, inst->district_id)) + continue; + + workable++; + } + return workable; +} + +int +compute_auto_distribution_hub_goal (Leader * leader, int city_count) +{ + int total_unused_tiles = 0; + int stagnating_cities = 0; + int slow_growth_cities = 0; + int very_low_production_cities = 0; + int low_production_cities = 0; + + FOR_CITIES_OF (coi, leader->ID) { + City * city = coi.city; + if (city == NULL) + continue; + + int pop_size = city->Body.Population.Size; + int workable_tiles = count_workable_tiles_for_city (city); + if ((workable_tiles > 0) && (pop_size < workable_tiles)) + total_unused_tiles += workable_tiles - pop_size; + + int net_food = city->Body.FoodIncome; + if (net_food <= 0) + stagnating_cities++; + else if (net_food <= 2) + slow_growth_cities++; + + int net_shields = city->Body.ProductionIncome + city->Body.ProductionLoss; + if (net_shields < 0) + net_shields = 0; + if (net_shields <= 3) + very_low_production_cities++; + else if (net_shields <= 6) + low_production_cities++; + } + + int base_desired = (city_count + 3) / 4; + + int tiles_per_chunk = is->workable_tile_count; + if (tiles_per_chunk <= 0) + tiles_per_chunk = 1; + int unused_bonus = (total_unused_tiles + tiles_per_chunk * 3 - 1) / (tiles_per_chunk * 3); + + int food_pressure = stagnating_cities * 2 + slow_growth_cities; + int food_bonus = (food_pressure + 2) / 3; + + int production_pressure = very_low_production_cities * 2 + low_production_cities; + int production_bonus = (production_pressure + 2) / 3; + + int desired = base_desired + unused_bonus + food_bonus + production_bonus; + int max_reasonable = (city_count + 1) / 2; + int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; + if (max_per_100 > 0) { + int capped = (city_count * max_per_100 + 99) / 100; + if (capped >= 0) + max_reasonable = capped; + } + if (desired > max_reasonable) + desired = max_reasonable; + if (desired < 1) + desired = 1; + + return desired; +} + +void +ai_update_distribution_hub_goal_for_leader (Leader * leader) +{ + if (leader == NULL) + return; + if (! is->current_config.enable_districts || + ! is->current_config.enable_distribution_hub_districts) + return; + + int civ_id = leader->ID; + if ((1 << civ_id) & *p_human_player_bits) + return; + + int city_count = leader->Cities_Count; + if (city_count <= 0) + return; + + int desired = 0; + if (is->current_config.ai_distribution_hub_build_strategy == ADHBS_AUTO) + desired = compute_auto_distribution_hub_goal (leader, city_count); + else { + int ideal_per_100 = is->current_config.ai_ideal_distribution_hub_count_per_100_cities; + if (ideal_per_100 <= 0) + return; + desired = (city_count * ideal_per_100) / 100; + } + if (desired <= 0) + return; + + int current = 0; + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if ((rec != NULL) && (rec->civ_id == civ_id)) + current++; + } + + int in_progress = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * tile = (Tile *)tei.key; + int mapped_district_id = tei.value; + if ((tile != NULL) && + (mapped_district_id == DISTRIBUTION_HUB_DISTRICT_ID) && + ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID)) { + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (owner == civ_id) + in_progress++; + } + } + + int pending = 0; + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req != NULL) && (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID)) + pending++; + } + + int planned = current + in_progress + pending; + if (planned >= desired) + return; + + City * capital = get_city_ptr (leader->CapitalID); + bool has_capital = (capital != NULL); + int capital_x = has_capital ? capital->Body.X : 0; + int capital_y = has_capital ? capital->Body.Y : 0; + + const int yield_weight = 40; + const int capital_distance_weight = 45; + const int desired_min_capital_distance = 8; + const int proximity_penalty_scale = 300; + + while (planned < desired) { + City * best_city = NULL; + int best_tile_x = 0; + int best_tile_y = 0; + int best_score = INT_MIN; + + FOR_CITIES_OF (coi, civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + if (city_has_required_district (city, DISTRIBUTION_HUB_DISTRICT_ID)) + continue; + + if (find_pending_district_request (city, DISTRIBUTION_HUB_DISTRICT_ID) != NULL) + continue; + + int tile_x, tile_y; + Tile * candidate = find_tile_for_district (city, DISTRIBUTION_HUB_DISTRICT_ID, &tile_x, &tile_y); + if (candidate == NULL) + continue; + + int yield_sum = compute_city_tile_yield_sum (city, tile_x, tile_y); + int distance_to_capital = 0; + if (has_capital) + distance_to_capital = compute_wrapped_manhattan_distance (city->Body.X, city->Body.Y, capital_x, capital_y); + + int closeness_penalty = 0; + if (has_capital && (distance_to_capital < desired_min_capital_distance)) + closeness_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; + + int score = yield_sum * yield_weight + distance_to_capital * capital_distance_weight - closeness_penalty; + if (tile_has_resource (candidate)) + score -= 500; + + if (score > best_score) { + best_score = score; + best_city = city; + best_tile_x = tile_x; + best_tile_y = tile_y; + } + } + + if (best_city == NULL) + break; + + mark_city_needs_district (best_city, DISTRIBUTION_HUB_DISTRICT_ID); + planned++; + } +} + +bool +assign_ai_fallback_production (City * city, int disallowed_improvement_id) +{ + if (city == NULL) + return false; + + City_Order new_order = { .OrderID = -1, .OrderType = 0 }; + patch_City_ai_choose_production (city, __, &new_order); + + bool order_ok = false; + if (new_order.OrderType == COT_Improvement) { + if ((new_order.OrderID >= 0) && + (new_order.OrderID < p_bic_data->ImprovementsCount) && + (new_order.OrderID != disallowed_improvement_id) && + ! city_requires_district_for_improvement (city, new_order.OrderID, NULL) && + ! is_wonder_or_small_wonder_already_being_built (city, new_order.OrderID)) + order_ok = true; + } else if (new_order.OrderType == COT_Unit) { + if ((new_order.OrderID >= 0) && + (new_order.OrderID < p_bic_data->UnitTypeCount) && + (p_bic_data->UnitTypes[new_order.OrderID].Unit_Class == UTC_Land) && + patch_City_can_build_unit (city, __, new_order.OrderID, 1, 0, 0)) + order_ok = true; + } + + char ss[200]; + snprintf (ss, sizeof ss, "assign_ai_fallback_production: Remembering fallback pending building order for city %d (%s): id %d\n", + city->Body.ID, city->Body.CityName, disallowed_improvement_id); + (*p_OutputDebugStringA) (ss); + remember_pending_building_order (city, disallowed_improvement_id); + + if (order_ok) { + City_set_production (city, __, new_order.OrderType, new_order.OrderID, false); + return true; + } + + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) { + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + return true; + } + } + + return false; +} + +void __fastcall +patch_Leader_do_production_phase (Leader * this) +{ + recompute_resources_if_necessary (); + + if (is->current_config.enable_districts) { + assign_workers_for_pending_districts (this); + + if ((is->current_config.enable_canal_districts || is->current_config.enable_bridge_districts) && + (is->current_config.ai_builds_bridges || is->current_config.ai_builds_canals)) + assign_workers_for_ai_candidate_bridge_or_canals (this); + + bool ai_player = ((*p_human_player_bits & (1 << this->ID)) == 0); + int auto_dynamic_district_ids[COUNT_DISTRICT_TYPES]; + int auto_dynamic_district_count = 0; + + // For dynamic districts, the AI will never be triggered to build them if they have no dependent buildings. + // Determine which dynamic districts the AI could build. In the city loop after, mark which cities need them + if (ai_player) { + for (int district_id = is->special_district_count; district_id < is->district_count; district_id++) { + struct district_config * cfg = &is->district_configs[district_id]; + struct district_infos * info = &is->district_infos[district_id]; + + if (info->dependent_building_count > 0) continue; + if (cfg->command == -1) continue; + + if (! leader_can_build_district (this, district_id)) + continue; + + if (auto_dynamic_district_count < ARRAY_LEN (auto_dynamic_district_ids)) + auto_dynamic_district_ids[auto_dynamic_district_count++] = district_id; + } + } + + // Special exception for AI to build Central Rail Hub, which is available in Industrial era but Mass Transit, + // the only building dependent on it, is in the Modern era. Without this the AI wouldn't build in Industrial era. + if (is->current_config.enable_central_rail_hub_districts) { + if (leader_can_build_district (this, CENTRAL_RAIL_HUB_DISTRICT_ID)) + auto_dynamic_district_ids[auto_dynamic_district_count++] = CENTRAL_RAIL_HUB_DISTRICT_ID; + } + + if (is->current_config.enable_distribution_hub_districts) { + if (leader_can_build_district (this, DISTRIBUTION_HUB_DISTRICT_ID)) + ai_update_distribution_hub_goal_for_leader (this); + } + + FOR_CITIES_OF (coi, this->ID) { + City * city = coi.city; + if (city == NULL) continue; + + bool at_neighborhood_cap = is->current_config.enable_neighborhood_districts && city_is_at_neighborhood_cap (city); + + // Mark any needed dynamic districts for AI players. This isn't the most intelligent approach (we're not weighing district benefits), + // but it's simple and works reasonably well + if (ai_player && (auto_dynamic_district_count > 0)) { + for (int i = 0; i < auto_dynamic_district_count; i++) { + int district_id = auto_dynamic_district_ids[i]; + + if (city_has_required_district (city, district_id)) continue; + if (! city_can_build_district (city, district_id)) continue; + if (find_pending_district_request (city, district_id) != NULL) continue; + + int target_x = 0, target_y = 0; + if (find_tile_for_district (city, district_id, &target_x, &target_y) == NULL) + continue; + + mark_city_needs_district (city, district_id); + } + } + + if (at_neighborhood_cap) { + if (! ai_player) + maybe_show_neighborhood_growth_warning (city); + else + ensure_neighborhood_request_for_city (city); + } + + if (city->Body.Order_Type == COT_Unit) { + int unit_id = city->Body.Order_ID; + int req_district_id = -1; + bool needs_halt = false; + + if ((unit_id >= 0) && (unit_id < p_bic_data->UnitTypeCount)) { + UnitType * type = &p_bic_data->UnitTypes[unit_id]; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { + req_district_id = AERODROME_DISTRICT_ID; + needs_halt = true; + } else if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (city, PORT_DISTRICT_ID))) { + req_district_id = PORT_DISTRICT_ID; + needs_halt = true; + } + } + + if (needs_halt) { + char ss[200]; + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting unit %d due to missing district %d\n", + city->Body.ID, city->Body.CityName, unit_id, req_district_id); + (*p_OutputDebugStringA) (ss); + + if (ai_player) + mark_city_needs_district (city, req_district_id); + + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + + continue; + } + } + + if (city->Body.Order_Type != COT_Improvement) continue; + int i_improv = city->Body.Order_ID; + + // Check if production needs to be halted due to missing district + int req_district_id = -1; + char const * district_description = NULL; + bool needs_halt = false; + + // Check buildings & wonders dependent on districts + if (city_requires_district_for_improvement (city, i_improv, &req_district_id)) { + if (req_district_id >= 0) { + needs_halt = true; + district_description = is->district_configs[req_district_id].name; + } + } + + // Wonders + char ss[200]; + if (is->current_config.enable_wonder_districts) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: Checking wonder improv %d for city %d (%s)\n", + i_improv, city->Body.ID, city->Body.CityName); + (*p_OutputDebugStringA) (ss); + if (city_is_currently_building_wonder (city)) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) is building wonder improv %d\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + bool wonder_requires_district = false; + if (i_improv >= 0) { + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); + if (district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) + wonder_requires_district = true; + } + + if (wonder_requires_district) { + bool has_wonder_district = reserve_wonder_district_for_city (city, i_improv); + if (! has_wonder_district) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) lacks Wonder District for wonder improv %d\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + needs_halt = true; + req_district_id = WONDER_DISTRICT_ID; + district_description = "Wonder District"; + } + } else { + release_wonder_district_reservation (city); + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) wonder improv %d does not require Wonder District\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + } + } else { + release_wonder_district_reservation (city); + } + } + + // If production needs to be halted, handle the reassignment and messaging + if (needs_halt) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting improv %d due to missing district %d\n", + city->Body.ID, city->Body.CityName, i_improv, req_district_id); + (*p_OutputDebugStringA) (ss); + // Switch production to another option + if (ai_player) { + mark_city_needs_district (city, req_district_id); + assign_ai_fallback_production (city, i_improv); + } else { + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + // Show message to human player + if (! ai_player && (city->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[160]; + char const * bname = p_bic_data->Improvements[i_improv].Name.S; + snprintf (msg, sizeof msg, "%s %s %s", bname, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_description); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + continue; + } + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) improv %d passed missing district check\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + } + } + + // Force-activate the barbs if there are any barb cities on the map and barb city capturing is enabled. This is necessary for barb city + // production to work given how it's currently implemented. + if (is->current_config.enable_city_capture_by_barbarians && (this->ID == 0)) { + int any_barb_cities = 0; + FOR_CITIES_OF (coi, this->ID) { + any_barb_cities = 1; + break; + } + if (any_barb_cities) + is->force_barb_activity_for_cities = 1; + } + + // If barbs are force-activated, make sure their activity level is at least 1 (sedentary). + int * p_barb_activity = &p_bic_data->Map.World.Final_Barbarians_Activity; + int saved_barb_activity = *p_barb_activity; + if (is->force_barb_activity_for_cities && (*p_barb_activity <= 0)) + *p_barb_activity = 1; + + Leader_do_production_phase (this); + + if (is->force_barb_activity_for_cities) { + *p_barb_activity = saved_barb_activity; + is->force_barb_activity_for_cities = 0; + } +} + +// This function counts the number of players in the game. The return value will be compared to the number of cities on the map to determine if there +// are enough cities (per player) to unlock barb production. If barb activity is forced on, return zero so that the check always passes. +int __cdecl +patch_count_player_bits_for_barb_prod (unsigned int bit_field) +{ + return is->force_barb_activity_for_cities ? 0 : count_set_bits (bit_field); +} + +Tile * __fastcall +patch_Map_get_tile_to_check_visibility (Map * this, int edx, int index) +{ + Tile * tr = Map_get_tile (this, __, index); + int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; + if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { + int human_bits = *p_human_player_bits; + is->dummy_tile->Body.Fog_Of_War = tr->Body.Fog_Of_War | ((tr->Body.Fog_Of_War & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.FOWStatus = tr->Body.FOWStatus | ((tr->Body.FOWStatus & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.V3 = tr->Body.V3 | ((tr->Body.V3 & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.Visibility = tr->Body.Visibility | ((tr->Body.Visibility & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.field_D0_Visibility = tr->Body.field_D0_Visibility | ((tr->Body.field_D0_Visibility & human_bits) != 0 ? human_bits : 0); + tr = is->dummy_tile; + } + is->tile_returned_for_visibility_check = tr; + return tr; +} + +Tile * __fastcall +patch_Map_get_tile_to_check_visibility_again (Map * this, int edx, int index) +{ + return is->tile_returned_for_visibility_check; +} + +// Same as above except this method uses the FOWStatus field instead of Fog_Of_War +Tile * __fastcall +patch_Map_get_tile_for_fow_status_check (Map * this, int edx, int index) +{ + Tile * tile = Map_get_tile (this, __, index); + int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; + if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { + is->dummy_tile->Body.FOWStatus = ((tile->Body.FOWStatus & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; + return is->dummy_tile; + } else + return tile; +} + +Tile * __cdecl +patch_tile_at_to_check_visibility (int x, int y) +{ + return patch_Map_get_tile_to_check_visibility (&p_bic_data->Map, __, (p_bic_data->Map.Width >> 1) * y + (x >> 1)); +} + +Tile * __cdecl +patch_tile_at_to_check_visibility_again (int x, int y) +{ + return is->tile_returned_for_visibility_check; +} + +unsigned __fastcall +patch_Tile_m42_Get_Overlays (Tile * this, int edx, byte visible_to_civ) +{ + unsigned base_vis_overlays = Tile_m42_Get_Overlays (this, __, visible_to_civ); + if ((visible_to_civ != 0) && // if we're seeing from a player's persp. instead of seeing the actual overlays AND + is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND + ((1 << visible_to_civ) & *p_human_player_bits) && // the perspective is of a human player AND + (base_vis_overlays != this->Overlays) && // that player can't already see all the actual overlays AND + (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game + + // Check if there's another human player that can see the actual overlays. If so, give that info to this player and return it. + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != visible_to_civ) && + (Tile_m42_Get_Overlays (this, __, n_player) == this->Overlays)) { + this->Body.Visibile_Overlays[visible_to_civ] = this->Overlays; + return this->Overlays; + } + player_bits >>= 1; + n_player++; + } + + return base_vis_overlays; + } else + return base_vis_overlays; +} + +int __fastcall +patch_Tile_check_water_for_sea_zoc (Tile * this) +{ + if ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) + return this->vtable->m35_Check_Is_Water (this); + else + return 1; // The caller will skip ZoC logic if this is a land tile without a city because the targeted unit is a sea unit. Instead + // return 1, so all tiles are considered sea tiles, so we can run the ZoC logic for land units or air units on land. +} + +int __fastcall +patch_Tile_check_water_for_land_zoc (Tile * this) +{ + // Same as above except this time we want to consider all tiles to be land + return ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) ? + this->vtable->m35_Check_Is_Water (this) : + 0; +} + + +int __fastcall +patch_Unit_get_attack_strength_for_sea_zoc (Unit * this) +{ + return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) ? Unit_get_attack_strength (this) : 0; +} + +int __fastcall +patch_Unit_get_attack_strength_for_land_zoc (Unit * this) +{ + return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) ? Unit_get_attack_strength (this) : 0; +} + +// Forward declaration; defined further below near patch_Fighter_get_odds_for_main_combat_loop +// where its dependencies (apply_counter_rules, Fighter_get_combat_odds, counter_combat_ctx) live. +Unit * find_civ4_best_defender_against (Unit * attacker, Tile * tile, int tile_x, int tile_y); + +Unit * __fastcall +patch_Main_Screen_Form_find_visible_unit (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * excluded) +{ + struct unit_display_override * override = &is->unit_display_override; + if ((override->unit_id >= 0) && (override->tile_x == tile_x) && (override->tile_y == tile_y)) { + Unit * unit = get_unit_ptr (override->unit_id); + if (unit != NULL) { + if ((unit->Body.X == tile_x) && (unit->Body.Y == tile_y)) + return unit; + } + } + + // Civ 4-style 'best defender' display: when a player selects an attacker, the unit at the top of the enemy stack + // should be the one with the lowest win rate against that attacker. + // Only takes effect when both `use_civ4_style_best_defender` and `enable_unit_counters` are enabled, + // and provided the currently selected unit belongs to the local player and there is an enemy unit on the target square. + // + if (is->current_config.use_civ4_style_best_defender && + is->current_config.enable_unit_counters && + (this->Current_Unit != NULL) && + (this->Current_Unit->Body.CivID == this->Player_CivID) && + ((this->Current_Unit->Body.X != tile_x) || (this->Current_Unit->Body.Y != tile_y))) { + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile) && + tile_has_enemy_unit (tile, this->Current_Unit->Body.CivID)) { + Unit * best = find_civ4_best_defender_against (this->Current_Unit, tile, tile_x, tile_y); + if ((best != NULL) && (best != excluded)) + return best; + } + } + + return Main_Screen_Form_find_visible_unit (this, __, tile_x, tile_y, excluded); +} + +void __fastcall +patch_Animator_play_zoc_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) +{ + if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Air) + Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); +} + +bool __fastcall +patch_Fighter_check_zoc_anim_visibility (Fighter * this, int edx, Unit * attacker, Unit * defender, bool param_3) +{ + // If we've reached this point in the code (in the calling method) then a unit has been selected to exert zone of control and it has passed + // its dice roll to cause damage. Stash its pointer for possible use later. + is->zoc_interceptor = attacker; + + // If an air unit was selected, pre-emptively undo the damage from ZoC since we'll want to run our own bit of logic to do that (the air unit + // may still get shot down). Return false from this function to skip over all of the animation logic in the caller since it wouldn't work for + // aircraft. + if (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Air) { + defender->Body.Damage -= 1; + return false; + + // Repeat a check done by the caller. We've deleted this check to ensure that this function always gets called so we can grab the interceptor. + } else if (attacker->Body.Animation.field_111 == 0) + return false; + + else { + bool tr = Fighter_check_combat_anim_visibility (this, __, attacker, defender, param_3); + + // If necessary, set up to ensure the unit's attack animation is visible. This means forcing it to the top of its stack and + // temporarily unfortifying it if it's fortified. (If it's fortified, the animation is occasionally not visible. Don't know why.) + if (tr && is->current_config.show_zoc_attacks_from_mid_stack) { + is->unit_display_override = (struct unit_display_override) { attacker->Body.ID, attacker->Body.X, attacker->Body.Y }; + if (attacker->Body.UnitState == UnitState_Fortifying) { + Unit_set_state (attacker, __, 0); + is->refortify_interceptor_after_zoc = true; + } + } + + return tr; + } +} + +int __fastcall +patch_City_sum_buildings_naval_power_for_zoc (City * this) +{ + // Cancel out city's naval power if the unit has only one HP left. This prevents coastal fortresses from knocking that last hit point off + // passing units when lethal ZoC is enabled, because to make that work we delete an earlier check excusing 1-HP units from ZoC. + if ((is->zoc_defender != NULL) && + ((Unit_get_max_hp (is->zoc_defender) - is->zoc_defender->Body.Damage) <= 1)) + return 0; + + else + return City_sum_buildings_naval_power (this); +} + +void __fastcall +patch_Fighter_apply_zone_of_control (Fighter * this, int edx, Unit * unit, int from_x, int from_y, int to_x, int to_y) +{ + is->zoc_interceptor = NULL; + is->zoc_defender = unit; + is->refortify_interceptor_after_zoc = false; + struct unit_display_override saved_udo = is->unit_display_override; + Fighter_apply_zone_of_control (this, __, unit, from_x, from_y, to_x, to_y); + + // Actually exert ZoC if an air unit managed to do so. + if ((is->zoc_interceptor != NULL) && (p_bic_data->UnitTypes[is->zoc_interceptor->Body.UnitTypeID].Unit_Class == UTC_Air)) { + bool intercepted = Unit_try_flying_over_tile (is->zoc_interceptor, __, from_x, from_y); + if (! intercepted) { + Unit_play_bombing_animation (is->zoc_interceptor, __, from_x, from_y); + unit->Body.Damage = not_below (0, unit->Body.Damage + 1); + } + } + + if (is->refortify_interceptor_after_zoc) + Unit_set_state (is->zoc_interceptor, __, UnitState_Fortifying); + is->unit_display_override = saved_udo; +} + +// These two patches replace two function calls in Unit::move_to_adjacent_tile that come immediately after the unit has been subjected to zone of +// control. These calls recheck that the move is valid, not sure why. Here they're patched to indicate that the move in invalid when the unit was +// previously killed by ZoC. This causes move_to_adjacent_tile to return early without running the code that would place the unit on the destination +// tile and, for example, capturing an enemy city there. +int __fastcall +patch_Trade_Net_get_move_cost_after_zoc (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned param_7, int neighbor_index, Trade_Net_Distance_Info * dist_info) +{ + return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (unit) - unit->Body.Damage) > 0) ? + patch_Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, param_7, neighbor_index, dist_info) : + -1; +} + +AdjacentMoveValidity __fastcall +patch_Unit_can_move_after_zoc (Unit * this, int edx, int neighbor_index, int param_2) +{ + return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (this) - this->Body.Damage) > 0) ? + patch_Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2) : + AMV_1; +} + +// Checks unit's HP after it was possibly hit by ZoC and deals with the consequences if it's dead. Does nothing if config option to make ZoC lethal +// isn't set or if interceptor is NULL. Returns true if the unit was killed, false otherwise. +bool +check_life_after_zoc (Unit * unit, Unit * interceptor) +{ + if ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) && (interceptor != NULL) && + ((Unit_get_max_hp (unit) - unit->Body.Damage) <= 0)) { + + // Call Unit::score_kill but turn off enslaving if we're configured to stop enslaving after bombardment and the ZoC was performed by + // bombardment, which is always the case for cross-domain ZoC or when bombard str > attack. + UnitType * interceptor_type = &p_bic_data->UnitTypes[interceptor->Body.UnitTypeID]; + if (is->current_config.prevent_enslaving_by_bombardment && + ((p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != interceptor_type->Unit_Class) || + (interceptor_type->Bombard_Strength >= Unit_get_attack_strength (interceptor)))) + is->do_not_enslave_units = true; + Unit_score_kill (interceptor, __, unit, false); + is->do_not_enslave_units = false; + + if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (&p_bic_data->fighter, __, interceptor, unit, true)) + Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, unit, AT_DEATH, false); + + bool prev_always_despawn_passengers = is->always_despawn_passengers; + is->always_despawn_passengers = is_land_transport (unit) && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); + patch_Unit_despawn (unit, __, interceptor->Body.CivID, 0, 0, 0, 0, 0, 0); + is->always_despawn_passengers = prev_always_despawn_passengers; + + return true; + } else + return false; +} + +int __fastcall +patch_Unit_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, bool param_2, int param_3, byte param_4) +{ + is->moving_unit_to_adjacent_tile = true; + is->move_spend_override_unit = NULL; + is->move_spend_override_value = 0; + + bool const allow_worker_coast = is->current_config.enable_districts && is->current_config.workers_can_enter_coast && is_worker (this); + bool const allow_bridge_walk = is->current_config.enable_districts && + is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land); + bool const allow_canal_sail = is->current_config.enable_districts && + is->current_config.enable_canal_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea); + bool coast_override_active = false; + enum UnitStateType prev_state = this->Body.UnitState; + int prev_container = this->Body.Container_Unit; + bool restore_goto_path = prev_state == UnitState_Go_To; + int prev_path_len = this->Body.path_len; + int prev_path_dest_x = this->Body.path_dest_x; + int prev_path_dest_y = this->Body.path_dest_y; + + if (allow_worker_coast || allow_bridge_walk || allow_canal_sail) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + Tile * dest = tile_at (nx, ny); + if (dest != NULL) { + if (allow_bridge_walk && ! dest->vtable->m35_Check_Is_Water (dest)) { + Tile * src = tile_at (this->Body.X, this->Body.Y); + if ((src != NULL) && (src != p_null_tile)) { + struct district_instance * src_inst = get_district_instance (src); + bool from_bridge = (src_inst != NULL) && + (src_inst->district_id == BRIDGE_DISTRICT_ID) && + district_is_complete (src, src_inst->district_id); + if (from_bridge) { + int move_cost = patch_Trade_Net_get_movement_cost ( + is->trade_net, __, + this->Body.X, this->Body.Y, nx, ny, + this, this->Body.CivID, 0, neighbor_index, NULL); + if (move_cost >= 0) { + int spent_moves = this->Body.Moves + move_cost; + is->move_spend_override_unit = this; + is->move_spend_override_value = not_above (spent_moves, patch_Unit_get_max_move_points (this)); + } + } + } + } + + bool should_override = false; + if (allow_worker_coast && + dest->vtable->m35_Check_Is_Water (dest) && + (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + if (is_human) { + should_override = true; + } else { + struct district_worker_record * rec = get_tracked_worker_record (this); + struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; + if (req != NULL) { + City * req_city = (req->city != NULL) ? req->city : get_city_ptr (req->city_id); + if ((req->district_id >= 0) && + (req->district_id < is->district_count) && + (req_city != NULL) && + city_radius_contains_tile (req_city, nx, ny) && + (req->target_x == nx) && (req->target_y == ny)) { + struct district_config const * cfg = &is->district_configs[req->district_id]; + if ((cfg->buildable_square_types_mask & (1 << SQ_Coast)) != 0) + should_override = true; + } + } + } + } + + if (! should_override && allow_bridge_walk) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && + (inst->district_id == BRIDGE_DISTRICT_ID) && + district_is_complete (dest, inst->district_id)) + should_override = true; + } + + if (! should_override && allow_canal_sail) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && + (inst->district_id == CANAL_DISTRICT_ID) && + district_is_complete (dest, inst->district_id)) + should_override = true; + } + + if (should_override) { + coast_override_active = true; + is->coast_walk_unit = this; + is->coast_walk_transport_override = false; + is->coast_walk_prev_state = prev_state; + is->coast_walk_prev_container = prev_container; + is->coast_walk_restore_goto_path = restore_goto_path; + is->coast_walk_prev_path_len = prev_path_len; + is->coast_walk_prev_path_dest_x = prev_path_dest_x; + is->coast_walk_prev_path_dest_y = prev_path_dest_y; + } + } + } + + is->zoc_interceptor = is->zoc_defender = NULL; + int tr = Unit_move_to_adjacent_tile (this, __, neighbor_index, param_2, param_3, param_4); + if ((this == is->zoc_defender) && check_life_after_zoc (this, is->zoc_interceptor)) + tr = ! is_online_game (); // This is what the original method returns when the unit was destroyed in combat + + if (coast_override_active) { + is->coast_walk_unit = NULL; + is->coast_walk_transport_override = false; + + if (this->Body.Container_Unit == this->Body.ID) { + this->Body.Container_Unit = is->coast_walk_prev_container; + Unit_set_state (this, __, is->coast_walk_prev_state); + if (is->coast_walk_restore_goto_path) { + this->Body.path_len = is->coast_walk_prev_path_len; + this->Body.path_dest_x = is->coast_walk_prev_path_dest_x; + this->Body.path_dest_y = is->coast_walk_prev_path_dest_y; + } + } + } + + is->temporarily_disallow_lethal_zoc = false; + is->moving_unit_to_adjacent_tile = false; + is->move_spend_override_unit = NULL; + is->move_spend_override_value = 0; + return tr; +} + +void __fastcall +patch_Unit_load_into_army_after_move_to_adj_tile (Unit * this, int edx, Unit * loadee) +{ + // Take care not to load an army into itself b/c that will cause the game to crash. The game may attempt to do that at the end of + // move_to_adjacent_tile b/c we return the unit itself as a transport target when we want to allow it to move onto coast. + if (is->coast_walk_transport_override && this == loadee) + return; + + Unit_load_into_army (this, __, loadee); +} + +int __fastcall +patch_Unit_teleport (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad) +{ + is->zoc_interceptor = NULL; + int tr = Unit_teleport (this, __, tile_x, tile_y, unit_telepad); + check_life_after_zoc (this, is->zoc_interceptor); + return tr; +} + +bool +can_do_defensive_bombard (Unit * unit, UnitType * type) +{ + if ((type->Bombard_Strength > 0) && (! Unit_has_ability (unit, __, UTA_Cruise_Missile))) { + if (cannot_defend_inside_transport (unit)) + return false; + + if ((unit->Body.Status & USF_USED_DEFENSIVE_BOMBARD) == 0) // has not already done DB this turn + return true; + + // If the "blitz" special DB rule is activated and this unit has blitz, check if it still has an extra DB to use + else if ((is->current_config.special_defensive_bombard_rules & SDBR_BLITZ) && UnitType_has_ability (type, __, UTA_Blitz)) { + int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, unit->Body.ID, 0); + return type->Movement > extra_dbs + 1; + + } else + return false; + } else + return false; +} + +Unit * __fastcall +patch_Fighter_find_defensive_bombarder (Fighter * this, int edx, Unit * attacker, Unit * defender) +{ + int special_db_rules = is->current_config.special_defensive_bombard_rules; + if ((special_db_rules == 0) && + ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) == 0) && + ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) == 0)) + return Fighter_find_defensive_bombarder (this, __, attacker, defender); + else { + enum UnitTypeClasses attacker_class = p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class; + int attacker_has_one_hp = Unit_get_max_hp (attacker) - attacker->Body.Damage <= 1; + + Tile * defender_tile = tile_at (defender->Body.X, defender->Body.Y); + if ((Unit_get_defense_strength (attacker) < 1) || // if attacker cannot defend OR + (defender_tile == NULL) || (defender_tile == p_null_tile) || // defender tile is invalid OR + (((special_db_rules & SDBR_LETHAL) == 0) && attacker_has_one_hp) || // (DB is non-lethal AND attacker has one HP remaining) OR + ((special_db_rules & SDBR_NOT_INVISIBLE) && ! patch_Unit_is_visible_to_civ (attacker, __, defender->Body.CivID, 1))) // (invisible units are immune to DB AND attacker is invisible) + return NULL; + + Unit * tr = NULL; + int highest_strength = -1; + enum UnitTypeAbilities lethal_bombard_req = (attacker_class == UTC_Sea) ? UTA_Lethal_Sea_Bombardment : UTA_Lethal_Land_Bombardment; + FOR_UNITS_ON (uti, defender_tile) { + Unit * candidate = uti.unit; + UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; + if (can_do_defensive_bombard (candidate, candidate_type) && + (candidate_type->Bombard_Strength > highest_strength) && + (candidate != defender) && + (Unit_get_containing_army (candidate) != defender) && + ((attacker_class == candidate_type->Unit_Class) || + ((special_db_rules & SDBR_AERIAL) && + (candidate_type->Unit_Class == UTC_Air) && + (candidate_type->Air_Missions & UCV_Bombing)) || + ((special_db_rules & SDBR_DOCKED_VS_LAND) && + (candidate_type->Unit_Class == UTC_Sea) && + (get_city_ptr (defender_tile->CityID) != NULL))) && + ((! attacker_has_one_hp) || UnitType_has_ability (candidate_type, __, lethal_bombard_req))) { + tr = candidate; + highest_strength = candidate_type->Bombard_Strength; + } + } + return tr; + } +} + +void __fastcall +patch_Fighter_damage_by_db_in_main_loop (Fighter * this, int edx, Unit * bombarder, Unit * defender) +{ + if (p_bic_data->UnitTypes[bombarder->Body.UnitTypeID].Unit_Class == UTC_Air) { + if (Unit_try_flying_over_tile (bombarder, __, defender->Body.X, defender->Body.Y)) + return; // intercepted + else if (patch_Main_Screen_Form_is_unit_visible_to_player (p_main_screen_form, __, defender->Body.X, defender->Body.Y, bombarder)) + Unit_play_bombing_animation (bombarder, __, defender->Body.X, defender->Body.Y); + } + + // If the unit has already performed DB this turn, then record that it's consumed one of its extra DBs + if (bombarder->Body.Status & USF_USED_DEFENSIVE_BOMBARD) { + int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, bombarder->Body.ID, 0); + itable_insert (&is->extra_defensive_bombards, bombarder->Body.ID, extra_dbs + 1); + } + + int damage_before = defender->Body.Damage; + Fighter_damage_by_defensive_bombard (this, __, bombarder, defender); + int damage_after = defender->Body.Damage; + + is->dbe.bombarder = bombarder; + is->dbe.defender = defender; + if (damage_after > damage_before) { + is->dbe.damage_done = true; + int max_hp = Unit_get_max_hp (defender); + int dead_before = damage_before >= max_hp, dead_after = damage_after >= max_hp; + + // If the unit was killed by defensive bombard, play its death animation then toggle off animations for the rest of the combat so it + // doesn't look like anything else happens. Technically, the combat continues and the dead unit is guarantted to lose because the + // patch to get_combat_odds ensures the dead unit has no chance of winning a round. + if (dead_before ^ dead_after) { + is->dbe.defender_was_destroyed = true; + if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (this, __, bombarder, defender, true)) + Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, defender, AT_DEATH, false); + is->dbe.saved_animation_setting = this->play_animations; + this->play_animations = 0; + } + } +} + +int __fastcall +patch_Fighter_get_odds_for_main_combat_loop (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses) +{ + if (is->dbe.defender_was_destroyed) + return 1025; + + struct c3x_config * cfg = &is->current_config; + // Only OR in counter-rule terrain skipping when we actually ran apply_counter_rules for this + // call. Otherwise counter_combat_ctx.ignore_terrain can be stale from an earlier probe (e.g. + // find_civ4_best_defender_against) or an earlier combat round — especially risky after + // merges that add new odds call sites. + bool ignore_terrain_for_odds = ignore_defensive_bonuses; + if (cfg->enable_unit_counters && attacker != NULL && defender != NULL) { + Tile * def_tile = tile_at (this->defender_location_x, + this->defender_location_y); + int aa, dd; + bool ignore_terrain; + apply_counter_rules (cfg, attacker, defender, def_tile, + &aa, &dd, &ignore_terrain); + + is->counter_combat_ctx.active = true; + is->counter_combat_ctx.attacker = attacker; + is->counter_combat_ctx.defender = defender; + is->counter_combat_ctx.attacker_atk_pct = aa; + is->counter_combat_ctx.defender_def_pct = dd; + is->counter_combat_ctx.ignore_terrain = ignore_terrain; + ignore_terrain_for_odds = ignore_defensive_bonuses || ignore_terrain; + } + + int result = Fighter_get_combat_odds (this, __, attacker, defender, bombarding, + ignore_terrain_for_odds); + is->counter_combat_ctx.active = false; + return result; +} + +// Civ 4-style best defender: On the specified tile, pick the defender that is hardest for the +// attacker to beat (i.e. the one with the highest *defender* win rate against the attacker). +// Takes unit counter rules into account. Returns NULL if there is no suitable defender. +// +// IMPORTANT — odds semantics: vanilla Fighter_get_combat_odds returns the *defender*'s win +// chance (out of ~1024), not the attacker's. Confirmed by the existing patch at +// patch_Fighter_get_odds_for_main_combat_loop: when the attacker has been killed by defensive +// bombardment ("defender_was_destroyed"), the patch returns 1025 so the still-running combat +// loop sees ~100% defender win chance and finishes off the doomed attacker. Therefore "hardest +// to beat" = "highest defender win chance" = max odds. +// +// Notes: +// - Skips units with Container_Unit >= 0 (units inside armies/transports; only the top unit represents the group). +// - Skips units not visible to the attacker's civ, avoiding revealing invisible units. +// - Skips units of the same civ as the attacker (they cannot defend). +// - Skips units with defense strength <= 0 (incapable of combat). +// - Temporarily overwrites is->counter_combat_ctx internally and saves/restores the context before/after execution, +// to avoid disrupting the actual combat odds context. +Unit * +find_civ4_best_defender_against (Unit * attacker, Tile * tile, int tile_x, int tile_y) +{ + if ((attacker == NULL) || (tile == NULL) || (tile == p_null_tile)) + return NULL; + + // Defensive: validate attacker shape before we deref any of its fields downstream. If the + // pointer is stale or refers to a half-initialized unit, UnitTypeID will be out of range and + // we bail out instead of crashing inside Fighter_get_combat_odds / vtable calls. + int atk_tid = attacker->Body.UnitTypeID; + if ((atk_tid < 0) || (atk_tid >= p_bic_data->UnitTypeCount)) + return NULL; + + struct c3x_config * cfg = &is->current_config; + int attacker_civ = attacker->Body.CivID; + + // Backup the current counter ctx, as we'll be repeatedly overwriting it within the loop. + bool saved_active = is->counter_combat_ctx.active; + Unit * saved_attacker = is->counter_combat_ctx.attacker; + Unit * saved_defender = is->counter_combat_ctx.defender; + int saved_attacker_atk = is->counter_combat_ctx.attacker_atk_pct; + int saved_defender_def = is->counter_combat_ctx.defender_def_pct; + bool saved_ignore_terrain = is->counter_combat_ctx.ignore_terrain; + + // Backup the live Fighter struct fields. Vanilla Fighter_get_combat_odds may consult + // fighter.attacker / fighter.defender / fighter.defender_location_x/y to fetch terrain or + // state; if those still point at units from a previous combat (or are NULL during init), the + // vanilla code can dereference garbage and crash. We point them at the current candidate + // inside the loop and restore the originals at the end. + Unit * saved_fighter_attacker = p_bic_data->fighter.attacker; + Unit * saved_fighter_defender = p_bic_data->fighter.defender; + int saved_fighter_atk_x = p_bic_data->fighter.attacker_location_x; + int saved_fighter_atk_y = p_bic_data->fighter.attacker_location_y; + int saved_fighter_def_x = p_bic_data->fighter.defender_location_x; + int saved_fighter_def_y = p_bic_data->fighter.defender_location_y; + + Unit * best = NULL; + // We track the maximum defender win rate. Start below any possible result so the first + // eligible candidate always becomes the initial best. + int best_odds = -1; + + FOR_UNITS_ON (uti, tile) { + Unit * d = uti.unit; + if ((d == NULL) || (d == attacker)) + continue; + // Defensive: a unit on the tile_units linked list with an out-of-range type id is almost + // certainly stale or in some half-initialized state — skip it entirely so we never pass it + // to anything that dereferences UnitType. + int dtid = d->Body.UnitTypeID; + if ((dtid < 0) || (dtid >= p_bic_data->UnitTypeCount)) + continue; + if (d->Body.Container_Unit >= 0) + continue; + if (d->Body.CivID == attacker_civ) + continue; + // Must be a true enemy of the attacker (allies/peace treaties). + if (! d->vtable->is_enemy_of_civ (d, __, attacker_civ, 0)) + continue; + if (Unit_get_defense_strength (d) <= 0) + continue; + if (! patch_Unit_is_visible_to_civ (d, __, attacker_civ, 0)) + continue; + + // Apply unit counter multipliers (100 if unit counters are disabled, equivalent to vanilla win rate formula). + int aa = 100, dd = 100; + bool ignore_terrain = false; + if (cfg->enable_unit_counters) + apply_counter_rules (cfg, attacker, d, tile, &aa, &dd, &ignore_terrain); + + is->counter_combat_ctx.active = true; + is->counter_combat_ctx.attacker = attacker; + is->counter_combat_ctx.defender = d; + is->counter_combat_ctx.attacker_atk_pct = aa; + is->counter_combat_ctx.defender_def_pct = dd; + is->counter_combat_ctx.ignore_terrain = ignore_terrain; + + // Point the live Fighter struct at the (attacker, d) pair so the vanilla odds function + // reads valid pointers instead of stale ones. + p_bic_data->fighter.attacker = attacker; + p_bic_data->fighter.defender = d; + p_bic_data->fighter.attacker_location_x = attacker->Body.X; + p_bic_data->fighter.attacker_location_y = attacker->Body.Y; + p_bic_data->fighter.defender_location_x = tile_x; + p_bic_data->fighter.defender_location_y = tile_y; + + // IMPORTANT: vanilla Fighter_get_combat_odds reads attack/defense values directly from + // UnitType.Attack and UnitType.Defence — it does NOT route through Unit_get_attack/defense_strength + // in a way that this mod has hooked (Unit_get_defense_strength is not registered in + // civ_prog_objects.csv as an inlead, so patch_Unit_get_defense_strength never gets called from + // inside vanilla odds computation). To make our counter multipliers actually affect the odds we + // compute here, we monkey-patch the UnitType fields for the duration of the call and restore + // them immediately after. This is single-threaded mod code and the call window is microseconds, + // so no other reader can observe the temporary values. + UnitType * a_type = &p_bic_data->UnitTypes[atk_tid]; + UnitType * d_type = &p_bic_data->UnitTypes[dtid]; + int saved_a_attack = a_type->Attack; + int saved_d_defence = d_type->Defence; + if (aa != 100) + a_type->Attack = (saved_a_attack * aa) / 100; + if (dd != 100) + d_type->Defence = (saved_d_defence * dd) / 100; + + int odds = Fighter_get_combat_odds (&p_bic_data->fighter, __, attacker, d, false, ignore_terrain); + + a_type->Attack = saved_a_attack; + d_type->Defence = saved_d_defence; + + // odds = defender's win chance (see comment above the function). We want the candidate + // that is hardest for the attacker to beat, i.e. the one with the *highest* odds. + bool replace; + if (best == NULL) { + replace = true; + } else if (odds > best_odds) { + replace = true; + } else if (odds < best_odds) { + replace = false; + } else { + // Odds tie. Defer to vanilla's own defender comparator (cheaper-cost-defends-first + // etc.) — but we must give it the *effective* defense of each candidate against + // this attacker, otherwise it would compare base defenses (e.g. Swordsman base 2 vs + // Musketman base 4) and pick Musketman immediately, never reaching the cost + // tie-break that should decide between two units that are effectively equally hard + // to beat (Swordsman with a x2 counter has effective def 4, equal to Musketman's + // base 4 — vanilla's tie-break should then prefer the cheaper Swordsman). + // + // We can't rely on counter_combat_ctx flowing through Unit_get_defense_strength + // here (see the long comment above the odds call: the patch isn't actually hooked + // into vanilla code). So we apply the multiplier ourselves on top of whatever + // Unit_get_defense_strength returns for each candidate. + int best_aa = 100, best_dd = 100; + bool best_ignore = false; + if (cfg->enable_unit_counters) + apply_counter_rules (cfg, attacker, best, tile, &best_aa, &best_dd, &best_ignore); + + int d_def = (Unit_get_defense_strength (d) * dd ) / 100; + int best_def = (Unit_get_defense_strength (best) * best_dd) / 100; + + replace = Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, + d, d_def, best, best_def, true); + } + if (replace) { + best = d; + best_odds = odds; + } + } + + is->counter_combat_ctx.active = saved_active; + is->counter_combat_ctx.attacker = saved_attacker; + is->counter_combat_ctx.defender = saved_defender; + is->counter_combat_ctx.attacker_atk_pct = saved_attacker_atk; + is->counter_combat_ctx.defender_def_pct = saved_defender_def; + is->counter_combat_ctx.ignore_terrain = saved_ignore_terrain; + + // Restore the live Fighter struct so we don't leave it pointing at our probe values when a + // real combat (or other code path that reads it) starts. + p_bic_data->fighter.attacker = saved_fighter_attacker; + p_bic_data->fighter.defender = saved_fighter_defender; + p_bic_data->fighter.attacker_location_x = saved_fighter_atk_x; + p_bic_data->fighter.attacker_location_y = saved_fighter_atk_y; + p_bic_data->fighter.defender_location_x = saved_fighter_def_x; + p_bic_data->fighter.defender_location_y = saved_fighter_def_y; + + return best; +} + +byte __fastcall +patch_Fighter_fight (Fighter * this, int edx, Unit * attacker, + int attack_direction, Unit * defender_or_null) +{ + // Civ 4-style best defender: compute the defender from the target tile (neighbor of the + // attacker) using counter-aware odds, then use that unit for combat. + // + // Vanilla usually *pre-resolves* a defender and passes it non-NULL. That selection uses base + // UnitType stats (and cost tie-breaks), not our counter rules — so combat could hit Musketman + // while Main_Screen_Form_find_visible_unit (which always calls find_civ4_best_defender_against) + // showed Swordsman. We therefore apply our pick whenever the attack is a normal 8-neighbor + // strike and either no defender was passed, or the passed defender still sits on the target + // tile (vanilla's stack defender). If vanilla passes a defender on some other tile, leave it + // alone (unusual / non-adjacent paths). + if (is->current_config.use_civ4_style_best_defender && + is->current_config.enable_unit_counters && + (attacker != NULL) && + // Strict guard: attack_direction must be a valid 8-neighbor index. Some non-combat code + // paths call Fighter_fight with sentinel values (-1 etc.); forwarding those into + // neighbor_index_to_diff would produce a junk target tile and crash. + (attack_direction >= 0) && (attack_direction < 8)) { + int dx = 0, dy = 0; + neighbor_index_to_diff (attack_direction, &dx, &dy); + // Belt-and-braces: dx/dy must lie on the 8-neighbor lattice. + if ((dx >= -1) && (dx <= 1) && (dy >= -1) && (dy <= 1) && ((dx != 0) || (dy != 0))) { + int target_x = attacker->Body.X + dx; + int target_y = attacker->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); + Tile * target_tile = tile_at (target_x, target_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + bool vanilla_defender_on_target = + (defender_or_null != NULL) && + (defender_or_null->Body.X == target_x) && + (defender_or_null->Body.Y == target_y); + if ((defender_or_null == NULL) || vanilla_defender_on_target) { + Unit * picked = find_civ4_best_defender_against (attacker, target_tile, target_x, target_y); + if (picked != NULL) + defender_or_null = picked; + } + } + } + } + + byte tr = Fighter_fight (this, __, attacker, attack_direction, + defender_or_null); + is->dbe = (struct defensive_bombard_event) {0}; + is->counter_combat_ctx.active = false; + return tr; +} + +int __fastcall +patch_Unit_get_attack_strength (Unit * this) +{ + int base = Unit_get_attack_strength (this); + if (! is->counter_combat_ctx.active) + return base; + if (this == is->counter_combat_ctx.attacker) + return base * is->counter_combat_ctx.attacker_atk_pct / 100; + return base; +} + +int __fastcall +patch_Unit_get_defense_strength (Unit * this) +{ + int base = Unit_get_defense_strength (this); + if (! is->counter_combat_ctx.active) + return base; + if (this == is->counter_combat_ctx.defender) + return base * is->counter_combat_ctx.defender_def_pct / 100; + return base; +} + +void __fastcall +patch_Unit_score_kill_by_defender (Unit * this, int edx, Unit * victim, bool was_attacking) +{ + // This function is called when the defender wins in combat. If the attacker was actually killed by defensive bombardment, then award credit + // for that kill to the defensive bombarder not the defender in combat. + if (is->dbe.defender_was_destroyed) { + is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; + Unit_score_kill (is->dbe.bombarder, __, victim, was_attacking); + is->do_not_enslave_units = false; + p_bic_data->fighter.play_animations = is->dbe.saved_animation_setting; + + } else + Unit_score_kill (this, __, victim, was_attacking); +} + +void __fastcall +patch_Unit_play_attack_anim_for_def_bombard (Unit * this, int edx, int direction) +{ + // Don't play any animation for air units, the animations are instead handled in the patch for damage_by_defensive_bombard + if (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) { + + // Make sure the unit is displayed if it's in an army and we're configured for that + struct unit_display_override saved_udo = is->unit_display_override; + Unit * container; + if (is->current_config.show_armies_performing_defensive_bombard && + (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && + Unit_has_ability (container, __, UTA_Army)) + is->unit_display_override = (struct unit_display_override) { this->Body.ID, this->Body.X, this->Body.Y }; + + Unit_play_attack_animation (this, __, direction); + + is->unit_display_override = saved_udo; + } +} + +bool +can_precision_strike_tile_improv_at (Unit * unit, int x, int y) +{ + Tile * tile; + return is->current_config.allow_precision_strikes_against_tile_improvements && // we're configured to allow prec. strikes vs tiles AND + ((tile = tile_at (x, y)) != p_null_tile) && // get tile, make sure it's valid AND + is_explored (tile, unit->Body.CivID) && // tile has been explored by attacker AND + has_any_destructible_overlays (tile, true); // it has something that can be destroyed by prec. strike +} + +// Same as above function except this one applies to the V3 field instead of FOWStatus +Tile * __cdecl +patch_tile_at_for_v3_check (int x, int y) +{ + Tile * tile = tile_at (x, y); + int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; + if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { + is->dummy_tile->Body.V3 = ((tile->Body.V3 & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; + return is->dummy_tile; + } else + return tile; +} + +bool __fastcall +patch_Unit_check_contact_bit_6_on_right_click (Unit * this, int edx, int civ_id) +{ + bool tr = Unit_check_contact_bit_6 (this, __, civ_id); + if ((! tr) && + is->current_config.share_visibility_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << civ_id) & *p_human_player_bits)) { // is civ_id a human player + if ((1 << this->Body.CivID) & *p_human_player_bits) + tr = true; + + else { + // Check if any other human player has contact + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != civ_id) && + Unit_check_contact_bit_6 (this, __, n_player)) { + tr = true; + break; + } + player_bits >>= 1; + n_player++; + } + } + } + return tr; +} + +bool __fastcall +patch_Unit_check_precision_strike_target (Unit * this, int edx, int tile_x, int tile_y) +{ + return Unit_check_precision_strike_target (this, __, tile_x, tile_y) || can_precision_strike_tile_improv_at (this, tile_x, tile_y); +} + +void __fastcall +patch_Unit_play_attack_animation_vs_tile (Unit * this, int edx, int direction) +{ + if (is->current_config.polish_precision_striking && + UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile) && + (is->attacking_tile_x != this->Body.X) && (is->attacking_tile_y != this->Body.Y)) + Unit_animate_cruise_missile_strike (this, __, is->attacking_tile_x, is->attacking_tile_y); + else + Unit_play_attack_animation (this, __, direction); +} + +void __fastcall +patch_Unit_attack_tile (Unit * this, int edx, int x, int y, int bombarding) +{ + Tile * target_tile = NULL; + bool had_district_before = false; + int district_id_before = -1; + int tile_x = x; + int tile_y = y; + + if (is->current_config.enable_districts) { + + // Check if this is a completed wonder district that cannot be destroyed + if (is->current_config.enable_wonder_districts && + !is->current_config.completed_wonder_districts_can_be_destroyed) { + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + target_tile = tile_at (tile_x, tile_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + struct wonder_district_info * info = get_wonder_district_info (target_tile); + if (info != NULL && info->state == WDS_COMPLETED) { + // This tile has a completed wonder district and they can't be destroyed + if (((*p_human_player_bits & (1 << this->Body.CivID)) != 0) && + (this->Body.CivID == p_main_screen_form->Player_CivID)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_PILLAGE", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + return; + } + } + } + + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + target_tile = tile_at (tile_x, tile_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (target_tile); + if (inst != NULL) { + had_district_before = true; + district_id_before = inst->district_id; + } + } + } + + is->attacking_tile_x = x; + is->attacking_tile_y = y; + if (bombarding) + is->unit_bombard_attacking_tile = this; + + Unit_attack_tile (this, __, x, y, bombarding); + + // Check if the district was destroyed by the attack + if (had_district_before && (target_tile != NULL) && (target_tile != p_null_tile) && district_id_before != NATURAL_WONDER_DISTRICT_ID) { + struct district_instance * inst_after = get_district_instance (target_tile); + bool has_district_after = (inst_after != NULL); + int district_id_after = (inst_after != NULL) ? inst_after->district_id : -1; + + // If the district existed before but not after, or the tile no longer has a mine, the district was destroyed + if (!has_district_after || !(target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & TILE_FLAG_MINE)) { + bool is_water_tile = target_tile != NULL && target_tile->vtable->m35_Check_Is_Water (target_tile); + handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, ! is_water_tile); + } + } + + is->unit_bombard_attacking_tile = NULL; + is->attacking_tile_x = is->attacking_tile_y = -1; +} + +void __fastcall +patch_Unit_do_precision_strike (Unit * this, int edx, int x, int y) +{ + if ((city_at (x, y) == NULL) && can_precision_strike_tile_improv_at (this, x, y)) + patch_Unit_attack_tile (this, __, x, y, 1); + else + Unit_do_precision_strike (this, __, x, y); + + if (is->current_config.polish_precision_striking && + UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile)) + patch_Unit_despawn (this, __, 0, false, false, 0, 0, 0, 0); +} + +int __fastcall +patch_Unit_get_max_moves_after_barricade_attack (Unit * this) +{ + if (is->current_config.dont_end_units_turn_after_bombarding_barricade && (this == is->unit_bombard_attacking_tile)) + return this->Body.Moves + p_bic_data->General.RoadsMovementRate; + else + return patch_Unit_get_max_move_points (this); +} + +City * __cdecl +patch_city_at_in_find_bombard_defender (int x, int y) +{ + // The caller (Fighter::find_defender_against_bombardment) has a set of lists of bombard priority/eligibility in its stack memory. The list + // for land units bombarding land tiles normally restricts the targets to land units by containing [UTC_Land, -1, -1]. If we're configured to + // remove that restriction, modify the list so it contains instead [UTC_Land, UTC_Sea, UTC_Air]. Conveniently, the offset from this function's + // first parameter to the list is 0x40 bytes in all executables. + if (is->current_config.remove_land_artillery_target_restrictions) { + enum UnitTypeClasses * list = (void *)((byte *)&x + 0x40); + list[1] = UTC_Sea; + list[2] = UTC_Air; + } + + return city_at (x, y); +} + +bool __fastcall +patch_Unit_check_bombard_target (Unit * this, int edx, int tile_x, int tile_y) +{ + bool base = Unit_check_bombard_target (this, __, tile_x, tile_y); + Tile * tile = tile_at (tile_x, tile_y); + int overlays; + + if (base && + itable_look_up_or (&is->current_config.can_bombard_only_sea_tiles, this->Body.UnitTypeID, 0) && + ! tile->vtable->m35_Check_Is_Water (tile)) + return false; + + else if (base && + is->current_config.disallow_useless_bombard_vs_airfields && + ! Unit_has_ability (this, __, UTA_Nuclear_Weapon) && + ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // if tile has an airfield AND + (overlays == 0x20000000)) { // tile only has an airfield + UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + + // Check that a bombard attack vs this tile would not be wasted. It won't be if either (1) there are no units on the tile, (2) there + // is a unit that can be damaged by bombarding, or (3) there are no units that can be damaged and no air units. The rules for + // bombardment are that you can't damage aircraft in an airfield and you also can't destroy an airfield from underneath aircraft. + int any_units = 0, + any_vulnerable_units = 0, + any_air_units = 0; + FOR_UNITS_ON (uti, tile) { + enum UnitTypeClasses class = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; + any_units = 1; + any_air_units |= class == UTC_Air; + any_vulnerable_units |= (class != UTC_Air) && (Unit_get_defense_strength (uti.unit) > 0) && + can_damage_bombarding (this_type, uti.unit, tile); + } + return (! any_units) || // case (1) above + any_vulnerable_units || // case (2) + ((! any_air_units) && (! any_vulnerable_units)); // case (3) + + } else + return base; +} + +bool __fastcall +patch_Unit_can_disembark_anything (Unit * this, int edx, int tile_x, int tile_y) +{ + Tile * this_tile = tile_at (this->Body.X, this->Body.Y); + Tile * target_tile = tile_at (tile_x, tile_y); + bool base = Unit_can_disembark_anything (this, __, tile_x, tile_y); + + // Apply units per tile limit + if (base) { + bool stack_limited_for_all = true; + FOR_UNITS_ON (uti, this_tile) + if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_below_stack_limit (target_tile, this->Body.CivID, uti.unit->Body.UnitTypeID)) { + stack_limited_for_all = false; + break; + } + if (stack_limited_for_all) + return false; + } + + // Apply trespassing restriction. First check if this civ may move into (tile_x, tile_y) without trespassing. If it would be trespassing, then + // we can only disembark anything if this transport has a passenger that can ignore the restriction. Without this check, the game can enter an + // infinite loop under rare circumstances. + if (base && + is->current_config.disallow_trespassing && + check_trespassing (this->Body.CivID, this_tile, target_tile)) { + bool any_exempt_passengers = false; + FOR_UNITS_ON (uti, this_tile) + if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_allowed_to_trespass (uti.unit)) { + any_exempt_passengers = true; + break; + } + return any_exempt_passengers; + + } else + return base; +} + +int __fastcall +patch_Unit_get_defense_for_bombardable_unit_check (Unit * this) +{ + // Returning a defense value of zero indicates this unit is not a target for bombardment. If configured, exclude all air units from + // bombardment so the attacks target tile improvements instead. Do this only if the tile has another improvement in addition to an airfield, + // or we could destroy the airfield itself. + Tile * tile; + int overlays; + if (is->current_config.allow_bombard_of_other_improvs_on_occupied_airfield && // If configured AND + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && // "this" is an air unit AND + ((tile = tile_at (this->Body.X, this->Body.Y)) != p_null_tile) && // "this" is on a valid tile AND + ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // tile has an airfield AND + (overlays != 0x20000000)) // tile does not only have an airfield + return 0; + + else + return Unit_get_defense_strength (this); +} + +void __fastcall +patch_Demographics_Form_m22_draw (Demographics_Form * this) +{ + Demographics_Form_m22_draw (this); + + if (is->current_config.show_total_city_count) { + // There's proably a better way to get the city count, but better safe than sorry. I don't know if it's possible for the city list to + // contain holes so the surest thing is to check every possible ID. + int city_count = 0; { + if (p_cities->Cities != NULL) + for (int n = 0; n <= p_cities->LastIndex; n++) { + City_Body * body = p_cities->Cities[n].City; + city_count += (body != NULL) && ((int)body != offsetof (City, Body)); + } + } + + PCX_Image * canvas = &this->Base.Data.Canvas; + + // Draw backdrop + { + char temp_path[2*MAX_PATH]; + PCX_Image backdrop; + PCX_Image_construct (&backdrop); + get_mod_art_path ("CityCountBackdrop.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&backdrop, __, temp_path, NULL, 0, 0x100, 2); + if (backdrop.JGL.Image != NULL) { + int w = backdrop.JGL.Image->vtable->m54_Get_Width (backdrop.JGL.Image); + PCX_Image_draw_onto (&backdrop, __, canvas, (1024 - w) / 2, 720); + } + backdrop.vtable->destruct (&backdrop, __, 0); + } + + // Draw text on top of the backdrop + char s[100]; + snprintf (s, sizeof s, "%s %d / %d", is->c3x_labels[CL_TOTAL_CITIES], city_count, is->city_limit); + s[(sizeof s) - 1] = '\0'; + PCX_Image_set_text_effects (canvas, __, 0x80000000, -1, 2, 2); // Set text color to black + PCX_Image_draw_centered_text (canvas, __, get_font (14, FSF_NONE), s, 1024/2 - 100, 730, 200, strlen (s)); + } +} + +int __fastcall +patch_Leader_get_optimal_city_number (Leader * this) +{ + if (! is->current_config.strengthen_forbidden_palace_ocn_effect) + return Leader_get_optimal_city_number (this); + else { + int num_sans_fp = Leader_get_optimal_city_number (this), // OCN w/o contrib from num of FPs + fp_count = patch_Leader_count_wonders_with_small_flag (this, __, ITSW_Reduces_Corruption, NULL), + s_diff = p_bic_data->DifficultyLevels[this->player_difficulty].Optimal_Cities, // Difficulty scaling, called "percentage of optimal cities" in the editor + base_ocn = p_bic_data->WorldSizes[p_bic_data->Map.World.World_Size].OptimalCityCount; + return num_sans_fp + (s_diff * fp_count * base_ocn + 50) / 100; // Add 50 to round off + } +} + +int __fastcall +patch_Leader_count_forbidden_palaces_for_ocn (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) +{ + if (! is->current_config.strengthen_forbidden_palace_ocn_effect) + return patch_Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); + else + return 0; // We'll add in the FP effect later with a different weight +} + +void __fastcall +patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id) +{ + is->is_computing_city_connections = true; + long long ts_before; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); + + if (is->tnx_init_state == IS_OK) { + if (is->tnx_cache == NULL) { + is->tnx_cache = is->create_tnx_cache (&p_bic_data->Map); + is->set_up_before_building_network (is->tnx_cache); + } else if (! is->keep_tnx_cache) + is->set_up_before_building_network (is->tnx_cache); + } + + Trade_Net_recompute_city_connections (this, __, civ_id, redo_road_network, param_3, redo_roads_for_city_id); + + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; + + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + is->time_spent_computing_city_connections += ts_after - ts_before; + is->count_calls_to_recompute_city_connections++; + is->is_computing_city_connections = false; +} + +void __fastcall +patch_Map_build_trade_network (Map * this) +{ + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) + is->set_up_before_building_network (is->tnx_cache); + is->keep_tnx_cache = true; + Map_build_trade_network (this); + is->keep_tnx_cache = false; + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; +} + +void __fastcall +patch_Trade_Net_recompute_city_cons_and_res (Trade_Net * this, int edx, bool param_1) +{ + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) + is->set_up_before_building_network (is->tnx_cache); + + is->keep_tnx_cache = true; + Trade_Net_recompute_city_cons_and_res (this, __, param_1); + is->keep_tnx_cache = false; + + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; +} + +int __fastcall +patch_Trade_Net_set_unit_path_to_fill_road_net (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) +{ + int tr; + long long ts_before; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); + + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { + is->flood_fill_road_network (is->tnx_cache, from_x, from_y, civ_id); + tr = 0; // Return value is not used by caller anyway + } else + tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); + + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + is->time_spent_filling_roads += ts_after - ts_before; + return tr; +} + +bool +set_up_gdi_plus () +{ + if (is->gdi_plus.init_state == IS_UNINITED) { + is->gdi_plus.init_state = IS_INIT_FAILED; + is->gdi_plus.gp_graphics = NULL; + + struct startup_input { + UINT32 GdiplusVersion; + void * DebugEventCallback; + BOOL SuppressBackgroundThread; + BOOL SuppressExternalCodecs; + } startup_input = {1, NULL, FALSE, FALSE}; + + is->gdi_plus.module = LoadLibraryA ("gdiplus.dll"); + if (is->gdi_plus.module == NULL) { + MessageBoxA (NULL, "Failed to load gdiplus.dll!", "Error", MB_ICONERROR); + goto end_init; + } + + int (WINAPI * GdiplusStartup) (ULONG_PTR * out_token, struct startup_input *, void * startup_output) = + (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdiplusStartup"); + + is->gdi_plus.CreateFromHDC = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreateFromHDC"); + is->gdi_plus.DeleteGraphics = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeleteGraphics"); + is->gdi_plus.SetSmoothingMode = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetSmoothingMode"); + is->gdi_plus.SetPenDashStyle = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetPenDashStyle"); + is->gdi_plus.CreatePen1 = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreatePen1"); + is->gdi_plus.DeletePen = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeletePen"); + is->gdi_plus.DrawLineI = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDrawLineI"); + if ((is->gdi_plus.CreateFromHDC == NULL) || (is->gdi_plus.DeleteGraphics == NULL) || + (is->gdi_plus.SetSmoothingMode == NULL) || (is->gdi_plus.SetPenDashStyle == NULL) || + (is->gdi_plus.CreatePen1 == NULL) || (is->gdi_plus.DeletePen == NULL) || + (is->gdi_plus.DrawLineI == NULL)) { + MessageBoxA (NULL, "Failed to get GDI+ proc addresses!", "Error", MB_ICONERROR); + goto end_init; + } + + int status = GdiplusStartup (&is->gdi_plus.token, &startup_input, NULL); + if (status != 0) { + char s[200]; + snprintf (s, sizeof s, "Failed to initialize GDI+! Startup status: %d", status); + MessageBoxA (NULL, s, "Error", MB_ICONERROR); + goto end_init; + } + + is->gdi_plus.init_state = IS_OK; + end_init: + ; + } + + return is->gdi_plus.init_state == IS_OK; +} + +int __fastcall +patch_OpenGLRenderer_initialize (OpenGLRenderer * this, int edx, PCX_Image * texture) +{ + if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || + ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) + return OpenGLRenderer_initialize (this, __, texture); + + // Initialize GDI+ instead + else { + if (! set_up_gdi_plus ()) + return 2; + if (is->gdi_plus.gp_graphics != NULL) { + is->gdi_plus.DeleteGraphics (is->gdi_plus.gp_graphics); + is->gdi_plus.gp_graphics = NULL; + } + int status = is->gdi_plus.CreateFromHDC (texture->JGL.Image->DC, &is->gdi_plus.gp_graphics); + if (status == 0) { + is->gdi_plus.SetSmoothingMode (is->gdi_plus.gp_graphics, 4); // 4 = SmoothingModeAntiAlias from GdiPlusEnums.h + return 0; + } else + return 2; + } +} + +void __fastcall +patch_OpenGLRenderer_set_color (OpenGLRenderer * this, int edx, unsigned int rgb555) +{ + // Convert rgb555 to rgb888 + unsigned int rgb888 = 0; { + unsigned int mask = 31; + int shift = 3; + for (int n = 0; n < 3; n++) { + rgb888 |= (rgb555 & mask) << shift; + mask <<= 5; + shift += 3; + } + } + + is->ogl_color = (is->ogl_color & 0xFF000000) | rgb888; + OpenGLRenderer_set_color (this, __, rgb555); +} + +void __fastcall +patch_OpenGLRenderer_set_opacity (OpenGLRenderer * this, int edx, unsigned int alpha) +{ + is->ogl_color = (is->ogl_color & 0x00FFFFFF) | (alpha << 24); + OpenGLRenderer_set_opacity (this, __, alpha); +} + +void __fastcall +patch_OpenGLRenderer_set_line_width (OpenGLRenderer * this, int edx, int width) +{ + is->ogl_line_width = width; + OpenGLRenderer_set_line_width (this, __, width); +} + +void __fastcall +patch_OpenGLRenderer_enable_line_dashing (OpenGLRenderer * this) +{ + is->ogl_line_stipple_enabled = true; + OpenGLRenderer_enable_line_dashing (this); +} + +void __fastcall +patch_OpenGLRenderer_disable_line_dashing (OpenGLRenderer * this) +{ + is->ogl_line_stipple_enabled = false; + OpenGLRenderer_disable_line_dashing (this); +} + +void __fastcall +patch_OpenGLRenderer_draw_line (OpenGLRenderer * this, int edx, int x1, int y1, int x2, int y2) +{ + if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || + ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) + OpenGLRenderer_draw_line (this, __, x1, y1, x2, y2); + + else if ((is->gdi_plus.init_state == IS_OK) && (is->gdi_plus.gp_graphics != NULL)) { + void * gp_pen; + int unit_world = 0; // = UnitWorld from gdiplusenums.h + int status = is->gdi_plus.CreatePen1 (is->ogl_color, (float)is->ogl_line_width, unit_world, &gp_pen); + if (status == 0) { + if (is->ogl_line_stipple_enabled) + is->gdi_plus.SetPenDashStyle (gp_pen, 1); // 1 = DashStyleDash from GdiPlusEnums.h + is->gdi_plus.DrawLineI (is->gdi_plus.gp_graphics, gp_pen, x1, y1, x2, y2); + is->gdi_plus.DeletePen (gp_pen); + } + } +} + +int __fastcall +patch_Tile_check_water_for_retreat_on_defense (Tile * this) +{ + Unit * defender = p_bic_data->fighter.defender; + + // Under the standard game rules, defensively retreating onto a water tile is not allowed. Set retreat_blocked to true if "this" is a water + // tile and we're not configured to allow retreating onto water tiles. + bool retreat_blocked; { + if (this->vtable->m35_Check_Is_Water (this)) { + if ( is->current_config.allow_defensive_retreat_on_water + && defender != NULL + && p_bic_data->UnitTypes[defender->Body.UnitTypeID].Unit_Class == UTC_Sea + && ( is->current_config.limit_defensive_retreat_on_water_to_types.len == 0 + || (bool)itable_look_up_or (&is->current_config.limit_defensive_retreat_on_water_to_types, defender->Body.UnitTypeID, 0))) + retreat_blocked = false; + else + retreat_blocked = true; + } else + retreat_blocked = false; + } + + // Check stack limit + if ((! retreat_blocked) && + (defender != NULL) && + ! is_below_stack_limit (this, defender->Body.CivID, defender->Body.UnitTypeID)) + retreat_blocked = true; + + // The return from this call is only used to filter the given tile as a possible retreat destination based on whether it's water or not + return (int)retreat_blocked; +} + +int __fastcall +patch_City_count_airports_for_airdrop (City * this, int edx, enum ImprovementTypeFlags airport_flag) +{ + if (is->current_config.allow_airdrop_without_airport) + return 1; + else + return City_count_improvements_with_flag (this, __, airport_flag); +} + +int __fastcall +patch_Leader_get_cont_city_count_for_worker_req (Leader * this, int edx, int cont_id) +{ + int tr = Leader_get_city_count_on_continent (this, __, cont_id); + if (is->current_config.ai_worker_requirement_percent != 100) + tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; + return tr; +} + +int __fastcall +patch_Leader_get_city_count_for_worker_prod_cap (Leader * this) +{ + int tr = this->Cities_Count; + // Don't scale down the cap since it's pretty low to begin with + if (is->current_config.ai_worker_requirement_percent > 100) + tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; + return tr; +} + +// If "only_improv_id" is >= 0, will only return yields from mills attached to that improv, otherwise returns all yields from all improvs +void +gather_mill_yields (City * city, int only_improv_id, int * out_food, int * out_shields, int * out_commerce) +{ + int food = 0, shields = 0, commerce = 0; + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if ((mill->flags & MF_YIELDS) && + ((only_improv_id < 0) || (mill->improv_id == only_improv_id)) && + can_generate_resource (city->Body.CivID, mill) && + has_active_building (city, mill->improv_id) && + has_resources_required_by_building (city, mill->improv_id)) { + Resource_Type * res = &p_bic_data->ResourceTypes[mill->resource_id]; + food += res->Food; + shields += res->Shield; + commerce += res->Commerce; + } + } + *out_food = food; + *out_shields = shields; + *out_commerce = commerce; +} + +int __fastcall +patch_City_calc_tile_yield_while_gathering (City * this, int edx, YieldKind kind, int tile_x, int tile_y) +{ + int tr = City_calc_tile_yield_at (this, __, kind, tile_x, tile_y); + + // Include yields from generated resources + if ((this->Body.X == tile_x) && (this->Body.Y == tile_y)) { + int mill_food, mill_shields, mill_commerce; + gather_mill_yields (this, -1, &mill_food, &mill_shields, &mill_commerce); + if (kind == YK_FOOD) tr += mill_food; + else if (kind == YK_SHIELDS) tr += mill_shields; + else if (kind == YK_COMMERCE) tr += mill_commerce; + + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + int bonus_food = 0, bonus_shields = 0, bonus_gold = 0; + calculate_city_center_district_bonus (this, &bonus_food, &bonus_shields, &bonus_gold); + if (kind == YK_FOOD) tr += bonus_food; + else if (kind == YK_SHIELDS) tr += bonus_shields; + else if (kind == YK_COMMERCE) tr += bonus_gold; + } + } + + return tr; +} + +bool __fastcall +patch_Leader_record_export (Leader * this, int edx, int importer_civ_id, int resource_id) +{ + bool exported = Leader_record_export (this, __, importer_civ_id, resource_id); + if (exported && + (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill + is->must_recompute_resources_for_mill_inputs = true; + return exported; +} + +bool __fastcall +patch_Leader_erase_export (Leader * this, int edx, int importer_civ_id, int resource_id) +{ + bool erased = Leader_erase_export (this, __, importer_civ_id, resource_id); + if (erased && + (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill + is->must_recompute_resources_for_mill_inputs = true; + return erased; +} + +int __fastcall +patch_Sprite_draw_improv_img_on_city_form (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int tr = Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); + + int generated_resources[16]; + int generated_resource_count = 0; + for (int n = 0; (n < is->current_config.count_mills) && (generated_resource_count < ARRAY_LEN (generated_resources)); n++) { + struct mill * mill = &is->current_config.mills[n]; + if ((mill->improv_id == is->drawing_icons_for_improv_id) && + ((mill->flags & MF_SHOW_BONUS) || (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus)) && + (! ((mill->flags & MF_HIDE_NON_BONUS) && (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus))) && + can_generate_resource (p_city_form->CurrentCity->Body.CivID, mill) && + has_active_building (p_city_form->CurrentCity, mill->improv_id) && + has_resources_required_by_building (p_city_form->CurrentCity, mill->improv_id)) + generated_resources[generated_resource_count++] = mill->resource_id; + } + + if ((generated_resource_count > 0) && (is->resources_sheet != NULL) && (is->resources_sheet->JGL.Image != NULL) && (TransparentBlt != NULL)) { + JGL_Image * jgl_canvas = canvas->JGL.Image, + * jgl_sheet = is->resources_sheet->JGL.Image; + + HDC canvas_dc = jgl_canvas->vtable->acquire_dc (jgl_canvas); + if (canvas_dc != NULL) { + HDC sheet_dc = jgl_sheet->vtable->acquire_dc (jgl_sheet); + if (sheet_dc != NULL) { + + for (int n = 0; n < generated_resource_count; n++) { + int icon_id = p_bic_data->ResourceTypes[generated_resources[n]].IconID, + sheet_row = icon_id / 6, + sheet_col = icon_id % 6; + + int dy = (n * 160 / not_below (1, generated_resource_count - 1) + 5) / 10; + TransparentBlt (canvas_dc, // dest DC + pixel_x + 15, pixel_y + dy, 24, 24, // dest x, y, width, height + sheet_dc, // src DC + 9 + 50*sheet_col, 9 + 50*sheet_row, 33, 33, // src x, y, width, height + 0xFF00FF); // transparent color (RGB) + } + + jgl_sheet->vtable->release_dc (jgl_sheet, __, 1); + } + jgl_canvas->vtable->release_dc (jgl_canvas, __, 1); + } + } + return tr; +} + +void __cdecl +patch_draw_improv_icons_on_city_screen (Base_List_Control * control, int improv_id, int item_index, int offset_x, int offset_y) +{ + is->drawing_icons_for_improv_id = improv_id; + draw_improv_icons_on_city_screen (control, improv_id, item_index, offset_x, offset_y); + is->drawing_icons_for_improv_id = -1; +} + +int __fastcall +patch_City_get_tourism_amount_to_draw (City * this, int edx, int improv_id) +{ + is->tourism_icon_counter = 0; + + int mill_food, mill_shields, mill_commerce; + gather_mill_yields (this, improv_id, &mill_food, &mill_shields, &mill_commerce); + int combined_commerce = mill_commerce + City_get_tourism_amount (this, __, improv_id); + + is->convert_displayed_tourism_to_food = mill_food; + is->convert_displayed_tourism_to_shields = mill_shields; + is->combined_tourism_and_mill_commerce = combined_commerce; + return int_abs (mill_food) + int_abs (mill_shields) + int_abs (combined_commerce); +} + +int __fastcall +patch_Sprite_draw_tourism_gold (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + // Replace the yield sprite we're drawing with food or a shield if needed. + Sprite * sprite = NULL; { + if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food)) { + if (is->convert_displayed_tourism_to_food >= 0) + sprite = &p_city_form->City_Icons_Images.Icon_15_Food; + else { + init_red_food_icon (); + if (is->red_food_icon_state == IS_OK) + sprite = &is->red_food_icon; + } + } else if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food) + int_abs (is->convert_displayed_tourism_to_shields)) + sprite = (is->convert_displayed_tourism_to_shields >= 0) ? &p_city_form->City_Icons_Images.Icon_13_Shield : &p_city_form->City_Icons_Images.Icon_05_Shield_Outcome; + else if (is->combined_tourism_and_mill_commerce < 0) + sprite = &p_city_form->City_Icons_Images.Icon_17_Gold_Outcome; + else + sprite = this; + } + + int tr = 0; // return value is not used by caller + if (sprite != NULL) + tr = Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, color_table); + is->tourism_icon_counter++; + return tr; +} + +Unit * __fastcall +patch_Leader_spawn_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) +{ + int spawn_x = tile_x, + spawn_y = tile_y; + + if (is->current_config.enable_districts) { + UnitType * type = &p_bic_data->UnitTypes[type_id]; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities) { + City * spawn_city = city_at (tile_x, tile_y); + if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { + int district_x, district_y; + Tile * district_tile = get_completed_district_tile_for_city (spawn_city, AERODROME_DISTRICT_ID, &district_x, &district_y); + if ((district_tile != NULL) && (district_tile != p_null_tile) && + (district_tile->Territory_OwnerID == this->ID) && + is_below_stack_limit (district_tile, this->ID, type_id)) { + spawn_x = district_x; + spawn_y = district_y; + } + } + } + + if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities) { + City * spawn_city = city_at (tile_x, tile_y); + if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { + int district_x, district_y; + Tile * district_tile = get_completed_district_tile_for_city (spawn_city, PORT_DISTRICT_ID, &district_x, &district_y); + if ((district_tile != NULL) && (district_tile != p_null_tile) && + (district_tile->Territory_OwnerID == this->ID) && + is_below_stack_limit (district_tile, this->ID, type_id)) { + spawn_x = district_x; + spawn_y = district_y; + } + } + } + } + + Unit * tr = Leader_spawn_unit (this, __, type_id, spawn_x, spawn_y, barb_tribe_id, id, param_6, leader_kind, race_id); + if (tr != NULL) + change_unit_type_count (this, type_id, 1); + return tr; +} + +Unit * __fastcall +patch_Leader_spawn_captured_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) +{ + Unit * tr = patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); + if ((tr != NULL) && is->moving_unit_to_adjacent_tile) + is->temporarily_disallow_lethal_zoc = true; + return tr; +} + +void __fastcall +patch_Leader_enter_new_era (Leader * this, int edx, bool param_1, bool no_online_sync) +{ + Leader_enter_new_era (this, __, param_1, no_online_sync); + apply_era_specific_names (this); +} + +char * __fastcall +patch_Leader_get_player_title_for_intro_popup (Leader * this) +{ + // Normally the era-specific names are applied later, after game loading is finished, but in this case we apply the player's names ahead of + // time so they appear on the intro popup. "this" will always refer to the human player in this call. + apply_era_specific_names (this); + return Leader_get_title (this); +} + +void __fastcall +patch_City_spawn_unit_if_done (City * this) +{ + bool skip_spawn = false; + + // Apply unit limit. If this city's owner has reached the limit for the unit type it's building then force it to build something else. + int available; + if ((this->Body.Order_Type == COT_Unit) && + get_available_unit_count (&leaders[this->Body.CivID], this->Body.Order_ID, &available) && + (available <= 0)) { + int limited_unit_type_id = this->Body.Order_ID; + + if (*p_human_player_bits & 1<Body.CivID) { + // Find another type ID to build instead of the limited one + int replacement_type_id = -1; { + int limited_unit_strat = p_bic_data->UnitTypes[limited_unit_type_id].AI_Strategy, + shields_in_box = this->Body.StoredProduction; + UnitType * replacement_type; + for (int can_type_id = 0; can_type_id < p_bic_data->UnitTypeCount; can_type_id++) + if (patch_City_can_build_unit (this, __, can_type_id, 1, 0, 0)) { + UnitType * candidate_type = &p_bic_data->UnitTypes[can_type_id]; + + // If we haven't found a replacement yet, use this one + if (replacement_type_id < 0) { + replacement_type_id = can_type_id; + replacement_type = candidate_type; + + // Keep the prev replacement if it doesn't waste shields but this candidate would + } else if ((replacement_type->Cost >= shields_in_box) && (candidate_type->Cost < shields_in_box)) + continue; + + // Keep the prev if it shares an AI strategy with the limited unit but this candidate doesn't + else if (((replacement_type->AI_Strategy & limited_unit_strat) != 0) && + ((candidate_type ->AI_Strategy & limited_unit_strat) == 0)) + continue; + + // At this point we know switching to the candidate would not cause us to waste shields and would not + // give us a worse match role-wise to the original limited unit. So pick it if it's better somehow, + // either a better role match or more expensive. + else if ((candidate_type->Cost > replacement_type->Cost) || + (((replacement_type->AI_Strategy & limited_unit_strat) == 0) && + ((candidate_type ->AI_Strategy & limited_unit_strat) != 0))) { + replacement_type_id = can_type_id; + replacement_type = candidate_type; + } + } + } + + if (replacement_type_id >= 0) { + City_set_production (this, __, COT_Unit, replacement_type_id, false); + if (this->Body.CivID == p_main_screen_form->Player_CivID) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, this->Body.CityName, -1, -1); + set_popup_str_param (1, p_bic_data->UnitTypes[limited_unit_type_id].Name, -1, -1); + int limit = -1; + get_unit_limit (&leaders[this->Body.CivID], limited_unit_type_id, &limit); + set_popup_int_param (2, limit); + set_popup_str_param (3, p_bic_data->UnitTypes[replacement_type_id].Name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_LIMITED_UNIT_CHANGE", -1, 0, 0, 0); + int response = patch_show_popup (popup, __, 0, 0); + if (response == 0) + *p_zoom_to_city_after_update = true; + } + } + + } else { + City_Order order; + patch_City_ai_choose_production (this, __, &order); + City_set_production (this, __, order.OrderType, order.OrderID, false); + } + + // If the player changed production to something other than a unit, don't spawn anything + if (this->Body.Order_Type != COT_Unit) + skip_spawn = true; + + // Just as a final check, if we weren't able to switch production off the limited unit, prevent it from being spawned so the limit + // doesn't get violated. + if ((this->Body.Order_Type == COT_Unit) && (this->Body.Order_ID == limited_unit_type_id)) + skip_spawn = true; + } + + // Check district requirements for air and naval units + if ((! skip_spawn) && (this->Body.Order_Type == COT_Unit) && is->current_config.enable_districts) { + int unit_id = this->Body.Order_ID; + UnitType * type = &p_bic_data->UnitTypes[unit_id]; + bool needs_district = false; + int required_district_id = -1; + + // Air units require aerodrome + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (this, AERODROME_DISTRICT_ID))) { + needs_district = true; + required_district_id = AERODROME_DISTRICT_ID; + } + // Naval units require port + else if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (this, PORT_DISTRICT_ID))) { + needs_district = true; + required_district_id = PORT_DISTRICT_ID; + } + + if (needs_district) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + + // For AI, redirect to a safe fallback and queue the missing district. + // For humans, this late hook should only veto the spawn and show a warning, + // otherwise the city gets switched off the intended build with no unit spawned. + if (! is_human) { + mark_city_needs_district (this, required_district_id); + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (this, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + // Show message to human player + if (is_human && (this->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[160]; + char const * unit_name = type->Name; + char const * district_name = is->district_configs[required_district_id].name; + snprintf (msg, sizeof msg, "%s %s %s", unit_name, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_name); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (this->Body.X, this->Body.Y, msg, true); + } + + skip_spawn = true; + } + } + + if (! skip_spawn) + City_spawn_unit_if_done (this); +} + +void __fastcall +patch_Leader_upgrade_all_units (Leader * this, int edx, int type_id) +{ + is->penciled_in_upgrade_count = 0; + Leader_upgrade_all_units (this, __, type_id); +} + +void __fastcall +patch_Main_Screen_Form_upgrade_all_units (Main_Screen_Form * this, int edx, int type_id) +{ + is->penciled_in_upgrade_count = 0; + Main_Screen_Form_upgrade_all_units (this, __, type_id); +} + +bool __fastcall +patch_Unit_can_perform_upgrade_all (Unit * this, int edx, int unit_command_value) +{ + bool base = patch_Unit_can_perform_command (this, __, unit_command_value); + + // Deal with unit limits. If the unit type we're upgrading to is limited, we need to pencil in the upgrade to make sure that we don't queue up + // so many upgrades that we exceed the limit. + City * city; + int upgrade_id, available; + if (base && + (is->current_config.unit_limits.len > 0) && + (NULL != (city = city_at (this->Body.X, this->Body.Y))) && + (0 <= (upgrade_id = City_get_upgraded_type_id (city, __, this->Body.UnitTypeID))) && + get_available_unit_count (&leaders[this->Body.CivID], upgrade_id, &available)) { + + // Find penciled in upgrade. Add a new one if we don't already have one. + struct penciled_in_upgrade * piu = NULL; { + for (int n = 0; n < is->penciled_in_upgrade_count; n++) + if (is->penciled_in_upgrades[n].unit_type_id == upgrade_id) { + piu = &is->penciled_in_upgrades[n]; + break; + } + if (piu == NULL) { + reserve (sizeof is->penciled_in_upgrades[0], (void **)&is->penciled_in_upgrades, &is->penciled_in_upgrade_capacity, is->penciled_in_upgrade_count); + piu = &is->penciled_in_upgrades[is->penciled_in_upgrade_count]; + is->penciled_in_upgrade_count += 1; + piu->unit_type_id = upgrade_id; + piu->count = 0; + } + } + + // If we can have more units of the type we're upgrading to, pencil in another upgrade and return true. Otherwise return false so this + // unit isn't considered one of the upgradable ones. + if (piu->count < available) { + piu->count += 1; + return true; + } else + return false; + + } else + return base; +} + +void __fastcall +patch_Fighter_animate_start_of_combat (Fighter * this, int edx, Unit * attacker, Unit * defender) +{ + // Temporarily clear the attacker retreat eligibility flag when needed so naval units are rotated and animated properly. Normally the game + // does not use ranged animations when the attacker can retreat and, worse, not using ranged anims means it also ignores the + // rotate-before-attack setting. + bool restore_attacker_retreat_eligibility = false; + if ((is->current_config.sea_retreat_rules != RR_STANDARD) && + (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Sea) && + Unit_has_ability (attacker, __, UTA_Ranged_Attack_Animation) && + Unit_has_ability (defender, __, UTA_Ranged_Attack_Animation) && + this->attacker_eligible_to_retreat) { + this->attacker_eligible_to_retreat = false; + restore_attacker_retreat_eligibility = true; + } + + Fighter_animate_start_of_combat (this, __, attacker, defender); + + if (restore_attacker_retreat_eligibility) + this->attacker_eligible_to_retreat = true; +} + +Unit * __fastcall +patch_Leader_spawn_unit_from_building (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) +{ + int available; + if (get_available_unit_count (this, type_id, &available) && (available <= 0)) + return NULL; + else + return patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); +} + +int __fastcall +patch_City_count_improvs_enabling_upgrade (City * this, int edx, enum ImprovementTypeFlags flag) +{ + return is->current_config.allow_upgrades_in_any_city ? 1 : City_count_improvements_with_flag (this, __, flag); +} + +City * __fastcall +patch_Leader_create_city_from_hut (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_POPPED_FROM_HUT); + return tr; +} + +City * __fastcall +patch_Leader_create_city_for_ai_respawn (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_PLACED_FOR_AI_RESPAWN); + return tr; +} + +City * __fastcall +patch_Leader_create_city_for_founding (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_FOUNDED); + return tr; +} + +City * __fastcall +patch_Leader_create_city_for_scenario (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_PLACED_FOR_SCENARIO); + return tr; +} + +City * +find_city_to_inherit_shared_small_wonder (Leader * leader, int wonder_improv_id) +{ + if ((leader == NULL) || + (! is->current_config.enable_districts) || + (! is->current_config.enable_wonder_districts) || + (! is->current_config.cities_with_mutual_district_receive_wonders)) + return NULL; + + FOR_CITIES_OF (coi, leader->ID) { + City * city = coi.city; + if ((city == NULL) || (! patch_City_has_improvement (city, __, wonder_improv_id, false))) + continue; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + Tile * tile = wai.tile; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if ((info == NULL) || (info->state != WDS_COMPLETED)) + continue; + + int nearby_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); + if (nearby_improv_id == wonder_improv_id) + return city; + } + } + + return NULL; +} + +void +collect_small_wonders_present_in_city (City * city, int * lost_small_wonders, int * lost_small_wonder_count, int max_lost_small_wonders) +{ + if ((city == NULL) || + (lost_small_wonders == NULL) || + (lost_small_wonder_count == NULL) || + (max_lost_small_wonders <= 0)) + return; + + *lost_small_wonder_count = 0; + + if (! is->current_config.enable_districts || + ! is->current_config.enable_wonder_districts || + ! is->current_config.cities_with_mutual_district_receive_wonders) + return; + + for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) == 0) + continue; + if (! patch_City_has_improvement (city, __, improv_id, false)) + continue; + if (*lost_small_wonder_count >= max_lost_small_wonders) + break; + lost_small_wonders[(*lost_small_wonder_count)++] = improv_id; + } +} + +void +reassign_shared_small_wonder_owners_after_city_loss (Leader * leader, int const * lost_small_wonders, int lost_small_wonder_count) +{ + if ((! is->current_config.enable_districts) || + (leader == NULL) || + (! is->current_config.enable_wonder_districts) || + (! is->current_config.cities_with_mutual_district_receive_wonders) || + (lost_small_wonders == NULL) || + (lost_small_wonder_count <= 0)) + return; + + for (int n = 0; n < lost_small_wonder_count; n++) { + int improv_id = lost_small_wonders[n]; + if ((improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) + continue; + + if (leader->Small_Wonders[improv_id] != -1) + continue; + + // Vanilla clears Leader.Small_Wonders when the recorded owner city loses the building during + // capture. Only repair the small wonders that were actually present in the lost city before + // capture, and if another city of the same civ still legitimately shares the wonder district, + // promote that city to be the new canonical owner so the small wonder's effects still work. + City * replacement = find_city_to_inherit_shared_small_wonder (leader, improv_id); + if (replacement != NULL) + leader->Small_Wonders[improv_id] = replacement->Body.ID; + } +} + +bool __fastcall +patch_Leader_do_capture_city (Leader * this, int edx, City * city, bool involuntary, bool converted) +{ + Leader * previous_owner = &leaders[city->Body.CivID]; + int lost_small_wonders[32]; + int lost_small_wonder_count; + + // Record which small wonders were physically present in the city before capture so any + // post-capture ownership repair only touches wonders actually affected. + collect_small_wonders_present_in_city (city, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); + + is->currently_capturing_city = city; + on_lose_city (previous_owner, city, converted ? CLR_CONVERTED : (involuntary ? CLR_CONQUERED : CLR_TRADED)); + bool tr = Leader_do_capture_city (this, __, city, involuntary, converted); + + // The game clears the losing civ's canonical Small_Wonders owner when the recorded city loses + // the building. Reassign that ownership here if another same-civ city still legitimately shares the wonder district. + if (is->current_config.enable_districts && + is->current_config.enable_wonder_districts && + is->current_config.cities_with_mutual_district_receive_wonders && + lost_small_wonder_count > 0) { + reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); + } + + on_gain_city (this, city, converted ? CGR_CONVERTED : (involuntary ? CGR_CONQUERED : CGR_TRADED)); + is->currently_capturing_city = NULL; + return tr; +} + +void __fastcall +patch_City_raze (City * this, int edx, int civ_id_responsible, bool checking_elimination) +{ + Leader * previous_owner = &leaders[this->Body.CivID]; + int lost_small_wonders[32]; + int lost_small_wonder_count; + + collect_small_wonders_present_in_city (this, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); + on_lose_city (previous_owner, this, CLR_DESTROYED); + City_raze (this, __, civ_id_responsible, checking_elimination); + + if (lost_small_wonder_count > 0) + reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); + + // Delete the extra improvement bits records for this city + City_Improvements * improv_lists[2] = {&this->Body.Improvements_1, &this->Body.Improvements_2}; + for (int n = 0; n < ARRAY_LEN (improv_lists); n++) { + City_Improvements * improv_list = improv_lists[n]; + byte * extra_bits; + if (itable_look_up (&is->extra_city_improvs, (int)improv_list, (int *)&extra_bits)) { + free (extra_bits); + itable_remove (&is->extra_city_improvs, (int)improv_list); + } + } +} + +void __fastcall +patch_City_draw_hud_icon (City * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y) +{ + Leader * owner = &leaders[this->Body.CivID]; + int restore_capital = owner->CapitalID; + + // Temporarily set this city as the capital if it has an extra palace so it gets the capital star icon + if ((is->current_config.ai_multi_city_start > 1) && + ((*p_human_player_bits & (1 << owner->ID)) == 0) && + has_extra_palace (this)) + owner->CapitalID = this->Body.ID; + + City_draw_hud_icon (this, __, canvas, pixel_x, pixel_y); + owner->CapitalID = restore_capital; +} + +bool __fastcall +patch_City_has_hud_icon (City * this) +{ + return City_has_hud_icon (this) + || ( (is->current_config.ai_multi_city_start > 1) + && ((*p_human_player_bits & (1 << this->Body.CivID)) == 0) + && has_extra_palace (this)); +} + +void __fastcall +patch_City_draw_on_map (City * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) +{ + Leader * owner = &leaders[this->Body.CivID]; + int restore_capital = owner->CapitalID; + + if (is->current_config.do_not_make_capital_cities_appear_larger) + owner->CapitalID = -1; + + // Temporarily set this city as the capital if it has an extra palace so it gets drawn with the next larger size + else if ((is->current_config.ai_multi_city_start > 1) && + ((*p_human_player_bits & (1 << owner->ID)) == 0) && + has_extra_palace (this)) + owner->CapitalID = this->Body.ID; + + City_draw_on_map (this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); + owner->CapitalID = restore_capital; +} + +// Writes a string to replace "Wake" or "Activate" on the right-click menu entry for the given unit. Some units might not have a replacement, in which +// case the function writes nothing and returns false. The string is written to out_str which must point to a buffer of at least str_capacity bytes. +bool +get_menu_verb_for_unit (Unit * unit, char * out_str, int str_capacity) +{ + struct state_desc { + enum c3x_label label; + bool is_doing_worker_job; + } state_descs[35] = { + {CL_IDLE , false}, // [No state] = 0x0 + {CL_FORTIFIED , false}, // Fortifying = 0x1 + {CL_MINING , true }, // Build_Mines = 0x2 + {CL_IRRIGATING , true }, // Irrigate = 0x3 + {CL_BUILDING_FORTRESS , true }, // Build_Fortress = 0x4 + {CL_BUILDING_ROAD , true }, // Build_Road = 0x5 + {CL_BUILDING_RAILROAD , true }, // Build_Railroad = 0x6 + {CL_PLANTING_FOREST , true }, // Plant_Forest = 0x7 + {CL_CLEARING_FOREST , true }, // Clear_Forest = 0x8 + {CL_CLEARING_WETLANDS , true }, // Clear_Wetlands = 0x9 + {CL_CLEARING_DAMAGE , true }, // Clear_Damage = 0xA + {CL_BUILDING_AIRFIELD , true }, // Build_Airfield = 0xB + {CL_BUILDING_RADAR_TOWER, true }, // Build_Radar_Tower = 0xC + {CL_BUILDING_OUTPOST , true }, // Build_Outpost = 0xD + {CL_BUILDING_BARRICADE , true }, // Build_Barricade = 0xE + {CL_INTERCEPTING , false}, // Intercept = 0xF + {CL_MOVING , false}, // Go_To = 0x10 + {CL_BUILDING_ROAD , true }, // Road_To_Tile = 0x11 + {CL_BUILDING_RAILROAD , true }, // Railroad_To_Tile = 0x12 + {CL_BUILDING_COLONY , true }, // Build_Colony = 0x13 + {CL_AUTOMATED , true }, // Auto_Irrigate = 0x14 + {CL_AUTOMATED , true }, // Build_Trade_Routes = 0x15 + {CL_AUTOMATED , true }, // Auto_Clear_Forest = 0x16 + {CL_AUTOMATED , true }, // Auto_Clear_Swamp = 0x17 + {CL_AUTOMATED , true }, // Auto_Clear_Pollution = 0x18 + {CL_AUTOMATED , true }, // Auto_Save_City_Tiles = 0x19 + {CL_EXPLORING , false}, // Explore = 0x1A + {CL_IN_STATE_27 , false}, // ? = 0x1B + {CL_IN_STATE_28 , false}, // Fleeing = 0x1C + {CL_IN_STATE_29 , false}, // ? = 0x1D + {CL_IN_STATE_30 , false}, // ? = 0x1E + {CL_BOMBARDING , false}, // Auto_Bombard = 0x1F + {CL_BOMBARDING , false}, // Auto_Air_Bombard = 0x20 + {CL_BOMBARDING , false}, // Auto_Precision_Strike = 0x21 + {CL_IDLE , false}, // Exhausted = 0x22 + }; + enum UnitStateType state = unit->Body.UnitState; + struct state_desc const * desc; + if ((state >= 0) && (state < ARRAY_LEN (state_descs)) && (desc = &state_descs[state]) && (desc->label >= 0) && (desc->label < COUNT_C3X_LABELS)) { + enum c3x_label label = desc->label; + Unit * container; + if (((label == CL_IDLE) || (label == CL_MOVING) || (label == CL_IN_STATE_29) || desc->is_doing_worker_job) && unit->Body.automated) + label = CL_AUTOMATED; + else if ((label == CL_FORTIFIED) && (NULL != (container = get_unit_ptr (unit->Body.Container_Unit))) && ! Unit_has_ability (container, __, UTA_Army)) + label = CL_TRANSPORTED; + else if ((label == CL_FORTIFIED) && (unit->Body.Status & (USF_SENTRY | USF_SENTRY_ENEMY_ONLY))) + label = CL_SENTRY; + else if ((label == CL_MINING) && is->current_config.enable_districts) { + + // Check if this unit is actually building a district instead of a mine + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + struct district_instance * inst = get_district_instance (tile); + if ((tile != NULL) && (tile != p_null_tile) && inst != NULL) { + char const * district_name = is->district_configs[inst->district_id].name; + snprintf (out_str, str_capacity, "%s %s", is->c3x_labels[CL_BUILDING], district_name); + out_str[str_capacity - 1] = '\0'; + return true; + } + } + + strncpy (out_str, is->c3x_labels[label], str_capacity); + out_str[str_capacity - 1] = '\0'; + return true; + } else + return false; +} + +void __fastcall +patch_MenuUnitItem_write_text_to_temp_str (MenuUnitItem * this) +{ + MenuUnitItem_write_text_to_temp_str (this); + + Unit * unit = this->unit; + char repl_verb[32]; + if (is->current_config.describe_states_of_units_on_menu && + (unit->Body.CivID == p_main_screen_form->Player_CivID) && + (Unit_get_containing_army (unit) == NULL) && + get_menu_verb_for_unit (unit, repl_verb, sizeof repl_verb)) { + char * verb = (unit->Body.UnitState == UnitState_Fortifying) ? (*p_labels)[LBL_WAKE] : (*p_labels)[LBL_ACTIVATE]; + char * verb_str_start = strstr (temp_str, verb); + if (verb_str_start != NULL) { + char s[500]; + char * verb_str_end = verb_str_start + strlen (verb); + snprintf (s, sizeof s, "%.*s%s%s", verb_str_start - temp_str, temp_str, repl_verb, verb_str_end); + s[(sizeof s) - 1] = '\0'; + strncpy (temp_str, s, sizeof s); + } + } +} + +void __fastcall +patch_Tile_m74_Set_Square_Type_for_hill_gen (Tile * this, int edx, enum SquareTypes sq, int tile_x, int tile_y) +{ + if ((sq == SQ_Volcano) && is->current_config.do_not_generate_volcanos) + sq = SQ_Mountains; + this->vtable->m74_Set_Square_Type (this, __, sq, tile_x, tile_y); +} + +void __fastcall +patch_Map_place_scenario_things (Map * this) +{ + is->is_placing_scenario_things = true; + + Map_place_scenario_things (this); + + // If there are any mills in the config then recompute yields & happiness in all cities. This must be done because we avoid doing this as + // mills are added to cities while placing scenario things. + if (is->current_config.count_mills > 0) + for (int n = 0; n <= p_cities->LastIndex; n++) { + City * city = get_city_ptr (n); + if (city != NULL) + patch_City_recompute_yields_and_happiness (city); + } + + if (is->current_config.enable_districts || + is->current_config.enable_natural_wonders || + is->current_config.enable_named_tiles) + load_scenario_districts_from_file (); + + if (is->current_config.enable_natural_wonders && + is->current_config.add_natural_wonders_to_scenarios_if_none) { + bool any_natural_wonders = false; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst != NULL) && + (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) { + any_natural_wonders = true; + break; + } + } + if (! any_natural_wonders) + place_natural_wonders_on_map (); + } + is->is_placing_scenario_things = false; +} + +void +on_open_advisor (AdvisorKind kind) +{ + recompute_resources_if_necessary (); +} + +bool __fastcall patch_Advisor_Base_Form_domestic_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_DOMESTIC); return Advisor_Base_Form_domestic_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_trade_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_TRADE) ; return Advisor_Base_Form_trade_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_military_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_MILITARY); return Advisor_Base_Form_military_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_foreign_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_FOREIGN) ; return Advisor_Base_Form_foreign_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_cultural_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_CULTURAL); return Advisor_Base_Form_cultural_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_science_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_SCIENCE) ; return Advisor_Base_Form_science_m95 (this); } + +void __fastcall +patch_Main_Screen_Form_open_quick_build_chooser (Main_Screen_Form * this, int edx, City * city, int mouse_x, int mouse_y) +{ + recompute_resources_if_necessary (); + Main_Screen_Form_open_quick_build_chooser (this, __, city, mouse_x, mouse_y); +} + +int __fastcall +patch_Context_Menu_get_selected_item_on_unit_rcm (Context_Menu * this) +{ + // In the base game, this method returns -1 for any disabled item which prevents the player from clicking those. We want players to be able to + // click unit items which have been disabled by the mod so they can interrupt the queued actions of units that have no moves left. + int index = this->Selected_Item; + if (index >= 0) { + if (is->current_config.enable_named_tiles && is->named_tile_menu_active) { + Context_Menu_Item * item = &this->Items[index]; + if (item->Menu_Item_ID == NAMED_TILE_MENU_ID) { + handle_named_tile_menu_selection (); + return -1; + } + } + bool is_enabled = (this->Items[index].Status & 2) == 0; + bool is_unit_item = (this->Items[index].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount)) >= 0; + return (is_enabled || is_unit_item) ? index : -1; + } + return -1; +} + +int __fastcall +patch_Tile_check_water_to_block_pollution (Tile * this) +{ + if (this->vtable->m35_Check_Is_Water (this)) + return 1; + else if (is->current_config.do_not_pollute_impassable_tiles) { + enum SquareTypes terrain_type = this->vtable->m50_Get_Square_BaseType (this); + return p_bic_data->TileTypes[terrain_type].Flags.Impassable; + } else + return 0; +} + +void __fastcall +patch_Tile_set_flag_for_eruption_damage (Tile * this, int edx, int param_1, int param_2, int x, int y) +{ + if (is->current_config.enable_districts) { + struct district_instance * inst = get_district_instance (this); + if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { + // District found - handle removal + int district_id = inst->district_id; + + // Notify human player if this tile is in their territory + int territory_owner = this->vtable->m38_Get_Territory_OwnerID (this); + if (territory_owner == p_main_screen_form->Player_CivID) { + char msg[160]; + char const * district_name = is->district_configs[district_id].name; + snprintf (msg, sizeof msg, "%s %s", district_name, is->c3x_labels[CL_DISTRICT_DESTROYED_BY_VOLCANO]); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (x, y, msg, true); + } + + // Remove the district + handle_district_removed (this, district_id, x, y, false); + + // Clear the mine flags + this->vtable->m62_Set_Tile_BuildingID (this, __, -1); + this->vtable->m51_Unset_Tile_Flags (this, __, 0, TILE_FLAG_MINE, x, y); + } + } + + // Apply the normal eruption damage (lava flag) if allowed + if (! (is->current_config.do_not_pollute_impassable_tiles && + p_bic_data->TileTypes[this->vtable->m50_Get_Square_BaseType (this)].Flags.Impassable)) + this->vtable->m56_Set_Tile_Flags (this, __, param_1, param_2, x, y); +} + +bool __fastcall +patch_City_confirm_production_switch (City * this, int edx, int order_type, int order_id) +{ + bool tr = City_confirm_production_switch (this, __, order_type, order_id); + if (tr && + (order_type == COT_Improvement) && (order_id >= 0) && (order_id < p_bic_data->ImprovementsCount) && + (this->Body.CivID == p_main_screen_form->Player_CivID) && + is->current_config.warn_when_chosen_building_would_replace_another) { + Improvement * improv = &p_bic_data->Improvements[order_id]; + if (improv->ImprovementFlags & ITF_Replaces_Other_Buildings) { + Improvement * replaced = NULL; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * other = &p_bic_data->Improvements[n]; + if ((other->ImprovementFlags & ITF_Replaces_Other_Buildings) && + patch_City_has_improvement (this, __, n, false)) { + replaced = other; + break; + } + } + if (replaced != NULL) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, improv->Name.S, -1, -1); + set_popup_str_param (1, replaced->Name.S, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARN_ABOUT_BUILDING_REPLACEMENT", -1, 0, 0, 0); + if (patch_show_popup (popup, __, 0, 0) == 1) + return false; + } + } + } + return tr; +} + +byte const c3x_save_segment_bookend[4] = {0x22, 'C', '3', 'X'}; + +// Writes a string to the buffer and pads the end so it's four-byte aligned (assuming the existing contents is already so aligned). +void +serialize_aligned_text (char const * text, struct buffer * b) +{ + int len = strlen (text); + if (len > 0) { + int padded_len = (len + 4) & ~3; // +1 for null terminator then +3 & ~3 for alignment + byte * p = buffer_allocate (b, padded_len); + strcpy (p, text); + for (int n = 0; n < padded_len - len; n++) + p[len + n] = (byte)0; + } +} + +void * __fastcall +patch_MappedFile_open_to_load_game (MappedFile * this, int edx, char * file_name, int sequential_access) +{ + void * tr = MappedFile_open (this, __, file_name, sequential_access); + if (tr != NULL) + is->accessing_save_file = this; + return tr; +} + +void * __fastcall +patch_MappedFile_create_file_to_save_game (MappedFile * this, int edx, LPCSTR file_path, unsigned file_size, int is_shared) +{ + // Determine if we're currently applying settler perfume to any AI player + bool any_current_settler_perfume = false; + if (is->current_config.ai_settler_perfume_on_founding != 0) { + int duration = is->current_config.ai_settler_perfume_on_founding_duration; + for (int n = 0; n < 32; n++) { + int last_founding_turn = is->turn_no_of_last_founding_for_settler_perfume[n]; + if ((last_founding_turn != -1) && ((*p_current_turn_no - last_founding_turn) < duration)) + any_current_settler_perfume = true; + } + } + + // Assemble mod save data + struct buffer mod_data = {0}; { + if (is->extra_defensive_bombards.len > 0) { + serialize_aligned_text ("extra_defensive_bombards", &mod_data); + itable_serialize (&is->extra_defensive_bombards, &mod_data); + } + if (is->airdrops_this_turn.len > 0) { + serialize_aligned_text ("airdrops_this_turn", &mod_data); + itable_serialize (&is->airdrops_this_turn, &mod_data); + } + if (is->unit_transport_ties.len > 0) { + serialize_aligned_text ("unit_transport_ties", &mod_data); + itable_serialize (&is->unit_transport_ties, &mod_data); + } + if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && is->waiting_units.len > 0) { + serialize_aligned_text ("waiting_units", &mod_data); + itable_serialize (&is->waiting_units, &mod_data); + } + if ((p_bic_data->ImprovementsCount > 256) && (p_cities->Cities != NULL) && (is->extra_city_improvs.len > 0)) { + serialize_aligned_text ("extra_city_improvs", &mod_data); + int extra_improv_count = p_bic_data->ImprovementsCount - 256; + *(int *)buffer_allocate (&mod_data, sizeof(int)) = extra_improv_count; + + int count_entries = 0; { + for (int n = 0; n <= p_cities->LastIndex; n++) { + City_Body * body = p_cities->Cities[n].City; + if ((body != NULL) && ((int)body != offsetof (City, Body))) { + int unused; + if (itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_1, &unused) || + itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_2, &unused)) + count_entries++; + } + } + } + *(int *)buffer_allocate (&mod_data, sizeof(int)) = count_entries; + + int ints_per_list = (extra_improv_count + 31) / 32; + int bytes_per_list = (extra_improv_count + 7) / 8; + for (int n = 0; n <= p_cities->LastIndex; n++) { + City_Body * body = p_cities->Cities[n].City; + if ((body != NULL) && ((int)body != offsetof (City, Body))) { + byte * extra_bit_lists[2]; + extra_bit_lists[0] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_1, 0); + extra_bit_lists[1] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_2, 0); + if ((extra_bit_lists[0] != NULL) || (extra_bit_lists[1] != NULL)) { + *(int *)buffer_allocate (&mod_data, sizeof(int)) = body->ID; + for (int k = 0; k < 2; k++) { + int list_size = sizeof(int) * ints_per_list; + int * list = (int *)buffer_allocate (&mod_data, list_size); + memset (list, 0, list_size); + if (extra_bit_lists[k] != NULL) + memcpy (list, extra_bit_lists[k], bytes_per_list); + } + } + } + } + } + if (any_current_settler_perfume) { + serialize_aligned_text ("turn_no_of_last_founding_for_settler_perfume", &mod_data); + void * area = buffer_allocate (&mod_data, sizeof is->turn_no_of_last_founding_for_settler_perfume); + memcpy (area, is->turn_no_of_last_founding_for_settler_perfume, sizeof is->turn_no_of_last_founding_for_settler_perfume); + } + if (is->current_config.day_night_cycle_mode != DNCM_OFF) { + serialize_aligned_text ("current_day_night_cycle", &mod_data); + int_to_bytes (buffer_allocate (&mod_data, sizeof is->current_day_night_cycle), is->current_day_night_cycle); + } + if (is->current_config.enable_districts && (is->district_count > 0)) { + serialize_aligned_text ("district_config_names", &mod_data); + int * entry_count = (int *)buffer_allocate (&mod_data, sizeof(int)); + *entry_count = is->district_count; + for (int district_id = 0; district_id < is->district_count; district_id++) { + *(int *)buffer_allocate (&mod_data, sizeof(int)) = district_id; + char const * name = is->district_configs[district_id].name; + if (name == NULL) + name = ""; + serialize_aligned_text (name, &mod_data); + } + } + + if (is->current_config.enable_districts) { + int entry_count = 0; + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req != NULL) && (req->city_id >= 0)) + entry_count++; + } + } + if (entry_count > 0) { + serialize_aligned_text ("district_pending_requests", &mod_data); + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 5 * entry_count)); + int * out = chunk + 1; + chunk[0] = entry_count; + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req == NULL) || (req->city_id < 0)) + continue; + out[0] = req->city_id; + out[1] = req->district_id; + out[2] = req->assigned_worker_id; + out[3] = req->target_x; + out[4] = req->target_y; + out += 5; + } + } + } + } + + if (is->current_config.enable_districts && + (is->city_pending_building_orders.len > 0)) { + int entry_count = 0; + FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { + City * city = (City *)tei.key; + int improv_id = tei.value; + if ((city != NULL) && (improv_id >= 0)) + entry_count++; + } + if (entry_count > 0) { + serialize_aligned_text ("building_pending_orders", &mod_data); + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 2 * entry_count)); + int * out = chunk + 1; + chunk[0] = entry_count; + FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { + City * city = (City *)tei.key; + int improv_id = tei.value; + if ((city == NULL) || (improv_id < 0)) + continue; + out[0] = city->Body.ID; + out[1] = improv_id; + out += 2; + } + } + } + + if (is->current_config.enable_districts && (is->district_tile_map.len > 0)) { + serialize_aligned_text ("district_tile_map", &mod_data); + int entry_capacity = is->district_tile_map.len; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 9 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * tile = (Tile *)tei.key; + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst == NULL) + continue; + int x, y; + if (! district_instance_get_coords (inst, tile, &x, &y)) + continue; + int wonder_city_id = inst->wonder_info.city_id; + if (wonder_city_id >= 0) { + City * info_city = get_city_ptr (wonder_city_id); + inst->wonder_info.city = info_city; + if (info_city == NULL) + wonder_city_id = -1; + } else + inst->wonder_info.city = NULL; + out[0] = x; + out[1] = y; + out[2] = inst->district_id; + out[3] = (int)inst->state; + out[4] = inst->built_by_civ_id; + out[5] = inst->completed_turn; + out[6] = (int)inst->wonder_info.state; + out[7] = wonder_city_id; + out[8] = inst->wonder_info.wonder_index; + out += 9; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 9 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + + if (is->current_config.enable_natural_wonders && (is->district_tile_map.len > 0)) { + int entry_capacity = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + if (inst->natural_wonder_info.natural_wonder_id < 0) + continue; + entry_capacity++; + } + if (entry_capacity > 0) { + serialize_aligned_text ("natural_wonder_districts", &mod_data); + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * tile = (Tile *)tei.key; + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || + (inst->district_id != NATURAL_WONDER_DISTRICT_ID) || + (inst->natural_wonder_info.natural_wonder_id < 0)) + continue; + int x, y; + if (! district_instance_get_coords (inst, tile, &x, &y)) + continue; + out[0] = x; + out[1] = y; + out[2] = inst->natural_wonder_info.natural_wonder_id; + out += 3; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + } + + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts && + (is->distribution_hub_records.len > 0)) { + serialize_aligned_text ("distribution_hub_records", &mod_data); + int entry_capacity = is->distribution_hub_records.len; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (rec == NULL) + continue; + out[0] = rec->tile_x; + out[1] = rec->tile_y; + out[2] = rec->civ_id; + out += 3; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + + if (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (is->aerodrome_airlift_usage.len > 0)) { + serialize_aligned_text ("aerodrome_airlift_usage", &mod_data); + int entry_capacity = is->aerodrome_airlift_usage.len; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { + Tile * tile = (Tile *)tei.key; + int mask = tei.value; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + continue; + + out[0] = tile_x; + out[1] = tile_y; + out[2] = mask; + out += 3; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + + if (is->current_config.enable_named_tiles && (is->named_tile_map.len > 0)) { + serialize_aligned_text ("named_tiles", &mod_data); + int entry_capacity = is->named_tile_map.len; + int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); + byte * chunk = (byte *)buffer_allocate (&mod_data, (int)sizeof(int) + bytes_per_entry * entry_capacity); + int * count = (int *)chunk; + byte * out = (byte *)(count + 1); + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if ((entry == NULL) || (entry->name[0] == '\0')) + continue; + Tile * tile = (Tile *)tei.key; + int tile_x = entry->tile_x; + int tile_y = entry->tile_y; + if ((tile != NULL) && (tile != p_null_tile)) + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + ((int *)out)[0] = tile_x; + ((int *)out)[1] = tile_y; + out += sizeof(int) * 2; + memcpy (out, entry->name, sizeof entry->name); + out += sizeof entry->name; + written++; + } + *count = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * bytes_per_entry; + mod_data.length -= trimmed_bytes; + } + } + + if (is->great_wall_auto_build != GWABS_NOT_STARTED) { + serialize_aligned_text ("great_wall_auto_build_state", &mod_data); + *(int *)buffer_allocate (&mod_data, sizeof(int)) = (int)is->great_wall_auto_build; + } + + if (is->ai_candidate_bridge_or_canals_initialized || (is->ai_candidate_bridge_or_canals_count > 0)) { + serialize_aligned_text ("ai_candidate_bridge_or_canals", &mod_data); + int * header = (int *)buffer_allocate (&mod_data, sizeof(int) * 3); + header[0] = is->ai_candidate_bridge_or_canals_initialized ? 1 : 0; + header[1] = is->ai_candidate_bridge_or_canals_count; + header[2] = is->ai_candidate_bridge_or_canals_capacity; + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + int tile_count = (int)entry->tile_count; + if ((tile_count <= 0) || (entry->tile_x == NULL) || (entry->tile_y == NULL)) + tile_count = 0; + + int field_count = 14; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (field_count + tile_count * 2)); + int pending_city_id = entry->pending_req.city_id; + if ((pending_city_id < 0) && (entry->pending_req.city != NULL)) + pending_city_id = entry->pending_req.city->Body.ID; + + chunk[0] = entry->district_id; + chunk[1] = (int)entry->owner_civ_id; + chunk[2] = tile_count; + chunk[3] = (entry->tile_capacity > 0) ? entry->tile_capacity : tile_count; + chunk[4] = entry->assigned_tile_index; + chunk[5] = entry->assigned_worker_id; + chunk[6] = entry->completed ? 1 : 0; + chunk[7] = pending_city_id; + chunk[8] = entry->pending_req.civ_id; + chunk[9] = entry->pending_req.district_id; + chunk[10] = entry->pending_req.assigned_worker_id; + chunk[11] = entry->pending_req.target_x; + chunk[12] = entry->pending_req.target_y; + chunk[13] = entry->pending_req.worker_assigned_turn; + + int * out = chunk + field_count; + for (int ti = 0; ti < tile_count; ti++) { + out[0] = entry->tile_x[ti]; + out[1] = entry->tile_y[ti]; + out += 2; + } + } + } + } + + int metadata_size = (mod_data.length > 0) ? 12 : 0; // Two four-byte bookends plus one four-byte size, only written if there's any mod data + + void * tr = MappedFile_create_file (this, __, file_path, file_size + mod_data.length + metadata_size, is_shared); + if (tr != NULL) { + is->accessing_save_file = this; + if ((mod_data.length > 0) && (mod_data.length + metadata_size <= this->size)) { + // Write first bookend to mod's segment in the save data + byte * seg_start = (byte *)tr + file_size; + for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) + seg_start[n] = c3x_save_segment_bookend[n]; + + // Write actual mod game data + memcpy ((byte *)tr + file_size + 4, mod_data.contents, mod_data.length); + + // Write size of mod data + byte * seg_end = (byte *)tr + file_size + 4 + mod_data.length; + int_to_bytes (seg_end, mod_data.length); + + // Finish off with another bookend + for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) + seg_end[4+n] = c3x_save_segment_bookend[n]; + } + } + buffer_deinit (&mod_data); + return tr; +} + +bool +match_save_chunk_name (byte ** cursor, char const * name) +{ + if (strcmp (name, *cursor) == 0) { + // Move cursor past the string if it matched. Also move past any padding that was added to ensure alignment (see serialize_aligned_text). + *cursor = (byte *)((int)*cursor + strlen (name) + 4 & ~3); + return true; + } else + return false; +} + +bool +match_save_segment_bookend (byte * b) +{ + return memcmp (c3x_save_segment_bookend, b, ARRAY_LEN (c3x_save_segment_bookend)) == 0; +} + +int __cdecl +patch_move_game_data (byte * buffer, bool save_else_load) +{ + int tr = move_game_data (buffer, save_else_load); + + if (! save_else_load) { + // Free all district_instance structs first + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst != NULL) + free (inst); + } + table_deinit (&is->district_tile_map); + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if (entry != NULL) + free (entry); + } + table_deinit (&is->named_tile_map); + clear_all_tracked_workers (); + reset_ai_candidate_bridge_or_canals (); + } + + // Check for a mod save data section and load it if present + MappedFile * save; + int seg_size; + byte * seg; + if ((! save_else_load) && + ((save = is->accessing_save_file) != NULL) && + (save->size >= 8) && + match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - 4)) && + ((seg_size = int_from_bytes ((byte *)((int)save->base_addr + save->size - 8))) > 0) && + (save->size >= seg_size + 12) && + match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - seg_size - 12)) && + ((seg = malloc (seg_size)) != NULL)) { + memcpy (seg, (void *)((int)save->base_addr + save->size - seg_size - 8), seg_size); + + byte * cursor = seg; + char * error_chunk_name = NULL; + while (cursor < seg + seg_size) { + if (match_save_chunk_name (&cursor, "special save message")) { + char * msg = (char *)cursor; + cursor = (byte *)((int)cursor + strlen (msg) + 4 & ~3); + + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + PopupForm_add_text (popup, __, "This save contains a special message:", 0); + PopupForm_add_text (popup, __, msg, 0); + patch_show_popup (popup, __, 0, 0); + + } else if (match_save_chunk_name (&cursor, "extra_defensive_bombards")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->extra_defensive_bombards); + if (bytes_read > 0) + cursor += bytes_read; + else { + error_chunk_name = "extra_defensive_bombards"; + break; + } + + } else if (match_save_chunk_name (&cursor, "airdrops_this_turn")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->airdrops_this_turn); + if (bytes_read > 0) + cursor += bytes_read; + else { + error_chunk_name = "airdrops_this_turn"; + break; + } + + } else if (match_save_chunk_name (&cursor, "unit_transport_ties")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->unit_transport_ties); + if (bytes_read > 0) + cursor += bytes_read; + else { + error_chunk_name = "unit_transport_ties"; + break; + } + + } else if (match_save_chunk_name (&cursor, "waiting_units")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->waiting_units); + if (bytes_read > 0) { + cursor += bytes_read; + is->have_loaded_waiting_units = true; + } else { + error_chunk_name = "waiting_units"; + break; + } + + } else if (match_save_chunk_name (&cursor, "extra_city_improvs")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + + // Read two int vars from this save chunk + int file_extra_improv_count, count_entries; + if (remaining_bytes >= 8) { + file_extra_improv_count = *((int *)cursor)++; + count_entries = *((int *)cursor)++; + remaining_bytes -= 8; + } else + goto done_with_extra_city_improvs; + + // Check that the extra improv counts are valid. They must be greater than zero and what was stored in the save must + // match what we got from the current scenario data. + int extra_improv_count = not_below (0, p_bic_data->ImprovementsCount - 256); + if ((file_extra_improv_count <= 0) || (extra_improv_count != file_extra_improv_count)) + goto done_with_extra_city_improvs; + + // The extra bits data in the save is stored in 32-bit chunks, "ints", to maintain alignment. Compute how many ints we + // need for each list of bits and check that reading all entries won't overrun the buffer. + int ints_per_list = (extra_improv_count + 31) / 32, + ints_per_entry = 1 + 2 * ints_per_list; + if (count_entries * ints_per_entry * sizeof(int) > remaining_bytes) + goto done_with_extra_city_improvs; + + // Main loop reading the extra bits data + for (int n = 0; n < count_entries; n++) { + City * city = get_city_ptr (*((int *)cursor)++); + if (city == NULL) + goto done_with_extra_city_improvs; + + byte * extra_bits_1 = calloc (sizeof (int), ints_per_list); + for (int k = 0; k < ints_per_list; k++) + ((int *)extra_bits_1)[k] = *((int *)cursor)++; + itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_1, (int)extra_bits_1); + + byte * extra_bits_2 = calloc (sizeof (int), ints_per_list); + for (int k = 0; k < ints_per_list; k++) + ((int *)extra_bits_2)[k] = *((int *)cursor)++; + itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_2, (int)extra_bits_2); + } + + // Rebuild the trade network since it may have changed as a result of the additional buildings. This method also + // refreshes the free improvement tables and recomputes city happiness. + patch_Map_build_trade_network (&p_bic_data->Map); + + success = true; + + done_with_extra_city_improvs: + if (! success) { + error_chunk_name = "extra_city_improvs";; + break; + } + + } else if (match_save_chunk_name (&cursor, "turn_no_of_last_founding_for_settler_perfume")) { + for (int n = 0; n < 32; n++) + is->turn_no_of_last_founding_for_settler_perfume[n] = *((int *)cursor)++; + + } else if (match_save_chunk_name (&cursor, "current_day_night_cycle")) { + is->current_day_night_cycle = *((int *)cursor)++; + is->day_night_cycle_unstarted = false; + + // The day/night cycle sprite proxies will have been cleared in patch_load_scenario. They will not necessarily be set + // up again in the usual way because Map_Renderer::load_images is not necessarily called when loading a save. The game + // skips reloading all graphics when loading a save while in-game with another that uses the same graphics (possibly + // only the standard graphics; I didn't test). If day/night cycle mode is active, restore the proxies now if they + // haven't already been. + if ((is->day_night_cycle_img_state == IS_OK) && ! is->day_night_cycle_img_proxies_indexed) + build_sprite_proxies_24 (&p_bic_data->Map.Renderer); + + // Because we've restored current_day_night_cycle from the save, set that is is not the first turn so the cycle + // doesn't get restarted. + is->day_night_cycle_unstarted = false; + + } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_state")) { + int state = *((int *)cursor)++; + if ((state >= GWABS_NOT_STARTED) && (state <= GWABS_DONE)) + is->great_wall_auto_build = (enum great_wall_auto_build_state)state; + else + is->great_wall_auto_build = GWABS_NOT_STARTED; + + } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_is_done")) { + bool was_done = (*((int *)cursor)++ != 0); + is->great_wall_auto_build = was_done ? GWABS_DONE : GWABS_NOT_STARTED; + + } else if (match_save_chunk_name (&cursor, "district_pending_requests")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && + (remaining_bytes >= entry_count * 5 * (int)sizeof(int))) { + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req != NULL) + free (req); + } + table_deinit (&is->city_pending_district_requests[civ_id]); + } + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 5 * (int)sizeof(int)) { + success = false; + break; + } + int city_id = *ints++; + int district_id = *ints++; + int assigned_worker_id = *ints++; + int target_x = *ints++; + int target_y = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 5 * (int)sizeof(int); + City * city = get_city_ptr (city_id); + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + continue; + struct pending_district_request * req = create_pending_district_request (city, district_id); + if (req == NULL) + continue; + if ((assigned_worker_id >= 0) && (get_unit_ptr (assigned_worker_id) == NULL)) + assigned_worker_id = -1; + req->assigned_worker_id = assigned_worker_id; + req->target_x = target_x; + req->target_y = target_y; + } + if (! success) { + for (int civ_id = 0; civ_id < 32; civ_id++) + table_deinit (&is->city_pending_district_requests[civ_id]); + } + } + } + if (! success) { + error_chunk_name = "district_pending_requests"; + break; + } + } else if (match_save_chunk_name (&cursor, "building_pending_orders")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && + (remaining_bytes >= entry_count * 2 * (int)sizeof(int))) { + table_deinit (&is->city_pending_building_orders); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 2 * (int)sizeof(int)) { + success = false; + break; + } + int city_id = *ints++; + int improv_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 2 * (int)sizeof(int); + if (improv_id < 0) + continue; + City * city = get_city_ptr (city_id); + if (city == NULL) + continue; + itable_insert (&is->city_pending_building_orders, (int)city, improv_id); + } + if (! success) + table_deinit (&is->city_pending_building_orders); + } + } + if (! success) { + error_chunk_name = "building_pending_orders"; + break; + } + } else if (match_save_chunk_name (&cursor, "district_tile_map")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if (entry_count >= 0) { + int ints_per_entry = 9; + success = true; + int required_bytes = entry_count * ints_per_entry * (int)sizeof(int); + if (success && remaining_bytes >= required_bytes) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst != NULL) + free (inst); + } + table_deinit (&is->district_tile_map); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < ints_per_entry * (int)sizeof(int)) { + success = false; + break; + } + int x = *ints++; + int y = *ints++; + int district_id = *ints++; + int state_val = *ints++; + int built_by_civ_id = *ints++; + int completed_turn = *ints++; + int wonder_state = *ints++; + int wonder_city_id = *ints++; + int wonder_index = *ints++; + cursor = (byte *)ints; + remaining_bytes -= ints_per_entry * (int)sizeof(int); + if ((district_id < 0) || (district_id >= is->district_count)) + continue; + Tile * tile = tile_at (x, y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = ensure_district_instance (tile, district_id, x, y); + if (inst != NULL) { + enum district_state new_state; + switch (state_val) { + case DS_COMPLETED: + new_state = DS_COMPLETED; + break; + case DS_UNDER_CONSTRUCTION: + new_state = DS_UNDER_CONSTRUCTION; + break; + default: + new_state = DS_UNDER_CONSTRUCTION; + break; + } + inst->state = new_state; + inst->built_by_civ_id = built_by_civ_id; + inst->completed_turn = completed_turn; + + inst->wonder_info.state = (enum wonder_district_state)wonder_state; + inst->wonder_info.city_id = (wonder_city_id >= 0) ? wonder_city_id : -1; + City * info_city = (wonder_city_id >= 0) ? get_city_ptr (wonder_city_id) : NULL; + inst->wonder_info.city = info_city; + if (info_city == NULL) + inst->wonder_info.city_id = -1; + inst->wonder_info.wonder_index = wonder_index; + set_tile_unworkable_for_all_cities (tile, x, y); + } + } + } + } + else + success = false; + } + } + if (! success) { + error_chunk_name = "district_tile_map"; + break; + } + } else if (match_save_chunk_name (&cursor, "natural_wonder_districts")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 3 * (int)sizeof(int)) { + success = false; + break; + } + int x = *ints++; + int y = *ints++; + int natural_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 3 * (int)sizeof(int); + if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) + continue; + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, x, y); + if (inst == NULL) + continue; + inst->district_id = NATURAL_WONDER_DISTRICT_ID; + inst->state = DS_COMPLETED; + inst->natural_wonder_info.natural_wonder_id = natural_id; + set_tile_unworkable_for_all_cities (tile, x, y); + } + } + } + if (! success) { + error_chunk_name = "natural_wonder_districts"; + break; + } + } else if (match_save_chunk_name (&cursor, "distribution_hub_records")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { + clear_distribution_hub_tables (); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 3 * (int)sizeof(int)) { + success = false; + break; + } + int x = *ints++; + int y = *ints++; + int civ_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 3 * (int)sizeof(int); + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + on_distribution_hub_completed (tile, x, y); + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec != NULL) + rec->civ_id = civ_id; + } + } + } + if (! success) { + error_chunk_name = "distribution_hub_records"; + break; + } + } else if (match_save_chunk_name (&cursor, "aerodrome_airlift_usage")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && + (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { + table_deinit (&is->aerodrome_airlift_usage); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 3 * (int)sizeof(int)) { + success = false; + break; + } + int tile_x = *ints++; + int tile_y = *ints++; + int mask = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 3 * (int)sizeof(int); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + itable_insert (&is->aerodrome_airlift_usage, (int)tile, mask); + } + if (! success) + table_deinit (&is->aerodrome_airlift_usage); + } + } + if (! success) { + error_chunk_name = "aerodrome_airlift_usage"; + break; + } + + } else if (match_save_chunk_name (&cursor, "named_tiles")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); + if ((entry_count >= 0) && (remaining_bytes >= entry_count * bytes_per_entry)) { + table_deinit (&is->named_tile_map); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < bytes_per_entry) { + success = false; + break; + } + int tile_x = *ints++; + int tile_y = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int) * 2; + + char name_buf[101]; + memcpy (name_buf, cursor, sizeof name_buf); + name_buf[(sizeof name_buf) - 1] = '\0'; + cursor += sizeof name_buf; + remaining_bytes -= sizeof name_buf; + ints = (int *)cursor; + + if (name_buf[0] == '\0') + continue; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + struct named_tile_entry * entry = calloc (1, sizeof *entry); + if (entry == NULL) { + success = false; + break; + } + entry->tile_x = tile_x; + entry->tile_y = tile_y; + strncpy (entry->name, name_buf, sizeof entry->name); + entry->name[(sizeof entry->name) - 1] = '\0'; + itable_insert (&is->named_tile_map, (int)tile, (int)entry); + } + if (! success) { + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if (entry != NULL) + free (entry); + } + table_deinit (&is->named_tile_map); + } + } + } + if (! success) { + error_chunk_name = "named_tiles"; + break; + } + + } else if (match_save_chunk_name (&cursor, "ai_candidate_bridge_or_canals")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int) * 3) { + int * ints = (int *)cursor; + int saved_initialized = *ints++; + int saved_count = *ints++; + int saved_capacity = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int) * 3; + + if ((saved_count >= 0) && (saved_capacity >= 0)) { + reset_ai_candidate_bridge_or_canals (); + success = true; + + int alloc_capacity = saved_capacity; + if (alloc_capacity < saved_count) + alloc_capacity = saved_count; + if (alloc_capacity > 0) { + is->ai_candidate_bridge_or_canals = (struct ai_candidate_bridge_or_canal_entry *)calloc (alloc_capacity, sizeof *is->ai_candidate_bridge_or_canals); + if (is->ai_candidate_bridge_or_canals == NULL) { + success = false; + alloc_capacity = 0; + } else + is->ai_candidate_bridge_or_canals_capacity = alloc_capacity; + } + + is->ai_candidate_bridge_or_canals_initialized = (saved_initialized != 0); + int loaded_count = 0; + for (int ei = 0; ei < saved_count; ei++) { + if (remaining_bytes < (int)sizeof(int) * 14) { + success = false; + break; + } + int district_id = *ints++; + int owner_civ_id = *ints++; + int tile_count = *ints++; + int tile_capacity = *ints++; + int assigned_tile_index = *ints++; + int assigned_worker_id = *ints++; + int completed = *ints++; + int pending_city_id = *ints++; + int pending_civ_id = *ints++; + int pending_district_id = *ints++; + int pending_assigned_worker_id = *ints++; + int pending_target_x = *ints++; + int pending_target_y = *ints++; + int pending_worker_assigned_turn = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int) * 14; + + if (tile_count < 0) { + success = false; + break; + } + if (remaining_bytes < tile_count * 2 * (int)sizeof(int)) { + success = false; + break; + } + + int stored_tile_count = tile_count; + if (tile_count > AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES) + tile_count = AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES; + if (tile_capacity < tile_count) + tile_capacity = tile_count; + + struct ai_candidate_bridge_or_canal_entry * entry = NULL; + if ((alloc_capacity > 0) && (loaded_count < alloc_capacity)) + entry = &is->ai_candidate_bridge_or_canals[loaded_count]; + + if (entry != NULL) { + entry->district_id = district_id; + entry->owner_civ_id = (short)owner_civ_id; + entry->tile_count = (short)tile_count; + entry->tile_capacity = tile_capacity; + entry->assigned_tile_index = assigned_tile_index; + entry->assigned_worker_id = assigned_worker_id; + entry->completed = (completed != 0); + + entry->tile_x = (short *)calloc (sizeof *entry->tile_x, tile_count); + entry->tile_y = (short *)calloc (sizeof *entry->tile_y, tile_count); + if ((tile_count > 0) && ((entry->tile_x == NULL) || (entry->tile_y == NULL))) { + if (entry->tile_x != NULL) + free (entry->tile_x); + if (entry->tile_y != NULL) + free (entry->tile_y); + entry->tile_x = NULL; + entry->tile_y = NULL; + entry->tile_count = 0; + entry->tile_capacity = 0; + } + + for (int ti = 0; ti < stored_tile_count; ti++) { + int tx = *ints++; + int ty = *ints++; + if ((entry->tile_x != NULL) && (ti < tile_count)) { + entry->tile_x[ti] = (short)tx; + entry->tile_y[ti] = (short)ty; + } + } + + entry->pending_req.city = (pending_city_id >= 0) ? get_city_ptr (pending_city_id) : NULL; + entry->pending_req.city_id = (entry->pending_req.city != NULL) ? pending_city_id : -1; + entry->pending_req.civ_id = pending_civ_id; + entry->pending_req.district_id = pending_district_id; + entry->pending_req.assigned_worker_id = pending_assigned_worker_id; + entry->pending_req.target_x = pending_target_x; + entry->pending_req.target_y = pending_target_y; + entry->pending_req.worker_assigned_turn = pending_worker_assigned_turn; + + if ((entry->assigned_worker_id >= 0) && (get_unit_ptr (entry->assigned_worker_id) == NULL)) + entry->assigned_worker_id = -1; + if ((entry->pending_req.assigned_worker_id >= 0) && (get_unit_ptr (entry->pending_req.assigned_worker_id) == NULL)) + entry->pending_req.assigned_worker_id = -1; + if ((entry->assigned_tile_index < 0) || (entry->assigned_tile_index >= entry->tile_count)) + entry->assigned_tile_index = -1; + + loaded_count++; + } else { + for (int ti = 0; ti < stored_tile_count; ti++) { + ints += 2; + } + } + + cursor = (byte *)ints; + remaining_bytes -= stored_tile_count * 2 * (int)sizeof(int); + } + if (success) + is->ai_candidate_bridge_or_canals_count = loaded_count; + } + } + if (! success) { + error_chunk_name = "ai_candidate_bridge_or_canals"; + break; + } + + } else if (match_save_chunk_name (&cursor, "district_config_names")) { + bool success = false; + bool mismatch_found = false; + bool count_mismatch = false; + char first_mismatch[200]; + first_mismatch[0] = '\0'; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int saved_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if (saved_count >= 0) { + success = true; + count_mismatch = (saved_count != is->district_count); + char * saved_names[saved_count]; + for (int n = 0; n < saved_count; n++) { + if (remaining_bytes < (int)sizeof(int)) { + success = false; + break; + } + ints = (int *)cursor; + int saved_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + + int name_len = -1; + for (int k = 0; k < remaining_bytes; k++) { + if (cursor[k] == '\0') { + name_len = k; + break; + } + } + if (name_len < 0) { + success = false; + break; + } + int padded_len = (name_len + 4) & ~3; + if (padded_len > remaining_bytes) { + success = false; + break; + } + + char * saved_name = (char *)cursor; + saved_names[n] = saved_name; + if (! mismatch_found) { + if ((saved_id < 0) || (saved_id >= is->district_count)) { + snprintf (first_mismatch, sizeof first_mismatch, "%s %d (\"%s\") %s", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW]); + first_mismatch[(sizeof first_mismatch) - 1] = '\0'; + mismatch_found = true; + } else { + char const * current_name = is->district_configs[saved_id].name; + if (current_name == NULL) + current_name = ""; + if (strcmp (current_name, saved_name) != 0) { + snprintf (first_mismatch, sizeof first_mismatch, "%s %d \"%s\" %s \"%s\"", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_NAME_MISMATCH], current_name); + first_mismatch[(sizeof first_mismatch) - 1] = '\0'; + mismatch_found = true; + } + } + } + + cursor += padded_len; + remaining_bytes -= padded_len; + } + if (success && count_mismatch && (first_mismatch[0] == '\0')) { + snprintf (first_mismatch, sizeof first_mismatch, "%s %d %s %d", is->c3x_labels[CL_SAVE_FILE_HAD], saved_count, is->c3x_labels[CL_CURRENT_CONFIG_HAS_ONLY], is->district_count); + first_mismatch[(sizeof first_mismatch) - 1] = '\0'; + mismatch_found = true; + } + if (success && mismatch_found) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); + + char s[1000]; + snprintf (s, sizeof s, "%s %s", is->c3x_labels[CL_WARNING_DISTRICTS_CONFIG_MISMATCH], first_mismatch); + snprintf (s, sizeof s, "%s. %s", s, is->c3x_labels[CL_MAY_BE_OTHER_ERRORS_AS_WELL]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^"); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_DISTRICTS_IN_SAVE_FILE]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + for (int n = 0; n < saved_count; n++) { + snprintf (s, sizeof s, "^ (%d) %s", n, saved_names[n]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + + snprintf (s, sizeof s, "^"); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^%s \"%s\":", is->c3x_labels[CL_CURRENTLY_CONFIGURED_DISTRICTS], is->current_districts_config_path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + for (int n = 0; n < is->district_count; n++) { + snprintf (s, sizeof s, "^ (%d) %s", n, is->district_configs[n].name); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + + patch_show_popup (popup, __, 0, 0); + } + } + } + if (! success) { + error_chunk_name = "district_config_names"; + break; + } + + } else { + error_chunk_name = "N/A"; + break; + } + } + + if (error_chunk_name != NULL) { + char s[200]; + snprintf (s, sizeof s, "Failed to read mod save data. Error occured in chunk: %s", error_chunk_name); + s[(sizeof s) - 1] = '\0'; + pop_up_in_game_error (s); + } + + free (seg); + } + + return tr; +} + +void __fastcall +patch_MappedFile_deinit_after_saving_or_loading (MappedFile * this) +{ + is->accessing_save_file = NULL; + MappedFile_deinit (this); +} + +bool __fastcall +patch_Tile_m7_Check_Barbarian_Camp (Tile * this, int edx, int visible_to_civ) +{ + int * p_stack = (int *)&visible_to_civ; + int ret_addr = p_stack[-1]; + + // If the barb unit AI is calling this method to check if there's a camp to defend, return true if we're allowing barb city capture and the + // tile has a city. This causes barb units to defend cities they've captured, otherwise they'll ignore them. + if ((ret_addr == ADDR_CHECK_BARB_CAMP_TO_DEFEND_RETURN) && + is->current_config.enable_city_capture_by_barbarians && + Tile_has_city (this)) + return true; + else + return Tile_m7_Check_Barbarian_Camp (this, __, visible_to_civ); +} + +bool __fastcall +patch_Unit_can_heal_at (Unit * this, int edx, int tile_x, int tile_y) +{ + if (is->current_config.enable_districts && + is->current_config.enable_port_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile_has_friendly_port_district (tile, this->Body.CivID)) { + int occupier_id = get_tile_occupier_id (tile_x, tile_y, -1, true); + return (occupier_id == -1) || (occupier_id == this->Body.CivID); + } + } + + return Unit_can_heal_at (this, __, tile_x, tile_y); +} + +bool __fastcall +patch_Unit_can_airdrop (Unit * this) +{ + UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + + bool allowed = Unit_can_airdrop (this); + + bool require_aerodrome = (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities); + + if (require_aerodrome) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + bool has_aerodrome = false; + + if ((tile != NULL) && (tile != p_null_tile)) + has_aerodrome = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); + + if (! has_aerodrome) + allowed = false; + else if (! allowed) { + if ((this_type->Unit_Class != UTC_Air) && + (this_type->Air_Missions & UCV_Airdrop) && + (this->Body.Moves == 0)) + allowed = true; + } + } + + // Possibly rule in this airdrop as allowed if it's by a paratrooper in a helicopter on a carrier and we're configured to allow airdrops under + // those circumstances. + if ((! allowed) && (is->current_config.special_helicopter_rules & SHR_PASSENGER_AIRDROP)) { + Unit * container = get_unit_ptr (this->Body.Container_Unit); + if (container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) { // if in helicopter + Unit * metacontainer = get_unit_ptr (container->Body.Container_Unit); + if (metacontainer != NULL && p_bic_data->UnitTypes[metacontainer->Body.UnitTypeID].Unit_Class == UTC_Sea && + Unit_has_ability (metacontainer, __, UTA_Transports_Only_Aircraft)) { // if that helicopter is on a carrier + // Allow the airdrop under the same restrictions as from an airfield + allowed = this_type->Unit_Class != UTC_Air && this->Body.Moves == 0; + } + } + } + + if (! allowed) + return false; + + return itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0) == 0; +} + +bool __fastcall +patch_City_Improvements_contains (City_Improvements * this, int edx, int id) +{ + byte * extra_bits; + if ((id < 256) || ! is->current_config.remove_city_improvement_limit) + return City_Improvements_contains (this, __, id); + else if (itable_look_up (&is->extra_city_improvs, (int)this, (int *)&extra_bits)) { + int extra_id = id - 256; + return (extra_bits[extra_id>>3] >> (extra_id & 7)) & 1; + } else + return false; +} + +void __fastcall +patch_City_Improvements_set (City_Improvements * this, int edx, int id, bool add_else_remove) +{ + if ((id < 256) || ! is->current_config.remove_city_improvement_limit) + return City_Improvements_set (this, __, id, add_else_remove); + else { + byte * extra_bits = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)this, 0); + int extra_id = id - 256; + byte mask = 1 << (extra_id & 7); + if (add_else_remove) { + if (! extra_bits) { + int extra_bits_size = (not_below (0, p_bic_data->ImprovementsCount - 256) >> 3) + 1; + extra_bits = calloc (1, extra_bits_size); + itable_insert (&is->extra_city_improvs, (int)this, (int)extra_bits); + } + extra_bits[extra_id>>3] |= mask; + } else if ((! add_else_remove) && (extra_bits != NULL)) + extra_bits[extra_id>>3] &= ~mask; + } +} + +bool __fastcall +patch_Leader_has_tech_to_stop_disease (Leader * this, int edx, int id) +{ + if (! is->current_config.patch_disease_stopping_tech_flag_bug) + return Leader_has_tech (this, __, id); + else + return Leader_has_tech_with_flag (this, __, ATF_Disabled_Deseases_From_Flood_Plains); +} + +void __fastcall +patch_set_worker_animation (void * this, int edx, Unit * unit, int job_id) +{ + AnimationType anim_type; + + // If districts disabled or unit is null or job is not building mines, use base logic + if ((! is->current_config.enable_districts) || + (unit == NULL) || + (job_id != WJ_Build_Mines)) { + set_worker_animation(this, __, unit, job_id); + return; + } + + // If tile has a district under construction + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && + ! district_is_complete (tile, inst->district_id) && job_id == WJ_Build_Mines) { + + // Override and ensure build animation is used + job_id = AT_BUILD; + } + + set_worker_animation(this, __, unit, job_id); +} + +void __fastcall +patch_Unit_work_simple_job (Unit * this, int edx, int job_id) +{ + is->lmify_tile_after_working_simple_job = NULL; + + // Check if districts are enabled + if (is->current_config.enable_districts) { + int tile_x = this->Body.X; + int tile_y = this->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + + if (tile != NULL && tile != p_null_tile) { + // Check if there's a completed district on this tile + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete(tile, inst->district_id)) { + int district_id = inst->district_id; + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + + // AI players only (human removal is handled via issue_district_worker_command) + if (!is_human) { + bool allow_removal = false; + if (district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = &inst->wonder_info; + allow_removal = (info->state == WDS_UNUSED); + } + + if (allow_removal) { + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + handle_district_removed (tile, district_id, tile_x, tile_y, false); + } + } + } + } + } + + Unit_work_simple_job (this, __, job_id); + + if (is->lmify_tile_after_working_simple_job != NULL) + is->lmify_tile_after_working_simple_job->vtable->m31_set_landmark (is->lmify_tile_after_working_simple_job, __, true); +} + +void __fastcall +patch_Map_change_tile_terrain_by_worker (Map * this, int edx, enum SquareTypes new_terrain_type, int x, int y) +{ + Map_change_tile_terrain (this, __, new_terrain_type, x, y); + + if (is->current_config.convert_to_landmark_after_planting_forest && (new_terrain_type == SQ_Forest)) + is->lmify_tile_after_working_simple_job = tile_at (x, y); +} + +int __fastcall +patch_Leader_ai_eval_technology (Leader * this, int edx, int id, bool param_2, bool param_3) +{ + int base = Leader_ai_eval_technology (this, __, id, param_2, param_3); + return apply_perfume (PK_TECHNOLOGY, p_bic_data->Advances[id].Name, base); +} + +int __fastcall +patch_Leader_ai_eval_government (Leader * this, int edx, int id) +{ + int base = Leader_ai_eval_government (this, __, id); + return apply_perfume (PK_GOVERNMENT, p_bic_data->Governments[id].Name.S, base); +} + +bool +roll_to_spare_unit_from_nuke (Unit * unit) +{ + int one_hp_destroy_chance = is->current_config.chance_for_nukes_to_destroy_max_one_hp_units; + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + if ((one_hp_destroy_chance < 100) && + (Unit_get_max_hp (unit) <= 1) && + (type->Defence > 0) && + ((type->Unit_Class == UTC_Land) || (type->Unit_Class == UTC_Sea))) + return ! (rand_int (p_rand_object, __, 100) < one_hp_destroy_chance); + else + return false; +} + +void __fastcall +patch_Unit_despawn_after_killed_by_nuke (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) +{ + if (roll_to_spare_unit_from_nuke (this)) + this->Body.Damage = Unit_get_max_hp (this) - 1; + else { + bool prev_always_despawn_passengers = is->always_despawn_passengers; + if ((is->current_config.land_transport_rules & LTR_NO_ESCAPE) && is_land_transport (this)) + is->always_despawn_passengers = true; + else if ((is->current_config.special_helicopter_rules & SHR_NO_ESCAPE) && p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air && + p_bic_data->UnitTypes[this->Body.UnitTypeID].Transport_Capacity > 0) + is->always_despawn_passengers = true; + patch_Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); + is->always_despawn_passengers = prev_always_despawn_passengers; + } +} + +void __fastcall +patch_mp_despawn_after_killed_by_nuke (void * this, int edx, int unit_id, int civ_id_responsible, byte param_3, byte param_4, byte param_5, byte param_6) +{ + Unit * unit = get_unit_ptr (unit_id); + if ((unit != NULL) && roll_to_spare_unit_from_nuke (unit)) + unit->Body.Damage = Unit_get_max_hp (unit) - 1; + else + mp_despawn (this, __, unit_id, civ_id_responsible, param_3, param_4, param_5, param_6); +} + +bool __fastcall +patch_City_has_unprotected_improv_to_sell (City * this, int edx, int id) +{ + // Fall back to original logic only if the config doesn't alter the behavior. + if (! is->current_config.allow_sale_of_aqueducts_and_hospitals && !is->current_config.allow_sale_of_small_wonders) + return City_has_unprotected_improv (this, __, id); + + else if (patch_City_has_improvement (this, __, id, false)) { + Improvement * improv = &p_bic_data->Improvements[id]; + int max_pop_to_sell = INT_MAX; // By default, population-based sell isn't restricted + if (improv->ImprovementFlags & (ITF_Allows_City_Level_2 | ITF_Allows_City_Level_3)) { // Aqueduct/Hospital? + if (is->current_config.allow_sale_of_aqueducts_and_hospitals) { + if (improv->ImprovementFlags & ITF_Allows_City_Level_2) + max_pop_to_sell = p_bic_data->General.MaximumSize_Town; + else if (improv->ImprovementFlags & ITF_Allows_City_Level_3) + max_pop_to_sell = p_bic_data->General.MaximumSize_City; + } else { + // Do not allow selling these. + max_pop_to_sell = 0; + } + } + + // Can't sell: + // - Great Wonders + // - Small Wonders, unless the config allows it + // - Capital + // - Aqueduct/Hospital if the city is too big for that population + return ((improv->Characteristics & ITC_Wonder) == 0) && + (is->current_config.allow_sale_of_small_wonders || ((improv->Characteristics & ITC_Small_Wonder) == 0)) && + ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && + (this->Body.Population.Size <= max_pop_to_sell); + + } else + return false; +} + +bool __fastcall +patch_UnitType_has_detector_ability_for_vis_check (UnitType * this, int edx, enum UnitTypeAbilities a) +{ + bool tr = UnitType_has_ability (this, __, a); + + // Restrict detection by sea units to other sea units and non-sea units to other non-sea units + if (tr && + is->current_config.no_cross_shore_detection && + (is->checking_visibility_for_unit != NULL) && + ((this->Unit_Class == UTC_Sea) ^ (p_bic_data->UnitTypes[is->checking_visibility_for_unit->Body.UnitTypeID].Unit_Class == UTC_Sea))) + tr = false; + + return tr; +} + +bool +is_airdrop_trespassing (Unit * unit, int target_x, int target_y) +{ + if (is->current_config.disallow_trespassing && + check_trespassing (unit->Body.CivID, tile_at (unit->Body.X, unit->Body.Y), tile_at (target_x, target_y))) { + bool allowed = is_allowed_to_trespass (unit); + + // If "unit" is an air unit that can carry others, like helicopters, then this airdrop is only allowed if all of its passengers are + // allowed to trespass. + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + if (allowed && (type->Unit_Class == UTC_Air) && (type->Transport_Capacity > 0)) + FOR_UNITS_ON (uti, tile_at (unit->Body.X, unit->Body.Y)) + if ((uti.unit->Body.Container_Unit == unit->Body.ID) && + (! is_allowed_to_trespass (uti.unit))) { + allowed = false; + break; + } + + return ! allowed; + } else + return false; +} + +bool __fastcall +patch_Unit_check_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) +{ + return Unit_check_airdrop_target (this, __, tile_x, tile_y) && + is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID) && + ! is_airdrop_trespassing (this, tile_x, tile_y); +} + +bool __fastcall +patch_Unit_can_airlift (Unit * this) +{ + bool base = Unit_can_airlift (this); + + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) + return base; + + Tile * tile = tile_at (this->Body.X, this->Body.Y); + if ((tile == NULL) || (tile == p_null_tile)) + return base; + + bool allow_from_non_city = false; + if (base) { + City * city = city_at (this->Body.X, this->Body.Y); + if ((city == NULL) || (city->Body.CivID != this->Body.CivID)) + allow_from_non_city = true; + } + + if (allow_from_non_city) + return true; + + return tile_has_friendly_aerodrome_district (tile, this->Body.CivID, true); +} + +bool __fastcall +patch_Unit_check_airlift_target (Unit * this, int edx, int tile_x, int tile_y) +{ + bool base = Unit_check_airlift_target (this, __, tile_x, tile_y); + bool allowed = base; + + Tile * tile = tile_at (tile_x, tile_y); + + if (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities) { + if ((tile == NULL) || (tile == p_null_tile)) { + allowed = false; + } else { + City * target_city = city_at (tile_x, tile_y); + if (allowed && + (target_city != NULL) && + (target_city->Body.CivID == this->Body.CivID)) + allowed = false; + + if (! allowed) + allowed = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); + } + } + + if (! allowed) + return false; + + return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); +} + +void __fastcall +patch_Unit_airlift (Unit * this, int edx, int tile_x, int tile_y) +{ + Tile * source_tile = NULL; + bool mark_usage = false; + + if (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities) { + source_tile = tile_at (this->Body.X, this->Body.Y); + if (tile_has_friendly_aerodrome_district (source_tile, this->Body.CivID, true)) + mark_usage = true; + } + + Unit_airlift (this, __, tile_x, tile_y); + + if (mark_usage && (source_tile != NULL) && (source_tile != p_null_tile)) { + int mask = itable_look_up_or (&is->aerodrome_airlift_usage, (int)source_tile, 0); + mask |= (1 << this->Body.CivID); + itable_insert (&is->aerodrome_airlift_usage, (int)source_tile, mask); + } +} + +int __fastcall +patch_City_count_airports_for_ai_airlift_target (City * this, int edx, enum ImprovementTypeFlags airport_flag) +{ + // When this function is called, the AI unit being moved is stored in register ESI. + Unit * unit; + __asm__ __volatile__("mov %%esi, %0" : "=r" (unit)); + + int tr = City_count_improvements_with_flag (this, __, airport_flag); + + // Check the stack limit here. If the city's tile is at the limit, return that it has no airport so the AI can't airlift there. + if ((tr > 0) && ! is_below_stack_limit (tile_at (this->Body.X, this->Body.Y), this->Body.CivID, unit->Body.UnitTypeID)) + return 0; + + else + return tr; +} + +int __fastcall +patch_Unit_ai_eval_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) +{ + int tr = Unit_ai_eval_airdrop_target (this, __, tile_x, tile_y); + + // Prevent the AI from airdropping onto tiles in violation of the stack limit or trespassing restriction + if ((tr > 0) && + ((! is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID)) || + is_airdrop_trespassing (this, tile_x, tile_y))) + tr = 0; + + return tr; +} + +bool __fastcall +patch_Unit_find_telepad_on_tile (Unit * this, int edx, int x, int y, bool show_selection_popup, Unit ** out_unit_telepad) +{ + if (! is_below_stack_limit (tile_at (x, y), this->Body.CivID, this->Body.UnitTypeID)) { + *out_unit_telepad = NULL; + return false; + } else + return Unit_find_telepad_on_tile (this, __, x, y, show_selection_popup, out_unit_telepad); +} + +bool __fastcall +patch_Unit_ai_go_to_capital (Unit * this) +{ + City * capital = get_city_ptr (leaders[this->Body.CivID].CapitalID); + + // Block going to capital if the capital's tile is at the stack limit. This stops the AI from airlifting there (would violate the limit) and + // saves it from trying to pathfind there. + if ((capital != NULL) && + ! is_below_stack_limit (tile_at (capital->Body.X, capital->Body.Y), this->Body.CivID, this->Body.UnitTypeID)) + return false; + + return Unit_ai_go_to_capital (this); +} + +bool __fastcall +patch_Unit_is_in_rebase_range (Unit * this, int edx, int tile_x, int tile_y) +{ + bool in_range; + + // 6 is the game's standard value, so fall back on the base game logic in that case + if (is->current_config.rebase_range_multiplier == 6) + in_range = Unit_is_in_rebase_range (this, __, tile_x, tile_y); + + else { + int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + if (op_range < 1) + op_range = 500; + + int x_dist = Map_get_x_dist (&p_bic_data->Map, __, tile_x, this->Body.X), + y_dist = Map_get_y_dist (&p_bic_data->Map, __, tile_y, this->Body.Y); + + in_range = ((x_dist + y_dist) >> 1) <= (op_range * is->current_config.rebase_range_multiplier); + } + + return in_range && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); +} + +bool __fastcall +patch_Unit_check_rebase_target (Unit * this, int edx, int tile_x, int tile_y) +{ + // Check if this is an air unit + bool is_air_unit = (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air); + + // If districts are enabled and this is an air unit, check for aerodrome districts + if (is_air_unit && is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts) { + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + // Check if tile has a district + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + int district_id = inst->district_id; + // Check if this is an aerodrome district owned by this unit's civ + if ((district_id == AERODROME_DISTRICT_ID) && (tile->Territory_OwnerID == this->Body.CivID)) { + // Check if aerodrome is complete + if (district_is_complete (tile, district_id)) { + // Perform range check + bool in_range = patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y); + if (in_range) { + return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); + } + } + } + } + + // If air_units_use_aerodrome_districts_not_cities is enabled, check if there's a city and disallow it + if (is->current_config.air_units_use_aerodrome_districts_not_cities) { + City * target_city = city_at (tile_x, tile_y); + if (target_city != NULL && target_city->Body.CivID == this->Body.CivID) { + // There's a friendly city here - disallow landing since configured to use aerodromes/airfields/carriers only + return false; + } + } + } + } + + // 6 is the game's standard value, so fall back on the base game logic in that case + if (is->current_config.rebase_range_multiplier == 6) { + return Unit_check_rebase_target (this, __, tile_x, tile_y) && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); + + // Otherwise, we have to redo the range check. Unlike Unit::is_in_rebase_range, the base method here does more than just check the range so we + // want to make sure to call it even if we determine that the target is in range. In that case, set the range to unlimited temporarily so the + // base game's range check passes. + } else { + if (patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y)) { + int * p_op_range = &p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + int original_op_range = *p_op_range; + *p_op_range = 0; + bool tr = Unit_check_rebase_target (this, __, tile_x, tile_y); + *p_op_range = original_op_range; + return tr; + } else + return false; + } +} + +int __fastcall +patch_Sprite_draw_already_worked_tile_img (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + Sprite * to_draw = this; + + if (is->do_not_draw_already_worked_tile_img) + return 0; + + if (is->current_config.toggle_zoom_with_z_on_city_screen && p_bic_data->is_zoomed_out) { + + // Load sprite if necessary + if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_UNINITED) { + is->tile_already_worked_zoomed_out_sprite_init_state = IS_INIT_FAILED; + PCX_Image * pcx = malloc (sizeof *pcx); + if (pcx != NULL) { + memset (pcx, 0, sizeof *pcx); + PCX_Image_construct (pcx); + char path[2*MAX_PATH]; + get_mod_art_path ("TileAlreadyWorkedZoomedOut.pcx", path, sizeof path); + PCX_Image_read_file (pcx, __, path, NULL, 0, 0x100, 2); + if (pcx->JGL.Image != NULL) { + Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; + memset (sprite, 0, sizeof *sprite); + Sprite_construct (sprite); + Sprite_slice_pcx (sprite, __, pcx, 0, 0, 64, 32, 1, 1); + is->tile_already_worked_zoomed_out_sprite_init_state = IS_OK; + } + pcx->vtable->destruct (pcx, __, 0); + free (pcx); + } + } + + if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_OK) + to_draw = &is->tile_already_worked_zoomed_out_sprite; + } + + return Sprite_draw (to_draw, __, canvas, pixel_x, pixel_y, color_table); +} + +int __fastcall +patch_Tile_m43_Get_field_30_for_city_loc_eval (Tile * this) +{ + int tr = this->vtable->m43_Get_field_30 (this); + + // This patch function replaces two places where ai_eval_city_location calls Tile::m43_Get_field_30 to check the 18th bit, which indicates + // whether the tile is in the workable area of any city. If it is but the work area has been expanded, check that it's actually within the + // normal 20-tile area. This prevents work area expansion from causing AIs to space their cities further apart. + // The field_30_get_counter is a crazy workaround for the fact that the game doesn't have any way to determine a tile's coordinates given a + // pointer to its object. So we track the initial (x, y) for the tile we're evaluating and then count calls to this func to know what + // neighboring coords "this" corresponds to. + int get_counter = is->ai_evaling_city_field_30_get_counter; + if (((tr >> 17) & 1) && (is->current_config.city_work_radius >= 3)) { + bool found_city = false; + int this_x, this_y; { + int dx, dy; + patch_ni_to_diff_for_work_area (get_counter, &dx, &dy); + this_x = is->ai_evaling_city_loc_x + dx; + this_y = is->ai_evaling_city_loc_y + dy; + wrap_tile_coords (&p_bic_data->Map, &this_x, &this_y); + } + FOR_TILES_AROUND (tai, 21, this_x, this_y) + if (Tile_has_city (tai.tile)) { + found_city = true; + break; + } + if (! found_city) + tr &= ~(1 << 17); + } + get_counter++; + if (get_counter >= 21) + get_counter = 0; + is->ai_evaling_city_field_30_get_counter = get_counter; + + return tr; + +} + +// Intercept the call where the game gets a random index at which to start searching for a suitable tile to become polluted. Normally, it passes 20 as +// the limit here. We must replace that to cover a potentially modded work area. +int __fastcall +patch_rand_int_to_place_pollution (void * this, int edx, int lim) +{ + return rand_int (this, __, is->workable_tile_count - 1); +} + +void __fastcall +patch_Main_Screen_Form_t2s_coords_to_draw_yields (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int * out_x, int * out_y) +{ + Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, out_x, out_y); + + // If we've zoomed out the map on the city screen, we may end up drawing the tile yields off screen depending on the map size. If this is the + // case, detected by negative screen coords, then shift the coords over by one map-screen back onto the actual screen. The shift amounts are + // 64*map_width/2 and 32*map_height/2 for x and y because (64, 32) is the size of a zoomed out tile and /2 is for overlap (I think). + if (p_bic_data->is_zoomed_out && (*out_x < 0)) + *out_x += p_bic_data->Map.Width << 5; + if (p_bic_data->is_zoomed_out && (*out_y < 0)) + *out_y += p_bic_data->Map.Height << 4; +} + +void +set_clip_area_to_map_view (City_Form * city_form) +{ + int left_margin = (p_bic_data->ScreenWidth - city_form->Background_Image.Width) / 2, + top_margin = (p_bic_data->ScreenHeight - city_form->Background_Image.Height) / 2; + RECT map_view_on_screen = { .left = left_margin, .top = top_margin + 92, .right = left_margin + 1024, .bottom = top_margin + 508 }; + JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; + jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &map_view_on_screen); +} + +void +clear_clip_area (City_Form * city_form) +{ + JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; + jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &jgl_canvas->Image_Rect); +} + +void +init_distribution_hub_icons () +{ + if (is->distribution_hub_icons_img_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char ss[200]; + snprintf (ss, sizeof ss, "[C3X] init_distribution_hub_icons: state=%d\n", is->distribution_hub_icons_img_state); + (*p_OutputDebugStringA) (ss); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("Districts/DistributionHubIncomeIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image == NULL) || + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { + (*p_OutputDebugStringA) ("[C3X] PCX file for distribution hub icons failed to load or is too small.\n"); + is->distribution_hub_icons_img_state = IS_INIT_FAILED; + goto cleanup; + } + + // Extract shield icon (index 4: x = 1 + 4*31 = 125, width 30) + Sprite_construct (&is->distribution_hub_shield_icon); + Sprite_slice_pcx (&is->distribution_hub_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); + + // Extract shield corruption icon (index 5: x = 1 + 5*31 = 156, width 30) + Sprite_construct (&is->distribution_hub_corruption_icon); + Sprite_slice_pcx (&is->distribution_hub_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); + + // Extract small shield icon (index 13) + Sprite_construct (&is->distribution_hub_shield_icon_small); + Sprite_slice_pcx (&is->distribution_hub_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); + + // Extract surplus food icon (index 6: x = 1 + 6*31 = 187, width 30) + Sprite_construct (&is->distribution_hub_food_icon); + Sprite_slice_pcx (&is->distribution_hub_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); + + // Extract small surplus food icon (index 15) + Sprite_construct (&is->distribution_hub_food_icon_small); + Sprite_slice_pcx (&is->distribution_hub_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); + + // Extract eaten food icon (index 7: x = 1 + 7*31 = 218, width 30) + Sprite_construct (&is->distribution_hub_eaten_food_icon); + Sprite_slice_pcx (&is->distribution_hub_eaten_food_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); + + is->distribution_hub_icons_img_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +draw_district_yields (City_Form * city_form, Tile * tile, int district_id, int screen_x, int screen_y) +{ + // Lazy load district icons + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + if (is->dc_icons_img_state != IS_OK) + return; + + if (district_id < 0 || district_id >= is->district_count) + return; + + // Get district configuration + struct district_config * config = &is->district_configs[district_id]; + struct district_instance * inst = get_district_instance (tile); + + // Count total yields from bonuses + int food_bonus = 0, shield_bonus = 0, gold_bonus = 0, science_bonus = 0, culture_bonus = 0, happiness_bonus = 0; + get_effective_district_yields (inst, config, &food_bonus, &shield_bonus, &gold_bonus, &science_bonus, &culture_bonus, &happiness_bonus); + if ((config->generated_resource_id >= 0) && + (config->generated_resource_flags & MF_YIELDS) && + (city_form->CurrentCity != NULL) && + district_generates_resource_for_civ (tile, inst, config, city_form->CurrentCity->Body.CivID)) { + Resource_Type * res = &p_bic_data->ResourceTypes[config->generated_resource_id]; + food_bonus += res->Food; + shield_bonus += res->Shield; + gold_bonus += res->Commerce; + } + + int food_pos = food_bonus > 0 ? food_bonus : 0; + int food_neg = food_bonus < 0 ? -food_bonus : 0; + int shield_pos = shield_bonus > 0 ? shield_bonus : 0; + int shield_neg = shield_bonus < 0 ? -shield_bonus : 0; + int gold_pos = gold_bonus > 0 ? gold_bonus : 0; + int gold_neg = gold_bonus < 0 ? -gold_bonus : 0; + int science_pos = science_bonus > 0 ? science_bonus : 0; + int science_neg = science_bonus < 0 ? -science_bonus : 0; + int culture_pos = culture_bonus > 0 ? culture_bonus : 0; + int culture_neg = culture_bonus < 0 ? -culture_bonus : 0; + int happiness_pos = happiness_bonus > 0 ? happiness_bonus : 0; + int happiness_neg = happiness_bonus < 0 ? -happiness_bonus : 0; + + int total_yield = 0; + total_yield += food_pos + food_neg; + total_yield += shield_pos + shield_neg; + total_yield += gold_pos + gold_neg; + total_yield += science_pos + science_neg; + total_yield += culture_pos + culture_neg; + total_yield += happiness_pos + happiness_neg; + + if (total_yield <= 0) + return; + + // Get sprites + Sprite * food_sprite = &is->district_food_icon_small; + Sprite * shield_sprite = &is->district_shield_icon_small; + Sprite * commerce_sprite = &is->district_commerce_icon_small; + Sprite * science_sprite = &is->district_science_icon_small; + Sprite * culture_sprite = &is->district_culture_icon_small; + Sprite * happiness_sprite = &is->district_happiness_icon_small; + Sprite * food_negative_sprite = &is->district_negative_food_icon_small; + Sprite * shield_negative_sprite = &is->district_negative_shield_icon_small; + Sprite * commerce_negative_sprite = &is->district_negative_commerce_icon_small; + Sprite * science_negative_sprite = &is->district_negative_science_icon_small; + Sprite * culture_negative_sprite = &is->district_negative_culture_icon_small; + Sprite * happiness_negative_sprite = &is->district_unhappiness_icon_small; + + // Determine sprite dimensions + int sprite_width = food_sprite->Width3; + int sprite_height = food_sprite->Height; + + // Calculate total width of all icons + int total_width = total_yield * sprite_width; + + // Center the icons horizontally + int half_width = total_width >> 1; + int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; + int max_offset = (tile_width >> 1) - 5; + if (half_width > max_offset) + half_width = max_offset; + + int pixel_x = screen_x - half_width; + int pixel_y = screen_y - (sprite_height >> 1); + + // Adjust spacing if icons would exceed tile width + int spacing = sprite_width; + if (total_width > tile_width - 10) { + if (total_yield > 1) { + spacing = (tile_width - 10 - sprite_width) / (total_yield - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > sprite_width) + spacing = sprite_width; + } + } + + // Draw icons in order: shields, food, science, commerce, culture + for (int i = 0; i < shield_pos; i++) { + Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < shield_neg; i++) { + Sprite_draw (shield_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < food_pos; i++) { + Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < food_neg; i++) { + Sprite_draw (food_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < science_pos; i++) { + Sprite_draw (science_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < science_neg; i++) { + Sprite_draw (science_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < gold_pos; i++) { + Sprite_draw (commerce_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < gold_neg; i++) { + Sprite_draw (commerce_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < culture_pos; i++) { + Sprite_draw (culture_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < culture_neg; i++) { + Sprite_draw (culture_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < happiness_pos; i++) { + Sprite_draw (happiness_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < happiness_neg; i++) { + Sprite_draw (happiness_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } +} + +void +draw_distribution_hub_yields (City_Form * city_form, Tile * tile, int tile_x, int tile_y, int screen_x, int screen_y) +{ + // Get the distribution hub record for this tile + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec == NULL) + return; + + City * anchor_city = get_connected_city_for_distribution_hub (rec); + if (! distribution_hub_accessible_to_city (rec, city_form->CurrentCity)) + return; + + int food_yield = rec->food_yield; + int shield_yield = rec->shield_yield; + int total_yield = food_yield + shield_yield; + + if (total_yield <= 0) + return; + + // Lazy load distribution hub icons + if (is->distribution_hub_icons_img_state == IS_UNINITED) + init_distribution_hub_icons (); + if (is->distribution_hub_icons_img_state != IS_OK) + return; + + Sprite * food_sprite = &is->distribution_hub_food_icon_small; + Sprite * shield_sprite = &is->distribution_hub_shield_icon_small; + + if (food_sprite->Width3 == 0) food_sprite = &is->distribution_hub_food_icon; + if (shield_sprite->Width3 == 0) shield_sprite = &is->distribution_hub_shield_icon; + + int sprite_height = food_sprite->Height; + if (sprite_height == 0) sprite_height = shield_sprite->Height; + + int food_width = food_sprite->Width3; + int shield_width = shield_sprite->Width3; + if ((food_width <= 0) && (shield_width > 0)) food_width = shield_width; + if ((shield_width <= 0) && (food_width > 0)) shield_width = food_width; + + // Calculate total width of all icons + int total_width = 0; + if (food_yield > 0) total_width += food_width * food_yield; + if (shield_yield > 0) total_width += shield_width * shield_yield; + + // Center the icons horizontally + int half_width = total_width >> 1; + int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; + int max_offset = (tile_width >> 1) - 5; + if (half_width > max_offset) half_width = max_offset; + + int pixel_x = screen_x - half_width; + int pixel_y = screen_y - (sprite_height >> 1); + + // Adjust spacing if icons would exceed tile width + int spacing_food = food_width; + int spacing_shield = shield_width; + + if (total_width > tile_width - 10) { + if (total_yield > 1) { + int spacing = (tile_width - 10 - food_width) / (total_yield - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > food_width) + spacing = food_width; + spacing_food = spacing; + spacing_shield = spacing; + } + } + + // Draw food icons first + for (int i = 0; i < food_yield; i++) { + Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing_food; + } + + // Draw shield icons + for (int i = 0; i < shield_yield; i++) { + Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing_shield; + } +} + +void __fastcall +patch_City_Form_draw_yields_on_worked_tiles (City_Form * this) +{ + // If we're zoomed in and the city work radius is at least 4 then it's likely we'll end up drawing things outside of the city screen's usual + // map area. Set the clip area to the map area so none of those draws are visible. + bool changed_clip_area = false; + if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { + set_clip_area_to_map_view (this); + changed_clip_area = true; + } + + if (is->current_config.enable_districts && this->CurrentCity != NULL) { + recompute_city_yields_with_districts (this->CurrentCity); + } + + is->do_not_draw_already_worked_tile_img = false; + City_Form_draw_yields_on_worked_tiles (this); + + // If we're zoomed out then draw the yields again but this time skip drawing of the tile-already-worked sprites. This is because the + // transparent regions of those sprites get drawn overtop of the yield sprites when zoomed out, and that overdrawing deletes parts of the + // yields, i.e., it overwrites their colored pixels with transparent ones. The simplest solution is to draw the yields again after the + // already-worked sprites to ensure the former get drawn overtop of the latter. + if (p_bic_data->is_zoomed_out) { + is->do_not_draw_already_worked_tile_img = true; + City_Form_draw_yields_on_worked_tiles (this); + } + + // Draw district bonuses on district tiles + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + City * city = this->CurrentCity; + if (city == NULL) + goto skip_district_yields; + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int civ_id = city->Body.CivID; + + // Calculate screen coordinates for city center + int center_screen_x, center_screen_y; + Main_Screen_Form_tile_to_screen_coords (p_main_screen_form, __, city_x, city_y, ¢er_screen_x, ¢er_screen_y); + + int tile_half_width = p_bic_data->is_zoomed_out ? 32 : 64; + int tile_half_height = p_bic_data->is_zoomed_out ? 16 : 32; + center_screen_x += tile_half_width; + if (center_screen_x < 0) + center_screen_x += p_bic_data->Map.Width * tile_half_width; + center_screen_y += tile_half_height; + if (center_screen_y < 0) + center_screen_y += p_bic_data->Map.Height * tile_half_height; + + int remaining_utilized_neighborhoods = 0; + if (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts) + remaining_utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + + FOR_DISTRICTS_AROUND (wai, city_x, city_y, true) { + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + bool is_distribution_hub = district_id == DISTRIBUTION_HUB_DISTRICT_ID; + bool is_natural_wonder = district_id == NATURAL_WONDER_DISTRICT_ID; + + if (is_natural_wonder && (!is->current_config.enable_natural_wonders)) + continue; + + // Distribution hubs are drawn in the dedicated wider-radius pass below. + if (is_distribution_hub) + continue; + + if (!is_natural_wonder && (!is->current_config.enable_districts)) + continue; + + // For neighborhood districts, check if population is high enough to utilize them + if (is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + district_id == NEIGHBORHOOD_DISTRICT_ID) { + // Only draw yields if this neighborhood is utilized + if (remaining_utilized_neighborhoods <= 0) + continue; + remaining_utilized_neighborhoods--; + } + + // Calculate screen coordinates for this tile + int screen_x = center_screen_x + (wai.dx * tile_half_width); + int screen_y = center_screen_y + (wai.dy * tile_half_height); + + // Call the appropriate drawing function + draw_district_yields (this, wai.tile, district_id, screen_x, screen_y); + } + + // Draw distribution hub yields around a larger radius so connected hubs outside the work area are shown + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { + int const max_tiles = workable_tile_counts[7]; + + for (int ni = 0; ni < max_tiles; ni++) { + int dx, dy; + patch_ni_to_diff_for_work_area (ni, &dx, &dy); + + int tile_x = city_x + dx; + int tile_y = city_y + dy; + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID)) + continue; + + int screen_x = center_screen_x + (dx * tile_half_width); + int screen_y = center_screen_y + (dy * tile_half_height); + draw_distribution_hub_yields (this, tile, tile_x, tile_y, screen_x, screen_y); + } + } + } + +skip_district_yields: + if (changed_clip_area) + clear_clip_area (this); +} + +bool __fastcall +patch_City_Form_draw_highlighted_yields (City_Form * this, int edx, int tile_x, int tile_y, int neighbor_index) +{ + // Make sure we don't draw outside the map area + bool changed_clip_area = false; + if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { + set_clip_area_to_map_view (this); + changed_clip_area = true; + } + + bool tr = City_Form_draw_highlighted_yields (this, __, tile_x, tile_y, neighbor_index); + + if (changed_clip_area) + clear_clip_area (this); + return tr; +} + +void __fastcall +patch_City_Form_draw_border_around_workable_tiles (City_Form * this) +{ + // Make sure we don't draw outside the map area + bool changed_clip_area = false; + if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { + set_clip_area_to_map_view (this); + changed_clip_area = true; + } + + City_Form_draw_border_around_workable_tiles (this); + + if (changed_clip_area) + clear_clip_area (this); +} + +bool __fastcall +patch_City_stop_working_polluted_tile (City * this, int edx, int neighbor_index) +{ + if (is->current_config.do_not_unassign_workers_from_polluted_tiles && + (*p_human_player_bits & (1 << this->Body.CivID))) + return false; // do nothing; return value is not used + else + return City_stop_working_tile (this, __, neighbor_index); +} + +void __fastcall +patch_City_manage_by_governor (City * this, int edx, bool manage_professions) +{ + int * p_stack = (int *)&manage_professions; + int ret_addr = p_stack[-1]; + + // Do nothing if called after spawning pollution but didn't unassign worker + if ((ret_addr == ADDR_MANAGE_CITY_AFTER_POLLUTION_RETURN) && + is->current_config.do_not_unassign_workers_from_polluted_tiles && + (*p_human_player_bits & (1 << this->Body.CivID))) + return; + + City_manage_by_governor (this, __, manage_professions); +} + +City * __cdecl +patch_find_nearest_city_for_ai_alliance_eval (int tile_x, int tile_y, int owner_id, int continent_id, int ignore_owner_id, int perspective_id, City * ignore_city) +{ + City * tr = find_nearest_city (tile_x, tile_y, owner_id, continent_id, ignore_owner_id, perspective_id, ignore_city); + if (is->current_config.patch_division_by_zero_in_ai_alliance_eval && (*p_nearest_city_distance == 0)) + *p_nearest_city_distance = 1; + return tr; +} + +int __fastcall +patch_Unit_get_max_move_points (Unit * this) +{ + if (Unit_has_ability (this, __, UTA_Army) && is->current_config.patch_empty_army_movement) { + int slowest_member_mp = INT_MAX; + bool any_units_in_army = false; + FOR_UNITS_ON (uti, tile_at (this->Body.X, this->Body.Y)) { + if (uti.unit->Body.Container_Unit == this->Body.ID) { + any_units_in_army = true; + slowest_member_mp = not_above (Unit_get_max_move_points (uti.unit), slowest_member_mp); + } + } + if (any_units_in_army) + return slowest_member_mp + p_bic_data->General.RoadsMovementRate; + else + return get_max_move_points (&p_bic_data->UnitTypes[this->Body.UnitTypeID], this->Body.CivID); + } else + return Unit_get_max_move_points (this); +} + +char __fastcall +patch_Unit_is_visible_to_civ_for_bouncing (Unit * this, int edx, int civ_id, int param_2) +{ + // If we're set not to kick out invisible units and this one is invis. then report that it's not seen so it's left alone + if (is->do_not_bounce_invisible_units && Unit_has_ability (this, __, UTA_Invisible)) + return 0; + else + return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); +} + +void __fastcall +patch_Leader_make_peace (Leader * this, int edx, int civ_id) +{ + Leader_make_peace (this, __, civ_id); + + if (is->current_config.disallow_trespassing && + (! this->At_War[civ_id]) && // Make sure the war actually ended + ((this->Relation_Treaties[civ_id] & 2) == 0)) { // Check right of passage (just in case) + is->do_not_bounce_invisible_units = true; + Leader_bounce_trespassing_units (&leaders[civ_id], __, this->ID); + is->do_not_bounce_invisible_units = false; + } +} + +// This patch function replaces calls to Leader::count_wonders_with_flag but is only valid in cases where it only matters whether the return value is +// zero or non-zero. This function will not return the actual count, just zero if no wonders are present and some >0 value if there is at least one. +int __fastcall +patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) +{ + int tr = Leader_count_wonders_with_flag (this, __, flag, only_in_city); + + if ((tr == 0) && + (only_in_city == NULL) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player + + // Sum up wonders owned by other human players + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->ID)) + if (Leader_count_wonders_with_flag (&leaders[n_player], __, flag, only_in_city) > 0) { + tr = 1; + break; + } + player_bits >>= 1; + n_player++; + } + } + + return tr; +} + +int __fastcall +patch_Leader_count_wonders_with_flag_ignore_great_wall (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) +{ + if (is->current_config.enable_districts && + is->current_config.enable_great_wall_districts && + is->current_config.disable_great_wall_city_defense_bonus && + flag == ITW_Doubles_City_Defenses) + return 0; + + return patch_Leader_count_any_shared_wonders_with_flag (this, __, flag, only_in_city); +} + +int const shared_small_wonder_flags = + ITSW_Increases_Chance_of_Leader_Appearance | + ITSW_Build_Larger_Armies | + ITSW_Treasury_Earns_5_Percent | + ITSW_Decreases_Success_Of_Missile_Attacks | + ITSW_Allows_Spy_Missions | + ITSW_Allows_Healing_In_Enemy_Territory | + ITSW_Requires_Victorous_Army | + ITSE_Requires_Elite_Naval_Units; + + +int __fastcall +patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) +{ + int tr = Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); + + // If "this" is a human player who's sharing wonders in hotseat and the flag is one of the ones that gets shared, include the wonders owned by + // all other humans in the game + if ((city_or_null == NULL) && + (flag & shared_small_wonder_flags) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player + + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->ID)) + tr += Leader_count_wonders_with_small_flag (&leaders[n_player], __, flag, city_or_null); + player_bits >>= 1; + n_player++; + } + } + + return tr; +} + +int +find_human_player_with_small_wonder (int improv_id) +{ + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if (player_bits & 1) + if (leaders[n_player].Small_Wonders[improv_id] != -1) + return n_player; + player_bits >>= 1; + n_player++; + } + return -1; +} + +bool __fastcall +patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2) +{ + Improvement * improv = &p_bic_data->Improvements[i_improv]; + bool restore = false; + bool already_shared = false; + int saved_status, saved_required_building_count, saved_armies_count; + if ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) && // if the improv in question is a great or small wonder + is->current_config.share_wonders_in_hotseat && // if we're configured to share wonder effects + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // if in a hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // if "this" is a human player + + // If another human player has already built this small wonder and it has no non-shared effects, then make it unbuildable + if ((improv->Characteristics & ITC_Small_Wonder) && + (find_human_player_with_small_wonder (i_improv) != -1) && + ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) + already_shared = true; + + else { + restore = true; + saved_status = this->Status; + if (improv->RequiredBuildingID != -1) + saved_required_building_count = this->Improvement_Counts[improv->RequiredBuildingID]; + saved_armies_count = this->Armies_Count; + + // Loop over all other human players in the game + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->ID)) { + + // Combine status bits + this->Status |= leaders[n_player].Status & (LSF_HAS_VICTORIOUS_ARMY | LSF_HAS_ELITE_NAVAL_UNIT); + + // Combine building counts for the required building if there is one + if (improv->RequiredBuildingID != -1) + this->Improvement_Counts[improv->RequiredBuildingID] += leaders[n_player].Improvement_Counts[improv->RequiredBuildingID]; + + // Combine army counts + this->Armies_Count += leaders[n_player].Armies_Count; + + } + player_bits >>= 1; + n_player++; + } + } + } + + bool tr = (! already_shared) && Leader_can_build_city_improvement (this, __, i_improv, param_2); + + if (restore) { + this->Status = saved_status; + if (improv->RequiredBuildingID != -1) + this->Improvement_Counts[improv->RequiredBuildingID] = saved_required_building_count; + + this->Armies_Count = saved_armies_count; + } + return tr; + +} + +void __fastcall +patch_City_add_happiness_from_buildings (City * this, int edx, int * inout_happiness, int * inout_unhappiness) +{ + // If we're in a hotseat game with shared wonder effects, merge all human player's improvement counts together so the base function checks for + // happiness from improvements owned by other human players. + Leader * owner = &leaders[this->Body.CivID]; + bool restore_improv_counts = false; + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->Body.CivID) & *p_human_player_bits)) { // "this" is owned by a human player + + // Ensure the space we've set aside for saving the real improv counts is large enough + if ((is->saved_improv_counts == NULL) || (is->saved_improv_counts_capacity < p_bic_data->ImprovementsCount)) { + free (is->saved_improv_counts); + is->saved_improv_counts = calloc (p_bic_data->ImprovementsCount, sizeof is->saved_improv_counts[0]); + is->saved_improv_counts_capacity = (is->saved_improv_counts != NULL) ? p_bic_data->ImprovementsCount : 0; + } + + + if (is->saved_improv_counts != NULL) { + // Save the owner's real improv counts and remember to restore them before returning + restore_improv_counts = true; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + is->saved_improv_counts[n] = owner->Improvement_Counts[n]; + + // Add in improv counts for wonders from all other human players in the game + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != owner->ID)) + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (p_bic_data->Improvements[n].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + owner->Improvement_Counts[n] += leaders[n_player].Improvement_Counts[n]; + player_bits >>= 1; + n_player++; + } + } + + } + + City_add_happiness_from_buildings (this, __, inout_happiness, inout_unhappiness); + + if (is->current_config.enable_districts) { + int district_happy = 0; + calculate_district_happiness_bonus (this, &district_happy); + + if (district_happy != 0) + *inout_happiness += district_happy; + } + + if (restore_improv_counts) { + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + owner->Improvement_Counts[n] = is->saved_improv_counts[n]; + } +} + +int __fastcall +patch_City_count_other_cont_happiness_buildings (City * this, int edx, int improv_id) +{ + int tr = City_count_other_buildings_on_continent (this, __, improv_id); + + // If it's a hotseat game where we're sharing wonders, "improv_id" refers to a wonder, and "this" is owned by a human player + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((p_bic_data->Improvements[improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && + ((1 << this->Body.CivID) & *p_human_player_bits)) { + + // Add in instances of this improvment on this continent owned by other human players + Tile * this_city_tile = tile_at (this->Body.X, this->Body.Y); + int this_cont_id = this_city_tile->vtable->m46_Get_ContinentID (this_city_tile); + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city != NULL) && (city != this) && + (city->Body.CivID != this->Body.CivID) && // if city is owned by a different player AND + ((1 << city->Body.CivID) & *p_human_player_bits)) { // that player is a human + Tile * that_city_tile = tile_at (city->Body.X, city->Body.Y); + int that_cont_id = that_city_tile->vtable->m46_Get_ContinentID (that_city_tile); + if ((this_cont_id == that_cont_id) && patch_City_has_improvement (city, __, improv_id, true)) + tr++; + } + } + + } + + return tr; +} + +void __fastcall +patch_Leader_update_great_library_unlocks (Leader * this) +{ + // If it's a hotseat game with shared wonder effects and "this" is a human player, share contacts among all human players so that "this" gets + // techs from civs known to any human player in the game. Save the real contact info and restore it afterward. NOTE: Contact info has to go + // two ways here; we must mark that "this" has contacted the AIs and vice-versa otherwise the techs won't be granted. That's why we must save + // & restore all contact bits for all players. + bool restore_contacts = false; + struct contact_set { + int contacts[32]; + } saved_contact_sets[32]; + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player + + restore_contacts = true; + for (int n = 0; n < 32; n++) + for (int k = 0; k < 32; k++) + saved_contact_sets[n].contacts[k] = leaders[n].Contacts[k]; + + unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_human = 1; + while (human_player_bits != 0) { + if ((human_player_bits & 1) && (n_human != this->ID)) // n_human is ID of a human player other than "this" + for (int n_ai = 0; n_ai < 32; n_ai++) + if ((*p_player_bits & (1 << n_ai)) && ((*p_human_player_bits & (1 << n_ai)) == 0)) { + // If the human and AI players have contact, mark "this" as having contact with the AI and vice-versa + if (leaders[n_human].Contacts[n_ai] & 1) { + this->Contacts[n_ai] |= 1; + leaders[n_ai].Contacts[this->ID] |= 1; + } + } + human_player_bits >>= 1; + n_human++; + } + } + + Leader_update_great_library_unlocks (this); + + if (restore_contacts) + for (int n = 0; n < 32; n++) + for (int k = 0; k < 32; k++) + leaders[n].Contacts[k] = saved_contact_sets[n].contacts[k]; +} + +bool __fastcall +patch_Leader_has_wonder_doubling_happiness_from (Leader * this, int edx, int improv_id) +{ + bool tr = Leader_has_wonder_doubling_happiness_from (this, __, improv_id); + + // If we're sharing wonder effects in a hotseat game and "this" is a human player, return true when another human player in the game has a + // wonder doubling happiness + if ((! tr) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player + unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_human = 1; + while (human_player_bits != 0) { + if ((human_player_bits & 1) && + (n_human != this->ID) && + Leader_has_wonder_doubling_happiness_from (&leaders[n_human], __, improv_id)) { + tr = true; + break; + } + human_player_bits >>= 1; + n_human++; + } + } + + return tr; +} + +int __fastcall +patch_Sprite_draw_citizen_head (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + // Reset variable + is->specialist_icon_drawing_running_x = INT_MIN; + + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +int +adjust_specialist_yield_icon_x (int pixel_x, int width) +{ + if (is->current_config.fix_overlapping_specialist_yield_icons) { + if (is->specialist_icon_drawing_running_x == INT_MIN) // first icon drawn + is->specialist_icon_drawing_running_x = pixel_x; + int tr = is->specialist_icon_drawing_running_x; + is->specialist_icon_drawing_running_x += width; + return tr; + } else + return pixel_x; +} + +int __fastcall +patch_Sprite_draw_entertainer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_12_Happy_Faces.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_scientist_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_16_Science.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_tax_collector_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_14_Gold.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_civil_engineer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_13_Shield.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_police_officer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_17_Gold_Outcome.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} + +void __fastcall +patch_City_add_building_if_done (City * this) +{ + // If sharing small wonders in hotseat, check whether the city is building a small wonder that's no longer available to the player b/c its + // effects are provided from another. + int improv_id = this->Body.Order_ID; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + int already_built_by_id; + if ((improv->Characteristics & ITC_Small_Wonder) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->Body.CivID) & *p_human_player_bits) && // city owned by a human player + ((already_built_by_id = find_human_player_with_small_wonder (improv_id)) != -1) && // SW already built by another human player + ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) { // SW has no non-shared effects + + // Switch city production to something else and notify the player + this->vtable->set_production_to_most_expensive_option (this); + if ((this->Body.CivID == p_main_screen_form->Player_CivID) && (already_built_by_id != p_main_screen_form->Player_CivID)) { + char * new_build_name = (this->Body.Order_Type == COT_Improvement) ? + p_bic_data->Improvements[this->Body.Order_ID].Name.S : + p_bic_data->UnitTypes[this->Body.Order_ID].Name; + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, this->Body.CityName, -1, -1); + set_popup_str_param (1, improv->Name.S, -1, -1); + set_popup_str_param (2, Leader_get_civ_noun (&leaders[already_built_by_id]), -1, -1); + set_popup_str_param (3, new_build_name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_SHARED_WONDER_CHANGE", -1, 0, 0, 0); + int response = patch_show_popup (popup, __, 0, 0); + if (response == 0) + *p_zoom_to_city_after_update = true; + } + + // As in the base logic, if production gets switched, the game doesn't check if it might still complete on the same turn. + return; + } + + // If production ended up on a wonder, make sure the city can actually build it; otherwise fall back to a defensive unit. + int order_type = this->Body.Order_Type; + int order_id = this->Body.Order_ID; + if (is->current_config.enable_districts && order_type == COT_Improvement) { + Improvement * new_improv = &p_bic_data->Improvements[order_id]; // Improvement might have changed + if (new_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { + if (! (City_can_build_improvement (this, __, order_id, false) && city_meets_district_prereqs_to_build_improvement (this, order_id, true))) { + char ss[256]; + snprintf (ss, sizeof ss, "patch_City_add_building_if_done: City '%s' cannot complete building of wonder '%s'; switching to defensive unit.\n", + this->Body.CityName, + new_improv->Name.S); + (*p_OutputDebugStringA) (ss); + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (this, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) { + City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); + return; + } + } + } + } + } + + City_add_building_if_done (this); +} + +bool __fastcall +patch_City_can_build_upgrade_type (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) +{ + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + if (is->current_config.prevent_old_units_from_upgrading_past_ability_block && + ((type->Special_Actions & UCV_Upgrade_Unit) == 0) && + (type->Available_To & (1 << leaders[this->Body.CivID].RaceID))) + exclude_upgradable = false; + + return patch_City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); +} + +void __fastcall +patch_Main_GUI_position_elements (Main_GUI * this) +{ + Main_GUI_position_elements (this); + + // Double size of minimap if configured + bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || + ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); + if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) { + this->Mini_Map_Click_Rect.top -= 105; + this->Mini_Map_Click_Rect.right += 229; + } +} + +#define PEDIA_DESC_LINES_PER_PAGE 38 + +// Returns whether or not the line should be drawn +bool +do_next_line_for_pedia_desc (PCX_Image * canvas, int * inout_y) +{ + if (is->cmpd.drawing_lines && is->current_config.allow_multipage_civilopedia_descriptions) { + int first_line_on_shown_page = is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE; + int page = is->cmpd.line_count / PEDIA_DESC_LINES_PER_PAGE; + is->cmpd.line_count += 1; + is->cmpd.last_page = (page > is->cmpd.last_page) ? page : is->cmpd.last_page; + + if (page == is->cmpd.shown_page) { + *inout_y -= is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE * PCX_Image_get_text_line_height (canvas); + return true; + } else + return false; + } + return true; +} + +int __fastcall +patch_PCX_Image_do_draw_centered_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) +{ + if (do_next_line_for_pedia_desc (this, &y)) + return PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); + else + return 0; // Caller does not use return value +} + +int __fastcall +patch_PCX_Image_draw_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int str_len) +{ + if (do_next_line_for_pedia_desc (this, &y)) + return PCX_Image_draw_text (this, __, str, x, y, str_len); + else + return PCX_Image_draw_text (this, __, " ", x, y, 1); // Caller uses the return value here so draw an empty string isntead of doing nothing +} + +// Steam code is slightly different; this no-len version of draw_text gets called sometimes. It's the same as draw_text instead it computes the string +// length itself instead of taking it in as a parameter. +int __fastcall +patch_PCX_Image_draw_text_no_len_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y) +{ + return patch_PCX_Image_draw_text_in_wrap_func (this, __, str, x, y, strlen (str)); +} + +void +draw_civilopedia_article (void (__fastcall * base) (Civilopedia_Article *), Civilopedia_Article * article) +{ + // If the article changed then clear things from the old one + if (is->cmpd.article != article) { + is->cmpd.last_page = 0; + is->cmpd.shown_page = 0; + is->cmpd.article = article; + } + + is->cmpd.line_count = 0; + is->cmpd.drawing_lines = article->show_description; + + base (article); + + is->cmpd.drawing_lines = false; +} + +void __fastcall +patch_Civilopedia_Article_m01_Draw_GCON_or_RACE (Civilopedia_Article * this) +{ + draw_civilopedia_article (Civilopedia_Article_m01_Draw_GCON_or_RACE, this); +} + +void +print_pedia_unit_stats (PCX_Image * canvas, int x, char ** entries, int entry_count) +{ + // Same forumula as the base game. Shifts entries upward if 4 or more. + int y = (entry_count > 3) ? 4 * (3 * entry_count - 9) : 0; + y = 449 - y; + + for (int n = 0; n < entry_count; n++) + y = PCX_Image_draw_and_wrap_text (canvas, __, entries[n], x, y, 150); +} + +void __fastcall +patch_Civilopedia_Article_m01_Draw_UNIT (Civilopedia_Article * this) +{ + // Make sure list of second column stat strings is clear before drawing + char ** entries = is->pedia_unit_stats_second_column_strs; + int capacity = ARRAY_LEN (is->pedia_unit_stats_second_column_strs); + if (is->current_config.expand_civilopedia_unit_stats) + for (int n = 0; n < capacity; n++) { + free (entries[n]); + entries[n] = NULL; + } + + draw_civilopedia_article (Civilopedia_Article_m01_Draw_UNIT, this); + + bool drew_stats = this->show_description == false || this->more_text_line_count == 0; + if (is->current_config.expand_civilopedia_unit_stats && drew_stats) { + // By this point entries have been filled in for the second column of unit stats (see ...draw_pedia_unit_stats_2nd_column), which has + // not actually been drawn. + int entry_count = 0; + for (int n = 0; n < capacity; n++) + if (entries[n] != NULL) + entry_count++; + + char s[100] = {0}; + + // Add entry for op range if aircraft. The original game shows movement instead of op range in the first column but we patch that to + // show movement always. + if (entry_count < capacity && this->unit_type->Unit_Class == UTC_Air) { + // Reserve spot at entries[0] to prepend new item + for (int n = capacity - 1; n > 0; n--) + entries[n] = entries[n-1]; + entry_count++; + + snprintf (s, (sizeof s) - 1, "%s: %d", (*p_labels)[LBL_OPERATIONAL_RANGE], this->unit_type->OperationalRange); + entries[0] = strdup (s); + } + + // Add bombard range if tactical nuke with bombard strength == 0 because the base game won't display it + if (entry_count < capacity && + this->unit_type->Unit_Class == UTC_Land && + this->unit_type->Bombard_Strength == 0 && + UnitType_has_ability (this->unit_type, __, UTA_Nuclear_Weapon) && + UnitType_has_ability (this->unit_type, __, UTA_Tacticle_Missile)) { + snprintf (s, (sizeof s) - 1, "%s: %d", (*p_labels)[LBL_BOMBARD_RANGE], this->unit_type->Bombard_Range); + entries[entry_count++] = strdup (s); + } + + // Add HP Bonus + if (entry_count < capacity && this->unit_type->Hit_Point_Bonus != 0) { + snprintf (s, (sizeof s) - 1, "%s: %d", is->c3x_labels[CL_HP_BONUS], this->unit_type->Hit_Point_Bonus); + entries[entry_count++] = strdup (s); + } + + // Add worker strength + int rounded_worker_strength = ((int)(this->unit_type->WorkerStrength * 10000.0f) + 50) / 100; + if (entry_count < capacity && rounded_worker_strength != 0) { + snprintf (s, (sizeof s) - 1, "%s: %d%%", is->c3x_labels[CL_WORKER_STRENGTH], rounded_worker_strength); + entries[entry_count++] = strdup (s); + } + + if (entry_count <= 6) + print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 213, entries, entry_count); + else { // If more than 6 entries, split some off into a third column + int third_count = entry_count / 2, + second_count = entry_count - third_count; + print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 198, entries, second_count); + print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 355, &entries[second_count], third_count); + } + } +} + +int __fastcall +patch_PCX_Image_draw_pedia_unit_stats_2nd_column (PCX_Image * this, int edx, char * str, int x, int y, int width) +{ + if (is->current_config.expand_civilopedia_unit_stats) + for (int n = 0; n < ARRAY_LEN (is->pedia_unit_stats_second_column_strs); n++) + if (is->pedia_unit_stats_second_column_strs[n] == NULL) { + is->pedia_unit_stats_second_column_strs[n] = strdup (str); // Record what would have been drawn here + str = " "; // Draw empty string. Can't skip draw call entirely b/c we need the return value + break; + } + + return PCX_Image_draw_and_wrap_text (this, __, str, x, y, width); +} + +void __fastcall +patch_Civilopedia_Form_m53_On_Control_Click (Civilopedia_Form * this, int edx, CivilopediaControlID control_id) +{ + Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; + + // "Effects" button leaves description mode, returns to showing effects + if ((control_id == PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID) && (current_article != NULL)) { + current_article->show_description = false; + is->cmpd.shown_page = 0; + play_sound_effect (26); // 26 = SE_SELECT + p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); + + // "Previous" button shows the previous page of a multi-page description or switches to effects mode if on the first page + } else if (control_id == PEDIA_MULTIPAGE_PREV_BUTTON_ID) { + if (is->cmpd.shown_page > 0) + is->cmpd.shown_page -= 1; + else + current_article->show_description = false; + play_sound_effect (26); + p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); + + } else if ((control_id == CCID_DESCRIPTION_BTN) && // if description/more/prev button was clicked AND + (current_article != NULL) && current_article->show_description && // currently showing a description of an article AND + (is->cmpd.last_page > 0)) { // this is a multi-page description + + // Show the next page of the multi-page description unless it's a two-page description and we're on the second page, in which case go + // back to the first. + if ((is->cmpd.last_page == 1) && (is->cmpd.shown_page == 1)) + is->cmpd.shown_page = 0; + else + is->cmpd.shown_page = not_above (is->cmpd.last_page, is->cmpd.shown_page + 1); + play_sound_effect (26); + p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); + + } else + Civilopedia_Form_m53_On_Control_Click (this, __, control_id); +} + +void __fastcall +patch_Civilopedia_Form_m22_Draw (Civilopedia_Form * this) +{ + // Make sure the new buttons are not visible and the multipage variables are cleared when we exit description mode + if ((this->Current_Article_ID < 0) || ! this->Articles[this->Current_Article_ID]->show_description) { + is->cmpd.shown_page = is->cmpd.last_page = 0; + if (is->cmpd.effects_btn != NULL) + is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); + if (is->cmpd.previous_btn != NULL) + is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); + } + + Civilopedia_Form_m22_Draw (this); +} + +int __fastcall +patch_Button_initialize_civilopedia_description (Button * this, int edx, char * text, int control_id, int x, int y, int width, int height, Base_Form * parent, int param_8) +{ + Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; + if (current_article == NULL) + return Button_initialize (this, __, text, control_id, x, y, width, height, parent, param_8); + + // Set button visibility for multi-page descriptions if we're showing such a thing right now + bool show_desc_btn = true, show_effects_btn = false, show_previous_btn = false; + char * desc_btn_text = text; + if (current_article->show_description && (is->cmpd.last_page > 0)) { + + // Tribe articles act like one long descripton. + if ((current_article->article_kind == CAK_TRIBE) || (current_article->article_kind == CAK_GAME_CONCEPT)) { + + // Show the more button as long as we're not on the last page. Show the previous always since we're in description mode. + show_previous_btn = true; + desc_btn_text = (*p_labels)[LBL_MORE]; + if (is->cmpd.shown_page >= is->cmpd.last_page) + show_desc_btn = false; + + // Unit articles have separate description/effects modes. + } else if (current_article->article_kind == CAK_UNIT) { + + // For a two-page description, show the effects button and the description button which will act as a next/previous button + if (is->cmpd.last_page == 1) { + show_effects_btn = true; + desc_btn_text = is->cmpd.shown_page == 0 ? (*p_labels)[LBL_MORE] : (*p_labels)[LBL_PREVIOUS]; + + // For a three or more page description, show the effects button, and show the description button only if we're not on the + // last page (b/c it's the next button), and show the previous button only if we're not on the first page. If the desc button + // is visible, make it say "More". + } else { + show_effects_btn = true; + if (is->cmpd.shown_page >= is->cmpd.last_page) + show_desc_btn = false; + else + desc_btn_text = (*p_labels)[LBL_MORE]; + show_previous_btn = is->cmpd.shown_page > 0; + } + } + } + + int tr = Button_initialize (this, __, desc_btn_text, control_id, x, y, width, height, parent, param_8); + + if (! show_desc_btn) + this->vtable->m02_Show_Disabled ((Base_Form *)this); + + if (is->cmpd.effects_btn != NULL) { + if (show_effects_btn) + is->cmpd.effects_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.effects_btn, __, 0); + else + is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); + } + + if (is->cmpd.previous_btn != NULL) { + if (show_previous_btn) + is->cmpd.previous_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.previous_btn, __, 0); + else + is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); + } + + return tr; +} + +int __fastcall +patch_Civilopedia_Form_m68_Show_Dialog (Civilopedia_Form * this, int edx, int param_1, void * param_2, void * param_3) +{ + memset (&is->cmpd, 0, sizeof is->cmpd); + + Button * bs[] = {malloc (sizeof Button), malloc (sizeof Button)}; + for (int n = 0; n < ARRAY_LEN (bs); n++) { + if (bs[n] == NULL) + continue; + Button_construct (bs[n]); + + int desc_btn_x = 535, desc_btn_y = 222, desc_btn_height = 17; + + Button_initialize (bs[n], __, + n == 0 ? (*p_labels)[LBL_EFFECTS] : (*p_labels)[LBL_PREVIOUS], + n == 0 ? PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID : PEDIA_MULTIPAGE_PREV_BUTTON_ID, // control ID + desc_btn_x, // location x + desc_btn_y + (n == 0 ? -2 : 2) * desc_btn_height, // location y + MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height + (Base_Form *)this, // parent + 0); // ? + + for (int k = 0; k < 3; k++) + bs[n]->Images[k] = &this->Description_Btn_Images[k]; + + // Do now draw the button until needed + bs[n]->vtable->m02_Show_Disabled ((Base_Form *)bs[n]); + } + is->cmpd.effects_btn = bs[0]; + is->cmpd.previous_btn = bs[1]; + + int tr = Civilopedia_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); + + for (int n = 0; n < ARRAY_LEN (bs); n++) + if (bs[n] != NULL) { + bs[n]->vtable->destruct ((Base_Form *)bs[n], __, 0); + free (bs[n]); + } + is->cmpd.effects_btn = is->cmpd.previous_btn = NULL; + + return tr; +} + +void +init_district_images () +{ + if (is_online_game () || is->dc_img_state != IS_UNINITED) + return; + + char art_dir[200]; + char temp_path[2*MAX_PATH]; + + is->dc_img_state = IS_INIT_FAILED; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + // For each district type + for (int dc = 0; dc < is->district_count; dc++) { + struct district_config const * cfg = &is->district_configs[dc]; + int variant_count = cfg->img_path_count; + if (variant_count <= 0) + continue; + + int era_count = cfg->vary_img_by_era ? 4 : 1; + int column_count = cfg->img_column_count; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + + // For each cultural variant + for (int variant_i = 0; variant_i < variant_count; variant_i++) { + if (cfg->img_paths[variant_i] == NULL) + continue; + + // Read PCX file + snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", cfg->img_paths[variant_i]); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + + if (pcx.JGL.Image == NULL) { + + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load district images from %s", temp_path); + pop_up_in_game_error (ss); + + (*p_OutputDebugStringA) ("[C3X] Failed to load districts sprite sheet.\n"); + for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) + for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) + for (int era_i = 0; era_i < 4; era_i++) { + for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { + Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + } + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + // For each era + for (int era_i = 0; era_i < era_count; era_i++) { + + // For each column in the image (variations on the district image for that era) + for (int col_i = 0; col_i < column_count; col_i++) { + Sprite_construct (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i]); + + int x = sprite_width * col_i, + y = sprite_height * era_i; + Sprite_slice_pcx (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i], __, &pcx, x, y, sprite_width, sprite_height, 1, 1); + } + } + + pcx.vtable->clear_JGL (&pcx); + } + } + // Load abandoned district images (land + maritime) + get_mod_art_path ("Districts/1200/Abandoned.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + + if (pcx.JGL.Image == NULL) { + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load abandoned district images from %s", temp_path); + pop_up_in_game_error (ss); + for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) + for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) + for (int era_i = 0; era_i < 4; era_i++) { + for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { + Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + } + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + Sprite_construct (&is->abandoned_district_img); + Sprite_slice_pcx (&is->abandoned_district_img, __, &pcx, 0, 0, 128, 64, 1, 1); + + Sprite_construct (&is->abandoned_maritime_district_img); + Sprite_slice_pcx (&is->abandoned_maritime_district_img, __, &pcx, 128, 0, 128, 64, 1, 1); + pcx.vtable->clear_JGL (&pcx); + + // Load wonder district images (dynamically per wonder) + if (is->current_config.enable_wonder_districts) { + char const * last_img_path = NULL; + PCX_Image wpcx; + PCX_Image_construct (&wpcx); + bool pcx_loaded = false; + + for (int wi = 0; wi < is->wonder_district_count; wi++) { + struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; + char const * img_path = cfg->img_path; + if (img_path == NULL) + img_path = "Wonders.pcx"; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + + // Load new image file if different from previous + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + + snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + PCX_Image_read_file (&wpcx, __, temp_path, NULL, 0, 0x100, 2); + + if (wpcx.JGL.Image == NULL) { + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load wonder district images from %s", temp_path); + pop_up_in_game_error (ss); + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; + + Sprite_construct (&set->img); + int x = sprite_width * cfg->img_column; + int y = sprite_height * cfg->img_row; + Sprite_slice_pcx (&set->img, __, &wpcx, x, y, sprite_width, sprite_height, 1, 1); + + Sprite_construct (&set->construct_img); + int cx = sprite_width * cfg->img_construct_column; + int cy = sprite_height * cfg->img_construct_row; + Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, sprite_width, sprite_height, 1, 1); + + if (cfg->enable_img_alt_dir) { + Sprite_construct (&set->alt_dir_img); + int ax = sprite_width * cfg->img_alt_dir_column; + int ay = sprite_height * cfg->img_alt_dir_row; + Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, sprite_width, sprite_height, 1, 1); + + Sprite_construct (&set->alt_dir_construct_img); + int acx = sprite_width * cfg->img_alt_dir_construct_column; + int acy = sprite_height * cfg->img_alt_dir_construct_row; + Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, sprite_width, sprite_height, 1, 1); + } + } + + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + wpcx.vtable->destruct (&wpcx, __, 0); + } + + if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { + char const * last_img_path = NULL; + PCX_Image nwpcx; + PCX_Image_construct (&nwpcx); + bool pcx_loaded = false; + + for (int ni = 0; ni < is->natural_wonder_count; ni++) { + struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[ni]; + if (cfg->name == NULL) + continue; + + char const * img_path = cfg->img_path; + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + + snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + PCX_Image_read_file (&nwpcx, __, temp_path, NULL, 0, 0x100, 2); + + if (nwpcx.JGL.Image == NULL) { + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load natural wonder images from %s", temp_path); + pop_up_in_game_error (ss); + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + Sprite_construct (&is->natural_wonder_img_sets[ni].img); + int x = 128 * cfg->img_column; + int y = 88 * cfg->img_row; + Sprite_slice_pcx (&is->natural_wonder_img_sets[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); + } + + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + nwpcx.vtable->destruct (&nwpcx, __, 0); + } + + is->dc_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +bool +tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv) +{ + Tile * center = tile_at (tile_x, tile_y); + + if ((center == NULL) || (center == p_null_tile)) return false; + int owner_id = center->Territory_OwnerID; + if (owner_id <= 0) return false; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + if (has_active_building (wai.city, i_improv)) + return true; + } + + return false; +} + +bool +wonder_requires_river (struct wonder_district_config const * cfg) +{ + unsigned int build_mask = wonder_buildable_square_type_mask (cfg); + if (build_mask == 0) + build_mask = district_default_buildable_mask (); + if ((build_mask & square_type_mask_bit (SQ_RIVER)) != 0) + return true; + if (cfg->buildable_on_rivers) + return true; + return false; +} + +Tile * +get_tile_sprite_indices (int tile_x, int tile_y, int * out_sheet_index, int * out_sprite_index) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + + if (tile != NULL && tile != p_null_tile) { + *out_sheet_index = (tile->SquareParts >> 8) & 0xFF; + *out_sprite_index = tile->SquareParts & 0xFF; + } else { + *out_sheet_index = -1; + *out_sprite_index = -1; + } + + return tile; +} + +void +align_district_with_river (Tile * tile, int * out_pixel_x, int * out_pixel_y, enum direction * out_dir) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return; + + enum direction dir = DIR_ZERO; + if (! get_primary_river_direction (tile, &dir)) + return; + + int dx, dy; + int offset = 36; + direction_to_offset (dir, &dx, &dy); + + dy = 0; + switch (dir) { + case DIR_N: dy = -offset; break; + case DIR_NE: dy = -offset/2; break; + case DIR_E: dy = 0; break; + case DIR_SE: dy = offset/2; break; + case DIR_S: dy = offset; break; + case DIR_SW: dy = offset/2; break; + case DIR_W: dy = 0; break; + case DIR_NW: dy = -offset/2; break; + default: break; + } + + if (out_pixel_x != NULL) + *out_pixel_x += dx; + if (out_pixel_y != NULL) + *out_pixel_y += dy; + if (out_dir != NULL) + *out_dir = dir; +} + +void +align_variant_and_pixel_offsets_with_coastline (Tile * tile, int * out_variant, int * out_pixel_x, int * out_pixel_y) +{ + if ((tile == NULL) || (tile == p_null_tile) || (out_variant == NULL)) + return; + + int owner_id = tile->Territory_OwnerID; + if (owner_id <= 0) + return; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return; + + int tile_x = inst->tile_x; + int tile_y = inst->tile_y; + Map * map = &p_bic_data->Map; + + City * closest_city = NULL; + int closest_dx = 0, closest_dy = 0; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + City * city = wai.city; + int ndx = city->Body.X - tile_x; + int ndy = city->Body.Y - tile_y; + + if (map->Flags & 1) { + int half_width = map->Width / 2; + if (ndx > half_width) + ndx -= map->Width; + else if (ndx < -half_width) + ndx += map->Width; + } + if (map->Flags & 2) { + int half_height = map->Height / 2; + if (ndy > half_height) + ndy -= map->Height; + else if (ndy < -half_height) + ndy += map->Height; + } + + closest_city = city; + closest_dx = ndx; + closest_dy = ndy; + break; + } + + if (closest_city == NULL) + return; + + bool city_is_directly_above_port = (closest_dx == 0) && (closest_dy == -2); + bool city_is_directly_below_port = (closest_dx == 0) && (closest_dy == 2); + bool city_is_directly_west_of_port = (closest_dx < 0) && (closest_dy == 0); + bool city_is_directly_east_of_port = (closest_dx > 0) && (closest_dy == 0); + bool city_is_directly_northeast_of_port = (closest_dx == 1) && (closest_dy == -1); + bool city_is_directly_southeast_of_port = (closest_dx == 1) && (closest_dy == 1); + bool city_is_directly_southwest_of_port = (closest_dx == -1) && (closest_dy == 1); + bool city_is_directly_northwest_of_port = (closest_dx == -1) && (closest_dy == -1); + + // Variant indices; can't use direction enum as values are slightly different + int NONE = -1; + int NW = 0; + int NE = 1; + int SE = 2; + int SW = 3; + *out_variant = NONE; + + enum direction anchor = NONE; + bool direct_diagonal = false; + + // Direct diagonals + if (city_is_directly_northeast_of_port) { *out_variant = SW; anchor = DIR_NE; direct_diagonal = true; } + else if (city_is_directly_southeast_of_port) { *out_variant = NW; anchor = DIR_SE; direct_diagonal = true; } + else if (city_is_directly_southwest_of_port) { *out_variant = NE; anchor = DIR_SW; direct_diagonal = true; } + else if (city_is_directly_northwest_of_port) { *out_variant = SE; anchor = DIR_NW; direct_diagonal = true; } + + // City either in a direct cardinal direction or not adjacent, check relative directions + else { + bool city_is_west_of_port = (closest_dx < 0); + bool city_is_east_of_port = (closest_dx > 0); + bool city_is_north_of_port = (closest_dy < 0); + bool city_is_south_of_port = (closest_dy > 0); + bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, true); + bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, true); + bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); + bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); + bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); + bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, true); + bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, true); + bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, true); + + if (city_is_directly_above_port) { + if (northwest_tile_is_land && ! tile_is_land (owner_id, tile_x + 1, tile_y + 1, true)) { + *out_variant = SE; anchor = DIR_NW; + } else if (northeast_tile_is_land && ! tile_is_land (owner_id, tile_x - 1, tile_y + 1, true)) { + *out_variant = SW; anchor = DIR_NE; + } else { + *out_variant = SW; anchor = DIR_NE; + *out_pixel_x -= 4; *out_pixel_y -= 4; + } + } else if (city_is_directly_below_port) { + if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else { + *out_variant = NE; anchor = DIR_SW; + *out_pixel_x += 4; *out_pixel_y += 4; + } + } else if (city_is_directly_west_of_port) { + if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else { + *out_variant = SE; anchor = DIR_NW; + *out_pixel_x -= 30; *out_pixel_y += 24; + } + } else if (city_is_directly_east_of_port) { + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else { + *out_variant = SW; anchor = DIR_NE; + *out_pixel_x += 30; *out_pixel_y -= 24; + } + } else if (city_is_north_of_port && city_is_west_of_port) { + if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + } else if (city_is_north_of_port && city_is_east_of_port) { + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + } else if (city_is_south_of_port && city_is_east_of_port) { + if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + } else if (city_is_south_of_port && city_is_west_of_port) { + if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + } + + // No ideal direction, pick based on any owner land tiles around port + if (*out_variant == NONE) { + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } + else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } + else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } + else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } + } + + // Same civ doesn't own any adjacent land tiles, pick based on *any* land tiles + if (*out_variant == NONE) { + bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); + bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); + bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); + bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); + bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); + bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); + bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); + bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } + else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } + else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } + else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } + else { *out_variant = SW; anchor = DIR_NE; } // Somehow no land tiles at all? Default to NE + } + } + + Tile * anchor_tile; + int anchor_sheet_index, anchor_sprite_index; + switch (anchor) { + case DIR_N: anchor_tile = get_tile_sprite_indices (tile_x, tile_y - 2, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_NE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_E: anchor_tile = get_tile_sprite_indices (tile_x + 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_SE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_S: anchor_tile = get_tile_sprite_indices (tile_x, tile_y + 2, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_SW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_W: anchor_tile = get_tile_sprite_indices (tile_x - 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_NW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; + default: anchor_sheet_index = -1; anchor_sprite_index = -1; break; + } + + bool anchor_is_hill = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Hills; + bool anchor_is_mountain = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Mountains; + + // Determine general pixel offsets based on direction & anchor + if (*out_variant == SW && anchor == DIR_NE) { *out_pixel_x -= 0; *out_pixel_y += 6; } + else if (*out_variant == SE && anchor == DIR_NW) { *out_pixel_x -= 2; *out_pixel_y += 6; } + else if (*out_variant == NW && anchor == DIR_SE) { *out_pixel_x -= 0; *out_pixel_y -= 2; } + else if (*out_variant == SW && anchor == DIR_N) { *out_pixel_x -= 56; *out_pixel_y -= 26; } + else if (*out_variant == SW && anchor == DIR_E) { *out_pixel_x += 36; *out_pixel_y += 18; } + else if (*out_variant == NE && anchor == DIR_S) { *out_pixel_x += 70; *out_pixel_y += 30; } + else if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 14; } + + // Handle edge cases. Tedious, but looks quite a bit better so worth it + if (! (anchor_is_hill || anchor_is_mountain) && ! direct_diagonal) { + if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 20; } + + // Sheet 0 + if (anchor_sheet_index == 0) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 32; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 32; } + + if ((*out_variant == NE || *out_variant == NW) && anchor == DIR_S && anchor_sprite_index == 26) { *out_pixel_x -= 4; *out_pixel_y += 30; } + else if (*out_variant == NE && anchor == DIR_SW && anchor_sprite_index == 20) { *out_pixel_x -= 2; *out_pixel_y += 4; } + + if (*out_variant == SW && (anchor_sprite_index == 0 || anchor_sprite_index == 4 || anchor_sprite_index == 10 || anchor_sprite_index == 1)) { *out_pixel_x +=2; *out_pixel_y -= 8; } + else if (*out_variant == SW && anchor == DIR_N && (anchor_sprite_index == 6)) { *out_pixel_x -= 6; *out_pixel_y -= 8; } + else if (*out_variant == SE && anchor == DIR_W && (anchor_sprite_index == 18)) { *out_pixel_x += 6; *out_pixel_y += 4; } + else if (*out_variant == NE && anchor == DIR_SW && (anchor_sprite_index == 51)) { *out_pixel_x += 20; *out_pixel_y -= 20; } + else if (*out_variant == SW && anchor == DIR_NE && (anchor_sprite_index == 0)) { *out_pixel_x -= 4; *out_pixel_y += 4; } + else if (*out_variant == NW && anchor == DIR_SE && (anchor_sprite_index == 44)) { *out_pixel_x -= 8; *out_pixel_y -= 12; } + } + // Sheet 1 + else if (anchor_sheet_index == 1) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 10; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 10; } + + if (*out_variant == SW && (anchor_sprite_index == 7 || anchor_sprite_index == 17 || anchor_sprite_index == 16)) { *out_pixel_x +=10; *out_pixel_y -= 8; } + } + // Sheet 3 + else if (anchor_sheet_index == 2) { + if (*out_variant == SW && (anchor_sprite_index == 6)) { *out_pixel_x +=2; *out_pixel_y -= 8; } + } + // Sheet 3 + else if (anchor_sheet_index == 3) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 16; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 16; } + + if (*out_variant == SW && (anchor_sprite_index == 43 || anchor_sprite_index == 40)) { *out_pixel_x +=6; *out_pixel_y -= 12; } + else if (*out_variant == SW && (anchor_sprite_index == 35 || anchor_sprite_index == 39)) { *out_pixel_x +=6; *out_pixel_y -= 12; } + else if (*out_variant == SE && (anchor_sprite_index == 50)) { *out_pixel_x -=6; *out_pixel_y -= 12; } + else if (*out_variant == SE && (anchor_sprite_index == 26)) { *out_pixel_x += 50; *out_pixel_y -= 2; } + } + // Sheet 4 + else if (anchor_sheet_index == 4) { + if (*out_variant == SW && (anchor_sprite_index == 71)) { *out_pixel_x +=2; *out_pixel_y -= 8; } + } + // Sheet 5 + else if (anchor_sheet_index == 5) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 18; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 18; } + + if ((*out_variant == SW || *out_variant == SE) && anchor_sprite_index == 18) { *out_pixel_y -= 10; } + else if (*out_variant == SW && anchor_sprite_index == 73) { *out_pixel_x -=4; *out_pixel_y -= 10; } + else if (*out_variant == NW && anchor == DIR_SE && anchor_sprite_index == 42) { *out_pixel_y -= 8; } + else if ((*out_variant == NW || *out_variant == SW) && anchor_sprite_index == 6) { *out_pixel_x += 12; *out_pixel_y -= 6; } + else if ((*out_variant == SW) && anchor_sprite_index == 16) { *out_pixel_x -=8; *out_pixel_y -= 10; } + } + } + else if (direct_diagonal && *out_variant == SW && anchor == DIR_NE) { *out_pixel_x -=8; *out_pixel_y -= 8; } + else if (direct_diagonal && *out_variant == SE && anchor == DIR_NW) { *out_pixel_x -=8; *out_pixel_y -= 8; } + else if (direct_diagonal && *out_variant == NW && anchor == DIR_SE) { *out_pixel_x +=6; *out_pixel_y += 6; } + else if (direct_diagonal && *out_variant == NE && anchor == DIR_SW) { *out_pixel_x +=6; *out_pixel_y += 6; } +} + +bool +wonder_should_use_alternative_direction_image (int tile_x, int tile_y, int owner_id, struct wonder_district_config const * cfg) +{ + if (owner_id <= 0) + return false; + + // We only care about the nearest same-civ city in the work area around the tile. + // Assumes the base wonder art (img_row/column) faces west and the alt art faces east. + // To "face away" from the nearest city, we pick the alt art when that city lies to the east. + Tile * center = is->current_render_tile; + if ((center == NULL) || (center == p_null_tile)) + return false; + + // If on a river and the wonder allows river alignment, make sure we face the river instead + bool allow_river = wonder_requires_river (cfg); + if (allow_river) { + enum direction river_dir = DIR_ZERO; + if (get_primary_river_direction (center, &river_dir)) { + int dx, dy; + + if (direction_to_offset (river_dir, &dx, &dy)) { + // I'm not completely sure of the logic here, but this seems to match the vanilla behavior + // in terms of having the wonder face the general direction of the river flow + if (dx == 2) + return false; + + return dx > 0; + } + } + } + + // Else face away from the nearest same-civ city + Map * map = &p_bic_data->Map; + int best_dist = INT_MAX; + int best_dx = 0; + int city_dx = 0; + int city_dy = 0; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + City * city = wai.city; + if ((city == NULL) || (city->Body.CivID != owner_id)) + continue; + + int dx = city->Body.X - tile_x; + int dy = city->Body.Y - tile_y; + + if (map->Flags & 1) { + int half_width = map->Width >> 1; + if (dx > half_width) + dx -= map->Width; + else if (dx < -half_width) + dx += map->Width; + } + if (map->Flags & 2) { + int half_height = map->Height >> 1; + if (dy > half_height) + dy -= map->Height; + else if (dy < -half_height) + dy += map->Height; + } + + int dist = int_abs (dx) + int_abs (dy); + // Pick the closest city; if tied, favor the one with a clearer east/west offset so we know which way to face. + if ((dist < best_dist) || + ((dist == best_dist) && ((int_abs (dx) < int_abs (best_dx)) || (best_dx == 0)))) { + best_dist = dist; + best_dx = dx; + city_dx = city->Body.X; + city_dy = city->Body.Y; + } + } + + bool city_is_directly_above_port = city_dx == tile_x && city_dy == tile_y - 2; + bool city_is_directly_below_port = city_dx == tile_x && city_dy == tile_y + 2; + + if (city_is_directly_above_port || city_is_directly_below_port) { + bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); + bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); + bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); + + if (northeast_tile_is_land || east_tile_is_land || southeast_tile_is_land) + return true; + } + + if ((best_dist == INT_MAX) || (best_dx == 0)) + return false; + + return best_dx > 0; +} + +void +draw_district_on_map_or_canvas(Sprite * sprite, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (is->tile_info_open) { + PCX_Image * canvas = (PCX_Image *)map_renderer; + patch_Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, NULL); + return; + } + + patch_Sprite_draw_on_map (sprite, __, map_renderer, pixel_x, pixel_y, 1, 1, (p_bic_data->is_zoomed_out != false) + 1, 0); +} + +int +get_energy_grid_image_index (int tile_x, int tile_y) +{ + struct district_infos * info = &is->district_infos[ENERGY_GRID_DISTRICT_ID]; + for (int i = 0; i < info->dependent_building_count; i++) { + // Zero is "no building"; Buildings start from index one + int column_index = i + 1; + int building_id = info->dependent_building_ids[i]; + if (tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) + return column_index; + } + + return 0; +} + +int +get_bridge_image_index (Tile * tile, int tile_x, int tile_y) +{ + int SW_NE = 0; + int NW_SE = 1; + int N_S = 2; + int W_E = 3; + + if ((tile->vtable->m42_Get_Overlays (tile, __, 0) & TILE_FLAG_RAILROAD) != 0) { + SW_NE += 4; + NW_SE += 4; + N_S += 4; + W_E += 4; + } + + bool bridge_n = tile_has_district_at (tile_x, tile_y - 2, BRIDGE_DISTRICT_ID); + bool bridge_s = tile_has_district_at (tile_x, tile_y + 2, BRIDGE_DISTRICT_ID); + bool bridge_w = tile_has_district_at (tile_x - 2, tile_y, BRIDGE_DISTRICT_ID); + bool bridge_e = tile_has_district_at (tile_x + 2, tile_y, BRIDGE_DISTRICT_ID); + bool bridge_ne = tile_has_district_at (tile_x + 1, tile_y - 1, BRIDGE_DISTRICT_ID); + bool bridge_nw = tile_has_district_at (tile_x - 1, tile_y - 1, BRIDGE_DISTRICT_ID); + bool bridge_se = tile_has_district_at (tile_x + 1, tile_y + 1, BRIDGE_DISTRICT_ID); + bool bridge_sw = tile_has_district_at (tile_x - 1, tile_y + 1, BRIDGE_DISTRICT_ID); + + if (bridge_n || bridge_s || bridge_w || bridge_e || bridge_ne || bridge_nw || bridge_se || bridge_sw) { + int ns_count = (bridge_n ? 1 : 0) + (bridge_s ? 1 : 0); + int we_count = (bridge_w ? 1 : 0) + (bridge_e ? 1 : 0); + int swne_count = (bridge_sw ? 1 : 0) + (bridge_ne ? 1 : 0); + int nwse_count = (bridge_nw ? 1 : 0) + (bridge_se ? 1 : 0); + + if (swne_count == 2) return SW_NE; + if (nwse_count == 2) return NW_SE; + if (ns_count == 2) return N_S; + if (we_count == 2) return W_E; + + if (bridge_ne || bridge_sw) return SW_NE; + if (bridge_nw || bridge_se) return NW_SE; + if (bridge_n || bridge_s) return N_S; + if (bridge_w || bridge_e) return W_E; + } + + int owner_id = tile->Territory_OwnerID; + bool north_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); + bool south_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); + bool west_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); + bool east_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); + bool ne_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); + bool nw_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); + bool se_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); + bool sw_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); + + bool north_link = north_land || bridge_n; + bool south_link = south_land || bridge_s; + bool west_link = west_land || bridge_w; + bool east_link = east_land || bridge_e; + bool ne_link = ne_land || bridge_ne; + bool nw_link = nw_land || bridge_nw; + bool se_link = se_land || bridge_se; + bool sw_link = sw_land || bridge_sw; + + if (sw_link && ne_link) return SW_NE; + if (nw_link && se_link) return NW_SE; + if (north_link && south_link) return N_S; + if (west_link && east_link) return W_E; + + if (ne_link || sw_link) return SW_NE; + if (nw_link || se_link) return NW_SE; + if (north_link || south_link) return N_S; + if (west_link || east_link) return W_E; + + return SW_NE; +} + +void +get_bridge_directions (Tile * tile, int tile_x, int tile_y, int * out_dir1, int * out_dir2) +{ + int dir1 = -1; + int dir2 = -1; + int index = get_bridge_image_index (tile, tile_x, tile_y); + + switch (index) { + case 0: dir1 = DIR_SW; dir2 = DIR_NE; break; + case 1: dir1 = DIR_NW; dir2 = DIR_SE; break; + case 2: dir1 = DIR_N; dir2 = DIR_S; break; + case 3: dir1 = DIR_W; dir2 = DIR_E; break; + default: break; + } + + *out_dir1 = dir1; + *out_dir2 = dir2; +} + +void +get_canal_directions (Tile * tile, int tile_x, int tile_y, bool out_water_dirs[9], int * out_dir1, int * out_dir2) +{ + bool canal_at_n = tile_has_district_at (tile_x, tile_y - 2, CANAL_DISTRICT_ID); + bool canal_at_s = tile_has_district_at (tile_x, tile_y + 2, CANAL_DISTRICT_ID); + bool canal_at_w = tile_has_district_at (tile_x - 2, tile_y, CANAL_DISTRICT_ID); + bool canal_at_e = tile_has_district_at (tile_x + 2, tile_y, CANAL_DISTRICT_ID); + bool canal_at_ne = tile_has_district_at (tile_x + 1, tile_y - 1, CANAL_DISTRICT_ID); + bool canal_at_nw = tile_has_district_at (tile_x - 1, tile_y - 1, CANAL_DISTRICT_ID); + bool canal_at_se = tile_has_district_at (tile_x + 1, tile_y + 1, CANAL_DISTRICT_ID); + bool canal_at_sw = tile_has_district_at (tile_x - 1, tile_y + 1, CANAL_DISTRICT_ID); + bool water_n = tile_is_water (tile_x, tile_y - 2); + bool water_s = tile_is_water (tile_x, tile_y + 2); + bool water_w = tile_is_water (tile_x - 2, tile_y); + bool water_e = tile_is_water (tile_x + 2, tile_y); + bool water_ne = tile_is_water (tile_x + 1, tile_y - 1); + bool water_nw = tile_is_water (tile_x - 1, tile_y - 1); + bool water_se = tile_is_water (tile_x + 1, tile_y + 1); + bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); + bool canal_or_water_n = canal_at_n || water_n; + bool canal_or_water_s = canal_at_s || water_s; + bool canal_or_water_w = canal_at_w || water_w; + bool canal_or_water_e = canal_at_e || water_e; + bool canal_or_water_ne = canal_at_ne || water_ne; + bool canal_or_water_nw = canal_at_nw || water_nw; + bool canal_or_water_se = canal_at_se || water_se; + bool canal_or_water_sw = canal_at_sw || water_sw; + + bool canal_dirs[9] = { + false, canal_at_ne, canal_at_e, canal_at_se, + canal_at_s, canal_at_sw, canal_at_w, canal_at_nw, canal_at_n + }; + bool water_dirs[9] = { + false, water_ne, water_e, water_se, + water_s, water_sw, water_w, water_nw, water_n + }; + bool available_dirs[9] = { + false, canal_or_water_ne, canal_or_water_e, canal_or_water_se, + canal_or_water_s, canal_or_water_sw, canal_or_water_w, canal_or_water_nw, canal_or_water_n + }; + + // Avoid acute angles (adjacent directions) that look cramped. + int disallowed_pairs[][2] = { + { DIR_N, DIR_NE }, { DIR_NE, DIR_E }, { DIR_E, DIR_SE }, { DIR_SE, DIR_S }, + { DIR_S, DIR_SW }, { DIR_SW, DIR_W }, { DIR_W, DIR_NW }, { DIR_NW, DIR_N } + }; + int disallowed_pair_count = sizeof(disallowed_pairs) / sizeof(disallowed_pairs[0]); + int pref_dirs[8] = { DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_N, DIR_E, DIR_S, DIR_W }; + + int dir1 = -1; + int dir2 = -1; + + bool has_canal_dir = canal_dirs[DIR_N] || canal_dirs[DIR_NE] || canal_dirs[DIR_E] || canal_dirs[DIR_SE] || + canal_dirs[DIR_S] || canal_dirs[DIR_SW] || canal_dirs[DIR_W] || canal_dirs[DIR_NW]; + + if (has_canal_dir) { + for (int i = 0; i < 8 && dir1 == -1; i++) { + int d = pref_dirs[i]; + if (canal_dirs[d]) + dir1 = d; + } + } else { + for (int i = 0; i < 8 && dir1 == -1; i++) { + int d = pref_dirs[i]; + if (available_dirs[d]) + dir1 = d; + } + } + + if (dir1 >= 0) { + for (int pass = 0; pass < 2 && dir2 == -1; pass++) { + bool * dirs = (pass == 0) ? canal_dirs : available_dirs; + for (int i = 0; i < 8; i++) { + int d = pref_dirs[i]; + if (d == dir1 || ! dirs[d]) + continue; + bool pair_is_too_close = false; + for (int k = 0; k < disallowed_pair_count; k++) { + if ((dir1 == disallowed_pairs[k][0] && d == disallowed_pairs[k][1]) || + (dir1 == disallowed_pairs[k][1] && d == disallowed_pairs[k][0])) { + pair_is_too_close = true; + break; + } + } + if (pair_is_too_close) + continue; + dir2 = d; + break; + } + } + } + + int draw_dir1 = dir1; + int draw_dir2 = dir2; + if ((draw_dir1 >= 0) && (draw_dir2 >= 0)) { + int weight1 = 0; + int weight2 = 0; + + if (draw_dir1 == DIR_S) weight1 = 2; + else if ((draw_dir1 == DIR_SE) || (draw_dir1 == DIR_SW)) weight1 = 1; + else if ((draw_dir1 == DIR_NE) || (draw_dir1 == DIR_NW) || (draw_dir1 == DIR_N)) weight1 = -1; + + if (draw_dir2 == DIR_S) weight2 = 2; + else if ((draw_dir2 == DIR_SE) || (draw_dir2 == DIR_SW)) weight2 = 1; + else if ((draw_dir2 == DIR_NE) || (draw_dir2 == DIR_NW) || (draw_dir2 == DIR_N)) weight2 = -1; + + if (weight1 > weight2) { + int tmp = draw_dir1; + draw_dir1 = draw_dir2; + draw_dir2 = tmp; + } + } + + // Manual overrides - overall algorithm works pretty well, but handle corner cases + if (!has_canal_dir && water_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir1 = DIR_NE; draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && water_dirs[DIR_N] && water_dirs[DIR_NE]) { draw_dir1 = DIR_N; draw_dir2 = DIR_S; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_SE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_NE] && water_dirs[DIR_N]) { draw_dir1 = DIR_N; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && water_dirs[DIR_S]) { draw_dir2 = DIR_S; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && canal_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && canal_dirs[DIR_NE] && water_dirs[DIR_S]) { draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NW && draw_dir2 == DIR_NE && canal_dirs[DIR_NW] && water_dirs[DIR_SE]) { draw_dir2 = DIR_SE; } + if (draw_dir1 == DIR_NW && draw_dir2 == DIR_S && canal_dirs[DIR_NW] && water_dirs[DIR_S]) { draw_dir2 = DIR_SE; } + + *out_dir1 = draw_dir1; + *out_dir2 = draw_dir2; + for (int i = 0; i < 9; i++) + out_water_dirs[i] = water_dirs[i]; +} + +void +draw_canal_on_map_or_canvas(Sprite * sprite, int tile_x, int tile_y, int dir, bool water_dirs[9], Map_Renderer * map_renderer, int draw_x, int draw_y) +{ + int y_offset = 9; + int x_offset = y_offset * 2; + + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y); + + // In certain cases, add an additional draw if adjacent to water so that the canal appears to extend far enough + if (dir == DIR_N && water_dirs[DIR_N]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y - y_offset); + else if (dir == DIR_NE && water_dirs[DIR_NE]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y - y_offset); + else if (dir == DIR_E && water_dirs[DIR_E]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y); + else if (dir == DIR_SE && water_dirs[DIR_SE]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y + y_offset); + else if (dir == DIR_S && water_dirs[DIR_S]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y + y_offset); + else if (dir == DIR_SW && water_dirs[DIR_SW]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y + y_offset); + else if (dir == DIR_W && water_dirs[DIR_W]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y); + else if (dir == DIR_NW && water_dirs[DIR_NW]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y - y_offset); +} + +void +draw_canal_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int era) +{ + struct district_config const * cfg = &is->district_configs[CANAL_DISTRICT_ID]; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + int offset_x = pixel_x + cfg->x_offset; + int offset_y = pixel_y + cfg->y_offset; + int dir1_draw_x = offset_x - ((sprite_width - 128) / 2); + int dir1_draw_y = offset_y - (sprite_height - 64); + int dir2_draw_x = dir1_draw_x; + int dir2_draw_y = dir1_draw_y; + + int draw_dir1 = -1; + int draw_dir2 = -1; + bool water_dirs[9] = { false, false, false, false, false, false, false, false, false }; + get_canal_directions (tile, tile_x, tile_y, water_dirs, &draw_dir1, &draw_dir2); + + // Set offsets based on directions for (literal) edge cases + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S) { dir1_draw_x += 7; dir1_draw_y -= 2; } + else if (draw_dir1 == DIR_N && draw_dir2 == DIR_W) { dir2_draw_x -= 12; } + else if (draw_dir1 == DIR_N && draw_dir2 == DIR_SE) { dir2_draw_x += 4; } + + if (draw_dir1 >= 0) { + Sprite * sprite1 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir1]; + draw_canal_on_map_or_canvas(sprite1, tile_x, tile_y, draw_dir1, water_dirs, map_renderer, dir1_draw_x, dir1_draw_y); + } + + if (draw_dir2 >= 0) { + Sprite * sprite2 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir2]; + draw_canal_on_map_or_canvas(sprite2, tile_x, tile_y, draw_dir2, water_dirs, map_renderer, dir2_draw_x, dir2_draw_y); + } +} + +void +draw_great_wall_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + bool wall_nw = tile_has_district_at (tile_x - 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); + bool wall_ne = tile_has_district_at (tile_x + 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); + bool wall_se = tile_has_district_at (tile_x + 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); + bool wall_sw = tile_has_district_at (tile_x - 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); + bool wall_s = tile_has_district_at (tile_x, tile_y + 2, GREAT_WALL_DISTRICT_ID); + bool wall_n = tile_has_district_at (tile_x, tile_y - 2, GREAT_WALL_DISTRICT_ID); + + bool water_ne = tile_is_water (tile_x - 1, tile_y - 1); + bool water_nw = tile_is_water (tile_x + 1, tile_y - 1); + bool water_w = tile_is_water (tile_x - 2, tile_y); + bool water_n = tile_is_water (tile_x, tile_y + 2); + bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); + bool water_se = tile_is_water (tile_x + 1, tile_y + 1); + + Sprite * sprites = is->district_img_sets[GREAT_WALL_DISTRICT_ID].imgs[0][0]; + Sprite * base = &sprites[0]; + + // Rotate around clockwise NW -> SW to get the perspective right + if (wall_nw) draw_district_on_map_or_canvas(&sprites[DIR_NW], map_renderer, pixel_x, pixel_y); + if (wall_ne) draw_district_on_map_or_canvas(&sprites[DIR_NE], map_renderer, pixel_x, pixel_y); + + // Base pillar + draw_district_on_map_or_canvas(base, map_renderer, pixel_x, pixel_y); + + if (wall_sw) draw_district_on_map_or_canvas(&sprites[DIR_SW], map_renderer, pixel_x, pixel_y); + if (wall_se) draw_district_on_map_or_canvas(&sprites[DIR_SE], map_renderer, pixel_x, pixel_y); +} + +void +draw_district_generated_resource_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, + int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) +{ + int base_resource = Tile_get_resource_visible_to (tile, __, visible_to_civ_id); + int district_resource = -1; + + if (inst->state == DS_COMPLETED) { + int district_id = inst->district_id; + if ((district_id >= 0) && (district_id < is->district_count)) { + struct district_config * cfg = &is->district_configs[district_id]; + if (cfg->generated_resource_id >= 0) { + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_id >= 0) && ((visible_to_civ_id < 0) || (owner_id == visible_to_civ_id))) { + int res_id = cfg->generated_resource_id; + if (district_generates_resource_for_civ (tile, inst, cfg, owner_id)) + district_resource = res_id; + } + } + } + } + + if (district_resource < 0) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; + int offset = tile_width >> 2; + int left_x = pixel_x - (offset >> 1); + int right_x = pixel_x + (offset >> 1); + + int icon_id = p_bic_data->ResourceTypes[district_resource].IconID; + Sprite * sprite = NULL; + Map_Renderer * resource_renderer = is->tile_info_open ? &p_bic_data->Map.Renderer : map_renderer; + int resource_sprite_count = 0; + if ((resource_renderer != NULL) && (resource_renderer->Resources != NULL)) + // The renderer allocates Resources as a counted heap array: the int stored just before the + // first Sprite is the number of entries loaded from resources.pcx. + resource_sprite_count = ((int *)resource_renderer->Resources)[-1]; + if ((icon_id < 0) || (icon_id >= resource_sprite_count)) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + sprite = &resource_renderer->Resources[icon_id]; + if (sprite == NULL) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + if (base_resource >= 0) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, left_x, pixel_y); + } + + int tile_height = tile_width >> 1; + int sprite_width = sprite->Width; + int sprite_height = sprite->Height; + if (sprite_width <= 0) sprite_width = sprite->Width3; + if (sprite_height <= 0) sprite_height = sprite->Height3; + int center_x = (tile_width - sprite_width) >> 1; + int center_y = (tile_height - sprite_height) >> 1; + int draw_x = (base_resource >= 0) ? right_x : pixel_x; + draw_x += center_x; + int draw_y = pixel_y + center_y; + if (is->tile_info_open) { + PCX_Image * canvas = (PCX_Image *)map_renderer; + patch_Sprite_draw (sprite, __, canvas, draw_x, draw_y, NULL); + } else { + int draw_scale = (p_bic_data->is_zoomed_out != false) + 1; + patch_Sprite_draw_on_map (sprite, __, map_renderer, draw_x, draw_y, 1, 1, draw_scale, 0); + } +} + +int +count_completed_buildings_in_district_radius (int tile_x, int tile_y, int district_id) +{ + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos * district_info = &is->district_infos[district_id]; + int completed_count = 0; + for (int i = 0; i < district_info->dependent_building_count; i++) { + int building_id = district_info->dependent_building_ids[i]; + if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) + completed_count++; + } + return completed_count; +} + +void +draw_district_on_map_or_canvas_by_buildings (Sprite * base_sprite, Map_Renderer * map_renderer, int district_id, int variant, int era, int tile_x, int tile_y, int draw_x, int draw_y) +{ + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos * district_info = &is->district_infos[district_id]; + + draw_district_on_map_or_canvas(base_sprite, map_renderer, draw_x, draw_y); + + for (int i = 0; i < district_info->dependent_building_count; i++) { + // Zero is "base texture"; Actual building column art starts from index one + int column_index = i + 1; + int building_id = district_info->dependent_building_ids[i]; + if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) { + Sprite * district_sprite = &is->district_img_sets[district_id].imgs[variant][era][column_index]; + draw_district_on_map_or_canvas(district_sprite, map_renderer, draw_x, draw_y); + } + } +} + +void +draw_district_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) +{ + int district_id = inst->district_id; + if (is->dc_img_state == IS_UNINITED) + init_district_images (); + + if (is->dc_img_state != IS_OK) + return; + + // Natural Wonder + if (district_id == NATURAL_WONDER_DISTRICT_ID) { + if (! is->current_config.enable_natural_wonders) + return; + + int natural_id = inst->natural_wonder_info.natural_wonder_id; + if ((natural_id >= 0) && (natural_id < is->natural_wonder_count)) { + Sprite * nsprite = &is->natural_wonder_img_sets[natural_id].img; + int y_offset = 88 - 64; // Height of wonder img minus height of tile + int draw_y = pixel_y - y_offset; + + draw_district_on_map_or_canvas(nsprite, map_renderer, pixel_x, draw_y); + } + return; + } + + // Districts + if (is->current_config.enable_districts) { + if (district_id < 0 || district_id >= is->district_count) return; + bool completed = district_is_complete (tile, district_id); + + if (! completed) + return; + + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos * district_info = &is->district_infos[district_id]; + int territory_owner_id = tile->Territory_OwnerID; + int variant = 0; + int era = 0; + int culture = 0; + int buildings = 0; + int draw_pixel_x = pixel_x; + int draw_pixel_y = pixel_y; + enum direction river_dir = DIR_ZERO; + + // If in a territory, use owner's culture/era + if (territory_owner_id > 0) { + Leader * leader = &leaders[territory_owner_id]; + culture = p_bic_data->Races[leader->RaceID].CultureGroupID; + if (cfg->vary_img_by_culture) + variant = culture; + if (cfg->vary_img_by_era) + era = leader->Era; + if (cfg->align_to_coast) + align_variant_and_pixel_offsets_with_coastline (tile, &variant, &draw_pixel_x, &draw_pixel_y); + + // Else render abandoned if not a Wonder, Natural Wonder, Bridge, or Canal + } else if (district_id != WONDER_DISTRICT_ID && district_id != NATURAL_WONDER_DISTRICT_ID && district_id != BRIDGE_DISTRICT_ID && district_id != CANAL_DISTRICT_ID) { + Sprite * abandoned_sprite = &is->abandoned_district_img; + if (tile->vtable->m35_Check_Is_Water (tile) && is->abandoned_maritime_district_img.vtable != NULL) + abandoned_sprite = &is->abandoned_maritime_district_img; + if (abandoned_sprite->vtable != NULL) { + draw_district_on_map_or_canvas(abandoned_sprite, map_renderer, draw_pixel_x + cfg->x_offset, draw_pixel_y + cfg->y_offset); + } + return; + } + + // If out of a territory (and not abandoned) but builder is known, use builder's era & culture + if (territory_owner_id < 0 && inst->built_by_civ_id >= 0) { + Leader * builder = &leaders[inst->built_by_civ_id]; + culture = p_bic_data->Races[builder->RaceID].CultureGroupID; + if (cfg->vary_img_by_culture) + variant = culture; + if (cfg->vary_img_by_era) + era = builder->Era; + } + + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + int offset_x = draw_pixel_x + cfg->x_offset; + int offset_y = draw_pixel_y + cfg->y_offset; + int draw_x = offset_x - ((sprite_width - 128) / 2); + int draw_y = offset_y - (sprite_height - 64); + Sprite (*sprites)[MAX_DISTRICT_ERA_COUNT][MAX_DISTRICT_COLUMN_COUNT] = is->district_img_sets[district_id].imgs; + + // Render + switch (district_id) { + case WONDER_DISTRICT_ID: + { + if (! is->current_config.enable_wonder_districts) + return; + + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info == NULL) + return; + + int construct_windex = -1; + Sprite * wsprite = NULL; + + struct wonder_district_config * wcfg = NULL; + struct wonder_district_image_set * set = NULL; + + // Completed + if (info->state == WDS_COMPLETED) { + int windex = info->wonder_index; + if ((windex < 0) || (windex >= is->wonder_district_count)) + return; + wcfg = &is->wonder_district_configs[windex]; + set = &is->wonder_district_img_sets[windex]; + // Under construction + } else if (wonder_district_tile_under_construction (tile, tile_x, tile_y, &construct_windex) && (construct_windex >= 0)) { + if (construct_windex >= is->wonder_district_count) + return; + wcfg = &is->wonder_district_configs[construct_windex]; + set = &is->wonder_district_img_sets[construct_windex]; + // Unused + } else { + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + + if (wonder_requires_river(wcfg)) + align_district_with_river (tile, &draw_pixel_x, &draw_pixel_y, &river_dir); + + int wonder_width = (wcfg->custom_width > 0) ? wcfg->custom_width : 128; + int wonder_height = (wcfg->custom_height > 0) ? wcfg->custom_height : 64; + int wonder_offset_x = draw_pixel_x + cfg->x_offset; + int wonder_offset_y = draw_pixel_y + cfg->y_offset; + int wonder_draw_x = wonder_offset_x - ((wonder_width - 128) / 2); + int wonder_draw_y = wonder_offset_y - (wonder_height - 64); + + bool use_alt_dir = wcfg->enable_img_alt_dir && wonder_should_use_alternative_direction_image (tile_x, tile_y, territory_owner_id, wcfg); + if (info->state == WDS_COMPLETED) + wsprite = (use_alt_dir && (set->alt_dir_img.vtable != NULL)) ? &set->alt_dir_img : &set->img; + else + wsprite = (use_alt_dir && (set->alt_dir_construct_img.vtable != NULL)) ? &set->alt_dir_construct_img : &set->construct_img; + + draw_district_on_map_or_canvas(wsprite, map_renderer, wonder_draw_x, wonder_draw_y); + return; + } + case NEIGHBORHOOD_DISTRICT_ID: + { + if (! is->current_config.enable_neighborhood_districts) + return; + + unsigned v = (unsigned)tile_x * 0x9E3779B1u + (unsigned)tile_y * 0x85EBCA6Bu; + v ^= v >> 16; + v *= 0x7FEB352Du; + v ^= v >> 15; + v *= 0x846CA68Bu; + v ^= v >> 16; + buildings = clamp(0, 3, (int)(v & 3u)); /* final 0..3 */ + variant = culture; + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + case DISTRIBUTION_HUB_DISTRICT_ID: + if (! is->current_config.enable_distribution_hub_districts) + return; + + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + case ENERGY_GRID_DISTRICT_ID: + { + if (! is->current_config.enable_energy_grid_districts) + return; + + buildings = get_energy_grid_image_index (tile_x, tile_y); + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + case BRIDGE_DISTRICT_ID: + { + if (! is->current_config.enable_bridge_districts) + return; + + buildings = get_bridge_image_index (tile, tile_x, tile_y); + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + case CANAL_DISTRICT_ID: + { + if (! is->current_config.enable_canal_districts) + return; + + draw_canal_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y, era); + return; + } + case GREAT_WALL_DISTRICT_ID: + { + if (! is->current_config.enable_great_wall_districts) + return; + + draw_great_wall_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + default: + { + // Draw by counting number of completed buildings in radius + if (cfg->render_strategy == DRS_BY_COUNT) { + buildings = count_completed_buildings_in_district_radius (tile_x, tile_y, district_id); + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + // Draw by checking each building individually and layering images + else if (cfg->render_strategy == DRS_BY_BUILDING) { + Sprite * base_sprite = &is->district_img_sets[district_id].imgs[variant][era][0]; + draw_district_on_map_or_canvas_by_buildings(base_sprite, map_renderer, district_id, variant, era, tile_x, tile_y, draw_x, draw_y); + return; + } + } + } + } + + Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Map_Renderer_m12_Draw_Tile_Buildings(Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { + Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + Tile * tile = is->current_render_tile; + if (is->tile_info_open) + tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if ((tile == NULL) || (tile == p_null_tile)) + return; + + struct district_instance * inst = is->current_render_tile_district; + if (is->tile_info_open) + inst = get_district_instance (tile); + if (inst == NULL) { + Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + // Draw resources first if needed + if (is->district_configs[inst->district_id].draw_over_resources) + draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); + + draw_district_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); +} + +void __fastcall +patch_Map_Renderer_m09_Draw_Tile_Resources (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (! is->current_config.enable_districts) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + Tile * tile = is->current_render_tile; + if (is->tile_info_open) + tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if ((tile == NULL) || (tile == p_null_tile)) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + struct district_instance * inst = is->current_render_tile_district; + if (is->tile_info_open) + inst = get_district_instance (tile); + if (inst == NULL) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + // Resources that should be drawn below district are already drawn, skip in that case + if (is->district_configs[inst->district_id].draw_over_resources) + return; + + draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); +} + +void __fastcall +patch_Map_Renderer_m11_Draw_Tile_Irrigation (Map_Renderer *this, int edx, int visible_to_civ, int tile_x, int tile_y, int param_4, int param_5, int param_6) +{ + if (! is->current_config.enable_districts) { + Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); + return; + } + + struct district_instance * inst = is->current_render_tile_district; + if (inst == NULL) { + Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); + return; + } + + // If it has a completed district that serves as pseudo-irrigation source, suppress drawing irrigation + if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (is->current_render_tile, inst->district_id)) + return; + + Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); +} + +bool __fastcall +patch_Tile_has_city_or_district (Tile * this) +{ + bool has_city = Tile_has_city (this); + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + return has_city || (get_district_instance (this) != NULL); + } + return has_city; +} + +int __fastcall +patch_Tile_check_water_for_navigator_cell_coloring (Tile * this) +{ + if (! is->current_config.show_territory_colors_on_water_tiles_in_minimap) + return this->vtable->m35_Check_Is_Water (this); + else + return 0; +} + +bool +is_skippable_popup (char * text_key) +{ + char * skippable_keys[] = {"SUMMARY_END_GOLDEN_AGE", "SUMMARY_END_SCIENCE_AGE", "SUMMARY_NEW_SMALL_WONDER", // unimportant domestic things + "WONDERPRODUCE", // another civ completed a wonder + "MAKEPEACE", "MUTUALPROTECTIONPACT", "MILITARYALLIANCE", "SUMMARY_DECLARE_WAR", // diplo events not involving the player + "TRADEEMBARGOENDS", // embargo vs player ends + "SUMMARY_CIV_DESTROYED_BY_CIV", "SUMMARY_CIV_DESTROYED", // foreign civs destroyed not by player + "LOSTGOOD", // 'We lost our supply of ...!' + "TRADEEMBARGO", "MILITARYALLIANCEWARONUS", "MILITARYALLIANCEAGAINSTUS", // trade embargo or alliance vs player + "SUMMARY_TRAVELERS_REPORT"}; // another civs starts a wonder + + for (int n = 0; n < ARRAY_LEN (skippable_keys); n++) + if (strcmp (text_key, skippable_keys[n]) == 0) + return true; + return false; +} + +int __fastcall +patch_PopupForm_impl_begin_showing_popup (PopupForm * this) +{ + if (is_online_game () || + (! is->current_config.convert_some_popups_into_online_mp_messages) || + (! is_skippable_popup (this->text_key))) + return PopupForm_impl_begin_showing_popup (this); + + else { + unsigned saved_prefs = *p_preferences; + int saved_flags = this->field_1BF0[0xE4]; + + *p_preferences |= P_SHOW_FEWER_MP_POPUPS; + this->field_1BF0[0xE4] |= 0x4000; + int tr = PopupForm_impl_begin_showing_popup (this); + + *(bool *)(p_main_screen_form->animator.field_18E4 + 10) = true; // Set what must be a dirty flag + Animator_update (&p_main_screen_form->animator); // Make sure message appears + + this->field_1BF0[0xE4] = saved_flags; + *p_preferences = saved_prefs; + + return tr; + } +} + +bool __stdcall +patch_is_online_game_for_show_popup () +{ + return is->current_config.convert_some_popups_into_online_mp_messages ? true : is_online_game (); +} + +bool +ai_move_district_worker (Unit * worker, struct district_worker_record * rec) +{ + if ((worker == NULL) || (rec == NULL)) + return false; + + char ss[200]; + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d assigned to build district\n", worker->Body.ID); + (*p_OutputDebugStringA) (ss); + + // Check the original request city made for district + struct pending_district_request * req = rec->pending_req; + if ((req == NULL) || + (req->assigned_worker_id != worker->Body.ID) || + (req->target_x < 0) || (req->target_y < 0)) + return false; + + int district_id = req->district_id; + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d moving to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); + (*p_OutputDebugStringA) (ss); + + City * request_city = get_city_ptr (req->city_id); + if (request_city == NULL) { + clear_tracked_worker_assignment (rec); + remove_pending_district_request (req); + return false; + } + req->city = request_city; + struct district_config * cfg = &is->district_configs[district_id]; + Tile * target_tile = tile_at (req->target_x, req->target_y); + if ((target_tile == NULL) || (target_tile == p_null_tile) || + (target_tile->vtable->m38_Get_Territory_OwnerID (target_tile) != worker->Body.CivID) || + (! city_radius_contains_tile (request_city, req->target_x, req->target_y))) { + clear_city_district_request (request_city, req->district_id); + return false; + } + + // If the worker has arrived + if ((worker->Body.X == req->target_x) && (worker->Body.Y == req->target_y)) { + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d arrived at (%d,%d) to build district\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + Tile * tile = tile_at (worker->Body.X, worker->Body.Y); + struct district_instance * inst = get_district_instance (tile); + bool do_replacement = false; + + // If there is a completed district here already + if ((inst != NULL) && district_is_complete (tile, inst->district_id)) { + int existing_district_id = inst->district_id; + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d found existing district ID %d at (%d,%d)\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + if (existing_district_id == req->district_id) { + clear_city_district_request (request_city, req->district_id); + clear_tracked_worker_assignment (rec); + return false; + } + + // Allow replacement of unused wonder districts + if (existing_district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = &inst->wonder_info; + if (info->state == WDS_UNUSED) + do_replacement = true; + } else if (district_is_obsolete_for_civ (existing_district_id, request_city->Body.CivID)) { + do_replacement = true; + } else { + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d cannot replace existing district ID %d at (%d,%d), cancelling request\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + clear_city_district_request (request_city, req->district_id); + return false; + } + + if (!do_replacement) { + return false; // Nothing left to do here + } + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for duplicate districts near city at (%d,%d)\n", request_city->Body.X, request_city->Body.Y); + (*p_OutputDebugStringA) (ss); + + // One final check: do we still need the district? Check for any dupes nearby + if (req->district_id != DISTRIBUTION_HUB_DISTRICT_ID && req->district_id != NEIGHBORHOOD_DISTRICT_ID) { + FOR_DISTRICTS_AROUND (wai, request_city->Body.X, request_city->Body.Y, false) { + if (wai.tile == tile) + continue; + + if (wai.district_inst->district_id == req->district_id) { + snprintf (ss, sizeof ss, "ai_move_district_worker: Found duplicate district ID %d near city at (%d,%d), cancelling request\n", req->district_id, request_city->Body.X, request_city->Body.Y); + (*p_OutputDebugStringA) (ss); + clear_city_district_request (request_city, req->district_id); + return false; + } + } + } + + // Need to make sure distro hubs get roads. If this will be one, build the road first to be sure + if (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID) { + bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); + if (! has_road && ! cfg->auto_add_road) { + Unit_set_state(worker, __, UnitState_Build_Road); + worker->Body.Job_ID = WJ_Build_Road; + return true; + } + } + + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); + bool district_buildable_here = district_is_buildable_on_tile (&is->district_configs[req->district_id], tile); + + // Remove any existing improvements + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); + if (do_replacement) { + remove_district_instance (tile); + handle_district_removed (tile, req->district_id, worker->Body.X, worker->Body.Y, false); + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for craters or pollution at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + if (tile->vtable->m21_Check_Crates (tile, __, 0) || tile->vtable->m20_Check_Pollution (tile, __, 0)) { + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d clearing craters or pollution at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + Unit_set_state(worker, __, UnitState_Clear_Damage); + worker->Body.Job_ID = WJ_Clean_Pollution; + return true; + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for forest or wetlands at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + // Clear any forest/wetlands + if (! district_buildable_here && base_type == SQ_Forest) { + Unit_set_state(worker, __, UnitState_Clear_Forest); + worker->Body.Job_ID = WJ_Clean_Forest; + return true; + } else if (! district_buildable_here && ((base_type == SQ_Jungle) || (base_type == SQ_Swamp))) { + Unit_set_state(worker, __, UnitState_Clear_Wetlands); + worker->Body.Job_ID = WJ_Clear_Swamp; + return true; + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d starting construction of district at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + // Clear any existing improvements (irrigation and mines) + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); + + // Start construction of district + inst = ensure_district_instance (tile, req->district_id, req->target_x, req->target_y); + inst->built_by_civ_id = worker->Body.CivID; + Unit_set_state(worker, __, UnitState_Build_Mines); + worker->Body.Job_ID = WJ_Build_Mines; // Build district + return true; + + // Else if the worker needs to be sent + } else { + if ((worker->Body.UnitState != UnitState_Go_To) || + (worker->Body.path_dest_x != req->target_x) || + (worker->Body.path_dest_y != req->target_y)) { + int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, + worker->Body.X, worker->Body.Y, req->target_x, req->target_y, + worker, worker->Body.CivID, 0x41, NULL); + if (path_result > 0) { + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d path set to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); + (*p_OutputDebugStringA) (ss); + + Unit_set_escortee (worker, __, -1); + Unit_set_state (worker, __, UnitState_Go_To); + worker->Body.path_dest_x = req->target_x; + worker->Body.path_dest_y = req->target_y; + } else { + clear_tracked_worker_assignment (rec); + return false; + } + } + } + return false; +} + +bool +ai_worker_try_tile_improvement_district (Unit * worker) +{ + if (! is->current_config.enable_districts || worker == NULL) return false; + if (! is_worker (worker)) return false; + if (worker->Body.Auto_CityID < 0) return false; + + City * city = get_city_ptr (worker->Body.Auto_CityID); + if (city == NULL) return false; + if (city->Body.CivID != worker->Body.CivID) return false; + + int civ_id = worker->Body.CivID; + int tile_x = worker->Body.X; + int tile_y = worker->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (tile->CityID >= 0) return false; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; + if (! city_radius_contains_tile (city, tile_x, tile_y)) return false; + if (get_district_instance (tile) != NULL) return false; + + // Evaluate whether the best improvement here is irrigation, mines, or a district, using heuristics based on city needs + int food_weight = (city->Body.FoodIncome < city->Body.FoodRequired) ? 3 : 1; + int shield_weight = (city->Body.ProductionIncome < city->Body.Population.Size) ? 2 : 1; + int unhappy_percent = + city->Body.UnhappyNoReasonPercent + + city->Body.UnhappyCrowdedPercent + + city->Body.UnhappyWarWearinessPercent + + city->Body.UnhappyAgresssionPercent + + city->Body.UnhappyPropagandaPercent + + city->Body.UnhappyDraftPercent + + city->Body.UnhappyOppressionPercent + + city->Body.UnhappyThisCityImprovementsPercent + + city->Body.UnhappyOtherCityImprovementsPercent; + int happiness_weight = (unhappy_percent > 0) ? 2 : 1; + int gold_weight = 1; + int resource_boost = 5 * (food_weight + shield_weight + gold_weight + happiness_weight); + + int irrigation_score = INT_MIN; + if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Irrigate, tile_x, tile_y, 0) && + ! tile->vtable->m17_Check_Irrigation (tile, __, 0)) { + int base_type = tile->vtable->m50_Get_Square_BaseType (tile); + int bonus = p_bic_data->TileTypes[base_type].IrrigationBonus; + if (bonus < 0) + bonus = 0; + irrigation_score = bonus * food_weight; + } + + int mine_score = INT_MIN; + if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Build_Mines, tile_x, tile_y, 0) && + ! tile->vtable->m18_Check_Mines (tile, __, 0)) { + int base_type = tile->vtable->m50_Get_Square_BaseType (tile); + int bonus = p_bic_data->TileTypes[base_type].MiningBonus; + if (bonus < 0) + bonus = 0; + mine_score = bonus * shield_weight; + } + + int best_score = INT_MIN; + int best_district_id = -1; + for (int i = 0; i < is->district_count; i++) { + struct district_config const * cfg = &is->district_configs[i]; + if (cfg->ai_build_strategy != DABS_TILE_IMPROVEMENT) + continue; + if (! can_build_district_on_tile (tile, i, civ_id)) + continue; + + struct district_instance temp = {0}; + temp.district_id = i; + temp.tile_x = (short)tile_x; + temp.tile_y = (short)tile_y; + + int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; + get_effective_district_yields (&temp, cfg, &food, &shields, &gold, &science, &culture, &happiness); + + int score = food * food_weight + shields * shield_weight + gold * gold_weight; + score += (science + culture) / 2; + score += happiness * happiness_weight; + if ((cfg->generated_resource_id >= 0) && + ! patch_City_has_resource (city, __, cfg->generated_resource_id)) + score += resource_boost; + + if (score > best_score) { + best_score = score; + best_district_id = i; + } + } + + if ((best_district_id >= 0) && + (best_score >= irrigation_score) && + (best_score >= mine_score)) { + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + if (removable_flags != 0) + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); + ensure_district_instance (tile, best_district_id, tile_x, tile_y); + Unit_set_state (worker, __, UnitState_Build_Mines); + worker->Body.Job_ID = WJ_Build_Mines; + return true; + } + + return false; +} + +void __fastcall +patch_Unit_ai_move_terraformer (Unit * this) +{ + Map * map = &p_bic_data->Map; + int type_id = this->Body.UnitTypeID; + int civ_id = this->Body.CivID; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + int territory_owner = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m38_Get_Territory_OwnerID (tile) : -1; + + + if (is->current_config.enable_districts && ! is_human && is_worker (this)) { + update_tracked_worker_for_unit (this); + struct district_instance * inst = get_district_instance (tile); + + if ((territory_owner == civ_id) && + inst != NULL && inst->district_id != NATURAL_WONDER_DISTRICT_ID && + tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Coast) { + // Roads should be made after district builds. The district is complete but + // worker is still likely on the tile, so check here and build road if needed + struct district_config * cfg = &is->district_configs[inst->district_id]; + bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); + if (! has_road && ! cfg->auto_add_road) { + Unit_set_state(this, __, UnitState_Build_Road); + this->Body.Job_ID = WJ_Build_Road; + return; + } + + // Same check for railroads + bool can_build_railroad = Leader_can_do_worker_job (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y, 0); + bool has_railroad = (*tile->vtable->m23_Check_Railroads)(tile, __, 0); + if (can_build_railroad && !has_railroad && ! cfg->auto_add_railroad) { + Unit_set_state(this, __, UnitState_Build_Railroad); + this->Body.Job_ID = WJ_Build_Railroad; + return; + } + } + + struct district_worker_record * rec = get_tracked_worker_record (this); + if (rec != NULL && rec->pending_req != NULL) { + if (ai_move_district_worker (this, rec)) + return; + } + + if ((this->Body.Auto_CityID >= 0) && ai_worker_try_tile_improvement_district (this)) + return; + } + + bool pop_else_caravan; + if ((tile != NULL) && (tile != p_null_tile) && + (type_id >= 0) && (type_id < p_bic_data->UnitTypeCount) && + is_material_unit (&p_bic_data->UnitTypes[type_id], &pop_else_caravan) && + ((pop_else_caravan && is->current_config.enable_pop_unit_ai) || + ((! pop_else_caravan) && is->current_config.enable_caravan_unit_ai))) { + ai_move_material_unit (this); + return; + } + + Unit_ai_move_terraformer (this); +} + +bool __fastcall +patch_Unit_ai_can_sacrifice (Unit * this, int edx, bool requires_city) +{ + int sacrifice_action = UCV_Sacrifice & 0x0FFFFFFF; // Mask out top four category bits + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.patch_ai_can_sacrifice_without_special_ability && ((type->Special_Actions & sacrifice_action) == 0)) + return false; + else + return Unit_ai_can_sacrifice (this, __, requires_city); +} + +int __cdecl +patch_get_building_defense_bonus_at (int x, int y, int param_3) +{ + // Get base building defense bonus first + int base = get_building_defense_bonus_at (x, y, param_3); + + // If districts are disabled, return base + if (!is->current_config.enable_districts) + return base; + + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + struct district_config const * cfg = &is->district_configs[inst->district_id]; + int bonus = cfg->defense_bonus_percent; + bonus += apply_district_bonus_entries (inst, &cfg->defense_bonus_extras, inst->district_id); + return bonus; + } + + return base; +} + +void __fastcall +patch_Unit_select (Unit * this) +{ + if (is->current_config.enable_districts) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && is_worker(this) && inst->district_id >= 0 && inst->district_id <= is->district_count && + ! district_is_complete (tile, inst->district_id)) { + int district_id = inst->district_id; + PopupForm * popup = get_popup_form (); + int remaining_turns = get_worker_remaining_turns_to_complete (this, __, 0); + set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); + set_popup_int_param (1, remaining_turns); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_CANCEL_BUILD_DISTRICT", -1, 0, 0, 0); + + int sel = patch_show_popup (popup, __, 0, 0); + if (sel == 0) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, 0); + + bool other_workers_present = false; + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit != NULL) && (unit != this) && + (unit->Body.UnitState == UnitState_Build_Mines) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { + other_workers_present = true; + break; + } + } + if (! other_workers_present) { + remove_district_instance (tile); + } + } else { + return; + } + } + } + + // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + + Unit_select (this); +} + +void __fastcall +patch_City_Form_draw_food_income_icons (City_Form * this) +{ + // Call original function first + City_Form_draw_food_income_icons (this); + + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) + return; + + // Get current city + City * city = this->CurrentCity; + if (city == NULL) + return; + + // Calculate standard district food bonus + int standard_district_food = 0; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int district_id = wai.district_inst->district_id; + int food_bonus = 0; + get_effective_district_yields (wai.district_inst, &is->district_configs[district_id], &food_bonus, NULL, NULL, NULL, NULL, NULL); + standard_district_food += food_bonus; + } + + // Get distribution hub food bonus + int distribution_hub_food = 0; + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) + get_distribution_hub_yields_for_city (city, &distribution_hub_food, NULL); + + // Total district food + int total_district_food = standard_district_food + distribution_hub_food; + if (total_district_food <= 0) + return; + + // Lazy load icons + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { + if (is->distribution_hub_icons_img_state == IS_UNINITED) + init_distribution_hub_icons (); + if (is->distribution_hub_icons_img_state != IS_OK) + return; + } + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + if (is->dc_icons_img_state != IS_OK) + return; + + int food_income = city->Body.FoodIncome; + int food_required = city->Body.FoodRequired; + + // Calculate how standard district food icons are distributed + int standard_food_eaten = 0; + int standard_food_surplus = 0; + if (standard_district_food > 0) { + if (standard_district_food >= food_income) { + standard_food_surplus = food_income; + standard_food_eaten = standard_district_food - food_income; + } else { + standard_food_surplus = standard_district_food; + standard_food_eaten = 0; + } + } + + // Calculate how distribution hub food icons are distributed + int hub_food_eaten = 0; + int hub_food_surplus = 0; + int remaining_income = food_income - standard_food_surplus; + if (distribution_hub_food > 0) { + if (distribution_hub_food >= remaining_income) { + hub_food_surplus = remaining_income; + hub_food_eaten = distribution_hub_food - remaining_income; + } else { + hub_food_surplus = distribution_hub_food; + hub_food_eaten = 0; + } + } + + // Draw eaten district food icons (left side, from right to left) + int total_eaten = standard_food_eaten + hub_food_eaten; + if (total_eaten > 0) { + Sprite * base_eaten_sprite = &(this->City_Icons_Images).Icon_07; + int eaten_sprite_width = base_eaten_sprite->Width; + int eaten_sprite_height = base_eaten_sprite->Height; + struct tagRECT * eaten_rect = &this->Food_Consumption_Rect; + int eaten_rect_width = eaten_rect->right - eaten_rect->left; + + int eaten_spacing = eaten_sprite_width; + if ((food_required > 1) && (food_required * eaten_sprite_width - eaten_rect_width != 0) && + (eaten_rect_width <= food_required * eaten_sprite_width)) { + eaten_spacing = (eaten_rect_width - eaten_sprite_width) / (food_required - 1); + if (eaten_spacing < 1) + eaten_spacing = 1; + else if (eaten_spacing > eaten_sprite_width) + eaten_spacing = eaten_sprite_width; + } + + int eaten_x_offset = eaten_spacing * (food_required - 1); + // Draw standard district eaten first + for (int i = 0; i < standard_food_eaten && i < food_required; i++) { + int x = eaten_rect->left + eaten_x_offset; + int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - + (eaten_sprite_height >> 1)); + Sprite_draw (&is->district_food_eaten_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + eaten_x_offset -= eaten_spacing; + } + // Draw distribution hub eaten + for (int i = 0; i < hub_food_eaten && eaten_x_offset >= 0; i++) { + int x = eaten_rect->left + eaten_x_offset; + int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - + (eaten_sprite_height >> 1)); + Sprite_draw (&is->distribution_hub_eaten_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + eaten_x_offset -= eaten_spacing; + } + } + + // Draw surplus district food icons (right side, from right to left) + int total_surplus = standard_food_surplus + hub_food_surplus; + if (total_surplus > 0) { + Sprite * base_surplus_sprite = &(this->City_Icons_Images).Icon_06; + int surplus_sprite_width = base_surplus_sprite->Width; + int surplus_sprite_height = base_surplus_sprite->Height; + struct tagRECT * surplus_rect = &this->Food_Storage_Rect; + int surplus_rect_width = surplus_rect->right - surplus_rect->left; + + int surplus_spacing = surplus_sprite_width; + if ((food_income > 1) && (food_income * surplus_sprite_width - surplus_rect_width != 0) && + (surplus_rect_width <= food_income * surplus_sprite_width)) { + surplus_spacing = (surplus_rect_width - surplus_sprite_width) / (food_income - 1); + if (surplus_spacing < 1) + surplus_spacing = 1; + else if (surplus_spacing > surplus_sprite_width) + surplus_spacing = surplus_sprite_width; + } + + int surplus_x_offset = 0; + // Draw standard district surplus first + for (int i = 0; i < standard_food_surplus && i < food_income; i++) { + int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; + int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - + (surplus_sprite_height >> 1)) - 1; + Sprite_draw (&is->district_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + surplus_x_offset += surplus_spacing; + } + // Draw distribution hub surplus + for (int i = 0; i < hub_food_surplus && surplus_x_offset < surplus_rect_width; i++) { + int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; + int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - + (surplus_sprite_height >> 1)) - 1; + Sprite_draw (&is->distribution_hub_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + surplus_x_offset += surplus_spacing; + } + } +} + +void +recompute_district_and_distribution_hub_shields_for_city_view (City * city) +{ + if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) + return; + + int city_id = city->Body.ID; + int city_x = city->Body.X; + int city_y = city->Body.Y; + + // District yields are injected through the city center tile in patch_City_calc_tile_yield_while_gathering. + // Grab the base yield (no districts) directly from the original function, then compute the + // district bonus that calculate_city_center_district_bonus will layer on afterward. + int city_center_base_shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, city_x, city_y); + int total_district_shield_bonus = 0; + calculate_city_center_district_bonus (city, NULL, &total_district_shield_bonus, NULL); + + // Distribution hub contribution is tracked separately for icon rendering. + int distribution_hub_shields = 0; + if (is->current_config.enable_distribution_hub_districts) + get_distribution_hub_yields_for_city (city, NULL, &distribution_hub_shields); + if (distribution_hub_shields < 0) + distribution_hub_shields = 0; + if (distribution_hub_shields > total_district_shield_bonus) + distribution_hub_shields = total_district_shield_bonus; + + int standard_district_shields = total_district_shield_bonus - distribution_hub_shields; + if (standard_district_shields < 0) + standard_district_shields = 0; + + // Recompute yields with districts active so ProductionIncome/Loss reflect the city view. + recompute_city_yields_with_districts (city); + int total_production_income = city->Body.ProductionIncome; + int total_production_loss = city->Body.ProductionLoss; + int total_net_shields = total_production_income + total_production_loss; // ProductionLoss stored as negative + + // Remove the district bonus from the gross tile production and recompute corruption on that base value. + int city_center_with_districts = city_center_base_shields + total_district_shield_bonus; + int gross_without_specials = city->Body.Tiles_Production - (city_center_with_districts - city_center_base_shields); + if (gross_without_specials < 0) + gross_without_specials = 0; + + int base_corruption_abs = patch_City_compute_corrupted_yield (city, __, gross_without_specials, true); + if (base_corruption_abs < 0) + base_corruption_abs = 0; + int base_production_loss = -base_corruption_abs; + + // Corruption becomes more negative as it increases. + int additional_corruption = total_production_loss - base_production_loss; + + int district_shields_remaining = standard_district_shields; + int hub_shields_remaining = distribution_hub_shields; + + if (additional_corruption < 0) { + int extra_loss = -additional_corruption; + + if (district_shields_remaining > 0) { + int from_districts = (extra_loss < district_shields_remaining) ? extra_loss : district_shields_remaining; + district_shields_remaining -= from_districts; + extra_loss -= from_districts; + } + + if ((extra_loss > 0) && (hub_shields_remaining > 0)) { + int from_hub = (extra_loss < hub_shields_remaining) ? extra_loss : hub_shields_remaining; + hub_shields_remaining -= from_hub; + extra_loss -= from_hub; + } + } + + int non_district_shields_remaining = total_net_shields - district_shields_remaining - hub_shields_remaining; + if (non_district_shields_remaining < 0) + non_district_shields_remaining = 0; + + int total_corruption = -total_production_loss; + if (total_corruption < 0) + total_corruption = 0; + int district_corruption = standard_district_shields - district_shields_remaining; + int hub_corruption = distribution_hub_shields - hub_shields_remaining; + int base_corruption = total_corruption - district_corruption - hub_corruption; + if (base_corruption < 0) + base_corruption = 0; + + is->non_district_shield_icons_remaining = non_district_shields_remaining; + is->district_shield_icons_remaining = district_shields_remaining; + is->distribution_hub_shield_icons_remaining = hub_shields_remaining; + + is->corruption_shield_icons_remaining = base_corruption; + is->district_corruption_icons_remaining = district_corruption; + is->distribution_hub_corruption_icons_remaining = hub_corruption; +} + +void __fastcall +patch_City_draw_production_income_icons (City * this, int edx, int canvas, int * rect_ptr) +{ + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { + City_draw_production_income_icons (this, __, canvas, rect_ptr); + return; + } + + recompute_district_and_distribution_hub_shields_for_city_view (this); + City_draw_production_income_icons (this, __, canvas, rect_ptr); + + is->corruption_shield_icons_remaining = 0; + is->district_corruption_icons_remaining = 0; + is->distribution_hub_corruption_icons_remaining = 0; + + is->non_district_shield_icons_remaining = 0; + is->district_shield_icons_remaining = 0; + is->distribution_hub_shield_icons_remaining = 0; +} + +int __fastcall +patch_Sprite_draw_production_income_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + if (is->distribution_hub_icons_img_state == IS_UNINITED) + init_distribution_hub_icons (); + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + + if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && is->dc_icons_img_state == IS_OK) { + Sprite to_draw = *this; + if (is->corruption_shield_icons_remaining > 0 || + is->district_corruption_icons_remaining > 0 || + is->distribution_hub_corruption_icons_remaining > 0) { + + if (is->corruption_shield_icons_remaining > 0) { + is->corruption_shield_icons_remaining--; + } else if (is->district_corruption_icons_remaining > 0) { + to_draw = is->district_corruption_icon; + is->district_corruption_icons_remaining--; + } else if (is->distribution_hub_icons_img_state == IS_OK) { + to_draw = is->distribution_hub_corruption_icon; + is->distribution_hub_corruption_icons_remaining--; + } + } + else if (is->non_district_shield_icons_remaining > 0 || + is->district_shield_icons_remaining > 0 || + is->distribution_hub_shield_icons_remaining > 0) { + + if (is->non_district_shield_icons_remaining > 0) { + is->non_district_shield_icons_remaining--; + } else if (is->district_shield_icons_remaining > 0) { + to_draw = is->district_shield_icon; + is->district_shield_icons_remaining--; + } else if (is->distribution_hub_icons_img_state == IS_OK) { + to_draw = is->distribution_hub_shield_icon; + is->distribution_hub_shield_icons_remaining--; + } + + } + return Sprite_draw (&to_draw, __, canvas, pixel_x, pixel_y, color_table); + } + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +bool +district_tile_needs_defense (Tile * tile, int tile_x, int tile_y, struct district_instance * inst, int civ_id, int work_radius) +{ + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (inst == NULL) return false; + + int district_id = inst->district_id; + struct district_config const * cfg = &is->district_configs[district_id]; + if (! district_is_complete (tile, district_id)) return false; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; + + // Check if already has enough defenders (2 for aerodromes, distribution hubs, destroyable completed wonders) + int defender_count = count_units_at (tile_x, tile_y, UF_DEFENDER_VIS_TO_A_OF_CLASS_B, civ_id, 0, -1); + int max_defenders = + (district_id == AERODROME_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID || + (cfg->defense_bonus_percent > 0 && district_id != NEIGHBORHOOD_DISTRICT_ID) || + (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed)) + ? 2 : 1; + if (defender_count >= max_defenders) + return false; + + // Distribution hubs always need defense + if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) + return true; + + // Wonder districts need defense if under construction or completed (not unused) + if (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed) { + enum wonder_district_state state = inst->wonder_info.state; + if (state == WDS_UNDER_CONSTRUCTION || state == WDS_COMPLETED) + return true; + // Unused wonder districts don't need defense + return false; + } + + return any_enemies_near (&leaders[civ_id], tile_x, tile_y, -1, work_radius); +} + +int +compute_turns_required_for_path (Unit * unit, int path_length) +{ + if (path_length < 1) + return 0; + + int max_mp = patch_Unit_get_max_move_points (unit); + if (max_mp <= 0) + return 9999; + + int moves_used_this_turn = max_mp - unit->Body.Moves; + moves_used_this_turn = not_below (0, moves_used_this_turn); + moves_used_this_turn = not_above (moves_used_this_turn, 9999); + + int remaining_mp = path_length - moves_used_this_turn; + if (remaining_mp < 0) + remaining_mp = 0; + + return (max_mp - 1 + remaining_mp) / max_mp + 1; +} + +void +maybe_update_best_district_target (Unit * unit, + int civ_id, + int max_distance, + int unit_x, + int unit_y, + int tile_x, + int tile_y, + int base_score, + int * best_score, + int * best_x, + int * best_y, + int * best_path_length, + int * evaluated_paths, + int max_path_checks) +{ + if (*evaluated_paths >= max_path_checks) + return; + + int path_length; + int path_result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, tile_x, tile_y, + unit, civ_id, 0x81, &path_length); + *evaluated_paths += 1; + if (path_result <= 0) + return; + + if (max_distance > 0) { + int turns = compute_turns_required_for_path (unit, path_length); + if (turns > max_distance) + return; + } + + int score = base_score - path_length; + if ((score > *best_score) || ((score == *best_score) && (path_length < *best_path_length))) { + *best_score = score; + *best_x = tile_x; + *best_y = tile_y; + *best_path_length = path_length; + } +} + +// Patch seek_colony to actively search for undefended districts +int __fastcall +patch_Unit_seek_colony (Unit * this, int edx, bool for_own_defense, int max_distance) +{ + // Only intercept if defending own assets and districts are enabled + if (!for_own_defense || + !is->current_config.enable_districts || + !is->current_config.ai_defends_districts) + return Unit_seek_colony (this, __, for_own_defense, max_distance); + + int civ_id = this->Body.CivID; + int unit_x = this->Body.X; + int unit_y = this->Body.Y; + + Tile * current_tile = tile_at (unit_x, unit_y); + if ((current_tile == NULL) || (current_tile == p_null_tile)) + return Unit_seek_colony (this, __, for_own_defense, max_distance); + + int continent_id = current_tile->vtable->m46_Get_ContinentID (current_tile); + + const int search_radius = 20; + const int max_path_checks = 64; + const int wonder_base_score = 1000; + const int regular_base_score = 500; + + int best_x = -1; + int best_y = -1; + int best_score = INT_MIN; + int best_path_length = INT_MAX; + int evaluated_paths = 0; + + bool abort_search = false; + + if ((is->current_config.enable_wonder_districts && is->current_config.completed_wonder_districts_can_be_destroyed) || + is->current_config.enable_distribution_hub_districts) { + for (int dx = -search_radius; (dx <= search_radius) && !abort_search; dx++) { + for (int dy = -search_radius; dy <= search_radius; dy++) { + if (evaluated_paths >= max_path_checks) { + abort_search = true; + break; + } + + int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); + int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); + Tile * district_tile = tile_at (target_x, target_y); + if ((district_tile == NULL) || (district_tile == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (district_tile); + if (inst == NULL) + continue; + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) + continue; + if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) + continue; + if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) + continue; + + maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, + tile_x, tile_y, wonder_base_score, + &best_score, &best_x, &best_y, + &best_path_length, &evaluated_paths, + max_path_checks); + } + } + } + + if ((best_x < 0) && (evaluated_paths < max_path_checks)) { + for (int dx = -search_radius; (dx <= search_radius) && (evaluated_paths < max_path_checks); dx++) { + for (int dy = -search_radius; dy <= search_radius; dy++) { + if (evaluated_paths >= max_path_checks) + break; + + int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); + int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); + Tile * district_tile = tile_at (target_x, target_y); + if ((district_tile == NULL) || (district_tile == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (district_tile); + if ((inst == NULL) || (inst->district_id == WONDER_DISTRICT_ID)) + continue; + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) + continue; + if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) + continue; + if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) + continue; + + maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, + tile_x, tile_y, regular_base_score, + &best_score, &best_x, &best_y, + &best_path_length, &evaluated_paths, + max_path_checks); + } + } + } + + if ((best_x >= 0) && (best_y >= 0)) { + int result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, best_x, best_y, + this, civ_id, 0x181, NULL); + return result; + } + + return Unit_seek_colony (this, __, for_own_defense, max_distance); +} + +// Patch has_colony to make units stay on districts, only patches within Unit::ai_move_defensive_unit +bool __fastcall +patch_Tile_has_district_or_colony (Tile * this) +{ + if (is->current_config.enable_districts && + is->current_config.ai_defends_districts) { + + struct district_instance * inst = get_district_instance (this); + return (inst != NULL) && district_is_complete (this, inst->district_id); + } + + // Fallback to original has_colony logic + return Tile_has_colony (this); +} + +int __fastcall +patch_Buildings_Info_get_age_in_years_for_tourism (Buildings_Info * this, int edx, int building_index) +{ + int base = Buildings_Info_get_age_in_years (this, __, building_index); + if (is->current_config.tourism_time_scale_percent == 100) + return base; + else if (is->current_config.tourism_time_scale_percent <= 0) + return INT_MAX; + else + return (base * 100 + 50) / is->current_config.tourism_time_scale_percent; +} + +int __fastcall +patch_Sprite_draw_minimap_frame (Sprite * this, int edx, Sprite * alpha, int param_2, PCX_Image * canvas, int x, int y, int param_6) +{ + bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || + ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); + if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) + return Sprite_draw_for_hud (&is->double_size_box_left_color_pcx, __, &is->double_size_box_left_alpha_pcx, param_2, canvas, x, y, param_6); + else + return Sprite_draw_for_hud (this, __, alpha, param_2, canvas, x, y, param_6); +} + +int __fastcall +patch_City_get_turns_to_build_2_for_ai_move_leader (City * this, int edx, City_Order * order, bool param_2) +{ + // Initialize order variable to city's current build. This is not done in the base logic and can cause crashes. + City_Order current_order = { .OrderID = this->Body.Order_ID, .OrderType = this->Body.Order_Type }; + if (is->current_config.patch_crash_in_leader_unit_ai) + order = ¤t_order; + + return City_get_turns_to_build_2 (this, __, order, param_2); +} + +void __fastcall +patch_City_set_production (City * this, int edx, int order_type, int order_id, bool ask_to_confirm) +{ + City_set_production (this, __, order_type, order_id, ask_to_confirm); + + if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) + return; + + // If the human player, we need to set/unset a wonder district for this city, depending + // on what is being built. The human player wouldn't be able to choose a wonder if a wonder + // district wasn't available, so we don't need to worry about feasibility here. + // The AI uses a different mechanism to reserve wonder districts via patch_Leader_do_production_phase. + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + if (! is_human) + return; + + char ss[256]; + bool release_reservation = true; + if (this->Body.Order_Type == COT_Improvement) { + Improvement * improv = &p_bic_data->Improvements[this->Body.Order_ID]; + if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { + if (reserve_wonder_district_for_city (this, this->Body.Order_ID)) { + release_reservation = false; + } + } + } + + if (release_reservation) { + release_wonder_district_reservation (this); + } +} + +int __fastcall +patch_Tile_m71_Check_Worker_Job (Tile * this) +{ + if (is->current_config.enable_natural_wonders) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && + (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) { + return -1; // No worker job allowed on natural wonders + } + } + return Tile_m71_Check_Worker_Job (this); +} + +int __fastcall +patch_Tile_get_road_bonus (Tile * this) +{ + if (is->current_config.enable_natural_wonders) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { + return 0; + } + } + if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { + return 1; + } + } + return Tile_get_road_bonus (this); +} + +bool __fastcall +patch_Unit_has_army_ability_to_perform_unload (Unit * this, int edx, enum UnitTypeAbilities a) +{ + return is->current_config.allow_unload_from_army ? false : Unit_has_ability (this, __, a); +} + +void __fastcall +patch_Unit_disembark (Unit * this, int edx, int tile_x, int tile_y) +{ + Unit * container = get_unit_ptr (this->Body.Container_Unit); + bool unloading_from_army = is->current_config.allow_unload_from_army && container != NULL && Unit_has_ability (container, __, UTA_Army); + + // If removing a unit from an army, transfer a proportional amount of damage to the unit removed + int damage_transferred = 0; + if (unloading_from_army) { + int army_damage_percent = container->Body.Damage * 100 / Unit_get_max_hp (container), + max_damage = Unit_get_max_hp (this) - 1 - this->Body.Damage; + damage_transferred = clamp (0, max_damage, (army_damage_percent * Unit_get_max_hp (this) + 50) / 100); + } + + Unit_disembark (this, __, tile_x, tile_y); + + if (unloading_from_army) { + this->Body.Damage = not_above (Unit_get_max_hp (this) - 1, this->Body.Damage + damage_transferred); + container->Body.Damage = not_below (0, container->Body.Damage - damage_transferred); + + if (this->Body.ID == container->Body.army_top_defender_id) { + Unit * new_top_defender = NULL; + FOR_UNITS_ON (uti, tile_at (container->Body.X, container->Body.Y)) + if (uti.unit->Body.Container_Unit == container->Body.ID) { + if (new_top_defender == NULL) + new_top_defender = uti.unit; + else if (Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, uti.unit, Unit_get_defense_strength (uti.unit), new_top_defender, Unit_get_defense_strength (new_top_defender), true)) + new_top_defender = uti.unit; + } + container->Body.army_top_defender_id = (new_top_defender != NULL) ? new_top_defender->Body.ID : -1; + } + } +} + +bool __fastcall +patch_Unit_has_ability_no_load_non_army_passengers (Unit * this, int edx, enum UnitTypeAbilities army_ability) +{ + UnitType * transport_type = &p_bic_data->UnitTypes[is->can_load_transport->Body.UnitTypeID], + * passenger_type = &p_bic_data->UnitTypes[this ->Body.UnitTypeID]; + + // This call comes from Unit::can_load at the point where it's determined that the passenger (this) has transport capacity > 0 and is checking + // whether it's an army. If not, it can't be loaded. Add two exceptions here for land transports, if configured, one to allow LTs to load into + // naval units and another to allow empty LTs to load into armies. + if (is->current_config.land_transport_rules != 0) + if ((passenger_type->Unit_Class == UTC_Land) && ! Unit_has_ability (this, __, army_ability)) { // if it's a land transport + if ((is->current_config.land_transport_rules & LTR_LOAD_ONTO_BOAT) && (transport_type->Unit_Class == UTC_Sea)) + return true; + if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && + Unit_has_ability (is->can_load_transport, __, army_ability) && (Unit_count_contained_units (this) == 0)) + return true; + } + + // Similarly, allow helicopters to be loaded onto carriers if so configured + if ((is->current_config.special_helicopter_rules & SHR_ALLOW_ON_CARRIERS) && + passenger_type->Unit_Class == UTC_Air && + transport_type->Unit_Class == UTC_Sea && + Unit_has_ability (is->can_load_transport, __, UTA_Transports_Only_Aircraft)) + return true; + + return Unit_has_ability (this, __, army_ability); +} + +bool __fastcall +patch_Unit_has_ability_no_load_transport_into_army (Unit * this, int edx, enum UnitTypeAbilities army_ability) +{ + // Similar to above, here it checks if the target unit is an army and rejects the load if it is (again, already determined that the passenger + // has transport capacity). Modify this rule to return false for land transports trying to join armies if configured. We don't have to check + // that the LT is empty since that is already disallowed by the modified check above. + bool is_army = Unit_has_ability (this, __, army_ability); + if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && is_army && + (p_bic_data->UnitTypes[is->can_load_passenger->Body.UnitTypeID].Unit_Class == UTC_Land)) + return false; + + else + return is_army; +} + +bool __fastcall +patch_Fighter_unit_can_defend (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) +{ + if (cannot_defend_inside_transport (unit)) + return false; + else + return Fighter_unit_can_defend (this, __, unit, tile_x, tile_y); +} + +bool __fastcall +patch_Leader_is_enemy_unit_for_ground_aa (Leader * this, int edx, Unit * bomber) +{ + // When this function is called, the potential interceptor unit is stored in register ESI. + Unit * interceptor; + __asm__ __volatile__("mov %%esi, %0" : "=r" (interceptor)); + + Unit * container = get_unit_ptr (interceptor->Body.Container_Unit); + bool in_transport = (container != NULL) && ! Unit_has_ability (container, __, UTA_Army); + if (in_transport && + (is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Land) + return false; + else if (in_transport && + (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return false; + else if (in_transport && + is->current_config.no_land_anti_air_from_inside_naval_transport && + (p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea)) + return false; + else + return Leader_is_enemy_unit (this, __, bomber); +} + +bool __fastcall +patch_Unit_has_army_ability_for_passenger_despawn (Unit * this, int edx, enum UnitTypeAbilities army_ability) +{ + // If the unit has the army ability, the game will always despawn the passengers. Otherwise there are exceptions like land unit passengers + // won't be despawned if the transport is on a land tile. + return is->always_despawn_passengers || Unit_has_ability (this, __, army_ability); +} + +int __cdecl +patch_count_units_at_in_try_capturing (int x, int y, enum unit_filter filter, int arg_a, int arg_b, int arg_c) +{ + Tile * tile = tile_at (x, y); + + // If one of the no-defense-from-inside rules is in force, count units like the function normally would except skip units that are inside + // transports from which they can't defend. Otherwise, if those transports have 0 defense, the passengers will prevent them from being + // captured but not fight themselves, making movement onto their tile impossible. + if (tile->vtable->m35_Check_Is_Water (tile) == 0 && + ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) || (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE))) { + int tr = 0; + FOR_UNITS_ON (tai, tile) { + if ((arg_b == -1 || p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].Unit_Class == arg_b) && + (arg_a == -1 || patch_Unit_is_visible_to_civ (tai.unit, __, arg_a, 1)) && + (Unit_get_defense_strength (tai.unit) > 0) && + ! cannot_defend_inside_transport (tai.unit)) + tr++; + } + return tr; + + } else + return count_units_at (x, y, filter, arg_a, arg_b, arg_c); +} + +void __fastcall +patch_Map_generate_resources (Map * this, int edx, int secondary_seed) +{ + int const bic_tag_good = 0x444f4f47; // = 'GOOD' + int resource_type_count = this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, -1, NULL); + bool * ratios_to_clear = NULL; + int lux_percent = is->current_config.luxury_randomized_appearance_rate_percent; + int seed = (this->Seed + 0x180E3) * secondary_seed; + + // To change the randomized appearance rate for luxuries, fill in an appearance rate for any that would be randomized (rate set == 0) using + // the same process the game would to randomize the rate but with different limits. That process involves taking two random numbers from 0 to + // 25 then adding them together and to 50 to produce a random rate from 50 to 100 biased toward the middle of that range. + if (lux_percent != 100 && + (ratios_to_clear = calloc (1, resource_type_count)) != NULL) { + for (int n = 0; n < resource_type_count; n++) { + Resource_Type * res; + this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); + if (res->Class == RC_Luxury && res->AppearanceRatio == 0) { + ratios_to_clear[n] = true; + int half_lux_percent = (lux_percent * 50 + 50) / 100, + quarter_lux_percent = (lux_percent * 25 + 50) / 100; + res->AppearanceRatio = not_below (1, half_lux_percent + rand_int (&seed, __, quarter_lux_percent) + rand_int (&seed, __, quarter_lux_percent)); + } + } + } + + Map_generate_resources (this, __, secondary_seed); + + if (ratios_to_clear != NULL) { + for (int n = 0; n < resource_type_count; n++) + if (ratios_to_clear[n]) { + Resource_Type * res; + this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); + res->AppearanceRatio = 0; + } + free (ratios_to_clear); + } +} + +PassBetweenValidity __fastcall +patch_Unit_can_pass_between (Unit * this, int edx, int from_x, int from_y, int to_x, int to_y, int param_5) +{ + PassBetweenValidity base = Unit_can_pass_between (this, __, from_x, from_y, to_x, to_y, param_5); + + if (is->current_config.enable_districts) { + Tile * to = tile_at (to_x, to_y); + bool to_valid = (to != NULL) && (to != p_null_tile); + struct district_instance * to_inst = NULL; + bool to_inst_complete = false; + if (to_valid) { + to_inst = get_district_instance (to); + if (to_inst != NULL) + to_inst_complete = district_is_complete (to, to_inst->district_id); + } + if (great_wall_blocks_civ (to, this->Body.CivID)) + return PBV_GENERIC_INVALID_MOVE; + if (to_valid) { + bool impassible = false; + bool impassible_to_wheeled = false; + if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { + if (impassible) + return PBV_GENERIC_INVALID_MOVE; + if (impassible_to_wheeled && Unit_has_ability (this, __, UTA_Wheeled)) { + Tile * from = tile_at (from_x, from_y); + bool connected_by_road = (from != NULL) && (to != NULL) && + (from->vtable->m25_Check_Roads (from, __, 0) != 0) && + (to->vtable->m25_Check_Roads (to, __, 0) != 0); + if (! connected_by_road) + return PBV_REQUIRES_ROAD; + } + } + } + + if (is->current_config.workers_can_enter_coast && + base != PBV_OK && is_worker(this)) { + Tile * source = tile_at (from_x, from_y); + if (source != NULL && + source->vtable->m35_Check_Is_Water (source) && + (source->vtable->m50_Get_Square_BaseType (source) == SQ_Coast)) + return PBV_OK; + + if (to_valid && + to->vtable->m35_Check_Is_Water (to) && + (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + + // If human, okay to enter coast tile + if (is_human) + return PBV_OK; + + struct district_worker_record * rec = get_tracked_worker_record (this); + struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; + if (req != NULL) + return PBV_OK; + } + } + + if (is->current_config.enable_bridge_districts && + base != PBV_OK && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == BRIDGE_DISTRICT_ID)) + return PBV_OK; + + if (is->current_config.enable_canal_districts && + base != PBV_OK && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == CANAL_DISTRICT_ID)) + return PBV_OK; + } + + return base; +} + +Unit * __fastcall +patch_Unit_select_transport (Unit * this, int edx, int tile_x, int tile_y, bool do_show_popup) +{ + Unit * transport = Unit_select_transport (this, __, tile_x, tile_y, do_show_popup); + + if (is->current_config.enable_districts && + (transport == NULL) && (this == is->coast_walk_unit)) { + Tile * dest = tile_at (tile_x, tile_y); + if (dest != NULL) { + bool allow_move = false; + if (is->current_config.workers_can_enter_coast && is_worker (this) && + dest->vtable->m35_Check_Is_Water (dest) && + (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) + allow_move = true; + + if (! allow_move && is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land)) { + struct district_instance * inst = get_district_instance (dest); + if (inst != NULL && inst->district_id == BRIDGE_DISTRICT_ID && + district_is_complete (dest, inst->district_id)) { + allow_move = true; + } + } + + if (allow_move) { + is->coast_walk_transport_override = true; + return this; // Fake a transport so the move logic proceeds + } + } + } + + return transport; +} + +// Returns true if the given tile is a water district owned by an enemy of the unit +bool +is_enemy_maritime_district_tile (Unit * unit, Tile * tile) +{ + if ((unit == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + if (! is->current_config.enable_districts) + return false; + + if (! tile->vtable->m35_Check_Is_Water (tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner <= 0) || (owner == unit->Body.CivID)) + return false; + + Leader * leader = &leaders[unit->Body.CivID]; + return leader->At_War[owner]; +} + +// Boost pillage desirability for maritime districts +int __fastcall +patch_Unit_ai_eval_pillage_target (Unit * this, int edx, int tile_x, int tile_y) +{ + int base = Unit_ai_eval_pillage_target (this, __, tile_x, tile_y); + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if (is_enemy_maritime_district_tile (this, tile)) { + // Double the base score so districts outrank generic coast targets + base += base + 0x300; + } + + return base; +} + +// Light-weight hunt for nearby friendly ports; returns true if a path/command was issued +bool +try_path_to_friendly_port_district (Unit * unit, bool require_damaged, bool require_undefended) +{ + if ((unit == NULL) || + ! is->current_config.enable_districts || + ! is->current_config.enable_port_districts) + return false; + + if (unit->Body.Container_Unit >= 0) // Don't redirect cargo + return false; + + if (unit->Body.Moves <= 0) + return false; + + if (require_damaged && (unit->Body.Damage <= 0)) + return false; + + if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Sea) + return false; + + int sea_id = unit->vtable->get_sea_id (unit); + if (sea_id < 0) + return false; + + int best_x = -1, best_y = -1, best_path_len = INT_MAX; + const int search_radius = 10; + for (int dy = -search_radius; dy <= search_radius; dy++) { + for (int dx = -search_radius; dx <= search_radius; dx++) { + int tx = unit->Body.X + dx, ty = unit->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + if ((short)tile->vtable->m46_Get_ContinentID (tile) != sea_id) + continue; + + if (! tile_has_friendly_port_district (tile, unit->Body.CivID)) + continue; + + int occupier_id = get_tile_occupier_id (tx, ty, -1, true); + if ((occupier_id != -1) && (occupier_id != unit->Body.CivID)) + continue; + + if (require_undefended) { + bool has_friendly_sea_unit = false; + FOR_UNITS_ON (uti, tile) { + Unit * on_tile = uti.unit; + if ((on_tile == NULL) || (on_tile->Body.Container_Unit >= 0)) + continue; + if (on_tile->Body.CivID != unit->Body.CivID) + continue; + if (p_bic_data->UnitTypes[on_tile->Body.UnitTypeID].Unit_Class != UTC_Sea) + continue; + if (on_tile->Body.ID == unit->Body.ID) + continue; + has_friendly_sea_unit = true; + break; + } + if (has_friendly_sea_unit) + continue; + } + + if (! is_below_stack_limit (tile, unit->Body.CivID, UTC_Sea)) + continue; + + int path_len = 0; + int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, + tx, ty, unit, unit->Body.CivID, 0x81, &path_len); + if (path_result <= 0) + continue; + + if (path_len < best_path_len) { + best_path_len = path_len; + best_x = tx; + best_y = ty; + } + } + } + + if (unit->Body.X == best_x && unit->Body.Y == best_y) { + Unit_set_escortee (unit, __, -1); + Unit_set_state (unit, __, UnitState_Fortifying); + return true; + } + else if (best_x >= 0) { + patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, best_x, best_y, + unit, unit->Body.CivID, 0x81, NULL); + Unit_set_escortee (unit, __, -1); + Unit_set_state (unit, __, UnitState_Go_To); + unit->Body.path_dest_x = best_x; + unit->Body.path_dest_y = best_y; + return true; + } + + return false; +} + +void __fastcall +patch_Unit_ai_move_naval_power_unit (Unit * this) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + ! is->current_config.naval_units_use_port_districts_not_cities) { + Unit_ai_move_naval_power_unit (this); + return; + } + + Tile * here = tile_at (this->Body.X, this->Body.Y); + if (here == NULL) { + Unit_ai_move_naval_power_unit (this); + return; + } + + // If we're on a port and the sole unit, fortify + if (is->current_config.ai_defends_districts && + tile_has_friendly_port_district (here, this->Body.CivID) && + count_units_at (this->Body.X, this->Body.Y, UF_0, this->Body.CivID, 0, -1) == 1) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If we're already sitting on an enemy maritime district, pillage it immediately + if (this->Body.Container_Unit < 0) { + if (is_enemy_maritime_district_tile (this, here) && + patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y) && + (patch_Unit_ai_eval_pillage_target (this, __, this->Body.X, this->Body.Y) > 0)) { + patch_Unit_attack_tile (this, __, this->Body.X, this->Body.Y, false); + return; + } + } + + // If damaged and CAN heal at current location (e.g. port district), fortify to heal + if (this->Body.Damage > 0 && patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If damaged and cannot heal here, try to path to a friendly port district + if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) + return; + + Unit_ai_move_naval_power_unit (this); + return; +} + +void __fastcall +patch_Unit_ai_move_naval_transport (Unit * this) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + ! is->current_config.naval_units_use_port_districts_not_cities) { + Unit_ai_move_naval_transport (this); + return; + } + + // If damaged and CAN heal at current location (e.g. port district), fortify to heal + if ((this->Body.Damage > 0) && + patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If damaged and cannot heal here, try to path to a friendly port district + if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) + return; + + Unit_ai_move_naval_transport (this); +} + +void __fastcall +patch_Unit_ai_move_naval_missile_transport (Unit * this) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + ! is->current_config.naval_units_use_port_districts_not_cities) { + patch_Unit_ai_move_naval_missile_transport (this); + return; + } + + // If damaged and CAN heal at current location (e.g. port district), fortify to heal + if ((this->Body.Damage > 0) && + patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If damaged and cannot heal here, try to path to a friendly port district + if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) + return; + + Unit_ai_move_naval_missile_transport (this); +} + +void __fastcall +patch_Unit_ai_move_air_bombard_unit (Unit * this) +{ + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) { + Unit_ai_move_air_bombard_unit (this); + return; + } + + if (this->Body.Damage > 0) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + int best_target = 0; + int target_x = -1, target_y = -1; + int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + int grid = op_range * 2 + 1; + if (1 < grid * grid) { + for (int n = 1; n < grid * grid; n++) { + int dx, dy; + neighbor_index_to_diff (n, &dx, &dy); + int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); + int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); + if (Map_in_range (&p_bic_data->Map, __, x, y)) { + int score = Unit_ai_eval_bombard_target (this, __, x, y, 1); + if (score > best_target) { + best_target = score; + target_x = x; + target_y = y; + } + } + } + } + + int best_base_score = 0x7fffffff; + int base_x = -1, base_y = -1; + FOR_AERODROMES_AROUND (this) { + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) + continue; + + int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 6, -1, -1); + int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); + int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); + int score = (count * 10) + ((x_dist + y_dist) >> 1); + if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) + score -= 20; + + if (score < best_base_score) { + best_base_score = score; + base_x = aerodrome_x; + base_y = aerodrome_y; + } + } + + if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { + Unit_set_escortee (this, __, -1); + Unit_rebase (this, __, base_x, base_y); + return; + } + + if ((target_x >= 0) && (target_y >= 0)) { + Unit_set_escortee (this, __, -1); + patch_Unit_bombard_tile (this, __, target_x, target_y); + return; + } + + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +void __fastcall +patch_Unit_ai_move_air_defense_unit (Unit * this) +{ + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) { + Unit_ai_move_air_defense_unit (this); + return; + } + + Unit_ai_move_air_defense_unit (this); + + Unit_set_state (this, __, 0); + if (this->Body.Damage > 0) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + int best_base_score = 0x7fffffff; + int base_x = -1, base_y = -1; + FOR_AERODROMES_AROUND (this) { + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) + continue; + + int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 7, -1, -1); + int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); + int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); + int score = (count * 10) + ((x_dist + y_dist) >> 1); + if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) + score -= 20; + + if (score < best_base_score) { + best_base_score = score; + base_x = aerodrome_x; + base_y = aerodrome_y; + } + } + + if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { + Unit_set_escortee (this, __, -1); + Unit_rebase (this, __, base_x, base_y); + return; + } + + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Intercept); +} + +void __fastcall +patch_Unit_ai_move_air_transport (Unit * this) +{ + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) { + Unit_ai_move_air_transport (this); + return; + } + + Unit_ai_move_air_transport (this); + + if (this->Body.Damage < 1) { + if (Unit_can_airdrop (this)) { + int best_score = 0; + int best_x = -1, best_y = -1; + int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + int grid = op_range * 2 + 1; + if (1 < grid * grid) { + for (int n = 1; n < grid * grid; n++) { + int dx, dy; + neighbor_index_to_diff (n, &dx, &dy); + int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); + int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); + if (Map_in_range (&p_bic_data->Map, __, x, y)) { + int score = Unit_ai_eval_airdrop_target (this, __, x, y); + if (score > best_score) { + best_score = score; + best_x = x; + best_y = y; + } + } + } + if ((best_x >= 0) && (best_y >= 0)) { + Unit_set_escortee (this, __, -1); + Unit_airdrop (this, __, best_x, best_y); + return; + } + } + } + + int best_score = -1; + int base_x = -1, base_y = -1; + FOR_AERODROMES_AROUND (this) { + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) + continue; + + int score = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 0, -1, -1) + + count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 1, -1, -1) + 1; + if (count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 9, -1, -1) == 0) + score *= 2; + int cont_id = aerodrome_tile->vtable->m46_Get_ContinentID (aerodrome_tile); + if ((cont_id >= 0) && (cont_id < p_bic_data->Map.Continent_Count) && + (p_bic_data->Map.Continents[cont_id].Body.TileCount > 0x15)) + score *= 2; + + if (score > best_score) { + best_score = score; + base_x = aerodrome_x; + base_y = aerodrome_y; + } + } + + if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { + Unit_set_escortee (this, __, -1); + Unit_rebase (this, __, base_x, base_y); + if (Unit_count_contained_units (this) > 0) { + patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); + } + return; + } + } + + if (Unit_count_contained_units (this) > 0) + patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); + + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +bool __fastcall +patch_Tile_has_colony_ignore_extraterritorial (Tile * tile) +{ + if (!Tile_has_colony (tile)) + return false; + + if (!is->current_config.allow_extraterritorial_colonies) + return true; + + if ((tile == NULL) || (tile == p_null_tile)) + return true; + + int tile_building_id = tile->vtable->m47_Get_Tile_BuildingID (tile); + if ((tile_building_id < 0) || (p_colonies == NULL) || (p_colonies->Items == NULL) || + (tile_building_id > p_colonies->LastIndex)) + return true; + + Tile_Building_Body * colony_body = p_colonies->Items[tile_building_id].Object; + if ((colony_body == NULL) || ((int)colony_body == offsetof (Tile_Building, Body))) + return true; + + return colony_body->OwnerID == tile->vtable->m38_Get_Territory_OwnerID (tile); +} + +int __fastcall +patch_Leader_get_attitude_toward (Leader * this, int edx, int civ_id, int param_2) +{ + int score = Leader_get_attitude_toward (this, __, civ_id, param_2); + if (!is->current_config.allow_extraterritorial_colonies) + return score; + + int penalty = is->current_config.per_extraterritorial_colony_relation_penalty; + if (penalty != 0) { + int this_civ_id = this->ID; + if ((p_colonies != NULL) && (p_colonies->Items != NULL)) { + for (int n = 0; n <= p_colonies->LastIndex; n++) { + Tile_Building_Body * colony_body = p_colonies->Items[n].Object; + if ((colony_body == NULL) || + ((int)colony_body == offsetof (Tile_Building, Body))) + continue; + + Tile * tile = tile_at (colony_body->X, colony_body->Y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != this_civ_id) + continue; + if (colony_body->OwnerID != civ_id) + continue; + score -= penalty; + } + } + } + return score; +} + +void __fastcall +patch_UnitIDList_insert_after_init (UnitIDList * this, int edx, int id, UnitIDItem * item) +{ + // If using non-standard unit cycling, avoid calling this method b/c it sometimes causes a crash + if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) + UnitIDList_insert_after (this, __, id, item); +} + +bool __fastcall +patch_Tile_m17_Check_Irrigation (Tile * this, int edx, int visible_to_civ_id) +{ + bool base = Tile_m17_Check_Irrigation (this, __, visible_to_civ_id); + if (base) + return true; + + if (! is->current_config.enable_districts) + return base; + + struct district_instance * inst = get_district_instance (this); + if (inst == NULL) + return base; + + if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (this, inst->district_id)) + return true; + + return base; +} + +int __fastcall +patch_Unit_ai_eval_bombard_target (Unit * this, int edx, int tile_x, int tile_y, int param_3) +{ + int score = Unit_ai_eval_bombard_target (this, __, tile_x, tile_y, param_3); + + if (! (is->current_config.enable_districts && + is->current_config.enable_great_wall_districts)) + return score; + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return score; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID) || (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID))) + return score; + + int obsolete_id = is->district_infos[GREAT_WALL_DISTRICT_ID].obsoleted_by_id; + if ((obsolete_id >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, obsolete_id)) + return score; + + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_id <= 0) || (owner_id == this->Body.CivID)) + return score; + if (! this->vtable->is_enemy_of_civ (this, __, owner_id, false)) + return score; + + bool has_unit_on_tile = false; + bool has_enemy_on_tile = false; + Leader * me = &leaders[this->Body.CivID]; + FOR_UNITS_ON (uti, tile) { + UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; + if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0)) { + has_unit_on_tile = true; + if (me->At_War[uti.unit->Body.CivID]) { + if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { + has_enemy_on_tile = true; + break; + } + } else + break; + } + } + + if (has_unit_on_tile && ! has_enemy_on_tile) + return score; + + // Boost score to prioritize Great Wall targets + if (score < 0x6000) + score = 0x6000; + + // Additional boost if there is no unit on it, more likely to destroy it + if (! has_enemy_on_tile) + score += 0x200; + + return score; +} + +void __fastcall +patch_Unit_heal_at_start_of_turn (Unit * this) +{ + if (is->current_config.enable_districts) { + Tile * tile = tile_at ((this->Body).X, (this->Body).Y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id) && + is->district_configs[inst->district_id].heal_units_in_one_turn) { + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (territory_owner == this->Body.CivID) { + (this->Body).Damage = 0; + return; + } + } + } + } + + Unit_heal_at_start_of_turn (this); +} + +// Makes naval AI treat enemy port districts as valid targets to path toward. +int __cdecl +patch_get_tile_occupier_id_in_Unit_ai_move_naval_power_unit (int x, int y, int pov_civ_id, bool respect_unit_invisibility) +{ + int base = get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); + if (base != -1) + return base; + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return -1; + + Tile * tile = tile_at (x, y); + if (tile == NULL || tile == p_null_tile) + return -1; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return -1; + + return (*tile->vtable->m38_Get_Territory_OwnerID) (tile); +} + +// Returns a non-zero score for enemy port district tiles so they pass the threshold check and are bombard targets +int __fastcall +patch_Fighter_eval_tile_vulnerability_in_Unit_ai_move_naval_power_unit (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) +{ + int base = Fighter_eval_tile_vulnerability (this, __, unit, tile_x, tile_y); + if (base > 0) + return base; + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if (tile == NULL || tile == p_null_tile) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return base; + + int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); + if (owner <= 0 || owner == unit->Body.CivID) + return base; + + if (! leaders[unit->Body.CivID].At_War[owner]) + return base; + + // Return a score high enough to pass threshold (iVar13 * 8 + 0x100) + // 0x300 should be sufficient for most cases + return 0x300; +} + +// Returns the territory owner for enemy port districts so the score isn't reduced and naval units move to enemy ports +// (to subsequently pillage them) +int __cdecl +patch_get_combat_occupier_in_Unit_ai_move_naval_power_unit (int tile_x, int tile_y, int civ_id, byte ignore_visibility) +{ + int base = get_combat_occupier (tile_x, tile_y, civ_id, ignore_visibility); + if (base != -1) + return base; + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if (tile == NULL || tile == p_null_tile) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return base; + + int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); + if (owner <= 0 || owner == civ_id) + return base; + + if (! leaders[civ_id].At_War[owner]) + return base; + + return owner; +} + +int __fastcall +patch_rand_int_to_enslave (void * this, int edx, int lim) +{ + // lim is 100, enslaving happens if the return value is < 33 + int r = rand_int (this, __, lim); + return is->do_not_enslave_units ? 100 : r; +} + +int __fastcall +patch_Sprite_draw_espionage_screen_target_civ_bkg (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + // Figure out which of the potential target civs we're drawing by working backwards from the Y location + int top = (p_bic_data->ScreenHeight - p_espionage_form->Image.Height) / 2; + is->espionage_form_drawing_target_index = (pixel_y - top - 0x5C) / 0x3a + p_espionage_form->field_1584; + + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +char * __fastcall +patch_Civilopedia_Article_get_name_for_esp_screen (Civilopedia_Article * this) +{ + // Ensure that we have captured a valid civ ID being drawn then, if that civ has an era-specific formal name, return that so that the + // era-specific names apply on the espionage screen. + int target_civ_id; + if (is->espionage_form_drawing_target_index >= 0 && + is->espionage_form_drawing_target_index < p_espionage_form->target_civ_id_count && + (target_civ_id = p_espionage_form->target_civ_ids[is->espionage_form_drawing_target_index]) >= 0 && + target_civ_id < 32 && + is->aliased_civ_formal_name_bits & 1<Name.S; +} + +void __fastcall +patch_Animator_play_one_shot_victory_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) +{ + if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Air && is->current_config.aircraft_victory_animation != NULL) { + struct string_slice slice = {.str = is->current_config.aircraft_victory_animation, .len = strlen (is->current_config.aircraft_victory_animation)}; + find_animation_type_by_name (&slice, true, &anim_type); + } + + Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); +} + +void +clear_selectable_units_list (Main_Screen_Form * main_screen_form, bool include_unit_objects) +{ + // This is what the base game does to clear things at the start of assemble_selectable_units + if (include_unit_objects && p_units->Units != NULL) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if (unit != NULL) + unit->Body.in_selectable_units_list = false; + } + UnitIDItem * item = main_screen_form->selectable_units.first; + while (item != NULL) { + UnitIDItem * next = item->next; + item->vtable->destruct (item, __, 1); + item = next; + } + main_screen_form->selectable_units.first = main_screen_form->selectable_units.last = NULL; + main_screen_form->selectable_units.length = 0; +} + +void __fastcall +patch_Main_Screen_Form_assemble_selectable_units (Main_Screen_Form * this) +{ + if (is->have_loaded_waiting_units) + is->have_loaded_waiting_units = false; + else + table_deinit (&is->waiting_units); + + if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) + Main_Screen_Form_assemble_selectable_units (this); + else { + clear_selectable_units_list (this, true); + this->unit_cycle_cursor = NULL; + this->completed_unit_cycle = false; + } +} + +void __fastcall +patch_Main_Screen_Form_set_selected_unit (Main_Screen_Form * this, int edx, Unit * unit, bool param_2) +{ + // To set a unit to wait, Main_Screen_Form::issue_command calls this method with unit == NULL and param_2 == false. Detect when that's + // happened and record that the unit's been set to wait so we can reimplement the wait command when replacing the base unit cycling logic. + int * p_stack = (int *)&unit; + int ret_addr = p_stack[-1]; + if (ret_addr == SET_SELECTED_UNIT_TO_ISSUE_WAIT_COMMAND_RET && unit == NULL && this->Current_Unit != NULL) { + // Give the unit a waiting level higher than the minimum among all units already set to wait. This ensures that this unit does not get + // immediately picked up again by the cycling logic unless it's the only selectable unit left. This also means that the first unit set + // to wait will be the first cycled to once all the non-waiting units have been moved (it's the only one at level 1). I consider that + // an advantage. + int min_others_waiting_level = INT_MAX; + bool any_others_waiting = false; + FOR_TABLE_ENTRIES (tei, &is->waiting_units) + if (tei.key != this->Current_Unit->Body.ID) { + any_others_waiting = true; + if (tei.value < min_others_waiting_level) + min_others_waiting_level = tei.value; + } + itable_insert (&is->waiting_units, this->Current_Unit->Body.ID, any_others_waiting ? min_others_waiting_level + 1 : 1); + } + + if (unit != NULL) { + is->last_selected_unit.initial_x = is->last_selected_unit.last_x = unit->Body.X; + is->last_selected_unit.initial_y = is->last_selected_unit.last_y = unit->Body.Y; + is->last_selected_unit.type_id = unit->Body.UnitTypeID; + is->last_selected_unit.ptr = unit; + itable_remove (&is->waiting_units, unit->Body.ID); // Clear waiting record when waiting unit is selected + } + + if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD) + clear_selectable_units_list (this, false); + + bool redraw = false; + if (is->current_config.show_ai_city_location_desirability_if_settler) { + int new_perspective = -1; + if (unit != NULL) { + int unit_type_id = unit->Body.UnitTypeID; + int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; + new_perspective = (worker_actions >= 1 && (worker_actions & (UCV_Build_City)) && !is_worker(unit)) ? p_main_screen_form->Player_CivID : -1; + } + + if (new_perspective != is->city_loc_display_perspective) { + is->city_loc_display_perspective = new_perspective; + redraw = true; + } + } + + Main_Screen_Form_set_selected_unit (this, __, unit, param_2); + + // If selecting a new unit, must insert it into the list to ensure it's actually selected. + if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && unit != NULL) { + UnitIDList_insert_before (&this->selectable_units, __, unit->Body.ID, NULL); + this->unit_cycle_cursor = this->selectable_units.first; + } + + if (redraw && ! this->is_now_loading_game) + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +Unit * __fastcall +patch_Main_Screen_Form_find_next_unit_for_cycling (Main_Screen_Form * this) +{ + if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) + return Main_Screen_Form_find_next_unit_for_cycling (this); + + else { + int least_difference = INT_MAX; + Unit * least_different_unit = NULL; + int sx = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_x : is->last_selected_unit.last_x, + sy = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_y : is->last_selected_unit.last_y; + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if (unit != NULL && unit->Body.CivID == this->Player_CivID && Unit_can_cycle_to (unit)) { + int distance = not_above (1<<15, int_abs (unit->Body.X - sx) + int_abs (unit->Body.Y - sy)); + + bool other_type, not_duplicate; { + if (is->last_selected_unit.type_id == unit->Body.UnitTypeID) { + other_type = false; + if (is->last_selected_unit.ptr != NULL) + not_duplicate = ! are_units_duplicate (&is->last_selected_unit.ptr->Body, &unit->Body, false); + else + not_duplicate = true; + } else + other_type = not_duplicate = true; + } + + int wait_level = itable_look_up_or (&is->waiting_units, unit->Body.ID, 0); + + int difference = ((int)wait_level << 20) + (distance << 2) + ((int)other_type << 1) + (int)not_duplicate; + if (difference < least_difference) { + least_difference = difference; + least_different_unit = unit; + } + } + } + this->completed_unit_cycle = least_different_unit == NULL; + return least_different_unit; + } +} + +void __fastcall +patch_City_m22 (City * this, int edx, bool param_1) +{ + int * p_stack = (int *)¶m_1; + int ret_addr = p_stack[-1]; + + City_m22 (this, __, param_1); + + // If the base game method failed to find a new thing for city to build, we've been called by the methods that complete a previous build, and + // the city is owned by the UI controller, the game will crash because there will be no default option for the build selector popup. If we're + // configured to fix that, suggest Wealth for the new build or, failing that, any buildable unit or improvement. + if ( this->Body.Order_Type == 0 + && is->current_config.patch_failure_to_find_new_city_build + && this->Body.CivID == p_main_screen_form->Player_CivID + && ( ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_1 + || ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_2 + || ret_addr == CITY_M22_TO_SPAWN_UNIT_IF_DONE_RETURN)) { + + // Search for an improvement-type order we can build. Choose Wealth if possible, otherwise just pick the first thing that can be built + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (patch_City_can_build_improvement (this, __, n, true)) { + if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { + this->Body.Order_Type = COT_Improvement; + this->Body.Order_ID = n; + break; + } else if (this->Body.Order_Type == 0) { + this->Body.Order_Type = COT_Improvement; + this->Body.Order_ID = n; + } + } + + // If we still don't have a build, pick the first buildable unit + if (this->Body.Order_Type == 0) + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) + if (patch_City_can_build_unit (this, __, n, true, 0, false)) { + this->Body.Order_Type = COT_Unit; + this->Body.Order_ID = n; + break; + } + } +} + +int __fastcall +patch_PCX_Image_process_dom_adv_turn_count_text (PCX_Image * this, int edx, char * str) +{ + if (is->current_config.reformat_turns_remaining_on_domestic_advisor_screen) { + char * start = strstr (str, p_advisor_internal_form->Labels[16].S); // Search for "turns" + if (start == NULL) + start = strstr (str, p_advisor_internal_form->Labels[17].S); // Search for "turn" + + if (start != NULL) { + *start = toupper (*start); // Upcase first letter of "turn/s" + + char s[64]; // Must be same size as "str" param, which is a 64-byte stack-allocated string + snprintf (s, sizeof s, "%.*s %s", start - str, str, start); // Reprint string with space before "Turn/s" + s[(sizeof s) - 1] = '\0'; + memcpy (str, s, sizeof s); + } + } + + return PCX_Image_process_text (this, __, str); +} + +int +compare_menu_unit_items (void const * a, void const * b) +{ + return MenuUnitItem_should_appear_after ((MenuUnitItem *)a, __, (MenuUnitItem *)b) ? 1 : -1; +} + +int __fastcall +patch_MenuUnitList_get_length_before_sorting (MenuUnitList * this) +{ + int length = MenuUnitList_get_length (this); + + if (is->current_config.patch_passengers_out_of_order_on_menu && length > 0) { + qsort (this->items, length, sizeof this->items[0], compare_menu_unit_items); + + // Fix any units not being listed immediately after the unit they're contained in + // First, loop over all units in the list, stopping at each that might contain others + for (int n = 0; n < length - 1; n++) { + Unit * container = this->items[n].unit; + if ((int)container > 1 && // original code checks if unit ptrs are NULL or equal to 1 + p_bic_data->UnitTypes[container->Body.UnitTypeID].Transport_Capacity > 0) { + + // Advance iterator "j" past the container and past any empty slots or correctly positioned units right after it + int j = n + 1; + while (j < length && ((int)this->items[j].unit <= 1 || this->items[j].unit->Body.Container_Unit == container->Body.ID)) + j++; + + // Check the rest of the list for out-of-place passengers + for (int k = j + 1; k < length; k++) { + if ((int)this->items[k].unit > 1 && this->items[k].unit->Body.Container_Unit == container->Body.ID) { + + // Move item from index "k" to index "j" and advance "j" past it + MenuUnitItem moved = this->items[k]; + memmove (&this->items[j + 1], &this->items[j], (k - j) * sizeof this->items[0]); + this->items[j] = moved; + j++; + } + } + } + } + + // The caller is checking if the length is > 0 before sorting the list. Since we've already sorted it, return 0. + return 0; + } else + return length; +} + +void __fastcall +patch_Map_finalize_params_for_scenario_map (Map * this) +{ + Map_finalize_params (this); + + enum barbarian_activity_override barb_override = is->current_config.override_barbarian_activity_level_for_scenario_maps; + if (barb_override != BAO_NONE) { + if (barb_override == BAO_RANDOM) { + LARGE_INTEGER time; + QueryPerformanceCounter (&time); + int r = this->Seed ^ time.u.LowPart; // The map seed will be the same every time so incorporate some entropy + this->World.Final_Barbarians_Activity = rand_int (&r, __, 5) - 1; + } else + this->World.Final_Barbarians_Activity = clamp (-1, 3, barb_override); + } +} + +Unit * __fastcall +patch_Unit_select_army_member_for_combat (Unit * this, int edx, int param_1, char param_2) +{ + if (is->current_config.patch_empty_army_combat_crash) { + int unit_count = 0; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + if (tile != NULL && tile != p_null_tile) { + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit != NULL) && (unit->Body.Container_Unit == this->Body.ID)) + unit_count += Unit_count_contained_units (unit) + 1; + } + } + if (unit_count == 0) + return this; + } + + return Unit_select_army_member_for_combat (this, __, param_1, param_2); +} + +int __fastcall +patch_Tile_check_water_for_canal_move_to_adjacent_tile_dest (Tile * this) +{ + if ((this != NULL) && (this != p_null_tile) && + is->current_config.enable_districts && + is->current_config.enable_canal_districts && + (is->coast_walk_unit != NULL) && + (p_bic_data->UnitTypes[is->coast_walk_unit->Body.UnitTypeID].Unit_Class == UTC_Sea)) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && + (inst->district_id == CANAL_DISTRICT_ID) && + district_is_complete (this, inst->district_id)) + return 1; + } + + return this->vtable->m35_Check_Is_Water (this); +} + +// TCC requires a main function be defined even though it's never used. +int main () { return 0; } diff --git a/lend/README.md b/lend/README.md index 6b7e24b5..bf970936 100644 --- a/lend/README.md +++ b/lend/README.md @@ -1,31 +1,31 @@ -lend -==== - -Tiny x86 Length Disassembler - -The inspiration for the design of this x86 length disassembler came from -Zdisasm by Z0MBiE (I can't actually find this on his page but it's around, -just google code search for zdisasm.h) and three ideas presented nicely in a -single forum thread: - -http://www.devmaster.net/forums/showthread.php?t=2311 - -The three ideas came from the following posts: - -1. The original post by Nick (a purely logical length disassembler) -2. The post by earlnsk (a Russian switch case length disassembler) - The Russian length disassembler can be found here: - http://hack-expo.void.ru/groups/blt/text/disasm.txt (Russian) - http://z0mbie.daemonlab.org/disasme.txt (English) -3. The post by WolfgangSt (bitmap lookup tables) - -With these ideas I decided to make a tiny length disassemler in c. - -My length disassembler can use logical statements or lookup tables (32 byte -bitmap tables) to perform the checks required to determine instruction length. -Currently the smallest footprint I have managed is 589 bytes (LengthDisasm -function length + 4x32 byte lookup tables). I'm sure there are further -optimizations possible (even without using assembly). - -I haven't looked into it too much but I don't think it would to too difficult -to adapt this approach for x86_64. +lend +==== + +Tiny x86 Length Disassembler + +The inspiration for the design of this x86 length disassembler came from +Zdisasm by Z0MBiE (I can't actually find this on his page but it's around, +just google code search for zdisasm.h) and three ideas presented nicely in a +single forum thread: + +http://www.devmaster.net/forums/showthread.php?t=2311 + +The three ideas came from the following posts: + +1. The original post by Nick (a purely logical length disassembler) +2. The post by earlnsk (a Russian switch case length disassembler) + The Russian length disassembler can be found here: + http://hack-expo.void.ru/groups/blt/text/disasm.txt (Russian) + http://z0mbie.daemonlab.org/disasme.txt (English) +3. The post by WolfgangSt (bitmap lookup tables) + +With these ideas I decided to make a tiny length disassemler in c. + +My length disassembler can use logical statements or lookup tables (32 byte +bitmap tables) to perform the checks required to determine instruction length. +Currently the smallest footprint I have managed is 589 bytes (LengthDisasm +function length + 4x32 byte lookup tables). I'm sure there are further +optimizations possible (even without using assembly). + +I haven't looked into it too much but I don't think it would to too difficult +to adapt this approach for x86_64. diff --git a/lend/ld32.c b/lend/ld32.c index bd21689e..50885525 100644 --- a/lend/ld32.c +++ b/lend/ld32.c @@ -1,80 +1,80 @@ -/* -x86 Length Disassembler. -Copyright (C) 2013 Byron Platt - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "ld32.h" - -/* length_disasm */ -unsigned int length_disasm(void * opcode0) { - - unsigned char* opcode = opcode0; - - unsigned int flag = 0; - unsigned int ddef = 4, mdef = 4; - unsigned int msize = 0, dsize = 0; - - unsigned char op, modrm, mod, rm; - -prefix: - op = *opcode++; - - /* prefix */ - if (CHECK_PREFIX(op)) { - if (CHECK_PREFIX_66(op)) ddef = 2; - else if (CHECK_PREFIX_67(op)) mdef = 2; - goto prefix; - } - - /* two byte opcode */ - if (CHECK_0F(op)) { - op = *opcode++; - if (CHECK_MODRM2(op)) flag++; - if (CHECK_DATA12(op)) dsize++; - if (CHECK_DATA662(op)) dsize += ddef; - } - - /* one byte opcode */ - else { - if (CHECK_MODRM(op)) flag++; - if (CHECK_TEST(op) && !(*opcode & 0x38)) dsize += (op & 1) ? ddef : 1; - if (CHECK_DATA1(op)) dsize++; - if (CHECK_DATA2(op)) dsize += 2; - if (CHECK_DATA66(op)) dsize += ddef; - if (CHECK_MEM67(op)) msize += mdef; - } - - /* modrm */ - if (flag) { - modrm = *opcode++; - mod = modrm & 0xc0; - rm = modrm & 0x07; - if (mod != 0xc0) { - if (mod == 0x40) msize++; - if (mod == 0x80) msize += mdef; - if (mdef == 2) { - if ((mod == 0x00) && (rm == 0x06)) msize += 2; - } else { - if (rm == 0x04) rm = *opcode++ & 0x07; - if (rm == 0x05 && mod == 0x00) msize += 4; - } - } - } - - opcode += msize + dsize; - - return opcode - (unsigned char *)opcode0; -} +/* +x86 Length Disassembler. +Copyright (C) 2013 Byron Platt + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "ld32.h" + +/* length_disasm */ +unsigned int length_disasm(void * opcode0) { + + unsigned char* opcode = opcode0; + + unsigned int flag = 0; + unsigned int ddef = 4, mdef = 4; + unsigned int msize = 0, dsize = 0; + + unsigned char op, modrm, mod, rm; + +prefix: + op = *opcode++; + + /* prefix */ + if (CHECK_PREFIX(op)) { + if (CHECK_PREFIX_66(op)) ddef = 2; + else if (CHECK_PREFIX_67(op)) mdef = 2; + goto prefix; + } + + /* two byte opcode */ + if (CHECK_0F(op)) { + op = *opcode++; + if (CHECK_MODRM2(op)) flag++; + if (CHECK_DATA12(op)) dsize++; + if (CHECK_DATA662(op)) dsize += ddef; + } + + /* one byte opcode */ + else { + if (CHECK_MODRM(op)) flag++; + if (CHECK_TEST(op) && !(*opcode & 0x38)) dsize += (op & 1) ? ddef : 1; + if (CHECK_DATA1(op)) dsize++; + if (CHECK_DATA2(op)) dsize += 2; + if (CHECK_DATA66(op)) dsize += ddef; + if (CHECK_MEM67(op)) msize += mdef; + } + + /* modrm */ + if (flag) { + modrm = *opcode++; + mod = modrm & 0xc0; + rm = modrm & 0x07; + if (mod != 0xc0) { + if (mod == 0x40) msize++; + if (mod == 0x80) msize += mdef; + if (mdef == 2) { + if ((mod == 0x00) && (rm == 0x06)) msize += 2; + } else { + if (rm == 0x04) rm = *opcode++ & 0x07; + if (rm == 0x05 && mod == 0x00) msize += 4; + } + } + } + + opcode += msize + dsize; + + return opcode - (unsigned char *)opcode0; +} diff --git a/lend/ld32.h b/lend/ld32.h index ac19a8bd..c29434e3 100644 --- a/lend/ld32.h +++ b/lend/ld32.h @@ -1,254 +1,254 @@ -/* -x86 Length Disassembler. -Copyright (C) 2013 Byron Platt - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#ifndef __LD32_H__ -#define __LD32_H__ - -/* implemented tables */ -#define PREFIX_T 1 -#define MODRM2_T 2 -#define MODRM_T 4 -#define DATA1_T 8 -#define DATA2_T 16 -#define DATA66_T 32 - -/* configure tables */ -#ifndef USE_T -#define USE_T (MODRM2_T|MODRM_T|DATA1_T|DATA66_T) -#endif - -/* length_disasm */ -unsigned int length_disasm(void* opcode0); - -/* table macros */ -#ifdef USE_T -#define BITMASK32( \ - b00,b01,b02,b03,b04,b05,b06,b07, \ - b08,b09,b0a,b0b,b0c,b0d,b0e,b0f, \ - b10,b11,b12,b13,b14,b15,b16,b17, \ - b18,b19,b1a,b1b,b1c,b1d,b1e,b1f \ -) ( \ - (b00<<0x00)|(b01<<0x01)|(b02<<0x02)|(b03<<0x03)| \ - (b04<<0x04)|(b05<<0x05)|(b06<<0x06)|(b07<<0x07)| \ - (b08<<0x08)|(b09<<0x09)|(b0a<<0x0a)|(b0b<<0x0b)| \ - (b0c<<0x0c)|(b0d<<0x0d)|(b0e<<0x0e)|(b0f<<0x0f)| \ - (b10<<0x10)|(b11<<0x11)|(b12<<0x12)|(b13<<0x13)| \ - (b14<<0x14)|(b15<<0x15)|(b16<<0x16)|(b17<<0x17)| \ - (b18<<0x18)|(b19<<0x19)|(b1a<<0x1a)|(b1b<<0x1b)| \ - (b1c<<0x1c)|(b1d<<0x1d)|(b1e<<0x1e)|(b1f<<0x1f) \ -) -#define CHECK_TABLE(t, v) ((t[(v)>>5]>>((v)&0x1f))&1) -#endif - -/* CHECK_PREFIX */ -#if defined(USE_T) && (USE_T & PREFIX_T) -const static unsigned int prefix_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ - BITMASK32(0,0,0,0,0,0,1,0, 0,0,0,0,0,0,1,0, /* 2 */ - 0,0,0,0,0,0,1,0, 0,0,0,0,0,0,1,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,0,0,1,1,1,1, 0,0,0,0,0,0,0,0, /* 6 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* c */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ - 1,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ -}; -#define CHECK_PREFIX(v) CHECK_TABLE(prefix_t, v) -#else -#define CHECK_PREFIX(v) \ - (((v)&0xe7)==0x26||((v)&0xfc)==0x64||(v)==0xf0||(v)==0xf2||(v)==0xf3) -#endif - -/* CHECK_PREFIX_66 */ -#define CHECK_PREFIX_66(v) ((v)==0x66) - -/* CHECK_PREFIX_67 */ -#define CHECK_PREFIX_67(v) ((v)==0x67) - -/* CHECK_0F */ -#define CHECK_0F(v) ((v)==0x0f) - -/* CHECK_MODRM2 */ -#if defined(USE_T) && (USE_T & MODRM2_T) -const static unsigned int modrm2_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(1,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 2 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 6 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1), /* 9 */ - BITMASK32(0,0,0,1,1,1,0,0, 0,0,0,1,1,1,0,1, /* a */ - 1,1,1,1,1,1,1,1, 0,0,1,1,1,1,1,1), /* b */ - BITMASK32(1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* c */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ -}; -#define CHECK_MODRM2(v) CHECK_TABLE(modrm2_t, v) -#else -#define CHECK_MODRM2(v) (__extension__ ({ \ - register BYTE __a=(v)&0xfc, __b=(v)&0xfe; \ - ((v)&0xf0)==0x90||((v)&0xf8)==0xb0||((v)&0xf6)==0xa4|| \ - __a==0x00||__a==0xbc||__b==0xba||__b==0xc0|| \ - (v)==0xa3||(v)==0xab||(v)==0xaf; \ -})) -#endif - -/* CHECK_DATA12 */ -#define CHECK_DATA12(v) ((v)==0xa4||(v)==0xac||(v)==0xba) - -/* CHECK_DATA662 */ -#define CHECK_DATA662(v) (((v)&0xf0)==0x80) - -/* CHECK_MODRM */ -#if defined(USE_T) && (USE_T & MODRM_T) -const static unsigned int modrm_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0, /* 0 */ - 1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0), /* 1 */ - BITMASK32(1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0, /* 2 */ - 1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,1,1,0,0,0,0, 0,1,0,1,0,0,0,0, /* 6 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ - BITMASK32(1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, /* 8 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ - BITMASK32(1,1,0,0,1,1,1,1, 0,0,0,0,0,0,0,0, /* c */ - 1,1,1,1,0,0,0,0, 1,1,1,1,1,1,1,1), /* d */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ - 0,0,0,0,0,0,1,1, 0,0,0,0,0,0,1,1) /* f */ -}; -#define CHECK_MODRM(v) CHECK_TABLE(modrm_t, v) -#else -#define CHECK_MODRM(v) (__extension__ ({ \ - register BYTE __a=(v)&0xfc, __b=(v)&0xfe; \ - ((v)&0xc4)==0x00||((v)&0xf0)==0x80||((v)&0xf8)==0xd8||((v)&0xf6)==0xf6|| \ - __a==0xc4||__a==0xd0||__b==0x62||__b==0xc0|| \ - (v)==0x69||(v)==0x6b; \ -})) -#endif - -/* CHECK_TEST */ -#define CHECK_TEST(v) ((v)==0xf6||(v)==0xf7) - -/* CHECK_DATA1 */ -#if defined(USE_T) && (USE_T & DATA1_T) -const static unsigned int data1_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0, /* 0 */ - 0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0), /* 1 */ - BITMASK32(0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0, /* 2 */ - 0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,1,1,0,0,0,0, /* 6 */ - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1), /* 7 */ - BITMASK32(1,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ - BITMASK32(0,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0, /* a */ - 1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0), /* b */ - BITMASK32(1,1,0,0,0,0,1,0, 1,0,0,0,0,1,0,0, /* c */ - 0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0), /* d */ - BITMASK32(1,1,1,1,1,1,1,1, 0,0,0,1,0,0,0,0, /* e */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ -}; -#define CHECK_DATA1(v) CHECK_TABLE(data1_t, v) -#else -#define CHECK_DATA1(v) (__extension__ ({ \ - register BYTE __a=(v)&0xf8, __b=(v)&0xfe; \ - ((v)&0xf0)==0x70||((v)&0xc7)==0x04|| \ - __a==0xb0||__a==0xe0||__b==0x6a||__b==0x82||__b==0xc0||__b==0xd4|| \ - (v)==0x80||(v)==0xa8||(v)==0xc6||(v)==0xc8||(v)==0xcd||(v)==0xeb; \ -})) -#endif - -/* CHECK_DATA2 */ -#if defined(USE_T) && (USE_T & DATA2_T) -const static unsigned int data2_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 2 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 6 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ - 0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0), /* 9 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ - BITMASK32(0,0,1,0,0,0,0,0, 1,0,1,0,0,0,0,0, /* c */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0, /* e */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ -}; -#define CHECK_DATA2(v) CHECK_TABLE(data2_t, v) -#else -#define CHECK_DATA2(v) \ - ((v)==0x9a||(v)==0xc2||(v)==0xc8||(v)==0xca||(v)==0xea) -#endif - -/* CHECK_DATA66 */ -#if defined(USE_T) && (USE_T & DATA66_T) -const static unsigned int data66_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0, /* 0 */ - 0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0), /* 1 */ - BITMASK32(0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0, /* 2 */ - 0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,0,0,0,0,0,0, 1,1,0,0,0,0,0,0, /* 6 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ - BITMASK32(0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ - 0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0), /* 9 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0, /* a */ - 0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1), /* b */ - BITMASK32(0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,0, /* c */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ - BITMASK32(0,0,0,0,0,0,0,0, 1,1,1,0,0,0,0,0, /* e */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ -}; -#define CHECK_DATA66(v) CHECK_TABLE(data66_t, v) -#else -#define CHECK_DATA66(v) \ - (((v)&0xc7)==0x05||((v)&0xf8)==0xb8||((v)&0x7e)==0x68|| \ - (v)==0x81||(v)==0x9a||(v)==0xa9||(v)==0xc7||(v)==0xea) -#endif - -/* CHECK_MEM67 */ -#define CHECK_MEM67(v) (((v)&0xfc)==0xa0) - -#endif +/* +x86 Length Disassembler. +Copyright (C) 2013 Byron Platt + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef __LD32_H__ +#define __LD32_H__ + +/* implemented tables */ +#define PREFIX_T 1 +#define MODRM2_T 2 +#define MODRM_T 4 +#define DATA1_T 8 +#define DATA2_T 16 +#define DATA66_T 32 + +/* configure tables */ +#ifndef USE_T +#define USE_T (MODRM2_T|MODRM_T|DATA1_T|DATA66_T) +#endif + +/* length_disasm */ +unsigned int length_disasm(void* opcode0); + +/* table macros */ +#ifdef USE_T +#define BITMASK32( \ + b00,b01,b02,b03,b04,b05,b06,b07, \ + b08,b09,b0a,b0b,b0c,b0d,b0e,b0f, \ + b10,b11,b12,b13,b14,b15,b16,b17, \ + b18,b19,b1a,b1b,b1c,b1d,b1e,b1f \ +) ( \ + (b00<<0x00)|(b01<<0x01)|(b02<<0x02)|(b03<<0x03)| \ + (b04<<0x04)|(b05<<0x05)|(b06<<0x06)|(b07<<0x07)| \ + (b08<<0x08)|(b09<<0x09)|(b0a<<0x0a)|(b0b<<0x0b)| \ + (b0c<<0x0c)|(b0d<<0x0d)|(b0e<<0x0e)|(b0f<<0x0f)| \ + (b10<<0x10)|(b11<<0x11)|(b12<<0x12)|(b13<<0x13)| \ + (b14<<0x14)|(b15<<0x15)|(b16<<0x16)|(b17<<0x17)| \ + (b18<<0x18)|(b19<<0x19)|(b1a<<0x1a)|(b1b<<0x1b)| \ + (b1c<<0x1c)|(b1d<<0x1d)|(b1e<<0x1e)|(b1f<<0x1f) \ +) +#define CHECK_TABLE(t, v) ((t[(v)>>5]>>((v)&0x1f))&1) +#endif + +/* CHECK_PREFIX */ +#if defined(USE_T) && (USE_T & PREFIX_T) +const static unsigned int prefix_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ + BITMASK32(0,0,0,0,0,0,1,0, 0,0,0,0,0,0,1,0, /* 2 */ + 0,0,0,0,0,0,1,0, 0,0,0,0,0,0,1,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,0,0,1,1,1,1, 0,0,0,0,0,0,0,0, /* 6 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* c */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ + 1,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ +}; +#define CHECK_PREFIX(v) CHECK_TABLE(prefix_t, v) +#else +#define CHECK_PREFIX(v) \ + (((v)&0xe7)==0x26||((v)&0xfc)==0x64||(v)==0xf0||(v)==0xf2||(v)==0xf3) +#endif + +/* CHECK_PREFIX_66 */ +#define CHECK_PREFIX_66(v) ((v)==0x66) + +/* CHECK_PREFIX_67 */ +#define CHECK_PREFIX_67(v) ((v)==0x67) + +/* CHECK_0F */ +#define CHECK_0F(v) ((v)==0x0f) + +/* CHECK_MODRM2 */ +#if defined(USE_T) && (USE_T & MODRM2_T) +const static unsigned int modrm2_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(1,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 2 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 6 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1), /* 9 */ + BITMASK32(0,0,0,1,1,1,0,0, 0,0,0,1,1,1,0,1, /* a */ + 1,1,1,1,1,1,1,1, 0,0,1,1,1,1,1,1), /* b */ + BITMASK32(1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* c */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ +}; +#define CHECK_MODRM2(v) CHECK_TABLE(modrm2_t, v) +#else +#define CHECK_MODRM2(v) (__extension__ ({ \ + register BYTE __a=(v)&0xfc, __b=(v)&0xfe; \ + ((v)&0xf0)==0x90||((v)&0xf8)==0xb0||((v)&0xf6)==0xa4|| \ + __a==0x00||__a==0xbc||__b==0xba||__b==0xc0|| \ + (v)==0xa3||(v)==0xab||(v)==0xaf; \ +})) +#endif + +/* CHECK_DATA12 */ +#define CHECK_DATA12(v) ((v)==0xa4||(v)==0xac||(v)==0xba) + +/* CHECK_DATA662 */ +#define CHECK_DATA662(v) (((v)&0xf0)==0x80) + +/* CHECK_MODRM */ +#if defined(USE_T) && (USE_T & MODRM_T) +const static unsigned int modrm_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0, /* 0 */ + 1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0), /* 1 */ + BITMASK32(1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0, /* 2 */ + 1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,1,1,0,0,0,0, 0,1,0,1,0,0,0,0, /* 6 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ + BITMASK32(1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, /* 8 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ + BITMASK32(1,1,0,0,1,1,1,1, 0,0,0,0,0,0,0,0, /* c */ + 1,1,1,1,0,0,0,0, 1,1,1,1,1,1,1,1), /* d */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ + 0,0,0,0,0,0,1,1, 0,0,0,0,0,0,1,1) /* f */ +}; +#define CHECK_MODRM(v) CHECK_TABLE(modrm_t, v) +#else +#define CHECK_MODRM(v) (__extension__ ({ \ + register BYTE __a=(v)&0xfc, __b=(v)&0xfe; \ + ((v)&0xc4)==0x00||((v)&0xf0)==0x80||((v)&0xf8)==0xd8||((v)&0xf6)==0xf6|| \ + __a==0xc4||__a==0xd0||__b==0x62||__b==0xc0|| \ + (v)==0x69||(v)==0x6b; \ +})) +#endif + +/* CHECK_TEST */ +#define CHECK_TEST(v) ((v)==0xf6||(v)==0xf7) + +/* CHECK_DATA1 */ +#if defined(USE_T) && (USE_T & DATA1_T) +const static unsigned int data1_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0, /* 0 */ + 0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0), /* 1 */ + BITMASK32(0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0, /* 2 */ + 0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,1,1,0,0,0,0, /* 6 */ + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1), /* 7 */ + BITMASK32(1,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ + BITMASK32(0,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0, /* a */ + 1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0), /* b */ + BITMASK32(1,1,0,0,0,0,1,0, 1,0,0,0,0,1,0,0, /* c */ + 0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0), /* d */ + BITMASK32(1,1,1,1,1,1,1,1, 0,0,0,1,0,0,0,0, /* e */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ +}; +#define CHECK_DATA1(v) CHECK_TABLE(data1_t, v) +#else +#define CHECK_DATA1(v) (__extension__ ({ \ + register BYTE __a=(v)&0xf8, __b=(v)&0xfe; \ + ((v)&0xf0)==0x70||((v)&0xc7)==0x04|| \ + __a==0xb0||__a==0xe0||__b==0x6a||__b==0x82||__b==0xc0||__b==0xd4|| \ + (v)==0x80||(v)==0xa8||(v)==0xc6||(v)==0xc8||(v)==0xcd||(v)==0xeb; \ +})) +#endif + +/* CHECK_DATA2 */ +#if defined(USE_T) && (USE_T & DATA2_T) +const static unsigned int data2_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 2 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 6 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ + 0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0), /* 9 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ + BITMASK32(0,0,1,0,0,0,0,0, 1,0,1,0,0,0,0,0, /* c */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0, /* e */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ +}; +#define CHECK_DATA2(v) CHECK_TABLE(data2_t, v) +#else +#define CHECK_DATA2(v) \ + ((v)==0x9a||(v)==0xc2||(v)==0xc8||(v)==0xca||(v)==0xea) +#endif + +/* CHECK_DATA66 */ +#if defined(USE_T) && (USE_T & DATA66_T) +const static unsigned int data66_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0, /* 0 */ + 0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0), /* 1 */ + BITMASK32(0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0, /* 2 */ + 0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,0,0,0,0,0,0, 1,1,0,0,0,0,0,0, /* 6 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ + BITMASK32(0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ + 0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0), /* 9 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0, /* a */ + 0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1), /* b */ + BITMASK32(0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,0, /* c */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ + BITMASK32(0,0,0,0,0,0,0,0, 1,1,1,0,0,0,0,0, /* e */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ +}; +#define CHECK_DATA66(v) CHECK_TABLE(data66_t, v) +#else +#define CHECK_DATA66(v) \ + (((v)&0xc7)==0x05||((v)&0xf8)==0xb8||((v)&0x7e)==0x68|| \ + (v)==0x81||(v)==0x9a||(v)==0xa9||(v)==0xc7||(v)==0xea) +#endif + +/* CHECK_MEM67 */ +#define CHECK_MEM67(v) (((v)&0xfc)==0xa0) + +#endif diff --git a/tcc/include/_mingw.h b/tcc/include/_mingw.h index 3f227f22..35de395f 100644 --- a/tcc/include/_mingw.h +++ b/tcc/include/_mingw.h @@ -1,164 +1,164 @@ -/* - * _mingw.h - * - * This file is for TinyCC and not part of the Mingw32 package. - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef __MINGW_H -#define __MINGW_H - -/* some winapi files define these before including _mingw.h --> */ -#undef __cdecl -#undef _X86_ -#undef WIN32 -/* <-- */ - -#include -#include - -#define __int8 char -#define __int16 short -#define __int32 int -#define __int64 long long -#define _HAVE_INT64 - -#define __cdecl -#define __declspec(x) __attribute__((x)) -#define __unaligned __attribute__((packed)) -#define __fastcall __attribute__((fastcall)) - -#define __MSVCRT__ 1 -#undef _MSVCRT_ -#define __MINGW_IMPORT extern __declspec(dllimport) -#define __MINGW_ATTRIB_NORETURN __declspec(noreturn) -#define __MINGW_ATTRIB_CONST -#define __MINGW_ATTRIB_DEPRECATED -#define __MINGW_ATTRIB_MALLOC -#define __MINGW_ATTRIB_PURE -#define __MINGW_ATTRIB_NONNULL(arg) -#define __MINGW_NOTHROW -#define __GNUC_VA_LIST - -#define _CRTIMP extern -#define __CRT_INLINE static __inline__ - -#define _CRT_ALIGN(x) __attribute__((aligned(x))) -#define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) -#define _CRT_PACKING 8 -#define __CRT_UNALIGNED -#define _CONST_RETURN - -#ifndef _TRUNCATE -#define _TRUNCATE ((size_t)-1) -#endif - -#define __CRT_STRINGIZE(_Value) #_Value -#define _CRT_STRINGIZE(_Value) __CRT_STRINGIZE(_Value) -#define __CRT_WIDE(_String) L ## _String -#define _CRT_WIDE(_String) __CRT_WIDE(_String) - -#ifdef _WIN64 -#define __stdcall -#define _AMD64_ 1 -#define __x86_64 1 -#define _M_X64 100 /* Visual Studio */ -#define _M_AMD64 100 /* Visual Studio */ -#define USE_MINGW_SETJMP_TWO_ARGS -#define mingw_getsp tinyc_getbp -#else -#define __stdcall __attribute__((__stdcall__)) -#define _X86_ 1 -#define _M_IX86 300 /* Visual Studio */ -#define _USE_32BIT_TIME_T -#endif - -/* in stddef.h */ -#define _SIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#define _PTRDIFF_T_DEFINED -#define _WCHAR_T_DEFINED -#define _UINTPTR_T_DEFINED -#define _INTPTR_T_DEFINED -#define _INTEGRAL_MAX_BITS 64 - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED -typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -typedef long long __time64_t; -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T -typedef __time32_t time_t; -#else -typedef __time64_t time_t; -#endif -#endif - -#ifndef _WCTYPE_T_DEFINED -#define _WCTYPE_T_DEFINED -typedef wchar_t wctype_t; -#endif - -#ifndef _WINT_T -#define _WINT_T -typedef __WINT_TYPE__ wint_t; -#endif - -typedef int errno_t; -#define _ERRCODE_DEFINED - -typedef struct threadlocaleinfostruct *pthreadlocinfo; -typedef struct threadmbcinfostruct *pthreadmbcinfo; -typedef struct localeinfo_struct _locale_tstruct,*_locale_t; - -/* for winapi */ -#define _ANONYMOUS_UNION -#define _ANONYMOUS_STRUCT -#define DECLSPEC_NORETURN __declspec(noreturn) -#define DECLARE_STDCALL_P(type) __stdcall type -#define NOSERVICE 1 -#define NOMCX 1 -#define NOIME 1 -#define __INTRIN_H_ -#ifndef DUMMYUNIONNAME -# define DUMMYUNIONNAME -# define DUMMYUNIONNAME1 -# define DUMMYUNIONNAME2 -# define DUMMYUNIONNAME3 -# define DUMMYUNIONNAME4 -# define DUMMYUNIONNAME5 -#endif -#ifndef DUMMYSTRUCTNAME -# define DUMMYSTRUCTNAME -#endif -#ifndef WINVER -# define WINVER 0x0502 -#endif -#ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x502 -#endif - -#define __C89_NAMELESS -#define __MINGW_EXTENSION -#define WINAPI_FAMILY_PARTITION(X) 1 -#define MINGW_HAS_SECURE_API -#define WIN32 1 - -#endif /* __MINGW_H */ +/* + * _mingw.h + * + * This file is for TinyCC and not part of the Mingw32 package. + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __MINGW_H +#define __MINGW_H + +/* some winapi files define these before including _mingw.h --> */ +#undef __cdecl +#undef _X86_ +#undef WIN32 +/* <-- */ + +#include +#include + +#define __int8 char +#define __int16 short +#define __int32 int +#define __int64 long long +#define _HAVE_INT64 + +#define __cdecl +#define __declspec(x) __attribute__((x)) +#define __unaligned __attribute__((packed)) +#define __fastcall __attribute__((fastcall)) + +#define __MSVCRT__ 1 +#undef _MSVCRT_ +#define __MINGW_IMPORT extern __declspec(dllimport) +#define __MINGW_ATTRIB_NORETURN __declspec(noreturn) +#define __MINGW_ATTRIB_CONST +#define __MINGW_ATTRIB_DEPRECATED +#define __MINGW_ATTRIB_MALLOC +#define __MINGW_ATTRIB_PURE +#define __MINGW_ATTRIB_NONNULL(arg) +#define __MINGW_NOTHROW +#define __GNUC_VA_LIST + +#define _CRTIMP extern +#define __CRT_INLINE static __inline__ + +#define _CRT_ALIGN(x) __attribute__((aligned(x))) +#define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) +#define _CRT_PACKING 8 +#define __CRT_UNALIGNED +#define _CONST_RETURN + +#ifndef _TRUNCATE +#define _TRUNCATE ((size_t)-1) +#endif + +#define __CRT_STRINGIZE(_Value) #_Value +#define _CRT_STRINGIZE(_Value) __CRT_STRINGIZE(_Value) +#define __CRT_WIDE(_String) L ## _String +#define _CRT_WIDE(_String) __CRT_WIDE(_String) + +#ifdef _WIN64 +#define __stdcall +#define _AMD64_ 1 +#define __x86_64 1 +#define _M_X64 100 /* Visual Studio */ +#define _M_AMD64 100 /* Visual Studio */ +#define USE_MINGW_SETJMP_TWO_ARGS +#define mingw_getsp tinyc_getbp +#else +#define __stdcall __attribute__((__stdcall__)) +#define _X86_ 1 +#define _M_IX86 300 /* Visual Studio */ +#define _USE_32BIT_TIME_T +#endif + +/* in stddef.h */ +#define _SIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#define _PTRDIFF_T_DEFINED +#define _WCHAR_T_DEFINED +#define _UINTPTR_T_DEFINED +#define _INTPTR_T_DEFINED +#define _INTEGRAL_MAX_BITS 64 + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED +typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +typedef long long __time64_t; +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T +typedef __time32_t time_t; +#else +typedef __time64_t time_t; +#endif +#endif + +#ifndef _WCTYPE_T_DEFINED +#define _WCTYPE_T_DEFINED +typedef wchar_t wctype_t; +#endif + +#ifndef _WINT_T +#define _WINT_T +typedef __WINT_TYPE__ wint_t; +#endif + +typedef int errno_t; +#define _ERRCODE_DEFINED + +typedef struct threadlocaleinfostruct *pthreadlocinfo; +typedef struct threadmbcinfostruct *pthreadmbcinfo; +typedef struct localeinfo_struct _locale_tstruct,*_locale_t; + +/* for winapi */ +#define _ANONYMOUS_UNION +#define _ANONYMOUS_STRUCT +#define DECLSPEC_NORETURN __declspec(noreturn) +#define DECLARE_STDCALL_P(type) __stdcall type +#define NOSERVICE 1 +#define NOMCX 1 +#define NOIME 1 +#define __INTRIN_H_ +#ifndef DUMMYUNIONNAME +# define DUMMYUNIONNAME +# define DUMMYUNIONNAME1 +# define DUMMYUNIONNAME2 +# define DUMMYUNIONNAME3 +# define DUMMYUNIONNAME4 +# define DUMMYUNIONNAME5 +#endif +#ifndef DUMMYSTRUCTNAME +# define DUMMYSTRUCTNAME +#endif +#ifndef WINVER +# define WINVER 0x0502 +#endif +#ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x502 +#endif + +#define __C89_NAMELESS +#define __MINGW_EXTENSION +#define WINAPI_FAMILY_PARTITION(X) 1 +#define MINGW_HAS_SECURE_API +#define WIN32 1 + +#endif /* __MINGW_H */ diff --git a/tcc/include/assert.h b/tcc/include/assert.h index b15bb638..4fce450e 100644 --- a/tcc/include/assert.h +++ b/tcc/include/assert.h @@ -1,62 +1,62 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef __ASSERT_H_ -#define __ASSERT_H_ - -#include <_mingw.h> -#ifdef __cplusplus -#include -#endif - -#ifdef NDEBUG -#ifndef assert -#define assert(_Expression) ((void)0) -#endif -#else - -#ifndef _CRT_TERMINATE_DEFINED -#define _CRT_TERMINATE_DEFINED - void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; - _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; -#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ -/* C99 function name */ -void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; -__CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) -{ _exit(status); } -#endif - -#pragma push_macro("abort") -#undef abort - void __cdecl __declspec(noreturn) abort(void); -#pragma pop_macro("abort") - -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -extern void __cdecl _wassert(const wchar_t *_Message,const wchar_t *_File,unsigned _Line); -extern void __cdecl _assert(const char *, const char *, unsigned); - -#ifdef __cplusplus -} -#endif - -#ifndef assert -//#define assert(_Expression) (void)((!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression),_CRT_WIDE(__FILE__),__LINE__),0)) -#define assert(e) ((e) ? (void)0 : _assert(#e, __FILE__, __LINE__)) -#endif - -#endif - -#if (__STDC_VERSION__ >= 201112L) && !defined(static_assert) -/* C11, section 7.2: The macro static_assert expands to _Static_assert. */ -#define static_assert(exp, str) _Static_assert(exp, str) -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef __ASSERT_H_ +#define __ASSERT_H_ + +#include <_mingw.h> +#ifdef __cplusplus +#include +#endif + +#ifdef NDEBUG +#ifndef assert +#define assert(_Expression) ((void)0) +#endif +#else + +#ifndef _CRT_TERMINATE_DEFINED +#define _CRT_TERMINATE_DEFINED + void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; + _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; +#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ +/* C99 function name */ +void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; +__CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) +{ _exit(status); } +#endif + +#pragma push_macro("abort") +#undef abort + void __cdecl __declspec(noreturn) abort(void); +#pragma pop_macro("abort") + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +extern void __cdecl _wassert(const wchar_t *_Message,const wchar_t *_File,unsigned _Line); +extern void __cdecl _assert(const char *, const char *, unsigned); + +#ifdef __cplusplus +} +#endif + +#ifndef assert +//#define assert(_Expression) (void)((!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression),_CRT_WIDE(__FILE__),__LINE__),0)) +#define assert(e) ((e) ? (void)0 : _assert(#e, __FILE__, __LINE__)) +#endif + +#endif + +#if (__STDC_VERSION__ >= 201112L) && !defined(static_assert) +/* C11, section 7.2: The macro static_assert expands to _Static_assert. */ +#define static_assert(exp, str) _Static_assert(exp, str) +#endif + +#endif diff --git a/tcc/include/conio.h b/tcc/include/conio.h index 39f779eb..7a4c1f19 100644 --- a/tcc/include/conio.h +++ b/tcc/include/conio.h @@ -1,409 +1,409 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_CONIO -#define _INC_CONIO - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP char *_cgets(char *_Buffer); - _CRTIMP int __cdecl _cprintf(const char *_Format,...); - _CRTIMP int __cdecl _cputs(const char *_Str); - _CRTIMP int __cdecl _cscanf(const char *_Format,...); - _CRTIMP int __cdecl _cscanf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _getch(void); - _CRTIMP int __cdecl _getche(void); - _CRTIMP int __cdecl _vcprintf(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_p(const char *_Format,...); - _CRTIMP int __cdecl _vcprintf_p(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_p_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _kbhit(void); - -#if defined(_X86_) && !defined(__x86_64) - int __cdecl _inp(unsigned short); - unsigned short __cdecl _inpw(unsigned short); - unsigned long __cdecl _inpd(unsigned short); - int __cdecl _outp(unsigned short,int); - unsigned short __cdecl _outpw(unsigned short,unsigned short); - unsigned long __cdecl _outpd(unsigned short,unsigned long); -#endif - - _CRTIMP int __cdecl _putch(int _Ch); - _CRTIMP int __cdecl _ungetch(int _Ch); - _CRTIMP int __cdecl _getch_nolock(void); - _CRTIMP int __cdecl _getche_nolock(void); - _CRTIMP int __cdecl _putch_nolock(int _Ch); - _CRTIMP int __cdecl _ungetch_nolock(int _Ch); - -#ifndef _WCONIO_DEFINED -#define _WCONIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - - _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _getwch(void); - _CRTIMP wint_t __cdecl _getwche(void); - _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); - _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); - _CRTIMP int __cdecl _cputws(const wchar_t *_String); - _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP wint_t __cdecl _putwch_nolock(wchar_t _WCh); - _CRTIMP wint_t __cdecl _getwch_nolock(void); - _CRTIMP wint_t __cdecl _getwche_nolock(void); - _CRTIMP wint_t __cdecl _ungetwch_nolock(wint_t _WCh); -#endif - -#ifndef NO_OLDNAMES - char *__cdecl cgets(char *_Buffer); - int __cdecl cprintf(const char *_Format,...); - int __cdecl cputs(const char *_Str); - int __cdecl cscanf(const char *_Format,...); - int __cdecl getch(void); - int __cdecl getche(void); - int __cdecl kbhit(void); - int __cdecl putch(int _Ch); - int __cdecl ungetch(int _Ch); - -#if (defined(_X86_) && !defined(__x86_64)) - int __cdecl inp(unsigned short); - unsigned short __cdecl inpw(unsigned short); - int __cdecl outp(unsigned short,int); - unsigned short __cdecl outpw(unsigned short,unsigned short); -#endif - - /* I/O intrin functions. */ - __CRT_INLINE unsigned char __inbyte(unsigned short Port) - { - unsigned char value; - __asm__ __volatile__ ("inb %w1,%b0" - : "=a" (value) - : "Nd" (Port)); - return value; - } - __CRT_INLINE unsigned short __inword(unsigned short Port) - { - unsigned short value; - __asm__ __volatile__ ("inw %w1,%w0" - : "=a" (value) - : "Nd" (Port)); - return value; - } - __CRT_INLINE unsigned long __indword(unsigned short Port) - { - unsigned long value; - __asm__ __volatile__ ("inl %w1,%0" - : "=a" (value) - : "Nd" (Port)); - return value; - } - __CRT_INLINE void __outbyte(unsigned short Port,unsigned char Data) - { - __asm__ __volatile__ ("outb %b0,%w1" - : - : "a" (Data), "Nd" (Port)); - } - __CRT_INLINE void __outword(unsigned short Port,unsigned short Data) - { - __asm__ __volatile__ ("outw %w0,%w1" - : - : "a" (Data), "Nd" (Port)); - } - __CRT_INLINE void __outdword(unsigned short Port,unsigned long Data) - { - __asm__ __volatile__ ("outl %0,%w1" - : - : "a" (Data), "Nd" (Port)); - } - __CRT_INLINE void __inbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; insb " - : "=D" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __inwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; insw " - : "=D" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __indwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; insl " - : "=D" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - - __CRT_INLINE void __outbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; outsb " - : "=S" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __outwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; outsw " - : "=S" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __outdwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; outsl " - : "=S" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - - __CRT_INLINE unsigned __int64 __readcr0(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr0, %[value]" - : [value] "=q" (value)); - return value; - } - - /* Register sizes are different between 32/64 bit mode. So we have to do this for _WIN64 and _WIN32 - separately. */ - -#ifdef _WIN64 - __CRT_INLINE void __writecr0(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr0" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr2(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr2, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr2(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr2" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr3(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr3, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr3(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr3" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr4(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr4, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr4(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr4" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr8(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr8, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr8(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr8" - : - : [Data] "q" (Data) - : "memory"); - } - -#elif defined(_WIN32) - - __CRT_INLINE void __writecr0(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr0" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr2(void) - { - unsigned long value; - __asm__ __volatile__ ( - "mov %%cr2, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr2(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr2" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr3(void) - { - unsigned long value; - __asm__ __volatile__ ( - "mov %%cr3, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr3(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr3" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr4(void) - { - unsigned long value; - __asm__ __volatile__ ( - "mov %%cr4, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr4(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr4" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr8(void) - { - unsigned long value; __asm__ __volatile__ ( - "mov %%cr8, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr8(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr8" - : - : [Data] "q" (Data) - : "memory"); - } - -#endif - - __CRT_INLINE unsigned __int64 __readmsr(unsigned long msr) - { - unsigned __int64 val1, val2; - __asm__ __volatile__( - "rdmsr" - : "=a" (val1), "=d" (val2) - : "c" (msr)); - return val1 | (val2 << 32); - } - - __CRT_INLINE void __writemsr (unsigned long msr, unsigned __int64 Value) - { - unsigned long val1 = Value, val2 = Value >> 32; - __asm__ __volatile__ ( - "wrmsr" - : - : "c" (msr), "a" (val1), "d" (val2)); - } - - __CRT_INLINE unsigned __int64 __rdtsc(void) - { - unsigned __int64 val1, val2; - __asm__ __volatile__ ( - "rdtsc" - : "=a" (val1), "=d" (val2)); - return val1 | (val2 << 32); - } - - __CRT_INLINE void __cpuid(int CPUInfo[4], int InfoType) - { - __asm__ __volatile__ ( - "cpuid" - : "=a" (CPUInfo [0]), "=b" (CPUInfo [1]), "=c" (CPUInfo [2]), "=d" (CPUInfo [3]) - : "a" (InfoType)); - } - -#endif - -#ifdef __cplusplus -} -#endif - -#include - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_CONIO +#define _INC_CONIO + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP char *_cgets(char *_Buffer); + _CRTIMP int __cdecl _cprintf(const char *_Format,...); + _CRTIMP int __cdecl _cputs(const char *_Str); + _CRTIMP int __cdecl _cscanf(const char *_Format,...); + _CRTIMP int __cdecl _cscanf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _getch(void); + _CRTIMP int __cdecl _getche(void); + _CRTIMP int __cdecl _vcprintf(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_p(const char *_Format,...); + _CRTIMP int __cdecl _vcprintf_p(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_p_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _kbhit(void); + +#if defined(_X86_) && !defined(__x86_64) + int __cdecl _inp(unsigned short); + unsigned short __cdecl _inpw(unsigned short); + unsigned long __cdecl _inpd(unsigned short); + int __cdecl _outp(unsigned short,int); + unsigned short __cdecl _outpw(unsigned short,unsigned short); + unsigned long __cdecl _outpd(unsigned short,unsigned long); +#endif + + _CRTIMP int __cdecl _putch(int _Ch); + _CRTIMP int __cdecl _ungetch(int _Ch); + _CRTIMP int __cdecl _getch_nolock(void); + _CRTIMP int __cdecl _getche_nolock(void); + _CRTIMP int __cdecl _putch_nolock(int _Ch); + _CRTIMP int __cdecl _ungetch_nolock(int _Ch); + +#ifndef _WCONIO_DEFINED +#define _WCONIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + + _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _getwch(void); + _CRTIMP wint_t __cdecl _getwche(void); + _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); + _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); + _CRTIMP int __cdecl _cputws(const wchar_t *_String); + _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP wint_t __cdecl _putwch_nolock(wchar_t _WCh); + _CRTIMP wint_t __cdecl _getwch_nolock(void); + _CRTIMP wint_t __cdecl _getwche_nolock(void); + _CRTIMP wint_t __cdecl _ungetwch_nolock(wint_t _WCh); +#endif + +#ifndef NO_OLDNAMES + char *__cdecl cgets(char *_Buffer); + int __cdecl cprintf(const char *_Format,...); + int __cdecl cputs(const char *_Str); + int __cdecl cscanf(const char *_Format,...); + int __cdecl getch(void); + int __cdecl getche(void); + int __cdecl kbhit(void); + int __cdecl putch(int _Ch); + int __cdecl ungetch(int _Ch); + +#if (defined(_X86_) && !defined(__x86_64)) + int __cdecl inp(unsigned short); + unsigned short __cdecl inpw(unsigned short); + int __cdecl outp(unsigned short,int); + unsigned short __cdecl outpw(unsigned short,unsigned short); +#endif + + /* I/O intrin functions. */ + __CRT_INLINE unsigned char __inbyte(unsigned short Port) + { + unsigned char value; + __asm__ __volatile__ ("inb %w1,%b0" + : "=a" (value) + : "Nd" (Port)); + return value; + } + __CRT_INLINE unsigned short __inword(unsigned short Port) + { + unsigned short value; + __asm__ __volatile__ ("inw %w1,%w0" + : "=a" (value) + : "Nd" (Port)); + return value; + } + __CRT_INLINE unsigned long __indword(unsigned short Port) + { + unsigned long value; + __asm__ __volatile__ ("inl %w1,%0" + : "=a" (value) + : "Nd" (Port)); + return value; + } + __CRT_INLINE void __outbyte(unsigned short Port,unsigned char Data) + { + __asm__ __volatile__ ("outb %b0,%w1" + : + : "a" (Data), "Nd" (Port)); + } + __CRT_INLINE void __outword(unsigned short Port,unsigned short Data) + { + __asm__ __volatile__ ("outw %w0,%w1" + : + : "a" (Data), "Nd" (Port)); + } + __CRT_INLINE void __outdword(unsigned short Port,unsigned long Data) + { + __asm__ __volatile__ ("outl %0,%w1" + : + : "a" (Data), "Nd" (Port)); + } + __CRT_INLINE void __inbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; insb " + : "=D" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __inwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; insw " + : "=D" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __indwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; insl " + : "=D" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + + __CRT_INLINE void __outbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; outsb " + : "=S" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __outwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; outsw " + : "=S" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __outdwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; outsl " + : "=S" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + + __CRT_INLINE unsigned __int64 __readcr0(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr0, %[value]" + : [value] "=q" (value)); + return value; + } + + /* Register sizes are different between 32/64 bit mode. So we have to do this for _WIN64 and _WIN32 + separately. */ + +#ifdef _WIN64 + __CRT_INLINE void __writecr0(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr0" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr2(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr2, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr2(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr2" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr3(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr3, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr3(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr3" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr4(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr4, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr4(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr4" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr8(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr8, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr8(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr8" + : + : [Data] "q" (Data) + : "memory"); + } + +#elif defined(_WIN32) + + __CRT_INLINE void __writecr0(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr0" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr2(void) + { + unsigned long value; + __asm__ __volatile__ ( + "mov %%cr2, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr2(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr2" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr3(void) + { + unsigned long value; + __asm__ __volatile__ ( + "mov %%cr3, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr3(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr3" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr4(void) + { + unsigned long value; + __asm__ __volatile__ ( + "mov %%cr4, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr4(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr4" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr8(void) + { + unsigned long value; __asm__ __volatile__ ( + "mov %%cr8, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr8(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr8" + : + : [Data] "q" (Data) + : "memory"); + } + +#endif + + __CRT_INLINE unsigned __int64 __readmsr(unsigned long msr) + { + unsigned __int64 val1, val2; + __asm__ __volatile__( + "rdmsr" + : "=a" (val1), "=d" (val2) + : "c" (msr)); + return val1 | (val2 << 32); + } + + __CRT_INLINE void __writemsr (unsigned long msr, unsigned __int64 Value) + { + unsigned long val1 = Value, val2 = Value >> 32; + __asm__ __volatile__ ( + "wrmsr" + : + : "c" (msr), "a" (val1), "d" (val2)); + } + + __CRT_INLINE unsigned __int64 __rdtsc(void) + { + unsigned __int64 val1, val2; + __asm__ __volatile__ ( + "rdtsc" + : "=a" (val1), "=d" (val2)); + return val1 | (val2 << 32); + } + + __CRT_INLINE void __cpuid(int CPUInfo[4], int InfoType) + { + __asm__ __volatile__ ( + "cpuid" + : "=a" (CPUInfo [0]), "=b" (CPUInfo [1]), "=c" (CPUInfo [2]), "=d" (CPUInfo [3]) + : "a" (InfoType)); + } + +#endif + +#ifdef __cplusplus +} +#endif + +#include + +#endif diff --git a/tcc/include/ctype.h b/tcc/include/ctype.h index 7e901002..346926cc 100644 --- a/tcc/include/ctype.h +++ b/tcc/include/ctype.h @@ -1,281 +1,281 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_CTYPE -#define _INC_CTYPE - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifndef _CRT_CTYPEDATA_DEFINED -#define _CRT_CTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef __PCTYPE_FUNC -#define __PCTYPE_FUNC __pctype_func() -#ifdef _MSVCRT_ -#define __pctype_func() (_pctype) -#else -#define __pctype_func() (*_imp___pctype) -#endif -#endif - -#ifndef _pctype -#ifdef _MSVCRT_ - extern unsigned short *_pctype; -#else - extern unsigned short **_imp___pctype; -#define _pctype (*_imp___pctype) -#endif -#endif - -#endif -#endif - -#ifndef _CRT_WCTYPEDATA_DEFINED -#define _CRT_WCTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS -#ifndef _wctype -#ifdef _MSVCRT_ - extern unsigned short *_wctype; -#else - extern unsigned short **_imp___wctype; -#define _wctype (*_imp___wctype) -#endif -#endif -#ifdef _MSVCRT_ -#define __pwctype_func() (_pwctype) -#ifndef _pwctype - extern unsigned short *_pwctype; -#endif -#else -#define __pwctype_func() (*_imp___pwctype) -#ifndef _pwctype - extern unsigned short **_imp___pwctype; -#define _pwctype (*_imp___pwctype) -#endif -#endif -#endif -#endif - - /* CRT stuff */ -#if 1 - extern const unsigned char __newclmap[]; - extern const unsigned char __newcumap[]; - extern pthreadlocinfo __ptlocinfo; - extern pthreadmbcinfo __ptmbcinfo; - extern int __globallocalestatus; - extern int __locale_changed; - extern struct threadlocaleinfostruct __initiallocinfo; - extern _locale_tstruct __initiallocalestructinfo; - pthreadlocinfo __cdecl __updatetlocinfo(void); - pthreadmbcinfo __cdecl __updatetmbcinfo(void); -#endif - -#define _UPPER 0x1 -#define _LOWER 0x2 -#define _DIGIT 0x4 -#define _SPACE 0x8 - -#define _PUNCT 0x10 -#define _CONTROL 0x20 -#define _BLANK 0x40 -#define _HEX 0x80 - -#define _LEADBYTE 0x8000 -#define _ALPHA (0x0100|_UPPER|_LOWER) - -#ifndef _CTYPE_DEFINED -#define _CTYPE_DEFINED - - _CRTIMP int __cdecl _isctype(int _C,int _Type); - _CRTIMP int __cdecl _isctype_l(int _C,int _Type,_locale_t _Locale); - _CRTIMP int __cdecl isalpha(int _C); - _CRTIMP int __cdecl _isalpha_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isupper(int _C); - _CRTIMP int __cdecl _isupper_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl islower(int _C); - _CRTIMP int __cdecl _islower_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isdigit(int _C); - _CRTIMP int __cdecl _isdigit_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isxdigit(int _C); - _CRTIMP int __cdecl _isxdigit_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isspace(int _C); - _CRTIMP int __cdecl _isspace_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl ispunct(int _C); - _CRTIMP int __cdecl _ispunct_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isalnum(int _C); - _CRTIMP int __cdecl _isalnum_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isprint(int _C); - _CRTIMP int __cdecl _isprint_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isgraph(int _C); - _CRTIMP int __cdecl _isgraph_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl iscntrl(int _C); - _CRTIMP int __cdecl _iscntrl_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl toupper(int _C); - _CRTIMP int __cdecl tolower(int _C); - _CRTIMP int __cdecl _tolower(int _C); - _CRTIMP int __cdecl _tolower_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl _toupper(int _C); - _CRTIMP int __cdecl _toupper_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl __isascii(int _C); - _CRTIMP int __cdecl __toascii(int _C); - _CRTIMP int __cdecl __iscsymf(int _C); - _CRTIMP int __cdecl __iscsym(int _C); - -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) -int __cdecl isblank(int _C); -#endif -#endif - -#ifndef _WCTYPE_DEFINED -#define _WCTYPE_DEFINED - - int __cdecl iswalpha(wint_t _C); - _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); - int __cdecl iswupper(wint_t _C); - _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); - int __cdecl iswlower(wint_t _C); - _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswdigit(wint_t _C); - _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswxdigit(wint_t _C); - _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswspace(wint_t _C); - _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); - int __cdecl iswpunct(wint_t _C); - _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); - int __cdecl iswalnum(wint_t _C); - _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); - int __cdecl iswprint(wint_t _C); - _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); - int __cdecl iswgraph(wint_t _C); - _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); - int __cdecl iswcntrl(wint_t _C); - _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); - int __cdecl iswascii(wint_t _C); - int __cdecl isleadbyte(int _C); - _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); - wint_t __cdecl towupper(wint_t _C); - _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); - wint_t __cdecl towlower(wint_t _C); - _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswctype(wint_t _C,wctype_t _Type); - _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsymf(wint_t _C); - _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsym(wint_t _C); - _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); - int __cdecl is_wctype(wint_t _C,wctype_t _Type); - -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) -int __cdecl iswblank(wint_t _C); -#endif -#endif - -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef MB_CUR_MAX -#define MB_CUR_MAX ___mb_cur_max_func() -#ifndef __mb_cur_max -#ifdef _MSVCRT_ - extern int __mb_cur_max; -#else -#define __mb_cur_max (*_imp____mb_cur_max) - extern int *_imp____mb_cur_max; -#endif -#endif -#ifdef _MSVCRT_ -#define ___mb_cur_max_func() (__mb_cur_max) -#else -#define ___mb_cur_max_func() (*_imp____mb_cur_max) -#endif -#endif - -#define __chvalidchk(a,b) (__PCTYPE_FUNC[(a)] & (b)) -#define _chvalidchk_l(_Char,_Flag,_Locale) (!_Locale ? __chvalidchk(_Char,_Flag) : ((_locale_t)_Locale)->locinfo->pctype[_Char] & (_Flag)) -#define _ischartype_l(_Char,_Flag,_Locale) (((_Locale)!=NULL && (((_locale_t)(_Locale))->locinfo->mb_cur_max) > 1) ? _isctype_l(_Char,(_Flag),_Locale) : _chvalidchk_l(_Char,_Flag,_Locale)) -#define _isalpha_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA,_Locale) -#define _isupper_l(_Char,_Locale) _ischartype_l(_Char,_UPPER,_Locale) -#define _islower_l(_Char,_Locale) _ischartype_l(_Char,_LOWER,_Locale) -#define _isdigit_l(_Char,_Locale) _ischartype_l(_Char,_DIGIT,_Locale) -#define _isxdigit_l(_Char,_Locale) _ischartype_l(_Char,_HEX,_Locale) -#define _isspace_l(_Char,_Locale) _ischartype_l(_Char,_SPACE,_Locale) -#define _ispunct_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT,_Locale) -#define _isalnum_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA|_DIGIT,_Locale) -#define _isprint_l(_Char,_Locale) _ischartype_l(_Char,_BLANK|_PUNCT|_ALPHA|_DIGIT,_Locale) -#define _isgraph_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT|_ALPHA|_DIGIT,_Locale) -#define _iscntrl_l(_Char,_Locale) _ischartype_l(_Char,_CONTROL,_Locale) -#define _tolower(_Char) ((_Char)-'A'+'a') -#define _toupper(_Char) ((_Char)-'a'+'A') -#define __isascii(_Char) ((unsigned)(_Char) < 0x80) -#define __toascii(_Char) ((_Char) & 0x7f) - -#ifndef _WCTYPE_INLINE_DEFINED -#define _WCTYPE_INLINE_DEFINED - -#undef _CRT_WCTYPE_NOINLINE -#ifndef __cplusplus -#define iswalpha(_c) (iswctype(_c,_ALPHA)) -#define iswupper(_c) (iswctype(_c,_UPPER)) -#define iswlower(_c) (iswctype(_c,_LOWER)) -#define iswdigit(_c) (iswctype(_c,_DIGIT)) -#define iswxdigit(_c) (iswctype(_c,_HEX)) -#define iswspace(_c) (iswctype(_c,_SPACE)) -#define iswpunct(_c) (iswctype(_c,_PUNCT)) -#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) -#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) -#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) -#define iswcntrl(_c) (iswctype(_c,_CONTROL)) -#define iswascii(_c) ((unsigned)(_c) < 0x80) -#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) -#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) -#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) -#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) -#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) -#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) -#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) -#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) -#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) -#endif -#endif - -#define __iscsymf(_c) (isalpha(_c) || ((_c)=='_')) -#define __iscsym(_c) (isalnum(_c) || ((_c)=='_')) -#define __iswcsymf(_c) (iswalpha(_c) || ((_c)=='_')) -#define __iswcsym(_c) (iswalnum(_c) || ((_c)=='_')) -#define _iscsymf_l(_c,_p) (_isalpha_l(_c,_p) || ((_c)=='_')) -#define _iscsym_l(_c,_p) (_isalnum_l(_c,_p) || ((_c)=='_')) -#define _iswcsymf_l(_c,_p) (_iswalpha_l(_c,_p) || ((_c)=='_')) -#define _iswcsym_l(_c,_p) (_iswalnum_l(_c,_p) || ((_c)=='_')) -#endif - -#ifndef NO_OLDNAMES -#ifndef _CTYPE_DEFINED - int __cdecl isascii(int _C); - int __cdecl toascii(int _C); - int __cdecl iscsymf(int _C); - int __cdecl iscsym(int _C); -#else -#define isascii __isascii -#define toascii __toascii -#define iscsymf __iscsymf -#define iscsym __iscsym -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_CTYPE +#define _INC_CTYPE + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifndef _CRT_CTYPEDATA_DEFINED +#define _CRT_CTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef __PCTYPE_FUNC +#define __PCTYPE_FUNC __pctype_func() +#ifdef _MSVCRT_ +#define __pctype_func() (_pctype) +#else +#define __pctype_func() (*_imp___pctype) +#endif +#endif + +#ifndef _pctype +#ifdef _MSVCRT_ + extern unsigned short *_pctype; +#else + extern unsigned short **_imp___pctype; +#define _pctype (*_imp___pctype) +#endif +#endif + +#endif +#endif + +#ifndef _CRT_WCTYPEDATA_DEFINED +#define _CRT_WCTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS +#ifndef _wctype +#ifdef _MSVCRT_ + extern unsigned short *_wctype; +#else + extern unsigned short **_imp___wctype; +#define _wctype (*_imp___wctype) +#endif +#endif +#ifdef _MSVCRT_ +#define __pwctype_func() (_pwctype) +#ifndef _pwctype + extern unsigned short *_pwctype; +#endif +#else +#define __pwctype_func() (*_imp___pwctype) +#ifndef _pwctype + extern unsigned short **_imp___pwctype; +#define _pwctype (*_imp___pwctype) +#endif +#endif +#endif +#endif + + /* CRT stuff */ +#if 1 + extern const unsigned char __newclmap[]; + extern const unsigned char __newcumap[]; + extern pthreadlocinfo __ptlocinfo; + extern pthreadmbcinfo __ptmbcinfo; + extern int __globallocalestatus; + extern int __locale_changed; + extern struct threadlocaleinfostruct __initiallocinfo; + extern _locale_tstruct __initiallocalestructinfo; + pthreadlocinfo __cdecl __updatetlocinfo(void); + pthreadmbcinfo __cdecl __updatetmbcinfo(void); +#endif + +#define _UPPER 0x1 +#define _LOWER 0x2 +#define _DIGIT 0x4 +#define _SPACE 0x8 + +#define _PUNCT 0x10 +#define _CONTROL 0x20 +#define _BLANK 0x40 +#define _HEX 0x80 + +#define _LEADBYTE 0x8000 +#define _ALPHA (0x0100|_UPPER|_LOWER) + +#ifndef _CTYPE_DEFINED +#define _CTYPE_DEFINED + + _CRTIMP int __cdecl _isctype(int _C,int _Type); + _CRTIMP int __cdecl _isctype_l(int _C,int _Type,_locale_t _Locale); + _CRTIMP int __cdecl isalpha(int _C); + _CRTIMP int __cdecl _isalpha_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isupper(int _C); + _CRTIMP int __cdecl _isupper_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl islower(int _C); + _CRTIMP int __cdecl _islower_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isdigit(int _C); + _CRTIMP int __cdecl _isdigit_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isxdigit(int _C); + _CRTIMP int __cdecl _isxdigit_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isspace(int _C); + _CRTIMP int __cdecl _isspace_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl ispunct(int _C); + _CRTIMP int __cdecl _ispunct_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isalnum(int _C); + _CRTIMP int __cdecl _isalnum_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isprint(int _C); + _CRTIMP int __cdecl _isprint_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isgraph(int _C); + _CRTIMP int __cdecl _isgraph_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl iscntrl(int _C); + _CRTIMP int __cdecl _iscntrl_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl toupper(int _C); + _CRTIMP int __cdecl tolower(int _C); + _CRTIMP int __cdecl _tolower(int _C); + _CRTIMP int __cdecl _tolower_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl _toupper(int _C); + _CRTIMP int __cdecl _toupper_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl __isascii(int _C); + _CRTIMP int __cdecl __toascii(int _C); + _CRTIMP int __cdecl __iscsymf(int _C); + _CRTIMP int __cdecl __iscsym(int _C); + +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) +int __cdecl isblank(int _C); +#endif +#endif + +#ifndef _WCTYPE_DEFINED +#define _WCTYPE_DEFINED + + int __cdecl iswalpha(wint_t _C); + _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); + int __cdecl iswupper(wint_t _C); + _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); + int __cdecl iswlower(wint_t _C); + _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswdigit(wint_t _C); + _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswxdigit(wint_t _C); + _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswspace(wint_t _C); + _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); + int __cdecl iswpunct(wint_t _C); + _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); + int __cdecl iswalnum(wint_t _C); + _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); + int __cdecl iswprint(wint_t _C); + _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); + int __cdecl iswgraph(wint_t _C); + _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); + int __cdecl iswcntrl(wint_t _C); + _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); + int __cdecl iswascii(wint_t _C); + int __cdecl isleadbyte(int _C); + _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); + wint_t __cdecl towupper(wint_t _C); + _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); + wint_t __cdecl towlower(wint_t _C); + _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswctype(wint_t _C,wctype_t _Type); + _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsymf(wint_t _C); + _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsym(wint_t _C); + _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); + int __cdecl is_wctype(wint_t _C,wctype_t _Type); + +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) +int __cdecl iswblank(wint_t _C); +#endif +#endif + +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef MB_CUR_MAX +#define MB_CUR_MAX ___mb_cur_max_func() +#ifndef __mb_cur_max +#ifdef _MSVCRT_ + extern int __mb_cur_max; +#else +#define __mb_cur_max (*_imp____mb_cur_max) + extern int *_imp____mb_cur_max; +#endif +#endif +#ifdef _MSVCRT_ +#define ___mb_cur_max_func() (__mb_cur_max) +#else +#define ___mb_cur_max_func() (*_imp____mb_cur_max) +#endif +#endif + +#define __chvalidchk(a,b) (__PCTYPE_FUNC[(a)] & (b)) +#define _chvalidchk_l(_Char,_Flag,_Locale) (!_Locale ? __chvalidchk(_Char,_Flag) : ((_locale_t)_Locale)->locinfo->pctype[_Char] & (_Flag)) +#define _ischartype_l(_Char,_Flag,_Locale) (((_Locale)!=NULL && (((_locale_t)(_Locale))->locinfo->mb_cur_max) > 1) ? _isctype_l(_Char,(_Flag),_Locale) : _chvalidchk_l(_Char,_Flag,_Locale)) +#define _isalpha_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA,_Locale) +#define _isupper_l(_Char,_Locale) _ischartype_l(_Char,_UPPER,_Locale) +#define _islower_l(_Char,_Locale) _ischartype_l(_Char,_LOWER,_Locale) +#define _isdigit_l(_Char,_Locale) _ischartype_l(_Char,_DIGIT,_Locale) +#define _isxdigit_l(_Char,_Locale) _ischartype_l(_Char,_HEX,_Locale) +#define _isspace_l(_Char,_Locale) _ischartype_l(_Char,_SPACE,_Locale) +#define _ispunct_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT,_Locale) +#define _isalnum_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA|_DIGIT,_Locale) +#define _isprint_l(_Char,_Locale) _ischartype_l(_Char,_BLANK|_PUNCT|_ALPHA|_DIGIT,_Locale) +#define _isgraph_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT|_ALPHA|_DIGIT,_Locale) +#define _iscntrl_l(_Char,_Locale) _ischartype_l(_Char,_CONTROL,_Locale) +#define _tolower(_Char) ((_Char)-'A'+'a') +#define _toupper(_Char) ((_Char)-'a'+'A') +#define __isascii(_Char) ((unsigned)(_Char) < 0x80) +#define __toascii(_Char) ((_Char) & 0x7f) + +#ifndef _WCTYPE_INLINE_DEFINED +#define _WCTYPE_INLINE_DEFINED + +#undef _CRT_WCTYPE_NOINLINE +#ifndef __cplusplus +#define iswalpha(_c) (iswctype(_c,_ALPHA)) +#define iswupper(_c) (iswctype(_c,_UPPER)) +#define iswlower(_c) (iswctype(_c,_LOWER)) +#define iswdigit(_c) (iswctype(_c,_DIGIT)) +#define iswxdigit(_c) (iswctype(_c,_HEX)) +#define iswspace(_c) (iswctype(_c,_SPACE)) +#define iswpunct(_c) (iswctype(_c,_PUNCT)) +#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) +#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) +#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) +#define iswcntrl(_c) (iswctype(_c,_CONTROL)) +#define iswascii(_c) ((unsigned)(_c) < 0x80) +#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) +#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) +#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) +#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) +#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) +#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) +#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) +#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) +#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) +#endif +#endif + +#define __iscsymf(_c) (isalpha(_c) || ((_c)=='_')) +#define __iscsym(_c) (isalnum(_c) || ((_c)=='_')) +#define __iswcsymf(_c) (iswalpha(_c) || ((_c)=='_')) +#define __iswcsym(_c) (iswalnum(_c) || ((_c)=='_')) +#define _iscsymf_l(_c,_p) (_isalpha_l(_c,_p) || ((_c)=='_')) +#define _iscsym_l(_c,_p) (_isalnum_l(_c,_p) || ((_c)=='_')) +#define _iswcsymf_l(_c,_p) (_iswalpha_l(_c,_p) || ((_c)=='_')) +#define _iswcsym_l(_c,_p) (_iswalnum_l(_c,_p) || ((_c)=='_')) +#endif + +#ifndef NO_OLDNAMES +#ifndef _CTYPE_DEFINED + int __cdecl isascii(int _C); + int __cdecl toascii(int _C); + int __cdecl iscsymf(int _C); + int __cdecl iscsym(int _C); +#else +#define isascii __isascii +#define toascii __toascii +#define iscsymf __iscsymf +#define iscsym __iscsym +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/dir.h b/tcc/include/dir.h index f38f750d..71d8b4f6 100644 --- a/tcc/include/dir.h +++ b/tcc/include/dir.h @@ -1,31 +1,31 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * dir.h - * - * This file OBSOLESCENT and only provided for backward compatibility. - * Please use io.h instead. - * - * This file is part of the Mingw32 package. - * - * Contributors: - * Created by Colin Peters - * Mumit Khan - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#include - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * dir.h + * + * This file OBSOLESCENT and only provided for backward compatibility. + * Please use io.h instead. + * + * This file is part of the Mingw32 package. + * + * Contributors: + * Created by Colin Peters + * Mumit Khan + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include + diff --git a/tcc/include/direct.h b/tcc/include/direct.h index 99ce69db..3e9a4e48 100644 --- a/tcc/include/direct.h +++ b/tcc/include/direct.h @@ -1,68 +1,68 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_DIRECT -#define _INC_DIRECT - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _DISKFREE_T_DEFINED -#define _DISKFREE_T_DEFINED - struct _diskfree_t { - unsigned total_clusters; - unsigned avail_clusters; - unsigned sectors_per_cluster; - unsigned bytes_per_sector; - }; -#endif - - _CRTIMP char *__cdecl _getcwd(char *_DstBuf,int _SizeInBytes); - _CRTIMP char *__cdecl _getdcwd(int _Drive,char *_DstBuf,int _SizeInBytes); - char *__cdecl _getdcwd_nolock(int _Drive,char *_DstBuf,int _SizeInBytes); - _CRTIMP int __cdecl _chdir(const char *_Path); - _CRTIMP int __cdecl _mkdir(const char *_Path); - _CRTIMP int __cdecl _rmdir(const char *_Path); - _CRTIMP int __cdecl _chdrive(int _Drive); - _CRTIMP int __cdecl _getdrive(void); - _CRTIMP unsigned long __cdecl _getdrives(void); - -#ifndef _GETDISKFREE_DEFINED -#define _GETDISKFREE_DEFINED - _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); -#endif - -#ifndef _WDIRECT_DEFINED -#define _WDIRECT_DEFINED - _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); -#endif - -#ifndef NO_OLDNAMES - -#define diskfree_t _diskfree_t - - char *__cdecl getcwd(char *_DstBuf,int _SizeInBytes); - int __cdecl chdir(const char *_Path); - int __cdecl mkdir(const char *_Path); - int __cdecl rmdir(const char *_Path); -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_DIRECT +#define _INC_DIRECT + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _DISKFREE_T_DEFINED +#define _DISKFREE_T_DEFINED + struct _diskfree_t { + unsigned total_clusters; + unsigned avail_clusters; + unsigned sectors_per_cluster; + unsigned bytes_per_sector; + }; +#endif + + _CRTIMP char *__cdecl _getcwd(char *_DstBuf,int _SizeInBytes); + _CRTIMP char *__cdecl _getdcwd(int _Drive,char *_DstBuf,int _SizeInBytes); + char *__cdecl _getdcwd_nolock(int _Drive,char *_DstBuf,int _SizeInBytes); + _CRTIMP int __cdecl _chdir(const char *_Path); + _CRTIMP int __cdecl _mkdir(const char *_Path); + _CRTIMP int __cdecl _rmdir(const char *_Path); + _CRTIMP int __cdecl _chdrive(int _Drive); + _CRTIMP int __cdecl _getdrive(void); + _CRTIMP unsigned long __cdecl _getdrives(void); + +#ifndef _GETDISKFREE_DEFINED +#define _GETDISKFREE_DEFINED + _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); +#endif + +#ifndef _WDIRECT_DEFINED +#define _WDIRECT_DEFINED + _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); +#endif + +#ifndef NO_OLDNAMES + +#define diskfree_t _diskfree_t + + char *__cdecl getcwd(char *_DstBuf,int _SizeInBytes); + int __cdecl chdir(const char *_Path); + int __cdecl mkdir(const char *_Path); + int __cdecl rmdir(const char *_Path); +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/dirent.h b/tcc/include/dirent.h index cd31f59e..99881ba7 100644 --- a/tcc/include/dirent.h +++ b/tcc/include/dirent.h @@ -1,135 +1,135 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* All the headers include this file. */ -#include <_mingw.h> - -#ifndef __STRICT_ANSI__ - -#ifndef _DIRENT_H_ -#define _DIRENT_H_ - - -#pragma pack(push,_CRT_PACKING) - -#include - -#ifndef RC_INVOKED - -#ifdef __cplusplus -extern "C" { -#endif - - struct dirent - { - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - char* d_name; /* File name. */ - /* NOTE: The name in the dirent structure points to the name in the - * finddata_t structure in the DIR. */ - }; - - /* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - * dd_stat field is now int (was short in older versions). - */ - typedef struct - { - /* disk transfer area for this dir */ - struct _finddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct dirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - char dd_name[1]; - } DIR; - - DIR* __cdecl opendir (const char*); - struct dirent* __cdecl readdir (DIR*); - int __cdecl closedir (DIR*); - void __cdecl rewinddir (DIR*); - long __cdecl telldir (DIR*); - void __cdecl seekdir (DIR*, long); - - - /* wide char versions */ - - struct _wdirent - { - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - wchar_t* d_name; /* File name. */ - /* NOTE: The name in the dirent structure points to the name in the * wfinddata_t structure in the _WDIR. */ - }; - - /* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - */ - typedef struct - { - /* disk transfer area for this dir */ - struct _wfinddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct _wdirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - wchar_t dd_name[1]; - } _WDIR; - - - - _WDIR* __cdecl _wopendir (const wchar_t*); - struct _wdirent* __cdecl _wreaddir (_WDIR*); - int __cdecl _wclosedir (_WDIR*); - void __cdecl _wrewinddir (_WDIR*); - long __cdecl _wtelldir (_WDIR*); - void __cdecl _wseekdir (_WDIR*, long); - - -#ifdef __cplusplus -} -#endif - -#endif /* Not RC_INVOKED */ - -#pragma pack(pop) - -#endif /* Not _DIRENT_H_ */ - - -#endif /* Not __STRICT_ANSI__ */ - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* All the headers include this file. */ +#include <_mingw.h> + +#ifndef __STRICT_ANSI__ + +#ifndef _DIRENT_H_ +#define _DIRENT_H_ + + +#pragma pack(push,_CRT_PACKING) + +#include + +#ifndef RC_INVOKED + +#ifdef __cplusplus +extern "C" { +#endif + + struct dirent + { + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + char* d_name; /* File name. */ + /* NOTE: The name in the dirent structure points to the name in the + * finddata_t structure in the DIR. */ + }; + + /* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + * dd_stat field is now int (was short in older versions). + */ + typedef struct + { + /* disk transfer area for this dir */ + struct _finddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct dirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + char dd_name[1]; + } DIR; + + DIR* __cdecl opendir (const char*); + struct dirent* __cdecl readdir (DIR*); + int __cdecl closedir (DIR*); + void __cdecl rewinddir (DIR*); + long __cdecl telldir (DIR*); + void __cdecl seekdir (DIR*, long); + + + /* wide char versions */ + + struct _wdirent + { + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + wchar_t* d_name; /* File name. */ + /* NOTE: The name in the dirent structure points to the name in the * wfinddata_t structure in the _WDIR. */ + }; + + /* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + */ + typedef struct + { + /* disk transfer area for this dir */ + struct _wfinddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct _wdirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + wchar_t dd_name[1]; + } _WDIR; + + + + _WDIR* __cdecl _wopendir (const wchar_t*); + struct _wdirent* __cdecl _wreaddir (_WDIR*); + int __cdecl _wclosedir (_WDIR*); + void __cdecl _wrewinddir (_WDIR*); + long __cdecl _wtelldir (_WDIR*); + void __cdecl _wseekdir (_WDIR*, long); + + +#ifdef __cplusplus +} +#endif + +#endif /* Not RC_INVOKED */ + +#pragma pack(pop) + +#endif /* Not _DIRENT_H_ */ + + +#endif /* Not __STRICT_ANSI__ */ + diff --git a/tcc/include/dos.h b/tcc/include/dos.h index 294e8fe1..7f907d6e 100644 --- a/tcc/include/dos.h +++ b/tcc/include/dos.h @@ -1,55 +1,55 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_DOS -#define _INC_DOS - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _DISKFREE_T_DEFINED -#define _DISKFREE_T_DEFINED - - struct _diskfree_t { - unsigned total_clusters; - unsigned avail_clusters; - unsigned sectors_per_cluster; - unsigned bytes_per_sector; - }; -#endif - -#define _A_NORMAL 0x00 -#define _A_RDONLY 0x01 -#define _A_HIDDEN 0x02 -#define _A_SYSTEM 0x04 -#define _A_SUBDIR 0x10 -#define _A_ARCH 0x20 - -#ifndef _GETDISKFREE_DEFINED -#define _GETDISKFREE_DEFINED - _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); -#endif - -#if (defined(_X86_) && !defined(__x86_64)) - void __cdecl _disable(void); - void __cdecl _enable(void); -#endif - -#ifndef NO_OLDNAMES -#define diskfree_t _diskfree_t -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_DOS +#define _INC_DOS + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _DISKFREE_T_DEFINED +#define _DISKFREE_T_DEFINED + + struct _diskfree_t { + unsigned total_clusters; + unsigned avail_clusters; + unsigned sectors_per_cluster; + unsigned bytes_per_sector; + }; +#endif + +#define _A_NORMAL 0x00 +#define _A_RDONLY 0x01 +#define _A_HIDDEN 0x02 +#define _A_SYSTEM 0x04 +#define _A_SUBDIR 0x10 +#define _A_ARCH 0x20 + +#ifndef _GETDISKFREE_DEFINED +#define _GETDISKFREE_DEFINED + _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); +#endif + +#if (defined(_X86_) && !defined(__x86_64)) + void __cdecl _disable(void); + void __cdecl _enable(void); +#endif + +#ifndef NO_OLDNAMES +#define diskfree_t _diskfree_t +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/errno.h b/tcc/include/errno.h index 574ffa9b..38b0b9a5 100644 --- a/tcc/include/errno.h +++ b/tcc/include/errno.h @@ -1,75 +1,75 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_ERRNO -#define _INC_ERRNO - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRT_ERRNO_DEFINED -#define _CRT_ERRNO_DEFINED - _CRTIMP int *__cdecl _errno(void); -#define errno (*_errno()) - - errno_t __cdecl _set_errno(int _Value); - errno_t __cdecl _get_errno(int *_Value); -#endif - -#define EPERM 1 -#define ENOENT 2 -#define ESRCH 3 -#define EINTR 4 -#define EIO 5 -#define ENXIO 6 -#define E2BIG 7 -#define ENOEXEC 8 -#define EBADF 9 -#define ECHILD 10 -#define EAGAIN 11 -#define ENOMEM 12 -#define EACCES 13 -#define EFAULT 14 -#define EBUSY 16 -#define EEXIST 17 -#define EXDEV 18 -#define ENODEV 19 -#define ENOTDIR 20 -#define EISDIR 21 -#define ENFILE 23 -#define EMFILE 24 -#define ENOTTY 25 -#define EFBIG 27 -#define ENOSPC 28 -#define ESPIPE 29 -#define EROFS 30 -#define EMLINK 31 -#define EPIPE 32 -#define EDOM 33 -#define EDEADLK 36 -#define ENAMETOOLONG 38 -#define ENOLCK 39 -#define ENOSYS 40 -#define ENOTEMPTY 41 - -#ifndef RC_INVOKED -#if !defined(_SECURECRT_ERRCODE_VALUES_DEFINED) -#define _SECURECRT_ERRCODE_VALUES_DEFINED -#define EINVAL 22 -#define ERANGE 34 -#define EILSEQ 42 -#define STRUNCATE 80 -#endif -#endif - -#define EDEADLOCK EDEADLK - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_ERRNO +#define _INC_ERRNO + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRT_ERRNO_DEFINED +#define _CRT_ERRNO_DEFINED + _CRTIMP int *__cdecl _errno(void); +#define errno (*_errno()) + + errno_t __cdecl _set_errno(int _Value); + errno_t __cdecl _get_errno(int *_Value); +#endif + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define EDEADLK 36 +#define ENAMETOOLONG 38 +#define ENOLCK 39 +#define ENOSYS 40 +#define ENOTEMPTY 41 + +#ifndef RC_INVOKED +#if !defined(_SECURECRT_ERRCODE_VALUES_DEFINED) +#define _SECURECRT_ERRCODE_VALUES_DEFINED +#define EINVAL 22 +#define ERANGE 34 +#define EILSEQ 42 +#define STRUNCATE 80 +#endif +#endif + +#define EDEADLOCK EDEADLK + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/excpt.h b/tcc/include/excpt.h index 26cc9437..c12a3489 100644 --- a/tcc/include/excpt.h +++ b/tcc/include/excpt.h @@ -1,123 +1,123 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_EXCPT -#define _INC_EXCPT - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - - struct _EXCEPTION_POINTERS; - -#ifndef EXCEPTION_DISPOSITION -#define EXCEPTION_DISPOSITION int -#endif -#define ExceptionContinueExecution 0 -#define ExceptionContinueSearch 1 -#define ExceptionNestedException 2 -#define ExceptionCollidedUnwind 3 - -#if (defined(_X86_) && !defined(__x86_64)) - struct _EXCEPTION_RECORD; - struct _CONTEXT; - - EXCEPTION_DISPOSITION __cdecl _except_handler(struct _EXCEPTION_RECORD *_ExceptionRecord,void *_EstablisherFrame,struct _CONTEXT *_ContextRecord,void *_DispatcherContext); -#elif defined(__ia64__) - - typedef struct _EXCEPTION_POINTERS *Exception_info_ptr; - struct _EXCEPTION_RECORD; - struct _CONTEXT; - struct _DISPATCHER_CONTEXT; - - _CRTIMP EXCEPTION_DISPOSITION __cdecl __C_specific_handler (struct _EXCEPTION_RECORD *_ExceptionRecord,unsigned __int64 _MemoryStackFp,unsigned __int64 _BackingStoreFp,struct _CONTEXT *_ContextRecord,struct _DISPATCHER_CONTEXT *_DispatcherContext,unsigned __int64 _GlobalPointer); -#elif defined(__x86_64) - - struct _EXCEPTION_RECORD; - struct _CONTEXT; -#endif - -#define GetExceptionCode _exception_code -#define exception_code _exception_code -#define GetExceptionInformation (struct _EXCEPTION_POINTERS *)_exception_info -#define exception_info (struct _EXCEPTION_POINTERS *)_exception_info -#define AbnormalTermination _abnormal_termination -#define abnormal_termination _abnormal_termination - - unsigned long __cdecl _exception_code(void); - void *__cdecl _exception_info(void); - int __cdecl _abnormal_termination(void); - -#define EXCEPTION_EXECUTE_HANDLER 1 -#define EXCEPTION_CONTINUE_SEARCH 0 -#define EXCEPTION_CONTINUE_EXECUTION -1 - - /* CRT stuff */ - typedef void (__cdecl * _PHNDLR)(int); - - struct _XCPT_ACTION { - unsigned long XcptNum; - int SigNum; - _PHNDLR XcptAction; - }; - - extern struct _XCPT_ACTION _XcptActTab[]; - extern int _XcptActTabCount; - extern int _XcptActTabSize; - extern int _First_FPE_Indx; - extern int _Num_FPE; - - int __cdecl __CppXcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); - int __cdecl _XcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); - - /* - * The type of function that is expected as an exception handler to be - * installed with _try1. - */ - typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); - -#ifndef HAVE_NO_SEH - /* - * This is not entirely necessary, but it is the structure installed by - * the _try1 primitive below. - */ - typedef struct _EXCEPTION_REGISTRATION { - struct _EXCEPTION_REGISTRATION *prev; - EXCEPTION_DISPOSITION (*handler)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); - } EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION; - - typedef EXCEPTION_REGISTRATION EXCEPTION_REGISTRATION_RECORD; - typedef PEXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION_RECORD; -#endif - -#if (defined(_X86_) && !defined(__x86_64)) -#define __try1(pHandler) \ - __asm__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : "g" (pHandler)); - -#define __except1 \ - __asm__ ("movl (%%esp),%%eax;movl %%eax,%%fs:0;addl $8,%%esp;" \ - : : : "%eax"); -#elif defined(__x86_64) -#define __try1(pHandler) \ - __asm__ ("pushq %0;pushq %%gs:0;movq %%rsp,%%gs:0;" : : "g" (pHandler)); - -#define __except1 \ - __asm__ ("movq (%%rsp),%%rax;movq %%rax,%%gs:0;addq $16,%%rsp;" \ - : : : "%rax"); -#else -#define __try1(pHandler) -#define __except1 -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_EXCPT +#define _INC_EXCPT + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + + struct _EXCEPTION_POINTERS; + +#ifndef EXCEPTION_DISPOSITION +#define EXCEPTION_DISPOSITION int +#endif +#define ExceptionContinueExecution 0 +#define ExceptionContinueSearch 1 +#define ExceptionNestedException 2 +#define ExceptionCollidedUnwind 3 + +#if (defined(_X86_) && !defined(__x86_64)) + struct _EXCEPTION_RECORD; + struct _CONTEXT; + + EXCEPTION_DISPOSITION __cdecl _except_handler(struct _EXCEPTION_RECORD *_ExceptionRecord,void *_EstablisherFrame,struct _CONTEXT *_ContextRecord,void *_DispatcherContext); +#elif defined(__ia64__) + + typedef struct _EXCEPTION_POINTERS *Exception_info_ptr; + struct _EXCEPTION_RECORD; + struct _CONTEXT; + struct _DISPATCHER_CONTEXT; + + _CRTIMP EXCEPTION_DISPOSITION __cdecl __C_specific_handler (struct _EXCEPTION_RECORD *_ExceptionRecord,unsigned __int64 _MemoryStackFp,unsigned __int64 _BackingStoreFp,struct _CONTEXT *_ContextRecord,struct _DISPATCHER_CONTEXT *_DispatcherContext,unsigned __int64 _GlobalPointer); +#elif defined(__x86_64) + + struct _EXCEPTION_RECORD; + struct _CONTEXT; +#endif + +#define GetExceptionCode _exception_code +#define exception_code _exception_code +#define GetExceptionInformation (struct _EXCEPTION_POINTERS *)_exception_info +#define exception_info (struct _EXCEPTION_POINTERS *)_exception_info +#define AbnormalTermination _abnormal_termination +#define abnormal_termination _abnormal_termination + + unsigned long __cdecl _exception_code(void); + void *__cdecl _exception_info(void); + int __cdecl _abnormal_termination(void); + +#define EXCEPTION_EXECUTE_HANDLER 1 +#define EXCEPTION_CONTINUE_SEARCH 0 +#define EXCEPTION_CONTINUE_EXECUTION -1 + + /* CRT stuff */ + typedef void (__cdecl * _PHNDLR)(int); + + struct _XCPT_ACTION { + unsigned long XcptNum; + int SigNum; + _PHNDLR XcptAction; + }; + + extern struct _XCPT_ACTION _XcptActTab[]; + extern int _XcptActTabCount; + extern int _XcptActTabSize; + extern int _First_FPE_Indx; + extern int _Num_FPE; + + int __cdecl __CppXcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); + int __cdecl _XcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); + + /* + * The type of function that is expected as an exception handler to be + * installed with _try1. + */ + typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); + +#ifndef HAVE_NO_SEH + /* + * This is not entirely necessary, but it is the structure installed by + * the _try1 primitive below. + */ + typedef struct _EXCEPTION_REGISTRATION { + struct _EXCEPTION_REGISTRATION *prev; + EXCEPTION_DISPOSITION (*handler)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); + } EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION; + + typedef EXCEPTION_REGISTRATION EXCEPTION_REGISTRATION_RECORD; + typedef PEXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION_RECORD; +#endif + +#if (defined(_X86_) && !defined(__x86_64)) +#define __try1(pHandler) \ + __asm__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : "g" (pHandler)); + +#define __except1 \ + __asm__ ("movl (%%esp),%%eax;movl %%eax,%%fs:0;addl $8,%%esp;" \ + : : : "%eax"); +#elif defined(__x86_64) +#define __try1(pHandler) \ + __asm__ ("pushq %0;pushq %%gs:0;movq %%rsp,%%gs:0;" : : "g" (pHandler)); + +#define __except1 \ + __asm__ ("movq (%%rsp),%%rax;movq %%rax,%%gs:0;addq $16,%%rsp;" \ + : : : "%rax"); +#else +#define __try1(pHandler) +#define __except1 +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/fcntl.h b/tcc/include/fcntl.h index 9202b08c..40543e39 100644 --- a/tcc/include/fcntl.h +++ b/tcc/include/fcntl.h @@ -1,52 +1,52 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#include <_mingw.h> - -#include - -#ifndef _INC_FCNTL -#define _INC_FCNTL - -#define _O_RDONLY 0x0000 -#define _O_WRONLY 0x0001 -#define _O_RDWR 0x0002 -#define _O_APPEND 0x0008 -#define _O_CREAT 0x0100 -#define _O_TRUNC 0x0200 -#define _O_EXCL 0x0400 -#define _O_TEXT 0x4000 -#define _O_BINARY 0x8000 -#define _O_WTEXT 0x10000 -#define _O_U16TEXT 0x20000 -#define _O_U8TEXT 0x40000 -#define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR) - -#define _O_RAW _O_BINARY -#define _O_NOINHERIT 0x0080 -#define _O_TEMPORARY 0x0040 -#define _O_SHORT_LIVED 0x1000 - -#define _O_SEQUENTIAL 0x0020 -#define _O_RANDOM 0x0010 - -#if !defined(NO_OLDNAMES) || defined(_POSIX) -#define O_RDONLY _O_RDONLY -#define O_WRONLY _O_WRONLY -#define O_RDWR _O_RDWR -#define O_APPEND _O_APPEND -#define O_CREAT _O_CREAT -#define O_TRUNC _O_TRUNC -#define O_EXCL _O_EXCL -#define O_TEXT _O_TEXT -#define O_BINARY _O_BINARY -#define O_RAW _O_BINARY -#define O_TEMPORARY _O_TEMPORARY -#define O_NOINHERIT _O_NOINHERIT -#define O_SEQUENTIAL _O_SEQUENTIAL -#define O_RANDOM _O_RANDOM -#define O_ACCMODE _O_ACCMODE -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#include <_mingw.h> + +#include + +#ifndef _INC_FCNTL +#define _INC_FCNTL + +#define _O_RDONLY 0x0000 +#define _O_WRONLY 0x0001 +#define _O_RDWR 0x0002 +#define _O_APPEND 0x0008 +#define _O_CREAT 0x0100 +#define _O_TRUNC 0x0200 +#define _O_EXCL 0x0400 +#define _O_TEXT 0x4000 +#define _O_BINARY 0x8000 +#define _O_WTEXT 0x10000 +#define _O_U16TEXT 0x20000 +#define _O_U8TEXT 0x40000 +#define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR) + +#define _O_RAW _O_BINARY +#define _O_NOINHERIT 0x0080 +#define _O_TEMPORARY 0x0040 +#define _O_SHORT_LIVED 0x1000 + +#define _O_SEQUENTIAL 0x0020 +#define _O_RANDOM 0x0010 + +#if !defined(NO_OLDNAMES) || defined(_POSIX) +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_RDWR _O_RDWR +#define O_APPEND _O_APPEND +#define O_CREAT _O_CREAT +#define O_TRUNC _O_TRUNC +#define O_EXCL _O_EXCL +#define O_TEXT _O_TEXT +#define O_BINARY _O_BINARY +#define O_RAW _O_BINARY +#define O_TEMPORARY _O_TEMPORARY +#define O_NOINHERIT _O_NOINHERIT +#define O_SEQUENTIAL _O_SEQUENTIAL +#define O_RANDOM _O_RANDOM +#define O_ACCMODE _O_ACCMODE +#endif +#endif diff --git a/tcc/include/fenv.h b/tcc/include/fenv.h index 258f3a5d..8efca4a0 100644 --- a/tcc/include/fenv.h +++ b/tcc/include/fenv.h @@ -1,108 +1,108 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _FENV_H_ -#define _FENV_H_ - -#include <_mingw.h> - -/* FPU status word exception flags */ -#define FE_INVALID 0x01 -#define FE_DENORMAL 0x02 -#define FE_DIVBYZERO 0x04 -#define FE_OVERFLOW 0x08 -#define FE_UNDERFLOW 0x10 -#define FE_INEXACT 0x20 -#define FE_ALL_EXCEPT (FE_INVALID | FE_DENORMAL | FE_DIVBYZERO \ - | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) - -/* FPU control word rounding flags */ -#define FE_TONEAREST 0x0000 -#define FE_DOWNWARD 0x0400 -#define FE_UPWARD 0x0800 -#define FE_TOWARDZERO 0x0c00 - -/* The MXCSR exception flags are the same as the - FE flags. */ -#define __MXCSR_EXCEPT_FLAG_SHIFT 0 - -/* How much to shift FE status word exception flags - to get MXCSR rounding flags, */ -#define __MXCSR_ROUND_FLAG_SHIFT 3 - -#ifndef RC_INVOKED -/* - For now, support only for the basic abstraction of flags that are - either set or clear. fexcept_t could be structure that holds more - info about the fp environment. -*/ -typedef unsigned short fexcept_t; - -/* This 32-byte struct represents the entire floating point - environment as stored by fnstenv or fstenv, augmented by - the contents of the MXCSR register, as stored by stmxcsr - (if CPU supports it). */ -typedef struct -{ - unsigned short __control_word; - unsigned short __unused0; - unsigned short __status_word; - unsigned short __unused1; - unsigned short __tag_word; - unsigned short __unused2; - unsigned int __ip_offset; /* instruction pointer offset */ - unsigned short __ip_selector; - unsigned short __opcode; - unsigned int __data_offset; - unsigned short __data_selector; - unsigned short __unused3; - unsigned int __mxcsr; /* contents of the MXCSR register */ -} fenv_t; - - -/*The C99 standard (7.6.9) allows us to define implementation-specific macros for - different fp environments */ - -/* The default Intel x87 floating point environment (64-bit mantissa) */ -#define FE_PC64_ENV ((const fenv_t *)-1) - -/* The floating point environment set by MSVCRT _fpreset (53-bit mantissa) */ -#define FE_PC53_ENV ((const fenv_t *)-2) - -/* The FE_DFL_ENV macro is required by standard. - fesetenv will use the environment set at app startup.*/ -#define FE_DFL_ENV ((const fenv_t *) 0) - -#ifdef __cplusplus -extern "C" { -#endif - -/*TODO: Some of these could be inlined */ -/* 7.6.2 Exception */ - -extern int __cdecl feclearexcept (int); -extern int __cdecl fegetexceptflag (fexcept_t * flagp, int excepts); -extern int __cdecl feraiseexcept (int excepts ); -extern int __cdecl fesetexceptflag (const fexcept_t *, int); -extern int __cdecl fetestexcept (int excepts); - -/* 7.6.3 Rounding */ - -extern int __cdecl fegetround (void); -extern int __cdecl fesetround (int mode); - -/* 7.6.4 Environment */ - -extern int __cdecl fegetenv(fenv_t * envp); -extern int __cdecl fesetenv(const fenv_t * ); -extern int __cdecl feupdateenv(const fenv_t *); -extern int __cdecl feholdexcept(fenv_t *); - -#ifdef __cplusplus -} -#endif -#endif /* Not RC_INVOKED */ - -#endif /* ndef _FENV_H */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _FENV_H_ +#define _FENV_H_ + +#include <_mingw.h> + +/* FPU status word exception flags */ +#define FE_INVALID 0x01 +#define FE_DENORMAL 0x02 +#define FE_DIVBYZERO 0x04 +#define FE_OVERFLOW 0x08 +#define FE_UNDERFLOW 0x10 +#define FE_INEXACT 0x20 +#define FE_ALL_EXCEPT (FE_INVALID | FE_DENORMAL | FE_DIVBYZERO \ + | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) + +/* FPU control word rounding flags */ +#define FE_TONEAREST 0x0000 +#define FE_DOWNWARD 0x0400 +#define FE_UPWARD 0x0800 +#define FE_TOWARDZERO 0x0c00 + +/* The MXCSR exception flags are the same as the + FE flags. */ +#define __MXCSR_EXCEPT_FLAG_SHIFT 0 + +/* How much to shift FE status word exception flags + to get MXCSR rounding flags, */ +#define __MXCSR_ROUND_FLAG_SHIFT 3 + +#ifndef RC_INVOKED +/* + For now, support only for the basic abstraction of flags that are + either set or clear. fexcept_t could be structure that holds more + info about the fp environment. +*/ +typedef unsigned short fexcept_t; + +/* This 32-byte struct represents the entire floating point + environment as stored by fnstenv or fstenv, augmented by + the contents of the MXCSR register, as stored by stmxcsr + (if CPU supports it). */ +typedef struct +{ + unsigned short __control_word; + unsigned short __unused0; + unsigned short __status_word; + unsigned short __unused1; + unsigned short __tag_word; + unsigned short __unused2; + unsigned int __ip_offset; /* instruction pointer offset */ + unsigned short __ip_selector; + unsigned short __opcode; + unsigned int __data_offset; + unsigned short __data_selector; + unsigned short __unused3; + unsigned int __mxcsr; /* contents of the MXCSR register */ +} fenv_t; + + +/*The C99 standard (7.6.9) allows us to define implementation-specific macros for + different fp environments */ + +/* The default Intel x87 floating point environment (64-bit mantissa) */ +#define FE_PC64_ENV ((const fenv_t *)-1) + +/* The floating point environment set by MSVCRT _fpreset (53-bit mantissa) */ +#define FE_PC53_ENV ((const fenv_t *)-2) + +/* The FE_DFL_ENV macro is required by standard. + fesetenv will use the environment set at app startup.*/ +#define FE_DFL_ENV ((const fenv_t *) 0) + +#ifdef __cplusplus +extern "C" { +#endif + +/*TODO: Some of these could be inlined */ +/* 7.6.2 Exception */ + +extern int __cdecl feclearexcept (int); +extern int __cdecl fegetexceptflag (fexcept_t * flagp, int excepts); +extern int __cdecl feraiseexcept (int excepts ); +extern int __cdecl fesetexceptflag (const fexcept_t *, int); +extern int __cdecl fetestexcept (int excepts); + +/* 7.6.3 Rounding */ + +extern int __cdecl fegetround (void); +extern int __cdecl fesetround (int mode); + +/* 7.6.4 Environment */ + +extern int __cdecl fegetenv(fenv_t * envp); +extern int __cdecl fesetenv(const fenv_t * ); +extern int __cdecl feupdateenv(const fenv_t *); +extern int __cdecl feholdexcept(fenv_t *); + +#ifdef __cplusplus +} +#endif +#endif /* Not RC_INVOKED */ + +#endif /* ndef _FENV_H */ diff --git a/tcc/include/float.h b/tcc/include/float.h index 35b28f2c..b11a0ff2 100644 --- a/tcc/include/float.h +++ b/tcc/include/float.h @@ -1,72 +1,72 @@ -#ifndef _FLOAT_H_ -#define _FLOAT_H_ - -#define FLT_RADIX 2 - -/* IEEE float */ -#define FLT_MANT_DIG 24 -#define FLT_DIG 6 -#define FLT_ROUNDS 1 -#define FLT_EPSILON 1.19209290e-07F -#define FLT_MIN_EXP (-125) -#define FLT_MIN 1.17549435e-38F -#define FLT_MIN_10_EXP (-37) -#define FLT_MAX_EXP 128 -#define FLT_MAX 3.40282347e+38F -#define FLT_MAX_10_EXP 38 - -/* IEEE double */ -#define DBL_MANT_DIG 53 -#define DBL_DIG 15 -#define DBL_EPSILON 2.2204460492503131e-16 -#define DBL_MIN_EXP (-1021) -#define DBL_MIN 2.2250738585072014e-308 -#define DBL_MIN_10_EXP (-307) -#define DBL_MAX_EXP 1024 -#define DBL_MAX 1.7976931348623157e+308 -#define DBL_MAX_10_EXP 308 - -/* horrible intel long double */ -#if defined __i386__ || defined __x86_64__ - -#define LDBL_MANT_DIG 64 -#define LDBL_DIG 18 -#define LDBL_EPSILON 1.08420217248550443401e-19L -#define LDBL_MIN_EXP (-16381) -#define LDBL_MIN 3.36210314311209350626e-4932L -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_EXP 16384 -#define LDBL_MAX 1.18973149535723176502e+4932L -#define LDBL_MAX_10_EXP 4932 - -#elif defined __aarch64__ || defined __riscv -/* - * Use values from: - * gcc -dM -E -xc /dev/null | grep LDBL | sed -e "s/__//g" - */ -#define LDBL_MANT_DIG 113 -#define LDBL_DIG 33 -#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L -#define LDBL_MIN_EXP (-16381) -#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_EXP 16384 -#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L -#define LDBL_MAX_EXP 16384 - -#else - -/* same as IEEE double */ -#define LDBL_MANT_DIG 53 -#define LDBL_DIG 15 -#define LDBL_EPSILON 2.2204460492503131e-16L -#define LDBL_MIN_EXP (-1021) -#define LDBL_MIN 2.2250738585072014e-308L -#define LDBL_MIN_10_EXP (-307) -#define LDBL_MAX_EXP 1024 -#define LDBL_MAX 1.7976931348623157e+308L -#define LDBL_MAX_10_EXP 308 - -#endif - -#endif /* _FLOAT_H_ */ +#ifndef _FLOAT_H_ +#define _FLOAT_H_ + +#define FLT_RADIX 2 + +/* IEEE float */ +#define FLT_MANT_DIG 24 +#define FLT_DIG 6 +#define FLT_ROUNDS 1 +#define FLT_EPSILON 1.19209290e-07F +#define FLT_MIN_EXP (-125) +#define FLT_MIN 1.17549435e-38F +#define FLT_MIN_10_EXP (-37) +#define FLT_MAX_EXP 128 +#define FLT_MAX 3.40282347e+38F +#define FLT_MAX_10_EXP 38 + +/* IEEE double */ +#define DBL_MANT_DIG 53 +#define DBL_DIG 15 +#define DBL_EPSILON 2.2204460492503131e-16 +#define DBL_MIN_EXP (-1021) +#define DBL_MIN 2.2250738585072014e-308 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_EXP 1024 +#define DBL_MAX 1.7976931348623157e+308 +#define DBL_MAX_10_EXP 308 + +/* horrible intel long double */ +#if defined __i386__ || defined __x86_64__ + +#define LDBL_MANT_DIG 64 +#define LDBL_DIG 18 +#define LDBL_EPSILON 1.08420217248550443401e-19L +#define LDBL_MIN_EXP (-16381) +#define LDBL_MIN 3.36210314311209350626e-4932L +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_EXP 16384 +#define LDBL_MAX 1.18973149535723176502e+4932L +#define LDBL_MAX_10_EXP 4932 + +#elif defined __aarch64__ || defined __riscv +/* + * Use values from: + * gcc -dM -E -xc /dev/null | grep LDBL | sed -e "s/__//g" + */ +#define LDBL_MANT_DIG 113 +#define LDBL_DIG 33 +#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L +#define LDBL_MIN_EXP (-16381) +#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_EXP 16384 +#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L +#define LDBL_MAX_EXP 16384 + +#else + +/* same as IEEE double */ +#define LDBL_MANT_DIG 53 +#define LDBL_DIG 15 +#define LDBL_EPSILON 2.2204460492503131e-16L +#define LDBL_MIN_EXP (-1021) +#define LDBL_MIN 2.2250738585072014e-308L +#define LDBL_MIN_10_EXP (-307) +#define LDBL_MAX_EXP 1024 +#define LDBL_MAX 1.7976931348623157e+308L +#define LDBL_MAX_10_EXP 308 + +#endif + +#endif /* _FLOAT_H_ */ diff --git a/tcc/include/inttypes.h b/tcc/include/inttypes.h index 73600919..08a906e1 100644 --- a/tcc/include/inttypes.h +++ b/tcc/include/inttypes.h @@ -1,297 +1,297 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* 7.8 Format conversion of integer types */ - -#ifndef _INTTYPES_H_ -#define _INTTYPES_H_ - -#include <_mingw.h> -#include -#define __need_wchar_t -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - intmax_t quot; - intmax_t rem; - } imaxdiv_t; - -#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) - -/* 7.8.1 Macros for format specifiers - * - * MS runtime does not yet understand C9x standard "ll" - * length specifier. It appears to treat "ll" as "l". - * The non-standard I64 length specifier causes warning in GCC, - * but understood by MS runtime functions. - */ - -/* fprintf macros for signed types */ -#define PRId8 "d" -#define PRId16 "d" -#define PRId32 "d" -#define PRId64 "I64d" - -#define PRIdLEAST8 "d" -#define PRIdLEAST16 "d" -#define PRIdLEAST32 "d" -#define PRIdLEAST64 "I64d" - -#define PRIdFAST8 "d" -#define PRIdFAST16 "d" -#define PRIdFAST32 "d" -#define PRIdFAST64 "I64d" - -#define PRIdMAX "I64d" - -#define PRIi8 "i" -#define PRIi16 "i" -#define PRIi32 "i" -#define PRIi64 "I64i" - -#define PRIiLEAST8 "i" -#define PRIiLEAST16 "i" -#define PRIiLEAST32 "i" -#define PRIiLEAST64 "I64i" - -#define PRIiFAST8 "i" -#define PRIiFAST16 "i" -#define PRIiFAST32 "i" -#define PRIiFAST64 "I64i" - -#define PRIiMAX "I64i" - -#define PRIo8 "o" -#define PRIo16 "o" -#define PRIo32 "o" -#define PRIo64 "I64o" - -#define PRIoLEAST8 "o" -#define PRIoLEAST16 "o" -#define PRIoLEAST32 "o" -#define PRIoLEAST64 "I64o" - -#define PRIoFAST8 "o" -#define PRIoFAST16 "o" -#define PRIoFAST32 "o" -#define PRIoFAST64 "I64o" - -#define PRIoMAX "I64o" - -/* fprintf macros for unsigned types */ -#define PRIu8 "u" -#define PRIu16 "u" -#define PRIu32 "u" -#define PRIu64 "I64u" - - -#define PRIuLEAST8 "u" -#define PRIuLEAST16 "u" -#define PRIuLEAST32 "u" -#define PRIuLEAST64 "I64u" - -#define PRIuFAST8 "u" -#define PRIuFAST16 "u" -#define PRIuFAST32 "u" -#define PRIuFAST64 "I64u" - -#define PRIuMAX "I64u" - -#define PRIx8 "x" -#define PRIx16 "x" -#define PRIx32 "x" -#define PRIx64 "I64x" - -#define PRIxLEAST8 "x" -#define PRIxLEAST16 "x" -#define PRIxLEAST32 "x" -#define PRIxLEAST64 "I64x" - -#define PRIxFAST8 "x" -#define PRIxFAST16 "x" -#define PRIxFAST32 "x" -#define PRIxFAST64 "I64x" - -#define PRIxMAX "I64x" - -#define PRIX8 "X" -#define PRIX16 "X" -#define PRIX32 "X" -#define PRIX64 "I64X" - -#define PRIXLEAST8 "X" -#define PRIXLEAST16 "X" -#define PRIXLEAST32 "X" -#define PRIXLEAST64 "I64X" - -#define PRIXFAST8 "X" -#define PRIXFAST16 "X" -#define PRIXFAST32 "X" -#define PRIXFAST64 "I64X" - -#define PRIXMAX "I64X" - -/* - * fscanf macros for signed int types - * NOTE: if 32-bit int is used for int_fast8_t and int_fast16_t - * (see stdint.h, 7.18.1.3), FAST8 and FAST16 should have - * no length identifiers - */ - -#define SCNd16 "hd" -#define SCNd32 "d" -#define SCNd64 "I64d" - -#define SCNdLEAST16 "hd" -#define SCNdLEAST32 "d" -#define SCNdLEAST64 "I64d" - -#define SCNdFAST16 "hd" -#define SCNdFAST32 "d" -#define SCNdFAST64 "I64d" - -#define SCNdMAX "I64d" - -#define SCNi16 "hi" -#define SCNi32 "i" -#define SCNi64 "I64i" - -#define SCNiLEAST16 "hi" -#define SCNiLEAST32 "i" -#define SCNiLEAST64 "I64i" - -#define SCNiFAST16 "hi" -#define SCNiFAST32 "i" -#define SCNiFAST64 "I64i" - -#define SCNiMAX "I64i" - -#define SCNo16 "ho" -#define SCNo32 "o" -#define SCNo64 "I64o" - -#define SCNoLEAST16 "ho" -#define SCNoLEAST32 "o" -#define SCNoLEAST64 "I64o" - -#define SCNoFAST16 "ho" -#define SCNoFAST32 "o" -#define SCNoFAST64 "I64o" - -#define SCNoMAX "I64o" - -#define SCNx16 "hx" -#define SCNx32 "x" -#define SCNx64 "I64x" - -#define SCNxLEAST16 "hx" -#define SCNxLEAST32 "x" -#define SCNxLEAST64 "I64x" - -#define SCNxFAST16 "hx" -#define SCNxFAST32 "x" -#define SCNxFAST64 "I64x" - -#define SCNxMAX "I64x" - -/* fscanf macros for unsigned int types */ - -#define SCNu16 "hu" -#define SCNu32 "u" -#define SCNu64 "I64u" - -#define SCNuLEAST16 "hu" -#define SCNuLEAST32 "u" -#define SCNuLEAST64 "I64u" - -#define SCNuFAST16 "hu" -#define SCNuFAST32 "u" -#define SCNuFAST64 "I64u" - -#define SCNuMAX "I64u" - -#ifdef _WIN64 -#define PRIdPTR "I64d" -#define PRIiPTR "I64i" -#define PRIoPTR "I64o" -#define PRIuPTR "I64u" -#define PRIxPTR "I64x" -#define PRIXPTR "I64X" -#define SCNdPTR "I64d" -#define SCNiPTR "I64i" -#define SCNoPTR "I64o" -#define SCNxPTR "I64x" -#define SCNuPTR "I64u" -#else -#define PRIdPTR "d" -#define PRIiPTR "i" -#define PRIoPTR "o" -#define PRIuPTR "u" -#define PRIxPTR "x" -#define PRIXPTR "X" -#define SCNdPTR "d" -#define SCNiPTR "i" -#define SCNoPTR "o" -#define SCNxPTR "x" -#define SCNuPTR "u" -#endif - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -/* - * no length modifier for char types prior to C9x - * MS runtime scanf appears to treat "hh" as "h" - */ - -/* signed char */ -#define SCNd8 "hhd" -#define SCNdLEAST8 "hhd" -#define SCNdFAST8 "hhd" - -#define SCNi8 "hhi" -#define SCNiLEAST8 "hhi" -#define SCNiFAST8 "hhi" - -#define SCNo8 "hho" -#define SCNoLEAST8 "hho" -#define SCNoFAST8 "hho" - -#define SCNx8 "hhx" -#define SCNxLEAST8 "hhx" -#define SCNxFAST8 "hhx" - -/* unsigned char */ -#define SCNu8 "hhu" -#define SCNuLEAST8 "hhu" -#define SCNuFAST8 "hhu" -#endif /* __STDC_VERSION__ >= 199901 */ - -#endif /* !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) */ - -intmax_t __cdecl imaxabs (intmax_t j); -__CRT_INLINE intmax_t __cdecl imaxabs (intmax_t j) - {return (j >= 0 ? j : -j);} -imaxdiv_t __cdecl imaxdiv (intmax_t numer, intmax_t denom); - -/* 7.8.2 Conversion functions for greatest-width integer types */ - -intmax_t __cdecl strtoimax (const char* __restrict__ nptr, - char** __restrict__ endptr, int base); -uintmax_t __cdecl strtoumax (const char* __restrict__ nptr, - char** __restrict__ endptr, int base); - -intmax_t __cdecl wcstoimax (const wchar_t* __restrict__ nptr, - wchar_t** __restrict__ endptr, int base); -uintmax_t __cdecl wcstoumax (const wchar_t* __restrict__ nptr, - wchar_t** __restrict__ endptr, int base); - -#ifdef __cplusplus -} -#endif - -#endif /* ndef _INTTYPES_H */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* 7.8 Format conversion of integer types */ + +#ifndef _INTTYPES_H_ +#define _INTTYPES_H_ + +#include <_mingw.h> +#include +#define __need_wchar_t +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + intmax_t quot; + intmax_t rem; + } imaxdiv_t; + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) + +/* 7.8.1 Macros for format specifiers + * + * MS runtime does not yet understand C9x standard "ll" + * length specifier. It appears to treat "ll" as "l". + * The non-standard I64 length specifier causes warning in GCC, + * but understood by MS runtime functions. + */ + +/* fprintf macros for signed types */ +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "d" +#define PRId64 "I64d" + +#define PRIdLEAST8 "d" +#define PRIdLEAST16 "d" +#define PRIdLEAST32 "d" +#define PRIdLEAST64 "I64d" + +#define PRIdFAST8 "d" +#define PRIdFAST16 "d" +#define PRIdFAST32 "d" +#define PRIdFAST64 "I64d" + +#define PRIdMAX "I64d" + +#define PRIi8 "i" +#define PRIi16 "i" +#define PRIi32 "i" +#define PRIi64 "I64i" + +#define PRIiLEAST8 "i" +#define PRIiLEAST16 "i" +#define PRIiLEAST32 "i" +#define PRIiLEAST64 "I64i" + +#define PRIiFAST8 "i" +#define PRIiFAST16 "i" +#define PRIiFAST32 "i" +#define PRIiFAST64 "I64i" + +#define PRIiMAX "I64i" + +#define PRIo8 "o" +#define PRIo16 "o" +#define PRIo32 "o" +#define PRIo64 "I64o" + +#define PRIoLEAST8 "o" +#define PRIoLEAST16 "o" +#define PRIoLEAST32 "o" +#define PRIoLEAST64 "I64o" + +#define PRIoFAST8 "o" +#define PRIoFAST16 "o" +#define PRIoFAST32 "o" +#define PRIoFAST64 "I64o" + +#define PRIoMAX "I64o" + +/* fprintf macros for unsigned types */ +#define PRIu8 "u" +#define PRIu16 "u" +#define PRIu32 "u" +#define PRIu64 "I64u" + + +#define PRIuLEAST8 "u" +#define PRIuLEAST16 "u" +#define PRIuLEAST32 "u" +#define PRIuLEAST64 "I64u" + +#define PRIuFAST8 "u" +#define PRIuFAST16 "u" +#define PRIuFAST32 "u" +#define PRIuFAST64 "I64u" + +#define PRIuMAX "I64u" + +#define PRIx8 "x" +#define PRIx16 "x" +#define PRIx32 "x" +#define PRIx64 "I64x" + +#define PRIxLEAST8 "x" +#define PRIxLEAST16 "x" +#define PRIxLEAST32 "x" +#define PRIxLEAST64 "I64x" + +#define PRIxFAST8 "x" +#define PRIxFAST16 "x" +#define PRIxFAST32 "x" +#define PRIxFAST64 "I64x" + +#define PRIxMAX "I64x" + +#define PRIX8 "X" +#define PRIX16 "X" +#define PRIX32 "X" +#define PRIX64 "I64X" + +#define PRIXLEAST8 "X" +#define PRIXLEAST16 "X" +#define PRIXLEAST32 "X" +#define PRIXLEAST64 "I64X" + +#define PRIXFAST8 "X" +#define PRIXFAST16 "X" +#define PRIXFAST32 "X" +#define PRIXFAST64 "I64X" + +#define PRIXMAX "I64X" + +/* + * fscanf macros for signed int types + * NOTE: if 32-bit int is used for int_fast8_t and int_fast16_t + * (see stdint.h, 7.18.1.3), FAST8 and FAST16 should have + * no length identifiers + */ + +#define SCNd16 "hd" +#define SCNd32 "d" +#define SCNd64 "I64d" + +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "d" +#define SCNdLEAST64 "I64d" + +#define SCNdFAST16 "hd" +#define SCNdFAST32 "d" +#define SCNdFAST64 "I64d" + +#define SCNdMAX "I64d" + +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 "I64i" + +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "i" +#define SCNiLEAST64 "I64i" + +#define SCNiFAST16 "hi" +#define SCNiFAST32 "i" +#define SCNiFAST64 "I64i" + +#define SCNiMAX "I64i" + +#define SCNo16 "ho" +#define SCNo32 "o" +#define SCNo64 "I64o" + +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "o" +#define SCNoLEAST64 "I64o" + +#define SCNoFAST16 "ho" +#define SCNoFAST32 "o" +#define SCNoFAST64 "I64o" + +#define SCNoMAX "I64o" + +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 "I64x" + +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "x" +#define SCNxLEAST64 "I64x" + +#define SCNxFAST16 "hx" +#define SCNxFAST32 "x" +#define SCNxFAST64 "I64x" + +#define SCNxMAX "I64x" + +/* fscanf macros for unsigned int types */ + +#define SCNu16 "hu" +#define SCNu32 "u" +#define SCNu64 "I64u" + +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "u" +#define SCNuLEAST64 "I64u" + +#define SCNuFAST16 "hu" +#define SCNuFAST32 "u" +#define SCNuFAST64 "I64u" + +#define SCNuMAX "I64u" + +#ifdef _WIN64 +#define PRIdPTR "I64d" +#define PRIiPTR "I64i" +#define PRIoPTR "I64o" +#define PRIuPTR "I64u" +#define PRIxPTR "I64x" +#define PRIXPTR "I64X" +#define SCNdPTR "I64d" +#define SCNiPTR "I64i" +#define SCNoPTR "I64o" +#define SCNxPTR "I64x" +#define SCNuPTR "I64u" +#else +#define PRIdPTR "d" +#define PRIiPTR "i" +#define PRIoPTR "o" +#define PRIuPTR "u" +#define PRIxPTR "x" +#define PRIXPTR "X" +#define SCNdPTR "d" +#define SCNiPTR "i" +#define SCNoPTR "o" +#define SCNxPTR "x" +#define SCNuPTR "u" +#endif + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +/* + * no length modifier for char types prior to C9x + * MS runtime scanf appears to treat "hh" as "h" + */ + +/* signed char */ +#define SCNd8 "hhd" +#define SCNdLEAST8 "hhd" +#define SCNdFAST8 "hhd" + +#define SCNi8 "hhi" +#define SCNiLEAST8 "hhi" +#define SCNiFAST8 "hhi" + +#define SCNo8 "hho" +#define SCNoLEAST8 "hho" +#define SCNoFAST8 "hho" + +#define SCNx8 "hhx" +#define SCNxLEAST8 "hhx" +#define SCNxFAST8 "hhx" + +/* unsigned char */ +#define SCNu8 "hhu" +#define SCNuLEAST8 "hhu" +#define SCNuFAST8 "hhu" +#endif /* __STDC_VERSION__ >= 199901 */ + +#endif /* !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) */ + +intmax_t __cdecl imaxabs (intmax_t j); +__CRT_INLINE intmax_t __cdecl imaxabs (intmax_t j) + {return (j >= 0 ? j : -j);} +imaxdiv_t __cdecl imaxdiv (intmax_t numer, intmax_t denom); + +/* 7.8.2 Conversion functions for greatest-width integer types */ + +intmax_t __cdecl strtoimax (const char* __restrict__ nptr, + char** __restrict__ endptr, int base); +uintmax_t __cdecl strtoumax (const char* __restrict__ nptr, + char** __restrict__ endptr, int base); + +intmax_t __cdecl wcstoimax (const wchar_t* __restrict__ nptr, + wchar_t** __restrict__ endptr, int base); +uintmax_t __cdecl wcstoumax (const wchar_t* __restrict__ nptr, + wchar_t** __restrict__ endptr, int base); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef _INTTYPES_H */ diff --git a/tcc/include/io.h b/tcc/include/io.h index e2aeec3d..2cd96045 100644 --- a/tcc/include/io.h +++ b/tcc/include/io.h @@ -1,418 +1,418 @@ - -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _IO_H_ -#define _IO_H_ - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifndef _POSIX_ - -#ifdef __cplusplus -extern "C" { -#endif - -_CRTIMP char* __cdecl _getcwd (char*, int); -#ifndef _FSIZE_T_DEFINED - typedef unsigned long _fsize_t; -#define _FSIZE_T_DEFINED -#endif - -#ifndef _FINDDATA_T_DEFINED - - struct _finddata32_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - _fsize_t size; - char name[260]; - }; - -/*#if _INTEGRAL_MAX_BITS >= 64*/ - - struct _finddata32i64_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - __int64 size; - char name[260]; - }; - - struct _finddata64i32_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - _fsize_t size; - char name[260]; - }; - - struct __finddata64_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - __int64 size; - char name[260]; - }; -/* #endif */ - -#ifdef _USE_32BIT_TIME_T -#define _finddata_t _finddata32_t -#define _finddatai64_t _finddata32i64_t - -#ifdef _WIN64 -#define _findfirst _findfirst32 -#define _findnext _findnext32 -#else -#define _findfirst32 _findfirst -#define _findnext32 _findnext -#endif -#define _findfirsti64 _findfirst32i64 -#define _findnexti64 _findnext32i64 -#else -#define _finddata_t _finddata64i32_t -#define _finddatai64_t __finddata64_t - -#define _findfirst _findfirst64i32 -#define _findnext _findnext64i32 -#define _findfirsti64 _findfirst64 -#define _findnexti64 _findnext64 -#endif - -#define _FINDDATA_T_DEFINED -#endif - -#ifndef _WFINDDATA_T_DEFINED - - struct _wfinddata32_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - -/* #if _INTEGRAL_MAX_BITS >= 64 */ - - struct _wfinddata32i64_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - __int64 size; - wchar_t name[260]; - }; - - struct _wfinddata64i32_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - - struct _wfinddata64_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - __int64 size; - wchar_t name[260]; - }; -/* #endif */ - -#ifdef _USE_32BIT_TIME_T -#define _wfinddata_t _wfinddata32_t -#define _wfinddatai64_t _wfinddata32i64_t - -#define _wfindfirst _wfindfirst32 -#define _wfindnext _wfindnext32 -#define _wfindfirsti64 _wfindfirst32i64 -#define _wfindnexti64 _wfindnext32i64 -#else -#define _wfinddata_t _wfinddata64i32_t -#define _wfinddatai64_t _wfinddata64_t - -#define _wfindfirst _wfindfirst64i32 -#define _wfindnext _wfindnext64i32 -#define _wfindfirsti64 _wfindfirst64 -#define _wfindnexti64 _wfindnext64 -#endif - -#define _WFINDDATA_T_DEFINED -#endif - -#define _A_NORMAL 0x00 -#define _A_RDONLY 0x01 -#define _A_HIDDEN 0x02 -#define _A_SYSTEM 0x04 -#define _A_SUBDIR 0x10 -#define _A_ARCH 0x20 - -#ifndef _SIZE_T_DEFINED -#define _SIZE_T_DEFINED -#undef size_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef unsigned int size_t __attribute__ ((mode (DI))); -#else - typedef unsigned __int64 size_t; -#endif -#else - typedef unsigned int size_t; -#endif -#endif - -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#undef ssize_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int ssize_t __attribute__ ((mode (DI))); -#else - typedef __int64 ssize_t; -#endif -#else - typedef int ssize_t; -#endif -#endif - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int _off64_t __attribute__ ((mode (DI))); -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef int off64_t __attribute__ ((mode (DI))); -#endif -#else - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif -#endif - - /* Some defines for _access nAccessMode (MS doesn't define them, but - * it doesn't seem to hurt to add them). */ -#define F_OK 0 /* Check for file existence */ -#define X_OK 1 /* Check for execute permission. */ -#define W_OK 2 /* Check for write permission */ -#define R_OK 4 /* Check for read permission */ - - _CRTIMP int __cdecl _access(const char *_Filename,int _AccessMode); - _CRTIMP int __cdecl _chmod(const char *_Filename,int _Mode); - _CRTIMP int __cdecl _chsize(int _FileHandle,long _Size); - _CRTIMP int __cdecl _close(int _FileHandle); - _CRTIMP int __cdecl _commit(int _FileHandle); - _CRTIMP int __cdecl _creat(const char *_Filename,int _PermissionMode); - _CRTIMP int __cdecl _dup(int _FileHandle); - _CRTIMP int __cdecl _dup2(int _FileHandleSrc,int _FileHandleDst); - _CRTIMP int __cdecl _eof(int _FileHandle); - _CRTIMP long __cdecl _filelength(int _FileHandle); - _CRTIMP intptr_t __cdecl _findfirst32(const char *_Filename,struct _finddata32_t *_FindData); - _CRTIMP int __cdecl _findnext32(intptr_t _FindHandle,struct _finddata32_t *_FindData); - _CRTIMP int __cdecl _findclose(intptr_t _FindHandle); - _CRTIMP int __cdecl _isatty(int _FileHandle); - _CRTIMP int __cdecl _locking(int _FileHandle,int _LockMode,long _NumOfBytes); - _CRTIMP long __cdecl _lseek(int _FileHandle,long _Offset,int _Origin); - _off64_t lseek64(int fd,_off64_t offset, int whence); - _CRTIMP char *__cdecl _mktemp(char *_TemplateName); - _CRTIMP int __cdecl _pipe(int *_PtHandles,unsigned int _PipeSize,int _TextMode); - _CRTIMP int __cdecl _read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); - -#ifndef _CRT_DIRECTORY_DEFINED -#define _CRT_DIRECTORY_DEFINED - int __cdecl remove(const char *_Filename); - int __cdecl rename(const char *_OldFilename,const char *_NewFilename); - _CRTIMP int __cdecl _unlink(const char *_Filename); -#ifndef NO_OLDNAMES - int __cdecl unlink(const char *_Filename); -#endif -#endif - - _CRTIMP int __cdecl _setmode(int _FileHandle,int _Mode); - _CRTIMP long __cdecl _tell(int _FileHandle); - _CRTIMP int __cdecl _umask(int _Mode); - _CRTIMP int __cdecl _write(int _FileHandle,const void *_Buf,unsigned int _MaxCharCount); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP __int64 __cdecl _filelengthi64(int _FileHandle); - _CRTIMP intptr_t __cdecl _findfirst32i64(const char *_Filename,struct _finddata32i64_t *_FindData); - _CRTIMP intptr_t __cdecl _findfirst64(const char *_Filename,struct __finddata64_t *_FindData); -#ifdef __cplusplus -#include -#endif - intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData); - __CRT_INLINE intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData) - { - struct __finddata64_t fd; - intptr_t ret = _findfirst64(_Filename,&fd); - _FindData->attrib=fd.attrib; - _FindData->time_create=fd.time_create; - _FindData->time_access=fd.time_access; - _FindData->time_write=fd.time_write; - _FindData->size=(_fsize_t) fd.size; - strncpy(_FindData->name,fd.name,260); - return ret; - } - _CRTIMP int __cdecl _findnext32i64(intptr_t _FindHandle,struct _finddata32i64_t *_FindData); - _CRTIMP int __cdecl _findnext64(intptr_t _FindHandle,struct __finddata64_t *_FindData); - int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData); - __CRT_INLINE int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData) - { - struct __finddata64_t fd; - int ret = _findnext64(_FindHandle,&fd); - _FindData->attrib=fd.attrib; - _FindData->time_create=fd.time_create; - _FindData->time_access=fd.time_access; - _FindData->time_write=fd.time_write; - _FindData->size=(_fsize_t) fd.size; - strncpy(_FindData->name,fd.name,260); - return ret; - } - __int64 __cdecl _lseeki64(int _FileHandle,__int64 _Offset,int _Origin); - __int64 __cdecl _telli64(int _FileHandle); -#endif -#ifndef NO_OLDNAMES - -#ifndef _UWIN - int __cdecl chdir (const char *); - char *__cdecl getcwd (char *, int); - int __cdecl mkdir (const char *); - char *__cdecl mktemp(char *); - int __cdecl rmdir (const char*); - int __cdecl chmod (const char *, int); -#endif /* _UWIN */ - -#endif /* Not NO_OLDNAMES */ - - _CRTIMP errno_t __cdecl _sopen_s(int *_FileHandle,const char *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode); - -#ifndef __cplusplus - _CRTIMP int __cdecl _open(const char *_Filename,int _OpenFlag,...); - _CRTIMP int __cdecl _sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); -#else - extern "C++" _CRTIMP int __cdecl _open(const char *_Filename,int _Openflag,int _PermissionMode = 0); - extern "C++" _CRTIMP int __cdecl _sopen(const char *_Filename,int _Openflag,int _ShareFlag,int _PermissionMode = 0); -#endif - -#ifndef _WIO_DEFINED -#define _WIO_DEFINED - _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); - _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); - _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); - _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); - _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); - _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); - intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); - _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); - _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); - int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); - _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); -#endif - - _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); - -#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) - _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); - _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); -#else - extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); - extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); -#endif - -#endif - - int __cdecl __lock_fhandle(int _Filehandle); - void __cdecl _unlock_fhandle(int _Filehandle); - _CRTIMP intptr_t __cdecl _get_osfhandle(int _FileHandle); - _CRTIMP int __cdecl _open_osfhandle(intptr_t _OSFileHandle,int _Flags); - -#ifndef NO_OLDNAMES - int __cdecl access(const char *_Filename,int _AccessMode); - int __cdecl chmod(const char *_Filename,int _AccessMode); - int __cdecl chsize(int _FileHandle,long _Size); - int __cdecl close(int _FileHandle); - int __cdecl creat(const char *_Filename,int _PermissionMode); - int __cdecl dup(int _FileHandle); - int __cdecl dup2(int _FileHandleSrc,int _FileHandleDst); - int __cdecl eof(int _FileHandle); - long __cdecl filelength(int _FileHandle); - int __cdecl isatty(int _FileHandle); - int __cdecl locking(int _FileHandle,int _LockMode,long _NumOfBytes); - long __cdecl lseek(int _FileHandle,long _Offset,int _Origin); - char *__cdecl mktemp(char *_TemplateName); - int __cdecl open(const char *_Filename,int _OpenFlag,...); - int __cdecl read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); - int __cdecl setmode(int _FileHandle,int _Mode); - int __cdecl sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); - long __cdecl tell(int _FileHandle); - int __cdecl umask(int _Mode); - int __cdecl write(int _Filehandle,const void *_Buf,unsigned int _MaxCharCount); -#endif - -#ifdef __cplusplus -} -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Misc stuff */ -char *getlogin(void); -#ifdef __USE_MINGW_ALARM -unsigned int alarm(unsigned int seconds); -#endif - -#ifdef __USE_MINGW_ACCESS -/* Old versions of MSVCRT access() just ignored X_OK, while the version - shipped with Vista, returns an error code. This will restore the - old behaviour */ -static inline int __mingw_access (const char *__fname, int __mode) { - return _access (__fname, __mode & ~X_OK); -} - -#define access(__f,__m) __mingw_access (__f, __m) -#endif - - -#ifdef __cplusplus -} -#endif - - -#pragma pack(pop) - -#include - -#endif /* End _IO_H_ */ - + +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _IO_H_ +#define _IO_H_ + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifndef _POSIX_ + +#ifdef __cplusplus +extern "C" { +#endif + +_CRTIMP char* __cdecl _getcwd (char*, int); +#ifndef _FSIZE_T_DEFINED + typedef unsigned long _fsize_t; +#define _FSIZE_T_DEFINED +#endif + +#ifndef _FINDDATA_T_DEFINED + + struct _finddata32_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + _fsize_t size; + char name[260]; + }; + +/*#if _INTEGRAL_MAX_BITS >= 64*/ + + struct _finddata32i64_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + __int64 size; + char name[260]; + }; + + struct _finddata64i32_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + _fsize_t size; + char name[260]; + }; + + struct __finddata64_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + __int64 size; + char name[260]; + }; +/* #endif */ + +#ifdef _USE_32BIT_TIME_T +#define _finddata_t _finddata32_t +#define _finddatai64_t _finddata32i64_t + +#ifdef _WIN64 +#define _findfirst _findfirst32 +#define _findnext _findnext32 +#else +#define _findfirst32 _findfirst +#define _findnext32 _findnext +#endif +#define _findfirsti64 _findfirst32i64 +#define _findnexti64 _findnext32i64 +#else +#define _finddata_t _finddata64i32_t +#define _finddatai64_t __finddata64_t + +#define _findfirst _findfirst64i32 +#define _findnext _findnext64i32 +#define _findfirsti64 _findfirst64 +#define _findnexti64 _findnext64 +#endif + +#define _FINDDATA_T_DEFINED +#endif + +#ifndef _WFINDDATA_T_DEFINED + + struct _wfinddata32_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + +/* #if _INTEGRAL_MAX_BITS >= 64 */ + + struct _wfinddata32i64_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + __int64 size; + wchar_t name[260]; + }; + + struct _wfinddata64i32_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + + struct _wfinddata64_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + __int64 size; + wchar_t name[260]; + }; +/* #endif */ + +#ifdef _USE_32BIT_TIME_T +#define _wfinddata_t _wfinddata32_t +#define _wfinddatai64_t _wfinddata32i64_t + +#define _wfindfirst _wfindfirst32 +#define _wfindnext _wfindnext32 +#define _wfindfirsti64 _wfindfirst32i64 +#define _wfindnexti64 _wfindnext32i64 +#else +#define _wfinddata_t _wfinddata64i32_t +#define _wfinddatai64_t _wfinddata64_t + +#define _wfindfirst _wfindfirst64i32 +#define _wfindnext _wfindnext64i32 +#define _wfindfirsti64 _wfindfirst64 +#define _wfindnexti64 _wfindnext64 +#endif + +#define _WFINDDATA_T_DEFINED +#endif + +#define _A_NORMAL 0x00 +#define _A_RDONLY 0x01 +#define _A_HIDDEN 0x02 +#define _A_SYSTEM 0x04 +#define _A_SUBDIR 0x10 +#define _A_ARCH 0x20 + +#ifndef _SIZE_T_DEFINED +#define _SIZE_T_DEFINED +#undef size_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef unsigned int size_t __attribute__ ((mode (DI))); +#else + typedef unsigned __int64 size_t; +#endif +#else + typedef unsigned int size_t; +#endif +#endif + +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#undef ssize_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int ssize_t __attribute__ ((mode (DI))); +#else + typedef __int64 ssize_t; +#endif +#else + typedef int ssize_t; +#endif +#endif + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int _off64_t __attribute__ ((mode (DI))); +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef int off64_t __attribute__ ((mode (DI))); +#endif +#else + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif +#endif + + /* Some defines for _access nAccessMode (MS doesn't define them, but + * it doesn't seem to hurt to add them). */ +#define F_OK 0 /* Check for file existence */ +#define X_OK 1 /* Check for execute permission. */ +#define W_OK 2 /* Check for write permission */ +#define R_OK 4 /* Check for read permission */ + + _CRTIMP int __cdecl _access(const char *_Filename,int _AccessMode); + _CRTIMP int __cdecl _chmod(const char *_Filename,int _Mode); + _CRTIMP int __cdecl _chsize(int _FileHandle,long _Size); + _CRTIMP int __cdecl _close(int _FileHandle); + _CRTIMP int __cdecl _commit(int _FileHandle); + _CRTIMP int __cdecl _creat(const char *_Filename,int _PermissionMode); + _CRTIMP int __cdecl _dup(int _FileHandle); + _CRTIMP int __cdecl _dup2(int _FileHandleSrc,int _FileHandleDst); + _CRTIMP int __cdecl _eof(int _FileHandle); + _CRTIMP long __cdecl _filelength(int _FileHandle); + _CRTIMP intptr_t __cdecl _findfirst32(const char *_Filename,struct _finddata32_t *_FindData); + _CRTIMP int __cdecl _findnext32(intptr_t _FindHandle,struct _finddata32_t *_FindData); + _CRTIMP int __cdecl _findclose(intptr_t _FindHandle); + _CRTIMP int __cdecl _isatty(int _FileHandle); + _CRTIMP int __cdecl _locking(int _FileHandle,int _LockMode,long _NumOfBytes); + _CRTIMP long __cdecl _lseek(int _FileHandle,long _Offset,int _Origin); + _off64_t lseek64(int fd,_off64_t offset, int whence); + _CRTIMP char *__cdecl _mktemp(char *_TemplateName); + _CRTIMP int __cdecl _pipe(int *_PtHandles,unsigned int _PipeSize,int _TextMode); + _CRTIMP int __cdecl _read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); + +#ifndef _CRT_DIRECTORY_DEFINED +#define _CRT_DIRECTORY_DEFINED + int __cdecl remove(const char *_Filename); + int __cdecl rename(const char *_OldFilename,const char *_NewFilename); + _CRTIMP int __cdecl _unlink(const char *_Filename); +#ifndef NO_OLDNAMES + int __cdecl unlink(const char *_Filename); +#endif +#endif + + _CRTIMP int __cdecl _setmode(int _FileHandle,int _Mode); + _CRTIMP long __cdecl _tell(int _FileHandle); + _CRTIMP int __cdecl _umask(int _Mode); + _CRTIMP int __cdecl _write(int _FileHandle,const void *_Buf,unsigned int _MaxCharCount); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP __int64 __cdecl _filelengthi64(int _FileHandle); + _CRTIMP intptr_t __cdecl _findfirst32i64(const char *_Filename,struct _finddata32i64_t *_FindData); + _CRTIMP intptr_t __cdecl _findfirst64(const char *_Filename,struct __finddata64_t *_FindData); +#ifdef __cplusplus +#include +#endif + intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData); + __CRT_INLINE intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData) + { + struct __finddata64_t fd; + intptr_t ret = _findfirst64(_Filename,&fd); + _FindData->attrib=fd.attrib; + _FindData->time_create=fd.time_create; + _FindData->time_access=fd.time_access; + _FindData->time_write=fd.time_write; + _FindData->size=(_fsize_t) fd.size; + strncpy(_FindData->name,fd.name,260); + return ret; + } + _CRTIMP int __cdecl _findnext32i64(intptr_t _FindHandle,struct _finddata32i64_t *_FindData); + _CRTIMP int __cdecl _findnext64(intptr_t _FindHandle,struct __finddata64_t *_FindData); + int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData); + __CRT_INLINE int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData) + { + struct __finddata64_t fd; + int ret = _findnext64(_FindHandle,&fd); + _FindData->attrib=fd.attrib; + _FindData->time_create=fd.time_create; + _FindData->time_access=fd.time_access; + _FindData->time_write=fd.time_write; + _FindData->size=(_fsize_t) fd.size; + strncpy(_FindData->name,fd.name,260); + return ret; + } + __int64 __cdecl _lseeki64(int _FileHandle,__int64 _Offset,int _Origin); + __int64 __cdecl _telli64(int _FileHandle); +#endif +#ifndef NO_OLDNAMES + +#ifndef _UWIN + int __cdecl chdir (const char *); + char *__cdecl getcwd (char *, int); + int __cdecl mkdir (const char *); + char *__cdecl mktemp(char *); + int __cdecl rmdir (const char*); + int __cdecl chmod (const char *, int); +#endif /* _UWIN */ + +#endif /* Not NO_OLDNAMES */ + + _CRTIMP errno_t __cdecl _sopen_s(int *_FileHandle,const char *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode); + +#ifndef __cplusplus + _CRTIMP int __cdecl _open(const char *_Filename,int _OpenFlag,...); + _CRTIMP int __cdecl _sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); +#else + extern "C++" _CRTIMP int __cdecl _open(const char *_Filename,int _Openflag,int _PermissionMode = 0); + extern "C++" _CRTIMP int __cdecl _sopen(const char *_Filename,int _Openflag,int _ShareFlag,int _PermissionMode = 0); +#endif + +#ifndef _WIO_DEFINED +#define _WIO_DEFINED + _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); + _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); + _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); + _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); + _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); + _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); + intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); + _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); + _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); + int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); + _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); +#endif + + _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); + +#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) + _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); + _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); +#else + extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); + extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); +#endif + +#endif + + int __cdecl __lock_fhandle(int _Filehandle); + void __cdecl _unlock_fhandle(int _Filehandle); + _CRTIMP intptr_t __cdecl _get_osfhandle(int _FileHandle); + _CRTIMP int __cdecl _open_osfhandle(intptr_t _OSFileHandle,int _Flags); + +#ifndef NO_OLDNAMES + int __cdecl access(const char *_Filename,int _AccessMode); + int __cdecl chmod(const char *_Filename,int _AccessMode); + int __cdecl chsize(int _FileHandle,long _Size); + int __cdecl close(int _FileHandle); + int __cdecl creat(const char *_Filename,int _PermissionMode); + int __cdecl dup(int _FileHandle); + int __cdecl dup2(int _FileHandleSrc,int _FileHandleDst); + int __cdecl eof(int _FileHandle); + long __cdecl filelength(int _FileHandle); + int __cdecl isatty(int _FileHandle); + int __cdecl locking(int _FileHandle,int _LockMode,long _NumOfBytes); + long __cdecl lseek(int _FileHandle,long _Offset,int _Origin); + char *__cdecl mktemp(char *_TemplateName); + int __cdecl open(const char *_Filename,int _OpenFlag,...); + int __cdecl read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); + int __cdecl setmode(int _FileHandle,int _Mode); + int __cdecl sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); + long __cdecl tell(int _FileHandle); + int __cdecl umask(int _Mode); + int __cdecl write(int _Filehandle,const void *_Buf,unsigned int _MaxCharCount); +#endif + +#ifdef __cplusplus +} +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Misc stuff */ +char *getlogin(void); +#ifdef __USE_MINGW_ALARM +unsigned int alarm(unsigned int seconds); +#endif + +#ifdef __USE_MINGW_ACCESS +/* Old versions of MSVCRT access() just ignored X_OK, while the version + shipped with Vista, returns an error code. This will restore the + old behaviour */ +static inline int __mingw_access (const char *__fname, int __mode) { + return _access (__fname, __mode & ~X_OK); +} + +#define access(__f,__m) __mingw_access (__f, __m) +#endif + + +#ifdef __cplusplus +} +#endif + + +#pragma pack(pop) + +#include + +#endif /* End _IO_H_ */ + diff --git a/tcc/include/iso646.h b/tcc/include/iso646.h index 02770f6b..2cea9a65 100644 --- a/tcc/include/iso646.h +++ b/tcc/include/iso646.h @@ -1,36 +1,36 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the TinyCC package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -/* - * ISO C Standard: 7.9 Alternative spellings - */ - -#ifndef _ISO646_H_ -#define _ISO646_H_ - -#define and && -#define and_eq &= -#define bitand & -#define bitor | -#define compl ~ -#define not ! -#define not_eq != -#define or || -#define or_eq |= -#define xor ^ -#define xor_eq ^= - -#endif /* _ISO646_H_ */ - - - - - - - - - - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the TinyCC package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +/* + * ISO C Standard: 7.9 Alternative spellings + */ + +#ifndef _ISO646_H_ +#define _ISO646_H_ + +#define and && +#define and_eq &= +#define bitand & +#define bitor | +#define compl ~ +#define not ! +#define not_eq != +#define or || +#define or_eq |= +#define xor ^ +#define xor_eq ^= + +#endif /* _ISO646_H_ */ + + + + + + + + + + diff --git a/tcc/include/limits.h b/tcc/include/limits.h index 498e02e4..816a5e97 100644 --- a/tcc/include/limits.h +++ b/tcc/include/limits.h @@ -1,116 +1,116 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#include <_mingw.h> - -#ifndef _INC_LIMITS -#define _INC_LIMITS - -/* -* File system limits -* -* TODO: NAME_MAX and OPEN_MAX are file system limits or not? Are they the -* same as FILENAME_MAX and FOPEN_MAX from stdio.h? -* NOTE: Apparently the actual size of PATH_MAX is 260, but a space is -* required for the NUL. TODO: Test? -*/ -#define PATH_MAX (259) - -#define CHAR_BIT 8 -#define SCHAR_MIN (-128) -#define SCHAR_MAX 127 -#define UCHAR_MAX 0xff - -#ifndef __CHAR_UNSIGNED__ -#define CHAR_MIN SCHAR_MIN -#define CHAR_MAX SCHAR_MAX -#else -#define CHAR_MIN 0 -#define CHAR_MAX UCHAR_MAX -#endif - -#define MB_LEN_MAX 5 -#define SHRT_MIN (-32768) -#define SHRT_MAX 32767 -#define USHRT_MAX 0xffff -#define INT_MIN (-2147483647 - 1) -#define INT_MAX 2147483647 -#define UINT_MAX 0xffffffff -#define LONG_MIN (-2147483647L - 1) -#define LONG_MAX 2147483647L -#define ULONG_MAX 0xffffffffUL -#define LLONG_MAX 9223372036854775807ll -#define LLONG_MIN (-9223372036854775807ll - 1) -#define ULLONG_MAX 0xffffffffffffffffull - -#if _INTEGRAL_MAX_BITS >= 8 -#define _I8_MIN (-127 - 1) -#define _I8_MAX 127i8 -#define _UI8_MAX 0xffu -#endif - -#if _INTEGRAL_MAX_BITS >= 16 -#define _I16_MIN (-32767 - 1) -#define _I16_MAX 32767i16 -#define _UI16_MAX 0xffffu -#endif - -#if _INTEGRAL_MAX_BITS >= 32 -#define _I32_MIN (-2147483647 - 1) -#define _I32_MAX 2147483647 -#define _UI32_MAX 0xffffffffu -#endif - -#if defined(__GNUC__) -#undef LONG_LONG_MAX -#define LONG_LONG_MAX 9223372036854775807ll -#undef LONG_LONG_MIN -#define LONG_LONG_MIN (-LONG_LONG_MAX-1) -#undef ULONG_LONG_MAX -#define ULONG_LONG_MAX (2ull * LONG_LONG_MAX + 1ull) -#endif - -#if _INTEGRAL_MAX_BITS >= 64 -#define _I64_MIN (-9223372036854775807ll - 1) -#define _I64_MAX 9223372036854775807ll -#define _UI64_MAX 0xffffffffffffffffull -#endif - -#ifndef SIZE_MAX -#ifdef _WIN64 -#define SIZE_MAX _UI64_MAX -#else -#define SIZE_MAX UINT_MAX -#endif -#endif - -#ifdef _POSIX_ -#define _POSIX_ARG_MAX 4096 -#define _POSIX_CHILD_MAX 6 -#define _POSIX_LINK_MAX 8 -#define _POSIX_MAX_CANON 255 -#define _POSIX_MAX_INPUT 255 -#define _POSIX_NAME_MAX 14 -#define _POSIX_NGROUPS_MAX 0 -#define _POSIX_OPEN_MAX 16 -#define _POSIX_PATH_MAX 255 -#define _POSIX_PIPE_BUF 512 -#define _POSIX_SSIZE_MAX 32767 -#define _POSIX_STREAM_MAX 8 -#define _POSIX_TZNAME_MAX 3 -#define ARG_MAX 14500 -#define LINK_MAX 1024 -#define MAX_CANON _POSIX_MAX_CANON -#define MAX_INPUT _POSIX_MAX_INPUT -#define NAME_MAX 255 -#define NGROUPS_MAX 16 -#define OPEN_MAX 32 -#define PATH_MAX 512 -#define PIPE_BUF _POSIX_PIPE_BUF -#define SSIZE_MAX _POSIX_SSIZE_MAX -#define STREAM_MAX 20 -#define TZNAME_MAX 10 -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#include <_mingw.h> + +#ifndef _INC_LIMITS +#define _INC_LIMITS + +/* +* File system limits +* +* TODO: NAME_MAX and OPEN_MAX are file system limits or not? Are they the +* same as FILENAME_MAX and FOPEN_MAX from stdio.h? +* NOTE: Apparently the actual size of PATH_MAX is 260, but a space is +* required for the NUL. TODO: Test? +*/ +#define PATH_MAX (259) + +#define CHAR_BIT 8 +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 +#define UCHAR_MAX 0xff + +#ifndef __CHAR_UNSIGNED__ +#define CHAR_MIN SCHAR_MIN +#define CHAR_MAX SCHAR_MAX +#else +#define CHAR_MIN 0 +#define CHAR_MAX UCHAR_MAX +#endif + +#define MB_LEN_MAX 5 +#define SHRT_MIN (-32768) +#define SHRT_MAX 32767 +#define USHRT_MAX 0xffff +#define INT_MIN (-2147483647 - 1) +#define INT_MAX 2147483647 +#define UINT_MAX 0xffffffff +#define LONG_MIN (-2147483647L - 1) +#define LONG_MAX 2147483647L +#define ULONG_MAX 0xffffffffUL +#define LLONG_MAX 9223372036854775807ll +#define LLONG_MIN (-9223372036854775807ll - 1) +#define ULLONG_MAX 0xffffffffffffffffull + +#if _INTEGRAL_MAX_BITS >= 8 +#define _I8_MIN (-127 - 1) +#define _I8_MAX 127i8 +#define _UI8_MAX 0xffu +#endif + +#if _INTEGRAL_MAX_BITS >= 16 +#define _I16_MIN (-32767 - 1) +#define _I16_MAX 32767i16 +#define _UI16_MAX 0xffffu +#endif + +#if _INTEGRAL_MAX_BITS >= 32 +#define _I32_MIN (-2147483647 - 1) +#define _I32_MAX 2147483647 +#define _UI32_MAX 0xffffffffu +#endif + +#if defined(__GNUC__) +#undef LONG_LONG_MAX +#define LONG_LONG_MAX 9223372036854775807ll +#undef LONG_LONG_MIN +#define LONG_LONG_MIN (-LONG_LONG_MAX-1) +#undef ULONG_LONG_MAX +#define ULONG_LONG_MAX (2ull * LONG_LONG_MAX + 1ull) +#endif + +#if _INTEGRAL_MAX_BITS >= 64 +#define _I64_MIN (-9223372036854775807ll - 1) +#define _I64_MAX 9223372036854775807ll +#define _UI64_MAX 0xffffffffffffffffull +#endif + +#ifndef SIZE_MAX +#ifdef _WIN64 +#define SIZE_MAX _UI64_MAX +#else +#define SIZE_MAX UINT_MAX +#endif +#endif + +#ifdef _POSIX_ +#define _POSIX_ARG_MAX 4096 +#define _POSIX_CHILD_MAX 6 +#define _POSIX_LINK_MAX 8 +#define _POSIX_MAX_CANON 255 +#define _POSIX_MAX_INPUT 255 +#define _POSIX_NAME_MAX 14 +#define _POSIX_NGROUPS_MAX 0 +#define _POSIX_OPEN_MAX 16 +#define _POSIX_PATH_MAX 255 +#define _POSIX_PIPE_BUF 512 +#define _POSIX_SSIZE_MAX 32767 +#define _POSIX_STREAM_MAX 8 +#define _POSIX_TZNAME_MAX 3 +#define ARG_MAX 14500 +#define LINK_MAX 1024 +#define MAX_CANON _POSIX_MAX_CANON +#define MAX_INPUT _POSIX_MAX_INPUT +#define NAME_MAX 255 +#define NGROUPS_MAX 16 +#define OPEN_MAX 32 +#define PATH_MAX 512 +#define PIPE_BUF _POSIX_PIPE_BUF +#define SSIZE_MAX _POSIX_SSIZE_MAX +#define STREAM_MAX 20 +#define TZNAME_MAX 10 +#endif +#endif diff --git a/tcc/include/locale.h b/tcc/include/locale.h index 686aa9ba..64bfc6d4 100644 --- a/tcc/include/locale.h +++ b/tcc/include/locale.h @@ -1,91 +1,91 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_LOCALE -#define _INC_LOCALE - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define LC_ALL 0 -#define LC_COLLATE 1 -#define LC_CTYPE 2 -#define LC_MONETARY 3 -#define LC_NUMERIC 4 -#define LC_TIME 5 - -#define LC_MIN LC_ALL -#define LC_MAX LC_TIME - -#ifndef _LCONV_DEFINED -#define _LCONV_DEFINED - struct lconv { - char *decimal_point; - char *thousands_sep; - char *grouping; - char *int_curr_symbol; - char *currency_symbol; - char *mon_decimal_point; - char *mon_thousands_sep; - char *mon_grouping; - char *positive_sign; - char *negative_sign; - char int_frac_digits; - char frac_digits; - char p_cs_precedes; - char p_sep_by_space; - char n_cs_precedes; - char n_sep_by_space; - char p_sign_posn; - char n_sign_posn; - }; -#endif - -#ifndef _CONFIG_LOCALE_SWT -#define _CONFIG_LOCALE_SWT - -#define _ENABLE_PER_THREAD_LOCALE 0x1 -#define _DISABLE_PER_THREAD_LOCALE 0x2 -#define _ENABLE_PER_THREAD_LOCALE_GLOBAL 0x10 -#define _DISABLE_PER_THREAD_LOCALE_GLOBAL 0x20 -#define _ENABLE_PER_THREAD_LOCALE_NEW 0x100 -#define _DISABLE_PER_THREAD_LOCALE_NEW 0x200 - -#endif - - int __cdecl _configthreadlocale(int _Flag); - char *__cdecl setlocale(int _Category,const char *_Locale); - _CRTIMP struct lconv *__cdecl localeconv(void); - _locale_t __cdecl _get_current_locale(void); - _locale_t __cdecl _create_locale(int _Category,const char *_Locale); - void __cdecl _free_locale(_locale_t _Locale); - _locale_t __cdecl __get_current_locale(void); - _locale_t __cdecl __create_locale(int _Category,const char *_Locale); - void __cdecl __free_locale(_locale_t _Locale); - -#ifndef _WLOCALE_DEFINED -#define _WLOCALE_DEFINED - _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_LOCALE +#define _INC_LOCALE + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define LC_ALL 0 +#define LC_COLLATE 1 +#define LC_CTYPE 2 +#define LC_MONETARY 3 +#define LC_NUMERIC 4 +#define LC_TIME 5 + +#define LC_MIN LC_ALL +#define LC_MAX LC_TIME + +#ifndef _LCONV_DEFINED +#define _LCONV_DEFINED + struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + }; +#endif + +#ifndef _CONFIG_LOCALE_SWT +#define _CONFIG_LOCALE_SWT + +#define _ENABLE_PER_THREAD_LOCALE 0x1 +#define _DISABLE_PER_THREAD_LOCALE 0x2 +#define _ENABLE_PER_THREAD_LOCALE_GLOBAL 0x10 +#define _DISABLE_PER_THREAD_LOCALE_GLOBAL 0x20 +#define _ENABLE_PER_THREAD_LOCALE_NEW 0x100 +#define _DISABLE_PER_THREAD_LOCALE_NEW 0x200 + +#endif + + int __cdecl _configthreadlocale(int _Flag); + char *__cdecl setlocale(int _Category,const char *_Locale); + _CRTIMP struct lconv *__cdecl localeconv(void); + _locale_t __cdecl _get_current_locale(void); + _locale_t __cdecl _create_locale(int _Category,const char *_Locale); + void __cdecl _free_locale(_locale_t _Locale); + _locale_t __cdecl __get_current_locale(void); + _locale_t __cdecl __create_locale(int _Category,const char *_Locale); + void __cdecl __free_locale(_locale_t _Locale); + +#ifndef _WLOCALE_DEFINED +#define _WLOCALE_DEFINED + _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/malloc.h b/tcc/include/malloc.h index fc783a8e..6e42432e 100644 --- a/tcc/include/malloc.h +++ b/tcc/include/malloc.h @@ -1,181 +1,181 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _MALLOC_H_ -#define _MALLOC_H_ - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifndef _MM_MALLOC_H_INCLUDED -#define _MM_MALLOC_H_INCLUDED -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _WIN64 -#define _HEAP_MAXREQ 0xFFFFFFFFFFFFFFE0 -#else -#define _HEAP_MAXREQ 0xFFFFFFE0 -#endif - -#ifndef _STATIC_ASSERT -#define _STATIC_ASSERT(expr) extern void __static_assert_t(int [(expr)?1:-1]) -#endif - -/* Return codes for _heapwalk() */ -#define _HEAPEMPTY (-1) -#define _HEAPOK (-2) -#define _HEAPBADBEGIN (-3) -#define _HEAPBADNODE (-4) -#define _HEAPEND (-5) -#define _HEAPBADPTR (-6) - -/* Values for _heapinfo.useflag */ -#define _FREEENTRY 0 -#define _USEDENTRY 1 - -#ifndef _HEAPINFO_DEFINED -#define _HEAPINFO_DEFINED - /* The structure used to walk through the heap with _heapwalk. */ - typedef struct _heapinfo { - int *_pentry; - size_t _size; - int _useflag; - } _HEAPINFO; -#endif - - extern unsigned int _amblksiz; - -#define _mm_free(a) _aligned_free(a) -#define _mm_malloc(a,b) _aligned_malloc(a,b) - -#ifndef _CRT_ALLOCATION_DEFINED -#define _CRT_ALLOCATION_DEFINED - void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); - void __cdecl free(void *_Memory); - void *__cdecl malloc(size_t _Size); - void *__cdecl realloc(void *_Memory,size_t _NewSize); - _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); - /* _CRTIMP void __cdecl _aligned_free(void *_Memory); - _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); */ - _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); -#endif - -#define _MAX_WAIT_MALLOC_CRT 60000 - - _CRTIMP int __cdecl _resetstkoflw (void); - _CRTIMP unsigned long __cdecl _set_malloc_crt_max_wait(unsigned long _NewValue); - - _CRTIMP void *__cdecl _expand(void *_Memory,size_t _NewSize); - _CRTIMP size_t __cdecl _msize(void *_Memory); -#ifdef __GNUC__ -#undef _alloca -#define _alloca(x) __builtin_alloca((x)) -#else - /* tcc implements alloca internally and exposes it (since commit d778bde7). - /* alloca is declared at include/stddef.h (which is distributed with tcc). - */ -#ifdef _alloca -#undef _alloca -#endif -#define _alloca(x) alloca((x)) -#endif - _CRTIMP size_t __cdecl _get_sbh_threshold(void); - _CRTIMP int __cdecl _set_sbh_threshold(size_t _NewValue); - _CRTIMP errno_t __cdecl _set_amblksiz(size_t _Value); - _CRTIMP errno_t __cdecl _get_amblksiz(size_t *_Value); - _CRTIMP int __cdecl _heapadd(void *_Memory,size_t _Size); - _CRTIMP int __cdecl _heapchk(void); - _CRTIMP int __cdecl _heapmin(void); - _CRTIMP int __cdecl _heapset(unsigned int _Fill); - _CRTIMP int __cdecl _heapwalk(_HEAPINFO *_EntryInfo); - _CRTIMP size_t __cdecl _heapused(size_t *_Used,size_t *_Commit); - _CRTIMP intptr_t __cdecl _get_heap_handle(void); - -#define _ALLOCA_S_THRESHOLD 1024 -#define _ALLOCA_S_STACK_MARKER 0xCCCC -#define _ALLOCA_S_HEAP_MARKER 0xDDDD - -#if(defined(_X86_) && !defined(__x86_64)) -#define _ALLOCA_S_MARKER_SIZE 8 -#elif defined(__ia64__) || defined(__x86_64) -#define _ALLOCA_S_MARKER_SIZE 16 -#endif - -#if !defined(RC_INVOKED) - static __inline void *_MarkAllocaS(void *_Ptr,unsigned int _Marker) { - if(_Ptr) { - *((unsigned int*)_Ptr) = _Marker; - _Ptr = (char*)_Ptr + _ALLOCA_S_MARKER_SIZE; - } - return _Ptr; - } -#endif - -#undef _malloca -#define _malloca(size) \ - ((((size) + _ALLOCA_S_MARKER_SIZE) <= _ALLOCA_S_THRESHOLD) ? \ - _MarkAllocaS(_alloca((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_STACK_MARKER) : \ - _MarkAllocaS(malloc((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_HEAP_MARKER)) -#undef _FREEA_INLINE -#define _FREEA_INLINE - -#ifndef RC_INVOKED -#undef _freea - static __inline void __cdecl _freea(void *_Memory) { - unsigned int _Marker; - if(_Memory) { - _Memory = (char*)_Memory - _ALLOCA_S_MARKER_SIZE; - _Marker = *(unsigned int *)_Memory; - if(_Marker==_ALLOCA_S_HEAP_MARKER) { - free(_Memory); - } -#ifdef _ASSERTE - else if(_Marker!=_ALLOCA_S_STACK_MARKER) { - _ASSERTE(("Corrupted pointer passed to _freea",0)); - } -#endif - } - } -#endif /* RC_INVOKED */ - -#ifndef NO_OLDNAMES -#ifdef __GNUC__ -#undef alloca -#define alloca(x) __builtin_alloca((x)) -#endif -#endif - -#ifdef HEAPHOOK -#ifndef _HEAPHOOK_DEFINED -#define _HEAPHOOK_DEFINED - typedef int (__cdecl *_HEAPHOOK)(int,size_t,void *,void **); -#endif - - _CRTIMP _HEAPHOOK __cdecl _setheaphook(_HEAPHOOK _NewHook); - -#define _HEAP_MALLOC 1 -#define _HEAP_CALLOC 2 -#define _HEAP_FREE 3 -#define _HEAP_REALLOC 4 -#define _HEAP_MSIZE 5 -#define _HEAP_EXPAND 6 -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#endif /* _MALLOC_H_ */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _MALLOC_H_ +#define _MALLOC_H_ + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifndef _MM_MALLOC_H_INCLUDED +#define _MM_MALLOC_H_INCLUDED +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN64 +#define _HEAP_MAXREQ 0xFFFFFFFFFFFFFFE0 +#else +#define _HEAP_MAXREQ 0xFFFFFFE0 +#endif + +#ifndef _STATIC_ASSERT +#define _STATIC_ASSERT(expr) extern void __static_assert_t(int [(expr)?1:-1]) +#endif + +/* Return codes for _heapwalk() */ +#define _HEAPEMPTY (-1) +#define _HEAPOK (-2) +#define _HEAPBADBEGIN (-3) +#define _HEAPBADNODE (-4) +#define _HEAPEND (-5) +#define _HEAPBADPTR (-6) + +/* Values for _heapinfo.useflag */ +#define _FREEENTRY 0 +#define _USEDENTRY 1 + +#ifndef _HEAPINFO_DEFINED +#define _HEAPINFO_DEFINED + /* The structure used to walk through the heap with _heapwalk. */ + typedef struct _heapinfo { + int *_pentry; + size_t _size; + int _useflag; + } _HEAPINFO; +#endif + + extern unsigned int _amblksiz; + +#define _mm_free(a) _aligned_free(a) +#define _mm_malloc(a,b) _aligned_malloc(a,b) + +#ifndef _CRT_ALLOCATION_DEFINED +#define _CRT_ALLOCATION_DEFINED + void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); + void __cdecl free(void *_Memory); + void *__cdecl malloc(size_t _Size); + void *__cdecl realloc(void *_Memory,size_t _NewSize); + _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); + /* _CRTIMP void __cdecl _aligned_free(void *_Memory); + _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); */ + _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); +#endif + +#define _MAX_WAIT_MALLOC_CRT 60000 + + _CRTIMP int __cdecl _resetstkoflw (void); + _CRTIMP unsigned long __cdecl _set_malloc_crt_max_wait(unsigned long _NewValue); + + _CRTIMP void *__cdecl _expand(void *_Memory,size_t _NewSize); + _CRTIMP size_t __cdecl _msize(void *_Memory); +#ifdef __GNUC__ +#undef _alloca +#define _alloca(x) __builtin_alloca((x)) +#else + /* tcc implements alloca internally and exposes it (since commit d778bde7). + /* alloca is declared at include/stddef.h (which is distributed with tcc). + */ +#ifdef _alloca +#undef _alloca +#endif +#define _alloca(x) alloca((x)) +#endif + _CRTIMP size_t __cdecl _get_sbh_threshold(void); + _CRTIMP int __cdecl _set_sbh_threshold(size_t _NewValue); + _CRTIMP errno_t __cdecl _set_amblksiz(size_t _Value); + _CRTIMP errno_t __cdecl _get_amblksiz(size_t *_Value); + _CRTIMP int __cdecl _heapadd(void *_Memory,size_t _Size); + _CRTIMP int __cdecl _heapchk(void); + _CRTIMP int __cdecl _heapmin(void); + _CRTIMP int __cdecl _heapset(unsigned int _Fill); + _CRTIMP int __cdecl _heapwalk(_HEAPINFO *_EntryInfo); + _CRTIMP size_t __cdecl _heapused(size_t *_Used,size_t *_Commit); + _CRTIMP intptr_t __cdecl _get_heap_handle(void); + +#define _ALLOCA_S_THRESHOLD 1024 +#define _ALLOCA_S_STACK_MARKER 0xCCCC +#define _ALLOCA_S_HEAP_MARKER 0xDDDD + +#if(defined(_X86_) && !defined(__x86_64)) +#define _ALLOCA_S_MARKER_SIZE 8 +#elif defined(__ia64__) || defined(__x86_64) +#define _ALLOCA_S_MARKER_SIZE 16 +#endif + +#if !defined(RC_INVOKED) + static __inline void *_MarkAllocaS(void *_Ptr,unsigned int _Marker) { + if(_Ptr) { + *((unsigned int*)_Ptr) = _Marker; + _Ptr = (char*)_Ptr + _ALLOCA_S_MARKER_SIZE; + } + return _Ptr; + } +#endif + +#undef _malloca +#define _malloca(size) \ + ((((size) + _ALLOCA_S_MARKER_SIZE) <= _ALLOCA_S_THRESHOLD) ? \ + _MarkAllocaS(_alloca((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_STACK_MARKER) : \ + _MarkAllocaS(malloc((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_HEAP_MARKER)) +#undef _FREEA_INLINE +#define _FREEA_INLINE + +#ifndef RC_INVOKED +#undef _freea + static __inline void __cdecl _freea(void *_Memory) { + unsigned int _Marker; + if(_Memory) { + _Memory = (char*)_Memory - _ALLOCA_S_MARKER_SIZE; + _Marker = *(unsigned int *)_Memory; + if(_Marker==_ALLOCA_S_HEAP_MARKER) { + free(_Memory); + } +#ifdef _ASSERTE + else if(_Marker!=_ALLOCA_S_STACK_MARKER) { + _ASSERTE(("Corrupted pointer passed to _freea",0)); + } +#endif + } + } +#endif /* RC_INVOKED */ + +#ifndef NO_OLDNAMES +#ifdef __GNUC__ +#undef alloca +#define alloca(x) __builtin_alloca((x)) +#endif +#endif + +#ifdef HEAPHOOK +#ifndef _HEAPHOOK_DEFINED +#define _HEAPHOOK_DEFINED + typedef int (__cdecl *_HEAPHOOK)(int,size_t,void *,void **); +#endif + + _CRTIMP _HEAPHOOK __cdecl _setheaphook(_HEAPHOOK _NewHook); + +#define _HEAP_MALLOC 1 +#define _HEAP_CALLOC 2 +#define _HEAP_FREE 3 +#define _HEAP_REALLOC 4 +#define _HEAP_MSIZE 5 +#define _HEAP_EXPAND 6 +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#endif /* _MALLOC_H_ */ diff --git a/tcc/include/math.h b/tcc/include/math.h index 8e66407e..1b2c2b23 100644 --- a/tcc/include/math.h +++ b/tcc/include/math.h @@ -1,497 +1,497 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _MATH_H_ -#define _MATH_H_ - -#if __GNUC__ >= 3 -#pragma GCC system_header -#endif - -#include <_mingw.h> - -struct exception; - -#pragma pack(push,_CRT_PACKING) - -#define _DOMAIN 1 -#define _SING 2 -#define _OVERFLOW 3 -#define _UNDERFLOW 4 -#define _TLOSS 5 -#define _PLOSS 6 - -#ifndef __STRICT_ANSI__ -#ifndef NO_OLDNAMES -#define DOMAIN _DOMAIN -#define SING _SING -#define OVERFLOW _OVERFLOW -#define UNDERFLOW _UNDERFLOW -#define TLOSS _TLOSS -#define PLOSS _PLOSS -#endif -#endif - -#ifndef __STRICT_ANSI__ -#define M_E 2.71828182845904523536 -#define M_LOG2E 1.44269504088896340736 -#define M_LOG10E 0.434294481903251827651 -#define M_LN2 0.693147180559945309417 -#define M_LN10 2.30258509299404568402 -#define M_PI 3.14159265358979323846 -#define M_PI_2 1.57079632679489661923 -#define M_PI_4 0.785398163397448309616 -#define M_1_PI 0.318309886183790671538 -#define M_2_PI 0.636619772367581343076 -#define M_2_SQRTPI 1.12837916709551257390 -#define M_SQRT2 1.41421356237309504880 -#define M_SQRT1_2 0.707106781186547524401 -#endif - -#ifndef __STRICT_ANSI__ -/* See also float.h */ -#ifndef __MINGW_FPCLASS_DEFINED -#define __MINGW_FPCLASS_DEFINED 1 -#define _FPCLASS_SNAN 0x0001 /* Signaling "Not a Number" */ -#define _FPCLASS_QNAN 0x0002 /* Quiet "Not a Number" */ -#define _FPCLASS_NINF 0x0004 /* Negative Infinity */ -#define _FPCLASS_NN 0x0008 /* Negative Normal */ -#define _FPCLASS_ND 0x0010 /* Negative Denormal */ -#define _FPCLASS_NZ 0x0020 /* Negative Zero */ -#define _FPCLASS_PZ 0x0040 /* Positive Zero */ -#define _FPCLASS_PD 0x0080 /* Positive Denormal */ -#define _FPCLASS_PN 0x0100 /* Positive Normal */ -#define _FPCLASS_PINF 0x0200 /* Positive Infinity */ -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _EXCEPTION_DEFINED -#define _EXCEPTION_DEFINED - struct _exception { - int type; - char *name; - double arg1; - double arg2; - double retval; - }; -#endif - -#ifndef _COMPLEX_DEFINED -#define _COMPLEX_DEFINED - struct _complex { - double x,y; - }; -#endif - -#define EDOM 33 -#define ERANGE 34 - -#ifndef _HUGE -#ifdef _MSVCRT_ - extern double *_HUGE; -#else - extern double *_imp___HUGE; -#define _HUGE (*_imp___HUGE) -#endif -#endif - -#define HUGE_VAL _HUGE - -#ifndef _CRT_ABS_DEFINED -#define _CRT_ABS_DEFINED - int __cdecl abs(int _X); - long __cdecl labs(long _X); -#endif - double __cdecl acos(double _X); - double __cdecl asin(double _X); - double __cdecl atan(double _X); - double __cdecl atan2(double _Y,double _X); -#ifndef _SIGN_DEFINED -#define _SIGN_DEFINED - _CRTIMP double __cdecl _copysign (double _Number,double _Sign); - _CRTIMP double __cdecl _chgsign (double _X); -#endif - double __cdecl cos(double _X); - double __cdecl cosh(double _X); - double __cdecl exp(double _X); - double __cdecl expm1(double _X); - double __cdecl fabs(double _X); - double __cdecl fmod(double _X,double _Y); - double __cdecl log(double _X); - double __cdecl log10(double _X); - double __cdecl pow(double _X,double _Y); - double __cdecl sin(double _X); - double __cdecl sinh(double _X); - double __cdecl tan(double _X); - double __cdecl tanh(double _X); - double __cdecl sqrt(double _X); -#ifndef _CRT_ATOF_DEFINED -#define _CRT_ATOF_DEFINED - double __cdecl atof(const char *_String); - double __cdecl _atof_l(const char *_String,_locale_t _Locale); -#endif - - _CRTIMP double __cdecl _cabs(struct _complex _ComplexA); - double __cdecl ceil(double _X); - double __cdecl floor(double _X); - double __cdecl frexp(double _X,int *_Y); - double __cdecl _hypot(double _X,double _Y); - _CRTIMP double __cdecl _j0(double _X); - _CRTIMP double __cdecl _j1(double _X); - _CRTIMP double __cdecl _jn(int _X,double _Y); - double __cdecl ldexp(double _X,int _Y); -#ifndef _CRT_MATHERR_DEFINED -#define _CRT_MATHERR_DEFINED - int __cdecl _matherr(struct _exception *_Except); -#endif - double __cdecl modf(double _X,double *_Y); - _CRTIMP double __cdecl _y0(double _X); - _CRTIMP double __cdecl _y1(double _X); - _CRTIMP double __cdecl _yn(int _X,double _Y); - -#if(defined(_X86_) && !defined(__x86_64)) - _CRTIMP int __cdecl _set_SSE2_enable(int _Flag); - /* from libmingwex */ - float __cdecl _hypotf(float _X,float _Y); -#endif - - float frexpf(float _X,int *_Y); - float __cdecl ldexpf(float _X,int _Y); - long double __cdecl ldexpl(long double _X,int _Y); - float __cdecl acosf(float _X); - float __cdecl asinf(float _X); - float __cdecl atanf(float _X); - float __cdecl atan2f(float _X,float _Y); - float __cdecl cosf(float _X); - float __cdecl sinf(float _X); - float __cdecl tanf(float _X); - float __cdecl coshf(float _X); - float __cdecl sinhf(float _X); - float __cdecl tanhf(float _X); - float __cdecl expf(float _X); - float __cdecl expm1f(float _X); - float __cdecl logf(float _X); - float __cdecl log10f(float _X); - float __cdecl modff(float _X,float *_Y); - float __cdecl powf(float _X,float _Y); - float __cdecl sqrtf(float _X); - float __cdecl ceilf(float _X); - float __cdecl floorf(float _X); - float __cdecl fmodf(float _X,float _Y); - float __cdecl _hypotf(float _X,float _Y); - float __cdecl fabsf(float _X); -#if !defined(__ia64__) - /* from libmingwex */ - float __cdecl _copysignf (float _Number,float _Sign); - float __cdecl _chgsignf (float _X); - float __cdecl _logbf(float _X); - float __cdecl _nextafterf(float _X,float _Y); - int __cdecl _finitef(float _X); - int __cdecl _isnanf(float _X); - int __cdecl _fpclassf(float _X); -#endif - -#ifndef NO_OLDNAMES -#define matherr _matherr - -#define HUGE _HUGE - /* double __cdecl cabs(struct _complex _X); */ - double __cdecl hypot(double _X,double _Y); - _CRTIMP double __cdecl j0(double _X); - _CRTIMP double __cdecl j1(double _X); - _CRTIMP double __cdecl jn(int _X,double _Y); - _CRTIMP double __cdecl y0(double _X); - _CRTIMP double __cdecl y1(double _X); - _CRTIMP double __cdecl yn(int _X,double _Y); -#endif - -#ifndef __NO_ISOCEXT -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \ - || !defined __STRICT_ANSI__ || defined __GLIBCPP__ - -#define NAN (0.0F/0.0F) -#define HUGE_VALF (1.0F/0.0F) -#define HUGE_VALL (1.0L/0.0L) -#define INFINITY (1.0F/0.0F) - - -#define FP_NAN 0x0100 -#define FP_NORMAL 0x0400 -#define FP_INFINITE (FP_NAN | FP_NORMAL) -#define FP_ZERO 0x4000 -#define FP_SUBNORMAL (FP_NORMAL | FP_ZERO) - /* 0x0200 is signbit mask */ - - - /* - We can't __CRT_INLINE float or double, because we want to ensure truncation - to semantic type before classification. - (A normal long double value might become subnormal when - converted to double, and zero when converted to float.) - */ - - extern int __cdecl __fpclassifyf (float); - extern int __cdecl __fpclassify (double); - extern int __cdecl __fpclassifyl (long double); - -/* Implemented at tcc/tcc_libm.h -#define fpclassify(x) (sizeof (x) == sizeof (float) ? __fpclassifyf (x) \ - : sizeof (x) == sizeof (double) ? __fpclassify (x) \ - : __fpclassifyl (x)) -*/ -#define fpclassify(x) \ - _Generic(x, float: __fpclassifyf, double: __fpclassify, long double: __fpclassifyl)(x) - - /* 7.12.3.2 */ -#define isfinite(x) ((fpclassify(x) & FP_NAN) == 0) - - /* 7.12.3.3 */ -#define isinf(x) (fpclassify(x) == FP_INFINITE) - - /* 7.12.3.4 */ - /* We don't need to worry about truncation here: - A NaN stays a NaN. */ -#define isnan(x) (fpclassify(x) == FP_NAN) - - /* 7.12.3.5 */ -#define isnormal(x) (fpclassify(x) == FP_NORMAL) - - /* 7.12.3.6 The signbit macro */ - - extern int __cdecl __signbitf (float); - extern int __cdecl __signbit (double); - extern int __cdecl __signbitl (long double); - -/* Implemented at tcc/tcc_libm.h -#define signbit(x) (sizeof (x) == sizeof (float) ? __signbitf (x) \ - : sizeof (x) == sizeof (double) ? __signbit (x) \ - : __signbitl (x)) -*/ -#define signbit(x) \ - _Generic(x, float: __signbitf, double: __signbit, long double: __signbitl)(x) - - extern double __cdecl exp2(double); - extern float __cdecl exp2f(float); - extern long double __cdecl exp2l(long double); - -#define FP_ILOGB0 ((int)0x80000000) -#define FP_ILOGBNAN ((int)0x80000000) - extern int __cdecl ilogb (double); - extern int __cdecl ilogbf (float); - extern int __cdecl ilogbl (long double); - - extern double __cdecl log1p(double); - extern float __cdecl log1pf(float); - extern long double __cdecl log1pl(long double); - - extern double __cdecl log2 (double); - extern float __cdecl log2f (float); - extern long double __cdecl log2l (long double); - - extern double __cdecl logb (double); - extern float __cdecl logbf (float); - extern long double __cdecl logbl (long double); - - extern long double __cdecl modfl (long double, long double*); - - /* 7.12.6.13 */ - extern double __cdecl scalbn (double, int); - extern float __cdecl scalbnf (float, int); - extern long double __cdecl scalbnl (long double, int); - - extern double __cdecl scalbln (double, long); - extern float __cdecl scalblnf (float, long); - extern long double __cdecl scalblnl (long double, long); - - /* 7.12.7.1 */ - /* Implementations adapted from Cephes versions */ - extern double __cdecl cbrt (double); - extern float __cdecl cbrtf (float); - extern long double __cdecl cbrtl (long double); - - extern double __cdecl hypot (double, double); - extern float __cdecl hypotf (float, float); - extern long double __cdecl hypotl (long double, long double); - - extern long double __cdecl powl (long double, long double); - extern long double __cdecl expl(long double); - extern long double __cdecl expm1l(long double); - extern long double __cdecl coshl(long double); - extern long double __cdecl fabsl (long double); - extern long double __cdecl acosl(long double); - extern long double __cdecl asinl(long double); - extern long double __cdecl atanl(long double); - extern long double __cdecl atan2l(long double,long double); - extern long double __cdecl sinhl(long double); - extern long double __cdecl tanhl(long double); - - /* 7.12.8.1 The erf functions */ - extern double __cdecl erf (double); - extern float __cdecl erff (float); - /* TODO - extern long double __cdecl erfl (long double); - */ - - /* 7.12.8.2 The erfc functions */ - extern double __cdecl erfc (double); - extern float __cdecl erfcf (float); - /* TODO - extern long double __cdecl erfcl (long double); - */ - - /* 7.12.8.3 The lgamma functions */ - extern double __cdecl lgamma (double); - extern float __cdecl lgammaf (float); - extern long double __cdecl lgammal (long double); - - /* 7.12.8.4 The tgamma functions */ - extern double __cdecl tgamma (double); - extern float __cdecl tgammaf (float); - extern long double __cdecl tgammal (long double); - - extern long double __cdecl ceill (long double); - extern long double __cdecl floorl (long double); - extern long double __cdecl frexpl(long double,int *); - extern long double __cdecl log10l(long double); - extern long double __cdecl logl(long double); - extern long double __cdecl cosl(long double); - extern long double __cdecl sinl(long double); - extern long double __cdecl tanl(long double); - extern long double sqrtl(long double); - - /* 7.12.9.3 */ - extern double __cdecl nearbyint ( double); - extern float __cdecl nearbyintf (float); - extern long double __cdecl nearbyintl (long double); - - /* 7.12.9.4 */ - /* round, using fpu control word settings */ - extern double __cdecl rint (double); - extern float __cdecl rintf (float); - extern long double __cdecl rintl (long double); - - extern long __cdecl lrint (double); - extern long __cdecl lrintf (float); - extern long __cdecl lrintl (long double); - - extern long long __cdecl llrint (double); - extern long long __cdecl llrintf (float); - extern long long __cdecl llrintl (long double); - - #define FE_TONEAREST 0x0000 - #define FE_DOWNWARD 0x0400 - #define FE_UPWARD 0x0800 - #define FE_TOWARDZERO 0x0c00 - - /* 7.12.9.6 */ - /* round away from zero, regardless of fpu control word settings */ - extern double __cdecl round (double); - extern float __cdecl roundf (float); - extern long double __cdecl roundl (long double); - - /* 7.12.9.7 */ - extern long __cdecl lround (double); - extern long __cdecl lroundf (float); - extern long __cdecl lroundl (long double); - - extern long long __cdecl llround (double); - extern long long __cdecl llroundf (float); - extern long long __cdecl llroundl (long double); - - /* 7.12.9.8 */ - /* round towards zero, regardless of fpu control word settings */ - extern double __cdecl trunc (double); - extern float __cdecl truncf (float); - extern long double __cdecl truncl (long double); - - extern long double __cdecl fmodl (long double, long double); - - /* 7.12.10.2 */ - extern double __cdecl remainder (double, double); - extern float __cdecl remainderf (float, float); - extern long double __cdecl remainderl (long double, long double); - - /* 7.12.10.3 */ - extern double __cdecl remquo(double, double, int *); - extern float __cdecl remquof(float, float, int *); - extern long double __cdecl remquol(long double, long double, int *); - - /* 7.12.11.1 */ - extern double __cdecl copysign (double, double); /* in libmoldname.a */ - extern float __cdecl copysignf (float, float); - extern long double __cdecl copysignl (long double, long double); - - /* 7.12.11.2 Return a NaN */ - extern double __cdecl nan(const char *tagp); - extern float __cdecl nanf(const char *tagp); - extern long double __cdecl nanl(const char *tagp); - -#ifndef __STRICT_ANSI__ -#define _nan() nan("") -#define _nanf() nanf("") -#define _nanl() nanl("") -#endif - - /* 7.12.11.3 */ - extern double __cdecl nextafter (double, double); /* in libmoldname.a */ - extern float __cdecl nextafterf (float, float); - extern long double __cdecl nextafterl (long double, long double); - - /* 7.12.11.4 The nexttoward functions: TODO */ - - /* 7.12.12.1 */ - /* x > y ? (x - y) : 0.0 */ - extern double __cdecl fdim (double x, double y); - extern float __cdecl fdimf (float x, float y); - extern long double __cdecl fdiml (long double x, long double y); - - /* fmax and fmin. - NaN arguments are treated as missing data: if one argument is a NaN - and the other numeric, then these functions choose the numeric - value. */ - - /* 7.12.12.2 */ - extern double __cdecl fmax (double, double); - extern float __cdecl fmaxf (float, float); - extern long double __cdecl fmaxl (long double, long double); - - /* 7.12.12.3 */ - extern double __cdecl fmin (double, double); - extern float __cdecl fminf (float, float); - extern long double __cdecl fminl (long double, long double); - - /* 7.12.13.1 */ - /* return x * y + z as a ternary op */ - extern double __cdecl fma (double, double, double); - extern float __cdecl fmaf (float, float, float); - extern long double __cdecl fmal (long double, long double, long double); - - -#endif /* __STDC_VERSION__ >= 199901L */ -#endif /* __NO_ISOCEXT */ - -#ifdef __cplusplus -} -#endif -#pragma pack(pop) - -/* 7.12.14 */ -/* - * With these functions, comparisons involving quiet NaNs set the FP - * condition code to "unordered". The IEEE floating-point spec - * dictates that the result of floating-point comparisons should be - * false whenever a NaN is involved, with the exception of the != op, - * which always returns true: yes, (NaN != NaN) is true). - */ - -/* Mini libm (inline __fpclassify*, __signbit* and variants) */ -#include "tcc/tcc_libm.h" - -#endif /* End _MATH_H_ */ - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _MATH_H_ +#define _MATH_H_ + +#if __GNUC__ >= 3 +#pragma GCC system_header +#endif + +#include <_mingw.h> + +struct exception; + +#pragma pack(push,_CRT_PACKING) + +#define _DOMAIN 1 +#define _SING 2 +#define _OVERFLOW 3 +#define _UNDERFLOW 4 +#define _TLOSS 5 +#define _PLOSS 6 + +#ifndef __STRICT_ANSI__ +#ifndef NO_OLDNAMES +#define DOMAIN _DOMAIN +#define SING _SING +#define OVERFLOW _OVERFLOW +#define UNDERFLOW _UNDERFLOW +#define TLOSS _TLOSS +#define PLOSS _PLOSS +#endif +#endif + +#ifndef __STRICT_ANSI__ +#define M_E 2.71828182845904523536 +#define M_LOG2E 1.44269504088896340736 +#define M_LOG10E 0.434294481903251827651 +#define M_LN2 0.693147180559945309417 +#define M_LN10 2.30258509299404568402 +#define M_PI 3.14159265358979323846 +#define M_PI_2 1.57079632679489661923 +#define M_PI_4 0.785398163397448309616 +#define M_1_PI 0.318309886183790671538 +#define M_2_PI 0.636619772367581343076 +#define M_2_SQRTPI 1.12837916709551257390 +#define M_SQRT2 1.41421356237309504880 +#define M_SQRT1_2 0.707106781186547524401 +#endif + +#ifndef __STRICT_ANSI__ +/* See also float.h */ +#ifndef __MINGW_FPCLASS_DEFINED +#define __MINGW_FPCLASS_DEFINED 1 +#define _FPCLASS_SNAN 0x0001 /* Signaling "Not a Number" */ +#define _FPCLASS_QNAN 0x0002 /* Quiet "Not a Number" */ +#define _FPCLASS_NINF 0x0004 /* Negative Infinity */ +#define _FPCLASS_NN 0x0008 /* Negative Normal */ +#define _FPCLASS_ND 0x0010 /* Negative Denormal */ +#define _FPCLASS_NZ 0x0020 /* Negative Zero */ +#define _FPCLASS_PZ 0x0040 /* Positive Zero */ +#define _FPCLASS_PD 0x0080 /* Positive Denormal */ +#define _FPCLASS_PN 0x0100 /* Positive Normal */ +#define _FPCLASS_PINF 0x0200 /* Positive Infinity */ +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _EXCEPTION_DEFINED +#define _EXCEPTION_DEFINED + struct _exception { + int type; + char *name; + double arg1; + double arg2; + double retval; + }; +#endif + +#ifndef _COMPLEX_DEFINED +#define _COMPLEX_DEFINED + struct _complex { + double x,y; + }; +#endif + +#define EDOM 33 +#define ERANGE 34 + +#ifndef _HUGE +#ifdef _MSVCRT_ + extern double *_HUGE; +#else + extern double *_imp___HUGE; +#define _HUGE (*_imp___HUGE) +#endif +#endif + +#define HUGE_VAL _HUGE + +#ifndef _CRT_ABS_DEFINED +#define _CRT_ABS_DEFINED + int __cdecl abs(int _X); + long __cdecl labs(long _X); +#endif + double __cdecl acos(double _X); + double __cdecl asin(double _X); + double __cdecl atan(double _X); + double __cdecl atan2(double _Y,double _X); +#ifndef _SIGN_DEFINED +#define _SIGN_DEFINED + _CRTIMP double __cdecl _copysign (double _Number,double _Sign); + _CRTIMP double __cdecl _chgsign (double _X); +#endif + double __cdecl cos(double _X); + double __cdecl cosh(double _X); + double __cdecl exp(double _X); + double __cdecl expm1(double _X); + double __cdecl fabs(double _X); + double __cdecl fmod(double _X,double _Y); + double __cdecl log(double _X); + double __cdecl log10(double _X); + double __cdecl pow(double _X,double _Y); + double __cdecl sin(double _X); + double __cdecl sinh(double _X); + double __cdecl tan(double _X); + double __cdecl tanh(double _X); + double __cdecl sqrt(double _X); +#ifndef _CRT_ATOF_DEFINED +#define _CRT_ATOF_DEFINED + double __cdecl atof(const char *_String); + double __cdecl _atof_l(const char *_String,_locale_t _Locale); +#endif + + _CRTIMP double __cdecl _cabs(struct _complex _ComplexA); + double __cdecl ceil(double _X); + double __cdecl floor(double _X); + double __cdecl frexp(double _X,int *_Y); + double __cdecl _hypot(double _X,double _Y); + _CRTIMP double __cdecl _j0(double _X); + _CRTIMP double __cdecl _j1(double _X); + _CRTIMP double __cdecl _jn(int _X,double _Y); + double __cdecl ldexp(double _X,int _Y); +#ifndef _CRT_MATHERR_DEFINED +#define _CRT_MATHERR_DEFINED + int __cdecl _matherr(struct _exception *_Except); +#endif + double __cdecl modf(double _X,double *_Y); + _CRTIMP double __cdecl _y0(double _X); + _CRTIMP double __cdecl _y1(double _X); + _CRTIMP double __cdecl _yn(int _X,double _Y); + +#if(defined(_X86_) && !defined(__x86_64)) + _CRTIMP int __cdecl _set_SSE2_enable(int _Flag); + /* from libmingwex */ + float __cdecl _hypotf(float _X,float _Y); +#endif + + float frexpf(float _X,int *_Y); + float __cdecl ldexpf(float _X,int _Y); + long double __cdecl ldexpl(long double _X,int _Y); + float __cdecl acosf(float _X); + float __cdecl asinf(float _X); + float __cdecl atanf(float _X); + float __cdecl atan2f(float _X,float _Y); + float __cdecl cosf(float _X); + float __cdecl sinf(float _X); + float __cdecl tanf(float _X); + float __cdecl coshf(float _X); + float __cdecl sinhf(float _X); + float __cdecl tanhf(float _X); + float __cdecl expf(float _X); + float __cdecl expm1f(float _X); + float __cdecl logf(float _X); + float __cdecl log10f(float _X); + float __cdecl modff(float _X,float *_Y); + float __cdecl powf(float _X,float _Y); + float __cdecl sqrtf(float _X); + float __cdecl ceilf(float _X); + float __cdecl floorf(float _X); + float __cdecl fmodf(float _X,float _Y); + float __cdecl _hypotf(float _X,float _Y); + float __cdecl fabsf(float _X); +#if !defined(__ia64__) + /* from libmingwex */ + float __cdecl _copysignf (float _Number,float _Sign); + float __cdecl _chgsignf (float _X); + float __cdecl _logbf(float _X); + float __cdecl _nextafterf(float _X,float _Y); + int __cdecl _finitef(float _X); + int __cdecl _isnanf(float _X); + int __cdecl _fpclassf(float _X); +#endif + +#ifndef NO_OLDNAMES +#define matherr _matherr + +#define HUGE _HUGE + /* double __cdecl cabs(struct _complex _X); */ + double __cdecl hypot(double _X,double _Y); + _CRTIMP double __cdecl j0(double _X); + _CRTIMP double __cdecl j1(double _X); + _CRTIMP double __cdecl jn(int _X,double _Y); + _CRTIMP double __cdecl y0(double _X); + _CRTIMP double __cdecl y1(double _X); + _CRTIMP double __cdecl yn(int _X,double _Y); +#endif + +#ifndef __NO_ISOCEXT +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \ + || !defined __STRICT_ANSI__ || defined __GLIBCPP__ + +#define NAN (0.0F/0.0F) +#define HUGE_VALF (1.0F/0.0F) +#define HUGE_VALL (1.0L/0.0L) +#define INFINITY (1.0F/0.0F) + + +#define FP_NAN 0x0100 +#define FP_NORMAL 0x0400 +#define FP_INFINITE (FP_NAN | FP_NORMAL) +#define FP_ZERO 0x4000 +#define FP_SUBNORMAL (FP_NORMAL | FP_ZERO) + /* 0x0200 is signbit mask */ + + + /* + We can't __CRT_INLINE float or double, because we want to ensure truncation + to semantic type before classification. + (A normal long double value might become subnormal when + converted to double, and zero when converted to float.) + */ + + extern int __cdecl __fpclassifyf (float); + extern int __cdecl __fpclassify (double); + extern int __cdecl __fpclassifyl (long double); + +/* Implemented at tcc/tcc_libm.h +#define fpclassify(x) (sizeof (x) == sizeof (float) ? __fpclassifyf (x) \ + : sizeof (x) == sizeof (double) ? __fpclassify (x) \ + : __fpclassifyl (x)) +*/ +#define fpclassify(x) \ + _Generic(x, float: __fpclassifyf, double: __fpclassify, long double: __fpclassifyl)(x) + + /* 7.12.3.2 */ +#define isfinite(x) ((fpclassify(x) & FP_NAN) == 0) + + /* 7.12.3.3 */ +#define isinf(x) (fpclassify(x) == FP_INFINITE) + + /* 7.12.3.4 */ + /* We don't need to worry about truncation here: + A NaN stays a NaN. */ +#define isnan(x) (fpclassify(x) == FP_NAN) + + /* 7.12.3.5 */ +#define isnormal(x) (fpclassify(x) == FP_NORMAL) + + /* 7.12.3.6 The signbit macro */ + + extern int __cdecl __signbitf (float); + extern int __cdecl __signbit (double); + extern int __cdecl __signbitl (long double); + +/* Implemented at tcc/tcc_libm.h +#define signbit(x) (sizeof (x) == sizeof (float) ? __signbitf (x) \ + : sizeof (x) == sizeof (double) ? __signbit (x) \ + : __signbitl (x)) +*/ +#define signbit(x) \ + _Generic(x, float: __signbitf, double: __signbit, long double: __signbitl)(x) + + extern double __cdecl exp2(double); + extern float __cdecl exp2f(float); + extern long double __cdecl exp2l(long double); + +#define FP_ILOGB0 ((int)0x80000000) +#define FP_ILOGBNAN ((int)0x80000000) + extern int __cdecl ilogb (double); + extern int __cdecl ilogbf (float); + extern int __cdecl ilogbl (long double); + + extern double __cdecl log1p(double); + extern float __cdecl log1pf(float); + extern long double __cdecl log1pl(long double); + + extern double __cdecl log2 (double); + extern float __cdecl log2f (float); + extern long double __cdecl log2l (long double); + + extern double __cdecl logb (double); + extern float __cdecl logbf (float); + extern long double __cdecl logbl (long double); + + extern long double __cdecl modfl (long double, long double*); + + /* 7.12.6.13 */ + extern double __cdecl scalbn (double, int); + extern float __cdecl scalbnf (float, int); + extern long double __cdecl scalbnl (long double, int); + + extern double __cdecl scalbln (double, long); + extern float __cdecl scalblnf (float, long); + extern long double __cdecl scalblnl (long double, long); + + /* 7.12.7.1 */ + /* Implementations adapted from Cephes versions */ + extern double __cdecl cbrt (double); + extern float __cdecl cbrtf (float); + extern long double __cdecl cbrtl (long double); + + extern double __cdecl hypot (double, double); + extern float __cdecl hypotf (float, float); + extern long double __cdecl hypotl (long double, long double); + + extern long double __cdecl powl (long double, long double); + extern long double __cdecl expl(long double); + extern long double __cdecl expm1l(long double); + extern long double __cdecl coshl(long double); + extern long double __cdecl fabsl (long double); + extern long double __cdecl acosl(long double); + extern long double __cdecl asinl(long double); + extern long double __cdecl atanl(long double); + extern long double __cdecl atan2l(long double,long double); + extern long double __cdecl sinhl(long double); + extern long double __cdecl tanhl(long double); + + /* 7.12.8.1 The erf functions */ + extern double __cdecl erf (double); + extern float __cdecl erff (float); + /* TODO + extern long double __cdecl erfl (long double); + */ + + /* 7.12.8.2 The erfc functions */ + extern double __cdecl erfc (double); + extern float __cdecl erfcf (float); + /* TODO + extern long double __cdecl erfcl (long double); + */ + + /* 7.12.8.3 The lgamma functions */ + extern double __cdecl lgamma (double); + extern float __cdecl lgammaf (float); + extern long double __cdecl lgammal (long double); + + /* 7.12.8.4 The tgamma functions */ + extern double __cdecl tgamma (double); + extern float __cdecl tgammaf (float); + extern long double __cdecl tgammal (long double); + + extern long double __cdecl ceill (long double); + extern long double __cdecl floorl (long double); + extern long double __cdecl frexpl(long double,int *); + extern long double __cdecl log10l(long double); + extern long double __cdecl logl(long double); + extern long double __cdecl cosl(long double); + extern long double __cdecl sinl(long double); + extern long double __cdecl tanl(long double); + extern long double sqrtl(long double); + + /* 7.12.9.3 */ + extern double __cdecl nearbyint ( double); + extern float __cdecl nearbyintf (float); + extern long double __cdecl nearbyintl (long double); + + /* 7.12.9.4 */ + /* round, using fpu control word settings */ + extern double __cdecl rint (double); + extern float __cdecl rintf (float); + extern long double __cdecl rintl (long double); + + extern long __cdecl lrint (double); + extern long __cdecl lrintf (float); + extern long __cdecl lrintl (long double); + + extern long long __cdecl llrint (double); + extern long long __cdecl llrintf (float); + extern long long __cdecl llrintl (long double); + + #define FE_TONEAREST 0x0000 + #define FE_DOWNWARD 0x0400 + #define FE_UPWARD 0x0800 + #define FE_TOWARDZERO 0x0c00 + + /* 7.12.9.6 */ + /* round away from zero, regardless of fpu control word settings */ + extern double __cdecl round (double); + extern float __cdecl roundf (float); + extern long double __cdecl roundl (long double); + + /* 7.12.9.7 */ + extern long __cdecl lround (double); + extern long __cdecl lroundf (float); + extern long __cdecl lroundl (long double); + + extern long long __cdecl llround (double); + extern long long __cdecl llroundf (float); + extern long long __cdecl llroundl (long double); + + /* 7.12.9.8 */ + /* round towards zero, regardless of fpu control word settings */ + extern double __cdecl trunc (double); + extern float __cdecl truncf (float); + extern long double __cdecl truncl (long double); + + extern long double __cdecl fmodl (long double, long double); + + /* 7.12.10.2 */ + extern double __cdecl remainder (double, double); + extern float __cdecl remainderf (float, float); + extern long double __cdecl remainderl (long double, long double); + + /* 7.12.10.3 */ + extern double __cdecl remquo(double, double, int *); + extern float __cdecl remquof(float, float, int *); + extern long double __cdecl remquol(long double, long double, int *); + + /* 7.12.11.1 */ + extern double __cdecl copysign (double, double); /* in libmoldname.a */ + extern float __cdecl copysignf (float, float); + extern long double __cdecl copysignl (long double, long double); + + /* 7.12.11.2 Return a NaN */ + extern double __cdecl nan(const char *tagp); + extern float __cdecl nanf(const char *tagp); + extern long double __cdecl nanl(const char *tagp); + +#ifndef __STRICT_ANSI__ +#define _nan() nan("") +#define _nanf() nanf("") +#define _nanl() nanl("") +#endif + + /* 7.12.11.3 */ + extern double __cdecl nextafter (double, double); /* in libmoldname.a */ + extern float __cdecl nextafterf (float, float); + extern long double __cdecl nextafterl (long double, long double); + + /* 7.12.11.4 The nexttoward functions: TODO */ + + /* 7.12.12.1 */ + /* x > y ? (x - y) : 0.0 */ + extern double __cdecl fdim (double x, double y); + extern float __cdecl fdimf (float x, float y); + extern long double __cdecl fdiml (long double x, long double y); + + /* fmax and fmin. + NaN arguments are treated as missing data: if one argument is a NaN + and the other numeric, then these functions choose the numeric + value. */ + + /* 7.12.12.2 */ + extern double __cdecl fmax (double, double); + extern float __cdecl fmaxf (float, float); + extern long double __cdecl fmaxl (long double, long double); + + /* 7.12.12.3 */ + extern double __cdecl fmin (double, double); + extern float __cdecl fminf (float, float); + extern long double __cdecl fminl (long double, long double); + + /* 7.12.13.1 */ + /* return x * y + z as a ternary op */ + extern double __cdecl fma (double, double, double); + extern float __cdecl fmaf (float, float, float); + extern long double __cdecl fmal (long double, long double, long double); + + +#endif /* __STDC_VERSION__ >= 199901L */ +#endif /* __NO_ISOCEXT */ + +#ifdef __cplusplus +} +#endif +#pragma pack(pop) + +/* 7.12.14 */ +/* + * With these functions, comparisons involving quiet NaNs set the FP + * condition code to "unordered". The IEEE floating-point spec + * dictates that the result of floating-point comparisons should be + * false whenever a NaN is involved, with the exception of the != op, + * which always returns true: yes, (NaN != NaN) is true). + */ + +/* Mini libm (inline __fpclassify*, __signbit* and variants) */ +#include "tcc/tcc_libm.h" + +#endif /* End _MATH_H_ */ + diff --git a/tcc/include/mem.h b/tcc/include/mem.h index 25520235..43e3bb2b 100644 --- a/tcc/include/mem.h +++ b/tcc/include/mem.h @@ -1,13 +1,13 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * mem.h maps to string.h - */ -#ifndef __STRICT_ANSI__ -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * mem.h maps to string.h + */ +#ifndef __STRICT_ANSI__ +#include +#endif diff --git a/tcc/include/memory.h b/tcc/include/memory.h index 90d88aed..8d15970e 100644 --- a/tcc/include/memory.h +++ b/tcc/include/memory.h @@ -1,40 +1,40 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_MEMORY -#define _INC_MEMORY - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CONST_RETURN -#define _CONST_RETURN -#endif - -#define _WConst_return _CONST_RETURN - -#ifndef _CRT_MEMORY_DEFINED -#define _CRT_MEMORY_DEFINED - _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); - _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); - _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); - _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); - int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); - void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); - void *__cdecl memset(void *_Dst,int _Val,size_t _Size); - -#ifndef NO_OLDNAMES - void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); - int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_MEMORY +#define _INC_MEMORY + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CONST_RETURN +#define _CONST_RETURN +#endif + +#define _WConst_return _CONST_RETURN + +#ifndef _CRT_MEMORY_DEFINED +#define _CRT_MEMORY_DEFINED + _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); + _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); + _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); + _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); + int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); + void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); + void *__cdecl memset(void *_Dst,int _Val,size_t _Size); + +#ifndef NO_OLDNAMES + void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); + int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/process.h b/tcc/include/process.h index dadaf2b7..7b94c0d6 100644 --- a/tcc/include/process.h +++ b/tcc/include/process.h @@ -1,176 +1,176 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_PROCESS -#define _INC_PROCESS - -#include <_mingw.h> - -/* Includes a definition of _pid_t and pid_t */ -#include - -#ifndef _POSIX_ -#ifdef __cplusplus -extern "C" { -#endif - -#define _P_WAIT 0 -#define _P_NOWAIT 1 -#define _OLD_P_OVERLAY 2 -#define _P_NOWAITO 3 -#define _P_DETACH 4 -#define _P_OVERLAY 2 - -#define _WAIT_CHILD 0 -#define _WAIT_GRANDCHILD 1 - - _CRTIMP uintptr_t __cdecl _beginthread(void (__cdecl *_StartAddress) (void *),unsigned _StackSize,void *_ArgList); - _CRTIMP void __cdecl _endthread(void); - _CRTIMP uintptr_t __cdecl _beginthreadex(void *_Security,unsigned _StackSize,unsigned (__stdcall *_StartAddress) (void *),void *_ArgList,unsigned _InitFlag,unsigned *_ThrdAddr); - _CRTIMP void __cdecl _endthreadex(unsigned _Retval); - -#ifndef _CRT_TERMINATE_DEFINED -#define _CRT_TERMINATE_DEFINED - void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; - _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; - -#pragma push_macro("abort") -#undef abort - void __cdecl __declspec(noreturn) abort(void); -#pragma pop_macro("abort") - -#endif - - _CRTIMP void __cdecl __MINGW_NOTHROW _cexit(void); - _CRTIMP void __cdecl __MINGW_NOTHROW _c_exit(void); - _CRTIMP int __cdecl _getpid(void); - _CRTIMP intptr_t __cdecl _cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); - _CRTIMP intptr_t __cdecl _execl(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execle(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execlp(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execlpe(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execv(const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _execve(const char *_Filename,const char *const *_ArgList,const char *const *_Env); - _CRTIMP intptr_t __cdecl _execvp(const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _execvpe(const char *_Filename,const char *const *_ArgList,const char *const *_Env); - _CRTIMP intptr_t __cdecl _spawnl(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnle(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnlp(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnlpe(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnv(int _Mode,const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _spawnve(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); - _CRTIMP intptr_t __cdecl _spawnvp(int _Mode,const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _spawnvpe(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); - -#ifndef _CRT_SYSTEM_DEFINED -#define _CRT_SYSTEM_DEFINED - int __cdecl system(const char *_Command); -#endif - -#ifndef _WPROCESS_DEFINED -#define _WPROCESS_DEFINED - _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif -#endif - - void __cdecl __security_init_cookie(void); -#if (defined(_X86_) && !defined(__x86_64)) - void __fastcall __security_check_cookie(uintptr_t _StackCookie); - __declspec(noreturn) void __cdecl __report_gsfailure(void); -#else - void __cdecl __security_check_cookie(uintptr_t _StackCookie); - __declspec(noreturn) void __cdecl __report_gsfailure(uintptr_t _StackCookie); -#endif - extern uintptr_t __security_cookie; - - intptr_t __cdecl _loaddll(char *_Filename); - int __cdecl _unloaddll(intptr_t _Handle); - int (__cdecl *__cdecl _getdllprocaddr(intptr_t _Handle,char *_ProcedureName,intptr_t _Ordinal))(void); - -#ifdef _DECL_DLLMAIN -#ifdef _WINDOWS_ - WINBOOL WINAPI DllMain(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); - WINBOOL WINAPI _CRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); - WINBOOL WINAPI _wCRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); - extern WINBOOL (WINAPI *const _pRawDllMain)(HANDLE,DWORD,LPVOID); -#else - int __stdcall DllMain(void *_HDllHandle,unsigned _Reason,void *_Reserved); - int __stdcall _CRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); - int __stdcall _wCRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); - extern int (__stdcall *const _pRawDllMain)(void *,unsigned,void *); -#endif -#endif - -#ifndef NO_OLDNAMES -#define P_WAIT _P_WAIT -#define P_NOWAIT _P_NOWAIT -#define P_OVERLAY _P_OVERLAY -#define OLD_P_OVERLAY _OLD_P_OVERLAY -#define P_NOWAITO _P_NOWAITO -#define P_DETACH _P_DETACH -#define WAIT_CHILD _WAIT_CHILD -#define WAIT_GRANDCHILD _WAIT_GRANDCHILD - - intptr_t __cdecl cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); -#ifdef __GNUC__ - int __cdecl execl(const char *_Filename,const char *_ArgList,...); - int __cdecl execle(const char *_Filename,const char *_ArgList,...); - int __cdecl execlp(const char *_Filename,const char *_ArgList,...); - int __cdecl execlpe(const char *_Filename,const char *_ArgList,...); -#else - intptr_t __cdecl execl(const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl execle(const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl execlp(const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl execlpe(const char *_Filename,const char *_ArgList,...); -#endif - intptr_t __cdecl spawnl(int,const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl spawnle(int,const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl spawnlp(int,const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl spawnlpe(int,const char *_Filename,const char *_ArgList,...); - int __cdecl getpid(void); -#ifdef __GNUC__ - /* Those methods are predefined by gcc builtins to return int. So to prevent - stupid warnings, define them in POSIX way. This is save, because those - methods do not return in success case, so that the return value is not - really dependent to its scalar width. */ - int __cdecl execv(const char *_Filename,const char *const _ArgList[]); - int __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); - int __cdecl execvp(const char *_Filename,const char *const _ArgList[]); - int __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); -#else - intptr_t __cdecl execv(const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); - intptr_t __cdecl execvp(const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); -#endif - intptr_t __cdecl spawnv(int,const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl spawnve(int,const char *_Filename,const char *const _ArgList[],const char *const _Env[]); - intptr_t __cdecl spawnvp(int,const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl spawnvpe(int,const char *_Filename,const char *const _ArgList[],char *const _Env[]); -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_PROCESS +#define _INC_PROCESS + +#include <_mingw.h> + +/* Includes a definition of _pid_t and pid_t */ +#include + +#ifndef _POSIX_ +#ifdef __cplusplus +extern "C" { +#endif + +#define _P_WAIT 0 +#define _P_NOWAIT 1 +#define _OLD_P_OVERLAY 2 +#define _P_NOWAITO 3 +#define _P_DETACH 4 +#define _P_OVERLAY 2 + +#define _WAIT_CHILD 0 +#define _WAIT_GRANDCHILD 1 + + _CRTIMP uintptr_t __cdecl _beginthread(void (__cdecl *_StartAddress) (void *),unsigned _StackSize,void *_ArgList); + _CRTIMP void __cdecl _endthread(void); + _CRTIMP uintptr_t __cdecl _beginthreadex(void *_Security,unsigned _StackSize,unsigned (__stdcall *_StartAddress) (void *),void *_ArgList,unsigned _InitFlag,unsigned *_ThrdAddr); + _CRTIMP void __cdecl _endthreadex(unsigned _Retval); + +#ifndef _CRT_TERMINATE_DEFINED +#define _CRT_TERMINATE_DEFINED + void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; + _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; + +#pragma push_macro("abort") +#undef abort + void __cdecl __declspec(noreturn) abort(void); +#pragma pop_macro("abort") + +#endif + + _CRTIMP void __cdecl __MINGW_NOTHROW _cexit(void); + _CRTIMP void __cdecl __MINGW_NOTHROW _c_exit(void); + _CRTIMP int __cdecl _getpid(void); + _CRTIMP intptr_t __cdecl _cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); + _CRTIMP intptr_t __cdecl _execl(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execle(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execlp(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execlpe(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execv(const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _execve(const char *_Filename,const char *const *_ArgList,const char *const *_Env); + _CRTIMP intptr_t __cdecl _execvp(const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _execvpe(const char *_Filename,const char *const *_ArgList,const char *const *_Env); + _CRTIMP intptr_t __cdecl _spawnl(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnle(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnlp(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnlpe(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnv(int _Mode,const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _spawnve(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); + _CRTIMP intptr_t __cdecl _spawnvp(int _Mode,const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _spawnvpe(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); + +#ifndef _CRT_SYSTEM_DEFINED +#define _CRT_SYSTEM_DEFINED + int __cdecl system(const char *_Command); +#endif + +#ifndef _WPROCESS_DEFINED +#define _WPROCESS_DEFINED + _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif +#endif + + void __cdecl __security_init_cookie(void); +#if (defined(_X86_) && !defined(__x86_64)) + void __fastcall __security_check_cookie(uintptr_t _StackCookie); + __declspec(noreturn) void __cdecl __report_gsfailure(void); +#else + void __cdecl __security_check_cookie(uintptr_t _StackCookie); + __declspec(noreturn) void __cdecl __report_gsfailure(uintptr_t _StackCookie); +#endif + extern uintptr_t __security_cookie; + + intptr_t __cdecl _loaddll(char *_Filename); + int __cdecl _unloaddll(intptr_t _Handle); + int (__cdecl *__cdecl _getdllprocaddr(intptr_t _Handle,char *_ProcedureName,intptr_t _Ordinal))(void); + +#ifdef _DECL_DLLMAIN +#ifdef _WINDOWS_ + WINBOOL WINAPI DllMain(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); + WINBOOL WINAPI _CRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); + WINBOOL WINAPI _wCRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); + extern WINBOOL (WINAPI *const _pRawDllMain)(HANDLE,DWORD,LPVOID); +#else + int __stdcall DllMain(void *_HDllHandle,unsigned _Reason,void *_Reserved); + int __stdcall _CRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); + int __stdcall _wCRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); + extern int (__stdcall *const _pRawDllMain)(void *,unsigned,void *); +#endif +#endif + +#ifndef NO_OLDNAMES +#define P_WAIT _P_WAIT +#define P_NOWAIT _P_NOWAIT +#define P_OVERLAY _P_OVERLAY +#define OLD_P_OVERLAY _OLD_P_OVERLAY +#define P_NOWAITO _P_NOWAITO +#define P_DETACH _P_DETACH +#define WAIT_CHILD _WAIT_CHILD +#define WAIT_GRANDCHILD _WAIT_GRANDCHILD + + intptr_t __cdecl cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); +#ifdef __GNUC__ + int __cdecl execl(const char *_Filename,const char *_ArgList,...); + int __cdecl execle(const char *_Filename,const char *_ArgList,...); + int __cdecl execlp(const char *_Filename,const char *_ArgList,...); + int __cdecl execlpe(const char *_Filename,const char *_ArgList,...); +#else + intptr_t __cdecl execl(const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl execle(const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl execlp(const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl execlpe(const char *_Filename,const char *_ArgList,...); +#endif + intptr_t __cdecl spawnl(int,const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl spawnle(int,const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl spawnlp(int,const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl spawnlpe(int,const char *_Filename,const char *_ArgList,...); + int __cdecl getpid(void); +#ifdef __GNUC__ + /* Those methods are predefined by gcc builtins to return int. So to prevent + stupid warnings, define them in POSIX way. This is save, because those + methods do not return in success case, so that the return value is not + really dependent to its scalar width. */ + int __cdecl execv(const char *_Filename,const char *const _ArgList[]); + int __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); + int __cdecl execvp(const char *_Filename,const char *const _ArgList[]); + int __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); +#else + intptr_t __cdecl execv(const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); + intptr_t __cdecl execvp(const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); +#endif + intptr_t __cdecl spawnv(int,const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl spawnve(int,const char *_Filename,const char *const _ArgList[],const char *const _Env[]); + intptr_t __cdecl spawnvp(int,const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl spawnvpe(int,const char *_Filename,const char *const _ArgList[],char *const _Env[]); +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tcc/include/sec_api/conio_s.h b/tcc/include/sec_api/conio_s.h index 98d97ba2..131ad61b 100644 --- a/tcc/include/sec_api/conio_s.h +++ b/tcc/include/sec_api/conio_s.h @@ -1,42 +1,42 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _INC_CONIO_S -#define _INC_CONIO_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _cgets_s(char *_Buffer,size_t _Size,size_t *_SizeRead); - _CRTIMP int __cdecl _cprintf_s(const char *_Format,...); - _CRTIMP int __cdecl _cscanf_s(const char *_Format,...); - _CRTIMP int __cdecl _cscanf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_s(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - -#ifndef _WCONIO_DEFINED_S -#define _WCONIO_DEFINED_S - _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); - _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _INC_CONIO_S +#define _INC_CONIO_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _cgets_s(char *_Buffer,size_t _Size,size_t *_SizeRead); + _CRTIMP int __cdecl _cprintf_s(const char *_Format,...); + _CRTIMP int __cdecl _cscanf_s(const char *_Format,...); + _CRTIMP int __cdecl _cscanf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_s(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + +#ifndef _WCONIO_DEFINED_S +#define _WCONIO_DEFINED_S + _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); + _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/crtdbg_s.h b/tcc/include/sec_api/crtdbg_s.h index 4598b4f7..c68a93fa 100644 --- a/tcc/include/sec_api/crtdbg_s.h +++ b/tcc/include/sec_api/crtdbg_s.h @@ -1,19 +1,19 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _INC_CRTDBG_S -#define _INC_CRTDBG_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#define _dupenv_s_dbg(ps1,size,s2,t,f,l) _dupenv_s(ps1,size,s2) -#define _wdupenv_s_dbg(ps1,size,s2,t,f,l) _wdupenv_s(ps1,size,s2) - -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _INC_CRTDBG_S +#define _INC_CRTDBG_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#define _dupenv_s_dbg(ps1,size,s2,t,f,l) _dupenv_s(ps1,size,s2) +#define _wdupenv_s_dbg(ps1,size,s2,t,f,l) _wdupenv_s(ps1,size,s2) + +#endif + +#endif diff --git a/tcc/include/sec_api/io_s.h b/tcc/include/sec_api/io_s.h index ec565a61..da0811a4 100644 --- a/tcc/include/sec_api/io_s.h +++ b/tcc/include/sec_api/io_s.h @@ -1,33 +1,33 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_IO_S -#define _INC_IO_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _access_s(const char *_Filename,int _AccessMode); - _CRTIMP errno_t __cdecl _chsize_s(int _FileHandle,__int64 _Size); - _CRTIMP errno_t __cdecl _mktemp_s(char *_TemplateName,size_t _Size); - _CRTIMP errno_t __cdecl _umask_s(int _NewMode,int *_OldMode); - -#ifndef _WIO_S_DEFINED -#define _WIO_S_DEFINED - _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); - _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_IO_S +#define _INC_IO_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _access_s(const char *_Filename,int _AccessMode); + _CRTIMP errno_t __cdecl _chsize_s(int _FileHandle,__int64 _Size); + _CRTIMP errno_t __cdecl _mktemp_s(char *_TemplateName,size_t _Size); + _CRTIMP errno_t __cdecl _umask_s(int _NewMode,int *_OldMode); + +#ifndef _WIO_S_DEFINED +#define _WIO_S_DEFINED + _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); + _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/mbstring_s.h b/tcc/include/sec_api/mbstring_s.h index 6b2b188f..d7c46bd5 100644 --- a/tcc/include/sec_api/mbstring_s.h +++ b/tcc/include/sec_api/mbstring_s.h @@ -1,52 +1,52 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_MBSTRING_S -#define _INC_MBSTRING_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _MBSTRING_S_DEFINED -#define _MBSTRING_S_DEFINED - _CRTIMP errno_t __cdecl _mbscat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); - _CRTIMP errno_t __cdecl _mbscat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbscpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); - _CRTIMP errno_t __cdecl _mbscpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbslwr_s(unsigned char *_Str,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _mbslwr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnbcat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnbcpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnbset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnbset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsncat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsncat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsncpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsncpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val); - _CRTIMP errno_t __cdecl _mbsset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,_locale_t _Locale); - _CRTIMP unsigned char *__cdecl _mbstok_s(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context); - _CRTIMP unsigned char *__cdecl _mbstok_s_l(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsupr_s(unsigned char *_Str,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _mbsupr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbccpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src); - _CRTIMP errno_t __cdecl _mbccpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src,_locale_t _Locale); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_MBSTRING_S +#define _INC_MBSTRING_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _MBSTRING_S_DEFINED +#define _MBSTRING_S_DEFINED + _CRTIMP errno_t __cdecl _mbscat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); + _CRTIMP errno_t __cdecl _mbscat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbscpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); + _CRTIMP errno_t __cdecl _mbscpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbslwr_s(unsigned char *_Str,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _mbslwr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnbcat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnbcpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnbset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnbset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsncat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsncat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsncpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsncpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val); + _CRTIMP errno_t __cdecl _mbsset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,_locale_t _Locale); + _CRTIMP unsigned char *__cdecl _mbstok_s(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context); + _CRTIMP unsigned char *__cdecl _mbstok_s_l(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsupr_s(unsigned char *_Str,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _mbsupr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbccpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src); + _CRTIMP errno_t __cdecl _mbccpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src,_locale_t _Locale); +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/search_s.h b/tcc/include/sec_api/search_s.h index cae89989..93e7f09e 100644 --- a/tcc/include/sec_api/search_s.h +++ b/tcc/include/sec_api/search_s.h @@ -1,25 +1,25 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SEARCH_S -#define _INC_SEARCH_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP void *__cdecl _lfind_s(const void *_Key,const void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); - _CRTIMP void *__cdecl _lsearch_s(const void *_Key,void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SEARCH_S +#define _INC_SEARCH_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP void *__cdecl _lfind_s(const void *_Key,const void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); + _CRTIMP void *__cdecl _lsearch_s(const void *_Key,void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/stdio_s.h b/tcc/include/sec_api/stdio_s.h index c9b803b1..8e9ce2ed 100644 --- a/tcc/include/sec_api/stdio_s.h +++ b/tcc/include/sec_api/stdio_s.h @@ -1,145 +1,145 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDIO_S -#define _INC_STDIO_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _STDIO_S_DEFINED -#define _STDIO_S_DEFINED - _CRTIMP errno_t __cdecl clearerr_s(FILE *_File); - int __cdecl fprintf_s(FILE *_File,const char *_Format,...); - size_t __cdecl fread_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); - _CRTIMP int __cdecl _fscanf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - int __cdecl printf_s(const char *_Format,...); - _CRTIMP int __cdecl _scanf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scanf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _snprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _vsnprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); - int __cdecl sprintf_s(char *_DstBuf,size_t _DstSize,const char *_Format,...); - _CRTIMP int __cdecl _fscanf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _sscanf_l(const char *_Src,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _sscanf_s_l(const char *_Src,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snscanf_s(const char *_Src,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _snscanf_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snscanf_s_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - int __cdecl vfprintf_s(FILE *_File,const char *_Format,va_list _ArgList); - int __cdecl vprintf_s(const char *_Format,va_list _ArgList); - int __cdecl vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); - int __cdecl vsprintf_s(char *_DstBuf,size_t _Size,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _fprintf_p(FILE *_File,const char *_Format,...); - _CRTIMP int __cdecl _printf_p(const char *_Format,...); - _CRTIMP int __cdecl _sprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _vfprintf_p(FILE *_File,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vprintf_p(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vsprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _scprintf_p(const char *_Format,...); - _CRTIMP int __cdecl _vscprintf_p(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _printf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _printf_p_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _fprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vfprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _sprintf_l(char *_DstBuf,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _sprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsprintf_l(char *_DstBuf,const char *_Format,_locale_t,va_list _ArgList); - _CRTIMP int __cdecl _vsprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _scprintf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scprintf_p_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vscprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vscprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _printf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _sprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vsnprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *,_locale_t _Locale,va_list _ArgList); - -#ifndef _WSTDIO_S_DEFINED -#define _WSTDIO_S_DEFINED - _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); - int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf_s(const wchar_t *_Format,...); - int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); - int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); - int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); - _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); - _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); - _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); - _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); - _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); -#endif -#endif - - _CRTIMP size_t __cdecl _fread_nolock_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); - -#ifdef __cplusplus -} -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDIO_S +#define _INC_STDIO_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _STDIO_S_DEFINED +#define _STDIO_S_DEFINED + _CRTIMP errno_t __cdecl clearerr_s(FILE *_File); + int __cdecl fprintf_s(FILE *_File,const char *_Format,...); + size_t __cdecl fread_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); + _CRTIMP int __cdecl _fscanf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + int __cdecl printf_s(const char *_Format,...); + _CRTIMP int __cdecl _scanf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scanf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _snprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _vsnprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); + int __cdecl sprintf_s(char *_DstBuf,size_t _DstSize,const char *_Format,...); + _CRTIMP int __cdecl _fscanf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _sscanf_l(const char *_Src,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _sscanf_s_l(const char *_Src,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snscanf_s(const char *_Src,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _snscanf_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snscanf_s_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + int __cdecl vfprintf_s(FILE *_File,const char *_Format,va_list _ArgList); + int __cdecl vprintf_s(const char *_Format,va_list _ArgList); + int __cdecl vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); + int __cdecl vsprintf_s(char *_DstBuf,size_t _Size,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _fprintf_p(FILE *_File,const char *_Format,...); + _CRTIMP int __cdecl _printf_p(const char *_Format,...); + _CRTIMP int __cdecl _sprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _vfprintf_p(FILE *_File,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vprintf_p(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vsprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _scprintf_p(const char *_Format,...); + _CRTIMP int __cdecl _vscprintf_p(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _printf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _printf_p_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _fprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vfprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _sprintf_l(char *_DstBuf,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _sprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsprintf_l(char *_DstBuf,const char *_Format,_locale_t,va_list _ArgList); + _CRTIMP int __cdecl _vsprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _scprintf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scprintf_p_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vscprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vscprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _printf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _sprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vsnprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *,_locale_t _Locale,va_list _ArgList); + +#ifndef _WSTDIO_S_DEFINED +#define _WSTDIO_S_DEFINED + _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); + int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf_s(const wchar_t *_Format,...); + int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); + int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); + int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); + _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); + _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); + _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); + _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); + _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); +#endif +#endif + + _CRTIMP size_t __cdecl _fread_nolock_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tcc/include/sec_api/stdlib_s.h b/tcc/include/sec_api/stdlib_s.h index f98262cc..7b78053d 100644 --- a/tcc/include/sec_api/stdlib_s.h +++ b/tcc/include/sec_api/stdlib_s.h @@ -1,67 +1,67 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDLIB_S -#define _INC_STDLIB_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _dupenv_s(char **_PBuffer,size_t *_PBufferSizeInBytes,const char *_VarName); - _CRTIMP errno_t __cdecl _itoa_s(int _Value,char *_DstBuf,size_t _Size,int _Radix); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _i64toa_s(__int64 _Val,char *_DstBuf,size_t _Size,int _Radix); - _CRTIMP errno_t __cdecl _ui64toa_s(unsigned __int64 _Val,char *_DstBuf,size_t _Size,int _Radix); -#endif - _CRTIMP errno_t __cdecl _ltoa_s(long _Val,char *_DstBuf,size_t _Size,int _Radix); - _CRTIMP errno_t __cdecl mbstowcs_s(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbstowcs_s_l(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _ultoa_s(unsigned long _Val,char *_DstBuf,size_t _Size,int _Radix); - _CRTIMP errno_t __cdecl _wctomb_s_l(int *_SizeConverted,char *_MbCh,size_t _SizeInBytes,wchar_t _WCh,_locale_t _Locale); - _CRTIMP errno_t __cdecl wcstombs_s(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes); - _CRTIMP errno_t __cdecl _wcstombs_s_l(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes,_locale_t _Locale); - -#ifndef _WSTDLIB_S_DEFINED -#define _WSTDLIB_S_DEFINED - _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); - _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); -#endif -#endif - -#ifndef _POSIX_ - _CRTIMP errno_t __cdecl _ecvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDights,int *_PtDec,int *_PtSign); - _CRTIMP errno_t __cdecl _fcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); - _CRTIMP errno_t __cdecl _gcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDigits); - _CRTIMP errno_t __cdecl _makepath_s(char *_PathResult,size_t _Size,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); - _CRTIMP errno_t __cdecl _putenv_s(const char *_Name,const char *_Value); - _CRTIMP errno_t __cdecl _searchenv_s(const char *_Filename,const char *_EnvVar,char *_ResultPath,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _splitpath_s(const char *_FullPath,char *_Drive,size_t _DriveSize,char *_Dir,size_t _DirSize,char *_Filename,size_t _FilenameSize,char *_Ext,size_t _ExtSize); - -#ifndef _WSTDLIBP_S_DEFINED -#define _WSTDLIBP_S_DEFINED - _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); - _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); - _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDLIB_S +#define _INC_STDLIB_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _dupenv_s(char **_PBuffer,size_t *_PBufferSizeInBytes,const char *_VarName); + _CRTIMP errno_t __cdecl _itoa_s(int _Value,char *_DstBuf,size_t _Size,int _Radix); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _i64toa_s(__int64 _Val,char *_DstBuf,size_t _Size,int _Radix); + _CRTIMP errno_t __cdecl _ui64toa_s(unsigned __int64 _Val,char *_DstBuf,size_t _Size,int _Radix); +#endif + _CRTIMP errno_t __cdecl _ltoa_s(long _Val,char *_DstBuf,size_t _Size,int _Radix); + _CRTIMP errno_t __cdecl mbstowcs_s(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbstowcs_s_l(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _ultoa_s(unsigned long _Val,char *_DstBuf,size_t _Size,int _Radix); + _CRTIMP errno_t __cdecl _wctomb_s_l(int *_SizeConverted,char *_MbCh,size_t _SizeInBytes,wchar_t _WCh,_locale_t _Locale); + _CRTIMP errno_t __cdecl wcstombs_s(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes); + _CRTIMP errno_t __cdecl _wcstombs_s_l(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes,_locale_t _Locale); + +#ifndef _WSTDLIB_S_DEFINED +#define _WSTDLIB_S_DEFINED + _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); + _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); +#endif +#endif + +#ifndef _POSIX_ + _CRTIMP errno_t __cdecl _ecvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDights,int *_PtDec,int *_PtSign); + _CRTIMP errno_t __cdecl _fcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); + _CRTIMP errno_t __cdecl _gcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDigits); + _CRTIMP errno_t __cdecl _makepath_s(char *_PathResult,size_t _Size,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); + _CRTIMP errno_t __cdecl _putenv_s(const char *_Name,const char *_Value); + _CRTIMP errno_t __cdecl _searchenv_s(const char *_Filename,const char *_EnvVar,char *_ResultPath,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _splitpath_s(const char *_FullPath,char *_Drive,size_t _DriveSize,char *_Dir,size_t _DirSize,char *_Filename,size_t _FilenameSize,char *_Ext,size_t _ExtSize); + +#ifndef _WSTDLIBP_S_DEFINED +#define _WSTDLIBP_S_DEFINED + _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); + _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); + _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/stralign_s.h b/tcc/include/sec_api/stralign_s.h index 5b78f586..2a7e4a41 100644 --- a/tcc/include/sec_api/stralign_s.h +++ b/tcc/include/sec_api/stralign_s.h @@ -1,30 +1,30 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef __STRALIGN_H_S_ -#define __STRALIGN_H_S_ - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(I_X86_) && defined(_WSTRING_S_DEFINED) -#if defined(__cplusplus) && defined(_WConst_Return) - static __inline PUWSTR ua_wcscpy_s(PUWSTR Destination,size_t DestinationSize,PCUWSTR Source) { - if(WSTR_ALIGNED(Source) && WSTR_ALIGNED(Destination)) return (wcscpy_s((PWSTR)Destination,DestinationSize,(PCWSTR)Source)==0 ? Destination : NULL); - return uaw_wcscpy((PCUWSTR)String,Character); - } -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef __STRALIGN_H_S_ +#define __STRALIGN_H_S_ + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(I_X86_) && defined(_WSTRING_S_DEFINED) +#if defined(__cplusplus) && defined(_WConst_Return) + static __inline PUWSTR ua_wcscpy_s(PUWSTR Destination,size_t DestinationSize,PCUWSTR Source) { + if(WSTR_ALIGNED(Source) && WSTR_ALIGNED(Destination)) return (wcscpy_s((PWSTR)Destination,DestinationSize,(PCWSTR)Source)==0 ? Destination : NULL); + return uaw_wcscpy((PCUWSTR)String,Character); + } +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tcc/include/sec_api/string_s.h b/tcc/include/sec_api/string_s.h index 9db70e77..5a648e5a 100644 --- a/tcc/include/sec_api/string_s.h +++ b/tcc/include/sec_api/string_s.h @@ -1,41 +1,41 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STRING_S -#define _INC_STRING_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _strset_s(char *_Dst,size_t _DstSize,int _Value); - _CRTIMP errno_t __cdecl _strerror_s(char *_Buf,size_t _SizeInBytes,const char *_ErrMsg); - _CRTIMP errno_t __cdecl _strlwr_s(char *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _strlwr_s_l(char *_Str,size_t _Size,_locale_t _Locale); - _CRTIMP errno_t __cdecl _strnset_s(char *_Str,size_t _Size,int _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _strupr_s(char *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _strupr_s_l(char *_Str,size_t _Size,_locale_t _Locale); -#ifndef _WSTRING_S_DEFINED -#define _WSTRING_S_DEFINED - _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); - _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); - _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); - _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); - _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); - _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STRING_S +#define _INC_STRING_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _strset_s(char *_Dst,size_t _DstSize,int _Value); + _CRTIMP errno_t __cdecl _strerror_s(char *_Buf,size_t _SizeInBytes,const char *_ErrMsg); + _CRTIMP errno_t __cdecl _strlwr_s(char *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _strlwr_s_l(char *_Str,size_t _Size,_locale_t _Locale); + _CRTIMP errno_t __cdecl _strnset_s(char *_Str,size_t _Size,int _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _strupr_s(char *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _strupr_s_l(char *_Str,size_t _Size,_locale_t _Locale); +#ifndef _WSTRING_S_DEFINED +#define _WSTRING_S_DEFINED + _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); + _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); + _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); + _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); + _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); + _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tcc/include/sec_api/sys/timeb_s.h b/tcc/include/sec_api/sys/timeb_s.h index af5ef098..35afa624 100644 --- a/tcc/include/sec_api/sys/timeb_s.h +++ b/tcc/include/sec_api/sys/timeb_s.h @@ -1,34 +1,34 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _TIMEB_H_S -#define _TIMEB_H_S - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef _USE_32BIT_TIME_T -#define _ftime_s _ftime32_s -#else -#define _ftime_s _ftime64_s -#endif - - _CRTIMP errno_t __cdecl _ftime32_s(struct __timeb32 *_Time); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _ftime64_s(struct __timeb64 *_Time); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _TIMEB_H_S +#define _TIMEB_H_S + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef _USE_32BIT_TIME_T +#define _ftime_s _ftime32_s +#else +#define _ftime_s _ftime64_s +#endif + + _CRTIMP errno_t __cdecl _ftime32_s(struct __timeb32 *_Time); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _ftime64_s(struct __timeb64 *_Time); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tcc/include/sec_api/tchar_s.h b/tcc/include/sec_api/tchar_s.h index 343d348e..b70d0574 100644 --- a/tcc/include/sec_api/tchar_s.h +++ b/tcc/include/sec_api/tchar_s.h @@ -1,266 +1,266 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_TCHAR_S -#define _INC_TCHAR_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _UNICODE - -#define _tprintf_s wprintf_s -#define _tprintf_s_l _wprintf_s_l -#define _tcprintf_s _cwprintf_s -#define _tcprintf_s_l _cwprintf_s_l -#define _vtcprintf_s _vcwprintf_s -#define _vtcprintf_s_l _vcwprintf_s_l -#define _ftprintf_s fwprintf_s -#define _ftprintf_s_l _fwprintf_s_l -#define _stprintf_s swprintf_s -#define _stprintf_s_l _swprintf_s_l -#define _sntprintf_s _snwprintf_s -#define _sntprintf_s_l _snwprintf_s_l -#define _vtprintf_s vwprintf_s -#define _vtprintf_s_l _vwprintf_s_l -#define _vftprintf_s vfwprintf_s -#define _vftprintf_s_l _vfwprintf_s_l -#define _vstprintf_s vswprintf_s -#define _vstprintf_s_l _vswprintf_s_l -#define _vsntprintf_s _vsnwprintf_s -#define _vsntprintf_s_l _vsnwprintf_s_l - -#define _tscanf_s wscanf_s -#define _tscanf_s_l _wscanf_s_l -#define _tcscanf_s _cwscanf_s -#define _tcscanf_s_l _cwscanf_s_l -#define _ftscanf_s fwscanf_s -#define _ftscanf_s_l _fwscanf_s_l -#define _stscanf_s swscanf_s -#define _stscanf_s_l _swscanf_s_l -#define _sntscanf_s _snwscanf_s -#define _sntscanf_s_l _snwscanf_s_l - -#define _cgetts_s _cgetws_s -#define _getts_s _getws_s - -#define _itot_s _itow_s -#define _ltot_s _ltow_s -#define _ultot_s _ultow_s -#define _i64tot_s _i64tow_s -#define _ui64tot_s _ui64tow_s - -#define _tcscat_s wcscat_s -#define _tcscpy_s wcscpy_s -#define _tcsncat_s wcsncat_s -#define _tcsncat_s_l _wcsncat_s_l -#define _tcsncpy_s wcsncpy_s -#define _tcsncpy_s_l _wcsncpy_s_l -#define _tcstok_s wcstok_s -#define _tcstok_s_l _wcstok_s_l -#define _tcserror_s _wcserror_s -#define __tcserror_s __wcserror_s - -#define _tcsnset_s _wcsnset_s -#define _tcsnset_s_l _wcsnset_s_l -#define _tcsset_s _wcsset_s -#define _tcsset_s_l _wcsset_s_l - -#define _tasctime_s _wasctime_s -#define _tctime_s _wctime_s -#define _tctime32_s _wctime32_s -#define _tctime64_s _wctime64_s -#define _tstrdate_s _wstrdate_s -#define _tstrtime_s _wstrtime_s - -#define _tgetenv_s _wgetenv_s -#define _tdupenv_s _wdupenv_s -#define _tmakepath_s _wmakepath_s -#define _tputenv_s _wputenv_s -#define _tsearchenv_s _wsearchenv_s -#define _tsplitpath_s _wsplitpath_s - -#define _tfopen_s _wfopen_s -#define _tfreopen_s _wfreopen_s -#define _ttmpnam_s _wtmpnam_s -#define _taccess_s _waccess_s -#define _tmktemp_s _wmktemp_s - -#define _tcsnccat_s wcsncat_s -#define _tcsnccat_s_l _wcsncat_s_l -#define _tcsnccpy_s wcsncpy_s -#define _tcsnccpy_s_l _wcsncpy_s_l - -#define _tcslwr_s _wcslwr_s -#define _tcslwr_s_l _wcslwr_s_l -#define _tcsupr_s _wcsupr_s -#define _tcsupr_s_l _wcsupr_s_l - -#define _wcstok_s_l(_String,_Delimiters,_Current_position,_Locale) (wcstok_s(_String,_Delimiters,_Current_position)) -#define _wcsnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_wcsnset_s(_Destination,_Destination_size_chars,_Value,_Count)) -#define _wcsset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_wcsset_s(_Destination,_Destination_size_chars,_Value)) - -#else - -#define _tprintf_s printf_s -#define _tprintf_s_l _printf_s_l -#define _tcprintf_s _cprintf_s -#define _tcprintf_s_l _cprintf_s_l -#define _vtcprintf_s _vcprintf_s -#define _vtcprintf_s_l _vcprintf_s_l -#define _ftprintf_s fprintf_s -#define _ftprintf_s_l _fprintf_s_l -#define _stprintf_s sprintf_s -#define _stprintf_s_l _sprintf_s_l -#define _sntprintf_s _snprintf_s -#define _sntprintf_s_l _snprintf_s_l -#define _vtprintf_s vprintf_s -#define _vtprintf_s_l _vprintf_s_l -#define _vftprintf_s vfprintf_s -#define _vftprintf_s_l _vfprintf_s_l -#define _vstprintf_s vsprintf_s -#define _vstprintf_s_l _vsprintf_s_l -#define _vsntprintf_s _vsnprintf_s -#define _vsntprintf_s_l _vsnprintf_s_l -#define _tscanf_s scanf_s -#define _tscanf_s_l _scanf_s_l -#define _tcscanf_s _cscanf_s -#define _tcscanf_s_l _cscanf_s_l -#define _ftscanf_s fscanf_s -#define _ftscanf_s_l _fscanf_s_l -#define _stscanf_s sscanf_s -#define _stscanf_s_l _sscanf_s_l -#define _sntscanf_s _snscanf_s -#define _sntscanf_s_l _snscanf_s_l - -#define _getts_s gets_s -#define _cgetts_s _cgets_s -#define _itot_s _itoa_s -#define _ltot_s _ltoa_s -#define _ultot_s _ultoa_s -#define _i64tot_s _i64toa_s -#define _ui64tot_s _ui64toa_s - -#define _tcscat_s strcat_s -#define _tcscpy_s strcpy_s -#define _tcserror_s strerror_s -#define __tcserror_s _strerror_s - -#define _tasctime_s asctime_s -#define _tctime_s ctime_s -#define _tctime32_s _ctime32_s -#define _tctime64_s _ctime64_s -#define _tstrdate_s _strdate_s -#define _tstrtime_s _strtime_s - -#define _tgetenv_s getenv_s -#define _tdupenv_s _dupenv_s -#define _tmakepath_s _makepath_s -#define _tputenv_s _putenv_s -#define _tsearchenv_s _searchenv_s -#define _tsplitpath_s _splitpath_s - -#define _tfopen_s fopen_s -#define _tfreopen_s freopen_s -#define _ttmpnam_s tmpnam_s -#define _tmktemp_s _mktemp_s - -#ifndef _POSIX_ -#define _taccess_s _access_s -#endif - -#define _tsopen_s _sopen_s - -#ifdef _MBCS - -#ifdef _MB_MAP_DIRECT - -#define _tcsncat_s _mbsnbcat_s -#define _tcsncat_s_l _mbsnbcat_s_l -#define _tcsncpy_s _mbsnbcpy_s -#define _tcsncpy_s_l _mbsnbcpy_s_l -#define _tcstok_s _mbstok_s -#define _tcstok_s_l _mbstok_s_l - -#define _tcsnset_s _mbsnbset_s -#define _tcsnset_s_l _mbsnbset_s_l -#define _tcsset_s _mbsset_s -#define _tcsset_s_l _mbsset_s_l - -#define _tcsnccat_s _mbsncat_s -#define _tcsnccat_s_l _mbsncat_s_l -#define _tcsnccpy_s _mbsncpy_s -#define _tcsnccpy_s_l _mbsncpy_s_l -#define _tcsncset_s _mbsnset_s -#define _tcsncset_s_l _mbsnset_s_l - -#define _tcslwr_s _mbslwr_s -#define _tcslwr_s_l _mbslwr_s_l -#define _tcsupr_s _mbsupr_s -#define _tcsupr_s_l _mbsupr_s_l - -#define _tccpy_s _mbccpy_s -#define _tccpy_s_l _mbccpy_s_l -#else - - _CRTIMP char *__cdecl _tcsncat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsncpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcstok_s(char *_Str,const char *_Delim,char **_Context); - _CRTIMP char *__cdecl _tcstok_s_l(char *_Str,const char *_Delim,char **_Context,_locale_t _Locale); - _CRTIMP errno_t __cdecl _tcsset_s(char *_Str,size_t _SizeInChars,unsigned int _Val); - _CRTIMP errno_t __cdecl _tcsset_s_l(char *_Str,size_t _SizeInChars,unsigned int,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcslwr_s(char *_Str,size_t _SizeInChars); - _CRTIMP char *__cdecl _tcslwr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsupr_s(char *_Str,size_t _SizeInChars); - _CRTIMP char *__cdecl _tcsupr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); - -#endif - -#else - -#define _tcsncat_s strncat_s -#define _tcsncat_s_l _strncat_s_l -#define _tcsncpy_s strncpy_s -#define _tcsncpy_s_l _strncpy_s_l -#define _tcstok_s strtok_s -#define _tcstok_s_l _strtok_s_l - -#define _tcsnset_s _strnset_s -#define _tcsnset_s_l _strnset_s_l -#define _tcsset_s _strset_s -#define _tcsset_s _strset_s -#define _tcsset_s_l _strset_s_l - -#define _tcsnccat_s strncat_s -#define _tcsnccat_s_l _strncat_s_l -#define _tcsnccpy_s strncpy_s -#define _tcsnccpy_s_l _strncpy_s_l - -#define _tcslwr_s _strlwr_s -#define _tcslwr_s_l _strlwr_s_l -#define _tcsupr_s _strupr_s -#define _tcsupr_s_l _strupr_s_l - -#define _strnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_strnset_s(_Destination,_Destination_size_chars,_Value,_Count)) -#define _strset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_strset_s(_Destination,_Destination_size_chars,_Value)) -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_TCHAR_S +#define _INC_TCHAR_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _UNICODE + +#define _tprintf_s wprintf_s +#define _tprintf_s_l _wprintf_s_l +#define _tcprintf_s _cwprintf_s +#define _tcprintf_s_l _cwprintf_s_l +#define _vtcprintf_s _vcwprintf_s +#define _vtcprintf_s_l _vcwprintf_s_l +#define _ftprintf_s fwprintf_s +#define _ftprintf_s_l _fwprintf_s_l +#define _stprintf_s swprintf_s +#define _stprintf_s_l _swprintf_s_l +#define _sntprintf_s _snwprintf_s +#define _sntprintf_s_l _snwprintf_s_l +#define _vtprintf_s vwprintf_s +#define _vtprintf_s_l _vwprintf_s_l +#define _vftprintf_s vfwprintf_s +#define _vftprintf_s_l _vfwprintf_s_l +#define _vstprintf_s vswprintf_s +#define _vstprintf_s_l _vswprintf_s_l +#define _vsntprintf_s _vsnwprintf_s +#define _vsntprintf_s_l _vsnwprintf_s_l + +#define _tscanf_s wscanf_s +#define _tscanf_s_l _wscanf_s_l +#define _tcscanf_s _cwscanf_s +#define _tcscanf_s_l _cwscanf_s_l +#define _ftscanf_s fwscanf_s +#define _ftscanf_s_l _fwscanf_s_l +#define _stscanf_s swscanf_s +#define _stscanf_s_l _swscanf_s_l +#define _sntscanf_s _snwscanf_s +#define _sntscanf_s_l _snwscanf_s_l + +#define _cgetts_s _cgetws_s +#define _getts_s _getws_s + +#define _itot_s _itow_s +#define _ltot_s _ltow_s +#define _ultot_s _ultow_s +#define _i64tot_s _i64tow_s +#define _ui64tot_s _ui64tow_s + +#define _tcscat_s wcscat_s +#define _tcscpy_s wcscpy_s +#define _tcsncat_s wcsncat_s +#define _tcsncat_s_l _wcsncat_s_l +#define _tcsncpy_s wcsncpy_s +#define _tcsncpy_s_l _wcsncpy_s_l +#define _tcstok_s wcstok_s +#define _tcstok_s_l _wcstok_s_l +#define _tcserror_s _wcserror_s +#define __tcserror_s __wcserror_s + +#define _tcsnset_s _wcsnset_s +#define _tcsnset_s_l _wcsnset_s_l +#define _tcsset_s _wcsset_s +#define _tcsset_s_l _wcsset_s_l + +#define _tasctime_s _wasctime_s +#define _tctime_s _wctime_s +#define _tctime32_s _wctime32_s +#define _tctime64_s _wctime64_s +#define _tstrdate_s _wstrdate_s +#define _tstrtime_s _wstrtime_s + +#define _tgetenv_s _wgetenv_s +#define _tdupenv_s _wdupenv_s +#define _tmakepath_s _wmakepath_s +#define _tputenv_s _wputenv_s +#define _tsearchenv_s _wsearchenv_s +#define _tsplitpath_s _wsplitpath_s + +#define _tfopen_s _wfopen_s +#define _tfreopen_s _wfreopen_s +#define _ttmpnam_s _wtmpnam_s +#define _taccess_s _waccess_s +#define _tmktemp_s _wmktemp_s + +#define _tcsnccat_s wcsncat_s +#define _tcsnccat_s_l _wcsncat_s_l +#define _tcsnccpy_s wcsncpy_s +#define _tcsnccpy_s_l _wcsncpy_s_l + +#define _tcslwr_s _wcslwr_s +#define _tcslwr_s_l _wcslwr_s_l +#define _tcsupr_s _wcsupr_s +#define _tcsupr_s_l _wcsupr_s_l + +#define _wcstok_s_l(_String,_Delimiters,_Current_position,_Locale) (wcstok_s(_String,_Delimiters,_Current_position)) +#define _wcsnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_wcsnset_s(_Destination,_Destination_size_chars,_Value,_Count)) +#define _wcsset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_wcsset_s(_Destination,_Destination_size_chars,_Value)) + +#else + +#define _tprintf_s printf_s +#define _tprintf_s_l _printf_s_l +#define _tcprintf_s _cprintf_s +#define _tcprintf_s_l _cprintf_s_l +#define _vtcprintf_s _vcprintf_s +#define _vtcprintf_s_l _vcprintf_s_l +#define _ftprintf_s fprintf_s +#define _ftprintf_s_l _fprintf_s_l +#define _stprintf_s sprintf_s +#define _stprintf_s_l _sprintf_s_l +#define _sntprintf_s _snprintf_s +#define _sntprintf_s_l _snprintf_s_l +#define _vtprintf_s vprintf_s +#define _vtprintf_s_l _vprintf_s_l +#define _vftprintf_s vfprintf_s +#define _vftprintf_s_l _vfprintf_s_l +#define _vstprintf_s vsprintf_s +#define _vstprintf_s_l _vsprintf_s_l +#define _vsntprintf_s _vsnprintf_s +#define _vsntprintf_s_l _vsnprintf_s_l +#define _tscanf_s scanf_s +#define _tscanf_s_l _scanf_s_l +#define _tcscanf_s _cscanf_s +#define _tcscanf_s_l _cscanf_s_l +#define _ftscanf_s fscanf_s +#define _ftscanf_s_l _fscanf_s_l +#define _stscanf_s sscanf_s +#define _stscanf_s_l _sscanf_s_l +#define _sntscanf_s _snscanf_s +#define _sntscanf_s_l _snscanf_s_l + +#define _getts_s gets_s +#define _cgetts_s _cgets_s +#define _itot_s _itoa_s +#define _ltot_s _ltoa_s +#define _ultot_s _ultoa_s +#define _i64tot_s _i64toa_s +#define _ui64tot_s _ui64toa_s + +#define _tcscat_s strcat_s +#define _tcscpy_s strcpy_s +#define _tcserror_s strerror_s +#define __tcserror_s _strerror_s + +#define _tasctime_s asctime_s +#define _tctime_s ctime_s +#define _tctime32_s _ctime32_s +#define _tctime64_s _ctime64_s +#define _tstrdate_s _strdate_s +#define _tstrtime_s _strtime_s + +#define _tgetenv_s getenv_s +#define _tdupenv_s _dupenv_s +#define _tmakepath_s _makepath_s +#define _tputenv_s _putenv_s +#define _tsearchenv_s _searchenv_s +#define _tsplitpath_s _splitpath_s + +#define _tfopen_s fopen_s +#define _tfreopen_s freopen_s +#define _ttmpnam_s tmpnam_s +#define _tmktemp_s _mktemp_s + +#ifndef _POSIX_ +#define _taccess_s _access_s +#endif + +#define _tsopen_s _sopen_s + +#ifdef _MBCS + +#ifdef _MB_MAP_DIRECT + +#define _tcsncat_s _mbsnbcat_s +#define _tcsncat_s_l _mbsnbcat_s_l +#define _tcsncpy_s _mbsnbcpy_s +#define _tcsncpy_s_l _mbsnbcpy_s_l +#define _tcstok_s _mbstok_s +#define _tcstok_s_l _mbstok_s_l + +#define _tcsnset_s _mbsnbset_s +#define _tcsnset_s_l _mbsnbset_s_l +#define _tcsset_s _mbsset_s +#define _tcsset_s_l _mbsset_s_l + +#define _tcsnccat_s _mbsncat_s +#define _tcsnccat_s_l _mbsncat_s_l +#define _tcsnccpy_s _mbsncpy_s +#define _tcsnccpy_s_l _mbsncpy_s_l +#define _tcsncset_s _mbsnset_s +#define _tcsncset_s_l _mbsnset_s_l + +#define _tcslwr_s _mbslwr_s +#define _tcslwr_s_l _mbslwr_s_l +#define _tcsupr_s _mbsupr_s +#define _tcsupr_s_l _mbsupr_s_l + +#define _tccpy_s _mbccpy_s +#define _tccpy_s_l _mbccpy_s_l +#else + + _CRTIMP char *__cdecl _tcsncat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsncpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcstok_s(char *_Str,const char *_Delim,char **_Context); + _CRTIMP char *__cdecl _tcstok_s_l(char *_Str,const char *_Delim,char **_Context,_locale_t _Locale); + _CRTIMP errno_t __cdecl _tcsset_s(char *_Str,size_t _SizeInChars,unsigned int _Val); + _CRTIMP errno_t __cdecl _tcsset_s_l(char *_Str,size_t _SizeInChars,unsigned int,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcslwr_s(char *_Str,size_t _SizeInChars); + _CRTIMP char *__cdecl _tcslwr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsupr_s(char *_Str,size_t _SizeInChars); + _CRTIMP char *__cdecl _tcsupr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); + +#endif + +#else + +#define _tcsncat_s strncat_s +#define _tcsncat_s_l _strncat_s_l +#define _tcsncpy_s strncpy_s +#define _tcsncpy_s_l _strncpy_s_l +#define _tcstok_s strtok_s +#define _tcstok_s_l _strtok_s_l + +#define _tcsnset_s _strnset_s +#define _tcsnset_s_l _strnset_s_l +#define _tcsset_s _strset_s +#define _tcsset_s _strset_s +#define _tcsset_s_l _strset_s_l + +#define _tcsnccat_s strncat_s +#define _tcsnccat_s_l _strncat_s_l +#define _tcsnccpy_s strncpy_s +#define _tcsnccpy_s_l _strncpy_s_l + +#define _tcslwr_s _strlwr_s +#define _tcslwr_s_l _strlwr_s_l +#define _tcsupr_s _strupr_s +#define _tcsupr_s_l _strupr_s_l + +#define _strnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_strnset_s(_Destination,_Destination_size_chars,_Value,_Count)) +#define _strset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_strset_s(_Destination,_Destination_size_chars,_Value)) +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tcc/include/sec_api/time_s.h b/tcc/include/sec_api/time_s.h index 9603b94f..b955304a 100644 --- a/tcc/include/sec_api/time_s.h +++ b/tcc/include/sec_api/time_s.h @@ -1,61 +1,61 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _TIME_H__S -#define _TIME_H__S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _ctime32_s(char *_Buf,size_t _SizeInBytes,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _gmtime32_s(struct tm *_Tm,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _localtime32_s(struct tm *_Tm,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _strdate_s(char *_Buf,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _strtime_s(char *_Buf ,size_t _SizeInBytes); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _ctime64_s(char *_Buf,size_t _SizeInBytes,const __time64_t *_Time); - _CRTIMP errno_t __cdecl _gmtime64_s(struct tm *_Tm,const __time64_t *_Time); - _CRTIMP errno_t __cdecl _localtime64_s(struct tm *_Tm,const __time64_t *_Time); -#endif - -#ifndef _WTIME_S_DEFINED -#define _WTIME_S_DEFINED - _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); - _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) -#define _INC_WTIME_S_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } -#else -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } -#endif -#endif -#endif - -#ifndef RC_INVOKED -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime32_s(_Tm,_Time); } -#else -__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime64_s(_Tm,_Time); } -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _TIME_H__S +#define _TIME_H__S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _ctime32_s(char *_Buf,size_t _SizeInBytes,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _gmtime32_s(struct tm *_Tm,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _localtime32_s(struct tm *_Tm,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _strdate_s(char *_Buf,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _strtime_s(char *_Buf ,size_t _SizeInBytes); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _ctime64_s(char *_Buf,size_t _SizeInBytes,const __time64_t *_Time); + _CRTIMP errno_t __cdecl _gmtime64_s(struct tm *_Tm,const __time64_t *_Time); + _CRTIMP errno_t __cdecl _localtime64_s(struct tm *_Tm,const __time64_t *_Time); +#endif + +#ifndef _WTIME_S_DEFINED +#define _WTIME_S_DEFINED + _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); + _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) +#define _INC_WTIME_S_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } +#else +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } +#endif +#endif +#endif + +#ifndef RC_INVOKED +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime32_s(_Tm,_Time); } +#else +__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime64_s(_Tm,_Time); } +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/wchar_s.h b/tcc/include/sec_api/wchar_s.h index 94251aa8..76c4b81a 100644 --- a/tcc/include/sec_api/wchar_s.h +++ b/tcc/include/sec_api/wchar_s.h @@ -1,128 +1,128 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_WCHAR_S -#define _INC_WCHAR_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _WIO_S_DEFINED -#define _WIO_S_DEFINED - _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); - _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); -#endif - -#ifndef _WCONIO_S_DEFINED -#define _WCONIO_S_DEFINED - _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); - _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); -#endif - -#ifndef _WSTDIO_S_DEFINED -#define _WSTDIO_S_DEFINED - _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); - int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf_s(const wchar_t *_Format,...); - int __cdecl vfwprintf_s(FILE *_File,const wchar_t *_Format,va_list _ArgList); - int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); - int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); - int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); - _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); -#endif - -#ifndef _WSTDLIB_S_DEFINED -#define _WSTDLIB_S_DEFINED - _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); - _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); -#endif -#endif - -#ifndef _POSIX_ -#ifndef _WSTDLIBP_S_DEFINED -#define _WSTDLIBP_S_DEFINED - _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); - _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); - _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); -#endif -#endif - -#ifndef _WSTRING_S_DEFINED -#define _WSTRING_S_DEFINED - _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); - _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); - _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); - _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); - _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); - _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); -#endif - -#ifndef _WTIME_S_DEFINED -#define _WTIME_S_DEFINED - _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); - _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) -#define _INC_WTIME_S_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } -#else -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } -#endif -#endif -#endif - - _CRTIMP errno_t __cdecl mbsrtowcs_s(size_t *_Retval,wchar_t *_Dst,size_t _SizeInWords,const char **_PSrc,size_t _N,mbstate_t *_State); - _CRTIMP errno_t __cdecl wcrtomb_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,wchar_t _Ch,mbstate_t *_State); - _CRTIMP errno_t __cdecl wcsrtombs_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,const wchar_t **_Src,size_t _Size,mbstate_t *_State); - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_WCHAR_S +#define _INC_WCHAR_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _WIO_S_DEFINED +#define _WIO_S_DEFINED + _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); + _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); +#endif + +#ifndef _WCONIO_S_DEFINED +#define _WCONIO_S_DEFINED + _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); + _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); +#endif + +#ifndef _WSTDIO_S_DEFINED +#define _WSTDIO_S_DEFINED + _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); + int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf_s(const wchar_t *_Format,...); + int __cdecl vfwprintf_s(FILE *_File,const wchar_t *_Format,va_list _ArgList); + int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); + int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); + int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); + _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); +#endif + +#ifndef _WSTDLIB_S_DEFINED +#define _WSTDLIB_S_DEFINED + _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); + _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); +#endif +#endif + +#ifndef _POSIX_ +#ifndef _WSTDLIBP_S_DEFINED +#define _WSTDLIBP_S_DEFINED + _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); + _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); + _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); +#endif +#endif + +#ifndef _WSTRING_S_DEFINED +#define _WSTRING_S_DEFINED + _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); + _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); + _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); + _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); + _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); + _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); +#endif + +#ifndef _WTIME_S_DEFINED +#define _WTIME_S_DEFINED + _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); + _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) +#define _INC_WTIME_S_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } +#else +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } +#endif +#endif +#endif + + _CRTIMP errno_t __cdecl mbsrtowcs_s(size_t *_Retval,wchar_t *_Dst,size_t _SizeInWords,const char **_PSrc,size_t _N,mbstate_t *_State); + _CRTIMP errno_t __cdecl wcrtomb_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,wchar_t _Ch,mbstate_t *_State); + _CRTIMP errno_t __cdecl wcsrtombs_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,const wchar_t **_Src,size_t _Size,mbstate_t *_State); + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/setjmp.h b/tcc/include/setjmp.h index e4f142a3..5545426b 100644 --- a/tcc/include/setjmp.h +++ b/tcc/include/setjmp.h @@ -1,160 +1,160 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SETJMP -#define _INC_SETJMP - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#if (defined(_X86_) && !defined(__x86_64)) - -#define _JBLEN 16 -#define _JBTYPE int - - typedef struct __JUMP_BUFFER { - unsigned long Ebp; - unsigned long Ebx; - unsigned long Edi; - unsigned long Esi; - unsigned long Esp; - unsigned long Eip; - unsigned long Registration; - unsigned long TryLevel; - unsigned long Cookie; - unsigned long UnwindFunc; - unsigned long UnwindData[6]; - } _JUMP_BUFFER; -#elif defined(__ia64__) - typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { - __int64 LowPart; - __int64 HighPart; - } SETJMP_FLOAT128; - -#define _JBLEN 33 - typedef SETJMP_FLOAT128 _JBTYPE; - - typedef struct __JUMP_BUFFER { - - unsigned long iAReserved[6]; - - unsigned long Registration; - unsigned long TryLevel; - unsigned long Cookie; - unsigned long UnwindFunc; - - unsigned long UnwindData[6]; - - SETJMP_FLOAT128 FltS0; - SETJMP_FLOAT128 FltS1; - SETJMP_FLOAT128 FltS2; - SETJMP_FLOAT128 FltS3; - SETJMP_FLOAT128 FltS4; - SETJMP_FLOAT128 FltS5; - SETJMP_FLOAT128 FltS6; - SETJMP_FLOAT128 FltS7; - SETJMP_FLOAT128 FltS8; - SETJMP_FLOAT128 FltS9; - SETJMP_FLOAT128 FltS10; - SETJMP_FLOAT128 FltS11; - SETJMP_FLOAT128 FltS12; - SETJMP_FLOAT128 FltS13; - SETJMP_FLOAT128 FltS14; - SETJMP_FLOAT128 FltS15; - SETJMP_FLOAT128 FltS16; - SETJMP_FLOAT128 FltS17; - SETJMP_FLOAT128 FltS18; - SETJMP_FLOAT128 FltS19; - __int64 FPSR; - __int64 StIIP; - __int64 BrS0; - __int64 BrS1; - __int64 BrS2; - __int64 BrS3; - __int64 BrS4; - __int64 IntS0; - __int64 IntS1; - __int64 IntS2; - __int64 IntS3; - __int64 RsBSP; - __int64 RsPFS; - __int64 ApUNAT; - __int64 ApLC; - __int64 IntSp; - __int64 IntNats; - __int64 Preds; - - } _JUMP_BUFFER; -#elif defined(__x86_64) - typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { - unsigned __int64 Part[2]; - } SETJMP_FLOAT128; - -#define _JBLEN 16 - typedef SETJMP_FLOAT128 _JBTYPE; - - typedef struct _JUMP_BUFFER { - unsigned __int64 Frame; - unsigned __int64 Rbx; - unsigned __int64 Rsp; - unsigned __int64 Rbp; - unsigned __int64 Rsi; - unsigned __int64 Rdi; - unsigned __int64 R12; - unsigned __int64 R13; - unsigned __int64 R14; - unsigned __int64 R15; - unsigned __int64 Rip; - unsigned __int64 Spare; - SETJMP_FLOAT128 Xmm6; - SETJMP_FLOAT128 Xmm7; - SETJMP_FLOAT128 Xmm8; - SETJMP_FLOAT128 Xmm9; - SETJMP_FLOAT128 Xmm10; - SETJMP_FLOAT128 Xmm11; - SETJMP_FLOAT128 Xmm12; - SETJMP_FLOAT128 Xmm13; - SETJMP_FLOAT128 Xmm14; - SETJMP_FLOAT128 Xmm15; - } _JUMP_BUFFER; -#endif -#ifndef _JMP_BUF_DEFINED - typedef _JBTYPE jmp_buf[_JBLEN]; -#define _JMP_BUF_DEFINED -#endif - - void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void); - -#ifdef USE_MINGW_SETJMP_TWO_ARGS -#ifndef _INC_SETJMPEX -#define setjmp(BUF) _setjmp((BUF),mingw_getsp()) - int __cdecl __attribute__ ((__nothrow__)) _setjmp(jmp_buf _Buf,void *_Ctx); -#else -#undef setjmp -#define setjmp(BUF) _setjmpex((BUF),mingw_getsp()) -#define setjmpex(BUF) _setjmpex((BUF),mingw_getsp()) - int __cdecl __attribute__ ((__nothrow__)) _setjmpex(jmp_buf _Buf,void *_Ctx); -#endif -#else -#ifndef _INC_SETJMPEX -#define setjmp _setjmp -#endif - int __cdecl __attribute__ ((__nothrow__)) setjmp(jmp_buf _Buf); -#endif - - __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl ms_longjmp(jmp_buf _Buf,int _Value)/* throw(...)*/; - __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value); - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SETJMP +#define _INC_SETJMP + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#if (defined(_X86_) && !defined(__x86_64)) + +#define _JBLEN 16 +#define _JBTYPE int + + typedef struct __JUMP_BUFFER { + unsigned long Ebp; + unsigned long Ebx; + unsigned long Edi; + unsigned long Esi; + unsigned long Esp; + unsigned long Eip; + unsigned long Registration; + unsigned long TryLevel; + unsigned long Cookie; + unsigned long UnwindFunc; + unsigned long UnwindData[6]; + } _JUMP_BUFFER; +#elif defined(__ia64__) + typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { + __int64 LowPart; + __int64 HighPart; + } SETJMP_FLOAT128; + +#define _JBLEN 33 + typedef SETJMP_FLOAT128 _JBTYPE; + + typedef struct __JUMP_BUFFER { + + unsigned long iAReserved[6]; + + unsigned long Registration; + unsigned long TryLevel; + unsigned long Cookie; + unsigned long UnwindFunc; + + unsigned long UnwindData[6]; + + SETJMP_FLOAT128 FltS0; + SETJMP_FLOAT128 FltS1; + SETJMP_FLOAT128 FltS2; + SETJMP_FLOAT128 FltS3; + SETJMP_FLOAT128 FltS4; + SETJMP_FLOAT128 FltS5; + SETJMP_FLOAT128 FltS6; + SETJMP_FLOAT128 FltS7; + SETJMP_FLOAT128 FltS8; + SETJMP_FLOAT128 FltS9; + SETJMP_FLOAT128 FltS10; + SETJMP_FLOAT128 FltS11; + SETJMP_FLOAT128 FltS12; + SETJMP_FLOAT128 FltS13; + SETJMP_FLOAT128 FltS14; + SETJMP_FLOAT128 FltS15; + SETJMP_FLOAT128 FltS16; + SETJMP_FLOAT128 FltS17; + SETJMP_FLOAT128 FltS18; + SETJMP_FLOAT128 FltS19; + __int64 FPSR; + __int64 StIIP; + __int64 BrS0; + __int64 BrS1; + __int64 BrS2; + __int64 BrS3; + __int64 BrS4; + __int64 IntS0; + __int64 IntS1; + __int64 IntS2; + __int64 IntS3; + __int64 RsBSP; + __int64 RsPFS; + __int64 ApUNAT; + __int64 ApLC; + __int64 IntSp; + __int64 IntNats; + __int64 Preds; + + } _JUMP_BUFFER; +#elif defined(__x86_64) + typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { + unsigned __int64 Part[2]; + } SETJMP_FLOAT128; + +#define _JBLEN 16 + typedef SETJMP_FLOAT128 _JBTYPE; + + typedef struct _JUMP_BUFFER { + unsigned __int64 Frame; + unsigned __int64 Rbx; + unsigned __int64 Rsp; + unsigned __int64 Rbp; + unsigned __int64 Rsi; + unsigned __int64 Rdi; + unsigned __int64 R12; + unsigned __int64 R13; + unsigned __int64 R14; + unsigned __int64 R15; + unsigned __int64 Rip; + unsigned __int64 Spare; + SETJMP_FLOAT128 Xmm6; + SETJMP_FLOAT128 Xmm7; + SETJMP_FLOAT128 Xmm8; + SETJMP_FLOAT128 Xmm9; + SETJMP_FLOAT128 Xmm10; + SETJMP_FLOAT128 Xmm11; + SETJMP_FLOAT128 Xmm12; + SETJMP_FLOAT128 Xmm13; + SETJMP_FLOAT128 Xmm14; + SETJMP_FLOAT128 Xmm15; + } _JUMP_BUFFER; +#endif +#ifndef _JMP_BUF_DEFINED + typedef _JBTYPE jmp_buf[_JBLEN]; +#define _JMP_BUF_DEFINED +#endif + + void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void); + +#ifdef USE_MINGW_SETJMP_TWO_ARGS +#ifndef _INC_SETJMPEX +#define setjmp(BUF) _setjmp((BUF),mingw_getsp()) + int __cdecl __attribute__ ((__nothrow__)) _setjmp(jmp_buf _Buf,void *_Ctx); +#else +#undef setjmp +#define setjmp(BUF) _setjmpex((BUF),mingw_getsp()) +#define setjmpex(BUF) _setjmpex((BUF),mingw_getsp()) + int __cdecl __attribute__ ((__nothrow__)) _setjmpex(jmp_buf _Buf,void *_Ctx); +#endif +#else +#ifndef _INC_SETJMPEX +#define setjmp _setjmp +#endif + int __cdecl __attribute__ ((__nothrow__)) setjmp(jmp_buf _Buf); +#endif + + __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl ms_longjmp(jmp_buf _Buf,int _Value)/* throw(...)*/; + __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value); + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/share.h b/tcc/include/share.h index 358855fe..9b1b9650 100644 --- a/tcc/include/share.h +++ b/tcc/include/share.h @@ -1,28 +1,28 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SHARE -#define _INC_SHARE - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#define _SH_COMPAT 0x00 -#define _SH_DENYRW 0x10 -#define _SH_DENYWR 0x20 -#define _SH_DENYRD 0x30 -#define _SH_DENYNO 0x40 -#define _SH_SECURE 0x80 - -#ifndef NO_OLDNAMES -#define SH_COMPAT _SH_COMPAT -#define SH_DENYRW _SH_DENYRW -#define SH_DENYWR _SH_DENYWR -#define SH_DENYRD _SH_DENYRD -#define SH_DENYNO _SH_DENYNO -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SHARE +#define _INC_SHARE + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#define _SH_COMPAT 0x00 +#define _SH_DENYRW 0x10 +#define _SH_DENYWR 0x20 +#define _SH_DENYRD 0x30 +#define _SH_DENYNO 0x40 +#define _SH_SECURE 0x80 + +#ifndef NO_OLDNAMES +#define SH_COMPAT _SH_COMPAT +#define SH_DENYRW _SH_DENYRW +#define SH_DENYWR _SH_DENYWR +#define SH_DENYRD _SH_DENYRD +#define SH_DENYNO _SH_DENYNO +#endif + +#endif diff --git a/tcc/include/signal.h b/tcc/include/signal.h index a518f6b3..c2424d35 100644 --- a/tcc/include/signal.h +++ b/tcc/include/signal.h @@ -1,63 +1,63 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SIGNAL -#define _INC_SIGNAL - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _SIG_ATOMIC_T_DEFINED -#define _SIG_ATOMIC_T_DEFINED - typedef int sig_atomic_t; -#endif - -#define NSIG 23 - -#define SIGHUP 1 /* hangup */ -#define SIGINT 2 -#define SIGQUIT 3 /* quit */ -#define SIGILL 4 -#define SIGTRAP 5 /* trace trap (not reset when caught) */ -#define SIGIOT 6 /* IOT instruction */ -#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */ -#define SIGEMT 7 /* EMT instruction */ -#define SIGFPE 8 -#define SIGKILL 9 /* kill (cannot be caught or ignored) */ -#define SIGBUS 10 /* bus error */ -#define SIGSEGV 11 -#define SIGSYS 12 /* bad argument to system call */ -#define SIGPIPE 13 /* write on a pipe with no one to read it */ -#ifdef __USE_MINGW_ALARM -#define SIGALRM 14 /* alarm clock */ -#endif -#define SIGTERM 15 -#define SIGBREAK 21 -#define SIGABRT2 22 - -#define SIGABRT_COMPAT 6 - - typedef void (*__p_sig_fn_t)(int); - -#define SIG_DFL (__p_sig_fn_t)0 -#define SIG_IGN (__p_sig_fn_t)1 -#define SIG_GET (__p_sig_fn_t)2 -#define SIG_SGE (__p_sig_fn_t)3 -#define SIG_ACK (__p_sig_fn_t)4 -#define SIG_ERR (__p_sig_fn_t)-1 - - extern void **__cdecl __pxcptinfoptrs(void); -#define _pxcptinfoptrs (*__pxcptinfoptrs()) - - __p_sig_fn_t __cdecl signal(int _SigNum,__p_sig_fn_t _Func); - int __cdecl raise(int _SigNum); - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SIGNAL +#define _INC_SIGNAL + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _SIG_ATOMIC_T_DEFINED +#define _SIG_ATOMIC_T_DEFINED + typedef int sig_atomic_t; +#endif + +#define NSIG 23 + +#define SIGHUP 1 /* hangup */ +#define SIGINT 2 +#define SIGQUIT 3 /* quit */ +#define SIGILL 4 +#define SIGTRAP 5 /* trace trap (not reset when caught) */ +#define SIGIOT 6 /* IOT instruction */ +#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */ +#define SIGEMT 7 /* EMT instruction */ +#define SIGFPE 8 +#define SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define SIGBUS 10 /* bus error */ +#define SIGSEGV 11 +#define SIGSYS 12 /* bad argument to system call */ +#define SIGPIPE 13 /* write on a pipe with no one to read it */ +#ifdef __USE_MINGW_ALARM +#define SIGALRM 14 /* alarm clock */ +#endif +#define SIGTERM 15 +#define SIGBREAK 21 +#define SIGABRT2 22 + +#define SIGABRT_COMPAT 6 + + typedef void (*__p_sig_fn_t)(int); + +#define SIG_DFL (__p_sig_fn_t)0 +#define SIG_IGN (__p_sig_fn_t)1 +#define SIG_GET (__p_sig_fn_t)2 +#define SIG_SGE (__p_sig_fn_t)3 +#define SIG_ACK (__p_sig_fn_t)4 +#define SIG_ERR (__p_sig_fn_t)-1 + + extern void **__cdecl __pxcptinfoptrs(void); +#define _pxcptinfoptrs (*__pxcptinfoptrs()) + + __p_sig_fn_t __cdecl signal(int _SigNum,__p_sig_fn_t _Func); + int __cdecl raise(int _SigNum); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/stdalign.h b/tcc/include/stdalign.h index ae46c349..51b96270 100644 --- a/tcc/include/stdalign.h +++ b/tcc/include/stdalign.h @@ -1,16 +1,16 @@ -#ifndef _STDALIGN_H -#define _STDALIGN_H - -#if __STDC_VERSION__ < 201112L && (defined(__GNUC__) || defined(__TINYC__)) -# define _Alignas(t) __attribute__((__aligned__(t))) -# define _Alignof(t) __alignof__(t) -#endif - -#define alignas _Alignas -#define alignof _Alignof - -#define __alignas_is_defined 1 -#define __alignof_is_defined 1 - -#endif /* _STDALIGN_H */ - +#ifndef _STDALIGN_H +#define _STDALIGN_H + +#if __STDC_VERSION__ < 201112L && (defined(__GNUC__) || defined(__TINYC__)) +# define _Alignas(t) __attribute__((__aligned__(t))) +# define _Alignof(t) __alignof__(t) +#endif + +#define alignas _Alignas +#define alignof _Alignof + +#define __alignas_is_defined 1 +#define __alignof_is_defined 1 + +#endif /* _STDALIGN_H */ + diff --git a/tcc/include/stdarg.h b/tcc/include/stdarg.h index aa784da2..4b3089f0 100644 --- a/tcc/include/stdarg.h +++ b/tcc/include/stdarg.h @@ -1,14 +1,14 @@ -#ifndef _STDARG_H -#define _STDARG_H - -typedef __builtin_va_list va_list; -#define va_start __builtin_va_start -#define va_arg __builtin_va_arg -#define va_copy __builtin_va_copy -#define va_end __builtin_va_end - -/* fix a buggy dependency on GCC in libio.h */ -typedef va_list __gnuc_va_list; -#define _VA_LIST_DEFINED - -#endif /* _STDARG_H */ +#ifndef _STDARG_H +#define _STDARG_H + +typedef __builtin_va_list va_list; +#define va_start __builtin_va_start +#define va_arg __builtin_va_arg +#define va_copy __builtin_va_copy +#define va_end __builtin_va_end + +/* fix a buggy dependency on GCC in libio.h */ +typedef va_list __gnuc_va_list; +#define _VA_LIST_DEFINED + +#endif /* _STDARG_H */ diff --git a/tcc/include/stdatomic.h b/tcc/include/stdatomic.h index ee3024c0..28778b57 100644 --- a/tcc/include/stdatomic.h +++ b/tcc/include/stdatomic.h @@ -1,125 +1,125 @@ -/* This file is derived from clang's stdatomic.h */ - -/*===---- stdatomic.h - Standard header for atomic types and operations -----=== - * - * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. - * See https://llvm.org/LICENSE.txt for license information. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - * - *===-----------------------------------------------------------------------=== - */ - -#ifndef _STDATOMIC_H -#define _STDATOMIC_H - -#include -#include - -/* Memory ordering */ -typedef enum { - memory_order_relaxed = __ATOMIC_RELAXED, - memory_order_consume = __ATOMIC_CONSUME, - memory_order_acquire = __ATOMIC_ACQUIRE, - memory_order_release = __ATOMIC_RELEASE, - memory_order_acq_rel = __ATOMIC_ACQ_REL, - memory_order_seq_cst = __ATOMIC_SEQ_CST, -} memory_order; - -/* Atomic typedefs */ -typedef _Atomic(_Bool) atomic_bool; -typedef _Atomic(char) atomic_char; -typedef _Atomic(signed char) atomic_schar; -typedef _Atomic(unsigned char) atomic_uchar; -typedef _Atomic(short) atomic_short; -typedef _Atomic(unsigned short) atomic_ushort; -typedef _Atomic(int) atomic_int; -typedef _Atomic(unsigned int) atomic_uint; -typedef _Atomic(long) atomic_long; -typedef _Atomic(unsigned long) atomic_ulong; -typedef _Atomic(long long) atomic_llong; -typedef _Atomic(unsigned long long) atomic_ullong; -typedef _Atomic(uint_least16_t) atomic_char16_t; -typedef _Atomic(uint_least32_t) atomic_char32_t; -typedef _Atomic(wchar_t) atomic_wchar_t; -typedef _Atomic(int_least8_t) atomic_int_least8_t; -typedef _Atomic(uint_least8_t) atomic_uint_least8_t; -typedef _Atomic(int_least16_t) atomic_int_least16_t; -typedef _Atomic(uint_least16_t) atomic_uint_least16_t; -typedef _Atomic(int_least32_t) atomic_int_least32_t; -typedef _Atomic(uint_least32_t) atomic_uint_least32_t; -typedef _Atomic(int_least64_t) atomic_int_least64_t; -typedef _Atomic(uint_least64_t) atomic_uint_least64_t; -typedef _Atomic(int_fast8_t) atomic_int_fast8_t; -typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t; -typedef _Atomic(int_fast16_t) atomic_int_fast16_t; -typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t; -typedef _Atomic(int_fast32_t) atomic_int_fast32_t; -typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t; -typedef _Atomic(int_fast64_t) atomic_int_fast64_t; -typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t; -typedef _Atomic(intptr_t) atomic_intptr_t; -typedef _Atomic(uintptr_t) atomic_uintptr_t; -typedef _Atomic(size_t) atomic_size_t; -typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t; -typedef _Atomic(intmax_t) atomic_intmax_t; -typedef _Atomic(uintmax_t) atomic_uintmax_t; - -/* Atomic flag */ -typedef struct { - atomic_bool value; -} atomic_flag; - -#define ATOMIC_FLAG_INIT {0} - -#define atomic_flag_test_and_set(object) \ - __c11_atomic_exchange(&(object)->value, 1, __ATOMIC_SEQ_CST) -#define atomic_flag_test_and_set_explicit(object, order) \ - __c11_atomic_exchange(&(object)->value, 1, order) - -#define atomic_flag_clear(object) \ - __c11_atomic_store(&(object)->value, 0, __ATOMIC_SEQ_CST) -#define atomic_flag_clear_explicit(object, order) \ - __c11_atomic_store(&(object)->value, 0, order) - -/* Generic routines */ -#define atomic_store(object, desired) \ - __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) -#define atomic_store_explicit __c11_atomic_store - -#define atomic_load(object) \ - __c11_atomic_load(object, __ATOMIC_SEQ_CST) -#define atomic_load_explicit __c11_atomic_load - -#define atomic_exchange(object, desired) \ - __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) -#define atomic_exchange_explicit __c11_atomic_exchange - -#define atomic_compare_exchange_strong(object, expected, desired) \ - __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) -#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong - -#define atomic_compare_exchange_weak(object, expected, desired) \ - __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) -#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak - -#define atomic_fetch_add(object, operand) \ - __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_add_explicit __c11_atomic_fetch_add - -#define atomic_fetch_sub(object, operand) \ - __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub - -#define atomic_fetch_or(object, operand) \ - __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_or_explicit __c11_atomic_fetch_or - -#define atomic_fetch_xor(object, operand) \ - __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor - -#define atomic_fetch_and(object, operand) \ - __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_and_explicit __c11_atomic_fetch_and - -#endif /* _STDATOMIC_H */ +/* This file is derived from clang's stdatomic.h */ + +/*===---- stdatomic.h - Standard header for atomic types and operations -----=== + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef _STDATOMIC_H +#define _STDATOMIC_H + +#include +#include + +/* Memory ordering */ +typedef enum { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST, +} memory_order; + +/* Atomic typedefs */ +typedef _Atomic(_Bool) atomic_bool; +typedef _Atomic(char) atomic_char; +typedef _Atomic(signed char) atomic_schar; +typedef _Atomic(unsigned char) atomic_uchar; +typedef _Atomic(short) atomic_short; +typedef _Atomic(unsigned short) atomic_ushort; +typedef _Atomic(int) atomic_int; +typedef _Atomic(unsigned int) atomic_uint; +typedef _Atomic(long) atomic_long; +typedef _Atomic(unsigned long) atomic_ulong; +typedef _Atomic(long long) atomic_llong; +typedef _Atomic(unsigned long long) atomic_ullong; +typedef _Atomic(uint_least16_t) atomic_char16_t; +typedef _Atomic(uint_least32_t) atomic_char32_t; +typedef _Atomic(wchar_t) atomic_wchar_t; +typedef _Atomic(int_least8_t) atomic_int_least8_t; +typedef _Atomic(uint_least8_t) atomic_uint_least8_t; +typedef _Atomic(int_least16_t) atomic_int_least16_t; +typedef _Atomic(uint_least16_t) atomic_uint_least16_t; +typedef _Atomic(int_least32_t) atomic_int_least32_t; +typedef _Atomic(uint_least32_t) atomic_uint_least32_t; +typedef _Atomic(int_least64_t) atomic_int_least64_t; +typedef _Atomic(uint_least64_t) atomic_uint_least64_t; +typedef _Atomic(int_fast8_t) atomic_int_fast8_t; +typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t; +typedef _Atomic(int_fast16_t) atomic_int_fast16_t; +typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t; +typedef _Atomic(int_fast32_t) atomic_int_fast32_t; +typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t; +typedef _Atomic(int_fast64_t) atomic_int_fast64_t; +typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t; +typedef _Atomic(intptr_t) atomic_intptr_t; +typedef _Atomic(uintptr_t) atomic_uintptr_t; +typedef _Atomic(size_t) atomic_size_t; +typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t; +typedef _Atomic(intmax_t) atomic_intmax_t; +typedef _Atomic(uintmax_t) atomic_uintmax_t; + +/* Atomic flag */ +typedef struct { + atomic_bool value; +} atomic_flag; + +#define ATOMIC_FLAG_INIT {0} + +#define atomic_flag_test_and_set(object) \ + __c11_atomic_exchange(&(object)->value, 1, __ATOMIC_SEQ_CST) +#define atomic_flag_test_and_set_explicit(object, order) \ + __c11_atomic_exchange(&(object)->value, 1, order) + +#define atomic_flag_clear(object) \ + __c11_atomic_store(&(object)->value, 0, __ATOMIC_SEQ_CST) +#define atomic_flag_clear_explicit(object, order) \ + __c11_atomic_store(&(object)->value, 0, order) + +/* Generic routines */ +#define atomic_store(object, desired) \ + __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) +#define atomic_store_explicit __c11_atomic_store + +#define atomic_load(object) \ + __c11_atomic_load(object, __ATOMIC_SEQ_CST) +#define atomic_load_explicit __c11_atomic_load + +#define atomic_exchange(object, desired) \ + __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) +#define atomic_exchange_explicit __c11_atomic_exchange + +#define atomic_compare_exchange_strong(object, expected, desired) \ + __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong + +#define atomic_compare_exchange_weak(object, expected, desired) \ + __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak + +#define atomic_fetch_add(object, operand) \ + __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_add_explicit __c11_atomic_fetch_add + +#define atomic_fetch_sub(object, operand) \ + __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub + +#define atomic_fetch_or(object, operand) \ + __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_or_explicit __c11_atomic_fetch_or + +#define atomic_fetch_xor(object, operand) \ + __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor + +#define atomic_fetch_and(object, operand) \ + __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_and_explicit __c11_atomic_fetch_and + +#endif /* _STDATOMIC_H */ diff --git a/tcc/include/stdbool.h b/tcc/include/stdbool.h index d2ee446e..71579490 100644 --- a/tcc/include/stdbool.h +++ b/tcc/include/stdbool.h @@ -1,11 +1,11 @@ -#ifndef _STDBOOL_H -#define _STDBOOL_H - -/* ISOC99 boolean */ - -#define bool _Bool -#define true 1 -#define false 0 -#define __bool_true_false_are_defined 1 - -#endif /* _STDBOOL_H */ +#ifndef _STDBOOL_H +#define _STDBOOL_H + +/* ISOC99 boolean */ + +#define bool _Bool +#define true 1 +#define false 0 +#define __bool_true_false_are_defined 1 + +#endif /* _STDBOOL_H */ diff --git a/tcc/include/stddef.h b/tcc/include/stddef.h index ea024f30..52232361 100644 --- a/tcc/include/stddef.h +++ b/tcc/include/stddef.h @@ -1,39 +1,39 @@ -#ifndef _STDDEF_H -#define _STDDEF_H - -typedef __SIZE_TYPE__ size_t; -typedef __PTRDIFF_TYPE__ ssize_t; -typedef __WCHAR_TYPE__ wchar_t; -typedef __PTRDIFF_TYPE__ ptrdiff_t; -typedef __PTRDIFF_TYPE__ intptr_t; -typedef __SIZE_TYPE__ uintptr_t; - -#if __STDC_VERSION__ >= 201112L -typedef union { long long __ll; long double __ld; } max_align_t; -#endif - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#undef offsetof -#define offsetof(type, field) ((size_t)&((type *)0)->field) - -void *alloca(size_t size); - -#endif - -/* Older glibc require a wint_t from (when requested - by __need_wint_t, as otherwise stddef.h isn't allowed to - define this type). Note that this must be outside the normal - _STDDEF_H guard, so that it works even when we've included the file - already (without requiring wint_t). Some other libs define _WINT_T - if they've already provided that type, so we can use that as guard. - TCC defines __WINT_TYPE__ for us. */ -#if defined (__need_wint_t) -#ifndef _WINT_T -#define _WINT_T -typedef __WINT_TYPE__ wint_t; -#endif -#undef __need_wint_t -#endif +#ifndef _STDDEF_H +#define _STDDEF_H + +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ssize_t; +typedef __WCHAR_TYPE__ wchar_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __PTRDIFF_TYPE__ intptr_t; +typedef __SIZE_TYPE__ uintptr_t; + +#if __STDC_VERSION__ >= 201112L +typedef union { long long __ll; long double __ld; } max_align_t; +#endif + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#undef offsetof +#define offsetof(type, field) ((size_t)&((type *)0)->field) + +void *alloca(size_t size); + +#endif + +/* Older glibc require a wint_t from (when requested + by __need_wint_t, as otherwise stddef.h isn't allowed to + define this type). Note that this must be outside the normal + _STDDEF_H guard, so that it works even when we've included the file + already (without requiring wint_t). Some other libs define _WINT_T + if they've already provided that type, so we can use that as guard. + TCC defines __WINT_TYPE__ for us. */ +#if defined (__need_wint_t) +#ifndef _WINT_T +#define _WINT_T +typedef __WINT_TYPE__ wint_t; +#endif +#undef __need_wint_t +#endif diff --git a/tcc/include/stdint.h b/tcc/include/stdint.h index cde32b6e..d6c0d33c 100644 --- a/tcc/include/stdint.h +++ b/tcc/include/stdint.h @@ -1,212 +1,212 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* ISO C9x 7.18 Integer types - * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * Contributor: Danny Smith - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Date: 2000-12-02 - */ - - -#ifndef _STDINT_H -#define _STDINT_H - -#include <_mingw.h> - -#define __need_wint_t -#define __need_wchar_t -#include "stddef.h" - -#ifndef __int8_t_defined -#define __int8_t_defined -/* 7.18.1.1 Exact-width integer types */ -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef int int32_t; -typedef unsigned uint32_t; -typedef long long int64_t; -typedef unsigned long long uint64_t; -#endif - -/* 7.18.1.2 Minimum-width integer types */ -typedef signed char int_least8_t; -typedef unsigned char uint_least8_t; -typedef short int_least16_t; -typedef unsigned short uint_least16_t; -typedef int int_least32_t; -typedef unsigned uint_least32_t; -typedef long long int_least64_t; -typedef unsigned long long uint_least64_t; - -/* 7.18.1.3 Fastest minimum-width integer types - * Not actually guaranteed to be fastest for all purposes - * Here we use the exact-width types for 8 and 16-bit ints. - */ -typedef char int_fast8_t; -typedef unsigned char uint_fast8_t; -typedef short int_fast16_t; -typedef unsigned short uint_fast16_t; -typedef int int_fast32_t; -typedef unsigned int uint_fast32_t; -typedef long long int_fast64_t; -typedef unsigned long long uint_fast64_t; - -/* 7.18.1.5 Greatest-width integer types */ -typedef long long intmax_t; -typedef unsigned long long uintmax_t; - -/* 7.18.2 Limits of specified-width integer types */ -#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) - -/* 7.18.2.1 Limits of exact-width integer types */ -#define INT8_MIN (-128) -#define INT16_MIN (-32768) -#define INT32_MIN (-2147483647 - 1) -#define INT64_MIN (-9223372036854775807LL - 1) - -#define INT8_MAX 127 -#define INT16_MAX 32767 -#define INT32_MAX 2147483647 -#define INT64_MAX 9223372036854775807LL - -#define UINT8_MAX 0xff /* 255U */ -#define UINT16_MAX 0xffff /* 65535U */ -#define UINT32_MAX 0xffffffff /* 4294967295U */ -#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ - -/* 7.18.2.2 Limits of minimum-width integer types */ -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST64_MIN INT64_MIN - -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MAX INT64_MAX - -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -/* 7.18.2.3 Limits of fastest minimum-width integer types */ -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST64_MIN INT64_MIN - -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MAX INT64_MAX - -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -/* 7.18.2.4 Limits of integer types capable of holding - object pointers */ -#ifdef _WIN64 -#define INTPTR_MIN INT64_MIN -#define INTPTR_MAX INT64_MAX -#define UINTPTR_MAX UINT64_MAX -#else -#define INTPTR_MIN INT32_MIN -#define INTPTR_MAX INT32_MAX -#define UINTPTR_MAX UINT32_MAX -#endif - -/* 7.18.2.5 Limits of greatest-width integer types */ -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -/* 7.18.3 Limits of other integer types */ -#ifdef _WIN64 -#define PTRDIFF_MIN INT64_MIN -#define PTRDIFF_MAX INT64_MAX -#else -#define PTRDIFF_MIN INT32_MIN -#define PTRDIFF_MAX INT32_MAX -#endif - -#define SIG_ATOMIC_MIN INT32_MIN -#define SIG_ATOMIC_MAX INT32_MAX - -#ifndef SIZE_MAX -#ifdef _WIN64 -#define SIZE_MAX UINT64_MAX -#else -#define SIZE_MAX UINT32_MAX -#endif -#endif - -#ifndef WCHAR_MIN /* also in wchar.h */ -#define WCHAR_MIN 0 -#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */ -#endif - -/* - * wint_t is unsigned short for compatibility with MS runtime - */ -#define WINT_MIN 0 -#define WINT_MAX ((wint_t)-1) /* UINT16_MAX */ - -#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ - - -/* 7.18.4 Macros for integer constants */ -#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) - -/* 7.18.4.1 Macros for minimum-width integer constants - - According to Douglas Gwyn : - "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC - 9899:1999 as initially published, the expansion was required - to be an integer constant of precisely matching type, which - is impossible to accomplish for the shorter types on most - platforms, because C99 provides no standard way to designate - an integer constant with width less than that of type int. - TC1 changed this to require just an integer constant - *expression* with *promoted* type." - - The trick used here is from Clive D W Feather. -*/ - -#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val)) -#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val)) -#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val)) -/* The 'trick' doesn't work in C89 for long long because, without - suffix, (val) will be evaluated as int, not intmax_t */ -#define INT64_C(val) val##LL - -#define UINT8_C(val) (UINT_LEAST8_MAX-UINT_LEAST8_MAX+(val)) -#define UINT16_C(val) (UINT_LEAST16_MAX-UINT_LEAST16_MAX+(val)) -#define UINT32_C(val) (UINT_LEAST32_MAX-UINT_LEAST32_MAX+(val)) -#define UINT64_C(val) val##ULL - -/* 7.18.4.2 Macros for greatest-width integer constants */ -#define INTMAX_C(val) val##LL -#define UINTMAX_C(val) val##ULL - -#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* ISO C9x 7.18 Integer types + * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * Contributor: Danny Smith + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Date: 2000-12-02 + */ + + +#ifndef _STDINT_H +#define _STDINT_H + +#include <_mingw.h> + +#define __need_wint_t +#define __need_wchar_t +#include "stddef.h" + +#ifndef __int8_t_defined +#define __int8_t_defined +/* 7.18.1.1 Exact-width integer types */ +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + +/* 7.18.1.2 Minimum-width integer types */ +typedef signed char int_least8_t; +typedef unsigned char uint_least8_t; +typedef short int_least16_t; +typedef unsigned short uint_least16_t; +typedef int int_least32_t; +typedef unsigned uint_least32_t; +typedef long long int_least64_t; +typedef unsigned long long uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types + * Not actually guaranteed to be fastest for all purposes + * Here we use the exact-width types for 8 and 16-bit ints. + */ +typedef char int_fast8_t; +typedef unsigned char uint_fast8_t; +typedef short int_fast16_t; +typedef unsigned short uint_fast16_t; +typedef int int_fast32_t; +typedef unsigned int uint_fast32_t; +typedef long long int_fast64_t; +typedef unsigned long long uint_fast64_t; + +/* 7.18.1.5 Greatest-width integer types */ +typedef long long intmax_t; +typedef unsigned long long uintmax_t; + +/* 7.18.2 Limits of specified-width integer types */ +#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) + +/* 7.18.2.1 Limits of exact-width integer types */ +#define INT8_MIN (-128) +#define INT16_MIN (-32768) +#define INT32_MIN (-2147483647 - 1) +#define INT64_MIN (-9223372036854775807LL - 1) + +#define INT8_MAX 127 +#define INT16_MAX 32767 +#define INT32_MAX 2147483647 +#define INT64_MAX 9223372036854775807LL + +#define UINT8_MAX 0xff /* 255U */ +#define UINT16_MAX 0xffff /* 65535U */ +#define UINT32_MAX 0xffffffff /* 4294967295U */ +#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ + +/* 7.18.2.2 Limits of minimum-width integer types */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* 7.18.2.3 Limits of fastest minimum-width integer types */ +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN + +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +/* 7.18.2.4 Limits of integer types capable of holding + object pointers */ +#ifdef _WIN64 +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX +#else +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#endif + +/* 7.18.2.5 Limits of greatest-width integer types */ +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +/* 7.18.3 Limits of other integer types */ +#ifdef _WIN64 +#define PTRDIFF_MIN INT64_MIN +#define PTRDIFF_MAX INT64_MAX +#else +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX +#endif + +#define SIG_ATOMIC_MIN INT32_MIN +#define SIG_ATOMIC_MAX INT32_MAX + +#ifndef SIZE_MAX +#ifdef _WIN64 +#define SIZE_MAX UINT64_MAX +#else +#define SIZE_MAX UINT32_MAX +#endif +#endif + +#ifndef WCHAR_MIN /* also in wchar.h */ +#define WCHAR_MIN 0 +#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */ +#endif + +/* + * wint_t is unsigned short for compatibility with MS runtime + */ +#define WINT_MIN 0 +#define WINT_MAX ((wint_t)-1) /* UINT16_MAX */ + +#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ + + +/* 7.18.4 Macros for integer constants */ +#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) + +/* 7.18.4.1 Macros for minimum-width integer constants + + According to Douglas Gwyn : + "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC + 9899:1999 as initially published, the expansion was required + to be an integer constant of precisely matching type, which + is impossible to accomplish for the shorter types on most + platforms, because C99 provides no standard way to designate + an integer constant with width less than that of type int. + TC1 changed this to require just an integer constant + *expression* with *promoted* type." + + The trick used here is from Clive D W Feather. +*/ + +#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val)) +#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val)) +#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val)) +/* The 'trick' doesn't work in C89 for long long because, without + suffix, (val) will be evaluated as int, not intmax_t */ +#define INT64_C(val) val##LL + +#define UINT8_C(val) (UINT_LEAST8_MAX-UINT_LEAST8_MAX+(val)) +#define UINT16_C(val) (UINT_LEAST16_MAX-UINT_LEAST16_MAX+(val)) +#define UINT32_C(val) (UINT_LEAST32_MAX-UINT_LEAST32_MAX+(val)) +#define UINT64_C(val) val##ULL + +/* 7.18.4.2 Macros for greatest-width integer constants */ +#define INTMAX_C(val) val##LL +#define UINTMAX_C(val) val##ULL + +#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ + +#endif diff --git a/tcc/include/stdio.h b/tcc/include/stdio.h index da887936..0ec55246 100644 --- a/tcc/include/stdio.h +++ b/tcc/include/stdio.h @@ -1,429 +1,429 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDIO -#define _INC_STDIO - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#define BUFSIZ 512 -#define _NFILE _NSTREAM_ -#define _NSTREAM_ 512 -#define _IOB_ENTRIES 20 -#define EOF (-1) - -#ifndef _FILE_DEFINED - struct _iobuf { - char *_ptr; - int _cnt; - char *_base; - int _flag; - int _file; - int _charbuf; - int _bufsiz; - char *_tmpfname; - }; - typedef struct _iobuf FILE; -#define _FILE_DEFINED -#endif - -#ifdef _POSIX_ -#define _P_tmpdir "/" -#define _wP_tmpdir L"/" -#else -#define _P_tmpdir "\\" -#define _wP_tmpdir L"\\" -#endif - -#define L_tmpnam (sizeof(_P_tmpdir) + 12) - -#ifdef _POSIX_ -#define L_ctermid 9 -#define L_cuserid 32 -#endif - -#define SEEK_CUR 1 -#define SEEK_END 2 -#define SEEK_SET 0 - -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 - -#define FILENAME_MAX 260 -#define FOPEN_MAX 20 -#define _SYS_OPEN 20 -#define TMP_MAX 32767 - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif - -#ifndef _STDIO_DEFINED -#ifdef _WIN64 - _CRTIMP FILE *__cdecl __iob_func(void); -#else -#ifdef _MSVCRT_ -extern FILE _iob[]; /* A pointer to an array of FILE */ -#define __iob_func() (_iob) -#else -extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ -#define __iob_func() (*_imp___iob) -#define _iob __iob_func() -#endif -#endif -#endif - -#ifndef _FPOS_T_DEFINED -#define _FPOS_T_DEFINED -#undef _FPOSOFF - -#if (!defined(NO_OLDNAMES) || defined(__GNUC__)) && _INTEGRAL_MAX_BITS >= 64 - typedef __int64 fpos_t; -#define _FPOSOFF(fp) ((long)(fp)) -#else - typedef long long fpos_t; -#define _FPOSOFF(fp) ((long)(fp)) -#endif - -#endif - -#ifndef _STDSTREAM_DEFINED -#define _STDSTREAM_DEFINED - -#define stdin (&__iob_func()[0]) -#define stdout (&__iob_func()[1]) -#define stderr (&__iob_func()[2]) -#endif - -#define _IOREAD 0x0001 -#define _IOWRT 0x0002 - -#define _IOFBF 0x0000 -#define _IOLBF 0x0040 -#define _IONBF 0x0004 - -#define _IOMYBUF 0x0008 -#define _IOEOF 0x0010 -#define _IOERR 0x0020 -#define _IOSTRG 0x0040 -#define _IORW 0x0080 -#ifdef _POSIX_ -#define _IOAPPEND 0x0200 -#endif - -#define _TWO_DIGIT_EXPONENT 0x1 - -#ifndef _STDIO_DEFINED - - _CRTIMP int __cdecl _filbuf(FILE *_File); - _CRTIMP int __cdecl _flsbuf(int _Ch,FILE *_File); -#ifdef _POSIX_ - _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode); -#else - _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode,int _ShFlag); -#endif - void __cdecl clearerr(FILE *_File); - int __cdecl fclose(FILE *_File); - _CRTIMP int __cdecl _fcloseall(void); -#ifdef _POSIX_ - FILE *__cdecl fdopen(int _FileHandle,const char *_Mode); -#else - _CRTIMP FILE *__cdecl _fdopen(int _FileHandle,const char *_Mode); -#endif - int __cdecl feof(FILE *_File); - int __cdecl ferror(FILE *_File); - int __cdecl fflush(FILE *_File); - int __cdecl fgetc(FILE *_File); - _CRTIMP int __cdecl _fgetchar(void); - int __cdecl fgetpos(FILE *_File ,fpos_t *_Pos); - char *__cdecl fgets(char *_Buf,int _MaxCount,FILE *_File); -#ifdef _POSIX_ - int __cdecl fileno(FILE *_File); -#else - _CRTIMP int __cdecl _fileno(FILE *_File); -#endif - _CRTIMP char *__cdecl _tempnam(const char *_DirName,const char *_FilePrefix); - _CRTIMP int __cdecl _flushall(void); - FILE *__cdecl fopen(const char *_Filename,const char *_Mode); - FILE *fopen64(const char *filename,const char *mode); - int __cdecl fprintf(FILE *_File,const char *_Format,...); - int __cdecl fputc(int _Ch,FILE *_File); - _CRTIMP int __cdecl _fputchar(int _Ch); - int __cdecl fputs(const char *_Str,FILE *_File); - size_t __cdecl fread(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); - FILE *__cdecl freopen(const char *_Filename,const char *_Mode,FILE *_File); - int __cdecl fscanf(FILE *_File,const char *_Format,...); - int __cdecl fsetpos(FILE *_File,const fpos_t *_Pos); - int __cdecl fseek(FILE *_File,long _Offset,int _Origin); - int fseeko64(FILE* stream, _off64_t offset, int whence); - long __cdecl ftell(FILE *_File); - _off64_t ftello64(FILE * stream); - int __cdecl _fseeki64(FILE *_File,__int64 _Offset,int _Origin); - __int64 __cdecl _ftelli64(FILE *_File); - size_t __cdecl fwrite(const void *_Str,size_t _Size,size_t _Count,FILE *_File); - int __cdecl getc(FILE *_File); - int __cdecl getchar(void); - _CRTIMP int __cdecl _getmaxstdio(void); - char *__cdecl gets(char *_Buffer); - int __cdecl _getw(FILE *_File); -#ifndef _CRT_PERROR_DEFINED -#define _CRT_PERROR_DEFINED - void __cdecl perror(const char *_ErrMsg); -#endif - _CRTIMP int __cdecl _pclose(FILE *_File); - _CRTIMP FILE *__cdecl _popen(const char *_Command,const char *_Mode); -#if !defined(NO_OLDNAMES) && !defined(popen) -#define popen _popen -#define pclose _pclose -#endif - int __cdecl printf(const char *_Format,...); - int __cdecl putc(int _Ch,FILE *_File); - int __cdecl putchar(int _Ch); - int __cdecl puts(const char *_Str); - _CRTIMP int __cdecl _putw(int _Word,FILE *_File); -#ifndef _CRT_DIRECTORY_DEFINED -#define _CRT_DIRECTORY_DEFINED - int __cdecl remove(const char *_Filename); - int __cdecl rename(const char *_OldFilename,const char *_NewFilename); - _CRTIMP int __cdecl _unlink(const char *_Filename); -#ifndef NO_OLDNAMES - int __cdecl unlink(const char *_Filename); -#endif -#endif - void __cdecl rewind(FILE *_File); - _CRTIMP int __cdecl _rmtmp(void); - int __cdecl scanf(const char *_Format,...); - void __cdecl setbuf(FILE *_File,char *_Buffer); - _CRTIMP int __cdecl _setmaxstdio(int _Max); - _CRTIMP unsigned int __cdecl _set_output_format(unsigned int _Format); - _CRTIMP unsigned int __cdecl _get_output_format(void); - int __cdecl setvbuf(FILE *_File,char *_Buf,int _Mode,size_t _Size); - _CRTIMP int __cdecl _scprintf(const char *_Format,...); - int __cdecl sscanf(const char *_Src,const char *_Format,...); - _CRTIMP int __cdecl _snscanf(const char *_Src,size_t _MaxCount,const char *_Format,...); - FILE *__cdecl tmpfile(void); - char *__cdecl tmpnam(char *_Buffer); - int __cdecl ungetc(int _Ch,FILE *_File); - int __cdecl vfprintf(FILE *_File,const char *_Format,va_list _ArgList); - int __cdecl vprintf(const char *_Format,va_list _ArgList); - /* Make sure macros are not defined. */ -#pragma push_macro("vsnprintf") -#pragma push_macro("snprintf") -# undef vsnprintf -# undef snprintf - extern - __attribute__((format(gnu_printf, 3, 0))) __attribute__((nonnull (3))) - int __mingw_vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); - extern - __attribute__((format(gnu_printf, 3, 4))) __attribute__((nonnull (3))) - int __mingw_snprintf(char* s, size_t n, const char* format, ...); - int __cdecl vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snprintf(char *_Dest,size_t _Count,const char *_Format,...); - _CRTIMP int __cdecl _vsnprintf(char *_Dest,size_t _Count,const char *_Format,va_list _Args); - int __cdecl sprintf(char *_Dest,const char *_Format,...); - int __cdecl vsprintf(char *_Dest,const char *_Format,va_list _Args); -#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ - int __cdecl snprintf(char* s, size_t n, const char* format, ...); - __CRT_INLINE int __cdecl vsnprintf (char* s, size_t n, const char* format,va_list arg) { - return _vsnprintf ( s, n, format, arg); - } - int __cdecl vscanf(const char * Format, va_list argp); - int __cdecl vfscanf (FILE * fp, const char * Format,va_list argp); - int __cdecl vsscanf (const char * _Str,const char * Format,va_list argp); -#endif -/* Restore may prior defined macros snprintf/vsnprintf. */ -#pragma pop_macro("snprintf") -#pragma pop_macro("vsnprintf") -/* Check if vsnprintf and snprintf are defaulting to gnu-style. */ -# if defined(USE_MINGW_GNU_SNPRINTF) && USE_MINGW_GNU_SNPRINTF -# ifndef vsnprint -# define vsnprintf __mingw_vsnprintf -# endif -# ifndef snprintf -# define snprintf __mingw_snprintf -# endif -# endif - _CRTIMP int __cdecl _vscprintf(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _set_printf_count_output(int _Value); - _CRTIMP int __cdecl _get_printf_count_output(void); - -#ifndef _WSTDIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifdef _POSIX_ - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); -#else - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); -#endif - wint_t __cdecl fgetwc(FILE *_File); - _CRTIMP wint_t __cdecl _fgetwchar(void); - wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); - wint_t __cdecl getwc(FILE *_File); - wint_t __cdecl getwchar(void); - wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); - wint_t __cdecl putwchar(wchar_t _Ch); - wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); - wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); - int __cdecl fputws(const wchar_t *_Str,FILE *_File); - _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); - _CRTIMP int __cdecl _putws(const wchar_t *_Str); - int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); - int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); - int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); - _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); - _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); -#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ - int __cdecl snwprintf (wchar_t* s, size_t n, const wchar_t* format, ...); - __CRT_INLINE int __cdecl vsnwprintf (wchar_t* s, size_t n, const wchar_t* format, va_list arg) { return _vsnwprintf(s,n,format,arg); } - int __cdecl vwscanf (const wchar_t *, va_list); - int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); - int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); -#endif - _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); - -#ifndef RC_INVOKED -#include -#endif - -#ifdef _CRT_NON_CONFORMING_SWPRINTFS -#ifndef __cplusplus -#define swprintf _swprintf -#define vswprintf _vswprintf -#define _swprintf_l __swprintf_l -#define _vswprintf_l __vswprintf_l -#endif -#endif - - _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); - _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); - int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); - int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - int __cdecl wscanf(const wchar_t *_Format,...); - _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); -#if !defined(NO_OLDNAMES) && !defined(wpopen) -#define wpopen _wpopen -#endif - _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); - _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); - _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); - -#undef _CRT_GETPUTWCHAR_NOINLINE - -#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) -#define getwchar() fgetwc(stdin) -#define putwchar(_c) fputwc((_c),stdout) -#else - __CRT_INLINE wint_t __cdecl getwchar() { return (fgetwc(stdin)); } - __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) { return (fputwc(_C,stdout)); } -#endif - -#define getwc(_stm) fgetwc(_stm) -#define putwc(_c,_stm) fputwc(_c,_stm) -#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) -#define _getwc_nolock(_stm) _fgetwc_nolock(_stm) - -#define _WSTDIO_DEFINED -#endif - -#define _STDIO_DEFINED -#endif - -#define _fgetc_nolock(_stream) (--(_stream)->_cnt >= 0 ? 0xff & *(_stream)->_ptr++ : _filbuf(_stream)) -#define _fputc_nolock(_c,_stream) (--(_stream)->_cnt >= 0 ? 0xff & (*(_stream)->_ptr++ = (char)(_c)) : _flsbuf((_c),(_stream))) -#define _getc_nolock(_stream) _fgetc_nolock(_stream) -#define _putc_nolock(_c,_stream) _fputc_nolock(_c,_stream) -#define _getchar_nolock() _getc_nolock(stdin) -#define _putchar_nolock(_c) _putc_nolock((_c),stdout) -#define _getwchar_nolock() _getwc_nolock(stdin) -#define _putwchar_nolock(_c) _putwc_nolock((_c),stdout) - - _CRTIMP void __cdecl _lock_file(FILE *_File); - _CRTIMP void __cdecl _unlock_file(FILE *_File); - _CRTIMP int __cdecl _fclose_nolock(FILE *_File); - _CRTIMP int __cdecl _fflush_nolock(FILE *_File); - _CRTIMP size_t __cdecl _fread_nolock(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); - _CRTIMP int __cdecl _fseek_nolock(FILE *_File,long _Offset,int _Origin); - _CRTIMP long __cdecl _ftell_nolock(FILE *_File); - _CRTIMP int __cdecl _fseeki64_nolock(FILE *_File,__int64 _Offset,int _Origin); - _CRTIMP __int64 __cdecl _ftelli64_nolock(FILE *_File); - _CRTIMP size_t __cdecl _fwrite_nolock(const void *_DstBuf,size_t _Size,size_t _Count,FILE *_File); - _CRTIMP int __cdecl _ungetc_nolock(int _Ch,FILE *_File); - -#if !defined(NO_OLDNAMES) || !defined(_POSIX) -#define P_tmpdir _P_tmpdir -#define SYS_OPEN _SYS_OPEN - - char *__cdecl tempnam(const char *_Directory,const char *_FilePrefix); - int __cdecl fcloseall(void); - FILE *__cdecl fdopen(int _FileHandle,const char *_Format); - int __cdecl fgetchar(void); - int __cdecl fileno(FILE *_File); - int __cdecl flushall(void); - int __cdecl fputchar(int _Ch); - int __cdecl getw(FILE *_File); - int __cdecl putw(int _Ch,FILE *_File); - int __cdecl rmtmp(void); -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDIO +#define _INC_STDIO + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#define BUFSIZ 512 +#define _NFILE _NSTREAM_ +#define _NSTREAM_ 512 +#define _IOB_ENTRIES 20 +#define EOF (-1) + +#ifndef _FILE_DEFINED + struct _iobuf { + char *_ptr; + int _cnt; + char *_base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char *_tmpfname; + }; + typedef struct _iobuf FILE; +#define _FILE_DEFINED +#endif + +#ifdef _POSIX_ +#define _P_tmpdir "/" +#define _wP_tmpdir L"/" +#else +#define _P_tmpdir "\\" +#define _wP_tmpdir L"\\" +#endif + +#define L_tmpnam (sizeof(_P_tmpdir) + 12) + +#ifdef _POSIX_ +#define L_ctermid 9 +#define L_cuserid 32 +#endif + +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_SET 0 + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#define FILENAME_MAX 260 +#define FOPEN_MAX 20 +#define _SYS_OPEN 20 +#define TMP_MAX 32767 + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif + +#ifndef _STDIO_DEFINED +#ifdef _WIN64 + _CRTIMP FILE *__cdecl __iob_func(void); +#else +#ifdef _MSVCRT_ +extern FILE _iob[]; /* A pointer to an array of FILE */ +#define __iob_func() (_iob) +#else +extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ +#define __iob_func() (*_imp___iob) +#define _iob __iob_func() +#endif +#endif +#endif + +#ifndef _FPOS_T_DEFINED +#define _FPOS_T_DEFINED +#undef _FPOSOFF + +#if (!defined(NO_OLDNAMES) || defined(__GNUC__)) && _INTEGRAL_MAX_BITS >= 64 + typedef __int64 fpos_t; +#define _FPOSOFF(fp) ((long)(fp)) +#else + typedef long long fpos_t; +#define _FPOSOFF(fp) ((long)(fp)) +#endif + +#endif + +#ifndef _STDSTREAM_DEFINED +#define _STDSTREAM_DEFINED + +#define stdin (&__iob_func()[0]) +#define stdout (&__iob_func()[1]) +#define stderr (&__iob_func()[2]) +#endif + +#define _IOREAD 0x0001 +#define _IOWRT 0x0002 + +#define _IOFBF 0x0000 +#define _IOLBF 0x0040 +#define _IONBF 0x0004 + +#define _IOMYBUF 0x0008 +#define _IOEOF 0x0010 +#define _IOERR 0x0020 +#define _IOSTRG 0x0040 +#define _IORW 0x0080 +#ifdef _POSIX_ +#define _IOAPPEND 0x0200 +#endif + +#define _TWO_DIGIT_EXPONENT 0x1 + +#ifndef _STDIO_DEFINED + + _CRTIMP int __cdecl _filbuf(FILE *_File); + _CRTIMP int __cdecl _flsbuf(int _Ch,FILE *_File); +#ifdef _POSIX_ + _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode); +#else + _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode,int _ShFlag); +#endif + void __cdecl clearerr(FILE *_File); + int __cdecl fclose(FILE *_File); + _CRTIMP int __cdecl _fcloseall(void); +#ifdef _POSIX_ + FILE *__cdecl fdopen(int _FileHandle,const char *_Mode); +#else + _CRTIMP FILE *__cdecl _fdopen(int _FileHandle,const char *_Mode); +#endif + int __cdecl feof(FILE *_File); + int __cdecl ferror(FILE *_File); + int __cdecl fflush(FILE *_File); + int __cdecl fgetc(FILE *_File); + _CRTIMP int __cdecl _fgetchar(void); + int __cdecl fgetpos(FILE *_File ,fpos_t *_Pos); + char *__cdecl fgets(char *_Buf,int _MaxCount,FILE *_File); +#ifdef _POSIX_ + int __cdecl fileno(FILE *_File); +#else + _CRTIMP int __cdecl _fileno(FILE *_File); +#endif + _CRTIMP char *__cdecl _tempnam(const char *_DirName,const char *_FilePrefix); + _CRTIMP int __cdecl _flushall(void); + FILE *__cdecl fopen(const char *_Filename,const char *_Mode); + FILE *fopen64(const char *filename,const char *mode); + int __cdecl fprintf(FILE *_File,const char *_Format,...); + int __cdecl fputc(int _Ch,FILE *_File); + _CRTIMP int __cdecl _fputchar(int _Ch); + int __cdecl fputs(const char *_Str,FILE *_File); + size_t __cdecl fread(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); + FILE *__cdecl freopen(const char *_Filename,const char *_Mode,FILE *_File); + int __cdecl fscanf(FILE *_File,const char *_Format,...); + int __cdecl fsetpos(FILE *_File,const fpos_t *_Pos); + int __cdecl fseek(FILE *_File,long _Offset,int _Origin); + int fseeko64(FILE* stream, _off64_t offset, int whence); + long __cdecl ftell(FILE *_File); + _off64_t ftello64(FILE * stream); + int __cdecl _fseeki64(FILE *_File,__int64 _Offset,int _Origin); + __int64 __cdecl _ftelli64(FILE *_File); + size_t __cdecl fwrite(const void *_Str,size_t _Size,size_t _Count,FILE *_File); + int __cdecl getc(FILE *_File); + int __cdecl getchar(void); + _CRTIMP int __cdecl _getmaxstdio(void); + char *__cdecl gets(char *_Buffer); + int __cdecl _getw(FILE *_File); +#ifndef _CRT_PERROR_DEFINED +#define _CRT_PERROR_DEFINED + void __cdecl perror(const char *_ErrMsg); +#endif + _CRTIMP int __cdecl _pclose(FILE *_File); + _CRTIMP FILE *__cdecl _popen(const char *_Command,const char *_Mode); +#if !defined(NO_OLDNAMES) && !defined(popen) +#define popen _popen +#define pclose _pclose +#endif + int __cdecl printf(const char *_Format,...); + int __cdecl putc(int _Ch,FILE *_File); + int __cdecl putchar(int _Ch); + int __cdecl puts(const char *_Str); + _CRTIMP int __cdecl _putw(int _Word,FILE *_File); +#ifndef _CRT_DIRECTORY_DEFINED +#define _CRT_DIRECTORY_DEFINED + int __cdecl remove(const char *_Filename); + int __cdecl rename(const char *_OldFilename,const char *_NewFilename); + _CRTIMP int __cdecl _unlink(const char *_Filename); +#ifndef NO_OLDNAMES + int __cdecl unlink(const char *_Filename); +#endif +#endif + void __cdecl rewind(FILE *_File); + _CRTIMP int __cdecl _rmtmp(void); + int __cdecl scanf(const char *_Format,...); + void __cdecl setbuf(FILE *_File,char *_Buffer); + _CRTIMP int __cdecl _setmaxstdio(int _Max); + _CRTIMP unsigned int __cdecl _set_output_format(unsigned int _Format); + _CRTIMP unsigned int __cdecl _get_output_format(void); + int __cdecl setvbuf(FILE *_File,char *_Buf,int _Mode,size_t _Size); + _CRTIMP int __cdecl _scprintf(const char *_Format,...); + int __cdecl sscanf(const char *_Src,const char *_Format,...); + _CRTIMP int __cdecl _snscanf(const char *_Src,size_t _MaxCount,const char *_Format,...); + FILE *__cdecl tmpfile(void); + char *__cdecl tmpnam(char *_Buffer); + int __cdecl ungetc(int _Ch,FILE *_File); + int __cdecl vfprintf(FILE *_File,const char *_Format,va_list _ArgList); + int __cdecl vprintf(const char *_Format,va_list _ArgList); + /* Make sure macros are not defined. */ +#pragma push_macro("vsnprintf") +#pragma push_macro("snprintf") +# undef vsnprintf +# undef snprintf + extern + __attribute__((format(gnu_printf, 3, 0))) __attribute__((nonnull (3))) + int __mingw_vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); + extern + __attribute__((format(gnu_printf, 3, 4))) __attribute__((nonnull (3))) + int __mingw_snprintf(char* s, size_t n, const char* format, ...); + int __cdecl vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snprintf(char *_Dest,size_t _Count,const char *_Format,...); + _CRTIMP int __cdecl _vsnprintf(char *_Dest,size_t _Count,const char *_Format,va_list _Args); + int __cdecl sprintf(char *_Dest,const char *_Format,...); + int __cdecl vsprintf(char *_Dest,const char *_Format,va_list _Args); +#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ + int __cdecl snprintf(char* s, size_t n, const char* format, ...); + __CRT_INLINE int __cdecl vsnprintf (char* s, size_t n, const char* format,va_list arg) { + return _vsnprintf ( s, n, format, arg); + } + int __cdecl vscanf(const char * Format, va_list argp); + int __cdecl vfscanf (FILE * fp, const char * Format,va_list argp); + int __cdecl vsscanf (const char * _Str,const char * Format,va_list argp); +#endif +/* Restore may prior defined macros snprintf/vsnprintf. */ +#pragma pop_macro("snprintf") +#pragma pop_macro("vsnprintf") +/* Check if vsnprintf and snprintf are defaulting to gnu-style. */ +# if defined(USE_MINGW_GNU_SNPRINTF) && USE_MINGW_GNU_SNPRINTF +# ifndef vsnprint +# define vsnprintf __mingw_vsnprintf +# endif +# ifndef snprintf +# define snprintf __mingw_snprintf +# endif +# endif + _CRTIMP int __cdecl _vscprintf(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _set_printf_count_output(int _Value); + _CRTIMP int __cdecl _get_printf_count_output(void); + +#ifndef _WSTDIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifdef _POSIX_ + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); +#else + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); +#endif + wint_t __cdecl fgetwc(FILE *_File); + _CRTIMP wint_t __cdecl _fgetwchar(void); + wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); + wint_t __cdecl getwc(FILE *_File); + wint_t __cdecl getwchar(void); + wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); + wint_t __cdecl putwchar(wchar_t _Ch); + wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); + wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); + int __cdecl fputws(const wchar_t *_Str,FILE *_File); + _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); + _CRTIMP int __cdecl _putws(const wchar_t *_Str); + int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); + int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); + int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); + _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); + _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); +#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ + int __cdecl snwprintf (wchar_t* s, size_t n, const wchar_t* format, ...); + __CRT_INLINE int __cdecl vsnwprintf (wchar_t* s, size_t n, const wchar_t* format, va_list arg) { return _vsnwprintf(s,n,format,arg); } + int __cdecl vwscanf (const wchar_t *, va_list); + int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); + int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); +#endif + _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); + +#ifndef RC_INVOKED +#include +#endif + +#ifdef _CRT_NON_CONFORMING_SWPRINTFS +#ifndef __cplusplus +#define swprintf _swprintf +#define vswprintf _vswprintf +#define _swprintf_l __swprintf_l +#define _vswprintf_l __vswprintf_l +#endif +#endif + + _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); + _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); + int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); + int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + int __cdecl wscanf(const wchar_t *_Format,...); + _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); +#if !defined(NO_OLDNAMES) && !defined(wpopen) +#define wpopen _wpopen +#endif + _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); + _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); + _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); + +#undef _CRT_GETPUTWCHAR_NOINLINE + +#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) +#define getwchar() fgetwc(stdin) +#define putwchar(_c) fputwc((_c),stdout) +#else + __CRT_INLINE wint_t __cdecl getwchar() { return (fgetwc(stdin)); } + __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) { return (fputwc(_C,stdout)); } +#endif + +#define getwc(_stm) fgetwc(_stm) +#define putwc(_c,_stm) fputwc(_c,_stm) +#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) +#define _getwc_nolock(_stm) _fgetwc_nolock(_stm) + +#define _WSTDIO_DEFINED +#endif + +#define _STDIO_DEFINED +#endif + +#define _fgetc_nolock(_stream) (--(_stream)->_cnt >= 0 ? 0xff & *(_stream)->_ptr++ : _filbuf(_stream)) +#define _fputc_nolock(_c,_stream) (--(_stream)->_cnt >= 0 ? 0xff & (*(_stream)->_ptr++ = (char)(_c)) : _flsbuf((_c),(_stream))) +#define _getc_nolock(_stream) _fgetc_nolock(_stream) +#define _putc_nolock(_c,_stream) _fputc_nolock(_c,_stream) +#define _getchar_nolock() _getc_nolock(stdin) +#define _putchar_nolock(_c) _putc_nolock((_c),stdout) +#define _getwchar_nolock() _getwc_nolock(stdin) +#define _putwchar_nolock(_c) _putwc_nolock((_c),stdout) + + _CRTIMP void __cdecl _lock_file(FILE *_File); + _CRTIMP void __cdecl _unlock_file(FILE *_File); + _CRTIMP int __cdecl _fclose_nolock(FILE *_File); + _CRTIMP int __cdecl _fflush_nolock(FILE *_File); + _CRTIMP size_t __cdecl _fread_nolock(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); + _CRTIMP int __cdecl _fseek_nolock(FILE *_File,long _Offset,int _Origin); + _CRTIMP long __cdecl _ftell_nolock(FILE *_File); + _CRTIMP int __cdecl _fseeki64_nolock(FILE *_File,__int64 _Offset,int _Origin); + _CRTIMP __int64 __cdecl _ftelli64_nolock(FILE *_File); + _CRTIMP size_t __cdecl _fwrite_nolock(const void *_DstBuf,size_t _Size,size_t _Count,FILE *_File); + _CRTIMP int __cdecl _ungetc_nolock(int _Ch,FILE *_File); + +#if !defined(NO_OLDNAMES) || !defined(_POSIX) +#define P_tmpdir _P_tmpdir +#define SYS_OPEN _SYS_OPEN + + char *__cdecl tempnam(const char *_Directory,const char *_FilePrefix); + int __cdecl fcloseall(void); + FILE *__cdecl fdopen(int _FileHandle,const char *_Format); + int __cdecl fgetchar(void); + int __cdecl fileno(FILE *_File); + int __cdecl flushall(void); + int __cdecl fputchar(int _Ch); + int __cdecl getw(FILE *_File); + int __cdecl putw(int _Ch,FILE *_File); + int __cdecl rmtmp(void); +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include + +#endif diff --git a/tcc/include/stdlib.h b/tcc/include/stdlib.h index 033c0fdf..d5560c54 100644 --- a/tcc/include/stdlib.h +++ b/tcc/include/stdlib.h @@ -1,580 +1,580 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDLIB -#define _INC_STDLIB - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define EXIT_SUCCESS 0 -#define EXIT_FAILURE 1 - -#ifndef _ONEXIT_T_DEFINED -#define _ONEXIT_T_DEFINED - - typedef int (__cdecl *_onexit_t)(void); - -#ifndef NO_OLDNAMES -#define onexit_t _onexit_t -#endif -#endif - -#ifndef _DIV_T_DEFINED -#define _DIV_T_DEFINED - - typedef struct _div_t { - int quot; - int rem; - } div_t; - - typedef struct _ldiv_t { - long quot; - long rem; - } ldiv_t; -#endif - -#ifndef _CRT_DOUBLE_DEC -#define _CRT_DOUBLE_DEC - -#pragma pack(4) - typedef struct { - unsigned char ld[10]; - } _LDOUBLE; -#pragma pack() - -#define _PTR_LD(x) ((unsigned char *)(&(x)->ld)) - - typedef struct { - double x; - } _CRT_DOUBLE; - - typedef struct { - float f; - } _CRT_FLOAT; - -#pragma push_macro("long") -#undef long - - typedef struct { - long double x; - } _LONGDOUBLE; - -#pragma pop_macro("long") - -#pragma pack(4) - typedef struct { - unsigned char ld12[12]; - } _LDBL12; -#pragma pack() -#endif - -#define RAND_MAX 0x7fff - -#ifndef MB_CUR_MAX -#define MB_CUR_MAX ___mb_cur_max_func() -#ifndef __mb_cur_max -#ifdef _MSVCRT_ - extern int __mb_cur_max; -#else -#define __mb_cur_max (*_imp____mb_cur_max) - extern int *_imp____mb_cur_max; -#endif -#endif -#ifdef _MSVCRT_ - extern int __mbcur_max; -#define ___mb_cur_max_func() (__mb_cur_max) -#else - extern int* _imp____mbcur_max; -#define ___mb_cur_max_func() (*_imp____mb_cur_max) -#endif -#endif - -#define __max(a,b) (((a) > (b)) ? (a) : (b)) -#define __min(a,b) (((a) < (b)) ? (a) : (b)) - -#define _MAX_PATH 260 -#define _MAX_DRIVE 3 -#define _MAX_DIR 256 -#define _MAX_FNAME 256 -#define _MAX_EXT 256 - -#define _OUT_TO_DEFAULT 0 -#define _OUT_TO_STDERR 1 -#define _OUT_TO_MSGBOX 2 -#define _REPORT_ERRMODE 3 - -#define _WRITE_ABORT_MSG 0x1 -#define _CALL_REPORTFAULT 0x2 - -#define _MAX_ENV 32767 - - typedef void (__cdecl *_purecall_handler)(void); - - _CRTIMP _purecall_handler __cdecl _set_purecall_handler(_purecall_handler _Handler); - _CRTIMP _purecall_handler __cdecl _get_purecall_handler(void); - - typedef void (__cdecl *_invalid_parameter_handler)(const wchar_t *,const wchar_t *,const wchar_t *,unsigned int,uintptr_t); - _invalid_parameter_handler __cdecl _set_invalid_parameter_handler(_invalid_parameter_handler _Handler); - _invalid_parameter_handler __cdecl _get_invalid_parameter_handler(void); - -#ifndef _CRT_ERRNO_DEFINED -#define _CRT_ERRNO_DEFINED - _CRTIMP int *__cdecl _errno(void); -#define errno (*_errno()) - errno_t __cdecl _set_errno(int _Value); - errno_t __cdecl _get_errno(int *_Value); -#endif - _CRTIMP unsigned long *__cdecl __doserrno(void); -#define _doserrno (*__doserrno()) - errno_t __cdecl _set_doserrno(unsigned long _Value); - errno_t __cdecl _get_doserrno(unsigned long *_Value); -#ifdef _MSVCRT_ - extern char *_sys_errlist[]; - extern int _sys_nerr; -#else - _CRTIMP char *_sys_errlist[1]; - _CRTIMP int _sys_nerr; -#endif -#if (defined(_X86_) && !defined(__x86_64)) - _CRTIMP int *__cdecl __p___argc(void); - _CRTIMP char ***__cdecl __p___argv(void); - _CRTIMP wchar_t ***__cdecl __p___wargv(void); - _CRTIMP char ***__cdecl __p__environ(void); - _CRTIMP wchar_t ***__cdecl __p__wenviron(void); - _CRTIMP char **__cdecl __p__pgmptr(void); - _CRTIMP wchar_t **__cdecl __p__wpgmptr(void); -#endif -#ifndef __argc -#ifdef _MSVCRT_ - extern int __argc; -#else -#define __argc (*_imp____argc) - extern int *_imp____argc; -#endif -#endif -#ifndef __argv -#ifdef _MSVCRT_ - extern char **__argv; -#else -#define __argv (*_imp____argv) - extern char ***_imp____argv; -#endif -#endif -#ifndef __wargv -#ifdef _MSVCRT_ - extern wchar_t **__wargv; -#else -#define __wargv (*_imp____wargv) - extern wchar_t ***_imp____wargv; -#endif -#endif - -#ifdef _POSIX_ - extern char **environ; -#else -#ifndef _environ -#ifdef _MSVCRT_ - extern char **_environ; -#else -#define _environ (*_imp___environ) - extern char ***_imp___environ; -#endif -#endif - -#ifndef _wenviron -#ifdef _MSVCRT_ - extern wchar_t **_wenviron; -#else -#define _wenviron (*_imp___wenviron) - extern wchar_t ***_imp___wenviron; -#endif -#endif -#endif -#ifndef _pgmptr -#ifdef _MSVCRT_ - extern char *_pgmptr; -#else -#define _pgmptr (*_imp___pgmptr) - extern char **_imp___pgmptr; -#endif -#endif - -#ifndef _wpgmptr -#ifdef _MSVCRT_ - extern wchar_t *_wpgmptr; -#else -#define _wpgmptr (*_imp___wpgmptr) - extern wchar_t **_imp___wpgmptr; -#endif -#endif - errno_t __cdecl _get_pgmptr(char **_Value); - errno_t __cdecl _get_wpgmptr(wchar_t **_Value); -#ifndef _fmode -#ifdef _MSVCRT_ - extern int _fmode; -#else -#define _fmode (*_imp___fmode) - extern int *_imp___fmode; -#endif -#endif - _CRTIMP errno_t __cdecl _set_fmode(int _Mode); - _CRTIMP errno_t __cdecl _get_fmode(int *_PMode); - -#ifndef _osplatform -#ifdef _MSVCRT_ - extern unsigned int _osplatform; -#else -#define _osplatform (*_imp___osplatform) - extern unsigned int *_imp___osplatform; -#endif -#endif - -#ifndef _osver -#ifdef _MSVCRT_ - extern unsigned int _osver; -#else -#define _osver (*_imp___osver) - extern unsigned int *_imp___osver; -#endif -#endif - -#ifndef _winver -#ifdef _MSVCRT_ - extern unsigned int _winver; -#else -#define _winver (*_imp___winver) - extern unsigned int *_imp___winver; -#endif -#endif - -#ifndef _winmajor -#ifdef _MSVCRT_ - extern unsigned int _winmajor; -#else -#define _winmajor (*_imp___winmajor) - extern unsigned int *_imp___winmajor; -#endif -#endif - -#ifndef _winminor -#ifdef _MSVCRT_ - extern unsigned int _winminor; -#else -#define _winminor (*_imp___winminor) - extern unsigned int *_imp___winminor; -#endif -#endif - - errno_t __cdecl _get_osplatform(unsigned int *_Value); - errno_t __cdecl _get_osver(unsigned int *_Value); - errno_t __cdecl _get_winver(unsigned int *_Value); - errno_t __cdecl _get_winmajor(unsigned int *_Value); - errno_t __cdecl _get_winminor(unsigned int *_Value); -#ifndef _countof -#ifndef __cplusplus -#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) -#else - extern "C++" { - template char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray]; -#define _countof(_Array) sizeof(*__countof_helper(_Array)) - } -#endif -#endif - -#ifndef _CRT_TERMINATE_DEFINED -#define _CRT_TERMINATE_DEFINED - void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; - _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; -#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ - /* C99 function name */ - void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; - __CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) - { _exit(status); } -#endif - -#pragma push_macro("abort") -#undef abort - void __cdecl __declspec(noreturn) abort(void); -#pragma pop_macro("abort") - -#endif - - _CRTIMP unsigned int __cdecl _set_abort_behavior(unsigned int _Flags,unsigned int _Mask); - -#ifndef _CRT_ABS_DEFINED -#define _CRT_ABS_DEFINED - int __cdecl abs(int _X); - long __cdecl labs(long _X); -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - __int64 __cdecl _abs64(__int64); -#endif - int __cdecl atexit(void (__cdecl *)(void)); -#ifndef _CRT_ATOF_DEFINED -#define _CRT_ATOF_DEFINED - double __cdecl atof(const char *_String); - double __cdecl _atof_l(const char *_String,_locale_t _Locale); -#endif - int __cdecl atoi(const char *_Str); - _CRTIMP int __cdecl _atoi_l(const char *_Str,_locale_t _Locale); - long __cdecl atol(const char *_Str); - _CRTIMP long __cdecl _atol_l(const char *_Str,_locale_t _Locale); -#ifndef _CRT_ALGO_DEFINED -#define _CRT_ALGO_DEFINED - void *__cdecl bsearch(const void *_Key,const void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); - void __cdecl qsort(void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); -#endif - unsigned short __cdecl _byteswap_ushort(unsigned short _Short); - /*unsigned long __cdecl _byteswap_ulong (unsigned long _Long); */ -#if _INTEGRAL_MAX_BITS >= 64 - unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64 _Int64); -#endif - div_t __cdecl div(int _Numerator,int _Denominator); - char *__cdecl getenv(const char *_VarName); - _CRTIMP char *__cdecl _itoa(int _Value,char *_Dest,int _Radix); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP char *__cdecl _i64toa(__int64 _Val,char *_DstBuf,int _Radix); - _CRTIMP char *__cdecl _ui64toa(unsigned __int64 _Val,char *_DstBuf,int _Radix); - _CRTIMP __int64 __cdecl _atoi64(const char *_String); - _CRTIMP __int64 __cdecl _atoi64_l(const char *_String,_locale_t _Locale); - _CRTIMP __int64 __cdecl _strtoi64(const char *_String,char **_EndPtr,int _Radix); - _CRTIMP __int64 __cdecl _strtoi64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP unsigned __int64 __cdecl _strtoui64(const char *_String,char **_EndPtr,int _Radix); - _CRTIMP unsigned __int64 __cdecl _strtoui64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); -#endif - ldiv_t __cdecl ldiv(long _Numerator,long _Denominator); - _CRTIMP char *__cdecl _ltoa(long _Value,char *_Dest,int _Radix); - int __cdecl mblen(const char *_Ch,size_t _MaxCount); - _CRTIMP int __cdecl _mblen_l(const char *_Ch,size_t _MaxCount,_locale_t _Locale); - _CRTIMP size_t __cdecl _mbstrlen(const char *_Str); - _CRTIMP size_t __cdecl _mbstrlen_l(const char *_Str,_locale_t _Locale); - _CRTIMP size_t __cdecl _mbstrnlen(const char *_Str,size_t _MaxCount); - _CRTIMP size_t __cdecl _mbstrnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); - int __cdecl mbtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes); - _CRTIMP int __cdecl _mbtowc_l(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes,_locale_t _Locale); - size_t __cdecl mbstowcs(wchar_t *_Dest,const char *_Source,size_t _MaxCount); - _CRTIMP size_t __cdecl _mbstowcs_l(wchar_t *_Dest,const char *_Source,size_t _MaxCount,_locale_t _Locale); - int __cdecl rand(void); - _CRTIMP int __cdecl _set_error_mode(int _Mode); - void __cdecl srand(unsigned int _Seed); - double __cdecl strtod(const char *_Str,char **_EndPtr); - float __cdecl strtof(const char *nptr, char **endptr); -#if !defined __NO_ISOCEXT /* in libmingwex.a */ - float __cdecl strtof (const char * __restrict__, char ** __restrict__); - long double __cdecl strtold(const char * __restrict__, char ** __restrict__); -#endif /* __NO_ISOCEXT */ - _CRTIMP double __cdecl _strtod_l(const char *_Str,char **_EndPtr,_locale_t _Locale); - long __cdecl strtol(const char *_Str,char **_EndPtr,int _Radix); - _CRTIMP long __cdecl _strtol_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); - unsigned long __cdecl strtoul(const char *_Str,char **_EndPtr,int _Radix); - _CRTIMP unsigned long __cdecl _strtoul_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); -#ifndef _CRT_SYSTEM_DEFINED -#define _CRT_SYSTEM_DEFINED - int __cdecl system(const char *_Command); -#endif - _CRTIMP char *__cdecl _ultoa(unsigned long _Value,char *_Dest,int _Radix); - int __cdecl wctomb(char *_MbCh,wchar_t _WCh); - _CRTIMP int __cdecl _wctomb_l(char *_MbCh,wchar_t _WCh,_locale_t _Locale); - size_t __cdecl wcstombs(char *_Dest,const wchar_t *_Source,size_t _MaxCount); - _CRTIMP size_t __cdecl _wcstombs_l(char *_Dest,const wchar_t *_Source,size_t _MaxCount,_locale_t _Locale); - -#ifndef _CRT_ALLOCATION_DEFINED -#define _CRT_ALLOCATION_DEFINED - void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); - void __cdecl free(void *_Memory); - void *__cdecl malloc(size_t _Size); - void *__cdecl realloc(void *_Memory,size_t _NewSize); - _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); - //_CRTIMP void __cdecl _aligned_free(void *_Memory); - //_CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); -#endif - -#ifndef _WSTDLIB_DEFINED -#define _WSTDLIB_DEFINED - - _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); - double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); - float __cdecl wcstof(const wchar_t *nptr, wchar_t **endptr); -#if !defined __NO_ISOCEXT /* in libmingwex.a */ - float __cdecl wcstof( const wchar_t * __restrict__, wchar_t ** __restrict__); - long double __cdecl wcstold(const wchar_t * __restrict__, wchar_t ** __restrict__); -#endif /* __NO_ISOCEXT */ - _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); - long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif - _CRTIMP double __cdecl _wtof(const wchar_t *_Str); - _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); - _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP long __cdecl _wtol(const wchar_t *_Str); - _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); - _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str ,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); -#endif -#endif - -#ifndef _POSIX_ -#define _CVTBUFSIZE (309+40) - _CRTIMP char *__cdecl _fullpath(char *_FullPath,const char *_Path,size_t _SizeInBytes); - _CRTIMP char *__cdecl _ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); - _CRTIMP char *__cdecl _fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); - _CRTIMP char *__cdecl _gcvt(double _Val,int _NumOfDigits,char *_DstBuf); - _CRTIMP int __cdecl _atodbl(_CRT_DOUBLE *_Result,char *_Str); - _CRTIMP int __cdecl _atoldbl(_LDOUBLE *_Result,char *_Str); - _CRTIMP int __cdecl _atoflt(_CRT_FLOAT *_Result,char *_Str); - _CRTIMP int __cdecl _atodbl_l(_CRT_DOUBLE *_Result,char *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _atoldbl_l(_LDOUBLE *_Result,char *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _atoflt_l(_CRT_FLOAT *_Result,char *_Str,_locale_t _Locale); - unsigned long __cdecl _lrotl(unsigned long _Val,int _Shift); - unsigned long __cdecl _lrotr(unsigned long _Val,int _Shift); - _CRTIMP void __cdecl _makepath(char *_Path,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); - _onexit_t __cdecl _onexit(_onexit_t _Func); - -#ifndef _CRT_PERROR_DEFINED -#define _CRT_PERROR_DEFINED - void __cdecl perror(const char *_ErrMsg); -#endif - _CRTIMP int __cdecl _putenv(const char *_EnvString); - unsigned int __cdecl _rotl(unsigned int _Val,int _Shift); -#if _INTEGRAL_MAX_BITS >= 64 - unsigned __int64 __cdecl _rotl64(unsigned __int64 _Val,int _Shift); -#endif - unsigned int __cdecl _rotr(unsigned int _Val,int _Shift); -#if _INTEGRAL_MAX_BITS >= 64 - unsigned __int64 __cdecl _rotr64(unsigned __int64 _Val,int _Shift); -#endif - _CRTIMP void __cdecl _searchenv(const char *_Filename,const char *_EnvVar,char *_ResultPath); - _CRTIMP void __cdecl _splitpath(const char *_FullPath,char *_Drive,char *_Dir,char *_Filename,char *_Ext); - _CRTIMP void __cdecl _swab(char *_Buf1,char *_Buf2,int _SizeInBytes); - -#ifndef _WSTDLIBP_DEFINED -#define _WSTDLIBP_DEFINED - _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); - _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); - _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); - _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); -#endif - - _CRTIMP void __cdecl _beep(unsigned _Frequency,unsigned _Duration) __MINGW_ATTRIB_DEPRECATED; - /* Not to be confused with _set_error_mode (int). */ - _CRTIMP void __cdecl _seterrormode(int _Mode) __MINGW_ATTRIB_DEPRECATED; - _CRTIMP void __cdecl _sleep(unsigned long _Duration) __MINGW_ATTRIB_DEPRECATED; -#endif - -#ifndef NO_OLDNAMES -#ifndef _POSIX_ -#if 0 -#ifndef __cplusplus -#ifndef NOMINMAX -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#endif -#endif -#endif - -#define sys_errlist _sys_errlist -#define sys_nerr _sys_nerr -#define environ _environ - char *__cdecl ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); - char *__cdecl fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); - char *__cdecl gcvt(double _Val,int _NumOfDigits,char *_DstBuf); - char *__cdecl itoa(int _Val,char *_DstBuf,int _Radix); - char *__cdecl ltoa(long _Val,char *_DstBuf,int _Radix); - int __cdecl putenv(const char *_EnvString); - void __cdecl swab(char *_Buf1,char *_Buf2,int _SizeInBytes); - char *__cdecl ultoa(unsigned long _Val,char *_Dstbuf,int _Radix); - onexit_t __cdecl onexit(onexit_t _Func); -#endif -#endif - -#if !defined __NO_ISOCEXT /* externs in static libmingwex.a */ - - typedef struct { long long quot, rem; } lldiv_t; - - lldiv_t __cdecl lldiv(long long, long long); - - __CRT_INLINE long long __cdecl llabs(long long _j) { return (_j >= 0 ? _j : -_j); } - - long long __cdecl strtoll(const char* __restrict__, char** __restrict, int); - unsigned long long __cdecl strtoull(const char* __restrict__, char** __restrict__, int); - - /* these are stubs for MS _i64 versions */ - long long __cdecl atoll (const char *); - -#ifndef __STRICT_ANSI__ - long long __cdecl wtoll (const wchar_t *); - char *__cdecl lltoa (long long, char *, int); - char *__cdecl ulltoa (unsigned long long , char *, int); - wchar_t *__cdecl lltow (long long, wchar_t *, int); - wchar_t *__cdecl ulltow (unsigned long long, wchar_t *, int); - - /* __CRT_INLINE using non-ansi functions */ - __CRT_INLINE long long __cdecl atoll (const char * _c) { return _atoi64 (_c); } - __CRT_INLINE char *__cdecl lltoa (long long _n, char * _c, int _i) { return _i64toa (_n, _c, _i); } - __CRT_INLINE char *__cdecl ulltoa (unsigned long long _n, char * _c, int _i) { return _ui64toa (_n, _c, _i); } - __CRT_INLINE long long __cdecl wtoll (const wchar_t * _w) { return _wtoi64 (_w); } - __CRT_INLINE wchar_t *__cdecl lltow (long long _n, wchar_t * _w, int _i) { return _i64tow (_n, _w, _i); } - __CRT_INLINE wchar_t *__cdecl ulltow (unsigned long long _n, wchar_t * _w, int _i) { return _ui64tow (_n, _w, _i); } -#endif /* (__STRICT_ANSI__) */ - -#endif /* !__NO_ISOCEXT */ - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include -#include - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDLIB +#define _INC_STDLIB + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#ifndef _ONEXIT_T_DEFINED +#define _ONEXIT_T_DEFINED + + typedef int (__cdecl *_onexit_t)(void); + +#ifndef NO_OLDNAMES +#define onexit_t _onexit_t +#endif +#endif + +#ifndef _DIV_T_DEFINED +#define _DIV_T_DEFINED + + typedef struct _div_t { + int quot; + int rem; + } div_t; + + typedef struct _ldiv_t { + long quot; + long rem; + } ldiv_t; +#endif + +#ifndef _CRT_DOUBLE_DEC +#define _CRT_DOUBLE_DEC + +#pragma pack(4) + typedef struct { + unsigned char ld[10]; + } _LDOUBLE; +#pragma pack() + +#define _PTR_LD(x) ((unsigned char *)(&(x)->ld)) + + typedef struct { + double x; + } _CRT_DOUBLE; + + typedef struct { + float f; + } _CRT_FLOAT; + +#pragma push_macro("long") +#undef long + + typedef struct { + long double x; + } _LONGDOUBLE; + +#pragma pop_macro("long") + +#pragma pack(4) + typedef struct { + unsigned char ld12[12]; + } _LDBL12; +#pragma pack() +#endif + +#define RAND_MAX 0x7fff + +#ifndef MB_CUR_MAX +#define MB_CUR_MAX ___mb_cur_max_func() +#ifndef __mb_cur_max +#ifdef _MSVCRT_ + extern int __mb_cur_max; +#else +#define __mb_cur_max (*_imp____mb_cur_max) + extern int *_imp____mb_cur_max; +#endif +#endif +#ifdef _MSVCRT_ + extern int __mbcur_max; +#define ___mb_cur_max_func() (__mb_cur_max) +#else + extern int* _imp____mbcur_max; +#define ___mb_cur_max_func() (*_imp____mb_cur_max) +#endif +#endif + +#define __max(a,b) (((a) > (b)) ? (a) : (b)) +#define __min(a,b) (((a) < (b)) ? (a) : (b)) + +#define _MAX_PATH 260 +#define _MAX_DRIVE 3 +#define _MAX_DIR 256 +#define _MAX_FNAME 256 +#define _MAX_EXT 256 + +#define _OUT_TO_DEFAULT 0 +#define _OUT_TO_STDERR 1 +#define _OUT_TO_MSGBOX 2 +#define _REPORT_ERRMODE 3 + +#define _WRITE_ABORT_MSG 0x1 +#define _CALL_REPORTFAULT 0x2 + +#define _MAX_ENV 32767 + + typedef void (__cdecl *_purecall_handler)(void); + + _CRTIMP _purecall_handler __cdecl _set_purecall_handler(_purecall_handler _Handler); + _CRTIMP _purecall_handler __cdecl _get_purecall_handler(void); + + typedef void (__cdecl *_invalid_parameter_handler)(const wchar_t *,const wchar_t *,const wchar_t *,unsigned int,uintptr_t); + _invalid_parameter_handler __cdecl _set_invalid_parameter_handler(_invalid_parameter_handler _Handler); + _invalid_parameter_handler __cdecl _get_invalid_parameter_handler(void); + +#ifndef _CRT_ERRNO_DEFINED +#define _CRT_ERRNO_DEFINED + _CRTIMP int *__cdecl _errno(void); +#define errno (*_errno()) + errno_t __cdecl _set_errno(int _Value); + errno_t __cdecl _get_errno(int *_Value); +#endif + _CRTIMP unsigned long *__cdecl __doserrno(void); +#define _doserrno (*__doserrno()) + errno_t __cdecl _set_doserrno(unsigned long _Value); + errno_t __cdecl _get_doserrno(unsigned long *_Value); +#ifdef _MSVCRT_ + extern char *_sys_errlist[]; + extern int _sys_nerr; +#else + _CRTIMP char *_sys_errlist[1]; + _CRTIMP int _sys_nerr; +#endif +#if (defined(_X86_) && !defined(__x86_64)) + _CRTIMP int *__cdecl __p___argc(void); + _CRTIMP char ***__cdecl __p___argv(void); + _CRTIMP wchar_t ***__cdecl __p___wargv(void); + _CRTIMP char ***__cdecl __p__environ(void); + _CRTIMP wchar_t ***__cdecl __p__wenviron(void); + _CRTIMP char **__cdecl __p__pgmptr(void); + _CRTIMP wchar_t **__cdecl __p__wpgmptr(void); +#endif +#ifndef __argc +#ifdef _MSVCRT_ + extern int __argc; +#else +#define __argc (*_imp____argc) + extern int *_imp____argc; +#endif +#endif +#ifndef __argv +#ifdef _MSVCRT_ + extern char **__argv; +#else +#define __argv (*_imp____argv) + extern char ***_imp____argv; +#endif +#endif +#ifndef __wargv +#ifdef _MSVCRT_ + extern wchar_t **__wargv; +#else +#define __wargv (*_imp____wargv) + extern wchar_t ***_imp____wargv; +#endif +#endif + +#ifdef _POSIX_ + extern char **environ; +#else +#ifndef _environ +#ifdef _MSVCRT_ + extern char **_environ; +#else +#define _environ (*_imp___environ) + extern char ***_imp___environ; +#endif +#endif + +#ifndef _wenviron +#ifdef _MSVCRT_ + extern wchar_t **_wenviron; +#else +#define _wenviron (*_imp___wenviron) + extern wchar_t ***_imp___wenviron; +#endif +#endif +#endif +#ifndef _pgmptr +#ifdef _MSVCRT_ + extern char *_pgmptr; +#else +#define _pgmptr (*_imp___pgmptr) + extern char **_imp___pgmptr; +#endif +#endif + +#ifndef _wpgmptr +#ifdef _MSVCRT_ + extern wchar_t *_wpgmptr; +#else +#define _wpgmptr (*_imp___wpgmptr) + extern wchar_t **_imp___wpgmptr; +#endif +#endif + errno_t __cdecl _get_pgmptr(char **_Value); + errno_t __cdecl _get_wpgmptr(wchar_t **_Value); +#ifndef _fmode +#ifdef _MSVCRT_ + extern int _fmode; +#else +#define _fmode (*_imp___fmode) + extern int *_imp___fmode; +#endif +#endif + _CRTIMP errno_t __cdecl _set_fmode(int _Mode); + _CRTIMP errno_t __cdecl _get_fmode(int *_PMode); + +#ifndef _osplatform +#ifdef _MSVCRT_ + extern unsigned int _osplatform; +#else +#define _osplatform (*_imp___osplatform) + extern unsigned int *_imp___osplatform; +#endif +#endif + +#ifndef _osver +#ifdef _MSVCRT_ + extern unsigned int _osver; +#else +#define _osver (*_imp___osver) + extern unsigned int *_imp___osver; +#endif +#endif + +#ifndef _winver +#ifdef _MSVCRT_ + extern unsigned int _winver; +#else +#define _winver (*_imp___winver) + extern unsigned int *_imp___winver; +#endif +#endif + +#ifndef _winmajor +#ifdef _MSVCRT_ + extern unsigned int _winmajor; +#else +#define _winmajor (*_imp___winmajor) + extern unsigned int *_imp___winmajor; +#endif +#endif + +#ifndef _winminor +#ifdef _MSVCRT_ + extern unsigned int _winminor; +#else +#define _winminor (*_imp___winminor) + extern unsigned int *_imp___winminor; +#endif +#endif + + errno_t __cdecl _get_osplatform(unsigned int *_Value); + errno_t __cdecl _get_osver(unsigned int *_Value); + errno_t __cdecl _get_winver(unsigned int *_Value); + errno_t __cdecl _get_winmajor(unsigned int *_Value); + errno_t __cdecl _get_winminor(unsigned int *_Value); +#ifndef _countof +#ifndef __cplusplus +#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) +#else + extern "C++" { + template char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray]; +#define _countof(_Array) sizeof(*__countof_helper(_Array)) + } +#endif +#endif + +#ifndef _CRT_TERMINATE_DEFINED +#define _CRT_TERMINATE_DEFINED + void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; + _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; +#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ + /* C99 function name */ + void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; + __CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) + { _exit(status); } +#endif + +#pragma push_macro("abort") +#undef abort + void __cdecl __declspec(noreturn) abort(void); +#pragma pop_macro("abort") + +#endif + + _CRTIMP unsigned int __cdecl _set_abort_behavior(unsigned int _Flags,unsigned int _Mask); + +#ifndef _CRT_ABS_DEFINED +#define _CRT_ABS_DEFINED + int __cdecl abs(int _X); + long __cdecl labs(long _X); +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + __int64 __cdecl _abs64(__int64); +#endif + int __cdecl atexit(void (__cdecl *)(void)); +#ifndef _CRT_ATOF_DEFINED +#define _CRT_ATOF_DEFINED + double __cdecl atof(const char *_String); + double __cdecl _atof_l(const char *_String,_locale_t _Locale); +#endif + int __cdecl atoi(const char *_Str); + _CRTIMP int __cdecl _atoi_l(const char *_Str,_locale_t _Locale); + long __cdecl atol(const char *_Str); + _CRTIMP long __cdecl _atol_l(const char *_Str,_locale_t _Locale); +#ifndef _CRT_ALGO_DEFINED +#define _CRT_ALGO_DEFINED + void *__cdecl bsearch(const void *_Key,const void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); + void __cdecl qsort(void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); +#endif + unsigned short __cdecl _byteswap_ushort(unsigned short _Short); + /*unsigned long __cdecl _byteswap_ulong (unsigned long _Long); */ +#if _INTEGRAL_MAX_BITS >= 64 + unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64 _Int64); +#endif + div_t __cdecl div(int _Numerator,int _Denominator); + char *__cdecl getenv(const char *_VarName); + _CRTIMP char *__cdecl _itoa(int _Value,char *_Dest,int _Radix); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP char *__cdecl _i64toa(__int64 _Val,char *_DstBuf,int _Radix); + _CRTIMP char *__cdecl _ui64toa(unsigned __int64 _Val,char *_DstBuf,int _Radix); + _CRTIMP __int64 __cdecl _atoi64(const char *_String); + _CRTIMP __int64 __cdecl _atoi64_l(const char *_String,_locale_t _Locale); + _CRTIMP __int64 __cdecl _strtoi64(const char *_String,char **_EndPtr,int _Radix); + _CRTIMP __int64 __cdecl _strtoi64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP unsigned __int64 __cdecl _strtoui64(const char *_String,char **_EndPtr,int _Radix); + _CRTIMP unsigned __int64 __cdecl _strtoui64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); +#endif + ldiv_t __cdecl ldiv(long _Numerator,long _Denominator); + _CRTIMP char *__cdecl _ltoa(long _Value,char *_Dest,int _Radix); + int __cdecl mblen(const char *_Ch,size_t _MaxCount); + _CRTIMP int __cdecl _mblen_l(const char *_Ch,size_t _MaxCount,_locale_t _Locale); + _CRTIMP size_t __cdecl _mbstrlen(const char *_Str); + _CRTIMP size_t __cdecl _mbstrlen_l(const char *_Str,_locale_t _Locale); + _CRTIMP size_t __cdecl _mbstrnlen(const char *_Str,size_t _MaxCount); + _CRTIMP size_t __cdecl _mbstrnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); + int __cdecl mbtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes); + _CRTIMP int __cdecl _mbtowc_l(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes,_locale_t _Locale); + size_t __cdecl mbstowcs(wchar_t *_Dest,const char *_Source,size_t _MaxCount); + _CRTIMP size_t __cdecl _mbstowcs_l(wchar_t *_Dest,const char *_Source,size_t _MaxCount,_locale_t _Locale); + int __cdecl rand(void); + _CRTIMP int __cdecl _set_error_mode(int _Mode); + void __cdecl srand(unsigned int _Seed); + double __cdecl strtod(const char *_Str,char **_EndPtr); + float __cdecl strtof(const char *nptr, char **endptr); +#if !defined __NO_ISOCEXT /* in libmingwex.a */ + float __cdecl strtof (const char * __restrict__, char ** __restrict__); + long double __cdecl strtold(const char * __restrict__, char ** __restrict__); +#endif /* __NO_ISOCEXT */ + _CRTIMP double __cdecl _strtod_l(const char *_Str,char **_EndPtr,_locale_t _Locale); + long __cdecl strtol(const char *_Str,char **_EndPtr,int _Radix); + _CRTIMP long __cdecl _strtol_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); + unsigned long __cdecl strtoul(const char *_Str,char **_EndPtr,int _Radix); + _CRTIMP unsigned long __cdecl _strtoul_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); +#ifndef _CRT_SYSTEM_DEFINED +#define _CRT_SYSTEM_DEFINED + int __cdecl system(const char *_Command); +#endif + _CRTIMP char *__cdecl _ultoa(unsigned long _Value,char *_Dest,int _Radix); + int __cdecl wctomb(char *_MbCh,wchar_t _WCh); + _CRTIMP int __cdecl _wctomb_l(char *_MbCh,wchar_t _WCh,_locale_t _Locale); + size_t __cdecl wcstombs(char *_Dest,const wchar_t *_Source,size_t _MaxCount); + _CRTIMP size_t __cdecl _wcstombs_l(char *_Dest,const wchar_t *_Source,size_t _MaxCount,_locale_t _Locale); + +#ifndef _CRT_ALLOCATION_DEFINED +#define _CRT_ALLOCATION_DEFINED + void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); + void __cdecl free(void *_Memory); + void *__cdecl malloc(size_t _Size); + void *__cdecl realloc(void *_Memory,size_t _NewSize); + _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); + //_CRTIMP void __cdecl _aligned_free(void *_Memory); + //_CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); +#endif + +#ifndef _WSTDLIB_DEFINED +#define _WSTDLIB_DEFINED + + _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); + double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); + float __cdecl wcstof(const wchar_t *nptr, wchar_t **endptr); +#if !defined __NO_ISOCEXT /* in libmingwex.a */ + float __cdecl wcstof( const wchar_t * __restrict__, wchar_t ** __restrict__); + long double __cdecl wcstold(const wchar_t * __restrict__, wchar_t ** __restrict__); +#endif /* __NO_ISOCEXT */ + _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); + long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif + _CRTIMP double __cdecl _wtof(const wchar_t *_Str); + _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); + _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP long __cdecl _wtol(const wchar_t *_Str); + _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); + _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str ,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); +#endif +#endif + +#ifndef _POSIX_ +#define _CVTBUFSIZE (309+40) + _CRTIMP char *__cdecl _fullpath(char *_FullPath,const char *_Path,size_t _SizeInBytes); + _CRTIMP char *__cdecl _ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); + _CRTIMP char *__cdecl _fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); + _CRTIMP char *__cdecl _gcvt(double _Val,int _NumOfDigits,char *_DstBuf); + _CRTIMP int __cdecl _atodbl(_CRT_DOUBLE *_Result,char *_Str); + _CRTIMP int __cdecl _atoldbl(_LDOUBLE *_Result,char *_Str); + _CRTIMP int __cdecl _atoflt(_CRT_FLOAT *_Result,char *_Str); + _CRTIMP int __cdecl _atodbl_l(_CRT_DOUBLE *_Result,char *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _atoldbl_l(_LDOUBLE *_Result,char *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _atoflt_l(_CRT_FLOAT *_Result,char *_Str,_locale_t _Locale); + unsigned long __cdecl _lrotl(unsigned long _Val,int _Shift); + unsigned long __cdecl _lrotr(unsigned long _Val,int _Shift); + _CRTIMP void __cdecl _makepath(char *_Path,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); + _onexit_t __cdecl _onexit(_onexit_t _Func); + +#ifndef _CRT_PERROR_DEFINED +#define _CRT_PERROR_DEFINED + void __cdecl perror(const char *_ErrMsg); +#endif + _CRTIMP int __cdecl _putenv(const char *_EnvString); + unsigned int __cdecl _rotl(unsigned int _Val,int _Shift); +#if _INTEGRAL_MAX_BITS >= 64 + unsigned __int64 __cdecl _rotl64(unsigned __int64 _Val,int _Shift); +#endif + unsigned int __cdecl _rotr(unsigned int _Val,int _Shift); +#if _INTEGRAL_MAX_BITS >= 64 + unsigned __int64 __cdecl _rotr64(unsigned __int64 _Val,int _Shift); +#endif + _CRTIMP void __cdecl _searchenv(const char *_Filename,const char *_EnvVar,char *_ResultPath); + _CRTIMP void __cdecl _splitpath(const char *_FullPath,char *_Drive,char *_Dir,char *_Filename,char *_Ext); + _CRTIMP void __cdecl _swab(char *_Buf1,char *_Buf2,int _SizeInBytes); + +#ifndef _WSTDLIBP_DEFINED +#define _WSTDLIBP_DEFINED + _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); + _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); + _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); + _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); +#endif + + _CRTIMP void __cdecl _beep(unsigned _Frequency,unsigned _Duration) __MINGW_ATTRIB_DEPRECATED; + /* Not to be confused with _set_error_mode (int). */ + _CRTIMP void __cdecl _seterrormode(int _Mode) __MINGW_ATTRIB_DEPRECATED; + _CRTIMP void __cdecl _sleep(unsigned long _Duration) __MINGW_ATTRIB_DEPRECATED; +#endif + +#ifndef NO_OLDNAMES +#ifndef _POSIX_ +#if 0 +#ifndef __cplusplus +#ifndef NOMINMAX +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#endif +#endif +#endif + +#define sys_errlist _sys_errlist +#define sys_nerr _sys_nerr +#define environ _environ + char *__cdecl ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); + char *__cdecl fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); + char *__cdecl gcvt(double _Val,int _NumOfDigits,char *_DstBuf); + char *__cdecl itoa(int _Val,char *_DstBuf,int _Radix); + char *__cdecl ltoa(long _Val,char *_DstBuf,int _Radix); + int __cdecl putenv(const char *_EnvString); + void __cdecl swab(char *_Buf1,char *_Buf2,int _SizeInBytes); + char *__cdecl ultoa(unsigned long _Val,char *_Dstbuf,int _Radix); + onexit_t __cdecl onexit(onexit_t _Func); +#endif +#endif + +#if !defined __NO_ISOCEXT /* externs in static libmingwex.a */ + + typedef struct { long long quot, rem; } lldiv_t; + + lldiv_t __cdecl lldiv(long long, long long); + + __CRT_INLINE long long __cdecl llabs(long long _j) { return (_j >= 0 ? _j : -_j); } + + long long __cdecl strtoll(const char* __restrict__, char** __restrict, int); + unsigned long long __cdecl strtoull(const char* __restrict__, char** __restrict__, int); + + /* these are stubs for MS _i64 versions */ + long long __cdecl atoll (const char *); + +#ifndef __STRICT_ANSI__ + long long __cdecl wtoll (const wchar_t *); + char *__cdecl lltoa (long long, char *, int); + char *__cdecl ulltoa (unsigned long long , char *, int); + wchar_t *__cdecl lltow (long long, wchar_t *, int); + wchar_t *__cdecl ulltow (unsigned long long, wchar_t *, int); + + /* __CRT_INLINE using non-ansi functions */ + __CRT_INLINE long long __cdecl atoll (const char * _c) { return _atoi64 (_c); } + __CRT_INLINE char *__cdecl lltoa (long long _n, char * _c, int _i) { return _i64toa (_n, _c, _i); } + __CRT_INLINE char *__cdecl ulltoa (unsigned long long _n, char * _c, int _i) { return _ui64toa (_n, _c, _i); } + __CRT_INLINE long long __cdecl wtoll (const wchar_t * _w) { return _wtoi64 (_w); } + __CRT_INLINE wchar_t *__cdecl lltow (long long _n, wchar_t * _w, int _i) { return _i64tow (_n, _w, _i); } + __CRT_INLINE wchar_t *__cdecl ulltow (unsigned long long _n, wchar_t * _w, int _i) { return _ui64tow (_n, _w, _i); } +#endif /* (__STRICT_ANSI__) */ + +#endif /* !__NO_ISOCEXT */ + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include +#include + +#endif diff --git a/tcc/include/stdnoreturn.h b/tcc/include/stdnoreturn.h index 4d580ea5..e71c9e1b 100644 --- a/tcc/include/stdnoreturn.h +++ b/tcc/include/stdnoreturn.h @@ -1,7 +1,7 @@ -#ifndef _STDNORETURN_H -#define _STDNORETURN_H - -/* ISOC11 noreturn */ -#define noreturn _Noreturn - -#endif /* _STDNORETURN_H */ +#ifndef _STDNORETURN_H +#define _STDNORETURN_H + +/* ISOC11 noreturn */ +#define noreturn _Noreturn + +#endif /* _STDNORETURN_H */ diff --git a/tcc/include/string.h b/tcc/include/string.h index 3249dc3b..288e12ba 100644 --- a/tcc/include/string.h +++ b/tcc/include/string.h @@ -1,164 +1,164 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STRING -#define _INC_STRING - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _NLSCMP_DEFINED -#define _NLSCMP_DEFINED -#define _NLSCMPERROR 2147483647 -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define _WConst_return _CONST_RETURN - -#ifndef _CRT_MEMORY_DEFINED -#define _CRT_MEMORY_DEFINED - _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); - _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); - _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); - _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); - int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); - void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); - void *__cdecl memset(void *_Dst,int _Val,size_t _Size); -#ifndef NO_OLDNAMES - void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); - int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); -#endif -#endif - char *__cdecl _strset(char *_Str,int _Val); - char *__cdecl strcpy(char *_Dest,const char *_Source); - char *__cdecl strcat(char *_Dest,const char *_Source); - int __cdecl strcmp(const char *_Str1,const char *_Str2); - size_t __cdecl strlen(const char *_Str); -#if 0 - size_t __cdecl strnlen(const char *_Str,size_t _MaxCount); -#endif - void *__cdecl memmove(void *_Dst,const void *_Src,size_t _Size); - _CRTIMP char *__cdecl _strdup(const char *_Src); - _CONST_RETURN char *__cdecl strchr(const char *_Str,int _Val); - _CRTIMP int __cdecl _stricmp(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _strcmpi(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _stricmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - int __cdecl strcoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _strcoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _stricoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _stricoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _strncoll (const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _strnicoll (const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - size_t __cdecl strcspn(const char *_Str,const char *_Control); - _CRTIMP char *__cdecl _strerror(const char *_ErrMsg); - char *__cdecl strerror(int); - _CRTIMP char *__cdecl _strlwr(char *_String); - char *strlwr_l(char *_String,_locale_t _Locale); - char *__cdecl strncat(char *_Dest,const char *_Source,size_t _Count); - int __cdecl strncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - char *strncpy(char *_Dest,const char *_Source,size_t _Count); - _CRTIMP char *__cdecl _strnset(char *_Str,int _Val,size_t _MaxCount); - _CONST_RETURN char *__cdecl strpbrk(const char *_Str,const char *_Control); - _CONST_RETURN char *__cdecl strrchr(const char *_Str,int _Ch); - _CRTIMP char *__cdecl _strrev(char *_Str); - size_t __cdecl strspn(const char *_Str,const char *_Control); - _CONST_RETURN char *__cdecl strstr(const char *_Str,const char *_SubStr); - char *__cdecl strtok(char *_Str,const char *_Delim); - _CRTIMP char *__cdecl _strupr(char *_String); - _CRTIMP char *_strupr_l(char *_String,_locale_t _Locale); - size_t __cdecl strxfrm(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP size_t __cdecl _strxfrm_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - -#ifndef NO_OLDNAMES - char *__cdecl strdup(const char *_Src); - int __cdecl strcmpi(const char *_Str1,const char *_Str2); - int __cdecl stricmp(const char *_Str1,const char *_Str2); - char *__cdecl strlwr(char *_Str); - int __cdecl strnicmp(const char *_Str1,const char *_Str,size_t _MaxCount); - __CRT_INLINE int __cdecl strncasecmp (const char *__sz1, const char *__sz2, size_t __sizeMaxCompare) { return _strnicmp (__sz1, __sz2, __sizeMaxCompare); } - __CRT_INLINE int __cdecl strcasecmp (const char *__sz1, const char *__sz2) { return _stricmp (__sz1, __sz2); } - char *__cdecl strnset(char *_Str,int _Val,size_t _MaxCount); - char *__cdecl strrev(char *_Str); - char *__cdecl strset(char *_Str,int _Val); - char *__cdecl strupr(char *_Str); -#endif - -#ifndef _WSTRING_DEFINED -#define _WSTRING_DEFINED - - _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); - wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); - _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); - int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); - wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); - size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); - size_t __cdecl wcslen(const wchar_t *_Str); - size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); - wchar_t *wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); - size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); - wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); - _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); - _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); - _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); - _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); - _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); - _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); - _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); - size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); - _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); - int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - -#ifndef NO_OLDNAMES - wchar_t *__cdecl wcsdup(const wchar_t *_Str); -#define wcswcs wcsstr - int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - wchar_t *__cdecl wcsrev(wchar_t *_Str); - wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); - wchar_t *__cdecl wcslwr(wchar_t *_Str); - wchar_t *__cdecl wcsupr(wchar_t *_Str); - int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STRING +#define _INC_STRING + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _NLSCMP_DEFINED +#define _NLSCMP_DEFINED +#define _NLSCMPERROR 2147483647 +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define _WConst_return _CONST_RETURN + +#ifndef _CRT_MEMORY_DEFINED +#define _CRT_MEMORY_DEFINED + _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); + _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); + _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); + _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); + int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); + void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); + void *__cdecl memset(void *_Dst,int _Val,size_t _Size); +#ifndef NO_OLDNAMES + void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); + int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); +#endif +#endif + char *__cdecl _strset(char *_Str,int _Val); + char *__cdecl strcpy(char *_Dest,const char *_Source); + char *__cdecl strcat(char *_Dest,const char *_Source); + int __cdecl strcmp(const char *_Str1,const char *_Str2); + size_t __cdecl strlen(const char *_Str); +#if 0 + size_t __cdecl strnlen(const char *_Str,size_t _MaxCount); +#endif + void *__cdecl memmove(void *_Dst,const void *_Src,size_t _Size); + _CRTIMP char *__cdecl _strdup(const char *_Src); + _CONST_RETURN char *__cdecl strchr(const char *_Str,int _Val); + _CRTIMP int __cdecl _stricmp(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _strcmpi(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _stricmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + int __cdecl strcoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _strcoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _stricoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _stricoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _strncoll (const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _strnicoll (const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + size_t __cdecl strcspn(const char *_Str,const char *_Control); + _CRTIMP char *__cdecl _strerror(const char *_ErrMsg); + char *__cdecl strerror(int); + _CRTIMP char *__cdecl _strlwr(char *_String); + char *strlwr_l(char *_String,_locale_t _Locale); + char *__cdecl strncat(char *_Dest,const char *_Source,size_t _Count); + int __cdecl strncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + char *strncpy(char *_Dest,const char *_Source,size_t _Count); + _CRTIMP char *__cdecl _strnset(char *_Str,int _Val,size_t _MaxCount); + _CONST_RETURN char *__cdecl strpbrk(const char *_Str,const char *_Control); + _CONST_RETURN char *__cdecl strrchr(const char *_Str,int _Ch); + _CRTIMP char *__cdecl _strrev(char *_Str); + size_t __cdecl strspn(const char *_Str,const char *_Control); + _CONST_RETURN char *__cdecl strstr(const char *_Str,const char *_SubStr); + char *__cdecl strtok(char *_Str,const char *_Delim); + _CRTIMP char *__cdecl _strupr(char *_String); + _CRTIMP char *_strupr_l(char *_String,_locale_t _Locale); + size_t __cdecl strxfrm(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP size_t __cdecl _strxfrm_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + +#ifndef NO_OLDNAMES + char *__cdecl strdup(const char *_Src); + int __cdecl strcmpi(const char *_Str1,const char *_Str2); + int __cdecl stricmp(const char *_Str1,const char *_Str2); + char *__cdecl strlwr(char *_Str); + int __cdecl strnicmp(const char *_Str1,const char *_Str,size_t _MaxCount); + __CRT_INLINE int __cdecl strncasecmp (const char *__sz1, const char *__sz2, size_t __sizeMaxCompare) { return _strnicmp (__sz1, __sz2, __sizeMaxCompare); } + __CRT_INLINE int __cdecl strcasecmp (const char *__sz1, const char *__sz2) { return _stricmp (__sz1, __sz2); } + char *__cdecl strnset(char *_Str,int _Val,size_t _MaxCount); + char *__cdecl strrev(char *_Str); + char *__cdecl strset(char *_Str,int _Val); + char *__cdecl strupr(char *_Str); +#endif + +#ifndef _WSTRING_DEFINED +#define _WSTRING_DEFINED + + _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); + wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); + _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); + int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); + wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); + size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); + size_t __cdecl wcslen(const wchar_t *_Str); + size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); + wchar_t *wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); + size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); + wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); + _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); + _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); + _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); + _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); + _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); + _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); + _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); + size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); + _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); + int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + +#ifndef NO_OLDNAMES + wchar_t *__cdecl wcsdup(const wchar_t *_Str); +#define wcswcs wcsstr + int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + wchar_t *__cdecl wcsrev(wchar_t *_Str); + wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); + wchar_t *__cdecl wcslwr(wchar_t *_Str); + wchar_t *__cdecl wcsupr(wchar_t *_Str); + int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#include +#endif diff --git a/tcc/include/sys/fcntl.h b/tcc/include/sys/fcntl.h index 29fd55a1..8456b824 100644 --- a/tcc/include/sys/fcntl.h +++ b/tcc/include/sys/fcntl.h @@ -1,13 +1,13 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * This fcntl.h maps to the root fcntl.h - */ -#ifndef __STRICT_ANSI__ -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * This fcntl.h maps to the root fcntl.h + */ +#ifndef __STRICT_ANSI__ +#include +#endif diff --git a/tcc/include/sys/file.h b/tcc/include/sys/file.h index 370f352d..70169f39 100644 --- a/tcc/include/sys/file.h +++ b/tcc/include/sys/file.h @@ -1,14 +1,14 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * This file.h maps to the root fcntl.h - * TODO? - */ -#ifndef __STRICT_ANSI__ -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * This file.h maps to the root fcntl.h + * TODO? + */ +#ifndef __STRICT_ANSI__ +#include +#endif diff --git a/tcc/include/sys/locking.h b/tcc/include/sys/locking.h index e3fc85b3..98d9acc4 100644 --- a/tcc/include/sys/locking.h +++ b/tcc/include/sys/locking.h @@ -1,30 +1,30 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_LOCKING -#define _INC_LOCKING - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -/* All the headers include this file. */ -#include <_mingw.h> - -#define _LK_UNLCK 0 -#define _LK_LOCK 1 -#define _LK_NBLCK 2 -#define _LK_RLCK 3 -#define _LK_NBRLCK 4 - -#ifndef NO_OLDNAMES -#define LK_UNLCK _LK_UNLCK -#define LK_LOCK _LK_LOCK -#define LK_NBLCK _LK_NBLCK -#define LK_RLCK _LK_RLCK -#define LK_NBRLCK _LK_NBRLCK -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_LOCKING +#define _INC_LOCKING + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +/* All the headers include this file. */ +#include <_mingw.h> + +#define _LK_UNLCK 0 +#define _LK_LOCK 1 +#define _LK_NBLCK 2 +#define _LK_RLCK 3 +#define _LK_NBRLCK 4 + +#ifndef NO_OLDNAMES +#define LK_UNLCK _LK_UNLCK +#define LK_LOCK _LK_LOCK +#define LK_NBLCK _LK_NBLCK +#define LK_RLCK _LK_RLCK +#define LK_NBRLCK _LK_NBRLCK +#endif + +#endif diff --git a/tcc/include/sys/stat.h b/tcc/include/sys/stat.h index 4a95e659..1d687dbd 100644 --- a/tcc/include/sys/stat.h +++ b/tcc/include/sys/stat.h @@ -1,290 +1,290 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STAT -#define _INC_STAT - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#include - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED - typedef long __time32_t; -#define _TIME32_T_DEFINED -#endif - -#ifndef _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 - typedef __int64 __time64_t; -#endif -#define _TIME64_T_DEFINED -#endif - -#ifndef _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#define _TIME_T_DEFINED -#endif - -#ifndef _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif - -#ifndef _STAT_DEFINED - -#ifdef _USE_32BIT_TIME_T -#ifndef _WIN64 -#define _fstat32 _fstat -#define _stat32 _stat -#define _wstat32 _wstat -#else -#define _fstat _fstat32 -#define _stat _stat32 -#define _wstat _wstat32 -#endif -#define _fstati64 _fstat32i64 -#define _stati64 _stat32i64 -#define _wstati64 _wstat32i64 -#else -#define _fstat _fstat64i32 -#define _fstati64 _fstat64 -#define _stat _stat64 -#define _stati64 _stat64 -#define _wstat _wstat64 -#define _wstati64 _wstat64 -#endif - - struct _stat32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - -#ifndef NO_OLDNAMES - struct stat { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; - }; -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - struct _stat32i64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - - struct _stat64i32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; - - struct _stat64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; -#endif - -#define __stat64 _stat64 - -#define _STAT_DEFINED -#endif - -#define _S_IFMT 0xF000 -#define _S_IFDIR 0x4000 -#define _S_IFCHR 0x2000 -#define _S_IFIFO 0x1000 -#define _S_IFREG 0x8000 -#define _S_IREAD 0x0100 -#define _S_IWRITE 0x0080 -#define _S_IEXEC 0x0040 - - _CRTIMP int __cdecl _fstat32(int _FileDes,struct _stat32 *_Stat); - _CRTIMP int __cdecl _stat32(const char *_Name,struct _stat32 *_Stat); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _fstat64(int _FileDes,struct _stat64 *_Stat); - _CRTIMP int __cdecl _fstat32i64(int _FileDes,struct _stat32i64 *_Stat); - int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat); - __CRT_INLINE int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat) - { - struct _stat64 st; - int ret=_fstat64(_FileDes,&st); - _Stat->st_dev=st.st_dev; - _Stat->st_ino=st.st_ino; - _Stat->st_mode=st.st_mode; - _Stat->st_nlink=st.st_nlink; - _Stat->st_uid=st.st_uid; - _Stat->st_gid=st.st_gid; - _Stat->st_rdev=st.st_rdev; - _Stat->st_size=(_off_t) st.st_size; - _Stat->st_atime=st.st_atime; - _Stat->st_mtime=st.st_mtime; - _Stat->st_ctime=st.st_ctime; - return ret; - } - _CRTIMP int __cdecl _stat64(const char *_Name,struct _stat64 *_Stat); - _CRTIMP int __cdecl _stat32i64(const char *_Name,struct _stat32i64 *_Stat); - int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat); - __CRT_INLINE int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat) - { - struct _stat64 st; - int ret=_stat64(_Name,&st); - _Stat->st_dev=st.st_dev; - _Stat->st_ino=st.st_ino; - _Stat->st_mode=st.st_mode; - _Stat->st_nlink=st.st_nlink; - _Stat->st_uid=st.st_uid; - _Stat->st_gid=st.st_gid; - _Stat->st_rdev=st.st_rdev; - _Stat->st_size=(_off_t) st.st_size; - _Stat->st_atime=st.st_atime; - _Stat->st_mtime=st.st_mtime; - _Stat->st_ctime=st.st_ctime; - return ret; - } -#endif - -#ifndef _WSTAT_DEFINED -#define _WSTAT_DEFINED - _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); - int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); - _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); -#endif -#endif - -#ifndef NO_OLDNAMES -#define _S_IFBLK 0x3000 /* Block: Is this ever set under w32? */ - -#define S_IFMT _S_IFMT -#define S_IFDIR _S_IFDIR -#define S_IFCHR _S_IFCHR -#define S_IFREG _S_IFREG -#define S_IREAD _S_IREAD -#define S_IWRITE _S_IWRITE -#define S_IEXEC _S_IEXEC -#define S_IFIFO _S_IFIFO -#define S_IFBLK _S_IFBLK - -#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) -#define _S_IXUSR _S_IEXEC -#define _S_IWUSR _S_IWRITE - -#define S_IRWXU _S_IRWXU -#define S_IXUSR _S_IXUSR -#define S_IWUSR _S_IWUSR -#define S_IRUSR _S_IRUSR -#define _S_IRUSR _S_IREAD - -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) - -#endif - -#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) -int __cdecl stat(const char *_Filename,struct stat *_Stat); -int __cdecl fstat(int _Desc,struct stat *_Stat); -int __cdecl wstat(const wchar_t *_Filename,struct stat *_Stat); -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { - return _fstat32(_Desc,(struct _stat32 *)_Stat); -} -__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { - return _stat32(_Filename,(struct _stat32 *)_Stat); -} -#else -__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { - return _fstat64i32(_Desc,(struct _stat64i32 *)_Stat); -} -__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { - return _stat64i32(_Filename,(struct _stat64i32 *)_Stat); -} -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STAT +#define _INC_STAT + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#include + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED + typedef long __time32_t; +#define _TIME32_T_DEFINED +#endif + +#ifndef _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 + typedef __int64 __time64_t; +#endif +#define _TIME64_T_DEFINED +#endif + +#ifndef _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#define _TIME_T_DEFINED +#endif + +#ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +#ifndef _STAT_DEFINED + +#ifdef _USE_32BIT_TIME_T +#ifndef _WIN64 +#define _fstat32 _fstat +#define _stat32 _stat +#define _wstat32 _wstat +#else +#define _fstat _fstat32 +#define _stat _stat32 +#define _wstat _wstat32 +#endif +#define _fstati64 _fstat32i64 +#define _stati64 _stat32i64 +#define _wstati64 _wstat32i64 +#else +#define _fstat _fstat64i32 +#define _fstati64 _fstat64 +#define _stat _stat64 +#define _stati64 _stat64 +#define _wstat _wstat64 +#define _wstati64 _wstat64 +#endif + + struct _stat32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + +#ifndef NO_OLDNAMES + struct stat { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + }; +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + struct _stat32i64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + + struct _stat64i32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; + + struct _stat64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; +#endif + +#define __stat64 _stat64 + +#define _STAT_DEFINED +#endif + +#define _S_IFMT 0xF000 +#define _S_IFDIR 0x4000 +#define _S_IFCHR 0x2000 +#define _S_IFIFO 0x1000 +#define _S_IFREG 0x8000 +#define _S_IREAD 0x0100 +#define _S_IWRITE 0x0080 +#define _S_IEXEC 0x0040 + + _CRTIMP int __cdecl _fstat32(int _FileDes,struct _stat32 *_Stat); + _CRTIMP int __cdecl _stat32(const char *_Name,struct _stat32 *_Stat); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _fstat64(int _FileDes,struct _stat64 *_Stat); + _CRTIMP int __cdecl _fstat32i64(int _FileDes,struct _stat32i64 *_Stat); + int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat); + __CRT_INLINE int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat) + { + struct _stat64 st; + int ret=_fstat64(_FileDes,&st); + _Stat->st_dev=st.st_dev; + _Stat->st_ino=st.st_ino; + _Stat->st_mode=st.st_mode; + _Stat->st_nlink=st.st_nlink; + _Stat->st_uid=st.st_uid; + _Stat->st_gid=st.st_gid; + _Stat->st_rdev=st.st_rdev; + _Stat->st_size=(_off_t) st.st_size; + _Stat->st_atime=st.st_atime; + _Stat->st_mtime=st.st_mtime; + _Stat->st_ctime=st.st_ctime; + return ret; + } + _CRTIMP int __cdecl _stat64(const char *_Name,struct _stat64 *_Stat); + _CRTIMP int __cdecl _stat32i64(const char *_Name,struct _stat32i64 *_Stat); + int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat); + __CRT_INLINE int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat) + { + struct _stat64 st; + int ret=_stat64(_Name,&st); + _Stat->st_dev=st.st_dev; + _Stat->st_ino=st.st_ino; + _Stat->st_mode=st.st_mode; + _Stat->st_nlink=st.st_nlink; + _Stat->st_uid=st.st_uid; + _Stat->st_gid=st.st_gid; + _Stat->st_rdev=st.st_rdev; + _Stat->st_size=(_off_t) st.st_size; + _Stat->st_atime=st.st_atime; + _Stat->st_mtime=st.st_mtime; + _Stat->st_ctime=st.st_ctime; + return ret; + } +#endif + +#ifndef _WSTAT_DEFINED +#define _WSTAT_DEFINED + _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); + int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); + _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); +#endif +#endif + +#ifndef NO_OLDNAMES +#define _S_IFBLK 0x3000 /* Block: Is this ever set under w32? */ + +#define S_IFMT _S_IFMT +#define S_IFDIR _S_IFDIR +#define S_IFCHR _S_IFCHR +#define S_IFREG _S_IFREG +#define S_IREAD _S_IREAD +#define S_IWRITE _S_IWRITE +#define S_IEXEC _S_IEXEC +#define S_IFIFO _S_IFIFO +#define S_IFBLK _S_IFBLK + +#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) +#define _S_IXUSR _S_IEXEC +#define _S_IWUSR _S_IWRITE + +#define S_IRWXU _S_IRWXU +#define S_IXUSR _S_IXUSR +#define S_IWUSR _S_IWUSR +#define S_IRUSR _S_IRUSR +#define _S_IRUSR _S_IREAD + +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) + +#endif + +#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) +int __cdecl stat(const char *_Filename,struct stat *_Stat); +int __cdecl fstat(int _Desc,struct stat *_Stat); +int __cdecl wstat(const wchar_t *_Filename,struct stat *_Stat); +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { + return _fstat32(_Desc,(struct _stat32 *)_Stat); +} +__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { + return _stat32(_Filename,(struct _stat32 *)_Stat); +} +#else +__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { + return _fstat64i32(_Desc,(struct _stat64i32 *)_Stat); +} +__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { + return _stat64i32(_Filename,(struct _stat64i32 *)_Stat); +} +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/sys/time.h b/tcc/include/sys/time.h index 8ccab831..af9be8f7 100644 --- a/tcc/include/sys/time.h +++ b/tcc/include/sys/time.h @@ -1,69 +1,69 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _SYS_TIME_H_ -#define _SYS_TIME_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __STRICT_ANSI__ -#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ -#define _TIMEVAL_DEFINED -struct timeval { - long tv_sec; - long tv_usec; -}; -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define timercmp(tvp, uvp, cmp) \ - (((tvp)->tv_sec != (uvp)->tv_sec) ? \ - ((tvp)->tv_sec cmp (uvp)->tv_sec) : \ - ((tvp)->tv_usec cmp (uvp)->tv_usec)) -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif /* _TIMEVAL_DEFINED */ - -#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ -#define _TIMEZONE_DEFINED -/* Provided for compatibility with code that assumes that - the presence of gettimeofday function implies a definition - of struct timezone. */ -struct timezone -{ - int tz_minuteswest; /* of Greenwich */ - int tz_dsttime; /* type of dst correction to apply */ -}; - - extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); - -#endif - -/* - Implementation as per: - The Open Group Base Specifications, Issue 6 - IEEE Std 1003.1, 2004 Edition - - The timezone pointer arg is ignored. Errors are ignored. -*/ -#ifndef _GETTIMEOFDAY_DEFINED -#define _GETTIMEOFDAY_DEFINED -int __cdecl gettimeofday(struct timeval *__restrict__, - void *__restrict__ /* tzp (unused) */); -#endif - -#endif /* __STRICT_ANSI__ */ - -#ifdef __cplusplus -} -#endif - -/* Adding timespec definition. */ -#include - - -#endif /* _SYS_TIME_H_ */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _SYS_TIME_H_ +#define _SYS_TIME_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __STRICT_ANSI__ +#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ +#define _TIMEVAL_DEFINED +struct timeval { + long tv_sec; + long tv_usec; +}; +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec != (uvp)->tv_sec) ? \ + ((tvp)->tv_sec cmp (uvp)->tv_sec) : \ + ((tvp)->tv_usec cmp (uvp)->tv_usec)) +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif /* _TIMEVAL_DEFINED */ + +#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ +#define _TIMEZONE_DEFINED +/* Provided for compatibility with code that assumes that + the presence of gettimeofday function implies a definition + of struct timezone. */ +struct timezone +{ + int tz_minuteswest; /* of Greenwich */ + int tz_dsttime; /* type of dst correction to apply */ +}; + + extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); + +#endif + +/* + Implementation as per: + The Open Group Base Specifications, Issue 6 + IEEE Std 1003.1, 2004 Edition + + The timezone pointer arg is ignored. Errors are ignored. +*/ +#ifndef _GETTIMEOFDAY_DEFINED +#define _GETTIMEOFDAY_DEFINED +int __cdecl gettimeofday(struct timeval *__restrict__, + void *__restrict__ /* tzp (unused) */); +#endif + +#endif /* __STRICT_ANSI__ */ + +#ifdef __cplusplus +} +#endif + +/* Adding timespec definition. */ +#include + + +#endif /* _SYS_TIME_H_ */ diff --git a/tcc/include/sys/timeb.h b/tcc/include/sys/timeb.h index 34837738..9fdb6965 100644 --- a/tcc/include/sys/timeb.h +++ b/tcc/include/sys/timeb.h @@ -1,133 +1,133 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _TIMEB_H_ -#define _TIMEB_H_ - -#include <_mingw.h> - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED - typedef long __time32_t; -#define _TIME32_T_DEFINED -#endif - -#ifndef _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 - typedef __int64 __time64_t; -#endif -#define _TIME64_T_DEFINED -#endif - -#ifndef _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#define _TIME_T_DEFINED -#endif - -#ifndef _TIMEB_DEFINED -#define _TIMEB_DEFINED - - struct __timeb32 { - __time32_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; - -#ifndef NO_OLDNAMES - struct timeb { - time_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - struct __timeb64 { - __time64_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; -#endif - -#ifdef _USE_32BIT_TIME_T -#define _timeb __timeb32 -//gr #define _ftime _ftime32 -#define _ftime32 _ftime -#else -#define _timeb __timeb64 -#define _ftime _ftime64 -#endif -#endif - - _CRTIMP void __cdecl _ftime32(struct __timeb32 *_Time); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP void __cdecl _ftime64(struct __timeb64 *_Time); -#endif - -#ifndef _TIMESPEC_DEFINED -#define _TIMESPEC_DEFINED -struct timespec { - time_t tv_sec; /* Seconds */ - long tv_nsec; /* Nanoseconds */ -}; - -struct itimerspec { - struct timespec it_interval; /* Timer period */ - struct timespec it_value; /* Timer expiration */ -}; -#endif - -#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { - _ftime32((struct __timeb32 *)_Tmb); -} -#else -__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { - _ftime64((struct __timeb64 *)_Tmb); -} -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _TIMEB_H_ +#define _TIMEB_H_ + +#include <_mingw.h> + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED + typedef long __time32_t; +#define _TIME32_T_DEFINED +#endif + +#ifndef _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 + typedef __int64 __time64_t; +#endif +#define _TIME64_T_DEFINED +#endif + +#ifndef _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#define _TIME_T_DEFINED +#endif + +#ifndef _TIMEB_DEFINED +#define _TIMEB_DEFINED + + struct __timeb32 { + __time32_t time; + unsigned short millitm; + short timezone; + short dstflag; + }; + +#ifndef NO_OLDNAMES + struct timeb { + time_t time; + unsigned short millitm; + short timezone; + short dstflag; + }; +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + struct __timeb64 { + __time64_t time; + unsigned short millitm; + short timezone; + short dstflag; + }; +#endif + +#ifdef _USE_32BIT_TIME_T +#define _timeb __timeb32 +//gr #define _ftime _ftime32 +#define _ftime32 _ftime +#else +#define _timeb __timeb64 +#define _ftime _ftime64 +#endif +#endif + + _CRTIMP void __cdecl _ftime32(struct __timeb32 *_Time); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP void __cdecl _ftime64(struct __timeb64 *_Time); +#endif + +#ifndef _TIMESPEC_DEFINED +#define _TIMESPEC_DEFINED +struct timespec { + time_t tv_sec; /* Seconds */ + long tv_nsec; /* Nanoseconds */ +}; + +struct itimerspec { + struct timespec it_interval; /* Timer period */ + struct timespec it_value; /* Timer expiration */ +}; +#endif + +#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { + _ftime32((struct __timeb32 *)_Tmb); +} +#else +__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { + _ftime64((struct __timeb64 *)_Tmb); +} +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include +#endif diff --git a/tcc/include/sys/types.h b/tcc/include/sys/types.h index 7379b0f1..80ba7a47 100644 --- a/tcc/include/sys/types.h +++ b/tcc/include/sys/types.h @@ -1,118 +1,118 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_TYPES -#define _INC_TYPES - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED -typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 -typedef __int64 __time64_t; -#endif -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T -typedef __time32_t time_t; -#else -typedef __time64_t time_t; -#endif -#endif - -#ifndef _INO_T_DEFINED -#define _INO_T_DEFINED -typedef unsigned short _ino_t; -#ifndef NO_OLDNAMES -typedef unsigned short ino_t; -#endif -#endif - -#ifndef _DEV_T_DEFINED -#define _DEV_T_DEFINED -typedef unsigned int _dev_t; -#ifndef NO_OLDNAMES -typedef unsigned int dev_t; -#endif -#endif - -#ifndef _PID_T_ -#define _PID_T_ -#ifndef _WIN64 -typedef int _pid_t; -#else -typedef __int64 _pid_t; -#endif - -#ifndef NO_OLDNAMES -typedef _pid_t pid_t; -#endif -#endif /* Not _PID_T_ */ - -#ifndef _MODE_T_ -#define _MODE_T_ -typedef unsigned short _mode_t; - -#ifndef NO_OLDNAMES -typedef _mode_t mode_t; -#endif -#endif /* Not _MODE_T_ */ - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif - -#ifndef _TIMESPEC_DEFINED -#define _TIMESPEC_DEFINED -struct timespec { - time_t tv_sec; /* Seconds */ - long tv_nsec; /* Nanoseconds */ -}; - -struct itimerspec { - struct timespec it_interval; /* Timer period */ - struct timespec it_value; /* Timer expiration */ -}; -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_TYPES +#define _INC_TYPES + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED +typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 +typedef __int64 __time64_t; +#endif +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T +typedef __time32_t time_t; +#else +typedef __time64_t time_t; +#endif +#endif + +#ifndef _INO_T_DEFINED +#define _INO_T_DEFINED +typedef unsigned short _ino_t; +#ifndef NO_OLDNAMES +typedef unsigned short ino_t; +#endif +#endif + +#ifndef _DEV_T_DEFINED +#define _DEV_T_DEFINED +typedef unsigned int _dev_t; +#ifndef NO_OLDNAMES +typedef unsigned int dev_t; +#endif +#endif + +#ifndef _PID_T_ +#define _PID_T_ +#ifndef _WIN64 +typedef int _pid_t; +#else +typedef __int64 _pid_t; +#endif + +#ifndef NO_OLDNAMES +typedef _pid_t pid_t; +#endif +#endif /* Not _PID_T_ */ + +#ifndef _MODE_T_ +#define _MODE_T_ +typedef unsigned short _mode_t; + +#ifndef NO_OLDNAMES +typedef _mode_t mode_t; +#endif +#endif /* Not _MODE_T_ */ + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif + +#ifndef _TIMESPEC_DEFINED +#define _TIMESPEC_DEFINED +struct timespec { + time_t tv_sec; /* Seconds */ + long tv_nsec; /* Nanoseconds */ +}; + +struct itimerspec { + struct timespec it_interval; /* Timer period */ + struct timespec it_value; /* Timer expiration */ +}; +#endif + +#endif diff --git a/tcc/include/sys/unistd.h b/tcc/include/sys/unistd.h index 31006d32..a0c29cda 100644 --- a/tcc/include/sys/unistd.h +++ b/tcc/include/sys/unistd.h @@ -1,14 +1,14 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * unistd.h maps (roughly) to io.h - */ -#ifndef __STRICT_ANSI__ -#include -#endif - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * unistd.h maps (roughly) to io.h + */ +#ifndef __STRICT_ANSI__ +#include +#endif + diff --git a/tcc/include/sys/utime.h b/tcc/include/sys/utime.h index fec8304f..4d9daee2 100644 --- a/tcc/include/sys/utime.h +++ b/tcc/include/sys/utime.h @@ -1,146 +1,146 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_UTIME -#define _INC_UTIME - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED - typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 - typedef __int64 __time64_t; -#endif -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#endif - -#ifndef _UTIMBUF_DEFINED -#define _UTIMBUF_DEFINED - - struct _utimbuf { - time_t actime; - time_t modtime; - }; - - struct __utimbuf32 { - __time32_t actime; - __time32_t modtime; - }; - -#if _INTEGRAL_MAX_BITS >= 64 - struct __utimbuf64 { - __time64_t actime; - __time64_t modtime; - }; -#endif - -#ifndef NO_OLDNAMES - struct utimbuf { - time_t actime; - time_t modtime; - }; - - struct utimbuf32 { - __time32_t actime; - __time32_t modtime; - }; -#endif -#endif - - _CRTIMP int __cdecl _utime32(const char *_Filename,struct __utimbuf32 *_Time); - _CRTIMP int __cdecl _futime32(int _FileDes,struct __utimbuf32 *_Time); - _CRTIMP int __cdecl _wutime32(const wchar_t *_Filename,struct __utimbuf32 *_Time); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _utime64(const char *_Filename,struct __utimbuf64 *_Time); - _CRTIMP int __cdecl _futime64(int _FileDes,struct __utimbuf64 *_Time); - _CRTIMP int __cdecl _wutime64(const wchar_t *_Filename,struct __utimbuf64 *_Time); -#endif - -#ifndef RC_INVOKED -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { - return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { - return _futime32(_Desc,(struct __utimbuf32 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { - return _wutime32(_Filename,(struct __utimbuf32 *)_Utimbuf); -} -#else -__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { - return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { - return _futime64(_Desc,(struct __utimbuf64 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { - return _wutime64(_Filename,(struct __utimbuf64 *)_Utimbuf); -} -#endif - -#ifndef NO_OLDNAMES -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { - return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); -} -#else -__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { - return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); -} -#endif -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_UTIME +#define _INC_UTIME + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED + typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 + typedef __int64 __time64_t; +#endif +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#endif + +#ifndef _UTIMBUF_DEFINED +#define _UTIMBUF_DEFINED + + struct _utimbuf { + time_t actime; + time_t modtime; + }; + + struct __utimbuf32 { + __time32_t actime; + __time32_t modtime; + }; + +#if _INTEGRAL_MAX_BITS >= 64 + struct __utimbuf64 { + __time64_t actime; + __time64_t modtime; + }; +#endif + +#ifndef NO_OLDNAMES + struct utimbuf { + time_t actime; + time_t modtime; + }; + + struct utimbuf32 { + __time32_t actime; + __time32_t modtime; + }; +#endif +#endif + + _CRTIMP int __cdecl _utime32(const char *_Filename,struct __utimbuf32 *_Time); + _CRTIMP int __cdecl _futime32(int _FileDes,struct __utimbuf32 *_Time); + _CRTIMP int __cdecl _wutime32(const wchar_t *_Filename,struct __utimbuf32 *_Time); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _utime64(const char *_Filename,struct __utimbuf64 *_Time); + _CRTIMP int __cdecl _futime64(int _FileDes,struct __utimbuf64 *_Time); + _CRTIMP int __cdecl _wutime64(const wchar_t *_Filename,struct __utimbuf64 *_Time); +#endif + +#ifndef RC_INVOKED +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { + return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { + return _futime32(_Desc,(struct __utimbuf32 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { + return _wutime32(_Filename,(struct __utimbuf32 *)_Utimbuf); +} +#else +__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { + return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { + return _futime64(_Desc,(struct __utimbuf64 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { + return _wutime64(_Filename,(struct __utimbuf64 *)_Utimbuf); +} +#endif + +#ifndef NO_OLDNAMES +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { + return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); +} +#else +__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { + return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); +} +#endif +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/tcc/tcc_libm.h b/tcc/include/tcc/tcc_libm.h index ba26ee00..0a6f791b 100644 --- a/tcc/include/tcc/tcc_libm.h +++ b/tcc/include/tcc/tcc_libm.h @@ -1,618 +1,618 @@ -#ifndef _TCC_LIBM_H_ -#define _TCC_LIBM_H_ - -#include "../math.h" -#include "../stdint.h" - -/* TCC uses 8 bytes for double and long double, so effectively the l variants - * are never used. For now, they just run the normal (double) variant. - */ - -/* - * most of the code in this file is taken from MUSL rs-1.0 (MIT license) - * - musl-libc: http://git.musl-libc.org/cgit/musl/tree/src/math?h=rs-1.0 - * - License: http://git.musl-libc.org/cgit/musl/tree/COPYRIGHT?h=rs-1.0 - */ - -/******************************************************************************* - Start of code based on MUSL -*******************************************************************************/ -/* -musl as a whole is licensed under the following standard MIT license: - ----------------------------------------------------------------------- -Copyright © 2005-2014 Rich Felker, et al. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- -*/ - -/* fpclassify */ - -__CRT_INLINE int __cdecl __fpclassify (double x) { - union {double f; uint64_t i;} u = {.f = x}; - int e = u.i>>52 & 0x7ff; - if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; - if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; - return FP_NORMAL; -} - -__CRT_INLINE int __cdecl __fpclassifyf (float x) { - union {float f; uint32_t i;} u = {.f = x}; - int e = u.i>>23 & 0xff; - if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; - if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; - return FP_NORMAL; -} - -__CRT_INLINE int __cdecl __fpclassifyl (long double x) { - return __fpclassify(x); -} - - -/* signbit */ - -__CRT_INLINE int __cdecl __signbit (double x) { - union {double f; uint64_t i;} u = {.f = x}; - return u.i>>63; -} - -__CRT_INLINE int __cdecl __signbitf (float x) { - union {float f; uint32_t i; } u = {.f = x}; - return u.i>>31; -} - -__CRT_INLINE int __cdecl __signbitl (long double x) { - return __signbit(x); -} - - -/* fmin*, fmax* */ - -#define TCCFP_FMIN_EVAL (isnan(x) ? y : \ - isnan(y) ? x : \ - (signbit(x) != signbit(y)) ? (signbit(x) ? x : y) : \ - x < y ? x : y) - -__CRT_INLINE double __cdecl fmin (double x, double y) { - return TCCFP_FMIN_EVAL; -} - -__CRT_INLINE float __cdecl fminf (float x, float y) { - return TCCFP_FMIN_EVAL; -} - -__CRT_INLINE long double __cdecl fminl (long double x, long double y) { - return TCCFP_FMIN_EVAL; -} - -#define TCCFP_FMAX_EVAL (isnan(x) ? y : \ - isnan(y) ? x : \ - (signbit(x) != signbit(y)) ? (signbit(x) ? y : x) : \ - x < y ? y : x) - -__CRT_INLINE double __cdecl fmax (double x, double y) { - return TCCFP_FMAX_EVAL; -} - -__CRT_INLINE float __cdecl fmaxf (float x, float y) { - return TCCFP_FMAX_EVAL; -} - -__CRT_INLINE long double __cdecl fmaxl (long double x, long double y) { - return TCCFP_FMAX_EVAL; -} - - -/* *round* */ - -#define TCCFP_FORCE_EVAL(x) do { \ - volatile typeof(x) __x; \ - __x = (x); \ -} while(0) - -__CRT_INLINE double __cdecl round (double x) { - union {double f; uint64_t i;} u = {.f = x}; - int e = u.i >> 52 & 0x7ff; - double y; - - if (e >= 0x3ff+52) - return x; - if (u.i >> 63) - x = -x; - if (e < 0x3ff-1) { - /* raise inexact if x!=0 */ - TCCFP_FORCE_EVAL(x + 0x1p52); - return 0*u.f; - } - y = (double)(x + 0x1p52) - 0x1p52 - x; - y = y + x - (y > 0.5) + (y <= -0.5); /* branchless */ - return (u.i >> 63) ? -y : y; -} - -__CRT_INLINE long __cdecl lround (double x) { - return round(x); -} - -__CRT_INLINE long long __cdecl llround (double x) { - return round(x); -} - -__CRT_INLINE float __cdecl roundf (float x) { - return round(x); -} - -__CRT_INLINE long __cdecl lroundf (float x) { - return round(x); -} - -__CRT_INLINE long long __cdecl llroundf (float x) { - return round(x); -} - -__CRT_INLINE long double __cdecl roundl (long double x) { - return round(x); -} - -__CRT_INLINE long __cdecl lroundl (long double x) { - return round(x); -} - -__CRT_INLINE long long __cdecl llroundl (long double x) { - return round(x); -} - - -/* MUSL asinh, acosh, atanh */ - -__CRT_INLINE double __cdecl asinh(double x) { - union {double f; uint64_t i;} u = {.f = x}; - unsigned e = u.i >> 52 & 0x7ff, s = u.i >> 63; - u.i &= -1ull / 2, x = u.f; - if (e >= 0x3ff + 26) x = log(x) + 0.693147180559945309; - else if (e >= 0x3ff + 1) x = log(2*x + 1 / (sqrt(x*x + 1) + x)); /* |x|>=2 */ - else if (e >= 0x3ff - 26) x = log1p(x + x*x / (sqrt(x*x + 1) + 1)); - else TCCFP_FORCE_EVAL(x + 0x1p120f); - return s ? -x : x; -} - -__CRT_INLINE double __cdecl acosh(double x) { - union {double f; uint64_t i;} u = {.f = x}; - unsigned e = u.i >> 52 & 0x7ff; - if (e < 0x3ff + 1) return --x, log1p(x + sqrt(x*x + 2*x)); /* |x|<2 */ - if (e < 0x3ff + 26) return log(2*x - 1 / (x + sqrt(x*x - 1))); - return log(x) + 0.693147180559945309; -} - -__CRT_INLINE double __cdecl atanh(double x) { - union {double f; uint64_t i;} u = {.f = x}; - unsigned e = u.i >> 52 & 0x7ff, s = u.i >> 63; - u.i &= -1ull / 2, x = u.f; - if (e < 0x3ff - 1) { - if (e < 0x3ff - 32) { if (e == 0) TCCFP_FORCE_EVAL((float)x); } - else x = 0.5 * log1p(2*x + 2*x*x / (1 - x)); /* |x| < 0.5 */ - } else x = 0.5 * log1p(2*(x / (1 - x))); /* avoid overflow */ - return s ? -x : x; -} - -/* MUSL scalbn */ - -__CRT_INLINE double __cdecl scalbn(double x, int n) { - union {double f; uint64_t i;} u; - if (n > 1023) { - x *= 0x1p1023, n -= 1023; - if (n > 1023) { - x *= 0x1p1023, n -= 1023; - if (n > 1023) n = 1023; - } - } else if (n < -1022) { - x *= 0x1p-1022 * 0x1p53, n += 1022 - 53; - if (n < -1022) { - x *= 0x1p-1022 * 0x1p53, n += 1022 - 53; - if (n < -1022) n = -1022; - } - } - u.i = (0x3ffull + n) << 52; - return x * u.f; -} - -/* MUSL: Override msvcrt frexp(): 4.5x speedup! */ - -__CRT_INLINE double __cdecl frexp(double x, int *e) { - union {double f; uint64_t i;} u = {.f = x}; - int ee = u.i>>52 & 0x7ff; - if (!ee) { - if (x) x = frexp(x*0x1p64, e), *e -= 64; - else *e = 0; - return x; - } else if (ee == 0x7ff) - return x; - *e = ee - 0x3fe; - u.i &= 0x800fffffffffffffull; - u.i |= 0x3fe0000000000000ull; - return u.f; -} - -/* MUSL nan */ - -__CRT_INLINE double __cdecl nan(const char* s) { - return NAN; -} -__CRT_INLINE float __cdecl nanf(const char* s) { - return NAN; -} -__CRT_INLINE long double __cdecl nanl(const char* s) { - return NAN; -} - - -/******************************************************************************* - End of code based on MUSL -*******************************************************************************/ - - -/* Following are math functions missing from msvcrt.dll, and not defined - * in math.h or above. Functions still remaining: - * remquo(), remainder(), fma(), erf(), erfc(), nearbyint(). - * In : lldiv(). - */ - -__CRT_INLINE float __cdecl scalbnf(float x, int n) { - return scalbn(x, n); -} -__CRT_INLINE long double __cdecl scalbnl(long double x, int n) { - return scalbn(x, n); -} - -__CRT_INLINE double __cdecl scalbln(double x, long n) { - return scalbn(x, n); -} -__CRT_INLINE float __cdecl scalblnf(float x, long n) { - return scalbn(x, n); -} -__CRT_INLINE long double __cdecl scalblnl(long double x, long n) { - return scalbn(x, n); -} - -/* Override msvcrt ldexp(): 7.3x speedup! */ - -__CRT_INLINE double __cdecl ldexp(double x, int expn) { - return scalbn(x, expn); -} -__CRT_INLINE float __cdecl ldexpf(float x, int expn) { - return scalbn(x, expn); -} -__CRT_INLINE long double __cdecl ldexpl(long double x, int expn) { - return scalbn(x, expn); -} - -__CRT_INLINE float __cdecl frexpf(float x, int *y) { - return frexp(x, y); -} -__CRT_INLINE long double __cdecl frexpl (long double x, int* y) { - return frexp(x, y); -} - - -__CRT_INLINE double __cdecl rint(double x) { -double retval; - __asm__ ( - "fldl %1\n" - "frndint \n" - "fstpl %0\n" : "=m" (retval) : "m" (x)); - return retval; -} - -__CRT_INLINE float __cdecl rintf(float x) { - float retval; - __asm__ ( - "flds %1\n" - "frndint \n" - "fstps %0\n" : "=m" (retval) : "m" (x)); - return retval; -} -__CRT_INLINE long double __cdecl rintl (long double x) { - return rint(x); -} - - -/* 7.12.9.5 */ -__CRT_INLINE long __cdecl lrint(double x) { - long retval; - __asm__ __volatile__ - ("fldl %1\n" - "fistpl %0" : "=m" (retval) : "m" (x)); - return retval; -} - -__CRT_INLINE long __cdecl lrintf(float x) { - long retval; - __asm__ __volatile__ - ("flds %1\n" - "fistpl %0" : "=m" (retval) : "m" (x)); - return retval; -} - -__CRT_INLINE long __cdecl lrintl (long double x) { - return lrint(x); -} - - -__CRT_INLINE long long __cdecl llrint(double x) { -long long retval; - __asm__ __volatile__ - ("fldl %1\n" - "fistpll %0" : "=m" (retval) : "m" (x)); - return retval; -} - -__CRT_INLINE long long __cdecl llrintf(float x) { - long long retval; - __asm__ __volatile__ - ("flds %1\n" - "fistpll %0" : "=m" (retval) : "m" (x)); - return retval; -} - -__CRT_INLINE long long __cdecl llrintl (long double x) { - return llrint(x); -} - - -__CRT_INLINE double __cdecl trunc(double _x) { - double retval; - unsigned short saved_cw; - unsigned short tmp_cw; - __asm__ ("fnstcw %0;" : "=m" (saved_cw)); /* save FPU control word */ - tmp_cw = (saved_cw & ~(FE_TONEAREST | FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO)) - | FE_TOWARDZERO; - __asm__ ("fldcw %0;" : : "m" (tmp_cw)); - __asm__ ("fldl %1;" - "frndint;" - "fstpl %0;" : "=m" (retval) : "m" (_x)); /* round towards zero */ - __asm__ ("fldcw %0;" : : "m" (saved_cw) ); /* restore saved control word */ - return retval; -} - -__CRT_INLINE float __cdecl truncf(float x) { - return (float) ((intptr_t) x); -} -__CRT_INLINE long double __cdecl truncl(long double x) { - return trunc(x); -} - - -__CRT_INLINE long double __cdecl nextafterl(long double x, long double to) { - return nextafter(x, to); -} - -__CRT_INLINE double __cdecl nexttoward(double x, long double to) { - return nextafter(x, to); -} -__CRT_INLINE float __cdecl nexttowardf(float x, long double to) { - return nextafterf(x, to); -} -__CRT_INLINE long double __cdecl nexttowardl(long double x, long double to) { - return nextafter(x, to); -} - -/* Override msvcrt fabs(): 6.3x speedup! */ - -__CRT_INLINE double __cdecl fabs(double x) { - return x < 0 ? -x : x; -} -__CRT_INLINE float __cdecl fabsf(float x) { - return x < 0 ? -x : x; -} -__CRT_INLINE long double __cdecl fabsl(long double x) { - return x < 0 ? -x : x; -} - - -#if defined(_WIN32) && !defined(_WIN64) && !defined(__ia64__) - __CRT_INLINE float acosf(float x) { return acos(x); } - __CRT_INLINE float asinf(float x) { return asin(x); } - __CRT_INLINE float atanf(float x) { return atan(x); } - __CRT_INLINE float atan2f(float x, float y) { return atan2(x, y); } - __CRT_INLINE float ceilf(float x) { return ceil(x); } - __CRT_INLINE float cosf(float x) { return cos(x); } - __CRT_INLINE float coshf(float x) { return cosh(x); } - __CRT_INLINE float expf(float x) { return exp(x); } - __CRT_INLINE float floorf(float x) { return floor(x); } - __CRT_INLINE float fmodf(float x, float y) { return fmod(x, y); } - __CRT_INLINE float logf(float x) { return log(x); } - __CRT_INLINE float logbf(float x) { return logb(x); } - __CRT_INLINE float log10f(float x) { return log10(x); } - __CRT_INLINE float modff(float x, float *y) { double di, df = modf(x, &di); *y = di; return df; } - __CRT_INLINE float powf(float x, float y) { return pow(x, y); } - __CRT_INLINE float sinf(float x) { return sin(x); } - __CRT_INLINE float sinhf(float x) { return sinh(x); } - __CRT_INLINE float sqrtf(float x) { return sqrt(x); } - __CRT_INLINE float tanf(float x) { return tan(x); } - __CRT_INLINE float tanhf(float x) { return tanh(x); } -#endif -__CRT_INLINE float __cdecl asinhf(float x) { return asinh(x); } -__CRT_INLINE float __cdecl acoshf(float x) { return acosh(x); } -__CRT_INLINE float __cdecl atanhf(float x) { return atanh(x); } - -__CRT_INLINE long double __cdecl asinhl(long double x) { return asinh(x); } -__CRT_INLINE long double __cdecl acoshl(long double x) { return acosh(x); } -__CRT_INLINE long double __cdecl atanhl(long double x) { return atanh(x); } -__CRT_INLINE long double __cdecl asinl(long double x) { return asin(x); } -__CRT_INLINE long double __cdecl acosl(long double x) { return acos(x); } -__CRT_INLINE long double __cdecl atanl(long double x) { return atan(x); } -__CRT_INLINE long double __cdecl ceill(long double x) { return ceil(x); } -__CRT_INLINE long double __cdecl coshl(long double x) { return cosh(x); } -__CRT_INLINE long double __cdecl cosl(long double x) { return cos(x); } -__CRT_INLINE long double __cdecl expl(long double x) { return exp(x); } -__CRT_INLINE long double __cdecl floorl(long double x) { return floor(x); } -__CRT_INLINE long double __cdecl fmodl(long double x, long double y) { return fmod(x, y); } -__CRT_INLINE long double __cdecl hypotl(long double x, long double y) { return hypot(x, y); } -__CRT_INLINE long double __cdecl logl(long double x) { return log(x); } -__CRT_INLINE long double __cdecl logbl(long double x) { return logb(x); } -__CRT_INLINE long double __cdecl log10l(long double x) { return log10(x); } -__CRT_INLINE long double __cdecl modfl(long double x, long double* y) { double y1 = *y; x = modf(x, &y1); *y = y1; return x; } -__CRT_INLINE long double __cdecl powl(long double x, long double y) { return pow(x, y); } -__CRT_INLINE long double __cdecl sinhl(long double x) { return sinh(x); } -__CRT_INLINE long double __cdecl sinl(long double x) { return sin(x); } -__CRT_INLINE long double __cdecl sqrtl(long double x) { return sqrt(x); } -__CRT_INLINE long double __cdecl tanhl(long double x) { return tanh(x); } -__CRT_INLINE long double __cdecl tanl(long double x) { return tan(x); } - -/* Following are accurate, but much shorter implementations than MUSL lib. */ - -__CRT_INLINE double __cdecl log1p(double x) { - double u = 1.0 + x; - return u == 1.0 ? x : log(u)*(x / (u - 1.0)); -} -__CRT_INLINE float __cdecl log1pf(float x) { - float u = 1.0f + x; - return u == 1.0f ? x : logf(u)*(x / (u - 1.0f)); -} -__CRT_INLINE long double __cdecl log1pl(long double x) { - return log1p(x); -} - - -__CRT_INLINE double __cdecl expm1(double x) { - if (x > 0.0024 || x < -0.0024) return exp(x) - 1.0; - return x*(1.0 + 0.5*x*(1.0 + (1/3.0)*x*(1.0 + 0.25*x*(1.0 + 0.2*x)))); -} -__CRT_INLINE float __cdecl expm1f(float x) { - if (x > 0.085f || x < -0.085f) return expf(x) - 1.0f; - return x*(1.0f + 0.5f*x*(1.0f + (1/3.0f)*x*(1.0f + 0.25f*x))); -} -__CRT_INLINE long double __cdecl expm1l(long double x) { - return expm1(x); -} - - -__CRT_INLINE double __cdecl cbrt(double x) { - return x < 0.0 ? -pow(-x, 1/3.0) : pow(x, 1/3.0); -} -__CRT_INLINE float __cdecl cbrtf(float x) { - return x < 0.0f ? -pow(-x, 1/3.0) : pow(x, 1/3.0); -} -__CRT_INLINE long double __cdecl cbrtl(long double x) { - return cbrt(x); -} - - -__CRT_INLINE double __cdecl log2(double x) { - return log(x) * 1.442695040888963407; -} -__CRT_INLINE float __cdecl log2f(float x) { - return log(x) * 1.442695040888963407; -} -__CRT_INLINE long double __cdecl log2l(long double x) { - return log(x) * 1.442695040888963407; -} - - -__CRT_INLINE double __cdecl exp2(double x) { - return exp(x * 0.693147180559945309); -} -__CRT_INLINE float __cdecl exp2f(float x) { - return exp(x * 0.693147180559945309); -} -__CRT_INLINE long double __cdecl exp2l(long double x) { - return exp(x * 0.693147180559945309); -} - - -__CRT_INLINE int __cdecl ilogb(double x) { - return (int) logb(x); -} -__CRT_INLINE int __cdecl ilogbf(float x) { - return (int) logbf(x); -} -__CRT_INLINE int __cdecl ilogbl(long double x) { - return (int) logb(x); -} - - -__CRT_INLINE double __cdecl fdim(double x, double y) { - if (isnan(x) || isnan(y)) return NAN; - return x > y ? x - y : 0; -} -__CRT_INLINE float __cdecl fdimf(float x, float y) { - if (isnan(x) || isnan(y)) return NAN; - return x > y ? x - y : 0; -} -__CRT_INLINE long double __cdecl fdiml(long double x, long double y) { - if (isnan(x) || isnan(y)) return NAN; - return x > y ? x - y : 0; -} - - -/* tgamma and lgamma: Lanczos approximation - * https://rosettacode.org/wiki/Gamma_function - * https://www.johndcook.com/blog/cpp_gamma - */ - -__CRT_INLINE double __cdecl tgamma(double x) { - double m = 1.0, t = 3.14159265358979323; - if (x == floor(x)) { - if (x == 0) return INFINITY; - if (x < 0) return NAN; - if (x < 26) { for (double k = 2; k < x; ++k) m *= k; return m; } - } - if (x < 0.5) - return t / (sin(t*x)*tgamma(1.0 - x)); - if (x > 12.0) - return exp(lgamma(x)); - - static const double c[8] = {676.5203681218851, -1259.1392167224028, - 771.32342877765313, -176.61502916214059, - 12.507343278686905, -0.13857109526572012, - 9.9843695780195716e-6, 1.5056327351493116e-7}; - m = 0.99999999999980993, t = x + 6.5; /* x-1+8-.5 */ - for (int k = 0; k < 8; ++k) m += c[k] / (x + k); - return 2.50662827463100050 * pow(t, x - 0.5)*exp(-t)*m; /* C=sqrt(2pi) */ -} - - -__CRT_INLINE double __cdecl lgamma(double x) { - if (x < 12.0) { - if (x <= 0.0 && x == floor(x)) return INFINITY; - x = tgamma(x); - return log(x < 0.0 ? -x : x); - } - static const double c[7] = {1.0/12.0, -1.0/360.0, 1.0/1260.0, -1.0/1680.0, - 1.0/1188.0, -691.0/360360.0, 1.0/156.0}; - double m = -3617.0/122400.0, t = 1.0 / (x*x); - for (int k = 6; k >= 0; --k) m = m*t + c[k]; - return (x - 0.5)*log(x) - x + 0.918938533204672742 + m / x; /* C=log(2pi)/2 */ -} - -__CRT_INLINE float __cdecl tgammaf(float x) { - return tgamma(x); -} -__CRT_INLINE float __cdecl lgammaf(float x) { - return lgamma(x); -} -__CRT_INLINE long double __cdecl tgammal(long double x) { - return tgamma(x); -} -__CRT_INLINE long double __cdecl lgammal(long double x) { - return lgamma(x); -} - -#endif /* _TCC_LIBM_H_ */ +#ifndef _TCC_LIBM_H_ +#define _TCC_LIBM_H_ + +#include "../math.h" +#include "../stdint.h" + +/* TCC uses 8 bytes for double and long double, so effectively the l variants + * are never used. For now, they just run the normal (double) variant. + */ + +/* + * most of the code in this file is taken from MUSL rs-1.0 (MIT license) + * - musl-libc: http://git.musl-libc.org/cgit/musl/tree/src/math?h=rs-1.0 + * - License: http://git.musl-libc.org/cgit/musl/tree/COPYRIGHT?h=rs-1.0 + */ + +/******************************************************************************* + Start of code based on MUSL +*******************************************************************************/ +/* +musl as a whole is licensed under the following standard MIT license: + +---------------------------------------------------------------------- +Copyright © 2005-2014 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------- +*/ + +/* fpclassify */ + +__CRT_INLINE int __cdecl __fpclassify (double x) { + union {double f; uint64_t i;} u = {.f = x}; + int e = u.i>>52 & 0x7ff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} + +__CRT_INLINE int __cdecl __fpclassifyf (float x) { + union {float f; uint32_t i;} u = {.f = x}; + int e = u.i>>23 & 0xff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} + +__CRT_INLINE int __cdecl __fpclassifyl (long double x) { + return __fpclassify(x); +} + + +/* signbit */ + +__CRT_INLINE int __cdecl __signbit (double x) { + union {double f; uint64_t i;} u = {.f = x}; + return u.i>>63; +} + +__CRT_INLINE int __cdecl __signbitf (float x) { + union {float f; uint32_t i; } u = {.f = x}; + return u.i>>31; +} + +__CRT_INLINE int __cdecl __signbitl (long double x) { + return __signbit(x); +} + + +/* fmin*, fmax* */ + +#define TCCFP_FMIN_EVAL (isnan(x) ? y : \ + isnan(y) ? x : \ + (signbit(x) != signbit(y)) ? (signbit(x) ? x : y) : \ + x < y ? x : y) + +__CRT_INLINE double __cdecl fmin (double x, double y) { + return TCCFP_FMIN_EVAL; +} + +__CRT_INLINE float __cdecl fminf (float x, float y) { + return TCCFP_FMIN_EVAL; +} + +__CRT_INLINE long double __cdecl fminl (long double x, long double y) { + return TCCFP_FMIN_EVAL; +} + +#define TCCFP_FMAX_EVAL (isnan(x) ? y : \ + isnan(y) ? x : \ + (signbit(x) != signbit(y)) ? (signbit(x) ? y : x) : \ + x < y ? y : x) + +__CRT_INLINE double __cdecl fmax (double x, double y) { + return TCCFP_FMAX_EVAL; +} + +__CRT_INLINE float __cdecl fmaxf (float x, float y) { + return TCCFP_FMAX_EVAL; +} + +__CRT_INLINE long double __cdecl fmaxl (long double x, long double y) { + return TCCFP_FMAX_EVAL; +} + + +/* *round* */ + +#define TCCFP_FORCE_EVAL(x) do { \ + volatile typeof(x) __x; \ + __x = (x); \ +} while(0) + +__CRT_INLINE double __cdecl round (double x) { + union {double f; uint64_t i;} u = {.f = x}; + int e = u.i >> 52 & 0x7ff; + double y; + + if (e >= 0x3ff+52) + return x; + if (u.i >> 63) + x = -x; + if (e < 0x3ff-1) { + /* raise inexact if x!=0 */ + TCCFP_FORCE_EVAL(x + 0x1p52); + return 0*u.f; + } + y = (double)(x + 0x1p52) - 0x1p52 - x; + y = y + x - (y > 0.5) + (y <= -0.5); /* branchless */ + return (u.i >> 63) ? -y : y; +} + +__CRT_INLINE long __cdecl lround (double x) { + return round(x); +} + +__CRT_INLINE long long __cdecl llround (double x) { + return round(x); +} + +__CRT_INLINE float __cdecl roundf (float x) { + return round(x); +} + +__CRT_INLINE long __cdecl lroundf (float x) { + return round(x); +} + +__CRT_INLINE long long __cdecl llroundf (float x) { + return round(x); +} + +__CRT_INLINE long double __cdecl roundl (long double x) { + return round(x); +} + +__CRT_INLINE long __cdecl lroundl (long double x) { + return round(x); +} + +__CRT_INLINE long long __cdecl llroundl (long double x) { + return round(x); +} + + +/* MUSL asinh, acosh, atanh */ + +__CRT_INLINE double __cdecl asinh(double x) { + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff, s = u.i >> 63; + u.i &= -1ull / 2, x = u.f; + if (e >= 0x3ff + 26) x = log(x) + 0.693147180559945309; + else if (e >= 0x3ff + 1) x = log(2*x + 1 / (sqrt(x*x + 1) + x)); /* |x|>=2 */ + else if (e >= 0x3ff - 26) x = log1p(x + x*x / (sqrt(x*x + 1) + 1)); + else TCCFP_FORCE_EVAL(x + 0x1p120f); + return s ? -x : x; +} + +__CRT_INLINE double __cdecl acosh(double x) { + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + if (e < 0x3ff + 1) return --x, log1p(x + sqrt(x*x + 2*x)); /* |x|<2 */ + if (e < 0x3ff + 26) return log(2*x - 1 / (x + sqrt(x*x - 1))); + return log(x) + 0.693147180559945309; +} + +__CRT_INLINE double __cdecl atanh(double x) { + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff, s = u.i >> 63; + u.i &= -1ull / 2, x = u.f; + if (e < 0x3ff - 1) { + if (e < 0x3ff - 32) { if (e == 0) TCCFP_FORCE_EVAL((float)x); } + else x = 0.5 * log1p(2*x + 2*x*x / (1 - x)); /* |x| < 0.5 */ + } else x = 0.5 * log1p(2*(x / (1 - x))); /* avoid overflow */ + return s ? -x : x; +} + +/* MUSL scalbn */ + +__CRT_INLINE double __cdecl scalbn(double x, int n) { + union {double f; uint64_t i;} u; + if (n > 1023) { + x *= 0x1p1023, n -= 1023; + if (n > 1023) { + x *= 0x1p1023, n -= 1023; + if (n > 1023) n = 1023; + } + } else if (n < -1022) { + x *= 0x1p-1022 * 0x1p53, n += 1022 - 53; + if (n < -1022) { + x *= 0x1p-1022 * 0x1p53, n += 1022 - 53; + if (n < -1022) n = -1022; + } + } + u.i = (0x3ffull + n) << 52; + return x * u.f; +} + +/* MUSL: Override msvcrt frexp(): 4.5x speedup! */ + +__CRT_INLINE double __cdecl frexp(double x, int *e) { + union {double f; uint64_t i;} u = {.f = x}; + int ee = u.i>>52 & 0x7ff; + if (!ee) { + if (x) x = frexp(x*0x1p64, e), *e -= 64; + else *e = 0; + return x; + } else if (ee == 0x7ff) + return x; + *e = ee - 0x3fe; + u.i &= 0x800fffffffffffffull; + u.i |= 0x3fe0000000000000ull; + return u.f; +} + +/* MUSL nan */ + +__CRT_INLINE double __cdecl nan(const char* s) { + return NAN; +} +__CRT_INLINE float __cdecl nanf(const char* s) { + return NAN; +} +__CRT_INLINE long double __cdecl nanl(const char* s) { + return NAN; +} + + +/******************************************************************************* + End of code based on MUSL +*******************************************************************************/ + + +/* Following are math functions missing from msvcrt.dll, and not defined + * in math.h or above. Functions still remaining: + * remquo(), remainder(), fma(), erf(), erfc(), nearbyint(). + * In : lldiv(). + */ + +__CRT_INLINE float __cdecl scalbnf(float x, int n) { + return scalbn(x, n); +} +__CRT_INLINE long double __cdecl scalbnl(long double x, int n) { + return scalbn(x, n); +} + +__CRT_INLINE double __cdecl scalbln(double x, long n) { + return scalbn(x, n); +} +__CRT_INLINE float __cdecl scalblnf(float x, long n) { + return scalbn(x, n); +} +__CRT_INLINE long double __cdecl scalblnl(long double x, long n) { + return scalbn(x, n); +} + +/* Override msvcrt ldexp(): 7.3x speedup! */ + +__CRT_INLINE double __cdecl ldexp(double x, int expn) { + return scalbn(x, expn); +} +__CRT_INLINE float __cdecl ldexpf(float x, int expn) { + return scalbn(x, expn); +} +__CRT_INLINE long double __cdecl ldexpl(long double x, int expn) { + return scalbn(x, expn); +} + +__CRT_INLINE float __cdecl frexpf(float x, int *y) { + return frexp(x, y); +} +__CRT_INLINE long double __cdecl frexpl (long double x, int* y) { + return frexp(x, y); +} + + +__CRT_INLINE double __cdecl rint(double x) { +double retval; + __asm__ ( + "fldl %1\n" + "frndint \n" + "fstpl %0\n" : "=m" (retval) : "m" (x)); + return retval; +} + +__CRT_INLINE float __cdecl rintf(float x) { + float retval; + __asm__ ( + "flds %1\n" + "frndint \n" + "fstps %0\n" : "=m" (retval) : "m" (x)); + return retval; +} +__CRT_INLINE long double __cdecl rintl (long double x) { + return rint(x); +} + + +/* 7.12.9.5 */ +__CRT_INLINE long __cdecl lrint(double x) { + long retval; + __asm__ __volatile__ + ("fldl %1\n" + "fistpl %0" : "=m" (retval) : "m" (x)); + return retval; +} + +__CRT_INLINE long __cdecl lrintf(float x) { + long retval; + __asm__ __volatile__ + ("flds %1\n" + "fistpl %0" : "=m" (retval) : "m" (x)); + return retval; +} + +__CRT_INLINE long __cdecl lrintl (long double x) { + return lrint(x); +} + + +__CRT_INLINE long long __cdecl llrint(double x) { +long long retval; + __asm__ __volatile__ + ("fldl %1\n" + "fistpll %0" : "=m" (retval) : "m" (x)); + return retval; +} + +__CRT_INLINE long long __cdecl llrintf(float x) { + long long retval; + __asm__ __volatile__ + ("flds %1\n" + "fistpll %0" : "=m" (retval) : "m" (x)); + return retval; +} + +__CRT_INLINE long long __cdecl llrintl (long double x) { + return llrint(x); +} + + +__CRT_INLINE double __cdecl trunc(double _x) { + double retval; + unsigned short saved_cw; + unsigned short tmp_cw; + __asm__ ("fnstcw %0;" : "=m" (saved_cw)); /* save FPU control word */ + tmp_cw = (saved_cw & ~(FE_TONEAREST | FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO)) + | FE_TOWARDZERO; + __asm__ ("fldcw %0;" : : "m" (tmp_cw)); + __asm__ ("fldl %1;" + "frndint;" + "fstpl %0;" : "=m" (retval) : "m" (_x)); /* round towards zero */ + __asm__ ("fldcw %0;" : : "m" (saved_cw) ); /* restore saved control word */ + return retval; +} + +__CRT_INLINE float __cdecl truncf(float x) { + return (float) ((intptr_t) x); +} +__CRT_INLINE long double __cdecl truncl(long double x) { + return trunc(x); +} + + +__CRT_INLINE long double __cdecl nextafterl(long double x, long double to) { + return nextafter(x, to); +} + +__CRT_INLINE double __cdecl nexttoward(double x, long double to) { + return nextafter(x, to); +} +__CRT_INLINE float __cdecl nexttowardf(float x, long double to) { + return nextafterf(x, to); +} +__CRT_INLINE long double __cdecl nexttowardl(long double x, long double to) { + return nextafter(x, to); +} + +/* Override msvcrt fabs(): 6.3x speedup! */ + +__CRT_INLINE double __cdecl fabs(double x) { + return x < 0 ? -x : x; +} +__CRT_INLINE float __cdecl fabsf(float x) { + return x < 0 ? -x : x; +} +__CRT_INLINE long double __cdecl fabsl(long double x) { + return x < 0 ? -x : x; +} + + +#if defined(_WIN32) && !defined(_WIN64) && !defined(__ia64__) + __CRT_INLINE float acosf(float x) { return acos(x); } + __CRT_INLINE float asinf(float x) { return asin(x); } + __CRT_INLINE float atanf(float x) { return atan(x); } + __CRT_INLINE float atan2f(float x, float y) { return atan2(x, y); } + __CRT_INLINE float ceilf(float x) { return ceil(x); } + __CRT_INLINE float cosf(float x) { return cos(x); } + __CRT_INLINE float coshf(float x) { return cosh(x); } + __CRT_INLINE float expf(float x) { return exp(x); } + __CRT_INLINE float floorf(float x) { return floor(x); } + __CRT_INLINE float fmodf(float x, float y) { return fmod(x, y); } + __CRT_INLINE float logf(float x) { return log(x); } + __CRT_INLINE float logbf(float x) { return logb(x); } + __CRT_INLINE float log10f(float x) { return log10(x); } + __CRT_INLINE float modff(float x, float *y) { double di, df = modf(x, &di); *y = di; return df; } + __CRT_INLINE float powf(float x, float y) { return pow(x, y); } + __CRT_INLINE float sinf(float x) { return sin(x); } + __CRT_INLINE float sinhf(float x) { return sinh(x); } + __CRT_INLINE float sqrtf(float x) { return sqrt(x); } + __CRT_INLINE float tanf(float x) { return tan(x); } + __CRT_INLINE float tanhf(float x) { return tanh(x); } +#endif +__CRT_INLINE float __cdecl asinhf(float x) { return asinh(x); } +__CRT_INLINE float __cdecl acoshf(float x) { return acosh(x); } +__CRT_INLINE float __cdecl atanhf(float x) { return atanh(x); } + +__CRT_INLINE long double __cdecl asinhl(long double x) { return asinh(x); } +__CRT_INLINE long double __cdecl acoshl(long double x) { return acosh(x); } +__CRT_INLINE long double __cdecl atanhl(long double x) { return atanh(x); } +__CRT_INLINE long double __cdecl asinl(long double x) { return asin(x); } +__CRT_INLINE long double __cdecl acosl(long double x) { return acos(x); } +__CRT_INLINE long double __cdecl atanl(long double x) { return atan(x); } +__CRT_INLINE long double __cdecl ceill(long double x) { return ceil(x); } +__CRT_INLINE long double __cdecl coshl(long double x) { return cosh(x); } +__CRT_INLINE long double __cdecl cosl(long double x) { return cos(x); } +__CRT_INLINE long double __cdecl expl(long double x) { return exp(x); } +__CRT_INLINE long double __cdecl floorl(long double x) { return floor(x); } +__CRT_INLINE long double __cdecl fmodl(long double x, long double y) { return fmod(x, y); } +__CRT_INLINE long double __cdecl hypotl(long double x, long double y) { return hypot(x, y); } +__CRT_INLINE long double __cdecl logl(long double x) { return log(x); } +__CRT_INLINE long double __cdecl logbl(long double x) { return logb(x); } +__CRT_INLINE long double __cdecl log10l(long double x) { return log10(x); } +__CRT_INLINE long double __cdecl modfl(long double x, long double* y) { double y1 = *y; x = modf(x, &y1); *y = y1; return x; } +__CRT_INLINE long double __cdecl powl(long double x, long double y) { return pow(x, y); } +__CRT_INLINE long double __cdecl sinhl(long double x) { return sinh(x); } +__CRT_INLINE long double __cdecl sinl(long double x) { return sin(x); } +__CRT_INLINE long double __cdecl sqrtl(long double x) { return sqrt(x); } +__CRT_INLINE long double __cdecl tanhl(long double x) { return tanh(x); } +__CRT_INLINE long double __cdecl tanl(long double x) { return tan(x); } + +/* Following are accurate, but much shorter implementations than MUSL lib. */ + +__CRT_INLINE double __cdecl log1p(double x) { + double u = 1.0 + x; + return u == 1.0 ? x : log(u)*(x / (u - 1.0)); +} +__CRT_INLINE float __cdecl log1pf(float x) { + float u = 1.0f + x; + return u == 1.0f ? x : logf(u)*(x / (u - 1.0f)); +} +__CRT_INLINE long double __cdecl log1pl(long double x) { + return log1p(x); +} + + +__CRT_INLINE double __cdecl expm1(double x) { + if (x > 0.0024 || x < -0.0024) return exp(x) - 1.0; + return x*(1.0 + 0.5*x*(1.0 + (1/3.0)*x*(1.0 + 0.25*x*(1.0 + 0.2*x)))); +} +__CRT_INLINE float __cdecl expm1f(float x) { + if (x > 0.085f || x < -0.085f) return expf(x) - 1.0f; + return x*(1.0f + 0.5f*x*(1.0f + (1/3.0f)*x*(1.0f + 0.25f*x))); +} +__CRT_INLINE long double __cdecl expm1l(long double x) { + return expm1(x); +} + + +__CRT_INLINE double __cdecl cbrt(double x) { + return x < 0.0 ? -pow(-x, 1/3.0) : pow(x, 1/3.0); +} +__CRT_INLINE float __cdecl cbrtf(float x) { + return x < 0.0f ? -pow(-x, 1/3.0) : pow(x, 1/3.0); +} +__CRT_INLINE long double __cdecl cbrtl(long double x) { + return cbrt(x); +} + + +__CRT_INLINE double __cdecl log2(double x) { + return log(x) * 1.442695040888963407; +} +__CRT_INLINE float __cdecl log2f(float x) { + return log(x) * 1.442695040888963407; +} +__CRT_INLINE long double __cdecl log2l(long double x) { + return log(x) * 1.442695040888963407; +} + + +__CRT_INLINE double __cdecl exp2(double x) { + return exp(x * 0.693147180559945309); +} +__CRT_INLINE float __cdecl exp2f(float x) { + return exp(x * 0.693147180559945309); +} +__CRT_INLINE long double __cdecl exp2l(long double x) { + return exp(x * 0.693147180559945309); +} + + +__CRT_INLINE int __cdecl ilogb(double x) { + return (int) logb(x); +} +__CRT_INLINE int __cdecl ilogbf(float x) { + return (int) logbf(x); +} +__CRT_INLINE int __cdecl ilogbl(long double x) { + return (int) logb(x); +} + + +__CRT_INLINE double __cdecl fdim(double x, double y) { + if (isnan(x) || isnan(y)) return NAN; + return x > y ? x - y : 0; +} +__CRT_INLINE float __cdecl fdimf(float x, float y) { + if (isnan(x) || isnan(y)) return NAN; + return x > y ? x - y : 0; +} +__CRT_INLINE long double __cdecl fdiml(long double x, long double y) { + if (isnan(x) || isnan(y)) return NAN; + return x > y ? x - y : 0; +} + + +/* tgamma and lgamma: Lanczos approximation + * https://rosettacode.org/wiki/Gamma_function + * https://www.johndcook.com/blog/cpp_gamma + */ + +__CRT_INLINE double __cdecl tgamma(double x) { + double m = 1.0, t = 3.14159265358979323; + if (x == floor(x)) { + if (x == 0) return INFINITY; + if (x < 0) return NAN; + if (x < 26) { for (double k = 2; k < x; ++k) m *= k; return m; } + } + if (x < 0.5) + return t / (sin(t*x)*tgamma(1.0 - x)); + if (x > 12.0) + return exp(lgamma(x)); + + static const double c[8] = {676.5203681218851, -1259.1392167224028, + 771.32342877765313, -176.61502916214059, + 12.507343278686905, -0.13857109526572012, + 9.9843695780195716e-6, 1.5056327351493116e-7}; + m = 0.99999999999980993, t = x + 6.5; /* x-1+8-.5 */ + for (int k = 0; k < 8; ++k) m += c[k] / (x + k); + return 2.50662827463100050 * pow(t, x - 0.5)*exp(-t)*m; /* C=sqrt(2pi) */ +} + + +__CRT_INLINE double __cdecl lgamma(double x) { + if (x < 12.0) { + if (x <= 0.0 && x == floor(x)) return INFINITY; + x = tgamma(x); + return log(x < 0.0 ? -x : x); + } + static const double c[7] = {1.0/12.0, -1.0/360.0, 1.0/1260.0, -1.0/1680.0, + 1.0/1188.0, -691.0/360360.0, 1.0/156.0}; + double m = -3617.0/122400.0, t = 1.0 / (x*x); + for (int k = 6; k >= 0; --k) m = m*t + c[k]; + return (x - 0.5)*log(x) - x + 0.918938533204672742 + m / x; /* C=log(2pi)/2 */ +} + +__CRT_INLINE float __cdecl tgammaf(float x) { + return tgamma(x); +} +__CRT_INLINE float __cdecl lgammaf(float x) { + return lgamma(x); +} +__CRT_INLINE long double __cdecl tgammal(long double x) { + return tgamma(x); +} +__CRT_INLINE long double __cdecl lgammal(long double x) { + return lgamma(x); +} + +#endif /* _TCC_LIBM_H_ */ diff --git a/tcc/include/tccdefs.h b/tcc/include/tccdefs.h index ba2a679f..79a71a23 100644 --- a/tcc/include/tccdefs.h +++ b/tcc/include/tccdefs.h @@ -1,284 +1,284 @@ -/* tccdefs.h - - Nothing is defined before this file except target machine, target os - and the few things related to option settings in tccpp.c:tcc_predefs(). - - This file is either included at runtime as is, or converted and - included as C-strings at compile-time (depending on CONFIG_TCC_PREDEFS). - - Note that line indent matters: - - - in lines starting at column 1, platform macros are replaced by - corresponding TCC target compile-time macros. See conftest.c for - the list of platform macros supported in lines starting at column 1. - - - only lines indented >= 4 are actually included into the executable, - check tccdefs_.h. -*/ - -#if __SIZEOF_POINTER__ == 4 - /* 32bit systems. */ -#if defined TARGETOS_OpenBSD - #define __SIZE_TYPE__ unsigned long - #define __PTRDIFF_TYPE__ long -#else - #define __SIZE_TYPE__ unsigned int - #define __PTRDIFF_TYPE__ int -#endif - #define __ILP32__ 1 - #define __INT64_TYPE__ long long -#elif __SIZEOF_LONG__ == 4 - /* 64bit Windows. */ - #define __SIZE_TYPE__ unsigned long long - #define __PTRDIFF_TYPE__ long long - #define __LLP64__ 1 - #define __INT64_TYPE__ long long -#else - /* Other 64bit systems. */ - #define __SIZE_TYPE__ unsigned long - #define __PTRDIFF_TYPE__ long - #define __LP64__ 1 -# if defined __linux__ - #define __INT64_TYPE__ long -# else /* APPLE, BSD */ - #define __INT64_TYPE__ long long -# endif -#endif - #define __SIZEOF_INT__ 4 - #define __INT_MAX__ 0x7fffffff -#if __SIZEOF_LONG__ == 4 - #define __LONG_MAX__ 0x7fffffffL -#else - #define __LONG_MAX__ 0x7fffffffffffffffL -#endif - #define __SIZEOF_LONG_LONG__ 8 - #define __LONG_LONG_MAX__ 0x7fffffffffffffffLL - #define __CHAR_BIT__ 8 - #define __ORDER_LITTLE_ENDIAN__ 1234 - #define __ORDER_BIG_ENDIAN__ 4321 - #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ -#if defined _WIN32 - #define __WCHAR_TYPE__ unsigned short - #define __WINT_TYPE__ unsigned short -#elif defined __linux__ - #define __WCHAR_TYPE__ int - #define __WINT_TYPE__ unsigned int -#else - #define __WCHAR_TYPE__ int - #define __WINT_TYPE__ int -#endif - - #if __STDC_VERSION__ == 201112L - # define __STDC_NO_ATOMICS__ 1 - # define __STDC_NO_COMPLEX__ 1 - # define __STDC_NO_THREADS__ 1 -#if !defined _WIN32 - # define __STDC_UTF_16__ 1 - # define __STDC_UTF_32__ 1 -#endif - #endif - - #define __ATOMIC_RELAXED 0 - #define __ATOMIC_CONSUME 1 - #define __ATOMIC_ACQUIRE 2 - #define __ATOMIC_RELEASE 3 - #define __ATOMIC_ACQ_REL 4 - #define __ATOMIC_SEQ_CST 5 - -#if defined _WIN32 - #define __declspec(x) __attribute__((x)) - #define __cdecl - -#elif defined __FreeBSD__ - #define __GNUC__ 9 - #define __GNUC_MINOR__ 3 - #define __GNUC_PATCHLEVEL__ 0 - #define __GNUC_STDC_INLINE__ 1 - #define __NO_TLS 1 -# if __SIZEOF_POINTER__ == 8 - /* FIXME, __int128_t is used by setjump */ - #define __int128_t struct { unsigned char _dummy[16] __attribute((aligned(16))); } -# endif - -#elif defined __FreeBSD_kernel__ - -#elif defined __NetBSD__ - #define __GNUC__ 4 - #define __GNUC_MINOR__ 1 - #define __GNUC_PATCHLEVEL__ 0 - #define _Pragma(x) - #define __ELF__ 1 -#if defined __aarch64__ - #define _LOCORE /* avoids usage of __asm */ -#endif - -#elif defined __OpenBSD__ - #define __GNUC__ 4 - #define _ANSI_LIBRARY 1 - -#elif defined __APPLE__ - /* emulate APPLE-GCC to make libc's headerfiles compile: */ - #define __GNUC__ 4 /* darwin emits warning on GCC<4 */ - #define __APPLE_CC__ 1 /* for */ - #define _DONT_USE_CTYPE_INLINE_ 1 - /* avoids usage of GCC/clang specific builtins in libc-headerfiles: */ - #define __FINITE_MATH_ONLY__ 1 - #define _FORTIFY_SOURCE 0 - -#else - /* Linux */ - -#endif - -#if !defined _WIN32 - /* glibc defines */ - #define __REDIRECT(name, proto, alias) name proto __asm__ (#alias) - #define __REDIRECT_NTH(name, proto, alias) name proto __asm__ (#alias) __THROW -#endif - - /* skip __builtin... with -E */ - #ifndef __TCC_PP__ - - #define __builtin_offsetof(type, field) ((__SIZE_TYPE__)&((type*)0)->field) - #define __builtin_extract_return_addr(x) x -#if !defined __linux__ && !defined _WIN32 - /* used by math.h */ - #define __builtin_huge_val() 1e500 - #define __builtin_huge_valf() 1e50f - #define __builtin_huge_vall() 1e5000L -# if defined __APPLE__ - #define __builtin_nanf(ignored_string) __nan() - /* used by floats.h to implement FLT_ROUNDS C99 macro. 1 == to nearest */ - #define __builtin_flt_rounds() 1 - /* used by _fd_def.h */ - #define __builtin_bzero(p, ignored_size) bzero(p, sizeof(*(p))) -# else - #define __builtin_nanf(ignored_string) (0.0F/0.0F) -# endif -#endif - - /* __builtin_va_list */ -#if defined __x86_64__ -#if !defined _WIN32 - /* GCC compatible definition of va_list. */ - /* This should be in sync with the declaration in our lib/libtcc1.c */ - typedef struct { - unsigned gp_offset, fp_offset; - union { - unsigned overflow_offset; - char *overflow_arg_area; - }; - char *reg_save_area; - } __builtin_va_list[1]; - - void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align); - #define __builtin_va_start(ap, last) \ - (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) - #define __builtin_va_arg(ap, t) \ - (*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t)))) - #define __builtin_va_copy(dest, src) (*(dest) = *(src)) - -#else /* _WIN64 */ - typedef char *__builtin_va_list; - #define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \ - ? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8)) -#endif - -#elif defined __arm__ - typedef char *__builtin_va_list; - #define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x) - #define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \ - & ~(_tcc_alignof(type) - 1)) - #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) - #define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \ - &~3), *(type *)(ap - ((sizeof(type)+3)&~3))) - -#elif defined __aarch64__ - typedef struct { - void *__stack, *__gr_top, *__vr_top; - int __gr_offs, __vr_offs; - } __builtin_va_list; - -#elif defined __riscv - typedef char *__builtin_va_list; - #define __va_reg_size (__riscv_xlen >> 3) - #define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \ - & -(__alignof__(type))) - #define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size))))) - -#else /* __i386__ */ - typedef char *__builtin_va_list; - #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) - #define __builtin_va_arg(ap,t) (*(t*)((ap+=(sizeof(t)+3)&~3)-((sizeof(t)+3)&~3))) - -#endif - #define __builtin_va_end(ap) (void)(ap) - #ifndef __builtin_va_copy - # define __builtin_va_copy(dest, src) (dest) = (src) - #endif - - /* TCC BBUILTIN AND BOUNDS ALIASES */ - #ifdef __leading_underscore - # define __RENAME(X) __asm__("_"X) - #else - # define __RENAME(X) __asm__(X) - #endif - #ifdef __BOUNDS_CHECKING_ON - # define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME("__bound_"#name); - # define __BOUND(ret,name,params) ret name params __RENAME("__bound_"#name); - #else - # define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(#name); - # define __BOUND(ret,name,params) - #endif - #define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params) - #define __BUILTIN(ret,name,params) ret __builtin_##name params __RENAME(#name); - - __BOTH(void*, memcpy, (void *, const void*, __SIZE_TYPE__)) - __BOTH(void*, memmove, (void *, const void*, __SIZE_TYPE__)) - __BOTH(void*, memset, (void *, int, __SIZE_TYPE__)) - __BOTH(int, memcmp, (const void *, const void*, __SIZE_TYPE__)) - __BOTH(__SIZE_TYPE__, strlen, (const char *)) - __BOTH(char*, strcpy, (char *, const char *)) - __BOTH(char*, strncpy, (char *, const char*, __SIZE_TYPE__)) - __BOTH(int, strcmp, (const char*, const char*)) - __BOTH(int, strncmp, (const char*, const char*, __SIZE_TYPE__)) - __BOTH(char*, strcat, (char*, const char*)) - __BOTH(char*, strchr, (const char*, int)) - __BOTH(char*, strdup, (const char*)) -#if defined __ARM_EABI__ - __BOUND(void*,__aeabi_memcpy,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memmove,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memmove4,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memmove8,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memset,(void*,int,__SIZE_TYPE__)) -#endif - -#if defined __linux__ || defined __APPLE__ // HAVE MALLOC_REDIR - #define __MAYBE_REDIR __BUILTIN -#else - #define __MAYBE_REDIR __BOTH -#endif - __MAYBE_REDIR(void*, malloc, (__SIZE_TYPE__)) - __MAYBE_REDIR(void*, realloc, (void *, __SIZE_TYPE__)) - __MAYBE_REDIR(void*, calloc, (__SIZE_TYPE__, __SIZE_TYPE__)) - __MAYBE_REDIR(void*, memalign, (__SIZE_TYPE__, __SIZE_TYPE__)) - __MAYBE_REDIR(void, free, (void*)) -#if defined __i386__ || defined __x86_64__ - __BOTH(void*, alloca, (__SIZE_TYPE__)) -#else - __BUILTIN(void*, alloca, (__SIZE_TYPE__)) -#endif - __BUILTIN(void, abort, (void)) - __BOUND(void, longjmp, ()) -#if !defined _WIN32 - __BOUND(void*, mmap, ()) - __BOUND(int, munmap, ()) -#endif - #undef __BUILTINBC - #undef __BUILTIN - #undef __BOUND - #undef __BOTH - #undef __MAYBE_REDIR - #undef __RENAME - - #endif /* ndef __TCC_PP__ */ +/* tccdefs.h + + Nothing is defined before this file except target machine, target os + and the few things related to option settings in tccpp.c:tcc_predefs(). + + This file is either included at runtime as is, or converted and + included as C-strings at compile-time (depending on CONFIG_TCC_PREDEFS). + + Note that line indent matters: + + - in lines starting at column 1, platform macros are replaced by + corresponding TCC target compile-time macros. See conftest.c for + the list of platform macros supported in lines starting at column 1. + + - only lines indented >= 4 are actually included into the executable, + check tccdefs_.h. +*/ + +#if __SIZEOF_POINTER__ == 4 + /* 32bit systems. */ +#if defined TARGETOS_OpenBSD + #define __SIZE_TYPE__ unsigned long + #define __PTRDIFF_TYPE__ long +#else + #define __SIZE_TYPE__ unsigned int + #define __PTRDIFF_TYPE__ int +#endif + #define __ILP32__ 1 + #define __INT64_TYPE__ long long +#elif __SIZEOF_LONG__ == 4 + /* 64bit Windows. */ + #define __SIZE_TYPE__ unsigned long long + #define __PTRDIFF_TYPE__ long long + #define __LLP64__ 1 + #define __INT64_TYPE__ long long +#else + /* Other 64bit systems. */ + #define __SIZE_TYPE__ unsigned long + #define __PTRDIFF_TYPE__ long + #define __LP64__ 1 +# if defined __linux__ + #define __INT64_TYPE__ long +# else /* APPLE, BSD */ + #define __INT64_TYPE__ long long +# endif +#endif + #define __SIZEOF_INT__ 4 + #define __INT_MAX__ 0x7fffffff +#if __SIZEOF_LONG__ == 4 + #define __LONG_MAX__ 0x7fffffffL +#else + #define __LONG_MAX__ 0x7fffffffffffffffL +#endif + #define __SIZEOF_LONG_LONG__ 8 + #define __LONG_LONG_MAX__ 0x7fffffffffffffffLL + #define __CHAR_BIT__ 8 + #define __ORDER_LITTLE_ENDIAN__ 1234 + #define __ORDER_BIG_ENDIAN__ 4321 + #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#if defined _WIN32 + #define __WCHAR_TYPE__ unsigned short + #define __WINT_TYPE__ unsigned short +#elif defined __linux__ + #define __WCHAR_TYPE__ int + #define __WINT_TYPE__ unsigned int +#else + #define __WCHAR_TYPE__ int + #define __WINT_TYPE__ int +#endif + + #if __STDC_VERSION__ == 201112L + # define __STDC_NO_ATOMICS__ 1 + # define __STDC_NO_COMPLEX__ 1 + # define __STDC_NO_THREADS__ 1 +#if !defined _WIN32 + # define __STDC_UTF_16__ 1 + # define __STDC_UTF_32__ 1 +#endif + #endif + + #define __ATOMIC_RELAXED 0 + #define __ATOMIC_CONSUME 1 + #define __ATOMIC_ACQUIRE 2 + #define __ATOMIC_RELEASE 3 + #define __ATOMIC_ACQ_REL 4 + #define __ATOMIC_SEQ_CST 5 + +#if defined _WIN32 + #define __declspec(x) __attribute__((x)) + #define __cdecl + +#elif defined __FreeBSD__ + #define __GNUC__ 9 + #define __GNUC_MINOR__ 3 + #define __GNUC_PATCHLEVEL__ 0 + #define __GNUC_STDC_INLINE__ 1 + #define __NO_TLS 1 +# if __SIZEOF_POINTER__ == 8 + /* FIXME, __int128_t is used by setjump */ + #define __int128_t struct { unsigned char _dummy[16] __attribute((aligned(16))); } +# endif + +#elif defined __FreeBSD_kernel__ + +#elif defined __NetBSD__ + #define __GNUC__ 4 + #define __GNUC_MINOR__ 1 + #define __GNUC_PATCHLEVEL__ 0 + #define _Pragma(x) + #define __ELF__ 1 +#if defined __aarch64__ + #define _LOCORE /* avoids usage of __asm */ +#endif + +#elif defined __OpenBSD__ + #define __GNUC__ 4 + #define _ANSI_LIBRARY 1 + +#elif defined __APPLE__ + /* emulate APPLE-GCC to make libc's headerfiles compile: */ + #define __GNUC__ 4 /* darwin emits warning on GCC<4 */ + #define __APPLE_CC__ 1 /* for */ + #define _DONT_USE_CTYPE_INLINE_ 1 + /* avoids usage of GCC/clang specific builtins in libc-headerfiles: */ + #define __FINITE_MATH_ONLY__ 1 + #define _FORTIFY_SOURCE 0 + +#else + /* Linux */ + +#endif + +#if !defined _WIN32 + /* glibc defines */ + #define __REDIRECT(name, proto, alias) name proto __asm__ (#alias) + #define __REDIRECT_NTH(name, proto, alias) name proto __asm__ (#alias) __THROW +#endif + + /* skip __builtin... with -E */ + #ifndef __TCC_PP__ + + #define __builtin_offsetof(type, field) ((__SIZE_TYPE__)&((type*)0)->field) + #define __builtin_extract_return_addr(x) x +#if !defined __linux__ && !defined _WIN32 + /* used by math.h */ + #define __builtin_huge_val() 1e500 + #define __builtin_huge_valf() 1e50f + #define __builtin_huge_vall() 1e5000L +# if defined __APPLE__ + #define __builtin_nanf(ignored_string) __nan() + /* used by floats.h to implement FLT_ROUNDS C99 macro. 1 == to nearest */ + #define __builtin_flt_rounds() 1 + /* used by _fd_def.h */ + #define __builtin_bzero(p, ignored_size) bzero(p, sizeof(*(p))) +# else + #define __builtin_nanf(ignored_string) (0.0F/0.0F) +# endif +#endif + + /* __builtin_va_list */ +#if defined __x86_64__ +#if !defined _WIN32 + /* GCC compatible definition of va_list. */ + /* This should be in sync with the declaration in our lib/libtcc1.c */ + typedef struct { + unsigned gp_offset, fp_offset; + union { + unsigned overflow_offset; + char *overflow_arg_area; + }; + char *reg_save_area; + } __builtin_va_list[1]; + + void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align); + #define __builtin_va_start(ap, last) \ + (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) + #define __builtin_va_arg(ap, t) \ + (*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t)))) + #define __builtin_va_copy(dest, src) (*(dest) = *(src)) + +#else /* _WIN64 */ + typedef char *__builtin_va_list; + #define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \ + ? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8)) +#endif + +#elif defined __arm__ + typedef char *__builtin_va_list; + #define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x) + #define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \ + & ~(_tcc_alignof(type) - 1)) + #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) + #define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \ + &~3), *(type *)(ap - ((sizeof(type)+3)&~3))) + +#elif defined __aarch64__ + typedef struct { + void *__stack, *__gr_top, *__vr_top; + int __gr_offs, __vr_offs; + } __builtin_va_list; + +#elif defined __riscv + typedef char *__builtin_va_list; + #define __va_reg_size (__riscv_xlen >> 3) + #define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \ + & -(__alignof__(type))) + #define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size))))) + +#else /* __i386__ */ + typedef char *__builtin_va_list; + #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) + #define __builtin_va_arg(ap,t) (*(t*)((ap+=(sizeof(t)+3)&~3)-((sizeof(t)+3)&~3))) + +#endif + #define __builtin_va_end(ap) (void)(ap) + #ifndef __builtin_va_copy + # define __builtin_va_copy(dest, src) (dest) = (src) + #endif + + /* TCC BBUILTIN AND BOUNDS ALIASES */ + #ifdef __leading_underscore + # define __RENAME(X) __asm__("_"X) + #else + # define __RENAME(X) __asm__(X) + #endif + #ifdef __BOUNDS_CHECKING_ON + # define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME("__bound_"#name); + # define __BOUND(ret,name,params) ret name params __RENAME("__bound_"#name); + #else + # define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(#name); + # define __BOUND(ret,name,params) + #endif + #define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params) + #define __BUILTIN(ret,name,params) ret __builtin_##name params __RENAME(#name); + + __BOTH(void*, memcpy, (void *, const void*, __SIZE_TYPE__)) + __BOTH(void*, memmove, (void *, const void*, __SIZE_TYPE__)) + __BOTH(void*, memset, (void *, int, __SIZE_TYPE__)) + __BOTH(int, memcmp, (const void *, const void*, __SIZE_TYPE__)) + __BOTH(__SIZE_TYPE__, strlen, (const char *)) + __BOTH(char*, strcpy, (char *, const char *)) + __BOTH(char*, strncpy, (char *, const char*, __SIZE_TYPE__)) + __BOTH(int, strcmp, (const char*, const char*)) + __BOTH(int, strncmp, (const char*, const char*, __SIZE_TYPE__)) + __BOTH(char*, strcat, (char*, const char*)) + __BOTH(char*, strchr, (const char*, int)) + __BOTH(char*, strdup, (const char*)) +#if defined __ARM_EABI__ + __BOUND(void*,__aeabi_memcpy,(void*,const void*,__SIZE_TYPE__)) + __BOUND(void*,__aeabi_memmove,(void*,const void*,__SIZE_TYPE__)) + __BOUND(void*,__aeabi_memmove4,(void*,const void*,__SIZE_TYPE__)) + __BOUND(void*,__aeabi_memmove8,(void*,const void*,__SIZE_TYPE__)) + __BOUND(void*,__aeabi_memset,(void*,int,__SIZE_TYPE__)) +#endif + +#if defined __linux__ || defined __APPLE__ // HAVE MALLOC_REDIR + #define __MAYBE_REDIR __BUILTIN +#else + #define __MAYBE_REDIR __BOTH +#endif + __MAYBE_REDIR(void*, malloc, (__SIZE_TYPE__)) + __MAYBE_REDIR(void*, realloc, (void *, __SIZE_TYPE__)) + __MAYBE_REDIR(void*, calloc, (__SIZE_TYPE__, __SIZE_TYPE__)) + __MAYBE_REDIR(void*, memalign, (__SIZE_TYPE__, __SIZE_TYPE__)) + __MAYBE_REDIR(void, free, (void*)) +#if defined __i386__ || defined __x86_64__ + __BOTH(void*, alloca, (__SIZE_TYPE__)) +#else + __BUILTIN(void*, alloca, (__SIZE_TYPE__)) +#endif + __BUILTIN(void, abort, (void)) + __BOUND(void, longjmp, ()) +#if !defined _WIN32 + __BOUND(void*, mmap, ()) + __BOUND(int, munmap, ()) +#endif + #undef __BUILTINBC + #undef __BUILTIN + #undef __BOUND + #undef __BOTH + #undef __MAYBE_REDIR + #undef __RENAME + + #endif /* ndef __TCC_PP__ */ diff --git a/tcc/include/tcclib.h b/tcc/include/tcclib.h index 8d59e4c9..b1968a40 100644 --- a/tcc/include/tcclib.h +++ b/tcc/include/tcclib.h @@ -1,80 +1,80 @@ -/* Simple libc header for TCC - * - * Add any function you want from the libc there. This file is here - * only for your convenience so that you do not need to put the whole - * glibc include files on your floppy disk - */ -#ifndef _TCCLIB_H -#define _TCCLIB_H - -#include -#include - -/* stdlib.h */ -void *calloc(size_t nmemb, size_t size); -void *malloc(size_t size); -void free(void *ptr); -void *realloc(void *ptr, size_t size); -int atoi(const char *nptr); -long int strtol(const char *nptr, char **endptr, int base); -unsigned long int strtoul(const char *nptr, char **endptr, int base); -void exit(int); - -/* stdio.h */ -typedef struct __FILE FILE; -#define EOF (-1) -extern FILE *stdin; -extern FILE *stdout; -extern FILE *stderr; -FILE *fopen(const char *path, const char *mode); -FILE *fdopen(int fildes, const char *mode); -FILE *freopen(const char *path, const char *mode, FILE *stream); -int fclose(FILE *stream); -size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); -size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); -int fgetc(FILE *stream); -char *fgets(char *s, int size, FILE *stream); -int getc(FILE *stream); -int getchar(void); -char *gets(char *s); -int ungetc(int c, FILE *stream); -int fflush(FILE *stream); -int putchar (int c); - -int printf(const char *format, ...); -int fprintf(FILE *stream, const char *format, ...); -int sprintf(char *str, const char *format, ...); -int snprintf(char *str, size_t size, const char *format, ...); -int asprintf(char **strp, const char *format, ...); -int dprintf(int fd, const char *format, ...); -int vprintf(const char *format, va_list ap); -int vfprintf(FILE *stream, const char *format, va_list ap); -int vsprintf(char *str, const char *format, va_list ap); -int vsnprintf(char *str, size_t size, const char *format, va_list ap); -int vasprintf(char **strp, const char *format, va_list ap); -int vdprintf(int fd, const char *format, va_list ap); - -void perror(const char *s); - -/* string.h */ -char *strcat(char *dest, const char *src); -char *strchr(const char *s, int c); -char *strrchr(const char *s, int c); -char *strcpy(char *dest, const char *src); -void *memcpy(void *dest, const void *src, size_t n); -void *memmove(void *dest, const void *src, size_t n); -void *memset(void *s, int c, size_t n); -char *strdup(const char *s); -size_t strlen(const char *s); - -/* dlfcn.h */ -#define RTLD_LAZY 0x001 -#define RTLD_NOW 0x002 -#define RTLD_GLOBAL 0x100 - -void *dlopen(const char *filename, int flag); -const char *dlerror(void); -void *dlsym(void *handle, char *symbol); -int dlclose(void *handle); - -#endif /* _TCCLIB_H */ +/* Simple libc header for TCC + * + * Add any function you want from the libc there. This file is here + * only for your convenience so that you do not need to put the whole + * glibc include files on your floppy disk + */ +#ifndef _TCCLIB_H +#define _TCCLIB_H + +#include +#include + +/* stdlib.h */ +void *calloc(size_t nmemb, size_t size); +void *malloc(size_t size); +void free(void *ptr); +void *realloc(void *ptr, size_t size); +int atoi(const char *nptr); +long int strtol(const char *nptr, char **endptr, int base); +unsigned long int strtoul(const char *nptr, char **endptr, int base); +void exit(int); + +/* stdio.h */ +typedef struct __FILE FILE; +#define EOF (-1) +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; +FILE *fopen(const char *path, const char *mode); +FILE *fdopen(int fildes, const char *mode); +FILE *freopen(const char *path, const char *mode, FILE *stream); +int fclose(FILE *stream); +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); +int fgetc(FILE *stream); +char *fgets(char *s, int size, FILE *stream); +int getc(FILE *stream); +int getchar(void); +char *gets(char *s); +int ungetc(int c, FILE *stream); +int fflush(FILE *stream); +int putchar (int c); + +int printf(const char *format, ...); +int fprintf(FILE *stream, const char *format, ...); +int sprintf(char *str, const char *format, ...); +int snprintf(char *str, size_t size, const char *format, ...); +int asprintf(char **strp, const char *format, ...); +int dprintf(int fd, const char *format, ...); +int vprintf(const char *format, va_list ap); +int vfprintf(FILE *stream, const char *format, va_list ap); +int vsprintf(char *str, const char *format, va_list ap); +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +int vasprintf(char **strp, const char *format, va_list ap); +int vdprintf(int fd, const char *format, va_list ap); + +void perror(const char *s); + +/* string.h */ +char *strcat(char *dest, const char *src); +char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); +char *strcpy(char *dest, const char *src); +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); +char *strdup(const char *s); +size_t strlen(const char *s); + +/* dlfcn.h */ +#define RTLD_LAZY 0x001 +#define RTLD_NOW 0x002 +#define RTLD_GLOBAL 0x100 + +void *dlopen(const char *filename, int flag); +const char *dlerror(void); +void *dlsym(void *handle, char *symbol); +int dlclose(void *handle); + +#endif /* _TCCLIB_H */ diff --git a/tcc/include/tchar.h b/tcc/include/tchar.h index cd44beca..e48c59ce 100644 --- a/tcc/include/tchar.h +++ b/tcc/include/tchar.h @@ -1,1102 +1,1102 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#include <_mingw.h> - -#ifndef _INC_TCHAR -#define _INC_TCHAR - -#ifdef _STRSAFE_H_INCLUDED_ -#error Need to include strsafe.h after tchar.h -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define _ftcscat _tcscat -#define _ftcschr _tcschr -#define _ftcscpy _tcscpy -#define _ftcscspn _tcscspn -#define _ftcslen _tcslen -#define _ftcsncat _tcsncat -#define _ftcsncpy _tcsncpy -#define _ftcspbrk _tcspbrk -#define _ftcsrchr _tcsrchr -#define _ftcsspn _tcsspn -#define _ftcsstr _tcsstr -#define _ftcstok _tcstok - -#define _ftcsdup _tcsdup -#define _ftcsnset _tcsnset -#define _ftcsrev _tcsrev -#define _ftcsset _tcsset - -#define _ftcscmp _tcscmp -#define _ftcsicmp _tcsicmp -#define _ftcsnccmp _tcsnccmp -#define _ftcsncmp _tcsncmp -#define _ftcsncicmp _tcsncicmp -#define _ftcsnicmp _tcsnicmp - -#define _ftcscoll _tcscoll -#define _ftcsicoll _tcsicoll -#define _ftcsnccoll _tcsnccoll -#define _ftcsncoll _tcsncoll -#define _ftcsncicoll _tcsncicoll -#define _ftcsnicoll _tcsnicoll - -#define _ftcsclen _tcsclen -#define _ftcsnccat _tcsnccat -#define _ftcsnccpy _tcsnccpy -#define _ftcsncset _tcsncset - -#define _ftcsdec _tcsdec -#define _ftcsinc _tcsinc -#define _ftcsnbcnt _tcsnbcnt -#define _ftcsnccnt _tcsnccnt -#define _ftcsnextc _tcsnextc -#define _ftcsninc _tcsninc -#define _ftcsspnp _tcsspnp - -#define _ftcslwr _tcslwr -#define _ftcsupr _tcsupr - -#define _ftclen _tclen -#define _ftccpy _tccpy -#define _ftccmp _tccmp - -#ifndef _CONST_RETURN -#ifdef __cplusplus -#define _CONST_RETURN const -#define _CRT_CONST_CORRECT_OVERLOADS -#else -#define _CONST_RETURN -#endif -#endif - -#define _WConst_return _CONST_RETURN - -#ifdef _UNICODE - -#ifdef __cplusplus -} -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _WCTYPE_T_DEFINED -#define _WCTYPE_T_DEFINED - typedef unsigned short wint_t; - typedef unsigned short wctype_t; -#endif - -#ifndef __TCHAR_DEFINED -#define __TCHAR_DEFINED - typedef wchar_t _TCHAR; - typedef wchar_t _TSCHAR; - typedef wchar_t _TUCHAR; - typedef wchar_t _TXCHAR; - typedef wint_t _TINT; -#endif - -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED -#ifndef NO_OLDNAMES - typedef wchar_t TCHAR; -#endif -#endif - -#define _TEOF WEOF - -#define __T(x) L##x - -#define _tmain wmain -#define _tWinMain wWinMain -#define _tenviron _wenviron -#define __targv __wargv - -#define _tprintf wprintf -#define _tprintf_l _wprintf_l -#define _tprintf_p _wprintf_p -#define _tprintf_p_l _wprintf_p_l -#define _tcprintf _cwprintf -#define _tcprintf_l _cwprintf_l -#define _tcprintf_p _cwprintf_p -#define _tcprintf_p_l _cwprintf_p_l -#define _vtcprintf _vcwprintf -#define _vtcprintf_l _vcwprintf_l -#define _vtcprintf_p _vcwprintf_p -#define _vtcprintf_p_l _vcwprintf_p_l -#define _ftprintf fwprintf -#define _ftprintf_l _fwprintf_l -#define _ftprintf_p _fwprintf_p -#define _ftprintf_p_l _fwprintf_p_l -#define _stprintf swprintf -#define _stprintf_l __swprintf_l -#define _stprintf_p _swprintf_p -#define _stprintf_p_l _swprintf_p_l -#define _sctprintf _scwprintf -#define _sctprintf_l _scwprintf_l -#define _sctprintf_p _scwprintf_p -#define _sctprintf_p_l _scwprintf_p_l -#define _sntprintf _snwprintf -#define _sntprintf_l _snwprintf_l -#define _vtprintf vwprintf -#define _vtprintf_l _vwprintf_l -#define _vtprintf_p _vwprintf_p -#define _vtprintf_p_l _vwprintf_p_l -#define _vftprintf vfwprintf -#define _vftprintf_l _vfwprintf_l -#define _vftprintf_p _vfwprintf_p -#define _vftprintf_p_l _vfwprintf_p_l -#define _vstprintf vswprintf -#define _vstprintf_l _vswprintf_l -#define _vstprintf_p _vswprintf_p -#define _vstprintf_p_l _vswprintf_p_l -#define _vsctprintf _vscwprintf -#define _vsctprintf_l _vscwprintf_l -#define _vsctprintf_p _vscwprintf_p -#define _vsctprintf_p_l _vscwprintf_p_l -#define _vsntprintf _vsnwprintf -#define _vsntprintf_l _vsnwprintf_l - -#define _tscanf wscanf -#define _tscanf_l _wscanf_l -#define _tcscanf _cwscanf -#define _tcscanf_l _cwscanf_l -#define _ftscanf fwscanf -#define _ftscanf_l _fwscanf_l -#define _stscanf swscanf -#define _stscanf_l _swscanf_l -#define _sntscanf _snwscanf -#define _sntscanf_l _snwscanf_l - -#define _fgettc fgetwc -#define _fgettc_nolock _fgetwc_nolock -#define _fgettchar _fgetwchar -#define _fgetts fgetws -#define _fputtc fputwc -#define _fputtc_nolock _fputwc_nolock -#define _fputtchar _fputwchar -#define _fputts fputws -#define _cputts _cputws -#define _cgetts _cgetws -#define _gettc getwc -#define _gettc_nolock _getwc_nolock -#define _gettch _getwch -#define _gettch_nolock _getwch_nolock -#define _gettche _getwche -#define _gettche_nolock _getwche_nolock -#define _gettchar getwchar -#define _gettchar_nolock _getwchar_nolock -#define _getts _getws -#define _puttc putwc -#define _puttc_nolock _putwc_nolock -#define _puttchar putwchar -#define _puttchar_nolock _putwchar_nolock -#define _puttch _putwch -#define _puttch_nolock _putwch_nolock -#define _putts _putws -#define _ungettc ungetwc -#define _ungettc_nolock _ungetwc_nolock -#define _ungettch _ungetwch -#define _ungettch_nolock _ungetwch_nolock - -#define _tcstod wcstod -#define _tcstol wcstol -#define _tcstoul wcstoul -#define _tcstoi64 _wcstoi64 -#define _tcstoui64 _wcstoui64 -#define _tstof _wtof -#define _tstol _wtol -#define _tstoi _wtoi -#define _tstoi64 _wtoi64 -#define _tcstod_l _wcstod_l -#define _tcstol_l _wcstol_l -#define _tcstoul_l _wcstoul_l -#define _tcstoi64_l _wcstoi64_l -#define _tcstoui64_l _wcstoui64_l -#define _tstof_l _wtof_l -#define _tstol_l _wtol_l -#define _tstoi_l _wtoi_l -#define _tstoi64_l _wtoi64_l - -#define _itot _itow -#define _ltot _ltow -#define _ultot _ultow -#define _ttoi _wtoi -#define _ttol _wtol - -#define _ttoi64 _wtoi64 -#define _i64tot _i64tow -#define _ui64tot _ui64tow - -#define _tcscat wcscat -#define _tcschr wcschr -#define _tcscpy wcscpy -#define _tcscspn wcscspn -#define _tcslen wcslen -#define _tcsnlen wcsnlen -#define _tcsncat wcsncat -#define _tcsncat_l _wcsncat_l -#define _tcsncpy wcsncpy -#define _tcsncpy_l _wcsncpy_l -#define _tcspbrk wcspbrk -#define _tcsrchr wcsrchr -#define _tcsspn wcsspn -#define _tcsstr wcsstr -#define _tcstok wcstok -#define _tcstok_l _wcstok_l -#define _tcserror _wcserror -#define __tcserror __wcserror - -#define _tcsdup _wcsdup -#define _tcsnset _wcsnset -#define _tcsnset_l _wcsnset_l -#define _tcsrev _wcsrev -#define _tcsset _wcsset -#define _tcsset_l _wcsset_l - -#define _tcscmp wcscmp -#define _tcsicmp _wcsicmp -#define _tcsicmp_l _wcsicmp_l -#define _tcsnccmp wcsncmp -#define _tcsncmp wcsncmp -#define _tcsncicmp _wcsnicmp -#define _tcsncicmp_l _wcsnicmp_l -#define _tcsnicmp _wcsnicmp -#define _tcsnicmp_l _wcsnicmp_l - -#define _tcscoll wcscoll -#define _tcscoll_l _wcscoll_l -#define _tcsicoll _wcsicoll -#define _tcsicoll_l _wcsicoll_l -#define _tcsnccoll _wcsncoll -#define _tcsnccoll_l _wcsncoll_l -#define _tcsncoll _wcsncoll -#define _tcsncoll_l _wcsncoll_l -#define _tcsncicoll _wcsnicoll -#define _tcsncicoll_l _wcsnicoll_l -#define _tcsnicoll _wcsnicoll -#define _tcsnicoll_l _wcsnicoll_l - -#define _texecl _wexecl -#define _texecle _wexecle -#define _texeclp _wexeclp -#define _texeclpe _wexeclpe -#define _texecv _wexecv -#define _texecve _wexecve -#define _texecvp _wexecvp -#define _texecvpe _wexecvpe - -#define _tspawnl _wspawnl -#define _tspawnle _wspawnle -#define _tspawnlp _wspawnlp -#define _tspawnlpe _wspawnlpe -#define _tspawnv _wspawnv -#define _tspawnve _wspawnve -#define _tspawnvp _wspawnvp -#define _tspawnvp _wspawnvp -#define _tspawnvpe _wspawnvpe - -#define _tsystem _wsystem - -#define _tasctime _wasctime -#define _tctime _wctime -#define _tctime32 _wctime32 -#define _tctime64 _wctime64 -#define _tstrdate _wstrdate -#define _tstrtime _wstrtime -#define _tutime _wutime -#define _tutime32 _wutime32 -#define _tutime64 _wutime64 -#define _tcsftime wcsftime -#define _tcsftime_l _wcsftime_l - -#define _tchdir _wchdir -#define _tgetcwd _wgetcwd -#define _tgetdcwd _wgetdcwd -#define _tgetdcwd_nolock _wgetdcwd_nolock -#define _tmkdir _wmkdir -#define _trmdir _wrmdir - -#define _tfullpath _wfullpath -#define _tgetenv _wgetenv -#define _tmakepath _wmakepath -#define _tpgmptr _wpgmptr -#define _get_tpgmptr _get_wpgmptr -#define _tputenv _wputenv -#define _tsearchenv _wsearchenv -#define _tsplitpath _wsplitpath - -#define _tfdopen _wfdopen -#define _tfsopen _wfsopen -#define _tfopen _wfopen -#define _tfreopen _wfreopen -#define _tperror _wperror -#define _tpopen _wpopen -#define _ttempnam _wtempnam -#define _ttmpnam _wtmpnam - -#define _taccess _waccess -#define _tchmod _wchmod -#define _tcreat _wcreat -#define _tfindfirst _wfindfirst -#define _tfindfirst32 _wfindfirst32 -#define _tfindfirst64 _wfindfirst64 -#define _tfindfirsti64 _wfindfirsti64 -#define _tfindfirst32i64 _wfindfirst32i64 -#define _tfindfirst64i32 _wfindfirst64i32 -#define _tfindnext _wfindnext -#define _tfindnext32 _wfindnext32 -#define _tfindnext64 _wfindnext64 -#define _tfindnexti64 _wfindnexti64 -#define _tfindnext32i64 _wfindnext32i64 -#define _tfindnext64i32 _wfindnext64i32 -#define _tmktemp _wmktemp -#define _topen _wopen -#define _tremove _wremove -#define _trename _wrename -#define _tsopen _wsopen -#define _tunlink _wunlink - -#define _tfinddata_t _wfinddata_t -#define _tfinddata32_t _wfinddata32_t -#define _tfinddata64_t _wfinddata64_t -#define _tfinddatai64_t _wfinddatai64_t -#define _tfinddata32i64_t _wfinddata32i64_t -#define _tfinddata64i32_t _wfinddata64i32_t - -#define _tstat _wstat -#define _tstat32 _wstat32 -#define _tstat32i64 _wstat32i64 -#define _tstat64 _wstat64 -#define _tstat64i32 _wstat64i32 -#define _tstati64 _wstati64 - -#define _tsetlocale _wsetlocale - -#define _tcsclen wcslen -#define _tcscnlen wcsnlen -#define _tcsclen_l(_String,_Locale) wcslen(_String) -#define _tcscnlen_l(_String,_Max_count,_Locale) wcsnlen_l((_String),(_Max_count)) -#define _tcsnccat wcsncat -#define _tcsnccat_l _wcsncat_l -#define _tcsnccpy wcsncpy -#define _tcsnccpy_l _wcsncpy_l -#define _tcsncset _wcsnset - -#define _tcsdec _wcsdec -#define _tcsinc _wcsinc -#define _tcsnbcnt _wcsncnt -#define _tcsnccnt _wcsncnt -#define _tcsnextc _wcsnextc -#define _tcsninc _wcsninc -#define _tcsspnp _wcsspnp - -#define _tcslwr _wcslwr -#define _tcslwr_l _wcslwr_l -#define _tcsupr _wcsupr -#define _tcsupr_l _wcsupr_l -#define _tcsxfrm wcsxfrm -#define _tcsxfrm_l _wcsxfrm_l - -#define _tclen(_pc) (1) -#define _tccpy(_pc1,_cpc2) ((*(_pc1) = *(_cpc2))) -#define _tccmp(_cpc1,_cpc2) ((*(_cpc1))-(*(_cpc2))) - -#define _istalnum iswalnum -#define _istalnum_l _iswalnum_l -#define _istalpha iswalpha -#define _istalpha_l _iswalpha_l -#define _istascii iswascii -#define _istcntrl iswcntrl -#define _istcntrl_l _iswcntrl_l -#define _istdigit iswdigit -#define _istdigit_l _iswdigit_l -#define _istgraph iswgraph -#define _istgraph_l _iswgraph_l -#define _istlower iswlower -#define _istlower_l _iswlower_l -#define _istprint iswprint -#define _istprint_l _iswprint_l -#define _istpunct iswpunct -#define _istpunct_l _iswpunct_l -#define _istspace iswspace -#define _istspace_l _iswspace_l -#define _istupper iswupper -#define _istupper_l _iswupper_l -#define _istxdigit iswxdigit -#define _istxdigit_l _iswxdigit_l - -#define _totupper towupper -#define _totupper_l _towupper_l -#define _totlower towlower -#define _totlower_l _towlower_l - -#define _istlegal(_Char) (1) -#define _istlead(_Char) (0) -#define _istleadbyte(_Char) (0) -#define _istleadbyte_l(_Char,_Locale) (0) - -#define _wcsdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) -#define _wcsinc(_pc) ((_pc)+1) -#define _wcsnextc(_cpc) ((unsigned int) *(_cpc)) -#define _wcsninc(_pc,_sz) (((_pc)+(_sz))) - _CRTIMP size_t __cdecl __wcsncnt(const wchar_t *_Str,size_t _MaxCount); -#define _wcsncnt(_cpc,_sz) (__wcsncnt(_cpc,_sz)) -#define _wcsspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+wcsspn(_cpc1,_cpc2))) ? ((_cpc1)+wcsspn(_cpc1,_cpc2)) : NULL)) -#define _wcsncpy_l(_Destination,_Source,_Count,_Locale) (wcsncpy(_Destination,_Source,_Count)) -#define _wcsncat_l(_Destination,_Source,_Count,_Locale) (wcsncat(_Destination,_Source,_Count)) -#define _wcstok_l(_String,_Delimiters,_Locale) (wcstok(_String,_Delimiters)) -#define _wcsnset_l(_Destination,_Value,_Count,_Locale) (_wcsnset(_Destination,_Value,_Count)) -#define _wcsset_l(_Destination,_Value,_Locale) (_wcsset(_Destination,_Value)) - - /* dirent structures and functions */ -#define _tdirent _wdirent -#define _TDIR _WDIR -#define _topendir _wopendir -#define _tclosedir _wclosedir -#define _treaddir _wreaddir -#define _trewinddir _wrewinddir -#define _ttelldir _wtelldir -#define _tseekdir _wseekdir - -#else - -#ifdef __cplusplus -} -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define _TEOF EOF - -#define __T(x) x - -#define _tmain main -#define _tWinMain WinMain -#ifdef _POSIX_ -#define _tenviron environ -#else -#define _tenviron _environ -#endif -#define __targv __argv - -#define _tprintf printf -#define _tprintf_l _printf_l -#define _tprintf_p _printf_p -#define _tprintf_p_l _printf_p_l -#define _tcprintf _cprintf -#define _tcprintf_l _cprintf_l -#define _tcprintf_p _cprintf_p -#define _tcprintf_p_l _cprintf_p_l -#define _vtcprintf _vcprintf -#define _vtcprintf_l _vcprintf_l -#define _vtcprintf_p _vcprintf_p -#define _vtcprintf_p_l _vcprintf_p_l -#define _ftprintf fprintf -#define _ftprintf_l _fprintf_l -#define _ftprintf_p _fprintf_p -#define _ftprintf_p_l _fprintf_p_l -#define _stprintf sprintf -#define _stprintf_l _sprintf_l -#define _stprintf_p _sprintf_p -#define _stprintf_p_l _sprintf_p_l -#define _sctprintf _scprintf -#define _sctprintf_l _scprintf_l -#define _sctprintf_p _scprintf_p -#define _sctprintf_p_l _scprintf_p_l -#define _sntprintf _snprintf -#define _sntprintf_l _snprintf_l -#define _vtprintf vprintf -#define _vtprintf_l _vprintf_l -#define _vtprintf_p _vprintf_p -#define _vtprintf_p_l _vprintf_p_l -#define _vftprintf vfprintf -#define _vftprintf_l _vfprintf_l -#define _vftprintf_p _vfprintf_p -#define _vftprintf_p_l _vfprintf_p_l -#define _vstprintf vsprintf -#define _vstprintf_l _vsprintf_l -#define _vstprintf_p _vsprintf_p -#define _vstprintf_p_l _vsprintf_p_l -#define _vsctprintf _vscprintf -#define _vsctprintf_l _vscprintf_l -#define _vsctprintf_p _vscprintf_p -#define _vsctprintf_p_l _vscprintf_p_l -#define _vsntprintf _vsnprintf -#define _vsntprintf_l _vsnprintf_l - -#define _tscanf scanf -#define _tscanf_l _scanf_l -#define _tcscanf _cscanf -#define _tcscanf_l _cscanf_l -#define _ftscanf fscanf -#define _ftscanf_l _fscanf_l -#define _stscanf sscanf -#define _stscanf_l _sscanf_l -#define _sntscanf _snscanf -#define _sntscanf_l _snscanf_l - -#define _fgettc fgetc -#define _fgettc_nolock _fgetc_nolock -#define _fgettchar _fgetchar -#define _fgetts fgets -#define _fputtc fputc -#define _fputtc_nolock _fputc_nolock -#define _fputtchar _fputchar -#define _fputts fputs -#define _cputts _cputs -#define _gettc getc -#define _gettc_nolock _getc_nolock -#define _gettch _getch -#define _gettch_nolock _getch_nolock -#define _gettche _getche -#define _gettche_nolock _getche_nolock -#define _gettchar getchar -#define _gettchar_nolock _getchar_nolock -#define _getts gets -#define _cgetts _cgets -#define _puttc putc -#define _puttc_nolock _putc_nolock -#define _puttchar putchar -#define _puttchar_nolock _putchar_nolock -#define _puttch _putch -#define _puttch_nolock _putch_nolock -#define _putts puts -#define _ungettc ungetc -#define _ungettc_nolock _ungetc_nolock -#define _ungettch _ungetch -#define _ungettch_nolock _ungetch_nolock - -#define _tcstod strtod -#define _tcstol strtol -#define _tcstoul strtoul -#define _tstof atof -#define _tstol atol -#define _tstoi atoi -#define _tstoi64 _atoi64 -#define _tcstod_l _strtod_l -#define _tcstol_l _strtol_l -#define _tcstoul_l _strtoul_l -#define _tstof_l _atof_l -#define _tstol_l _atol_l -#define _tstoi_l _atoi_l -#define _tstoi64_l _atoi64_l - -#define _itot _itoa -#define _ltot _ltoa -#define _ultot _ultoa -#define _ttoi atoi -#define _ttol atol - -#define _ttoi64 _atoi64 -#define _tcstoi64 _strtoi64 -#define _tcstoi64_l _strtoi64_l -#define _tcstoui64 _strtoui64 -#define _tcstoui64_l _strtoui64_l -#define _i64tot _i64toa -#define _ui64tot _ui64toa - -#define _tcscat strcat -#define _tcscpy strcpy -#define _tcsdup _strdup -#define _tcslen strlen -#if 0 -#define _tcsnlen strnlen -#endif -#define _tcsxfrm strxfrm -#define _tcsxfrm_l _strxfrm_l -#define _tcserror strerror -#define __tcserror _strerror - -#define _texecl _execl -#define _texecle _execle -#define _texeclp _execlp -#define _texeclpe _execlpe -#define _texecv _execv -#define _texecve _execve -#define _texecvp _execvp -#define _texecvpe _execvpe - -#define _tspawnl _spawnl -#define _tspawnle _spawnle -#define _tspawnlp _spawnlp -#define _tspawnlpe _spawnlpe -#define _tspawnv _spawnv -#define _tspawnve _spawnve -#define _tspawnvp _spawnvp -#define _tspawnvpe _spawnvpe - -#define _tsystem system - -#define _tasctime asctime -#define _tctime ctime -#define _tctime32 _ctime32 -#define _tctime64 _ctime64 -#define _tstrdate _strdate -#define _tstrtime _strtime -#define _tutime _utime -#define _tutime32 _utime32 -#define _tutime64 _utime64 -#define _tcsftime strftime -#define _tcsftime_l _strftime_l - -#define _tchdir _chdir -#define _tgetcwd _getcwd -#define _tgetdcwd _getdcwd -#define _tgetdcwd_nolock _getdcwd_nolock -#define _tmkdir _mkdir -#define _trmdir _rmdir - -#define _tfullpath _fullpath -#define _tgetenv getenv -#define _tmakepath _makepath -#define _tpgmptr _pgmptr -#define _get_tpgmptr _get_pgmptr -#define _tputenv _putenv -#define _tsearchenv _searchenv -#define _tsplitpath _splitpath - -#ifdef _POSIX_ -#define _tfdopen fdopen -#else -#define _tfdopen _fdopen -#endif -#define _tfsopen _fsopen -#define _tfopen fopen -#define _tfreopen freopen -#define _tperror perror -#define _tpopen _popen -#define _ttempnam _tempnam -#define _ttmpnam tmpnam - -#define _tchmod _chmod -#define _tcreat _creat -#define _tfindfirst _findfirst -#define _tfindfirst32 _findfirst32 -#define _tfindfirst64 _findfirst64 -#define _tfindfirsti64 _findfirsti64 -#define _tfindfirst32i64 _findfirst32i64 -#define _tfindfirst64i32 _findfirst64i32 -#define _tfindnext _findnext -#define _tfindnext32 _findnext32 -#define _tfindnext64 _findnext64 -#define _tfindnexti64 _findnexti64 -#define _tfindnext32i64 _findnext32i64 -#define _tfindnext64i32 _findnext64i32 -#define _tmktemp _mktemp - -#ifdef _POSIX_ -#define _topen open -#define _taccess access -#else -#define _topen _open -#define _taccess _access -#endif - -#define _tremove remove -#define _trename rename -#define _tsopen _sopen -#define _tunlink _unlink - -#define _tfinddata_t _finddata_t -#define _tfinddata32_t _finddata32_t -#define _tfinddata64_t __finddata64_t -#define _tfinddatai64_t _finddatai64_t -#define _tfinddata32i64_t _finddata32i64_t -#define _tfinddata64i32_t _finddata64i32_t - -#define _istascii __isascii -#define _istcntrl iscntrl -#define _istcntrl_l _iscntrl_l -#define _istxdigit isxdigit -#define _istxdigit_l _isxdigit_l - -#define _tstat _stat -#define _tstat32 _stat32 -#define _tstat32i64 _stat32i64 -#define _tstat64 _stat64 -#define _tstat64i32 _stat64i32 -#define _tstati64 _stati64 - -#define _tsetlocale setlocale - -#ifdef _MBCS - -#ifdef __cplusplus -} -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __TCHAR_DEFINED - typedef char _TCHAR; - typedef signed char _TSCHAR; - typedef unsigned char _TUCHAR; - typedef unsigned char _TXCHAR; - typedef unsigned int _TINT; -#define __TCHAR_DEFINED -#endif - -#ifndef _TCHAR_DEFINED -#ifndef NO_OLDNAMES - typedef char TCHAR; -#endif -#define _TCHAR_DEFINED -#endif - -#ifdef _MB_MAP_DIRECT - -#define _tcschr _mbschr -#define _tcscspn _mbscspn -#define _tcsncat _mbsnbcat -#define _tcsncat_l _mbsnbcat_l -#define _tcsncpy _mbsnbcpy -#define _tcsncpy_l _mbsnbcpy_l -#define _tcspbrk _mbspbrk -#define _tcsrchr _mbsrchr -#define _tcsspn _mbsspn -#define _tcsstr _mbsstr -#define _tcstok _mbstok -#define _tcstok_l _mbstok_l - -#define _tcsnset _mbsnbset -#define _tcsnset_l _mbsnbset_l -#define _tcsrev _mbsrev -#define _tcsset _mbsset -#define _tcsset_l _mbsset_l - -#define _tcscmp _mbscmp -#define _tcsicmp _mbsicmp -#define _tcsicmp_l _mbsicmp_l -#define _tcsnccmp _mbsncmp -#define _tcsncmp _mbsnbcmp -#define _tcsncicmp _mbsnicmp -#define _tcsncicmp_l _mbsnicmp_l -#define _tcsnicmp _mbsnbicmp -#define _tcsnicmp_l _mbsnbicmp_l - -#define _tcscoll _mbscoll -#define _tcscoll_l _mbscoll_l -#define _tcsicoll _mbsicoll -#define _tcsicoll_l _mbsicoll_l -#define _tcsnccoll _mbsncoll -#define _tcsnccoll_l _mbsncoll_l -#define _tcsncoll _mbsnbcoll -#define _tcsncoll_l _mbsnbcoll_l -#define _tcsncicoll _mbsnicoll -#define _tcsncicoll_l _mbsnicoll_l -#define _tcsnicoll _mbsnbicoll -#define _tcsnicoll_l _mbsnbicoll_l - -#define _tcsclen _mbslen -#define _tcscnlen _mbsnlen -#define _tcsclen_l _mbslen_l -#define _tcscnlen_l _mbsnlen_l -#define _tcsnccat _mbsncat -#define _tcsnccat_l _mbsncat_l -#define _tcsnccpy _mbsncpy -#define _tcsnccpy_l _mbsncpy_l -#define _tcsncset _mbsnset -#define _tcsncset_l _mbsnset_l - -#define _tcsdec _mbsdec -#define _tcsinc _mbsinc -#define _tcsnbcnt _mbsnbcnt -#define _tcsnccnt _mbsnccnt -#define _tcsnextc _mbsnextc -#define _tcsninc _mbsninc -#define _tcsspnp _mbsspnp - -#define _tcslwr _mbslwr -#define _tcslwr_l _mbslwr_l -#define _tcsupr _mbsupr -#define _tcsupr_l _mbsupr_l - -#define _tclen _mbclen -#define _tccpy _mbccpy -#define _tccpy_l _mbccpy_l -#else - - _CRTIMP _CONST_RETURN char *__cdecl _tcschr(const char *_Str,unsigned int _Val); - _CRTIMP size_t __cdecl _tcscspn(const char *_Str,const char *_Control); - _CRTIMP char *__cdecl _tcsncat(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsncpy(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP _CONST_RETURN char *__cdecl _tcspbrk(const char *_Str,const char *_Control); - _CRTIMP _CONST_RETURN char *__cdecl _tcsrchr(const char *_Str,unsigned int _Ch); - _CRTIMP size_t __cdecl _tcsspn(const char *_Str,const char *_Control); - _CRTIMP _CONST_RETURN char *__cdecl _tcsstr(const char *_Str,const char *_Substr); - _CRTIMP char *__cdecl _tcstok(char *_Str,const char *_Delim); - _CRTIMP char *__cdecl _tcstok_l(char *_Str,const char *_Delim,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnset(char *_Str,unsigned int _Val,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsrev(char *_Str); - _CRTIMP char *__cdecl _tcsset(char *_Str,unsigned int _Val); - _CRTIMP char *__cdecl _tcsset_l(char *_Str,unsigned int _Val,_locale_t _Locale); - _CRTIMP int __cdecl _tcscmp(const char *_Str1,const char *_Str); - _CRTIMP int __cdecl _tcsicmp(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _tcsicmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnccmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcscoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _tcscoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _tcsicoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _tcsicoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnccoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsnccoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsncoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsncicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP size_t __cdecl _tcsclen(const char *_Str); - _CRTIMP size_t __cdecl _tcscnlen(const char *_Str,size_t _MaxCount); - _CRTIMP size_t __cdecl _tcsclen_l(const char *_Str,_locale_t _Locale); - _CRTIMP size_t __cdecl _tcscnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccat(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccpy(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsncset(char *_Str,unsigned int _Val,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsdec(const char *_Start,const char *_Pos); - _CRTIMP char *__cdecl _tcsinc(const char *_Ptr); - _CRTIMP size_t __cdecl _tcsnbcnt(const char *_Str,size_t _MaxCount); - _CRTIMP size_t __cdecl _tcsnccnt(const char *_Str,size_t _MaxCount); - _CRTIMP unsigned int __cdecl _tcsnextc (const char *_Str); - _CRTIMP char *__cdecl _tcsninc(const char *_Ptr,size_t _Count); - _CRTIMP char *__cdecl _tcsspnp(const char *_Str1,const char *_Str2); - _CRTIMP char *__cdecl _tcslwr(char *_Str); - _CRTIMP char *__cdecl _tcslwr_l(char *_Str,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsupr(char *_Str); - _CRTIMP char *__cdecl _tcsupr_l(char *_Str,_locale_t _Locale); - _CRTIMP size_t __cdecl _tclen(const char *_Str); - _CRTIMP void __cdecl _tccpy(char *_DstCh,const char *_SrcCh); - -#ifdef __cplusplus -#ifndef _CPP_TCHAR_INLINES_DEFINED -#define _CPP_TCHAR_INLINES_DEFINED - extern "C++" { - extern inline char *__cdecl _tcschr(char *_S,unsigned int _C) { return ((char *)_tcschr((const char *)_S,_C)); } - extern inline char *__cdecl _tcspbrk(char *_S,const char *_P) { return ((char *)_tcspbrk((const char *)_S,_P)); } - extern inline char *__cdecl _tcsrchr(char *_S,unsigned int _C) { return ((char *)_tcsrchr((const char *)_S,_C)); } - extern inline char *__cdecl _tcsstr(char *_S,const char *_P) { return ((char *)_tcsstr((const char *)_S,_P)); } - } -#endif -#endif -#endif - -#define _tccmp(_cp1,_cp2) _tcsnccmp(_cp1,_cp2,1) - -#define _istalnum _ismbcalnum -#define _istalnum_l _ismbcalnum_l -#define _istalpha _ismbcalpha -#define _istalpha_l _ismbcalpha_l -#define _istdigit _ismbcdigit -#define _istdigit_l _ismbcdigit_l -#define _istgraph _ismbcgraph -#define _istgraph_l _ismbcgraph_l -#define _istlegal _ismbclegal -#define _istlegal_l _ismbclegal_l -#define _istlower _ismbclower -#define _istlower_l _ismbclower_l -#define _istprint _ismbcprint -#define _istprint_l _ismbcprint_l -#define _istpunct _ismbcpunct -#define _istpunct_l _ismbcpunct_l -#define _istspace _ismbcspace -#define _istspace_l _ismbcspace_l -#define _istupper _ismbcupper -#define _istupper_l _ismbcupper_l - -#define _totupper _mbctoupper -#define _totupper_l _mbctoupper_l -#define _totlower _mbctolower -#define _totlower_l _mbctolower_l - -#define _istlead _ismbblead -#define _istleadbyte isleadbyte -#define _istleadbyte_l _isleadbyte_l -#else - -#ifndef __TCHAR_DEFINED -#define __TCHAR_DEFINED - typedef char _TCHAR; - typedef signed char _TSCHAR; - typedef unsigned char _TUCHAR; - typedef char _TXCHAR; - typedef int _TINT; -#endif - -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED -#ifndef NO_OLDNAMES - typedef char TCHAR; -#endif -#endif - -#define _tcschr strchr -#define _tcscspn strcspn -#define _tcsncat strncat -#define _tcsncat_l _strncat_l -#define _tcsncpy strncpy -#define _tcsncpy_l _strncpy_l -#define _tcspbrk strpbrk -#define _tcsrchr strrchr -#define _tcsspn strspn -#define _tcsstr strstr -#define _tcstok strtok -#define _tcstok_l _strtok_l - -#define _tcsnset _strnset -#define _tcsnset_l _strnset_l -#define _tcsrev _strrev -#define _tcsset _strset - -#define _tcscmp strcmp -#define _tcsicmp _stricmp -#define _tcsicmp_l _stricmp_l -#define _tcsnccmp strncmp -#define _tcsncmp strncmp -#define _tcsncicmp _strnicmp -#define _tcsncicmp_l _strnicmp_l -#define _tcsnicmp _strnicmp -#define _tcsnicmp_l _strnicmp_l - -#define _tcscoll strcoll -#define _tcscoll_l _strcoll_l -#define _tcsicoll _stricoll -#define _tcsicoll_l _stricoll_l -#define _tcsnccoll _strncoll -#define _tcsnccoll_l _strncoll_l -#define _tcsncoll _strncoll -#define _tcsncoll_l _strncoll_l -#define _tcsncicoll _strnicoll -#define _tcsncicoll_l _strnicoll_l -#define _tcsnicoll _strnicoll -#define _tcsnicoll_l _strnicoll_l - -#define _tcsclen strlen -#define _tcscnlen strnlen -#define _tcsclen_l(_String,_Locale) strlen(_String) -#define _tcscnlen_l(_String,_Max_count,_Locale) strnlen_l((_String),(_Max_count)) -#define _tcsnccat strncat -#define _tcsnccat_l _strncat_l -#define _tcsnccpy strncpy -#define _tcsnccpy_l _strncpy_l -#define _tcsncset _strnset - -#define _tcsdec _strdec -#define _tcsinc _strinc -#define _tcsnbcnt _strncnt -#define _tcsnccnt _strncnt -#define _tcsnextc _strnextc -#define _tcsninc _strninc -#define _tcsspnp _strspnp - -#define _tcslwr _strlwr -#define _tcslwr_l _strlwr_l -#define _tcsupr _strupr -#define _tcsupr_l _strupr_l -#define _tcsxfrm strxfrm -#define _tcsxfrm_l _strxfrm_l - -#define _istlead(_Char) (0) -#define _istleadbyte(_Char) (0) -#define _istleadbyte_l(_Char,_Locale) (0) - -#define _tclen(_pc) (1) -#define _tccpy(_pc1,_cpc2) (*(_pc1) = *(_cpc2)) -#define _tccmp(_cpc1,_cpc2) (((unsigned char)*(_cpc1))-((unsigned char)*(_cpc2))) - - /* dirent structures and functions */ -#define _tdirent dirent -#define _TDIR DIR -#define _topendir opendir -#define _tclosedir closedir -#define _treaddir readdir -#define _trewinddir rewinddir -#define _ttelldir telldir -#define _tseekdir seekdir - -#define _istalnum isalnum -#define _istalnum_l _isalnum_l -#define _istalpha isalpha -#define _istalpha_l _isalpha_l -#define _istdigit isdigit -#define _istdigit_l _isdigit_l -#define _istgraph isgraph -#define _istgraph_l _isgraph_l -#define _istlower islower -#define _istlower_l _islower_l -#define _istprint isprint -#define _istprint_l _isprint_l -#define _istpunct ispunct -#define _istpunct_l _ispunct_l -#define _istspace isspace -#define _istspace_l _isspace_l -#define _istupper isupper -#define _istupper_l _isupper_l - -#define _totupper toupper -#define _totupper_l _toupper_l -#define _totlower tolower -#define _totlower_l _tolower_l - -#define _istlegal(_c) (1) - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define _strdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) -#define _strinc(_pc) ((_pc)+1) -#define _strnextc(_cpc) ((unsigned int) *(const unsigned char *)(_cpc)) -#define _strninc(_pc,_sz) (((_pc)+(_sz))) - _CRTIMP size_t __cdecl __strncnt(const char *_Str,size_t _Cnt); -#define _strncnt(_cpc,_sz) (__strncnt(_cpc,_sz)) -#define _strspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+strspn(_cpc1,_cpc2))) ? ((_cpc1)+strspn(_cpc1,_cpc2)) : NULL)) - -#define _strncpy_l(_Destination,_Source,_Count,_Locale) (strncpy(_Destination,_Source,_Count)) -#define _strncat_l(_Destination,_Source,_Count,_Locale) (strncat(_Destination,_Source,_Count)) -#define _strtok_l(_String,_Delimiters,_Locale) (strtok(_String,_Delimiters)) -#define _strnset_l(_Destination,_Value,_Count,_Locale) (_strnset(_Destination,_Value,_Count)) -#define _strset_l(_Destination,_Value,_Locale) (_strset(_Destination,_Value)) -#endif -#endif - -#define _T(x) __T(x) -#define _TEXT(x) __T(x) - -#ifdef __cplusplus -} -#endif - -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#include <_mingw.h> + +#ifndef _INC_TCHAR +#define _INC_TCHAR + +#ifdef _STRSAFE_H_INCLUDED_ +#error Need to include strsafe.h after tchar.h +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define _ftcscat _tcscat +#define _ftcschr _tcschr +#define _ftcscpy _tcscpy +#define _ftcscspn _tcscspn +#define _ftcslen _tcslen +#define _ftcsncat _tcsncat +#define _ftcsncpy _tcsncpy +#define _ftcspbrk _tcspbrk +#define _ftcsrchr _tcsrchr +#define _ftcsspn _tcsspn +#define _ftcsstr _tcsstr +#define _ftcstok _tcstok + +#define _ftcsdup _tcsdup +#define _ftcsnset _tcsnset +#define _ftcsrev _tcsrev +#define _ftcsset _tcsset + +#define _ftcscmp _tcscmp +#define _ftcsicmp _tcsicmp +#define _ftcsnccmp _tcsnccmp +#define _ftcsncmp _tcsncmp +#define _ftcsncicmp _tcsncicmp +#define _ftcsnicmp _tcsnicmp + +#define _ftcscoll _tcscoll +#define _ftcsicoll _tcsicoll +#define _ftcsnccoll _tcsnccoll +#define _ftcsncoll _tcsncoll +#define _ftcsncicoll _tcsncicoll +#define _ftcsnicoll _tcsnicoll + +#define _ftcsclen _tcsclen +#define _ftcsnccat _tcsnccat +#define _ftcsnccpy _tcsnccpy +#define _ftcsncset _tcsncset + +#define _ftcsdec _tcsdec +#define _ftcsinc _tcsinc +#define _ftcsnbcnt _tcsnbcnt +#define _ftcsnccnt _tcsnccnt +#define _ftcsnextc _tcsnextc +#define _ftcsninc _tcsninc +#define _ftcsspnp _tcsspnp + +#define _ftcslwr _tcslwr +#define _ftcsupr _tcsupr + +#define _ftclen _tclen +#define _ftccpy _tccpy +#define _ftccmp _tccmp + +#ifndef _CONST_RETURN +#ifdef __cplusplus +#define _CONST_RETURN const +#define _CRT_CONST_CORRECT_OVERLOADS +#else +#define _CONST_RETURN +#endif +#endif + +#define _WConst_return _CONST_RETURN + +#ifdef _UNICODE + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _WCTYPE_T_DEFINED +#define _WCTYPE_T_DEFINED + typedef unsigned short wint_t; + typedef unsigned short wctype_t; +#endif + +#ifndef __TCHAR_DEFINED +#define __TCHAR_DEFINED + typedef wchar_t _TCHAR; + typedef wchar_t _TSCHAR; + typedef wchar_t _TUCHAR; + typedef wchar_t _TXCHAR; + typedef wint_t _TINT; +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +#ifndef NO_OLDNAMES + typedef wchar_t TCHAR; +#endif +#endif + +#define _TEOF WEOF + +#define __T(x) L##x + +#define _tmain wmain +#define _tWinMain wWinMain +#define _tenviron _wenviron +#define __targv __wargv + +#define _tprintf wprintf +#define _tprintf_l _wprintf_l +#define _tprintf_p _wprintf_p +#define _tprintf_p_l _wprintf_p_l +#define _tcprintf _cwprintf +#define _tcprintf_l _cwprintf_l +#define _tcprintf_p _cwprintf_p +#define _tcprintf_p_l _cwprintf_p_l +#define _vtcprintf _vcwprintf +#define _vtcprintf_l _vcwprintf_l +#define _vtcprintf_p _vcwprintf_p +#define _vtcprintf_p_l _vcwprintf_p_l +#define _ftprintf fwprintf +#define _ftprintf_l _fwprintf_l +#define _ftprintf_p _fwprintf_p +#define _ftprintf_p_l _fwprintf_p_l +#define _stprintf swprintf +#define _stprintf_l __swprintf_l +#define _stprintf_p _swprintf_p +#define _stprintf_p_l _swprintf_p_l +#define _sctprintf _scwprintf +#define _sctprintf_l _scwprintf_l +#define _sctprintf_p _scwprintf_p +#define _sctprintf_p_l _scwprintf_p_l +#define _sntprintf _snwprintf +#define _sntprintf_l _snwprintf_l +#define _vtprintf vwprintf +#define _vtprintf_l _vwprintf_l +#define _vtprintf_p _vwprintf_p +#define _vtprintf_p_l _vwprintf_p_l +#define _vftprintf vfwprintf +#define _vftprintf_l _vfwprintf_l +#define _vftprintf_p _vfwprintf_p +#define _vftprintf_p_l _vfwprintf_p_l +#define _vstprintf vswprintf +#define _vstprintf_l _vswprintf_l +#define _vstprintf_p _vswprintf_p +#define _vstprintf_p_l _vswprintf_p_l +#define _vsctprintf _vscwprintf +#define _vsctprintf_l _vscwprintf_l +#define _vsctprintf_p _vscwprintf_p +#define _vsctprintf_p_l _vscwprintf_p_l +#define _vsntprintf _vsnwprintf +#define _vsntprintf_l _vsnwprintf_l + +#define _tscanf wscanf +#define _tscanf_l _wscanf_l +#define _tcscanf _cwscanf +#define _tcscanf_l _cwscanf_l +#define _ftscanf fwscanf +#define _ftscanf_l _fwscanf_l +#define _stscanf swscanf +#define _stscanf_l _swscanf_l +#define _sntscanf _snwscanf +#define _sntscanf_l _snwscanf_l + +#define _fgettc fgetwc +#define _fgettc_nolock _fgetwc_nolock +#define _fgettchar _fgetwchar +#define _fgetts fgetws +#define _fputtc fputwc +#define _fputtc_nolock _fputwc_nolock +#define _fputtchar _fputwchar +#define _fputts fputws +#define _cputts _cputws +#define _cgetts _cgetws +#define _gettc getwc +#define _gettc_nolock _getwc_nolock +#define _gettch _getwch +#define _gettch_nolock _getwch_nolock +#define _gettche _getwche +#define _gettche_nolock _getwche_nolock +#define _gettchar getwchar +#define _gettchar_nolock _getwchar_nolock +#define _getts _getws +#define _puttc putwc +#define _puttc_nolock _putwc_nolock +#define _puttchar putwchar +#define _puttchar_nolock _putwchar_nolock +#define _puttch _putwch +#define _puttch_nolock _putwch_nolock +#define _putts _putws +#define _ungettc ungetwc +#define _ungettc_nolock _ungetwc_nolock +#define _ungettch _ungetwch +#define _ungettch_nolock _ungetwch_nolock + +#define _tcstod wcstod +#define _tcstol wcstol +#define _tcstoul wcstoul +#define _tcstoi64 _wcstoi64 +#define _tcstoui64 _wcstoui64 +#define _tstof _wtof +#define _tstol _wtol +#define _tstoi _wtoi +#define _tstoi64 _wtoi64 +#define _tcstod_l _wcstod_l +#define _tcstol_l _wcstol_l +#define _tcstoul_l _wcstoul_l +#define _tcstoi64_l _wcstoi64_l +#define _tcstoui64_l _wcstoui64_l +#define _tstof_l _wtof_l +#define _tstol_l _wtol_l +#define _tstoi_l _wtoi_l +#define _tstoi64_l _wtoi64_l + +#define _itot _itow +#define _ltot _ltow +#define _ultot _ultow +#define _ttoi _wtoi +#define _ttol _wtol + +#define _ttoi64 _wtoi64 +#define _i64tot _i64tow +#define _ui64tot _ui64tow + +#define _tcscat wcscat +#define _tcschr wcschr +#define _tcscpy wcscpy +#define _tcscspn wcscspn +#define _tcslen wcslen +#define _tcsnlen wcsnlen +#define _tcsncat wcsncat +#define _tcsncat_l _wcsncat_l +#define _tcsncpy wcsncpy +#define _tcsncpy_l _wcsncpy_l +#define _tcspbrk wcspbrk +#define _tcsrchr wcsrchr +#define _tcsspn wcsspn +#define _tcsstr wcsstr +#define _tcstok wcstok +#define _tcstok_l _wcstok_l +#define _tcserror _wcserror +#define __tcserror __wcserror + +#define _tcsdup _wcsdup +#define _tcsnset _wcsnset +#define _tcsnset_l _wcsnset_l +#define _tcsrev _wcsrev +#define _tcsset _wcsset +#define _tcsset_l _wcsset_l + +#define _tcscmp wcscmp +#define _tcsicmp _wcsicmp +#define _tcsicmp_l _wcsicmp_l +#define _tcsnccmp wcsncmp +#define _tcsncmp wcsncmp +#define _tcsncicmp _wcsnicmp +#define _tcsncicmp_l _wcsnicmp_l +#define _tcsnicmp _wcsnicmp +#define _tcsnicmp_l _wcsnicmp_l + +#define _tcscoll wcscoll +#define _tcscoll_l _wcscoll_l +#define _tcsicoll _wcsicoll +#define _tcsicoll_l _wcsicoll_l +#define _tcsnccoll _wcsncoll +#define _tcsnccoll_l _wcsncoll_l +#define _tcsncoll _wcsncoll +#define _tcsncoll_l _wcsncoll_l +#define _tcsncicoll _wcsnicoll +#define _tcsncicoll_l _wcsnicoll_l +#define _tcsnicoll _wcsnicoll +#define _tcsnicoll_l _wcsnicoll_l + +#define _texecl _wexecl +#define _texecle _wexecle +#define _texeclp _wexeclp +#define _texeclpe _wexeclpe +#define _texecv _wexecv +#define _texecve _wexecve +#define _texecvp _wexecvp +#define _texecvpe _wexecvpe + +#define _tspawnl _wspawnl +#define _tspawnle _wspawnle +#define _tspawnlp _wspawnlp +#define _tspawnlpe _wspawnlpe +#define _tspawnv _wspawnv +#define _tspawnve _wspawnve +#define _tspawnvp _wspawnvp +#define _tspawnvp _wspawnvp +#define _tspawnvpe _wspawnvpe + +#define _tsystem _wsystem + +#define _tasctime _wasctime +#define _tctime _wctime +#define _tctime32 _wctime32 +#define _tctime64 _wctime64 +#define _tstrdate _wstrdate +#define _tstrtime _wstrtime +#define _tutime _wutime +#define _tutime32 _wutime32 +#define _tutime64 _wutime64 +#define _tcsftime wcsftime +#define _tcsftime_l _wcsftime_l + +#define _tchdir _wchdir +#define _tgetcwd _wgetcwd +#define _tgetdcwd _wgetdcwd +#define _tgetdcwd_nolock _wgetdcwd_nolock +#define _tmkdir _wmkdir +#define _trmdir _wrmdir + +#define _tfullpath _wfullpath +#define _tgetenv _wgetenv +#define _tmakepath _wmakepath +#define _tpgmptr _wpgmptr +#define _get_tpgmptr _get_wpgmptr +#define _tputenv _wputenv +#define _tsearchenv _wsearchenv +#define _tsplitpath _wsplitpath + +#define _tfdopen _wfdopen +#define _tfsopen _wfsopen +#define _tfopen _wfopen +#define _tfreopen _wfreopen +#define _tperror _wperror +#define _tpopen _wpopen +#define _ttempnam _wtempnam +#define _ttmpnam _wtmpnam + +#define _taccess _waccess +#define _tchmod _wchmod +#define _tcreat _wcreat +#define _tfindfirst _wfindfirst +#define _tfindfirst32 _wfindfirst32 +#define _tfindfirst64 _wfindfirst64 +#define _tfindfirsti64 _wfindfirsti64 +#define _tfindfirst32i64 _wfindfirst32i64 +#define _tfindfirst64i32 _wfindfirst64i32 +#define _tfindnext _wfindnext +#define _tfindnext32 _wfindnext32 +#define _tfindnext64 _wfindnext64 +#define _tfindnexti64 _wfindnexti64 +#define _tfindnext32i64 _wfindnext32i64 +#define _tfindnext64i32 _wfindnext64i32 +#define _tmktemp _wmktemp +#define _topen _wopen +#define _tremove _wremove +#define _trename _wrename +#define _tsopen _wsopen +#define _tunlink _wunlink + +#define _tfinddata_t _wfinddata_t +#define _tfinddata32_t _wfinddata32_t +#define _tfinddata64_t _wfinddata64_t +#define _tfinddatai64_t _wfinddatai64_t +#define _tfinddata32i64_t _wfinddata32i64_t +#define _tfinddata64i32_t _wfinddata64i32_t + +#define _tstat _wstat +#define _tstat32 _wstat32 +#define _tstat32i64 _wstat32i64 +#define _tstat64 _wstat64 +#define _tstat64i32 _wstat64i32 +#define _tstati64 _wstati64 + +#define _tsetlocale _wsetlocale + +#define _tcsclen wcslen +#define _tcscnlen wcsnlen +#define _tcsclen_l(_String,_Locale) wcslen(_String) +#define _tcscnlen_l(_String,_Max_count,_Locale) wcsnlen_l((_String),(_Max_count)) +#define _tcsnccat wcsncat +#define _tcsnccat_l _wcsncat_l +#define _tcsnccpy wcsncpy +#define _tcsnccpy_l _wcsncpy_l +#define _tcsncset _wcsnset + +#define _tcsdec _wcsdec +#define _tcsinc _wcsinc +#define _tcsnbcnt _wcsncnt +#define _tcsnccnt _wcsncnt +#define _tcsnextc _wcsnextc +#define _tcsninc _wcsninc +#define _tcsspnp _wcsspnp + +#define _tcslwr _wcslwr +#define _tcslwr_l _wcslwr_l +#define _tcsupr _wcsupr +#define _tcsupr_l _wcsupr_l +#define _tcsxfrm wcsxfrm +#define _tcsxfrm_l _wcsxfrm_l + +#define _tclen(_pc) (1) +#define _tccpy(_pc1,_cpc2) ((*(_pc1) = *(_cpc2))) +#define _tccmp(_cpc1,_cpc2) ((*(_cpc1))-(*(_cpc2))) + +#define _istalnum iswalnum +#define _istalnum_l _iswalnum_l +#define _istalpha iswalpha +#define _istalpha_l _iswalpha_l +#define _istascii iswascii +#define _istcntrl iswcntrl +#define _istcntrl_l _iswcntrl_l +#define _istdigit iswdigit +#define _istdigit_l _iswdigit_l +#define _istgraph iswgraph +#define _istgraph_l _iswgraph_l +#define _istlower iswlower +#define _istlower_l _iswlower_l +#define _istprint iswprint +#define _istprint_l _iswprint_l +#define _istpunct iswpunct +#define _istpunct_l _iswpunct_l +#define _istspace iswspace +#define _istspace_l _iswspace_l +#define _istupper iswupper +#define _istupper_l _iswupper_l +#define _istxdigit iswxdigit +#define _istxdigit_l _iswxdigit_l + +#define _totupper towupper +#define _totupper_l _towupper_l +#define _totlower towlower +#define _totlower_l _towlower_l + +#define _istlegal(_Char) (1) +#define _istlead(_Char) (0) +#define _istleadbyte(_Char) (0) +#define _istleadbyte_l(_Char,_Locale) (0) + +#define _wcsdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) +#define _wcsinc(_pc) ((_pc)+1) +#define _wcsnextc(_cpc) ((unsigned int) *(_cpc)) +#define _wcsninc(_pc,_sz) (((_pc)+(_sz))) + _CRTIMP size_t __cdecl __wcsncnt(const wchar_t *_Str,size_t _MaxCount); +#define _wcsncnt(_cpc,_sz) (__wcsncnt(_cpc,_sz)) +#define _wcsspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+wcsspn(_cpc1,_cpc2))) ? ((_cpc1)+wcsspn(_cpc1,_cpc2)) : NULL)) +#define _wcsncpy_l(_Destination,_Source,_Count,_Locale) (wcsncpy(_Destination,_Source,_Count)) +#define _wcsncat_l(_Destination,_Source,_Count,_Locale) (wcsncat(_Destination,_Source,_Count)) +#define _wcstok_l(_String,_Delimiters,_Locale) (wcstok(_String,_Delimiters)) +#define _wcsnset_l(_Destination,_Value,_Count,_Locale) (_wcsnset(_Destination,_Value,_Count)) +#define _wcsset_l(_Destination,_Value,_Locale) (_wcsset(_Destination,_Value)) + + /* dirent structures and functions */ +#define _tdirent _wdirent +#define _TDIR _WDIR +#define _topendir _wopendir +#define _tclosedir _wclosedir +#define _treaddir _wreaddir +#define _trewinddir _wrewinddir +#define _ttelldir _wtelldir +#define _tseekdir _wseekdir + +#else + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define _TEOF EOF + +#define __T(x) x + +#define _tmain main +#define _tWinMain WinMain +#ifdef _POSIX_ +#define _tenviron environ +#else +#define _tenviron _environ +#endif +#define __targv __argv + +#define _tprintf printf +#define _tprintf_l _printf_l +#define _tprintf_p _printf_p +#define _tprintf_p_l _printf_p_l +#define _tcprintf _cprintf +#define _tcprintf_l _cprintf_l +#define _tcprintf_p _cprintf_p +#define _tcprintf_p_l _cprintf_p_l +#define _vtcprintf _vcprintf +#define _vtcprintf_l _vcprintf_l +#define _vtcprintf_p _vcprintf_p +#define _vtcprintf_p_l _vcprintf_p_l +#define _ftprintf fprintf +#define _ftprintf_l _fprintf_l +#define _ftprintf_p _fprintf_p +#define _ftprintf_p_l _fprintf_p_l +#define _stprintf sprintf +#define _stprintf_l _sprintf_l +#define _stprintf_p _sprintf_p +#define _stprintf_p_l _sprintf_p_l +#define _sctprintf _scprintf +#define _sctprintf_l _scprintf_l +#define _sctprintf_p _scprintf_p +#define _sctprintf_p_l _scprintf_p_l +#define _sntprintf _snprintf +#define _sntprintf_l _snprintf_l +#define _vtprintf vprintf +#define _vtprintf_l _vprintf_l +#define _vtprintf_p _vprintf_p +#define _vtprintf_p_l _vprintf_p_l +#define _vftprintf vfprintf +#define _vftprintf_l _vfprintf_l +#define _vftprintf_p _vfprintf_p +#define _vftprintf_p_l _vfprintf_p_l +#define _vstprintf vsprintf +#define _vstprintf_l _vsprintf_l +#define _vstprintf_p _vsprintf_p +#define _vstprintf_p_l _vsprintf_p_l +#define _vsctprintf _vscprintf +#define _vsctprintf_l _vscprintf_l +#define _vsctprintf_p _vscprintf_p +#define _vsctprintf_p_l _vscprintf_p_l +#define _vsntprintf _vsnprintf +#define _vsntprintf_l _vsnprintf_l + +#define _tscanf scanf +#define _tscanf_l _scanf_l +#define _tcscanf _cscanf +#define _tcscanf_l _cscanf_l +#define _ftscanf fscanf +#define _ftscanf_l _fscanf_l +#define _stscanf sscanf +#define _stscanf_l _sscanf_l +#define _sntscanf _snscanf +#define _sntscanf_l _snscanf_l + +#define _fgettc fgetc +#define _fgettc_nolock _fgetc_nolock +#define _fgettchar _fgetchar +#define _fgetts fgets +#define _fputtc fputc +#define _fputtc_nolock _fputc_nolock +#define _fputtchar _fputchar +#define _fputts fputs +#define _cputts _cputs +#define _gettc getc +#define _gettc_nolock _getc_nolock +#define _gettch _getch +#define _gettch_nolock _getch_nolock +#define _gettche _getche +#define _gettche_nolock _getche_nolock +#define _gettchar getchar +#define _gettchar_nolock _getchar_nolock +#define _getts gets +#define _cgetts _cgets +#define _puttc putc +#define _puttc_nolock _putc_nolock +#define _puttchar putchar +#define _puttchar_nolock _putchar_nolock +#define _puttch _putch +#define _puttch_nolock _putch_nolock +#define _putts puts +#define _ungettc ungetc +#define _ungettc_nolock _ungetc_nolock +#define _ungettch _ungetch +#define _ungettch_nolock _ungetch_nolock + +#define _tcstod strtod +#define _tcstol strtol +#define _tcstoul strtoul +#define _tstof atof +#define _tstol atol +#define _tstoi atoi +#define _tstoi64 _atoi64 +#define _tcstod_l _strtod_l +#define _tcstol_l _strtol_l +#define _tcstoul_l _strtoul_l +#define _tstof_l _atof_l +#define _tstol_l _atol_l +#define _tstoi_l _atoi_l +#define _tstoi64_l _atoi64_l + +#define _itot _itoa +#define _ltot _ltoa +#define _ultot _ultoa +#define _ttoi atoi +#define _ttol atol + +#define _ttoi64 _atoi64 +#define _tcstoi64 _strtoi64 +#define _tcstoi64_l _strtoi64_l +#define _tcstoui64 _strtoui64 +#define _tcstoui64_l _strtoui64_l +#define _i64tot _i64toa +#define _ui64tot _ui64toa + +#define _tcscat strcat +#define _tcscpy strcpy +#define _tcsdup _strdup +#define _tcslen strlen +#if 0 +#define _tcsnlen strnlen +#endif +#define _tcsxfrm strxfrm +#define _tcsxfrm_l _strxfrm_l +#define _tcserror strerror +#define __tcserror _strerror + +#define _texecl _execl +#define _texecle _execle +#define _texeclp _execlp +#define _texeclpe _execlpe +#define _texecv _execv +#define _texecve _execve +#define _texecvp _execvp +#define _texecvpe _execvpe + +#define _tspawnl _spawnl +#define _tspawnle _spawnle +#define _tspawnlp _spawnlp +#define _tspawnlpe _spawnlpe +#define _tspawnv _spawnv +#define _tspawnve _spawnve +#define _tspawnvp _spawnvp +#define _tspawnvpe _spawnvpe + +#define _tsystem system + +#define _tasctime asctime +#define _tctime ctime +#define _tctime32 _ctime32 +#define _tctime64 _ctime64 +#define _tstrdate _strdate +#define _tstrtime _strtime +#define _tutime _utime +#define _tutime32 _utime32 +#define _tutime64 _utime64 +#define _tcsftime strftime +#define _tcsftime_l _strftime_l + +#define _tchdir _chdir +#define _tgetcwd _getcwd +#define _tgetdcwd _getdcwd +#define _tgetdcwd_nolock _getdcwd_nolock +#define _tmkdir _mkdir +#define _trmdir _rmdir + +#define _tfullpath _fullpath +#define _tgetenv getenv +#define _tmakepath _makepath +#define _tpgmptr _pgmptr +#define _get_tpgmptr _get_pgmptr +#define _tputenv _putenv +#define _tsearchenv _searchenv +#define _tsplitpath _splitpath + +#ifdef _POSIX_ +#define _tfdopen fdopen +#else +#define _tfdopen _fdopen +#endif +#define _tfsopen _fsopen +#define _tfopen fopen +#define _tfreopen freopen +#define _tperror perror +#define _tpopen _popen +#define _ttempnam _tempnam +#define _ttmpnam tmpnam + +#define _tchmod _chmod +#define _tcreat _creat +#define _tfindfirst _findfirst +#define _tfindfirst32 _findfirst32 +#define _tfindfirst64 _findfirst64 +#define _tfindfirsti64 _findfirsti64 +#define _tfindfirst32i64 _findfirst32i64 +#define _tfindfirst64i32 _findfirst64i32 +#define _tfindnext _findnext +#define _tfindnext32 _findnext32 +#define _tfindnext64 _findnext64 +#define _tfindnexti64 _findnexti64 +#define _tfindnext32i64 _findnext32i64 +#define _tfindnext64i32 _findnext64i32 +#define _tmktemp _mktemp + +#ifdef _POSIX_ +#define _topen open +#define _taccess access +#else +#define _topen _open +#define _taccess _access +#endif + +#define _tremove remove +#define _trename rename +#define _tsopen _sopen +#define _tunlink _unlink + +#define _tfinddata_t _finddata_t +#define _tfinddata32_t _finddata32_t +#define _tfinddata64_t __finddata64_t +#define _tfinddatai64_t _finddatai64_t +#define _tfinddata32i64_t _finddata32i64_t +#define _tfinddata64i32_t _finddata64i32_t + +#define _istascii __isascii +#define _istcntrl iscntrl +#define _istcntrl_l _iscntrl_l +#define _istxdigit isxdigit +#define _istxdigit_l _isxdigit_l + +#define _tstat _stat +#define _tstat32 _stat32 +#define _tstat32i64 _stat32i64 +#define _tstat64 _stat64 +#define _tstat64i32 _stat64i32 +#define _tstati64 _stati64 + +#define _tsetlocale setlocale + +#ifdef _MBCS + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __TCHAR_DEFINED + typedef char _TCHAR; + typedef signed char _TSCHAR; + typedef unsigned char _TUCHAR; + typedef unsigned char _TXCHAR; + typedef unsigned int _TINT; +#define __TCHAR_DEFINED +#endif + +#ifndef _TCHAR_DEFINED +#ifndef NO_OLDNAMES + typedef char TCHAR; +#endif +#define _TCHAR_DEFINED +#endif + +#ifdef _MB_MAP_DIRECT + +#define _tcschr _mbschr +#define _tcscspn _mbscspn +#define _tcsncat _mbsnbcat +#define _tcsncat_l _mbsnbcat_l +#define _tcsncpy _mbsnbcpy +#define _tcsncpy_l _mbsnbcpy_l +#define _tcspbrk _mbspbrk +#define _tcsrchr _mbsrchr +#define _tcsspn _mbsspn +#define _tcsstr _mbsstr +#define _tcstok _mbstok +#define _tcstok_l _mbstok_l + +#define _tcsnset _mbsnbset +#define _tcsnset_l _mbsnbset_l +#define _tcsrev _mbsrev +#define _tcsset _mbsset +#define _tcsset_l _mbsset_l + +#define _tcscmp _mbscmp +#define _tcsicmp _mbsicmp +#define _tcsicmp_l _mbsicmp_l +#define _tcsnccmp _mbsncmp +#define _tcsncmp _mbsnbcmp +#define _tcsncicmp _mbsnicmp +#define _tcsncicmp_l _mbsnicmp_l +#define _tcsnicmp _mbsnbicmp +#define _tcsnicmp_l _mbsnbicmp_l + +#define _tcscoll _mbscoll +#define _tcscoll_l _mbscoll_l +#define _tcsicoll _mbsicoll +#define _tcsicoll_l _mbsicoll_l +#define _tcsnccoll _mbsncoll +#define _tcsnccoll_l _mbsncoll_l +#define _tcsncoll _mbsnbcoll +#define _tcsncoll_l _mbsnbcoll_l +#define _tcsncicoll _mbsnicoll +#define _tcsncicoll_l _mbsnicoll_l +#define _tcsnicoll _mbsnbicoll +#define _tcsnicoll_l _mbsnbicoll_l + +#define _tcsclen _mbslen +#define _tcscnlen _mbsnlen +#define _tcsclen_l _mbslen_l +#define _tcscnlen_l _mbsnlen_l +#define _tcsnccat _mbsncat +#define _tcsnccat_l _mbsncat_l +#define _tcsnccpy _mbsncpy +#define _tcsnccpy_l _mbsncpy_l +#define _tcsncset _mbsnset +#define _tcsncset_l _mbsnset_l + +#define _tcsdec _mbsdec +#define _tcsinc _mbsinc +#define _tcsnbcnt _mbsnbcnt +#define _tcsnccnt _mbsnccnt +#define _tcsnextc _mbsnextc +#define _tcsninc _mbsninc +#define _tcsspnp _mbsspnp + +#define _tcslwr _mbslwr +#define _tcslwr_l _mbslwr_l +#define _tcsupr _mbsupr +#define _tcsupr_l _mbsupr_l + +#define _tclen _mbclen +#define _tccpy _mbccpy +#define _tccpy_l _mbccpy_l +#else + + _CRTIMP _CONST_RETURN char *__cdecl _tcschr(const char *_Str,unsigned int _Val); + _CRTIMP size_t __cdecl _tcscspn(const char *_Str,const char *_Control); + _CRTIMP char *__cdecl _tcsncat(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsncpy(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP _CONST_RETURN char *__cdecl _tcspbrk(const char *_Str,const char *_Control); + _CRTIMP _CONST_RETURN char *__cdecl _tcsrchr(const char *_Str,unsigned int _Ch); + _CRTIMP size_t __cdecl _tcsspn(const char *_Str,const char *_Control); + _CRTIMP _CONST_RETURN char *__cdecl _tcsstr(const char *_Str,const char *_Substr); + _CRTIMP char *__cdecl _tcstok(char *_Str,const char *_Delim); + _CRTIMP char *__cdecl _tcstok_l(char *_Str,const char *_Delim,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnset(char *_Str,unsigned int _Val,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsrev(char *_Str); + _CRTIMP char *__cdecl _tcsset(char *_Str,unsigned int _Val); + _CRTIMP char *__cdecl _tcsset_l(char *_Str,unsigned int _Val,_locale_t _Locale); + _CRTIMP int __cdecl _tcscmp(const char *_Str1,const char *_Str); + _CRTIMP int __cdecl _tcsicmp(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _tcsicmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnccmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcscoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _tcscoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _tcsicoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _tcsicoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnccoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsnccoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsncoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsncicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP size_t __cdecl _tcsclen(const char *_Str); + _CRTIMP size_t __cdecl _tcscnlen(const char *_Str,size_t _MaxCount); + _CRTIMP size_t __cdecl _tcsclen_l(const char *_Str,_locale_t _Locale); + _CRTIMP size_t __cdecl _tcscnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccat(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccpy(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsncset(char *_Str,unsigned int _Val,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsdec(const char *_Start,const char *_Pos); + _CRTIMP char *__cdecl _tcsinc(const char *_Ptr); + _CRTIMP size_t __cdecl _tcsnbcnt(const char *_Str,size_t _MaxCount); + _CRTIMP size_t __cdecl _tcsnccnt(const char *_Str,size_t _MaxCount); + _CRTIMP unsigned int __cdecl _tcsnextc (const char *_Str); + _CRTIMP char *__cdecl _tcsninc(const char *_Ptr,size_t _Count); + _CRTIMP char *__cdecl _tcsspnp(const char *_Str1,const char *_Str2); + _CRTIMP char *__cdecl _tcslwr(char *_Str); + _CRTIMP char *__cdecl _tcslwr_l(char *_Str,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsupr(char *_Str); + _CRTIMP char *__cdecl _tcsupr_l(char *_Str,_locale_t _Locale); + _CRTIMP size_t __cdecl _tclen(const char *_Str); + _CRTIMP void __cdecl _tccpy(char *_DstCh,const char *_SrcCh); + +#ifdef __cplusplus +#ifndef _CPP_TCHAR_INLINES_DEFINED +#define _CPP_TCHAR_INLINES_DEFINED + extern "C++" { + extern inline char *__cdecl _tcschr(char *_S,unsigned int _C) { return ((char *)_tcschr((const char *)_S,_C)); } + extern inline char *__cdecl _tcspbrk(char *_S,const char *_P) { return ((char *)_tcspbrk((const char *)_S,_P)); } + extern inline char *__cdecl _tcsrchr(char *_S,unsigned int _C) { return ((char *)_tcsrchr((const char *)_S,_C)); } + extern inline char *__cdecl _tcsstr(char *_S,const char *_P) { return ((char *)_tcsstr((const char *)_S,_P)); } + } +#endif +#endif +#endif + +#define _tccmp(_cp1,_cp2) _tcsnccmp(_cp1,_cp2,1) + +#define _istalnum _ismbcalnum +#define _istalnum_l _ismbcalnum_l +#define _istalpha _ismbcalpha +#define _istalpha_l _ismbcalpha_l +#define _istdigit _ismbcdigit +#define _istdigit_l _ismbcdigit_l +#define _istgraph _ismbcgraph +#define _istgraph_l _ismbcgraph_l +#define _istlegal _ismbclegal +#define _istlegal_l _ismbclegal_l +#define _istlower _ismbclower +#define _istlower_l _ismbclower_l +#define _istprint _ismbcprint +#define _istprint_l _ismbcprint_l +#define _istpunct _ismbcpunct +#define _istpunct_l _ismbcpunct_l +#define _istspace _ismbcspace +#define _istspace_l _ismbcspace_l +#define _istupper _ismbcupper +#define _istupper_l _ismbcupper_l + +#define _totupper _mbctoupper +#define _totupper_l _mbctoupper_l +#define _totlower _mbctolower +#define _totlower_l _mbctolower_l + +#define _istlead _ismbblead +#define _istleadbyte isleadbyte +#define _istleadbyte_l _isleadbyte_l +#else + +#ifndef __TCHAR_DEFINED +#define __TCHAR_DEFINED + typedef char _TCHAR; + typedef signed char _TSCHAR; + typedef unsigned char _TUCHAR; + typedef char _TXCHAR; + typedef int _TINT; +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +#ifndef NO_OLDNAMES + typedef char TCHAR; +#endif +#endif + +#define _tcschr strchr +#define _tcscspn strcspn +#define _tcsncat strncat +#define _tcsncat_l _strncat_l +#define _tcsncpy strncpy +#define _tcsncpy_l _strncpy_l +#define _tcspbrk strpbrk +#define _tcsrchr strrchr +#define _tcsspn strspn +#define _tcsstr strstr +#define _tcstok strtok +#define _tcstok_l _strtok_l + +#define _tcsnset _strnset +#define _tcsnset_l _strnset_l +#define _tcsrev _strrev +#define _tcsset _strset + +#define _tcscmp strcmp +#define _tcsicmp _stricmp +#define _tcsicmp_l _stricmp_l +#define _tcsnccmp strncmp +#define _tcsncmp strncmp +#define _tcsncicmp _strnicmp +#define _tcsncicmp_l _strnicmp_l +#define _tcsnicmp _strnicmp +#define _tcsnicmp_l _strnicmp_l + +#define _tcscoll strcoll +#define _tcscoll_l _strcoll_l +#define _tcsicoll _stricoll +#define _tcsicoll_l _stricoll_l +#define _tcsnccoll _strncoll +#define _tcsnccoll_l _strncoll_l +#define _tcsncoll _strncoll +#define _tcsncoll_l _strncoll_l +#define _tcsncicoll _strnicoll +#define _tcsncicoll_l _strnicoll_l +#define _tcsnicoll _strnicoll +#define _tcsnicoll_l _strnicoll_l + +#define _tcsclen strlen +#define _tcscnlen strnlen +#define _tcsclen_l(_String,_Locale) strlen(_String) +#define _tcscnlen_l(_String,_Max_count,_Locale) strnlen_l((_String),(_Max_count)) +#define _tcsnccat strncat +#define _tcsnccat_l _strncat_l +#define _tcsnccpy strncpy +#define _tcsnccpy_l _strncpy_l +#define _tcsncset _strnset + +#define _tcsdec _strdec +#define _tcsinc _strinc +#define _tcsnbcnt _strncnt +#define _tcsnccnt _strncnt +#define _tcsnextc _strnextc +#define _tcsninc _strninc +#define _tcsspnp _strspnp + +#define _tcslwr _strlwr +#define _tcslwr_l _strlwr_l +#define _tcsupr _strupr +#define _tcsupr_l _strupr_l +#define _tcsxfrm strxfrm +#define _tcsxfrm_l _strxfrm_l + +#define _istlead(_Char) (0) +#define _istleadbyte(_Char) (0) +#define _istleadbyte_l(_Char,_Locale) (0) + +#define _tclen(_pc) (1) +#define _tccpy(_pc1,_cpc2) (*(_pc1) = *(_cpc2)) +#define _tccmp(_cpc1,_cpc2) (((unsigned char)*(_cpc1))-((unsigned char)*(_cpc2))) + + /* dirent structures and functions */ +#define _tdirent dirent +#define _TDIR DIR +#define _topendir opendir +#define _tclosedir closedir +#define _treaddir readdir +#define _trewinddir rewinddir +#define _ttelldir telldir +#define _tseekdir seekdir + +#define _istalnum isalnum +#define _istalnum_l _isalnum_l +#define _istalpha isalpha +#define _istalpha_l _isalpha_l +#define _istdigit isdigit +#define _istdigit_l _isdigit_l +#define _istgraph isgraph +#define _istgraph_l _isgraph_l +#define _istlower islower +#define _istlower_l _islower_l +#define _istprint isprint +#define _istprint_l _isprint_l +#define _istpunct ispunct +#define _istpunct_l _ispunct_l +#define _istspace isspace +#define _istspace_l _isspace_l +#define _istupper isupper +#define _istupper_l _isupper_l + +#define _totupper toupper +#define _totupper_l _toupper_l +#define _totlower tolower +#define _totlower_l _tolower_l + +#define _istlegal(_c) (1) + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define _strdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) +#define _strinc(_pc) ((_pc)+1) +#define _strnextc(_cpc) ((unsigned int) *(const unsigned char *)(_cpc)) +#define _strninc(_pc,_sz) (((_pc)+(_sz))) + _CRTIMP size_t __cdecl __strncnt(const char *_Str,size_t _Cnt); +#define _strncnt(_cpc,_sz) (__strncnt(_cpc,_sz)) +#define _strspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+strspn(_cpc1,_cpc2))) ? ((_cpc1)+strspn(_cpc1,_cpc2)) : NULL)) + +#define _strncpy_l(_Destination,_Source,_Count,_Locale) (strncpy(_Destination,_Source,_Count)) +#define _strncat_l(_Destination,_Source,_Count,_Locale) (strncat(_Destination,_Source,_Count)) +#define _strtok_l(_String,_Delimiters,_Locale) (strtok(_String,_Delimiters)) +#define _strnset_l(_Destination,_Value,_Count,_Locale) (_strnset(_Destination,_Value,_Count)) +#define _strset_l(_Destination,_Value,_Locale) (_strset(_Destination,_Value)) +#endif +#endif + +#define _T(x) __T(x) +#define _TEXT(x) __T(x) + +#ifdef __cplusplus +} +#endif + +#include +#endif diff --git a/tcc/include/tgmath.h b/tcc/include/tgmath.h index 5d3e3578..46ff48b2 100644 --- a/tcc/include/tgmath.h +++ b/tcc/include/tgmath.h @@ -1,89 +1,89 @@ -/* - * ISO C Standard: 7.22 Type-generic math - */ - -#ifndef _TGMATH_H -#define _TGMATH_H - -#include - -#ifndef __cplusplus -#define __tgmath_real(x, F) \ - _Generic ((x), float: F##f, long double: F##l, default: F)(x) -#define __tgmath_real_2_1(x, y, F) \ - _Generic ((x), float: F##f, long double: F##l, default: F)(x, y) -#define __tgmath_real_2(x, y, F) \ - _Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y) -#define __tgmath_real_3_2(x, y, z, F) \ - _Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y, z) -#define __tgmath_real_3(x, y, z, F) \ - _Generic ((x)+(y)+(z), float: F##f, long double: F##l, default: F)(x, y, z) - -/* Functions defined in both and (7.22p4) */ -#define acos(z) __tgmath_real(z, acos) -#define asin(z) __tgmath_real(z, asin) -#define atan(z) __tgmath_real(z, atan) -#define acosh(z) __tgmath_real(z, acosh) -#define asinh(z) __tgmath_real(z, asinh) -#define atanh(z) __tgmath_real(z, atanh) -#define cos(z) __tgmath_real(z, cos) -#define sin(z) __tgmath_real(z, sin) -#define tan(z) __tgmath_real(z, tan) -#define cosh(z) __tgmath_real(z, cosh) -#define sinh(z) __tgmath_real(z, sinh) -#define tanh(z) __tgmath_real(z, tanh) -#define exp(z) __tgmath_real(z, exp) -#define log(z) __tgmath_real(z, log) -#define pow(z1,z2) __tgmath_real_2(z1, z2, pow) -#define sqrt(z) __tgmath_real(z, sqrt) -#define fabs(z) __tgmath_real(z, fabs) - -/* Functions defined in only (7.22p5) */ -#define atan2(x,y) __tgmath_real_2(x, y, atan2) -#define cbrt(x) __tgmath_real(x, cbrt) -#define ceil(x) __tgmath_real(x, ceil) -#define copysign(x,y) __tgmath_real_2(x, y, copysign) -#define erf(x) __tgmath_real(x, erf) -#define erfc(x) __tgmath_real(x, erfc) -#define exp2(x) __tgmath_real(x, exp2) -#define expm1(x) __tgmath_real(x, expm1) -#define fdim(x,y) __tgmath_real_2(x, y, fdim) -#define floor(x) __tgmath_real(x, floor) -#define fma(x,y,z) __tgmath_real_3(x, y, z, fma) -#define fmax(x,y) __tgmath_real_2(x, y, fmax) -#define fmin(x,y) __tgmath_real_2(x, y, fmin) -#define fmod(x,y) __tgmath_real_2(x, y, fmod) -#define frexp(x,y) __tgmath_real_2_1(x, y, frexp) -#define hypot(x,y) __tgmath_real_2(x, y, hypot) -#define ilogb(x) __tgmath_real(x, ilogb) -#define ldexp(x,y) __tgmath_real_2_1(x, y, ldexp) -#define lgamma(x) __tgmath_real(x, lgamma) -#define llrint(x) __tgmath_real(x, llrint) -#define llround(x) __tgmath_real(x, llround) -#define log10(x) __tgmath_real(x, log10) -#define log1p(x) __tgmath_real(x, log1p) -#define log2(x) __tgmath_real(x, log2) -#define logb(x) __tgmath_real(x, logb) -#define lrint(x) __tgmath_real(x, lrint) -#define lround(x) __tgmath_real(x, lround) -#define nearbyint(x) __tgmath_real(x, nearbyint) -#define nextafter(x,y) __tgmath_real_2(x, y, nextafter) -#define nexttoward(x,y) __tgmath_real_2(x, y, nexttoward) -#define remainder(x,y) __tgmath_real_2(x, y, remainder) -#define remquo(x,y,z) __tgmath_real_3_2(x, y, z, remquo) -#define rint(x) __tgmath_real(x, rint) -#define round(x) __tgmath_real(x, round) -#define scalbln(x,y) __tgmath_real_2_1(x, y, scalbln) -#define scalbn(x,y) __tgmath_real_2_1(x, y, scalbn) -#define tgamma(x) __tgmath_real(x, tgamma) -#define trunc(x) __tgmath_real(x, trunc) - -/* Functions defined in only (7.22p6) -#define carg(z) __tgmath_cplx_only(z, carg) -#define cimag(z) __tgmath_cplx_only(z, cimag) -#define conj(z) __tgmath_cplx_only(z, conj) -#define cproj(z) __tgmath_cplx_only(z, cproj) -#define creal(z) __tgmath_cplx_only(z, creal) -*/ -#endif /* __cplusplus */ -#endif /* _TGMATH_H */ +/* + * ISO C Standard: 7.22 Type-generic math + */ + +#ifndef _TGMATH_H +#define _TGMATH_H + +#include + +#ifndef __cplusplus +#define __tgmath_real(x, F) \ + _Generic ((x), float: F##f, long double: F##l, default: F)(x) +#define __tgmath_real_2_1(x, y, F) \ + _Generic ((x), float: F##f, long double: F##l, default: F)(x, y) +#define __tgmath_real_2(x, y, F) \ + _Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y) +#define __tgmath_real_3_2(x, y, z, F) \ + _Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y, z) +#define __tgmath_real_3(x, y, z, F) \ + _Generic ((x)+(y)+(z), float: F##f, long double: F##l, default: F)(x, y, z) + +/* Functions defined in both and (7.22p4) */ +#define acos(z) __tgmath_real(z, acos) +#define asin(z) __tgmath_real(z, asin) +#define atan(z) __tgmath_real(z, atan) +#define acosh(z) __tgmath_real(z, acosh) +#define asinh(z) __tgmath_real(z, asinh) +#define atanh(z) __tgmath_real(z, atanh) +#define cos(z) __tgmath_real(z, cos) +#define sin(z) __tgmath_real(z, sin) +#define tan(z) __tgmath_real(z, tan) +#define cosh(z) __tgmath_real(z, cosh) +#define sinh(z) __tgmath_real(z, sinh) +#define tanh(z) __tgmath_real(z, tanh) +#define exp(z) __tgmath_real(z, exp) +#define log(z) __tgmath_real(z, log) +#define pow(z1,z2) __tgmath_real_2(z1, z2, pow) +#define sqrt(z) __tgmath_real(z, sqrt) +#define fabs(z) __tgmath_real(z, fabs) + +/* Functions defined in only (7.22p5) */ +#define atan2(x,y) __tgmath_real_2(x, y, atan2) +#define cbrt(x) __tgmath_real(x, cbrt) +#define ceil(x) __tgmath_real(x, ceil) +#define copysign(x,y) __tgmath_real_2(x, y, copysign) +#define erf(x) __tgmath_real(x, erf) +#define erfc(x) __tgmath_real(x, erfc) +#define exp2(x) __tgmath_real(x, exp2) +#define expm1(x) __tgmath_real(x, expm1) +#define fdim(x,y) __tgmath_real_2(x, y, fdim) +#define floor(x) __tgmath_real(x, floor) +#define fma(x,y,z) __tgmath_real_3(x, y, z, fma) +#define fmax(x,y) __tgmath_real_2(x, y, fmax) +#define fmin(x,y) __tgmath_real_2(x, y, fmin) +#define fmod(x,y) __tgmath_real_2(x, y, fmod) +#define frexp(x,y) __tgmath_real_2_1(x, y, frexp) +#define hypot(x,y) __tgmath_real_2(x, y, hypot) +#define ilogb(x) __tgmath_real(x, ilogb) +#define ldexp(x,y) __tgmath_real_2_1(x, y, ldexp) +#define lgamma(x) __tgmath_real(x, lgamma) +#define llrint(x) __tgmath_real(x, llrint) +#define llround(x) __tgmath_real(x, llround) +#define log10(x) __tgmath_real(x, log10) +#define log1p(x) __tgmath_real(x, log1p) +#define log2(x) __tgmath_real(x, log2) +#define logb(x) __tgmath_real(x, logb) +#define lrint(x) __tgmath_real(x, lrint) +#define lround(x) __tgmath_real(x, lround) +#define nearbyint(x) __tgmath_real(x, nearbyint) +#define nextafter(x,y) __tgmath_real_2(x, y, nextafter) +#define nexttoward(x,y) __tgmath_real_2(x, y, nexttoward) +#define remainder(x,y) __tgmath_real_2(x, y, remainder) +#define remquo(x,y,z) __tgmath_real_3_2(x, y, z, remquo) +#define rint(x) __tgmath_real(x, rint) +#define round(x) __tgmath_real(x, round) +#define scalbln(x,y) __tgmath_real_2_1(x, y, scalbln) +#define scalbn(x,y) __tgmath_real_2_1(x, y, scalbn) +#define tgamma(x) __tgmath_real(x, tgamma) +#define trunc(x) __tgmath_real(x, trunc) + +/* Functions defined in only (7.22p6) +#define carg(z) __tgmath_cplx_only(z, carg) +#define cimag(z) __tgmath_cplx_only(z, cimag) +#define conj(z) __tgmath_cplx_only(z, conj) +#define cproj(z) __tgmath_cplx_only(z, cproj) +#define creal(z) __tgmath_cplx_only(z, creal) +*/ +#endif /* __cplusplus */ +#endif /* _TGMATH_H */ diff --git a/tcc/include/time.h b/tcc/include/time.h index 6c72e266..7846d2f2 100644 --- a/tcc/include/time.h +++ b/tcc/include/time.h @@ -1,287 +1,287 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _TIME_H_ -#define _TIME_H_ - -#include <_mingw.h> - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef _WCHAR_T_DEFINED -#define _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#endif - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED - typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int _time64_t __attribute__ ((mode (DI))); -#else - typedef __int64 __time64_t; -#endif -#endif -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#endif - -#ifndef _CLOCK_T_DEFINED -#define _CLOCK_T_DEFINED - typedef long clock_t; -#endif - -#ifndef _SIZE_T_DEFINED -#define _SIZE_T_DEFINED -#undef size_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef unsigned int size_t __attribute__ ((mode (DI))); -#else - typedef unsigned __int64 size_t; -#endif -#else - typedef unsigned int size_t; -#endif -#endif - -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#undef ssize_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int ssize_t __attribute__ ((mode (DI))); -#else - typedef __int64 ssize_t; -#endif -#else - typedef int ssize_t; -#endif -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifdef _USE_32BIT_TIME_T -#define _localtime32 localtime -#define _difftime32 difftime -#define _ctime32 ctime -#define _gmtime32 gmtime -#define _mktime32 mktime -#define _time32 time -#endif - -#ifndef _TM_DEFINED -#define _TM_DEFINED - struct tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - }; -#endif - -#define CLOCKS_PER_SEC 1000 - - __MINGW_IMPORT int _daylight; - __MINGW_IMPORT long _dstbias; - __MINGW_IMPORT long _timezone; - __MINGW_IMPORT char * _tzname[2]; - _CRTIMP errno_t __cdecl _get_daylight(int *_Daylight); - _CRTIMP errno_t __cdecl _get_dstbias(long *_Daylight_savings_bias); - _CRTIMP errno_t __cdecl _get_timezone(long *_Timezone); - _CRTIMP errno_t __cdecl _get_tzname(size_t *_ReturnValue,char *_Buffer,size_t _SizeInBytes,int _Index); - char *__cdecl asctime(const struct tm *_Tm); - _CRTIMP char *__cdecl _ctime32(const __time32_t *_Time); - clock_t __cdecl clock(void); - _CRTIMP double __cdecl _difftime32(__time32_t _Time1,__time32_t _Time2); - _CRTIMP struct tm *__cdecl _gmtime32(const __time32_t *_Time); - _CRTIMP struct tm *__cdecl _localtime32(const __time32_t *_Time); - size_t __cdecl strftime(char *_Buf,size_t _SizeInBytes,const char *_Format,const struct tm *_Tm); - _CRTIMP size_t __cdecl _strftime_l(char *_Buf,size_t _Max_size,const char *_Format,const struct tm *_Tm,_locale_t _Locale); - _CRTIMP char *__cdecl _strdate(char *_Buffer); - _CRTIMP char *__cdecl _strtime(char *_Buffer); - _CRTIMP __time32_t __cdecl _time32(__time32_t *_Time); - _CRTIMP __time32_t __cdecl _mktime32(struct tm *_Tm); - _CRTIMP __time32_t __cdecl _mkgmtime32(struct tm *_Tm); -#if defined (_POSIX_) || defined(__GNUC__) - void __cdecl tzset(void); -#else - _CRTIMP void __cdecl _tzset(void); -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - double __cdecl _difftime64(__time64_t _Time1,__time64_t _Time2); - _CRTIMP char *__cdecl _ctime64(const __time64_t *_Time); - _CRTIMP struct tm *__cdecl _gmtime64(const __time64_t *_Time); - _CRTIMP struct tm *__cdecl _localtime64(const __time64_t *_Time); - _CRTIMP __time64_t __cdecl _mktime64(struct tm *_Tm); - _CRTIMP __time64_t __cdecl _mkgmtime64(struct tm *_Tm); - _CRTIMP __time64_t __cdecl _time64(__time64_t *_Time); -#endif - unsigned __cdecl _getsystime(struct tm *_Tm); - unsigned __cdecl _setsystime(struct tm *_Tm,unsigned _MilliSec); - -#ifndef _SIZE_T_DEFINED -#define _SIZE_T_DEFINED -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef unsigned int size_t __attribute__ ((mode (DI))); -#else - typedef unsigned __int64 size_t; -#endif -#else - typedef unsigned long size_t; -#endif -#endif - -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int ssize_t __attribute__ ((mode (DI))); -#else - typedef __int64 ssize_t; -#endif -#else - typedef long ssize_t; -#endif -#endif - -#ifndef _WTIME_DEFINED - _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); - _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); - size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); - _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); - _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) -#define _INC_WTIME_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } -#else -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } -#endif -#endif - -#define _WTIME_DEFINED -#endif - -#ifndef RC_INVOKED -double __cdecl difftime(time_t _Time1,time_t _Time2); -char *__cdecl ctime(const time_t *_Time); -struct tm *__cdecl gmtime(const time_t *_Time); -struct tm *__cdecl localtime(const time_t *_Time); -struct tm *__cdecl localtime_r(const time_t *_Time,struct tm *); - -time_t __cdecl mktime(struct tm *_Tm); -time_t __cdecl _mkgmtime(struct tm *_Tm); -time_t __cdecl time(time_t *_Time); - -#ifdef _USE_32BIT_TIME_T -#if 0 -__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime32(_Time1,_Time2); } -__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime32(_Time); } -__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime32(_Time); } -__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime32(_Time); } -__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime32(_Tm); } -__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime32(_Tm); } -__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time32(_Time); } -#endif -#else -__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime64(_Time1,_Time2); } -__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime64(_Time); } -__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime64(_Time); } -__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime64(_Time); } -__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime64(_Tm); } -__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime64(_Tm); } -__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time64(_Time); } -#endif -#endif - -#if !defined(NO_OLDNAMES) || defined(_POSIX) -#define CLK_TCK CLOCKS_PER_SEC - - __MINGW_IMPORT int daylight; - __MINGW_IMPORT long dstbias; - __MINGW_IMPORT long timezone; - __MINGW_IMPORT char *tzname[2]; - void __cdecl tzset(void); -#endif - -#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ -#define _TIMEVAL_DEFINED -struct timeval { - long tv_sec; - long tv_usec; -}; -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif /* _TIMEVAL_DEFINED */ - -#ifndef __STRICT_ANSI__ -#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ -#define _TIMEZONE_DEFINED -struct timezone { - int tz_minuteswest; - int tz_dsttime; -}; - - extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); -#endif -#endif /* __STRICT_ANSI__ */ - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include - -/* Adding timespec definition. */ -#include - -#endif /* End _TIME_H_ */ - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _TIME_H_ +#define _TIME_H_ + +#include <_mingw.h> + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef _WCHAR_T_DEFINED +#define _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#endif + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED + typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int _time64_t __attribute__ ((mode (DI))); +#else + typedef __int64 __time64_t; +#endif +#endif +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#endif + +#ifndef _CLOCK_T_DEFINED +#define _CLOCK_T_DEFINED + typedef long clock_t; +#endif + +#ifndef _SIZE_T_DEFINED +#define _SIZE_T_DEFINED +#undef size_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef unsigned int size_t __attribute__ ((mode (DI))); +#else + typedef unsigned __int64 size_t; +#endif +#else + typedef unsigned int size_t; +#endif +#endif + +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#undef ssize_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int ssize_t __attribute__ ((mode (DI))); +#else + typedef __int64 ssize_t; +#endif +#else + typedef int ssize_t; +#endif +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifdef _USE_32BIT_TIME_T +#define _localtime32 localtime +#define _difftime32 difftime +#define _ctime32 ctime +#define _gmtime32 gmtime +#define _mktime32 mktime +#define _time32 time +#endif + +#ifndef _TM_DEFINED +#define _TM_DEFINED + struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + }; +#endif + +#define CLOCKS_PER_SEC 1000 + + __MINGW_IMPORT int _daylight; + __MINGW_IMPORT long _dstbias; + __MINGW_IMPORT long _timezone; + __MINGW_IMPORT char * _tzname[2]; + _CRTIMP errno_t __cdecl _get_daylight(int *_Daylight); + _CRTIMP errno_t __cdecl _get_dstbias(long *_Daylight_savings_bias); + _CRTIMP errno_t __cdecl _get_timezone(long *_Timezone); + _CRTIMP errno_t __cdecl _get_tzname(size_t *_ReturnValue,char *_Buffer,size_t _SizeInBytes,int _Index); + char *__cdecl asctime(const struct tm *_Tm); + _CRTIMP char *__cdecl _ctime32(const __time32_t *_Time); + clock_t __cdecl clock(void); + _CRTIMP double __cdecl _difftime32(__time32_t _Time1,__time32_t _Time2); + _CRTIMP struct tm *__cdecl _gmtime32(const __time32_t *_Time); + _CRTIMP struct tm *__cdecl _localtime32(const __time32_t *_Time); + size_t __cdecl strftime(char *_Buf,size_t _SizeInBytes,const char *_Format,const struct tm *_Tm); + _CRTIMP size_t __cdecl _strftime_l(char *_Buf,size_t _Max_size,const char *_Format,const struct tm *_Tm,_locale_t _Locale); + _CRTIMP char *__cdecl _strdate(char *_Buffer); + _CRTIMP char *__cdecl _strtime(char *_Buffer); + _CRTIMP __time32_t __cdecl _time32(__time32_t *_Time); + _CRTIMP __time32_t __cdecl _mktime32(struct tm *_Tm); + _CRTIMP __time32_t __cdecl _mkgmtime32(struct tm *_Tm); +#if defined (_POSIX_) || defined(__GNUC__) + void __cdecl tzset(void); +#else + _CRTIMP void __cdecl _tzset(void); +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + double __cdecl _difftime64(__time64_t _Time1,__time64_t _Time2); + _CRTIMP char *__cdecl _ctime64(const __time64_t *_Time); + _CRTIMP struct tm *__cdecl _gmtime64(const __time64_t *_Time); + _CRTIMP struct tm *__cdecl _localtime64(const __time64_t *_Time); + _CRTIMP __time64_t __cdecl _mktime64(struct tm *_Tm); + _CRTIMP __time64_t __cdecl _mkgmtime64(struct tm *_Tm); + _CRTIMP __time64_t __cdecl _time64(__time64_t *_Time); +#endif + unsigned __cdecl _getsystime(struct tm *_Tm); + unsigned __cdecl _setsystime(struct tm *_Tm,unsigned _MilliSec); + +#ifndef _SIZE_T_DEFINED +#define _SIZE_T_DEFINED +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef unsigned int size_t __attribute__ ((mode (DI))); +#else + typedef unsigned __int64 size_t; +#endif +#else + typedef unsigned long size_t; +#endif +#endif + +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int ssize_t __attribute__ ((mode (DI))); +#else + typedef __int64 ssize_t; +#endif +#else + typedef long ssize_t; +#endif +#endif + +#ifndef _WTIME_DEFINED + _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); + _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); + size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); + _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); + _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) +#define _INC_WTIME_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } +#else +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } +#endif +#endif + +#define _WTIME_DEFINED +#endif + +#ifndef RC_INVOKED +double __cdecl difftime(time_t _Time1,time_t _Time2); +char *__cdecl ctime(const time_t *_Time); +struct tm *__cdecl gmtime(const time_t *_Time); +struct tm *__cdecl localtime(const time_t *_Time); +struct tm *__cdecl localtime_r(const time_t *_Time,struct tm *); + +time_t __cdecl mktime(struct tm *_Tm); +time_t __cdecl _mkgmtime(struct tm *_Tm); +time_t __cdecl time(time_t *_Time); + +#ifdef _USE_32BIT_TIME_T +#if 0 +__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime32(_Time1,_Time2); } +__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime32(_Time); } +__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime32(_Time); } +__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime32(_Time); } +__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime32(_Tm); } +__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime32(_Tm); } +__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time32(_Time); } +#endif +#else +__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime64(_Time1,_Time2); } +__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime64(_Time); } +__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime64(_Time); } +__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime64(_Time); } +__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime64(_Tm); } +__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime64(_Tm); } +__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time64(_Time); } +#endif +#endif + +#if !defined(NO_OLDNAMES) || defined(_POSIX) +#define CLK_TCK CLOCKS_PER_SEC + + __MINGW_IMPORT int daylight; + __MINGW_IMPORT long dstbias; + __MINGW_IMPORT long timezone; + __MINGW_IMPORT char *tzname[2]; + void __cdecl tzset(void); +#endif + +#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ +#define _TIMEVAL_DEFINED +struct timeval { + long tv_sec; + long tv_usec; +}; +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif /* _TIMEVAL_DEFINED */ + +#ifndef __STRICT_ANSI__ +#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ +#define _TIMEZONE_DEFINED +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + + extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); +#endif +#endif /* __STRICT_ANSI__ */ + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include + +/* Adding timespec definition. */ +#include + +#endif /* End _TIME_H_ */ + diff --git a/tcc/include/uchar.h b/tcc/include/uchar.h index 1a2c0294..4e9b13ce 100644 --- a/tcc/include/uchar.h +++ b/tcc/include/uchar.h @@ -1,33 +1,33 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the TinyCC package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _INC_UCHAR -#define _INC_UCHAR - -/* - * The following defines are only valid when C11 (-std=c11) is used. - * - * ... a wide character constant prefixed by the letter u or U has type char16_t - * or char32_t, respectively, unsigned integer types defined in the - * header. - */ - -#if __STDC_VERSION__ >= 201112L -/** - * __STDC_UTF_16__ The integer constant 1, intended to indicate that - * values of type char16_t are UTF-16 encoded. - */ -#define __STDC_UTF_16__ 1 -/** - * __STDC_UTF_32__ The integer constant 1, intended to indicate that - * values of type char32_t are UTF-32 encoded. - */ -#define __STDC_UTF_32__ 1 - -typedef unsigned short char16_t; -typedef unsigned int char32_t; -#endif /* __STDC_VERSION__ >= 201112L */ -#endif /* _INC_UCHAR */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the TinyCC package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _INC_UCHAR +#define _INC_UCHAR + +/* + * The following defines are only valid when C11 (-std=c11) is used. + * + * ... a wide character constant prefixed by the letter u or U has type char16_t + * or char32_t, respectively, unsigned integer types defined in the + * header. + */ + +#if __STDC_VERSION__ >= 201112L +/** + * __STDC_UTF_16__ The integer constant 1, intended to indicate that + * values of type char16_t are UTF-16 encoded. + */ +#define __STDC_UTF_16__ 1 +/** + * __STDC_UTF_32__ The integer constant 1, intended to indicate that + * values of type char32_t are UTF-32 encoded. + */ +#define __STDC_UTF_32__ 1 + +typedef unsigned short char16_t; +typedef unsigned int char32_t; +#endif /* __STDC_VERSION__ >= 201112L */ +#endif /* _INC_UCHAR */ diff --git a/tcc/include/vadefs.h b/tcc/include/vadefs.h index 749b0bdd..bb6eacea 100644 --- a/tcc/include/vadefs.h +++ b/tcc/include/vadefs.h @@ -1,11 +1,11 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_VADEFS -#define _INC_VADEFS - -//!__TINYC__: GNUC specific stuff removed - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_VADEFS +#define _INC_VADEFS + +//!__TINYC__: GNUC specific stuff removed + +#endif diff --git a/tcc/include/values.h b/tcc/include/values.h index 1cd643ce..8b821727 100644 --- a/tcc/include/values.h +++ b/tcc/include/values.h @@ -1,4 +1,4 @@ -/* - * TODO: Nothing here yet. Should provide UNIX compatibility constants - * comparable to those in limits.h and float.h. - */ +/* + * TODO: Nothing here yet. Should provide UNIX compatibility constants + * comparable to those in limits.h and float.h. + */ diff --git a/tcc/include/varargs.h b/tcc/include/varargs.h index d614366e..4e3d5a55 100644 --- a/tcc/include/varargs.h +++ b/tcc/include/varargs.h @@ -1,12 +1,12 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _VARARGS_H -#define _VARARGS_H - -#error "TinyCC no longer implements ." -#error "Revise your code to use ." - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _VARARGS_H +#define _VARARGS_H + +#error "TinyCC no longer implements ." +#error "Revise your code to use ." + +#endif diff --git a/tcc/include/wchar.h b/tcc/include/wchar.h index 389196fa..0069f1fa 100644 --- a/tcc/include/wchar.h +++ b/tcc/include/wchar.h @@ -1,873 +1,873 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_WCHAR -#define _INC_WCHAR - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WCHAR_MIN /* also at stdint.h */ -#define WCHAR_MIN 0 -#define WCHAR_MAX ((wchar_t) -1) /* UINT16_MAX */ -#endif - -#ifndef __GNUC_VA_LIST -#define __GNUC_VA_LIST - typedef __builtin_va_list __gnuc_va_list; -#endif - -#ifndef _VA_LIST_DEFINED -#define _VA_LIST_DEFINED - typedef __gnuc_va_list va_list; -#endif - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifndef _FILE_DEFINED - struct _iobuf { - char *_ptr; - int _cnt; - char *_base; - int _flag; - int _file; - int _charbuf; - int _bufsiz; - char *_tmpfname; - }; - typedef struct _iobuf FILE; -#define _FILE_DEFINED -#endif - -#ifndef _STDIO_DEFINED -#ifdef _WIN64 - _CRTIMP FILE *__cdecl __iob_func(void); -#else -#ifdef _MSVCRT_ -extern FILE _iob[]; /* A pointer to an array of FILE */ -#define __iob_func() (_iob) -#else -extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ -#define __iob_func() (*_imp___iob) -#define _iob __iob_func() -#endif -#endif - -#define _iob __iob_func() -#endif - -#ifndef _STDSTREAM_DEFINED -#define stdin (&__iob_func()[0]) -#define stdout (&__iob_func()[1]) -#define stderr (&__iob_func()[2]) -#define _STDSTREAM_DEFINED -#endif - -#ifndef _FSIZE_T_DEFINED - typedef unsigned long _fsize_t; -#define _FSIZE_T_DEFINED -#endif - -#ifndef _WFINDDATA_T_DEFINED - struct _wfinddata32_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - -/* #if _INTEGRAL_MAX_BITS >= 64 */ - - struct _wfinddata32i64_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - __int64 size; - wchar_t name[260]; - }; - - struct _wfinddata64i32_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - - struct _wfinddata64_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - __int64 size; - wchar_t name[260]; - }; -/* #endif */ - -#ifdef _USE_32BIT_TIME_T -#define _wfinddata_t _wfinddata32_t -#define _wfinddatai64_t _wfinddata32i64_t - -#define _wfindfirst _wfindfirst32 -#define _wfindnext _wfindnext32 -#define _wfindfirsti64 _wfindfirst32i64 -#define _wfindnexti64 _wfindnext32i64 -#else -#define _wfinddata_t _wfinddata64i32_t -#define _wfinddatai64_t _wfinddata64_t - -#define _wfindfirst _wfindfirst64i32 -#define _wfindnext _wfindnext64i32 -#define _wfindfirsti64 _wfindfirst64 -#define _wfindnexti64 _wfindnext64 -#endif - -#define _WFINDDATA_T_DEFINED -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifndef _CONST_RETURN -#define _CONST_RETURN -#endif - -#define _WConst_return _CONST_RETURN - -#ifndef _CRT_CTYPEDATA_DEFINED -#define _CRT_CTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef __PCTYPE_FUNC -#define __PCTYPE_FUNC __pctype_func() -#ifdef _MSVCRT_ -#define __pctype_func() (_pctype) -#else -#define __pctype_func() (*_imp___pctype) -#endif -#endif - -#ifndef _pctype -#ifdef _MSVCRT_ - extern unsigned short *_pctype; -#else - extern unsigned short **_imp___pctype; -#define _pctype (*_imp___pctype) -#endif -#endif -#endif -#endif - -#ifndef _CRT_WCTYPEDATA_DEFINED -#define _CRT_WCTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS -#ifndef _wctype -#ifdef _MSVCRT_ - extern unsigned short *_wctype; -#else - extern unsigned short **_imp___wctype; -#define _wctype (*_imp___wctype) -#endif -#endif - -#ifdef _MSVCRT_ -#define __pwctype_func() (_pwctype) -#else -#define __pwctype_func() (*_imp___pwctype) -#endif - -#ifndef _pwctype -#ifdef _MSVCRT_ - extern unsigned short *_pwctype; -#else - extern unsigned short **_imp___pwctype; -#define _pwctype (*_imp___pwctype) -#endif -#endif - -#endif -#endif - -#define _UPPER 0x1 -#define _LOWER 0x2 -#define _DIGIT 0x4 -#define _SPACE 0x8 - -#define _PUNCT 0x10 -#define _CONTROL 0x20 -#define _BLANK 0x40 -#define _HEX 0x80 - -#define _LEADBYTE 0x8000 -#define _ALPHA (0x0100|_UPPER|_LOWER) - -#ifndef _WCTYPE_DEFINED -#define _WCTYPE_DEFINED - - int __cdecl iswalpha(wint_t _C); - _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); - int __cdecl iswupper(wint_t _C); - _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); - int __cdecl iswlower(wint_t _C); - _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswdigit(wint_t _C); - _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswxdigit(wint_t _C); - _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswspace(wint_t _C); - _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); - int __cdecl iswpunct(wint_t _C); - _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); - int __cdecl iswalnum(wint_t _C); - _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); - int __cdecl iswprint(wint_t _C); - _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); - int __cdecl iswgraph(wint_t _C); - _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); - int __cdecl iswcntrl(wint_t _C); - _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); - int __cdecl iswascii(wint_t _C); - int __cdecl isleadbyte(int _C); - _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); - wint_t __cdecl towupper(wint_t _C); - _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); - wint_t __cdecl towlower(wint_t _C); - _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswctype(wint_t _C,wctype_t _Type); - _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsymf(wint_t _C); - _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsym(wint_t _C); - _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); - int __cdecl is_wctype(wint_t _C,wctype_t _Type); -#endif - -#ifndef _WDIRECT_DEFINED -#define _WDIRECT_DEFINED - - _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); -#endif - -#ifndef _WIO_DEFINED -#define _WIO_DEFINED - - _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); - _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); - _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); - _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); - _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); - _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); - intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); - _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); - _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); - int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); - _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); -#endif - _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); -#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) - _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); - _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); -#else - extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); - extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); -#endif -#endif - -#ifndef _WLOCALE_DEFINED -#define _WLOCALE_DEFINED - _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); -#endif - -#ifndef _WPROCESS_DEFINED -#define _WPROCESS_DEFINED - - _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif -#endif - -#ifndef _WCTYPE_INLINE_DEFINED -#undef _CRT_WCTYPE_NOINLINE -#if !defined(__cplusplus) || defined(_CRT_WCTYPE_NOINLINE) -#define iswalpha(_c) (iswctype(_c,_ALPHA)) -#define iswupper(_c) (iswctype(_c,_UPPER)) -#define iswlower(_c) (iswctype(_c,_LOWER)) -#define iswdigit(_c) (iswctype(_c,_DIGIT)) -#define iswxdigit(_c) (iswctype(_c,_HEX)) -#define iswspace(_c) (iswctype(_c,_SPACE)) -#define iswpunct(_c) (iswctype(_c,_PUNCT)) -#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) -#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) -#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) -#define iswcntrl(_c) (iswctype(_c,_CONTROL)) -#define iswascii(_c) ((unsigned)(_c) < 0x80) - -#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) -#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) -#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) -#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) -#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) -#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) -#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) -#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) -#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) -#ifndef _CTYPE_DISABLE_MACROS -#define isleadbyte(_c) (__PCTYPE_FUNC[(unsigned char)(_c)] & _LEADBYTE) -#endif -#endif -#define _WCTYPE_INLINE_DEFINED -#endif - -#if !defined(_POSIX_) || defined(__GNUC__) -#ifndef _INO_T_DEFINED -#define _INO_T_DEFINED - typedef unsigned short _ino_t; -#ifndef NO_OLDNAMES - typedef unsigned short ino_t; -#endif -#endif - -#ifndef _DEV_T_DEFINED -#define _DEV_T_DEFINED - typedef unsigned int _dev_t; -#ifndef NO_OLDNAMES - typedef unsigned int dev_t; -#endif -#endif - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif - -#ifndef _STAT_DEFINED -#define _STAT_DEFINED - -#ifdef _USE_32BIT_TIME_T -#ifdef WIN64 -#define _fstat _fstat32 -#define _stat _stat32 -#define _wstat _wstat32 -#else -#define _fstat32 _fstat -#define _stat32 _stat -#define _wstat32 _wstat -#endif -#define _fstati64 _fstat32i64 -#define _stati64 _stat32i64 -#define _wstati64 _wstat32i64 -#else -#define _fstat _fstat64i32 -#define _fstati64 _fstat64 -#define _stat _stat64i32 -#define _stati64 _stat64 -#define _wstat _wstat64i32 -#define _wstati64 _wstat64 -#endif - - struct _stat32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - -#ifndef NO_OLDNAMES - struct stat { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; - }; -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - - struct _stat32i64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - - struct _stat64i32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; - - struct _stat64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; -#endif - -#define __stat64 _stat64 - -#endif - -#ifndef _WSTAT_DEFINED -#define _WSTAT_DEFINED - - _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); - int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); - _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); -#endif -#endif -#endif - -#ifndef _WCONIO_DEFINED -#define _WCONIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - - _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _getwch(void); - _CRTIMP wint_t __cdecl _getwche(void); - _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); - _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); - _CRTIMP int __cdecl _cputws(const wchar_t *_String); - _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); - - _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - wint_t __cdecl _putwch_nolock(wchar_t _WCh); - wint_t __cdecl _getwch_nolock(void); - wint_t __cdecl _getwche_nolock(void); - wint_t __cdecl _ungetwch_nolock(wint_t _WCh); -#endif - -#ifndef _WSTDIO_DEFINED -#define _WSTDIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifdef _POSIX_ - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); -#else - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); -#endif - - wint_t __cdecl fgetwc(FILE *_File); - _CRTIMP wint_t __cdecl _fgetwchar(void); - wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); - wint_t __cdecl getwc(FILE *_File); - wint_t __cdecl getwchar(void); - wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); - wint_t __cdecl putwchar(wchar_t _Ch); - wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); - wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); - int __cdecl fputws(const wchar_t *_Str,FILE *_File); - _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); - _CRTIMP int __cdecl _putws(const wchar_t *_Str); - int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); - int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); - int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); - _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); - _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); -#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ - int __cdecl snwprintf (wchar_t *s, size_t n, const wchar_t * format, ...); - __CRT_INLINE int __cdecl vsnwprintf (wchar_t *s, size_t n, const wchar_t *format, va_list arg) { return _vsnwprintf(s,n,format,arg); } - int __cdecl vwscanf (const wchar_t *, va_list); - int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); - int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); -#endif - _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); - _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); - _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); - _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); -#ifndef RC_INVOKED -#include -#endif - -#ifdef _CRT_NON_CONFORMING_SWPRINTFS -#ifndef __cplusplus -#define swprintf _swprintf -#define vswprintf _vswprintf -#define _swprintf_l __swprintf_l -#define _vswprintf_l __vswprintf_l -#endif -#endif - - _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); - _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); - _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); - _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - int __cdecl wscanf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); - -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); -#if !defined(NO_OLDNAMES) && !defined(wpopen) -#define wpopen _wpopen -#endif - _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); - _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); - _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); - -#undef _CRT_GETPUTWCHAR_NOINLINE - -#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) -#define getwchar() fgetwc(stdin) -#define putwchar(_c) fputwc((_c),stdout) -#else - __CRT_INLINE wint_t __cdecl getwchar() {return (fgetwc(stdin)); } - __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) {return (fputwc(_C,stdout)); } -#endif - -#define getwc(_stm) fgetwc(_stm) -#define putwc(_c,_stm) fputwc(_c,_stm) -#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) -#define _getwc_nolock(_c) _fgetwc_nolock(_c) -#endif - -#ifndef _WSTDLIB_DEFINED -#define _WSTDLIB_DEFINED - - _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); - double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); - _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); - float __cdecl wcstof( const wchar_t *nptr, wchar_t **endptr); -#if !defined __NO_ISOCEXT /* in libmingwex.a */ - float __cdecl wcstof (const wchar_t * __restrict__, wchar_t ** __restrict__); - long double __cdecl wcstold (const wchar_t * __restrict__, wchar_t ** __restrict__); -#endif /* __NO_ISOCEXT */ - long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif - _CRTIMP double __cdecl _wtof(const wchar_t *_Str); - _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); - _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP long __cdecl _wtol(const wchar_t *_Str); - _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); - _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); -#endif -#endif - -#ifndef _POSIX_ -#ifndef _WSTDLIBP_DEFINED -#define _WSTDLIBP_DEFINED - _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); - _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); - _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); - _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); -#endif -#endif - -#ifndef _WSTRING_DEFINED -#define _WSTRING_DEFINED - _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); - wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); - _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); - int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); - wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); - size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); - size_t __cdecl wcslen(const wchar_t *_Str); - size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); - wchar_t *__cdecl wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *__cdecl wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); - size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); - wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); - _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); - _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); - _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); - _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); - _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); - _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); - _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); - size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); - _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); - int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - -#ifndef NO_OLDNAMES - wchar_t *__cdecl wcsdup(const wchar_t *_Str); -#define wcswcs wcsstr - int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - wchar_t *__cdecl wcsrev(wchar_t *_Str); - wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); - wchar_t *__cdecl wcslwr(wchar_t *_Str); - wchar_t *__cdecl wcsupr(wchar_t *_Str); - int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); -#endif -#endif - -#ifndef _TM_DEFINED -#define _TM_DEFINED - struct tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - }; -#endif - -#ifndef _WTIME_DEFINED -#define _WTIME_DEFINED - - _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); - _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); - size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); - _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); - _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) -#define _INC_WTIME_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } -#else -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } -#endif -#endif -#endif - - typedef int mbstate_t; - typedef wchar_t _Wint_t; - - wint_t __cdecl btowc(int); - size_t __cdecl mbrlen(const char *_Ch,size_t _SizeInBytes,mbstate_t *_State); - size_t __cdecl mbrtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SizeInBytes,mbstate_t *_State); - size_t __cdecl mbsrtowcs(wchar_t *_Dest,const char **_PSrc,size_t _Count,mbstate_t *_State); - size_t __cdecl wcrtomb(char *_Dest,wchar_t _Source,mbstate_t *_State); - size_t __cdecl wcsrtombs(char *_Dest,const wchar_t **_PSource,size_t _Count,mbstate_t *_State); - int __cdecl wctob(wint_t _WCh); - -#ifndef __NO_ISOCEXT /* these need static lib libmingwex.a */ - wchar_t *__cdecl wmemset(wchar_t *s, wchar_t c, size_t n); - _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *s, wchar_t c, size_t n); - int wmemcmp(const wchar_t *s1, const wchar_t *s2,size_t n); - wchar_t *__cdecl wmemcpy(wchar_t *s1,const wchar_t *s2,size_t n); - wchar_t *__cdecl wmemmove(wchar_t *s1, const wchar_t *s2, size_t n); - long long __cdecl wcstoll(const wchar_t *nptr,wchar_t **endptr, int base); - unsigned long long __cdecl wcstoull(const wchar_t *nptr,wchar_t **endptr, int base); -#endif /* __NO_ISOCEXT */ - - void *__cdecl memmove(void *_Dst,const void *_Src,size_t _MaxCount); - void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _MaxCount); - __CRT_INLINE int __cdecl fwide(FILE *_F,int _M) { (void)_F; return (_M); } - __CRT_INLINE int __cdecl mbsinit(const mbstate_t *_P) { return (!_P || *_P==0); } - __CRT_INLINE _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *_S,wchar_t _C,size_t _N) { for (;0<_N;++_S,--_N) if (*_S==_C) return (_CONST_RETURN wchar_t *)(_S); return (0); } - __CRT_INLINE int __cdecl wmemcmp(const wchar_t *_S1,const wchar_t *_S2,size_t _N) { for (; 0 < _N; ++_S1,++_S2,--_N) if (*_S1!=*_S2) return (*_S1 < *_S2 ? -1 : +1); return (0); } - __CRT_INLINE wchar_t *__cdecl wmemcpy(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memcpy(_S1,_S2,_N*sizeof(wchar_t)); } - __CRT_INLINE wchar_t *__cdecl wmemmove(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memmove(_S1,_S2,_N*sizeof(wchar_t)); } - __CRT_INLINE wchar_t *__cdecl wmemset(wchar_t *_S,wchar_t _C,size_t _N) { - wchar_t *_Su = _S; - for (;0<_N;++_Su,--_N) { - *_Su = _C; - } - return (_S); - } -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_WCHAR +#define _INC_WCHAR + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WCHAR_MIN /* also at stdint.h */ +#define WCHAR_MIN 0 +#define WCHAR_MAX ((wchar_t) -1) /* UINT16_MAX */ +#endif + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST + typedef __builtin_va_list __gnuc_va_list; +#endif + +#ifndef _VA_LIST_DEFINED +#define _VA_LIST_DEFINED + typedef __gnuc_va_list va_list; +#endif + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifndef _FILE_DEFINED + struct _iobuf { + char *_ptr; + int _cnt; + char *_base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char *_tmpfname; + }; + typedef struct _iobuf FILE; +#define _FILE_DEFINED +#endif + +#ifndef _STDIO_DEFINED +#ifdef _WIN64 + _CRTIMP FILE *__cdecl __iob_func(void); +#else +#ifdef _MSVCRT_ +extern FILE _iob[]; /* A pointer to an array of FILE */ +#define __iob_func() (_iob) +#else +extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ +#define __iob_func() (*_imp___iob) +#define _iob __iob_func() +#endif +#endif + +#define _iob __iob_func() +#endif + +#ifndef _STDSTREAM_DEFINED +#define stdin (&__iob_func()[0]) +#define stdout (&__iob_func()[1]) +#define stderr (&__iob_func()[2]) +#define _STDSTREAM_DEFINED +#endif + +#ifndef _FSIZE_T_DEFINED + typedef unsigned long _fsize_t; +#define _FSIZE_T_DEFINED +#endif + +#ifndef _WFINDDATA_T_DEFINED + struct _wfinddata32_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + +/* #if _INTEGRAL_MAX_BITS >= 64 */ + + struct _wfinddata32i64_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + __int64 size; + wchar_t name[260]; + }; + + struct _wfinddata64i32_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + + struct _wfinddata64_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + __int64 size; + wchar_t name[260]; + }; +/* #endif */ + +#ifdef _USE_32BIT_TIME_T +#define _wfinddata_t _wfinddata32_t +#define _wfinddatai64_t _wfinddata32i64_t + +#define _wfindfirst _wfindfirst32 +#define _wfindnext _wfindnext32 +#define _wfindfirsti64 _wfindfirst32i64 +#define _wfindnexti64 _wfindnext32i64 +#else +#define _wfinddata_t _wfinddata64i32_t +#define _wfinddatai64_t _wfinddata64_t + +#define _wfindfirst _wfindfirst64i32 +#define _wfindnext _wfindnext64i32 +#define _wfindfirsti64 _wfindfirst64 +#define _wfindnexti64 _wfindnext64 +#endif + +#define _WFINDDATA_T_DEFINED +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef _CONST_RETURN +#define _CONST_RETURN +#endif + +#define _WConst_return _CONST_RETURN + +#ifndef _CRT_CTYPEDATA_DEFINED +#define _CRT_CTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef __PCTYPE_FUNC +#define __PCTYPE_FUNC __pctype_func() +#ifdef _MSVCRT_ +#define __pctype_func() (_pctype) +#else +#define __pctype_func() (*_imp___pctype) +#endif +#endif + +#ifndef _pctype +#ifdef _MSVCRT_ + extern unsigned short *_pctype; +#else + extern unsigned short **_imp___pctype; +#define _pctype (*_imp___pctype) +#endif +#endif +#endif +#endif + +#ifndef _CRT_WCTYPEDATA_DEFINED +#define _CRT_WCTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS +#ifndef _wctype +#ifdef _MSVCRT_ + extern unsigned short *_wctype; +#else + extern unsigned short **_imp___wctype; +#define _wctype (*_imp___wctype) +#endif +#endif + +#ifdef _MSVCRT_ +#define __pwctype_func() (_pwctype) +#else +#define __pwctype_func() (*_imp___pwctype) +#endif + +#ifndef _pwctype +#ifdef _MSVCRT_ + extern unsigned short *_pwctype; +#else + extern unsigned short **_imp___pwctype; +#define _pwctype (*_imp___pwctype) +#endif +#endif + +#endif +#endif + +#define _UPPER 0x1 +#define _LOWER 0x2 +#define _DIGIT 0x4 +#define _SPACE 0x8 + +#define _PUNCT 0x10 +#define _CONTROL 0x20 +#define _BLANK 0x40 +#define _HEX 0x80 + +#define _LEADBYTE 0x8000 +#define _ALPHA (0x0100|_UPPER|_LOWER) + +#ifndef _WCTYPE_DEFINED +#define _WCTYPE_DEFINED + + int __cdecl iswalpha(wint_t _C); + _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); + int __cdecl iswupper(wint_t _C); + _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); + int __cdecl iswlower(wint_t _C); + _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswdigit(wint_t _C); + _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswxdigit(wint_t _C); + _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswspace(wint_t _C); + _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); + int __cdecl iswpunct(wint_t _C); + _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); + int __cdecl iswalnum(wint_t _C); + _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); + int __cdecl iswprint(wint_t _C); + _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); + int __cdecl iswgraph(wint_t _C); + _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); + int __cdecl iswcntrl(wint_t _C); + _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); + int __cdecl iswascii(wint_t _C); + int __cdecl isleadbyte(int _C); + _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); + wint_t __cdecl towupper(wint_t _C); + _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); + wint_t __cdecl towlower(wint_t _C); + _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswctype(wint_t _C,wctype_t _Type); + _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsymf(wint_t _C); + _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsym(wint_t _C); + _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); + int __cdecl is_wctype(wint_t _C,wctype_t _Type); +#endif + +#ifndef _WDIRECT_DEFINED +#define _WDIRECT_DEFINED + + _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); +#endif + +#ifndef _WIO_DEFINED +#define _WIO_DEFINED + + _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); + _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); + _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); + _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); + _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); + _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); + intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); + _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); + _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); + int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); + _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); +#endif + _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); +#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) + _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); + _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); +#else + extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); + extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); +#endif +#endif + +#ifndef _WLOCALE_DEFINED +#define _WLOCALE_DEFINED + _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); +#endif + +#ifndef _WPROCESS_DEFINED +#define _WPROCESS_DEFINED + + _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif +#endif + +#ifndef _WCTYPE_INLINE_DEFINED +#undef _CRT_WCTYPE_NOINLINE +#if !defined(__cplusplus) || defined(_CRT_WCTYPE_NOINLINE) +#define iswalpha(_c) (iswctype(_c,_ALPHA)) +#define iswupper(_c) (iswctype(_c,_UPPER)) +#define iswlower(_c) (iswctype(_c,_LOWER)) +#define iswdigit(_c) (iswctype(_c,_DIGIT)) +#define iswxdigit(_c) (iswctype(_c,_HEX)) +#define iswspace(_c) (iswctype(_c,_SPACE)) +#define iswpunct(_c) (iswctype(_c,_PUNCT)) +#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) +#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) +#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) +#define iswcntrl(_c) (iswctype(_c,_CONTROL)) +#define iswascii(_c) ((unsigned)(_c) < 0x80) + +#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) +#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) +#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) +#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) +#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) +#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) +#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) +#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) +#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) +#ifndef _CTYPE_DISABLE_MACROS +#define isleadbyte(_c) (__PCTYPE_FUNC[(unsigned char)(_c)] & _LEADBYTE) +#endif +#endif +#define _WCTYPE_INLINE_DEFINED +#endif + +#if !defined(_POSIX_) || defined(__GNUC__) +#ifndef _INO_T_DEFINED +#define _INO_T_DEFINED + typedef unsigned short _ino_t; +#ifndef NO_OLDNAMES + typedef unsigned short ino_t; +#endif +#endif + +#ifndef _DEV_T_DEFINED +#define _DEV_T_DEFINED + typedef unsigned int _dev_t; +#ifndef NO_OLDNAMES + typedef unsigned int dev_t; +#endif +#endif + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif + +#ifndef _STAT_DEFINED +#define _STAT_DEFINED + +#ifdef _USE_32BIT_TIME_T +#ifdef WIN64 +#define _fstat _fstat32 +#define _stat _stat32 +#define _wstat _wstat32 +#else +#define _fstat32 _fstat +#define _stat32 _stat +#define _wstat32 _wstat +#endif +#define _fstati64 _fstat32i64 +#define _stati64 _stat32i64 +#define _wstati64 _wstat32i64 +#else +#define _fstat _fstat64i32 +#define _fstati64 _fstat64 +#define _stat _stat64i32 +#define _stati64 _stat64 +#define _wstat _wstat64i32 +#define _wstati64 _wstat64 +#endif + + struct _stat32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + +#ifndef NO_OLDNAMES + struct stat { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + }; +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + + struct _stat32i64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + + struct _stat64i32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; + + struct _stat64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; +#endif + +#define __stat64 _stat64 + +#endif + +#ifndef _WSTAT_DEFINED +#define _WSTAT_DEFINED + + _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); + int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); + _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); +#endif +#endif +#endif + +#ifndef _WCONIO_DEFINED +#define _WCONIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + + _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _getwch(void); + _CRTIMP wint_t __cdecl _getwche(void); + _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); + _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); + _CRTIMP int __cdecl _cputws(const wchar_t *_String); + _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); + + _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + wint_t __cdecl _putwch_nolock(wchar_t _WCh); + wint_t __cdecl _getwch_nolock(void); + wint_t __cdecl _getwche_nolock(void); + wint_t __cdecl _ungetwch_nolock(wint_t _WCh); +#endif + +#ifndef _WSTDIO_DEFINED +#define _WSTDIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifdef _POSIX_ + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); +#else + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); +#endif + + wint_t __cdecl fgetwc(FILE *_File); + _CRTIMP wint_t __cdecl _fgetwchar(void); + wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); + wint_t __cdecl getwc(FILE *_File); + wint_t __cdecl getwchar(void); + wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); + wint_t __cdecl putwchar(wchar_t _Ch); + wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); + wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); + int __cdecl fputws(const wchar_t *_Str,FILE *_File); + _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); + _CRTIMP int __cdecl _putws(const wchar_t *_Str); + int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); + int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); + int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); + _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); + _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); +#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ + int __cdecl snwprintf (wchar_t *s, size_t n, const wchar_t * format, ...); + __CRT_INLINE int __cdecl vsnwprintf (wchar_t *s, size_t n, const wchar_t *format, va_list arg) { return _vsnwprintf(s,n,format,arg); } + int __cdecl vwscanf (const wchar_t *, va_list); + int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); + int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); +#endif + _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); + _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); + _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); + _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); +#ifndef RC_INVOKED +#include +#endif + +#ifdef _CRT_NON_CONFORMING_SWPRINTFS +#ifndef __cplusplus +#define swprintf _swprintf +#define vswprintf _vswprintf +#define _swprintf_l __swprintf_l +#define _vswprintf_l __vswprintf_l +#endif +#endif + + _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); + _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); + _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); + _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + int __cdecl wscanf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); + +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); +#if !defined(NO_OLDNAMES) && !defined(wpopen) +#define wpopen _wpopen +#endif + _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); + _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); + _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); + +#undef _CRT_GETPUTWCHAR_NOINLINE + +#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) +#define getwchar() fgetwc(stdin) +#define putwchar(_c) fputwc((_c),stdout) +#else + __CRT_INLINE wint_t __cdecl getwchar() {return (fgetwc(stdin)); } + __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) {return (fputwc(_C,stdout)); } +#endif + +#define getwc(_stm) fgetwc(_stm) +#define putwc(_c,_stm) fputwc(_c,_stm) +#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) +#define _getwc_nolock(_c) _fgetwc_nolock(_c) +#endif + +#ifndef _WSTDLIB_DEFINED +#define _WSTDLIB_DEFINED + + _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); + double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); + _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); + float __cdecl wcstof( const wchar_t *nptr, wchar_t **endptr); +#if !defined __NO_ISOCEXT /* in libmingwex.a */ + float __cdecl wcstof (const wchar_t * __restrict__, wchar_t ** __restrict__); + long double __cdecl wcstold (const wchar_t * __restrict__, wchar_t ** __restrict__); +#endif /* __NO_ISOCEXT */ + long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif + _CRTIMP double __cdecl _wtof(const wchar_t *_Str); + _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); + _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP long __cdecl _wtol(const wchar_t *_Str); + _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); + _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); +#endif +#endif + +#ifndef _POSIX_ +#ifndef _WSTDLIBP_DEFINED +#define _WSTDLIBP_DEFINED + _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); + _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); + _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); + _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); +#endif +#endif + +#ifndef _WSTRING_DEFINED +#define _WSTRING_DEFINED + _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); + wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); + _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); + int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); + wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); + size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); + size_t __cdecl wcslen(const wchar_t *_Str); + size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); + wchar_t *__cdecl wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *__cdecl wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); + size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); + wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); + _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); + _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); + _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); + _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); + _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); + _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); + _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); + size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); + _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); + int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + +#ifndef NO_OLDNAMES + wchar_t *__cdecl wcsdup(const wchar_t *_Str); +#define wcswcs wcsstr + int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + wchar_t *__cdecl wcsrev(wchar_t *_Str); + wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); + wchar_t *__cdecl wcslwr(wchar_t *_Str); + wchar_t *__cdecl wcsupr(wchar_t *_Str); + int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); +#endif +#endif + +#ifndef _TM_DEFINED +#define _TM_DEFINED + struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + }; +#endif + +#ifndef _WTIME_DEFINED +#define _WTIME_DEFINED + + _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); + _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); + size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); + _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); + _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) +#define _INC_WTIME_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } +#else +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } +#endif +#endif +#endif + + typedef int mbstate_t; + typedef wchar_t _Wint_t; + + wint_t __cdecl btowc(int); + size_t __cdecl mbrlen(const char *_Ch,size_t _SizeInBytes,mbstate_t *_State); + size_t __cdecl mbrtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SizeInBytes,mbstate_t *_State); + size_t __cdecl mbsrtowcs(wchar_t *_Dest,const char **_PSrc,size_t _Count,mbstate_t *_State); + size_t __cdecl wcrtomb(char *_Dest,wchar_t _Source,mbstate_t *_State); + size_t __cdecl wcsrtombs(char *_Dest,const wchar_t **_PSource,size_t _Count,mbstate_t *_State); + int __cdecl wctob(wint_t _WCh); + +#ifndef __NO_ISOCEXT /* these need static lib libmingwex.a */ + wchar_t *__cdecl wmemset(wchar_t *s, wchar_t c, size_t n); + _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *s, wchar_t c, size_t n); + int wmemcmp(const wchar_t *s1, const wchar_t *s2,size_t n); + wchar_t *__cdecl wmemcpy(wchar_t *s1,const wchar_t *s2,size_t n); + wchar_t *__cdecl wmemmove(wchar_t *s1, const wchar_t *s2, size_t n); + long long __cdecl wcstoll(const wchar_t *nptr,wchar_t **endptr, int base); + unsigned long long __cdecl wcstoull(const wchar_t *nptr,wchar_t **endptr, int base); +#endif /* __NO_ISOCEXT */ + + void *__cdecl memmove(void *_Dst,const void *_Src,size_t _MaxCount); + void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _MaxCount); + __CRT_INLINE int __cdecl fwide(FILE *_F,int _M) { (void)_F; return (_M); } + __CRT_INLINE int __cdecl mbsinit(const mbstate_t *_P) { return (!_P || *_P==0); } + __CRT_INLINE _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *_S,wchar_t _C,size_t _N) { for (;0<_N;++_S,--_N) if (*_S==_C) return (_CONST_RETURN wchar_t *)(_S); return (0); } + __CRT_INLINE int __cdecl wmemcmp(const wchar_t *_S1,const wchar_t *_S2,size_t _N) { for (; 0 < _N; ++_S1,++_S2,--_N) if (*_S1!=*_S2) return (*_S1 < *_S2 ? -1 : +1); return (0); } + __CRT_INLINE wchar_t *__cdecl wmemcpy(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memcpy(_S1,_S2,_N*sizeof(wchar_t)); } + __CRT_INLINE wchar_t *__cdecl wmemmove(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memmove(_S1,_S2,_N*sizeof(wchar_t)); } + __CRT_INLINE wchar_t *__cdecl wmemset(wchar_t *_S,wchar_t _C,size_t _N) { + wchar_t *_Su = _S; + for (;0<_N;++_Su,--_N) { + *_Su = _C; + } + return (_S); + } +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include +#endif diff --git a/tcc/include/wctype.h b/tcc/include/wctype.h index a44cb384..5739f10c 100644 --- a/tcc/include/wctype.h +++ b/tcc/include/wctype.h @@ -1,172 +1,172 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_WCTYPE -#define _INC_WCTYPE - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif - -#ifndef _WCTYPE_T_DEFINED - typedef unsigned short wint_t; - typedef unsigned short wctype_t; -#define _WCTYPE_T_DEFINED -#endif - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifndef _CRT_CTYPEDATA_DEFINED -#define _CRT_CTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef __PCTYPE_FUNC -#define __PCTYPE_FUNC __pctype_func() -#ifdef _MSVCRT_ -#define __pctype_func() (_pctype) -#else -#define __pctype_func() (*_imp___pctype) -#endif -#endif - -#ifndef _pctype -#ifdef _MSVCRT_ - extern unsigned short *_pctype; -#else - extern unsigned short **_imp___pctype; -#define _pctype (*_imp___pctype) -#endif -#endif - -#endif -#endif - -#ifndef _CRT_WCTYPEDATA_DEFINED -#define _CRT_WCTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS -#ifndef _wctype -#ifdef _MSVCRT_ - extern unsigned short *_wctype; -#else - extern unsigned short **_imp___wctype; -#define _wctype (*_imp___wctype) -#endif -#endif - -#ifndef _pwctype -#ifdef _MSVCRT_ - extern unsigned short *_pwctype; -#else - extern unsigned short **_imp___pwctype; -#define _pwctype (*_imp___pwctype) -#define __pwctype_func() (*_imp___pwctype) -#endif -#endif -#endif -#endif - -#define _UPPER 0x1 -#define _LOWER 0x2 -#define _DIGIT 0x4 -#define _SPACE 0x8 - -#define _PUNCT 0x10 -#define _CONTROL 0x20 -#define _BLANK 0x40 -#define _HEX 0x80 - -#define _LEADBYTE 0x8000 -#define _ALPHA (0x0100|_UPPER|_LOWER) - -#ifndef _WCTYPE_DEFINED -#define _WCTYPE_DEFINED - - int __cdecl iswalpha(wint_t); - int __cdecl iswupper(wint_t); - int __cdecl iswlower(wint_t); - int __cdecl iswdigit(wint_t); - int __cdecl iswxdigit(wint_t); - int __cdecl iswspace(wint_t); - int __cdecl iswpunct(wint_t); - int __cdecl iswalnum(wint_t); - int __cdecl iswprint(wint_t); - int __cdecl iswgraph(wint_t); - int __cdecl iswcntrl(wint_t); - int __cdecl iswascii(wint_t); - int __cdecl isleadbyte(int); - wint_t __cdecl towupper(wint_t); - wint_t __cdecl towlower(wint_t); - int __cdecl iswctype(wint_t,wctype_t); - _CRTIMP int __cdecl __iswcsymf(wint_t); - _CRTIMP int __cdecl __iswcsym(wint_t); - int __cdecl is_wctype(wint_t,wctype_t); -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) -int __cdecl isblank(int _C); -#endif -#endif - -#ifndef _WCTYPE_INLINE_DEFINED -#define _WCTYPE_INLINE_DEFINED -#ifndef __cplusplus -#define iswalpha(_c) (iswctype(_c,_ALPHA)) -#define iswupper(_c) (iswctype(_c,_UPPER)) -#define iswlower(_c) (iswctype(_c,_LOWER)) -#define iswdigit(_c) (iswctype(_c,_DIGIT)) -#define iswxdigit(_c) (iswctype(_c,_HEX)) -#define iswspace(_c) (iswctype(_c,_SPACE)) -#define iswpunct(_c) (iswctype(_c,_PUNCT)) -#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) -#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) -#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) -#define iswcntrl(_c) (iswctype(_c,_CONTROL)) -#define iswascii(_c) ((unsigned)(_c) < 0x80) -#define isleadbyte(c) (__pctype_func()[(unsigned char)(c)] & _LEADBYTE) -#else - __CRT_INLINE int __cdecl iswalpha(wint_t _C) {return (iswctype(_C,_ALPHA)); } - __CRT_INLINE int __cdecl iswupper(wint_t _C) {return (iswctype(_C,_UPPER)); } - __CRT_INLINE int __cdecl iswlower(wint_t _C) {return (iswctype(_C,_LOWER)); } - __CRT_INLINE int __cdecl iswdigit(wint_t _C) {return (iswctype(_C,_DIGIT)); } - __CRT_INLINE int __cdecl iswxdigit(wint_t _C) {return (iswctype(_C,_HEX)); } - __CRT_INLINE int __cdecl iswspace(wint_t _C) {return (iswctype(_C,_SPACE)); } - __CRT_INLINE int __cdecl iswpunct(wint_t _C) {return (iswctype(_C,_PUNCT)); } - __CRT_INLINE int __cdecl iswalnum(wint_t _C) {return (iswctype(_C,_ALPHA|_DIGIT)); } - __CRT_INLINE int __cdecl iswprint(wint_t _C) {return (iswctype(_C,_BLANK|_PUNCT|_ALPHA|_DIGIT)); } - __CRT_INLINE int __cdecl iswgraph(wint_t _C) {return (iswctype(_C,_PUNCT|_ALPHA|_DIGIT)); } - __CRT_INLINE int __cdecl iswcntrl(wint_t _C) {return (iswctype(_C,_CONTROL)); } - __CRT_INLINE int __cdecl iswascii(wint_t _C) {return ((unsigned)(_C) < 0x80); } - __CRT_INLINE int __cdecl isleadbyte(int _C) {return (__pctype_func()[(unsigned char)(_C)] & _LEADBYTE); } -#endif -#endif - - typedef wchar_t wctrans_t; - wint_t __cdecl towctrans(wint_t,wctrans_t); - wctrans_t __cdecl wctrans(const char *); - wctype_t __cdecl wctype(const char *); - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_WCTYPE +#define _INC_WCTYPE + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +#ifndef _WCTYPE_T_DEFINED + typedef unsigned short wint_t; + typedef unsigned short wctype_t; +#define _WCTYPE_T_DEFINED +#endif + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifndef _CRT_CTYPEDATA_DEFINED +#define _CRT_CTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef __PCTYPE_FUNC +#define __PCTYPE_FUNC __pctype_func() +#ifdef _MSVCRT_ +#define __pctype_func() (_pctype) +#else +#define __pctype_func() (*_imp___pctype) +#endif +#endif + +#ifndef _pctype +#ifdef _MSVCRT_ + extern unsigned short *_pctype; +#else + extern unsigned short **_imp___pctype; +#define _pctype (*_imp___pctype) +#endif +#endif + +#endif +#endif + +#ifndef _CRT_WCTYPEDATA_DEFINED +#define _CRT_WCTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS +#ifndef _wctype +#ifdef _MSVCRT_ + extern unsigned short *_wctype; +#else + extern unsigned short **_imp___wctype; +#define _wctype (*_imp___wctype) +#endif +#endif + +#ifndef _pwctype +#ifdef _MSVCRT_ + extern unsigned short *_pwctype; +#else + extern unsigned short **_imp___pwctype; +#define _pwctype (*_imp___pwctype) +#define __pwctype_func() (*_imp___pwctype) +#endif +#endif +#endif +#endif + +#define _UPPER 0x1 +#define _LOWER 0x2 +#define _DIGIT 0x4 +#define _SPACE 0x8 + +#define _PUNCT 0x10 +#define _CONTROL 0x20 +#define _BLANK 0x40 +#define _HEX 0x80 + +#define _LEADBYTE 0x8000 +#define _ALPHA (0x0100|_UPPER|_LOWER) + +#ifndef _WCTYPE_DEFINED +#define _WCTYPE_DEFINED + + int __cdecl iswalpha(wint_t); + int __cdecl iswupper(wint_t); + int __cdecl iswlower(wint_t); + int __cdecl iswdigit(wint_t); + int __cdecl iswxdigit(wint_t); + int __cdecl iswspace(wint_t); + int __cdecl iswpunct(wint_t); + int __cdecl iswalnum(wint_t); + int __cdecl iswprint(wint_t); + int __cdecl iswgraph(wint_t); + int __cdecl iswcntrl(wint_t); + int __cdecl iswascii(wint_t); + int __cdecl isleadbyte(int); + wint_t __cdecl towupper(wint_t); + wint_t __cdecl towlower(wint_t); + int __cdecl iswctype(wint_t,wctype_t); + _CRTIMP int __cdecl __iswcsymf(wint_t); + _CRTIMP int __cdecl __iswcsym(wint_t); + int __cdecl is_wctype(wint_t,wctype_t); +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) +int __cdecl isblank(int _C); +#endif +#endif + +#ifndef _WCTYPE_INLINE_DEFINED +#define _WCTYPE_INLINE_DEFINED +#ifndef __cplusplus +#define iswalpha(_c) (iswctype(_c,_ALPHA)) +#define iswupper(_c) (iswctype(_c,_UPPER)) +#define iswlower(_c) (iswctype(_c,_LOWER)) +#define iswdigit(_c) (iswctype(_c,_DIGIT)) +#define iswxdigit(_c) (iswctype(_c,_HEX)) +#define iswspace(_c) (iswctype(_c,_SPACE)) +#define iswpunct(_c) (iswctype(_c,_PUNCT)) +#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) +#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) +#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) +#define iswcntrl(_c) (iswctype(_c,_CONTROL)) +#define iswascii(_c) ((unsigned)(_c) < 0x80) +#define isleadbyte(c) (__pctype_func()[(unsigned char)(c)] & _LEADBYTE) +#else + __CRT_INLINE int __cdecl iswalpha(wint_t _C) {return (iswctype(_C,_ALPHA)); } + __CRT_INLINE int __cdecl iswupper(wint_t _C) {return (iswctype(_C,_UPPER)); } + __CRT_INLINE int __cdecl iswlower(wint_t _C) {return (iswctype(_C,_LOWER)); } + __CRT_INLINE int __cdecl iswdigit(wint_t _C) {return (iswctype(_C,_DIGIT)); } + __CRT_INLINE int __cdecl iswxdigit(wint_t _C) {return (iswctype(_C,_HEX)); } + __CRT_INLINE int __cdecl iswspace(wint_t _C) {return (iswctype(_C,_SPACE)); } + __CRT_INLINE int __cdecl iswpunct(wint_t _C) {return (iswctype(_C,_PUNCT)); } + __CRT_INLINE int __cdecl iswalnum(wint_t _C) {return (iswctype(_C,_ALPHA|_DIGIT)); } + __CRT_INLINE int __cdecl iswprint(wint_t _C) {return (iswctype(_C,_BLANK|_PUNCT|_ALPHA|_DIGIT)); } + __CRT_INLINE int __cdecl iswgraph(wint_t _C) {return (iswctype(_C,_PUNCT|_ALPHA|_DIGIT)); } + __CRT_INLINE int __cdecl iswcntrl(wint_t _C) {return (iswctype(_C,_CONTROL)); } + __CRT_INLINE int __cdecl iswascii(wint_t _C) {return ((unsigned)(_C) < 0x80); } + __CRT_INLINE int __cdecl isleadbyte(int _C) {return (__pctype_func()[(unsigned char)(_C)] & _LEADBYTE); } +#endif +#endif + + typedef wchar_t wctrans_t; + wint_t __cdecl towctrans(wint_t,wctrans_t); + wctrans_t __cdecl wctrans(const char *); + wctype_t __cdecl wctype(const char *); + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/winapi/basetsd.h b/tcc/include/winapi/basetsd.h index 47d78c4c..adc29da9 100644 --- a/tcc/include/winapi/basetsd.h +++ b/tcc/include/winapi/basetsd.h @@ -1,149 +1,149 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _BASETSD_H_ -#define _BASETSD_H_ - -#if (defined(__x86_64) || defined(__ia64__)) && !defined(RC_INVOKED) -typedef unsigned __int64 POINTER_64_INT; -#else -typedef unsigned long POINTER_64_INT; -#endif - -#define POINTER_32 -#define POINTER_64 -#define FIRMWARE_PTR - -#ifdef __cplusplus -extern "C" { -#endif - - typedef signed char INT8,*PINT8; - typedef signed short INT16,*PINT16; - typedef signed int INT32,*PINT32; - typedef signed __int64 INT64,*PINT64; - typedef unsigned char UINT8,*PUINT8; - typedef unsigned short UINT16,*PUINT16; - typedef unsigned int UINT32,*PUINT32; - typedef unsigned __int64 UINT64,*PUINT64; - typedef signed int LONG32,*PLONG32; - typedef unsigned int ULONG32,*PULONG32; - typedef unsigned int DWORD32,*PDWORD32; - -#ifndef _W64 -#define _W64 -#endif - -#ifdef _WIN64 - typedef __int64 INT_PTR,*PINT_PTR; - typedef unsigned __int64 UINT_PTR,*PUINT_PTR; - typedef __int64 LONG_PTR,*PLONG_PTR; - typedef unsigned __int64 ULONG_PTR,*PULONG_PTR; -#define __int3264 __int64 -#else - typedef int INT_PTR,*PINT_PTR; - typedef unsigned int UINT_PTR,*PUINT_PTR; - typedef long LONG_PTR,*PLONG_PTR; - typedef unsigned long ULONG_PTR,*PULONG_PTR; -#define __int3264 __int32 -#endif - -#ifdef _WIN64 -#define ADDRESS_TAG_BIT 0x40000000000ULL - typedef __int64 SHANDLE_PTR; - typedef unsigned __int64 HANDLE_PTR; - typedef unsigned int UHALF_PTR,*PUHALF_PTR; - typedef int HALF_PTR,*PHALF_PTR; - - static __inline unsigned long HandleToULong(const void *h) { return((unsigned long) (ULONG_PTR) h); } - static __inline long HandleToLong(const void *h) { return((long) (LONG_PTR) h); } - static __inline void *ULongToHandle(const unsigned long h) { return((void *) (UINT_PTR) h); } - static __inline void *LongToHandle(const long h) { return((void *) (INT_PTR) h); } - static __inline unsigned long PtrToUlong(const void *p) { return((unsigned long) (ULONG_PTR) p); } - static __inline unsigned int PtrToUint(const void *p) { return((unsigned int) (UINT_PTR) p); } - static __inline unsigned short PtrToUshort(const void *p) { return((unsigned short) (unsigned long) (ULONG_PTR) p); } - static __inline long PtrToLong(const void *p) { return((long) (LONG_PTR) p); } - static __inline int PtrToInt(const void *p) { return((int) (INT_PTR) p); } - static __inline short PtrToShort(const void *p) { return((short) (long) (LONG_PTR) p); } - static __inline void *IntToPtr(const int i) { return((void *)(INT_PTR)i); } - static __inline void *UIntToPtr(const unsigned int ui) { return((void *)(UINT_PTR)ui); } - static __inline void *LongToPtr(const long l) { return((void *)(LONG_PTR)l); } - static __inline void *ULongToPtr(const unsigned long ul) { return((void *)(ULONG_PTR)ul); } - -#define PtrToPtr64(p) ((void *) p) -#define Ptr64ToPtr(p) ((void *) p) -#define HandleToHandle64(h) (PtrToPtr64(h)) -#define Handle64ToHandle(h) (Ptr64ToPtr(h)) - - static __inline void *Ptr32ToPtr(const void *p) { return (void *)p; } - static __inline void *Handle32ToHandle(const void *h) { return((void *) h); } - static __inline void *PtrToPtr32(const void *p) { return((void *) (ULONG_PTR) p); } - -#define HandleToHandle32(h) (PtrToPtr32(h)) -#else - -#define ADDRESS_TAG_BIT 0x80000000UL - - typedef unsigned short UHALF_PTR,*PUHALF_PTR; - typedef short HALF_PTR,*PHALF_PTR; - typedef long SHANDLE_PTR; - typedef unsigned long HANDLE_PTR; - -#define HandleToULong(h) ((ULONG)(ULONG_PTR)(h)) -#define HandleToLong(h) ((LONG)(LONG_PTR) (h)) -#define ULongToHandle(ul) ((HANDLE)(ULONG_PTR) (ul)) -#define LongToHandle(h) ((HANDLE)(LONG_PTR) (h)) -#define PtrToUlong(p) ((ULONG)(ULONG_PTR) (p)) -#define PtrToLong(p) ((LONG)(LONG_PTR) (p)) -#define PtrToUint(p) ((UINT)(UINT_PTR) (p)) -#define PtrToInt(p) ((INT)(INT_PTR) (p)) -#define PtrToUshort(p) ((unsigned short)(ULONG_PTR)(p)) -#define PtrToShort(p) ((short)(LONG_PTR)(p)) -#define IntToPtr(i) ((VOID *)(INT_PTR)((int)i)) -#define UIntToPtr(ui) ((VOID *)(UINT_PTR)((unsigned int)ui)) -#define LongToPtr(l) ((VOID *)(LONG_PTR)((long)l)) -#define ULongToPtr(ul) ((VOID *)(ULONG_PTR)((unsigned long)ul)) - - static __inline void *PtrToPtr64(const void *p) { return((void *) (ULONG_PTR)p); } - static __inline void *Ptr64ToPtr(const void *p) { return((void *) (ULONG_PTR) p); } - static __inline void *HandleToHandle64(const void *h) { return((void *) h); } - static __inline void *Handle64ToHandle(const void *h) { return((void *) (ULONG_PTR) h); } - -#define Ptr32ToPtr(p) ((void *) p) -#define Handle32ToHandle(h) (Ptr32ToPtr(h)) -#define PtrToPtr32(p) ((void *) p) -#define HandleToHandle32(h) (PtrToPtr32(h)) -#endif - -#define HandleToUlong(h) HandleToULong(h) -#define UlongToHandle(ul) ULongToHandle(ul) -#define UlongToPtr(ul) ULongToPtr(ul) -#define UintToPtr(ui) UIntToPtr(ui) - -#define MAXUINT_PTR (~((UINT_PTR)0)) -#define MAXINT_PTR ((INT_PTR)(MAXUINT_PTR >> 1)) -#define MININT_PTR (~MAXINT_PTR) - -#define MAXULONG_PTR (~((ULONG_PTR)0)) -#define MAXLONG_PTR ((LONG_PTR)(MAXULONG_PTR >> 1)) -#define MINLONG_PTR (~MAXLONG_PTR) - -#define MAXUHALF_PTR ((UHALF_PTR)~0) -#define MAXHALF_PTR ((HALF_PTR)(MAXUHALF_PTR >> 1)) -#define MINHALF_PTR (~MAXHALF_PTR) - - typedef ULONG_PTR SIZE_T,*PSIZE_T; - typedef LONG_PTR SSIZE_T,*PSSIZE_T; - typedef ULONG_PTR DWORD_PTR,*PDWORD_PTR; - typedef __int64 LONG64,*PLONG64; - typedef unsigned __int64 ULONG64,*PULONG64; - typedef unsigned __int64 DWORD64,*PDWORD64; - typedef ULONG_PTR KAFFINITY; - typedef KAFFINITY *PKAFFINITY; - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _BASETSD_H_ +#define _BASETSD_H_ + +#if (defined(__x86_64) || defined(__ia64__)) && !defined(RC_INVOKED) +typedef unsigned __int64 POINTER_64_INT; +#else +typedef unsigned long POINTER_64_INT; +#endif + +#define POINTER_32 +#define POINTER_64 +#define FIRMWARE_PTR + +#ifdef __cplusplus +extern "C" { +#endif + + typedef signed char INT8,*PINT8; + typedef signed short INT16,*PINT16; + typedef signed int INT32,*PINT32; + typedef signed __int64 INT64,*PINT64; + typedef unsigned char UINT8,*PUINT8; + typedef unsigned short UINT16,*PUINT16; + typedef unsigned int UINT32,*PUINT32; + typedef unsigned __int64 UINT64,*PUINT64; + typedef signed int LONG32,*PLONG32; + typedef unsigned int ULONG32,*PULONG32; + typedef unsigned int DWORD32,*PDWORD32; + +#ifndef _W64 +#define _W64 +#endif + +#ifdef _WIN64 + typedef __int64 INT_PTR,*PINT_PTR; + typedef unsigned __int64 UINT_PTR,*PUINT_PTR; + typedef __int64 LONG_PTR,*PLONG_PTR; + typedef unsigned __int64 ULONG_PTR,*PULONG_PTR; +#define __int3264 __int64 +#else + typedef int INT_PTR,*PINT_PTR; + typedef unsigned int UINT_PTR,*PUINT_PTR; + typedef long LONG_PTR,*PLONG_PTR; + typedef unsigned long ULONG_PTR,*PULONG_PTR; +#define __int3264 __int32 +#endif + +#ifdef _WIN64 +#define ADDRESS_TAG_BIT 0x40000000000ULL + typedef __int64 SHANDLE_PTR; + typedef unsigned __int64 HANDLE_PTR; + typedef unsigned int UHALF_PTR,*PUHALF_PTR; + typedef int HALF_PTR,*PHALF_PTR; + + static __inline unsigned long HandleToULong(const void *h) { return((unsigned long) (ULONG_PTR) h); } + static __inline long HandleToLong(const void *h) { return((long) (LONG_PTR) h); } + static __inline void *ULongToHandle(const unsigned long h) { return((void *) (UINT_PTR) h); } + static __inline void *LongToHandle(const long h) { return((void *) (INT_PTR) h); } + static __inline unsigned long PtrToUlong(const void *p) { return((unsigned long) (ULONG_PTR) p); } + static __inline unsigned int PtrToUint(const void *p) { return((unsigned int) (UINT_PTR) p); } + static __inline unsigned short PtrToUshort(const void *p) { return((unsigned short) (unsigned long) (ULONG_PTR) p); } + static __inline long PtrToLong(const void *p) { return((long) (LONG_PTR) p); } + static __inline int PtrToInt(const void *p) { return((int) (INT_PTR) p); } + static __inline short PtrToShort(const void *p) { return((short) (long) (LONG_PTR) p); } + static __inline void *IntToPtr(const int i) { return((void *)(INT_PTR)i); } + static __inline void *UIntToPtr(const unsigned int ui) { return((void *)(UINT_PTR)ui); } + static __inline void *LongToPtr(const long l) { return((void *)(LONG_PTR)l); } + static __inline void *ULongToPtr(const unsigned long ul) { return((void *)(ULONG_PTR)ul); } + +#define PtrToPtr64(p) ((void *) p) +#define Ptr64ToPtr(p) ((void *) p) +#define HandleToHandle64(h) (PtrToPtr64(h)) +#define Handle64ToHandle(h) (Ptr64ToPtr(h)) + + static __inline void *Ptr32ToPtr(const void *p) { return (void *)p; } + static __inline void *Handle32ToHandle(const void *h) { return((void *) h); } + static __inline void *PtrToPtr32(const void *p) { return((void *) (ULONG_PTR) p); } + +#define HandleToHandle32(h) (PtrToPtr32(h)) +#else + +#define ADDRESS_TAG_BIT 0x80000000UL + + typedef unsigned short UHALF_PTR,*PUHALF_PTR; + typedef short HALF_PTR,*PHALF_PTR; + typedef long SHANDLE_PTR; + typedef unsigned long HANDLE_PTR; + +#define HandleToULong(h) ((ULONG)(ULONG_PTR)(h)) +#define HandleToLong(h) ((LONG)(LONG_PTR) (h)) +#define ULongToHandle(ul) ((HANDLE)(ULONG_PTR) (ul)) +#define LongToHandle(h) ((HANDLE)(LONG_PTR) (h)) +#define PtrToUlong(p) ((ULONG)(ULONG_PTR) (p)) +#define PtrToLong(p) ((LONG)(LONG_PTR) (p)) +#define PtrToUint(p) ((UINT)(UINT_PTR) (p)) +#define PtrToInt(p) ((INT)(INT_PTR) (p)) +#define PtrToUshort(p) ((unsigned short)(ULONG_PTR)(p)) +#define PtrToShort(p) ((short)(LONG_PTR)(p)) +#define IntToPtr(i) ((VOID *)(INT_PTR)((int)i)) +#define UIntToPtr(ui) ((VOID *)(UINT_PTR)((unsigned int)ui)) +#define LongToPtr(l) ((VOID *)(LONG_PTR)((long)l)) +#define ULongToPtr(ul) ((VOID *)(ULONG_PTR)((unsigned long)ul)) + + static __inline void *PtrToPtr64(const void *p) { return((void *) (ULONG_PTR)p); } + static __inline void *Ptr64ToPtr(const void *p) { return((void *) (ULONG_PTR) p); } + static __inline void *HandleToHandle64(const void *h) { return((void *) h); } + static __inline void *Handle64ToHandle(const void *h) { return((void *) (ULONG_PTR) h); } + +#define Ptr32ToPtr(p) ((void *) p) +#define Handle32ToHandle(h) (Ptr32ToPtr(h)) +#define PtrToPtr32(p) ((void *) p) +#define HandleToHandle32(h) (PtrToPtr32(h)) +#endif + +#define HandleToUlong(h) HandleToULong(h) +#define UlongToHandle(ul) ULongToHandle(ul) +#define UlongToPtr(ul) ULongToPtr(ul) +#define UintToPtr(ui) UIntToPtr(ui) + +#define MAXUINT_PTR (~((UINT_PTR)0)) +#define MAXINT_PTR ((INT_PTR)(MAXUINT_PTR >> 1)) +#define MININT_PTR (~MAXINT_PTR) + +#define MAXULONG_PTR (~((ULONG_PTR)0)) +#define MAXLONG_PTR ((LONG_PTR)(MAXULONG_PTR >> 1)) +#define MINLONG_PTR (~MAXLONG_PTR) + +#define MAXUHALF_PTR ((UHALF_PTR)~0) +#define MAXHALF_PTR ((HALF_PTR)(MAXUHALF_PTR >> 1)) +#define MINHALF_PTR (~MAXHALF_PTR) + + typedef ULONG_PTR SIZE_T,*PSIZE_T; + typedef LONG_PTR SSIZE_T,*PSSIZE_T; + typedef ULONG_PTR DWORD_PTR,*PDWORD_PTR; + typedef __int64 LONG64,*PLONG64; + typedef unsigned __int64 ULONG64,*PULONG64; + typedef unsigned __int64 DWORD64,*PDWORD64; + typedef ULONG_PTR KAFFINITY; + typedef KAFFINITY *PKAFFINITY; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/basetyps.h b/tcc/include/winapi/basetyps.h index 376665e7..698ec7ee 100644 --- a/tcc/include/winapi/basetyps.h +++ b/tcc/include/winapi/basetyps.h @@ -1,85 +1,85 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !defined(_BASETYPS_H_) -#define _BASETYPS_H_ - -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C extern -#endif - -#define STDMETHODCALLTYPE WINAPI -#define STDMETHODVCALLTYPE __cdecl - -#define STDAPICALLTYPE WINAPI -#define STDAPIVCALLTYPE __cdecl - -#define STDAPI EXTERN_C HRESULT WINAPI -#define STDAPI_(type) EXTERN_C type WINAPI - -#define STDMETHODIMP HRESULT WINAPI -#define STDMETHODIMP_(type) type WINAPI - -#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE -#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE - -#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE -#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE - -#if defined(__cplusplus) && !defined(CINTERFACE) - -#define __STRUCT__ struct -#define STDMETHOD(method) virtual HRESULT WINAPI method -#define STDMETHOD_(type,method) virtual type WINAPI method -#define STDMETHODV(method) virtual HRESULT STDMETHODVCALLTYPE method -#define STDMETHODV_(type,method) virtual type STDMETHODVCALLTYPE method -#define PURE = 0 -#define THIS_ -#define THIS void -#define DECLARE_INTERFACE(iface) __STRUCT__ iface -#define DECLARE_INTERFACE_(iface,baseiface) __STRUCT__ iface : public baseiface -#else - -#ifndef __OBJC__ -#define interface struct -#endif - -#define STDMETHOD(method) HRESULT (WINAPI *method) -#define STDMETHOD_(type,method) type (WINAPI *method) -#define STDMETHODV(method) HRESULT (STDMETHODVCALLTYPE *method) -#define STDMETHODV_(type,method) type (STDMETHODVCALLTYPE *method) - -#define PURE -#define THIS_ INTERFACE *This, -#define THIS INTERFACE *This -#ifdef CONST_VTABLE -#define DECLARE_INTERFACE(iface) typedef struct iface { \ - const struct iface##Vtbl *lpVtbl; } iface; \ - typedef const struct iface##Vtbl iface##Vtbl; \ - const struct iface##Vtbl -#else -#define DECLARE_INTERFACE(iface) typedef struct iface { \ - struct iface##Vtbl *lpVtbl; \ - } iface; \ - typedef struct iface##Vtbl iface##Vtbl; \ - struct iface##Vtbl -#endif -#define DECLARE_INTERFACE_(iface,baseiface) DECLARE_INTERFACE(iface) -#endif - -#include - -#ifndef _ERROR_STATUS_T_DEFINED -#define _ERROR_STATUS_T_DEFINED -typedef unsigned long error_status_t; -#endif - -#ifndef _WCHAR_T_DEFINED -typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !defined(_BASETYPS_H_) +#define _BASETYPS_H_ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C extern +#endif + +#define STDMETHODCALLTYPE WINAPI +#define STDMETHODVCALLTYPE __cdecl + +#define STDAPICALLTYPE WINAPI +#define STDAPIVCALLTYPE __cdecl + +#define STDAPI EXTERN_C HRESULT WINAPI +#define STDAPI_(type) EXTERN_C type WINAPI + +#define STDMETHODIMP HRESULT WINAPI +#define STDMETHODIMP_(type) type WINAPI + +#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE +#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE + +#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE +#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE + +#if defined(__cplusplus) && !defined(CINTERFACE) + +#define __STRUCT__ struct +#define STDMETHOD(method) virtual HRESULT WINAPI method +#define STDMETHOD_(type,method) virtual type WINAPI method +#define STDMETHODV(method) virtual HRESULT STDMETHODVCALLTYPE method +#define STDMETHODV_(type,method) virtual type STDMETHODVCALLTYPE method +#define PURE = 0 +#define THIS_ +#define THIS void +#define DECLARE_INTERFACE(iface) __STRUCT__ iface +#define DECLARE_INTERFACE_(iface,baseiface) __STRUCT__ iface : public baseiface +#else + +#ifndef __OBJC__ +#define interface struct +#endif + +#define STDMETHOD(method) HRESULT (WINAPI *method) +#define STDMETHOD_(type,method) type (WINAPI *method) +#define STDMETHODV(method) HRESULT (STDMETHODVCALLTYPE *method) +#define STDMETHODV_(type,method) type (STDMETHODVCALLTYPE *method) + +#define PURE +#define THIS_ INTERFACE *This, +#define THIS INTERFACE *This +#ifdef CONST_VTABLE +#define DECLARE_INTERFACE(iface) typedef struct iface { \ + const struct iface##Vtbl *lpVtbl; } iface; \ + typedef const struct iface##Vtbl iface##Vtbl; \ + const struct iface##Vtbl +#else +#define DECLARE_INTERFACE(iface) typedef struct iface { \ + struct iface##Vtbl *lpVtbl; \ + } iface; \ + typedef struct iface##Vtbl iface##Vtbl; \ + struct iface##Vtbl +#endif +#define DECLARE_INTERFACE_(iface,baseiface) DECLARE_INTERFACE(iface) +#endif + +#include + +#ifndef _ERROR_STATUS_T_DEFINED +#define _ERROR_STATUS_T_DEFINED +typedef unsigned long error_status_t; +#endif + +#ifndef _WCHAR_T_DEFINED +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif +#endif diff --git a/tcc/include/winapi/guiddef.h b/tcc/include/winapi/guiddef.h index 4e7909a9..aab49b3b 100644 --- a/tcc/include/winapi/guiddef.h +++ b/tcc/include/winapi/guiddef.h @@ -1,156 +1,156 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef GUID_DEFINED -#define GUID_DEFINED -typedef struct _GUID { - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[8 ]; -} GUID; -#endif - -#ifndef UUID_DEFINED -#define UUID_DEFINED -typedef GUID UUID; -#endif - -#ifndef FAR -#define FAR -#endif - -#ifndef DECLSPEC_SELECTANY -#define DECLSPEC_SELECTANY __declspec(selectany) -#endif - -#ifndef EXTERN_C -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C extern -#endif -#endif - -#ifdef DEFINE_GUID -#undef DEFINE_GUID -#endif - -#ifdef INITGUID -#ifdef __cplusplus -#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } -#else -#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } -#endif -#else -#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID name -#endif - -#define DEFINE_OLEGUID(name,l,w1,w2) DEFINE_GUID(name,l,w1,w2,0xC0,0,0,0,0,0,0,0x46) - -#ifndef _GUIDDEF_H_ -#define _GUIDDEF_H_ - -#ifndef __LPGUID_DEFINED__ -#define __LPGUID_DEFINED__ -typedef GUID *LPGUID; -#endif - -#ifndef __LPCGUID_DEFINED__ -#define __LPCGUID_DEFINED__ -typedef const GUID *LPCGUID; -#endif - -#ifndef __IID_DEFINED__ -#define __IID_DEFINED__ - -typedef GUID IID; -typedef IID *LPIID; -#define IID_NULL GUID_NULL -#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) -typedef GUID CLSID; -typedef CLSID *LPCLSID; -#define CLSID_NULL GUID_NULL -#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) -typedef GUID FMTID; -typedef FMTID *LPFMTID; -#define FMTID_NULL GUID_NULL -#define IsEqualFMTID(rfmtid1,rfmtid2) IsEqualGUID(rfmtid1,rfmtid2) - -#ifdef __midl_proxy -#define __MIDL_CONST -#else -#define __MIDL_CONST const -#endif - -#ifndef _REFGUID_DEFINED -#define _REFGUID_DEFINED -#ifdef __cplusplus -#define REFGUID const GUID & -#else -#define REFGUID const GUID *__MIDL_CONST -#endif -#endif - -#ifndef _REFIID_DEFINED -#define _REFIID_DEFINED -#ifdef __cplusplus -#define REFIID const IID & -#else -#define REFIID const IID *__MIDL_CONST -#endif -#endif - -#ifndef _REFCLSID_DEFINED -#define _REFCLSID_DEFINED -#ifdef __cplusplus -#define REFCLSID const IID & -#else -#define REFCLSID const IID *__MIDL_CONST -#endif -#endif - -#ifndef _REFFMTID_DEFINED -#define _REFFMTID_DEFINED -#ifdef __cplusplus -#define REFFMTID const IID & -#else -#define REFFMTID const IID *__MIDL_CONST -#endif -#endif -#endif - -#ifndef _SYS_GUID_OPERATORS_ -#define _SYS_GUID_OPERATORS_ -#include - -#ifdef __cplusplus -__inline int InlineIsEqualGUID(REFGUID rguid1,REFGUID rguid2) { - return (((unsigned long *) &rguid1)[0]==((unsigned long *) &rguid2)[0] && ((unsigned long *) &rguid1)[1]==((unsigned long *) &rguid2)[1] && - ((unsigned long *) &rguid1)[2]==((unsigned long *) &rguid2)[2] && ((unsigned long *) &rguid1)[3]==((unsigned long *) &rguid2)[3]); -} -__inline int IsEqualGUID(REFGUID rguid1,REFGUID rguid2) { return !memcmp(&rguid1,&rguid2,sizeof(GUID)); } -#else -#define InlineIsEqualGUID(rguid1,rguid2) (((unsigned long *) rguid1)[0]==((unsigned long *) rguid2)[0] && ((unsigned long *) rguid1)[1]==((unsigned long *) rguid2)[1] && ((unsigned long *) rguid1)[2]==((unsigned long *) rguid2)[2] && ((unsigned long *) rguid1)[3]==((unsigned long *) rguid2)[3]) -#define IsEqualGUID(rguid1,rguid2) (!memcmp(rguid1,rguid2,sizeof(GUID))) -#endif - -#ifdef __INLINE_ISEQUAL_GUID -#undef IsEqualGUID -#define IsEqualGUID(rguid1,rguid2) InlineIsEqualGUID(rguid1,rguid2) -#endif - -#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) -#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) - -#if !defined _SYS_GUID_OPERATOR_EQ_ && !defined _NO_SYS_GUID_OPERATOR_EQ_ -#define _SYS_GUID_OPERATOR_EQ_ -#ifdef __cplusplus -__inline int operator==(REFGUID guidOne,REFGUID guidOther) { return IsEqualGUID(guidOne,guidOther); } -__inline int operator!=(REFGUID guidOne,REFGUID guidOther) { return !(guidOne==guidOther); } -#endif -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID { + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8 ]; +} GUID; +#endif + +#ifndef UUID_DEFINED +#define UUID_DEFINED +typedef GUID UUID; +#endif + +#ifndef FAR +#define FAR +#endif + +#ifndef DECLSPEC_SELECTANY +#define DECLSPEC_SELECTANY __declspec(selectany) +#endif + +#ifndef EXTERN_C +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C extern +#endif +#endif + +#ifdef DEFINE_GUID +#undef DEFINE_GUID +#endif + +#ifdef INITGUID +#ifdef __cplusplus +#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } +#else +#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } +#endif +#else +#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID name +#endif + +#define DEFINE_OLEGUID(name,l,w1,w2) DEFINE_GUID(name,l,w1,w2,0xC0,0,0,0,0,0,0,0x46) + +#ifndef _GUIDDEF_H_ +#define _GUIDDEF_H_ + +#ifndef __LPGUID_DEFINED__ +#define __LPGUID_DEFINED__ +typedef GUID *LPGUID; +#endif + +#ifndef __LPCGUID_DEFINED__ +#define __LPCGUID_DEFINED__ +typedef const GUID *LPCGUID; +#endif + +#ifndef __IID_DEFINED__ +#define __IID_DEFINED__ + +typedef GUID IID; +typedef IID *LPIID; +#define IID_NULL GUID_NULL +#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) +typedef GUID CLSID; +typedef CLSID *LPCLSID; +#define CLSID_NULL GUID_NULL +#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) +typedef GUID FMTID; +typedef FMTID *LPFMTID; +#define FMTID_NULL GUID_NULL +#define IsEqualFMTID(rfmtid1,rfmtid2) IsEqualGUID(rfmtid1,rfmtid2) + +#ifdef __midl_proxy +#define __MIDL_CONST +#else +#define __MIDL_CONST const +#endif + +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#ifdef __cplusplus +#define REFGUID const GUID & +#else +#define REFGUID const GUID *__MIDL_CONST +#endif +#endif + +#ifndef _REFIID_DEFINED +#define _REFIID_DEFINED +#ifdef __cplusplus +#define REFIID const IID & +#else +#define REFIID const IID *__MIDL_CONST +#endif +#endif + +#ifndef _REFCLSID_DEFINED +#define _REFCLSID_DEFINED +#ifdef __cplusplus +#define REFCLSID const IID & +#else +#define REFCLSID const IID *__MIDL_CONST +#endif +#endif + +#ifndef _REFFMTID_DEFINED +#define _REFFMTID_DEFINED +#ifdef __cplusplus +#define REFFMTID const IID & +#else +#define REFFMTID const IID *__MIDL_CONST +#endif +#endif +#endif + +#ifndef _SYS_GUID_OPERATORS_ +#define _SYS_GUID_OPERATORS_ +#include + +#ifdef __cplusplus +__inline int InlineIsEqualGUID(REFGUID rguid1,REFGUID rguid2) { + return (((unsigned long *) &rguid1)[0]==((unsigned long *) &rguid2)[0] && ((unsigned long *) &rguid1)[1]==((unsigned long *) &rguid2)[1] && + ((unsigned long *) &rguid1)[2]==((unsigned long *) &rguid2)[2] && ((unsigned long *) &rguid1)[3]==((unsigned long *) &rguid2)[3]); +} +__inline int IsEqualGUID(REFGUID rguid1,REFGUID rguid2) { return !memcmp(&rguid1,&rguid2,sizeof(GUID)); } +#else +#define InlineIsEqualGUID(rguid1,rguid2) (((unsigned long *) rguid1)[0]==((unsigned long *) rguid2)[0] && ((unsigned long *) rguid1)[1]==((unsigned long *) rguid2)[1] && ((unsigned long *) rguid1)[2]==((unsigned long *) rguid2)[2] && ((unsigned long *) rguid1)[3]==((unsigned long *) rguid2)[3]) +#define IsEqualGUID(rguid1,rguid2) (!memcmp(rguid1,rguid2,sizeof(GUID))) +#endif + +#ifdef __INLINE_ISEQUAL_GUID +#undef IsEqualGUID +#define IsEqualGUID(rguid1,rguid2) InlineIsEqualGUID(rguid1,rguid2) +#endif + +#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) +#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) + +#if !defined _SYS_GUID_OPERATOR_EQ_ && !defined _NO_SYS_GUID_OPERATOR_EQ_ +#define _SYS_GUID_OPERATOR_EQ_ +#ifdef __cplusplus +__inline int operator==(REFGUID guidOne,REFGUID guidOther) { return IsEqualGUID(guidOne,guidOther); } +__inline int operator!=(REFGUID guidOne,REFGUID guidOther) { return !(guidOne==guidOther); } +#endif +#endif +#endif +#endif diff --git a/tcc/include/winapi/poppack.h b/tcc/include/winapi/poppack.h index b08cba22..5a9094d3 100644 --- a/tcc/include/winapi/poppack.h +++ b/tcc/include/winapi/poppack.h @@ -1,8 +1,8 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(pop) +#endif diff --git a/tcc/include/winapi/pshpack1.h b/tcc/include/winapi/pshpack1.h index d18d9e85..18cbd8e6 100644 --- a/tcc/include/winapi/pshpack1.h +++ b/tcc/include/winapi/pshpack1.h @@ -1,8 +1,8 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,1) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,1) +#endif diff --git a/tcc/include/winapi/pshpack2.h b/tcc/include/winapi/pshpack2.h index 7de16fd3..6afc106e 100644 --- a/tcc/include/winapi/pshpack2.h +++ b/tcc/include/winapi/pshpack2.h @@ -1,8 +1,8 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,2) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,2) +#endif diff --git a/tcc/include/winapi/pshpack4.h b/tcc/include/winapi/pshpack4.h index 1c8e61d7..1e10441f 100644 --- a/tcc/include/winapi/pshpack4.h +++ b/tcc/include/winapi/pshpack4.h @@ -1,8 +1,8 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,4) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,4) +#endif diff --git a/tcc/include/winapi/pshpack8.h b/tcc/include/winapi/pshpack8.h index 70a3c7f7..0f4e2de1 100644 --- a/tcc/include/winapi/pshpack8.h +++ b/tcc/include/winapi/pshpack8.h @@ -1,8 +1,8 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,8) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,8) +#endif diff --git a/tcc/include/winapi/qos.h b/tcc/include/winapi/qos.h index 7fa6ad19..23f89fae 100644 --- a/tcc/include/winapi/qos.h +++ b/tcc/include/winapi/qos.h @@ -1,72 +1,72 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef __QOS_H_ -#define __QOS_H_ - -typedef ULONG SERVICETYPE; - -#define SERVICETYPE_NOTRAFFIC 0x00000000 -#define SERVICETYPE_BESTEFFORT 0x00000001 -#define SERVICETYPE_CONTROLLEDLOAD 0x00000002 -#define SERVICETYPE_GUARANTEED 0x00000003 - -#define SERVICETYPE_NETWORK_UNAVAILABLE 0x00000004 -#define SERVICETYPE_GENERAL_INFORMATION 0x00000005 -#define SERVICETYPE_NOCHANGE 0x00000006 -#define SERVICETYPE_NONCONFORMING 0x00000009 -#define SERVICETYPE_NETWORK_CONTROL 0x0000000A -#define SERVICETYPE_QUALITATIVE 0x0000000D - -#define SERVICE_BESTEFFORT 0x80010000 -#define SERVICE_CONTROLLEDLOAD 0x80020000 -#define SERVICE_GUARANTEED 0x80040000 -#define SERVICE_QUALITATIVE 0x80200000 - -#define SERVICE_NO_TRAFFIC_CONTROL 0x81000000 - -#define SERVICE_NO_QOS_SIGNALING 0x40000000 - -typedef struct _flowspec { - ULONG TokenRate; - ULONG TokenBucketSize; - ULONG PeakBandwidth; - ULONG Latency; - ULONG DelayVariation; - SERVICETYPE ServiceType; - ULONG MaxSduSize; - ULONG MinimumPolicedSize; -} FLOWSPEC,*PFLOWSPEC,*LPFLOWSPEC; - -#define QOS_NOT_SPECIFIED 0xFFFFFFFF -#define POSITIVE_INFINITY_RATE 0xFFFFFFFE - -typedef struct { - ULONG ObjectType; - ULONG ObjectLength; -} QOS_OBJECT_HDR,*LPQOS_OBJECT_HDR; - -#define QOS_GENERAL_ID_BASE 2000 -#define QOS_OBJECT_END_OF_LIST (0x00000001 + QOS_GENERAL_ID_BASE) -#define QOS_OBJECT_SD_MODE (0x00000002 + QOS_GENERAL_ID_BASE) -#define QOS_OBJECT_SHAPING_RATE (0x00000003 + QOS_GENERAL_ID_BASE) -#define QOS_OBJECT_DESTADDR (0x00000004 + QOS_GENERAL_ID_BASE) - -typedef struct _QOS_SD_MODE { - QOS_OBJECT_HDR ObjectHdr; - ULONG ShapeDiscardMode; -} QOS_SD_MODE,*LPQOS_SD_MODE; - -#define TC_NONCONF_BORROW 0 -#define TC_NONCONF_SHAPE 1 -#define TC_NONCONF_DISCARD 2 -#define TC_NONCONF_BORROW_PLUS 3 - -typedef struct _QOS_SHAPING_RATE { - QOS_OBJECT_HDR ObjectHdr; - ULONG ShapingRate; -} QOS_SHAPING_RATE,*LPQOS_SHAPING_RATE; - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef __QOS_H_ +#define __QOS_H_ + +typedef ULONG SERVICETYPE; + +#define SERVICETYPE_NOTRAFFIC 0x00000000 +#define SERVICETYPE_BESTEFFORT 0x00000001 +#define SERVICETYPE_CONTROLLEDLOAD 0x00000002 +#define SERVICETYPE_GUARANTEED 0x00000003 + +#define SERVICETYPE_NETWORK_UNAVAILABLE 0x00000004 +#define SERVICETYPE_GENERAL_INFORMATION 0x00000005 +#define SERVICETYPE_NOCHANGE 0x00000006 +#define SERVICETYPE_NONCONFORMING 0x00000009 +#define SERVICETYPE_NETWORK_CONTROL 0x0000000A +#define SERVICETYPE_QUALITATIVE 0x0000000D + +#define SERVICE_BESTEFFORT 0x80010000 +#define SERVICE_CONTROLLEDLOAD 0x80020000 +#define SERVICE_GUARANTEED 0x80040000 +#define SERVICE_QUALITATIVE 0x80200000 + +#define SERVICE_NO_TRAFFIC_CONTROL 0x81000000 + +#define SERVICE_NO_QOS_SIGNALING 0x40000000 + +typedef struct _flowspec { + ULONG TokenRate; + ULONG TokenBucketSize; + ULONG PeakBandwidth; + ULONG Latency; + ULONG DelayVariation; + SERVICETYPE ServiceType; + ULONG MaxSduSize; + ULONG MinimumPolicedSize; +} FLOWSPEC,*PFLOWSPEC,*LPFLOWSPEC; + +#define QOS_NOT_SPECIFIED 0xFFFFFFFF +#define POSITIVE_INFINITY_RATE 0xFFFFFFFE + +typedef struct { + ULONG ObjectType; + ULONG ObjectLength; +} QOS_OBJECT_HDR,*LPQOS_OBJECT_HDR; + +#define QOS_GENERAL_ID_BASE 2000 +#define QOS_OBJECT_END_OF_LIST (0x00000001 + QOS_GENERAL_ID_BASE) +#define QOS_OBJECT_SD_MODE (0x00000002 + QOS_GENERAL_ID_BASE) +#define QOS_OBJECT_SHAPING_RATE (0x00000003 + QOS_GENERAL_ID_BASE) +#define QOS_OBJECT_DESTADDR (0x00000004 + QOS_GENERAL_ID_BASE) + +typedef struct _QOS_SD_MODE { + QOS_OBJECT_HDR ObjectHdr; + ULONG ShapeDiscardMode; +} QOS_SD_MODE,*LPQOS_SD_MODE; + +#define TC_NONCONF_BORROW 0 +#define TC_NONCONF_SHAPE 1 +#define TC_NONCONF_DISCARD 2 +#define TC_NONCONF_BORROW_PLUS 3 + +typedef struct _QOS_SHAPING_RATE { + QOS_OBJECT_HDR ObjectHdr; + ULONG ShapingRate; +} QOS_SHAPING_RATE,*LPQOS_SHAPING_RATE; + +#endif diff --git a/tcc/include/winapi/winbase.h b/tcc/include/winapi/winbase.h index 4a38006e..8752e1d1 100644 --- a/tcc/include/winapi/winbase.h +++ b/tcc/include/winapi/winbase.h @@ -1,2951 +1,2951 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINBASE_ -#define _WINBASE_ - -#define WINADVAPI DECLSPEC_IMPORT -#define WINBASEAPI DECLSPEC_IMPORT -#define ZAWPROXYAPI DECLSPEC_IMPORT - -#ifdef __cplusplus -extern "C" { -#endif - -#define DefineHandleTable(w) ((w),TRUE) -#define LimitEmsPages(dw) -#define SetSwapAreaSize(w) (w) -#define LockSegment(w) GlobalFix((HANDLE)(w)) -#define UnlockSegment(w) GlobalUnfix((HANDLE)(w)) -#define GetCurrentTime() GetTickCount() - -#define Yield() - -#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) -#define INVALID_FILE_SIZE ((DWORD)0xffffffff) -#define INVALID_SET_FILE_POINTER ((DWORD)-1) -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) - -#define FILE_BEGIN 0 -#define FILE_CURRENT 1 -#define FILE_END 2 - -#define TIME_ZONE_ID_INVALID ((DWORD)0xffffffff) - -#define WAIT_FAILED ((DWORD)0xffffffff) -#define WAIT_OBJECT_0 ((STATUS_WAIT_0) + 0) -#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0) + 0) -#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0) + 0) -#define WAIT_IO_COMPLETION STATUS_USER_APC -#define STILL_ACTIVE STATUS_PENDING -#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION -#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT -#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT -#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP -#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED -#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND -#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO -#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT -#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION -#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW -#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK -#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW -#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO -#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW -#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION -#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR -#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION -#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION -#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW -#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION -#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION -#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE -#define EXCEPTION_POSSIBLE_DEADLOCK STATUS_POSSIBLE_DEADLOCK -#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT -#define MoveMemory RtlMoveMemory -#define CopyMemory RtlCopyMemory -#define FillMemory RtlFillMemory -#define ZeroMemory RtlZeroMemory -#define SecureZeroMemory RtlSecureZeroMemory - -#define FILE_FLAG_WRITE_THROUGH 0x80000000 -#define FILE_FLAG_OVERLAPPED 0x40000000 -#define FILE_FLAG_NO_BUFFERING 0x20000000 -#define FILE_FLAG_RANDOM_ACCESS 0x10000000 -#define FILE_FLAG_SEQUENTIAL_SCAN 0x8000000 -#define FILE_FLAG_DELETE_ON_CLOSE 0x4000000 -#define FILE_FLAG_BACKUP_SEMANTICS 0x2000000 -#define FILE_FLAG_POSIX_SEMANTICS 0x1000000 -#define FILE_FLAG_OPEN_REPARSE_POINT 0x200000 -#define FILE_FLAG_OPEN_NO_RECALL 0x100000 -#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x80000 - -#define CREATE_NEW 1 -#define CREATE_ALWAYS 2 -#define OPEN_EXISTING 3 -#define OPEN_ALWAYS 4 -#define TRUNCATE_EXISTING 5 - -#define PROGRESS_CONTINUE 0 -#define PROGRESS_CANCEL 1 -#define PROGRESS_STOP 2 -#define PROGRESS_QUIET 3 - -#define CALLBACK_CHUNK_FINISHED 0x0 -#define CALLBACK_STREAM_SWITCH 0x1 - -#define COPY_FILE_FAIL_IF_EXISTS 0x1 -#define COPY_FILE_RESTARTABLE 0x2 -#define COPY_FILE_OPEN_SOURCE_FOR_WRITE 0x4 -#define COPY_FILE_ALLOW_DECRYPTED_DESTINATION 0x8 - -#define REPLACEFILE_WRITE_THROUGH 0x1 -#define REPLACEFILE_IGNORE_MERGE_ERRORS 0x2 - -#define PIPE_ACCESS_INBOUND 0x1 -#define PIPE_ACCESS_OUTBOUND 0x2 -#define PIPE_ACCESS_DUPLEX 0x3 - -#define PIPE_CLIENT_END 0x0 -#define PIPE_SERVER_END 0x1 - -#define PIPE_WAIT 0x0 -#define PIPE_NOWAIT 0x1 -#define PIPE_READMODE_BYTE 0x0 -#define PIPE_READMODE_MESSAGE 0x2 -#define PIPE_TYPE_BYTE 0x0 -#define PIPE_TYPE_MESSAGE 0x4 - -#define PIPE_UNLIMITED_INSTANCES 255 - -#define SECURITY_ANONYMOUS (SecurityAnonymous << 16) -#define SECURITY_IDENTIFICATION (SecurityIdentification << 16) -#define SECURITY_IMPERSONATION (SecurityImpersonation << 16) -#define SECURITY_DELEGATION (SecurityDelegation << 16) - -#define SECURITY_CONTEXT_TRACKING 0x40000 -#define SECURITY_EFFECTIVE_ONLY 0x80000 - -#define SECURITY_SQOS_PRESENT 0x100000 -#define SECURITY_VALID_SQOS_FLAGS 0x1f0000 - - typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - }; - PVOID Pointer; - }; - HANDLE hEvent; - } OVERLAPPED,*LPOVERLAPPED; - - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - LPVOID lpSecurityDescriptor; - WINBOOL bInheritHandle; - } SECURITY_ATTRIBUTES,*PSECURITY_ATTRIBUTES,*LPSECURITY_ATTRIBUTES; - - typedef struct _PROCESS_INFORMATION { - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; - } PROCESS_INFORMATION,*PPROCESS_INFORMATION,*LPPROCESS_INFORMATION; - -#ifndef _FILETIME_ -#define _FILETIME_ - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME,*PFILETIME,*LPFILETIME; -#endif - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME,*PSYSTEMTIME,*LPSYSTEMTIME; - - typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); - typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - typedef VOID (WINAPI *PFIBER_START_ROUTINE)(LPVOID lpFiberParameter); - typedef PFIBER_START_ROUTINE LPFIBER_START_ROUTINE; - - typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; - typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION; - typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION; - typedef RTL_CRITICAL_SECTION_DEBUG CRITICAL_SECTION_DEBUG; - typedef PRTL_CRITICAL_SECTION_DEBUG PCRITICAL_SECTION_DEBUG; - typedef PRTL_CRITICAL_SECTION_DEBUG LPCRITICAL_SECTION_DEBUG; - - WINBASEAPI PVOID WINAPI EncodePointer(PVOID Ptr); - WINBASEAPI PVOID WINAPI DecodePointer(PVOID Ptr); - WINBASEAPI PVOID WINAPI EncodeSystemPointer(PVOID Ptr); - WINBASEAPI PVOID WINAPI DecodeSystemPointer(PVOID Ptr); - -#ifdef I_X86_ - typedef PLDT_ENTRY LPLDT_ENTRY; -#else - typedef LPVOID LPLDT_ENTRY; -#endif - -#define MUTEX_MODIFY_STATE MUTANT_QUERY_STATE -#define MUTEX_ALL_ACCESS MUTANT_ALL_ACCESS - -#define SP_SERIALCOMM ((DWORD)0x1) - -#define PST_UNSPECIFIED ((DWORD)0x0) -#define PST_RS232 ((DWORD)0x1) -#define PST_PARALLELPORT ((DWORD)0x2) -#define PST_RS422 ((DWORD)0x3) -#define PST_RS423 ((DWORD)0x4) -#define PST_RS449 ((DWORD)0x5) -#define PST_MODEM ((DWORD)0x6) -#define PST_FAX ((DWORD)0x21) -#define PST_SCANNER ((DWORD)0x22) -#define PST_NETWORK_BRIDGE ((DWORD)0x100) -#define PST_LAT ((DWORD)0x101) -#define PST_TCPIP_TELNET ((DWORD)0x102) -#define PST_X25 ((DWORD)0x103) - -#define PCF_DTRDSR ((DWORD)0x1) -#define PCF_RTSCTS ((DWORD)0x2) -#define PCF_RLSD ((DWORD)0x4) -#define PCF_PARITY_CHECK ((DWORD)0x8) -#define PCF_XONXOFF ((DWORD)0x10) -#define PCF_SETXCHAR ((DWORD)0x20) -#define PCF_TOTALTIMEOUTS ((DWORD)0x40) -#define PCF_INTTIMEOUTS ((DWORD)0x80) -#define PCF_SPECIALCHARS ((DWORD)0x100) -#define PCF_16BITMODE ((DWORD)0x200) - -#define SP_PARITY ((DWORD)0x1) -#define SP_BAUD ((DWORD)0x2) -#define SP_DATABITS ((DWORD)0x4) -#define SP_STOPBITS ((DWORD)0x8) -#define SP_HANDSHAKING ((DWORD)0x10) -#define SP_PARITY_CHECK ((DWORD)0x20) -#define SP_RLSD ((DWORD)0x40) - -#define BAUD_075 ((DWORD)0x1) -#define BAUD_110 ((DWORD)0x2) -#define BAUD_134_5 ((DWORD)0x4) -#define BAUD_150 ((DWORD)0x8) -#define BAUD_300 ((DWORD)0x10) -#define BAUD_600 ((DWORD)0x20) -#define BAUD_1200 ((DWORD)0x40) -#define BAUD_1800 ((DWORD)0x80) -#define BAUD_2400 ((DWORD)0x100) -#define BAUD_4800 ((DWORD)0x200) -#define BAUD_7200 ((DWORD)0x400) -#define BAUD_9600 ((DWORD)0x800) -#define BAUD_14400 ((DWORD)0x1000) -#define BAUD_19200 ((DWORD)0x2000) -#define BAUD_38400 ((DWORD)0x4000) -#define BAUD_56K ((DWORD)0x8000) -#define BAUD_128K ((DWORD)0x10000) -#define BAUD_115200 ((DWORD)0x20000) -#define BAUD_57600 ((DWORD)0x40000) -#define BAUD_USER ((DWORD)0x10000000) - -#define DATABITS_5 ((WORD)0x1) -#define DATABITS_6 ((WORD)0x2) -#define DATABITS_7 ((WORD)0x4) -#define DATABITS_8 ((WORD)0x8) -#define DATABITS_16 ((WORD)0x10) -#define DATABITS_16X ((WORD)0x20) - -#define STOPBITS_10 ((WORD)0x1) -#define STOPBITS_15 ((WORD)0x2) -#define STOPBITS_20 ((WORD)0x4) -#define PARITY_NONE ((WORD)0x100) -#define PARITY_ODD ((WORD)0x200) -#define PARITY_EVEN ((WORD)0x400) -#define PARITY_MARK ((WORD)0x800) -#define PARITY_SPACE ((WORD)0x1000) - - typedef struct _COMMPROP { - WORD wPacketLength; - WORD wPacketVersion; - DWORD dwServiceMask; - DWORD dwReserved1; - DWORD dwMaxTxQueue; - DWORD dwMaxRxQueue; - DWORD dwMaxBaud; - DWORD dwProvSubType; - DWORD dwProvCapabilities; - DWORD dwSettableParams; - DWORD dwSettableBaud; - WORD wSettableData; - WORD wSettableStopParity; - DWORD dwCurrentTxQueue; - DWORD dwCurrentRxQueue; - DWORD dwProvSpec1; - DWORD dwProvSpec2; - WCHAR wcProvChar[1]; - } COMMPROP,*LPCOMMPROP; - -#define COMMPROP_INITIALIZED ((DWORD)0xE73CF52E) - - typedef struct _COMSTAT { - DWORD fCtsHold : 1; - DWORD fDsrHold : 1; - DWORD fRlsdHold : 1; - DWORD fXoffHold : 1; - DWORD fXoffSent : 1; - DWORD fEof : 1; - DWORD fTxim : 1; - DWORD fReserved : 25; - DWORD cbInQue; - DWORD cbOutQue; - } COMSTAT,*LPCOMSTAT; - -#define DTR_CONTROL_DISABLE 0x0 -#define DTR_CONTROL_ENABLE 0x1 -#define DTR_CONTROL_HANDSHAKE 0x2 - -#define RTS_CONTROL_DISABLE 0x0 -#define RTS_CONTROL_ENABLE 0x1 -#define RTS_CONTROL_HANDSHAKE 0x2 -#define RTS_CONTROL_TOGGLE 0x3 - - typedef struct _DCB { - DWORD DCBlength; - DWORD BaudRate; - DWORD fBinary: 1; - DWORD fParity: 1; - DWORD fOutxCtsFlow:1; - DWORD fOutxDsrFlow:1; - DWORD fDtrControl:2; - DWORD fDsrSensitivity:1; - DWORD fTXContinueOnXoff: 1; - DWORD fOutX: 1; - DWORD fInX: 1; - DWORD fErrorChar: 1; - DWORD fNull: 1; - DWORD fRtsControl:2; - DWORD fAbortOnError:1; - DWORD fDummy2:17; - WORD wReserved; - WORD XonLim; - WORD XoffLim; - BYTE ByteSize; - BYTE Parity; - BYTE StopBits; - char XonChar; - char XoffChar; - char ErrorChar; - char EofChar; - char EvtChar; - WORD wReserved1; - } DCB,*LPDCB; - - typedef struct _COMMTIMEOUTS { - DWORD ReadIntervalTimeout; - DWORD ReadTotalTimeoutMultiplier; - DWORD ReadTotalTimeoutConstant; - DWORD WriteTotalTimeoutMultiplier; - DWORD WriteTotalTimeoutConstant; - } COMMTIMEOUTS,*LPCOMMTIMEOUTS; - - typedef struct _COMMCONFIG { - DWORD dwSize; - WORD wVersion; - WORD wReserved; - DCB dcb; - DWORD dwProviderSubType; - DWORD dwProviderOffset; - DWORD dwProviderSize; - WCHAR wcProviderData[1]; - } COMMCONFIG,*LPCOMMCONFIG; - - typedef struct _SYSTEM_INFO { - union { - DWORD dwOemId; - struct { - WORD wProcessorArchitecture; - WORD wReserved; - }; - }; - DWORD dwPageSize; - LPVOID lpMinimumApplicationAddress; - LPVOID lpMaximumApplicationAddress; - DWORD_PTR dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; - } SYSTEM_INFO,*LPSYSTEM_INFO; - -#define FreeModule(hLibModule) FreeLibrary((hLibModule)) -#define MakeProcInstance(lpProc,hInstance) (lpProc) -#define FreeProcInstance(lpProc) (lpProc) - -#define GMEM_FIXED 0x0 -#define GMEM_MOVEABLE 0x2 -#define GMEM_NOCOMPACT 0x10 -#define GMEM_NODISCARD 0x20 -#define GMEM_ZEROINIT 0x40 -#define GMEM_MODIFY 0x80 -#define GMEM_DISCARDABLE 0x100 -#define GMEM_NOT_BANKED 0x1000 -#define GMEM_SHARE 0x2000 -#define GMEM_DDESHARE 0x2000 -#define GMEM_NOTIFY 0x4000 -#define GMEM_LOWER GMEM_NOT_BANKED -#define GMEM_VALID_FLAGS 0x7F72 -#define GMEM_INVALID_HANDLE 0x8000 - -#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT) -#define GPTR (GMEM_FIXED | GMEM_ZEROINIT) - -#define GlobalLRUNewest(h) ((HANDLE)(h)) -#define GlobalLRUOldest(h) ((HANDLE)(h)) -#define GlobalDiscard(h) GlobalReAlloc((h),0,GMEM_MOVEABLE) - -#define GMEM_DISCARDED 0x4000 -#define GMEM_LOCKCOUNT 0xff - - typedef struct _MEMORYSTATUS { - DWORD dwLength; - DWORD dwMemoryLoad; - SIZE_T dwTotalPhys; - SIZE_T dwAvailPhys; - SIZE_T dwTotalPageFile; - SIZE_T dwAvailPageFile; - SIZE_T dwTotalVirtual; - SIZE_T dwAvailVirtual; - } MEMORYSTATUS,*LPMEMORYSTATUS; - -#define LMEM_FIXED 0x0 -#define LMEM_MOVEABLE 0x2 -#define LMEM_NOCOMPACT 0x10 -#define LMEM_NODISCARD 0x20 -#define LMEM_ZEROINIT 0x40 -#define LMEM_MODIFY 0x80 -#define LMEM_DISCARDABLE 0xf00 -#define LMEM_VALID_FLAGS 0xf72 -#define LMEM_INVALID_HANDLE 0x8000 - -#define LHND (LMEM_MOVEABLE | LMEM_ZEROINIT) -#define LPTR (LMEM_FIXED | LMEM_ZEROINIT) - -#define NONZEROLHND (LMEM_MOVEABLE) -#define NONZEROLPTR (LMEM_FIXED) - -#define LocalDiscard(h) LocalReAlloc((h),0,LMEM_MOVEABLE) - -#define LMEM_DISCARDED 0x4000 -#define LMEM_LOCKCOUNT 0xff - -#define DEBUG_PROCESS 0x1 -#define DEBUG_ONLY_THIS_PROCESS 0x2 -#define CREATE_SUSPENDED 0x4 -#define DETACHED_PROCESS 0x8 -#define CREATE_NEW_CONSOLE 0x10 -#define NORMAL_PRIORITY_CLASS 0x20 -#define IDLE_PRIORITY_CLASS 0x40 -#define HIGH_PRIORITY_CLASS 0x80 -#define REALTIME_PRIORITY_CLASS 0x100 -#define CREATE_NEW_PROCESS_GROUP 0x200 -#define CREATE_UNICODE_ENVIRONMENT 0x400 -#define CREATE_SEPARATE_WOW_VDM 0x800 -#define CREATE_SHARED_WOW_VDM 0x1000 -#define CREATE_FORCEDOS 0x2000 -#define BELOW_NORMAL_PRIORITY_CLASS 0x4000 -#define ABOVE_NORMAL_PRIORITY_CLASS 0x8000 -#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x10000 - -#define CREATE_BREAKAWAY_FROM_JOB 0x1000000 -#define CREATE_PRESERVE_CODE_AUTHZ_LEVEL 0x2000000 - -#define CREATE_DEFAULT_ERROR_MODE 0x4000000 -#define CREATE_NO_WINDOW 0x8000000 - -#define PROFILE_USER 0x10000000 -#define PROFILE_KERNEL 0x20000000 -#define PROFILE_SERVER 0x40000000 - -#define CREATE_IGNORE_SYSTEM_DEFAULT 0x80000000 - -#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN -#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1) -#define THREAD_PRIORITY_NORMAL 0 -#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX -#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1) -#define THREAD_PRIORITY_ERROR_RETURN (MAXLONG) - -#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT -#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE - -#define EXCEPTION_DEBUG_EVENT 1 -#define CREATE_THREAD_DEBUG_EVENT 2 -#define CREATE_PROCESS_DEBUG_EVENT 3 -#define EXIT_THREAD_DEBUG_EVENT 4 -#define EXIT_PROCESS_DEBUG_EVENT 5 -#define LOAD_DLL_DEBUG_EVENT 6 -#define UNLOAD_DLL_DEBUG_EVENT 7 -#define OUTPUT_DEBUG_STRING_EVENT 8 -#define RIP_EVENT 9 - - typedef struct _EXCEPTION_DEBUG_INFO { - EXCEPTION_RECORD ExceptionRecord; - DWORD dwFirstChance; - } EXCEPTION_DEBUG_INFO,*LPEXCEPTION_DEBUG_INFO; - - typedef struct _CREATE_THREAD_DEBUG_INFO { - HANDLE hThread; - LPVOID lpThreadLocalBase; - LPTHREAD_START_ROUTINE lpStartAddress; - } CREATE_THREAD_DEBUG_INFO,*LPCREATE_THREAD_DEBUG_INFO; - - typedef struct _CREATE_PROCESS_DEBUG_INFO { - HANDLE hFile; - HANDLE hProcess; - HANDLE hThread; - LPVOID lpBaseOfImage; - DWORD dwDebugInfoFileOffset; - DWORD nDebugInfoSize; - LPVOID lpThreadLocalBase; - LPTHREAD_START_ROUTINE lpStartAddress; - LPVOID lpImageName; - WORD fUnicode; - } CREATE_PROCESS_DEBUG_INFO,*LPCREATE_PROCESS_DEBUG_INFO; - - typedef struct _EXIT_THREAD_DEBUG_INFO { - DWORD dwExitCode; - } EXIT_THREAD_DEBUG_INFO,*LPEXIT_THREAD_DEBUG_INFO; - - typedef struct _EXIT_PROCESS_DEBUG_INFO { - DWORD dwExitCode; - } EXIT_PROCESS_DEBUG_INFO,*LPEXIT_PROCESS_DEBUG_INFO; - - typedef struct _LOAD_DLL_DEBUG_INFO { - HANDLE hFile; - LPVOID lpBaseOfDll; - DWORD dwDebugInfoFileOffset; - DWORD nDebugInfoSize; - LPVOID lpImageName; - WORD fUnicode; - } LOAD_DLL_DEBUG_INFO,*LPLOAD_DLL_DEBUG_INFO; - - typedef struct _UNLOAD_DLL_DEBUG_INFO { - LPVOID lpBaseOfDll; - } UNLOAD_DLL_DEBUG_INFO,*LPUNLOAD_DLL_DEBUG_INFO; - - typedef struct _OUTPUT_DEBUG_STRING_INFO { - LPSTR lpDebugStringData; - WORD fUnicode; - WORD nDebugStringLength; - } OUTPUT_DEBUG_STRING_INFO,*LPOUTPUT_DEBUG_STRING_INFO; - - typedef struct _RIP_INFO { - DWORD dwError; - DWORD dwType; - } RIP_INFO,*LPRIP_INFO; - - typedef struct _DEBUG_EVENT { - DWORD dwDebugEventCode; - DWORD dwProcessId; - DWORD dwThreadId; - union { - EXCEPTION_DEBUG_INFO Exception; - CREATE_THREAD_DEBUG_INFO CreateThread; - CREATE_PROCESS_DEBUG_INFO CreateProcessInfo; - EXIT_THREAD_DEBUG_INFO ExitThread; - EXIT_PROCESS_DEBUG_INFO ExitProcess; - LOAD_DLL_DEBUG_INFO LoadDll; - UNLOAD_DLL_DEBUG_INFO UnloadDll; - OUTPUT_DEBUG_STRING_INFO DebugString; - RIP_INFO RipInfo; - } u; - } DEBUG_EVENT,*LPDEBUG_EVENT; - - typedef PCONTEXT LPCONTEXT; - typedef PEXCEPTION_RECORD LPEXCEPTION_RECORD; - typedef PEXCEPTION_POINTERS LPEXCEPTION_POINTERS; - -#define DRIVE_UNKNOWN 0 -#define DRIVE_NO_ROOT_DIR 1 -#define DRIVE_REMOVABLE 2 -#define DRIVE_FIXED 3 -#define DRIVE_REMOTE 4 -#define DRIVE_CDROM 5 -#define DRIVE_RAMDISK 6 - -#define GetFreeSpace(w) (0x100000L) -#define FILE_TYPE_UNKNOWN 0x0 -#define FILE_TYPE_DISK 0x1 -#define FILE_TYPE_CHAR 0x2 -#define FILE_TYPE_PIPE 0x3 -#define FILE_TYPE_REMOTE 0x8000 - -#define STD_INPUT_HANDLE ((DWORD)-10) -#define STD_OUTPUT_HANDLE ((DWORD)-11) -#define STD_ERROR_HANDLE ((DWORD)-12) - -#define NOPARITY 0 -#define ODDPARITY 1 -#define EVENPARITY 2 -#define MARKPARITY 3 -#define SPACEPARITY 4 - -#define ONESTOPBIT 0 -#define ONE5STOPBITS 1 -#define TWOSTOPBITS 2 - -#define IGNORE 0 -#define INFINITE 0xffffffff - -#define CBR_110 110 -#define CBR_300 300 -#define CBR_600 600 -#define CBR_1200 1200 -#define CBR_2400 2400 -#define CBR_4800 4800 -#define CBR_9600 9600 -#define CBR_14400 14400 -#define CBR_19200 19200 -#define CBR_38400 38400 -#define CBR_56000 56000 -#define CBR_57600 57600 -#define CBR_115200 115200 -#define CBR_128000 128000 -#define CBR_256000 256000 - -#define CE_RXOVER 0x1 -#define CE_OVERRUN 0x2 -#define CE_RXPARITY 0x4 -#define CE_FRAME 0x8 -#define CE_BREAK 0x10 -#define CE_TXFULL 0x100 -#define CE_PTO 0x200 -#define CE_IOE 0x400 -#define CE_DNS 0x800 -#define CE_OOP 0x1000 -#define CE_MODE 0x8000 - -#define IE_BADID (-1) -#define IE_OPEN (-2) -#define IE_NOPEN (-3) -#define IE_MEMORY (-4) -#define IE_DEFAULT (-5) -#define IE_HARDWARE (-10) -#define IE_BYTESIZE (-11) -#define IE_BAUDRATE (-12) - -#define EV_RXCHAR 0x1 -#define EV_RXFLAG 0x2 -#define EV_TXEMPTY 0x4 -#define EV_CTS 0x8 -#define EV_DSR 0x10 -#define EV_RLSD 0x20 -#define EV_BREAK 0x40 -#define EV_ERR 0x80 -#define EV_RING 0x100 -#define EV_PERR 0x200 -#define EV_RX80FULL 0x400 -#define EV_EVENT1 0x800 -#define EV_EVENT2 0x1000 - -#define SETXOFF 1 -#define SETXON 2 -#define SETRTS 3 -#define CLRRTS 4 -#define SETDTR 5 -#define CLRDTR 6 -#define RESETDEV 7 -#define SETBREAK 8 -#define CLRBREAK 9 - -#define PURGE_TXABORT 0x1 -#define PURGE_RXABORT 0x2 -#define PURGE_TXCLEAR 0x4 -#define PURGE_RXCLEAR 0x8 - -#define LPTx 0x80 - -#define MS_CTS_ON ((DWORD)0x10) -#define MS_DSR_ON ((DWORD)0x20) -#define MS_RING_ON ((DWORD)0x40) -#define MS_RLSD_ON ((DWORD)0x80) - -#define S_QUEUEEMPTY 0 -#define S_THRESHOLD 1 -#define S_ALLTHRESHOLD 2 - -#define S_NORMAL 0 -#define S_LEGATO 1 -#define S_STACCATO 2 - -#define S_PERIOD512 0 -#define S_PERIOD1024 1 -#define S_PERIOD2048 2 -#define S_PERIODVOICE 3 -#define S_WHITE512 4 -#define S_WHITE1024 5 -#define S_WHITE2048 6 -#define S_WHITEVOICE 7 - -#define S_SERDVNA (-1) -#define S_SEROFM (-2) -#define S_SERMACT (-3) -#define S_SERQFUL (-4) -#define S_SERBDNT (-5) -#define S_SERDLN (-6) -#define S_SERDCC (-7) -#define S_SERDTP (-8) -#define S_SERDVL (-9) -#define S_SERDMD (-10) -#define S_SERDSH (-11) -#define S_SERDPT (-12) -#define S_SERDFQ (-13) -#define S_SERDDR (-14) -#define S_SERDSR (-15) -#define S_SERDST (-16) - -#define NMPWAIT_WAIT_FOREVER 0xffffffff -#define NMPWAIT_NOWAIT 0x1 -#define NMPWAIT_USE_DEFAULT_WAIT 0x0 - -#define FS_CASE_IS_PRESERVED FILE_CASE_PRESERVED_NAMES -#define FS_CASE_SENSITIVE FILE_CASE_SENSITIVE_SEARCH -#define FS_UNICODE_STORED_ON_DISK FILE_UNICODE_ON_DISK -#define FS_PERSISTENT_ACLS FILE_PERSISTENT_ACLS -#define FS_VOL_IS_COMPRESSED FILE_VOLUME_IS_COMPRESSED -#define FS_FILE_COMPRESSION FILE_FILE_COMPRESSION -#define FS_FILE_ENCRYPTION FILE_SUPPORTS_ENCRYPTION - -#define FILE_MAP_COPY SECTION_QUERY -#define FILE_MAP_WRITE SECTION_MAP_WRITE -#define FILE_MAP_READ SECTION_MAP_READ -#define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS -#define FILE_MAP_EXECUTE SECTION_MAP_EXECUTE_EXPLICIT - -#define OF_READ 0x0 -#define OF_WRITE 0x1 -#define OF_READWRITE 0x2 -#define OF_SHARE_COMPAT 0x0 -#define OF_SHARE_EXCLUSIVE 0x10 -#define OF_SHARE_DENY_WRITE 0x20 -#define OF_SHARE_DENY_READ 0x30 -#define OF_SHARE_DENY_NONE 0x40 -#define OF_PARSE 0x100 -#define OF_DELETE 0x200 -#define OF_VERIFY 0x400 -#define OF_CANCEL 0x800 -#define OF_CREATE 0x1000 -#define OF_PROMPT 0x2000 -#define OF_EXIST 0x4000 -#define OF_REOPEN 0x8000 - -#define OFS_MAXPATHNAME 128 - typedef struct _OFSTRUCT { - BYTE cBytes; - BYTE fFixedDisk; - WORD nErrCode; - WORD Reserved1; - WORD Reserved2; - CHAR szPathName[OFS_MAXPATHNAME]; - } OFSTRUCT,*LPOFSTRUCT,*POFSTRUCT; - -#ifndef NOWINBASEINTERLOCK - -#ifndef _NTOS_ - -#if defined(__ia64__) && !defined(RC_INVOKED) - -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedIncrementAcquire _InterlockedIncrement_acq -#define InterlockedIncrementRelease _InterlockedIncrement_rel -#define InterlockedDecrement _InterlockedDecrement -#define InterlockedDecrementAcquire _InterlockedDecrement_acq -#define InterlockedDecrementRelease _InterlockedDecrement_rel -#define InterlockedExchange _InterlockedExchange -#define InterlockedExchangeAdd _InterlockedExchangeAdd -#define InterlockedCompareExchange _InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire _InterlockedCompareExchange_acq -#define InterlockedCompareExchangeRelease _InterlockedCompareExchange_rel -#define InterlockedExchangePointer _InterlockedExchangePointer -#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer_rel -#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer_acq - -#define InterlockedIncrement64 _InterlockedIncrement64 -#define InterlockedDecrement64 _InterlockedDecrement64 -#define InterlockedExchange64 _InterlockedExchange64 -#define InterlockedExchangeAcquire64 _InterlockedExchange64_acq -#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 -#define InterlockedCompareExchange64 _InterlockedCompareExchange64 -#define InterlockedCompareExchangeAcquire64 _InterlockedCompareExchange64_acq -#define InterlockedCompareExchangeRelease64 _InterlockedCompareExchange64_rel - - LONGLONG __cdecl InterlockedIncrement64(LONGLONG volatile *Addend); - LONGLONG __cdecl InterlockedDecrement64(LONGLONG volatile *Addend); - LONG __cdecl InterlockedIncrementAcquire(LONG volatile *Addend); - LONG __cdecl InterlockedDecrementAcquire(LONG volatile *Addend); - LONG __cdecl InterlockedIncrementRelease(LONG volatile *Addend); - LONG __cdecl InterlockedDecrementRelease(LONG volatile *Addend); - LONGLONG __cdecl InterlockedExchange64 (LONGLONG volatile *Target,LONGLONG Value); - LONGLONG __cdecl InterlockedExchangeAcquire64 (LONGLONG volatile *Target,LONGLONG Value); - LONGLONG __cdecl InterlockedExchangeAdd64 (LONGLONG volatile *Addend,LONGLONG Value); - LONGLONG __cdecl InterlockedCompareExchange64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); - LONGLONG __cdecl InterlockedCompareExchangeAcquire64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); - LONGLONG __cdecl InterlockedCompareExchangeRelease64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); - LONG __cdecl InterlockedIncrement(LONG volatile *lpAddend); - LONG __cdecl InterlockedDecrement(LONG volatile *lpAddend); - LONG __cdecl InterlockedExchange(LONG volatile *Target,LONG Value); - LONG __cdecl InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - LONG __cdecl InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); - LONG __cdecl InterlockedCompareExchangeRelease(LONG volatile *Destination,LONG ExChange,LONG Comperand); - LONG __cdecl InterlockedCompareExchangeAcquire(LONG volatile *Destination,LONG ExChange,LONG Comperand); - PVOID __cdecl InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); - PVOID __cdecl InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand); - PVOID __cdecl InterlockedCompareExchangePointerAcquire(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); - PVOID __cdecl InterlockedCompareExchangePointerRelease(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); - -#ifndef InterlockedAnd -#define InterlockedAnd InterlockedAnd_Inline - __CRT_INLINE LONG InterlockedAnd_Inline(LONG volatile *Target,LONG Set) { - LONG i; - LONG j; - j = *Target; - do { - i = j; - j = InterlockedCompareExchange(Target,i & Set,i); - } while(i!=j); - return j; - } -#endif - -#ifndef InterlockedOr -#define InterlockedOr InterlockedOr_Inline - - __CRT_INLINE LONG InterlockedOr_Inline(LONG volatile *Target,LONG Set) { - LONG i; - LONG j; - j = *Target; - do { - i = j; - j = InterlockedCompareExchange(Target,i | Set,i); - } while(i!=j); - return j; - } -#endif - -#ifndef InterlockedXor -#define InterlockedXor InterlockedXor_Inline - - __CRT_INLINE LONG InterlockedXor_Inline(LONG volatile *Target,LONG Set) { - LONG i; - LONG j; - j = *Target; - do { - i = j; - j = InterlockedCompareExchange(Target,i ^ Set,i); - } while(i!=j); - return j; - } -#endif - -#ifndef !defined (InterlockedAnd64) -#define InterlockedAnd64 InterlockedAnd64_Inline - - __CRT_INLINE LONGLONG InterlockedAnd64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); - return Old; - } -#endif - -#ifndef InterlockedOr64 -#define InterlockedOr64 InterlockedOr64_Inline - - __CRT_INLINE LONGLONG InterlockedOr64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); - return Old; - } -#endif - -#ifndef InterlockedXor64 -#define InterlockedXor64 InterlockedXor64_Inline - - __CRT_INLINE LONGLONG InterlockedXor64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); - return Old; - } -#endif - -#ifndef InterlockedBitTestAndSet -#define InterlockedBitTestAndSet InterlockedBitTestAndSet_Inline - - __CRT_INLINE BOOLEAN InterlockedBitTestAndSet_Inline(LONG *Base,LONG Bit) { - LONG tBit; - tBit = 1<<(Bit & (sizeof (*Base)*8-1)); - return (BOOLEAN)((InterlockedOr(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); - } -#endif - -#ifndef InterlockedBitTestAndReset -#define InterlockedBitTestAndReset InterlockedBitTestAndReset_Inline - - __CRT_INLINE BOOLEAN InterlockedBitTestAndReset_Inline(LONG *Base,LONG Bit) { - LONG tBit; - tBit = 1<<(Bit & (sizeof (*Base)*8-1)); - return (BOOLEAN)((InterlockedAnd(&Base[Bit/(sizeof(*Base)*8)],~tBit)&tBit)!=0); - } -#endif - -#ifndef InterlockedBitTestAndComplement -#define InterlockedBitTestAndComplement InterlockedBitTestAndComplement_Inline - - __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement_Inline(LONG *Base,LONG Bit) { - LONG tBit; - tBit = 1<<(Bit & (sizeof (*Base)*8-1)); - return (BOOLEAN)((InterlockedXor(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); - } -#endif -#elif defined(__x86_64) && !defined(RC_INVOKED) - -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedDecrement _InterlockedDecrement -#define InterlockedDecrementAcquire InterlockedDecrement -#define InterlockedDecrementRelease InterlockedDecrement -#define InterlockedExchange _InterlockedExchange -#define InterlockedExchangeAdd _InterlockedExchangeAdd -#define InterlockedCompareExchange _InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire InterlockedCompareExchange -#define InterlockedCompareExchangeRelease InterlockedCompareExchange -#define InterlockedExchangePointer _InterlockedExchangePointer -#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer -#define InterlockedAnd64 _InterlockedAnd64 -#define InterlockedOr64 _InterlockedOr64 -#define InterlockedXor64 _InterlockedXor64 -#define InterlockedIncrement64 _InterlockedIncrement64 -#define InterlockedDecrement64 _InterlockedDecrement64 -#define InterlockedExchange64 _InterlockedExchange64 -#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 -#define InterlockedCompareExchange64 _InterlockedCompareExchange64 -#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 -#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 - - LONG InterlockedIncrement(LONG volatile *Addend); - LONG InterlockedDecrement(LONG volatile *Addend); - LONG InterlockedExchange(LONG volatile *Target,LONG Value); - LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); - PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); - PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); - LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value); - LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value); - LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value); - LONG64 InterlockedIncrement64(LONG64 volatile *Addend); - LONG64 InterlockedDecrement64(LONG64 volatile *Addend); - LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value); - LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); - LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand); -#else - LONG WINAPI InterlockedIncrement(LONG volatile *lpAddend); - LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend); - LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value); - -#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value)) - - LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand); - LONGLONG WINAPI InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand); - - __CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); - return Old; - } - - __CRT_INLINE LONGLONG InterlockedOr64 (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); - return Old; - } - - __CRT_INLINE LONGLONG InterlockedXor64 (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); - - return Old; - } - - __CRT_INLINE LONGLONG InterlockedIncrement64(LONGLONG volatile *Addend) { - LONGLONG Old; - do { - Old = *Addend; - } while(InterlockedCompareExchange64(Addend,Old + 1,Old)!=Old); - return Old + 1; - } - - __CRT_INLINE LONGLONG InterlockedDecrement64(LONGLONG volatile *Addend) { - LONGLONG Old; - do { - Old = *Addend; - } while(InterlockedCompareExchange64(Addend,Old - 1,Old)!=Old); - return Old - 1; - } - - __CRT_INLINE LONGLONG InterlockedExchange64(LONGLONG volatile *Target,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Target; - } while(InterlockedCompareExchange64(Target,Value,Old)!=Old); - return Old; - } - - __CRT_INLINE LONGLONG InterlockedExchangeAdd64(LONGLONG volatile *Addend,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Addend; - } while(InterlockedCompareExchange64(Addend,Old + Value,Old)!=Old); - return Old; - } - -#ifdef __cplusplus - __CRT_INLINE PVOID __cdecl __InlineInterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { - return((PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)Destination,(LONG)(LONG_PTR)ExChange,(LONG)(LONG_PTR)Comperand)); - } -#define InterlockedCompareExchangePointer __InlineInterlockedCompareExchangePointer -#else -#define InterlockedCompareExchangePointer(Destination,ExChange,Comperand)(PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)(Destination),(LONG)(LONG_PTR)(ExChange),(LONG)(LONG_PTR)(Comperand)) -#endif - -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedDecrementAcquire InterlockedDecrement -#define InterlockedDecrementRelease InterlockedDecrement -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedCompareExchangeAcquire InterlockedCompareExchange -#define InterlockedCompareExchangeRelease InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 -#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 -#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer -#endif - -#if defined(_SLIST_HEADER_) && !defined(_NTOSP_) - WINBASEAPI VOID WINAPI InitializeSListHead(PSLIST_HEADER ListHead); - WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPopEntrySList(PSLIST_HEADER ListHead); - WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); - WINBASEAPI PSLIST_ENTRY WINAPI InterlockedFlushSList(PSLIST_HEADER ListHead); - WINBASEAPI USHORT WINAPI QueryDepthSList(PSLIST_HEADER ListHead); -#endif -#endif -#endif - - WINBASEAPI WINBOOL WINAPI FreeResource(HGLOBAL hResData); - WINBASEAPI LPVOID WINAPI LockResource(HGLOBAL hResData); - -#define UnlockResource(hResData) ((hResData),0) -#define MAXINTATOM 0xC000 -#define MAKEINTATOM(i) (LPTSTR)((ULONG_PTR)((WORD)(i))) -#define INVALID_ATOM ((ATOM)0) - - int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd); - WINBASEAPI WINBOOL WINAPI FreeLibrary(HMODULE hLibModule); - WINBASEAPI DECLSPEC_NORETURN VOID WINAPI FreeLibraryAndExitThread(HMODULE hLibModule,DWORD dwExitCode); - WINBASEAPI WINBOOL WINAPI DisableThreadLibraryCalls(HMODULE hLibModule); - WINBASEAPI FARPROC WINAPI GetProcAddress(HMODULE hModule,LPCSTR lpProcName); - WINBASEAPI DWORD WINAPI GetVersion(VOID); - WINBASEAPI HGLOBAL WINAPI GlobalAlloc(UINT uFlags,SIZE_T dwBytes); - WINBASEAPI HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem,SIZE_T dwBytes,UINT uFlags); - WINBASEAPI SIZE_T WINAPI GlobalSize(HGLOBAL hMem); - WINBASEAPI UINT WINAPI GlobalFlags(HGLOBAL hMem); - WINBASEAPI LPVOID WINAPI GlobalLock(HGLOBAL hMem); - WINBASEAPI HGLOBAL WINAPI GlobalHandle(LPCVOID pMem); - WINBASEAPI WINBOOL WINAPI GlobalUnlock(HGLOBAL hMem); - WINBASEAPI HGLOBAL WINAPI GlobalFree(HGLOBAL hMem); - WINBASEAPI SIZE_T WINAPI GlobalCompact(DWORD dwMinFree); - WINBASEAPI VOID WINAPI GlobalFix(HGLOBAL hMem); - WINBASEAPI VOID WINAPI GlobalUnfix(HGLOBAL hMem); - WINBASEAPI LPVOID WINAPI GlobalWire(HGLOBAL hMem); - WINBASEAPI WINBOOL WINAPI GlobalUnWire(HGLOBAL hMem); - WINBASEAPI VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer); - - typedef struct _MEMORYSTATUSEX { - DWORD dwLength; - DWORD dwMemoryLoad; - DWORDLONG ullTotalPhys; - DWORDLONG ullAvailPhys; - DWORDLONG ullTotalPageFile; - DWORDLONG ullAvailPageFile; - DWORDLONG ullTotalVirtual; - DWORDLONG ullAvailVirtual; - DWORDLONG ullAvailExtendedVirtual; - } MEMORYSTATUSEX,*LPMEMORYSTATUSEX; - - WINBASEAPI WINBOOL WINAPI GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer); - WINBASEAPI HLOCAL WINAPI LocalAlloc(UINT uFlags,SIZE_T uBytes); - WINBASEAPI HLOCAL WINAPI LocalReAlloc(HLOCAL hMem,SIZE_T uBytes,UINT uFlags); - WINBASEAPI LPVOID WINAPI LocalLock(HLOCAL hMem); - WINBASEAPI HLOCAL WINAPI LocalHandle(LPCVOID pMem); - WINBASEAPI WINBOOL WINAPI LocalUnlock(HLOCAL hMem); - WINBASEAPI SIZE_T WINAPI LocalSize(HLOCAL hMem); - WINBASEAPI UINT WINAPI LocalFlags(HLOCAL hMem); - WINBASEAPI HLOCAL WINAPI LocalFree(HLOCAL hMem); - WINBASEAPI SIZE_T WINAPI LocalShrink(HLOCAL hMem,UINT cbNewSize); - WINBASEAPI SIZE_T WINAPI LocalCompact(UINT uMinFree); - WINBASEAPI WINBOOL WINAPI FlushInstructionCache(HANDLE hProcess,LPCVOID lpBaseAddress,SIZE_T dwSize); - WINBASEAPI LPVOID WINAPI VirtualAlloc(LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); - WINBASEAPI WINBOOL WINAPI VirtualFree(LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); - WINBASEAPI WINBOOL WINAPI VirtualProtect(LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); - WINBASEAPI SIZE_T WINAPI VirtualQuery(LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); - WINBASEAPI LPVOID WINAPI VirtualAllocEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); - WINBASEAPI UINT WINAPI GetWriteWatch(DWORD dwFlags,PVOID lpBaseAddress,SIZE_T dwRegionSize,PVOID *lpAddresses,ULONG_PTR *lpdwCount,PULONG lpdwGranularity); - WINBASEAPI UINT WINAPI ResetWriteWatch(LPVOID lpBaseAddress,SIZE_T dwRegionSize); - WINBASEAPI SIZE_T WINAPI GetLargePageMinimum(VOID); - WINBASEAPI UINT WINAPI EnumSystemFirmwareTables(DWORD FirmwareTableProviderSignature,PVOID pFirmwareTableEnumBuffer,DWORD BufferSize); - WINBASEAPI UINT WINAPI GetSystemFirmwareTable(DWORD FirmwareTableProviderSignature,DWORD FirmwareTableID,PVOID pFirmwareTableBuffer,DWORD BufferSize); - WINBASEAPI WINBOOL WINAPI VirtualFreeEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); - WINBASEAPI WINBOOL WINAPI VirtualProtectEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); - WINBASEAPI SIZE_T WINAPI VirtualQueryEx(HANDLE hProcess,LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); - WINBASEAPI HANDLE WINAPI HeapCreate(DWORD flOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize); - WINBASEAPI WINBOOL WINAPI HeapDestroy(HANDLE hHeap); - WINBASEAPI LPVOID WINAPI HeapAlloc(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes); - WINBASEAPI LPVOID WINAPI HeapReAlloc(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem,SIZE_T dwBytes); - WINBASEAPI WINBOOL WINAPI HeapFree(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem); - WINBASEAPI SIZE_T WINAPI HeapSize(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); - WINBASEAPI WINBOOL WINAPI HeapValidate(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); - WINBASEAPI SIZE_T WINAPI HeapCompact(HANDLE hHeap,DWORD dwFlags); - WINBASEAPI HANDLE WINAPI GetProcessHeap(VOID); - WINBASEAPI DWORD WINAPI GetProcessHeaps(DWORD NumberOfHeaps,PHANDLE ProcessHeaps); - - typedef struct _PROCESS_HEAP_ENTRY { - PVOID lpData; - DWORD cbData; - BYTE cbOverhead; - BYTE iRegionIndex; - WORD wFlags; - union { - struct { - HANDLE hMem; - DWORD dwReserved[3]; - } Block; - struct { - DWORD dwCommittedSize; - DWORD dwUnCommittedSize; - LPVOID lpFirstBlock; - LPVOID lpLastBlock; - } Region; - }; - } PROCESS_HEAP_ENTRY,*LPPROCESS_HEAP_ENTRY,*PPROCESS_HEAP_ENTRY; - -#define PROCESS_HEAP_REGION 0x1 -#define PROCESS_HEAP_UNCOMMITTED_RANGE 0x2 -#define PROCESS_HEAP_ENTRY_BUSY 0x4 -#define PROCESS_HEAP_ENTRY_MOVEABLE 0x10 -#define PROCESS_HEAP_ENTRY_DDESHARE 0x20 - - WINBASEAPI WINBOOL WINAPI HeapLock(HANDLE hHeap); - WINBASEAPI WINBOOL WINAPI HeapUnlock(HANDLE hHeap); - WINBASEAPI WINBOOL WINAPI HeapWalk(HANDLE hHeap,LPPROCESS_HEAP_ENTRY lpEntry); - WINBASEAPI WINBOOL WINAPI HeapSetInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); - WINBASEAPI WINBOOL WINAPI HeapQueryInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); - -#define SCS_32BIT_BINARY 0 -#define SCS_DOS_BINARY 1 -#define SCS_WOW_BINARY 2 -#define SCS_PIF_BINARY 3 -#define SCS_POSIX_BINARY 4 -#define SCS_OS216_BINARY 5 -#define SCS_64BIT_BINARY 6 - -#ifdef UNICODE -#define GetBinaryType GetBinaryTypeW -#define GetShortPathName GetShortPathNameW -#define GetLongPathName GetLongPathNameW -#define GetEnvironmentStrings GetEnvironmentStringsW -#define SetEnvironmentStrings SetEnvironmentStringsW -#define FreeEnvironmentStrings FreeEnvironmentStringsW -#else -#define GetBinaryType GetBinaryTypeA -#define GetShortPathName GetShortPathNameA -#define GetLongPathName GetLongPathNameA -#define GetEnvironmentStringsA GetEnvironmentStrings -#define SetEnvironmentStrings SetEnvironmentStringsA -#define FreeEnvironmentStrings FreeEnvironmentStringsA -#endif - -#ifdef _WIN64 -#define SCS_THIS_PLATFORM_BINARY SCS_64BIT_BINARY -#else -#define SCS_THIS_PLATFORM_BINARY SCS_32BIT_BINARY -#endif - - WINBASEAPI WINBOOL WINAPI GetBinaryTypeA(LPCSTR lpApplicationName,LPDWORD lpBinaryType); - WINBASEAPI WINBOOL WINAPI GetBinaryTypeW(LPCWSTR lpApplicationName,LPDWORD lpBinaryType); - WINBASEAPI DWORD WINAPI GetShortPathNameA(LPCSTR lpszLongPath,LPSTR lpszShortPath,DWORD cchBuffer); - WINBASEAPI DWORD WINAPI GetShortPathNameW(LPCWSTR lpszLongPath,LPWSTR lpszShortPath,DWORD cchBuffer); - WINBASEAPI DWORD WINAPI GetLongPathNameA(LPCSTR lpszShortPath,LPSTR lpszLongPath,DWORD cchBuffer); - WINBASEAPI DWORD WINAPI GetLongPathNameW(LPCWSTR lpszShortPath,LPWSTR lpszLongPath,DWORD cchBuffer); - WINBASEAPI WINBOOL WINAPI GetProcessAffinityMask(HANDLE hProcess,PDWORD_PTR lpProcessAffinityMask,PDWORD_PTR lpSystemAffinityMask); - WINBASEAPI WINBOOL WINAPI SetProcessAffinityMask(HANDLE hProcess,DWORD_PTR dwProcessAffinityMask); - WINBASEAPI WINBOOL WINAPI GetProcessHandleCount(HANDLE hProcess,PDWORD pdwHandleCount); - WINBASEAPI WINBOOL WINAPI GetProcessTimes(HANDLE hProcess,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); - WINBASEAPI WINBOOL WINAPI GetProcessIoCounters(HANDLE hProcess,PIO_COUNTERS lpIoCounters); - WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize); - WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSizeEx(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize,PDWORD Flags); - WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize); - WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSizeEx(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize,DWORD Flags); - WINBASEAPI HANDLE WINAPI OpenProcess(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwProcessId); - WINBASEAPI HANDLE WINAPI GetCurrentProcess(VOID); - WINBASEAPI DWORD WINAPI GetCurrentProcessId(VOID); - WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitProcess(UINT uExitCode); - WINBASEAPI WINBOOL WINAPI TerminateProcess(HANDLE hProcess,UINT uExitCode); - WINBASEAPI WINBOOL WINAPI GetExitCodeProcess(HANDLE hProcess,LPDWORD lpExitCode); - WINBASEAPI VOID WINAPI FatalExit(int ExitCode); - /* WINBASEAPI LPCH WINAPI GetEnvironmentStrings(VOID); */ - WINBASEAPI LPWCH WINAPI GetEnvironmentStringsW(VOID); - WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsA(LPCH NewEnvironment); - WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsW(LPWCH NewEnvironment); - WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsA(LPCH); - WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsW(LPWCH); - WINBASEAPI VOID WINAPI RaiseException(DWORD dwExceptionCode,DWORD dwExceptionFlags,DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments); - WINBASEAPI LONG WINAPI UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo); - - typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(struct _EXCEPTION_POINTERS *ExceptionInfo); - typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER; - - WINBASEAPI LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); - -#define FIBER_FLAG_FLOAT_SWITCH 0x1 - - WINBASEAPI LPVOID WINAPI CreateFiber(SIZE_T dwStackSize,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); - WINBASEAPI LPVOID WINAPI CreateFiberEx(SIZE_T dwStackCommitSize,SIZE_T dwStackReserveSize,DWORD dwFlags,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); - WINBASEAPI VOID WINAPI DeleteFiber(LPVOID lpFiber); - WINBASEAPI LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter); - WINBASEAPI LPVOID WINAPI ConvertThreadToFiberEx(LPVOID lpParameter,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI ConvertFiberToThread(VOID); - WINBASEAPI VOID WINAPI SwitchToFiber(LPVOID lpFiber); - WINBASEAPI WINBOOL WINAPI SwitchToThread(VOID); - WINBASEAPI HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); - WINBASEAPI HANDLE WINAPI CreateRemoteThread(HANDLE hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); - WINBASEAPI HANDLE WINAPI GetCurrentThread(VOID); - WINBASEAPI DWORD WINAPI GetCurrentThreadId(VOID); - WINBASEAPI WINBOOL WINAPI SetThreadStackGuarantee (PULONG StackSizeInBytes); - WINBASEAPI DWORD WINAPI GetProcessIdOfThread(HANDLE Thread); - WINBASEAPI DWORD WINAPI GetThreadId(HANDLE Thread); - WINBASEAPI DWORD WINAPI GetProcessId(HANDLE Process); - WINBASEAPI DWORD WINAPI GetCurrentProcessorNumber(VOID); - WINBASEAPI DWORD_PTR WINAPI SetThreadAffinityMask(HANDLE hThread,DWORD_PTR dwThreadAffinityMask); - WINBASEAPI DWORD WINAPI SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor); - WINBASEAPI WINBOOL WINAPI SetProcessPriorityBoost(HANDLE hProcess,WINBOOL bDisablePriorityBoost); - WINBASEAPI WINBOOL WINAPI GetProcessPriorityBoost(HANDLE hProcess,PBOOL pDisablePriorityBoost); - WINBASEAPI WINBOOL WINAPI RequestWakeupLatency(LATENCY_TIME latency); - WINBASEAPI WINBOOL WINAPI IsSystemResumeAutomatic(VOID); - WINBASEAPI HANDLE WINAPI OpenThread(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwThreadId); - WINBASEAPI WINBOOL WINAPI SetThreadPriority(HANDLE hThread,int nPriority); - WINBASEAPI WINBOOL WINAPI SetThreadPriorityBoost(HANDLE hThread,WINBOOL bDisablePriorityBoost); - WINBASEAPI WINBOOL WINAPI GetThreadPriorityBoost(HANDLE hThread,PBOOL pDisablePriorityBoost); - WINBASEAPI int WINAPI GetThreadPriority(HANDLE hThread); - WINBASEAPI WINBOOL WINAPI GetThreadTimes(HANDLE hThread,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); - WINBASEAPI WINBOOL WINAPI GetThreadIOPendingFlag(HANDLE hThread,PBOOL lpIOIsPending); - WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitThread(DWORD dwExitCode); - WINBASEAPI WINBOOL WINAPI TerminateThread(HANDLE hThread,DWORD dwExitCode); - WINBASEAPI WINBOOL WINAPI GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode); - WINBASEAPI WINBOOL WINAPI GetThreadSelectorEntry(HANDLE hThread,DWORD dwSelector,LPLDT_ENTRY lpSelectorEntry); - WINBASEAPI EXECUTION_STATE WINAPI SetThreadExecutionState(EXECUTION_STATE esFlags); - WINBASEAPI DWORD WINAPI GetLastError(VOID); - WINBASEAPI VOID WINAPI SetLastError(DWORD dwErrCode); - -#ifndef RC_INVOKED -#ifdef WINBASE_DECLARE_RESTORE_LAST_ERROR - WINBASEAPI VOID WINAPI RestoreLastError(DWORD dwErrCode); - - typedef VOID (WINAPI *PRESTORE_LAST_ERROR)(DWORD); - -#define RESTORE_LAST_ERROR_NAME_A "RestoreLastError" -#define RESTORE_LAST_ERROR_NAME_W L"RestoreLastError" -#define RESTORE_LAST_ERROR_NAME TEXT("RestoreLastError") -#endif -#endif - -#define HasOverlappedIoCompleted(lpOverlapped) (((DWORD)(lpOverlapped)->Internal)!=STATUS_PENDING) - - WINBASEAPI WINBOOL WINAPI GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,LPDWORD lpNumberOfBytesTransferred,WINBOOL bWait); - WINBASEAPI HANDLE WINAPI CreateIoCompletionPort(HANDLE FileHandle,HANDLE ExistingCompletionPort,ULONG_PTR CompletionKey,DWORD NumberOfConcurrentThreads); - WINBASEAPI WINBOOL WINAPI GetQueuedCompletionStatus(HANDLE CompletionPort,LPDWORD lpNumberOfBytesTransferred,PULONG_PTR lpCompletionKey,LPOVERLAPPED *lpOverlapped,DWORD dwMilliseconds); - WINBASEAPI WINBOOL WINAPI PostQueuedCompletionStatus(HANDLE CompletionPort,DWORD dwNumberOfBytesTransferred,ULONG_PTR dwCompletionKey,LPOVERLAPPED lpOverlapped); - -#define SEM_FAILCRITICALERRORS 0x1 -#define SEM_NOGPFAULTERRORBOX 0x2 -#define SEM_NOALIGNMENTFAULTEXCEPT 0x4 -#define SEM_NOOPENFILEERRORBOX 0x8000 - - WINBASEAPI UINT WINAPI SetErrorMode(UINT uMode); - WINBASEAPI WINBOOL WINAPI ReadProcessMemory(HANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesRead); - WINBASEAPI WINBOOL WINAPI WriteProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesWritten); - WINBASEAPI WINBOOL WINAPI GetThreadContext(HANDLE hThread,LPCONTEXT lpContext); - WINBASEAPI WINBOOL WINAPI SetThreadContext(HANDLE hThread,CONST CONTEXT *lpContext); - WINBASEAPI DWORD WINAPI SuspendThread(HANDLE hThread); - WINBASEAPI DWORD WINAPI ResumeThread(HANDLE hThread); - - typedef VOID (WINAPI *PAPCFUNC)(ULONG_PTR dwParam); - - WINBASEAPI DWORD WINAPI QueueUserAPC(PAPCFUNC pfnAPC,HANDLE hThread,ULONG_PTR dwData); - WINBASEAPI WINBOOL WINAPI IsDebuggerPresent(VOID); - WINBASEAPI WINBOOL WINAPI CheckRemoteDebuggerPresent(HANDLE hProcess,PBOOL pbDebuggerPresent); - WINBASEAPI VOID WINAPI DebugBreak(VOID); - WINBASEAPI WINBOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT lpDebugEvent,DWORD dwMilliseconds); - WINBASEAPI WINBOOL WINAPI ContinueDebugEvent(DWORD dwProcessId,DWORD dwThreadId,DWORD dwContinueStatus); - WINBASEAPI WINBOOL WINAPI DebugActiveProcess(DWORD dwProcessId); - WINBASEAPI WINBOOL WINAPI DebugActiveProcessStop(DWORD dwProcessId); - WINBASEAPI WINBOOL WINAPI DebugSetProcessKillOnExit(WINBOOL KillOnExit); - WINBASEAPI WINBOOL WINAPI DebugBreakProcess(HANDLE Process); - WINBASEAPI VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI WINBOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); - WINBASEAPI DWORD WINAPI SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); - WINBASEAPI WINBOOL WINAPI TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI WINBOOL WINAPI SetEvent(HANDLE hEvent); - WINBASEAPI WINBOOL WINAPI ResetEvent(HANDLE hEvent); - WINBASEAPI WINBOOL WINAPI PulseEvent(HANDLE hEvent); - WINBASEAPI WINBOOL WINAPI ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount,LPLONG lpPreviousCount); - WINBASEAPI WINBOOL WINAPI ReleaseMutex(HANDLE hMutex); - WINBASEAPI DWORD WINAPI WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds); - WINBASEAPI DWORD WINAPI WaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds); - WINBASEAPI VOID WINAPI Sleep(DWORD dwMilliseconds); - WINBASEAPI HGLOBAL WINAPI LoadResource(HMODULE hModule,HRSRC hResInfo); - WINBASEAPI DWORD WINAPI SizeofResource(HMODULE hModule,HRSRC hResInfo); - WINBASEAPI ATOM WINAPI GlobalDeleteAtom(ATOM nAtom); - WINBASEAPI WINBOOL WINAPI InitAtomTable(DWORD nSize); - WINBASEAPI ATOM WINAPI DeleteAtom(ATOM nAtom); - WINBASEAPI UINT WINAPI SetHandleCount(UINT uNumber); - WINBASEAPI DWORD WINAPI GetLogicalDrives(VOID); - WINBASEAPI WINBOOL WINAPI LockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh); - WINBASEAPI WINBOOL WINAPI UnlockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh); - WINBASEAPI WINBOOL WINAPI LockFileEx(HANDLE hFile,DWORD dwFlags,DWORD dwReserved,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh,LPOVERLAPPED lpOverlapped); - -#define LOCKFILE_FAIL_IMMEDIATELY 0x1 -#define LOCKFILE_EXCLUSIVE_LOCK 0x2 - - WINBASEAPI WINBOOL WINAPI UnlockFileEx(HANDLE hFile,DWORD dwReserved,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh,LPOVERLAPPED lpOverlapped); - - typedef struct _BY_HANDLE_FILE_INFORMATION { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD dwVolumeSerialNumber; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD nNumberOfLinks; - DWORD nFileIndexHigh; - DWORD nFileIndexLow; - } BY_HANDLE_FILE_INFORMATION,*PBY_HANDLE_FILE_INFORMATION,*LPBY_HANDLE_FILE_INFORMATION; - -#ifdef UNICODE -#define SetFileShortName SetFileShortNameW -#else -#define SetFileShortName SetFileShortNameA -#endif - - WINBASEAPI WINBOOL WINAPI GetFileInformationByHandle(HANDLE hFile,LPBY_HANDLE_FILE_INFORMATION lpFileInformation); - WINBASEAPI DWORD WINAPI GetFileType(HANDLE hFile); - WINBASEAPI DWORD WINAPI GetFileSize(HANDLE hFile,LPDWORD lpFileSizeHigh); - WINBASEAPI WINBOOL WINAPI GetFileSizeEx(HANDLE hFile,PLARGE_INTEGER lpFileSize); - WINBASEAPI HANDLE WINAPI GetStdHandle(DWORD nStdHandle); - WINBASEAPI WINBOOL WINAPI SetStdHandle(DWORD nStdHandle,HANDLE hHandle); - WINBASEAPI WINBOOL WINAPI WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI FlushFileBuffers(HANDLE hFile); - WINBASEAPI WINBOOL WINAPI DeviceIoControl(HANDLE hDevice,DWORD dwIoControlCode,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI RequestDeviceWakeup(HANDLE hDevice); - WINBASEAPI WINBOOL WINAPI CancelDeviceWakeupRequest(HANDLE hDevice); - WINBASEAPI WINBOOL WINAPI GetDevicePowerState(HANDLE hDevice,WINBOOL *pfOn); - WINBASEAPI WINBOOL WINAPI SetMessageWaitingIndicator(HANDLE hMsgIndicator,ULONG ulMsgCount); - WINBASEAPI WINBOOL WINAPI SetEndOfFile(HANDLE hFile); - WINBASEAPI DWORD WINAPI SetFilePointer(HANDLE hFile,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod); - WINBASEAPI WINBOOL WINAPI SetFilePointerEx(HANDLE hFile,LARGE_INTEGER liDistanceToMove,PLARGE_INTEGER lpNewFilePointer,DWORD dwMoveMethod); - WINBASEAPI WINBOOL WINAPI FindClose(HANDLE hFindFile); - WINBASEAPI WINBOOL WINAPI GetFileTime(HANDLE hFile,LPFILETIME lpCreationTime,LPFILETIME lpLastAccessTime,LPFILETIME lpLastWriteTime); - WINBASEAPI WINBOOL WINAPI SetFileTime(HANDLE hFile,CONST FILETIME *lpCreationTime,CONST FILETIME *lpLastAccessTime,CONST FILETIME *lpLastWriteTime); - WINBASEAPI WINBOOL WINAPI SetFileValidData(HANDLE hFile,LONGLONG ValidDataLength); - WINBASEAPI WINBOOL WINAPI SetFileShortNameA(HANDLE hFile,LPCSTR lpShortName); - WINBASEAPI WINBOOL WINAPI SetFileShortNameW(HANDLE hFile,LPCWSTR lpShortName); - WINBASEAPI WINBOOL WINAPI CloseHandle(HANDLE hObject); - WINBASEAPI WINBOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle,HANDLE hSourceHandle,HANDLE hTargetProcessHandle,LPHANDLE lpTargetHandle,DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwOptions); - WINBASEAPI WINBOOL WINAPI GetHandleInformation(HANDLE hObject,LPDWORD lpdwFlags); - WINBASEAPI WINBOOL WINAPI SetHandleInformation(HANDLE hObject,DWORD dwMask,DWORD dwFlags); - -#define HANDLE_FLAG_INHERIT 0x1 -#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x2 - -#define HINSTANCE_ERROR 32 - - WINBASEAPI DWORD WINAPI LoadModule(LPCSTR lpModuleName,LPVOID lpParameterBlock); - WINBASEAPI UINT WINAPI WinExec(LPCSTR lpCmdLine,UINT uCmdShow); - WINBASEAPI WINBOOL WINAPI ClearCommBreak(HANDLE hFile); - WINBASEAPI WINBOOL WINAPI ClearCommError(HANDLE hFile,LPDWORD lpErrors,LPCOMSTAT lpStat); - WINBASEAPI WINBOOL WINAPI SetupComm(HANDLE hFile,DWORD dwInQueue,DWORD dwOutQueue); - WINBASEAPI WINBOOL WINAPI EscapeCommFunction(HANDLE hFile,DWORD dwFunc); - WINBASEAPI WINBOOL WINAPI GetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); - WINBASEAPI WINBOOL WINAPI GetCommMask(HANDLE hFile,LPDWORD lpEvtMask); - WINBASEAPI WINBOOL WINAPI GetCommProperties(HANDLE hFile,LPCOMMPROP lpCommProp); - WINBASEAPI WINBOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat); - WINBASEAPI WINBOOL WINAPI GetCommState(HANDLE hFile,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI GetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI PurgeComm(HANDLE hFile,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI SetCommBreak(HANDLE hFile); - WINBASEAPI WINBOOL WINAPI SetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,DWORD dwSize); - WINBASEAPI WINBOOL WINAPI SetCommMask(HANDLE hFile,DWORD dwEvtMask); - WINBASEAPI WINBOOL WINAPI SetCommState(HANDLE hFile,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI SetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI TransmitCommChar(HANDLE hFile,char cChar); - WINBASEAPI WINBOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD lpEvtMask,LPOVERLAPPED lpOverlapped); - WINBASEAPI DWORD WINAPI SetTapePosition(HANDLE hDevice,DWORD dwPositionMethod,DWORD dwPartition,DWORD dwOffsetLow,DWORD dwOffsetHigh,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI GetTapePosition(HANDLE hDevice,DWORD dwPositionType,LPDWORD lpdwPartition,LPDWORD lpdwOffsetLow,LPDWORD lpdwOffsetHigh); - WINBASEAPI DWORD WINAPI PrepareTape(HANDLE hDevice,DWORD dwOperation,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI EraseTape(HANDLE hDevice,DWORD dwEraseType,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI CreateTapePartition(HANDLE hDevice,DWORD dwPartitionMethod,DWORD dwCount,DWORD dwSize); - WINBASEAPI DWORD WINAPI WriteTapemark(HANDLE hDevice,DWORD dwTapemarkType,DWORD dwTapemarkCount,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI GetTapeStatus(HANDLE hDevice); - WINBASEAPI DWORD WINAPI GetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPDWORD lpdwSize,LPVOID lpTapeInformation); - -#define GET_TAPE_MEDIA_INFORMATION 0 -#define GET_TAPE_DRIVE_INFORMATION 1 - - WINBASEAPI DWORD WINAPI SetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPVOID lpTapeInformation); - -#define SET_TAPE_MEDIA_INFORMATION 0 -#define SET_TAPE_DRIVE_INFORMATION 1 - - WINBASEAPI WINBOOL WINAPI Beep(DWORD dwFreq,DWORD dwDuration); - WINBASEAPI int WINAPI MulDiv(int nNumber,int nNumerator,int nDenominator); - WINBASEAPI VOID WINAPI GetSystemTime(LPSYSTEMTIME lpSystemTime); - WINBASEAPI VOID WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); - WINBASEAPI WINBOOL WINAPI SetSystemTime(CONST SYSTEMTIME *lpSystemTime); - WINBASEAPI VOID WINAPI GetLocalTime(LPSYSTEMTIME lpSystemTime); - WINBASEAPI WINBOOL WINAPI SetLocalTime(CONST SYSTEMTIME *lpSystemTime); - WINBASEAPI VOID WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo); - WINBASEAPI WINBOOL WINAPI SetSystemFileCacheSize(SIZE_T MinimumFileCacheSize,SIZE_T MaximumFileCacheSize,DWORD Flags); - WINBASEAPI WINBOOL WINAPI GetSystemFileCacheSize(PSIZE_T lpMinimumFileCacheSize,PSIZE_T lpMaximumFileCacheSize,PDWORD lpFlags); - WINBASEAPI WINBOOL WINAPI GetSystemRegistryQuota(PDWORD pdwQuotaAllowed,PDWORD pdwQuotaUsed); - WINBOOL WINAPI GetSystemTimes(LPFILETIME lpIdleTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); - WINBASEAPI VOID WINAPI GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo); - WINBASEAPI WINBOOL WINAPI IsProcessorFeaturePresent(DWORD ProcessorFeature); - - typedef struct _TIME_ZONE_INFORMATION { - LONG Bias; - WCHAR StandardName[32]; - SYSTEMTIME StandardDate; - LONG StandardBias; - WCHAR DaylightName[32]; - SYSTEMTIME DaylightDate; - LONG DaylightBias; - } TIME_ZONE_INFORMATION,*PTIME_ZONE_INFORMATION,*LPTIME_ZONE_INFORMATION; - -#ifdef UNICODE -#define FormatMessage FormatMessageW -#else -#define FormatMessage FormatMessageA -#endif - - WINBASEAPI WINBOOL WINAPI SystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpUniversalTime,LPSYSTEMTIME lpLocalTime); - WINBASEAPI WINBOOL WINAPI TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpLocalTime,LPSYSTEMTIME lpUniversalTime); - WINBASEAPI DWORD WINAPI GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation); - WINBASEAPI WINBOOL WINAPI SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation); - WINBASEAPI WINBOOL WINAPI SystemTimeToFileTime(CONST SYSTEMTIME *lpSystemTime,LPFILETIME lpFileTime); - WINBASEAPI WINBOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *lpFileTime,LPFILETIME lpLocalFileTime); - WINBASEAPI WINBOOL WINAPI LocalFileTimeToFileTime(CONST FILETIME *lpLocalFileTime,LPFILETIME lpFileTime); - WINBASEAPI WINBOOL WINAPI FileTimeToSystemTime(CONST FILETIME *lpFileTime,LPSYSTEMTIME lpSystemTime); - WINBASEAPI LONG WINAPI CompareFileTime(CONST FILETIME *lpFileTime1,CONST FILETIME *lpFileTime2); - WINBASEAPI WINBOOL WINAPI FileTimeToDosDateTime(CONST FILETIME *lpFileTime,LPWORD lpFatDate,LPWORD lpFatTime); - WINBASEAPI WINBOOL WINAPI DosDateTimeToFileTime(WORD wFatDate,WORD wFatTime,LPFILETIME lpFileTime); - WINBASEAPI DWORD WINAPI GetTickCount(VOID); - WINBASEAPI WINBOOL WINAPI SetSystemTimeAdjustment(DWORD dwTimeAdjustment,WINBOOL bTimeAdjustmentDisabled); - WINBASEAPI WINBOOL WINAPI GetSystemTimeAdjustment(PDWORD lpTimeAdjustment,PDWORD lpTimeIncrement,PBOOL lpTimeAdjustmentDisabled); - WINBASEAPI DWORD WINAPI FormatMessageA(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPSTR lpBuffer,DWORD nSize,va_list *Arguments); - WINBASEAPI DWORD WINAPI FormatMessageW(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPWSTR lpBuffer,DWORD nSize,va_list *Arguments); - -#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x100 -#define FORMAT_MESSAGE_IGNORE_INSERTS 0x200 -#define FORMAT_MESSAGE_FROM_STRING 0x400 -#define FORMAT_MESSAGE_FROM_HMODULE 0x800 -#define FORMAT_MESSAGE_FROM_SYSTEM 0x1000 -#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x2000 -#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0xff - -#ifdef UNICODE -#define CreateMailslot CreateMailslotW -#define EncryptFile EncryptFileW -#define DecryptFile DecryptFileW -#define FileEncryptionStatus FileEncryptionStatusW -#else -#define CreateMailslot CreateMailslotA -#define EncryptFile EncryptFileA -#define DecryptFile DecryptFileA -#define FileEncryptionStatus FileEncryptionStatusA -#endif - - WINBASEAPI WINBOOL WINAPI CreatePipe(PHANDLE hReadPipe,PHANDLE hWritePipe,LPSECURITY_ATTRIBUTES lpPipeAttributes,DWORD nSize); - WINBASEAPI WINBOOL WINAPI ConnectNamedPipe(HANDLE hNamedPipe,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI DisconnectNamedPipe(HANDLE hNamedPipe); - WINBASEAPI WINBOOL WINAPI SetNamedPipeHandleState(HANDLE hNamedPipe,LPDWORD lpMode,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout); - WINBASEAPI WINBOOL WINAPI GetNamedPipeInfo(HANDLE hNamedPipe,LPDWORD lpFlags,LPDWORD lpOutBufferSize,LPDWORD lpInBufferSize,LPDWORD lpMaxInstances); - WINBASEAPI WINBOOL WINAPI PeekNamedPipe(HANDLE hNamedPipe,LPVOID lpBuffer,DWORD nBufferSize,LPDWORD lpBytesRead,LPDWORD lpTotalBytesAvail,LPDWORD lpBytesLeftThisMessage); - WINBASEAPI WINBOOL WINAPI TransactNamedPipe(HANDLE hNamedPipe,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,LPOVERLAPPED lpOverlapped); - WINBASEAPI HANDLE WINAPI CreateMailslotA(LPCSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI HANDLE WINAPI CreateMailslotW(LPCWSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI GetMailslotInfo(HANDLE hMailslot,LPDWORD lpMaxMessageSize,LPDWORD lpNextSize,LPDWORD lpMessageCount,LPDWORD lpReadTimeout); - WINBASEAPI WINBOOL WINAPI SetMailslotInfo(HANDLE hMailslot,DWORD lReadTimeout); - WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap); - WINBASEAPI WINBOOL WINAPI FlushViewOfFile(LPCVOID lpBaseAddress,SIZE_T dwNumberOfBytesToFlush); - WINBASEAPI WINBOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress); - WINADVAPI WINBOOL WINAPI EncryptFileA(LPCSTR lpFileName); - WINADVAPI WINBOOL WINAPI EncryptFileW(LPCWSTR lpFileName); - WINADVAPI WINBOOL WINAPI DecryptFileA(LPCSTR lpFileName,DWORD dwReserved); - WINADVAPI WINBOOL WINAPI DecryptFileW(LPCWSTR lpFileName,DWORD dwReserved); - -#define FILE_ENCRYPTABLE 0 -#define FILE_IS_ENCRYPTED 1 -#define FILE_SYSTEM_ATTR 2 -#define FILE_ROOT_DIR 3 -#define FILE_SYSTEM_DIR 4 -#define FILE_UNKNOWN 5 -#define FILE_SYSTEM_NOT_SUPPORT 6 -#define FILE_USER_DISALLOWED 7 -#define FILE_READ_ONLY 8 -#define FILE_DIR_DISALLOWED 9 - - WINADVAPI WINBOOL WINAPI FileEncryptionStatusA(LPCSTR lpFileName,LPDWORD lpStatus); - WINADVAPI WINBOOL WINAPI FileEncryptionStatusW(LPCWSTR lpFileName,LPDWORD lpStatus); - -#define EFS_USE_RECOVERY_KEYS (0x1) - - typedef DWORD (WINAPI *PFE_EXPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,ULONG ulLength); - typedef DWORD (WINAPI *PFE_IMPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,PULONG ulLength); - -#define CREATE_FOR_IMPORT (1) -#define CREATE_FOR_DIR (2) -#define OVERWRITE_HIDDEN (4) - -#ifdef UNICODE -#define OpenEncryptedFileRaw OpenEncryptedFileRawW -#define lstrcmp lstrcmpW -#define lstrcmpi lstrcmpiW -#define lstrcpyn lstrcpynW -#define lstrcpy lstrcpyW -#define lstrcat lstrcatW -#define lstrlen lstrlenW -#else -#define OpenEncryptedFileRaw OpenEncryptedFileRawA -#define lstrcmp lstrcmpA -#define lstrcmpi lstrcmpiA -#define lstrcpyn lstrcpynA -#define lstrcpy lstrcpyA -#define lstrcat lstrcatA -#define lstrlen lstrlenA -#endif - - WINADVAPI DWORD WINAPI OpenEncryptedFileRawA(LPCSTR lpFileName,ULONG ulFlags,PVOID *pvContext); - WINADVAPI DWORD WINAPI OpenEncryptedFileRawW(LPCWSTR lpFileName,ULONG ulFlags,PVOID *pvContext); - WINADVAPI DWORD WINAPI ReadEncryptedFileRaw(PFE_EXPORT_FUNC pfExportCallback,PVOID pvCallbackContext,PVOID pvContext); - WINADVAPI DWORD WINAPI WriteEncryptedFileRaw(PFE_IMPORT_FUNC pfImportCallback,PVOID pvCallbackContext,PVOID pvContext); - WINADVAPI VOID WINAPI CloseEncryptedFileRaw(PVOID pvContext); - WINBASEAPI int WINAPI lstrcmpA(LPCSTR lpString1,LPCSTR lpString2); - WINBASEAPI int WINAPI lstrcmpW(LPCWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI int WINAPI lstrcmpiA(LPCSTR lpString1,LPCSTR lpString2); - WINBASEAPI int WINAPI lstrcmpiW(LPCWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI LPSTR WINAPI lstrcpynA(LPSTR lpString1,LPCSTR lpString2,int iMaxLength); - WINBASEAPI LPWSTR WINAPI lstrcpynW(LPWSTR lpString1,LPCWSTR lpString2,int iMaxLength); - WINBASEAPI LPSTR WINAPI lstrcpyA(LPSTR lpString1,LPCSTR lpString2); - WINBASEAPI LPWSTR WINAPI lstrcpyW(LPWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI LPSTR WINAPI lstrcatA(LPSTR lpString1,LPCSTR lpString2); - WINBASEAPI LPWSTR WINAPI lstrcatW(LPWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI int WINAPI lstrlenA(LPCSTR lpString); - WINBASEAPI int WINAPI lstrlenW(LPCWSTR lpString); - WINBASEAPI HFILE WINAPI OpenFile(LPCSTR lpFileName,LPOFSTRUCT lpReOpenBuff,UINT uStyle); - WINBASEAPI HFILE WINAPI _lopen(LPCSTR lpPathName,int iReadWrite); - WINBASEAPI HFILE WINAPI _lcreat(LPCSTR lpPathName,int iAttribute); - WINBASEAPI UINT WINAPI _lread(HFILE hFile,LPVOID lpBuffer,UINT uBytes); - WINBASEAPI UINT WINAPI _lwrite(HFILE hFile,LPCCH lpBuffer,UINT uBytes); - WINBASEAPI long WINAPI _hread(HFILE hFile,LPVOID lpBuffer,long lBytes); - WINBASEAPI long WINAPI _hwrite(HFILE hFile,LPCCH lpBuffer,long lBytes); - WINBASEAPI HFILE WINAPI _lclose(HFILE hFile); - WINBASEAPI LONG WINAPI _llseek(HFILE hFile,LONG lOffset,int iOrigin); - WINADVAPI WINBOOL WINAPI IsTextUnicode(CONST VOID *lpv,int iSize,LPINT lpiResult); - -#define FLS_OUT_OF_INDEXES ((DWORD)0xffffffff) - - WINBASEAPI DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); - WINBASEAPI PVOID WINAPI FlsGetValue(DWORD dwFlsIndex); - WINBASEAPI WINBOOL WINAPI FlsSetValue(DWORD dwFlsIndex,PVOID lpFlsData); - WINBASEAPI WINBOOL WINAPI FlsFree(DWORD dwFlsIndex); - -#define TLS_OUT_OF_INDEXES ((DWORD)0xffffffff) - - WINBASEAPI DWORD WINAPI TlsAlloc(VOID); - WINBASEAPI LPVOID WINAPI TlsGetValue(DWORD dwTlsIndex); - WINBASEAPI WINBOOL WINAPI TlsSetValue(DWORD dwTlsIndex,LPVOID lpTlsValue); - WINBASEAPI WINBOOL WINAPI TlsFree(DWORD dwTlsIndex); - - typedef VOID (WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped); - - WINBASEAPI DWORD WINAPI SleepEx(DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI DWORD WINAPI WaitForSingleObjectEx(HANDLE hHandle,DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI DWORD WINAPI WaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI DWORD WINAPI SignalObjectAndWait(HANDLE hObjectToSignal,HANDLE hObjectToWaitOn,DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI WINBOOL WINAPI ReadFileEx(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINBASEAPI WINBOOL WINAPI WriteFileEx(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINBASEAPI WINBOOL WINAPI BackupRead(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); - WINBASEAPI WINBOOL WINAPI BackupSeek(HANDLE hFile,DWORD dwLowBytesToSeek,DWORD dwHighBytesToSeek,LPDWORD lpdwLowByteSeeked,LPDWORD lpdwHighByteSeeked,LPVOID *lpContext); - WINBASEAPI WINBOOL WINAPI BackupWrite(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); - - typedef struct _WIN32_STREAM_ID { - DWORD dwStreamId; - DWORD dwStreamAttributes; - LARGE_INTEGER Size; - DWORD dwStreamNameSize; - WCHAR cStreamName[ANYSIZE_ARRAY]; - } WIN32_STREAM_ID,*LPWIN32_STREAM_ID; - -#define BACKUP_INVALID 0x0 -#define BACKUP_DATA 0x1 -#define BACKUP_EA_DATA 0x2 -#define BACKUP_SECURITY_DATA 0x3 -#define BACKUP_ALTERNATE_DATA 0x4 -#define BACKUP_LINK 0x5 -#define BACKUP_PROPERTY_DATA 0x6 -#define BACKUP_OBJECT_ID 0x7 -#define BACKUP_REPARSE_DATA 0x8 -#define BACKUP_SPARSE_BLOCK 0x9 - -#define STREAM_NORMAL_ATTRIBUTE 0x0 -#define STREAM_MODIFIED_WHEN_READ 0x1 -#define STREAM_CONTAINS_SECURITY 0x2 -#define STREAM_CONTAINS_PROPERTIES 0x4 -#define STREAM_SPARSE_ATTRIBUTE 0x8 - - WINBASEAPI WINBOOL WINAPI ReadFileScatter(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToRead,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI WriteFileGather(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToWrite,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); - -#define STARTF_USESHOWWINDOW 0x1 -#define STARTF_USESIZE 0x2 -#define STARTF_USEPOSITION 0x4 -#define STARTF_USECOUNTCHARS 0x8 -#define STARTF_USEFILLATTRIBUTE 0x10 -#define STARTF_RUNFULLSCREEN 0x20 -#define STARTF_FORCEONFEEDBACK 0x40 -#define STARTF_FORCEOFFFEEDBACK 0x80 -#define STARTF_USESTDHANDLES 0x100 - -#define STARTF_USEHOTKEY 0x200 - - typedef struct _STARTUPINFOA { - DWORD cb; - LPSTR lpReserved; - LPSTR lpDesktop; - LPSTR lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - LPBYTE lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOA,*LPSTARTUPINFOA; - - typedef struct _STARTUPINFOW { - DWORD cb; - LPWSTR lpReserved; - LPWSTR lpDesktop; - LPWSTR lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - LPBYTE lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOW,*LPSTARTUPINFOW; - -#ifdef UNICODE - typedef STARTUPINFOW STARTUPINFO; - typedef LPSTARTUPINFOW LPSTARTUPINFO; -#else - typedef STARTUPINFOA STARTUPINFO; - typedef LPSTARTUPINFOA LPSTARTUPINFO; -#endif - -#define SHUTDOWN_NORETRY 0x1 - - typedef struct _WIN32_FIND_DATAA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - CHAR cFileName[MAX_PATH]; - CHAR cAlternateFileName[14]; - } WIN32_FIND_DATAA,*PWIN32_FIND_DATAA,*LPWIN32_FIND_DATAA; - - typedef struct _WIN32_FIND_DATAW { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - WCHAR cFileName[MAX_PATH]; - WCHAR cAlternateFileName[14]; - } WIN32_FIND_DATAW,*PWIN32_FIND_DATAW,*LPWIN32_FIND_DATAW; - -#ifdef UNICODE - typedef WIN32_FIND_DATAW WIN32_FIND_DATA; - typedef PWIN32_FIND_DATAW PWIN32_FIND_DATA; - typedef LPWIN32_FIND_DATAW LPWIN32_FIND_DATA; -#else - typedef WIN32_FIND_DATAA WIN32_FIND_DATA; - typedef PWIN32_FIND_DATAA PWIN32_FIND_DATA; - typedef LPWIN32_FIND_DATAA LPWIN32_FIND_DATA; -#endif - - typedef struct _WIN32_FILE_ATTRIBUTE_DATA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA,*LPWIN32_FILE_ATTRIBUTE_DATA; - -#ifdef UNICODE -#define CreateMutex CreateMutexW -#define OpenMutex OpenMutexW -#define CreateEvent CreateEventW -#define OpenEvent OpenEventW -#define CreateSemaphore CreateSemaphoreW -#define OpenSemaphore OpenSemaphoreW -#else -#define CreateMutex CreateMutexA -#define OpenMutex OpenMutexA -#define CreateEvent CreateEventA -#define OpenEvent OpenEventA -#define CreateSemaphore CreateSemaphoreA -#define OpenSemaphore OpenSemaphoreA -#endif - - WINBASEAPI HANDLE WINAPI CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenMutexA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenMutexW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenEventA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenEventW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenSemaphoreA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenSemaphoreW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - - typedef VOID (WINAPI *PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue); - -#ifdef UNICODE -#define CreateWaitableTimer CreateWaitableTimerW -#define OpenWaitableTimer OpenWaitableTimerW -#define CreateFileMapping CreateFileMappingW -#define OpenFileMapping OpenFileMappingW -#define GetLogicalDriveStrings GetLogicalDriveStringsW -#define LoadLibrary LoadLibraryW -#define LoadLibraryEx LoadLibraryExW -#define GetModuleFileName GetModuleFileNameW -#define GetModuleHandle GetModuleHandleW -#else -#define CreateWaitableTimer CreateWaitableTimerA -#define OpenWaitableTimer OpenWaitableTimerA -#define CreateFileMapping CreateFileMappingA -#define OpenFileMapping OpenFileMappingA -#define GetLogicalDriveStrings GetLogicalDriveStringsA -#define LoadLibrary LoadLibraryA -#define LoadLibraryEx LoadLibraryExA -#define GetModuleFileName GetModuleFileNameA -#define GetModuleHandle GetModuleHandleA -#endif - - WINBASEAPI HANDLE WINAPI CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCSTR lpTimerName); - WINBASEAPI HANDLE WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCWSTR lpTimerName); - WINBASEAPI HANDLE WINAPI OpenWaitableTimerA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpTimerName); - WINBASEAPI HANDLE WINAPI OpenWaitableTimerW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpTimerName); - WINBASEAPI WINBOOL WINAPI SetWaitableTimer(HANDLE hTimer,const LARGE_INTEGER *lpDueTime,LONG lPeriod,PTIMERAPCROUTINE pfnCompletionRoutine,LPVOID lpArgToCompletionRoutine,WINBOOL fResume); - WINBASEAPI WINBOOL WINAPI CancelWaitableTimer(HANDLE hTimer); - WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenFileMappingA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenFileMappingW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI DWORD WINAPI GetLogicalDriveStringsA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetLogicalDriveStringsW(DWORD nBufferLength,LPWSTR lpBuffer); - - typedef enum _MEMORY_RESOURCE_NOTIFICATION_TYPE { - LowMemoryResourceNotification,HighMemoryResourceNotification - } MEMORY_RESOURCE_NOTIFICATION_TYPE; - - WINBASEAPI HANDLE WINAPI CreateMemoryResourceNotification(MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType); - WINBASEAPI WINBOOL WINAPI QueryMemoryResourceNotification(HANDLE ResourceNotificationHandle,PBOOL ResourceState); - WINBASEAPI HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName); - WINBASEAPI HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName); - WINBASEAPI HMODULE WINAPI LoadLibraryExA(LPCSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); - WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); - -#define DONT_RESOLVE_DLL_REFERENCES 0x1 -#define LOAD_LIBRARY_AS_DATAFILE 0x2 -#define LOAD_WITH_ALTERED_SEARCH_PATH 0x8 -#define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x10 -#define LOAD_LINRARY_AS_IMAGE_RESOURCE 0x20 -#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x40 - - WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule,LPCH lpFilename,DWORD nSize); - WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE hModule,LPWCH lpFilename,DWORD nSize); - WINBASEAPI HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName); - WINBASEAPI HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName); - -#ifndef RC_INVOKED -#define GET_MODULE_HANDLE_EX_FLAG_PIN (0x1) -#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT (0x2) -#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS (0x4) - - typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXA)(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); - typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXW)(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); - -#ifdef UNICODE -#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXW -#define GetModuleHandleEx GetModuleHandleExW -#else -#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXA -#define GetModuleHandleEx GetModuleHandleExA -#endif - - WINBASEAPI WINBOOL WINAPI GetModuleHandleExA(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); - WINBASEAPI WINBOOL WINAPI GetModuleHandleExW(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); -#endif - -#ifdef UNICODE -#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathW -#define CreateProcess CreateProcessW -#define FatalAppExit FatalAppExitW -#define GetStartupInfo GetStartupInfoW -#define GetCommandLine GetCommandLineW -#define GetEnvironmentVariable GetEnvironmentVariableW -#define SetEnvironmentVariable SetEnvironmentVariableW -#define ExpandEnvironmentStrings ExpandEnvironmentStringsW -#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableW -#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableW -#define OutputDebugString OutputDebugStringW -#define FindResource FindResourceW -#define FindResourceEx FindResourceExW -#else -#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathA -#define CreateProcess CreateProcessA -#define FatalAppExit FatalAppExitA -#define GetStartupInfo GetStartupInfoA -#define GetCommandLine GetCommandLineA -#define GetEnvironmentVariable GetEnvironmentVariableA -#define SetEnvironmentVariable SetEnvironmentVariableA -#define ExpandEnvironmentStrings ExpandEnvironmentStringsA -#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableA -#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableA -#define OutputDebugString OutputDebugStringA -#define FindResource FindResourceA -#define FindResourceEx FindResourceExA -#endif - - WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathA(LPCSTR ExeName); - WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathW(LPCWSTR ExeName); - WINBASEAPI WINBOOL WINAPI CreateProcessA(LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINBASEAPI WINBOOL WINAPI CreateProcessW(LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameA(LPCSTR lpDnsFQHostname,ULONG ulFlags); - WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameW(LPCWSTR lpDnsFQHostname,ULONG ulFlags); - WINBASEAPI WINBOOL WINAPI SetProcessShutdownParameters(DWORD dwLevel,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI GetProcessShutdownParameters(LPDWORD lpdwLevel,LPDWORD lpdwFlags); - WINBASEAPI DWORD WINAPI GetProcessVersion(DWORD ProcessId); - WINBASEAPI VOID WINAPI FatalAppExitA(UINT uAction,LPCSTR lpMessageText); - WINBASEAPI VOID WINAPI FatalAppExitW(UINT uAction,LPCWSTR lpMessageText); - WINBASEAPI VOID WINAPI GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo); - WINBASEAPI VOID WINAPI GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo); - WINBASEAPI LPSTR WINAPI GetCommandLineA(VOID); - WINBASEAPI LPWSTR WINAPI GetCommandLineW(VOID); - WINBASEAPI DWORD WINAPI GetEnvironmentVariableA(LPCSTR lpName,LPSTR lpBuffer,DWORD nSize); - WINBASEAPI DWORD WINAPI GetEnvironmentVariableW(LPCWSTR lpName,LPWSTR lpBuffer,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableA(LPCSTR lpName,LPCSTR lpValue); - WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpValue); - WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsA(LPCSTR lpSrc,LPSTR lpDst,DWORD nSize); - WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsW(LPCWSTR lpSrc,LPWSTR lpDst,DWORD nSize); - WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pBuffer,DWORD nSize); - WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pBuffer,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pValue,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pValue,DWORD nSize); - WINBASEAPI VOID WINAPI OutputDebugStringA(LPCSTR lpOutputString); - WINBASEAPI VOID WINAPI OutputDebugStringW(LPCWSTR lpOutputString); - WINBASEAPI HRSRC WINAPI FindResourceA(HMODULE hModule,LPCSTR lpName,LPCSTR lpType); - WINBASEAPI HRSRC WINAPI FindResourceW(HMODULE hModule,LPCWSTR lpName,LPCWSTR lpType); - WINBASEAPI HRSRC WINAPI FindResourceExA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage); - WINBASEAPI HRSRC WINAPI FindResourceExW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage); - -#ifdef UNICODE -#define ENUMRESTYPEPROC ENUMRESTYPEPROCW -#define ENUMRESNAMEPROC ENUMRESNAMEPROCW -#define ENUMRESLANGPROC ENUMRESLANGPROCW -#define EnumResourceTypes EnumResourceTypesW -#define EnumResourceNames EnumResourceNamesW -#define EnumResourceLanguages EnumResourceLanguagesW -#define BeginUpdateResource BeginUpdateResourceW -#define UpdateResource UpdateResourceW -#define EndUpdateResource EndUpdateResourceW -#define GlobalAddAtom GlobalAddAtomW -#define GlobalFindAtom GlobalFindAtomW -#define GlobalGetAtomName GlobalGetAtomNameW -#define AddAtom AddAtomW -#define FindAtom FindAtomW -#define GetAtomName GetAtomNameW -#define GetProfileInt GetProfileIntW -#define GetProfileString GetProfileStringW -#define WriteProfileString WriteProfileStringW -#define GetProfileSection GetProfileSectionW -#define WriteProfileSection WriteProfileSectionW -#define GetPrivateProfileInt GetPrivateProfileIntW -#define GetPrivateProfileString GetPrivateProfileStringW -#define WritePrivateProfileString WritePrivateProfileStringW -#define GetPrivateProfileSection GetPrivateProfileSectionW -#define WritePrivateProfileSection WritePrivateProfileSectionW -#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesW -#define GetPrivateProfileStruct GetPrivateProfileStructW -#define WritePrivateProfileStruct WritePrivateProfileStructW -#define GetDriveType GetDriveTypeW -#define GetSystemDirectory GetSystemDirectoryW -#define GetTempPath GetTempPathW -#define GetTempFileName GetTempFileNameW -#define GetWindowsDirectory GetWindowsDirectoryW -#define GetSystemWindowsDirectory GetSystemWindowsDirectoryW -#define AddLocalAlternateComputerName AddLocalAlternateComputerNameW -#else -#define ENUMRESTYPEPROC ENUMRESTYPEPROCA -#define ENUMRESNAMEPROC ENUMRESNAMEPROCA -#define ENUMRESLANGPROC ENUMRESLANGPROCA -#define EnumResourceTypes EnumResourceTypesA -#define EnumResourceNames EnumResourceNamesA -#define EnumResourceLanguages EnumResourceLanguagesA -#define BeginUpdateResource BeginUpdateResourceA -#define UpdateResource UpdateResourceA -#define EndUpdateResource EndUpdateResourceA -#define GlobalAddAtom GlobalAddAtomA -#define GlobalFindAtom GlobalFindAtomA -#define GlobalGetAtomName GlobalGetAtomNameA -#define AddAtom AddAtomA -#define FindAtom FindAtomA -#define GetAtomName GetAtomNameA -#define GetProfileInt GetProfileIntA -#define GetProfileString GetProfileStringA -#define WriteProfileString WriteProfileStringA -#define GetProfileSection GetProfileSectionA -#define WriteProfileSection WriteProfileSectionA -#define GetPrivateProfileInt GetPrivateProfileIntA -#define GetPrivateProfileString GetPrivateProfileStringA -#define WritePrivateProfileString WritePrivateProfileStringA -#define GetPrivateProfileSection GetPrivateProfileSectionA -#define WritePrivateProfileSection WritePrivateProfileSectionA -#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesA -#define GetPrivateProfileStruct GetPrivateProfileStructA -#define WritePrivateProfileStruct WritePrivateProfileStructA -#define GetDriveType GetDriveTypeA -#define GetSystemDirectory GetSystemDirectoryA -#define GetTempPath GetTempPathA -#define GetTempFileName GetTempFileNameA -#define GetWindowsDirectory GetWindowsDirectoryA -#define GetSystemWindowsDirectory GetSystemWindowsDirectoryA -#define AddLocalAlternateComputerName AddLocalAlternateComputerNameA -#endif - - typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCA)(HMODULE hModule,LPSTR lpType,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCW)(HMODULE hModule,LPWSTR lpType,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCA)(HMODULE hModule,LPCSTR lpType,LPSTR lpName,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCW)(HMODULE hModule,LPCWSTR lpType,LPWSTR lpName,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESLANGPROCA)(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESLANGPROCW)(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LONG_PTR lParam); - - WINBASEAPI WINBOOL WINAPI EnumResourceTypesA(HMODULE hModule,ENUMRESTYPEPROCA lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceTypesW(HMODULE hModule,ENUMRESTYPEPROCW lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceNamesA(HMODULE hModule,LPCSTR lpType,ENUMRESNAMEPROCA lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceNamesW(HMODULE hModule,LPCWSTR lpType,ENUMRESNAMEPROCW lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,ENUMRESLANGPROCA lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,ENUMRESLANGPROCW lpEnumFunc,LONG_PTR lParam); - WINBASEAPI HANDLE WINAPI BeginUpdateResourceA(LPCSTR pFileName,WINBOOL bDeleteExistingResources); - WINBASEAPI HANDLE WINAPI BeginUpdateResourceW(LPCWSTR pFileName,WINBOOL bDeleteExistingResources); - WINBASEAPI WINBOOL WINAPI UpdateResourceA(HANDLE hUpdate,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); - WINBASEAPI WINBOOL WINAPI UpdateResourceW(HANDLE hUpdate,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); - WINBASEAPI WINBOOL WINAPI EndUpdateResourceA(HANDLE hUpdate,WINBOOL fDiscard); - WINBASEAPI WINBOOL WINAPI EndUpdateResourceW(HANDLE hUpdate,WINBOOL fDiscard); - WINBASEAPI ATOM WINAPI GlobalAddAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI GlobalAddAtomW(LPCWSTR lpString); - WINBASEAPI ATOM WINAPI GlobalFindAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI GlobalFindAtomW(LPCWSTR lpString); - WINBASEAPI UINT WINAPI GlobalGetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); - WINBASEAPI UINT WINAPI GlobalGetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); - WINBASEAPI ATOM WINAPI AddAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI AddAtomW(LPCWSTR lpString); - WINBASEAPI ATOM WINAPI FindAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI FindAtomW(LPCWSTR lpString); - WINBASEAPI UINT WINAPI GetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); - WINBASEAPI UINT WINAPI GetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); - WINBASEAPI UINT WINAPI GetProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault); - WINBASEAPI UINT WINAPI GetProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault); - WINBASEAPI DWORD WINAPI GetProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize); - WINBASEAPI DWORD WINAPI GetProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize); - WINBASEAPI WINBOOL WINAPI WriteProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString); - WINBASEAPI WINBOOL WINAPI WriteProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString); - WINBASEAPI DWORD WINAPI GetProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize); - WINBASEAPI DWORD WINAPI GetProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize); - WINBASEAPI WINBOOL WINAPI WriteProfileSectionA(LPCSTR lpAppName,LPCSTR lpString); - WINBASEAPI WINBOOL WINAPI WriteProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString); - WINBASEAPI UINT WINAPI GetPrivateProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault,LPCSTR lpFileName); - WINBASEAPI UINT WINAPI GetPrivateProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault,LPCWSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString,LPCSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString,LPCWSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionA(LPCSTR lpAppName,LPCSTR lpString,LPCSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString,LPCWSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesA(LPSTR lpszReturnBuffer,DWORD nSize,LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesW(LPWSTR lpszReturnBuffer,DWORD nSize,LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); - WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); - WINBASEAPI UINT WINAPI GetDriveTypeA(LPCSTR lpRootPathName); - WINBASEAPI UINT WINAPI GetDriveTypeW(LPCWSTR lpRootPathName); - WINBASEAPI UINT WINAPI GetSystemDirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemDirectoryW(LPWSTR lpBuffer,UINT uSize); - WINBASEAPI DWORD WINAPI GetTempPathA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetTempPathW(DWORD nBufferLength,LPWSTR lpBuffer); - WINBASEAPI UINT WINAPI GetTempFileNameA(LPCSTR lpPathName,LPCSTR lpPrefixString,UINT uUnique,LPSTR lpTempFileName); - WINBASEAPI UINT WINAPI GetTempFileNameW(LPCWSTR lpPathName,LPCWSTR lpPrefixString,UINT uUnique,LPWSTR lpTempFileName); - WINBASEAPI UINT WINAPI GetWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); - -#ifndef RC_INVOKED -#ifdef UNICODE -#define GetSystemWow64Directory GetSystemWow64DirectoryW -#else -#define GetSystemWow64Directory GetSystemWow64DirectoryA -#endif - - WINBASEAPI UINT WINAPI GetSystemWow64DirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemWow64DirectoryW(LPWSTR lpBuffer,UINT uSize); - WINBASEAPI BOOLEAN WINAPI Wow64EnableWow64FsRedirection(BOOLEAN Wow64FsEnableRedirection); - WINBASEAPI WINBOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue); - WINBASEAPI WINBOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OlValue); - - typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_A)(LPSTR lpBuffer,UINT uSize); - typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_W)(LPWSTR lpBuffer,UINT uSize); - -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A "GetSystemWow64DirectoryA" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W L"GetSystemWow64DirectoryA" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T TEXT("GetSystemWow64DirectoryA") -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A "GetSystemWow64DirectoryW" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W L"GetSystemWow64DirectoryW" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T TEXT("GetSystemWow64DirectoryW") - -#ifdef UNICODE -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T -#else -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T -#endif -#endif - -#ifdef UNICODE -#define SetCurrentDirectory SetCurrentDirectoryW -#define GetCurrentDirectory GetCurrentDirectoryW -#define SetDllDirectory SetDllDirectoryW -#define GetDllDirectory GetDllDirectoryW -#define GetDiskFreeSpace GetDiskFreeSpaceW -#define GetDiskFreeSpaceEx GetDiskFreeSpaceExW -#define CreateDirectory CreateDirectoryW -#define CreateDirectoryEx CreateDirectoryExW -#define RemoveDirectory RemoveDirectoryW -#define GetFullPathName GetFullPathNameW -#define DefineDosDevice DefineDosDeviceW -#define QueryDosDevice QueryDosDeviceW -#define CreateFile CreateFileW -#define SetFileAttributes SetFileAttributesW -#define GetFileAttributes GetFileAttributesW -#else -#define SetCurrentDirectory SetCurrentDirectoryA -#define GetCurrentDirectory GetCurrentDirectoryA -#define SetDllDirectory SetDllDirectoryA -#define GetDllDirectory GetDllDirectoryA -#define GetDiskFreeSpace GetDiskFreeSpaceA -#define GetDiskFreeSpaceEx GetDiskFreeSpaceExA -#define CreateDirectory CreateDirectoryA -#define CreateDirectoryEx CreateDirectoryExA -#define RemoveDirectory RemoveDirectoryA -#define GetFullPathName GetFullPathNameA -#define DefineDosDevice DefineDosDeviceA -#define QueryDosDevice QueryDosDeviceA -#define CreateFile CreateFileA -#define SetFileAttributes SetFileAttributesA -#define GetFileAttributes GetFileAttributesA -#endif - - WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryA(LPCSTR lpPathName); - WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryW(LPCWSTR lpPathName); - WINBASEAPI DWORD WINAPI GetCurrentDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetCurrentDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI SetDllDirectoryA(LPCSTR lpPathName); - WINBASEAPI WINBOOL WINAPI SetDllDirectoryW(LPCWSTR lpPathName); - WINBASEAPI DWORD WINAPI GetDllDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetDllDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceA(LPCSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceW(LPCWSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExA(LPCSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExW(LPCWSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryA(LPCSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryW(LPCWSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryExA(LPCSTR lpTemplateDirectory,LPCSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryExW(LPCWSTR lpTemplateDirectory,LPCWSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI RemoveDirectoryA(LPCSTR lpPathName); - WINBASEAPI WINBOOL WINAPI RemoveDirectoryW(LPCWSTR lpPathName); - WINBASEAPI DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); - WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); - -#define DDD_RAW_TARGET_PATH 0x1 -#define DDD_REMOVE_DEFINITION 0x2 -#define DDD_EXACT_MATCH_ON_REMOVE 0x4 -#define DDD_NO_BROADCAST_SYSTEM 0x8 -#define DDD_LUID_BROADCAST_DRIVE 0x10 - - WINBASEAPI WINBOOL WINAPI DefineDosDeviceA(DWORD dwFlags,LPCSTR lpDeviceName,LPCSTR lpTargetPath); - WINBASEAPI WINBOOL WINAPI DefineDosDeviceW(DWORD dwFlags,LPCWSTR lpDeviceName,LPCWSTR lpTargetPath); - WINBASEAPI DWORD WINAPI QueryDosDeviceA(LPCSTR lpDeviceName,LPSTR lpTargetPath,DWORD ucchMax); - WINBASEAPI DWORD WINAPI QueryDosDeviceW(LPCWSTR lpDeviceName,LPWSTR lpTargetPath,DWORD ucchMax); - -#define EXPAND_LOCAL_DRIVES - - WINBASEAPI HANDLE WINAPI CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); - WINBASEAPI HANDLE WINAPI CreateFileW(LPCWSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); - WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE hOriginalFile,DWORD dwDesiredAccess,DWORD dwShareMode,DWORD dwFlagsAndAttributes); - WINBASEAPI WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName,DWORD dwFileAttributes); - WINBASEAPI WINBOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName,DWORD dwFileAttributes); - WINBASEAPI DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName); - - typedef enum _GET_FILEEX_INFO_LEVELS { - GetFileExInfoStandard,GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - -#ifdef UNICODE -#define GetFileAttributesEx GetFileAttributesExW -#define GetCompressedFileSize GetCompressedFileSizeW -#define DeleteFile DeleteFileW -#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3W -#else -#define GetFileAttributesEx GetFileAttributesExA -#define GetCompressedFileSize GetCompressedFileSizeA -#define DeleteFile DeleteFileA -#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3A -#endif - - WINBASEAPI WINBOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); - WINBASEAPI WINBOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); - WINBASEAPI DWORD WINAPI GetCompressedFileSizeA(LPCSTR lpFileName,LPDWORD lpFileSizeHigh); - WINBASEAPI DWORD WINAPI GetCompressedFileSizeW(LPCWSTR lpFileName,LPDWORD lpFileSizeHigh); - WINBASEAPI WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName); - WINBASEAPI WINBOOL WINAPI DeleteFileW(LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3A(LPCSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); - WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3W(LPCWSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); - - typedef enum _FINDEX_INFO_LEVELS { - FindExInfoStandard,FindExInfoMaxInfoLevel - } FINDEX_INFO_LEVELS; - - typedef enum _FINDEX_SEARCH_OPS { - FindExSearchNameMatch,FindExSearchLimitToDirectories,FindExSearchLimitToDevices,FindExSearchMaxSearchOp - } FINDEX_SEARCH_OPS; - -#define FIND_FIRST_EX_CASE_SENSITIVE 0x1 - -#ifdef UNICODE -#define FindFirstFileEx FindFirstFileExW -#define FindFirstFile FindFirstFileW -#define FindNextFile FindNextFileW -#define SearchPath SearchPathW -#define CopyFile CopyFileW -#define CopyFileEx CopyFileExW -#define MoveFile MoveFileW -#define MoveFileEx MoveFileExW -#define MoveFileWithProgress MoveFileWithProgressW -#define ReplaceFile ReplaceFileW -#define CreateHardLink CreateHardLinkW -#define CreateNamedPipe CreateNamedPipeW -#define GetNamedPipeHandleState GetNamedPipeHandleStateW -#define CallNamedPipe CallNamedPipeW -#define WaitNamedPipe WaitNamedPipeW -#define SetVolumeLabel SetVolumeLabelW -#define GetVolumeInformation GetVolumeInformationW -#define ClearEventLog ClearEventLogW -#define BackupEventLog BackupEventLogW -#define OpenEventLog OpenEventLogW -#define RegisterEventSource RegisterEventSourceW -#define OpenBackupEventLog OpenBackupEventLogW -#define ReadEventLog ReadEventLogW -#define ReportEvent ReportEventW -#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmW -#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmW -#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmW -#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleW -#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmW -#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmW -#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmW -#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmW -#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmW -#define SetFileSecurity SetFileSecurityW -#define GetFileSecurity GetFileSecurityW -#define FindFirstChangeNotification FindFirstChangeNotificationW -#define IsBadStringPtr IsBadStringPtrW -#define LookupAccountSid LookupAccountSidW -#define LookupAccountName LookupAccountNameW -#define LookupPrivilegeValue LookupPrivilegeValueW -#define LookupPrivilegeName LookupPrivilegeNameW -#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameW -#define BuildCommDCB BuildCommDCBW -#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW -#define CommConfigDialog CommConfigDialogW -#define GetDefaultCommConfig GetDefaultCommConfigW -#define SetDefaultCommConfig SetDefaultCommConfigW -#define GetComputerName GetComputerNameW -#define SetComputerName SetComputerNameW -#define GetComputerNameEx GetComputerNameExW -#define SetComputerNameEx SetComputerNameExW -#define DnsHostnameToComputerName DnsHostnameToComputerNameW -#define GetUserName GetUserNameW -#else -#define FindFirstFileEx FindFirstFileExA -#define FindFirstFile FindFirstFileA -#define FindNextFile FindNextFileA -#define SearchPath SearchPathA -#define CopyFile CopyFileA -#define CopyFileEx CopyFileExA -#define MoveFile MoveFileA -#define MoveFileEx MoveFileExA -#define MoveFileWithProgress MoveFileWithProgressA -#define ReplaceFile ReplaceFileA -#define CreateHardLink CreateHardLinkA -#define CreateNamedPipe CreateNamedPipeA -#define GetNamedPipeHandleState GetNamedPipeHandleStateA -#define CallNamedPipe CallNamedPipeA -#define WaitNamedPipe WaitNamedPipeA -#define SetVolumeLabel SetVolumeLabelA -#define GetVolumeInformation GetVolumeInformationA -#define ClearEventLog ClearEventLogA -#define BackupEventLog BackupEventLogA -#define OpenEventLog OpenEventLogA -#define RegisterEventSource RegisterEventSourceA -#define OpenBackupEventLog OpenBackupEventLogA -#define ReadEventLog ReadEventLogA -#define ReportEvent ReportEventA -#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmA -#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmA -#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmA -#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleA -#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmA -#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmA -#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmA -#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmA -#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmA -#define SetFileSecurity SetFileSecurityA -#define GetFileSecurity GetFileSecurityA -#define FindFirstChangeNotification FindFirstChangeNotificationA -#define IsBadStringPtr IsBadStringPtrA -#define LookupAccountSid LookupAccountSidA -#define LookupAccountName LookupAccountNameA -#define LookupPrivilegeValue LookupPrivilegeValueA -#define LookupPrivilegeName LookupPrivilegeNameA -#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameA -#define BuildCommDCB BuildCommDCBA -#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA -#define CommConfigDialog CommConfigDialogA -#define GetDefaultCommConfig GetDefaultCommConfigA -#define SetDefaultCommConfig SetDefaultCommConfigA -#define GetComputerName GetComputerNameA -#define SetComputerName SetComputerNameA -#define GetComputerNameEx GetComputerNameExA -#define SetComputerNameEx SetComputerNameExA -#define DnsHostnameToComputerName DnsHostnameToComputerNameA -#define GetUserName GetUserNameA -#endif - - WINBASEAPI HANDLE WINAPI FindFirstFileExA(LPCSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); - WINBASEAPI HANDLE WINAPI FindFirstFileExW(LPCWSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); - WINBASEAPI HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName,LPWIN32_FIND_DATAA lpFindFileData); - WINBASEAPI HANDLE WINAPI FindFirstFileW(LPCWSTR lpFileName,LPWIN32_FIND_DATAW lpFindFileData); - WINBASEAPI WINBOOL WINAPI FindNextFileA(HANDLE hFindFile,LPWIN32_FIND_DATAA lpFindFileData); - WINBASEAPI WINBOOL WINAPI FindNextFileW(HANDLE hFindFile,LPWIN32_FIND_DATAW lpFindFileData); - WINBASEAPI DWORD WINAPI SearchPathA(LPCSTR lpPath,LPCSTR lpFileName,LPCSTR lpExtension,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); - WINBASEAPI DWORD WINAPI SearchPathW(LPCWSTR lpPath,LPCWSTR lpFileName,LPCWSTR lpExtension,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); - WINBASEAPI WINBOOL WINAPI CopyFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,WINBOOL bFailIfExists); - WINBASEAPI WINBOOL WINAPI CopyFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,WINBOOL bFailIfExists); - - typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER TotalFileSize,LARGE_INTEGER TotalBytesTransferred,LARGE_INTEGER StreamSize,LARGE_INTEGER StreamBytesTransferred,DWORD dwStreamNumber,DWORD dwCallbackReason,HANDLE hSourceFile,HANDLE hDestinationFile,LPVOID lpData); - - WINBASEAPI WINBOOL WINAPI CopyFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); - WINBASEAPI WINBOOL WINAPI CopyFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); - WINBASEAPI WINBOOL WINAPI MoveFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName); - WINBASEAPI WINBOOL WINAPI MoveFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName); - WINBASEAPI WINBOOL WINAPI MoveFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI MoveFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI MoveFileWithProgressA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI MoveFileWithProgressW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); - -#define MOVEFILE_REPLACE_EXISTING 0x1 -#define MOVEFILE_COPY_ALLOWED 0x2 -#define MOVEFILE_DELAY_UNTIL_REBOOT 0x4 -#define MOVEFILE_WRITE_THROUGH 0x8 -#define MOVEFILE_CREATE_HARDLINK 0x10 -#define MOVEFILE_FAIL_IF_NOT_TRACKABLE 0x20 - - WINBASEAPI WINBOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,LPCSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,LPCWSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI CreateHardLinkA(LPCSTR lpFileName,LPCSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateHardLinkW(LPCWSTR lpFileName,LPCWSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - - typedef enum _STREAM_INFO_LEVELS { - FindStreamInfoStandard,FindStreamInfoMaxInfoLevel - } STREAM_INFO_LEVELS; - - typedef struct _WIN32_FIND_STREAM_DATA { - LARGE_INTEGER StreamSize; - WCHAR cStreamName[MAX_PATH + 36]; - } WIN32_FIND_STREAM_DATA,*PWIN32_FIND_STREAM_DATA; - - HANDLE WINAPI FindFirstStreamW(LPCWSTR lpFileName,STREAM_INFO_LEVELS InfoLevel,LPVOID lpFindStreamData,DWORD dwFlags); - WINBOOL WINAPI FindNextStreamW(HANDLE hFindStream,LPVOID lpFindStreamData); - WINBASEAPI HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI HANDLE WINAPI CreateNamedPipeW(LPCWSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateA(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPSTR lpUserName,DWORD nMaxUserNameSize); - WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateW(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPWSTR lpUserName,DWORD nMaxUserNameSize); - WINBASEAPI WINBOOL WINAPI CallNamedPipeA(LPCSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI CallNamedPipeW(LPCWSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI WaitNamedPipeA(LPCSTR lpNamedPipeName,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI WaitNamedPipeW(LPCWSTR lpNamedPipeName,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI SetVolumeLabelA(LPCSTR lpRootPathName,LPCSTR lpVolumeName); - WINBASEAPI WINBOOL WINAPI SetVolumeLabelW(LPCWSTR lpRootPathName,LPCWSTR lpVolumeName); - WINBASEAPI VOID WINAPI SetFileApisToOEM(VOID); - WINBASEAPI VOID WINAPI SetFileApisToANSI(VOID); - WINBASEAPI WINBOOL WINAPI AreFileApisANSI(VOID); - WINBASEAPI WINBOOL WINAPI GetVolumeInformationA(LPCSTR lpRootPathName,LPSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); - WINBASEAPI WINBOOL WINAPI GetVolumeInformationW(LPCWSTR lpRootPathName,LPWSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPWSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); - WINBASEAPI WINBOOL WINAPI CancelIo(HANDLE hFile); - WINADVAPI WINBOOL WINAPI ClearEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI ClearEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI BackupEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI BackupEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI CloseEventLog(HANDLE hEventLog); - WINADVAPI WINBOOL WINAPI DeregisterEventSource(HANDLE hEventLog); - WINADVAPI WINBOOL WINAPI NotifyChangeEventLog(HANDLE hEventLog,HANDLE hEvent); - WINADVAPI WINBOOL WINAPI GetNumberOfEventLogRecords(HANDLE hEventLog,PDWORD NumberOfRecords); - WINADVAPI WINBOOL WINAPI GetOldestEventLogRecord(HANDLE hEventLog,PDWORD OldestRecord); - WINADVAPI HANDLE WINAPI OpenEventLogA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); - WINADVAPI HANDLE WINAPI OpenEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); - WINADVAPI HANDLE WINAPI RegisterEventSourceA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); - WINADVAPI HANDLE WINAPI RegisterEventSourceW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); - WINADVAPI HANDLE WINAPI OpenBackupEventLogA(LPCSTR lpUNCServerName,LPCSTR lpFileName); - WINADVAPI HANDLE WINAPI OpenBackupEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpFileName); - WINADVAPI WINBOOL WINAPI ReadEventLogA(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); - WINADVAPI WINBOOL WINAPI ReadEventLogW(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); - WINADVAPI WINBOOL WINAPI ReportEventA(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCSTR *lpStrings,LPVOID lpRawData); - WINADVAPI WINBOOL WINAPI ReportEventW(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCWSTR *lpStrings,LPVOID lpRawData); - -#define EVENTLOG_FULL_INFO 0 - - typedef struct _EVENTLOG_FULL_INFORMATION { - DWORD dwFull; - } EVENTLOG_FULL_INFORMATION,*LPEVENTLOG_FULL_INFORMATION; - - WINADVAPI WINBOOL WINAPI GetEventLogInformation(HANDLE hEventLog,DWORD dwInfoLevel,LPVOID lpBuffer,DWORD cbBufSize,LPDWORD pcbBytesNeeded); - WINADVAPI WINBOOL WINAPI DuplicateToken(HANDLE ExistingTokenHandle,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,PHANDLE DuplicateTokenHandle); - WINADVAPI WINBOOL WINAPI GetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); - WINADVAPI WINBOOL WINAPI ImpersonateNamedPipeClient(HANDLE hNamedPipe); - WINADVAPI WINBOOL WINAPI ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel); - WINADVAPI WINBOOL WINAPI RevertToSelf(VOID); - WINADVAPI WINBOOL WINAPI SetThreadToken (PHANDLE Thread,HANDLE Token); - WINADVAPI WINBOOL WINAPI AccessCheck(PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); - WINADVAPI WINBOOL WINAPI AccessCheckByType(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultList(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccessList,LPDWORD AccessStatusList); - WINADVAPI WINBOOL WINAPI OpenProcessToken(HANDLE ProcessHandle,DWORD DesiredAccess,PHANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI OpenThreadToken(HANDLE ThreadHandle,DWORD DesiredAccess,WINBOOL OpenAsSelf,PHANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI GetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI SetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength); - WINADVAPI WINBOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle,WINBOOL DisableAllPrivileges,PTOKEN_PRIVILEGES NewState,DWORD BufferLength,PTOKEN_PRIVILEGES PreviousState,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI AdjustTokenGroups(HANDLE TokenHandle,WINBOOL ResetToDefault,PTOKEN_GROUPS NewState,DWORD BufferLength,PTOKEN_GROUPS PreviousState,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI PrivilegeCheck(HANDLE ClientToken,PPRIVILEGE_SET RequiredPrivileges,LPBOOL pfResult); - WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmA(LPCSTR SubsystemName,LPCSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmW(LPCWSTR SubsystemName,LPCWSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI IsWellKnownSid(PSID pSid,WELL_KNOWN_SID_TYPE WellKnownSidType); - WINADVAPI WINBOOL WINAPI CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType,PSID DomainSid,PSID pSid,DWORD *cbSid); - WINADVAPI WINBOOL WINAPI EqualDomainSid(PSID pSid1,PSID pSid2,WINBOOL *pfEqual); - WINADVAPI WINBOOL WINAPI GetWindowsAccountDomainSid(PSID pSid,PSID pDomainSid,DWORD *cbDomainSid); - WINADVAPI WINBOOL WINAPI IsValidSid(PSID pSid); - WINADVAPI WINBOOL WINAPI EqualSid(PSID pSid1,PSID pSid2); - WINADVAPI WINBOOL WINAPI EqualPrefixSid(PSID pSid1,PSID pSid2); - WINADVAPI DWORD WINAPI GetSidLengthRequired (UCHAR nSubAuthorityCount); - WINADVAPI WINBOOL WINAPI AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount,DWORD nSubAuthority0,DWORD nSubAuthority1,DWORD nSubAuthority2,DWORD nSubAuthority3,DWORD nSubAuthority4,DWORD nSubAuthority5,DWORD nSubAuthority6,DWORD nSubAuthority7,PSID *pSid); - WINADVAPI PVOID WINAPI FreeSid(PSID pSid); - WINADVAPI WINBOOL WINAPI InitializeSid(PSID Sid,PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount); - WINADVAPI PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid); - WINADVAPI PDWORD WINAPI GetSidSubAuthority(PSID pSid,DWORD nSubAuthority); - WINADVAPI PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid); - WINADVAPI DWORD WINAPI GetLengthSid(PSID pSid); - WINADVAPI WINBOOL WINAPI CopySid(DWORD nDestinationSidLength,PSID pDestinationSid,PSID pSourceSid); - WINADVAPI WINBOOL WINAPI AreAllAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); - WINADVAPI WINBOOL WINAPI AreAnyAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); - WINADVAPI VOID WINAPI MapGenericMask(PDWORD AccessMask,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI IsValidAcl(PACL pAcl); - WINADVAPI WINBOOL WINAPI InitializeAcl(PACL pAcl,DWORD nAclLength,DWORD dwAclRevision); - WINADVAPI WINBOOL WINAPI GetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); - WINADVAPI WINBOOL WINAPI SetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); - WINADVAPI WINBOOL WINAPI AddAce(PACL pAcl,DWORD dwAceRevision,DWORD dwStartingAceIndex,LPVOID pAceList,DWORD nAceListLength); - WINADVAPI WINBOOL WINAPI DeleteAce(PACL pAcl,DWORD dwAceIndex); - WINADVAPI WINBOOL WINAPI GetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce); - WINADVAPI WINBOOL WINAPI AddAccessAllowedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessAllowedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessDeniedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessDeniedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAuditAccessAce(PACL pAcl,DWORD dwAceRevision,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); - WINADVAPI WINBOOL WINAPI AddAuditAccessAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); - WINADVAPI WINBOOL WINAPI AddAccessAllowedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessDeniedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAuditAccessObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); - WINADVAPI WINBOOL WINAPI FindFirstFreeAce(PACL pAcl,LPVOID *pAce); - WINADVAPI WINBOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD dwRevision); - WINADVAPI WINBOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI DWORD WINAPI GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSECURITY_DESCRIPTOR_CONTROL pControl,LPDWORD lpdwRevision); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bDaclPresent,PACL pDacl,WINBOOL bDaclDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbDaclPresent,PACL *pDacl,LPBOOL lpbDaclDefaulted); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bSaclPresent,PACL pSacl,WINBOOL bSaclDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbSaclPresent,PACL *pSacl,LPBOOL lpbSaclDefaulted); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pOwner,WINBOOL bOwnerDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pOwner,LPBOOL lpbOwnerDefaulted); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pGroup,WINBOOL bGroupDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pGroup,LPBOOL lpbGroupDefaulted); - WINADVAPI DWORD WINAPI SetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); - WINADVAPI DWORD WINAPI GetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); - WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,WINBOOL IsDirectoryObject,HANDLE Token,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI ConvertToAutoInheritPrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CurrentSecurityDescriptor,PSECURITY_DESCRIPTOR *NewSecurityDescriptor,GUID *ObjectType,BOOLEAN IsDirectoryObject,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityEx(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID *ObjectType,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityWithMultipleInheritance(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID **ObjectTypes,ULONG GuidCount,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurity (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,PGENERIC_MAPPING GenericMapping,HANDLE Token); - WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurityEx (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,ULONG AutoInheritFlags,PGENERIC_MAPPING GenericMapping,HANDLE Token); - WINADVAPI WINBOOL WINAPI GetPrivateObjectSecurity(PSECURITY_DESCRIPTOR ObjectDescriptor,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ResultantDescriptor,DWORD DescriptorLength,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI DestroyPrivateObjectSecurity(PSECURITY_DESCRIPTOR *ObjectDescriptor); - WINADVAPI WINBOOL WINAPI MakeSelfRelativeSD(PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferLength); - WINADVAPI WINBOOL WINAPI MakeAbsoluteSD(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,LPDWORD lpdwAbsoluteSecurityDescriptorSize,PACL pDacl,LPDWORD lpdwDaclSize,PACL pSacl,LPDWORD lpdwSaclSize,PSID pOwner,LPDWORD lpdwOwnerSize,PSID pPrimaryGroup,LPDWORD lpdwPrimaryGroupSize); - WINADVAPI WINBOOL WINAPI MakeAbsoluteSD2(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferSize); - WINADVAPI WINBOOL WINAPI SetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI WINBOOL WINAPI SetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI WINBOOL WINAPI GetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); - WINADVAPI WINBOOL WINAPI GetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); - WINADVAPI WINBOOL WINAPI SetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR SecurityDescriptor); - WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationA(LPCSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); - WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationW(LPCWSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); - WINBASEAPI WINBOOL WINAPI FindNextChangeNotification(HANDLE hChangeHandle); - WINBASEAPI WINBOOL WINAPI FindCloseChangeNotification(HANDLE hChangeHandle); - WINBASEAPI WINBOOL WINAPI ReadDirectoryChangesW(HANDLE hDirectory,LPVOID lpBuffer,DWORD nBufferLength,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINBASEAPI WINBOOL WINAPI VirtualLock(LPVOID lpAddress,SIZE_T dwSize); - WINBASEAPI WINBOOL WINAPI VirtualUnlock(LPVOID lpAddress,SIZE_T dwSize); - WINBASEAPI LPVOID WINAPI MapViewOfFileEx(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap,LPVOID lpBaseAddress); - WINBASEAPI WINBOOL WINAPI SetPriorityClass(HANDLE hProcess,DWORD dwPriorityClass); - WINBASEAPI DWORD WINAPI GetPriorityClass(HANDLE hProcess); - WINBASEAPI WINBOOL WINAPI IsBadReadPtr(CONST VOID *lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadWritePtr(LPVOID lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadHugeReadPtr(CONST VOID *lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadHugeWritePtr(LPVOID lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadCodePtr(FARPROC lpfn); - WINBASEAPI WINBOOL WINAPI IsBadStringPtrA(LPCSTR lpsz,UINT_PTR ucchMax); - WINBASEAPI WINBOOL WINAPI IsBadStringPtrW(LPCWSTR lpsz,UINT_PTR ucchMax); - WINADVAPI WINBOOL WINAPI LookupAccountSidA(LPCSTR lpSystemName,PSID Sid,LPSTR Name,LPDWORD cchName,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName,PSID Sid,LPWSTR Name,LPDWORD cchName,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupAccountNameA(LPCSTR lpSystemName,LPCSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupAccountNameW(LPCWSTR lpSystemName,LPCWSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName,LPCSTR lpName,PLUID lpLuid); - WINADVAPI WINBOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName,LPCWSTR lpName,PLUID lpLuid); - WINADVAPI WINBOOL WINAPI LookupPrivilegeNameA(LPCSTR lpSystemName,PLUID lpLuid,LPSTR lpName,LPDWORD cchName); - WINADVAPI WINBOOL WINAPI LookupPrivilegeNameW(LPCWSTR lpSystemName,PLUID lpLuid,LPWSTR lpName,LPDWORD cchName); - WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameA(LPCSTR lpSystemName,LPCSTR lpName,LPSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); - WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameW(LPCWSTR lpSystemName,LPCWSTR lpName,LPWSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); - WINADVAPI WINBOOL WINAPI AllocateLocallyUniqueId(PLUID Luid); - WINBASEAPI WINBOOL WINAPI BuildCommDCBA(LPCSTR lpDef,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI BuildCommDCBW(LPCWSTR lpDef,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsW(LPCWSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI CommConfigDialogA(LPCSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); - WINBASEAPI WINBOOL WINAPI CommConfigDialogW(LPCWSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); - WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); - WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); - WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); - WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); - -#define MAX_COMPUTERNAME_LENGTH 15 - - WINBASEAPI WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI GetComputerNameW(LPWSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI SetComputerNameA(LPCSTR lpComputerName); - WINBASEAPI WINBOOL WINAPI SetComputerNameW(LPCWSTR lpComputerName); - - typedef enum _COMPUTER_NAME_FORMAT { - ComputerNameNetBIOS,ComputerNameDnsHostname,ComputerNameDnsDomain,ComputerNameDnsFullyQualified,ComputerNamePhysicalNetBIOS,ComputerNamePhysicalDnsHostname,ComputerNamePhysicalDnsDomain,ComputerNamePhysicalDnsFullyQualified,ComputerNameMax - } COMPUTER_NAME_FORMAT; - - WINBASEAPI WINBOOL WINAPI GetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI GetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPWSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI SetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPCSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI SetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPCWSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameA(LPCSTR Hostname,LPSTR ComputerName,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameW(LPCWSTR Hostname,LPWSTR ComputerName,LPDWORD nSize); - WINADVAPI WINBOOL WINAPI GetUserNameA(LPSTR lpBuffer,LPDWORD pcbBuffer); - WINADVAPI WINBOOL WINAPI GetUserNameW(LPWSTR lpBuffer,LPDWORD pcbBuffer); - -#define LOGON32_LOGON_INTERACTIVE 2 -#define LOGON32_LOGON_NETWORK 3 -#define LOGON32_LOGON_BATCH 4 -#define LOGON32_LOGON_SERVICE 5 -#define LOGON32_LOGON_UNLOCK 7 -#define LOGON32_LOGON_NETWORK_CLEARTEXT 8 -#define LOGON32_LOGON_NEW_CREDENTIALS 9 - -#define LOGON32_PROVIDER_DEFAULT 0 -#define LOGON32_PROVIDER_WINNT35 1 -#define LOGON32_PROVIDER_WINNT40 2 -#define LOGON32_PROVIDER_WINNT50 3 - -#ifdef UNICODE -#define LogonUser LogonUserW -#define LogonUserEx LogonUserExW -#define CreateProcessAsUser CreateProcessAsUserW -#else -#define LogonUser LogonUserA -#define LogonUserEx LogonUserExA -#define CreateProcessAsUser CreateProcessAsUserA -#endif - - WINADVAPI WINBOOL WINAPI LogonUserA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); - WINADVAPI WINBOOL WINAPI LogonUserW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); - WINADVAPI WINBOOL WINAPI LogonUserExA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); - WINADVAPI WINBOOL WINAPI LogonUserExW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); - WINADVAPI WINBOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken); - WINADVAPI WINBOOL WINAPI CreateProcessAsUserA(HANDLE hToken,LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINADVAPI WINBOOL WINAPI CreateProcessAsUserW(HANDLE hToken,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - -#define LOGON_WITH_PROFILE 0x1 -#define LOGON_NETCREDENTIALS_ONLY 0x2 -#define LOGON_ZERO_PASSWORD_BUFFER 0x80000000 - - WINADVAPI WINBOOL WINAPI CreateProcessWithLogonW(LPCWSTR lpUsername,LPCWSTR lpDomain,LPCWSTR lpPassword,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINADVAPI WINBOOL WINAPI CreateProcessWithTokenW(HANDLE hToken,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINADVAPI WINBOOL WINAPI ImpersonateAnonymousToken(HANDLE ThreadHandle); - WINADVAPI WINBOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken,DWORD dwDesiredAccess,LPSECURITY_ATTRIBUTES lpTokenAttributes,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,TOKEN_TYPE TokenType,PHANDLE phNewToken); - WINADVAPI WINBOOL WINAPI CreateRestrictedToken(HANDLE ExistingTokenHandle,DWORD Flags,DWORD DisableSidCount,PSID_AND_ATTRIBUTES SidsToDisable,DWORD DeletePrivilegeCount,PLUID_AND_ATTRIBUTES PrivilegesToDelete,DWORD RestrictedSidCount,PSID_AND_ATTRIBUTES SidsToRestrict,PHANDLE NewTokenHandle); - WINADVAPI WINBOOL WINAPI IsTokenRestricted(HANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI IsTokenUntrusted(HANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI CheckTokenMembership(HANDLE TokenHandle,PSID SidToCheck,PBOOL IsMember); - - typedef WAITORTIMERCALLBACKFUNC WAITORTIMERCALLBACK; - - WINBASEAPI WINBOOL WINAPI RegisterWaitForSingleObject(PHANDLE phNewWaitObject,HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); - WINBASEAPI HANDLE WINAPI RegisterWaitForSingleObjectEx(HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); - WINBASEAPI WINBOOL WINAPI UnregisterWait(HANDLE WaitHandle); - WINBASEAPI WINBOOL WINAPI UnregisterWaitEx(HANDLE WaitHandle,HANDLE CompletionEvent); - WINBASEAPI WINBOOL WINAPI QueueUserWorkItem(LPTHREAD_START_ROUTINE Function,PVOID Context,ULONG Flags); - WINBASEAPI WINBOOL WINAPI BindIoCompletionCallback(HANDLE FileHandle,LPOVERLAPPED_COMPLETION_ROUTINE Function,ULONG Flags); - WINBASEAPI HANDLE WINAPI CreateTimerQueue(VOID); - WINBASEAPI WINBOOL WINAPI CreateTimerQueueTimer(PHANDLE phNewTimer,HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,ULONG Flags); - WINBASEAPI WINBOOL WINAPI ChangeTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,ULONG DueTime,ULONG Period); - WINBASEAPI WINBOOL WINAPI DeleteTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,HANDLE CompletionEvent); - WINBASEAPI WINBOOL WINAPI DeleteTimerQueueEx(HANDLE TimerQueue,HANDLE CompletionEvent); - WINBASEAPI HANDLE WINAPI SetTimerQueueTimer(HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,WINBOOL PreferIo); - WINBASEAPI WINBOOL WINAPI CancelTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer); - WINBASEAPI WINBOOL WINAPI DeleteTimerQueue(HANDLE TimerQueue); - -#define HW_PROFILE_GUIDLEN 39 -#define MAX_PROFILE_LEN 80 - -#define DOCKINFO_UNDOCKED (0x1) -#define DOCKINFO_DOCKED (0x2) -#define DOCKINFO_USER_SUPPLIED (0x4) -#define DOCKINFO_USER_UNDOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_UNDOCKED) -#define DOCKINFO_USER_DOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_DOCKED) - - typedef struct tagHW_PROFILE_INFOA { - DWORD dwDockInfo; - CHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; - CHAR szHwProfileName[MAX_PROFILE_LEN]; - } HW_PROFILE_INFOA,*LPHW_PROFILE_INFOA; - - typedef struct tagHW_PROFILE_INFOW { - DWORD dwDockInfo; - WCHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; - WCHAR szHwProfileName[MAX_PROFILE_LEN]; - } HW_PROFILE_INFOW,*LPHW_PROFILE_INFOW; - -#ifdef UNICODE - typedef HW_PROFILE_INFOW HW_PROFILE_INFO; - typedef LPHW_PROFILE_INFOW LPHW_PROFILE_INFO; -#else - typedef HW_PROFILE_INFOA HW_PROFILE_INFO; - typedef LPHW_PROFILE_INFOA LPHW_PROFILE_INFO; -#endif - -#ifdef UNICODE -#define GetCurrentHwProfile GetCurrentHwProfileW -#define GetVersionEx GetVersionExW -#define VerifyVersionInfo VerifyVersionInfoW -#else -#define GetCurrentHwProfile GetCurrentHwProfileA -#define GetVersionEx GetVersionExA -#define VerifyVersionInfo VerifyVersionInfoA -#endif - - WINADVAPI WINBOOL WINAPI GetCurrentHwProfileA (LPHW_PROFILE_INFOA lpHwProfileInfo); - WINADVAPI WINBOOL WINAPI GetCurrentHwProfileW (LPHW_PROFILE_INFOW lpHwProfileInfo); - WINBASEAPI WINBOOL WINAPI QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); - WINBASEAPI WINBOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); - WINBASEAPI WINBOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation); - WINBASEAPI WINBOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation); - WINBASEAPI WINBOOL WINAPI VerifyVersionInfoA(LPOSVERSIONINFOEXA lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); - WINBASEAPI WINBOOL WINAPI VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); - -#include - -#define TC_NORMAL 0 -#define TC_HARDERR 1 -#define TC_GP_TRAP 2 -#define TC_SIGNAL 3 - -#define AC_LINE_OFFLINE 0x0 -#define AC_LINE_ONLINE 0x1 -#define AC_LINE_BACKUP_POWER 0x2 -#define AC_LINE_UNKNOWN 0xff - -#define BATTERY_FLAG_HIGH 0x1 -#define BATTERY_FLAG_LOW 0x2 -#define BATTERY_FLAG_CRITICAL 0x4 -#define BATTERY_FLAG_CHARGING 0x8 -#define BATTERY_FLAG_NO_BATTERY 0x80 -#define BATTERY_FLAG_UNKNOWN 0xff - -#define BATTERY_PERCENTAGE_UNKNOWN 0xff - -#define BATTERY_LIFE_UNKNOWN 0xffffffff - - typedef struct _SYSTEM_POWER_STATUS { - BYTE ACLineStatus; - BYTE BatteryFlag; - BYTE BatteryLifePercent; - BYTE Reserved1; - DWORD BatteryLifeTime; - DWORD BatteryFullLifeTime; - } SYSTEM_POWER_STATUS,*LPSYSTEM_POWER_STATUS; - -#ifdef UNICODE -#define CreateJobObject CreateJobObjectW -#define OpenJobObject OpenJobObjectW -#define FindFirstVolume FindFirstVolumeW -#define FindNextVolume FindNextVolumeW -#define FindFirstVolumeMountPoint FindFirstVolumeMountPointW -#define FindNextVolumeMountPoint FindNextVolumeMountPointW -#define SetVolumeMountPoint SetVolumeMountPointW -#define DeleteVolumeMountPoint DeleteVolumeMountPointW -#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointW -#define GetVolumePathName GetVolumePathNameW -#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameW -#else -#define CreateJobObject CreateJobObjectA -#define OpenJobObject OpenJobObjectA -#define FindFirstVolume FindFirstVolumeA -#define FindNextVolume FindNextVolumeA -#define FindFirstVolumeMountPoint FindFirstVolumeMountPointA -#define FindNextVolumeMountPoint FindNextVolumeMountPointA -#define SetVolumeMountPoint SetVolumeMountPointA -#define DeleteVolumeMountPoint DeleteVolumeMountPointA -#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointA -#define GetVolumePathName GetVolumePathNameA -#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameA -#endif - - WINBOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS lpSystemPowerStatus); - WINBOOL WINAPI SetSystemPowerState(WINBOOL fSuspend,WINBOOL fForce); - WINBASEAPI WINBOOL WINAPI AllocateUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI WINBOOL WINAPI FreeUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI WINBOOL WINAPI MapUserPhysicalPages(PVOID VirtualAddress,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI WINBOOL WINAPI MapUserPhysicalPagesScatter(PVOID *VirtualAddresses,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI HANDLE WINAPI CreateJobObjectA(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateJobObjectW(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenJobObjectA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenJobObjectW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI WINBOOL WINAPI AssignProcessToJobObject(HANDLE hJob,HANDLE hProcess); - WINBASEAPI WINBOOL WINAPI TerminateJobObject(HANDLE hJob,UINT uExitCode); - WINBASEAPI WINBOOL WINAPI QueryInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength,LPDWORD lpReturnLength); - WINBASEAPI WINBOOL WINAPI SetInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength); - WINBASEAPI WINBOOL WINAPI IsProcessInJob(HANDLE ProcessHandle,HANDLE JobHandle,PBOOL Result); - WINBASEAPI WINBOOL WINAPI CreateJobSet(ULONG NumJob,PJOB_SET_ARRAY UserJobSet,ULONG Flags); - WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); - WINBASEAPI ULONG WINAPI RemoveVectoredExceptionHandler(PVOID Handle); - WINBASEAPI PVOID WINAPI AddVectoredContinueHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); - WINBASEAPI ULONG WINAPI RemoveVectoredContinueHandler(PVOID Handle); - WINBASEAPI HANDLE WINAPI FindFirstVolumeA(LPSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI HANDLE WINAPI FindFirstVolumeW(LPWSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeA(HANDLE hFindVolume,LPSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeW(HANDLE hFindVolume,LPWSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindVolumeClose(HANDLE hFindVolume); - WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointA(LPCSTR lpszRootPathName,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointW(LPCWSTR lpszRootPathName,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointA(HANDLE hFindVolumeMountPoint,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointW(HANDLE hFindVolumeMountPoint,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindVolumeMountPointClose(HANDLE hFindVolumeMountPoint); - WINBASEAPI WINBOOL WINAPI SetVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPCSTR lpszVolumeName); - WINBASEAPI WINBOOL WINAPI SetVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPCWSTR lpszVolumeName); - WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointA(LPCSTR lpszVolumeMountPoint); - WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointW(LPCWSTR lpszVolumeMountPoint); - WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPWSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNameA(LPCSTR lpszFileName,LPSTR lpszVolumePathName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNameW(LPCWSTR lpszFileName,LPWSTR lpszVolumePathName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameA(LPCSTR lpszVolumeName,LPCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameW(LPCWSTR lpszVolumeName,LPWCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); - -#define ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID 0x1 -#define ACTCTX_FLAG_LANGID_VALID 0x2 -#define ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID 0x4 -#define ACTCTX_FLAG_RESOURCE_NAME_VALID 0x8 -#define ACTCTX_FLAG_SET_PROCESS_DEFAULT 0x10 -#define ACTCTX_FLAG_APPLICATION_NAME_VALID 0x20 -#define ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF 0x40 -#define ACTCTX_FLAG_HMODULE_VALID 0x80 - - typedef struct tagACTCTXA { - ULONG cbSize; - DWORD dwFlags; - LPCSTR lpSource; - USHORT wProcessorArchitecture; - LANGID wLangId; - LPCSTR lpAssemblyDirectory; - LPCSTR lpResourceName; - LPCSTR lpApplicationName; - HMODULE hModule; - } ACTCTXA,*PACTCTXA; - - typedef struct tagACTCTXW { - ULONG cbSize; - DWORD dwFlags; - LPCWSTR lpSource; - USHORT wProcessorArchitecture; - LANGID wLangId; - LPCWSTR lpAssemblyDirectory; - LPCWSTR lpResourceName; - LPCWSTR lpApplicationName; - HMODULE hModule; - } ACTCTXW,*PACTCTXW; - - typedef const ACTCTXA *PCACTCTXA; - typedef const ACTCTXW *PCACTCTXW; - -#ifdef UNICODE - typedef ACTCTXW ACTCTX; - typedef PACTCTXW PACTCTX; - typedef PCACTCTXW PCACTCTX; -#else - typedef ACTCTXA ACTCTX; - typedef PACTCTXA PACTCTX; - typedef PCACTCTXA PCACTCTX; -#endif - -#ifdef UNICODE -#define CreateActCtx CreateActCtxW -#else -#define CreateActCtx CreateActCtxA -#endif - - WINBASEAPI HANDLE WINAPI CreateActCtxA(PCACTCTXA pActCtx); - WINBASEAPI HANDLE WINAPI CreateActCtxW(PCACTCTXW pActCtx); - WINBASEAPI VOID WINAPI AddRefActCtx(HANDLE hActCtx); - WINBASEAPI VOID WINAPI ReleaseActCtx(HANDLE hActCtx); - WINBASEAPI WINBOOL WINAPI ZombifyActCtx(HANDLE hActCtx); - WINBASEAPI WINBOOL WINAPI ActivateActCtx(HANDLE hActCtx,ULONG_PTR *lpCookie); - -#define DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION (0x1) - - WINBASEAPI WINBOOL WINAPI DeactivateActCtx(DWORD dwFlags,ULONG_PTR ulCookie); - WINBASEAPI WINBOOL WINAPI GetCurrentActCtx(HANDLE *lphActCtx); - - typedef struct tagACTCTX_SECTION_KEYED_DATA_2600 { - ULONG cbSize; - ULONG ulDataFormatVersion; - PVOID lpData; - ULONG ulLength; - PVOID lpSectionGlobalData; - ULONG ulSectionGlobalDataLength; - PVOID lpSectionBase; - ULONG ulSectionTotalLength; - HANDLE hActCtx; - ULONG ulAssemblyRosterIndex; - } ACTCTX_SECTION_KEYED_DATA_2600,*PACTCTX_SECTION_KEYED_DATA_2600; - - typedef const ACTCTX_SECTION_KEYED_DATA_2600 *PCACTCTX_SECTION_KEYED_DATA_2600; - - typedef struct tagACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA { - PVOID lpInformation; - PVOID lpSectionBase; - ULONG ulSectionLength; - PVOID lpSectionGlobalDataBase; - ULONG ulSectionGlobalDataLength; - } ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA,*PACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; - - typedef const ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA *PCACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; - - typedef struct tagACTCTX_SECTION_KEYED_DATA { - ULONG cbSize; - ULONG ulDataFormatVersion; - PVOID lpData; - ULONG ulLength; - PVOID lpSectionGlobalData; - ULONG ulSectionGlobalDataLength; - PVOID lpSectionBase; - ULONG ulSectionTotalLength; - HANDLE hActCtx; - ULONG ulAssemblyRosterIndex; - - ULONG ulFlags; - ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA AssemblyMetadata; - } ACTCTX_SECTION_KEYED_DATA,*PACTCTX_SECTION_KEYED_DATA; - - typedef const ACTCTX_SECTION_KEYED_DATA *PCACTCTX_SECTION_KEYED_DATA; - -#define FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX 0x1 -#define FIND_ACTCTX_SECTION_KEY_RETURN_FLAGS 0x2 -#define FIND_ACTCTX_SECTION_KEY_RETURN_ASSEMBLY_METADATA 0x4 - -#ifdef UNICODE -#define FindActCtxSectionString FindActCtxSectionStringW -#else -#define FindActCtxSectionString FindActCtxSectionStringA -#endif - - WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringA(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); - WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCWSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); - WINBASEAPI WINBOOL WINAPI FindActCtxSectionGuid(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,const GUID *lpGuidToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); - -#ifndef RC_INVOKED -#ifndef ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED - - typedef struct _ACTIVATION_CONTEXT_BASIC_INFORMATION { - HANDLE hActCtx; - DWORD dwFlags; - } ACTIVATION_CONTEXT_BASIC_INFORMATION,*PACTIVATION_CONTEXT_BASIC_INFORMATION; - - typedef const struct _ACTIVATION_CONTEXT_BASIC_INFORMATION *PCACTIVATION_CONTEXT_BASIC_INFORMATION; - -#define ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED 1 -#endif -#endif - -#define QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX 0x4 -#define QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE 0x8 -#define QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS 0x10 -#define QUERY_ACTCTX_FLAG_NO_ADDREF 0x80000000 - - WINBASEAPI WINBOOL WINAPI QueryActCtxW(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); - - typedef WINBOOL (WINAPI *PQUERYACTCTXW_FUNC)(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); - - WINBASEAPI WINBOOL WINAPI ProcessIdToSessionId(DWORD dwProcessId,DWORD *pSessionId); - WINBASEAPI DWORD WINAPI WTSGetActiveConsoleSessionId(); - WINBASEAPI WINBOOL WINAPI IsWow64Process(HANDLE hProcess,PBOOL Wow64Process); - WINBASEAPI WINBOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer,PDWORD ReturnedLength); - WINBASEAPI WINBOOL WINAPI GetNumaHighestNodeNumber(PULONG HighestNodeNumber); - WINBASEAPI WINBOOL WINAPI GetNumaProcessorNode(UCHAR Processor,PUCHAR NodeNumber); - WINBASEAPI WINBOOL WINAPI GetNumaNodeProcessorMask(UCHAR Node,PULONGLONG ProcessorMask); - WINBASEAPI WINBOOL WINAPI GetNumaAvailableMemoryNode(UCHAR Node,PULONGLONG AvailableBytes); - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINBASE_ +#define _WINBASE_ + +#define WINADVAPI DECLSPEC_IMPORT +#define WINBASEAPI DECLSPEC_IMPORT +#define ZAWPROXYAPI DECLSPEC_IMPORT + +#ifdef __cplusplus +extern "C" { +#endif + +#define DefineHandleTable(w) ((w),TRUE) +#define LimitEmsPages(dw) +#define SetSwapAreaSize(w) (w) +#define LockSegment(w) GlobalFix((HANDLE)(w)) +#define UnlockSegment(w) GlobalUnfix((HANDLE)(w)) +#define GetCurrentTime() GetTickCount() + +#define Yield() + +#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) +#define INVALID_FILE_SIZE ((DWORD)0xffffffff) +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) + +#define FILE_BEGIN 0 +#define FILE_CURRENT 1 +#define FILE_END 2 + +#define TIME_ZONE_ID_INVALID ((DWORD)0xffffffff) + +#define WAIT_FAILED ((DWORD)0xffffffff) +#define WAIT_OBJECT_0 ((STATUS_WAIT_0) + 0) +#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0) + 0) +#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0) + 0) +#define WAIT_IO_COMPLETION STATUS_USER_APC +#define STILL_ACTIVE STATUS_PENDING +#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION +#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT +#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT +#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP +#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED +#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND +#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO +#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT +#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION +#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW +#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK +#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW +#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO +#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW +#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION +#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR +#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION +#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION +#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW +#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION +#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION +#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE +#define EXCEPTION_POSSIBLE_DEADLOCK STATUS_POSSIBLE_DEADLOCK +#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT +#define MoveMemory RtlMoveMemory +#define CopyMemory RtlCopyMemory +#define FillMemory RtlFillMemory +#define ZeroMemory RtlZeroMemory +#define SecureZeroMemory RtlSecureZeroMemory + +#define FILE_FLAG_WRITE_THROUGH 0x80000000 +#define FILE_FLAG_OVERLAPPED 0x40000000 +#define FILE_FLAG_NO_BUFFERING 0x20000000 +#define FILE_FLAG_RANDOM_ACCESS 0x10000000 +#define FILE_FLAG_SEQUENTIAL_SCAN 0x8000000 +#define FILE_FLAG_DELETE_ON_CLOSE 0x4000000 +#define FILE_FLAG_BACKUP_SEMANTICS 0x2000000 +#define FILE_FLAG_POSIX_SEMANTICS 0x1000000 +#define FILE_FLAG_OPEN_REPARSE_POINT 0x200000 +#define FILE_FLAG_OPEN_NO_RECALL 0x100000 +#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x80000 + +#define CREATE_NEW 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define OPEN_ALWAYS 4 +#define TRUNCATE_EXISTING 5 + +#define PROGRESS_CONTINUE 0 +#define PROGRESS_CANCEL 1 +#define PROGRESS_STOP 2 +#define PROGRESS_QUIET 3 + +#define CALLBACK_CHUNK_FINISHED 0x0 +#define CALLBACK_STREAM_SWITCH 0x1 + +#define COPY_FILE_FAIL_IF_EXISTS 0x1 +#define COPY_FILE_RESTARTABLE 0x2 +#define COPY_FILE_OPEN_SOURCE_FOR_WRITE 0x4 +#define COPY_FILE_ALLOW_DECRYPTED_DESTINATION 0x8 + +#define REPLACEFILE_WRITE_THROUGH 0x1 +#define REPLACEFILE_IGNORE_MERGE_ERRORS 0x2 + +#define PIPE_ACCESS_INBOUND 0x1 +#define PIPE_ACCESS_OUTBOUND 0x2 +#define PIPE_ACCESS_DUPLEX 0x3 + +#define PIPE_CLIENT_END 0x0 +#define PIPE_SERVER_END 0x1 + +#define PIPE_WAIT 0x0 +#define PIPE_NOWAIT 0x1 +#define PIPE_READMODE_BYTE 0x0 +#define PIPE_READMODE_MESSAGE 0x2 +#define PIPE_TYPE_BYTE 0x0 +#define PIPE_TYPE_MESSAGE 0x4 + +#define PIPE_UNLIMITED_INSTANCES 255 + +#define SECURITY_ANONYMOUS (SecurityAnonymous << 16) +#define SECURITY_IDENTIFICATION (SecurityIdentification << 16) +#define SECURITY_IMPERSONATION (SecurityImpersonation << 16) +#define SECURITY_DELEGATION (SecurityDelegation << 16) + +#define SECURITY_CONTEXT_TRACKING 0x40000 +#define SECURITY_EFFECTIVE_ONLY 0x80000 + +#define SECURITY_SQOS_PRESENT 0x100000 +#define SECURITY_VALID_SQOS_FLAGS 0x1f0000 + + typedef struct _OVERLAPPED { + ULONG_PTR Internal; + ULONG_PTR InternalHigh; + union { + struct { + DWORD Offset; + DWORD OffsetHigh; + }; + PVOID Pointer; + }; + HANDLE hEvent; + } OVERLAPPED,*LPOVERLAPPED; + + typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + LPVOID lpSecurityDescriptor; + WINBOOL bInheritHandle; + } SECURITY_ATTRIBUTES,*PSECURITY_ATTRIBUTES,*LPSECURITY_ATTRIBUTES; + + typedef struct _PROCESS_INFORMATION { + HANDLE hProcess; + HANDLE hThread; + DWORD dwProcessId; + DWORD dwThreadId; + } PROCESS_INFORMATION,*PPROCESS_INFORMATION,*LPPROCESS_INFORMATION; + +#ifndef _FILETIME_ +#define _FILETIME_ + typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; + } FILETIME,*PFILETIME,*LPFILETIME; +#endif + + typedef struct _SYSTEMTIME { + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; + } SYSTEMTIME,*PSYSTEMTIME,*LPSYSTEMTIME; + + typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); + typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; + typedef VOID (WINAPI *PFIBER_START_ROUTINE)(LPVOID lpFiberParameter); + typedef PFIBER_START_ROUTINE LPFIBER_START_ROUTINE; + + typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; + typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION; + typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION; + typedef RTL_CRITICAL_SECTION_DEBUG CRITICAL_SECTION_DEBUG; + typedef PRTL_CRITICAL_SECTION_DEBUG PCRITICAL_SECTION_DEBUG; + typedef PRTL_CRITICAL_SECTION_DEBUG LPCRITICAL_SECTION_DEBUG; + + WINBASEAPI PVOID WINAPI EncodePointer(PVOID Ptr); + WINBASEAPI PVOID WINAPI DecodePointer(PVOID Ptr); + WINBASEAPI PVOID WINAPI EncodeSystemPointer(PVOID Ptr); + WINBASEAPI PVOID WINAPI DecodeSystemPointer(PVOID Ptr); + +#ifdef I_X86_ + typedef PLDT_ENTRY LPLDT_ENTRY; +#else + typedef LPVOID LPLDT_ENTRY; +#endif + +#define MUTEX_MODIFY_STATE MUTANT_QUERY_STATE +#define MUTEX_ALL_ACCESS MUTANT_ALL_ACCESS + +#define SP_SERIALCOMM ((DWORD)0x1) + +#define PST_UNSPECIFIED ((DWORD)0x0) +#define PST_RS232 ((DWORD)0x1) +#define PST_PARALLELPORT ((DWORD)0x2) +#define PST_RS422 ((DWORD)0x3) +#define PST_RS423 ((DWORD)0x4) +#define PST_RS449 ((DWORD)0x5) +#define PST_MODEM ((DWORD)0x6) +#define PST_FAX ((DWORD)0x21) +#define PST_SCANNER ((DWORD)0x22) +#define PST_NETWORK_BRIDGE ((DWORD)0x100) +#define PST_LAT ((DWORD)0x101) +#define PST_TCPIP_TELNET ((DWORD)0x102) +#define PST_X25 ((DWORD)0x103) + +#define PCF_DTRDSR ((DWORD)0x1) +#define PCF_RTSCTS ((DWORD)0x2) +#define PCF_RLSD ((DWORD)0x4) +#define PCF_PARITY_CHECK ((DWORD)0x8) +#define PCF_XONXOFF ((DWORD)0x10) +#define PCF_SETXCHAR ((DWORD)0x20) +#define PCF_TOTALTIMEOUTS ((DWORD)0x40) +#define PCF_INTTIMEOUTS ((DWORD)0x80) +#define PCF_SPECIALCHARS ((DWORD)0x100) +#define PCF_16BITMODE ((DWORD)0x200) + +#define SP_PARITY ((DWORD)0x1) +#define SP_BAUD ((DWORD)0x2) +#define SP_DATABITS ((DWORD)0x4) +#define SP_STOPBITS ((DWORD)0x8) +#define SP_HANDSHAKING ((DWORD)0x10) +#define SP_PARITY_CHECK ((DWORD)0x20) +#define SP_RLSD ((DWORD)0x40) + +#define BAUD_075 ((DWORD)0x1) +#define BAUD_110 ((DWORD)0x2) +#define BAUD_134_5 ((DWORD)0x4) +#define BAUD_150 ((DWORD)0x8) +#define BAUD_300 ((DWORD)0x10) +#define BAUD_600 ((DWORD)0x20) +#define BAUD_1200 ((DWORD)0x40) +#define BAUD_1800 ((DWORD)0x80) +#define BAUD_2400 ((DWORD)0x100) +#define BAUD_4800 ((DWORD)0x200) +#define BAUD_7200 ((DWORD)0x400) +#define BAUD_9600 ((DWORD)0x800) +#define BAUD_14400 ((DWORD)0x1000) +#define BAUD_19200 ((DWORD)0x2000) +#define BAUD_38400 ((DWORD)0x4000) +#define BAUD_56K ((DWORD)0x8000) +#define BAUD_128K ((DWORD)0x10000) +#define BAUD_115200 ((DWORD)0x20000) +#define BAUD_57600 ((DWORD)0x40000) +#define BAUD_USER ((DWORD)0x10000000) + +#define DATABITS_5 ((WORD)0x1) +#define DATABITS_6 ((WORD)0x2) +#define DATABITS_7 ((WORD)0x4) +#define DATABITS_8 ((WORD)0x8) +#define DATABITS_16 ((WORD)0x10) +#define DATABITS_16X ((WORD)0x20) + +#define STOPBITS_10 ((WORD)0x1) +#define STOPBITS_15 ((WORD)0x2) +#define STOPBITS_20 ((WORD)0x4) +#define PARITY_NONE ((WORD)0x100) +#define PARITY_ODD ((WORD)0x200) +#define PARITY_EVEN ((WORD)0x400) +#define PARITY_MARK ((WORD)0x800) +#define PARITY_SPACE ((WORD)0x1000) + + typedef struct _COMMPROP { + WORD wPacketLength; + WORD wPacketVersion; + DWORD dwServiceMask; + DWORD dwReserved1; + DWORD dwMaxTxQueue; + DWORD dwMaxRxQueue; + DWORD dwMaxBaud; + DWORD dwProvSubType; + DWORD dwProvCapabilities; + DWORD dwSettableParams; + DWORD dwSettableBaud; + WORD wSettableData; + WORD wSettableStopParity; + DWORD dwCurrentTxQueue; + DWORD dwCurrentRxQueue; + DWORD dwProvSpec1; + DWORD dwProvSpec2; + WCHAR wcProvChar[1]; + } COMMPROP,*LPCOMMPROP; + +#define COMMPROP_INITIALIZED ((DWORD)0xE73CF52E) + + typedef struct _COMSTAT { + DWORD fCtsHold : 1; + DWORD fDsrHold : 1; + DWORD fRlsdHold : 1; + DWORD fXoffHold : 1; + DWORD fXoffSent : 1; + DWORD fEof : 1; + DWORD fTxim : 1; + DWORD fReserved : 25; + DWORD cbInQue; + DWORD cbOutQue; + } COMSTAT,*LPCOMSTAT; + +#define DTR_CONTROL_DISABLE 0x0 +#define DTR_CONTROL_ENABLE 0x1 +#define DTR_CONTROL_HANDSHAKE 0x2 + +#define RTS_CONTROL_DISABLE 0x0 +#define RTS_CONTROL_ENABLE 0x1 +#define RTS_CONTROL_HANDSHAKE 0x2 +#define RTS_CONTROL_TOGGLE 0x3 + + typedef struct _DCB { + DWORD DCBlength; + DWORD BaudRate; + DWORD fBinary: 1; + DWORD fParity: 1; + DWORD fOutxCtsFlow:1; + DWORD fOutxDsrFlow:1; + DWORD fDtrControl:2; + DWORD fDsrSensitivity:1; + DWORD fTXContinueOnXoff: 1; + DWORD fOutX: 1; + DWORD fInX: 1; + DWORD fErrorChar: 1; + DWORD fNull: 1; + DWORD fRtsControl:2; + DWORD fAbortOnError:1; + DWORD fDummy2:17; + WORD wReserved; + WORD XonLim; + WORD XoffLim; + BYTE ByteSize; + BYTE Parity; + BYTE StopBits; + char XonChar; + char XoffChar; + char ErrorChar; + char EofChar; + char EvtChar; + WORD wReserved1; + } DCB,*LPDCB; + + typedef struct _COMMTIMEOUTS { + DWORD ReadIntervalTimeout; + DWORD ReadTotalTimeoutMultiplier; + DWORD ReadTotalTimeoutConstant; + DWORD WriteTotalTimeoutMultiplier; + DWORD WriteTotalTimeoutConstant; + } COMMTIMEOUTS,*LPCOMMTIMEOUTS; + + typedef struct _COMMCONFIG { + DWORD dwSize; + WORD wVersion; + WORD wReserved; + DCB dcb; + DWORD dwProviderSubType; + DWORD dwProviderOffset; + DWORD dwProviderSize; + WCHAR wcProviderData[1]; + } COMMCONFIG,*LPCOMMCONFIG; + + typedef struct _SYSTEM_INFO { + union { + DWORD dwOemId; + struct { + WORD wProcessorArchitecture; + WORD wReserved; + }; + }; + DWORD dwPageSize; + LPVOID lpMinimumApplicationAddress; + LPVOID lpMaximumApplicationAddress; + DWORD_PTR dwActiveProcessorMask; + DWORD dwNumberOfProcessors; + DWORD dwProcessorType; + DWORD dwAllocationGranularity; + WORD wProcessorLevel; + WORD wProcessorRevision; + } SYSTEM_INFO,*LPSYSTEM_INFO; + +#define FreeModule(hLibModule) FreeLibrary((hLibModule)) +#define MakeProcInstance(lpProc,hInstance) (lpProc) +#define FreeProcInstance(lpProc) (lpProc) + +#define GMEM_FIXED 0x0 +#define GMEM_MOVEABLE 0x2 +#define GMEM_NOCOMPACT 0x10 +#define GMEM_NODISCARD 0x20 +#define GMEM_ZEROINIT 0x40 +#define GMEM_MODIFY 0x80 +#define GMEM_DISCARDABLE 0x100 +#define GMEM_NOT_BANKED 0x1000 +#define GMEM_SHARE 0x2000 +#define GMEM_DDESHARE 0x2000 +#define GMEM_NOTIFY 0x4000 +#define GMEM_LOWER GMEM_NOT_BANKED +#define GMEM_VALID_FLAGS 0x7F72 +#define GMEM_INVALID_HANDLE 0x8000 + +#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT) +#define GPTR (GMEM_FIXED | GMEM_ZEROINIT) + +#define GlobalLRUNewest(h) ((HANDLE)(h)) +#define GlobalLRUOldest(h) ((HANDLE)(h)) +#define GlobalDiscard(h) GlobalReAlloc((h),0,GMEM_MOVEABLE) + +#define GMEM_DISCARDED 0x4000 +#define GMEM_LOCKCOUNT 0xff + + typedef struct _MEMORYSTATUS { + DWORD dwLength; + DWORD dwMemoryLoad; + SIZE_T dwTotalPhys; + SIZE_T dwAvailPhys; + SIZE_T dwTotalPageFile; + SIZE_T dwAvailPageFile; + SIZE_T dwTotalVirtual; + SIZE_T dwAvailVirtual; + } MEMORYSTATUS,*LPMEMORYSTATUS; + +#define LMEM_FIXED 0x0 +#define LMEM_MOVEABLE 0x2 +#define LMEM_NOCOMPACT 0x10 +#define LMEM_NODISCARD 0x20 +#define LMEM_ZEROINIT 0x40 +#define LMEM_MODIFY 0x80 +#define LMEM_DISCARDABLE 0xf00 +#define LMEM_VALID_FLAGS 0xf72 +#define LMEM_INVALID_HANDLE 0x8000 + +#define LHND (LMEM_MOVEABLE | LMEM_ZEROINIT) +#define LPTR (LMEM_FIXED | LMEM_ZEROINIT) + +#define NONZEROLHND (LMEM_MOVEABLE) +#define NONZEROLPTR (LMEM_FIXED) + +#define LocalDiscard(h) LocalReAlloc((h),0,LMEM_MOVEABLE) + +#define LMEM_DISCARDED 0x4000 +#define LMEM_LOCKCOUNT 0xff + +#define DEBUG_PROCESS 0x1 +#define DEBUG_ONLY_THIS_PROCESS 0x2 +#define CREATE_SUSPENDED 0x4 +#define DETACHED_PROCESS 0x8 +#define CREATE_NEW_CONSOLE 0x10 +#define NORMAL_PRIORITY_CLASS 0x20 +#define IDLE_PRIORITY_CLASS 0x40 +#define HIGH_PRIORITY_CLASS 0x80 +#define REALTIME_PRIORITY_CLASS 0x100 +#define CREATE_NEW_PROCESS_GROUP 0x200 +#define CREATE_UNICODE_ENVIRONMENT 0x400 +#define CREATE_SEPARATE_WOW_VDM 0x800 +#define CREATE_SHARED_WOW_VDM 0x1000 +#define CREATE_FORCEDOS 0x2000 +#define BELOW_NORMAL_PRIORITY_CLASS 0x4000 +#define ABOVE_NORMAL_PRIORITY_CLASS 0x8000 +#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x10000 + +#define CREATE_BREAKAWAY_FROM_JOB 0x1000000 +#define CREATE_PRESERVE_CODE_AUTHZ_LEVEL 0x2000000 + +#define CREATE_DEFAULT_ERROR_MODE 0x4000000 +#define CREATE_NO_WINDOW 0x8000000 + +#define PROFILE_USER 0x10000000 +#define PROFILE_KERNEL 0x20000000 +#define PROFILE_SERVER 0x40000000 + +#define CREATE_IGNORE_SYSTEM_DEFAULT 0x80000000 + +#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN +#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1) +#define THREAD_PRIORITY_NORMAL 0 +#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX +#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1) +#define THREAD_PRIORITY_ERROR_RETURN (MAXLONG) + +#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT +#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE + +#define EXCEPTION_DEBUG_EVENT 1 +#define CREATE_THREAD_DEBUG_EVENT 2 +#define CREATE_PROCESS_DEBUG_EVENT 3 +#define EXIT_THREAD_DEBUG_EVENT 4 +#define EXIT_PROCESS_DEBUG_EVENT 5 +#define LOAD_DLL_DEBUG_EVENT 6 +#define UNLOAD_DLL_DEBUG_EVENT 7 +#define OUTPUT_DEBUG_STRING_EVENT 8 +#define RIP_EVENT 9 + + typedef struct _EXCEPTION_DEBUG_INFO { + EXCEPTION_RECORD ExceptionRecord; + DWORD dwFirstChance; + } EXCEPTION_DEBUG_INFO,*LPEXCEPTION_DEBUG_INFO; + + typedef struct _CREATE_THREAD_DEBUG_INFO { + HANDLE hThread; + LPVOID lpThreadLocalBase; + LPTHREAD_START_ROUTINE lpStartAddress; + } CREATE_THREAD_DEBUG_INFO,*LPCREATE_THREAD_DEBUG_INFO; + + typedef struct _CREATE_PROCESS_DEBUG_INFO { + HANDLE hFile; + HANDLE hProcess; + HANDLE hThread; + LPVOID lpBaseOfImage; + DWORD dwDebugInfoFileOffset; + DWORD nDebugInfoSize; + LPVOID lpThreadLocalBase; + LPTHREAD_START_ROUTINE lpStartAddress; + LPVOID lpImageName; + WORD fUnicode; + } CREATE_PROCESS_DEBUG_INFO,*LPCREATE_PROCESS_DEBUG_INFO; + + typedef struct _EXIT_THREAD_DEBUG_INFO { + DWORD dwExitCode; + } EXIT_THREAD_DEBUG_INFO,*LPEXIT_THREAD_DEBUG_INFO; + + typedef struct _EXIT_PROCESS_DEBUG_INFO { + DWORD dwExitCode; + } EXIT_PROCESS_DEBUG_INFO,*LPEXIT_PROCESS_DEBUG_INFO; + + typedef struct _LOAD_DLL_DEBUG_INFO { + HANDLE hFile; + LPVOID lpBaseOfDll; + DWORD dwDebugInfoFileOffset; + DWORD nDebugInfoSize; + LPVOID lpImageName; + WORD fUnicode; + } LOAD_DLL_DEBUG_INFO,*LPLOAD_DLL_DEBUG_INFO; + + typedef struct _UNLOAD_DLL_DEBUG_INFO { + LPVOID lpBaseOfDll; + } UNLOAD_DLL_DEBUG_INFO,*LPUNLOAD_DLL_DEBUG_INFO; + + typedef struct _OUTPUT_DEBUG_STRING_INFO { + LPSTR lpDebugStringData; + WORD fUnicode; + WORD nDebugStringLength; + } OUTPUT_DEBUG_STRING_INFO,*LPOUTPUT_DEBUG_STRING_INFO; + + typedef struct _RIP_INFO { + DWORD dwError; + DWORD dwType; + } RIP_INFO,*LPRIP_INFO; + + typedef struct _DEBUG_EVENT { + DWORD dwDebugEventCode; + DWORD dwProcessId; + DWORD dwThreadId; + union { + EXCEPTION_DEBUG_INFO Exception; + CREATE_THREAD_DEBUG_INFO CreateThread; + CREATE_PROCESS_DEBUG_INFO CreateProcessInfo; + EXIT_THREAD_DEBUG_INFO ExitThread; + EXIT_PROCESS_DEBUG_INFO ExitProcess; + LOAD_DLL_DEBUG_INFO LoadDll; + UNLOAD_DLL_DEBUG_INFO UnloadDll; + OUTPUT_DEBUG_STRING_INFO DebugString; + RIP_INFO RipInfo; + } u; + } DEBUG_EVENT,*LPDEBUG_EVENT; + + typedef PCONTEXT LPCONTEXT; + typedef PEXCEPTION_RECORD LPEXCEPTION_RECORD; + typedef PEXCEPTION_POINTERS LPEXCEPTION_POINTERS; + +#define DRIVE_UNKNOWN 0 +#define DRIVE_NO_ROOT_DIR 1 +#define DRIVE_REMOVABLE 2 +#define DRIVE_FIXED 3 +#define DRIVE_REMOTE 4 +#define DRIVE_CDROM 5 +#define DRIVE_RAMDISK 6 + +#define GetFreeSpace(w) (0x100000L) +#define FILE_TYPE_UNKNOWN 0x0 +#define FILE_TYPE_DISK 0x1 +#define FILE_TYPE_CHAR 0x2 +#define FILE_TYPE_PIPE 0x3 +#define FILE_TYPE_REMOTE 0x8000 + +#define STD_INPUT_HANDLE ((DWORD)-10) +#define STD_OUTPUT_HANDLE ((DWORD)-11) +#define STD_ERROR_HANDLE ((DWORD)-12) + +#define NOPARITY 0 +#define ODDPARITY 1 +#define EVENPARITY 2 +#define MARKPARITY 3 +#define SPACEPARITY 4 + +#define ONESTOPBIT 0 +#define ONE5STOPBITS 1 +#define TWOSTOPBITS 2 + +#define IGNORE 0 +#define INFINITE 0xffffffff + +#define CBR_110 110 +#define CBR_300 300 +#define CBR_600 600 +#define CBR_1200 1200 +#define CBR_2400 2400 +#define CBR_4800 4800 +#define CBR_9600 9600 +#define CBR_14400 14400 +#define CBR_19200 19200 +#define CBR_38400 38400 +#define CBR_56000 56000 +#define CBR_57600 57600 +#define CBR_115200 115200 +#define CBR_128000 128000 +#define CBR_256000 256000 + +#define CE_RXOVER 0x1 +#define CE_OVERRUN 0x2 +#define CE_RXPARITY 0x4 +#define CE_FRAME 0x8 +#define CE_BREAK 0x10 +#define CE_TXFULL 0x100 +#define CE_PTO 0x200 +#define CE_IOE 0x400 +#define CE_DNS 0x800 +#define CE_OOP 0x1000 +#define CE_MODE 0x8000 + +#define IE_BADID (-1) +#define IE_OPEN (-2) +#define IE_NOPEN (-3) +#define IE_MEMORY (-4) +#define IE_DEFAULT (-5) +#define IE_HARDWARE (-10) +#define IE_BYTESIZE (-11) +#define IE_BAUDRATE (-12) + +#define EV_RXCHAR 0x1 +#define EV_RXFLAG 0x2 +#define EV_TXEMPTY 0x4 +#define EV_CTS 0x8 +#define EV_DSR 0x10 +#define EV_RLSD 0x20 +#define EV_BREAK 0x40 +#define EV_ERR 0x80 +#define EV_RING 0x100 +#define EV_PERR 0x200 +#define EV_RX80FULL 0x400 +#define EV_EVENT1 0x800 +#define EV_EVENT2 0x1000 + +#define SETXOFF 1 +#define SETXON 2 +#define SETRTS 3 +#define CLRRTS 4 +#define SETDTR 5 +#define CLRDTR 6 +#define RESETDEV 7 +#define SETBREAK 8 +#define CLRBREAK 9 + +#define PURGE_TXABORT 0x1 +#define PURGE_RXABORT 0x2 +#define PURGE_TXCLEAR 0x4 +#define PURGE_RXCLEAR 0x8 + +#define LPTx 0x80 + +#define MS_CTS_ON ((DWORD)0x10) +#define MS_DSR_ON ((DWORD)0x20) +#define MS_RING_ON ((DWORD)0x40) +#define MS_RLSD_ON ((DWORD)0x80) + +#define S_QUEUEEMPTY 0 +#define S_THRESHOLD 1 +#define S_ALLTHRESHOLD 2 + +#define S_NORMAL 0 +#define S_LEGATO 1 +#define S_STACCATO 2 + +#define S_PERIOD512 0 +#define S_PERIOD1024 1 +#define S_PERIOD2048 2 +#define S_PERIODVOICE 3 +#define S_WHITE512 4 +#define S_WHITE1024 5 +#define S_WHITE2048 6 +#define S_WHITEVOICE 7 + +#define S_SERDVNA (-1) +#define S_SEROFM (-2) +#define S_SERMACT (-3) +#define S_SERQFUL (-4) +#define S_SERBDNT (-5) +#define S_SERDLN (-6) +#define S_SERDCC (-7) +#define S_SERDTP (-8) +#define S_SERDVL (-9) +#define S_SERDMD (-10) +#define S_SERDSH (-11) +#define S_SERDPT (-12) +#define S_SERDFQ (-13) +#define S_SERDDR (-14) +#define S_SERDSR (-15) +#define S_SERDST (-16) + +#define NMPWAIT_WAIT_FOREVER 0xffffffff +#define NMPWAIT_NOWAIT 0x1 +#define NMPWAIT_USE_DEFAULT_WAIT 0x0 + +#define FS_CASE_IS_PRESERVED FILE_CASE_PRESERVED_NAMES +#define FS_CASE_SENSITIVE FILE_CASE_SENSITIVE_SEARCH +#define FS_UNICODE_STORED_ON_DISK FILE_UNICODE_ON_DISK +#define FS_PERSISTENT_ACLS FILE_PERSISTENT_ACLS +#define FS_VOL_IS_COMPRESSED FILE_VOLUME_IS_COMPRESSED +#define FS_FILE_COMPRESSION FILE_FILE_COMPRESSION +#define FS_FILE_ENCRYPTION FILE_SUPPORTS_ENCRYPTION + +#define FILE_MAP_COPY SECTION_QUERY +#define FILE_MAP_WRITE SECTION_MAP_WRITE +#define FILE_MAP_READ SECTION_MAP_READ +#define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS +#define FILE_MAP_EXECUTE SECTION_MAP_EXECUTE_EXPLICIT + +#define OF_READ 0x0 +#define OF_WRITE 0x1 +#define OF_READWRITE 0x2 +#define OF_SHARE_COMPAT 0x0 +#define OF_SHARE_EXCLUSIVE 0x10 +#define OF_SHARE_DENY_WRITE 0x20 +#define OF_SHARE_DENY_READ 0x30 +#define OF_SHARE_DENY_NONE 0x40 +#define OF_PARSE 0x100 +#define OF_DELETE 0x200 +#define OF_VERIFY 0x400 +#define OF_CANCEL 0x800 +#define OF_CREATE 0x1000 +#define OF_PROMPT 0x2000 +#define OF_EXIST 0x4000 +#define OF_REOPEN 0x8000 + +#define OFS_MAXPATHNAME 128 + typedef struct _OFSTRUCT { + BYTE cBytes; + BYTE fFixedDisk; + WORD nErrCode; + WORD Reserved1; + WORD Reserved2; + CHAR szPathName[OFS_MAXPATHNAME]; + } OFSTRUCT,*LPOFSTRUCT,*POFSTRUCT; + +#ifndef NOWINBASEINTERLOCK + +#ifndef _NTOS_ + +#if defined(__ia64__) && !defined(RC_INVOKED) + +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedIncrementAcquire _InterlockedIncrement_acq +#define InterlockedIncrementRelease _InterlockedIncrement_rel +#define InterlockedDecrement _InterlockedDecrement +#define InterlockedDecrementAcquire _InterlockedDecrement_acq +#define InterlockedDecrementRelease _InterlockedDecrement_rel +#define InterlockedExchange _InterlockedExchange +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire _InterlockedCompareExchange_acq +#define InterlockedCompareExchangeRelease _InterlockedCompareExchange_rel +#define InterlockedExchangePointer _InterlockedExchangePointer +#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer_rel +#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer_acq + +#define InterlockedIncrement64 _InterlockedIncrement64 +#define InterlockedDecrement64 _InterlockedDecrement64 +#define InterlockedExchange64 _InterlockedExchange64 +#define InterlockedExchangeAcquire64 _InterlockedExchange64_acq +#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 +#define InterlockedCompareExchangeAcquire64 _InterlockedCompareExchange64_acq +#define InterlockedCompareExchangeRelease64 _InterlockedCompareExchange64_rel + + LONGLONG __cdecl InterlockedIncrement64(LONGLONG volatile *Addend); + LONGLONG __cdecl InterlockedDecrement64(LONGLONG volatile *Addend); + LONG __cdecl InterlockedIncrementAcquire(LONG volatile *Addend); + LONG __cdecl InterlockedDecrementAcquire(LONG volatile *Addend); + LONG __cdecl InterlockedIncrementRelease(LONG volatile *Addend); + LONG __cdecl InterlockedDecrementRelease(LONG volatile *Addend); + LONGLONG __cdecl InterlockedExchange64 (LONGLONG volatile *Target,LONGLONG Value); + LONGLONG __cdecl InterlockedExchangeAcquire64 (LONGLONG volatile *Target,LONGLONG Value); + LONGLONG __cdecl InterlockedExchangeAdd64 (LONGLONG volatile *Addend,LONGLONG Value); + LONGLONG __cdecl InterlockedCompareExchange64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); + LONGLONG __cdecl InterlockedCompareExchangeAcquire64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); + LONGLONG __cdecl InterlockedCompareExchangeRelease64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); + LONG __cdecl InterlockedIncrement(LONG volatile *lpAddend); + LONG __cdecl InterlockedDecrement(LONG volatile *lpAddend); + LONG __cdecl InterlockedExchange(LONG volatile *Target,LONG Value); + LONG __cdecl InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + LONG __cdecl InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); + LONG __cdecl InterlockedCompareExchangeRelease(LONG volatile *Destination,LONG ExChange,LONG Comperand); + LONG __cdecl InterlockedCompareExchangeAcquire(LONG volatile *Destination,LONG ExChange,LONG Comperand); + PVOID __cdecl InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); + PVOID __cdecl InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand); + PVOID __cdecl InterlockedCompareExchangePointerAcquire(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); + PVOID __cdecl InterlockedCompareExchangePointerRelease(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); + +#ifndef InterlockedAnd +#define InterlockedAnd InterlockedAnd_Inline + __CRT_INLINE LONG InterlockedAnd_Inline(LONG volatile *Target,LONG Set) { + LONG i; + LONG j; + j = *Target; + do { + i = j; + j = InterlockedCompareExchange(Target,i & Set,i); + } while(i!=j); + return j; + } +#endif + +#ifndef InterlockedOr +#define InterlockedOr InterlockedOr_Inline + + __CRT_INLINE LONG InterlockedOr_Inline(LONG volatile *Target,LONG Set) { + LONG i; + LONG j; + j = *Target; + do { + i = j; + j = InterlockedCompareExchange(Target,i | Set,i); + } while(i!=j); + return j; + } +#endif + +#ifndef InterlockedXor +#define InterlockedXor InterlockedXor_Inline + + __CRT_INLINE LONG InterlockedXor_Inline(LONG volatile *Target,LONG Set) { + LONG i; + LONG j; + j = *Target; + do { + i = j; + j = InterlockedCompareExchange(Target,i ^ Set,i); + } while(i!=j); + return j; + } +#endif + +#ifndef !defined (InterlockedAnd64) +#define InterlockedAnd64 InterlockedAnd64_Inline + + __CRT_INLINE LONGLONG InterlockedAnd64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); + return Old; + } +#endif + +#ifndef InterlockedOr64 +#define InterlockedOr64 InterlockedOr64_Inline + + __CRT_INLINE LONGLONG InterlockedOr64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); + return Old; + } +#endif + +#ifndef InterlockedXor64 +#define InterlockedXor64 InterlockedXor64_Inline + + __CRT_INLINE LONGLONG InterlockedXor64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); + return Old; + } +#endif + +#ifndef InterlockedBitTestAndSet +#define InterlockedBitTestAndSet InterlockedBitTestAndSet_Inline + + __CRT_INLINE BOOLEAN InterlockedBitTestAndSet_Inline(LONG *Base,LONG Bit) { + LONG tBit; + tBit = 1<<(Bit & (sizeof (*Base)*8-1)); + return (BOOLEAN)((InterlockedOr(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); + } +#endif + +#ifndef InterlockedBitTestAndReset +#define InterlockedBitTestAndReset InterlockedBitTestAndReset_Inline + + __CRT_INLINE BOOLEAN InterlockedBitTestAndReset_Inline(LONG *Base,LONG Bit) { + LONG tBit; + tBit = 1<<(Bit & (sizeof (*Base)*8-1)); + return (BOOLEAN)((InterlockedAnd(&Base[Bit/(sizeof(*Base)*8)],~tBit)&tBit)!=0); + } +#endif + +#ifndef InterlockedBitTestAndComplement +#define InterlockedBitTestAndComplement InterlockedBitTestAndComplement_Inline + + __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement_Inline(LONG *Base,LONG Bit) { + LONG tBit; + tBit = 1<<(Bit & (sizeof (*Base)*8-1)); + return (BOOLEAN)((InterlockedXor(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); + } +#endif +#elif defined(__x86_64) && !defined(RC_INVOKED) + +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedDecrement _InterlockedDecrement +#define InterlockedDecrementAcquire InterlockedDecrement +#define InterlockedDecrementRelease InterlockedDecrement +#define InterlockedExchange _InterlockedExchange +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire InterlockedCompareExchange +#define InterlockedCompareExchangeRelease InterlockedCompareExchange +#define InterlockedExchangePointer _InterlockedExchangePointer +#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer +#define InterlockedAnd64 _InterlockedAnd64 +#define InterlockedOr64 _InterlockedOr64 +#define InterlockedXor64 _InterlockedXor64 +#define InterlockedIncrement64 _InterlockedIncrement64 +#define InterlockedDecrement64 _InterlockedDecrement64 +#define InterlockedExchange64 _InterlockedExchange64 +#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 +#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 +#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 + + LONG InterlockedIncrement(LONG volatile *Addend); + LONG InterlockedDecrement(LONG volatile *Addend); + LONG InterlockedExchange(LONG volatile *Target,LONG Value); + LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); + PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); + PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); + LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value); + LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value); + LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value); + LONG64 InterlockedIncrement64(LONG64 volatile *Addend); + LONG64 InterlockedDecrement64(LONG64 volatile *Addend); + LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value); + LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); + LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand); +#else + LONG WINAPI InterlockedIncrement(LONG volatile *lpAddend); + LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend); + LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value); + +#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value)) + + LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand); + LONGLONG WINAPI InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand); + + __CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); + return Old; + } + + __CRT_INLINE LONGLONG InterlockedOr64 (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); + return Old; + } + + __CRT_INLINE LONGLONG InterlockedXor64 (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); + + return Old; + } + + __CRT_INLINE LONGLONG InterlockedIncrement64(LONGLONG volatile *Addend) { + LONGLONG Old; + do { + Old = *Addend; + } while(InterlockedCompareExchange64(Addend,Old + 1,Old)!=Old); + return Old + 1; + } + + __CRT_INLINE LONGLONG InterlockedDecrement64(LONGLONG volatile *Addend) { + LONGLONG Old; + do { + Old = *Addend; + } while(InterlockedCompareExchange64(Addend,Old - 1,Old)!=Old); + return Old - 1; + } + + __CRT_INLINE LONGLONG InterlockedExchange64(LONGLONG volatile *Target,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Target; + } while(InterlockedCompareExchange64(Target,Value,Old)!=Old); + return Old; + } + + __CRT_INLINE LONGLONG InterlockedExchangeAdd64(LONGLONG volatile *Addend,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Addend; + } while(InterlockedCompareExchange64(Addend,Old + Value,Old)!=Old); + return Old; + } + +#ifdef __cplusplus + __CRT_INLINE PVOID __cdecl __InlineInterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { + return((PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)Destination,(LONG)(LONG_PTR)ExChange,(LONG)(LONG_PTR)Comperand)); + } +#define InterlockedCompareExchangePointer __InlineInterlockedCompareExchangePointer +#else +#define InterlockedCompareExchangePointer(Destination,ExChange,Comperand)(PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)(Destination),(LONG)(LONG_PTR)(ExChange),(LONG)(LONG_PTR)(Comperand)) +#endif + +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedDecrementAcquire InterlockedDecrement +#define InterlockedDecrementRelease InterlockedDecrement +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedCompareExchangeAcquire InterlockedCompareExchange +#define InterlockedCompareExchangeRelease InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 +#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 +#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer +#endif + +#if defined(_SLIST_HEADER_) && !defined(_NTOSP_) + WINBASEAPI VOID WINAPI InitializeSListHead(PSLIST_HEADER ListHead); + WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPopEntrySList(PSLIST_HEADER ListHead); + WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); + WINBASEAPI PSLIST_ENTRY WINAPI InterlockedFlushSList(PSLIST_HEADER ListHead); + WINBASEAPI USHORT WINAPI QueryDepthSList(PSLIST_HEADER ListHead); +#endif +#endif +#endif + + WINBASEAPI WINBOOL WINAPI FreeResource(HGLOBAL hResData); + WINBASEAPI LPVOID WINAPI LockResource(HGLOBAL hResData); + +#define UnlockResource(hResData) ((hResData),0) +#define MAXINTATOM 0xC000 +#define MAKEINTATOM(i) (LPTSTR)((ULONG_PTR)((WORD)(i))) +#define INVALID_ATOM ((ATOM)0) + + int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd); + WINBASEAPI WINBOOL WINAPI FreeLibrary(HMODULE hLibModule); + WINBASEAPI DECLSPEC_NORETURN VOID WINAPI FreeLibraryAndExitThread(HMODULE hLibModule,DWORD dwExitCode); + WINBASEAPI WINBOOL WINAPI DisableThreadLibraryCalls(HMODULE hLibModule); + WINBASEAPI FARPROC WINAPI GetProcAddress(HMODULE hModule,LPCSTR lpProcName); + WINBASEAPI DWORD WINAPI GetVersion(VOID); + WINBASEAPI HGLOBAL WINAPI GlobalAlloc(UINT uFlags,SIZE_T dwBytes); + WINBASEAPI HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem,SIZE_T dwBytes,UINT uFlags); + WINBASEAPI SIZE_T WINAPI GlobalSize(HGLOBAL hMem); + WINBASEAPI UINT WINAPI GlobalFlags(HGLOBAL hMem); + WINBASEAPI LPVOID WINAPI GlobalLock(HGLOBAL hMem); + WINBASEAPI HGLOBAL WINAPI GlobalHandle(LPCVOID pMem); + WINBASEAPI WINBOOL WINAPI GlobalUnlock(HGLOBAL hMem); + WINBASEAPI HGLOBAL WINAPI GlobalFree(HGLOBAL hMem); + WINBASEAPI SIZE_T WINAPI GlobalCompact(DWORD dwMinFree); + WINBASEAPI VOID WINAPI GlobalFix(HGLOBAL hMem); + WINBASEAPI VOID WINAPI GlobalUnfix(HGLOBAL hMem); + WINBASEAPI LPVOID WINAPI GlobalWire(HGLOBAL hMem); + WINBASEAPI WINBOOL WINAPI GlobalUnWire(HGLOBAL hMem); + WINBASEAPI VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer); + + typedef struct _MEMORYSTATUSEX { + DWORD dwLength; + DWORD dwMemoryLoad; + DWORDLONG ullTotalPhys; + DWORDLONG ullAvailPhys; + DWORDLONG ullTotalPageFile; + DWORDLONG ullAvailPageFile; + DWORDLONG ullTotalVirtual; + DWORDLONG ullAvailVirtual; + DWORDLONG ullAvailExtendedVirtual; + } MEMORYSTATUSEX,*LPMEMORYSTATUSEX; + + WINBASEAPI WINBOOL WINAPI GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer); + WINBASEAPI HLOCAL WINAPI LocalAlloc(UINT uFlags,SIZE_T uBytes); + WINBASEAPI HLOCAL WINAPI LocalReAlloc(HLOCAL hMem,SIZE_T uBytes,UINT uFlags); + WINBASEAPI LPVOID WINAPI LocalLock(HLOCAL hMem); + WINBASEAPI HLOCAL WINAPI LocalHandle(LPCVOID pMem); + WINBASEAPI WINBOOL WINAPI LocalUnlock(HLOCAL hMem); + WINBASEAPI SIZE_T WINAPI LocalSize(HLOCAL hMem); + WINBASEAPI UINT WINAPI LocalFlags(HLOCAL hMem); + WINBASEAPI HLOCAL WINAPI LocalFree(HLOCAL hMem); + WINBASEAPI SIZE_T WINAPI LocalShrink(HLOCAL hMem,UINT cbNewSize); + WINBASEAPI SIZE_T WINAPI LocalCompact(UINT uMinFree); + WINBASEAPI WINBOOL WINAPI FlushInstructionCache(HANDLE hProcess,LPCVOID lpBaseAddress,SIZE_T dwSize); + WINBASEAPI LPVOID WINAPI VirtualAlloc(LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); + WINBASEAPI WINBOOL WINAPI VirtualFree(LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); + WINBASEAPI WINBOOL WINAPI VirtualProtect(LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); + WINBASEAPI SIZE_T WINAPI VirtualQuery(LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); + WINBASEAPI LPVOID WINAPI VirtualAllocEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); + WINBASEAPI UINT WINAPI GetWriteWatch(DWORD dwFlags,PVOID lpBaseAddress,SIZE_T dwRegionSize,PVOID *lpAddresses,ULONG_PTR *lpdwCount,PULONG lpdwGranularity); + WINBASEAPI UINT WINAPI ResetWriteWatch(LPVOID lpBaseAddress,SIZE_T dwRegionSize); + WINBASEAPI SIZE_T WINAPI GetLargePageMinimum(VOID); + WINBASEAPI UINT WINAPI EnumSystemFirmwareTables(DWORD FirmwareTableProviderSignature,PVOID pFirmwareTableEnumBuffer,DWORD BufferSize); + WINBASEAPI UINT WINAPI GetSystemFirmwareTable(DWORD FirmwareTableProviderSignature,DWORD FirmwareTableID,PVOID pFirmwareTableBuffer,DWORD BufferSize); + WINBASEAPI WINBOOL WINAPI VirtualFreeEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); + WINBASEAPI WINBOOL WINAPI VirtualProtectEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); + WINBASEAPI SIZE_T WINAPI VirtualQueryEx(HANDLE hProcess,LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); + WINBASEAPI HANDLE WINAPI HeapCreate(DWORD flOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize); + WINBASEAPI WINBOOL WINAPI HeapDestroy(HANDLE hHeap); + WINBASEAPI LPVOID WINAPI HeapAlloc(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes); + WINBASEAPI LPVOID WINAPI HeapReAlloc(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem,SIZE_T dwBytes); + WINBASEAPI WINBOOL WINAPI HeapFree(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem); + WINBASEAPI SIZE_T WINAPI HeapSize(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); + WINBASEAPI WINBOOL WINAPI HeapValidate(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); + WINBASEAPI SIZE_T WINAPI HeapCompact(HANDLE hHeap,DWORD dwFlags); + WINBASEAPI HANDLE WINAPI GetProcessHeap(VOID); + WINBASEAPI DWORD WINAPI GetProcessHeaps(DWORD NumberOfHeaps,PHANDLE ProcessHeaps); + + typedef struct _PROCESS_HEAP_ENTRY { + PVOID lpData; + DWORD cbData; + BYTE cbOverhead; + BYTE iRegionIndex; + WORD wFlags; + union { + struct { + HANDLE hMem; + DWORD dwReserved[3]; + } Block; + struct { + DWORD dwCommittedSize; + DWORD dwUnCommittedSize; + LPVOID lpFirstBlock; + LPVOID lpLastBlock; + } Region; + }; + } PROCESS_HEAP_ENTRY,*LPPROCESS_HEAP_ENTRY,*PPROCESS_HEAP_ENTRY; + +#define PROCESS_HEAP_REGION 0x1 +#define PROCESS_HEAP_UNCOMMITTED_RANGE 0x2 +#define PROCESS_HEAP_ENTRY_BUSY 0x4 +#define PROCESS_HEAP_ENTRY_MOVEABLE 0x10 +#define PROCESS_HEAP_ENTRY_DDESHARE 0x20 + + WINBASEAPI WINBOOL WINAPI HeapLock(HANDLE hHeap); + WINBASEAPI WINBOOL WINAPI HeapUnlock(HANDLE hHeap); + WINBASEAPI WINBOOL WINAPI HeapWalk(HANDLE hHeap,LPPROCESS_HEAP_ENTRY lpEntry); + WINBASEAPI WINBOOL WINAPI HeapSetInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); + WINBASEAPI WINBOOL WINAPI HeapQueryInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); + +#define SCS_32BIT_BINARY 0 +#define SCS_DOS_BINARY 1 +#define SCS_WOW_BINARY 2 +#define SCS_PIF_BINARY 3 +#define SCS_POSIX_BINARY 4 +#define SCS_OS216_BINARY 5 +#define SCS_64BIT_BINARY 6 + +#ifdef UNICODE +#define GetBinaryType GetBinaryTypeW +#define GetShortPathName GetShortPathNameW +#define GetLongPathName GetLongPathNameW +#define GetEnvironmentStrings GetEnvironmentStringsW +#define SetEnvironmentStrings SetEnvironmentStringsW +#define FreeEnvironmentStrings FreeEnvironmentStringsW +#else +#define GetBinaryType GetBinaryTypeA +#define GetShortPathName GetShortPathNameA +#define GetLongPathName GetLongPathNameA +#define GetEnvironmentStringsA GetEnvironmentStrings +#define SetEnvironmentStrings SetEnvironmentStringsA +#define FreeEnvironmentStrings FreeEnvironmentStringsA +#endif + +#ifdef _WIN64 +#define SCS_THIS_PLATFORM_BINARY SCS_64BIT_BINARY +#else +#define SCS_THIS_PLATFORM_BINARY SCS_32BIT_BINARY +#endif + + WINBASEAPI WINBOOL WINAPI GetBinaryTypeA(LPCSTR lpApplicationName,LPDWORD lpBinaryType); + WINBASEAPI WINBOOL WINAPI GetBinaryTypeW(LPCWSTR lpApplicationName,LPDWORD lpBinaryType); + WINBASEAPI DWORD WINAPI GetShortPathNameA(LPCSTR lpszLongPath,LPSTR lpszShortPath,DWORD cchBuffer); + WINBASEAPI DWORD WINAPI GetShortPathNameW(LPCWSTR lpszLongPath,LPWSTR lpszShortPath,DWORD cchBuffer); + WINBASEAPI DWORD WINAPI GetLongPathNameA(LPCSTR lpszShortPath,LPSTR lpszLongPath,DWORD cchBuffer); + WINBASEAPI DWORD WINAPI GetLongPathNameW(LPCWSTR lpszShortPath,LPWSTR lpszLongPath,DWORD cchBuffer); + WINBASEAPI WINBOOL WINAPI GetProcessAffinityMask(HANDLE hProcess,PDWORD_PTR lpProcessAffinityMask,PDWORD_PTR lpSystemAffinityMask); + WINBASEAPI WINBOOL WINAPI SetProcessAffinityMask(HANDLE hProcess,DWORD_PTR dwProcessAffinityMask); + WINBASEAPI WINBOOL WINAPI GetProcessHandleCount(HANDLE hProcess,PDWORD pdwHandleCount); + WINBASEAPI WINBOOL WINAPI GetProcessTimes(HANDLE hProcess,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); + WINBASEAPI WINBOOL WINAPI GetProcessIoCounters(HANDLE hProcess,PIO_COUNTERS lpIoCounters); + WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize); + WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSizeEx(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize,PDWORD Flags); + WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize); + WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSizeEx(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize,DWORD Flags); + WINBASEAPI HANDLE WINAPI OpenProcess(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwProcessId); + WINBASEAPI HANDLE WINAPI GetCurrentProcess(VOID); + WINBASEAPI DWORD WINAPI GetCurrentProcessId(VOID); + WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitProcess(UINT uExitCode); + WINBASEAPI WINBOOL WINAPI TerminateProcess(HANDLE hProcess,UINT uExitCode); + WINBASEAPI WINBOOL WINAPI GetExitCodeProcess(HANDLE hProcess,LPDWORD lpExitCode); + WINBASEAPI VOID WINAPI FatalExit(int ExitCode); + /* WINBASEAPI LPCH WINAPI GetEnvironmentStrings(VOID); */ + WINBASEAPI LPWCH WINAPI GetEnvironmentStringsW(VOID); + WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsA(LPCH NewEnvironment); + WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsW(LPWCH NewEnvironment); + WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsA(LPCH); + WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsW(LPWCH); + WINBASEAPI VOID WINAPI RaiseException(DWORD dwExceptionCode,DWORD dwExceptionFlags,DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments); + WINBASEAPI LONG WINAPI UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo); + + typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(struct _EXCEPTION_POINTERS *ExceptionInfo); + typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER; + + WINBASEAPI LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); + +#define FIBER_FLAG_FLOAT_SWITCH 0x1 + + WINBASEAPI LPVOID WINAPI CreateFiber(SIZE_T dwStackSize,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); + WINBASEAPI LPVOID WINAPI CreateFiberEx(SIZE_T dwStackCommitSize,SIZE_T dwStackReserveSize,DWORD dwFlags,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); + WINBASEAPI VOID WINAPI DeleteFiber(LPVOID lpFiber); + WINBASEAPI LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter); + WINBASEAPI LPVOID WINAPI ConvertThreadToFiberEx(LPVOID lpParameter,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI ConvertFiberToThread(VOID); + WINBASEAPI VOID WINAPI SwitchToFiber(LPVOID lpFiber); + WINBASEAPI WINBOOL WINAPI SwitchToThread(VOID); + WINBASEAPI HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); + WINBASEAPI HANDLE WINAPI CreateRemoteThread(HANDLE hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); + WINBASEAPI HANDLE WINAPI GetCurrentThread(VOID); + WINBASEAPI DWORD WINAPI GetCurrentThreadId(VOID); + WINBASEAPI WINBOOL WINAPI SetThreadStackGuarantee (PULONG StackSizeInBytes); + WINBASEAPI DWORD WINAPI GetProcessIdOfThread(HANDLE Thread); + WINBASEAPI DWORD WINAPI GetThreadId(HANDLE Thread); + WINBASEAPI DWORD WINAPI GetProcessId(HANDLE Process); + WINBASEAPI DWORD WINAPI GetCurrentProcessorNumber(VOID); + WINBASEAPI DWORD_PTR WINAPI SetThreadAffinityMask(HANDLE hThread,DWORD_PTR dwThreadAffinityMask); + WINBASEAPI DWORD WINAPI SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor); + WINBASEAPI WINBOOL WINAPI SetProcessPriorityBoost(HANDLE hProcess,WINBOOL bDisablePriorityBoost); + WINBASEAPI WINBOOL WINAPI GetProcessPriorityBoost(HANDLE hProcess,PBOOL pDisablePriorityBoost); + WINBASEAPI WINBOOL WINAPI RequestWakeupLatency(LATENCY_TIME latency); + WINBASEAPI WINBOOL WINAPI IsSystemResumeAutomatic(VOID); + WINBASEAPI HANDLE WINAPI OpenThread(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwThreadId); + WINBASEAPI WINBOOL WINAPI SetThreadPriority(HANDLE hThread,int nPriority); + WINBASEAPI WINBOOL WINAPI SetThreadPriorityBoost(HANDLE hThread,WINBOOL bDisablePriorityBoost); + WINBASEAPI WINBOOL WINAPI GetThreadPriorityBoost(HANDLE hThread,PBOOL pDisablePriorityBoost); + WINBASEAPI int WINAPI GetThreadPriority(HANDLE hThread); + WINBASEAPI WINBOOL WINAPI GetThreadTimes(HANDLE hThread,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); + WINBASEAPI WINBOOL WINAPI GetThreadIOPendingFlag(HANDLE hThread,PBOOL lpIOIsPending); + WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitThread(DWORD dwExitCode); + WINBASEAPI WINBOOL WINAPI TerminateThread(HANDLE hThread,DWORD dwExitCode); + WINBASEAPI WINBOOL WINAPI GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode); + WINBASEAPI WINBOOL WINAPI GetThreadSelectorEntry(HANDLE hThread,DWORD dwSelector,LPLDT_ENTRY lpSelectorEntry); + WINBASEAPI EXECUTION_STATE WINAPI SetThreadExecutionState(EXECUTION_STATE esFlags); + WINBASEAPI DWORD WINAPI GetLastError(VOID); + WINBASEAPI VOID WINAPI SetLastError(DWORD dwErrCode); + +#ifndef RC_INVOKED +#ifdef WINBASE_DECLARE_RESTORE_LAST_ERROR + WINBASEAPI VOID WINAPI RestoreLastError(DWORD dwErrCode); + + typedef VOID (WINAPI *PRESTORE_LAST_ERROR)(DWORD); + +#define RESTORE_LAST_ERROR_NAME_A "RestoreLastError" +#define RESTORE_LAST_ERROR_NAME_W L"RestoreLastError" +#define RESTORE_LAST_ERROR_NAME TEXT("RestoreLastError") +#endif +#endif + +#define HasOverlappedIoCompleted(lpOverlapped) (((DWORD)(lpOverlapped)->Internal)!=STATUS_PENDING) + + WINBASEAPI WINBOOL WINAPI GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,LPDWORD lpNumberOfBytesTransferred,WINBOOL bWait); + WINBASEAPI HANDLE WINAPI CreateIoCompletionPort(HANDLE FileHandle,HANDLE ExistingCompletionPort,ULONG_PTR CompletionKey,DWORD NumberOfConcurrentThreads); + WINBASEAPI WINBOOL WINAPI GetQueuedCompletionStatus(HANDLE CompletionPort,LPDWORD lpNumberOfBytesTransferred,PULONG_PTR lpCompletionKey,LPOVERLAPPED *lpOverlapped,DWORD dwMilliseconds); + WINBASEAPI WINBOOL WINAPI PostQueuedCompletionStatus(HANDLE CompletionPort,DWORD dwNumberOfBytesTransferred,ULONG_PTR dwCompletionKey,LPOVERLAPPED lpOverlapped); + +#define SEM_FAILCRITICALERRORS 0x1 +#define SEM_NOGPFAULTERRORBOX 0x2 +#define SEM_NOALIGNMENTFAULTEXCEPT 0x4 +#define SEM_NOOPENFILEERRORBOX 0x8000 + + WINBASEAPI UINT WINAPI SetErrorMode(UINT uMode); + WINBASEAPI WINBOOL WINAPI ReadProcessMemory(HANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesRead); + WINBASEAPI WINBOOL WINAPI WriteProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesWritten); + WINBASEAPI WINBOOL WINAPI GetThreadContext(HANDLE hThread,LPCONTEXT lpContext); + WINBASEAPI WINBOOL WINAPI SetThreadContext(HANDLE hThread,CONST CONTEXT *lpContext); + WINBASEAPI DWORD WINAPI SuspendThread(HANDLE hThread); + WINBASEAPI DWORD WINAPI ResumeThread(HANDLE hThread); + + typedef VOID (WINAPI *PAPCFUNC)(ULONG_PTR dwParam); + + WINBASEAPI DWORD WINAPI QueueUserAPC(PAPCFUNC pfnAPC,HANDLE hThread,ULONG_PTR dwData); + WINBASEAPI WINBOOL WINAPI IsDebuggerPresent(VOID); + WINBASEAPI WINBOOL WINAPI CheckRemoteDebuggerPresent(HANDLE hProcess,PBOOL pbDebuggerPresent); + WINBASEAPI VOID WINAPI DebugBreak(VOID); + WINBASEAPI WINBOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT lpDebugEvent,DWORD dwMilliseconds); + WINBASEAPI WINBOOL WINAPI ContinueDebugEvent(DWORD dwProcessId,DWORD dwThreadId,DWORD dwContinueStatus); + WINBASEAPI WINBOOL WINAPI DebugActiveProcess(DWORD dwProcessId); + WINBASEAPI WINBOOL WINAPI DebugActiveProcessStop(DWORD dwProcessId); + WINBASEAPI WINBOOL WINAPI DebugSetProcessKillOnExit(WINBOOL KillOnExit); + WINBASEAPI WINBOOL WINAPI DebugBreakProcess(HANDLE Process); + WINBASEAPI VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI WINBOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); + WINBASEAPI DWORD WINAPI SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); + WINBASEAPI WINBOOL WINAPI TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI WINBOOL WINAPI SetEvent(HANDLE hEvent); + WINBASEAPI WINBOOL WINAPI ResetEvent(HANDLE hEvent); + WINBASEAPI WINBOOL WINAPI PulseEvent(HANDLE hEvent); + WINBASEAPI WINBOOL WINAPI ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount,LPLONG lpPreviousCount); + WINBASEAPI WINBOOL WINAPI ReleaseMutex(HANDLE hMutex); + WINBASEAPI DWORD WINAPI WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds); + WINBASEAPI DWORD WINAPI WaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds); + WINBASEAPI VOID WINAPI Sleep(DWORD dwMilliseconds); + WINBASEAPI HGLOBAL WINAPI LoadResource(HMODULE hModule,HRSRC hResInfo); + WINBASEAPI DWORD WINAPI SizeofResource(HMODULE hModule,HRSRC hResInfo); + WINBASEAPI ATOM WINAPI GlobalDeleteAtom(ATOM nAtom); + WINBASEAPI WINBOOL WINAPI InitAtomTable(DWORD nSize); + WINBASEAPI ATOM WINAPI DeleteAtom(ATOM nAtom); + WINBASEAPI UINT WINAPI SetHandleCount(UINT uNumber); + WINBASEAPI DWORD WINAPI GetLogicalDrives(VOID); + WINBASEAPI WINBOOL WINAPI LockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh); + WINBASEAPI WINBOOL WINAPI UnlockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh); + WINBASEAPI WINBOOL WINAPI LockFileEx(HANDLE hFile,DWORD dwFlags,DWORD dwReserved,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh,LPOVERLAPPED lpOverlapped); + +#define LOCKFILE_FAIL_IMMEDIATELY 0x1 +#define LOCKFILE_EXCLUSIVE_LOCK 0x2 + + WINBASEAPI WINBOOL WINAPI UnlockFileEx(HANDLE hFile,DWORD dwReserved,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh,LPOVERLAPPED lpOverlapped); + + typedef struct _BY_HANDLE_FILE_INFORMATION { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD dwVolumeSerialNumber; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD nNumberOfLinks; + DWORD nFileIndexHigh; + DWORD nFileIndexLow; + } BY_HANDLE_FILE_INFORMATION,*PBY_HANDLE_FILE_INFORMATION,*LPBY_HANDLE_FILE_INFORMATION; + +#ifdef UNICODE +#define SetFileShortName SetFileShortNameW +#else +#define SetFileShortName SetFileShortNameA +#endif + + WINBASEAPI WINBOOL WINAPI GetFileInformationByHandle(HANDLE hFile,LPBY_HANDLE_FILE_INFORMATION lpFileInformation); + WINBASEAPI DWORD WINAPI GetFileType(HANDLE hFile); + WINBASEAPI DWORD WINAPI GetFileSize(HANDLE hFile,LPDWORD lpFileSizeHigh); + WINBASEAPI WINBOOL WINAPI GetFileSizeEx(HANDLE hFile,PLARGE_INTEGER lpFileSize); + WINBASEAPI HANDLE WINAPI GetStdHandle(DWORD nStdHandle); + WINBASEAPI WINBOOL WINAPI SetStdHandle(DWORD nStdHandle,HANDLE hHandle); + WINBASEAPI WINBOOL WINAPI WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI FlushFileBuffers(HANDLE hFile); + WINBASEAPI WINBOOL WINAPI DeviceIoControl(HANDLE hDevice,DWORD dwIoControlCode,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI RequestDeviceWakeup(HANDLE hDevice); + WINBASEAPI WINBOOL WINAPI CancelDeviceWakeupRequest(HANDLE hDevice); + WINBASEAPI WINBOOL WINAPI GetDevicePowerState(HANDLE hDevice,WINBOOL *pfOn); + WINBASEAPI WINBOOL WINAPI SetMessageWaitingIndicator(HANDLE hMsgIndicator,ULONG ulMsgCount); + WINBASEAPI WINBOOL WINAPI SetEndOfFile(HANDLE hFile); + WINBASEAPI DWORD WINAPI SetFilePointer(HANDLE hFile,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod); + WINBASEAPI WINBOOL WINAPI SetFilePointerEx(HANDLE hFile,LARGE_INTEGER liDistanceToMove,PLARGE_INTEGER lpNewFilePointer,DWORD dwMoveMethod); + WINBASEAPI WINBOOL WINAPI FindClose(HANDLE hFindFile); + WINBASEAPI WINBOOL WINAPI GetFileTime(HANDLE hFile,LPFILETIME lpCreationTime,LPFILETIME lpLastAccessTime,LPFILETIME lpLastWriteTime); + WINBASEAPI WINBOOL WINAPI SetFileTime(HANDLE hFile,CONST FILETIME *lpCreationTime,CONST FILETIME *lpLastAccessTime,CONST FILETIME *lpLastWriteTime); + WINBASEAPI WINBOOL WINAPI SetFileValidData(HANDLE hFile,LONGLONG ValidDataLength); + WINBASEAPI WINBOOL WINAPI SetFileShortNameA(HANDLE hFile,LPCSTR lpShortName); + WINBASEAPI WINBOOL WINAPI SetFileShortNameW(HANDLE hFile,LPCWSTR lpShortName); + WINBASEAPI WINBOOL WINAPI CloseHandle(HANDLE hObject); + WINBASEAPI WINBOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle,HANDLE hSourceHandle,HANDLE hTargetProcessHandle,LPHANDLE lpTargetHandle,DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwOptions); + WINBASEAPI WINBOOL WINAPI GetHandleInformation(HANDLE hObject,LPDWORD lpdwFlags); + WINBASEAPI WINBOOL WINAPI SetHandleInformation(HANDLE hObject,DWORD dwMask,DWORD dwFlags); + +#define HANDLE_FLAG_INHERIT 0x1 +#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x2 + +#define HINSTANCE_ERROR 32 + + WINBASEAPI DWORD WINAPI LoadModule(LPCSTR lpModuleName,LPVOID lpParameterBlock); + WINBASEAPI UINT WINAPI WinExec(LPCSTR lpCmdLine,UINT uCmdShow); + WINBASEAPI WINBOOL WINAPI ClearCommBreak(HANDLE hFile); + WINBASEAPI WINBOOL WINAPI ClearCommError(HANDLE hFile,LPDWORD lpErrors,LPCOMSTAT lpStat); + WINBASEAPI WINBOOL WINAPI SetupComm(HANDLE hFile,DWORD dwInQueue,DWORD dwOutQueue); + WINBASEAPI WINBOOL WINAPI EscapeCommFunction(HANDLE hFile,DWORD dwFunc); + WINBASEAPI WINBOOL WINAPI GetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); + WINBASEAPI WINBOOL WINAPI GetCommMask(HANDLE hFile,LPDWORD lpEvtMask); + WINBASEAPI WINBOOL WINAPI GetCommProperties(HANDLE hFile,LPCOMMPROP lpCommProp); + WINBASEAPI WINBOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat); + WINBASEAPI WINBOOL WINAPI GetCommState(HANDLE hFile,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI GetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI PurgeComm(HANDLE hFile,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI SetCommBreak(HANDLE hFile); + WINBASEAPI WINBOOL WINAPI SetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,DWORD dwSize); + WINBASEAPI WINBOOL WINAPI SetCommMask(HANDLE hFile,DWORD dwEvtMask); + WINBASEAPI WINBOOL WINAPI SetCommState(HANDLE hFile,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI SetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI TransmitCommChar(HANDLE hFile,char cChar); + WINBASEAPI WINBOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD lpEvtMask,LPOVERLAPPED lpOverlapped); + WINBASEAPI DWORD WINAPI SetTapePosition(HANDLE hDevice,DWORD dwPositionMethod,DWORD dwPartition,DWORD dwOffsetLow,DWORD dwOffsetHigh,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI GetTapePosition(HANDLE hDevice,DWORD dwPositionType,LPDWORD lpdwPartition,LPDWORD lpdwOffsetLow,LPDWORD lpdwOffsetHigh); + WINBASEAPI DWORD WINAPI PrepareTape(HANDLE hDevice,DWORD dwOperation,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI EraseTape(HANDLE hDevice,DWORD dwEraseType,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI CreateTapePartition(HANDLE hDevice,DWORD dwPartitionMethod,DWORD dwCount,DWORD dwSize); + WINBASEAPI DWORD WINAPI WriteTapemark(HANDLE hDevice,DWORD dwTapemarkType,DWORD dwTapemarkCount,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI GetTapeStatus(HANDLE hDevice); + WINBASEAPI DWORD WINAPI GetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPDWORD lpdwSize,LPVOID lpTapeInformation); + +#define GET_TAPE_MEDIA_INFORMATION 0 +#define GET_TAPE_DRIVE_INFORMATION 1 + + WINBASEAPI DWORD WINAPI SetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPVOID lpTapeInformation); + +#define SET_TAPE_MEDIA_INFORMATION 0 +#define SET_TAPE_DRIVE_INFORMATION 1 + + WINBASEAPI WINBOOL WINAPI Beep(DWORD dwFreq,DWORD dwDuration); + WINBASEAPI int WINAPI MulDiv(int nNumber,int nNumerator,int nDenominator); + WINBASEAPI VOID WINAPI GetSystemTime(LPSYSTEMTIME lpSystemTime); + WINBASEAPI VOID WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); + WINBASEAPI WINBOOL WINAPI SetSystemTime(CONST SYSTEMTIME *lpSystemTime); + WINBASEAPI VOID WINAPI GetLocalTime(LPSYSTEMTIME lpSystemTime); + WINBASEAPI WINBOOL WINAPI SetLocalTime(CONST SYSTEMTIME *lpSystemTime); + WINBASEAPI VOID WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo); + WINBASEAPI WINBOOL WINAPI SetSystemFileCacheSize(SIZE_T MinimumFileCacheSize,SIZE_T MaximumFileCacheSize,DWORD Flags); + WINBASEAPI WINBOOL WINAPI GetSystemFileCacheSize(PSIZE_T lpMinimumFileCacheSize,PSIZE_T lpMaximumFileCacheSize,PDWORD lpFlags); + WINBASEAPI WINBOOL WINAPI GetSystemRegistryQuota(PDWORD pdwQuotaAllowed,PDWORD pdwQuotaUsed); + WINBOOL WINAPI GetSystemTimes(LPFILETIME lpIdleTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); + WINBASEAPI VOID WINAPI GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo); + WINBASEAPI WINBOOL WINAPI IsProcessorFeaturePresent(DWORD ProcessorFeature); + + typedef struct _TIME_ZONE_INFORMATION { + LONG Bias; + WCHAR StandardName[32]; + SYSTEMTIME StandardDate; + LONG StandardBias; + WCHAR DaylightName[32]; + SYSTEMTIME DaylightDate; + LONG DaylightBias; + } TIME_ZONE_INFORMATION,*PTIME_ZONE_INFORMATION,*LPTIME_ZONE_INFORMATION; + +#ifdef UNICODE +#define FormatMessage FormatMessageW +#else +#define FormatMessage FormatMessageA +#endif + + WINBASEAPI WINBOOL WINAPI SystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpUniversalTime,LPSYSTEMTIME lpLocalTime); + WINBASEAPI WINBOOL WINAPI TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpLocalTime,LPSYSTEMTIME lpUniversalTime); + WINBASEAPI DWORD WINAPI GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation); + WINBASEAPI WINBOOL WINAPI SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation); + WINBASEAPI WINBOOL WINAPI SystemTimeToFileTime(CONST SYSTEMTIME *lpSystemTime,LPFILETIME lpFileTime); + WINBASEAPI WINBOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *lpFileTime,LPFILETIME lpLocalFileTime); + WINBASEAPI WINBOOL WINAPI LocalFileTimeToFileTime(CONST FILETIME *lpLocalFileTime,LPFILETIME lpFileTime); + WINBASEAPI WINBOOL WINAPI FileTimeToSystemTime(CONST FILETIME *lpFileTime,LPSYSTEMTIME lpSystemTime); + WINBASEAPI LONG WINAPI CompareFileTime(CONST FILETIME *lpFileTime1,CONST FILETIME *lpFileTime2); + WINBASEAPI WINBOOL WINAPI FileTimeToDosDateTime(CONST FILETIME *lpFileTime,LPWORD lpFatDate,LPWORD lpFatTime); + WINBASEAPI WINBOOL WINAPI DosDateTimeToFileTime(WORD wFatDate,WORD wFatTime,LPFILETIME lpFileTime); + WINBASEAPI DWORD WINAPI GetTickCount(VOID); + WINBASEAPI WINBOOL WINAPI SetSystemTimeAdjustment(DWORD dwTimeAdjustment,WINBOOL bTimeAdjustmentDisabled); + WINBASEAPI WINBOOL WINAPI GetSystemTimeAdjustment(PDWORD lpTimeAdjustment,PDWORD lpTimeIncrement,PBOOL lpTimeAdjustmentDisabled); + WINBASEAPI DWORD WINAPI FormatMessageA(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPSTR lpBuffer,DWORD nSize,va_list *Arguments); + WINBASEAPI DWORD WINAPI FormatMessageW(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPWSTR lpBuffer,DWORD nSize,va_list *Arguments); + +#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x100 +#define FORMAT_MESSAGE_IGNORE_INSERTS 0x200 +#define FORMAT_MESSAGE_FROM_STRING 0x400 +#define FORMAT_MESSAGE_FROM_HMODULE 0x800 +#define FORMAT_MESSAGE_FROM_SYSTEM 0x1000 +#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x2000 +#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0xff + +#ifdef UNICODE +#define CreateMailslot CreateMailslotW +#define EncryptFile EncryptFileW +#define DecryptFile DecryptFileW +#define FileEncryptionStatus FileEncryptionStatusW +#else +#define CreateMailslot CreateMailslotA +#define EncryptFile EncryptFileA +#define DecryptFile DecryptFileA +#define FileEncryptionStatus FileEncryptionStatusA +#endif + + WINBASEAPI WINBOOL WINAPI CreatePipe(PHANDLE hReadPipe,PHANDLE hWritePipe,LPSECURITY_ATTRIBUTES lpPipeAttributes,DWORD nSize); + WINBASEAPI WINBOOL WINAPI ConnectNamedPipe(HANDLE hNamedPipe,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI DisconnectNamedPipe(HANDLE hNamedPipe); + WINBASEAPI WINBOOL WINAPI SetNamedPipeHandleState(HANDLE hNamedPipe,LPDWORD lpMode,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout); + WINBASEAPI WINBOOL WINAPI GetNamedPipeInfo(HANDLE hNamedPipe,LPDWORD lpFlags,LPDWORD lpOutBufferSize,LPDWORD lpInBufferSize,LPDWORD lpMaxInstances); + WINBASEAPI WINBOOL WINAPI PeekNamedPipe(HANDLE hNamedPipe,LPVOID lpBuffer,DWORD nBufferSize,LPDWORD lpBytesRead,LPDWORD lpTotalBytesAvail,LPDWORD lpBytesLeftThisMessage); + WINBASEAPI WINBOOL WINAPI TransactNamedPipe(HANDLE hNamedPipe,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,LPOVERLAPPED lpOverlapped); + WINBASEAPI HANDLE WINAPI CreateMailslotA(LPCSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI HANDLE WINAPI CreateMailslotW(LPCWSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI GetMailslotInfo(HANDLE hMailslot,LPDWORD lpMaxMessageSize,LPDWORD lpNextSize,LPDWORD lpMessageCount,LPDWORD lpReadTimeout); + WINBASEAPI WINBOOL WINAPI SetMailslotInfo(HANDLE hMailslot,DWORD lReadTimeout); + WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap); + WINBASEAPI WINBOOL WINAPI FlushViewOfFile(LPCVOID lpBaseAddress,SIZE_T dwNumberOfBytesToFlush); + WINBASEAPI WINBOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress); + WINADVAPI WINBOOL WINAPI EncryptFileA(LPCSTR lpFileName); + WINADVAPI WINBOOL WINAPI EncryptFileW(LPCWSTR lpFileName); + WINADVAPI WINBOOL WINAPI DecryptFileA(LPCSTR lpFileName,DWORD dwReserved); + WINADVAPI WINBOOL WINAPI DecryptFileW(LPCWSTR lpFileName,DWORD dwReserved); + +#define FILE_ENCRYPTABLE 0 +#define FILE_IS_ENCRYPTED 1 +#define FILE_SYSTEM_ATTR 2 +#define FILE_ROOT_DIR 3 +#define FILE_SYSTEM_DIR 4 +#define FILE_UNKNOWN 5 +#define FILE_SYSTEM_NOT_SUPPORT 6 +#define FILE_USER_DISALLOWED 7 +#define FILE_READ_ONLY 8 +#define FILE_DIR_DISALLOWED 9 + + WINADVAPI WINBOOL WINAPI FileEncryptionStatusA(LPCSTR lpFileName,LPDWORD lpStatus); + WINADVAPI WINBOOL WINAPI FileEncryptionStatusW(LPCWSTR lpFileName,LPDWORD lpStatus); + +#define EFS_USE_RECOVERY_KEYS (0x1) + + typedef DWORD (WINAPI *PFE_EXPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,ULONG ulLength); + typedef DWORD (WINAPI *PFE_IMPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,PULONG ulLength); + +#define CREATE_FOR_IMPORT (1) +#define CREATE_FOR_DIR (2) +#define OVERWRITE_HIDDEN (4) + +#ifdef UNICODE +#define OpenEncryptedFileRaw OpenEncryptedFileRawW +#define lstrcmp lstrcmpW +#define lstrcmpi lstrcmpiW +#define lstrcpyn lstrcpynW +#define lstrcpy lstrcpyW +#define lstrcat lstrcatW +#define lstrlen lstrlenW +#else +#define OpenEncryptedFileRaw OpenEncryptedFileRawA +#define lstrcmp lstrcmpA +#define lstrcmpi lstrcmpiA +#define lstrcpyn lstrcpynA +#define lstrcpy lstrcpyA +#define lstrcat lstrcatA +#define lstrlen lstrlenA +#endif + + WINADVAPI DWORD WINAPI OpenEncryptedFileRawA(LPCSTR lpFileName,ULONG ulFlags,PVOID *pvContext); + WINADVAPI DWORD WINAPI OpenEncryptedFileRawW(LPCWSTR lpFileName,ULONG ulFlags,PVOID *pvContext); + WINADVAPI DWORD WINAPI ReadEncryptedFileRaw(PFE_EXPORT_FUNC pfExportCallback,PVOID pvCallbackContext,PVOID pvContext); + WINADVAPI DWORD WINAPI WriteEncryptedFileRaw(PFE_IMPORT_FUNC pfImportCallback,PVOID pvCallbackContext,PVOID pvContext); + WINADVAPI VOID WINAPI CloseEncryptedFileRaw(PVOID pvContext); + WINBASEAPI int WINAPI lstrcmpA(LPCSTR lpString1,LPCSTR lpString2); + WINBASEAPI int WINAPI lstrcmpW(LPCWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI int WINAPI lstrcmpiA(LPCSTR lpString1,LPCSTR lpString2); + WINBASEAPI int WINAPI lstrcmpiW(LPCWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI LPSTR WINAPI lstrcpynA(LPSTR lpString1,LPCSTR lpString2,int iMaxLength); + WINBASEAPI LPWSTR WINAPI lstrcpynW(LPWSTR lpString1,LPCWSTR lpString2,int iMaxLength); + WINBASEAPI LPSTR WINAPI lstrcpyA(LPSTR lpString1,LPCSTR lpString2); + WINBASEAPI LPWSTR WINAPI lstrcpyW(LPWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI LPSTR WINAPI lstrcatA(LPSTR lpString1,LPCSTR lpString2); + WINBASEAPI LPWSTR WINAPI lstrcatW(LPWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI int WINAPI lstrlenA(LPCSTR lpString); + WINBASEAPI int WINAPI lstrlenW(LPCWSTR lpString); + WINBASEAPI HFILE WINAPI OpenFile(LPCSTR lpFileName,LPOFSTRUCT lpReOpenBuff,UINT uStyle); + WINBASEAPI HFILE WINAPI _lopen(LPCSTR lpPathName,int iReadWrite); + WINBASEAPI HFILE WINAPI _lcreat(LPCSTR lpPathName,int iAttribute); + WINBASEAPI UINT WINAPI _lread(HFILE hFile,LPVOID lpBuffer,UINT uBytes); + WINBASEAPI UINT WINAPI _lwrite(HFILE hFile,LPCCH lpBuffer,UINT uBytes); + WINBASEAPI long WINAPI _hread(HFILE hFile,LPVOID lpBuffer,long lBytes); + WINBASEAPI long WINAPI _hwrite(HFILE hFile,LPCCH lpBuffer,long lBytes); + WINBASEAPI HFILE WINAPI _lclose(HFILE hFile); + WINBASEAPI LONG WINAPI _llseek(HFILE hFile,LONG lOffset,int iOrigin); + WINADVAPI WINBOOL WINAPI IsTextUnicode(CONST VOID *lpv,int iSize,LPINT lpiResult); + +#define FLS_OUT_OF_INDEXES ((DWORD)0xffffffff) + + WINBASEAPI DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); + WINBASEAPI PVOID WINAPI FlsGetValue(DWORD dwFlsIndex); + WINBASEAPI WINBOOL WINAPI FlsSetValue(DWORD dwFlsIndex,PVOID lpFlsData); + WINBASEAPI WINBOOL WINAPI FlsFree(DWORD dwFlsIndex); + +#define TLS_OUT_OF_INDEXES ((DWORD)0xffffffff) + + WINBASEAPI DWORD WINAPI TlsAlloc(VOID); + WINBASEAPI LPVOID WINAPI TlsGetValue(DWORD dwTlsIndex); + WINBASEAPI WINBOOL WINAPI TlsSetValue(DWORD dwTlsIndex,LPVOID lpTlsValue); + WINBASEAPI WINBOOL WINAPI TlsFree(DWORD dwTlsIndex); + + typedef VOID (WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped); + + WINBASEAPI DWORD WINAPI SleepEx(DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI DWORD WINAPI WaitForSingleObjectEx(HANDLE hHandle,DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI DWORD WINAPI WaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI DWORD WINAPI SignalObjectAndWait(HANDLE hObjectToSignal,HANDLE hObjectToWaitOn,DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI WINBOOL WINAPI ReadFileEx(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINBASEAPI WINBOOL WINAPI WriteFileEx(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINBASEAPI WINBOOL WINAPI BackupRead(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); + WINBASEAPI WINBOOL WINAPI BackupSeek(HANDLE hFile,DWORD dwLowBytesToSeek,DWORD dwHighBytesToSeek,LPDWORD lpdwLowByteSeeked,LPDWORD lpdwHighByteSeeked,LPVOID *lpContext); + WINBASEAPI WINBOOL WINAPI BackupWrite(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); + + typedef struct _WIN32_STREAM_ID { + DWORD dwStreamId; + DWORD dwStreamAttributes; + LARGE_INTEGER Size; + DWORD dwStreamNameSize; + WCHAR cStreamName[ANYSIZE_ARRAY]; + } WIN32_STREAM_ID,*LPWIN32_STREAM_ID; + +#define BACKUP_INVALID 0x0 +#define BACKUP_DATA 0x1 +#define BACKUP_EA_DATA 0x2 +#define BACKUP_SECURITY_DATA 0x3 +#define BACKUP_ALTERNATE_DATA 0x4 +#define BACKUP_LINK 0x5 +#define BACKUP_PROPERTY_DATA 0x6 +#define BACKUP_OBJECT_ID 0x7 +#define BACKUP_REPARSE_DATA 0x8 +#define BACKUP_SPARSE_BLOCK 0x9 + +#define STREAM_NORMAL_ATTRIBUTE 0x0 +#define STREAM_MODIFIED_WHEN_READ 0x1 +#define STREAM_CONTAINS_SECURITY 0x2 +#define STREAM_CONTAINS_PROPERTIES 0x4 +#define STREAM_SPARSE_ATTRIBUTE 0x8 + + WINBASEAPI WINBOOL WINAPI ReadFileScatter(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToRead,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI WriteFileGather(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToWrite,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); + +#define STARTF_USESHOWWINDOW 0x1 +#define STARTF_USESIZE 0x2 +#define STARTF_USEPOSITION 0x4 +#define STARTF_USECOUNTCHARS 0x8 +#define STARTF_USEFILLATTRIBUTE 0x10 +#define STARTF_RUNFULLSCREEN 0x20 +#define STARTF_FORCEONFEEDBACK 0x40 +#define STARTF_FORCEOFFFEEDBACK 0x80 +#define STARTF_USESTDHANDLES 0x100 + +#define STARTF_USEHOTKEY 0x200 + + typedef struct _STARTUPINFOA { + DWORD cb; + LPSTR lpReserved; + LPSTR lpDesktop; + LPSTR lpTitle; + DWORD dwX; + DWORD dwY; + DWORD dwXSize; + DWORD dwYSize; + DWORD dwXCountChars; + DWORD dwYCountChars; + DWORD dwFillAttribute; + DWORD dwFlags; + WORD wShowWindow; + WORD cbReserved2; + LPBYTE lpReserved2; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + } STARTUPINFOA,*LPSTARTUPINFOA; + + typedef struct _STARTUPINFOW { + DWORD cb; + LPWSTR lpReserved; + LPWSTR lpDesktop; + LPWSTR lpTitle; + DWORD dwX; + DWORD dwY; + DWORD dwXSize; + DWORD dwYSize; + DWORD dwXCountChars; + DWORD dwYCountChars; + DWORD dwFillAttribute; + DWORD dwFlags; + WORD wShowWindow; + WORD cbReserved2; + LPBYTE lpReserved2; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + } STARTUPINFOW,*LPSTARTUPINFOW; + +#ifdef UNICODE + typedef STARTUPINFOW STARTUPINFO; + typedef LPSTARTUPINFOW LPSTARTUPINFO; +#else + typedef STARTUPINFOA STARTUPINFO; + typedef LPSTARTUPINFOA LPSTARTUPINFO; +#endif + +#define SHUTDOWN_NORETRY 0x1 + + typedef struct _WIN32_FIND_DATAA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + CHAR cFileName[MAX_PATH]; + CHAR cAlternateFileName[14]; + } WIN32_FIND_DATAA,*PWIN32_FIND_DATAA,*LPWIN32_FIND_DATAA; + + typedef struct _WIN32_FIND_DATAW { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + WCHAR cFileName[MAX_PATH]; + WCHAR cAlternateFileName[14]; + } WIN32_FIND_DATAW,*PWIN32_FIND_DATAW,*LPWIN32_FIND_DATAW; + +#ifdef UNICODE + typedef WIN32_FIND_DATAW WIN32_FIND_DATA; + typedef PWIN32_FIND_DATAW PWIN32_FIND_DATA; + typedef LPWIN32_FIND_DATAW LPWIN32_FIND_DATA; +#else + typedef WIN32_FIND_DATAA WIN32_FIND_DATA; + typedef PWIN32_FIND_DATAA PWIN32_FIND_DATA; + typedef LPWIN32_FIND_DATAA LPWIN32_FIND_DATA; +#endif + + typedef struct _WIN32_FILE_ATTRIBUTE_DATA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + } WIN32_FILE_ATTRIBUTE_DATA,*LPWIN32_FILE_ATTRIBUTE_DATA; + +#ifdef UNICODE +#define CreateMutex CreateMutexW +#define OpenMutex OpenMutexW +#define CreateEvent CreateEventW +#define OpenEvent OpenEventW +#define CreateSemaphore CreateSemaphoreW +#define OpenSemaphore OpenSemaphoreW +#else +#define CreateMutex CreateMutexA +#define OpenMutex OpenMutexA +#define CreateEvent CreateEventA +#define OpenEvent OpenEventA +#define CreateSemaphore CreateSemaphoreA +#define OpenSemaphore OpenSemaphoreA +#endif + + WINBASEAPI HANDLE WINAPI CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenMutexA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenMutexW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenEventA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenEventW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenSemaphoreA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenSemaphoreW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + + typedef VOID (WINAPI *PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue); + +#ifdef UNICODE +#define CreateWaitableTimer CreateWaitableTimerW +#define OpenWaitableTimer OpenWaitableTimerW +#define CreateFileMapping CreateFileMappingW +#define OpenFileMapping OpenFileMappingW +#define GetLogicalDriveStrings GetLogicalDriveStringsW +#define LoadLibrary LoadLibraryW +#define LoadLibraryEx LoadLibraryExW +#define GetModuleFileName GetModuleFileNameW +#define GetModuleHandle GetModuleHandleW +#else +#define CreateWaitableTimer CreateWaitableTimerA +#define OpenWaitableTimer OpenWaitableTimerA +#define CreateFileMapping CreateFileMappingA +#define OpenFileMapping OpenFileMappingA +#define GetLogicalDriveStrings GetLogicalDriveStringsA +#define LoadLibrary LoadLibraryA +#define LoadLibraryEx LoadLibraryExA +#define GetModuleFileName GetModuleFileNameA +#define GetModuleHandle GetModuleHandleA +#endif + + WINBASEAPI HANDLE WINAPI CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCSTR lpTimerName); + WINBASEAPI HANDLE WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCWSTR lpTimerName); + WINBASEAPI HANDLE WINAPI OpenWaitableTimerA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpTimerName); + WINBASEAPI HANDLE WINAPI OpenWaitableTimerW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpTimerName); + WINBASEAPI WINBOOL WINAPI SetWaitableTimer(HANDLE hTimer,const LARGE_INTEGER *lpDueTime,LONG lPeriod,PTIMERAPCROUTINE pfnCompletionRoutine,LPVOID lpArgToCompletionRoutine,WINBOOL fResume); + WINBASEAPI WINBOOL WINAPI CancelWaitableTimer(HANDLE hTimer); + WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenFileMappingA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenFileMappingW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI DWORD WINAPI GetLogicalDriveStringsA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetLogicalDriveStringsW(DWORD nBufferLength,LPWSTR lpBuffer); + + typedef enum _MEMORY_RESOURCE_NOTIFICATION_TYPE { + LowMemoryResourceNotification,HighMemoryResourceNotification + } MEMORY_RESOURCE_NOTIFICATION_TYPE; + + WINBASEAPI HANDLE WINAPI CreateMemoryResourceNotification(MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType); + WINBASEAPI WINBOOL WINAPI QueryMemoryResourceNotification(HANDLE ResourceNotificationHandle,PBOOL ResourceState); + WINBASEAPI HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName); + WINBASEAPI HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName); + WINBASEAPI HMODULE WINAPI LoadLibraryExA(LPCSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); + WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); + +#define DONT_RESOLVE_DLL_REFERENCES 0x1 +#define LOAD_LIBRARY_AS_DATAFILE 0x2 +#define LOAD_WITH_ALTERED_SEARCH_PATH 0x8 +#define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x10 +#define LOAD_LINRARY_AS_IMAGE_RESOURCE 0x20 +#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x40 + + WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule,LPCH lpFilename,DWORD nSize); + WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE hModule,LPWCH lpFilename,DWORD nSize); + WINBASEAPI HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName); + WINBASEAPI HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName); + +#ifndef RC_INVOKED +#define GET_MODULE_HANDLE_EX_FLAG_PIN (0x1) +#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT (0x2) +#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS (0x4) + + typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXA)(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); + typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXW)(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); + +#ifdef UNICODE +#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXW +#define GetModuleHandleEx GetModuleHandleExW +#else +#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXA +#define GetModuleHandleEx GetModuleHandleExA +#endif + + WINBASEAPI WINBOOL WINAPI GetModuleHandleExA(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); + WINBASEAPI WINBOOL WINAPI GetModuleHandleExW(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); +#endif + +#ifdef UNICODE +#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathW +#define CreateProcess CreateProcessW +#define FatalAppExit FatalAppExitW +#define GetStartupInfo GetStartupInfoW +#define GetCommandLine GetCommandLineW +#define GetEnvironmentVariable GetEnvironmentVariableW +#define SetEnvironmentVariable SetEnvironmentVariableW +#define ExpandEnvironmentStrings ExpandEnvironmentStringsW +#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableW +#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableW +#define OutputDebugString OutputDebugStringW +#define FindResource FindResourceW +#define FindResourceEx FindResourceExW +#else +#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathA +#define CreateProcess CreateProcessA +#define FatalAppExit FatalAppExitA +#define GetStartupInfo GetStartupInfoA +#define GetCommandLine GetCommandLineA +#define GetEnvironmentVariable GetEnvironmentVariableA +#define SetEnvironmentVariable SetEnvironmentVariableA +#define ExpandEnvironmentStrings ExpandEnvironmentStringsA +#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableA +#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableA +#define OutputDebugString OutputDebugStringA +#define FindResource FindResourceA +#define FindResourceEx FindResourceExA +#endif + + WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathA(LPCSTR ExeName); + WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathW(LPCWSTR ExeName); + WINBASEAPI WINBOOL WINAPI CreateProcessA(LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINBASEAPI WINBOOL WINAPI CreateProcessW(LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameA(LPCSTR lpDnsFQHostname,ULONG ulFlags); + WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameW(LPCWSTR lpDnsFQHostname,ULONG ulFlags); + WINBASEAPI WINBOOL WINAPI SetProcessShutdownParameters(DWORD dwLevel,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI GetProcessShutdownParameters(LPDWORD lpdwLevel,LPDWORD lpdwFlags); + WINBASEAPI DWORD WINAPI GetProcessVersion(DWORD ProcessId); + WINBASEAPI VOID WINAPI FatalAppExitA(UINT uAction,LPCSTR lpMessageText); + WINBASEAPI VOID WINAPI FatalAppExitW(UINT uAction,LPCWSTR lpMessageText); + WINBASEAPI VOID WINAPI GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo); + WINBASEAPI VOID WINAPI GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo); + WINBASEAPI LPSTR WINAPI GetCommandLineA(VOID); + WINBASEAPI LPWSTR WINAPI GetCommandLineW(VOID); + WINBASEAPI DWORD WINAPI GetEnvironmentVariableA(LPCSTR lpName,LPSTR lpBuffer,DWORD nSize); + WINBASEAPI DWORD WINAPI GetEnvironmentVariableW(LPCWSTR lpName,LPWSTR lpBuffer,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableA(LPCSTR lpName,LPCSTR lpValue); + WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpValue); + WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsA(LPCSTR lpSrc,LPSTR lpDst,DWORD nSize); + WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsW(LPCWSTR lpSrc,LPWSTR lpDst,DWORD nSize); + WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pBuffer,DWORD nSize); + WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pBuffer,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pValue,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pValue,DWORD nSize); + WINBASEAPI VOID WINAPI OutputDebugStringA(LPCSTR lpOutputString); + WINBASEAPI VOID WINAPI OutputDebugStringW(LPCWSTR lpOutputString); + WINBASEAPI HRSRC WINAPI FindResourceA(HMODULE hModule,LPCSTR lpName,LPCSTR lpType); + WINBASEAPI HRSRC WINAPI FindResourceW(HMODULE hModule,LPCWSTR lpName,LPCWSTR lpType); + WINBASEAPI HRSRC WINAPI FindResourceExA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage); + WINBASEAPI HRSRC WINAPI FindResourceExW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage); + +#ifdef UNICODE +#define ENUMRESTYPEPROC ENUMRESTYPEPROCW +#define ENUMRESNAMEPROC ENUMRESNAMEPROCW +#define ENUMRESLANGPROC ENUMRESLANGPROCW +#define EnumResourceTypes EnumResourceTypesW +#define EnumResourceNames EnumResourceNamesW +#define EnumResourceLanguages EnumResourceLanguagesW +#define BeginUpdateResource BeginUpdateResourceW +#define UpdateResource UpdateResourceW +#define EndUpdateResource EndUpdateResourceW +#define GlobalAddAtom GlobalAddAtomW +#define GlobalFindAtom GlobalFindAtomW +#define GlobalGetAtomName GlobalGetAtomNameW +#define AddAtom AddAtomW +#define FindAtom FindAtomW +#define GetAtomName GetAtomNameW +#define GetProfileInt GetProfileIntW +#define GetProfileString GetProfileStringW +#define WriteProfileString WriteProfileStringW +#define GetProfileSection GetProfileSectionW +#define WriteProfileSection WriteProfileSectionW +#define GetPrivateProfileInt GetPrivateProfileIntW +#define GetPrivateProfileString GetPrivateProfileStringW +#define WritePrivateProfileString WritePrivateProfileStringW +#define GetPrivateProfileSection GetPrivateProfileSectionW +#define WritePrivateProfileSection WritePrivateProfileSectionW +#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesW +#define GetPrivateProfileStruct GetPrivateProfileStructW +#define WritePrivateProfileStruct WritePrivateProfileStructW +#define GetDriveType GetDriveTypeW +#define GetSystemDirectory GetSystemDirectoryW +#define GetTempPath GetTempPathW +#define GetTempFileName GetTempFileNameW +#define GetWindowsDirectory GetWindowsDirectoryW +#define GetSystemWindowsDirectory GetSystemWindowsDirectoryW +#define AddLocalAlternateComputerName AddLocalAlternateComputerNameW +#else +#define ENUMRESTYPEPROC ENUMRESTYPEPROCA +#define ENUMRESNAMEPROC ENUMRESNAMEPROCA +#define ENUMRESLANGPROC ENUMRESLANGPROCA +#define EnumResourceTypes EnumResourceTypesA +#define EnumResourceNames EnumResourceNamesA +#define EnumResourceLanguages EnumResourceLanguagesA +#define BeginUpdateResource BeginUpdateResourceA +#define UpdateResource UpdateResourceA +#define EndUpdateResource EndUpdateResourceA +#define GlobalAddAtom GlobalAddAtomA +#define GlobalFindAtom GlobalFindAtomA +#define GlobalGetAtomName GlobalGetAtomNameA +#define AddAtom AddAtomA +#define FindAtom FindAtomA +#define GetAtomName GetAtomNameA +#define GetProfileInt GetProfileIntA +#define GetProfileString GetProfileStringA +#define WriteProfileString WriteProfileStringA +#define GetProfileSection GetProfileSectionA +#define WriteProfileSection WriteProfileSectionA +#define GetPrivateProfileInt GetPrivateProfileIntA +#define GetPrivateProfileString GetPrivateProfileStringA +#define WritePrivateProfileString WritePrivateProfileStringA +#define GetPrivateProfileSection GetPrivateProfileSectionA +#define WritePrivateProfileSection WritePrivateProfileSectionA +#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesA +#define GetPrivateProfileStruct GetPrivateProfileStructA +#define WritePrivateProfileStruct WritePrivateProfileStructA +#define GetDriveType GetDriveTypeA +#define GetSystemDirectory GetSystemDirectoryA +#define GetTempPath GetTempPathA +#define GetTempFileName GetTempFileNameA +#define GetWindowsDirectory GetWindowsDirectoryA +#define GetSystemWindowsDirectory GetSystemWindowsDirectoryA +#define AddLocalAlternateComputerName AddLocalAlternateComputerNameA +#endif + + typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCA)(HMODULE hModule,LPSTR lpType,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCW)(HMODULE hModule,LPWSTR lpType,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCA)(HMODULE hModule,LPCSTR lpType,LPSTR lpName,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCW)(HMODULE hModule,LPCWSTR lpType,LPWSTR lpName,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESLANGPROCA)(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESLANGPROCW)(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LONG_PTR lParam); + + WINBASEAPI WINBOOL WINAPI EnumResourceTypesA(HMODULE hModule,ENUMRESTYPEPROCA lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceTypesW(HMODULE hModule,ENUMRESTYPEPROCW lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceNamesA(HMODULE hModule,LPCSTR lpType,ENUMRESNAMEPROCA lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceNamesW(HMODULE hModule,LPCWSTR lpType,ENUMRESNAMEPROCW lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,ENUMRESLANGPROCA lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,ENUMRESLANGPROCW lpEnumFunc,LONG_PTR lParam); + WINBASEAPI HANDLE WINAPI BeginUpdateResourceA(LPCSTR pFileName,WINBOOL bDeleteExistingResources); + WINBASEAPI HANDLE WINAPI BeginUpdateResourceW(LPCWSTR pFileName,WINBOOL bDeleteExistingResources); + WINBASEAPI WINBOOL WINAPI UpdateResourceA(HANDLE hUpdate,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); + WINBASEAPI WINBOOL WINAPI UpdateResourceW(HANDLE hUpdate,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); + WINBASEAPI WINBOOL WINAPI EndUpdateResourceA(HANDLE hUpdate,WINBOOL fDiscard); + WINBASEAPI WINBOOL WINAPI EndUpdateResourceW(HANDLE hUpdate,WINBOOL fDiscard); + WINBASEAPI ATOM WINAPI GlobalAddAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI GlobalAddAtomW(LPCWSTR lpString); + WINBASEAPI ATOM WINAPI GlobalFindAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI GlobalFindAtomW(LPCWSTR lpString); + WINBASEAPI UINT WINAPI GlobalGetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); + WINBASEAPI UINT WINAPI GlobalGetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); + WINBASEAPI ATOM WINAPI AddAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI AddAtomW(LPCWSTR lpString); + WINBASEAPI ATOM WINAPI FindAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI FindAtomW(LPCWSTR lpString); + WINBASEAPI UINT WINAPI GetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); + WINBASEAPI UINT WINAPI GetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); + WINBASEAPI UINT WINAPI GetProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault); + WINBASEAPI UINT WINAPI GetProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault); + WINBASEAPI DWORD WINAPI GetProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize); + WINBASEAPI DWORD WINAPI GetProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize); + WINBASEAPI WINBOOL WINAPI WriteProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString); + WINBASEAPI WINBOOL WINAPI WriteProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString); + WINBASEAPI DWORD WINAPI GetProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize); + WINBASEAPI DWORD WINAPI GetProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize); + WINBASEAPI WINBOOL WINAPI WriteProfileSectionA(LPCSTR lpAppName,LPCSTR lpString); + WINBASEAPI WINBOOL WINAPI WriteProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString); + WINBASEAPI UINT WINAPI GetPrivateProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault,LPCSTR lpFileName); + WINBASEAPI UINT WINAPI GetPrivateProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault,LPCWSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString,LPCSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString,LPCWSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionA(LPCSTR lpAppName,LPCSTR lpString,LPCSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString,LPCWSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesA(LPSTR lpszReturnBuffer,DWORD nSize,LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesW(LPWSTR lpszReturnBuffer,DWORD nSize,LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); + WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); + WINBASEAPI UINT WINAPI GetDriveTypeA(LPCSTR lpRootPathName); + WINBASEAPI UINT WINAPI GetDriveTypeW(LPCWSTR lpRootPathName); + WINBASEAPI UINT WINAPI GetSystemDirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemDirectoryW(LPWSTR lpBuffer,UINT uSize); + WINBASEAPI DWORD WINAPI GetTempPathA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetTempPathW(DWORD nBufferLength,LPWSTR lpBuffer); + WINBASEAPI UINT WINAPI GetTempFileNameA(LPCSTR lpPathName,LPCSTR lpPrefixString,UINT uUnique,LPSTR lpTempFileName); + WINBASEAPI UINT WINAPI GetTempFileNameW(LPCWSTR lpPathName,LPCWSTR lpPrefixString,UINT uUnique,LPWSTR lpTempFileName); + WINBASEAPI UINT WINAPI GetWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); + +#ifndef RC_INVOKED +#ifdef UNICODE +#define GetSystemWow64Directory GetSystemWow64DirectoryW +#else +#define GetSystemWow64Directory GetSystemWow64DirectoryA +#endif + + WINBASEAPI UINT WINAPI GetSystemWow64DirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemWow64DirectoryW(LPWSTR lpBuffer,UINT uSize); + WINBASEAPI BOOLEAN WINAPI Wow64EnableWow64FsRedirection(BOOLEAN Wow64FsEnableRedirection); + WINBASEAPI WINBOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue); + WINBASEAPI WINBOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OlValue); + + typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_A)(LPSTR lpBuffer,UINT uSize); + typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_W)(LPWSTR lpBuffer,UINT uSize); + +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A "GetSystemWow64DirectoryA" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W L"GetSystemWow64DirectoryA" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T TEXT("GetSystemWow64DirectoryA") +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A "GetSystemWow64DirectoryW" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W L"GetSystemWow64DirectoryW" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T TEXT("GetSystemWow64DirectoryW") + +#ifdef UNICODE +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T +#else +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T +#endif +#endif + +#ifdef UNICODE +#define SetCurrentDirectory SetCurrentDirectoryW +#define GetCurrentDirectory GetCurrentDirectoryW +#define SetDllDirectory SetDllDirectoryW +#define GetDllDirectory GetDllDirectoryW +#define GetDiskFreeSpace GetDiskFreeSpaceW +#define GetDiskFreeSpaceEx GetDiskFreeSpaceExW +#define CreateDirectory CreateDirectoryW +#define CreateDirectoryEx CreateDirectoryExW +#define RemoveDirectory RemoveDirectoryW +#define GetFullPathName GetFullPathNameW +#define DefineDosDevice DefineDosDeviceW +#define QueryDosDevice QueryDosDeviceW +#define CreateFile CreateFileW +#define SetFileAttributes SetFileAttributesW +#define GetFileAttributes GetFileAttributesW +#else +#define SetCurrentDirectory SetCurrentDirectoryA +#define GetCurrentDirectory GetCurrentDirectoryA +#define SetDllDirectory SetDllDirectoryA +#define GetDllDirectory GetDllDirectoryA +#define GetDiskFreeSpace GetDiskFreeSpaceA +#define GetDiskFreeSpaceEx GetDiskFreeSpaceExA +#define CreateDirectory CreateDirectoryA +#define CreateDirectoryEx CreateDirectoryExA +#define RemoveDirectory RemoveDirectoryA +#define GetFullPathName GetFullPathNameA +#define DefineDosDevice DefineDosDeviceA +#define QueryDosDevice QueryDosDeviceA +#define CreateFile CreateFileA +#define SetFileAttributes SetFileAttributesA +#define GetFileAttributes GetFileAttributesA +#endif + + WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryA(LPCSTR lpPathName); + WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryW(LPCWSTR lpPathName); + WINBASEAPI DWORD WINAPI GetCurrentDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetCurrentDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI SetDllDirectoryA(LPCSTR lpPathName); + WINBASEAPI WINBOOL WINAPI SetDllDirectoryW(LPCWSTR lpPathName); + WINBASEAPI DWORD WINAPI GetDllDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetDllDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceA(LPCSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceW(LPCWSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExA(LPCSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExW(LPCWSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryA(LPCSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryW(LPCWSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryExA(LPCSTR lpTemplateDirectory,LPCSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryExW(LPCWSTR lpTemplateDirectory,LPCWSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI RemoveDirectoryA(LPCSTR lpPathName); + WINBASEAPI WINBOOL WINAPI RemoveDirectoryW(LPCWSTR lpPathName); + WINBASEAPI DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); + WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); + +#define DDD_RAW_TARGET_PATH 0x1 +#define DDD_REMOVE_DEFINITION 0x2 +#define DDD_EXACT_MATCH_ON_REMOVE 0x4 +#define DDD_NO_BROADCAST_SYSTEM 0x8 +#define DDD_LUID_BROADCAST_DRIVE 0x10 + + WINBASEAPI WINBOOL WINAPI DefineDosDeviceA(DWORD dwFlags,LPCSTR lpDeviceName,LPCSTR lpTargetPath); + WINBASEAPI WINBOOL WINAPI DefineDosDeviceW(DWORD dwFlags,LPCWSTR lpDeviceName,LPCWSTR lpTargetPath); + WINBASEAPI DWORD WINAPI QueryDosDeviceA(LPCSTR lpDeviceName,LPSTR lpTargetPath,DWORD ucchMax); + WINBASEAPI DWORD WINAPI QueryDosDeviceW(LPCWSTR lpDeviceName,LPWSTR lpTargetPath,DWORD ucchMax); + +#define EXPAND_LOCAL_DRIVES + + WINBASEAPI HANDLE WINAPI CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); + WINBASEAPI HANDLE WINAPI CreateFileW(LPCWSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); + WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE hOriginalFile,DWORD dwDesiredAccess,DWORD dwShareMode,DWORD dwFlagsAndAttributes); + WINBASEAPI WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName,DWORD dwFileAttributes); + WINBASEAPI WINBOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName,DWORD dwFileAttributes); + WINBASEAPI DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName); + + typedef enum _GET_FILEEX_INFO_LEVELS { + GetFileExInfoStandard,GetFileExMaxInfoLevel + } GET_FILEEX_INFO_LEVELS; + +#ifdef UNICODE +#define GetFileAttributesEx GetFileAttributesExW +#define GetCompressedFileSize GetCompressedFileSizeW +#define DeleteFile DeleteFileW +#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3W +#else +#define GetFileAttributesEx GetFileAttributesExA +#define GetCompressedFileSize GetCompressedFileSizeA +#define DeleteFile DeleteFileA +#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3A +#endif + + WINBASEAPI WINBOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); + WINBASEAPI WINBOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); + WINBASEAPI DWORD WINAPI GetCompressedFileSizeA(LPCSTR lpFileName,LPDWORD lpFileSizeHigh); + WINBASEAPI DWORD WINAPI GetCompressedFileSizeW(LPCWSTR lpFileName,LPDWORD lpFileSizeHigh); + WINBASEAPI WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName); + WINBASEAPI WINBOOL WINAPI DeleteFileW(LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3A(LPCSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); + WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3W(LPCWSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); + + typedef enum _FINDEX_INFO_LEVELS { + FindExInfoStandard,FindExInfoMaxInfoLevel + } FINDEX_INFO_LEVELS; + + typedef enum _FINDEX_SEARCH_OPS { + FindExSearchNameMatch,FindExSearchLimitToDirectories,FindExSearchLimitToDevices,FindExSearchMaxSearchOp + } FINDEX_SEARCH_OPS; + +#define FIND_FIRST_EX_CASE_SENSITIVE 0x1 + +#ifdef UNICODE +#define FindFirstFileEx FindFirstFileExW +#define FindFirstFile FindFirstFileW +#define FindNextFile FindNextFileW +#define SearchPath SearchPathW +#define CopyFile CopyFileW +#define CopyFileEx CopyFileExW +#define MoveFile MoveFileW +#define MoveFileEx MoveFileExW +#define MoveFileWithProgress MoveFileWithProgressW +#define ReplaceFile ReplaceFileW +#define CreateHardLink CreateHardLinkW +#define CreateNamedPipe CreateNamedPipeW +#define GetNamedPipeHandleState GetNamedPipeHandleStateW +#define CallNamedPipe CallNamedPipeW +#define WaitNamedPipe WaitNamedPipeW +#define SetVolumeLabel SetVolumeLabelW +#define GetVolumeInformation GetVolumeInformationW +#define ClearEventLog ClearEventLogW +#define BackupEventLog BackupEventLogW +#define OpenEventLog OpenEventLogW +#define RegisterEventSource RegisterEventSourceW +#define OpenBackupEventLog OpenBackupEventLogW +#define ReadEventLog ReadEventLogW +#define ReportEvent ReportEventW +#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmW +#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmW +#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmW +#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleW +#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmW +#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmW +#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmW +#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmW +#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmW +#define SetFileSecurity SetFileSecurityW +#define GetFileSecurity GetFileSecurityW +#define FindFirstChangeNotification FindFirstChangeNotificationW +#define IsBadStringPtr IsBadStringPtrW +#define LookupAccountSid LookupAccountSidW +#define LookupAccountName LookupAccountNameW +#define LookupPrivilegeValue LookupPrivilegeValueW +#define LookupPrivilegeName LookupPrivilegeNameW +#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameW +#define BuildCommDCB BuildCommDCBW +#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW +#define CommConfigDialog CommConfigDialogW +#define GetDefaultCommConfig GetDefaultCommConfigW +#define SetDefaultCommConfig SetDefaultCommConfigW +#define GetComputerName GetComputerNameW +#define SetComputerName SetComputerNameW +#define GetComputerNameEx GetComputerNameExW +#define SetComputerNameEx SetComputerNameExW +#define DnsHostnameToComputerName DnsHostnameToComputerNameW +#define GetUserName GetUserNameW +#else +#define FindFirstFileEx FindFirstFileExA +#define FindFirstFile FindFirstFileA +#define FindNextFile FindNextFileA +#define SearchPath SearchPathA +#define CopyFile CopyFileA +#define CopyFileEx CopyFileExA +#define MoveFile MoveFileA +#define MoveFileEx MoveFileExA +#define MoveFileWithProgress MoveFileWithProgressA +#define ReplaceFile ReplaceFileA +#define CreateHardLink CreateHardLinkA +#define CreateNamedPipe CreateNamedPipeA +#define GetNamedPipeHandleState GetNamedPipeHandleStateA +#define CallNamedPipe CallNamedPipeA +#define WaitNamedPipe WaitNamedPipeA +#define SetVolumeLabel SetVolumeLabelA +#define GetVolumeInformation GetVolumeInformationA +#define ClearEventLog ClearEventLogA +#define BackupEventLog BackupEventLogA +#define OpenEventLog OpenEventLogA +#define RegisterEventSource RegisterEventSourceA +#define OpenBackupEventLog OpenBackupEventLogA +#define ReadEventLog ReadEventLogA +#define ReportEvent ReportEventA +#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmA +#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmA +#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmA +#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleA +#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmA +#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmA +#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmA +#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmA +#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmA +#define SetFileSecurity SetFileSecurityA +#define GetFileSecurity GetFileSecurityA +#define FindFirstChangeNotification FindFirstChangeNotificationA +#define IsBadStringPtr IsBadStringPtrA +#define LookupAccountSid LookupAccountSidA +#define LookupAccountName LookupAccountNameA +#define LookupPrivilegeValue LookupPrivilegeValueA +#define LookupPrivilegeName LookupPrivilegeNameA +#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameA +#define BuildCommDCB BuildCommDCBA +#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA +#define CommConfigDialog CommConfigDialogA +#define GetDefaultCommConfig GetDefaultCommConfigA +#define SetDefaultCommConfig SetDefaultCommConfigA +#define GetComputerName GetComputerNameA +#define SetComputerName SetComputerNameA +#define GetComputerNameEx GetComputerNameExA +#define SetComputerNameEx SetComputerNameExA +#define DnsHostnameToComputerName DnsHostnameToComputerNameA +#define GetUserName GetUserNameA +#endif + + WINBASEAPI HANDLE WINAPI FindFirstFileExA(LPCSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); + WINBASEAPI HANDLE WINAPI FindFirstFileExW(LPCWSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); + WINBASEAPI HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName,LPWIN32_FIND_DATAA lpFindFileData); + WINBASEAPI HANDLE WINAPI FindFirstFileW(LPCWSTR lpFileName,LPWIN32_FIND_DATAW lpFindFileData); + WINBASEAPI WINBOOL WINAPI FindNextFileA(HANDLE hFindFile,LPWIN32_FIND_DATAA lpFindFileData); + WINBASEAPI WINBOOL WINAPI FindNextFileW(HANDLE hFindFile,LPWIN32_FIND_DATAW lpFindFileData); + WINBASEAPI DWORD WINAPI SearchPathA(LPCSTR lpPath,LPCSTR lpFileName,LPCSTR lpExtension,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); + WINBASEAPI DWORD WINAPI SearchPathW(LPCWSTR lpPath,LPCWSTR lpFileName,LPCWSTR lpExtension,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); + WINBASEAPI WINBOOL WINAPI CopyFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,WINBOOL bFailIfExists); + WINBASEAPI WINBOOL WINAPI CopyFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,WINBOOL bFailIfExists); + + typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER TotalFileSize,LARGE_INTEGER TotalBytesTransferred,LARGE_INTEGER StreamSize,LARGE_INTEGER StreamBytesTransferred,DWORD dwStreamNumber,DWORD dwCallbackReason,HANDLE hSourceFile,HANDLE hDestinationFile,LPVOID lpData); + + WINBASEAPI WINBOOL WINAPI CopyFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); + WINBASEAPI WINBOOL WINAPI CopyFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); + WINBASEAPI WINBOOL WINAPI MoveFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName); + WINBASEAPI WINBOOL WINAPI MoveFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName); + WINBASEAPI WINBOOL WINAPI MoveFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI MoveFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI MoveFileWithProgressA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI MoveFileWithProgressW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); + +#define MOVEFILE_REPLACE_EXISTING 0x1 +#define MOVEFILE_COPY_ALLOWED 0x2 +#define MOVEFILE_DELAY_UNTIL_REBOOT 0x4 +#define MOVEFILE_WRITE_THROUGH 0x8 +#define MOVEFILE_CREATE_HARDLINK 0x10 +#define MOVEFILE_FAIL_IF_NOT_TRACKABLE 0x20 + + WINBASEAPI WINBOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,LPCSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,LPCWSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI CreateHardLinkA(LPCSTR lpFileName,LPCSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateHardLinkW(LPCWSTR lpFileName,LPCWSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + + typedef enum _STREAM_INFO_LEVELS { + FindStreamInfoStandard,FindStreamInfoMaxInfoLevel + } STREAM_INFO_LEVELS; + + typedef struct _WIN32_FIND_STREAM_DATA { + LARGE_INTEGER StreamSize; + WCHAR cStreamName[MAX_PATH + 36]; + } WIN32_FIND_STREAM_DATA,*PWIN32_FIND_STREAM_DATA; + + HANDLE WINAPI FindFirstStreamW(LPCWSTR lpFileName,STREAM_INFO_LEVELS InfoLevel,LPVOID lpFindStreamData,DWORD dwFlags); + WINBOOL WINAPI FindNextStreamW(HANDLE hFindStream,LPVOID lpFindStreamData); + WINBASEAPI HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI HANDLE WINAPI CreateNamedPipeW(LPCWSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateA(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPSTR lpUserName,DWORD nMaxUserNameSize); + WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateW(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPWSTR lpUserName,DWORD nMaxUserNameSize); + WINBASEAPI WINBOOL WINAPI CallNamedPipeA(LPCSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI CallNamedPipeW(LPCWSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI WaitNamedPipeA(LPCSTR lpNamedPipeName,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI WaitNamedPipeW(LPCWSTR lpNamedPipeName,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI SetVolumeLabelA(LPCSTR lpRootPathName,LPCSTR lpVolumeName); + WINBASEAPI WINBOOL WINAPI SetVolumeLabelW(LPCWSTR lpRootPathName,LPCWSTR lpVolumeName); + WINBASEAPI VOID WINAPI SetFileApisToOEM(VOID); + WINBASEAPI VOID WINAPI SetFileApisToANSI(VOID); + WINBASEAPI WINBOOL WINAPI AreFileApisANSI(VOID); + WINBASEAPI WINBOOL WINAPI GetVolumeInformationA(LPCSTR lpRootPathName,LPSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); + WINBASEAPI WINBOOL WINAPI GetVolumeInformationW(LPCWSTR lpRootPathName,LPWSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPWSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); + WINBASEAPI WINBOOL WINAPI CancelIo(HANDLE hFile); + WINADVAPI WINBOOL WINAPI ClearEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI ClearEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI BackupEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI BackupEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI CloseEventLog(HANDLE hEventLog); + WINADVAPI WINBOOL WINAPI DeregisterEventSource(HANDLE hEventLog); + WINADVAPI WINBOOL WINAPI NotifyChangeEventLog(HANDLE hEventLog,HANDLE hEvent); + WINADVAPI WINBOOL WINAPI GetNumberOfEventLogRecords(HANDLE hEventLog,PDWORD NumberOfRecords); + WINADVAPI WINBOOL WINAPI GetOldestEventLogRecord(HANDLE hEventLog,PDWORD OldestRecord); + WINADVAPI HANDLE WINAPI OpenEventLogA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); + WINADVAPI HANDLE WINAPI OpenEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); + WINADVAPI HANDLE WINAPI RegisterEventSourceA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); + WINADVAPI HANDLE WINAPI RegisterEventSourceW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); + WINADVAPI HANDLE WINAPI OpenBackupEventLogA(LPCSTR lpUNCServerName,LPCSTR lpFileName); + WINADVAPI HANDLE WINAPI OpenBackupEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpFileName); + WINADVAPI WINBOOL WINAPI ReadEventLogA(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); + WINADVAPI WINBOOL WINAPI ReadEventLogW(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); + WINADVAPI WINBOOL WINAPI ReportEventA(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCSTR *lpStrings,LPVOID lpRawData); + WINADVAPI WINBOOL WINAPI ReportEventW(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCWSTR *lpStrings,LPVOID lpRawData); + +#define EVENTLOG_FULL_INFO 0 + + typedef struct _EVENTLOG_FULL_INFORMATION { + DWORD dwFull; + } EVENTLOG_FULL_INFORMATION,*LPEVENTLOG_FULL_INFORMATION; + + WINADVAPI WINBOOL WINAPI GetEventLogInformation(HANDLE hEventLog,DWORD dwInfoLevel,LPVOID lpBuffer,DWORD cbBufSize,LPDWORD pcbBytesNeeded); + WINADVAPI WINBOOL WINAPI DuplicateToken(HANDLE ExistingTokenHandle,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,PHANDLE DuplicateTokenHandle); + WINADVAPI WINBOOL WINAPI GetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); + WINADVAPI WINBOOL WINAPI ImpersonateNamedPipeClient(HANDLE hNamedPipe); + WINADVAPI WINBOOL WINAPI ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel); + WINADVAPI WINBOOL WINAPI RevertToSelf(VOID); + WINADVAPI WINBOOL WINAPI SetThreadToken (PHANDLE Thread,HANDLE Token); + WINADVAPI WINBOOL WINAPI AccessCheck(PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); + WINADVAPI WINBOOL WINAPI AccessCheckByType(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultList(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccessList,LPDWORD AccessStatusList); + WINADVAPI WINBOOL WINAPI OpenProcessToken(HANDLE ProcessHandle,DWORD DesiredAccess,PHANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI OpenThreadToken(HANDLE ThreadHandle,DWORD DesiredAccess,WINBOOL OpenAsSelf,PHANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI GetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI SetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength); + WINADVAPI WINBOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle,WINBOOL DisableAllPrivileges,PTOKEN_PRIVILEGES NewState,DWORD BufferLength,PTOKEN_PRIVILEGES PreviousState,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI AdjustTokenGroups(HANDLE TokenHandle,WINBOOL ResetToDefault,PTOKEN_GROUPS NewState,DWORD BufferLength,PTOKEN_GROUPS PreviousState,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI PrivilegeCheck(HANDLE ClientToken,PPRIVILEGE_SET RequiredPrivileges,LPBOOL pfResult); + WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmA(LPCSTR SubsystemName,LPCSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmW(LPCWSTR SubsystemName,LPCWSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI IsWellKnownSid(PSID pSid,WELL_KNOWN_SID_TYPE WellKnownSidType); + WINADVAPI WINBOOL WINAPI CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType,PSID DomainSid,PSID pSid,DWORD *cbSid); + WINADVAPI WINBOOL WINAPI EqualDomainSid(PSID pSid1,PSID pSid2,WINBOOL *pfEqual); + WINADVAPI WINBOOL WINAPI GetWindowsAccountDomainSid(PSID pSid,PSID pDomainSid,DWORD *cbDomainSid); + WINADVAPI WINBOOL WINAPI IsValidSid(PSID pSid); + WINADVAPI WINBOOL WINAPI EqualSid(PSID pSid1,PSID pSid2); + WINADVAPI WINBOOL WINAPI EqualPrefixSid(PSID pSid1,PSID pSid2); + WINADVAPI DWORD WINAPI GetSidLengthRequired (UCHAR nSubAuthorityCount); + WINADVAPI WINBOOL WINAPI AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount,DWORD nSubAuthority0,DWORD nSubAuthority1,DWORD nSubAuthority2,DWORD nSubAuthority3,DWORD nSubAuthority4,DWORD nSubAuthority5,DWORD nSubAuthority6,DWORD nSubAuthority7,PSID *pSid); + WINADVAPI PVOID WINAPI FreeSid(PSID pSid); + WINADVAPI WINBOOL WINAPI InitializeSid(PSID Sid,PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount); + WINADVAPI PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid); + WINADVAPI PDWORD WINAPI GetSidSubAuthority(PSID pSid,DWORD nSubAuthority); + WINADVAPI PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid); + WINADVAPI DWORD WINAPI GetLengthSid(PSID pSid); + WINADVAPI WINBOOL WINAPI CopySid(DWORD nDestinationSidLength,PSID pDestinationSid,PSID pSourceSid); + WINADVAPI WINBOOL WINAPI AreAllAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); + WINADVAPI WINBOOL WINAPI AreAnyAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); + WINADVAPI VOID WINAPI MapGenericMask(PDWORD AccessMask,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI IsValidAcl(PACL pAcl); + WINADVAPI WINBOOL WINAPI InitializeAcl(PACL pAcl,DWORD nAclLength,DWORD dwAclRevision); + WINADVAPI WINBOOL WINAPI GetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); + WINADVAPI WINBOOL WINAPI SetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); + WINADVAPI WINBOOL WINAPI AddAce(PACL pAcl,DWORD dwAceRevision,DWORD dwStartingAceIndex,LPVOID pAceList,DWORD nAceListLength); + WINADVAPI WINBOOL WINAPI DeleteAce(PACL pAcl,DWORD dwAceIndex); + WINADVAPI WINBOOL WINAPI GetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce); + WINADVAPI WINBOOL WINAPI AddAccessAllowedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessAllowedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessDeniedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessDeniedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAuditAccessAce(PACL pAcl,DWORD dwAceRevision,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); + WINADVAPI WINBOOL WINAPI AddAuditAccessAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); + WINADVAPI WINBOOL WINAPI AddAccessAllowedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessDeniedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAuditAccessObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); + WINADVAPI WINBOOL WINAPI FindFirstFreeAce(PACL pAcl,LPVOID *pAce); + WINADVAPI WINBOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD dwRevision); + WINADVAPI WINBOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI DWORD WINAPI GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSECURITY_DESCRIPTOR_CONTROL pControl,LPDWORD lpdwRevision); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bDaclPresent,PACL pDacl,WINBOOL bDaclDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbDaclPresent,PACL *pDacl,LPBOOL lpbDaclDefaulted); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bSaclPresent,PACL pSacl,WINBOOL bSaclDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbSaclPresent,PACL *pSacl,LPBOOL lpbSaclDefaulted); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pOwner,WINBOOL bOwnerDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pOwner,LPBOOL lpbOwnerDefaulted); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pGroup,WINBOOL bGroupDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pGroup,LPBOOL lpbGroupDefaulted); + WINADVAPI DWORD WINAPI SetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); + WINADVAPI DWORD WINAPI GetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); + WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,WINBOOL IsDirectoryObject,HANDLE Token,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI ConvertToAutoInheritPrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CurrentSecurityDescriptor,PSECURITY_DESCRIPTOR *NewSecurityDescriptor,GUID *ObjectType,BOOLEAN IsDirectoryObject,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityEx(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID *ObjectType,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityWithMultipleInheritance(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID **ObjectTypes,ULONG GuidCount,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurity (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,PGENERIC_MAPPING GenericMapping,HANDLE Token); + WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurityEx (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,ULONG AutoInheritFlags,PGENERIC_MAPPING GenericMapping,HANDLE Token); + WINADVAPI WINBOOL WINAPI GetPrivateObjectSecurity(PSECURITY_DESCRIPTOR ObjectDescriptor,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ResultantDescriptor,DWORD DescriptorLength,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI DestroyPrivateObjectSecurity(PSECURITY_DESCRIPTOR *ObjectDescriptor); + WINADVAPI WINBOOL WINAPI MakeSelfRelativeSD(PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferLength); + WINADVAPI WINBOOL WINAPI MakeAbsoluteSD(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,LPDWORD lpdwAbsoluteSecurityDescriptorSize,PACL pDacl,LPDWORD lpdwDaclSize,PACL pSacl,LPDWORD lpdwSaclSize,PSID pOwner,LPDWORD lpdwOwnerSize,PSID pPrimaryGroup,LPDWORD lpdwPrimaryGroupSize); + WINADVAPI WINBOOL WINAPI MakeAbsoluteSD2(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferSize); + WINADVAPI WINBOOL WINAPI SetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI WINBOOL WINAPI SetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI WINBOOL WINAPI GetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); + WINADVAPI WINBOOL WINAPI GetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); + WINADVAPI WINBOOL WINAPI SetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR SecurityDescriptor); + WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationA(LPCSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); + WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationW(LPCWSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); + WINBASEAPI WINBOOL WINAPI FindNextChangeNotification(HANDLE hChangeHandle); + WINBASEAPI WINBOOL WINAPI FindCloseChangeNotification(HANDLE hChangeHandle); + WINBASEAPI WINBOOL WINAPI ReadDirectoryChangesW(HANDLE hDirectory,LPVOID lpBuffer,DWORD nBufferLength,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINBASEAPI WINBOOL WINAPI VirtualLock(LPVOID lpAddress,SIZE_T dwSize); + WINBASEAPI WINBOOL WINAPI VirtualUnlock(LPVOID lpAddress,SIZE_T dwSize); + WINBASEAPI LPVOID WINAPI MapViewOfFileEx(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap,LPVOID lpBaseAddress); + WINBASEAPI WINBOOL WINAPI SetPriorityClass(HANDLE hProcess,DWORD dwPriorityClass); + WINBASEAPI DWORD WINAPI GetPriorityClass(HANDLE hProcess); + WINBASEAPI WINBOOL WINAPI IsBadReadPtr(CONST VOID *lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadWritePtr(LPVOID lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadHugeReadPtr(CONST VOID *lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadHugeWritePtr(LPVOID lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadCodePtr(FARPROC lpfn); + WINBASEAPI WINBOOL WINAPI IsBadStringPtrA(LPCSTR lpsz,UINT_PTR ucchMax); + WINBASEAPI WINBOOL WINAPI IsBadStringPtrW(LPCWSTR lpsz,UINT_PTR ucchMax); + WINADVAPI WINBOOL WINAPI LookupAccountSidA(LPCSTR lpSystemName,PSID Sid,LPSTR Name,LPDWORD cchName,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName,PSID Sid,LPWSTR Name,LPDWORD cchName,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupAccountNameA(LPCSTR lpSystemName,LPCSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupAccountNameW(LPCWSTR lpSystemName,LPCWSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName,LPCSTR lpName,PLUID lpLuid); + WINADVAPI WINBOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName,LPCWSTR lpName,PLUID lpLuid); + WINADVAPI WINBOOL WINAPI LookupPrivilegeNameA(LPCSTR lpSystemName,PLUID lpLuid,LPSTR lpName,LPDWORD cchName); + WINADVAPI WINBOOL WINAPI LookupPrivilegeNameW(LPCWSTR lpSystemName,PLUID lpLuid,LPWSTR lpName,LPDWORD cchName); + WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameA(LPCSTR lpSystemName,LPCSTR lpName,LPSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); + WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameW(LPCWSTR lpSystemName,LPCWSTR lpName,LPWSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); + WINADVAPI WINBOOL WINAPI AllocateLocallyUniqueId(PLUID Luid); + WINBASEAPI WINBOOL WINAPI BuildCommDCBA(LPCSTR lpDef,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI BuildCommDCBW(LPCWSTR lpDef,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsW(LPCWSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI CommConfigDialogA(LPCSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); + WINBASEAPI WINBOOL WINAPI CommConfigDialogW(LPCWSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); + WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); + WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); + WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); + WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); + +#define MAX_COMPUTERNAME_LENGTH 15 + + WINBASEAPI WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI GetComputerNameW(LPWSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI SetComputerNameA(LPCSTR lpComputerName); + WINBASEAPI WINBOOL WINAPI SetComputerNameW(LPCWSTR lpComputerName); + + typedef enum _COMPUTER_NAME_FORMAT { + ComputerNameNetBIOS,ComputerNameDnsHostname,ComputerNameDnsDomain,ComputerNameDnsFullyQualified,ComputerNamePhysicalNetBIOS,ComputerNamePhysicalDnsHostname,ComputerNamePhysicalDnsDomain,ComputerNamePhysicalDnsFullyQualified,ComputerNameMax + } COMPUTER_NAME_FORMAT; + + WINBASEAPI WINBOOL WINAPI GetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI GetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPWSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI SetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPCSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI SetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPCWSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameA(LPCSTR Hostname,LPSTR ComputerName,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameW(LPCWSTR Hostname,LPWSTR ComputerName,LPDWORD nSize); + WINADVAPI WINBOOL WINAPI GetUserNameA(LPSTR lpBuffer,LPDWORD pcbBuffer); + WINADVAPI WINBOOL WINAPI GetUserNameW(LPWSTR lpBuffer,LPDWORD pcbBuffer); + +#define LOGON32_LOGON_INTERACTIVE 2 +#define LOGON32_LOGON_NETWORK 3 +#define LOGON32_LOGON_BATCH 4 +#define LOGON32_LOGON_SERVICE 5 +#define LOGON32_LOGON_UNLOCK 7 +#define LOGON32_LOGON_NETWORK_CLEARTEXT 8 +#define LOGON32_LOGON_NEW_CREDENTIALS 9 + +#define LOGON32_PROVIDER_DEFAULT 0 +#define LOGON32_PROVIDER_WINNT35 1 +#define LOGON32_PROVIDER_WINNT40 2 +#define LOGON32_PROVIDER_WINNT50 3 + +#ifdef UNICODE +#define LogonUser LogonUserW +#define LogonUserEx LogonUserExW +#define CreateProcessAsUser CreateProcessAsUserW +#else +#define LogonUser LogonUserA +#define LogonUserEx LogonUserExA +#define CreateProcessAsUser CreateProcessAsUserA +#endif + + WINADVAPI WINBOOL WINAPI LogonUserA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); + WINADVAPI WINBOOL WINAPI LogonUserW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); + WINADVAPI WINBOOL WINAPI LogonUserExA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); + WINADVAPI WINBOOL WINAPI LogonUserExW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); + WINADVAPI WINBOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken); + WINADVAPI WINBOOL WINAPI CreateProcessAsUserA(HANDLE hToken,LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINADVAPI WINBOOL WINAPI CreateProcessAsUserW(HANDLE hToken,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + +#define LOGON_WITH_PROFILE 0x1 +#define LOGON_NETCREDENTIALS_ONLY 0x2 +#define LOGON_ZERO_PASSWORD_BUFFER 0x80000000 + + WINADVAPI WINBOOL WINAPI CreateProcessWithLogonW(LPCWSTR lpUsername,LPCWSTR lpDomain,LPCWSTR lpPassword,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINADVAPI WINBOOL WINAPI CreateProcessWithTokenW(HANDLE hToken,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINADVAPI WINBOOL WINAPI ImpersonateAnonymousToken(HANDLE ThreadHandle); + WINADVAPI WINBOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken,DWORD dwDesiredAccess,LPSECURITY_ATTRIBUTES lpTokenAttributes,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,TOKEN_TYPE TokenType,PHANDLE phNewToken); + WINADVAPI WINBOOL WINAPI CreateRestrictedToken(HANDLE ExistingTokenHandle,DWORD Flags,DWORD DisableSidCount,PSID_AND_ATTRIBUTES SidsToDisable,DWORD DeletePrivilegeCount,PLUID_AND_ATTRIBUTES PrivilegesToDelete,DWORD RestrictedSidCount,PSID_AND_ATTRIBUTES SidsToRestrict,PHANDLE NewTokenHandle); + WINADVAPI WINBOOL WINAPI IsTokenRestricted(HANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI IsTokenUntrusted(HANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI CheckTokenMembership(HANDLE TokenHandle,PSID SidToCheck,PBOOL IsMember); + + typedef WAITORTIMERCALLBACKFUNC WAITORTIMERCALLBACK; + + WINBASEAPI WINBOOL WINAPI RegisterWaitForSingleObject(PHANDLE phNewWaitObject,HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); + WINBASEAPI HANDLE WINAPI RegisterWaitForSingleObjectEx(HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); + WINBASEAPI WINBOOL WINAPI UnregisterWait(HANDLE WaitHandle); + WINBASEAPI WINBOOL WINAPI UnregisterWaitEx(HANDLE WaitHandle,HANDLE CompletionEvent); + WINBASEAPI WINBOOL WINAPI QueueUserWorkItem(LPTHREAD_START_ROUTINE Function,PVOID Context,ULONG Flags); + WINBASEAPI WINBOOL WINAPI BindIoCompletionCallback(HANDLE FileHandle,LPOVERLAPPED_COMPLETION_ROUTINE Function,ULONG Flags); + WINBASEAPI HANDLE WINAPI CreateTimerQueue(VOID); + WINBASEAPI WINBOOL WINAPI CreateTimerQueueTimer(PHANDLE phNewTimer,HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,ULONG Flags); + WINBASEAPI WINBOOL WINAPI ChangeTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,ULONG DueTime,ULONG Period); + WINBASEAPI WINBOOL WINAPI DeleteTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,HANDLE CompletionEvent); + WINBASEAPI WINBOOL WINAPI DeleteTimerQueueEx(HANDLE TimerQueue,HANDLE CompletionEvent); + WINBASEAPI HANDLE WINAPI SetTimerQueueTimer(HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,WINBOOL PreferIo); + WINBASEAPI WINBOOL WINAPI CancelTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer); + WINBASEAPI WINBOOL WINAPI DeleteTimerQueue(HANDLE TimerQueue); + +#define HW_PROFILE_GUIDLEN 39 +#define MAX_PROFILE_LEN 80 + +#define DOCKINFO_UNDOCKED (0x1) +#define DOCKINFO_DOCKED (0x2) +#define DOCKINFO_USER_SUPPLIED (0x4) +#define DOCKINFO_USER_UNDOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_UNDOCKED) +#define DOCKINFO_USER_DOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_DOCKED) + + typedef struct tagHW_PROFILE_INFOA { + DWORD dwDockInfo; + CHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; + CHAR szHwProfileName[MAX_PROFILE_LEN]; + } HW_PROFILE_INFOA,*LPHW_PROFILE_INFOA; + + typedef struct tagHW_PROFILE_INFOW { + DWORD dwDockInfo; + WCHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; + WCHAR szHwProfileName[MAX_PROFILE_LEN]; + } HW_PROFILE_INFOW,*LPHW_PROFILE_INFOW; + +#ifdef UNICODE + typedef HW_PROFILE_INFOW HW_PROFILE_INFO; + typedef LPHW_PROFILE_INFOW LPHW_PROFILE_INFO; +#else + typedef HW_PROFILE_INFOA HW_PROFILE_INFO; + typedef LPHW_PROFILE_INFOA LPHW_PROFILE_INFO; +#endif + +#ifdef UNICODE +#define GetCurrentHwProfile GetCurrentHwProfileW +#define GetVersionEx GetVersionExW +#define VerifyVersionInfo VerifyVersionInfoW +#else +#define GetCurrentHwProfile GetCurrentHwProfileA +#define GetVersionEx GetVersionExA +#define VerifyVersionInfo VerifyVersionInfoA +#endif + + WINADVAPI WINBOOL WINAPI GetCurrentHwProfileA (LPHW_PROFILE_INFOA lpHwProfileInfo); + WINADVAPI WINBOOL WINAPI GetCurrentHwProfileW (LPHW_PROFILE_INFOW lpHwProfileInfo); + WINBASEAPI WINBOOL WINAPI QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); + WINBASEAPI WINBOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); + WINBASEAPI WINBOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation); + WINBASEAPI WINBOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation); + WINBASEAPI WINBOOL WINAPI VerifyVersionInfoA(LPOSVERSIONINFOEXA lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); + WINBASEAPI WINBOOL WINAPI VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); + +#include + +#define TC_NORMAL 0 +#define TC_HARDERR 1 +#define TC_GP_TRAP 2 +#define TC_SIGNAL 3 + +#define AC_LINE_OFFLINE 0x0 +#define AC_LINE_ONLINE 0x1 +#define AC_LINE_BACKUP_POWER 0x2 +#define AC_LINE_UNKNOWN 0xff + +#define BATTERY_FLAG_HIGH 0x1 +#define BATTERY_FLAG_LOW 0x2 +#define BATTERY_FLAG_CRITICAL 0x4 +#define BATTERY_FLAG_CHARGING 0x8 +#define BATTERY_FLAG_NO_BATTERY 0x80 +#define BATTERY_FLAG_UNKNOWN 0xff + +#define BATTERY_PERCENTAGE_UNKNOWN 0xff + +#define BATTERY_LIFE_UNKNOWN 0xffffffff + + typedef struct _SYSTEM_POWER_STATUS { + BYTE ACLineStatus; + BYTE BatteryFlag; + BYTE BatteryLifePercent; + BYTE Reserved1; + DWORD BatteryLifeTime; + DWORD BatteryFullLifeTime; + } SYSTEM_POWER_STATUS,*LPSYSTEM_POWER_STATUS; + +#ifdef UNICODE +#define CreateJobObject CreateJobObjectW +#define OpenJobObject OpenJobObjectW +#define FindFirstVolume FindFirstVolumeW +#define FindNextVolume FindNextVolumeW +#define FindFirstVolumeMountPoint FindFirstVolumeMountPointW +#define FindNextVolumeMountPoint FindNextVolumeMountPointW +#define SetVolumeMountPoint SetVolumeMountPointW +#define DeleteVolumeMountPoint DeleteVolumeMountPointW +#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointW +#define GetVolumePathName GetVolumePathNameW +#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameW +#else +#define CreateJobObject CreateJobObjectA +#define OpenJobObject OpenJobObjectA +#define FindFirstVolume FindFirstVolumeA +#define FindNextVolume FindNextVolumeA +#define FindFirstVolumeMountPoint FindFirstVolumeMountPointA +#define FindNextVolumeMountPoint FindNextVolumeMountPointA +#define SetVolumeMountPoint SetVolumeMountPointA +#define DeleteVolumeMountPoint DeleteVolumeMountPointA +#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointA +#define GetVolumePathName GetVolumePathNameA +#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameA +#endif + + WINBOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS lpSystemPowerStatus); + WINBOOL WINAPI SetSystemPowerState(WINBOOL fSuspend,WINBOOL fForce); + WINBASEAPI WINBOOL WINAPI AllocateUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI WINBOOL WINAPI FreeUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI WINBOOL WINAPI MapUserPhysicalPages(PVOID VirtualAddress,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI WINBOOL WINAPI MapUserPhysicalPagesScatter(PVOID *VirtualAddresses,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI HANDLE WINAPI CreateJobObjectA(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateJobObjectW(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenJobObjectA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenJobObjectW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI WINBOOL WINAPI AssignProcessToJobObject(HANDLE hJob,HANDLE hProcess); + WINBASEAPI WINBOOL WINAPI TerminateJobObject(HANDLE hJob,UINT uExitCode); + WINBASEAPI WINBOOL WINAPI QueryInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength,LPDWORD lpReturnLength); + WINBASEAPI WINBOOL WINAPI SetInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength); + WINBASEAPI WINBOOL WINAPI IsProcessInJob(HANDLE ProcessHandle,HANDLE JobHandle,PBOOL Result); + WINBASEAPI WINBOOL WINAPI CreateJobSet(ULONG NumJob,PJOB_SET_ARRAY UserJobSet,ULONG Flags); + WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); + WINBASEAPI ULONG WINAPI RemoveVectoredExceptionHandler(PVOID Handle); + WINBASEAPI PVOID WINAPI AddVectoredContinueHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); + WINBASEAPI ULONG WINAPI RemoveVectoredContinueHandler(PVOID Handle); + WINBASEAPI HANDLE WINAPI FindFirstVolumeA(LPSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI HANDLE WINAPI FindFirstVolumeW(LPWSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeA(HANDLE hFindVolume,LPSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeW(HANDLE hFindVolume,LPWSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindVolumeClose(HANDLE hFindVolume); + WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointA(LPCSTR lpszRootPathName,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointW(LPCWSTR lpszRootPathName,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointA(HANDLE hFindVolumeMountPoint,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointW(HANDLE hFindVolumeMountPoint,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindVolumeMountPointClose(HANDLE hFindVolumeMountPoint); + WINBASEAPI WINBOOL WINAPI SetVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPCSTR lpszVolumeName); + WINBASEAPI WINBOOL WINAPI SetVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPCWSTR lpszVolumeName); + WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointA(LPCSTR lpszVolumeMountPoint); + WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointW(LPCWSTR lpszVolumeMountPoint); + WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPWSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNameA(LPCSTR lpszFileName,LPSTR lpszVolumePathName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNameW(LPCWSTR lpszFileName,LPWSTR lpszVolumePathName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameA(LPCSTR lpszVolumeName,LPCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameW(LPCWSTR lpszVolumeName,LPWCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); + +#define ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID 0x1 +#define ACTCTX_FLAG_LANGID_VALID 0x2 +#define ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID 0x4 +#define ACTCTX_FLAG_RESOURCE_NAME_VALID 0x8 +#define ACTCTX_FLAG_SET_PROCESS_DEFAULT 0x10 +#define ACTCTX_FLAG_APPLICATION_NAME_VALID 0x20 +#define ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF 0x40 +#define ACTCTX_FLAG_HMODULE_VALID 0x80 + + typedef struct tagACTCTXA { + ULONG cbSize; + DWORD dwFlags; + LPCSTR lpSource; + USHORT wProcessorArchitecture; + LANGID wLangId; + LPCSTR lpAssemblyDirectory; + LPCSTR lpResourceName; + LPCSTR lpApplicationName; + HMODULE hModule; + } ACTCTXA,*PACTCTXA; + + typedef struct tagACTCTXW { + ULONG cbSize; + DWORD dwFlags; + LPCWSTR lpSource; + USHORT wProcessorArchitecture; + LANGID wLangId; + LPCWSTR lpAssemblyDirectory; + LPCWSTR lpResourceName; + LPCWSTR lpApplicationName; + HMODULE hModule; + } ACTCTXW,*PACTCTXW; + + typedef const ACTCTXA *PCACTCTXA; + typedef const ACTCTXW *PCACTCTXW; + +#ifdef UNICODE + typedef ACTCTXW ACTCTX; + typedef PACTCTXW PACTCTX; + typedef PCACTCTXW PCACTCTX; +#else + typedef ACTCTXA ACTCTX; + typedef PACTCTXA PACTCTX; + typedef PCACTCTXA PCACTCTX; +#endif + +#ifdef UNICODE +#define CreateActCtx CreateActCtxW +#else +#define CreateActCtx CreateActCtxA +#endif + + WINBASEAPI HANDLE WINAPI CreateActCtxA(PCACTCTXA pActCtx); + WINBASEAPI HANDLE WINAPI CreateActCtxW(PCACTCTXW pActCtx); + WINBASEAPI VOID WINAPI AddRefActCtx(HANDLE hActCtx); + WINBASEAPI VOID WINAPI ReleaseActCtx(HANDLE hActCtx); + WINBASEAPI WINBOOL WINAPI ZombifyActCtx(HANDLE hActCtx); + WINBASEAPI WINBOOL WINAPI ActivateActCtx(HANDLE hActCtx,ULONG_PTR *lpCookie); + +#define DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION (0x1) + + WINBASEAPI WINBOOL WINAPI DeactivateActCtx(DWORD dwFlags,ULONG_PTR ulCookie); + WINBASEAPI WINBOOL WINAPI GetCurrentActCtx(HANDLE *lphActCtx); + + typedef struct tagACTCTX_SECTION_KEYED_DATA_2600 { + ULONG cbSize; + ULONG ulDataFormatVersion; + PVOID lpData; + ULONG ulLength; + PVOID lpSectionGlobalData; + ULONG ulSectionGlobalDataLength; + PVOID lpSectionBase; + ULONG ulSectionTotalLength; + HANDLE hActCtx; + ULONG ulAssemblyRosterIndex; + } ACTCTX_SECTION_KEYED_DATA_2600,*PACTCTX_SECTION_KEYED_DATA_2600; + + typedef const ACTCTX_SECTION_KEYED_DATA_2600 *PCACTCTX_SECTION_KEYED_DATA_2600; + + typedef struct tagACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA { + PVOID lpInformation; + PVOID lpSectionBase; + ULONG ulSectionLength; + PVOID lpSectionGlobalDataBase; + ULONG ulSectionGlobalDataLength; + } ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA,*PACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; + + typedef const ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA *PCACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; + + typedef struct tagACTCTX_SECTION_KEYED_DATA { + ULONG cbSize; + ULONG ulDataFormatVersion; + PVOID lpData; + ULONG ulLength; + PVOID lpSectionGlobalData; + ULONG ulSectionGlobalDataLength; + PVOID lpSectionBase; + ULONG ulSectionTotalLength; + HANDLE hActCtx; + ULONG ulAssemblyRosterIndex; + + ULONG ulFlags; + ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA AssemblyMetadata; + } ACTCTX_SECTION_KEYED_DATA,*PACTCTX_SECTION_KEYED_DATA; + + typedef const ACTCTX_SECTION_KEYED_DATA *PCACTCTX_SECTION_KEYED_DATA; + +#define FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX 0x1 +#define FIND_ACTCTX_SECTION_KEY_RETURN_FLAGS 0x2 +#define FIND_ACTCTX_SECTION_KEY_RETURN_ASSEMBLY_METADATA 0x4 + +#ifdef UNICODE +#define FindActCtxSectionString FindActCtxSectionStringW +#else +#define FindActCtxSectionString FindActCtxSectionStringA +#endif + + WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringA(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); + WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCWSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); + WINBASEAPI WINBOOL WINAPI FindActCtxSectionGuid(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,const GUID *lpGuidToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); + +#ifndef RC_INVOKED +#ifndef ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED + + typedef struct _ACTIVATION_CONTEXT_BASIC_INFORMATION { + HANDLE hActCtx; + DWORD dwFlags; + } ACTIVATION_CONTEXT_BASIC_INFORMATION,*PACTIVATION_CONTEXT_BASIC_INFORMATION; + + typedef const struct _ACTIVATION_CONTEXT_BASIC_INFORMATION *PCACTIVATION_CONTEXT_BASIC_INFORMATION; + +#define ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED 1 +#endif +#endif + +#define QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX 0x4 +#define QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE 0x8 +#define QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS 0x10 +#define QUERY_ACTCTX_FLAG_NO_ADDREF 0x80000000 + + WINBASEAPI WINBOOL WINAPI QueryActCtxW(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); + + typedef WINBOOL (WINAPI *PQUERYACTCTXW_FUNC)(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); + + WINBASEAPI WINBOOL WINAPI ProcessIdToSessionId(DWORD dwProcessId,DWORD *pSessionId); + WINBASEAPI DWORD WINAPI WTSGetActiveConsoleSessionId(); + WINBASEAPI WINBOOL WINAPI IsWow64Process(HANDLE hProcess,PBOOL Wow64Process); + WINBASEAPI WINBOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer,PDWORD ReturnedLength); + WINBASEAPI WINBOOL WINAPI GetNumaHighestNodeNumber(PULONG HighestNodeNumber); + WINBASEAPI WINBOOL WINAPI GetNumaProcessorNode(UCHAR Processor,PUCHAR NodeNumber); + WINBASEAPI WINBOOL WINAPI GetNumaNodeProcessorMask(UCHAR Node,PULONGLONG ProcessorMask); + WINBASEAPI WINBOOL WINAPI GetNumaAvailableMemoryNode(UCHAR Node,PULONGLONG AvailableBytes); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/wincon.h b/tcc/include/winapi/wincon.h index a3501ee7..3a9a94d7 100644 --- a/tcc/include/winapi/wincon.h +++ b/tcc/include/winapi/wincon.h @@ -1,301 +1,301 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINCON_ -#define _WINCON_ - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct _COORD { - SHORT X; - SHORT Y; - } COORD,*PCOORD; - - typedef struct _SMALL_RECT { - SHORT Left; - SHORT Top; - SHORT Right; - SHORT Bottom; - } SMALL_RECT,*PSMALL_RECT; - - typedef struct _KEY_EVENT_RECORD { - WINBOOL bKeyDown; - WORD wRepeatCount; - WORD wVirtualKeyCode; - WORD wVirtualScanCode; - union { - WCHAR UnicodeChar; - CHAR AsciiChar; - } uChar; - DWORD dwControlKeyState; - } KEY_EVENT_RECORD,*PKEY_EVENT_RECORD; - -#define RIGHT_ALT_PRESSED 0x1 -#define LEFT_ALT_PRESSED 0x2 -#define RIGHT_CTRL_PRESSED 0x4 -#define LEFT_CTRL_PRESSED 0x8 -#define SHIFT_PRESSED 0x10 -#define NUMLOCK_ON 0x20 -#define SCROLLLOCK_ON 0x40 -#define CAPSLOCK_ON 0x80 -#define ENHANCED_KEY 0x100 -#define NLS_DBCSCHAR 0x10000 -#define NLS_ALPHANUMERIC 0x0 -#define NLS_KATAKANA 0x20000 -#define NLS_HIRAGANA 0x40000 -#define NLS_ROMAN 0x400000 -#define NLS_IME_CONVERSION 0x800000 -#define NLS_IME_DISABLE 0x20000000 - - typedef struct _MOUSE_EVENT_RECORD { - COORD dwMousePosition; - DWORD dwButtonState; - DWORD dwControlKeyState; - DWORD dwEventFlags; - } MOUSE_EVENT_RECORD,*PMOUSE_EVENT_RECORD; - -#define FROM_LEFT_1ST_BUTTON_PRESSED 0x1 -#define RIGHTMOST_BUTTON_PRESSED 0x2 -#define FROM_LEFT_2ND_BUTTON_PRESSED 0x4 -#define FROM_LEFT_3RD_BUTTON_PRESSED 0x8 -#define FROM_LEFT_4TH_BUTTON_PRESSED 0x10 - -#define MOUSE_MOVED 0x1 -#define DOUBLE_CLICK 0x2 -#define MOUSE_WHEELED 0x4 - - typedef struct _WINDOW_BUFFER_SIZE_RECORD { - COORD dwSize; - } WINDOW_BUFFER_SIZE_RECORD,*PWINDOW_BUFFER_SIZE_RECORD; - - typedef struct _MENU_EVENT_RECORD { - UINT dwCommandId; - } MENU_EVENT_RECORD,*PMENU_EVENT_RECORD; - - typedef struct _FOCUS_EVENT_RECORD { - WINBOOL bSetFocus; - } FOCUS_EVENT_RECORD,*PFOCUS_EVENT_RECORD; - - typedef struct _INPUT_RECORD { - WORD EventType; - union { - KEY_EVENT_RECORD KeyEvent; - MOUSE_EVENT_RECORD MouseEvent; - WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; - MENU_EVENT_RECORD MenuEvent; - FOCUS_EVENT_RECORD FocusEvent; - } Event; - } INPUT_RECORD,*PINPUT_RECORD; - -#define KEY_EVENT 0x1 -#define MOUSE_EVENT 0x2 -#define WINDOW_BUFFER_SIZE_EVENT 0x4 -#define MENU_EVENT 0x8 -#define FOCUS_EVENT 0x10 - - typedef struct _CHAR_INFO { - union { - WCHAR UnicodeChar; - CHAR AsciiChar; - } Char; - WORD Attributes; - } CHAR_INFO,*PCHAR_INFO; - -#define FOREGROUND_BLUE 0x1 -#define FOREGROUND_GREEN 0x2 -#define FOREGROUND_RED 0x4 -#define FOREGROUND_INTENSITY 0x8 -#define BACKGROUND_BLUE 0x10 -#define BACKGROUND_GREEN 0x20 -#define BACKGROUND_RED 0x40 -#define BACKGROUND_INTENSITY 0x80 -#define COMMON_LVB_LEADING_BYTE 0x100 -#define COMMON_LVB_TRAILING_BYTE 0x200 -#define COMMON_LVB_GRID_HORIZONTAL 0x400 -#define COMMON_LVB_GRID_LVERTICAL 0x800 -#define COMMON_LVB_GRID_RVERTICAL 0x1000 -#define COMMON_LVB_REVERSE_VIDEO 0x4000 -#define COMMON_LVB_UNDERSCORE 0x8000 - -#define COMMON_LVB_SBCSDBCS 0x300 - - typedef struct _CONSOLE_SCREEN_BUFFER_INFO { - COORD dwSize; - COORD dwCursorPosition; - WORD wAttributes; - SMALL_RECT srWindow; - COORD dwMaximumWindowSize; - } CONSOLE_SCREEN_BUFFER_INFO,*PCONSOLE_SCREEN_BUFFER_INFO; - - typedef struct _CONSOLE_CURSOR_INFO { - DWORD dwSize; - WINBOOL bVisible; - } CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO; - - typedef struct _CONSOLE_FONT_INFO { - DWORD nFont; - COORD dwFontSize; - } CONSOLE_FONT_INFO,*PCONSOLE_FONT_INFO; - - typedef struct _CONSOLE_SELECTION_INFO { - DWORD dwFlags; - COORD dwSelectionAnchor; - SMALL_RECT srSelection; - } CONSOLE_SELECTION_INFO,*PCONSOLE_SELECTION_INFO; - -#define CONSOLE_NO_SELECTION 0x0 -#define CONSOLE_SELECTION_IN_PROGRESS 0x1 -#define CONSOLE_SELECTION_NOT_EMPTY 0x2 -#define CONSOLE_MOUSE_SELECTION 0x4 -#define CONSOLE_MOUSE_DOWN 0x8 - - typedef WINBOOL (WINAPI *PHANDLER_ROUTINE)(DWORD CtrlType); - -#define CTRL_C_EVENT 0 -#define CTRL_BREAK_EVENT 1 -#define CTRL_CLOSE_EVENT 2 - -#define CTRL_LOGOFF_EVENT 5 -#define CTRL_SHUTDOWN_EVENT 6 - -#define ENABLE_PROCESSED_INPUT 0x1 -#define ENABLE_LINE_INPUT 0x2 -#define ENABLE_ECHO_INPUT 0x4 -#define ENABLE_WINDOW_INPUT 0x8 -#define ENABLE_MOUSE_INPUT 0x10 - -#define ENABLE_PROCESSED_OUTPUT 0x1 -#define ENABLE_WRAP_AT_EOL_OUTPUT 0x2 - -#ifdef UNICODE -#define PeekConsoleInput PeekConsoleInputW -#define ReadConsoleInput ReadConsoleInputW -#define WriteConsoleInput WriteConsoleInputW -#define ReadConsoleOutput ReadConsoleOutputW -#define WriteConsoleOutput WriteConsoleOutputW -#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterW -#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterW -#define FillConsoleOutputCharacter FillConsoleOutputCharacterW -#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferW -#define GetConsoleTitle GetConsoleTitleW -#define SetConsoleTitle SetConsoleTitleW -#define ReadConsole ReadConsoleW -#define WriteConsole WriteConsoleW -#define AddConsoleAlias AddConsoleAliasW -#define GetConsoleAlias GetConsoleAliasW -#define GetConsoleAliasesLength GetConsoleAliasesLengthW -#define GetConsoleAliasExesLength GetConsoleAliasExesLengthW -#define GetConsoleAliases GetConsoleAliasesW -#define GetConsoleAliasExes GetConsoleAliasExesW -#else -#define PeekConsoleInput PeekConsoleInputA -#define ReadConsoleInput ReadConsoleInputA -#define WriteConsoleInput WriteConsoleInputA -#define ReadConsoleOutput ReadConsoleOutputA -#define WriteConsoleOutput WriteConsoleOutputA -#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterA -#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterA -#define FillConsoleOutputCharacter FillConsoleOutputCharacterA -#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferA -#define GetConsoleTitle GetConsoleTitleA -#define SetConsoleTitle SetConsoleTitleA -#define ReadConsole ReadConsoleA -#define WriteConsole WriteConsoleA -#define AddConsoleAlias AddConsoleAliasA -#define GetConsoleAlias GetConsoleAliasA -#define GetConsoleAliasesLength GetConsoleAliasesLengthA -#define GetConsoleAliasExesLength GetConsoleAliasExesLengthA -#define GetConsoleAliases GetConsoleAliasesA -#define GetConsoleAliasExes GetConsoleAliasExesA -#endif - - WINBASEAPI WINBOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI WriteConsoleInputA(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); - WINBASEAPI WINBOOL WINAPI WriteConsoleInputW(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputA(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputW(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputA(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputW(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput,LPSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterW(HANDLE hConsoleOutput,LPWSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputAttribute(HANDLE hConsoleOutput,LPWORD lpAttribute,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfAttrsRead); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterA(HANDLE hConsoleOutput,LPCSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterW(HANDLE hConsoleOutput,LPCWSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputAttribute(HANDLE hConsoleOutput,CONST WORD *lpAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); - WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterA(HANDLE hConsoleOutput,CHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,WCHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI FillConsoleOutputAttribute(HANDLE hConsoleOutput,WORD wAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); - WINBASEAPI WINBOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle,LPDWORD lpMode); - WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hConsoleInput,LPDWORD lpNumberOfEvents); - WINBASEAPI WINBOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput,PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); - WINBASEAPI COORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput); - WINBASEAPI WINBOOL WINAPI GetConsoleCursorInfo(HANDLE hConsoleOutput,PCONSOLE_CURSOR_INFO lpConsoleCursorInfo); - WINBASEAPI WINBOOL WINAPI GetCurrentConsoleFont(HANDLE hConsoleOutput,WINBOOL bMaximumWindow,PCONSOLE_FONT_INFO lpConsoleCurrentFont); - WINBASEAPI COORD WINAPI GetConsoleFontSize(HANDLE hConsoleOutput,DWORD nFont); - WINBASEAPI WINBOOL WINAPI GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo); - WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD lpNumberOfMouseButtons); - WINBASEAPI WINBOOL WINAPI SetConsoleMode(HANDLE hConsoleHandle,DWORD dwMode); - WINBASEAPI WINBOOL WINAPI SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput); - WINBASEAPI WINBOOL WINAPI FlushConsoleInputBuffer(HANDLE hConsoleInput); - WINBASEAPI WINBOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput,COORD dwSize); - WINBASEAPI WINBOOL WINAPI SetConsoleCursorPosition(HANDLE hConsoleOutput,COORD dwCursorPosition); - WINBASEAPI WINBOOL WINAPI SetConsoleCursorInfo(HANDLE hConsoleOutput,CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo); - WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferA(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); - WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); - WINBASEAPI WINBOOL WINAPI SetConsoleWindowInfo(HANDLE hConsoleOutput,WINBOOL bAbsolute,CONST SMALL_RECT *lpConsoleWindow); - WINBASEAPI WINBOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttributes); - WINBASEAPI WINBOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,WINBOOL Add); - WINBASEAPI WINBOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,DWORD dwProcessGroupId); - WINBASEAPI WINBOOL WINAPI AllocConsole(VOID); - WINBASEAPI WINBOOL WINAPI FreeConsole(VOID); - WINBASEAPI WINBOOL WINAPI AttachConsole(DWORD dwProcessId); - -#define ATTACH_PARENT_PROCESS ((DWORD)-1) - - WINBASEAPI DWORD WINAPI GetConsoleTitleA(LPSTR lpConsoleTitle,DWORD nSize); - WINBASEAPI DWORD WINAPI GetConsoleTitleW(LPWSTR lpConsoleTitle,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetConsoleTitleA(LPCSTR lpConsoleTitle); - WINBASEAPI WINBOOL WINAPI SetConsoleTitleW(LPCWSTR lpConsoleTitle); - WINBASEAPI WINBOOL WINAPI ReadConsoleA(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI ReadConsoleW(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI WriteConsoleA(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); - -#define CONSOLE_TEXTMODE_BUFFER 1 - - WINBASEAPI HANDLE WINAPI CreateConsoleScreenBuffer(DWORD dwDesiredAccess,DWORD dwShareMode,CONST SECURITY_ATTRIBUTES *lpSecurityAttributes,DWORD dwFlags,LPVOID lpScreenBufferData); - WINBASEAPI UINT WINAPI GetConsoleCP(VOID); - WINBASEAPI WINBOOL WINAPI SetConsoleCP(UINT wCodePageID); - WINBASEAPI UINT WINAPI GetConsoleOutputCP(VOID); - WINBASEAPI WINBOOL WINAPI SetConsoleOutputCP(UINT wCodePageID); - -#define CONSOLE_FULLSCREEN 1 -#define CONSOLE_FULLSCREEN_HARDWARE 2 - - WINBASEAPI WINBOOL WINAPI GetConsoleDisplayMode(LPDWORD lpModeFlags); - WINBASEAPI HWND WINAPI GetConsoleWindow(VOID); - WINBASEAPI DWORD WINAPI GetConsoleProcessList(LPDWORD lpdwProcessList,DWORD dwProcessCount); - WINBASEAPI WINBOOL WINAPI AddConsoleAliasA(LPSTR Source,LPSTR Target,LPSTR ExeName); - WINBASEAPI WINBOOL WINAPI AddConsoleAliasW(LPWSTR Source,LPWSTR Target,LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasA(LPSTR Source,LPSTR TargetBuffer,DWORD TargetBufferLength,LPSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasW(LPWSTR Source,LPWSTR TargetBuffer,DWORD TargetBufferLength,LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthA(LPSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthW(LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthA(VOID); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthW(VOID); - WINBASEAPI DWORD WINAPI GetConsoleAliasesA(LPSTR AliasBuffer,DWORD AliasBufferLength,LPSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasesW(LPWSTR AliasBuffer,DWORD AliasBufferLength,LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesA(LPSTR ExeNameBuffer,DWORD ExeNameBufferLength); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesW(LPWSTR ExeNameBuffer,DWORD ExeNameBufferLength); - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINCON_ +#define _WINCON_ + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct _COORD { + SHORT X; + SHORT Y; + } COORD,*PCOORD; + + typedef struct _SMALL_RECT { + SHORT Left; + SHORT Top; + SHORT Right; + SHORT Bottom; + } SMALL_RECT,*PSMALL_RECT; + + typedef struct _KEY_EVENT_RECORD { + WINBOOL bKeyDown; + WORD wRepeatCount; + WORD wVirtualKeyCode; + WORD wVirtualScanCode; + union { + WCHAR UnicodeChar; + CHAR AsciiChar; + } uChar; + DWORD dwControlKeyState; + } KEY_EVENT_RECORD,*PKEY_EVENT_RECORD; + +#define RIGHT_ALT_PRESSED 0x1 +#define LEFT_ALT_PRESSED 0x2 +#define RIGHT_CTRL_PRESSED 0x4 +#define LEFT_CTRL_PRESSED 0x8 +#define SHIFT_PRESSED 0x10 +#define NUMLOCK_ON 0x20 +#define SCROLLLOCK_ON 0x40 +#define CAPSLOCK_ON 0x80 +#define ENHANCED_KEY 0x100 +#define NLS_DBCSCHAR 0x10000 +#define NLS_ALPHANUMERIC 0x0 +#define NLS_KATAKANA 0x20000 +#define NLS_HIRAGANA 0x40000 +#define NLS_ROMAN 0x400000 +#define NLS_IME_CONVERSION 0x800000 +#define NLS_IME_DISABLE 0x20000000 + + typedef struct _MOUSE_EVENT_RECORD { + COORD dwMousePosition; + DWORD dwButtonState; + DWORD dwControlKeyState; + DWORD dwEventFlags; + } MOUSE_EVENT_RECORD,*PMOUSE_EVENT_RECORD; + +#define FROM_LEFT_1ST_BUTTON_PRESSED 0x1 +#define RIGHTMOST_BUTTON_PRESSED 0x2 +#define FROM_LEFT_2ND_BUTTON_PRESSED 0x4 +#define FROM_LEFT_3RD_BUTTON_PRESSED 0x8 +#define FROM_LEFT_4TH_BUTTON_PRESSED 0x10 + +#define MOUSE_MOVED 0x1 +#define DOUBLE_CLICK 0x2 +#define MOUSE_WHEELED 0x4 + + typedef struct _WINDOW_BUFFER_SIZE_RECORD { + COORD dwSize; + } WINDOW_BUFFER_SIZE_RECORD,*PWINDOW_BUFFER_SIZE_RECORD; + + typedef struct _MENU_EVENT_RECORD { + UINT dwCommandId; + } MENU_EVENT_RECORD,*PMENU_EVENT_RECORD; + + typedef struct _FOCUS_EVENT_RECORD { + WINBOOL bSetFocus; + } FOCUS_EVENT_RECORD,*PFOCUS_EVENT_RECORD; + + typedef struct _INPUT_RECORD { + WORD EventType; + union { + KEY_EVENT_RECORD KeyEvent; + MOUSE_EVENT_RECORD MouseEvent; + WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; + MENU_EVENT_RECORD MenuEvent; + FOCUS_EVENT_RECORD FocusEvent; + } Event; + } INPUT_RECORD,*PINPUT_RECORD; + +#define KEY_EVENT 0x1 +#define MOUSE_EVENT 0x2 +#define WINDOW_BUFFER_SIZE_EVENT 0x4 +#define MENU_EVENT 0x8 +#define FOCUS_EVENT 0x10 + + typedef struct _CHAR_INFO { + union { + WCHAR UnicodeChar; + CHAR AsciiChar; + } Char; + WORD Attributes; + } CHAR_INFO,*PCHAR_INFO; + +#define FOREGROUND_BLUE 0x1 +#define FOREGROUND_GREEN 0x2 +#define FOREGROUND_RED 0x4 +#define FOREGROUND_INTENSITY 0x8 +#define BACKGROUND_BLUE 0x10 +#define BACKGROUND_GREEN 0x20 +#define BACKGROUND_RED 0x40 +#define BACKGROUND_INTENSITY 0x80 +#define COMMON_LVB_LEADING_BYTE 0x100 +#define COMMON_LVB_TRAILING_BYTE 0x200 +#define COMMON_LVB_GRID_HORIZONTAL 0x400 +#define COMMON_LVB_GRID_LVERTICAL 0x800 +#define COMMON_LVB_GRID_RVERTICAL 0x1000 +#define COMMON_LVB_REVERSE_VIDEO 0x4000 +#define COMMON_LVB_UNDERSCORE 0x8000 + +#define COMMON_LVB_SBCSDBCS 0x300 + + typedef struct _CONSOLE_SCREEN_BUFFER_INFO { + COORD dwSize; + COORD dwCursorPosition; + WORD wAttributes; + SMALL_RECT srWindow; + COORD dwMaximumWindowSize; + } CONSOLE_SCREEN_BUFFER_INFO,*PCONSOLE_SCREEN_BUFFER_INFO; + + typedef struct _CONSOLE_CURSOR_INFO { + DWORD dwSize; + WINBOOL bVisible; + } CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO; + + typedef struct _CONSOLE_FONT_INFO { + DWORD nFont; + COORD dwFontSize; + } CONSOLE_FONT_INFO,*PCONSOLE_FONT_INFO; + + typedef struct _CONSOLE_SELECTION_INFO { + DWORD dwFlags; + COORD dwSelectionAnchor; + SMALL_RECT srSelection; + } CONSOLE_SELECTION_INFO,*PCONSOLE_SELECTION_INFO; + +#define CONSOLE_NO_SELECTION 0x0 +#define CONSOLE_SELECTION_IN_PROGRESS 0x1 +#define CONSOLE_SELECTION_NOT_EMPTY 0x2 +#define CONSOLE_MOUSE_SELECTION 0x4 +#define CONSOLE_MOUSE_DOWN 0x8 + + typedef WINBOOL (WINAPI *PHANDLER_ROUTINE)(DWORD CtrlType); + +#define CTRL_C_EVENT 0 +#define CTRL_BREAK_EVENT 1 +#define CTRL_CLOSE_EVENT 2 + +#define CTRL_LOGOFF_EVENT 5 +#define CTRL_SHUTDOWN_EVENT 6 + +#define ENABLE_PROCESSED_INPUT 0x1 +#define ENABLE_LINE_INPUT 0x2 +#define ENABLE_ECHO_INPUT 0x4 +#define ENABLE_WINDOW_INPUT 0x8 +#define ENABLE_MOUSE_INPUT 0x10 + +#define ENABLE_PROCESSED_OUTPUT 0x1 +#define ENABLE_WRAP_AT_EOL_OUTPUT 0x2 + +#ifdef UNICODE +#define PeekConsoleInput PeekConsoleInputW +#define ReadConsoleInput ReadConsoleInputW +#define WriteConsoleInput WriteConsoleInputW +#define ReadConsoleOutput ReadConsoleOutputW +#define WriteConsoleOutput WriteConsoleOutputW +#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterW +#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterW +#define FillConsoleOutputCharacter FillConsoleOutputCharacterW +#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferW +#define GetConsoleTitle GetConsoleTitleW +#define SetConsoleTitle SetConsoleTitleW +#define ReadConsole ReadConsoleW +#define WriteConsole WriteConsoleW +#define AddConsoleAlias AddConsoleAliasW +#define GetConsoleAlias GetConsoleAliasW +#define GetConsoleAliasesLength GetConsoleAliasesLengthW +#define GetConsoleAliasExesLength GetConsoleAliasExesLengthW +#define GetConsoleAliases GetConsoleAliasesW +#define GetConsoleAliasExes GetConsoleAliasExesW +#else +#define PeekConsoleInput PeekConsoleInputA +#define ReadConsoleInput ReadConsoleInputA +#define WriteConsoleInput WriteConsoleInputA +#define ReadConsoleOutput ReadConsoleOutputA +#define WriteConsoleOutput WriteConsoleOutputA +#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterA +#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterA +#define FillConsoleOutputCharacter FillConsoleOutputCharacterA +#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferA +#define GetConsoleTitle GetConsoleTitleA +#define SetConsoleTitle SetConsoleTitleA +#define ReadConsole ReadConsoleA +#define WriteConsole WriteConsoleA +#define AddConsoleAlias AddConsoleAliasA +#define GetConsoleAlias GetConsoleAliasA +#define GetConsoleAliasesLength GetConsoleAliasesLengthA +#define GetConsoleAliasExesLength GetConsoleAliasExesLengthA +#define GetConsoleAliases GetConsoleAliasesA +#define GetConsoleAliasExes GetConsoleAliasExesA +#endif + + WINBASEAPI WINBOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI WriteConsoleInputA(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); + WINBASEAPI WINBOOL WINAPI WriteConsoleInputW(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputA(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputW(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputA(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputW(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput,LPSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterW(HANDLE hConsoleOutput,LPWSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputAttribute(HANDLE hConsoleOutput,LPWORD lpAttribute,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfAttrsRead); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterA(HANDLE hConsoleOutput,LPCSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterW(HANDLE hConsoleOutput,LPCWSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputAttribute(HANDLE hConsoleOutput,CONST WORD *lpAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); + WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterA(HANDLE hConsoleOutput,CHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,WCHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI FillConsoleOutputAttribute(HANDLE hConsoleOutput,WORD wAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); + WINBASEAPI WINBOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle,LPDWORD lpMode); + WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hConsoleInput,LPDWORD lpNumberOfEvents); + WINBASEAPI WINBOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput,PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); + WINBASEAPI COORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput); + WINBASEAPI WINBOOL WINAPI GetConsoleCursorInfo(HANDLE hConsoleOutput,PCONSOLE_CURSOR_INFO lpConsoleCursorInfo); + WINBASEAPI WINBOOL WINAPI GetCurrentConsoleFont(HANDLE hConsoleOutput,WINBOOL bMaximumWindow,PCONSOLE_FONT_INFO lpConsoleCurrentFont); + WINBASEAPI COORD WINAPI GetConsoleFontSize(HANDLE hConsoleOutput,DWORD nFont); + WINBASEAPI WINBOOL WINAPI GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo); + WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD lpNumberOfMouseButtons); + WINBASEAPI WINBOOL WINAPI SetConsoleMode(HANDLE hConsoleHandle,DWORD dwMode); + WINBASEAPI WINBOOL WINAPI SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput); + WINBASEAPI WINBOOL WINAPI FlushConsoleInputBuffer(HANDLE hConsoleInput); + WINBASEAPI WINBOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput,COORD dwSize); + WINBASEAPI WINBOOL WINAPI SetConsoleCursorPosition(HANDLE hConsoleOutput,COORD dwCursorPosition); + WINBASEAPI WINBOOL WINAPI SetConsoleCursorInfo(HANDLE hConsoleOutput,CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo); + WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferA(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); + WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); + WINBASEAPI WINBOOL WINAPI SetConsoleWindowInfo(HANDLE hConsoleOutput,WINBOOL bAbsolute,CONST SMALL_RECT *lpConsoleWindow); + WINBASEAPI WINBOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttributes); + WINBASEAPI WINBOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,WINBOOL Add); + WINBASEAPI WINBOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,DWORD dwProcessGroupId); + WINBASEAPI WINBOOL WINAPI AllocConsole(VOID); + WINBASEAPI WINBOOL WINAPI FreeConsole(VOID); + WINBASEAPI WINBOOL WINAPI AttachConsole(DWORD dwProcessId); + +#define ATTACH_PARENT_PROCESS ((DWORD)-1) + + WINBASEAPI DWORD WINAPI GetConsoleTitleA(LPSTR lpConsoleTitle,DWORD nSize); + WINBASEAPI DWORD WINAPI GetConsoleTitleW(LPWSTR lpConsoleTitle,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetConsoleTitleA(LPCSTR lpConsoleTitle); + WINBASEAPI WINBOOL WINAPI SetConsoleTitleW(LPCWSTR lpConsoleTitle); + WINBASEAPI WINBOOL WINAPI ReadConsoleA(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI ReadConsoleW(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI WriteConsoleA(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); + +#define CONSOLE_TEXTMODE_BUFFER 1 + + WINBASEAPI HANDLE WINAPI CreateConsoleScreenBuffer(DWORD dwDesiredAccess,DWORD dwShareMode,CONST SECURITY_ATTRIBUTES *lpSecurityAttributes,DWORD dwFlags,LPVOID lpScreenBufferData); + WINBASEAPI UINT WINAPI GetConsoleCP(VOID); + WINBASEAPI WINBOOL WINAPI SetConsoleCP(UINT wCodePageID); + WINBASEAPI UINT WINAPI GetConsoleOutputCP(VOID); + WINBASEAPI WINBOOL WINAPI SetConsoleOutputCP(UINT wCodePageID); + +#define CONSOLE_FULLSCREEN 1 +#define CONSOLE_FULLSCREEN_HARDWARE 2 + + WINBASEAPI WINBOOL WINAPI GetConsoleDisplayMode(LPDWORD lpModeFlags); + WINBASEAPI HWND WINAPI GetConsoleWindow(VOID); + WINBASEAPI DWORD WINAPI GetConsoleProcessList(LPDWORD lpdwProcessList,DWORD dwProcessCount); + WINBASEAPI WINBOOL WINAPI AddConsoleAliasA(LPSTR Source,LPSTR Target,LPSTR ExeName); + WINBASEAPI WINBOOL WINAPI AddConsoleAliasW(LPWSTR Source,LPWSTR Target,LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasA(LPSTR Source,LPSTR TargetBuffer,DWORD TargetBufferLength,LPSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasW(LPWSTR Source,LPWSTR TargetBuffer,DWORD TargetBufferLength,LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthA(LPSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthW(LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthA(VOID); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthW(VOID); + WINBASEAPI DWORD WINAPI GetConsoleAliasesA(LPSTR AliasBuffer,DWORD AliasBufferLength,LPSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasesW(LPWSTR AliasBuffer,DWORD AliasBufferLength,LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesA(LPSTR ExeNameBuffer,DWORD ExeNameBufferLength); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesW(LPWSTR ExeNameBuffer,DWORD ExeNameBufferLength); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/windef.h b/tcc/include/winapi/windef.h index d63bdef1..e784a008 100644 --- a/tcc/include/winapi/windef.h +++ b/tcc/include/winapi/windef.h @@ -1,293 +1,293 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINDEF_ -#define _WINDEF_ - -#ifndef STRICT -#define STRICT 1 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#ifndef BASETYPES -#define BASETYPES - typedef unsigned long ULONG; - typedef ULONG *PULONG; - typedef unsigned short USHORT; - typedef USHORT *PUSHORT; - typedef unsigned char UCHAR; - typedef UCHAR *PUCHAR; - typedef char *PSZ; -#endif - -#define MAX_PATH 260 - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef IN -#define IN -#endif - -#ifndef OUT -#define OUT -#endif - -#ifndef OPTIONAL -#define OPTIONAL -#endif - -#undef far -#undef near -#undef pascal - -#define far -#define near -#define pascal __stdcall - -#define cdecl -#ifndef CDECL -#define CDECL -#endif -#ifndef CALLBACK -#define CALLBACK __stdcall -#endif -#ifndef WINAPI -#define WINAPI __stdcall -#endif -#define WINAPIV __cdecl -#define APIENTRY WINAPI -#define APIPRIVATE WINAPI -#define PASCAL WINAPI -#define WINAPI_INLINE WINAPI - -#undef FAR -#undef NEAR -#define FAR -#define NEAR -#ifndef CONST -#define CONST const -#endif - - typedef unsigned long DWORD; - typedef int WINBOOL; -#define BOOL WINBOOL - typedef unsigned char BYTE; - typedef unsigned short WORD; - typedef float FLOAT; - typedef FLOAT *PFLOAT; - typedef WINBOOL *PBOOL; - typedef WINBOOL *LPBOOL; - typedef BYTE *PBYTE; - typedef BYTE *LPBYTE; - typedef int *PINT; - typedef int *LPINT; - typedef WORD *PWORD; - typedef WORD *LPWORD; - typedef long *LPLONG; - typedef DWORD *PDWORD; - typedef DWORD *LPDWORD; - typedef void *LPVOID; -# ifndef _LPCVOID_DEFINED -#define _LPCVOID_DEFINED -typedef CONST void *LPCVOID; -#endif - typedef int INT; - typedef unsigned int UINT; - typedef unsigned int *PUINT; - -#ifndef NT_INCLUDED -#include -#endif - -//gr #include - - typedef UINT_PTR WPARAM; - typedef LONG_PTR LPARAM; - typedef LONG_PTR LRESULT; - -#ifndef __cplusplus -#ifndef NOMINMAX -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#endif -#endif - -#define MAKEWORD(a,b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8)) -#define MAKELONG(a,b) ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16)) -#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) -#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) -#define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff)) -#define HIBYTE(w) ((BYTE)((DWORD_PTR)(w) >> 8)) - -#ifndef WIN_INTERNAL - DECLARE_HANDLE (HWND); - DECLARE_HANDLE (HHOOK); -#ifdef WINABLE - DECLARE_HANDLE (HEVENT); -#endif -#endif - - typedef WORD ATOM; - - typedef HANDLE *SPHANDLE; - typedef HANDLE *LPHANDLE; - typedef HANDLE HGLOBAL; - typedef HANDLE HLOCAL; - typedef HANDLE GLOBALHANDLE; - typedef HANDLE LOCALHANDLE; -#ifdef _WIN64 - typedef INT_PTR (WINAPI *FARPROC)(); - typedef INT_PTR (WINAPI *NEARPROC)(); - typedef INT_PTR (WINAPI *PROC)(); -#else - typedef int (WINAPI *FARPROC)(); - typedef int (WINAPI *NEARPROC)(); - typedef int (WINAPI *PROC)(); -#endif - - typedef void *HGDIOBJ; - - DECLARE_HANDLE(HKEY); - typedef HKEY *PHKEY; - - DECLARE_HANDLE(HACCEL); - DECLARE_HANDLE(HBITMAP); - DECLARE_HANDLE(HBRUSH); - DECLARE_HANDLE(HCOLORSPACE); - DECLARE_HANDLE(HDC); - DECLARE_HANDLE(HGLRC); - DECLARE_HANDLE(HDESK); - DECLARE_HANDLE(HENHMETAFILE); - DECLARE_HANDLE(HFONT); - DECLARE_HANDLE(HICON); - DECLARE_HANDLE(HMENU); - DECLARE_HANDLE(HMETAFILE); - DECLARE_HANDLE(HINSTANCE); - typedef HINSTANCE HMODULE; - DECLARE_HANDLE(HPALETTE); - DECLARE_HANDLE(HPEN); - DECLARE_HANDLE(HRGN); - DECLARE_HANDLE(HRSRC); - DECLARE_HANDLE(HSTR); - DECLARE_HANDLE(HTASK); - DECLARE_HANDLE(HWINSTA); - DECLARE_HANDLE(HKL); - DECLARE_HANDLE(HMONITOR); - DECLARE_HANDLE(HWINEVENTHOOK); - DECLARE_HANDLE(HUMPD); - - typedef int HFILE; - typedef HICON HCURSOR; - typedef DWORD COLORREF; - typedef DWORD *LPCOLORREF; - -#define HFILE_ERROR ((HFILE)-1) - - typedef struct tagRECT { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECT,*PRECT,*NPRECT,*LPRECT; - - typedef const RECT *LPCRECT; - - typedef struct _RECTL { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECTL,*PRECTL,*LPRECTL; - - typedef const RECTL *LPCRECTL; - - typedef struct tagPOINT { - LONG x; - LONG y; - } POINT,*PPOINT,*NPPOINT,*LPPOINT; - - typedef struct _POINTL { - LONG x; - LONG y; - } POINTL,*PPOINTL; - - typedef struct tagSIZE { - LONG cx; - LONG cy; - } SIZE,*PSIZE,*LPSIZE; - - typedef SIZE SIZEL; - typedef SIZE *PSIZEL,*LPSIZEL; - - typedef struct tagPOINTS { - SHORT x; - SHORT y; - } POINTS,*PPOINTS,*LPPOINTS; - - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME,*PFILETIME,*LPFILETIME; -#define _FILETIME_ - -#define DM_UPDATE 1 -#define DM_COPY 2 -#define DM_PROMPT 4 -#define DM_MODIFY 8 - -#define DM_IN_BUFFER DM_MODIFY -#define DM_IN_PROMPT DM_PROMPT -#define DM_OUT_BUFFER DM_COPY -#define DM_OUT_DEFAULT DM_UPDATE - -#define DC_FIELDS 1 -#define DC_PAPERS 2 -#define DC_PAPERSIZE 3 -#define DC_MINEXTENT 4 -#define DC_MAXEXTENT 5 -#define DC_BINS 6 -#define DC_DUPLEX 7 -#define DC_SIZE 8 -#define DC_EXTRA 9 -#define DC_VERSION 10 -#define DC_DRIVER 11 -#define DC_BINNAMES 12 -#define DC_ENUMRESOLUTIONS 13 -#define DC_FILEDEPENDENCIES 14 -#define DC_TRUETYPE 15 -#define DC_PAPERNAMES 16 -#define DC_ORIENTATION 17 -#define DC_COPIES 18 - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINDEF_ +#define _WINDEF_ + +#ifndef STRICT +#define STRICT 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#ifndef BASETYPES +#define BASETYPES + typedef unsigned long ULONG; + typedef ULONG *PULONG; + typedef unsigned short USHORT; + typedef USHORT *PUSHORT; + typedef unsigned char UCHAR; + typedef UCHAR *PUCHAR; + typedef char *PSZ; +#endif + +#define MAX_PATH 260 + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + +#ifndef OPTIONAL +#define OPTIONAL +#endif + +#undef far +#undef near +#undef pascal + +#define far +#define near +#define pascal __stdcall + +#define cdecl +#ifndef CDECL +#define CDECL +#endif +#ifndef CALLBACK +#define CALLBACK __stdcall +#endif +#ifndef WINAPI +#define WINAPI __stdcall +#endif +#define WINAPIV __cdecl +#define APIENTRY WINAPI +#define APIPRIVATE WINAPI +#define PASCAL WINAPI +#define WINAPI_INLINE WINAPI + +#undef FAR +#undef NEAR +#define FAR +#define NEAR +#ifndef CONST +#define CONST const +#endif + + typedef unsigned long DWORD; + typedef int WINBOOL; +#define BOOL WINBOOL + typedef unsigned char BYTE; + typedef unsigned short WORD; + typedef float FLOAT; + typedef FLOAT *PFLOAT; + typedef WINBOOL *PBOOL; + typedef WINBOOL *LPBOOL; + typedef BYTE *PBYTE; + typedef BYTE *LPBYTE; + typedef int *PINT; + typedef int *LPINT; + typedef WORD *PWORD; + typedef WORD *LPWORD; + typedef long *LPLONG; + typedef DWORD *PDWORD; + typedef DWORD *LPDWORD; + typedef void *LPVOID; +# ifndef _LPCVOID_DEFINED +#define _LPCVOID_DEFINED +typedef CONST void *LPCVOID; +#endif + typedef int INT; + typedef unsigned int UINT; + typedef unsigned int *PUINT; + +#ifndef NT_INCLUDED +#include +#endif + +//gr #include + + typedef UINT_PTR WPARAM; + typedef LONG_PTR LPARAM; + typedef LONG_PTR LRESULT; + +#ifndef __cplusplus +#ifndef NOMINMAX +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#endif +#endif + +#define MAKEWORD(a,b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8)) +#define MAKELONG(a,b) ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16)) +#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) +#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) +#define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff)) +#define HIBYTE(w) ((BYTE)((DWORD_PTR)(w) >> 8)) + +#ifndef WIN_INTERNAL + DECLARE_HANDLE (HWND); + DECLARE_HANDLE (HHOOK); +#ifdef WINABLE + DECLARE_HANDLE (HEVENT); +#endif +#endif + + typedef WORD ATOM; + + typedef HANDLE *SPHANDLE; + typedef HANDLE *LPHANDLE; + typedef HANDLE HGLOBAL; + typedef HANDLE HLOCAL; + typedef HANDLE GLOBALHANDLE; + typedef HANDLE LOCALHANDLE; +#ifdef _WIN64 + typedef INT_PTR (WINAPI *FARPROC)(); + typedef INT_PTR (WINAPI *NEARPROC)(); + typedef INT_PTR (WINAPI *PROC)(); +#else + typedef int (WINAPI *FARPROC)(); + typedef int (WINAPI *NEARPROC)(); + typedef int (WINAPI *PROC)(); +#endif + + typedef void *HGDIOBJ; + + DECLARE_HANDLE(HKEY); + typedef HKEY *PHKEY; + + DECLARE_HANDLE(HACCEL); + DECLARE_HANDLE(HBITMAP); + DECLARE_HANDLE(HBRUSH); + DECLARE_HANDLE(HCOLORSPACE); + DECLARE_HANDLE(HDC); + DECLARE_HANDLE(HGLRC); + DECLARE_HANDLE(HDESK); + DECLARE_HANDLE(HENHMETAFILE); + DECLARE_HANDLE(HFONT); + DECLARE_HANDLE(HICON); + DECLARE_HANDLE(HMENU); + DECLARE_HANDLE(HMETAFILE); + DECLARE_HANDLE(HINSTANCE); + typedef HINSTANCE HMODULE; + DECLARE_HANDLE(HPALETTE); + DECLARE_HANDLE(HPEN); + DECLARE_HANDLE(HRGN); + DECLARE_HANDLE(HRSRC); + DECLARE_HANDLE(HSTR); + DECLARE_HANDLE(HTASK); + DECLARE_HANDLE(HWINSTA); + DECLARE_HANDLE(HKL); + DECLARE_HANDLE(HMONITOR); + DECLARE_HANDLE(HWINEVENTHOOK); + DECLARE_HANDLE(HUMPD); + + typedef int HFILE; + typedef HICON HCURSOR; + typedef DWORD COLORREF; + typedef DWORD *LPCOLORREF; + +#define HFILE_ERROR ((HFILE)-1) + + typedef struct tagRECT { + LONG left; + LONG top; + LONG right; + LONG bottom; + } RECT,*PRECT,*NPRECT,*LPRECT; + + typedef const RECT *LPCRECT; + + typedef struct _RECTL { + LONG left; + LONG top; + LONG right; + LONG bottom; + } RECTL,*PRECTL,*LPRECTL; + + typedef const RECTL *LPCRECTL; + + typedef struct tagPOINT { + LONG x; + LONG y; + } POINT,*PPOINT,*NPPOINT,*LPPOINT; + + typedef struct _POINTL { + LONG x; + LONG y; + } POINTL,*PPOINTL; + + typedef struct tagSIZE { + LONG cx; + LONG cy; + } SIZE,*PSIZE,*LPSIZE; + + typedef SIZE SIZEL; + typedef SIZE *PSIZEL,*LPSIZEL; + + typedef struct tagPOINTS { + SHORT x; + SHORT y; + } POINTS,*PPOINTS,*LPPOINTS; + + typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; + } FILETIME,*PFILETIME,*LPFILETIME; +#define _FILETIME_ + +#define DM_UPDATE 1 +#define DM_COPY 2 +#define DM_PROMPT 4 +#define DM_MODIFY 8 + +#define DM_IN_BUFFER DM_MODIFY +#define DM_IN_PROMPT DM_PROMPT +#define DM_OUT_BUFFER DM_COPY +#define DM_OUT_DEFAULT DM_UPDATE + +#define DC_FIELDS 1 +#define DC_PAPERS 2 +#define DC_PAPERSIZE 3 +#define DC_MINEXTENT 4 +#define DC_MAXEXTENT 5 +#define DC_BINS 6 +#define DC_DUPLEX 7 +#define DC_SIZE 8 +#define DC_EXTRA 9 +#define DC_VERSION 10 +#define DC_DRIVER 11 +#define DC_BINNAMES 12 +#define DC_ENUMRESOLUTIONS 13 +#define DC_FILEDEPENDENCIES 14 +#define DC_TRUETYPE 15 +#define DC_PAPERNAMES 16 +#define DC_ORIENTATION 17 +#define DC_COPIES 18 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/windows.h b/tcc/include/winapi/windows.h index ff6454a9..ebbeed59 100644 --- a/tcc/include/winapi/windows.h +++ b/tcc/include/winapi/windows.h @@ -1,127 +1,127 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINDOWS_ -#define _WINDOWS_ - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#include <_mingw.h> - -#ifndef _INC_WINDOWS -#define _INC_WINDOWS - -#if defined(RC_INVOKED) && !defined(NOWINRES) - -#include -#else - -#ifdef RC_INVOKED -#define NOATOM -#define NOGDI -#define NOGDICAPMASKS -#define NOMETAFILE -#define NOMINMAX -#define NOMSG -#define NOOPENFILE -#define NORASTEROPS -#define NOSCROLL -#define NOSOUND -#define NOSYSMETRICS -#define NOTEXTMETRIC -#define NOWH -#define NOCOMM -#define NOKANJI -#define NOCRYPT -#define NOMCX -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) -#define I_X86_ -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) -#define _AMD64_ -#endif - -#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) -#if !defined(_IA64_) -#define _IA64_ -#endif -#endif - -#ifndef RC_INVOKED -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -//gr #include - -#ifndef WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef NOCRYPT -#include -#include -#include -#endif - -#ifndef NOUSER -#ifndef NOGDI -#include -#ifdef INC_OLE1 -#include -#else -#include -#endif -#include -#endif -#endif -#endif - -//gr #include - -#ifdef INC_OLE2 -#include -#endif - -#ifndef NOSERVICE -#include -#endif - -#ifndef NOMCX -#include -#endif - -#ifndef NOIME -#include -#endif - -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINDOWS_ +#define _WINDOWS_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#include <_mingw.h> + +#ifndef _INC_WINDOWS +#define _INC_WINDOWS + +#if defined(RC_INVOKED) && !defined(NOWINRES) + +#include +#else + +#ifdef RC_INVOKED +#define NOATOM +#define NOGDI +#define NOGDICAPMASKS +#define NOMETAFILE +#define NOMINMAX +#define NOMSG +#define NOOPENFILE +#define NORASTEROPS +#define NOSCROLL +#define NOSOUND +#define NOSYSMETRICS +#define NOTEXTMETRIC +#define NOWH +#define NOCOMM +#define NOKANJI +#define NOCRYPT +#define NOMCX +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) +#define I_X86_ +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) +#define _AMD64_ +#endif + +#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) +#if !defined(_IA64_) +#define _IA64_ +#endif +#endif + +#ifndef RC_INVOKED +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +//gr #include + +#ifndef WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef NOCRYPT +#include +#include +#include +#endif + +#ifndef NOUSER +#ifndef NOGDI +#include +#ifdef INC_OLE1 +#include +#else +#include +#endif +#include +#endif +#endif +#endif + +//gr #include + +#ifdef INC_OLE2 +#include +#endif + +#ifndef NOSERVICE +#include +#endif + +#ifndef NOMCX +#include +#endif + +#ifndef NOIME +#include +#endif + +#endif +#endif +#endif diff --git a/tcc/include/winapi/winerror.h b/tcc/include/winapi/winerror.h index 77d85edc..4524a3c1 100644 --- a/tcc/include/winapi/winerror.h +++ b/tcc/include/winapi/winerror.h @@ -1,3166 +1,3166 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINERROR_ -#define _WINERROR_ - -#define FACILITY_WINDOWSUPDATE 36 -#define FACILITY_WINDOWS_CE 24 -#define FACILITY_WINDOWS 8 -#define FACILITY_URT 19 -#define FACILITY_UMI 22 -#define FACILITY_SXS 23 -#define FACILITY_STORAGE 3 -#define FACILITY_STATE_MANAGEMENT 34 -#define FACILITY_SSPI 9 -#define FACILITY_SCARD 16 -#define FACILITY_SETUPAPI 15 -#define FACILITY_SECURITY 9 -#define FACILITY_RPC 1 -#define FACILITY_WIN32 7 -#define FACILITY_CONTROL 10 -#define FACILITY_NULL 0 -#define FACILITY_METADIRECTORY 35 -#define FACILITY_MSMQ 14 -#define FACILITY_MEDIASERVER 13 -#define FACILITY_INTERNET 12 -#define FACILITY_ITF 4 -#define FACILITY_HTTP 25 -#define FACILITY_DPLAY 21 -#define FACILITY_DISPATCH 2 -#define FACILITY_DIRECTORYSERVICE 37 -#define FACILITY_CONFIGURATION 33 -#define FACILITY_COMPLUS 17 -#define FACILITY_CERT 11 -#define FACILITY_BACKGROUNDCOPY 32 -#define FACILITY_ACS 20 -#define FACILITY_AAF 18 -#define ERROR_SUCCESS 0L -#define NO_ERROR 0L -#define SEC_E_OK ((HRESULT)0x00000000L) -#define ERROR_INVALID_FUNCTION 1L -#define ERROR_FILE_NOT_FOUND 2L -#define ERROR_PATH_NOT_FOUND 3L -#define ERROR_TOO_MANY_OPEN_FILES 4L -#define ERROR_ACCESS_DENIED 5L -#define ERROR_INVALID_HANDLE 6L -#define ERROR_ARENA_TRASHED 7L -#define ERROR_NOT_ENOUGH_MEMORY 8L -#define ERROR_INVALID_BLOCK 9L -#define ERROR_BAD_ENVIRONMENT 10L -#define ERROR_BAD_FORMAT 11L -#define ERROR_INVALID_ACCESS 12L -#define ERROR_INVALID_DATA 13L -#define ERROR_OUTOFMEMORY 14L -#define ERROR_INVALID_DRIVE 15L -#define ERROR_CURRENT_DIRECTORY 16L -#define ERROR_NOT_SAME_DEVICE 17L -#define ERROR_NO_MORE_FILES 18L -#define ERROR_WRITE_PROTECT 19L -#define ERROR_BAD_UNIT 20L -#define ERROR_NOT_READY 21L -#define ERROR_BAD_COMMAND 22L -#define ERROR_CRC 23L -#define ERROR_BAD_LENGTH 24L -#define ERROR_SEEK 25L -#define ERROR_NOT_DOS_DISK 26L -#define ERROR_SECTOR_NOT_FOUND 27L -#define ERROR_OUT_OF_PAPER 28L -#define ERROR_WRITE_FAULT 29L -#define ERROR_READ_FAULT 30L -#define ERROR_GEN_FAILURE 31L -#define ERROR_SHARING_VIOLATION 32L -#define ERROR_LOCK_VIOLATION 33L -#define ERROR_WRONG_DISK 34L -#define ERROR_SHARING_BUFFER_EXCEEDED 36L -#define ERROR_HANDLE_EOF 38L -#define ERROR_HANDLE_DISK_FULL 39L -#define ERROR_NOT_SUPPORTED 50L -#define ERROR_REM_NOT_LIST 51L -#define ERROR_DUP_NAME 52L -#define ERROR_BAD_NETPATH 53L -#define ERROR_NETWORK_BUSY 54L -#define ERROR_DEV_NOT_EXIST 55L -#define ERROR_TOO_MANY_CMDS 56L -#define ERROR_ADAP_HDW_ERR 57L -#define ERROR_BAD_NET_RESP 58L -#define ERROR_UNEXP_NET_ERR 59L -#define ERROR_BAD_REM_ADAP 60L -#define ERROR_PRINTQ_FULL 61L -#define ERROR_NO_SPOOL_SPACE 62L -#define ERROR_PRINT_CANCELLED 63L -#define ERROR_NETNAME_DELETED 64L -#define ERROR_NETWORK_ACCESS_DENIED 65L -#define ERROR_BAD_DEV_TYPE 66L -#define ERROR_BAD_NET_NAME 67L -#define ERROR_TOO_MANY_NAMES 68L -#define ERROR_TOO_MANY_SESS 69L -#define ERROR_SHARING_PAUSED 70L -#define ERROR_REQ_NOT_ACCEP 71L -#define ERROR_REDIR_PAUSED 72L -#define ERROR_FILE_EXISTS 80L -#define ERROR_CANNOT_MAKE 82L -#define ERROR_FAIL_I24 83L -#define ERROR_OUT_OF_STRUCTURES 84L -#define ERROR_ALREADY_ASSIGNED 85L -#define ERROR_INVALID_PASSWORD 86L -#define ERROR_INVALID_PARAMETER 87L -#define ERROR_NET_WRITE_FAULT 88L -#define ERROR_NO_PROC_SLOTS 89L -#define ERROR_TOO_MANY_SEMAPHORES 100L -#define ERROR_EXCL_SEM_ALREADY_OWNED 101L -#define ERROR_SEM_IS_SET 102L -#define ERROR_TOO_MANY_SEM_REQUESTS 103L -#define ERROR_INVALID_AT_INTERRUPT_TIME 104L -#define ERROR_SEM_OWNER_DIED 105L -#define ERROR_SEM_USER_LIMIT 106L -#define ERROR_DISK_CHANGE 107L -#define ERROR_DRIVE_LOCKED 108L -#define ERROR_BROKEN_PIPE 109L -#define ERROR_OPEN_FAILED 110L -#define ERROR_BUFFER_OVERFLOW 111L -#define ERROR_DISK_FULL 112L -#define ERROR_NO_MORE_SEARCH_HANDLES 113L -#define ERROR_INVALID_TARGET_HANDLE 114L -#define ERROR_INVALID_CATEGORY 117L -#define ERROR_INVALID_VERIFY_SWITCH 118L -#define ERROR_BAD_DRIVER_LEVEL 119L -#define ERROR_CALL_NOT_IMPLEMENTED 120L -#define ERROR_SEM_TIMEOUT 121L -#define ERROR_INSUFFICIENT_BUFFER 122L -#define ERROR_INVALID_NAME 123L -#define ERROR_INVALID_LEVEL 124L -#define ERROR_NO_VOLUME_LABEL 125L -#define ERROR_MOD_NOT_FOUND 126L -#define ERROR_PROC_NOT_FOUND 127L -#define ERROR_WAIT_NO_CHILDREN 128L -#define ERROR_CHILD_NOT_COMPLETE 129L -#define ERROR_DIRECT_ACCESS_HANDLE 130L -#define ERROR_NEGATIVE_SEEK 131L -#define ERROR_SEEK_ON_DEVICE 132L -#define ERROR_IS_JOIN_TARGET 133L -#define ERROR_IS_JOINED 134L -#define ERROR_IS_SUBSTED 135L -#define ERROR_NOT_JOINED 136L -#define ERROR_NOT_SUBSTED 137L -#define ERROR_JOIN_TO_JOIN 138L -#define ERROR_SUBST_TO_SUBST 139L -#define ERROR_JOIN_TO_SUBST 140L -#define ERROR_SUBST_TO_JOIN 141L -#define ERROR_BUSY_DRIVE 142L -#define ERROR_SAME_DRIVE 143L -#define ERROR_DIR_NOT_ROOT 144L -#define ERROR_DIR_NOT_EMPTY 145L -#define ERROR_IS_SUBST_PATH 146L -#define ERROR_IS_JOIN_PATH 147L -#define ERROR_PATH_BUSY 148L -#define ERROR_IS_SUBST_TARGET 149L -#define ERROR_SYSTEM_TRACE 150L -#define ERROR_INVALID_EVENT_COUNT 151L -#define ERROR_TOO_MANY_MUXWAITERS 152L -#define ERROR_INVALID_LIST_FORMAT 153L -#define ERROR_LABEL_TOO_LONG 154L -#define ERROR_TOO_MANY_TCBS 155L -#define ERROR_SIGNAL_REFUSED 156L -#define ERROR_DISCARDED 157L -#define ERROR_NOT_LOCKED 158L -#define ERROR_BAD_THREADID_ADDR 159L -#define ERROR_BAD_ARGUMENTS 160L -#define ERROR_BAD_PATHNAME 161L -#define ERROR_SIGNAL_PENDING 162L -#define ERROR_MAX_THRDS_REACHED 164L -#define ERROR_LOCK_FAILED 167L -#define ERROR_BUSY 170L -#define ERROR_CANCEL_VIOLATION 173L -#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174L -#define ERROR_INVALID_SEGMENT_NUMBER 180L -#define ERROR_INVALID_ORDINAL 182L -#define ERROR_ALREADY_EXISTS 183L -#define ERROR_INVALID_FLAG_NUMBER 186L -#define ERROR_SEM_NOT_FOUND 187L -#define ERROR_INVALID_STARTING_CODESEG 188L -#define ERROR_INVALID_STACKSEG 189L -#define ERROR_INVALID_MODULETYPE 190L -#define ERROR_INVALID_EXE_SIGNATURE 191L -#define ERROR_EXE_MARKED_INVALID 192L -#define ERROR_BAD_EXE_FORMAT 193L -#define ERROR_ITERATED_DATA_EXCEEDS_64k 194L -#define ERROR_INVALID_MINALLOCSIZE 195L -#define ERROR_DYNLINK_FROM_INVALID_RING 196L -#define ERROR_IOPL_NOT_ENABLED 197L -#define ERROR_INVALID_SEGDPL 198L -#define ERROR_AUTODATASEG_EXCEEDS_64k 199L -#define ERROR_RING2SEG_MUST_BE_MOVABLE 200L -#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201L -#define ERROR_INFLOOP_IN_RELOC_CHAIN 202L -#define ERROR_ENVVAR_NOT_FOUND 203L -#define ERROR_NO_SIGNAL_SENT 205L -#define ERROR_FILENAME_EXCED_RANGE 206L -#define ERROR_RING2_STACK_IN_USE 207L -#define ERROR_META_EXPANSION_TOO_LONG 208L -#define ERROR_INVALID_SIGNAL_NUMBER 209L -#define ERROR_THREAD_1_INACTIVE 210L -#define ERROR_LOCKED 212L -#define ERROR_TOO_MANY_MODULES 214L -#define ERROR_NESTING_NOT_ALLOWED 215L -#define ERROR_EXE_MACHINE_TYPE_MISMATCH 216L -#define ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY 217L -#define ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY 218L -#define ERROR_BAD_PIPE 230L -#define ERROR_PIPE_BUSY 231L -#define ERROR_NO_DATA 232L -#define ERROR_PIPE_NOT_CONNECTED 233L -#define ERROR_MORE_DATA 234L -#define ERROR_VC_DISCONNECTED 240L -#define ERROR_INVALID_EA_NAME 254L -#define ERROR_EA_LIST_INCONSISTENT 255L -#define WAIT_TIMEOUT 258L -#define ERROR_NO_MORE_ITEMS 259L -#define ERROR_CANNOT_COPY 266L -#define ERROR_DIRECTORY 267L -#define ERROR_EAS_DIDNT_FIT 275L -#define ERROR_EA_FILE_CORRUPT 276L -#define ERROR_EA_TABLE_FULL 277L -#define ERROR_INVALID_EA_HANDLE 278L -#define ERROR_EAS_NOT_SUPPORTED 282L -#define ERROR_NOT_OWNER 288L -#define ERROR_TOO_MANY_POSTS 298L -#define ERROR_PARTIAL_COPY 299L -#define ERROR_OPLOCK_NOT_GRANTED 300L -#define ERROR_INVALID_OPLOCK_PROTOCOL 301L -#define ERROR_DISK_TOO_FRAGMENTED 302L -#define ERROR_DELETE_PENDING 303L -#define ERROR_MR_MID_NOT_FOUND 317L -#define ERROR_SCOPE_NOT_FOUND 318L -#define ERROR_INVALID_ADDRESS 487L -#define ERROR_ARITHMETIC_OVERFLOW 534L -#define ERROR_PIPE_CONNECTED 535L -#define ERROR_PIPE_LISTENING 536L -#define ERROR_EA_ACCESS_DENIED 994L -#define ERROR_OPERATION_ABORTED 995L -#define ERROR_IO_INCOMPLETE 996L -#define ERROR_IO_PENDING 997L -#define ERROR_NOACCESS 998L -#define ERROR_SWAPERROR 999L -#define ERROR_STACK_OVERFLOW 1001L -#define ERROR_INVALID_MESSAGE 1002L -#define ERROR_CAN_NOT_COMPLETE 1003L -#define ERROR_INVALID_FLAGS 1004L -#define ERROR_UNRECOGNIZED_VOLUME 1005L -#define ERROR_FILE_INVALID 1006L -#define ERROR_FULLSCREEN_MODE 1007L -#define ERROR_NO_TOKEN 1008L -#define ERROR_BADDB 1009L -#define ERROR_BADKEY 1010L -#define ERROR_CANTOPEN 1011L -#define ERROR_CANTREAD 1012L -#define ERROR_CANTWRITE 1013L -#define ERROR_REGISTRY_RECOVERED 1014L -#define ERROR_REGISTRY_CORRUPT 1015L -#define ERROR_REGISTRY_IO_FAILED 1016L -#define ERROR_NOT_REGISTRY_FILE 1017L -#define ERROR_KEY_DELETED 1018L -#define ERROR_NO_LOG_SPACE 1019L -#define ERROR_KEY_HAS_CHILDREN 1020L -#define ERROR_CHILD_MUST_BE_VOLATILE 1021L -#define ERROR_NOTIFY_ENUM_DIR 1022L -#define ERROR_DEPENDENT_SERVICES_RUNNING 1051L -#define ERROR_INVALID_SERVICE_CONTROL 1052L -#define ERROR_SERVICE_REQUEST_TIMEOUT 1053L -#define ERROR_SERVICE_NO_THREAD 1054L -#define ERROR_SERVICE_DATABASE_LOCKED 1055L -#define ERROR_SERVICE_ALREADY_RUNNING 1056L -#define ERROR_INVALID_SERVICE_ACCOUNT 1057L -#define ERROR_SERVICE_DISABLED 1058L -#define ERROR_CIRCULAR_DEPENDENCY 1059L -#define ERROR_SERVICE_DOES_NOT_EXIST 1060L -#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061L -#define ERROR_SERVICE_NOT_ACTIVE 1062L -#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063L -#define ERROR_EXCEPTION_IN_SERVICE 1064L -#define ERROR_DATABASE_DOES_NOT_EXIST 1065L -#define ERROR_SERVICE_SPECIFIC_ERROR 1066L -#define ERROR_PROCESS_ABORTED 1067L -#define ERROR_SERVICE_DEPENDENCY_FAIL 1068L -#define ERROR_SERVICE_LOGON_FAILED 1069L -#define ERROR_SERVICE_START_HANG 1070L -#define ERROR_INVALID_SERVICE_LOCK 1071L -#define ERROR_SERVICE_MARKED_FOR_DELETE 1072L -#define ERROR_SERVICE_EXISTS 1073L -#define ERROR_ALREADY_RUNNING_LKG 1074L -#define ERROR_SERVICE_DEPENDENCY_DELETED 1075L -#define ERROR_BOOT_ALREADY_ACCEPTED 1076L -#define ERROR_SERVICE_NEVER_STARTED 1077L -#define ERROR_DUPLICATE_SERVICE_NAME 1078L -#define ERROR_DIFFERENT_SERVICE_ACCOUNT 1079L -#define ERROR_CANNOT_DETECT_DRIVER_FAILURE 1080L -#define ERROR_CANNOT_DETECT_PROCESS_ABORT 1081L -#define ERROR_NO_RECOVERY_PROGRAM 1082L -#define ERROR_SERVICE_NOT_IN_EXE 1083L -#define ERROR_NOT_SAFEBOOT_SERVICE 1084L -#define ERROR_END_OF_MEDIA 1100L -#define ERROR_FILEMARK_DETECTED 1101L -#define ERROR_BEGINNING_OF_MEDIA 1102L -#define ERROR_SETMARK_DETECTED 1103L -#define ERROR_NO_DATA_DETECTED 1104L -#define ERROR_PARTITION_FAILURE 1105L -#define ERROR_INVALID_BLOCK_LENGTH 1106L -#define ERROR_DEVICE_NOT_PARTITIONED 1107L -#define ERROR_UNABLE_TO_LOCK_MEDIA 1108L -#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109L -#define ERROR_MEDIA_CHANGED 1110L -#define ERROR_BUS_RESET 1111L -#define ERROR_NO_MEDIA_IN_DRIVE 1112L -#define ERROR_NO_UNICODE_TRANSLATION 1113L -#define ERROR_DLL_INIT_FAILED 1114L -#define ERROR_SHUTDOWN_IN_PROGRESS 1115L -#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116L -#define ERROR_IO_DEVICE 1117L -#define ERROR_SERIAL_NO_DEVICE 1118L -#define ERROR_IRQ_BUSY 1119L -#define ERROR_MORE_WRITES 1120L -#define ERROR_COUNTER_TIMEOUT 1121L -#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122L -#define ERROR_FLOPPY_WRONG_CYLINDER 1123L -#define ERROR_FLOPPY_UNKNOWN_ERROR 1124L -#define ERROR_FLOPPY_BAD_REGISTERS 1125L -#define ERROR_DISK_RECALIBRATE_FAILED 1126L -#define ERROR_DISK_OPERATION_FAILED 1127L -#define ERROR_DISK_RESET_FAILED 1128L -#define ERROR_EOM_OVERFLOW 1129L -#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130L -#define ERROR_POSSIBLE_DEADLOCK 1131L -#define ERROR_MAPPED_ALIGNMENT 1132L -#define ERROR_SET_POWER_STATE_VETOED 1140L -#define ERROR_SET_POWER_STATE_FAILED 1141L -#define ERROR_TOO_MANY_LINKS 1142L -#define ERROR_OLD_WIN_VERSION 1150L -#define ERROR_APP_WRONG_OS 1151L -#define ERROR_SINGLE_INSTANCE_APP 1152L -#define ERROR_RMODE_APP 1153L -#define ERROR_INVALID_DLL 1154L -#define ERROR_NO_ASSOCIATION 1155L -#define ERROR_DDE_FAIL 1156L -#define ERROR_DLL_NOT_FOUND 1157L -#define ERROR_NO_MORE_USER_HANDLES 1158L -#define ERROR_MESSAGE_SYNC_ONLY 1159L -#define ERROR_SOURCE_ELEMENT_EMPTY 1160L -#define ERROR_DESTINATION_ELEMENT_FULL 1161L -#define ERROR_ILLEGAL_ELEMENT_ADDRESS 1162L -#define ERROR_MAGAZINE_NOT_PRESENT 1163L -#define ERROR_DEVICE_REINITIALIZATION_NEEDED 1164L -#define ERROR_DEVICE_REQUIRES_CLEANING 1165L -#define ERROR_DEVICE_DOOR_OPEN 1166L -#define ERROR_DEVICE_NOT_CONNECTED 1167L -#define ERROR_NOT_FOUND 1168L -#define ERROR_NO_MATCH 1169L -#define ERROR_SET_NOT_FOUND 1170L -#define ERROR_POINT_NOT_FOUND 1171L -#define ERROR_NO_TRACKING_SERVICE 1172L -#define ERROR_NO_VOLUME_ID 1173L -#define ERROR_UNABLE_TO_REMOVE_REPLACED 1175L -#define ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176L -#define ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 1177L -#define ERROR_JOURNAL_DELETE_IN_PROGRESS 1178L -#define ERROR_JOURNAL_NOT_ACTIVE 1179L -#define ERROR_POTENTIAL_FILE_FOUND 1180L -#define ERROR_JOURNAL_ENTRY_DELETED 1181L -#define ERROR_BAD_DEVICE 1200L -#define ERROR_CONNECTION_UNAVAIL 1201L -#define ERROR_DEVICE_ALREADY_REMEMBERED 1202L -#define ERROR_NO_NET_OR_BAD_PATH 1203L -#define ERROR_BAD_PROVIDER 1204L -#define ERROR_CANNOT_OPEN_PROFILE 1205L -#define ERROR_BAD_PROFILE 1206L -#define ERROR_NOT_CONTAINER 1207L -#define ERROR_EXTENDED_ERROR 1208L -#define ERROR_INVALID_GROUPNAME 1209L -#define ERROR_INVALID_COMPUTERNAME 1210L -#define ERROR_INVALID_EVENTNAME 1211L -#define ERROR_INVALID_DOMAINNAME 1212L -#define ERROR_INVALID_SERVICENAME 1213L -#define ERROR_INVALID_NETNAME 1214L -#define ERROR_INVALID_SHARENAME 1215L -#define ERROR_INVALID_PASSWORDNAME 1216L -#define ERROR_INVALID_MESSAGENAME 1217L -#define ERROR_INVALID_MESSAGEDEST 1218L -#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219L -#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220L -#define ERROR_DUP_DOMAINNAME 1221L -#define ERROR_NO_NETWORK 1222L -#define ERROR_CANCELLED 1223L -#define ERROR_USER_MAPPED_FILE 1224L -#define ERROR_CONNECTION_REFUSED 1225L -#define ERROR_GRACEFUL_DISCONNECT 1226L -#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227L -#define ERROR_ADDRESS_NOT_ASSOCIATED 1228L -#define ERROR_CONNECTION_INVALID 1229L -#define ERROR_CONNECTION_ACTIVE 1230L -#define ERROR_NETWORK_UNREACHABLE 1231L -#define ERROR_HOST_UNREACHABLE 1232L -#define ERROR_PROTOCOL_UNREACHABLE 1233L -#define ERROR_PORT_UNREACHABLE 1234L -#define ERROR_REQUEST_ABORTED 1235L -#define ERROR_CONNECTION_ABORTED 1236L -#define ERROR_RETRY 1237L -#define ERROR_CONNECTION_COUNT_LIMIT 1238L -#define ERROR_LOGIN_TIME_RESTRICTION 1239L -#define ERROR_LOGIN_WKSTA_RESTRICTION 1240L -#define ERROR_INCORRECT_ADDRESS 1241L -#define ERROR_ALREADY_REGISTERED 1242L -#define ERROR_SERVICE_NOT_FOUND 1243L -#define ERROR_NOT_AUTHENTICATED 1244L -#define ERROR_NOT_LOGGED_ON 1245L -#define ERROR_CONTINUE 1246L -#define ERROR_ALREADY_INITIALIZED 1247L -#define ERROR_NO_MORE_DEVICES 1248L -#define ERROR_NO_SUCH_SITE 1249L -#define ERROR_DOMAIN_CONTROLLER_EXISTS 1250L -#define ERROR_ONLY_IF_CONNECTED 1251L -#define ERROR_OVERRIDE_NOCHANGES 1252L -#define ERROR_BAD_USER_PROFILE 1253L -#define ERROR_NOT_SUPPORTED_ON_SBS 1254L -#define ERROR_SERVER_SHUTDOWN_IN_PROGRESS 1255L -#define ERROR_HOST_DOWN 1256L -#define ERROR_NON_ACCOUNT_SID 1257L -#define ERROR_NON_DOMAIN_SID 1258L -#define ERROR_APPHELP_BLOCK 1259L -#define ERROR_ACCESS_DISABLED_BY_POLICY 1260L -#define ERROR_REG_NAT_CONSUMPTION 1261L -#define ERROR_CSCSHARE_OFFLINE 1262L -#define ERROR_PKINIT_FAILURE 1263L -#define ERROR_SMARTCARD_SUBSYSTEM_FAILURE 1264L -#define ERROR_DOWNGRADE_DETECTED 1265L -#define ERROR_MACHINE_LOCKED 1271L -#define ERROR_CALLBACK_SUPPLIED_INVALID_DATA 1273L -#define ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED 1274L -#define ERROR_DRIVER_BLOCKED 1275L -#define ERROR_INVALID_IMPORT_OF_NON_DLL 1276L -#define ERROR_ACCESS_DISABLED_WEBBLADE 1277L -#define ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER 1278L -#define ERROR_RECOVERY_FAILURE 1279L -#define ERROR_ALREADY_FIBER 1280L -#define ERROR_ALREADY_THREAD 1281L -#define ERROR_STACK_BUFFER_OVERRUN 1282L -#define ERROR_PARAMETER_QUOTA_EXCEEDED 1283L -#define ERROR_DEBUGGER_INACTIVE 1284L -#define ERROR_DELAY_LOAD_FAILED 1285L -#define ERROR_VDM_DISALLOWED 1286L -#define ERROR_UNIDENTIFIED_ERROR 1287L -#define ERROR_NOT_ALL_ASSIGNED 1300L -#define ERROR_SOME_NOT_MAPPED 1301L -#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302L -#define ERROR_LOCAL_USER_SESSION_KEY 1303L -#define ERROR_NULL_LM_PASSWORD 1304L -#define ERROR_UNKNOWN_REVISION 1305L -#define ERROR_REVISION_MISMATCH 1306L -#define ERROR_INVALID_OWNER 1307L -#define ERROR_INVALID_PRIMARY_GROUP 1308L -#define ERROR_NO_IMPERSONATION_TOKEN 1309L -#define ERROR_CANT_DISABLE_MANDATORY 1310L -#define ERROR_NO_LOGON_SERVERS 1311L -#define ERROR_NO_SUCH_LOGON_SESSION 1312L -#define ERROR_NO_SUCH_PRIVILEGE 1313L -#define ERROR_PRIVILEGE_NOT_HELD 1314L -#define ERROR_INVALID_ACCOUNT_NAME 1315L -#define ERROR_USER_EXISTS 1316L -#define ERROR_NO_SUCH_USER 1317L -#define ERROR_GROUP_EXISTS 1318L -#define ERROR_NO_SUCH_GROUP 1319L -#define ERROR_MEMBER_IN_GROUP 1320L -#define ERROR_MEMBER_NOT_IN_GROUP 1321L -#define ERROR_LAST_ADMIN 1322L -#define ERROR_WRONG_PASSWORD 1323L -#define ERROR_ILL_FORMED_PASSWORD 1324L -#define ERROR_PASSWORD_RESTRICTION 1325L -#define ERROR_LOGON_FAILURE 1326L -#define ERROR_ACCOUNT_RESTRICTION 1327L -#define ERROR_INVALID_LOGON_HOURS 1328L -#define ERROR_INVALID_WORKSTATION 1329L -#define ERROR_PASSWORD_EXPIRED 1330L -#define ERROR_ACCOUNT_DISABLED 1331L -#define ERROR_NONE_MAPPED 1332L -#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333L -#define ERROR_LUIDS_EXHAUSTED 1334L -#define ERROR_INVALID_SUB_AUTHORITY 1335L -#define ERROR_INVALID_ACL 1336L -#define ERROR_INVALID_SID 1337L -#define ERROR_INVALID_SECURITY_DESCR 1338L -#define ERROR_BAD_INHERITANCE_ACL 1340L -#define ERROR_SERVER_DISABLED 1341L -#define ERROR_SERVER_NOT_DISABLED 1342L -#define ERROR_INVALID_ID_AUTHORITY 1343L -#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344L -#define ERROR_INVALID_GROUP_ATTRIBUTES 1345L -#define ERROR_BAD_IMPERSONATION_LEVEL 1346L -#define ERROR_CANT_OPEN_ANONYMOUS 1347L -#define ERROR_BAD_VALIDATION_CLASS 1348L -#define ERROR_BAD_TOKEN_TYPE 1349L -#define ERROR_NO_SECURITY_ON_OBJECT 1350L -#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351L -#define ERROR_INVALID_SERVER_STATE 1352L -#define ERROR_INVALID_DOMAIN_STATE 1353L -#define ERROR_INVALID_DOMAIN_ROLE 1354L -#define ERROR_NO_SUCH_DOMAIN 1355L -#define ERROR_DOMAIN_EXISTS 1356L -#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357L -#define ERROR_INTERNAL_DB_CORRUPTION 1358L -#define ERROR_INTERNAL_ERROR 1359L -#define ERROR_GENERIC_NOT_MAPPED 1360L -#define ERROR_BAD_DESCRIPTOR_FORMAT 1361L -#define ERROR_NOT_LOGON_PROCESS 1362L -#define ERROR_LOGON_SESSION_EXISTS 1363L -#define ERROR_NO_SUCH_PACKAGE 1364L -#define ERROR_BAD_LOGON_SESSION_STATE 1365L -#define ERROR_LOGON_SESSION_COLLISION 1366L -#define ERROR_INVALID_LOGON_TYPE 1367L -#define ERROR_CANNOT_IMPERSONATE 1368L -#define ERROR_RXACT_INVALID_STATE 1369L -#define ERROR_RXACT_COMMIT_FAILURE 1370L -#define ERROR_SPECIAL_ACCOUNT 1371L -#define ERROR_SPECIAL_GROUP 1372L -#define ERROR_SPECIAL_USER 1373L -#define ERROR_MEMBERS_PRIMARY_GROUP 1374L -#define ERROR_TOKEN_ALREADY_IN_USE 1375L -#define ERROR_NO_SUCH_ALIAS 1376L -#define ERROR_MEMBER_NOT_IN_ALIAS 1377L -#define ERROR_MEMBER_IN_ALIAS 1378L -#define ERROR_ALIAS_EXISTS 1379L -#define ERROR_LOGON_NOT_GRANTED 1380L -#define ERROR_TOO_MANY_SECRETS 1381L -#define ERROR_SECRET_TOO_LONG 1382L -#define ERROR_INTERNAL_DB_ERROR 1383L -#define ERROR_TOO_MANY_CONTEXT_IDS 1384L -#define ERROR_LOGON_TYPE_NOT_GRANTED 1385L -#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386L -#define ERROR_NO_SUCH_MEMBER 1387L -#define ERROR_INVALID_MEMBER 1388L -#define ERROR_TOO_MANY_SIDS 1389L -#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390L -#define ERROR_NO_INHERITANCE 1391L -#define ERROR_FILE_CORRUPT 1392L -#define ERROR_DISK_CORRUPT 1393L -#define ERROR_NO_USER_SESSION_KEY 1394L -#define ERROR_LICENSE_QUOTA_EXCEEDED 1395L -#define ERROR_WRONG_TARGET_NAME 1396L -#define ERROR_MUTUAL_AUTH_FAILED 1397L -#define ERROR_TIME_SKEW 1398L -#define ERROR_CURRENT_DOMAIN_NOT_ALLOWED 1399L -#define ERROR_INVALID_WINDOW_HANDLE 1400L -#define ERROR_INVALID_MENU_HANDLE 1401L -#define ERROR_INVALID_CURSOR_HANDLE 1402L -#define ERROR_INVALID_ACCEL_HANDLE 1403L -#define ERROR_INVALID_HOOK_HANDLE 1404L -#define ERROR_INVALID_DWP_HANDLE 1405L -#define ERROR_TLW_WITH_WSCHILD 1406L -#define ERROR_CANNOT_FIND_WND_CLASS 1407L -#define ERROR_WINDOW_OF_OTHER_THREAD 1408L -#define ERROR_HOTKEY_ALREADY_REGISTERED 1409L -#define ERROR_CLASS_ALREADY_EXISTS 1410L -#define ERROR_CLASS_DOES_NOT_EXIST 1411L -#define ERROR_CLASS_HAS_WINDOWS 1412L -#define ERROR_INVALID_INDEX 1413L -#define ERROR_INVALID_ICON_HANDLE 1414L -#define ERROR_PRIVATE_DIALOG_INDEX 1415L -#define ERROR_LISTBOX_ID_NOT_FOUND 1416L -#define ERROR_NO_WILDCARD_CHARACTERS 1417L -#define ERROR_CLIPBOARD_NOT_OPEN 1418L -#define ERROR_HOTKEY_NOT_REGISTERED 1419L -#define ERROR_WINDOW_NOT_DIALOG 1420L -#define ERROR_CONTROL_ID_NOT_FOUND 1421L -#define ERROR_INVALID_COMBOBOX_MESSAGE 1422L -#define ERROR_WINDOW_NOT_COMBOBOX 1423L -#define ERROR_INVALID_EDIT_HEIGHT 1424L -#define ERROR_DC_NOT_FOUND 1425L -#define ERROR_INVALID_HOOK_FILTER 1426L -#define ERROR_INVALID_FILTER_PROC 1427L -#define ERROR_HOOK_NEEDS_HMOD 1428L -#define ERROR_GLOBAL_ONLY_HOOK 1429L -#define ERROR_JOURNAL_HOOK_SET 1430L -#define ERROR_HOOK_NOT_INSTALLED 1431L -#define ERROR_INVALID_LB_MESSAGE 1432L -#define ERROR_SETCOUNT_ON_BAD_LB 1433L -#define ERROR_LB_WITHOUT_TABSTOPS 1434L -#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435L -#define ERROR_CHILD_WINDOW_MENU 1436L -#define ERROR_NO_SYSTEM_MENU 1437L -#define ERROR_INVALID_MSGBOX_STYLE 1438L -#define ERROR_INVALID_SPI_VALUE 1439L -#define ERROR_SCREEN_ALREADY_LOCKED 1440L -#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441L -#define ERROR_NOT_CHILD_WINDOW 1442L -#define ERROR_INVALID_GW_COMMAND 1443L -#define ERROR_INVALID_THREAD_ID 1444L -#define ERROR_NON_MDICHILD_WINDOW 1445L -#define ERROR_POPUP_ALREADY_ACTIVE 1446L -#define ERROR_NO_SCROLLBARS 1447L -#define ERROR_INVALID_SCROLLBAR_RANGE 1448L -#define ERROR_INVALID_SHOWWIN_COMMAND 1449L -#define ERROR_NO_SYSTEM_RESOURCES 1450L -#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451L -#define ERROR_PAGED_SYSTEM_RESOURCES 1452L -#define ERROR_WORKING_SET_QUOTA 1453L -#define ERROR_PAGEFILE_QUOTA 1454L -#define ERROR_COMMITMENT_LIMIT 1455L -#define ERROR_MENU_ITEM_NOT_FOUND 1456L -#define ERROR_INVALID_KEYBOARD_HANDLE 1457L -#define ERROR_HOOK_TYPE_NOT_ALLOWED 1458L -#define ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION 1459L -#define ERROR_TIMEOUT 1460L -#define ERROR_INVALID_MONITOR_HANDLE 1461L -#define ERROR_INCORRECT_SIZE 1462L -#define ERROR_EVENTLOG_FILE_CORRUPT 1500L -#define ERROR_EVENTLOG_CANT_START 1501L -#define ERROR_LOG_FILE_FULL 1502L -#define ERROR_EVENTLOG_FILE_CHANGED 1503L -#define ERROR_INSTALL_SERVICE_FAILURE 1601L -#define ERROR_INSTALL_USEREXIT 1602L -#define ERROR_INSTALL_FAILURE 1603L -#define ERROR_INSTALL_SUSPEND 1604L -#define ERROR_UNKNOWN_PRODUCT 1605L -#define ERROR_UNKNOWN_FEATURE 1606L -#define ERROR_UNKNOWN_COMPONENT 1607L -#define ERROR_UNKNOWN_PROPERTY 1608L -#define ERROR_INVALID_HANDLE_STATE 1609L -#define ERROR_BAD_CONFIGURATION 1610L -#define ERROR_INDEX_ABSENT 1611L -#define ERROR_INSTALL_SOURCE_ABSENT 1612L -#define ERROR_INSTALL_PACKAGE_VERSION 1613L -#define ERROR_PRODUCT_UNINSTALLED 1614L -#define ERROR_BAD_QUERY_SYNTAX 1615L -#define ERROR_INVALID_FIELD 1616L -#define ERROR_DEVICE_REMOVED 1617L -#define ERROR_INSTALL_ALREADY_RUNNING 1618L -#define ERROR_INSTALL_PACKAGE_OPEN_FAILED 1619L -#define ERROR_INSTALL_PACKAGE_INVALID 1620L -#define ERROR_INSTALL_UI_FAILURE 1621L -#define ERROR_INSTALL_LOG_FAILURE 1622L -#define ERROR_INSTALL_LANGUAGE_UNSUPPORTED 1623L -#define ERROR_INSTALL_TRANSFORM_FAILURE 1624L -#define ERROR_INSTALL_PACKAGE_REJECTED 1625L -#define ERROR_FUNCTION_NOT_CALLED 1626L -#define ERROR_FUNCTION_FAILED 1627L -#define ERROR_INVALID_TABLE 1628L -#define ERROR_DATATYPE_MISMATCH 1629L -#define ERROR_UNSUPPORTED_TYPE 1630L -#define ERROR_CREATE_FAILED 1631L -#define ERROR_INSTALL_TEMP_UNWRITABLE 1632L -#define ERROR_INSTALL_PLATFORM_UNSUPPORTED 1633L -#define ERROR_INSTALL_NOTUSED 1634L -#define ERROR_PATCH_PACKAGE_OPEN_FAILED 1635L -#define ERROR_PATCH_PACKAGE_INVALID 1636L -#define ERROR_PATCH_PACKAGE_UNSUPPORTED 1637L -#define ERROR_PRODUCT_VERSION 1638L -#define ERROR_INVALID_COMMAND_LINE 1639L -#define ERROR_INSTALL_REMOTE_DISALLOWED 1640L -#define ERROR_SUCCESS_REBOOT_INITIATED 1641L -#define ERROR_PATCH_TARGET_NOT_FOUND 1642L -#define ERROR_PATCH_PACKAGE_REJECTED 1643L -#define ERROR_INSTALL_TRANSFORM_REJECTED 1644L -#define ERROR_INSTALL_REMOTE_PROHIBITED 1645L -#define RPC_S_INVALID_STRING_BINDING 1700L -#define RPC_S_WRONG_KIND_OF_BINDING 1701L -#define RPC_S_INVALID_BINDING 1702L -#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703L -#define RPC_S_INVALID_RPC_PROTSEQ 1704L -#define RPC_S_INVALID_STRING_UUID 1705L -#define RPC_S_INVALID_ENDPOINT_FORMAT 1706L -#define RPC_S_INVALID_NET_ADDR 1707L -#define RPC_S_NO_ENDPOINT_FOUND 1708L -#define RPC_S_INVALID_TIMEOUT 1709L -#define RPC_S_OBJECT_NOT_FOUND 1710L -#define RPC_S_ALREADY_REGISTERED 1711L -#define RPC_S_TYPE_ALREADY_REGISTERED 1712L -#define RPC_S_ALREADY_LISTENING 1713L -#define RPC_S_NO_PROTSEQS_REGISTERED 1714L -#define RPC_S_NOT_LISTENING 1715L -#define RPC_S_UNKNOWN_MGR_TYPE 1716L -#define RPC_S_UNKNOWN_IF 1717L -#define RPC_S_NO_BINDINGS 1718L -#define RPC_S_NO_PROTSEQS 1719L -#define RPC_S_CANT_CREATE_ENDPOINT 1720L -#define RPC_S_OUT_OF_RESOURCES 1721L -#define RPC_S_SERVER_UNAVAILABLE 1722L -#define RPC_S_SERVER_TOO_BUSY 1723L -#define RPC_S_INVALID_NETWORK_OPTIONS 1724L -#define RPC_S_NO_CALL_ACTIVE 1725L -#define RPC_S_CALL_FAILED 1726L -#define RPC_S_CALL_FAILED_DNE 1727L -#define RPC_S_PROTOCOL_ERROR 1728L -#define RPC_S_UNSUPPORTED_TRANS_SYN 1730L -#define RPC_S_UNSUPPORTED_TYPE 1732L -#define RPC_S_INVALID_TAG 1733L -#define RPC_S_INVALID_BOUND 1734L -#define RPC_S_NO_ENTRY_NAME 1735L -#define RPC_S_INVALID_NAME_SYNTAX 1736L -#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737L -#define RPC_S_UUID_NO_ADDRESS 1739L -#define RPC_S_DUPLICATE_ENDPOINT 1740L -#define RPC_S_UNKNOWN_AUTHN_TYPE 1741L -#define RPC_S_MAX_CALLS_TOO_SMALL 1742L -#define RPC_S_STRING_TOO_LONG 1743L -#define RPC_S_PROTSEQ_NOT_FOUND 1744L -#define RPC_S_PROCNUM_OUT_OF_RANGE 1745L -#define RPC_S_BINDING_HAS_NO_AUTH 1746L -#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747L -#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748L -#define RPC_S_INVALID_AUTH_IDENTITY 1749L -#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750L -#define EPT_S_INVALID_ENTRY 1751L -#define EPT_S_CANT_PERFORM_OP 1752L -#define EPT_S_NOT_REGISTERED 1753L -#define RPC_S_NOTHING_TO_EXPORT 1754L -#define RPC_S_INCOMPLETE_NAME 1755L -#define RPC_S_INVALID_VERS_OPTION 1756L -#define RPC_S_NO_MORE_MEMBERS 1757L -#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758L -#define RPC_S_INTERFACE_NOT_FOUND 1759L -#define RPC_S_ENTRY_ALREADY_EXISTS 1760L -#define RPC_S_ENTRY_NOT_FOUND 1761L -#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762L -#define RPC_S_INVALID_NAF_ID 1763L -#define RPC_S_CANNOT_SUPPORT 1764L -#define RPC_S_NO_CONTEXT_AVAILABLE 1765L -#define RPC_S_INTERNAL_ERROR 1766L -#define RPC_S_ZERO_DIVIDE 1767L -#define RPC_S_ADDRESS_ERROR 1768L -#define RPC_S_FP_DIV_ZERO 1769L -#define RPC_S_FP_UNDERFLOW 1770L -#define RPC_S_FP_OVERFLOW 1771L -#define RPC_X_NO_MORE_ENTRIES 1772L -#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773L -#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774L -#define RPC_X_SS_IN_NULL_CONTEXT 1775L -#define RPC_X_SS_CONTEXT_DAMAGED 1777L -#define RPC_X_SS_HANDLES_MISMATCH 1778L -#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779L -#define RPC_X_NULL_REF_POINTER 1780L -#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781L -#define RPC_X_BYTE_COUNT_TOO_SMALL 1782L -#define RPC_X_BAD_STUB_DATA 1783L -#define ERROR_INVALID_USER_BUFFER 1784L -#define ERROR_UNRECOGNIZED_MEDIA 1785L -#define ERROR_NO_TRUST_LSA_SECRET 1786L -#define ERROR_NO_TRUST_SAM_ACCOUNT 1787L -#define ERROR_TRUSTED_DOMAIN_FAILURE 1788L -#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789L -#define ERROR_TRUST_FAILURE 1790L -#define RPC_S_CALL_IN_PROGRESS 1791L -#define ERROR_NETLOGON_NOT_STARTED 1792L -#define ERROR_ACCOUNT_EXPIRED 1793L -#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794L -#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795L -#define ERROR_UNKNOWN_PORT 1796L -#define ERROR_UNKNOWN_PRINTER_DRIVER 1797L -#define ERROR_UNKNOWN_PRINTPROCESSOR 1798L -#define ERROR_INVALID_SEPARATOR_FILE 1799L -#define ERROR_INVALID_PRIORITY 1800L -#define ERROR_INVALID_PRINTER_NAME 1801L -#define ERROR_PRINTER_ALREADY_EXISTS 1802L -#define ERROR_INVALID_PRINTER_COMMAND 1803L -#define ERROR_INVALID_DATATYPE 1804L -#define ERROR_INVALID_ENVIRONMENT 1805L -#define RPC_S_NO_MORE_BINDINGS 1806L -#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807L -#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808L -#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809L -#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810L -#define ERROR_SERVER_HAS_OPEN_HANDLES 1811L -#define ERROR_RESOURCE_DATA_NOT_FOUND 1812L -#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813L -#define ERROR_RESOURCE_NAME_NOT_FOUND 1814L -#define ERROR_RESOURCE_LANG_NOT_FOUND 1815L -#define ERROR_NOT_ENOUGH_QUOTA 1816L -#define RPC_S_NO_INTERFACES 1817L -#define RPC_S_CALL_CANCELLED 1818L -#define RPC_S_BINDING_INCOMPLETE 1819L -#define RPC_S_COMM_FAILURE 1820L -#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821L -#define RPC_S_NO_PRINC_NAME 1822L -#define RPC_S_NOT_RPC_ERROR 1823L -#define RPC_S_UUID_LOCAL_ONLY 1824L -#define RPC_S_SEC_PKG_ERROR 1825L -#define RPC_S_NOT_CANCELLED 1826L -#define RPC_X_INVALID_ES_ACTION 1827L -#define RPC_X_WRONG_ES_VERSION 1828L -#define RPC_X_WRONG_STUB_VERSION 1829L -#define RPC_X_INVALID_PIPE_OBJECT 1830L -#define RPC_X_WRONG_PIPE_ORDER 1831L -#define RPC_X_WRONG_PIPE_VERSION 1832L -#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898L -#define EPT_S_CANT_CREATE 1899L -#define RPC_S_INVALID_OBJECT 1900L -#define ERROR_INVALID_TIME 1901L -#define ERROR_INVALID_FORM_NAME 1902L -#define ERROR_INVALID_FORM_SIZE 1903L -#define ERROR_ALREADY_WAITING 1904L -#define ERROR_PRINTER_DELETED 1905L -#define ERROR_INVALID_PRINTER_STATE 1906L -#define ERROR_PASSWORD_MUST_CHANGE 1907L -#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908L -#define ERROR_ACCOUNT_LOCKED_OUT 1909L -#define OR_INVALID_OXID 1910L -#define OR_INVALID_OID 1911L -#define OR_INVALID_SET 1912L -#define RPC_S_SEND_INCOMPLETE 1913L -#define RPC_S_INVALID_ASYNC_HANDLE 1914L -#define RPC_S_INVALID_ASYNC_CALL 1915L -#define RPC_X_PIPE_CLOSED 1916L -#define RPC_X_PIPE_DISCIPLINE_ERROR 1917L -#define RPC_X_PIPE_EMPTY 1918L -#define ERROR_NO_SITENAME 1919L -#define ERROR_CANT_ACCESS_FILE 1920L -#define ERROR_CANT_RESOLVE_FILENAME 1921L -#define RPC_S_ENTRY_TYPE_MISMATCH 1922L -#define RPC_S_NOT_ALL_OBJS_EXPORTED 1923L -#define RPC_S_INTERFACE_NOT_EXPORTED 1924L -#define RPC_S_PROFILE_NOT_ADDED 1925L -#define RPC_S_PRF_ELT_NOT_ADDED 1926L -#define RPC_S_PRF_ELT_NOT_REMOVED 1927L -#define RPC_S_GRP_ELT_NOT_ADDED 1928L -#define RPC_S_GRP_ELT_NOT_REMOVED 1929L -#define ERROR_KM_DRIVER_BLOCKED 1930L -#define ERROR_CONTEXT_EXPIRED 1931L -#define ERROR_PER_USER_TRUST_QUOTA_EXCEEDED 1932L -#define ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED 1933L -#define ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED 1934L -#define ERROR_AUTHENTICATION_FIREWALL_FAILED 1935L -#define ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED 1936L -#define ERROR_INVALID_PIXEL_FORMAT 2000L -#define ERROR_BAD_DRIVER 2001L -#define ERROR_INVALID_WINDOW_STYLE 2002L -#define ERROR_METAFILE_NOT_SUPPORTED 2003L -#define ERROR_TRANSFORM_NOT_SUPPORTED 2004L -#define ERROR_CLIPPING_NOT_SUPPORTED 2005L -#define ERROR_INVALID_CMM 2010L -#define ERROR_INVALID_PROFILE 2011L -#define ERROR_TAG_NOT_FOUND 2012L -#define ERROR_TAG_NOT_PRESENT 2013L -#define ERROR_DUPLICATE_TAG 2014L -#define ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE 2015L -#define ERROR_PROFILE_NOT_FOUND 2016L -#define ERROR_INVALID_COLORSPACE 2017L -#define ERROR_ICM_NOT_ENABLED 2018L -#define ERROR_DELETING_ICM_XFORM 2019L -#define ERROR_INVALID_TRANSFORM 2020L -#define ERROR_COLORSPACE_MISMATCH 2021L -#define ERROR_INVALID_COLORINDEX 2022L -#define ERROR_CONNECTED_OTHER_PASSWORD 2108L -#define ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT 2109L -#define ERROR_BAD_USERNAME 2202L -#define ERROR_NOT_CONNECTED 2250L -#define ERROR_OPEN_FILES 2401L -#define ERROR_ACTIVE_CONNECTIONS 2402L -#define ERROR_DEVICE_IN_USE 2404L -#define ERROR_UNKNOWN_PRINT_MONITOR 3000L -#define ERROR_PRINTER_DRIVER_IN_USE 3001L -#define ERROR_SPOOL_FILE_NOT_FOUND 3002L -#define ERROR_SPL_NO_STARTDOC 3003L -#define ERROR_SPL_NO_ADDJOB 3004L -#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005L -#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006L -#define ERROR_INVALID_PRINT_MONITOR 3007L -#define ERROR_PRINT_MONITOR_IN_USE 3008L -#define ERROR_PRINTER_HAS_JOBS_QUEUED 3009L -#define ERROR_SUCCESS_REBOOT_REQUIRED 3010L -#define ERROR_SUCCESS_RESTART_REQUIRED 3011L -#define ERROR_PRINTER_NOT_FOUND 3012L -#define ERROR_PRINTER_DRIVER_WARNED 3013L -#define ERROR_PRINTER_DRIVER_BLOCKED 3014L -#define ERROR_WINS_INTERNAL 4000L -#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001L -#define ERROR_STATIC_INIT 4002L -#define ERROR_INC_BACKUP 4003L -#define ERROR_FULL_BACKUP 4004L -#define ERROR_REC_NON_EXISTENT 4005L -#define ERROR_RPL_NOT_ALLOWED 4006L -#define ERROR_DHCP_ADDRESS_CONFLICT 4100L -#define ERROR_WMI_GUID_NOT_FOUND 4200L -#define ERROR_WMI_INSTANCE_NOT_FOUND 4201L -#define ERROR_WMI_ITEMID_NOT_FOUND 4202L -#define ERROR_WMI_TRY_AGAIN 4203L -#define ERROR_WMI_DP_NOT_FOUND 4204L -#define ERROR_WMI_UNRESOLVED_INSTANCE_REF 4205L -#define ERROR_WMI_ALREADY_ENABLED 4206L -#define ERROR_WMI_GUID_DISCONNECTED 4207L -#define ERROR_WMI_SERVER_UNAVAILABLE 4208L -#define ERROR_WMI_DP_FAILED 4209L -#define ERROR_WMI_INVALID_MOF 4210L -#define ERROR_WMI_INVALID_REGINFO 4211L -#define ERROR_WMI_ALREADY_DISABLED 4212L -#define ERROR_WMI_READ_ONLY 4213L -#define ERROR_WMI_SET_FAILURE 4214L -#define ERROR_INVALID_MEDIA 4300L -#define ERROR_INVALID_LIBRARY 4301L -#define ERROR_INVALID_MEDIA_POOL 4302L -#define ERROR_DRIVE_MEDIA_MISMATCH 4303L -#define ERROR_MEDIA_OFFLINE 4304L -#define ERROR_LIBRARY_OFFLINE 4305L -#define ERROR_EMPTY 4306L -#define ERROR_NOT_EMPTY 4307L -#define ERROR_MEDIA_UNAVAILABLE 4308L -#define ERROR_RESOURCE_DISABLED 4309L -#define ERROR_INVALID_CLEANER 4310L -#define ERROR_UNABLE_TO_CLEAN 4311L -#define ERROR_OBJECT_NOT_FOUND 4312L -#define ERROR_DATABASE_FAILURE 4313L -#define ERROR_DATABASE_FULL 4314L -#define ERROR_MEDIA_INCOMPATIBLE 4315L -#define ERROR_RESOURCE_NOT_PRESENT 4316L -#define ERROR_INVALID_OPERATION 4317L -#define ERROR_MEDIA_NOT_AVAILABLE 4318L -#define ERROR_DEVICE_NOT_AVAILABLE 4319L -#define ERROR_REQUEST_REFUSED 4320L -#define ERROR_INVALID_DRIVE_OBJECT 4321L -#define ERROR_LIBRARY_FULL 4322L -#define ERROR_MEDIUM_NOT_ACCESSIBLE 4323L -#define ERROR_UNABLE_TO_LOAD_MEDIUM 4324L -#define ERROR_UNABLE_TO_INVENTORY_DRIVE 4325L -#define ERROR_UNABLE_TO_INVENTORY_SLOT 4326L -#define ERROR_UNABLE_TO_INVENTORY_TRANSPORT 4327L -#define ERROR_TRANSPORT_FULL 4328L -#define ERROR_CONTROLLING_IEPORT 4329L -#define ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA 4330L -#define ERROR_CLEANER_SLOT_SET 4331L -#define ERROR_CLEANER_SLOT_NOT_SET 4332L -#define ERROR_CLEANER_CARTRIDGE_SPENT 4333L -#define ERROR_UNEXPECTED_OMID 4334L -#define ERROR_CANT_DELETE_LAST_ITEM 4335L -#define ERROR_MESSAGE_EXCEEDS_MAX_SIZE 4336L -#define ERROR_VOLUME_CONTAINS_SYS_FILES 4337L -#define ERROR_INDIGENOUS_TYPE 4338L -#define ERROR_NO_SUPPORTING_DRIVES 4339L -#define ERROR_CLEANER_CARTRIDGE_INSTALLED 4340L -#define ERROR_IEPORT_FULL 4341L -#define ERROR_FILE_OFFLINE 4350L -#define ERROR_REMOTE_STORAGE_NOT_ACTIVE 4351L -#define ERROR_REMOTE_STORAGE_MEDIA_ERROR 4352L -#define ERROR_NOT_A_REPARSE_POINT 4390L -#define ERROR_REPARSE_ATTRIBUTE_CONFLICT 4391L -#define ERROR_INVALID_REPARSE_DATA 4392L -#define ERROR_REPARSE_TAG_INVALID 4393L -#define ERROR_REPARSE_TAG_MISMATCH 4394L -#define ERROR_VOLUME_NOT_SIS_ENABLED 4500L -#define ERROR_DEPENDENT_RESOURCE_EXISTS 5001L -#define ERROR_DEPENDENCY_NOT_FOUND 5002L -#define ERROR_DEPENDENCY_ALREADY_EXISTS 5003L -#define ERROR_RESOURCE_NOT_ONLINE 5004L -#define ERROR_HOST_NODE_NOT_AVAILABLE 5005L -#define ERROR_RESOURCE_NOT_AVAILABLE 5006L -#define ERROR_RESOURCE_NOT_FOUND 5007L -#define ERROR_SHUTDOWN_CLUSTER 5008L -#define ERROR_CANT_EVICT_ACTIVE_NODE 5009L -#define ERROR_OBJECT_ALREADY_EXISTS 5010L -#define ERROR_OBJECT_IN_LIST 5011L -#define ERROR_GROUP_NOT_AVAILABLE 5012L -#define ERROR_GROUP_NOT_FOUND 5013L -#define ERROR_GROUP_NOT_ONLINE 5014L -#define ERROR_HOST_NODE_NOT_RESOURCE_OWNER 5015L -#define ERROR_HOST_NODE_NOT_GROUP_OWNER 5016L -#define ERROR_RESMON_CREATE_FAILED 5017L -#define ERROR_RESMON_ONLINE_FAILED 5018L -#define ERROR_RESOURCE_ONLINE 5019L -#define ERROR_QUORUM_RESOURCE 5020L -#define ERROR_NOT_QUORUM_CAPABLE 5021L -#define ERROR_CLUSTER_SHUTTING_DOWN 5022L -#define ERROR_INVALID_STATE 5023L -#define ERROR_RESOURCE_PROPERTIES_STORED 5024L -#define ERROR_NOT_QUORUM_CLASS 5025L -#define ERROR_CORE_RESOURCE 5026L -#define ERROR_QUORUM_RESOURCE_ONLINE_FAILED 5027L -#define ERROR_QUORUMLOG_OPEN_FAILED 5028L -#define ERROR_CLUSTERLOG_CORRUPT 5029L -#define ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE 5030L -#define ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE 5031L -#define ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND 5032L -#define ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE 5033L -#define ERROR_QUORUM_OWNER_ALIVE 5034L -#define ERROR_NETWORK_NOT_AVAILABLE 5035L -#define ERROR_NODE_NOT_AVAILABLE 5036L -#define ERROR_ALL_NODES_NOT_AVAILABLE 5037L -#define ERROR_RESOURCE_FAILED 5038L -#define ERROR_CLUSTER_INVALID_NODE 5039L -#define ERROR_CLUSTER_NODE_EXISTS 5040L -#define ERROR_CLUSTER_JOIN_IN_PROGRESS 5041L -#define ERROR_CLUSTER_NODE_NOT_FOUND 5042L -#define ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND 5043L -#define ERROR_CLUSTER_NETWORK_EXISTS 5044L -#define ERROR_CLUSTER_NETWORK_NOT_FOUND 5045L -#define ERROR_CLUSTER_NETINTERFACE_EXISTS 5046L -#define ERROR_CLUSTER_NETINTERFACE_NOT_FOUND 5047L -#define ERROR_CLUSTER_INVALID_REQUEST 5048L -#define ERROR_CLUSTER_INVALID_NETWORK_PROVIDER 5049L -#define ERROR_CLUSTER_NODE_DOWN 5050L -#define ERROR_CLUSTER_NODE_UNREACHABLE 5051L -#define ERROR_CLUSTER_NODE_NOT_MEMBER 5052L -#define ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS 5053L -#define ERROR_CLUSTER_INVALID_NETWORK 5054L -#define ERROR_CLUSTER_NODE_UP 5056L -#define ERROR_CLUSTER_IPADDR_IN_USE 5057L -#define ERROR_CLUSTER_NODE_NOT_PAUSED 5058L -#define ERROR_CLUSTER_NO_SECURITY_CONTEXT 5059L -#define ERROR_CLUSTER_NETWORK_NOT_INTERNAL 5060L -#define ERROR_CLUSTER_NODE_ALREADY_UP 5061L -#define ERROR_CLUSTER_NODE_ALREADY_DOWN 5062L -#define ERROR_CLUSTER_NETWORK_ALREADY_ONLINE 5063L -#define ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE 5064L -#define ERROR_CLUSTER_NODE_ALREADY_MEMBER 5065L -#define ERROR_CLUSTER_LAST_INTERNAL_NETWORK 5066L -#define ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS 5067L -#define ERROR_INVALID_OPERATION_ON_QUORUM 5068L -#define ERROR_DEPENDENCY_NOT_ALLOWED 5069L -#define ERROR_CLUSTER_NODE_PAUSED 5070L -#define ERROR_NODE_CANT_HOST_RESOURCE 5071L -#define ERROR_CLUSTER_NODE_NOT_READY 5072L -#define ERROR_CLUSTER_NODE_SHUTTING_DOWN 5073L -#define ERROR_CLUSTER_JOIN_ABORTED 5074L -#define ERROR_CLUSTER_INCOMPATIBLE_VERSIONS 5075L -#define ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED 5076L -#define ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED 5077L -#define ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND 5078L -#define ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED 5079L -#define ERROR_CLUSTER_RESNAME_NOT_FOUND 5080L -#define ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED 5081L -#define ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST 5082L -#define ERROR_CLUSTER_DATABASE_SEQMISMATCH 5083L -#define ERROR_RESMON_INVALID_STATE 5084L -#define ERROR_CLUSTER_GUM_NOT_LOCKER 5085L -#define ERROR_QUORUM_DISK_NOT_FOUND 5086L -#define ERROR_DATABASE_BACKUP_CORRUPT 5087L -#define ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT 5088L -#define ERROR_RESOURCE_PROPERTY_UNCHANGEABLE 5089L -#define ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE 5890L -#define ERROR_CLUSTER_QUORUMLOG_NOT_FOUND 5891L -#define ERROR_CLUSTER_MEMBERSHIP_HALT 5892L -#define ERROR_CLUSTER_INSTANCE_ID_MISMATCH 5893L -#define ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP 5894L -#define ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH 5895L -#define ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP 5896L -#define ERROR_CLUSTER_PARAMETER_MISMATCH 5897L -#define ERROR_NODE_CANNOT_BE_CLUSTERED 5898L -#define ERROR_CLUSTER_WRONG_OS_VERSION 5899L -#define ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME 5900L -#define ERROR_CLUSCFG_ALREADY_COMMITTED 5901L -#define ERROR_CLUSCFG_ROLLBACK_FAILED 5902L -#define ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT 5903L -#define ERROR_CLUSTER_OLD_VERSION 5904L -#define ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME 5905L -#define ERROR_ENCRYPTION_FAILED 6000L -#define ERROR_DECRYPTION_FAILED 6001L -#define ERROR_FILE_ENCRYPTED 6002L -#define ERROR_NO_RECOVERY_POLICY 6003L -#define ERROR_NO_EFS 6004L -#define ERROR_WRONG_EFS 6005L -#define ERROR_NO_USER_KEYS 6006L -#define ERROR_FILE_NOT_ENCRYPTED 6007L -#define ERROR_NOT_EXPORT_FORMAT 6008L -#define ERROR_FILE_READ_ONLY 6009L -#define ERROR_DIR_EFS_DISALLOWED 6010L -#define ERROR_EFS_SERVER_NOT_TRUSTED 6011L -#define ERROR_BAD_RECOVERY_POLICY 6012L -#define ERROR_EFS_ALG_BLOB_TOO_BIG 6013L -#define ERROR_VOLUME_NOT_SUPPORT_EFS 6014L -#define ERROR_EFS_DISABLED 6015L -#define ERROR_EFS_VERSION_NOT_SUPPORT 6016L -#define ERROR_NO_BROWSER_SERVERS_FOUND 6118L -#define SCHED_E_SERVICE_NOT_LOCALSYSTEM 6200L -#define ERROR_CTX_WINSTATION_NAME_INVALID 7001L -#define ERROR_CTX_INVALID_PD 7002L -#define ERROR_CTX_PD_NOT_FOUND 7003L -#define ERROR_CTX_WD_NOT_FOUND 7004L -#define ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY 7005L -#define ERROR_CTX_SERVICE_NAME_COLLISION 7006L -#define ERROR_CTX_CLOSE_PENDING 7007L -#define ERROR_CTX_NO_OUTBUF 7008L -#define ERROR_CTX_MODEM_INF_NOT_FOUND 7009L -#define ERROR_CTX_INVALID_MODEMNAME 7010L -#define ERROR_CTX_MODEM_RESPONSE_ERROR 7011L -#define ERROR_CTX_MODEM_RESPONSE_TIMEOUT 7012L -#define ERROR_CTX_MODEM_RESPONSE_NO_CARRIER 7013L -#define ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE 7014L -#define ERROR_CTX_MODEM_RESPONSE_BUSY 7015L -#define ERROR_CTX_MODEM_RESPONSE_VOICE 7016L -#define ERROR_CTX_TD_ERROR 7017L -#define ERROR_CTX_WINSTATION_NOT_FOUND 7022L -#define ERROR_CTX_WINSTATION_ALREADY_EXISTS 7023L -#define ERROR_CTX_WINSTATION_BUSY 7024L -#define ERROR_CTX_BAD_VIDEO_MODE 7025L -#define ERROR_CTX_GRAPHICS_INVALID 7035L -#define ERROR_CTX_LOGON_DISABLED 7037L -#define ERROR_CTX_NOT_CONSOLE 7038L -#define ERROR_CTX_CLIENT_QUERY_TIMEOUT 7040L -#define ERROR_CTX_CONSOLE_DISCONNECT 7041L -#define ERROR_CTX_CONSOLE_CONNECT 7042L -#define ERROR_CTX_SHADOW_DENIED 7044L -#define ERROR_CTX_WINSTATION_ACCESS_DENIED 7045L -#define ERROR_CTX_INVALID_WD 7049L -#define ERROR_CTX_SHADOW_INVALID 7050L -#define ERROR_CTX_SHADOW_DISABLED 7051L -#define ERROR_CTX_CLIENT_LICENSE_IN_USE 7052L -#define ERROR_CTX_CLIENT_LICENSE_NOT_SET 7053L -#define ERROR_CTX_LICENSE_NOT_AVAILABLE 7054L -#define ERROR_CTX_LICENSE_CLIENT_INVALID 7055L -#define ERROR_CTX_LICENSE_EXPIRED 7056L -#define ERROR_CTX_SHADOW_NOT_RUNNING 7057L -#define ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE 7058L -#define ERROR_ACTIVATION_COUNT_EXCEEDED 7059L -#define FRS_ERR_INVALID_API_SEQUENCE 8001L -#define FRS_ERR_STARTING_SERVICE 8002L -#define FRS_ERR_STOPPING_SERVICE 8003L -#define FRS_ERR_INTERNAL_API 8004L -#define FRS_ERR_INTERNAL 8005L -#define FRS_ERR_SERVICE_COMM 8006L -#define FRS_ERR_INSUFFICIENT_PRIV 8007L -#define FRS_ERR_AUTHENTICATION 8008L -#define FRS_ERR_PARENT_INSUFFICIENT_PRIV 8009L -#define FRS_ERR_PARENT_AUTHENTICATION 8010L -#define FRS_ERR_CHILD_TO_PARENT_COMM 8011L -#define FRS_ERR_PARENT_TO_CHILD_COMM 8012L -#define FRS_ERR_SYSVOL_POPULATE 8013L -#define FRS_ERR_SYSVOL_POPULATE_TIMEOUT 8014L -#define FRS_ERR_SYSVOL_IS_BUSY 8015L -#define FRS_ERR_SYSVOL_DEMOTE 8016L -#define FRS_ERR_INVALID_SERVICE_PARAMETER 8017L -#define DS_S_SUCCESS NO_ERROR -#define ERROR_DS_NOT_INSTALLED 8200L -#define ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY 8201L -#define ERROR_DS_NO_ATTRIBUTE_OR_VALUE 8202L -#define ERROR_DS_INVALID_ATTRIBUTE_SYNTAX 8203L -#define ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED 8204L -#define ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS 8205L -#define ERROR_DS_BUSY 8206L -#define ERROR_DS_UNAVAILABLE 8207L -#define ERROR_DS_NO_RIDS_ALLOCATED 8208L -#define ERROR_DS_NO_MORE_RIDS 8209L -#define ERROR_DS_INCORRECT_ROLE_OWNER 8210L -#define ERROR_DS_RIDMGR_INIT_ERROR 8211L -#define ERROR_DS_OBJ_CLASS_VIOLATION 8212L -#define ERROR_DS_CANT_ON_NON_LEAF 8213L -#define ERROR_DS_CANT_ON_RDN 8214L -#define ERROR_DS_CANT_MOD_OBJ_CLASS 8215L -#define ERROR_DS_CROSS_DOM_MOVE_ERROR 8216L -#define ERROR_DS_GC_NOT_AVAILABLE 8217L -#define ERROR_SHARED_POLICY 8218L -#define ERROR_POLICY_OBJECT_NOT_FOUND 8219L -#define ERROR_POLICY_ONLY_IN_DS 8220L -#define ERROR_PROMOTION_ACTIVE 8221L -#define ERROR_NO_PROMOTION_ACTIVE 8222L -#define ERROR_DS_OPERATIONS_ERROR 8224L -#define ERROR_DS_PROTOCOL_ERROR 8225L -#define ERROR_DS_TIMELIMIT_EXCEEDED 8226L -#define ERROR_DS_SIZELIMIT_EXCEEDED 8227L -#define ERROR_DS_ADMIN_LIMIT_EXCEEDED 8228L -#define ERROR_DS_COMPARE_FALSE 8229L -#define ERROR_DS_COMPARE_TRUE 8230L -#define ERROR_DS_AUTH_METHOD_NOT_SUPPORTED 8231L -#define ERROR_DS_STRONG_AUTH_REQUIRED 8232L -#define ERROR_DS_INAPPROPRIATE_AUTH 8233L -#define ERROR_DS_AUTH_UNKNOWN 8234L -#define ERROR_DS_REFERRAL 8235L -#define ERROR_DS_UNAVAILABLE_CRIT_EXTENSION 8236L -#define ERROR_DS_CONFIDENTIALITY_REQUIRED 8237L -#define ERROR_DS_INAPPROPRIATE_MATCHING 8238L -#define ERROR_DS_CONSTRAINT_VIOLATION 8239L -#define ERROR_DS_NO_SUCH_OBJECT 8240L -#define ERROR_DS_ALIAS_PROBLEM 8241L -#define ERROR_DS_INVALID_DN_SYNTAX 8242L -#define ERROR_DS_IS_LEAF 8243L -#define ERROR_DS_ALIAS_DEREF_PROBLEM 8244L -#define ERROR_DS_UNWILLING_TO_PERFORM 8245L -#define ERROR_DS_LOOP_DETECT 8246L -#define ERROR_DS_NAMING_VIOLATION 8247L -#define ERROR_DS_OBJECT_RESULTS_TOO_LARGE 8248L -#define ERROR_DS_AFFECTS_MULTIPLE_DSAS 8249L -#define ERROR_DS_SERVER_DOWN 8250L -#define ERROR_DS_LOCAL_ERROR 8251L -#define ERROR_DS_ENCODING_ERROR 8252L -#define ERROR_DS_DECODING_ERROR 8253L -#define ERROR_DS_FILTER_UNKNOWN 8254L -#define ERROR_DS_PARAM_ERROR 8255L -#define ERROR_DS_NOT_SUPPORTED 8256L -#define ERROR_DS_NO_RESULTS_RETURNED 8257L -#define ERROR_DS_CONTROL_NOT_FOUND 8258L -#define ERROR_DS_CLIENT_LOOP 8259L -#define ERROR_DS_REFERRAL_LIMIT_EXCEEDED 8260L -#define ERROR_DS_SORT_CONTROL_MISSING 8261L -#define ERROR_DS_OFFSET_RANGE_ERROR 8262L -#define ERROR_DS_ROOT_MUST_BE_NC 8301L -#define ERROR_DS_ADD_REPLICA_INHIBITED 8302L -#define ERROR_DS_ATT_NOT_DEF_IN_SCHEMA 8303L -#define ERROR_DS_MAX_OBJ_SIZE_EXCEEDED 8304L -#define ERROR_DS_OBJ_STRING_NAME_EXISTS 8305L -#define ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA 8306L -#define ERROR_DS_RDN_DOESNT_MATCH_SCHEMA 8307L -#define ERROR_DS_NO_REQUESTED_ATTS_FOUND 8308L -#define ERROR_DS_USER_BUFFER_TO_SMALL 8309L -#define ERROR_DS_ATT_IS_NOT_ON_OBJ 8310L -#define ERROR_DS_ILLEGAL_MOD_OPERATION 8311L -#define ERROR_DS_OBJ_TOO_LARGE 8312L -#define ERROR_DS_BAD_INSTANCE_TYPE 8313L -#define ERROR_DS_MASTERDSA_REQUIRED 8314L -#define ERROR_DS_OBJECT_CLASS_REQUIRED 8315L -#define ERROR_DS_MISSING_REQUIRED_ATT 8316L -#define ERROR_DS_ATT_NOT_DEF_FOR_CLASS 8317L -#define ERROR_DS_ATT_ALREADY_EXISTS 8318L -#define ERROR_DS_CANT_ADD_ATT_VALUES 8320L -#define ERROR_DS_SINGLE_VALUE_CONSTRAINT 8321L -#define ERROR_DS_RANGE_CONSTRAINT 8322L -#define ERROR_DS_ATT_VAL_ALREADY_EXISTS 8323L -#define ERROR_DS_CANT_REM_MISSING_ATT 8324L -#define ERROR_DS_CANT_REM_MISSING_ATT_VAL 8325L -#define ERROR_DS_ROOT_CANT_BE_SUBREF 8326L -#define ERROR_DS_NO_CHAINING 8327L -#define ERROR_DS_NO_CHAINED_EVAL 8328L -#define ERROR_DS_NO_PARENT_OBJECT 8329L -#define ERROR_DS_PARENT_IS_AN_ALIAS 8330L -#define ERROR_DS_CANT_MIX_MASTER_AND_REPS 8331L -#define ERROR_DS_CHILDREN_EXIST 8332L -#define ERROR_DS_OBJ_NOT_FOUND 8333L -#define ERROR_DS_ALIASED_OBJ_MISSING 8334L -#define ERROR_DS_BAD_NAME_SYNTAX 8335L -#define ERROR_DS_ALIAS_POINTS_TO_ALIAS 8336L -#define ERROR_DS_CANT_DEREF_ALIAS 8337L -#define ERROR_DS_OUT_OF_SCOPE 8338L -#define ERROR_DS_OBJECT_BEING_REMOVED 8339L -#define ERROR_DS_CANT_DELETE_DSA_OBJ 8340L -#define ERROR_DS_GENERIC_ERROR 8341L -#define ERROR_DS_DSA_MUST_BE_INT_MASTER 8342L -#define ERROR_DS_CLASS_NOT_DSA 8343L -#define ERROR_DS_INSUFF_ACCESS_RIGHTS 8344L -#define ERROR_DS_ILLEGAL_SUPERIOR 8345L -#define ERROR_DS_ATTRIBUTE_OWNED_BY_SAM 8346L -#define ERROR_DS_NAME_TOO_MANY_PARTS 8347L -#define ERROR_DS_NAME_TOO_LONG 8348L -#define ERROR_DS_NAME_VALUE_TOO_LONG 8349L -#define ERROR_DS_NAME_UNPARSEABLE 8350L -#define ERROR_DS_NAME_TYPE_UNKNOWN 8351L -#define ERROR_DS_NOT_AN_OBJECT 8352L -#define ERROR_DS_SEC_DESC_TOO_SHORT 8353L -#define ERROR_DS_SEC_DESC_INVALID 8354L -#define ERROR_DS_NO_DELETED_NAME 8355L -#define ERROR_DS_SUBREF_MUST_HAVE_PARENT 8356L -#define ERROR_DS_NCNAME_MUST_BE_NC 8357L -#define ERROR_DS_CANT_ADD_SYSTEM_ONLY 8358L -#define ERROR_DS_CLASS_MUST_BE_CONCRETE 8359L -#define ERROR_DS_INVALID_DMD 8360L -#define ERROR_DS_OBJ_GUID_EXISTS 8361L -#define ERROR_DS_NOT_ON_BACKLINK 8362L -#define ERROR_DS_NO_CROSSREF_FOR_NC 8363L -#define ERROR_DS_SHUTTING_DOWN 8364L -#define ERROR_DS_UNKNOWN_OPERATION 8365L -#define ERROR_DS_INVALID_ROLE_OWNER 8366L -#define ERROR_DS_COULDNT_CONTACT_FSMO 8367L -#define ERROR_DS_CROSS_NC_DN_RENAME 8368L -#define ERROR_DS_CANT_MOD_SYSTEM_ONLY 8369L -#define ERROR_DS_REPLICATOR_ONLY 8370L -#define ERROR_DS_OBJ_CLASS_NOT_DEFINED 8371L -#define ERROR_DS_OBJ_CLASS_NOT_SUBCLASS 8372L -#define ERROR_DS_NAME_REFERENCE_INVALID 8373L -#define ERROR_DS_CROSS_REF_EXISTS 8374L -#define ERROR_DS_CANT_DEL_MASTER_CROSSREF 8375L -#define ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD 8376L -#define ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX 8377L -#define ERROR_DS_DUP_RDN 8378L -#define ERROR_DS_DUP_OID 8379L -#define ERROR_DS_DUP_MAPI_ID 8380L -#define ERROR_DS_DUP_SCHEMA_ID_GUID 8381L -#define ERROR_DS_DUP_LDAP_DISPLAY_NAME 8382L -#define ERROR_DS_SEMANTIC_ATT_TEST 8383L -#define ERROR_DS_SYNTAX_MISMATCH 8384L -#define ERROR_DS_EXISTS_IN_MUST_HAVE 8385L -#define ERROR_DS_EXISTS_IN_MAY_HAVE 8386L -#define ERROR_DS_NONEXISTENT_MAY_HAVE 8387L -#define ERROR_DS_NONEXISTENT_MUST_HAVE 8388L -#define ERROR_DS_AUX_CLS_TEST_FAIL 8389L -#define ERROR_DS_NONEXISTENT_POSS_SUP 8390L -#define ERROR_DS_SUB_CLS_TEST_FAIL 8391L -#define ERROR_DS_BAD_RDN_ATT_ID_SYNTAX 8392L -#define ERROR_DS_EXISTS_IN_AUX_CLS 8393L -#define ERROR_DS_EXISTS_IN_SUB_CLS 8394L -#define ERROR_DS_EXISTS_IN_POSS_SUP 8395L -#define ERROR_DS_RECALCSCHEMA_FAILED 8396L -#define ERROR_DS_TREE_DELETE_NOT_FINISHED 8397L -#define ERROR_DS_CANT_DELETE 8398L -#define ERROR_DS_ATT_SCHEMA_REQ_ID 8399L -#define ERROR_DS_BAD_ATT_SCHEMA_SYNTAX 8400L -#define ERROR_DS_CANT_CACHE_ATT 8401L -#define ERROR_DS_CANT_CACHE_CLASS 8402L -#define ERROR_DS_CANT_REMOVE_ATT_CACHE 8403L -#define ERROR_DS_CANT_REMOVE_CLASS_CACHE 8404L -#define ERROR_DS_CANT_RETRIEVE_DN 8405L -#define ERROR_DS_MISSING_SUPREF 8406L -#define ERROR_DS_CANT_RETRIEVE_INSTANCE 8407L -#define ERROR_DS_CODE_INCONSISTENCY 8408L -#define ERROR_DS_DATABASE_ERROR 8409L -#define ERROR_DS_GOVERNSID_MISSING 8410L -#define ERROR_DS_MISSING_EXPECTED_ATT 8411L -#define ERROR_DS_NCNAME_MISSING_CR_REF 8412L -#define ERROR_DS_SECURITY_CHECKING_ERROR 8413L -#define ERROR_DS_SCHEMA_NOT_LOADED 8414L -#define ERROR_DS_SCHEMA_ALLOC_FAILED 8415L -#define ERROR_DS_ATT_SCHEMA_REQ_SYNTAX 8416L -#define ERROR_DS_GCVERIFY_ERROR 8417L -#define ERROR_DS_DRA_SCHEMA_MISMATCH 8418L -#define ERROR_DS_CANT_FIND_DSA_OBJ 8419L -#define ERROR_DS_CANT_FIND_EXPECTED_NC 8420L -#define ERROR_DS_CANT_FIND_NC_IN_CACHE 8421L -#define ERROR_DS_CANT_RETRIEVE_CHILD 8422L -#define ERROR_DS_SECURITY_ILLEGAL_MODIFY 8423L -#define ERROR_DS_CANT_REPLACE_HIDDEN_REC 8424L -#define ERROR_DS_BAD_HIERARCHY_FILE 8425L -#define ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED 8426L -#define ERROR_DS_CONFIG_PARAM_MISSING 8427L -#define ERROR_DS_COUNTING_AB_INDICES_FAILED 8428L -#define ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED 8429L -#define ERROR_DS_INTERNAL_FAILURE 8430L -#define ERROR_DS_UNKNOWN_ERROR 8431L -#define ERROR_DS_ROOT_REQUIRES_CLASS_TOP 8432L -#define ERROR_DS_REFUSING_FSMO_ROLES 8433L -#define ERROR_DS_MISSING_FSMO_SETTINGS 8434L -#define ERROR_DS_UNABLE_TO_SURRENDER_ROLES 8435L -#define ERROR_DS_DRA_GENERIC 8436L -#define ERROR_DS_DRA_INVALID_PARAMETER 8437L -#define ERROR_DS_DRA_BUSY 8438L -#define ERROR_DS_DRA_BAD_DN 8439L -#define ERROR_DS_DRA_BAD_NC 8440L -#define ERROR_DS_DRA_DN_EXISTS 8441L -#define ERROR_DS_DRA_INTERNAL_ERROR 8442L -#define ERROR_DS_DRA_INCONSISTENT_DIT 8443L -#define ERROR_DS_DRA_CONNECTION_FAILED 8444L -#define ERROR_DS_DRA_BAD_INSTANCE_TYPE 8445L -#define ERROR_DS_DRA_OUT_OF_MEM 8446L -#define ERROR_DS_DRA_MAIL_PROBLEM 8447L -#define ERROR_DS_DRA_REF_ALREADY_EXISTS 8448L -#define ERROR_DS_DRA_REF_NOT_FOUND 8449L -#define ERROR_DS_DRA_OBJ_IS_REP_SOURCE 8450L -#define ERROR_DS_DRA_DB_ERROR 8451L -#define ERROR_DS_DRA_NO_REPLICA 8452L -#define ERROR_DS_DRA_ACCESS_DENIED 8453L -#define ERROR_DS_DRA_NOT_SUPPORTED 8454L -#define ERROR_DS_DRA_RPC_CANCELLED 8455L -#define ERROR_DS_DRA_SOURCE_DISABLED 8456L -#define ERROR_DS_DRA_SINK_DISABLED 8457L -#define ERROR_DS_DRA_NAME_COLLISION 8458L -#define ERROR_DS_DRA_SOURCE_REINSTALLED 8459L -#define ERROR_DS_DRA_MISSING_PARENT 8460L -#define ERROR_DS_DRA_PREEMPTED 8461L -#define ERROR_DS_DRA_ABANDON_SYNC 8462L -#define ERROR_DS_DRA_SHUTDOWN 8463L -#define ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET 8464L -#define ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA 8465L -#define ERROR_DS_DRA_EXTN_CONNECTION_FAILED 8466L -#define ERROR_DS_INSTALL_SCHEMA_MISMATCH 8467L -#define ERROR_DS_DUP_LINK_ID 8468L -#define ERROR_DS_NAME_ERROR_RESOLVING 8469L -#define ERROR_DS_NAME_ERROR_NOT_FOUND 8470L -#define ERROR_DS_NAME_ERROR_NOT_UNIQUE 8471L -#define ERROR_DS_NAME_ERROR_NO_MAPPING 8472L -#define ERROR_DS_NAME_ERROR_DOMAIN_ONLY 8473L -#define ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING 8474L -#define ERROR_DS_CONSTRUCTED_ATT_MOD 8475L -#define ERROR_DS_WRONG_OM_OBJ_CLASS 8476L -#define ERROR_DS_DRA_REPL_PENDING 8477L -#define ERROR_DS_DS_REQUIRED 8478L -#define ERROR_DS_INVALID_LDAP_DISPLAY_NAME 8479L -#define ERROR_DS_NON_BASE_SEARCH 8480L -#define ERROR_DS_CANT_RETRIEVE_ATTS 8481L -#define ERROR_DS_BACKLINK_WITHOUT_LINK 8482L -#define ERROR_DS_EPOCH_MISMATCH 8483L -#define ERROR_DS_SRC_NAME_MISMATCH 8484L -#define ERROR_DS_SRC_AND_DST_NC_IDENTICAL 8485L -#define ERROR_DS_DST_NC_MISMATCH 8486L -#define ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC 8487L -#define ERROR_DS_SRC_GUID_MISMATCH 8488L -#define ERROR_DS_CANT_MOVE_DELETED_OBJECT 8489L -#define ERROR_DS_PDC_OPERATION_IN_PROGRESS 8490L -#define ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD 8491L -#define ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION 8492L -#define ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS 8493L -#define ERROR_DS_NC_MUST_HAVE_NC_PARENT 8494L -#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE 8495L -#define ERROR_DS_DST_DOMAIN_NOT_NATIVE 8496L -#define ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER 8497L -#define ERROR_DS_CANT_MOVE_ACCOUNT_GROUP 8498L -#define ERROR_DS_CANT_MOVE_RESOURCE_GROUP 8499L -#define ERROR_DS_INVALID_SEARCH_FLAG 8500L -#define ERROR_DS_NO_TREE_DELETE_ABOVE_NC 8501L -#define ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE 8502L -#define ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE 8503L -#define ERROR_DS_SAM_INIT_FAILURE 8504L -#define ERROR_DS_SENSITIVE_GROUP_VIOLATION 8505L -#define ERROR_DS_CANT_MOD_PRIMARYGROUPID 8506L -#define ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD 8507L -#define ERROR_DS_NONSAFE_SCHEMA_CHANGE 8508L -#define ERROR_DS_SCHEMA_UPDATE_DISALLOWED 8509L -#define ERROR_DS_CANT_CREATE_UNDER_SCHEMA 8510L -#define ERROR_DS_INSTALL_NO_SRC_SCH_VERSION 8511L -#define ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE 8512L -#define ERROR_DS_INVALID_GROUP_TYPE 8513L -#define ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN 8514L -#define ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN 8515L -#define ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER 8516L -#define ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER 8517L -#define ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER 8518L -#define ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER 8519L -#define ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER 8520L -#define ERROR_DS_HAVE_PRIMARY_MEMBERS 8521L -#define ERROR_DS_STRING_SD_CONVERSION_FAILED 8522L -#define ERROR_DS_NAMING_MASTER_GC 8523L -#define ERROR_DS_DNS_LOOKUP_FAILURE 8524L -#define ERROR_DS_COULDNT_UPDATE_SPNS 8525L -#define ERROR_DS_CANT_RETRIEVE_SD 8526L -#define ERROR_DS_KEY_NOT_UNIQUE 8527L -#define ERROR_DS_WRONG_LINKED_ATT_SYNTAX 8528L -#define ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD 8529L -#define ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY 8530L -#define ERROR_DS_CANT_START 8531L -#define ERROR_DS_INIT_FAILURE 8532L -#define ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION 8533L -#define ERROR_DS_SOURCE_DOMAIN_IN_FOREST 8534L -#define ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST 8535L -#define ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED 8536L -#define ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN 8537L -#define ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER 8538L -#define ERROR_DS_SRC_SID_EXISTS_IN_FOREST 8539L -#define ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH 8540L -#define ERROR_SAM_INIT_FAILURE 8541L -#define ERROR_DS_DRA_SCHEMA_INFO_SHIP 8542L -#define ERROR_DS_DRA_SCHEMA_CONFLICT 8543L -#define ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT 8544L -#define ERROR_DS_DRA_OBJ_NC_MISMATCH 8545L -#define ERROR_DS_NC_STILL_HAS_DSAS 8546L -#define ERROR_DS_GC_REQUIRED 8547L -#define ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY 8548L -#define ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS 8549L -#define ERROR_DS_CANT_ADD_TO_GC 8550L -#define ERROR_DS_NO_CHECKPOINT_WITH_PDC 8551L -#define ERROR_DS_SOURCE_AUDITING_NOT_ENABLED 8552L -#define ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC 8553L -#define ERROR_DS_INVALID_NAME_FOR_SPN 8554L -#define ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS 8555L -#define ERROR_DS_UNICODEPWD_NOT_IN_QUOTES 8556L -#define ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED 8557L -#define ERROR_DS_MUST_BE_RUN_ON_DST_DC 8558L -#define ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER 8559L -#define ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ 8560L -#define ERROR_DS_INIT_FAILURE_CONSOLE 8561L -#define ERROR_DS_SAM_INIT_FAILURE_CONSOLE 8562L -#define ERROR_DS_FOREST_VERSION_TOO_HIGH 8563L -#define ERROR_DS_DOMAIN_VERSION_TOO_HIGH 8564L -#define ERROR_DS_FOREST_VERSION_TOO_LOW 8565L -#define ERROR_DS_DOMAIN_VERSION_TOO_LOW 8566L -#define ERROR_DS_INCOMPATIBLE_VERSION 8567L -#define ERROR_DS_LOW_DSA_VERSION 8568L -#define ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN 8569L -#define ERROR_DS_NOT_SUPPORTED_SORT_ORDER 8570L -#define ERROR_DS_NAME_NOT_UNIQUE 8571L -#define ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4 8572L -#define ERROR_DS_OUT_OF_VERSION_STORE 8573L -#define ERROR_DS_INCOMPATIBLE_CONTROLS_USED 8574L -#define ERROR_DS_NO_REF_DOMAIN 8575L -#define ERROR_DS_RESERVED_LINK_ID 8576L -#define ERROR_DS_LINK_ID_NOT_AVAILABLE 8577L -#define ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER 8578L -#define ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE 8579L -#define ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC 8580L -#define ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG 8581L -#define ERROR_DS_MODIFYDN_WRONG_GRANDPARENT 8582L -#define ERROR_DS_NAME_ERROR_TRUST_REFERRAL 8583L -#define ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER 8584L -#define ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD 8585L -#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2 8586L -#define ERROR_DS_THREAD_LIMIT_EXCEEDED 8587L -#define ERROR_DS_NOT_CLOSEST 8588L -#define ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF 8589L -#define ERROR_DS_SINGLE_USER_MODE_FAILED 8590L -#define ERROR_DS_NTDSCRIPT_SYNTAX_ERROR 8591L -#define ERROR_DS_NTDSCRIPT_PROCESS_ERROR 8592L -#define ERROR_DS_DIFFERENT_REPL_EPOCHS 8593L -#define ERROR_DS_DRS_EXTENSIONS_CHANGED 8594L -#define ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR 8595L -#define ERROR_DS_NO_MSDS_INTID 8596L -#define ERROR_DS_DUP_MSDS_INTID 8597L -#define ERROR_DS_EXISTS_IN_RDNATTID 8598L -#define ERROR_DS_AUTHORIZATION_FAILED 8599L -#define ERROR_DS_INVALID_SCRIPT 8600L -#define ERROR_DS_REMOTE_CROSSREF_OP_FAILED 8601L -#define ERROR_DS_CROSS_REF_BUSY 8602L -#define ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN 8603L -#define ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC 8604L -#define ERROR_DS_DUPLICATE_ID_FOUND 8605L -#define ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT 8606L -#define ERROR_DS_GROUP_CONVERSION_ERROR 8607L -#define ERROR_DS_CANT_MOVE_APP_BASIC_GROUP 8608L -#define ERROR_DS_CANT_MOVE_APP_QUERY_GROUP 8609L -#define ERROR_DS_ROLE_NOT_VERIFIED 8610L -#define ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL 8611L -#define ERROR_DS_DOMAIN_RENAME_IN_PROGRESS 8612L -#define ERROR_DS_EXISTING_AD_CHILD_NC 8613L -#define ERROR_DS_REPL_LIFETIME_EXCEEDED 8614L -#define ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER 8615L -#define ERROR_DS_LDAP_SEND_QUEUE_FULL 8616L -#define ERROR_DS_DRA_OUT_SCHEDULE_WINDOW 8617L -#define DNS_ERROR_RESPONSE_CODES_BASE 9000 -#define DNS_ERROR_RCODE_NO_ERROR NO_ERROR -#define DNS_ERROR_MASK 0x00002328 -#define DNS_ERROR_RCODE_FORMAT_ERROR 9001L -#define DNS_ERROR_RCODE_SERVER_FAILURE 9002L -#define DNS_ERROR_RCODE_NAME_ERROR 9003L -#define DNS_ERROR_RCODE_NOT_IMPLEMENTED 9004L -#define DNS_ERROR_RCODE_REFUSED 9005L -#define DNS_ERROR_RCODE_YXDOMAIN 9006L -#define DNS_ERROR_RCODE_YXRRSET 9007L -#define DNS_ERROR_RCODE_NXRRSET 9008L -#define DNS_ERROR_RCODE_NOTAUTH 9009L -#define DNS_ERROR_RCODE_NOTZONE 9010L -#define DNS_ERROR_RCODE_BADSIG 9016L -#define DNS_ERROR_RCODE_BADKEY 9017L -#define DNS_ERROR_RCODE_BADTIME 9018L -#define DNS_ERROR_RCODE_LAST DNS_ERROR_RCODE_BADTIME -#define DNS_ERROR_PACKET_FMT_BASE 9500 -#define DNS_INFO_NO_RECORDS 9501L -#define DNS_ERROR_BAD_PACKET 9502L -#define DNS_ERROR_NO_PACKET 9503L -#define DNS_ERROR_RCODE 9504L -#define DNS_ERROR_UNSECURE_PACKET 9505L -#define DNS_STATUS_PACKET_UNSECURE DNS_ERROR_UNSECURE_PACKET -#define DNS_ERROR_NO_MEMORY ERROR_OUTOFMEMORY -#define DNS_ERROR_INVALID_NAME ERROR_INVALID_NAME -#define DNS_ERROR_INVALID_DATA ERROR_INVALID_DATA -#define DNS_ERROR_GENERAL_API_BASE 9550 -#define DNS_ERROR_INVALID_TYPE 9551L -#define DNS_ERROR_INVALID_IP_ADDRESS 9552L -#define DNS_ERROR_INVALID_PROPERTY 9553L -#define DNS_ERROR_TRY_AGAIN_LATER 9554L -#define DNS_ERROR_NOT_UNIQUE 9555L -#define DNS_ERROR_NON_RFC_NAME 9556L -#define DNS_STATUS_FQDN 9557L -#define DNS_STATUS_DOTTED_NAME 9558L -#define DNS_STATUS_SINGLE_PART_NAME 9559L -#define DNS_ERROR_INVALID_NAME_CHAR 9560L -#define DNS_ERROR_NUMERIC_NAME 9561L -#define DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER 9562L -#define DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION 9563L -#define DNS_ERROR_CANNOT_FIND_ROOT_HINTS 9564L -#define DNS_ERROR_INCONSISTENT_ROOT_HINTS 9565L -#define DNS_ERROR_ZONE_BASE 9600 -#define DNS_ERROR_ZONE_DOES_NOT_EXIST 9601L -#define DNS_ERROR_NO_ZONE_INFO 9602L -#define DNS_ERROR_INVALID_ZONE_OPERATION 9603L -#define DNS_ERROR_ZONE_CONFIGURATION_ERROR 9604L -#define DNS_ERROR_ZONE_HAS_NO_SOA_RECORD 9605L -#define DNS_ERROR_ZONE_HAS_NO_NS_RECORDS 9606L -#define DNS_ERROR_ZONE_LOCKED 9607L -#define DNS_ERROR_ZONE_CREATION_FAILED 9608L -#define DNS_ERROR_ZONE_ALREADY_EXISTS 9609L -#define DNS_ERROR_AUTOZONE_ALREADY_EXISTS 9610L -#define DNS_ERROR_INVALID_ZONE_TYPE 9611L -#define DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP 9612L -#define DNS_ERROR_ZONE_NOT_SECONDARY 9613L -#define DNS_ERROR_NEED_SECONDARY_ADDRESSES 9614L -#define DNS_ERROR_WINS_INIT_FAILED 9615L -#define DNS_ERROR_NEED_WINS_SERVERS 9616L -#define DNS_ERROR_NBSTAT_INIT_FAILED 9617L -#define DNS_ERROR_SOA_DELETE_INVALID 9618L -#define DNS_ERROR_FORWARDER_ALREADY_EXISTS 9619L -#define DNS_ERROR_ZONE_REQUIRES_MASTER_IP 9620L -#define DNS_ERROR_ZONE_IS_SHUTDOWN 9621L -#define DNS_ERROR_DATAFILE_BASE 9650 -#define DNS_ERROR_PRIMARY_REQUIRES_DATAFILE 9651L -#define DNS_ERROR_INVALID_DATAFILE_NAME 9652L -#define DNS_ERROR_DATAFILE_OPEN_FAILURE 9653L -#define DNS_ERROR_FILE_WRITEBACK_FAILED 9654L -#define DNS_ERROR_DATAFILE_PARSING 9655L -#define DNS_ERROR_DATABASE_BASE 9700 -#define DNS_ERROR_RECORD_DOES_NOT_EXIST 9701L -#define DNS_ERROR_RECORD_FORMAT 9702L -#define DNS_ERROR_NODE_CREATION_FAILED 9703L -#define DNS_ERROR_UNKNOWN_RECORD_TYPE 9704L -#define DNS_ERROR_RECORD_TIMED_OUT 9705L -#define DNS_ERROR_NAME_NOT_IN_ZONE 9706L -#define DNS_ERROR_CNAME_LOOP 9707L -#define DNS_ERROR_NODE_IS_CNAME 9708L -#define DNS_ERROR_CNAME_COLLISION 9709L -#define DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT 9710L -#define DNS_ERROR_RECORD_ALREADY_EXISTS 9711L -#define DNS_ERROR_SECONDARY_DATA 9712L -#define DNS_ERROR_NO_CREATE_CACHE_DATA 9713L -#define DNS_ERROR_NAME_DOES_NOT_EXIST 9714L -#define DNS_WARNING_PTR_CREATE_FAILED 9715L -#define DNS_WARNING_DOMAIN_UNDELETED 9716L -#define DNS_ERROR_DS_UNAVAILABLE 9717L -#define DNS_ERROR_DS_ZONE_ALREADY_EXISTS 9718L -#define DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE 9719L -#define DNS_ERROR_OPERATION_BASE 9750 -#define DNS_INFO_AXFR_COMPLETE 9751L -#define DNS_ERROR_AXFR 9752L -#define DNS_INFO_ADDED_LOCAL_WINS 9753L -#define DNS_ERROR_SECURE_BASE 9800 -#define DNS_STATUS_CONTINUE_NEEDED 9801L -#define DNS_ERROR_SETUP_BASE 9850 -#define DNS_ERROR_NO_TCPIP 9851L -#define DNS_ERROR_NO_DNS_SERVERS 9852L -#define DNS_ERROR_DP_BASE 9900 -#define DNS_ERROR_DP_DOES_NOT_EXIST 9901L -#define DNS_ERROR_DP_ALREADY_EXISTS 9902L -#define DNS_ERROR_DP_NOT_ENLISTED 9903L -#define DNS_ERROR_DP_ALREADY_ENLISTED 9904L -#define DNS_ERROR_DP_NOT_AVAILABLE 9905L -#define DNS_ERROR_DP_FSMO_ERROR 9906L - -#ifndef WSABASEERR -#define WSABASEERR 10000 -#define WSAEINTR 10004L -#define WSAEBADF 10009L -#define WSAEACCES 10013L -#define WSAEFAULT 10014L -#define WSAEINVAL 10022L -#define WSAEMFILE 10024L -#define WSAEWOULDBLOCK 10035L -#define WSAEINPROGRESS 10036L -#define WSAEALREADY 10037L -#define WSAENOTSOCK 10038L -#define WSAEDESTADDRREQ 10039L -#define WSAEMSGSIZE 10040L -#define WSAEPROTOTYPE 10041L -#define WSAENOPROTOOPT 10042L -#define WSAEPROTONOSUPPORT 10043L -#define WSAESOCKTNOSUPPORT 10044L -#define WSAEOPNOTSUPP 10045L -#define WSAEPFNOSUPPORT 10046L -#define WSAEAFNOSUPPORT 10047L -#define WSAEADDRINUSE 10048L -#define WSAEADDRNOTAVAIL 10049L -#define WSAENETDOWN 10050L -#define WSAENETUNREACH 10051L -#define WSAENETRESET 10052L -#define WSAECONNABORTED 10053L -#define WSAECONNRESET 10054L -#define WSAENOBUFS 10055L -#define WSAEISCONN 10056L -#define WSAENOTCONN 10057L -#define WSAESHUTDOWN 10058L -#define WSAETOOMANYREFS 10059L -#define WSAETIMEDOUT 10060L -#define WSAECONNREFUSED 10061L -#define WSAELOOP 10062L -#define WSAENAMETOOLONG 10063L -#define WSAEHOSTDOWN 10064L -#define WSAEHOSTUNREACH 10065L -#define WSAENOTEMPTY 10066L -#define WSAEPROCLIM 10067L -#define WSAEUSERS 10068L -#define WSAEDQUOT 10069L -#define WSAESTALE 10070L -#define WSAEREMOTE 10071L -#define WSASYSNOTREADY 10091L -#define WSAVERNOTSUPPORTED 10092L -#define WSANOTINITIALISED 10093L -#define WSAEDISCON 10101L -#define WSAENOMORE 10102L -#define WSAECANCELLED 10103L -#define WSAEINVALIDPROCTABLE 10104L -#define WSAEINVALIDPROVIDER 10105L -#define WSAEPROVIDERFAILEDINIT 10106L -#define WSASYSCALLFAILURE 10107L -#define WSASERVICE_NOT_FOUND 10108L -#define WSATYPE_NOT_FOUND 10109L -#define WSA_E_NO_MORE 10110L -#define WSA_E_CANCELLED 10111L -#define WSAEREFUSED 10112L -#ifndef WSAHOST_NOT_FOUND -#define WSAHOST_NOT_FOUND 11001L -#endif -#ifndef WSATRY_AGAIN -#define WSATRY_AGAIN 11002L -#endif -#ifndef WSANO_RECOVERY -#define WSANO_RECOVERY 11003L -#endif -#ifndef WSANO_DATA -#define WSANO_DATA 11004L -#endif -#ifndef WSA_QOS_RECEIVERS -#define WSA_QOS_RECEIVERS 11005L -#endif -#ifndef WSA_QOS_SENDERS -#define WSA_QOS_SENDERS 11006L -#endif -#ifndef WSA_QOS_NO_SENDERS -#define WSA_QOS_NO_SENDERS 11007L -#endif -#ifndef WSA_QOS_NO_RECEIVERS -#define WSA_QOS_NO_RECEIVERS 11008L -#endif -#ifndef WSA_QOS_REQUEST_CONFIRMED -#define WSA_QOS_REQUEST_CONFIRMED 11009L -#endif -#ifndef WSA_QOS_ADMISSION_FAILURE -#define WSA_QOS_ADMISSION_FAILURE 11010L -#endif -#ifndef WSA_QOS_POLICY_FAILURE -#define WSA_QOS_POLICY_FAILURE 11011L -#endif -#ifndef WSA_QOS_BAD_STYLE -#define WSA_QOS_BAD_STYLE 11012L -#endif -#ifndef WSA_QOS_BAD_OBJECT -#define WSA_QOS_BAD_OBJECT 11013L -#endif -#ifndef WSA_QOS_TRAFFIC_CTRL_ERROR -#define WSA_QOS_TRAFFIC_CTRL_ERROR 11014L -#endif -#ifndef WSA_QOS_GENERIC_ERROR -#define WSA_QOS_GENERIC_ERROR 11015L -#endif -#ifndef WSA_QOS_ESERVICETYPE -#define WSA_QOS_ESERVICETYPE 11016L -#endif -#ifndef WSA_QOS_EFLOWSPEC -#define WSA_QOS_EFLOWSPEC 11017L -#endif -#ifndef WSA_QOS_EPROVSPECBUF -#define WSA_QOS_EPROVSPECBUF 11018L -#endif -#ifndef WSA_QOS_EFILTERSTYLE -#define WSA_QOS_EFILTERSTYLE 11019L -#endif -#ifndef WSA_QOS_EFILTERTYPE -#define WSA_QOS_EFILTERTYPE 11020L -#endif -#ifndef WSA_QOS_EFILTERCOUNT -#define WSA_QOS_EFILTERCOUNT 11021L -#endif -#ifndef WSA_QOS_EOBJLENGTH -#define WSA_QOS_EOBJLENGTH 11022L -#endif -#ifndef WSA_QOS_EFLOWCOUNT -#define WSA_QOS_EFLOWCOUNT 11023L -#endif -#ifndef WSA_QOS_EUNKNOWNPSOBJ -#define WSA_QOS_EUNKNOWNPSOBJ 11024L -#endif -#ifndef WSA_QOS_EPOLICYOBJ -#define WSA_QOS_EPOLICYOBJ 11025L -#endif -#ifndef WSA_QOS_EFLOWDESC -#define WSA_QOS_EFLOWDESC 11026L -#endif -#ifndef WSA_QOS_EPSFLOWSPEC -#define WSA_QOS_EPSFLOWSPEC 11027L -#endif -#ifndef WSA_QOS_EPSFILTERSPEC -#define WSA_QOS_EPSFILTERSPEC 11028L -#endif -#ifndef WSA_QOS_ESDMODEOBJ -#define WSA_QOS_ESDMODEOBJ 11029L -#endif -#ifndef WSA_QOS_ESHAPERATEOBJ -#define WSA_QOS_ESHAPERATEOBJ 11030L -#endif -#ifndef WSA_QOS_RESERVED_PETYPE -#define WSA_QOS_RESERVED_PETYPE 11031L -#endif -#endif /* WSABASEERR */ - -#define ERROR_SXS_SECTION_NOT_FOUND 14000L -#define ERROR_SXS_CANT_GEN_ACTCTX 14001L -#define ERROR_SXS_INVALID_ACTCTXDATA_FORMAT 14002L -#define ERROR_SXS_ASSEMBLY_NOT_FOUND 14003L -#define ERROR_SXS_MANIFEST_FORMAT_ERROR 14004L -#define ERROR_SXS_MANIFEST_PARSE_ERROR 14005L -#define ERROR_SXS_ACTIVATION_CONTEXT_DISABLED 14006L -#define ERROR_SXS_KEY_NOT_FOUND 14007L -#define ERROR_SXS_VERSION_CONFLICT 14008L -#define ERROR_SXS_WRONG_SECTION_TYPE 14009L -#define ERROR_SXS_THREAD_QUERIES_DISABLED 14010L -#define ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET 14011L -#define ERROR_SXS_UNKNOWN_ENCODING_GROUP 14012L -#define ERROR_SXS_UNKNOWN_ENCODING 14013L -#define ERROR_SXS_INVALID_XML_NAMESPACE_URI 14014L -#define ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED 14015L -#define ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED 14016L -#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE 14017L -#define ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE 14018L -#define ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE 14019L -#define ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT 14020L -#define ERROR_SXS_DUPLICATE_DLL_NAME 14021L -#define ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME 14022L -#define ERROR_SXS_DUPLICATE_CLSID 14023L -#define ERROR_SXS_DUPLICATE_IID 14024L -#define ERROR_SXS_DUPLICATE_TLBID 14025L -#define ERROR_SXS_DUPLICATE_PROGID 14026L -#define ERROR_SXS_DUPLICATE_ASSEMBLY_NAME 14027L -#define ERROR_SXS_FILE_HASH_MISMATCH 14028L -#define ERROR_SXS_POLICY_PARSE_ERROR 14029L -#define ERROR_SXS_XML_E_MISSINGQUOTE 14030L -#define ERROR_SXS_XML_E_COMMENTSYNTAX 14031L -#define ERROR_SXS_XML_E_BADSTARTNAMECHAR 14032L -#define ERROR_SXS_XML_E_BADNAMECHAR 14033L -#define ERROR_SXS_XML_E_BADCHARINSTRING 14034L -#define ERROR_SXS_XML_E_XMLDECLSYNTAX 14035L -#define ERROR_SXS_XML_E_BADCHARDATA 14036L -#define ERROR_SXS_XML_E_MISSINGWHITESPACE 14037L -#define ERROR_SXS_XML_E_EXPECTINGTAGEND 14038L -#define ERROR_SXS_XML_E_MISSINGSEMICOLON 14039L -#define ERROR_SXS_XML_E_UNBALANCEDPAREN 14040L -#define ERROR_SXS_XML_E_INTERNALERROR 14041L -#define ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE 14042L -#define ERROR_SXS_XML_E_INCOMPLETE_ENCODING 14043L -#define ERROR_SXS_XML_E_MISSING_PAREN 14044L -#define ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE 14045L -#define ERROR_SXS_XML_E_MULTIPLE_COLONS 14046L -#define ERROR_SXS_XML_E_INVALID_DECIMAL 14047L -#define ERROR_SXS_XML_E_INVALID_HEXIDECIMAL 14048L -#define ERROR_SXS_XML_E_INVALID_UNICODE 14049L -#define ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK 14050L -#define ERROR_SXS_XML_E_UNEXPECTEDENDTAG 14051L -#define ERROR_SXS_XML_E_UNCLOSEDTAG 14052L -#define ERROR_SXS_XML_E_DUPLICATEATTRIBUTE 14053L -#define ERROR_SXS_XML_E_MULTIPLEROOTS 14054L -#define ERROR_SXS_XML_E_INVALIDATROOTLEVEL 14055L -#define ERROR_SXS_XML_E_BADXMLDECL 14056L -#define ERROR_SXS_XML_E_MISSINGROOT 14057L -#define ERROR_SXS_XML_E_UNEXPECTEDEOF 14058L -#define ERROR_SXS_XML_E_BADPEREFINSUBSET 14059L -#define ERROR_SXS_XML_E_UNCLOSEDSTARTTAG 14060L -#define ERROR_SXS_XML_E_UNCLOSEDENDTAG 14061L -#define ERROR_SXS_XML_E_UNCLOSEDSTRING 14062L -#define ERROR_SXS_XML_E_UNCLOSEDCOMMENT 14063L -#define ERROR_SXS_XML_E_UNCLOSEDDECL 14064L -#define ERROR_SXS_XML_E_UNCLOSEDCDATA 14065L -#define ERROR_SXS_XML_E_RESERVEDNAMESPACE 14066L -#define ERROR_SXS_XML_E_INVALIDENCODING 14067L -#define ERROR_SXS_XML_E_INVALIDSWITCH 14068L -#define ERROR_SXS_XML_E_BADXMLCASE 14069L -#define ERROR_SXS_XML_E_INVALID_STANDALONE 14070L -#define ERROR_SXS_XML_E_UNEXPECTED_STANDALONE 14071L -#define ERROR_SXS_XML_E_INVALID_VERSION 14072L -#define ERROR_SXS_XML_E_MISSINGEQUALS 14073L -#define ERROR_SXS_PROTECTION_RECOVERY_FAILED 14074L -#define ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT 14075L -#define ERROR_SXS_PROTECTION_CATALOG_NOT_VALID 14076L -#define ERROR_SXS_UNTRANSLATABLE_HRESULT 14077L -#define ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING 14078L -#define ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE 14079L -#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME 14080L -#define ERROR_IPSEC_QM_POLICY_EXISTS 13000L -#define ERROR_IPSEC_QM_POLICY_NOT_FOUND 13001L -#define ERROR_IPSEC_QM_POLICY_IN_USE 13002L -#define ERROR_IPSEC_MM_POLICY_EXISTS 13003L -#define ERROR_IPSEC_MM_POLICY_NOT_FOUND 13004L -#define ERROR_IPSEC_MM_POLICY_IN_USE 13005L -#define ERROR_IPSEC_MM_FILTER_EXISTS 13006L -#define ERROR_IPSEC_MM_FILTER_NOT_FOUND 13007L -#define ERROR_IPSEC_TRANSPORT_FILTER_EXISTS 13008L -#define ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND 13009L -#define ERROR_IPSEC_MM_AUTH_EXISTS 13010L -#define ERROR_IPSEC_MM_AUTH_NOT_FOUND 13011L -#define ERROR_IPSEC_MM_AUTH_IN_USE 13012L -#define ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND 13013L -#define ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND 13014L -#define ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND 13015L -#define ERROR_IPSEC_TUNNEL_FILTER_EXISTS 13016L -#define ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND 13017L -#define ERROR_IPSEC_MM_FILTER_PENDING_DELETION 13018L -#define ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION 13019L -#define ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION 13020L -#define ERROR_IPSEC_MM_POLICY_PENDING_DELETION 13021L -#define ERROR_IPSEC_MM_AUTH_PENDING_DELETION 13022L -#define ERROR_IPSEC_QM_POLICY_PENDING_DELETION 13023L -#define WARNING_IPSEC_MM_POLICY_PRUNED 13024L -#define WARNING_IPSEC_QM_POLICY_PRUNED 13025L -#define ERROR_IPSEC_IKE_NEG_STATUS_BEGIN 13800L -#define ERROR_IPSEC_IKE_AUTH_FAIL 13801L -#define ERROR_IPSEC_IKE_ATTRIB_FAIL 13802L -#define ERROR_IPSEC_IKE_NEGOTIATION_PENDING 13803L -#define ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR 13804L -#define ERROR_IPSEC_IKE_TIMED_OUT 13805L -#define ERROR_IPSEC_IKE_NO_CERT 13806L -#define ERROR_IPSEC_IKE_SA_DELETED 13807L -#define ERROR_IPSEC_IKE_SA_REAPED 13808L -#define ERROR_IPSEC_IKE_MM_ACQUIRE_DROP 13809L -#define ERROR_IPSEC_IKE_QM_ACQUIRE_DROP 13810L -#define ERROR_IPSEC_IKE_QUEUE_DROP_MM 13811L -#define ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM 13812L -#define ERROR_IPSEC_IKE_DROP_NO_RESPONSE 13813L -#define ERROR_IPSEC_IKE_MM_DELAY_DROP 13814L -#define ERROR_IPSEC_IKE_QM_DELAY_DROP 13815L -#define ERROR_IPSEC_IKE_ERROR 13816L -#define ERROR_IPSEC_IKE_CRL_FAILED 13817L -#define ERROR_IPSEC_IKE_INVALID_KEY_USAGE 13818L -#define ERROR_IPSEC_IKE_INVALID_CERT_TYPE 13819L -#define ERROR_IPSEC_IKE_NO_PRIVATE_KEY 13820L -#define ERROR_IPSEC_IKE_DH_FAIL 13822L -#define ERROR_IPSEC_IKE_INVALID_HEADER 13824L -#define ERROR_IPSEC_IKE_NO_POLICY 13825L -#define ERROR_IPSEC_IKE_INVALID_SIGNATURE 13826L -#define ERROR_IPSEC_IKE_KERBEROS_ERROR 13827L -#define ERROR_IPSEC_IKE_NO_PUBLIC_KEY 13828L -#define ERROR_IPSEC_IKE_PROCESS_ERR 13829L -#define ERROR_IPSEC_IKE_PROCESS_ERR_SA 13830L -#define ERROR_IPSEC_IKE_PROCESS_ERR_PROP 13831L -#define ERROR_IPSEC_IKE_PROCESS_ERR_TRANS 13832L -#define ERROR_IPSEC_IKE_PROCESS_ERR_KE 13833L -#define ERROR_IPSEC_IKE_PROCESS_ERR_ID 13834L -#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT 13835L -#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ 13836L -#define ERROR_IPSEC_IKE_PROCESS_ERR_HASH 13837L -#define ERROR_IPSEC_IKE_PROCESS_ERR_SIG 13838L -#define ERROR_IPSEC_IKE_PROCESS_ERR_NONCE 13839L -#define ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY 13840L -#define ERROR_IPSEC_IKE_PROCESS_ERR_DELETE 13841L -#define ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR 13842L -#define ERROR_IPSEC_IKE_INVALID_PAYLOAD 13843L -#define ERROR_IPSEC_IKE_LOAD_SOFT_SA 13844L -#define ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN 13845L -#define ERROR_IPSEC_IKE_INVALID_COOKIE 13846L -#define ERROR_IPSEC_IKE_NO_PEER_CERT 13847L -#define ERROR_IPSEC_IKE_PEER_CRL_FAILED 13848L -#define ERROR_IPSEC_IKE_POLICY_CHANGE 13849L -#define ERROR_IPSEC_IKE_NO_MM_POLICY 13850L -#define ERROR_IPSEC_IKE_NOTCBPRIV 13851L -#define ERROR_IPSEC_IKE_SECLOADFAIL 13852L -#define ERROR_IPSEC_IKE_FAILSSPINIT 13853L -#define ERROR_IPSEC_IKE_FAILQUERYSSP 13854L -#define ERROR_IPSEC_IKE_SRVACQFAIL 13855L -#define ERROR_IPSEC_IKE_SRVQUERYCRED 13856L -#define ERROR_IPSEC_IKE_GETSPIFAIL 13857L -#define ERROR_IPSEC_IKE_INVALID_FILTER 13858L -#define ERROR_IPSEC_IKE_OUT_OF_MEMORY 13859L -#define ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED 13860L -#define ERROR_IPSEC_IKE_INVALID_POLICY 13861L -#define ERROR_IPSEC_IKE_UNKNOWN_DOI 13862L -#define ERROR_IPSEC_IKE_INVALID_SITUATION 13863L -#define ERROR_IPSEC_IKE_DH_FAILURE 13864L -#define ERROR_IPSEC_IKE_INVALID_GROUP 13865L -#define ERROR_IPSEC_IKE_ENCRYPT 13866L -#define ERROR_IPSEC_IKE_DECRYPT 13867L -#define ERROR_IPSEC_IKE_POLICY_MATCH 13868L -#define ERROR_IPSEC_IKE_UNSUPPORTED_ID 13869L -#define ERROR_IPSEC_IKE_INVALID_HASH 13870L -#define ERROR_IPSEC_IKE_INVALID_HASH_ALG 13871L -#define ERROR_IPSEC_IKE_INVALID_HASH_SIZE 13872L -#define ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG 13873L -#define ERROR_IPSEC_IKE_INVALID_AUTH_ALG 13874L -#define ERROR_IPSEC_IKE_INVALID_SIG 13875L -#define ERROR_IPSEC_IKE_LOAD_FAILED 13876L -#define ERROR_IPSEC_IKE_RPC_DELETE 13877L -#define ERROR_IPSEC_IKE_BENIGN_REINIT 13878L -#define ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY 13879L -#define ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN 13881L -#define ERROR_IPSEC_IKE_MM_LIMIT 13882L -#define ERROR_IPSEC_IKE_NEGOTIATION_DISABLED 13883L -#define ERROR_IPSEC_IKE_NEG_STATUS_END 13884L -#define SEVERITY_SUCCESS 0 -#define SEVERITY_ERROR 1 -#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) -#define FAILED(hr) ((HRESULT)(hr) < 0) -#define IS_ERROR(Status) ((unsigned long)(Status) >> 31==SEVERITY_ERROR) -#define HRESULT_CODE(hr) ((hr) & 0xFFFF) -#define SCODE_CODE(sc) ((sc) & 0xFFFF) -#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) -#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1fff) -#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) -#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1) -#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) -#define MAKE_SCODE(sev,fac,code) ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) -#define FACILITY_NT_BIT 0x10000000 -#define __HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) -#ifdef INLINE_HRESULT_FROM_WIN32 -#ifndef _HRESULT_DEFINED -#define _HRESULT_DEFINED -typedef long HRESULT; -#endif -__CRT_INLINE HRESULT HRESULT_FROM_WIN32(long x) { return x <= 0 ? (HRESULT)x : (HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000);} -#else -#define HRESULT_FROM_WIN32(x) __HRESULT_FROM_WIN32(x) -#endif -#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT)) -#define GetScode(hr) ((SCODE) (hr)) -#define ResultFromScode(sc) ((HRESULT) (sc)) -#define PropagateResult(hrPrevious,scBase) ((HRESULT) scBase) -#ifdef RC_INVOKED -#define _HRESULT_TYPEDEF_(_sc) _sc -#else -#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc) -#endif -#define NOERROR 0 -#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL) -#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L) -#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL) -#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L) -#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L) -#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L) -#define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L) -#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L) -#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L) -#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L) -#define E_PENDING _HRESULT_TYPEDEF_(0x8000000AL) -#define CO_E_INIT_TLS _HRESULT_TYPEDEF_(0x80004006L) -#define CO_E_INIT_SHARED_ALLOCATOR _HRESULT_TYPEDEF_(0x80004007L) -#define CO_E_INIT_MEMORY_ALLOCATOR _HRESULT_TYPEDEF_(0x80004008L) -#define CO_E_INIT_CLASS_CACHE _HRESULT_TYPEDEF_(0x80004009L) -#define CO_E_INIT_RPC_CHANNEL _HRESULT_TYPEDEF_(0x8000400AL) -#define CO_E_INIT_TLS_SET_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400BL) -#define CO_E_INIT_TLS_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400CL) -#define CO_E_INIT_UNACCEPTED_USER_ALLOCATOR _HRESULT_TYPEDEF_(0x8000400DL) -#define CO_E_INIT_SCM_MUTEX_EXISTS _HRESULT_TYPEDEF_(0x8000400EL) -#define CO_E_INIT_SCM_FILE_MAPPING_EXISTS _HRESULT_TYPEDEF_(0x8000400FL) -#define CO_E_INIT_SCM_MAP_VIEW_OF_FILE _HRESULT_TYPEDEF_(0x80004010L) -#define CO_E_INIT_SCM_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80004011L) -#define CO_E_INIT_ONLY_SINGLE_THREADED _HRESULT_TYPEDEF_(0x80004012L) -#define CO_E_CANT_REMOTE _HRESULT_TYPEDEF_(0x80004013L) -#define CO_E_BAD_SERVER_NAME _HRESULT_TYPEDEF_(0x80004014L) -#define CO_E_WRONG_SERVER_IDENTITY _HRESULT_TYPEDEF_(0x80004015L) -#define CO_E_OLE1DDE_DISABLED _HRESULT_TYPEDEF_(0x80004016L) -#define CO_E_RUNAS_SYNTAX _HRESULT_TYPEDEF_(0x80004017L) -#define CO_E_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004018L) -#define CO_E_RUNAS_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004019L) -#define CO_E_RUNAS_LOGON_FAILURE _HRESULT_TYPEDEF_(0x8000401AL) -#define CO_E_LAUNCH_PERMSSION_DENIED _HRESULT_TYPEDEF_(0x8000401BL) -#define CO_E_START_SERVICE_FAILURE _HRESULT_TYPEDEF_(0x8000401CL) -#define CO_E_REMOTE_COMMUNICATION_FAILURE _HRESULT_TYPEDEF_(0x8000401DL) -#define CO_E_SERVER_START_TIMEOUT _HRESULT_TYPEDEF_(0x8000401EL) -#define CO_E_CLSREG_INCONSISTENT _HRESULT_TYPEDEF_(0x8000401FL) -#define CO_E_IIDREG_INCONSISTENT _HRESULT_TYPEDEF_(0x80004020L) -#define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L) -#define CO_E_RELOAD_DLL _HRESULT_TYPEDEF_(0x80004022L) -#define CO_E_MSI_ERROR _HRESULT_TYPEDEF_(0x80004023L) -#define CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT _HRESULT_TYPEDEF_(0x80004024L) -#define CO_E_SERVER_PAUSED _HRESULT_TYPEDEF_(0x80004025L) -#define CO_E_SERVER_NOT_PAUSED _HRESULT_TYPEDEF_(0x80004026L) -#define CO_E_CLASS_DISABLED _HRESULT_TYPEDEF_(0x80004027L) -#define CO_E_CLRNOTAVAILABLE _HRESULT_TYPEDEF_(0x80004028L) -#define CO_E_ASYNC_WORK_REJECTED _HRESULT_TYPEDEF_(0x80004029L) -#define CO_E_SERVER_INIT_TIMEOUT _HRESULT_TYPEDEF_(0x8000402AL) -#define CO_E_NO_SECCTX_IN_ACTIVATE _HRESULT_TYPEDEF_(0x8000402BL) -#define CO_E_TRACKER_CONFIG _HRESULT_TYPEDEF_(0x80004030L) -#define CO_E_THREADPOOL_CONFIG _HRESULT_TYPEDEF_(0x80004031L) -#define CO_E_SXS_CONFIG _HRESULT_TYPEDEF_(0x80004032L) -#define CO_E_MALFORMED_SPN _HRESULT_TYPEDEF_(0x80004033L) -#define S_OK ((HRESULT)0x00000000L) -#define S_FALSE ((HRESULT)0x00000001L) -#define OLE_E_FIRST ((HRESULT)0x80040000L) -#define OLE_E_LAST ((HRESULT)0x800400FFL) -#define OLE_S_FIRST ((HRESULT)0x00040000L) -#define OLE_S_LAST ((HRESULT)0x000400FFL) -#define OLE_E_OLEVERB _HRESULT_TYPEDEF_(0x80040000L) -#define OLE_E_ADVF _HRESULT_TYPEDEF_(0x80040001L) -#define OLE_E_ENUM_NOMORE _HRESULT_TYPEDEF_(0x80040002L) -#define OLE_E_ADVISENOTSUPPORTED _HRESULT_TYPEDEF_(0x80040003L) -#define OLE_E_NOCONNECTION _HRESULT_TYPEDEF_(0x80040004L) -#define OLE_E_NOTRUNNING _HRESULT_TYPEDEF_(0x80040005L) -#define OLE_E_NOCACHE _HRESULT_TYPEDEF_(0x80040006L) -#define OLE_E_BLANK _HRESULT_TYPEDEF_(0x80040007L) -#define OLE_E_CLASSDIFF _HRESULT_TYPEDEF_(0x80040008L) -#define OLE_E_CANT_GETMONIKER _HRESULT_TYPEDEF_(0x80040009L) -#define OLE_E_CANT_BINDTOSOURCE _HRESULT_TYPEDEF_(0x8004000AL) -#define OLE_E_STATIC _HRESULT_TYPEDEF_(0x8004000BL) -#define OLE_E_PROMPTSAVECANCELLED _HRESULT_TYPEDEF_(0x8004000CL) -#define OLE_E_INVALIDRECT _HRESULT_TYPEDEF_(0x8004000DL) -#define OLE_E_WRONGCOMPOBJ _HRESULT_TYPEDEF_(0x8004000EL) -#define OLE_E_INVALIDHWND _HRESULT_TYPEDEF_(0x8004000FL) -#define OLE_E_NOT_INPLACEACTIVE _HRESULT_TYPEDEF_(0x80040010L) -#define OLE_E_CANTCONVERT _HRESULT_TYPEDEF_(0x80040011L) -#define OLE_E_NOSTORAGE _HRESULT_TYPEDEF_(0x80040012L) -#define DV_E_FORMATETC _HRESULT_TYPEDEF_(0x80040064L) -#define DV_E_DVTARGETDEVICE _HRESULT_TYPEDEF_(0x80040065L) -#define DV_E_STGMEDIUM _HRESULT_TYPEDEF_(0x80040066L) -#define DV_E_STATDATA _HRESULT_TYPEDEF_(0x80040067L) -#define DV_E_LINDEX _HRESULT_TYPEDEF_(0x80040068L) -#define DV_E_TYMED _HRESULT_TYPEDEF_(0x80040069L) -#define DV_E_CLIPFORMAT _HRESULT_TYPEDEF_(0x8004006AL) -#define DV_E_DVASPECT _HRESULT_TYPEDEF_(0x8004006BL) -#define DV_E_DVTARGETDEVICE_SIZE _HRESULT_TYPEDEF_(0x8004006CL) -#define DV_E_NOIVIEWOBJECT _HRESULT_TYPEDEF_(0x8004006DL) -#define DRAGDROP_E_FIRST 0x80040100L -#define DRAGDROP_E_LAST 0x8004010FL -#define DRAGDROP_S_FIRST 0x00040100L -#define DRAGDROP_S_LAST 0x0004010FL -#define DRAGDROP_E_NOTREGISTERED _HRESULT_TYPEDEF_(0x80040100L) -#define DRAGDROP_E_ALREADYREGISTERED _HRESULT_TYPEDEF_(0x80040101L) -#define DRAGDROP_E_INVALIDHWND _HRESULT_TYPEDEF_(0x80040102L) -#define CLASSFACTORY_E_FIRST 0x80040110L -#define CLASSFACTORY_E_LAST 0x8004011FL -#define CLASSFACTORY_S_FIRST 0x00040110L -#define CLASSFACTORY_S_LAST 0x0004011FL -#define CLASS_E_NOAGGREGATION _HRESULT_TYPEDEF_(0x80040110L) -#define CLASS_E_CLASSNOTAVAILABLE _HRESULT_TYPEDEF_(0x80040111L) -#define CLASS_E_NOTLICENSED _HRESULT_TYPEDEF_(0x80040112L) -#define MARSHAL_E_FIRST 0x80040120L -#define MARSHAL_E_LAST 0x8004012FL -#define MARSHAL_S_FIRST 0x00040120L -#define MARSHAL_S_LAST 0x0004012FL -#define DATA_E_FIRST 0x80040130L -#define DATA_E_LAST 0x8004013FL -#define DATA_S_FIRST 0x00040130L -#define DATA_S_LAST 0x0004013FL -#define VIEW_E_FIRST 0x80040140L -#define VIEW_E_LAST 0x8004014FL -#define VIEW_S_FIRST 0x00040140L -#define VIEW_S_LAST 0x0004014FL -#define VIEW_E_DRAW _HRESULT_TYPEDEF_(0x80040140L) -#define REGDB_E_FIRST 0x80040150L -#define REGDB_E_LAST 0x8004015FL -#define REGDB_S_FIRST 0x00040150L -#define REGDB_S_LAST 0x0004015FL -#define REGDB_E_READREGDB _HRESULT_TYPEDEF_(0x80040150L) -#define REGDB_E_WRITEREGDB _HRESULT_TYPEDEF_(0x80040151L) -#define REGDB_E_KEYMISSING _HRESULT_TYPEDEF_(0x80040152L) -#define REGDB_E_INVALIDVALUE _HRESULT_TYPEDEF_(0x80040153L) -#define REGDB_E_CLASSNOTREG _HRESULT_TYPEDEF_(0x80040154L) -#define REGDB_E_IIDNOTREG _HRESULT_TYPEDEF_(0x80040155L) -#define REGDB_E_BADTHREADINGMODEL _HRESULT_TYPEDEF_(0x80040156L) -#define CAT_E_FIRST 0x80040160L -#define CAT_E_LAST 0x80040161L -#define CAT_E_CATIDNOEXIST _HRESULT_TYPEDEF_(0x80040160L) -#define CAT_E_NODESCRIPTION _HRESULT_TYPEDEF_(0x80040161L) -#define CS_E_FIRST 0x80040164L -#define CS_E_LAST 0x8004016FL -#define CS_E_PACKAGE_NOTFOUND _HRESULT_TYPEDEF_(0x80040164L) -#define CS_E_NOT_DELETABLE _HRESULT_TYPEDEF_(0x80040165L) -#define CS_E_CLASS_NOTFOUND _HRESULT_TYPEDEF_(0x80040166L) -#define CS_E_INVALID_VERSION _HRESULT_TYPEDEF_(0x80040167L) -#define CS_E_NO_CLASSSTORE _HRESULT_TYPEDEF_(0x80040168L) -#define CS_E_OBJECT_NOTFOUND _HRESULT_TYPEDEF_(0x80040169L) -#define CS_E_OBJECT_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x8004016AL) -#define CS_E_INVALID_PATH _HRESULT_TYPEDEF_(0x8004016BL) -#define CS_E_NETWORK_ERROR _HRESULT_TYPEDEF_(0x8004016CL) -#define CS_E_ADMIN_LIMIT_EXCEEDED _HRESULT_TYPEDEF_(0x8004016DL) -#define CS_E_SCHEMA_MISMATCH _HRESULT_TYPEDEF_(0x8004016EL) -#define CS_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x8004016FL) -#define CACHE_E_FIRST 0x80040170L -#define CACHE_E_LAST 0x8004017FL -#define CACHE_S_FIRST 0x00040170L -#define CACHE_S_LAST 0x0004017FL -#define CACHE_E_NOCACHE_UPDATED _HRESULT_TYPEDEF_(0x80040170L) -#define OLEOBJ_E_FIRST 0x80040180L -#define OLEOBJ_E_LAST 0x8004018FL -#define OLEOBJ_S_FIRST 0x00040180L -#define OLEOBJ_S_LAST 0x0004018FL -#define OLEOBJ_E_NOVERBS _HRESULT_TYPEDEF_(0x80040180L) -#define OLEOBJ_E_INVALIDVERB _HRESULT_TYPEDEF_(0x80040181L) -#define CLIENTSITE_E_FIRST 0x80040190L -#define CLIENTSITE_E_LAST 0x8004019FL -#define CLIENTSITE_S_FIRST 0x00040190L -#define CLIENTSITE_S_LAST 0x0004019FL -#define INPLACE_E_NOTUNDOABLE _HRESULT_TYPEDEF_(0x800401A0L) -#define INPLACE_E_NOTOOLSPACE _HRESULT_TYPEDEF_(0x800401A1L) -#define INPLACE_E_FIRST 0x800401A0L -#define INPLACE_E_LAST 0x800401AFL -#define INPLACE_S_FIRST 0x000401A0L -#define INPLACE_S_LAST 0x000401AFL -#define ENUM_E_FIRST 0x800401B0L -#define ENUM_E_LAST 0x800401BFL -#define ENUM_S_FIRST 0x000401B0L -#define ENUM_S_LAST 0x000401BFL -#define CONVERT10_E_FIRST 0x800401C0L -#define CONVERT10_E_LAST 0x800401CFL -#define CONVERT10_S_FIRST 0x000401C0L -#define CONVERT10_S_LAST 0x000401CFL -#define CONVERT10_E_OLESTREAM_GET _HRESULT_TYPEDEF_(0x800401C0L) -#define CONVERT10_E_OLESTREAM_PUT _HRESULT_TYPEDEF_(0x800401C1L) -#define CONVERT10_E_OLESTREAM_FMT _HRESULT_TYPEDEF_(0x800401C2L) -#define CONVERT10_E_OLESTREAM_BITMAP_TO_DIB _HRESULT_TYPEDEF_(0x800401C3L) -#define CONVERT10_E_STG_FMT _HRESULT_TYPEDEF_(0x800401C4L) -#define CONVERT10_E_STG_NO_STD_STREAM _HRESULT_TYPEDEF_(0x800401C5L) -#define CONVERT10_E_STG_DIB_TO_BITMAP _HRESULT_TYPEDEF_(0x800401C6L) -#define CLIPBRD_E_FIRST 0x800401D0L -#define CLIPBRD_E_LAST 0x800401DFL -#define CLIPBRD_S_FIRST 0x000401D0L -#define CLIPBRD_S_LAST 0x000401DFL -#define CLIPBRD_E_CANT_OPEN _HRESULT_TYPEDEF_(0x800401D0L) -#define CLIPBRD_E_CANT_EMPTY _HRESULT_TYPEDEF_(0x800401D1L) -#define CLIPBRD_E_CANT_SET _HRESULT_TYPEDEF_(0x800401D2L) -#define CLIPBRD_E_BAD_DATA _HRESULT_TYPEDEF_(0x800401D3L) -#define CLIPBRD_E_CANT_CLOSE _HRESULT_TYPEDEF_(0x800401D4L) -#define MK_E_FIRST 0x800401E0L -#define MK_E_LAST 0x800401EFL -#define MK_S_FIRST 0x000401E0L -#define MK_S_LAST 0x000401EFL -#define MK_E_CONNECTMANUALLY _HRESULT_TYPEDEF_(0x800401E0L) -#define MK_E_EXCEEDEDDEADLINE _HRESULT_TYPEDEF_(0x800401E1L) -#define MK_E_NEEDGENERIC _HRESULT_TYPEDEF_(0x800401E2L) -#define MK_E_UNAVAILABLE _HRESULT_TYPEDEF_(0x800401E3L) -#define MK_E_SYNTAX _HRESULT_TYPEDEF_(0x800401E4L) -#define MK_E_NOOBJECT _HRESULT_TYPEDEF_(0x800401E5L) -#define MK_E_INVALIDEXTENSION _HRESULT_TYPEDEF_(0x800401E6L) -#define MK_E_INTERMEDIATEINTERFACENOTSUPPORTED _HRESULT_TYPEDEF_(0x800401E7L) -#define MK_E_NOTBINDABLE _HRESULT_TYPEDEF_(0x800401E8L) -#define MK_E_NOTBOUND _HRESULT_TYPEDEF_(0x800401E9L) -#define MK_E_CANTOPENFILE _HRESULT_TYPEDEF_(0x800401EAL) -#define MK_E_MUSTBOTHERUSER _HRESULT_TYPEDEF_(0x800401EBL) -#define MK_E_NOINVERSE _HRESULT_TYPEDEF_(0x800401ECL) -#define MK_E_NOSTORAGE _HRESULT_TYPEDEF_(0x800401EDL) -#define MK_E_NOPREFIX _HRESULT_TYPEDEF_(0x800401EEL) -#define MK_E_ENUMERATION_FAILED _HRESULT_TYPEDEF_(0x800401EFL) -#define CO_E_FIRST 0x800401F0L -#define CO_E_LAST 0x800401FFL -#define CO_S_FIRST 0x000401F0L -#define CO_S_LAST 0x000401FFL -#define CO_E_NOTINITIALIZED _HRESULT_TYPEDEF_(0x800401F0L) -#define CO_E_ALREADYINITIALIZED _HRESULT_TYPEDEF_(0x800401F1L) -#define CO_E_CANTDETERMINECLASS _HRESULT_TYPEDEF_(0x800401F2L) -#define CO_E_CLASSSTRING _HRESULT_TYPEDEF_(0x800401F3L) -#define CO_E_IIDSTRING _HRESULT_TYPEDEF_(0x800401F4L) -#define CO_E_APPNOTFOUND _HRESULT_TYPEDEF_(0x800401F5L) -#define CO_E_APPSINGLEUSE _HRESULT_TYPEDEF_(0x800401F6L) -#define CO_E_ERRORINAPP _HRESULT_TYPEDEF_(0x800401F7L) -#define CO_E_DLLNOTFOUND _HRESULT_TYPEDEF_(0x800401F8L) -#define CO_E_ERRORINDLL _HRESULT_TYPEDEF_(0x800401F9L) -#define CO_E_WRONGOSFORAPP _HRESULT_TYPEDEF_(0x800401FAL) -#define CO_E_OBJNOTREG _HRESULT_TYPEDEF_(0x800401FBL) -#define CO_E_OBJISREG _HRESULT_TYPEDEF_(0x800401FCL) -#define CO_E_OBJNOTCONNECTED _HRESULT_TYPEDEF_(0x800401FDL) -#define CO_E_APPDIDNTREG _HRESULT_TYPEDEF_(0x800401FEL) -#define CO_E_RELEASED _HRESULT_TYPEDEF_(0x800401FFL) -#define EVENT_E_FIRST 0x80040200L -#define EVENT_E_LAST 0x8004021FL -#define EVENT_S_FIRST 0x00040200L -#define EVENT_S_LAST 0x0004021FL -#define EVENT_S_SOME_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x00040200L) -#define EVENT_E_ALL_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x80040201L) -#define EVENT_S_NOSUBSCRIBERS _HRESULT_TYPEDEF_(0x00040202L) -#define EVENT_E_QUERYSYNTAX _HRESULT_TYPEDEF_(0x80040203L) -#define EVENT_E_QUERYFIELD _HRESULT_TYPEDEF_(0x80040204L) -#define EVENT_E_INTERNALEXCEPTION _HRESULT_TYPEDEF_(0x80040205L) -#define EVENT_E_INTERNALERROR _HRESULT_TYPEDEF_(0x80040206L) -#define EVENT_E_INVALID_PER_USER_SID _HRESULT_TYPEDEF_(0x80040207L) -#define EVENT_E_USER_EXCEPTION _HRESULT_TYPEDEF_(0x80040208L) -#define EVENT_E_TOO_MANY_METHODS _HRESULT_TYPEDEF_(0x80040209L) -#define EVENT_E_MISSING_EVENTCLASS _HRESULT_TYPEDEF_(0x8004020AL) -#define EVENT_E_NOT_ALL_REMOVED _HRESULT_TYPEDEF_(0x8004020BL) -#define EVENT_E_COMPLUS_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004020CL) -#define EVENT_E_CANT_MODIFY_OR_DELETE_UNCONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020DL) -#define EVENT_E_CANT_MODIFY_OR_DELETE_CONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020EL) -#define EVENT_E_INVALID_EVENT_CLASS_PARTITION _HRESULT_TYPEDEF_(0x8004020FL) -#define EVENT_E_PER_USER_SID_NOT_LOGGED_ON _HRESULT_TYPEDEF_(0x80040210L) -#define XACT_E_FIRST 0x8004D000 -#define XACT_E_LAST 0x8004D029 -#define XACT_S_FIRST 0x0004D000 -#define XACT_S_LAST 0x0004D010 -#define XACT_E_ALREADYOTHERSINGLEPHASE _HRESULT_TYPEDEF_(0x8004D000L) -#define XACT_E_CANTRETAIN _HRESULT_TYPEDEF_(0x8004D001L) -#define XACT_E_COMMITFAILED _HRESULT_TYPEDEF_(0x8004D002L) -#define XACT_E_COMMITPREVENTED _HRESULT_TYPEDEF_(0x8004D003L) -#define XACT_E_HEURISTICABORT _HRESULT_TYPEDEF_(0x8004D004L) -#define XACT_E_HEURISTICCOMMIT _HRESULT_TYPEDEF_(0x8004D005L) -#define XACT_E_HEURISTICDAMAGE _HRESULT_TYPEDEF_(0x8004D006L) -#define XACT_E_HEURISTICDANGER _HRESULT_TYPEDEF_(0x8004D007L) -#define XACT_E_ISOLATIONLEVEL _HRESULT_TYPEDEF_(0x8004D008L) -#define XACT_E_NOASYNC _HRESULT_TYPEDEF_(0x8004D009L) -#define XACT_E_NOENLIST _HRESULT_TYPEDEF_(0x8004D00AL) -#define XACT_E_NOISORETAIN _HRESULT_TYPEDEF_(0x8004D00BL) -#define XACT_E_NORESOURCE _HRESULT_TYPEDEF_(0x8004D00CL) -#define XACT_E_NOTCURRENT _HRESULT_TYPEDEF_(0x8004D00DL) -#define XACT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004D00EL) -#define XACT_E_NOTSUPPORTED _HRESULT_TYPEDEF_(0x8004D00FL) -#define XACT_E_UNKNOWNRMGRID _HRESULT_TYPEDEF_(0x8004D010L) -#define XACT_E_WRONGSTATE _HRESULT_TYPEDEF_(0x8004D011L) -#define XACT_E_WRONGUOW _HRESULT_TYPEDEF_(0x8004D012L) -#define XACT_E_XTIONEXISTS _HRESULT_TYPEDEF_(0x8004D013L) -#define XACT_E_NOIMPORTOBJECT _HRESULT_TYPEDEF_(0x8004D014L) -#define XACT_E_INVALIDCOOKIE _HRESULT_TYPEDEF_(0x8004D015L) -#define XACT_E_INDOUBT _HRESULT_TYPEDEF_(0x8004D016L) -#define XACT_E_NOTIMEOUT _HRESULT_TYPEDEF_(0x8004D017L) -#define XACT_E_ALREADYINPROGRESS _HRESULT_TYPEDEF_(0x8004D018L) -#define XACT_E_ABORTED _HRESULT_TYPEDEF_(0x8004D019L) -#define XACT_E_LOGFULL _HRESULT_TYPEDEF_(0x8004D01AL) -#define XACT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D01BL) -#define XACT_E_CONNECTION_DOWN _HRESULT_TYPEDEF_(0x8004D01CL) -#define XACT_E_CONNECTION_DENIED _HRESULT_TYPEDEF_(0x8004D01DL) -#define XACT_E_REENLISTTIMEOUT _HRESULT_TYPEDEF_(0x8004D01EL) -#define XACT_E_TIP_CONNECT_FAILED _HRESULT_TYPEDEF_(0x8004D01FL) -#define XACT_E_TIP_PROTOCOL_ERROR _HRESULT_TYPEDEF_(0x8004D020L) -#define XACT_E_TIP_PULL_FAILED _HRESULT_TYPEDEF_(0x8004D021L) -#define XACT_E_DEST_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D022L) -#define XACT_E_TIP_DISABLED _HRESULT_TYPEDEF_(0x8004D023L) -#define XACT_E_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D024L) -#define XACT_E_PARTNER_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D025L) -#define XACT_E_XA_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D026L) -#define XACT_E_UNABLE_TO_READ_DTC_CONFIG _HRESULT_TYPEDEF_(0x8004D027L) -#define XACT_E_UNABLE_TO_LOAD_DTC_PROXY _HRESULT_TYPEDEF_(0x8004D028L) -#define XACT_E_ABORTING _HRESULT_TYPEDEF_(0x8004D029L) -#define XACT_E_CLERKNOTFOUND _HRESULT_TYPEDEF_(0x8004D080L) -#define XACT_E_CLERKEXISTS _HRESULT_TYPEDEF_(0x8004D081L) -#define XACT_E_RECOVERYINPROGRESS _HRESULT_TYPEDEF_(0x8004D082L) -#define XACT_E_TRANSACTIONCLOSED _HRESULT_TYPEDEF_(0x8004D083L) -#define XACT_E_INVALIDLSN _HRESULT_TYPEDEF_(0x8004D084L) -#define XACT_E_REPLAYREQUEST _HRESULT_TYPEDEF_(0x8004D085L) -#define XACT_S_ASYNC _HRESULT_TYPEDEF_(0x0004D000L) -#define XACT_S_DEFECT _HRESULT_TYPEDEF_(0x0004D001L) -#define XACT_S_READONLY _HRESULT_TYPEDEF_(0x0004D002L) -#define XACT_S_SOMENORETAIN _HRESULT_TYPEDEF_(0x0004D003L) -#define XACT_S_OKINFORM _HRESULT_TYPEDEF_(0x0004D004L) -#define XACT_S_MADECHANGESCONTENT _HRESULT_TYPEDEF_(0x0004D005L) -#define XACT_S_MADECHANGESINFORM _HRESULT_TYPEDEF_(0x0004D006L) -#define XACT_S_ALLNORETAIN _HRESULT_TYPEDEF_(0x0004D007L) -#define XACT_S_ABORTING _HRESULT_TYPEDEF_(0x0004D008L) -#define XACT_S_SINGLEPHASE _HRESULT_TYPEDEF_(0x0004D009L) -#define XACT_S_LOCALLY_OK _HRESULT_TYPEDEF_(0x0004D00AL) -#define XACT_S_LASTRESOURCEMANAGER _HRESULT_TYPEDEF_(0x0004D010L) -#define CONTEXT_E_FIRST 0x8004E000L -#define CONTEXT_E_LAST 0x8004E02FL -#define CONTEXT_S_FIRST 0x0004E000L -#define CONTEXT_S_LAST 0x0004E02FL -#define CONTEXT_E_ABORTED _HRESULT_TYPEDEF_(0x8004E002L) -#define CONTEXT_E_ABORTING _HRESULT_TYPEDEF_(0x8004E003L) -#define CONTEXT_E_NOCONTEXT _HRESULT_TYPEDEF_(0x8004E004L) -#define CONTEXT_E_WOULD_DEADLOCK _HRESULT_TYPEDEF_(0x8004E005L) -#define CONTEXT_E_SYNCH_TIMEOUT _HRESULT_TYPEDEF_(0x8004E006L) -#define CONTEXT_E_OLDREF _HRESULT_TYPEDEF_(0x8004E007L) -#define CONTEXT_E_ROLENOTFOUND _HRESULT_TYPEDEF_(0x8004E00CL) -#define CONTEXT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004E00FL) -#define CO_E_ACTIVATIONFAILED _HRESULT_TYPEDEF_(0x8004E021L) -#define CO_E_ACTIVATIONFAILED_EVENTLOGGED _HRESULT_TYPEDEF_(0x8004E022L) -#define CO_E_ACTIVATIONFAILED_CATALOGERROR _HRESULT_TYPEDEF_(0x8004E023L) -#define CO_E_ACTIVATIONFAILED_TIMEOUT _HRESULT_TYPEDEF_(0x8004E024L) -#define CO_E_INITIALIZATIONFAILED _HRESULT_TYPEDEF_(0x8004E025L) -#define CONTEXT_E_NOJIT _HRESULT_TYPEDEF_(0x8004E026L) -#define CONTEXT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004E027L) -#define CO_E_THREADINGMODEL_CHANGED _HRESULT_TYPEDEF_(0x8004E028L) -#define CO_E_NOIISINTRINSICS _HRESULT_TYPEDEF_(0x8004E029L) -#define CO_E_NOCOOKIES _HRESULT_TYPEDEF_(0x8004E02AL) -#define CO_E_DBERROR _HRESULT_TYPEDEF_(0x8004E02BL) -#define CO_E_NOTPOOLED _HRESULT_TYPEDEF_(0x8004E02CL) -#define CO_E_NOTCONSTRUCTED _HRESULT_TYPEDEF_(0x8004E02DL) -#define CO_E_NOSYNCHRONIZATION _HRESULT_TYPEDEF_(0x8004E02EL) -#define CO_E_ISOLEVELMISMATCH _HRESULT_TYPEDEF_(0x8004E02FL) -#define OLE_S_USEREG _HRESULT_TYPEDEF_(0x00040000L) -#define OLE_S_STATIC _HRESULT_TYPEDEF_(0x00040001L) -#define OLE_S_MAC_CLIPFORMAT _HRESULT_TYPEDEF_(0x00040002L) -#define DRAGDROP_S_DROP _HRESULT_TYPEDEF_(0x00040100L) -#define DRAGDROP_S_CANCEL _HRESULT_TYPEDEF_(0x00040101L) -#define DRAGDROP_S_USEDEFAULTCURSORS _HRESULT_TYPEDEF_(0x00040102L) -#define DATA_S_SAMEFORMATETC _HRESULT_TYPEDEF_(0x00040130L) -#define VIEW_S_ALREADY_FROZEN _HRESULT_TYPEDEF_(0x00040140L) -#define CACHE_S_FORMATETC_NOTSUPPORTED _HRESULT_TYPEDEF_(0x00040170L) -#define CACHE_S_SAMECACHE _HRESULT_TYPEDEF_(0x00040171L) -#define CACHE_S_SOMECACHES_NOTUPDATED _HRESULT_TYPEDEF_(0x00040172L) -#define OLEOBJ_S_INVALIDVERB _HRESULT_TYPEDEF_(0x00040180L) -#define OLEOBJ_S_CANNOT_DOVERB_NOW _HRESULT_TYPEDEF_(0x00040181L) -#define OLEOBJ_S_INVALIDHWND _HRESULT_TYPEDEF_(0x00040182L) -#define INPLACE_S_TRUNCATED _HRESULT_TYPEDEF_(0x000401A0L) -#define CONVERT10_S_NO_PRESENTATION _HRESULT_TYPEDEF_(0x000401C0L) -#define MK_S_REDUCED_TO_SELF _HRESULT_TYPEDEF_(0x000401E2L) -#define MK_S_ME _HRESULT_TYPEDEF_(0x000401E4L) -#define MK_S_HIM _HRESULT_TYPEDEF_(0x000401E5L) -#define MK_S_US _HRESULT_TYPEDEF_(0x000401E6L) -#define MK_S_MONIKERALREADYREGISTERED _HRESULT_TYPEDEF_(0x000401E7L) -#define SCHED_S_TASK_READY _HRESULT_TYPEDEF_(0x00041300L) -#define SCHED_S_TASK_RUNNING _HRESULT_TYPEDEF_(0x00041301L) -#define SCHED_S_TASK_DISABLED _HRESULT_TYPEDEF_(0x00041302L) -#define SCHED_S_TASK_HAS_NOT_RUN _HRESULT_TYPEDEF_(0x00041303L) -#define SCHED_S_TASK_NO_MORE_RUNS _HRESULT_TYPEDEF_(0x00041304L) -#define SCHED_S_TASK_NOT_SCHEDULED _HRESULT_TYPEDEF_(0x00041305L) -#define SCHED_S_TASK_TERMINATED _HRESULT_TYPEDEF_(0x00041306L) -#define SCHED_S_TASK_NO_VALID_TRIGGERS _HRESULT_TYPEDEF_(0x00041307L) -#define SCHED_S_EVENT_TRIGGER _HRESULT_TYPEDEF_(0x00041308L) -#define SCHED_E_TRIGGER_NOT_FOUND _HRESULT_TYPEDEF_(0x80041309L) -#define SCHED_E_TASK_NOT_READY _HRESULT_TYPEDEF_(0x8004130AL) -#define SCHED_E_TASK_NOT_RUNNING _HRESULT_TYPEDEF_(0x8004130BL) -#define SCHED_E_SERVICE_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004130CL) -#define SCHED_E_CANNOT_OPEN_TASK _HRESULT_TYPEDEF_(0x8004130DL) -#define SCHED_E_INVALID_TASK _HRESULT_TYPEDEF_(0x8004130EL) -#define SCHED_E_ACCOUNT_INFORMATION_NOT_SET _HRESULT_TYPEDEF_(0x8004130FL) -#define SCHED_E_ACCOUNT_NAME_NOT_FOUND _HRESULT_TYPEDEF_(0x80041310L) -#define SCHED_E_ACCOUNT_DBASE_CORRUPT _HRESULT_TYPEDEF_(0x80041311L) -#define SCHED_E_NO_SECURITY_SERVICES _HRESULT_TYPEDEF_(0x80041312L) -#define SCHED_E_UNKNOWN_OBJECT_VERSION _HRESULT_TYPEDEF_(0x80041313L) -#define SCHED_E_UNSUPPORTED_ACCOUNT_OPTION _HRESULT_TYPEDEF_(0x80041314L) -#define SCHED_E_SERVICE_NOT_RUNNING _HRESULT_TYPEDEF_(0x80041315L) -#define CO_E_CLASS_CREATE_FAILED _HRESULT_TYPEDEF_(0x80080001L) -#define CO_E_SCM_ERROR _HRESULT_TYPEDEF_(0x80080002L) -#define CO_E_SCM_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080003L) -#define CO_E_BAD_PATH _HRESULT_TYPEDEF_(0x80080004L) -#define CO_E_SERVER_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80080005L) -#define CO_E_OBJSRV_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080006L) -#define MK_E_NO_NORMALIZED _HRESULT_TYPEDEF_(0x80080007L) -#define CO_E_SERVER_STOPPING _HRESULT_TYPEDEF_(0x80080008L) -#define MEM_E_INVALID_ROOT _HRESULT_TYPEDEF_(0x80080009L) -#define MEM_E_INVALID_LINK _HRESULT_TYPEDEF_(0x80080010L) -#define MEM_E_INVALID_SIZE _HRESULT_TYPEDEF_(0x80080011L) -#define CO_S_NOTALLINTERFACES _HRESULT_TYPEDEF_(0x00080012L) -#define CO_S_MACHINENAMENOTFOUND _HRESULT_TYPEDEF_(0x00080013L) -#define DISP_E_UNKNOWNINTERFACE _HRESULT_TYPEDEF_(0x80020001L) -#define DISP_E_MEMBERNOTFOUND _HRESULT_TYPEDEF_(0x80020003L) -#define DISP_E_PARAMNOTFOUND _HRESULT_TYPEDEF_(0x80020004L) -#define DISP_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80020005L) -#define DISP_E_UNKNOWNNAME _HRESULT_TYPEDEF_(0x80020006L) -#define DISP_E_NONAMEDARGS _HRESULT_TYPEDEF_(0x80020007L) -#define DISP_E_BADVARTYPE _HRESULT_TYPEDEF_(0x80020008L) -#define DISP_E_EXCEPTION _HRESULT_TYPEDEF_(0x80020009L) -#define DISP_E_OVERFLOW _HRESULT_TYPEDEF_(0x8002000AL) -#define DISP_E_BADINDEX _HRESULT_TYPEDEF_(0x8002000BL) -#define DISP_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002000CL) -#define DISP_E_ARRAYISLOCKED _HRESULT_TYPEDEF_(0x8002000DL) -#define DISP_E_BADPARAMCOUNT _HRESULT_TYPEDEF_(0x8002000EL) -#define DISP_E_PARAMNOTOPTIONAL _HRESULT_TYPEDEF_(0x8002000FL) -#define DISP_E_BADCALLEE _HRESULT_TYPEDEF_(0x80020010L) -#define DISP_E_NOTACOLLECTION _HRESULT_TYPEDEF_(0x80020011L) -#define DISP_E_DIVBYZERO _HRESULT_TYPEDEF_(0x80020012L) -#define DISP_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80020013L) -#define TYPE_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80028016L) -#define TYPE_E_FIELDNOTFOUND _HRESULT_TYPEDEF_(0x80028017L) -#define TYPE_E_INVDATAREAD _HRESULT_TYPEDEF_(0x80028018L) -#define TYPE_E_UNSUPFORMAT _HRESULT_TYPEDEF_(0x80028019L) -#define TYPE_E_REGISTRYACCESS _HRESULT_TYPEDEF_(0x8002801CL) -#define TYPE_E_LIBNOTREGISTERED _HRESULT_TYPEDEF_(0x8002801DL) -#define TYPE_E_UNDEFINEDTYPE _HRESULT_TYPEDEF_(0x80028027L) -#define TYPE_E_QUALIFIEDNAMEDISALLOWED _HRESULT_TYPEDEF_(0x80028028L) -#define TYPE_E_INVALIDSTATE _HRESULT_TYPEDEF_(0x80028029L) -#define TYPE_E_WRONGTYPEKIND _HRESULT_TYPEDEF_(0x8002802AL) -#define TYPE_E_ELEMENTNOTFOUND _HRESULT_TYPEDEF_(0x8002802BL) -#define TYPE_E_AMBIGUOUSNAME _HRESULT_TYPEDEF_(0x8002802CL) -#define TYPE_E_NAMECONFLICT _HRESULT_TYPEDEF_(0x8002802DL) -#define TYPE_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002802EL) -#define TYPE_E_DLLFUNCTIONNOTFOUND _HRESULT_TYPEDEF_(0x8002802FL) -#define TYPE_E_BADMODULEKIND _HRESULT_TYPEDEF_(0x800288BDL) -#define TYPE_E_SIZETOOBIG _HRESULT_TYPEDEF_(0x800288C5L) -#define TYPE_E_DUPLICATEID _HRESULT_TYPEDEF_(0x800288C6L) -#define TYPE_E_INVALIDID _HRESULT_TYPEDEF_(0x800288CFL) -#define TYPE_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80028CA0L) -#define TYPE_E_OUTOFBOUNDS _HRESULT_TYPEDEF_(0x80028CA1L) -#define TYPE_E_IOERROR _HRESULT_TYPEDEF_(0x80028CA2L) -#define TYPE_E_CANTCREATETMPFILE _HRESULT_TYPEDEF_(0x80028CA3L) -#define TYPE_E_CANTLOADLIBRARY _HRESULT_TYPEDEF_(0x80029C4AL) -#define TYPE_E_INCONSISTENTPROPFUNCS _HRESULT_TYPEDEF_(0x80029C83L) -#define TYPE_E_CIRCULARTYPE _HRESULT_TYPEDEF_(0x80029C84L) -#define STG_E_INVALIDFUNCTION _HRESULT_TYPEDEF_(0x80030001L) -#define STG_E_FILENOTFOUND _HRESULT_TYPEDEF_(0x80030002L) -#define STG_E_PATHNOTFOUND _HRESULT_TYPEDEF_(0x80030003L) -#define STG_E_TOOMANYOPENFILES _HRESULT_TYPEDEF_(0x80030004L) -#define STG_E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80030005L) -#define STG_E_INVALIDHANDLE _HRESULT_TYPEDEF_(0x80030006L) -#define STG_E_INSUFFICIENTMEMORY _HRESULT_TYPEDEF_(0x80030008L) -#define STG_E_INVALIDPOINTER _HRESULT_TYPEDEF_(0x80030009L) -#define STG_E_NOMOREFILES _HRESULT_TYPEDEF_(0x80030012L) -#define STG_E_DISKISWRITEPROTECTED _HRESULT_TYPEDEF_(0x80030013L) -#define STG_E_SEEKERROR _HRESULT_TYPEDEF_(0x80030019L) -#define STG_E_WRITEFAULT _HRESULT_TYPEDEF_(0x8003001DL) -#define STG_E_READFAULT _HRESULT_TYPEDEF_(0x8003001EL) -#define STG_E_SHAREVIOLATION _HRESULT_TYPEDEF_(0x80030020L) -#define STG_E_LOCKVIOLATION _HRESULT_TYPEDEF_(0x80030021L) -#define STG_E_FILEALREADYEXISTS _HRESULT_TYPEDEF_(0x80030050L) -#define STG_E_INVALIDPARAMETER _HRESULT_TYPEDEF_(0x80030057L) -#define STG_E_MEDIUMFULL _HRESULT_TYPEDEF_(0x80030070L) -#define STG_E_PROPSETMISMATCHED _HRESULT_TYPEDEF_(0x800300F0L) -#define STG_E_ABNORMALAPIEXIT _HRESULT_TYPEDEF_(0x800300FAL) -#define STG_E_INVALIDHEADER _HRESULT_TYPEDEF_(0x800300FBL) -#define STG_E_INVALIDNAME _HRESULT_TYPEDEF_(0x800300FCL) -#define STG_E_UNKNOWN _HRESULT_TYPEDEF_(0x800300FDL) -#define STG_E_UNIMPLEMENTEDFUNCTION _HRESULT_TYPEDEF_(0x800300FEL) -#define STG_E_INVALIDFLAG _HRESULT_TYPEDEF_(0x800300FFL) -#define STG_E_INUSE _HRESULT_TYPEDEF_(0x80030100L) -#define STG_E_NOTCURRENT _HRESULT_TYPEDEF_(0x80030101L) -#define STG_E_REVERTED _HRESULT_TYPEDEF_(0x80030102L) -#define STG_E_CANTSAVE _HRESULT_TYPEDEF_(0x80030103L) -#define STG_E_OLDFORMAT _HRESULT_TYPEDEF_(0x80030104L) -#define STG_E_OLDDLL _HRESULT_TYPEDEF_(0x80030105L) -#define STG_E_SHAREREQUIRED _HRESULT_TYPEDEF_(0x80030106L) -#define STG_E_NOTFILEBASEDSTORAGE _HRESULT_TYPEDEF_(0x80030107L) -#define STG_E_EXTANTMARSHALLINGS _HRESULT_TYPEDEF_(0x80030108L) -#define STG_E_DOCFILECORRUPT _HRESULT_TYPEDEF_(0x80030109L) -#define STG_E_BADBASEADDRESS _HRESULT_TYPEDEF_(0x80030110L) -#define STG_E_DOCFILETOOLARGE _HRESULT_TYPEDEF_(0x80030111L) -#define STG_E_NOTSIMPLEFORMAT _HRESULT_TYPEDEF_(0x80030112L) -#define STG_E_INCOMPLETE _HRESULT_TYPEDEF_(0x80030201L) -#define STG_E_TERMINATED _HRESULT_TYPEDEF_(0x80030202L) -#define STG_S_CONVERTED _HRESULT_TYPEDEF_(0x00030200L) -#define STG_S_BLOCK _HRESULT_TYPEDEF_(0x00030201L) -#define STG_S_RETRYNOW _HRESULT_TYPEDEF_(0x00030202L) -#define STG_S_MONITORING _HRESULT_TYPEDEF_(0x00030203L) -#define STG_S_MULTIPLEOPENS _HRESULT_TYPEDEF_(0x00030204L) -#define STG_S_CONSOLIDATIONFAILED _HRESULT_TYPEDEF_(0x00030205L) -#define STG_S_CANNOTCONSOLIDATE _HRESULT_TYPEDEF_(0x00030206L) -#define STG_E_STATUS_COPY_PROTECTION_FAILURE _HRESULT_TYPEDEF_(0x80030305L) -#define STG_E_CSS_AUTHENTICATION_FAILURE _HRESULT_TYPEDEF_(0x80030306L) -#define STG_E_CSS_KEY_NOT_PRESENT _HRESULT_TYPEDEF_(0x80030307L) -#define STG_E_CSS_KEY_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x80030308L) -#define STG_E_CSS_SCRAMBLED_SECTOR _HRESULT_TYPEDEF_(0x80030309L) -#define STG_E_CSS_REGION_MISMATCH _HRESULT_TYPEDEF_(0x8003030AL) -#define STG_E_RESETS_EXHAUSTED _HRESULT_TYPEDEF_(0x8003030BL) -#define RPC_E_CALL_REJECTED _HRESULT_TYPEDEF_(0x80010001L) -#define RPC_E_CALL_CANCELED _HRESULT_TYPEDEF_(0x80010002L) -#define RPC_E_CANTPOST_INSENDCALL _HRESULT_TYPEDEF_(0x80010003L) -#define RPC_E_CANTCALLOUT_INASYNCCALL _HRESULT_TYPEDEF_(0x80010004L) -#define RPC_E_CANTCALLOUT_INEXTERNALCALL _HRESULT_TYPEDEF_(0x80010005L) -#define RPC_E_CONNECTION_TERMINATED _HRESULT_TYPEDEF_(0x80010006L) -#define RPC_E_SERVER_DIED _HRESULT_TYPEDEF_(0x80010007L) -#define RPC_E_CLIENT_DIED _HRESULT_TYPEDEF_(0x80010008L) -#define RPC_E_INVALID_DATAPACKET _HRESULT_TYPEDEF_(0x80010009L) -#define RPC_E_CANTTRANSMIT_CALL _HRESULT_TYPEDEF_(0x8001000AL) -#define RPC_E_CLIENT_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000BL) -#define RPC_E_CLIENT_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000CL) -#define RPC_E_SERVER_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000DL) -#define RPC_E_SERVER_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000EL) -#define RPC_E_INVALID_DATA _HRESULT_TYPEDEF_(0x8001000FL) -#define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L) -#define RPC_E_CANTCALLOUT_AGAIN _HRESULT_TYPEDEF_(0x80010011L) -#define RPC_E_SERVER_DIED_DNE _HRESULT_TYPEDEF_(0x80010012L) -#define RPC_E_SYS_CALL_FAILED _HRESULT_TYPEDEF_(0x80010100L) -#define RPC_E_OUT_OF_RESOURCES _HRESULT_TYPEDEF_(0x80010101L) -#define RPC_E_ATTEMPTED_MULTITHREAD _HRESULT_TYPEDEF_(0x80010102L) -#define RPC_E_NOT_REGISTERED _HRESULT_TYPEDEF_(0x80010103L) -#define RPC_E_FAULT _HRESULT_TYPEDEF_(0x80010104L) -#define RPC_E_SERVERFAULT _HRESULT_TYPEDEF_(0x80010105L) -#define RPC_E_CHANGED_MODE _HRESULT_TYPEDEF_(0x80010106L) -#define RPC_E_INVALIDMETHOD _HRESULT_TYPEDEF_(0x80010107L) -#define RPC_E_DISCONNECTED _HRESULT_TYPEDEF_(0x80010108L) -#define RPC_E_RETRY _HRESULT_TYPEDEF_(0x80010109L) -#define RPC_E_SERVERCALL_RETRYLATER _HRESULT_TYPEDEF_(0x8001010AL) -#define RPC_E_SERVERCALL_REJECTED _HRESULT_TYPEDEF_(0x8001010BL) -#define RPC_E_INVALID_CALLDATA _HRESULT_TYPEDEF_(0x8001010CL) -#define RPC_E_CANTCALLOUT_ININPUTSYNCCALL _HRESULT_TYPEDEF_(0x8001010DL) -#define RPC_E_WRONG_THREAD _HRESULT_TYPEDEF_(0x8001010EL) -#define RPC_E_THREAD_NOT_INIT _HRESULT_TYPEDEF_(0x8001010FL) -#define RPC_E_VERSION_MISMATCH _HRESULT_TYPEDEF_(0x80010110L) -#define RPC_E_INVALID_HEADER _HRESULT_TYPEDEF_(0x80010111L) -#define RPC_E_INVALID_EXTENSION _HRESULT_TYPEDEF_(0x80010112L) -#define RPC_E_INVALID_IPID _HRESULT_TYPEDEF_(0x80010113L) -#define RPC_E_INVALID_OBJECT _HRESULT_TYPEDEF_(0x80010114L) -#define RPC_S_CALLPENDING _HRESULT_TYPEDEF_(0x80010115L) -#define RPC_S_WAITONTIMER _HRESULT_TYPEDEF_(0x80010116L) -#define RPC_E_CALL_COMPLETE _HRESULT_TYPEDEF_(0x80010117L) -#define RPC_E_UNSECURE_CALL _HRESULT_TYPEDEF_(0x80010118L) -#define RPC_E_TOO_LATE _HRESULT_TYPEDEF_(0x80010119L) -#define RPC_E_NO_GOOD_SECURITY_PACKAGES _HRESULT_TYPEDEF_(0x8001011AL) -#define RPC_E_ACCESS_DENIED _HRESULT_TYPEDEF_(0x8001011BL) -#define RPC_E_REMOTE_DISABLED _HRESULT_TYPEDEF_(0x8001011CL) -#define RPC_E_INVALID_OBJREF _HRESULT_TYPEDEF_(0x8001011DL) -#define RPC_E_NO_CONTEXT _HRESULT_TYPEDEF_(0x8001011EL) -#define RPC_E_TIMEOUT _HRESULT_TYPEDEF_(0x8001011FL) -#define RPC_E_NO_SYNC _HRESULT_TYPEDEF_(0x80010120L) -#define RPC_E_FULLSIC_REQUIRED _HRESULT_TYPEDEF_(0x80010121L) -#define RPC_E_INVALID_STD_NAME _HRESULT_TYPEDEF_(0x80010122L) -#define CO_E_FAILEDTOIMPERSONATE _HRESULT_TYPEDEF_(0x80010123L) -#define CO_E_FAILEDTOGETSECCTX _HRESULT_TYPEDEF_(0x80010124L) -#define CO_E_FAILEDTOOPENTHREADTOKEN _HRESULT_TYPEDEF_(0x80010125L) -#define CO_E_FAILEDTOGETTOKENINFO _HRESULT_TYPEDEF_(0x80010126L) -#define CO_E_TRUSTEEDOESNTMATCHCLIENT _HRESULT_TYPEDEF_(0x80010127L) -#define CO_E_FAILEDTOQUERYCLIENTBLANKET _HRESULT_TYPEDEF_(0x80010128L) -#define CO_E_FAILEDTOSETDACL _HRESULT_TYPEDEF_(0x80010129L) -#define CO_E_ACCESSCHECKFAILED _HRESULT_TYPEDEF_(0x8001012AL) -#define CO_E_NETACCESSAPIFAILED _HRESULT_TYPEDEF_(0x8001012BL) -#define CO_E_WRONGTRUSTEENAMESYNTAX _HRESULT_TYPEDEF_(0x8001012CL) -#define CO_E_INVALIDSID _HRESULT_TYPEDEF_(0x8001012DL) -#define CO_E_CONVERSIONFAILED _HRESULT_TYPEDEF_(0x8001012EL) -#define CO_E_NOMATCHINGSIDFOUND _HRESULT_TYPEDEF_(0x8001012FL) -#define CO_E_LOOKUPACCSIDFAILED _HRESULT_TYPEDEF_(0x80010130L) -#define CO_E_NOMATCHINGNAMEFOUND _HRESULT_TYPEDEF_(0x80010131L) -#define CO_E_LOOKUPACCNAMEFAILED _HRESULT_TYPEDEF_(0x80010132L) -#define CO_E_SETSERLHNDLFAILED _HRESULT_TYPEDEF_(0x80010133L) -#define CO_E_FAILEDTOGETWINDIR _HRESULT_TYPEDEF_(0x80010134L) -#define CO_E_PATHTOOLONG _HRESULT_TYPEDEF_(0x80010135L) -#define CO_E_FAILEDTOGENUUID _HRESULT_TYPEDEF_(0x80010136L) -#define CO_E_FAILEDTOCREATEFILE _HRESULT_TYPEDEF_(0x80010137L) -#define CO_E_FAILEDTOCLOSEHANDLE _HRESULT_TYPEDEF_(0x80010138L) -#define CO_E_EXCEEDSYSACLLIMIT _HRESULT_TYPEDEF_(0x80010139L) -#define CO_E_ACESINWRONGORDER _HRESULT_TYPEDEF_(0x8001013AL) -#define CO_E_INCOMPATIBLESTREAMVERSION _HRESULT_TYPEDEF_(0x8001013BL) -#define CO_E_FAILEDTOOPENPROCESSTOKEN _HRESULT_TYPEDEF_(0x8001013CL) -#define CO_E_DECODEFAILED _HRESULT_TYPEDEF_(0x8001013DL) -#define CO_E_ACNOTINITIALIZED _HRESULT_TYPEDEF_(0x8001013FL) -#define CO_E_CANCEL_DISABLED _HRESULT_TYPEDEF_(0x80010140L) -#define RPC_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8001FFFFL) -#define ERROR_AUDITING_DISABLED _HRESULT_TYPEDEF_(0xC0090001L) -#define ERROR_ALL_SIDS_FILTERED _HRESULT_TYPEDEF_(0xC0090002L) -#define NTE_BAD_UID _HRESULT_TYPEDEF_(0x80090001L) -#define NTE_BAD_HASH _HRESULT_TYPEDEF_(0x80090002L) -#define NTE_BAD_KEY _HRESULT_TYPEDEF_(0x80090003L) -#define NTE_BAD_LEN _HRESULT_TYPEDEF_(0x80090004L) -#define NTE_BAD_DATA _HRESULT_TYPEDEF_(0x80090005L) -#define NTE_BAD_SIGNATURE _HRESULT_TYPEDEF_(0x80090006L) -#define NTE_BAD_VER _HRESULT_TYPEDEF_(0x80090007L) -#define NTE_BAD_ALGID _HRESULT_TYPEDEF_(0x80090008L) -#define NTE_BAD_FLAGS _HRESULT_TYPEDEF_(0x80090009L) -#define NTE_BAD_TYPE _HRESULT_TYPEDEF_(0x8009000AL) -#define NTE_BAD_KEY_STATE _HRESULT_TYPEDEF_(0x8009000BL) -#define NTE_BAD_HASH_STATE _HRESULT_TYPEDEF_(0x8009000CL) -#define NTE_NO_KEY _HRESULT_TYPEDEF_(0x8009000DL) -#define NTE_NO_MEMORY _HRESULT_TYPEDEF_(0x8009000EL) -#define NTE_EXISTS _HRESULT_TYPEDEF_(0x8009000FL) -#define NTE_PERM _HRESULT_TYPEDEF_(0x80090010L) -#define NTE_NOT_FOUND _HRESULT_TYPEDEF_(0x80090011L) -#define NTE_DOUBLE_ENCRYPT _HRESULT_TYPEDEF_(0x80090012L) -#define NTE_BAD_PROVIDER _HRESULT_TYPEDEF_(0x80090013L) -#define NTE_BAD_PROV_TYPE _HRESULT_TYPEDEF_(0x80090014L) -#define NTE_BAD_PUBLIC_KEY _HRESULT_TYPEDEF_(0x80090015L) -#define NTE_BAD_KEYSET _HRESULT_TYPEDEF_(0x80090016L) -#define NTE_PROV_TYPE_NOT_DEF _HRESULT_TYPEDEF_(0x80090017L) -#define NTE_PROV_TYPE_ENTRY_BAD _HRESULT_TYPEDEF_(0x80090018L) -#define NTE_KEYSET_NOT_DEF _HRESULT_TYPEDEF_(0x80090019L) -#define NTE_KEYSET_ENTRY_BAD _HRESULT_TYPEDEF_(0x8009001AL) -#define NTE_PROV_TYPE_NO_MATCH _HRESULT_TYPEDEF_(0x8009001BL) -#define NTE_SIGNATURE_FILE_BAD _HRESULT_TYPEDEF_(0x8009001CL) -#define NTE_PROVIDER_DLL_FAIL _HRESULT_TYPEDEF_(0x8009001DL) -#define NTE_PROV_DLL_NOT_FOUND _HRESULT_TYPEDEF_(0x8009001EL) -#define NTE_BAD_KEYSET_PARAM _HRESULT_TYPEDEF_(0x8009001FL) -#define NTE_FAIL _HRESULT_TYPEDEF_(0x80090020L) -#define NTE_SYS_ERR _HRESULT_TYPEDEF_(0x80090021L) -#define NTE_SILENT_CONTEXT _HRESULT_TYPEDEF_(0x80090022L) -#define NTE_TOKEN_KEYSET_STORAGE_FULL _HRESULT_TYPEDEF_(0x80090023L) -#define NTE_TEMPORARY_PROFILE _HRESULT_TYPEDEF_(0x80090024L) -#define NTE_FIXEDPARAMETER _HRESULT_TYPEDEF_(0x80090025L) -#define SEC_E_INSUFFICIENT_MEMORY _HRESULT_TYPEDEF_(0x80090300L) -#define SEC_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80090301L) -#define SEC_E_UNSUPPORTED_FUNCTION _HRESULT_TYPEDEF_(0x80090302L) -#define SEC_E_TARGET_UNKNOWN _HRESULT_TYPEDEF_(0x80090303L) -#define SEC_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80090304L) -#define SEC_E_SECPKG_NOT_FOUND _HRESULT_TYPEDEF_(0x80090305L) -#define SEC_E_NOT_OWNER _HRESULT_TYPEDEF_(0x80090306L) -#define SEC_E_CANNOT_INSTALL _HRESULT_TYPEDEF_(0x80090307L) -#define SEC_E_INVALID_TOKEN _HRESULT_TYPEDEF_(0x80090308L) -#define SEC_E_CANNOT_PACK _HRESULT_TYPEDEF_(0x80090309L) -#define SEC_E_QOP_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009030AL) -#define SEC_E_NO_IMPERSONATION _HRESULT_TYPEDEF_(0x8009030BL) -#define SEC_E_LOGON_DENIED _HRESULT_TYPEDEF_(0x8009030CL) -#define SEC_E_UNKNOWN_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030DL) -#define SEC_E_NO_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030EL) -#define SEC_E_MESSAGE_ALTERED _HRESULT_TYPEDEF_(0x8009030FL) -#define SEC_E_OUT_OF_SEQUENCE _HRESULT_TYPEDEF_(0x80090310L) -#define SEC_E_NO_AUTHENTICATING_AUTHORITY _HRESULT_TYPEDEF_(0x80090311L) -#define SEC_I_CONTINUE_NEEDED _HRESULT_TYPEDEF_(0x00090312L) -#define SEC_I_COMPLETE_NEEDED _HRESULT_TYPEDEF_(0x00090313L) -#define SEC_I_COMPLETE_AND_CONTINUE _HRESULT_TYPEDEF_(0x00090314L) -#define SEC_I_LOCAL_LOGON _HRESULT_TYPEDEF_(0x00090315L) -#define SEC_E_BAD_PKGID _HRESULT_TYPEDEF_(0x80090316L) -#define SEC_E_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x80090317L) -#define SEC_I_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x00090317L) -#define SEC_E_INCOMPLETE_MESSAGE _HRESULT_TYPEDEF_(0x80090318L) -#define SEC_E_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x80090320L) -#define SEC_E_BUFFER_TOO_SMALL _HRESULT_TYPEDEF_(0x80090321L) -#define SEC_I_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x00090320L) -#define SEC_I_RENEGOTIATE _HRESULT_TYPEDEF_(0x00090321L) -#define SEC_E_WRONG_PRINCIPAL _HRESULT_TYPEDEF_(0x80090322L) -#define SEC_I_NO_LSA_CONTEXT _HRESULT_TYPEDEF_(0x00090323L) -#define SEC_E_TIME_SKEW _HRESULT_TYPEDEF_(0x80090324L) -#define SEC_E_UNTRUSTED_ROOT _HRESULT_TYPEDEF_(0x80090325L) -#define SEC_E_ILLEGAL_MESSAGE _HRESULT_TYPEDEF_(0x80090326L) -#define SEC_E_CERT_UNKNOWN _HRESULT_TYPEDEF_(0x80090327L) -#define SEC_E_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090328L) -#define SEC_E_ENCRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090329L) -#define SEC_E_DECRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090330L) -#define SEC_E_ALGORITHM_MISMATCH _HRESULT_TYPEDEF_(0x80090331L) -#define SEC_E_SECURITY_QOS_FAILED _HRESULT_TYPEDEF_(0x80090332L) -#define SEC_E_UNFINISHED_CONTEXT_DELETED _HRESULT_TYPEDEF_(0x80090333L) -#define SEC_E_NO_TGT_REPLY _HRESULT_TYPEDEF_(0x80090334L) -#define SEC_E_NO_IP_ADDRESSES _HRESULT_TYPEDEF_(0x80090335L) -#define SEC_E_WRONG_CREDENTIAL_HANDLE _HRESULT_TYPEDEF_(0x80090336L) -#define SEC_E_CRYPTO_SYSTEM_INVALID _HRESULT_TYPEDEF_(0x80090337L) -#define SEC_E_MAX_REFERRALS_EXCEEDED _HRESULT_TYPEDEF_(0x80090338L) -#define SEC_E_MUST_BE_KDC _HRESULT_TYPEDEF_(0x80090339L) -#define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009033AL) -#define SEC_E_TOO_MANY_PRINCIPALS _HRESULT_TYPEDEF_(0x8009033BL) -#define SEC_E_NO_PA_DATA _HRESULT_TYPEDEF_(0x8009033CL) -#define SEC_E_PKINIT_NAME_MISMATCH _HRESULT_TYPEDEF_(0x8009033DL) -#define SEC_E_SMARTCARD_LOGON_REQUIRED _HRESULT_TYPEDEF_(0x8009033EL) -#define SEC_E_SHUTDOWN_IN_PROGRESS _HRESULT_TYPEDEF_(0x8009033FL) -#define SEC_E_KDC_INVALID_REQUEST _HRESULT_TYPEDEF_(0x80090340L) -#define SEC_E_KDC_UNABLE_TO_REFER _HRESULT_TYPEDEF_(0x80090341L) -#define SEC_E_KDC_UNKNOWN_ETYPE _HRESULT_TYPEDEF_(0x80090342L) -#define SEC_E_UNSUPPORTED_PREAUTH _HRESULT_TYPEDEF_(0x80090343L) -#define SEC_E_DELEGATION_REQUIRED _HRESULT_TYPEDEF_(0x80090345L) -#define SEC_E_BAD_BINDINGS _HRESULT_TYPEDEF_(0x80090346L) -#define SEC_E_MULTIPLE_ACCOUNTS _HRESULT_TYPEDEF_(0x80090347L) -#define SEC_E_NO_KERB_KEY _HRESULT_TYPEDEF_(0x80090348L) -#define SEC_E_CERT_WRONG_USAGE _HRESULT_TYPEDEF_(0x80090349L) -#define SEC_E_DOWNGRADE_DETECTED _HRESULT_TYPEDEF_(0x80090350L) -#define SEC_E_SMARTCARD_CERT_REVOKED _HRESULT_TYPEDEF_(0x80090351L) -#define SEC_E_ISSUING_CA_UNTRUSTED _HRESULT_TYPEDEF_(0x80090352L) -#define SEC_E_REVOCATION_OFFLINE_C _HRESULT_TYPEDEF_(0x80090353L) -#define SEC_E_PKINIT_CLIENT_FAILURE _HRESULT_TYPEDEF_(0x80090354L) -#define SEC_E_SMARTCARD_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090355L) -#define SEC_E_NO_S4U_PROT_SUPPORT _HRESULT_TYPEDEF_(0x80090356L) -#define SEC_E_CROSSREALM_DELEGATION_FAILURE _HRESULT_TYPEDEF_(0x80090357L) -#define SEC_E_REVOCATION_OFFLINE_KDC _HRESULT_TYPEDEF_(0x80090358L) -#define SEC_E_ISSUING_CA_UNTRUSTED_KDC _HRESULT_TYPEDEF_(0x80090359L) -#define SEC_E_KDC_CERT_EXPIRED _HRESULT_TYPEDEF_(0x8009035AL) -#define SEC_E_KDC_CERT_REVOKED _HRESULT_TYPEDEF_(0x8009035BL) -#define SEC_E_NO_SPM SEC_E_INTERNAL_ERROR -#define SEC_E_NOT_SUPPORTED SEC_E_UNSUPPORTED_FUNCTION -#define CRYPT_E_MSG_ERROR _HRESULT_TYPEDEF_(0x80091001L) -#define CRYPT_E_UNKNOWN_ALGO _HRESULT_TYPEDEF_(0x80091002L) -#define CRYPT_E_OID_FORMAT _HRESULT_TYPEDEF_(0x80091003L) -#define CRYPT_E_INVALID_MSG_TYPE _HRESULT_TYPEDEF_(0x80091004L) -#define CRYPT_E_UNEXPECTED_ENCODING _HRESULT_TYPEDEF_(0x80091005L) -#define CRYPT_E_AUTH_ATTR_MISSING _HRESULT_TYPEDEF_(0x80091006L) -#define CRYPT_E_HASH_VALUE _HRESULT_TYPEDEF_(0x80091007L) -#define CRYPT_E_INVALID_INDEX _HRESULT_TYPEDEF_(0x80091008L) -#define CRYPT_E_ALREADY_DECRYPTED _HRESULT_TYPEDEF_(0x80091009L) -#define CRYPT_E_NOT_DECRYPTED _HRESULT_TYPEDEF_(0x8009100AL) -#define CRYPT_E_RECIPIENT_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100BL) -#define CRYPT_E_CONTROL_TYPE _HRESULT_TYPEDEF_(0x8009100CL) -#define CRYPT_E_ISSUER_SERIALNUMBER _HRESULT_TYPEDEF_(0x8009100DL) -#define CRYPT_E_SIGNER_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100EL) -#define CRYPT_E_ATTRIBUTES_MISSING _HRESULT_TYPEDEF_(0x8009100FL) -#define CRYPT_E_STREAM_MSG_NOT_READY _HRESULT_TYPEDEF_(0x80091010L) -#define CRYPT_E_STREAM_INSUFFICIENT_DATA _HRESULT_TYPEDEF_(0x80091011L) -#define CRYPT_I_NEW_PROTECTION_REQUIRED _HRESULT_TYPEDEF_(0x00091012L) -#define CRYPT_E_BAD_LEN _HRESULT_TYPEDEF_(0x80092001L) -#define CRYPT_E_BAD_ENCODE _HRESULT_TYPEDEF_(0x80092002L) -#define CRYPT_E_FILE_ERROR _HRESULT_TYPEDEF_(0x80092003L) -#define CRYPT_E_NOT_FOUND _HRESULT_TYPEDEF_(0x80092004L) -#define CRYPT_E_EXISTS _HRESULT_TYPEDEF_(0x80092005L) -#define CRYPT_E_NO_PROVIDER _HRESULT_TYPEDEF_(0x80092006L) -#define CRYPT_E_SELF_SIGNED _HRESULT_TYPEDEF_(0x80092007L) -#define CRYPT_E_DELETED_PREV _HRESULT_TYPEDEF_(0x80092008L) -#define CRYPT_E_NO_MATCH _HRESULT_TYPEDEF_(0x80092009L) -#define CRYPT_E_UNEXPECTED_MSG_TYPE _HRESULT_TYPEDEF_(0x8009200AL) -#define CRYPT_E_NO_KEY_PROPERTY _HRESULT_TYPEDEF_(0x8009200BL) -#define CRYPT_E_NO_DECRYPT_CERT _HRESULT_TYPEDEF_(0x8009200CL) -#define CRYPT_E_BAD_MSG _HRESULT_TYPEDEF_(0x8009200DL) -#define CRYPT_E_NO_SIGNER _HRESULT_TYPEDEF_(0x8009200EL) -#define CRYPT_E_PENDING_CLOSE _HRESULT_TYPEDEF_(0x8009200FL) -#define CRYPT_E_REVOKED _HRESULT_TYPEDEF_(0x80092010L) -#define CRYPT_E_NO_REVOCATION_DLL _HRESULT_TYPEDEF_(0x80092011L) -#define CRYPT_E_NO_REVOCATION_CHECK _HRESULT_TYPEDEF_(0x80092012L) -#define CRYPT_E_REVOCATION_OFFLINE _HRESULT_TYPEDEF_(0x80092013L) -#define CRYPT_E_NOT_IN_REVOCATION_DATABASE _HRESULT_TYPEDEF_(0x80092014L) -#define CRYPT_E_INVALID_NUMERIC_STRING _HRESULT_TYPEDEF_(0x80092020L) -#define CRYPT_E_INVALID_PRINTABLE_STRING _HRESULT_TYPEDEF_(0x80092021L) -#define CRYPT_E_INVALID_IA5_STRING _HRESULT_TYPEDEF_(0x80092022L) -#define CRYPT_E_INVALID_X500_STRING _HRESULT_TYPEDEF_(0x80092023L) -#define CRYPT_E_NOT_CHAR_STRING _HRESULT_TYPEDEF_(0x80092024L) -#define CRYPT_E_FILERESIZED _HRESULT_TYPEDEF_(0x80092025L) -#define CRYPT_E_SECURITY_SETTINGS _HRESULT_TYPEDEF_(0x80092026L) -#define CRYPT_E_NO_VERIFY_USAGE_DLL _HRESULT_TYPEDEF_(0x80092027L) -#define CRYPT_E_NO_VERIFY_USAGE_CHECK _HRESULT_TYPEDEF_(0x80092028L) -#define CRYPT_E_VERIFY_USAGE_OFFLINE _HRESULT_TYPEDEF_(0x80092029L) -#define CRYPT_E_NOT_IN_CTL _HRESULT_TYPEDEF_(0x8009202AL) -#define CRYPT_E_NO_TRUSTED_SIGNER _HRESULT_TYPEDEF_(0x8009202BL) -#define CRYPT_E_MISSING_PUBKEY_PARA _HRESULT_TYPEDEF_(0x8009202CL) -#define CRYPT_E_OSS_ERROR _HRESULT_TYPEDEF_(0x80093000L) -#define OSS_MORE_BUF _HRESULT_TYPEDEF_(0x80093001L) -#define OSS_NEGATIVE_UINTEGER _HRESULT_TYPEDEF_(0x80093002L) -#define OSS_PDU_RANGE _HRESULT_TYPEDEF_(0x80093003L) -#define OSS_MORE_INPUT _HRESULT_TYPEDEF_(0x80093004L) -#define OSS_DATA_ERROR _HRESULT_TYPEDEF_(0x80093005L) -#define OSS_BAD_ARG _HRESULT_TYPEDEF_(0x80093006L) -#define OSS_BAD_VERSION _HRESULT_TYPEDEF_(0x80093007L) -#define OSS_OUT_MEMORY _HRESULT_TYPEDEF_(0x80093008L) -#define OSS_PDU_MISMATCH _HRESULT_TYPEDEF_(0x80093009L) -#define OSS_LIMITED _HRESULT_TYPEDEF_(0x8009300AL) -#define OSS_BAD_PTR _HRESULT_TYPEDEF_(0x8009300BL) -#define OSS_BAD_TIME _HRESULT_TYPEDEF_(0x8009300CL) -#define OSS_INDEFINITE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009300DL) -#define OSS_MEM_ERROR _HRESULT_TYPEDEF_(0x8009300EL) -#define OSS_BAD_TABLE _HRESULT_TYPEDEF_(0x8009300FL) -#define OSS_TOO_LONG _HRESULT_TYPEDEF_(0x80093010L) -#define OSS_CONSTRAINT_VIOLATED _HRESULT_TYPEDEF_(0x80093011L) -#define OSS_FATAL_ERROR _HRESULT_TYPEDEF_(0x80093012L) -#define OSS_ACCESS_SERIALIZATION_ERROR _HRESULT_TYPEDEF_(0x80093013L) -#define OSS_NULL_TBL _HRESULT_TYPEDEF_(0x80093014L) -#define OSS_NULL_FCN _HRESULT_TYPEDEF_(0x80093015L) -#define OSS_BAD_ENCRULES _HRESULT_TYPEDEF_(0x80093016L) -#define OSS_UNAVAIL_ENCRULES _HRESULT_TYPEDEF_(0x80093017L) -#define OSS_CANT_OPEN_TRACE_WINDOW _HRESULT_TYPEDEF_(0x80093018L) -#define OSS_UNIMPLEMENTED _HRESULT_TYPEDEF_(0x80093019L) -#define OSS_OID_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301AL) -#define OSS_CANT_OPEN_TRACE_FILE _HRESULT_TYPEDEF_(0x8009301BL) -#define OSS_TRACE_FILE_ALREADY_OPEN _HRESULT_TYPEDEF_(0x8009301CL) -#define OSS_TABLE_MISMATCH _HRESULT_TYPEDEF_(0x8009301DL) -#define OSS_TYPE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009301EL) -#define OSS_REAL_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301FL) -#define OSS_REAL_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093020L) -#define OSS_OUT_OF_RANGE _HRESULT_TYPEDEF_(0x80093021L) -#define OSS_COPIER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093022L) -#define OSS_CONSTRAINT_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093023L) -#define OSS_COMPARATOR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093024L) -#define OSS_COMPARATOR_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093025L) -#define OSS_MEM_MGR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093026L) -#define OSS_PDV_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093027L) -#define OSS_PDV_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093028L) -#define OSS_API_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093029L) -#define OSS_BERDER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302AL) -#define OSS_PER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302BL) -#define OSS_OPEN_TYPE_ERROR _HRESULT_TYPEDEF_(0x8009302CL) -#define OSS_MUTEX_NOT_CREATED _HRESULT_TYPEDEF_(0x8009302DL) -#define OSS_CANT_CLOSE_TRACE_FILE _HRESULT_TYPEDEF_(0x8009302EL) -#define CRYPT_E_ASN1_ERROR _HRESULT_TYPEDEF_(0x80093100L) -#define CRYPT_E_ASN1_INTERNAL _HRESULT_TYPEDEF_(0x80093101L) -#define CRYPT_E_ASN1_EOD _HRESULT_TYPEDEF_(0x80093102L) -#define CRYPT_E_ASN1_CORRUPT _HRESULT_TYPEDEF_(0x80093103L) -#define CRYPT_E_ASN1_LARGE _HRESULT_TYPEDEF_(0x80093104L) -#define CRYPT_E_ASN1_CONSTRAINT _HRESULT_TYPEDEF_(0x80093105L) -#define CRYPT_E_ASN1_MEMORY _HRESULT_TYPEDEF_(0x80093106L) -#define CRYPT_E_ASN1_OVERFLOW _HRESULT_TYPEDEF_(0x80093107L) -#define CRYPT_E_ASN1_BADPDU _HRESULT_TYPEDEF_(0x80093108L) -#define CRYPT_E_ASN1_BADARGS _HRESULT_TYPEDEF_(0x80093109L) -#define CRYPT_E_ASN1_BADREAL _HRESULT_TYPEDEF_(0x8009310AL) -#define CRYPT_E_ASN1_BADTAG _HRESULT_TYPEDEF_(0x8009310BL) -#define CRYPT_E_ASN1_CHOICE _HRESULT_TYPEDEF_(0x8009310CL) -#define CRYPT_E_ASN1_RULE _HRESULT_TYPEDEF_(0x8009310DL) -#define CRYPT_E_ASN1_UTF8 _HRESULT_TYPEDEF_(0x8009310EL) -#define CRYPT_E_ASN1_PDU_TYPE _HRESULT_TYPEDEF_(0x80093133L) -#define CRYPT_E_ASN1_NYI _HRESULT_TYPEDEF_(0x80093134L) -#define CRYPT_E_ASN1_EXTENDED _HRESULT_TYPEDEF_(0x80093201L) -#define CRYPT_E_ASN1_NOEOD _HRESULT_TYPEDEF_(0x80093202L) -#define CERTSRV_E_BAD_REQUESTSUBJECT _HRESULT_TYPEDEF_(0x80094001L) -#define CERTSRV_E_NO_REQUEST _HRESULT_TYPEDEF_(0x80094002L) -#define CERTSRV_E_BAD_REQUESTSTATUS _HRESULT_TYPEDEF_(0x80094003L) -#define CERTSRV_E_PROPERTY_EMPTY _HRESULT_TYPEDEF_(0x80094004L) -#define CERTSRV_E_INVALID_CA_CERTIFICATE _HRESULT_TYPEDEF_(0x80094005L) -#define CERTSRV_E_SERVER_SUSPENDED _HRESULT_TYPEDEF_(0x80094006L) -#define CERTSRV_E_ENCODING_LENGTH _HRESULT_TYPEDEF_(0x80094007L) -#define CERTSRV_E_ROLECONFLICT _HRESULT_TYPEDEF_(0x80094008L) -#define CERTSRV_E_RESTRICTEDOFFICER _HRESULT_TYPEDEF_(0x80094009L) -#define CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED _HRESULT_TYPEDEF_(0x8009400AL) -#define CERTSRV_E_NO_VALID_KRA _HRESULT_TYPEDEF_(0x8009400BL) -#define CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL _HRESULT_TYPEDEF_(0x8009400CL) -#define CERTSRV_E_NO_CAADMIN_DEFINED _HRESULT_TYPEDEF_(0x8009400DL) -#define CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE _HRESULT_TYPEDEF_(0x8009400EL) -#define CERTSRV_E_NO_DB_SESSIONS _HRESULT_TYPEDEF_(0x8009400FL) -#define CERTSRV_E_ALIGNMENT_FAULT _HRESULT_TYPEDEF_(0x80094010L) -#define CERTSRV_E_ENROLL_DENIED _HRESULT_TYPEDEF_(0x80094011L) -#define CERTSRV_E_TEMPLATE_DENIED _HRESULT_TYPEDEF_(0x80094012L) -#define CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE _HRESULT_TYPEDEF_(0x80094013L) -#define CERTSRV_E_UNSUPPORTED_CERT_TYPE _HRESULT_TYPEDEF_(0x80094800L) -#define CERTSRV_E_NO_CERT_TYPE _HRESULT_TYPEDEF_(0x80094801L) -#define CERTSRV_E_TEMPLATE_CONFLICT _HRESULT_TYPEDEF_(0x80094802L) -#define CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED _HRESULT_TYPEDEF_(0x80094803L) -#define CERTSRV_E_ARCHIVED_KEY_REQUIRED _HRESULT_TYPEDEF_(0x80094804L) -#define CERTSRV_E_SMIME_REQUIRED _HRESULT_TYPEDEF_(0x80094805L) -#define CERTSRV_E_BAD_RENEWAL_SUBJECT _HRESULT_TYPEDEF_(0x80094806L) -#define CERTSRV_E_BAD_TEMPLATE_VERSION _HRESULT_TYPEDEF_(0x80094807L) -#define CERTSRV_E_TEMPLATE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094808L) -#define CERTSRV_E_SIGNATURE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094809L) -#define CERTSRV_E_SIGNATURE_COUNT _HRESULT_TYPEDEF_(0x8009480AL) -#define CERTSRV_E_SIGNATURE_REJECTED _HRESULT_TYPEDEF_(0x8009480BL) -#define CERTSRV_E_ISSUANCE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x8009480CL) -#define CERTSRV_E_SUBJECT_UPN_REQUIRED _HRESULT_TYPEDEF_(0x8009480DL) -#define CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED _HRESULT_TYPEDEF_(0x8009480EL) -#define CERTSRV_E_SUBJECT_DNS_REQUIRED _HRESULT_TYPEDEF_(0x8009480FL) -#define CERTSRV_E_ARCHIVED_KEY_UNEXPECTED _HRESULT_TYPEDEF_(0x80094810L) -#define CERTSRV_E_KEY_LENGTH _HRESULT_TYPEDEF_(0x80094811L) -#define CERTSRV_E_SUBJECT_EMAIL_REQUIRED _HRESULT_TYPEDEF_(0x80094812L) -#define CERTSRV_E_UNKNOWN_CERT_TYPE _HRESULT_TYPEDEF_(0x80094813L) -#define CERTSRV_E_CERT_TYPE_OVERLAP _HRESULT_TYPEDEF_(0x80094814L) -#define XENROLL_E_KEY_NOT_EXPORTABLE _HRESULT_TYPEDEF_(0x80095000L) -#define XENROLL_E_CANNOT_ADD_ROOT_CERT _HRESULT_TYPEDEF_(0x80095001L) -#define XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND _HRESULT_TYPEDEF_(0x80095002L) -#define XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH _HRESULT_TYPEDEF_(0x80095003L) -#define XENROLL_E_RESPONSE_KA_HASH_MISMATCH _HRESULT_TYPEDEF_(0x80095004L) -#define XENROLL_E_KEYSPEC_SMIME_MISMATCH _HRESULT_TYPEDEF_(0x80095005L) -#define TRUST_E_SYSTEM_ERROR _HRESULT_TYPEDEF_(0x80096001L) -#define TRUST_E_NO_SIGNER_CERT _HRESULT_TYPEDEF_(0x80096002L) -#define TRUST_E_COUNTER_SIGNER _HRESULT_TYPEDEF_(0x80096003L) -#define TRUST_E_CERT_SIGNATURE _HRESULT_TYPEDEF_(0x80096004L) -#define TRUST_E_TIME_STAMP _HRESULT_TYPEDEF_(0x80096005L) -#define TRUST_E_BAD_DIGEST _HRESULT_TYPEDEF_(0x80096010L) -#define TRUST_E_BASIC_CONSTRAINTS _HRESULT_TYPEDEF_(0x80096019L) -#define TRUST_E_FINANCIAL_CRITERIA _HRESULT_TYPEDEF_(0x8009601EL) -#define MSSIPOTF_E_OUTOFMEMRANGE _HRESULT_TYPEDEF_(0x80097001L) -#define MSSIPOTF_E_CANTGETOBJECT _HRESULT_TYPEDEF_(0x80097002L) -#define MSSIPOTF_E_NOHEADTABLE _HRESULT_TYPEDEF_(0x80097003L) -#define MSSIPOTF_E_BAD_MAGICNUMBER _HRESULT_TYPEDEF_(0x80097004L) -#define MSSIPOTF_E_BAD_OFFSET_TABLE _HRESULT_TYPEDEF_(0x80097005L) -#define MSSIPOTF_E_TABLE_TAGORDER _HRESULT_TYPEDEF_(0x80097006L) -#define MSSIPOTF_E_TABLE_LONGWORD _HRESULT_TYPEDEF_(0x80097007L) -#define MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT _HRESULT_TYPEDEF_(0x80097008L) -#define MSSIPOTF_E_TABLES_OVERLAP _HRESULT_TYPEDEF_(0x80097009L) -#define MSSIPOTF_E_TABLE_PADBYTES _HRESULT_TYPEDEF_(0x8009700AL) -#define MSSIPOTF_E_FILETOOSMALL _HRESULT_TYPEDEF_(0x8009700BL) -#define MSSIPOTF_E_TABLE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700CL) -#define MSSIPOTF_E_FILE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700DL) -#define MSSIPOTF_E_FAILED_POLICY _HRESULT_TYPEDEF_(0x80097010L) -#define MSSIPOTF_E_FAILED_HINTS_CHECK _HRESULT_TYPEDEF_(0x80097011L) -#define MSSIPOTF_E_NOT_OPENTYPE _HRESULT_TYPEDEF_(0x80097012L) -#define MSSIPOTF_E_FILE _HRESULT_TYPEDEF_(0x80097013L) -#define MSSIPOTF_E_CRYPT _HRESULT_TYPEDEF_(0x80097014L) -#define MSSIPOTF_E_BADVERSION _HRESULT_TYPEDEF_(0x80097015L) -#define MSSIPOTF_E_DSIG_STRUCTURE _HRESULT_TYPEDEF_(0x80097016L) -#define MSSIPOTF_E_PCONST_CHECK _HRESULT_TYPEDEF_(0x80097017L) -#define MSSIPOTF_E_STRUCTURE _HRESULT_TYPEDEF_(0x80097018L) -#define NTE_OP_OK 0 -#define TRUST_E_PROVIDER_UNKNOWN _HRESULT_TYPEDEF_(0x800B0001L) -#define TRUST_E_ACTION_UNKNOWN _HRESULT_TYPEDEF_(0x800B0002L) -#define TRUST_E_SUBJECT_FORM_UNKNOWN _HRESULT_TYPEDEF_(0x800B0003L) -#define TRUST_E_SUBJECT_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800B0004L) -#define DIGSIG_E_ENCODE _HRESULT_TYPEDEF_(0x800B0005L) -#define DIGSIG_E_DECODE _HRESULT_TYPEDEF_(0x800B0006L) -#define DIGSIG_E_EXTENSIBILITY _HRESULT_TYPEDEF_(0x800B0007L) -#define DIGSIG_E_CRYPTO _HRESULT_TYPEDEF_(0x800B0008L) -#define PERSIST_E_SIZEDEFINITE _HRESULT_TYPEDEF_(0x800B0009L) -#define PERSIST_E_SIZEINDEFINITE _HRESULT_TYPEDEF_(0x800B000AL) -#define PERSIST_E_NOTSELFSIZING _HRESULT_TYPEDEF_(0x800B000BL) -#define TRUST_E_NOSIGNATURE _HRESULT_TYPEDEF_(0x800B0100L) -#define CERT_E_EXPIRED _HRESULT_TYPEDEF_(0x800B0101L) -#define CERT_E_VALIDITYPERIODNESTING _HRESULT_TYPEDEF_(0x800B0102L) -#define CERT_E_ROLE _HRESULT_TYPEDEF_(0x800B0103L) -#define CERT_E_PATHLENCONST _HRESULT_TYPEDEF_(0x800B0104L) -#define CERT_E_CRITICAL _HRESULT_TYPEDEF_(0x800B0105L) -#define CERT_E_PURPOSE _HRESULT_TYPEDEF_(0x800B0106L) -#define CERT_E_ISSUERCHAINING _HRESULT_TYPEDEF_(0x800B0107L) -#define CERT_E_MALFORMED _HRESULT_TYPEDEF_(0x800B0108L) -#define CERT_E_UNTRUSTEDROOT _HRESULT_TYPEDEF_(0x800B0109L) -#define CERT_E_CHAINING _HRESULT_TYPEDEF_(0x800B010AL) -#define TRUST_E_FAIL _HRESULT_TYPEDEF_(0x800B010BL) -#define CERT_E_REVOKED _HRESULT_TYPEDEF_(0x800B010CL) -#define CERT_E_UNTRUSTEDTESTROOT _HRESULT_TYPEDEF_(0x800B010DL) -#define CERT_E_REVOCATION_FAILURE _HRESULT_TYPEDEF_(0x800B010EL) -#define CERT_E_CN_NO_MATCH _HRESULT_TYPEDEF_(0x800B010FL) -#define CERT_E_WRONG_USAGE _HRESULT_TYPEDEF_(0x800B0110L) -#define TRUST_E_EXPLICIT_DISTRUST _HRESULT_TYPEDEF_(0x800B0111L) -#define CERT_E_UNTRUSTEDCA _HRESULT_TYPEDEF_(0x800B0112L) -#define CERT_E_INVALID_POLICY _HRESULT_TYPEDEF_(0x800B0113L) -#define CERT_E_INVALID_NAME _HRESULT_TYPEDEF_(0x800B0114L) -#define HRESULT_FROM_SETUPAPI(x) ((((x) & (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR))==(APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR)) ? ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_SETUPAPI << 16) | 0x80000000)) : HRESULT_FROM_WIN32(x)) -#define SPAPI_E_EXPECTED_SECTION_NAME _HRESULT_TYPEDEF_(0x800F0000L) -#define SPAPI_E_BAD_SECTION_NAME_LINE _HRESULT_TYPEDEF_(0x800F0001L) -#define SPAPI_E_SECTION_NAME_TOO_LONG _HRESULT_TYPEDEF_(0x800F0002L) -#define SPAPI_E_GENERAL_SYNTAX _HRESULT_TYPEDEF_(0x800F0003L) -#define SPAPI_E_WRONG_INF_STYLE _HRESULT_TYPEDEF_(0x800F0100L) -#define SPAPI_E_SECTION_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0101L) -#define SPAPI_E_LINE_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0102L) -#define SPAPI_E_NO_BACKUP _HRESULT_TYPEDEF_(0x800F0103L) -#define SPAPI_E_NO_ASSOCIATED_CLASS _HRESULT_TYPEDEF_(0x800F0200L) -#define SPAPI_E_CLASS_MISMATCH _HRESULT_TYPEDEF_(0x800F0201L) -#define SPAPI_E_DUPLICATE_FOUND _HRESULT_TYPEDEF_(0x800F0202L) -#define SPAPI_E_NO_DRIVER_SELECTED _HRESULT_TYPEDEF_(0x800F0203L) -#define SPAPI_E_KEY_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x800F0204L) -#define SPAPI_E_INVALID_DEVINST_NAME _HRESULT_TYPEDEF_(0x800F0205L) -#define SPAPI_E_INVALID_CLASS _HRESULT_TYPEDEF_(0x800F0206L) -#define SPAPI_E_DEVINST_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x800F0207L) -#define SPAPI_E_DEVINFO_NOT_REGISTERED _HRESULT_TYPEDEF_(0x800F0208L) -#define SPAPI_E_INVALID_REG_PROPERTY _HRESULT_TYPEDEF_(0x800F0209L) -#define SPAPI_E_NO_INF _HRESULT_TYPEDEF_(0x800F020AL) -#define SPAPI_E_NO_SUCH_DEVINST _HRESULT_TYPEDEF_(0x800F020BL) -#define SPAPI_E_CANT_LOAD_CLASS_ICON _HRESULT_TYPEDEF_(0x800F020CL) -#define SPAPI_E_INVALID_CLASS_INSTALLER _HRESULT_TYPEDEF_(0x800F020DL) -#define SPAPI_E_DI_DO_DEFAULT _HRESULT_TYPEDEF_(0x800F020EL) -#define SPAPI_E_DI_NOFILECOPY _HRESULT_TYPEDEF_(0x800F020FL) -#define SPAPI_E_INVALID_HWPROFILE _HRESULT_TYPEDEF_(0x800F0210L) -#define SPAPI_E_NO_DEVICE_SELECTED _HRESULT_TYPEDEF_(0x800F0211L) -#define SPAPI_E_DEVINFO_LIST_LOCKED _HRESULT_TYPEDEF_(0x800F0212L) -#define SPAPI_E_DEVINFO_DATA_LOCKED _HRESULT_TYPEDEF_(0x800F0213L) -#define SPAPI_E_DI_BAD_PATH _HRESULT_TYPEDEF_(0x800F0214L) -#define SPAPI_E_NO_CLASSINSTALL_PARAMS _HRESULT_TYPEDEF_(0x800F0215L) -#define SPAPI_E_FILEQUEUE_LOCKED _HRESULT_TYPEDEF_(0x800F0216L) -#define SPAPI_E_BAD_SERVICE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F0217L) -#define SPAPI_E_NO_CLASS_DRIVER_LIST _HRESULT_TYPEDEF_(0x800F0218L) -#define SPAPI_E_NO_ASSOCIATED_SERVICE _HRESULT_TYPEDEF_(0x800F0219L) -#define SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F021AL) -#define SPAPI_E_DEVICE_INTERFACE_ACTIVE _HRESULT_TYPEDEF_(0x800F021BL) -#define SPAPI_E_DEVICE_INTERFACE_REMOVED _HRESULT_TYPEDEF_(0x800F021CL) -#define SPAPI_E_BAD_INTERFACE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F021DL) -#define SPAPI_E_NO_SUCH_INTERFACE_CLASS _HRESULT_TYPEDEF_(0x800F021EL) -#define SPAPI_E_INVALID_REFERENCE_STRING _HRESULT_TYPEDEF_(0x800F021FL) -#define SPAPI_E_INVALID_MACHINENAME _HRESULT_TYPEDEF_(0x800F0220L) -#define SPAPI_E_REMOTE_COMM_FAILURE _HRESULT_TYPEDEF_(0x800F0221L) -#define SPAPI_E_MACHINE_UNAVAILABLE _HRESULT_TYPEDEF_(0x800F0222L) -#define SPAPI_E_NO_CONFIGMGR_SERVICES _HRESULT_TYPEDEF_(0x800F0223L) -#define SPAPI_E_INVALID_PROPPAGE_PROVIDER _HRESULT_TYPEDEF_(0x800F0224L) -#define SPAPI_E_NO_SUCH_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F0225L) -#define SPAPI_E_DI_POSTPROCESSING_REQUIRED _HRESULT_TYPEDEF_(0x800F0226L) -#define SPAPI_E_INVALID_COINSTALLER _HRESULT_TYPEDEF_(0x800F0227L) -#define SPAPI_E_NO_COMPAT_DRIVERS _HRESULT_TYPEDEF_(0x800F0228L) -#define SPAPI_E_NO_DEVICE_ICON _HRESULT_TYPEDEF_(0x800F0229L) -#define SPAPI_E_INVALID_INF_LOGCONFIG _HRESULT_TYPEDEF_(0x800F022AL) -#define SPAPI_E_DI_DONT_INSTALL _HRESULT_TYPEDEF_(0x800F022BL) -#define SPAPI_E_INVALID_FILTER_DRIVER _HRESULT_TYPEDEF_(0x800F022CL) -#define SPAPI_E_NON_WINDOWS_NT_DRIVER _HRESULT_TYPEDEF_(0x800F022DL) -#define SPAPI_E_NON_WINDOWS_DRIVER _HRESULT_TYPEDEF_(0x800F022EL) -#define SPAPI_E_NO_CATALOG_FOR_OEM_INF _HRESULT_TYPEDEF_(0x800F022FL) -#define SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE _HRESULT_TYPEDEF_(0x800F0230L) -#define SPAPI_E_NOT_DISABLEABLE _HRESULT_TYPEDEF_(0x800F0231L) -#define SPAPI_E_CANT_REMOVE_DEVINST _HRESULT_TYPEDEF_(0x800F0232L) -#define SPAPI_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x800F0233L) -#define SPAPI_E_DRIVER_NONNATIVE _HRESULT_TYPEDEF_(0x800F0234L) -#define SPAPI_E_IN_WOW64 _HRESULT_TYPEDEF_(0x800F0235L) -#define SPAPI_E_SET_SYSTEM_RESTORE_POINT _HRESULT_TYPEDEF_(0x800F0236L) -#define SPAPI_E_INCORRECTLY_COPIED_INF _HRESULT_TYPEDEF_(0x800F0237L) -#define SPAPI_E_SCE_DISABLED _HRESULT_TYPEDEF_(0x800F0238L) -#define SPAPI_E_UNKNOWN_EXCEPTION _HRESULT_TYPEDEF_(0x800F0239L) -#define SPAPI_E_PNP_REGISTRY_ERROR _HRESULT_TYPEDEF_(0x800F023AL) -#define SPAPI_E_REMOTE_REQUEST_UNSUPPORTED _HRESULT_TYPEDEF_(0x800F023BL) -#define SPAPI_E_NOT_AN_INSTALLED_OEM_INF _HRESULT_TYPEDEF_(0x800F023CL) -#define SPAPI_E_INF_IN_USE_BY_DEVICES _HRESULT_TYPEDEF_(0x800F023DL) -#define SPAPI_E_DI_FUNCTION_OBSOLETE _HRESULT_TYPEDEF_(0x800F023EL) -#define SPAPI_E_NO_AUTHENTICODE_CATALOG _HRESULT_TYPEDEF_(0x800F023FL) -#define SPAPI_E_AUTHENTICODE_DISALLOWED _HRESULT_TYPEDEF_(0x800F0240L) -#define SPAPI_E_AUTHENTICODE_TRUSTED_PUBLISHER _HRESULT_TYPEDEF_(0x800F0241L) -#define SPAPI_E_AUTHENTICODE_TRUST_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x800F0242L) -#define SPAPI_E_AUTHENTICODE_PUBLISHER_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800F0243L) -#define SPAPI_E_SIGNATURE_OSATTRIBUTE_MISMATCH _HRESULT_TYPEDEF_(0x800F0244L) -#define SPAPI_E_ONLY_VALIDATE_VIA_AUTHENTICODE _HRESULT_TYPEDEF_(0x800F0245L) -#define SPAPI_E_UNRECOVERABLE_STACK_OVERFLOW _HRESULT_TYPEDEF_(0x800F0300L) -#define SPAPI_E_ERROR_NOT_INSTALLED _HRESULT_TYPEDEF_(0x800F1000L) -#define SCARD_S_SUCCESS NO_ERROR -#define SCARD_F_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80100001L) -#define SCARD_E_CANCELLED _HRESULT_TYPEDEF_(0x80100002L) -#define SCARD_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80100003L) -#define SCARD_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80100004L) -#define SCARD_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x80100005L) -#define SCARD_E_NO_MEMORY _HRESULT_TYPEDEF_(0x80100006L) -#define SCARD_F_WAITED_TOO_LONG _HRESULT_TYPEDEF_(0x80100007L) -#define SCARD_E_INSUFFICIENT_BUFFER _HRESULT_TYPEDEF_(0x80100008L) -#define SCARD_E_UNKNOWN_READER _HRESULT_TYPEDEF_(0x80100009L) -#define SCARD_E_TIMEOUT _HRESULT_TYPEDEF_(0x8010000AL) -#define SCARD_E_SHARING_VIOLATION _HRESULT_TYPEDEF_(0x8010000BL) -#define SCARD_E_NO_SMARTCARD _HRESULT_TYPEDEF_(0x8010000CL) -#define SCARD_E_UNKNOWN_CARD _HRESULT_TYPEDEF_(0x8010000DL) -#define SCARD_E_CANT_DISPOSE _HRESULT_TYPEDEF_(0x8010000EL) -#define SCARD_E_PROTO_MISMATCH _HRESULT_TYPEDEF_(0x8010000FL) -#define SCARD_E_NOT_READY _HRESULT_TYPEDEF_(0x80100010L) -#define SCARD_E_INVALID_VALUE _HRESULT_TYPEDEF_(0x80100011L) -#define SCARD_E_SYSTEM_CANCELLED _HRESULT_TYPEDEF_(0x80100012L) -#define SCARD_F_COMM_ERROR _HRESULT_TYPEDEF_(0x80100013L) -#define SCARD_F_UNKNOWN_ERROR _HRESULT_TYPEDEF_(0x80100014L) -#define SCARD_E_INVALID_ATR _HRESULT_TYPEDEF_(0x80100015L) -#define SCARD_E_NOT_TRANSACTED _HRESULT_TYPEDEF_(0x80100016L) -#define SCARD_E_READER_UNAVAILABLE _HRESULT_TYPEDEF_(0x80100017L) -#define SCARD_P_SHUTDOWN _HRESULT_TYPEDEF_(0x80100018L) -#define SCARD_E_PCI_TOO_SMALL _HRESULT_TYPEDEF_(0x80100019L) -#define SCARD_E_READER_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001AL) -#define SCARD_E_DUPLICATE_READER _HRESULT_TYPEDEF_(0x8010001BL) -#define SCARD_E_CARD_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001CL) -#define SCARD_E_NO_SERVICE _HRESULT_TYPEDEF_(0x8010001DL) -#define SCARD_E_SERVICE_STOPPED _HRESULT_TYPEDEF_(0x8010001EL) -#define SCARD_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8010001FL) -#define SCARD_E_ICC_INSTALLATION _HRESULT_TYPEDEF_(0x80100020L) -#define SCARD_E_ICC_CREATEORDER _HRESULT_TYPEDEF_(0x80100021L) -#define SCARD_E_UNSUPPORTED_FEATURE _HRESULT_TYPEDEF_(0x80100022L) -#define SCARD_E_DIR_NOT_FOUND _HRESULT_TYPEDEF_(0x80100023L) -#define SCARD_E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80100024L) -#define SCARD_E_NO_DIR _HRESULT_TYPEDEF_(0x80100025L) -#define SCARD_E_NO_FILE _HRESULT_TYPEDEF_(0x80100026L) -#define SCARD_E_NO_ACCESS _HRESULT_TYPEDEF_(0x80100027L) -#define SCARD_E_WRITE_TOO_MANY _HRESULT_TYPEDEF_(0x80100028L) -#define SCARD_E_BAD_SEEK _HRESULT_TYPEDEF_(0x80100029L) -#define SCARD_E_INVALID_CHV _HRESULT_TYPEDEF_(0x8010002AL) -#define SCARD_E_UNKNOWN_RES_MNG _HRESULT_TYPEDEF_(0x8010002BL) -#define SCARD_E_NO_SUCH_CERTIFICATE _HRESULT_TYPEDEF_(0x8010002CL) -#define SCARD_E_CERTIFICATE_UNAVAILABLE _HRESULT_TYPEDEF_(0x8010002DL) -#define SCARD_E_NO_READERS_AVAILABLE _HRESULT_TYPEDEF_(0x8010002EL) -#define SCARD_E_COMM_DATA_LOST _HRESULT_TYPEDEF_(0x8010002FL) -#define SCARD_E_NO_KEY_CONTAINER _HRESULT_TYPEDEF_(0x80100030L) -#define SCARD_E_SERVER_TOO_BUSY _HRESULT_TYPEDEF_(0x80100031L) -#define SCARD_W_UNSUPPORTED_CARD _HRESULT_TYPEDEF_(0x80100065L) -#define SCARD_W_UNRESPONSIVE_CARD _HRESULT_TYPEDEF_(0x80100066L) -#define SCARD_W_UNPOWERED_CARD _HRESULT_TYPEDEF_(0x80100067L) -#define SCARD_W_RESET_CARD _HRESULT_TYPEDEF_(0x80100068L) -#define SCARD_W_REMOVED_CARD _HRESULT_TYPEDEF_(0x80100069L) -#define SCARD_W_SECURITY_VIOLATION _HRESULT_TYPEDEF_(0x8010006AL) -#define SCARD_W_WRONG_CHV _HRESULT_TYPEDEF_(0x8010006BL) -#define SCARD_W_CHV_BLOCKED _HRESULT_TYPEDEF_(0x8010006CL) -#define SCARD_W_EOF _HRESULT_TYPEDEF_(0x8010006DL) -#define SCARD_W_CANCELLED_BY_USER _HRESULT_TYPEDEF_(0x8010006EL) -#define SCARD_W_CARD_NOT_AUTHENTICATED _HRESULT_TYPEDEF_(0x8010006FL) -#define COMADMIN_E_OBJECTERRORS _HRESULT_TYPEDEF_(0x80110401L) -#define COMADMIN_E_OBJECTINVALID _HRESULT_TYPEDEF_(0x80110402L) -#define COMADMIN_E_KEYMISSING _HRESULT_TYPEDEF_(0x80110403L) -#define COMADMIN_E_ALREADYINSTALLED _HRESULT_TYPEDEF_(0x80110404L) -#define COMADMIN_E_APP_FILE_WRITEFAIL _HRESULT_TYPEDEF_(0x80110407L) -#define COMADMIN_E_APP_FILE_READFAIL _HRESULT_TYPEDEF_(0x80110408L) -#define COMADMIN_E_APP_FILE_VERSION _HRESULT_TYPEDEF_(0x80110409L) -#define COMADMIN_E_BADPATH _HRESULT_TYPEDEF_(0x8011040AL) -#define COMADMIN_E_APPLICATIONEXISTS _HRESULT_TYPEDEF_(0x8011040BL) -#define COMADMIN_E_ROLEEXISTS _HRESULT_TYPEDEF_(0x8011040CL) -#define COMADMIN_E_CANTCOPYFILE _HRESULT_TYPEDEF_(0x8011040DL) -#define COMADMIN_E_NOUSER _HRESULT_TYPEDEF_(0x8011040FL) -#define COMADMIN_E_INVALIDUSERIDS _HRESULT_TYPEDEF_(0x80110410L) -#define COMADMIN_E_NOREGISTRYCLSID _HRESULT_TYPEDEF_(0x80110411L) -#define COMADMIN_E_BADREGISTRYPROGID _HRESULT_TYPEDEF_(0x80110412L) -#define COMADMIN_E_AUTHENTICATIONLEVEL _HRESULT_TYPEDEF_(0x80110413L) -#define COMADMIN_E_USERPASSWDNOTVALID _HRESULT_TYPEDEF_(0x80110414L) -#define COMADMIN_E_CLSIDORIIDMISMATCH _HRESULT_TYPEDEF_(0x80110418L) -#define COMADMIN_E_REMOTEINTERFACE _HRESULT_TYPEDEF_(0x80110419L) -#define COMADMIN_E_DLLREGISTERSERVER _HRESULT_TYPEDEF_(0x8011041AL) -#define COMADMIN_E_NOSERVERSHARE _HRESULT_TYPEDEF_(0x8011041BL) -#define COMADMIN_E_DLLLOADFAILED _HRESULT_TYPEDEF_(0x8011041DL) -#define COMADMIN_E_BADREGISTRYLIBID _HRESULT_TYPEDEF_(0x8011041EL) -#define COMADMIN_E_APPDIRNOTFOUND _HRESULT_TYPEDEF_(0x8011041FL) -#define COMADMIN_E_REGISTRARFAILED _HRESULT_TYPEDEF_(0x80110423L) -#define COMADMIN_E_COMPFILE_DOESNOTEXIST _HRESULT_TYPEDEF_(0x80110424L) -#define COMADMIN_E_COMPFILE_LOADDLLFAIL _HRESULT_TYPEDEF_(0x80110425L) -#define COMADMIN_E_COMPFILE_GETCLASSOBJ _HRESULT_TYPEDEF_(0x80110426L) -#define COMADMIN_E_COMPFILE_CLASSNOTAVAIL _HRESULT_TYPEDEF_(0x80110427L) -#define COMADMIN_E_COMPFILE_BADTLB _HRESULT_TYPEDEF_(0x80110428L) -#define COMADMIN_E_COMPFILE_NOTINSTALLABLE _HRESULT_TYPEDEF_(0x80110429L) -#define COMADMIN_E_NOTCHANGEABLE _HRESULT_TYPEDEF_(0x8011042AL) -#define COMADMIN_E_NOTDELETEABLE _HRESULT_TYPEDEF_(0x8011042BL) -#define COMADMIN_E_SESSION _HRESULT_TYPEDEF_(0x8011042CL) -#define COMADMIN_E_COMP_MOVE_LOCKED _HRESULT_TYPEDEF_(0x8011042DL) -#define COMADMIN_E_COMP_MOVE_BAD_DEST _HRESULT_TYPEDEF_(0x8011042EL) -#define COMADMIN_E_REGISTERTLB _HRESULT_TYPEDEF_(0x80110430L) -#define COMADMIN_E_SYSTEMAPP _HRESULT_TYPEDEF_(0x80110433L) -#define COMADMIN_E_COMPFILE_NOREGISTRAR _HRESULT_TYPEDEF_(0x80110434L) -#define COMADMIN_E_COREQCOMPINSTALLED _HRESULT_TYPEDEF_(0x80110435L) -#define COMADMIN_E_SERVICENOTINSTALLED _HRESULT_TYPEDEF_(0x80110436L) -#define COMADMIN_E_PROPERTYSAVEFAILED _HRESULT_TYPEDEF_(0x80110437L) -#define COMADMIN_E_OBJECTEXISTS _HRESULT_TYPEDEF_(0x80110438L) -#define COMADMIN_E_COMPONENTEXISTS _HRESULT_TYPEDEF_(0x80110439L) -#define COMADMIN_E_REGFILE_CORRUPT _HRESULT_TYPEDEF_(0x8011043BL) -#define COMADMIN_E_PROPERTY_OVERFLOW _HRESULT_TYPEDEF_(0x8011043CL) -#define COMADMIN_E_NOTINREGISTRY _HRESULT_TYPEDEF_(0x8011043EL) -#define COMADMIN_E_OBJECTNOTPOOLABLE _HRESULT_TYPEDEF_(0x8011043FL) -#define COMADMIN_E_APPLID_MATCHES_CLSID _HRESULT_TYPEDEF_(0x80110446L) -#define COMADMIN_E_ROLE_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110447L) -#define COMADMIN_E_START_APP_NEEDS_COMPONENTS _HRESULT_TYPEDEF_(0x80110448L) -#define COMADMIN_E_REQUIRES_DIFFERENT_PLATFORM _HRESULT_TYPEDEF_(0x80110449L) -#define COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY _HRESULT_TYPEDEF_(0x8011044AL) -#define COMADMIN_E_CAN_NOT_START_APP _HRESULT_TYPEDEF_(0x8011044BL) -#define COMADMIN_E_CAN_NOT_EXPORT_SYS_APP _HRESULT_TYPEDEF_(0x8011044CL) -#define COMADMIN_E_CANT_SUBSCRIBE_TO_COMPONENT _HRESULT_TYPEDEF_(0x8011044DL) -#define COMADMIN_E_EVENTCLASS_CANT_BE_SUBSCRIBER _HRESULT_TYPEDEF_(0x8011044EL) -#define COMADMIN_E_LIB_APP_PROXY_INCOMPATIBLE _HRESULT_TYPEDEF_(0x8011044FL) -#define COMADMIN_E_BASE_PARTITION_ONLY _HRESULT_TYPEDEF_(0x80110450L) -#define COMADMIN_E_START_APP_DISABLED _HRESULT_TYPEDEF_(0x80110451L) -#define COMADMIN_E_CAT_DUPLICATE_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110457L) -#define COMADMIN_E_CAT_INVALID_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110458L) -#define COMADMIN_E_CAT_PARTITION_IN_USE _HRESULT_TYPEDEF_(0x80110459L) -#define COMADMIN_E_FILE_PARTITION_DUPLICATE_FILES _HRESULT_TYPEDEF_(0x8011045AL) -#define COMADMIN_E_CAT_IMPORTED_COMPONENTS_NOT_ALLOWED _HRESULT_TYPEDEF_(0x8011045BL) -#define COMADMIN_E_AMBIGUOUS_APPLICATION_NAME _HRESULT_TYPEDEF_(0x8011045CL) -#define COMADMIN_E_AMBIGUOUS_PARTITION_NAME _HRESULT_TYPEDEF_(0x8011045DL) -#define COMADMIN_E_REGDB_NOTINITIALIZED _HRESULT_TYPEDEF_(0x80110472L) -#define COMADMIN_E_REGDB_NOTOPEN _HRESULT_TYPEDEF_(0x80110473L) -#define COMADMIN_E_REGDB_SYSTEMERR _HRESULT_TYPEDEF_(0x80110474L) -#define COMADMIN_E_REGDB_ALREADYRUNNING _HRESULT_TYPEDEF_(0x80110475L) -#define COMADMIN_E_MIG_VERSIONNOTSUPPORTED _HRESULT_TYPEDEF_(0x80110480L) -#define COMADMIN_E_MIG_SCHEMANOTFOUND _HRESULT_TYPEDEF_(0x80110481L) -#define COMADMIN_E_CAT_BITNESSMISMATCH _HRESULT_TYPEDEF_(0x80110482L) -#define COMADMIN_E_CAT_UNACCEPTABLEBITNESS _HRESULT_TYPEDEF_(0x80110483L) -#define COMADMIN_E_CAT_WRONGAPPBITNESS _HRESULT_TYPEDEF_(0x80110484L) -#define COMADMIN_E_CAT_PAUSE_RESUME_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80110485L) -#define COMADMIN_E_CAT_SERVERFAULT _HRESULT_TYPEDEF_(0x80110486L) -#define COMQC_E_APPLICATION_NOT_QUEUED _HRESULT_TYPEDEF_(0x80110600L) -#define COMQC_E_NO_QUEUEABLE_INTERFACES _HRESULT_TYPEDEF_(0x80110601L) -#define COMQC_E_QUEUING_SERVICE_NOT_AVAILABLE _HRESULT_TYPEDEF_(0x80110602L) -#define COMQC_E_NO_IPERSISTSTREAM _HRESULT_TYPEDEF_(0x80110603L) -#define COMQC_E_BAD_MESSAGE _HRESULT_TYPEDEF_(0x80110604L) -#define COMQC_E_UNAUTHENTICATED _HRESULT_TYPEDEF_(0x80110605L) -#define COMQC_E_UNTRUSTED_ENQUEUER _HRESULT_TYPEDEF_(0x80110606L) -#define MSDTC_E_DUPLICATE_RESOURCE _HRESULT_TYPEDEF_(0x80110701L) -#define COMADMIN_E_OBJECT_PARENT_MISSING _HRESULT_TYPEDEF_(0x80110808L) -#define COMADMIN_E_OBJECT_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110809L) -#define COMADMIN_E_APP_NOT_RUNNING _HRESULT_TYPEDEF_(0x8011080AL) -#define COMADMIN_E_INVALID_PARTITION _HRESULT_TYPEDEF_(0x8011080BL) -#define COMADMIN_E_SVCAPP_NOT_POOLABLE_OR_RECYCLABLE _HRESULT_TYPEDEF_(0x8011080DL) -#define COMADMIN_E_USER_IN_SET _HRESULT_TYPEDEF_(0x8011080EL) -#define COMADMIN_E_CANTRECYCLELIBRARYAPPS _HRESULT_TYPEDEF_(0x8011080FL) -#define COMADMIN_E_CANTRECYCLESERVICEAPPS _HRESULT_TYPEDEF_(0x80110811L) -#define COMADMIN_E_PROCESSALREADYRECYCLED _HRESULT_TYPEDEF_(0x80110812L) -#define COMADMIN_E_PAUSEDPROCESSMAYNOTBERECYCLED _HRESULT_TYPEDEF_(0x80110813L) -#define COMADMIN_E_CANTMAKEINPROCSERVICE _HRESULT_TYPEDEF_(0x80110814L) -#define COMADMIN_E_PROGIDINUSEBYCLSID _HRESULT_TYPEDEF_(0x80110815L) -#define COMADMIN_E_DEFAULT_PARTITION_NOT_IN_SET _HRESULT_TYPEDEF_(0x80110816L) -#define COMADMIN_E_RECYCLEDPROCESSMAYNOTBEPAUSED _HRESULT_TYPEDEF_(0x80110817L) -#define COMADMIN_E_PARTITION_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110818L) -#define COMADMIN_E_PARTITION_MSI_ONLY _HRESULT_TYPEDEF_(0x80110819L) -#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_1_0_FORMAT _HRESULT_TYPEDEF_(0x8011081AL) -#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_NONBASE_PARTITIONS _HRESULT_TYPEDEF_(0x8011081BL) -#define COMADMIN_E_COMP_MOVE_SOURCE _HRESULT_TYPEDEF_(0x8011081CL) -#define COMADMIN_E_COMP_MOVE_DEST _HRESULT_TYPEDEF_(0x8011081DL) -#define COMADMIN_E_COMP_MOVE_PRIVATE _HRESULT_TYPEDEF_(0x8011081EL) -#define COMADMIN_E_BASEPARTITION_REQUIRED_IN_SET _HRESULT_TYPEDEF_(0x8011081FL) -#define COMADMIN_E_CANNOT_ALIAS_EVENTCLASS _HRESULT_TYPEDEF_(0x80110820L) -#define COMADMIN_E_PRIVATE_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110821L) -#define COMADMIN_E_SAFERINVALID _HRESULT_TYPEDEF_(0x80110822L) -#define COMADMIN_E_REGISTRY_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110823L) -#define COMADMIN_E_PARTITIONS_DISABLED _HRESULT_TYPEDEF_(0x80110824L) -#endif /* _WINERROR_ */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINERROR_ +#define _WINERROR_ + +#define FACILITY_WINDOWSUPDATE 36 +#define FACILITY_WINDOWS_CE 24 +#define FACILITY_WINDOWS 8 +#define FACILITY_URT 19 +#define FACILITY_UMI 22 +#define FACILITY_SXS 23 +#define FACILITY_STORAGE 3 +#define FACILITY_STATE_MANAGEMENT 34 +#define FACILITY_SSPI 9 +#define FACILITY_SCARD 16 +#define FACILITY_SETUPAPI 15 +#define FACILITY_SECURITY 9 +#define FACILITY_RPC 1 +#define FACILITY_WIN32 7 +#define FACILITY_CONTROL 10 +#define FACILITY_NULL 0 +#define FACILITY_METADIRECTORY 35 +#define FACILITY_MSMQ 14 +#define FACILITY_MEDIASERVER 13 +#define FACILITY_INTERNET 12 +#define FACILITY_ITF 4 +#define FACILITY_HTTP 25 +#define FACILITY_DPLAY 21 +#define FACILITY_DISPATCH 2 +#define FACILITY_DIRECTORYSERVICE 37 +#define FACILITY_CONFIGURATION 33 +#define FACILITY_COMPLUS 17 +#define FACILITY_CERT 11 +#define FACILITY_BACKGROUNDCOPY 32 +#define FACILITY_ACS 20 +#define FACILITY_AAF 18 +#define ERROR_SUCCESS 0L +#define NO_ERROR 0L +#define SEC_E_OK ((HRESULT)0x00000000L) +#define ERROR_INVALID_FUNCTION 1L +#define ERROR_FILE_NOT_FOUND 2L +#define ERROR_PATH_NOT_FOUND 3L +#define ERROR_TOO_MANY_OPEN_FILES 4L +#define ERROR_ACCESS_DENIED 5L +#define ERROR_INVALID_HANDLE 6L +#define ERROR_ARENA_TRASHED 7L +#define ERROR_NOT_ENOUGH_MEMORY 8L +#define ERROR_INVALID_BLOCK 9L +#define ERROR_BAD_ENVIRONMENT 10L +#define ERROR_BAD_FORMAT 11L +#define ERROR_INVALID_ACCESS 12L +#define ERROR_INVALID_DATA 13L +#define ERROR_OUTOFMEMORY 14L +#define ERROR_INVALID_DRIVE 15L +#define ERROR_CURRENT_DIRECTORY 16L +#define ERROR_NOT_SAME_DEVICE 17L +#define ERROR_NO_MORE_FILES 18L +#define ERROR_WRITE_PROTECT 19L +#define ERROR_BAD_UNIT 20L +#define ERROR_NOT_READY 21L +#define ERROR_BAD_COMMAND 22L +#define ERROR_CRC 23L +#define ERROR_BAD_LENGTH 24L +#define ERROR_SEEK 25L +#define ERROR_NOT_DOS_DISK 26L +#define ERROR_SECTOR_NOT_FOUND 27L +#define ERROR_OUT_OF_PAPER 28L +#define ERROR_WRITE_FAULT 29L +#define ERROR_READ_FAULT 30L +#define ERROR_GEN_FAILURE 31L +#define ERROR_SHARING_VIOLATION 32L +#define ERROR_LOCK_VIOLATION 33L +#define ERROR_WRONG_DISK 34L +#define ERROR_SHARING_BUFFER_EXCEEDED 36L +#define ERROR_HANDLE_EOF 38L +#define ERROR_HANDLE_DISK_FULL 39L +#define ERROR_NOT_SUPPORTED 50L +#define ERROR_REM_NOT_LIST 51L +#define ERROR_DUP_NAME 52L +#define ERROR_BAD_NETPATH 53L +#define ERROR_NETWORK_BUSY 54L +#define ERROR_DEV_NOT_EXIST 55L +#define ERROR_TOO_MANY_CMDS 56L +#define ERROR_ADAP_HDW_ERR 57L +#define ERROR_BAD_NET_RESP 58L +#define ERROR_UNEXP_NET_ERR 59L +#define ERROR_BAD_REM_ADAP 60L +#define ERROR_PRINTQ_FULL 61L +#define ERROR_NO_SPOOL_SPACE 62L +#define ERROR_PRINT_CANCELLED 63L +#define ERROR_NETNAME_DELETED 64L +#define ERROR_NETWORK_ACCESS_DENIED 65L +#define ERROR_BAD_DEV_TYPE 66L +#define ERROR_BAD_NET_NAME 67L +#define ERROR_TOO_MANY_NAMES 68L +#define ERROR_TOO_MANY_SESS 69L +#define ERROR_SHARING_PAUSED 70L +#define ERROR_REQ_NOT_ACCEP 71L +#define ERROR_REDIR_PAUSED 72L +#define ERROR_FILE_EXISTS 80L +#define ERROR_CANNOT_MAKE 82L +#define ERROR_FAIL_I24 83L +#define ERROR_OUT_OF_STRUCTURES 84L +#define ERROR_ALREADY_ASSIGNED 85L +#define ERROR_INVALID_PASSWORD 86L +#define ERROR_INVALID_PARAMETER 87L +#define ERROR_NET_WRITE_FAULT 88L +#define ERROR_NO_PROC_SLOTS 89L +#define ERROR_TOO_MANY_SEMAPHORES 100L +#define ERROR_EXCL_SEM_ALREADY_OWNED 101L +#define ERROR_SEM_IS_SET 102L +#define ERROR_TOO_MANY_SEM_REQUESTS 103L +#define ERROR_INVALID_AT_INTERRUPT_TIME 104L +#define ERROR_SEM_OWNER_DIED 105L +#define ERROR_SEM_USER_LIMIT 106L +#define ERROR_DISK_CHANGE 107L +#define ERROR_DRIVE_LOCKED 108L +#define ERROR_BROKEN_PIPE 109L +#define ERROR_OPEN_FAILED 110L +#define ERROR_BUFFER_OVERFLOW 111L +#define ERROR_DISK_FULL 112L +#define ERROR_NO_MORE_SEARCH_HANDLES 113L +#define ERROR_INVALID_TARGET_HANDLE 114L +#define ERROR_INVALID_CATEGORY 117L +#define ERROR_INVALID_VERIFY_SWITCH 118L +#define ERROR_BAD_DRIVER_LEVEL 119L +#define ERROR_CALL_NOT_IMPLEMENTED 120L +#define ERROR_SEM_TIMEOUT 121L +#define ERROR_INSUFFICIENT_BUFFER 122L +#define ERROR_INVALID_NAME 123L +#define ERROR_INVALID_LEVEL 124L +#define ERROR_NO_VOLUME_LABEL 125L +#define ERROR_MOD_NOT_FOUND 126L +#define ERROR_PROC_NOT_FOUND 127L +#define ERROR_WAIT_NO_CHILDREN 128L +#define ERROR_CHILD_NOT_COMPLETE 129L +#define ERROR_DIRECT_ACCESS_HANDLE 130L +#define ERROR_NEGATIVE_SEEK 131L +#define ERROR_SEEK_ON_DEVICE 132L +#define ERROR_IS_JOIN_TARGET 133L +#define ERROR_IS_JOINED 134L +#define ERROR_IS_SUBSTED 135L +#define ERROR_NOT_JOINED 136L +#define ERROR_NOT_SUBSTED 137L +#define ERROR_JOIN_TO_JOIN 138L +#define ERROR_SUBST_TO_SUBST 139L +#define ERROR_JOIN_TO_SUBST 140L +#define ERROR_SUBST_TO_JOIN 141L +#define ERROR_BUSY_DRIVE 142L +#define ERROR_SAME_DRIVE 143L +#define ERROR_DIR_NOT_ROOT 144L +#define ERROR_DIR_NOT_EMPTY 145L +#define ERROR_IS_SUBST_PATH 146L +#define ERROR_IS_JOIN_PATH 147L +#define ERROR_PATH_BUSY 148L +#define ERROR_IS_SUBST_TARGET 149L +#define ERROR_SYSTEM_TRACE 150L +#define ERROR_INVALID_EVENT_COUNT 151L +#define ERROR_TOO_MANY_MUXWAITERS 152L +#define ERROR_INVALID_LIST_FORMAT 153L +#define ERROR_LABEL_TOO_LONG 154L +#define ERROR_TOO_MANY_TCBS 155L +#define ERROR_SIGNAL_REFUSED 156L +#define ERROR_DISCARDED 157L +#define ERROR_NOT_LOCKED 158L +#define ERROR_BAD_THREADID_ADDR 159L +#define ERROR_BAD_ARGUMENTS 160L +#define ERROR_BAD_PATHNAME 161L +#define ERROR_SIGNAL_PENDING 162L +#define ERROR_MAX_THRDS_REACHED 164L +#define ERROR_LOCK_FAILED 167L +#define ERROR_BUSY 170L +#define ERROR_CANCEL_VIOLATION 173L +#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174L +#define ERROR_INVALID_SEGMENT_NUMBER 180L +#define ERROR_INVALID_ORDINAL 182L +#define ERROR_ALREADY_EXISTS 183L +#define ERROR_INVALID_FLAG_NUMBER 186L +#define ERROR_SEM_NOT_FOUND 187L +#define ERROR_INVALID_STARTING_CODESEG 188L +#define ERROR_INVALID_STACKSEG 189L +#define ERROR_INVALID_MODULETYPE 190L +#define ERROR_INVALID_EXE_SIGNATURE 191L +#define ERROR_EXE_MARKED_INVALID 192L +#define ERROR_BAD_EXE_FORMAT 193L +#define ERROR_ITERATED_DATA_EXCEEDS_64k 194L +#define ERROR_INVALID_MINALLOCSIZE 195L +#define ERROR_DYNLINK_FROM_INVALID_RING 196L +#define ERROR_IOPL_NOT_ENABLED 197L +#define ERROR_INVALID_SEGDPL 198L +#define ERROR_AUTODATASEG_EXCEEDS_64k 199L +#define ERROR_RING2SEG_MUST_BE_MOVABLE 200L +#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201L +#define ERROR_INFLOOP_IN_RELOC_CHAIN 202L +#define ERROR_ENVVAR_NOT_FOUND 203L +#define ERROR_NO_SIGNAL_SENT 205L +#define ERROR_FILENAME_EXCED_RANGE 206L +#define ERROR_RING2_STACK_IN_USE 207L +#define ERROR_META_EXPANSION_TOO_LONG 208L +#define ERROR_INVALID_SIGNAL_NUMBER 209L +#define ERROR_THREAD_1_INACTIVE 210L +#define ERROR_LOCKED 212L +#define ERROR_TOO_MANY_MODULES 214L +#define ERROR_NESTING_NOT_ALLOWED 215L +#define ERROR_EXE_MACHINE_TYPE_MISMATCH 216L +#define ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY 217L +#define ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY 218L +#define ERROR_BAD_PIPE 230L +#define ERROR_PIPE_BUSY 231L +#define ERROR_NO_DATA 232L +#define ERROR_PIPE_NOT_CONNECTED 233L +#define ERROR_MORE_DATA 234L +#define ERROR_VC_DISCONNECTED 240L +#define ERROR_INVALID_EA_NAME 254L +#define ERROR_EA_LIST_INCONSISTENT 255L +#define WAIT_TIMEOUT 258L +#define ERROR_NO_MORE_ITEMS 259L +#define ERROR_CANNOT_COPY 266L +#define ERROR_DIRECTORY 267L +#define ERROR_EAS_DIDNT_FIT 275L +#define ERROR_EA_FILE_CORRUPT 276L +#define ERROR_EA_TABLE_FULL 277L +#define ERROR_INVALID_EA_HANDLE 278L +#define ERROR_EAS_NOT_SUPPORTED 282L +#define ERROR_NOT_OWNER 288L +#define ERROR_TOO_MANY_POSTS 298L +#define ERROR_PARTIAL_COPY 299L +#define ERROR_OPLOCK_NOT_GRANTED 300L +#define ERROR_INVALID_OPLOCK_PROTOCOL 301L +#define ERROR_DISK_TOO_FRAGMENTED 302L +#define ERROR_DELETE_PENDING 303L +#define ERROR_MR_MID_NOT_FOUND 317L +#define ERROR_SCOPE_NOT_FOUND 318L +#define ERROR_INVALID_ADDRESS 487L +#define ERROR_ARITHMETIC_OVERFLOW 534L +#define ERROR_PIPE_CONNECTED 535L +#define ERROR_PIPE_LISTENING 536L +#define ERROR_EA_ACCESS_DENIED 994L +#define ERROR_OPERATION_ABORTED 995L +#define ERROR_IO_INCOMPLETE 996L +#define ERROR_IO_PENDING 997L +#define ERROR_NOACCESS 998L +#define ERROR_SWAPERROR 999L +#define ERROR_STACK_OVERFLOW 1001L +#define ERROR_INVALID_MESSAGE 1002L +#define ERROR_CAN_NOT_COMPLETE 1003L +#define ERROR_INVALID_FLAGS 1004L +#define ERROR_UNRECOGNIZED_VOLUME 1005L +#define ERROR_FILE_INVALID 1006L +#define ERROR_FULLSCREEN_MODE 1007L +#define ERROR_NO_TOKEN 1008L +#define ERROR_BADDB 1009L +#define ERROR_BADKEY 1010L +#define ERROR_CANTOPEN 1011L +#define ERROR_CANTREAD 1012L +#define ERROR_CANTWRITE 1013L +#define ERROR_REGISTRY_RECOVERED 1014L +#define ERROR_REGISTRY_CORRUPT 1015L +#define ERROR_REGISTRY_IO_FAILED 1016L +#define ERROR_NOT_REGISTRY_FILE 1017L +#define ERROR_KEY_DELETED 1018L +#define ERROR_NO_LOG_SPACE 1019L +#define ERROR_KEY_HAS_CHILDREN 1020L +#define ERROR_CHILD_MUST_BE_VOLATILE 1021L +#define ERROR_NOTIFY_ENUM_DIR 1022L +#define ERROR_DEPENDENT_SERVICES_RUNNING 1051L +#define ERROR_INVALID_SERVICE_CONTROL 1052L +#define ERROR_SERVICE_REQUEST_TIMEOUT 1053L +#define ERROR_SERVICE_NO_THREAD 1054L +#define ERROR_SERVICE_DATABASE_LOCKED 1055L +#define ERROR_SERVICE_ALREADY_RUNNING 1056L +#define ERROR_INVALID_SERVICE_ACCOUNT 1057L +#define ERROR_SERVICE_DISABLED 1058L +#define ERROR_CIRCULAR_DEPENDENCY 1059L +#define ERROR_SERVICE_DOES_NOT_EXIST 1060L +#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061L +#define ERROR_SERVICE_NOT_ACTIVE 1062L +#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063L +#define ERROR_EXCEPTION_IN_SERVICE 1064L +#define ERROR_DATABASE_DOES_NOT_EXIST 1065L +#define ERROR_SERVICE_SPECIFIC_ERROR 1066L +#define ERROR_PROCESS_ABORTED 1067L +#define ERROR_SERVICE_DEPENDENCY_FAIL 1068L +#define ERROR_SERVICE_LOGON_FAILED 1069L +#define ERROR_SERVICE_START_HANG 1070L +#define ERROR_INVALID_SERVICE_LOCK 1071L +#define ERROR_SERVICE_MARKED_FOR_DELETE 1072L +#define ERROR_SERVICE_EXISTS 1073L +#define ERROR_ALREADY_RUNNING_LKG 1074L +#define ERROR_SERVICE_DEPENDENCY_DELETED 1075L +#define ERROR_BOOT_ALREADY_ACCEPTED 1076L +#define ERROR_SERVICE_NEVER_STARTED 1077L +#define ERROR_DUPLICATE_SERVICE_NAME 1078L +#define ERROR_DIFFERENT_SERVICE_ACCOUNT 1079L +#define ERROR_CANNOT_DETECT_DRIVER_FAILURE 1080L +#define ERROR_CANNOT_DETECT_PROCESS_ABORT 1081L +#define ERROR_NO_RECOVERY_PROGRAM 1082L +#define ERROR_SERVICE_NOT_IN_EXE 1083L +#define ERROR_NOT_SAFEBOOT_SERVICE 1084L +#define ERROR_END_OF_MEDIA 1100L +#define ERROR_FILEMARK_DETECTED 1101L +#define ERROR_BEGINNING_OF_MEDIA 1102L +#define ERROR_SETMARK_DETECTED 1103L +#define ERROR_NO_DATA_DETECTED 1104L +#define ERROR_PARTITION_FAILURE 1105L +#define ERROR_INVALID_BLOCK_LENGTH 1106L +#define ERROR_DEVICE_NOT_PARTITIONED 1107L +#define ERROR_UNABLE_TO_LOCK_MEDIA 1108L +#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109L +#define ERROR_MEDIA_CHANGED 1110L +#define ERROR_BUS_RESET 1111L +#define ERROR_NO_MEDIA_IN_DRIVE 1112L +#define ERROR_NO_UNICODE_TRANSLATION 1113L +#define ERROR_DLL_INIT_FAILED 1114L +#define ERROR_SHUTDOWN_IN_PROGRESS 1115L +#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116L +#define ERROR_IO_DEVICE 1117L +#define ERROR_SERIAL_NO_DEVICE 1118L +#define ERROR_IRQ_BUSY 1119L +#define ERROR_MORE_WRITES 1120L +#define ERROR_COUNTER_TIMEOUT 1121L +#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122L +#define ERROR_FLOPPY_WRONG_CYLINDER 1123L +#define ERROR_FLOPPY_UNKNOWN_ERROR 1124L +#define ERROR_FLOPPY_BAD_REGISTERS 1125L +#define ERROR_DISK_RECALIBRATE_FAILED 1126L +#define ERROR_DISK_OPERATION_FAILED 1127L +#define ERROR_DISK_RESET_FAILED 1128L +#define ERROR_EOM_OVERFLOW 1129L +#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130L +#define ERROR_POSSIBLE_DEADLOCK 1131L +#define ERROR_MAPPED_ALIGNMENT 1132L +#define ERROR_SET_POWER_STATE_VETOED 1140L +#define ERROR_SET_POWER_STATE_FAILED 1141L +#define ERROR_TOO_MANY_LINKS 1142L +#define ERROR_OLD_WIN_VERSION 1150L +#define ERROR_APP_WRONG_OS 1151L +#define ERROR_SINGLE_INSTANCE_APP 1152L +#define ERROR_RMODE_APP 1153L +#define ERROR_INVALID_DLL 1154L +#define ERROR_NO_ASSOCIATION 1155L +#define ERROR_DDE_FAIL 1156L +#define ERROR_DLL_NOT_FOUND 1157L +#define ERROR_NO_MORE_USER_HANDLES 1158L +#define ERROR_MESSAGE_SYNC_ONLY 1159L +#define ERROR_SOURCE_ELEMENT_EMPTY 1160L +#define ERROR_DESTINATION_ELEMENT_FULL 1161L +#define ERROR_ILLEGAL_ELEMENT_ADDRESS 1162L +#define ERROR_MAGAZINE_NOT_PRESENT 1163L +#define ERROR_DEVICE_REINITIALIZATION_NEEDED 1164L +#define ERROR_DEVICE_REQUIRES_CLEANING 1165L +#define ERROR_DEVICE_DOOR_OPEN 1166L +#define ERROR_DEVICE_NOT_CONNECTED 1167L +#define ERROR_NOT_FOUND 1168L +#define ERROR_NO_MATCH 1169L +#define ERROR_SET_NOT_FOUND 1170L +#define ERROR_POINT_NOT_FOUND 1171L +#define ERROR_NO_TRACKING_SERVICE 1172L +#define ERROR_NO_VOLUME_ID 1173L +#define ERROR_UNABLE_TO_REMOVE_REPLACED 1175L +#define ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176L +#define ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 1177L +#define ERROR_JOURNAL_DELETE_IN_PROGRESS 1178L +#define ERROR_JOURNAL_NOT_ACTIVE 1179L +#define ERROR_POTENTIAL_FILE_FOUND 1180L +#define ERROR_JOURNAL_ENTRY_DELETED 1181L +#define ERROR_BAD_DEVICE 1200L +#define ERROR_CONNECTION_UNAVAIL 1201L +#define ERROR_DEVICE_ALREADY_REMEMBERED 1202L +#define ERROR_NO_NET_OR_BAD_PATH 1203L +#define ERROR_BAD_PROVIDER 1204L +#define ERROR_CANNOT_OPEN_PROFILE 1205L +#define ERROR_BAD_PROFILE 1206L +#define ERROR_NOT_CONTAINER 1207L +#define ERROR_EXTENDED_ERROR 1208L +#define ERROR_INVALID_GROUPNAME 1209L +#define ERROR_INVALID_COMPUTERNAME 1210L +#define ERROR_INVALID_EVENTNAME 1211L +#define ERROR_INVALID_DOMAINNAME 1212L +#define ERROR_INVALID_SERVICENAME 1213L +#define ERROR_INVALID_NETNAME 1214L +#define ERROR_INVALID_SHARENAME 1215L +#define ERROR_INVALID_PASSWORDNAME 1216L +#define ERROR_INVALID_MESSAGENAME 1217L +#define ERROR_INVALID_MESSAGEDEST 1218L +#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219L +#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220L +#define ERROR_DUP_DOMAINNAME 1221L +#define ERROR_NO_NETWORK 1222L +#define ERROR_CANCELLED 1223L +#define ERROR_USER_MAPPED_FILE 1224L +#define ERROR_CONNECTION_REFUSED 1225L +#define ERROR_GRACEFUL_DISCONNECT 1226L +#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227L +#define ERROR_ADDRESS_NOT_ASSOCIATED 1228L +#define ERROR_CONNECTION_INVALID 1229L +#define ERROR_CONNECTION_ACTIVE 1230L +#define ERROR_NETWORK_UNREACHABLE 1231L +#define ERROR_HOST_UNREACHABLE 1232L +#define ERROR_PROTOCOL_UNREACHABLE 1233L +#define ERROR_PORT_UNREACHABLE 1234L +#define ERROR_REQUEST_ABORTED 1235L +#define ERROR_CONNECTION_ABORTED 1236L +#define ERROR_RETRY 1237L +#define ERROR_CONNECTION_COUNT_LIMIT 1238L +#define ERROR_LOGIN_TIME_RESTRICTION 1239L +#define ERROR_LOGIN_WKSTA_RESTRICTION 1240L +#define ERROR_INCORRECT_ADDRESS 1241L +#define ERROR_ALREADY_REGISTERED 1242L +#define ERROR_SERVICE_NOT_FOUND 1243L +#define ERROR_NOT_AUTHENTICATED 1244L +#define ERROR_NOT_LOGGED_ON 1245L +#define ERROR_CONTINUE 1246L +#define ERROR_ALREADY_INITIALIZED 1247L +#define ERROR_NO_MORE_DEVICES 1248L +#define ERROR_NO_SUCH_SITE 1249L +#define ERROR_DOMAIN_CONTROLLER_EXISTS 1250L +#define ERROR_ONLY_IF_CONNECTED 1251L +#define ERROR_OVERRIDE_NOCHANGES 1252L +#define ERROR_BAD_USER_PROFILE 1253L +#define ERROR_NOT_SUPPORTED_ON_SBS 1254L +#define ERROR_SERVER_SHUTDOWN_IN_PROGRESS 1255L +#define ERROR_HOST_DOWN 1256L +#define ERROR_NON_ACCOUNT_SID 1257L +#define ERROR_NON_DOMAIN_SID 1258L +#define ERROR_APPHELP_BLOCK 1259L +#define ERROR_ACCESS_DISABLED_BY_POLICY 1260L +#define ERROR_REG_NAT_CONSUMPTION 1261L +#define ERROR_CSCSHARE_OFFLINE 1262L +#define ERROR_PKINIT_FAILURE 1263L +#define ERROR_SMARTCARD_SUBSYSTEM_FAILURE 1264L +#define ERROR_DOWNGRADE_DETECTED 1265L +#define ERROR_MACHINE_LOCKED 1271L +#define ERROR_CALLBACK_SUPPLIED_INVALID_DATA 1273L +#define ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED 1274L +#define ERROR_DRIVER_BLOCKED 1275L +#define ERROR_INVALID_IMPORT_OF_NON_DLL 1276L +#define ERROR_ACCESS_DISABLED_WEBBLADE 1277L +#define ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER 1278L +#define ERROR_RECOVERY_FAILURE 1279L +#define ERROR_ALREADY_FIBER 1280L +#define ERROR_ALREADY_THREAD 1281L +#define ERROR_STACK_BUFFER_OVERRUN 1282L +#define ERROR_PARAMETER_QUOTA_EXCEEDED 1283L +#define ERROR_DEBUGGER_INACTIVE 1284L +#define ERROR_DELAY_LOAD_FAILED 1285L +#define ERROR_VDM_DISALLOWED 1286L +#define ERROR_UNIDENTIFIED_ERROR 1287L +#define ERROR_NOT_ALL_ASSIGNED 1300L +#define ERROR_SOME_NOT_MAPPED 1301L +#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302L +#define ERROR_LOCAL_USER_SESSION_KEY 1303L +#define ERROR_NULL_LM_PASSWORD 1304L +#define ERROR_UNKNOWN_REVISION 1305L +#define ERROR_REVISION_MISMATCH 1306L +#define ERROR_INVALID_OWNER 1307L +#define ERROR_INVALID_PRIMARY_GROUP 1308L +#define ERROR_NO_IMPERSONATION_TOKEN 1309L +#define ERROR_CANT_DISABLE_MANDATORY 1310L +#define ERROR_NO_LOGON_SERVERS 1311L +#define ERROR_NO_SUCH_LOGON_SESSION 1312L +#define ERROR_NO_SUCH_PRIVILEGE 1313L +#define ERROR_PRIVILEGE_NOT_HELD 1314L +#define ERROR_INVALID_ACCOUNT_NAME 1315L +#define ERROR_USER_EXISTS 1316L +#define ERROR_NO_SUCH_USER 1317L +#define ERROR_GROUP_EXISTS 1318L +#define ERROR_NO_SUCH_GROUP 1319L +#define ERROR_MEMBER_IN_GROUP 1320L +#define ERROR_MEMBER_NOT_IN_GROUP 1321L +#define ERROR_LAST_ADMIN 1322L +#define ERROR_WRONG_PASSWORD 1323L +#define ERROR_ILL_FORMED_PASSWORD 1324L +#define ERROR_PASSWORD_RESTRICTION 1325L +#define ERROR_LOGON_FAILURE 1326L +#define ERROR_ACCOUNT_RESTRICTION 1327L +#define ERROR_INVALID_LOGON_HOURS 1328L +#define ERROR_INVALID_WORKSTATION 1329L +#define ERROR_PASSWORD_EXPIRED 1330L +#define ERROR_ACCOUNT_DISABLED 1331L +#define ERROR_NONE_MAPPED 1332L +#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333L +#define ERROR_LUIDS_EXHAUSTED 1334L +#define ERROR_INVALID_SUB_AUTHORITY 1335L +#define ERROR_INVALID_ACL 1336L +#define ERROR_INVALID_SID 1337L +#define ERROR_INVALID_SECURITY_DESCR 1338L +#define ERROR_BAD_INHERITANCE_ACL 1340L +#define ERROR_SERVER_DISABLED 1341L +#define ERROR_SERVER_NOT_DISABLED 1342L +#define ERROR_INVALID_ID_AUTHORITY 1343L +#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344L +#define ERROR_INVALID_GROUP_ATTRIBUTES 1345L +#define ERROR_BAD_IMPERSONATION_LEVEL 1346L +#define ERROR_CANT_OPEN_ANONYMOUS 1347L +#define ERROR_BAD_VALIDATION_CLASS 1348L +#define ERROR_BAD_TOKEN_TYPE 1349L +#define ERROR_NO_SECURITY_ON_OBJECT 1350L +#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351L +#define ERROR_INVALID_SERVER_STATE 1352L +#define ERROR_INVALID_DOMAIN_STATE 1353L +#define ERROR_INVALID_DOMAIN_ROLE 1354L +#define ERROR_NO_SUCH_DOMAIN 1355L +#define ERROR_DOMAIN_EXISTS 1356L +#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357L +#define ERROR_INTERNAL_DB_CORRUPTION 1358L +#define ERROR_INTERNAL_ERROR 1359L +#define ERROR_GENERIC_NOT_MAPPED 1360L +#define ERROR_BAD_DESCRIPTOR_FORMAT 1361L +#define ERROR_NOT_LOGON_PROCESS 1362L +#define ERROR_LOGON_SESSION_EXISTS 1363L +#define ERROR_NO_SUCH_PACKAGE 1364L +#define ERROR_BAD_LOGON_SESSION_STATE 1365L +#define ERROR_LOGON_SESSION_COLLISION 1366L +#define ERROR_INVALID_LOGON_TYPE 1367L +#define ERROR_CANNOT_IMPERSONATE 1368L +#define ERROR_RXACT_INVALID_STATE 1369L +#define ERROR_RXACT_COMMIT_FAILURE 1370L +#define ERROR_SPECIAL_ACCOUNT 1371L +#define ERROR_SPECIAL_GROUP 1372L +#define ERROR_SPECIAL_USER 1373L +#define ERROR_MEMBERS_PRIMARY_GROUP 1374L +#define ERROR_TOKEN_ALREADY_IN_USE 1375L +#define ERROR_NO_SUCH_ALIAS 1376L +#define ERROR_MEMBER_NOT_IN_ALIAS 1377L +#define ERROR_MEMBER_IN_ALIAS 1378L +#define ERROR_ALIAS_EXISTS 1379L +#define ERROR_LOGON_NOT_GRANTED 1380L +#define ERROR_TOO_MANY_SECRETS 1381L +#define ERROR_SECRET_TOO_LONG 1382L +#define ERROR_INTERNAL_DB_ERROR 1383L +#define ERROR_TOO_MANY_CONTEXT_IDS 1384L +#define ERROR_LOGON_TYPE_NOT_GRANTED 1385L +#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386L +#define ERROR_NO_SUCH_MEMBER 1387L +#define ERROR_INVALID_MEMBER 1388L +#define ERROR_TOO_MANY_SIDS 1389L +#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390L +#define ERROR_NO_INHERITANCE 1391L +#define ERROR_FILE_CORRUPT 1392L +#define ERROR_DISK_CORRUPT 1393L +#define ERROR_NO_USER_SESSION_KEY 1394L +#define ERROR_LICENSE_QUOTA_EXCEEDED 1395L +#define ERROR_WRONG_TARGET_NAME 1396L +#define ERROR_MUTUAL_AUTH_FAILED 1397L +#define ERROR_TIME_SKEW 1398L +#define ERROR_CURRENT_DOMAIN_NOT_ALLOWED 1399L +#define ERROR_INVALID_WINDOW_HANDLE 1400L +#define ERROR_INVALID_MENU_HANDLE 1401L +#define ERROR_INVALID_CURSOR_HANDLE 1402L +#define ERROR_INVALID_ACCEL_HANDLE 1403L +#define ERROR_INVALID_HOOK_HANDLE 1404L +#define ERROR_INVALID_DWP_HANDLE 1405L +#define ERROR_TLW_WITH_WSCHILD 1406L +#define ERROR_CANNOT_FIND_WND_CLASS 1407L +#define ERROR_WINDOW_OF_OTHER_THREAD 1408L +#define ERROR_HOTKEY_ALREADY_REGISTERED 1409L +#define ERROR_CLASS_ALREADY_EXISTS 1410L +#define ERROR_CLASS_DOES_NOT_EXIST 1411L +#define ERROR_CLASS_HAS_WINDOWS 1412L +#define ERROR_INVALID_INDEX 1413L +#define ERROR_INVALID_ICON_HANDLE 1414L +#define ERROR_PRIVATE_DIALOG_INDEX 1415L +#define ERROR_LISTBOX_ID_NOT_FOUND 1416L +#define ERROR_NO_WILDCARD_CHARACTERS 1417L +#define ERROR_CLIPBOARD_NOT_OPEN 1418L +#define ERROR_HOTKEY_NOT_REGISTERED 1419L +#define ERROR_WINDOW_NOT_DIALOG 1420L +#define ERROR_CONTROL_ID_NOT_FOUND 1421L +#define ERROR_INVALID_COMBOBOX_MESSAGE 1422L +#define ERROR_WINDOW_NOT_COMBOBOX 1423L +#define ERROR_INVALID_EDIT_HEIGHT 1424L +#define ERROR_DC_NOT_FOUND 1425L +#define ERROR_INVALID_HOOK_FILTER 1426L +#define ERROR_INVALID_FILTER_PROC 1427L +#define ERROR_HOOK_NEEDS_HMOD 1428L +#define ERROR_GLOBAL_ONLY_HOOK 1429L +#define ERROR_JOURNAL_HOOK_SET 1430L +#define ERROR_HOOK_NOT_INSTALLED 1431L +#define ERROR_INVALID_LB_MESSAGE 1432L +#define ERROR_SETCOUNT_ON_BAD_LB 1433L +#define ERROR_LB_WITHOUT_TABSTOPS 1434L +#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435L +#define ERROR_CHILD_WINDOW_MENU 1436L +#define ERROR_NO_SYSTEM_MENU 1437L +#define ERROR_INVALID_MSGBOX_STYLE 1438L +#define ERROR_INVALID_SPI_VALUE 1439L +#define ERROR_SCREEN_ALREADY_LOCKED 1440L +#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441L +#define ERROR_NOT_CHILD_WINDOW 1442L +#define ERROR_INVALID_GW_COMMAND 1443L +#define ERROR_INVALID_THREAD_ID 1444L +#define ERROR_NON_MDICHILD_WINDOW 1445L +#define ERROR_POPUP_ALREADY_ACTIVE 1446L +#define ERROR_NO_SCROLLBARS 1447L +#define ERROR_INVALID_SCROLLBAR_RANGE 1448L +#define ERROR_INVALID_SHOWWIN_COMMAND 1449L +#define ERROR_NO_SYSTEM_RESOURCES 1450L +#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451L +#define ERROR_PAGED_SYSTEM_RESOURCES 1452L +#define ERROR_WORKING_SET_QUOTA 1453L +#define ERROR_PAGEFILE_QUOTA 1454L +#define ERROR_COMMITMENT_LIMIT 1455L +#define ERROR_MENU_ITEM_NOT_FOUND 1456L +#define ERROR_INVALID_KEYBOARD_HANDLE 1457L +#define ERROR_HOOK_TYPE_NOT_ALLOWED 1458L +#define ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION 1459L +#define ERROR_TIMEOUT 1460L +#define ERROR_INVALID_MONITOR_HANDLE 1461L +#define ERROR_INCORRECT_SIZE 1462L +#define ERROR_EVENTLOG_FILE_CORRUPT 1500L +#define ERROR_EVENTLOG_CANT_START 1501L +#define ERROR_LOG_FILE_FULL 1502L +#define ERROR_EVENTLOG_FILE_CHANGED 1503L +#define ERROR_INSTALL_SERVICE_FAILURE 1601L +#define ERROR_INSTALL_USEREXIT 1602L +#define ERROR_INSTALL_FAILURE 1603L +#define ERROR_INSTALL_SUSPEND 1604L +#define ERROR_UNKNOWN_PRODUCT 1605L +#define ERROR_UNKNOWN_FEATURE 1606L +#define ERROR_UNKNOWN_COMPONENT 1607L +#define ERROR_UNKNOWN_PROPERTY 1608L +#define ERROR_INVALID_HANDLE_STATE 1609L +#define ERROR_BAD_CONFIGURATION 1610L +#define ERROR_INDEX_ABSENT 1611L +#define ERROR_INSTALL_SOURCE_ABSENT 1612L +#define ERROR_INSTALL_PACKAGE_VERSION 1613L +#define ERROR_PRODUCT_UNINSTALLED 1614L +#define ERROR_BAD_QUERY_SYNTAX 1615L +#define ERROR_INVALID_FIELD 1616L +#define ERROR_DEVICE_REMOVED 1617L +#define ERROR_INSTALL_ALREADY_RUNNING 1618L +#define ERROR_INSTALL_PACKAGE_OPEN_FAILED 1619L +#define ERROR_INSTALL_PACKAGE_INVALID 1620L +#define ERROR_INSTALL_UI_FAILURE 1621L +#define ERROR_INSTALL_LOG_FAILURE 1622L +#define ERROR_INSTALL_LANGUAGE_UNSUPPORTED 1623L +#define ERROR_INSTALL_TRANSFORM_FAILURE 1624L +#define ERROR_INSTALL_PACKAGE_REJECTED 1625L +#define ERROR_FUNCTION_NOT_CALLED 1626L +#define ERROR_FUNCTION_FAILED 1627L +#define ERROR_INVALID_TABLE 1628L +#define ERROR_DATATYPE_MISMATCH 1629L +#define ERROR_UNSUPPORTED_TYPE 1630L +#define ERROR_CREATE_FAILED 1631L +#define ERROR_INSTALL_TEMP_UNWRITABLE 1632L +#define ERROR_INSTALL_PLATFORM_UNSUPPORTED 1633L +#define ERROR_INSTALL_NOTUSED 1634L +#define ERROR_PATCH_PACKAGE_OPEN_FAILED 1635L +#define ERROR_PATCH_PACKAGE_INVALID 1636L +#define ERROR_PATCH_PACKAGE_UNSUPPORTED 1637L +#define ERROR_PRODUCT_VERSION 1638L +#define ERROR_INVALID_COMMAND_LINE 1639L +#define ERROR_INSTALL_REMOTE_DISALLOWED 1640L +#define ERROR_SUCCESS_REBOOT_INITIATED 1641L +#define ERROR_PATCH_TARGET_NOT_FOUND 1642L +#define ERROR_PATCH_PACKAGE_REJECTED 1643L +#define ERROR_INSTALL_TRANSFORM_REJECTED 1644L +#define ERROR_INSTALL_REMOTE_PROHIBITED 1645L +#define RPC_S_INVALID_STRING_BINDING 1700L +#define RPC_S_WRONG_KIND_OF_BINDING 1701L +#define RPC_S_INVALID_BINDING 1702L +#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703L +#define RPC_S_INVALID_RPC_PROTSEQ 1704L +#define RPC_S_INVALID_STRING_UUID 1705L +#define RPC_S_INVALID_ENDPOINT_FORMAT 1706L +#define RPC_S_INVALID_NET_ADDR 1707L +#define RPC_S_NO_ENDPOINT_FOUND 1708L +#define RPC_S_INVALID_TIMEOUT 1709L +#define RPC_S_OBJECT_NOT_FOUND 1710L +#define RPC_S_ALREADY_REGISTERED 1711L +#define RPC_S_TYPE_ALREADY_REGISTERED 1712L +#define RPC_S_ALREADY_LISTENING 1713L +#define RPC_S_NO_PROTSEQS_REGISTERED 1714L +#define RPC_S_NOT_LISTENING 1715L +#define RPC_S_UNKNOWN_MGR_TYPE 1716L +#define RPC_S_UNKNOWN_IF 1717L +#define RPC_S_NO_BINDINGS 1718L +#define RPC_S_NO_PROTSEQS 1719L +#define RPC_S_CANT_CREATE_ENDPOINT 1720L +#define RPC_S_OUT_OF_RESOURCES 1721L +#define RPC_S_SERVER_UNAVAILABLE 1722L +#define RPC_S_SERVER_TOO_BUSY 1723L +#define RPC_S_INVALID_NETWORK_OPTIONS 1724L +#define RPC_S_NO_CALL_ACTIVE 1725L +#define RPC_S_CALL_FAILED 1726L +#define RPC_S_CALL_FAILED_DNE 1727L +#define RPC_S_PROTOCOL_ERROR 1728L +#define RPC_S_UNSUPPORTED_TRANS_SYN 1730L +#define RPC_S_UNSUPPORTED_TYPE 1732L +#define RPC_S_INVALID_TAG 1733L +#define RPC_S_INVALID_BOUND 1734L +#define RPC_S_NO_ENTRY_NAME 1735L +#define RPC_S_INVALID_NAME_SYNTAX 1736L +#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737L +#define RPC_S_UUID_NO_ADDRESS 1739L +#define RPC_S_DUPLICATE_ENDPOINT 1740L +#define RPC_S_UNKNOWN_AUTHN_TYPE 1741L +#define RPC_S_MAX_CALLS_TOO_SMALL 1742L +#define RPC_S_STRING_TOO_LONG 1743L +#define RPC_S_PROTSEQ_NOT_FOUND 1744L +#define RPC_S_PROCNUM_OUT_OF_RANGE 1745L +#define RPC_S_BINDING_HAS_NO_AUTH 1746L +#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747L +#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748L +#define RPC_S_INVALID_AUTH_IDENTITY 1749L +#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750L +#define EPT_S_INVALID_ENTRY 1751L +#define EPT_S_CANT_PERFORM_OP 1752L +#define EPT_S_NOT_REGISTERED 1753L +#define RPC_S_NOTHING_TO_EXPORT 1754L +#define RPC_S_INCOMPLETE_NAME 1755L +#define RPC_S_INVALID_VERS_OPTION 1756L +#define RPC_S_NO_MORE_MEMBERS 1757L +#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758L +#define RPC_S_INTERFACE_NOT_FOUND 1759L +#define RPC_S_ENTRY_ALREADY_EXISTS 1760L +#define RPC_S_ENTRY_NOT_FOUND 1761L +#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762L +#define RPC_S_INVALID_NAF_ID 1763L +#define RPC_S_CANNOT_SUPPORT 1764L +#define RPC_S_NO_CONTEXT_AVAILABLE 1765L +#define RPC_S_INTERNAL_ERROR 1766L +#define RPC_S_ZERO_DIVIDE 1767L +#define RPC_S_ADDRESS_ERROR 1768L +#define RPC_S_FP_DIV_ZERO 1769L +#define RPC_S_FP_UNDERFLOW 1770L +#define RPC_S_FP_OVERFLOW 1771L +#define RPC_X_NO_MORE_ENTRIES 1772L +#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773L +#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774L +#define RPC_X_SS_IN_NULL_CONTEXT 1775L +#define RPC_X_SS_CONTEXT_DAMAGED 1777L +#define RPC_X_SS_HANDLES_MISMATCH 1778L +#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779L +#define RPC_X_NULL_REF_POINTER 1780L +#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781L +#define RPC_X_BYTE_COUNT_TOO_SMALL 1782L +#define RPC_X_BAD_STUB_DATA 1783L +#define ERROR_INVALID_USER_BUFFER 1784L +#define ERROR_UNRECOGNIZED_MEDIA 1785L +#define ERROR_NO_TRUST_LSA_SECRET 1786L +#define ERROR_NO_TRUST_SAM_ACCOUNT 1787L +#define ERROR_TRUSTED_DOMAIN_FAILURE 1788L +#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789L +#define ERROR_TRUST_FAILURE 1790L +#define RPC_S_CALL_IN_PROGRESS 1791L +#define ERROR_NETLOGON_NOT_STARTED 1792L +#define ERROR_ACCOUNT_EXPIRED 1793L +#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794L +#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795L +#define ERROR_UNKNOWN_PORT 1796L +#define ERROR_UNKNOWN_PRINTER_DRIVER 1797L +#define ERROR_UNKNOWN_PRINTPROCESSOR 1798L +#define ERROR_INVALID_SEPARATOR_FILE 1799L +#define ERROR_INVALID_PRIORITY 1800L +#define ERROR_INVALID_PRINTER_NAME 1801L +#define ERROR_PRINTER_ALREADY_EXISTS 1802L +#define ERROR_INVALID_PRINTER_COMMAND 1803L +#define ERROR_INVALID_DATATYPE 1804L +#define ERROR_INVALID_ENVIRONMENT 1805L +#define RPC_S_NO_MORE_BINDINGS 1806L +#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807L +#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808L +#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809L +#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810L +#define ERROR_SERVER_HAS_OPEN_HANDLES 1811L +#define ERROR_RESOURCE_DATA_NOT_FOUND 1812L +#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813L +#define ERROR_RESOURCE_NAME_NOT_FOUND 1814L +#define ERROR_RESOURCE_LANG_NOT_FOUND 1815L +#define ERROR_NOT_ENOUGH_QUOTA 1816L +#define RPC_S_NO_INTERFACES 1817L +#define RPC_S_CALL_CANCELLED 1818L +#define RPC_S_BINDING_INCOMPLETE 1819L +#define RPC_S_COMM_FAILURE 1820L +#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821L +#define RPC_S_NO_PRINC_NAME 1822L +#define RPC_S_NOT_RPC_ERROR 1823L +#define RPC_S_UUID_LOCAL_ONLY 1824L +#define RPC_S_SEC_PKG_ERROR 1825L +#define RPC_S_NOT_CANCELLED 1826L +#define RPC_X_INVALID_ES_ACTION 1827L +#define RPC_X_WRONG_ES_VERSION 1828L +#define RPC_X_WRONG_STUB_VERSION 1829L +#define RPC_X_INVALID_PIPE_OBJECT 1830L +#define RPC_X_WRONG_PIPE_ORDER 1831L +#define RPC_X_WRONG_PIPE_VERSION 1832L +#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898L +#define EPT_S_CANT_CREATE 1899L +#define RPC_S_INVALID_OBJECT 1900L +#define ERROR_INVALID_TIME 1901L +#define ERROR_INVALID_FORM_NAME 1902L +#define ERROR_INVALID_FORM_SIZE 1903L +#define ERROR_ALREADY_WAITING 1904L +#define ERROR_PRINTER_DELETED 1905L +#define ERROR_INVALID_PRINTER_STATE 1906L +#define ERROR_PASSWORD_MUST_CHANGE 1907L +#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908L +#define ERROR_ACCOUNT_LOCKED_OUT 1909L +#define OR_INVALID_OXID 1910L +#define OR_INVALID_OID 1911L +#define OR_INVALID_SET 1912L +#define RPC_S_SEND_INCOMPLETE 1913L +#define RPC_S_INVALID_ASYNC_HANDLE 1914L +#define RPC_S_INVALID_ASYNC_CALL 1915L +#define RPC_X_PIPE_CLOSED 1916L +#define RPC_X_PIPE_DISCIPLINE_ERROR 1917L +#define RPC_X_PIPE_EMPTY 1918L +#define ERROR_NO_SITENAME 1919L +#define ERROR_CANT_ACCESS_FILE 1920L +#define ERROR_CANT_RESOLVE_FILENAME 1921L +#define RPC_S_ENTRY_TYPE_MISMATCH 1922L +#define RPC_S_NOT_ALL_OBJS_EXPORTED 1923L +#define RPC_S_INTERFACE_NOT_EXPORTED 1924L +#define RPC_S_PROFILE_NOT_ADDED 1925L +#define RPC_S_PRF_ELT_NOT_ADDED 1926L +#define RPC_S_PRF_ELT_NOT_REMOVED 1927L +#define RPC_S_GRP_ELT_NOT_ADDED 1928L +#define RPC_S_GRP_ELT_NOT_REMOVED 1929L +#define ERROR_KM_DRIVER_BLOCKED 1930L +#define ERROR_CONTEXT_EXPIRED 1931L +#define ERROR_PER_USER_TRUST_QUOTA_EXCEEDED 1932L +#define ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED 1933L +#define ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED 1934L +#define ERROR_AUTHENTICATION_FIREWALL_FAILED 1935L +#define ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED 1936L +#define ERROR_INVALID_PIXEL_FORMAT 2000L +#define ERROR_BAD_DRIVER 2001L +#define ERROR_INVALID_WINDOW_STYLE 2002L +#define ERROR_METAFILE_NOT_SUPPORTED 2003L +#define ERROR_TRANSFORM_NOT_SUPPORTED 2004L +#define ERROR_CLIPPING_NOT_SUPPORTED 2005L +#define ERROR_INVALID_CMM 2010L +#define ERROR_INVALID_PROFILE 2011L +#define ERROR_TAG_NOT_FOUND 2012L +#define ERROR_TAG_NOT_PRESENT 2013L +#define ERROR_DUPLICATE_TAG 2014L +#define ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE 2015L +#define ERROR_PROFILE_NOT_FOUND 2016L +#define ERROR_INVALID_COLORSPACE 2017L +#define ERROR_ICM_NOT_ENABLED 2018L +#define ERROR_DELETING_ICM_XFORM 2019L +#define ERROR_INVALID_TRANSFORM 2020L +#define ERROR_COLORSPACE_MISMATCH 2021L +#define ERROR_INVALID_COLORINDEX 2022L +#define ERROR_CONNECTED_OTHER_PASSWORD 2108L +#define ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT 2109L +#define ERROR_BAD_USERNAME 2202L +#define ERROR_NOT_CONNECTED 2250L +#define ERROR_OPEN_FILES 2401L +#define ERROR_ACTIVE_CONNECTIONS 2402L +#define ERROR_DEVICE_IN_USE 2404L +#define ERROR_UNKNOWN_PRINT_MONITOR 3000L +#define ERROR_PRINTER_DRIVER_IN_USE 3001L +#define ERROR_SPOOL_FILE_NOT_FOUND 3002L +#define ERROR_SPL_NO_STARTDOC 3003L +#define ERROR_SPL_NO_ADDJOB 3004L +#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005L +#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006L +#define ERROR_INVALID_PRINT_MONITOR 3007L +#define ERROR_PRINT_MONITOR_IN_USE 3008L +#define ERROR_PRINTER_HAS_JOBS_QUEUED 3009L +#define ERROR_SUCCESS_REBOOT_REQUIRED 3010L +#define ERROR_SUCCESS_RESTART_REQUIRED 3011L +#define ERROR_PRINTER_NOT_FOUND 3012L +#define ERROR_PRINTER_DRIVER_WARNED 3013L +#define ERROR_PRINTER_DRIVER_BLOCKED 3014L +#define ERROR_WINS_INTERNAL 4000L +#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001L +#define ERROR_STATIC_INIT 4002L +#define ERROR_INC_BACKUP 4003L +#define ERROR_FULL_BACKUP 4004L +#define ERROR_REC_NON_EXISTENT 4005L +#define ERROR_RPL_NOT_ALLOWED 4006L +#define ERROR_DHCP_ADDRESS_CONFLICT 4100L +#define ERROR_WMI_GUID_NOT_FOUND 4200L +#define ERROR_WMI_INSTANCE_NOT_FOUND 4201L +#define ERROR_WMI_ITEMID_NOT_FOUND 4202L +#define ERROR_WMI_TRY_AGAIN 4203L +#define ERROR_WMI_DP_NOT_FOUND 4204L +#define ERROR_WMI_UNRESOLVED_INSTANCE_REF 4205L +#define ERROR_WMI_ALREADY_ENABLED 4206L +#define ERROR_WMI_GUID_DISCONNECTED 4207L +#define ERROR_WMI_SERVER_UNAVAILABLE 4208L +#define ERROR_WMI_DP_FAILED 4209L +#define ERROR_WMI_INVALID_MOF 4210L +#define ERROR_WMI_INVALID_REGINFO 4211L +#define ERROR_WMI_ALREADY_DISABLED 4212L +#define ERROR_WMI_READ_ONLY 4213L +#define ERROR_WMI_SET_FAILURE 4214L +#define ERROR_INVALID_MEDIA 4300L +#define ERROR_INVALID_LIBRARY 4301L +#define ERROR_INVALID_MEDIA_POOL 4302L +#define ERROR_DRIVE_MEDIA_MISMATCH 4303L +#define ERROR_MEDIA_OFFLINE 4304L +#define ERROR_LIBRARY_OFFLINE 4305L +#define ERROR_EMPTY 4306L +#define ERROR_NOT_EMPTY 4307L +#define ERROR_MEDIA_UNAVAILABLE 4308L +#define ERROR_RESOURCE_DISABLED 4309L +#define ERROR_INVALID_CLEANER 4310L +#define ERROR_UNABLE_TO_CLEAN 4311L +#define ERROR_OBJECT_NOT_FOUND 4312L +#define ERROR_DATABASE_FAILURE 4313L +#define ERROR_DATABASE_FULL 4314L +#define ERROR_MEDIA_INCOMPATIBLE 4315L +#define ERROR_RESOURCE_NOT_PRESENT 4316L +#define ERROR_INVALID_OPERATION 4317L +#define ERROR_MEDIA_NOT_AVAILABLE 4318L +#define ERROR_DEVICE_NOT_AVAILABLE 4319L +#define ERROR_REQUEST_REFUSED 4320L +#define ERROR_INVALID_DRIVE_OBJECT 4321L +#define ERROR_LIBRARY_FULL 4322L +#define ERROR_MEDIUM_NOT_ACCESSIBLE 4323L +#define ERROR_UNABLE_TO_LOAD_MEDIUM 4324L +#define ERROR_UNABLE_TO_INVENTORY_DRIVE 4325L +#define ERROR_UNABLE_TO_INVENTORY_SLOT 4326L +#define ERROR_UNABLE_TO_INVENTORY_TRANSPORT 4327L +#define ERROR_TRANSPORT_FULL 4328L +#define ERROR_CONTROLLING_IEPORT 4329L +#define ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA 4330L +#define ERROR_CLEANER_SLOT_SET 4331L +#define ERROR_CLEANER_SLOT_NOT_SET 4332L +#define ERROR_CLEANER_CARTRIDGE_SPENT 4333L +#define ERROR_UNEXPECTED_OMID 4334L +#define ERROR_CANT_DELETE_LAST_ITEM 4335L +#define ERROR_MESSAGE_EXCEEDS_MAX_SIZE 4336L +#define ERROR_VOLUME_CONTAINS_SYS_FILES 4337L +#define ERROR_INDIGENOUS_TYPE 4338L +#define ERROR_NO_SUPPORTING_DRIVES 4339L +#define ERROR_CLEANER_CARTRIDGE_INSTALLED 4340L +#define ERROR_IEPORT_FULL 4341L +#define ERROR_FILE_OFFLINE 4350L +#define ERROR_REMOTE_STORAGE_NOT_ACTIVE 4351L +#define ERROR_REMOTE_STORAGE_MEDIA_ERROR 4352L +#define ERROR_NOT_A_REPARSE_POINT 4390L +#define ERROR_REPARSE_ATTRIBUTE_CONFLICT 4391L +#define ERROR_INVALID_REPARSE_DATA 4392L +#define ERROR_REPARSE_TAG_INVALID 4393L +#define ERROR_REPARSE_TAG_MISMATCH 4394L +#define ERROR_VOLUME_NOT_SIS_ENABLED 4500L +#define ERROR_DEPENDENT_RESOURCE_EXISTS 5001L +#define ERROR_DEPENDENCY_NOT_FOUND 5002L +#define ERROR_DEPENDENCY_ALREADY_EXISTS 5003L +#define ERROR_RESOURCE_NOT_ONLINE 5004L +#define ERROR_HOST_NODE_NOT_AVAILABLE 5005L +#define ERROR_RESOURCE_NOT_AVAILABLE 5006L +#define ERROR_RESOURCE_NOT_FOUND 5007L +#define ERROR_SHUTDOWN_CLUSTER 5008L +#define ERROR_CANT_EVICT_ACTIVE_NODE 5009L +#define ERROR_OBJECT_ALREADY_EXISTS 5010L +#define ERROR_OBJECT_IN_LIST 5011L +#define ERROR_GROUP_NOT_AVAILABLE 5012L +#define ERROR_GROUP_NOT_FOUND 5013L +#define ERROR_GROUP_NOT_ONLINE 5014L +#define ERROR_HOST_NODE_NOT_RESOURCE_OWNER 5015L +#define ERROR_HOST_NODE_NOT_GROUP_OWNER 5016L +#define ERROR_RESMON_CREATE_FAILED 5017L +#define ERROR_RESMON_ONLINE_FAILED 5018L +#define ERROR_RESOURCE_ONLINE 5019L +#define ERROR_QUORUM_RESOURCE 5020L +#define ERROR_NOT_QUORUM_CAPABLE 5021L +#define ERROR_CLUSTER_SHUTTING_DOWN 5022L +#define ERROR_INVALID_STATE 5023L +#define ERROR_RESOURCE_PROPERTIES_STORED 5024L +#define ERROR_NOT_QUORUM_CLASS 5025L +#define ERROR_CORE_RESOURCE 5026L +#define ERROR_QUORUM_RESOURCE_ONLINE_FAILED 5027L +#define ERROR_QUORUMLOG_OPEN_FAILED 5028L +#define ERROR_CLUSTERLOG_CORRUPT 5029L +#define ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE 5030L +#define ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE 5031L +#define ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND 5032L +#define ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE 5033L +#define ERROR_QUORUM_OWNER_ALIVE 5034L +#define ERROR_NETWORK_NOT_AVAILABLE 5035L +#define ERROR_NODE_NOT_AVAILABLE 5036L +#define ERROR_ALL_NODES_NOT_AVAILABLE 5037L +#define ERROR_RESOURCE_FAILED 5038L +#define ERROR_CLUSTER_INVALID_NODE 5039L +#define ERROR_CLUSTER_NODE_EXISTS 5040L +#define ERROR_CLUSTER_JOIN_IN_PROGRESS 5041L +#define ERROR_CLUSTER_NODE_NOT_FOUND 5042L +#define ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND 5043L +#define ERROR_CLUSTER_NETWORK_EXISTS 5044L +#define ERROR_CLUSTER_NETWORK_NOT_FOUND 5045L +#define ERROR_CLUSTER_NETINTERFACE_EXISTS 5046L +#define ERROR_CLUSTER_NETINTERFACE_NOT_FOUND 5047L +#define ERROR_CLUSTER_INVALID_REQUEST 5048L +#define ERROR_CLUSTER_INVALID_NETWORK_PROVIDER 5049L +#define ERROR_CLUSTER_NODE_DOWN 5050L +#define ERROR_CLUSTER_NODE_UNREACHABLE 5051L +#define ERROR_CLUSTER_NODE_NOT_MEMBER 5052L +#define ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS 5053L +#define ERROR_CLUSTER_INVALID_NETWORK 5054L +#define ERROR_CLUSTER_NODE_UP 5056L +#define ERROR_CLUSTER_IPADDR_IN_USE 5057L +#define ERROR_CLUSTER_NODE_NOT_PAUSED 5058L +#define ERROR_CLUSTER_NO_SECURITY_CONTEXT 5059L +#define ERROR_CLUSTER_NETWORK_NOT_INTERNAL 5060L +#define ERROR_CLUSTER_NODE_ALREADY_UP 5061L +#define ERROR_CLUSTER_NODE_ALREADY_DOWN 5062L +#define ERROR_CLUSTER_NETWORK_ALREADY_ONLINE 5063L +#define ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE 5064L +#define ERROR_CLUSTER_NODE_ALREADY_MEMBER 5065L +#define ERROR_CLUSTER_LAST_INTERNAL_NETWORK 5066L +#define ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS 5067L +#define ERROR_INVALID_OPERATION_ON_QUORUM 5068L +#define ERROR_DEPENDENCY_NOT_ALLOWED 5069L +#define ERROR_CLUSTER_NODE_PAUSED 5070L +#define ERROR_NODE_CANT_HOST_RESOURCE 5071L +#define ERROR_CLUSTER_NODE_NOT_READY 5072L +#define ERROR_CLUSTER_NODE_SHUTTING_DOWN 5073L +#define ERROR_CLUSTER_JOIN_ABORTED 5074L +#define ERROR_CLUSTER_INCOMPATIBLE_VERSIONS 5075L +#define ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED 5076L +#define ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED 5077L +#define ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND 5078L +#define ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED 5079L +#define ERROR_CLUSTER_RESNAME_NOT_FOUND 5080L +#define ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED 5081L +#define ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST 5082L +#define ERROR_CLUSTER_DATABASE_SEQMISMATCH 5083L +#define ERROR_RESMON_INVALID_STATE 5084L +#define ERROR_CLUSTER_GUM_NOT_LOCKER 5085L +#define ERROR_QUORUM_DISK_NOT_FOUND 5086L +#define ERROR_DATABASE_BACKUP_CORRUPT 5087L +#define ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT 5088L +#define ERROR_RESOURCE_PROPERTY_UNCHANGEABLE 5089L +#define ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE 5890L +#define ERROR_CLUSTER_QUORUMLOG_NOT_FOUND 5891L +#define ERROR_CLUSTER_MEMBERSHIP_HALT 5892L +#define ERROR_CLUSTER_INSTANCE_ID_MISMATCH 5893L +#define ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP 5894L +#define ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH 5895L +#define ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP 5896L +#define ERROR_CLUSTER_PARAMETER_MISMATCH 5897L +#define ERROR_NODE_CANNOT_BE_CLUSTERED 5898L +#define ERROR_CLUSTER_WRONG_OS_VERSION 5899L +#define ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME 5900L +#define ERROR_CLUSCFG_ALREADY_COMMITTED 5901L +#define ERROR_CLUSCFG_ROLLBACK_FAILED 5902L +#define ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT 5903L +#define ERROR_CLUSTER_OLD_VERSION 5904L +#define ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME 5905L +#define ERROR_ENCRYPTION_FAILED 6000L +#define ERROR_DECRYPTION_FAILED 6001L +#define ERROR_FILE_ENCRYPTED 6002L +#define ERROR_NO_RECOVERY_POLICY 6003L +#define ERROR_NO_EFS 6004L +#define ERROR_WRONG_EFS 6005L +#define ERROR_NO_USER_KEYS 6006L +#define ERROR_FILE_NOT_ENCRYPTED 6007L +#define ERROR_NOT_EXPORT_FORMAT 6008L +#define ERROR_FILE_READ_ONLY 6009L +#define ERROR_DIR_EFS_DISALLOWED 6010L +#define ERROR_EFS_SERVER_NOT_TRUSTED 6011L +#define ERROR_BAD_RECOVERY_POLICY 6012L +#define ERROR_EFS_ALG_BLOB_TOO_BIG 6013L +#define ERROR_VOLUME_NOT_SUPPORT_EFS 6014L +#define ERROR_EFS_DISABLED 6015L +#define ERROR_EFS_VERSION_NOT_SUPPORT 6016L +#define ERROR_NO_BROWSER_SERVERS_FOUND 6118L +#define SCHED_E_SERVICE_NOT_LOCALSYSTEM 6200L +#define ERROR_CTX_WINSTATION_NAME_INVALID 7001L +#define ERROR_CTX_INVALID_PD 7002L +#define ERROR_CTX_PD_NOT_FOUND 7003L +#define ERROR_CTX_WD_NOT_FOUND 7004L +#define ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY 7005L +#define ERROR_CTX_SERVICE_NAME_COLLISION 7006L +#define ERROR_CTX_CLOSE_PENDING 7007L +#define ERROR_CTX_NO_OUTBUF 7008L +#define ERROR_CTX_MODEM_INF_NOT_FOUND 7009L +#define ERROR_CTX_INVALID_MODEMNAME 7010L +#define ERROR_CTX_MODEM_RESPONSE_ERROR 7011L +#define ERROR_CTX_MODEM_RESPONSE_TIMEOUT 7012L +#define ERROR_CTX_MODEM_RESPONSE_NO_CARRIER 7013L +#define ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE 7014L +#define ERROR_CTX_MODEM_RESPONSE_BUSY 7015L +#define ERROR_CTX_MODEM_RESPONSE_VOICE 7016L +#define ERROR_CTX_TD_ERROR 7017L +#define ERROR_CTX_WINSTATION_NOT_FOUND 7022L +#define ERROR_CTX_WINSTATION_ALREADY_EXISTS 7023L +#define ERROR_CTX_WINSTATION_BUSY 7024L +#define ERROR_CTX_BAD_VIDEO_MODE 7025L +#define ERROR_CTX_GRAPHICS_INVALID 7035L +#define ERROR_CTX_LOGON_DISABLED 7037L +#define ERROR_CTX_NOT_CONSOLE 7038L +#define ERROR_CTX_CLIENT_QUERY_TIMEOUT 7040L +#define ERROR_CTX_CONSOLE_DISCONNECT 7041L +#define ERROR_CTX_CONSOLE_CONNECT 7042L +#define ERROR_CTX_SHADOW_DENIED 7044L +#define ERROR_CTX_WINSTATION_ACCESS_DENIED 7045L +#define ERROR_CTX_INVALID_WD 7049L +#define ERROR_CTX_SHADOW_INVALID 7050L +#define ERROR_CTX_SHADOW_DISABLED 7051L +#define ERROR_CTX_CLIENT_LICENSE_IN_USE 7052L +#define ERROR_CTX_CLIENT_LICENSE_NOT_SET 7053L +#define ERROR_CTX_LICENSE_NOT_AVAILABLE 7054L +#define ERROR_CTX_LICENSE_CLIENT_INVALID 7055L +#define ERROR_CTX_LICENSE_EXPIRED 7056L +#define ERROR_CTX_SHADOW_NOT_RUNNING 7057L +#define ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE 7058L +#define ERROR_ACTIVATION_COUNT_EXCEEDED 7059L +#define FRS_ERR_INVALID_API_SEQUENCE 8001L +#define FRS_ERR_STARTING_SERVICE 8002L +#define FRS_ERR_STOPPING_SERVICE 8003L +#define FRS_ERR_INTERNAL_API 8004L +#define FRS_ERR_INTERNAL 8005L +#define FRS_ERR_SERVICE_COMM 8006L +#define FRS_ERR_INSUFFICIENT_PRIV 8007L +#define FRS_ERR_AUTHENTICATION 8008L +#define FRS_ERR_PARENT_INSUFFICIENT_PRIV 8009L +#define FRS_ERR_PARENT_AUTHENTICATION 8010L +#define FRS_ERR_CHILD_TO_PARENT_COMM 8011L +#define FRS_ERR_PARENT_TO_CHILD_COMM 8012L +#define FRS_ERR_SYSVOL_POPULATE 8013L +#define FRS_ERR_SYSVOL_POPULATE_TIMEOUT 8014L +#define FRS_ERR_SYSVOL_IS_BUSY 8015L +#define FRS_ERR_SYSVOL_DEMOTE 8016L +#define FRS_ERR_INVALID_SERVICE_PARAMETER 8017L +#define DS_S_SUCCESS NO_ERROR +#define ERROR_DS_NOT_INSTALLED 8200L +#define ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY 8201L +#define ERROR_DS_NO_ATTRIBUTE_OR_VALUE 8202L +#define ERROR_DS_INVALID_ATTRIBUTE_SYNTAX 8203L +#define ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED 8204L +#define ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS 8205L +#define ERROR_DS_BUSY 8206L +#define ERROR_DS_UNAVAILABLE 8207L +#define ERROR_DS_NO_RIDS_ALLOCATED 8208L +#define ERROR_DS_NO_MORE_RIDS 8209L +#define ERROR_DS_INCORRECT_ROLE_OWNER 8210L +#define ERROR_DS_RIDMGR_INIT_ERROR 8211L +#define ERROR_DS_OBJ_CLASS_VIOLATION 8212L +#define ERROR_DS_CANT_ON_NON_LEAF 8213L +#define ERROR_DS_CANT_ON_RDN 8214L +#define ERROR_DS_CANT_MOD_OBJ_CLASS 8215L +#define ERROR_DS_CROSS_DOM_MOVE_ERROR 8216L +#define ERROR_DS_GC_NOT_AVAILABLE 8217L +#define ERROR_SHARED_POLICY 8218L +#define ERROR_POLICY_OBJECT_NOT_FOUND 8219L +#define ERROR_POLICY_ONLY_IN_DS 8220L +#define ERROR_PROMOTION_ACTIVE 8221L +#define ERROR_NO_PROMOTION_ACTIVE 8222L +#define ERROR_DS_OPERATIONS_ERROR 8224L +#define ERROR_DS_PROTOCOL_ERROR 8225L +#define ERROR_DS_TIMELIMIT_EXCEEDED 8226L +#define ERROR_DS_SIZELIMIT_EXCEEDED 8227L +#define ERROR_DS_ADMIN_LIMIT_EXCEEDED 8228L +#define ERROR_DS_COMPARE_FALSE 8229L +#define ERROR_DS_COMPARE_TRUE 8230L +#define ERROR_DS_AUTH_METHOD_NOT_SUPPORTED 8231L +#define ERROR_DS_STRONG_AUTH_REQUIRED 8232L +#define ERROR_DS_INAPPROPRIATE_AUTH 8233L +#define ERROR_DS_AUTH_UNKNOWN 8234L +#define ERROR_DS_REFERRAL 8235L +#define ERROR_DS_UNAVAILABLE_CRIT_EXTENSION 8236L +#define ERROR_DS_CONFIDENTIALITY_REQUIRED 8237L +#define ERROR_DS_INAPPROPRIATE_MATCHING 8238L +#define ERROR_DS_CONSTRAINT_VIOLATION 8239L +#define ERROR_DS_NO_SUCH_OBJECT 8240L +#define ERROR_DS_ALIAS_PROBLEM 8241L +#define ERROR_DS_INVALID_DN_SYNTAX 8242L +#define ERROR_DS_IS_LEAF 8243L +#define ERROR_DS_ALIAS_DEREF_PROBLEM 8244L +#define ERROR_DS_UNWILLING_TO_PERFORM 8245L +#define ERROR_DS_LOOP_DETECT 8246L +#define ERROR_DS_NAMING_VIOLATION 8247L +#define ERROR_DS_OBJECT_RESULTS_TOO_LARGE 8248L +#define ERROR_DS_AFFECTS_MULTIPLE_DSAS 8249L +#define ERROR_DS_SERVER_DOWN 8250L +#define ERROR_DS_LOCAL_ERROR 8251L +#define ERROR_DS_ENCODING_ERROR 8252L +#define ERROR_DS_DECODING_ERROR 8253L +#define ERROR_DS_FILTER_UNKNOWN 8254L +#define ERROR_DS_PARAM_ERROR 8255L +#define ERROR_DS_NOT_SUPPORTED 8256L +#define ERROR_DS_NO_RESULTS_RETURNED 8257L +#define ERROR_DS_CONTROL_NOT_FOUND 8258L +#define ERROR_DS_CLIENT_LOOP 8259L +#define ERROR_DS_REFERRAL_LIMIT_EXCEEDED 8260L +#define ERROR_DS_SORT_CONTROL_MISSING 8261L +#define ERROR_DS_OFFSET_RANGE_ERROR 8262L +#define ERROR_DS_ROOT_MUST_BE_NC 8301L +#define ERROR_DS_ADD_REPLICA_INHIBITED 8302L +#define ERROR_DS_ATT_NOT_DEF_IN_SCHEMA 8303L +#define ERROR_DS_MAX_OBJ_SIZE_EXCEEDED 8304L +#define ERROR_DS_OBJ_STRING_NAME_EXISTS 8305L +#define ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA 8306L +#define ERROR_DS_RDN_DOESNT_MATCH_SCHEMA 8307L +#define ERROR_DS_NO_REQUESTED_ATTS_FOUND 8308L +#define ERROR_DS_USER_BUFFER_TO_SMALL 8309L +#define ERROR_DS_ATT_IS_NOT_ON_OBJ 8310L +#define ERROR_DS_ILLEGAL_MOD_OPERATION 8311L +#define ERROR_DS_OBJ_TOO_LARGE 8312L +#define ERROR_DS_BAD_INSTANCE_TYPE 8313L +#define ERROR_DS_MASTERDSA_REQUIRED 8314L +#define ERROR_DS_OBJECT_CLASS_REQUIRED 8315L +#define ERROR_DS_MISSING_REQUIRED_ATT 8316L +#define ERROR_DS_ATT_NOT_DEF_FOR_CLASS 8317L +#define ERROR_DS_ATT_ALREADY_EXISTS 8318L +#define ERROR_DS_CANT_ADD_ATT_VALUES 8320L +#define ERROR_DS_SINGLE_VALUE_CONSTRAINT 8321L +#define ERROR_DS_RANGE_CONSTRAINT 8322L +#define ERROR_DS_ATT_VAL_ALREADY_EXISTS 8323L +#define ERROR_DS_CANT_REM_MISSING_ATT 8324L +#define ERROR_DS_CANT_REM_MISSING_ATT_VAL 8325L +#define ERROR_DS_ROOT_CANT_BE_SUBREF 8326L +#define ERROR_DS_NO_CHAINING 8327L +#define ERROR_DS_NO_CHAINED_EVAL 8328L +#define ERROR_DS_NO_PARENT_OBJECT 8329L +#define ERROR_DS_PARENT_IS_AN_ALIAS 8330L +#define ERROR_DS_CANT_MIX_MASTER_AND_REPS 8331L +#define ERROR_DS_CHILDREN_EXIST 8332L +#define ERROR_DS_OBJ_NOT_FOUND 8333L +#define ERROR_DS_ALIASED_OBJ_MISSING 8334L +#define ERROR_DS_BAD_NAME_SYNTAX 8335L +#define ERROR_DS_ALIAS_POINTS_TO_ALIAS 8336L +#define ERROR_DS_CANT_DEREF_ALIAS 8337L +#define ERROR_DS_OUT_OF_SCOPE 8338L +#define ERROR_DS_OBJECT_BEING_REMOVED 8339L +#define ERROR_DS_CANT_DELETE_DSA_OBJ 8340L +#define ERROR_DS_GENERIC_ERROR 8341L +#define ERROR_DS_DSA_MUST_BE_INT_MASTER 8342L +#define ERROR_DS_CLASS_NOT_DSA 8343L +#define ERROR_DS_INSUFF_ACCESS_RIGHTS 8344L +#define ERROR_DS_ILLEGAL_SUPERIOR 8345L +#define ERROR_DS_ATTRIBUTE_OWNED_BY_SAM 8346L +#define ERROR_DS_NAME_TOO_MANY_PARTS 8347L +#define ERROR_DS_NAME_TOO_LONG 8348L +#define ERROR_DS_NAME_VALUE_TOO_LONG 8349L +#define ERROR_DS_NAME_UNPARSEABLE 8350L +#define ERROR_DS_NAME_TYPE_UNKNOWN 8351L +#define ERROR_DS_NOT_AN_OBJECT 8352L +#define ERROR_DS_SEC_DESC_TOO_SHORT 8353L +#define ERROR_DS_SEC_DESC_INVALID 8354L +#define ERROR_DS_NO_DELETED_NAME 8355L +#define ERROR_DS_SUBREF_MUST_HAVE_PARENT 8356L +#define ERROR_DS_NCNAME_MUST_BE_NC 8357L +#define ERROR_DS_CANT_ADD_SYSTEM_ONLY 8358L +#define ERROR_DS_CLASS_MUST_BE_CONCRETE 8359L +#define ERROR_DS_INVALID_DMD 8360L +#define ERROR_DS_OBJ_GUID_EXISTS 8361L +#define ERROR_DS_NOT_ON_BACKLINK 8362L +#define ERROR_DS_NO_CROSSREF_FOR_NC 8363L +#define ERROR_DS_SHUTTING_DOWN 8364L +#define ERROR_DS_UNKNOWN_OPERATION 8365L +#define ERROR_DS_INVALID_ROLE_OWNER 8366L +#define ERROR_DS_COULDNT_CONTACT_FSMO 8367L +#define ERROR_DS_CROSS_NC_DN_RENAME 8368L +#define ERROR_DS_CANT_MOD_SYSTEM_ONLY 8369L +#define ERROR_DS_REPLICATOR_ONLY 8370L +#define ERROR_DS_OBJ_CLASS_NOT_DEFINED 8371L +#define ERROR_DS_OBJ_CLASS_NOT_SUBCLASS 8372L +#define ERROR_DS_NAME_REFERENCE_INVALID 8373L +#define ERROR_DS_CROSS_REF_EXISTS 8374L +#define ERROR_DS_CANT_DEL_MASTER_CROSSREF 8375L +#define ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD 8376L +#define ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX 8377L +#define ERROR_DS_DUP_RDN 8378L +#define ERROR_DS_DUP_OID 8379L +#define ERROR_DS_DUP_MAPI_ID 8380L +#define ERROR_DS_DUP_SCHEMA_ID_GUID 8381L +#define ERROR_DS_DUP_LDAP_DISPLAY_NAME 8382L +#define ERROR_DS_SEMANTIC_ATT_TEST 8383L +#define ERROR_DS_SYNTAX_MISMATCH 8384L +#define ERROR_DS_EXISTS_IN_MUST_HAVE 8385L +#define ERROR_DS_EXISTS_IN_MAY_HAVE 8386L +#define ERROR_DS_NONEXISTENT_MAY_HAVE 8387L +#define ERROR_DS_NONEXISTENT_MUST_HAVE 8388L +#define ERROR_DS_AUX_CLS_TEST_FAIL 8389L +#define ERROR_DS_NONEXISTENT_POSS_SUP 8390L +#define ERROR_DS_SUB_CLS_TEST_FAIL 8391L +#define ERROR_DS_BAD_RDN_ATT_ID_SYNTAX 8392L +#define ERROR_DS_EXISTS_IN_AUX_CLS 8393L +#define ERROR_DS_EXISTS_IN_SUB_CLS 8394L +#define ERROR_DS_EXISTS_IN_POSS_SUP 8395L +#define ERROR_DS_RECALCSCHEMA_FAILED 8396L +#define ERROR_DS_TREE_DELETE_NOT_FINISHED 8397L +#define ERROR_DS_CANT_DELETE 8398L +#define ERROR_DS_ATT_SCHEMA_REQ_ID 8399L +#define ERROR_DS_BAD_ATT_SCHEMA_SYNTAX 8400L +#define ERROR_DS_CANT_CACHE_ATT 8401L +#define ERROR_DS_CANT_CACHE_CLASS 8402L +#define ERROR_DS_CANT_REMOVE_ATT_CACHE 8403L +#define ERROR_DS_CANT_REMOVE_CLASS_CACHE 8404L +#define ERROR_DS_CANT_RETRIEVE_DN 8405L +#define ERROR_DS_MISSING_SUPREF 8406L +#define ERROR_DS_CANT_RETRIEVE_INSTANCE 8407L +#define ERROR_DS_CODE_INCONSISTENCY 8408L +#define ERROR_DS_DATABASE_ERROR 8409L +#define ERROR_DS_GOVERNSID_MISSING 8410L +#define ERROR_DS_MISSING_EXPECTED_ATT 8411L +#define ERROR_DS_NCNAME_MISSING_CR_REF 8412L +#define ERROR_DS_SECURITY_CHECKING_ERROR 8413L +#define ERROR_DS_SCHEMA_NOT_LOADED 8414L +#define ERROR_DS_SCHEMA_ALLOC_FAILED 8415L +#define ERROR_DS_ATT_SCHEMA_REQ_SYNTAX 8416L +#define ERROR_DS_GCVERIFY_ERROR 8417L +#define ERROR_DS_DRA_SCHEMA_MISMATCH 8418L +#define ERROR_DS_CANT_FIND_DSA_OBJ 8419L +#define ERROR_DS_CANT_FIND_EXPECTED_NC 8420L +#define ERROR_DS_CANT_FIND_NC_IN_CACHE 8421L +#define ERROR_DS_CANT_RETRIEVE_CHILD 8422L +#define ERROR_DS_SECURITY_ILLEGAL_MODIFY 8423L +#define ERROR_DS_CANT_REPLACE_HIDDEN_REC 8424L +#define ERROR_DS_BAD_HIERARCHY_FILE 8425L +#define ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED 8426L +#define ERROR_DS_CONFIG_PARAM_MISSING 8427L +#define ERROR_DS_COUNTING_AB_INDICES_FAILED 8428L +#define ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED 8429L +#define ERROR_DS_INTERNAL_FAILURE 8430L +#define ERROR_DS_UNKNOWN_ERROR 8431L +#define ERROR_DS_ROOT_REQUIRES_CLASS_TOP 8432L +#define ERROR_DS_REFUSING_FSMO_ROLES 8433L +#define ERROR_DS_MISSING_FSMO_SETTINGS 8434L +#define ERROR_DS_UNABLE_TO_SURRENDER_ROLES 8435L +#define ERROR_DS_DRA_GENERIC 8436L +#define ERROR_DS_DRA_INVALID_PARAMETER 8437L +#define ERROR_DS_DRA_BUSY 8438L +#define ERROR_DS_DRA_BAD_DN 8439L +#define ERROR_DS_DRA_BAD_NC 8440L +#define ERROR_DS_DRA_DN_EXISTS 8441L +#define ERROR_DS_DRA_INTERNAL_ERROR 8442L +#define ERROR_DS_DRA_INCONSISTENT_DIT 8443L +#define ERROR_DS_DRA_CONNECTION_FAILED 8444L +#define ERROR_DS_DRA_BAD_INSTANCE_TYPE 8445L +#define ERROR_DS_DRA_OUT_OF_MEM 8446L +#define ERROR_DS_DRA_MAIL_PROBLEM 8447L +#define ERROR_DS_DRA_REF_ALREADY_EXISTS 8448L +#define ERROR_DS_DRA_REF_NOT_FOUND 8449L +#define ERROR_DS_DRA_OBJ_IS_REP_SOURCE 8450L +#define ERROR_DS_DRA_DB_ERROR 8451L +#define ERROR_DS_DRA_NO_REPLICA 8452L +#define ERROR_DS_DRA_ACCESS_DENIED 8453L +#define ERROR_DS_DRA_NOT_SUPPORTED 8454L +#define ERROR_DS_DRA_RPC_CANCELLED 8455L +#define ERROR_DS_DRA_SOURCE_DISABLED 8456L +#define ERROR_DS_DRA_SINK_DISABLED 8457L +#define ERROR_DS_DRA_NAME_COLLISION 8458L +#define ERROR_DS_DRA_SOURCE_REINSTALLED 8459L +#define ERROR_DS_DRA_MISSING_PARENT 8460L +#define ERROR_DS_DRA_PREEMPTED 8461L +#define ERROR_DS_DRA_ABANDON_SYNC 8462L +#define ERROR_DS_DRA_SHUTDOWN 8463L +#define ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET 8464L +#define ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA 8465L +#define ERROR_DS_DRA_EXTN_CONNECTION_FAILED 8466L +#define ERROR_DS_INSTALL_SCHEMA_MISMATCH 8467L +#define ERROR_DS_DUP_LINK_ID 8468L +#define ERROR_DS_NAME_ERROR_RESOLVING 8469L +#define ERROR_DS_NAME_ERROR_NOT_FOUND 8470L +#define ERROR_DS_NAME_ERROR_NOT_UNIQUE 8471L +#define ERROR_DS_NAME_ERROR_NO_MAPPING 8472L +#define ERROR_DS_NAME_ERROR_DOMAIN_ONLY 8473L +#define ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING 8474L +#define ERROR_DS_CONSTRUCTED_ATT_MOD 8475L +#define ERROR_DS_WRONG_OM_OBJ_CLASS 8476L +#define ERROR_DS_DRA_REPL_PENDING 8477L +#define ERROR_DS_DS_REQUIRED 8478L +#define ERROR_DS_INVALID_LDAP_DISPLAY_NAME 8479L +#define ERROR_DS_NON_BASE_SEARCH 8480L +#define ERROR_DS_CANT_RETRIEVE_ATTS 8481L +#define ERROR_DS_BACKLINK_WITHOUT_LINK 8482L +#define ERROR_DS_EPOCH_MISMATCH 8483L +#define ERROR_DS_SRC_NAME_MISMATCH 8484L +#define ERROR_DS_SRC_AND_DST_NC_IDENTICAL 8485L +#define ERROR_DS_DST_NC_MISMATCH 8486L +#define ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC 8487L +#define ERROR_DS_SRC_GUID_MISMATCH 8488L +#define ERROR_DS_CANT_MOVE_DELETED_OBJECT 8489L +#define ERROR_DS_PDC_OPERATION_IN_PROGRESS 8490L +#define ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD 8491L +#define ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION 8492L +#define ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS 8493L +#define ERROR_DS_NC_MUST_HAVE_NC_PARENT 8494L +#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE 8495L +#define ERROR_DS_DST_DOMAIN_NOT_NATIVE 8496L +#define ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER 8497L +#define ERROR_DS_CANT_MOVE_ACCOUNT_GROUP 8498L +#define ERROR_DS_CANT_MOVE_RESOURCE_GROUP 8499L +#define ERROR_DS_INVALID_SEARCH_FLAG 8500L +#define ERROR_DS_NO_TREE_DELETE_ABOVE_NC 8501L +#define ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE 8502L +#define ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE 8503L +#define ERROR_DS_SAM_INIT_FAILURE 8504L +#define ERROR_DS_SENSITIVE_GROUP_VIOLATION 8505L +#define ERROR_DS_CANT_MOD_PRIMARYGROUPID 8506L +#define ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD 8507L +#define ERROR_DS_NONSAFE_SCHEMA_CHANGE 8508L +#define ERROR_DS_SCHEMA_UPDATE_DISALLOWED 8509L +#define ERROR_DS_CANT_CREATE_UNDER_SCHEMA 8510L +#define ERROR_DS_INSTALL_NO_SRC_SCH_VERSION 8511L +#define ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE 8512L +#define ERROR_DS_INVALID_GROUP_TYPE 8513L +#define ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN 8514L +#define ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN 8515L +#define ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER 8516L +#define ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER 8517L +#define ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER 8518L +#define ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER 8519L +#define ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER 8520L +#define ERROR_DS_HAVE_PRIMARY_MEMBERS 8521L +#define ERROR_DS_STRING_SD_CONVERSION_FAILED 8522L +#define ERROR_DS_NAMING_MASTER_GC 8523L +#define ERROR_DS_DNS_LOOKUP_FAILURE 8524L +#define ERROR_DS_COULDNT_UPDATE_SPNS 8525L +#define ERROR_DS_CANT_RETRIEVE_SD 8526L +#define ERROR_DS_KEY_NOT_UNIQUE 8527L +#define ERROR_DS_WRONG_LINKED_ATT_SYNTAX 8528L +#define ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD 8529L +#define ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY 8530L +#define ERROR_DS_CANT_START 8531L +#define ERROR_DS_INIT_FAILURE 8532L +#define ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION 8533L +#define ERROR_DS_SOURCE_DOMAIN_IN_FOREST 8534L +#define ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST 8535L +#define ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED 8536L +#define ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN 8537L +#define ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER 8538L +#define ERROR_DS_SRC_SID_EXISTS_IN_FOREST 8539L +#define ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH 8540L +#define ERROR_SAM_INIT_FAILURE 8541L +#define ERROR_DS_DRA_SCHEMA_INFO_SHIP 8542L +#define ERROR_DS_DRA_SCHEMA_CONFLICT 8543L +#define ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT 8544L +#define ERROR_DS_DRA_OBJ_NC_MISMATCH 8545L +#define ERROR_DS_NC_STILL_HAS_DSAS 8546L +#define ERROR_DS_GC_REQUIRED 8547L +#define ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY 8548L +#define ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS 8549L +#define ERROR_DS_CANT_ADD_TO_GC 8550L +#define ERROR_DS_NO_CHECKPOINT_WITH_PDC 8551L +#define ERROR_DS_SOURCE_AUDITING_NOT_ENABLED 8552L +#define ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC 8553L +#define ERROR_DS_INVALID_NAME_FOR_SPN 8554L +#define ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS 8555L +#define ERROR_DS_UNICODEPWD_NOT_IN_QUOTES 8556L +#define ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED 8557L +#define ERROR_DS_MUST_BE_RUN_ON_DST_DC 8558L +#define ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER 8559L +#define ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ 8560L +#define ERROR_DS_INIT_FAILURE_CONSOLE 8561L +#define ERROR_DS_SAM_INIT_FAILURE_CONSOLE 8562L +#define ERROR_DS_FOREST_VERSION_TOO_HIGH 8563L +#define ERROR_DS_DOMAIN_VERSION_TOO_HIGH 8564L +#define ERROR_DS_FOREST_VERSION_TOO_LOW 8565L +#define ERROR_DS_DOMAIN_VERSION_TOO_LOW 8566L +#define ERROR_DS_INCOMPATIBLE_VERSION 8567L +#define ERROR_DS_LOW_DSA_VERSION 8568L +#define ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN 8569L +#define ERROR_DS_NOT_SUPPORTED_SORT_ORDER 8570L +#define ERROR_DS_NAME_NOT_UNIQUE 8571L +#define ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4 8572L +#define ERROR_DS_OUT_OF_VERSION_STORE 8573L +#define ERROR_DS_INCOMPATIBLE_CONTROLS_USED 8574L +#define ERROR_DS_NO_REF_DOMAIN 8575L +#define ERROR_DS_RESERVED_LINK_ID 8576L +#define ERROR_DS_LINK_ID_NOT_AVAILABLE 8577L +#define ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER 8578L +#define ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE 8579L +#define ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC 8580L +#define ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG 8581L +#define ERROR_DS_MODIFYDN_WRONG_GRANDPARENT 8582L +#define ERROR_DS_NAME_ERROR_TRUST_REFERRAL 8583L +#define ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER 8584L +#define ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD 8585L +#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2 8586L +#define ERROR_DS_THREAD_LIMIT_EXCEEDED 8587L +#define ERROR_DS_NOT_CLOSEST 8588L +#define ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF 8589L +#define ERROR_DS_SINGLE_USER_MODE_FAILED 8590L +#define ERROR_DS_NTDSCRIPT_SYNTAX_ERROR 8591L +#define ERROR_DS_NTDSCRIPT_PROCESS_ERROR 8592L +#define ERROR_DS_DIFFERENT_REPL_EPOCHS 8593L +#define ERROR_DS_DRS_EXTENSIONS_CHANGED 8594L +#define ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR 8595L +#define ERROR_DS_NO_MSDS_INTID 8596L +#define ERROR_DS_DUP_MSDS_INTID 8597L +#define ERROR_DS_EXISTS_IN_RDNATTID 8598L +#define ERROR_DS_AUTHORIZATION_FAILED 8599L +#define ERROR_DS_INVALID_SCRIPT 8600L +#define ERROR_DS_REMOTE_CROSSREF_OP_FAILED 8601L +#define ERROR_DS_CROSS_REF_BUSY 8602L +#define ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN 8603L +#define ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC 8604L +#define ERROR_DS_DUPLICATE_ID_FOUND 8605L +#define ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT 8606L +#define ERROR_DS_GROUP_CONVERSION_ERROR 8607L +#define ERROR_DS_CANT_MOVE_APP_BASIC_GROUP 8608L +#define ERROR_DS_CANT_MOVE_APP_QUERY_GROUP 8609L +#define ERROR_DS_ROLE_NOT_VERIFIED 8610L +#define ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL 8611L +#define ERROR_DS_DOMAIN_RENAME_IN_PROGRESS 8612L +#define ERROR_DS_EXISTING_AD_CHILD_NC 8613L +#define ERROR_DS_REPL_LIFETIME_EXCEEDED 8614L +#define ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER 8615L +#define ERROR_DS_LDAP_SEND_QUEUE_FULL 8616L +#define ERROR_DS_DRA_OUT_SCHEDULE_WINDOW 8617L +#define DNS_ERROR_RESPONSE_CODES_BASE 9000 +#define DNS_ERROR_RCODE_NO_ERROR NO_ERROR +#define DNS_ERROR_MASK 0x00002328 +#define DNS_ERROR_RCODE_FORMAT_ERROR 9001L +#define DNS_ERROR_RCODE_SERVER_FAILURE 9002L +#define DNS_ERROR_RCODE_NAME_ERROR 9003L +#define DNS_ERROR_RCODE_NOT_IMPLEMENTED 9004L +#define DNS_ERROR_RCODE_REFUSED 9005L +#define DNS_ERROR_RCODE_YXDOMAIN 9006L +#define DNS_ERROR_RCODE_YXRRSET 9007L +#define DNS_ERROR_RCODE_NXRRSET 9008L +#define DNS_ERROR_RCODE_NOTAUTH 9009L +#define DNS_ERROR_RCODE_NOTZONE 9010L +#define DNS_ERROR_RCODE_BADSIG 9016L +#define DNS_ERROR_RCODE_BADKEY 9017L +#define DNS_ERROR_RCODE_BADTIME 9018L +#define DNS_ERROR_RCODE_LAST DNS_ERROR_RCODE_BADTIME +#define DNS_ERROR_PACKET_FMT_BASE 9500 +#define DNS_INFO_NO_RECORDS 9501L +#define DNS_ERROR_BAD_PACKET 9502L +#define DNS_ERROR_NO_PACKET 9503L +#define DNS_ERROR_RCODE 9504L +#define DNS_ERROR_UNSECURE_PACKET 9505L +#define DNS_STATUS_PACKET_UNSECURE DNS_ERROR_UNSECURE_PACKET +#define DNS_ERROR_NO_MEMORY ERROR_OUTOFMEMORY +#define DNS_ERROR_INVALID_NAME ERROR_INVALID_NAME +#define DNS_ERROR_INVALID_DATA ERROR_INVALID_DATA +#define DNS_ERROR_GENERAL_API_BASE 9550 +#define DNS_ERROR_INVALID_TYPE 9551L +#define DNS_ERROR_INVALID_IP_ADDRESS 9552L +#define DNS_ERROR_INVALID_PROPERTY 9553L +#define DNS_ERROR_TRY_AGAIN_LATER 9554L +#define DNS_ERROR_NOT_UNIQUE 9555L +#define DNS_ERROR_NON_RFC_NAME 9556L +#define DNS_STATUS_FQDN 9557L +#define DNS_STATUS_DOTTED_NAME 9558L +#define DNS_STATUS_SINGLE_PART_NAME 9559L +#define DNS_ERROR_INVALID_NAME_CHAR 9560L +#define DNS_ERROR_NUMERIC_NAME 9561L +#define DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER 9562L +#define DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION 9563L +#define DNS_ERROR_CANNOT_FIND_ROOT_HINTS 9564L +#define DNS_ERROR_INCONSISTENT_ROOT_HINTS 9565L +#define DNS_ERROR_ZONE_BASE 9600 +#define DNS_ERROR_ZONE_DOES_NOT_EXIST 9601L +#define DNS_ERROR_NO_ZONE_INFO 9602L +#define DNS_ERROR_INVALID_ZONE_OPERATION 9603L +#define DNS_ERROR_ZONE_CONFIGURATION_ERROR 9604L +#define DNS_ERROR_ZONE_HAS_NO_SOA_RECORD 9605L +#define DNS_ERROR_ZONE_HAS_NO_NS_RECORDS 9606L +#define DNS_ERROR_ZONE_LOCKED 9607L +#define DNS_ERROR_ZONE_CREATION_FAILED 9608L +#define DNS_ERROR_ZONE_ALREADY_EXISTS 9609L +#define DNS_ERROR_AUTOZONE_ALREADY_EXISTS 9610L +#define DNS_ERROR_INVALID_ZONE_TYPE 9611L +#define DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP 9612L +#define DNS_ERROR_ZONE_NOT_SECONDARY 9613L +#define DNS_ERROR_NEED_SECONDARY_ADDRESSES 9614L +#define DNS_ERROR_WINS_INIT_FAILED 9615L +#define DNS_ERROR_NEED_WINS_SERVERS 9616L +#define DNS_ERROR_NBSTAT_INIT_FAILED 9617L +#define DNS_ERROR_SOA_DELETE_INVALID 9618L +#define DNS_ERROR_FORWARDER_ALREADY_EXISTS 9619L +#define DNS_ERROR_ZONE_REQUIRES_MASTER_IP 9620L +#define DNS_ERROR_ZONE_IS_SHUTDOWN 9621L +#define DNS_ERROR_DATAFILE_BASE 9650 +#define DNS_ERROR_PRIMARY_REQUIRES_DATAFILE 9651L +#define DNS_ERROR_INVALID_DATAFILE_NAME 9652L +#define DNS_ERROR_DATAFILE_OPEN_FAILURE 9653L +#define DNS_ERROR_FILE_WRITEBACK_FAILED 9654L +#define DNS_ERROR_DATAFILE_PARSING 9655L +#define DNS_ERROR_DATABASE_BASE 9700 +#define DNS_ERROR_RECORD_DOES_NOT_EXIST 9701L +#define DNS_ERROR_RECORD_FORMAT 9702L +#define DNS_ERROR_NODE_CREATION_FAILED 9703L +#define DNS_ERROR_UNKNOWN_RECORD_TYPE 9704L +#define DNS_ERROR_RECORD_TIMED_OUT 9705L +#define DNS_ERROR_NAME_NOT_IN_ZONE 9706L +#define DNS_ERROR_CNAME_LOOP 9707L +#define DNS_ERROR_NODE_IS_CNAME 9708L +#define DNS_ERROR_CNAME_COLLISION 9709L +#define DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT 9710L +#define DNS_ERROR_RECORD_ALREADY_EXISTS 9711L +#define DNS_ERROR_SECONDARY_DATA 9712L +#define DNS_ERROR_NO_CREATE_CACHE_DATA 9713L +#define DNS_ERROR_NAME_DOES_NOT_EXIST 9714L +#define DNS_WARNING_PTR_CREATE_FAILED 9715L +#define DNS_WARNING_DOMAIN_UNDELETED 9716L +#define DNS_ERROR_DS_UNAVAILABLE 9717L +#define DNS_ERROR_DS_ZONE_ALREADY_EXISTS 9718L +#define DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE 9719L +#define DNS_ERROR_OPERATION_BASE 9750 +#define DNS_INFO_AXFR_COMPLETE 9751L +#define DNS_ERROR_AXFR 9752L +#define DNS_INFO_ADDED_LOCAL_WINS 9753L +#define DNS_ERROR_SECURE_BASE 9800 +#define DNS_STATUS_CONTINUE_NEEDED 9801L +#define DNS_ERROR_SETUP_BASE 9850 +#define DNS_ERROR_NO_TCPIP 9851L +#define DNS_ERROR_NO_DNS_SERVERS 9852L +#define DNS_ERROR_DP_BASE 9900 +#define DNS_ERROR_DP_DOES_NOT_EXIST 9901L +#define DNS_ERROR_DP_ALREADY_EXISTS 9902L +#define DNS_ERROR_DP_NOT_ENLISTED 9903L +#define DNS_ERROR_DP_ALREADY_ENLISTED 9904L +#define DNS_ERROR_DP_NOT_AVAILABLE 9905L +#define DNS_ERROR_DP_FSMO_ERROR 9906L + +#ifndef WSABASEERR +#define WSABASEERR 10000 +#define WSAEINTR 10004L +#define WSAEBADF 10009L +#define WSAEACCES 10013L +#define WSAEFAULT 10014L +#define WSAEINVAL 10022L +#define WSAEMFILE 10024L +#define WSAEWOULDBLOCK 10035L +#define WSAEINPROGRESS 10036L +#define WSAEALREADY 10037L +#define WSAENOTSOCK 10038L +#define WSAEDESTADDRREQ 10039L +#define WSAEMSGSIZE 10040L +#define WSAEPROTOTYPE 10041L +#define WSAENOPROTOOPT 10042L +#define WSAEPROTONOSUPPORT 10043L +#define WSAESOCKTNOSUPPORT 10044L +#define WSAEOPNOTSUPP 10045L +#define WSAEPFNOSUPPORT 10046L +#define WSAEAFNOSUPPORT 10047L +#define WSAEADDRINUSE 10048L +#define WSAEADDRNOTAVAIL 10049L +#define WSAENETDOWN 10050L +#define WSAENETUNREACH 10051L +#define WSAENETRESET 10052L +#define WSAECONNABORTED 10053L +#define WSAECONNRESET 10054L +#define WSAENOBUFS 10055L +#define WSAEISCONN 10056L +#define WSAENOTCONN 10057L +#define WSAESHUTDOWN 10058L +#define WSAETOOMANYREFS 10059L +#define WSAETIMEDOUT 10060L +#define WSAECONNREFUSED 10061L +#define WSAELOOP 10062L +#define WSAENAMETOOLONG 10063L +#define WSAEHOSTDOWN 10064L +#define WSAEHOSTUNREACH 10065L +#define WSAENOTEMPTY 10066L +#define WSAEPROCLIM 10067L +#define WSAEUSERS 10068L +#define WSAEDQUOT 10069L +#define WSAESTALE 10070L +#define WSAEREMOTE 10071L +#define WSASYSNOTREADY 10091L +#define WSAVERNOTSUPPORTED 10092L +#define WSANOTINITIALISED 10093L +#define WSAEDISCON 10101L +#define WSAENOMORE 10102L +#define WSAECANCELLED 10103L +#define WSAEINVALIDPROCTABLE 10104L +#define WSAEINVALIDPROVIDER 10105L +#define WSAEPROVIDERFAILEDINIT 10106L +#define WSASYSCALLFAILURE 10107L +#define WSASERVICE_NOT_FOUND 10108L +#define WSATYPE_NOT_FOUND 10109L +#define WSA_E_NO_MORE 10110L +#define WSA_E_CANCELLED 10111L +#define WSAEREFUSED 10112L +#ifndef WSAHOST_NOT_FOUND +#define WSAHOST_NOT_FOUND 11001L +#endif +#ifndef WSATRY_AGAIN +#define WSATRY_AGAIN 11002L +#endif +#ifndef WSANO_RECOVERY +#define WSANO_RECOVERY 11003L +#endif +#ifndef WSANO_DATA +#define WSANO_DATA 11004L +#endif +#ifndef WSA_QOS_RECEIVERS +#define WSA_QOS_RECEIVERS 11005L +#endif +#ifndef WSA_QOS_SENDERS +#define WSA_QOS_SENDERS 11006L +#endif +#ifndef WSA_QOS_NO_SENDERS +#define WSA_QOS_NO_SENDERS 11007L +#endif +#ifndef WSA_QOS_NO_RECEIVERS +#define WSA_QOS_NO_RECEIVERS 11008L +#endif +#ifndef WSA_QOS_REQUEST_CONFIRMED +#define WSA_QOS_REQUEST_CONFIRMED 11009L +#endif +#ifndef WSA_QOS_ADMISSION_FAILURE +#define WSA_QOS_ADMISSION_FAILURE 11010L +#endif +#ifndef WSA_QOS_POLICY_FAILURE +#define WSA_QOS_POLICY_FAILURE 11011L +#endif +#ifndef WSA_QOS_BAD_STYLE +#define WSA_QOS_BAD_STYLE 11012L +#endif +#ifndef WSA_QOS_BAD_OBJECT +#define WSA_QOS_BAD_OBJECT 11013L +#endif +#ifndef WSA_QOS_TRAFFIC_CTRL_ERROR +#define WSA_QOS_TRAFFIC_CTRL_ERROR 11014L +#endif +#ifndef WSA_QOS_GENERIC_ERROR +#define WSA_QOS_GENERIC_ERROR 11015L +#endif +#ifndef WSA_QOS_ESERVICETYPE +#define WSA_QOS_ESERVICETYPE 11016L +#endif +#ifndef WSA_QOS_EFLOWSPEC +#define WSA_QOS_EFLOWSPEC 11017L +#endif +#ifndef WSA_QOS_EPROVSPECBUF +#define WSA_QOS_EPROVSPECBUF 11018L +#endif +#ifndef WSA_QOS_EFILTERSTYLE +#define WSA_QOS_EFILTERSTYLE 11019L +#endif +#ifndef WSA_QOS_EFILTERTYPE +#define WSA_QOS_EFILTERTYPE 11020L +#endif +#ifndef WSA_QOS_EFILTERCOUNT +#define WSA_QOS_EFILTERCOUNT 11021L +#endif +#ifndef WSA_QOS_EOBJLENGTH +#define WSA_QOS_EOBJLENGTH 11022L +#endif +#ifndef WSA_QOS_EFLOWCOUNT +#define WSA_QOS_EFLOWCOUNT 11023L +#endif +#ifndef WSA_QOS_EUNKNOWNPSOBJ +#define WSA_QOS_EUNKNOWNPSOBJ 11024L +#endif +#ifndef WSA_QOS_EPOLICYOBJ +#define WSA_QOS_EPOLICYOBJ 11025L +#endif +#ifndef WSA_QOS_EFLOWDESC +#define WSA_QOS_EFLOWDESC 11026L +#endif +#ifndef WSA_QOS_EPSFLOWSPEC +#define WSA_QOS_EPSFLOWSPEC 11027L +#endif +#ifndef WSA_QOS_EPSFILTERSPEC +#define WSA_QOS_EPSFILTERSPEC 11028L +#endif +#ifndef WSA_QOS_ESDMODEOBJ +#define WSA_QOS_ESDMODEOBJ 11029L +#endif +#ifndef WSA_QOS_ESHAPERATEOBJ +#define WSA_QOS_ESHAPERATEOBJ 11030L +#endif +#ifndef WSA_QOS_RESERVED_PETYPE +#define WSA_QOS_RESERVED_PETYPE 11031L +#endif +#endif /* WSABASEERR */ + +#define ERROR_SXS_SECTION_NOT_FOUND 14000L +#define ERROR_SXS_CANT_GEN_ACTCTX 14001L +#define ERROR_SXS_INVALID_ACTCTXDATA_FORMAT 14002L +#define ERROR_SXS_ASSEMBLY_NOT_FOUND 14003L +#define ERROR_SXS_MANIFEST_FORMAT_ERROR 14004L +#define ERROR_SXS_MANIFEST_PARSE_ERROR 14005L +#define ERROR_SXS_ACTIVATION_CONTEXT_DISABLED 14006L +#define ERROR_SXS_KEY_NOT_FOUND 14007L +#define ERROR_SXS_VERSION_CONFLICT 14008L +#define ERROR_SXS_WRONG_SECTION_TYPE 14009L +#define ERROR_SXS_THREAD_QUERIES_DISABLED 14010L +#define ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET 14011L +#define ERROR_SXS_UNKNOWN_ENCODING_GROUP 14012L +#define ERROR_SXS_UNKNOWN_ENCODING 14013L +#define ERROR_SXS_INVALID_XML_NAMESPACE_URI 14014L +#define ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED 14015L +#define ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED 14016L +#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE 14017L +#define ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE 14018L +#define ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE 14019L +#define ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT 14020L +#define ERROR_SXS_DUPLICATE_DLL_NAME 14021L +#define ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME 14022L +#define ERROR_SXS_DUPLICATE_CLSID 14023L +#define ERROR_SXS_DUPLICATE_IID 14024L +#define ERROR_SXS_DUPLICATE_TLBID 14025L +#define ERROR_SXS_DUPLICATE_PROGID 14026L +#define ERROR_SXS_DUPLICATE_ASSEMBLY_NAME 14027L +#define ERROR_SXS_FILE_HASH_MISMATCH 14028L +#define ERROR_SXS_POLICY_PARSE_ERROR 14029L +#define ERROR_SXS_XML_E_MISSINGQUOTE 14030L +#define ERROR_SXS_XML_E_COMMENTSYNTAX 14031L +#define ERROR_SXS_XML_E_BADSTARTNAMECHAR 14032L +#define ERROR_SXS_XML_E_BADNAMECHAR 14033L +#define ERROR_SXS_XML_E_BADCHARINSTRING 14034L +#define ERROR_SXS_XML_E_XMLDECLSYNTAX 14035L +#define ERROR_SXS_XML_E_BADCHARDATA 14036L +#define ERROR_SXS_XML_E_MISSINGWHITESPACE 14037L +#define ERROR_SXS_XML_E_EXPECTINGTAGEND 14038L +#define ERROR_SXS_XML_E_MISSINGSEMICOLON 14039L +#define ERROR_SXS_XML_E_UNBALANCEDPAREN 14040L +#define ERROR_SXS_XML_E_INTERNALERROR 14041L +#define ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE 14042L +#define ERROR_SXS_XML_E_INCOMPLETE_ENCODING 14043L +#define ERROR_SXS_XML_E_MISSING_PAREN 14044L +#define ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE 14045L +#define ERROR_SXS_XML_E_MULTIPLE_COLONS 14046L +#define ERROR_SXS_XML_E_INVALID_DECIMAL 14047L +#define ERROR_SXS_XML_E_INVALID_HEXIDECIMAL 14048L +#define ERROR_SXS_XML_E_INVALID_UNICODE 14049L +#define ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK 14050L +#define ERROR_SXS_XML_E_UNEXPECTEDENDTAG 14051L +#define ERROR_SXS_XML_E_UNCLOSEDTAG 14052L +#define ERROR_SXS_XML_E_DUPLICATEATTRIBUTE 14053L +#define ERROR_SXS_XML_E_MULTIPLEROOTS 14054L +#define ERROR_SXS_XML_E_INVALIDATROOTLEVEL 14055L +#define ERROR_SXS_XML_E_BADXMLDECL 14056L +#define ERROR_SXS_XML_E_MISSINGROOT 14057L +#define ERROR_SXS_XML_E_UNEXPECTEDEOF 14058L +#define ERROR_SXS_XML_E_BADPEREFINSUBSET 14059L +#define ERROR_SXS_XML_E_UNCLOSEDSTARTTAG 14060L +#define ERROR_SXS_XML_E_UNCLOSEDENDTAG 14061L +#define ERROR_SXS_XML_E_UNCLOSEDSTRING 14062L +#define ERROR_SXS_XML_E_UNCLOSEDCOMMENT 14063L +#define ERROR_SXS_XML_E_UNCLOSEDDECL 14064L +#define ERROR_SXS_XML_E_UNCLOSEDCDATA 14065L +#define ERROR_SXS_XML_E_RESERVEDNAMESPACE 14066L +#define ERROR_SXS_XML_E_INVALIDENCODING 14067L +#define ERROR_SXS_XML_E_INVALIDSWITCH 14068L +#define ERROR_SXS_XML_E_BADXMLCASE 14069L +#define ERROR_SXS_XML_E_INVALID_STANDALONE 14070L +#define ERROR_SXS_XML_E_UNEXPECTED_STANDALONE 14071L +#define ERROR_SXS_XML_E_INVALID_VERSION 14072L +#define ERROR_SXS_XML_E_MISSINGEQUALS 14073L +#define ERROR_SXS_PROTECTION_RECOVERY_FAILED 14074L +#define ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT 14075L +#define ERROR_SXS_PROTECTION_CATALOG_NOT_VALID 14076L +#define ERROR_SXS_UNTRANSLATABLE_HRESULT 14077L +#define ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING 14078L +#define ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE 14079L +#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME 14080L +#define ERROR_IPSEC_QM_POLICY_EXISTS 13000L +#define ERROR_IPSEC_QM_POLICY_NOT_FOUND 13001L +#define ERROR_IPSEC_QM_POLICY_IN_USE 13002L +#define ERROR_IPSEC_MM_POLICY_EXISTS 13003L +#define ERROR_IPSEC_MM_POLICY_NOT_FOUND 13004L +#define ERROR_IPSEC_MM_POLICY_IN_USE 13005L +#define ERROR_IPSEC_MM_FILTER_EXISTS 13006L +#define ERROR_IPSEC_MM_FILTER_NOT_FOUND 13007L +#define ERROR_IPSEC_TRANSPORT_FILTER_EXISTS 13008L +#define ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND 13009L +#define ERROR_IPSEC_MM_AUTH_EXISTS 13010L +#define ERROR_IPSEC_MM_AUTH_NOT_FOUND 13011L +#define ERROR_IPSEC_MM_AUTH_IN_USE 13012L +#define ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND 13013L +#define ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND 13014L +#define ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND 13015L +#define ERROR_IPSEC_TUNNEL_FILTER_EXISTS 13016L +#define ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND 13017L +#define ERROR_IPSEC_MM_FILTER_PENDING_DELETION 13018L +#define ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION 13019L +#define ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION 13020L +#define ERROR_IPSEC_MM_POLICY_PENDING_DELETION 13021L +#define ERROR_IPSEC_MM_AUTH_PENDING_DELETION 13022L +#define ERROR_IPSEC_QM_POLICY_PENDING_DELETION 13023L +#define WARNING_IPSEC_MM_POLICY_PRUNED 13024L +#define WARNING_IPSEC_QM_POLICY_PRUNED 13025L +#define ERROR_IPSEC_IKE_NEG_STATUS_BEGIN 13800L +#define ERROR_IPSEC_IKE_AUTH_FAIL 13801L +#define ERROR_IPSEC_IKE_ATTRIB_FAIL 13802L +#define ERROR_IPSEC_IKE_NEGOTIATION_PENDING 13803L +#define ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR 13804L +#define ERROR_IPSEC_IKE_TIMED_OUT 13805L +#define ERROR_IPSEC_IKE_NO_CERT 13806L +#define ERROR_IPSEC_IKE_SA_DELETED 13807L +#define ERROR_IPSEC_IKE_SA_REAPED 13808L +#define ERROR_IPSEC_IKE_MM_ACQUIRE_DROP 13809L +#define ERROR_IPSEC_IKE_QM_ACQUIRE_DROP 13810L +#define ERROR_IPSEC_IKE_QUEUE_DROP_MM 13811L +#define ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM 13812L +#define ERROR_IPSEC_IKE_DROP_NO_RESPONSE 13813L +#define ERROR_IPSEC_IKE_MM_DELAY_DROP 13814L +#define ERROR_IPSEC_IKE_QM_DELAY_DROP 13815L +#define ERROR_IPSEC_IKE_ERROR 13816L +#define ERROR_IPSEC_IKE_CRL_FAILED 13817L +#define ERROR_IPSEC_IKE_INVALID_KEY_USAGE 13818L +#define ERROR_IPSEC_IKE_INVALID_CERT_TYPE 13819L +#define ERROR_IPSEC_IKE_NO_PRIVATE_KEY 13820L +#define ERROR_IPSEC_IKE_DH_FAIL 13822L +#define ERROR_IPSEC_IKE_INVALID_HEADER 13824L +#define ERROR_IPSEC_IKE_NO_POLICY 13825L +#define ERROR_IPSEC_IKE_INVALID_SIGNATURE 13826L +#define ERROR_IPSEC_IKE_KERBEROS_ERROR 13827L +#define ERROR_IPSEC_IKE_NO_PUBLIC_KEY 13828L +#define ERROR_IPSEC_IKE_PROCESS_ERR 13829L +#define ERROR_IPSEC_IKE_PROCESS_ERR_SA 13830L +#define ERROR_IPSEC_IKE_PROCESS_ERR_PROP 13831L +#define ERROR_IPSEC_IKE_PROCESS_ERR_TRANS 13832L +#define ERROR_IPSEC_IKE_PROCESS_ERR_KE 13833L +#define ERROR_IPSEC_IKE_PROCESS_ERR_ID 13834L +#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT 13835L +#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ 13836L +#define ERROR_IPSEC_IKE_PROCESS_ERR_HASH 13837L +#define ERROR_IPSEC_IKE_PROCESS_ERR_SIG 13838L +#define ERROR_IPSEC_IKE_PROCESS_ERR_NONCE 13839L +#define ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY 13840L +#define ERROR_IPSEC_IKE_PROCESS_ERR_DELETE 13841L +#define ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR 13842L +#define ERROR_IPSEC_IKE_INVALID_PAYLOAD 13843L +#define ERROR_IPSEC_IKE_LOAD_SOFT_SA 13844L +#define ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN 13845L +#define ERROR_IPSEC_IKE_INVALID_COOKIE 13846L +#define ERROR_IPSEC_IKE_NO_PEER_CERT 13847L +#define ERROR_IPSEC_IKE_PEER_CRL_FAILED 13848L +#define ERROR_IPSEC_IKE_POLICY_CHANGE 13849L +#define ERROR_IPSEC_IKE_NO_MM_POLICY 13850L +#define ERROR_IPSEC_IKE_NOTCBPRIV 13851L +#define ERROR_IPSEC_IKE_SECLOADFAIL 13852L +#define ERROR_IPSEC_IKE_FAILSSPINIT 13853L +#define ERROR_IPSEC_IKE_FAILQUERYSSP 13854L +#define ERROR_IPSEC_IKE_SRVACQFAIL 13855L +#define ERROR_IPSEC_IKE_SRVQUERYCRED 13856L +#define ERROR_IPSEC_IKE_GETSPIFAIL 13857L +#define ERROR_IPSEC_IKE_INVALID_FILTER 13858L +#define ERROR_IPSEC_IKE_OUT_OF_MEMORY 13859L +#define ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED 13860L +#define ERROR_IPSEC_IKE_INVALID_POLICY 13861L +#define ERROR_IPSEC_IKE_UNKNOWN_DOI 13862L +#define ERROR_IPSEC_IKE_INVALID_SITUATION 13863L +#define ERROR_IPSEC_IKE_DH_FAILURE 13864L +#define ERROR_IPSEC_IKE_INVALID_GROUP 13865L +#define ERROR_IPSEC_IKE_ENCRYPT 13866L +#define ERROR_IPSEC_IKE_DECRYPT 13867L +#define ERROR_IPSEC_IKE_POLICY_MATCH 13868L +#define ERROR_IPSEC_IKE_UNSUPPORTED_ID 13869L +#define ERROR_IPSEC_IKE_INVALID_HASH 13870L +#define ERROR_IPSEC_IKE_INVALID_HASH_ALG 13871L +#define ERROR_IPSEC_IKE_INVALID_HASH_SIZE 13872L +#define ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG 13873L +#define ERROR_IPSEC_IKE_INVALID_AUTH_ALG 13874L +#define ERROR_IPSEC_IKE_INVALID_SIG 13875L +#define ERROR_IPSEC_IKE_LOAD_FAILED 13876L +#define ERROR_IPSEC_IKE_RPC_DELETE 13877L +#define ERROR_IPSEC_IKE_BENIGN_REINIT 13878L +#define ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY 13879L +#define ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN 13881L +#define ERROR_IPSEC_IKE_MM_LIMIT 13882L +#define ERROR_IPSEC_IKE_NEGOTIATION_DISABLED 13883L +#define ERROR_IPSEC_IKE_NEG_STATUS_END 13884L +#define SEVERITY_SUCCESS 0 +#define SEVERITY_ERROR 1 +#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) +#define FAILED(hr) ((HRESULT)(hr) < 0) +#define IS_ERROR(Status) ((unsigned long)(Status) >> 31==SEVERITY_ERROR) +#define HRESULT_CODE(hr) ((hr) & 0xFFFF) +#define SCODE_CODE(sc) ((sc) & 0xFFFF) +#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) +#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1fff) +#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) +#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1) +#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) +#define MAKE_SCODE(sev,fac,code) ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) +#define FACILITY_NT_BIT 0x10000000 +#define __HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) +#ifdef INLINE_HRESULT_FROM_WIN32 +#ifndef _HRESULT_DEFINED +#define _HRESULT_DEFINED +typedef long HRESULT; +#endif +__CRT_INLINE HRESULT HRESULT_FROM_WIN32(long x) { return x <= 0 ? (HRESULT)x : (HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000);} +#else +#define HRESULT_FROM_WIN32(x) __HRESULT_FROM_WIN32(x) +#endif +#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT)) +#define GetScode(hr) ((SCODE) (hr)) +#define ResultFromScode(sc) ((HRESULT) (sc)) +#define PropagateResult(hrPrevious,scBase) ((HRESULT) scBase) +#ifdef RC_INVOKED +#define _HRESULT_TYPEDEF_(_sc) _sc +#else +#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc) +#endif +#define NOERROR 0 +#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL) +#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L) +#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL) +#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L) +#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L) +#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L) +#define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L) +#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L) +#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L) +#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L) +#define E_PENDING _HRESULT_TYPEDEF_(0x8000000AL) +#define CO_E_INIT_TLS _HRESULT_TYPEDEF_(0x80004006L) +#define CO_E_INIT_SHARED_ALLOCATOR _HRESULT_TYPEDEF_(0x80004007L) +#define CO_E_INIT_MEMORY_ALLOCATOR _HRESULT_TYPEDEF_(0x80004008L) +#define CO_E_INIT_CLASS_CACHE _HRESULT_TYPEDEF_(0x80004009L) +#define CO_E_INIT_RPC_CHANNEL _HRESULT_TYPEDEF_(0x8000400AL) +#define CO_E_INIT_TLS_SET_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400BL) +#define CO_E_INIT_TLS_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400CL) +#define CO_E_INIT_UNACCEPTED_USER_ALLOCATOR _HRESULT_TYPEDEF_(0x8000400DL) +#define CO_E_INIT_SCM_MUTEX_EXISTS _HRESULT_TYPEDEF_(0x8000400EL) +#define CO_E_INIT_SCM_FILE_MAPPING_EXISTS _HRESULT_TYPEDEF_(0x8000400FL) +#define CO_E_INIT_SCM_MAP_VIEW_OF_FILE _HRESULT_TYPEDEF_(0x80004010L) +#define CO_E_INIT_SCM_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80004011L) +#define CO_E_INIT_ONLY_SINGLE_THREADED _HRESULT_TYPEDEF_(0x80004012L) +#define CO_E_CANT_REMOTE _HRESULT_TYPEDEF_(0x80004013L) +#define CO_E_BAD_SERVER_NAME _HRESULT_TYPEDEF_(0x80004014L) +#define CO_E_WRONG_SERVER_IDENTITY _HRESULT_TYPEDEF_(0x80004015L) +#define CO_E_OLE1DDE_DISABLED _HRESULT_TYPEDEF_(0x80004016L) +#define CO_E_RUNAS_SYNTAX _HRESULT_TYPEDEF_(0x80004017L) +#define CO_E_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004018L) +#define CO_E_RUNAS_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004019L) +#define CO_E_RUNAS_LOGON_FAILURE _HRESULT_TYPEDEF_(0x8000401AL) +#define CO_E_LAUNCH_PERMSSION_DENIED _HRESULT_TYPEDEF_(0x8000401BL) +#define CO_E_START_SERVICE_FAILURE _HRESULT_TYPEDEF_(0x8000401CL) +#define CO_E_REMOTE_COMMUNICATION_FAILURE _HRESULT_TYPEDEF_(0x8000401DL) +#define CO_E_SERVER_START_TIMEOUT _HRESULT_TYPEDEF_(0x8000401EL) +#define CO_E_CLSREG_INCONSISTENT _HRESULT_TYPEDEF_(0x8000401FL) +#define CO_E_IIDREG_INCONSISTENT _HRESULT_TYPEDEF_(0x80004020L) +#define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L) +#define CO_E_RELOAD_DLL _HRESULT_TYPEDEF_(0x80004022L) +#define CO_E_MSI_ERROR _HRESULT_TYPEDEF_(0x80004023L) +#define CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT _HRESULT_TYPEDEF_(0x80004024L) +#define CO_E_SERVER_PAUSED _HRESULT_TYPEDEF_(0x80004025L) +#define CO_E_SERVER_NOT_PAUSED _HRESULT_TYPEDEF_(0x80004026L) +#define CO_E_CLASS_DISABLED _HRESULT_TYPEDEF_(0x80004027L) +#define CO_E_CLRNOTAVAILABLE _HRESULT_TYPEDEF_(0x80004028L) +#define CO_E_ASYNC_WORK_REJECTED _HRESULT_TYPEDEF_(0x80004029L) +#define CO_E_SERVER_INIT_TIMEOUT _HRESULT_TYPEDEF_(0x8000402AL) +#define CO_E_NO_SECCTX_IN_ACTIVATE _HRESULT_TYPEDEF_(0x8000402BL) +#define CO_E_TRACKER_CONFIG _HRESULT_TYPEDEF_(0x80004030L) +#define CO_E_THREADPOOL_CONFIG _HRESULT_TYPEDEF_(0x80004031L) +#define CO_E_SXS_CONFIG _HRESULT_TYPEDEF_(0x80004032L) +#define CO_E_MALFORMED_SPN _HRESULT_TYPEDEF_(0x80004033L) +#define S_OK ((HRESULT)0x00000000L) +#define S_FALSE ((HRESULT)0x00000001L) +#define OLE_E_FIRST ((HRESULT)0x80040000L) +#define OLE_E_LAST ((HRESULT)0x800400FFL) +#define OLE_S_FIRST ((HRESULT)0x00040000L) +#define OLE_S_LAST ((HRESULT)0x000400FFL) +#define OLE_E_OLEVERB _HRESULT_TYPEDEF_(0x80040000L) +#define OLE_E_ADVF _HRESULT_TYPEDEF_(0x80040001L) +#define OLE_E_ENUM_NOMORE _HRESULT_TYPEDEF_(0x80040002L) +#define OLE_E_ADVISENOTSUPPORTED _HRESULT_TYPEDEF_(0x80040003L) +#define OLE_E_NOCONNECTION _HRESULT_TYPEDEF_(0x80040004L) +#define OLE_E_NOTRUNNING _HRESULT_TYPEDEF_(0x80040005L) +#define OLE_E_NOCACHE _HRESULT_TYPEDEF_(0x80040006L) +#define OLE_E_BLANK _HRESULT_TYPEDEF_(0x80040007L) +#define OLE_E_CLASSDIFF _HRESULT_TYPEDEF_(0x80040008L) +#define OLE_E_CANT_GETMONIKER _HRESULT_TYPEDEF_(0x80040009L) +#define OLE_E_CANT_BINDTOSOURCE _HRESULT_TYPEDEF_(0x8004000AL) +#define OLE_E_STATIC _HRESULT_TYPEDEF_(0x8004000BL) +#define OLE_E_PROMPTSAVECANCELLED _HRESULT_TYPEDEF_(0x8004000CL) +#define OLE_E_INVALIDRECT _HRESULT_TYPEDEF_(0x8004000DL) +#define OLE_E_WRONGCOMPOBJ _HRESULT_TYPEDEF_(0x8004000EL) +#define OLE_E_INVALIDHWND _HRESULT_TYPEDEF_(0x8004000FL) +#define OLE_E_NOT_INPLACEACTIVE _HRESULT_TYPEDEF_(0x80040010L) +#define OLE_E_CANTCONVERT _HRESULT_TYPEDEF_(0x80040011L) +#define OLE_E_NOSTORAGE _HRESULT_TYPEDEF_(0x80040012L) +#define DV_E_FORMATETC _HRESULT_TYPEDEF_(0x80040064L) +#define DV_E_DVTARGETDEVICE _HRESULT_TYPEDEF_(0x80040065L) +#define DV_E_STGMEDIUM _HRESULT_TYPEDEF_(0x80040066L) +#define DV_E_STATDATA _HRESULT_TYPEDEF_(0x80040067L) +#define DV_E_LINDEX _HRESULT_TYPEDEF_(0x80040068L) +#define DV_E_TYMED _HRESULT_TYPEDEF_(0x80040069L) +#define DV_E_CLIPFORMAT _HRESULT_TYPEDEF_(0x8004006AL) +#define DV_E_DVASPECT _HRESULT_TYPEDEF_(0x8004006BL) +#define DV_E_DVTARGETDEVICE_SIZE _HRESULT_TYPEDEF_(0x8004006CL) +#define DV_E_NOIVIEWOBJECT _HRESULT_TYPEDEF_(0x8004006DL) +#define DRAGDROP_E_FIRST 0x80040100L +#define DRAGDROP_E_LAST 0x8004010FL +#define DRAGDROP_S_FIRST 0x00040100L +#define DRAGDROP_S_LAST 0x0004010FL +#define DRAGDROP_E_NOTREGISTERED _HRESULT_TYPEDEF_(0x80040100L) +#define DRAGDROP_E_ALREADYREGISTERED _HRESULT_TYPEDEF_(0x80040101L) +#define DRAGDROP_E_INVALIDHWND _HRESULT_TYPEDEF_(0x80040102L) +#define CLASSFACTORY_E_FIRST 0x80040110L +#define CLASSFACTORY_E_LAST 0x8004011FL +#define CLASSFACTORY_S_FIRST 0x00040110L +#define CLASSFACTORY_S_LAST 0x0004011FL +#define CLASS_E_NOAGGREGATION _HRESULT_TYPEDEF_(0x80040110L) +#define CLASS_E_CLASSNOTAVAILABLE _HRESULT_TYPEDEF_(0x80040111L) +#define CLASS_E_NOTLICENSED _HRESULT_TYPEDEF_(0x80040112L) +#define MARSHAL_E_FIRST 0x80040120L +#define MARSHAL_E_LAST 0x8004012FL +#define MARSHAL_S_FIRST 0x00040120L +#define MARSHAL_S_LAST 0x0004012FL +#define DATA_E_FIRST 0x80040130L +#define DATA_E_LAST 0x8004013FL +#define DATA_S_FIRST 0x00040130L +#define DATA_S_LAST 0x0004013FL +#define VIEW_E_FIRST 0x80040140L +#define VIEW_E_LAST 0x8004014FL +#define VIEW_S_FIRST 0x00040140L +#define VIEW_S_LAST 0x0004014FL +#define VIEW_E_DRAW _HRESULT_TYPEDEF_(0x80040140L) +#define REGDB_E_FIRST 0x80040150L +#define REGDB_E_LAST 0x8004015FL +#define REGDB_S_FIRST 0x00040150L +#define REGDB_S_LAST 0x0004015FL +#define REGDB_E_READREGDB _HRESULT_TYPEDEF_(0x80040150L) +#define REGDB_E_WRITEREGDB _HRESULT_TYPEDEF_(0x80040151L) +#define REGDB_E_KEYMISSING _HRESULT_TYPEDEF_(0x80040152L) +#define REGDB_E_INVALIDVALUE _HRESULT_TYPEDEF_(0x80040153L) +#define REGDB_E_CLASSNOTREG _HRESULT_TYPEDEF_(0x80040154L) +#define REGDB_E_IIDNOTREG _HRESULT_TYPEDEF_(0x80040155L) +#define REGDB_E_BADTHREADINGMODEL _HRESULT_TYPEDEF_(0x80040156L) +#define CAT_E_FIRST 0x80040160L +#define CAT_E_LAST 0x80040161L +#define CAT_E_CATIDNOEXIST _HRESULT_TYPEDEF_(0x80040160L) +#define CAT_E_NODESCRIPTION _HRESULT_TYPEDEF_(0x80040161L) +#define CS_E_FIRST 0x80040164L +#define CS_E_LAST 0x8004016FL +#define CS_E_PACKAGE_NOTFOUND _HRESULT_TYPEDEF_(0x80040164L) +#define CS_E_NOT_DELETABLE _HRESULT_TYPEDEF_(0x80040165L) +#define CS_E_CLASS_NOTFOUND _HRESULT_TYPEDEF_(0x80040166L) +#define CS_E_INVALID_VERSION _HRESULT_TYPEDEF_(0x80040167L) +#define CS_E_NO_CLASSSTORE _HRESULT_TYPEDEF_(0x80040168L) +#define CS_E_OBJECT_NOTFOUND _HRESULT_TYPEDEF_(0x80040169L) +#define CS_E_OBJECT_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x8004016AL) +#define CS_E_INVALID_PATH _HRESULT_TYPEDEF_(0x8004016BL) +#define CS_E_NETWORK_ERROR _HRESULT_TYPEDEF_(0x8004016CL) +#define CS_E_ADMIN_LIMIT_EXCEEDED _HRESULT_TYPEDEF_(0x8004016DL) +#define CS_E_SCHEMA_MISMATCH _HRESULT_TYPEDEF_(0x8004016EL) +#define CS_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x8004016FL) +#define CACHE_E_FIRST 0x80040170L +#define CACHE_E_LAST 0x8004017FL +#define CACHE_S_FIRST 0x00040170L +#define CACHE_S_LAST 0x0004017FL +#define CACHE_E_NOCACHE_UPDATED _HRESULT_TYPEDEF_(0x80040170L) +#define OLEOBJ_E_FIRST 0x80040180L +#define OLEOBJ_E_LAST 0x8004018FL +#define OLEOBJ_S_FIRST 0x00040180L +#define OLEOBJ_S_LAST 0x0004018FL +#define OLEOBJ_E_NOVERBS _HRESULT_TYPEDEF_(0x80040180L) +#define OLEOBJ_E_INVALIDVERB _HRESULT_TYPEDEF_(0x80040181L) +#define CLIENTSITE_E_FIRST 0x80040190L +#define CLIENTSITE_E_LAST 0x8004019FL +#define CLIENTSITE_S_FIRST 0x00040190L +#define CLIENTSITE_S_LAST 0x0004019FL +#define INPLACE_E_NOTUNDOABLE _HRESULT_TYPEDEF_(0x800401A0L) +#define INPLACE_E_NOTOOLSPACE _HRESULT_TYPEDEF_(0x800401A1L) +#define INPLACE_E_FIRST 0x800401A0L +#define INPLACE_E_LAST 0x800401AFL +#define INPLACE_S_FIRST 0x000401A0L +#define INPLACE_S_LAST 0x000401AFL +#define ENUM_E_FIRST 0x800401B0L +#define ENUM_E_LAST 0x800401BFL +#define ENUM_S_FIRST 0x000401B0L +#define ENUM_S_LAST 0x000401BFL +#define CONVERT10_E_FIRST 0x800401C0L +#define CONVERT10_E_LAST 0x800401CFL +#define CONVERT10_S_FIRST 0x000401C0L +#define CONVERT10_S_LAST 0x000401CFL +#define CONVERT10_E_OLESTREAM_GET _HRESULT_TYPEDEF_(0x800401C0L) +#define CONVERT10_E_OLESTREAM_PUT _HRESULT_TYPEDEF_(0x800401C1L) +#define CONVERT10_E_OLESTREAM_FMT _HRESULT_TYPEDEF_(0x800401C2L) +#define CONVERT10_E_OLESTREAM_BITMAP_TO_DIB _HRESULT_TYPEDEF_(0x800401C3L) +#define CONVERT10_E_STG_FMT _HRESULT_TYPEDEF_(0x800401C4L) +#define CONVERT10_E_STG_NO_STD_STREAM _HRESULT_TYPEDEF_(0x800401C5L) +#define CONVERT10_E_STG_DIB_TO_BITMAP _HRESULT_TYPEDEF_(0x800401C6L) +#define CLIPBRD_E_FIRST 0x800401D0L +#define CLIPBRD_E_LAST 0x800401DFL +#define CLIPBRD_S_FIRST 0x000401D0L +#define CLIPBRD_S_LAST 0x000401DFL +#define CLIPBRD_E_CANT_OPEN _HRESULT_TYPEDEF_(0x800401D0L) +#define CLIPBRD_E_CANT_EMPTY _HRESULT_TYPEDEF_(0x800401D1L) +#define CLIPBRD_E_CANT_SET _HRESULT_TYPEDEF_(0x800401D2L) +#define CLIPBRD_E_BAD_DATA _HRESULT_TYPEDEF_(0x800401D3L) +#define CLIPBRD_E_CANT_CLOSE _HRESULT_TYPEDEF_(0x800401D4L) +#define MK_E_FIRST 0x800401E0L +#define MK_E_LAST 0x800401EFL +#define MK_S_FIRST 0x000401E0L +#define MK_S_LAST 0x000401EFL +#define MK_E_CONNECTMANUALLY _HRESULT_TYPEDEF_(0x800401E0L) +#define MK_E_EXCEEDEDDEADLINE _HRESULT_TYPEDEF_(0x800401E1L) +#define MK_E_NEEDGENERIC _HRESULT_TYPEDEF_(0x800401E2L) +#define MK_E_UNAVAILABLE _HRESULT_TYPEDEF_(0x800401E3L) +#define MK_E_SYNTAX _HRESULT_TYPEDEF_(0x800401E4L) +#define MK_E_NOOBJECT _HRESULT_TYPEDEF_(0x800401E5L) +#define MK_E_INVALIDEXTENSION _HRESULT_TYPEDEF_(0x800401E6L) +#define MK_E_INTERMEDIATEINTERFACENOTSUPPORTED _HRESULT_TYPEDEF_(0x800401E7L) +#define MK_E_NOTBINDABLE _HRESULT_TYPEDEF_(0x800401E8L) +#define MK_E_NOTBOUND _HRESULT_TYPEDEF_(0x800401E9L) +#define MK_E_CANTOPENFILE _HRESULT_TYPEDEF_(0x800401EAL) +#define MK_E_MUSTBOTHERUSER _HRESULT_TYPEDEF_(0x800401EBL) +#define MK_E_NOINVERSE _HRESULT_TYPEDEF_(0x800401ECL) +#define MK_E_NOSTORAGE _HRESULT_TYPEDEF_(0x800401EDL) +#define MK_E_NOPREFIX _HRESULT_TYPEDEF_(0x800401EEL) +#define MK_E_ENUMERATION_FAILED _HRESULT_TYPEDEF_(0x800401EFL) +#define CO_E_FIRST 0x800401F0L +#define CO_E_LAST 0x800401FFL +#define CO_S_FIRST 0x000401F0L +#define CO_S_LAST 0x000401FFL +#define CO_E_NOTINITIALIZED _HRESULT_TYPEDEF_(0x800401F0L) +#define CO_E_ALREADYINITIALIZED _HRESULT_TYPEDEF_(0x800401F1L) +#define CO_E_CANTDETERMINECLASS _HRESULT_TYPEDEF_(0x800401F2L) +#define CO_E_CLASSSTRING _HRESULT_TYPEDEF_(0x800401F3L) +#define CO_E_IIDSTRING _HRESULT_TYPEDEF_(0x800401F4L) +#define CO_E_APPNOTFOUND _HRESULT_TYPEDEF_(0x800401F5L) +#define CO_E_APPSINGLEUSE _HRESULT_TYPEDEF_(0x800401F6L) +#define CO_E_ERRORINAPP _HRESULT_TYPEDEF_(0x800401F7L) +#define CO_E_DLLNOTFOUND _HRESULT_TYPEDEF_(0x800401F8L) +#define CO_E_ERRORINDLL _HRESULT_TYPEDEF_(0x800401F9L) +#define CO_E_WRONGOSFORAPP _HRESULT_TYPEDEF_(0x800401FAL) +#define CO_E_OBJNOTREG _HRESULT_TYPEDEF_(0x800401FBL) +#define CO_E_OBJISREG _HRESULT_TYPEDEF_(0x800401FCL) +#define CO_E_OBJNOTCONNECTED _HRESULT_TYPEDEF_(0x800401FDL) +#define CO_E_APPDIDNTREG _HRESULT_TYPEDEF_(0x800401FEL) +#define CO_E_RELEASED _HRESULT_TYPEDEF_(0x800401FFL) +#define EVENT_E_FIRST 0x80040200L +#define EVENT_E_LAST 0x8004021FL +#define EVENT_S_FIRST 0x00040200L +#define EVENT_S_LAST 0x0004021FL +#define EVENT_S_SOME_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x00040200L) +#define EVENT_E_ALL_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x80040201L) +#define EVENT_S_NOSUBSCRIBERS _HRESULT_TYPEDEF_(0x00040202L) +#define EVENT_E_QUERYSYNTAX _HRESULT_TYPEDEF_(0x80040203L) +#define EVENT_E_QUERYFIELD _HRESULT_TYPEDEF_(0x80040204L) +#define EVENT_E_INTERNALEXCEPTION _HRESULT_TYPEDEF_(0x80040205L) +#define EVENT_E_INTERNALERROR _HRESULT_TYPEDEF_(0x80040206L) +#define EVENT_E_INVALID_PER_USER_SID _HRESULT_TYPEDEF_(0x80040207L) +#define EVENT_E_USER_EXCEPTION _HRESULT_TYPEDEF_(0x80040208L) +#define EVENT_E_TOO_MANY_METHODS _HRESULT_TYPEDEF_(0x80040209L) +#define EVENT_E_MISSING_EVENTCLASS _HRESULT_TYPEDEF_(0x8004020AL) +#define EVENT_E_NOT_ALL_REMOVED _HRESULT_TYPEDEF_(0x8004020BL) +#define EVENT_E_COMPLUS_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004020CL) +#define EVENT_E_CANT_MODIFY_OR_DELETE_UNCONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020DL) +#define EVENT_E_CANT_MODIFY_OR_DELETE_CONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020EL) +#define EVENT_E_INVALID_EVENT_CLASS_PARTITION _HRESULT_TYPEDEF_(0x8004020FL) +#define EVENT_E_PER_USER_SID_NOT_LOGGED_ON _HRESULT_TYPEDEF_(0x80040210L) +#define XACT_E_FIRST 0x8004D000 +#define XACT_E_LAST 0x8004D029 +#define XACT_S_FIRST 0x0004D000 +#define XACT_S_LAST 0x0004D010 +#define XACT_E_ALREADYOTHERSINGLEPHASE _HRESULT_TYPEDEF_(0x8004D000L) +#define XACT_E_CANTRETAIN _HRESULT_TYPEDEF_(0x8004D001L) +#define XACT_E_COMMITFAILED _HRESULT_TYPEDEF_(0x8004D002L) +#define XACT_E_COMMITPREVENTED _HRESULT_TYPEDEF_(0x8004D003L) +#define XACT_E_HEURISTICABORT _HRESULT_TYPEDEF_(0x8004D004L) +#define XACT_E_HEURISTICCOMMIT _HRESULT_TYPEDEF_(0x8004D005L) +#define XACT_E_HEURISTICDAMAGE _HRESULT_TYPEDEF_(0x8004D006L) +#define XACT_E_HEURISTICDANGER _HRESULT_TYPEDEF_(0x8004D007L) +#define XACT_E_ISOLATIONLEVEL _HRESULT_TYPEDEF_(0x8004D008L) +#define XACT_E_NOASYNC _HRESULT_TYPEDEF_(0x8004D009L) +#define XACT_E_NOENLIST _HRESULT_TYPEDEF_(0x8004D00AL) +#define XACT_E_NOISORETAIN _HRESULT_TYPEDEF_(0x8004D00BL) +#define XACT_E_NORESOURCE _HRESULT_TYPEDEF_(0x8004D00CL) +#define XACT_E_NOTCURRENT _HRESULT_TYPEDEF_(0x8004D00DL) +#define XACT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004D00EL) +#define XACT_E_NOTSUPPORTED _HRESULT_TYPEDEF_(0x8004D00FL) +#define XACT_E_UNKNOWNRMGRID _HRESULT_TYPEDEF_(0x8004D010L) +#define XACT_E_WRONGSTATE _HRESULT_TYPEDEF_(0x8004D011L) +#define XACT_E_WRONGUOW _HRESULT_TYPEDEF_(0x8004D012L) +#define XACT_E_XTIONEXISTS _HRESULT_TYPEDEF_(0x8004D013L) +#define XACT_E_NOIMPORTOBJECT _HRESULT_TYPEDEF_(0x8004D014L) +#define XACT_E_INVALIDCOOKIE _HRESULT_TYPEDEF_(0x8004D015L) +#define XACT_E_INDOUBT _HRESULT_TYPEDEF_(0x8004D016L) +#define XACT_E_NOTIMEOUT _HRESULT_TYPEDEF_(0x8004D017L) +#define XACT_E_ALREADYINPROGRESS _HRESULT_TYPEDEF_(0x8004D018L) +#define XACT_E_ABORTED _HRESULT_TYPEDEF_(0x8004D019L) +#define XACT_E_LOGFULL _HRESULT_TYPEDEF_(0x8004D01AL) +#define XACT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D01BL) +#define XACT_E_CONNECTION_DOWN _HRESULT_TYPEDEF_(0x8004D01CL) +#define XACT_E_CONNECTION_DENIED _HRESULT_TYPEDEF_(0x8004D01DL) +#define XACT_E_REENLISTTIMEOUT _HRESULT_TYPEDEF_(0x8004D01EL) +#define XACT_E_TIP_CONNECT_FAILED _HRESULT_TYPEDEF_(0x8004D01FL) +#define XACT_E_TIP_PROTOCOL_ERROR _HRESULT_TYPEDEF_(0x8004D020L) +#define XACT_E_TIP_PULL_FAILED _HRESULT_TYPEDEF_(0x8004D021L) +#define XACT_E_DEST_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D022L) +#define XACT_E_TIP_DISABLED _HRESULT_TYPEDEF_(0x8004D023L) +#define XACT_E_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D024L) +#define XACT_E_PARTNER_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D025L) +#define XACT_E_XA_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D026L) +#define XACT_E_UNABLE_TO_READ_DTC_CONFIG _HRESULT_TYPEDEF_(0x8004D027L) +#define XACT_E_UNABLE_TO_LOAD_DTC_PROXY _HRESULT_TYPEDEF_(0x8004D028L) +#define XACT_E_ABORTING _HRESULT_TYPEDEF_(0x8004D029L) +#define XACT_E_CLERKNOTFOUND _HRESULT_TYPEDEF_(0x8004D080L) +#define XACT_E_CLERKEXISTS _HRESULT_TYPEDEF_(0x8004D081L) +#define XACT_E_RECOVERYINPROGRESS _HRESULT_TYPEDEF_(0x8004D082L) +#define XACT_E_TRANSACTIONCLOSED _HRESULT_TYPEDEF_(0x8004D083L) +#define XACT_E_INVALIDLSN _HRESULT_TYPEDEF_(0x8004D084L) +#define XACT_E_REPLAYREQUEST _HRESULT_TYPEDEF_(0x8004D085L) +#define XACT_S_ASYNC _HRESULT_TYPEDEF_(0x0004D000L) +#define XACT_S_DEFECT _HRESULT_TYPEDEF_(0x0004D001L) +#define XACT_S_READONLY _HRESULT_TYPEDEF_(0x0004D002L) +#define XACT_S_SOMENORETAIN _HRESULT_TYPEDEF_(0x0004D003L) +#define XACT_S_OKINFORM _HRESULT_TYPEDEF_(0x0004D004L) +#define XACT_S_MADECHANGESCONTENT _HRESULT_TYPEDEF_(0x0004D005L) +#define XACT_S_MADECHANGESINFORM _HRESULT_TYPEDEF_(0x0004D006L) +#define XACT_S_ALLNORETAIN _HRESULT_TYPEDEF_(0x0004D007L) +#define XACT_S_ABORTING _HRESULT_TYPEDEF_(0x0004D008L) +#define XACT_S_SINGLEPHASE _HRESULT_TYPEDEF_(0x0004D009L) +#define XACT_S_LOCALLY_OK _HRESULT_TYPEDEF_(0x0004D00AL) +#define XACT_S_LASTRESOURCEMANAGER _HRESULT_TYPEDEF_(0x0004D010L) +#define CONTEXT_E_FIRST 0x8004E000L +#define CONTEXT_E_LAST 0x8004E02FL +#define CONTEXT_S_FIRST 0x0004E000L +#define CONTEXT_S_LAST 0x0004E02FL +#define CONTEXT_E_ABORTED _HRESULT_TYPEDEF_(0x8004E002L) +#define CONTEXT_E_ABORTING _HRESULT_TYPEDEF_(0x8004E003L) +#define CONTEXT_E_NOCONTEXT _HRESULT_TYPEDEF_(0x8004E004L) +#define CONTEXT_E_WOULD_DEADLOCK _HRESULT_TYPEDEF_(0x8004E005L) +#define CONTEXT_E_SYNCH_TIMEOUT _HRESULT_TYPEDEF_(0x8004E006L) +#define CONTEXT_E_OLDREF _HRESULT_TYPEDEF_(0x8004E007L) +#define CONTEXT_E_ROLENOTFOUND _HRESULT_TYPEDEF_(0x8004E00CL) +#define CONTEXT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004E00FL) +#define CO_E_ACTIVATIONFAILED _HRESULT_TYPEDEF_(0x8004E021L) +#define CO_E_ACTIVATIONFAILED_EVENTLOGGED _HRESULT_TYPEDEF_(0x8004E022L) +#define CO_E_ACTIVATIONFAILED_CATALOGERROR _HRESULT_TYPEDEF_(0x8004E023L) +#define CO_E_ACTIVATIONFAILED_TIMEOUT _HRESULT_TYPEDEF_(0x8004E024L) +#define CO_E_INITIALIZATIONFAILED _HRESULT_TYPEDEF_(0x8004E025L) +#define CONTEXT_E_NOJIT _HRESULT_TYPEDEF_(0x8004E026L) +#define CONTEXT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004E027L) +#define CO_E_THREADINGMODEL_CHANGED _HRESULT_TYPEDEF_(0x8004E028L) +#define CO_E_NOIISINTRINSICS _HRESULT_TYPEDEF_(0x8004E029L) +#define CO_E_NOCOOKIES _HRESULT_TYPEDEF_(0x8004E02AL) +#define CO_E_DBERROR _HRESULT_TYPEDEF_(0x8004E02BL) +#define CO_E_NOTPOOLED _HRESULT_TYPEDEF_(0x8004E02CL) +#define CO_E_NOTCONSTRUCTED _HRESULT_TYPEDEF_(0x8004E02DL) +#define CO_E_NOSYNCHRONIZATION _HRESULT_TYPEDEF_(0x8004E02EL) +#define CO_E_ISOLEVELMISMATCH _HRESULT_TYPEDEF_(0x8004E02FL) +#define OLE_S_USEREG _HRESULT_TYPEDEF_(0x00040000L) +#define OLE_S_STATIC _HRESULT_TYPEDEF_(0x00040001L) +#define OLE_S_MAC_CLIPFORMAT _HRESULT_TYPEDEF_(0x00040002L) +#define DRAGDROP_S_DROP _HRESULT_TYPEDEF_(0x00040100L) +#define DRAGDROP_S_CANCEL _HRESULT_TYPEDEF_(0x00040101L) +#define DRAGDROP_S_USEDEFAULTCURSORS _HRESULT_TYPEDEF_(0x00040102L) +#define DATA_S_SAMEFORMATETC _HRESULT_TYPEDEF_(0x00040130L) +#define VIEW_S_ALREADY_FROZEN _HRESULT_TYPEDEF_(0x00040140L) +#define CACHE_S_FORMATETC_NOTSUPPORTED _HRESULT_TYPEDEF_(0x00040170L) +#define CACHE_S_SAMECACHE _HRESULT_TYPEDEF_(0x00040171L) +#define CACHE_S_SOMECACHES_NOTUPDATED _HRESULT_TYPEDEF_(0x00040172L) +#define OLEOBJ_S_INVALIDVERB _HRESULT_TYPEDEF_(0x00040180L) +#define OLEOBJ_S_CANNOT_DOVERB_NOW _HRESULT_TYPEDEF_(0x00040181L) +#define OLEOBJ_S_INVALIDHWND _HRESULT_TYPEDEF_(0x00040182L) +#define INPLACE_S_TRUNCATED _HRESULT_TYPEDEF_(0x000401A0L) +#define CONVERT10_S_NO_PRESENTATION _HRESULT_TYPEDEF_(0x000401C0L) +#define MK_S_REDUCED_TO_SELF _HRESULT_TYPEDEF_(0x000401E2L) +#define MK_S_ME _HRESULT_TYPEDEF_(0x000401E4L) +#define MK_S_HIM _HRESULT_TYPEDEF_(0x000401E5L) +#define MK_S_US _HRESULT_TYPEDEF_(0x000401E6L) +#define MK_S_MONIKERALREADYREGISTERED _HRESULT_TYPEDEF_(0x000401E7L) +#define SCHED_S_TASK_READY _HRESULT_TYPEDEF_(0x00041300L) +#define SCHED_S_TASK_RUNNING _HRESULT_TYPEDEF_(0x00041301L) +#define SCHED_S_TASK_DISABLED _HRESULT_TYPEDEF_(0x00041302L) +#define SCHED_S_TASK_HAS_NOT_RUN _HRESULT_TYPEDEF_(0x00041303L) +#define SCHED_S_TASK_NO_MORE_RUNS _HRESULT_TYPEDEF_(0x00041304L) +#define SCHED_S_TASK_NOT_SCHEDULED _HRESULT_TYPEDEF_(0x00041305L) +#define SCHED_S_TASK_TERMINATED _HRESULT_TYPEDEF_(0x00041306L) +#define SCHED_S_TASK_NO_VALID_TRIGGERS _HRESULT_TYPEDEF_(0x00041307L) +#define SCHED_S_EVENT_TRIGGER _HRESULT_TYPEDEF_(0x00041308L) +#define SCHED_E_TRIGGER_NOT_FOUND _HRESULT_TYPEDEF_(0x80041309L) +#define SCHED_E_TASK_NOT_READY _HRESULT_TYPEDEF_(0x8004130AL) +#define SCHED_E_TASK_NOT_RUNNING _HRESULT_TYPEDEF_(0x8004130BL) +#define SCHED_E_SERVICE_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004130CL) +#define SCHED_E_CANNOT_OPEN_TASK _HRESULT_TYPEDEF_(0x8004130DL) +#define SCHED_E_INVALID_TASK _HRESULT_TYPEDEF_(0x8004130EL) +#define SCHED_E_ACCOUNT_INFORMATION_NOT_SET _HRESULT_TYPEDEF_(0x8004130FL) +#define SCHED_E_ACCOUNT_NAME_NOT_FOUND _HRESULT_TYPEDEF_(0x80041310L) +#define SCHED_E_ACCOUNT_DBASE_CORRUPT _HRESULT_TYPEDEF_(0x80041311L) +#define SCHED_E_NO_SECURITY_SERVICES _HRESULT_TYPEDEF_(0x80041312L) +#define SCHED_E_UNKNOWN_OBJECT_VERSION _HRESULT_TYPEDEF_(0x80041313L) +#define SCHED_E_UNSUPPORTED_ACCOUNT_OPTION _HRESULT_TYPEDEF_(0x80041314L) +#define SCHED_E_SERVICE_NOT_RUNNING _HRESULT_TYPEDEF_(0x80041315L) +#define CO_E_CLASS_CREATE_FAILED _HRESULT_TYPEDEF_(0x80080001L) +#define CO_E_SCM_ERROR _HRESULT_TYPEDEF_(0x80080002L) +#define CO_E_SCM_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080003L) +#define CO_E_BAD_PATH _HRESULT_TYPEDEF_(0x80080004L) +#define CO_E_SERVER_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80080005L) +#define CO_E_OBJSRV_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080006L) +#define MK_E_NO_NORMALIZED _HRESULT_TYPEDEF_(0x80080007L) +#define CO_E_SERVER_STOPPING _HRESULT_TYPEDEF_(0x80080008L) +#define MEM_E_INVALID_ROOT _HRESULT_TYPEDEF_(0x80080009L) +#define MEM_E_INVALID_LINK _HRESULT_TYPEDEF_(0x80080010L) +#define MEM_E_INVALID_SIZE _HRESULT_TYPEDEF_(0x80080011L) +#define CO_S_NOTALLINTERFACES _HRESULT_TYPEDEF_(0x00080012L) +#define CO_S_MACHINENAMENOTFOUND _HRESULT_TYPEDEF_(0x00080013L) +#define DISP_E_UNKNOWNINTERFACE _HRESULT_TYPEDEF_(0x80020001L) +#define DISP_E_MEMBERNOTFOUND _HRESULT_TYPEDEF_(0x80020003L) +#define DISP_E_PARAMNOTFOUND _HRESULT_TYPEDEF_(0x80020004L) +#define DISP_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80020005L) +#define DISP_E_UNKNOWNNAME _HRESULT_TYPEDEF_(0x80020006L) +#define DISP_E_NONAMEDARGS _HRESULT_TYPEDEF_(0x80020007L) +#define DISP_E_BADVARTYPE _HRESULT_TYPEDEF_(0x80020008L) +#define DISP_E_EXCEPTION _HRESULT_TYPEDEF_(0x80020009L) +#define DISP_E_OVERFLOW _HRESULT_TYPEDEF_(0x8002000AL) +#define DISP_E_BADINDEX _HRESULT_TYPEDEF_(0x8002000BL) +#define DISP_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002000CL) +#define DISP_E_ARRAYISLOCKED _HRESULT_TYPEDEF_(0x8002000DL) +#define DISP_E_BADPARAMCOUNT _HRESULT_TYPEDEF_(0x8002000EL) +#define DISP_E_PARAMNOTOPTIONAL _HRESULT_TYPEDEF_(0x8002000FL) +#define DISP_E_BADCALLEE _HRESULT_TYPEDEF_(0x80020010L) +#define DISP_E_NOTACOLLECTION _HRESULT_TYPEDEF_(0x80020011L) +#define DISP_E_DIVBYZERO _HRESULT_TYPEDEF_(0x80020012L) +#define DISP_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80020013L) +#define TYPE_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80028016L) +#define TYPE_E_FIELDNOTFOUND _HRESULT_TYPEDEF_(0x80028017L) +#define TYPE_E_INVDATAREAD _HRESULT_TYPEDEF_(0x80028018L) +#define TYPE_E_UNSUPFORMAT _HRESULT_TYPEDEF_(0x80028019L) +#define TYPE_E_REGISTRYACCESS _HRESULT_TYPEDEF_(0x8002801CL) +#define TYPE_E_LIBNOTREGISTERED _HRESULT_TYPEDEF_(0x8002801DL) +#define TYPE_E_UNDEFINEDTYPE _HRESULT_TYPEDEF_(0x80028027L) +#define TYPE_E_QUALIFIEDNAMEDISALLOWED _HRESULT_TYPEDEF_(0x80028028L) +#define TYPE_E_INVALIDSTATE _HRESULT_TYPEDEF_(0x80028029L) +#define TYPE_E_WRONGTYPEKIND _HRESULT_TYPEDEF_(0x8002802AL) +#define TYPE_E_ELEMENTNOTFOUND _HRESULT_TYPEDEF_(0x8002802BL) +#define TYPE_E_AMBIGUOUSNAME _HRESULT_TYPEDEF_(0x8002802CL) +#define TYPE_E_NAMECONFLICT _HRESULT_TYPEDEF_(0x8002802DL) +#define TYPE_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002802EL) +#define TYPE_E_DLLFUNCTIONNOTFOUND _HRESULT_TYPEDEF_(0x8002802FL) +#define TYPE_E_BADMODULEKIND _HRESULT_TYPEDEF_(0x800288BDL) +#define TYPE_E_SIZETOOBIG _HRESULT_TYPEDEF_(0x800288C5L) +#define TYPE_E_DUPLICATEID _HRESULT_TYPEDEF_(0x800288C6L) +#define TYPE_E_INVALIDID _HRESULT_TYPEDEF_(0x800288CFL) +#define TYPE_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80028CA0L) +#define TYPE_E_OUTOFBOUNDS _HRESULT_TYPEDEF_(0x80028CA1L) +#define TYPE_E_IOERROR _HRESULT_TYPEDEF_(0x80028CA2L) +#define TYPE_E_CANTCREATETMPFILE _HRESULT_TYPEDEF_(0x80028CA3L) +#define TYPE_E_CANTLOADLIBRARY _HRESULT_TYPEDEF_(0x80029C4AL) +#define TYPE_E_INCONSISTENTPROPFUNCS _HRESULT_TYPEDEF_(0x80029C83L) +#define TYPE_E_CIRCULARTYPE _HRESULT_TYPEDEF_(0x80029C84L) +#define STG_E_INVALIDFUNCTION _HRESULT_TYPEDEF_(0x80030001L) +#define STG_E_FILENOTFOUND _HRESULT_TYPEDEF_(0x80030002L) +#define STG_E_PATHNOTFOUND _HRESULT_TYPEDEF_(0x80030003L) +#define STG_E_TOOMANYOPENFILES _HRESULT_TYPEDEF_(0x80030004L) +#define STG_E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80030005L) +#define STG_E_INVALIDHANDLE _HRESULT_TYPEDEF_(0x80030006L) +#define STG_E_INSUFFICIENTMEMORY _HRESULT_TYPEDEF_(0x80030008L) +#define STG_E_INVALIDPOINTER _HRESULT_TYPEDEF_(0x80030009L) +#define STG_E_NOMOREFILES _HRESULT_TYPEDEF_(0x80030012L) +#define STG_E_DISKISWRITEPROTECTED _HRESULT_TYPEDEF_(0x80030013L) +#define STG_E_SEEKERROR _HRESULT_TYPEDEF_(0x80030019L) +#define STG_E_WRITEFAULT _HRESULT_TYPEDEF_(0x8003001DL) +#define STG_E_READFAULT _HRESULT_TYPEDEF_(0x8003001EL) +#define STG_E_SHAREVIOLATION _HRESULT_TYPEDEF_(0x80030020L) +#define STG_E_LOCKVIOLATION _HRESULT_TYPEDEF_(0x80030021L) +#define STG_E_FILEALREADYEXISTS _HRESULT_TYPEDEF_(0x80030050L) +#define STG_E_INVALIDPARAMETER _HRESULT_TYPEDEF_(0x80030057L) +#define STG_E_MEDIUMFULL _HRESULT_TYPEDEF_(0x80030070L) +#define STG_E_PROPSETMISMATCHED _HRESULT_TYPEDEF_(0x800300F0L) +#define STG_E_ABNORMALAPIEXIT _HRESULT_TYPEDEF_(0x800300FAL) +#define STG_E_INVALIDHEADER _HRESULT_TYPEDEF_(0x800300FBL) +#define STG_E_INVALIDNAME _HRESULT_TYPEDEF_(0x800300FCL) +#define STG_E_UNKNOWN _HRESULT_TYPEDEF_(0x800300FDL) +#define STG_E_UNIMPLEMENTEDFUNCTION _HRESULT_TYPEDEF_(0x800300FEL) +#define STG_E_INVALIDFLAG _HRESULT_TYPEDEF_(0x800300FFL) +#define STG_E_INUSE _HRESULT_TYPEDEF_(0x80030100L) +#define STG_E_NOTCURRENT _HRESULT_TYPEDEF_(0x80030101L) +#define STG_E_REVERTED _HRESULT_TYPEDEF_(0x80030102L) +#define STG_E_CANTSAVE _HRESULT_TYPEDEF_(0x80030103L) +#define STG_E_OLDFORMAT _HRESULT_TYPEDEF_(0x80030104L) +#define STG_E_OLDDLL _HRESULT_TYPEDEF_(0x80030105L) +#define STG_E_SHAREREQUIRED _HRESULT_TYPEDEF_(0x80030106L) +#define STG_E_NOTFILEBASEDSTORAGE _HRESULT_TYPEDEF_(0x80030107L) +#define STG_E_EXTANTMARSHALLINGS _HRESULT_TYPEDEF_(0x80030108L) +#define STG_E_DOCFILECORRUPT _HRESULT_TYPEDEF_(0x80030109L) +#define STG_E_BADBASEADDRESS _HRESULT_TYPEDEF_(0x80030110L) +#define STG_E_DOCFILETOOLARGE _HRESULT_TYPEDEF_(0x80030111L) +#define STG_E_NOTSIMPLEFORMAT _HRESULT_TYPEDEF_(0x80030112L) +#define STG_E_INCOMPLETE _HRESULT_TYPEDEF_(0x80030201L) +#define STG_E_TERMINATED _HRESULT_TYPEDEF_(0x80030202L) +#define STG_S_CONVERTED _HRESULT_TYPEDEF_(0x00030200L) +#define STG_S_BLOCK _HRESULT_TYPEDEF_(0x00030201L) +#define STG_S_RETRYNOW _HRESULT_TYPEDEF_(0x00030202L) +#define STG_S_MONITORING _HRESULT_TYPEDEF_(0x00030203L) +#define STG_S_MULTIPLEOPENS _HRESULT_TYPEDEF_(0x00030204L) +#define STG_S_CONSOLIDATIONFAILED _HRESULT_TYPEDEF_(0x00030205L) +#define STG_S_CANNOTCONSOLIDATE _HRESULT_TYPEDEF_(0x00030206L) +#define STG_E_STATUS_COPY_PROTECTION_FAILURE _HRESULT_TYPEDEF_(0x80030305L) +#define STG_E_CSS_AUTHENTICATION_FAILURE _HRESULT_TYPEDEF_(0x80030306L) +#define STG_E_CSS_KEY_NOT_PRESENT _HRESULT_TYPEDEF_(0x80030307L) +#define STG_E_CSS_KEY_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x80030308L) +#define STG_E_CSS_SCRAMBLED_SECTOR _HRESULT_TYPEDEF_(0x80030309L) +#define STG_E_CSS_REGION_MISMATCH _HRESULT_TYPEDEF_(0x8003030AL) +#define STG_E_RESETS_EXHAUSTED _HRESULT_TYPEDEF_(0x8003030BL) +#define RPC_E_CALL_REJECTED _HRESULT_TYPEDEF_(0x80010001L) +#define RPC_E_CALL_CANCELED _HRESULT_TYPEDEF_(0x80010002L) +#define RPC_E_CANTPOST_INSENDCALL _HRESULT_TYPEDEF_(0x80010003L) +#define RPC_E_CANTCALLOUT_INASYNCCALL _HRESULT_TYPEDEF_(0x80010004L) +#define RPC_E_CANTCALLOUT_INEXTERNALCALL _HRESULT_TYPEDEF_(0x80010005L) +#define RPC_E_CONNECTION_TERMINATED _HRESULT_TYPEDEF_(0x80010006L) +#define RPC_E_SERVER_DIED _HRESULT_TYPEDEF_(0x80010007L) +#define RPC_E_CLIENT_DIED _HRESULT_TYPEDEF_(0x80010008L) +#define RPC_E_INVALID_DATAPACKET _HRESULT_TYPEDEF_(0x80010009L) +#define RPC_E_CANTTRANSMIT_CALL _HRESULT_TYPEDEF_(0x8001000AL) +#define RPC_E_CLIENT_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000BL) +#define RPC_E_CLIENT_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000CL) +#define RPC_E_SERVER_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000DL) +#define RPC_E_SERVER_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000EL) +#define RPC_E_INVALID_DATA _HRESULT_TYPEDEF_(0x8001000FL) +#define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L) +#define RPC_E_CANTCALLOUT_AGAIN _HRESULT_TYPEDEF_(0x80010011L) +#define RPC_E_SERVER_DIED_DNE _HRESULT_TYPEDEF_(0x80010012L) +#define RPC_E_SYS_CALL_FAILED _HRESULT_TYPEDEF_(0x80010100L) +#define RPC_E_OUT_OF_RESOURCES _HRESULT_TYPEDEF_(0x80010101L) +#define RPC_E_ATTEMPTED_MULTITHREAD _HRESULT_TYPEDEF_(0x80010102L) +#define RPC_E_NOT_REGISTERED _HRESULT_TYPEDEF_(0x80010103L) +#define RPC_E_FAULT _HRESULT_TYPEDEF_(0x80010104L) +#define RPC_E_SERVERFAULT _HRESULT_TYPEDEF_(0x80010105L) +#define RPC_E_CHANGED_MODE _HRESULT_TYPEDEF_(0x80010106L) +#define RPC_E_INVALIDMETHOD _HRESULT_TYPEDEF_(0x80010107L) +#define RPC_E_DISCONNECTED _HRESULT_TYPEDEF_(0x80010108L) +#define RPC_E_RETRY _HRESULT_TYPEDEF_(0x80010109L) +#define RPC_E_SERVERCALL_RETRYLATER _HRESULT_TYPEDEF_(0x8001010AL) +#define RPC_E_SERVERCALL_REJECTED _HRESULT_TYPEDEF_(0x8001010BL) +#define RPC_E_INVALID_CALLDATA _HRESULT_TYPEDEF_(0x8001010CL) +#define RPC_E_CANTCALLOUT_ININPUTSYNCCALL _HRESULT_TYPEDEF_(0x8001010DL) +#define RPC_E_WRONG_THREAD _HRESULT_TYPEDEF_(0x8001010EL) +#define RPC_E_THREAD_NOT_INIT _HRESULT_TYPEDEF_(0x8001010FL) +#define RPC_E_VERSION_MISMATCH _HRESULT_TYPEDEF_(0x80010110L) +#define RPC_E_INVALID_HEADER _HRESULT_TYPEDEF_(0x80010111L) +#define RPC_E_INVALID_EXTENSION _HRESULT_TYPEDEF_(0x80010112L) +#define RPC_E_INVALID_IPID _HRESULT_TYPEDEF_(0x80010113L) +#define RPC_E_INVALID_OBJECT _HRESULT_TYPEDEF_(0x80010114L) +#define RPC_S_CALLPENDING _HRESULT_TYPEDEF_(0x80010115L) +#define RPC_S_WAITONTIMER _HRESULT_TYPEDEF_(0x80010116L) +#define RPC_E_CALL_COMPLETE _HRESULT_TYPEDEF_(0x80010117L) +#define RPC_E_UNSECURE_CALL _HRESULT_TYPEDEF_(0x80010118L) +#define RPC_E_TOO_LATE _HRESULT_TYPEDEF_(0x80010119L) +#define RPC_E_NO_GOOD_SECURITY_PACKAGES _HRESULT_TYPEDEF_(0x8001011AL) +#define RPC_E_ACCESS_DENIED _HRESULT_TYPEDEF_(0x8001011BL) +#define RPC_E_REMOTE_DISABLED _HRESULT_TYPEDEF_(0x8001011CL) +#define RPC_E_INVALID_OBJREF _HRESULT_TYPEDEF_(0x8001011DL) +#define RPC_E_NO_CONTEXT _HRESULT_TYPEDEF_(0x8001011EL) +#define RPC_E_TIMEOUT _HRESULT_TYPEDEF_(0x8001011FL) +#define RPC_E_NO_SYNC _HRESULT_TYPEDEF_(0x80010120L) +#define RPC_E_FULLSIC_REQUIRED _HRESULT_TYPEDEF_(0x80010121L) +#define RPC_E_INVALID_STD_NAME _HRESULT_TYPEDEF_(0x80010122L) +#define CO_E_FAILEDTOIMPERSONATE _HRESULT_TYPEDEF_(0x80010123L) +#define CO_E_FAILEDTOGETSECCTX _HRESULT_TYPEDEF_(0x80010124L) +#define CO_E_FAILEDTOOPENTHREADTOKEN _HRESULT_TYPEDEF_(0x80010125L) +#define CO_E_FAILEDTOGETTOKENINFO _HRESULT_TYPEDEF_(0x80010126L) +#define CO_E_TRUSTEEDOESNTMATCHCLIENT _HRESULT_TYPEDEF_(0x80010127L) +#define CO_E_FAILEDTOQUERYCLIENTBLANKET _HRESULT_TYPEDEF_(0x80010128L) +#define CO_E_FAILEDTOSETDACL _HRESULT_TYPEDEF_(0x80010129L) +#define CO_E_ACCESSCHECKFAILED _HRESULT_TYPEDEF_(0x8001012AL) +#define CO_E_NETACCESSAPIFAILED _HRESULT_TYPEDEF_(0x8001012BL) +#define CO_E_WRONGTRUSTEENAMESYNTAX _HRESULT_TYPEDEF_(0x8001012CL) +#define CO_E_INVALIDSID _HRESULT_TYPEDEF_(0x8001012DL) +#define CO_E_CONVERSIONFAILED _HRESULT_TYPEDEF_(0x8001012EL) +#define CO_E_NOMATCHINGSIDFOUND _HRESULT_TYPEDEF_(0x8001012FL) +#define CO_E_LOOKUPACCSIDFAILED _HRESULT_TYPEDEF_(0x80010130L) +#define CO_E_NOMATCHINGNAMEFOUND _HRESULT_TYPEDEF_(0x80010131L) +#define CO_E_LOOKUPACCNAMEFAILED _HRESULT_TYPEDEF_(0x80010132L) +#define CO_E_SETSERLHNDLFAILED _HRESULT_TYPEDEF_(0x80010133L) +#define CO_E_FAILEDTOGETWINDIR _HRESULT_TYPEDEF_(0x80010134L) +#define CO_E_PATHTOOLONG _HRESULT_TYPEDEF_(0x80010135L) +#define CO_E_FAILEDTOGENUUID _HRESULT_TYPEDEF_(0x80010136L) +#define CO_E_FAILEDTOCREATEFILE _HRESULT_TYPEDEF_(0x80010137L) +#define CO_E_FAILEDTOCLOSEHANDLE _HRESULT_TYPEDEF_(0x80010138L) +#define CO_E_EXCEEDSYSACLLIMIT _HRESULT_TYPEDEF_(0x80010139L) +#define CO_E_ACESINWRONGORDER _HRESULT_TYPEDEF_(0x8001013AL) +#define CO_E_INCOMPATIBLESTREAMVERSION _HRESULT_TYPEDEF_(0x8001013BL) +#define CO_E_FAILEDTOOPENPROCESSTOKEN _HRESULT_TYPEDEF_(0x8001013CL) +#define CO_E_DECODEFAILED _HRESULT_TYPEDEF_(0x8001013DL) +#define CO_E_ACNOTINITIALIZED _HRESULT_TYPEDEF_(0x8001013FL) +#define CO_E_CANCEL_DISABLED _HRESULT_TYPEDEF_(0x80010140L) +#define RPC_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8001FFFFL) +#define ERROR_AUDITING_DISABLED _HRESULT_TYPEDEF_(0xC0090001L) +#define ERROR_ALL_SIDS_FILTERED _HRESULT_TYPEDEF_(0xC0090002L) +#define NTE_BAD_UID _HRESULT_TYPEDEF_(0x80090001L) +#define NTE_BAD_HASH _HRESULT_TYPEDEF_(0x80090002L) +#define NTE_BAD_KEY _HRESULT_TYPEDEF_(0x80090003L) +#define NTE_BAD_LEN _HRESULT_TYPEDEF_(0x80090004L) +#define NTE_BAD_DATA _HRESULT_TYPEDEF_(0x80090005L) +#define NTE_BAD_SIGNATURE _HRESULT_TYPEDEF_(0x80090006L) +#define NTE_BAD_VER _HRESULT_TYPEDEF_(0x80090007L) +#define NTE_BAD_ALGID _HRESULT_TYPEDEF_(0x80090008L) +#define NTE_BAD_FLAGS _HRESULT_TYPEDEF_(0x80090009L) +#define NTE_BAD_TYPE _HRESULT_TYPEDEF_(0x8009000AL) +#define NTE_BAD_KEY_STATE _HRESULT_TYPEDEF_(0x8009000BL) +#define NTE_BAD_HASH_STATE _HRESULT_TYPEDEF_(0x8009000CL) +#define NTE_NO_KEY _HRESULT_TYPEDEF_(0x8009000DL) +#define NTE_NO_MEMORY _HRESULT_TYPEDEF_(0x8009000EL) +#define NTE_EXISTS _HRESULT_TYPEDEF_(0x8009000FL) +#define NTE_PERM _HRESULT_TYPEDEF_(0x80090010L) +#define NTE_NOT_FOUND _HRESULT_TYPEDEF_(0x80090011L) +#define NTE_DOUBLE_ENCRYPT _HRESULT_TYPEDEF_(0x80090012L) +#define NTE_BAD_PROVIDER _HRESULT_TYPEDEF_(0x80090013L) +#define NTE_BAD_PROV_TYPE _HRESULT_TYPEDEF_(0x80090014L) +#define NTE_BAD_PUBLIC_KEY _HRESULT_TYPEDEF_(0x80090015L) +#define NTE_BAD_KEYSET _HRESULT_TYPEDEF_(0x80090016L) +#define NTE_PROV_TYPE_NOT_DEF _HRESULT_TYPEDEF_(0x80090017L) +#define NTE_PROV_TYPE_ENTRY_BAD _HRESULT_TYPEDEF_(0x80090018L) +#define NTE_KEYSET_NOT_DEF _HRESULT_TYPEDEF_(0x80090019L) +#define NTE_KEYSET_ENTRY_BAD _HRESULT_TYPEDEF_(0x8009001AL) +#define NTE_PROV_TYPE_NO_MATCH _HRESULT_TYPEDEF_(0x8009001BL) +#define NTE_SIGNATURE_FILE_BAD _HRESULT_TYPEDEF_(0x8009001CL) +#define NTE_PROVIDER_DLL_FAIL _HRESULT_TYPEDEF_(0x8009001DL) +#define NTE_PROV_DLL_NOT_FOUND _HRESULT_TYPEDEF_(0x8009001EL) +#define NTE_BAD_KEYSET_PARAM _HRESULT_TYPEDEF_(0x8009001FL) +#define NTE_FAIL _HRESULT_TYPEDEF_(0x80090020L) +#define NTE_SYS_ERR _HRESULT_TYPEDEF_(0x80090021L) +#define NTE_SILENT_CONTEXT _HRESULT_TYPEDEF_(0x80090022L) +#define NTE_TOKEN_KEYSET_STORAGE_FULL _HRESULT_TYPEDEF_(0x80090023L) +#define NTE_TEMPORARY_PROFILE _HRESULT_TYPEDEF_(0x80090024L) +#define NTE_FIXEDPARAMETER _HRESULT_TYPEDEF_(0x80090025L) +#define SEC_E_INSUFFICIENT_MEMORY _HRESULT_TYPEDEF_(0x80090300L) +#define SEC_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80090301L) +#define SEC_E_UNSUPPORTED_FUNCTION _HRESULT_TYPEDEF_(0x80090302L) +#define SEC_E_TARGET_UNKNOWN _HRESULT_TYPEDEF_(0x80090303L) +#define SEC_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80090304L) +#define SEC_E_SECPKG_NOT_FOUND _HRESULT_TYPEDEF_(0x80090305L) +#define SEC_E_NOT_OWNER _HRESULT_TYPEDEF_(0x80090306L) +#define SEC_E_CANNOT_INSTALL _HRESULT_TYPEDEF_(0x80090307L) +#define SEC_E_INVALID_TOKEN _HRESULT_TYPEDEF_(0x80090308L) +#define SEC_E_CANNOT_PACK _HRESULT_TYPEDEF_(0x80090309L) +#define SEC_E_QOP_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009030AL) +#define SEC_E_NO_IMPERSONATION _HRESULT_TYPEDEF_(0x8009030BL) +#define SEC_E_LOGON_DENIED _HRESULT_TYPEDEF_(0x8009030CL) +#define SEC_E_UNKNOWN_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030DL) +#define SEC_E_NO_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030EL) +#define SEC_E_MESSAGE_ALTERED _HRESULT_TYPEDEF_(0x8009030FL) +#define SEC_E_OUT_OF_SEQUENCE _HRESULT_TYPEDEF_(0x80090310L) +#define SEC_E_NO_AUTHENTICATING_AUTHORITY _HRESULT_TYPEDEF_(0x80090311L) +#define SEC_I_CONTINUE_NEEDED _HRESULT_TYPEDEF_(0x00090312L) +#define SEC_I_COMPLETE_NEEDED _HRESULT_TYPEDEF_(0x00090313L) +#define SEC_I_COMPLETE_AND_CONTINUE _HRESULT_TYPEDEF_(0x00090314L) +#define SEC_I_LOCAL_LOGON _HRESULT_TYPEDEF_(0x00090315L) +#define SEC_E_BAD_PKGID _HRESULT_TYPEDEF_(0x80090316L) +#define SEC_E_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x80090317L) +#define SEC_I_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x00090317L) +#define SEC_E_INCOMPLETE_MESSAGE _HRESULT_TYPEDEF_(0x80090318L) +#define SEC_E_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x80090320L) +#define SEC_E_BUFFER_TOO_SMALL _HRESULT_TYPEDEF_(0x80090321L) +#define SEC_I_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x00090320L) +#define SEC_I_RENEGOTIATE _HRESULT_TYPEDEF_(0x00090321L) +#define SEC_E_WRONG_PRINCIPAL _HRESULT_TYPEDEF_(0x80090322L) +#define SEC_I_NO_LSA_CONTEXT _HRESULT_TYPEDEF_(0x00090323L) +#define SEC_E_TIME_SKEW _HRESULT_TYPEDEF_(0x80090324L) +#define SEC_E_UNTRUSTED_ROOT _HRESULT_TYPEDEF_(0x80090325L) +#define SEC_E_ILLEGAL_MESSAGE _HRESULT_TYPEDEF_(0x80090326L) +#define SEC_E_CERT_UNKNOWN _HRESULT_TYPEDEF_(0x80090327L) +#define SEC_E_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090328L) +#define SEC_E_ENCRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090329L) +#define SEC_E_DECRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090330L) +#define SEC_E_ALGORITHM_MISMATCH _HRESULT_TYPEDEF_(0x80090331L) +#define SEC_E_SECURITY_QOS_FAILED _HRESULT_TYPEDEF_(0x80090332L) +#define SEC_E_UNFINISHED_CONTEXT_DELETED _HRESULT_TYPEDEF_(0x80090333L) +#define SEC_E_NO_TGT_REPLY _HRESULT_TYPEDEF_(0x80090334L) +#define SEC_E_NO_IP_ADDRESSES _HRESULT_TYPEDEF_(0x80090335L) +#define SEC_E_WRONG_CREDENTIAL_HANDLE _HRESULT_TYPEDEF_(0x80090336L) +#define SEC_E_CRYPTO_SYSTEM_INVALID _HRESULT_TYPEDEF_(0x80090337L) +#define SEC_E_MAX_REFERRALS_EXCEEDED _HRESULT_TYPEDEF_(0x80090338L) +#define SEC_E_MUST_BE_KDC _HRESULT_TYPEDEF_(0x80090339L) +#define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009033AL) +#define SEC_E_TOO_MANY_PRINCIPALS _HRESULT_TYPEDEF_(0x8009033BL) +#define SEC_E_NO_PA_DATA _HRESULT_TYPEDEF_(0x8009033CL) +#define SEC_E_PKINIT_NAME_MISMATCH _HRESULT_TYPEDEF_(0x8009033DL) +#define SEC_E_SMARTCARD_LOGON_REQUIRED _HRESULT_TYPEDEF_(0x8009033EL) +#define SEC_E_SHUTDOWN_IN_PROGRESS _HRESULT_TYPEDEF_(0x8009033FL) +#define SEC_E_KDC_INVALID_REQUEST _HRESULT_TYPEDEF_(0x80090340L) +#define SEC_E_KDC_UNABLE_TO_REFER _HRESULT_TYPEDEF_(0x80090341L) +#define SEC_E_KDC_UNKNOWN_ETYPE _HRESULT_TYPEDEF_(0x80090342L) +#define SEC_E_UNSUPPORTED_PREAUTH _HRESULT_TYPEDEF_(0x80090343L) +#define SEC_E_DELEGATION_REQUIRED _HRESULT_TYPEDEF_(0x80090345L) +#define SEC_E_BAD_BINDINGS _HRESULT_TYPEDEF_(0x80090346L) +#define SEC_E_MULTIPLE_ACCOUNTS _HRESULT_TYPEDEF_(0x80090347L) +#define SEC_E_NO_KERB_KEY _HRESULT_TYPEDEF_(0x80090348L) +#define SEC_E_CERT_WRONG_USAGE _HRESULT_TYPEDEF_(0x80090349L) +#define SEC_E_DOWNGRADE_DETECTED _HRESULT_TYPEDEF_(0x80090350L) +#define SEC_E_SMARTCARD_CERT_REVOKED _HRESULT_TYPEDEF_(0x80090351L) +#define SEC_E_ISSUING_CA_UNTRUSTED _HRESULT_TYPEDEF_(0x80090352L) +#define SEC_E_REVOCATION_OFFLINE_C _HRESULT_TYPEDEF_(0x80090353L) +#define SEC_E_PKINIT_CLIENT_FAILURE _HRESULT_TYPEDEF_(0x80090354L) +#define SEC_E_SMARTCARD_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090355L) +#define SEC_E_NO_S4U_PROT_SUPPORT _HRESULT_TYPEDEF_(0x80090356L) +#define SEC_E_CROSSREALM_DELEGATION_FAILURE _HRESULT_TYPEDEF_(0x80090357L) +#define SEC_E_REVOCATION_OFFLINE_KDC _HRESULT_TYPEDEF_(0x80090358L) +#define SEC_E_ISSUING_CA_UNTRUSTED_KDC _HRESULT_TYPEDEF_(0x80090359L) +#define SEC_E_KDC_CERT_EXPIRED _HRESULT_TYPEDEF_(0x8009035AL) +#define SEC_E_KDC_CERT_REVOKED _HRESULT_TYPEDEF_(0x8009035BL) +#define SEC_E_NO_SPM SEC_E_INTERNAL_ERROR +#define SEC_E_NOT_SUPPORTED SEC_E_UNSUPPORTED_FUNCTION +#define CRYPT_E_MSG_ERROR _HRESULT_TYPEDEF_(0x80091001L) +#define CRYPT_E_UNKNOWN_ALGO _HRESULT_TYPEDEF_(0x80091002L) +#define CRYPT_E_OID_FORMAT _HRESULT_TYPEDEF_(0x80091003L) +#define CRYPT_E_INVALID_MSG_TYPE _HRESULT_TYPEDEF_(0x80091004L) +#define CRYPT_E_UNEXPECTED_ENCODING _HRESULT_TYPEDEF_(0x80091005L) +#define CRYPT_E_AUTH_ATTR_MISSING _HRESULT_TYPEDEF_(0x80091006L) +#define CRYPT_E_HASH_VALUE _HRESULT_TYPEDEF_(0x80091007L) +#define CRYPT_E_INVALID_INDEX _HRESULT_TYPEDEF_(0x80091008L) +#define CRYPT_E_ALREADY_DECRYPTED _HRESULT_TYPEDEF_(0x80091009L) +#define CRYPT_E_NOT_DECRYPTED _HRESULT_TYPEDEF_(0x8009100AL) +#define CRYPT_E_RECIPIENT_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100BL) +#define CRYPT_E_CONTROL_TYPE _HRESULT_TYPEDEF_(0x8009100CL) +#define CRYPT_E_ISSUER_SERIALNUMBER _HRESULT_TYPEDEF_(0x8009100DL) +#define CRYPT_E_SIGNER_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100EL) +#define CRYPT_E_ATTRIBUTES_MISSING _HRESULT_TYPEDEF_(0x8009100FL) +#define CRYPT_E_STREAM_MSG_NOT_READY _HRESULT_TYPEDEF_(0x80091010L) +#define CRYPT_E_STREAM_INSUFFICIENT_DATA _HRESULT_TYPEDEF_(0x80091011L) +#define CRYPT_I_NEW_PROTECTION_REQUIRED _HRESULT_TYPEDEF_(0x00091012L) +#define CRYPT_E_BAD_LEN _HRESULT_TYPEDEF_(0x80092001L) +#define CRYPT_E_BAD_ENCODE _HRESULT_TYPEDEF_(0x80092002L) +#define CRYPT_E_FILE_ERROR _HRESULT_TYPEDEF_(0x80092003L) +#define CRYPT_E_NOT_FOUND _HRESULT_TYPEDEF_(0x80092004L) +#define CRYPT_E_EXISTS _HRESULT_TYPEDEF_(0x80092005L) +#define CRYPT_E_NO_PROVIDER _HRESULT_TYPEDEF_(0x80092006L) +#define CRYPT_E_SELF_SIGNED _HRESULT_TYPEDEF_(0x80092007L) +#define CRYPT_E_DELETED_PREV _HRESULT_TYPEDEF_(0x80092008L) +#define CRYPT_E_NO_MATCH _HRESULT_TYPEDEF_(0x80092009L) +#define CRYPT_E_UNEXPECTED_MSG_TYPE _HRESULT_TYPEDEF_(0x8009200AL) +#define CRYPT_E_NO_KEY_PROPERTY _HRESULT_TYPEDEF_(0x8009200BL) +#define CRYPT_E_NO_DECRYPT_CERT _HRESULT_TYPEDEF_(0x8009200CL) +#define CRYPT_E_BAD_MSG _HRESULT_TYPEDEF_(0x8009200DL) +#define CRYPT_E_NO_SIGNER _HRESULT_TYPEDEF_(0x8009200EL) +#define CRYPT_E_PENDING_CLOSE _HRESULT_TYPEDEF_(0x8009200FL) +#define CRYPT_E_REVOKED _HRESULT_TYPEDEF_(0x80092010L) +#define CRYPT_E_NO_REVOCATION_DLL _HRESULT_TYPEDEF_(0x80092011L) +#define CRYPT_E_NO_REVOCATION_CHECK _HRESULT_TYPEDEF_(0x80092012L) +#define CRYPT_E_REVOCATION_OFFLINE _HRESULT_TYPEDEF_(0x80092013L) +#define CRYPT_E_NOT_IN_REVOCATION_DATABASE _HRESULT_TYPEDEF_(0x80092014L) +#define CRYPT_E_INVALID_NUMERIC_STRING _HRESULT_TYPEDEF_(0x80092020L) +#define CRYPT_E_INVALID_PRINTABLE_STRING _HRESULT_TYPEDEF_(0x80092021L) +#define CRYPT_E_INVALID_IA5_STRING _HRESULT_TYPEDEF_(0x80092022L) +#define CRYPT_E_INVALID_X500_STRING _HRESULT_TYPEDEF_(0x80092023L) +#define CRYPT_E_NOT_CHAR_STRING _HRESULT_TYPEDEF_(0x80092024L) +#define CRYPT_E_FILERESIZED _HRESULT_TYPEDEF_(0x80092025L) +#define CRYPT_E_SECURITY_SETTINGS _HRESULT_TYPEDEF_(0x80092026L) +#define CRYPT_E_NO_VERIFY_USAGE_DLL _HRESULT_TYPEDEF_(0x80092027L) +#define CRYPT_E_NO_VERIFY_USAGE_CHECK _HRESULT_TYPEDEF_(0x80092028L) +#define CRYPT_E_VERIFY_USAGE_OFFLINE _HRESULT_TYPEDEF_(0x80092029L) +#define CRYPT_E_NOT_IN_CTL _HRESULT_TYPEDEF_(0x8009202AL) +#define CRYPT_E_NO_TRUSTED_SIGNER _HRESULT_TYPEDEF_(0x8009202BL) +#define CRYPT_E_MISSING_PUBKEY_PARA _HRESULT_TYPEDEF_(0x8009202CL) +#define CRYPT_E_OSS_ERROR _HRESULT_TYPEDEF_(0x80093000L) +#define OSS_MORE_BUF _HRESULT_TYPEDEF_(0x80093001L) +#define OSS_NEGATIVE_UINTEGER _HRESULT_TYPEDEF_(0x80093002L) +#define OSS_PDU_RANGE _HRESULT_TYPEDEF_(0x80093003L) +#define OSS_MORE_INPUT _HRESULT_TYPEDEF_(0x80093004L) +#define OSS_DATA_ERROR _HRESULT_TYPEDEF_(0x80093005L) +#define OSS_BAD_ARG _HRESULT_TYPEDEF_(0x80093006L) +#define OSS_BAD_VERSION _HRESULT_TYPEDEF_(0x80093007L) +#define OSS_OUT_MEMORY _HRESULT_TYPEDEF_(0x80093008L) +#define OSS_PDU_MISMATCH _HRESULT_TYPEDEF_(0x80093009L) +#define OSS_LIMITED _HRESULT_TYPEDEF_(0x8009300AL) +#define OSS_BAD_PTR _HRESULT_TYPEDEF_(0x8009300BL) +#define OSS_BAD_TIME _HRESULT_TYPEDEF_(0x8009300CL) +#define OSS_INDEFINITE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009300DL) +#define OSS_MEM_ERROR _HRESULT_TYPEDEF_(0x8009300EL) +#define OSS_BAD_TABLE _HRESULT_TYPEDEF_(0x8009300FL) +#define OSS_TOO_LONG _HRESULT_TYPEDEF_(0x80093010L) +#define OSS_CONSTRAINT_VIOLATED _HRESULT_TYPEDEF_(0x80093011L) +#define OSS_FATAL_ERROR _HRESULT_TYPEDEF_(0x80093012L) +#define OSS_ACCESS_SERIALIZATION_ERROR _HRESULT_TYPEDEF_(0x80093013L) +#define OSS_NULL_TBL _HRESULT_TYPEDEF_(0x80093014L) +#define OSS_NULL_FCN _HRESULT_TYPEDEF_(0x80093015L) +#define OSS_BAD_ENCRULES _HRESULT_TYPEDEF_(0x80093016L) +#define OSS_UNAVAIL_ENCRULES _HRESULT_TYPEDEF_(0x80093017L) +#define OSS_CANT_OPEN_TRACE_WINDOW _HRESULT_TYPEDEF_(0x80093018L) +#define OSS_UNIMPLEMENTED _HRESULT_TYPEDEF_(0x80093019L) +#define OSS_OID_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301AL) +#define OSS_CANT_OPEN_TRACE_FILE _HRESULT_TYPEDEF_(0x8009301BL) +#define OSS_TRACE_FILE_ALREADY_OPEN _HRESULT_TYPEDEF_(0x8009301CL) +#define OSS_TABLE_MISMATCH _HRESULT_TYPEDEF_(0x8009301DL) +#define OSS_TYPE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009301EL) +#define OSS_REAL_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301FL) +#define OSS_REAL_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093020L) +#define OSS_OUT_OF_RANGE _HRESULT_TYPEDEF_(0x80093021L) +#define OSS_COPIER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093022L) +#define OSS_CONSTRAINT_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093023L) +#define OSS_COMPARATOR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093024L) +#define OSS_COMPARATOR_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093025L) +#define OSS_MEM_MGR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093026L) +#define OSS_PDV_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093027L) +#define OSS_PDV_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093028L) +#define OSS_API_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093029L) +#define OSS_BERDER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302AL) +#define OSS_PER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302BL) +#define OSS_OPEN_TYPE_ERROR _HRESULT_TYPEDEF_(0x8009302CL) +#define OSS_MUTEX_NOT_CREATED _HRESULT_TYPEDEF_(0x8009302DL) +#define OSS_CANT_CLOSE_TRACE_FILE _HRESULT_TYPEDEF_(0x8009302EL) +#define CRYPT_E_ASN1_ERROR _HRESULT_TYPEDEF_(0x80093100L) +#define CRYPT_E_ASN1_INTERNAL _HRESULT_TYPEDEF_(0x80093101L) +#define CRYPT_E_ASN1_EOD _HRESULT_TYPEDEF_(0x80093102L) +#define CRYPT_E_ASN1_CORRUPT _HRESULT_TYPEDEF_(0x80093103L) +#define CRYPT_E_ASN1_LARGE _HRESULT_TYPEDEF_(0x80093104L) +#define CRYPT_E_ASN1_CONSTRAINT _HRESULT_TYPEDEF_(0x80093105L) +#define CRYPT_E_ASN1_MEMORY _HRESULT_TYPEDEF_(0x80093106L) +#define CRYPT_E_ASN1_OVERFLOW _HRESULT_TYPEDEF_(0x80093107L) +#define CRYPT_E_ASN1_BADPDU _HRESULT_TYPEDEF_(0x80093108L) +#define CRYPT_E_ASN1_BADARGS _HRESULT_TYPEDEF_(0x80093109L) +#define CRYPT_E_ASN1_BADREAL _HRESULT_TYPEDEF_(0x8009310AL) +#define CRYPT_E_ASN1_BADTAG _HRESULT_TYPEDEF_(0x8009310BL) +#define CRYPT_E_ASN1_CHOICE _HRESULT_TYPEDEF_(0x8009310CL) +#define CRYPT_E_ASN1_RULE _HRESULT_TYPEDEF_(0x8009310DL) +#define CRYPT_E_ASN1_UTF8 _HRESULT_TYPEDEF_(0x8009310EL) +#define CRYPT_E_ASN1_PDU_TYPE _HRESULT_TYPEDEF_(0x80093133L) +#define CRYPT_E_ASN1_NYI _HRESULT_TYPEDEF_(0x80093134L) +#define CRYPT_E_ASN1_EXTENDED _HRESULT_TYPEDEF_(0x80093201L) +#define CRYPT_E_ASN1_NOEOD _HRESULT_TYPEDEF_(0x80093202L) +#define CERTSRV_E_BAD_REQUESTSUBJECT _HRESULT_TYPEDEF_(0x80094001L) +#define CERTSRV_E_NO_REQUEST _HRESULT_TYPEDEF_(0x80094002L) +#define CERTSRV_E_BAD_REQUESTSTATUS _HRESULT_TYPEDEF_(0x80094003L) +#define CERTSRV_E_PROPERTY_EMPTY _HRESULT_TYPEDEF_(0x80094004L) +#define CERTSRV_E_INVALID_CA_CERTIFICATE _HRESULT_TYPEDEF_(0x80094005L) +#define CERTSRV_E_SERVER_SUSPENDED _HRESULT_TYPEDEF_(0x80094006L) +#define CERTSRV_E_ENCODING_LENGTH _HRESULT_TYPEDEF_(0x80094007L) +#define CERTSRV_E_ROLECONFLICT _HRESULT_TYPEDEF_(0x80094008L) +#define CERTSRV_E_RESTRICTEDOFFICER _HRESULT_TYPEDEF_(0x80094009L) +#define CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED _HRESULT_TYPEDEF_(0x8009400AL) +#define CERTSRV_E_NO_VALID_KRA _HRESULT_TYPEDEF_(0x8009400BL) +#define CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL _HRESULT_TYPEDEF_(0x8009400CL) +#define CERTSRV_E_NO_CAADMIN_DEFINED _HRESULT_TYPEDEF_(0x8009400DL) +#define CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE _HRESULT_TYPEDEF_(0x8009400EL) +#define CERTSRV_E_NO_DB_SESSIONS _HRESULT_TYPEDEF_(0x8009400FL) +#define CERTSRV_E_ALIGNMENT_FAULT _HRESULT_TYPEDEF_(0x80094010L) +#define CERTSRV_E_ENROLL_DENIED _HRESULT_TYPEDEF_(0x80094011L) +#define CERTSRV_E_TEMPLATE_DENIED _HRESULT_TYPEDEF_(0x80094012L) +#define CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE _HRESULT_TYPEDEF_(0x80094013L) +#define CERTSRV_E_UNSUPPORTED_CERT_TYPE _HRESULT_TYPEDEF_(0x80094800L) +#define CERTSRV_E_NO_CERT_TYPE _HRESULT_TYPEDEF_(0x80094801L) +#define CERTSRV_E_TEMPLATE_CONFLICT _HRESULT_TYPEDEF_(0x80094802L) +#define CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED _HRESULT_TYPEDEF_(0x80094803L) +#define CERTSRV_E_ARCHIVED_KEY_REQUIRED _HRESULT_TYPEDEF_(0x80094804L) +#define CERTSRV_E_SMIME_REQUIRED _HRESULT_TYPEDEF_(0x80094805L) +#define CERTSRV_E_BAD_RENEWAL_SUBJECT _HRESULT_TYPEDEF_(0x80094806L) +#define CERTSRV_E_BAD_TEMPLATE_VERSION _HRESULT_TYPEDEF_(0x80094807L) +#define CERTSRV_E_TEMPLATE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094808L) +#define CERTSRV_E_SIGNATURE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094809L) +#define CERTSRV_E_SIGNATURE_COUNT _HRESULT_TYPEDEF_(0x8009480AL) +#define CERTSRV_E_SIGNATURE_REJECTED _HRESULT_TYPEDEF_(0x8009480BL) +#define CERTSRV_E_ISSUANCE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x8009480CL) +#define CERTSRV_E_SUBJECT_UPN_REQUIRED _HRESULT_TYPEDEF_(0x8009480DL) +#define CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED _HRESULT_TYPEDEF_(0x8009480EL) +#define CERTSRV_E_SUBJECT_DNS_REQUIRED _HRESULT_TYPEDEF_(0x8009480FL) +#define CERTSRV_E_ARCHIVED_KEY_UNEXPECTED _HRESULT_TYPEDEF_(0x80094810L) +#define CERTSRV_E_KEY_LENGTH _HRESULT_TYPEDEF_(0x80094811L) +#define CERTSRV_E_SUBJECT_EMAIL_REQUIRED _HRESULT_TYPEDEF_(0x80094812L) +#define CERTSRV_E_UNKNOWN_CERT_TYPE _HRESULT_TYPEDEF_(0x80094813L) +#define CERTSRV_E_CERT_TYPE_OVERLAP _HRESULT_TYPEDEF_(0x80094814L) +#define XENROLL_E_KEY_NOT_EXPORTABLE _HRESULT_TYPEDEF_(0x80095000L) +#define XENROLL_E_CANNOT_ADD_ROOT_CERT _HRESULT_TYPEDEF_(0x80095001L) +#define XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND _HRESULT_TYPEDEF_(0x80095002L) +#define XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH _HRESULT_TYPEDEF_(0x80095003L) +#define XENROLL_E_RESPONSE_KA_HASH_MISMATCH _HRESULT_TYPEDEF_(0x80095004L) +#define XENROLL_E_KEYSPEC_SMIME_MISMATCH _HRESULT_TYPEDEF_(0x80095005L) +#define TRUST_E_SYSTEM_ERROR _HRESULT_TYPEDEF_(0x80096001L) +#define TRUST_E_NO_SIGNER_CERT _HRESULT_TYPEDEF_(0x80096002L) +#define TRUST_E_COUNTER_SIGNER _HRESULT_TYPEDEF_(0x80096003L) +#define TRUST_E_CERT_SIGNATURE _HRESULT_TYPEDEF_(0x80096004L) +#define TRUST_E_TIME_STAMP _HRESULT_TYPEDEF_(0x80096005L) +#define TRUST_E_BAD_DIGEST _HRESULT_TYPEDEF_(0x80096010L) +#define TRUST_E_BASIC_CONSTRAINTS _HRESULT_TYPEDEF_(0x80096019L) +#define TRUST_E_FINANCIAL_CRITERIA _HRESULT_TYPEDEF_(0x8009601EL) +#define MSSIPOTF_E_OUTOFMEMRANGE _HRESULT_TYPEDEF_(0x80097001L) +#define MSSIPOTF_E_CANTGETOBJECT _HRESULT_TYPEDEF_(0x80097002L) +#define MSSIPOTF_E_NOHEADTABLE _HRESULT_TYPEDEF_(0x80097003L) +#define MSSIPOTF_E_BAD_MAGICNUMBER _HRESULT_TYPEDEF_(0x80097004L) +#define MSSIPOTF_E_BAD_OFFSET_TABLE _HRESULT_TYPEDEF_(0x80097005L) +#define MSSIPOTF_E_TABLE_TAGORDER _HRESULT_TYPEDEF_(0x80097006L) +#define MSSIPOTF_E_TABLE_LONGWORD _HRESULT_TYPEDEF_(0x80097007L) +#define MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT _HRESULT_TYPEDEF_(0x80097008L) +#define MSSIPOTF_E_TABLES_OVERLAP _HRESULT_TYPEDEF_(0x80097009L) +#define MSSIPOTF_E_TABLE_PADBYTES _HRESULT_TYPEDEF_(0x8009700AL) +#define MSSIPOTF_E_FILETOOSMALL _HRESULT_TYPEDEF_(0x8009700BL) +#define MSSIPOTF_E_TABLE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700CL) +#define MSSIPOTF_E_FILE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700DL) +#define MSSIPOTF_E_FAILED_POLICY _HRESULT_TYPEDEF_(0x80097010L) +#define MSSIPOTF_E_FAILED_HINTS_CHECK _HRESULT_TYPEDEF_(0x80097011L) +#define MSSIPOTF_E_NOT_OPENTYPE _HRESULT_TYPEDEF_(0x80097012L) +#define MSSIPOTF_E_FILE _HRESULT_TYPEDEF_(0x80097013L) +#define MSSIPOTF_E_CRYPT _HRESULT_TYPEDEF_(0x80097014L) +#define MSSIPOTF_E_BADVERSION _HRESULT_TYPEDEF_(0x80097015L) +#define MSSIPOTF_E_DSIG_STRUCTURE _HRESULT_TYPEDEF_(0x80097016L) +#define MSSIPOTF_E_PCONST_CHECK _HRESULT_TYPEDEF_(0x80097017L) +#define MSSIPOTF_E_STRUCTURE _HRESULT_TYPEDEF_(0x80097018L) +#define NTE_OP_OK 0 +#define TRUST_E_PROVIDER_UNKNOWN _HRESULT_TYPEDEF_(0x800B0001L) +#define TRUST_E_ACTION_UNKNOWN _HRESULT_TYPEDEF_(0x800B0002L) +#define TRUST_E_SUBJECT_FORM_UNKNOWN _HRESULT_TYPEDEF_(0x800B0003L) +#define TRUST_E_SUBJECT_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800B0004L) +#define DIGSIG_E_ENCODE _HRESULT_TYPEDEF_(0x800B0005L) +#define DIGSIG_E_DECODE _HRESULT_TYPEDEF_(0x800B0006L) +#define DIGSIG_E_EXTENSIBILITY _HRESULT_TYPEDEF_(0x800B0007L) +#define DIGSIG_E_CRYPTO _HRESULT_TYPEDEF_(0x800B0008L) +#define PERSIST_E_SIZEDEFINITE _HRESULT_TYPEDEF_(0x800B0009L) +#define PERSIST_E_SIZEINDEFINITE _HRESULT_TYPEDEF_(0x800B000AL) +#define PERSIST_E_NOTSELFSIZING _HRESULT_TYPEDEF_(0x800B000BL) +#define TRUST_E_NOSIGNATURE _HRESULT_TYPEDEF_(0x800B0100L) +#define CERT_E_EXPIRED _HRESULT_TYPEDEF_(0x800B0101L) +#define CERT_E_VALIDITYPERIODNESTING _HRESULT_TYPEDEF_(0x800B0102L) +#define CERT_E_ROLE _HRESULT_TYPEDEF_(0x800B0103L) +#define CERT_E_PATHLENCONST _HRESULT_TYPEDEF_(0x800B0104L) +#define CERT_E_CRITICAL _HRESULT_TYPEDEF_(0x800B0105L) +#define CERT_E_PURPOSE _HRESULT_TYPEDEF_(0x800B0106L) +#define CERT_E_ISSUERCHAINING _HRESULT_TYPEDEF_(0x800B0107L) +#define CERT_E_MALFORMED _HRESULT_TYPEDEF_(0x800B0108L) +#define CERT_E_UNTRUSTEDROOT _HRESULT_TYPEDEF_(0x800B0109L) +#define CERT_E_CHAINING _HRESULT_TYPEDEF_(0x800B010AL) +#define TRUST_E_FAIL _HRESULT_TYPEDEF_(0x800B010BL) +#define CERT_E_REVOKED _HRESULT_TYPEDEF_(0x800B010CL) +#define CERT_E_UNTRUSTEDTESTROOT _HRESULT_TYPEDEF_(0x800B010DL) +#define CERT_E_REVOCATION_FAILURE _HRESULT_TYPEDEF_(0x800B010EL) +#define CERT_E_CN_NO_MATCH _HRESULT_TYPEDEF_(0x800B010FL) +#define CERT_E_WRONG_USAGE _HRESULT_TYPEDEF_(0x800B0110L) +#define TRUST_E_EXPLICIT_DISTRUST _HRESULT_TYPEDEF_(0x800B0111L) +#define CERT_E_UNTRUSTEDCA _HRESULT_TYPEDEF_(0x800B0112L) +#define CERT_E_INVALID_POLICY _HRESULT_TYPEDEF_(0x800B0113L) +#define CERT_E_INVALID_NAME _HRESULT_TYPEDEF_(0x800B0114L) +#define HRESULT_FROM_SETUPAPI(x) ((((x) & (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR))==(APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR)) ? ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_SETUPAPI << 16) | 0x80000000)) : HRESULT_FROM_WIN32(x)) +#define SPAPI_E_EXPECTED_SECTION_NAME _HRESULT_TYPEDEF_(0x800F0000L) +#define SPAPI_E_BAD_SECTION_NAME_LINE _HRESULT_TYPEDEF_(0x800F0001L) +#define SPAPI_E_SECTION_NAME_TOO_LONG _HRESULT_TYPEDEF_(0x800F0002L) +#define SPAPI_E_GENERAL_SYNTAX _HRESULT_TYPEDEF_(0x800F0003L) +#define SPAPI_E_WRONG_INF_STYLE _HRESULT_TYPEDEF_(0x800F0100L) +#define SPAPI_E_SECTION_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0101L) +#define SPAPI_E_LINE_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0102L) +#define SPAPI_E_NO_BACKUP _HRESULT_TYPEDEF_(0x800F0103L) +#define SPAPI_E_NO_ASSOCIATED_CLASS _HRESULT_TYPEDEF_(0x800F0200L) +#define SPAPI_E_CLASS_MISMATCH _HRESULT_TYPEDEF_(0x800F0201L) +#define SPAPI_E_DUPLICATE_FOUND _HRESULT_TYPEDEF_(0x800F0202L) +#define SPAPI_E_NO_DRIVER_SELECTED _HRESULT_TYPEDEF_(0x800F0203L) +#define SPAPI_E_KEY_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x800F0204L) +#define SPAPI_E_INVALID_DEVINST_NAME _HRESULT_TYPEDEF_(0x800F0205L) +#define SPAPI_E_INVALID_CLASS _HRESULT_TYPEDEF_(0x800F0206L) +#define SPAPI_E_DEVINST_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x800F0207L) +#define SPAPI_E_DEVINFO_NOT_REGISTERED _HRESULT_TYPEDEF_(0x800F0208L) +#define SPAPI_E_INVALID_REG_PROPERTY _HRESULT_TYPEDEF_(0x800F0209L) +#define SPAPI_E_NO_INF _HRESULT_TYPEDEF_(0x800F020AL) +#define SPAPI_E_NO_SUCH_DEVINST _HRESULT_TYPEDEF_(0x800F020BL) +#define SPAPI_E_CANT_LOAD_CLASS_ICON _HRESULT_TYPEDEF_(0x800F020CL) +#define SPAPI_E_INVALID_CLASS_INSTALLER _HRESULT_TYPEDEF_(0x800F020DL) +#define SPAPI_E_DI_DO_DEFAULT _HRESULT_TYPEDEF_(0x800F020EL) +#define SPAPI_E_DI_NOFILECOPY _HRESULT_TYPEDEF_(0x800F020FL) +#define SPAPI_E_INVALID_HWPROFILE _HRESULT_TYPEDEF_(0x800F0210L) +#define SPAPI_E_NO_DEVICE_SELECTED _HRESULT_TYPEDEF_(0x800F0211L) +#define SPAPI_E_DEVINFO_LIST_LOCKED _HRESULT_TYPEDEF_(0x800F0212L) +#define SPAPI_E_DEVINFO_DATA_LOCKED _HRESULT_TYPEDEF_(0x800F0213L) +#define SPAPI_E_DI_BAD_PATH _HRESULT_TYPEDEF_(0x800F0214L) +#define SPAPI_E_NO_CLASSINSTALL_PARAMS _HRESULT_TYPEDEF_(0x800F0215L) +#define SPAPI_E_FILEQUEUE_LOCKED _HRESULT_TYPEDEF_(0x800F0216L) +#define SPAPI_E_BAD_SERVICE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F0217L) +#define SPAPI_E_NO_CLASS_DRIVER_LIST _HRESULT_TYPEDEF_(0x800F0218L) +#define SPAPI_E_NO_ASSOCIATED_SERVICE _HRESULT_TYPEDEF_(0x800F0219L) +#define SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F021AL) +#define SPAPI_E_DEVICE_INTERFACE_ACTIVE _HRESULT_TYPEDEF_(0x800F021BL) +#define SPAPI_E_DEVICE_INTERFACE_REMOVED _HRESULT_TYPEDEF_(0x800F021CL) +#define SPAPI_E_BAD_INTERFACE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F021DL) +#define SPAPI_E_NO_SUCH_INTERFACE_CLASS _HRESULT_TYPEDEF_(0x800F021EL) +#define SPAPI_E_INVALID_REFERENCE_STRING _HRESULT_TYPEDEF_(0x800F021FL) +#define SPAPI_E_INVALID_MACHINENAME _HRESULT_TYPEDEF_(0x800F0220L) +#define SPAPI_E_REMOTE_COMM_FAILURE _HRESULT_TYPEDEF_(0x800F0221L) +#define SPAPI_E_MACHINE_UNAVAILABLE _HRESULT_TYPEDEF_(0x800F0222L) +#define SPAPI_E_NO_CONFIGMGR_SERVICES _HRESULT_TYPEDEF_(0x800F0223L) +#define SPAPI_E_INVALID_PROPPAGE_PROVIDER _HRESULT_TYPEDEF_(0x800F0224L) +#define SPAPI_E_NO_SUCH_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F0225L) +#define SPAPI_E_DI_POSTPROCESSING_REQUIRED _HRESULT_TYPEDEF_(0x800F0226L) +#define SPAPI_E_INVALID_COINSTALLER _HRESULT_TYPEDEF_(0x800F0227L) +#define SPAPI_E_NO_COMPAT_DRIVERS _HRESULT_TYPEDEF_(0x800F0228L) +#define SPAPI_E_NO_DEVICE_ICON _HRESULT_TYPEDEF_(0x800F0229L) +#define SPAPI_E_INVALID_INF_LOGCONFIG _HRESULT_TYPEDEF_(0x800F022AL) +#define SPAPI_E_DI_DONT_INSTALL _HRESULT_TYPEDEF_(0x800F022BL) +#define SPAPI_E_INVALID_FILTER_DRIVER _HRESULT_TYPEDEF_(0x800F022CL) +#define SPAPI_E_NON_WINDOWS_NT_DRIVER _HRESULT_TYPEDEF_(0x800F022DL) +#define SPAPI_E_NON_WINDOWS_DRIVER _HRESULT_TYPEDEF_(0x800F022EL) +#define SPAPI_E_NO_CATALOG_FOR_OEM_INF _HRESULT_TYPEDEF_(0x800F022FL) +#define SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE _HRESULT_TYPEDEF_(0x800F0230L) +#define SPAPI_E_NOT_DISABLEABLE _HRESULT_TYPEDEF_(0x800F0231L) +#define SPAPI_E_CANT_REMOVE_DEVINST _HRESULT_TYPEDEF_(0x800F0232L) +#define SPAPI_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x800F0233L) +#define SPAPI_E_DRIVER_NONNATIVE _HRESULT_TYPEDEF_(0x800F0234L) +#define SPAPI_E_IN_WOW64 _HRESULT_TYPEDEF_(0x800F0235L) +#define SPAPI_E_SET_SYSTEM_RESTORE_POINT _HRESULT_TYPEDEF_(0x800F0236L) +#define SPAPI_E_INCORRECTLY_COPIED_INF _HRESULT_TYPEDEF_(0x800F0237L) +#define SPAPI_E_SCE_DISABLED _HRESULT_TYPEDEF_(0x800F0238L) +#define SPAPI_E_UNKNOWN_EXCEPTION _HRESULT_TYPEDEF_(0x800F0239L) +#define SPAPI_E_PNP_REGISTRY_ERROR _HRESULT_TYPEDEF_(0x800F023AL) +#define SPAPI_E_REMOTE_REQUEST_UNSUPPORTED _HRESULT_TYPEDEF_(0x800F023BL) +#define SPAPI_E_NOT_AN_INSTALLED_OEM_INF _HRESULT_TYPEDEF_(0x800F023CL) +#define SPAPI_E_INF_IN_USE_BY_DEVICES _HRESULT_TYPEDEF_(0x800F023DL) +#define SPAPI_E_DI_FUNCTION_OBSOLETE _HRESULT_TYPEDEF_(0x800F023EL) +#define SPAPI_E_NO_AUTHENTICODE_CATALOG _HRESULT_TYPEDEF_(0x800F023FL) +#define SPAPI_E_AUTHENTICODE_DISALLOWED _HRESULT_TYPEDEF_(0x800F0240L) +#define SPAPI_E_AUTHENTICODE_TRUSTED_PUBLISHER _HRESULT_TYPEDEF_(0x800F0241L) +#define SPAPI_E_AUTHENTICODE_TRUST_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x800F0242L) +#define SPAPI_E_AUTHENTICODE_PUBLISHER_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800F0243L) +#define SPAPI_E_SIGNATURE_OSATTRIBUTE_MISMATCH _HRESULT_TYPEDEF_(0x800F0244L) +#define SPAPI_E_ONLY_VALIDATE_VIA_AUTHENTICODE _HRESULT_TYPEDEF_(0x800F0245L) +#define SPAPI_E_UNRECOVERABLE_STACK_OVERFLOW _HRESULT_TYPEDEF_(0x800F0300L) +#define SPAPI_E_ERROR_NOT_INSTALLED _HRESULT_TYPEDEF_(0x800F1000L) +#define SCARD_S_SUCCESS NO_ERROR +#define SCARD_F_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80100001L) +#define SCARD_E_CANCELLED _HRESULT_TYPEDEF_(0x80100002L) +#define SCARD_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80100003L) +#define SCARD_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80100004L) +#define SCARD_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x80100005L) +#define SCARD_E_NO_MEMORY _HRESULT_TYPEDEF_(0x80100006L) +#define SCARD_F_WAITED_TOO_LONG _HRESULT_TYPEDEF_(0x80100007L) +#define SCARD_E_INSUFFICIENT_BUFFER _HRESULT_TYPEDEF_(0x80100008L) +#define SCARD_E_UNKNOWN_READER _HRESULT_TYPEDEF_(0x80100009L) +#define SCARD_E_TIMEOUT _HRESULT_TYPEDEF_(0x8010000AL) +#define SCARD_E_SHARING_VIOLATION _HRESULT_TYPEDEF_(0x8010000BL) +#define SCARD_E_NO_SMARTCARD _HRESULT_TYPEDEF_(0x8010000CL) +#define SCARD_E_UNKNOWN_CARD _HRESULT_TYPEDEF_(0x8010000DL) +#define SCARD_E_CANT_DISPOSE _HRESULT_TYPEDEF_(0x8010000EL) +#define SCARD_E_PROTO_MISMATCH _HRESULT_TYPEDEF_(0x8010000FL) +#define SCARD_E_NOT_READY _HRESULT_TYPEDEF_(0x80100010L) +#define SCARD_E_INVALID_VALUE _HRESULT_TYPEDEF_(0x80100011L) +#define SCARD_E_SYSTEM_CANCELLED _HRESULT_TYPEDEF_(0x80100012L) +#define SCARD_F_COMM_ERROR _HRESULT_TYPEDEF_(0x80100013L) +#define SCARD_F_UNKNOWN_ERROR _HRESULT_TYPEDEF_(0x80100014L) +#define SCARD_E_INVALID_ATR _HRESULT_TYPEDEF_(0x80100015L) +#define SCARD_E_NOT_TRANSACTED _HRESULT_TYPEDEF_(0x80100016L) +#define SCARD_E_READER_UNAVAILABLE _HRESULT_TYPEDEF_(0x80100017L) +#define SCARD_P_SHUTDOWN _HRESULT_TYPEDEF_(0x80100018L) +#define SCARD_E_PCI_TOO_SMALL _HRESULT_TYPEDEF_(0x80100019L) +#define SCARD_E_READER_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001AL) +#define SCARD_E_DUPLICATE_READER _HRESULT_TYPEDEF_(0x8010001BL) +#define SCARD_E_CARD_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001CL) +#define SCARD_E_NO_SERVICE _HRESULT_TYPEDEF_(0x8010001DL) +#define SCARD_E_SERVICE_STOPPED _HRESULT_TYPEDEF_(0x8010001EL) +#define SCARD_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8010001FL) +#define SCARD_E_ICC_INSTALLATION _HRESULT_TYPEDEF_(0x80100020L) +#define SCARD_E_ICC_CREATEORDER _HRESULT_TYPEDEF_(0x80100021L) +#define SCARD_E_UNSUPPORTED_FEATURE _HRESULT_TYPEDEF_(0x80100022L) +#define SCARD_E_DIR_NOT_FOUND _HRESULT_TYPEDEF_(0x80100023L) +#define SCARD_E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80100024L) +#define SCARD_E_NO_DIR _HRESULT_TYPEDEF_(0x80100025L) +#define SCARD_E_NO_FILE _HRESULT_TYPEDEF_(0x80100026L) +#define SCARD_E_NO_ACCESS _HRESULT_TYPEDEF_(0x80100027L) +#define SCARD_E_WRITE_TOO_MANY _HRESULT_TYPEDEF_(0x80100028L) +#define SCARD_E_BAD_SEEK _HRESULT_TYPEDEF_(0x80100029L) +#define SCARD_E_INVALID_CHV _HRESULT_TYPEDEF_(0x8010002AL) +#define SCARD_E_UNKNOWN_RES_MNG _HRESULT_TYPEDEF_(0x8010002BL) +#define SCARD_E_NO_SUCH_CERTIFICATE _HRESULT_TYPEDEF_(0x8010002CL) +#define SCARD_E_CERTIFICATE_UNAVAILABLE _HRESULT_TYPEDEF_(0x8010002DL) +#define SCARD_E_NO_READERS_AVAILABLE _HRESULT_TYPEDEF_(0x8010002EL) +#define SCARD_E_COMM_DATA_LOST _HRESULT_TYPEDEF_(0x8010002FL) +#define SCARD_E_NO_KEY_CONTAINER _HRESULT_TYPEDEF_(0x80100030L) +#define SCARD_E_SERVER_TOO_BUSY _HRESULT_TYPEDEF_(0x80100031L) +#define SCARD_W_UNSUPPORTED_CARD _HRESULT_TYPEDEF_(0x80100065L) +#define SCARD_W_UNRESPONSIVE_CARD _HRESULT_TYPEDEF_(0x80100066L) +#define SCARD_W_UNPOWERED_CARD _HRESULT_TYPEDEF_(0x80100067L) +#define SCARD_W_RESET_CARD _HRESULT_TYPEDEF_(0x80100068L) +#define SCARD_W_REMOVED_CARD _HRESULT_TYPEDEF_(0x80100069L) +#define SCARD_W_SECURITY_VIOLATION _HRESULT_TYPEDEF_(0x8010006AL) +#define SCARD_W_WRONG_CHV _HRESULT_TYPEDEF_(0x8010006BL) +#define SCARD_W_CHV_BLOCKED _HRESULT_TYPEDEF_(0x8010006CL) +#define SCARD_W_EOF _HRESULT_TYPEDEF_(0x8010006DL) +#define SCARD_W_CANCELLED_BY_USER _HRESULT_TYPEDEF_(0x8010006EL) +#define SCARD_W_CARD_NOT_AUTHENTICATED _HRESULT_TYPEDEF_(0x8010006FL) +#define COMADMIN_E_OBJECTERRORS _HRESULT_TYPEDEF_(0x80110401L) +#define COMADMIN_E_OBJECTINVALID _HRESULT_TYPEDEF_(0x80110402L) +#define COMADMIN_E_KEYMISSING _HRESULT_TYPEDEF_(0x80110403L) +#define COMADMIN_E_ALREADYINSTALLED _HRESULT_TYPEDEF_(0x80110404L) +#define COMADMIN_E_APP_FILE_WRITEFAIL _HRESULT_TYPEDEF_(0x80110407L) +#define COMADMIN_E_APP_FILE_READFAIL _HRESULT_TYPEDEF_(0x80110408L) +#define COMADMIN_E_APP_FILE_VERSION _HRESULT_TYPEDEF_(0x80110409L) +#define COMADMIN_E_BADPATH _HRESULT_TYPEDEF_(0x8011040AL) +#define COMADMIN_E_APPLICATIONEXISTS _HRESULT_TYPEDEF_(0x8011040BL) +#define COMADMIN_E_ROLEEXISTS _HRESULT_TYPEDEF_(0x8011040CL) +#define COMADMIN_E_CANTCOPYFILE _HRESULT_TYPEDEF_(0x8011040DL) +#define COMADMIN_E_NOUSER _HRESULT_TYPEDEF_(0x8011040FL) +#define COMADMIN_E_INVALIDUSERIDS _HRESULT_TYPEDEF_(0x80110410L) +#define COMADMIN_E_NOREGISTRYCLSID _HRESULT_TYPEDEF_(0x80110411L) +#define COMADMIN_E_BADREGISTRYPROGID _HRESULT_TYPEDEF_(0x80110412L) +#define COMADMIN_E_AUTHENTICATIONLEVEL _HRESULT_TYPEDEF_(0x80110413L) +#define COMADMIN_E_USERPASSWDNOTVALID _HRESULT_TYPEDEF_(0x80110414L) +#define COMADMIN_E_CLSIDORIIDMISMATCH _HRESULT_TYPEDEF_(0x80110418L) +#define COMADMIN_E_REMOTEINTERFACE _HRESULT_TYPEDEF_(0x80110419L) +#define COMADMIN_E_DLLREGISTERSERVER _HRESULT_TYPEDEF_(0x8011041AL) +#define COMADMIN_E_NOSERVERSHARE _HRESULT_TYPEDEF_(0x8011041BL) +#define COMADMIN_E_DLLLOADFAILED _HRESULT_TYPEDEF_(0x8011041DL) +#define COMADMIN_E_BADREGISTRYLIBID _HRESULT_TYPEDEF_(0x8011041EL) +#define COMADMIN_E_APPDIRNOTFOUND _HRESULT_TYPEDEF_(0x8011041FL) +#define COMADMIN_E_REGISTRARFAILED _HRESULT_TYPEDEF_(0x80110423L) +#define COMADMIN_E_COMPFILE_DOESNOTEXIST _HRESULT_TYPEDEF_(0x80110424L) +#define COMADMIN_E_COMPFILE_LOADDLLFAIL _HRESULT_TYPEDEF_(0x80110425L) +#define COMADMIN_E_COMPFILE_GETCLASSOBJ _HRESULT_TYPEDEF_(0x80110426L) +#define COMADMIN_E_COMPFILE_CLASSNOTAVAIL _HRESULT_TYPEDEF_(0x80110427L) +#define COMADMIN_E_COMPFILE_BADTLB _HRESULT_TYPEDEF_(0x80110428L) +#define COMADMIN_E_COMPFILE_NOTINSTALLABLE _HRESULT_TYPEDEF_(0x80110429L) +#define COMADMIN_E_NOTCHANGEABLE _HRESULT_TYPEDEF_(0x8011042AL) +#define COMADMIN_E_NOTDELETEABLE _HRESULT_TYPEDEF_(0x8011042BL) +#define COMADMIN_E_SESSION _HRESULT_TYPEDEF_(0x8011042CL) +#define COMADMIN_E_COMP_MOVE_LOCKED _HRESULT_TYPEDEF_(0x8011042DL) +#define COMADMIN_E_COMP_MOVE_BAD_DEST _HRESULT_TYPEDEF_(0x8011042EL) +#define COMADMIN_E_REGISTERTLB _HRESULT_TYPEDEF_(0x80110430L) +#define COMADMIN_E_SYSTEMAPP _HRESULT_TYPEDEF_(0x80110433L) +#define COMADMIN_E_COMPFILE_NOREGISTRAR _HRESULT_TYPEDEF_(0x80110434L) +#define COMADMIN_E_COREQCOMPINSTALLED _HRESULT_TYPEDEF_(0x80110435L) +#define COMADMIN_E_SERVICENOTINSTALLED _HRESULT_TYPEDEF_(0x80110436L) +#define COMADMIN_E_PROPERTYSAVEFAILED _HRESULT_TYPEDEF_(0x80110437L) +#define COMADMIN_E_OBJECTEXISTS _HRESULT_TYPEDEF_(0x80110438L) +#define COMADMIN_E_COMPONENTEXISTS _HRESULT_TYPEDEF_(0x80110439L) +#define COMADMIN_E_REGFILE_CORRUPT _HRESULT_TYPEDEF_(0x8011043BL) +#define COMADMIN_E_PROPERTY_OVERFLOW _HRESULT_TYPEDEF_(0x8011043CL) +#define COMADMIN_E_NOTINREGISTRY _HRESULT_TYPEDEF_(0x8011043EL) +#define COMADMIN_E_OBJECTNOTPOOLABLE _HRESULT_TYPEDEF_(0x8011043FL) +#define COMADMIN_E_APPLID_MATCHES_CLSID _HRESULT_TYPEDEF_(0x80110446L) +#define COMADMIN_E_ROLE_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110447L) +#define COMADMIN_E_START_APP_NEEDS_COMPONENTS _HRESULT_TYPEDEF_(0x80110448L) +#define COMADMIN_E_REQUIRES_DIFFERENT_PLATFORM _HRESULT_TYPEDEF_(0x80110449L) +#define COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY _HRESULT_TYPEDEF_(0x8011044AL) +#define COMADMIN_E_CAN_NOT_START_APP _HRESULT_TYPEDEF_(0x8011044BL) +#define COMADMIN_E_CAN_NOT_EXPORT_SYS_APP _HRESULT_TYPEDEF_(0x8011044CL) +#define COMADMIN_E_CANT_SUBSCRIBE_TO_COMPONENT _HRESULT_TYPEDEF_(0x8011044DL) +#define COMADMIN_E_EVENTCLASS_CANT_BE_SUBSCRIBER _HRESULT_TYPEDEF_(0x8011044EL) +#define COMADMIN_E_LIB_APP_PROXY_INCOMPATIBLE _HRESULT_TYPEDEF_(0x8011044FL) +#define COMADMIN_E_BASE_PARTITION_ONLY _HRESULT_TYPEDEF_(0x80110450L) +#define COMADMIN_E_START_APP_DISABLED _HRESULT_TYPEDEF_(0x80110451L) +#define COMADMIN_E_CAT_DUPLICATE_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110457L) +#define COMADMIN_E_CAT_INVALID_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110458L) +#define COMADMIN_E_CAT_PARTITION_IN_USE _HRESULT_TYPEDEF_(0x80110459L) +#define COMADMIN_E_FILE_PARTITION_DUPLICATE_FILES _HRESULT_TYPEDEF_(0x8011045AL) +#define COMADMIN_E_CAT_IMPORTED_COMPONENTS_NOT_ALLOWED _HRESULT_TYPEDEF_(0x8011045BL) +#define COMADMIN_E_AMBIGUOUS_APPLICATION_NAME _HRESULT_TYPEDEF_(0x8011045CL) +#define COMADMIN_E_AMBIGUOUS_PARTITION_NAME _HRESULT_TYPEDEF_(0x8011045DL) +#define COMADMIN_E_REGDB_NOTINITIALIZED _HRESULT_TYPEDEF_(0x80110472L) +#define COMADMIN_E_REGDB_NOTOPEN _HRESULT_TYPEDEF_(0x80110473L) +#define COMADMIN_E_REGDB_SYSTEMERR _HRESULT_TYPEDEF_(0x80110474L) +#define COMADMIN_E_REGDB_ALREADYRUNNING _HRESULT_TYPEDEF_(0x80110475L) +#define COMADMIN_E_MIG_VERSIONNOTSUPPORTED _HRESULT_TYPEDEF_(0x80110480L) +#define COMADMIN_E_MIG_SCHEMANOTFOUND _HRESULT_TYPEDEF_(0x80110481L) +#define COMADMIN_E_CAT_BITNESSMISMATCH _HRESULT_TYPEDEF_(0x80110482L) +#define COMADMIN_E_CAT_UNACCEPTABLEBITNESS _HRESULT_TYPEDEF_(0x80110483L) +#define COMADMIN_E_CAT_WRONGAPPBITNESS _HRESULT_TYPEDEF_(0x80110484L) +#define COMADMIN_E_CAT_PAUSE_RESUME_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80110485L) +#define COMADMIN_E_CAT_SERVERFAULT _HRESULT_TYPEDEF_(0x80110486L) +#define COMQC_E_APPLICATION_NOT_QUEUED _HRESULT_TYPEDEF_(0x80110600L) +#define COMQC_E_NO_QUEUEABLE_INTERFACES _HRESULT_TYPEDEF_(0x80110601L) +#define COMQC_E_QUEUING_SERVICE_NOT_AVAILABLE _HRESULT_TYPEDEF_(0x80110602L) +#define COMQC_E_NO_IPERSISTSTREAM _HRESULT_TYPEDEF_(0x80110603L) +#define COMQC_E_BAD_MESSAGE _HRESULT_TYPEDEF_(0x80110604L) +#define COMQC_E_UNAUTHENTICATED _HRESULT_TYPEDEF_(0x80110605L) +#define COMQC_E_UNTRUSTED_ENQUEUER _HRESULT_TYPEDEF_(0x80110606L) +#define MSDTC_E_DUPLICATE_RESOURCE _HRESULT_TYPEDEF_(0x80110701L) +#define COMADMIN_E_OBJECT_PARENT_MISSING _HRESULT_TYPEDEF_(0x80110808L) +#define COMADMIN_E_OBJECT_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110809L) +#define COMADMIN_E_APP_NOT_RUNNING _HRESULT_TYPEDEF_(0x8011080AL) +#define COMADMIN_E_INVALID_PARTITION _HRESULT_TYPEDEF_(0x8011080BL) +#define COMADMIN_E_SVCAPP_NOT_POOLABLE_OR_RECYCLABLE _HRESULT_TYPEDEF_(0x8011080DL) +#define COMADMIN_E_USER_IN_SET _HRESULT_TYPEDEF_(0x8011080EL) +#define COMADMIN_E_CANTRECYCLELIBRARYAPPS _HRESULT_TYPEDEF_(0x8011080FL) +#define COMADMIN_E_CANTRECYCLESERVICEAPPS _HRESULT_TYPEDEF_(0x80110811L) +#define COMADMIN_E_PROCESSALREADYRECYCLED _HRESULT_TYPEDEF_(0x80110812L) +#define COMADMIN_E_PAUSEDPROCESSMAYNOTBERECYCLED _HRESULT_TYPEDEF_(0x80110813L) +#define COMADMIN_E_CANTMAKEINPROCSERVICE _HRESULT_TYPEDEF_(0x80110814L) +#define COMADMIN_E_PROGIDINUSEBYCLSID _HRESULT_TYPEDEF_(0x80110815L) +#define COMADMIN_E_DEFAULT_PARTITION_NOT_IN_SET _HRESULT_TYPEDEF_(0x80110816L) +#define COMADMIN_E_RECYCLEDPROCESSMAYNOTBEPAUSED _HRESULT_TYPEDEF_(0x80110817L) +#define COMADMIN_E_PARTITION_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110818L) +#define COMADMIN_E_PARTITION_MSI_ONLY _HRESULT_TYPEDEF_(0x80110819L) +#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_1_0_FORMAT _HRESULT_TYPEDEF_(0x8011081AL) +#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_NONBASE_PARTITIONS _HRESULT_TYPEDEF_(0x8011081BL) +#define COMADMIN_E_COMP_MOVE_SOURCE _HRESULT_TYPEDEF_(0x8011081CL) +#define COMADMIN_E_COMP_MOVE_DEST _HRESULT_TYPEDEF_(0x8011081DL) +#define COMADMIN_E_COMP_MOVE_PRIVATE _HRESULT_TYPEDEF_(0x8011081EL) +#define COMADMIN_E_BASEPARTITION_REQUIRED_IN_SET _HRESULT_TYPEDEF_(0x8011081FL) +#define COMADMIN_E_CANNOT_ALIAS_EVENTCLASS _HRESULT_TYPEDEF_(0x80110820L) +#define COMADMIN_E_PRIVATE_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110821L) +#define COMADMIN_E_SAFERINVALID _HRESULT_TYPEDEF_(0x80110822L) +#define COMADMIN_E_REGISTRY_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110823L) +#define COMADMIN_E_PARTITIONS_DISABLED _HRESULT_TYPEDEF_(0x80110824L) +#endif /* _WINERROR_ */ diff --git a/tcc/include/winapi/wingdi.h b/tcc/include/winapi/wingdi.h index 63d38917..af33bd2a 100644 --- a/tcc/include/winapi/wingdi.h +++ b/tcc/include/winapi/wingdi.h @@ -1,4080 +1,4080 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINGDI_ -#define _WINGDI_ - -#define WINGDIAPI DECLSPEC_IMPORT -#define WINSPOOLAPI DECLSPEC_IMPORT - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#ifndef NOGDI -#ifndef NORASTEROPS -#define R2_BLACK 1 -#define R2_NOTMERGEPEN 2 -#define R2_MASKNOTPEN 3 -#define R2_NOTCOPYPEN 4 -#define R2_MASKPENNOT 5 -#define R2_NOT 6 -#define R2_XORPEN 7 -#define R2_NOTMASKPEN 8 -#define R2_MASKPEN 9 -#define R2_NOTXORPEN 10 -#define R2_NOP 11 -#define R2_MERGENOTPEN 12 -#define R2_COPYPEN 13 -#define R2_MERGEPENNOT 14 -#define R2_MERGEPEN 15 -#define R2_WHITE 16 -#define R2_LAST 16 - -#define SRCCOPY (DWORD)0x00CC0020 -#define SRCPAINT (DWORD)0x00EE0086 -#define SRCAND (DWORD)0x008800C6 -#define SRCINVERT (DWORD)0x00660046 -#define SRCERASE (DWORD)0x00440328 -#define NOTSRCCOPY (DWORD)0x00330008 -#define NOTSRCERASE (DWORD)0x001100A6 -#define MERGECOPY (DWORD)0x00C000CA -#define MERGEPAINT (DWORD)0x00BB0226 -#define PATCOPY (DWORD)0x00F00021 -#define PATPAINT (DWORD)0x00FB0A09 -#define PATINVERT (DWORD)0x005A0049 -#define DSTINVERT (DWORD)0x00550009 -#define BLACKNESS (DWORD)0x00000042 -#define WHITENESS (DWORD)0x00FF0062 -#define NOMIRRORBITMAP (DWORD)0x80000000 -#define CAPTUREBLT (DWORD)0x40000000 -#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) -#endif - -#define GDI_ERROR (0xFFFFFFFFL) -#define HGDI_ERROR (LongToHandle(0xFFFFFFFFL)) - -#define ERROR 0 -#define NULLREGION 1 -#define SIMPLEREGION 2 -#define COMPLEXREGION 3 -#define RGN_ERROR ERROR - -#define RGN_AND 1 -#define RGN_OR 2 -#define RGN_XOR 3 -#define RGN_DIFF 4 -#define RGN_COPY 5 -#define RGN_MIN RGN_AND -#define RGN_MAX RGN_COPY - -#define BLACKONWHITE 1 -#define WHITEONBLACK 2 -#define COLORONCOLOR 3 -#define HALFTONE 4 -#define MAXSTRETCHBLTMODE 4 - -#define STRETCH_ANDSCANS BLACKONWHITE -#define STRETCH_ORSCANS WHITEONBLACK -#define STRETCH_DELETESCANS COLORONCOLOR -#define STRETCH_HALFTONE HALFTONE - -#define ALTERNATE 1 -#define WINDING 2 -#define POLYFILL_LAST 2 - -#define LAYOUT_RTL 0x00000001 -#define LAYOUT_BTT 0x00000002 -#define LAYOUT_VBH 0x00000004 -#define LAYOUT_ORIENTATIONMASK (LAYOUT_RTL | LAYOUT_BTT | LAYOUT_VBH) -#define LAYOUT_BITMAPORIENTATIONPRESERVED 0x00000008 - -#define TA_NOUPDATECP 0 -#define TA_UPDATECP 1 - -#define TA_LEFT 0 -#define TA_RIGHT 2 -#define TA_CENTER 6 - -#define TA_TOP 0 -#define TA_BOTTOM 8 -#define TA_BASELINE 24 -#define TA_RTLREADING 256 -#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING) - -#define VTA_BASELINE TA_BASELINE -#define VTA_LEFT TA_BOTTOM -#define VTA_RIGHT TA_TOP -#define VTA_CENTER TA_CENTER -#define VTA_BOTTOM TA_RIGHT -#define VTA_TOP TA_LEFT - -#define ETO_OPAQUE 0x0002 -#define ETO_CLIPPED 0x0004 -#define ETO_GLYPH_INDEX 0x0010 -#define ETO_RTLREADING 0x0080 -#define ETO_NUMERICSLOCAL 0x0400 -#define ETO_NUMERICSLATIN 0x0800 -#define ETO_IGNORELANGUAGE 0x1000 -#define ETO_PDY 0x2000 - -#define ASPECT_FILTERING 0x0001 - -#define DCB_RESET 0x0001 -#define DCB_ACCUMULATE 0x0002 -#define DCB_DIRTY DCB_ACCUMULATE -#define DCB_SET (DCB_RESET | DCB_ACCUMULATE) -#define DCB_ENABLE 0x0004 -#define DCB_DISABLE 0x0008 - -#ifndef NOMETAFILE - -#define META_SETBKCOLOR 0x0201 -#define META_SETBKMODE 0x0102 -#define META_SETMAPMODE 0x0103 -#define META_SETROP2 0x0104 -#define META_SETRELABS 0x0105 -#define META_SETPOLYFILLMODE 0x0106 -#define META_SETSTRETCHBLTMODE 0x0107 -#define META_SETTEXTCHAREXTRA 0x0108 -#define META_SETTEXTCOLOR 0x0209 -#define META_SETTEXTJUSTIFICATION 0x020A -#define META_SETWINDOWORG 0x020B -#define META_SETWINDOWEXT 0x020C -#define META_SETVIEWPORTORG 0x020D -#define META_SETVIEWPORTEXT 0x020E -#define META_OFFSETWINDOWORG 0x020F -#define META_SCALEWINDOWEXT 0x0410 -#define META_OFFSETVIEWPORTORG 0x0211 -#define META_SCALEVIEWPORTEXT 0x0412 -#define META_LINETO 0x0213 -#define META_MOVETO 0x0214 -#define META_EXCLUDECLIPRECT 0x0415 -#define META_INTERSECTCLIPRECT 0x0416 -#define META_ARC 0x0817 -#define META_ELLIPSE 0x0418 -#define META_FLOODFILL 0x0419 -#define META_PIE 0x081A -#define META_RECTANGLE 0x041B -#define META_ROUNDRECT 0x061C -#define META_PATBLT 0x061D -#define META_SAVEDC 0x001E -#define META_SETPIXEL 0x041F -#define META_OFFSETCLIPRGN 0x0220 -#define META_TEXTOUT 0x0521 -#define META_BITBLT 0x0922 -#define META_STRETCHBLT 0x0B23 -#define META_POLYGON 0x0324 -#define META_POLYLINE 0x0325 -#define META_ESCAPE 0x0626 -#define META_RESTOREDC 0x0127 -#define META_FILLREGION 0x0228 -#define META_FRAMEREGION 0x0429 -#define META_INVERTREGION 0x012A -#define META_PAINTREGION 0x012B -#define META_SELECTCLIPREGION 0x012C -#define META_SELECTOBJECT 0x012D -#define META_SETTEXTALIGN 0x012E -#define META_CHORD 0x0830 -#define META_SETMAPPERFLAGS 0x0231 -#define META_EXTTEXTOUT 0x0a32 -#define META_SETDIBTODEV 0x0d33 -#define META_SELECTPALETTE 0x0234 -#define META_REALIZEPALETTE 0x0035 -#define META_ANIMATEPALETTE 0x0436 -#define META_SETPALENTRIES 0x0037 -#define META_POLYPOLYGON 0x0538 -#define META_RESIZEPALETTE 0x0139 -#define META_DIBBITBLT 0x0940 -#define META_DIBSTRETCHBLT 0x0b41 -#define META_DIBCREATEPATTERNBRUSH 0x0142 -#define META_STRETCHDIB 0x0f43 -#define META_EXTFLOODFILL 0x0548 -#define META_SETLAYOUT 0x0149 -#define META_DELETEOBJECT 0x01f0 -#define META_CREATEPALETTE 0x00f7 -#define META_CREATEPATTERNBRUSH 0x01F9 -#define META_CREATEPENINDIRECT 0x02FA -#define META_CREATEFONTINDIRECT 0x02FB -#define META_CREATEBRUSHINDIRECT 0x02FC -#define META_CREATEREGION 0x06FF - - typedef struct _DRAWPATRECT { - POINT ptPosition; - POINT ptSize; - WORD wStyle; - WORD wPattern; - } DRAWPATRECT,*PDRAWPATRECT; -#endif - -#define NEWFRAME 1 -#define ABORTDOC 2 -#define NEXTBAND 3 -#define SETCOLORTABLE 4 -#define GETCOLORTABLE 5 -#define FLUSHOUTPUT 6 -#define DRAFTMODE 7 -#define QUERYESCSUPPORT 8 -#define SETABORTPROC 9 -#define STARTDOC 10 -#define ENDDOC 11 -#define GETPHYSPAGESIZE 12 -#define GETPRINTINGOFFSET 13 -#define GETSCALINGFACTOR 14 -#define MFCOMMENT 15 -#define GETPENWIDTH 16 -#define SETCOPYCOUNT 17 -#define SELECTPAPERSOURCE 18 -#define DEVICEDATA 19 -#define PASSTHROUGH 19 -#define GETTECHNOLGY 20 -#define GETTECHNOLOGY 20 -#define SETLINECAP 21 -#define SETLINEJOIN 22 -#define SETMITERLIMIT 23 -#define BANDINFO 24 -#define DRAWPATTERNRECT 25 -#define GETVECTORPENSIZE 26 -#define GETVECTORBRUSHSIZE 27 -#define ENABLEDUPLEX 28 -#define GETSETPAPERBINS 29 -#define GETSETPRINTORIENT 30 -#define ENUMPAPERBINS 31 -#define SETDIBSCALING 32 -#define EPSPRINTING 33 -#define ENUMPAPERMETRICS 34 -#define GETSETPAPERMETRICS 35 -#define POSTSCRIPT_DATA 37 -#define POSTSCRIPT_IGNORE 38 -#define MOUSETRAILS 39 -#define GETDEVICEUNITS 42 - -#define GETEXTENDEDTEXTMETRICS 256 -#define GETEXTENTTABLE 257 -#define GETPAIRKERNTABLE 258 -#define GETTRACKKERNTABLE 259 -#define EXTTEXTOUT 512 -#define GETFACENAME 513 -#define DOWNLOADFACE 514 -#define ENABLERELATIVEWIDTHS 768 -#define ENABLEPAIRKERNING 769 -#define SETKERNTRACK 770 -#define SETALLJUSTVALUES 771 -#define SETCHARSET 772 - -#define STRETCHBLT 2048 -#define METAFILE_DRIVER 2049 -#define GETSETSCREENPARAMS 3072 -#define QUERYDIBSUPPORT 3073 -#define BEGIN_PATH 4096 -#define CLIP_TO_PATH 4097 -#define END_PATH 4098 -#define EXT_DEVICE_CAPS 4099 -#define RESTORE_CTM 4100 -#define SAVE_CTM 4101 -#define SET_ARC_DIRECTION 4102 -#define SET_BACKGROUND_COLOR 4103 -#define SET_POLY_MODE 4104 -#define SET_SCREEN_ANGLE 4105 -#define SET_SPREAD 4106 -#define TRANSFORM_CTM 4107 -#define SET_CLIP_BOX 4108 -#define SET_BOUNDS 4109 -#define SET_MIRROR_MODE 4110 -#define OPENCHANNEL 4110 -#define DOWNLOADHEADER 4111 -#define CLOSECHANNEL 4112 -#define POSTSCRIPT_PASSTHROUGH 4115 -#define ENCAPSULATED_POSTSCRIPT 4116 - -#define POSTSCRIPT_IDENTIFY 4117 -#define POSTSCRIPT_INJECTION 4118 - -#define CHECKJPEGFORMAT 4119 -#define CHECKPNGFORMAT 4120 - -#define GET_PS_FEATURESETTING 4121 - -#define SPCLPASSTHROUGH2 4568 - -#define PSIDENT_GDICENTRIC 0 -#define PSIDENT_PSCENTRIC 1 - - typedef struct _PSINJECTDATA { - DWORD DataBytes; - WORD InjectionPoint; - WORD PageNumber; - } PSINJECTDATA,*PPSINJECTDATA; - -#define PSINJECT_BEGINSTREAM 1 -#define PSINJECT_PSADOBE 2 -#define PSINJECT_PAGESATEND 3 -#define PSINJECT_PAGES 4 - -#define PSINJECT_DOCNEEDEDRES 5 -#define PSINJECT_DOCSUPPLIEDRES 6 -#define PSINJECT_PAGEORDER 7 -#define PSINJECT_ORIENTATION 8 -#define PSINJECT_BOUNDINGBOX 9 -#define PSINJECT_DOCUMENTPROCESSCOLORS 10 - -#define PSINJECT_COMMENTS 11 -#define PSINJECT_BEGINDEFAULTS 12 -#define PSINJECT_ENDDEFAULTS 13 -#define PSINJECT_BEGINPROLOG 14 -#define PSINJECT_ENDPROLOG 15 -#define PSINJECT_BEGINSETUP 16 -#define PSINJECT_ENDSETUP 17 -#define PSINJECT_TRAILER 18 -#define PSINJECT_EOF 19 -#define PSINJECT_ENDSTREAM 20 -#define PSINJECT_DOCUMENTPROCESSCOLORSATEND 21 - -#define PSINJECT_PAGENUMBER 100 -#define PSINJECT_BEGINPAGESETUP 101 -#define PSINJECT_ENDPAGESETUP 102 -#define PSINJECT_PAGETRAILER 103 -#define PSINJECT_PLATECOLOR 104 - -#define PSINJECT_SHOWPAGE 105 -#define PSINJECT_PAGEBBOX 106 -#define PSINJECT_ENDPAGECOMMENTS 107 - -#define PSINJECT_VMSAVE 200 -#define PSINJECT_VMRESTORE 201 - -#define FEATURESETTING_NUP 0 -#define FEATURESETTING_OUTPUT 1 -#define FEATURESETTING_PSLEVEL 2 -#define FEATURESETTING_CUSTPAPER 3 -#define FEATURESETTING_MIRROR 4 -#define FEATURESETTING_NEGATIVE 5 -#define FEATURESETTING_PROTOCOL 6 - -#define FEATURESETTING_PRIVATE_BEGIN 0x1000 -#define FEATURESETTING_PRIVATE_END 0x1FFF - - typedef struct _PSFEATURE_OUTPUT { - WINBOOL bPageIndependent; - WINBOOL bSetPageDevice; - } PSFEATURE_OUTPUT,*PPSFEATURE_OUTPUT; - - typedef struct _PSFEATURE_CUSTPAPER { - LONG lOrientation; - LONG lWidth; - LONG lHeight; - LONG lWidthOffset; - LONG lHeightOffset; - } PSFEATURE_CUSTPAPER,*PPSFEATURE_CUSTPAPER; - -#define PSPROTOCOL_ASCII 0 -#define PSPROTOCOL_BCP 1 -#define PSPROTOCOL_TBCP 2 -#define PSPROTOCOL_BINARY 3 - -#define QDI_SETDIBITS 1 -#define QDI_GETDIBITS 2 -#define QDI_DIBTOSCREEN 4 -#define QDI_STRETCHDIB 8 - -#define SP_NOTREPORTED 0x4000 -#define SP_ERROR (-1) -#define SP_APPABORT (-2) -#define SP_USERABORT (-3) -#define SP_OUTOFDISK (-4) -#define SP_OUTOFMEMORY (-5) - -#define PR_JOBSTATUS 0x0000 - -#define OBJ_PEN 1 -#define OBJ_BRUSH 2 -#define OBJ_DC 3 -#define OBJ_METADC 4 -#define OBJ_PAL 5 -#define OBJ_FONT 6 -#define OBJ_BITMAP 7 -#define OBJ_REGION 8 -#define OBJ_METAFILE 9 -#define OBJ_MEMDC 10 -#define OBJ_EXTPEN 11 -#define OBJ_ENHMETADC 12 -#define OBJ_ENHMETAFILE 13 -#define OBJ_COLORSPACE 14 - -#define MWT_IDENTITY 1 -#define MWT_LEFTMULTIPLY 2 -#define MWT_RIGHTMULTIPLY 3 - -#define MWT_MIN MWT_IDENTITY -#define MWT_MAX MWT_RIGHTMULTIPLY - -#define _XFORM_ - typedef struct tagXFORM { - FLOAT eM11; - FLOAT eM12; - FLOAT eM21; - FLOAT eM22; - FLOAT eDx; - FLOAT eDy; - } XFORM,*PXFORM,*LPXFORM; - - typedef struct tagBITMAP { - LONG bmType; - LONG bmWidth; - LONG bmHeight; - LONG bmWidthBytes; - WORD bmPlanes; - WORD bmBitsPixel; - LPVOID bmBits; - } BITMAP,*PBITMAP,*NPBITMAP,*LPBITMAP; - -#include - typedef struct tagRGBTRIPLE { - BYTE rgbtBlue; - BYTE rgbtGreen; - BYTE rgbtRed; - } RGBTRIPLE; -#include - - typedef struct tagRGBQUAD { - BYTE rgbBlue; - BYTE rgbGreen; - BYTE rgbRed; - BYTE rgbReserved; - } RGBQUAD; - typedef RGBQUAD *LPRGBQUAD; - -#define CS_ENABLE 0x00000001L -#define CS_DISABLE 0x00000002L -#define CS_DELETE_TRANSFORM 0x00000003L - -//!__TINYC__: #define LCS_SIGNATURE 'PSOC' -//!__TINYC__: #define LCS_sRGB 'sRGB' -//!__TINYC__: #define LCS_WINDOWS_COLOR_SPACE 'Win ' - - typedef LONG LCSCSTYPE; -#define LCS_CALIBRATED_RGB 0x00000000L - - typedef LONG LCSGAMUTMATCH; -#define LCS_GM_BUSINESS 0x00000001L -#define LCS_GM_GRAPHICS 0x00000002L -#define LCS_GM_IMAGES 0x00000004L -#define LCS_GM_ABS_COLORIMETRIC 0x00000008L - -#define CM_OUT_OF_GAMUT 255 -#define CM_IN_GAMUT 0 - -#define ICM_ADDPROFILE 1 -#define ICM_DELETEPROFILE 2 -#define ICM_QUERYPROFILE 3 -#define ICM_SETDEFAULTPROFILE 4 -#define ICM_REGISTERICMATCHER 5 -#define ICM_UNREGISTERICMATCHER 6 -#define ICM_QUERYMATCH 7 - -#define GetKValue(cmyk) ((BYTE)(cmyk)) -#define GetYValue(cmyk) ((BYTE)((cmyk)>> 8)) -#define GetMValue(cmyk) ((BYTE)((cmyk)>>16)) -#define GetCValue(cmyk) ((BYTE)((cmyk)>>24)) - -#define CMYK(c,m,y,k) ((COLORREF)((((BYTE)(k)|((WORD)((BYTE)(y))<<8))|(((DWORD)(BYTE)(m))<<16))|(((DWORD)(BYTE)(c))<<24))) - - typedef long FXPT16DOT16,*LPFXPT16DOT16; - typedef long FXPT2DOT30,*LPFXPT2DOT30; - - typedef struct tagCIEXYZ { - FXPT2DOT30 ciexyzX; - FXPT2DOT30 ciexyzY; - FXPT2DOT30 ciexyzZ; - } CIEXYZ; - typedef CIEXYZ *LPCIEXYZ; - - typedef struct tagICEXYZTRIPLE { - CIEXYZ ciexyzRed; - CIEXYZ ciexyzGreen; - CIEXYZ ciexyzBlue; - } CIEXYZTRIPLE; - - typedef CIEXYZTRIPLE *LPCIEXYZTRIPLE; - - typedef struct tagLOGCOLORSPACEA { - DWORD lcsSignature; - DWORD lcsVersion; - DWORD lcsSize; - LCSCSTYPE lcsCSType; - LCSGAMUTMATCH lcsIntent; - CIEXYZTRIPLE lcsEndpoints; - DWORD lcsGammaRed; - DWORD lcsGammaGreen; - DWORD lcsGammaBlue; - CHAR lcsFilename[MAX_PATH]; - } LOGCOLORSPACEA,*LPLOGCOLORSPACEA; - - typedef struct tagLOGCOLORSPACEW { - DWORD lcsSignature; - DWORD lcsVersion; - DWORD lcsSize; - LCSCSTYPE lcsCSType; - LCSGAMUTMATCH lcsIntent; - CIEXYZTRIPLE lcsEndpoints; - DWORD lcsGammaRed; - DWORD lcsGammaGreen; - DWORD lcsGammaBlue; - WCHAR lcsFilename[MAX_PATH]; - } LOGCOLORSPACEW,*LPLOGCOLORSPACEW; - -#ifdef UNICODE - typedef LOGCOLORSPACEW LOGCOLORSPACE; - typedef LPLOGCOLORSPACEW LPLOGCOLORSPACE; -#else - typedef LOGCOLORSPACEA LOGCOLORSPACE; - typedef LPLOGCOLORSPACEA LPLOGCOLORSPACE; -#endif - - typedef struct tagBITMAPCOREHEADER { - DWORD bcSize; - WORD bcWidth; - WORD bcHeight; - WORD bcPlanes; - WORD bcBitCount; - } BITMAPCOREHEADER,*LPBITMAPCOREHEADER,*PBITMAPCOREHEADER; - - typedef struct tagBITMAPINFOHEADER { - DWORD biSize; - LONG biWidth; - LONG biHeight; - WORD biPlanes; - WORD biBitCount; - DWORD biCompression; - DWORD biSizeImage; - LONG biXPelsPerMeter; - LONG biYPelsPerMeter; - DWORD biClrUsed; - DWORD biClrImportant; - } BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER; - - typedef struct { - DWORD bV4Size; - LONG bV4Width; - LONG bV4Height; - WORD bV4Planes; - WORD bV4BitCount; - DWORD bV4V4Compression; - DWORD bV4SizeImage; - LONG bV4XPelsPerMeter; - LONG bV4YPelsPerMeter; - DWORD bV4ClrUsed; - DWORD bV4ClrImportant; - DWORD bV4RedMask; - DWORD bV4GreenMask; - DWORD bV4BlueMask; - DWORD bV4AlphaMask; - DWORD bV4CSType; - CIEXYZTRIPLE bV4Endpoints; - DWORD bV4GammaRed; - DWORD bV4GammaGreen; - DWORD bV4GammaBlue; - } BITMAPV4HEADER,*LPBITMAPV4HEADER,*PBITMAPV4HEADER; - - typedef struct { - DWORD bV5Size; - LONG bV5Width; - LONG bV5Height; - WORD bV5Planes; - WORD bV5BitCount; - DWORD bV5Compression; - DWORD bV5SizeImage; - LONG bV5XPelsPerMeter; - LONG bV5YPelsPerMeter; - DWORD bV5ClrUsed; - DWORD bV5ClrImportant; - DWORD bV5RedMask; - DWORD bV5GreenMask; - DWORD bV5BlueMask; - DWORD bV5AlphaMask; - DWORD bV5CSType; - CIEXYZTRIPLE bV5Endpoints; - DWORD bV5GammaRed; - DWORD bV5GammaGreen; - DWORD bV5GammaBlue; - DWORD bV5Intent; - DWORD bV5ProfileData; - DWORD bV5ProfileSize; - DWORD bV5Reserved; - } BITMAPV5HEADER,*LPBITMAPV5HEADER,*PBITMAPV5HEADER; - -//!__TINYC__: #define PROFILE_LINKED 'LINK' -//!__TINYC__: #define PROFILE_EMBEDDED 'MBED' - -#define BI_RGB 0L -#define BI_RLE8 1L -#define BI_RLE4 2L -#define BI_BITFIELDS 3L -#define BI_JPEG 4L -#define BI_PNG 5L - - typedef struct tagBITMAPINFO { - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[1]; - } BITMAPINFO,*LPBITMAPINFO,*PBITMAPINFO; - - typedef struct tagBITMAPCOREINFO { - BITMAPCOREHEADER bmciHeader; - RGBTRIPLE bmciColors[1]; - } BITMAPCOREINFO,*LPBITMAPCOREINFO,*PBITMAPCOREINFO; - -#include - typedef struct tagBITMAPFILEHEADER { - WORD bfType; - DWORD bfSize; - WORD bfReserved1; - WORD bfReserved2; - DWORD bfOffBits; - } BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER; -#include - -#define MAKEPOINTS(l) (*((POINTS *)&(l))) - -#ifndef NOFONTSIG - typedef struct tagFONTSIGNATURE { - DWORD fsUsb[4]; - DWORD fsCsb[2]; - } FONTSIGNATURE,*PFONTSIGNATURE,*LPFONTSIGNATURE; - - typedef struct tagCHARSETINFO { - UINT ciCharset; - UINT ciACP; - FONTSIGNATURE fs; - } CHARSETINFO,*PCHARSETINFO,*NPCHARSETINFO,*LPCHARSETINFO; - -#define TCI_SRCCHARSET 1 -#define TCI_SRCCODEPAGE 2 -#define TCI_SRCFONTSIG 3 -#define TCI_SRCLOCALE 0x1000 - - typedef struct tagLOCALESIGNATURE { - DWORD lsUsb[4]; - DWORD lsCsbDefault[2]; - DWORD lsCsbSupported[2]; - } LOCALESIGNATURE,*PLOCALESIGNATURE,*LPLOCALESIGNATURE; -#endif - - -#ifndef NOMETAFILE - typedef struct tagHANDLETABLE { - HGDIOBJ objectHandle[1]; - } HANDLETABLE,*PHANDLETABLE,*LPHANDLETABLE; - - typedef struct tagMETARECORD { - DWORD rdSize; - WORD rdFunction; - WORD rdParm[1]; - } METARECORD; - typedef struct tagMETARECORD UNALIGNED *PMETARECORD; - typedef struct tagMETARECORD UNALIGNED *LPMETARECORD; - - typedef struct tagMETAFILEPICT { - LONG mm; - LONG xExt; - LONG yExt; - HMETAFILE hMF; - } METAFILEPICT,*LPMETAFILEPICT; - -#include - typedef struct tagMETAHEADER { - WORD mtType; - WORD mtHeaderSize; - WORD mtVersion; - DWORD mtSize; - WORD mtNoObjects; - DWORD mtMaxRecord; - WORD mtNoParameters; - } METAHEADER; - typedef struct tagMETAHEADER UNALIGNED *PMETAHEADER; - typedef struct tagMETAHEADER UNALIGNED *LPMETAHEADER; - -#include - - typedef struct tagENHMETARECORD { - DWORD iType; - DWORD nSize; - DWORD dParm[1]; - } ENHMETARECORD,*PENHMETARECORD,*LPENHMETARECORD; - - typedef struct tagENHMETAHEADER { - DWORD iType; - DWORD nSize; - RECTL rclBounds; - RECTL rclFrame; - DWORD dSignature; - DWORD nVersion; - DWORD nBytes; - DWORD nRecords; - WORD nHandles; - WORD sReserved; - DWORD nDescription; - DWORD offDescription; - DWORD nPalEntries; - SIZEL szlDevice; - SIZEL szlMillimeters; - DWORD cbPixelFormat; - DWORD offPixelFormat; - DWORD bOpenGL; - SIZEL szlMicrometers; - } ENHMETAHEADER,*PENHMETAHEADER,*LPENHMETAHEADER; -#endif - -#ifndef NOTEXTMETRIC -#define TMPF_FIXED_PITCH 0x01 -#define TMPF_VECTOR 0x02 -#define TMPF_DEVICE 0x08 -#define TMPF_TRUETYPE 0x04 - -#ifdef UNICODE - typedef WCHAR BCHAR; -#else - typedef BYTE BCHAR; -#endif - -#ifndef _TEXTMETRIC_DEFINED -#define _TEXTMETRIC_DEFINED - typedef struct tagTEXTMETRICA { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - BYTE tmFirstChar; - BYTE tmLastChar; - BYTE tmDefaultChar; - BYTE tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - } TEXTMETRICA,*PTEXTMETRICA,*NPTEXTMETRICA,*LPTEXTMETRICA; - - typedef struct tagTEXTMETRICW { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - WCHAR tmFirstChar; - WCHAR tmLastChar; - WCHAR tmDefaultChar; - WCHAR tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - } TEXTMETRICW,*PTEXTMETRICW,*NPTEXTMETRICW,*LPTEXTMETRICW; -#ifdef UNICODE - typedef TEXTMETRICW TEXTMETRIC; - typedef PTEXTMETRICW PTEXTMETRIC; - typedef NPTEXTMETRICW NPTEXTMETRIC; - typedef LPTEXTMETRICW LPTEXTMETRIC; -#else - typedef TEXTMETRICA TEXTMETRIC; - typedef PTEXTMETRICA PTEXTMETRIC; - typedef NPTEXTMETRICA NPTEXTMETRIC; - typedef LPTEXTMETRICA LPTEXTMETRIC; -#endif -#endif - -#define NTM_REGULAR 0x00000040L -#define NTM_BOLD 0x00000020L -#define NTM_ITALIC 0x00000001L - -#define NTM_NONNEGATIVE_AC 0x00010000 -#define NTM_PS_OPENTYPE 0x00020000 -#define NTM_TT_OPENTYPE 0x00040000 -#define NTM_MULTIPLEMASTER 0x00080000 -#define NTM_TYPE1 0x00100000 -#define NTM_DSIG 0x00200000 - -#include - typedef struct tagNEWTEXTMETRICA { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - BYTE tmFirstChar; - BYTE tmLastChar; - BYTE tmDefaultChar; - BYTE tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - DWORD ntmFlags; - UINT ntmSizeEM; - UINT ntmCellHeight; - UINT ntmAvgWidth; - } NEWTEXTMETRICA,*PNEWTEXTMETRICA,*NPNEWTEXTMETRICA,*LPNEWTEXTMETRICA; - - typedef struct tagNEWTEXTMETRICW { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - WCHAR tmFirstChar; - WCHAR tmLastChar; - WCHAR tmDefaultChar; - WCHAR tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - DWORD ntmFlags; - UINT ntmSizeEM; - UINT ntmCellHeight; - UINT ntmAvgWidth; - } NEWTEXTMETRICW,*PNEWTEXTMETRICW,*NPNEWTEXTMETRICW,*LPNEWTEXTMETRICW; -#ifdef UNICODE - typedef NEWTEXTMETRICW NEWTEXTMETRIC; - typedef PNEWTEXTMETRICW PNEWTEXTMETRIC; - typedef NPNEWTEXTMETRICW NPNEWTEXTMETRIC; - typedef LPNEWTEXTMETRICW LPNEWTEXTMETRIC; -#else - typedef NEWTEXTMETRICA NEWTEXTMETRIC; - typedef PNEWTEXTMETRICA PNEWTEXTMETRIC; - typedef NPNEWTEXTMETRICA NPNEWTEXTMETRIC; - typedef LPNEWTEXTMETRICA LPNEWTEXTMETRIC; -#endif -#include - - typedef struct tagNEWTEXTMETRICEXA { - NEWTEXTMETRICA ntmTm; - FONTSIGNATURE ntmFontSig; - } NEWTEXTMETRICEXA; - - typedef struct tagNEWTEXTMETRICEXW { - NEWTEXTMETRICW ntmTm; - FONTSIGNATURE ntmFontSig; - } NEWTEXTMETRICEXW; -#ifdef UNICODE - typedef NEWTEXTMETRICEXW NEWTEXTMETRICEX; -#else - typedef NEWTEXTMETRICEXA NEWTEXTMETRICEX; -#endif -#endif - - typedef struct tagPELARRAY { - LONG paXCount; - LONG paYCount; - LONG paXExt; - LONG paYExt; - BYTE paRGBs; - } PELARRAY,*PPELARRAY,*NPPELARRAY,*LPPELARRAY; - - typedef struct tagLOGBRUSH { - UINT lbStyle; - COLORREF lbColor; - ULONG_PTR lbHatch; - } LOGBRUSH,*PLOGBRUSH,*NPLOGBRUSH,*LPLOGBRUSH; - - typedef struct tagLOGBRUSH32 { - UINT lbStyle; - COLORREF lbColor; - ULONG lbHatch; - } LOGBRUSH32,*PLOGBRUSH32,*NPLOGBRUSH32,*LPLOGBRUSH32; - - typedef LOGBRUSH PATTERN; - typedef PATTERN *PPATTERN; - typedef PATTERN *NPPATTERN; - typedef PATTERN *LPPATTERN; - - typedef struct tagLOGPEN { - UINT lopnStyle; - POINT lopnWidth; - COLORREF lopnColor; - } LOGPEN,*PLOGPEN,*NPLOGPEN,*LPLOGPEN; - - typedef struct tagEXTLOGPEN { - DWORD elpPenStyle; - DWORD elpWidth; - UINT elpBrushStyle; - COLORREF elpColor; - ULONG_PTR elpHatch; - DWORD elpNumEntries; - DWORD elpStyleEntry[1]; - } EXTLOGPEN,*PEXTLOGPEN,*NPEXTLOGPEN,*LPEXTLOGPEN; - -#ifndef _PALETTEENTRY_DEFINED -#define _PALETTEENTRY_DEFINED - typedef struct tagPALETTEENTRY { - BYTE peRed; - BYTE peGreen; - BYTE peBlue; - BYTE peFlags; - } PALETTEENTRY,*PPALETTEENTRY,*LPPALETTEENTRY; -#endif - -#ifndef _LOGPALETTE_DEFINED -#define _LOGPALETTE_DEFINED - - typedef struct tagLOGPALETTE { - WORD palVersion; - WORD palNumEntries; - PALETTEENTRY palPalEntry[1]; - } LOGPALETTE,*PLOGPALETTE,*NPLOGPALETTE,*LPLOGPALETTE; -#endif - -#define LF_FACESIZE 32 - - typedef struct tagLOGFONTA { - LONG lfHeight; - LONG lfWidth; - LONG lfEscapement; - LONG lfOrientation; - LONG lfWeight; - BYTE lfItalic; - BYTE lfUnderline; - BYTE lfStrikeOut; - BYTE lfCharSet; - BYTE lfOutPrecision; - BYTE lfClipPrecision; - BYTE lfQuality; - BYTE lfPitchAndFamily; - CHAR lfFaceName[LF_FACESIZE]; - } LOGFONTA,*PLOGFONTA,*NPLOGFONTA,*LPLOGFONTA; - - typedef struct tagLOGFONTW { - LONG lfHeight; - LONG lfWidth; - LONG lfEscapement; - LONG lfOrientation; - LONG lfWeight; - BYTE lfItalic; - BYTE lfUnderline; - BYTE lfStrikeOut; - BYTE lfCharSet; - BYTE lfOutPrecision; - BYTE lfClipPrecision; - BYTE lfQuality; - BYTE lfPitchAndFamily; - WCHAR lfFaceName[LF_FACESIZE]; - } LOGFONTW,*PLOGFONTW,*NPLOGFONTW,*LPLOGFONTW; -#ifdef UNICODE - typedef LOGFONTW LOGFONT; - typedef PLOGFONTW PLOGFONT; - typedef NPLOGFONTW NPLOGFONT; - typedef LPLOGFONTW LPLOGFONT; -#else - typedef LOGFONTA LOGFONT; - typedef PLOGFONTA PLOGFONT; - typedef NPLOGFONTA NPLOGFONT; - typedef LPLOGFONTA LPLOGFONT; -#endif - -#define LF_FULLFACESIZE 64 - - typedef struct tagENUMLOGFONTA { - LOGFONTA elfLogFont; - BYTE elfFullName[LF_FULLFACESIZE]; - BYTE elfStyle[LF_FACESIZE]; - } ENUMLOGFONTA,*LPENUMLOGFONTA; - - typedef struct tagENUMLOGFONTW { - LOGFONTW elfLogFont; - WCHAR elfFullName[LF_FULLFACESIZE]; - WCHAR elfStyle[LF_FACESIZE]; - } ENUMLOGFONTW,*LPENUMLOGFONTW; -#ifdef UNICODE - typedef ENUMLOGFONTW ENUMLOGFONT; - typedef LPENUMLOGFONTW LPENUMLOGFONT; -#else - typedef ENUMLOGFONTA ENUMLOGFONT; - typedef LPENUMLOGFONTA LPENUMLOGFONT; -#endif - - typedef struct tagENUMLOGFONTEXA { - LOGFONTA elfLogFont; - BYTE elfFullName[LF_FULLFACESIZE]; - BYTE elfStyle[LF_FACESIZE]; - BYTE elfScript[LF_FACESIZE]; - } ENUMLOGFONTEXA,*LPENUMLOGFONTEXA; - - typedef struct tagENUMLOGFONTEXW { - LOGFONTW elfLogFont; - WCHAR elfFullName[LF_FULLFACESIZE]; - WCHAR elfStyle[LF_FACESIZE]; - WCHAR elfScript[LF_FACESIZE]; - } ENUMLOGFONTEXW,*LPENUMLOGFONTEXW; -#ifdef UNICODE - typedef ENUMLOGFONTEXW ENUMLOGFONTEX; - typedef LPENUMLOGFONTEXW LPENUMLOGFONTEX; -#else - typedef ENUMLOGFONTEXA ENUMLOGFONTEX; - typedef LPENUMLOGFONTEXA LPENUMLOGFONTEX; -#endif - -#define OUT_DEFAULT_PRECIS 0 -#define OUT_STRING_PRECIS 1 -#define OUT_CHARACTER_PRECIS 2 -#define OUT_STROKE_PRECIS 3 -#define OUT_TT_PRECIS 4 -#define OUT_DEVICE_PRECIS 5 -#define OUT_RASTER_PRECIS 6 -#define OUT_TT_ONLY_PRECIS 7 -#define OUT_OUTLINE_PRECIS 8 -#define OUT_SCREEN_OUTLINE_PRECIS 9 -#define OUT_PS_ONLY_PRECIS 10 - -#define CLIP_DEFAULT_PRECIS 0 -#define CLIP_CHARACTER_PRECIS 1 -#define CLIP_STROKE_PRECIS 2 -#define CLIP_MASK 0xf -#define CLIP_LH_ANGLES (1<<4) -#define CLIP_TT_ALWAYS (2<<4) -#define CLIP_DFA_DISABLE (4<<4) -#define CLIP_EMBEDDED (8<<4) - -#define DEFAULT_QUALITY 0 -#define DRAFT_QUALITY 1 -#define PROOF_QUALITY 2 -#define NONANTIALIASED_QUALITY 3 -#define ANTIALIASED_QUALITY 4 - -#define CLEARTYPE_QUALITY 5 -#define CLEARTYPE_NATURAL_QUALITY 6 - -#define DEFAULT_PITCH 0 -#define FIXED_PITCH 1 -#define VARIABLE_PITCH 2 -#define MONO_FONT 8 - -#define ANSI_CHARSET 0 -#define DEFAULT_CHARSET 1 -#define SYMBOL_CHARSET 2 -#define SHIFTJIS_CHARSET 128 -#define HANGEUL_CHARSET 129 -#define HANGUL_CHARSET 129 -#define GB2312_CHARSET 134 -#define CHINESEBIG5_CHARSET 136 -#define OEM_CHARSET 255 -#define JOHAB_CHARSET 130 -#define HEBREW_CHARSET 177 -#define ARABIC_CHARSET 178 -#define GREEK_CHARSET 161 -#define TURKISH_CHARSET 162 -#define VIETNAMESE_CHARSET 163 -#define THAI_CHARSET 222 -#define EASTEUROPE_CHARSET 238 -#define RUSSIAN_CHARSET 204 - -#define MAC_CHARSET 77 -#define BALTIC_CHARSET 186 - -#define FS_LATIN1 0x00000001L -#define FS_LATIN2 0x00000002L -#define FS_CYRILLIC 0x00000004L -#define FS_GREEK 0x00000008L -#define FS_TURKISH 0x00000010L -#define FS_HEBREW 0x00000020L -#define FS_ARABIC 0x00000040L -#define FS_BALTIC 0x00000080L -#define FS_VIETNAMESE 0x00000100L -#define FS_THAI 0x00010000L -#define FS_JISJAPAN 0x00020000L -#define FS_CHINESESIMP 0x00040000L -#define FS_WANSUNG 0x00080000L -#define FS_CHINESETRAD 0x00100000L -#define FS_JOHAB 0x00200000L -#define FS_SYMBOL 0x80000000L - -#define FF_DONTCARE (0<<4) -#define FF_ROMAN (1<<4) - -#define FF_SWISS (2<<4) - -#define FF_MODERN (3<<4) - -#define FF_SCRIPT (4<<4) -#define FF_DECORATIVE (5<<4) - -#define FW_DONTCARE 0 -#define FW_THIN 100 -#define FW_EXTRALIGHT 200 -#define FW_LIGHT 300 -#define FW_NORMAL 400 -#define FW_MEDIUM 500 -#define FW_SEMIBOLD 600 -#define FW_BOLD 700 -#define FW_EXTRABOLD 800 -#define FW_HEAVY 900 - -#define FW_ULTRALIGHT FW_EXTRALIGHT -#define FW_REGULAR FW_NORMAL -#define FW_DEMIBOLD FW_SEMIBOLD -#define FW_ULTRABOLD FW_EXTRABOLD -#define FW_BLACK FW_HEAVY - -#define PANOSE_COUNT 10 -#define PAN_FAMILYTYPE_INDEX 0 -#define PAN_SERIFSTYLE_INDEX 1 -#define PAN_WEIGHT_INDEX 2 -#define PAN_PROPORTION_INDEX 3 -#define PAN_CONTRAST_INDEX 4 -#define PAN_STROKEVARIATION_INDEX 5 -#define PAN_ARMSTYLE_INDEX 6 -#define PAN_LETTERFORM_INDEX 7 -#define PAN_MIDLINE_INDEX 8 -#define PAN_XHEIGHT_INDEX 9 - -#define PAN_CULTURE_LATIN 0 - - typedef struct tagPANOSE { - BYTE bFamilyType; - BYTE bSerifStyle; - BYTE bWeight; - BYTE bProportion; - BYTE bContrast; - BYTE bStrokeVariation; - BYTE bArmStyle; - BYTE bLetterform; - BYTE bMidline; - BYTE bXHeight; - } PANOSE,*LPPANOSE; - -#define PAN_ANY 0 -#define PAN_NO_FIT 1 - -#define PAN_FAMILY_TEXT_DISPLAY 2 -#define PAN_FAMILY_SCRIPT 3 -#define PAN_FAMILY_DECORATIVE 4 -#define PAN_FAMILY_PICTORIAL 5 - -#define PAN_SERIF_COVE 2 -#define PAN_SERIF_OBTUSE_COVE 3 -#define PAN_SERIF_SQUARE_COVE 4 -#define PAN_SERIF_OBTUSE_SQUARE_COVE 5 -#define PAN_SERIF_SQUARE 6 -#define PAN_SERIF_THIN 7 -#define PAN_SERIF_BONE 8 -#define PAN_SERIF_EXAGGERATED 9 -#define PAN_SERIF_TRIANGLE 10 -#define PAN_SERIF_NORMAL_SANS 11 -#define PAN_SERIF_OBTUSE_SANS 12 -#define PAN_SERIF_PERP_SANS 13 -#define PAN_SERIF_FLARED 14 -#define PAN_SERIF_ROUNDED 15 - -#define PAN_WEIGHT_VERY_LIGHT 2 -#define PAN_WEIGHT_LIGHT 3 -#define PAN_WEIGHT_THIN 4 -#define PAN_WEIGHT_BOOK 5 -#define PAN_WEIGHT_MEDIUM 6 -#define PAN_WEIGHT_DEMI 7 -#define PAN_WEIGHT_BOLD 8 -#define PAN_WEIGHT_HEAVY 9 -#define PAN_WEIGHT_BLACK 10 -#define PAN_WEIGHT_NORD 11 - -#define PAN_PROP_OLD_STYLE 2 -#define PAN_PROP_MODERN 3 -#define PAN_PROP_EVEN_WIDTH 4 -#define PAN_PROP_EXPANDED 5 -#define PAN_PROP_CONDENSED 6 -#define PAN_PROP_VERY_EXPANDED 7 -#define PAN_PROP_VERY_CONDENSED 8 -#define PAN_PROP_MONOSPACED 9 - -#define PAN_CONTRAST_NONE 2 -#define PAN_CONTRAST_VERY_LOW 3 -#define PAN_CONTRAST_LOW 4 -#define PAN_CONTRAST_MEDIUM_LOW 5 -#define PAN_CONTRAST_MEDIUM 6 -#define PAN_CONTRAST_MEDIUM_HIGH 7 -#define PAN_CONTRAST_HIGH 8 -#define PAN_CONTRAST_VERY_HIGH 9 - -#define PAN_STROKE_GRADUAL_DIAG 2 -#define PAN_STROKE_GRADUAL_TRAN 3 -#define PAN_STROKE_GRADUAL_VERT 4 -#define PAN_STROKE_GRADUAL_HORZ 5 -#define PAN_STROKE_RAPID_VERT 6 -#define PAN_STROKE_RAPID_HORZ 7 -#define PAN_STROKE_INSTANT_VERT 8 - -#define PAN_STRAIGHT_ARMS_HORZ 2 -#define PAN_STRAIGHT_ARMS_WEDGE 3 -#define PAN_STRAIGHT_ARMS_VERT 4 -#define PAN_STRAIGHT_ARMS_SINGLE_SERIF 5 -#define PAN_STRAIGHT_ARMS_DOUBLE_SERIF 6 -#define PAN_BENT_ARMS_HORZ 7 -#define PAN_BENT_ARMS_WEDGE 8 -#define PAN_BENT_ARMS_VERT 9 -#define PAN_BENT_ARMS_SINGLE_SERIF 10 -#define PAN_BENT_ARMS_DOUBLE_SERIF 11 - -#define PAN_LETT_NORMAL_CONTACT 2 -#define PAN_LETT_NORMAL_WEIGHTED 3 -#define PAN_LETT_NORMAL_BOXED 4 -#define PAN_LETT_NORMAL_FLATTENED 5 -#define PAN_LETT_NORMAL_ROUNDED 6 -#define PAN_LETT_NORMAL_OFF_CENTER 7 -#define PAN_LETT_NORMAL_SQUARE 8 -#define PAN_LETT_OBLIQUE_CONTACT 9 -#define PAN_LETT_OBLIQUE_WEIGHTED 10 -#define PAN_LETT_OBLIQUE_BOXED 11 -#define PAN_LETT_OBLIQUE_FLATTENED 12 -#define PAN_LETT_OBLIQUE_ROUNDED 13 -#define PAN_LETT_OBLIQUE_OFF_CENTER 14 -#define PAN_LETT_OBLIQUE_SQUARE 15 - -#define PAN_MIDLINE_STANDARD_TRIMMED 2 -#define PAN_MIDLINE_STANDARD_POINTED 3 -#define PAN_MIDLINE_STANDARD_SERIFED 4 -#define PAN_MIDLINE_HIGH_TRIMMED 5 -#define PAN_MIDLINE_HIGH_POINTED 6 -#define PAN_MIDLINE_HIGH_SERIFED 7 -#define PAN_MIDLINE_CONSTANT_TRIMMED 8 -#define PAN_MIDLINE_CONSTANT_POINTED 9 -#define PAN_MIDLINE_CONSTANT_SERIFED 10 -#define PAN_MIDLINE_LOW_TRIMMED 11 -#define PAN_MIDLINE_LOW_POINTED 12 -#define PAN_MIDLINE_LOW_SERIFED 13 - -#define PAN_XHEIGHT_CONSTANT_SMALL 2 -#define PAN_XHEIGHT_CONSTANT_STD 3 -#define PAN_XHEIGHT_CONSTANT_LARGE 4 -#define PAN_XHEIGHT_DUCKING_SMALL 5 -#define PAN_XHEIGHT_DUCKING_STD 6 -#define PAN_XHEIGHT_DUCKING_LARGE 7 - -#define ELF_VENDOR_SIZE 4 - - typedef struct tagEXTLOGFONTA { - LOGFONTA elfLogFont; - BYTE elfFullName[LF_FULLFACESIZE]; - BYTE elfStyle[LF_FACESIZE]; - DWORD elfVersion; - DWORD elfStyleSize; - DWORD elfMatch; - DWORD elfReserved; - BYTE elfVendorId[ELF_VENDOR_SIZE]; - DWORD elfCulture; - PANOSE elfPanose; - } EXTLOGFONTA,*PEXTLOGFONTA,*NPEXTLOGFONTA,*LPEXTLOGFONTA; - - typedef struct tagEXTLOGFONTW { - LOGFONTW elfLogFont; - WCHAR elfFullName[LF_FULLFACESIZE]; - WCHAR elfStyle[LF_FACESIZE]; - DWORD elfVersion; - DWORD elfStyleSize; - DWORD elfMatch; - DWORD elfReserved; - BYTE elfVendorId[ELF_VENDOR_SIZE]; - DWORD elfCulture; - PANOSE elfPanose; - } EXTLOGFONTW,*PEXTLOGFONTW,*NPEXTLOGFONTW,*LPEXTLOGFONTW; -#ifdef UNICODE - typedef EXTLOGFONTW EXTLOGFONT; - typedef PEXTLOGFONTW PEXTLOGFONT; - typedef NPEXTLOGFONTW NPEXTLOGFONT; - typedef LPEXTLOGFONTW LPEXTLOGFONT; -#else - typedef EXTLOGFONTA EXTLOGFONT; - typedef PEXTLOGFONTA PEXTLOGFONT; - typedef NPEXTLOGFONTA NPEXTLOGFONT; - typedef LPEXTLOGFONTA LPEXTLOGFONT; -#endif - -#define ELF_VERSION 0 -#define ELF_CULTURE_LATIN 0 - -#define RASTER_FONTTYPE 0x0001 -#define DEVICE_FONTTYPE 0x002 -#define TRUETYPE_FONTTYPE 0x004 - -#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) -#define PALETTERGB(r,g,b) (0x02000000 | RGB(r,g,b)) -#define PALETTEINDEX(i) ((COLORREF)(0x01000000 | (DWORD)(WORD)(i))) - -#define PC_RESERVED 0x01 -#define PC_EXPLICIT 0x02 -#define PC_NOCOLLAPSE 0x04 - -#define GetRValue(rgb) (LOBYTE(rgb)) -#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8)) -#define GetBValue(rgb) (LOBYTE((rgb)>>16)) - -#define TRANSPARENT 1 -#define OPAQUE 2 -#define BKMODE_LAST 2 - -#define GM_COMPATIBLE 1 -#define GM_ADVANCED 2 -#define GM_LAST 2 - -#define PT_CLOSEFIGURE 0x01 -#define PT_LINETO 0x02 -#define PT_BEZIERTO 0x04 -#define PT_MOVETO 0x06 - -#define MM_TEXT 1 -#define MM_LOMETRIC 2 -#define MM_HIMETRIC 3 -#define MM_LOENGLISH 4 -#define MM_HIENGLISH 5 -#define MM_TWIPS 6 -#define MM_ISOTROPIC 7 -#define MM_ANISOTROPIC 8 - -#define MM_MIN MM_TEXT -#define MM_MAX MM_ANISOTROPIC -#define MM_MAX_FIXEDSCALE MM_TWIPS - -#define ABSOLUTE 1 -#define RELATIVE 2 - -#define WHITE_BRUSH 0 -#define LTGRAY_BRUSH 1 -#define GRAY_BRUSH 2 -#define DKGRAY_BRUSH 3 -#define BLACK_BRUSH 4 -#define NULL_BRUSH 5 -#define HOLLOW_BRUSH NULL_BRUSH -#define WHITE_PEN 6 -#define BLACK_PEN 7 -#define NULL_PEN 8 -#define OEM_FIXED_FONT 10 -#define ANSI_FIXED_FONT 11 -#define ANSI_VAR_FONT 12 -#define SYSTEM_FONT 13 -#define DEVICE_DEFAULT_FONT 14 -#define DEFAULT_PALETTE 15 -#define SYSTEM_FIXED_FONT 16 - -#define DEFAULT_GUI_FONT 17 - -#define DC_BRUSH 18 -#define DC_PEN 19 - -#define STOCK_LAST 19 - -#define CLR_INVALID 0xFFFFFFFF - -#define BS_SOLID 0 -#define BS_NULL 1 -#define BS_HOLLOW BS_NULL -#define BS_HATCHED 2 -#define BS_PATTERN 3 -#define BS_INDEXED 4 -#define BS_DIBPATTERN 5 -#define BS_DIBPATTERNPT 6 -#define BS_PATTERN8X8 7 -#define BS_DIBPATTERN8X8 8 -#define BS_MONOPATTERN 9 - -#define HS_HORIZONTAL 0 -#define HS_VERTICAL 1 -#define HS_FDIAGONAL 2 -#define HS_BDIAGONAL 3 -#define HS_CROSS 4 -#define HS_DIAGCROSS 5 - -#define PS_SOLID 0 -#define PS_DASH 1 -#define PS_DOT 2 -#define PS_DASHDOT 3 -#define PS_DASHDOTDOT 4 -#define PS_NULL 5 -#define PS_INSIDEFRAME 6 -#define PS_USERSTYLE 7 -#define PS_ALTERNATE 8 -#define PS_STYLE_MASK 0x0000000F - -#define PS_ENDCAP_ROUND 0x00000000 -#define PS_ENDCAP_SQUARE 0x00000100 -#define PS_ENDCAP_FLAT 0x00000200 -#define PS_ENDCAP_MASK 0x00000F00 - -#define PS_JOIN_ROUND 0x00000000 -#define PS_JOIN_BEVEL 0x00001000 -#define PS_JOIN_MITER 0x00002000 -#define PS_JOIN_MASK 0x0000F000 - -#define PS_COSMETIC 0x00000000 -#define PS_GEOMETRIC 0x00010000 -#define PS_TYPE_MASK 0x000F0000 - -#define AD_COUNTERCLOCKWISE 1 -#define AD_CLOCKWISE 2 - -#define DRIVERVERSION 0 -#define TECHNOLOGY 2 -#define HORZSIZE 4 -#define VERTSIZE 6 -#define HORZRES 8 -#define VERTRES 10 -#define BITSPIXEL 12 -#define PLANES 14 -#define NUMBRUSHES 16 -#define NUMPENS 18 -#define NUMMARKERS 20 -#define NUMFONTS 22 -#define NUMCOLORS 24 -#define PDEVICESIZE 26 -#define CURVECAPS 28 -#define LINECAPS 30 -#define POLYGONALCAPS 32 -#define TEXTCAPS 34 -#define CLIPCAPS 36 -#define RASTERCAPS 38 -#define ASPECTX 40 -#define ASPECTY 42 -#define ASPECTXY 44 - -#define LOGPIXELSX 88 -#define LOGPIXELSY 90 - -#define SIZEPALETTE 104 -#define NUMRESERVED 106 -#define COLORRES 108 - -#define PHYSICALWIDTH 110 -#define PHYSICALHEIGHT 111 -#define PHYSICALOFFSETX 112 -#define PHYSICALOFFSETY 113 -#define SCALINGFACTORX 114 -#define SCALINGFACTORY 115 - -#define VREFRESH 116 - -#define DESKTOPVERTRES 117 - -#define DESKTOPHORZRES 118 - -#define BLTALIGNMENT 119 - -#define SHADEBLENDCAPS 120 -#define COLORMGMTCAPS 121 - -#ifndef NOGDICAPMASKS -#define DT_PLOTTER 0 -#define DT_RASDISPLAY 1 -#define DT_RASPRINTER 2 -#define DT_RASCAMERA 3 -#define DT_CHARSTREAM 4 -#define DT_METAFILE 5 -#define DT_DISPFILE 6 - -#define CC_NONE 0 -#define CC_CIRCLES 1 -#define CC_PIE 2 -#define CC_CHORD 4 -#define CC_ELLIPSES 8 -#define CC_WIDE 16 -#define CC_STYLED 32 -#define CC_WIDESTYLED 64 -#define CC_INTERIORS 128 -#define CC_ROUNDRECT 256 - -#define LC_NONE 0 -#define LC_POLYLINE 2 -#define LC_MARKER 4 -#define LC_POLYMARKER 8 -#define LC_WIDE 16 -#define LC_STYLED 32 -#define LC_WIDESTYLED 64 -#define LC_INTERIORS 128 - -#define PC_NONE 0 -#define PC_POLYGON 1 -#define PC_RECTANGLE 2 -#define PC_WINDPOLYGON 4 -#define PC_TRAPEZOID 4 -#define PC_SCANLINE 8 -#define PC_WIDE 16 -#define PC_STYLED 32 -#define PC_WIDESTYLED 64 -#define PC_INTERIORS 128 -#define PC_POLYPOLYGON 256 -#define PC_PATHS 512 - -#define CP_NONE 0 -#define CP_RECTANGLE 1 -#define CP_REGION 2 - -#define TC_OP_CHARACTER 0x00000001 -#define TC_OP_STROKE 0x00000002 -#define TC_CP_STROKE 0x00000004 -#define TC_CR_90 0x00000008 -#define TC_CR_ANY 0x00000010 -#define TC_SF_X_YINDEP 0x00000020 -#define TC_SA_DOUBLE 0x00000040 -#define TC_SA_INTEGER 0x00000080 -#define TC_SA_CONTIN 0x00000100 -#define TC_EA_DOUBLE 0x00000200 -#define TC_IA_ABLE 0x00000400 -#define TC_UA_ABLE 0x00000800 -#define TC_SO_ABLE 0x00001000 -#define TC_RA_ABLE 0x00002000 -#define TC_VA_ABLE 0x00004000 -#define TC_RESERVED 0x00008000 -#define TC_SCROLLBLT 0x00010000 -#endif - -#define RC_NONE -#define RC_BITBLT 1 -#define RC_BANDING 2 -#define RC_SCALING 4 -#define RC_BITMAP64 8 -#define RC_GDI20_OUTPUT 0x0010 -#define RC_GDI20_STATE 0x0020 -#define RC_SAVEBITMAP 0x0040 -#define RC_DI_BITMAP 0x0080 -#define RC_PALETTE 0x0100 -#define RC_DIBTODEV 0x0200 -#define RC_BIGFONT 0x0400 -#define RC_STRETCHBLT 0x0800 -#define RC_FLOODFILL 0x1000 -#define RC_STRETCHDIB 0x2000 -#define RC_OP_DX_OUTPUT 0x4000 -#define RC_DEVBITS 0x8000 - -#define SB_NONE 0x00000000 -#define SB_CONST_ALPHA 0x00000001 -#define SB_PIXEL_ALPHA 0x00000002 -#define SB_PREMULT_ALPHA 0x00000004 - -#define SB_GRAD_RECT 0x00000010 -#define SB_GRAD_TRI 0x00000020 - -#define CM_NONE 0x00000000 -#define CM_DEVICE_ICM 0x00000001 -#define CM_GAMMA_RAMP 0x00000002 -#define CM_CMYK_COLOR 0x00000004 - -#define DIB_RGB_COLORS 0 -#define DIB_PAL_COLORS 1 - -#define SYSPAL_ERROR 0 -#define SYSPAL_STATIC 1 -#define SYSPAL_NOSTATIC 2 -#define SYSPAL_NOSTATIC256 3 - -#define CBM_INIT 0x04L - -#define FLOODFILLBORDER 0 -#define FLOODFILLSURFACE 1 - -#define CCHDEVICENAME 32 - -#define CCHFORMNAME 32 - - typedef struct _devicemodeA { - BYTE dmDeviceName[CCHDEVICENAME]; - WORD dmSpecVersion; - WORD dmDriverVersion; - WORD dmSize; - WORD dmDriverExtra; - DWORD dmFields; - union { - struct { - short dmOrientation; - short dmPaperSize; - short dmPaperLength; - short dmPaperWidth; - short dmScale; - short dmCopies; - short dmDefaultSource; - short dmPrintQuality; - }; - struct { - POINTL dmPosition; - DWORD dmDisplayOrientation; - DWORD dmDisplayFixedOutput; - }; - }; - short dmColor; - short dmDuplex; - short dmYResolution; - short dmTTOption; - short dmCollate; - BYTE dmFormName[CCHFORMNAME]; - WORD dmLogPixels; - DWORD dmBitsPerPel; - DWORD dmPelsWidth; - DWORD dmPelsHeight; - union { - DWORD dmDisplayFlags; - DWORD dmNup; - }; - DWORD dmDisplayFrequency; - DWORD dmICMMethod; - DWORD dmICMIntent; - DWORD dmMediaType; - DWORD dmDitherType; - DWORD dmReserved1; - DWORD dmReserved2; - DWORD dmPanningWidth; - DWORD dmPanningHeight; - } DEVMODEA,*PDEVMODEA,*NPDEVMODEA,*LPDEVMODEA; - - typedef struct _devicemodeW { - WCHAR dmDeviceName[CCHDEVICENAME]; - WORD dmSpecVersion; - WORD dmDriverVersion; - WORD dmSize; - WORD dmDriverExtra; - DWORD dmFields; - union { - struct { - short dmOrientation; - short dmPaperSize; - short dmPaperLength; - short dmPaperWidth; - short dmScale; - short dmCopies; - short dmDefaultSource; - short dmPrintQuality; - }; - struct { - POINTL dmPosition; - DWORD dmDisplayOrientation; - DWORD dmDisplayFixedOutput; - }; - }; - short dmColor; - short dmDuplex; - short dmYResolution; - short dmTTOption; - short dmCollate; - WCHAR dmFormName[CCHFORMNAME]; - WORD dmLogPixels; - DWORD dmBitsPerPel; - DWORD dmPelsWidth; - DWORD dmPelsHeight; - union { - DWORD dmDisplayFlags; - DWORD dmNup; - }; - DWORD dmDisplayFrequency; - DWORD dmICMMethod; - DWORD dmICMIntent; - DWORD dmMediaType; - DWORD dmDitherType; - DWORD dmReserved1; - DWORD dmReserved2; - DWORD dmPanningWidth; - DWORD dmPanningHeight; - } DEVMODEW,*PDEVMODEW,*NPDEVMODEW,*LPDEVMODEW; -#ifdef UNICODE - typedef DEVMODEW DEVMODE; - typedef PDEVMODEW PDEVMODE; - typedef NPDEVMODEW NPDEVMODE; - typedef LPDEVMODEW LPDEVMODE; -#else - typedef DEVMODEA DEVMODE; - typedef PDEVMODEA PDEVMODE; - typedef NPDEVMODEA NPDEVMODE; - typedef LPDEVMODEA LPDEVMODE; -#endif - -#define DM_SPECVERSION 0x0401 - -#define DM_ORIENTATION 0x00000001L -#define DM_PAPERSIZE 0x00000002L -#define DM_PAPERLENGTH 0x00000004L -#define DM_PAPERWIDTH 0x00000008L -#define DM_SCALE 0x00000010L -#define DM_POSITION 0x00000020L -#define DM_NUP 0x00000040L -#define DM_DISPLAYORIENTATION 0x00000080L -#define DM_COPIES 0x00000100L -#define DM_DEFAULTSOURCE 0x00000200L -#define DM_PRINTQUALITY 0x00000400L -#define DM_COLOR 0x00000800L -#define DM_DUPLEX 0x00001000L -#define DM_YRESOLUTION 0x00002000L -#define DM_TTOPTION 0x00004000L -#define DM_COLLATE 0x00008000L -#define DM_FORMNAME 0x00010000L -#define DM_LOGPIXELS 0x00020000L -#define DM_BITSPERPEL 0x00040000L -#define DM_PELSWIDTH 0x00080000L -#define DM_PELSHEIGHT 0x00100000L -#define DM_DISPLAYFLAGS 0x00200000L -#define DM_DISPLAYFREQUENCY 0x00400000L -#define DM_ICMMETHOD 0x00800000L -#define DM_ICMINTENT 0x01000000L -#define DM_MEDIATYPE 0x02000000L -#define DM_DITHERTYPE 0x04000000L -#define DM_PANNINGWIDTH 0x08000000L -#define DM_PANNINGHEIGHT 0x10000000L -#define DM_DISPLAYFIXEDOUTPUT 0x20000000L - -#define DMORIENT_PORTRAIT 1 -#define DMORIENT_LANDSCAPE 2 - -#define DMPAPER_FIRST DMPAPER_LETTER -#define DMPAPER_LETTER 1 -#define DMPAPER_LETTERSMALL 2 -#define DMPAPER_TABLOID 3 -#define DMPAPER_LEDGER 4 -#define DMPAPER_LEGAL 5 -#define DMPAPER_STATEMENT 6 -#define DMPAPER_EXECUTIVE 7 -#define DMPAPER_A3 8 -#define DMPAPER_A4 9 -#define DMPAPER_A4SMALL 10 -#define DMPAPER_A5 11 -#define DMPAPER_B4 12 -#define DMPAPER_B5 13 -#define DMPAPER_FOLIO 14 -#define DMPAPER_QUARTO 15 -#define DMPAPER_10X14 16 -#define DMPAPER_11X17 17 -#define DMPAPER_NOTE 18 -#define DMPAPER_ENV_9 19 -#define DMPAPER_ENV_10 20 -#define DMPAPER_ENV_11 21 -#define DMPAPER_ENV_12 22 -#define DMPAPER_ENV_14 23 -#define DMPAPER_CSHEET 24 -#define DMPAPER_DSHEET 25 -#define DMPAPER_ESHEET 26 -#define DMPAPER_ENV_DL 27 -#define DMPAPER_ENV_C5 28 -#define DMPAPER_ENV_C3 29 -#define DMPAPER_ENV_C4 30 -#define DMPAPER_ENV_C6 31 -#define DMPAPER_ENV_C65 32 -#define DMPAPER_ENV_B4 33 -#define DMPAPER_ENV_B5 34 -#define DMPAPER_ENV_B6 35 -#define DMPAPER_ENV_ITALY 36 -#define DMPAPER_ENV_MONARCH 37 -#define DMPAPER_ENV_PERSONAL 38 -#define DMPAPER_FANFOLD_US 39 -#define DMPAPER_FANFOLD_STD_GERMAN 40 -#define DMPAPER_FANFOLD_LGL_GERMAN 41 -#define DMPAPER_ISO_B4 42 -#define DMPAPER_JAPANESE_POSTCARD 43 -#define DMPAPER_9X11 44 -#define DMPAPER_10X11 45 -#define DMPAPER_15X11 46 -#define DMPAPER_ENV_INVITE 47 -#define DMPAPER_RESERVED_48 48 -#define DMPAPER_RESERVED_49 49 -#define DMPAPER_LETTER_EXTRA 50 -#define DMPAPER_LEGAL_EXTRA 51 -#define DMPAPER_TABLOID_EXTRA 52 -#define DMPAPER_A4_EXTRA 53 -#define DMPAPER_LETTER_TRANSVERSE 54 -#define DMPAPER_A4_TRANSVERSE 55 -#define DMPAPER_LETTER_EXTRA_TRANSVERSE 56 -#define DMPAPER_A_PLUS 57 -#define DMPAPER_B_PLUS 58 -#define DMPAPER_LETTER_PLUS 59 -#define DMPAPER_A4_PLUS 60 -#define DMPAPER_A5_TRANSVERSE 61 -#define DMPAPER_B5_TRANSVERSE 62 -#define DMPAPER_A3_EXTRA 63 -#define DMPAPER_A5_EXTRA 64 -#define DMPAPER_B5_EXTRA 65 -#define DMPAPER_A2 66 -#define DMPAPER_A3_TRANSVERSE 67 -#define DMPAPER_A3_EXTRA_TRANSVERSE 68 -#define DMPAPER_DBL_JAPANESE_POSTCARD 69 -#define DMPAPER_A6 70 -#define DMPAPER_JENV_KAKU2 71 -#define DMPAPER_JENV_KAKU3 72 -#define DMPAPER_JENV_CHOU3 73 -#define DMPAPER_JENV_CHOU4 74 -#define DMPAPER_LETTER_ROTATED 75 -#define DMPAPER_A3_ROTATED 76 -#define DMPAPER_A4_ROTATED 77 -#define DMPAPER_A5_ROTATED 78 -#define DMPAPER_B4_JIS_ROTATED 79 -#define DMPAPER_B5_JIS_ROTATED 80 -#define DMPAPER_JAPANESE_POSTCARD_ROTATED 81 -#define DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED 82 -#define DMPAPER_A6_ROTATED 83 -#define DMPAPER_JENV_KAKU2_ROTATED 84 -#define DMPAPER_JENV_KAKU3_ROTATED 85 -#define DMPAPER_JENV_CHOU3_ROTATED 86 -#define DMPAPER_JENV_CHOU4_ROTATED 87 -#define DMPAPER_B6_JIS 88 -#define DMPAPER_B6_JIS_ROTATED 89 -#define DMPAPER_12X11 90 -#define DMPAPER_JENV_YOU4 91 -#define DMPAPER_JENV_YOU4_ROTATED 92 -#define DMPAPER_P16K 93 -#define DMPAPER_P32K 94 -#define DMPAPER_P32KBIG 95 -#define DMPAPER_PENV_1 96 -#define DMPAPER_PENV_2 97 -#define DMPAPER_PENV_3 98 -#define DMPAPER_PENV_4 99 -#define DMPAPER_PENV_5 100 -#define DMPAPER_PENV_6 101 -#define DMPAPER_PENV_7 102 -#define DMPAPER_PENV_8 103 -#define DMPAPER_PENV_9 104 -#define DMPAPER_PENV_10 105 -#define DMPAPER_P16K_ROTATED 106 -#define DMPAPER_P32K_ROTATED 107 -#define DMPAPER_P32KBIG_ROTATED 108 -#define DMPAPER_PENV_1_ROTATED 109 -#define DMPAPER_PENV_2_ROTATED 110 -#define DMPAPER_PENV_3_ROTATED 111 -#define DMPAPER_PENV_4_ROTATED 112 -#define DMPAPER_PENV_5_ROTATED 113 -#define DMPAPER_PENV_6_ROTATED 114 -#define DMPAPER_PENV_7_ROTATED 115 -#define DMPAPER_PENV_8_ROTATED 116 -#define DMPAPER_PENV_9_ROTATED 117 -#define DMPAPER_PENV_10_ROTATED 118 - -#define DMPAPER_LAST DMPAPER_PENV_10_ROTATED - -#define DMPAPER_USER 256 - -#define DMBIN_FIRST DMBIN_UPPER -#define DMBIN_UPPER 1 -#define DMBIN_ONLYONE 1 -#define DMBIN_LOWER 2 -#define DMBIN_MIDDLE 3 -#define DMBIN_MANUAL 4 -#define DMBIN_ENVELOPE 5 -#define DMBIN_ENVMANUAL 6 -#define DMBIN_AUTO 7 -#define DMBIN_TRACTOR 8 -#define DMBIN_SMALLFMT 9 -#define DMBIN_LARGEFMT 10 -#define DMBIN_LARGECAPACITY 11 -#define DMBIN_CASSETTE 14 -#define DMBIN_FORMSOURCE 15 -#define DMBIN_LAST DMBIN_FORMSOURCE - -#define DMBIN_USER 256 - -#define DMRES_DRAFT (-1) -#define DMRES_LOW (-2) -#define DMRES_MEDIUM (-3) -#define DMRES_HIGH (-4) - -#define DMCOLOR_MONOCHROME 1 -#define DMCOLOR_COLOR 2 - -#define DMDUP_SIMPLEX 1 -#define DMDUP_VERTICAL 2 -#define DMDUP_HORIZONTAL 3 - -#define DMTT_BITMAP 1 -#define DMTT_DOWNLOAD 2 -#define DMTT_SUBDEV 3 -#define DMTT_DOWNLOAD_OUTLINE 4 - -#define DMCOLLATE_FALSE 0 -#define DMCOLLATE_TRUE 1 - -#define DMDO_DEFAULT 0 -#define DMDO_90 1 -#define DMDO_180 2 -#define DMDO_270 3 - -#define DMDFO_DEFAULT 0 -#define DMDFO_STRETCH 1 -#define DMDFO_CENTER 2 - -#define DMDISPLAYFLAGS_TEXTMODE 0x00000004 - -#define DMNUP_SYSTEM 1 -#define DMNUP_ONEUP 2 - -#define DMICMMETHOD_NONE 1 -#define DMICMMETHOD_SYSTEM 2 -#define DMICMMETHOD_DRIVER 3 -#define DMICMMETHOD_DEVICE 4 - -#define DMICMMETHOD_USER 256 - -#define DMICM_SATURATE 1 -#define DMICM_CONTRAST 2 -#define DMICM_COLORIMETRIC 3 -#define DMICM_ABS_COLORIMETRIC 4 - -#define DMICM_USER 256 - -#define DMMEDIA_STANDARD 1 -#define DMMEDIA_TRANSPARENCY 2 -#define DMMEDIA_GLOSSY 3 - -#define DMMEDIA_USER 256 - -#define DMDITHER_NONE 1 -#define DMDITHER_COARSE 2 -#define DMDITHER_FINE 3 -#define DMDITHER_LINEART 4 -#define DMDITHER_ERRORDIFFUSION 5 -#define DMDITHER_RESERVED6 6 -#define DMDITHER_RESERVED7 7 -#define DMDITHER_RESERVED8 8 -#define DMDITHER_RESERVED9 9 -#define DMDITHER_GRAYSCALE 10 - -#define DMDITHER_USER 256 - - typedef struct _DISPLAY_DEVICEA { - DWORD cb; - CHAR DeviceName[32]; - CHAR DeviceString[128]; - DWORD StateFlags; - CHAR DeviceID[128]; - CHAR DeviceKey[128]; - } DISPLAY_DEVICEA,*PDISPLAY_DEVICEA,*LPDISPLAY_DEVICEA; - typedef struct _DISPLAY_DEVICEW { - DWORD cb; - WCHAR DeviceName[32]; - WCHAR DeviceString[128]; - DWORD StateFlags; - WCHAR DeviceID[128]; - WCHAR DeviceKey[128]; - } DISPLAY_DEVICEW,*PDISPLAY_DEVICEW,*LPDISPLAY_DEVICEW; -#ifdef UNICODE - typedef DISPLAY_DEVICEW DISPLAY_DEVICE; - typedef PDISPLAY_DEVICEW PDISPLAY_DEVICE; - typedef LPDISPLAY_DEVICEW LPDISPLAY_DEVICE; -#else - typedef DISPLAY_DEVICEA DISPLAY_DEVICE; - typedef PDISPLAY_DEVICEA PDISPLAY_DEVICE; - typedef LPDISPLAY_DEVICEA LPDISPLAY_DEVICE; -#endif - -#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 -#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002 -#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 -#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 -#define DISPLAY_DEVICE_VGA_COMPATIBLE 0x00000010 -#define DISPLAY_DEVICE_REMOVABLE 0x00000020 -#define DISPLAY_DEVICE_MODESPRUNED 0x08000000 -#define DISPLAY_DEVICE_REMOTE 0x04000000 -#define DISPLAY_DEVICE_DISCONNECT 0x02000000 - -#define DISPLAY_DEVICE_ACTIVE 0x00000001 -#define DISPLAY_DEVICE_ATTACHED 0x00000002 - -#define RDH_RECTANGLES 1 - - typedef struct _RGNDATAHEADER { - DWORD dwSize; - DWORD iType; - DWORD nCount; - DWORD nRgnSize; - RECT rcBound; - } RGNDATAHEADER,*PRGNDATAHEADER; - - typedef struct _RGNDATA { - RGNDATAHEADER rdh; - char Buffer[1]; - } RGNDATA,*PRGNDATA,*NPRGNDATA,*LPRGNDATA; - -#define SYSRGN 4 - - typedef struct _ABC { - int abcA; - UINT abcB; - int abcC; - } ABC,*PABC,*NPABC,*LPABC; - - typedef struct _ABCFLOAT { - FLOAT abcfA; - FLOAT abcfB; - FLOAT abcfC; - } ABCFLOAT,*PABCFLOAT,*NPABCFLOAT,*LPABCFLOAT; - -#ifndef NOTEXTMETRIC - - typedef struct _OUTLINETEXTMETRICA { - UINT otmSize; - TEXTMETRICA otmTextMetrics; - BYTE otmFiller; - PANOSE otmPanoseNumber; - UINT otmfsSelection; - UINT otmfsType; - int otmsCharSlopeRise; - int otmsCharSlopeRun; - int otmItalicAngle; - UINT otmEMSquare; - int otmAscent; - int otmDescent; - UINT otmLineGap; - UINT otmsCapEmHeight; - UINT otmsXHeight; - RECT otmrcFontBox; - int otmMacAscent; - int otmMacDescent; - UINT otmMacLineGap; - UINT otmusMinimumPPEM; - POINT otmptSubscriptSize; - POINT otmptSubscriptOffset; - POINT otmptSuperscriptSize; - POINT otmptSuperscriptOffset; - UINT otmsStrikeoutSize; - int otmsStrikeoutPosition; - int otmsUnderscoreSize; - int otmsUnderscorePosition; - PSTR otmpFamilyName; - PSTR otmpFaceName; - PSTR otmpStyleName; - PSTR otmpFullName; - } OUTLINETEXTMETRICA,*POUTLINETEXTMETRICA,*NPOUTLINETEXTMETRICA,*LPOUTLINETEXTMETRICA; - - typedef struct _OUTLINETEXTMETRICW { - UINT otmSize; - TEXTMETRICW otmTextMetrics; - BYTE otmFiller; - PANOSE otmPanoseNumber; - UINT otmfsSelection; - UINT otmfsType; - int otmsCharSlopeRise; - int otmsCharSlopeRun; - int otmItalicAngle; - UINT otmEMSquare; - int otmAscent; - int otmDescent; - UINT otmLineGap; - UINT otmsCapEmHeight; - UINT otmsXHeight; - RECT otmrcFontBox; - int otmMacAscent; - int otmMacDescent; - UINT otmMacLineGap; - UINT otmusMinimumPPEM; - POINT otmptSubscriptSize; - POINT otmptSubscriptOffset; - POINT otmptSuperscriptSize; - POINT otmptSuperscriptOffset; - UINT otmsStrikeoutSize; - int otmsStrikeoutPosition; - int otmsUnderscoreSize; - int otmsUnderscorePosition; - PSTR otmpFamilyName; - PSTR otmpFaceName; - PSTR otmpStyleName; - PSTR otmpFullName; - } OUTLINETEXTMETRICW,*POUTLINETEXTMETRICW,*NPOUTLINETEXTMETRICW,*LPOUTLINETEXTMETRICW; -#ifdef UNICODE - typedef OUTLINETEXTMETRICW OUTLINETEXTMETRIC; - typedef POUTLINETEXTMETRICW POUTLINETEXTMETRIC; - typedef NPOUTLINETEXTMETRICW NPOUTLINETEXTMETRIC; - typedef LPOUTLINETEXTMETRICW LPOUTLINETEXTMETRIC; -#else - typedef OUTLINETEXTMETRICA OUTLINETEXTMETRIC; - typedef POUTLINETEXTMETRICA POUTLINETEXTMETRIC; - typedef NPOUTLINETEXTMETRICA NPOUTLINETEXTMETRIC; - typedef LPOUTLINETEXTMETRICA LPOUTLINETEXTMETRIC; -#endif -#endif - - typedef struct tagPOLYTEXTA { - int x; - int y; - UINT n; - LPCSTR lpstr; - UINT uiFlags; - RECT rcl; - int *pdx; - } POLYTEXTA,*PPOLYTEXTA,*NPPOLYTEXTA,*LPPOLYTEXTA; - - typedef struct tagPOLYTEXTW { - int x; - int y; - UINT n; - LPCWSTR lpstr; - UINT uiFlags; - RECT rcl; - int *pdx; - } POLYTEXTW,*PPOLYTEXTW,*NPPOLYTEXTW,*LPPOLYTEXTW; -#ifdef UNICODE - typedef POLYTEXTW POLYTEXT; - typedef PPOLYTEXTW PPOLYTEXT; - typedef NPPOLYTEXTW NPPOLYTEXT; - typedef LPPOLYTEXTW LPPOLYTEXT; -#else - typedef POLYTEXTA POLYTEXT; - typedef PPOLYTEXTA PPOLYTEXT; - typedef NPPOLYTEXTA NPPOLYTEXT; - typedef LPPOLYTEXTA LPPOLYTEXT; -#endif - - typedef struct _FIXED { - WORD fract; - short value; - } FIXED; - - typedef struct _MAT2 { - FIXED eM11; - FIXED eM12; - FIXED eM21; - FIXED eM22; - } MAT2,*LPMAT2; - - typedef struct _GLYPHMETRICS { - UINT gmBlackBoxX; - UINT gmBlackBoxY; - POINT gmptGlyphOrigin; - short gmCellIncX; - short gmCellIncY; - } GLYPHMETRICS,*LPGLYPHMETRICS; - -#define GGO_METRICS 0 -#define GGO_BITMAP 1 -#define GGO_NATIVE 2 -#define GGO_BEZIER 3 - -#define GGO_GRAY2_BITMAP 4 -#define GGO_GRAY4_BITMAP 5 -#define GGO_GRAY8_BITMAP 6 -#define GGO_GLYPH_INDEX 0x0080 -#define GGO_UNHINTED 0x0100 - -#define TT_POLYGON_TYPE 24 - -#define TT_PRIM_LINE 1 -#define TT_PRIM_QSPLINE 2 -#define TT_PRIM_CSPLINE 3 - - typedef struct tagPOINTFX { - FIXED x; - FIXED y; - } POINTFX,*LPPOINTFX; - - typedef struct tagTTPOLYCURVE { - WORD wType; - WORD cpfx; - POINTFX apfx[1]; - } TTPOLYCURVE,*LPTTPOLYCURVE; - - typedef struct tagTTPOLYGONHEADER { - DWORD cb; - DWORD dwType; - POINTFX pfxStart; - } TTPOLYGONHEADER,*LPTTPOLYGONHEADER; - -#define GCP_DBCS 0x0001 -#define GCP_REORDER 0x0002 -#define GCP_USEKERNING 0x0008 -#define GCP_GLYPHSHAPE 0x0010 -#define GCP_LIGATE 0x0020 - -#define GCP_DIACRITIC 0x0100 -#define GCP_KASHIDA 0x0400 -#define GCP_ERROR 0x8000 -#define FLI_MASK 0x103B - -#define GCP_JUSTIFY 0x00010000L - -#define FLI_GLYPHS 0x00040000L -#define GCP_CLASSIN 0x00080000L -#define GCP_MAXEXTENT 0x00100000L -#define GCP_JUSTIFYIN 0x00200000L -#define GCP_DISPLAYZWG 0x00400000L -#define GCP_SYMSWAPOFF 0x00800000L -#define GCP_NUMERICOVERRIDE 0x01000000L -#define GCP_NEUTRALOVERRIDE 0x02000000L -#define GCP_NUMERICSLATIN 0x04000000L -#define GCP_NUMERICSLOCAL 0x08000000L - -#define GCPCLASS_LATIN 1 -#define GCPCLASS_HEBREW 2 -#define GCPCLASS_ARABIC 2 -#define GCPCLASS_NEUTRAL 3 -#define GCPCLASS_LOCALNUMBER 4 -#define GCPCLASS_LATINNUMBER 5 -#define GCPCLASS_LATINNUMERICTERMINATOR 6 -#define GCPCLASS_LATINNUMERICSEPARATOR 7 -#define GCPCLASS_NUMERICSEPARATOR 8 -#define GCPCLASS_PREBOUNDLTR 0x80 -#define GCPCLASS_PREBOUNDRTL 0x40 -#define GCPCLASS_POSTBOUNDLTR 0x20 -#define GCPCLASS_POSTBOUNDRTL 0x10 - -#define GCPGLYPH_LINKBEFORE 0x8000 -#define GCPGLYPH_LINKAFTER 0x4000 - - typedef struct tagGCP_RESULTSA { - DWORD lStructSize; - LPSTR lpOutString; - UINT *lpOrder; - int *lpDx; - int *lpCaretPos; - LPSTR lpClass; - LPWSTR lpGlyphs; - UINT nGlyphs; - int nMaxFit; - } GCP_RESULTSA,*LPGCP_RESULTSA; - typedef struct tagGCP_RESULTSW { - DWORD lStructSize; - LPWSTR lpOutString; - UINT *lpOrder; - int *lpDx; - int *lpCaretPos; - LPSTR lpClass; - LPWSTR lpGlyphs; - UINT nGlyphs; - int nMaxFit; - } GCP_RESULTSW,*LPGCP_RESULTSW; -#ifdef UNICODE - typedef GCP_RESULTSW GCP_RESULTS; - typedef LPGCP_RESULTSW LPGCP_RESULTS; -#else - typedef GCP_RESULTSA GCP_RESULTS; - typedef LPGCP_RESULTSA LPGCP_RESULTS; -#endif - - typedef struct _RASTERIZER_STATUS { - short nSize; - short wFlags; - short nLanguageID; - } RASTERIZER_STATUS,*LPRASTERIZER_STATUS; - -#define TT_AVAILABLE 0x0001 -#define TT_ENABLED 0x0002 - - typedef struct tagPIXELFORMATDESCRIPTOR { - WORD nSize; - WORD nVersion; - DWORD dwFlags; - BYTE iPixelType; - BYTE cColorBits; - BYTE cRedBits; - BYTE cRedShift; - BYTE cGreenBits; - BYTE cGreenShift; - BYTE cBlueBits; - BYTE cBlueShift; - BYTE cAlphaBits; - BYTE cAlphaShift; - BYTE cAccumBits; - BYTE cAccumRedBits; - BYTE cAccumGreenBits; - BYTE cAccumBlueBits; - BYTE cAccumAlphaBits; - BYTE cDepthBits; - BYTE cStencilBits; - BYTE cAuxBuffers; - BYTE iLayerType; - BYTE bReserved; - DWORD dwLayerMask; - DWORD dwVisibleMask; - DWORD dwDamageMask; - } PIXELFORMATDESCRIPTOR,*PPIXELFORMATDESCRIPTOR,*LPPIXELFORMATDESCRIPTOR; - -#define PFD_TYPE_RGBA 0 -#define PFD_TYPE_COLORINDEX 1 - -#define PFD_MAIN_PLANE 0 -#define PFD_OVERLAY_PLANE 1 -#define PFD_UNDERLAY_PLANE (-1) - -#define PFD_DOUBLEBUFFER 0x00000001 -#define PFD_STEREO 0x00000002 -#define PFD_DRAW_TO_WINDOW 0x00000004 -#define PFD_DRAW_TO_BITMAP 0x00000008 -#define PFD_SUPPORT_GDI 0x00000010 -#define PFD_SUPPORT_OPENGL 0x00000020 -#define PFD_GENERIC_FORMAT 0x00000040 -#define PFD_NEED_PALETTE 0x00000080 -#define PFD_NEED_SYSTEM_PALETTE 0x00000100 -#define PFD_SWAP_EXCHANGE 0x00000200 -#define PFD_SWAP_COPY 0x00000400 -#define PFD_SWAP_LAYER_BUFFERS 0x00000800 -#define PFD_GENERIC_ACCELERATED 0x00001000 -#define PFD_SUPPORT_DIRECTDRAW 0x00002000 - -#define PFD_DEPTH_DONTCARE 0x20000000 -#define PFD_DOUBLEBUFFER_DONTCARE 0x40000000 -#define PFD_STEREO_DONTCARE 0x80000000 - -#ifndef NOTEXTMETRIC - typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST TEXTMETRICA *,DWORD,LPARAM); - typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST TEXTMETRICW *,DWORD,LPARAM); -#ifdef UNICODE -#define OLDFONTENUMPROC OLDFONTENUMPROCW -#else -#define OLDFONTENUMPROC OLDFONTENUMPROCA -#endif -#else - typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST VOID *,DWORD,LPARAM); - typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST VOID *,DWORD,LPARAM); -#ifdef UNICODE -#define OLDFONTENUMPROC OLDFONTENUMPROCW -#else -#define OLDFONTENUMPROC OLDFONTENUMPROCA -#endif -#endif - - typedef OLDFONTENUMPROCA FONTENUMPROCA; - typedef OLDFONTENUMPROCW FONTENUMPROCW; -#ifdef UNICODE - typedef FONTENUMPROCW FONTENUMPROC; -#else - typedef FONTENUMPROCA FONTENUMPROC; -#endif - - typedef int (CALLBACK *GOBJENUMPROC)(LPVOID,LPARAM); - typedef VOID (CALLBACK *LINEDDAPROC)(int,int,LPARAM); - -#ifdef UNICODE -#define AddFontResource AddFontResourceW -#define CopyMetaFile CopyMetaFileW -#define CreateDC CreateDCW -#define CreateFontIndirect CreateFontIndirectW -#define CreateFont CreateFontW -#define CreateIC CreateICW -#define CreateMetaFile CreateMetaFileW -#define CreateScalableFontResource CreateScalableFontResourceW -#else -#define AddFontResource AddFontResourceA -#define CopyMetaFile CopyMetaFileA -#define CreateDC CreateDCA -#define CreateFontIndirect CreateFontIndirectA -#define CreateFont CreateFontA -#define CreateIC CreateICA -#define CreateMetaFile CreateMetaFileA -#define CreateScalableFontResource CreateScalableFontResourceA -#endif - - WINGDIAPI int WINAPI AddFontResourceA(LPCSTR); - WINGDIAPI int WINAPI AddFontResourceW(LPCWSTR); - WINGDIAPI WINBOOL WINAPI AnimatePalette(HPALETTE hPal,UINT iStartIndex,UINT cEntries,CONST PALETTEENTRY *ppe); - WINGDIAPI WINBOOL WINAPI Arc(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); - WINGDIAPI WINBOOL WINAPI BitBlt(HDC hdc,int x,int y,int cx,int cy,HDC hdcSrc,int x1,int y1,DWORD rop); - WINGDIAPI WINBOOL WINAPI CancelDC(HDC hdc); - WINGDIAPI WINBOOL WINAPI Chord(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); - WINGDIAPI int WINAPI ChoosePixelFormat(HDC hdc,CONST PIXELFORMATDESCRIPTOR *ppfd); - WINGDIAPI HMETAFILE WINAPI CloseMetaFile(HDC hdc); - WINGDIAPI int WINAPI CombineRgn(HRGN hrgnDst,HRGN hrgnSrc1,HRGN hrgnSrc2,int iMode); - WINGDIAPI HMETAFILE WINAPI CopyMetaFileA(HMETAFILE,LPCSTR); - WINGDIAPI HMETAFILE WINAPI CopyMetaFileW(HMETAFILE,LPCWSTR); - WINGDIAPI HBITMAP WINAPI CreateBitmap(int nWidth,int nHeight,UINT nPlanes,UINT nBitCount,CONST VOID *lpBits); - WINGDIAPI HBITMAP WINAPI CreateBitmapIndirect(CONST BITMAP *pbm); - WINGDIAPI HBRUSH WINAPI CreateBrushIndirect(CONST LOGBRUSH *plbrush); - WINGDIAPI HBITMAP WINAPI CreateCompatibleBitmap(HDC hdc,int cx,int cy); - WINGDIAPI HBITMAP WINAPI CreateDiscardableBitmap(HDC hdc,int cx,int cy); - WINGDIAPI HDC WINAPI CreateCompatibleDC(HDC hdc); - WINGDIAPI HDC WINAPI CreateDCA(LPCSTR pwszDriver,LPCSTR pwszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); - WINGDIAPI HDC WINAPI CreateDCW(LPCWSTR pwszDriver,LPCWSTR pwszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); - WINGDIAPI HBITMAP WINAPI CreateDIBitmap(HDC hdc,CONST BITMAPINFOHEADER *pbmih,DWORD flInit,CONST VOID *pjBits,CONST BITMAPINFO *pbmi,UINT iUsage); - WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrush(HGLOBAL h,UINT iUsage); - WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrushPt(CONST VOID *lpPackedDIB,UINT iUsage); - WINGDIAPI HRGN WINAPI CreateEllipticRgn(int x1,int y1,int x2,int y2); - WINGDIAPI HRGN WINAPI CreateEllipticRgnIndirect(CONST RECT *lprect); - WINGDIAPI HFONT WINAPI CreateFontIndirectA(CONST LOGFONTA *lplf); - WINGDIAPI HFONT WINAPI CreateFontIndirectW(CONST LOGFONTW *lplf); - WINGDIAPI HFONT WINAPI CreateFontA(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCSTR pszFaceName); - WINGDIAPI HFONT WINAPI CreateFontW(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCWSTR pszFaceName); - WINGDIAPI HBRUSH WINAPI CreateHatchBrush(int iHatch,COLORREF color); - WINGDIAPI HDC WINAPI CreateICA(LPCSTR pszDriver,LPCSTR pszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); - WINGDIAPI HDC WINAPI CreateICW(LPCWSTR pszDriver,LPCWSTR pszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); - WINGDIAPI HDC WINAPI CreateMetaFileA(LPCSTR pszFile); - WINGDIAPI HDC WINAPI CreateMetaFileW(LPCWSTR pszFile); - WINGDIAPI HPALETTE WINAPI CreatePalette(CONST LOGPALETTE *plpal); - WINGDIAPI HPEN WINAPI CreatePen(int iStyle,int cWidth,COLORREF color); - WINGDIAPI HPEN WINAPI CreatePenIndirect(CONST LOGPEN *plpen); - WINGDIAPI HRGN WINAPI CreatePolyPolygonRgn(CONST POINT *pptl,CONST INT *pc,int cPoly,int iMode); - WINGDIAPI HBRUSH WINAPI CreatePatternBrush(HBITMAP hbm); - WINGDIAPI HRGN WINAPI CreateRectRgn(int x1,int y1,int x2,int y2); - WINGDIAPI HRGN WINAPI CreateRectRgnIndirect(CONST RECT *lprect); - WINGDIAPI HRGN WINAPI CreateRoundRectRgn(int x1,int y1,int x2,int y2,int w,int h); - WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceA(DWORD fdwHidden,LPCSTR lpszFont,LPCSTR lpszFile,LPCSTR lpszPath); - WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceW(DWORD fdwHidden,LPCWSTR lpszFont,LPCWSTR lpszFile,LPCWSTR lpszPath); - WINGDIAPI HBRUSH WINAPI CreateSolidBrush(COLORREF color); - WINGDIAPI WINBOOL WINAPI DeleteDC(HDC hdc); - WINGDIAPI WINBOOL WINAPI DeleteMetaFile(HMETAFILE hmf); - WINGDIAPI WINBOOL WINAPI DeleteObject(HGDIOBJ ho); - WINGDIAPI int WINAPI DescribePixelFormat(HDC hdc,int iPixelFormat,UINT nBytes,LPPIXELFORMATDESCRIPTOR ppfd); - - typedef UINT (CALLBACK *LPFNDEVMODE)(HWND,HMODULE,LPDEVMODE,LPSTR,LPSTR,LPDEVMODE,LPSTR,UINT); - typedef DWORD (CALLBACK *LPFNDEVCAPS)(LPSTR,LPSTR,UINT,LPSTR,LPDEVMODE); - -#define DM_UPDATE 1 -#define DM_COPY 2 -#define DM_PROMPT 4 -#define DM_MODIFY 8 - -#define DM_IN_BUFFER DM_MODIFY -#define DM_IN_PROMPT DM_PROMPT -#define DM_OUT_BUFFER DM_COPY -#define DM_OUT_DEFAULT DM_UPDATE - -#define DC_FIELDS 1 -#define DC_PAPERS 2 -#define DC_PAPERSIZE 3 -#define DC_MINEXTENT 4 -#define DC_MAXEXTENT 5 -#define DC_BINS 6 -#define DC_DUPLEX 7 -#define DC_SIZE 8 -#define DC_EXTRA 9 -#define DC_VERSION 10 -#define DC_DRIVER 11 -#define DC_BINNAMES 12 -#define DC_ENUMRESOLUTIONS 13 -#define DC_FILEDEPENDENCIES 14 -#define DC_TRUETYPE 15 -#define DC_PAPERNAMES 16 -#define DC_ORIENTATION 17 -#define DC_COPIES 18 -#define DC_BINADJUST 19 -#define DC_EMF_COMPLIANT 20 -#define DC_DATATYPE_PRODUCED 21 -#define DC_COLLATE 22 -#define DC_MANUFACTURER 23 -#define DC_MODEL 24 -#define DC_PERSONALITY 25 -#define DC_PRINTRATE 26 -#define DC_PRINTRATEUNIT 27 -#define PRINTRATEUNIT_PPM 1 -#define PRINTRATEUNIT_CPS 2 -#define PRINTRATEUNIT_LPM 3 -#define PRINTRATEUNIT_IPM 4 -#define DC_PRINTERMEM 28 -#define DC_MEDIAREADY 29 -#define DC_STAPLE 30 -#define DC_PRINTRATEPPM 31 -#define DC_COLORDEVICE 32 -#define DC_NUP 33 -#define DC_MEDIATYPENAMES 34 -#define DC_MEDIATYPES 35 - -#define DCTT_BITMAP 0x0000001L -#define DCTT_DOWNLOAD 0x0000002L -#define DCTT_SUBDEV 0x0000004L -#define DCTT_DOWNLOAD_OUTLINE 0x0000008L - -#define DCBA_FACEUPNONE 0x0000 -#define DCBA_FACEUPCENTER 0x0001 -#define DCBA_FACEUPLEFT 0x0002 -#define DCBA_FACEUPRIGHT 0x0003 -#define DCBA_FACEDOWNNONE 0x0100 -#define DCBA_FACEDOWNCENTER 0x0101 -#define DCBA_FACEDOWNLEFT 0x0102 -#define DCBA_FACEDOWNRIGHT 0x0103 - -#ifdef UNICODE -#define DeviceCapabilities DeviceCapabilitiesW -#define EnumFontFamiliesEx EnumFontFamiliesExW -#define EnumFontFamilies EnumFontFamiliesW -#define EnumFonts EnumFontsW -#define GetCharWidth GetCharWidthW -#define GetCharWidth32 GetCharWidth32W -#define GetCharWidthFloat GetCharWidthFloatW -#define GetCharABCWidths GetCharABCWidthsW -#define GetCharABCWidthsFloat GetCharABCWidthsFloatW -#define GetGlyphOutline GetGlyphOutlineW -#define GetMetaFile GetMetaFileW -#else -#define DeviceCapabilities DeviceCapabilitiesA -#define EnumFontFamiliesEx EnumFontFamiliesExA -#define EnumFontFamilies EnumFontFamiliesA -#define EnumFonts EnumFontsA -#define GetCharWidth GetCharWidthA -#define GetCharWidth32 GetCharWidth32A -#define GetCharWidthFloat GetCharWidthFloatA -#define GetCharABCWidths GetCharABCWidthsA -#define GetCharABCWidthsFloat GetCharABCWidthsFloatA -#define GetGlyphOutline GetGlyphOutlineA -#define GetMetaFile GetMetaFileA -#endif - - WINSPOOLAPI int WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort,WORD fwCapability,LPSTR pOutput,CONST DEVMODEA *pDevMode); - WINSPOOLAPI int WINAPI DeviceCapabilitiesW(LPCWSTR pDevice,LPCWSTR pPort,WORD fwCapability,LPWSTR pOutput,CONST DEVMODEW *pDevMode); - WINGDIAPI int WINAPI DrawEscape(HDC hdc,int iEscape,int cjIn,LPCSTR lpIn); - WINGDIAPI WINBOOL WINAPI Ellipse(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI int WINAPI EnumFontFamiliesExA(HDC hdc,LPLOGFONTA lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam,DWORD dwFlags); - WINGDIAPI int WINAPI EnumFontFamiliesExW(HDC hdc,LPLOGFONTW lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam,DWORD dwFlags); - WINGDIAPI int WINAPI EnumFontFamiliesA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumFontFamiliesW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumFontsA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumFontsW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumObjects(HDC hdc,int nType,GOBJENUMPROC lpFunc,LPARAM lParam); - WINGDIAPI WINBOOL WINAPI EqualRgn(HRGN hrgn1,HRGN hrgn2); - WINGDIAPI int WINAPI Escape(HDC hdc,int iEscape,int cjIn,LPCSTR pvIn,LPVOID pvOut); - WINGDIAPI int WINAPI ExtEscape(HDC hdc,int iEscape,int cjInput,LPCSTR lpInData,int cjOutput,LPSTR lpOutData); - WINGDIAPI int WINAPI ExcludeClipRect(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI HRGN WINAPI ExtCreateRegion(CONST XFORM *lpx,DWORD nCount,CONST RGNDATA *lpData); - WINGDIAPI WINBOOL WINAPI ExtFloodFill(HDC hdc,int x,int y,COLORREF color,UINT type); - WINGDIAPI WINBOOL WINAPI FillRgn(HDC hdc,HRGN hrgn,HBRUSH hbr); - WINGDIAPI WINBOOL WINAPI FloodFill(HDC hdc,int x,int y,COLORREF color); - WINGDIAPI WINBOOL WINAPI FrameRgn(HDC hdc,HRGN hrgn,HBRUSH hbr,int w,int h); - WINGDIAPI int WINAPI GetROP2(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetAspectRatioFilterEx(HDC hdc,LPSIZE lpsize); - WINGDIAPI COLORREF WINAPI GetBkColor(HDC hdc); - WINGDIAPI COLORREF WINAPI GetDCBrushColor(HDC hdc); - WINGDIAPI COLORREF WINAPI GetDCPenColor(HDC hdc); - WINGDIAPI int WINAPI GetBkMode(HDC hdc); - WINGDIAPI LONG WINAPI GetBitmapBits(HBITMAP hbit,LONG cb,LPVOID lpvBits); - WINGDIAPI WINBOOL WINAPI GetBitmapDimensionEx(HBITMAP hbit,LPSIZE lpsize); - WINGDIAPI UINT WINAPI GetBoundsRect(HDC hdc,LPRECT lprect,UINT flags); - WINGDIAPI WINBOOL WINAPI GetBrushOrgEx(HDC hdc,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI GetCharWidthA(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidthW(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidth32A(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidth32W(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidthFloatA(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidthFloatW(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsA(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsW(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatA(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatW(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); - WINGDIAPI int WINAPI GetClipBox(HDC hdc,LPRECT lprect); - WINGDIAPI int WINAPI GetClipRgn(HDC hdc,HRGN hrgn); - WINGDIAPI int WINAPI GetMetaRgn(HDC hdc,HRGN hrgn); - WINGDIAPI HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type); - WINGDIAPI WINBOOL WINAPI GetCurrentPositionEx(HDC hdc,LPPOINT lppt); - WINGDIAPI int WINAPI GetDeviceCaps(HDC hdc,int index); - WINGDIAPI int WINAPI GetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,LPVOID lpvBits,LPBITMAPINFO lpbmi,UINT usage); - WINGDIAPI DWORD WINAPI GetFontData (HDC hdc,DWORD dwTable,DWORD dwOffset,PVOID pvBuffer,DWORD cjBuffer); - WINGDIAPI DWORD WINAPI GetGlyphOutlineA(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); - WINGDIAPI DWORD WINAPI GetGlyphOutlineW(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); - WINGDIAPI int WINAPI GetGraphicsMode(HDC hdc); - WINGDIAPI int WINAPI GetMapMode(HDC hdc); - WINGDIAPI UINT WINAPI GetMetaFileBitsEx(HMETAFILE hMF,UINT cbBuffer,LPVOID lpData); - WINGDIAPI HMETAFILE WINAPI GetMetaFileA(LPCSTR lpName); - WINGDIAPI HMETAFILE WINAPI GetMetaFileW(LPCWSTR lpName); - WINGDIAPI COLORREF WINAPI GetNearestColor(HDC hdc,COLORREF color); - WINGDIAPI UINT WINAPI GetNearestPaletteIndex(HPALETTE h,COLORREF color); - WINGDIAPI DWORD WINAPI GetObjectType(HGDIOBJ h); - -#ifndef NOTEXTMETRIC -#ifdef UNICODE -#define GetOutlineTextMetrics GetOutlineTextMetricsW -#else -#define GetOutlineTextMetrics GetOutlineTextMetricsA -#endif - - WINGDIAPI UINT WINAPI GetOutlineTextMetricsA(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICA potm); - WINGDIAPI UINT WINAPI GetOutlineTextMetricsW(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICW potm); -#endif - -#ifdef UNICODE -#define GetTextExtentPoint GetTextExtentPointW -#define GetTextExtentPoint32 GetTextExtentPoint32W -#define GetTextExtentExPoint GetTextExtentExPointW -#define GetCharacterPlacement GetCharacterPlacementW -#else -#define GetTextExtentPoint GetTextExtentPointA -#define GetTextExtentPoint32 GetTextExtentPoint32A -#define GetTextExtentExPoint GetTextExtentExPointA -#define GetCharacterPlacement GetCharacterPlacementA -#endif - - WINGDIAPI UINT WINAPI GetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); - WINGDIAPI COLORREF WINAPI GetPixel(HDC hdc,int x,int y); - WINGDIAPI int WINAPI GetPixelFormat(HDC hdc); - WINGDIAPI int WINAPI GetPolyFillMode(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetRasterizerCaps(LPRASTERIZER_STATUS lpraststat,UINT cjBytes); - WINGDIAPI int WINAPI GetRandomRgn (HDC hdc,HRGN hrgn,INT i); - WINGDIAPI DWORD WINAPI GetRegionData(HRGN hrgn,DWORD nCount,LPRGNDATA lpRgnData); - WINGDIAPI int WINAPI GetRgnBox(HRGN hrgn,LPRECT lprc); - WINGDIAPI HGDIOBJ WINAPI GetStockObject(int i); - WINGDIAPI int WINAPI GetStretchBltMode(HDC hdc); - WINGDIAPI UINT WINAPI GetSystemPaletteEntries(HDC hdc,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); - WINGDIAPI UINT WINAPI GetSystemPaletteUse(HDC hdc); - WINGDIAPI int WINAPI GetTextCharacterExtra(HDC hdc); - WINGDIAPI UINT WINAPI GetTextAlign(HDC hdc); - WINGDIAPI COLORREF WINAPI GetTextColor(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetTextExtentPointA(HDC hdc,LPCSTR lpString,int c,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI GetTextExtentPointW(HDC hdc,LPCWSTR lpString,int c,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32A(HDC hdc,LPCSTR lpString,int c,LPSIZE psizl); - WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32W(HDC hdc,LPCWSTR lpString,int c,LPSIZE psizl); - WINGDIAPI WINBOOL WINAPI GetTextExtentExPointA(HDC hdc,LPCSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); - WINGDIAPI WINBOOL WINAPI GetTextExtentExPointW(HDC hdc,LPCWSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); - WINGDIAPI int WINAPI GetTextCharset(HDC hdc); - WINGDIAPI int WINAPI GetTextCharsetInfo(HDC hdc,LPFONTSIGNATURE lpSig,DWORD dwFlags); - WINGDIAPI WINBOOL WINAPI TranslateCharsetInfo(DWORD *lpSrc,LPCHARSETINFO lpCs,DWORD dwFlags); - WINGDIAPI DWORD WINAPI GetFontLanguageInfo(HDC hdc); - WINGDIAPI DWORD WINAPI GetCharacterPlacementA(HDC hdc,LPCSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSA lpResults,DWORD dwFlags); - WINGDIAPI DWORD WINAPI GetCharacterPlacementW(HDC hdc,LPCWSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSW lpResults,DWORD dwFlags); - - typedef struct tagWCRANGE { - WCHAR wcLow; - USHORT cGlyphs; - } WCRANGE,*PWCRANGE,*LPWCRANGE; - - typedef struct tagGLYPHSET { - DWORD cbThis; - DWORD flAccel; - DWORD cGlyphsSupported; - DWORD cRanges; - WCRANGE ranges[1]; - } GLYPHSET,*PGLYPHSET,*LPGLYPHSET; - -#define GS_8BIT_INDICES 0x00000001 - -#define GGI_MARK_NONEXISTING_GLYPHS 0X0001 - -#ifdef UNICODE -#define GetGlyphIndices GetGlyphIndicesW -#else -#define GetGlyphIndices GetGlyphIndicesA -#endif - - WINGDIAPI DWORD WINAPI GetFontUnicodeRanges(HDC hdc,LPGLYPHSET lpgs); - WINGDIAPI DWORD WINAPI GetGlyphIndicesA(HDC hdc,LPCSTR lpstr,int c,LPWORD pgi,DWORD fl); - WINGDIAPI DWORD WINAPI GetGlyphIndicesW(HDC hdc,LPCWSTR lpstr,int c,LPWORD pgi,DWORD fl); - WINGDIAPI WINBOOL WINAPI GetTextExtentPointI(HDC hdc,LPWORD pgiIn,int cgi,LPSIZE psize); - WINGDIAPI WINBOOL WINAPI GetTextExtentExPointI (HDC hdc,LPWORD lpwszString,int cwchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); - WINGDIAPI WINBOOL WINAPI GetCharWidthI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPINT piWidths); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPABC pabc); - -#define STAMP_DESIGNVECTOR (0x8000000 + 'd' + ('v' << 8)) -#define STAMP_AXESLIST (0x8000000 + 'a' + ('l' << 8)) -#define MM_MAX_NUMAXES 16 - - typedef struct tagDESIGNVECTOR { - DWORD dvReserved; - DWORD dvNumAxes; - LONG dvValues[MM_MAX_NUMAXES]; - } DESIGNVECTOR,*PDESIGNVECTOR,*LPDESIGNVECTOR; - -#ifdef UNICODE -#define AddFontResourceEx AddFontResourceExW -#define RemoveFontResourceEx RemoveFontResourceExW -#else -#define AddFontResourceEx AddFontResourceExA -#define RemoveFontResourceEx RemoveFontResourceExA -#endif - - WINGDIAPI int WINAPI AddFontResourceExA(LPCSTR name,DWORD fl,PVOID res); - WINGDIAPI int WINAPI AddFontResourceExW(LPCWSTR name,DWORD fl,PVOID res); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceExA(LPCSTR name,DWORD fl,PVOID pdv); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceExW(LPCWSTR name,DWORD fl,PVOID pdv); - WINGDIAPI HANDLE WINAPI AddFontMemResourceEx(PVOID pFileView,DWORD cjSize,PVOID pvResrved,DWORD *pNumFonts); - WINGDIAPI WINBOOL WINAPI RemoveFontMemResourceEx(HANDLE h); - -#define FR_PRIVATE 0x10 -#define FR_NOT_ENUM 0x20 - -#define MM_MAX_AXES_NAMELEN 16 - - typedef struct tagAXISINFOA { - LONG axMinValue; - LONG axMaxValue; - BYTE axAxisName[MM_MAX_AXES_NAMELEN]; - } AXISINFOA,*PAXISINFOA,*LPAXISINFOA; - - typedef struct tagAXISINFOW { - LONG axMinValue; - LONG axMaxValue; - WCHAR axAxisName[MM_MAX_AXES_NAMELEN]; - } AXISINFOW,*PAXISINFOW,*LPAXISINFOW; -#ifdef UNICODE - typedef AXISINFOW AXISINFO; - typedef PAXISINFOW PAXISINFO; - typedef LPAXISINFOW LPAXISINFO; -#else - typedef AXISINFOA AXISINFO; - typedef PAXISINFOA PAXISINFO; - typedef LPAXISINFOA LPAXISINFO; -#endif - - typedef struct tagAXESLISTA { - DWORD axlReserved; - DWORD axlNumAxes; - AXISINFOA axlAxisInfo[MM_MAX_NUMAXES]; - } AXESLISTA,*PAXESLISTA,*LPAXESLISTA; - - typedef struct tagAXESLISTW { - DWORD axlReserved; - DWORD axlNumAxes; - AXISINFOW axlAxisInfo[MM_MAX_NUMAXES]; - } AXESLISTW,*PAXESLISTW,*LPAXESLISTW; -#ifdef UNICODE - typedef AXESLISTW AXESLIST; - typedef PAXESLISTW PAXESLIST; - typedef LPAXESLISTW LPAXESLIST; -#else - typedef AXESLISTA AXESLIST; - typedef PAXESLISTA PAXESLIST; - typedef LPAXESLISTA LPAXESLIST; -#endif - - typedef struct tagENUMLOGFONTEXDVA { - ENUMLOGFONTEXA elfEnumLogfontEx; - DESIGNVECTOR elfDesignVector; - } ENUMLOGFONTEXDVA,*PENUMLOGFONTEXDVA,*LPENUMLOGFONTEXDVA; - - typedef struct tagENUMLOGFONTEXDVW { - ENUMLOGFONTEXW elfEnumLogfontEx; - DESIGNVECTOR elfDesignVector; - } ENUMLOGFONTEXDVW,*PENUMLOGFONTEXDVW,*LPENUMLOGFONTEXDVW; -#ifdef UNICODE - typedef ENUMLOGFONTEXDVW ENUMLOGFONTEXDV; - typedef PENUMLOGFONTEXDVW PENUMLOGFONTEXDV; - typedef LPENUMLOGFONTEXDVW LPENUMLOGFONTEXDV; -#else - typedef ENUMLOGFONTEXDVA ENUMLOGFONTEXDV; - typedef PENUMLOGFONTEXDVA PENUMLOGFONTEXDV; - typedef LPENUMLOGFONTEXDVA LPENUMLOGFONTEXDV; -#endif - -#ifdef UNICODE -#define CreateFontIndirectEx CreateFontIndirectExW -#else -#define CreateFontIndirectEx CreateFontIndirectExA -#endif - - WINGDIAPI HFONT WINAPI CreateFontIndirectExA(CONST ENUMLOGFONTEXDVA *); - WINGDIAPI HFONT WINAPI CreateFontIndirectExW(CONST ENUMLOGFONTEXDVW *); - -#ifndef NOTEXTMETRIC - typedef struct tagENUMTEXTMETRICA { - NEWTEXTMETRICEXA etmNewTextMetricEx; - AXESLISTA etmAxesList; - } ENUMTEXTMETRICA,*PENUMTEXTMETRICA,*LPENUMTEXTMETRICA; - typedef struct tagENUMTEXTMETRICW - { - NEWTEXTMETRICEXW etmNewTextMetricEx; - AXESLISTW etmAxesList; - } ENUMTEXTMETRICW,*PENUMTEXTMETRICW,*LPENUMTEXTMETRICW; -#ifdef UNICODE - typedef ENUMTEXTMETRICW ENUMTEXTMETRIC; - typedef PENUMTEXTMETRICW PENUMTEXTMETRIC; - typedef LPENUMTEXTMETRICW LPENUMTEXTMETRIC; -#else - typedef ENUMTEXTMETRICA ENUMTEXTMETRIC; - typedef PENUMTEXTMETRICA PENUMTEXTMETRIC; - typedef LPENUMTEXTMETRICA LPENUMTEXTMETRIC; -#endif -#endif - -#ifdef UNICODE -#define ResetDC ResetDCW -#define RemoveFontResource RemoveFontResourceW -#else -#define ResetDC ResetDCA -#define RemoveFontResource RemoveFontResourceA -#endif - - WINGDIAPI WINBOOL WINAPI GetViewportExtEx(HDC hdc,LPSIZE lpsize); - WINGDIAPI WINBOOL WINAPI GetViewportOrgEx(HDC hdc,LPPOINT lppoint); - WINGDIAPI WINBOOL WINAPI GetWindowExtEx(HDC hdc,LPSIZE lpsize); - WINGDIAPI WINBOOL WINAPI GetWindowOrgEx(HDC hdc,LPPOINT lppoint); - WINGDIAPI int WINAPI IntersectClipRect(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI WINBOOL WINAPI InvertRgn(HDC hdc,HRGN hrgn); - WINGDIAPI WINBOOL WINAPI LineDDA(int xStart,int yStart,int xEnd,int yEnd,LINEDDAPROC lpProc,LPARAM data); - WINGDIAPI WINBOOL WINAPI LineTo(HDC hdc,int x,int y); - WINGDIAPI WINBOOL WINAPI MaskBlt(HDC hdcDest,int xDest,int yDest,int width,int height,HDC hdcSrc,int xSrc,int ySrc,HBITMAP hbmMask,int xMask,int yMask,DWORD rop); - WINGDIAPI WINBOOL WINAPI PlgBlt(HDC hdcDest,CONST POINT *lpPoint,HDC hdcSrc,int xSrc,int ySrc,int width,int height,HBITMAP hbmMask,int xMask,int yMask); - WINGDIAPI int WINAPI OffsetClipRgn(HDC hdc,int x,int y); - WINGDIAPI int WINAPI OffsetRgn(HRGN hrgn,int x,int y); - WINGDIAPI WINBOOL WINAPI PatBlt(HDC hdc,int x,int y,int w,int h,DWORD rop); - WINGDIAPI WINBOOL WINAPI Pie(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); - WINGDIAPI WINBOOL WINAPI PlayMetaFile(HDC hdc,HMETAFILE hmf); - WINGDIAPI WINBOOL WINAPI PaintRgn(HDC hdc,HRGN hrgn); - WINGDIAPI WINBOOL WINAPI PolyPolygon(HDC hdc,CONST POINT *apt,CONST INT *asz,int csz); - WINGDIAPI WINBOOL WINAPI PtInRegion(HRGN hrgn,int x,int y); - WINGDIAPI WINBOOL WINAPI PtVisible(HDC hdc,int x,int y); - WINGDIAPI WINBOOL WINAPI RectInRegion(HRGN hrgn,CONST RECT *lprect); - WINGDIAPI WINBOOL WINAPI RectVisible(HDC hdc,CONST RECT *lprect); - WINGDIAPI WINBOOL WINAPI Rectangle(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI WINBOOL WINAPI RestoreDC(HDC hdc,int nSavedDC); - WINGDIAPI HDC WINAPI ResetDCA(HDC hdc,CONST DEVMODEA *lpdm); - WINGDIAPI HDC WINAPI ResetDCW(HDC hdc,CONST DEVMODEW *lpdm); - WINGDIAPI UINT WINAPI RealizePalette(HDC hdc); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceA(LPCSTR lpFileName); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceW(LPCWSTR lpFileName); - WINGDIAPI WINBOOL WINAPI RoundRect(HDC hdc,int left,int top,int right,int bottom,int width,int height); - WINGDIAPI WINBOOL WINAPI ResizePalette(HPALETTE hpal,UINT n); - WINGDIAPI int WINAPI SaveDC(HDC hdc); - WINGDIAPI int WINAPI SelectClipRgn(HDC hdc,HRGN hrgn); - WINGDIAPI int WINAPI ExtSelectClipRgn(HDC hdc,HRGN hrgn,int mode); - WINGDIAPI int WINAPI SetMetaRgn(HDC hdc); - WINGDIAPI HGDIOBJ WINAPI SelectObject(HDC hdc,HGDIOBJ h); - WINGDIAPI HPALETTE WINAPI SelectPalette(HDC hdc,HPALETTE hPal,WINBOOL bForceBkgd); - WINGDIAPI COLORREF WINAPI SetBkColor(HDC hdc,COLORREF color); - WINGDIAPI COLORREF WINAPI SetDCBrushColor(HDC hdc,COLORREF color); - WINGDIAPI COLORREF WINAPI SetDCPenColor(HDC hdc,COLORREF color); - WINGDIAPI int WINAPI SetBkMode(HDC hdc,int mode); - WINGDIAPI LONG WINAPI SetBitmapBits(HBITMAP hbm,DWORD cb,CONST VOID *pvBits); - WINGDIAPI UINT WINAPI SetBoundsRect(HDC hdc,CONST RECT *lprect,UINT flags); - WINGDIAPI int WINAPI SetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); - WINGDIAPI int WINAPI SetDIBitsToDevice(HDC hdc,int xDest,int yDest,DWORD w,DWORD h,int xSrc,int ySrc,UINT StartScan,UINT cLines,CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); - WINGDIAPI DWORD WINAPI SetMapperFlags(HDC hdc,DWORD flags); - WINGDIAPI int WINAPI SetGraphicsMode(HDC hdc,int iMode); - WINGDIAPI int WINAPI SetMapMode(HDC hdc,int iMode); - WINGDIAPI DWORD WINAPI SetLayout(HDC hdc,DWORD l); - WINGDIAPI DWORD WINAPI GetLayout(HDC hdc); - WINGDIAPI HMETAFILE WINAPI SetMetaFileBitsEx(UINT cbBuffer,CONST BYTE *lpData); - WINGDIAPI UINT WINAPI SetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,CONST PALETTEENTRY *pPalEntries); - WINGDIAPI COLORREF WINAPI SetPixel(HDC hdc,int x,int y,COLORREF color); - WINGDIAPI WINBOOL WINAPI SetPixelV(HDC hdc,int x,int y,COLORREF color); - WINGDIAPI WINBOOL WINAPI SetPixelFormat(HDC hdc,int format,CONST PIXELFORMATDESCRIPTOR *ppfd); - WINGDIAPI int WINAPI SetPolyFillMode(HDC hdc,int mode); - WINGDIAPI WINBOOL WINAPI StretchBlt(HDC hdcDest,int xDest,int yDest,int wDest,int hDest,HDC hdcSrc,int xSrc,int ySrc,int wSrc,int hSrc,DWORD rop); - WINGDIAPI WINBOOL WINAPI SetRectRgn(HRGN hrgn,int left,int top,int right,int bottom); - WINGDIAPI int WINAPI StretchDIBits(HDC hdc,int xDest,int yDest,int DestWidth,int DestHeight,int xSrc,int ySrc,int SrcWidth,int SrcHeight,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT iUsage,DWORD rop); - WINGDIAPI int WINAPI SetROP2(HDC hdc,int rop2); - WINGDIAPI int WINAPI SetStretchBltMode(HDC hdc,int mode); - WINGDIAPI UINT WINAPI SetSystemPaletteUse(HDC hdc,UINT use); - WINGDIAPI int WINAPI SetTextCharacterExtra(HDC hdc,int extra); - WINGDIAPI COLORREF WINAPI SetTextColor(HDC hdc,COLORREF color); - WINGDIAPI UINT WINAPI SetTextAlign(HDC hdc,UINT align); - WINGDIAPI WINBOOL WINAPI SetTextJustification(HDC hdc,int extra,int count); - WINGDIAPI WINBOOL WINAPI UpdateColors(HDC hdc); - - typedef USHORT COLOR16; - - typedef struct _TRIVERTEX { - LONG x; - LONG y; - COLOR16 Red; - COLOR16 Green; - COLOR16 Blue; - COLOR16 Alpha; - } TRIVERTEX,*PTRIVERTEX,*LPTRIVERTEX; - - typedef struct _GRADIENT_TRIANGLE { - ULONG Vertex1; - ULONG Vertex2; - ULONG Vertex3; - } GRADIENT_TRIANGLE,*PGRADIENT_TRIANGLE,*LPGRADIENT_TRIANGLE; - - typedef struct _GRADIENT_RECT { - ULONG UpperLeft; - ULONG LowerRight; - } GRADIENT_RECT,*PGRADIENT_RECT,*LPGRADIENT_RECT; - - typedef struct _BLENDFUNCTION { - BYTE BlendOp; - BYTE BlendFlags; - BYTE SourceConstantAlpha; - BYTE AlphaFormat; - } BLENDFUNCTION,*PBLENDFUNCTION; - -#define AC_SRC_OVER 0x00 -#define AC_SRC_ALPHA 0x01 - - WINGDIAPI WINBOOL WINAPI AlphaBlend(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,BLENDFUNCTION ftn); - WINGDIAPI WINBOOL WINAPI TransparentBlt(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,UINT crTransparent); - -#define GRADIENT_FILL_RECT_H 0x00000000 -#define GRADIENT_FILL_RECT_V 0x00000001 -#define GRADIENT_FILL_TRIANGLE 0x00000002 -#define GRADIENT_FILL_OP_FLAG 0x000000ff - - WINGDIAPI WINBOOL WINAPI GradientFill(HDC hdc,PTRIVERTEX pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,ULONG ulMode); - -#ifndef NOMETAFILE - -#ifdef UNICODE -#define CopyEnhMetaFile CopyEnhMetaFileW -#define CreateEnhMetaFile CreateEnhMetaFileW -#define GetEnhMetaFile GetEnhMetaFileW -#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionW -#else -#define CopyEnhMetaFile CopyEnhMetaFileA -#define CreateEnhMetaFile CreateEnhMetaFileA -#define GetEnhMetaFile GetEnhMetaFileA -#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionA -#endif - - WINGDIAPI WINBOOL WINAPI PlayMetaFileRecord(HDC hdc,LPHANDLETABLE lpHandleTable,LPMETARECORD lpMR,UINT noObjs); - - typedef int (CALLBACK *MFENUMPROC)(HDC hdc,HANDLETABLE *lpht,METARECORD *lpMR,int nObj,LPARAM param); - - WINGDIAPI WINBOOL WINAPI EnumMetaFile(HDC hdc,HMETAFILE hmf,MFENUMPROC proc,LPARAM param); - - typedef int (CALLBACK *ENHMFENUMPROC)(HDC hdc,HANDLETABLE *lpht,CONST ENHMETARECORD *lpmr,int hHandles,LPARAM data); - - WINGDIAPI HENHMETAFILE WINAPI CloseEnhMetaFile(HDC hdc); - WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileA(HENHMETAFILE hEnh,LPCSTR lpFileName); - WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileW(HENHMETAFILE hEnh,LPCWSTR lpFileName); - WINGDIAPI HDC WINAPI CreateEnhMetaFileA(HDC hdc,LPCSTR lpFilename,CONST RECT *lprc,LPCSTR lpDesc); - WINGDIAPI HDC WINAPI CreateEnhMetaFileW(HDC hdc,LPCWSTR lpFilename,CONST RECT *lprc,LPCWSTR lpDesc); - WINGDIAPI WINBOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf); - WINGDIAPI WINBOOL WINAPI EnumEnhMetaFile(HDC hdc,HENHMETAFILE hmf,ENHMFENUMPROC proc,LPVOID param,CONST RECT *lpRect); - WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileA(LPCSTR lpName); - WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileW(LPCWSTR lpName); - WINGDIAPI UINT WINAPI GetEnhMetaFileBits(HENHMETAFILE hEMF,UINT nSize,LPBYTE lpData); - WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionA(HENHMETAFILE hemf,UINT cchBuffer,LPSTR lpDescription); - WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionW(HENHMETAFILE hemf,UINT cchBuffer,LPWSTR lpDescription); - WINGDIAPI UINT WINAPI GetEnhMetaFileHeader(HENHMETAFILE hemf,UINT nSize,LPENHMETAHEADER lpEnhMetaHeader); - WINGDIAPI UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf,UINT nNumEntries,LPPALETTEENTRY lpPaletteEntries); - WINGDIAPI UINT WINAPI GetEnhMetaFilePixelFormat(HENHMETAFILE hemf,UINT cbBuffer,PIXELFORMATDESCRIPTOR *ppfd); - WINGDIAPI UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,UINT cbData16,LPBYTE pData16,INT iMapMode,HDC hdcRef); - WINGDIAPI WINBOOL WINAPI PlayEnhMetaFile(HDC hdc,HENHMETAFILE hmf,CONST RECT *lprect); - WINGDIAPI WINBOOL WINAPI PlayEnhMetaFileRecord(HDC hdc,LPHANDLETABLE pht,CONST ENHMETARECORD *pmr,UINT cht); - WINGDIAPI HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT nSize,CONST BYTE *pb); - WINGDIAPI HENHMETAFILE WINAPI SetWinMetaFileBits(UINT nSize,CONST BYTE *lpMeta16Data,HDC hdcRef,CONST METAFILEPICT *lpMFP); - WINGDIAPI WINBOOL WINAPI GdiComment(HDC hdc,UINT nSize,CONST BYTE *lpData); -#endif - -#ifndef NOTEXTMETRIC -#ifdef UNICODE -#define GetTextMetrics GetTextMetricsW -#else -#define GetTextMetrics GetTextMetricsA -#endif - - WINGDIAPI WINBOOL WINAPI GetTextMetricsA(HDC hdc,LPTEXTMETRICA lptm); - WINGDIAPI WINBOOL WINAPI GetTextMetricsW(HDC hdc,LPTEXTMETRICW lptm); -#endif - - typedef struct tagDIBSECTION { - BITMAP dsBm; - BITMAPINFOHEADER dsBmih; - DWORD dsBitfields[3]; - HANDLE dshSection; - DWORD dsOffset; - } DIBSECTION,*LPDIBSECTION,*PDIBSECTION; - - WINGDIAPI WINBOOL WINAPI AngleArc(HDC hdc,int x,int y,DWORD r,FLOAT StartAngle,FLOAT SweepAngle); - WINGDIAPI WINBOOL WINAPI PolyPolyline(HDC hdc,CONST POINT *apt,CONST DWORD *asz,DWORD csz); - WINGDIAPI WINBOOL WINAPI GetWorldTransform(HDC hdc,LPXFORM lpxf); - WINGDIAPI WINBOOL WINAPI SetWorldTransform(HDC hdc,CONST XFORM *lpxf); - WINGDIAPI WINBOOL WINAPI ModifyWorldTransform(HDC hdc,CONST XFORM *lpxf,DWORD mode); - WINGDIAPI WINBOOL WINAPI CombineTransform(LPXFORM lpxfOut,CONST XFORM *lpxf1,CONST XFORM *lpxf2); - WINGDIAPI HBITMAP WINAPI CreateDIBSection(HDC hdc,CONST BITMAPINFO *lpbmi,UINT usage,VOID **ppvBits,HANDLE hSection,DWORD offset); - WINGDIAPI UINT WINAPI GetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,RGBQUAD *prgbq); - WINGDIAPI UINT WINAPI SetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,CONST RGBQUAD *prgbq); - -#define CA_NEGATIVE 0x0001 -#define CA_LOG_FILTER 0x0002 - -#define ILLUMINANT_DEVICE_DEFAULT 0 -#define ILLUMINANT_A 1 -#define ILLUMINANT_B 2 -#define ILLUMINANT_C 3 -#define ILLUMINANT_D50 4 -#define ILLUMINANT_D55 5 -#define ILLUMINANT_D65 6 -#define ILLUMINANT_D75 7 -#define ILLUMINANT_F2 8 -#define ILLUMINANT_MAX_INDEX ILLUMINANT_F2 - -#define ILLUMINANT_TUNGSTEN ILLUMINANT_A -#define ILLUMINANT_DAYLIGHT ILLUMINANT_C -#define ILLUMINANT_FLUORESCENT ILLUMINANT_F2 -#define ILLUMINANT_NTSC ILLUMINANT_C - -#define RGB_GAMMA_MIN (WORD)02500 -#define RGB_GAMMA_MAX (WORD)65000 - -#define REFERENCE_WHITE_MIN (WORD)6000 -#define REFERENCE_WHITE_MAX (WORD)10000 -#define REFERENCE_BLACK_MIN (WORD)0 -#define REFERENCE_BLACK_MAX (WORD)4000 - -#define COLOR_ADJ_MIN (SHORT)-100 -#define COLOR_ADJ_MAX (SHORT)100 - - typedef struct tagCOLORADJUSTMENT { - WORD caSize; - WORD caFlags; - WORD caIlluminantIndex; - WORD caRedGamma; - WORD caGreenGamma; - WORD caBlueGamma; - WORD caReferenceBlack; - WORD caReferenceWhite; - SHORT caContrast; - SHORT caBrightness; - SHORT caColorfulness; - SHORT caRedGreenTint; - } COLORADJUSTMENT,*PCOLORADJUSTMENT,*LPCOLORADJUSTMENT; - - WINGDIAPI WINBOOL WINAPI SetColorAdjustment(HDC hdc,CONST COLORADJUSTMENT *lpca); - WINGDIAPI WINBOOL WINAPI GetColorAdjustment(HDC hdc,LPCOLORADJUSTMENT lpca); - WINGDIAPI HPALETTE WINAPI CreateHalftonePalette(HDC hdc); - - typedef WINBOOL (CALLBACK *ABORTPROC)(HDC,int); - - typedef struct _DOCINFOA { - int cbSize; - LPCSTR lpszDocName; - LPCSTR lpszOutput; - LPCSTR lpszDatatype; - DWORD fwType; - } DOCINFOA,*LPDOCINFOA; - - typedef struct _DOCINFOW { - int cbSize; - LPCWSTR lpszDocName; - LPCWSTR lpszOutput; - LPCWSTR lpszDatatype; - DWORD fwType; - } DOCINFOW,*LPDOCINFOW; - -#ifdef UNICODE - typedef DOCINFOW DOCINFO; - typedef LPDOCINFOW LPDOCINFO; -#else - typedef DOCINFOA DOCINFO; - typedef LPDOCINFOA LPDOCINFO; -#endif - -#define DI_APPBANDING 0x00000001 -#define DI_ROPS_READ_DESTINATION 0x00000002 - -#ifdef UNICODE -#define StartDoc StartDocW -#define GetObject GetObjectW -#define TextOut TextOutW -#define ExtTextOut ExtTextOutW -#define PolyTextOut PolyTextOutW -#define GetTextFace GetTextFaceW -#else -#define StartDoc StartDocA -#define GetObject GetObjectA -#define TextOut TextOutA -#define ExtTextOut ExtTextOutA -#define PolyTextOut PolyTextOutA -#define GetTextFace GetTextFaceA -#endif - - WINGDIAPI int WINAPI StartDocA(HDC hdc,CONST DOCINFOA *lpdi); - WINGDIAPI int WINAPI StartDocW(HDC hdc,CONST DOCINFOW *lpdi); - WINGDIAPI int WINAPI EndDoc(HDC hdc); - WINGDIAPI int WINAPI StartPage(HDC hdc); - WINGDIAPI int WINAPI EndPage(HDC hdc); - WINGDIAPI int WINAPI AbortDoc(HDC hdc); - WINGDIAPI int WINAPI SetAbortProc(HDC hdc,ABORTPROC proc); - WINGDIAPI WINBOOL WINAPI AbortPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI ArcTo(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); - WINGDIAPI WINBOOL WINAPI BeginPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI CloseFigure(HDC hdc); - WINGDIAPI WINBOOL WINAPI EndPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI FillPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI FlattenPath(HDC hdc); - WINGDIAPI int WINAPI GetPath(HDC hdc,LPPOINT apt,LPBYTE aj,int cpt); - WINGDIAPI HRGN WINAPI PathToRegion(HDC hdc); - WINGDIAPI WINBOOL WINAPI PolyDraw(HDC hdc,CONST POINT *apt,CONST BYTE *aj,int cpt); - WINGDIAPI WINBOOL WINAPI SelectClipPath(HDC hdc,int mode); - WINGDIAPI int WINAPI SetArcDirection(HDC hdc,int dir); - WINGDIAPI WINBOOL WINAPI SetMiterLimit(HDC hdc,FLOAT limit,PFLOAT old); - WINGDIAPI WINBOOL WINAPI StrokeAndFillPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI StrokePath(HDC hdc); - WINGDIAPI WINBOOL WINAPI WidenPath(HDC hdc); - WINGDIAPI HPEN WINAPI ExtCreatePen(DWORD iPenStyle,DWORD cWidth,CONST LOGBRUSH *plbrush,DWORD cStyle,CONST DWORD *pstyle); - WINGDIAPI WINBOOL WINAPI GetMiterLimit(HDC hdc,PFLOAT plimit); - WINGDIAPI int WINAPI GetArcDirection(HDC hdc); - WINGDIAPI int WINAPI GetObjectA(HANDLE h,int c,LPVOID pv); - WINGDIAPI int WINAPI GetObjectW(HANDLE h,int c,LPVOID pv); - WINGDIAPI WINBOOL WINAPI MoveToEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI TextOutA(HDC hdc,int x,int y,LPCSTR lpString,int c); - WINGDIAPI WINBOOL WINAPI TextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int c); - WINGDIAPI WINBOOL WINAPI ExtTextOutA(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCSTR lpString,UINT c,CONST INT *lpDx); - WINGDIAPI WINBOOL WINAPI ExtTextOutW(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCWSTR lpString,UINT c,CONST INT *lpDx); - WINGDIAPI WINBOOL WINAPI PolyTextOutA(HDC hdc,CONST POLYTEXTA *ppt,int nstrings); - WINGDIAPI WINBOOL WINAPI PolyTextOutW(HDC hdc,CONST POLYTEXTW *ppt,int nstrings); - WINGDIAPI HRGN WINAPI CreatePolygonRgn(CONST POINT *pptl,int cPoint,int iMode); - WINGDIAPI WINBOOL WINAPI DPtoLP(HDC hdc,LPPOINT lppt,int c); - WINGDIAPI WINBOOL WINAPI LPtoDP(HDC hdc,LPPOINT lppt,int c); - WINGDIAPI WINBOOL WINAPI Polygon(HDC hdc,CONST POINT *apt,int cpt); - WINGDIAPI WINBOOL WINAPI Polyline(HDC hdc,CONST POINT *apt,int cpt); - WINGDIAPI WINBOOL WINAPI PolyBezier(HDC hdc,CONST POINT *apt,DWORD cpt); - WINGDIAPI WINBOOL WINAPI PolyBezierTo(HDC hdc,CONST POINT *apt,DWORD cpt); - WINGDIAPI WINBOOL WINAPI PolylineTo(HDC hdc,CONST POINT *apt,DWORD cpt); - WINGDIAPI WINBOOL WINAPI SetViewportExtEx(HDC hdc,int x,int y,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI SetWindowExtEx(HDC hdc,int x,int y,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI OffsetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI OffsetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI ScaleViewportExtEx(HDC hdc,int xn,int dx,int yn,int yd,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI ScaleWindowExtEx(HDC hdc,int xn,int xd,int yn,int yd,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetBitmapDimensionEx(HBITMAP hbm,int w,int h,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetBrushOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI int WINAPI GetTextFaceA(HDC hdc,int c,LPSTR lpName); - WINGDIAPI int WINAPI GetTextFaceW(HDC hdc,int c,LPWSTR lpName); - -#define FONTMAPPER_MAX 10 - - typedef struct tagKERNINGPAIR { - WORD wFirst; - WORD wSecond; - int iKernAmount; - } KERNINGPAIR,*LPKERNINGPAIR; - -#ifdef UNICODE -#define GetKerningPairs GetKerningPairsW -#else -#define GetKerningPairs GetKerningPairsA -#endif - - WINGDIAPI DWORD WINAPI GetKerningPairsA(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); - WINGDIAPI DWORD WINAPI GetKerningPairsW(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); - WINGDIAPI WINBOOL WINAPI GetDCOrgEx(HDC hdc,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI FixBrushOrgEx(HDC hdc,int x,int y,LPPOINT ptl); - WINGDIAPI WINBOOL WINAPI UnrealizeObject(HGDIOBJ h); - WINGDIAPI WINBOOL WINAPI GdiFlush(); - WINGDIAPI DWORD WINAPI GdiSetBatchLimit(DWORD dw); - WINGDIAPI DWORD WINAPI GdiGetBatchLimit(); - -#define ICM_OFF 1 -#define ICM_ON 2 -#define ICM_QUERY 3 -#define ICM_DONE_OUTSIDEDC 4 - - typedef int (CALLBACK *ICMENUMPROCA)(LPSTR,LPARAM); - typedef int (CALLBACK *ICMENUMPROCW)(LPWSTR,LPARAM); - -#ifdef UNICODE -#define ICMENUMPROC ICMENUMPROCW -#define EnumICMProfiles EnumICMProfilesW -#define UpdateICMRegKey UpdateICMRegKeyW -#define GetLogColorSpace GetLogColorSpaceW -#define CreateColorSpace CreateColorSpaceW -#define GetICMProfile GetICMProfileW -#define SetICMProfile SetICMProfileW -#else -#define ICMENUMPROC ICMENUMPROCA -#define EnumICMProfiles EnumICMProfilesA -#define UpdateICMRegKey UpdateICMRegKeyA -#define GetLogColorSpace GetLogColorSpaceA -#define CreateColorSpace CreateColorSpaceA -#define GetICMProfile GetICMProfileA -#define SetICMProfile SetICMProfileA -#endif - - WINGDIAPI int WINAPI SetICMMode(HDC hdc,int mode); - WINGDIAPI WINBOOL WINAPI CheckColorsInGamut(HDC hdc,LPVOID lpRGBTriple,LPVOID dlpBuffer,DWORD nCount); - WINGDIAPI HCOLORSPACE WINAPI GetColorSpace(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetLogColorSpaceA(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEA lpBuffer,DWORD nSize); - WINGDIAPI WINBOOL WINAPI GetLogColorSpaceW(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEW lpBuffer,DWORD nSize); - WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceA(LPLOGCOLORSPACEA lplcs); - WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceW(LPLOGCOLORSPACEW lplcs); - WINGDIAPI HCOLORSPACE WINAPI SetColorSpace(HDC hdc,HCOLORSPACE hcs); - WINGDIAPI WINBOOL WINAPI DeleteColorSpace(HCOLORSPACE hcs); - WINGDIAPI WINBOOL WINAPI GetICMProfileA(HDC hdc,LPDWORD pBufSize,LPSTR pszFilename); - WINGDIAPI WINBOOL WINAPI GetICMProfileW(HDC hdc,LPDWORD pBufSize,LPWSTR pszFilename); - WINGDIAPI WINBOOL WINAPI SetICMProfileA(HDC hdc,LPSTR lpFileName); - WINGDIAPI WINBOOL WINAPI SetICMProfileW(HDC hdc,LPWSTR lpFileName); - WINGDIAPI WINBOOL WINAPI GetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); - WINGDIAPI WINBOOL WINAPI SetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); - WINGDIAPI WINBOOL WINAPI ColorMatchToTarget(HDC hdc,HDC hdcTarget,DWORD action); - WINGDIAPI int WINAPI EnumICMProfilesA(HDC hdc,ICMENUMPROCA proc,LPARAM param); - WINGDIAPI int WINAPI EnumICMProfilesW(HDC hdc,ICMENUMPROCW proc,LPARAM param); - WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyA(DWORD reserved,LPSTR lpszCMID,LPSTR lpszFileName,UINT command); - WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyW(DWORD reserved,LPWSTR lpszCMID,LPWSTR lpszFileName,UINT command); - WINGDIAPI WINBOOL WINAPI ColorCorrectPalette(HDC hdc,HPALETTE hPal,DWORD deFirst,DWORD num); - -#ifndef NOMETAFILE - -#define ENHMETA_SIGNATURE 0x464D4520 -#define ENHMETA_STOCK_OBJECT 0x80000000 - -#define EMR_HEADER 1 -#define EMR_POLYBEZIER 2 -#define EMR_POLYGON 3 -#define EMR_POLYLINE 4 -#define EMR_POLYBEZIERTO 5 -#define EMR_POLYLINETO 6 -#define EMR_POLYPOLYLINE 7 -#define EMR_POLYPOLYGON 8 -#define EMR_SETWINDOWEXTEX 9 -#define EMR_SETWINDOWORGEX 10 -#define EMR_SETVIEWPORTEXTEX 11 -#define EMR_SETVIEWPORTORGEX 12 -#define EMR_SETBRUSHORGEX 13 -#define EMR_EOF 14 -#define EMR_SETPIXELV 15 -#define EMR_SETMAPPERFLAGS 16 -#define EMR_SETMAPMODE 17 -#define EMR_SETBKMODE 18 -#define EMR_SETPOLYFILLMODE 19 -#define EMR_SETROP2 20 -#define EMR_SETSTRETCHBLTMODE 21 -#define EMR_SETTEXTALIGN 22 -#define EMR_SETCOLORADJUSTMENT 23 -#define EMR_SETTEXTCOLOR 24 -#define EMR_SETBKCOLOR 25 -#define EMR_OFFSETCLIPRGN 26 -#define EMR_MOVETOEX 27 -#define EMR_SETMETARGN 28 -#define EMR_EXCLUDECLIPRECT 29 -#define EMR_INTERSECTCLIPRECT 30 -#define EMR_SCALEVIEWPORTEXTEX 31 -#define EMR_SCALEWINDOWEXTEX 32 -#define EMR_SAVEDC 33 -#define EMR_RESTOREDC 34 -#define EMR_SETWORLDTRANSFORM 35 -#define EMR_MODIFYWORLDTRANSFORM 36 -#define EMR_SELECTOBJECT 37 -#define EMR_CREATEPEN 38 -#define EMR_CREATEBRUSHINDIRECT 39 -#define EMR_DELETEOBJECT 40 -#define EMR_ANGLEARC 41 -#define EMR_ELLIPSE 42 -#define EMR_RECTANGLE 43 -#define EMR_ROUNDRECT 44 -#define EMR_ARC 45 -#define EMR_CHORD 46 -#define EMR_PIE 47 -#define EMR_SELECTPALETTE 48 -#define EMR_CREATEPALETTE 49 -#define EMR_SETPALETTEENTRIES 50 -#define EMR_RESIZEPALETTE 51 -#define EMR_REALIZEPALETTE 52 -#define EMR_EXTFLOODFILL 53 -#define EMR_LINETO 54 -#define EMR_ARCTO 55 -#define EMR_POLYDRAW 56 -#define EMR_SETARCDIRECTION 57 -#define EMR_SETMITERLIMIT 58 -#define EMR_BEGINPATH 59 -#define EMR_ENDPATH 60 -#define EMR_CLOSEFIGURE 61 -#define EMR_FILLPATH 62 -#define EMR_STROKEANDFILLPATH 63 -#define EMR_STROKEPATH 64 -#define EMR_FLATTENPATH 65 -#define EMR_WIDENPATH 66 -#define EMR_SELECTCLIPPATH 67 -#define EMR_ABORTPATH 68 - -#define EMR_GDICOMMENT 70 -#define EMR_FILLRGN 71 -#define EMR_FRAMERGN 72 -#define EMR_INVERTRGN 73 -#define EMR_PAINTRGN 74 -#define EMR_EXTSELECTCLIPRGN 75 -#define EMR_BITBLT 76 -#define EMR_STRETCHBLT 77 -#define EMR_MASKBLT 78 -#define EMR_PLGBLT 79 -#define EMR_SETDIBITSTODEVICE 80 -#define EMR_STRETCHDIBITS 81 -#define EMR_EXTCREATEFONTINDIRECTW 82 -#define EMR_EXTTEXTOUTA 83 -#define EMR_EXTTEXTOUTW 84 -#define EMR_POLYBEZIER16 85 -#define EMR_POLYGON16 86 -#define EMR_POLYLINE16 87 -#define EMR_POLYBEZIERTO16 88 -#define EMR_POLYLINETO16 89 -#define EMR_POLYPOLYLINE16 90 -#define EMR_POLYPOLYGON16 91 -#define EMR_POLYDRAW16 92 -#define EMR_CREATEMONOBRUSH 93 -#define EMR_CREATEDIBPATTERNBRUSHPT 94 -#define EMR_EXTCREATEPEN 95 -#define EMR_POLYTEXTOUTA 96 -#define EMR_POLYTEXTOUTW 97 - -#define EMR_SETICMMODE 98 -#define EMR_CREATECOLORSPACE 99 -#define EMR_SETCOLORSPACE 100 -#define EMR_DELETECOLORSPACE 101 -#define EMR_GLSRECORD 102 -#define EMR_GLSBOUNDEDRECORD 103 -#define EMR_PIXELFORMAT 104 -#define EMR_RESERVED_105 105 -#define EMR_RESERVED_106 106 -#define EMR_RESERVED_107 107 -#define EMR_RESERVED_108 108 -#define EMR_RESERVED_109 109 -#define EMR_RESERVED_110 110 -#define EMR_COLORCORRECTPALETTE 111 -#define EMR_SETICMPROFILEA 112 -#define EMR_SETICMPROFILEW 113 -#define EMR_ALPHABLEND 114 -#define EMR_SETLAYOUT 115 -#define EMR_TRANSPARENTBLT 116 -#define EMR_RESERVED_117 117 -#define EMR_GRADIENTFILL 118 -#define EMR_RESERVED_119 119 -#define EMR_RESERVED_120 120 -#define EMR_COLORMATCHTOTARGETW 121 -#define EMR_CREATECOLORSPACEW 122 - -#define EMR_MIN 1 - -#define EMR_MAX 122 - - typedef struct tagEMR { - DWORD iType; - DWORD nSize; - } EMR,*PEMR; - - typedef struct tagEMRTEXT { - POINTL ptlReference; - DWORD nChars; - DWORD offString; - DWORD fOptions; - RECTL rcl; - DWORD offDx; - } EMRTEXT,*PEMRTEXT; - - typedef struct tagABORTPATH { - EMR emr; - } EMRABORTPATH,*PEMRABORTPATH,EMRBEGINPATH,*PEMRBEGINPATH,EMRENDPATH,*PEMRENDPATH,EMRCLOSEFIGURE,*PEMRCLOSEFIGURE,EMRFLATTENPATH,*PEMRFLATTENPATH,EMRWIDENPATH,*PEMRWIDENPATH,EMRSETMETARGN,*PEMRSETMETARGN,EMRSAVEDC,*PEMRSAVEDC,EMRREALIZEPALETTE,*PEMRREALIZEPALETTE; - - typedef struct tagEMRSELECTCLIPPATH { - EMR emr; - DWORD iMode; - } EMRSELECTCLIPPATH,*PEMRSELECTCLIPPATH,EMRSETBKMODE,*PEMRSETBKMODE,EMRSETMAPMODE,*PEMRSETMAPMODE,EMRSETLAYOUT,*PEMRSETLAYOUT, - EMRSETPOLYFILLMODE,*PEMRSETPOLYFILLMODE,EMRSETROP2,*PEMRSETROP2,EMRSETSTRETCHBLTMODE,*PEMRSETSTRETCHBLTMODE,EMRSETICMMODE, - *PEMRSETICMMODE,EMRSETTEXTALIGN,*PEMRSETTEXTALIGN; - - typedef struct tagEMRSETMITERLIMIT { - EMR emr; - FLOAT eMiterLimit; - } EMRSETMITERLIMIT,*PEMRSETMITERLIMIT; - - typedef struct tagEMRRESTOREDC { - EMR emr; - LONG iRelative; - } EMRRESTOREDC,*PEMRRESTOREDC; - - typedef struct tagEMRSETARCDIRECTION { - EMR emr; - DWORD iArcDirection; - - } EMRSETARCDIRECTION,*PEMRSETARCDIRECTION; - - typedef struct tagEMRSETMAPPERFLAGS { - EMR emr; - DWORD dwFlags; - } EMRSETMAPPERFLAGS,*PEMRSETMAPPERFLAGS; - - typedef struct tagEMRSETTEXTCOLOR { - EMR emr; - COLORREF crColor; - } EMRSETBKCOLOR,*PEMRSETBKCOLOR,EMRSETTEXTCOLOR,*PEMRSETTEXTCOLOR; - - typedef struct tagEMRSELECTOBJECT { - EMR emr; - DWORD ihObject; - } EMRSELECTOBJECT,*PEMRSELECTOBJECT,EMRDELETEOBJECT,*PEMRDELETEOBJECT; - - typedef struct tagEMRSELECTPALETTE { - EMR emr; - DWORD ihPal; - } EMRSELECTPALETTE,*PEMRSELECTPALETTE; - - typedef struct tagEMRRESIZEPALETTE { - EMR emr; - DWORD ihPal; - DWORD cEntries; - } EMRRESIZEPALETTE,*PEMRRESIZEPALETTE; - - typedef struct tagEMRSETPALETTEENTRIES { - EMR emr; - DWORD ihPal; - DWORD iStart; - DWORD cEntries; - PALETTEENTRY aPalEntries[1]; - } EMRSETPALETTEENTRIES,*PEMRSETPALETTEENTRIES; - - typedef struct tagEMRSETCOLORADJUSTMENT { - EMR emr; - COLORADJUSTMENT ColorAdjustment; - } EMRSETCOLORADJUSTMENT,*PEMRSETCOLORADJUSTMENT; - - typedef struct tagEMRGDICOMMENT { - EMR emr; - DWORD cbData; - BYTE Data[1]; - } EMRGDICOMMENT,*PEMRGDICOMMENT; - - typedef struct tagEMREOF { - EMR emr; - DWORD nPalEntries; - DWORD offPalEntries; - DWORD nSizeLast; - } EMREOF,*PEMREOF; - - typedef struct tagEMRLINETO { - EMR emr; - POINTL ptl; - } EMRLINETO,*PEMRLINETO,EMRMOVETOEX,*PEMRMOVETOEX; - - typedef struct tagEMROFFSETCLIPRGN { - EMR emr; - POINTL ptlOffset; - } EMROFFSETCLIPRGN,*PEMROFFSETCLIPRGN; - - typedef struct tagEMRFILLPATH { - EMR emr; - RECTL rclBounds; - } EMRFILLPATH,*PEMRFILLPATH,EMRSTROKEANDFILLPATH,*PEMRSTROKEANDFILLPATH,EMRSTROKEPATH,*PEMRSTROKEPATH; - - typedef struct tagEMREXCLUDECLIPRECT { - EMR emr; - RECTL rclClip; - } EMREXCLUDECLIPRECT,*PEMREXCLUDECLIPRECT,EMRINTERSECTCLIPRECT,*PEMRINTERSECTCLIPRECT; - - typedef struct tagEMRSETVIEWPORTORGEX { - EMR emr; - POINTL ptlOrigin; - } EMRSETVIEWPORTORGEX,*PEMRSETVIEWPORTORGEX,EMRSETWINDOWORGEX,*PEMRSETWINDOWORGEX,EMRSETBRUSHORGEX,*PEMRSETBRUSHORGEX; - - typedef struct tagEMRSETVIEWPORTEXTEX { - EMR emr; - SIZEL szlExtent; - } EMRSETVIEWPORTEXTEX,*PEMRSETVIEWPORTEXTEX,EMRSETWINDOWEXTEX,*PEMRSETWINDOWEXTEX; - - typedef struct tagEMRSCALEVIEWPORTEXTEX { - EMR emr; - LONG xNum; - LONG xDenom; - LONG yNum; - LONG yDenom; - } EMRSCALEVIEWPORTEXTEX,*PEMRSCALEVIEWPORTEXTEX,EMRSCALEWINDOWEXTEX,*PEMRSCALEWINDOWEXTEX; - - typedef struct tagEMRSETWORLDTRANSFORM { - EMR emr; - XFORM xform; - } EMRSETWORLDTRANSFORM,*PEMRSETWORLDTRANSFORM; - - typedef struct tagEMRMODIFYWORLDTRANSFORM { - EMR emr; - XFORM xform; - DWORD iMode; - } EMRMODIFYWORLDTRANSFORM,*PEMRMODIFYWORLDTRANSFORM; - - typedef struct tagEMRSETPIXELV { - EMR emr; - POINTL ptlPixel; - COLORREF crColor; - } EMRSETPIXELV,*PEMRSETPIXELV; - - typedef struct tagEMREXTFLOODFILL { - EMR emr; - POINTL ptlStart; - COLORREF crColor; - DWORD iMode; - } EMREXTFLOODFILL,*PEMREXTFLOODFILL; - - typedef struct tagEMRELLIPSE { - EMR emr; - RECTL rclBox; - } EMRELLIPSE,*PEMRELLIPSE,EMRRECTANGLE,*PEMRRECTANGLE; - - typedef struct tagEMRROUNDRECT { - EMR emr; - RECTL rclBox; - SIZEL szlCorner; - } EMRROUNDRECT,*PEMRROUNDRECT; - - typedef struct tagEMRARC { - EMR emr; - RECTL rclBox; - POINTL ptlStart; - POINTL ptlEnd; - } EMRARC,*PEMRARC,EMRARCTO,*PEMRARCTO,EMRCHORD,*PEMRCHORD,EMRPIE,*PEMRPIE; - - typedef struct tagEMRANGLEARC { - EMR emr; - POINTL ptlCenter; - DWORD nRadius; - FLOAT eStartAngle; - FLOAT eSweepAngle; - } EMRANGLEARC,*PEMRANGLEARC; - - typedef struct tagEMRPOLYLINE { - EMR emr; - RECTL rclBounds; - DWORD cptl; - POINTL aptl[1]; - } EMRPOLYLINE,*PEMRPOLYLINE,EMRPOLYBEZIER,*PEMRPOLYBEZIER,EMRPOLYGON,*PEMRPOLYGON,EMRPOLYBEZIERTO,*PEMRPOLYBEZIERTO,EMRPOLYLINETO,*PEMRPOLYLINETO; - - typedef struct tagEMRPOLYLINE16 { - EMR emr; - RECTL rclBounds; - DWORD cpts; - POINTS apts[1]; - } EMRPOLYLINE16,*PEMRPOLYLINE16,EMRPOLYBEZIER16,*PEMRPOLYBEZIER16,EMRPOLYGON16,*PEMRPOLYGON16,EMRPOLYBEZIERTO16,*PEMRPOLYBEZIERTO16,EMRPOLYLINETO16,*PEMRPOLYLINETO16; - - typedef struct tagEMRPOLYDRAW { - EMR emr; - RECTL rclBounds; - DWORD cptl; - POINTL aptl[1]; - BYTE abTypes[1]; - } EMRPOLYDRAW,*PEMRPOLYDRAW; - - typedef struct tagEMRPOLYDRAW16 { - EMR emr; - RECTL rclBounds; - DWORD cpts; - POINTS apts[1]; - BYTE abTypes[1]; - } EMRPOLYDRAW16,*PEMRPOLYDRAW16; - - typedef struct tagEMRPOLYPOLYLINE { - EMR emr; - RECTL rclBounds; - DWORD nPolys; - DWORD cptl; - DWORD aPolyCounts[1]; - POINTL aptl[1]; - } EMRPOLYPOLYLINE,*PEMRPOLYPOLYLINE,EMRPOLYPOLYGON,*PEMRPOLYPOLYGON; - - typedef struct tagEMRPOLYPOLYLINE16 { - EMR emr; - RECTL rclBounds; - DWORD nPolys; - DWORD cpts; - DWORD aPolyCounts[1]; - POINTS apts[1]; - } EMRPOLYPOLYLINE16,*PEMRPOLYPOLYLINE16,EMRPOLYPOLYGON16,*PEMRPOLYPOLYGON16; - - typedef struct tagEMRINVERTRGN { - EMR emr; - RECTL rclBounds; - DWORD cbRgnData; - BYTE RgnData[1]; - } EMRINVERTRGN,*PEMRINVERTRGN,EMRPAINTRGN,*PEMRPAINTRGN; - - typedef struct tagEMRFILLRGN { - EMR emr; - RECTL rclBounds; - DWORD cbRgnData; - DWORD ihBrush; - BYTE RgnData[1]; - } EMRFILLRGN,*PEMRFILLRGN; - - typedef struct tagEMRFRAMERGN { - EMR emr; - RECTL rclBounds; - DWORD cbRgnData; - DWORD ihBrush; - SIZEL szlStroke; - BYTE RgnData[1]; - } EMRFRAMERGN,*PEMRFRAMERGN; - - typedef struct tagEMREXTSELECTCLIPRGN { - EMR emr; - DWORD cbRgnData; - DWORD iMode; - BYTE RgnData[1]; - } EMREXTSELECTCLIPRGN,*PEMREXTSELECTCLIPRGN; - - typedef struct tagEMREXTTEXTOUTA { - EMR emr; - RECTL rclBounds; - DWORD iGraphicsMode; - FLOAT exScale; - FLOAT eyScale; - EMRTEXT emrtext; - } EMREXTTEXTOUTA,*PEMREXTTEXTOUTA,EMREXTTEXTOUTW,*PEMREXTTEXTOUTW; - - typedef struct tagEMRPOLYTEXTOUTA { - EMR emr; - RECTL rclBounds; - DWORD iGraphicsMode; - FLOAT exScale; - FLOAT eyScale; - LONG cStrings; - EMRTEXT aemrtext[1]; - } EMRPOLYTEXTOUTA,*PEMRPOLYTEXTOUTA,EMRPOLYTEXTOUTW,*PEMRPOLYTEXTOUTW; - - typedef struct tagEMRBITBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - } EMRBITBLT,*PEMRBITBLT; - - typedef struct tagEMRSTRETCHBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG cxSrc; - LONG cySrc; - } EMRSTRETCHBLT,*PEMRSTRETCHBLT; - - typedef struct tagEMRMASKBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG xMask; - LONG yMask; - DWORD iUsageMask; - DWORD offBmiMask; - DWORD cbBmiMask; - DWORD offBitsMask; - DWORD cbBitsMask; - } EMRMASKBLT,*PEMRMASKBLT; - - typedef struct tagEMRPLGBLT { - EMR emr; - RECTL rclBounds; - POINTL aptlDest[3]; - LONG xSrc; - LONG ySrc; - LONG cxSrc; - LONG cySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG xMask; - LONG yMask; - DWORD iUsageMask; - DWORD offBmiMask; - DWORD cbBmiMask; - DWORD offBitsMask; - DWORD cbBitsMask; - } EMRPLGBLT,*PEMRPLGBLT; - - typedef struct tagEMRSETDIBITSTODEVICE { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG xSrc; - LONG ySrc; - LONG cxSrc; - LONG cySrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - DWORD iUsageSrc; - DWORD iStartScan; - DWORD cScans; - } EMRSETDIBITSTODEVICE,*PEMRSETDIBITSTODEVICE; - - typedef struct tagEMRSTRETCHDIBITS { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG xSrc; - LONG ySrc; - LONG cxSrc; - LONG cySrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - DWORD iUsageSrc; - DWORD dwRop; - LONG cxDest; - LONG cyDest; - } EMRSTRETCHDIBITS,*PEMRSTRETCHDIBITS; - - typedef struct tagEMREXTCREATEFONTINDIRECTW { - EMR emr; - DWORD ihFont; - EXTLOGFONTW elfw; - } EMREXTCREATEFONTINDIRECTW,*PEMREXTCREATEFONTINDIRECTW; - - typedef struct tagEMRCREATEPALETTE { - EMR emr; - DWORD ihPal; - LOGPALETTE lgpl; - } EMRCREATEPALETTE,*PEMRCREATEPALETTE; - - typedef struct tagEMRCREATEPEN { - EMR emr; - DWORD ihPen; - LOGPEN lopn; - } EMRCREATEPEN,*PEMRCREATEPEN; - - typedef struct tagEMREXTCREATEPEN { - EMR emr; - DWORD ihPen; - DWORD offBmi; - DWORD cbBmi; - DWORD offBits; - DWORD cbBits; - EXTLOGPEN elp; - } EMREXTCREATEPEN,*PEMREXTCREATEPEN; - - typedef struct tagEMRCREATEBRUSHINDIRECT { - EMR emr; - DWORD ihBrush; - LOGBRUSH32 lb; - } EMRCREATEBRUSHINDIRECT,*PEMRCREATEBRUSHINDIRECT; - - typedef struct tagEMRCREATEMONOBRUSH { - EMR emr; - DWORD ihBrush; - DWORD iUsage; - DWORD offBmi; - DWORD cbBmi; - DWORD offBits; - DWORD cbBits; - } EMRCREATEMONOBRUSH,*PEMRCREATEMONOBRUSH; - - typedef struct tagEMRCREATEDIBPATTERNBRUSHPT { - EMR emr; - DWORD ihBrush; - DWORD iUsage; - DWORD offBmi; - DWORD cbBmi; - DWORD offBits; - DWORD cbBits; - } EMRCREATEDIBPATTERNBRUSHPT,*PEMRCREATEDIBPATTERNBRUSHPT; - - typedef struct tagEMRFORMAT { - DWORD dSignature; - DWORD nVersion; - DWORD cbData; - DWORD offData; - } EMRFORMAT,*PEMRFORMAT; - - typedef struct tagEMRGLSRECORD { - EMR emr; - DWORD cbData; - BYTE Data[1]; - } EMRGLSRECORD,*PEMRGLSRECORD; - - typedef struct tagEMRGLSBOUNDEDRECORD { - EMR emr; - RECTL rclBounds; - DWORD cbData; - BYTE Data[1]; - } EMRGLSBOUNDEDRECORD,*PEMRGLSBOUNDEDRECORD; - - typedef struct tagEMRPIXELFORMAT { - EMR emr; - PIXELFORMATDESCRIPTOR pfd; - } EMRPIXELFORMAT,*PEMRPIXELFORMAT; - - typedef struct tagEMRCREATECOLORSPACE { - EMR emr; - DWORD ihCS; - LOGCOLORSPACEA lcs; - } EMRCREATECOLORSPACE,*PEMRCREATECOLORSPACE; - - typedef struct tagEMRSETCOLORSPACE { - EMR emr; - DWORD ihCS; - } EMRSETCOLORSPACE,*PEMRSETCOLORSPACE,EMRSELECTCOLORSPACE,*PEMRSELECTCOLORSPACE,EMRDELETECOLORSPACE,*PEMRDELETECOLORSPACE; - - typedef struct tagEMREXTESCAPE { - EMR emr; - INT iEscape; - INT cbEscData; - BYTE EscData[1]; - } EMREXTESCAPE,*PEMREXTESCAPE,EMRDRAWESCAPE,*PEMRDRAWESCAPE; - - typedef struct tagEMRNAMEDESCAPE { - EMR emr; - INT iEscape; - INT cbDriver; - INT cbEscData; - BYTE EscData[1]; - } EMRNAMEDESCAPE,*PEMRNAMEDESCAPE; - -#define SETICMPROFILE_EMBEDED 0x00000001 - - typedef struct tagEMRSETICMPROFILE { - EMR emr; - DWORD dwFlags; - DWORD cbName; - DWORD cbData; - BYTE Data[1]; - } EMRSETICMPROFILE,*PEMRSETICMPROFILE,EMRSETICMPROFILEA,*PEMRSETICMPROFILEA,EMRSETICMPROFILEW,*PEMRSETICMPROFILEW; - -#define CREATECOLORSPACE_EMBEDED 0x00000001 - - typedef struct tagEMRCREATECOLORSPACEW { - EMR emr; - DWORD ihCS; - LOGCOLORSPACEW lcs; - DWORD dwFlags; - DWORD cbData; - BYTE Data[1]; - } EMRCREATECOLORSPACEW,*PEMRCREATECOLORSPACEW; - -#define COLORMATCHTOTARGET_EMBEDED 0x00000001 - - typedef struct tagCOLORMATCHTOTARGET { - EMR emr; - DWORD dwAction; - DWORD dwFlags; - DWORD cbName; - DWORD cbData; - BYTE Data[1]; - } EMRCOLORMATCHTOTARGET,*PEMRCOLORMATCHTOTARGET; - - typedef struct tagCOLORCORRECTPALETTE { - EMR emr; - DWORD ihPalette; - DWORD nFirstEntry; - DWORD nPalEntries; - DWORD nReserved; - } EMRCOLORCORRECTPALETTE,*PEMRCOLORCORRECTPALETTE; - - typedef struct tagEMRALPHABLEND { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG cxSrc; - LONG cySrc; - } EMRALPHABLEND,*PEMRALPHABLEND; - - typedef struct tagEMRGRADIENTFILL { - EMR emr; - RECTL rclBounds; - DWORD nVer; - DWORD nTri; - ULONG ulMode; - TRIVERTEX Ver[1]; - } EMRGRADIENTFILL,*PEMRGRADIENTFILL; - - typedef struct tagEMRTRANSPARENTBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG cxSrc; - LONG cySrc; - } EMRTRANSPARENTBLT,*PEMRTRANSPARENTBLT; - -#define GDICOMMENT_IDENTIFIER 0x43494447 -#define GDICOMMENT_WINDOWS_METAFILE 0x80000001 -#define GDICOMMENT_BEGINGROUP 0x00000002 -#define GDICOMMENT_ENDGROUP 0x00000003 -#define GDICOMMENT_MULTIFORMATS 0x40000004 -#define EPS_SIGNATURE 0x46535045 -#define GDICOMMENT_UNICODE_STRING 0x00000040 -#define GDICOMMENT_UNICODE_END 0x00000080 -#endif - -#ifdef UNICODE -#define wglUseFontBitmaps wglUseFontBitmapsW -#else -#define wglUseFontBitmaps wglUseFontBitmapsA -#endif - - WINGDIAPI WINBOOL WINAPI wglCopyContext(HGLRC,HGLRC,UINT); - WINGDIAPI HGLRC WINAPI wglCreateContext(HDC); - WINGDIAPI HGLRC WINAPI wglCreateLayerContext(HDC,int); - WINGDIAPI WINBOOL WINAPI wglDeleteContext(HGLRC); - WINGDIAPI HGLRC WINAPI wglGetCurrentContext(VOID); - WINGDIAPI HDC WINAPI wglGetCurrentDC(VOID); - WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR); - WINGDIAPI WINBOOL WINAPI wglMakeCurrent(HDC,HGLRC); - WINGDIAPI WINBOOL WINAPI wglShareLists(HGLRC,HGLRC); - WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsA(HDC,DWORD,DWORD,DWORD); - WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsW(HDC,DWORD,DWORD,DWORD); - WINGDIAPI WINBOOL WINAPI SwapBuffers(HDC); - - typedef struct _POINTFLOAT { - FLOAT x; - FLOAT y; - } POINTFLOAT,*PPOINTFLOAT; - - typedef struct _GLYPHMETRICSFLOAT { - FLOAT gmfBlackBoxX; - FLOAT gmfBlackBoxY; - POINTFLOAT gmfptGlyphOrigin; - FLOAT gmfCellIncX; - FLOAT gmfCellIncY; - } GLYPHMETRICSFLOAT,*PGLYPHMETRICSFLOAT,*LPGLYPHMETRICSFLOAT; - -#define WGL_FONT_LINES 0 -#define WGL_FONT_POLYGONS 1 - -#ifdef UNICODE -#define wglUseFontOutlines wglUseFontOutlinesW -#else -#define wglUseFontOutlines wglUseFontOutlinesA -#endif - - WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesA(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); - WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesW(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); - - typedef struct tagLAYERPLANEDESCRIPTOR { - WORD nSize; - WORD nVersion; - DWORD dwFlags; - BYTE iPixelType; - BYTE cColorBits; - BYTE cRedBits; - BYTE cRedShift; - BYTE cGreenBits; - BYTE cGreenShift; - BYTE cBlueBits; - BYTE cBlueShift; - BYTE cAlphaBits; - BYTE cAlphaShift; - BYTE cAccumBits; - BYTE cAccumRedBits; - BYTE cAccumGreenBits; - BYTE cAccumBlueBits; - BYTE cAccumAlphaBits; - BYTE cDepthBits; - BYTE cStencilBits; - BYTE cAuxBuffers; - BYTE iLayerPlane; - BYTE bReserved; - COLORREF crTransparent; - } LAYERPLANEDESCRIPTOR,*PLAYERPLANEDESCRIPTOR,*LPLAYERPLANEDESCRIPTOR; - -#define LPD_DOUBLEBUFFER 0x00000001 -#define LPD_STEREO 0x00000002 -#define LPD_SUPPORT_GDI 0x00000010 -#define LPD_SUPPORT_OPENGL 0x00000020 -#define LPD_SHARE_DEPTH 0x00000040 -#define LPD_SHARE_STENCIL 0x00000080 -#define LPD_SHARE_ACCUM 0x00000100 -#define LPD_SWAP_EXCHANGE 0x00000200 -#define LPD_SWAP_COPY 0x00000400 -#define LPD_TRANSPARENT 0x00001000 - -#define LPD_TYPE_RGBA 0 -#define LPD_TYPE_COLORINDEX 1 - -#define WGL_SWAP_MAIN_PLANE 0x00000001 -#define WGL_SWAP_OVERLAY1 0x00000002 -#define WGL_SWAP_OVERLAY2 0x00000004 -#define WGL_SWAP_OVERLAY3 0x00000008 -#define WGL_SWAP_OVERLAY4 0x00000010 -#define WGL_SWAP_OVERLAY5 0x00000020 -#define WGL_SWAP_OVERLAY6 0x00000040 -#define WGL_SWAP_OVERLAY7 0x00000080 -#define WGL_SWAP_OVERLAY8 0x00000100 -#define WGL_SWAP_OVERLAY9 0x00000200 -#define WGL_SWAP_OVERLAY10 0x00000400 -#define WGL_SWAP_OVERLAY11 0x00000800 -#define WGL_SWAP_OVERLAY12 0x00001000 -#define WGL_SWAP_OVERLAY13 0x00002000 -#define WGL_SWAP_OVERLAY14 0x00004000 -#define WGL_SWAP_OVERLAY15 0x00008000 -#define WGL_SWAP_UNDERLAY1 0x00010000 -#define WGL_SWAP_UNDERLAY2 0x00020000 -#define WGL_SWAP_UNDERLAY3 0x00040000 -#define WGL_SWAP_UNDERLAY4 0x00080000 -#define WGL_SWAP_UNDERLAY5 0x00100000 -#define WGL_SWAP_UNDERLAY6 0x00200000 -#define WGL_SWAP_UNDERLAY7 0x00400000 -#define WGL_SWAP_UNDERLAY8 0x00800000 -#define WGL_SWAP_UNDERLAY9 0x01000000 -#define WGL_SWAP_UNDERLAY10 0x02000000 -#define WGL_SWAP_UNDERLAY11 0x04000000 -#define WGL_SWAP_UNDERLAY12 0x08000000 -#define WGL_SWAP_UNDERLAY13 0x10000000 -#define WGL_SWAP_UNDERLAY14 0x20000000 -#define WGL_SWAP_UNDERLAY15 0x40000000 - - WINGDIAPI WINBOOL WINAPI wglDescribeLayerPlane(HDC,int,int,UINT,LPLAYERPLANEDESCRIPTOR); - WINGDIAPI int WINAPI wglSetLayerPaletteEntries(HDC,int,int,int,CONST COLORREF *); - WINGDIAPI int WINAPI wglGetLayerPaletteEntries(HDC,int,int,int,COLORREF *); - WINGDIAPI WINBOOL WINAPI wglRealizeLayerPalette(HDC,int,WINBOOL); - WINGDIAPI WINBOOL WINAPI wglSwapLayerBuffers(HDC,UINT); - - typedef struct _WGLSWAP { - HDC hdc; - UINT uiFlags; - } WGLSWAP,*PWGLSWAP,*LPWGLSWAP; - -#define WGL_SWAPMULTIPLE_MAX 16 - - WINGDIAPI DWORD WINAPI wglSwapMultipleBuffers(UINT,CONST WGLSWAP *); -#endif - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINGDI_ +#define _WINGDI_ + +#define WINGDIAPI DECLSPEC_IMPORT +#define WINSPOOLAPI DECLSPEC_IMPORT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#ifndef NOGDI +#ifndef NORASTEROPS +#define R2_BLACK 1 +#define R2_NOTMERGEPEN 2 +#define R2_MASKNOTPEN 3 +#define R2_NOTCOPYPEN 4 +#define R2_MASKPENNOT 5 +#define R2_NOT 6 +#define R2_XORPEN 7 +#define R2_NOTMASKPEN 8 +#define R2_MASKPEN 9 +#define R2_NOTXORPEN 10 +#define R2_NOP 11 +#define R2_MERGENOTPEN 12 +#define R2_COPYPEN 13 +#define R2_MERGEPENNOT 14 +#define R2_MERGEPEN 15 +#define R2_WHITE 16 +#define R2_LAST 16 + +#define SRCCOPY (DWORD)0x00CC0020 +#define SRCPAINT (DWORD)0x00EE0086 +#define SRCAND (DWORD)0x008800C6 +#define SRCINVERT (DWORD)0x00660046 +#define SRCERASE (DWORD)0x00440328 +#define NOTSRCCOPY (DWORD)0x00330008 +#define NOTSRCERASE (DWORD)0x001100A6 +#define MERGECOPY (DWORD)0x00C000CA +#define MERGEPAINT (DWORD)0x00BB0226 +#define PATCOPY (DWORD)0x00F00021 +#define PATPAINT (DWORD)0x00FB0A09 +#define PATINVERT (DWORD)0x005A0049 +#define DSTINVERT (DWORD)0x00550009 +#define BLACKNESS (DWORD)0x00000042 +#define WHITENESS (DWORD)0x00FF0062 +#define NOMIRRORBITMAP (DWORD)0x80000000 +#define CAPTUREBLT (DWORD)0x40000000 +#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) +#endif + +#define GDI_ERROR (0xFFFFFFFFL) +#define HGDI_ERROR (LongToHandle(0xFFFFFFFFL)) + +#define ERROR 0 +#define NULLREGION 1 +#define SIMPLEREGION 2 +#define COMPLEXREGION 3 +#define RGN_ERROR ERROR + +#define RGN_AND 1 +#define RGN_OR 2 +#define RGN_XOR 3 +#define RGN_DIFF 4 +#define RGN_COPY 5 +#define RGN_MIN RGN_AND +#define RGN_MAX RGN_COPY + +#define BLACKONWHITE 1 +#define WHITEONBLACK 2 +#define COLORONCOLOR 3 +#define HALFTONE 4 +#define MAXSTRETCHBLTMODE 4 + +#define STRETCH_ANDSCANS BLACKONWHITE +#define STRETCH_ORSCANS WHITEONBLACK +#define STRETCH_DELETESCANS COLORONCOLOR +#define STRETCH_HALFTONE HALFTONE + +#define ALTERNATE 1 +#define WINDING 2 +#define POLYFILL_LAST 2 + +#define LAYOUT_RTL 0x00000001 +#define LAYOUT_BTT 0x00000002 +#define LAYOUT_VBH 0x00000004 +#define LAYOUT_ORIENTATIONMASK (LAYOUT_RTL | LAYOUT_BTT | LAYOUT_VBH) +#define LAYOUT_BITMAPORIENTATIONPRESERVED 0x00000008 + +#define TA_NOUPDATECP 0 +#define TA_UPDATECP 1 + +#define TA_LEFT 0 +#define TA_RIGHT 2 +#define TA_CENTER 6 + +#define TA_TOP 0 +#define TA_BOTTOM 8 +#define TA_BASELINE 24 +#define TA_RTLREADING 256 +#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING) + +#define VTA_BASELINE TA_BASELINE +#define VTA_LEFT TA_BOTTOM +#define VTA_RIGHT TA_TOP +#define VTA_CENTER TA_CENTER +#define VTA_BOTTOM TA_RIGHT +#define VTA_TOP TA_LEFT + +#define ETO_OPAQUE 0x0002 +#define ETO_CLIPPED 0x0004 +#define ETO_GLYPH_INDEX 0x0010 +#define ETO_RTLREADING 0x0080 +#define ETO_NUMERICSLOCAL 0x0400 +#define ETO_NUMERICSLATIN 0x0800 +#define ETO_IGNORELANGUAGE 0x1000 +#define ETO_PDY 0x2000 + +#define ASPECT_FILTERING 0x0001 + +#define DCB_RESET 0x0001 +#define DCB_ACCUMULATE 0x0002 +#define DCB_DIRTY DCB_ACCUMULATE +#define DCB_SET (DCB_RESET | DCB_ACCUMULATE) +#define DCB_ENABLE 0x0004 +#define DCB_DISABLE 0x0008 + +#ifndef NOMETAFILE + +#define META_SETBKCOLOR 0x0201 +#define META_SETBKMODE 0x0102 +#define META_SETMAPMODE 0x0103 +#define META_SETROP2 0x0104 +#define META_SETRELABS 0x0105 +#define META_SETPOLYFILLMODE 0x0106 +#define META_SETSTRETCHBLTMODE 0x0107 +#define META_SETTEXTCHAREXTRA 0x0108 +#define META_SETTEXTCOLOR 0x0209 +#define META_SETTEXTJUSTIFICATION 0x020A +#define META_SETWINDOWORG 0x020B +#define META_SETWINDOWEXT 0x020C +#define META_SETVIEWPORTORG 0x020D +#define META_SETVIEWPORTEXT 0x020E +#define META_OFFSETWINDOWORG 0x020F +#define META_SCALEWINDOWEXT 0x0410 +#define META_OFFSETVIEWPORTORG 0x0211 +#define META_SCALEVIEWPORTEXT 0x0412 +#define META_LINETO 0x0213 +#define META_MOVETO 0x0214 +#define META_EXCLUDECLIPRECT 0x0415 +#define META_INTERSECTCLIPRECT 0x0416 +#define META_ARC 0x0817 +#define META_ELLIPSE 0x0418 +#define META_FLOODFILL 0x0419 +#define META_PIE 0x081A +#define META_RECTANGLE 0x041B +#define META_ROUNDRECT 0x061C +#define META_PATBLT 0x061D +#define META_SAVEDC 0x001E +#define META_SETPIXEL 0x041F +#define META_OFFSETCLIPRGN 0x0220 +#define META_TEXTOUT 0x0521 +#define META_BITBLT 0x0922 +#define META_STRETCHBLT 0x0B23 +#define META_POLYGON 0x0324 +#define META_POLYLINE 0x0325 +#define META_ESCAPE 0x0626 +#define META_RESTOREDC 0x0127 +#define META_FILLREGION 0x0228 +#define META_FRAMEREGION 0x0429 +#define META_INVERTREGION 0x012A +#define META_PAINTREGION 0x012B +#define META_SELECTCLIPREGION 0x012C +#define META_SELECTOBJECT 0x012D +#define META_SETTEXTALIGN 0x012E +#define META_CHORD 0x0830 +#define META_SETMAPPERFLAGS 0x0231 +#define META_EXTTEXTOUT 0x0a32 +#define META_SETDIBTODEV 0x0d33 +#define META_SELECTPALETTE 0x0234 +#define META_REALIZEPALETTE 0x0035 +#define META_ANIMATEPALETTE 0x0436 +#define META_SETPALENTRIES 0x0037 +#define META_POLYPOLYGON 0x0538 +#define META_RESIZEPALETTE 0x0139 +#define META_DIBBITBLT 0x0940 +#define META_DIBSTRETCHBLT 0x0b41 +#define META_DIBCREATEPATTERNBRUSH 0x0142 +#define META_STRETCHDIB 0x0f43 +#define META_EXTFLOODFILL 0x0548 +#define META_SETLAYOUT 0x0149 +#define META_DELETEOBJECT 0x01f0 +#define META_CREATEPALETTE 0x00f7 +#define META_CREATEPATTERNBRUSH 0x01F9 +#define META_CREATEPENINDIRECT 0x02FA +#define META_CREATEFONTINDIRECT 0x02FB +#define META_CREATEBRUSHINDIRECT 0x02FC +#define META_CREATEREGION 0x06FF + + typedef struct _DRAWPATRECT { + POINT ptPosition; + POINT ptSize; + WORD wStyle; + WORD wPattern; + } DRAWPATRECT,*PDRAWPATRECT; +#endif + +#define NEWFRAME 1 +#define ABORTDOC 2 +#define NEXTBAND 3 +#define SETCOLORTABLE 4 +#define GETCOLORTABLE 5 +#define FLUSHOUTPUT 6 +#define DRAFTMODE 7 +#define QUERYESCSUPPORT 8 +#define SETABORTPROC 9 +#define STARTDOC 10 +#define ENDDOC 11 +#define GETPHYSPAGESIZE 12 +#define GETPRINTINGOFFSET 13 +#define GETSCALINGFACTOR 14 +#define MFCOMMENT 15 +#define GETPENWIDTH 16 +#define SETCOPYCOUNT 17 +#define SELECTPAPERSOURCE 18 +#define DEVICEDATA 19 +#define PASSTHROUGH 19 +#define GETTECHNOLGY 20 +#define GETTECHNOLOGY 20 +#define SETLINECAP 21 +#define SETLINEJOIN 22 +#define SETMITERLIMIT 23 +#define BANDINFO 24 +#define DRAWPATTERNRECT 25 +#define GETVECTORPENSIZE 26 +#define GETVECTORBRUSHSIZE 27 +#define ENABLEDUPLEX 28 +#define GETSETPAPERBINS 29 +#define GETSETPRINTORIENT 30 +#define ENUMPAPERBINS 31 +#define SETDIBSCALING 32 +#define EPSPRINTING 33 +#define ENUMPAPERMETRICS 34 +#define GETSETPAPERMETRICS 35 +#define POSTSCRIPT_DATA 37 +#define POSTSCRIPT_IGNORE 38 +#define MOUSETRAILS 39 +#define GETDEVICEUNITS 42 + +#define GETEXTENDEDTEXTMETRICS 256 +#define GETEXTENTTABLE 257 +#define GETPAIRKERNTABLE 258 +#define GETTRACKKERNTABLE 259 +#define EXTTEXTOUT 512 +#define GETFACENAME 513 +#define DOWNLOADFACE 514 +#define ENABLERELATIVEWIDTHS 768 +#define ENABLEPAIRKERNING 769 +#define SETKERNTRACK 770 +#define SETALLJUSTVALUES 771 +#define SETCHARSET 772 + +#define STRETCHBLT 2048 +#define METAFILE_DRIVER 2049 +#define GETSETSCREENPARAMS 3072 +#define QUERYDIBSUPPORT 3073 +#define BEGIN_PATH 4096 +#define CLIP_TO_PATH 4097 +#define END_PATH 4098 +#define EXT_DEVICE_CAPS 4099 +#define RESTORE_CTM 4100 +#define SAVE_CTM 4101 +#define SET_ARC_DIRECTION 4102 +#define SET_BACKGROUND_COLOR 4103 +#define SET_POLY_MODE 4104 +#define SET_SCREEN_ANGLE 4105 +#define SET_SPREAD 4106 +#define TRANSFORM_CTM 4107 +#define SET_CLIP_BOX 4108 +#define SET_BOUNDS 4109 +#define SET_MIRROR_MODE 4110 +#define OPENCHANNEL 4110 +#define DOWNLOADHEADER 4111 +#define CLOSECHANNEL 4112 +#define POSTSCRIPT_PASSTHROUGH 4115 +#define ENCAPSULATED_POSTSCRIPT 4116 + +#define POSTSCRIPT_IDENTIFY 4117 +#define POSTSCRIPT_INJECTION 4118 + +#define CHECKJPEGFORMAT 4119 +#define CHECKPNGFORMAT 4120 + +#define GET_PS_FEATURESETTING 4121 + +#define SPCLPASSTHROUGH2 4568 + +#define PSIDENT_GDICENTRIC 0 +#define PSIDENT_PSCENTRIC 1 + + typedef struct _PSINJECTDATA { + DWORD DataBytes; + WORD InjectionPoint; + WORD PageNumber; + } PSINJECTDATA,*PPSINJECTDATA; + +#define PSINJECT_BEGINSTREAM 1 +#define PSINJECT_PSADOBE 2 +#define PSINJECT_PAGESATEND 3 +#define PSINJECT_PAGES 4 + +#define PSINJECT_DOCNEEDEDRES 5 +#define PSINJECT_DOCSUPPLIEDRES 6 +#define PSINJECT_PAGEORDER 7 +#define PSINJECT_ORIENTATION 8 +#define PSINJECT_BOUNDINGBOX 9 +#define PSINJECT_DOCUMENTPROCESSCOLORS 10 + +#define PSINJECT_COMMENTS 11 +#define PSINJECT_BEGINDEFAULTS 12 +#define PSINJECT_ENDDEFAULTS 13 +#define PSINJECT_BEGINPROLOG 14 +#define PSINJECT_ENDPROLOG 15 +#define PSINJECT_BEGINSETUP 16 +#define PSINJECT_ENDSETUP 17 +#define PSINJECT_TRAILER 18 +#define PSINJECT_EOF 19 +#define PSINJECT_ENDSTREAM 20 +#define PSINJECT_DOCUMENTPROCESSCOLORSATEND 21 + +#define PSINJECT_PAGENUMBER 100 +#define PSINJECT_BEGINPAGESETUP 101 +#define PSINJECT_ENDPAGESETUP 102 +#define PSINJECT_PAGETRAILER 103 +#define PSINJECT_PLATECOLOR 104 + +#define PSINJECT_SHOWPAGE 105 +#define PSINJECT_PAGEBBOX 106 +#define PSINJECT_ENDPAGECOMMENTS 107 + +#define PSINJECT_VMSAVE 200 +#define PSINJECT_VMRESTORE 201 + +#define FEATURESETTING_NUP 0 +#define FEATURESETTING_OUTPUT 1 +#define FEATURESETTING_PSLEVEL 2 +#define FEATURESETTING_CUSTPAPER 3 +#define FEATURESETTING_MIRROR 4 +#define FEATURESETTING_NEGATIVE 5 +#define FEATURESETTING_PROTOCOL 6 + +#define FEATURESETTING_PRIVATE_BEGIN 0x1000 +#define FEATURESETTING_PRIVATE_END 0x1FFF + + typedef struct _PSFEATURE_OUTPUT { + WINBOOL bPageIndependent; + WINBOOL bSetPageDevice; + } PSFEATURE_OUTPUT,*PPSFEATURE_OUTPUT; + + typedef struct _PSFEATURE_CUSTPAPER { + LONG lOrientation; + LONG lWidth; + LONG lHeight; + LONG lWidthOffset; + LONG lHeightOffset; + } PSFEATURE_CUSTPAPER,*PPSFEATURE_CUSTPAPER; + +#define PSPROTOCOL_ASCII 0 +#define PSPROTOCOL_BCP 1 +#define PSPROTOCOL_TBCP 2 +#define PSPROTOCOL_BINARY 3 + +#define QDI_SETDIBITS 1 +#define QDI_GETDIBITS 2 +#define QDI_DIBTOSCREEN 4 +#define QDI_STRETCHDIB 8 + +#define SP_NOTREPORTED 0x4000 +#define SP_ERROR (-1) +#define SP_APPABORT (-2) +#define SP_USERABORT (-3) +#define SP_OUTOFDISK (-4) +#define SP_OUTOFMEMORY (-5) + +#define PR_JOBSTATUS 0x0000 + +#define OBJ_PEN 1 +#define OBJ_BRUSH 2 +#define OBJ_DC 3 +#define OBJ_METADC 4 +#define OBJ_PAL 5 +#define OBJ_FONT 6 +#define OBJ_BITMAP 7 +#define OBJ_REGION 8 +#define OBJ_METAFILE 9 +#define OBJ_MEMDC 10 +#define OBJ_EXTPEN 11 +#define OBJ_ENHMETADC 12 +#define OBJ_ENHMETAFILE 13 +#define OBJ_COLORSPACE 14 + +#define MWT_IDENTITY 1 +#define MWT_LEFTMULTIPLY 2 +#define MWT_RIGHTMULTIPLY 3 + +#define MWT_MIN MWT_IDENTITY +#define MWT_MAX MWT_RIGHTMULTIPLY + +#define _XFORM_ + typedef struct tagXFORM { + FLOAT eM11; + FLOAT eM12; + FLOAT eM21; + FLOAT eM22; + FLOAT eDx; + FLOAT eDy; + } XFORM,*PXFORM,*LPXFORM; + + typedef struct tagBITMAP { + LONG bmType; + LONG bmWidth; + LONG bmHeight; + LONG bmWidthBytes; + WORD bmPlanes; + WORD bmBitsPixel; + LPVOID bmBits; + } BITMAP,*PBITMAP,*NPBITMAP,*LPBITMAP; + +#include + typedef struct tagRGBTRIPLE { + BYTE rgbtBlue; + BYTE rgbtGreen; + BYTE rgbtRed; + } RGBTRIPLE; +#include + + typedef struct tagRGBQUAD { + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; + BYTE rgbReserved; + } RGBQUAD; + typedef RGBQUAD *LPRGBQUAD; + +#define CS_ENABLE 0x00000001L +#define CS_DISABLE 0x00000002L +#define CS_DELETE_TRANSFORM 0x00000003L + +//!__TINYC__: #define LCS_SIGNATURE 'PSOC' +//!__TINYC__: #define LCS_sRGB 'sRGB' +//!__TINYC__: #define LCS_WINDOWS_COLOR_SPACE 'Win ' + + typedef LONG LCSCSTYPE; +#define LCS_CALIBRATED_RGB 0x00000000L + + typedef LONG LCSGAMUTMATCH; +#define LCS_GM_BUSINESS 0x00000001L +#define LCS_GM_GRAPHICS 0x00000002L +#define LCS_GM_IMAGES 0x00000004L +#define LCS_GM_ABS_COLORIMETRIC 0x00000008L + +#define CM_OUT_OF_GAMUT 255 +#define CM_IN_GAMUT 0 + +#define ICM_ADDPROFILE 1 +#define ICM_DELETEPROFILE 2 +#define ICM_QUERYPROFILE 3 +#define ICM_SETDEFAULTPROFILE 4 +#define ICM_REGISTERICMATCHER 5 +#define ICM_UNREGISTERICMATCHER 6 +#define ICM_QUERYMATCH 7 + +#define GetKValue(cmyk) ((BYTE)(cmyk)) +#define GetYValue(cmyk) ((BYTE)((cmyk)>> 8)) +#define GetMValue(cmyk) ((BYTE)((cmyk)>>16)) +#define GetCValue(cmyk) ((BYTE)((cmyk)>>24)) + +#define CMYK(c,m,y,k) ((COLORREF)((((BYTE)(k)|((WORD)((BYTE)(y))<<8))|(((DWORD)(BYTE)(m))<<16))|(((DWORD)(BYTE)(c))<<24))) + + typedef long FXPT16DOT16,*LPFXPT16DOT16; + typedef long FXPT2DOT30,*LPFXPT2DOT30; + + typedef struct tagCIEXYZ { + FXPT2DOT30 ciexyzX; + FXPT2DOT30 ciexyzY; + FXPT2DOT30 ciexyzZ; + } CIEXYZ; + typedef CIEXYZ *LPCIEXYZ; + + typedef struct tagICEXYZTRIPLE { + CIEXYZ ciexyzRed; + CIEXYZ ciexyzGreen; + CIEXYZ ciexyzBlue; + } CIEXYZTRIPLE; + + typedef CIEXYZTRIPLE *LPCIEXYZTRIPLE; + + typedef struct tagLOGCOLORSPACEA { + DWORD lcsSignature; + DWORD lcsVersion; + DWORD lcsSize; + LCSCSTYPE lcsCSType; + LCSGAMUTMATCH lcsIntent; + CIEXYZTRIPLE lcsEndpoints; + DWORD lcsGammaRed; + DWORD lcsGammaGreen; + DWORD lcsGammaBlue; + CHAR lcsFilename[MAX_PATH]; + } LOGCOLORSPACEA,*LPLOGCOLORSPACEA; + + typedef struct tagLOGCOLORSPACEW { + DWORD lcsSignature; + DWORD lcsVersion; + DWORD lcsSize; + LCSCSTYPE lcsCSType; + LCSGAMUTMATCH lcsIntent; + CIEXYZTRIPLE lcsEndpoints; + DWORD lcsGammaRed; + DWORD lcsGammaGreen; + DWORD lcsGammaBlue; + WCHAR lcsFilename[MAX_PATH]; + } LOGCOLORSPACEW,*LPLOGCOLORSPACEW; + +#ifdef UNICODE + typedef LOGCOLORSPACEW LOGCOLORSPACE; + typedef LPLOGCOLORSPACEW LPLOGCOLORSPACE; +#else + typedef LOGCOLORSPACEA LOGCOLORSPACE; + typedef LPLOGCOLORSPACEA LPLOGCOLORSPACE; +#endif + + typedef struct tagBITMAPCOREHEADER { + DWORD bcSize; + WORD bcWidth; + WORD bcHeight; + WORD bcPlanes; + WORD bcBitCount; + } BITMAPCOREHEADER,*LPBITMAPCOREHEADER,*PBITMAPCOREHEADER; + + typedef struct tagBITMAPINFOHEADER { + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; + } BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER; + + typedef struct { + DWORD bV4Size; + LONG bV4Width; + LONG bV4Height; + WORD bV4Planes; + WORD bV4BitCount; + DWORD bV4V4Compression; + DWORD bV4SizeImage; + LONG bV4XPelsPerMeter; + LONG bV4YPelsPerMeter; + DWORD bV4ClrUsed; + DWORD bV4ClrImportant; + DWORD bV4RedMask; + DWORD bV4GreenMask; + DWORD bV4BlueMask; + DWORD bV4AlphaMask; + DWORD bV4CSType; + CIEXYZTRIPLE bV4Endpoints; + DWORD bV4GammaRed; + DWORD bV4GammaGreen; + DWORD bV4GammaBlue; + } BITMAPV4HEADER,*LPBITMAPV4HEADER,*PBITMAPV4HEADER; + + typedef struct { + DWORD bV5Size; + LONG bV5Width; + LONG bV5Height; + WORD bV5Planes; + WORD bV5BitCount; + DWORD bV5Compression; + DWORD bV5SizeImage; + LONG bV5XPelsPerMeter; + LONG bV5YPelsPerMeter; + DWORD bV5ClrUsed; + DWORD bV5ClrImportant; + DWORD bV5RedMask; + DWORD bV5GreenMask; + DWORD bV5BlueMask; + DWORD bV5AlphaMask; + DWORD bV5CSType; + CIEXYZTRIPLE bV5Endpoints; + DWORD bV5GammaRed; + DWORD bV5GammaGreen; + DWORD bV5GammaBlue; + DWORD bV5Intent; + DWORD bV5ProfileData; + DWORD bV5ProfileSize; + DWORD bV5Reserved; + } BITMAPV5HEADER,*LPBITMAPV5HEADER,*PBITMAPV5HEADER; + +//!__TINYC__: #define PROFILE_LINKED 'LINK' +//!__TINYC__: #define PROFILE_EMBEDDED 'MBED' + +#define BI_RGB 0L +#define BI_RLE8 1L +#define BI_RLE4 2L +#define BI_BITFIELDS 3L +#define BI_JPEG 4L +#define BI_PNG 5L + + typedef struct tagBITMAPINFO { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; + } BITMAPINFO,*LPBITMAPINFO,*PBITMAPINFO; + + typedef struct tagBITMAPCOREINFO { + BITMAPCOREHEADER bmciHeader; + RGBTRIPLE bmciColors[1]; + } BITMAPCOREINFO,*LPBITMAPCOREINFO,*PBITMAPCOREINFO; + +#include + typedef struct tagBITMAPFILEHEADER { + WORD bfType; + DWORD bfSize; + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; + } BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER; +#include + +#define MAKEPOINTS(l) (*((POINTS *)&(l))) + +#ifndef NOFONTSIG + typedef struct tagFONTSIGNATURE { + DWORD fsUsb[4]; + DWORD fsCsb[2]; + } FONTSIGNATURE,*PFONTSIGNATURE,*LPFONTSIGNATURE; + + typedef struct tagCHARSETINFO { + UINT ciCharset; + UINT ciACP; + FONTSIGNATURE fs; + } CHARSETINFO,*PCHARSETINFO,*NPCHARSETINFO,*LPCHARSETINFO; + +#define TCI_SRCCHARSET 1 +#define TCI_SRCCODEPAGE 2 +#define TCI_SRCFONTSIG 3 +#define TCI_SRCLOCALE 0x1000 + + typedef struct tagLOCALESIGNATURE { + DWORD lsUsb[4]; + DWORD lsCsbDefault[2]; + DWORD lsCsbSupported[2]; + } LOCALESIGNATURE,*PLOCALESIGNATURE,*LPLOCALESIGNATURE; +#endif + + +#ifndef NOMETAFILE + typedef struct tagHANDLETABLE { + HGDIOBJ objectHandle[1]; + } HANDLETABLE,*PHANDLETABLE,*LPHANDLETABLE; + + typedef struct tagMETARECORD { + DWORD rdSize; + WORD rdFunction; + WORD rdParm[1]; + } METARECORD; + typedef struct tagMETARECORD UNALIGNED *PMETARECORD; + typedef struct tagMETARECORD UNALIGNED *LPMETARECORD; + + typedef struct tagMETAFILEPICT { + LONG mm; + LONG xExt; + LONG yExt; + HMETAFILE hMF; + } METAFILEPICT,*LPMETAFILEPICT; + +#include + typedef struct tagMETAHEADER { + WORD mtType; + WORD mtHeaderSize; + WORD mtVersion; + DWORD mtSize; + WORD mtNoObjects; + DWORD mtMaxRecord; + WORD mtNoParameters; + } METAHEADER; + typedef struct tagMETAHEADER UNALIGNED *PMETAHEADER; + typedef struct tagMETAHEADER UNALIGNED *LPMETAHEADER; + +#include + + typedef struct tagENHMETARECORD { + DWORD iType; + DWORD nSize; + DWORD dParm[1]; + } ENHMETARECORD,*PENHMETARECORD,*LPENHMETARECORD; + + typedef struct tagENHMETAHEADER { + DWORD iType; + DWORD nSize; + RECTL rclBounds; + RECTL rclFrame; + DWORD dSignature; + DWORD nVersion; + DWORD nBytes; + DWORD nRecords; + WORD nHandles; + WORD sReserved; + DWORD nDescription; + DWORD offDescription; + DWORD nPalEntries; + SIZEL szlDevice; + SIZEL szlMillimeters; + DWORD cbPixelFormat; + DWORD offPixelFormat; + DWORD bOpenGL; + SIZEL szlMicrometers; + } ENHMETAHEADER,*PENHMETAHEADER,*LPENHMETAHEADER; +#endif + +#ifndef NOTEXTMETRIC +#define TMPF_FIXED_PITCH 0x01 +#define TMPF_VECTOR 0x02 +#define TMPF_DEVICE 0x08 +#define TMPF_TRUETYPE 0x04 + +#ifdef UNICODE + typedef WCHAR BCHAR; +#else + typedef BYTE BCHAR; +#endif + +#ifndef _TEXTMETRIC_DEFINED +#define _TEXTMETRIC_DEFINED + typedef struct tagTEXTMETRICA { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + BYTE tmFirstChar; + BYTE tmLastChar; + BYTE tmDefaultChar; + BYTE tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + } TEXTMETRICA,*PTEXTMETRICA,*NPTEXTMETRICA,*LPTEXTMETRICA; + + typedef struct tagTEXTMETRICW { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + WCHAR tmFirstChar; + WCHAR tmLastChar; + WCHAR tmDefaultChar; + WCHAR tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + } TEXTMETRICW,*PTEXTMETRICW,*NPTEXTMETRICW,*LPTEXTMETRICW; +#ifdef UNICODE + typedef TEXTMETRICW TEXTMETRIC; + typedef PTEXTMETRICW PTEXTMETRIC; + typedef NPTEXTMETRICW NPTEXTMETRIC; + typedef LPTEXTMETRICW LPTEXTMETRIC; +#else + typedef TEXTMETRICA TEXTMETRIC; + typedef PTEXTMETRICA PTEXTMETRIC; + typedef NPTEXTMETRICA NPTEXTMETRIC; + typedef LPTEXTMETRICA LPTEXTMETRIC; +#endif +#endif + +#define NTM_REGULAR 0x00000040L +#define NTM_BOLD 0x00000020L +#define NTM_ITALIC 0x00000001L + +#define NTM_NONNEGATIVE_AC 0x00010000 +#define NTM_PS_OPENTYPE 0x00020000 +#define NTM_TT_OPENTYPE 0x00040000 +#define NTM_MULTIPLEMASTER 0x00080000 +#define NTM_TYPE1 0x00100000 +#define NTM_DSIG 0x00200000 + +#include + typedef struct tagNEWTEXTMETRICA { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + BYTE tmFirstChar; + BYTE tmLastChar; + BYTE tmDefaultChar; + BYTE tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + DWORD ntmFlags; + UINT ntmSizeEM; + UINT ntmCellHeight; + UINT ntmAvgWidth; + } NEWTEXTMETRICA,*PNEWTEXTMETRICA,*NPNEWTEXTMETRICA,*LPNEWTEXTMETRICA; + + typedef struct tagNEWTEXTMETRICW { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + WCHAR tmFirstChar; + WCHAR tmLastChar; + WCHAR tmDefaultChar; + WCHAR tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + DWORD ntmFlags; + UINT ntmSizeEM; + UINT ntmCellHeight; + UINT ntmAvgWidth; + } NEWTEXTMETRICW,*PNEWTEXTMETRICW,*NPNEWTEXTMETRICW,*LPNEWTEXTMETRICW; +#ifdef UNICODE + typedef NEWTEXTMETRICW NEWTEXTMETRIC; + typedef PNEWTEXTMETRICW PNEWTEXTMETRIC; + typedef NPNEWTEXTMETRICW NPNEWTEXTMETRIC; + typedef LPNEWTEXTMETRICW LPNEWTEXTMETRIC; +#else + typedef NEWTEXTMETRICA NEWTEXTMETRIC; + typedef PNEWTEXTMETRICA PNEWTEXTMETRIC; + typedef NPNEWTEXTMETRICA NPNEWTEXTMETRIC; + typedef LPNEWTEXTMETRICA LPNEWTEXTMETRIC; +#endif +#include + + typedef struct tagNEWTEXTMETRICEXA { + NEWTEXTMETRICA ntmTm; + FONTSIGNATURE ntmFontSig; + } NEWTEXTMETRICEXA; + + typedef struct tagNEWTEXTMETRICEXW { + NEWTEXTMETRICW ntmTm; + FONTSIGNATURE ntmFontSig; + } NEWTEXTMETRICEXW; +#ifdef UNICODE + typedef NEWTEXTMETRICEXW NEWTEXTMETRICEX; +#else + typedef NEWTEXTMETRICEXA NEWTEXTMETRICEX; +#endif +#endif + + typedef struct tagPELARRAY { + LONG paXCount; + LONG paYCount; + LONG paXExt; + LONG paYExt; + BYTE paRGBs; + } PELARRAY,*PPELARRAY,*NPPELARRAY,*LPPELARRAY; + + typedef struct tagLOGBRUSH { + UINT lbStyle; + COLORREF lbColor; + ULONG_PTR lbHatch; + } LOGBRUSH,*PLOGBRUSH,*NPLOGBRUSH,*LPLOGBRUSH; + + typedef struct tagLOGBRUSH32 { + UINT lbStyle; + COLORREF lbColor; + ULONG lbHatch; + } LOGBRUSH32,*PLOGBRUSH32,*NPLOGBRUSH32,*LPLOGBRUSH32; + + typedef LOGBRUSH PATTERN; + typedef PATTERN *PPATTERN; + typedef PATTERN *NPPATTERN; + typedef PATTERN *LPPATTERN; + + typedef struct tagLOGPEN { + UINT lopnStyle; + POINT lopnWidth; + COLORREF lopnColor; + } LOGPEN,*PLOGPEN,*NPLOGPEN,*LPLOGPEN; + + typedef struct tagEXTLOGPEN { + DWORD elpPenStyle; + DWORD elpWidth; + UINT elpBrushStyle; + COLORREF elpColor; + ULONG_PTR elpHatch; + DWORD elpNumEntries; + DWORD elpStyleEntry[1]; + } EXTLOGPEN,*PEXTLOGPEN,*NPEXTLOGPEN,*LPEXTLOGPEN; + +#ifndef _PALETTEENTRY_DEFINED +#define _PALETTEENTRY_DEFINED + typedef struct tagPALETTEENTRY { + BYTE peRed; + BYTE peGreen; + BYTE peBlue; + BYTE peFlags; + } PALETTEENTRY,*PPALETTEENTRY,*LPPALETTEENTRY; +#endif + +#ifndef _LOGPALETTE_DEFINED +#define _LOGPALETTE_DEFINED + + typedef struct tagLOGPALETTE { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[1]; + } LOGPALETTE,*PLOGPALETTE,*NPLOGPALETTE,*LPLOGPALETTE; +#endif + +#define LF_FACESIZE 32 + + typedef struct tagLOGFONTA { + LONG lfHeight; + LONG lfWidth; + LONG lfEscapement; + LONG lfOrientation; + LONG lfWeight; + BYTE lfItalic; + BYTE lfUnderline; + BYTE lfStrikeOut; + BYTE lfCharSet; + BYTE lfOutPrecision; + BYTE lfClipPrecision; + BYTE lfQuality; + BYTE lfPitchAndFamily; + CHAR lfFaceName[LF_FACESIZE]; + } LOGFONTA,*PLOGFONTA,*NPLOGFONTA,*LPLOGFONTA; + + typedef struct tagLOGFONTW { + LONG lfHeight; + LONG lfWidth; + LONG lfEscapement; + LONG lfOrientation; + LONG lfWeight; + BYTE lfItalic; + BYTE lfUnderline; + BYTE lfStrikeOut; + BYTE lfCharSet; + BYTE lfOutPrecision; + BYTE lfClipPrecision; + BYTE lfQuality; + BYTE lfPitchAndFamily; + WCHAR lfFaceName[LF_FACESIZE]; + } LOGFONTW,*PLOGFONTW,*NPLOGFONTW,*LPLOGFONTW; +#ifdef UNICODE + typedef LOGFONTW LOGFONT; + typedef PLOGFONTW PLOGFONT; + typedef NPLOGFONTW NPLOGFONT; + typedef LPLOGFONTW LPLOGFONT; +#else + typedef LOGFONTA LOGFONT; + typedef PLOGFONTA PLOGFONT; + typedef NPLOGFONTA NPLOGFONT; + typedef LPLOGFONTA LPLOGFONT; +#endif + +#define LF_FULLFACESIZE 64 + + typedef struct tagENUMLOGFONTA { + LOGFONTA elfLogFont; + BYTE elfFullName[LF_FULLFACESIZE]; + BYTE elfStyle[LF_FACESIZE]; + } ENUMLOGFONTA,*LPENUMLOGFONTA; + + typedef struct tagENUMLOGFONTW { + LOGFONTW elfLogFont; + WCHAR elfFullName[LF_FULLFACESIZE]; + WCHAR elfStyle[LF_FACESIZE]; + } ENUMLOGFONTW,*LPENUMLOGFONTW; +#ifdef UNICODE + typedef ENUMLOGFONTW ENUMLOGFONT; + typedef LPENUMLOGFONTW LPENUMLOGFONT; +#else + typedef ENUMLOGFONTA ENUMLOGFONT; + typedef LPENUMLOGFONTA LPENUMLOGFONT; +#endif + + typedef struct tagENUMLOGFONTEXA { + LOGFONTA elfLogFont; + BYTE elfFullName[LF_FULLFACESIZE]; + BYTE elfStyle[LF_FACESIZE]; + BYTE elfScript[LF_FACESIZE]; + } ENUMLOGFONTEXA,*LPENUMLOGFONTEXA; + + typedef struct tagENUMLOGFONTEXW { + LOGFONTW elfLogFont; + WCHAR elfFullName[LF_FULLFACESIZE]; + WCHAR elfStyle[LF_FACESIZE]; + WCHAR elfScript[LF_FACESIZE]; + } ENUMLOGFONTEXW,*LPENUMLOGFONTEXW; +#ifdef UNICODE + typedef ENUMLOGFONTEXW ENUMLOGFONTEX; + typedef LPENUMLOGFONTEXW LPENUMLOGFONTEX; +#else + typedef ENUMLOGFONTEXA ENUMLOGFONTEX; + typedef LPENUMLOGFONTEXA LPENUMLOGFONTEX; +#endif + +#define OUT_DEFAULT_PRECIS 0 +#define OUT_STRING_PRECIS 1 +#define OUT_CHARACTER_PRECIS 2 +#define OUT_STROKE_PRECIS 3 +#define OUT_TT_PRECIS 4 +#define OUT_DEVICE_PRECIS 5 +#define OUT_RASTER_PRECIS 6 +#define OUT_TT_ONLY_PRECIS 7 +#define OUT_OUTLINE_PRECIS 8 +#define OUT_SCREEN_OUTLINE_PRECIS 9 +#define OUT_PS_ONLY_PRECIS 10 + +#define CLIP_DEFAULT_PRECIS 0 +#define CLIP_CHARACTER_PRECIS 1 +#define CLIP_STROKE_PRECIS 2 +#define CLIP_MASK 0xf +#define CLIP_LH_ANGLES (1<<4) +#define CLIP_TT_ALWAYS (2<<4) +#define CLIP_DFA_DISABLE (4<<4) +#define CLIP_EMBEDDED (8<<4) + +#define DEFAULT_QUALITY 0 +#define DRAFT_QUALITY 1 +#define PROOF_QUALITY 2 +#define NONANTIALIASED_QUALITY 3 +#define ANTIALIASED_QUALITY 4 + +#define CLEARTYPE_QUALITY 5 +#define CLEARTYPE_NATURAL_QUALITY 6 + +#define DEFAULT_PITCH 0 +#define FIXED_PITCH 1 +#define VARIABLE_PITCH 2 +#define MONO_FONT 8 + +#define ANSI_CHARSET 0 +#define DEFAULT_CHARSET 1 +#define SYMBOL_CHARSET 2 +#define SHIFTJIS_CHARSET 128 +#define HANGEUL_CHARSET 129 +#define HANGUL_CHARSET 129 +#define GB2312_CHARSET 134 +#define CHINESEBIG5_CHARSET 136 +#define OEM_CHARSET 255 +#define JOHAB_CHARSET 130 +#define HEBREW_CHARSET 177 +#define ARABIC_CHARSET 178 +#define GREEK_CHARSET 161 +#define TURKISH_CHARSET 162 +#define VIETNAMESE_CHARSET 163 +#define THAI_CHARSET 222 +#define EASTEUROPE_CHARSET 238 +#define RUSSIAN_CHARSET 204 + +#define MAC_CHARSET 77 +#define BALTIC_CHARSET 186 + +#define FS_LATIN1 0x00000001L +#define FS_LATIN2 0x00000002L +#define FS_CYRILLIC 0x00000004L +#define FS_GREEK 0x00000008L +#define FS_TURKISH 0x00000010L +#define FS_HEBREW 0x00000020L +#define FS_ARABIC 0x00000040L +#define FS_BALTIC 0x00000080L +#define FS_VIETNAMESE 0x00000100L +#define FS_THAI 0x00010000L +#define FS_JISJAPAN 0x00020000L +#define FS_CHINESESIMP 0x00040000L +#define FS_WANSUNG 0x00080000L +#define FS_CHINESETRAD 0x00100000L +#define FS_JOHAB 0x00200000L +#define FS_SYMBOL 0x80000000L + +#define FF_DONTCARE (0<<4) +#define FF_ROMAN (1<<4) + +#define FF_SWISS (2<<4) + +#define FF_MODERN (3<<4) + +#define FF_SCRIPT (4<<4) +#define FF_DECORATIVE (5<<4) + +#define FW_DONTCARE 0 +#define FW_THIN 100 +#define FW_EXTRALIGHT 200 +#define FW_LIGHT 300 +#define FW_NORMAL 400 +#define FW_MEDIUM 500 +#define FW_SEMIBOLD 600 +#define FW_BOLD 700 +#define FW_EXTRABOLD 800 +#define FW_HEAVY 900 + +#define FW_ULTRALIGHT FW_EXTRALIGHT +#define FW_REGULAR FW_NORMAL +#define FW_DEMIBOLD FW_SEMIBOLD +#define FW_ULTRABOLD FW_EXTRABOLD +#define FW_BLACK FW_HEAVY + +#define PANOSE_COUNT 10 +#define PAN_FAMILYTYPE_INDEX 0 +#define PAN_SERIFSTYLE_INDEX 1 +#define PAN_WEIGHT_INDEX 2 +#define PAN_PROPORTION_INDEX 3 +#define PAN_CONTRAST_INDEX 4 +#define PAN_STROKEVARIATION_INDEX 5 +#define PAN_ARMSTYLE_INDEX 6 +#define PAN_LETTERFORM_INDEX 7 +#define PAN_MIDLINE_INDEX 8 +#define PAN_XHEIGHT_INDEX 9 + +#define PAN_CULTURE_LATIN 0 + + typedef struct tagPANOSE { + BYTE bFamilyType; + BYTE bSerifStyle; + BYTE bWeight; + BYTE bProportion; + BYTE bContrast; + BYTE bStrokeVariation; + BYTE bArmStyle; + BYTE bLetterform; + BYTE bMidline; + BYTE bXHeight; + } PANOSE,*LPPANOSE; + +#define PAN_ANY 0 +#define PAN_NO_FIT 1 + +#define PAN_FAMILY_TEXT_DISPLAY 2 +#define PAN_FAMILY_SCRIPT 3 +#define PAN_FAMILY_DECORATIVE 4 +#define PAN_FAMILY_PICTORIAL 5 + +#define PAN_SERIF_COVE 2 +#define PAN_SERIF_OBTUSE_COVE 3 +#define PAN_SERIF_SQUARE_COVE 4 +#define PAN_SERIF_OBTUSE_SQUARE_COVE 5 +#define PAN_SERIF_SQUARE 6 +#define PAN_SERIF_THIN 7 +#define PAN_SERIF_BONE 8 +#define PAN_SERIF_EXAGGERATED 9 +#define PAN_SERIF_TRIANGLE 10 +#define PAN_SERIF_NORMAL_SANS 11 +#define PAN_SERIF_OBTUSE_SANS 12 +#define PAN_SERIF_PERP_SANS 13 +#define PAN_SERIF_FLARED 14 +#define PAN_SERIF_ROUNDED 15 + +#define PAN_WEIGHT_VERY_LIGHT 2 +#define PAN_WEIGHT_LIGHT 3 +#define PAN_WEIGHT_THIN 4 +#define PAN_WEIGHT_BOOK 5 +#define PAN_WEIGHT_MEDIUM 6 +#define PAN_WEIGHT_DEMI 7 +#define PAN_WEIGHT_BOLD 8 +#define PAN_WEIGHT_HEAVY 9 +#define PAN_WEIGHT_BLACK 10 +#define PAN_WEIGHT_NORD 11 + +#define PAN_PROP_OLD_STYLE 2 +#define PAN_PROP_MODERN 3 +#define PAN_PROP_EVEN_WIDTH 4 +#define PAN_PROP_EXPANDED 5 +#define PAN_PROP_CONDENSED 6 +#define PAN_PROP_VERY_EXPANDED 7 +#define PAN_PROP_VERY_CONDENSED 8 +#define PAN_PROP_MONOSPACED 9 + +#define PAN_CONTRAST_NONE 2 +#define PAN_CONTRAST_VERY_LOW 3 +#define PAN_CONTRAST_LOW 4 +#define PAN_CONTRAST_MEDIUM_LOW 5 +#define PAN_CONTRAST_MEDIUM 6 +#define PAN_CONTRAST_MEDIUM_HIGH 7 +#define PAN_CONTRAST_HIGH 8 +#define PAN_CONTRAST_VERY_HIGH 9 + +#define PAN_STROKE_GRADUAL_DIAG 2 +#define PAN_STROKE_GRADUAL_TRAN 3 +#define PAN_STROKE_GRADUAL_VERT 4 +#define PAN_STROKE_GRADUAL_HORZ 5 +#define PAN_STROKE_RAPID_VERT 6 +#define PAN_STROKE_RAPID_HORZ 7 +#define PAN_STROKE_INSTANT_VERT 8 + +#define PAN_STRAIGHT_ARMS_HORZ 2 +#define PAN_STRAIGHT_ARMS_WEDGE 3 +#define PAN_STRAIGHT_ARMS_VERT 4 +#define PAN_STRAIGHT_ARMS_SINGLE_SERIF 5 +#define PAN_STRAIGHT_ARMS_DOUBLE_SERIF 6 +#define PAN_BENT_ARMS_HORZ 7 +#define PAN_BENT_ARMS_WEDGE 8 +#define PAN_BENT_ARMS_VERT 9 +#define PAN_BENT_ARMS_SINGLE_SERIF 10 +#define PAN_BENT_ARMS_DOUBLE_SERIF 11 + +#define PAN_LETT_NORMAL_CONTACT 2 +#define PAN_LETT_NORMAL_WEIGHTED 3 +#define PAN_LETT_NORMAL_BOXED 4 +#define PAN_LETT_NORMAL_FLATTENED 5 +#define PAN_LETT_NORMAL_ROUNDED 6 +#define PAN_LETT_NORMAL_OFF_CENTER 7 +#define PAN_LETT_NORMAL_SQUARE 8 +#define PAN_LETT_OBLIQUE_CONTACT 9 +#define PAN_LETT_OBLIQUE_WEIGHTED 10 +#define PAN_LETT_OBLIQUE_BOXED 11 +#define PAN_LETT_OBLIQUE_FLATTENED 12 +#define PAN_LETT_OBLIQUE_ROUNDED 13 +#define PAN_LETT_OBLIQUE_OFF_CENTER 14 +#define PAN_LETT_OBLIQUE_SQUARE 15 + +#define PAN_MIDLINE_STANDARD_TRIMMED 2 +#define PAN_MIDLINE_STANDARD_POINTED 3 +#define PAN_MIDLINE_STANDARD_SERIFED 4 +#define PAN_MIDLINE_HIGH_TRIMMED 5 +#define PAN_MIDLINE_HIGH_POINTED 6 +#define PAN_MIDLINE_HIGH_SERIFED 7 +#define PAN_MIDLINE_CONSTANT_TRIMMED 8 +#define PAN_MIDLINE_CONSTANT_POINTED 9 +#define PAN_MIDLINE_CONSTANT_SERIFED 10 +#define PAN_MIDLINE_LOW_TRIMMED 11 +#define PAN_MIDLINE_LOW_POINTED 12 +#define PAN_MIDLINE_LOW_SERIFED 13 + +#define PAN_XHEIGHT_CONSTANT_SMALL 2 +#define PAN_XHEIGHT_CONSTANT_STD 3 +#define PAN_XHEIGHT_CONSTANT_LARGE 4 +#define PAN_XHEIGHT_DUCKING_SMALL 5 +#define PAN_XHEIGHT_DUCKING_STD 6 +#define PAN_XHEIGHT_DUCKING_LARGE 7 + +#define ELF_VENDOR_SIZE 4 + + typedef struct tagEXTLOGFONTA { + LOGFONTA elfLogFont; + BYTE elfFullName[LF_FULLFACESIZE]; + BYTE elfStyle[LF_FACESIZE]; + DWORD elfVersion; + DWORD elfStyleSize; + DWORD elfMatch; + DWORD elfReserved; + BYTE elfVendorId[ELF_VENDOR_SIZE]; + DWORD elfCulture; + PANOSE elfPanose; + } EXTLOGFONTA,*PEXTLOGFONTA,*NPEXTLOGFONTA,*LPEXTLOGFONTA; + + typedef struct tagEXTLOGFONTW { + LOGFONTW elfLogFont; + WCHAR elfFullName[LF_FULLFACESIZE]; + WCHAR elfStyle[LF_FACESIZE]; + DWORD elfVersion; + DWORD elfStyleSize; + DWORD elfMatch; + DWORD elfReserved; + BYTE elfVendorId[ELF_VENDOR_SIZE]; + DWORD elfCulture; + PANOSE elfPanose; + } EXTLOGFONTW,*PEXTLOGFONTW,*NPEXTLOGFONTW,*LPEXTLOGFONTW; +#ifdef UNICODE + typedef EXTLOGFONTW EXTLOGFONT; + typedef PEXTLOGFONTW PEXTLOGFONT; + typedef NPEXTLOGFONTW NPEXTLOGFONT; + typedef LPEXTLOGFONTW LPEXTLOGFONT; +#else + typedef EXTLOGFONTA EXTLOGFONT; + typedef PEXTLOGFONTA PEXTLOGFONT; + typedef NPEXTLOGFONTA NPEXTLOGFONT; + typedef LPEXTLOGFONTA LPEXTLOGFONT; +#endif + +#define ELF_VERSION 0 +#define ELF_CULTURE_LATIN 0 + +#define RASTER_FONTTYPE 0x0001 +#define DEVICE_FONTTYPE 0x002 +#define TRUETYPE_FONTTYPE 0x004 + +#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) +#define PALETTERGB(r,g,b) (0x02000000 | RGB(r,g,b)) +#define PALETTEINDEX(i) ((COLORREF)(0x01000000 | (DWORD)(WORD)(i))) + +#define PC_RESERVED 0x01 +#define PC_EXPLICIT 0x02 +#define PC_NOCOLLAPSE 0x04 + +#define GetRValue(rgb) (LOBYTE(rgb)) +#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8)) +#define GetBValue(rgb) (LOBYTE((rgb)>>16)) + +#define TRANSPARENT 1 +#define OPAQUE 2 +#define BKMODE_LAST 2 + +#define GM_COMPATIBLE 1 +#define GM_ADVANCED 2 +#define GM_LAST 2 + +#define PT_CLOSEFIGURE 0x01 +#define PT_LINETO 0x02 +#define PT_BEZIERTO 0x04 +#define PT_MOVETO 0x06 + +#define MM_TEXT 1 +#define MM_LOMETRIC 2 +#define MM_HIMETRIC 3 +#define MM_LOENGLISH 4 +#define MM_HIENGLISH 5 +#define MM_TWIPS 6 +#define MM_ISOTROPIC 7 +#define MM_ANISOTROPIC 8 + +#define MM_MIN MM_TEXT +#define MM_MAX MM_ANISOTROPIC +#define MM_MAX_FIXEDSCALE MM_TWIPS + +#define ABSOLUTE 1 +#define RELATIVE 2 + +#define WHITE_BRUSH 0 +#define LTGRAY_BRUSH 1 +#define GRAY_BRUSH 2 +#define DKGRAY_BRUSH 3 +#define BLACK_BRUSH 4 +#define NULL_BRUSH 5 +#define HOLLOW_BRUSH NULL_BRUSH +#define WHITE_PEN 6 +#define BLACK_PEN 7 +#define NULL_PEN 8 +#define OEM_FIXED_FONT 10 +#define ANSI_FIXED_FONT 11 +#define ANSI_VAR_FONT 12 +#define SYSTEM_FONT 13 +#define DEVICE_DEFAULT_FONT 14 +#define DEFAULT_PALETTE 15 +#define SYSTEM_FIXED_FONT 16 + +#define DEFAULT_GUI_FONT 17 + +#define DC_BRUSH 18 +#define DC_PEN 19 + +#define STOCK_LAST 19 + +#define CLR_INVALID 0xFFFFFFFF + +#define BS_SOLID 0 +#define BS_NULL 1 +#define BS_HOLLOW BS_NULL +#define BS_HATCHED 2 +#define BS_PATTERN 3 +#define BS_INDEXED 4 +#define BS_DIBPATTERN 5 +#define BS_DIBPATTERNPT 6 +#define BS_PATTERN8X8 7 +#define BS_DIBPATTERN8X8 8 +#define BS_MONOPATTERN 9 + +#define HS_HORIZONTAL 0 +#define HS_VERTICAL 1 +#define HS_FDIAGONAL 2 +#define HS_BDIAGONAL 3 +#define HS_CROSS 4 +#define HS_DIAGCROSS 5 + +#define PS_SOLID 0 +#define PS_DASH 1 +#define PS_DOT 2 +#define PS_DASHDOT 3 +#define PS_DASHDOTDOT 4 +#define PS_NULL 5 +#define PS_INSIDEFRAME 6 +#define PS_USERSTYLE 7 +#define PS_ALTERNATE 8 +#define PS_STYLE_MASK 0x0000000F + +#define PS_ENDCAP_ROUND 0x00000000 +#define PS_ENDCAP_SQUARE 0x00000100 +#define PS_ENDCAP_FLAT 0x00000200 +#define PS_ENDCAP_MASK 0x00000F00 + +#define PS_JOIN_ROUND 0x00000000 +#define PS_JOIN_BEVEL 0x00001000 +#define PS_JOIN_MITER 0x00002000 +#define PS_JOIN_MASK 0x0000F000 + +#define PS_COSMETIC 0x00000000 +#define PS_GEOMETRIC 0x00010000 +#define PS_TYPE_MASK 0x000F0000 + +#define AD_COUNTERCLOCKWISE 1 +#define AD_CLOCKWISE 2 + +#define DRIVERVERSION 0 +#define TECHNOLOGY 2 +#define HORZSIZE 4 +#define VERTSIZE 6 +#define HORZRES 8 +#define VERTRES 10 +#define BITSPIXEL 12 +#define PLANES 14 +#define NUMBRUSHES 16 +#define NUMPENS 18 +#define NUMMARKERS 20 +#define NUMFONTS 22 +#define NUMCOLORS 24 +#define PDEVICESIZE 26 +#define CURVECAPS 28 +#define LINECAPS 30 +#define POLYGONALCAPS 32 +#define TEXTCAPS 34 +#define CLIPCAPS 36 +#define RASTERCAPS 38 +#define ASPECTX 40 +#define ASPECTY 42 +#define ASPECTXY 44 + +#define LOGPIXELSX 88 +#define LOGPIXELSY 90 + +#define SIZEPALETTE 104 +#define NUMRESERVED 106 +#define COLORRES 108 + +#define PHYSICALWIDTH 110 +#define PHYSICALHEIGHT 111 +#define PHYSICALOFFSETX 112 +#define PHYSICALOFFSETY 113 +#define SCALINGFACTORX 114 +#define SCALINGFACTORY 115 + +#define VREFRESH 116 + +#define DESKTOPVERTRES 117 + +#define DESKTOPHORZRES 118 + +#define BLTALIGNMENT 119 + +#define SHADEBLENDCAPS 120 +#define COLORMGMTCAPS 121 + +#ifndef NOGDICAPMASKS +#define DT_PLOTTER 0 +#define DT_RASDISPLAY 1 +#define DT_RASPRINTER 2 +#define DT_RASCAMERA 3 +#define DT_CHARSTREAM 4 +#define DT_METAFILE 5 +#define DT_DISPFILE 6 + +#define CC_NONE 0 +#define CC_CIRCLES 1 +#define CC_PIE 2 +#define CC_CHORD 4 +#define CC_ELLIPSES 8 +#define CC_WIDE 16 +#define CC_STYLED 32 +#define CC_WIDESTYLED 64 +#define CC_INTERIORS 128 +#define CC_ROUNDRECT 256 + +#define LC_NONE 0 +#define LC_POLYLINE 2 +#define LC_MARKER 4 +#define LC_POLYMARKER 8 +#define LC_WIDE 16 +#define LC_STYLED 32 +#define LC_WIDESTYLED 64 +#define LC_INTERIORS 128 + +#define PC_NONE 0 +#define PC_POLYGON 1 +#define PC_RECTANGLE 2 +#define PC_WINDPOLYGON 4 +#define PC_TRAPEZOID 4 +#define PC_SCANLINE 8 +#define PC_WIDE 16 +#define PC_STYLED 32 +#define PC_WIDESTYLED 64 +#define PC_INTERIORS 128 +#define PC_POLYPOLYGON 256 +#define PC_PATHS 512 + +#define CP_NONE 0 +#define CP_RECTANGLE 1 +#define CP_REGION 2 + +#define TC_OP_CHARACTER 0x00000001 +#define TC_OP_STROKE 0x00000002 +#define TC_CP_STROKE 0x00000004 +#define TC_CR_90 0x00000008 +#define TC_CR_ANY 0x00000010 +#define TC_SF_X_YINDEP 0x00000020 +#define TC_SA_DOUBLE 0x00000040 +#define TC_SA_INTEGER 0x00000080 +#define TC_SA_CONTIN 0x00000100 +#define TC_EA_DOUBLE 0x00000200 +#define TC_IA_ABLE 0x00000400 +#define TC_UA_ABLE 0x00000800 +#define TC_SO_ABLE 0x00001000 +#define TC_RA_ABLE 0x00002000 +#define TC_VA_ABLE 0x00004000 +#define TC_RESERVED 0x00008000 +#define TC_SCROLLBLT 0x00010000 +#endif + +#define RC_NONE +#define RC_BITBLT 1 +#define RC_BANDING 2 +#define RC_SCALING 4 +#define RC_BITMAP64 8 +#define RC_GDI20_OUTPUT 0x0010 +#define RC_GDI20_STATE 0x0020 +#define RC_SAVEBITMAP 0x0040 +#define RC_DI_BITMAP 0x0080 +#define RC_PALETTE 0x0100 +#define RC_DIBTODEV 0x0200 +#define RC_BIGFONT 0x0400 +#define RC_STRETCHBLT 0x0800 +#define RC_FLOODFILL 0x1000 +#define RC_STRETCHDIB 0x2000 +#define RC_OP_DX_OUTPUT 0x4000 +#define RC_DEVBITS 0x8000 + +#define SB_NONE 0x00000000 +#define SB_CONST_ALPHA 0x00000001 +#define SB_PIXEL_ALPHA 0x00000002 +#define SB_PREMULT_ALPHA 0x00000004 + +#define SB_GRAD_RECT 0x00000010 +#define SB_GRAD_TRI 0x00000020 + +#define CM_NONE 0x00000000 +#define CM_DEVICE_ICM 0x00000001 +#define CM_GAMMA_RAMP 0x00000002 +#define CM_CMYK_COLOR 0x00000004 + +#define DIB_RGB_COLORS 0 +#define DIB_PAL_COLORS 1 + +#define SYSPAL_ERROR 0 +#define SYSPAL_STATIC 1 +#define SYSPAL_NOSTATIC 2 +#define SYSPAL_NOSTATIC256 3 + +#define CBM_INIT 0x04L + +#define FLOODFILLBORDER 0 +#define FLOODFILLSURFACE 1 + +#define CCHDEVICENAME 32 + +#define CCHFORMNAME 32 + + typedef struct _devicemodeA { + BYTE dmDeviceName[CCHDEVICENAME]; + WORD dmSpecVersion; + WORD dmDriverVersion; + WORD dmSize; + WORD dmDriverExtra; + DWORD dmFields; + union { + struct { + short dmOrientation; + short dmPaperSize; + short dmPaperLength; + short dmPaperWidth; + short dmScale; + short dmCopies; + short dmDefaultSource; + short dmPrintQuality; + }; + struct { + POINTL dmPosition; + DWORD dmDisplayOrientation; + DWORD dmDisplayFixedOutput; + }; + }; + short dmColor; + short dmDuplex; + short dmYResolution; + short dmTTOption; + short dmCollate; + BYTE dmFormName[CCHFORMNAME]; + WORD dmLogPixels; + DWORD dmBitsPerPel; + DWORD dmPelsWidth; + DWORD dmPelsHeight; + union { + DWORD dmDisplayFlags; + DWORD dmNup; + }; + DWORD dmDisplayFrequency; + DWORD dmICMMethod; + DWORD dmICMIntent; + DWORD dmMediaType; + DWORD dmDitherType; + DWORD dmReserved1; + DWORD dmReserved2; + DWORD dmPanningWidth; + DWORD dmPanningHeight; + } DEVMODEA,*PDEVMODEA,*NPDEVMODEA,*LPDEVMODEA; + + typedef struct _devicemodeW { + WCHAR dmDeviceName[CCHDEVICENAME]; + WORD dmSpecVersion; + WORD dmDriverVersion; + WORD dmSize; + WORD dmDriverExtra; + DWORD dmFields; + union { + struct { + short dmOrientation; + short dmPaperSize; + short dmPaperLength; + short dmPaperWidth; + short dmScale; + short dmCopies; + short dmDefaultSource; + short dmPrintQuality; + }; + struct { + POINTL dmPosition; + DWORD dmDisplayOrientation; + DWORD dmDisplayFixedOutput; + }; + }; + short dmColor; + short dmDuplex; + short dmYResolution; + short dmTTOption; + short dmCollate; + WCHAR dmFormName[CCHFORMNAME]; + WORD dmLogPixels; + DWORD dmBitsPerPel; + DWORD dmPelsWidth; + DWORD dmPelsHeight; + union { + DWORD dmDisplayFlags; + DWORD dmNup; + }; + DWORD dmDisplayFrequency; + DWORD dmICMMethod; + DWORD dmICMIntent; + DWORD dmMediaType; + DWORD dmDitherType; + DWORD dmReserved1; + DWORD dmReserved2; + DWORD dmPanningWidth; + DWORD dmPanningHeight; + } DEVMODEW,*PDEVMODEW,*NPDEVMODEW,*LPDEVMODEW; +#ifdef UNICODE + typedef DEVMODEW DEVMODE; + typedef PDEVMODEW PDEVMODE; + typedef NPDEVMODEW NPDEVMODE; + typedef LPDEVMODEW LPDEVMODE; +#else + typedef DEVMODEA DEVMODE; + typedef PDEVMODEA PDEVMODE; + typedef NPDEVMODEA NPDEVMODE; + typedef LPDEVMODEA LPDEVMODE; +#endif + +#define DM_SPECVERSION 0x0401 + +#define DM_ORIENTATION 0x00000001L +#define DM_PAPERSIZE 0x00000002L +#define DM_PAPERLENGTH 0x00000004L +#define DM_PAPERWIDTH 0x00000008L +#define DM_SCALE 0x00000010L +#define DM_POSITION 0x00000020L +#define DM_NUP 0x00000040L +#define DM_DISPLAYORIENTATION 0x00000080L +#define DM_COPIES 0x00000100L +#define DM_DEFAULTSOURCE 0x00000200L +#define DM_PRINTQUALITY 0x00000400L +#define DM_COLOR 0x00000800L +#define DM_DUPLEX 0x00001000L +#define DM_YRESOLUTION 0x00002000L +#define DM_TTOPTION 0x00004000L +#define DM_COLLATE 0x00008000L +#define DM_FORMNAME 0x00010000L +#define DM_LOGPIXELS 0x00020000L +#define DM_BITSPERPEL 0x00040000L +#define DM_PELSWIDTH 0x00080000L +#define DM_PELSHEIGHT 0x00100000L +#define DM_DISPLAYFLAGS 0x00200000L +#define DM_DISPLAYFREQUENCY 0x00400000L +#define DM_ICMMETHOD 0x00800000L +#define DM_ICMINTENT 0x01000000L +#define DM_MEDIATYPE 0x02000000L +#define DM_DITHERTYPE 0x04000000L +#define DM_PANNINGWIDTH 0x08000000L +#define DM_PANNINGHEIGHT 0x10000000L +#define DM_DISPLAYFIXEDOUTPUT 0x20000000L + +#define DMORIENT_PORTRAIT 1 +#define DMORIENT_LANDSCAPE 2 + +#define DMPAPER_FIRST DMPAPER_LETTER +#define DMPAPER_LETTER 1 +#define DMPAPER_LETTERSMALL 2 +#define DMPAPER_TABLOID 3 +#define DMPAPER_LEDGER 4 +#define DMPAPER_LEGAL 5 +#define DMPAPER_STATEMENT 6 +#define DMPAPER_EXECUTIVE 7 +#define DMPAPER_A3 8 +#define DMPAPER_A4 9 +#define DMPAPER_A4SMALL 10 +#define DMPAPER_A5 11 +#define DMPAPER_B4 12 +#define DMPAPER_B5 13 +#define DMPAPER_FOLIO 14 +#define DMPAPER_QUARTO 15 +#define DMPAPER_10X14 16 +#define DMPAPER_11X17 17 +#define DMPAPER_NOTE 18 +#define DMPAPER_ENV_9 19 +#define DMPAPER_ENV_10 20 +#define DMPAPER_ENV_11 21 +#define DMPAPER_ENV_12 22 +#define DMPAPER_ENV_14 23 +#define DMPAPER_CSHEET 24 +#define DMPAPER_DSHEET 25 +#define DMPAPER_ESHEET 26 +#define DMPAPER_ENV_DL 27 +#define DMPAPER_ENV_C5 28 +#define DMPAPER_ENV_C3 29 +#define DMPAPER_ENV_C4 30 +#define DMPAPER_ENV_C6 31 +#define DMPAPER_ENV_C65 32 +#define DMPAPER_ENV_B4 33 +#define DMPAPER_ENV_B5 34 +#define DMPAPER_ENV_B6 35 +#define DMPAPER_ENV_ITALY 36 +#define DMPAPER_ENV_MONARCH 37 +#define DMPAPER_ENV_PERSONAL 38 +#define DMPAPER_FANFOLD_US 39 +#define DMPAPER_FANFOLD_STD_GERMAN 40 +#define DMPAPER_FANFOLD_LGL_GERMAN 41 +#define DMPAPER_ISO_B4 42 +#define DMPAPER_JAPANESE_POSTCARD 43 +#define DMPAPER_9X11 44 +#define DMPAPER_10X11 45 +#define DMPAPER_15X11 46 +#define DMPAPER_ENV_INVITE 47 +#define DMPAPER_RESERVED_48 48 +#define DMPAPER_RESERVED_49 49 +#define DMPAPER_LETTER_EXTRA 50 +#define DMPAPER_LEGAL_EXTRA 51 +#define DMPAPER_TABLOID_EXTRA 52 +#define DMPAPER_A4_EXTRA 53 +#define DMPAPER_LETTER_TRANSVERSE 54 +#define DMPAPER_A4_TRANSVERSE 55 +#define DMPAPER_LETTER_EXTRA_TRANSVERSE 56 +#define DMPAPER_A_PLUS 57 +#define DMPAPER_B_PLUS 58 +#define DMPAPER_LETTER_PLUS 59 +#define DMPAPER_A4_PLUS 60 +#define DMPAPER_A5_TRANSVERSE 61 +#define DMPAPER_B5_TRANSVERSE 62 +#define DMPAPER_A3_EXTRA 63 +#define DMPAPER_A5_EXTRA 64 +#define DMPAPER_B5_EXTRA 65 +#define DMPAPER_A2 66 +#define DMPAPER_A3_TRANSVERSE 67 +#define DMPAPER_A3_EXTRA_TRANSVERSE 68 +#define DMPAPER_DBL_JAPANESE_POSTCARD 69 +#define DMPAPER_A6 70 +#define DMPAPER_JENV_KAKU2 71 +#define DMPAPER_JENV_KAKU3 72 +#define DMPAPER_JENV_CHOU3 73 +#define DMPAPER_JENV_CHOU4 74 +#define DMPAPER_LETTER_ROTATED 75 +#define DMPAPER_A3_ROTATED 76 +#define DMPAPER_A4_ROTATED 77 +#define DMPAPER_A5_ROTATED 78 +#define DMPAPER_B4_JIS_ROTATED 79 +#define DMPAPER_B5_JIS_ROTATED 80 +#define DMPAPER_JAPANESE_POSTCARD_ROTATED 81 +#define DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED 82 +#define DMPAPER_A6_ROTATED 83 +#define DMPAPER_JENV_KAKU2_ROTATED 84 +#define DMPAPER_JENV_KAKU3_ROTATED 85 +#define DMPAPER_JENV_CHOU3_ROTATED 86 +#define DMPAPER_JENV_CHOU4_ROTATED 87 +#define DMPAPER_B6_JIS 88 +#define DMPAPER_B6_JIS_ROTATED 89 +#define DMPAPER_12X11 90 +#define DMPAPER_JENV_YOU4 91 +#define DMPAPER_JENV_YOU4_ROTATED 92 +#define DMPAPER_P16K 93 +#define DMPAPER_P32K 94 +#define DMPAPER_P32KBIG 95 +#define DMPAPER_PENV_1 96 +#define DMPAPER_PENV_2 97 +#define DMPAPER_PENV_3 98 +#define DMPAPER_PENV_4 99 +#define DMPAPER_PENV_5 100 +#define DMPAPER_PENV_6 101 +#define DMPAPER_PENV_7 102 +#define DMPAPER_PENV_8 103 +#define DMPAPER_PENV_9 104 +#define DMPAPER_PENV_10 105 +#define DMPAPER_P16K_ROTATED 106 +#define DMPAPER_P32K_ROTATED 107 +#define DMPAPER_P32KBIG_ROTATED 108 +#define DMPAPER_PENV_1_ROTATED 109 +#define DMPAPER_PENV_2_ROTATED 110 +#define DMPAPER_PENV_3_ROTATED 111 +#define DMPAPER_PENV_4_ROTATED 112 +#define DMPAPER_PENV_5_ROTATED 113 +#define DMPAPER_PENV_6_ROTATED 114 +#define DMPAPER_PENV_7_ROTATED 115 +#define DMPAPER_PENV_8_ROTATED 116 +#define DMPAPER_PENV_9_ROTATED 117 +#define DMPAPER_PENV_10_ROTATED 118 + +#define DMPAPER_LAST DMPAPER_PENV_10_ROTATED + +#define DMPAPER_USER 256 + +#define DMBIN_FIRST DMBIN_UPPER +#define DMBIN_UPPER 1 +#define DMBIN_ONLYONE 1 +#define DMBIN_LOWER 2 +#define DMBIN_MIDDLE 3 +#define DMBIN_MANUAL 4 +#define DMBIN_ENVELOPE 5 +#define DMBIN_ENVMANUAL 6 +#define DMBIN_AUTO 7 +#define DMBIN_TRACTOR 8 +#define DMBIN_SMALLFMT 9 +#define DMBIN_LARGEFMT 10 +#define DMBIN_LARGECAPACITY 11 +#define DMBIN_CASSETTE 14 +#define DMBIN_FORMSOURCE 15 +#define DMBIN_LAST DMBIN_FORMSOURCE + +#define DMBIN_USER 256 + +#define DMRES_DRAFT (-1) +#define DMRES_LOW (-2) +#define DMRES_MEDIUM (-3) +#define DMRES_HIGH (-4) + +#define DMCOLOR_MONOCHROME 1 +#define DMCOLOR_COLOR 2 + +#define DMDUP_SIMPLEX 1 +#define DMDUP_VERTICAL 2 +#define DMDUP_HORIZONTAL 3 + +#define DMTT_BITMAP 1 +#define DMTT_DOWNLOAD 2 +#define DMTT_SUBDEV 3 +#define DMTT_DOWNLOAD_OUTLINE 4 + +#define DMCOLLATE_FALSE 0 +#define DMCOLLATE_TRUE 1 + +#define DMDO_DEFAULT 0 +#define DMDO_90 1 +#define DMDO_180 2 +#define DMDO_270 3 + +#define DMDFO_DEFAULT 0 +#define DMDFO_STRETCH 1 +#define DMDFO_CENTER 2 + +#define DMDISPLAYFLAGS_TEXTMODE 0x00000004 + +#define DMNUP_SYSTEM 1 +#define DMNUP_ONEUP 2 + +#define DMICMMETHOD_NONE 1 +#define DMICMMETHOD_SYSTEM 2 +#define DMICMMETHOD_DRIVER 3 +#define DMICMMETHOD_DEVICE 4 + +#define DMICMMETHOD_USER 256 + +#define DMICM_SATURATE 1 +#define DMICM_CONTRAST 2 +#define DMICM_COLORIMETRIC 3 +#define DMICM_ABS_COLORIMETRIC 4 + +#define DMICM_USER 256 + +#define DMMEDIA_STANDARD 1 +#define DMMEDIA_TRANSPARENCY 2 +#define DMMEDIA_GLOSSY 3 + +#define DMMEDIA_USER 256 + +#define DMDITHER_NONE 1 +#define DMDITHER_COARSE 2 +#define DMDITHER_FINE 3 +#define DMDITHER_LINEART 4 +#define DMDITHER_ERRORDIFFUSION 5 +#define DMDITHER_RESERVED6 6 +#define DMDITHER_RESERVED7 7 +#define DMDITHER_RESERVED8 8 +#define DMDITHER_RESERVED9 9 +#define DMDITHER_GRAYSCALE 10 + +#define DMDITHER_USER 256 + + typedef struct _DISPLAY_DEVICEA { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD StateFlags; + CHAR DeviceID[128]; + CHAR DeviceKey[128]; + } DISPLAY_DEVICEA,*PDISPLAY_DEVICEA,*LPDISPLAY_DEVICEA; + typedef struct _DISPLAY_DEVICEW { + DWORD cb; + WCHAR DeviceName[32]; + WCHAR DeviceString[128]; + DWORD StateFlags; + WCHAR DeviceID[128]; + WCHAR DeviceKey[128]; + } DISPLAY_DEVICEW,*PDISPLAY_DEVICEW,*LPDISPLAY_DEVICEW; +#ifdef UNICODE + typedef DISPLAY_DEVICEW DISPLAY_DEVICE; + typedef PDISPLAY_DEVICEW PDISPLAY_DEVICE; + typedef LPDISPLAY_DEVICEW LPDISPLAY_DEVICE; +#else + typedef DISPLAY_DEVICEA DISPLAY_DEVICE; + typedef PDISPLAY_DEVICEA PDISPLAY_DEVICE; + typedef LPDISPLAY_DEVICEA LPDISPLAY_DEVICE; +#endif + +#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 +#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002 +#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 +#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 +#define DISPLAY_DEVICE_VGA_COMPATIBLE 0x00000010 +#define DISPLAY_DEVICE_REMOVABLE 0x00000020 +#define DISPLAY_DEVICE_MODESPRUNED 0x08000000 +#define DISPLAY_DEVICE_REMOTE 0x04000000 +#define DISPLAY_DEVICE_DISCONNECT 0x02000000 + +#define DISPLAY_DEVICE_ACTIVE 0x00000001 +#define DISPLAY_DEVICE_ATTACHED 0x00000002 + +#define RDH_RECTANGLES 1 + + typedef struct _RGNDATAHEADER { + DWORD dwSize; + DWORD iType; + DWORD nCount; + DWORD nRgnSize; + RECT rcBound; + } RGNDATAHEADER,*PRGNDATAHEADER; + + typedef struct _RGNDATA { + RGNDATAHEADER rdh; + char Buffer[1]; + } RGNDATA,*PRGNDATA,*NPRGNDATA,*LPRGNDATA; + +#define SYSRGN 4 + + typedef struct _ABC { + int abcA; + UINT abcB; + int abcC; + } ABC,*PABC,*NPABC,*LPABC; + + typedef struct _ABCFLOAT { + FLOAT abcfA; + FLOAT abcfB; + FLOAT abcfC; + } ABCFLOAT,*PABCFLOAT,*NPABCFLOAT,*LPABCFLOAT; + +#ifndef NOTEXTMETRIC + + typedef struct _OUTLINETEXTMETRICA { + UINT otmSize; + TEXTMETRICA otmTextMetrics; + BYTE otmFiller; + PANOSE otmPanoseNumber; + UINT otmfsSelection; + UINT otmfsType; + int otmsCharSlopeRise; + int otmsCharSlopeRun; + int otmItalicAngle; + UINT otmEMSquare; + int otmAscent; + int otmDescent; + UINT otmLineGap; + UINT otmsCapEmHeight; + UINT otmsXHeight; + RECT otmrcFontBox; + int otmMacAscent; + int otmMacDescent; + UINT otmMacLineGap; + UINT otmusMinimumPPEM; + POINT otmptSubscriptSize; + POINT otmptSubscriptOffset; + POINT otmptSuperscriptSize; + POINT otmptSuperscriptOffset; + UINT otmsStrikeoutSize; + int otmsStrikeoutPosition; + int otmsUnderscoreSize; + int otmsUnderscorePosition; + PSTR otmpFamilyName; + PSTR otmpFaceName; + PSTR otmpStyleName; + PSTR otmpFullName; + } OUTLINETEXTMETRICA,*POUTLINETEXTMETRICA,*NPOUTLINETEXTMETRICA,*LPOUTLINETEXTMETRICA; + + typedef struct _OUTLINETEXTMETRICW { + UINT otmSize; + TEXTMETRICW otmTextMetrics; + BYTE otmFiller; + PANOSE otmPanoseNumber; + UINT otmfsSelection; + UINT otmfsType; + int otmsCharSlopeRise; + int otmsCharSlopeRun; + int otmItalicAngle; + UINT otmEMSquare; + int otmAscent; + int otmDescent; + UINT otmLineGap; + UINT otmsCapEmHeight; + UINT otmsXHeight; + RECT otmrcFontBox; + int otmMacAscent; + int otmMacDescent; + UINT otmMacLineGap; + UINT otmusMinimumPPEM; + POINT otmptSubscriptSize; + POINT otmptSubscriptOffset; + POINT otmptSuperscriptSize; + POINT otmptSuperscriptOffset; + UINT otmsStrikeoutSize; + int otmsStrikeoutPosition; + int otmsUnderscoreSize; + int otmsUnderscorePosition; + PSTR otmpFamilyName; + PSTR otmpFaceName; + PSTR otmpStyleName; + PSTR otmpFullName; + } OUTLINETEXTMETRICW,*POUTLINETEXTMETRICW,*NPOUTLINETEXTMETRICW,*LPOUTLINETEXTMETRICW; +#ifdef UNICODE + typedef OUTLINETEXTMETRICW OUTLINETEXTMETRIC; + typedef POUTLINETEXTMETRICW POUTLINETEXTMETRIC; + typedef NPOUTLINETEXTMETRICW NPOUTLINETEXTMETRIC; + typedef LPOUTLINETEXTMETRICW LPOUTLINETEXTMETRIC; +#else + typedef OUTLINETEXTMETRICA OUTLINETEXTMETRIC; + typedef POUTLINETEXTMETRICA POUTLINETEXTMETRIC; + typedef NPOUTLINETEXTMETRICA NPOUTLINETEXTMETRIC; + typedef LPOUTLINETEXTMETRICA LPOUTLINETEXTMETRIC; +#endif +#endif + + typedef struct tagPOLYTEXTA { + int x; + int y; + UINT n; + LPCSTR lpstr; + UINT uiFlags; + RECT rcl; + int *pdx; + } POLYTEXTA,*PPOLYTEXTA,*NPPOLYTEXTA,*LPPOLYTEXTA; + + typedef struct tagPOLYTEXTW { + int x; + int y; + UINT n; + LPCWSTR lpstr; + UINT uiFlags; + RECT rcl; + int *pdx; + } POLYTEXTW,*PPOLYTEXTW,*NPPOLYTEXTW,*LPPOLYTEXTW; +#ifdef UNICODE + typedef POLYTEXTW POLYTEXT; + typedef PPOLYTEXTW PPOLYTEXT; + typedef NPPOLYTEXTW NPPOLYTEXT; + typedef LPPOLYTEXTW LPPOLYTEXT; +#else + typedef POLYTEXTA POLYTEXT; + typedef PPOLYTEXTA PPOLYTEXT; + typedef NPPOLYTEXTA NPPOLYTEXT; + typedef LPPOLYTEXTA LPPOLYTEXT; +#endif + + typedef struct _FIXED { + WORD fract; + short value; + } FIXED; + + typedef struct _MAT2 { + FIXED eM11; + FIXED eM12; + FIXED eM21; + FIXED eM22; + } MAT2,*LPMAT2; + + typedef struct _GLYPHMETRICS { + UINT gmBlackBoxX; + UINT gmBlackBoxY; + POINT gmptGlyphOrigin; + short gmCellIncX; + short gmCellIncY; + } GLYPHMETRICS,*LPGLYPHMETRICS; + +#define GGO_METRICS 0 +#define GGO_BITMAP 1 +#define GGO_NATIVE 2 +#define GGO_BEZIER 3 + +#define GGO_GRAY2_BITMAP 4 +#define GGO_GRAY4_BITMAP 5 +#define GGO_GRAY8_BITMAP 6 +#define GGO_GLYPH_INDEX 0x0080 +#define GGO_UNHINTED 0x0100 + +#define TT_POLYGON_TYPE 24 + +#define TT_PRIM_LINE 1 +#define TT_PRIM_QSPLINE 2 +#define TT_PRIM_CSPLINE 3 + + typedef struct tagPOINTFX { + FIXED x; + FIXED y; + } POINTFX,*LPPOINTFX; + + typedef struct tagTTPOLYCURVE { + WORD wType; + WORD cpfx; + POINTFX apfx[1]; + } TTPOLYCURVE,*LPTTPOLYCURVE; + + typedef struct tagTTPOLYGONHEADER { + DWORD cb; + DWORD dwType; + POINTFX pfxStart; + } TTPOLYGONHEADER,*LPTTPOLYGONHEADER; + +#define GCP_DBCS 0x0001 +#define GCP_REORDER 0x0002 +#define GCP_USEKERNING 0x0008 +#define GCP_GLYPHSHAPE 0x0010 +#define GCP_LIGATE 0x0020 + +#define GCP_DIACRITIC 0x0100 +#define GCP_KASHIDA 0x0400 +#define GCP_ERROR 0x8000 +#define FLI_MASK 0x103B + +#define GCP_JUSTIFY 0x00010000L + +#define FLI_GLYPHS 0x00040000L +#define GCP_CLASSIN 0x00080000L +#define GCP_MAXEXTENT 0x00100000L +#define GCP_JUSTIFYIN 0x00200000L +#define GCP_DISPLAYZWG 0x00400000L +#define GCP_SYMSWAPOFF 0x00800000L +#define GCP_NUMERICOVERRIDE 0x01000000L +#define GCP_NEUTRALOVERRIDE 0x02000000L +#define GCP_NUMERICSLATIN 0x04000000L +#define GCP_NUMERICSLOCAL 0x08000000L + +#define GCPCLASS_LATIN 1 +#define GCPCLASS_HEBREW 2 +#define GCPCLASS_ARABIC 2 +#define GCPCLASS_NEUTRAL 3 +#define GCPCLASS_LOCALNUMBER 4 +#define GCPCLASS_LATINNUMBER 5 +#define GCPCLASS_LATINNUMERICTERMINATOR 6 +#define GCPCLASS_LATINNUMERICSEPARATOR 7 +#define GCPCLASS_NUMERICSEPARATOR 8 +#define GCPCLASS_PREBOUNDLTR 0x80 +#define GCPCLASS_PREBOUNDRTL 0x40 +#define GCPCLASS_POSTBOUNDLTR 0x20 +#define GCPCLASS_POSTBOUNDRTL 0x10 + +#define GCPGLYPH_LINKBEFORE 0x8000 +#define GCPGLYPH_LINKAFTER 0x4000 + + typedef struct tagGCP_RESULTSA { + DWORD lStructSize; + LPSTR lpOutString; + UINT *lpOrder; + int *lpDx; + int *lpCaretPos; + LPSTR lpClass; + LPWSTR lpGlyphs; + UINT nGlyphs; + int nMaxFit; + } GCP_RESULTSA,*LPGCP_RESULTSA; + typedef struct tagGCP_RESULTSW { + DWORD lStructSize; + LPWSTR lpOutString; + UINT *lpOrder; + int *lpDx; + int *lpCaretPos; + LPSTR lpClass; + LPWSTR lpGlyphs; + UINT nGlyphs; + int nMaxFit; + } GCP_RESULTSW,*LPGCP_RESULTSW; +#ifdef UNICODE + typedef GCP_RESULTSW GCP_RESULTS; + typedef LPGCP_RESULTSW LPGCP_RESULTS; +#else + typedef GCP_RESULTSA GCP_RESULTS; + typedef LPGCP_RESULTSA LPGCP_RESULTS; +#endif + + typedef struct _RASTERIZER_STATUS { + short nSize; + short wFlags; + short nLanguageID; + } RASTERIZER_STATUS,*LPRASTERIZER_STATUS; + +#define TT_AVAILABLE 0x0001 +#define TT_ENABLED 0x0002 + + typedef struct tagPIXELFORMATDESCRIPTOR { + WORD nSize; + WORD nVersion; + DWORD dwFlags; + BYTE iPixelType; + BYTE cColorBits; + BYTE cRedBits; + BYTE cRedShift; + BYTE cGreenBits; + BYTE cGreenShift; + BYTE cBlueBits; + BYTE cBlueShift; + BYTE cAlphaBits; + BYTE cAlphaShift; + BYTE cAccumBits; + BYTE cAccumRedBits; + BYTE cAccumGreenBits; + BYTE cAccumBlueBits; + BYTE cAccumAlphaBits; + BYTE cDepthBits; + BYTE cStencilBits; + BYTE cAuxBuffers; + BYTE iLayerType; + BYTE bReserved; + DWORD dwLayerMask; + DWORD dwVisibleMask; + DWORD dwDamageMask; + } PIXELFORMATDESCRIPTOR,*PPIXELFORMATDESCRIPTOR,*LPPIXELFORMATDESCRIPTOR; + +#define PFD_TYPE_RGBA 0 +#define PFD_TYPE_COLORINDEX 1 + +#define PFD_MAIN_PLANE 0 +#define PFD_OVERLAY_PLANE 1 +#define PFD_UNDERLAY_PLANE (-1) + +#define PFD_DOUBLEBUFFER 0x00000001 +#define PFD_STEREO 0x00000002 +#define PFD_DRAW_TO_WINDOW 0x00000004 +#define PFD_DRAW_TO_BITMAP 0x00000008 +#define PFD_SUPPORT_GDI 0x00000010 +#define PFD_SUPPORT_OPENGL 0x00000020 +#define PFD_GENERIC_FORMAT 0x00000040 +#define PFD_NEED_PALETTE 0x00000080 +#define PFD_NEED_SYSTEM_PALETTE 0x00000100 +#define PFD_SWAP_EXCHANGE 0x00000200 +#define PFD_SWAP_COPY 0x00000400 +#define PFD_SWAP_LAYER_BUFFERS 0x00000800 +#define PFD_GENERIC_ACCELERATED 0x00001000 +#define PFD_SUPPORT_DIRECTDRAW 0x00002000 + +#define PFD_DEPTH_DONTCARE 0x20000000 +#define PFD_DOUBLEBUFFER_DONTCARE 0x40000000 +#define PFD_STEREO_DONTCARE 0x80000000 + +#ifndef NOTEXTMETRIC + typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST TEXTMETRICA *,DWORD,LPARAM); + typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST TEXTMETRICW *,DWORD,LPARAM); +#ifdef UNICODE +#define OLDFONTENUMPROC OLDFONTENUMPROCW +#else +#define OLDFONTENUMPROC OLDFONTENUMPROCA +#endif +#else + typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST VOID *,DWORD,LPARAM); + typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST VOID *,DWORD,LPARAM); +#ifdef UNICODE +#define OLDFONTENUMPROC OLDFONTENUMPROCW +#else +#define OLDFONTENUMPROC OLDFONTENUMPROCA +#endif +#endif + + typedef OLDFONTENUMPROCA FONTENUMPROCA; + typedef OLDFONTENUMPROCW FONTENUMPROCW; +#ifdef UNICODE + typedef FONTENUMPROCW FONTENUMPROC; +#else + typedef FONTENUMPROCA FONTENUMPROC; +#endif + + typedef int (CALLBACK *GOBJENUMPROC)(LPVOID,LPARAM); + typedef VOID (CALLBACK *LINEDDAPROC)(int,int,LPARAM); + +#ifdef UNICODE +#define AddFontResource AddFontResourceW +#define CopyMetaFile CopyMetaFileW +#define CreateDC CreateDCW +#define CreateFontIndirect CreateFontIndirectW +#define CreateFont CreateFontW +#define CreateIC CreateICW +#define CreateMetaFile CreateMetaFileW +#define CreateScalableFontResource CreateScalableFontResourceW +#else +#define AddFontResource AddFontResourceA +#define CopyMetaFile CopyMetaFileA +#define CreateDC CreateDCA +#define CreateFontIndirect CreateFontIndirectA +#define CreateFont CreateFontA +#define CreateIC CreateICA +#define CreateMetaFile CreateMetaFileA +#define CreateScalableFontResource CreateScalableFontResourceA +#endif + + WINGDIAPI int WINAPI AddFontResourceA(LPCSTR); + WINGDIAPI int WINAPI AddFontResourceW(LPCWSTR); + WINGDIAPI WINBOOL WINAPI AnimatePalette(HPALETTE hPal,UINT iStartIndex,UINT cEntries,CONST PALETTEENTRY *ppe); + WINGDIAPI WINBOOL WINAPI Arc(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); + WINGDIAPI WINBOOL WINAPI BitBlt(HDC hdc,int x,int y,int cx,int cy,HDC hdcSrc,int x1,int y1,DWORD rop); + WINGDIAPI WINBOOL WINAPI CancelDC(HDC hdc); + WINGDIAPI WINBOOL WINAPI Chord(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); + WINGDIAPI int WINAPI ChoosePixelFormat(HDC hdc,CONST PIXELFORMATDESCRIPTOR *ppfd); + WINGDIAPI HMETAFILE WINAPI CloseMetaFile(HDC hdc); + WINGDIAPI int WINAPI CombineRgn(HRGN hrgnDst,HRGN hrgnSrc1,HRGN hrgnSrc2,int iMode); + WINGDIAPI HMETAFILE WINAPI CopyMetaFileA(HMETAFILE,LPCSTR); + WINGDIAPI HMETAFILE WINAPI CopyMetaFileW(HMETAFILE,LPCWSTR); + WINGDIAPI HBITMAP WINAPI CreateBitmap(int nWidth,int nHeight,UINT nPlanes,UINT nBitCount,CONST VOID *lpBits); + WINGDIAPI HBITMAP WINAPI CreateBitmapIndirect(CONST BITMAP *pbm); + WINGDIAPI HBRUSH WINAPI CreateBrushIndirect(CONST LOGBRUSH *plbrush); + WINGDIAPI HBITMAP WINAPI CreateCompatibleBitmap(HDC hdc,int cx,int cy); + WINGDIAPI HBITMAP WINAPI CreateDiscardableBitmap(HDC hdc,int cx,int cy); + WINGDIAPI HDC WINAPI CreateCompatibleDC(HDC hdc); + WINGDIAPI HDC WINAPI CreateDCA(LPCSTR pwszDriver,LPCSTR pwszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); + WINGDIAPI HDC WINAPI CreateDCW(LPCWSTR pwszDriver,LPCWSTR pwszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); + WINGDIAPI HBITMAP WINAPI CreateDIBitmap(HDC hdc,CONST BITMAPINFOHEADER *pbmih,DWORD flInit,CONST VOID *pjBits,CONST BITMAPINFO *pbmi,UINT iUsage); + WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrush(HGLOBAL h,UINT iUsage); + WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrushPt(CONST VOID *lpPackedDIB,UINT iUsage); + WINGDIAPI HRGN WINAPI CreateEllipticRgn(int x1,int y1,int x2,int y2); + WINGDIAPI HRGN WINAPI CreateEllipticRgnIndirect(CONST RECT *lprect); + WINGDIAPI HFONT WINAPI CreateFontIndirectA(CONST LOGFONTA *lplf); + WINGDIAPI HFONT WINAPI CreateFontIndirectW(CONST LOGFONTW *lplf); + WINGDIAPI HFONT WINAPI CreateFontA(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCSTR pszFaceName); + WINGDIAPI HFONT WINAPI CreateFontW(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCWSTR pszFaceName); + WINGDIAPI HBRUSH WINAPI CreateHatchBrush(int iHatch,COLORREF color); + WINGDIAPI HDC WINAPI CreateICA(LPCSTR pszDriver,LPCSTR pszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); + WINGDIAPI HDC WINAPI CreateICW(LPCWSTR pszDriver,LPCWSTR pszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); + WINGDIAPI HDC WINAPI CreateMetaFileA(LPCSTR pszFile); + WINGDIAPI HDC WINAPI CreateMetaFileW(LPCWSTR pszFile); + WINGDIAPI HPALETTE WINAPI CreatePalette(CONST LOGPALETTE *plpal); + WINGDIAPI HPEN WINAPI CreatePen(int iStyle,int cWidth,COLORREF color); + WINGDIAPI HPEN WINAPI CreatePenIndirect(CONST LOGPEN *plpen); + WINGDIAPI HRGN WINAPI CreatePolyPolygonRgn(CONST POINT *pptl,CONST INT *pc,int cPoly,int iMode); + WINGDIAPI HBRUSH WINAPI CreatePatternBrush(HBITMAP hbm); + WINGDIAPI HRGN WINAPI CreateRectRgn(int x1,int y1,int x2,int y2); + WINGDIAPI HRGN WINAPI CreateRectRgnIndirect(CONST RECT *lprect); + WINGDIAPI HRGN WINAPI CreateRoundRectRgn(int x1,int y1,int x2,int y2,int w,int h); + WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceA(DWORD fdwHidden,LPCSTR lpszFont,LPCSTR lpszFile,LPCSTR lpszPath); + WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceW(DWORD fdwHidden,LPCWSTR lpszFont,LPCWSTR lpszFile,LPCWSTR lpszPath); + WINGDIAPI HBRUSH WINAPI CreateSolidBrush(COLORREF color); + WINGDIAPI WINBOOL WINAPI DeleteDC(HDC hdc); + WINGDIAPI WINBOOL WINAPI DeleteMetaFile(HMETAFILE hmf); + WINGDIAPI WINBOOL WINAPI DeleteObject(HGDIOBJ ho); + WINGDIAPI int WINAPI DescribePixelFormat(HDC hdc,int iPixelFormat,UINT nBytes,LPPIXELFORMATDESCRIPTOR ppfd); + + typedef UINT (CALLBACK *LPFNDEVMODE)(HWND,HMODULE,LPDEVMODE,LPSTR,LPSTR,LPDEVMODE,LPSTR,UINT); + typedef DWORD (CALLBACK *LPFNDEVCAPS)(LPSTR,LPSTR,UINT,LPSTR,LPDEVMODE); + +#define DM_UPDATE 1 +#define DM_COPY 2 +#define DM_PROMPT 4 +#define DM_MODIFY 8 + +#define DM_IN_BUFFER DM_MODIFY +#define DM_IN_PROMPT DM_PROMPT +#define DM_OUT_BUFFER DM_COPY +#define DM_OUT_DEFAULT DM_UPDATE + +#define DC_FIELDS 1 +#define DC_PAPERS 2 +#define DC_PAPERSIZE 3 +#define DC_MINEXTENT 4 +#define DC_MAXEXTENT 5 +#define DC_BINS 6 +#define DC_DUPLEX 7 +#define DC_SIZE 8 +#define DC_EXTRA 9 +#define DC_VERSION 10 +#define DC_DRIVER 11 +#define DC_BINNAMES 12 +#define DC_ENUMRESOLUTIONS 13 +#define DC_FILEDEPENDENCIES 14 +#define DC_TRUETYPE 15 +#define DC_PAPERNAMES 16 +#define DC_ORIENTATION 17 +#define DC_COPIES 18 +#define DC_BINADJUST 19 +#define DC_EMF_COMPLIANT 20 +#define DC_DATATYPE_PRODUCED 21 +#define DC_COLLATE 22 +#define DC_MANUFACTURER 23 +#define DC_MODEL 24 +#define DC_PERSONALITY 25 +#define DC_PRINTRATE 26 +#define DC_PRINTRATEUNIT 27 +#define PRINTRATEUNIT_PPM 1 +#define PRINTRATEUNIT_CPS 2 +#define PRINTRATEUNIT_LPM 3 +#define PRINTRATEUNIT_IPM 4 +#define DC_PRINTERMEM 28 +#define DC_MEDIAREADY 29 +#define DC_STAPLE 30 +#define DC_PRINTRATEPPM 31 +#define DC_COLORDEVICE 32 +#define DC_NUP 33 +#define DC_MEDIATYPENAMES 34 +#define DC_MEDIATYPES 35 + +#define DCTT_BITMAP 0x0000001L +#define DCTT_DOWNLOAD 0x0000002L +#define DCTT_SUBDEV 0x0000004L +#define DCTT_DOWNLOAD_OUTLINE 0x0000008L + +#define DCBA_FACEUPNONE 0x0000 +#define DCBA_FACEUPCENTER 0x0001 +#define DCBA_FACEUPLEFT 0x0002 +#define DCBA_FACEUPRIGHT 0x0003 +#define DCBA_FACEDOWNNONE 0x0100 +#define DCBA_FACEDOWNCENTER 0x0101 +#define DCBA_FACEDOWNLEFT 0x0102 +#define DCBA_FACEDOWNRIGHT 0x0103 + +#ifdef UNICODE +#define DeviceCapabilities DeviceCapabilitiesW +#define EnumFontFamiliesEx EnumFontFamiliesExW +#define EnumFontFamilies EnumFontFamiliesW +#define EnumFonts EnumFontsW +#define GetCharWidth GetCharWidthW +#define GetCharWidth32 GetCharWidth32W +#define GetCharWidthFloat GetCharWidthFloatW +#define GetCharABCWidths GetCharABCWidthsW +#define GetCharABCWidthsFloat GetCharABCWidthsFloatW +#define GetGlyphOutline GetGlyphOutlineW +#define GetMetaFile GetMetaFileW +#else +#define DeviceCapabilities DeviceCapabilitiesA +#define EnumFontFamiliesEx EnumFontFamiliesExA +#define EnumFontFamilies EnumFontFamiliesA +#define EnumFonts EnumFontsA +#define GetCharWidth GetCharWidthA +#define GetCharWidth32 GetCharWidth32A +#define GetCharWidthFloat GetCharWidthFloatA +#define GetCharABCWidths GetCharABCWidthsA +#define GetCharABCWidthsFloat GetCharABCWidthsFloatA +#define GetGlyphOutline GetGlyphOutlineA +#define GetMetaFile GetMetaFileA +#endif + + WINSPOOLAPI int WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort,WORD fwCapability,LPSTR pOutput,CONST DEVMODEA *pDevMode); + WINSPOOLAPI int WINAPI DeviceCapabilitiesW(LPCWSTR pDevice,LPCWSTR pPort,WORD fwCapability,LPWSTR pOutput,CONST DEVMODEW *pDevMode); + WINGDIAPI int WINAPI DrawEscape(HDC hdc,int iEscape,int cjIn,LPCSTR lpIn); + WINGDIAPI WINBOOL WINAPI Ellipse(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI int WINAPI EnumFontFamiliesExA(HDC hdc,LPLOGFONTA lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam,DWORD dwFlags); + WINGDIAPI int WINAPI EnumFontFamiliesExW(HDC hdc,LPLOGFONTW lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam,DWORD dwFlags); + WINGDIAPI int WINAPI EnumFontFamiliesA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumFontFamiliesW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumFontsA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumFontsW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumObjects(HDC hdc,int nType,GOBJENUMPROC lpFunc,LPARAM lParam); + WINGDIAPI WINBOOL WINAPI EqualRgn(HRGN hrgn1,HRGN hrgn2); + WINGDIAPI int WINAPI Escape(HDC hdc,int iEscape,int cjIn,LPCSTR pvIn,LPVOID pvOut); + WINGDIAPI int WINAPI ExtEscape(HDC hdc,int iEscape,int cjInput,LPCSTR lpInData,int cjOutput,LPSTR lpOutData); + WINGDIAPI int WINAPI ExcludeClipRect(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI HRGN WINAPI ExtCreateRegion(CONST XFORM *lpx,DWORD nCount,CONST RGNDATA *lpData); + WINGDIAPI WINBOOL WINAPI ExtFloodFill(HDC hdc,int x,int y,COLORREF color,UINT type); + WINGDIAPI WINBOOL WINAPI FillRgn(HDC hdc,HRGN hrgn,HBRUSH hbr); + WINGDIAPI WINBOOL WINAPI FloodFill(HDC hdc,int x,int y,COLORREF color); + WINGDIAPI WINBOOL WINAPI FrameRgn(HDC hdc,HRGN hrgn,HBRUSH hbr,int w,int h); + WINGDIAPI int WINAPI GetROP2(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetAspectRatioFilterEx(HDC hdc,LPSIZE lpsize); + WINGDIAPI COLORREF WINAPI GetBkColor(HDC hdc); + WINGDIAPI COLORREF WINAPI GetDCBrushColor(HDC hdc); + WINGDIAPI COLORREF WINAPI GetDCPenColor(HDC hdc); + WINGDIAPI int WINAPI GetBkMode(HDC hdc); + WINGDIAPI LONG WINAPI GetBitmapBits(HBITMAP hbit,LONG cb,LPVOID lpvBits); + WINGDIAPI WINBOOL WINAPI GetBitmapDimensionEx(HBITMAP hbit,LPSIZE lpsize); + WINGDIAPI UINT WINAPI GetBoundsRect(HDC hdc,LPRECT lprect,UINT flags); + WINGDIAPI WINBOOL WINAPI GetBrushOrgEx(HDC hdc,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI GetCharWidthA(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidthW(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidth32A(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidth32W(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidthFloatA(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidthFloatW(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsA(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsW(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatA(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatW(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); + WINGDIAPI int WINAPI GetClipBox(HDC hdc,LPRECT lprect); + WINGDIAPI int WINAPI GetClipRgn(HDC hdc,HRGN hrgn); + WINGDIAPI int WINAPI GetMetaRgn(HDC hdc,HRGN hrgn); + WINGDIAPI HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type); + WINGDIAPI WINBOOL WINAPI GetCurrentPositionEx(HDC hdc,LPPOINT lppt); + WINGDIAPI int WINAPI GetDeviceCaps(HDC hdc,int index); + WINGDIAPI int WINAPI GetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,LPVOID lpvBits,LPBITMAPINFO lpbmi,UINT usage); + WINGDIAPI DWORD WINAPI GetFontData (HDC hdc,DWORD dwTable,DWORD dwOffset,PVOID pvBuffer,DWORD cjBuffer); + WINGDIAPI DWORD WINAPI GetGlyphOutlineA(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); + WINGDIAPI DWORD WINAPI GetGlyphOutlineW(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); + WINGDIAPI int WINAPI GetGraphicsMode(HDC hdc); + WINGDIAPI int WINAPI GetMapMode(HDC hdc); + WINGDIAPI UINT WINAPI GetMetaFileBitsEx(HMETAFILE hMF,UINT cbBuffer,LPVOID lpData); + WINGDIAPI HMETAFILE WINAPI GetMetaFileA(LPCSTR lpName); + WINGDIAPI HMETAFILE WINAPI GetMetaFileW(LPCWSTR lpName); + WINGDIAPI COLORREF WINAPI GetNearestColor(HDC hdc,COLORREF color); + WINGDIAPI UINT WINAPI GetNearestPaletteIndex(HPALETTE h,COLORREF color); + WINGDIAPI DWORD WINAPI GetObjectType(HGDIOBJ h); + +#ifndef NOTEXTMETRIC +#ifdef UNICODE +#define GetOutlineTextMetrics GetOutlineTextMetricsW +#else +#define GetOutlineTextMetrics GetOutlineTextMetricsA +#endif + + WINGDIAPI UINT WINAPI GetOutlineTextMetricsA(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICA potm); + WINGDIAPI UINT WINAPI GetOutlineTextMetricsW(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICW potm); +#endif + +#ifdef UNICODE +#define GetTextExtentPoint GetTextExtentPointW +#define GetTextExtentPoint32 GetTextExtentPoint32W +#define GetTextExtentExPoint GetTextExtentExPointW +#define GetCharacterPlacement GetCharacterPlacementW +#else +#define GetTextExtentPoint GetTextExtentPointA +#define GetTextExtentPoint32 GetTextExtentPoint32A +#define GetTextExtentExPoint GetTextExtentExPointA +#define GetCharacterPlacement GetCharacterPlacementA +#endif + + WINGDIAPI UINT WINAPI GetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); + WINGDIAPI COLORREF WINAPI GetPixel(HDC hdc,int x,int y); + WINGDIAPI int WINAPI GetPixelFormat(HDC hdc); + WINGDIAPI int WINAPI GetPolyFillMode(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetRasterizerCaps(LPRASTERIZER_STATUS lpraststat,UINT cjBytes); + WINGDIAPI int WINAPI GetRandomRgn (HDC hdc,HRGN hrgn,INT i); + WINGDIAPI DWORD WINAPI GetRegionData(HRGN hrgn,DWORD nCount,LPRGNDATA lpRgnData); + WINGDIAPI int WINAPI GetRgnBox(HRGN hrgn,LPRECT lprc); + WINGDIAPI HGDIOBJ WINAPI GetStockObject(int i); + WINGDIAPI int WINAPI GetStretchBltMode(HDC hdc); + WINGDIAPI UINT WINAPI GetSystemPaletteEntries(HDC hdc,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); + WINGDIAPI UINT WINAPI GetSystemPaletteUse(HDC hdc); + WINGDIAPI int WINAPI GetTextCharacterExtra(HDC hdc); + WINGDIAPI UINT WINAPI GetTextAlign(HDC hdc); + WINGDIAPI COLORREF WINAPI GetTextColor(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetTextExtentPointA(HDC hdc,LPCSTR lpString,int c,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI GetTextExtentPointW(HDC hdc,LPCWSTR lpString,int c,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32A(HDC hdc,LPCSTR lpString,int c,LPSIZE psizl); + WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32W(HDC hdc,LPCWSTR lpString,int c,LPSIZE psizl); + WINGDIAPI WINBOOL WINAPI GetTextExtentExPointA(HDC hdc,LPCSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); + WINGDIAPI WINBOOL WINAPI GetTextExtentExPointW(HDC hdc,LPCWSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); + WINGDIAPI int WINAPI GetTextCharset(HDC hdc); + WINGDIAPI int WINAPI GetTextCharsetInfo(HDC hdc,LPFONTSIGNATURE lpSig,DWORD dwFlags); + WINGDIAPI WINBOOL WINAPI TranslateCharsetInfo(DWORD *lpSrc,LPCHARSETINFO lpCs,DWORD dwFlags); + WINGDIAPI DWORD WINAPI GetFontLanguageInfo(HDC hdc); + WINGDIAPI DWORD WINAPI GetCharacterPlacementA(HDC hdc,LPCSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSA lpResults,DWORD dwFlags); + WINGDIAPI DWORD WINAPI GetCharacterPlacementW(HDC hdc,LPCWSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSW lpResults,DWORD dwFlags); + + typedef struct tagWCRANGE { + WCHAR wcLow; + USHORT cGlyphs; + } WCRANGE,*PWCRANGE,*LPWCRANGE; + + typedef struct tagGLYPHSET { + DWORD cbThis; + DWORD flAccel; + DWORD cGlyphsSupported; + DWORD cRanges; + WCRANGE ranges[1]; + } GLYPHSET,*PGLYPHSET,*LPGLYPHSET; + +#define GS_8BIT_INDICES 0x00000001 + +#define GGI_MARK_NONEXISTING_GLYPHS 0X0001 + +#ifdef UNICODE +#define GetGlyphIndices GetGlyphIndicesW +#else +#define GetGlyphIndices GetGlyphIndicesA +#endif + + WINGDIAPI DWORD WINAPI GetFontUnicodeRanges(HDC hdc,LPGLYPHSET lpgs); + WINGDIAPI DWORD WINAPI GetGlyphIndicesA(HDC hdc,LPCSTR lpstr,int c,LPWORD pgi,DWORD fl); + WINGDIAPI DWORD WINAPI GetGlyphIndicesW(HDC hdc,LPCWSTR lpstr,int c,LPWORD pgi,DWORD fl); + WINGDIAPI WINBOOL WINAPI GetTextExtentPointI(HDC hdc,LPWORD pgiIn,int cgi,LPSIZE psize); + WINGDIAPI WINBOOL WINAPI GetTextExtentExPointI (HDC hdc,LPWORD lpwszString,int cwchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); + WINGDIAPI WINBOOL WINAPI GetCharWidthI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPINT piWidths); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPABC pabc); + +#define STAMP_DESIGNVECTOR (0x8000000 + 'd' + ('v' << 8)) +#define STAMP_AXESLIST (0x8000000 + 'a' + ('l' << 8)) +#define MM_MAX_NUMAXES 16 + + typedef struct tagDESIGNVECTOR { + DWORD dvReserved; + DWORD dvNumAxes; + LONG dvValues[MM_MAX_NUMAXES]; + } DESIGNVECTOR,*PDESIGNVECTOR,*LPDESIGNVECTOR; + +#ifdef UNICODE +#define AddFontResourceEx AddFontResourceExW +#define RemoveFontResourceEx RemoveFontResourceExW +#else +#define AddFontResourceEx AddFontResourceExA +#define RemoveFontResourceEx RemoveFontResourceExA +#endif + + WINGDIAPI int WINAPI AddFontResourceExA(LPCSTR name,DWORD fl,PVOID res); + WINGDIAPI int WINAPI AddFontResourceExW(LPCWSTR name,DWORD fl,PVOID res); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceExA(LPCSTR name,DWORD fl,PVOID pdv); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceExW(LPCWSTR name,DWORD fl,PVOID pdv); + WINGDIAPI HANDLE WINAPI AddFontMemResourceEx(PVOID pFileView,DWORD cjSize,PVOID pvResrved,DWORD *pNumFonts); + WINGDIAPI WINBOOL WINAPI RemoveFontMemResourceEx(HANDLE h); + +#define FR_PRIVATE 0x10 +#define FR_NOT_ENUM 0x20 + +#define MM_MAX_AXES_NAMELEN 16 + + typedef struct tagAXISINFOA { + LONG axMinValue; + LONG axMaxValue; + BYTE axAxisName[MM_MAX_AXES_NAMELEN]; + } AXISINFOA,*PAXISINFOA,*LPAXISINFOA; + + typedef struct tagAXISINFOW { + LONG axMinValue; + LONG axMaxValue; + WCHAR axAxisName[MM_MAX_AXES_NAMELEN]; + } AXISINFOW,*PAXISINFOW,*LPAXISINFOW; +#ifdef UNICODE + typedef AXISINFOW AXISINFO; + typedef PAXISINFOW PAXISINFO; + typedef LPAXISINFOW LPAXISINFO; +#else + typedef AXISINFOA AXISINFO; + typedef PAXISINFOA PAXISINFO; + typedef LPAXISINFOA LPAXISINFO; +#endif + + typedef struct tagAXESLISTA { + DWORD axlReserved; + DWORD axlNumAxes; + AXISINFOA axlAxisInfo[MM_MAX_NUMAXES]; + } AXESLISTA,*PAXESLISTA,*LPAXESLISTA; + + typedef struct tagAXESLISTW { + DWORD axlReserved; + DWORD axlNumAxes; + AXISINFOW axlAxisInfo[MM_MAX_NUMAXES]; + } AXESLISTW,*PAXESLISTW,*LPAXESLISTW; +#ifdef UNICODE + typedef AXESLISTW AXESLIST; + typedef PAXESLISTW PAXESLIST; + typedef LPAXESLISTW LPAXESLIST; +#else + typedef AXESLISTA AXESLIST; + typedef PAXESLISTA PAXESLIST; + typedef LPAXESLISTA LPAXESLIST; +#endif + + typedef struct tagENUMLOGFONTEXDVA { + ENUMLOGFONTEXA elfEnumLogfontEx; + DESIGNVECTOR elfDesignVector; + } ENUMLOGFONTEXDVA,*PENUMLOGFONTEXDVA,*LPENUMLOGFONTEXDVA; + + typedef struct tagENUMLOGFONTEXDVW { + ENUMLOGFONTEXW elfEnumLogfontEx; + DESIGNVECTOR elfDesignVector; + } ENUMLOGFONTEXDVW,*PENUMLOGFONTEXDVW,*LPENUMLOGFONTEXDVW; +#ifdef UNICODE + typedef ENUMLOGFONTEXDVW ENUMLOGFONTEXDV; + typedef PENUMLOGFONTEXDVW PENUMLOGFONTEXDV; + typedef LPENUMLOGFONTEXDVW LPENUMLOGFONTEXDV; +#else + typedef ENUMLOGFONTEXDVA ENUMLOGFONTEXDV; + typedef PENUMLOGFONTEXDVA PENUMLOGFONTEXDV; + typedef LPENUMLOGFONTEXDVA LPENUMLOGFONTEXDV; +#endif + +#ifdef UNICODE +#define CreateFontIndirectEx CreateFontIndirectExW +#else +#define CreateFontIndirectEx CreateFontIndirectExA +#endif + + WINGDIAPI HFONT WINAPI CreateFontIndirectExA(CONST ENUMLOGFONTEXDVA *); + WINGDIAPI HFONT WINAPI CreateFontIndirectExW(CONST ENUMLOGFONTEXDVW *); + +#ifndef NOTEXTMETRIC + typedef struct tagENUMTEXTMETRICA { + NEWTEXTMETRICEXA etmNewTextMetricEx; + AXESLISTA etmAxesList; + } ENUMTEXTMETRICA,*PENUMTEXTMETRICA,*LPENUMTEXTMETRICA; + typedef struct tagENUMTEXTMETRICW + { + NEWTEXTMETRICEXW etmNewTextMetricEx; + AXESLISTW etmAxesList; + } ENUMTEXTMETRICW,*PENUMTEXTMETRICW,*LPENUMTEXTMETRICW; +#ifdef UNICODE + typedef ENUMTEXTMETRICW ENUMTEXTMETRIC; + typedef PENUMTEXTMETRICW PENUMTEXTMETRIC; + typedef LPENUMTEXTMETRICW LPENUMTEXTMETRIC; +#else + typedef ENUMTEXTMETRICA ENUMTEXTMETRIC; + typedef PENUMTEXTMETRICA PENUMTEXTMETRIC; + typedef LPENUMTEXTMETRICA LPENUMTEXTMETRIC; +#endif +#endif + +#ifdef UNICODE +#define ResetDC ResetDCW +#define RemoveFontResource RemoveFontResourceW +#else +#define ResetDC ResetDCA +#define RemoveFontResource RemoveFontResourceA +#endif + + WINGDIAPI WINBOOL WINAPI GetViewportExtEx(HDC hdc,LPSIZE lpsize); + WINGDIAPI WINBOOL WINAPI GetViewportOrgEx(HDC hdc,LPPOINT lppoint); + WINGDIAPI WINBOOL WINAPI GetWindowExtEx(HDC hdc,LPSIZE lpsize); + WINGDIAPI WINBOOL WINAPI GetWindowOrgEx(HDC hdc,LPPOINT lppoint); + WINGDIAPI int WINAPI IntersectClipRect(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI WINBOOL WINAPI InvertRgn(HDC hdc,HRGN hrgn); + WINGDIAPI WINBOOL WINAPI LineDDA(int xStart,int yStart,int xEnd,int yEnd,LINEDDAPROC lpProc,LPARAM data); + WINGDIAPI WINBOOL WINAPI LineTo(HDC hdc,int x,int y); + WINGDIAPI WINBOOL WINAPI MaskBlt(HDC hdcDest,int xDest,int yDest,int width,int height,HDC hdcSrc,int xSrc,int ySrc,HBITMAP hbmMask,int xMask,int yMask,DWORD rop); + WINGDIAPI WINBOOL WINAPI PlgBlt(HDC hdcDest,CONST POINT *lpPoint,HDC hdcSrc,int xSrc,int ySrc,int width,int height,HBITMAP hbmMask,int xMask,int yMask); + WINGDIAPI int WINAPI OffsetClipRgn(HDC hdc,int x,int y); + WINGDIAPI int WINAPI OffsetRgn(HRGN hrgn,int x,int y); + WINGDIAPI WINBOOL WINAPI PatBlt(HDC hdc,int x,int y,int w,int h,DWORD rop); + WINGDIAPI WINBOOL WINAPI Pie(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); + WINGDIAPI WINBOOL WINAPI PlayMetaFile(HDC hdc,HMETAFILE hmf); + WINGDIAPI WINBOOL WINAPI PaintRgn(HDC hdc,HRGN hrgn); + WINGDIAPI WINBOOL WINAPI PolyPolygon(HDC hdc,CONST POINT *apt,CONST INT *asz,int csz); + WINGDIAPI WINBOOL WINAPI PtInRegion(HRGN hrgn,int x,int y); + WINGDIAPI WINBOOL WINAPI PtVisible(HDC hdc,int x,int y); + WINGDIAPI WINBOOL WINAPI RectInRegion(HRGN hrgn,CONST RECT *lprect); + WINGDIAPI WINBOOL WINAPI RectVisible(HDC hdc,CONST RECT *lprect); + WINGDIAPI WINBOOL WINAPI Rectangle(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI WINBOOL WINAPI RestoreDC(HDC hdc,int nSavedDC); + WINGDIAPI HDC WINAPI ResetDCA(HDC hdc,CONST DEVMODEA *lpdm); + WINGDIAPI HDC WINAPI ResetDCW(HDC hdc,CONST DEVMODEW *lpdm); + WINGDIAPI UINT WINAPI RealizePalette(HDC hdc); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceA(LPCSTR lpFileName); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceW(LPCWSTR lpFileName); + WINGDIAPI WINBOOL WINAPI RoundRect(HDC hdc,int left,int top,int right,int bottom,int width,int height); + WINGDIAPI WINBOOL WINAPI ResizePalette(HPALETTE hpal,UINT n); + WINGDIAPI int WINAPI SaveDC(HDC hdc); + WINGDIAPI int WINAPI SelectClipRgn(HDC hdc,HRGN hrgn); + WINGDIAPI int WINAPI ExtSelectClipRgn(HDC hdc,HRGN hrgn,int mode); + WINGDIAPI int WINAPI SetMetaRgn(HDC hdc); + WINGDIAPI HGDIOBJ WINAPI SelectObject(HDC hdc,HGDIOBJ h); + WINGDIAPI HPALETTE WINAPI SelectPalette(HDC hdc,HPALETTE hPal,WINBOOL bForceBkgd); + WINGDIAPI COLORREF WINAPI SetBkColor(HDC hdc,COLORREF color); + WINGDIAPI COLORREF WINAPI SetDCBrushColor(HDC hdc,COLORREF color); + WINGDIAPI COLORREF WINAPI SetDCPenColor(HDC hdc,COLORREF color); + WINGDIAPI int WINAPI SetBkMode(HDC hdc,int mode); + WINGDIAPI LONG WINAPI SetBitmapBits(HBITMAP hbm,DWORD cb,CONST VOID *pvBits); + WINGDIAPI UINT WINAPI SetBoundsRect(HDC hdc,CONST RECT *lprect,UINT flags); + WINGDIAPI int WINAPI SetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); + WINGDIAPI int WINAPI SetDIBitsToDevice(HDC hdc,int xDest,int yDest,DWORD w,DWORD h,int xSrc,int ySrc,UINT StartScan,UINT cLines,CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); + WINGDIAPI DWORD WINAPI SetMapperFlags(HDC hdc,DWORD flags); + WINGDIAPI int WINAPI SetGraphicsMode(HDC hdc,int iMode); + WINGDIAPI int WINAPI SetMapMode(HDC hdc,int iMode); + WINGDIAPI DWORD WINAPI SetLayout(HDC hdc,DWORD l); + WINGDIAPI DWORD WINAPI GetLayout(HDC hdc); + WINGDIAPI HMETAFILE WINAPI SetMetaFileBitsEx(UINT cbBuffer,CONST BYTE *lpData); + WINGDIAPI UINT WINAPI SetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,CONST PALETTEENTRY *pPalEntries); + WINGDIAPI COLORREF WINAPI SetPixel(HDC hdc,int x,int y,COLORREF color); + WINGDIAPI WINBOOL WINAPI SetPixelV(HDC hdc,int x,int y,COLORREF color); + WINGDIAPI WINBOOL WINAPI SetPixelFormat(HDC hdc,int format,CONST PIXELFORMATDESCRIPTOR *ppfd); + WINGDIAPI int WINAPI SetPolyFillMode(HDC hdc,int mode); + WINGDIAPI WINBOOL WINAPI StretchBlt(HDC hdcDest,int xDest,int yDest,int wDest,int hDest,HDC hdcSrc,int xSrc,int ySrc,int wSrc,int hSrc,DWORD rop); + WINGDIAPI WINBOOL WINAPI SetRectRgn(HRGN hrgn,int left,int top,int right,int bottom); + WINGDIAPI int WINAPI StretchDIBits(HDC hdc,int xDest,int yDest,int DestWidth,int DestHeight,int xSrc,int ySrc,int SrcWidth,int SrcHeight,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT iUsage,DWORD rop); + WINGDIAPI int WINAPI SetROP2(HDC hdc,int rop2); + WINGDIAPI int WINAPI SetStretchBltMode(HDC hdc,int mode); + WINGDIAPI UINT WINAPI SetSystemPaletteUse(HDC hdc,UINT use); + WINGDIAPI int WINAPI SetTextCharacterExtra(HDC hdc,int extra); + WINGDIAPI COLORREF WINAPI SetTextColor(HDC hdc,COLORREF color); + WINGDIAPI UINT WINAPI SetTextAlign(HDC hdc,UINT align); + WINGDIAPI WINBOOL WINAPI SetTextJustification(HDC hdc,int extra,int count); + WINGDIAPI WINBOOL WINAPI UpdateColors(HDC hdc); + + typedef USHORT COLOR16; + + typedef struct _TRIVERTEX { + LONG x; + LONG y; + COLOR16 Red; + COLOR16 Green; + COLOR16 Blue; + COLOR16 Alpha; + } TRIVERTEX,*PTRIVERTEX,*LPTRIVERTEX; + + typedef struct _GRADIENT_TRIANGLE { + ULONG Vertex1; + ULONG Vertex2; + ULONG Vertex3; + } GRADIENT_TRIANGLE,*PGRADIENT_TRIANGLE,*LPGRADIENT_TRIANGLE; + + typedef struct _GRADIENT_RECT { + ULONG UpperLeft; + ULONG LowerRight; + } GRADIENT_RECT,*PGRADIENT_RECT,*LPGRADIENT_RECT; + + typedef struct _BLENDFUNCTION { + BYTE BlendOp; + BYTE BlendFlags; + BYTE SourceConstantAlpha; + BYTE AlphaFormat; + } BLENDFUNCTION,*PBLENDFUNCTION; + +#define AC_SRC_OVER 0x00 +#define AC_SRC_ALPHA 0x01 + + WINGDIAPI WINBOOL WINAPI AlphaBlend(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,BLENDFUNCTION ftn); + WINGDIAPI WINBOOL WINAPI TransparentBlt(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,UINT crTransparent); + +#define GRADIENT_FILL_RECT_H 0x00000000 +#define GRADIENT_FILL_RECT_V 0x00000001 +#define GRADIENT_FILL_TRIANGLE 0x00000002 +#define GRADIENT_FILL_OP_FLAG 0x000000ff + + WINGDIAPI WINBOOL WINAPI GradientFill(HDC hdc,PTRIVERTEX pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,ULONG ulMode); + +#ifndef NOMETAFILE + +#ifdef UNICODE +#define CopyEnhMetaFile CopyEnhMetaFileW +#define CreateEnhMetaFile CreateEnhMetaFileW +#define GetEnhMetaFile GetEnhMetaFileW +#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionW +#else +#define CopyEnhMetaFile CopyEnhMetaFileA +#define CreateEnhMetaFile CreateEnhMetaFileA +#define GetEnhMetaFile GetEnhMetaFileA +#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionA +#endif + + WINGDIAPI WINBOOL WINAPI PlayMetaFileRecord(HDC hdc,LPHANDLETABLE lpHandleTable,LPMETARECORD lpMR,UINT noObjs); + + typedef int (CALLBACK *MFENUMPROC)(HDC hdc,HANDLETABLE *lpht,METARECORD *lpMR,int nObj,LPARAM param); + + WINGDIAPI WINBOOL WINAPI EnumMetaFile(HDC hdc,HMETAFILE hmf,MFENUMPROC proc,LPARAM param); + + typedef int (CALLBACK *ENHMFENUMPROC)(HDC hdc,HANDLETABLE *lpht,CONST ENHMETARECORD *lpmr,int hHandles,LPARAM data); + + WINGDIAPI HENHMETAFILE WINAPI CloseEnhMetaFile(HDC hdc); + WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileA(HENHMETAFILE hEnh,LPCSTR lpFileName); + WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileW(HENHMETAFILE hEnh,LPCWSTR lpFileName); + WINGDIAPI HDC WINAPI CreateEnhMetaFileA(HDC hdc,LPCSTR lpFilename,CONST RECT *lprc,LPCSTR lpDesc); + WINGDIAPI HDC WINAPI CreateEnhMetaFileW(HDC hdc,LPCWSTR lpFilename,CONST RECT *lprc,LPCWSTR lpDesc); + WINGDIAPI WINBOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf); + WINGDIAPI WINBOOL WINAPI EnumEnhMetaFile(HDC hdc,HENHMETAFILE hmf,ENHMFENUMPROC proc,LPVOID param,CONST RECT *lpRect); + WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileA(LPCSTR lpName); + WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileW(LPCWSTR lpName); + WINGDIAPI UINT WINAPI GetEnhMetaFileBits(HENHMETAFILE hEMF,UINT nSize,LPBYTE lpData); + WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionA(HENHMETAFILE hemf,UINT cchBuffer,LPSTR lpDescription); + WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionW(HENHMETAFILE hemf,UINT cchBuffer,LPWSTR lpDescription); + WINGDIAPI UINT WINAPI GetEnhMetaFileHeader(HENHMETAFILE hemf,UINT nSize,LPENHMETAHEADER lpEnhMetaHeader); + WINGDIAPI UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf,UINT nNumEntries,LPPALETTEENTRY lpPaletteEntries); + WINGDIAPI UINT WINAPI GetEnhMetaFilePixelFormat(HENHMETAFILE hemf,UINT cbBuffer,PIXELFORMATDESCRIPTOR *ppfd); + WINGDIAPI UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,UINT cbData16,LPBYTE pData16,INT iMapMode,HDC hdcRef); + WINGDIAPI WINBOOL WINAPI PlayEnhMetaFile(HDC hdc,HENHMETAFILE hmf,CONST RECT *lprect); + WINGDIAPI WINBOOL WINAPI PlayEnhMetaFileRecord(HDC hdc,LPHANDLETABLE pht,CONST ENHMETARECORD *pmr,UINT cht); + WINGDIAPI HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT nSize,CONST BYTE *pb); + WINGDIAPI HENHMETAFILE WINAPI SetWinMetaFileBits(UINT nSize,CONST BYTE *lpMeta16Data,HDC hdcRef,CONST METAFILEPICT *lpMFP); + WINGDIAPI WINBOOL WINAPI GdiComment(HDC hdc,UINT nSize,CONST BYTE *lpData); +#endif + +#ifndef NOTEXTMETRIC +#ifdef UNICODE +#define GetTextMetrics GetTextMetricsW +#else +#define GetTextMetrics GetTextMetricsA +#endif + + WINGDIAPI WINBOOL WINAPI GetTextMetricsA(HDC hdc,LPTEXTMETRICA lptm); + WINGDIAPI WINBOOL WINAPI GetTextMetricsW(HDC hdc,LPTEXTMETRICW lptm); +#endif + + typedef struct tagDIBSECTION { + BITMAP dsBm; + BITMAPINFOHEADER dsBmih; + DWORD dsBitfields[3]; + HANDLE dshSection; + DWORD dsOffset; + } DIBSECTION,*LPDIBSECTION,*PDIBSECTION; + + WINGDIAPI WINBOOL WINAPI AngleArc(HDC hdc,int x,int y,DWORD r,FLOAT StartAngle,FLOAT SweepAngle); + WINGDIAPI WINBOOL WINAPI PolyPolyline(HDC hdc,CONST POINT *apt,CONST DWORD *asz,DWORD csz); + WINGDIAPI WINBOOL WINAPI GetWorldTransform(HDC hdc,LPXFORM lpxf); + WINGDIAPI WINBOOL WINAPI SetWorldTransform(HDC hdc,CONST XFORM *lpxf); + WINGDIAPI WINBOOL WINAPI ModifyWorldTransform(HDC hdc,CONST XFORM *lpxf,DWORD mode); + WINGDIAPI WINBOOL WINAPI CombineTransform(LPXFORM lpxfOut,CONST XFORM *lpxf1,CONST XFORM *lpxf2); + WINGDIAPI HBITMAP WINAPI CreateDIBSection(HDC hdc,CONST BITMAPINFO *lpbmi,UINT usage,VOID **ppvBits,HANDLE hSection,DWORD offset); + WINGDIAPI UINT WINAPI GetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,RGBQUAD *prgbq); + WINGDIAPI UINT WINAPI SetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,CONST RGBQUAD *prgbq); + +#define CA_NEGATIVE 0x0001 +#define CA_LOG_FILTER 0x0002 + +#define ILLUMINANT_DEVICE_DEFAULT 0 +#define ILLUMINANT_A 1 +#define ILLUMINANT_B 2 +#define ILLUMINANT_C 3 +#define ILLUMINANT_D50 4 +#define ILLUMINANT_D55 5 +#define ILLUMINANT_D65 6 +#define ILLUMINANT_D75 7 +#define ILLUMINANT_F2 8 +#define ILLUMINANT_MAX_INDEX ILLUMINANT_F2 + +#define ILLUMINANT_TUNGSTEN ILLUMINANT_A +#define ILLUMINANT_DAYLIGHT ILLUMINANT_C +#define ILLUMINANT_FLUORESCENT ILLUMINANT_F2 +#define ILLUMINANT_NTSC ILLUMINANT_C + +#define RGB_GAMMA_MIN (WORD)02500 +#define RGB_GAMMA_MAX (WORD)65000 + +#define REFERENCE_WHITE_MIN (WORD)6000 +#define REFERENCE_WHITE_MAX (WORD)10000 +#define REFERENCE_BLACK_MIN (WORD)0 +#define REFERENCE_BLACK_MAX (WORD)4000 + +#define COLOR_ADJ_MIN (SHORT)-100 +#define COLOR_ADJ_MAX (SHORT)100 + + typedef struct tagCOLORADJUSTMENT { + WORD caSize; + WORD caFlags; + WORD caIlluminantIndex; + WORD caRedGamma; + WORD caGreenGamma; + WORD caBlueGamma; + WORD caReferenceBlack; + WORD caReferenceWhite; + SHORT caContrast; + SHORT caBrightness; + SHORT caColorfulness; + SHORT caRedGreenTint; + } COLORADJUSTMENT,*PCOLORADJUSTMENT,*LPCOLORADJUSTMENT; + + WINGDIAPI WINBOOL WINAPI SetColorAdjustment(HDC hdc,CONST COLORADJUSTMENT *lpca); + WINGDIAPI WINBOOL WINAPI GetColorAdjustment(HDC hdc,LPCOLORADJUSTMENT lpca); + WINGDIAPI HPALETTE WINAPI CreateHalftonePalette(HDC hdc); + + typedef WINBOOL (CALLBACK *ABORTPROC)(HDC,int); + + typedef struct _DOCINFOA { + int cbSize; + LPCSTR lpszDocName; + LPCSTR lpszOutput; + LPCSTR lpszDatatype; + DWORD fwType; + } DOCINFOA,*LPDOCINFOA; + + typedef struct _DOCINFOW { + int cbSize; + LPCWSTR lpszDocName; + LPCWSTR lpszOutput; + LPCWSTR lpszDatatype; + DWORD fwType; + } DOCINFOW,*LPDOCINFOW; + +#ifdef UNICODE + typedef DOCINFOW DOCINFO; + typedef LPDOCINFOW LPDOCINFO; +#else + typedef DOCINFOA DOCINFO; + typedef LPDOCINFOA LPDOCINFO; +#endif + +#define DI_APPBANDING 0x00000001 +#define DI_ROPS_READ_DESTINATION 0x00000002 + +#ifdef UNICODE +#define StartDoc StartDocW +#define GetObject GetObjectW +#define TextOut TextOutW +#define ExtTextOut ExtTextOutW +#define PolyTextOut PolyTextOutW +#define GetTextFace GetTextFaceW +#else +#define StartDoc StartDocA +#define GetObject GetObjectA +#define TextOut TextOutA +#define ExtTextOut ExtTextOutA +#define PolyTextOut PolyTextOutA +#define GetTextFace GetTextFaceA +#endif + + WINGDIAPI int WINAPI StartDocA(HDC hdc,CONST DOCINFOA *lpdi); + WINGDIAPI int WINAPI StartDocW(HDC hdc,CONST DOCINFOW *lpdi); + WINGDIAPI int WINAPI EndDoc(HDC hdc); + WINGDIAPI int WINAPI StartPage(HDC hdc); + WINGDIAPI int WINAPI EndPage(HDC hdc); + WINGDIAPI int WINAPI AbortDoc(HDC hdc); + WINGDIAPI int WINAPI SetAbortProc(HDC hdc,ABORTPROC proc); + WINGDIAPI WINBOOL WINAPI AbortPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI ArcTo(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); + WINGDIAPI WINBOOL WINAPI BeginPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI CloseFigure(HDC hdc); + WINGDIAPI WINBOOL WINAPI EndPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI FillPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI FlattenPath(HDC hdc); + WINGDIAPI int WINAPI GetPath(HDC hdc,LPPOINT apt,LPBYTE aj,int cpt); + WINGDIAPI HRGN WINAPI PathToRegion(HDC hdc); + WINGDIAPI WINBOOL WINAPI PolyDraw(HDC hdc,CONST POINT *apt,CONST BYTE *aj,int cpt); + WINGDIAPI WINBOOL WINAPI SelectClipPath(HDC hdc,int mode); + WINGDIAPI int WINAPI SetArcDirection(HDC hdc,int dir); + WINGDIAPI WINBOOL WINAPI SetMiterLimit(HDC hdc,FLOAT limit,PFLOAT old); + WINGDIAPI WINBOOL WINAPI StrokeAndFillPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI StrokePath(HDC hdc); + WINGDIAPI WINBOOL WINAPI WidenPath(HDC hdc); + WINGDIAPI HPEN WINAPI ExtCreatePen(DWORD iPenStyle,DWORD cWidth,CONST LOGBRUSH *plbrush,DWORD cStyle,CONST DWORD *pstyle); + WINGDIAPI WINBOOL WINAPI GetMiterLimit(HDC hdc,PFLOAT plimit); + WINGDIAPI int WINAPI GetArcDirection(HDC hdc); + WINGDIAPI int WINAPI GetObjectA(HANDLE h,int c,LPVOID pv); + WINGDIAPI int WINAPI GetObjectW(HANDLE h,int c,LPVOID pv); + WINGDIAPI WINBOOL WINAPI MoveToEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI TextOutA(HDC hdc,int x,int y,LPCSTR lpString,int c); + WINGDIAPI WINBOOL WINAPI TextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int c); + WINGDIAPI WINBOOL WINAPI ExtTextOutA(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCSTR lpString,UINT c,CONST INT *lpDx); + WINGDIAPI WINBOOL WINAPI ExtTextOutW(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCWSTR lpString,UINT c,CONST INT *lpDx); + WINGDIAPI WINBOOL WINAPI PolyTextOutA(HDC hdc,CONST POLYTEXTA *ppt,int nstrings); + WINGDIAPI WINBOOL WINAPI PolyTextOutW(HDC hdc,CONST POLYTEXTW *ppt,int nstrings); + WINGDIAPI HRGN WINAPI CreatePolygonRgn(CONST POINT *pptl,int cPoint,int iMode); + WINGDIAPI WINBOOL WINAPI DPtoLP(HDC hdc,LPPOINT lppt,int c); + WINGDIAPI WINBOOL WINAPI LPtoDP(HDC hdc,LPPOINT lppt,int c); + WINGDIAPI WINBOOL WINAPI Polygon(HDC hdc,CONST POINT *apt,int cpt); + WINGDIAPI WINBOOL WINAPI Polyline(HDC hdc,CONST POINT *apt,int cpt); + WINGDIAPI WINBOOL WINAPI PolyBezier(HDC hdc,CONST POINT *apt,DWORD cpt); + WINGDIAPI WINBOOL WINAPI PolyBezierTo(HDC hdc,CONST POINT *apt,DWORD cpt); + WINGDIAPI WINBOOL WINAPI PolylineTo(HDC hdc,CONST POINT *apt,DWORD cpt); + WINGDIAPI WINBOOL WINAPI SetViewportExtEx(HDC hdc,int x,int y,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI SetWindowExtEx(HDC hdc,int x,int y,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI OffsetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI OffsetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI ScaleViewportExtEx(HDC hdc,int xn,int dx,int yn,int yd,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI ScaleWindowExtEx(HDC hdc,int xn,int xd,int yn,int yd,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetBitmapDimensionEx(HBITMAP hbm,int w,int h,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetBrushOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI int WINAPI GetTextFaceA(HDC hdc,int c,LPSTR lpName); + WINGDIAPI int WINAPI GetTextFaceW(HDC hdc,int c,LPWSTR lpName); + +#define FONTMAPPER_MAX 10 + + typedef struct tagKERNINGPAIR { + WORD wFirst; + WORD wSecond; + int iKernAmount; + } KERNINGPAIR,*LPKERNINGPAIR; + +#ifdef UNICODE +#define GetKerningPairs GetKerningPairsW +#else +#define GetKerningPairs GetKerningPairsA +#endif + + WINGDIAPI DWORD WINAPI GetKerningPairsA(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); + WINGDIAPI DWORD WINAPI GetKerningPairsW(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); + WINGDIAPI WINBOOL WINAPI GetDCOrgEx(HDC hdc,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI FixBrushOrgEx(HDC hdc,int x,int y,LPPOINT ptl); + WINGDIAPI WINBOOL WINAPI UnrealizeObject(HGDIOBJ h); + WINGDIAPI WINBOOL WINAPI GdiFlush(); + WINGDIAPI DWORD WINAPI GdiSetBatchLimit(DWORD dw); + WINGDIAPI DWORD WINAPI GdiGetBatchLimit(); + +#define ICM_OFF 1 +#define ICM_ON 2 +#define ICM_QUERY 3 +#define ICM_DONE_OUTSIDEDC 4 + + typedef int (CALLBACK *ICMENUMPROCA)(LPSTR,LPARAM); + typedef int (CALLBACK *ICMENUMPROCW)(LPWSTR,LPARAM); + +#ifdef UNICODE +#define ICMENUMPROC ICMENUMPROCW +#define EnumICMProfiles EnumICMProfilesW +#define UpdateICMRegKey UpdateICMRegKeyW +#define GetLogColorSpace GetLogColorSpaceW +#define CreateColorSpace CreateColorSpaceW +#define GetICMProfile GetICMProfileW +#define SetICMProfile SetICMProfileW +#else +#define ICMENUMPROC ICMENUMPROCA +#define EnumICMProfiles EnumICMProfilesA +#define UpdateICMRegKey UpdateICMRegKeyA +#define GetLogColorSpace GetLogColorSpaceA +#define CreateColorSpace CreateColorSpaceA +#define GetICMProfile GetICMProfileA +#define SetICMProfile SetICMProfileA +#endif + + WINGDIAPI int WINAPI SetICMMode(HDC hdc,int mode); + WINGDIAPI WINBOOL WINAPI CheckColorsInGamut(HDC hdc,LPVOID lpRGBTriple,LPVOID dlpBuffer,DWORD nCount); + WINGDIAPI HCOLORSPACE WINAPI GetColorSpace(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetLogColorSpaceA(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEA lpBuffer,DWORD nSize); + WINGDIAPI WINBOOL WINAPI GetLogColorSpaceW(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEW lpBuffer,DWORD nSize); + WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceA(LPLOGCOLORSPACEA lplcs); + WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceW(LPLOGCOLORSPACEW lplcs); + WINGDIAPI HCOLORSPACE WINAPI SetColorSpace(HDC hdc,HCOLORSPACE hcs); + WINGDIAPI WINBOOL WINAPI DeleteColorSpace(HCOLORSPACE hcs); + WINGDIAPI WINBOOL WINAPI GetICMProfileA(HDC hdc,LPDWORD pBufSize,LPSTR pszFilename); + WINGDIAPI WINBOOL WINAPI GetICMProfileW(HDC hdc,LPDWORD pBufSize,LPWSTR pszFilename); + WINGDIAPI WINBOOL WINAPI SetICMProfileA(HDC hdc,LPSTR lpFileName); + WINGDIAPI WINBOOL WINAPI SetICMProfileW(HDC hdc,LPWSTR lpFileName); + WINGDIAPI WINBOOL WINAPI GetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); + WINGDIAPI WINBOOL WINAPI SetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); + WINGDIAPI WINBOOL WINAPI ColorMatchToTarget(HDC hdc,HDC hdcTarget,DWORD action); + WINGDIAPI int WINAPI EnumICMProfilesA(HDC hdc,ICMENUMPROCA proc,LPARAM param); + WINGDIAPI int WINAPI EnumICMProfilesW(HDC hdc,ICMENUMPROCW proc,LPARAM param); + WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyA(DWORD reserved,LPSTR lpszCMID,LPSTR lpszFileName,UINT command); + WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyW(DWORD reserved,LPWSTR lpszCMID,LPWSTR lpszFileName,UINT command); + WINGDIAPI WINBOOL WINAPI ColorCorrectPalette(HDC hdc,HPALETTE hPal,DWORD deFirst,DWORD num); + +#ifndef NOMETAFILE + +#define ENHMETA_SIGNATURE 0x464D4520 +#define ENHMETA_STOCK_OBJECT 0x80000000 + +#define EMR_HEADER 1 +#define EMR_POLYBEZIER 2 +#define EMR_POLYGON 3 +#define EMR_POLYLINE 4 +#define EMR_POLYBEZIERTO 5 +#define EMR_POLYLINETO 6 +#define EMR_POLYPOLYLINE 7 +#define EMR_POLYPOLYGON 8 +#define EMR_SETWINDOWEXTEX 9 +#define EMR_SETWINDOWORGEX 10 +#define EMR_SETVIEWPORTEXTEX 11 +#define EMR_SETVIEWPORTORGEX 12 +#define EMR_SETBRUSHORGEX 13 +#define EMR_EOF 14 +#define EMR_SETPIXELV 15 +#define EMR_SETMAPPERFLAGS 16 +#define EMR_SETMAPMODE 17 +#define EMR_SETBKMODE 18 +#define EMR_SETPOLYFILLMODE 19 +#define EMR_SETROP2 20 +#define EMR_SETSTRETCHBLTMODE 21 +#define EMR_SETTEXTALIGN 22 +#define EMR_SETCOLORADJUSTMENT 23 +#define EMR_SETTEXTCOLOR 24 +#define EMR_SETBKCOLOR 25 +#define EMR_OFFSETCLIPRGN 26 +#define EMR_MOVETOEX 27 +#define EMR_SETMETARGN 28 +#define EMR_EXCLUDECLIPRECT 29 +#define EMR_INTERSECTCLIPRECT 30 +#define EMR_SCALEVIEWPORTEXTEX 31 +#define EMR_SCALEWINDOWEXTEX 32 +#define EMR_SAVEDC 33 +#define EMR_RESTOREDC 34 +#define EMR_SETWORLDTRANSFORM 35 +#define EMR_MODIFYWORLDTRANSFORM 36 +#define EMR_SELECTOBJECT 37 +#define EMR_CREATEPEN 38 +#define EMR_CREATEBRUSHINDIRECT 39 +#define EMR_DELETEOBJECT 40 +#define EMR_ANGLEARC 41 +#define EMR_ELLIPSE 42 +#define EMR_RECTANGLE 43 +#define EMR_ROUNDRECT 44 +#define EMR_ARC 45 +#define EMR_CHORD 46 +#define EMR_PIE 47 +#define EMR_SELECTPALETTE 48 +#define EMR_CREATEPALETTE 49 +#define EMR_SETPALETTEENTRIES 50 +#define EMR_RESIZEPALETTE 51 +#define EMR_REALIZEPALETTE 52 +#define EMR_EXTFLOODFILL 53 +#define EMR_LINETO 54 +#define EMR_ARCTO 55 +#define EMR_POLYDRAW 56 +#define EMR_SETARCDIRECTION 57 +#define EMR_SETMITERLIMIT 58 +#define EMR_BEGINPATH 59 +#define EMR_ENDPATH 60 +#define EMR_CLOSEFIGURE 61 +#define EMR_FILLPATH 62 +#define EMR_STROKEANDFILLPATH 63 +#define EMR_STROKEPATH 64 +#define EMR_FLATTENPATH 65 +#define EMR_WIDENPATH 66 +#define EMR_SELECTCLIPPATH 67 +#define EMR_ABORTPATH 68 + +#define EMR_GDICOMMENT 70 +#define EMR_FILLRGN 71 +#define EMR_FRAMERGN 72 +#define EMR_INVERTRGN 73 +#define EMR_PAINTRGN 74 +#define EMR_EXTSELECTCLIPRGN 75 +#define EMR_BITBLT 76 +#define EMR_STRETCHBLT 77 +#define EMR_MASKBLT 78 +#define EMR_PLGBLT 79 +#define EMR_SETDIBITSTODEVICE 80 +#define EMR_STRETCHDIBITS 81 +#define EMR_EXTCREATEFONTINDIRECTW 82 +#define EMR_EXTTEXTOUTA 83 +#define EMR_EXTTEXTOUTW 84 +#define EMR_POLYBEZIER16 85 +#define EMR_POLYGON16 86 +#define EMR_POLYLINE16 87 +#define EMR_POLYBEZIERTO16 88 +#define EMR_POLYLINETO16 89 +#define EMR_POLYPOLYLINE16 90 +#define EMR_POLYPOLYGON16 91 +#define EMR_POLYDRAW16 92 +#define EMR_CREATEMONOBRUSH 93 +#define EMR_CREATEDIBPATTERNBRUSHPT 94 +#define EMR_EXTCREATEPEN 95 +#define EMR_POLYTEXTOUTA 96 +#define EMR_POLYTEXTOUTW 97 + +#define EMR_SETICMMODE 98 +#define EMR_CREATECOLORSPACE 99 +#define EMR_SETCOLORSPACE 100 +#define EMR_DELETECOLORSPACE 101 +#define EMR_GLSRECORD 102 +#define EMR_GLSBOUNDEDRECORD 103 +#define EMR_PIXELFORMAT 104 +#define EMR_RESERVED_105 105 +#define EMR_RESERVED_106 106 +#define EMR_RESERVED_107 107 +#define EMR_RESERVED_108 108 +#define EMR_RESERVED_109 109 +#define EMR_RESERVED_110 110 +#define EMR_COLORCORRECTPALETTE 111 +#define EMR_SETICMPROFILEA 112 +#define EMR_SETICMPROFILEW 113 +#define EMR_ALPHABLEND 114 +#define EMR_SETLAYOUT 115 +#define EMR_TRANSPARENTBLT 116 +#define EMR_RESERVED_117 117 +#define EMR_GRADIENTFILL 118 +#define EMR_RESERVED_119 119 +#define EMR_RESERVED_120 120 +#define EMR_COLORMATCHTOTARGETW 121 +#define EMR_CREATECOLORSPACEW 122 + +#define EMR_MIN 1 + +#define EMR_MAX 122 + + typedef struct tagEMR { + DWORD iType; + DWORD nSize; + } EMR,*PEMR; + + typedef struct tagEMRTEXT { + POINTL ptlReference; + DWORD nChars; + DWORD offString; + DWORD fOptions; + RECTL rcl; + DWORD offDx; + } EMRTEXT,*PEMRTEXT; + + typedef struct tagABORTPATH { + EMR emr; + } EMRABORTPATH,*PEMRABORTPATH,EMRBEGINPATH,*PEMRBEGINPATH,EMRENDPATH,*PEMRENDPATH,EMRCLOSEFIGURE,*PEMRCLOSEFIGURE,EMRFLATTENPATH,*PEMRFLATTENPATH,EMRWIDENPATH,*PEMRWIDENPATH,EMRSETMETARGN,*PEMRSETMETARGN,EMRSAVEDC,*PEMRSAVEDC,EMRREALIZEPALETTE,*PEMRREALIZEPALETTE; + + typedef struct tagEMRSELECTCLIPPATH { + EMR emr; + DWORD iMode; + } EMRSELECTCLIPPATH,*PEMRSELECTCLIPPATH,EMRSETBKMODE,*PEMRSETBKMODE,EMRSETMAPMODE,*PEMRSETMAPMODE,EMRSETLAYOUT,*PEMRSETLAYOUT, + EMRSETPOLYFILLMODE,*PEMRSETPOLYFILLMODE,EMRSETROP2,*PEMRSETROP2,EMRSETSTRETCHBLTMODE,*PEMRSETSTRETCHBLTMODE,EMRSETICMMODE, + *PEMRSETICMMODE,EMRSETTEXTALIGN,*PEMRSETTEXTALIGN; + + typedef struct tagEMRSETMITERLIMIT { + EMR emr; + FLOAT eMiterLimit; + } EMRSETMITERLIMIT,*PEMRSETMITERLIMIT; + + typedef struct tagEMRRESTOREDC { + EMR emr; + LONG iRelative; + } EMRRESTOREDC,*PEMRRESTOREDC; + + typedef struct tagEMRSETARCDIRECTION { + EMR emr; + DWORD iArcDirection; + + } EMRSETARCDIRECTION,*PEMRSETARCDIRECTION; + + typedef struct tagEMRSETMAPPERFLAGS { + EMR emr; + DWORD dwFlags; + } EMRSETMAPPERFLAGS,*PEMRSETMAPPERFLAGS; + + typedef struct tagEMRSETTEXTCOLOR { + EMR emr; + COLORREF crColor; + } EMRSETBKCOLOR,*PEMRSETBKCOLOR,EMRSETTEXTCOLOR,*PEMRSETTEXTCOLOR; + + typedef struct tagEMRSELECTOBJECT { + EMR emr; + DWORD ihObject; + } EMRSELECTOBJECT,*PEMRSELECTOBJECT,EMRDELETEOBJECT,*PEMRDELETEOBJECT; + + typedef struct tagEMRSELECTPALETTE { + EMR emr; + DWORD ihPal; + } EMRSELECTPALETTE,*PEMRSELECTPALETTE; + + typedef struct tagEMRRESIZEPALETTE { + EMR emr; + DWORD ihPal; + DWORD cEntries; + } EMRRESIZEPALETTE,*PEMRRESIZEPALETTE; + + typedef struct tagEMRSETPALETTEENTRIES { + EMR emr; + DWORD ihPal; + DWORD iStart; + DWORD cEntries; + PALETTEENTRY aPalEntries[1]; + } EMRSETPALETTEENTRIES,*PEMRSETPALETTEENTRIES; + + typedef struct tagEMRSETCOLORADJUSTMENT { + EMR emr; + COLORADJUSTMENT ColorAdjustment; + } EMRSETCOLORADJUSTMENT,*PEMRSETCOLORADJUSTMENT; + + typedef struct tagEMRGDICOMMENT { + EMR emr; + DWORD cbData; + BYTE Data[1]; + } EMRGDICOMMENT,*PEMRGDICOMMENT; + + typedef struct tagEMREOF { + EMR emr; + DWORD nPalEntries; + DWORD offPalEntries; + DWORD nSizeLast; + } EMREOF,*PEMREOF; + + typedef struct tagEMRLINETO { + EMR emr; + POINTL ptl; + } EMRLINETO,*PEMRLINETO,EMRMOVETOEX,*PEMRMOVETOEX; + + typedef struct tagEMROFFSETCLIPRGN { + EMR emr; + POINTL ptlOffset; + } EMROFFSETCLIPRGN,*PEMROFFSETCLIPRGN; + + typedef struct tagEMRFILLPATH { + EMR emr; + RECTL rclBounds; + } EMRFILLPATH,*PEMRFILLPATH,EMRSTROKEANDFILLPATH,*PEMRSTROKEANDFILLPATH,EMRSTROKEPATH,*PEMRSTROKEPATH; + + typedef struct tagEMREXCLUDECLIPRECT { + EMR emr; + RECTL rclClip; + } EMREXCLUDECLIPRECT,*PEMREXCLUDECLIPRECT,EMRINTERSECTCLIPRECT,*PEMRINTERSECTCLIPRECT; + + typedef struct tagEMRSETVIEWPORTORGEX { + EMR emr; + POINTL ptlOrigin; + } EMRSETVIEWPORTORGEX,*PEMRSETVIEWPORTORGEX,EMRSETWINDOWORGEX,*PEMRSETWINDOWORGEX,EMRSETBRUSHORGEX,*PEMRSETBRUSHORGEX; + + typedef struct tagEMRSETVIEWPORTEXTEX { + EMR emr; + SIZEL szlExtent; + } EMRSETVIEWPORTEXTEX,*PEMRSETVIEWPORTEXTEX,EMRSETWINDOWEXTEX,*PEMRSETWINDOWEXTEX; + + typedef struct tagEMRSCALEVIEWPORTEXTEX { + EMR emr; + LONG xNum; + LONG xDenom; + LONG yNum; + LONG yDenom; + } EMRSCALEVIEWPORTEXTEX,*PEMRSCALEVIEWPORTEXTEX,EMRSCALEWINDOWEXTEX,*PEMRSCALEWINDOWEXTEX; + + typedef struct tagEMRSETWORLDTRANSFORM { + EMR emr; + XFORM xform; + } EMRSETWORLDTRANSFORM,*PEMRSETWORLDTRANSFORM; + + typedef struct tagEMRMODIFYWORLDTRANSFORM { + EMR emr; + XFORM xform; + DWORD iMode; + } EMRMODIFYWORLDTRANSFORM,*PEMRMODIFYWORLDTRANSFORM; + + typedef struct tagEMRSETPIXELV { + EMR emr; + POINTL ptlPixel; + COLORREF crColor; + } EMRSETPIXELV,*PEMRSETPIXELV; + + typedef struct tagEMREXTFLOODFILL { + EMR emr; + POINTL ptlStart; + COLORREF crColor; + DWORD iMode; + } EMREXTFLOODFILL,*PEMREXTFLOODFILL; + + typedef struct tagEMRELLIPSE { + EMR emr; + RECTL rclBox; + } EMRELLIPSE,*PEMRELLIPSE,EMRRECTANGLE,*PEMRRECTANGLE; + + typedef struct tagEMRROUNDRECT { + EMR emr; + RECTL rclBox; + SIZEL szlCorner; + } EMRROUNDRECT,*PEMRROUNDRECT; + + typedef struct tagEMRARC { + EMR emr; + RECTL rclBox; + POINTL ptlStart; + POINTL ptlEnd; + } EMRARC,*PEMRARC,EMRARCTO,*PEMRARCTO,EMRCHORD,*PEMRCHORD,EMRPIE,*PEMRPIE; + + typedef struct tagEMRANGLEARC { + EMR emr; + POINTL ptlCenter; + DWORD nRadius; + FLOAT eStartAngle; + FLOAT eSweepAngle; + } EMRANGLEARC,*PEMRANGLEARC; + + typedef struct tagEMRPOLYLINE { + EMR emr; + RECTL rclBounds; + DWORD cptl; + POINTL aptl[1]; + } EMRPOLYLINE,*PEMRPOLYLINE,EMRPOLYBEZIER,*PEMRPOLYBEZIER,EMRPOLYGON,*PEMRPOLYGON,EMRPOLYBEZIERTO,*PEMRPOLYBEZIERTO,EMRPOLYLINETO,*PEMRPOLYLINETO; + + typedef struct tagEMRPOLYLINE16 { + EMR emr; + RECTL rclBounds; + DWORD cpts; + POINTS apts[1]; + } EMRPOLYLINE16,*PEMRPOLYLINE16,EMRPOLYBEZIER16,*PEMRPOLYBEZIER16,EMRPOLYGON16,*PEMRPOLYGON16,EMRPOLYBEZIERTO16,*PEMRPOLYBEZIERTO16,EMRPOLYLINETO16,*PEMRPOLYLINETO16; + + typedef struct tagEMRPOLYDRAW { + EMR emr; + RECTL rclBounds; + DWORD cptl; + POINTL aptl[1]; + BYTE abTypes[1]; + } EMRPOLYDRAW,*PEMRPOLYDRAW; + + typedef struct tagEMRPOLYDRAW16 { + EMR emr; + RECTL rclBounds; + DWORD cpts; + POINTS apts[1]; + BYTE abTypes[1]; + } EMRPOLYDRAW16,*PEMRPOLYDRAW16; + + typedef struct tagEMRPOLYPOLYLINE { + EMR emr; + RECTL rclBounds; + DWORD nPolys; + DWORD cptl; + DWORD aPolyCounts[1]; + POINTL aptl[1]; + } EMRPOLYPOLYLINE,*PEMRPOLYPOLYLINE,EMRPOLYPOLYGON,*PEMRPOLYPOLYGON; + + typedef struct tagEMRPOLYPOLYLINE16 { + EMR emr; + RECTL rclBounds; + DWORD nPolys; + DWORD cpts; + DWORD aPolyCounts[1]; + POINTS apts[1]; + } EMRPOLYPOLYLINE16,*PEMRPOLYPOLYLINE16,EMRPOLYPOLYGON16,*PEMRPOLYPOLYGON16; + + typedef struct tagEMRINVERTRGN { + EMR emr; + RECTL rclBounds; + DWORD cbRgnData; + BYTE RgnData[1]; + } EMRINVERTRGN,*PEMRINVERTRGN,EMRPAINTRGN,*PEMRPAINTRGN; + + typedef struct tagEMRFILLRGN { + EMR emr; + RECTL rclBounds; + DWORD cbRgnData; + DWORD ihBrush; + BYTE RgnData[1]; + } EMRFILLRGN,*PEMRFILLRGN; + + typedef struct tagEMRFRAMERGN { + EMR emr; + RECTL rclBounds; + DWORD cbRgnData; + DWORD ihBrush; + SIZEL szlStroke; + BYTE RgnData[1]; + } EMRFRAMERGN,*PEMRFRAMERGN; + + typedef struct tagEMREXTSELECTCLIPRGN { + EMR emr; + DWORD cbRgnData; + DWORD iMode; + BYTE RgnData[1]; + } EMREXTSELECTCLIPRGN,*PEMREXTSELECTCLIPRGN; + + typedef struct tagEMREXTTEXTOUTA { + EMR emr; + RECTL rclBounds; + DWORD iGraphicsMode; + FLOAT exScale; + FLOAT eyScale; + EMRTEXT emrtext; + } EMREXTTEXTOUTA,*PEMREXTTEXTOUTA,EMREXTTEXTOUTW,*PEMREXTTEXTOUTW; + + typedef struct tagEMRPOLYTEXTOUTA { + EMR emr; + RECTL rclBounds; + DWORD iGraphicsMode; + FLOAT exScale; + FLOAT eyScale; + LONG cStrings; + EMRTEXT aemrtext[1]; + } EMRPOLYTEXTOUTA,*PEMRPOLYTEXTOUTA,EMRPOLYTEXTOUTW,*PEMRPOLYTEXTOUTW; + + typedef struct tagEMRBITBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + } EMRBITBLT,*PEMRBITBLT; + + typedef struct tagEMRSTRETCHBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG cxSrc; + LONG cySrc; + } EMRSTRETCHBLT,*PEMRSTRETCHBLT; + + typedef struct tagEMRMASKBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG xMask; + LONG yMask; + DWORD iUsageMask; + DWORD offBmiMask; + DWORD cbBmiMask; + DWORD offBitsMask; + DWORD cbBitsMask; + } EMRMASKBLT,*PEMRMASKBLT; + + typedef struct tagEMRPLGBLT { + EMR emr; + RECTL rclBounds; + POINTL aptlDest[3]; + LONG xSrc; + LONG ySrc; + LONG cxSrc; + LONG cySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG xMask; + LONG yMask; + DWORD iUsageMask; + DWORD offBmiMask; + DWORD cbBmiMask; + DWORD offBitsMask; + DWORD cbBitsMask; + } EMRPLGBLT,*PEMRPLGBLT; + + typedef struct tagEMRSETDIBITSTODEVICE { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG xSrc; + LONG ySrc; + LONG cxSrc; + LONG cySrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + DWORD iUsageSrc; + DWORD iStartScan; + DWORD cScans; + } EMRSETDIBITSTODEVICE,*PEMRSETDIBITSTODEVICE; + + typedef struct tagEMRSTRETCHDIBITS { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG xSrc; + LONG ySrc; + LONG cxSrc; + LONG cySrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + DWORD iUsageSrc; + DWORD dwRop; + LONG cxDest; + LONG cyDest; + } EMRSTRETCHDIBITS,*PEMRSTRETCHDIBITS; + + typedef struct tagEMREXTCREATEFONTINDIRECTW { + EMR emr; + DWORD ihFont; + EXTLOGFONTW elfw; + } EMREXTCREATEFONTINDIRECTW,*PEMREXTCREATEFONTINDIRECTW; + + typedef struct tagEMRCREATEPALETTE { + EMR emr; + DWORD ihPal; + LOGPALETTE lgpl; + } EMRCREATEPALETTE,*PEMRCREATEPALETTE; + + typedef struct tagEMRCREATEPEN { + EMR emr; + DWORD ihPen; + LOGPEN lopn; + } EMRCREATEPEN,*PEMRCREATEPEN; + + typedef struct tagEMREXTCREATEPEN { + EMR emr; + DWORD ihPen; + DWORD offBmi; + DWORD cbBmi; + DWORD offBits; + DWORD cbBits; + EXTLOGPEN elp; + } EMREXTCREATEPEN,*PEMREXTCREATEPEN; + + typedef struct tagEMRCREATEBRUSHINDIRECT { + EMR emr; + DWORD ihBrush; + LOGBRUSH32 lb; + } EMRCREATEBRUSHINDIRECT,*PEMRCREATEBRUSHINDIRECT; + + typedef struct tagEMRCREATEMONOBRUSH { + EMR emr; + DWORD ihBrush; + DWORD iUsage; + DWORD offBmi; + DWORD cbBmi; + DWORD offBits; + DWORD cbBits; + } EMRCREATEMONOBRUSH,*PEMRCREATEMONOBRUSH; + + typedef struct tagEMRCREATEDIBPATTERNBRUSHPT { + EMR emr; + DWORD ihBrush; + DWORD iUsage; + DWORD offBmi; + DWORD cbBmi; + DWORD offBits; + DWORD cbBits; + } EMRCREATEDIBPATTERNBRUSHPT,*PEMRCREATEDIBPATTERNBRUSHPT; + + typedef struct tagEMRFORMAT { + DWORD dSignature; + DWORD nVersion; + DWORD cbData; + DWORD offData; + } EMRFORMAT,*PEMRFORMAT; + + typedef struct tagEMRGLSRECORD { + EMR emr; + DWORD cbData; + BYTE Data[1]; + } EMRGLSRECORD,*PEMRGLSRECORD; + + typedef struct tagEMRGLSBOUNDEDRECORD { + EMR emr; + RECTL rclBounds; + DWORD cbData; + BYTE Data[1]; + } EMRGLSBOUNDEDRECORD,*PEMRGLSBOUNDEDRECORD; + + typedef struct tagEMRPIXELFORMAT { + EMR emr; + PIXELFORMATDESCRIPTOR pfd; + } EMRPIXELFORMAT,*PEMRPIXELFORMAT; + + typedef struct tagEMRCREATECOLORSPACE { + EMR emr; + DWORD ihCS; + LOGCOLORSPACEA lcs; + } EMRCREATECOLORSPACE,*PEMRCREATECOLORSPACE; + + typedef struct tagEMRSETCOLORSPACE { + EMR emr; + DWORD ihCS; + } EMRSETCOLORSPACE,*PEMRSETCOLORSPACE,EMRSELECTCOLORSPACE,*PEMRSELECTCOLORSPACE,EMRDELETECOLORSPACE,*PEMRDELETECOLORSPACE; + + typedef struct tagEMREXTESCAPE { + EMR emr; + INT iEscape; + INT cbEscData; + BYTE EscData[1]; + } EMREXTESCAPE,*PEMREXTESCAPE,EMRDRAWESCAPE,*PEMRDRAWESCAPE; + + typedef struct tagEMRNAMEDESCAPE { + EMR emr; + INT iEscape; + INT cbDriver; + INT cbEscData; + BYTE EscData[1]; + } EMRNAMEDESCAPE,*PEMRNAMEDESCAPE; + +#define SETICMPROFILE_EMBEDED 0x00000001 + + typedef struct tagEMRSETICMPROFILE { + EMR emr; + DWORD dwFlags; + DWORD cbName; + DWORD cbData; + BYTE Data[1]; + } EMRSETICMPROFILE,*PEMRSETICMPROFILE,EMRSETICMPROFILEA,*PEMRSETICMPROFILEA,EMRSETICMPROFILEW,*PEMRSETICMPROFILEW; + +#define CREATECOLORSPACE_EMBEDED 0x00000001 + + typedef struct tagEMRCREATECOLORSPACEW { + EMR emr; + DWORD ihCS; + LOGCOLORSPACEW lcs; + DWORD dwFlags; + DWORD cbData; + BYTE Data[1]; + } EMRCREATECOLORSPACEW,*PEMRCREATECOLORSPACEW; + +#define COLORMATCHTOTARGET_EMBEDED 0x00000001 + + typedef struct tagCOLORMATCHTOTARGET { + EMR emr; + DWORD dwAction; + DWORD dwFlags; + DWORD cbName; + DWORD cbData; + BYTE Data[1]; + } EMRCOLORMATCHTOTARGET,*PEMRCOLORMATCHTOTARGET; + + typedef struct tagCOLORCORRECTPALETTE { + EMR emr; + DWORD ihPalette; + DWORD nFirstEntry; + DWORD nPalEntries; + DWORD nReserved; + } EMRCOLORCORRECTPALETTE,*PEMRCOLORCORRECTPALETTE; + + typedef struct tagEMRALPHABLEND { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG cxSrc; + LONG cySrc; + } EMRALPHABLEND,*PEMRALPHABLEND; + + typedef struct tagEMRGRADIENTFILL { + EMR emr; + RECTL rclBounds; + DWORD nVer; + DWORD nTri; + ULONG ulMode; + TRIVERTEX Ver[1]; + } EMRGRADIENTFILL,*PEMRGRADIENTFILL; + + typedef struct tagEMRTRANSPARENTBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG cxSrc; + LONG cySrc; + } EMRTRANSPARENTBLT,*PEMRTRANSPARENTBLT; + +#define GDICOMMENT_IDENTIFIER 0x43494447 +#define GDICOMMENT_WINDOWS_METAFILE 0x80000001 +#define GDICOMMENT_BEGINGROUP 0x00000002 +#define GDICOMMENT_ENDGROUP 0x00000003 +#define GDICOMMENT_MULTIFORMATS 0x40000004 +#define EPS_SIGNATURE 0x46535045 +#define GDICOMMENT_UNICODE_STRING 0x00000040 +#define GDICOMMENT_UNICODE_END 0x00000080 +#endif + +#ifdef UNICODE +#define wglUseFontBitmaps wglUseFontBitmapsW +#else +#define wglUseFontBitmaps wglUseFontBitmapsA +#endif + + WINGDIAPI WINBOOL WINAPI wglCopyContext(HGLRC,HGLRC,UINT); + WINGDIAPI HGLRC WINAPI wglCreateContext(HDC); + WINGDIAPI HGLRC WINAPI wglCreateLayerContext(HDC,int); + WINGDIAPI WINBOOL WINAPI wglDeleteContext(HGLRC); + WINGDIAPI HGLRC WINAPI wglGetCurrentContext(VOID); + WINGDIAPI HDC WINAPI wglGetCurrentDC(VOID); + WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR); + WINGDIAPI WINBOOL WINAPI wglMakeCurrent(HDC,HGLRC); + WINGDIAPI WINBOOL WINAPI wglShareLists(HGLRC,HGLRC); + WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsA(HDC,DWORD,DWORD,DWORD); + WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsW(HDC,DWORD,DWORD,DWORD); + WINGDIAPI WINBOOL WINAPI SwapBuffers(HDC); + + typedef struct _POINTFLOAT { + FLOAT x; + FLOAT y; + } POINTFLOAT,*PPOINTFLOAT; + + typedef struct _GLYPHMETRICSFLOAT { + FLOAT gmfBlackBoxX; + FLOAT gmfBlackBoxY; + POINTFLOAT gmfptGlyphOrigin; + FLOAT gmfCellIncX; + FLOAT gmfCellIncY; + } GLYPHMETRICSFLOAT,*PGLYPHMETRICSFLOAT,*LPGLYPHMETRICSFLOAT; + +#define WGL_FONT_LINES 0 +#define WGL_FONT_POLYGONS 1 + +#ifdef UNICODE +#define wglUseFontOutlines wglUseFontOutlinesW +#else +#define wglUseFontOutlines wglUseFontOutlinesA +#endif + + WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesA(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); + WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesW(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); + + typedef struct tagLAYERPLANEDESCRIPTOR { + WORD nSize; + WORD nVersion; + DWORD dwFlags; + BYTE iPixelType; + BYTE cColorBits; + BYTE cRedBits; + BYTE cRedShift; + BYTE cGreenBits; + BYTE cGreenShift; + BYTE cBlueBits; + BYTE cBlueShift; + BYTE cAlphaBits; + BYTE cAlphaShift; + BYTE cAccumBits; + BYTE cAccumRedBits; + BYTE cAccumGreenBits; + BYTE cAccumBlueBits; + BYTE cAccumAlphaBits; + BYTE cDepthBits; + BYTE cStencilBits; + BYTE cAuxBuffers; + BYTE iLayerPlane; + BYTE bReserved; + COLORREF crTransparent; + } LAYERPLANEDESCRIPTOR,*PLAYERPLANEDESCRIPTOR,*LPLAYERPLANEDESCRIPTOR; + +#define LPD_DOUBLEBUFFER 0x00000001 +#define LPD_STEREO 0x00000002 +#define LPD_SUPPORT_GDI 0x00000010 +#define LPD_SUPPORT_OPENGL 0x00000020 +#define LPD_SHARE_DEPTH 0x00000040 +#define LPD_SHARE_STENCIL 0x00000080 +#define LPD_SHARE_ACCUM 0x00000100 +#define LPD_SWAP_EXCHANGE 0x00000200 +#define LPD_SWAP_COPY 0x00000400 +#define LPD_TRANSPARENT 0x00001000 + +#define LPD_TYPE_RGBA 0 +#define LPD_TYPE_COLORINDEX 1 + +#define WGL_SWAP_MAIN_PLANE 0x00000001 +#define WGL_SWAP_OVERLAY1 0x00000002 +#define WGL_SWAP_OVERLAY2 0x00000004 +#define WGL_SWAP_OVERLAY3 0x00000008 +#define WGL_SWAP_OVERLAY4 0x00000010 +#define WGL_SWAP_OVERLAY5 0x00000020 +#define WGL_SWAP_OVERLAY6 0x00000040 +#define WGL_SWAP_OVERLAY7 0x00000080 +#define WGL_SWAP_OVERLAY8 0x00000100 +#define WGL_SWAP_OVERLAY9 0x00000200 +#define WGL_SWAP_OVERLAY10 0x00000400 +#define WGL_SWAP_OVERLAY11 0x00000800 +#define WGL_SWAP_OVERLAY12 0x00001000 +#define WGL_SWAP_OVERLAY13 0x00002000 +#define WGL_SWAP_OVERLAY14 0x00004000 +#define WGL_SWAP_OVERLAY15 0x00008000 +#define WGL_SWAP_UNDERLAY1 0x00010000 +#define WGL_SWAP_UNDERLAY2 0x00020000 +#define WGL_SWAP_UNDERLAY3 0x00040000 +#define WGL_SWAP_UNDERLAY4 0x00080000 +#define WGL_SWAP_UNDERLAY5 0x00100000 +#define WGL_SWAP_UNDERLAY6 0x00200000 +#define WGL_SWAP_UNDERLAY7 0x00400000 +#define WGL_SWAP_UNDERLAY8 0x00800000 +#define WGL_SWAP_UNDERLAY9 0x01000000 +#define WGL_SWAP_UNDERLAY10 0x02000000 +#define WGL_SWAP_UNDERLAY11 0x04000000 +#define WGL_SWAP_UNDERLAY12 0x08000000 +#define WGL_SWAP_UNDERLAY13 0x10000000 +#define WGL_SWAP_UNDERLAY14 0x20000000 +#define WGL_SWAP_UNDERLAY15 0x40000000 + + WINGDIAPI WINBOOL WINAPI wglDescribeLayerPlane(HDC,int,int,UINT,LPLAYERPLANEDESCRIPTOR); + WINGDIAPI int WINAPI wglSetLayerPaletteEntries(HDC,int,int,int,CONST COLORREF *); + WINGDIAPI int WINAPI wglGetLayerPaletteEntries(HDC,int,int,int,COLORREF *); + WINGDIAPI WINBOOL WINAPI wglRealizeLayerPalette(HDC,int,WINBOOL); + WINGDIAPI WINBOOL WINAPI wglSwapLayerBuffers(HDC,UINT); + + typedef struct _WGLSWAP { + HDC hdc; + UINT uiFlags; + } WGLSWAP,*PWGLSWAP,*LPWGLSWAP; + +#define WGL_SWAPMULTIPLE_MAX 16 + + WINGDIAPI DWORD WINAPI wglSwapMultipleBuffers(UINT,CONST WGLSWAP *); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/winnls.h b/tcc/include/winapi/winnls.h index 296b4cb3..4f17c7a0 100644 --- a/tcc/include/winapi/winnls.h +++ b/tcc/include/winapi/winnls.h @@ -1,778 +1,778 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINNLS_ -#define _WINNLS_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef NONLS - -#define MAX_LEADBYTES 12 -#define MAX_DEFAULTCHAR 2 - -#define MB_PRECOMPOSED 0x00000001 -#define MB_COMPOSITE 0x00000002 -#define MB_USEGLYPHCHARS 0x00000004 -#define MB_ERR_INVALID_CHARS 0x00000008 - -#define WC_COMPOSITECHECK 0x00000200 -#define WC_DISCARDNS 0x00000010 -#define WC_SEPCHARS 0x00000020 -#define WC_DEFAULTCHAR 0x00000040 -#define WC_NO_BEST_FIT_CHARS 0x00000400 - -#define CT_CTYPE1 0x00000001 -#define CT_CTYPE2 0x00000002 -#define CT_CTYPE3 0x00000004 - -#define C1_UPPER 0x0001 -#define C1_LOWER 0x0002 -#define C1_DIGIT 0x0004 -#define C1_SPACE 0x0008 -#define C1_PUNCT 0x0010 -#define C1_CNTRL 0x0020 -#define C1_BLANK 0x0040 -#define C1_XDIGIT 0x0080 -#define C1_ALPHA 0x0100 -#define C1_DEFINED 0x0200 - -#define C2_LEFTTORIGHT 0x0001 -#define C2_RIGHTTOLEFT 0x0002 - -#define C2_EUROPENUMBER 0x0003 -#define C2_EUROPESEPARATOR 0x0004 -#define C2_EUROPETERMINATOR 0x0005 -#define C2_ARABICNUMBER 0x0006 -#define C2_COMMONSEPARATOR 0x0007 - -#define C2_BLOCKSEPARATOR 0x0008 -#define C2_SEGMENTSEPARATOR 0x0009 -#define C2_WHITESPACE 0x000A -#define C2_OTHERNEUTRAL 0x000B - -#define C2_NOTAPPLICABLE 0x0000 - -#define C3_NONSPACING 0x0001 -#define C3_DIACRITIC 0x0002 -#define C3_VOWELMARK 0x0004 -#define C3_SYMBOL 0x0008 - -#define C3_KATAKANA 0x0010 -#define C3_HIRAGANA 0x0020 -#define C3_HALFWIDTH 0x0040 -#define C3_FULLWIDTH 0x0080 -#define C3_IDEOGRAPH 0x0100 -#define C3_KASHIDA 0x0200 -#define C3_LEXICAL 0x0400 - -#define C3_ALPHA 0x8000 - -#define C3_NOTAPPLICABLE 0x0000 - -#define NORM_IGNORECASE 0x00000001 -#define NORM_IGNORENONSPACE 0x00000002 -#define NORM_IGNORESYMBOLS 0x00000004 - -#define NORM_IGNOREKANATYPE 0x00010000 -#define NORM_IGNOREWIDTH 0x00020000 - -#define MAP_FOLDCZONE 0x00000010 -#define MAP_PRECOMPOSED 0x00000020 -#define MAP_COMPOSITE 0x00000040 -#define MAP_FOLDDIGITS 0x00000080 -#define MAP_EXPAND_LIGATURES 0x00002000 - -#define LCMAP_LOWERCASE 0x00000100 -#define LCMAP_UPPERCASE 0x00000200 -#define LCMAP_SORTKEY 0x00000400 -#define LCMAP_BYTEREV 0x00000800 - -#define LCMAP_HIRAGANA 0x00100000 -#define LCMAP_KATAKANA 0x00200000 -#define LCMAP_HALFWIDTH 0x00400000 -#define LCMAP_FULLWIDTH 0x00800000 - -#define LCMAP_LINGUISTIC_CASING 0x01000000 - -#define LCMAP_SIMPLIFIED_CHINESE 0x02000000 -#define LCMAP_TRADITIONAL_CHINESE 0x04000000 - -#define LGRPID_INSTALLED 0x00000001 -#define LGRPID_SUPPORTED 0x00000002 - -#define LCID_INSTALLED 0x00000001 -#define LCID_SUPPORTED 0x00000002 -#define LCID_ALTERNATE_SORTS 0x00000004 - -#define CP_INSTALLED 0x00000001 -#define CP_SUPPORTED 0x00000002 - -#define SORT_STRINGSORT 0x00001000 - -#define CSTR_LESS_THAN 1 -#define CSTR_EQUAL 2 -#define CSTR_GREATER_THAN 3 - -#define CP_ACP 0 -#define CP_OEMCP 1 -#define CP_MACCP 2 -#define CP_THREAD_ACP 3 -#define CP_SYMBOL 42 - -#define CP_UTF7 65000 -#define CP_UTF8 65001 - -#define CTRY_DEFAULT 0 - -#define CTRY_ALBANIA 355 -#define CTRY_ALGERIA 213 -#define CTRY_ARGENTINA 54 -#define CTRY_ARMENIA 374 -#define CTRY_AUSTRALIA 61 -#define CTRY_AUSTRIA 43 -#define CTRY_AZERBAIJAN 994 -#define CTRY_BAHRAIN 973 -#define CTRY_BELARUS 375 -#define CTRY_BELGIUM 32 -#define CTRY_BELIZE 501 -#define CTRY_BOLIVIA 591 -#define CTRY_BRAZIL 55 -#define CTRY_BRUNEI_DARUSSALAM 673 -#define CTRY_BULGARIA 359 -#define CTRY_CANADA 2 -#define CTRY_CARIBBEAN 1 -#define CTRY_CHILE 56 -#define CTRY_COLOMBIA 57 -#define CTRY_COSTA_RICA 506 -#define CTRY_CROATIA 385 -#define CTRY_CZECH 420 -#define CTRY_DENMARK 45 -#define CTRY_DOMINICAN_REPUBLIC 1 -#define CTRY_ECUADOR 593 -#define CTRY_EGYPT 20 -#define CTRY_EL_SALVADOR 503 -#define CTRY_ESTONIA 372 -#define CTRY_FAEROE_ISLANDS 298 -#define CTRY_FINLAND 358 -#define CTRY_FRANCE 33 -#define CTRY_GEORGIA 995 -#define CTRY_GERMANY 49 -#define CTRY_GREECE 30 -#define CTRY_GUATEMALA 502 -#define CTRY_HONDURAS 504 -#define CTRY_HONG_KONG 852 -#define CTRY_HUNGARY 36 -#define CTRY_ICELAND 354 -#define CTRY_INDIA 91 -#define CTRY_INDONESIA 62 -#define CTRY_IRAN 981 -#define CTRY_IRAQ 964 -#define CTRY_IRELAND 353 -#define CTRY_ISRAEL 972 -#define CTRY_ITALY 39 -#define CTRY_JAMAICA 1 -#define CTRY_JAPAN 81 -#define CTRY_JORDAN 962 -#define CTRY_KAZAKSTAN 7 -#define CTRY_KENYA 254 -#define CTRY_KUWAIT 965 -#define CTRY_KYRGYZSTAN 996 -#define CTRY_LATVIA 371 -#define CTRY_LEBANON 961 -#define CTRY_LIBYA 218 -#define CTRY_LIECHTENSTEIN 41 -#define CTRY_LITHUANIA 370 -#define CTRY_LUXEMBOURG 352 -#define CTRY_MACAU 853 -#define CTRY_MACEDONIA 389 -#define CTRY_MALAYSIA 60 -#define CTRY_MALDIVES 960 -#define CTRY_MEXICO 52 -#define CTRY_MONACO 33 -#define CTRY_MONGOLIA 976 -#define CTRY_MOROCCO 212 -#define CTRY_NETHERLANDS 31 -#define CTRY_NEW_ZEALAND 64 -#define CTRY_NICARAGUA 505 -#define CTRY_NORWAY 47 -#define CTRY_OMAN 968 -#define CTRY_PAKISTAN 92 -#define CTRY_PANAMA 507 -#define CTRY_PARAGUAY 595 -#define CTRY_PERU 51 -#define CTRY_PHILIPPINES 63 -#define CTRY_POLAND 48 -#define CTRY_PORTUGAL 351 -#define CTRY_PRCHINA 86 -#define CTRY_PUERTO_RICO 1 -#define CTRY_QATAR 974 -#define CTRY_ROMANIA 40 -#define CTRY_RUSSIA 7 -#define CTRY_SAUDI_ARABIA 966 -#define CTRY_SERBIA 381 -#define CTRY_SINGAPORE 65 -#define CTRY_SLOVAK 421 -#define CTRY_SLOVENIA 386 -#define CTRY_SOUTH_AFRICA 27 -#define CTRY_SOUTH_KOREA 82 -#define CTRY_SPAIN 34 -#define CTRY_SWEDEN 46 -#define CTRY_SWITZERLAND 41 -#define CTRY_SYRIA 963 -#define CTRY_TAIWAN 886 -#define CTRY_TATARSTAN 7 -#define CTRY_THAILAND 66 -#define CTRY_TRINIDAD_Y_TOBAGO 1 -#define CTRY_TUNISIA 216 -#define CTRY_TURKEY 90 -#define CTRY_UAE 971 -#define CTRY_UKRAINE 380 -#define CTRY_UNITED_KINGDOM 44 -#define CTRY_UNITED_STATES 1 -#define CTRY_URUGUAY 598 -#define CTRY_UZBEKISTAN 7 -#define CTRY_VENEZUELA 58 -#define CTRY_VIET_NAM 84 -#define CTRY_YEMEN 967 -#define CTRY_ZIMBABWE 263 - -#define LOCALE_NOUSEROVERRIDE 0x80000000 -#define LOCALE_USE_CP_ACP 0x40000000 -#define LOCALE_RETURN_NUMBER 0x20000000 - -#define LOCALE_ILANGUAGE 0x00000001 -#define LOCALE_SLANGUAGE 0x00000002 -#define LOCALE_SENGLANGUAGE 0x00001001 -#define LOCALE_SABBREVLANGNAME 0x00000003 -#define LOCALE_SNATIVELANGNAME 0x00000004 - -#define LOCALE_ICOUNTRY 0x00000005 -#define LOCALE_SCOUNTRY 0x00000006 -#define LOCALE_SENGCOUNTRY 0x00001002 -#define LOCALE_SABBREVCTRYNAME 0x00000007 -#define LOCALE_SNATIVECTRYNAME 0x00000008 - -#define LOCALE_IDEFAULTLANGUAGE 0x00000009 -#define LOCALE_IDEFAULTCOUNTRY 0x0000000A -#define LOCALE_IDEFAULTCODEPAGE 0x0000000B -#define LOCALE_IDEFAULTANSICODEPAGE 0x00001004 -#define LOCALE_IDEFAULTMACCODEPAGE 0x00001011 - -#define LOCALE_SLIST 0x0000000C -#define LOCALE_IMEASURE 0x0000000D - -#define LOCALE_SDECIMAL 0x0000000E -#define LOCALE_STHOUSAND 0x0000000F -#define LOCALE_SGROUPING 0x00000010 -#define LOCALE_IDIGITS 0x00000011 -#define LOCALE_ILZERO 0x00000012 -#define LOCALE_INEGNUMBER 0x00001010 -#define LOCALE_SNATIVEDIGITS 0x00000013 - -#define LOCALE_SCURRENCY 0x00000014 -#define LOCALE_SINTLSYMBOL 0x00000015 -#define LOCALE_SMONDECIMALSEP 0x00000016 -#define LOCALE_SMONTHOUSANDSEP 0x00000017 -#define LOCALE_SMONGROUPING 0x00000018 -#define LOCALE_ICURRDIGITS 0x00000019 -#define LOCALE_IINTLCURRDIGITS 0x0000001A -#define LOCALE_ICURRENCY 0x0000001B -#define LOCALE_INEGCURR 0x0000001C - -#define LOCALE_SDATE 0x0000001D -#define LOCALE_STIME 0x0000001E -#define LOCALE_SSHORTDATE 0x0000001F -#define LOCALE_SLONGDATE 0x00000020 -#define LOCALE_STIMEFORMAT 0x00001003 -#define LOCALE_IDATE 0x00000021 -#define LOCALE_ILDATE 0x00000022 -#define LOCALE_ITIME 0x00000023 -#define LOCALE_ITIMEMARKPOSN 0x00001005 -#define LOCALE_ICENTURY 0x00000024 -#define LOCALE_ITLZERO 0x00000025 -#define LOCALE_IDAYLZERO 0x00000026 -#define LOCALE_IMONLZERO 0x00000027 -#define LOCALE_S1159 0x00000028 -#define LOCALE_S2359 0x00000029 - -#define LOCALE_ICALENDARTYPE 0x00001009 -#define LOCALE_IOPTIONALCALENDAR 0x0000100B -#define LOCALE_IFIRSTDAYOFWEEK 0x0000100C -#define LOCALE_IFIRSTWEEKOFYEAR 0x0000100D - -#define LOCALE_SDAYNAME1 0x0000002A -#define LOCALE_SDAYNAME2 0x0000002B -#define LOCALE_SDAYNAME3 0x0000002C -#define LOCALE_SDAYNAME4 0x0000002D -#define LOCALE_SDAYNAME5 0x0000002E -#define LOCALE_SDAYNAME6 0x0000002F -#define LOCALE_SDAYNAME7 0x00000030 -#define LOCALE_SABBREVDAYNAME1 0x00000031 -#define LOCALE_SABBREVDAYNAME2 0x00000032 -#define LOCALE_SABBREVDAYNAME3 0x00000033 -#define LOCALE_SABBREVDAYNAME4 0x00000034 -#define LOCALE_SABBREVDAYNAME5 0x00000035 -#define LOCALE_SABBREVDAYNAME6 0x00000036 -#define LOCALE_SABBREVDAYNAME7 0x00000037 -#define LOCALE_SMONTHNAME1 0x00000038 -#define LOCALE_SMONTHNAME2 0x00000039 -#define LOCALE_SMONTHNAME3 0x0000003A -#define LOCALE_SMONTHNAME4 0x0000003B -#define LOCALE_SMONTHNAME5 0x0000003C -#define LOCALE_SMONTHNAME6 0x0000003D -#define LOCALE_SMONTHNAME7 0x0000003E -#define LOCALE_SMONTHNAME8 0x0000003F -#define LOCALE_SMONTHNAME9 0x00000040 -#define LOCALE_SMONTHNAME10 0x00000041 -#define LOCALE_SMONTHNAME11 0x00000042 -#define LOCALE_SMONTHNAME12 0x00000043 -#define LOCALE_SMONTHNAME13 0x0000100E -#define LOCALE_SABBREVMONTHNAME1 0x00000044 -#define LOCALE_SABBREVMONTHNAME2 0x00000045 -#define LOCALE_SABBREVMONTHNAME3 0x00000046 -#define LOCALE_SABBREVMONTHNAME4 0x00000047 -#define LOCALE_SABBREVMONTHNAME5 0x00000048 -#define LOCALE_SABBREVMONTHNAME6 0x00000049 -#define LOCALE_SABBREVMONTHNAME7 0x0000004A -#define LOCALE_SABBREVMONTHNAME8 0x0000004B -#define LOCALE_SABBREVMONTHNAME9 0x0000004C -#define LOCALE_SABBREVMONTHNAME10 0x0000004D -#define LOCALE_SABBREVMONTHNAME11 0x0000004E -#define LOCALE_SABBREVMONTHNAME12 0x0000004F -#define LOCALE_SABBREVMONTHNAME13 0x0000100F - -#define LOCALE_SPOSITIVESIGN 0x00000050 -#define LOCALE_SNEGATIVESIGN 0x00000051 -#define LOCALE_IPOSSIGNPOSN 0x00000052 -#define LOCALE_INEGSIGNPOSN 0x00000053 -#define LOCALE_IPOSSYMPRECEDES 0x00000054 -#define LOCALE_IPOSSEPBYSPACE 0x00000055 -#define LOCALE_INEGSYMPRECEDES 0x00000056 -#define LOCALE_INEGSEPBYSPACE 0x00000057 -#define LOCALE_FONTSIGNATURE 0x00000058 -#define LOCALE_SISO639LANGNAME 0x00000059 -#define LOCALE_SISO3166CTRYNAME 0x0000005A - -#define LOCALE_IDEFAULTEBCDICCODEPAGE 0x00001012 -#define LOCALE_IPAPERSIZE 0x0000100A -#define LOCALE_SENGCURRNAME 0x00001007 -#define LOCALE_SNATIVECURRNAME 0x00001008 -#define LOCALE_SYEARMONTH 0x00001006 -#define LOCALE_SSORTNAME 0x00001013 -#define LOCALE_IDIGITSUBSTITUTION 0x00001014 - -#define TIME_NOMINUTESORSECONDS 0x00000001 -#define TIME_NOSECONDS 0x00000002 -#define TIME_NOTIMEMARKER 0x00000004 -#define TIME_FORCE24HOURFORMAT 0x00000008 - -#define DATE_SHORTDATE 0x00000001 -#define DATE_LONGDATE 0x00000002 -#define DATE_USE_ALT_CALENDAR 0x00000004 -#define DATE_YEARMONTH 0x00000008 -#define DATE_LTRREADING 0x00000010 -#define DATE_RTLREADING 0x00000020 - -#define CAL_NOUSEROVERRIDE LOCALE_NOUSEROVERRIDE -#define CAL_USE_CP_ACP LOCALE_USE_CP_ACP -#define CAL_RETURN_NUMBER LOCALE_RETURN_NUMBER - -#define CAL_ICALINTVALUE 0x00000001 -#define CAL_SCALNAME 0x00000002 -#define CAL_IYEAROFFSETRANGE 0x00000003 -#define CAL_SERASTRING 0x00000004 -#define CAL_SSHORTDATE 0x00000005 -#define CAL_SLONGDATE 0x00000006 -#define CAL_SDAYNAME1 0x00000007 -#define CAL_SDAYNAME2 0x00000008 -#define CAL_SDAYNAME3 0x00000009 -#define CAL_SDAYNAME4 0x0000000a -#define CAL_SDAYNAME5 0x0000000b -#define CAL_SDAYNAME6 0x0000000c -#define CAL_SDAYNAME7 0x0000000d -#define CAL_SABBREVDAYNAME1 0x0000000e -#define CAL_SABBREVDAYNAME2 0x0000000f -#define CAL_SABBREVDAYNAME3 0x00000010 -#define CAL_SABBREVDAYNAME4 0x00000011 -#define CAL_SABBREVDAYNAME5 0x00000012 -#define CAL_SABBREVDAYNAME6 0x00000013 -#define CAL_SABBREVDAYNAME7 0x00000014 -#define CAL_SMONTHNAME1 0x00000015 -#define CAL_SMONTHNAME2 0x00000016 -#define CAL_SMONTHNAME3 0x00000017 -#define CAL_SMONTHNAME4 0x00000018 -#define CAL_SMONTHNAME5 0x00000019 -#define CAL_SMONTHNAME6 0x0000001a -#define CAL_SMONTHNAME7 0x0000001b -#define CAL_SMONTHNAME8 0x0000001c -#define CAL_SMONTHNAME9 0x0000001d -#define CAL_SMONTHNAME10 0x0000001e -#define CAL_SMONTHNAME11 0x0000001f -#define CAL_SMONTHNAME12 0x00000020 -#define CAL_SMONTHNAME13 0x00000021 -#define CAL_SABBREVMONTHNAME1 0x00000022 -#define CAL_SABBREVMONTHNAME2 0x00000023 -#define CAL_SABBREVMONTHNAME3 0x00000024 -#define CAL_SABBREVMONTHNAME4 0x00000025 -#define CAL_SABBREVMONTHNAME5 0x00000026 -#define CAL_SABBREVMONTHNAME6 0x00000027 -#define CAL_SABBREVMONTHNAME7 0x00000028 -#define CAL_SABBREVMONTHNAME8 0x00000029 -#define CAL_SABBREVMONTHNAME9 0x0000002a -#define CAL_SABBREVMONTHNAME10 0x0000002b -#define CAL_SABBREVMONTHNAME11 0x0000002c -#define CAL_SABBREVMONTHNAME12 0x0000002d -#define CAL_SABBREVMONTHNAME13 0x0000002e -#define CAL_SYEARMONTH 0x0000002f -#define CAL_ITWODIGITYEARMAX 0x00000030 - -#define ENUM_ALL_CALENDARS 0xffffffff - -#define CAL_GREGORIAN 1 -#define CAL_GREGORIAN_US 2 -#define CAL_JAPAN 3 -#define CAL_TAIWAN 4 -#define CAL_KOREA 5 -#define CAL_HIJRI 6 -#define CAL_THAI 7 -#define CAL_HEBREW 8 -#define CAL_GREGORIAN_ME_FRENCH 9 -#define CAL_GREGORIAN_ARABIC 10 -#define CAL_GREGORIAN_XLIT_ENGLISH 11 -#define CAL_GREGORIAN_XLIT_FRENCH 12 - -#define LGRPID_WESTERN_EUROPE 0x0001 -#define LGRPID_CENTRAL_EUROPE 0x0002 -#define LGRPID_BALTIC 0x0003 -#define LGRPID_GREEK 0x0004 -#define LGRPID_CYRILLIC 0x0005 -#define LGRPID_TURKISH 0x0006 -#define LGRPID_JAPANESE 0x0007 -#define LGRPID_KOREAN 0x0008 -#define LGRPID_TRADITIONAL_CHINESE 0x0009 -#define LGRPID_SIMPLIFIED_CHINESE 0x000a -#define LGRPID_THAI 0x000b -#define LGRPID_HEBREW 0x000c -#define LGRPID_ARABIC 0x000d -#define LGRPID_VIETNAMESE 0x000e -#define LGRPID_INDIC 0x000f -#define LGRPID_GEORGIAN 0x0010 -#define LGRPID_ARMENIAN 0x0011 - - typedef DWORD LGRPID; - typedef DWORD LCTYPE; - typedef DWORD CALTYPE; - typedef DWORD CALID; - - typedef struct _cpinfo { - UINT MaxCharSize; - BYTE DefaultChar[MAX_DEFAULTCHAR]; - BYTE LeadByte[MAX_LEADBYTES]; - } CPINFO,*LPCPINFO; - - typedef struct _cpinfoexA { - UINT MaxCharSize; - BYTE DefaultChar[MAX_DEFAULTCHAR]; - BYTE LeadByte[MAX_LEADBYTES]; - WCHAR UnicodeDefaultChar; - UINT CodePage; - CHAR CodePageName[MAX_PATH]; - } CPINFOEXA,*LPCPINFOEXA; - - typedef struct _cpinfoexW { - UINT MaxCharSize; - BYTE DefaultChar[MAX_DEFAULTCHAR]; - BYTE LeadByte[MAX_LEADBYTES]; - WCHAR UnicodeDefaultChar; - UINT CodePage; - WCHAR CodePageName[MAX_PATH]; - } CPINFOEXW,*LPCPINFOEXW; - -#ifdef UNICODE - typedef CPINFOEXW CPINFOEX; - typedef LPCPINFOEXW LPCPINFOEX; -#else - typedef CPINFOEXA CPINFOEX; - typedef LPCPINFOEXA LPCPINFOEX; -#endif - - typedef struct _numberfmtA { - UINT NumDigits; - UINT LeadingZero; - UINT Grouping; - LPSTR lpDecimalSep; - LPSTR lpThousandSep; - UINT NegativeOrder; - } NUMBERFMTA,*LPNUMBERFMTA; - - typedef struct _numberfmtW { - UINT NumDigits; - UINT LeadingZero; - UINT Grouping; - LPWSTR lpDecimalSep; - LPWSTR lpThousandSep; - UINT NegativeOrder; - } NUMBERFMTW,*LPNUMBERFMTW; - -#ifdef UNICODE - typedef NUMBERFMTW NUMBERFMT; - typedef LPNUMBERFMTW LPNUMBERFMT; -#else - typedef NUMBERFMTA NUMBERFMT; - typedef LPNUMBERFMTA LPNUMBERFMT; -#endif - - typedef struct _currencyfmtA { - UINT NumDigits; - UINT LeadingZero; - UINT Grouping; - LPSTR lpDecimalSep; - LPSTR lpThousandSep; - UINT NegativeOrder; - UINT PositiveOrder; - LPSTR lpCurrencySymbol; - } CURRENCYFMTA,*LPCURRENCYFMTA; - - typedef struct _currencyfmtW { - UINT NumDigits; - UINT LeadingZero; - UINT Grouping; - LPWSTR lpDecimalSep; - LPWSTR lpThousandSep; - UINT NegativeOrder; - UINT PositiveOrder; - LPWSTR lpCurrencySymbol; - } CURRENCYFMTW,*LPCURRENCYFMTW; - -#ifdef UNICODE - typedef CURRENCYFMTW CURRENCYFMT; - typedef LPCURRENCYFMTW LPCURRENCYFMT; -#else - typedef CURRENCYFMTA CURRENCYFMT; - typedef LPCURRENCYFMTA LPCURRENCYFMT; -#endif - - enum SYSNLS_FUNCTION { - COMPARE_STRING = 0x0001 - }; - - typedef DWORD NLS_FUNCTION; - - typedef struct _nlsversioninfo{ - DWORD dwNLSVersionInfoSize; - DWORD dwNLSVersion; - DWORD dwDefinedVersion; - } NLSVERSIONINFO,*LPNLSVERSIONINFO; - - typedef LONG GEOID; - typedef DWORD GEOTYPE; - typedef DWORD GEOCLASS; - -#define GEOID_NOT_AVAILABLE -1 - - enum SYSGEOTYPE { - GEO_NATION = 0x0001,GEO_LATITUDE = 0x0002,GEO_LONGITUDE = 0x0003,GEO_ISO2 = 0x0004,GEO_ISO3 = 0x0005,GEO_RFC1766 = 0x0006,GEO_LCID = 0x0007, - GEO_FRIENDLYNAME= 0x0008,GEO_OFFICIALNAME= 0x0009,GEO_TIMEZONES = 0x000A,GEO_OFFICIALLANGUAGES = 0x000B - }; - - enum SYSGEOCLASS { - GEOCLASS_NATION = 16,GEOCLASS_REGION = 14 - }; - - typedef enum _NORM_FORM { - NormalizationOther = 0, - NormalizationC = 0x1, - NormalizationD = 0x2, - NormalizationKC = 0x5, - NormalizationKD = 0x6 -} NORM_FORM; - - typedef WINBOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCA)(LGRPID,LPSTR,LPSTR,DWORD,LONG_PTR); - typedef WINBOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCA)(LGRPID,LCID,LPSTR,LONG_PTR); - typedef WINBOOL (CALLBACK *UILANGUAGE_ENUMPROCA)(LPSTR,LONG_PTR); - typedef WINBOOL (CALLBACK *LOCALE_ENUMPROCA)(LPSTR); - typedef WINBOOL (CALLBACK *CODEPAGE_ENUMPROCA)(LPSTR); - typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCA)(LPSTR); - typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCEXA)(LPSTR,CALID); - typedef WINBOOL (CALLBACK *TIMEFMT_ENUMPROCA)(LPSTR); - typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCA)(LPSTR); - typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCEXA)(LPSTR,CALID); - typedef WINBOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCW)(LGRPID,LPWSTR,LPWSTR,DWORD,LONG_PTR); - typedef WINBOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCW)(LGRPID,LCID,LPWSTR,LONG_PTR); - typedef WINBOOL (CALLBACK *UILANGUAGE_ENUMPROCW)(LPWSTR,LONG_PTR); - typedef WINBOOL (CALLBACK *LOCALE_ENUMPROCW)(LPWSTR); - typedef WINBOOL (CALLBACK *CODEPAGE_ENUMPROCW)(LPWSTR); - typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCW)(LPWSTR); - typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCEXW)(LPWSTR,CALID); - typedef WINBOOL (CALLBACK *TIMEFMT_ENUMPROCW)(LPWSTR); - typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCW)(LPWSTR); - typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCEXW)(LPWSTR,CALID); - typedef WINBOOL (CALLBACK *GEO_ENUMPROC)(GEOID); - -#ifdef UNICODE -#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCW -#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCW -#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCW -#define LOCALE_ENUMPROC LOCALE_ENUMPROCW -#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCW -#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCW -#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXW -#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCW -#define CALINFO_ENUMPROC CALINFO_ENUMPROCW -#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXW -#else -#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCA -#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCA -#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCA -#define LOCALE_ENUMPROC LOCALE_ENUMPROCA -#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCA -#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCA -#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXA -#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCA -#define CALINFO_ENUMPROC CALINFO_ENUMPROCA -#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXA -#endif - -#ifdef UNICODE -#define GetCPInfoEx GetCPInfoExW -#define CompareString CompareStringW -#define LCMapString LCMapStringW -#define GetLocaleInfo GetLocaleInfoW -#define SetLocaleInfo SetLocaleInfoW -#define GetCalendarInfo GetCalendarInfoW -#define SetCalendarInfo SetCalendarInfoW -#define GetTimeFormat GetTimeFormatW -#define GetDateFormat GetDateFormatW -#define GetNumberFormat GetNumberFormatW -#define GetCurrencyFormat GetCurrencyFormatW -#define EnumCalendarInfo EnumCalendarInfoW -#define EnumCalendarInfoEx EnumCalendarInfoExW -#define EnumTimeFormats EnumTimeFormatsW -#define EnumDateFormats EnumDateFormatsW -#define EnumDateFormatsEx EnumDateFormatsExW -#define GetGeoInfo GetGeoInfoW -#define GetStringTypeEx GetStringTypeExW -#define FoldString FoldStringW -#define EnumSystemLanguageGroups EnumSystemLanguageGroupsW -#define EnumLanguageGroupLocales EnumLanguageGroupLocalesW -#define EnumUILanguages EnumUILanguagesW -#define EnumSystemLocales EnumSystemLocalesW -#define EnumSystemCodePages EnumSystemCodePagesW -#else -#define GetCPInfoEx GetCPInfoExA -#define CompareString CompareStringA -#define LCMapString LCMapStringA -#define GetLocaleInfo GetLocaleInfoA -#define SetLocaleInfo SetLocaleInfoA -#define GetCalendarInfo GetCalendarInfoA -#define SetCalendarInfo SetCalendarInfoA -#define GetTimeFormat GetTimeFormatA -#define GetDateFormat GetDateFormatA -#define GetNumberFormat GetNumberFormatA -#define GetCurrencyFormat GetCurrencyFormatA -#define EnumCalendarInfo EnumCalendarInfoA -#define EnumCalendarInfoEx EnumCalendarInfoExA -#define EnumTimeFormats EnumTimeFormatsA -#define EnumDateFormats EnumDateFormatsA -#define EnumDateFormatsEx EnumDateFormatsExA -#define GetGeoInfo GetGeoInfoA -#define GetStringTypeEx GetStringTypeExA -#define FoldString FoldStringA -#define EnumSystemLanguageGroups EnumSystemLanguageGroupsA -#define EnumLanguageGroupLocales EnumLanguageGroupLocalesA -#define EnumUILanguages EnumUILanguagesA -#define EnumSystemLocales EnumSystemLocalesA -#define EnumSystemCodePages EnumSystemCodePagesA -#endif - - WINBASEAPI WINBOOL WINAPI IsValidCodePage(UINT CodePage); - WINBASEAPI UINT WINAPI GetACP(void); - WINBASEAPI UINT WINAPI GetOEMCP(void); - WINBASEAPI WINBOOL WINAPI GetCPInfo(UINT CodePage,LPCPINFO lpCPInfo); - WINBASEAPI WINBOOL WINAPI GetCPInfoExA(UINT CodePage,DWORD dwFlags,LPCPINFOEXA lpCPInfoEx); - WINBASEAPI WINBOOL WINAPI GetCPInfoExW(UINT CodePage,DWORD dwFlags,LPCPINFOEXW lpCPInfoEx); - WINBASEAPI WINBOOL WINAPI IsDBCSLeadByte(BYTE TestChar); - WINBASEAPI WINBOOL WINAPI IsDBCSLeadByteEx(UINT CodePage,BYTE TestChar); - WINBASEAPI int WINAPI MultiByteToWideChar(UINT CodePage,DWORD dwFlags,LPCSTR lpMultiByteStr,int cbMultiByte,LPWSTR lpWideCharStr,int cchWideChar); - WINBASEAPI int WINAPI WideCharToMultiByte(UINT CodePage,DWORD dwFlags,LPCWSTR lpWideCharStr,int cchWideChar,LPSTR lpMultiByteStr,int cbMultiByte,LPCSTR lpDefaultChar,LPBOOL lpUsedDefaultChar); - WINBASEAPI int WINAPI CompareStringA(LCID Locale,DWORD dwCmpFlags,LPCSTR lpString1,int cchCount1,LPCSTR lpString2,int cchCount2); - WINBASEAPI int WINAPI CompareStringW(LCID Locale,DWORD dwCmpFlags,LPCWSTR lpString1,int cchCount1,LPCWSTR lpString2,int cchCount2); - WINBASEAPI int WINAPI LCMapStringA(LCID Locale,DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest); - WINBASEAPI int WINAPI LCMapStringW(LCID Locale,DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest); - WINBASEAPI int WINAPI GetLocaleInfoA(LCID Locale,LCTYPE LCType,LPSTR lpLCData,int cchData); - WINBASEAPI int WINAPI GetLocaleInfoW(LCID Locale,LCTYPE LCType,LPWSTR lpLCData,int cchData); - WINBASEAPI WINBOOL WINAPI SetLocaleInfoA(LCID Locale,LCTYPE LCType,LPCSTR lpLCData); - WINBASEAPI WINBOOL WINAPI SetLocaleInfoW(LCID Locale,LCTYPE LCType,LPCWSTR lpLCData); - WINBASEAPI int WINAPI GetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPSTR lpCalData,int cchData,LPDWORD lpValue); - WINBASEAPI int WINAPI GetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPWSTR lpCalData,int cchData,LPDWORD lpValue); - WINBASEAPI WINBOOL WINAPI SetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPCSTR lpCalData); - WINBASEAPI WINBOOL WINAPI SetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPCWSTR lpCalData); - WINBASEAPI int WINAPI GetTimeFormatA(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpTime,LPCSTR lpFormat,LPSTR lpTimeStr,int cchTime); - WINBASEAPI int WINAPI GetTimeFormatW(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpTime,LPCWSTR lpFormat,LPWSTR lpTimeStr,int cchTime); - WINBASEAPI int WINAPI GetDateFormatA(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpDate,LPCSTR lpFormat,LPSTR lpDateStr,int cchDate); - WINBASEAPI int WINAPI GetDateFormatW(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpDate,LPCWSTR lpFormat,LPWSTR lpDateStr,int cchDate); - WINBASEAPI int WINAPI GetNumberFormatA(LCID Locale,DWORD dwFlags,LPCSTR lpValue,CONST NUMBERFMTA *lpFormat,LPSTR lpNumberStr,int cchNumber); - WINBASEAPI int WINAPI GetNumberFormatW(LCID Locale,DWORD dwFlags,LPCWSTR lpValue,CONST NUMBERFMTW *lpFormat,LPWSTR lpNumberStr,int cchNumber); - WINBASEAPI int WINAPI GetCurrencyFormatA(LCID Locale,DWORD dwFlags,LPCSTR lpValue,CONST CURRENCYFMTA *lpFormat,LPSTR lpCurrencyStr,int cchCurrency); - WINBASEAPI int WINAPI GetCurrencyFormatW(LCID Locale,DWORD dwFlags,LPCWSTR lpValue,CONST CURRENCYFMTW *lpFormat,LPWSTR lpCurrencyStr,int cchCurrency); - WINBASEAPI WINBOOL WINAPI EnumCalendarInfoA(CALINFO_ENUMPROCA lpCalInfoEnumProc,LCID Locale,CALID Calendar,CALTYPE CalType); - WINBASEAPI WINBOOL WINAPI EnumCalendarInfoW(CALINFO_ENUMPROCW lpCalInfoEnumProc,LCID Locale,CALID Calendar,CALTYPE CalType); - WINBASEAPI WINBOOL WINAPI EnumCalendarInfoExA(CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx,LCID Locale,CALID Calendar,CALTYPE CalType); - WINBASEAPI WINBOOL WINAPI EnumCalendarInfoExW(CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx,LCID Locale,CALID Calendar,CALTYPE CalType); - WINBASEAPI WINBOOL WINAPI EnumTimeFormatsA(TIMEFMT_ENUMPROCA lpTimeFmtEnumProc,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumTimeFormatsW(TIMEFMT_ENUMPROCW lpTimeFmtEnumProc,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA lpDateFmtEnumProc,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumDateFormatsW(DATEFMT_ENUMPROCW lpDateFmtEnumProc,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumDateFormatsExA(DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumDateFormatsExW(DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI IsValidLanguageGroup(LGRPID LanguageGroup,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI GetNLSVersion(NLS_FUNCTION Function,LCID Locale,LPNLSVERSIONINFO lpVersionInformation); - WINBASEAPI WINBOOL WINAPI IsNLSDefinedString(NLS_FUNCTION Function,DWORD dwFlags,LPNLSVERSIONINFO lpVersionInformation,LPCWSTR lpString,INT cchStr); - WINBASEAPI WINBOOL WINAPI IsValidLocale(LCID Locale,DWORD dwFlags); - WINBASEAPI int WINAPI GetGeoInfoA(GEOID Location,GEOTYPE GeoType,LPSTR lpGeoData,int cchData,LANGID LangId); - WINBASEAPI int WINAPI GetGeoInfoW(GEOID Location,GEOTYPE GeoType,LPWSTR lpGeoData,int cchData,LANGID LangId); - WINBASEAPI WINBOOL WINAPI EnumSystemGeoID(GEOCLASS GeoClass,GEOID ParentGeoId,GEO_ENUMPROC lpGeoEnumProc); - WINBASEAPI GEOID WINAPI GetUserGeoID(GEOCLASS GeoClass); - WINBASEAPI WINBOOL WINAPI SetUserGeoID(GEOID GeoId); - WINBASEAPI LCID WINAPI ConvertDefaultLocale(LCID Locale); - WINBASEAPI LCID WINAPI GetThreadLocale(void); - WINBASEAPI WINBOOL WINAPI SetThreadLocale(LCID Locale); - WINBASEAPI LANGID WINAPI GetSystemDefaultUILanguage(void); - WINBASEAPI LANGID WINAPI GetUserDefaultUILanguage(void); - WINBASEAPI LANGID WINAPI GetSystemDefaultLangID(void); - WINBASEAPI LANGID WINAPI GetUserDefaultLangID(void); - WINBASEAPI LCID WINAPI GetSystemDefaultLCID(void); - WINBASEAPI LCID WINAPI GetUserDefaultLCID(void); - WINBASEAPI WINBOOL WINAPI GetStringTypeExA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType); - WINBASEAPI WINBOOL WINAPI GetStringTypeExW(LCID Locale,DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType); - WINBASEAPI WINBOOL WINAPI GetStringTypeA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType); - WINBASEAPI WINBOOL WINAPI GetStringTypeW(DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType); - WINBASEAPI int WINAPI FoldStringA(DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest); - WINBASEAPI int WINAPI FoldStringW(DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest); - WINBASEAPI WINBOOL WINAPI EnumSystemLanguageGroupsA(LANGUAGEGROUP_ENUMPROCA lpLanguageGroupEnumProc,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumSystemLanguageGroupsW(LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumLanguageGroupLocalesA(LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc,LGRPID LanguageGroup,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumLanguageGroupLocalesW(LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc,LGRPID LanguageGroup,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumUILanguagesA(UILANGUAGE_ENUMPROCA lpUILanguageEnumProc,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumUILanguagesW(UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumSystemLocalesA(LOCALE_ENUMPROCA lpLocaleEnumProc,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumSystemLocalesW(LOCALE_ENUMPROCW lpLocaleEnumProc,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumSystemCodePagesA(CODEPAGE_ENUMPROCA lpCodePageEnumProc,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumSystemCodePagesW(CODEPAGE_ENUMPROCW lpCodePageEnumProc,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI IsNormalizedString(NORM_FORM NormForm,LPCWSTR lpString,int cwLength); - WINBASEAPI int WINAPI NormalizeString(NORM_FORM NormForm,LPCWSTR lpSrcString,int cwSrcLength,LPWSTR lpDstString,int cwDstLength); - WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,LPCWSTR lpUnicodeCharStr,int cchUnicodeChar,LPWSTR lpASCIICharStr,int cchASCIIChar); - WINBASEAPI int WINAPI IdnToNameprepUnicode(DWORD dwFlags,LPCWSTR lpUnicodeCharStr,int cchUnicodeChar,LPWSTR lpNameprepCharStr,int cchNameprepChar); - WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,LPCWSTR lpASCIICharStr,int cchASCIIChar,LPWSTR lpUnicodeCharStr,int cchUnicodeChar); - -#endif - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINNLS_ +#define _WINNLS_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NONLS + +#define MAX_LEADBYTES 12 +#define MAX_DEFAULTCHAR 2 + +#define MB_PRECOMPOSED 0x00000001 +#define MB_COMPOSITE 0x00000002 +#define MB_USEGLYPHCHARS 0x00000004 +#define MB_ERR_INVALID_CHARS 0x00000008 + +#define WC_COMPOSITECHECK 0x00000200 +#define WC_DISCARDNS 0x00000010 +#define WC_SEPCHARS 0x00000020 +#define WC_DEFAULTCHAR 0x00000040 +#define WC_NO_BEST_FIT_CHARS 0x00000400 + +#define CT_CTYPE1 0x00000001 +#define CT_CTYPE2 0x00000002 +#define CT_CTYPE3 0x00000004 + +#define C1_UPPER 0x0001 +#define C1_LOWER 0x0002 +#define C1_DIGIT 0x0004 +#define C1_SPACE 0x0008 +#define C1_PUNCT 0x0010 +#define C1_CNTRL 0x0020 +#define C1_BLANK 0x0040 +#define C1_XDIGIT 0x0080 +#define C1_ALPHA 0x0100 +#define C1_DEFINED 0x0200 + +#define C2_LEFTTORIGHT 0x0001 +#define C2_RIGHTTOLEFT 0x0002 + +#define C2_EUROPENUMBER 0x0003 +#define C2_EUROPESEPARATOR 0x0004 +#define C2_EUROPETERMINATOR 0x0005 +#define C2_ARABICNUMBER 0x0006 +#define C2_COMMONSEPARATOR 0x0007 + +#define C2_BLOCKSEPARATOR 0x0008 +#define C2_SEGMENTSEPARATOR 0x0009 +#define C2_WHITESPACE 0x000A +#define C2_OTHERNEUTRAL 0x000B + +#define C2_NOTAPPLICABLE 0x0000 + +#define C3_NONSPACING 0x0001 +#define C3_DIACRITIC 0x0002 +#define C3_VOWELMARK 0x0004 +#define C3_SYMBOL 0x0008 + +#define C3_KATAKANA 0x0010 +#define C3_HIRAGANA 0x0020 +#define C3_HALFWIDTH 0x0040 +#define C3_FULLWIDTH 0x0080 +#define C3_IDEOGRAPH 0x0100 +#define C3_KASHIDA 0x0200 +#define C3_LEXICAL 0x0400 + +#define C3_ALPHA 0x8000 + +#define C3_NOTAPPLICABLE 0x0000 + +#define NORM_IGNORECASE 0x00000001 +#define NORM_IGNORENONSPACE 0x00000002 +#define NORM_IGNORESYMBOLS 0x00000004 + +#define NORM_IGNOREKANATYPE 0x00010000 +#define NORM_IGNOREWIDTH 0x00020000 + +#define MAP_FOLDCZONE 0x00000010 +#define MAP_PRECOMPOSED 0x00000020 +#define MAP_COMPOSITE 0x00000040 +#define MAP_FOLDDIGITS 0x00000080 +#define MAP_EXPAND_LIGATURES 0x00002000 + +#define LCMAP_LOWERCASE 0x00000100 +#define LCMAP_UPPERCASE 0x00000200 +#define LCMAP_SORTKEY 0x00000400 +#define LCMAP_BYTEREV 0x00000800 + +#define LCMAP_HIRAGANA 0x00100000 +#define LCMAP_KATAKANA 0x00200000 +#define LCMAP_HALFWIDTH 0x00400000 +#define LCMAP_FULLWIDTH 0x00800000 + +#define LCMAP_LINGUISTIC_CASING 0x01000000 + +#define LCMAP_SIMPLIFIED_CHINESE 0x02000000 +#define LCMAP_TRADITIONAL_CHINESE 0x04000000 + +#define LGRPID_INSTALLED 0x00000001 +#define LGRPID_SUPPORTED 0x00000002 + +#define LCID_INSTALLED 0x00000001 +#define LCID_SUPPORTED 0x00000002 +#define LCID_ALTERNATE_SORTS 0x00000004 + +#define CP_INSTALLED 0x00000001 +#define CP_SUPPORTED 0x00000002 + +#define SORT_STRINGSORT 0x00001000 + +#define CSTR_LESS_THAN 1 +#define CSTR_EQUAL 2 +#define CSTR_GREATER_THAN 3 + +#define CP_ACP 0 +#define CP_OEMCP 1 +#define CP_MACCP 2 +#define CP_THREAD_ACP 3 +#define CP_SYMBOL 42 + +#define CP_UTF7 65000 +#define CP_UTF8 65001 + +#define CTRY_DEFAULT 0 + +#define CTRY_ALBANIA 355 +#define CTRY_ALGERIA 213 +#define CTRY_ARGENTINA 54 +#define CTRY_ARMENIA 374 +#define CTRY_AUSTRALIA 61 +#define CTRY_AUSTRIA 43 +#define CTRY_AZERBAIJAN 994 +#define CTRY_BAHRAIN 973 +#define CTRY_BELARUS 375 +#define CTRY_BELGIUM 32 +#define CTRY_BELIZE 501 +#define CTRY_BOLIVIA 591 +#define CTRY_BRAZIL 55 +#define CTRY_BRUNEI_DARUSSALAM 673 +#define CTRY_BULGARIA 359 +#define CTRY_CANADA 2 +#define CTRY_CARIBBEAN 1 +#define CTRY_CHILE 56 +#define CTRY_COLOMBIA 57 +#define CTRY_COSTA_RICA 506 +#define CTRY_CROATIA 385 +#define CTRY_CZECH 420 +#define CTRY_DENMARK 45 +#define CTRY_DOMINICAN_REPUBLIC 1 +#define CTRY_ECUADOR 593 +#define CTRY_EGYPT 20 +#define CTRY_EL_SALVADOR 503 +#define CTRY_ESTONIA 372 +#define CTRY_FAEROE_ISLANDS 298 +#define CTRY_FINLAND 358 +#define CTRY_FRANCE 33 +#define CTRY_GEORGIA 995 +#define CTRY_GERMANY 49 +#define CTRY_GREECE 30 +#define CTRY_GUATEMALA 502 +#define CTRY_HONDURAS 504 +#define CTRY_HONG_KONG 852 +#define CTRY_HUNGARY 36 +#define CTRY_ICELAND 354 +#define CTRY_INDIA 91 +#define CTRY_INDONESIA 62 +#define CTRY_IRAN 981 +#define CTRY_IRAQ 964 +#define CTRY_IRELAND 353 +#define CTRY_ISRAEL 972 +#define CTRY_ITALY 39 +#define CTRY_JAMAICA 1 +#define CTRY_JAPAN 81 +#define CTRY_JORDAN 962 +#define CTRY_KAZAKSTAN 7 +#define CTRY_KENYA 254 +#define CTRY_KUWAIT 965 +#define CTRY_KYRGYZSTAN 996 +#define CTRY_LATVIA 371 +#define CTRY_LEBANON 961 +#define CTRY_LIBYA 218 +#define CTRY_LIECHTENSTEIN 41 +#define CTRY_LITHUANIA 370 +#define CTRY_LUXEMBOURG 352 +#define CTRY_MACAU 853 +#define CTRY_MACEDONIA 389 +#define CTRY_MALAYSIA 60 +#define CTRY_MALDIVES 960 +#define CTRY_MEXICO 52 +#define CTRY_MONACO 33 +#define CTRY_MONGOLIA 976 +#define CTRY_MOROCCO 212 +#define CTRY_NETHERLANDS 31 +#define CTRY_NEW_ZEALAND 64 +#define CTRY_NICARAGUA 505 +#define CTRY_NORWAY 47 +#define CTRY_OMAN 968 +#define CTRY_PAKISTAN 92 +#define CTRY_PANAMA 507 +#define CTRY_PARAGUAY 595 +#define CTRY_PERU 51 +#define CTRY_PHILIPPINES 63 +#define CTRY_POLAND 48 +#define CTRY_PORTUGAL 351 +#define CTRY_PRCHINA 86 +#define CTRY_PUERTO_RICO 1 +#define CTRY_QATAR 974 +#define CTRY_ROMANIA 40 +#define CTRY_RUSSIA 7 +#define CTRY_SAUDI_ARABIA 966 +#define CTRY_SERBIA 381 +#define CTRY_SINGAPORE 65 +#define CTRY_SLOVAK 421 +#define CTRY_SLOVENIA 386 +#define CTRY_SOUTH_AFRICA 27 +#define CTRY_SOUTH_KOREA 82 +#define CTRY_SPAIN 34 +#define CTRY_SWEDEN 46 +#define CTRY_SWITZERLAND 41 +#define CTRY_SYRIA 963 +#define CTRY_TAIWAN 886 +#define CTRY_TATARSTAN 7 +#define CTRY_THAILAND 66 +#define CTRY_TRINIDAD_Y_TOBAGO 1 +#define CTRY_TUNISIA 216 +#define CTRY_TURKEY 90 +#define CTRY_UAE 971 +#define CTRY_UKRAINE 380 +#define CTRY_UNITED_KINGDOM 44 +#define CTRY_UNITED_STATES 1 +#define CTRY_URUGUAY 598 +#define CTRY_UZBEKISTAN 7 +#define CTRY_VENEZUELA 58 +#define CTRY_VIET_NAM 84 +#define CTRY_YEMEN 967 +#define CTRY_ZIMBABWE 263 + +#define LOCALE_NOUSEROVERRIDE 0x80000000 +#define LOCALE_USE_CP_ACP 0x40000000 +#define LOCALE_RETURN_NUMBER 0x20000000 + +#define LOCALE_ILANGUAGE 0x00000001 +#define LOCALE_SLANGUAGE 0x00000002 +#define LOCALE_SENGLANGUAGE 0x00001001 +#define LOCALE_SABBREVLANGNAME 0x00000003 +#define LOCALE_SNATIVELANGNAME 0x00000004 + +#define LOCALE_ICOUNTRY 0x00000005 +#define LOCALE_SCOUNTRY 0x00000006 +#define LOCALE_SENGCOUNTRY 0x00001002 +#define LOCALE_SABBREVCTRYNAME 0x00000007 +#define LOCALE_SNATIVECTRYNAME 0x00000008 + +#define LOCALE_IDEFAULTLANGUAGE 0x00000009 +#define LOCALE_IDEFAULTCOUNTRY 0x0000000A +#define LOCALE_IDEFAULTCODEPAGE 0x0000000B +#define LOCALE_IDEFAULTANSICODEPAGE 0x00001004 +#define LOCALE_IDEFAULTMACCODEPAGE 0x00001011 + +#define LOCALE_SLIST 0x0000000C +#define LOCALE_IMEASURE 0x0000000D + +#define LOCALE_SDECIMAL 0x0000000E +#define LOCALE_STHOUSAND 0x0000000F +#define LOCALE_SGROUPING 0x00000010 +#define LOCALE_IDIGITS 0x00000011 +#define LOCALE_ILZERO 0x00000012 +#define LOCALE_INEGNUMBER 0x00001010 +#define LOCALE_SNATIVEDIGITS 0x00000013 + +#define LOCALE_SCURRENCY 0x00000014 +#define LOCALE_SINTLSYMBOL 0x00000015 +#define LOCALE_SMONDECIMALSEP 0x00000016 +#define LOCALE_SMONTHOUSANDSEP 0x00000017 +#define LOCALE_SMONGROUPING 0x00000018 +#define LOCALE_ICURRDIGITS 0x00000019 +#define LOCALE_IINTLCURRDIGITS 0x0000001A +#define LOCALE_ICURRENCY 0x0000001B +#define LOCALE_INEGCURR 0x0000001C + +#define LOCALE_SDATE 0x0000001D +#define LOCALE_STIME 0x0000001E +#define LOCALE_SSHORTDATE 0x0000001F +#define LOCALE_SLONGDATE 0x00000020 +#define LOCALE_STIMEFORMAT 0x00001003 +#define LOCALE_IDATE 0x00000021 +#define LOCALE_ILDATE 0x00000022 +#define LOCALE_ITIME 0x00000023 +#define LOCALE_ITIMEMARKPOSN 0x00001005 +#define LOCALE_ICENTURY 0x00000024 +#define LOCALE_ITLZERO 0x00000025 +#define LOCALE_IDAYLZERO 0x00000026 +#define LOCALE_IMONLZERO 0x00000027 +#define LOCALE_S1159 0x00000028 +#define LOCALE_S2359 0x00000029 + +#define LOCALE_ICALENDARTYPE 0x00001009 +#define LOCALE_IOPTIONALCALENDAR 0x0000100B +#define LOCALE_IFIRSTDAYOFWEEK 0x0000100C +#define LOCALE_IFIRSTWEEKOFYEAR 0x0000100D + +#define LOCALE_SDAYNAME1 0x0000002A +#define LOCALE_SDAYNAME2 0x0000002B +#define LOCALE_SDAYNAME3 0x0000002C +#define LOCALE_SDAYNAME4 0x0000002D +#define LOCALE_SDAYNAME5 0x0000002E +#define LOCALE_SDAYNAME6 0x0000002F +#define LOCALE_SDAYNAME7 0x00000030 +#define LOCALE_SABBREVDAYNAME1 0x00000031 +#define LOCALE_SABBREVDAYNAME2 0x00000032 +#define LOCALE_SABBREVDAYNAME3 0x00000033 +#define LOCALE_SABBREVDAYNAME4 0x00000034 +#define LOCALE_SABBREVDAYNAME5 0x00000035 +#define LOCALE_SABBREVDAYNAME6 0x00000036 +#define LOCALE_SABBREVDAYNAME7 0x00000037 +#define LOCALE_SMONTHNAME1 0x00000038 +#define LOCALE_SMONTHNAME2 0x00000039 +#define LOCALE_SMONTHNAME3 0x0000003A +#define LOCALE_SMONTHNAME4 0x0000003B +#define LOCALE_SMONTHNAME5 0x0000003C +#define LOCALE_SMONTHNAME6 0x0000003D +#define LOCALE_SMONTHNAME7 0x0000003E +#define LOCALE_SMONTHNAME8 0x0000003F +#define LOCALE_SMONTHNAME9 0x00000040 +#define LOCALE_SMONTHNAME10 0x00000041 +#define LOCALE_SMONTHNAME11 0x00000042 +#define LOCALE_SMONTHNAME12 0x00000043 +#define LOCALE_SMONTHNAME13 0x0000100E +#define LOCALE_SABBREVMONTHNAME1 0x00000044 +#define LOCALE_SABBREVMONTHNAME2 0x00000045 +#define LOCALE_SABBREVMONTHNAME3 0x00000046 +#define LOCALE_SABBREVMONTHNAME4 0x00000047 +#define LOCALE_SABBREVMONTHNAME5 0x00000048 +#define LOCALE_SABBREVMONTHNAME6 0x00000049 +#define LOCALE_SABBREVMONTHNAME7 0x0000004A +#define LOCALE_SABBREVMONTHNAME8 0x0000004B +#define LOCALE_SABBREVMONTHNAME9 0x0000004C +#define LOCALE_SABBREVMONTHNAME10 0x0000004D +#define LOCALE_SABBREVMONTHNAME11 0x0000004E +#define LOCALE_SABBREVMONTHNAME12 0x0000004F +#define LOCALE_SABBREVMONTHNAME13 0x0000100F + +#define LOCALE_SPOSITIVESIGN 0x00000050 +#define LOCALE_SNEGATIVESIGN 0x00000051 +#define LOCALE_IPOSSIGNPOSN 0x00000052 +#define LOCALE_INEGSIGNPOSN 0x00000053 +#define LOCALE_IPOSSYMPRECEDES 0x00000054 +#define LOCALE_IPOSSEPBYSPACE 0x00000055 +#define LOCALE_INEGSYMPRECEDES 0x00000056 +#define LOCALE_INEGSEPBYSPACE 0x00000057 +#define LOCALE_FONTSIGNATURE 0x00000058 +#define LOCALE_SISO639LANGNAME 0x00000059 +#define LOCALE_SISO3166CTRYNAME 0x0000005A + +#define LOCALE_IDEFAULTEBCDICCODEPAGE 0x00001012 +#define LOCALE_IPAPERSIZE 0x0000100A +#define LOCALE_SENGCURRNAME 0x00001007 +#define LOCALE_SNATIVECURRNAME 0x00001008 +#define LOCALE_SYEARMONTH 0x00001006 +#define LOCALE_SSORTNAME 0x00001013 +#define LOCALE_IDIGITSUBSTITUTION 0x00001014 + +#define TIME_NOMINUTESORSECONDS 0x00000001 +#define TIME_NOSECONDS 0x00000002 +#define TIME_NOTIMEMARKER 0x00000004 +#define TIME_FORCE24HOURFORMAT 0x00000008 + +#define DATE_SHORTDATE 0x00000001 +#define DATE_LONGDATE 0x00000002 +#define DATE_USE_ALT_CALENDAR 0x00000004 +#define DATE_YEARMONTH 0x00000008 +#define DATE_LTRREADING 0x00000010 +#define DATE_RTLREADING 0x00000020 + +#define CAL_NOUSEROVERRIDE LOCALE_NOUSEROVERRIDE +#define CAL_USE_CP_ACP LOCALE_USE_CP_ACP +#define CAL_RETURN_NUMBER LOCALE_RETURN_NUMBER + +#define CAL_ICALINTVALUE 0x00000001 +#define CAL_SCALNAME 0x00000002 +#define CAL_IYEAROFFSETRANGE 0x00000003 +#define CAL_SERASTRING 0x00000004 +#define CAL_SSHORTDATE 0x00000005 +#define CAL_SLONGDATE 0x00000006 +#define CAL_SDAYNAME1 0x00000007 +#define CAL_SDAYNAME2 0x00000008 +#define CAL_SDAYNAME3 0x00000009 +#define CAL_SDAYNAME4 0x0000000a +#define CAL_SDAYNAME5 0x0000000b +#define CAL_SDAYNAME6 0x0000000c +#define CAL_SDAYNAME7 0x0000000d +#define CAL_SABBREVDAYNAME1 0x0000000e +#define CAL_SABBREVDAYNAME2 0x0000000f +#define CAL_SABBREVDAYNAME3 0x00000010 +#define CAL_SABBREVDAYNAME4 0x00000011 +#define CAL_SABBREVDAYNAME5 0x00000012 +#define CAL_SABBREVDAYNAME6 0x00000013 +#define CAL_SABBREVDAYNAME7 0x00000014 +#define CAL_SMONTHNAME1 0x00000015 +#define CAL_SMONTHNAME2 0x00000016 +#define CAL_SMONTHNAME3 0x00000017 +#define CAL_SMONTHNAME4 0x00000018 +#define CAL_SMONTHNAME5 0x00000019 +#define CAL_SMONTHNAME6 0x0000001a +#define CAL_SMONTHNAME7 0x0000001b +#define CAL_SMONTHNAME8 0x0000001c +#define CAL_SMONTHNAME9 0x0000001d +#define CAL_SMONTHNAME10 0x0000001e +#define CAL_SMONTHNAME11 0x0000001f +#define CAL_SMONTHNAME12 0x00000020 +#define CAL_SMONTHNAME13 0x00000021 +#define CAL_SABBREVMONTHNAME1 0x00000022 +#define CAL_SABBREVMONTHNAME2 0x00000023 +#define CAL_SABBREVMONTHNAME3 0x00000024 +#define CAL_SABBREVMONTHNAME4 0x00000025 +#define CAL_SABBREVMONTHNAME5 0x00000026 +#define CAL_SABBREVMONTHNAME6 0x00000027 +#define CAL_SABBREVMONTHNAME7 0x00000028 +#define CAL_SABBREVMONTHNAME8 0x00000029 +#define CAL_SABBREVMONTHNAME9 0x0000002a +#define CAL_SABBREVMONTHNAME10 0x0000002b +#define CAL_SABBREVMONTHNAME11 0x0000002c +#define CAL_SABBREVMONTHNAME12 0x0000002d +#define CAL_SABBREVMONTHNAME13 0x0000002e +#define CAL_SYEARMONTH 0x0000002f +#define CAL_ITWODIGITYEARMAX 0x00000030 + +#define ENUM_ALL_CALENDARS 0xffffffff + +#define CAL_GREGORIAN 1 +#define CAL_GREGORIAN_US 2 +#define CAL_JAPAN 3 +#define CAL_TAIWAN 4 +#define CAL_KOREA 5 +#define CAL_HIJRI 6 +#define CAL_THAI 7 +#define CAL_HEBREW 8 +#define CAL_GREGORIAN_ME_FRENCH 9 +#define CAL_GREGORIAN_ARABIC 10 +#define CAL_GREGORIAN_XLIT_ENGLISH 11 +#define CAL_GREGORIAN_XLIT_FRENCH 12 + +#define LGRPID_WESTERN_EUROPE 0x0001 +#define LGRPID_CENTRAL_EUROPE 0x0002 +#define LGRPID_BALTIC 0x0003 +#define LGRPID_GREEK 0x0004 +#define LGRPID_CYRILLIC 0x0005 +#define LGRPID_TURKISH 0x0006 +#define LGRPID_JAPANESE 0x0007 +#define LGRPID_KOREAN 0x0008 +#define LGRPID_TRADITIONAL_CHINESE 0x0009 +#define LGRPID_SIMPLIFIED_CHINESE 0x000a +#define LGRPID_THAI 0x000b +#define LGRPID_HEBREW 0x000c +#define LGRPID_ARABIC 0x000d +#define LGRPID_VIETNAMESE 0x000e +#define LGRPID_INDIC 0x000f +#define LGRPID_GEORGIAN 0x0010 +#define LGRPID_ARMENIAN 0x0011 + + typedef DWORD LGRPID; + typedef DWORD LCTYPE; + typedef DWORD CALTYPE; + typedef DWORD CALID; + + typedef struct _cpinfo { + UINT MaxCharSize; + BYTE DefaultChar[MAX_DEFAULTCHAR]; + BYTE LeadByte[MAX_LEADBYTES]; + } CPINFO,*LPCPINFO; + + typedef struct _cpinfoexA { + UINT MaxCharSize; + BYTE DefaultChar[MAX_DEFAULTCHAR]; + BYTE LeadByte[MAX_LEADBYTES]; + WCHAR UnicodeDefaultChar; + UINT CodePage; + CHAR CodePageName[MAX_PATH]; + } CPINFOEXA,*LPCPINFOEXA; + + typedef struct _cpinfoexW { + UINT MaxCharSize; + BYTE DefaultChar[MAX_DEFAULTCHAR]; + BYTE LeadByte[MAX_LEADBYTES]; + WCHAR UnicodeDefaultChar; + UINT CodePage; + WCHAR CodePageName[MAX_PATH]; + } CPINFOEXW,*LPCPINFOEXW; + +#ifdef UNICODE + typedef CPINFOEXW CPINFOEX; + typedef LPCPINFOEXW LPCPINFOEX; +#else + typedef CPINFOEXA CPINFOEX; + typedef LPCPINFOEXA LPCPINFOEX; +#endif + + typedef struct _numberfmtA { + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPSTR lpDecimalSep; + LPSTR lpThousandSep; + UINT NegativeOrder; + } NUMBERFMTA,*LPNUMBERFMTA; + + typedef struct _numberfmtW { + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPWSTR lpDecimalSep; + LPWSTR lpThousandSep; + UINT NegativeOrder; + } NUMBERFMTW,*LPNUMBERFMTW; + +#ifdef UNICODE + typedef NUMBERFMTW NUMBERFMT; + typedef LPNUMBERFMTW LPNUMBERFMT; +#else + typedef NUMBERFMTA NUMBERFMT; + typedef LPNUMBERFMTA LPNUMBERFMT; +#endif + + typedef struct _currencyfmtA { + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPSTR lpDecimalSep; + LPSTR lpThousandSep; + UINT NegativeOrder; + UINT PositiveOrder; + LPSTR lpCurrencySymbol; + } CURRENCYFMTA,*LPCURRENCYFMTA; + + typedef struct _currencyfmtW { + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPWSTR lpDecimalSep; + LPWSTR lpThousandSep; + UINT NegativeOrder; + UINT PositiveOrder; + LPWSTR lpCurrencySymbol; + } CURRENCYFMTW,*LPCURRENCYFMTW; + +#ifdef UNICODE + typedef CURRENCYFMTW CURRENCYFMT; + typedef LPCURRENCYFMTW LPCURRENCYFMT; +#else + typedef CURRENCYFMTA CURRENCYFMT; + typedef LPCURRENCYFMTA LPCURRENCYFMT; +#endif + + enum SYSNLS_FUNCTION { + COMPARE_STRING = 0x0001 + }; + + typedef DWORD NLS_FUNCTION; + + typedef struct _nlsversioninfo{ + DWORD dwNLSVersionInfoSize; + DWORD dwNLSVersion; + DWORD dwDefinedVersion; + } NLSVERSIONINFO,*LPNLSVERSIONINFO; + + typedef LONG GEOID; + typedef DWORD GEOTYPE; + typedef DWORD GEOCLASS; + +#define GEOID_NOT_AVAILABLE -1 + + enum SYSGEOTYPE { + GEO_NATION = 0x0001,GEO_LATITUDE = 0x0002,GEO_LONGITUDE = 0x0003,GEO_ISO2 = 0x0004,GEO_ISO3 = 0x0005,GEO_RFC1766 = 0x0006,GEO_LCID = 0x0007, + GEO_FRIENDLYNAME= 0x0008,GEO_OFFICIALNAME= 0x0009,GEO_TIMEZONES = 0x000A,GEO_OFFICIALLANGUAGES = 0x000B + }; + + enum SYSGEOCLASS { + GEOCLASS_NATION = 16,GEOCLASS_REGION = 14 + }; + + typedef enum _NORM_FORM { + NormalizationOther = 0, + NormalizationC = 0x1, + NormalizationD = 0x2, + NormalizationKC = 0x5, + NormalizationKD = 0x6 +} NORM_FORM; + + typedef WINBOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCA)(LGRPID,LPSTR,LPSTR,DWORD,LONG_PTR); + typedef WINBOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCA)(LGRPID,LCID,LPSTR,LONG_PTR); + typedef WINBOOL (CALLBACK *UILANGUAGE_ENUMPROCA)(LPSTR,LONG_PTR); + typedef WINBOOL (CALLBACK *LOCALE_ENUMPROCA)(LPSTR); + typedef WINBOOL (CALLBACK *CODEPAGE_ENUMPROCA)(LPSTR); + typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCA)(LPSTR); + typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCEXA)(LPSTR,CALID); + typedef WINBOOL (CALLBACK *TIMEFMT_ENUMPROCA)(LPSTR); + typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCA)(LPSTR); + typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCEXA)(LPSTR,CALID); + typedef WINBOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCW)(LGRPID,LPWSTR,LPWSTR,DWORD,LONG_PTR); + typedef WINBOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCW)(LGRPID,LCID,LPWSTR,LONG_PTR); + typedef WINBOOL (CALLBACK *UILANGUAGE_ENUMPROCW)(LPWSTR,LONG_PTR); + typedef WINBOOL (CALLBACK *LOCALE_ENUMPROCW)(LPWSTR); + typedef WINBOOL (CALLBACK *CODEPAGE_ENUMPROCW)(LPWSTR); + typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCW)(LPWSTR); + typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCEXW)(LPWSTR,CALID); + typedef WINBOOL (CALLBACK *TIMEFMT_ENUMPROCW)(LPWSTR); + typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCW)(LPWSTR); + typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCEXW)(LPWSTR,CALID); + typedef WINBOOL (CALLBACK *GEO_ENUMPROC)(GEOID); + +#ifdef UNICODE +#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCW +#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCW +#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCW +#define LOCALE_ENUMPROC LOCALE_ENUMPROCW +#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCW +#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCW +#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXW +#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCW +#define CALINFO_ENUMPROC CALINFO_ENUMPROCW +#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXW +#else +#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCA +#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCA +#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCA +#define LOCALE_ENUMPROC LOCALE_ENUMPROCA +#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCA +#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCA +#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXA +#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCA +#define CALINFO_ENUMPROC CALINFO_ENUMPROCA +#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXA +#endif + +#ifdef UNICODE +#define GetCPInfoEx GetCPInfoExW +#define CompareString CompareStringW +#define LCMapString LCMapStringW +#define GetLocaleInfo GetLocaleInfoW +#define SetLocaleInfo SetLocaleInfoW +#define GetCalendarInfo GetCalendarInfoW +#define SetCalendarInfo SetCalendarInfoW +#define GetTimeFormat GetTimeFormatW +#define GetDateFormat GetDateFormatW +#define GetNumberFormat GetNumberFormatW +#define GetCurrencyFormat GetCurrencyFormatW +#define EnumCalendarInfo EnumCalendarInfoW +#define EnumCalendarInfoEx EnumCalendarInfoExW +#define EnumTimeFormats EnumTimeFormatsW +#define EnumDateFormats EnumDateFormatsW +#define EnumDateFormatsEx EnumDateFormatsExW +#define GetGeoInfo GetGeoInfoW +#define GetStringTypeEx GetStringTypeExW +#define FoldString FoldStringW +#define EnumSystemLanguageGroups EnumSystemLanguageGroupsW +#define EnumLanguageGroupLocales EnumLanguageGroupLocalesW +#define EnumUILanguages EnumUILanguagesW +#define EnumSystemLocales EnumSystemLocalesW +#define EnumSystemCodePages EnumSystemCodePagesW +#else +#define GetCPInfoEx GetCPInfoExA +#define CompareString CompareStringA +#define LCMapString LCMapStringA +#define GetLocaleInfo GetLocaleInfoA +#define SetLocaleInfo SetLocaleInfoA +#define GetCalendarInfo GetCalendarInfoA +#define SetCalendarInfo SetCalendarInfoA +#define GetTimeFormat GetTimeFormatA +#define GetDateFormat GetDateFormatA +#define GetNumberFormat GetNumberFormatA +#define GetCurrencyFormat GetCurrencyFormatA +#define EnumCalendarInfo EnumCalendarInfoA +#define EnumCalendarInfoEx EnumCalendarInfoExA +#define EnumTimeFormats EnumTimeFormatsA +#define EnumDateFormats EnumDateFormatsA +#define EnumDateFormatsEx EnumDateFormatsExA +#define GetGeoInfo GetGeoInfoA +#define GetStringTypeEx GetStringTypeExA +#define FoldString FoldStringA +#define EnumSystemLanguageGroups EnumSystemLanguageGroupsA +#define EnumLanguageGroupLocales EnumLanguageGroupLocalesA +#define EnumUILanguages EnumUILanguagesA +#define EnumSystemLocales EnumSystemLocalesA +#define EnumSystemCodePages EnumSystemCodePagesA +#endif + + WINBASEAPI WINBOOL WINAPI IsValidCodePage(UINT CodePage); + WINBASEAPI UINT WINAPI GetACP(void); + WINBASEAPI UINT WINAPI GetOEMCP(void); + WINBASEAPI WINBOOL WINAPI GetCPInfo(UINT CodePage,LPCPINFO lpCPInfo); + WINBASEAPI WINBOOL WINAPI GetCPInfoExA(UINT CodePage,DWORD dwFlags,LPCPINFOEXA lpCPInfoEx); + WINBASEAPI WINBOOL WINAPI GetCPInfoExW(UINT CodePage,DWORD dwFlags,LPCPINFOEXW lpCPInfoEx); + WINBASEAPI WINBOOL WINAPI IsDBCSLeadByte(BYTE TestChar); + WINBASEAPI WINBOOL WINAPI IsDBCSLeadByteEx(UINT CodePage,BYTE TestChar); + WINBASEAPI int WINAPI MultiByteToWideChar(UINT CodePage,DWORD dwFlags,LPCSTR lpMultiByteStr,int cbMultiByte,LPWSTR lpWideCharStr,int cchWideChar); + WINBASEAPI int WINAPI WideCharToMultiByte(UINT CodePage,DWORD dwFlags,LPCWSTR lpWideCharStr,int cchWideChar,LPSTR lpMultiByteStr,int cbMultiByte,LPCSTR lpDefaultChar,LPBOOL lpUsedDefaultChar); + WINBASEAPI int WINAPI CompareStringA(LCID Locale,DWORD dwCmpFlags,LPCSTR lpString1,int cchCount1,LPCSTR lpString2,int cchCount2); + WINBASEAPI int WINAPI CompareStringW(LCID Locale,DWORD dwCmpFlags,LPCWSTR lpString1,int cchCount1,LPCWSTR lpString2,int cchCount2); + WINBASEAPI int WINAPI LCMapStringA(LCID Locale,DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest); + WINBASEAPI int WINAPI LCMapStringW(LCID Locale,DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest); + WINBASEAPI int WINAPI GetLocaleInfoA(LCID Locale,LCTYPE LCType,LPSTR lpLCData,int cchData); + WINBASEAPI int WINAPI GetLocaleInfoW(LCID Locale,LCTYPE LCType,LPWSTR lpLCData,int cchData); + WINBASEAPI WINBOOL WINAPI SetLocaleInfoA(LCID Locale,LCTYPE LCType,LPCSTR lpLCData); + WINBASEAPI WINBOOL WINAPI SetLocaleInfoW(LCID Locale,LCTYPE LCType,LPCWSTR lpLCData); + WINBASEAPI int WINAPI GetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPSTR lpCalData,int cchData,LPDWORD lpValue); + WINBASEAPI int WINAPI GetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPWSTR lpCalData,int cchData,LPDWORD lpValue); + WINBASEAPI WINBOOL WINAPI SetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPCSTR lpCalData); + WINBASEAPI WINBOOL WINAPI SetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPCWSTR lpCalData); + WINBASEAPI int WINAPI GetTimeFormatA(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpTime,LPCSTR lpFormat,LPSTR lpTimeStr,int cchTime); + WINBASEAPI int WINAPI GetTimeFormatW(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpTime,LPCWSTR lpFormat,LPWSTR lpTimeStr,int cchTime); + WINBASEAPI int WINAPI GetDateFormatA(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpDate,LPCSTR lpFormat,LPSTR lpDateStr,int cchDate); + WINBASEAPI int WINAPI GetDateFormatW(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpDate,LPCWSTR lpFormat,LPWSTR lpDateStr,int cchDate); + WINBASEAPI int WINAPI GetNumberFormatA(LCID Locale,DWORD dwFlags,LPCSTR lpValue,CONST NUMBERFMTA *lpFormat,LPSTR lpNumberStr,int cchNumber); + WINBASEAPI int WINAPI GetNumberFormatW(LCID Locale,DWORD dwFlags,LPCWSTR lpValue,CONST NUMBERFMTW *lpFormat,LPWSTR lpNumberStr,int cchNumber); + WINBASEAPI int WINAPI GetCurrencyFormatA(LCID Locale,DWORD dwFlags,LPCSTR lpValue,CONST CURRENCYFMTA *lpFormat,LPSTR lpCurrencyStr,int cchCurrency); + WINBASEAPI int WINAPI GetCurrencyFormatW(LCID Locale,DWORD dwFlags,LPCWSTR lpValue,CONST CURRENCYFMTW *lpFormat,LPWSTR lpCurrencyStr,int cchCurrency); + WINBASEAPI WINBOOL WINAPI EnumCalendarInfoA(CALINFO_ENUMPROCA lpCalInfoEnumProc,LCID Locale,CALID Calendar,CALTYPE CalType); + WINBASEAPI WINBOOL WINAPI EnumCalendarInfoW(CALINFO_ENUMPROCW lpCalInfoEnumProc,LCID Locale,CALID Calendar,CALTYPE CalType); + WINBASEAPI WINBOOL WINAPI EnumCalendarInfoExA(CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx,LCID Locale,CALID Calendar,CALTYPE CalType); + WINBASEAPI WINBOOL WINAPI EnumCalendarInfoExW(CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx,LCID Locale,CALID Calendar,CALTYPE CalType); + WINBASEAPI WINBOOL WINAPI EnumTimeFormatsA(TIMEFMT_ENUMPROCA lpTimeFmtEnumProc,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumTimeFormatsW(TIMEFMT_ENUMPROCW lpTimeFmtEnumProc,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA lpDateFmtEnumProc,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumDateFormatsW(DATEFMT_ENUMPROCW lpDateFmtEnumProc,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumDateFormatsExA(DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumDateFormatsExW(DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI IsValidLanguageGroup(LGRPID LanguageGroup,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI GetNLSVersion(NLS_FUNCTION Function,LCID Locale,LPNLSVERSIONINFO lpVersionInformation); + WINBASEAPI WINBOOL WINAPI IsNLSDefinedString(NLS_FUNCTION Function,DWORD dwFlags,LPNLSVERSIONINFO lpVersionInformation,LPCWSTR lpString,INT cchStr); + WINBASEAPI WINBOOL WINAPI IsValidLocale(LCID Locale,DWORD dwFlags); + WINBASEAPI int WINAPI GetGeoInfoA(GEOID Location,GEOTYPE GeoType,LPSTR lpGeoData,int cchData,LANGID LangId); + WINBASEAPI int WINAPI GetGeoInfoW(GEOID Location,GEOTYPE GeoType,LPWSTR lpGeoData,int cchData,LANGID LangId); + WINBASEAPI WINBOOL WINAPI EnumSystemGeoID(GEOCLASS GeoClass,GEOID ParentGeoId,GEO_ENUMPROC lpGeoEnumProc); + WINBASEAPI GEOID WINAPI GetUserGeoID(GEOCLASS GeoClass); + WINBASEAPI WINBOOL WINAPI SetUserGeoID(GEOID GeoId); + WINBASEAPI LCID WINAPI ConvertDefaultLocale(LCID Locale); + WINBASEAPI LCID WINAPI GetThreadLocale(void); + WINBASEAPI WINBOOL WINAPI SetThreadLocale(LCID Locale); + WINBASEAPI LANGID WINAPI GetSystemDefaultUILanguage(void); + WINBASEAPI LANGID WINAPI GetUserDefaultUILanguage(void); + WINBASEAPI LANGID WINAPI GetSystemDefaultLangID(void); + WINBASEAPI LANGID WINAPI GetUserDefaultLangID(void); + WINBASEAPI LCID WINAPI GetSystemDefaultLCID(void); + WINBASEAPI LCID WINAPI GetUserDefaultLCID(void); + WINBASEAPI WINBOOL WINAPI GetStringTypeExA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType); + WINBASEAPI WINBOOL WINAPI GetStringTypeExW(LCID Locale,DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType); + WINBASEAPI WINBOOL WINAPI GetStringTypeA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType); + WINBASEAPI WINBOOL WINAPI GetStringTypeW(DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType); + WINBASEAPI int WINAPI FoldStringA(DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest); + WINBASEAPI int WINAPI FoldStringW(DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest); + WINBASEAPI WINBOOL WINAPI EnumSystemLanguageGroupsA(LANGUAGEGROUP_ENUMPROCA lpLanguageGroupEnumProc,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumSystemLanguageGroupsW(LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumLanguageGroupLocalesA(LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc,LGRPID LanguageGroup,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumLanguageGroupLocalesW(LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc,LGRPID LanguageGroup,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumUILanguagesA(UILANGUAGE_ENUMPROCA lpUILanguageEnumProc,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumUILanguagesW(UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumSystemLocalesA(LOCALE_ENUMPROCA lpLocaleEnumProc,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumSystemLocalesW(LOCALE_ENUMPROCW lpLocaleEnumProc,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumSystemCodePagesA(CODEPAGE_ENUMPROCA lpCodePageEnumProc,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumSystemCodePagesW(CODEPAGE_ENUMPROCW lpCodePageEnumProc,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI IsNormalizedString(NORM_FORM NormForm,LPCWSTR lpString,int cwLength); + WINBASEAPI int WINAPI NormalizeString(NORM_FORM NormForm,LPCWSTR lpSrcString,int cwSrcLength,LPWSTR lpDstString,int cwDstLength); + WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,LPCWSTR lpUnicodeCharStr,int cchUnicodeChar,LPWSTR lpASCIICharStr,int cchASCIIChar); + WINBASEAPI int WINAPI IdnToNameprepUnicode(DWORD dwFlags,LPCWSTR lpUnicodeCharStr,int cchUnicodeChar,LPWSTR lpNameprepCharStr,int cchNameprepChar); + WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,LPCWSTR lpASCIICharStr,int cchASCIIChar,LPWSTR lpUnicodeCharStr,int cchUnicodeChar); + +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/winnt.h b/tcc/include/winapi/winnt.h index 8c334047..41a9aa2c 100644 --- a/tcc/include/winapi/winnt.h +++ b/tcc/include/winapi/winnt.h @@ -1,5835 +1,5835 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINNT_ -#define _WINNT_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#define ANYSIZE_ARRAY 1 - -//gr #include - -#define RESTRICTED_POINTER - -#ifndef __CRT_UNALIGNED -#define __CRT_UNALIGNED -#endif - -#if defined(__ia64__) || defined(__x86_64) -#define UNALIGNED __CRT_UNALIGNED -#ifdef _WIN64 -#define UNALIGNED64 __CRT_UNALIGNED -#else -#define UNALIGNED64 -#endif -#else -#define UNALIGNED -#define UNALIGNED64 -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) -#define I_X86_ -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) -#define _AMD64_ -#endif - -#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) -#if !defined(_IA64_) -#define _IA64_ -#endif -#endif - - -#ifdef _WIN64 -#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) -#define MEMORY_ALLOCATION_ALIGNMENT 16 -#else -#define MAX_NATURAL_ALIGNMENT sizeof(DWORD) -#define MEMORY_ALLOCATION_ALIGNMENT 8 -#endif - -#ifdef __cplusplus -#define TYPE_ALIGNMENT(t) __alignof__ (t) -#else -#define TYPE_ALIGNMENT(t) FIELD_OFFSET(struct { char x; t test; },test) -#endif - -#ifdef _WIN64 -#ifdef _AMD64_ -#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) -#elif defined(_IA64_) -#define PROBE_ALIGNMENT(_s) (TYPE_ALIGNMENT(_s) > TYPE_ALIGNMENT(DWORD) ? TYPE_ALIGNMENT(_s) : TYPE_ALIGNMENT(DWORD)) -#else -#error No Target Architecture -#endif -#define PROBE_ALIGNMENT32(_s) TYPE_ALIGNMENT(DWORD) -#else -#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) -#endif - -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] - -#include - -#if defined(_X86_) || defined(__ia64__) || defined(__x86_64) -#define DECLSPEC_IMPORT __declspec(dllimport) -#else -#define DECLSPEC_IMPORT -#endif - -#ifndef DECLSPEC_NORETURN -#define DECLSPEC_NORETURN __declspec(noreturn) -#endif - -#ifndef DECLSPEC_ALIGN -#define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) -#endif - -#ifndef SYSTEM_CACHE_ALIGNMENT_SIZE -#if defined(_AMD64_) || defined(I_X86_) -#define SYSTEM_CACHE_ALIGNMENT_SIZE 64 -#else -#define SYSTEM_CACHE_ALIGNMENT_SIZE 128 -#endif -#endif - -#ifndef DECLSPEC_CACHEALIGN -#define DECLSPEC_CACHEALIGN DECLSPEC_ALIGN(SYSTEM_CACHE_ALIGNMENT_SIZE) -#endif - -#ifndef DECLSPEC_UUID -#define DECLSPEC_UUID(x) -#endif - -#ifndef DECLSPEC_NOVTABLE -#define DECLSPEC_NOVTABLE -#endif - -#ifndef DECLSPEC_SELECTANY -#define DECLSPEC_SELECTANY __declspec(selectany) -#endif - -#ifndef NOP_FUNCTION -#define NOP_FUNCTION (void)0 -#endif - -#ifndef DECLSPEC_NOINLINE -#define DECLSPEC_NOINLINE -#endif - -#ifndef FORCEINLINE -#define FORCEINLINE static __inline__ -#endif - -#ifndef DECLSPEC_DEPRECATED -#define DECLSPEC_DEPRECATED __declspec(deprecated) -#define DEPRECATE_SUPPORTED -#endif - -#define DECLSPEC_DEPRECATED_DDK -#define PRAGMA_DEPRECATED_DDK 0 - - typedef void *PVOID; - typedef void *PVOID64; - -#define NTAPI __stdcall -#define NTSYSAPI DECLSPEC_IMPORT -#define NTSYSCALLAPI DECLSPEC_IMPORT - -#ifndef VOID -#define VOID void - typedef char CHAR; - typedef short SHORT; - typedef long LONG; -#endif - - typedef wchar_t WCHAR; - typedef WCHAR *PWCHAR,*LPWCH,*PWCH; - typedef CONST WCHAR *LPCWCH,*PCWCH; - typedef WCHAR *NWPSTR,*LPWSTR,*PWSTR; - typedef PWSTR *PZPWSTR; - typedef CONST PWSTR *PCZPWSTR; - typedef WCHAR UNALIGNED *LPUWSTR,*PUWSTR; - typedef CONST WCHAR *LPCWSTR,*PCWSTR; - typedef PCWSTR *PZPCWSTR; - typedef CONST WCHAR UNALIGNED *LPCUWSTR,*PCUWSTR; - typedef CHAR *PCHAR,*LPCH,*PCH; - typedef CONST CHAR *LPCCH,*PCCH; - typedef CHAR *NPSTR,*LPSTR,*PSTR; - typedef PSTR *PZPSTR; - typedef CONST PSTR *PCZPSTR; - typedef CONST CHAR *LPCSTR,*PCSTR; - typedef PCSTR *PZPCSTR; - -#ifdef UNICODE -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED - typedef WCHAR TCHAR,*PTCHAR; - typedef WCHAR TBYTE ,*PTBYTE; -#endif - - typedef LPWSTR LPTCH,PTCH; - typedef LPWSTR PTSTR,LPTSTR; - typedef LPCWSTR PCTSTR,LPCTSTR; - typedef LPUWSTR PUTSTR,LPUTSTR; - typedef LPCUWSTR PCUTSTR,LPCUTSTR; - typedef LPWSTR LP; -#define __TEXT(quote) L##quote -#else -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED - typedef char TCHAR,*PTCHAR; - typedef unsigned char TBYTE ,*PTBYTE; -#endif - - typedef LPSTR LPTCH,PTCH; - typedef LPSTR PTSTR,LPTSTR,PUTSTR,LPUTSTR; - typedef LPCSTR PCTSTR,LPCTSTR,PCUTSTR,LPCUTSTR; -#define __TEXT(quote) quote -#endif - -#define TEXT(quote) __TEXT(quote) - - typedef SHORT *PSHORT; - typedef LONG *PLONG; - - typedef void *HANDLE; -#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name - typedef HANDLE *PHANDLE; - - typedef BYTE FCHAR; - typedef WORD FSHORT; - typedef DWORD FLONG; - -#ifndef _HRESULT_DEFINED -#define _HRESULT_DEFINED - typedef LONG HRESULT; -#endif - -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C extern -#endif - -#define STDMETHODCALLTYPE WINAPI -#define STDMETHODVCALLTYPE __cdecl -#define STDAPICALLTYPE WINAPI -#define STDAPIVCALLTYPE __cdecl -#define STDAPI EXTERN_C HRESULT WINAPI -#define STDAPI_(type) EXTERN_C type WINAPI -#define STDMETHODIMP HRESULT WINAPI -#define STDMETHODIMP_(type) type WINAPI -#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE -#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE -#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE -#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE - - typedef char CCHAR; -#ifndef _LCID_DEFINED -#define _LCID_DEFINED -typedef DWORD LCID; -#endif - typedef PDWORD PLCID; -#ifndef _LANGID_DEFINED -#define _LANGID_DEFINED - typedef WORD LANGID; -#endif -#define APPLICATION_ERROR_MASK 0x20000000 -#define ERROR_SEVERITY_SUCCESS 0x00000000 -#define ERROR_SEVERITY_INFORMATIONAL 0x40000000 -#define ERROR_SEVERITY_WARNING 0x80000000 -#define ERROR_SEVERITY_ERROR 0xC0000000 - -#ifdef __ia64__ - __declspec(align(16)) -#endif - typedef struct _FLOAT128 { - __int64 LowPart; - __int64 HighPart; - } FLOAT128; - - typedef FLOAT128 *PFLOAT128; - -#define _ULONGLONG_ -#if((!(defined(_X86_) && !defined(__x86_64)) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64))) - typedef __int64 LONGLONG; - typedef unsigned __int64 ULONGLONG; - -#define MAXLONGLONG (0x7fffffffffffffff) -#else - - typedef double LONGLONG; - typedef double ULONGLONG; -#endif - - typedef LONGLONG *PLONGLONG; - typedef ULONGLONG *PULONGLONG; - - typedef LONGLONG USN; - - typedef union _LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - }; - struct { - DWORD LowPart; - LONG HighPart; - } u; - LONGLONG QuadPart; - } LARGE_INTEGER; - - typedef LARGE_INTEGER *PLARGE_INTEGER; - - typedef union _ULARGE_INTEGER { - struct { - DWORD LowPart; - DWORD HighPart; - }; - struct { - DWORD LowPart; - DWORD HighPart; - } u; - ULONGLONG QuadPart; - } ULARGE_INTEGER; - - typedef ULARGE_INTEGER *PULARGE_INTEGER; - - typedef struct _LUID { - DWORD LowPart; - LONG HighPart; - } LUID,*PLUID; - -#define _DWORDLONG_ - typedef ULONGLONG DWORDLONG; - typedef DWORDLONG *PDWORDLONG; - -#ifdef RC_INVOKED -#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) -#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) -#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) -#elif (defined(_X86_) && !defined(__x86_64)) -#define Int32x32To64(a,b) (LONGLONG)((LONGLONG)(LONG)(a) *(LONG)(b)) -#define UInt32x32To64(a,b) (ULONGLONG)((ULONGLONG)(DWORD)(a) *(DWORD)(b)) -#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(b)) -#elif defined(__ia64__) || defined(__x86_64) -#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) -#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) -#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) -#else -#error Must define a target architecture. -#endif - -#define Int64ShraMod32(a,b) ((LONGLONG)(a) >> (b)) -#define Int64ShllMod32(a,b) ((ULONGLONG)(a) << (b)) - -#ifdef __cplusplus - extern "C" { -#endif - -#ifdef __x86_64 - -#define RotateLeft8 _rotl8 -#define RotateLeft16 _rotl16 -#define RotateRight8 _rotr8 -#define RotateRight16 _rotr16 - - unsigned char __cdecl _rotl8(unsigned char Value,unsigned char Shift); - unsigned short __cdecl _rotl16(unsigned short Value,unsigned char Shift); - unsigned char __cdecl _rotr8(unsigned char Value,unsigned char Shift); - unsigned short __cdecl _rotr16(unsigned short Value,unsigned char Shift); -#endif - -#define RotateLeft32 _rotl -#define RotateLeft64 _rotl64 -#define RotateRight32 _rotr -#define RotateRight64 _rotr64 - - unsigned int __cdecl _rotl(unsigned int Value,int Shift); - unsigned __int64 __cdecl _rotl64(unsigned __int64 Value,int Shift); - unsigned int __cdecl _rotr(unsigned int Value,int Shift); - unsigned __int64 __cdecl _rotr64(unsigned __int64 Value,int Shift); -#ifdef __cplusplus - } -#endif - -#define ANSI_NULL ((CHAR)0) -#define UNICODE_NULL ((WCHAR)0) -#define UNICODE_STRING_MAX_BYTES ((WORD) 65534) -#define UNICODE_STRING_MAX_CHARS (32767) - -#ifndef _BOOLEAN_ -#define _BOOLEAN_ - typedef BYTE BOOLEAN; -#endif - typedef BOOLEAN *PBOOLEAN; - - typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; - } LIST_ENTRY,*PLIST_ENTRY,*RESTRICTED_POINTER PRLIST_ENTRY; - - typedef struct _SINGLE_LIST_ENTRY { - struct _SINGLE_LIST_ENTRY *Next; - } SINGLE_LIST_ENTRY,*PSINGLE_LIST_ENTRY; - - typedef struct LIST_ENTRY32 { - DWORD Flink; - DWORD Blink; - } LIST_ENTRY32; - typedef LIST_ENTRY32 *PLIST_ENTRY32; - - typedef struct LIST_ENTRY64 { - ULONGLONG Flink; - ULONGLONG Blink; - } LIST_ENTRY64; - typedef LIST_ENTRY64 *PLIST_ENTRY64; - -#include - -#ifndef __OBJECTID_DEFINED -#define __OBJECTID_DEFINED - typedef struct _OBJECTID { - GUID Lineage; - DWORD Uniquifier; - } OBJECTID; -#endif - -#define MINCHAR 0x80 -#define MAXCHAR 0x7f -#define MINSHORT 0x8000 -#define MAXSHORT 0x7fff -#define MINLONG 0x80000000 -#define MAXLONG 0x7fffffff -#define MAXBYTE 0xff -#define MAXWORD 0xffff -#define MAXDWORD 0xffffffff - -#define FIELD_OFFSET(type,field) ((LONG)(LONG_PTR)&(((type *)0)->field)) -#define RTL_FIELD_SIZE(type,field) (sizeof(((type *)0)->field)) -#define RTL_SIZEOF_THROUGH_FIELD(type,field) (FIELD_OFFSET(type,field) + RTL_FIELD_SIZE(type,field)) -#define RTL_CONTAINS_FIELD(Struct,Size,Field) ((((PCHAR)(&(Struct)->Field)) + sizeof((Struct)->Field)) <= (((PCHAR)(Struct))+(Size))) -#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) -#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A) - -#ifdef ENABLE_RTL_NUMBER_OF_V2 -#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V2(A) -#else -#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V1(A) -#endif - -#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A) -#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) - -#define RTL_FIELD_TYPE(type,field) (((type*)0)->field) -#define RTL_NUMBER_OF_FIELD(type,field) (RTL_NUMBER_OF(RTL_FIELD_TYPE(type,field))) -#define RTL_PADDING_BETWEEN_FIELDS(T,F1,F2) ((FIELD_OFFSET(T,F2) > FIELD_OFFSET(T,F1)) ? (FIELD_OFFSET(T,F2) - FIELD_OFFSET(T,F1) - RTL_FIELD_SIZE(T,F1)) : (FIELD_OFFSET(T,F1) - FIELD_OFFSET(T,F2) - RTL_FIELD_SIZE(T,F2))) - -#ifdef __cplusplus -#define RTL_CONST_CAST(type) const_cast -#else -#define RTL_CONST_CAST(type) (type) -#endif - -#define RTL_BITS_OF(sizeOfArg) (sizeof(sizeOfArg) *8) -#define RTL_BITS_OF_FIELD(type,field) (RTL_BITS_OF(RTL_FIELD_TYPE(type,field))) -#define CONTAINING_RECORD(address,type,field) ((type *)((PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field))) - -#define VER_SERVER_NT 0x80000000 -#define VER_WORKSTATION_NT 0x40000000 -#define VER_SUITE_SMALLBUSINESS 0x00000001 -#define VER_SUITE_ENTERPRISE 0x00000002 -#define VER_SUITE_BACKOFFICE 0x00000004 -#define VER_SUITE_COMMUNICATIONS 0x00000008 -#define VER_SUITE_TERMINAL 0x00000010 -#define VER_SUITE_SMALLBUSINESS_RESTRICTED 0x00000020 -#define VER_SUITE_EMBEDDEDNT 0x00000040 -#define VER_SUITE_DATACENTER 0x00000080 -#define VER_SUITE_SINGLEUSERTS 0x00000100 -#define VER_SUITE_PERSONAL 0x00000200 -#define VER_SUITE_BLADE 0x00000400 -#define VER_SUITE_EMBEDDED_RESTRICTED 0x00000800 -#define VER_SUITE_SECURITY_APPLIANCE 0x00001000 -#define VER_SUITE_STORAGE_SERVER 0x00002000 -#define VER_SUITE_COMPUTE_SERVER 0x00004000 - -#define PRODUCT_UNDEFINED 0x0 - -#define PRODUCT_ULTIMATE 0x1 -#define PRODUCT_HOME_BASIC 0x2 -#define PRODUCT_HOME_PREMIUM 0x3 -#define PRODUCT_ENTERPRISE 0x4 -#define PRODUCT_HOME_BASIC_N 0x5 -#define PRODUCT_BUSINESS 0x6 -#define PRODUCT_STANDARD_SERVER 0x7 -#define PRODUCT_DATACENTER_SERVER 0x8 -#define PRODUCT_SMALLBUSINESS_SERVER 0x9 -#define PRODUCT_ENTERPRISE_SERVER 0xa -#define PRODUCT_STARTER 0xb -#define PRODUCT_DATACENTER_SERVER_CORE 0xc -#define PRODUCT_STANDARD_SERVER_CORE 0xd -#define PRODUCT_ENTERPRISE_SERVER_CORE 0xe -#define PRODUCT_ENTERPRISE_SERVER_IA64 0xf -#define PRODUCT_BUSINESS_N 0x10 -#define PRODUCT_WEB_SERVER 0x11 -#define PRODUCT_CLUSTER_SERVER 0x12 -#define PRODUCT_HOME_SERVER 0x13 -#define PRODUCT_STORAGE_EXPRESS_SERVER 0x14 -#define PRODUCT_STORAGE_STANDARD_SERVER 0x15 -#define PRODUCT_STORAGE_WORKGROUP_SERVER 0x16 -#define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x17 -#define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x18 -#define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x19 - -#define PRODUCT_UNLICENSED 0xabcdabcd - -#define LANG_NEUTRAL 0x00 -#define LANG_INVARIANT 0x7f - -#define LANG_AFRIKAANS 0x36 -#define LANG_ALBANIAN 0x1c -#define LANG_ALSATIAN 0x84 -#define LANG_AMHARIC 0x5e -#define LANG_ARABIC 0x01 -#define LANG_ARMENIAN 0x2b -#define LANG_ASSAMESE 0x4d -#define LANG_AZERI 0x2c -#define LANG_BASHKIR 0x6d -#define LANG_BASQUE 0x2d -#define LANG_BELARUSIAN 0x23 -#define LANG_BENGALI 0x45 -#define LANG_BRETON 0x7e -#define LANG_BOSNIAN 0x1a -#define LANG_BOSNIAN_NEUTRAL 0x781a -#define LANG_BULGARIAN 0x02 -#define LANG_CATALAN 0x03 -#define LANG_CHINESE 0x04 -#define LANG_CHINESE_SIMPLIFIED 0x04 -#define LANG_CHINESE_TRADITIONAL 0x7c04 -#define LANG_CORSICAN 0x83 -#define LANG_CROATIAN 0x1a -#define LANG_CZECH 0x05 -#define LANG_DANISH 0x06 -#define LANG_DARI 0x8c -#define LANG_DIVEHI 0x65 -#define LANG_DUTCH 0x13 -#define LANG_ENGLISH 0x09 -#define LANG_ESTONIAN 0x25 -#define LANG_FAEROESE 0x38 -#define LANG_FARSI 0x29 -#define LANG_FILIPINO 0x64 -#define LANG_FINNISH 0x0b -#define LANG_FRENCH 0x0c -#define LANG_FRISIAN 0x62 -#define LANG_GALICIAN 0x56 -#define LANG_GEORGIAN 0x37 -#define LANG_GERMAN 0x07 -#define LANG_GREEK 0x08 -#define LANG_GREENLANDIC 0x6f -#define LANG_GUJARATI 0x47 -#define LANG_HAUSA 0x68 -#define LANG_HEBREW 0x0d -#define LANG_HINDI 0x39 -#define LANG_HUNGARIAN 0x0e -#define LANG_ICELANDIC 0x0f -#define LANG_IGBO 0x70 -#define LANG_INDONESIAN 0x21 -#define LANG_INUKTITUT 0x5d -#define LANG_IRISH 0x3c -#define LANG_ITALIAN 0x10 -#define LANG_JAPANESE 0x11 -#define LANG_KANNADA 0x4b -#define LANG_KASHMIRI 0x60 -#define LANG_KAZAK 0x3f -#define LANG_KHMER 0x53 -#define LANG_KICHE 0x86 -#define LANG_KINYARWANDA 0x87 -#define LANG_KONKANI 0x57 -#define LANG_KOREAN 0x12 -#define LANG_KYRGYZ 0x40 -#define LANG_LAO 0x54 -#define LANG_LATVIAN 0x26 -#define LANG_LITHUANIAN 0x27 -#define LANG_LOWER_SORBIAN 0x2e -#define LANG_LUXEMBOURGISH 0x6e -#define LANG_MACEDONIAN 0x2f -#define LANG_MALAY 0x3e -#define LANG_MALAYALAM 0x4c -#define LANG_MALTESE 0x3a -#define LANG_MANIPURI 0x58 -#define LANG_MAORI 0x81 -#define LANG_MAPUDUNGUN 0x7a -#define LANG_MARATHI 0x4e -#define LANG_MOHAWK 0x7c -#define LANG_MONGOLIAN 0x50 -#define LANG_NEPALI 0x61 -#define LANG_NORWEGIAN 0x14 -#define LANG_OCCITAN 0x82 -#define LANG_ORIYA 0x48 -#define LANG_PASHTO 0x63 -#define LANG_PERSIAN 0x29 -#define LANG_POLISH 0x15 -#define LANG_PORTUGUESE 0x16 -#define LANG_PUNJABI 0x46 -#define LANG_QUECHUA 0x6b -#define LANG_ROMANIAN 0x18 -#define LANG_RUSSIAN 0x19 -#define LANG_SAMI 0x3b -#define LANG_ROMANSH 0x17 -#define LANG_SANSKRIT 0x4f -#define LANG_SERBIAN 0x1a -#define LANG_SERBIAN_NEUTRAL 0x7c1a -#define LANG_SINDHI 0x59 -#define LANG_SINHALESE 0x5b -#define LANG_SLOVAK 0x1b -#define LANG_SLOVENIAN 0x24 -#define LANG_SOTHO 0x6c -#define LANG_SPANISH 0x0a -#define LANG_SWAHILI 0x41 -#define LANG_SWEDISH 0x1d -#define LANG_SYRIAC 0x5a -#define LANG_TAJIK 0x28 -#define LANG_TAMAZIGHT 0x5f -#define LANG_TAMIL 0x49 -#define LANG_TATAR 0x44 -#define LANG_TELUGU 0x4a -#define LANG_THAI 0x1e -#define LANG_TIBETAN 0x51 -#define LANG_TIGRIGNA 0x73 -#define LANG_TSWANA 0x32 -#define LANG_TURKISH 0x1f -#define LANG_TURKMEN 0x42 -#define LANG_UIGHUR 0x80 -#define LANG_UKRAINIAN 0x22 -#define LANG_UPPER_SORBIAN 0x2e -#define LANG_URDU 0x20 -#define LANG_UZBEK 0x43 -#define LANG_VIETNAMESE 0x2a -#define LANG_WELSH 0x52 -#define LANG_WOLOF 0x88 -#define LANG_XHOSA 0x34 -#define LANG_YAKUT 0x85 -#define LANG_YI 0x78 -#define LANG_YORUBA 0x6a -#define LANG_ZULU 0x35 - -#define SUBLANG_NEUTRAL 0x0 -#define SUBLANG_DEFAULT 0x1 -#define SUBLANG_SYS_DEFAULT 0x2 -#define SUBLANG_CUSTOM_DEFAULT 0x3 -#define SUBLANG_CUSTOM_UNSPECIFIED 0x4 -#define SUBLANG_UI_CUSTOM_DEFAULT 0x5 - -#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 -#define SUBLANG_ARABIC_IRAQ 0x02 -#define SUBLANG_ARABIC_EGYPT 0x03 -#define SUBLANG_ARABIC_LIBYA 0x04 -#define SUBLANG_ARABIC_ALGERIA 0x05 -#define SUBLANG_ARABIC_MOROCCO 0x06 -#define SUBLANG_ARABIC_TUNISIA 0x07 -#define SUBLANG_ARABIC_OMAN 0x08 -#define SUBLANG_ARABIC_YEMEN 0x09 -#define SUBLANG_ARABIC_SYRIA 0x0a -#define SUBLANG_ARABIC_JORDAN 0x0b -#define SUBLANG_ARABIC_LEBANON 0x0c -#define SUBLANG_ARABIC_KUWAIT 0x0d -#define SUBLANG_ARABIC_UAE 0x0e -#define SUBLANG_ARABIC_BAHRAIN 0x0f -#define SUBLANG_ARABIC_QATAR 0x10 -#define SUBLANG_AZERI_LATIN 0x01 -#define SUBLANG_AZERI_CYRILLIC 0x02 -#define SUBLANG_CHINESE_TRADITIONAL 0x01 -#define SUBLANG_CHINESE_SIMPLIFIED 0x02 -#define SUBLANG_CHINESE_HONGKONG 0x03 -#define SUBLANG_CHINESE_SINGAPORE 0x04 -#define SUBLANG_CHINESE_MACAU 0x05 -#define SUBLANG_DUTCH 0x01 -#define SUBLANG_DUTCH_BELGIAN 0x02 -#define SUBLANG_ENGLISH_US 0x01 -#define SUBLANG_ENGLISH_UK 0x02 -#define SUBLANG_ENGLISH_AUS 0x03 -#define SUBLANG_ENGLISH_CAN 0x04 -#define SUBLANG_ENGLISH_NZ 0x05 -#define SUBLANG_ENGLISH_EIRE 0x06 -#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 -#define SUBLANG_ENGLISH_JAMAICA 0x08 -#define SUBLANG_ENGLISH_CARIBBEAN 0x09 -#define SUBLANG_ENGLISH_BELIZE 0x0a -#define SUBLANG_ENGLISH_TRINIDAD 0x0b -#define SUBLANG_ENGLISH_ZIMBABWE 0x0c -#define SUBLANG_ENGLISH_PHILIPPINES 0x0d -#define SUBLANG_FRENCH 0x01 -#define SUBLANG_FRENCH_BELGIAN 0x02 -#define SUBLANG_FRENCH_CANADIAN 0x03 -#define SUBLANG_FRENCH_SWISS 0x04 -#define SUBLANG_FRENCH_LUXEMBOURG 0x05 -#define SUBLANG_FRENCH_MONACO 0x06 -#define SUBLANG_GERMAN 0x01 -#define SUBLANG_GERMAN_SWISS 0x02 -#define SUBLANG_GERMAN_AUSTRIAN 0x03 -#define SUBLANG_GERMAN_LUXEMBOURG 0x04 -#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 -#define SUBLANG_ITALIAN 0x01 -#define SUBLANG_ITALIAN_SWISS 0x02 -#define SUBLANG_KASHMIRI_SASIA 0x02 -#define SUBLANG_KASHMIRI_INDIA 0x02 -#define SUBLANG_KOREAN 0x01 -#define SUBLANG_LITHUANIAN 0x01 -#define SUBLANG_MALAY_MALAYSIA 0x01 -#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 -#define SUBLANG_NEPALI_INDIA 0x02 -#define SUBLANG_NORWEGIAN_BOKMAL 0x01 -#define SUBLANG_NORWEGIAN_NYNORSK 0x02 -#define SUBLANG_PORTUGUESE 0x02 -#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01 -#define SUBLANG_SERBIAN_LATIN 0x02 -#define SUBLANG_SERBIAN_CYRILLIC 0x03 -#define SUBLANG_SPANISH 0x01 -#define SUBLANG_SPANISH_MEXICAN 0x02 -#define SUBLANG_SPANISH_MODERN 0x03 -#define SUBLANG_SPANISH_GUATEMALA 0x04 -#define SUBLANG_SPANISH_COSTA_RICA 0x05 -#define SUBLANG_SPANISH_PANAMA 0x06 -#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 -#define SUBLANG_SPANISH_VENEZUELA 0x08 -#define SUBLANG_SPANISH_COLOMBIA 0x09 -#define SUBLANG_SPANISH_PERU 0x0a -#define SUBLANG_SPANISH_ARGENTINA 0x0b -#define SUBLANG_SPANISH_ECUADOR 0x0c -#define SUBLANG_SPANISH_CHILE 0x0d -#define SUBLANG_SPANISH_URUGUAY 0x0e -#define SUBLANG_SPANISH_PARAGUAY 0x0f -#define SUBLANG_SPANISH_BOLIVIA 0x10 -#define SUBLANG_SPANISH_EL_SALVADOR 0x11 -#define SUBLANG_SPANISH_HONDURAS 0x12 -#define SUBLANG_SPANISH_NICARAGUA 0x13 -#define SUBLANG_SPANISH_PUERTO_RICO 0x14 -#define SUBLANG_SWEDISH 0x01 -#define SUBLANG_SWEDISH_FINLAND 0x02 -#define SUBLANG_URDU_PAKISTAN 0x01 -#define SUBLANG_URDU_INDIA 0x02 -#define SUBLANG_UZBEK_LATIN 0x01 -#define SUBLANG_UZBEK_CYRILLIC 0x02 - -#define SORT_DEFAULT 0x0 -#define SORT_INVARIANT_MATH 0x1 - -#define SORT_JAPANESE_XJIS 0x0 -#define SORT_JAPANESE_UNICODE 0x1 -#define SORT_JAPANESE_RADICALSTROKE 0x4 - -#define SORT_CHINESE_BIG5 0x0 -#define SORT_CHINESE_PRCP 0x0 -#define SORT_CHINESE_UNICODE 0x1 -#define SORT_CHINESE_PRC 0x2 -#define SORT_CHINESE_BOPOMOFO 0x3 - -#define SORT_KOREAN_KSC 0x0 -#define SORT_KOREAN_UNICODE 0x1 - -#define SORT_GERMAN_PHONE_BOOK 0x1 - -#define SORT_HUNGARIAN_DEFAULT 0x0 -#define SORT_HUNGARIAN_TECHNICAL 0x1 - -#define SORT_GEORGIAN_TRADITIONAL 0x0 -#define SORT_GEORGIAN_MODERN 0x1 - -#define MAKELANGID(p,s) ((((WORD)(s)) << 10) | (WORD)(p)) -#define PRIMARYLANGID(lgid) ((WORD)(lgid) & 0x3ff) -#define SUBLANGID(lgid) ((WORD)(lgid) >> 10) - -#define NLS_VALID_LOCALE_MASK 0x000fffff - -#define MAKELCID(lgid,srtid) ((DWORD)((((DWORD)((WORD)(srtid))) << 16) | ((DWORD)((WORD)(lgid))))) -#define MAKESORTLCID(lgid,srtid,ver) ((DWORD)((MAKELCID(lgid,srtid)) | (((DWORD)((WORD)(ver))) << 20))) -#define LANGIDFROMLCID(lcid) ((WORD)(lcid)) -#define SORTIDFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 16) & 0xf)) -#define SORTVERSIONFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 20) & 0xf)) - -#define LOCALE_NAME_MAX_LENGTH 85 -#define LANG_SYSTEM_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT)) -#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)) - -#define LOCALE_SYSTEM_DEFAULT (MAKELCID(LANG_SYSTEM_DEFAULT,SORT_DEFAULT)) -#define LOCALE_USER_DEFAULT (MAKELCID(LANG_USER_DEFAULT,SORT_DEFAULT)) - -#define LOCALE_NEUTRAL (MAKELCID(MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),SORT_DEFAULT)) - -#define LOCALE_CUSTOM_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), SORT_DEFAULT)) -#define LOCALE_CUSTOM_UNSPECIFIED (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED), SORT_DEFAULT)) -#define LOCALE_CUSTOM_UI_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT), SORT_DEFAULT)) - -#define LOCALE_INVARIANT (MAKELCID(MAKELANGID(LANG_INVARIANT,SUBLANG_NEUTRAL),SORT_DEFAULT)) - -#define UNREFERENCED_PARAMETER(P) (P) -#define DBG_UNREFERENCED_PARAMETER(P) (P) -#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (V) - -#define DEFAULT_UNREACHABLE - -#ifndef WIN32_NO_STATUS -#define STATUS_WAIT_0 ((DWORD)0x00000000L) -#define STATUS_ABANDONED_WAIT_0 ((DWORD)0x00000080L) -#define STATUS_USER_APC ((DWORD)0x000000C0L) -#define STATUS_TIMEOUT ((DWORD)0x00000102L) -#define STATUS_PENDING ((DWORD)0x00000103L) -#define DBG_EXCEPTION_HANDLED ((DWORD)0x00010001L) -#define DBG_CONTINUE ((DWORD)0x00010002L) -#define STATUS_SEGMENT_NOTIFICATION ((DWORD)0x40000005L) -#define DBG_TERMINATE_THREAD ((DWORD)0x40010003L) -#define DBG_TERMINATE_PROCESS ((DWORD)0x40010004L) -#define DBG_CONTROL_C ((DWORD)0x40010005L) -#define DBG_CONTROL_BREAK ((DWORD)0x40010008L) -#define DBG_COMMAND_EXCEPTION ((DWORD)0x40010009L) -#define STATUS_GUARD_PAGE_VIOLATION ((DWORD)0x80000001L) -#define STATUS_DATATYPE_MISALIGNMENT ((DWORD)0x80000002L) -#define STATUS_BREAKPOINT ((DWORD)0x80000003L) -#define STATUS_SINGLE_STEP ((DWORD)0x80000004L) -#define DBG_EXCEPTION_NOT_HANDLED ((DWORD)0x80010001L) -#define STATUS_ACCESS_VIOLATION ((DWORD)0xC0000005L) -#define STATUS_IN_PAGE_ERROR ((DWORD)0xC0000006L) -#define STATUS_INVALID_HANDLE ((DWORD)0xC0000008L) -#define STATUS_NO_MEMORY ((DWORD)0xC0000017L) -#define STATUS_ILLEGAL_INSTRUCTION ((DWORD)0xC000001DL) -#define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD)0xC0000025L) -#define STATUS_INVALID_DISPOSITION ((DWORD)0xC0000026L) -#define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD)0xC000008CL) -#define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD)0xC000008DL) -#define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD)0xC000008EL) -#define STATUS_FLOAT_INEXACT_RESULT ((DWORD)0xC000008FL) -#define STATUS_FLOAT_INVALID_OPERATION ((DWORD)0xC0000090L) -#define STATUS_FLOAT_OVERFLOW ((DWORD)0xC0000091L) -#define STATUS_FLOAT_STACK_CHECK ((DWORD)0xC0000092L) -#define STATUS_FLOAT_UNDERFLOW ((DWORD)0xC0000093L) -#define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD)0xC0000094L) -#define STATUS_INTEGER_OVERFLOW ((DWORD)0xC0000095L) -#define STATUS_PRIVILEGED_INSTRUCTION ((DWORD)0xC0000096L) -#define STATUS_STACK_OVERFLOW ((DWORD)0xC00000FDL) -#define STATUS_CONTROL_C_EXIT ((DWORD)0xC000013AL) -#define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD)0xC00002B4L) -#define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD)0xC00002B5L) -#define STATUS_REG_NAT_CONSUMPTION ((DWORD)0xC00002C9L) -#define STATUS_SXS_EARLY_DEACTIVATION ((DWORD)0xC015000FL) -#define STATUS_SXS_INVALID_DEACTIVATION ((DWORD)0xC0150010L) -#endif - -#define MAXIMUM_WAIT_OBJECTS 64 -#define MAXIMUM_SUSPEND_COUNT MAXCHAR - - typedef ULONG_PTR KSPIN_LOCK; - typedef KSPIN_LOCK *PKSPIN_LOCK; - -#ifdef _AMD64_ - -#if defined(__x86_64) && !defined(RC_INVOKED) - -#ifdef __cplusplus - extern "C" { -#endif - -#define BitTest _bittest -#define BitTestAndComplement _bittestandcomplement -#define BitTestAndSet _bittestandset -#define BitTestAndReset _bittestandreset -#define InterlockedBitTestAndSet _interlockedbittestandset -#define InterlockedBitTestAndReset _interlockedbittestandreset -#define BitTest64 _bittest64 -#define BitTestAndComplement64 _bittestandcomplement64 -#define BitTestAndSet64 _bittestandset64 -#define BitTestAndReset64 _bittestandreset64 -#define InterlockedBitTestAndSet64 _interlockedbittestandset64 -#define InterlockedBitTestAndReset64 _interlockedbittestandreset64 - - __CRT_INLINE BOOLEAN _bittest(LONG const *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandcomplement(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandreset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandreset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittest64(LONG64 const *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandcomplement64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btcq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btsq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandreset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btrq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("lock ; btsq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandreset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("lock ; btrq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } -#define BitScanForward _BitScanForward -#define BitScanReverse _BitScanReverse -#define BitScanForward64 _BitScanForward64 -#define BitScanReverse64 _BitScanReverse64 - - __CRT_INLINE BOOLEAN _BitScanForward(DWORD *Index,DWORD Mask) { - __asm__ __volatile__("bsfl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); - return Mask!=0; - } - __CRT_INLINE BOOLEAN _BitScanReverse(DWORD *Index,DWORD Mask) { - __asm__ __volatile__("bsrl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); - return Mask!=0; - } - __CRT_INLINE BOOLEAN _BitScanForward64(DWORD *Index,DWORD64 Mask) { - __asm__ __volatile__("bsfq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); - return Mask!=0; - } - __CRT_INLINE BOOLEAN _BitScanReverse64(DWORD *Index,DWORD64 Mask) { - __asm__ __volatile__("bsrq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); - return Mask!=0; - } - -#define InterlockedIncrement16 _InterlockedIncrement16 -#define InterlockedDecrement16 _InterlockedDecrement16 -#define InterlockedCompareExchange16 _InterlockedCompareExchange16 - -#define InterlockedAnd _InterlockedAnd -#define InterlockedOr _InterlockedOr -#define InterlockedXor _InterlockedXor -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedDecrement _InterlockedDecrement -#define InterlockedDecrementAcquire InterlockedDecrement -#define InterlockedDecrementRelease InterlockedDecrement -#define InterlockedAdd _InterlockedAdd -#define InterlockedExchange _InterlockedExchange -#define InterlockedExchangeAdd _InterlockedExchangeAdd -#define InterlockedCompareExchange _InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire InterlockedCompareExchange -#define InterlockedCompareExchangeRelease InterlockedCompareExchange - -#define InterlockedAnd64 _InterlockedAnd64 -#define InterlockedAndAffinity InterlockedAnd64 -#define InterlockedOr64 _InterlockedOr64 -#define InterlockedOrAffinity InterlockedOr64 -#define InterlockedXor64 _InterlockedXor64 -#define InterlockedIncrement64 _InterlockedIncrement64 -#define InterlockedDecrement64 _InterlockedDecrement64 -#define InterlockedAdd64 _InterlockedAdd64 -#define InterlockedExchange64 _InterlockedExchange64 -#define InterlockedExchangeAcquire64 InterlockedExchange64 -#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 -#define InterlockedCompareExchange64 _InterlockedCompareExchange64 -#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 -#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 - -#define InterlockedExchangePointer _InterlockedExchangePointer -#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer - -#define InterlockedExchangeAddSizeT(a,b) InterlockedExchangeAdd64((LONG64 *)a,b) -#define InterlockedIncrementSizeT(a) InterlockedIncrement64((LONG64 *)a) -#define InterlockedDecrementSizeT(a) InterlockedDecrement64((LONG64 *)a) - - __CRT_INLINE SHORT InterlockedIncrement16(SHORT volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; addw $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE SHORT InterlockedDecrement16(SHORT volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; subw $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE SHORT InterlockedCompareExchange16(SHORT volatile *Destination,SHORT ExChange,SHORT Comperand) { - SHORT prev; - __asm__ __volatile__("lock ; cmpxchgw %w1,%2" - :"=a"(prev) - :"q"(ExChange), "m"(*Destination), "0"(Comperand) - : "memory"); - return prev; - } - __CRT_INLINE LONG InterlockedAnd(LONG volatile *Destination,LONG Value) { - __asm__ __volatile__("lock ; andl %0,%1" - : :"r"(Value),"m"(*Destination) - : "memory"); - return *Destination; - } - __CRT_INLINE LONG InterlockedOr(LONG volatile *Destination,LONG Value) { - __asm__ __volatile__("lock ; orl %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG InterlockedXor(LONG volatile *Destination,LONG Value) { - __asm__ __volatile__("lock ; xorl %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - // $$$$ - __CRT_INLINE LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value) { - __asm__ __volatile__("lock ; andq %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value) { - __asm__ __volatile__("lock ; orq %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value) { - __asm__ __volatile__("lock ; xorq %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG InterlockedIncrement(LONG volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; addl $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG InterlockedDecrement(LONG volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; subl $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG InterlockedExchange(LONG volatile *Target,LONG Value) { - __asm__ __volatile("lock ; xchgl %0,%1" - : "=r"(Value) - : "m"(*Target),"0"(Value) - : "memory"); - return Value; - } - LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - -#ifndef _X86AMD64_ - __CRT_INLINE LONG InterlockedAdd(LONG volatile *Addend,LONG Value) { return InterlockedExchangeAdd(Addend,Value) + Value; } -#endif - __CRT_INLINE LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand) { - LONG prev; - __asm__ __volatile__("lock ; cmpxchgl %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); - return prev; - } - __CRT_INLINE LONG64 InterlockedIncrement64(LONG64 volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; addq $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG64 InterlockedDecrement64(LONG64 volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; subq $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value) { - __asm__ __volatile("lock ; xchgq %0,%1" - : "=r"(Value) - : "m"(*Target),"0"(Value) - : "memory"); - return Value; - } - LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); - -#ifndef _X86AMD64_ - __CRT_INLINE LONG64 InterlockedAdd64(LONG64 volatile *Addend,LONG64 Value) { return InterlockedExchangeAdd64(Addend,Value) + Value; } -#endif - - __CRT_INLINE LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand) { - LONG64 prev; - __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); - return prev; - } - __CRT_INLINE PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { - PVOID prev; - __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); - return prev; - } - __CRT_INLINE PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value) { - __asm__ __volatile("lock ; xchgq %0,%1" - : "=r"(Value) - : "m"(*Target),"0"(Value) - : "memory"); - return Value; - } - -#define CacheLineFlush(Address) _mm_clflush(Address) - - VOID _ReadWriteBarrier(VOID); - -#define FastFence __faststorefence -#define LoadFence _mm_lfence -#define MemoryFence _mm_mfence -#define StoreFence _mm_sfence - - VOID __faststorefence(VOID); - VOID _m_prefetchw(volatile CONST VOID *Source); - -//!__TINYC__: #include - -#define YieldProcessor _mm_pause -#define MemoryBarrier __faststorefence -#define PreFetchCacheLine(l,a) _mm_prefetch((CHAR CONST *) a,l) -#define PrefetchForWrite(p) _m_prefetchw(p) -#define ReadForWriteAccess(p) (_m_prefetchw(p),*(p)) - -#define PF_TEMPORAL_LEVEL_1 _MM_HINT_T0 -#define PF_TEMPORAL_LEVEL_2 _MM_HINT_T1 -#define PF_TEMPORAL_LEVEL_3 _MM_HINT_T2 -#define PF_NON_TEMPORAL_LEVEL_ALL _MM_HINT_NTA - -#define ReadMxCsr _mm_getcsr -#define WriteMxCsr _mm_setcsr - - VOID __int2c(VOID); - -#define DbgRaiseAssertionFailure() __int2c() -#define GetCallersEflags() __getcallerseflags() - - unsigned __int32 __getcallerseflags(VOID); - -#define GetSegmentLimit __segmentlimit - - DWORD __segmentlimit(DWORD Selector); - -#define ReadTimeStampCounter() __rdtsc() - - DWORD64 __rdtsc(VOID); - VOID __movsb(PBYTE Destination,BYTE const *Source,SIZE_T Count); - VOID __movsw(PWORD Destination,WORD const *Source,SIZE_T Count); - VOID __movsd(PDWORD Destination,DWORD const *Source,SIZE_T Count); - VOID __movsq(PDWORD64 Destination,DWORD64 const *Source,SIZE_T Count); - VOID __stosb(PBYTE Destination,BYTE Value,SIZE_T Count); - VOID __stosw(PWORD Destination,WORD Value,SIZE_T Count); - VOID __stosd(PDWORD Destination,DWORD Value,SIZE_T Count); - VOID __stosq(PDWORD64 Destination,DWORD64 Value,SIZE_T Count); - -#define MultiplyHigh __mulh -#define UnsignedMultiplyHigh __umulh - - LONGLONG MultiplyHigh(LONGLONG Multiplier,LONGLONG Multiplicand); - ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); - -#define ShiftLeft128 __shiftleft128 -#define ShiftRight128 __shiftright128 - - DWORD64 ShiftLeft128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); - DWORD64 ShiftRight128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); - -#define Multiply128 _mul128 - - LONG64 Multiply128(LONG64 Multiplier,LONG64 Multiplicand,LONG64 *HighProduct); - -#define UnsignedMultiply128 _umul128 - - DWORD64 UnsignedMultiply128(DWORD64 Multiplier,DWORD64 Multiplicand,DWORD64 *HighProduct); - - __CRT_INLINE LONG64 MultiplyExtract128(LONG64 Multiplier,LONG64 Multiplicand,BYTE Shift) { - LONG64 extractedProduct; - LONG64 highProduct; - LONG64 lowProduct; - lowProduct = Multiply128(Multiplier,Multiplicand,&highProduct); - extractedProduct = (LONG64)ShiftRight128((LONG64)lowProduct,(LONG64)highProduct,Shift); - return extractedProduct; - } - - __CRT_INLINE DWORD64 UnsignedMultiplyExtract128(DWORD64 Multiplier,DWORD64 Multiplicand,BYTE Shift) { - DWORD64 extractedProduct; - DWORD64 highProduct; - DWORD64 lowProduct; - lowProduct = UnsignedMultiply128(Multiplier,Multiplicand,&highProduct); - extractedProduct = ShiftRight128(lowProduct,highProduct,Shift); - return extractedProduct; - } - - __CRT_INLINE BYTE __readgsbyte(DWORD Offset) { - BYTE ret; - __asm__ volatile ("movb %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return ret; - } - __CRT_INLINE WORD __readgsword(DWORD Offset) { - WORD ret; - __asm__ volatile ("movw %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return ret; - } - __CRT_INLINE DWORD __readgsdword(DWORD Offset) { - DWORD ret; - __asm__ volatile ("movl %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return ret; - } - __CRT_INLINE DWORD64 __readgsqword(DWORD Offset) { - void *ret; - __asm__ volatile ("movq %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return (DWORD64) ret; - } - __CRT_INLINE VOID __writegsbyte(DWORD Offset,BYTE Data) { - __asm__ volatile ("movb %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - __CRT_INLINE VOID __writegsword(DWORD Offset,WORD Data) { - __asm__ volatile ("movw %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - __CRT_INLINE VOID __writegsdword(DWORD Offset,DWORD Data) { - __asm__ volatile ("movl %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - __CRT_INLINE VOID __writegsqword(DWORD Offset,DWORD64 Data) { - __asm__ volatile ("movq %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - -#ifdef __cplusplus - } -#endif -#endif - -#define EXCEPTION_READ_FAULT 0 -#define EXCEPTION_WRITE_FAULT 1 -#define EXCEPTION_EXECUTE_FAULT 8 - -#if !defined(RC_INVOKED) - -#define CONTEXT_AMD64 0x100000 - -#define CONTEXT_CONTROL (CONTEXT_AMD64 | 0x1L) -#define CONTEXT_INTEGER (CONTEXT_AMD64 | 0x2L) -#define CONTEXT_SEGMENTS (CONTEXT_AMD64 | 0x4L) -#define CONTEXT_FLOATING_POINT (CONTEXT_AMD64 | 0x8L) -#define CONTEXT_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L) - -#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) -#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS) - -#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 -#define CONTEXT_SERVICE_ACTIVE 0x10000000 -#define CONTEXT_EXCEPTION_REQUEST 0x40000000 -#define CONTEXT_EXCEPTION_REPORTING 0x80000000 -#endif - -#define INITIAL_MXCSR 0x1f80 -#define INITIAL_FPCSR 0x027f - - typedef struct DECLSPEC_ALIGN(16) _M128A { - ULONGLONG Low; - LONGLONG High; - } M128A,*PM128A; - - typedef struct _XMM_SAVE_AREA32 { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A FloatRegisters[8]; - M128A XmmRegisters[16]; - BYTE Reserved4[96]; - } XMM_SAVE_AREA32,*PXMM_SAVE_AREA32; - -#define LEGACY_SAVE_AREA_LENGTH sizeof(XMM_SAVE_AREA32) - - typedef struct DECLSPEC_ALIGN(16) _CONTEXT { - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; - union { - XMM_SAVE_AREA32 FltSave; - XMM_SAVE_AREA32 FloatSave; - struct { - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - }; - }; - M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; - } CONTEXT,*PCONTEXT; - -#define RUNTIME_FUNCTION_INDIRECT 0x1 - - typedef struct _RUNTIME_FUNCTION { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindData; - } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; - - typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); - typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); - -#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" - - NTSYSAPI VOID __cdecl RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); - NTSYSAPI BOOLEAN __cdecl RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,DWORD64 BaseAddress); - NTSYSAPI BOOLEAN __cdecl RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); - NTSYSAPI BOOLEAN __cdecl RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); -#endif - -#ifdef I_X86_ -#if(defined(_X86_) && !defined(__x86_64)) && !defined(RC_INVOKED) -#ifdef __cplusplus - extern "C" { -#endif - - __CRT_INLINE BOOLEAN InterlockedBitTestAndSet(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - - __CRT_INLINE BOOLEAN InterlockedBitTestAndReset(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - - __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - -#ifdef _PREFIX_ - BYTE __readfsbyte(DWORD Offset); - WORD __readfsword(DWORD Offset); - DWORD __readfsdword(DWORD Offset); - VOID __writefsbyte(DWORD Offset,BYTE Data); - VOID __writefsword(DWORD Offset,WORD Data); - VOID __writefsdword(DWORD Offset,DWORD Data); -#endif - -#ifdef __cplusplus - } -#endif -#endif - -#if(defined(_X86_) && !defined(__x86_64)) - __CRT_INLINE VOID MemoryBarrier(VOID) { - LONG Barrier; - __asm__ __volatile__("xchgl %%eax,%0 " - :"=r" (Barrier)); - } -#define YieldProcessor() __asm__ __volatile__("rep nop "); - -#define PreFetchCacheLine(l,a) -#define ReadForWriteAccess(p) (*(p)) - -#define PF_TEMPORAL_LEVEL_1 -#define PF_NON_TEMPORAL_LEVEL_ALL - - __CRT_INLINE VOID DbgRaiseAssertionFailure(void) { - __asm__ __volatile__("int $0x2c "); - } - PVOID GetCurrentFiber(void); - __CRT_INLINE PVOID GetCurrentFiber(void) - { - void *ret; - __asm__ volatile ("movl %%fs:0x10,%0" - : "=r" (ret)); - return ret; - } - PVOID GetFiberData(void); - __CRT_INLINE PVOID GetFiberData(void) - { - void *ret; - __asm__ volatile ("movl %%fs:0x10,%0\n" - "movl (%0),%0" - : "=r" (ret)); - return ret; - } -#endif - -#define EXCEPTION_READ_FAULT 0 -#define EXCEPTION_WRITE_FAULT 1 -#define EXCEPTION_EXECUTE_FAULT 8 - -#define SIZE_OF_80387_REGISTERS 80 - -#if !defined(RC_INVOKED) - -#define CONTEXT_i386 0x00010000 -#define CONTEXT_i486 0x00010000 - -#define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) -#define CONTEXT_INTEGER (CONTEXT_i386 | 0x00000002L) -#define CONTEXT_SEGMENTS (CONTEXT_i386 | 0x00000004L) -#define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 0x00000008L) -#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) -#define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386 | 0x00000020L) - -#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) - -#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS) -#endif - -#define MAXIMUM_SUPPORTED_EXTENSION 512 - - typedef struct _FLOATING_SAVE_AREA { - DWORD ControlWord; - DWORD StatusWord; - DWORD TagWord; - DWORD ErrorOffset; - DWORD ErrorSelector; - DWORD DataOffset; - DWORD DataSelector; - BYTE RegisterArea[SIZE_OF_80387_REGISTERS]; - DWORD Cr0NpxState; - } FLOATING_SAVE_AREA; - - typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA; - - typedef struct _CONTEXT { - DWORD ContextFlags; - DWORD Dr0; - DWORD Dr1; - DWORD Dr2; - DWORD Dr3; - DWORD Dr6; - DWORD Dr7; - FLOATING_SAVE_AREA FloatSave; - DWORD SegGs; - DWORD SegFs; - DWORD SegEs; - DWORD SegDs; - - DWORD Edi; - DWORD Esi; - DWORD Ebx; - DWORD Edx; - DWORD Ecx; - DWORD Eax; - DWORD Ebp; - DWORD Eip; - DWORD SegCs; - DWORD EFlags; - DWORD Esp; - DWORD SegSs; - BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; - } CONTEXT; - - typedef CONTEXT *PCONTEXT; -#endif - -#ifndef _LDT_ENTRY_DEFINED -#define _LDT_ENTRY_DEFINED - - typedef struct _LDT_ENTRY { - WORD LimitLow; - WORD BaseLow; - union { - struct { - BYTE BaseMid; - BYTE Flags1; - BYTE Flags2; - BYTE BaseHi; - } Bytes; - struct { - DWORD BaseMid : 8; - DWORD Type : 5; - DWORD Dpl : 2; - DWORD Pres : 1; - DWORD LimitHi : 4; - DWORD Sys : 1; - DWORD Reserved_0 : 1; - DWORD Default_Big : 1; - DWORD Granularity : 1; - DWORD BaseHi : 8; - } Bits; - } HighWord; - } LDT_ENTRY,*PLDT_ENTRY; -#endif - -#if defined(__ia64__) && !defined(RC_INVOKED) - -#ifdef __cplusplus - extern "C" { -#endif - - BOOLEAN BitScanForward64(DWORD *Index,DWORD64 Mask); - BOOLEAN BitScanReverse64(DWORD *Index,DWORD64 Mask); - -#ifdef __cplusplus - } -#endif -#endif - -#if !defined(GENUTIL) && !defined(_GENIA64_) && defined(_IA64_) - - void *_cdecl _rdteb(void); -#ifdef __ia64__ - -#define NtCurrentTeb() ((struct _TEB *)_rdteb()) -#define GetCurrentFiber() (((PNT_TIB)NtCurrentTeb())->FiberData) -#define GetFiberData() (*(PVOID *)(GetCurrentFiber())) - -#ifdef __cplusplus - extern "C" { -#endif - - void __break(int); - void __yield(void); - void __mf(void); - void __lfetch(int Level,VOID CONST *Address); - void __lfetchfault(int Level,VOID CONST *Address); - void __lfetch_excl(int Level,VOID CONST *Address); - void __lfetchfault_excl(int Level,VOID CONST *Address); - -#define MD_LFHINT_NONE 0x00 -#define MD_LFHINT_NT1 0x01 -#define MD_LFHINT_NT2 0x02 -#define MD_LFHINT_NTA 0x03 - -#ifdef __cplusplus - } -#endif - -#define YieldProcessor __yield -#define MemoryBarrier __mf -#define PreFetchCacheLine __lfetch -#define ReadForWriteAccess(p) (*(p)) -#define DbgRaiseAssertionFailure() __break(ASSERT_BREAKPOINT) - -#define PF_TEMPORAL_LEVEL_1 MD_LFHINT_NONE -#define PF_NON_TEMPORAL_LEVEL_ALL MD_LFHINT_NTA - -#define UnsignedMultiplyHigh __UMULH - - ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); -#else - struct _TEB *NtCurrentTeb(void); -#endif -#endif - -#ifdef _IA64_ - -#define EXCEPTION_READ_FAULT 0 -#define EXCEPTION_WRITE_FAULT 1 -#define EXCEPTION_EXECUTE_FAULT 2 - -#if !defined(RC_INVOKED) - -#define CONTEXT_IA64 0x00080000 - -#define CONTEXT_CONTROL (CONTEXT_IA64 | 0x00000001L) -#define CONTEXT_LOWER_FLOATING_POINT (CONTEXT_IA64 | 0x00000002L) -#define CONTEXT_HIGHER_FLOATING_POINT (CONTEXT_IA64 | 0x00000004L) -#define CONTEXT_INTEGER (CONTEXT_IA64 | 0x00000008L) -#define CONTEXT_DEBUG (CONTEXT_IA64 | 0x00000010L) -#define CONTEXT_IA32_CONTROL (CONTEXT_IA64 | 0x00000020L) - -#define CONTEXT_FLOATING_POINT (CONTEXT_LOWER_FLOATING_POINT | CONTEXT_HIGHER_FLOATING_POINT) -#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_IA32_CONTROL) -#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_DEBUG | CONTEXT_IA32_CONTROL) - -#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 -#define CONTEXT_SERVICE_ACTIVE 0x10000000 -#define CONTEXT_EXCEPTION_REQUEST 0x40000000 -#define CONTEXT_EXCEPTION_REPORTING 0x80000000 -#endif - - typedef struct _CONTEXT { - DWORD ContextFlags; - DWORD Fill1[3]; - ULONGLONG DbI0; - ULONGLONG DbI1; - ULONGLONG DbI2; - ULONGLONG DbI3; - ULONGLONG DbI4; - ULONGLONG DbI5; - ULONGLONG DbI6; - ULONGLONG DbI7; - ULONGLONG DbD0; - ULONGLONG DbD1; - ULONGLONG DbD2; - ULONGLONG DbD3; - ULONGLONG DbD4; - ULONGLONG DbD5; - ULONGLONG DbD6; - ULONGLONG DbD7; - FLOAT128 FltS0; - FLOAT128 FltS1; - FLOAT128 FltS2; - FLOAT128 FltS3; - FLOAT128 FltT0; - FLOAT128 FltT1; - FLOAT128 FltT2; - FLOAT128 FltT3; - FLOAT128 FltT4; - FLOAT128 FltT5; - FLOAT128 FltT6; - FLOAT128 FltT7; - FLOAT128 FltT8; - FLOAT128 FltT9; - FLOAT128 FltS4; - FLOAT128 FltS5; - FLOAT128 FltS6; - FLOAT128 FltS7; - FLOAT128 FltS8; - FLOAT128 FltS9; - FLOAT128 FltS10; - FLOAT128 FltS11; - FLOAT128 FltS12; - FLOAT128 FltS13; - FLOAT128 FltS14; - FLOAT128 FltS15; - FLOAT128 FltS16; - FLOAT128 FltS17; - FLOAT128 FltS18; - FLOAT128 FltS19; - FLOAT128 FltF32; - FLOAT128 FltF33; - FLOAT128 FltF34; - FLOAT128 FltF35; - FLOAT128 FltF36; - FLOAT128 FltF37; - FLOAT128 FltF38; - FLOAT128 FltF39; - FLOAT128 FltF40; - FLOAT128 FltF41; - FLOAT128 FltF42; - FLOAT128 FltF43; - FLOAT128 FltF44; - FLOAT128 FltF45; - FLOAT128 FltF46; - FLOAT128 FltF47; - FLOAT128 FltF48; - FLOAT128 FltF49; - FLOAT128 FltF50; - FLOAT128 FltF51; - FLOAT128 FltF52; - FLOAT128 FltF53; - FLOAT128 FltF54; - FLOAT128 FltF55; - FLOAT128 FltF56; - FLOAT128 FltF57; - FLOAT128 FltF58; - FLOAT128 FltF59; - FLOAT128 FltF60; - FLOAT128 FltF61; - FLOAT128 FltF62; - FLOAT128 FltF63; - FLOAT128 FltF64; - FLOAT128 FltF65; - FLOAT128 FltF66; - FLOAT128 FltF67; - FLOAT128 FltF68; - FLOAT128 FltF69; - FLOAT128 FltF70; - FLOAT128 FltF71; - FLOAT128 FltF72; - FLOAT128 FltF73; - FLOAT128 FltF74; - FLOAT128 FltF75; - FLOAT128 FltF76; - FLOAT128 FltF77; - FLOAT128 FltF78; - FLOAT128 FltF79; - FLOAT128 FltF80; - FLOAT128 FltF81; - FLOAT128 FltF82; - FLOAT128 FltF83; - FLOAT128 FltF84; - FLOAT128 FltF85; - FLOAT128 FltF86; - FLOAT128 FltF87; - FLOAT128 FltF88; - FLOAT128 FltF89; - FLOAT128 FltF90; - FLOAT128 FltF91; - FLOAT128 FltF92; - FLOAT128 FltF93; - FLOAT128 FltF94; - FLOAT128 FltF95; - FLOAT128 FltF96; - FLOAT128 FltF97; - FLOAT128 FltF98; - FLOAT128 FltF99; - FLOAT128 FltF100; - FLOAT128 FltF101; - FLOAT128 FltF102; - FLOAT128 FltF103; - FLOAT128 FltF104; - FLOAT128 FltF105; - FLOAT128 FltF106; - FLOAT128 FltF107; - FLOAT128 FltF108; - FLOAT128 FltF109; - FLOAT128 FltF110; - FLOAT128 FltF111; - FLOAT128 FltF112; - FLOAT128 FltF113; - FLOAT128 FltF114; - FLOAT128 FltF115; - FLOAT128 FltF116; - FLOAT128 FltF117; - FLOAT128 FltF118; - FLOAT128 FltF119; - FLOAT128 FltF120; - FLOAT128 FltF121; - FLOAT128 FltF122; - FLOAT128 FltF123; - FLOAT128 FltF124; - FLOAT128 FltF125; - FLOAT128 FltF126; - FLOAT128 FltF127; - ULONGLONG StFPSR; - ULONGLONG IntGp; - ULONGLONG IntT0; - ULONGLONG IntT1; - ULONGLONG IntS0; - ULONGLONG IntS1; - ULONGLONG IntS2; - ULONGLONG IntS3; - ULONGLONG IntV0; - ULONGLONG IntT2; - ULONGLONG IntT3; - ULONGLONG IntT4; - ULONGLONG IntSp; - ULONGLONG IntTeb; - ULONGLONG IntT5; - ULONGLONG IntT6; - ULONGLONG IntT7; - ULONGLONG IntT8; - ULONGLONG IntT9; - ULONGLONG IntT10; - ULONGLONG IntT11; - ULONGLONG IntT12; - ULONGLONG IntT13; - ULONGLONG IntT14; - ULONGLONG IntT15; - ULONGLONG IntT16; - ULONGLONG IntT17; - ULONGLONG IntT18; - ULONGLONG IntT19; - ULONGLONG IntT20; - ULONGLONG IntT21; - ULONGLONG IntT22; - ULONGLONG IntNats; - ULONGLONG Preds; - ULONGLONG BrRp; - ULONGLONG BrS0; - ULONGLONG BrS1; - ULONGLONG BrS2; - ULONGLONG BrS3; - ULONGLONG BrS4; - ULONGLONG BrT0; - ULONGLONG BrT1; - ULONGLONG ApUNAT; - ULONGLONG ApLC; - ULONGLONG ApEC; - ULONGLONG ApCCV; - ULONGLONG ApDCR; - ULONGLONG RsPFS; - ULONGLONG RsBSP; - ULONGLONG RsBSPSTORE; - ULONGLONG RsRSC; - ULONGLONG RsRNAT; - ULONGLONG StIPSR; - ULONGLONG StIIP; - ULONGLONG StIFS; - ULONGLONG StFCR; - ULONGLONG Eflag; - ULONGLONG SegCSD; - ULONGLONG SegSSD; - ULONGLONG Cflag; - ULONGLONG StFSR; - ULONGLONG StFIR; - ULONGLONG StFDR; - ULONGLONG UNUSEDPACK; - } CONTEXT,*PCONTEXT; - - typedef struct _PLABEL_DESCRIPTOR { - ULONGLONG EntryPoint; - ULONGLONG GlobalPointer; - } PLABEL_DESCRIPTOR,*PPLABEL_DESCRIPTOR; - - typedef struct _RUNTIME_FUNCTION { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindInfoAddress; - } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; - - typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); - typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); - -#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" - - BOOLEAN RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,ULONGLONG BaseAddress,ULONGLONG TargetGp); - BOOLEAN RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,DWORD64 TargetGp,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); - BOOLEAN RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); - VOID RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); - VOID __jump_unwind(ULONGLONG TargetMsFrame,ULONGLONG TargetBsFrame,ULONGLONG TargetPc); -#endif - -#define EXCEPTION_NONCONTINUABLE 0x1 -#define EXCEPTION_MAXIMUM_PARAMETERS 15 - - typedef struct _EXCEPTION_RECORD { - DWORD ExceptionCode; - DWORD ExceptionFlags; - struct _EXCEPTION_RECORD *ExceptionRecord; - PVOID ExceptionAddress; - DWORD NumberParameters; - ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - } EXCEPTION_RECORD; - - typedef EXCEPTION_RECORD *PEXCEPTION_RECORD; - - typedef struct _EXCEPTION_RECORD32 { - DWORD ExceptionCode; - DWORD ExceptionFlags; - DWORD ExceptionRecord; - DWORD ExceptionAddress; - DWORD NumberParameters; - DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - } EXCEPTION_RECORD32,*PEXCEPTION_RECORD32; - - typedef struct _EXCEPTION_RECORD64 { - DWORD ExceptionCode; - DWORD ExceptionFlags; - DWORD64 ExceptionRecord; - DWORD64 ExceptionAddress; - DWORD NumberParameters; - DWORD __unusedAlignment; - DWORD64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - } EXCEPTION_RECORD64,*PEXCEPTION_RECORD64; - - typedef struct _EXCEPTION_POINTERS { - PEXCEPTION_RECORD ExceptionRecord; - PCONTEXT ContextRecord; - } EXCEPTION_POINTERS,*PEXCEPTION_POINTERS; - -#ifdef __x86_64 - - typedef EXCEPTION_DISPOSITION NTAPI EXCEPTION_ROUTINE (struct _EXCEPTION_RECORD *ExceptionRecord, PVOID EstablisherFrame, struct _CONTEXT *ContextRecord, PVOID DispatcherContext); -#ifndef __PEXCEPTION_ROUTINE_DEFINED -#define __PEXCEPTION_ROUTINE_DEFINED - typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE; -#endif - - /* http://msdn.microsoft.com/en-us/library/ms680597(VS.85).aspx */ - -#define UNWIND_HISTORY_TABLE_SIZE 12 - - typedef struct _UNWIND_HISTORY_TABLE_ENTRY { - ULONG64 ImageBase; - PRUNTIME_FUNCTION FunctionEntry; - } UNWIND_HISTORY_TABLE_ENTRY, *PUNWIND_HISTORY_TABLE_ENTRY; - -#define UNWIND_HISTORY_TABLE_NONE 0 -#define UNWIND_HISTORY_TABLE_GLOBAL 1 -#define UNWIND_HISTORY_TABLE_LOCAL 2 - - typedef struct _UNWIND_HISTORY_TABLE { - ULONG Count; - UCHAR Search; - ULONG64 LowAddress; - ULONG64 HighAddress; - UNWIND_HISTORY_TABLE_ENTRY Entry[UNWIND_HISTORY_TABLE_SIZE]; - } UNWIND_HISTORY_TABLE, *PUNWIND_HISTORY_TABLE; - - /* http://msdn.microsoft.com/en-us/library/b6sf5kbd(VS.80).aspx */ - - struct _DISPATCHER_CONTEXT; - typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; - typedef struct _DISPATCHER_CONTEXT *PDISPATCHER_CONTEXT; - - struct _DISPATCHER_CONTEXT { - ULONG64 ControlPc; - ULONG64 ImageBase; - PRUNTIME_FUNCTION FunctionEntry; - ULONG64 EstablisherFrame; - ULONG64 TargetIp; - PCONTEXT ContextRecord; - PEXCEPTION_ROUTINE LanguageHandler; - PVOID HandlerData; - /* http://www.nynaeve.net/?p=99 */ - PUNWIND_HISTORY_TABLE HistoryTable; - ULONG ScopeIndex; - ULONG Fill0; - }; - - /* http://msdn.microsoft.com/en-us/library/ms680617(VS.85).aspx */ - - typedef struct _KNONVOLATILE_CONTEXT_POINTERS - { - PM128A FloatingContext[16]; - PULONG64 IntegerContext[16]; - } KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS; -#endif /* defined(__x86_64) */ - - typedef PVOID PACCESS_TOKEN; - typedef PVOID PSECURITY_DESCRIPTOR; - typedef PVOID PSID; - - typedef DWORD ACCESS_MASK; - typedef ACCESS_MASK *PACCESS_MASK; - -#define DELETE (0x00010000L) -#define READ_CONTROL (0x00020000L) -#define WRITE_DAC (0x00040000L) -#define WRITE_OWNER (0x00080000L) -#define SYNCHRONIZE (0x00100000L) - -#define STANDARD_RIGHTS_REQUIRED (0x000F0000L) -#define STANDARD_RIGHTS_READ (READ_CONTROL) -#define STANDARD_RIGHTS_WRITE (READ_CONTROL) -#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL) -#define STANDARD_RIGHTS_ALL (0x001F0000L) - -#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL) - -#define ACCESS_SYSTEM_SECURITY (0x01000000L) - -#define MAXIMUM_ALLOWED (0x02000000L) - -#define GENERIC_READ (0x80000000L) -#define GENERIC_WRITE (0x40000000L) -#define GENERIC_EXECUTE (0x20000000L) -#define GENERIC_ALL (0x10000000L) - - typedef struct _GENERIC_MAPPING { - ACCESS_MASK GenericRead; - ACCESS_MASK GenericWrite; - ACCESS_MASK GenericExecute; - ACCESS_MASK GenericAll; - } GENERIC_MAPPING; - typedef GENERIC_MAPPING *PGENERIC_MAPPING; - -#include - - typedef struct _LUID_AND_ATTRIBUTES { - LUID Luid; - DWORD Attributes; - } LUID_AND_ATTRIBUTES,*PLUID_AND_ATTRIBUTES; - typedef LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; - typedef LUID_AND_ATTRIBUTES_ARRAY *PLUID_AND_ATTRIBUTES_ARRAY; - -#include - -#ifndef SID_IDENTIFIER_AUTHORITY_DEFINED -#define SID_IDENTIFIER_AUTHORITY_DEFINED - typedef struct _SID_IDENTIFIER_AUTHORITY { - BYTE Value[6]; - } SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY; -#endif - -#ifndef SID_DEFINED -#define SID_DEFINED - typedef struct _SID { - BYTE Revision; - BYTE SubAuthorityCount; - SID_IDENTIFIER_AUTHORITY IdentifierAuthority; - DWORD SubAuthority[ANYSIZE_ARRAY]; - } SID,*PISID; -#endif - -#define SID_REVISION (1) -#define SID_MAX_SUB_AUTHORITIES (15) -#define SID_RECOMMENDED_SUB_AUTHORITIES (1) - -#define SECURITY_MAX_SID_SIZE (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES *sizeof(DWORD))) - - typedef enum _SID_NAME_USE { - SidTypeUser = 1,SidTypeGroup,SidTypeDomain,SidTypeAlias,SidTypeWellKnownGroup,SidTypeDeletedAccount,SidTypeInvalid,SidTypeUnknown,SidTypeComputer - } SID_NAME_USE,*PSID_NAME_USE; - - typedef struct _SID_AND_ATTRIBUTES { - PSID Sid; - DWORD Attributes; - } SID_AND_ATTRIBUTES,*PSID_AND_ATTRIBUTES; - - typedef SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; - typedef SID_AND_ATTRIBUTES_ARRAY *PSID_AND_ATTRIBUTES_ARRAY; - -#define SECURITY_NULL_SID_AUTHORITY {0,0,0,0,0,0} -#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} -#define SECURITY_LOCAL_SID_AUTHORITY {0,0,0,0,0,2} -#define SECURITY_CREATOR_SID_AUTHORITY {0,0,0,0,0,3} -#define SECURITY_NON_UNIQUE_AUTHORITY {0,0,0,0,0,4} -#define SECURITY_RESOURCE_MANAGER_AUTHORITY {0,0,0,0,0,9} - -#define SECURITY_NULL_RID (0x00000000L) -#define SECURITY_WORLD_RID (0x00000000L) -#define SECURITY_LOCAL_RID (0x00000000L) - -#define SECURITY_CREATOR_OWNER_RID (0x00000000L) -#define SECURITY_CREATOR_GROUP_RID (0x00000001L) - -#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L) -#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L) - -#define SECURITY_NT_AUTHORITY {0,0,0,0,0,5} - -#define SECURITY_DIALUP_RID (0x00000001L) -#define SECURITY_NETWORK_RID (0x00000002L) -#define SECURITY_BATCH_RID (0x00000003L) -#define SECURITY_INTERACTIVE_RID (0x00000004L) -#define SECURITY_LOGON_IDS_RID (0x00000005L) -#define SECURITY_LOGON_IDS_RID_COUNT (3L) -#define SECURITY_SERVICE_RID (0x00000006L) -#define SECURITY_ANONYMOUS_LOGON_RID (0x00000007L) -#define SECURITY_PROXY_RID (0x00000008L) -#define SECURITY_ENTERPRISE_CONTROLLERS_RID (0x00000009L) -#define SECURITY_SERVER_LOGON_RID SECURITY_ENTERPRISE_CONTROLLERS_RID -#define SECURITY_PRINCIPAL_SELF_RID (0x0000000AL) -#define SECURITY_AUTHENTICATED_USER_RID (0x0000000BL) -#define SECURITY_RESTRICTED_CODE_RID (0x0000000CL) -#define SECURITY_TERMINAL_SERVER_RID (0x0000000DL) -#define SECURITY_REMOTE_LOGON_RID (0x0000000EL) -#define SECURITY_THIS_ORGANIZATION_RID (0x0000000FL) -#define SECURITY_IUSER_RID (0x00000011L) - -#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L) -#define SECURITY_LOCAL_SERVICE_RID (0x00000013L) -#define SECURITY_NETWORK_SERVICE_RID (0x00000014L) - -#define SECURITY_NT_NON_UNIQUE (0x00000015L) -#define SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT (3L) - -#define SECURITY_ENTERPRISE_READONLY_CONTROLLERS_RID (0x00000016L) - -#define SECURITY_BUILTIN_DOMAIN_RID (0x00000020L) -#define SECURITY_WRITE_RESTRICTED_CODE_RID (0x00000021L) - -#define SECURITY_PACKAGE_BASE_RID (0x00000040L) -#define SECURITY_PACKAGE_RID_COUNT (2L) -#define SECURITY_PACKAGE_NTLM_RID (0x0000000AL) -#define SECURITY_PACKAGE_SCHANNEL_RID (0x0000000EL) -#define SECURITY_PACKAGE_DIGEST_RID (0x00000015L) - -#define SECURITY_SERVICE_ID_BASE_RID (0x00000050L) -#define SECURITY_SERVICE_ID_RID_COUNT (6L) - -#define SECURITY_RESERVED_ID_BASE_RID (0x00000051L) - -#define SECURITY_MAX_ALWAYS_FILTERED (0x000003E7L) -#define SECURITY_MIN_NEVER_FILTERED (0x000003E8L) - -#define SECURITY_OTHER_ORGANIZATION_RID (0x000003E8L) - -#define FOREST_USER_RID_MAX (0x000001F3L) - -#define DOMAIN_USER_RID_ADMIN (0x000001F4L) -#define DOMAIN_USER_RID_GUEST (0x000001F5L) -#define DOMAIN_USER_RID_KRBTGT (0x000001F6L) - -#define DOMAIN_USER_RID_MAX (0x000003E7L) - -#define DOMAIN_GROUP_RID_ADMINS (0x00000200L) -#define DOMAIN_GROUP_RID_USERS (0x00000201L) -#define DOMAIN_GROUP_RID_GUESTS (0x00000202L) -#define DOMAIN_GROUP_RID_COMPUTERS (0x00000203L) -#define DOMAIN_GROUP_RID_CONTROLLERS (0x00000204L) -#define DOMAIN_GROUP_RID_CERT_ADMINS (0x00000205L) -#define DOMAIN_GROUP_RID_SCHEMA_ADMINS (0x00000206L) -#define DOMAIN_GROUP_RID_ENTERPRISE_ADMINS (0x00000207L) -#define DOMAIN_GROUP_RID_POLICY_ADMINS (0x00000208L) -#define DOMAIN_GROUP_RID_READONLY_CONTROLLERS (0x00000209L) - -#define DOMAIN_ALIAS_RID_ADMINS (0x00000220L) -#define DOMAIN_ALIAS_RID_USERS (0x00000221L) -#define DOMAIN_ALIAS_RID_GUESTS (0x00000222L) -#define DOMAIN_ALIAS_RID_POWER_USERS (0x00000223L) - -#define DOMAIN_ALIAS_RID_ACCOUNT_OPS (0x00000224L) -#define DOMAIN_ALIAS_RID_SYSTEM_OPS (0x00000225L) -#define DOMAIN_ALIAS_RID_PRINT_OPS (0x00000226L) -#define DOMAIN_ALIAS_RID_BACKUP_OPS (0x00000227L) - -#define DOMAIN_ALIAS_RID_REPLICATOR (0x00000228L) -#define DOMAIN_ALIAS_RID_RAS_SERVERS (0x00000229L) -#define DOMAIN_ALIAS_RID_PREW2KCOMPACCESS (0x0000022AL) -#define DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS (0x0000022BL) -#define DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS (0x0000022CL) -#define DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS (0x0000022DL) - -#define DOMAIN_ALIAS_RID_MONITORING_USERS (0x0000022EL) -#define DOMAIN_ALIAS_RID_LOGGING_USERS (0x0000022FL) -#define DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS (0x00000230L) -#define DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS (0x00000231L) -#define DOMAIN_ALIAS_RID_DCOM_USERS (0x00000232L) - -#define DOMAIN_ALIAS_RID_IUSERS (0x00000238L) -#define DOMAIN_ALIAS_RID_CRYPTO_OPERATORS (0x00000239L) -#define DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP (0x0000023BL) -#define DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP (0x0000023CL) -#define DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP (0x0000023DL) - -#define SECURITY_MANDATORY_LABEL_AUTHORITY {0,0,0,0,0,16} -#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L) -#define SECURITY_MANDATORY_LOW_RID (0x00001000L) -#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L) -#define SECURITY_MANDATORY_HIGH_RID (0x00003000L) -#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L) -#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L) - -#define SECURITY_MANDATORY_MAXIMUM_USER_RID SECURITY_MANDATORY_SYSTEM_RID - -#define MANDATORY_LEVEL_TO_MANDATORY_RID(IL) (IL * 0x1000) - - typedef enum { - WinNullSid = 0,WinWorldSid = 1,WinLocalSid = 2,WinCreatorOwnerSid = 3,WinCreatorGroupSid = 4,WinCreatorOwnerServerSid = 5,WinCreatorGroupServerSid = 6,WinNtAuthoritySid = 7,WinDialupSid = 8,WinNetworkSid = 9,WinBatchSid = 10,WinInteractiveSid = 11,WinServiceSid = 12,WinAnonymousSid = 13,WinProxySid = 14,WinEnterpriseControllersSid = 15,WinSelfSid = 16,WinAuthenticatedUserSid = 17,WinRestrictedCodeSid = 18,WinTerminalServerSid = 19,WinRemoteLogonIdSid = 20,WinLogonIdsSid = 21,WinLocalSystemSid = 22,WinLocalServiceSid = 23,WinNetworkServiceSid = 24,WinBuiltinDomainSid = 25,WinBuiltinAdministratorsSid = 26,WinBuiltinUsersSid = 27,WinBuiltinGuestsSid = 28,WinBuiltinPowerUsersSid = 29,WinBuiltinAccountOperatorsSid = 30,WinBuiltinSystemOperatorsSid = 31,WinBuiltinPrintOperatorsSid = 32,WinBuiltinBackupOperatorsSid = 33,WinBuiltinReplicatorSid = 34,WinBuiltinPreWindows2000CompatibleAccessSid = 35,WinBuiltinRemoteDesktopUsersSid = 36,WinBuiltinNetworkConfigurationOperatorsSid = 37,WinAccountAdministratorSid = 38,WinAccountGuestSid = 39,WinAccountKrbtgtSid = 40,WinAccountDomainAdminsSid = 41,WinAccountDomainUsersSid = 42,WinAccountDomainGuestsSid = 43,WinAccountComputersSid = 44,WinAccountControllersSid = 45,WinAccountCertAdminsSid = 46,WinAccountSchemaAdminsSid = 47,WinAccountEnterpriseAdminsSid = 48,WinAccountPolicyAdminsSid = 49,WinAccountRasAndIasServersSid = 50,WinNTLMAuthenticationSid = 51,WinDigestAuthenticationSid = 52,WinSChannelAuthenticationSid = 53,WinThisOrganizationSid = 54,WinOtherOrganizationSid = 55,WinBuiltinIncomingForestTrustBuildersSid = 56,WinBuiltinPerfMonitoringUsersSid = 57,WinBuiltinPerfLoggingUsersSid = 58,WinBuiltinAuthorizationAccessSid = 59,WinBuiltinTerminalServerLicenseServersSid = 60,WinBuiltinDCOMUsersSid = 61 - } WELL_KNOWN_SID_TYPE; - -#define SYSTEM_LUID { 0x3E7,0x0 } -#define ANONYMOUS_LOGON_LUID { 0x3e6,0x0 } -#define LOCALSERVICE_LUID { 0x3e5,0x0 } -#define NETWORKSERVICE_LUID { 0x3e4,0x0 } -#define IUSER_LUID { 0x3e3, 0x0 } - -#define SE_GROUP_MANDATORY (0x00000001L) -#define SE_GROUP_ENABLED_BY_DEFAULT (0x00000002L) -#define SE_GROUP_ENABLED (0x00000004L) -#define SE_GROUP_OWNER (0x00000008L) -#define SE_GROUP_USE_FOR_DENY_ONLY (0x00000010L) -#define SE_GROUP_INTEGRITY (0x00000020L) -#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L) -#define SE_GROUP_LOGON_ID (0xC0000000L) -#define SE_GROUP_RESOURCE (0x20000000L) - -#define ACL_REVISION (2) -#define ACL_REVISION_DS (4) - -#define ACL_REVISION1 (1) -#define MIN_ACL_REVISION ACL_REVISION2 -#define ACL_REVISION2 (2) -#define ACL_REVISION3 (3) -#define ACL_REVISION4 (4) -#define MAX_ACL_REVISION ACL_REVISION4 - - typedef struct _ACL { - BYTE AclRevision; - BYTE Sbz1; - WORD AclSize; - WORD AceCount; - WORD Sbz2; - } ACL; - typedef ACL *PACL; - - typedef struct _ACE_HEADER { - BYTE AceType; - BYTE AceFlags; - WORD AceSize; - } ACE_HEADER; - typedef ACE_HEADER *PACE_HEADER; - -#define ACCESS_MIN_MS_ACE_TYPE (0x0) -#define ACCESS_ALLOWED_ACE_TYPE (0x0) -#define ACCESS_DENIED_ACE_TYPE (0x1) -#define SYSTEM_AUDIT_ACE_TYPE (0x2) -#define SYSTEM_ALARM_ACE_TYPE (0x3) -#define ACCESS_MAX_MS_V2_ACE_TYPE (0x3) - -#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE (0x4) -#define ACCESS_MAX_MS_V3_ACE_TYPE (0x4) - -#define ACCESS_MIN_MS_OBJECT_ACE_TYPE (0x5) -#define ACCESS_ALLOWED_OBJECT_ACE_TYPE (0x5) -#define ACCESS_DENIED_OBJECT_ACE_TYPE (0x6) -#define SYSTEM_AUDIT_OBJECT_ACE_TYPE (0x7) -#define SYSTEM_ALARM_OBJECT_ACE_TYPE (0x8) -#define ACCESS_MAX_MS_OBJECT_ACE_TYPE (0x8) - -#define ACCESS_MAX_MS_V4_ACE_TYPE (0x8) -#define ACCESS_MAX_MS_ACE_TYPE (0x8) - -#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE (0x9) -#define ACCESS_DENIED_CALLBACK_ACE_TYPE (0xA) -#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE (0xB) -#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE (0xC) -#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE (0xD) -#define SYSTEM_ALARM_CALLBACK_ACE_TYPE (0xE) -#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE (0xF) -#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE (0x10) - -#define SYSTEM_MANDATORY_LABEL_ACE_TYPE (0x11) -#define ACCESS_MAX_MS_V5_ACE_TYPE (0x11) - -#define OBJECT_INHERIT_ACE (0x1) -#define CONTAINER_INHERIT_ACE (0x2) -#define NO_PROPAGATE_INHERIT_ACE (0x4) -#define INHERIT_ONLY_ACE (0x8) -#define INHERITED_ACE (0x10) -#define VALID_INHERIT_FLAGS (0x1F) - -#define SUCCESSFUL_ACCESS_ACE_FLAG (0x40) -#define FAILED_ACCESS_ACE_FLAG (0x80) - - typedef struct _ACCESS_ALLOWED_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } ACCESS_ALLOWED_ACE; - - typedef ACCESS_ALLOWED_ACE *PACCESS_ALLOWED_ACE; - - typedef struct _ACCESS_DENIED_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } ACCESS_DENIED_ACE; - typedef ACCESS_DENIED_ACE *PACCESS_DENIED_ACE; - - typedef struct _SYSTEM_AUDIT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } SYSTEM_AUDIT_ACE; - typedef SYSTEM_AUDIT_ACE *PSYSTEM_AUDIT_ACE; - - typedef struct _SYSTEM_ALARM_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } SYSTEM_ALARM_ACE; - typedef SYSTEM_ALARM_ACE *PSYSTEM_ALARM_ACE; - - typedef struct _ACCESS_ALLOWED_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } ACCESS_ALLOWED_OBJECT_ACE,*PACCESS_ALLOWED_OBJECT_ACE; - - typedef struct _ACCESS_DENIED_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } ACCESS_DENIED_OBJECT_ACE,*PACCESS_DENIED_OBJECT_ACE; - - typedef struct _SYSTEM_AUDIT_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } SYSTEM_AUDIT_OBJECT_ACE,*PSYSTEM_AUDIT_OBJECT_ACE; - - typedef struct _SYSTEM_ALARM_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } SYSTEM_ALARM_OBJECT_ACE,*PSYSTEM_ALARM_OBJECT_ACE; - - typedef struct _ACCESS_ALLOWED_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } ACCESS_ALLOWED_CALLBACK_ACE,*PACCESS_ALLOWED_CALLBACK_ACE; - - typedef struct _ACCESS_DENIED_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } ACCESS_DENIED_CALLBACK_ACE,*PACCESS_DENIED_CALLBACK_ACE; - - typedef struct _SYSTEM_AUDIT_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } SYSTEM_AUDIT_CALLBACK_ACE,*PSYSTEM_AUDIT_CALLBACK_ACE; - - typedef struct _SYSTEM_ALARM_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } SYSTEM_ALARM_CALLBACK_ACE,*PSYSTEM_ALARM_CALLBACK_ACE; - - typedef struct _ACCESS_ALLOWED_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } ACCESS_ALLOWED_CALLBACK_OBJECT_ACE,*PACCESS_ALLOWED_CALLBACK_OBJECT_ACE; - - typedef struct _ACCESS_DENIED_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } ACCESS_DENIED_CALLBACK_OBJECT_ACE,*PACCESS_DENIED_CALLBACK_OBJECT_ACE; - - typedef struct _SYSTEM_AUDIT_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } SYSTEM_AUDIT_CALLBACK_OBJECT_ACE,*PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE; - - typedef struct _SYSTEM_ALARM_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } SYSTEM_ALARM_CALLBACK_OBJECT_ACE,*PSYSTEM_ALARM_CALLBACK_OBJECT_ACE; - -#define ACE_OBJECT_TYPE_PRESENT 0x1 -#define ACE_INHERITED_OBJECT_TYPE_PRESENT 0x2 - - typedef enum _ACL_INFORMATION_CLASS { - AclRevisionInformation = 1,AclSizeInformation - } ACL_INFORMATION_CLASS; - - typedef struct _ACL_REVISION_INFORMATION { - DWORD AclRevision; - } ACL_REVISION_INFORMATION; - typedef ACL_REVISION_INFORMATION *PACL_REVISION_INFORMATION; - - typedef struct _ACL_SIZE_INFORMATION { - DWORD AceCount; - DWORD AclBytesInUse; - DWORD AclBytesFree; - } ACL_SIZE_INFORMATION; - typedef ACL_SIZE_INFORMATION *PACL_SIZE_INFORMATION; - -#define SECURITY_DESCRIPTOR_REVISION (1) -#define SECURITY_DESCRIPTOR_REVISION1 (1) - -#define SECURITY_DESCRIPTOR_MIN_LENGTH (sizeof(SECURITY_DESCRIPTOR)) - - typedef WORD SECURITY_DESCRIPTOR_CONTROL,*PSECURITY_DESCRIPTOR_CONTROL; - -#define SE_OWNER_DEFAULTED (0x0001) -#define SE_GROUP_DEFAULTED (0x0002) -#define SE_DACL_PRESENT (0x0004) -#define SE_DACL_DEFAULTED (0x0008) -#define SE_SACL_PRESENT (0x0010) -#define SE_SACL_DEFAULTED (0x0020) -#define SE_DACL_AUTO_INHERIT_REQ (0x0100) -#define SE_SACL_AUTO_INHERIT_REQ (0x0200) -#define SE_DACL_AUTO_INHERITED (0x0400) -#define SE_SACL_AUTO_INHERITED (0x0800) -#define SE_DACL_PROTECTED (0x1000) -#define SE_SACL_PROTECTED (0x2000) -#define SE_RM_CONTROL_VALID (0x4000) -#define SE_SELF_RELATIVE (0x8000) - - typedef struct _SECURITY_DESCRIPTOR_RELATIVE { - BYTE Revision; - BYTE Sbz1; - SECURITY_DESCRIPTOR_CONTROL Control; - DWORD Owner; - DWORD Group; - DWORD Sacl; - DWORD Dacl; - } SECURITY_DESCRIPTOR_RELATIVE,*PISECURITY_DESCRIPTOR_RELATIVE; - - typedef struct _SECURITY_DESCRIPTOR { - BYTE Revision; - BYTE Sbz1; - SECURITY_DESCRIPTOR_CONTROL Control; - PSID Owner; - PSID Group; - PACL Sacl; - PACL Dacl; - - } SECURITY_DESCRIPTOR,*PISECURITY_DESCRIPTOR; - - typedef struct _OBJECT_TYPE_LIST { - WORD Level; - WORD Sbz; - GUID *ObjectType; - } OBJECT_TYPE_LIST,*POBJECT_TYPE_LIST; - -#define ACCESS_OBJECT_GUID 0 -#define ACCESS_PROPERTY_SET_GUID 1 -#define ACCESS_PROPERTY_GUID 2 - -#define ACCESS_MAX_LEVEL 4 - - typedef enum _AUDIT_EVENT_TYPE { - AuditEventObjectAccess,AuditEventDirectoryServiceAccess - } AUDIT_EVENT_TYPE,*PAUDIT_EVENT_TYPE; - -#define AUDIT_ALLOW_NO_PRIVILEGE 0x1 - -#define ACCESS_DS_SOURCE_A "DS" -#define ACCESS_DS_SOURCE_W L"DS" -#define ACCESS_DS_OBJECT_TYPE_NAME_A "Directory Service Object" -#define ACCESS_DS_OBJECT_TYPE_NAME_W L"Directory Service Object" - -#define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L) -#define SE_PRIVILEGE_ENABLED (0x00000002L) -#define SE_PRIVILEGE_REMOVED (0X00000004L) -#define SE_PRIVILEGE_USED_FOR_ACCESS (0x80000000L) - -#define PRIVILEGE_SET_ALL_NECESSARY (1) - - typedef struct _PRIVILEGE_SET { - DWORD PrivilegeCount; - DWORD Control; - LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]; - } PRIVILEGE_SET,*PPRIVILEGE_SET; - -#define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege") -#define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege") -#define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege") -#define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege") -#define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege") -#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege") -#define SE_TCB_NAME TEXT("SeTcbPrivilege") -#define SE_SECURITY_NAME TEXT("SeSecurityPrivilege") -#define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege") -#define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege") -#define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege") -#define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege") -#define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege") -#define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege") -#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege") -#define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege") -#define SE_BACKUP_NAME TEXT("SeBackupPrivilege") -#define SE_RESTORE_NAME TEXT("SeRestorePrivilege") -#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege") -#define SE_DEBUG_NAME TEXT("SeDebugPrivilege") -#define SE_AUDIT_NAME TEXT("SeAuditPrivilege") -#define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege") -#define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege") -#define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege") -#define SE_UNDOCK_NAME TEXT("SeUndockPrivilege") -#define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege") -#define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege") -#define SE_MANAGE_VOLUME_NAME TEXT("SeManageVolumePrivilege") -#define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege") -#define SE_CREATE_GLOBAL_NAME TEXT("SeCreateGlobalPrivilege") - - typedef enum _SECURITY_IMPERSONATION_LEVEL { - SecurityAnonymous,SecurityIdentification,SecurityImpersonation,SecurityDelegation - } SECURITY_IMPERSONATION_LEVEL,*PSECURITY_IMPERSONATION_LEVEL; - -#define SECURITY_MAX_IMPERSONATION_LEVEL SecurityDelegation -#define SECURITY_MIN_IMPERSONATION_LEVEL SecurityAnonymous -#define DEFAULT_IMPERSONATION_LEVEL SecurityImpersonation -#define VALID_IMPERSONATION_LEVEL(L) (((L) >= SECURITY_MIN_IMPERSONATION_LEVEL) && ((L) <= SECURITY_MAX_IMPERSONATION_LEVEL)) - -#define TOKEN_ASSIGN_PRIMARY (0x0001) -#define TOKEN_DUPLICATE (0x0002) -#define TOKEN_IMPERSONATE (0x0004) -#define TOKEN_QUERY (0x0008) -#define TOKEN_QUERY_SOURCE (0x0010) -#define TOKEN_ADJUST_PRIVILEGES (0x0020) -#define TOKEN_ADJUST_GROUPS (0x0040) -#define TOKEN_ADJUST_DEFAULT (0x0080) -#define TOKEN_ADJUST_SESSIONID (0x0100) - -#define TOKEN_ALL_ACCESS_P (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) -#define TOKEN_ALL_ACCESS (TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID) -#define TOKEN_READ (STANDARD_RIGHTS_READ | TOKEN_QUERY) - -#define TOKEN_WRITE (STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) - -#define TOKEN_EXECUTE (STANDARD_RIGHTS_EXECUTE) - - typedef enum _TOKEN_TYPE { - TokenPrimary = 1,TokenImpersonation - } TOKEN_TYPE; - typedef TOKEN_TYPE *PTOKEN_TYPE; - - typedef enum _TOKEN_INFORMATION_CLASS { - TokenUser = 1,TokenGroups,TokenPrivileges,TokenOwner,TokenPrimaryGroup,TokenDefaultDacl,TokenSource,TokenType,TokenImpersonationLevel, - TokenStatistics,TokenRestrictedSids,TokenSessionId,TokenGroupsAndPrivileges,TokenSessionReference,TokenSandBoxInert,TokenAuditPolicy, - TokenOrigin,MaxTokenInfoClass - } TOKEN_INFORMATION_CLASS,*PTOKEN_INFORMATION_CLASS; - - typedef struct _TOKEN_USER { - SID_AND_ATTRIBUTES User; - } TOKEN_USER,*PTOKEN_USER; - - typedef struct _TOKEN_GROUPS { - DWORD GroupCount; - SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; - } TOKEN_GROUPS,*PTOKEN_GROUPS; - - typedef struct _TOKEN_PRIVILEGES { - DWORD PrivilegeCount; - LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; - } TOKEN_PRIVILEGES,*PTOKEN_PRIVILEGES; - - typedef struct _TOKEN_OWNER { - PSID Owner; - } TOKEN_OWNER,*PTOKEN_OWNER; - - typedef struct _TOKEN_PRIMARY_GROUP { - PSID PrimaryGroup; - } TOKEN_PRIMARY_GROUP,*PTOKEN_PRIMARY_GROUP; - - typedef struct _TOKEN_DEFAULT_DACL { - PACL DefaultDacl; - } TOKEN_DEFAULT_DACL,*PTOKEN_DEFAULT_DACL; - - typedef struct _TOKEN_GROUPS_AND_PRIVILEGES { - DWORD SidCount; - DWORD SidLength; - PSID_AND_ATTRIBUTES Sids; - DWORD RestrictedSidCount; - DWORD RestrictedSidLength; - PSID_AND_ATTRIBUTES RestrictedSids; - DWORD PrivilegeCount; - DWORD PrivilegeLength; - PLUID_AND_ATTRIBUTES Privileges; - LUID AuthenticationId; - } TOKEN_GROUPS_AND_PRIVILEGES,*PTOKEN_GROUPS_AND_PRIVILEGES; - -#define TOKEN_AUDIT_SUCCESS_INCLUDE 0x1 -#define TOKEN_AUDIT_SUCCESS_EXCLUDE 0x2 -#define TOKEN_AUDIT_FAILURE_INCLUDE 0x4 -#define TOKEN_AUDIT_FAILURE_EXCLUDE 0x8 - -#define VALID_AUDIT_POLICY_BITS (TOKEN_AUDIT_SUCCESS_INCLUDE | TOKEN_AUDIT_SUCCESS_EXCLUDE | TOKEN_AUDIT_FAILURE_INCLUDE | TOKEN_AUDIT_FAILURE_EXCLUDE) -#define VALID_TOKEN_AUDIT_POLICY_ELEMENT(P) ((((P).PolicyMask & ~VALID_AUDIT_POLICY_BITS)==0) && ((P).Category <= AuditEventMaxType)) - - typedef struct _TOKEN_AUDIT_POLICY_ELEMENT { - DWORD Category; - DWORD PolicyMask; - } TOKEN_AUDIT_POLICY_ELEMENT,*PTOKEN_AUDIT_POLICY_ELEMENT; - - typedef struct _TOKEN_AUDIT_POLICY { - DWORD PolicyCount; - TOKEN_AUDIT_POLICY_ELEMENT Policy[ANYSIZE_ARRAY]; - } TOKEN_AUDIT_POLICY,*PTOKEN_AUDIT_POLICY; - -#define PER_USER_AUDITING_POLICY_SIZE(p) (sizeof(TOKEN_AUDIT_POLICY) + (((p)->PolicyCount > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((p)->PolicyCount - ANYSIZE_ARRAY)) : 0)) -#define PER_USER_AUDITING_POLICY_SIZE_BY_COUNT(C) (sizeof(TOKEN_AUDIT_POLICY) + (((C) > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((C) - ANYSIZE_ARRAY)) : 0)) - -#define TOKEN_SOURCE_LENGTH 8 - - typedef struct _TOKEN_SOURCE { - CHAR SourceName[TOKEN_SOURCE_LENGTH]; - LUID SourceIdentifier; - } TOKEN_SOURCE,*PTOKEN_SOURCE; - - typedef struct _TOKEN_STATISTICS { - LUID TokenId; - LUID AuthenticationId; - LARGE_INTEGER ExpirationTime; - TOKEN_TYPE TokenType; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - DWORD DynamicCharged; - DWORD DynamicAvailable; - DWORD GroupCount; - DWORD PrivilegeCount; - LUID ModifiedId; - } TOKEN_STATISTICS,*PTOKEN_STATISTICS; - - typedef struct _TOKEN_CONTROL { - LUID TokenId; - LUID AuthenticationId; - LUID ModifiedId; - TOKEN_SOURCE TokenSource; - } TOKEN_CONTROL,*PTOKEN_CONTROL; - - typedef struct _TOKEN_ORIGIN { - LUID OriginatingLogonSession; - } TOKEN_ORIGIN,*PTOKEN_ORIGIN; - -#define SECURITY_DYNAMIC_TRACKING (TRUE) -#define SECURITY_STATIC_TRACKING (FALSE) - - typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE,*PSECURITY_CONTEXT_TRACKING_MODE; - - typedef struct _SECURITY_QUALITY_OF_SERVICE { - DWORD Length; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode; - BOOLEAN EffectiveOnly; - } SECURITY_QUALITY_OF_SERVICE,*PSECURITY_QUALITY_OF_SERVICE; - - typedef struct _SE_IMPERSONATION_STATE { - PACCESS_TOKEN Token; - BOOLEAN CopyOnOpen; - BOOLEAN EffectiveOnly; - SECURITY_IMPERSONATION_LEVEL Level; - } SE_IMPERSONATION_STATE,*PSE_IMPERSONATION_STATE; - -#define DISABLE_MAX_PRIVILEGE 0x1 -#define SANDBOX_INERT 0x2 - - typedef DWORD SECURITY_INFORMATION,*PSECURITY_INFORMATION; - -#define OWNER_SECURITY_INFORMATION (0x00000001L) -#define GROUP_SECURITY_INFORMATION (0x00000002L) -#define DACL_SECURITY_INFORMATION (0x00000004L) -#define SACL_SECURITY_INFORMATION (0x00000008L) - -#define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L) -#define PROTECTED_SACL_SECURITY_INFORMATION (0x40000000L) -#define UNPROTECTED_DACL_SECURITY_INFORMATION (0x20000000L) -#define UNPROTECTED_SACL_SECURITY_INFORMATION (0x10000000L) - -#define PROCESS_TERMINATE (0x0001) -#define PROCESS_CREATE_THREAD (0x0002) -#define PROCESS_SET_SESSIONID (0x0004) -#define PROCESS_VM_OPERATION (0x0008) -#define PROCESS_VM_READ (0x0010) -#define PROCESS_VM_WRITE (0x0020) -#define PROCESS_DUP_HANDLE (0x0040) -#define PROCESS_CREATE_PROCESS (0x0080) -#define PROCESS_SET_QUOTA (0x0100) -#define PROCESS_SET_INFORMATION (0x0200) -#define PROCESS_QUERY_INFORMATION (0x0400) -#define PROCESS_SUSPEND_RESUME (0x0800) -#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF) - -#ifdef _WIN64 -#define MAXIMUM_PROCESSORS 64 -#else -#define MAXIMUM_PROCESSORS 32 -#endif - -#define THREAD_TERMINATE (0x0001) -#define THREAD_SUSPEND_RESUME (0x0002) -#define THREAD_GET_CONTEXT (0x0008) -#define THREAD_SET_CONTEXT (0x0010) -#define THREAD_SET_INFORMATION (0x0020) -#define THREAD_QUERY_INFORMATION (0x0040) -#define THREAD_SET_THREAD_TOKEN (0x0080) -#define THREAD_IMPERSONATE (0x0100) -#define THREAD_DIRECT_IMPERSONATION (0x0200) - -#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF) - -#define JOB_OBJECT_ASSIGN_PROCESS (0x0001) -#define JOB_OBJECT_SET_ATTRIBUTES (0x0002) -#define JOB_OBJECT_QUERY (0x0004) -#define JOB_OBJECT_TERMINATE (0x0008) -#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010) -#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1F) - - typedef struct _JOB_SET_ARRAY { - HANDLE JobHandle; - DWORD MemberLevel; - DWORD Flags; - } JOB_SET_ARRAY,*PJOB_SET_ARRAY; - -#define FLS_MAXIMUM_AVAILABLE 128 -#define TLS_MINIMUM_AVAILABLE 64 - -#ifndef _NT_TIB_DEFINED -#define _NT_TIB_DEFINED - typedef struct _NT_TIB { - struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; - PVOID StackBase; - PVOID StackLimit; - PVOID SubSystemTib; - union { - PVOID FiberData; - DWORD Version; - }; - PVOID ArbitraryUserPointer; - struct _NT_TIB *Self; - } NT_TIB; - typedef NT_TIB *PNT_TIB; -#endif - - typedef struct _NT_TIB32 { - DWORD ExceptionList; - DWORD StackBase; - DWORD StackLimit; - DWORD SubSystemTib; - union { - DWORD FiberData; - DWORD Version; - }; - DWORD ArbitraryUserPointer; - DWORD Self; - } NT_TIB32,*PNT_TIB32; - - typedef struct _NT_TIB64 { - DWORD64 ExceptionList; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD64 SubSystemTib; - union { - DWORD64 FiberData; - DWORD Version; - }; - DWORD64 ArbitraryUserPointer; - DWORD64 Self; - } NT_TIB64,*PNT_TIB64; - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) -#define WX86 -#endif - -#define THREAD_BASE_PRIORITY_LOWRT 15 -#define THREAD_BASE_PRIORITY_MAX 2 -#define THREAD_BASE_PRIORITY_MIN (-2) -#define THREAD_BASE_PRIORITY_IDLE (-15) - - typedef struct _QUOTA_LIMITS { - SIZE_T PagedPoolLimit; - SIZE_T NonPagedPoolLimit; - SIZE_T MinimumWorkingSetSize; - SIZE_T MaximumWorkingSetSize; - SIZE_T PagefileLimit; - LARGE_INTEGER TimeLimit; - } QUOTA_LIMITS,*PQUOTA_LIMITS; - -#define QUOTA_LIMITS_HARDWS_MIN_ENABLE 0x00000001 -#define QUOTA_LIMITS_HARDWS_MIN_DISABLE 0x00000002 -#define QUOTA_LIMITS_HARDWS_MAX_ENABLE 0x00000004 -#define QUOTA_LIMITS_HARDWS_MAX_DISABLE 0x00000008 - - typedef struct _QUOTA_LIMITS_EX { - SIZE_T PagedPoolLimit; - SIZE_T NonPagedPoolLimit; - SIZE_T MinimumWorkingSetSize; - SIZE_T MaximumWorkingSetSize; - SIZE_T PagefileLimit; - LARGE_INTEGER TimeLimit; - SIZE_T Reserved1; - SIZE_T Reserved2; - SIZE_T Reserved3; - SIZE_T Reserved4; - DWORD Flags; - DWORD Reserved5; - } QUOTA_LIMITS_EX,*PQUOTA_LIMITS_EX; - - typedef struct _IO_COUNTERS { - ULONGLONG ReadOperationCount; - ULONGLONG WriteOperationCount; - ULONGLONG OtherOperationCount; - ULONGLONG ReadTransferCount; - ULONGLONG WriteTransferCount; - ULONGLONG OtherTransferCount; - } IO_COUNTERS; - typedef IO_COUNTERS *PIO_COUNTERS; - - typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION { - LARGE_INTEGER TotalUserTime; - LARGE_INTEGER TotalKernelTime; - LARGE_INTEGER ThisPeriodTotalUserTime; - LARGE_INTEGER ThisPeriodTotalKernelTime; - DWORD TotalPageFaultCount; - DWORD TotalProcesses; - DWORD ActiveProcesses; - DWORD TotalTerminatedProcesses; - } JOBOBJECT_BASIC_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION; - - typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION { - LARGE_INTEGER PerProcessUserTimeLimit; - LARGE_INTEGER PerJobUserTimeLimit; - DWORD LimitFlags; - SIZE_T MinimumWorkingSetSize; - SIZE_T MaximumWorkingSetSize; - DWORD ActiveProcessLimit; - ULONG_PTR Affinity; - DWORD PriorityClass; - DWORD SchedulingClass; - } JOBOBJECT_BASIC_LIMIT_INFORMATION,*PJOBOBJECT_BASIC_LIMIT_INFORMATION; - - typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION { - JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; - IO_COUNTERS IoInfo; - SIZE_T ProcessMemoryLimit; - SIZE_T JobMemoryLimit; - SIZE_T PeakProcessMemoryUsed; - SIZE_T PeakJobMemoryUsed; - } JOBOBJECT_EXTENDED_LIMIT_INFORMATION,*PJOBOBJECT_EXTENDED_LIMIT_INFORMATION; - - typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST { - DWORD NumberOfAssignedProcesses; - DWORD NumberOfProcessIdsInList; - ULONG_PTR ProcessIdList[1]; - } JOBOBJECT_BASIC_PROCESS_ID_LIST,*PJOBOBJECT_BASIC_PROCESS_ID_LIST; - - typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS { - DWORD UIRestrictionsClass; - } JOBOBJECT_BASIC_UI_RESTRICTIONS,*PJOBOBJECT_BASIC_UI_RESTRICTIONS; - - typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION { - DWORD SecurityLimitFlags; - HANDLE JobToken; - PTOKEN_GROUPS SidsToDisable; - PTOKEN_PRIVILEGES PrivilegesToDelete; - PTOKEN_GROUPS RestrictedSids; - } JOBOBJECT_SECURITY_LIMIT_INFORMATION,*PJOBOBJECT_SECURITY_LIMIT_INFORMATION; - - typedef struct _JOBOBJECT_END_OF_JOB_TIME_INFORMATION { - DWORD EndOfJobTimeAction; - } JOBOBJECT_END_OF_JOB_TIME_INFORMATION,*PJOBOBJECT_END_OF_JOB_TIME_INFORMATION; - - typedef struct _JOBOBJECT_ASSOCIATE_COMPLETION_PORT { - PVOID CompletionKey; - HANDLE CompletionPort; - } JOBOBJECT_ASSOCIATE_COMPLETION_PORT,*PJOBOBJECT_ASSOCIATE_COMPLETION_PORT; - - typedef struct _JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION { - JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo; - IO_COUNTERS IoInfo; - } JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION; - - typedef struct _JOBOBJECT_JOBSET_INFORMATION { - DWORD MemberLevel; - } JOBOBJECT_JOBSET_INFORMATION,*PJOBOBJECT_JOBSET_INFORMATION; - -#define JOB_OBJECT_TERMINATE_AT_END_OF_JOB 0 -#define JOB_OBJECT_POST_AT_END_OF_JOB 1 - -#define JOB_OBJECT_MSG_END_OF_JOB_TIME 1 -#define JOB_OBJECT_MSG_END_OF_PROCESS_TIME 2 -#define JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT 3 -#define JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO 4 -#define JOB_OBJECT_MSG_NEW_PROCESS 6 -#define JOB_OBJECT_MSG_EXIT_PROCESS 7 -#define JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS 8 -#define JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT 9 -#define JOB_OBJECT_MSG_JOB_MEMORY_LIMIT 10 - -#define JOB_OBJECT_LIMIT_WORKINGSET 0x00000001 -#define JOB_OBJECT_LIMIT_PROCESS_TIME 0x00000002 -#define JOB_OBJECT_LIMIT_JOB_TIME 0x00000004 -#define JOB_OBJECT_LIMIT_ACTIVE_PROCESS 0x00000008 -#define JOB_OBJECT_LIMIT_AFFINITY 0x00000010 -#define JOB_OBJECT_LIMIT_PRIORITY_CLASS 0x00000020 -#define JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME 0x00000040 -#define JOB_OBJECT_LIMIT_SCHEDULING_CLASS 0x00000080 - -#define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100 -#define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200 -#define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400 -#define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800 -#define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000 -#define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 - -#define JOB_OBJECT_LIMIT_RESERVED2 0x00004000 -#define JOB_OBJECT_LIMIT_RESERVED3 0x00008000 -#define JOB_OBJECT_LIMIT_RESERVED4 0x00010000 -#define JOB_OBJECT_LIMIT_RESERVED5 0x00020000 -#define JOB_OBJECT_LIMIT_RESERVED6 0x00040000 - -#define JOB_OBJECT_LIMIT_VALID_FLAGS 0x0007ffff - -#define JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS 0x000000ff -#define JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS 0x00003fff -#define JOB_OBJECT_RESERVED_LIMIT_VALID_FLAGS 0x0007ffff - -#define JOB_OBJECT_UILIMIT_NONE 0x00000000 - -#define JOB_OBJECT_UILIMIT_HANDLES 0x00000001 -#define JOB_OBJECT_UILIMIT_READCLIPBOARD 0x00000002 -#define JOB_OBJECT_UILIMIT_WRITECLIPBOARD 0x00000004 -#define JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS 0x00000008 -#define JOB_OBJECT_UILIMIT_DISPLAYSETTINGS 0x00000010 -#define JOB_OBJECT_UILIMIT_GLOBALATOMS 0x00000020 -#define JOB_OBJECT_UILIMIT_DESKTOP 0x00000040 -#define JOB_OBJECT_UILIMIT_EXITWINDOWS 0x00000080 - -#define JOB_OBJECT_UILIMIT_ALL 0x000000FF - -#define JOB_OBJECT_UI_VALID_FLAGS 0x000000FF - -#define JOB_OBJECT_SECURITY_NO_ADMIN 0x00000001 -#define JOB_OBJECT_SECURITY_RESTRICTED_TOKEN 0x00000002 -#define JOB_OBJECT_SECURITY_ONLY_TOKEN 0x00000004 -#define JOB_OBJECT_SECURITY_FILTER_TOKENS 0x00000008 - -#define JOB_OBJECT_SECURITY_VALID_FLAGS 0x0000000f - - typedef enum _JOBOBJECTINFOCLASS { - JobObjectBasicAccountingInformation = 1,JobObjectBasicLimitInformation,JobObjectBasicProcessIdList,JobObjectBasicUIRestrictions, - JobObjectSecurityLimitInformation,JobObjectEndOfJobTimeInformation,JobObjectAssociateCompletionPortInformation, - JobObjectBasicAndIoAccountingInformation,JobObjectExtendedLimitInformation,JobObjectJobSetInformation,MaxJobObjectInfoClass - } JOBOBJECTINFOCLASS; - -#define EVENT_MODIFY_STATE 0x0002 -#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) - -#define MUTANT_QUERY_STATE 0x0001 - -#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| MUTANT_QUERY_STATE) -#define SEMAPHORE_MODIFY_STATE 0x0002 -#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) - -#define TIMER_QUERY_STATE 0x0001 -#define TIMER_MODIFY_STATE 0x0002 - -#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| TIMER_QUERY_STATE|TIMER_MODIFY_STATE) - -#define TIME_ZONE_ID_UNKNOWN 0 -#define TIME_ZONE_ID_STANDARD 1 -#define TIME_ZONE_ID_DAYLIGHT 2 - - typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { - RelationProcessorCore,RelationNumaNode,RelationCache - } LOGICAL_PROCESSOR_RELATIONSHIP; - -#define LTP_PC_SMT 0x1 - - typedef enum _PROCESSOR_CACHE_TYPE { - CacheUnified,CacheInstruction,CacheData,CacheTrace - } PROCESSOR_CACHE_TYPE; - -#define CACHE_FULLY_ASSOCIATIVE 0xFF - - typedef struct _CACHE_DESCRIPTOR { - BYTE Level; - BYTE Associativity; - WORD LineSize; - DWORD Size; - PROCESSOR_CACHE_TYPE Type; - } CACHE_DESCRIPTOR,*PCACHE_DESCRIPTOR; - - typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { - ULONG_PTR ProcessorMask; - LOGICAL_PROCESSOR_RELATIONSHIP Relationship; - union { - struct { - BYTE Flags; - } ProcessorCore; - struct { - DWORD NodeNumber; - } NumaNode; - CACHE_DESCRIPTOR Cache; - ULONGLONG Reserved[2]; - }; - } SYSTEM_LOGICAL_PROCESSOR_INFORMATION,*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; - -#define PROCESSOR_INTEL_386 386 -#define PROCESSOR_INTEL_486 486 -#define PROCESSOR_INTEL_PENTIUM 586 -#define PROCESSOR_INTEL_IA64 2200 -#define PROCESSOR_AMD_X8664 8664 -#define PROCESSOR_MIPS_R4000 4000 -#define PROCESSOR_ALPHA_21064 21064 -#define PROCESSOR_PPC_601 601 -#define PROCESSOR_PPC_603 603 -#define PROCESSOR_PPC_604 604 -#define PROCESSOR_PPC_620 620 -#define PROCESSOR_HITACHI_SH3 10003 -#define PROCESSOR_HITACHI_SH3E 10004 -#define PROCESSOR_HITACHI_SH4 10005 -#define PROCESSOR_MOTOROLA_821 821 -#define PROCESSOR_SHx_SH3 103 -#define PROCESSOR_SHx_SH4 104 -#define PROCESSOR_STRONGARM 2577 -#define PROCESSOR_ARM720 1824 -#define PROCESSOR_ARM820 2080 -#define PROCESSOR_ARM920 2336 -#define PROCESSOR_ARM_7TDMI 70001 -#define PROCESSOR_OPTIL 0x494f - -#define PROCESSOR_ARCHITECTURE_INTEL 0 -#define PROCESSOR_ARCHITECTURE_MIPS 1 -#define PROCESSOR_ARCHITECTURE_ALPHA 2 -#define PROCESSOR_ARCHITECTURE_PPC 3 -#define PROCESSOR_ARCHITECTURE_SHX 4 -#define PROCESSOR_ARCHITECTURE_ARM 5 -#define PROCESSOR_ARCHITECTURE_IA64 6 -#define PROCESSOR_ARCHITECTURE_ALPHA64 7 -#define PROCESSOR_ARCHITECTURE_MSIL 8 -#define PROCESSOR_ARCHITECTURE_AMD64 9 -#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 - -#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF - -#define PF_FLOATING_POINT_PRECISION_ERRATA 0 -#define PF_FLOATING_POINT_EMULATED 1 -#define PF_COMPARE_EXCHANGE_DOUBLE 2 -#define PF_MMX_INSTRUCTIONS_AVAILABLE 3 -#define PF_PPC_MOVEMEM_64BIT_OK 4 -#define PF_ALPHA_BYTE_INSTRUCTIONS 5 -#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6 -#define PF_3DNOW_INSTRUCTIONS_AVAILABLE 7 -#define PF_RDTSC_INSTRUCTION_AVAILABLE 8 -#define PF_PAE_ENABLED 9 -#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10 -#define PF_SSE_DAZ_MODE_AVAILABLE 11 -#define PF_NX_ENABLED 12 - - typedef struct _MEMORY_BASIC_INFORMATION { - PVOID BaseAddress; - PVOID AllocationBase; - DWORD AllocationProtect; - SIZE_T RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; - } MEMORY_BASIC_INFORMATION,*PMEMORY_BASIC_INFORMATION; - - typedef struct _MEMORY_BASIC_INFORMATION32 { - DWORD BaseAddress; - DWORD AllocationBase; - DWORD AllocationProtect; - DWORD RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; - } MEMORY_BASIC_INFORMATION32,*PMEMORY_BASIC_INFORMATION32; - - typedef struct DECLSPEC_ALIGN(16) _MEMORY_BASIC_INFORMATION64 { - ULONGLONG BaseAddress; - ULONGLONG AllocationBase; - DWORD AllocationProtect; - DWORD __alignment1; - ULONGLONG RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; - DWORD __alignment2; - } MEMORY_BASIC_INFORMATION64,*PMEMORY_BASIC_INFORMATION64; - -#define SECTION_QUERY 0x0001 -#define SECTION_MAP_WRITE 0x0002 -#define SECTION_MAP_READ 0x0004 -#define SECTION_MAP_EXECUTE 0x0008 -#define SECTION_EXTEND_SIZE 0x0010 -#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020 - -#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY| SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE) -#define PAGE_NOACCESS 0x01 -#define PAGE_READONLY 0x02 -#define PAGE_READWRITE 0x04 -#define PAGE_WRITECOPY 0x08 -#define PAGE_EXECUTE 0x10 -#define PAGE_EXECUTE_READ 0x20 -#define PAGE_EXECUTE_READWRITE 0x40 -#define PAGE_EXECUTE_WRITECOPY 0x80 -#define PAGE_GUARD 0x100 -#define PAGE_NOCACHE 0x200 -#define PAGE_WRITECOMBINE 0x400 -#define MEM_COMMIT 0x1000 -#define MEM_RESERVE 0x2000 -#define MEM_DECOMMIT 0x4000 -#define MEM_RELEASE 0x8000 -#define MEM_FREE 0x10000 -#define MEM_PRIVATE 0x20000 -#define MEM_MAPPED 0x40000 -#define MEM_RESET 0x80000 -#define MEM_TOP_DOWN 0x100000 -#define MEM_WRITE_WATCH 0x200000 -#define MEM_PHYSICAL 0x400000 -#define MEM_LARGE_PAGES 0x20000000 -#define MEM_4MB_PAGES 0x80000000 -#define SEC_FILE 0x800000 -#define SEC_IMAGE 0x1000000 -#define SEC_RESERVE 0x4000000 -#define SEC_COMMIT 0x8000000 -#define SEC_NOCACHE 0x10000000 -#define SEC_LARGE_PAGES 0x80000000 -#define MEM_IMAGE SEC_IMAGE -#define WRITE_WATCH_FLAG_RESET 0x01 - -#define FILE_READ_DATA (0x0001) -#define FILE_LIST_DIRECTORY (0x0001) - -#define FILE_WRITE_DATA (0x0002) -#define FILE_ADD_FILE (0x0002) - -#define FILE_APPEND_DATA (0x0004) -#define FILE_ADD_SUBDIRECTORY (0x0004) -#define FILE_CREATE_PIPE_INSTANCE (0x0004) - -#define FILE_READ_EA (0x0008) - -#define FILE_WRITE_EA (0x0010) - -#define FILE_EXECUTE (0x0020) -#define FILE_TRAVERSE (0x0020) - -#define FILE_DELETE_CHILD (0x0040) - -#define FILE_READ_ATTRIBUTES (0x0080) - -#define FILE_WRITE_ATTRIBUTES (0x0100) - -#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) -#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE) -#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE) -#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE) - -#define FILE_SHARE_READ 0x00000001 -#define FILE_SHARE_WRITE 0x00000002 -#define FILE_SHARE_DELETE 0x00000004 -#define FILE_ATTRIBUTE_READONLY 0x00000001 -#define FILE_ATTRIBUTE_HIDDEN 0x00000002 -#define FILE_ATTRIBUTE_SYSTEM 0x00000004 -#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 -#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 -#define FILE_ATTRIBUTE_DEVICE 0x00000040 -#define FILE_ATTRIBUTE_NORMAL 0x00000080 -#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 -#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 -#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 -#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 -#define FILE_ATTRIBUTE_OFFLINE 0x00001000 -#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 -#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 -#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 -#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 -#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 -#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 -#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 -#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 -#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 -#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 -#define FILE_ACTION_ADDED 0x00000001 -#define FILE_ACTION_REMOVED 0x00000002 -#define FILE_ACTION_MODIFIED 0x00000003 -#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 -#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 -#define MAILSLOT_NO_MESSAGE ((DWORD)-1) -#define MAILSLOT_WAIT_FOREVER ((DWORD)-1) -#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 -#define FILE_CASE_PRESERVED_NAMES 0x00000002 -#define FILE_UNICODE_ON_DISK 0x00000004 -#define FILE_PERSISTENT_ACLS 0x00000008 -#define FILE_FILE_COMPRESSION 0x00000010 -#define FILE_VOLUME_QUOTAS 0x00000020 -#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 -#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 -#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 -#define FILE_VOLUME_IS_COMPRESSED 0x00008000 -#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 -#define FILE_SUPPORTS_ENCRYPTION 0x00020000 -#define FILE_NAMED_STREAMS 0x00040000 -#define FILE_READ_ONLY_VOLUME 0x00080000 - - typedef struct _FILE_NOTIFY_INFORMATION { - DWORD NextEntryOffset; - DWORD Action; - DWORD FileNameLength; - WCHAR FileName[1]; - } FILE_NOTIFY_INFORMATION,*PFILE_NOTIFY_INFORMATION; - - typedef union _FILE_SEGMENT_ELEMENT { - PVOID64 Buffer; - ULONGLONG Alignment; - }FILE_SEGMENT_ELEMENT,*PFILE_SEGMENT_ELEMENT; - - typedef struct _REPARSE_GUID_DATA_BUFFER { - DWORD ReparseTag; - WORD ReparseDataLength; - WORD Reserved; - GUID ReparseGuid; - struct { - BYTE DataBuffer[1]; - } GenericReparseBuffer; - } REPARSE_GUID_DATA_BUFFER,*PREPARSE_GUID_DATA_BUFFER; - -#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER,GenericReparseBuffer) - -#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 *1024) - -#define IO_REPARSE_TAG_RESERVED_ZERO (0) -#define IO_REPARSE_TAG_RESERVED_ONE (1) - -#define IO_REPARSE_TAG_RESERVED_RANGE IO_REPARSE_TAG_RESERVED_ONE - -#define IsReparseTagMicrosoft(_tag) (((_tag) & 0x80000000)) -#define IsReparseTagNameSurrogate(_tag) (((_tag) & 0x20000000)) - -#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) -#define IO_REPARSE_TAG_HSM (0xC0000004L) -#define IO_REPARSE_TAG_SIS (0x80000007L) -#define IO_REPARSE_TAG_DFS (0x8000000AL) -#define IO_REPARSE_TAG_FILTER_MANAGER (0x8000000BL) -#define IO_COMPLETION_MODIFY_STATE 0x0002 -#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) -#define DUPLICATE_CLOSE_SOURCE 0x00000001 -#define DUPLICATE_SAME_ACCESS 0x00000002 - - typedef enum _SYSTEM_POWER_STATE { - PowerSystemUnspecified = 0,PowerSystemWorking = 1,PowerSystemSleeping1 = 2,PowerSystemSleeping2 = 3,PowerSystemSleeping3 = 4,PowerSystemHibernate = 5,PowerSystemShutdown = 6,PowerSystemMaximum = 7 - } SYSTEM_POWER_STATE,*PSYSTEM_POWER_STATE; - -#define POWER_SYSTEM_MAXIMUM 7 - - typedef enum { - PowerActionNone = 0,PowerActionReserved,PowerActionSleep,PowerActionHibernate,PowerActionShutdown,PowerActionShutdownReset,PowerActionShutdownOff,PowerActionWarmEject - } POWER_ACTION,*PPOWER_ACTION; - - typedef enum _DEVICE_POWER_STATE { - PowerDeviceUnspecified = 0,PowerDeviceD0,PowerDeviceD1,PowerDeviceD2,PowerDeviceD3,PowerDeviceMaximum - } DEVICE_POWER_STATE,*PDEVICE_POWER_STATE; - -#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001) -#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002) -#define ES_USER_PRESENT ((DWORD)0x00000004) -#define ES_CONTINUOUS ((DWORD)0x80000000) - - typedef DWORD EXECUTION_STATE; - - typedef enum { - LT_DONT_CARE,LT_LOWEST_LATENCY - } LATENCY_TIME; - -#define PDCAP_D0_SUPPORTED 0x00000001 -#define PDCAP_D1_SUPPORTED 0x00000002 -#define PDCAP_D2_SUPPORTED 0x00000004 -#define PDCAP_D3_SUPPORTED 0x00000008 -#define PDCAP_WAKE_FROM_D0_SUPPORTED 0x00000010 -#define PDCAP_WAKE_FROM_D1_SUPPORTED 0x00000020 -#define PDCAP_WAKE_FROM_D2_SUPPORTED 0x00000040 -#define PDCAP_WAKE_FROM_D3_SUPPORTED 0x00000080 -#define PDCAP_WARM_EJECT_SUPPORTED 0x00000100 - - typedef struct CM_Power_Data_s { - DWORD PD_Size; - DEVICE_POWER_STATE PD_MostRecentPowerState; - DWORD PD_Capabilities; - DWORD PD_D1Latency; - DWORD PD_D2Latency; - DWORD PD_D3Latency; - DEVICE_POWER_STATE PD_PowerStateMapping[POWER_SYSTEM_MAXIMUM]; - SYSTEM_POWER_STATE PD_DeepestSystemWake; - } CM_POWER_DATA,*PCM_POWER_DATA; - - typedef enum { - SystemPowerPolicyAc,SystemPowerPolicyDc,VerifySystemPolicyAc,VerifySystemPolicyDc,SystemPowerCapabilities,SystemBatteryState,SystemPowerStateHandler,ProcessorStateHandler,SystemPowerPolicyCurrent,AdministratorPowerPolicy,SystemReserveHiberFile,ProcessorInformation,SystemPowerInformation,ProcessorStateHandler2,LastWakeTime,LastSleepTime,SystemExecutionState,SystemPowerStateNotifyHandler,ProcessorPowerPolicyAc,ProcessorPowerPolicyDc,VerifyProcessorPowerPolicyAc,VerifyProcessorPowerPolicyDc,ProcessorPowerPolicyCurrent,SystemPowerStateLogging,SystemPowerLoggingEntry - } POWER_INFORMATION_LEVEL; - - typedef struct { - DWORD Granularity; - DWORD Capacity; - } BATTERY_REPORTING_SCALE,*PBATTERY_REPORTING_SCALE; - - typedef struct { - POWER_ACTION Action; - DWORD Flags; - DWORD EventCode; - } POWER_ACTION_POLICY,*PPOWER_ACTION_POLICY; - -#define POWER_ACTION_QUERY_ALLOWED 0x00000001 -#define POWER_ACTION_UI_ALLOWED 0x00000002 -#define POWER_ACTION_OVERRIDE_APPS 0x00000004 -#define POWER_ACTION_LIGHTEST_FIRST 0x10000000 -#define POWER_ACTION_LOCK_CONSOLE 0x20000000 -#define POWER_ACTION_DISABLE_WAKES 0x40000000 -#define POWER_ACTION_CRITICAL 0x80000000 - -#define POWER_LEVEL_USER_NOTIFY_TEXT 0x00000001 -#define POWER_LEVEL_USER_NOTIFY_SOUND 0x00000002 -#define POWER_LEVEL_USER_NOTIFY_EXEC 0x00000004 -#define POWER_USER_NOTIFY_BUTTON 0x00000008 -#define POWER_USER_NOTIFY_SHUTDOWN 0x00000010 -#define POWER_FORCE_TRIGGER_RESET 0x80000000 - - typedef struct { - BOOLEAN Enable; - BYTE Spare[3]; - DWORD BatteryLevel; - POWER_ACTION_POLICY PowerPolicy; - SYSTEM_POWER_STATE MinSystemState; - } SYSTEM_POWER_LEVEL,*PSYSTEM_POWER_LEVEL; - -#define NUM_DISCHARGE_POLICIES 4 -#define DISCHARGE_POLICY_CRITICAL 0 -#define DISCHARGE_POLICY_LOW 1 - -#define PO_THROTTLE_NONE 0 -#define PO_THROTTLE_CONSTANT 1 -#define PO_THROTTLE_DEGRADE 2 -#define PO_THROTTLE_ADAPTIVE 3 -#define PO_THROTTLE_MAXIMUM 4 - - typedef struct _SYSTEM_POWER_POLICY { - DWORD Revision; - POWER_ACTION_POLICY PowerButton; - POWER_ACTION_POLICY SleepButton; - POWER_ACTION_POLICY LidClose; - SYSTEM_POWER_STATE LidOpenWake; - DWORD Reserved; - POWER_ACTION_POLICY Idle; - DWORD IdleTimeout; - BYTE IdleSensitivity; - BYTE DynamicThrottle; - BYTE Spare2[2]; - SYSTEM_POWER_STATE MinSleep; - SYSTEM_POWER_STATE MaxSleep; - SYSTEM_POWER_STATE ReducedLatencySleep; - DWORD WinLogonFlags; - DWORD Spare3; - DWORD DozeS4Timeout; - DWORD BroadcastCapacityResolution; - SYSTEM_POWER_LEVEL DischargePolicy[NUM_DISCHARGE_POLICIES]; - DWORD VideoTimeout; - BOOLEAN VideoDimDisplay; - DWORD VideoReserved[3]; - DWORD SpindownTimeout; - BOOLEAN OptimizeForPower; - BYTE FanThrottleTolerance; - BYTE ForcedThrottle; - BYTE MinThrottle; - POWER_ACTION_POLICY OverThrottled; - } SYSTEM_POWER_POLICY,*PSYSTEM_POWER_POLICY; - - typedef struct _PROCESSOR_POWER_POLICY_INFO { - DWORD TimeCheck; - DWORD DemoteLimit; - DWORD PromoteLimit; - BYTE DemotePercent; - BYTE PromotePercent; - BYTE Spare[2]; - DWORD AllowDemotion:1; - DWORD AllowPromotion:1; - DWORD Reserved:30; - } PROCESSOR_POWER_POLICY_INFO,*PPROCESSOR_POWER_POLICY_INFO; - - typedef struct _PROCESSOR_POWER_POLICY { - DWORD Revision; - BYTE DynamicThrottle; - BYTE Spare[3]; - DWORD DisableCStates:1; - DWORD Reserved:31; - DWORD PolicyCount; - PROCESSOR_POWER_POLICY_INFO Policy[3]; - } PROCESSOR_POWER_POLICY,*PPROCESSOR_POWER_POLICY; - - typedef struct _ADMINISTRATOR_POWER_POLICY { - SYSTEM_POWER_STATE MinSleep; - SYSTEM_POWER_STATE MaxSleep; - DWORD MinVideoTimeout; - DWORD MaxVideoTimeout; - DWORD MinSpindownTimeout; - DWORD MaxSpindownTimeout; - } ADMINISTRATOR_POWER_POLICY,*PADMINISTRATOR_POWER_POLICY; - - typedef struct { - BOOLEAN PowerButtonPresent; - BOOLEAN SleepButtonPresent; - BOOLEAN LidPresent; - BOOLEAN SystemS1; - BOOLEAN SystemS2; - BOOLEAN SystemS3; - BOOLEAN SystemS4; - BOOLEAN SystemS5; - BOOLEAN HiberFilePresent; - BOOLEAN FullWake; - BOOLEAN VideoDimPresent; - BOOLEAN ApmPresent; - BOOLEAN UpsPresent; - BOOLEAN ThermalControl; - BOOLEAN ProcessorThrottle; - BYTE ProcessorMinThrottle; - BYTE ProcessorMaxThrottle; - BYTE spare2[4]; - BOOLEAN DiskSpinDown; - BYTE spare3[8]; - BOOLEAN SystemBatteriesPresent; - BOOLEAN BatteriesAreShortTerm; - BATTERY_REPORTING_SCALE BatteryScale[3]; - SYSTEM_POWER_STATE AcOnLineWake; - SYSTEM_POWER_STATE SoftLidWake; - SYSTEM_POWER_STATE RtcWake; - SYSTEM_POWER_STATE MinDeviceWakeState; - SYSTEM_POWER_STATE DefaultLowLatencyWake; - } SYSTEM_POWER_CAPABILITIES,*PSYSTEM_POWER_CAPABILITIES; - - typedef struct { - BOOLEAN AcOnLine; - BOOLEAN BatteryPresent; - BOOLEAN Charging; - BOOLEAN Discharging; - BOOLEAN Spare1[4]; - DWORD MaxCapacity; - DWORD RemainingCapacity; - DWORD Rate; - DWORD EstimatedTime; - DWORD DefaultAlert1; - DWORD DefaultAlert2; - } SYSTEM_BATTERY_STATE,*PSYSTEM_BATTERY_STATE; - -#include "pshpack4.h" - -#define IMAGE_DOS_SIGNATURE 0x5A4D -#define IMAGE_OS2_SIGNATURE 0x454E -#define IMAGE_OS2_SIGNATURE_LE 0x454C -#define IMAGE_VXD_SIGNATURE 0x454C -#define IMAGE_NT_SIGNATURE 0x00004550 - -#include "pshpack2.h" - - typedef struct _IMAGE_DOS_HEADER { - WORD e_magic; - WORD e_cblp; - WORD e_cp; - WORD e_crlc; - WORD e_cparhdr; - WORD e_minalloc; - WORD e_maxalloc; - WORD e_ss; - WORD e_sp; - WORD e_csum; - WORD e_ip; - WORD e_cs; - WORD e_lfarlc; - WORD e_ovno; - WORD e_res[4]; - WORD e_oemid; - WORD e_oeminfo; - WORD e_res2[10]; - LONG e_lfanew; - } IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER; - - typedef struct _IMAGE_OS2_HEADER { - WORD ne_magic; - CHAR ne_ver; - CHAR ne_rev; - WORD ne_enttab; - WORD ne_cbenttab; - LONG ne_crc; - WORD ne_flags; - WORD ne_autodata; - WORD ne_heap; - WORD ne_stack; - LONG ne_csip; - LONG ne_sssp; - WORD ne_cseg; - WORD ne_cmod; - WORD ne_cbnrestab; - WORD ne_segtab; - WORD ne_rsrctab; - WORD ne_restab; - WORD ne_modtab; - WORD ne_imptab; - LONG ne_nrestab; - WORD ne_cmovent; - WORD ne_align; - WORD ne_cres; - BYTE ne_exetyp; - BYTE ne_flagsothers; - WORD ne_pretthunks; - WORD ne_psegrefbytes; - WORD ne_swaparea; - WORD ne_expver; - } IMAGE_OS2_HEADER,*PIMAGE_OS2_HEADER; - - typedef struct _IMAGE_VXD_HEADER { - WORD e32_magic; - BYTE e32_border; - BYTE e32_worder; - DWORD e32_level; - WORD e32_cpu; - WORD e32_os; - DWORD e32_ver; - DWORD e32_mflags; - DWORD e32_mpages; - DWORD e32_startobj; - DWORD e32_eip; - DWORD e32_stackobj; - DWORD e32_esp; - DWORD e32_pagesize; - DWORD e32_lastpagesize; - DWORD e32_fixupsize; - DWORD e32_fixupsum; - DWORD e32_ldrsize; - DWORD e32_ldrsum; - DWORD e32_objtab; - DWORD e32_objcnt; - DWORD e32_objmap; - DWORD e32_itermap; - DWORD e32_rsrctab; - DWORD e32_rsrccnt; - DWORD e32_restab; - DWORD e32_enttab; - DWORD e32_dirtab; - DWORD e32_dircnt; - DWORD e32_fpagetab; - DWORD e32_frectab; - DWORD e32_impmod; - DWORD e32_impmodcnt; - DWORD e32_impproc; - DWORD e32_pagesum; - DWORD e32_datapage; - DWORD e32_preload; - DWORD e32_nrestab; - DWORD e32_cbnrestab; - DWORD e32_nressum; - DWORD e32_autodata; - DWORD e32_debuginfo; - DWORD e32_debuglen; - DWORD e32_instpreload; - DWORD e32_instdemand; - DWORD e32_heapsize; - BYTE e32_res3[12]; - DWORD e32_winresoff; - DWORD e32_winreslen; - WORD e32_devid; - WORD e32_ddkver; - } IMAGE_VXD_HEADER,*PIMAGE_VXD_HEADER; - -#include "poppack.h" - - typedef struct _IMAGE_FILE_HEADER { - WORD Machine; - WORD NumberOfSections; - DWORD TimeDateStamp; - DWORD PointerToSymbolTable; - DWORD NumberOfSymbols; - WORD SizeOfOptionalHeader; - WORD Characteristics; - } IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER; - -#define IMAGE_SIZEOF_FILE_HEADER 20 - -#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 -#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 -#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 -#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 -#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 -#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 -#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 -#define IMAGE_FILE_32BIT_MACHINE 0x0100 -#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 -#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 -#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 -#define IMAGE_FILE_SYSTEM 0x1000 -#define IMAGE_FILE_DLL 0x2000 -#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 -#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 - -#define IMAGE_FILE_MACHINE_UNKNOWN 0 -#define IMAGE_FILE_MACHINE_I386 0x014c -#define IMAGE_FILE_MACHINE_R3000 0x0162 -#define IMAGE_FILE_MACHINE_R4000 0x0166 -#define IMAGE_FILE_MACHINE_R10000 0x0168 -#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 -#define IMAGE_FILE_MACHINE_ALPHA 0x0184 -#define IMAGE_FILE_MACHINE_SH3 0x01a2 -#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 -#define IMAGE_FILE_MACHINE_SH3E 0x01a4 -#define IMAGE_FILE_MACHINE_SH4 0x01a6 -#define IMAGE_FILE_MACHINE_SH5 0x01a8 -#define IMAGE_FILE_MACHINE_ARM 0x01c0 -#define IMAGE_FILE_MACHINE_THUMB 0x01c2 -#define IMAGE_FILE_MACHINE_AM33 0x01d3 -#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 -#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 -#define IMAGE_FILE_MACHINE_IA64 0x0200 -#define IMAGE_FILE_MACHINE_MIPS16 0x0266 -#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 -#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 -#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 -#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 -#define IMAGE_FILE_MACHINE_TRICORE 0x0520 -#define IMAGE_FILE_MACHINE_CEF 0x0CEF -#define IMAGE_FILE_MACHINE_EBC 0x0EBC -#define IMAGE_FILE_MACHINE_AMD64 0x8664 -#define IMAGE_FILE_MACHINE_M32R 0x9041 -#define IMAGE_FILE_MACHINE_CEE 0xC0EE - - typedef struct _IMAGE_DATA_DIRECTORY { - DWORD VirtualAddress; - DWORD Size; - } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY; - -#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 - - typedef struct _IMAGE_OPTIONAL_HEADER { - - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; - DWORD BaseOfData; - DWORD ImageBase; - DWORD SectionAlignment; - DWORD FileAlignment; - WORD MajorOperatingSystemVersion; - WORD MinorOperatingSystemVersion; - WORD MajorImageVersion; - WORD MinorImageVersion; - WORD MajorSubsystemVersion; - WORD MinorSubsystemVersion; - DWORD Win32VersionValue; - DWORD SizeOfImage; - DWORD SizeOfHeaders; - DWORD CheckSum; - WORD Subsystem; - WORD DllCharacteristics; - DWORD SizeOfStackReserve; - DWORD SizeOfStackCommit; - DWORD SizeOfHeapReserve; - DWORD SizeOfHeapCommit; - DWORD LoaderFlags; - DWORD NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - } IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32; - - typedef struct _IMAGE_ROM_OPTIONAL_HEADER { - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; - DWORD BaseOfData; - DWORD BaseOfBss; - DWORD GprMask; - DWORD CprMask[4]; - DWORD GpValue; - } IMAGE_ROM_OPTIONAL_HEADER,*PIMAGE_ROM_OPTIONAL_HEADER; - - typedef struct _IMAGE_OPTIONAL_HEADER64 { - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; - ULONGLONG ImageBase; - DWORD SectionAlignment; - DWORD FileAlignment; - WORD MajorOperatingSystemVersion; - WORD MinorOperatingSystemVersion; - WORD MajorImageVersion; - WORD MinorImageVersion; - WORD MajorSubsystemVersion; - WORD MinorSubsystemVersion; - DWORD Win32VersionValue; - DWORD SizeOfImage; - DWORD SizeOfHeaders; - DWORD CheckSum; - WORD Subsystem; - WORD DllCharacteristics; - ULONGLONG SizeOfStackReserve; - ULONGLONG SizeOfStackCommit; - ULONGLONG SizeOfHeapReserve; - ULONGLONG SizeOfHeapCommit; - DWORD LoaderFlags; - DWORD NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - } IMAGE_OPTIONAL_HEADER64,*PIMAGE_OPTIONAL_HEADER64; - -#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 -#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 -#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224 -#define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240 - -#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b -#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b -#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 - -#ifdef _WIN64 - typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; - typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; -#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL64_HEADER -#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC -#else - typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; - typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; -#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL32_HEADER -#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC -#endif - - typedef struct _IMAGE_NT_HEADERS64 { - DWORD Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER64 OptionalHeader; - } IMAGE_NT_HEADERS64,*PIMAGE_NT_HEADERS64; - - typedef struct _IMAGE_NT_HEADERS { - DWORD Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER32 OptionalHeader; - } IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32; - - typedef struct _IMAGE_ROM_HEADERS { - IMAGE_FILE_HEADER FileHeader; - IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; - } IMAGE_ROM_HEADERS,*PIMAGE_ROM_HEADERS; - -#ifdef _WIN64 - typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; - typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; -#else - typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; - typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; -#endif - -#define IMAGE_FIRST_SECTION(ntheader) ((PIMAGE_SECTION_HEADER) ((ULONG_PTR)ntheader + FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader) + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) - -#define IMAGE_SUBSYSTEM_UNKNOWN 0 -#define IMAGE_SUBSYSTEM_NATIVE 1 -#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 -#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 -#define IMAGE_SUBSYSTEM_OS2_CUI 5 -#define IMAGE_SUBSYSTEM_POSIX_CUI 7 -#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 -#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 -#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 -#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 -#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 -#define IMAGE_SUBSYSTEM_EFI_ROM 13 -#define IMAGE_SUBSYSTEM_XBOX 14 - -#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 -#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 -#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 -#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 -#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 - -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 - -#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 -#define IMAGE_DIRECTORY_ENTRY_TLS 9 -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 -#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 -#define IMAGE_DIRECTORY_ENTRY_IAT 12 -#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 -#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 - - typedef struct ANON_OBJECT_HEADER { - WORD Sig1; - WORD Sig2; - WORD Version; - WORD Machine; - DWORD TimeDateStamp; - CLSID ClassID; - DWORD SizeOfData; - } ANON_OBJECT_HEADER; - -#define IMAGE_SIZEOF_SHORT_NAME 8 - - typedef struct _IMAGE_SECTION_HEADER { - BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; - union { - DWORD PhysicalAddress; - DWORD VirtualSize; - } Misc; - DWORD VirtualAddress; - DWORD SizeOfRawData; - DWORD PointerToRawData; - DWORD PointerToRelocations; - DWORD PointerToLinenumbers; - WORD NumberOfRelocations; - WORD NumberOfLinenumbers; - DWORD Characteristics; - } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER; - -#define IMAGE_SIZEOF_SECTION_HEADER 40 - -#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 - -#define IMAGE_SCN_CNT_CODE 0x00000020 -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 -#define IMAGE_SCN_LNK_OTHER 0x00000100 -#define IMAGE_SCN_LNK_INFO 0x00000200 -#define IMAGE_SCN_LNK_REMOVE 0x00000800 -#define IMAGE_SCN_LNK_COMDAT 0x00001000 -#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 -#define IMAGE_SCN_GPREL 0x00008000 -#define IMAGE_SCN_MEM_FARDATA 0x00008000 -#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 -#define IMAGE_SCN_MEM_16BIT 0x00020000 -#define IMAGE_SCN_MEM_LOCKED 0x00040000 -#define IMAGE_SCN_MEM_PRELOAD 0x00080000 - -#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 -#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 -#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 -#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 -#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 -#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 -#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 -#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 -#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 -#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 -#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 -#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 -#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 -#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 - -#define IMAGE_SCN_ALIGN_MASK 0x00F00000 - -#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 -#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 -#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 -#define IMAGE_SCN_MEM_SHARED 0x10000000 -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 -#define IMAGE_SCN_MEM_READ 0x40000000 -#define IMAGE_SCN_MEM_WRITE 0x80000000 - -#define IMAGE_SCN_SCALE_INDEX 0x00000001 - -#include "pshpack2.h" - - typedef struct _IMAGE_SYMBOL { - union { - BYTE ShortName[8]; - struct { - DWORD Short; - DWORD Long; - } Name; - DWORD LongName[2]; - } N; - DWORD Value; - SHORT SectionNumber; - WORD Type; - BYTE StorageClass; - BYTE NumberOfAuxSymbols; - } IMAGE_SYMBOL; - typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL; - -#define IMAGE_SIZEOF_SYMBOL 18 - -#define IMAGE_SYM_UNDEFINED (SHORT)0 -#define IMAGE_SYM_ABSOLUTE (SHORT)-1 -#define IMAGE_SYM_DEBUG (SHORT)-2 -#define IMAGE_SYM_SECTION_MAX 0xFEFF - -#define IMAGE_SYM_TYPE_NULL 0x0000 -#define IMAGE_SYM_TYPE_VOID 0x0001 -#define IMAGE_SYM_TYPE_CHAR 0x0002 -#define IMAGE_SYM_TYPE_SHORT 0x0003 -#define IMAGE_SYM_TYPE_INT 0x0004 -#define IMAGE_SYM_TYPE_LONG 0x0005 -#define IMAGE_SYM_TYPE_FLOAT 0x0006 -#define IMAGE_SYM_TYPE_DOUBLE 0x0007 -#define IMAGE_SYM_TYPE_STRUCT 0x0008 -#define IMAGE_SYM_TYPE_UNION 0x0009 -#define IMAGE_SYM_TYPE_ENUM 0x000A -#define IMAGE_SYM_TYPE_MOE 0x000B -#define IMAGE_SYM_TYPE_BYTE 0x000C -#define IMAGE_SYM_TYPE_WORD 0x000D -#define IMAGE_SYM_TYPE_UINT 0x000E -#define IMAGE_SYM_TYPE_DWORD 0x000F -#define IMAGE_SYM_TYPE_PCODE 0x8000 - -#define IMAGE_SYM_DTYPE_NULL 0 -#define IMAGE_SYM_DTYPE_POINTER 1 -#define IMAGE_SYM_DTYPE_FUNCTION 2 -#define IMAGE_SYM_DTYPE_ARRAY 3 - -#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE)-1 -#define IMAGE_SYM_CLASS_NULL 0x0000 -#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 -#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 -#define IMAGE_SYM_CLASS_STATIC 0x0003 -#define IMAGE_SYM_CLASS_REGISTER 0x0004 -#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 -#define IMAGE_SYM_CLASS_LABEL 0x0006 -#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 -#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 -#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 -#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A -#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B -#define IMAGE_SYM_CLASS_UNION_TAG 0x000C -#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D -#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E -#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F -#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 -#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 -#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 -#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 -#define IMAGE_SYM_CLASS_BLOCK 0x0064 -#define IMAGE_SYM_CLASS_FUNCTION 0x0065 -#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 -#define IMAGE_SYM_CLASS_FILE 0x0067 -#define IMAGE_SYM_CLASS_SECTION 0x0068 -#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 -#define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B - -#define N_BTMASK 0x000F -#define N_TMASK 0x0030 -#define N_TMASK1 0x00C0 -#define N_TMASK2 0x00F0 -#define N_BTSHFT 4 -#define N_TSHIFT 2 - -#define BTYPE(x) ((x) & N_BTMASK) - -#ifndef ISPTR -#define ISPTR(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) -#endif - -#ifndef ISFCN -#define ISFCN(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) -#endif - -#ifndef ISARY -#define ISARY(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) -#endif - -#ifndef ISTAG -#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) -#endif - -#ifndef INCREF -#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) -#endif - - typedef union _IMAGE_AUX_SYMBOL { - struct { - DWORD TagIndex; - union { - struct { - WORD Linenumber; - WORD Size; - } LnSz; - DWORD TotalSize; - } Misc; - union { - struct { - DWORD PointerToLinenumber; - DWORD PointerToNextFunction; - } Function; - struct { - WORD Dimension[4]; - } Array; - } FcnAry; - WORD TvIndex; - } Sym; - struct { - BYTE Name[IMAGE_SIZEOF_SYMBOL]; - } File; - struct { - DWORD Length; - WORD NumberOfRelocations; - WORD NumberOfLinenumbers; - DWORD CheckSum; - SHORT Number; - BYTE Selection; - } Section; - } IMAGE_AUX_SYMBOL; - typedef IMAGE_AUX_SYMBOL UNALIGNED *PIMAGE_AUX_SYMBOL; - -#define IMAGE_SIZEOF_AUX_SYMBOL 18 - - typedef enum IMAGE_AUX_SYMBOL_TYPE { - IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF = 1 - } IMAGE_AUX_SYMBOL_TYPE; - -#include - - typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF { - BYTE bAuxType; - BYTE bReserved; - DWORD SymbolTableIndex; - BYTE rgbReserved[12]; - } IMAGE_AUX_SYMBOL_TOKEN_DEF; - - typedef IMAGE_AUX_SYMBOL_TOKEN_DEF UNALIGNED *PIMAGE_AUX_SYMBOL_TOKEN_DEF; - -#include - -#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 -#define IMAGE_COMDAT_SELECT_ANY 2 -#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 -#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 -#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 -#define IMAGE_COMDAT_SELECT_LARGEST 6 -#define IMAGE_COMDAT_SELECT_NEWEST 7 - -#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 -#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 -#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 - - typedef struct _IMAGE_RELOCATION { - union { - DWORD VirtualAddress; - DWORD RelocCount; - }; - DWORD SymbolTableIndex; - WORD Type; - } IMAGE_RELOCATION; - typedef IMAGE_RELOCATION UNALIGNED *PIMAGE_RELOCATION; - -#define IMAGE_SIZEOF_RELOCATION 10 - -#define IMAGE_REL_I386_ABSOLUTE 0x0000 -#define IMAGE_REL_I386_DIR16 0x0001 -#define IMAGE_REL_I386_REL16 0x0002 -#define IMAGE_REL_I386_DIR32 0x0006 -#define IMAGE_REL_I386_DIR32NB 0x0007 -#define IMAGE_REL_I386_SEG12 0x0009 -#define IMAGE_REL_I386_SECTION 0x000A -#define IMAGE_REL_I386_SECREL 0x000B -#define IMAGE_REL_I386_TOKEN 0x000C -#define IMAGE_REL_I386_SECREL7 0x000D -#define IMAGE_REL_I386_REL32 0x0014 - -#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 -#define IMAGE_REL_MIPS_REFHALF 0x0001 -#define IMAGE_REL_MIPS_REFWORD 0x0002 -#define IMAGE_REL_MIPS_JMPADDR 0x0003 -#define IMAGE_REL_MIPS_REFHI 0x0004 -#define IMAGE_REL_MIPS_REFLO 0x0005 -#define IMAGE_REL_MIPS_GPREL 0x0006 -#define IMAGE_REL_MIPS_LITERAL 0x0007 -#define IMAGE_REL_MIPS_SECTION 0x000A -#define IMAGE_REL_MIPS_SECREL 0x000B -#define IMAGE_REL_MIPS_SECRELLO 0x000C -#define IMAGE_REL_MIPS_SECRELHI 0x000D -#define IMAGE_REL_MIPS_TOKEN 0x000E -#define IMAGE_REL_MIPS_JMPADDR16 0x0010 -#define IMAGE_REL_MIPS_REFWORDNB 0x0022 -#define IMAGE_REL_MIPS_PAIR 0x0025 - -#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 -#define IMAGE_REL_ALPHA_REFLONG 0x0001 -#define IMAGE_REL_ALPHA_REFQUAD 0x0002 -#define IMAGE_REL_ALPHA_GPREL32 0x0003 -#define IMAGE_REL_ALPHA_LITERAL 0x0004 -#define IMAGE_REL_ALPHA_LITUSE 0x0005 -#define IMAGE_REL_ALPHA_GPDISP 0x0006 -#define IMAGE_REL_ALPHA_BRADDR 0x0007 -#define IMAGE_REL_ALPHA_HINT 0x0008 -#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 -#define IMAGE_REL_ALPHA_REFHI 0x000A -#define IMAGE_REL_ALPHA_REFLO 0x000B -#define IMAGE_REL_ALPHA_PAIR 0x000C -#define IMAGE_REL_ALPHA_MATCH 0x000D -#define IMAGE_REL_ALPHA_SECTION 0x000E -#define IMAGE_REL_ALPHA_SECREL 0x000F -#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 -#define IMAGE_REL_ALPHA_SECRELLO 0x0011 -#define IMAGE_REL_ALPHA_SECRELHI 0x0012 -#define IMAGE_REL_ALPHA_REFQ3 0x0013 -#define IMAGE_REL_ALPHA_REFQ2 0x0014 -#define IMAGE_REL_ALPHA_REFQ1 0x0015 -#define IMAGE_REL_ALPHA_GPRELLO 0x0016 -#define IMAGE_REL_ALPHA_GPRELHI 0x0017 - -#define IMAGE_REL_PPC_ABSOLUTE 0x0000 -#define IMAGE_REL_PPC_ADDR64 0x0001 -#define IMAGE_REL_PPC_ADDR32 0x0002 -#define IMAGE_REL_PPC_ADDR24 0x0003 -#define IMAGE_REL_PPC_ADDR16 0x0004 -#define IMAGE_REL_PPC_ADDR14 0x0005 -#define IMAGE_REL_PPC_REL24 0x0006 -#define IMAGE_REL_PPC_REL14 0x0007 -#define IMAGE_REL_PPC_TOCREL16 0x0008 -#define IMAGE_REL_PPC_TOCREL14 0x0009 -#define IMAGE_REL_PPC_ADDR32NB 0x000A -#define IMAGE_REL_PPC_SECREL 0x000B -#define IMAGE_REL_PPC_SECTION 0x000C -#define IMAGE_REL_PPC_IFGLUE 0x000D -#define IMAGE_REL_PPC_IMGLUE 0x000E -#define IMAGE_REL_PPC_SECREL16 0x000F -#define IMAGE_REL_PPC_REFHI 0x0010 -#define IMAGE_REL_PPC_REFLO 0x0011 -#define IMAGE_REL_PPC_PAIR 0x0012 -#define IMAGE_REL_PPC_SECRELLO 0x0013 -#define IMAGE_REL_PPC_SECRELHI 0x0014 -#define IMAGE_REL_PPC_GPREL 0x0015 -#define IMAGE_REL_PPC_TOKEN 0x0016 -#define IMAGE_REL_PPC_TYPEMASK 0x00FF -#define IMAGE_REL_PPC_NEG 0x0100 -#define IMAGE_REL_PPC_BRTAKEN 0x0200 -#define IMAGE_REL_PPC_BRNTAKEN 0x0400 -#define IMAGE_REL_PPC_TOCDEFN 0x0800 - -#define IMAGE_REL_SH3_ABSOLUTE 0x0000 -#define IMAGE_REL_SH3_DIRECT16 0x0001 -#define IMAGE_REL_SH3_DIRECT32 0x0002 -#define IMAGE_REL_SH3_DIRECT8 0x0003 -#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 -#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 -#define IMAGE_REL_SH3_DIRECT4 0x0006 -#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 -#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 -#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 -#define IMAGE_REL_SH3_PCREL8_LONG 0x000A -#define IMAGE_REL_SH3_PCREL12_WORD 0x000B -#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C -#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D -#define IMAGE_REL_SH3_SECTION 0x000E -#define IMAGE_REL_SH3_SECREL 0x000F -#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 -#define IMAGE_REL_SH3_GPREL4_LONG 0x0011 -#define IMAGE_REL_SH3_TOKEN 0x0012 - -#define IMAGE_REL_SHM_PCRELPT 0x0013 -#define IMAGE_REL_SHM_REFLO 0x0014 -#define IMAGE_REL_SHM_REFHALF 0x0015 -#define IMAGE_REL_SHM_RELLO 0x0016 -#define IMAGE_REL_SHM_RELHALF 0x0017 -#define IMAGE_REL_SHM_PAIR 0x0018 - -#define IMAGE_REL_SH_NOMODE 0x8000 - -#define IMAGE_REL_ARM_ABSOLUTE 0x0000 -#define IMAGE_REL_ARM_ADDR32 0x0001 -#define IMAGE_REL_ARM_ADDR32NB 0x0002 -#define IMAGE_REL_ARM_BRANCH24 0x0003 -#define IMAGE_REL_ARM_BRANCH11 0x0004 -#define IMAGE_REL_ARM_TOKEN 0x0005 -#define IMAGE_REL_ARM_GPREL12 0x0006 -#define IMAGE_REL_ARM_GPREL7 0x0007 -#define IMAGE_REL_ARM_BLX24 0x0008 -#define IMAGE_REL_ARM_BLX11 0x0009 -#define IMAGE_REL_ARM_SECTION 0x000E -#define IMAGE_REL_ARM_SECREL 0x000F - -#define IMAGE_REL_AM_ABSOLUTE 0x0000 -#define IMAGE_REL_AM_ADDR32 0x0001 -#define IMAGE_REL_AM_ADDR32NB 0x0002 -#define IMAGE_REL_AM_CALL32 0x0003 -#define IMAGE_REL_AM_FUNCINFO 0x0004 -#define IMAGE_REL_AM_REL32_1 0x0005 -#define IMAGE_REL_AM_REL32_2 0x0006 -#define IMAGE_REL_AM_SECREL 0x0007 -#define IMAGE_REL_AM_SECTION 0x0008 -#define IMAGE_REL_AM_TOKEN 0x0009 - -#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 -#define IMAGE_REL_AMD64_ADDR64 0x0001 -#define IMAGE_REL_AMD64_ADDR32 0x0002 -#define IMAGE_REL_AMD64_ADDR32NB 0x0003 -#define IMAGE_REL_AMD64_REL32 0x0004 -#define IMAGE_REL_AMD64_REL32_1 0x0005 -#define IMAGE_REL_AMD64_REL32_2 0x0006 -#define IMAGE_REL_AMD64_REL32_3 0x0007 -#define IMAGE_REL_AMD64_REL32_4 0x0008 -#define IMAGE_REL_AMD64_REL32_5 0x0009 -#define IMAGE_REL_AMD64_SECTION 0x000A -#define IMAGE_REL_AMD64_SECREL 0x000B -#define IMAGE_REL_AMD64_SECREL7 0x000C -#define IMAGE_REL_AMD64_TOKEN 0x000D -#define IMAGE_REL_AMD64_SREL32 0x000E -#define IMAGE_REL_AMD64_PAIR 0x000F -#define IMAGE_REL_AMD64_SSPAN32 0x0010 - -#define IMAGE_REL_IA64_ABSOLUTE 0x0000 -#define IMAGE_REL_IA64_IMM14 0x0001 -#define IMAGE_REL_IA64_IMM22 0x0002 -#define IMAGE_REL_IA64_IMM64 0x0003 -#define IMAGE_REL_IA64_DIR32 0x0004 -#define IMAGE_REL_IA64_DIR64 0x0005 -#define IMAGE_REL_IA64_PCREL21B 0x0006 -#define IMAGE_REL_IA64_PCREL21M 0x0007 -#define IMAGE_REL_IA64_PCREL21F 0x0008 -#define IMAGE_REL_IA64_GPREL22 0x0009 -#define IMAGE_REL_IA64_LTOFF22 0x000A -#define IMAGE_REL_IA64_SECTION 0x000B -#define IMAGE_REL_IA64_SECREL22 0x000C -#define IMAGE_REL_IA64_SECREL64I 0x000D -#define IMAGE_REL_IA64_SECREL32 0x000E - -#define IMAGE_REL_IA64_DIR32NB 0x0010 -#define IMAGE_REL_IA64_SREL14 0x0011 -#define IMAGE_REL_IA64_SREL22 0x0012 -#define IMAGE_REL_IA64_SREL32 0x0013 -#define IMAGE_REL_IA64_UREL32 0x0014 -#define IMAGE_REL_IA64_PCREL60X 0x0015 -#define IMAGE_REL_IA64_PCREL60B 0x0016 -#define IMAGE_REL_IA64_PCREL60F 0x0017 -#define IMAGE_REL_IA64_PCREL60I 0x0018 -#define IMAGE_REL_IA64_PCREL60M 0x0019 -#define IMAGE_REL_IA64_IMMGPREL64 0x001A -#define IMAGE_REL_IA64_TOKEN 0x001B -#define IMAGE_REL_IA64_GPREL32 0x001C -#define IMAGE_REL_IA64_ADDEND 0x001F - -#define IMAGE_REL_CEF_ABSOLUTE 0x0000 -#define IMAGE_REL_CEF_ADDR32 0x0001 -#define IMAGE_REL_CEF_ADDR64 0x0002 -#define IMAGE_REL_CEF_ADDR32NB 0x0003 -#define IMAGE_REL_CEF_SECTION 0x0004 -#define IMAGE_REL_CEF_SECREL 0x0005 -#define IMAGE_REL_CEF_TOKEN 0x0006 - -#define IMAGE_REL_CEE_ABSOLUTE 0x0000 -#define IMAGE_REL_CEE_ADDR32 0x0001 -#define IMAGE_REL_CEE_ADDR64 0x0002 -#define IMAGE_REL_CEE_ADDR32NB 0x0003 -#define IMAGE_REL_CEE_SECTION 0x0004 -#define IMAGE_REL_CEE_SECREL 0x0005 -#define IMAGE_REL_CEE_TOKEN 0x0006 - -#define IMAGE_REL_M32R_ABSOLUTE 0x0000 -#define IMAGE_REL_M32R_ADDR32 0x0001 -#define IMAGE_REL_M32R_ADDR32NB 0x0002 -#define IMAGE_REL_M32R_ADDR24 0x0003 -#define IMAGE_REL_M32R_GPREL16 0x0004 -#define IMAGE_REL_M32R_PCREL24 0x0005 -#define IMAGE_REL_M32R_PCREL16 0x0006 -#define IMAGE_REL_M32R_PCREL8 0x0007 -#define IMAGE_REL_M32R_REFHALF 0x0008 -#define IMAGE_REL_M32R_REFHI 0x0009 -#define IMAGE_REL_M32R_REFLO 0x000A -#define IMAGE_REL_M32R_PAIR 0x000B -#define IMAGE_REL_M32R_SECTION 0x000C -#define IMAGE_REL_M32R_SECREL32 0x000D -#define IMAGE_REL_M32R_TOKEN 0x000E - -#define EXT_IMM64(Value,Address,Size,InstPos,ValPos) Value |= (((ULONGLONG)((*(Address) >> InstPos) & (((ULONGLONG)1 << Size) - 1))) << ValPos) -#define INS_IMM64(Value,Address,Size,InstPos,ValPos) *(PDWORD)Address = (*(PDWORD)Address & ~(((1 << Size) - 1) << InstPos)) | ((DWORD)((((ULONGLONG)Value >> ValPos) & (((ULONGLONG)1 << Size) - 1))) << InstPos) - -#define EMARCH_ENC_I17_IMM7B_INST_WORD_X 3 -#define EMARCH_ENC_I17_IMM7B_SIZE_X 7 -#define EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X 4 -#define EMARCH_ENC_I17_IMM7B_VAL_POS_X 0 - -#define EMARCH_ENC_I17_IMM9D_INST_WORD_X 3 -#define EMARCH_ENC_I17_IMM9D_SIZE_X 9 -#define EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X 18 -#define EMARCH_ENC_I17_IMM9D_VAL_POS_X 7 - -#define EMARCH_ENC_I17_IMM5C_INST_WORD_X 3 -#define EMARCH_ENC_I17_IMM5C_SIZE_X 5 -#define EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X 13 -#define EMARCH_ENC_I17_IMM5C_VAL_POS_X 16 - -#define EMARCH_ENC_I17_IC_INST_WORD_X 3 -#define EMARCH_ENC_I17_IC_SIZE_X 1 -#define EMARCH_ENC_I17_IC_INST_WORD_POS_X 12 -#define EMARCH_ENC_I17_IC_VAL_POS_X 21 - -#define EMARCH_ENC_I17_IMM41a_INST_WORD_X 1 -#define EMARCH_ENC_I17_IMM41a_SIZE_X 10 -#define EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X 14 -#define EMARCH_ENC_I17_IMM41a_VAL_POS_X 22 - -#define EMARCH_ENC_I17_IMM41b_INST_WORD_X 1 -#define EMARCH_ENC_I17_IMM41b_SIZE_X 8 -#define EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X 24 -#define EMARCH_ENC_I17_IMM41b_VAL_POS_X 32 - -#define EMARCH_ENC_I17_IMM41c_INST_WORD_X 2 -#define EMARCH_ENC_I17_IMM41c_SIZE_X 23 -#define EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X 0 -#define EMARCH_ENC_I17_IMM41c_VAL_POS_X 40 - -#define EMARCH_ENC_I17_SIGN_INST_WORD_X 3 -#define EMARCH_ENC_I17_SIGN_SIZE_X 1 -#define EMARCH_ENC_I17_SIGN_INST_WORD_POS_X 27 -#define EMARCH_ENC_I17_SIGN_VAL_POS_X 63 - -#define X3_OPCODE_INST_WORD_X 3 -#define X3_OPCODE_SIZE_X 4 -#define X3_OPCODE_INST_WORD_POS_X 28 -#define X3_OPCODE_SIGN_VAL_POS_X 0 - -#define X3_I_INST_WORD_X 3 -#define X3_I_SIZE_X 1 -#define X3_I_INST_WORD_POS_X 27 -#define X3_I_SIGN_VAL_POS_X 59 - -#define X3_D_WH_INST_WORD_X 3 -#define X3_D_WH_SIZE_X 3 -#define X3_D_WH_INST_WORD_POS_X 24 -#define X3_D_WH_SIGN_VAL_POS_X 0 - -#define X3_IMM20_INST_WORD_X 3 -#define X3_IMM20_SIZE_X 20 -#define X3_IMM20_INST_WORD_POS_X 4 -#define X3_IMM20_SIGN_VAL_POS_X 0 - -#define X3_IMM39_1_INST_WORD_X 2 -#define X3_IMM39_1_SIZE_X 23 -#define X3_IMM39_1_INST_WORD_POS_X 0 -#define X3_IMM39_1_SIGN_VAL_POS_X 36 - -#define X3_IMM39_2_INST_WORD_X 1 -#define X3_IMM39_2_SIZE_X 16 -#define X3_IMM39_2_INST_WORD_POS_X 16 -#define X3_IMM39_2_SIGN_VAL_POS_X 20 - -#define X3_P_INST_WORD_X 3 -#define X3_P_SIZE_X 4 -#define X3_P_INST_WORD_POS_X 0 -#define X3_P_SIGN_VAL_POS_X 0 - -#define X3_TMPLT_INST_WORD_X 0 -#define X3_TMPLT_SIZE_X 4 -#define X3_TMPLT_INST_WORD_POS_X 0 -#define X3_TMPLT_SIGN_VAL_POS_X 0 - -#define X3_BTYPE_QP_INST_WORD_X 2 -#define X3_BTYPE_QP_SIZE_X 9 -#define X3_BTYPE_QP_INST_WORD_POS_X 23 -#define X3_BTYPE_QP_INST_VAL_POS_X 0 - -#define X3_EMPTY_INST_WORD_X 1 -#define X3_EMPTY_SIZE_X 2 -#define X3_EMPTY_INST_WORD_POS_X 14 -#define X3_EMPTY_INST_VAL_POS_X 0 - - typedef struct _IMAGE_LINENUMBER { - union { - DWORD SymbolTableIndex; - DWORD VirtualAddress; - } Type; - WORD Linenumber; - } IMAGE_LINENUMBER; - typedef IMAGE_LINENUMBER UNALIGNED *PIMAGE_LINENUMBER; - -#define IMAGE_SIZEOF_LINENUMBER 6 - -#include "poppack.h" - - typedef struct _IMAGE_BASE_RELOCATION { - DWORD VirtualAddress; - DWORD SizeOfBlock; - - } IMAGE_BASE_RELOCATION; - typedef IMAGE_BASE_RELOCATION UNALIGNED *PIMAGE_BASE_RELOCATION; - -#define IMAGE_SIZEOF_BASE_RELOCATION 8 - -#define IMAGE_REL_BASED_ABSOLUTE 0 -#define IMAGE_REL_BASED_HIGH 1 -#define IMAGE_REL_BASED_LOW 2 -#define IMAGE_REL_BASED_HIGHLOW 3 -#define IMAGE_REL_BASED_HIGHADJ 4 -#define IMAGE_REL_BASED_MIPS_JMPADDR 5 -#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 -#define IMAGE_REL_BASED_IA64_IMM64 9 -#define IMAGE_REL_BASED_DIR64 10 - -#define IMAGE_ARCHIVE_START_SIZE 8 -#define IMAGE_ARCHIVE_START "!\n" -#define IMAGE_ARCHIVE_END "`\n" -#define IMAGE_ARCHIVE_PAD "\n" -#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " -#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " - - typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { - BYTE Name[16]; - BYTE Date[12]; - BYTE UserID[6]; - BYTE GroupID[6]; - BYTE Mode[8]; - BYTE Size[10]; - BYTE EndHeader[2]; - } IMAGE_ARCHIVE_MEMBER_HEADER,*PIMAGE_ARCHIVE_MEMBER_HEADER; - -#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 - - typedef struct _IMAGE_EXPORT_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD Name; - DWORD Base; - DWORD NumberOfFunctions; - DWORD NumberOfNames; - DWORD AddressOfFunctions; - DWORD AddressOfNames; - DWORD AddressOfNameOrdinals; - } IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; - - typedef struct _IMAGE_IMPORT_BY_NAME { - WORD Hint; - BYTE Name[1]; - } IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; - -#include "pshpack8.h" - - typedef struct _IMAGE_THUNK_DATA64 { - union { - ULONGLONG ForwarderString; - ULONGLONG Function; - ULONGLONG Ordinal; - ULONGLONG AddressOfData; - } u1; - } IMAGE_THUNK_DATA64; - typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; - -#include "poppack.h" - - typedef struct _IMAGE_THUNK_DATA32 { - union { - DWORD ForwarderString; - DWORD Function; - DWORD Ordinal; - DWORD AddressOfData; - } u1; - } IMAGE_THUNK_DATA32; - typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; - -#define IMAGE_ORDINAL_FLAG64 0x8000000000000000ull -#define IMAGE_ORDINAL_FLAG32 0x80000000 -#define IMAGE_ORDINAL64(Ordinal) (Ordinal & 0xffffull) -#define IMAGE_ORDINAL32(Ordinal) (Ordinal & 0xffff) -#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64)!=0) -#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32)!=0) - - typedef VOID - (NTAPI *PIMAGE_TLS_CALLBACK)(PVOID DllHandle,DWORD Reason,PVOID Reserved); - - typedef struct _IMAGE_TLS_DIRECTORY64 { - ULONGLONG StartAddressOfRawData; - ULONGLONG EndAddressOfRawData; - ULONGLONG AddressOfIndex; - ULONGLONG AddressOfCallBacks; - DWORD SizeOfZeroFill; - DWORD Characteristics; - } IMAGE_TLS_DIRECTORY64; - typedef IMAGE_TLS_DIRECTORY64 *PIMAGE_TLS_DIRECTORY64; - - typedef struct _IMAGE_TLS_DIRECTORY32 { - DWORD StartAddressOfRawData; - DWORD EndAddressOfRawData; - DWORD AddressOfIndex; - DWORD AddressOfCallBacks; - DWORD SizeOfZeroFill; - DWORD Characteristics; - } IMAGE_TLS_DIRECTORY32; - typedef IMAGE_TLS_DIRECTORY32 *PIMAGE_TLS_DIRECTORY32; - -#ifdef _WIN64 -#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64 -#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL64(Ordinal) - typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; - typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; -#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL64(Ordinal) - typedef IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY; - typedef PIMAGE_TLS_DIRECTORY64 PIMAGE_TLS_DIRECTORY; -#else -#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32 -#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL32(Ordinal) - typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; - typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; -#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL32(Ordinal) - typedef IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY; - typedef PIMAGE_TLS_DIRECTORY32 PIMAGE_TLS_DIRECTORY; -#endif - - typedef struct _IMAGE_IMPORT_DESCRIPTOR { - union { - DWORD Characteristics; - DWORD OriginalFirstThunk; - }; - DWORD TimeDateStamp; - - DWORD ForwarderChain; - DWORD Name; - DWORD FirstThunk; - } IMAGE_IMPORT_DESCRIPTOR; - typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR; - - typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR { - DWORD TimeDateStamp; - WORD OffsetModuleName; - WORD NumberOfModuleForwarderRefs; - } IMAGE_BOUND_IMPORT_DESCRIPTOR,*PIMAGE_BOUND_IMPORT_DESCRIPTOR; - - typedef struct _IMAGE_BOUND_FORWARDER_REF { - DWORD TimeDateStamp; - WORD OffsetModuleName; - WORD Reserved; - } IMAGE_BOUND_FORWARDER_REF,*PIMAGE_BOUND_FORWARDER_REF; - - typedef struct _IMAGE_RESOURCE_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - WORD NumberOfNamedEntries; - WORD NumberOfIdEntries; - } IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; - -#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 -#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 - - typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { - union { - struct { - DWORD NameOffset:31; - DWORD NameIsString:1; - }; - DWORD Name; - WORD Id; - }; - union { - DWORD OffsetToData; - struct { - DWORD OffsetToDirectory:31; - DWORD DataIsDirectory:1; - }; - }; - } IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; - - typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { - WORD Length; - CHAR NameString[1]; - } IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; - - typedef struct _IMAGE_RESOURCE_DIR_STRING_U { - WORD Length; - WCHAR NameString[1]; - } IMAGE_RESOURCE_DIR_STRING_U,*PIMAGE_RESOURCE_DIR_STRING_U; - - typedef struct _IMAGE_RESOURCE_DATA_ENTRY { - DWORD OffsetToData; - DWORD Size; - DWORD CodePage; - DWORD Reserved; - } IMAGE_RESOURCE_DATA_ENTRY,*PIMAGE_RESOURCE_DATA_ENTRY; - - typedef struct { - DWORD Size; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD GlobalFlagsClear; - DWORD GlobalFlagsSet; - DWORD CriticalSectionDefaultTimeout; - DWORD DeCommitFreeBlockThreshold; - DWORD DeCommitTotalFreeThreshold; - DWORD LockPrefixTable; - DWORD MaximumAllocationSize; - DWORD VirtualMemoryThreshold; - DWORD ProcessHeapFlags; - DWORD ProcessAffinityMask; - WORD CSDVersion; - WORD Reserved1; - DWORD EditList; - DWORD SecurityCookie; - DWORD SEHandlerTable; - DWORD SEHandlerCount; - } IMAGE_LOAD_CONFIG_DIRECTORY32,*PIMAGE_LOAD_CONFIG_DIRECTORY32; - - typedef struct { - DWORD Size; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD GlobalFlagsClear; - DWORD GlobalFlagsSet; - DWORD CriticalSectionDefaultTimeout; - ULONGLONG DeCommitFreeBlockThreshold; - ULONGLONG DeCommitTotalFreeThreshold; - ULONGLONG LockPrefixTable; - ULONGLONG MaximumAllocationSize; - ULONGLONG VirtualMemoryThreshold; - ULONGLONG ProcessAffinityMask; - DWORD ProcessHeapFlags; - WORD CSDVersion; - WORD Reserved1; - ULONGLONG EditList; - ULONGLONG SecurityCookie; - ULONGLONG SEHandlerTable; - ULONGLONG SEHandlerCount; - } IMAGE_LOAD_CONFIG_DIRECTORY64,*PIMAGE_LOAD_CONFIG_DIRECTORY64; - -#ifdef _WIN64 - typedef IMAGE_LOAD_CONFIG_DIRECTORY64 IMAGE_LOAD_CONFIG_DIRECTORY; - typedef PIMAGE_LOAD_CONFIG_DIRECTORY64 PIMAGE_LOAD_CONFIG_DIRECTORY; -#else - typedef IMAGE_LOAD_CONFIG_DIRECTORY32 IMAGE_LOAD_CONFIG_DIRECTORY; - typedef PIMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY; -#endif - - typedef struct _IMAGE_CE_RUNTIME_FUNCTION_ENTRY { - DWORD FuncStart; - DWORD PrologLen : 8; - DWORD FuncLen : 22; - DWORD ThirtyTwoBit : 1; - DWORD ExceptionFlag : 1; - } IMAGE_CE_RUNTIME_FUNCTION_ENTRY,*PIMAGE_CE_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY { - ULONGLONG BeginAddress; - ULONGLONG EndAddress; - ULONGLONG ExceptionHandler; - ULONGLONG HandlerData; - ULONGLONG PrologEndAddress; - } IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY { - DWORD BeginAddress; - DWORD EndAddress; - DWORD ExceptionHandler; - DWORD HandlerData; - DWORD PrologEndAddress; - } IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindInfoAddress; - } _IMAGE_RUNTIME_FUNCTION_ENTRY,*_PIMAGE_RUNTIME_FUNCTION_ENTRY; - - typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_IA64_RUNTIME_FUNCTION_ENTRY; - typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY; - - typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_RUNTIME_FUNCTION_ENTRY; - typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_DEBUG_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD Type; - DWORD SizeOfData; - DWORD AddressOfRawData; - DWORD PointerToRawData; - } IMAGE_DEBUG_DIRECTORY,*PIMAGE_DEBUG_DIRECTORY; - -#define IMAGE_DEBUG_TYPE_UNKNOWN 0 -#define IMAGE_DEBUG_TYPE_COFF 1 -#define IMAGE_DEBUG_TYPE_CODEVIEW 2 -#define IMAGE_DEBUG_TYPE_FPO 3 -#define IMAGE_DEBUG_TYPE_MISC 4 -#define IMAGE_DEBUG_TYPE_EXCEPTION 5 -#define IMAGE_DEBUG_TYPE_FIXUP 6 -#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 -#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 -#define IMAGE_DEBUG_TYPE_BORLAND 9 -#define IMAGE_DEBUG_TYPE_RESERVED10 10 -#define IMAGE_DEBUG_TYPE_CLSID 11 - - typedef struct _IMAGE_COFF_SYMBOLS_HEADER { - DWORD NumberOfSymbols; - DWORD LvaToFirstSymbol; - DWORD NumberOfLinenumbers; - DWORD LvaToFirstLinenumber; - DWORD RvaToFirstByteOfCode; - DWORD RvaToLastByteOfCode; - DWORD RvaToFirstByteOfData; - DWORD RvaToLastByteOfData; - } IMAGE_COFF_SYMBOLS_HEADER,*PIMAGE_COFF_SYMBOLS_HEADER; - -#define FRAME_FPO 0 -#define FRAME_TRAP 1 -#define FRAME_TSS 2 -#define FRAME_NONFPO 3 - - typedef struct _FPO_DATA { - DWORD ulOffStart; - DWORD cbProcSize; - DWORD cdwLocals; - WORD cdwParams; - WORD cbProlog : 8; - WORD cbRegs : 3; - WORD fHasSEH : 1; - WORD fUseBP : 1; - WORD reserved : 1; - WORD cbFrame : 2; - } FPO_DATA,*PFPO_DATA; -#define SIZEOF_RFPO_DATA 16 - -#define IMAGE_DEBUG_MISC_EXENAME 1 - - typedef struct _IMAGE_DEBUG_MISC { - DWORD DataType; - DWORD Length; - BOOLEAN Unicode; - BYTE Reserved[3]; - BYTE Data[1]; - } IMAGE_DEBUG_MISC,*PIMAGE_DEBUG_MISC; - - typedef struct _IMAGE_FUNCTION_ENTRY { - DWORD StartingAddress; - DWORD EndingAddress; - DWORD EndOfPrologue; - } IMAGE_FUNCTION_ENTRY,*PIMAGE_FUNCTION_ENTRY; - - typedef struct _IMAGE_FUNCTION_ENTRY64 { - ULONGLONG StartingAddress; - ULONGLONG EndingAddress; - union { - ULONGLONG EndOfPrologue; - ULONGLONG UnwindInfoAddress; - }; - } IMAGE_FUNCTION_ENTRY64,*PIMAGE_FUNCTION_ENTRY64; - - typedef struct _IMAGE_SEPARATE_DEBUG_HEADER { - WORD Signature; - WORD Flags; - WORD Machine; - WORD Characteristics; - DWORD TimeDateStamp; - DWORD CheckSum; - DWORD ImageBase; - DWORD SizeOfImage; - DWORD NumberOfSections; - DWORD ExportedNamesSize; - DWORD DebugDirectorySize; - DWORD SectionAlignment; - DWORD Reserved[2]; - } IMAGE_SEPARATE_DEBUG_HEADER,*PIMAGE_SEPARATE_DEBUG_HEADER; - - typedef struct _NON_PAGED_DEBUG_INFO { - WORD Signature; - WORD Flags; - DWORD Size; - WORD Machine; - WORD Characteristics; - DWORD TimeDateStamp; - DWORD CheckSum; - DWORD SizeOfImage; - ULONGLONG ImageBase; - - } NON_PAGED_DEBUG_INFO,*PNON_PAGED_DEBUG_INFO; - -#define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944 -#define NON_PAGED_DEBUG_SIGNATURE 0x494E - -#define IMAGE_SEPARATE_DEBUG_FLAGS_MASK 0x8000 -#define IMAGE_SEPARATE_DEBUG_MISMATCH 0x8000 - - typedef struct _ImageArchitectureHeader { - unsigned int AmaskValue: 1; - int Adummy1 :7; - unsigned int AmaskShift: 8; - int Adummy2 :16; - DWORD FirstEntryRVA; - } IMAGE_ARCHITECTURE_HEADER,*PIMAGE_ARCHITECTURE_HEADER; - - typedef struct _ImageArchitectureEntry { - DWORD FixupInstRVA; - DWORD NewInst; - } IMAGE_ARCHITECTURE_ENTRY,*PIMAGE_ARCHITECTURE_ENTRY; - -#include "poppack.h" - -#define IMPORT_OBJECT_HDR_SIG2 0xffff - - typedef struct IMPORT_OBJECT_HEADER { - WORD Sig1; - WORD Sig2; - WORD Version; - WORD Machine; - DWORD TimeDateStamp; - DWORD SizeOfData; - union { - WORD Ordinal; - WORD Hint; - }; - WORD Type : 2; - WORD NameType : 3; - WORD Reserved : 11; - } IMPORT_OBJECT_HEADER; - - typedef enum IMPORT_OBJECT_TYPE { - IMPORT_OBJECT_CODE = 0,IMPORT_OBJECT_DATA = 1,IMPORT_OBJECT_CONST = 2 - } IMPORT_OBJECT_TYPE; - - typedef enum IMPORT_OBJECT_NAME_TYPE { - IMPORT_OBJECT_ORDINAL = 0,IMPORT_OBJECT_NAME = 1,IMPORT_OBJECT_NAME_NO_PREFIX = 2,IMPORT_OBJECT_NAME_UNDECORATE = 3 - } IMPORT_OBJECT_NAME_TYPE; - -#ifndef __IMAGE_COR20_HEADER_DEFINED__ -#define __IMAGE_COR20_HEADER_DEFINED__ - typedef enum ReplacesCorHdrNumericDefines { - COMIMAGE_FLAGS_ILONLY =0x00000001,COMIMAGE_FLAGS_32BITREQUIRED =0x00000002,COMIMAGE_FLAGS_IL_LIBRARY =0x00000004, - COMIMAGE_FLAGS_STRONGNAMESIGNED =0x00000008,COMIMAGE_FLAGS_TRACKDEBUGDATA =0x00010000,COR_VERSION_MAJOR_V2 =2, - COR_VERSION_MAJOR =COR_VERSION_MAJOR_V2,COR_VERSION_MINOR =0,COR_DELETED_NAME_LENGTH =8,COR_VTABLEGAP_NAME_LENGTH =8, - NATIVE_TYPE_MAX_CB =1,COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE=0xFF,IMAGE_COR_MIH_METHODRVA =0x01,IMAGE_COR_MIH_EHRVA =0x02, - IMAGE_COR_MIH_BASICBLOCK =0x08,COR_VTABLE_32BIT =0x01,COR_VTABLE_64BIT =0x02,COR_VTABLE_FROM_UNMANAGED =0x04, - COR_VTABLE_CALL_MOST_DERIVED =0x10,IMAGE_COR_EATJ_THUNK_SIZE =32,MAX_CLASS_NAME =1024,MAX_PACKAGE_NAME =1024 - } ReplacesCorHdrNumericDefines; - - typedef struct IMAGE_COR20_HEADER { - DWORD cb; - WORD MajorRuntimeVersion; - WORD MinorRuntimeVersion; - IMAGE_DATA_DIRECTORY MetaData; - DWORD Flags; - DWORD EntryPointToken; - IMAGE_DATA_DIRECTORY Resources; - IMAGE_DATA_DIRECTORY StrongNameSignature; - IMAGE_DATA_DIRECTORY CodeManagerTable; - IMAGE_DATA_DIRECTORY VTableFixups; - IMAGE_DATA_DIRECTORY ExportAddressTableJumps; - IMAGE_DATA_DIRECTORY ManagedNativeHeader; - } IMAGE_COR20_HEADER,*PIMAGE_COR20_HEADER; -#endif - -#if defined (__x86_64) - NTSYSAPI PRUNTIME_FUNCTION NTAPI RtlLookupFunctionEntry (DWORD64 ControlPc, PDWORD64 ImageBase, PUNWIND_HISTORY_TABLE HistoryTable); - NTSYSAPI VOID NTAPI RtlUnwindEx (PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable); -#endif - -#include - -#ifndef _SLIST_HEADER_ -#define _SLIST_HEADER_ - -#ifdef _WIN64 - typedef struct _SLIST_ENTRY *PSLIST_ENTRY; - typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY { - PSLIST_ENTRY Next; - } SLIST_ENTRY; -#else - -#define SLIST_ENTRY SINGLE_LIST_ENTRY -#define _SLIST_ENTRY _SINGLE_LIST_ENTRY -#define PSLIST_ENTRY PSINGLE_LIST_ENTRY -#endif - -#if defined(_WIN64) - - typedef struct DECLSPEC_ALIGN(16) _SLIST_HEADER { - ULONGLONG Alignment; - ULONGLONG Region; - } SLIST_HEADER; - - typedef struct _SLIST_HEADER *PSLIST_HEADER; -#else - - typedef union _SLIST_HEADER { - ULONGLONG Alignment; - struct { - SLIST_ENTRY Next; - WORD Depth; - WORD Sequence; - }; - } SLIST_HEADER,*PSLIST_HEADER; -#endif -#endif - - NTSYSAPI VOID NTAPI RtlInitializeSListHead(PSLIST_HEADER ListHead); - NTSYSAPI PSLIST_ENTRY NTAPI RtlFirstEntrySList(const SLIST_HEADER *ListHead); - NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPopEntrySList(PSLIST_HEADER ListHead); - NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); - NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedFlushSList(PSLIST_HEADER ListHead); - NTSYSAPI WORD NTAPI RtlQueryDepthSList(PSLIST_HEADER ListHead); - -#define HEAP_NO_SERIALIZE 0x00000001 -#define HEAP_GROWABLE 0x00000002 -#define HEAP_GENERATE_EXCEPTIONS 0x00000004 -#define HEAP_ZERO_MEMORY 0x00000008 -#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 -#define HEAP_TAIL_CHECKING_ENABLED 0x00000020 -#define HEAP_FREE_CHECKING_ENABLED 0x00000040 -#define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 -#define HEAP_CREATE_ALIGN_16 0x00010000 -#define HEAP_CREATE_ENABLE_TRACING 0x00020000 -#define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 -#define HEAP_MAXIMUM_TAG 0x0FFF -#define HEAP_PSEUDO_TAG_FLAG 0x8000 -#define HEAP_TAG_SHIFT 18 -#define HEAP_MAKE_TAG_FLAGS(b,o) ((DWORD)((b) + ((o) << 18))) - - NTSYSAPI VOID NTAPI RtlCaptureContext(PCONTEXT ContextRecord); - -#define IS_TEXT_UNICODE_ASCII16 0x0001 -#define IS_TEXT_UNICODE_REVERSE_ASCII16 0x0010 - -#define IS_TEXT_UNICODE_STATISTICS 0x0002 -#define IS_TEXT_UNICODE_REVERSE_STATISTICS 0x0020 - -#define IS_TEXT_UNICODE_CONTROLS 0x0004 -#define IS_TEXT_UNICODE_REVERSE_CONTROLS 0x0040 - -#define IS_TEXT_UNICODE_SIGNATURE 0x0008 -#define IS_TEXT_UNICODE_REVERSE_SIGNATURE 0x0080 - -#define IS_TEXT_UNICODE_ILLEGAL_CHARS 0x0100 -#define IS_TEXT_UNICODE_ODD_LENGTH 0x0200 -#define IS_TEXT_UNICODE_DBCS_LEADBYTE 0x0400 -#define IS_TEXT_UNICODE_NULL_BYTES 0x1000 - -#define IS_TEXT_UNICODE_UNICODE_MASK 0x000F -#define IS_TEXT_UNICODE_REVERSE_MASK 0x00F0 -#define IS_TEXT_UNICODE_NOT_UNICODE_MASK 0x0F00 -#define IS_TEXT_UNICODE_NOT_ASCII_MASK 0xF000 - -#define COMPRESSION_FORMAT_NONE (0x0000) -#define COMPRESSION_FORMAT_DEFAULT (0x0001) -#define COMPRESSION_FORMAT_LZNT1 (0x0002) -#define COMPRESSION_ENGINE_STANDARD (0x0000) -#define COMPRESSION_ENGINE_MAXIMUM (0x0100) -#define COMPRESSION_ENGINE_HIBER (0x0200) - -#if _DBG_MEMCPY_INLINE_ && !defined(_MEMCPY_INLINE_) && !defined(_CRTBLD) -#define _MEMCPY_INLINE_ - __CRT_INLINE PVOID __cdecl memcpy_inline(void *dst,const void *src,size_t size) { - if(((char *)dst > (char *)src) && ((char *)dst < ((char *)src + size))) { - __debugbreak(); - } - return memcpy(dst,src,size); - } -#define memcpy memcpy_inline -#endif - - NTSYSAPI SIZE_T NTAPI RtlCompareMemory(const VOID *Source1,const VOID *Source2,SIZE_T Length); - -#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length))) -#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length)) -#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length)) -#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length)) -#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) - - __CRT_INLINE PVOID RtlSecureZeroMemory(PVOID ptr,SIZE_T cnt) { - volatile char *vptr =(volatile char *)ptr; -#ifdef __x86_64 - __stosb((PBYTE)((DWORD64)vptr),0,cnt); -#else - while(cnt) { - *vptr = 0; - vptr++; - cnt--; - } -#endif - return ptr; - } - - typedef struct _MESSAGE_RESOURCE_ENTRY { - WORD Length; - WORD Flags; - BYTE Text[1]; - } MESSAGE_RESOURCE_ENTRY,*PMESSAGE_RESOURCE_ENTRY; - -#define MESSAGE_RESOURCE_UNICODE 0x0001 - - typedef struct _MESSAGE_RESOURCE_BLOCK { - DWORD LowId; - DWORD HighId; - DWORD OffsetToEntries; - } MESSAGE_RESOURCE_BLOCK,*PMESSAGE_RESOURCE_BLOCK; - - typedef struct _MESSAGE_RESOURCE_DATA { - DWORD NumberOfBlocks; - MESSAGE_RESOURCE_BLOCK Blocks[1]; - } MESSAGE_RESOURCE_DATA,*PMESSAGE_RESOURCE_DATA; - - typedef struct _OSVERSIONINFOA { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - CHAR szCSDVersion[128]; - } OSVERSIONINFOA,*POSVERSIONINFOA,*LPOSVERSIONINFOA; - - typedef struct _OSVERSIONINFOW { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - WCHAR szCSDVersion[128]; - } OSVERSIONINFOW,*POSVERSIONINFOW,*LPOSVERSIONINFOW,RTL_OSVERSIONINFOW,*PRTL_OSVERSIONINFOW; - -#ifdef UNICODE - typedef OSVERSIONINFOW OSVERSIONINFO; - typedef POSVERSIONINFOW POSVERSIONINFO; - typedef LPOSVERSIONINFOW LPOSVERSIONINFO; -#else - typedef OSVERSIONINFOA OSVERSIONINFO; - typedef POSVERSIONINFOA POSVERSIONINFO; - typedef LPOSVERSIONINFOA LPOSVERSIONINFO; -#endif - - typedef struct _OSVERSIONINFOEXA { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - CHAR szCSDVersion[128]; - WORD wServicePackMajor; - WORD wServicePackMinor; - WORD wSuiteMask; - BYTE wProductType; - BYTE wReserved; - } OSVERSIONINFOEXA,*POSVERSIONINFOEXA,*LPOSVERSIONINFOEXA; - - typedef struct _OSVERSIONINFOEXW { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - WCHAR szCSDVersion[128]; - WORD wServicePackMajor; - WORD wServicePackMinor; - WORD wSuiteMask; - BYTE wProductType; - BYTE wReserved; - } OSVERSIONINFOEXW,*POSVERSIONINFOEXW,*LPOSVERSIONINFOEXW,RTL_OSVERSIONINFOEXW,*PRTL_OSVERSIONINFOEXW; -#ifdef UNICODE - typedef OSVERSIONINFOEXW OSVERSIONINFOEX; - typedef POSVERSIONINFOEXW POSVERSIONINFOEX; - typedef LPOSVERSIONINFOEXW LPOSVERSIONINFOEX; -#else - typedef OSVERSIONINFOEXA OSVERSIONINFOEX; - typedef POSVERSIONINFOEXA POSVERSIONINFOEX; - typedef LPOSVERSIONINFOEXA LPOSVERSIONINFOEX; -#endif - -#define VER_EQUAL 1 -#define VER_GREATER 2 -#define VER_GREATER_EQUAL 3 -#define VER_LESS 4 -#define VER_LESS_EQUAL 5 -#define VER_AND 6 -#define VER_OR 7 - -#define VER_CONDITION_MASK 7 -#define VER_NUM_BITS_PER_CONDITION_MASK 3 - -#define VER_MINORVERSION 0x0000001 -#define VER_MAJORVERSION 0x0000002 -#define VER_BUILDNUMBER 0x0000004 -#define VER_PLATFORMID 0x0000008 -#define VER_SERVICEPACKMINOR 0x0000010 -#define VER_SERVICEPACKMAJOR 0x0000020 -#define VER_SUITENAME 0x0000040 -#define VER_PRODUCT_TYPE 0x0000080 - -#define VER_NT_WORKSTATION 0x0000001 -#define VER_NT_DOMAIN_CONTROLLER 0x0000002 -#define VER_NT_SERVER 0x0000003 - -#define VER_PLATFORM_WIN32s 0 -#define VER_PLATFORM_WIN32_WINDOWS 1 -#define VER_PLATFORM_WIN32_NT 2 - -#define VER_SET_CONDITION(_m_,_t_,_c_) ((_m_)=VerSetConditionMask((_m_),(_t_),(_c_))) - - NTSYSAPI ULONGLONG NTAPI VerSetConditionMask(ULONGLONG ConditionMask,DWORD TypeMask,BYTE Condition); - - typedef struct _RTL_CRITICAL_SECTION_DEBUG { - WORD Type; - WORD CreatorBackTraceIndex; - struct _RTL_CRITICAL_SECTION *CriticalSection; - LIST_ENTRY ProcessLocksList; - DWORD EntryCount; - DWORD ContentionCount; - DWORD Spare[2]; - } RTL_CRITICAL_SECTION_DEBUG,*PRTL_CRITICAL_SECTION_DEBUG,RTL_RESOURCE_DEBUG,*PRTL_RESOURCE_DEBUG; - -#define RTL_CRITSECT_TYPE 0 -#define RTL_RESOURCE_TYPE 1 - - typedef struct _RTL_CRITICAL_SECTION { - PRTL_CRITICAL_SECTION_DEBUG DebugInfo; - LONG LockCount; - LONG RecursionCount; - HANDLE OwningThread; - HANDLE LockSemaphore; - ULONG_PTR SpinCount; - } RTL_CRITICAL_SECTION,*PRTL_CRITICAL_SECTION; - - typedef VOID (NTAPI *RTL_VERIFIER_DLL_LOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); - typedef VOID (NTAPI *RTL_VERIFIER_DLL_UNLOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); - typedef VOID (NTAPI *RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK)(PVOID AllocationBase,SIZE_T AllocationSize); - - typedef struct _RTL_VERIFIER_THUNK_DESCRIPTOR { - PCHAR ThunkName; - PVOID ThunkOldAddress; - PVOID ThunkNewAddress; - } RTL_VERIFIER_THUNK_DESCRIPTOR,*PRTL_VERIFIER_THUNK_DESCRIPTOR; - - typedef struct _RTL_VERIFIER_DLL_DESCRIPTOR { - PWCHAR DllName; - DWORD DllFlags; - PVOID DllAddress; - PRTL_VERIFIER_THUNK_DESCRIPTOR DllThunks; - } RTL_VERIFIER_DLL_DESCRIPTOR,*PRTL_VERIFIER_DLL_DESCRIPTOR; - - typedef struct _RTL_VERIFIER_PROVIDER_DESCRIPTOR { - DWORD Length; - PRTL_VERIFIER_DLL_DESCRIPTOR ProviderDlls; - RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback; - RTL_VERIFIER_DLL_UNLOAD_CALLBACK ProviderDllUnloadCallback; - PWSTR VerifierImage; - DWORD VerifierFlags; - DWORD VerifierDebug; - PVOID RtlpGetStackTraceAddress; - PVOID RtlpDebugPageHeapCreate; - PVOID RtlpDebugPageHeapDestroy; - RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK ProviderNtdllHeapFreeCallback; - } RTL_VERIFIER_PROVIDER_DESCRIPTOR,*PRTL_VERIFIER_PROVIDER_DESCRIPTOR; - -#define RTL_VRF_FLG_FULL_PAGE_HEAP 0x00000001 -#define RTL_VRF_FLG_RESERVED_DONOTUSE 0x00000002 -#define RTL_VRF_FLG_HANDLE_CHECKS 0x00000004 -#define RTL_VRF_FLG_STACK_CHECKS 0x00000008 -#define RTL_VRF_FLG_APPCOMPAT_CHECKS 0x00000010 -#define RTL_VRF_FLG_TLS_CHECKS 0x00000020 -#define RTL_VRF_FLG_DIRTY_STACKS 0x00000040 -#define RTL_VRF_FLG_RPC_CHECKS 0x00000080 -#define RTL_VRF_FLG_COM_CHECKS 0x00000100 -#define RTL_VRF_FLG_DANGEROUS_APIS 0x00000200 -#define RTL_VRF_FLG_RACE_CHECKS 0x00000400 -#define RTL_VRF_FLG_DEADLOCK_CHECKS 0x00000800 -#define RTL_VRF_FLG_FIRST_CHANCE_EXCEPTION_CHECKS 0x00001000 -#define RTL_VRF_FLG_VIRTUAL_MEM_CHECKS 0x00002000 -#define RTL_VRF_FLG_ENABLE_LOGGING 0x00004000 -#define RTL_VRF_FLG_FAST_FILL_HEAP 0x00008000 -#define RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING 0x00010000 -#define RTL_VRF_FLG_ENABLED_SYSTEM_WIDE 0x00020000 -#define RTL_VRF_FLG_MISCELLANEOUS_CHECKS 0x00020000 -#define RTL_VRF_FLG_LOCK_CHECKS 0x00040000 - -#define APPLICATION_VERIFIER_INTERNAL_ERROR 0x80000000 -#define APPLICATION_VERIFIER_INTERNAL_WARNING 0x40000000 -#define APPLICATION_VERIFIER_NO_BREAK 0x20000000 -#define APPLICATION_VERIFIER_CONTINUABLE_BREAK 0x10000000 - -#define APPLICATION_VERIFIER_UNKNOWN_ERROR 0x0001 -#define APPLICATION_VERIFIER_ACCESS_VIOLATION 0x0002 -#define APPLICATION_VERIFIER_UNSYNCHRONIZED_ACCESS 0x0003 -#define APPLICATION_VERIFIER_EXTREME_SIZE_REQUEST 0x0004 -#define APPLICATION_VERIFIER_BAD_HEAP_HANDLE 0x0005 -#define APPLICATION_VERIFIER_SWITCHED_HEAP_HANDLE 0x0006 -#define APPLICATION_VERIFIER_DOUBLE_FREE 0x0007 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK 0x0008 -#define APPLICATION_VERIFIER_DESTROY_PROCESS_HEAP 0x0009 -#define APPLICATION_VERIFIER_UNEXPECTED_EXCEPTION 0x000A -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_HEADER 0x000B -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_PROBING 0x000C -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_HEADER 0x000D -#define APPLICATION_VERIFIER_CORRUPTED_FREED_HEAP_BLOCK 0x000E -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_SUFFIX 0x000F -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_START_STAMP 0x0010 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_END_STAMP 0x0011 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_PREFIX 0x0012 -#define APPLICATION_VERIFIER_FIRST_CHANCE_ACCESS_VIOLATION 0x0013 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_LIST 0x0014 - -#define APPLICATION_VERIFIER_TERMINATE_THREAD_CALL 0x0100 -#define APPLICATION_VERIFIER_STACK_OVERFLOW 0x0101 -#define APPLICATION_VERIFIER_INVALID_EXIT_PROCESS_CALL 0x0102 - -#define APPLICATION_VERIFIER_EXIT_THREAD_OWNS_LOCK 0x0200 -#define APPLICATION_VERIFIER_LOCK_IN_UNLOADED_DLL 0x0201 -#define APPLICATION_VERIFIER_LOCK_IN_FREED_HEAP 0x0202 -#define APPLICATION_VERIFIER_LOCK_DOUBLE_INITIALIZE 0x0203 -#define APPLICATION_VERIFIER_LOCK_IN_FREED_MEMORY 0x0204 -#define APPLICATION_VERIFIER_LOCK_CORRUPTED 0x0205 -#define APPLICATION_VERIFIER_LOCK_INVALID_OWNER 0x0206 -#define APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT 0x0207 -#define APPLICATION_VERIFIER_LOCK_INVALID_LOCK_COUNT 0x0208 -#define APPLICATION_VERIFIER_LOCK_OVER_RELEASED 0x0209 -#define APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED 0x0210 -#define APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED 0x0211 -#define APPLICATION_VERIFIER_LOCK_IN_FREED_VMEM 0x0212 -#define APPLICATION_VERIFIER_LOCK_IN_UNMAPPED_MEM 0x0213 -#define APPLICATION_VERIFIER_THREAD_NOT_LOCK_OWNER 0x0214 - -#define APPLICATION_VERIFIER_INVALID_HANDLE 0x0300 -#define APPLICATION_VERIFIER_INVALID_TLS_VALUE 0x0301 -#define APPLICATION_VERIFIER_INCORRECT_WAIT_CALL 0x0302 -#define APPLICATION_VERIFIER_NULL_HANDLE 0x0303 -#define APPLICATION_VERIFIER_WAIT_IN_DLLMAIN 0x0304 - -#define APPLICATION_VERIFIER_COM_ERROR 0x0400 -#define APPLICATION_VERIFIER_COM_API_IN_DLLMAIN 0x0401 -#define APPLICATION_VERIFIER_COM_UNHANDLED_EXCEPTION 0x0402 -#define APPLICATION_VERIFIER_COM_UNBALANCED_COINIT 0x0403 -#define APPLICATION_VERIFIER_COM_UNBALANCED_OLEINIT 0x0404 -#define APPLICATION_VERIFIER_COM_UNBALANCED_SWC 0x0405 -#define APPLICATION_VERIFIER_COM_NULL_DACL 0x0406 -#define APPLICATION_VERIFIER_COM_UNSAFE_IMPERSONATION 0x0407 -#define APPLICATION_VERIFIER_COM_SMUGGLED_WRAPPER 0x0408 -#define APPLICATION_VERIFIER_COM_SMUGGLED_PROXY 0x0409 -#define APPLICATION_VERIFIER_COM_CF_SUCCESS_WITH_NULL 0x040A -#define APPLICATION_VERIFIER_COM_GCO_SUCCESS_WITH_NULL 0x040B -#define APPLICATION_VERIFIER_COM_OBJECT_IN_FREED_MEMORY 0x040C -#define APPLICATION_VERIFIER_COM_OBJECT_IN_UNLOADED_DLL 0x040D -#define APPLICATION_VERIFIER_COM_VTBL_IN_FREED_MEMORY 0x040E -#define APPLICATION_VERIFIER_COM_VTBL_IN_UNLOADED_DLL 0x040F -#define APPLICATION_VERIFIER_COM_HOLDING_LOCKS_ON_CALL 0x0410 - -#define APPLICATION_VERIFIER_RPC_ERROR 0x0500 - -#define APPLICATION_VERIFIER_INVALID_FREEMEM 0x0600 -#define APPLICATION_VERIFIER_INVALID_ALLOCMEM 0x0601 -#define APPLICATION_VERIFIER_INVALID_MAPVIEW 0x0602 -#define APPLICATION_VERIFIER_PROBE_INVALID_ADDRESS 0x0603 -#define APPLICATION_VERIFIER_PROBE_FREE_MEM 0x0604 -#define APPLICATION_VERIFIER_PROBE_GUARD_PAGE 0x0605 -#define APPLICATION_VERIFIER_PROBE_NULL 0x0606 -#define APPLICATION_VERIFIER_PROBE_INVALID_START_OR_SIZE 0x0607 -#define APPLICATION_VERIFIER_SIZE_HEAP_UNEXPECTED_EXCEPTION 0x0618 - -#define VERIFIER_STOP(Code,Msg,P1,S1,P2,S2,P3,S3,P4,S4) { RtlApplicationVerifierStop ((Code),(Msg),(ULONG_PTR)(P1),(S1),(ULONG_PTR)(P2),(S2),(ULONG_PTR)(P3),(S3),(ULONG_PTR)(P4),(S4)); } - - VOID NTAPI RtlApplicationVerifierStop(ULONG_PTR Code,PSTR Message,ULONG_PTR Param1,PSTR Description1,ULONG_PTR Param2,PSTR Description2,ULONG_PTR Param3,PSTR Description3,ULONG_PTR Param4,PSTR Description4); - - typedef LONG (NTAPI *PVECTORED_EXCEPTION_HANDLER)(struct _EXCEPTION_POINTERS *ExceptionInfo); -#define SEF_DACL_AUTO_INHERIT 0x01 -#define SEF_SACL_AUTO_INHERIT 0x02 -#define SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT 0x04 -#define SEF_AVOID_PRIVILEGE_CHECK 0x08 -#define SEF_AVOID_OWNER_CHECK 0x10 -#define SEF_DEFAULT_OWNER_FROM_PARENT 0x20 -#define SEF_DEFAULT_GROUP_FROM_PARENT 0x40 - - typedef enum _HEAP_INFORMATION_CLASS { - HeapCompatibilityInformation - } HEAP_INFORMATION_CLASS; - - NTSYSAPI DWORD NTAPI RtlSetHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); - NTSYSAPI DWORD NTAPI RtlQueryHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); - DWORD NTAPI RtlMultipleAllocateHeap(PVOID HeapHandle,DWORD Flags,SIZE_T Size,DWORD Count,PVOID *Array); - DWORD NTAPI RtlMultipleFreeHeap(PVOID HeapHandle,DWORD Flags,DWORD Count,PVOID *Array); - -#define WT_EXECUTEDEFAULT 0x00000000 -#define WT_EXECUTEINIOTHREAD 0x00000001 -#define WT_EXECUTEINUITHREAD 0x00000002 -#define WT_EXECUTEINWAITTHREAD 0x00000004 -#define WT_EXECUTEONLYONCE 0x00000008 -#define WT_EXECUTEINTIMERTHREAD 0x00000020 -#define WT_EXECUTELONGFUNCTION 0x00000010 -#define WT_EXECUTEINPERSISTENTIOTHREAD 0x00000040 -#define WT_EXECUTEINPERSISTENTTHREAD 0x00000080 -#define WT_TRANSFER_IMPERSONATION 0x00000100 -#define WT_SET_MAX_THREADPOOL_THREADS(Flags,Limit) ((Flags) |= (Limit)<<16) - typedef VOID (NTAPI *WAITORTIMERCALLBACKFUNC)(PVOID,BOOLEAN); - typedef VOID (NTAPI *WORKERCALLBACKFUNC)(PVOID); - typedef VOID (NTAPI *APC_CALLBACK_FUNCTION)(DWORD ,PVOID,PVOID); - typedef - VOID - (NTAPI *PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); -#define WT_EXECUTEINLONGTHREAD 0x00000010 -#define WT_EXECUTEDELETEWAIT 0x00000008 - - typedef enum _ACTIVATION_CONTEXT_INFO_CLASS { - ActivationContextBasicInformation = 1,ActivationContextDetailedInformation = 2,AssemblyDetailedInformationInActivationContext = 3,FileInformationInAssemblyOfAssemblyInActivationContext = 4,MaxActivationContextInfoClass,AssemblyDetailedInformationInActivationContxt = 3,FileInformationInAssemblyOfAssemblyInActivationContxt = 4 - } ACTIVATION_CONTEXT_INFO_CLASS; - -#define ACTIVATIONCONTEXTINFOCLASS ACTIVATION_CONTEXT_INFO_CLASS - - typedef struct _ACTIVATION_CONTEXT_QUERY_INDEX { - DWORD ulAssemblyIndex; - DWORD ulFileIndexInAssembly; - } ACTIVATION_CONTEXT_QUERY_INDEX,*PACTIVATION_CONTEXT_QUERY_INDEX; - - typedef const struct _ACTIVATION_CONTEXT_QUERY_INDEX *PCACTIVATION_CONTEXT_QUERY_INDEX; - -#define ACTIVATION_CONTEXT_PATH_TYPE_NONE (1) -#define ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE (2) -#define ACTIVATION_CONTEXT_PATH_TYPE_URL (3) -#define ACTIVATION_CONTEXT_PATH_TYPE_ASSEMBLYREF (4) - - typedef struct _ASSEMBLY_FILE_DETAILED_INFORMATION { - DWORD ulFlags; - DWORD ulFilenameLength; - DWORD ulPathLength; - - PCWSTR lpFileName; - PCWSTR lpFilePath; - } ASSEMBLY_FILE_DETAILED_INFORMATION,*PASSEMBLY_FILE_DETAILED_INFORMATION; - typedef const ASSEMBLY_FILE_DETAILED_INFORMATION *PCASSEMBLY_FILE_DETAILED_INFORMATION; - -#define _ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION _ASSEMBLY_FILE_DETAILED_INFORMATION -#define ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION ASSEMBLY_FILE_DETAILED_INFORMATION -#define PASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PASSEMBLY_FILE_DETAILED_INFORMATION -#define PCASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PCASSEMBLY_FILE_DETAILED_INFORMATION - - typedef struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION { - DWORD ulFlags; - DWORD ulEncodedAssemblyIdentityLength; - DWORD ulManifestPathType; - DWORD ulManifestPathLength; - LARGE_INTEGER liManifestLastWriteTime; - DWORD ulPolicyPathType; - DWORD ulPolicyPathLength; - LARGE_INTEGER liPolicyLastWriteTime; - DWORD ulMetadataSatelliteRosterIndex; - DWORD ulManifestVersionMajor; - DWORD ulManifestVersionMinor; - DWORD ulPolicyVersionMajor; - DWORD ulPolicyVersionMinor; - DWORD ulAssemblyDirectoryNameLength; - PCWSTR lpAssemblyEncodedAssemblyIdentity; - PCWSTR lpAssemblyManifestPath; - PCWSTR lpAssemblyPolicyPath; - PCWSTR lpAssemblyDirectoryName; - DWORD ulFileCount; - } ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; - - typedef const struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; - - typedef struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION { - DWORD dwFlags; - DWORD ulFormatVersion; - DWORD ulAssemblyCount; - DWORD ulRootManifestPathType; - DWORD ulRootManifestPathChars; - DWORD ulRootConfigurationPathType; - DWORD ulRootConfigurationPathChars; - DWORD ulAppDirPathType; - DWORD ulAppDirPathChars; - PCWSTR lpRootManifestPath; - PCWSTR lpRootConfigurationPath; - PCWSTR lpAppDirPath; - } ACTIVATION_CONTEXT_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_DETAILED_INFORMATION; - - typedef const struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_DETAILED_INFORMATION; - -#define DLL_PROCESS_ATTACH 1 -#define DLL_THREAD_ATTACH 2 -#define DLL_THREAD_DETACH 3 -#define DLL_PROCESS_DETACH 0 -#define DLL_PROCESS_VERIFIER 4 - -#define EVENTLOG_SEQUENTIAL_READ 0x0001 -#define EVENTLOG_SEEK_READ 0x0002 -#define EVENTLOG_FORWARDS_READ 0x0004 -#define EVENTLOG_BACKWARDS_READ 0x0008 - -#define EVENTLOG_SUCCESS 0x0000 -#define EVENTLOG_ERROR_TYPE 0x0001 -#define EVENTLOG_WARNING_TYPE 0x0002 -#define EVENTLOG_INFORMATION_TYPE 0x0004 -#define EVENTLOG_AUDIT_SUCCESS 0x0008 -#define EVENTLOG_AUDIT_FAILURE 0x0010 - -#define EVENTLOG_START_PAIRED_EVENT 0x0001 -#define EVENTLOG_END_PAIRED_EVENT 0x0002 -#define EVENTLOG_END_ALL_PAIRED_EVENTS 0x0004 -#define EVENTLOG_PAIRED_EVENT_ACTIVE 0x0008 -#define EVENTLOG_PAIRED_EVENT_INACTIVE 0x0010 - - typedef struct _EVENTLOGRECORD { - DWORD Length; - DWORD Reserved; - DWORD RecordNumber; - DWORD TimeGenerated; - DWORD TimeWritten; - DWORD EventID; - WORD EventType; - WORD NumStrings; - WORD EventCategory; - WORD ReservedFlags; - DWORD ClosingRecordNumber; - DWORD StringOffset; - DWORD UserSidLength; - DWORD UserSidOffset; - DWORD DataLength; - DWORD DataOffset; - } EVENTLOGRECORD,*PEVENTLOGRECORD; - -#define MAXLOGICALLOGNAMESIZE 256 - - typedef struct _EVENTSFORLOGFILE{ - DWORD ulSize; - WCHAR szLogicalLogFile[MAXLOGICALLOGNAMESIZE]; - DWORD ulNumRecords; - EVENTLOGRECORD pEventLogRecords[]; - } EVENTSFORLOGFILE,*PEVENTSFORLOGFILE; - - typedef struct _PACKEDEVENTINFO{ - DWORD ulSize; - DWORD ulNumEventsForLogFile; - DWORD ulOffsets[]; - } PACKEDEVENTINFO,*PPACKEDEVENTINFO; - -#define KEY_QUERY_VALUE (0x0001) -#define KEY_SET_VALUE (0x0002) -#define KEY_CREATE_SUB_KEY (0x0004) -#define KEY_ENUMERATE_SUB_KEYS (0x0008) -#define KEY_NOTIFY (0x0010) -#define KEY_CREATE_LINK (0x0020) -#define KEY_WOW64_32KEY (0x0200) -#define KEY_WOW64_64KEY (0x0100) -#define KEY_WOW64_RES (0x0300) - -#define KEY_READ ((STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & (~SYNCHRONIZE)) -#define KEY_WRITE ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE)) -#define KEY_EXECUTE ((KEY_READ) & (~SYNCHRONIZE)) -#define KEY_ALL_ACCESS ((STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & (~SYNCHRONIZE)) -#define REG_OPTION_RESERVED (0x00000000L) - -#define REG_OPTION_NON_VOLATILE (0x00000000L) -#define REG_OPTION_VOLATILE (0x00000001L) -#define REG_OPTION_CREATE_LINK (0x00000002L) -#define REG_OPTION_BACKUP_RESTORE (0x00000004L) -#define REG_OPTION_OPEN_LINK (0x00000008L) -#define REG_LEGAL_OPTION (REG_OPTION_RESERVED | REG_OPTION_NON_VOLATILE | REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK | REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK) -#define REG_CREATED_NEW_KEY (0x00000001L) -#define REG_OPENED_EXISTING_KEY (0x00000002L) -#define REG_STANDARD_FORMAT 1 -#define REG_LATEST_FORMAT 2 -#define REG_NO_COMPRESSION 4 -#define REG_WHOLE_HIVE_VOLATILE (0x00000001L) -#define REG_REFRESH_HIVE (0x00000002L) -#define REG_NO_LAZY_FLUSH (0x00000004L) -#define REG_FORCE_RESTORE (0x00000008L) -#define REG_FORCE_UNLOAD 1 - -#define REG_NOTIFY_CHANGE_NAME (0x00000001L) -#define REG_NOTIFY_CHANGE_ATTRIBUTES (0x00000002L) -#define REG_NOTIFY_CHANGE_LAST_SET (0x00000004L) -#define REG_NOTIFY_CHANGE_SECURITY (0x00000008L) - -#define REG_LEGAL_CHANGE_FILTER (REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY) - -#define REG_NONE (0) -#define REG_SZ (1) -#define REG_EXPAND_SZ (2) - -#define REG_BINARY (3) -#define REG_DWORD (4) -#define REG_DWORD_LITTLE_ENDIAN (4) -#define REG_DWORD_BIG_ENDIAN (5) -#define REG_LINK (6) -#define REG_MULTI_SZ (7) -#define REG_RESOURCE_LIST (8) -#define REG_FULL_RESOURCE_DESCRIPTOR (9) -#define REG_RESOURCE_REQUIREMENTS_LIST (10) -#define REG_QWORD (11) -#define REG_QWORD_LITTLE_ENDIAN (11) - -#define SERVICE_KERNEL_DRIVER 0x00000001 -#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 -#define SERVICE_ADAPTER 0x00000004 -#define SERVICE_RECOGNIZER_DRIVER 0x00000008 - -#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER) - -#define SERVICE_WIN32_OWN_PROCESS 0x00000010 -#define SERVICE_WIN32_SHARE_PROCESS 0x00000020 -#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS) - -#define SERVICE_INTERACTIVE_PROCESS 0x00000100 - -#define SERVICE_TYPE_ALL (SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS) - -#define SERVICE_BOOT_START 0x00000000 -#define SERVICE_SYSTEM_START 0x00000001 -#define SERVICE_AUTO_START 0x00000002 -#define SERVICE_DEMAND_START 0x00000003 -#define SERVICE_DISABLED 0x00000004 - -#define SERVICE_ERROR_IGNORE 0x00000000 -#define SERVICE_ERROR_NORMAL 0x00000001 -#define SERVICE_ERROR_SEVERE 0x00000002 -#define SERVICE_ERROR_CRITICAL 0x00000003 - - typedef enum _CM_SERVICE_NODE_TYPE { - DriverType = SERVICE_KERNEL_DRIVER,FileSystemType = SERVICE_FILE_SYSTEM_DRIVER,Win32ServiceOwnProcess = SERVICE_WIN32_OWN_PROCESS, - Win32ServiceShareProcess = SERVICE_WIN32_SHARE_PROCESS,AdapterType = SERVICE_ADAPTER,RecognizerType = SERVICE_RECOGNIZER_DRIVER - } SERVICE_NODE_TYPE; - - typedef enum _CM_SERVICE_LOAD_TYPE { - BootLoad = SERVICE_BOOT_START,SystemLoad = SERVICE_SYSTEM_START,AutoLoad = SERVICE_AUTO_START,DemandLoad = SERVICE_DEMAND_START, - DisableLoad = SERVICE_DISABLED - } SERVICE_LOAD_TYPE; - - typedef enum _CM_ERROR_CONTROL_TYPE { - IgnoreError = SERVICE_ERROR_IGNORE,NormalError = SERVICE_ERROR_NORMAL,SevereError = SERVICE_ERROR_SEVERE,CriticalError = SERVICE_ERROR_CRITICAL - } SERVICE_ERROR_TYPE; - -#define TAPE_ERASE_SHORT 0L -#define TAPE_ERASE_LONG 1L - - typedef struct _TAPE_ERASE { - DWORD Type; - BOOLEAN Immediate; - } TAPE_ERASE,*PTAPE_ERASE; - -#define TAPE_LOAD 0L -#define TAPE_UNLOAD 1L -#define TAPE_TENSION 2L -#define TAPE_LOCK 3L -#define TAPE_UNLOCK 4L -#define TAPE_FORMAT 5L - - typedef struct _TAPE_PREPARE { - DWORD Operation; - BOOLEAN Immediate; - } TAPE_PREPARE,*PTAPE_PREPARE; - -#define TAPE_SETMARKS 0L -#define TAPE_FILEMARKS 1L -#define TAPE_SHORT_FILEMARKS 2L -#define TAPE_LONG_FILEMARKS 3L - - typedef struct _TAPE_WRITE_MARKS { - DWORD Type; - DWORD Count; - BOOLEAN Immediate; - } TAPE_WRITE_MARKS,*PTAPE_WRITE_MARKS; - -#define TAPE_ABSOLUTE_POSITION 0L -#define TAPE_LOGICAL_POSITION 1L -#define TAPE_PSEUDO_LOGICAL_POSITION 2L - - typedef struct _TAPE_GET_POSITION { - DWORD Type; - DWORD Partition; - LARGE_INTEGER Offset; - } TAPE_GET_POSITION,*PTAPE_GET_POSITION; - -#define TAPE_REWIND 0L -#define TAPE_ABSOLUTE_BLOCK 1L -#define TAPE_LOGICAL_BLOCK 2L -#define TAPE_PSEUDO_LOGICAL_BLOCK 3L -#define TAPE_SPACE_END_OF_DATA 4L -#define TAPE_SPACE_RELATIVE_BLOCKS 5L -#define TAPE_SPACE_FILEMARKS 6L -#define TAPE_SPACE_SEQUENTIAL_FMKS 7L -#define TAPE_SPACE_SETMARKS 8L -#define TAPE_SPACE_SEQUENTIAL_SMKS 9L - - typedef struct _TAPE_SET_POSITION { - DWORD Method; - DWORD Partition; - LARGE_INTEGER Offset; - BOOLEAN Immediate; - } TAPE_SET_POSITION,*PTAPE_SET_POSITION; - -#define TAPE_DRIVE_FIXED 0x00000001 -#define TAPE_DRIVE_SELECT 0x00000002 -#define TAPE_DRIVE_INITIATOR 0x00000004 - -#define TAPE_DRIVE_ERASE_SHORT 0x00000010 -#define TAPE_DRIVE_ERASE_LONG 0x00000020 -#define TAPE_DRIVE_ERASE_BOP_ONLY 0x00000040 -#define TAPE_DRIVE_ERASE_IMMEDIATE 0x00000080 - -#define TAPE_DRIVE_TAPE_CAPACITY 0x00000100 -#define TAPE_DRIVE_TAPE_REMAINING 0x00000200 -#define TAPE_DRIVE_FIXED_BLOCK 0x00000400 -#define TAPE_DRIVE_VARIABLE_BLOCK 0x00000800 - -#define TAPE_DRIVE_WRITE_PROTECT 0x00001000 -#define TAPE_DRIVE_EOT_WZ_SIZE 0x00002000 - -#define TAPE_DRIVE_ECC 0x00010000 -#define TAPE_DRIVE_COMPRESSION 0x00020000 -#define TAPE_DRIVE_PADDING 0x00040000 -#define TAPE_DRIVE_REPORT_SMKS 0x00080000 - -#define TAPE_DRIVE_GET_ABSOLUTE_BLK 0x00100000 -#define TAPE_DRIVE_GET_LOGICAL_BLK 0x00200000 -#define TAPE_DRIVE_SET_EOT_WZ_SIZE 0x00400000 - -#define TAPE_DRIVE_EJECT_MEDIA 0x01000000 -#define TAPE_DRIVE_CLEAN_REQUESTS 0x02000000 -#define TAPE_DRIVE_SET_CMP_BOP_ONLY 0x04000000 - -#define TAPE_DRIVE_RESERVED_BIT 0x80000000 - -#define TAPE_DRIVE_LOAD_UNLOAD 0x80000001 -#define TAPE_DRIVE_TENSION 0x80000002 -#define TAPE_DRIVE_LOCK_UNLOCK 0x80000004 -#define TAPE_DRIVE_REWIND_IMMEDIATE 0x80000008 - -#define TAPE_DRIVE_SET_BLOCK_SIZE 0x80000010 -#define TAPE_DRIVE_LOAD_UNLD_IMMED 0x80000020 -#define TAPE_DRIVE_TENSION_IMMED 0x80000040 -#define TAPE_DRIVE_LOCK_UNLK_IMMED 0x80000080 - -#define TAPE_DRIVE_SET_ECC 0x80000100 -#define TAPE_DRIVE_SET_COMPRESSION 0x80000200 -#define TAPE_DRIVE_SET_PADDING 0x80000400 -#define TAPE_DRIVE_SET_REPORT_SMKS 0x80000800 - -#define TAPE_DRIVE_ABSOLUTE_BLK 0x80001000 -#define TAPE_DRIVE_ABS_BLK_IMMED 0x80002000 -#define TAPE_DRIVE_LOGICAL_BLK 0x80004000 -#define TAPE_DRIVE_LOG_BLK_IMMED 0x80008000 - -#define TAPE_DRIVE_END_OF_DATA 0x80010000 -#define TAPE_DRIVE_RELATIVE_BLKS 0x80020000 -#define TAPE_DRIVE_FILEMARKS 0x80040000 -#define TAPE_DRIVE_SEQUENTIAL_FMKS 0x80080000 - -#define TAPE_DRIVE_SETMARKS 0x80100000 -#define TAPE_DRIVE_SEQUENTIAL_SMKS 0x80200000 -#define TAPE_DRIVE_REVERSE_POSITION 0x80400000 -#define TAPE_DRIVE_SPACE_IMMEDIATE 0x80800000 - -#define TAPE_DRIVE_WRITE_SETMARKS 0x81000000 -#define TAPE_DRIVE_WRITE_FILEMARKS 0x82000000 -#define TAPE_DRIVE_WRITE_SHORT_FMKS 0x84000000 -#define TAPE_DRIVE_WRITE_LONG_FMKS 0x88000000 - -#define TAPE_DRIVE_WRITE_MARK_IMMED 0x90000000 -#define TAPE_DRIVE_FORMAT 0xA0000000 -#define TAPE_DRIVE_FORMAT_IMMEDIATE 0xC0000000 -#define TAPE_DRIVE_HIGH_FEATURES 0x80000000 - - typedef struct _TAPE_GET_DRIVE_PARAMETERS { - BOOLEAN ECC; - BOOLEAN Compression; - BOOLEAN DataPadding; - BOOLEAN ReportSetmarks; - DWORD DefaultBlockSize; - DWORD MaximumBlockSize; - DWORD MinimumBlockSize; - DWORD MaximumPartitionCount; - DWORD FeaturesLow; - DWORD FeaturesHigh; - DWORD EOTWarningZoneSize; - } TAPE_GET_DRIVE_PARAMETERS,*PTAPE_GET_DRIVE_PARAMETERS; - - typedef struct _TAPE_SET_DRIVE_PARAMETERS { - BOOLEAN ECC; - BOOLEAN Compression; - BOOLEAN DataPadding; - BOOLEAN ReportSetmarks; - DWORD EOTWarningZoneSize; - } TAPE_SET_DRIVE_PARAMETERS,*PTAPE_SET_DRIVE_PARAMETERS; - - typedef struct _TAPE_GET_MEDIA_PARAMETERS { - LARGE_INTEGER Capacity; - LARGE_INTEGER Remaining; - DWORD BlockSize; - DWORD PartitionCount; - BOOLEAN WriteProtected; - } TAPE_GET_MEDIA_PARAMETERS,*PTAPE_GET_MEDIA_PARAMETERS; - - typedef struct _TAPE_SET_MEDIA_PARAMETERS { - DWORD BlockSize; - } TAPE_SET_MEDIA_PARAMETERS,*PTAPE_SET_MEDIA_PARAMETERS; - -#define TAPE_FIXED_PARTITIONS 0L -#define TAPE_SELECT_PARTITIONS 1L -#define TAPE_INITIATOR_PARTITIONS 2L - - typedef struct _TAPE_CREATE_PARTITION { - DWORD Method; - DWORD Count; - DWORD Size; - } TAPE_CREATE_PARTITION,*PTAPE_CREATE_PARTITION; - -#define TAPE_QUERY_DRIVE_PARAMETERS 0L -#define TAPE_QUERY_MEDIA_CAPACITY 1L -#define TAPE_CHECK_FOR_DRIVE_PROBLEM 2L -#define TAPE_QUERY_IO_ERROR_DATA 3L -#define TAPE_QUERY_DEVICE_ERROR_DATA 4L - - typedef struct _TAPE_WMI_OPERATIONS { - DWORD Method; - DWORD DataBufferSize; - PVOID DataBuffer; - } TAPE_WMI_OPERATIONS,*PTAPE_WMI_OPERATIONS; - - typedef enum _TAPE_DRIVE_PROBLEM_TYPE { - TapeDriveProblemNone,TapeDriveReadWriteWarning,TapeDriveReadWriteError,TapeDriveReadWarning,TapeDriveWriteWarning,TapeDriveReadError,TapeDriveWriteError,TapeDriveHardwareError,TapeDriveUnsupportedMedia,TapeDriveScsiConnectionError,TapeDriveTimetoClean,TapeDriveCleanDriveNow,TapeDriveMediaLifeExpired,TapeDriveSnappedTape - } TAPE_DRIVE_PROBLEM_TYPE; - -#if defined(__x86_64) - __CRT_INLINE struct _TEB *NtCurrentTeb(VOID) { return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB,Self)); } - __CRT_INLINE PVOID GetCurrentFiber(VOID) { return(PVOID)__readgsqword(FIELD_OFFSET(NT_TIB,FiberData)); } - __CRT_INLINE PVOID GetFiberData(VOID) { - return *(PVOID *)GetCurrentFiber(); - } -#endif - -#if(defined(_X86_) && !defined(__x86_64)) -#define PcTeb 0x18 - __CRT_INLINE struct _TEB *NtCurrentTeb(void) { - struct _TEB *ret; - __asm__ volatile ("movl %%fs:0x18,%0" - : "=r" (ret)); - return ret; - } -#endif - -#define ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION (1) -#define ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION (2) -#define ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION (3) -#define ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION (4) -#define ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION (5) -#define ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION (6) -#define ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION (7) -#define ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE (8) -#define ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES (9) -#define ACTIVATION_CONTEXT_SECTION_APPLICATION_SETTINGS (10) - -#ifdef __cplusplus - } -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINNT_ +#define _WINNT_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#define ANYSIZE_ARRAY 1 + +//gr #include + +#define RESTRICTED_POINTER + +#ifndef __CRT_UNALIGNED +#define __CRT_UNALIGNED +#endif + +#if defined(__ia64__) || defined(__x86_64) +#define UNALIGNED __CRT_UNALIGNED +#ifdef _WIN64 +#define UNALIGNED64 __CRT_UNALIGNED +#else +#define UNALIGNED64 +#endif +#else +#define UNALIGNED +#define UNALIGNED64 +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) +#define I_X86_ +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) +#define _AMD64_ +#endif + +#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) +#if !defined(_IA64_) +#define _IA64_ +#endif +#endif + + +#ifdef _WIN64 +#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) +#define MEMORY_ALLOCATION_ALIGNMENT 16 +#else +#define MAX_NATURAL_ALIGNMENT sizeof(DWORD) +#define MEMORY_ALLOCATION_ALIGNMENT 8 +#endif + +#ifdef __cplusplus +#define TYPE_ALIGNMENT(t) __alignof__ (t) +#else +#define TYPE_ALIGNMENT(t) FIELD_OFFSET(struct { char x; t test; },test) +#endif + +#ifdef _WIN64 +#ifdef _AMD64_ +#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) +#elif defined(_IA64_) +#define PROBE_ALIGNMENT(_s) (TYPE_ALIGNMENT(_s) > TYPE_ALIGNMENT(DWORD) ? TYPE_ALIGNMENT(_s) : TYPE_ALIGNMENT(DWORD)) +#else +#error No Target Architecture +#endif +#define PROBE_ALIGNMENT32(_s) TYPE_ALIGNMENT(DWORD) +#else +#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) +#endif + +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] + +#include + +#if defined(_X86_) || defined(__ia64__) || defined(__x86_64) +#define DECLSPEC_IMPORT __declspec(dllimport) +#else +#define DECLSPEC_IMPORT +#endif + +#ifndef DECLSPEC_NORETURN +#define DECLSPEC_NORETURN __declspec(noreturn) +#endif + +#ifndef DECLSPEC_ALIGN +#define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) +#endif + +#ifndef SYSTEM_CACHE_ALIGNMENT_SIZE +#if defined(_AMD64_) || defined(I_X86_) +#define SYSTEM_CACHE_ALIGNMENT_SIZE 64 +#else +#define SYSTEM_CACHE_ALIGNMENT_SIZE 128 +#endif +#endif + +#ifndef DECLSPEC_CACHEALIGN +#define DECLSPEC_CACHEALIGN DECLSPEC_ALIGN(SYSTEM_CACHE_ALIGNMENT_SIZE) +#endif + +#ifndef DECLSPEC_UUID +#define DECLSPEC_UUID(x) +#endif + +#ifndef DECLSPEC_NOVTABLE +#define DECLSPEC_NOVTABLE +#endif + +#ifndef DECLSPEC_SELECTANY +#define DECLSPEC_SELECTANY __declspec(selectany) +#endif + +#ifndef NOP_FUNCTION +#define NOP_FUNCTION (void)0 +#endif + +#ifndef DECLSPEC_NOINLINE +#define DECLSPEC_NOINLINE +#endif + +#ifndef FORCEINLINE +#define FORCEINLINE static __inline__ +#endif + +#ifndef DECLSPEC_DEPRECATED +#define DECLSPEC_DEPRECATED __declspec(deprecated) +#define DEPRECATE_SUPPORTED +#endif + +#define DECLSPEC_DEPRECATED_DDK +#define PRAGMA_DEPRECATED_DDK 0 + + typedef void *PVOID; + typedef void *PVOID64; + +#define NTAPI __stdcall +#define NTSYSAPI DECLSPEC_IMPORT +#define NTSYSCALLAPI DECLSPEC_IMPORT + +#ifndef VOID +#define VOID void + typedef char CHAR; + typedef short SHORT; + typedef long LONG; +#endif + + typedef wchar_t WCHAR; + typedef WCHAR *PWCHAR,*LPWCH,*PWCH; + typedef CONST WCHAR *LPCWCH,*PCWCH; + typedef WCHAR *NWPSTR,*LPWSTR,*PWSTR; + typedef PWSTR *PZPWSTR; + typedef CONST PWSTR *PCZPWSTR; + typedef WCHAR UNALIGNED *LPUWSTR,*PUWSTR; + typedef CONST WCHAR *LPCWSTR,*PCWSTR; + typedef PCWSTR *PZPCWSTR; + typedef CONST WCHAR UNALIGNED *LPCUWSTR,*PCUWSTR; + typedef CHAR *PCHAR,*LPCH,*PCH; + typedef CONST CHAR *LPCCH,*PCCH; + typedef CHAR *NPSTR,*LPSTR,*PSTR; + typedef PSTR *PZPSTR; + typedef CONST PSTR *PCZPSTR; + typedef CONST CHAR *LPCSTR,*PCSTR; + typedef PCSTR *PZPCSTR; + +#ifdef UNICODE +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED + typedef WCHAR TCHAR,*PTCHAR; + typedef WCHAR TBYTE ,*PTBYTE; +#endif + + typedef LPWSTR LPTCH,PTCH; + typedef LPWSTR PTSTR,LPTSTR; + typedef LPCWSTR PCTSTR,LPCTSTR; + typedef LPUWSTR PUTSTR,LPUTSTR; + typedef LPCUWSTR PCUTSTR,LPCUTSTR; + typedef LPWSTR LP; +#define __TEXT(quote) L##quote +#else +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED + typedef char TCHAR,*PTCHAR; + typedef unsigned char TBYTE ,*PTBYTE; +#endif + + typedef LPSTR LPTCH,PTCH; + typedef LPSTR PTSTR,LPTSTR,PUTSTR,LPUTSTR; + typedef LPCSTR PCTSTR,LPCTSTR,PCUTSTR,LPCUTSTR; +#define __TEXT(quote) quote +#endif + +#define TEXT(quote) __TEXT(quote) + + typedef SHORT *PSHORT; + typedef LONG *PLONG; + + typedef void *HANDLE; +#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name + typedef HANDLE *PHANDLE; + + typedef BYTE FCHAR; + typedef WORD FSHORT; + typedef DWORD FLONG; + +#ifndef _HRESULT_DEFINED +#define _HRESULT_DEFINED + typedef LONG HRESULT; +#endif + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C extern +#endif + +#define STDMETHODCALLTYPE WINAPI +#define STDMETHODVCALLTYPE __cdecl +#define STDAPICALLTYPE WINAPI +#define STDAPIVCALLTYPE __cdecl +#define STDAPI EXTERN_C HRESULT WINAPI +#define STDAPI_(type) EXTERN_C type WINAPI +#define STDMETHODIMP HRESULT WINAPI +#define STDMETHODIMP_(type) type WINAPI +#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE +#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE +#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE +#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE + + typedef char CCHAR; +#ifndef _LCID_DEFINED +#define _LCID_DEFINED +typedef DWORD LCID; +#endif + typedef PDWORD PLCID; +#ifndef _LANGID_DEFINED +#define _LANGID_DEFINED + typedef WORD LANGID; +#endif +#define APPLICATION_ERROR_MASK 0x20000000 +#define ERROR_SEVERITY_SUCCESS 0x00000000 +#define ERROR_SEVERITY_INFORMATIONAL 0x40000000 +#define ERROR_SEVERITY_WARNING 0x80000000 +#define ERROR_SEVERITY_ERROR 0xC0000000 + +#ifdef __ia64__ + __declspec(align(16)) +#endif + typedef struct _FLOAT128 { + __int64 LowPart; + __int64 HighPart; + } FLOAT128; + + typedef FLOAT128 *PFLOAT128; + +#define _ULONGLONG_ +#if((!(defined(_X86_) && !defined(__x86_64)) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64))) + typedef __int64 LONGLONG; + typedef unsigned __int64 ULONGLONG; + +#define MAXLONGLONG (0x7fffffffffffffff) +#else + + typedef double LONGLONG; + typedef double ULONGLONG; +#endif + + typedef LONGLONG *PLONGLONG; + typedef ULONGLONG *PULONGLONG; + + typedef LONGLONG USN; + + typedef union _LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + }; + struct { + DWORD LowPart; + LONG HighPart; + } u; + LONGLONG QuadPart; + } LARGE_INTEGER; + + typedef LARGE_INTEGER *PLARGE_INTEGER; + + typedef union _ULARGE_INTEGER { + struct { + DWORD LowPart; + DWORD HighPart; + }; + struct { + DWORD LowPart; + DWORD HighPart; + } u; + ULONGLONG QuadPart; + } ULARGE_INTEGER; + + typedef ULARGE_INTEGER *PULARGE_INTEGER; + + typedef struct _LUID { + DWORD LowPart; + LONG HighPart; + } LUID,*PLUID; + +#define _DWORDLONG_ + typedef ULONGLONG DWORDLONG; + typedef DWORDLONG *PDWORDLONG; + +#ifdef RC_INVOKED +#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) +#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) +#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) +#elif (defined(_X86_) && !defined(__x86_64)) +#define Int32x32To64(a,b) (LONGLONG)((LONGLONG)(LONG)(a) *(LONG)(b)) +#define UInt32x32To64(a,b) (ULONGLONG)((ULONGLONG)(DWORD)(a) *(DWORD)(b)) +#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(b)) +#elif defined(__ia64__) || defined(__x86_64) +#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) +#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) +#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) +#else +#error Must define a target architecture. +#endif + +#define Int64ShraMod32(a,b) ((LONGLONG)(a) >> (b)) +#define Int64ShllMod32(a,b) ((ULONGLONG)(a) << (b)) + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __x86_64 + +#define RotateLeft8 _rotl8 +#define RotateLeft16 _rotl16 +#define RotateRight8 _rotr8 +#define RotateRight16 _rotr16 + + unsigned char __cdecl _rotl8(unsigned char Value,unsigned char Shift); + unsigned short __cdecl _rotl16(unsigned short Value,unsigned char Shift); + unsigned char __cdecl _rotr8(unsigned char Value,unsigned char Shift); + unsigned short __cdecl _rotr16(unsigned short Value,unsigned char Shift); +#endif + +#define RotateLeft32 _rotl +#define RotateLeft64 _rotl64 +#define RotateRight32 _rotr +#define RotateRight64 _rotr64 + + unsigned int __cdecl _rotl(unsigned int Value,int Shift); + unsigned __int64 __cdecl _rotl64(unsigned __int64 Value,int Shift); + unsigned int __cdecl _rotr(unsigned int Value,int Shift); + unsigned __int64 __cdecl _rotr64(unsigned __int64 Value,int Shift); +#ifdef __cplusplus + } +#endif + +#define ANSI_NULL ((CHAR)0) +#define UNICODE_NULL ((WCHAR)0) +#define UNICODE_STRING_MAX_BYTES ((WORD) 65534) +#define UNICODE_STRING_MAX_CHARS (32767) + +#ifndef _BOOLEAN_ +#define _BOOLEAN_ + typedef BYTE BOOLEAN; +#endif + typedef BOOLEAN *PBOOLEAN; + + typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; + } LIST_ENTRY,*PLIST_ENTRY,*RESTRICTED_POINTER PRLIST_ENTRY; + + typedef struct _SINGLE_LIST_ENTRY { + struct _SINGLE_LIST_ENTRY *Next; + } SINGLE_LIST_ENTRY,*PSINGLE_LIST_ENTRY; + + typedef struct LIST_ENTRY32 { + DWORD Flink; + DWORD Blink; + } LIST_ENTRY32; + typedef LIST_ENTRY32 *PLIST_ENTRY32; + + typedef struct LIST_ENTRY64 { + ULONGLONG Flink; + ULONGLONG Blink; + } LIST_ENTRY64; + typedef LIST_ENTRY64 *PLIST_ENTRY64; + +#include + +#ifndef __OBJECTID_DEFINED +#define __OBJECTID_DEFINED + typedef struct _OBJECTID { + GUID Lineage; + DWORD Uniquifier; + } OBJECTID; +#endif + +#define MINCHAR 0x80 +#define MAXCHAR 0x7f +#define MINSHORT 0x8000 +#define MAXSHORT 0x7fff +#define MINLONG 0x80000000 +#define MAXLONG 0x7fffffff +#define MAXBYTE 0xff +#define MAXWORD 0xffff +#define MAXDWORD 0xffffffff + +#define FIELD_OFFSET(type,field) ((LONG)(LONG_PTR)&(((type *)0)->field)) +#define RTL_FIELD_SIZE(type,field) (sizeof(((type *)0)->field)) +#define RTL_SIZEOF_THROUGH_FIELD(type,field) (FIELD_OFFSET(type,field) + RTL_FIELD_SIZE(type,field)) +#define RTL_CONTAINS_FIELD(Struct,Size,Field) ((((PCHAR)(&(Struct)->Field)) + sizeof((Struct)->Field)) <= (((PCHAR)(Struct))+(Size))) +#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) +#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A) + +#ifdef ENABLE_RTL_NUMBER_OF_V2 +#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V2(A) +#else +#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V1(A) +#endif + +#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A) +#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) + +#define RTL_FIELD_TYPE(type,field) (((type*)0)->field) +#define RTL_NUMBER_OF_FIELD(type,field) (RTL_NUMBER_OF(RTL_FIELD_TYPE(type,field))) +#define RTL_PADDING_BETWEEN_FIELDS(T,F1,F2) ((FIELD_OFFSET(T,F2) > FIELD_OFFSET(T,F1)) ? (FIELD_OFFSET(T,F2) - FIELD_OFFSET(T,F1) - RTL_FIELD_SIZE(T,F1)) : (FIELD_OFFSET(T,F1) - FIELD_OFFSET(T,F2) - RTL_FIELD_SIZE(T,F2))) + +#ifdef __cplusplus +#define RTL_CONST_CAST(type) const_cast +#else +#define RTL_CONST_CAST(type) (type) +#endif + +#define RTL_BITS_OF(sizeOfArg) (sizeof(sizeOfArg) *8) +#define RTL_BITS_OF_FIELD(type,field) (RTL_BITS_OF(RTL_FIELD_TYPE(type,field))) +#define CONTAINING_RECORD(address,type,field) ((type *)((PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field))) + +#define VER_SERVER_NT 0x80000000 +#define VER_WORKSTATION_NT 0x40000000 +#define VER_SUITE_SMALLBUSINESS 0x00000001 +#define VER_SUITE_ENTERPRISE 0x00000002 +#define VER_SUITE_BACKOFFICE 0x00000004 +#define VER_SUITE_COMMUNICATIONS 0x00000008 +#define VER_SUITE_TERMINAL 0x00000010 +#define VER_SUITE_SMALLBUSINESS_RESTRICTED 0x00000020 +#define VER_SUITE_EMBEDDEDNT 0x00000040 +#define VER_SUITE_DATACENTER 0x00000080 +#define VER_SUITE_SINGLEUSERTS 0x00000100 +#define VER_SUITE_PERSONAL 0x00000200 +#define VER_SUITE_BLADE 0x00000400 +#define VER_SUITE_EMBEDDED_RESTRICTED 0x00000800 +#define VER_SUITE_SECURITY_APPLIANCE 0x00001000 +#define VER_SUITE_STORAGE_SERVER 0x00002000 +#define VER_SUITE_COMPUTE_SERVER 0x00004000 + +#define PRODUCT_UNDEFINED 0x0 + +#define PRODUCT_ULTIMATE 0x1 +#define PRODUCT_HOME_BASIC 0x2 +#define PRODUCT_HOME_PREMIUM 0x3 +#define PRODUCT_ENTERPRISE 0x4 +#define PRODUCT_HOME_BASIC_N 0x5 +#define PRODUCT_BUSINESS 0x6 +#define PRODUCT_STANDARD_SERVER 0x7 +#define PRODUCT_DATACENTER_SERVER 0x8 +#define PRODUCT_SMALLBUSINESS_SERVER 0x9 +#define PRODUCT_ENTERPRISE_SERVER 0xa +#define PRODUCT_STARTER 0xb +#define PRODUCT_DATACENTER_SERVER_CORE 0xc +#define PRODUCT_STANDARD_SERVER_CORE 0xd +#define PRODUCT_ENTERPRISE_SERVER_CORE 0xe +#define PRODUCT_ENTERPRISE_SERVER_IA64 0xf +#define PRODUCT_BUSINESS_N 0x10 +#define PRODUCT_WEB_SERVER 0x11 +#define PRODUCT_CLUSTER_SERVER 0x12 +#define PRODUCT_HOME_SERVER 0x13 +#define PRODUCT_STORAGE_EXPRESS_SERVER 0x14 +#define PRODUCT_STORAGE_STANDARD_SERVER 0x15 +#define PRODUCT_STORAGE_WORKGROUP_SERVER 0x16 +#define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x17 +#define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x18 +#define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x19 + +#define PRODUCT_UNLICENSED 0xabcdabcd + +#define LANG_NEUTRAL 0x00 +#define LANG_INVARIANT 0x7f + +#define LANG_AFRIKAANS 0x36 +#define LANG_ALBANIAN 0x1c +#define LANG_ALSATIAN 0x84 +#define LANG_AMHARIC 0x5e +#define LANG_ARABIC 0x01 +#define LANG_ARMENIAN 0x2b +#define LANG_ASSAMESE 0x4d +#define LANG_AZERI 0x2c +#define LANG_BASHKIR 0x6d +#define LANG_BASQUE 0x2d +#define LANG_BELARUSIAN 0x23 +#define LANG_BENGALI 0x45 +#define LANG_BRETON 0x7e +#define LANG_BOSNIAN 0x1a +#define LANG_BOSNIAN_NEUTRAL 0x781a +#define LANG_BULGARIAN 0x02 +#define LANG_CATALAN 0x03 +#define LANG_CHINESE 0x04 +#define LANG_CHINESE_SIMPLIFIED 0x04 +#define LANG_CHINESE_TRADITIONAL 0x7c04 +#define LANG_CORSICAN 0x83 +#define LANG_CROATIAN 0x1a +#define LANG_CZECH 0x05 +#define LANG_DANISH 0x06 +#define LANG_DARI 0x8c +#define LANG_DIVEHI 0x65 +#define LANG_DUTCH 0x13 +#define LANG_ENGLISH 0x09 +#define LANG_ESTONIAN 0x25 +#define LANG_FAEROESE 0x38 +#define LANG_FARSI 0x29 +#define LANG_FILIPINO 0x64 +#define LANG_FINNISH 0x0b +#define LANG_FRENCH 0x0c +#define LANG_FRISIAN 0x62 +#define LANG_GALICIAN 0x56 +#define LANG_GEORGIAN 0x37 +#define LANG_GERMAN 0x07 +#define LANG_GREEK 0x08 +#define LANG_GREENLANDIC 0x6f +#define LANG_GUJARATI 0x47 +#define LANG_HAUSA 0x68 +#define LANG_HEBREW 0x0d +#define LANG_HINDI 0x39 +#define LANG_HUNGARIAN 0x0e +#define LANG_ICELANDIC 0x0f +#define LANG_IGBO 0x70 +#define LANG_INDONESIAN 0x21 +#define LANG_INUKTITUT 0x5d +#define LANG_IRISH 0x3c +#define LANG_ITALIAN 0x10 +#define LANG_JAPANESE 0x11 +#define LANG_KANNADA 0x4b +#define LANG_KASHMIRI 0x60 +#define LANG_KAZAK 0x3f +#define LANG_KHMER 0x53 +#define LANG_KICHE 0x86 +#define LANG_KINYARWANDA 0x87 +#define LANG_KONKANI 0x57 +#define LANG_KOREAN 0x12 +#define LANG_KYRGYZ 0x40 +#define LANG_LAO 0x54 +#define LANG_LATVIAN 0x26 +#define LANG_LITHUANIAN 0x27 +#define LANG_LOWER_SORBIAN 0x2e +#define LANG_LUXEMBOURGISH 0x6e +#define LANG_MACEDONIAN 0x2f +#define LANG_MALAY 0x3e +#define LANG_MALAYALAM 0x4c +#define LANG_MALTESE 0x3a +#define LANG_MANIPURI 0x58 +#define LANG_MAORI 0x81 +#define LANG_MAPUDUNGUN 0x7a +#define LANG_MARATHI 0x4e +#define LANG_MOHAWK 0x7c +#define LANG_MONGOLIAN 0x50 +#define LANG_NEPALI 0x61 +#define LANG_NORWEGIAN 0x14 +#define LANG_OCCITAN 0x82 +#define LANG_ORIYA 0x48 +#define LANG_PASHTO 0x63 +#define LANG_PERSIAN 0x29 +#define LANG_POLISH 0x15 +#define LANG_PORTUGUESE 0x16 +#define LANG_PUNJABI 0x46 +#define LANG_QUECHUA 0x6b +#define LANG_ROMANIAN 0x18 +#define LANG_RUSSIAN 0x19 +#define LANG_SAMI 0x3b +#define LANG_ROMANSH 0x17 +#define LANG_SANSKRIT 0x4f +#define LANG_SERBIAN 0x1a +#define LANG_SERBIAN_NEUTRAL 0x7c1a +#define LANG_SINDHI 0x59 +#define LANG_SINHALESE 0x5b +#define LANG_SLOVAK 0x1b +#define LANG_SLOVENIAN 0x24 +#define LANG_SOTHO 0x6c +#define LANG_SPANISH 0x0a +#define LANG_SWAHILI 0x41 +#define LANG_SWEDISH 0x1d +#define LANG_SYRIAC 0x5a +#define LANG_TAJIK 0x28 +#define LANG_TAMAZIGHT 0x5f +#define LANG_TAMIL 0x49 +#define LANG_TATAR 0x44 +#define LANG_TELUGU 0x4a +#define LANG_THAI 0x1e +#define LANG_TIBETAN 0x51 +#define LANG_TIGRIGNA 0x73 +#define LANG_TSWANA 0x32 +#define LANG_TURKISH 0x1f +#define LANG_TURKMEN 0x42 +#define LANG_UIGHUR 0x80 +#define LANG_UKRAINIAN 0x22 +#define LANG_UPPER_SORBIAN 0x2e +#define LANG_URDU 0x20 +#define LANG_UZBEK 0x43 +#define LANG_VIETNAMESE 0x2a +#define LANG_WELSH 0x52 +#define LANG_WOLOF 0x88 +#define LANG_XHOSA 0x34 +#define LANG_YAKUT 0x85 +#define LANG_YI 0x78 +#define LANG_YORUBA 0x6a +#define LANG_ZULU 0x35 + +#define SUBLANG_NEUTRAL 0x0 +#define SUBLANG_DEFAULT 0x1 +#define SUBLANG_SYS_DEFAULT 0x2 +#define SUBLANG_CUSTOM_DEFAULT 0x3 +#define SUBLANG_CUSTOM_UNSPECIFIED 0x4 +#define SUBLANG_UI_CUSTOM_DEFAULT 0x5 + +#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 +#define SUBLANG_ARABIC_IRAQ 0x02 +#define SUBLANG_ARABIC_EGYPT 0x03 +#define SUBLANG_ARABIC_LIBYA 0x04 +#define SUBLANG_ARABIC_ALGERIA 0x05 +#define SUBLANG_ARABIC_MOROCCO 0x06 +#define SUBLANG_ARABIC_TUNISIA 0x07 +#define SUBLANG_ARABIC_OMAN 0x08 +#define SUBLANG_ARABIC_YEMEN 0x09 +#define SUBLANG_ARABIC_SYRIA 0x0a +#define SUBLANG_ARABIC_JORDAN 0x0b +#define SUBLANG_ARABIC_LEBANON 0x0c +#define SUBLANG_ARABIC_KUWAIT 0x0d +#define SUBLANG_ARABIC_UAE 0x0e +#define SUBLANG_ARABIC_BAHRAIN 0x0f +#define SUBLANG_ARABIC_QATAR 0x10 +#define SUBLANG_AZERI_LATIN 0x01 +#define SUBLANG_AZERI_CYRILLIC 0x02 +#define SUBLANG_CHINESE_TRADITIONAL 0x01 +#define SUBLANG_CHINESE_SIMPLIFIED 0x02 +#define SUBLANG_CHINESE_HONGKONG 0x03 +#define SUBLANG_CHINESE_SINGAPORE 0x04 +#define SUBLANG_CHINESE_MACAU 0x05 +#define SUBLANG_DUTCH 0x01 +#define SUBLANG_DUTCH_BELGIAN 0x02 +#define SUBLANG_ENGLISH_US 0x01 +#define SUBLANG_ENGLISH_UK 0x02 +#define SUBLANG_ENGLISH_AUS 0x03 +#define SUBLANG_ENGLISH_CAN 0x04 +#define SUBLANG_ENGLISH_NZ 0x05 +#define SUBLANG_ENGLISH_EIRE 0x06 +#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 +#define SUBLANG_ENGLISH_JAMAICA 0x08 +#define SUBLANG_ENGLISH_CARIBBEAN 0x09 +#define SUBLANG_ENGLISH_BELIZE 0x0a +#define SUBLANG_ENGLISH_TRINIDAD 0x0b +#define SUBLANG_ENGLISH_ZIMBABWE 0x0c +#define SUBLANG_ENGLISH_PHILIPPINES 0x0d +#define SUBLANG_FRENCH 0x01 +#define SUBLANG_FRENCH_BELGIAN 0x02 +#define SUBLANG_FRENCH_CANADIAN 0x03 +#define SUBLANG_FRENCH_SWISS 0x04 +#define SUBLANG_FRENCH_LUXEMBOURG 0x05 +#define SUBLANG_FRENCH_MONACO 0x06 +#define SUBLANG_GERMAN 0x01 +#define SUBLANG_GERMAN_SWISS 0x02 +#define SUBLANG_GERMAN_AUSTRIAN 0x03 +#define SUBLANG_GERMAN_LUXEMBOURG 0x04 +#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 +#define SUBLANG_ITALIAN 0x01 +#define SUBLANG_ITALIAN_SWISS 0x02 +#define SUBLANG_KASHMIRI_SASIA 0x02 +#define SUBLANG_KASHMIRI_INDIA 0x02 +#define SUBLANG_KOREAN 0x01 +#define SUBLANG_LITHUANIAN 0x01 +#define SUBLANG_MALAY_MALAYSIA 0x01 +#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 +#define SUBLANG_NEPALI_INDIA 0x02 +#define SUBLANG_NORWEGIAN_BOKMAL 0x01 +#define SUBLANG_NORWEGIAN_NYNORSK 0x02 +#define SUBLANG_PORTUGUESE 0x02 +#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01 +#define SUBLANG_SERBIAN_LATIN 0x02 +#define SUBLANG_SERBIAN_CYRILLIC 0x03 +#define SUBLANG_SPANISH 0x01 +#define SUBLANG_SPANISH_MEXICAN 0x02 +#define SUBLANG_SPANISH_MODERN 0x03 +#define SUBLANG_SPANISH_GUATEMALA 0x04 +#define SUBLANG_SPANISH_COSTA_RICA 0x05 +#define SUBLANG_SPANISH_PANAMA 0x06 +#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 +#define SUBLANG_SPANISH_VENEZUELA 0x08 +#define SUBLANG_SPANISH_COLOMBIA 0x09 +#define SUBLANG_SPANISH_PERU 0x0a +#define SUBLANG_SPANISH_ARGENTINA 0x0b +#define SUBLANG_SPANISH_ECUADOR 0x0c +#define SUBLANG_SPANISH_CHILE 0x0d +#define SUBLANG_SPANISH_URUGUAY 0x0e +#define SUBLANG_SPANISH_PARAGUAY 0x0f +#define SUBLANG_SPANISH_BOLIVIA 0x10 +#define SUBLANG_SPANISH_EL_SALVADOR 0x11 +#define SUBLANG_SPANISH_HONDURAS 0x12 +#define SUBLANG_SPANISH_NICARAGUA 0x13 +#define SUBLANG_SPANISH_PUERTO_RICO 0x14 +#define SUBLANG_SWEDISH 0x01 +#define SUBLANG_SWEDISH_FINLAND 0x02 +#define SUBLANG_URDU_PAKISTAN 0x01 +#define SUBLANG_URDU_INDIA 0x02 +#define SUBLANG_UZBEK_LATIN 0x01 +#define SUBLANG_UZBEK_CYRILLIC 0x02 + +#define SORT_DEFAULT 0x0 +#define SORT_INVARIANT_MATH 0x1 + +#define SORT_JAPANESE_XJIS 0x0 +#define SORT_JAPANESE_UNICODE 0x1 +#define SORT_JAPANESE_RADICALSTROKE 0x4 + +#define SORT_CHINESE_BIG5 0x0 +#define SORT_CHINESE_PRCP 0x0 +#define SORT_CHINESE_UNICODE 0x1 +#define SORT_CHINESE_PRC 0x2 +#define SORT_CHINESE_BOPOMOFO 0x3 + +#define SORT_KOREAN_KSC 0x0 +#define SORT_KOREAN_UNICODE 0x1 + +#define SORT_GERMAN_PHONE_BOOK 0x1 + +#define SORT_HUNGARIAN_DEFAULT 0x0 +#define SORT_HUNGARIAN_TECHNICAL 0x1 + +#define SORT_GEORGIAN_TRADITIONAL 0x0 +#define SORT_GEORGIAN_MODERN 0x1 + +#define MAKELANGID(p,s) ((((WORD)(s)) << 10) | (WORD)(p)) +#define PRIMARYLANGID(lgid) ((WORD)(lgid) & 0x3ff) +#define SUBLANGID(lgid) ((WORD)(lgid) >> 10) + +#define NLS_VALID_LOCALE_MASK 0x000fffff + +#define MAKELCID(lgid,srtid) ((DWORD)((((DWORD)((WORD)(srtid))) << 16) | ((DWORD)((WORD)(lgid))))) +#define MAKESORTLCID(lgid,srtid,ver) ((DWORD)((MAKELCID(lgid,srtid)) | (((DWORD)((WORD)(ver))) << 20))) +#define LANGIDFROMLCID(lcid) ((WORD)(lcid)) +#define SORTIDFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 16) & 0xf)) +#define SORTVERSIONFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 20) & 0xf)) + +#define LOCALE_NAME_MAX_LENGTH 85 +#define LANG_SYSTEM_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT)) +#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)) + +#define LOCALE_SYSTEM_DEFAULT (MAKELCID(LANG_SYSTEM_DEFAULT,SORT_DEFAULT)) +#define LOCALE_USER_DEFAULT (MAKELCID(LANG_USER_DEFAULT,SORT_DEFAULT)) + +#define LOCALE_NEUTRAL (MAKELCID(MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),SORT_DEFAULT)) + +#define LOCALE_CUSTOM_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), SORT_DEFAULT)) +#define LOCALE_CUSTOM_UNSPECIFIED (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED), SORT_DEFAULT)) +#define LOCALE_CUSTOM_UI_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT), SORT_DEFAULT)) + +#define LOCALE_INVARIANT (MAKELCID(MAKELANGID(LANG_INVARIANT,SUBLANG_NEUTRAL),SORT_DEFAULT)) + +#define UNREFERENCED_PARAMETER(P) (P) +#define DBG_UNREFERENCED_PARAMETER(P) (P) +#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (V) + +#define DEFAULT_UNREACHABLE + +#ifndef WIN32_NO_STATUS +#define STATUS_WAIT_0 ((DWORD)0x00000000L) +#define STATUS_ABANDONED_WAIT_0 ((DWORD)0x00000080L) +#define STATUS_USER_APC ((DWORD)0x000000C0L) +#define STATUS_TIMEOUT ((DWORD)0x00000102L) +#define STATUS_PENDING ((DWORD)0x00000103L) +#define DBG_EXCEPTION_HANDLED ((DWORD)0x00010001L) +#define DBG_CONTINUE ((DWORD)0x00010002L) +#define STATUS_SEGMENT_NOTIFICATION ((DWORD)0x40000005L) +#define DBG_TERMINATE_THREAD ((DWORD)0x40010003L) +#define DBG_TERMINATE_PROCESS ((DWORD)0x40010004L) +#define DBG_CONTROL_C ((DWORD)0x40010005L) +#define DBG_CONTROL_BREAK ((DWORD)0x40010008L) +#define DBG_COMMAND_EXCEPTION ((DWORD)0x40010009L) +#define STATUS_GUARD_PAGE_VIOLATION ((DWORD)0x80000001L) +#define STATUS_DATATYPE_MISALIGNMENT ((DWORD)0x80000002L) +#define STATUS_BREAKPOINT ((DWORD)0x80000003L) +#define STATUS_SINGLE_STEP ((DWORD)0x80000004L) +#define DBG_EXCEPTION_NOT_HANDLED ((DWORD)0x80010001L) +#define STATUS_ACCESS_VIOLATION ((DWORD)0xC0000005L) +#define STATUS_IN_PAGE_ERROR ((DWORD)0xC0000006L) +#define STATUS_INVALID_HANDLE ((DWORD)0xC0000008L) +#define STATUS_NO_MEMORY ((DWORD)0xC0000017L) +#define STATUS_ILLEGAL_INSTRUCTION ((DWORD)0xC000001DL) +#define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD)0xC0000025L) +#define STATUS_INVALID_DISPOSITION ((DWORD)0xC0000026L) +#define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD)0xC000008CL) +#define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD)0xC000008DL) +#define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD)0xC000008EL) +#define STATUS_FLOAT_INEXACT_RESULT ((DWORD)0xC000008FL) +#define STATUS_FLOAT_INVALID_OPERATION ((DWORD)0xC0000090L) +#define STATUS_FLOAT_OVERFLOW ((DWORD)0xC0000091L) +#define STATUS_FLOAT_STACK_CHECK ((DWORD)0xC0000092L) +#define STATUS_FLOAT_UNDERFLOW ((DWORD)0xC0000093L) +#define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD)0xC0000094L) +#define STATUS_INTEGER_OVERFLOW ((DWORD)0xC0000095L) +#define STATUS_PRIVILEGED_INSTRUCTION ((DWORD)0xC0000096L) +#define STATUS_STACK_OVERFLOW ((DWORD)0xC00000FDL) +#define STATUS_CONTROL_C_EXIT ((DWORD)0xC000013AL) +#define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD)0xC00002B4L) +#define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD)0xC00002B5L) +#define STATUS_REG_NAT_CONSUMPTION ((DWORD)0xC00002C9L) +#define STATUS_SXS_EARLY_DEACTIVATION ((DWORD)0xC015000FL) +#define STATUS_SXS_INVALID_DEACTIVATION ((DWORD)0xC0150010L) +#endif + +#define MAXIMUM_WAIT_OBJECTS 64 +#define MAXIMUM_SUSPEND_COUNT MAXCHAR + + typedef ULONG_PTR KSPIN_LOCK; + typedef KSPIN_LOCK *PKSPIN_LOCK; + +#ifdef _AMD64_ + +#if defined(__x86_64) && !defined(RC_INVOKED) + +#ifdef __cplusplus + extern "C" { +#endif + +#define BitTest _bittest +#define BitTestAndComplement _bittestandcomplement +#define BitTestAndSet _bittestandset +#define BitTestAndReset _bittestandreset +#define InterlockedBitTestAndSet _interlockedbittestandset +#define InterlockedBitTestAndReset _interlockedbittestandreset +#define BitTest64 _bittest64 +#define BitTestAndComplement64 _bittestandcomplement64 +#define BitTestAndSet64 _bittestandset64 +#define BitTestAndReset64 _bittestandreset64 +#define InterlockedBitTestAndSet64 _interlockedbittestandset64 +#define InterlockedBitTestAndReset64 _interlockedbittestandreset64 + + __CRT_INLINE BOOLEAN _bittest(LONG const *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandcomplement(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandreset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandreset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittest64(LONG64 const *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandcomplement64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btcq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btsq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandreset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btrq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("lock ; btsq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandreset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("lock ; btrq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } +#define BitScanForward _BitScanForward +#define BitScanReverse _BitScanReverse +#define BitScanForward64 _BitScanForward64 +#define BitScanReverse64 _BitScanReverse64 + + __CRT_INLINE BOOLEAN _BitScanForward(DWORD *Index,DWORD Mask) { + __asm__ __volatile__("bsfl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); + return Mask!=0; + } + __CRT_INLINE BOOLEAN _BitScanReverse(DWORD *Index,DWORD Mask) { + __asm__ __volatile__("bsrl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); + return Mask!=0; + } + __CRT_INLINE BOOLEAN _BitScanForward64(DWORD *Index,DWORD64 Mask) { + __asm__ __volatile__("bsfq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); + return Mask!=0; + } + __CRT_INLINE BOOLEAN _BitScanReverse64(DWORD *Index,DWORD64 Mask) { + __asm__ __volatile__("bsrq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); + return Mask!=0; + } + +#define InterlockedIncrement16 _InterlockedIncrement16 +#define InterlockedDecrement16 _InterlockedDecrement16 +#define InterlockedCompareExchange16 _InterlockedCompareExchange16 + +#define InterlockedAnd _InterlockedAnd +#define InterlockedOr _InterlockedOr +#define InterlockedXor _InterlockedXor +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedDecrement _InterlockedDecrement +#define InterlockedDecrementAcquire InterlockedDecrement +#define InterlockedDecrementRelease InterlockedDecrement +#define InterlockedAdd _InterlockedAdd +#define InterlockedExchange _InterlockedExchange +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire InterlockedCompareExchange +#define InterlockedCompareExchangeRelease InterlockedCompareExchange + +#define InterlockedAnd64 _InterlockedAnd64 +#define InterlockedAndAffinity InterlockedAnd64 +#define InterlockedOr64 _InterlockedOr64 +#define InterlockedOrAffinity InterlockedOr64 +#define InterlockedXor64 _InterlockedXor64 +#define InterlockedIncrement64 _InterlockedIncrement64 +#define InterlockedDecrement64 _InterlockedDecrement64 +#define InterlockedAdd64 _InterlockedAdd64 +#define InterlockedExchange64 _InterlockedExchange64 +#define InterlockedExchangeAcquire64 InterlockedExchange64 +#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 +#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 +#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 + +#define InterlockedExchangePointer _InterlockedExchangePointer +#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer + +#define InterlockedExchangeAddSizeT(a,b) InterlockedExchangeAdd64((LONG64 *)a,b) +#define InterlockedIncrementSizeT(a) InterlockedIncrement64((LONG64 *)a) +#define InterlockedDecrementSizeT(a) InterlockedDecrement64((LONG64 *)a) + + __CRT_INLINE SHORT InterlockedIncrement16(SHORT volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; addw $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE SHORT InterlockedDecrement16(SHORT volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; subw $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE SHORT InterlockedCompareExchange16(SHORT volatile *Destination,SHORT ExChange,SHORT Comperand) { + SHORT prev; + __asm__ __volatile__("lock ; cmpxchgw %w1,%2" + :"=a"(prev) + :"q"(ExChange), "m"(*Destination), "0"(Comperand) + : "memory"); + return prev; + } + __CRT_INLINE LONG InterlockedAnd(LONG volatile *Destination,LONG Value) { + __asm__ __volatile__("lock ; andl %0,%1" + : :"r"(Value),"m"(*Destination) + : "memory"); + return *Destination; + } + __CRT_INLINE LONG InterlockedOr(LONG volatile *Destination,LONG Value) { + __asm__ __volatile__("lock ; orl %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG InterlockedXor(LONG volatile *Destination,LONG Value) { + __asm__ __volatile__("lock ; xorl %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + // $$$$ + __CRT_INLINE LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value) { + __asm__ __volatile__("lock ; andq %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value) { + __asm__ __volatile__("lock ; orq %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value) { + __asm__ __volatile__("lock ; xorq %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG InterlockedIncrement(LONG volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; addl $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG InterlockedDecrement(LONG volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; subl $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG InterlockedExchange(LONG volatile *Target,LONG Value) { + __asm__ __volatile("lock ; xchgl %0,%1" + : "=r"(Value) + : "m"(*Target),"0"(Value) + : "memory"); + return Value; + } + LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + +#ifndef _X86AMD64_ + __CRT_INLINE LONG InterlockedAdd(LONG volatile *Addend,LONG Value) { return InterlockedExchangeAdd(Addend,Value) + Value; } +#endif + __CRT_INLINE LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand) { + LONG prev; + __asm__ __volatile__("lock ; cmpxchgl %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); + return prev; + } + __CRT_INLINE LONG64 InterlockedIncrement64(LONG64 volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; addq $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG64 InterlockedDecrement64(LONG64 volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; subq $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value) { + __asm__ __volatile("lock ; xchgq %0,%1" + : "=r"(Value) + : "m"(*Target),"0"(Value) + : "memory"); + return Value; + } + LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); + +#ifndef _X86AMD64_ + __CRT_INLINE LONG64 InterlockedAdd64(LONG64 volatile *Addend,LONG64 Value) { return InterlockedExchangeAdd64(Addend,Value) + Value; } +#endif + + __CRT_INLINE LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand) { + LONG64 prev; + __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); + return prev; + } + __CRT_INLINE PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { + PVOID prev; + __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); + return prev; + } + __CRT_INLINE PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value) { + __asm__ __volatile("lock ; xchgq %0,%1" + : "=r"(Value) + : "m"(*Target),"0"(Value) + : "memory"); + return Value; + } + +#define CacheLineFlush(Address) _mm_clflush(Address) + + VOID _ReadWriteBarrier(VOID); + +#define FastFence __faststorefence +#define LoadFence _mm_lfence +#define MemoryFence _mm_mfence +#define StoreFence _mm_sfence + + VOID __faststorefence(VOID); + VOID _m_prefetchw(volatile CONST VOID *Source); + +//!__TINYC__: #include + +#define YieldProcessor _mm_pause +#define MemoryBarrier __faststorefence +#define PreFetchCacheLine(l,a) _mm_prefetch((CHAR CONST *) a,l) +#define PrefetchForWrite(p) _m_prefetchw(p) +#define ReadForWriteAccess(p) (_m_prefetchw(p),*(p)) + +#define PF_TEMPORAL_LEVEL_1 _MM_HINT_T0 +#define PF_TEMPORAL_LEVEL_2 _MM_HINT_T1 +#define PF_TEMPORAL_LEVEL_3 _MM_HINT_T2 +#define PF_NON_TEMPORAL_LEVEL_ALL _MM_HINT_NTA + +#define ReadMxCsr _mm_getcsr +#define WriteMxCsr _mm_setcsr + + VOID __int2c(VOID); + +#define DbgRaiseAssertionFailure() __int2c() +#define GetCallersEflags() __getcallerseflags() + + unsigned __int32 __getcallerseflags(VOID); + +#define GetSegmentLimit __segmentlimit + + DWORD __segmentlimit(DWORD Selector); + +#define ReadTimeStampCounter() __rdtsc() + + DWORD64 __rdtsc(VOID); + VOID __movsb(PBYTE Destination,BYTE const *Source,SIZE_T Count); + VOID __movsw(PWORD Destination,WORD const *Source,SIZE_T Count); + VOID __movsd(PDWORD Destination,DWORD const *Source,SIZE_T Count); + VOID __movsq(PDWORD64 Destination,DWORD64 const *Source,SIZE_T Count); + VOID __stosb(PBYTE Destination,BYTE Value,SIZE_T Count); + VOID __stosw(PWORD Destination,WORD Value,SIZE_T Count); + VOID __stosd(PDWORD Destination,DWORD Value,SIZE_T Count); + VOID __stosq(PDWORD64 Destination,DWORD64 Value,SIZE_T Count); + +#define MultiplyHigh __mulh +#define UnsignedMultiplyHigh __umulh + + LONGLONG MultiplyHigh(LONGLONG Multiplier,LONGLONG Multiplicand); + ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); + +#define ShiftLeft128 __shiftleft128 +#define ShiftRight128 __shiftright128 + + DWORD64 ShiftLeft128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); + DWORD64 ShiftRight128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); + +#define Multiply128 _mul128 + + LONG64 Multiply128(LONG64 Multiplier,LONG64 Multiplicand,LONG64 *HighProduct); + +#define UnsignedMultiply128 _umul128 + + DWORD64 UnsignedMultiply128(DWORD64 Multiplier,DWORD64 Multiplicand,DWORD64 *HighProduct); + + __CRT_INLINE LONG64 MultiplyExtract128(LONG64 Multiplier,LONG64 Multiplicand,BYTE Shift) { + LONG64 extractedProduct; + LONG64 highProduct; + LONG64 lowProduct; + lowProduct = Multiply128(Multiplier,Multiplicand,&highProduct); + extractedProduct = (LONG64)ShiftRight128((LONG64)lowProduct,(LONG64)highProduct,Shift); + return extractedProduct; + } + + __CRT_INLINE DWORD64 UnsignedMultiplyExtract128(DWORD64 Multiplier,DWORD64 Multiplicand,BYTE Shift) { + DWORD64 extractedProduct; + DWORD64 highProduct; + DWORD64 lowProduct; + lowProduct = UnsignedMultiply128(Multiplier,Multiplicand,&highProduct); + extractedProduct = ShiftRight128(lowProduct,highProduct,Shift); + return extractedProduct; + } + + __CRT_INLINE BYTE __readgsbyte(DWORD Offset) { + BYTE ret; + __asm__ volatile ("movb %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return ret; + } + __CRT_INLINE WORD __readgsword(DWORD Offset) { + WORD ret; + __asm__ volatile ("movw %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return ret; + } + __CRT_INLINE DWORD __readgsdword(DWORD Offset) { + DWORD ret; + __asm__ volatile ("movl %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return ret; + } + __CRT_INLINE DWORD64 __readgsqword(DWORD Offset) { + void *ret; + __asm__ volatile ("movq %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return (DWORD64) ret; + } + __CRT_INLINE VOID __writegsbyte(DWORD Offset,BYTE Data) { + __asm__ volatile ("movb %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + __CRT_INLINE VOID __writegsword(DWORD Offset,WORD Data) { + __asm__ volatile ("movw %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + __CRT_INLINE VOID __writegsdword(DWORD Offset,DWORD Data) { + __asm__ volatile ("movl %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + __CRT_INLINE VOID __writegsqword(DWORD Offset,DWORD64 Data) { + __asm__ volatile ("movq %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + +#ifdef __cplusplus + } +#endif +#endif + +#define EXCEPTION_READ_FAULT 0 +#define EXCEPTION_WRITE_FAULT 1 +#define EXCEPTION_EXECUTE_FAULT 8 + +#if !defined(RC_INVOKED) + +#define CONTEXT_AMD64 0x100000 + +#define CONTEXT_CONTROL (CONTEXT_AMD64 | 0x1L) +#define CONTEXT_INTEGER (CONTEXT_AMD64 | 0x2L) +#define CONTEXT_SEGMENTS (CONTEXT_AMD64 | 0x4L) +#define CONTEXT_FLOATING_POINT (CONTEXT_AMD64 | 0x8L) +#define CONTEXT_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L) + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS) + +#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 +#define CONTEXT_SERVICE_ACTIVE 0x10000000 +#define CONTEXT_EXCEPTION_REQUEST 0x40000000 +#define CONTEXT_EXCEPTION_REPORTING 0x80000000 +#endif + +#define INITIAL_MXCSR 0x1f80 +#define INITIAL_FPCSR 0x027f + + typedef struct DECLSPEC_ALIGN(16) _M128A { + ULONGLONG Low; + LONGLONG High; + } M128A,*PM128A; + + typedef struct _XMM_SAVE_AREA32 { + WORD ControlWord; + WORD StatusWord; + BYTE TagWord; + BYTE Reserved1; + WORD ErrorOpcode; + DWORD ErrorOffset; + WORD ErrorSelector; + WORD Reserved2; + DWORD DataOffset; + WORD DataSelector; + WORD Reserved3; + DWORD MxCsr; + DWORD MxCsr_Mask; + M128A FloatRegisters[8]; + M128A XmmRegisters[16]; + BYTE Reserved4[96]; + } XMM_SAVE_AREA32,*PXMM_SAVE_AREA32; + +#define LEGACY_SAVE_AREA_LENGTH sizeof(XMM_SAVE_AREA32) + + typedef struct DECLSPEC_ALIGN(16) _CONTEXT { + DWORD64 P1Home; + DWORD64 P2Home; + DWORD64 P3Home; + DWORD64 P4Home; + DWORD64 P5Home; + DWORD64 P6Home; + DWORD ContextFlags; + DWORD MxCsr; + WORD SegCs; + WORD SegDs; + WORD SegEs; + WORD SegFs; + WORD SegGs; + WORD SegSs; + DWORD EFlags; + DWORD64 Dr0; + DWORD64 Dr1; + DWORD64 Dr2; + DWORD64 Dr3; + DWORD64 Dr6; + DWORD64 Dr7; + DWORD64 Rax; + DWORD64 Rcx; + DWORD64 Rdx; + DWORD64 Rbx; + DWORD64 Rsp; + DWORD64 Rbp; + DWORD64 Rsi; + DWORD64 Rdi; + DWORD64 R8; + DWORD64 R9; + DWORD64 R10; + DWORD64 R11; + DWORD64 R12; + DWORD64 R13; + DWORD64 R14; + DWORD64 R15; + DWORD64 Rip; + union { + XMM_SAVE_AREA32 FltSave; + XMM_SAVE_AREA32 FloatSave; + struct { + M128A Header[2]; + M128A Legacy[8]; + M128A Xmm0; + M128A Xmm1; + M128A Xmm2; + M128A Xmm3; + M128A Xmm4; + M128A Xmm5; + M128A Xmm6; + M128A Xmm7; + M128A Xmm8; + M128A Xmm9; + M128A Xmm10; + M128A Xmm11; + M128A Xmm12; + M128A Xmm13; + M128A Xmm14; + M128A Xmm15; + }; + }; + M128A VectorRegister[26]; + DWORD64 VectorControl; + DWORD64 DebugControl; + DWORD64 LastBranchToRip; + DWORD64 LastBranchFromRip; + DWORD64 LastExceptionToRip; + DWORD64 LastExceptionFromRip; + } CONTEXT,*PCONTEXT; + +#define RUNTIME_FUNCTION_INDIRECT 0x1 + + typedef struct _RUNTIME_FUNCTION { + DWORD BeginAddress; + DWORD EndAddress; + DWORD UnwindData; + } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; + + typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); + typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); + +#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" + + NTSYSAPI VOID __cdecl RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); + NTSYSAPI BOOLEAN __cdecl RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,DWORD64 BaseAddress); + NTSYSAPI BOOLEAN __cdecl RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); + NTSYSAPI BOOLEAN __cdecl RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); +#endif + +#ifdef I_X86_ +#if(defined(_X86_) && !defined(__x86_64)) && !defined(RC_INVOKED) +#ifdef __cplusplus + extern "C" { +#endif + + __CRT_INLINE BOOLEAN InterlockedBitTestAndSet(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + + __CRT_INLINE BOOLEAN InterlockedBitTestAndReset(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + + __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + +#ifdef _PREFIX_ + BYTE __readfsbyte(DWORD Offset); + WORD __readfsword(DWORD Offset); + DWORD __readfsdword(DWORD Offset); + VOID __writefsbyte(DWORD Offset,BYTE Data); + VOID __writefsword(DWORD Offset,WORD Data); + VOID __writefsdword(DWORD Offset,DWORD Data); +#endif + +#ifdef __cplusplus + } +#endif +#endif + +#if(defined(_X86_) && !defined(__x86_64)) + __CRT_INLINE VOID MemoryBarrier(VOID) { + LONG Barrier; + __asm__ __volatile__("xchgl %%eax,%0 " + :"=r" (Barrier)); + } +#define YieldProcessor() __asm__ __volatile__("rep nop "); + +#define PreFetchCacheLine(l,a) +#define ReadForWriteAccess(p) (*(p)) + +#define PF_TEMPORAL_LEVEL_1 +#define PF_NON_TEMPORAL_LEVEL_ALL + + __CRT_INLINE VOID DbgRaiseAssertionFailure(void) { + __asm__ __volatile__("int $0x2c "); + } + PVOID GetCurrentFiber(void); + __CRT_INLINE PVOID GetCurrentFiber(void) + { + void *ret; + __asm__ volatile ("movl %%fs:0x10,%0" + : "=r" (ret)); + return ret; + } + PVOID GetFiberData(void); + __CRT_INLINE PVOID GetFiberData(void) + { + void *ret; + __asm__ volatile ("movl %%fs:0x10,%0\n" + "movl (%0),%0" + : "=r" (ret)); + return ret; + } +#endif + +#define EXCEPTION_READ_FAULT 0 +#define EXCEPTION_WRITE_FAULT 1 +#define EXCEPTION_EXECUTE_FAULT 8 + +#define SIZE_OF_80387_REGISTERS 80 + +#if !defined(RC_INVOKED) + +#define CONTEXT_i386 0x00010000 +#define CONTEXT_i486 0x00010000 + +#define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) +#define CONTEXT_INTEGER (CONTEXT_i386 | 0x00000002L) +#define CONTEXT_SEGMENTS (CONTEXT_i386 | 0x00000004L) +#define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 0x00000008L) +#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) +#define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386 | 0x00000020L) + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) + +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS) +#endif + +#define MAXIMUM_SUPPORTED_EXTENSION 512 + + typedef struct _FLOATING_SAVE_AREA { + DWORD ControlWord; + DWORD StatusWord; + DWORD TagWord; + DWORD ErrorOffset; + DWORD ErrorSelector; + DWORD DataOffset; + DWORD DataSelector; + BYTE RegisterArea[SIZE_OF_80387_REGISTERS]; + DWORD Cr0NpxState; + } FLOATING_SAVE_AREA; + + typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA; + + typedef struct _CONTEXT { + DWORD ContextFlags; + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr6; + DWORD Dr7; + FLOATING_SAVE_AREA FloatSave; + DWORD SegGs; + DWORD SegFs; + DWORD SegEs; + DWORD SegDs; + + DWORD Edi; + DWORD Esi; + DWORD Ebx; + DWORD Edx; + DWORD Ecx; + DWORD Eax; + DWORD Ebp; + DWORD Eip; + DWORD SegCs; + DWORD EFlags; + DWORD Esp; + DWORD SegSs; + BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; + } CONTEXT; + + typedef CONTEXT *PCONTEXT; +#endif + +#ifndef _LDT_ENTRY_DEFINED +#define _LDT_ENTRY_DEFINED + + typedef struct _LDT_ENTRY { + WORD LimitLow; + WORD BaseLow; + union { + struct { + BYTE BaseMid; + BYTE Flags1; + BYTE Flags2; + BYTE BaseHi; + } Bytes; + struct { + DWORD BaseMid : 8; + DWORD Type : 5; + DWORD Dpl : 2; + DWORD Pres : 1; + DWORD LimitHi : 4; + DWORD Sys : 1; + DWORD Reserved_0 : 1; + DWORD Default_Big : 1; + DWORD Granularity : 1; + DWORD BaseHi : 8; + } Bits; + } HighWord; + } LDT_ENTRY,*PLDT_ENTRY; +#endif + +#if defined(__ia64__) && !defined(RC_INVOKED) + +#ifdef __cplusplus + extern "C" { +#endif + + BOOLEAN BitScanForward64(DWORD *Index,DWORD64 Mask); + BOOLEAN BitScanReverse64(DWORD *Index,DWORD64 Mask); + +#ifdef __cplusplus + } +#endif +#endif + +#if !defined(GENUTIL) && !defined(_GENIA64_) && defined(_IA64_) + + void *_cdecl _rdteb(void); +#ifdef __ia64__ + +#define NtCurrentTeb() ((struct _TEB *)_rdteb()) +#define GetCurrentFiber() (((PNT_TIB)NtCurrentTeb())->FiberData) +#define GetFiberData() (*(PVOID *)(GetCurrentFiber())) + +#ifdef __cplusplus + extern "C" { +#endif + + void __break(int); + void __yield(void); + void __mf(void); + void __lfetch(int Level,VOID CONST *Address); + void __lfetchfault(int Level,VOID CONST *Address); + void __lfetch_excl(int Level,VOID CONST *Address); + void __lfetchfault_excl(int Level,VOID CONST *Address); + +#define MD_LFHINT_NONE 0x00 +#define MD_LFHINT_NT1 0x01 +#define MD_LFHINT_NT2 0x02 +#define MD_LFHINT_NTA 0x03 + +#ifdef __cplusplus + } +#endif + +#define YieldProcessor __yield +#define MemoryBarrier __mf +#define PreFetchCacheLine __lfetch +#define ReadForWriteAccess(p) (*(p)) +#define DbgRaiseAssertionFailure() __break(ASSERT_BREAKPOINT) + +#define PF_TEMPORAL_LEVEL_1 MD_LFHINT_NONE +#define PF_NON_TEMPORAL_LEVEL_ALL MD_LFHINT_NTA + +#define UnsignedMultiplyHigh __UMULH + + ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); +#else + struct _TEB *NtCurrentTeb(void); +#endif +#endif + +#ifdef _IA64_ + +#define EXCEPTION_READ_FAULT 0 +#define EXCEPTION_WRITE_FAULT 1 +#define EXCEPTION_EXECUTE_FAULT 2 + +#if !defined(RC_INVOKED) + +#define CONTEXT_IA64 0x00080000 + +#define CONTEXT_CONTROL (CONTEXT_IA64 | 0x00000001L) +#define CONTEXT_LOWER_FLOATING_POINT (CONTEXT_IA64 | 0x00000002L) +#define CONTEXT_HIGHER_FLOATING_POINT (CONTEXT_IA64 | 0x00000004L) +#define CONTEXT_INTEGER (CONTEXT_IA64 | 0x00000008L) +#define CONTEXT_DEBUG (CONTEXT_IA64 | 0x00000010L) +#define CONTEXT_IA32_CONTROL (CONTEXT_IA64 | 0x00000020L) + +#define CONTEXT_FLOATING_POINT (CONTEXT_LOWER_FLOATING_POINT | CONTEXT_HIGHER_FLOATING_POINT) +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_IA32_CONTROL) +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_DEBUG | CONTEXT_IA32_CONTROL) + +#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 +#define CONTEXT_SERVICE_ACTIVE 0x10000000 +#define CONTEXT_EXCEPTION_REQUEST 0x40000000 +#define CONTEXT_EXCEPTION_REPORTING 0x80000000 +#endif + + typedef struct _CONTEXT { + DWORD ContextFlags; + DWORD Fill1[3]; + ULONGLONG DbI0; + ULONGLONG DbI1; + ULONGLONG DbI2; + ULONGLONG DbI3; + ULONGLONG DbI4; + ULONGLONG DbI5; + ULONGLONG DbI6; + ULONGLONG DbI7; + ULONGLONG DbD0; + ULONGLONG DbD1; + ULONGLONG DbD2; + ULONGLONG DbD3; + ULONGLONG DbD4; + ULONGLONG DbD5; + ULONGLONG DbD6; + ULONGLONG DbD7; + FLOAT128 FltS0; + FLOAT128 FltS1; + FLOAT128 FltS2; + FLOAT128 FltS3; + FLOAT128 FltT0; + FLOAT128 FltT1; + FLOAT128 FltT2; + FLOAT128 FltT3; + FLOAT128 FltT4; + FLOAT128 FltT5; + FLOAT128 FltT6; + FLOAT128 FltT7; + FLOAT128 FltT8; + FLOAT128 FltT9; + FLOAT128 FltS4; + FLOAT128 FltS5; + FLOAT128 FltS6; + FLOAT128 FltS7; + FLOAT128 FltS8; + FLOAT128 FltS9; + FLOAT128 FltS10; + FLOAT128 FltS11; + FLOAT128 FltS12; + FLOAT128 FltS13; + FLOAT128 FltS14; + FLOAT128 FltS15; + FLOAT128 FltS16; + FLOAT128 FltS17; + FLOAT128 FltS18; + FLOAT128 FltS19; + FLOAT128 FltF32; + FLOAT128 FltF33; + FLOAT128 FltF34; + FLOAT128 FltF35; + FLOAT128 FltF36; + FLOAT128 FltF37; + FLOAT128 FltF38; + FLOAT128 FltF39; + FLOAT128 FltF40; + FLOAT128 FltF41; + FLOAT128 FltF42; + FLOAT128 FltF43; + FLOAT128 FltF44; + FLOAT128 FltF45; + FLOAT128 FltF46; + FLOAT128 FltF47; + FLOAT128 FltF48; + FLOAT128 FltF49; + FLOAT128 FltF50; + FLOAT128 FltF51; + FLOAT128 FltF52; + FLOAT128 FltF53; + FLOAT128 FltF54; + FLOAT128 FltF55; + FLOAT128 FltF56; + FLOAT128 FltF57; + FLOAT128 FltF58; + FLOAT128 FltF59; + FLOAT128 FltF60; + FLOAT128 FltF61; + FLOAT128 FltF62; + FLOAT128 FltF63; + FLOAT128 FltF64; + FLOAT128 FltF65; + FLOAT128 FltF66; + FLOAT128 FltF67; + FLOAT128 FltF68; + FLOAT128 FltF69; + FLOAT128 FltF70; + FLOAT128 FltF71; + FLOAT128 FltF72; + FLOAT128 FltF73; + FLOAT128 FltF74; + FLOAT128 FltF75; + FLOAT128 FltF76; + FLOAT128 FltF77; + FLOAT128 FltF78; + FLOAT128 FltF79; + FLOAT128 FltF80; + FLOAT128 FltF81; + FLOAT128 FltF82; + FLOAT128 FltF83; + FLOAT128 FltF84; + FLOAT128 FltF85; + FLOAT128 FltF86; + FLOAT128 FltF87; + FLOAT128 FltF88; + FLOAT128 FltF89; + FLOAT128 FltF90; + FLOAT128 FltF91; + FLOAT128 FltF92; + FLOAT128 FltF93; + FLOAT128 FltF94; + FLOAT128 FltF95; + FLOAT128 FltF96; + FLOAT128 FltF97; + FLOAT128 FltF98; + FLOAT128 FltF99; + FLOAT128 FltF100; + FLOAT128 FltF101; + FLOAT128 FltF102; + FLOAT128 FltF103; + FLOAT128 FltF104; + FLOAT128 FltF105; + FLOAT128 FltF106; + FLOAT128 FltF107; + FLOAT128 FltF108; + FLOAT128 FltF109; + FLOAT128 FltF110; + FLOAT128 FltF111; + FLOAT128 FltF112; + FLOAT128 FltF113; + FLOAT128 FltF114; + FLOAT128 FltF115; + FLOAT128 FltF116; + FLOAT128 FltF117; + FLOAT128 FltF118; + FLOAT128 FltF119; + FLOAT128 FltF120; + FLOAT128 FltF121; + FLOAT128 FltF122; + FLOAT128 FltF123; + FLOAT128 FltF124; + FLOAT128 FltF125; + FLOAT128 FltF126; + FLOAT128 FltF127; + ULONGLONG StFPSR; + ULONGLONG IntGp; + ULONGLONG IntT0; + ULONGLONG IntT1; + ULONGLONG IntS0; + ULONGLONG IntS1; + ULONGLONG IntS2; + ULONGLONG IntS3; + ULONGLONG IntV0; + ULONGLONG IntT2; + ULONGLONG IntT3; + ULONGLONG IntT4; + ULONGLONG IntSp; + ULONGLONG IntTeb; + ULONGLONG IntT5; + ULONGLONG IntT6; + ULONGLONG IntT7; + ULONGLONG IntT8; + ULONGLONG IntT9; + ULONGLONG IntT10; + ULONGLONG IntT11; + ULONGLONG IntT12; + ULONGLONG IntT13; + ULONGLONG IntT14; + ULONGLONG IntT15; + ULONGLONG IntT16; + ULONGLONG IntT17; + ULONGLONG IntT18; + ULONGLONG IntT19; + ULONGLONG IntT20; + ULONGLONG IntT21; + ULONGLONG IntT22; + ULONGLONG IntNats; + ULONGLONG Preds; + ULONGLONG BrRp; + ULONGLONG BrS0; + ULONGLONG BrS1; + ULONGLONG BrS2; + ULONGLONG BrS3; + ULONGLONG BrS4; + ULONGLONG BrT0; + ULONGLONG BrT1; + ULONGLONG ApUNAT; + ULONGLONG ApLC; + ULONGLONG ApEC; + ULONGLONG ApCCV; + ULONGLONG ApDCR; + ULONGLONG RsPFS; + ULONGLONG RsBSP; + ULONGLONG RsBSPSTORE; + ULONGLONG RsRSC; + ULONGLONG RsRNAT; + ULONGLONG StIPSR; + ULONGLONG StIIP; + ULONGLONG StIFS; + ULONGLONG StFCR; + ULONGLONG Eflag; + ULONGLONG SegCSD; + ULONGLONG SegSSD; + ULONGLONG Cflag; + ULONGLONG StFSR; + ULONGLONG StFIR; + ULONGLONG StFDR; + ULONGLONG UNUSEDPACK; + } CONTEXT,*PCONTEXT; + + typedef struct _PLABEL_DESCRIPTOR { + ULONGLONG EntryPoint; + ULONGLONG GlobalPointer; + } PLABEL_DESCRIPTOR,*PPLABEL_DESCRIPTOR; + + typedef struct _RUNTIME_FUNCTION { + DWORD BeginAddress; + DWORD EndAddress; + DWORD UnwindInfoAddress; + } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; + + typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); + typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); + +#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" + + BOOLEAN RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,ULONGLONG BaseAddress,ULONGLONG TargetGp); + BOOLEAN RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,DWORD64 TargetGp,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); + BOOLEAN RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); + VOID RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); + VOID __jump_unwind(ULONGLONG TargetMsFrame,ULONGLONG TargetBsFrame,ULONGLONG TargetPc); +#endif + +#define EXCEPTION_NONCONTINUABLE 0x1 +#define EXCEPTION_MAXIMUM_PARAMETERS 15 + + typedef struct _EXCEPTION_RECORD { + DWORD ExceptionCode; + DWORD ExceptionFlags; + struct _EXCEPTION_RECORD *ExceptionRecord; + PVOID ExceptionAddress; + DWORD NumberParameters; + ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } EXCEPTION_RECORD; + + typedef EXCEPTION_RECORD *PEXCEPTION_RECORD; + + typedef struct _EXCEPTION_RECORD32 { + DWORD ExceptionCode; + DWORD ExceptionFlags; + DWORD ExceptionRecord; + DWORD ExceptionAddress; + DWORD NumberParameters; + DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } EXCEPTION_RECORD32,*PEXCEPTION_RECORD32; + + typedef struct _EXCEPTION_RECORD64 { + DWORD ExceptionCode; + DWORD ExceptionFlags; + DWORD64 ExceptionRecord; + DWORD64 ExceptionAddress; + DWORD NumberParameters; + DWORD __unusedAlignment; + DWORD64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } EXCEPTION_RECORD64,*PEXCEPTION_RECORD64; + + typedef struct _EXCEPTION_POINTERS { + PEXCEPTION_RECORD ExceptionRecord; + PCONTEXT ContextRecord; + } EXCEPTION_POINTERS,*PEXCEPTION_POINTERS; + +#ifdef __x86_64 + + typedef EXCEPTION_DISPOSITION NTAPI EXCEPTION_ROUTINE (struct _EXCEPTION_RECORD *ExceptionRecord, PVOID EstablisherFrame, struct _CONTEXT *ContextRecord, PVOID DispatcherContext); +#ifndef __PEXCEPTION_ROUTINE_DEFINED +#define __PEXCEPTION_ROUTINE_DEFINED + typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE; +#endif + + /* http://msdn.microsoft.com/en-us/library/ms680597(VS.85).aspx */ + +#define UNWIND_HISTORY_TABLE_SIZE 12 + + typedef struct _UNWIND_HISTORY_TABLE_ENTRY { + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + } UNWIND_HISTORY_TABLE_ENTRY, *PUNWIND_HISTORY_TABLE_ENTRY; + +#define UNWIND_HISTORY_TABLE_NONE 0 +#define UNWIND_HISTORY_TABLE_GLOBAL 1 +#define UNWIND_HISTORY_TABLE_LOCAL 2 + + typedef struct _UNWIND_HISTORY_TABLE { + ULONG Count; + UCHAR Search; + ULONG64 LowAddress; + ULONG64 HighAddress; + UNWIND_HISTORY_TABLE_ENTRY Entry[UNWIND_HISTORY_TABLE_SIZE]; + } UNWIND_HISTORY_TABLE, *PUNWIND_HISTORY_TABLE; + + /* http://msdn.microsoft.com/en-us/library/b6sf5kbd(VS.80).aspx */ + + struct _DISPATCHER_CONTEXT; + typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; + typedef struct _DISPATCHER_CONTEXT *PDISPATCHER_CONTEXT; + + struct _DISPATCHER_CONTEXT { + ULONG64 ControlPc; + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + ULONG64 EstablisherFrame; + ULONG64 TargetIp; + PCONTEXT ContextRecord; + PEXCEPTION_ROUTINE LanguageHandler; + PVOID HandlerData; + /* http://www.nynaeve.net/?p=99 */ + PUNWIND_HISTORY_TABLE HistoryTable; + ULONG ScopeIndex; + ULONG Fill0; + }; + + /* http://msdn.microsoft.com/en-us/library/ms680617(VS.85).aspx */ + + typedef struct _KNONVOLATILE_CONTEXT_POINTERS + { + PM128A FloatingContext[16]; + PULONG64 IntegerContext[16]; + } KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS; +#endif /* defined(__x86_64) */ + + typedef PVOID PACCESS_TOKEN; + typedef PVOID PSECURITY_DESCRIPTOR; + typedef PVOID PSID; + + typedef DWORD ACCESS_MASK; + typedef ACCESS_MASK *PACCESS_MASK; + +#define DELETE (0x00010000L) +#define READ_CONTROL (0x00020000L) +#define WRITE_DAC (0x00040000L) +#define WRITE_OWNER (0x00080000L) +#define SYNCHRONIZE (0x00100000L) + +#define STANDARD_RIGHTS_REQUIRED (0x000F0000L) +#define STANDARD_RIGHTS_READ (READ_CONTROL) +#define STANDARD_RIGHTS_WRITE (READ_CONTROL) +#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL) +#define STANDARD_RIGHTS_ALL (0x001F0000L) + +#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL) + +#define ACCESS_SYSTEM_SECURITY (0x01000000L) + +#define MAXIMUM_ALLOWED (0x02000000L) + +#define GENERIC_READ (0x80000000L) +#define GENERIC_WRITE (0x40000000L) +#define GENERIC_EXECUTE (0x20000000L) +#define GENERIC_ALL (0x10000000L) + + typedef struct _GENERIC_MAPPING { + ACCESS_MASK GenericRead; + ACCESS_MASK GenericWrite; + ACCESS_MASK GenericExecute; + ACCESS_MASK GenericAll; + } GENERIC_MAPPING; + typedef GENERIC_MAPPING *PGENERIC_MAPPING; + +#include + + typedef struct _LUID_AND_ATTRIBUTES { + LUID Luid; + DWORD Attributes; + } LUID_AND_ATTRIBUTES,*PLUID_AND_ATTRIBUTES; + typedef LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; + typedef LUID_AND_ATTRIBUTES_ARRAY *PLUID_AND_ATTRIBUTES_ARRAY; + +#include + +#ifndef SID_IDENTIFIER_AUTHORITY_DEFINED +#define SID_IDENTIFIER_AUTHORITY_DEFINED + typedef struct _SID_IDENTIFIER_AUTHORITY { + BYTE Value[6]; + } SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY; +#endif + +#ifndef SID_DEFINED +#define SID_DEFINED + typedef struct _SID { + BYTE Revision; + BYTE SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + DWORD SubAuthority[ANYSIZE_ARRAY]; + } SID,*PISID; +#endif + +#define SID_REVISION (1) +#define SID_MAX_SUB_AUTHORITIES (15) +#define SID_RECOMMENDED_SUB_AUTHORITIES (1) + +#define SECURITY_MAX_SID_SIZE (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES *sizeof(DWORD))) + + typedef enum _SID_NAME_USE { + SidTypeUser = 1,SidTypeGroup,SidTypeDomain,SidTypeAlias,SidTypeWellKnownGroup,SidTypeDeletedAccount,SidTypeInvalid,SidTypeUnknown,SidTypeComputer + } SID_NAME_USE,*PSID_NAME_USE; + + typedef struct _SID_AND_ATTRIBUTES { + PSID Sid; + DWORD Attributes; + } SID_AND_ATTRIBUTES,*PSID_AND_ATTRIBUTES; + + typedef SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; + typedef SID_AND_ATTRIBUTES_ARRAY *PSID_AND_ATTRIBUTES_ARRAY; + +#define SECURITY_NULL_SID_AUTHORITY {0,0,0,0,0,0} +#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} +#define SECURITY_LOCAL_SID_AUTHORITY {0,0,0,0,0,2} +#define SECURITY_CREATOR_SID_AUTHORITY {0,0,0,0,0,3} +#define SECURITY_NON_UNIQUE_AUTHORITY {0,0,0,0,0,4} +#define SECURITY_RESOURCE_MANAGER_AUTHORITY {0,0,0,0,0,9} + +#define SECURITY_NULL_RID (0x00000000L) +#define SECURITY_WORLD_RID (0x00000000L) +#define SECURITY_LOCAL_RID (0x00000000L) + +#define SECURITY_CREATOR_OWNER_RID (0x00000000L) +#define SECURITY_CREATOR_GROUP_RID (0x00000001L) + +#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L) +#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L) + +#define SECURITY_NT_AUTHORITY {0,0,0,0,0,5} + +#define SECURITY_DIALUP_RID (0x00000001L) +#define SECURITY_NETWORK_RID (0x00000002L) +#define SECURITY_BATCH_RID (0x00000003L) +#define SECURITY_INTERACTIVE_RID (0x00000004L) +#define SECURITY_LOGON_IDS_RID (0x00000005L) +#define SECURITY_LOGON_IDS_RID_COUNT (3L) +#define SECURITY_SERVICE_RID (0x00000006L) +#define SECURITY_ANONYMOUS_LOGON_RID (0x00000007L) +#define SECURITY_PROXY_RID (0x00000008L) +#define SECURITY_ENTERPRISE_CONTROLLERS_RID (0x00000009L) +#define SECURITY_SERVER_LOGON_RID SECURITY_ENTERPRISE_CONTROLLERS_RID +#define SECURITY_PRINCIPAL_SELF_RID (0x0000000AL) +#define SECURITY_AUTHENTICATED_USER_RID (0x0000000BL) +#define SECURITY_RESTRICTED_CODE_RID (0x0000000CL) +#define SECURITY_TERMINAL_SERVER_RID (0x0000000DL) +#define SECURITY_REMOTE_LOGON_RID (0x0000000EL) +#define SECURITY_THIS_ORGANIZATION_RID (0x0000000FL) +#define SECURITY_IUSER_RID (0x00000011L) + +#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L) +#define SECURITY_LOCAL_SERVICE_RID (0x00000013L) +#define SECURITY_NETWORK_SERVICE_RID (0x00000014L) + +#define SECURITY_NT_NON_UNIQUE (0x00000015L) +#define SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT (3L) + +#define SECURITY_ENTERPRISE_READONLY_CONTROLLERS_RID (0x00000016L) + +#define SECURITY_BUILTIN_DOMAIN_RID (0x00000020L) +#define SECURITY_WRITE_RESTRICTED_CODE_RID (0x00000021L) + +#define SECURITY_PACKAGE_BASE_RID (0x00000040L) +#define SECURITY_PACKAGE_RID_COUNT (2L) +#define SECURITY_PACKAGE_NTLM_RID (0x0000000AL) +#define SECURITY_PACKAGE_SCHANNEL_RID (0x0000000EL) +#define SECURITY_PACKAGE_DIGEST_RID (0x00000015L) + +#define SECURITY_SERVICE_ID_BASE_RID (0x00000050L) +#define SECURITY_SERVICE_ID_RID_COUNT (6L) + +#define SECURITY_RESERVED_ID_BASE_RID (0x00000051L) + +#define SECURITY_MAX_ALWAYS_FILTERED (0x000003E7L) +#define SECURITY_MIN_NEVER_FILTERED (0x000003E8L) + +#define SECURITY_OTHER_ORGANIZATION_RID (0x000003E8L) + +#define FOREST_USER_RID_MAX (0x000001F3L) + +#define DOMAIN_USER_RID_ADMIN (0x000001F4L) +#define DOMAIN_USER_RID_GUEST (0x000001F5L) +#define DOMAIN_USER_RID_KRBTGT (0x000001F6L) + +#define DOMAIN_USER_RID_MAX (0x000003E7L) + +#define DOMAIN_GROUP_RID_ADMINS (0x00000200L) +#define DOMAIN_GROUP_RID_USERS (0x00000201L) +#define DOMAIN_GROUP_RID_GUESTS (0x00000202L) +#define DOMAIN_GROUP_RID_COMPUTERS (0x00000203L) +#define DOMAIN_GROUP_RID_CONTROLLERS (0x00000204L) +#define DOMAIN_GROUP_RID_CERT_ADMINS (0x00000205L) +#define DOMAIN_GROUP_RID_SCHEMA_ADMINS (0x00000206L) +#define DOMAIN_GROUP_RID_ENTERPRISE_ADMINS (0x00000207L) +#define DOMAIN_GROUP_RID_POLICY_ADMINS (0x00000208L) +#define DOMAIN_GROUP_RID_READONLY_CONTROLLERS (0x00000209L) + +#define DOMAIN_ALIAS_RID_ADMINS (0x00000220L) +#define DOMAIN_ALIAS_RID_USERS (0x00000221L) +#define DOMAIN_ALIAS_RID_GUESTS (0x00000222L) +#define DOMAIN_ALIAS_RID_POWER_USERS (0x00000223L) + +#define DOMAIN_ALIAS_RID_ACCOUNT_OPS (0x00000224L) +#define DOMAIN_ALIAS_RID_SYSTEM_OPS (0x00000225L) +#define DOMAIN_ALIAS_RID_PRINT_OPS (0x00000226L) +#define DOMAIN_ALIAS_RID_BACKUP_OPS (0x00000227L) + +#define DOMAIN_ALIAS_RID_REPLICATOR (0x00000228L) +#define DOMAIN_ALIAS_RID_RAS_SERVERS (0x00000229L) +#define DOMAIN_ALIAS_RID_PREW2KCOMPACCESS (0x0000022AL) +#define DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS (0x0000022BL) +#define DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS (0x0000022CL) +#define DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS (0x0000022DL) + +#define DOMAIN_ALIAS_RID_MONITORING_USERS (0x0000022EL) +#define DOMAIN_ALIAS_RID_LOGGING_USERS (0x0000022FL) +#define DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS (0x00000230L) +#define DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS (0x00000231L) +#define DOMAIN_ALIAS_RID_DCOM_USERS (0x00000232L) + +#define DOMAIN_ALIAS_RID_IUSERS (0x00000238L) +#define DOMAIN_ALIAS_RID_CRYPTO_OPERATORS (0x00000239L) +#define DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP (0x0000023BL) +#define DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP (0x0000023CL) +#define DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP (0x0000023DL) + +#define SECURITY_MANDATORY_LABEL_AUTHORITY {0,0,0,0,0,16} +#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L) +#define SECURITY_MANDATORY_LOW_RID (0x00001000L) +#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L) +#define SECURITY_MANDATORY_HIGH_RID (0x00003000L) +#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L) +#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L) + +#define SECURITY_MANDATORY_MAXIMUM_USER_RID SECURITY_MANDATORY_SYSTEM_RID + +#define MANDATORY_LEVEL_TO_MANDATORY_RID(IL) (IL * 0x1000) + + typedef enum { + WinNullSid = 0,WinWorldSid = 1,WinLocalSid = 2,WinCreatorOwnerSid = 3,WinCreatorGroupSid = 4,WinCreatorOwnerServerSid = 5,WinCreatorGroupServerSid = 6,WinNtAuthoritySid = 7,WinDialupSid = 8,WinNetworkSid = 9,WinBatchSid = 10,WinInteractiveSid = 11,WinServiceSid = 12,WinAnonymousSid = 13,WinProxySid = 14,WinEnterpriseControllersSid = 15,WinSelfSid = 16,WinAuthenticatedUserSid = 17,WinRestrictedCodeSid = 18,WinTerminalServerSid = 19,WinRemoteLogonIdSid = 20,WinLogonIdsSid = 21,WinLocalSystemSid = 22,WinLocalServiceSid = 23,WinNetworkServiceSid = 24,WinBuiltinDomainSid = 25,WinBuiltinAdministratorsSid = 26,WinBuiltinUsersSid = 27,WinBuiltinGuestsSid = 28,WinBuiltinPowerUsersSid = 29,WinBuiltinAccountOperatorsSid = 30,WinBuiltinSystemOperatorsSid = 31,WinBuiltinPrintOperatorsSid = 32,WinBuiltinBackupOperatorsSid = 33,WinBuiltinReplicatorSid = 34,WinBuiltinPreWindows2000CompatibleAccessSid = 35,WinBuiltinRemoteDesktopUsersSid = 36,WinBuiltinNetworkConfigurationOperatorsSid = 37,WinAccountAdministratorSid = 38,WinAccountGuestSid = 39,WinAccountKrbtgtSid = 40,WinAccountDomainAdminsSid = 41,WinAccountDomainUsersSid = 42,WinAccountDomainGuestsSid = 43,WinAccountComputersSid = 44,WinAccountControllersSid = 45,WinAccountCertAdminsSid = 46,WinAccountSchemaAdminsSid = 47,WinAccountEnterpriseAdminsSid = 48,WinAccountPolicyAdminsSid = 49,WinAccountRasAndIasServersSid = 50,WinNTLMAuthenticationSid = 51,WinDigestAuthenticationSid = 52,WinSChannelAuthenticationSid = 53,WinThisOrganizationSid = 54,WinOtherOrganizationSid = 55,WinBuiltinIncomingForestTrustBuildersSid = 56,WinBuiltinPerfMonitoringUsersSid = 57,WinBuiltinPerfLoggingUsersSid = 58,WinBuiltinAuthorizationAccessSid = 59,WinBuiltinTerminalServerLicenseServersSid = 60,WinBuiltinDCOMUsersSid = 61 + } WELL_KNOWN_SID_TYPE; + +#define SYSTEM_LUID { 0x3E7,0x0 } +#define ANONYMOUS_LOGON_LUID { 0x3e6,0x0 } +#define LOCALSERVICE_LUID { 0x3e5,0x0 } +#define NETWORKSERVICE_LUID { 0x3e4,0x0 } +#define IUSER_LUID { 0x3e3, 0x0 } + +#define SE_GROUP_MANDATORY (0x00000001L) +#define SE_GROUP_ENABLED_BY_DEFAULT (0x00000002L) +#define SE_GROUP_ENABLED (0x00000004L) +#define SE_GROUP_OWNER (0x00000008L) +#define SE_GROUP_USE_FOR_DENY_ONLY (0x00000010L) +#define SE_GROUP_INTEGRITY (0x00000020L) +#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L) +#define SE_GROUP_LOGON_ID (0xC0000000L) +#define SE_GROUP_RESOURCE (0x20000000L) + +#define ACL_REVISION (2) +#define ACL_REVISION_DS (4) + +#define ACL_REVISION1 (1) +#define MIN_ACL_REVISION ACL_REVISION2 +#define ACL_REVISION2 (2) +#define ACL_REVISION3 (3) +#define ACL_REVISION4 (4) +#define MAX_ACL_REVISION ACL_REVISION4 + + typedef struct _ACL { + BYTE AclRevision; + BYTE Sbz1; + WORD AclSize; + WORD AceCount; + WORD Sbz2; + } ACL; + typedef ACL *PACL; + + typedef struct _ACE_HEADER { + BYTE AceType; + BYTE AceFlags; + WORD AceSize; + } ACE_HEADER; + typedef ACE_HEADER *PACE_HEADER; + +#define ACCESS_MIN_MS_ACE_TYPE (0x0) +#define ACCESS_ALLOWED_ACE_TYPE (0x0) +#define ACCESS_DENIED_ACE_TYPE (0x1) +#define SYSTEM_AUDIT_ACE_TYPE (0x2) +#define SYSTEM_ALARM_ACE_TYPE (0x3) +#define ACCESS_MAX_MS_V2_ACE_TYPE (0x3) + +#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE (0x4) +#define ACCESS_MAX_MS_V3_ACE_TYPE (0x4) + +#define ACCESS_MIN_MS_OBJECT_ACE_TYPE (0x5) +#define ACCESS_ALLOWED_OBJECT_ACE_TYPE (0x5) +#define ACCESS_DENIED_OBJECT_ACE_TYPE (0x6) +#define SYSTEM_AUDIT_OBJECT_ACE_TYPE (0x7) +#define SYSTEM_ALARM_OBJECT_ACE_TYPE (0x8) +#define ACCESS_MAX_MS_OBJECT_ACE_TYPE (0x8) + +#define ACCESS_MAX_MS_V4_ACE_TYPE (0x8) +#define ACCESS_MAX_MS_ACE_TYPE (0x8) + +#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE (0x9) +#define ACCESS_DENIED_CALLBACK_ACE_TYPE (0xA) +#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE (0xB) +#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE (0xC) +#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE (0xD) +#define SYSTEM_ALARM_CALLBACK_ACE_TYPE (0xE) +#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE (0xF) +#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE (0x10) + +#define SYSTEM_MANDATORY_LABEL_ACE_TYPE (0x11) +#define ACCESS_MAX_MS_V5_ACE_TYPE (0x11) + +#define OBJECT_INHERIT_ACE (0x1) +#define CONTAINER_INHERIT_ACE (0x2) +#define NO_PROPAGATE_INHERIT_ACE (0x4) +#define INHERIT_ONLY_ACE (0x8) +#define INHERITED_ACE (0x10) +#define VALID_INHERIT_FLAGS (0x1F) + +#define SUCCESSFUL_ACCESS_ACE_FLAG (0x40) +#define FAILED_ACCESS_ACE_FLAG (0x80) + + typedef struct _ACCESS_ALLOWED_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } ACCESS_ALLOWED_ACE; + + typedef ACCESS_ALLOWED_ACE *PACCESS_ALLOWED_ACE; + + typedef struct _ACCESS_DENIED_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } ACCESS_DENIED_ACE; + typedef ACCESS_DENIED_ACE *PACCESS_DENIED_ACE; + + typedef struct _SYSTEM_AUDIT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } SYSTEM_AUDIT_ACE; + typedef SYSTEM_AUDIT_ACE *PSYSTEM_AUDIT_ACE; + + typedef struct _SYSTEM_ALARM_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } SYSTEM_ALARM_ACE; + typedef SYSTEM_ALARM_ACE *PSYSTEM_ALARM_ACE; + + typedef struct _ACCESS_ALLOWED_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } ACCESS_ALLOWED_OBJECT_ACE,*PACCESS_ALLOWED_OBJECT_ACE; + + typedef struct _ACCESS_DENIED_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } ACCESS_DENIED_OBJECT_ACE,*PACCESS_DENIED_OBJECT_ACE; + + typedef struct _SYSTEM_AUDIT_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } SYSTEM_AUDIT_OBJECT_ACE,*PSYSTEM_AUDIT_OBJECT_ACE; + + typedef struct _SYSTEM_ALARM_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } SYSTEM_ALARM_OBJECT_ACE,*PSYSTEM_ALARM_OBJECT_ACE; + + typedef struct _ACCESS_ALLOWED_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } ACCESS_ALLOWED_CALLBACK_ACE,*PACCESS_ALLOWED_CALLBACK_ACE; + + typedef struct _ACCESS_DENIED_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } ACCESS_DENIED_CALLBACK_ACE,*PACCESS_DENIED_CALLBACK_ACE; + + typedef struct _SYSTEM_AUDIT_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } SYSTEM_AUDIT_CALLBACK_ACE,*PSYSTEM_AUDIT_CALLBACK_ACE; + + typedef struct _SYSTEM_ALARM_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } SYSTEM_ALARM_CALLBACK_ACE,*PSYSTEM_ALARM_CALLBACK_ACE; + + typedef struct _ACCESS_ALLOWED_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } ACCESS_ALLOWED_CALLBACK_OBJECT_ACE,*PACCESS_ALLOWED_CALLBACK_OBJECT_ACE; + + typedef struct _ACCESS_DENIED_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } ACCESS_DENIED_CALLBACK_OBJECT_ACE,*PACCESS_DENIED_CALLBACK_OBJECT_ACE; + + typedef struct _SYSTEM_AUDIT_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } SYSTEM_AUDIT_CALLBACK_OBJECT_ACE,*PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE; + + typedef struct _SYSTEM_ALARM_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } SYSTEM_ALARM_CALLBACK_OBJECT_ACE,*PSYSTEM_ALARM_CALLBACK_OBJECT_ACE; + +#define ACE_OBJECT_TYPE_PRESENT 0x1 +#define ACE_INHERITED_OBJECT_TYPE_PRESENT 0x2 + + typedef enum _ACL_INFORMATION_CLASS { + AclRevisionInformation = 1,AclSizeInformation + } ACL_INFORMATION_CLASS; + + typedef struct _ACL_REVISION_INFORMATION { + DWORD AclRevision; + } ACL_REVISION_INFORMATION; + typedef ACL_REVISION_INFORMATION *PACL_REVISION_INFORMATION; + + typedef struct _ACL_SIZE_INFORMATION { + DWORD AceCount; + DWORD AclBytesInUse; + DWORD AclBytesFree; + } ACL_SIZE_INFORMATION; + typedef ACL_SIZE_INFORMATION *PACL_SIZE_INFORMATION; + +#define SECURITY_DESCRIPTOR_REVISION (1) +#define SECURITY_DESCRIPTOR_REVISION1 (1) + +#define SECURITY_DESCRIPTOR_MIN_LENGTH (sizeof(SECURITY_DESCRIPTOR)) + + typedef WORD SECURITY_DESCRIPTOR_CONTROL,*PSECURITY_DESCRIPTOR_CONTROL; + +#define SE_OWNER_DEFAULTED (0x0001) +#define SE_GROUP_DEFAULTED (0x0002) +#define SE_DACL_PRESENT (0x0004) +#define SE_DACL_DEFAULTED (0x0008) +#define SE_SACL_PRESENT (0x0010) +#define SE_SACL_DEFAULTED (0x0020) +#define SE_DACL_AUTO_INHERIT_REQ (0x0100) +#define SE_SACL_AUTO_INHERIT_REQ (0x0200) +#define SE_DACL_AUTO_INHERITED (0x0400) +#define SE_SACL_AUTO_INHERITED (0x0800) +#define SE_DACL_PROTECTED (0x1000) +#define SE_SACL_PROTECTED (0x2000) +#define SE_RM_CONTROL_VALID (0x4000) +#define SE_SELF_RELATIVE (0x8000) + + typedef struct _SECURITY_DESCRIPTOR_RELATIVE { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + DWORD Owner; + DWORD Group; + DWORD Sacl; + DWORD Dacl; + } SECURITY_DESCRIPTOR_RELATIVE,*PISECURITY_DESCRIPTOR_RELATIVE; + + typedef struct _SECURITY_DESCRIPTOR { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + PSID Owner; + PSID Group; + PACL Sacl; + PACL Dacl; + + } SECURITY_DESCRIPTOR,*PISECURITY_DESCRIPTOR; + + typedef struct _OBJECT_TYPE_LIST { + WORD Level; + WORD Sbz; + GUID *ObjectType; + } OBJECT_TYPE_LIST,*POBJECT_TYPE_LIST; + +#define ACCESS_OBJECT_GUID 0 +#define ACCESS_PROPERTY_SET_GUID 1 +#define ACCESS_PROPERTY_GUID 2 + +#define ACCESS_MAX_LEVEL 4 + + typedef enum _AUDIT_EVENT_TYPE { + AuditEventObjectAccess,AuditEventDirectoryServiceAccess + } AUDIT_EVENT_TYPE,*PAUDIT_EVENT_TYPE; + +#define AUDIT_ALLOW_NO_PRIVILEGE 0x1 + +#define ACCESS_DS_SOURCE_A "DS" +#define ACCESS_DS_SOURCE_W L"DS" +#define ACCESS_DS_OBJECT_TYPE_NAME_A "Directory Service Object" +#define ACCESS_DS_OBJECT_TYPE_NAME_W L"Directory Service Object" + +#define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L) +#define SE_PRIVILEGE_ENABLED (0x00000002L) +#define SE_PRIVILEGE_REMOVED (0X00000004L) +#define SE_PRIVILEGE_USED_FOR_ACCESS (0x80000000L) + +#define PRIVILEGE_SET_ALL_NECESSARY (1) + + typedef struct _PRIVILEGE_SET { + DWORD PrivilegeCount; + DWORD Control; + LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]; + } PRIVILEGE_SET,*PPRIVILEGE_SET; + +#define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege") +#define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege") +#define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege") +#define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege") +#define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege") +#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege") +#define SE_TCB_NAME TEXT("SeTcbPrivilege") +#define SE_SECURITY_NAME TEXT("SeSecurityPrivilege") +#define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege") +#define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege") +#define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege") +#define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege") +#define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege") +#define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege") +#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege") +#define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege") +#define SE_BACKUP_NAME TEXT("SeBackupPrivilege") +#define SE_RESTORE_NAME TEXT("SeRestorePrivilege") +#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege") +#define SE_DEBUG_NAME TEXT("SeDebugPrivilege") +#define SE_AUDIT_NAME TEXT("SeAuditPrivilege") +#define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege") +#define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege") +#define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege") +#define SE_UNDOCK_NAME TEXT("SeUndockPrivilege") +#define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege") +#define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege") +#define SE_MANAGE_VOLUME_NAME TEXT("SeManageVolumePrivilege") +#define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege") +#define SE_CREATE_GLOBAL_NAME TEXT("SeCreateGlobalPrivilege") + + typedef enum _SECURITY_IMPERSONATION_LEVEL { + SecurityAnonymous,SecurityIdentification,SecurityImpersonation,SecurityDelegation + } SECURITY_IMPERSONATION_LEVEL,*PSECURITY_IMPERSONATION_LEVEL; + +#define SECURITY_MAX_IMPERSONATION_LEVEL SecurityDelegation +#define SECURITY_MIN_IMPERSONATION_LEVEL SecurityAnonymous +#define DEFAULT_IMPERSONATION_LEVEL SecurityImpersonation +#define VALID_IMPERSONATION_LEVEL(L) (((L) >= SECURITY_MIN_IMPERSONATION_LEVEL) && ((L) <= SECURITY_MAX_IMPERSONATION_LEVEL)) + +#define TOKEN_ASSIGN_PRIMARY (0x0001) +#define TOKEN_DUPLICATE (0x0002) +#define TOKEN_IMPERSONATE (0x0004) +#define TOKEN_QUERY (0x0008) +#define TOKEN_QUERY_SOURCE (0x0010) +#define TOKEN_ADJUST_PRIVILEGES (0x0020) +#define TOKEN_ADJUST_GROUPS (0x0040) +#define TOKEN_ADJUST_DEFAULT (0x0080) +#define TOKEN_ADJUST_SESSIONID (0x0100) + +#define TOKEN_ALL_ACCESS_P (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) +#define TOKEN_ALL_ACCESS (TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID) +#define TOKEN_READ (STANDARD_RIGHTS_READ | TOKEN_QUERY) + +#define TOKEN_WRITE (STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) + +#define TOKEN_EXECUTE (STANDARD_RIGHTS_EXECUTE) + + typedef enum _TOKEN_TYPE { + TokenPrimary = 1,TokenImpersonation + } TOKEN_TYPE; + typedef TOKEN_TYPE *PTOKEN_TYPE; + + typedef enum _TOKEN_INFORMATION_CLASS { + TokenUser = 1,TokenGroups,TokenPrivileges,TokenOwner,TokenPrimaryGroup,TokenDefaultDacl,TokenSource,TokenType,TokenImpersonationLevel, + TokenStatistics,TokenRestrictedSids,TokenSessionId,TokenGroupsAndPrivileges,TokenSessionReference,TokenSandBoxInert,TokenAuditPolicy, + TokenOrigin,MaxTokenInfoClass + } TOKEN_INFORMATION_CLASS,*PTOKEN_INFORMATION_CLASS; + + typedef struct _TOKEN_USER { + SID_AND_ATTRIBUTES User; + } TOKEN_USER,*PTOKEN_USER; + + typedef struct _TOKEN_GROUPS { + DWORD GroupCount; + SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; + } TOKEN_GROUPS,*PTOKEN_GROUPS; + + typedef struct _TOKEN_PRIVILEGES { + DWORD PrivilegeCount; + LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; + } TOKEN_PRIVILEGES,*PTOKEN_PRIVILEGES; + + typedef struct _TOKEN_OWNER { + PSID Owner; + } TOKEN_OWNER,*PTOKEN_OWNER; + + typedef struct _TOKEN_PRIMARY_GROUP { + PSID PrimaryGroup; + } TOKEN_PRIMARY_GROUP,*PTOKEN_PRIMARY_GROUP; + + typedef struct _TOKEN_DEFAULT_DACL { + PACL DefaultDacl; + } TOKEN_DEFAULT_DACL,*PTOKEN_DEFAULT_DACL; + + typedef struct _TOKEN_GROUPS_AND_PRIVILEGES { + DWORD SidCount; + DWORD SidLength; + PSID_AND_ATTRIBUTES Sids; + DWORD RestrictedSidCount; + DWORD RestrictedSidLength; + PSID_AND_ATTRIBUTES RestrictedSids; + DWORD PrivilegeCount; + DWORD PrivilegeLength; + PLUID_AND_ATTRIBUTES Privileges; + LUID AuthenticationId; + } TOKEN_GROUPS_AND_PRIVILEGES,*PTOKEN_GROUPS_AND_PRIVILEGES; + +#define TOKEN_AUDIT_SUCCESS_INCLUDE 0x1 +#define TOKEN_AUDIT_SUCCESS_EXCLUDE 0x2 +#define TOKEN_AUDIT_FAILURE_INCLUDE 0x4 +#define TOKEN_AUDIT_FAILURE_EXCLUDE 0x8 + +#define VALID_AUDIT_POLICY_BITS (TOKEN_AUDIT_SUCCESS_INCLUDE | TOKEN_AUDIT_SUCCESS_EXCLUDE | TOKEN_AUDIT_FAILURE_INCLUDE | TOKEN_AUDIT_FAILURE_EXCLUDE) +#define VALID_TOKEN_AUDIT_POLICY_ELEMENT(P) ((((P).PolicyMask & ~VALID_AUDIT_POLICY_BITS)==0) && ((P).Category <= AuditEventMaxType)) + + typedef struct _TOKEN_AUDIT_POLICY_ELEMENT { + DWORD Category; + DWORD PolicyMask; + } TOKEN_AUDIT_POLICY_ELEMENT,*PTOKEN_AUDIT_POLICY_ELEMENT; + + typedef struct _TOKEN_AUDIT_POLICY { + DWORD PolicyCount; + TOKEN_AUDIT_POLICY_ELEMENT Policy[ANYSIZE_ARRAY]; + } TOKEN_AUDIT_POLICY,*PTOKEN_AUDIT_POLICY; + +#define PER_USER_AUDITING_POLICY_SIZE(p) (sizeof(TOKEN_AUDIT_POLICY) + (((p)->PolicyCount > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((p)->PolicyCount - ANYSIZE_ARRAY)) : 0)) +#define PER_USER_AUDITING_POLICY_SIZE_BY_COUNT(C) (sizeof(TOKEN_AUDIT_POLICY) + (((C) > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((C) - ANYSIZE_ARRAY)) : 0)) + +#define TOKEN_SOURCE_LENGTH 8 + + typedef struct _TOKEN_SOURCE { + CHAR SourceName[TOKEN_SOURCE_LENGTH]; + LUID SourceIdentifier; + } TOKEN_SOURCE,*PTOKEN_SOURCE; + + typedef struct _TOKEN_STATISTICS { + LUID TokenId; + LUID AuthenticationId; + LARGE_INTEGER ExpirationTime; + TOKEN_TYPE TokenType; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + DWORD DynamicCharged; + DWORD DynamicAvailable; + DWORD GroupCount; + DWORD PrivilegeCount; + LUID ModifiedId; + } TOKEN_STATISTICS,*PTOKEN_STATISTICS; + + typedef struct _TOKEN_CONTROL { + LUID TokenId; + LUID AuthenticationId; + LUID ModifiedId; + TOKEN_SOURCE TokenSource; + } TOKEN_CONTROL,*PTOKEN_CONTROL; + + typedef struct _TOKEN_ORIGIN { + LUID OriginatingLogonSession; + } TOKEN_ORIGIN,*PTOKEN_ORIGIN; + +#define SECURITY_DYNAMIC_TRACKING (TRUE) +#define SECURITY_STATIC_TRACKING (FALSE) + + typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE,*PSECURITY_CONTEXT_TRACKING_MODE; + + typedef struct _SECURITY_QUALITY_OF_SERVICE { + DWORD Length; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode; + BOOLEAN EffectiveOnly; + } SECURITY_QUALITY_OF_SERVICE,*PSECURITY_QUALITY_OF_SERVICE; + + typedef struct _SE_IMPERSONATION_STATE { + PACCESS_TOKEN Token; + BOOLEAN CopyOnOpen; + BOOLEAN EffectiveOnly; + SECURITY_IMPERSONATION_LEVEL Level; + } SE_IMPERSONATION_STATE,*PSE_IMPERSONATION_STATE; + +#define DISABLE_MAX_PRIVILEGE 0x1 +#define SANDBOX_INERT 0x2 + + typedef DWORD SECURITY_INFORMATION,*PSECURITY_INFORMATION; + +#define OWNER_SECURITY_INFORMATION (0x00000001L) +#define GROUP_SECURITY_INFORMATION (0x00000002L) +#define DACL_SECURITY_INFORMATION (0x00000004L) +#define SACL_SECURITY_INFORMATION (0x00000008L) + +#define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L) +#define PROTECTED_SACL_SECURITY_INFORMATION (0x40000000L) +#define UNPROTECTED_DACL_SECURITY_INFORMATION (0x20000000L) +#define UNPROTECTED_SACL_SECURITY_INFORMATION (0x10000000L) + +#define PROCESS_TERMINATE (0x0001) +#define PROCESS_CREATE_THREAD (0x0002) +#define PROCESS_SET_SESSIONID (0x0004) +#define PROCESS_VM_OPERATION (0x0008) +#define PROCESS_VM_READ (0x0010) +#define PROCESS_VM_WRITE (0x0020) +#define PROCESS_DUP_HANDLE (0x0040) +#define PROCESS_CREATE_PROCESS (0x0080) +#define PROCESS_SET_QUOTA (0x0100) +#define PROCESS_SET_INFORMATION (0x0200) +#define PROCESS_QUERY_INFORMATION (0x0400) +#define PROCESS_SUSPEND_RESUME (0x0800) +#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF) + +#ifdef _WIN64 +#define MAXIMUM_PROCESSORS 64 +#else +#define MAXIMUM_PROCESSORS 32 +#endif + +#define THREAD_TERMINATE (0x0001) +#define THREAD_SUSPEND_RESUME (0x0002) +#define THREAD_GET_CONTEXT (0x0008) +#define THREAD_SET_CONTEXT (0x0010) +#define THREAD_SET_INFORMATION (0x0020) +#define THREAD_QUERY_INFORMATION (0x0040) +#define THREAD_SET_THREAD_TOKEN (0x0080) +#define THREAD_IMPERSONATE (0x0100) +#define THREAD_DIRECT_IMPERSONATION (0x0200) + +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF) + +#define JOB_OBJECT_ASSIGN_PROCESS (0x0001) +#define JOB_OBJECT_SET_ATTRIBUTES (0x0002) +#define JOB_OBJECT_QUERY (0x0004) +#define JOB_OBJECT_TERMINATE (0x0008) +#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010) +#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1F) + + typedef struct _JOB_SET_ARRAY { + HANDLE JobHandle; + DWORD MemberLevel; + DWORD Flags; + } JOB_SET_ARRAY,*PJOB_SET_ARRAY; + +#define FLS_MAXIMUM_AVAILABLE 128 +#define TLS_MINIMUM_AVAILABLE 64 + +#ifndef _NT_TIB_DEFINED +#define _NT_TIB_DEFINED + typedef struct _NT_TIB { + struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; + PVOID StackBase; + PVOID StackLimit; + PVOID SubSystemTib; + union { + PVOID FiberData; + DWORD Version; + }; + PVOID ArbitraryUserPointer; + struct _NT_TIB *Self; + } NT_TIB; + typedef NT_TIB *PNT_TIB; +#endif + + typedef struct _NT_TIB32 { + DWORD ExceptionList; + DWORD StackBase; + DWORD StackLimit; + DWORD SubSystemTib; + union { + DWORD FiberData; + DWORD Version; + }; + DWORD ArbitraryUserPointer; + DWORD Self; + } NT_TIB32,*PNT_TIB32; + + typedef struct _NT_TIB64 { + DWORD64 ExceptionList; + DWORD64 StackBase; + DWORD64 StackLimit; + DWORD64 SubSystemTib; + union { + DWORD64 FiberData; + DWORD Version; + }; + DWORD64 ArbitraryUserPointer; + DWORD64 Self; + } NT_TIB64,*PNT_TIB64; + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) +#define WX86 +#endif + +#define THREAD_BASE_PRIORITY_LOWRT 15 +#define THREAD_BASE_PRIORITY_MAX 2 +#define THREAD_BASE_PRIORITY_MIN (-2) +#define THREAD_BASE_PRIORITY_IDLE (-15) + + typedef struct _QUOTA_LIMITS { + SIZE_T PagedPoolLimit; + SIZE_T NonPagedPoolLimit; + SIZE_T MinimumWorkingSetSize; + SIZE_T MaximumWorkingSetSize; + SIZE_T PagefileLimit; + LARGE_INTEGER TimeLimit; + } QUOTA_LIMITS,*PQUOTA_LIMITS; + +#define QUOTA_LIMITS_HARDWS_MIN_ENABLE 0x00000001 +#define QUOTA_LIMITS_HARDWS_MIN_DISABLE 0x00000002 +#define QUOTA_LIMITS_HARDWS_MAX_ENABLE 0x00000004 +#define QUOTA_LIMITS_HARDWS_MAX_DISABLE 0x00000008 + + typedef struct _QUOTA_LIMITS_EX { + SIZE_T PagedPoolLimit; + SIZE_T NonPagedPoolLimit; + SIZE_T MinimumWorkingSetSize; + SIZE_T MaximumWorkingSetSize; + SIZE_T PagefileLimit; + LARGE_INTEGER TimeLimit; + SIZE_T Reserved1; + SIZE_T Reserved2; + SIZE_T Reserved3; + SIZE_T Reserved4; + DWORD Flags; + DWORD Reserved5; + } QUOTA_LIMITS_EX,*PQUOTA_LIMITS_EX; + + typedef struct _IO_COUNTERS { + ULONGLONG ReadOperationCount; + ULONGLONG WriteOperationCount; + ULONGLONG OtherOperationCount; + ULONGLONG ReadTransferCount; + ULONGLONG WriteTransferCount; + ULONGLONG OtherTransferCount; + } IO_COUNTERS; + typedef IO_COUNTERS *PIO_COUNTERS; + + typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION { + LARGE_INTEGER TotalUserTime; + LARGE_INTEGER TotalKernelTime; + LARGE_INTEGER ThisPeriodTotalUserTime; + LARGE_INTEGER ThisPeriodTotalKernelTime; + DWORD TotalPageFaultCount; + DWORD TotalProcesses; + DWORD ActiveProcesses; + DWORD TotalTerminatedProcesses; + } JOBOBJECT_BASIC_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION; + + typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION { + LARGE_INTEGER PerProcessUserTimeLimit; + LARGE_INTEGER PerJobUserTimeLimit; + DWORD LimitFlags; + SIZE_T MinimumWorkingSetSize; + SIZE_T MaximumWorkingSetSize; + DWORD ActiveProcessLimit; + ULONG_PTR Affinity; + DWORD PriorityClass; + DWORD SchedulingClass; + } JOBOBJECT_BASIC_LIMIT_INFORMATION,*PJOBOBJECT_BASIC_LIMIT_INFORMATION; + + typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION { + JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; + IO_COUNTERS IoInfo; + SIZE_T ProcessMemoryLimit; + SIZE_T JobMemoryLimit; + SIZE_T PeakProcessMemoryUsed; + SIZE_T PeakJobMemoryUsed; + } JOBOBJECT_EXTENDED_LIMIT_INFORMATION,*PJOBOBJECT_EXTENDED_LIMIT_INFORMATION; + + typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST { + DWORD NumberOfAssignedProcesses; + DWORD NumberOfProcessIdsInList; + ULONG_PTR ProcessIdList[1]; + } JOBOBJECT_BASIC_PROCESS_ID_LIST,*PJOBOBJECT_BASIC_PROCESS_ID_LIST; + + typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS { + DWORD UIRestrictionsClass; + } JOBOBJECT_BASIC_UI_RESTRICTIONS,*PJOBOBJECT_BASIC_UI_RESTRICTIONS; + + typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION { + DWORD SecurityLimitFlags; + HANDLE JobToken; + PTOKEN_GROUPS SidsToDisable; + PTOKEN_PRIVILEGES PrivilegesToDelete; + PTOKEN_GROUPS RestrictedSids; + } JOBOBJECT_SECURITY_LIMIT_INFORMATION,*PJOBOBJECT_SECURITY_LIMIT_INFORMATION; + + typedef struct _JOBOBJECT_END_OF_JOB_TIME_INFORMATION { + DWORD EndOfJobTimeAction; + } JOBOBJECT_END_OF_JOB_TIME_INFORMATION,*PJOBOBJECT_END_OF_JOB_TIME_INFORMATION; + + typedef struct _JOBOBJECT_ASSOCIATE_COMPLETION_PORT { + PVOID CompletionKey; + HANDLE CompletionPort; + } JOBOBJECT_ASSOCIATE_COMPLETION_PORT,*PJOBOBJECT_ASSOCIATE_COMPLETION_PORT; + + typedef struct _JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION { + JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo; + IO_COUNTERS IoInfo; + } JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION; + + typedef struct _JOBOBJECT_JOBSET_INFORMATION { + DWORD MemberLevel; + } JOBOBJECT_JOBSET_INFORMATION,*PJOBOBJECT_JOBSET_INFORMATION; + +#define JOB_OBJECT_TERMINATE_AT_END_OF_JOB 0 +#define JOB_OBJECT_POST_AT_END_OF_JOB 1 + +#define JOB_OBJECT_MSG_END_OF_JOB_TIME 1 +#define JOB_OBJECT_MSG_END_OF_PROCESS_TIME 2 +#define JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT 3 +#define JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO 4 +#define JOB_OBJECT_MSG_NEW_PROCESS 6 +#define JOB_OBJECT_MSG_EXIT_PROCESS 7 +#define JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS 8 +#define JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT 9 +#define JOB_OBJECT_MSG_JOB_MEMORY_LIMIT 10 + +#define JOB_OBJECT_LIMIT_WORKINGSET 0x00000001 +#define JOB_OBJECT_LIMIT_PROCESS_TIME 0x00000002 +#define JOB_OBJECT_LIMIT_JOB_TIME 0x00000004 +#define JOB_OBJECT_LIMIT_ACTIVE_PROCESS 0x00000008 +#define JOB_OBJECT_LIMIT_AFFINITY 0x00000010 +#define JOB_OBJECT_LIMIT_PRIORITY_CLASS 0x00000020 +#define JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME 0x00000040 +#define JOB_OBJECT_LIMIT_SCHEDULING_CLASS 0x00000080 + +#define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100 +#define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200 +#define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400 +#define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800 +#define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000 +#define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 + +#define JOB_OBJECT_LIMIT_RESERVED2 0x00004000 +#define JOB_OBJECT_LIMIT_RESERVED3 0x00008000 +#define JOB_OBJECT_LIMIT_RESERVED4 0x00010000 +#define JOB_OBJECT_LIMIT_RESERVED5 0x00020000 +#define JOB_OBJECT_LIMIT_RESERVED6 0x00040000 + +#define JOB_OBJECT_LIMIT_VALID_FLAGS 0x0007ffff + +#define JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS 0x000000ff +#define JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS 0x00003fff +#define JOB_OBJECT_RESERVED_LIMIT_VALID_FLAGS 0x0007ffff + +#define JOB_OBJECT_UILIMIT_NONE 0x00000000 + +#define JOB_OBJECT_UILIMIT_HANDLES 0x00000001 +#define JOB_OBJECT_UILIMIT_READCLIPBOARD 0x00000002 +#define JOB_OBJECT_UILIMIT_WRITECLIPBOARD 0x00000004 +#define JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS 0x00000008 +#define JOB_OBJECT_UILIMIT_DISPLAYSETTINGS 0x00000010 +#define JOB_OBJECT_UILIMIT_GLOBALATOMS 0x00000020 +#define JOB_OBJECT_UILIMIT_DESKTOP 0x00000040 +#define JOB_OBJECT_UILIMIT_EXITWINDOWS 0x00000080 + +#define JOB_OBJECT_UILIMIT_ALL 0x000000FF + +#define JOB_OBJECT_UI_VALID_FLAGS 0x000000FF + +#define JOB_OBJECT_SECURITY_NO_ADMIN 0x00000001 +#define JOB_OBJECT_SECURITY_RESTRICTED_TOKEN 0x00000002 +#define JOB_OBJECT_SECURITY_ONLY_TOKEN 0x00000004 +#define JOB_OBJECT_SECURITY_FILTER_TOKENS 0x00000008 + +#define JOB_OBJECT_SECURITY_VALID_FLAGS 0x0000000f + + typedef enum _JOBOBJECTINFOCLASS { + JobObjectBasicAccountingInformation = 1,JobObjectBasicLimitInformation,JobObjectBasicProcessIdList,JobObjectBasicUIRestrictions, + JobObjectSecurityLimitInformation,JobObjectEndOfJobTimeInformation,JobObjectAssociateCompletionPortInformation, + JobObjectBasicAndIoAccountingInformation,JobObjectExtendedLimitInformation,JobObjectJobSetInformation,MaxJobObjectInfoClass + } JOBOBJECTINFOCLASS; + +#define EVENT_MODIFY_STATE 0x0002 +#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define MUTANT_QUERY_STATE 0x0001 + +#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| MUTANT_QUERY_STATE) +#define SEMAPHORE_MODIFY_STATE 0x0002 +#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define TIMER_QUERY_STATE 0x0001 +#define TIMER_MODIFY_STATE 0x0002 + +#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| TIMER_QUERY_STATE|TIMER_MODIFY_STATE) + +#define TIME_ZONE_ID_UNKNOWN 0 +#define TIME_ZONE_ID_STANDARD 1 +#define TIME_ZONE_ID_DAYLIGHT 2 + + typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { + RelationProcessorCore,RelationNumaNode,RelationCache + } LOGICAL_PROCESSOR_RELATIONSHIP; + +#define LTP_PC_SMT 0x1 + + typedef enum _PROCESSOR_CACHE_TYPE { + CacheUnified,CacheInstruction,CacheData,CacheTrace + } PROCESSOR_CACHE_TYPE; + +#define CACHE_FULLY_ASSOCIATIVE 0xFF + + typedef struct _CACHE_DESCRIPTOR { + BYTE Level; + BYTE Associativity; + WORD LineSize; + DWORD Size; + PROCESSOR_CACHE_TYPE Type; + } CACHE_DESCRIPTOR,*PCACHE_DESCRIPTOR; + + typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { + ULONG_PTR ProcessorMask; + LOGICAL_PROCESSOR_RELATIONSHIP Relationship; + union { + struct { + BYTE Flags; + } ProcessorCore; + struct { + DWORD NodeNumber; + } NumaNode; + CACHE_DESCRIPTOR Cache; + ULONGLONG Reserved[2]; + }; + } SYSTEM_LOGICAL_PROCESSOR_INFORMATION,*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; + +#define PROCESSOR_INTEL_386 386 +#define PROCESSOR_INTEL_486 486 +#define PROCESSOR_INTEL_PENTIUM 586 +#define PROCESSOR_INTEL_IA64 2200 +#define PROCESSOR_AMD_X8664 8664 +#define PROCESSOR_MIPS_R4000 4000 +#define PROCESSOR_ALPHA_21064 21064 +#define PROCESSOR_PPC_601 601 +#define PROCESSOR_PPC_603 603 +#define PROCESSOR_PPC_604 604 +#define PROCESSOR_PPC_620 620 +#define PROCESSOR_HITACHI_SH3 10003 +#define PROCESSOR_HITACHI_SH3E 10004 +#define PROCESSOR_HITACHI_SH4 10005 +#define PROCESSOR_MOTOROLA_821 821 +#define PROCESSOR_SHx_SH3 103 +#define PROCESSOR_SHx_SH4 104 +#define PROCESSOR_STRONGARM 2577 +#define PROCESSOR_ARM720 1824 +#define PROCESSOR_ARM820 2080 +#define PROCESSOR_ARM920 2336 +#define PROCESSOR_ARM_7TDMI 70001 +#define PROCESSOR_OPTIL 0x494f + +#define PROCESSOR_ARCHITECTURE_INTEL 0 +#define PROCESSOR_ARCHITECTURE_MIPS 1 +#define PROCESSOR_ARCHITECTURE_ALPHA 2 +#define PROCESSOR_ARCHITECTURE_PPC 3 +#define PROCESSOR_ARCHITECTURE_SHX 4 +#define PROCESSOR_ARCHITECTURE_ARM 5 +#define PROCESSOR_ARCHITECTURE_IA64 6 +#define PROCESSOR_ARCHITECTURE_ALPHA64 7 +#define PROCESSOR_ARCHITECTURE_MSIL 8 +#define PROCESSOR_ARCHITECTURE_AMD64 9 +#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 + +#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF + +#define PF_FLOATING_POINT_PRECISION_ERRATA 0 +#define PF_FLOATING_POINT_EMULATED 1 +#define PF_COMPARE_EXCHANGE_DOUBLE 2 +#define PF_MMX_INSTRUCTIONS_AVAILABLE 3 +#define PF_PPC_MOVEMEM_64BIT_OK 4 +#define PF_ALPHA_BYTE_INSTRUCTIONS 5 +#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6 +#define PF_3DNOW_INSTRUCTIONS_AVAILABLE 7 +#define PF_RDTSC_INSTRUCTION_AVAILABLE 8 +#define PF_PAE_ENABLED 9 +#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10 +#define PF_SSE_DAZ_MODE_AVAILABLE 11 +#define PF_NX_ENABLED 12 + + typedef struct _MEMORY_BASIC_INFORMATION { + PVOID BaseAddress; + PVOID AllocationBase; + DWORD AllocationProtect; + SIZE_T RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; + } MEMORY_BASIC_INFORMATION,*PMEMORY_BASIC_INFORMATION; + + typedef struct _MEMORY_BASIC_INFORMATION32 { + DWORD BaseAddress; + DWORD AllocationBase; + DWORD AllocationProtect; + DWORD RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; + } MEMORY_BASIC_INFORMATION32,*PMEMORY_BASIC_INFORMATION32; + + typedef struct DECLSPEC_ALIGN(16) _MEMORY_BASIC_INFORMATION64 { + ULONGLONG BaseAddress; + ULONGLONG AllocationBase; + DWORD AllocationProtect; + DWORD __alignment1; + ULONGLONG RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; + DWORD __alignment2; + } MEMORY_BASIC_INFORMATION64,*PMEMORY_BASIC_INFORMATION64; + +#define SECTION_QUERY 0x0001 +#define SECTION_MAP_WRITE 0x0002 +#define SECTION_MAP_READ 0x0004 +#define SECTION_MAP_EXECUTE 0x0008 +#define SECTION_EXTEND_SIZE 0x0010 +#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020 + +#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY| SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE) +#define PAGE_NOACCESS 0x01 +#define PAGE_READONLY 0x02 +#define PAGE_READWRITE 0x04 +#define PAGE_WRITECOPY 0x08 +#define PAGE_EXECUTE 0x10 +#define PAGE_EXECUTE_READ 0x20 +#define PAGE_EXECUTE_READWRITE 0x40 +#define PAGE_EXECUTE_WRITECOPY 0x80 +#define PAGE_GUARD 0x100 +#define PAGE_NOCACHE 0x200 +#define PAGE_WRITECOMBINE 0x400 +#define MEM_COMMIT 0x1000 +#define MEM_RESERVE 0x2000 +#define MEM_DECOMMIT 0x4000 +#define MEM_RELEASE 0x8000 +#define MEM_FREE 0x10000 +#define MEM_PRIVATE 0x20000 +#define MEM_MAPPED 0x40000 +#define MEM_RESET 0x80000 +#define MEM_TOP_DOWN 0x100000 +#define MEM_WRITE_WATCH 0x200000 +#define MEM_PHYSICAL 0x400000 +#define MEM_LARGE_PAGES 0x20000000 +#define MEM_4MB_PAGES 0x80000000 +#define SEC_FILE 0x800000 +#define SEC_IMAGE 0x1000000 +#define SEC_RESERVE 0x4000000 +#define SEC_COMMIT 0x8000000 +#define SEC_NOCACHE 0x10000000 +#define SEC_LARGE_PAGES 0x80000000 +#define MEM_IMAGE SEC_IMAGE +#define WRITE_WATCH_FLAG_RESET 0x01 + +#define FILE_READ_DATA (0x0001) +#define FILE_LIST_DIRECTORY (0x0001) + +#define FILE_WRITE_DATA (0x0002) +#define FILE_ADD_FILE (0x0002) + +#define FILE_APPEND_DATA (0x0004) +#define FILE_ADD_SUBDIRECTORY (0x0004) +#define FILE_CREATE_PIPE_INSTANCE (0x0004) + +#define FILE_READ_EA (0x0008) + +#define FILE_WRITE_EA (0x0010) + +#define FILE_EXECUTE (0x0020) +#define FILE_TRAVERSE (0x0020) + +#define FILE_DELETE_CHILD (0x0040) + +#define FILE_READ_ATTRIBUTES (0x0080) + +#define FILE_WRITE_ATTRIBUTES (0x0100) + +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE) +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE) +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE) + +#define FILE_SHARE_READ 0x00000001 +#define FILE_SHARE_WRITE 0x00000002 +#define FILE_SHARE_DELETE 0x00000004 +#define FILE_ATTRIBUTE_READONLY 0x00000001 +#define FILE_ATTRIBUTE_HIDDEN 0x00000002 +#define FILE_ATTRIBUTE_SYSTEM 0x00000004 +#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 +#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 +#define FILE_ATTRIBUTE_DEVICE 0x00000040 +#define FILE_ATTRIBUTE_NORMAL 0x00000080 +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 +#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 +#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 +#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 +#define FILE_ATTRIBUTE_OFFLINE 0x00001000 +#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 +#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 +#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 +#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 +#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 +#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 +#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 +#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 +#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 +#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 +#define FILE_ACTION_ADDED 0x00000001 +#define FILE_ACTION_REMOVED 0x00000002 +#define FILE_ACTION_MODIFIED 0x00000003 +#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 +#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 +#define MAILSLOT_NO_MESSAGE ((DWORD)-1) +#define MAILSLOT_WAIT_FOREVER ((DWORD)-1) +#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 +#define FILE_CASE_PRESERVED_NAMES 0x00000002 +#define FILE_UNICODE_ON_DISK 0x00000004 +#define FILE_PERSISTENT_ACLS 0x00000008 +#define FILE_FILE_COMPRESSION 0x00000010 +#define FILE_VOLUME_QUOTAS 0x00000020 +#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 +#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 +#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 +#define FILE_VOLUME_IS_COMPRESSED 0x00008000 +#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 +#define FILE_SUPPORTS_ENCRYPTION 0x00020000 +#define FILE_NAMED_STREAMS 0x00040000 +#define FILE_READ_ONLY_VOLUME 0x00080000 + + typedef struct _FILE_NOTIFY_INFORMATION { + DWORD NextEntryOffset; + DWORD Action; + DWORD FileNameLength; + WCHAR FileName[1]; + } FILE_NOTIFY_INFORMATION,*PFILE_NOTIFY_INFORMATION; + + typedef union _FILE_SEGMENT_ELEMENT { + PVOID64 Buffer; + ULONGLONG Alignment; + }FILE_SEGMENT_ELEMENT,*PFILE_SEGMENT_ELEMENT; + + typedef struct _REPARSE_GUID_DATA_BUFFER { + DWORD ReparseTag; + WORD ReparseDataLength; + WORD Reserved; + GUID ReparseGuid; + struct { + BYTE DataBuffer[1]; + } GenericReparseBuffer; + } REPARSE_GUID_DATA_BUFFER,*PREPARSE_GUID_DATA_BUFFER; + +#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER,GenericReparseBuffer) + +#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 *1024) + +#define IO_REPARSE_TAG_RESERVED_ZERO (0) +#define IO_REPARSE_TAG_RESERVED_ONE (1) + +#define IO_REPARSE_TAG_RESERVED_RANGE IO_REPARSE_TAG_RESERVED_ONE + +#define IsReparseTagMicrosoft(_tag) (((_tag) & 0x80000000)) +#define IsReparseTagNameSurrogate(_tag) (((_tag) & 0x20000000)) + +#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) +#define IO_REPARSE_TAG_HSM (0xC0000004L) +#define IO_REPARSE_TAG_SIS (0x80000007L) +#define IO_REPARSE_TAG_DFS (0x8000000AL) +#define IO_REPARSE_TAG_FILTER_MANAGER (0x8000000BL) +#define IO_COMPLETION_MODIFY_STATE 0x0002 +#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) +#define DUPLICATE_CLOSE_SOURCE 0x00000001 +#define DUPLICATE_SAME_ACCESS 0x00000002 + + typedef enum _SYSTEM_POWER_STATE { + PowerSystemUnspecified = 0,PowerSystemWorking = 1,PowerSystemSleeping1 = 2,PowerSystemSleeping2 = 3,PowerSystemSleeping3 = 4,PowerSystemHibernate = 5,PowerSystemShutdown = 6,PowerSystemMaximum = 7 + } SYSTEM_POWER_STATE,*PSYSTEM_POWER_STATE; + +#define POWER_SYSTEM_MAXIMUM 7 + + typedef enum { + PowerActionNone = 0,PowerActionReserved,PowerActionSleep,PowerActionHibernate,PowerActionShutdown,PowerActionShutdownReset,PowerActionShutdownOff,PowerActionWarmEject + } POWER_ACTION,*PPOWER_ACTION; + + typedef enum _DEVICE_POWER_STATE { + PowerDeviceUnspecified = 0,PowerDeviceD0,PowerDeviceD1,PowerDeviceD2,PowerDeviceD3,PowerDeviceMaximum + } DEVICE_POWER_STATE,*PDEVICE_POWER_STATE; + +#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001) +#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002) +#define ES_USER_PRESENT ((DWORD)0x00000004) +#define ES_CONTINUOUS ((DWORD)0x80000000) + + typedef DWORD EXECUTION_STATE; + + typedef enum { + LT_DONT_CARE,LT_LOWEST_LATENCY + } LATENCY_TIME; + +#define PDCAP_D0_SUPPORTED 0x00000001 +#define PDCAP_D1_SUPPORTED 0x00000002 +#define PDCAP_D2_SUPPORTED 0x00000004 +#define PDCAP_D3_SUPPORTED 0x00000008 +#define PDCAP_WAKE_FROM_D0_SUPPORTED 0x00000010 +#define PDCAP_WAKE_FROM_D1_SUPPORTED 0x00000020 +#define PDCAP_WAKE_FROM_D2_SUPPORTED 0x00000040 +#define PDCAP_WAKE_FROM_D3_SUPPORTED 0x00000080 +#define PDCAP_WARM_EJECT_SUPPORTED 0x00000100 + + typedef struct CM_Power_Data_s { + DWORD PD_Size; + DEVICE_POWER_STATE PD_MostRecentPowerState; + DWORD PD_Capabilities; + DWORD PD_D1Latency; + DWORD PD_D2Latency; + DWORD PD_D3Latency; + DEVICE_POWER_STATE PD_PowerStateMapping[POWER_SYSTEM_MAXIMUM]; + SYSTEM_POWER_STATE PD_DeepestSystemWake; + } CM_POWER_DATA,*PCM_POWER_DATA; + + typedef enum { + SystemPowerPolicyAc,SystemPowerPolicyDc,VerifySystemPolicyAc,VerifySystemPolicyDc,SystemPowerCapabilities,SystemBatteryState,SystemPowerStateHandler,ProcessorStateHandler,SystemPowerPolicyCurrent,AdministratorPowerPolicy,SystemReserveHiberFile,ProcessorInformation,SystemPowerInformation,ProcessorStateHandler2,LastWakeTime,LastSleepTime,SystemExecutionState,SystemPowerStateNotifyHandler,ProcessorPowerPolicyAc,ProcessorPowerPolicyDc,VerifyProcessorPowerPolicyAc,VerifyProcessorPowerPolicyDc,ProcessorPowerPolicyCurrent,SystemPowerStateLogging,SystemPowerLoggingEntry + } POWER_INFORMATION_LEVEL; + + typedef struct { + DWORD Granularity; + DWORD Capacity; + } BATTERY_REPORTING_SCALE,*PBATTERY_REPORTING_SCALE; + + typedef struct { + POWER_ACTION Action; + DWORD Flags; + DWORD EventCode; + } POWER_ACTION_POLICY,*PPOWER_ACTION_POLICY; + +#define POWER_ACTION_QUERY_ALLOWED 0x00000001 +#define POWER_ACTION_UI_ALLOWED 0x00000002 +#define POWER_ACTION_OVERRIDE_APPS 0x00000004 +#define POWER_ACTION_LIGHTEST_FIRST 0x10000000 +#define POWER_ACTION_LOCK_CONSOLE 0x20000000 +#define POWER_ACTION_DISABLE_WAKES 0x40000000 +#define POWER_ACTION_CRITICAL 0x80000000 + +#define POWER_LEVEL_USER_NOTIFY_TEXT 0x00000001 +#define POWER_LEVEL_USER_NOTIFY_SOUND 0x00000002 +#define POWER_LEVEL_USER_NOTIFY_EXEC 0x00000004 +#define POWER_USER_NOTIFY_BUTTON 0x00000008 +#define POWER_USER_NOTIFY_SHUTDOWN 0x00000010 +#define POWER_FORCE_TRIGGER_RESET 0x80000000 + + typedef struct { + BOOLEAN Enable; + BYTE Spare[3]; + DWORD BatteryLevel; + POWER_ACTION_POLICY PowerPolicy; + SYSTEM_POWER_STATE MinSystemState; + } SYSTEM_POWER_LEVEL,*PSYSTEM_POWER_LEVEL; + +#define NUM_DISCHARGE_POLICIES 4 +#define DISCHARGE_POLICY_CRITICAL 0 +#define DISCHARGE_POLICY_LOW 1 + +#define PO_THROTTLE_NONE 0 +#define PO_THROTTLE_CONSTANT 1 +#define PO_THROTTLE_DEGRADE 2 +#define PO_THROTTLE_ADAPTIVE 3 +#define PO_THROTTLE_MAXIMUM 4 + + typedef struct _SYSTEM_POWER_POLICY { + DWORD Revision; + POWER_ACTION_POLICY PowerButton; + POWER_ACTION_POLICY SleepButton; + POWER_ACTION_POLICY LidClose; + SYSTEM_POWER_STATE LidOpenWake; + DWORD Reserved; + POWER_ACTION_POLICY Idle; + DWORD IdleTimeout; + BYTE IdleSensitivity; + BYTE DynamicThrottle; + BYTE Spare2[2]; + SYSTEM_POWER_STATE MinSleep; + SYSTEM_POWER_STATE MaxSleep; + SYSTEM_POWER_STATE ReducedLatencySleep; + DWORD WinLogonFlags; + DWORD Spare3; + DWORD DozeS4Timeout; + DWORD BroadcastCapacityResolution; + SYSTEM_POWER_LEVEL DischargePolicy[NUM_DISCHARGE_POLICIES]; + DWORD VideoTimeout; + BOOLEAN VideoDimDisplay; + DWORD VideoReserved[3]; + DWORD SpindownTimeout; + BOOLEAN OptimizeForPower; + BYTE FanThrottleTolerance; + BYTE ForcedThrottle; + BYTE MinThrottle; + POWER_ACTION_POLICY OverThrottled; + } SYSTEM_POWER_POLICY,*PSYSTEM_POWER_POLICY; + + typedef struct _PROCESSOR_POWER_POLICY_INFO { + DWORD TimeCheck; + DWORD DemoteLimit; + DWORD PromoteLimit; + BYTE DemotePercent; + BYTE PromotePercent; + BYTE Spare[2]; + DWORD AllowDemotion:1; + DWORD AllowPromotion:1; + DWORD Reserved:30; + } PROCESSOR_POWER_POLICY_INFO,*PPROCESSOR_POWER_POLICY_INFO; + + typedef struct _PROCESSOR_POWER_POLICY { + DWORD Revision; + BYTE DynamicThrottle; + BYTE Spare[3]; + DWORD DisableCStates:1; + DWORD Reserved:31; + DWORD PolicyCount; + PROCESSOR_POWER_POLICY_INFO Policy[3]; + } PROCESSOR_POWER_POLICY,*PPROCESSOR_POWER_POLICY; + + typedef struct _ADMINISTRATOR_POWER_POLICY { + SYSTEM_POWER_STATE MinSleep; + SYSTEM_POWER_STATE MaxSleep; + DWORD MinVideoTimeout; + DWORD MaxVideoTimeout; + DWORD MinSpindownTimeout; + DWORD MaxSpindownTimeout; + } ADMINISTRATOR_POWER_POLICY,*PADMINISTRATOR_POWER_POLICY; + + typedef struct { + BOOLEAN PowerButtonPresent; + BOOLEAN SleepButtonPresent; + BOOLEAN LidPresent; + BOOLEAN SystemS1; + BOOLEAN SystemS2; + BOOLEAN SystemS3; + BOOLEAN SystemS4; + BOOLEAN SystemS5; + BOOLEAN HiberFilePresent; + BOOLEAN FullWake; + BOOLEAN VideoDimPresent; + BOOLEAN ApmPresent; + BOOLEAN UpsPresent; + BOOLEAN ThermalControl; + BOOLEAN ProcessorThrottle; + BYTE ProcessorMinThrottle; + BYTE ProcessorMaxThrottle; + BYTE spare2[4]; + BOOLEAN DiskSpinDown; + BYTE spare3[8]; + BOOLEAN SystemBatteriesPresent; + BOOLEAN BatteriesAreShortTerm; + BATTERY_REPORTING_SCALE BatteryScale[3]; + SYSTEM_POWER_STATE AcOnLineWake; + SYSTEM_POWER_STATE SoftLidWake; + SYSTEM_POWER_STATE RtcWake; + SYSTEM_POWER_STATE MinDeviceWakeState; + SYSTEM_POWER_STATE DefaultLowLatencyWake; + } SYSTEM_POWER_CAPABILITIES,*PSYSTEM_POWER_CAPABILITIES; + + typedef struct { + BOOLEAN AcOnLine; + BOOLEAN BatteryPresent; + BOOLEAN Charging; + BOOLEAN Discharging; + BOOLEAN Spare1[4]; + DWORD MaxCapacity; + DWORD RemainingCapacity; + DWORD Rate; + DWORD EstimatedTime; + DWORD DefaultAlert1; + DWORD DefaultAlert2; + } SYSTEM_BATTERY_STATE,*PSYSTEM_BATTERY_STATE; + +#include "pshpack4.h" + +#define IMAGE_DOS_SIGNATURE 0x5A4D +#define IMAGE_OS2_SIGNATURE 0x454E +#define IMAGE_OS2_SIGNATURE_LE 0x454C +#define IMAGE_VXD_SIGNATURE 0x454C +#define IMAGE_NT_SIGNATURE 0x00004550 + +#include "pshpack2.h" + + typedef struct _IMAGE_DOS_HEADER { + WORD e_magic; + WORD e_cblp; + WORD e_cp; + WORD e_crlc; + WORD e_cparhdr; + WORD e_minalloc; + WORD e_maxalloc; + WORD e_ss; + WORD e_sp; + WORD e_csum; + WORD e_ip; + WORD e_cs; + WORD e_lfarlc; + WORD e_ovno; + WORD e_res[4]; + WORD e_oemid; + WORD e_oeminfo; + WORD e_res2[10]; + LONG e_lfanew; + } IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER; + + typedef struct _IMAGE_OS2_HEADER { + WORD ne_magic; + CHAR ne_ver; + CHAR ne_rev; + WORD ne_enttab; + WORD ne_cbenttab; + LONG ne_crc; + WORD ne_flags; + WORD ne_autodata; + WORD ne_heap; + WORD ne_stack; + LONG ne_csip; + LONG ne_sssp; + WORD ne_cseg; + WORD ne_cmod; + WORD ne_cbnrestab; + WORD ne_segtab; + WORD ne_rsrctab; + WORD ne_restab; + WORD ne_modtab; + WORD ne_imptab; + LONG ne_nrestab; + WORD ne_cmovent; + WORD ne_align; + WORD ne_cres; + BYTE ne_exetyp; + BYTE ne_flagsothers; + WORD ne_pretthunks; + WORD ne_psegrefbytes; + WORD ne_swaparea; + WORD ne_expver; + } IMAGE_OS2_HEADER,*PIMAGE_OS2_HEADER; + + typedef struct _IMAGE_VXD_HEADER { + WORD e32_magic; + BYTE e32_border; + BYTE e32_worder; + DWORD e32_level; + WORD e32_cpu; + WORD e32_os; + DWORD e32_ver; + DWORD e32_mflags; + DWORD e32_mpages; + DWORD e32_startobj; + DWORD e32_eip; + DWORD e32_stackobj; + DWORD e32_esp; + DWORD e32_pagesize; + DWORD e32_lastpagesize; + DWORD e32_fixupsize; + DWORD e32_fixupsum; + DWORD e32_ldrsize; + DWORD e32_ldrsum; + DWORD e32_objtab; + DWORD e32_objcnt; + DWORD e32_objmap; + DWORD e32_itermap; + DWORD e32_rsrctab; + DWORD e32_rsrccnt; + DWORD e32_restab; + DWORD e32_enttab; + DWORD e32_dirtab; + DWORD e32_dircnt; + DWORD e32_fpagetab; + DWORD e32_frectab; + DWORD e32_impmod; + DWORD e32_impmodcnt; + DWORD e32_impproc; + DWORD e32_pagesum; + DWORD e32_datapage; + DWORD e32_preload; + DWORD e32_nrestab; + DWORD e32_cbnrestab; + DWORD e32_nressum; + DWORD e32_autodata; + DWORD e32_debuginfo; + DWORD e32_debuglen; + DWORD e32_instpreload; + DWORD e32_instdemand; + DWORD e32_heapsize; + BYTE e32_res3[12]; + DWORD e32_winresoff; + DWORD e32_winreslen; + WORD e32_devid; + WORD e32_ddkver; + } IMAGE_VXD_HEADER,*PIMAGE_VXD_HEADER; + +#include "poppack.h" + + typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; + } IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER; + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_R3000 0x0162 +#define IMAGE_FILE_MACHINE_R4000 0x0166 +#define IMAGE_FILE_MACHINE_R10000 0x0168 +#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 +#define IMAGE_FILE_MACHINE_ALPHA 0x0184 +#define IMAGE_FILE_MACHINE_SH3 0x01a2 +#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 +#define IMAGE_FILE_MACHINE_SH3E 0x01a4 +#define IMAGE_FILE_MACHINE_SH4 0x01a6 +#define IMAGE_FILE_MACHINE_SH5 0x01a8 +#define IMAGE_FILE_MACHINE_ARM 0x01c0 +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 +#define IMAGE_FILE_MACHINE_AM33 0x01d3 +#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 +#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_MIPS16 0x0266 +#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 +#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 +#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 +#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 +#define IMAGE_FILE_MACHINE_TRICORE 0x0520 +#define IMAGE_FILE_MACHINE_CEF 0x0CEF +#define IMAGE_FILE_MACHINE_EBC 0x0EBC +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_M32R 0x9041 +#define IMAGE_FILE_MACHINE_CEE 0xC0EE + + typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; + } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + + typedef struct _IMAGE_OPTIONAL_HEADER { + + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + } IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32; + + typedef struct _IMAGE_ROM_OPTIONAL_HEADER { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD BaseOfBss; + DWORD GprMask; + DWORD CprMask[4]; + DWORD GpValue; + } IMAGE_ROM_OPTIONAL_HEADER,*PIMAGE_ROM_OPTIONAL_HEADER; + + typedef struct _IMAGE_OPTIONAL_HEADER64 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + } IMAGE_OPTIONAL_HEADER64,*PIMAGE_OPTIONAL_HEADER64; + +#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 +#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 +#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224 +#define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240 + +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +#ifdef _WIN64 + typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; + typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL64_HEADER +#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC +#else + typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; + typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL32_HEADER +#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC +#endif + + typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; + } IMAGE_NT_HEADERS64,*PIMAGE_NT_HEADERS64; + + typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; + } IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32; + + typedef struct _IMAGE_ROM_HEADERS { + IMAGE_FILE_HEADER FileHeader; + IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; + } IMAGE_ROM_HEADERS,*PIMAGE_ROM_HEADERS; + +#ifdef _WIN64 + typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; + typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; +#else + typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; + typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; +#endif + +#define IMAGE_FIRST_SECTION(ntheader) ((PIMAGE_SECTION_HEADER) ((ULONG_PTR)ntheader + FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader) + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 +#define IMAGE_SUBSYSTEM_NATIVE 1 +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 +#define IMAGE_SUBSYSTEM_OS2_CUI 5 +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 +#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 +#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define IMAGE_SUBSYSTEM_EFI_ROM 13 +#define IMAGE_SUBSYSTEM_XBOX 14 + +#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 +#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 +#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 +#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 +#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 + +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 +#define IMAGE_DIRECTORY_ENTRY_IAT 12 +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + + typedef struct ANON_OBJECT_HEADER { + WORD Sig1; + WORD Sig2; + WORD Version; + WORD Machine; + DWORD TimeDateStamp; + CLSID ClassID; + DWORD SizeOfData; + } ANON_OBJECT_HEADER; + +#define IMAGE_SIZEOF_SHORT_NAME 8 + + typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; + } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 +#define IMAGE_SCN_LNK_OTHER 0x00000100 +#define IMAGE_SCN_LNK_INFO 0x00000200 +#define IMAGE_SCN_LNK_REMOVE 0x00000800 +#define IMAGE_SCN_LNK_COMDAT 0x00001000 +#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 +#define IMAGE_SCN_GPREL 0x00008000 +#define IMAGE_SCN_MEM_FARDATA 0x00008000 +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 +#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 +#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 +#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 +#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 + +#define IMAGE_SCN_ALIGN_MASK 0x00F00000 + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +#define IMAGE_SCN_SCALE_INDEX 0x00000001 + +#include "pshpack2.h" + + typedef struct _IMAGE_SYMBOL { + union { + BYTE ShortName[8]; + struct { + DWORD Short; + DWORD Long; + } Name; + DWORD LongName[2]; + } N; + DWORD Value; + SHORT SectionNumber; + WORD Type; + BYTE StorageClass; + BYTE NumberOfAuxSymbols; + } IMAGE_SYMBOL; + typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL; + +#define IMAGE_SIZEOF_SYMBOL 18 + +#define IMAGE_SYM_UNDEFINED (SHORT)0 +#define IMAGE_SYM_ABSOLUTE (SHORT)-1 +#define IMAGE_SYM_DEBUG (SHORT)-2 +#define IMAGE_SYM_SECTION_MAX 0xFEFF + +#define IMAGE_SYM_TYPE_NULL 0x0000 +#define IMAGE_SYM_TYPE_VOID 0x0001 +#define IMAGE_SYM_TYPE_CHAR 0x0002 +#define IMAGE_SYM_TYPE_SHORT 0x0003 +#define IMAGE_SYM_TYPE_INT 0x0004 +#define IMAGE_SYM_TYPE_LONG 0x0005 +#define IMAGE_SYM_TYPE_FLOAT 0x0006 +#define IMAGE_SYM_TYPE_DOUBLE 0x0007 +#define IMAGE_SYM_TYPE_STRUCT 0x0008 +#define IMAGE_SYM_TYPE_UNION 0x0009 +#define IMAGE_SYM_TYPE_ENUM 0x000A +#define IMAGE_SYM_TYPE_MOE 0x000B +#define IMAGE_SYM_TYPE_BYTE 0x000C +#define IMAGE_SYM_TYPE_WORD 0x000D +#define IMAGE_SYM_TYPE_UINT 0x000E +#define IMAGE_SYM_TYPE_DWORD 0x000F +#define IMAGE_SYM_TYPE_PCODE 0x8000 + +#define IMAGE_SYM_DTYPE_NULL 0 +#define IMAGE_SYM_DTYPE_POINTER 1 +#define IMAGE_SYM_DTYPE_FUNCTION 2 +#define IMAGE_SYM_DTYPE_ARRAY 3 + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE)-1 +#define IMAGE_SYM_CLASS_NULL 0x0000 +#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 +#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 +#define IMAGE_SYM_CLASS_STATIC 0x0003 +#define IMAGE_SYM_CLASS_REGISTER 0x0004 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 +#define IMAGE_SYM_CLASS_LABEL 0x0006 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 +#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 +#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B +#define IMAGE_SYM_CLASS_UNION_TAG 0x000C +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E +#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 +#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 +#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 +#define IMAGE_SYM_CLASS_BLOCK 0x0064 +#define IMAGE_SYM_CLASS_FUNCTION 0x0065 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 +#define IMAGE_SYM_CLASS_FILE 0x0067 +#define IMAGE_SYM_CLASS_SECTION 0x0068 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 +#define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B + +#define N_BTMASK 0x000F +#define N_TMASK 0x0030 +#define N_TMASK1 0x00C0 +#define N_TMASK2 0x00F0 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +#define BTYPE(x) ((x) & N_BTMASK) + +#ifndef ISPTR +#define ISPTR(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) +#endif + +#ifndef ISFCN +#define ISFCN(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) +#endif + +#ifndef ISARY +#define ISARY(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) +#endif + +#ifndef ISTAG +#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) +#endif + +#ifndef INCREF +#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) +#endif + + typedef union _IMAGE_AUX_SYMBOL { + struct { + DWORD TagIndex; + union { + struct { + WORD Linenumber; + WORD Size; + } LnSz; + DWORD TotalSize; + } Misc; + union { + struct { + DWORD PointerToLinenumber; + DWORD PointerToNextFunction; + } Function; + struct { + WORD Dimension[4]; + } Array; + } FcnAry; + WORD TvIndex; + } Sym; + struct { + BYTE Name[IMAGE_SIZEOF_SYMBOL]; + } File; + struct { + DWORD Length; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD CheckSum; + SHORT Number; + BYTE Selection; + } Section; + } IMAGE_AUX_SYMBOL; + typedef IMAGE_AUX_SYMBOL UNALIGNED *PIMAGE_AUX_SYMBOL; + +#define IMAGE_SIZEOF_AUX_SYMBOL 18 + + typedef enum IMAGE_AUX_SYMBOL_TYPE { + IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF = 1 + } IMAGE_AUX_SYMBOL_TYPE; + +#include + + typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF { + BYTE bAuxType; + BYTE bReserved; + DWORD SymbolTableIndex; + BYTE rgbReserved[12]; + } IMAGE_AUX_SYMBOL_TOKEN_DEF; + + typedef IMAGE_AUX_SYMBOL_TOKEN_DEF UNALIGNED *PIMAGE_AUX_SYMBOL_TOKEN_DEF; + +#include + +#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define IMAGE_COMDAT_SELECT_ANY 2 +#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 +#define IMAGE_COMDAT_SELECT_LARGEST 6 +#define IMAGE_COMDAT_SELECT_NEWEST 7 + +#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + + typedef struct _IMAGE_RELOCATION { + union { + DWORD VirtualAddress; + DWORD RelocCount; + }; + DWORD SymbolTableIndex; + WORD Type; + } IMAGE_RELOCATION; + typedef IMAGE_RELOCATION UNALIGNED *PIMAGE_RELOCATION; + +#define IMAGE_SIZEOF_RELOCATION 10 + +#define IMAGE_REL_I386_ABSOLUTE 0x0000 +#define IMAGE_REL_I386_DIR16 0x0001 +#define IMAGE_REL_I386_REL16 0x0002 +#define IMAGE_REL_I386_DIR32 0x0006 +#define IMAGE_REL_I386_DIR32NB 0x0007 +#define IMAGE_REL_I386_SEG12 0x0009 +#define IMAGE_REL_I386_SECTION 0x000A +#define IMAGE_REL_I386_SECREL 0x000B +#define IMAGE_REL_I386_TOKEN 0x000C +#define IMAGE_REL_I386_SECREL7 0x000D +#define IMAGE_REL_I386_REL32 0x0014 + +#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 +#define IMAGE_REL_MIPS_REFHALF 0x0001 +#define IMAGE_REL_MIPS_REFWORD 0x0002 +#define IMAGE_REL_MIPS_JMPADDR 0x0003 +#define IMAGE_REL_MIPS_REFHI 0x0004 +#define IMAGE_REL_MIPS_REFLO 0x0005 +#define IMAGE_REL_MIPS_GPREL 0x0006 +#define IMAGE_REL_MIPS_LITERAL 0x0007 +#define IMAGE_REL_MIPS_SECTION 0x000A +#define IMAGE_REL_MIPS_SECREL 0x000B +#define IMAGE_REL_MIPS_SECRELLO 0x000C +#define IMAGE_REL_MIPS_SECRELHI 0x000D +#define IMAGE_REL_MIPS_TOKEN 0x000E +#define IMAGE_REL_MIPS_JMPADDR16 0x0010 +#define IMAGE_REL_MIPS_REFWORDNB 0x0022 +#define IMAGE_REL_MIPS_PAIR 0x0025 + +#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 +#define IMAGE_REL_ALPHA_REFLONG 0x0001 +#define IMAGE_REL_ALPHA_REFQUAD 0x0002 +#define IMAGE_REL_ALPHA_GPREL32 0x0003 +#define IMAGE_REL_ALPHA_LITERAL 0x0004 +#define IMAGE_REL_ALPHA_LITUSE 0x0005 +#define IMAGE_REL_ALPHA_GPDISP 0x0006 +#define IMAGE_REL_ALPHA_BRADDR 0x0007 +#define IMAGE_REL_ALPHA_HINT 0x0008 +#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 +#define IMAGE_REL_ALPHA_REFHI 0x000A +#define IMAGE_REL_ALPHA_REFLO 0x000B +#define IMAGE_REL_ALPHA_PAIR 0x000C +#define IMAGE_REL_ALPHA_MATCH 0x000D +#define IMAGE_REL_ALPHA_SECTION 0x000E +#define IMAGE_REL_ALPHA_SECREL 0x000F +#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 +#define IMAGE_REL_ALPHA_SECRELLO 0x0011 +#define IMAGE_REL_ALPHA_SECRELHI 0x0012 +#define IMAGE_REL_ALPHA_REFQ3 0x0013 +#define IMAGE_REL_ALPHA_REFQ2 0x0014 +#define IMAGE_REL_ALPHA_REFQ1 0x0015 +#define IMAGE_REL_ALPHA_GPRELLO 0x0016 +#define IMAGE_REL_ALPHA_GPRELHI 0x0017 + +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 +#define IMAGE_REL_PPC_ADDR64 0x0001 +#define IMAGE_REL_PPC_ADDR32 0x0002 +#define IMAGE_REL_PPC_ADDR24 0x0003 +#define IMAGE_REL_PPC_ADDR16 0x0004 +#define IMAGE_REL_PPC_ADDR14 0x0005 +#define IMAGE_REL_PPC_REL24 0x0006 +#define IMAGE_REL_PPC_REL14 0x0007 +#define IMAGE_REL_PPC_TOCREL16 0x0008 +#define IMAGE_REL_PPC_TOCREL14 0x0009 +#define IMAGE_REL_PPC_ADDR32NB 0x000A +#define IMAGE_REL_PPC_SECREL 0x000B +#define IMAGE_REL_PPC_SECTION 0x000C +#define IMAGE_REL_PPC_IFGLUE 0x000D +#define IMAGE_REL_PPC_IMGLUE 0x000E +#define IMAGE_REL_PPC_SECREL16 0x000F +#define IMAGE_REL_PPC_REFHI 0x0010 +#define IMAGE_REL_PPC_REFLO 0x0011 +#define IMAGE_REL_PPC_PAIR 0x0012 +#define IMAGE_REL_PPC_SECRELLO 0x0013 +#define IMAGE_REL_PPC_SECRELHI 0x0014 +#define IMAGE_REL_PPC_GPREL 0x0015 +#define IMAGE_REL_PPC_TOKEN 0x0016 +#define IMAGE_REL_PPC_TYPEMASK 0x00FF +#define IMAGE_REL_PPC_NEG 0x0100 +#define IMAGE_REL_PPC_BRTAKEN 0x0200 +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 +#define IMAGE_REL_PPC_TOCDEFN 0x0800 + +#define IMAGE_REL_SH3_ABSOLUTE 0x0000 +#define IMAGE_REL_SH3_DIRECT16 0x0001 +#define IMAGE_REL_SH3_DIRECT32 0x0002 +#define IMAGE_REL_SH3_DIRECT8 0x0003 +#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 +#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 +#define IMAGE_REL_SH3_DIRECT4 0x0006 +#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 +#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 +#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 +#define IMAGE_REL_SH3_PCREL8_LONG 0x000A +#define IMAGE_REL_SH3_PCREL12_WORD 0x000B +#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C +#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D +#define IMAGE_REL_SH3_SECTION 0x000E +#define IMAGE_REL_SH3_SECREL 0x000F +#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 +#define IMAGE_REL_SH3_GPREL4_LONG 0x0011 +#define IMAGE_REL_SH3_TOKEN 0x0012 + +#define IMAGE_REL_SHM_PCRELPT 0x0013 +#define IMAGE_REL_SHM_REFLO 0x0014 +#define IMAGE_REL_SHM_REFHALF 0x0015 +#define IMAGE_REL_SHM_RELLO 0x0016 +#define IMAGE_REL_SHM_RELHALF 0x0017 +#define IMAGE_REL_SHM_PAIR 0x0018 + +#define IMAGE_REL_SH_NOMODE 0x8000 + +#define IMAGE_REL_ARM_ABSOLUTE 0x0000 +#define IMAGE_REL_ARM_ADDR32 0x0001 +#define IMAGE_REL_ARM_ADDR32NB 0x0002 +#define IMAGE_REL_ARM_BRANCH24 0x0003 +#define IMAGE_REL_ARM_BRANCH11 0x0004 +#define IMAGE_REL_ARM_TOKEN 0x0005 +#define IMAGE_REL_ARM_GPREL12 0x0006 +#define IMAGE_REL_ARM_GPREL7 0x0007 +#define IMAGE_REL_ARM_BLX24 0x0008 +#define IMAGE_REL_ARM_BLX11 0x0009 +#define IMAGE_REL_ARM_SECTION 0x000E +#define IMAGE_REL_ARM_SECREL 0x000F + +#define IMAGE_REL_AM_ABSOLUTE 0x0000 +#define IMAGE_REL_AM_ADDR32 0x0001 +#define IMAGE_REL_AM_ADDR32NB 0x0002 +#define IMAGE_REL_AM_CALL32 0x0003 +#define IMAGE_REL_AM_FUNCINFO 0x0004 +#define IMAGE_REL_AM_REL32_1 0x0005 +#define IMAGE_REL_AM_REL32_2 0x0006 +#define IMAGE_REL_AM_SECREL 0x0007 +#define IMAGE_REL_AM_SECTION 0x0008 +#define IMAGE_REL_AM_TOKEN 0x0009 + +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 +#define IMAGE_REL_AMD64_ADDR32 0x0002 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 +#define IMAGE_REL_AMD64_REL32_1 0x0005 +#define IMAGE_REL_AMD64_REL32_2 0x0006 +#define IMAGE_REL_AMD64_REL32_3 0x0007 +#define IMAGE_REL_AMD64_REL32_4 0x0008 +#define IMAGE_REL_AMD64_REL32_5 0x0009 +#define IMAGE_REL_AMD64_SECTION 0x000A +#define IMAGE_REL_AMD64_SECREL 0x000B +#define IMAGE_REL_AMD64_SECREL7 0x000C +#define IMAGE_REL_AMD64_TOKEN 0x000D +#define IMAGE_REL_AMD64_SREL32 0x000E +#define IMAGE_REL_AMD64_PAIR 0x000F +#define IMAGE_REL_AMD64_SSPAN32 0x0010 + +#define IMAGE_REL_IA64_ABSOLUTE 0x0000 +#define IMAGE_REL_IA64_IMM14 0x0001 +#define IMAGE_REL_IA64_IMM22 0x0002 +#define IMAGE_REL_IA64_IMM64 0x0003 +#define IMAGE_REL_IA64_DIR32 0x0004 +#define IMAGE_REL_IA64_DIR64 0x0005 +#define IMAGE_REL_IA64_PCREL21B 0x0006 +#define IMAGE_REL_IA64_PCREL21M 0x0007 +#define IMAGE_REL_IA64_PCREL21F 0x0008 +#define IMAGE_REL_IA64_GPREL22 0x0009 +#define IMAGE_REL_IA64_LTOFF22 0x000A +#define IMAGE_REL_IA64_SECTION 0x000B +#define IMAGE_REL_IA64_SECREL22 0x000C +#define IMAGE_REL_IA64_SECREL64I 0x000D +#define IMAGE_REL_IA64_SECREL32 0x000E + +#define IMAGE_REL_IA64_DIR32NB 0x0010 +#define IMAGE_REL_IA64_SREL14 0x0011 +#define IMAGE_REL_IA64_SREL22 0x0012 +#define IMAGE_REL_IA64_SREL32 0x0013 +#define IMAGE_REL_IA64_UREL32 0x0014 +#define IMAGE_REL_IA64_PCREL60X 0x0015 +#define IMAGE_REL_IA64_PCREL60B 0x0016 +#define IMAGE_REL_IA64_PCREL60F 0x0017 +#define IMAGE_REL_IA64_PCREL60I 0x0018 +#define IMAGE_REL_IA64_PCREL60M 0x0019 +#define IMAGE_REL_IA64_IMMGPREL64 0x001A +#define IMAGE_REL_IA64_TOKEN 0x001B +#define IMAGE_REL_IA64_GPREL32 0x001C +#define IMAGE_REL_IA64_ADDEND 0x001F + +#define IMAGE_REL_CEF_ABSOLUTE 0x0000 +#define IMAGE_REL_CEF_ADDR32 0x0001 +#define IMAGE_REL_CEF_ADDR64 0x0002 +#define IMAGE_REL_CEF_ADDR32NB 0x0003 +#define IMAGE_REL_CEF_SECTION 0x0004 +#define IMAGE_REL_CEF_SECREL 0x0005 +#define IMAGE_REL_CEF_TOKEN 0x0006 + +#define IMAGE_REL_CEE_ABSOLUTE 0x0000 +#define IMAGE_REL_CEE_ADDR32 0x0001 +#define IMAGE_REL_CEE_ADDR64 0x0002 +#define IMAGE_REL_CEE_ADDR32NB 0x0003 +#define IMAGE_REL_CEE_SECTION 0x0004 +#define IMAGE_REL_CEE_SECREL 0x0005 +#define IMAGE_REL_CEE_TOKEN 0x0006 + +#define IMAGE_REL_M32R_ABSOLUTE 0x0000 +#define IMAGE_REL_M32R_ADDR32 0x0001 +#define IMAGE_REL_M32R_ADDR32NB 0x0002 +#define IMAGE_REL_M32R_ADDR24 0x0003 +#define IMAGE_REL_M32R_GPREL16 0x0004 +#define IMAGE_REL_M32R_PCREL24 0x0005 +#define IMAGE_REL_M32R_PCREL16 0x0006 +#define IMAGE_REL_M32R_PCREL8 0x0007 +#define IMAGE_REL_M32R_REFHALF 0x0008 +#define IMAGE_REL_M32R_REFHI 0x0009 +#define IMAGE_REL_M32R_REFLO 0x000A +#define IMAGE_REL_M32R_PAIR 0x000B +#define IMAGE_REL_M32R_SECTION 0x000C +#define IMAGE_REL_M32R_SECREL32 0x000D +#define IMAGE_REL_M32R_TOKEN 0x000E + +#define EXT_IMM64(Value,Address,Size,InstPos,ValPos) Value |= (((ULONGLONG)((*(Address) >> InstPos) & (((ULONGLONG)1 << Size) - 1))) << ValPos) +#define INS_IMM64(Value,Address,Size,InstPos,ValPos) *(PDWORD)Address = (*(PDWORD)Address & ~(((1 << Size) - 1) << InstPos)) | ((DWORD)((((ULONGLONG)Value >> ValPos) & (((ULONGLONG)1 << Size) - 1))) << InstPos) + +#define EMARCH_ENC_I17_IMM7B_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM7B_SIZE_X 7 +#define EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X 4 +#define EMARCH_ENC_I17_IMM7B_VAL_POS_X 0 + +#define EMARCH_ENC_I17_IMM9D_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM9D_SIZE_X 9 +#define EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X 18 +#define EMARCH_ENC_I17_IMM9D_VAL_POS_X 7 + +#define EMARCH_ENC_I17_IMM5C_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM5C_SIZE_X 5 +#define EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X 13 +#define EMARCH_ENC_I17_IMM5C_VAL_POS_X 16 + +#define EMARCH_ENC_I17_IC_INST_WORD_X 3 +#define EMARCH_ENC_I17_IC_SIZE_X 1 +#define EMARCH_ENC_I17_IC_INST_WORD_POS_X 12 +#define EMARCH_ENC_I17_IC_VAL_POS_X 21 + +#define EMARCH_ENC_I17_IMM41a_INST_WORD_X 1 +#define EMARCH_ENC_I17_IMM41a_SIZE_X 10 +#define EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X 14 +#define EMARCH_ENC_I17_IMM41a_VAL_POS_X 22 + +#define EMARCH_ENC_I17_IMM41b_INST_WORD_X 1 +#define EMARCH_ENC_I17_IMM41b_SIZE_X 8 +#define EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X 24 +#define EMARCH_ENC_I17_IMM41b_VAL_POS_X 32 + +#define EMARCH_ENC_I17_IMM41c_INST_WORD_X 2 +#define EMARCH_ENC_I17_IMM41c_SIZE_X 23 +#define EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X 0 +#define EMARCH_ENC_I17_IMM41c_VAL_POS_X 40 + +#define EMARCH_ENC_I17_SIGN_INST_WORD_X 3 +#define EMARCH_ENC_I17_SIGN_SIZE_X 1 +#define EMARCH_ENC_I17_SIGN_INST_WORD_POS_X 27 +#define EMARCH_ENC_I17_SIGN_VAL_POS_X 63 + +#define X3_OPCODE_INST_WORD_X 3 +#define X3_OPCODE_SIZE_X 4 +#define X3_OPCODE_INST_WORD_POS_X 28 +#define X3_OPCODE_SIGN_VAL_POS_X 0 + +#define X3_I_INST_WORD_X 3 +#define X3_I_SIZE_X 1 +#define X3_I_INST_WORD_POS_X 27 +#define X3_I_SIGN_VAL_POS_X 59 + +#define X3_D_WH_INST_WORD_X 3 +#define X3_D_WH_SIZE_X 3 +#define X3_D_WH_INST_WORD_POS_X 24 +#define X3_D_WH_SIGN_VAL_POS_X 0 + +#define X3_IMM20_INST_WORD_X 3 +#define X3_IMM20_SIZE_X 20 +#define X3_IMM20_INST_WORD_POS_X 4 +#define X3_IMM20_SIGN_VAL_POS_X 0 + +#define X3_IMM39_1_INST_WORD_X 2 +#define X3_IMM39_1_SIZE_X 23 +#define X3_IMM39_1_INST_WORD_POS_X 0 +#define X3_IMM39_1_SIGN_VAL_POS_X 36 + +#define X3_IMM39_2_INST_WORD_X 1 +#define X3_IMM39_2_SIZE_X 16 +#define X3_IMM39_2_INST_WORD_POS_X 16 +#define X3_IMM39_2_SIGN_VAL_POS_X 20 + +#define X3_P_INST_WORD_X 3 +#define X3_P_SIZE_X 4 +#define X3_P_INST_WORD_POS_X 0 +#define X3_P_SIGN_VAL_POS_X 0 + +#define X3_TMPLT_INST_WORD_X 0 +#define X3_TMPLT_SIZE_X 4 +#define X3_TMPLT_INST_WORD_POS_X 0 +#define X3_TMPLT_SIGN_VAL_POS_X 0 + +#define X3_BTYPE_QP_INST_WORD_X 2 +#define X3_BTYPE_QP_SIZE_X 9 +#define X3_BTYPE_QP_INST_WORD_POS_X 23 +#define X3_BTYPE_QP_INST_VAL_POS_X 0 + +#define X3_EMPTY_INST_WORD_X 1 +#define X3_EMPTY_SIZE_X 2 +#define X3_EMPTY_INST_WORD_POS_X 14 +#define X3_EMPTY_INST_VAL_POS_X 0 + + typedef struct _IMAGE_LINENUMBER { + union { + DWORD SymbolTableIndex; + DWORD VirtualAddress; + } Type; + WORD Linenumber; + } IMAGE_LINENUMBER; + typedef IMAGE_LINENUMBER UNALIGNED *PIMAGE_LINENUMBER; + +#define IMAGE_SIZEOF_LINENUMBER 6 + +#include "poppack.h" + + typedef struct _IMAGE_BASE_RELOCATION { + DWORD VirtualAddress; + DWORD SizeOfBlock; + + } IMAGE_BASE_RELOCATION; + typedef IMAGE_BASE_RELOCATION UNALIGNED *PIMAGE_BASE_RELOCATION; + +#define IMAGE_SIZEOF_BASE_RELOCATION 8 + +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define IMAGE_REL_BASED_IA64_IMM64 9 +#define IMAGE_REL_BASED_DIR64 10 + +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + + typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { + BYTE Name[16]; + BYTE Date[12]; + BYTE UserID[6]; + BYTE GroupID[6]; + BYTE Mode[8]; + BYTE Size[10]; + BYTE EndHeader[2]; + } IMAGE_ARCHIVE_MEMBER_HEADER,*PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + + typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; + } IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; + + typedef struct _IMAGE_IMPORT_BY_NAME { + WORD Hint; + BYTE Name[1]; + } IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; + +#include "pshpack8.h" + + typedef struct _IMAGE_THUNK_DATA64 { + union { + ULONGLONG ForwarderString; + ULONGLONG Function; + ULONGLONG Ordinal; + ULONGLONG AddressOfData; + } u1; + } IMAGE_THUNK_DATA64; + typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; + +#include "poppack.h" + + typedef struct _IMAGE_THUNK_DATA32 { + union { + DWORD ForwarderString; + DWORD Function; + DWORD Ordinal; + DWORD AddressOfData; + } u1; + } IMAGE_THUNK_DATA32; + typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; + +#define IMAGE_ORDINAL_FLAG64 0x8000000000000000ull +#define IMAGE_ORDINAL_FLAG32 0x80000000 +#define IMAGE_ORDINAL64(Ordinal) (Ordinal & 0xffffull) +#define IMAGE_ORDINAL32(Ordinal) (Ordinal & 0xffff) +#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64)!=0) +#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32)!=0) + + typedef VOID + (NTAPI *PIMAGE_TLS_CALLBACK)(PVOID DllHandle,DWORD Reason,PVOID Reserved); + + typedef struct _IMAGE_TLS_DIRECTORY64 { + ULONGLONG StartAddressOfRawData; + ULONGLONG EndAddressOfRawData; + ULONGLONG AddressOfIndex; + ULONGLONG AddressOfCallBacks; + DWORD SizeOfZeroFill; + DWORD Characteristics; + } IMAGE_TLS_DIRECTORY64; + typedef IMAGE_TLS_DIRECTORY64 *PIMAGE_TLS_DIRECTORY64; + + typedef struct _IMAGE_TLS_DIRECTORY32 { + DWORD StartAddressOfRawData; + DWORD EndAddressOfRawData; + DWORD AddressOfIndex; + DWORD AddressOfCallBacks; + DWORD SizeOfZeroFill; + DWORD Characteristics; + } IMAGE_TLS_DIRECTORY32; + typedef IMAGE_TLS_DIRECTORY32 *PIMAGE_TLS_DIRECTORY32; + +#ifdef _WIN64 +#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64 +#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL64(Ordinal) + typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; + typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL64(Ordinal) + typedef IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY; + typedef PIMAGE_TLS_DIRECTORY64 PIMAGE_TLS_DIRECTORY; +#else +#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32 +#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL32(Ordinal) + typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; + typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL32(Ordinal) + typedef IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY; + typedef PIMAGE_TLS_DIRECTORY32 PIMAGE_TLS_DIRECTORY; +#endif + + typedef struct _IMAGE_IMPORT_DESCRIPTOR { + union { + DWORD Characteristics; + DWORD OriginalFirstThunk; + }; + DWORD TimeDateStamp; + + DWORD ForwarderChain; + DWORD Name; + DWORD FirstThunk; + } IMAGE_IMPORT_DESCRIPTOR; + typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR; + + typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR { + DWORD TimeDateStamp; + WORD OffsetModuleName; + WORD NumberOfModuleForwarderRefs; + } IMAGE_BOUND_IMPORT_DESCRIPTOR,*PIMAGE_BOUND_IMPORT_DESCRIPTOR; + + typedef struct _IMAGE_BOUND_FORWARDER_REF { + DWORD TimeDateStamp; + WORD OffsetModuleName; + WORD Reserved; + } IMAGE_BOUND_FORWARDER_REF,*PIMAGE_BOUND_FORWARDER_REF; + + typedef struct _IMAGE_RESOURCE_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + WORD NumberOfNamedEntries; + WORD NumberOfIdEntries; + } IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; + +#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 +#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 + + typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { + union { + struct { + DWORD NameOffset:31; + DWORD NameIsString:1; + }; + DWORD Name; + WORD Id; + }; + union { + DWORD OffsetToData; + struct { + DWORD OffsetToDirectory:31; + DWORD DataIsDirectory:1; + }; + }; + } IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; + + typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { + WORD Length; + CHAR NameString[1]; + } IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; + + typedef struct _IMAGE_RESOURCE_DIR_STRING_U { + WORD Length; + WCHAR NameString[1]; + } IMAGE_RESOURCE_DIR_STRING_U,*PIMAGE_RESOURCE_DIR_STRING_U; + + typedef struct _IMAGE_RESOURCE_DATA_ENTRY { + DWORD OffsetToData; + DWORD Size; + DWORD CodePage; + DWORD Reserved; + } IMAGE_RESOURCE_DATA_ENTRY,*PIMAGE_RESOURCE_DATA_ENTRY; + + typedef struct { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + DWORD DeCommitFreeBlockThreshold; + DWORD DeCommitTotalFreeThreshold; + DWORD LockPrefixTable; + DWORD MaximumAllocationSize; + DWORD VirtualMemoryThreshold; + DWORD ProcessHeapFlags; + DWORD ProcessAffinityMask; + WORD CSDVersion; + WORD Reserved1; + DWORD EditList; + DWORD SecurityCookie; + DWORD SEHandlerTable; + DWORD SEHandlerCount; + } IMAGE_LOAD_CONFIG_DIRECTORY32,*PIMAGE_LOAD_CONFIG_DIRECTORY32; + + typedef struct { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + ULONGLONG DeCommitFreeBlockThreshold; + ULONGLONG DeCommitTotalFreeThreshold; + ULONGLONG LockPrefixTable; + ULONGLONG MaximumAllocationSize; + ULONGLONG VirtualMemoryThreshold; + ULONGLONG ProcessAffinityMask; + DWORD ProcessHeapFlags; + WORD CSDVersion; + WORD Reserved1; + ULONGLONG EditList; + ULONGLONG SecurityCookie; + ULONGLONG SEHandlerTable; + ULONGLONG SEHandlerCount; + } IMAGE_LOAD_CONFIG_DIRECTORY64,*PIMAGE_LOAD_CONFIG_DIRECTORY64; + +#ifdef _WIN64 + typedef IMAGE_LOAD_CONFIG_DIRECTORY64 IMAGE_LOAD_CONFIG_DIRECTORY; + typedef PIMAGE_LOAD_CONFIG_DIRECTORY64 PIMAGE_LOAD_CONFIG_DIRECTORY; +#else + typedef IMAGE_LOAD_CONFIG_DIRECTORY32 IMAGE_LOAD_CONFIG_DIRECTORY; + typedef PIMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY; +#endif + + typedef struct _IMAGE_CE_RUNTIME_FUNCTION_ENTRY { + DWORD FuncStart; + DWORD PrologLen : 8; + DWORD FuncLen : 22; + DWORD ThirtyTwoBit : 1; + DWORD ExceptionFlag : 1; + } IMAGE_CE_RUNTIME_FUNCTION_ENTRY,*PIMAGE_CE_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY { + ULONGLONG BeginAddress; + ULONGLONG EndAddress; + ULONGLONG ExceptionHandler; + ULONGLONG HandlerData; + ULONGLONG PrologEndAddress; + } IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY { + DWORD BeginAddress; + DWORD EndAddress; + DWORD ExceptionHandler; + DWORD HandlerData; + DWORD PrologEndAddress; + } IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { + DWORD BeginAddress; + DWORD EndAddress; + DWORD UnwindInfoAddress; + } _IMAGE_RUNTIME_FUNCTION_ENTRY,*_PIMAGE_RUNTIME_FUNCTION_ENTRY; + + typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_IA64_RUNTIME_FUNCTION_ENTRY; + typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY; + + typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_RUNTIME_FUNCTION_ENTRY; + typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_DEBUG_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Type; + DWORD SizeOfData; + DWORD AddressOfRawData; + DWORD PointerToRawData; + } IMAGE_DEBUG_DIRECTORY,*PIMAGE_DEBUG_DIRECTORY; + +#define IMAGE_DEBUG_TYPE_UNKNOWN 0 +#define IMAGE_DEBUG_TYPE_COFF 1 +#define IMAGE_DEBUG_TYPE_CODEVIEW 2 +#define IMAGE_DEBUG_TYPE_FPO 3 +#define IMAGE_DEBUG_TYPE_MISC 4 +#define IMAGE_DEBUG_TYPE_EXCEPTION 5 +#define IMAGE_DEBUG_TYPE_FIXUP 6 +#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 +#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 +#define IMAGE_DEBUG_TYPE_BORLAND 9 +#define IMAGE_DEBUG_TYPE_RESERVED10 10 +#define IMAGE_DEBUG_TYPE_CLSID 11 + + typedef struct _IMAGE_COFF_SYMBOLS_HEADER { + DWORD NumberOfSymbols; + DWORD LvaToFirstSymbol; + DWORD NumberOfLinenumbers; + DWORD LvaToFirstLinenumber; + DWORD RvaToFirstByteOfCode; + DWORD RvaToLastByteOfCode; + DWORD RvaToFirstByteOfData; + DWORD RvaToLastByteOfData; + } IMAGE_COFF_SYMBOLS_HEADER,*PIMAGE_COFF_SYMBOLS_HEADER; + +#define FRAME_FPO 0 +#define FRAME_TRAP 1 +#define FRAME_TSS 2 +#define FRAME_NONFPO 3 + + typedef struct _FPO_DATA { + DWORD ulOffStart; + DWORD cbProcSize; + DWORD cdwLocals; + WORD cdwParams; + WORD cbProlog : 8; + WORD cbRegs : 3; + WORD fHasSEH : 1; + WORD fUseBP : 1; + WORD reserved : 1; + WORD cbFrame : 2; + } FPO_DATA,*PFPO_DATA; +#define SIZEOF_RFPO_DATA 16 + +#define IMAGE_DEBUG_MISC_EXENAME 1 + + typedef struct _IMAGE_DEBUG_MISC { + DWORD DataType; + DWORD Length; + BOOLEAN Unicode; + BYTE Reserved[3]; + BYTE Data[1]; + } IMAGE_DEBUG_MISC,*PIMAGE_DEBUG_MISC; + + typedef struct _IMAGE_FUNCTION_ENTRY { + DWORD StartingAddress; + DWORD EndingAddress; + DWORD EndOfPrologue; + } IMAGE_FUNCTION_ENTRY,*PIMAGE_FUNCTION_ENTRY; + + typedef struct _IMAGE_FUNCTION_ENTRY64 { + ULONGLONG StartingAddress; + ULONGLONG EndingAddress; + union { + ULONGLONG EndOfPrologue; + ULONGLONG UnwindInfoAddress; + }; + } IMAGE_FUNCTION_ENTRY64,*PIMAGE_FUNCTION_ENTRY64; + + typedef struct _IMAGE_SEPARATE_DEBUG_HEADER { + WORD Signature; + WORD Flags; + WORD Machine; + WORD Characteristics; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD ImageBase; + DWORD SizeOfImage; + DWORD NumberOfSections; + DWORD ExportedNamesSize; + DWORD DebugDirectorySize; + DWORD SectionAlignment; + DWORD Reserved[2]; + } IMAGE_SEPARATE_DEBUG_HEADER,*PIMAGE_SEPARATE_DEBUG_HEADER; + + typedef struct _NON_PAGED_DEBUG_INFO { + WORD Signature; + WORD Flags; + DWORD Size; + WORD Machine; + WORD Characteristics; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD SizeOfImage; + ULONGLONG ImageBase; + + } NON_PAGED_DEBUG_INFO,*PNON_PAGED_DEBUG_INFO; + +#define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944 +#define NON_PAGED_DEBUG_SIGNATURE 0x494E + +#define IMAGE_SEPARATE_DEBUG_FLAGS_MASK 0x8000 +#define IMAGE_SEPARATE_DEBUG_MISMATCH 0x8000 + + typedef struct _ImageArchitectureHeader { + unsigned int AmaskValue: 1; + int Adummy1 :7; + unsigned int AmaskShift: 8; + int Adummy2 :16; + DWORD FirstEntryRVA; + } IMAGE_ARCHITECTURE_HEADER,*PIMAGE_ARCHITECTURE_HEADER; + + typedef struct _ImageArchitectureEntry { + DWORD FixupInstRVA; + DWORD NewInst; + } IMAGE_ARCHITECTURE_ENTRY,*PIMAGE_ARCHITECTURE_ENTRY; + +#include "poppack.h" + +#define IMPORT_OBJECT_HDR_SIG2 0xffff + + typedef struct IMPORT_OBJECT_HEADER { + WORD Sig1; + WORD Sig2; + WORD Version; + WORD Machine; + DWORD TimeDateStamp; + DWORD SizeOfData; + union { + WORD Ordinal; + WORD Hint; + }; + WORD Type : 2; + WORD NameType : 3; + WORD Reserved : 11; + } IMPORT_OBJECT_HEADER; + + typedef enum IMPORT_OBJECT_TYPE { + IMPORT_OBJECT_CODE = 0,IMPORT_OBJECT_DATA = 1,IMPORT_OBJECT_CONST = 2 + } IMPORT_OBJECT_TYPE; + + typedef enum IMPORT_OBJECT_NAME_TYPE { + IMPORT_OBJECT_ORDINAL = 0,IMPORT_OBJECT_NAME = 1,IMPORT_OBJECT_NAME_NO_PREFIX = 2,IMPORT_OBJECT_NAME_UNDECORATE = 3 + } IMPORT_OBJECT_NAME_TYPE; + +#ifndef __IMAGE_COR20_HEADER_DEFINED__ +#define __IMAGE_COR20_HEADER_DEFINED__ + typedef enum ReplacesCorHdrNumericDefines { + COMIMAGE_FLAGS_ILONLY =0x00000001,COMIMAGE_FLAGS_32BITREQUIRED =0x00000002,COMIMAGE_FLAGS_IL_LIBRARY =0x00000004, + COMIMAGE_FLAGS_STRONGNAMESIGNED =0x00000008,COMIMAGE_FLAGS_TRACKDEBUGDATA =0x00010000,COR_VERSION_MAJOR_V2 =2, + COR_VERSION_MAJOR =COR_VERSION_MAJOR_V2,COR_VERSION_MINOR =0,COR_DELETED_NAME_LENGTH =8,COR_VTABLEGAP_NAME_LENGTH =8, + NATIVE_TYPE_MAX_CB =1,COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE=0xFF,IMAGE_COR_MIH_METHODRVA =0x01,IMAGE_COR_MIH_EHRVA =0x02, + IMAGE_COR_MIH_BASICBLOCK =0x08,COR_VTABLE_32BIT =0x01,COR_VTABLE_64BIT =0x02,COR_VTABLE_FROM_UNMANAGED =0x04, + COR_VTABLE_CALL_MOST_DERIVED =0x10,IMAGE_COR_EATJ_THUNK_SIZE =32,MAX_CLASS_NAME =1024,MAX_PACKAGE_NAME =1024 + } ReplacesCorHdrNumericDefines; + + typedef struct IMAGE_COR20_HEADER { + DWORD cb; + WORD MajorRuntimeVersion; + WORD MinorRuntimeVersion; + IMAGE_DATA_DIRECTORY MetaData; + DWORD Flags; + DWORD EntryPointToken; + IMAGE_DATA_DIRECTORY Resources; + IMAGE_DATA_DIRECTORY StrongNameSignature; + IMAGE_DATA_DIRECTORY CodeManagerTable; + IMAGE_DATA_DIRECTORY VTableFixups; + IMAGE_DATA_DIRECTORY ExportAddressTableJumps; + IMAGE_DATA_DIRECTORY ManagedNativeHeader; + } IMAGE_COR20_HEADER,*PIMAGE_COR20_HEADER; +#endif + +#if defined (__x86_64) + NTSYSAPI PRUNTIME_FUNCTION NTAPI RtlLookupFunctionEntry (DWORD64 ControlPc, PDWORD64 ImageBase, PUNWIND_HISTORY_TABLE HistoryTable); + NTSYSAPI VOID NTAPI RtlUnwindEx (PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable); +#endif + +#include + +#ifndef _SLIST_HEADER_ +#define _SLIST_HEADER_ + +#ifdef _WIN64 + typedef struct _SLIST_ENTRY *PSLIST_ENTRY; + typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY { + PSLIST_ENTRY Next; + } SLIST_ENTRY; +#else + +#define SLIST_ENTRY SINGLE_LIST_ENTRY +#define _SLIST_ENTRY _SINGLE_LIST_ENTRY +#define PSLIST_ENTRY PSINGLE_LIST_ENTRY +#endif + +#if defined(_WIN64) + + typedef struct DECLSPEC_ALIGN(16) _SLIST_HEADER { + ULONGLONG Alignment; + ULONGLONG Region; + } SLIST_HEADER; + + typedef struct _SLIST_HEADER *PSLIST_HEADER; +#else + + typedef union _SLIST_HEADER { + ULONGLONG Alignment; + struct { + SLIST_ENTRY Next; + WORD Depth; + WORD Sequence; + }; + } SLIST_HEADER,*PSLIST_HEADER; +#endif +#endif + + NTSYSAPI VOID NTAPI RtlInitializeSListHead(PSLIST_HEADER ListHead); + NTSYSAPI PSLIST_ENTRY NTAPI RtlFirstEntrySList(const SLIST_HEADER *ListHead); + NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPopEntrySList(PSLIST_HEADER ListHead); + NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); + NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedFlushSList(PSLIST_HEADER ListHead); + NTSYSAPI WORD NTAPI RtlQueryDepthSList(PSLIST_HEADER ListHead); + +#define HEAP_NO_SERIALIZE 0x00000001 +#define HEAP_GROWABLE 0x00000002 +#define HEAP_GENERATE_EXCEPTIONS 0x00000004 +#define HEAP_ZERO_MEMORY 0x00000008 +#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 +#define HEAP_TAIL_CHECKING_ENABLED 0x00000020 +#define HEAP_FREE_CHECKING_ENABLED 0x00000040 +#define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 +#define HEAP_CREATE_ALIGN_16 0x00010000 +#define HEAP_CREATE_ENABLE_TRACING 0x00020000 +#define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 +#define HEAP_MAXIMUM_TAG 0x0FFF +#define HEAP_PSEUDO_TAG_FLAG 0x8000 +#define HEAP_TAG_SHIFT 18 +#define HEAP_MAKE_TAG_FLAGS(b,o) ((DWORD)((b) + ((o) << 18))) + + NTSYSAPI VOID NTAPI RtlCaptureContext(PCONTEXT ContextRecord); + +#define IS_TEXT_UNICODE_ASCII16 0x0001 +#define IS_TEXT_UNICODE_REVERSE_ASCII16 0x0010 + +#define IS_TEXT_UNICODE_STATISTICS 0x0002 +#define IS_TEXT_UNICODE_REVERSE_STATISTICS 0x0020 + +#define IS_TEXT_UNICODE_CONTROLS 0x0004 +#define IS_TEXT_UNICODE_REVERSE_CONTROLS 0x0040 + +#define IS_TEXT_UNICODE_SIGNATURE 0x0008 +#define IS_TEXT_UNICODE_REVERSE_SIGNATURE 0x0080 + +#define IS_TEXT_UNICODE_ILLEGAL_CHARS 0x0100 +#define IS_TEXT_UNICODE_ODD_LENGTH 0x0200 +#define IS_TEXT_UNICODE_DBCS_LEADBYTE 0x0400 +#define IS_TEXT_UNICODE_NULL_BYTES 0x1000 + +#define IS_TEXT_UNICODE_UNICODE_MASK 0x000F +#define IS_TEXT_UNICODE_REVERSE_MASK 0x00F0 +#define IS_TEXT_UNICODE_NOT_UNICODE_MASK 0x0F00 +#define IS_TEXT_UNICODE_NOT_ASCII_MASK 0xF000 + +#define COMPRESSION_FORMAT_NONE (0x0000) +#define COMPRESSION_FORMAT_DEFAULT (0x0001) +#define COMPRESSION_FORMAT_LZNT1 (0x0002) +#define COMPRESSION_ENGINE_STANDARD (0x0000) +#define COMPRESSION_ENGINE_MAXIMUM (0x0100) +#define COMPRESSION_ENGINE_HIBER (0x0200) + +#if _DBG_MEMCPY_INLINE_ && !defined(_MEMCPY_INLINE_) && !defined(_CRTBLD) +#define _MEMCPY_INLINE_ + __CRT_INLINE PVOID __cdecl memcpy_inline(void *dst,const void *src,size_t size) { + if(((char *)dst > (char *)src) && ((char *)dst < ((char *)src + size))) { + __debugbreak(); + } + return memcpy(dst,src,size); + } +#define memcpy memcpy_inline +#endif + + NTSYSAPI SIZE_T NTAPI RtlCompareMemory(const VOID *Source1,const VOID *Source2,SIZE_T Length); + +#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length))) +#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length)) +#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length)) +#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length)) +#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) + + __CRT_INLINE PVOID RtlSecureZeroMemory(PVOID ptr,SIZE_T cnt) { + volatile char *vptr =(volatile char *)ptr; +#ifdef __x86_64 + __stosb((PBYTE)((DWORD64)vptr),0,cnt); +#else + while(cnt) { + *vptr = 0; + vptr++; + cnt--; + } +#endif + return ptr; + } + + typedef struct _MESSAGE_RESOURCE_ENTRY { + WORD Length; + WORD Flags; + BYTE Text[1]; + } MESSAGE_RESOURCE_ENTRY,*PMESSAGE_RESOURCE_ENTRY; + +#define MESSAGE_RESOURCE_UNICODE 0x0001 + + typedef struct _MESSAGE_RESOURCE_BLOCK { + DWORD LowId; + DWORD HighId; + DWORD OffsetToEntries; + } MESSAGE_RESOURCE_BLOCK,*PMESSAGE_RESOURCE_BLOCK; + + typedef struct _MESSAGE_RESOURCE_DATA { + DWORD NumberOfBlocks; + MESSAGE_RESOURCE_BLOCK Blocks[1]; + } MESSAGE_RESOURCE_DATA,*PMESSAGE_RESOURCE_DATA; + + typedef struct _OSVERSIONINFOA { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + CHAR szCSDVersion[128]; + } OSVERSIONINFOA,*POSVERSIONINFOA,*LPOSVERSIONINFOA; + + typedef struct _OSVERSIONINFOW { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + WCHAR szCSDVersion[128]; + } OSVERSIONINFOW,*POSVERSIONINFOW,*LPOSVERSIONINFOW,RTL_OSVERSIONINFOW,*PRTL_OSVERSIONINFOW; + +#ifdef UNICODE + typedef OSVERSIONINFOW OSVERSIONINFO; + typedef POSVERSIONINFOW POSVERSIONINFO; + typedef LPOSVERSIONINFOW LPOSVERSIONINFO; +#else + typedef OSVERSIONINFOA OSVERSIONINFO; + typedef POSVERSIONINFOA POSVERSIONINFO; + typedef LPOSVERSIONINFOA LPOSVERSIONINFO; +#endif + + typedef struct _OSVERSIONINFOEXA { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + CHAR szCSDVersion[128]; + WORD wServicePackMajor; + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; + BYTE wReserved; + } OSVERSIONINFOEXA,*POSVERSIONINFOEXA,*LPOSVERSIONINFOEXA; + + typedef struct _OSVERSIONINFOEXW { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + WCHAR szCSDVersion[128]; + WORD wServicePackMajor; + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; + BYTE wReserved; + } OSVERSIONINFOEXW,*POSVERSIONINFOEXW,*LPOSVERSIONINFOEXW,RTL_OSVERSIONINFOEXW,*PRTL_OSVERSIONINFOEXW; +#ifdef UNICODE + typedef OSVERSIONINFOEXW OSVERSIONINFOEX; + typedef POSVERSIONINFOEXW POSVERSIONINFOEX; + typedef LPOSVERSIONINFOEXW LPOSVERSIONINFOEX; +#else + typedef OSVERSIONINFOEXA OSVERSIONINFOEX; + typedef POSVERSIONINFOEXA POSVERSIONINFOEX; + typedef LPOSVERSIONINFOEXA LPOSVERSIONINFOEX; +#endif + +#define VER_EQUAL 1 +#define VER_GREATER 2 +#define VER_GREATER_EQUAL 3 +#define VER_LESS 4 +#define VER_LESS_EQUAL 5 +#define VER_AND 6 +#define VER_OR 7 + +#define VER_CONDITION_MASK 7 +#define VER_NUM_BITS_PER_CONDITION_MASK 3 + +#define VER_MINORVERSION 0x0000001 +#define VER_MAJORVERSION 0x0000002 +#define VER_BUILDNUMBER 0x0000004 +#define VER_PLATFORMID 0x0000008 +#define VER_SERVICEPACKMINOR 0x0000010 +#define VER_SERVICEPACKMAJOR 0x0000020 +#define VER_SUITENAME 0x0000040 +#define VER_PRODUCT_TYPE 0x0000080 + +#define VER_NT_WORKSTATION 0x0000001 +#define VER_NT_DOMAIN_CONTROLLER 0x0000002 +#define VER_NT_SERVER 0x0000003 + +#define VER_PLATFORM_WIN32s 0 +#define VER_PLATFORM_WIN32_WINDOWS 1 +#define VER_PLATFORM_WIN32_NT 2 + +#define VER_SET_CONDITION(_m_,_t_,_c_) ((_m_)=VerSetConditionMask((_m_),(_t_),(_c_))) + + NTSYSAPI ULONGLONG NTAPI VerSetConditionMask(ULONGLONG ConditionMask,DWORD TypeMask,BYTE Condition); + + typedef struct _RTL_CRITICAL_SECTION_DEBUG { + WORD Type; + WORD CreatorBackTraceIndex; + struct _RTL_CRITICAL_SECTION *CriticalSection; + LIST_ENTRY ProcessLocksList; + DWORD EntryCount; + DWORD ContentionCount; + DWORD Spare[2]; + } RTL_CRITICAL_SECTION_DEBUG,*PRTL_CRITICAL_SECTION_DEBUG,RTL_RESOURCE_DEBUG,*PRTL_RESOURCE_DEBUG; + +#define RTL_CRITSECT_TYPE 0 +#define RTL_RESOURCE_TYPE 1 + + typedef struct _RTL_CRITICAL_SECTION { + PRTL_CRITICAL_SECTION_DEBUG DebugInfo; + LONG LockCount; + LONG RecursionCount; + HANDLE OwningThread; + HANDLE LockSemaphore; + ULONG_PTR SpinCount; + } RTL_CRITICAL_SECTION,*PRTL_CRITICAL_SECTION; + + typedef VOID (NTAPI *RTL_VERIFIER_DLL_LOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); + typedef VOID (NTAPI *RTL_VERIFIER_DLL_UNLOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); + typedef VOID (NTAPI *RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK)(PVOID AllocationBase,SIZE_T AllocationSize); + + typedef struct _RTL_VERIFIER_THUNK_DESCRIPTOR { + PCHAR ThunkName; + PVOID ThunkOldAddress; + PVOID ThunkNewAddress; + } RTL_VERIFIER_THUNK_DESCRIPTOR,*PRTL_VERIFIER_THUNK_DESCRIPTOR; + + typedef struct _RTL_VERIFIER_DLL_DESCRIPTOR { + PWCHAR DllName; + DWORD DllFlags; + PVOID DllAddress; + PRTL_VERIFIER_THUNK_DESCRIPTOR DllThunks; + } RTL_VERIFIER_DLL_DESCRIPTOR,*PRTL_VERIFIER_DLL_DESCRIPTOR; + + typedef struct _RTL_VERIFIER_PROVIDER_DESCRIPTOR { + DWORD Length; + PRTL_VERIFIER_DLL_DESCRIPTOR ProviderDlls; + RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback; + RTL_VERIFIER_DLL_UNLOAD_CALLBACK ProviderDllUnloadCallback; + PWSTR VerifierImage; + DWORD VerifierFlags; + DWORD VerifierDebug; + PVOID RtlpGetStackTraceAddress; + PVOID RtlpDebugPageHeapCreate; + PVOID RtlpDebugPageHeapDestroy; + RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK ProviderNtdllHeapFreeCallback; + } RTL_VERIFIER_PROVIDER_DESCRIPTOR,*PRTL_VERIFIER_PROVIDER_DESCRIPTOR; + +#define RTL_VRF_FLG_FULL_PAGE_HEAP 0x00000001 +#define RTL_VRF_FLG_RESERVED_DONOTUSE 0x00000002 +#define RTL_VRF_FLG_HANDLE_CHECKS 0x00000004 +#define RTL_VRF_FLG_STACK_CHECKS 0x00000008 +#define RTL_VRF_FLG_APPCOMPAT_CHECKS 0x00000010 +#define RTL_VRF_FLG_TLS_CHECKS 0x00000020 +#define RTL_VRF_FLG_DIRTY_STACKS 0x00000040 +#define RTL_VRF_FLG_RPC_CHECKS 0x00000080 +#define RTL_VRF_FLG_COM_CHECKS 0x00000100 +#define RTL_VRF_FLG_DANGEROUS_APIS 0x00000200 +#define RTL_VRF_FLG_RACE_CHECKS 0x00000400 +#define RTL_VRF_FLG_DEADLOCK_CHECKS 0x00000800 +#define RTL_VRF_FLG_FIRST_CHANCE_EXCEPTION_CHECKS 0x00001000 +#define RTL_VRF_FLG_VIRTUAL_MEM_CHECKS 0x00002000 +#define RTL_VRF_FLG_ENABLE_LOGGING 0x00004000 +#define RTL_VRF_FLG_FAST_FILL_HEAP 0x00008000 +#define RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING 0x00010000 +#define RTL_VRF_FLG_ENABLED_SYSTEM_WIDE 0x00020000 +#define RTL_VRF_FLG_MISCELLANEOUS_CHECKS 0x00020000 +#define RTL_VRF_FLG_LOCK_CHECKS 0x00040000 + +#define APPLICATION_VERIFIER_INTERNAL_ERROR 0x80000000 +#define APPLICATION_VERIFIER_INTERNAL_WARNING 0x40000000 +#define APPLICATION_VERIFIER_NO_BREAK 0x20000000 +#define APPLICATION_VERIFIER_CONTINUABLE_BREAK 0x10000000 + +#define APPLICATION_VERIFIER_UNKNOWN_ERROR 0x0001 +#define APPLICATION_VERIFIER_ACCESS_VIOLATION 0x0002 +#define APPLICATION_VERIFIER_UNSYNCHRONIZED_ACCESS 0x0003 +#define APPLICATION_VERIFIER_EXTREME_SIZE_REQUEST 0x0004 +#define APPLICATION_VERIFIER_BAD_HEAP_HANDLE 0x0005 +#define APPLICATION_VERIFIER_SWITCHED_HEAP_HANDLE 0x0006 +#define APPLICATION_VERIFIER_DOUBLE_FREE 0x0007 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK 0x0008 +#define APPLICATION_VERIFIER_DESTROY_PROCESS_HEAP 0x0009 +#define APPLICATION_VERIFIER_UNEXPECTED_EXCEPTION 0x000A +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_HEADER 0x000B +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_PROBING 0x000C +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_HEADER 0x000D +#define APPLICATION_VERIFIER_CORRUPTED_FREED_HEAP_BLOCK 0x000E +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_SUFFIX 0x000F +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_START_STAMP 0x0010 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_END_STAMP 0x0011 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_PREFIX 0x0012 +#define APPLICATION_VERIFIER_FIRST_CHANCE_ACCESS_VIOLATION 0x0013 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_LIST 0x0014 + +#define APPLICATION_VERIFIER_TERMINATE_THREAD_CALL 0x0100 +#define APPLICATION_VERIFIER_STACK_OVERFLOW 0x0101 +#define APPLICATION_VERIFIER_INVALID_EXIT_PROCESS_CALL 0x0102 + +#define APPLICATION_VERIFIER_EXIT_THREAD_OWNS_LOCK 0x0200 +#define APPLICATION_VERIFIER_LOCK_IN_UNLOADED_DLL 0x0201 +#define APPLICATION_VERIFIER_LOCK_IN_FREED_HEAP 0x0202 +#define APPLICATION_VERIFIER_LOCK_DOUBLE_INITIALIZE 0x0203 +#define APPLICATION_VERIFIER_LOCK_IN_FREED_MEMORY 0x0204 +#define APPLICATION_VERIFIER_LOCK_CORRUPTED 0x0205 +#define APPLICATION_VERIFIER_LOCK_INVALID_OWNER 0x0206 +#define APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT 0x0207 +#define APPLICATION_VERIFIER_LOCK_INVALID_LOCK_COUNT 0x0208 +#define APPLICATION_VERIFIER_LOCK_OVER_RELEASED 0x0209 +#define APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED 0x0210 +#define APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED 0x0211 +#define APPLICATION_VERIFIER_LOCK_IN_FREED_VMEM 0x0212 +#define APPLICATION_VERIFIER_LOCK_IN_UNMAPPED_MEM 0x0213 +#define APPLICATION_VERIFIER_THREAD_NOT_LOCK_OWNER 0x0214 + +#define APPLICATION_VERIFIER_INVALID_HANDLE 0x0300 +#define APPLICATION_VERIFIER_INVALID_TLS_VALUE 0x0301 +#define APPLICATION_VERIFIER_INCORRECT_WAIT_CALL 0x0302 +#define APPLICATION_VERIFIER_NULL_HANDLE 0x0303 +#define APPLICATION_VERIFIER_WAIT_IN_DLLMAIN 0x0304 + +#define APPLICATION_VERIFIER_COM_ERROR 0x0400 +#define APPLICATION_VERIFIER_COM_API_IN_DLLMAIN 0x0401 +#define APPLICATION_VERIFIER_COM_UNHANDLED_EXCEPTION 0x0402 +#define APPLICATION_VERIFIER_COM_UNBALANCED_COINIT 0x0403 +#define APPLICATION_VERIFIER_COM_UNBALANCED_OLEINIT 0x0404 +#define APPLICATION_VERIFIER_COM_UNBALANCED_SWC 0x0405 +#define APPLICATION_VERIFIER_COM_NULL_DACL 0x0406 +#define APPLICATION_VERIFIER_COM_UNSAFE_IMPERSONATION 0x0407 +#define APPLICATION_VERIFIER_COM_SMUGGLED_WRAPPER 0x0408 +#define APPLICATION_VERIFIER_COM_SMUGGLED_PROXY 0x0409 +#define APPLICATION_VERIFIER_COM_CF_SUCCESS_WITH_NULL 0x040A +#define APPLICATION_VERIFIER_COM_GCO_SUCCESS_WITH_NULL 0x040B +#define APPLICATION_VERIFIER_COM_OBJECT_IN_FREED_MEMORY 0x040C +#define APPLICATION_VERIFIER_COM_OBJECT_IN_UNLOADED_DLL 0x040D +#define APPLICATION_VERIFIER_COM_VTBL_IN_FREED_MEMORY 0x040E +#define APPLICATION_VERIFIER_COM_VTBL_IN_UNLOADED_DLL 0x040F +#define APPLICATION_VERIFIER_COM_HOLDING_LOCKS_ON_CALL 0x0410 + +#define APPLICATION_VERIFIER_RPC_ERROR 0x0500 + +#define APPLICATION_VERIFIER_INVALID_FREEMEM 0x0600 +#define APPLICATION_VERIFIER_INVALID_ALLOCMEM 0x0601 +#define APPLICATION_VERIFIER_INVALID_MAPVIEW 0x0602 +#define APPLICATION_VERIFIER_PROBE_INVALID_ADDRESS 0x0603 +#define APPLICATION_VERIFIER_PROBE_FREE_MEM 0x0604 +#define APPLICATION_VERIFIER_PROBE_GUARD_PAGE 0x0605 +#define APPLICATION_VERIFIER_PROBE_NULL 0x0606 +#define APPLICATION_VERIFIER_PROBE_INVALID_START_OR_SIZE 0x0607 +#define APPLICATION_VERIFIER_SIZE_HEAP_UNEXPECTED_EXCEPTION 0x0618 + +#define VERIFIER_STOP(Code,Msg,P1,S1,P2,S2,P3,S3,P4,S4) { RtlApplicationVerifierStop ((Code),(Msg),(ULONG_PTR)(P1),(S1),(ULONG_PTR)(P2),(S2),(ULONG_PTR)(P3),(S3),(ULONG_PTR)(P4),(S4)); } + + VOID NTAPI RtlApplicationVerifierStop(ULONG_PTR Code,PSTR Message,ULONG_PTR Param1,PSTR Description1,ULONG_PTR Param2,PSTR Description2,ULONG_PTR Param3,PSTR Description3,ULONG_PTR Param4,PSTR Description4); + + typedef LONG (NTAPI *PVECTORED_EXCEPTION_HANDLER)(struct _EXCEPTION_POINTERS *ExceptionInfo); +#define SEF_DACL_AUTO_INHERIT 0x01 +#define SEF_SACL_AUTO_INHERIT 0x02 +#define SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT 0x04 +#define SEF_AVOID_PRIVILEGE_CHECK 0x08 +#define SEF_AVOID_OWNER_CHECK 0x10 +#define SEF_DEFAULT_OWNER_FROM_PARENT 0x20 +#define SEF_DEFAULT_GROUP_FROM_PARENT 0x40 + + typedef enum _HEAP_INFORMATION_CLASS { + HeapCompatibilityInformation + } HEAP_INFORMATION_CLASS; + + NTSYSAPI DWORD NTAPI RtlSetHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); + NTSYSAPI DWORD NTAPI RtlQueryHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); + DWORD NTAPI RtlMultipleAllocateHeap(PVOID HeapHandle,DWORD Flags,SIZE_T Size,DWORD Count,PVOID *Array); + DWORD NTAPI RtlMultipleFreeHeap(PVOID HeapHandle,DWORD Flags,DWORD Count,PVOID *Array); + +#define WT_EXECUTEDEFAULT 0x00000000 +#define WT_EXECUTEINIOTHREAD 0x00000001 +#define WT_EXECUTEINUITHREAD 0x00000002 +#define WT_EXECUTEINWAITTHREAD 0x00000004 +#define WT_EXECUTEONLYONCE 0x00000008 +#define WT_EXECUTEINTIMERTHREAD 0x00000020 +#define WT_EXECUTELONGFUNCTION 0x00000010 +#define WT_EXECUTEINPERSISTENTIOTHREAD 0x00000040 +#define WT_EXECUTEINPERSISTENTTHREAD 0x00000080 +#define WT_TRANSFER_IMPERSONATION 0x00000100 +#define WT_SET_MAX_THREADPOOL_THREADS(Flags,Limit) ((Flags) |= (Limit)<<16) + typedef VOID (NTAPI *WAITORTIMERCALLBACKFUNC)(PVOID,BOOLEAN); + typedef VOID (NTAPI *WORKERCALLBACKFUNC)(PVOID); + typedef VOID (NTAPI *APC_CALLBACK_FUNCTION)(DWORD ,PVOID,PVOID); + typedef + VOID + (NTAPI *PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); +#define WT_EXECUTEINLONGTHREAD 0x00000010 +#define WT_EXECUTEDELETEWAIT 0x00000008 + + typedef enum _ACTIVATION_CONTEXT_INFO_CLASS { + ActivationContextBasicInformation = 1,ActivationContextDetailedInformation = 2,AssemblyDetailedInformationInActivationContext = 3,FileInformationInAssemblyOfAssemblyInActivationContext = 4,MaxActivationContextInfoClass,AssemblyDetailedInformationInActivationContxt = 3,FileInformationInAssemblyOfAssemblyInActivationContxt = 4 + } ACTIVATION_CONTEXT_INFO_CLASS; + +#define ACTIVATIONCONTEXTINFOCLASS ACTIVATION_CONTEXT_INFO_CLASS + + typedef struct _ACTIVATION_CONTEXT_QUERY_INDEX { + DWORD ulAssemblyIndex; + DWORD ulFileIndexInAssembly; + } ACTIVATION_CONTEXT_QUERY_INDEX,*PACTIVATION_CONTEXT_QUERY_INDEX; + + typedef const struct _ACTIVATION_CONTEXT_QUERY_INDEX *PCACTIVATION_CONTEXT_QUERY_INDEX; + +#define ACTIVATION_CONTEXT_PATH_TYPE_NONE (1) +#define ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE (2) +#define ACTIVATION_CONTEXT_PATH_TYPE_URL (3) +#define ACTIVATION_CONTEXT_PATH_TYPE_ASSEMBLYREF (4) + + typedef struct _ASSEMBLY_FILE_DETAILED_INFORMATION { + DWORD ulFlags; + DWORD ulFilenameLength; + DWORD ulPathLength; + + PCWSTR lpFileName; + PCWSTR lpFilePath; + } ASSEMBLY_FILE_DETAILED_INFORMATION,*PASSEMBLY_FILE_DETAILED_INFORMATION; + typedef const ASSEMBLY_FILE_DETAILED_INFORMATION *PCASSEMBLY_FILE_DETAILED_INFORMATION; + +#define _ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION _ASSEMBLY_FILE_DETAILED_INFORMATION +#define ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION ASSEMBLY_FILE_DETAILED_INFORMATION +#define PASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PASSEMBLY_FILE_DETAILED_INFORMATION +#define PCASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PCASSEMBLY_FILE_DETAILED_INFORMATION + + typedef struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION { + DWORD ulFlags; + DWORD ulEncodedAssemblyIdentityLength; + DWORD ulManifestPathType; + DWORD ulManifestPathLength; + LARGE_INTEGER liManifestLastWriteTime; + DWORD ulPolicyPathType; + DWORD ulPolicyPathLength; + LARGE_INTEGER liPolicyLastWriteTime; + DWORD ulMetadataSatelliteRosterIndex; + DWORD ulManifestVersionMajor; + DWORD ulManifestVersionMinor; + DWORD ulPolicyVersionMajor; + DWORD ulPolicyVersionMinor; + DWORD ulAssemblyDirectoryNameLength; + PCWSTR lpAssemblyEncodedAssemblyIdentity; + PCWSTR lpAssemblyManifestPath; + PCWSTR lpAssemblyPolicyPath; + PCWSTR lpAssemblyDirectoryName; + DWORD ulFileCount; + } ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; + + typedef const struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; + + typedef struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION { + DWORD dwFlags; + DWORD ulFormatVersion; + DWORD ulAssemblyCount; + DWORD ulRootManifestPathType; + DWORD ulRootManifestPathChars; + DWORD ulRootConfigurationPathType; + DWORD ulRootConfigurationPathChars; + DWORD ulAppDirPathType; + DWORD ulAppDirPathChars; + PCWSTR lpRootManifestPath; + PCWSTR lpRootConfigurationPath; + PCWSTR lpAppDirPath; + } ACTIVATION_CONTEXT_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_DETAILED_INFORMATION; + + typedef const struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_DETAILED_INFORMATION; + +#define DLL_PROCESS_ATTACH 1 +#define DLL_THREAD_ATTACH 2 +#define DLL_THREAD_DETACH 3 +#define DLL_PROCESS_DETACH 0 +#define DLL_PROCESS_VERIFIER 4 + +#define EVENTLOG_SEQUENTIAL_READ 0x0001 +#define EVENTLOG_SEEK_READ 0x0002 +#define EVENTLOG_FORWARDS_READ 0x0004 +#define EVENTLOG_BACKWARDS_READ 0x0008 + +#define EVENTLOG_SUCCESS 0x0000 +#define EVENTLOG_ERROR_TYPE 0x0001 +#define EVENTLOG_WARNING_TYPE 0x0002 +#define EVENTLOG_INFORMATION_TYPE 0x0004 +#define EVENTLOG_AUDIT_SUCCESS 0x0008 +#define EVENTLOG_AUDIT_FAILURE 0x0010 + +#define EVENTLOG_START_PAIRED_EVENT 0x0001 +#define EVENTLOG_END_PAIRED_EVENT 0x0002 +#define EVENTLOG_END_ALL_PAIRED_EVENTS 0x0004 +#define EVENTLOG_PAIRED_EVENT_ACTIVE 0x0008 +#define EVENTLOG_PAIRED_EVENT_INACTIVE 0x0010 + + typedef struct _EVENTLOGRECORD { + DWORD Length; + DWORD Reserved; + DWORD RecordNumber; + DWORD TimeGenerated; + DWORD TimeWritten; + DWORD EventID; + WORD EventType; + WORD NumStrings; + WORD EventCategory; + WORD ReservedFlags; + DWORD ClosingRecordNumber; + DWORD StringOffset; + DWORD UserSidLength; + DWORD UserSidOffset; + DWORD DataLength; + DWORD DataOffset; + } EVENTLOGRECORD,*PEVENTLOGRECORD; + +#define MAXLOGICALLOGNAMESIZE 256 + + typedef struct _EVENTSFORLOGFILE{ + DWORD ulSize; + WCHAR szLogicalLogFile[MAXLOGICALLOGNAMESIZE]; + DWORD ulNumRecords; + EVENTLOGRECORD pEventLogRecords[]; + } EVENTSFORLOGFILE,*PEVENTSFORLOGFILE; + + typedef struct _PACKEDEVENTINFO{ + DWORD ulSize; + DWORD ulNumEventsForLogFile; + DWORD ulOffsets[]; + } PACKEDEVENTINFO,*PPACKEDEVENTINFO; + +#define KEY_QUERY_VALUE (0x0001) +#define KEY_SET_VALUE (0x0002) +#define KEY_CREATE_SUB_KEY (0x0004) +#define KEY_ENUMERATE_SUB_KEYS (0x0008) +#define KEY_NOTIFY (0x0010) +#define KEY_CREATE_LINK (0x0020) +#define KEY_WOW64_32KEY (0x0200) +#define KEY_WOW64_64KEY (0x0100) +#define KEY_WOW64_RES (0x0300) + +#define KEY_READ ((STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & (~SYNCHRONIZE)) +#define KEY_WRITE ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE)) +#define KEY_EXECUTE ((KEY_READ) & (~SYNCHRONIZE)) +#define KEY_ALL_ACCESS ((STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & (~SYNCHRONIZE)) +#define REG_OPTION_RESERVED (0x00000000L) + +#define REG_OPTION_NON_VOLATILE (0x00000000L) +#define REG_OPTION_VOLATILE (0x00000001L) +#define REG_OPTION_CREATE_LINK (0x00000002L) +#define REG_OPTION_BACKUP_RESTORE (0x00000004L) +#define REG_OPTION_OPEN_LINK (0x00000008L) +#define REG_LEGAL_OPTION (REG_OPTION_RESERVED | REG_OPTION_NON_VOLATILE | REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK | REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK) +#define REG_CREATED_NEW_KEY (0x00000001L) +#define REG_OPENED_EXISTING_KEY (0x00000002L) +#define REG_STANDARD_FORMAT 1 +#define REG_LATEST_FORMAT 2 +#define REG_NO_COMPRESSION 4 +#define REG_WHOLE_HIVE_VOLATILE (0x00000001L) +#define REG_REFRESH_HIVE (0x00000002L) +#define REG_NO_LAZY_FLUSH (0x00000004L) +#define REG_FORCE_RESTORE (0x00000008L) +#define REG_FORCE_UNLOAD 1 + +#define REG_NOTIFY_CHANGE_NAME (0x00000001L) +#define REG_NOTIFY_CHANGE_ATTRIBUTES (0x00000002L) +#define REG_NOTIFY_CHANGE_LAST_SET (0x00000004L) +#define REG_NOTIFY_CHANGE_SECURITY (0x00000008L) + +#define REG_LEGAL_CHANGE_FILTER (REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY) + +#define REG_NONE (0) +#define REG_SZ (1) +#define REG_EXPAND_SZ (2) + +#define REG_BINARY (3) +#define REG_DWORD (4) +#define REG_DWORD_LITTLE_ENDIAN (4) +#define REG_DWORD_BIG_ENDIAN (5) +#define REG_LINK (6) +#define REG_MULTI_SZ (7) +#define REG_RESOURCE_LIST (8) +#define REG_FULL_RESOURCE_DESCRIPTOR (9) +#define REG_RESOURCE_REQUIREMENTS_LIST (10) +#define REG_QWORD (11) +#define REG_QWORD_LITTLE_ENDIAN (11) + +#define SERVICE_KERNEL_DRIVER 0x00000001 +#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 +#define SERVICE_ADAPTER 0x00000004 +#define SERVICE_RECOGNIZER_DRIVER 0x00000008 + +#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER) + +#define SERVICE_WIN32_OWN_PROCESS 0x00000010 +#define SERVICE_WIN32_SHARE_PROCESS 0x00000020 +#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS) + +#define SERVICE_INTERACTIVE_PROCESS 0x00000100 + +#define SERVICE_TYPE_ALL (SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS) + +#define SERVICE_BOOT_START 0x00000000 +#define SERVICE_SYSTEM_START 0x00000001 +#define SERVICE_AUTO_START 0x00000002 +#define SERVICE_DEMAND_START 0x00000003 +#define SERVICE_DISABLED 0x00000004 + +#define SERVICE_ERROR_IGNORE 0x00000000 +#define SERVICE_ERROR_NORMAL 0x00000001 +#define SERVICE_ERROR_SEVERE 0x00000002 +#define SERVICE_ERROR_CRITICAL 0x00000003 + + typedef enum _CM_SERVICE_NODE_TYPE { + DriverType = SERVICE_KERNEL_DRIVER,FileSystemType = SERVICE_FILE_SYSTEM_DRIVER,Win32ServiceOwnProcess = SERVICE_WIN32_OWN_PROCESS, + Win32ServiceShareProcess = SERVICE_WIN32_SHARE_PROCESS,AdapterType = SERVICE_ADAPTER,RecognizerType = SERVICE_RECOGNIZER_DRIVER + } SERVICE_NODE_TYPE; + + typedef enum _CM_SERVICE_LOAD_TYPE { + BootLoad = SERVICE_BOOT_START,SystemLoad = SERVICE_SYSTEM_START,AutoLoad = SERVICE_AUTO_START,DemandLoad = SERVICE_DEMAND_START, + DisableLoad = SERVICE_DISABLED + } SERVICE_LOAD_TYPE; + + typedef enum _CM_ERROR_CONTROL_TYPE { + IgnoreError = SERVICE_ERROR_IGNORE,NormalError = SERVICE_ERROR_NORMAL,SevereError = SERVICE_ERROR_SEVERE,CriticalError = SERVICE_ERROR_CRITICAL + } SERVICE_ERROR_TYPE; + +#define TAPE_ERASE_SHORT 0L +#define TAPE_ERASE_LONG 1L + + typedef struct _TAPE_ERASE { + DWORD Type; + BOOLEAN Immediate; + } TAPE_ERASE,*PTAPE_ERASE; + +#define TAPE_LOAD 0L +#define TAPE_UNLOAD 1L +#define TAPE_TENSION 2L +#define TAPE_LOCK 3L +#define TAPE_UNLOCK 4L +#define TAPE_FORMAT 5L + + typedef struct _TAPE_PREPARE { + DWORD Operation; + BOOLEAN Immediate; + } TAPE_PREPARE,*PTAPE_PREPARE; + +#define TAPE_SETMARKS 0L +#define TAPE_FILEMARKS 1L +#define TAPE_SHORT_FILEMARKS 2L +#define TAPE_LONG_FILEMARKS 3L + + typedef struct _TAPE_WRITE_MARKS { + DWORD Type; + DWORD Count; + BOOLEAN Immediate; + } TAPE_WRITE_MARKS,*PTAPE_WRITE_MARKS; + +#define TAPE_ABSOLUTE_POSITION 0L +#define TAPE_LOGICAL_POSITION 1L +#define TAPE_PSEUDO_LOGICAL_POSITION 2L + + typedef struct _TAPE_GET_POSITION { + DWORD Type; + DWORD Partition; + LARGE_INTEGER Offset; + } TAPE_GET_POSITION,*PTAPE_GET_POSITION; + +#define TAPE_REWIND 0L +#define TAPE_ABSOLUTE_BLOCK 1L +#define TAPE_LOGICAL_BLOCK 2L +#define TAPE_PSEUDO_LOGICAL_BLOCK 3L +#define TAPE_SPACE_END_OF_DATA 4L +#define TAPE_SPACE_RELATIVE_BLOCKS 5L +#define TAPE_SPACE_FILEMARKS 6L +#define TAPE_SPACE_SEQUENTIAL_FMKS 7L +#define TAPE_SPACE_SETMARKS 8L +#define TAPE_SPACE_SEQUENTIAL_SMKS 9L + + typedef struct _TAPE_SET_POSITION { + DWORD Method; + DWORD Partition; + LARGE_INTEGER Offset; + BOOLEAN Immediate; + } TAPE_SET_POSITION,*PTAPE_SET_POSITION; + +#define TAPE_DRIVE_FIXED 0x00000001 +#define TAPE_DRIVE_SELECT 0x00000002 +#define TAPE_DRIVE_INITIATOR 0x00000004 + +#define TAPE_DRIVE_ERASE_SHORT 0x00000010 +#define TAPE_DRIVE_ERASE_LONG 0x00000020 +#define TAPE_DRIVE_ERASE_BOP_ONLY 0x00000040 +#define TAPE_DRIVE_ERASE_IMMEDIATE 0x00000080 + +#define TAPE_DRIVE_TAPE_CAPACITY 0x00000100 +#define TAPE_DRIVE_TAPE_REMAINING 0x00000200 +#define TAPE_DRIVE_FIXED_BLOCK 0x00000400 +#define TAPE_DRIVE_VARIABLE_BLOCK 0x00000800 + +#define TAPE_DRIVE_WRITE_PROTECT 0x00001000 +#define TAPE_DRIVE_EOT_WZ_SIZE 0x00002000 + +#define TAPE_DRIVE_ECC 0x00010000 +#define TAPE_DRIVE_COMPRESSION 0x00020000 +#define TAPE_DRIVE_PADDING 0x00040000 +#define TAPE_DRIVE_REPORT_SMKS 0x00080000 + +#define TAPE_DRIVE_GET_ABSOLUTE_BLK 0x00100000 +#define TAPE_DRIVE_GET_LOGICAL_BLK 0x00200000 +#define TAPE_DRIVE_SET_EOT_WZ_SIZE 0x00400000 + +#define TAPE_DRIVE_EJECT_MEDIA 0x01000000 +#define TAPE_DRIVE_CLEAN_REQUESTS 0x02000000 +#define TAPE_DRIVE_SET_CMP_BOP_ONLY 0x04000000 + +#define TAPE_DRIVE_RESERVED_BIT 0x80000000 + +#define TAPE_DRIVE_LOAD_UNLOAD 0x80000001 +#define TAPE_DRIVE_TENSION 0x80000002 +#define TAPE_DRIVE_LOCK_UNLOCK 0x80000004 +#define TAPE_DRIVE_REWIND_IMMEDIATE 0x80000008 + +#define TAPE_DRIVE_SET_BLOCK_SIZE 0x80000010 +#define TAPE_DRIVE_LOAD_UNLD_IMMED 0x80000020 +#define TAPE_DRIVE_TENSION_IMMED 0x80000040 +#define TAPE_DRIVE_LOCK_UNLK_IMMED 0x80000080 + +#define TAPE_DRIVE_SET_ECC 0x80000100 +#define TAPE_DRIVE_SET_COMPRESSION 0x80000200 +#define TAPE_DRIVE_SET_PADDING 0x80000400 +#define TAPE_DRIVE_SET_REPORT_SMKS 0x80000800 + +#define TAPE_DRIVE_ABSOLUTE_BLK 0x80001000 +#define TAPE_DRIVE_ABS_BLK_IMMED 0x80002000 +#define TAPE_DRIVE_LOGICAL_BLK 0x80004000 +#define TAPE_DRIVE_LOG_BLK_IMMED 0x80008000 + +#define TAPE_DRIVE_END_OF_DATA 0x80010000 +#define TAPE_DRIVE_RELATIVE_BLKS 0x80020000 +#define TAPE_DRIVE_FILEMARKS 0x80040000 +#define TAPE_DRIVE_SEQUENTIAL_FMKS 0x80080000 + +#define TAPE_DRIVE_SETMARKS 0x80100000 +#define TAPE_DRIVE_SEQUENTIAL_SMKS 0x80200000 +#define TAPE_DRIVE_REVERSE_POSITION 0x80400000 +#define TAPE_DRIVE_SPACE_IMMEDIATE 0x80800000 + +#define TAPE_DRIVE_WRITE_SETMARKS 0x81000000 +#define TAPE_DRIVE_WRITE_FILEMARKS 0x82000000 +#define TAPE_DRIVE_WRITE_SHORT_FMKS 0x84000000 +#define TAPE_DRIVE_WRITE_LONG_FMKS 0x88000000 + +#define TAPE_DRIVE_WRITE_MARK_IMMED 0x90000000 +#define TAPE_DRIVE_FORMAT 0xA0000000 +#define TAPE_DRIVE_FORMAT_IMMEDIATE 0xC0000000 +#define TAPE_DRIVE_HIGH_FEATURES 0x80000000 + + typedef struct _TAPE_GET_DRIVE_PARAMETERS { + BOOLEAN ECC; + BOOLEAN Compression; + BOOLEAN DataPadding; + BOOLEAN ReportSetmarks; + DWORD DefaultBlockSize; + DWORD MaximumBlockSize; + DWORD MinimumBlockSize; + DWORD MaximumPartitionCount; + DWORD FeaturesLow; + DWORD FeaturesHigh; + DWORD EOTWarningZoneSize; + } TAPE_GET_DRIVE_PARAMETERS,*PTAPE_GET_DRIVE_PARAMETERS; + + typedef struct _TAPE_SET_DRIVE_PARAMETERS { + BOOLEAN ECC; + BOOLEAN Compression; + BOOLEAN DataPadding; + BOOLEAN ReportSetmarks; + DWORD EOTWarningZoneSize; + } TAPE_SET_DRIVE_PARAMETERS,*PTAPE_SET_DRIVE_PARAMETERS; + + typedef struct _TAPE_GET_MEDIA_PARAMETERS { + LARGE_INTEGER Capacity; + LARGE_INTEGER Remaining; + DWORD BlockSize; + DWORD PartitionCount; + BOOLEAN WriteProtected; + } TAPE_GET_MEDIA_PARAMETERS,*PTAPE_GET_MEDIA_PARAMETERS; + + typedef struct _TAPE_SET_MEDIA_PARAMETERS { + DWORD BlockSize; + } TAPE_SET_MEDIA_PARAMETERS,*PTAPE_SET_MEDIA_PARAMETERS; + +#define TAPE_FIXED_PARTITIONS 0L +#define TAPE_SELECT_PARTITIONS 1L +#define TAPE_INITIATOR_PARTITIONS 2L + + typedef struct _TAPE_CREATE_PARTITION { + DWORD Method; + DWORD Count; + DWORD Size; + } TAPE_CREATE_PARTITION,*PTAPE_CREATE_PARTITION; + +#define TAPE_QUERY_DRIVE_PARAMETERS 0L +#define TAPE_QUERY_MEDIA_CAPACITY 1L +#define TAPE_CHECK_FOR_DRIVE_PROBLEM 2L +#define TAPE_QUERY_IO_ERROR_DATA 3L +#define TAPE_QUERY_DEVICE_ERROR_DATA 4L + + typedef struct _TAPE_WMI_OPERATIONS { + DWORD Method; + DWORD DataBufferSize; + PVOID DataBuffer; + } TAPE_WMI_OPERATIONS,*PTAPE_WMI_OPERATIONS; + + typedef enum _TAPE_DRIVE_PROBLEM_TYPE { + TapeDriveProblemNone,TapeDriveReadWriteWarning,TapeDriveReadWriteError,TapeDriveReadWarning,TapeDriveWriteWarning,TapeDriveReadError,TapeDriveWriteError,TapeDriveHardwareError,TapeDriveUnsupportedMedia,TapeDriveScsiConnectionError,TapeDriveTimetoClean,TapeDriveCleanDriveNow,TapeDriveMediaLifeExpired,TapeDriveSnappedTape + } TAPE_DRIVE_PROBLEM_TYPE; + +#if defined(__x86_64) + __CRT_INLINE struct _TEB *NtCurrentTeb(VOID) { return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB,Self)); } + __CRT_INLINE PVOID GetCurrentFiber(VOID) { return(PVOID)__readgsqword(FIELD_OFFSET(NT_TIB,FiberData)); } + __CRT_INLINE PVOID GetFiberData(VOID) { + return *(PVOID *)GetCurrentFiber(); + } +#endif + +#if(defined(_X86_) && !defined(__x86_64)) +#define PcTeb 0x18 + __CRT_INLINE struct _TEB *NtCurrentTeb(void) { + struct _TEB *ret; + __asm__ volatile ("movl %%fs:0x18,%0" + : "=r" (ret)); + return ret; + } +#endif + +#define ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION (1) +#define ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION (2) +#define ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION (3) +#define ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION (4) +#define ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION (5) +#define ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION (6) +#define ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION (7) +#define ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE (8) +#define ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES (9) +#define ACTIVATION_CONTEXT_SECTION_APPLICATION_SETTINGS (10) + +#ifdef __cplusplus + } +#endif +#endif diff --git a/tcc/include/winapi/winreg.h b/tcc/include/winapi/winreg.h index f158d282..a3b5eb3b 100644 --- a/tcc/include/winapi/winreg.h +++ b/tcc/include/winapi/winreg.h @@ -1,272 +1,272 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINREG_ -#define _WINREG_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#define RRF_RT_REG_NONE 0x00000001 -#define RRF_RT_REG_SZ 0x00000002 -#define RRF_RT_REG_EXPAND_SZ 0x00000004 -#define RRF_RT_REG_BINARY 0x00000008 -#define RRF_RT_REG_DWORD 0x00000010 -#define RRF_RT_REG_MULTI_SZ 0x00000020 -#define RRF_RT_REG_QWORD 0x00000040 - -#define RRF_RT_DWORD (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD) -#define RRF_RT_QWORD (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD) -#define RRF_RT_ANY 0x0000ffff - -#define RRF_NOEXPAND 0x10000000 -#define RRF_ZEROONFAILURE 0x20000000 - - typedef ACCESS_MASK REGSAM; - -#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000)) -#define HKEY_CURRENT_USER ((HKEY) (ULONG_PTR)((LONG)0x80000001)) -#define HKEY_LOCAL_MACHINE ((HKEY) (ULONG_PTR)((LONG)0x80000002)) -#define HKEY_USERS ((HKEY) (ULONG_PTR)((LONG)0x80000003)) -#define HKEY_PERFORMANCE_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000004)) -#define HKEY_PERFORMANCE_TEXT ((HKEY) (ULONG_PTR)((LONG)0x80000050)) -#define HKEY_PERFORMANCE_NLSTEXT ((HKEY) (ULONG_PTR)((LONG)0x80000060)) -#define HKEY_CURRENT_CONFIG ((HKEY) (ULONG_PTR)((LONG)0x80000005)) -#define HKEY_DYN_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000006)) - -#define REG_SECURE_CONNECTION 1 - -#ifndef _PROVIDER_STRUCTS_DEFINED -#define _PROVIDER_STRUCTS_DEFINED - -#define PROVIDER_KEEPS_VALUE_LENGTH 0x1 - struct val_context { - int valuelen; - LPVOID value_context; - LPVOID val_buff_ptr; - }; - - typedef struct val_context *PVALCONTEXT; - - typedef struct pvalueA { - LPSTR pv_valuename; - int pv_valuelen; - LPVOID pv_value_context; - DWORD pv_type; - }PVALUEA,*PPVALUEA; - - typedef struct pvalueW { - LPWSTR pv_valuename; - int pv_valuelen; - LPVOID pv_value_context; - DWORD pv_type; - }PVALUEW,*PPVALUEW; - -#ifdef UNICODE - typedef PVALUEW PVALUE; - typedef PPVALUEW PPVALUE; -#else - typedef PVALUEA PVALUE; - typedef PPVALUEA PPVALUE; -#endif - - typedef DWORD __cdecl QUERYHANDLER(LPVOID keycontext,PVALCONTEXT val_list,DWORD num_vals,LPVOID outputbuffer,DWORD *total_outlen,DWORD input_blen); - - typedef QUERYHANDLER *PQUERYHANDLER; - - typedef struct provider_info { - PQUERYHANDLER pi_R0_1val; - PQUERYHANDLER pi_R0_allvals; - PQUERYHANDLER pi_R3_1val; - PQUERYHANDLER pi_R3_allvals; - DWORD pi_flags; - LPVOID pi_key_context; - } REG_PROVIDER; - - typedef struct provider_info *PPROVIDER; - - typedef struct value_entA { - LPSTR ve_valuename; - DWORD ve_valuelen; - DWORD_PTR ve_valueptr; - DWORD ve_type; - } VALENTA,*PVALENTA; - - typedef struct value_entW { - LPWSTR ve_valuename; - DWORD ve_valuelen; - DWORD_PTR ve_valueptr; - DWORD ve_type; - } VALENTW,*PVALENTW; - -#ifdef UNICODE - typedef VALENTW VALENT; - typedef PVALENTW PVALENT; -#else - typedef VALENTA VALENT; - typedef PVALENTA PVALENT; -#endif -#endif - -#define WIN31_CLASS NULL - -#ifdef UNICODE -#define RegConnectRegistry RegConnectRegistryW -#define RegConnectRegistryEx RegConnectRegistryExW -#define RegCreateKey RegCreateKeyW -#define RegCreateKeyEx RegCreateKeyExW -#define RegDeleteKey RegDeleteKeyW -#define RegDeleteKeyEx RegDeleteKeyExW -#define RegDeleteValue RegDeleteValueW -#define RegEnumKey RegEnumKeyW -#define RegEnumKeyEx RegEnumKeyExW -#define RegEnumValue RegEnumValueW -#define RegLoadKey RegLoadKeyW -#define RegOpenKey RegOpenKeyW -#define RegOpenKeyEx RegOpenKeyExW -#define RegQueryInfoKey RegQueryInfoKeyW -#define RegQueryValue RegQueryValueW -#define RegQueryMultipleValues RegQueryMultipleValuesW -#define RegQueryValueEx RegQueryValueExW -#define RegReplaceKey RegReplaceKeyW -#define RegRestoreKey RegRestoreKeyW -#define RegSaveKey RegSaveKeyW -#define RegSetValue RegSetValueW -#define RegSetValueEx RegSetValueExW -#define RegUnLoadKey RegUnLoadKeyW -#define RegGetValue RegGetValueW -#define InitiateSystemShutdown InitiateSystemShutdownW -#define AbortSystemShutdown AbortSystemShutdownW -#else -#define RegConnectRegistry RegConnectRegistryA -#define RegConnectRegistryEx RegConnectRegistryExA -#define RegCreateKey RegCreateKeyA -#define RegCreateKeyEx RegCreateKeyExA -#define RegDeleteKey RegDeleteKeyA -#define RegDeleteKeyEx RegDeleteKeyExA -#define RegDeleteValue RegDeleteValueA -#define RegEnumKey RegEnumKeyA -#define RegEnumKeyEx RegEnumKeyExA -#define RegEnumValue RegEnumValueA -#define RegLoadKey RegLoadKeyA -#define RegOpenKey RegOpenKeyA -#define RegOpenKeyEx RegOpenKeyExA -#define RegQueryInfoKey RegQueryInfoKeyA -#define RegQueryValue RegQueryValueA -#define RegQueryMultipleValues RegQueryMultipleValuesA -#define RegQueryValueEx RegQueryValueExA -#define RegReplaceKey RegReplaceKeyA -#define RegRestoreKey RegRestoreKeyA -#define RegSaveKey RegSaveKeyA -#define RegSetValue RegSetValueA -#define RegSetValueEx RegSetValueExA -#define RegUnLoadKey RegUnLoadKeyA -#define RegGetValue RegGetValueA -#define InitiateSystemShutdown InitiateSystemShutdownA -#define AbortSystemShutdown AbortSystemShutdownA -#endif - - WINADVAPI LONG WINAPI RegCloseKey(HKEY hKey); - WINADVAPI LONG WINAPI RegOverridePredefKey(HKEY hKey,HKEY hNewHKey); - WINADVAPI LONG WINAPI RegOpenUserClassesRoot(HANDLE hToken,DWORD dwOptions,REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenCurrentUser(REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegDisablePredefinedCache(); - WINADVAPI LONG WINAPI RegConnectRegistryA(LPCSTR lpMachineName,HKEY hKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegConnectRegistryW(LPCWSTR lpMachineName,HKEY hKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegConnectRegistryExA(LPCSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); - WINADVAPI LONG WINAPI RegConnectRegistryExW(LPCWSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); - WINADVAPI LONG WINAPI RegCreateKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegCreateKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegCreateKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD Reserved,LPSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); - WINADVAPI LONG WINAPI RegCreateKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD Reserved,LPWSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); - WINADVAPI LONG WINAPI RegDeleteKeyA(HKEY hKey,LPCSTR lpSubKey); - WINADVAPI LONG WINAPI RegDeleteKeyW(HKEY hKey,LPCWSTR lpSubKey); - WINADVAPI LONG WINAPI RegDeleteKeyExA(HKEY hKey,LPCSTR lpSubKey,REGSAM samDesired,DWORD Reserved); - WINADVAPI LONG WINAPI RegDeleteKeyExW(HKEY hKey,LPCWSTR lpSubKey,REGSAM samDesired,DWORD Reserved); - WINADVAPI LONG WINAPI RegDisableReflectionKey(HKEY hBase); - WINADVAPI LONG WINAPI RegEnableReflectionKey(HKEY hBase); - WINADVAPI LONG WINAPI RegQueryReflectionKey(HKEY hBase,WINBOOL *bIsReflectionDisabled); - WINADVAPI LONG WINAPI RegDeleteValueA(HKEY hKey,LPCSTR lpValueName); - WINADVAPI LONG WINAPI RegDeleteValueW(HKEY hKey,LPCWSTR lpValueName); - WINADVAPI LONG WINAPI RegEnumKeyA(HKEY hKey,DWORD dwIndex,LPSTR lpName,DWORD cchName); - WINADVAPI LONG WINAPI RegEnumKeyW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,DWORD cchName); - WINADVAPI LONG WINAPI RegEnumKeyExA(HKEY hKey,DWORD dwIndex,LPSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegEnumKeyExW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPWSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegEnumValueA(HKEY hKey,DWORD dwIndex,LPSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegEnumValueW(HKEY hKey,DWORD dwIndex,LPWSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegFlushKey(HKEY hKey); - WINADVAPI LONG WINAPI RegGetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,LPDWORD lpcbSecurityDescriptor); - WINADVAPI LONG WINAPI RegLoadKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpFile); - WINADVAPI LONG WINAPI RegLoadKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpFile); - WINADVAPI LONG WINAPI RegNotifyChangeKeyValue(HKEY hKey,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,HANDLE hEvent,WINBOOL fAsynchronous); - WINADVAPI LONG WINAPI RegOpenKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegQueryInfoKeyA(HKEY hKey,LPSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegQueryInfoKeyW(HKEY hKey,LPWSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegQueryValueA(HKEY hKey,LPCSTR lpSubKey,LPSTR lpData,PLONG lpcbData); - WINADVAPI LONG WINAPI RegQueryValueW(HKEY hKey,LPCWSTR lpSubKey,LPWSTR lpData,PLONG lpcbData); - WINADVAPI LONG WINAPI RegQueryMultipleValuesA(HKEY hKey,PVALENTA val_list,DWORD num_vals,LPSTR lpValueBuf,LPDWORD ldwTotsize); - WINADVAPI LONG WINAPI RegQueryMultipleValuesW(HKEY hKey,PVALENTW val_list,DWORD num_vals,LPWSTR lpValueBuf,LPDWORD ldwTotsize); - WINADVAPI LONG WINAPI RegQueryValueExA(HKEY hKey,LPCSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegQueryValueExW(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegReplaceKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpNewFile,LPCSTR lpOldFile); - WINADVAPI LONG WINAPI RegReplaceKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpNewFile,LPCWSTR lpOldFile); - WINADVAPI LONG WINAPI RegRestoreKeyA(HKEY hKey,LPCSTR lpFile,DWORD dwFlags); - WINADVAPI LONG WINAPI RegRestoreKeyW(HKEY hKey,LPCWSTR lpFile,DWORD dwFlags); - WINADVAPI LONG WINAPI RegSaveKeyA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINADVAPI LONG WINAPI RegSaveKeyW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINADVAPI LONG WINAPI RegSetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI LONG WINAPI RegSetValueA(HKEY hKey,LPCSTR lpSubKey,DWORD dwType,LPCSTR lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegSetValueW(HKEY hKey,LPCWSTR lpSubKey,DWORD dwType,LPCWSTR lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegSetValueExA(HKEY hKey,LPCSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegSetValueExW(HKEY hKey,LPCWSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegUnLoadKeyA(HKEY hKey,LPCSTR lpSubKey); - WINADVAPI LONG WINAPI RegUnLoadKeyW(HKEY hKey,LPCWSTR lpSubKey); - WINADVAPI LONG WINAPI RegGetValueA(HKEY hkey,LPCSTR lpSubKey,LPCSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); - WINADVAPI LONG WINAPI RegGetValueW(HKEY hkey,LPCWSTR lpSubKey,LPCWSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); - WINADVAPI WINBOOL WINAPI AbortSystemShutdownA(LPSTR lpMachineName); - WINADVAPI WINBOOL WINAPI AbortSystemShutdownW(LPWSTR lpMachineName); - -//gr #include - -#define REASON_SWINSTALL SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_INSTALLATION -#define REASON_HWINSTALL SHTDN_REASON_MAJOR_HARDWARE|SHTDN_REASON_MINOR_INSTALLATION -#define REASON_SERVICEHANG SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_HUNG -#define REASON_UNSTABLE SHTDN_REASON_MAJOR_SYSTEM|SHTDN_REASON_MINOR_UNSTABLE -#define REASON_SWHWRECONF SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_RECONFIG -#define REASON_OTHER SHTDN_REASON_MAJOR_OTHER|SHTDN_REASON_MINOR_OTHER -#define REASON_UNKNOWN SHTDN_REASON_UNKNOWN -#define REASON_LEGACY_API SHTDN_REASON_LEGACY_API -#define REASON_PLANNED_FLAG SHTDN_REASON_FLAG_PLANNED - -#define MAX_SHUTDOWN_TIMEOUT (10*365*24*60*60) - -#ifdef UNICODE -#define InitiateSystemShutdownEx InitiateSystemShutdownExW -#define RegSaveKeyEx RegSaveKeyExW -#else -#define InitiateSystemShutdownEx InitiateSystemShutdownExA -#define RegSaveKeyEx RegSaveKeyExA -#endif - - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); - WINADVAPI LONG WINAPI RegSaveKeyExA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); - WINADVAPI LONG WINAPI RegSaveKeyExW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); - WINADVAPI LONG WINAPI Wow64Win32ApiEntry (DWORD dwFuncNumber,DWORD dwFlag,DWORD dwRes); - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINREG_ +#define _WINREG_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#define RRF_RT_REG_NONE 0x00000001 +#define RRF_RT_REG_SZ 0x00000002 +#define RRF_RT_REG_EXPAND_SZ 0x00000004 +#define RRF_RT_REG_BINARY 0x00000008 +#define RRF_RT_REG_DWORD 0x00000010 +#define RRF_RT_REG_MULTI_SZ 0x00000020 +#define RRF_RT_REG_QWORD 0x00000040 + +#define RRF_RT_DWORD (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD) +#define RRF_RT_QWORD (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD) +#define RRF_RT_ANY 0x0000ffff + +#define RRF_NOEXPAND 0x10000000 +#define RRF_ZEROONFAILURE 0x20000000 + + typedef ACCESS_MASK REGSAM; + +#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000)) +#define HKEY_CURRENT_USER ((HKEY) (ULONG_PTR)((LONG)0x80000001)) +#define HKEY_LOCAL_MACHINE ((HKEY) (ULONG_PTR)((LONG)0x80000002)) +#define HKEY_USERS ((HKEY) (ULONG_PTR)((LONG)0x80000003)) +#define HKEY_PERFORMANCE_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000004)) +#define HKEY_PERFORMANCE_TEXT ((HKEY) (ULONG_PTR)((LONG)0x80000050)) +#define HKEY_PERFORMANCE_NLSTEXT ((HKEY) (ULONG_PTR)((LONG)0x80000060)) +#define HKEY_CURRENT_CONFIG ((HKEY) (ULONG_PTR)((LONG)0x80000005)) +#define HKEY_DYN_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000006)) + +#define REG_SECURE_CONNECTION 1 + +#ifndef _PROVIDER_STRUCTS_DEFINED +#define _PROVIDER_STRUCTS_DEFINED + +#define PROVIDER_KEEPS_VALUE_LENGTH 0x1 + struct val_context { + int valuelen; + LPVOID value_context; + LPVOID val_buff_ptr; + }; + + typedef struct val_context *PVALCONTEXT; + + typedef struct pvalueA { + LPSTR pv_valuename; + int pv_valuelen; + LPVOID pv_value_context; + DWORD pv_type; + }PVALUEA,*PPVALUEA; + + typedef struct pvalueW { + LPWSTR pv_valuename; + int pv_valuelen; + LPVOID pv_value_context; + DWORD pv_type; + }PVALUEW,*PPVALUEW; + +#ifdef UNICODE + typedef PVALUEW PVALUE; + typedef PPVALUEW PPVALUE; +#else + typedef PVALUEA PVALUE; + typedef PPVALUEA PPVALUE; +#endif + + typedef DWORD __cdecl QUERYHANDLER(LPVOID keycontext,PVALCONTEXT val_list,DWORD num_vals,LPVOID outputbuffer,DWORD *total_outlen,DWORD input_blen); + + typedef QUERYHANDLER *PQUERYHANDLER; + + typedef struct provider_info { + PQUERYHANDLER pi_R0_1val; + PQUERYHANDLER pi_R0_allvals; + PQUERYHANDLER pi_R3_1val; + PQUERYHANDLER pi_R3_allvals; + DWORD pi_flags; + LPVOID pi_key_context; + } REG_PROVIDER; + + typedef struct provider_info *PPROVIDER; + + typedef struct value_entA { + LPSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; + } VALENTA,*PVALENTA; + + typedef struct value_entW { + LPWSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; + } VALENTW,*PVALENTW; + +#ifdef UNICODE + typedef VALENTW VALENT; + typedef PVALENTW PVALENT; +#else + typedef VALENTA VALENT; + typedef PVALENTA PVALENT; +#endif +#endif + +#define WIN31_CLASS NULL + +#ifdef UNICODE +#define RegConnectRegistry RegConnectRegistryW +#define RegConnectRegistryEx RegConnectRegistryExW +#define RegCreateKey RegCreateKeyW +#define RegCreateKeyEx RegCreateKeyExW +#define RegDeleteKey RegDeleteKeyW +#define RegDeleteKeyEx RegDeleteKeyExW +#define RegDeleteValue RegDeleteValueW +#define RegEnumKey RegEnumKeyW +#define RegEnumKeyEx RegEnumKeyExW +#define RegEnumValue RegEnumValueW +#define RegLoadKey RegLoadKeyW +#define RegOpenKey RegOpenKeyW +#define RegOpenKeyEx RegOpenKeyExW +#define RegQueryInfoKey RegQueryInfoKeyW +#define RegQueryValue RegQueryValueW +#define RegQueryMultipleValues RegQueryMultipleValuesW +#define RegQueryValueEx RegQueryValueExW +#define RegReplaceKey RegReplaceKeyW +#define RegRestoreKey RegRestoreKeyW +#define RegSaveKey RegSaveKeyW +#define RegSetValue RegSetValueW +#define RegSetValueEx RegSetValueExW +#define RegUnLoadKey RegUnLoadKeyW +#define RegGetValue RegGetValueW +#define InitiateSystemShutdown InitiateSystemShutdownW +#define AbortSystemShutdown AbortSystemShutdownW +#else +#define RegConnectRegistry RegConnectRegistryA +#define RegConnectRegistryEx RegConnectRegistryExA +#define RegCreateKey RegCreateKeyA +#define RegCreateKeyEx RegCreateKeyExA +#define RegDeleteKey RegDeleteKeyA +#define RegDeleteKeyEx RegDeleteKeyExA +#define RegDeleteValue RegDeleteValueA +#define RegEnumKey RegEnumKeyA +#define RegEnumKeyEx RegEnumKeyExA +#define RegEnumValue RegEnumValueA +#define RegLoadKey RegLoadKeyA +#define RegOpenKey RegOpenKeyA +#define RegOpenKeyEx RegOpenKeyExA +#define RegQueryInfoKey RegQueryInfoKeyA +#define RegQueryValue RegQueryValueA +#define RegQueryMultipleValues RegQueryMultipleValuesA +#define RegQueryValueEx RegQueryValueExA +#define RegReplaceKey RegReplaceKeyA +#define RegRestoreKey RegRestoreKeyA +#define RegSaveKey RegSaveKeyA +#define RegSetValue RegSetValueA +#define RegSetValueEx RegSetValueExA +#define RegUnLoadKey RegUnLoadKeyA +#define RegGetValue RegGetValueA +#define InitiateSystemShutdown InitiateSystemShutdownA +#define AbortSystemShutdown AbortSystemShutdownA +#endif + + WINADVAPI LONG WINAPI RegCloseKey(HKEY hKey); + WINADVAPI LONG WINAPI RegOverridePredefKey(HKEY hKey,HKEY hNewHKey); + WINADVAPI LONG WINAPI RegOpenUserClassesRoot(HANDLE hToken,DWORD dwOptions,REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenCurrentUser(REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegDisablePredefinedCache(); + WINADVAPI LONG WINAPI RegConnectRegistryA(LPCSTR lpMachineName,HKEY hKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegConnectRegistryW(LPCWSTR lpMachineName,HKEY hKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegConnectRegistryExA(LPCSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); + WINADVAPI LONG WINAPI RegConnectRegistryExW(LPCWSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); + WINADVAPI LONG WINAPI RegCreateKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegCreateKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegCreateKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD Reserved,LPSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); + WINADVAPI LONG WINAPI RegCreateKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD Reserved,LPWSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); + WINADVAPI LONG WINAPI RegDeleteKeyA(HKEY hKey,LPCSTR lpSubKey); + WINADVAPI LONG WINAPI RegDeleteKeyW(HKEY hKey,LPCWSTR lpSubKey); + WINADVAPI LONG WINAPI RegDeleteKeyExA(HKEY hKey,LPCSTR lpSubKey,REGSAM samDesired,DWORD Reserved); + WINADVAPI LONG WINAPI RegDeleteKeyExW(HKEY hKey,LPCWSTR lpSubKey,REGSAM samDesired,DWORD Reserved); + WINADVAPI LONG WINAPI RegDisableReflectionKey(HKEY hBase); + WINADVAPI LONG WINAPI RegEnableReflectionKey(HKEY hBase); + WINADVAPI LONG WINAPI RegQueryReflectionKey(HKEY hBase,WINBOOL *bIsReflectionDisabled); + WINADVAPI LONG WINAPI RegDeleteValueA(HKEY hKey,LPCSTR lpValueName); + WINADVAPI LONG WINAPI RegDeleteValueW(HKEY hKey,LPCWSTR lpValueName); + WINADVAPI LONG WINAPI RegEnumKeyA(HKEY hKey,DWORD dwIndex,LPSTR lpName,DWORD cchName); + WINADVAPI LONG WINAPI RegEnumKeyW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,DWORD cchName); + WINADVAPI LONG WINAPI RegEnumKeyExA(HKEY hKey,DWORD dwIndex,LPSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegEnumKeyExW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPWSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegEnumValueA(HKEY hKey,DWORD dwIndex,LPSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegEnumValueW(HKEY hKey,DWORD dwIndex,LPWSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegFlushKey(HKEY hKey); + WINADVAPI LONG WINAPI RegGetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,LPDWORD lpcbSecurityDescriptor); + WINADVAPI LONG WINAPI RegLoadKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpFile); + WINADVAPI LONG WINAPI RegLoadKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpFile); + WINADVAPI LONG WINAPI RegNotifyChangeKeyValue(HKEY hKey,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,HANDLE hEvent,WINBOOL fAsynchronous); + WINADVAPI LONG WINAPI RegOpenKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegQueryInfoKeyA(HKEY hKey,LPSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegQueryInfoKeyW(HKEY hKey,LPWSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegQueryValueA(HKEY hKey,LPCSTR lpSubKey,LPSTR lpData,PLONG lpcbData); + WINADVAPI LONG WINAPI RegQueryValueW(HKEY hKey,LPCWSTR lpSubKey,LPWSTR lpData,PLONG lpcbData); + WINADVAPI LONG WINAPI RegQueryMultipleValuesA(HKEY hKey,PVALENTA val_list,DWORD num_vals,LPSTR lpValueBuf,LPDWORD ldwTotsize); + WINADVAPI LONG WINAPI RegQueryMultipleValuesW(HKEY hKey,PVALENTW val_list,DWORD num_vals,LPWSTR lpValueBuf,LPDWORD ldwTotsize); + WINADVAPI LONG WINAPI RegQueryValueExA(HKEY hKey,LPCSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegQueryValueExW(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegReplaceKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpNewFile,LPCSTR lpOldFile); + WINADVAPI LONG WINAPI RegReplaceKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpNewFile,LPCWSTR lpOldFile); + WINADVAPI LONG WINAPI RegRestoreKeyA(HKEY hKey,LPCSTR lpFile,DWORD dwFlags); + WINADVAPI LONG WINAPI RegRestoreKeyW(HKEY hKey,LPCWSTR lpFile,DWORD dwFlags); + WINADVAPI LONG WINAPI RegSaveKeyA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINADVAPI LONG WINAPI RegSaveKeyW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINADVAPI LONG WINAPI RegSetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI LONG WINAPI RegSetValueA(HKEY hKey,LPCSTR lpSubKey,DWORD dwType,LPCSTR lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegSetValueW(HKEY hKey,LPCWSTR lpSubKey,DWORD dwType,LPCWSTR lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegSetValueExA(HKEY hKey,LPCSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegSetValueExW(HKEY hKey,LPCWSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegUnLoadKeyA(HKEY hKey,LPCSTR lpSubKey); + WINADVAPI LONG WINAPI RegUnLoadKeyW(HKEY hKey,LPCWSTR lpSubKey); + WINADVAPI LONG WINAPI RegGetValueA(HKEY hkey,LPCSTR lpSubKey,LPCSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); + WINADVAPI LONG WINAPI RegGetValueW(HKEY hkey,LPCWSTR lpSubKey,LPCWSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); + WINADVAPI WINBOOL WINAPI AbortSystemShutdownA(LPSTR lpMachineName); + WINADVAPI WINBOOL WINAPI AbortSystemShutdownW(LPWSTR lpMachineName); + +//gr #include + +#define REASON_SWINSTALL SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_INSTALLATION +#define REASON_HWINSTALL SHTDN_REASON_MAJOR_HARDWARE|SHTDN_REASON_MINOR_INSTALLATION +#define REASON_SERVICEHANG SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_HUNG +#define REASON_UNSTABLE SHTDN_REASON_MAJOR_SYSTEM|SHTDN_REASON_MINOR_UNSTABLE +#define REASON_SWHWRECONF SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_RECONFIG +#define REASON_OTHER SHTDN_REASON_MAJOR_OTHER|SHTDN_REASON_MINOR_OTHER +#define REASON_UNKNOWN SHTDN_REASON_UNKNOWN +#define REASON_LEGACY_API SHTDN_REASON_LEGACY_API +#define REASON_PLANNED_FLAG SHTDN_REASON_FLAG_PLANNED + +#define MAX_SHUTDOWN_TIMEOUT (10*365*24*60*60) + +#ifdef UNICODE +#define InitiateSystemShutdownEx InitiateSystemShutdownExW +#define RegSaveKeyEx RegSaveKeyExW +#else +#define InitiateSystemShutdownEx InitiateSystemShutdownExA +#define RegSaveKeyEx RegSaveKeyExA +#endif + + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); + WINADVAPI LONG WINAPI RegSaveKeyExA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); + WINADVAPI LONG WINAPI RegSaveKeyExW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); + WINADVAPI LONG WINAPI Wow64Win32ApiEntry (DWORD dwFuncNumber,DWORD dwFlag,DWORD dwRes); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/winsock2.h b/tcc/include/winapi/winsock2.h index 365ace64..e3d9eaa9 100644 --- a/tcc/include/winapi/winsock2.h +++ b/tcc/include/winapi/winsock2.h @@ -1,1474 +1,1474 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _WINSOCK2API_ -#define _WINSOCK2API_ - -#ifndef INCL_WINSOCK_API_TYPEDEFS -#define INCL_WINSOCK_API_TYPEDEFS 0 -#endif - -#ifndef _INC_WINDOWS -#include -#endif - -#ifndef MAKEWORD -#define MAKEWORD(low,high) ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8)) -#endif - -#ifndef WINSOCK_VERSION -#define WINSOCK_VERSION MAKEWORD(2,2) -#endif - -#ifndef WINSOCK_API_LINKAGE -#ifdef DECLSPEC_IMPORT -#define WINSOCK_API_LINKAGE DECLSPEC_IMPORT -#else -#define WINSOCK_API_LINKAGE -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _WINSOCK_SOCKET_DEFINED -#define _WINSOCK_SOCKET_DEFINED - typedef unsigned char u_char; - typedef unsigned short u_short; - typedef unsigned int u_int; - typedef unsigned long u_long; - __MINGW_EXTENSION typedef unsigned __int64 u_int64; - typedef INT_PTR SOCKET; -#endif - -#ifndef FD_SETSIZE -#define FD_SETSIZE 64 -#endif - - typedef struct fd_set { - u_int fd_count; - SOCKET fd_array[FD_SETSIZE]; - } fd_set; - - extern int WINAPI __WSAFDIsSet(SOCKET,fd_set *); - -#define FD_CLR(fd,set) do { u_int __i; for(__i = 0;__i < ((fd_set *)(set))->fd_count;__i++) { if (((fd_set *)(set))->fd_array[__i]==fd) { while (__i < ((fd_set *)(set))->fd_count-1) { ((fd_set *)(set))->fd_array[__i] = ((fd_set *)(set))->fd_array[__i+1]; __i++; } ((fd_set *)(set))->fd_count--; break; } } } while(0) -#define FD_SET(fd,set) do { u_int __i; for(__i = 0;__i < ((fd_set *)(set))->fd_count;__i++) { if (((fd_set *)(set))->fd_array[__i]==(fd)) { break; } } if (__i==((fd_set *)(set))->fd_count) { if (((fd_set *)(set))->fd_count < FD_SETSIZE) { ((fd_set *)(set))->fd_array[__i] = (fd); ((fd_set *)(set))->fd_count++; } } } while(0) -#define FD_ZERO(set) (((fd_set *)(set))->fd_count=0) -#define FD_ISSET(fd,set) __WSAFDIsSet((SOCKET)(fd),(fd_set *)(set)) - -#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ -#define _TIMEVAL_DEFINED - struct timeval { - long tv_sec; - long tv_usec; - }; - -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif /* _TIMEVAL_DEFINED */ - -#define IOCPARM_MASK 0x7f -#define IOC_VOID 0x20000000 -#define IOC_OUT 0x40000000 -#define IOC_IN 0x80000000 -#define IOC_INOUT (IOC_IN|IOC_OUT) - -#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) -#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) -#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) - -#define FIONREAD _IOR('f',127,u_long) -#define FIONBIO _IOW('f',126,u_long) -#define FIOASYNC _IOW('f',125,u_long) - -#define SIOCSHIWAT _IOW('s',0,u_long) -#define SIOCGHIWAT _IOR('s',1,u_long) -#define SIOCSLOWAT _IOW('s',2,u_long) -#define SIOCGLOWAT _IOR('s',3,u_long) -#define SIOCATMARK _IOR('s',7,u_long) - -#define h_addr h_addr_list[0] - - struct hostent { - char *h_name; - char **h_aliases; - short h_addrtype; - short h_length; - char **h_addr_list; - }; - - struct netent { - char *n_name; - char **n_aliases; - short n_addrtype; - u_long n_net; - }; - - struct servent { - char *s_name; - char **s_aliases; -#ifdef _WIN64 - char *s_proto; - short s_port; -#else - short s_port; - char *s_proto; -#endif - }; - - struct protoent { - char *p_name; - char **p_aliases; - short p_proto; - }; - -#define IPPROTO_IP 0 -#define IPPROTO_HOPOPTS 0 -#define IPPROTO_ICMP 1 -#define IPPROTO_IGMP 2 -#define IPPROTO_GGP 3 -#define IPPROTO_IPV4 4 -#define IPPROTO_TCP 6 -#define IPPROTO_PUP 12 -#define IPPROTO_UDP 17 -#define IPPROTO_IDP 22 -#define IPPROTO_IPV6 41 -#define IPPROTO_ROUTING 43 -#define IPPROTO_FRAGMENT 44 -#define IPPROTO_ESP 50 -#define IPPROTO_AH 51 -#define IPPROTO_ICMPV6 58 -#define IPPROTO_NONE 59 -#define IPPROTO_DSTOPTS 60 -#define IPPROTO_ND 77 -#define IPPROTO_ICLFXBM 78 - -#define IPPROTO_RAW 255 -#define IPPROTO_MAX 256 - -#define IPPORT_ECHO 7 -#define IPPORT_DISCARD 9 -#define IPPORT_SYSTAT 11 -#define IPPORT_DAYTIME 13 -#define IPPORT_NETSTAT 15 -#define IPPORT_FTP 21 -#define IPPORT_TELNET 23 -#define IPPORT_SMTP 25 -#define IPPORT_TIMESERVER 37 -#define IPPORT_NAMESERVER 42 -#define IPPORT_WHOIS 43 -#define IPPORT_MTP 57 - -#define IPPORT_TFTP 69 -#define IPPORT_RJE 77 -#define IPPORT_FINGER 79 -#define IPPORT_TTYLINK 87 -#define IPPORT_SUPDUP 95 - -#define IPPORT_EXECSERVER 512 -#define IPPORT_LOGINSERVER 513 -#define IPPORT_CMDSERVER 514 -#define IPPORT_EFSSERVER 520 - -#define IPPORT_BIFFUDP 512 -#define IPPORT_WHOSERVER 513 -#define IPPORT_ROUTESERVER 520 - -#define IPPORT_RESERVED 1024 - -#define IMPLINK_IP 155 -#define IMPLINK_LOWEXPER 156 -#define IMPLINK_HIGHEXPER 158 - -#ifndef s_addr - - struct in_addr { - union { - struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; - struct { u_short s_w1,s_w2; } S_un_w; - u_long S_addr; - } S_un; - }; - -#define s_addr S_un.S_addr -#define s_host S_un.S_un_b.s_b2 -#define s_net S_un.S_un_b.s_b1 -#define s_imp S_un.S_un_w.s_w2 -#define s_impno S_un.S_un_b.s_b4 -#define s_lh S_un.S_un_b.s_b3 - -#endif - -#define IN_CLASSA(i) (((long)(i) & 0x80000000)==0) -#define IN_CLASSA_NET 0xff000000 -#define IN_CLASSA_NSHIFT 24 -#define IN_CLASSA_HOST 0x00ffffff -#define IN_CLASSA_MAX 128 - -#define IN_CLASSB(i) (((long)(i) & 0xc0000000)==0x80000000) -#define IN_CLASSB_NET 0xffff0000 -#define IN_CLASSB_NSHIFT 16 -#define IN_CLASSB_HOST 0x0000ffff -#define IN_CLASSB_MAX 65536 - -#define IN_CLASSC(i) (((long)(i) & 0xe0000000)==0xc0000000) -#define IN_CLASSC_NET 0xffffff00 -#define IN_CLASSC_NSHIFT 8 -#define IN_CLASSC_HOST 0x000000ff - -#define IN_CLASSD(i) (((long)(i) & 0xf0000000)==0xe0000000) -#define IN_CLASSD_NET 0xf0000000 -#define IN_CLASSD_NSHIFT 28 -#define IN_CLASSD_HOST 0x0fffffff -#define IN_MULTICAST(i) IN_CLASSD(i) - -#define INADDR_ANY (u_long)0x00000000 -#define INADDR_LOOPBACK 0x7f000001 -#define INADDR_BROADCAST (u_long)0xffffffff -#define INADDR_NONE 0xffffffff - -#define ADDR_ANY INADDR_ANY - - struct sockaddr_in { - short sin_family; - u_short sin_port; - struct in_addr sin_addr; - char sin_zero[8]; - }; - -#define WSADESCRIPTION_LEN 256 -#define WSASYS_STATUS_LEN 128 - - typedef struct WSAData { - WORD wVersion; - WORD wHighVersion; -#ifdef _WIN64 - unsigned short iMaxSockets; - unsigned short iMaxUdpDg; - char *lpVendorInfo; - char szDescription[WSADESCRIPTION_LEN+1]; - char szSystemStatus[WSASYS_STATUS_LEN+1]; -#else - char szDescription[WSADESCRIPTION_LEN+1]; - char szSystemStatus[WSASYS_STATUS_LEN+1]; - unsigned short iMaxSockets; - unsigned short iMaxUdpDg; - char *lpVendorInfo; -#endif - } WSADATA,*LPWSADATA; - -#define INVALID_SOCKET (SOCKET)(~0) -#define SOCKET_ERROR (-1) - -#define FROM_PROTOCOL_INFO (-1) - -#define SOCK_STREAM 1 -#define SOCK_DGRAM 2 -#define SOCK_RAW 3 -#define SOCK_RDM 4 -#define SOCK_SEQPACKET 5 - -#define SO_DEBUG 0x0001 -#define SO_ACCEPTCONN 0x0002 -#define SO_REUSEADDR 0x0004 -#define SO_KEEPALIVE 0x0008 -#define SO_DONTROUTE 0x0010 -#define SO_BROADCAST 0x0020 -#define SO_USELOOPBACK 0x0040 -#define SO_LINGER 0x0080 -#define SO_OOBINLINE 0x0100 - -#define SO_DONTLINGER (int)(~SO_LINGER) -#define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR)) - -#define SO_SNDBUF 0x1001 -#define SO_RCVBUF 0x1002 -#define SO_SNDLOWAT 0x1003 -#define SO_RCVLOWAT 0x1004 -#define SO_SNDTIMEO 0x1005 -#define SO_RCVTIMEO 0x1006 -#define SO_ERROR 0x1007 -#define SO_TYPE 0x1008 - -#define SO_GROUP_ID 0x2001 -#define SO_GROUP_PRIORITY 0x2002 -#define SO_MAX_MSG_SIZE 0x2003 -#define SO_PROTOCOL_INFOA 0x2004 -#define SO_PROTOCOL_INFOW 0x2005 -#ifdef UNICODE -#define SO_PROTOCOL_INFO SO_PROTOCOL_INFOW -#else -#define SO_PROTOCOL_INFO SO_PROTOCOL_INFOA -#endif -#define PVD_CONFIG 0x3001 -#define SO_CONDITIONAL_ACCEPT 0x3002 - -#define TCP_NODELAY 0x0001 - -#define AF_UNSPEC 0 - -#define AF_UNIX 1 -#define AF_INET 2 -#define AF_IMPLINK 3 -#define AF_PUP 4 -#define AF_CHAOS 5 -#define AF_NS 6 -#define AF_IPX AF_NS -#define AF_ISO 7 -#define AF_OSI AF_ISO -#define AF_ECMA 8 -#define AF_DATAKIT 9 -#define AF_CCITT 10 -#define AF_SNA 11 -#define AF_DECnet 12 -#define AF_DLI 13 -#define AF_LAT 14 -#define AF_HYLINK 15 -#define AF_APPLETALK 16 -#define AF_NETBIOS 17 -#define AF_VOICEVIEW 18 -#define AF_FIREFOX 19 -#define AF_UNKNOWN1 20 -#define AF_BAN 21 -#define AF_ATM 22 -#define AF_INET6 23 -#define AF_CLUSTER 24 -#define AF_12844 25 -#define AF_IRDA 26 -#define AF_NETDES 28 -#define AF_TCNPROCESS 29 -#define AF_TCNMESSAGE 30 -#define AF_ICLFXBM 31 - -#define AF_MAX 32 - - struct sockaddr { - u_short sa_family; - char sa_data[14]; - }; - -#define _SS_MAXSIZE 128 -#define _SS_ALIGNSIZE (8) - -#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (short)) -#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (short) + _SS_PAD1SIZE + _SS_ALIGNSIZE)) - - struct sockaddr_storage { - short ss_family; - char __ss_pad1[_SS_PAD1SIZE]; - - __MINGW_EXTENSION __int64 __ss_align; - char __ss_pad2[_SS_PAD2SIZE]; - - }; - - struct sockproto { - u_short sp_family; - u_short sp_protocol; - }; - -#define PF_UNSPEC AF_UNSPEC -#define PF_UNIX AF_UNIX -#define PF_INET AF_INET -#define PF_IMPLINK AF_IMPLINK -#define PF_PUP AF_PUP -#define PF_CHAOS AF_CHAOS -#define PF_NS AF_NS -#define PF_IPX AF_IPX -#define PF_ISO AF_ISO -#define PF_OSI AF_OSI -#define PF_ECMA AF_ECMA -#define PF_DATAKIT AF_DATAKIT -#define PF_CCITT AF_CCITT -#define PF_SNA AF_SNA -#define PF_DECnet AF_DECnet -#define PF_DLI AF_DLI -#define PF_LAT AF_LAT -#define PF_HYLINK AF_HYLINK -#define PF_APPLETALK AF_APPLETALK -#define PF_VOICEVIEW AF_VOICEVIEW -#define PF_FIREFOX AF_FIREFOX -#define PF_UNKNOWN1 AF_UNKNOWN1 -#define PF_BAN AF_BAN -#define PF_ATM AF_ATM -#define PF_INET6 AF_INET6 - -#define PF_MAX AF_MAX - - struct linger { - u_short l_onoff; - u_short l_linger; - }; - -#define SOL_SOCKET 0xffff - -#define SOMAXCONN 0x7fffffff - -#define MSG_OOB 0x1 -#define MSG_PEEK 0x2 -#define MSG_DONTROUTE 0x4 -#define MSG_WAITALL 0x8 - -#define MSG_PARTIAL 0x8000 - -#define MSG_INTERRUPT 0x10 - -#define MSG_MAXIOVLEN 16 - -#define MAXGETHOSTSTRUCT 1024 - -#define FD_READ_BIT 0 -#define FD_READ (1 << FD_READ_BIT) - -#define FD_WRITE_BIT 1 -#define FD_WRITE (1 << FD_WRITE_BIT) - -#define FD_OOB_BIT 2 -#define FD_OOB (1 << FD_OOB_BIT) - -#define FD_ACCEPT_BIT 3 -#define FD_ACCEPT (1 << FD_ACCEPT_BIT) - -#define FD_CONNECT_BIT 4 -#define FD_CONNECT (1 << FD_CONNECT_BIT) - -#define FD_CLOSE_BIT 5 -#define FD_CLOSE (1 << FD_CLOSE_BIT) - -#define FD_QOS_BIT 6 -#define FD_QOS (1 << FD_QOS_BIT) - -#define FD_GROUP_QOS_BIT 7 -#define FD_GROUP_QOS (1 << FD_GROUP_QOS_BIT) - -#define FD_ROUTING_INTERFACE_CHANGE_BIT 8 -#define FD_ROUTING_INTERFACE_CHANGE (1 << FD_ROUTING_INTERFACE_CHANGE_BIT) - -#define FD_ADDRESS_LIST_CHANGE_BIT 9 -#define FD_ADDRESS_LIST_CHANGE (1 << FD_ADDRESS_LIST_CHANGE_BIT) - -#define FD_MAX_EVENTS 10 -#define FD_ALL_EVENTS ((1 << FD_MAX_EVENTS) - 1) - -#ifndef WSABASEERR - -#define WSABASEERR 10000 - -#define WSAEINTR (WSABASEERR+4) -#define WSAEBADF (WSABASEERR+9) -#define WSAEACCES (WSABASEERR+13) -#define WSAEFAULT (WSABASEERR+14) -#define WSAEINVAL (WSABASEERR+22) -#define WSAEMFILE (WSABASEERR+24) - -#define WSAEWOULDBLOCK (WSABASEERR+35) -#define WSAEINPROGRESS (WSABASEERR+36) -#define WSAEALREADY (WSABASEERR+37) -#define WSAENOTSOCK (WSABASEERR+38) -#define WSAEDESTADDRREQ (WSABASEERR+39) -#define WSAEMSGSIZE (WSABASEERR+40) -#define WSAEPROTOTYPE (WSABASEERR+41) -#define WSAENOPROTOOPT (WSABASEERR+42) -#define WSAEPROTONOSUPPORT (WSABASEERR+43) -#define WSAESOCKTNOSUPPORT (WSABASEERR+44) -#define WSAEOPNOTSUPP (WSABASEERR+45) -#define WSAEPFNOSUPPORT (WSABASEERR+46) -#define WSAEAFNOSUPPORT (WSABASEERR+47) -#define WSAEADDRINUSE (WSABASEERR+48) -#define WSAEADDRNOTAVAIL (WSABASEERR+49) -#define WSAENETDOWN (WSABASEERR+50) -#define WSAENETUNREACH (WSABASEERR+51) -#define WSAENETRESET (WSABASEERR+52) -#define WSAECONNABORTED (WSABASEERR+53) -#define WSAECONNRESET (WSABASEERR+54) -#define WSAENOBUFS (WSABASEERR+55) -#define WSAEISCONN (WSABASEERR+56) -#define WSAENOTCONN (WSABASEERR+57) -#define WSAESHUTDOWN (WSABASEERR+58) -#define WSAETOOMANYREFS (WSABASEERR+59) -#define WSAETIMEDOUT (WSABASEERR+60) -#define WSAECONNREFUSED (WSABASEERR+61) -#define WSAELOOP (WSABASEERR+62) -#define WSAENAMETOOLONG (WSABASEERR+63) -#define WSAEHOSTDOWN (WSABASEERR+64) -#define WSAEHOSTUNREACH (WSABASEERR+65) -#define WSAENOTEMPTY (WSABASEERR+66) -#define WSAEPROCLIM (WSABASEERR+67) -#define WSAEUSERS (WSABASEERR+68) -#define WSAEDQUOT (WSABASEERR+69) -#define WSAESTALE (WSABASEERR+70) -#define WSAEREMOTE (WSABASEERR+71) - -#define WSASYSNOTREADY (WSABASEERR+91) -#define WSAVERNOTSUPPORTED (WSABASEERR+92) -#define WSANOTINITIALISED (WSABASEERR+93) -#define WSAEDISCON (WSABASEERR+101) -#ifndef WSAHOST_NOT_FOUND -#define WSAHOST_NOT_FOUND (WSABASEERR+1001) -#endif -#ifndef WSATRY_AGAIN -#define WSATRY_AGAIN (WSABASEERR+1002) -#endif -#ifndef WSANO_RECOVERY -#define WSANO_RECOVERY (WSABASEERR+1003) -#endif -#ifndef WSANO_DATA -#define WSANO_DATA (WSABASEERR+1004) -#endif - -#define WSAENOMORE (WSABASEERR+102) -#define WSAECANCELLED (WSABASEERR+103) -#define WSAEINVALIDPROCTABLE (WSABASEERR+104) -#define WSAEINVALIDPROVIDER (WSABASEERR+105) -#define WSAEPROVIDERFAILEDINIT (WSABASEERR+106) -#define WSASYSCALLFAILURE (WSABASEERR+107) -#define WSASERVICE_NOT_FOUND (WSABASEERR+108) -#define WSATYPE_NOT_FOUND (WSABASEERR+109) -#define WSA_E_NO_MORE (WSABASEERR+110) -#define WSA_E_CANCELLED (WSABASEERR+111) -#define WSAEREFUSED (WSABASEERR+112) -#ifndef WSA_QOS_RECEIVERS -#define WSA_QOS_RECEIVERS (WSABASEERR + 1005) -#endif -#ifndef WSA_QOS_SENDERS -#define WSA_QOS_SENDERS (WSABASEERR + 1006) -#endif -#ifndef WSA_QOS_NO_SENDERS -#define WSA_QOS_NO_SENDERS (WSABASEERR + 1007) -#define WSA_QOS_NO_RECEIVERS (WSABASEERR + 1008) -#define WSA_QOS_REQUEST_CONFIRMED (WSABASEERR + 1009) -#define WSA_QOS_ADMISSION_FAILURE (WSABASEERR + 1010) -#define WSA_QOS_POLICY_FAILURE (WSABASEERR + 1011) -#define WSA_QOS_BAD_STYLE (WSABASEERR + 1012) -#define WSA_QOS_BAD_OBJECT (WSABASEERR + 1013) -#define WSA_QOS_TRAFFIC_CTRL_ERROR (WSABASEERR + 1014) -#define WSA_QOS_GENERIC_ERROR (WSABASEERR + 1015) -#define WSA_QOS_ESERVICETYPE (WSABASEERR + 1016) -#define WSA_QOS_EFLOWSPEC (WSABASEERR + 1017) -#define WSA_QOS_EPROVSPECBUF (WSABASEERR + 1018) -#endif -#ifndef WSA_QOS_EFILTERSTYLE -#define WSA_QOS_EFILTERSTYLE (WSABASEERR + 1019) -#endif -#ifndef WSA_QOS_EFILTERTYPE -#define WSA_QOS_EFILTERTYPE (WSABASEERR + 1020) -#endif -#ifndef WSA_QOS_EFILTERCOUNT -#define WSA_QOS_EFILTERCOUNT (WSABASEERR + 1021) -#endif -#ifndef WSA_QOS_EOBJLENGTH -#define WSA_QOS_EOBJLENGTH (WSABASEERR + 1022) -#endif -#ifndef WSA_QOS_EFLOWCOUNT -#define WSA_QOS_EFLOWCOUNT (WSABASEERR + 1023) -#endif -#ifndef WSA_QOS_EUNKNOWNPSOBJ -#define WSA_QOS_EUNKNOWNPSOBJ (WSABASEERR + 1024) -#endif -#ifndef WSA_QOS_EPOLICYOBJ -#define WSA_QOS_EPOLICYOBJ (WSABASEERR + 1025) -#endif -#ifndef WSA_QOS_EFLOWDESC -#define WSA_QOS_EFLOWDESC (WSABASEERR + 1026) -#endif -#ifndef WSA_QOS_EPSFLOWSPEC -#define WSA_QOS_EPSFLOWSPEC (WSABASEERR + 1027) -#endif -#ifndef WSA_QOS_EPSFILTERSPEC -#define WSA_QOS_EPSFILTERSPEC (WSABASEERR + 1028) -#endif -#ifndef WSA_QOS_ESDMODEOBJ -#define WSA_QOS_ESDMODEOBJ (WSABASEERR + 1029) -#endif -#ifndef WSA_QOS_ESHAPERATEOBJ -#define WSA_QOS_ESHAPERATEOBJ (WSABASEERR + 1030) -#endif -#ifndef WSA_QOS_RESERVED_PETYPE -#define WSA_QOS_RESERVED_PETYPE (WSABASEERR + 1031) -#endif -#endif // WSABASEERR - -#define h_errno WSAGetLastError() -#define HOST_NOT_FOUND WSAHOST_NOT_FOUND -#define TRY_AGAIN WSATRY_AGAIN -#define NO_RECOVERY WSANO_RECOVERY -#define NO_DATA WSANO_DATA - -#define WSANO_ADDRESS WSANO_DATA -#define NO_ADDRESS WSANO_ADDRESS - -#if 0 -#define EWOULDBLOCK WSAEWOULDBLOCK -#define EINPROGRESS WSAEINPROGRESS -#define EALREADY WSAEALREADY -#define ENOTSOCK WSAENOTSOCK -#define EDESTADDRREQ WSAEDESTADDRREQ -#define EMSGSIZE WSAEMSGSIZE -#define EPROTOTYPE WSAEPROTOTYPE -#define ENOPROTOOPT WSAENOPROTOOPT -#define EPROTONOSUPPORT WSAEPROTONOSUPPORT -#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT -#define EOPNOTSUPP WSAEOPNOTSUPP -#define EPFNOSUPPORT WSAEPFNOSUPPORT -#define EAFNOSUPPORT WSAEAFNOSUPPORT -#define EADDRINUSE WSAEADDRINUSE -#define EADDRNOTAVAIL WSAEADDRNOTAVAIL -#define ENETDOWN WSAENETDOWN -#define ENETUNREACH WSAENETUNREACH -#define ENETRESET WSAENETRESET -#define ECONNABORTED WSAECONNABORTED -#define ECONNRESET WSAECONNRESET -#define ENOBUFS WSAENOBUFS -#define EISCONN WSAEISCONN -#define ENOTCONN WSAENOTCONN -#define ESHUTDOWN WSAESHUTDOWN -#define ETOOMANYREFS WSAETOOMANYREFS -#define ETIMEDOUT WSAETIMEDOUT -#define ECONNREFUSED WSAECONNREFUSED -#define ELOOP WSAELOOP -#define ENAMETOOLONG WSAENAMETOOLONG -#define EHOSTDOWN WSAEHOSTDOWN -#define EHOSTUNREACH WSAEHOSTUNREACH -#define ENOTEMPTY WSAENOTEMPTY -#define EPROCLIM WSAEPROCLIM -#define EUSERS WSAEUSERS -#define EDQUOT WSAEDQUOT -#define ESTALE WSAESTALE -#define EREMOTE WSAEREMOTE -#endif - -#define WSAAPI WINAPI -#define WSAEVENT HANDLE -#define LPWSAEVENT LPHANDLE -#define WSAOVERLAPPED OVERLAPPED - typedef struct _OVERLAPPED *LPWSAOVERLAPPED; - -#define WSA_IO_PENDING (ERROR_IO_PENDING) -#define WSA_IO_INCOMPLETE (ERROR_IO_INCOMPLETE) -#define WSA_INVALID_HANDLE (ERROR_INVALID_HANDLE) -#define WSA_INVALID_PARAMETER (ERROR_INVALID_PARAMETER) -#define WSA_NOT_ENOUGH_MEMORY (ERROR_NOT_ENOUGH_MEMORY) -#define WSA_OPERATION_ABORTED (ERROR_OPERATION_ABORTED) - -#define WSA_INVALID_EVENT ((WSAEVENT)NULL) -#define WSA_MAXIMUM_WAIT_EVENTS (MAXIMUM_WAIT_OBJECTS) -#define WSA_WAIT_FAILED (WAIT_FAILED) -#define WSA_WAIT_EVENT_0 (WAIT_OBJECT_0) -#define WSA_WAIT_IO_COMPLETION (WAIT_IO_COMPLETION) -#define WSA_WAIT_TIMEOUT (WAIT_TIMEOUT) -#define WSA_INFINITE (INFINITE) - - typedef struct _WSABUF { - u_long len; - char *buf; - } WSABUF,*LPWSABUF; - -#include - - typedef struct _QualityOfService { - FLOWSPEC SendingFlowspec; - FLOWSPEC ReceivingFlowspec; - WSABUF ProviderSpecific; - } QOS,*LPQOS; - -#define CF_ACCEPT 0x0000 -#define CF_REJECT 0x0001 -#define CF_DEFER 0x0002 - -#define SD_RECEIVE 0x00 -#define SD_SEND 0x01 -#define SD_BOTH 0x02 - - typedef unsigned int GROUP; - -#define SG_UNCONSTRAINED_GROUP 0x01 -#define SG_CONSTRAINED_GROUP 0x02 - - typedef struct _WSANETWORKEVENTS { - long lNetworkEvents; - int iErrorCode[FD_MAX_EVENTS]; - } WSANETWORKEVENTS,*LPWSANETWORKEVENTS; - -#ifndef GUID_DEFINED -#include -#endif - -#define MAX_PROTOCOL_CHAIN 7 - -#define BASE_PROTOCOL 1 -#define LAYERED_PROTOCOL 0 - - typedef struct _WSAPROTOCOLCHAIN { - int ChainLen; - - DWORD ChainEntries[MAX_PROTOCOL_CHAIN]; - } WSAPROTOCOLCHAIN,*LPWSAPROTOCOLCHAIN; - -#define WSAPROTOCOL_LEN 255 - - typedef struct _WSAPROTOCOL_INFOA { - DWORD dwServiceFlags1; - DWORD dwServiceFlags2; - DWORD dwServiceFlags3; - DWORD dwServiceFlags4; - DWORD dwProviderFlags; - GUID ProviderId; - DWORD dwCatalogEntryId; - WSAPROTOCOLCHAIN ProtocolChain; - int iVersion; - int iAddressFamily; - int iMaxSockAddr; - int iMinSockAddr; - int iSocketType; - int iProtocol; - int iProtocolMaxOffset; - int iNetworkByteOrder; - int iSecurityScheme; - DWORD dwMessageSize; - DWORD dwProviderReserved; - CHAR szProtocol[WSAPROTOCOL_LEN+1]; - } WSAPROTOCOL_INFOA,*LPWSAPROTOCOL_INFOA; - typedef struct _WSAPROTOCOL_INFOW { - DWORD dwServiceFlags1; - DWORD dwServiceFlags2; - DWORD dwServiceFlags3; - DWORD dwServiceFlags4; - DWORD dwProviderFlags; - GUID ProviderId; - DWORD dwCatalogEntryId; - WSAPROTOCOLCHAIN ProtocolChain; - int iVersion; - int iAddressFamily; - int iMaxSockAddr; - int iMinSockAddr; - int iSocketType; - int iProtocol; - int iProtocolMaxOffset; - int iNetworkByteOrder; - int iSecurityScheme; - DWORD dwMessageSize; - DWORD dwProviderReserved; - WCHAR szProtocol[WSAPROTOCOL_LEN+1]; - } WSAPROTOCOL_INFOW,*LPWSAPROTOCOL_INFOW; -#ifdef UNICODE - typedef WSAPROTOCOL_INFOW WSAPROTOCOL_INFO; - typedef LPWSAPROTOCOL_INFOW LPWSAPROTOCOL_INFO; -#else - typedef WSAPROTOCOL_INFOA WSAPROTOCOL_INFO; - typedef LPWSAPROTOCOL_INFOA LPWSAPROTOCOL_INFO; -#endif - -#define PFL_MULTIPLE_PROTO_ENTRIES 0x00000001 -#define PFL_RECOMMENDED_PROTO_ENTRY 0x00000002 -#define PFL_HIDDEN 0x00000004 -#define PFL_MATCHES_PROTOCOL_ZERO 0x00000008 - -#define XP1_CONNECTIONLESS 0x00000001 -#define XP1_GUARANTEED_DELIVERY 0x00000002 -#define XP1_GUARANTEED_ORDER 0x00000004 -#define XP1_MESSAGE_ORIENTED 0x00000008 -#define XP1_PSEUDO_STREAM 0x00000010 -#define XP1_GRACEFUL_CLOSE 0x00000020 -#define XP1_EXPEDITED_DATA 0x00000040 -#define XP1_CONNECT_DATA 0x00000080 -#define XP1_DISCONNECT_DATA 0x00000100 -#define XP1_SUPPORT_BROADCAST 0x00000200 -#define XP1_SUPPORT_MULTIPOINT 0x00000400 -#define XP1_MULTIPOINT_CONTROL_PLANE 0x00000800 -#define XP1_MULTIPOINT_DATA_PLANE 0x00001000 -#define XP1_QOS_SUPPORTED 0x00002000 -#define XP1_INTERRUPT 0x00004000 -#define XP1_UNI_SEND 0x00008000 -#define XP1_UNI_RECV 0x00010000 -#define XP1_IFS_HANDLES 0x00020000 -#define XP1_PARTIAL_MESSAGE 0x00040000 - -#define BIGENDIAN 0x0000 -#define LITTLEENDIAN 0x0001 - -#define SECURITY_PROTOCOL_NONE 0x0000 - -#define JL_SENDER_ONLY 0x01 -#define JL_RECEIVER_ONLY 0x02 -#define JL_BOTH 0x04 - -#define WSA_FLAG_OVERLAPPED 0x01 -#define WSA_FLAG_MULTIPOINT_C_ROOT 0x02 -#define WSA_FLAG_MULTIPOINT_C_LEAF 0x04 -#define WSA_FLAG_MULTIPOINT_D_ROOT 0x08 -#define WSA_FLAG_MULTIPOINT_D_LEAF 0x10 - -#define IOC_UNIX 0x00000000 -#define IOC_WS2 0x08000000 -#define IOC_PROTOCOL 0x10000000 -#define IOC_VENDOR 0x18000000 - -#define _WSAIO(x,y) (IOC_VOID|(x)|(y)) -#define _WSAIOR(x,y) (IOC_OUT|(x)|(y)) -#define _WSAIOW(x,y) (IOC_IN|(x)|(y)) -#define _WSAIORW(x,y) (IOC_INOUT|(x)|(y)) - -#define SIO_ASSOCIATE_HANDLE _WSAIOW(IOC_WS2,1) -#define SIO_ENABLE_CIRCULAR_QUEUEING _WSAIO(IOC_WS2,2) -#define SIO_FIND_ROUTE _WSAIOR(IOC_WS2,3) -#define SIO_FLUSH _WSAIO(IOC_WS2,4) -#define SIO_GET_BROADCAST_ADDRESS _WSAIOR(IOC_WS2,5) -#define SIO_GET_EXTENSION_FUNCTION_POINTER _WSAIORW(IOC_WS2,6) -#define SIO_GET_QOS _WSAIORW(IOC_WS2,7) -#define SIO_GET_GROUP_QOS _WSAIORW(IOC_WS2,8) -#define SIO_MULTIPOINT_LOOPBACK _WSAIOW(IOC_WS2,9) -#define SIO_MULTICAST_SCOPE _WSAIOW(IOC_WS2,10) -#define SIO_SET_QOS _WSAIOW(IOC_WS2,11) -#define SIO_SET_GROUP_QOS _WSAIOW(IOC_WS2,12) -#define SIO_TRANSLATE_HANDLE _WSAIORW(IOC_WS2,13) -#define SIO_ROUTING_INTERFACE_QUERY _WSAIORW(IOC_WS2,20) -#define SIO_ROUTING_INTERFACE_CHANGE _WSAIOW(IOC_WS2,21) -#define SIO_ADDRESS_LIST_QUERY _WSAIOR(IOC_WS2,22) -#define SIO_ADDRESS_LIST_CHANGE _WSAIO(IOC_WS2,23) -#define SIO_QUERY_TARGET_PNP_HANDLE _WSAIOR(IOC_WS2,24) -#define SIO_ADDRESS_LIST_SORT _WSAIORW(IOC_WS2,25) - - typedef int (CALLBACK *LPCONDITIONPROC)(LPWSABUF lpCallerId,LPWSABUF lpCallerData,LPQOS lpSQOS,LPQOS lpGQOS,LPWSABUF lpCalleeId,LPWSABUF lpCalleeData,GROUP *g,DWORD_PTR dwCallbackData); - typedef void (CALLBACK *LPWSAOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwError,DWORD cbTransferred,LPWSAOVERLAPPED lpOverlapped,DWORD dwFlags); - -#define SIO_NSP_NOTIFY_CHANGE _WSAIOW(IOC_WS2,25) - - typedef enum _WSACOMPLETIONTYPE { - NSP_NOTIFY_IMMEDIATELY = 0,NSP_NOTIFY_HWND,NSP_NOTIFY_EVENT,NSP_NOTIFY_PORT,NSP_NOTIFY_APC - } WSACOMPLETIONTYPE,*PWSACOMPLETIONTYPE,*LPWSACOMPLETIONTYPE; - - typedef struct _WSACOMPLETION { - WSACOMPLETIONTYPE Type; - union { - struct { - HWND hWnd; - UINT uMsg; - WPARAM context; - } WindowMessage; - struct { - LPWSAOVERLAPPED lpOverlapped; - } Event; - struct { - LPWSAOVERLAPPED lpOverlapped; - LPWSAOVERLAPPED_COMPLETION_ROUTINE lpfnCompletionProc; - } Apc; - struct { - LPWSAOVERLAPPED lpOverlapped; - HANDLE hPort; - ULONG_PTR Key; - } Port; - } Parameters; - } WSACOMPLETION,*PWSACOMPLETION,*LPWSACOMPLETION; - -#define TH_NETDEV 0x00000001 -#define TH_TAPI 0x00000002 - - typedef struct sockaddr SOCKADDR; - typedef struct sockaddr *PSOCKADDR; - typedef struct sockaddr *LPSOCKADDR; - typedef struct sockaddr_storage SOCKADDR_STORAGE; - typedef struct sockaddr_storage *PSOCKADDR_STORAGE; - typedef struct sockaddr_storage *LPSOCKADDR_STORAGE; - -#ifndef _tagBLOB_DEFINED -#define _tagBLOB_DEFINED -#define _BLOB_DEFINED -#define _LPBLOB_DEFINED - typedef struct _BLOB { - ULONG cbSize; - BYTE *pBlobData; - } BLOB,*LPBLOB; -#endif - -#define SERVICE_MULTIPLE (0x00000001) - -#define NS_ALL (0) - -#define NS_SAP (1) -#define NS_NDS (2) -#define NS_PEER_BROWSE (3) -#define NS_SLP (5) -#define NS_DHCP (6) - -#define NS_TCPIP_LOCAL (10) -#define NS_TCPIP_HOSTS (11) -#define NS_DNS (12) -#define NS_NETBT (13) -#define NS_WINS (14) -#define NS_NLA (15) - -#define NS_NBP (20) - -#define NS_MS (30) -#define NS_STDA (31) -#define NS_NTDS (32) - -#define NS_X500 (40) -#define NS_NIS (41) -#define NS_NISPLUS (42) - -#define NS_WRQ (50) - -#define NS_NETDES (60) - -#define RES_UNUSED_1 (0x00000001) -#define RES_FLUSH_CACHE (0x00000002) -#ifndef RES_SERVICE -#define RES_SERVICE (0x00000004) -#endif - -#define SERVICE_TYPE_VALUE_IPXPORTA "IpxSocket" -#define SERVICE_TYPE_VALUE_IPXPORTW L"IpxSocket" -#define SERVICE_TYPE_VALUE_SAPIDA "SapId" -#define SERVICE_TYPE_VALUE_SAPIDW L"SapId" - -#define SERVICE_TYPE_VALUE_TCPPORTA "TcpPort" -#define SERVICE_TYPE_VALUE_TCPPORTW L"TcpPort" - -#define SERVICE_TYPE_VALUE_UDPPORTA "UdpPort" -#define SERVICE_TYPE_VALUE_UDPPORTW L"UdpPort" - -#define SERVICE_TYPE_VALUE_OBJECTIDA "ObjectId" -#define SERVICE_TYPE_VALUE_OBJECTIDW L"ObjectId" - -#ifdef UNICODE - -#define SERVICE_TYPE_VALUE_SAPID SERVICE_TYPE_VALUE_SAPIDW -#define SERVICE_TYPE_VALUE_TCPPORT SERVICE_TYPE_VALUE_TCPPORTW -#define SERVICE_TYPE_VALUE_UDPPORT SERVICE_TYPE_VALUE_UDPPORTW -#define SERVICE_TYPE_VALUE_OBJECTID SERVICE_TYPE_VALUE_OBJECTIDW -#else - -#define SERVICE_TYPE_VALUE_SAPID SERVICE_TYPE_VALUE_SAPIDA -#define SERVICE_TYPE_VALUE_TCPPORT SERVICE_TYPE_VALUE_TCPPORTA -#define SERVICE_TYPE_VALUE_UDPPORT SERVICE_TYPE_VALUE_UDPPORTA -#define SERVICE_TYPE_VALUE_OBJECTID SERVICE_TYPE_VALUE_OBJECTIDA -#endif - -#ifndef __CSADDR_DEFINED__ -#define __CSADDR_DEFINED__ - - typedef struct _SOCKET_ADDRESS { - LPSOCKADDR lpSockaddr; - INT iSockaddrLength; - } SOCKET_ADDRESS,*PSOCKET_ADDRESS,*LPSOCKET_ADDRESS; - - typedef struct _CSADDR_INFO { - SOCKET_ADDRESS LocalAddr; - SOCKET_ADDRESS RemoteAddr; - INT iSocketType; - INT iProtocol; - } CSADDR_INFO,*PCSADDR_INFO,*LPCSADDR_INFO; -#endif - - typedef struct _SOCKET_ADDRESS_LIST { - INT iAddressCount; - SOCKET_ADDRESS Address[1]; - } SOCKET_ADDRESS_LIST,*LPSOCKET_ADDRESS_LIST; - - typedef struct _AFPROTOCOLS { - INT iAddressFamily; - INT iProtocol; - } AFPROTOCOLS,*PAFPROTOCOLS,*LPAFPROTOCOLS; - - typedef enum _WSAEcomparator { - COMP_EQUAL = 0,COMP_NOTLESS - } WSAECOMPARATOR,*PWSAECOMPARATOR,*LPWSAECOMPARATOR; - - typedef struct _WSAVersion { - DWORD dwVersion; - WSAECOMPARATOR ecHow; - } WSAVERSION,*PWSAVERSION,*LPWSAVERSION; - - typedef struct _WSAQuerySetA { - DWORD dwSize; - LPSTR lpszServiceInstanceName; - LPGUID lpServiceClassId; - LPWSAVERSION lpVersion; - LPSTR lpszComment; - DWORD dwNameSpace; - LPGUID lpNSProviderId; - LPSTR lpszContext; - DWORD dwNumberOfProtocols; - LPAFPROTOCOLS lpafpProtocols; - LPSTR lpszQueryString; - DWORD dwNumberOfCsAddrs; - LPCSADDR_INFO lpcsaBuffer; - DWORD dwOutputFlags; - LPBLOB lpBlob; - } WSAQUERYSETA,*PWSAQUERYSETA,*LPWSAQUERYSETA; - - typedef struct _WSAQuerySetW { - DWORD dwSize; - LPWSTR lpszServiceInstanceName; - LPGUID lpServiceClassId; - LPWSAVERSION lpVersion; - LPWSTR lpszComment; - DWORD dwNameSpace; - LPGUID lpNSProviderId; - LPWSTR lpszContext; - DWORD dwNumberOfProtocols; - LPAFPROTOCOLS lpafpProtocols; - LPWSTR lpszQueryString; - DWORD dwNumberOfCsAddrs; - LPCSADDR_INFO lpcsaBuffer; - DWORD dwOutputFlags; - LPBLOB lpBlob; - } WSAQUERYSETW,*PWSAQUERYSETW,*LPWSAQUERYSETW; - -#ifdef UNICODE - typedef WSAQUERYSETW WSAQUERYSET; - typedef PWSAQUERYSETW PWSAQUERYSET; - typedef LPWSAQUERYSETW LPWSAQUERYSET; -#else - typedef WSAQUERYSETA WSAQUERYSET; - typedef PWSAQUERYSETA PWSAQUERYSET; - typedef LPWSAQUERYSETA LPWSAQUERYSET; -#endif - -#define LUP_DEEP 0x0001 -#define LUP_CONTAINERS 0x0002 -#define LUP_NOCONTAINERS 0x0004 -#define LUP_NEAREST 0x0008 -#define LUP_RETURN_NAME 0x0010 -#define LUP_RETURN_TYPE 0x0020 -#define LUP_RETURN_VERSION 0x0040 -#define LUP_RETURN_COMMENT 0x0080 -#define LUP_RETURN_ADDR 0x0100 -#define LUP_RETURN_BLOB 0x0200 -#define LUP_RETURN_ALIASES 0x0400 -#define LUP_RETURN_QUERY_STRING 0x0800 -#define LUP_RETURN_ALL 0x0FF0 -#define LUP_RES_SERVICE 0x8000 - -#define LUP_FLUSHCACHE 0x1000 -#define LUP_FLUSHPREVIOUS 0x2000 - -#define RESULT_IS_ALIAS 0x0001 -#define RESULT_IS_ADDED 0x0010 -#define RESULT_IS_CHANGED 0x0020 -#define RESULT_IS_DELETED 0x0040 - - typedef enum _WSAESETSERVICEOP { - RNRSERVICE_REGISTER=0,RNRSERVICE_DEREGISTER,RNRSERVICE_DELETE - } WSAESETSERVICEOP,*PWSAESETSERVICEOP,*LPWSAESETSERVICEOP; - - typedef struct _WSANSClassInfoA { - LPSTR lpszName; - DWORD dwNameSpace; - DWORD dwValueType; - DWORD dwValueSize; - LPVOID lpValue; - } WSANSCLASSINFOA,*PWSANSCLASSINFOA,*LPWSANSCLASSINFOA; - - typedef struct _WSANSClassInfoW { - LPWSTR lpszName; - DWORD dwNameSpace; - DWORD dwValueType; - DWORD dwValueSize; - LPVOID lpValue; - } WSANSCLASSINFOW,*PWSANSCLASSINFOW,*LPWSANSCLASSINFOW; - -#ifdef UNICODE - typedef WSANSCLASSINFOW WSANSCLASSINFO; - typedef PWSANSCLASSINFOW PWSANSCLASSINFO; - typedef LPWSANSCLASSINFOW LPWSANSCLASSINFO; -#else - typedef WSANSCLASSINFOA WSANSCLASSINFO; - typedef PWSANSCLASSINFOA PWSANSCLASSINFO; - typedef LPWSANSCLASSINFOA LPWSANSCLASSINFO; -#endif - - typedef struct _WSAServiceClassInfoA { - LPGUID lpServiceClassId; - LPSTR lpszServiceClassName; - DWORD dwCount; - LPWSANSCLASSINFOA lpClassInfos; - } WSASERVICECLASSINFOA,*PWSASERVICECLASSINFOA,*LPWSASERVICECLASSINFOA; - - typedef struct _WSAServiceClassInfoW { - LPGUID lpServiceClassId; - LPWSTR lpszServiceClassName; - DWORD dwCount; - LPWSANSCLASSINFOW lpClassInfos; - } WSASERVICECLASSINFOW,*PWSASERVICECLASSINFOW,*LPWSASERVICECLASSINFOW; - -#ifdef UNICODE - typedef WSASERVICECLASSINFOW WSASERVICECLASSINFO; - typedef PWSASERVICECLASSINFOW PWSASERVICECLASSINFO; - typedef LPWSASERVICECLASSINFOW LPWSASERVICECLASSINFO; -#else - typedef WSASERVICECLASSINFOA WSASERVICECLASSINFO; - typedef PWSASERVICECLASSINFOA PWSASERVICECLASSINFO; - typedef LPWSASERVICECLASSINFOA LPWSASERVICECLASSINFO; -#endif - - typedef struct _WSANAMESPACE_INFOA { - GUID NSProviderId; - DWORD dwNameSpace; - WINBOOL fActive; - DWORD dwVersion; - LPSTR lpszIdentifier; - } WSANAMESPACE_INFOA,*PWSANAMESPACE_INFOA,*LPWSANAMESPACE_INFOA; - - typedef struct _WSANAMESPACE_INFOW { - GUID NSProviderId; - DWORD dwNameSpace; - WINBOOL fActive; - DWORD dwVersion; - LPWSTR lpszIdentifier; - } WSANAMESPACE_INFOW,*PWSANAMESPACE_INFOW,*LPWSANAMESPACE_INFOW; - -#ifdef UNICODE - typedef WSANAMESPACE_INFOW WSANAMESPACE_INFO; - typedef PWSANAMESPACE_INFOW PWSANAMESPACE_INFO; - typedef LPWSANAMESPACE_INFOW LPWSANAMESPACE_INFO; -#else - typedef WSANAMESPACE_INFOA WSANAMESPACE_INFO; - typedef PWSANAMESPACE_INFOA PWSANAMESPACE_INFO; - typedef LPWSANAMESPACE_INFOA LPWSANAMESPACE_INFO; -#endif - -#if INCL_WINSOCK_API_TYPEDEFS -#ifdef UNICODE -#define LPFN_WSADUPLICATESOCKET LPFN_WSADUPLICATESOCKETW -#define LPFN_WSAENUMPROTOCOLS LPFN_WSAENUMPROTOCOLSW -#define LPFN_WSASOCKET LPFN_WSASOCKETW -#define LPFN_WSAADDRESSTOSTRING LPFN_WSAADDRESSTOSTRINGW -#define LPFN_WSASTRINGTOADDRESS LPFN_WSASTRINGTOADDRESSW -#define LPFN_WSALOOKUPSERVICEBEGIN LPFN_WSALOOKUPSERVICEBEGINW -#define LPFN_WSALOOKUPSERVICENEXT LPFN_WSALOOKUPSERVICENEXTW -#define LPFN_WSAINSTALLSERVICECLASS LPFN_WSAINSTALLSERVICECLASSW -#define LPFN_WSAGETSERVICECLASSINFO LPFN_WSAGETSERVICECLASSINFOW -#define LPFN_WSAENUMNAMESPACEPROVIDERS LPFN_WSAENUMNAMESPACEPROVIDERSW -#define LPFN_WSAGETSERVICECLASSNAMEBYCLASSID LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDW -#define LPFN_WSASETSERVICE LPFN_WSASETSERVICEW -#else -#define LPFN_WSADUPLICATESOCKET LPFN_WSADUPLICATESOCKETA -#define LPFN_WSAENUMPROTOCOLS LPFN_WSAENUMPROTOCOLSA -#define LPFN_WSASOCKET LPFN_WSASOCKETA -#define LPFN_WSAADDRESSTOSTRING LPFN_WSAADDRESSTOSTRINGA -#define LPFN_WSASTRINGTOADDRESS LPFN_WSASTRINGTOADDRESSA -#define LPFN_WSALOOKUPSERVICEBEGIN LPFN_WSALOOKUPSERVICEBEGINA -#define LPFN_WSALOOKUPSERVICENEXT LPFN_WSALOOKUPSERVICENEXTA -#define LPFN_WSAINSTALLSERVICECLASS LPFN_WSAINSTALLSERVICECLASSA -#define LPFN_WSAGETSERVICECLASSINFO LPFN_WSAGETSERVICECLASSINFOA -#define LPFN_WSAENUMNAMESPACEPROVIDERS LPFN_WSAENUMNAMESPACEPROVIDERSA -#define LPFN_WSAGETSERVICECLASSNAMEBYCLASSID LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDA -#define LPFN_WSASETSERVICE LPFN_WSASETSERVICEA -#endif - - typedef SOCKET (WSAAPI *LPFN_ACCEPT)(SOCKET s,struct sockaddr *addr,int *addrlen); - typedef int (WSAAPI *LPFN_BIND)(SOCKET s,const struct sockaddr *name,int namelen); - typedef int (WSAAPI *LPFN_CLOSESOCKET)(SOCKET s); - typedef int (WSAAPI *LPFN_CONNECT)(SOCKET s,const struct sockaddr *name,int namelen); - typedef int (WSAAPI *LPFN_IOCTLSOCKET)(SOCKET s,long cmd,u_long *argp); - typedef int (WSAAPI *LPFN_GETPEERNAME)(SOCKET s,struct sockaddr *name,int *namelen); - typedef int (WSAAPI *LPFN_GETSOCKNAME)(SOCKET s,struct sockaddr *name,int *namelen); - typedef int (WSAAPI *LPFN_GETSOCKOPT)(SOCKET s,int level,int optname,char *optval,int *optlen); - typedef u_long (WSAAPI *LPFN_HTONL)(u_long hostlong); - typedef u_short (WSAAPI *LPFN_HTONS)(u_short hostshort); - typedef unsigned long (WSAAPI *LPFN_INET_ADDR)(const char *cp); - typedef char *(WSAAPI *LPFN_INET_NTOA)(struct in_addr in); - typedef int (WSAAPI *LPFN_LISTEN)(SOCKET s,int backlog); - typedef u_long (WSAAPI *LPFN_NTOHL)(u_long netlong); - typedef u_short (WSAAPI *LPFN_NTOHS)(u_short netshort); - typedef int (WSAAPI *LPFN_RECV)(SOCKET s,char *buf,int len,int flags); - typedef int (WSAAPI *LPFN_RECVFROM)(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen); - typedef int (WSAAPI *LPFN_SELECT)(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout); - typedef int (WSAAPI *LPFN_SEND)(SOCKET s,const char *buf,int len,int flags); - typedef int (WSAAPI *LPFN_SENDTO)(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen); - typedef int (WSAAPI *LPFN_SETSOCKOPT)(SOCKET s,int level,int optname,const char *optval,int optlen); - typedef int (WSAAPI *LPFN_SHUTDOWN)(SOCKET s,int how); - typedef SOCKET (WSAAPI *LPFN_SOCKET)(int af,int type,int protocol); - typedef struct hostent *(WSAAPI *LPFN_GETHOSTBYADDR)(const char *addr,int len,int type); - typedef struct hostent *(WSAAPI *LPFN_GETHOSTBYNAME)(const char *name); - typedef int (WSAAPI *LPFN_GETHOSTNAME)(char *name,int namelen); - typedef struct servent *(WSAAPI *LPFN_GETSERVBYPORT)(int port,const char *proto); - typedef struct servent *(WSAAPI *LPFN_GETSERVBYNAME)(const char *name,const char *proto); - typedef struct protoent *(WSAAPI *LPFN_GETPROTOBYNUMBER)(int number); - typedef struct protoent *(WSAAPI *LPFN_GETPROTOBYNAME)(const char *name); - typedef int (WSAAPI *LPFN_WSASTARTUP)(WORD wVersionRequested,LPWSADATA lpWSAData); - typedef int (WSAAPI *LPFN_WSACLEANUP)(void); - typedef void (WSAAPI *LPFN_WSASETLASTERROR)(int iError); - typedef int (WSAAPI *LPFN_WSAGETLASTERROR)(void); - typedef WINBOOL (WSAAPI *LPFN_WSAISBLOCKING)(void); - typedef int (WSAAPI *LPFN_WSAUNHOOKBLOCKINGHOOK)(void); - typedef FARPROC (WSAAPI *LPFN_WSASETBLOCKINGHOOK)(FARPROC lpBlockFunc); - typedef int (WSAAPI *LPFN_WSACANCELBLOCKINGCALL)(void); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETSERVBYNAME)(HWND hWnd,u_int wMsg,const char *name,const char *proto,char *buf,int buflen); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETSERVBYPORT)(HWND hWnd,u_int wMsg,int port,const char *proto,char *buf,int buflen); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETPROTOBYNAME)(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETPROTOBYNUMBER)(HWND hWnd,u_int wMsg,int number,char *buf,int buflen); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETHOSTBYNAME)(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETHOSTBYADDR)(HWND hWnd,u_int wMsg,const char *addr,int len,int type,char *buf,int buflen); - typedef int (WSAAPI *LPFN_WSACANCELASYNCREQUEST)(HANDLE hAsyncTaskHandle); - typedef int (WSAAPI *LPFN_WSAASYNCSELECT)(SOCKET s,HWND hWnd,u_int wMsg,long lEvent); - typedef SOCKET (WSAAPI *LPFN_WSAACCEPT)(SOCKET s,struct sockaddr *addr,LPINT addrlen,LPCONDITIONPROC lpfnCondition,DWORD_PTR dwCallbackData); - typedef WINBOOL (WSAAPI *LPFN_WSACLOSEEVENT)(WSAEVENT hEvent); - typedef int (WSAAPI *LPFN_WSACONNECT)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS); - typedef WSAEVENT (WSAAPI *LPFN_WSACREATEEVENT)(void); - typedef int (WSAAPI *LPFN_WSADUPLICATESOCKETA)(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOA lpProtocolInfo); - typedef int (WSAAPI *LPFN_WSADUPLICATESOCKETW)(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOW lpProtocolInfo); - typedef int (WSAAPI *LPFN_WSAENUMNETWORKEVENTS)(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents); - typedef int (WSAAPI *LPFN_WSAENUMPROTOCOLSA)(LPINT lpiProtocols,LPWSAPROTOCOL_INFOA lpProtocolBuffer,LPDWORD lpdwBufferLength); - typedef int (WSAAPI *LPFN_WSAENUMPROTOCOLSW)(LPINT lpiProtocols,LPWSAPROTOCOL_INFOW lpProtocolBuffer,LPDWORD lpdwBufferLength); - typedef int (WSAAPI *LPFN_WSAEVENTSELECT)(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents); - typedef WINBOOL (WSAAPI *LPFN_WSAGETOVERLAPPEDRESULT)(SOCKET s,LPWSAOVERLAPPED lpOverlapped,LPDWORD lpcbTransfer,WINBOOL fWait,LPDWORD lpdwFlags); - typedef WINBOOL (WSAAPI *LPFN_WSAGETQOSBYNAME)(SOCKET s,LPWSABUF lpQOSName,LPQOS lpQOS); - typedef int (WSAAPI *LPFN_WSAHTONL)(SOCKET s,u_long hostlong,u_long *lpnetlong); - typedef int (WSAAPI *LPFN_WSAHTONS)(SOCKET s,u_short hostshort,u_short *lpnetshort); - typedef int (WSAAPI *LPFN_WSAIOCTL)(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - typedef SOCKET (WSAAPI *LPFN_WSAJOINLEAF)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,DWORD dwFlags); - typedef int (WSAAPI *LPFN_WSANTOHL)(SOCKET s,u_long netlong,u_long *lphostlong); - typedef int (WSAAPI *LPFN_WSANTOHS)(SOCKET s,u_short netshort,u_short *lphostshort); - typedef int (WSAAPI *LPFN_WSARECV)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - typedef int (WSAAPI *LPFN_WSARECVDISCONNECT)(SOCKET s,LPWSABUF lpInboundDisconnectData); - typedef int (WSAAPI *LPFN_WSARECVFROM)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,struct sockaddr *lpFrom,LPINT lpFromlen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - typedef WINBOOL (WSAAPI *LPFN_WSARESETEVENT)(WSAEVENT hEvent); - typedef int (WSAAPI *LPFN_WSASEND)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - typedef int (WSAAPI *LPFN_WSASENDDISCONNECT)(SOCKET s,LPWSABUF lpOutboundDisconnectData); - typedef int (WSAAPI *LPFN_WSASENDTO)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,const struct sockaddr *lpTo,int iTolen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - typedef WINBOOL (WSAAPI *LPFN_WSASETEVENT)(WSAEVENT hEvent); - typedef SOCKET (WSAAPI *LPFN_WSASOCKETA)(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags); - typedef SOCKET (WSAAPI *LPFN_WSASOCKETW)(int af,int type,int protocol,LPWSAPROTOCOL_INFOW lpProtocolInfo,GROUP g,DWORD dwFlags); - typedef DWORD (WSAAPI *LPFN_WSAWAITFORMULTIPLEEVENTS)(DWORD cEvents,const WSAEVENT *lphEvents,WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable); - typedef INT (WSAAPI *LPFN_WSAADDRESSTOSTRINGA)(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSTR lpszAddressString,LPDWORD lpdwAddressStringLength); - typedef INT (WSAAPI *LPFN_WSAADDRESSTOSTRINGW)(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPWSTR lpszAddressString,LPDWORD lpdwAddressStringLength); - typedef INT (WSAAPI *LPFN_WSASTRINGTOADDRESSA)(LPSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); - typedef INT (WSAAPI *LPFN_WSASTRINGTOADDRESSW)(LPWSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); - typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEBEGINA)(LPWSAQUERYSETA lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); - typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEBEGINW)(LPWSAQUERYSETW lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); - typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICENEXTA)(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETA lpqsResults); - typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICENEXTW)(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETW lpqsResults); - typedef INT (WSAAPI *LPFN_WSANSPIOCTL)(HANDLE hLookup,DWORD dwControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSACOMPLETION lpCompletion); - typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEEND)(HANDLE hLookup); - typedef INT (WSAAPI *LPFN_WSAINSTALLSERVICECLASSA)(LPWSASERVICECLASSINFOA lpServiceClassInfo); - typedef INT (WSAAPI *LPFN_WSAINSTALLSERVICECLASSW)(LPWSASERVICECLASSINFOW lpServiceClassInfo); - typedef INT (WSAAPI *LPFN_WSAREMOVESERVICECLASS)(LPGUID lpServiceClassId); - typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSINFOA)(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOA lpServiceClassInfo); - typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSINFOW)(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOW lpServiceClassInfo); - typedef INT (WSAAPI *LPFN_WSAENUMNAMESPACEPROVIDERSA)(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOA lpnspBuffer); - typedef INT (WSAAPI *LPFN_WSAENUMNAMESPACEPROVIDERSW)(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOW lpnspBuffer); - typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDA)(LPGUID lpServiceClassId,LPSTR lpszServiceClassName,LPDWORD lpdwBufferLength); - typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDW)(LPGUID lpServiceClassId,LPWSTR lpszServiceClassName,LPDWORD lpdwBufferLength); - typedef INT (WSAAPI *LPFN_WSASETSERVICEA)(LPWSAQUERYSETA lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); - typedef INT (WSAAPI *LPFN_WSASETSERVICEW)(LPWSAQUERYSETW lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); - typedef INT (WSAAPI *LPFN_WSAPROVIDERCONFIGCHANGE)(LPHANDLE lpNotificationHandle,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); -#endif - -#ifdef UNICODE -#define WSADuplicateSocket WSADuplicateSocketW -#define WSAEnumProtocols WSAEnumProtocolsW -#define WSAAddressToString WSAAddressToStringW -#define WSASocket WSASocketW -#define WSAStringToAddress WSAStringToAddressW -#define WSALookupServiceBegin WSALookupServiceBeginW -#define WSALookupServiceNext WSALookupServiceNextW -#define WSAInstallServiceClass WSAInstallServiceClassW -#define WSAGetServiceClassInfo WSAGetServiceClassInfoW -#define WSAEnumNameSpaceProviders WSAEnumNameSpaceProvidersW -#define WSAGetServiceClassNameByClassId WSAGetServiceClassNameByClassIdW -#define WSASetService WSASetServiceW -#else -#define WSADuplicateSocket WSADuplicateSocketA -#define WSAEnumProtocols WSAEnumProtocolsA -#define WSASocket WSASocketA -#define WSAAddressToString WSAAddressToStringA -#define WSAStringToAddress WSAStringToAddressA -#define WSALookupServiceBegin WSALookupServiceBeginA -#define WSALookupServiceNext WSALookupServiceNextA -#define WSAInstallServiceClass WSAInstallServiceClassA -#define WSAGetServiceClassInfo WSAGetServiceClassInfoA -#define WSAEnumNameSpaceProviders WSAEnumNameSpaceProvidersA -#define WSAGetServiceClassNameByClassId WSAGetServiceClassNameByClassIdA -#define WSASetService WSASetServiceA -#endif - - WINSOCK_API_LINKAGE SOCKET WSAAPI accept(SOCKET s,struct sockaddr *addr,int *addrlen); - WINSOCK_API_LINKAGE int WSAAPI bind(SOCKET s,const struct sockaddr *name,int namelen); - WINSOCK_API_LINKAGE int WSAAPI closesocket(SOCKET s); - WINSOCK_API_LINKAGE int WSAAPI connect(SOCKET s,const struct sockaddr *name,int namelen); - WINSOCK_API_LINKAGE int WSAAPI ioctlsocket(SOCKET s,long cmd,u_long *argp); - WINSOCK_API_LINKAGE int WSAAPI getpeername(SOCKET s,struct sockaddr *name,int *namelen); - WINSOCK_API_LINKAGE int WSAAPI getsockname(SOCKET s,struct sockaddr *name,int *namelen); - WINSOCK_API_LINKAGE int WSAAPI getsockopt(SOCKET s,int level,int optname,char *optval,int *optlen); - WINSOCK_API_LINKAGE u_long WSAAPI htonl(u_long hostlong); - WINSOCK_API_LINKAGE u_short WSAAPI htons(u_short hostshort); - WINSOCK_API_LINKAGE unsigned long WSAAPI inet_addr(const char *cp); - WINSOCK_API_LINKAGE char *WSAAPI inet_ntoa(struct in_addr in); - WINSOCK_API_LINKAGE int WSAAPI listen(SOCKET s,int backlog); - WINSOCK_API_LINKAGE u_long WSAAPI ntohl(u_long netlong); - WINSOCK_API_LINKAGE u_short WSAAPI ntohs(u_short netshort); - WINSOCK_API_LINKAGE int WSAAPI recv(SOCKET s,char *buf,int len,int flags); - WINSOCK_API_LINKAGE int WSAAPI recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen); - WINSOCK_API_LINKAGE int WSAAPI select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout); - WINSOCK_API_LINKAGE int WSAAPI send(SOCKET s,const char *buf,int len,int flags); - WINSOCK_API_LINKAGE int WSAAPI sendto(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen); - WINSOCK_API_LINKAGE int WSAAPI setsockopt(SOCKET s,int level,int optname,const char *optval,int optlen); - WINSOCK_API_LINKAGE int WSAAPI shutdown(SOCKET s,int how); - WINSOCK_API_LINKAGE SOCKET WSAAPI socket(int af,int type,int protocol); - WINSOCK_API_LINKAGE struct hostent *WSAAPI gethostbyaddr(const char *addr,int len,int type); - WINSOCK_API_LINKAGE struct hostent *WSAAPI gethostbyname(const char *name); - WINSOCK_API_LINKAGE int WSAAPI gethostname(char *name,int namelen); - WINSOCK_API_LINKAGE struct servent *WSAAPI getservbyport(int port,const char *proto); - WINSOCK_API_LINKAGE struct servent *WSAAPI getservbyname(const char *name,const char *proto); - WINSOCK_API_LINKAGE struct protoent *WSAAPI getprotobynumber(int number); - WINSOCK_API_LINKAGE struct protoent *WSAAPI getprotobyname(const char *name); - WINSOCK_API_LINKAGE int WSAAPI WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData); - WINSOCK_API_LINKAGE int WSAAPI WSACleanup(void); - WINSOCK_API_LINKAGE void WSAAPI WSASetLastError(int iError); - WINSOCK_API_LINKAGE int WSAAPI WSAGetLastError(void); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAIsBlocking(void); - WINSOCK_API_LINKAGE int WSAAPI WSAUnhookBlockingHook(void); - WINSOCK_API_LINKAGE FARPROC WSAAPI WSASetBlockingHook(FARPROC lpBlockFunc); - WINSOCK_API_LINKAGE int WSAAPI WSACancelBlockingCall(void); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetServByName(HWND hWnd,u_int wMsg,const char *name,const char *proto,char *buf,int buflen); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetServByPort(HWND hWnd,u_int wMsg,int port,const char *proto,char *buf,int buflen); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetProtoByName(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetProtoByNumber(HWND hWnd,u_int wMsg,int number,char *buf,int buflen); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetHostByName(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetHostByAddr(HWND hWnd,u_int wMsg,const char *addr,int len,int type,char *buf,int buflen); - WINSOCK_API_LINKAGE int WSAAPI WSACancelAsyncRequest(HANDLE hAsyncTaskHandle); - WINSOCK_API_LINKAGE int WSAAPI WSAAsyncSelect(SOCKET s,HWND hWnd,u_int wMsg,long lEvent); - WINSOCK_API_LINKAGE SOCKET WSAAPI WSAAccept(SOCKET s,struct sockaddr *addr,LPINT addrlen,LPCONDITIONPROC lpfnCondition,DWORD_PTR dwCallbackData); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSACloseEvent(WSAEVENT hEvent); - WINSOCK_API_LINKAGE int WSAAPI WSAConnect(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS); - WINSOCK_API_LINKAGE WSAEVENT WSAAPI WSACreateEvent(void); - WINSOCK_API_LINKAGE int WSAAPI WSADuplicateSocketA(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOA lpProtocolInfo); - WINSOCK_API_LINKAGE int WSAAPI WSADuplicateSocketW(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOW lpProtocolInfo); - WINSOCK_API_LINKAGE int WSAAPI WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents); - WINSOCK_API_LINKAGE int WSAAPI WSAEnumProtocolsA(LPINT lpiProtocols,LPWSAPROTOCOL_INFOA lpProtocolBuffer,LPDWORD lpdwBufferLength); - WINSOCK_API_LINKAGE int WSAAPI WSAEnumProtocolsW(LPINT lpiProtocols,LPWSAPROTOCOL_INFOW lpProtocolBuffer,LPDWORD lpdwBufferLength); - WINSOCK_API_LINKAGE int WSAAPI WSAEventSelect(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAGetOverlappedResult(SOCKET s,LPWSAOVERLAPPED lpOverlapped,LPDWORD lpcbTransfer,WINBOOL fWait,LPDWORD lpdwFlags); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAGetQOSByName(SOCKET s,LPWSABUF lpQOSName,LPQOS lpQOS); - WINSOCK_API_LINKAGE int WSAAPI WSAHtonl(SOCKET s,u_long hostlong,u_long *lpnetlong); - WINSOCK_API_LINKAGE int WSAAPI WSAHtons(SOCKET s,u_short hostshort,u_short *lpnetshort); - WINSOCK_API_LINKAGE int WSAAPI WSAIoctl(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINSOCK_API_LINKAGE SOCKET WSAAPI WSAJoinLeaf(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,DWORD dwFlags); - WINSOCK_API_LINKAGE int WSAAPI WSANtohl(SOCKET s,u_long netlong,u_long *lphostlong); - WINSOCK_API_LINKAGE int WSAAPI WSANtohs(SOCKET s,u_short netshort,u_short *lphostshort); - WINSOCK_API_LINKAGE int WSAAPI WSARecv(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINSOCK_API_LINKAGE int WSAAPI WSARecvDisconnect(SOCKET s,LPWSABUF lpInboundDisconnectData); - WINSOCK_API_LINKAGE int WSAAPI WSARecvFrom(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,struct sockaddr *lpFrom,LPINT lpFromlen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAResetEvent(WSAEVENT hEvent); - WINSOCK_API_LINKAGE int WSAAPI WSASend(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINSOCK_API_LINKAGE int WSAAPI WSASendDisconnect(SOCKET s,LPWSABUF lpOutboundDisconnectData); - WINSOCK_API_LINKAGE int WSAAPI WSASendTo(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,const struct sockaddr *lpTo,int iTolen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSASetEvent(WSAEVENT hEvent); - WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketA(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags); - WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketW(int af,int type,int protocol,LPWSAPROTOCOL_INFOW lpProtocolInfo,GROUP g,DWORD dwFlags); - WINSOCK_API_LINKAGE DWORD WSAAPI WSAWaitForMultipleEvents(DWORD cEvents,const WSAEVENT *lphEvents,WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable); - WINSOCK_API_LINKAGE INT WSAAPI WSAAddressToStringA(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSTR lpszAddressString,LPDWORD lpdwAddressStringLength); - WINSOCK_API_LINKAGE INT WSAAPI WSAAddressToStringW(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPWSTR lpszAddressString,LPDWORD lpdwAddressStringLength); - WINSOCK_API_LINKAGE INT WSAAPI WSAStringToAddressA(LPSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); - WINSOCK_API_LINKAGE INT WSAAPI WSAStringToAddressW(LPWSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); - WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceBeginA(LPWSAQUERYSETA lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); - WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceBeginW(LPWSAQUERYSETW lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); - WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceNextA(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETA lpqsResults); - WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceNextW(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETW lpqsResults); - WINSOCK_API_LINKAGE INT WSAAPI WSANSPIoctl(HANDLE hLookup,DWORD dwControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSACOMPLETION lpCompletion); - WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceEnd(HANDLE hLookup); - WINSOCK_API_LINKAGE INT WSAAPI WSAInstallServiceClassA(LPWSASERVICECLASSINFOA lpServiceClassInfo); - WINSOCK_API_LINKAGE INT WSAAPI WSAInstallServiceClassW(LPWSASERVICECLASSINFOW lpServiceClassInfo); - WINSOCK_API_LINKAGE INT WSAAPI WSARemoveServiceClass(LPGUID lpServiceClassId); - WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassInfoA(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOA lpServiceClassInfo); - WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassInfoW(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOW lpServiceClassInfo); - WINSOCK_API_LINKAGE INT WSAAPI WSAEnumNameSpaceProvidersA(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOA lpnspBuffer); - WINSOCK_API_LINKAGE INT WSAAPI WSAEnumNameSpaceProvidersW(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOW lpnspBuffer); - WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassNameByClassIdA(LPGUID lpServiceClassId,LPSTR lpszServiceClassName,LPDWORD lpdwBufferLength); - WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassNameByClassIdW(LPGUID lpServiceClassId,LPWSTR lpszServiceClassName,LPDWORD lpdwBufferLength); - WINSOCK_API_LINKAGE INT WSAAPI WSASetServiceA(LPWSAQUERYSETA lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); - WINSOCK_API_LINKAGE INT WSAAPI WSASetServiceW(LPWSAQUERYSETW lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); - WINSOCK_API_LINKAGE INT WSAAPI WSAProviderConfigChange(LPHANDLE lpNotificationHandle,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - - typedef struct sockaddr_in SOCKADDR_IN; - typedef struct sockaddr_in *PSOCKADDR_IN; - typedef struct sockaddr_in *LPSOCKADDR_IN; - - typedef struct linger LINGER; - typedef struct linger *PLINGER; - typedef struct linger *LPLINGER; - - typedef struct in_addr IN_ADDR; - typedef struct in_addr *PIN_ADDR; - typedef struct in_addr *LPIN_ADDR; - - typedef struct fd_set FD_SET; - typedef struct fd_set *PFD_SET; - typedef struct fd_set *LPFD_SET; - - typedef struct hostent HOSTENT; - typedef struct hostent *PHOSTENT; - typedef struct hostent *LPHOSTENT; - - typedef struct servent SERVENT; - typedef struct servent *PSERVENT; - typedef struct servent *LPSERVENT; - - typedef struct protoent PROTOENT; - typedef struct protoent *PPROTOENT; - typedef struct protoent *LPPROTOENT; - - typedef struct timeval TIMEVAL; - typedef struct timeval *PTIMEVAL; - typedef struct timeval *LPTIMEVAL; - -#define WSAMAKEASYNCREPLY(buflen,error) MAKELONG(buflen,error) -#define WSAMAKESELECTREPLY(event,error) MAKELONG(event,error) -#define WSAGETASYNCBUFLEN(lParam) LOWORD(lParam) -#define WSAGETASYNCERROR(lParam) HIWORD(lParam) -#define WSAGETSELECTEVENT(lParam) LOWORD(lParam) -#define WSAGETSELECTERROR(lParam) HIWORD(lParam) - -/* #if (_WIN32_WINNT >= 0x0600) */ -#define POLLRDNORM 0x0100 -#define POLLRDBAND 0x0200 -#define POLLIN (POLLRDNORM | POLLRDBAND) -#define POLLPRI 0x0400 - -#define POLLWRNORM 0x0010 -#define POLLOUT (POLLWRNORM) -#define POLLWRBAND 0x0020 - -#define POLLERR 0x0001 -#define POLLHUP 0x0002 -#define POLLNVAL 0x0004 - -typedef struct pollfd { - SOCKET fd; - SHORT events; - SHORT revents; -} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; - -WINSOCK_API_LINKAGE int WSAAPI WSAPoll(LPWSAPOLLFD fdArray, ULONG fds, INT timeout); -/* #endif // (_WIN32_WINNT >= 0x0600) */ - -#ifdef __cplusplus -} -#endif - -#ifdef _NEED_POPPACK -#include -#endif - -#ifdef IPV6STRICT -#include -#endif - -#ifndef _WINSOCKAPI_ -#define _WINSOCKAPI_ -#endif - -#ifdef _INC_WINSOCK_H -#include -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _WINSOCK2API_ +#define _WINSOCK2API_ + +#ifndef INCL_WINSOCK_API_TYPEDEFS +#define INCL_WINSOCK_API_TYPEDEFS 0 +#endif + +#ifndef _INC_WINDOWS +#include +#endif + +#ifndef MAKEWORD +#define MAKEWORD(low,high) ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8)) +#endif + +#ifndef WINSOCK_VERSION +#define WINSOCK_VERSION MAKEWORD(2,2) +#endif + +#ifndef WINSOCK_API_LINKAGE +#ifdef DECLSPEC_IMPORT +#define WINSOCK_API_LINKAGE DECLSPEC_IMPORT +#else +#define WINSOCK_API_LINKAGE +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _WINSOCK_SOCKET_DEFINED +#define _WINSOCK_SOCKET_DEFINED + typedef unsigned char u_char; + typedef unsigned short u_short; + typedef unsigned int u_int; + typedef unsigned long u_long; + __MINGW_EXTENSION typedef unsigned __int64 u_int64; + typedef INT_PTR SOCKET; +#endif + +#ifndef FD_SETSIZE +#define FD_SETSIZE 64 +#endif + + typedef struct fd_set { + u_int fd_count; + SOCKET fd_array[FD_SETSIZE]; + } fd_set; + + extern int WINAPI __WSAFDIsSet(SOCKET,fd_set *); + +#define FD_CLR(fd,set) do { u_int __i; for(__i = 0;__i < ((fd_set *)(set))->fd_count;__i++) { if (((fd_set *)(set))->fd_array[__i]==fd) { while (__i < ((fd_set *)(set))->fd_count-1) { ((fd_set *)(set))->fd_array[__i] = ((fd_set *)(set))->fd_array[__i+1]; __i++; } ((fd_set *)(set))->fd_count--; break; } } } while(0) +#define FD_SET(fd,set) do { u_int __i; for(__i = 0;__i < ((fd_set *)(set))->fd_count;__i++) { if (((fd_set *)(set))->fd_array[__i]==(fd)) { break; } } if (__i==((fd_set *)(set))->fd_count) { if (((fd_set *)(set))->fd_count < FD_SETSIZE) { ((fd_set *)(set))->fd_array[__i] = (fd); ((fd_set *)(set))->fd_count++; } } } while(0) +#define FD_ZERO(set) (((fd_set *)(set))->fd_count=0) +#define FD_ISSET(fd,set) __WSAFDIsSet((SOCKET)(fd),(fd_set *)(set)) + +#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ +#define _TIMEVAL_DEFINED + struct timeval { + long tv_sec; + long tv_usec; + }; + +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif /* _TIMEVAL_DEFINED */ + +#define IOCPARM_MASK 0x7f +#define IOC_VOID 0x20000000 +#define IOC_OUT 0x40000000 +#define IOC_IN 0x80000000 +#define IOC_INOUT (IOC_IN|IOC_OUT) + +#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) +#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define FIONREAD _IOR('f',127,u_long) +#define FIONBIO _IOW('f',126,u_long) +#define FIOASYNC _IOW('f',125,u_long) + +#define SIOCSHIWAT _IOW('s',0,u_long) +#define SIOCGHIWAT _IOR('s',1,u_long) +#define SIOCSLOWAT _IOW('s',2,u_long) +#define SIOCGLOWAT _IOR('s',3,u_long) +#define SIOCATMARK _IOR('s',7,u_long) + +#define h_addr h_addr_list[0] + + struct hostent { + char *h_name; + char **h_aliases; + short h_addrtype; + short h_length; + char **h_addr_list; + }; + + struct netent { + char *n_name; + char **n_aliases; + short n_addrtype; + u_long n_net; + }; + + struct servent { + char *s_name; + char **s_aliases; +#ifdef _WIN64 + char *s_proto; + short s_port; +#else + short s_port; + char *s_proto; +#endif + }; + + struct protoent { + char *p_name; + char **p_aliases; + short p_proto; + }; + +#define IPPROTO_IP 0 +#define IPPROTO_HOPOPTS 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_IGMP 2 +#define IPPROTO_GGP 3 +#define IPPROTO_IPV4 4 +#define IPPROTO_TCP 6 +#define IPPROTO_PUP 12 +#define IPPROTO_UDP 17 +#define IPPROTO_IDP 22 +#define IPPROTO_IPV6 41 +#define IPPROTO_ROUTING 43 +#define IPPROTO_FRAGMENT 44 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_NONE 59 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_ND 77 +#define IPPROTO_ICLFXBM 78 + +#define IPPROTO_RAW 255 +#define IPPROTO_MAX 256 + +#define IPPORT_ECHO 7 +#define IPPORT_DISCARD 9 +#define IPPORT_SYSTAT 11 +#define IPPORT_DAYTIME 13 +#define IPPORT_NETSTAT 15 +#define IPPORT_FTP 21 +#define IPPORT_TELNET 23 +#define IPPORT_SMTP 25 +#define IPPORT_TIMESERVER 37 +#define IPPORT_NAMESERVER 42 +#define IPPORT_WHOIS 43 +#define IPPORT_MTP 57 + +#define IPPORT_TFTP 69 +#define IPPORT_RJE 77 +#define IPPORT_FINGER 79 +#define IPPORT_TTYLINK 87 +#define IPPORT_SUPDUP 95 + +#define IPPORT_EXECSERVER 512 +#define IPPORT_LOGINSERVER 513 +#define IPPORT_CMDSERVER 514 +#define IPPORT_EFSSERVER 520 + +#define IPPORT_BIFFUDP 512 +#define IPPORT_WHOSERVER 513 +#define IPPORT_ROUTESERVER 520 + +#define IPPORT_RESERVED 1024 + +#define IMPLINK_IP 155 +#define IMPLINK_LOWEXPER 156 +#define IMPLINK_HIGHEXPER 158 + +#ifndef s_addr + + struct in_addr { + union { + struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; + struct { u_short s_w1,s_w2; } S_un_w; + u_long S_addr; + } S_un; + }; + +#define s_addr S_un.S_addr +#define s_host S_un.S_un_b.s_b2 +#define s_net S_un.S_un_b.s_b1 +#define s_imp S_un.S_un_w.s_w2 +#define s_impno S_un.S_un_b.s_b4 +#define s_lh S_un.S_un_b.s_b3 + +#endif + +#define IN_CLASSA(i) (((long)(i) & 0x80000000)==0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST 0x00ffffff +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(i) (((long)(i) & 0xc0000000)==0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST 0x0000ffff +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(i) (((long)(i) & 0xe0000000)==0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST 0x000000ff + +#define IN_CLASSD(i) (((long)(i) & 0xf0000000)==0xe0000000) +#define IN_CLASSD_NET 0xf0000000 +#define IN_CLASSD_NSHIFT 28 +#define IN_CLASSD_HOST 0x0fffffff +#define IN_MULTICAST(i) IN_CLASSD(i) + +#define INADDR_ANY (u_long)0x00000000 +#define INADDR_LOOPBACK 0x7f000001 +#define INADDR_BROADCAST (u_long)0xffffffff +#define INADDR_NONE 0xffffffff + +#define ADDR_ANY INADDR_ANY + + struct sockaddr_in { + short sin_family; + u_short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; + }; + +#define WSADESCRIPTION_LEN 256 +#define WSASYS_STATUS_LEN 128 + + typedef struct WSAData { + WORD wVersion; + WORD wHighVersion; +#ifdef _WIN64 + unsigned short iMaxSockets; + unsigned short iMaxUdpDg; + char *lpVendorInfo; + char szDescription[WSADESCRIPTION_LEN+1]; + char szSystemStatus[WSASYS_STATUS_LEN+1]; +#else + char szDescription[WSADESCRIPTION_LEN+1]; + char szSystemStatus[WSASYS_STATUS_LEN+1]; + unsigned short iMaxSockets; + unsigned short iMaxUdpDg; + char *lpVendorInfo; +#endif + } WSADATA,*LPWSADATA; + +#define INVALID_SOCKET (SOCKET)(~0) +#define SOCKET_ERROR (-1) + +#define FROM_PROTOCOL_INFO (-1) + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 +#define SOCK_RDM 4 +#define SOCK_SEQPACKET 5 + +#define SO_DEBUG 0x0001 +#define SO_ACCEPTCONN 0x0002 +#define SO_REUSEADDR 0x0004 +#define SO_KEEPALIVE 0x0008 +#define SO_DONTROUTE 0x0010 +#define SO_BROADCAST 0x0020 +#define SO_USELOOPBACK 0x0040 +#define SO_LINGER 0x0080 +#define SO_OOBINLINE 0x0100 + +#define SO_DONTLINGER (int)(~SO_LINGER) +#define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR)) + +#define SO_SNDBUF 0x1001 +#define SO_RCVBUF 0x1002 +#define SO_SNDLOWAT 0x1003 +#define SO_RCVLOWAT 0x1004 +#define SO_SNDTIMEO 0x1005 +#define SO_RCVTIMEO 0x1006 +#define SO_ERROR 0x1007 +#define SO_TYPE 0x1008 + +#define SO_GROUP_ID 0x2001 +#define SO_GROUP_PRIORITY 0x2002 +#define SO_MAX_MSG_SIZE 0x2003 +#define SO_PROTOCOL_INFOA 0x2004 +#define SO_PROTOCOL_INFOW 0x2005 +#ifdef UNICODE +#define SO_PROTOCOL_INFO SO_PROTOCOL_INFOW +#else +#define SO_PROTOCOL_INFO SO_PROTOCOL_INFOA +#endif +#define PVD_CONFIG 0x3001 +#define SO_CONDITIONAL_ACCEPT 0x3002 + +#define TCP_NODELAY 0x0001 + +#define AF_UNSPEC 0 + +#define AF_UNIX 1 +#define AF_INET 2 +#define AF_IMPLINK 3 +#define AF_PUP 4 +#define AF_CHAOS 5 +#define AF_NS 6 +#define AF_IPX AF_NS +#define AF_ISO 7 +#define AF_OSI AF_ISO +#define AF_ECMA 8 +#define AF_DATAKIT 9 +#define AF_CCITT 10 +#define AF_SNA 11 +#define AF_DECnet 12 +#define AF_DLI 13 +#define AF_LAT 14 +#define AF_HYLINK 15 +#define AF_APPLETALK 16 +#define AF_NETBIOS 17 +#define AF_VOICEVIEW 18 +#define AF_FIREFOX 19 +#define AF_UNKNOWN1 20 +#define AF_BAN 21 +#define AF_ATM 22 +#define AF_INET6 23 +#define AF_CLUSTER 24 +#define AF_12844 25 +#define AF_IRDA 26 +#define AF_NETDES 28 +#define AF_TCNPROCESS 29 +#define AF_TCNMESSAGE 30 +#define AF_ICLFXBM 31 + +#define AF_MAX 32 + + struct sockaddr { + u_short sa_family; + char sa_data[14]; + }; + +#define _SS_MAXSIZE 128 +#define _SS_ALIGNSIZE (8) + +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (short)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (short) + _SS_PAD1SIZE + _SS_ALIGNSIZE)) + + struct sockaddr_storage { + short ss_family; + char __ss_pad1[_SS_PAD1SIZE]; + + __MINGW_EXTENSION __int64 __ss_align; + char __ss_pad2[_SS_PAD2SIZE]; + + }; + + struct sockproto { + u_short sp_family; + u_short sp_protocol; + }; + +#define PF_UNSPEC AF_UNSPEC +#define PF_UNIX AF_UNIX +#define PF_INET AF_INET +#define PF_IMPLINK AF_IMPLINK +#define PF_PUP AF_PUP +#define PF_CHAOS AF_CHAOS +#define PF_NS AF_NS +#define PF_IPX AF_IPX +#define PF_ISO AF_ISO +#define PF_OSI AF_OSI +#define PF_ECMA AF_ECMA +#define PF_DATAKIT AF_DATAKIT +#define PF_CCITT AF_CCITT +#define PF_SNA AF_SNA +#define PF_DECnet AF_DECnet +#define PF_DLI AF_DLI +#define PF_LAT AF_LAT +#define PF_HYLINK AF_HYLINK +#define PF_APPLETALK AF_APPLETALK +#define PF_VOICEVIEW AF_VOICEVIEW +#define PF_FIREFOX AF_FIREFOX +#define PF_UNKNOWN1 AF_UNKNOWN1 +#define PF_BAN AF_BAN +#define PF_ATM AF_ATM +#define PF_INET6 AF_INET6 + +#define PF_MAX AF_MAX + + struct linger { + u_short l_onoff; + u_short l_linger; + }; + +#define SOL_SOCKET 0xffff + +#define SOMAXCONN 0x7fffffff + +#define MSG_OOB 0x1 +#define MSG_PEEK 0x2 +#define MSG_DONTROUTE 0x4 +#define MSG_WAITALL 0x8 + +#define MSG_PARTIAL 0x8000 + +#define MSG_INTERRUPT 0x10 + +#define MSG_MAXIOVLEN 16 + +#define MAXGETHOSTSTRUCT 1024 + +#define FD_READ_BIT 0 +#define FD_READ (1 << FD_READ_BIT) + +#define FD_WRITE_BIT 1 +#define FD_WRITE (1 << FD_WRITE_BIT) + +#define FD_OOB_BIT 2 +#define FD_OOB (1 << FD_OOB_BIT) + +#define FD_ACCEPT_BIT 3 +#define FD_ACCEPT (1 << FD_ACCEPT_BIT) + +#define FD_CONNECT_BIT 4 +#define FD_CONNECT (1 << FD_CONNECT_BIT) + +#define FD_CLOSE_BIT 5 +#define FD_CLOSE (1 << FD_CLOSE_BIT) + +#define FD_QOS_BIT 6 +#define FD_QOS (1 << FD_QOS_BIT) + +#define FD_GROUP_QOS_BIT 7 +#define FD_GROUP_QOS (1 << FD_GROUP_QOS_BIT) + +#define FD_ROUTING_INTERFACE_CHANGE_BIT 8 +#define FD_ROUTING_INTERFACE_CHANGE (1 << FD_ROUTING_INTERFACE_CHANGE_BIT) + +#define FD_ADDRESS_LIST_CHANGE_BIT 9 +#define FD_ADDRESS_LIST_CHANGE (1 << FD_ADDRESS_LIST_CHANGE_BIT) + +#define FD_MAX_EVENTS 10 +#define FD_ALL_EVENTS ((1 << FD_MAX_EVENTS) - 1) + +#ifndef WSABASEERR + +#define WSABASEERR 10000 + +#define WSAEINTR (WSABASEERR+4) +#define WSAEBADF (WSABASEERR+9) +#define WSAEACCES (WSABASEERR+13) +#define WSAEFAULT (WSABASEERR+14) +#define WSAEINVAL (WSABASEERR+22) +#define WSAEMFILE (WSABASEERR+24) + +#define WSAEWOULDBLOCK (WSABASEERR+35) +#define WSAEINPROGRESS (WSABASEERR+36) +#define WSAEALREADY (WSABASEERR+37) +#define WSAENOTSOCK (WSABASEERR+38) +#define WSAEDESTADDRREQ (WSABASEERR+39) +#define WSAEMSGSIZE (WSABASEERR+40) +#define WSAEPROTOTYPE (WSABASEERR+41) +#define WSAENOPROTOOPT (WSABASEERR+42) +#define WSAEPROTONOSUPPORT (WSABASEERR+43) +#define WSAESOCKTNOSUPPORT (WSABASEERR+44) +#define WSAEOPNOTSUPP (WSABASEERR+45) +#define WSAEPFNOSUPPORT (WSABASEERR+46) +#define WSAEAFNOSUPPORT (WSABASEERR+47) +#define WSAEADDRINUSE (WSABASEERR+48) +#define WSAEADDRNOTAVAIL (WSABASEERR+49) +#define WSAENETDOWN (WSABASEERR+50) +#define WSAENETUNREACH (WSABASEERR+51) +#define WSAENETRESET (WSABASEERR+52) +#define WSAECONNABORTED (WSABASEERR+53) +#define WSAECONNRESET (WSABASEERR+54) +#define WSAENOBUFS (WSABASEERR+55) +#define WSAEISCONN (WSABASEERR+56) +#define WSAENOTCONN (WSABASEERR+57) +#define WSAESHUTDOWN (WSABASEERR+58) +#define WSAETOOMANYREFS (WSABASEERR+59) +#define WSAETIMEDOUT (WSABASEERR+60) +#define WSAECONNREFUSED (WSABASEERR+61) +#define WSAELOOP (WSABASEERR+62) +#define WSAENAMETOOLONG (WSABASEERR+63) +#define WSAEHOSTDOWN (WSABASEERR+64) +#define WSAEHOSTUNREACH (WSABASEERR+65) +#define WSAENOTEMPTY (WSABASEERR+66) +#define WSAEPROCLIM (WSABASEERR+67) +#define WSAEUSERS (WSABASEERR+68) +#define WSAEDQUOT (WSABASEERR+69) +#define WSAESTALE (WSABASEERR+70) +#define WSAEREMOTE (WSABASEERR+71) + +#define WSASYSNOTREADY (WSABASEERR+91) +#define WSAVERNOTSUPPORTED (WSABASEERR+92) +#define WSANOTINITIALISED (WSABASEERR+93) +#define WSAEDISCON (WSABASEERR+101) +#ifndef WSAHOST_NOT_FOUND +#define WSAHOST_NOT_FOUND (WSABASEERR+1001) +#endif +#ifndef WSATRY_AGAIN +#define WSATRY_AGAIN (WSABASEERR+1002) +#endif +#ifndef WSANO_RECOVERY +#define WSANO_RECOVERY (WSABASEERR+1003) +#endif +#ifndef WSANO_DATA +#define WSANO_DATA (WSABASEERR+1004) +#endif + +#define WSAENOMORE (WSABASEERR+102) +#define WSAECANCELLED (WSABASEERR+103) +#define WSAEINVALIDPROCTABLE (WSABASEERR+104) +#define WSAEINVALIDPROVIDER (WSABASEERR+105) +#define WSAEPROVIDERFAILEDINIT (WSABASEERR+106) +#define WSASYSCALLFAILURE (WSABASEERR+107) +#define WSASERVICE_NOT_FOUND (WSABASEERR+108) +#define WSATYPE_NOT_FOUND (WSABASEERR+109) +#define WSA_E_NO_MORE (WSABASEERR+110) +#define WSA_E_CANCELLED (WSABASEERR+111) +#define WSAEREFUSED (WSABASEERR+112) +#ifndef WSA_QOS_RECEIVERS +#define WSA_QOS_RECEIVERS (WSABASEERR + 1005) +#endif +#ifndef WSA_QOS_SENDERS +#define WSA_QOS_SENDERS (WSABASEERR + 1006) +#endif +#ifndef WSA_QOS_NO_SENDERS +#define WSA_QOS_NO_SENDERS (WSABASEERR + 1007) +#define WSA_QOS_NO_RECEIVERS (WSABASEERR + 1008) +#define WSA_QOS_REQUEST_CONFIRMED (WSABASEERR + 1009) +#define WSA_QOS_ADMISSION_FAILURE (WSABASEERR + 1010) +#define WSA_QOS_POLICY_FAILURE (WSABASEERR + 1011) +#define WSA_QOS_BAD_STYLE (WSABASEERR + 1012) +#define WSA_QOS_BAD_OBJECT (WSABASEERR + 1013) +#define WSA_QOS_TRAFFIC_CTRL_ERROR (WSABASEERR + 1014) +#define WSA_QOS_GENERIC_ERROR (WSABASEERR + 1015) +#define WSA_QOS_ESERVICETYPE (WSABASEERR + 1016) +#define WSA_QOS_EFLOWSPEC (WSABASEERR + 1017) +#define WSA_QOS_EPROVSPECBUF (WSABASEERR + 1018) +#endif +#ifndef WSA_QOS_EFILTERSTYLE +#define WSA_QOS_EFILTERSTYLE (WSABASEERR + 1019) +#endif +#ifndef WSA_QOS_EFILTERTYPE +#define WSA_QOS_EFILTERTYPE (WSABASEERR + 1020) +#endif +#ifndef WSA_QOS_EFILTERCOUNT +#define WSA_QOS_EFILTERCOUNT (WSABASEERR + 1021) +#endif +#ifndef WSA_QOS_EOBJLENGTH +#define WSA_QOS_EOBJLENGTH (WSABASEERR + 1022) +#endif +#ifndef WSA_QOS_EFLOWCOUNT +#define WSA_QOS_EFLOWCOUNT (WSABASEERR + 1023) +#endif +#ifndef WSA_QOS_EUNKNOWNPSOBJ +#define WSA_QOS_EUNKNOWNPSOBJ (WSABASEERR + 1024) +#endif +#ifndef WSA_QOS_EPOLICYOBJ +#define WSA_QOS_EPOLICYOBJ (WSABASEERR + 1025) +#endif +#ifndef WSA_QOS_EFLOWDESC +#define WSA_QOS_EFLOWDESC (WSABASEERR + 1026) +#endif +#ifndef WSA_QOS_EPSFLOWSPEC +#define WSA_QOS_EPSFLOWSPEC (WSABASEERR + 1027) +#endif +#ifndef WSA_QOS_EPSFILTERSPEC +#define WSA_QOS_EPSFILTERSPEC (WSABASEERR + 1028) +#endif +#ifndef WSA_QOS_ESDMODEOBJ +#define WSA_QOS_ESDMODEOBJ (WSABASEERR + 1029) +#endif +#ifndef WSA_QOS_ESHAPERATEOBJ +#define WSA_QOS_ESHAPERATEOBJ (WSABASEERR + 1030) +#endif +#ifndef WSA_QOS_RESERVED_PETYPE +#define WSA_QOS_RESERVED_PETYPE (WSABASEERR + 1031) +#endif +#endif // WSABASEERR + +#define h_errno WSAGetLastError() +#define HOST_NOT_FOUND WSAHOST_NOT_FOUND +#define TRY_AGAIN WSATRY_AGAIN +#define NO_RECOVERY WSANO_RECOVERY +#define NO_DATA WSANO_DATA + +#define WSANO_ADDRESS WSANO_DATA +#define NO_ADDRESS WSANO_ADDRESS + +#if 0 +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINPROGRESS WSAEINPROGRESS +#define EALREADY WSAEALREADY +#define ENOTSOCK WSAENOTSOCK +#define EDESTADDRREQ WSAEDESTADDRREQ +#define EMSGSIZE WSAEMSGSIZE +#define EPROTOTYPE WSAEPROTOTYPE +#define ENOPROTOOPT WSAENOPROTOOPT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EADDRINUSE WSAEADDRINUSE +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define ENETDOWN WSAENETDOWN +#define ENETUNREACH WSAENETUNREACH +#define ENETRESET WSAENETRESET +#define ECONNABORTED WSAECONNABORTED +#define ECONNRESET WSAECONNRESET +#define ENOBUFS WSAENOBUFS +#define EISCONN WSAEISCONN +#define ENOTCONN WSAENOTCONN +#define ESHUTDOWN WSAESHUTDOWN +#define ETOOMANYREFS WSAETOOMANYREFS +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define ELOOP WSAELOOP +#define ENAMETOOLONG WSAENAMETOOLONG +#define EHOSTDOWN WSAEHOSTDOWN +#define EHOSTUNREACH WSAEHOSTUNREACH +#define ENOTEMPTY WSAENOTEMPTY +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE +#endif + +#define WSAAPI WINAPI +#define WSAEVENT HANDLE +#define LPWSAEVENT LPHANDLE +#define WSAOVERLAPPED OVERLAPPED + typedef struct _OVERLAPPED *LPWSAOVERLAPPED; + +#define WSA_IO_PENDING (ERROR_IO_PENDING) +#define WSA_IO_INCOMPLETE (ERROR_IO_INCOMPLETE) +#define WSA_INVALID_HANDLE (ERROR_INVALID_HANDLE) +#define WSA_INVALID_PARAMETER (ERROR_INVALID_PARAMETER) +#define WSA_NOT_ENOUGH_MEMORY (ERROR_NOT_ENOUGH_MEMORY) +#define WSA_OPERATION_ABORTED (ERROR_OPERATION_ABORTED) + +#define WSA_INVALID_EVENT ((WSAEVENT)NULL) +#define WSA_MAXIMUM_WAIT_EVENTS (MAXIMUM_WAIT_OBJECTS) +#define WSA_WAIT_FAILED (WAIT_FAILED) +#define WSA_WAIT_EVENT_0 (WAIT_OBJECT_0) +#define WSA_WAIT_IO_COMPLETION (WAIT_IO_COMPLETION) +#define WSA_WAIT_TIMEOUT (WAIT_TIMEOUT) +#define WSA_INFINITE (INFINITE) + + typedef struct _WSABUF { + u_long len; + char *buf; + } WSABUF,*LPWSABUF; + +#include + + typedef struct _QualityOfService { + FLOWSPEC SendingFlowspec; + FLOWSPEC ReceivingFlowspec; + WSABUF ProviderSpecific; + } QOS,*LPQOS; + +#define CF_ACCEPT 0x0000 +#define CF_REJECT 0x0001 +#define CF_DEFER 0x0002 + +#define SD_RECEIVE 0x00 +#define SD_SEND 0x01 +#define SD_BOTH 0x02 + + typedef unsigned int GROUP; + +#define SG_UNCONSTRAINED_GROUP 0x01 +#define SG_CONSTRAINED_GROUP 0x02 + + typedef struct _WSANETWORKEVENTS { + long lNetworkEvents; + int iErrorCode[FD_MAX_EVENTS]; + } WSANETWORKEVENTS,*LPWSANETWORKEVENTS; + +#ifndef GUID_DEFINED +#include +#endif + +#define MAX_PROTOCOL_CHAIN 7 + +#define BASE_PROTOCOL 1 +#define LAYERED_PROTOCOL 0 + + typedef struct _WSAPROTOCOLCHAIN { + int ChainLen; + + DWORD ChainEntries[MAX_PROTOCOL_CHAIN]; + } WSAPROTOCOLCHAIN,*LPWSAPROTOCOLCHAIN; + +#define WSAPROTOCOL_LEN 255 + + typedef struct _WSAPROTOCOL_INFOA { + DWORD dwServiceFlags1; + DWORD dwServiceFlags2; + DWORD dwServiceFlags3; + DWORD dwServiceFlags4; + DWORD dwProviderFlags; + GUID ProviderId; + DWORD dwCatalogEntryId; + WSAPROTOCOLCHAIN ProtocolChain; + int iVersion; + int iAddressFamily; + int iMaxSockAddr; + int iMinSockAddr; + int iSocketType; + int iProtocol; + int iProtocolMaxOffset; + int iNetworkByteOrder; + int iSecurityScheme; + DWORD dwMessageSize; + DWORD dwProviderReserved; + CHAR szProtocol[WSAPROTOCOL_LEN+1]; + } WSAPROTOCOL_INFOA,*LPWSAPROTOCOL_INFOA; + typedef struct _WSAPROTOCOL_INFOW { + DWORD dwServiceFlags1; + DWORD dwServiceFlags2; + DWORD dwServiceFlags3; + DWORD dwServiceFlags4; + DWORD dwProviderFlags; + GUID ProviderId; + DWORD dwCatalogEntryId; + WSAPROTOCOLCHAIN ProtocolChain; + int iVersion; + int iAddressFamily; + int iMaxSockAddr; + int iMinSockAddr; + int iSocketType; + int iProtocol; + int iProtocolMaxOffset; + int iNetworkByteOrder; + int iSecurityScheme; + DWORD dwMessageSize; + DWORD dwProviderReserved; + WCHAR szProtocol[WSAPROTOCOL_LEN+1]; + } WSAPROTOCOL_INFOW,*LPWSAPROTOCOL_INFOW; +#ifdef UNICODE + typedef WSAPROTOCOL_INFOW WSAPROTOCOL_INFO; + typedef LPWSAPROTOCOL_INFOW LPWSAPROTOCOL_INFO; +#else + typedef WSAPROTOCOL_INFOA WSAPROTOCOL_INFO; + typedef LPWSAPROTOCOL_INFOA LPWSAPROTOCOL_INFO; +#endif + +#define PFL_MULTIPLE_PROTO_ENTRIES 0x00000001 +#define PFL_RECOMMENDED_PROTO_ENTRY 0x00000002 +#define PFL_HIDDEN 0x00000004 +#define PFL_MATCHES_PROTOCOL_ZERO 0x00000008 + +#define XP1_CONNECTIONLESS 0x00000001 +#define XP1_GUARANTEED_DELIVERY 0x00000002 +#define XP1_GUARANTEED_ORDER 0x00000004 +#define XP1_MESSAGE_ORIENTED 0x00000008 +#define XP1_PSEUDO_STREAM 0x00000010 +#define XP1_GRACEFUL_CLOSE 0x00000020 +#define XP1_EXPEDITED_DATA 0x00000040 +#define XP1_CONNECT_DATA 0x00000080 +#define XP1_DISCONNECT_DATA 0x00000100 +#define XP1_SUPPORT_BROADCAST 0x00000200 +#define XP1_SUPPORT_MULTIPOINT 0x00000400 +#define XP1_MULTIPOINT_CONTROL_PLANE 0x00000800 +#define XP1_MULTIPOINT_DATA_PLANE 0x00001000 +#define XP1_QOS_SUPPORTED 0x00002000 +#define XP1_INTERRUPT 0x00004000 +#define XP1_UNI_SEND 0x00008000 +#define XP1_UNI_RECV 0x00010000 +#define XP1_IFS_HANDLES 0x00020000 +#define XP1_PARTIAL_MESSAGE 0x00040000 + +#define BIGENDIAN 0x0000 +#define LITTLEENDIAN 0x0001 + +#define SECURITY_PROTOCOL_NONE 0x0000 + +#define JL_SENDER_ONLY 0x01 +#define JL_RECEIVER_ONLY 0x02 +#define JL_BOTH 0x04 + +#define WSA_FLAG_OVERLAPPED 0x01 +#define WSA_FLAG_MULTIPOINT_C_ROOT 0x02 +#define WSA_FLAG_MULTIPOINT_C_LEAF 0x04 +#define WSA_FLAG_MULTIPOINT_D_ROOT 0x08 +#define WSA_FLAG_MULTIPOINT_D_LEAF 0x10 + +#define IOC_UNIX 0x00000000 +#define IOC_WS2 0x08000000 +#define IOC_PROTOCOL 0x10000000 +#define IOC_VENDOR 0x18000000 + +#define _WSAIO(x,y) (IOC_VOID|(x)|(y)) +#define _WSAIOR(x,y) (IOC_OUT|(x)|(y)) +#define _WSAIOW(x,y) (IOC_IN|(x)|(y)) +#define _WSAIORW(x,y) (IOC_INOUT|(x)|(y)) + +#define SIO_ASSOCIATE_HANDLE _WSAIOW(IOC_WS2,1) +#define SIO_ENABLE_CIRCULAR_QUEUEING _WSAIO(IOC_WS2,2) +#define SIO_FIND_ROUTE _WSAIOR(IOC_WS2,3) +#define SIO_FLUSH _WSAIO(IOC_WS2,4) +#define SIO_GET_BROADCAST_ADDRESS _WSAIOR(IOC_WS2,5) +#define SIO_GET_EXTENSION_FUNCTION_POINTER _WSAIORW(IOC_WS2,6) +#define SIO_GET_QOS _WSAIORW(IOC_WS2,7) +#define SIO_GET_GROUP_QOS _WSAIORW(IOC_WS2,8) +#define SIO_MULTIPOINT_LOOPBACK _WSAIOW(IOC_WS2,9) +#define SIO_MULTICAST_SCOPE _WSAIOW(IOC_WS2,10) +#define SIO_SET_QOS _WSAIOW(IOC_WS2,11) +#define SIO_SET_GROUP_QOS _WSAIOW(IOC_WS2,12) +#define SIO_TRANSLATE_HANDLE _WSAIORW(IOC_WS2,13) +#define SIO_ROUTING_INTERFACE_QUERY _WSAIORW(IOC_WS2,20) +#define SIO_ROUTING_INTERFACE_CHANGE _WSAIOW(IOC_WS2,21) +#define SIO_ADDRESS_LIST_QUERY _WSAIOR(IOC_WS2,22) +#define SIO_ADDRESS_LIST_CHANGE _WSAIO(IOC_WS2,23) +#define SIO_QUERY_TARGET_PNP_HANDLE _WSAIOR(IOC_WS2,24) +#define SIO_ADDRESS_LIST_SORT _WSAIORW(IOC_WS2,25) + + typedef int (CALLBACK *LPCONDITIONPROC)(LPWSABUF lpCallerId,LPWSABUF lpCallerData,LPQOS lpSQOS,LPQOS lpGQOS,LPWSABUF lpCalleeId,LPWSABUF lpCalleeData,GROUP *g,DWORD_PTR dwCallbackData); + typedef void (CALLBACK *LPWSAOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwError,DWORD cbTransferred,LPWSAOVERLAPPED lpOverlapped,DWORD dwFlags); + +#define SIO_NSP_NOTIFY_CHANGE _WSAIOW(IOC_WS2,25) + + typedef enum _WSACOMPLETIONTYPE { + NSP_NOTIFY_IMMEDIATELY = 0,NSP_NOTIFY_HWND,NSP_NOTIFY_EVENT,NSP_NOTIFY_PORT,NSP_NOTIFY_APC + } WSACOMPLETIONTYPE,*PWSACOMPLETIONTYPE,*LPWSACOMPLETIONTYPE; + + typedef struct _WSACOMPLETION { + WSACOMPLETIONTYPE Type; + union { + struct { + HWND hWnd; + UINT uMsg; + WPARAM context; + } WindowMessage; + struct { + LPWSAOVERLAPPED lpOverlapped; + } Event; + struct { + LPWSAOVERLAPPED lpOverlapped; + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpfnCompletionProc; + } Apc; + struct { + LPWSAOVERLAPPED lpOverlapped; + HANDLE hPort; + ULONG_PTR Key; + } Port; + } Parameters; + } WSACOMPLETION,*PWSACOMPLETION,*LPWSACOMPLETION; + +#define TH_NETDEV 0x00000001 +#define TH_TAPI 0x00000002 + + typedef struct sockaddr SOCKADDR; + typedef struct sockaddr *PSOCKADDR; + typedef struct sockaddr *LPSOCKADDR; + typedef struct sockaddr_storage SOCKADDR_STORAGE; + typedef struct sockaddr_storage *PSOCKADDR_STORAGE; + typedef struct sockaddr_storage *LPSOCKADDR_STORAGE; + +#ifndef _tagBLOB_DEFINED +#define _tagBLOB_DEFINED +#define _BLOB_DEFINED +#define _LPBLOB_DEFINED + typedef struct _BLOB { + ULONG cbSize; + BYTE *pBlobData; + } BLOB,*LPBLOB; +#endif + +#define SERVICE_MULTIPLE (0x00000001) + +#define NS_ALL (0) + +#define NS_SAP (1) +#define NS_NDS (2) +#define NS_PEER_BROWSE (3) +#define NS_SLP (5) +#define NS_DHCP (6) + +#define NS_TCPIP_LOCAL (10) +#define NS_TCPIP_HOSTS (11) +#define NS_DNS (12) +#define NS_NETBT (13) +#define NS_WINS (14) +#define NS_NLA (15) + +#define NS_NBP (20) + +#define NS_MS (30) +#define NS_STDA (31) +#define NS_NTDS (32) + +#define NS_X500 (40) +#define NS_NIS (41) +#define NS_NISPLUS (42) + +#define NS_WRQ (50) + +#define NS_NETDES (60) + +#define RES_UNUSED_1 (0x00000001) +#define RES_FLUSH_CACHE (0x00000002) +#ifndef RES_SERVICE +#define RES_SERVICE (0x00000004) +#endif + +#define SERVICE_TYPE_VALUE_IPXPORTA "IpxSocket" +#define SERVICE_TYPE_VALUE_IPXPORTW L"IpxSocket" +#define SERVICE_TYPE_VALUE_SAPIDA "SapId" +#define SERVICE_TYPE_VALUE_SAPIDW L"SapId" + +#define SERVICE_TYPE_VALUE_TCPPORTA "TcpPort" +#define SERVICE_TYPE_VALUE_TCPPORTW L"TcpPort" + +#define SERVICE_TYPE_VALUE_UDPPORTA "UdpPort" +#define SERVICE_TYPE_VALUE_UDPPORTW L"UdpPort" + +#define SERVICE_TYPE_VALUE_OBJECTIDA "ObjectId" +#define SERVICE_TYPE_VALUE_OBJECTIDW L"ObjectId" + +#ifdef UNICODE + +#define SERVICE_TYPE_VALUE_SAPID SERVICE_TYPE_VALUE_SAPIDW +#define SERVICE_TYPE_VALUE_TCPPORT SERVICE_TYPE_VALUE_TCPPORTW +#define SERVICE_TYPE_VALUE_UDPPORT SERVICE_TYPE_VALUE_UDPPORTW +#define SERVICE_TYPE_VALUE_OBJECTID SERVICE_TYPE_VALUE_OBJECTIDW +#else + +#define SERVICE_TYPE_VALUE_SAPID SERVICE_TYPE_VALUE_SAPIDA +#define SERVICE_TYPE_VALUE_TCPPORT SERVICE_TYPE_VALUE_TCPPORTA +#define SERVICE_TYPE_VALUE_UDPPORT SERVICE_TYPE_VALUE_UDPPORTA +#define SERVICE_TYPE_VALUE_OBJECTID SERVICE_TYPE_VALUE_OBJECTIDA +#endif + +#ifndef __CSADDR_DEFINED__ +#define __CSADDR_DEFINED__ + + typedef struct _SOCKET_ADDRESS { + LPSOCKADDR lpSockaddr; + INT iSockaddrLength; + } SOCKET_ADDRESS,*PSOCKET_ADDRESS,*LPSOCKET_ADDRESS; + + typedef struct _CSADDR_INFO { + SOCKET_ADDRESS LocalAddr; + SOCKET_ADDRESS RemoteAddr; + INT iSocketType; + INT iProtocol; + } CSADDR_INFO,*PCSADDR_INFO,*LPCSADDR_INFO; +#endif + + typedef struct _SOCKET_ADDRESS_LIST { + INT iAddressCount; + SOCKET_ADDRESS Address[1]; + } SOCKET_ADDRESS_LIST,*LPSOCKET_ADDRESS_LIST; + + typedef struct _AFPROTOCOLS { + INT iAddressFamily; + INT iProtocol; + } AFPROTOCOLS,*PAFPROTOCOLS,*LPAFPROTOCOLS; + + typedef enum _WSAEcomparator { + COMP_EQUAL = 0,COMP_NOTLESS + } WSAECOMPARATOR,*PWSAECOMPARATOR,*LPWSAECOMPARATOR; + + typedef struct _WSAVersion { + DWORD dwVersion; + WSAECOMPARATOR ecHow; + } WSAVERSION,*PWSAVERSION,*LPWSAVERSION; + + typedef struct _WSAQuerySetA { + DWORD dwSize; + LPSTR lpszServiceInstanceName; + LPGUID lpServiceClassId; + LPWSAVERSION lpVersion; + LPSTR lpszComment; + DWORD dwNameSpace; + LPGUID lpNSProviderId; + LPSTR lpszContext; + DWORD dwNumberOfProtocols; + LPAFPROTOCOLS lpafpProtocols; + LPSTR lpszQueryString; + DWORD dwNumberOfCsAddrs; + LPCSADDR_INFO lpcsaBuffer; + DWORD dwOutputFlags; + LPBLOB lpBlob; + } WSAQUERYSETA,*PWSAQUERYSETA,*LPWSAQUERYSETA; + + typedef struct _WSAQuerySetW { + DWORD dwSize; + LPWSTR lpszServiceInstanceName; + LPGUID lpServiceClassId; + LPWSAVERSION lpVersion; + LPWSTR lpszComment; + DWORD dwNameSpace; + LPGUID lpNSProviderId; + LPWSTR lpszContext; + DWORD dwNumberOfProtocols; + LPAFPROTOCOLS lpafpProtocols; + LPWSTR lpszQueryString; + DWORD dwNumberOfCsAddrs; + LPCSADDR_INFO lpcsaBuffer; + DWORD dwOutputFlags; + LPBLOB lpBlob; + } WSAQUERYSETW,*PWSAQUERYSETW,*LPWSAQUERYSETW; + +#ifdef UNICODE + typedef WSAQUERYSETW WSAQUERYSET; + typedef PWSAQUERYSETW PWSAQUERYSET; + typedef LPWSAQUERYSETW LPWSAQUERYSET; +#else + typedef WSAQUERYSETA WSAQUERYSET; + typedef PWSAQUERYSETA PWSAQUERYSET; + typedef LPWSAQUERYSETA LPWSAQUERYSET; +#endif + +#define LUP_DEEP 0x0001 +#define LUP_CONTAINERS 0x0002 +#define LUP_NOCONTAINERS 0x0004 +#define LUP_NEAREST 0x0008 +#define LUP_RETURN_NAME 0x0010 +#define LUP_RETURN_TYPE 0x0020 +#define LUP_RETURN_VERSION 0x0040 +#define LUP_RETURN_COMMENT 0x0080 +#define LUP_RETURN_ADDR 0x0100 +#define LUP_RETURN_BLOB 0x0200 +#define LUP_RETURN_ALIASES 0x0400 +#define LUP_RETURN_QUERY_STRING 0x0800 +#define LUP_RETURN_ALL 0x0FF0 +#define LUP_RES_SERVICE 0x8000 + +#define LUP_FLUSHCACHE 0x1000 +#define LUP_FLUSHPREVIOUS 0x2000 + +#define RESULT_IS_ALIAS 0x0001 +#define RESULT_IS_ADDED 0x0010 +#define RESULT_IS_CHANGED 0x0020 +#define RESULT_IS_DELETED 0x0040 + + typedef enum _WSAESETSERVICEOP { + RNRSERVICE_REGISTER=0,RNRSERVICE_DEREGISTER,RNRSERVICE_DELETE + } WSAESETSERVICEOP,*PWSAESETSERVICEOP,*LPWSAESETSERVICEOP; + + typedef struct _WSANSClassInfoA { + LPSTR lpszName; + DWORD dwNameSpace; + DWORD dwValueType; + DWORD dwValueSize; + LPVOID lpValue; + } WSANSCLASSINFOA,*PWSANSCLASSINFOA,*LPWSANSCLASSINFOA; + + typedef struct _WSANSClassInfoW { + LPWSTR lpszName; + DWORD dwNameSpace; + DWORD dwValueType; + DWORD dwValueSize; + LPVOID lpValue; + } WSANSCLASSINFOW,*PWSANSCLASSINFOW,*LPWSANSCLASSINFOW; + +#ifdef UNICODE + typedef WSANSCLASSINFOW WSANSCLASSINFO; + typedef PWSANSCLASSINFOW PWSANSCLASSINFO; + typedef LPWSANSCLASSINFOW LPWSANSCLASSINFO; +#else + typedef WSANSCLASSINFOA WSANSCLASSINFO; + typedef PWSANSCLASSINFOA PWSANSCLASSINFO; + typedef LPWSANSCLASSINFOA LPWSANSCLASSINFO; +#endif + + typedef struct _WSAServiceClassInfoA { + LPGUID lpServiceClassId; + LPSTR lpszServiceClassName; + DWORD dwCount; + LPWSANSCLASSINFOA lpClassInfos; + } WSASERVICECLASSINFOA,*PWSASERVICECLASSINFOA,*LPWSASERVICECLASSINFOA; + + typedef struct _WSAServiceClassInfoW { + LPGUID lpServiceClassId; + LPWSTR lpszServiceClassName; + DWORD dwCount; + LPWSANSCLASSINFOW lpClassInfos; + } WSASERVICECLASSINFOW,*PWSASERVICECLASSINFOW,*LPWSASERVICECLASSINFOW; + +#ifdef UNICODE + typedef WSASERVICECLASSINFOW WSASERVICECLASSINFO; + typedef PWSASERVICECLASSINFOW PWSASERVICECLASSINFO; + typedef LPWSASERVICECLASSINFOW LPWSASERVICECLASSINFO; +#else + typedef WSASERVICECLASSINFOA WSASERVICECLASSINFO; + typedef PWSASERVICECLASSINFOA PWSASERVICECLASSINFO; + typedef LPWSASERVICECLASSINFOA LPWSASERVICECLASSINFO; +#endif + + typedef struct _WSANAMESPACE_INFOA { + GUID NSProviderId; + DWORD dwNameSpace; + WINBOOL fActive; + DWORD dwVersion; + LPSTR lpszIdentifier; + } WSANAMESPACE_INFOA,*PWSANAMESPACE_INFOA,*LPWSANAMESPACE_INFOA; + + typedef struct _WSANAMESPACE_INFOW { + GUID NSProviderId; + DWORD dwNameSpace; + WINBOOL fActive; + DWORD dwVersion; + LPWSTR lpszIdentifier; + } WSANAMESPACE_INFOW,*PWSANAMESPACE_INFOW,*LPWSANAMESPACE_INFOW; + +#ifdef UNICODE + typedef WSANAMESPACE_INFOW WSANAMESPACE_INFO; + typedef PWSANAMESPACE_INFOW PWSANAMESPACE_INFO; + typedef LPWSANAMESPACE_INFOW LPWSANAMESPACE_INFO; +#else + typedef WSANAMESPACE_INFOA WSANAMESPACE_INFO; + typedef PWSANAMESPACE_INFOA PWSANAMESPACE_INFO; + typedef LPWSANAMESPACE_INFOA LPWSANAMESPACE_INFO; +#endif + +#if INCL_WINSOCK_API_TYPEDEFS +#ifdef UNICODE +#define LPFN_WSADUPLICATESOCKET LPFN_WSADUPLICATESOCKETW +#define LPFN_WSAENUMPROTOCOLS LPFN_WSAENUMPROTOCOLSW +#define LPFN_WSASOCKET LPFN_WSASOCKETW +#define LPFN_WSAADDRESSTOSTRING LPFN_WSAADDRESSTOSTRINGW +#define LPFN_WSASTRINGTOADDRESS LPFN_WSASTRINGTOADDRESSW +#define LPFN_WSALOOKUPSERVICEBEGIN LPFN_WSALOOKUPSERVICEBEGINW +#define LPFN_WSALOOKUPSERVICENEXT LPFN_WSALOOKUPSERVICENEXTW +#define LPFN_WSAINSTALLSERVICECLASS LPFN_WSAINSTALLSERVICECLASSW +#define LPFN_WSAGETSERVICECLASSINFO LPFN_WSAGETSERVICECLASSINFOW +#define LPFN_WSAENUMNAMESPACEPROVIDERS LPFN_WSAENUMNAMESPACEPROVIDERSW +#define LPFN_WSAGETSERVICECLASSNAMEBYCLASSID LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDW +#define LPFN_WSASETSERVICE LPFN_WSASETSERVICEW +#else +#define LPFN_WSADUPLICATESOCKET LPFN_WSADUPLICATESOCKETA +#define LPFN_WSAENUMPROTOCOLS LPFN_WSAENUMPROTOCOLSA +#define LPFN_WSASOCKET LPFN_WSASOCKETA +#define LPFN_WSAADDRESSTOSTRING LPFN_WSAADDRESSTOSTRINGA +#define LPFN_WSASTRINGTOADDRESS LPFN_WSASTRINGTOADDRESSA +#define LPFN_WSALOOKUPSERVICEBEGIN LPFN_WSALOOKUPSERVICEBEGINA +#define LPFN_WSALOOKUPSERVICENEXT LPFN_WSALOOKUPSERVICENEXTA +#define LPFN_WSAINSTALLSERVICECLASS LPFN_WSAINSTALLSERVICECLASSA +#define LPFN_WSAGETSERVICECLASSINFO LPFN_WSAGETSERVICECLASSINFOA +#define LPFN_WSAENUMNAMESPACEPROVIDERS LPFN_WSAENUMNAMESPACEPROVIDERSA +#define LPFN_WSAGETSERVICECLASSNAMEBYCLASSID LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDA +#define LPFN_WSASETSERVICE LPFN_WSASETSERVICEA +#endif + + typedef SOCKET (WSAAPI *LPFN_ACCEPT)(SOCKET s,struct sockaddr *addr,int *addrlen); + typedef int (WSAAPI *LPFN_BIND)(SOCKET s,const struct sockaddr *name,int namelen); + typedef int (WSAAPI *LPFN_CLOSESOCKET)(SOCKET s); + typedef int (WSAAPI *LPFN_CONNECT)(SOCKET s,const struct sockaddr *name,int namelen); + typedef int (WSAAPI *LPFN_IOCTLSOCKET)(SOCKET s,long cmd,u_long *argp); + typedef int (WSAAPI *LPFN_GETPEERNAME)(SOCKET s,struct sockaddr *name,int *namelen); + typedef int (WSAAPI *LPFN_GETSOCKNAME)(SOCKET s,struct sockaddr *name,int *namelen); + typedef int (WSAAPI *LPFN_GETSOCKOPT)(SOCKET s,int level,int optname,char *optval,int *optlen); + typedef u_long (WSAAPI *LPFN_HTONL)(u_long hostlong); + typedef u_short (WSAAPI *LPFN_HTONS)(u_short hostshort); + typedef unsigned long (WSAAPI *LPFN_INET_ADDR)(const char *cp); + typedef char *(WSAAPI *LPFN_INET_NTOA)(struct in_addr in); + typedef int (WSAAPI *LPFN_LISTEN)(SOCKET s,int backlog); + typedef u_long (WSAAPI *LPFN_NTOHL)(u_long netlong); + typedef u_short (WSAAPI *LPFN_NTOHS)(u_short netshort); + typedef int (WSAAPI *LPFN_RECV)(SOCKET s,char *buf,int len,int flags); + typedef int (WSAAPI *LPFN_RECVFROM)(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen); + typedef int (WSAAPI *LPFN_SELECT)(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout); + typedef int (WSAAPI *LPFN_SEND)(SOCKET s,const char *buf,int len,int flags); + typedef int (WSAAPI *LPFN_SENDTO)(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen); + typedef int (WSAAPI *LPFN_SETSOCKOPT)(SOCKET s,int level,int optname,const char *optval,int optlen); + typedef int (WSAAPI *LPFN_SHUTDOWN)(SOCKET s,int how); + typedef SOCKET (WSAAPI *LPFN_SOCKET)(int af,int type,int protocol); + typedef struct hostent *(WSAAPI *LPFN_GETHOSTBYADDR)(const char *addr,int len,int type); + typedef struct hostent *(WSAAPI *LPFN_GETHOSTBYNAME)(const char *name); + typedef int (WSAAPI *LPFN_GETHOSTNAME)(char *name,int namelen); + typedef struct servent *(WSAAPI *LPFN_GETSERVBYPORT)(int port,const char *proto); + typedef struct servent *(WSAAPI *LPFN_GETSERVBYNAME)(const char *name,const char *proto); + typedef struct protoent *(WSAAPI *LPFN_GETPROTOBYNUMBER)(int number); + typedef struct protoent *(WSAAPI *LPFN_GETPROTOBYNAME)(const char *name); + typedef int (WSAAPI *LPFN_WSASTARTUP)(WORD wVersionRequested,LPWSADATA lpWSAData); + typedef int (WSAAPI *LPFN_WSACLEANUP)(void); + typedef void (WSAAPI *LPFN_WSASETLASTERROR)(int iError); + typedef int (WSAAPI *LPFN_WSAGETLASTERROR)(void); + typedef WINBOOL (WSAAPI *LPFN_WSAISBLOCKING)(void); + typedef int (WSAAPI *LPFN_WSAUNHOOKBLOCKINGHOOK)(void); + typedef FARPROC (WSAAPI *LPFN_WSASETBLOCKINGHOOK)(FARPROC lpBlockFunc); + typedef int (WSAAPI *LPFN_WSACANCELBLOCKINGCALL)(void); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETSERVBYNAME)(HWND hWnd,u_int wMsg,const char *name,const char *proto,char *buf,int buflen); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETSERVBYPORT)(HWND hWnd,u_int wMsg,int port,const char *proto,char *buf,int buflen); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETPROTOBYNAME)(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETPROTOBYNUMBER)(HWND hWnd,u_int wMsg,int number,char *buf,int buflen); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETHOSTBYNAME)(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETHOSTBYADDR)(HWND hWnd,u_int wMsg,const char *addr,int len,int type,char *buf,int buflen); + typedef int (WSAAPI *LPFN_WSACANCELASYNCREQUEST)(HANDLE hAsyncTaskHandle); + typedef int (WSAAPI *LPFN_WSAASYNCSELECT)(SOCKET s,HWND hWnd,u_int wMsg,long lEvent); + typedef SOCKET (WSAAPI *LPFN_WSAACCEPT)(SOCKET s,struct sockaddr *addr,LPINT addrlen,LPCONDITIONPROC lpfnCondition,DWORD_PTR dwCallbackData); + typedef WINBOOL (WSAAPI *LPFN_WSACLOSEEVENT)(WSAEVENT hEvent); + typedef int (WSAAPI *LPFN_WSACONNECT)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS); + typedef WSAEVENT (WSAAPI *LPFN_WSACREATEEVENT)(void); + typedef int (WSAAPI *LPFN_WSADUPLICATESOCKETA)(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOA lpProtocolInfo); + typedef int (WSAAPI *LPFN_WSADUPLICATESOCKETW)(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOW lpProtocolInfo); + typedef int (WSAAPI *LPFN_WSAENUMNETWORKEVENTS)(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents); + typedef int (WSAAPI *LPFN_WSAENUMPROTOCOLSA)(LPINT lpiProtocols,LPWSAPROTOCOL_INFOA lpProtocolBuffer,LPDWORD lpdwBufferLength); + typedef int (WSAAPI *LPFN_WSAENUMPROTOCOLSW)(LPINT lpiProtocols,LPWSAPROTOCOL_INFOW lpProtocolBuffer,LPDWORD lpdwBufferLength); + typedef int (WSAAPI *LPFN_WSAEVENTSELECT)(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents); + typedef WINBOOL (WSAAPI *LPFN_WSAGETOVERLAPPEDRESULT)(SOCKET s,LPWSAOVERLAPPED lpOverlapped,LPDWORD lpcbTransfer,WINBOOL fWait,LPDWORD lpdwFlags); + typedef WINBOOL (WSAAPI *LPFN_WSAGETQOSBYNAME)(SOCKET s,LPWSABUF lpQOSName,LPQOS lpQOS); + typedef int (WSAAPI *LPFN_WSAHTONL)(SOCKET s,u_long hostlong,u_long *lpnetlong); + typedef int (WSAAPI *LPFN_WSAHTONS)(SOCKET s,u_short hostshort,u_short *lpnetshort); + typedef int (WSAAPI *LPFN_WSAIOCTL)(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + typedef SOCKET (WSAAPI *LPFN_WSAJOINLEAF)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,DWORD dwFlags); + typedef int (WSAAPI *LPFN_WSANTOHL)(SOCKET s,u_long netlong,u_long *lphostlong); + typedef int (WSAAPI *LPFN_WSANTOHS)(SOCKET s,u_short netshort,u_short *lphostshort); + typedef int (WSAAPI *LPFN_WSARECV)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + typedef int (WSAAPI *LPFN_WSARECVDISCONNECT)(SOCKET s,LPWSABUF lpInboundDisconnectData); + typedef int (WSAAPI *LPFN_WSARECVFROM)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,struct sockaddr *lpFrom,LPINT lpFromlen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + typedef WINBOOL (WSAAPI *LPFN_WSARESETEVENT)(WSAEVENT hEvent); + typedef int (WSAAPI *LPFN_WSASEND)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + typedef int (WSAAPI *LPFN_WSASENDDISCONNECT)(SOCKET s,LPWSABUF lpOutboundDisconnectData); + typedef int (WSAAPI *LPFN_WSASENDTO)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,const struct sockaddr *lpTo,int iTolen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + typedef WINBOOL (WSAAPI *LPFN_WSASETEVENT)(WSAEVENT hEvent); + typedef SOCKET (WSAAPI *LPFN_WSASOCKETA)(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags); + typedef SOCKET (WSAAPI *LPFN_WSASOCKETW)(int af,int type,int protocol,LPWSAPROTOCOL_INFOW lpProtocolInfo,GROUP g,DWORD dwFlags); + typedef DWORD (WSAAPI *LPFN_WSAWAITFORMULTIPLEEVENTS)(DWORD cEvents,const WSAEVENT *lphEvents,WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable); + typedef INT (WSAAPI *LPFN_WSAADDRESSTOSTRINGA)(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSTR lpszAddressString,LPDWORD lpdwAddressStringLength); + typedef INT (WSAAPI *LPFN_WSAADDRESSTOSTRINGW)(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPWSTR lpszAddressString,LPDWORD lpdwAddressStringLength); + typedef INT (WSAAPI *LPFN_WSASTRINGTOADDRESSA)(LPSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); + typedef INT (WSAAPI *LPFN_WSASTRINGTOADDRESSW)(LPWSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); + typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEBEGINA)(LPWSAQUERYSETA lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); + typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEBEGINW)(LPWSAQUERYSETW lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); + typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICENEXTA)(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETA lpqsResults); + typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICENEXTW)(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETW lpqsResults); + typedef INT (WSAAPI *LPFN_WSANSPIOCTL)(HANDLE hLookup,DWORD dwControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSACOMPLETION lpCompletion); + typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEEND)(HANDLE hLookup); + typedef INT (WSAAPI *LPFN_WSAINSTALLSERVICECLASSA)(LPWSASERVICECLASSINFOA lpServiceClassInfo); + typedef INT (WSAAPI *LPFN_WSAINSTALLSERVICECLASSW)(LPWSASERVICECLASSINFOW lpServiceClassInfo); + typedef INT (WSAAPI *LPFN_WSAREMOVESERVICECLASS)(LPGUID lpServiceClassId); + typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSINFOA)(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOA lpServiceClassInfo); + typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSINFOW)(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOW lpServiceClassInfo); + typedef INT (WSAAPI *LPFN_WSAENUMNAMESPACEPROVIDERSA)(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOA lpnspBuffer); + typedef INT (WSAAPI *LPFN_WSAENUMNAMESPACEPROVIDERSW)(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOW lpnspBuffer); + typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDA)(LPGUID lpServiceClassId,LPSTR lpszServiceClassName,LPDWORD lpdwBufferLength); + typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDW)(LPGUID lpServiceClassId,LPWSTR lpszServiceClassName,LPDWORD lpdwBufferLength); + typedef INT (WSAAPI *LPFN_WSASETSERVICEA)(LPWSAQUERYSETA lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); + typedef INT (WSAAPI *LPFN_WSASETSERVICEW)(LPWSAQUERYSETW lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); + typedef INT (WSAAPI *LPFN_WSAPROVIDERCONFIGCHANGE)(LPHANDLE lpNotificationHandle,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); +#endif + +#ifdef UNICODE +#define WSADuplicateSocket WSADuplicateSocketW +#define WSAEnumProtocols WSAEnumProtocolsW +#define WSAAddressToString WSAAddressToStringW +#define WSASocket WSASocketW +#define WSAStringToAddress WSAStringToAddressW +#define WSALookupServiceBegin WSALookupServiceBeginW +#define WSALookupServiceNext WSALookupServiceNextW +#define WSAInstallServiceClass WSAInstallServiceClassW +#define WSAGetServiceClassInfo WSAGetServiceClassInfoW +#define WSAEnumNameSpaceProviders WSAEnumNameSpaceProvidersW +#define WSAGetServiceClassNameByClassId WSAGetServiceClassNameByClassIdW +#define WSASetService WSASetServiceW +#else +#define WSADuplicateSocket WSADuplicateSocketA +#define WSAEnumProtocols WSAEnumProtocolsA +#define WSASocket WSASocketA +#define WSAAddressToString WSAAddressToStringA +#define WSAStringToAddress WSAStringToAddressA +#define WSALookupServiceBegin WSALookupServiceBeginA +#define WSALookupServiceNext WSALookupServiceNextA +#define WSAInstallServiceClass WSAInstallServiceClassA +#define WSAGetServiceClassInfo WSAGetServiceClassInfoA +#define WSAEnumNameSpaceProviders WSAEnumNameSpaceProvidersA +#define WSAGetServiceClassNameByClassId WSAGetServiceClassNameByClassIdA +#define WSASetService WSASetServiceA +#endif + + WINSOCK_API_LINKAGE SOCKET WSAAPI accept(SOCKET s,struct sockaddr *addr,int *addrlen); + WINSOCK_API_LINKAGE int WSAAPI bind(SOCKET s,const struct sockaddr *name,int namelen); + WINSOCK_API_LINKAGE int WSAAPI closesocket(SOCKET s); + WINSOCK_API_LINKAGE int WSAAPI connect(SOCKET s,const struct sockaddr *name,int namelen); + WINSOCK_API_LINKAGE int WSAAPI ioctlsocket(SOCKET s,long cmd,u_long *argp); + WINSOCK_API_LINKAGE int WSAAPI getpeername(SOCKET s,struct sockaddr *name,int *namelen); + WINSOCK_API_LINKAGE int WSAAPI getsockname(SOCKET s,struct sockaddr *name,int *namelen); + WINSOCK_API_LINKAGE int WSAAPI getsockopt(SOCKET s,int level,int optname,char *optval,int *optlen); + WINSOCK_API_LINKAGE u_long WSAAPI htonl(u_long hostlong); + WINSOCK_API_LINKAGE u_short WSAAPI htons(u_short hostshort); + WINSOCK_API_LINKAGE unsigned long WSAAPI inet_addr(const char *cp); + WINSOCK_API_LINKAGE char *WSAAPI inet_ntoa(struct in_addr in); + WINSOCK_API_LINKAGE int WSAAPI listen(SOCKET s,int backlog); + WINSOCK_API_LINKAGE u_long WSAAPI ntohl(u_long netlong); + WINSOCK_API_LINKAGE u_short WSAAPI ntohs(u_short netshort); + WINSOCK_API_LINKAGE int WSAAPI recv(SOCKET s,char *buf,int len,int flags); + WINSOCK_API_LINKAGE int WSAAPI recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen); + WINSOCK_API_LINKAGE int WSAAPI select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout); + WINSOCK_API_LINKAGE int WSAAPI send(SOCKET s,const char *buf,int len,int flags); + WINSOCK_API_LINKAGE int WSAAPI sendto(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen); + WINSOCK_API_LINKAGE int WSAAPI setsockopt(SOCKET s,int level,int optname,const char *optval,int optlen); + WINSOCK_API_LINKAGE int WSAAPI shutdown(SOCKET s,int how); + WINSOCK_API_LINKAGE SOCKET WSAAPI socket(int af,int type,int protocol); + WINSOCK_API_LINKAGE struct hostent *WSAAPI gethostbyaddr(const char *addr,int len,int type); + WINSOCK_API_LINKAGE struct hostent *WSAAPI gethostbyname(const char *name); + WINSOCK_API_LINKAGE int WSAAPI gethostname(char *name,int namelen); + WINSOCK_API_LINKAGE struct servent *WSAAPI getservbyport(int port,const char *proto); + WINSOCK_API_LINKAGE struct servent *WSAAPI getservbyname(const char *name,const char *proto); + WINSOCK_API_LINKAGE struct protoent *WSAAPI getprotobynumber(int number); + WINSOCK_API_LINKAGE struct protoent *WSAAPI getprotobyname(const char *name); + WINSOCK_API_LINKAGE int WSAAPI WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData); + WINSOCK_API_LINKAGE int WSAAPI WSACleanup(void); + WINSOCK_API_LINKAGE void WSAAPI WSASetLastError(int iError); + WINSOCK_API_LINKAGE int WSAAPI WSAGetLastError(void); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAIsBlocking(void); + WINSOCK_API_LINKAGE int WSAAPI WSAUnhookBlockingHook(void); + WINSOCK_API_LINKAGE FARPROC WSAAPI WSASetBlockingHook(FARPROC lpBlockFunc); + WINSOCK_API_LINKAGE int WSAAPI WSACancelBlockingCall(void); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetServByName(HWND hWnd,u_int wMsg,const char *name,const char *proto,char *buf,int buflen); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetServByPort(HWND hWnd,u_int wMsg,int port,const char *proto,char *buf,int buflen); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetProtoByName(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetProtoByNumber(HWND hWnd,u_int wMsg,int number,char *buf,int buflen); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetHostByName(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetHostByAddr(HWND hWnd,u_int wMsg,const char *addr,int len,int type,char *buf,int buflen); + WINSOCK_API_LINKAGE int WSAAPI WSACancelAsyncRequest(HANDLE hAsyncTaskHandle); + WINSOCK_API_LINKAGE int WSAAPI WSAAsyncSelect(SOCKET s,HWND hWnd,u_int wMsg,long lEvent); + WINSOCK_API_LINKAGE SOCKET WSAAPI WSAAccept(SOCKET s,struct sockaddr *addr,LPINT addrlen,LPCONDITIONPROC lpfnCondition,DWORD_PTR dwCallbackData); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSACloseEvent(WSAEVENT hEvent); + WINSOCK_API_LINKAGE int WSAAPI WSAConnect(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS); + WINSOCK_API_LINKAGE WSAEVENT WSAAPI WSACreateEvent(void); + WINSOCK_API_LINKAGE int WSAAPI WSADuplicateSocketA(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOA lpProtocolInfo); + WINSOCK_API_LINKAGE int WSAAPI WSADuplicateSocketW(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOW lpProtocolInfo); + WINSOCK_API_LINKAGE int WSAAPI WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents); + WINSOCK_API_LINKAGE int WSAAPI WSAEnumProtocolsA(LPINT lpiProtocols,LPWSAPROTOCOL_INFOA lpProtocolBuffer,LPDWORD lpdwBufferLength); + WINSOCK_API_LINKAGE int WSAAPI WSAEnumProtocolsW(LPINT lpiProtocols,LPWSAPROTOCOL_INFOW lpProtocolBuffer,LPDWORD lpdwBufferLength); + WINSOCK_API_LINKAGE int WSAAPI WSAEventSelect(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAGetOverlappedResult(SOCKET s,LPWSAOVERLAPPED lpOverlapped,LPDWORD lpcbTransfer,WINBOOL fWait,LPDWORD lpdwFlags); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAGetQOSByName(SOCKET s,LPWSABUF lpQOSName,LPQOS lpQOS); + WINSOCK_API_LINKAGE int WSAAPI WSAHtonl(SOCKET s,u_long hostlong,u_long *lpnetlong); + WINSOCK_API_LINKAGE int WSAAPI WSAHtons(SOCKET s,u_short hostshort,u_short *lpnetshort); + WINSOCK_API_LINKAGE int WSAAPI WSAIoctl(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINSOCK_API_LINKAGE SOCKET WSAAPI WSAJoinLeaf(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,DWORD dwFlags); + WINSOCK_API_LINKAGE int WSAAPI WSANtohl(SOCKET s,u_long netlong,u_long *lphostlong); + WINSOCK_API_LINKAGE int WSAAPI WSANtohs(SOCKET s,u_short netshort,u_short *lphostshort); + WINSOCK_API_LINKAGE int WSAAPI WSARecv(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINSOCK_API_LINKAGE int WSAAPI WSARecvDisconnect(SOCKET s,LPWSABUF lpInboundDisconnectData); + WINSOCK_API_LINKAGE int WSAAPI WSARecvFrom(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,struct sockaddr *lpFrom,LPINT lpFromlen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAResetEvent(WSAEVENT hEvent); + WINSOCK_API_LINKAGE int WSAAPI WSASend(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINSOCK_API_LINKAGE int WSAAPI WSASendDisconnect(SOCKET s,LPWSABUF lpOutboundDisconnectData); + WINSOCK_API_LINKAGE int WSAAPI WSASendTo(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,const struct sockaddr *lpTo,int iTolen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSASetEvent(WSAEVENT hEvent); + WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketA(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags); + WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketW(int af,int type,int protocol,LPWSAPROTOCOL_INFOW lpProtocolInfo,GROUP g,DWORD dwFlags); + WINSOCK_API_LINKAGE DWORD WSAAPI WSAWaitForMultipleEvents(DWORD cEvents,const WSAEVENT *lphEvents,WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable); + WINSOCK_API_LINKAGE INT WSAAPI WSAAddressToStringA(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSTR lpszAddressString,LPDWORD lpdwAddressStringLength); + WINSOCK_API_LINKAGE INT WSAAPI WSAAddressToStringW(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPWSTR lpszAddressString,LPDWORD lpdwAddressStringLength); + WINSOCK_API_LINKAGE INT WSAAPI WSAStringToAddressA(LPSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); + WINSOCK_API_LINKAGE INT WSAAPI WSAStringToAddressW(LPWSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); + WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceBeginA(LPWSAQUERYSETA lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); + WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceBeginW(LPWSAQUERYSETW lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); + WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceNextA(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETA lpqsResults); + WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceNextW(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETW lpqsResults); + WINSOCK_API_LINKAGE INT WSAAPI WSANSPIoctl(HANDLE hLookup,DWORD dwControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSACOMPLETION lpCompletion); + WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceEnd(HANDLE hLookup); + WINSOCK_API_LINKAGE INT WSAAPI WSAInstallServiceClassA(LPWSASERVICECLASSINFOA lpServiceClassInfo); + WINSOCK_API_LINKAGE INT WSAAPI WSAInstallServiceClassW(LPWSASERVICECLASSINFOW lpServiceClassInfo); + WINSOCK_API_LINKAGE INT WSAAPI WSARemoveServiceClass(LPGUID lpServiceClassId); + WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassInfoA(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOA lpServiceClassInfo); + WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassInfoW(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOW lpServiceClassInfo); + WINSOCK_API_LINKAGE INT WSAAPI WSAEnumNameSpaceProvidersA(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOA lpnspBuffer); + WINSOCK_API_LINKAGE INT WSAAPI WSAEnumNameSpaceProvidersW(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOW lpnspBuffer); + WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassNameByClassIdA(LPGUID lpServiceClassId,LPSTR lpszServiceClassName,LPDWORD lpdwBufferLength); + WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassNameByClassIdW(LPGUID lpServiceClassId,LPWSTR lpszServiceClassName,LPDWORD lpdwBufferLength); + WINSOCK_API_LINKAGE INT WSAAPI WSASetServiceA(LPWSAQUERYSETA lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); + WINSOCK_API_LINKAGE INT WSAAPI WSASetServiceW(LPWSAQUERYSETW lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); + WINSOCK_API_LINKAGE INT WSAAPI WSAProviderConfigChange(LPHANDLE lpNotificationHandle,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + + typedef struct sockaddr_in SOCKADDR_IN; + typedef struct sockaddr_in *PSOCKADDR_IN; + typedef struct sockaddr_in *LPSOCKADDR_IN; + + typedef struct linger LINGER; + typedef struct linger *PLINGER; + typedef struct linger *LPLINGER; + + typedef struct in_addr IN_ADDR; + typedef struct in_addr *PIN_ADDR; + typedef struct in_addr *LPIN_ADDR; + + typedef struct fd_set FD_SET; + typedef struct fd_set *PFD_SET; + typedef struct fd_set *LPFD_SET; + + typedef struct hostent HOSTENT; + typedef struct hostent *PHOSTENT; + typedef struct hostent *LPHOSTENT; + + typedef struct servent SERVENT; + typedef struct servent *PSERVENT; + typedef struct servent *LPSERVENT; + + typedef struct protoent PROTOENT; + typedef struct protoent *PPROTOENT; + typedef struct protoent *LPPROTOENT; + + typedef struct timeval TIMEVAL; + typedef struct timeval *PTIMEVAL; + typedef struct timeval *LPTIMEVAL; + +#define WSAMAKEASYNCREPLY(buflen,error) MAKELONG(buflen,error) +#define WSAMAKESELECTREPLY(event,error) MAKELONG(event,error) +#define WSAGETASYNCBUFLEN(lParam) LOWORD(lParam) +#define WSAGETASYNCERROR(lParam) HIWORD(lParam) +#define WSAGETSELECTEVENT(lParam) LOWORD(lParam) +#define WSAGETSELECTERROR(lParam) HIWORD(lParam) + +/* #if (_WIN32_WINNT >= 0x0600) */ +#define POLLRDNORM 0x0100 +#define POLLRDBAND 0x0200 +#define POLLIN (POLLRDNORM | POLLRDBAND) +#define POLLPRI 0x0400 + +#define POLLWRNORM 0x0010 +#define POLLOUT (POLLWRNORM) +#define POLLWRBAND 0x0020 + +#define POLLERR 0x0001 +#define POLLHUP 0x0002 +#define POLLNVAL 0x0004 + +typedef struct pollfd { + SOCKET fd; + SHORT events; + SHORT revents; +} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; + +WINSOCK_API_LINKAGE int WSAAPI WSAPoll(LPWSAPOLLFD fdArray, ULONG fds, INT timeout); +/* #endif // (_WIN32_WINNT >= 0x0600) */ + +#ifdef __cplusplus +} +#endif + +#ifdef _NEED_POPPACK +#include +#endif + +#ifdef IPV6STRICT +#include +#endif + +#ifndef _WINSOCKAPI_ +#define _WINSOCKAPI_ +#endif + +#ifdef _INC_WINSOCK_H +#include +#endif + +#endif diff --git a/tcc/include/winapi/winuser.h b/tcc/include/winapi/winuser.h index 4cd9ffb5..a28526fb 100644 --- a/tcc/include/winapi/winuser.h +++ b/tcc/include/winapi/winuser.h @@ -1,5651 +1,5651 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINUSER_ -#define _WINUSER_ - -#define WINUSERAPI DECLSPEC_IMPORT - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#include - -#ifndef NOUSER - typedef HANDLE HDWP; - typedef VOID MENUTEMPLATEA; - typedef VOID MENUTEMPLATEW; - typedef PVOID LPMENUTEMPLATEA; - typedef PVOID LPMENUTEMPLATEW; - -#ifdef UNICODE - typedef MENUTEMPLATEW MENUTEMPLATE; - typedef LPMENUTEMPLATEW LPMENUTEMPLATE; -#else - typedef MENUTEMPLATEA MENUTEMPLATE; - typedef LPMENUTEMPLATEA LPMENUTEMPLATE; -#endif - - typedef LRESULT (CALLBACK *WNDPROC)(HWND,UINT,WPARAM,LPARAM); - typedef INT_PTR (CALLBACK *DLGPROC)(HWND,UINT,WPARAM,LPARAM); - typedef VOID (CALLBACK *TIMERPROC)(HWND,UINT,UINT_PTR,DWORD); - typedef WINBOOL (CALLBACK *GRAYSTRINGPROC)(HDC,LPARAM,int); - typedef WINBOOL (CALLBACK *WNDENUMPROC)(HWND,LPARAM); - typedef LRESULT (CALLBACK *HOOKPROC)(int code,WPARAM wParam,LPARAM lParam); - typedef VOID (CALLBACK *SENDASYNCPROC)(HWND,UINT,ULONG_PTR,LRESULT); - typedef WINBOOL (CALLBACK *PROPENUMPROCA)(HWND,LPCSTR,HANDLE); - typedef WINBOOL (CALLBACK *PROPENUMPROCW)(HWND,LPCWSTR,HANDLE); - typedef WINBOOL (CALLBACK *PROPENUMPROCEXA)(HWND,LPSTR,HANDLE,ULONG_PTR); - typedef WINBOOL (CALLBACK *PROPENUMPROCEXW)(HWND,LPWSTR,HANDLE,ULONG_PTR); - typedef int (CALLBACK *EDITWORDBREAKPROCA)(LPSTR lpch,int ichCurrent,int cch,int code); - typedef int (CALLBACK *EDITWORDBREAKPROCW)(LPWSTR lpch,int ichCurrent,int cch,int code); - typedef WINBOOL (CALLBACK *DRAWSTATEPROC)(HDC hdc,LPARAM lData,WPARAM wData,int cx,int cy); - -#ifdef UNICODE - typedef PROPENUMPROCW PROPENUMPROC; - typedef PROPENUMPROCEXW PROPENUMPROCEX; - typedef EDITWORDBREAKPROCW EDITWORDBREAKPROC; -#else - typedef PROPENUMPROCA PROPENUMPROC; - typedef PROPENUMPROCEXA PROPENUMPROCEX; - typedef EDITWORDBREAKPROCA EDITWORDBREAKPROC; -#endif - - typedef WINBOOL (CALLBACK *NAMEENUMPROCA)(LPSTR,LPARAM); - typedef WINBOOL (CALLBACK *NAMEENUMPROCW)(LPWSTR,LPARAM); - typedef NAMEENUMPROCA WINSTAENUMPROCA; - typedef NAMEENUMPROCA DESKTOPENUMPROCA; - typedef NAMEENUMPROCW WINSTAENUMPROCW; - typedef NAMEENUMPROCW DESKTOPENUMPROCW; - -#ifdef UNICODE - typedef WINSTAENUMPROCW WINSTAENUMPROC; - typedef DESKTOPENUMPROCW DESKTOPENUMPROC; -#else - typedef WINSTAENUMPROCA WINSTAENUMPROC; - typedef DESKTOPENUMPROCA DESKTOPENUMPROC; -#endif - -#define IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16)==0) -#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i)))) -#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i)))) -#ifdef UNICODE -#define MAKEINTRESOURCE MAKEINTRESOURCEW -#else -#define MAKEINTRESOURCE MAKEINTRESOURCEA -#endif - -#ifndef NORESOURCE - -#define RT_CURSOR MAKEINTRESOURCE(1) -#define RT_BITMAP MAKEINTRESOURCE(2) -#define RT_ICON MAKEINTRESOURCE(3) -#define RT_MENU MAKEINTRESOURCE(4) -#define RT_DIALOG MAKEINTRESOURCE(5) -#define RT_STRING MAKEINTRESOURCE(6) -#define RT_FONTDIR MAKEINTRESOURCE(7) -#define RT_FONT MAKEINTRESOURCE(8) -#define RT_ACCELERATOR MAKEINTRESOURCE(9) -#define RT_RCDATA MAKEINTRESOURCE(10) -#define RT_MESSAGETABLE MAKEINTRESOURCE(11) - -#define DIFFERENCE 11 -#define RT_GROUP_CURSOR MAKEINTRESOURCE((ULONG_PTR)RT_CURSOR + DIFFERENCE) -#define RT_GROUP_ICON MAKEINTRESOURCE((ULONG_PTR)RT_ICON + DIFFERENCE) -#define RT_VERSION MAKEINTRESOURCE(16) -#define RT_DLGINCLUDE MAKEINTRESOURCE(17) -#define RT_PLUGPLAY MAKEINTRESOURCE(19) -#define RT_VXD MAKEINTRESOURCE(20) -#define RT_ANICURSOR MAKEINTRESOURCE(21) -#define RT_ANIICON MAKEINTRESOURCE(22) -#define RT_HTML MAKEINTRESOURCE(23) -#ifdef RC_INVOKED -#define RT_MANIFEST 24 -#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 -#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 -#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3 -#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID 1 -#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID 16 -#else -#define RT_MANIFEST MAKEINTRESOURCE(24) -#define CREATEPROCESS_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) -#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(2) -#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(3) -#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) -#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(16) -#endif -#endif - -#ifdef UNICODE -#define wvsprintf wvsprintfW -#define wsprintf wsprintfW -#else -#define wvsprintf wvsprintfA -#define wsprintf wsprintfA -#endif - - WINUSERAPI int WINAPI wvsprintfA(LPSTR,LPCSTR,va_list arglist); - WINUSERAPI int WINAPI wvsprintfW(LPWSTR,LPCWSTR,va_list arglist); - WINUSERAPI int WINAPIV wsprintfA(LPSTR,LPCSTR,...); - WINUSERAPI int WINAPIV wsprintfW(LPWSTR,LPCWSTR,...); - -#define SETWALLPAPER_DEFAULT ((LPWSTR)-1) - -#ifndef NOSCROLL -#define SB_HORZ 0 -#define SB_VERT 1 -#define SB_CTL 2 -#define SB_BOTH 3 - -#define SB_LINEUP 0 -#define SB_LINELEFT 0 -#define SB_LINEDOWN 1 -#define SB_LINERIGHT 1 -#define SB_PAGEUP 2 -#define SB_PAGELEFT 2 -#define SB_PAGEDOWN 3 -#define SB_PAGERIGHT 3 -#define SB_THUMBPOSITION 4 -#define SB_THUMBTRACK 5 -#define SB_TOP 6 -#define SB_LEFT 6 -#define SB_BOTTOM 7 -#define SB_RIGHT 7 -#define SB_ENDSCROLL 8 -#endif - -#ifndef NOSHOWWINDOW -#define SW_HIDE 0 -#define SW_SHOWNORMAL 1 -#define SW_NORMAL 1 -#define SW_SHOWMINIMIZED 2 -#define SW_SHOWMAXIMIZED 3 -#define SW_MAXIMIZE 3 -#define SW_SHOWNOACTIVATE 4 -#define SW_SHOW 5 -#define SW_MINIMIZE 6 -#define SW_SHOWMINNOACTIVE 7 -#define SW_SHOWNA 8 -#define SW_RESTORE 9 -#define SW_SHOWDEFAULT 10 -#define SW_FORCEMINIMIZE 11 -#define SW_MAX 11 - -#define HIDE_WINDOW 0 -#define SHOW_OPENWINDOW 1 -#define SHOW_ICONWINDOW 2 -#define SHOW_FULLSCREEN 3 -#define SHOW_OPENNOACTIVATE 4 - -#define SW_PARENTCLOSING 1 -#define SW_OTHERZOOM 2 -#define SW_PARENTOPENING 3 -#define SW_OTHERUNZOOM 4 -#endif - -#define AW_HOR_POSITIVE 0x00000001 -#define AW_HOR_NEGATIVE 0x00000002 -#define AW_VER_POSITIVE 0x00000004 -#define AW_VER_NEGATIVE 0x00000008 -#define AW_CENTER 0x00000010 -#define AW_HIDE 0x00010000 -#define AW_ACTIVATE 0x00020000 -#define AW_SLIDE 0x00040000 -#define AW_BLEND 0x00080000 - -#define KF_EXTENDED 0x0100 -#define KF_DLGMODE 0x0800 -#define KF_MENUMODE 0x1000 -#define KF_ALTDOWN 0x2000 -#define KF_REPEAT 0x4000 -#define KF_UP 0x8000 - -#ifndef NOVIRTUALKEYCODES - -#define VK_LBUTTON 0x01 -#define VK_RBUTTON 0x02 -#define VK_CANCEL 0x03 -#define VK_MBUTTON 0x04 -#define VK_XBUTTON1 0x05 -#define VK_XBUTTON2 0x06 -#define VK_BACK 0x08 -#define VK_TAB 0x09 -#define VK_CLEAR 0x0C -#define VK_RETURN 0x0D -#define VK_SHIFT 0x10 -#define VK_CONTROL 0x11 -#define VK_MENU 0x12 -#define VK_PAUSE 0x13 -#define VK_CAPITAL 0x14 -#define VK_KANA 0x15 -#define VK_HANGEUL 0x15 -#define VK_HANGUL 0x15 -#define VK_JUNJA 0x17 -#define VK_FINAL 0x18 -#define VK_HANJA 0x19 -#define VK_KANJI 0x19 -#define VK_ESCAPE 0x1B -#define VK_CONVERT 0x1C -#define VK_NONCONVERT 0x1D -#define VK_ACCEPT 0x1E -#define VK_MODECHANGE 0x1F -#define VK_SPACE 0x20 -#define VK_PRIOR 0x21 -#define VK_NEXT 0x22 -#define VK_END 0x23 -#define VK_HOME 0x24 -#define VK_LEFT 0x25 -#define VK_UP 0x26 -#define VK_RIGHT 0x27 -#define VK_DOWN 0x28 -#define VK_SELECT 0x29 -#define VK_PRINT 0x2A -#define VK_EXECUTE 0x2B -#define VK_SNAPSHOT 0x2C -#define VK_INSERT 0x2D -#define VK_DELETE 0x2E -#define VK_HELP 0x2F - -#define VK_LWIN 0x5B -#define VK_RWIN 0x5C -#define VK_APPS 0x5D -#define VK_SLEEP 0x5F -#define VK_NUMPAD0 0x60 -#define VK_NUMPAD1 0x61 -#define VK_NUMPAD2 0x62 -#define VK_NUMPAD3 0x63 -#define VK_NUMPAD4 0x64 -#define VK_NUMPAD5 0x65 -#define VK_NUMPAD6 0x66 -#define VK_NUMPAD7 0x67 -#define VK_NUMPAD8 0x68 -#define VK_NUMPAD9 0x69 -#define VK_MULTIPLY 0x6A -#define VK_ADD 0x6B -#define VK_SEPARATOR 0x6C -#define VK_SUBTRACT 0x6D -#define VK_DECIMAL 0x6E -#define VK_DIVIDE 0x6F -#define VK_F1 0x70 -#define VK_F2 0x71 -#define VK_F3 0x72 -#define VK_F4 0x73 -#define VK_F5 0x74 -#define VK_F6 0x75 -#define VK_F7 0x76 -#define VK_F8 0x77 -#define VK_F9 0x78 -#define VK_F10 0x79 -#define VK_F11 0x7A -#define VK_F12 0x7B -#define VK_F13 0x7C -#define VK_F14 0x7D -#define VK_F15 0x7E -#define VK_F16 0x7F -#define VK_F17 0x80 -#define VK_F18 0x81 -#define VK_F19 0x82 -#define VK_F20 0x83 -#define VK_F21 0x84 -#define VK_F22 0x85 -#define VK_F23 0x86 -#define VK_F24 0x87 -#define VK_NUMLOCK 0x90 -#define VK_SCROLL 0x91 -#define VK_OEM_NEC_EQUAL 0x92 -#define VK_OEM_FJ_JISHO 0x92 -#define VK_OEM_FJ_MASSHOU 0x93 -#define VK_OEM_FJ_TOUROKU 0x94 -#define VK_OEM_FJ_LOYA 0x95 -#define VK_OEM_FJ_ROYA 0x96 -#define VK_LSHIFT 0xA0 -#define VK_RSHIFT 0xA1 -#define VK_LCONTROL 0xA2 -#define VK_RCONTROL 0xA3 -#define VK_LMENU 0xA4 -#define VK_RMENU 0xA5 -#define VK_BROWSER_BACK 0xA6 -#define VK_BROWSER_FORWARD 0xA7 -#define VK_BROWSER_REFRESH 0xA8 -#define VK_BROWSER_STOP 0xA9 -#define VK_BROWSER_SEARCH 0xAA -#define VK_BROWSER_FAVORITES 0xAB -#define VK_BROWSER_HOME 0xAC -#define VK_VOLUME_MUTE 0xAD -#define VK_VOLUME_DOWN 0xAE -#define VK_VOLUME_UP 0xAF -#define VK_MEDIA_NEXT_TRACK 0xB0 -#define VK_MEDIA_PREV_TRACK 0xB1 -#define VK_MEDIA_STOP 0xB2 -#define VK_MEDIA_PLAY_PAUSE 0xB3 -#define VK_LAUNCH_MAIL 0xB4 -#define VK_LAUNCH_MEDIA_SELECT 0xB5 -#define VK_LAUNCH_APP1 0xB6 -#define VK_LAUNCH_APP2 0xB7 -#define VK_OEM_1 0xBA -#define VK_OEM_PLUS 0xBB -#define VK_OEM_COMMA 0xBC -#define VK_OEM_MINUS 0xBD -#define VK_OEM_PERIOD 0xBE -#define VK_OEM_2 0xBF -#define VK_OEM_3 0xC0 -#define VK_OEM_4 0xDB -#define VK_OEM_5 0xDC -#define VK_OEM_6 0xDD -#define VK_OEM_7 0xDE -#define VK_OEM_8 0xDF -#define VK_OEM_AX 0xE1 -#define VK_OEM_102 0xE2 -#define VK_ICO_HELP 0xE3 -#define VK_ICO_00 0xE4 -#define VK_PROCESSKEY 0xE5 -#define VK_ICO_CLEAR 0xE6 -#define VK_PACKET 0xE7 -#define VK_OEM_RESET 0xE9 -#define VK_OEM_JUMP 0xEA -#define VK_OEM_PA1 0xEB -#define VK_OEM_PA2 0xEC -#define VK_OEM_PA3 0xED -#define VK_OEM_WSCTRL 0xEE -#define VK_OEM_CUSEL 0xEF -#define VK_OEM_ATTN 0xF0 -#define VK_OEM_FINISH 0xF1 -#define VK_OEM_COPY 0xF2 -#define VK_OEM_AUTO 0xF3 -#define VK_OEM_ENLW 0xF4 -#define VK_OEM_BACKTAB 0xF5 -#define VK_ATTN 0xF6 -#define VK_CRSEL 0xF7 -#define VK_EXSEL 0xF8 -#define VK_EREOF 0xF9 -#define VK_PLAY 0xFA -#define VK_ZOOM 0xFB -#define VK_NONAME 0xFC -#define VK_PA1 0xFD -#define VK_OEM_CLEAR 0xFE -#endif - -#ifndef NOWH - -#define WH_MIN (-1) -#define WH_MSGFILTER (-1) -#define WH_JOURNALRECORD 0 -#define WH_JOURNALPLAYBACK 1 -#define WH_KEYBOARD 2 -#define WH_GETMESSAGE 3 -#define WH_CALLWNDPROC 4 -#define WH_CBT 5 -#define WH_SYSMSGFILTER 6 -#define WH_MOUSE 7 -#define WH_HARDWARE 8 -#define WH_DEBUG 9 -#define WH_SHELL 10 -#define WH_FOREGROUNDIDLE 11 -#define WH_CALLWNDPROCRET 12 - -#define WH_KEYBOARD_LL 13 -#define WH_MOUSE_LL 14 - -#define WH_MAX 14 - -#define WH_MINHOOK WH_MIN -#define WH_MAXHOOK WH_MAX - -#define HC_ACTION 0 -#define HC_GETNEXT 1 -#define HC_SKIP 2 -#define HC_NOREMOVE 3 -#define HC_NOREM HC_NOREMOVE -#define HC_SYSMODALON 4 -#define HC_SYSMODALOFF 5 - -#define HCBT_MOVESIZE 0 -#define HCBT_MINMAX 1 -#define HCBT_QS 2 -#define HCBT_CREATEWND 3 -#define HCBT_DESTROYWND 4 -#define HCBT_ACTIVATE 5 -#define HCBT_CLICKSKIPPED 6 -#define HCBT_KEYSKIPPED 7 -#define HCBT_SYSCOMMAND 8 -#define HCBT_SETFOCUS 9 - - typedef struct tagCBT_CREATEWNDA { - struct tagCREATESTRUCTA *lpcs; - HWND hwndInsertAfter; - } CBT_CREATEWNDA,*LPCBT_CREATEWNDA; - - typedef struct tagCBT_CREATEWNDW { - struct tagCREATESTRUCTW *lpcs; - HWND hwndInsertAfter; - } CBT_CREATEWNDW,*LPCBT_CREATEWNDW; -#ifdef UNICODE - typedef CBT_CREATEWNDW CBT_CREATEWND; - typedef LPCBT_CREATEWNDW LPCBT_CREATEWND; -#else - typedef CBT_CREATEWNDA CBT_CREATEWND; - typedef LPCBT_CREATEWNDA LPCBT_CREATEWND; -#endif - - typedef struct tagCBTACTIVATESTRUCT - { - WINBOOL fMouse; - HWND hWndActive; - } CBTACTIVATESTRUCT,*LPCBTACTIVATESTRUCT; - - typedef struct tagWTSSESSION_NOTIFICATION { - DWORD cbSize; - DWORD dwSessionId; - - } WTSSESSION_NOTIFICATION,*PWTSSESSION_NOTIFICATION; - -#define WTS_CONSOLE_CONNECT 0x1 -#define WTS_CONSOLE_DISCONNECT 0x2 -#define WTS_REMOTE_CONNECT 0x3 -#define WTS_REMOTE_DISCONNECT 0x4 -#define WTS_SESSION_LOGON 0x5 -#define WTS_SESSION_LOGOFF 0x6 -#define WTS_SESSION_LOCK 0x7 -#define WTS_SESSION_UNLOCK 0x8 -#define WTS_SESSION_REMOTE_CONTROL 0x9 - -#define MSGF_DIALOGBOX 0 -#define MSGF_MESSAGEBOX 1 -#define MSGF_MENU 2 -#define MSGF_SCROLLBAR 5 -#define MSGF_NEXTWINDOW 6 -#define MSGF_MAX 8 -#define MSGF_USER 4096 - -#define HSHELL_WINDOWCREATED 1 -#define HSHELL_WINDOWDESTROYED 2 -#define HSHELL_ACTIVATESHELLWINDOW 3 - -#define HSHELL_WINDOWACTIVATED 4 -#define HSHELL_GETMINRECT 5 -#define HSHELL_REDRAW 6 -#define HSHELL_TASKMAN 7 -#define HSHELL_LANGUAGE 8 -#define HSHELL_SYSMENU 9 -#define HSHELL_ENDTASK 10 -#define HSHELL_ACCESSIBILITYSTATE 11 -#define HSHELL_APPCOMMAND 12 -#define HSHELL_WINDOWREPLACED 13 -#define HSHELL_WINDOWREPLACING 14 -#define HSHELL_HIGHBIT 0x8000 -#define HSHELL_FLASH (HSHELL_REDRAW|HSHELL_HIGHBIT) -#define HSHELL_RUDEAPPACTIVATED (HSHELL_WINDOWACTIVATED|HSHELL_HIGHBIT) - -#define ACCESS_STICKYKEYS 0x0001 -#define ACCESS_FILTERKEYS 0x0002 -#define ACCESS_MOUSEKEYS 0x0003 - -#define APPCOMMAND_BROWSER_BACKWARD 1 -#define APPCOMMAND_BROWSER_FORWARD 2 -#define APPCOMMAND_BROWSER_REFRESH 3 -#define APPCOMMAND_BROWSER_STOP 4 -#define APPCOMMAND_BROWSER_SEARCH 5 -#define APPCOMMAND_BROWSER_FAVORITES 6 -#define APPCOMMAND_BROWSER_HOME 7 -#define APPCOMMAND_VOLUME_MUTE 8 -#define APPCOMMAND_VOLUME_DOWN 9 -#define APPCOMMAND_VOLUME_UP 10 -#define APPCOMMAND_MEDIA_NEXTTRACK 11 -#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12 -#define APPCOMMAND_MEDIA_STOP 13 -#define APPCOMMAND_MEDIA_PLAY_PAUSE 14 -#define APPCOMMAND_LAUNCH_MAIL 15 -#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16 -#define APPCOMMAND_LAUNCH_APP1 17 -#define APPCOMMAND_LAUNCH_APP2 18 -#define APPCOMMAND_BASS_DOWN 19 -#define APPCOMMAND_BASS_BOOST 20 -#define APPCOMMAND_BASS_UP 21 -#define APPCOMMAND_TREBLE_DOWN 22 -#define APPCOMMAND_TREBLE_UP 23 -#define APPCOMMAND_MICROPHONE_VOLUME_MUTE 24 -#define APPCOMMAND_MICROPHONE_VOLUME_DOWN 25 -#define APPCOMMAND_MICROPHONE_VOLUME_UP 26 -#define APPCOMMAND_HELP 27 -#define APPCOMMAND_FIND 28 -#define APPCOMMAND_NEW 29 -#define APPCOMMAND_OPEN 30 -#define APPCOMMAND_CLOSE 31 -#define APPCOMMAND_SAVE 32 -#define APPCOMMAND_PRINT 33 -#define APPCOMMAND_UNDO 34 -#define APPCOMMAND_REDO 35 -#define APPCOMMAND_COPY 36 -#define APPCOMMAND_CUT 37 -#define APPCOMMAND_PASTE 38 -#define APPCOMMAND_REPLY_TO_MAIL 39 -#define APPCOMMAND_FORWARD_MAIL 40 -#define APPCOMMAND_SEND_MAIL 41 -#define APPCOMMAND_SPELL_CHECK 42 -#define APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE 43 -#define APPCOMMAND_MIC_ON_OFF_TOGGLE 44 -#define APPCOMMAND_CORRECTION_LIST 45 -#define APPCOMMAND_MEDIA_PLAY 46 -#define APPCOMMAND_MEDIA_PAUSE 47 -#define APPCOMMAND_MEDIA_RECORD 48 -#define APPCOMMAND_MEDIA_FAST_FORWARD 49 -#define APPCOMMAND_MEDIA_REWIND 50 -#define APPCOMMAND_MEDIA_CHANNEL_UP 51 -#define APPCOMMAND_MEDIA_CHANNEL_DOWN 52 - -#define FAPPCOMMAND_MOUSE 0x8000 -#define FAPPCOMMAND_KEY 0 -#define FAPPCOMMAND_OEM 0x1000 -#define FAPPCOMMAND_MASK 0xF000 - -#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK)) -#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK)) -#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM -#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam)) -#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam) - - typedef struct { - HWND hwnd; - RECT rc; - } SHELLHOOKINFO,*LPSHELLHOOKINFO; - - typedef struct tagEVENTMSG { - UINT message; - UINT paramL; - UINT paramH; - DWORD time; - HWND hwnd; - } EVENTMSG,*PEVENTMSGMSG,*NPEVENTMSGMSG,*LPEVENTMSGMSG; - - typedef struct tagEVENTMSG *PEVENTMSG,*NPEVENTMSG,*LPEVENTMSG; - - typedef struct tagCWPSTRUCT { - LPARAM lParam; - WPARAM wParam; - UINT message; - HWND hwnd; - } CWPSTRUCT,*PCWPSTRUCT,*NPCWPSTRUCT,*LPCWPSTRUCT; - - typedef struct tagCWPRETSTRUCT { - LRESULT lResult; - LPARAM lParam; - WPARAM wParam; - UINT message; - HWND hwnd; - } CWPRETSTRUCT,*PCWPRETSTRUCT,*NPCWPRETSTRUCT,*LPCWPRETSTRUCT; - -#define LLKHF_EXTENDED (KF_EXTENDED >> 8) -#define LLKHF_INJECTED 0x00000010 -#define LLKHF_ALTDOWN (KF_ALTDOWN >> 8) -#define LLKHF_UP (KF_UP >> 8) - -#define LLMHF_INJECTED 0x00000001 - - typedef struct tagKBDLLHOOKSTRUCT { - DWORD vkCode; - DWORD scanCode; - DWORD flags; - DWORD time; - ULONG_PTR dwExtraInfo; - } KBDLLHOOKSTRUCT,*LPKBDLLHOOKSTRUCT,*PKBDLLHOOKSTRUCT; - - typedef struct tagMSLLHOOKSTRUCT { - POINT pt; - DWORD mouseData; - DWORD flags; - DWORD time; - ULONG_PTR dwExtraInfo; - } MSLLHOOKSTRUCT,*LPMSLLHOOKSTRUCT,*PMSLLHOOKSTRUCT; - - typedef struct tagDEBUGHOOKINFO { - DWORD idThread; - DWORD idThreadInstaller; - LPARAM lParam; - WPARAM wParam; - int code; - } DEBUGHOOKINFO,*PDEBUGHOOKINFO,*NPDEBUGHOOKINFO,*LPDEBUGHOOKINFO; - - typedef struct tagMOUSEHOOKSTRUCT { - POINT pt; - HWND hwnd; - UINT wHitTestCode; - ULONG_PTR dwExtraInfo; - } MOUSEHOOKSTRUCT,*LPMOUSEHOOKSTRUCT,*PMOUSEHOOKSTRUCT; - -#ifdef __cplusplus - typedef struct tagMOUSEHOOKSTRUCTEX : public tagMOUSEHOOKSTRUCT { - DWORD mouseData; - } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; -#else - typedef struct tagMOUSEHOOKSTRUCTEX { - MOUSEHOOKSTRUCT _unnamed; - DWORD mouseData; - } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; -#endif - - typedef struct tagHARDWAREHOOKSTRUCT { - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; - } HARDWAREHOOKSTRUCT,*LPHARDWAREHOOKSTRUCT,*PHARDWAREHOOKSTRUCT; -#endif - -#define HKL_PREV 0 -#define HKL_NEXT 1 - -#define KLF_ACTIVATE 0x00000001 -#define KLF_SUBSTITUTE_OK 0x00000002 -#define KLF_REORDER 0x00000008 -#define KLF_REPLACELANG 0x00000010 -#define KLF_NOTELLSHELL 0x00000080 -#define KLF_SETFORPROCESS 0x00000100 -#define KLF_SHIFTLOCK 0x00010000 -#define KLF_RESET 0x40000000 - -#define INPUTLANGCHANGE_SYSCHARSET 0x0001 -#define INPUTLANGCHANGE_FORWARD 0x0002 -#define INPUTLANGCHANGE_BACKWARD 0x0004 - -#define KL_NAMELENGTH 9 - -#ifdef UNICODE -#define LoadKeyboardLayout LoadKeyboardLayoutW -#define GetKeyboardLayoutName GetKeyboardLayoutNameW -#else -#define LoadKeyboardLayout LoadKeyboardLayoutA -#define GetKeyboardLayoutName GetKeyboardLayoutNameA -#endif - - WINUSERAPI HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID,UINT Flags); - WINUSERAPI HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID,UINT Flags); - WINUSERAPI HKL WINAPI ActivateKeyboardLayout(HKL hkl,UINT Flags); - WINUSERAPI int WINAPI ToUnicodeEx(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags,HKL dwhkl); - WINUSERAPI WINBOOL WINAPI UnloadKeyboardLayout(HKL hkl); - WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameA(LPSTR pwszKLID); - WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID); - WINUSERAPI int WINAPI GetKeyboardLayoutList(int nBuff,HKL *lpList); - WINUSERAPI HKL WINAPI GetKeyboardLayout(DWORD idThread); - - typedef struct tagMOUSEMOVEPOINT { - int x; - int y; - DWORD time; - ULONG_PTR dwExtraInfo; - } MOUSEMOVEPOINT,*PMOUSEMOVEPOINT,*LPMOUSEMOVEPOINT; - -#define GMMP_USE_DISPLAY_POINTS 1 -#define GMMP_USE_HIGH_RESOLUTION_POINTS 2 - - WINUSERAPI int WINAPI GetMouseMovePointsEx(UINT cbSize,LPMOUSEMOVEPOINT lppt,LPMOUSEMOVEPOINT lpptBuf,int nBufPoints,DWORD resolution); - -#ifndef NODESKTOP - -#define DESKTOP_READOBJECTS 0x0001L -#define DESKTOP_CREATEWINDOW 0x0002L -#define DESKTOP_CREATEMENU 0x0004L -#define DESKTOP_HOOKCONTROL 0x0008L -#define DESKTOP_JOURNALRECORD 0x0010L -#define DESKTOP_JOURNALPLAYBACK 0x0020L -#define DESKTOP_ENUMERATE 0x0040L -#define DESKTOP_WRITEOBJECTS 0x0080L -#define DESKTOP_SWITCHDESKTOP 0x0100L - -#define DF_ALLOWOTHERACCOUNTHOOK 0x0001L - -#ifdef _WINGDI_ -#ifndef NOGDI -#ifdef UNICODE -#define CreateDesktop CreateDesktopW -#else -#define CreateDesktop CreateDesktopA -#endif - - WINUSERAPI HDESK WINAPI CreateDesktopA(LPCSTR lpszDesktop,LPCSTR lpszDevice,LPDEVMODEA pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); - WINUSERAPI HDESK WINAPI CreateDesktopW(LPCWSTR lpszDesktop,LPCWSTR lpszDevice,LPDEVMODEW pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); -#endif -#endif - -#ifdef UNICODE -#define OpenDesktop OpenDesktopW -#define EnumDesktops EnumDesktopsW -#else -#define OpenDesktop OpenDesktopA -#define EnumDesktops EnumDesktopsA -#endif - - WINUSERAPI HDESK WINAPI OpenDesktopA(LPCSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI HDESK WINAPI OpenDesktopW(LPCWSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI HDESK WINAPI OpenInputDesktop(DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI WINBOOL WINAPI EnumDesktopsA(HWINSTA hwinsta,DESKTOPENUMPROCA lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumDesktopsW(HWINSTA hwinsta,DESKTOPENUMPROCW lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumDesktopWindows(HDESK hDesktop,WNDENUMPROC lpfn,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI SwitchDesktop(HDESK hDesktop); - WINUSERAPI WINBOOL WINAPI SetThreadDesktop(HDESK hDesktop); - WINUSERAPI WINBOOL WINAPI CloseDesktop(HDESK hDesktop); - WINUSERAPI HDESK WINAPI GetThreadDesktop(DWORD dwThreadId); -#endif - -#ifndef NOWINDOWSTATION -#define WINSTA_ENUMDESKTOPS 0x0001L -#define WINSTA_READATTRIBUTES 0x0002L -#define WINSTA_ACCESSCLIPBOARD 0x0004L -#define WINSTA_CREATEDESKTOP 0x0008L -#define WINSTA_WRITEATTRIBUTES 0x0010L -#define WINSTA_ACCESSGLOBALATOMS 0x0020L -#define WINSTA_EXITWINDOWS 0x0040L -#define WINSTA_ENUMERATE 0x0100L -#define WINSTA_READSCREEN 0x0200L -#define WINSTA_ALL_ACCESS (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN) - -#define CWF_CREATE_ONLY 0x0001L - -#define WSF_VISIBLE 0x0001L - -#ifdef UNICODE -#define CreateWindowStation CreateWindowStationW -#define OpenWindowStation OpenWindowStationW -#define EnumWindowStations EnumWindowStationsW -#else -#define CreateWindowStation CreateWindowStationA -#define OpenWindowStation OpenWindowStationA -#define EnumWindowStations EnumWindowStationsA -#endif - - WINUSERAPI HWINSTA WINAPI CreateWindowStationA(LPCSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); - WINUSERAPI HWINSTA WINAPI CreateWindowStationW(LPCWSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); - WINUSERAPI HWINSTA WINAPI OpenWindowStationA(LPCSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI HWINSTA WINAPI OpenWindowStationW(LPCWSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI WINBOOL WINAPI EnumWindowStationsA(WINSTAENUMPROCA lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumWindowStationsW(WINSTAENUMPROCW lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI CloseWindowStation(HWINSTA hWinSta); - WINUSERAPI WINBOOL WINAPI SetProcessWindowStation(HWINSTA hWinSta); - WINUSERAPI HWINSTA WINAPI GetProcessWindowStation(VOID); -#endif - -#ifndef NOSECURITY - WINUSERAPI WINBOOL WINAPI SetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID); - WINUSERAPI WINBOOL WINAPI GetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID,DWORD nLength,LPDWORD lpnLengthNeeded); - -#define UOI_FLAGS 1 -#define UOI_NAME 2 -#define UOI_TYPE 3 -#define UOI_USER_SID 4 - - typedef struct tagUSEROBJECTFLAGS { - WINBOOL fInherit; - WINBOOL fReserved; - DWORD dwFlags; - } USEROBJECTFLAGS,*PUSEROBJECTFLAGS; - -#ifdef UNICODE -#define GetUserObjectInformation GetUserObjectInformationW -#define SetUserObjectInformation SetUserObjectInformationW -#else -#define GetUserObjectInformation GetUserObjectInformationA -#define SetUserObjectInformation SetUserObjectInformationA -#endif - - WINUSERAPI WINBOOL WINAPI GetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); - WINUSERAPI WINBOOL WINAPI GetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); - WINUSERAPI WINBOOL WINAPI SetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); - WINUSERAPI WINBOOL WINAPI SetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); -#endif - - typedef struct tagWNDCLASSEXA { - UINT cbSize; - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCSTR lpszMenuName; - LPCSTR lpszClassName; - HICON hIconSm; - } WNDCLASSEXA,*PWNDCLASSEXA,*NPWNDCLASSEXA,*LPWNDCLASSEXA; - - typedef struct tagWNDCLASSEXW { - UINT cbSize; - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCWSTR lpszMenuName; - LPCWSTR lpszClassName; - - HICON hIconSm; - } WNDCLASSEXW,*PWNDCLASSEXW,*NPWNDCLASSEXW,*LPWNDCLASSEXW; - -#ifdef UNICODE - typedef WNDCLASSEXW WNDCLASSEX; - typedef PWNDCLASSEXW PWNDCLASSEX; - typedef NPWNDCLASSEXW NPWNDCLASSEX; - typedef LPWNDCLASSEXW LPWNDCLASSEX; -#else - typedef WNDCLASSEXA WNDCLASSEX; - typedef PWNDCLASSEXA PWNDCLASSEX; - typedef NPWNDCLASSEXA NPWNDCLASSEX; - typedef LPWNDCLASSEXA LPWNDCLASSEX; -#endif - - typedef struct tagWNDCLASSA { - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCSTR lpszMenuName; - LPCSTR lpszClassName; - } WNDCLASSA,*PWNDCLASSA,*NPWNDCLASSA,*LPWNDCLASSA; - - typedef struct tagWNDCLASSW { - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCWSTR lpszMenuName; - LPCWSTR lpszClassName; - } WNDCLASSW,*PWNDCLASSW,*NPWNDCLASSW,*LPWNDCLASSW; - -#ifdef UNICODE - typedef WNDCLASSW WNDCLASS; - typedef PWNDCLASSW PWNDCLASS; - typedef NPWNDCLASSW NPWNDCLASS; - typedef LPWNDCLASSW LPWNDCLASS; -#else - typedef WNDCLASSA WNDCLASS; - typedef PWNDCLASSA PWNDCLASS; - typedef NPWNDCLASSA NPWNDCLASS; - typedef LPWNDCLASSA LPWNDCLASS; -#endif - - WINUSERAPI WINBOOL WINAPI IsHungAppWindow(HWND hwnd); - WINUSERAPI VOID WINAPI DisableProcessWindowsGhosting(VOID); - -#ifndef NOMSG - typedef struct tagMSG { - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; - DWORD time; - POINT pt; - } MSG,*PMSG,*NPMSG,*LPMSG; - -#define POINTSTOPOINT(pt,pts) { (pt).x = (LONG)(SHORT)LOWORD(*(LONG*)&pts); (pt).y = (LONG)(SHORT)HIWORD(*(LONG*)&pts); } - -#define POINTTOPOINTS(pt) (MAKELONG((short)((pt).x),(short)((pt).y))) -#define MAKEWPARAM(l,h) ((WPARAM)(DWORD)MAKELONG(l,h)) -#define MAKELPARAM(l,h) ((LPARAM)(DWORD)MAKELONG(l,h)) -#define MAKELRESULT(l,h) ((LRESULT)(DWORD)MAKELONG(l,h)) -#endif - -#ifndef NOWINOFFSETS -#define GWL_WNDPROC (-4) -#define GWL_HINSTANCE (-6) -#define GWL_HWNDPARENT (-8) -#define GWL_STYLE (-16) -#define GWL_EXSTYLE (-20) -#define GWL_USERDATA (-21) -#define GWL_ID (-12) - -#ifdef _WIN64 -#undef GWL_WNDPROC -#undef GWL_HINSTANCE -#undef GWL_HWNDPARENT -#undef GWL_USERDATA -#endif - -#define GWLP_WNDPROC (-4) -#define GWLP_HINSTANCE (-6) -#define GWLP_HWNDPARENT (-8) -#define GWLP_USERDATA (-21) -#define GWLP_ID (-12) - -#define GCL_MENUNAME (-8) -#define GCL_HBRBACKGROUND (-10) -#define GCL_HCURSOR (-12) -#define GCL_HICON (-14) -#define GCL_HMODULE (-16) -#define GCL_CBWNDEXTRA (-18) -#define GCL_CBCLSEXTRA (-20) -#define GCL_WNDPROC (-24) -#define GCL_STYLE (-26) -#define GCW_ATOM (-32) -#define GCL_HICONSM (-34) - -#ifdef _WIN64 - -#undef GCL_MENUNAME -#undef GCL_HBRBACKGROUND -#undef GCL_HCURSOR -#undef GCL_HICON -#undef GCL_HMODULE -#undef GCL_WNDPROC -#undef GCL_HICONSM -#endif - -#define GCLP_MENUNAME (-8) -#define GCLP_HBRBACKGROUND (-10) -#define GCLP_HCURSOR (-12) -#define GCLP_HICON (-14) -#define GCLP_HMODULE (-16) -#define GCLP_WNDPROC (-24) -#define GCLP_HICONSM (-34) -#endif - -#ifndef NOWINMESSAGES - -#define WM_NULL 0x0000 -#define WM_CREATE 0x0001 -#define WM_DESTROY 0x0002 -#define WM_MOVE 0x0003 -#define WM_SIZE 0x0005 - -#define WM_ACTIVATE 0x0006 - -#define WA_INACTIVE 0 -#define WA_ACTIVE 1 -#define WA_CLICKACTIVE 2 - -#define WM_SETFOCUS 0x0007 -#define WM_KILLFOCUS 0x0008 -#define WM_ENABLE 0x000A -#define WM_SETREDRAW 0x000B -#define WM_SETTEXT 0x000C -#define WM_GETTEXT 0x000D -#define WM_GETTEXTLENGTH 0x000E -#define WM_PAINT 0x000F -#define WM_CLOSE 0x0010 -#ifndef _WIN32_WCE -#define WM_QUERYENDSESSION 0x0011 -#define WM_QUERYOPEN 0x0013 -#define WM_ENDSESSION 0x0016 -#endif -#define WM_QUIT 0x0012 -#define WM_ERASEBKGND 0x0014 -#define WM_SYSCOLORCHANGE 0x0015 -#define WM_SHOWWINDOW 0x0018 -#define WM_WININICHANGE 0x001A -#define WM_SETTINGCHANGE WM_WININICHANGE -#define WM_DEVMODECHANGE 0x001B -#define WM_ACTIVATEAPP 0x001C -#define WM_FONTCHANGE 0x001D -#define WM_TIMECHANGE 0x001E -#define WM_CANCELMODE 0x001F -#define WM_SETCURSOR 0x0020 -#define WM_MOUSEACTIVATE 0x0021 -#define WM_CHILDACTIVATE 0x0022 -#define WM_QUEUESYNC 0x0023 - -#define WM_GETMINMAXINFO 0x0024 - - typedef struct tagMINMAXINFO { - POINT ptReserved; - POINT ptMaxSize; - POINT ptMaxPosition; - POINT ptMinTrackSize; - POINT ptMaxTrackSize; - } MINMAXINFO,*PMINMAXINFO,*LPMINMAXINFO; - -#define WM_PAINTICON 0x0026 -#define WM_ICONERASEBKGND 0x0027 -#define WM_NEXTDLGCTL 0x0028 -#define WM_SPOOLERSTATUS 0x002A -#define WM_DRAWITEM 0x002B -#define WM_MEASUREITEM 0x002C -#define WM_DELETEITEM 0x002D -#define WM_VKEYTOITEM 0x002E -#define WM_CHARTOITEM 0x002F -#define WM_SETFONT 0x0030 -#define WM_GETFONT 0x0031 -#define WM_SETHOTKEY 0x0032 -#define WM_GETHOTKEY 0x0033 -#define WM_QUERYDRAGICON 0x0037 -#define WM_COMPAREITEM 0x0039 -#ifndef _WIN32_WCE -#define WM_GETOBJECT 0x003D -#endif -#define WM_COMPACTING 0x0041 -#define WM_COMMNOTIFY 0x0044 -#define WM_WINDOWPOSCHANGING 0x0046 -#define WM_WINDOWPOSCHANGED 0x0047 - -#define WM_POWER 0x0048 - -#define PWR_OK 1 -#define PWR_FAIL (-1) -#define PWR_SUSPENDREQUEST 1 -#define PWR_SUSPENDRESUME 2 -#define PWR_CRITICALRESUME 3 - -#define WM_COPYDATA 0x004A -#define WM_CANCELJOURNAL 0x004B - - typedef struct tagCOPYDATASTRUCT { - ULONG_PTR dwData; - DWORD cbData; - PVOID lpData; - } COPYDATASTRUCT,*PCOPYDATASTRUCT; - - typedef struct tagMDINEXTMENU { - HMENU hmenuIn; - HMENU hmenuNext; - HWND hwndNext; - } MDINEXTMENU,*PMDINEXTMENU,*LPMDINEXTMENU; - -#define WM_NOTIFY 0x004E -#define WM_INPUTLANGCHANGEREQUEST 0x0050 -#define WM_INPUTLANGCHANGE 0x0051 -#define WM_TCARD 0x0052 -#define WM_HELP 0x0053 -#define WM_USERCHANGED 0x0054 -#define WM_NOTIFYFORMAT 0x0055 - -#define NFR_ANSI 1 -#define NFR_UNICODE 2 -#define NF_QUERY 3 -#define NF_REQUERY 4 - -#define WM_CONTEXTMENU 0x007B -#define WM_STYLECHANGING 0x007C -#define WM_STYLECHANGED 0x007D -#define WM_DISPLAYCHANGE 0x007E -#define WM_GETICON 0x007F -#define WM_SETICON 0x0080 - -#define WM_NCCREATE 0x0081 -#define WM_NCDESTROY 0x0082 -#define WM_NCCALCSIZE 0x0083 -#define WM_NCHITTEST 0x0084 -#define WM_NCPAINT 0x0085 -#define WM_NCACTIVATE 0x0086 -#define WM_GETDLGCODE 0x0087 -#ifndef _WIN32_WCE -#define WM_SYNCPAINT 0x0088 -#endif -#define WM_NCMOUSEMOVE 0x00A0 -#define WM_NCLBUTTONDOWN 0x00A1 -#define WM_NCLBUTTONUP 0x00A2 -#define WM_NCLBUTTONDBLCLK 0x00A3 -#define WM_NCRBUTTONDOWN 0x00A4 -#define WM_NCRBUTTONUP 0x00A5 -#define WM_NCRBUTTONDBLCLK 0x00A6 -#define WM_NCMBUTTONDOWN 0x00A7 -#define WM_NCMBUTTONUP 0x00A8 -#define WM_NCMBUTTONDBLCLK 0x00A9 - -#define WM_NCXBUTTONDOWN 0x00AB -#define WM_NCXBUTTONUP 0x00AC -#define WM_NCXBUTTONDBLCLK 0x00AD -#define WM_INPUT 0x00FF -#define WM_KEYFIRST 0x0100 -#define WM_KEYDOWN 0x0100 -#define WM_KEYUP 0x0101 -#define WM_CHAR 0x0102 -#define WM_DEADCHAR 0x0103 -#define WM_SYSKEYDOWN 0x0104 -#define WM_SYSKEYUP 0x0105 -#define WM_SYSCHAR 0x0106 -#define WM_SYSDEADCHAR 0x0107 -#define WM_UNICHAR 0x0109 -#define WM_KEYLAST 0x0109 -#define UNICODE_NOCHAR 0xFFFF -#define WM_IME_STARTCOMPOSITION 0x010D -#define WM_IME_ENDCOMPOSITION 0x010E -#define WM_IME_COMPOSITION 0x010F -#define WM_IME_KEYLAST 0x010F -#define WM_INITDIALOG 0x0110 -#define WM_COMMAND 0x0111 -#define WM_SYSCOMMAND 0x0112 -#define WM_TIMER 0x0113 -#define WM_HSCROLL 0x0114 -#define WM_VSCROLL 0x0115 -#define WM_INITMENU 0x0116 -#define WM_INITMENUPOPUP 0x0117 -#define WM_MENUSELECT 0x011F -#define WM_MENUCHAR 0x0120 -#define WM_ENTERIDLE 0x0121 -#ifndef _WIN32_WCE -#define WM_MENURBUTTONUP 0x0122 -#define WM_MENUDRAG 0x0123 -#define WM_MENUGETOBJECT 0x0124 -#define WM_UNINITMENUPOPUP 0x0125 -#define WM_MENUCOMMAND 0x0126 - -#ifndef _WIN32_WCE -#define WM_CHANGEUISTATE 0x0127 -#define WM_UPDATEUISTATE 0x0128 -#define WM_QUERYUISTATE 0x0129 - -#define UIS_SET 1 -#define UIS_CLEAR 2 -#define UIS_INITIALIZE 3 - -#define UISF_HIDEFOCUS 0x1 -#define UISF_HIDEACCEL 0x2 -#define UISF_ACTIVE 0x4 -#endif -#endif - -#define WM_CTLCOLORMSGBOX 0x0132 -#define WM_CTLCOLOREDIT 0x0133 -#define WM_CTLCOLORLISTBOX 0x0134 -#define WM_CTLCOLORBTN 0x0135 -#define WM_CTLCOLORDLG 0x0136 -#define WM_CTLCOLORSCROLLBAR 0x0137 -#define WM_CTLCOLORSTATIC 0x0138 -#define MN_GETHMENU 0x01E1 - -#define WM_MOUSEFIRST 0x0200 -#define WM_MOUSEMOVE 0x0200 -#define WM_LBUTTONDOWN 0x0201 -#define WM_LBUTTONUP 0x0202 -#define WM_LBUTTONDBLCLK 0x0203 -#define WM_RBUTTONDOWN 0x0204 -#define WM_RBUTTONUP 0x0205 -#define WM_RBUTTONDBLCLK 0x0206 -#define WM_MBUTTONDOWN 0x0207 -#define WM_MBUTTONUP 0x0208 -#define WM_MBUTTONDBLCLK 0x0209 -#define WM_MOUSEWHEEL 0x020A -#define WM_XBUTTONDOWN 0x020B -#define WM_XBUTTONUP 0x020C -#define WM_XBUTTONDBLCLK 0x020D -#define WM_MOUSELAST 0x020D - -#define WHEEL_DELTA 120 -#define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) - -#define WHEEL_PAGESCROLL (UINT_MAX) - -#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam)) -#define GET_NCHITTEST_WPARAM(wParam) ((short)LOWORD(wParam)) -#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) - -#define XBUTTON1 0x0001 -#define XBUTTON2 0x0002 - -#define WM_PARENTNOTIFY 0x0210 -#define WM_ENTERMENULOOP 0x0211 -#define WM_EXITMENULOOP 0x0212 - -#define WM_NEXTMENU 0x0213 -#define WM_SIZING 0x0214 -#define WM_CAPTURECHANGED 0x0215 -#define WM_MOVING 0x0216 - -#define WM_POWERBROADCAST 0x0218 - -#ifndef _WIN32_WCE -#define PBT_APMQUERYSUSPEND 0x0000 -#define PBT_APMQUERYSTANDBY 0x0001 - -#define PBT_APMQUERYSUSPENDFAILED 0x0002 -#define PBT_APMQUERYSTANDBYFAILED 0x0003 - -#define PBT_APMSUSPEND 0x0004 -#define PBT_APMSTANDBY 0x0005 - -#define PBT_APMRESUMECRITICAL 0x0006 -#define PBT_APMRESUMESUSPEND 0x0007 -#define PBT_APMRESUMESTANDBY 0x0008 - -#define PBTF_APMRESUMEFROMFAILURE 0x00000001 - -#define PBT_APMBATTERYLOW 0x0009 -#define PBT_APMPOWERSTATUSCHANGE 0x000A - -#define PBT_APMOEMEVENT 0x000B -#define PBT_APMRESUMEAUTOMATIC 0x0012 -#endif - -#define WM_DEVICECHANGE 0x0219 - -#define WM_MDICREATE 0x0220 -#define WM_MDIDESTROY 0x0221 -#define WM_MDIACTIVATE 0x0222 -#define WM_MDIRESTORE 0x0223 -#define WM_MDINEXT 0x0224 -#define WM_MDIMAXIMIZE 0x0225 -#define WM_MDITILE 0x0226 -#define WM_MDICASCADE 0x0227 -#define WM_MDIICONARRANGE 0x0228 -#define WM_MDIGETACTIVE 0x0229 - -#define WM_MDISETMENU 0x0230 -#define WM_ENTERSIZEMOVE 0x0231 -#define WM_EXITSIZEMOVE 0x0232 -#define WM_DROPFILES 0x0233 -#define WM_MDIREFRESHMENU 0x0234 - -#define WM_IME_SETCONTEXT 0x0281 -#define WM_IME_NOTIFY 0x0282 -#define WM_IME_CONTROL 0x0283 -#define WM_IME_COMPOSITIONFULL 0x0284 -#define WM_IME_SELECT 0x0285 -#define WM_IME_CHAR 0x0286 -#define WM_IME_REQUEST 0x0288 -#define WM_IME_KEYDOWN 0x0290 -#define WM_IME_KEYUP 0x0291 - -#define WM_MOUSEHOVER 0x02A1 -#define WM_MOUSELEAVE 0x02A3 -#define WM_NCMOUSEHOVER 0x02A0 -#define WM_NCMOUSELEAVE 0x02A2 -#define WM_WTSSESSION_CHANGE 0x02B1 -#define WM_TABLET_FIRST 0x02c0 -#define WM_TABLET_LAST 0x02df -#define WM_CUT 0x0300 -#define WM_COPY 0x0301 -#define WM_PASTE 0x0302 -#define WM_CLEAR 0x0303 -#define WM_UNDO 0x0304 -#define WM_RENDERFORMAT 0x0305 -#define WM_RENDERALLFORMATS 0x0306 -#define WM_DESTROYCLIPBOARD 0x0307 -#define WM_DRAWCLIPBOARD 0x0308 -#define WM_PAINTCLIPBOARD 0x0309 -#define WM_VSCROLLCLIPBOARD 0x030A -#define WM_SIZECLIPBOARD 0x030B -#define WM_ASKCBFORMATNAME 0x030C -#define WM_CHANGECBCHAIN 0x030D -#define WM_HSCROLLCLIPBOARD 0x030E -#define WM_QUERYNEWPALETTE 0x030F -#define WM_PALETTEISCHANGING 0x0310 -#define WM_PALETTECHANGED 0x0311 -#define WM_HOTKEY 0x0312 -#define WM_PRINT 0x0317 -#define WM_PRINTCLIENT 0x0318 -#define WM_APPCOMMAND 0x0319 -#define WM_THEMECHANGED 0x031A -#define WM_HANDHELDFIRST 0x0358 -#define WM_HANDHELDLAST 0x035F -#define WM_AFXFIRST 0x0360 -#define WM_AFXLAST 0x037F -#define WM_PENWINFIRST 0x0380 -#define WM_PENWINLAST 0x038F -#define WM_APP 0x8000 -#define WM_USER 0x0400 - -#define WMSZ_LEFT 1 -#define WMSZ_RIGHT 2 -#define WMSZ_TOP 3 -#define WMSZ_TOPLEFT 4 -#define WMSZ_TOPRIGHT 5 -#define WMSZ_BOTTOM 6 -#define WMSZ_BOTTOMLEFT 7 -#define WMSZ_BOTTOMRIGHT 8 - -#ifndef NONCMESSAGES - -#define HTERROR (-2) -#define HTTRANSPARENT (-1) -#define HTNOWHERE 0 -#define HTCLIENT 1 -#define HTCAPTION 2 -#define HTSYSMENU 3 -#define HTGROWBOX 4 -#define HTSIZE HTGROWBOX -#define HTMENU 5 -#define HTHSCROLL 6 -#define HTVSCROLL 7 -#define HTMINBUTTON 8 -#define HTMAXBUTTON 9 -#define HTLEFT 10 -#define HTRIGHT 11 -#define HTTOP 12 -#define HTTOPLEFT 13 -#define HTTOPRIGHT 14 -#define HTBOTTOM 15 -#define HTBOTTOMLEFT 16 -#define HTBOTTOMRIGHT 17 -#define HTBORDER 18 -#define HTREDUCE HTMINBUTTON -#define HTZOOM HTMAXBUTTON -#define HTSIZEFIRST HTLEFT -#define HTSIZELAST HTBOTTOMRIGHT -#define HTOBJECT 19 -#define HTCLOSE 20 -#define HTHELP 21 - -#define SMTO_NORMAL 0x0000 -#define SMTO_BLOCK 0x0001 -#define SMTO_ABORTIFHUNG 0x0002 -#define SMTO_NOTIMEOUTIFNOTHUNG 0x0008 -#endif - -#define MA_ACTIVATE 1 -#define MA_ACTIVATEANDEAT 2 -#define MA_NOACTIVATE 3 -#define MA_NOACTIVATEANDEAT 4 - -#define ICON_SMALL 0 -#define ICON_BIG 1 -#define ICON_SMALL2 2 - -#ifdef UNICODE -#define RegisterWindowMessage RegisterWindowMessageW -#else -#define RegisterWindowMessage RegisterWindowMessageA -#endif - - WINUSERAPI UINT WINAPI RegisterWindowMessageA(LPCSTR lpString); - WINUSERAPI UINT WINAPI RegisterWindowMessageW(LPCWSTR lpString); - -#define SIZE_RESTORED 0 -#define SIZE_MINIMIZED 1 -#define SIZE_MAXIMIZED 2 -#define SIZE_MAXSHOW 3 -#define SIZE_MAXHIDE 4 - -#define SIZENORMAL SIZE_RESTORED -#define SIZEICONIC SIZE_MINIMIZED -#define SIZEFULLSCREEN SIZE_MAXIMIZED -#define SIZEZOOMSHOW SIZE_MAXSHOW -#define SIZEZOOMHIDE SIZE_MAXHIDE - - typedef struct tagWINDOWPOS { - HWND hwnd; - HWND hwndInsertAfter; - int x; - int y; - int cx; - int cy; - UINT flags; - } WINDOWPOS,*LPWINDOWPOS,*PWINDOWPOS; - - typedef struct tagNCCALCSIZE_PARAMS { - RECT rgrc[3]; - PWINDOWPOS lppos; - } NCCALCSIZE_PARAMS,*LPNCCALCSIZE_PARAMS; - -#define WVR_ALIGNTOP 0x0010 -#define WVR_ALIGNLEFT 0x0020 -#define WVR_ALIGNBOTTOM 0x0040 -#define WVR_ALIGNRIGHT 0x0080 -#define WVR_HREDRAW 0x0100 -#define WVR_VREDRAW 0x0200 -#define WVR_REDRAW (WVR_HREDRAW | WVR_VREDRAW) -#define WVR_VALIDRECTS 0x0400 - -#ifndef NOKEYSTATES - -#define MK_LBUTTON 0x0001 -#define MK_RBUTTON 0x0002 -#define MK_SHIFT 0x0004 -#define MK_CONTROL 0x0008 -#define MK_MBUTTON 0x0010 -#define MK_XBUTTON1 0x0020 -#define MK_XBUTTON2 0x0040 -#endif - -#ifndef NOTRACKMOUSEEVENT -#define TME_HOVER 0x00000001 -#define TME_LEAVE 0x00000002 -#define TME_NONCLIENT 0x00000010 -#define TME_QUERY 0x40000000 -#define TME_CANCEL 0x80000000 - -#define HOVER_DEFAULT 0xFFFFFFFF -#endif - - typedef struct tagTRACKMOUSEEVENT { - DWORD cbSize; - DWORD dwFlags; - HWND hwndTrack; - DWORD dwHoverTime; - } TRACKMOUSEEVENT,*LPTRACKMOUSEEVENT; - - WINUSERAPI WINBOOL WINAPI TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack); -#endif - -#ifndef NOWINSTYLES - -#define WS_OVERLAPPED 0x00000000L -#define WS_POPUP 0x80000000L -#define WS_CHILD 0x40000000L -#define WS_MINIMIZE 0x20000000L -#define WS_VISIBLE 0x10000000L -#define WS_DISABLED 0x08000000L -#define WS_CLIPSIBLINGS 0x04000000L -#define WS_CLIPCHILDREN 0x02000000L -#define WS_MAXIMIZE 0x01000000L -#define WS_CAPTION 0x00C00000L -#define WS_BORDER 0x00800000L -#define WS_DLGFRAME 0x00400000L -#define WS_VSCROLL 0x00200000L -#define WS_HSCROLL 0x00100000L -#define WS_SYSMENU 0x00080000L -#define WS_THICKFRAME 0x00040000L -#define WS_GROUP 0x00020000L -#define WS_TABSTOP 0x00010000L -#define WS_MINIMIZEBOX 0x00020000L -#define WS_MAXIMIZEBOX 0x00010000L -#define WS_TILED WS_OVERLAPPED -#define WS_ICONIC WS_MINIMIZE -#define WS_SIZEBOX WS_THICKFRAME -#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW -#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) -#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU) -#define WS_CHILDWINDOW (WS_CHILD) - -#define WS_EX_DLGMODALFRAME 0x00000001L -#define WS_EX_NOPARENTNOTIFY 0x00000004L -#define WS_EX_TOPMOST 0x00000008L -#define WS_EX_ACCEPTFILES 0x00000010L -#define WS_EX_TRANSPARENT 0x00000020L -#define WS_EX_MDICHILD 0x00000040L -#define WS_EX_TOOLWINDOW 0x00000080L -#define WS_EX_WINDOWEDGE 0x00000100L -#define WS_EX_CLIENTEDGE 0x00000200L -#define WS_EX_CONTEXTHELP 0x00000400L -#define WS_EX_RIGHT 0x00001000L -#define WS_EX_LEFT 0x00000000L -#define WS_EX_RTLREADING 0x00002000L -#define WS_EX_LTRREADING 0x00000000L -#define WS_EX_LEFTSCROLLBAR 0x00004000L -#define WS_EX_RIGHTSCROLLBAR 0x00000000L -#define WS_EX_CONTROLPARENT 0x00010000L -#define WS_EX_STATICEDGE 0x00020000L -#define WS_EX_APPWINDOW 0x00040000L -#define WS_EX_OVERLAPPEDWINDOW (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE) -#define WS_EX_PALETTEWINDOW (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST) -#define WS_EX_LAYERED 0x00080000 -#define WS_EX_NOINHERITLAYOUT 0x00100000L -#define WS_EX_LAYOUTRTL 0x00400000L -#define WS_EX_COMPOSITED 0x02000000L -#define WS_EX_NOACTIVATE 0x08000000L - -#define CS_VREDRAW 0x0001 -#define CS_HREDRAW 0x0002 -#define CS_DBLCLKS 0x0008 -#define CS_OWNDC 0x0020 -#define CS_CLASSDC 0x0040 -#define CS_PARENTDC 0x0080 -#define CS_NOCLOSE 0x0200 -#define CS_SAVEBITS 0x0800 -#define CS_BYTEALIGNCLIENT 0x1000 -#define CS_BYTEALIGNWINDOW 0x2000 -#define CS_GLOBALCLASS 0x4000 -#define CS_IME 0x00010000 -#define CS_DROPSHADOW 0x00020000 -#endif - -#define PRF_CHECKVISIBLE 0x00000001L -#define PRF_NONCLIENT 0x00000002L -#define PRF_CLIENT 0x00000004L -#define PRF_ERASEBKGND 0x00000008L -#define PRF_CHILDREN 0x00000010L -#define PRF_OWNED 0x00000020L - -#define BDR_RAISEDOUTER 0x0001 -#define BDR_SUNKENOUTER 0x0002 -#define BDR_RAISEDINNER 0x0004 -#define BDR_SUNKENINNER 0x0008 - -#define BDR_OUTER (BDR_RAISEDOUTER | BDR_SUNKENOUTER) -#define BDR_INNER (BDR_RAISEDINNER | BDR_SUNKENINNER) -#define BDR_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) -#define BDR_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) - -#define EDGE_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) -#define EDGE_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) -#define EDGE_ETCHED (BDR_SUNKENOUTER | BDR_RAISEDINNER) -#define EDGE_BUMP (BDR_RAISEDOUTER | BDR_SUNKENINNER) - -#define BF_LEFT 0x0001 -#define BF_TOP 0x0002 -#define BF_RIGHT 0x0004 -#define BF_BOTTOM 0x0008 - -#define BF_TOPLEFT (BF_TOP | BF_LEFT) -#define BF_TOPRIGHT (BF_TOP | BF_RIGHT) -#define BF_BOTTOMLEFT (BF_BOTTOM | BF_LEFT) -#define BF_BOTTOMRIGHT (BF_BOTTOM | BF_RIGHT) -#define BF_RECT (BF_LEFT | BF_TOP | BF_RIGHT | BF_BOTTOM) - -#define BF_DIAGONAL 0x0010 - -#define BF_DIAGONAL_ENDTOPRIGHT (BF_DIAGONAL | BF_TOP | BF_RIGHT) -#define BF_DIAGONAL_ENDTOPLEFT (BF_DIAGONAL | BF_TOP | BF_LEFT) -#define BF_DIAGONAL_ENDBOTTOMLEFT (BF_DIAGONAL | BF_BOTTOM | BF_LEFT) -#define BF_DIAGONAL_ENDBOTTOMRIGHT (BF_DIAGONAL | BF_BOTTOM | BF_RIGHT) - -#define BF_MIDDLE 0x0800 -#define BF_SOFT 0x1000 -#define BF_ADJUST 0x2000 -#define BF_FLAT 0x4000 -#define BF_MONO 0x8000 - - WINUSERAPI WINBOOL WINAPI DrawEdge(HDC hdc,LPRECT qrc,UINT edge,UINT grfFlags); - -#define DFC_CAPTION 1 -#define DFC_MENU 2 -#define DFC_SCROLL 3 -#define DFC_BUTTON 4 -#define DFC_POPUPMENU 5 - -#define DFCS_CAPTIONCLOSE 0x0000 -#define DFCS_CAPTIONMIN 0x0001 -#define DFCS_CAPTIONMAX 0x0002 -#define DFCS_CAPTIONRESTORE 0x0003 -#define DFCS_CAPTIONHELP 0x0004 - -#define DFCS_MENUARROW 0x0000 -#define DFCS_MENUCHECK 0x0001 -#define DFCS_MENUBULLET 0x0002 -#define DFCS_MENUARROWRIGHT 0x0004 -#define DFCS_SCROLLUP 0x0000 -#define DFCS_SCROLLDOWN 0x0001 -#define DFCS_SCROLLLEFT 0x0002 -#define DFCS_SCROLLRIGHT 0x0003 -#define DFCS_SCROLLCOMBOBOX 0x0005 -#define DFCS_SCROLLSIZEGRIP 0x0008 -#define DFCS_SCROLLSIZEGRIPRIGHT 0x0010 - -#define DFCS_BUTTONCHECK 0x0000 -#define DFCS_BUTTONRADIOIMAGE 0x0001 -#define DFCS_BUTTONRADIOMASK 0x0002 -#define DFCS_BUTTONRADIO 0x0004 -#define DFCS_BUTTON3STATE 0x0008 -#define DFCS_BUTTONPUSH 0x0010 - -#define DFCS_INACTIVE 0x0100 -#define DFCS_PUSHED 0x0200 -#define DFCS_CHECKED 0x0400 - -#define DFCS_TRANSPARENT 0x0800 -#define DFCS_HOT 0x1000 - -#define DFCS_ADJUSTRECT 0x2000 -#define DFCS_FLAT 0x4000 -#define DFCS_MONO 0x8000 - - WINUSERAPI WINBOOL WINAPI DrawFrameControl(HDC,LPRECT,UINT,UINT); - -#define DC_ACTIVE 0x0001 -#define DC_SMALLCAP 0x0002 -#define DC_ICON 0x0004 -#define DC_TEXT 0x0008 -#define DC_INBUTTON 0x0010 -#define DC_GRADIENT 0x0020 -#define DC_BUTTONS 0x1000 - - WINUSERAPI WINBOOL WINAPI DrawCaption(HWND hwnd,HDC hdc,CONST RECT *lprect,UINT flags); - -#define IDANI_OPEN 1 -#define IDANI_CAPTION 3 - - WINUSERAPI WINBOOL WINAPI DrawAnimatedRects(HWND hwnd,int idAni,CONST RECT *lprcFrom,CONST RECT *lprcTo); - -#ifndef NOCLIPBOARD - -#define CF_TEXT 1 -#define CF_BITMAP 2 -#define CF_METAFILEPICT 3 -#define CF_SYLK 4 -#define CF_DIF 5 -#define CF_TIFF 6 -#define CF_OEMTEXT 7 -#define CF_DIB 8 -#define CF_PALETTE 9 -#define CF_PENDATA 10 -#define CF_RIFF 11 -#define CF_WAVE 12 -#define CF_UNICODETEXT 13 -#define CF_ENHMETAFILE 14 -#define CF_HDROP 15 -#define CF_LOCALE 16 -#define CF_DIBV5 17 -#define CF_MAX 18 - -#define CF_OWNERDISPLAY 0x0080 -#define CF_DSPTEXT 0x0081 -#define CF_DSPBITMAP 0x0082 -#define CF_DSPMETAFILEPICT 0x0083 -#define CF_DSPENHMETAFILE 0x008E - -#define CF_PRIVATEFIRST 0x0200 -#define CF_PRIVATELAST 0x02FF - -#define CF_GDIOBJFIRST 0x0300 -#define CF_GDIOBJLAST 0x03FF -#endif - -#define FVIRTKEY TRUE -#define FNOINVERT 0x02 -#define FSHIFT 0x04 -#define FCONTROL 0x08 -#define FALT 0x10 - - typedef struct tagACCEL { - BYTE fVirt; - WORD key; - WORD cmd; - } ACCEL,*LPACCEL; - - typedef struct tagPAINTSTRUCT { - HDC hdc; - WINBOOL fErase; - RECT rcPaint; - WINBOOL fRestore; - WINBOOL fIncUpdate; - BYTE rgbReserved[32]; - } PAINTSTRUCT,*PPAINTSTRUCT,*NPPAINTSTRUCT,*LPPAINTSTRUCT; - - typedef struct tagCREATESTRUCTA { - LPVOID lpCreateParams; - HINSTANCE hInstance; - HMENU hMenu; - HWND hwndParent; - int cy; - int cx; - int y; - int x; - LONG style; - LPCSTR lpszName; - LPCSTR lpszClass; - DWORD dwExStyle; - } CREATESTRUCTA,*LPCREATESTRUCTA; - - typedef struct tagCREATESTRUCTW { - LPVOID lpCreateParams; - HINSTANCE hInstance; - HMENU hMenu; - HWND hwndParent; - int cy; - int cx; - int y; - int x; - LONG style; - LPCWSTR lpszName; - LPCWSTR lpszClass; - DWORD dwExStyle; - } CREATESTRUCTW,*LPCREATESTRUCTW; - -#ifdef UNICODE - typedef CREATESTRUCTW CREATESTRUCT; - typedef LPCREATESTRUCTW LPCREATESTRUCT; -#else - typedef CREATESTRUCTA CREATESTRUCT; - typedef LPCREATESTRUCTA LPCREATESTRUCT; -#endif - - typedef struct tagWINDOWPLACEMENT { - UINT length; - UINT flags; - UINT showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - } WINDOWPLACEMENT; - typedef WINDOWPLACEMENT *PWINDOWPLACEMENT,*LPWINDOWPLACEMENT; - -#define WPF_SETMINPOSITION 0x0001 -#define WPF_RESTORETOMAXIMIZED 0x0002 -#define WPF_ASYNCWINDOWPLACEMENT 0x0004 - - typedef struct tagNMHDR { - HWND hwndFrom; - UINT_PTR idFrom; - UINT code; - } NMHDR; - - typedef NMHDR *LPNMHDR; - - typedef struct tagSTYLESTRUCT { - DWORD styleOld; - DWORD styleNew; - } STYLESTRUCT,*LPSTYLESTRUCT; - -#define ODT_MENU 1 -#define ODT_LISTBOX 2 -#define ODT_COMBOBOX 3 -#define ODT_BUTTON 4 -#define ODT_STATIC 5 - -#define ODA_DRAWENTIRE 0x0001 -#define ODA_SELECT 0x0002 -#define ODA_FOCUS 0x0004 - -#define ODS_SELECTED 0x0001 -#define ODS_GRAYED 0x0002 -#define ODS_DISABLED 0x0004 -#define ODS_CHECKED 0x0008 -#define ODS_FOCUS 0x0010 -#define ODS_DEFAULT 0x0020 -#define ODS_COMBOBOXEDIT 0x1000 -#define ODS_HOTLIGHT 0x0040 -#define ODS_INACTIVE 0x0080 -#define ODS_NOACCEL 0x0100 -#define ODS_NOFOCUSRECT 0x0200 - - typedef struct tagMEASUREITEMSTRUCT { - UINT CtlType; - UINT CtlID; - UINT itemID; - UINT itemWidth; - UINT itemHeight; - ULONG_PTR itemData; - } MEASUREITEMSTRUCT,*PMEASUREITEMSTRUCT,*LPMEASUREITEMSTRUCT; - - typedef struct tagDRAWITEMSTRUCT { - UINT CtlType; - UINT CtlID; - UINT itemID; - UINT itemAction; - UINT itemState; - HWND hwndItem; - HDC hDC; - RECT rcItem; - ULONG_PTR itemData; - } DRAWITEMSTRUCT,*PDRAWITEMSTRUCT,*LPDRAWITEMSTRUCT; - - typedef struct tagDELETEITEMSTRUCT { - UINT CtlType; - UINT CtlID; - UINT itemID; - HWND hwndItem; - ULONG_PTR itemData; - } DELETEITEMSTRUCT,*PDELETEITEMSTRUCT,*LPDELETEITEMSTRUCT; - - typedef struct tagCOMPAREITEMSTRUCT { - UINT CtlType; - UINT CtlID; - HWND hwndItem; - UINT itemID1; - ULONG_PTR itemData1; - UINT itemID2; - ULONG_PTR itemData2; - DWORD dwLocaleId; - } COMPAREITEMSTRUCT,*PCOMPAREITEMSTRUCT,*LPCOMPAREITEMSTRUCT; - -#ifndef NOMSG -#ifdef UNICODE -#define GetMessage GetMessageW -#define DispatchMessage DispatchMessageW -#define PeekMessage PeekMessageW -#else -#define GetMessage GetMessageA -#define DispatchMessage DispatchMessageA -#define PeekMessage PeekMessageA -#endif - - WINUSERAPI WINBOOL WINAPI GetMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); - WINUSERAPI WINBOOL WINAPI GetMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); - WINUSERAPI WINBOOL WINAPI TranslateMessage(CONST MSG *lpMsg); - WINUSERAPI LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg); - WINUSERAPI LRESULT WINAPI DispatchMessageW(CONST MSG *lpMsg); - WINUSERAPI WINBOOL WINAPI SetMessageQueue(int cMessagesMax); - WINUSERAPI WINBOOL WINAPI PeekMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); - WINUSERAPI WINBOOL WINAPI PeekMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); - -#define PM_NOREMOVE 0x0000 -#define PM_REMOVE 0x0001 -#define PM_NOYIELD 0x0002 -#define PM_QS_INPUT (QS_INPUT << 16) -#define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16) -#define PM_QS_PAINT (QS_PAINT << 16) -#define PM_QS_SENDMESSAGE (QS_SENDMESSAGE << 16) -#endif - - WINUSERAPI WINBOOL WINAPI RegisterHotKey(HWND hWnd,int id,UINT fsModifiers,UINT vk); - WINUSERAPI WINBOOL WINAPI UnregisterHotKey(HWND hWnd,int id); - -#define MOD_ALT 0x0001 -#define MOD_CONTROL 0x0002 -#define MOD_SHIFT 0x0004 -#define MOD_WIN 0x0008 - -#define IDHOT_SNAPWINDOW (-1) -#define IDHOT_SNAPDESKTOP (-2) - -#ifdef WIN_INTERNAL -#ifndef LSTRING -#define NOLSTRING -#endif -#ifndef LFILEIO -#define NOLFILEIO -#endif -#endif - -#define ENDSESSION_LOGOFF 0x80000000 - -#define EWX_LOGOFF 0 -#define EWX_SHUTDOWN 0x00000001 -#define EWX_REBOOT 0x00000002 -#define EWX_FORCE 0x00000004 -#define EWX_POWEROFF 0x00000008 -#define EWX_FORCEIFHUNG 0x00000010 - -#define ExitWindows(dwReserved,Code) ExitWindowsEx(EWX_LOGOFF,0xFFFFFFFF) - -#ifdef UNICODE -#define SendMessage SendMessageW -#define SendMessageTimeout SendMessageTimeoutW -#define SendNotifyMessage SendNotifyMessageW -#define SendMessageCallback SendMessageCallbackW -#else -#define SendMessage SendMessageA -#define SendMessageTimeout SendMessageTimeoutA -#define SendNotifyMessage SendNotifyMessageA -#define SendMessageCallback SendMessageCallbackA -#endif - - WINUSERAPI WINBOOL WINAPI ExitWindowsEx(UINT uFlags,DWORD dwReason); - WINUSERAPI WINBOOL WINAPI SwapMouseButton(WINBOOL fSwap); - WINUSERAPI DWORD WINAPI GetMessagePos(VOID); - WINUSERAPI LONG WINAPI GetMessageTime(VOID); - WINUSERAPI LPARAM WINAPI GetMessageExtraInfo(VOID); - WINUSERAPI WINBOOL WINAPI IsWow64Message(VOID); - WINUSERAPI LPARAM WINAPI SetMessageExtraInfo(LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendMessageTimeoutA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); - WINUSERAPI LRESULT WINAPI SendMessageTimeoutW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); - WINUSERAPI WINBOOL WINAPI SendNotifyMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI SendNotifyMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI SendMessageCallbackA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); - WINUSERAPI WINBOOL WINAPI SendMessageCallbackW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); - - typedef struct { - UINT cbSize; - HDESK hdesk; - HWND hwnd; - LUID luid; - } BSMINFO,*PBSMINFO; - -#ifdef UNICODE -#define BroadcastSystemMessageEx BroadcastSystemMessageExW -#define BroadcastSystemMessage BroadcastSystemMessageW -#else -#define BroadcastSystemMessageEx BroadcastSystemMessageExA -#define BroadcastSystemMessage BroadcastSystemMessageA -#endif - - WINUSERAPI long WINAPI BroadcastSystemMessageExA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); - WINUSERAPI long WINAPI BroadcastSystemMessageExW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); - WINUSERAPI long WINAPI BroadcastSystemMessageA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI long WINAPI BroadcastSystemMessageW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); - -#define BSM_ALLCOMPONENTS 0x00000000 -#define BSM_VXDS 0x00000001 -#define BSM_NETDRIVER 0x00000002 -#define BSM_INSTALLABLEDRIVERS 0x00000004 -#define BSM_APPLICATIONS 0x00000008 -#define BSM_ALLDESKTOPS 0x00000010 - -#define BSF_QUERY 0x00000001 -#define BSF_IGNORECURRENTTASK 0x00000002 -#define BSF_FLUSHDISK 0x00000004 -#define BSF_NOHANG 0x00000008 -#define BSF_POSTMESSAGE 0x00000010 -#define BSF_FORCEIFHUNG 0x00000020 -#define BSF_NOTIMEOUTIFNOTHUNG 0x00000040 -#define BSF_ALLOWSFW 0x00000080 -#define BSF_SENDNOTIFYMESSAGE 0x00000100 -#define BSF_RETURNHDESK 0x00000200 -#define BSF_LUID 0x00000400 - -#define BROADCAST_QUERY_DENY 0x424D5144 - - typedef PVOID HDEVNOTIFY; - typedef HDEVNOTIFY *PHDEVNOTIFY; - -#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000 -#define DEVICE_NOTIFY_SERVICE_HANDLE 0x00000001 -#define DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 0x00000004 - -#ifdef UNICODE -#define RegisterDeviceNotification RegisterDeviceNotificationW -#define PostMessage PostMessageW -#define PostThreadMessage PostThreadMessageW -#define PostAppMessage PostAppMessageW -#define DefWindowProc DefWindowProcW -#define CallWindowProc CallWindowProcW -#define RegisterClass RegisterClassW -#define UnregisterClass UnregisterClassW -#define GetClassInfo GetClassInfoW -#define RegisterClassEx RegisterClassExW -#define GetClassInfoEx GetClassInfoExW -#else -#define RegisterDeviceNotification RegisterDeviceNotificationA -#define PostMessage PostMessageA -#define PostThreadMessage PostThreadMessageA -#define PostAppMessage PostAppMessageA -#define DefWindowProc DefWindowProcA -#define CallWindowProc CallWindowProcA -#define RegisterClass RegisterClassA -#define UnregisterClass UnregisterClassA -#define GetClassInfo GetClassInfoA -#define RegisterClassEx RegisterClassExA -#define GetClassInfoEx GetClassInfoExA -#endif - - WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); - WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationW(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); - WINUSERAPI WINBOOL WINAPI UnregisterDeviceNotification(HDEVNOTIFY Handle); - WINUSERAPI WINBOOL WINAPI PostMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI PostMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI PostThreadMessageA(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI PostThreadMessageW(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); -#define PostAppMessageA(idThread,wMsg,wParam,lParam) PostThreadMessageA((DWORD)idThread,wMsg,wParam,lParam) -#define PostAppMessageW(idThread,wMsg,wParam,lParam) PostThreadMessageW((DWORD)idThread,wMsg,wParam,lParam) - -#define HWND_BROADCAST ((HWND)0xffff) -#define HWND_MESSAGE ((HWND)-3) - - WINUSERAPI WINBOOL WINAPI AttachThreadInput(DWORD idAttach,DWORD idAttachTo,WINBOOL fAttach); - WINUSERAPI WINBOOL WINAPI ReplyMessage(LRESULT lResult); - WINUSERAPI WINBOOL WINAPI WaitMessage(VOID); - WINUSERAPI DWORD WINAPI WaitForInputIdle(HANDLE hProcess,DWORD dwMilliseconds); - WINUSERAPI LRESULT WINAPI DefWindowProcA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefWindowProcW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI VOID WINAPI PostQuitMessage(int nExitCode); - WINUSERAPI LRESULT WINAPI CallWindowProcA(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI CallWindowProcW(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI InSendMessage(VOID); - WINUSERAPI DWORD WINAPI InSendMessageEx(LPVOID lpReserved); - -#define ISMEX_NOSEND 0x00000000 -#define ISMEX_SEND 0x00000001 -#define ISMEX_NOTIFY 0x00000002 -#define ISMEX_CALLBACK 0x00000004 -#define ISMEX_REPLIED 0x00000008 - - WINUSERAPI UINT WINAPI GetDoubleClickTime(VOID); - WINUSERAPI WINBOOL WINAPI SetDoubleClickTime(UINT); - WINUSERAPI ATOM WINAPI RegisterClassA(CONST WNDCLASSA *lpWndClass); - WINUSERAPI ATOM WINAPI RegisterClassW(CONST WNDCLASSW *lpWndClass); - WINUSERAPI WINBOOL WINAPI UnregisterClassA(LPCSTR lpClassName,HINSTANCE hInstance); - WINUSERAPI WINBOOL WINAPI UnregisterClassW(LPCWSTR lpClassName,HINSTANCE hInstance); - WINUSERAPI WINBOOL WINAPI GetClassInfoA(HINSTANCE hInstance,LPCSTR lpClassName,LPWNDCLASSA lpWndClass); - WINUSERAPI WINBOOL WINAPI GetClassInfoW(HINSTANCE hInstance,LPCWSTR lpClassName,LPWNDCLASSW lpWndClass); - WINUSERAPI ATOM WINAPI RegisterClassExA(CONST WNDCLASSEXA *); - WINUSERAPI ATOM WINAPI RegisterClassExW(CONST WNDCLASSEXW *); - WINUSERAPI WINBOOL WINAPI GetClassInfoExA(HINSTANCE hInstance,LPCSTR lpszClass,LPWNDCLASSEXA lpwcx); - WINUSERAPI WINBOOL WINAPI GetClassInfoExW(HINSTANCE hInstance,LPCWSTR lpszClass,LPWNDCLASSEXW lpwcx); - -#define CW_USEDEFAULT ((int)0x80000000) - -#define HWND_DESKTOP ((HWND)0) - - typedef BOOLEAN (WINAPI *PREGISTERCLASSNAMEW)(LPCWSTR); - -#ifdef UNICODE -#define CreateWindowEx CreateWindowExW -#define CreateWindow CreateWindowW -#else -#define CreateWindowEx CreateWindowExA -#define CreateWindow CreateWindowA -#endif - - WINUSERAPI HWND WINAPI CreateWindowExA(DWORD dwExStyle,LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); - WINUSERAPI HWND WINAPI CreateWindowExW(DWORD dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); -#define CreateWindowA(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExA(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) -#define CreateWindowW(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExW(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) - WINUSERAPI WINBOOL WINAPI IsWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI IsMenu(HMENU hMenu); - WINUSERAPI WINBOOL WINAPI IsChild(HWND hWndParent,HWND hWnd); - WINUSERAPI WINBOOL WINAPI DestroyWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI ShowWindow(HWND hWnd,int nCmdShow); - WINUSERAPI WINBOOL WINAPI AnimateWindow(HWND hWnd,DWORD dwTime,DWORD dwFlags); - -#if defined(_WINGDI_) && !defined(NOGDI) - WINUSERAPI WINBOOL WINAPI UpdateLayeredWindow(HWND hWnd,HDC hdcDst,POINT *pptDst,SIZE *psize,HDC hdcSrc,POINT *pptSrc,COLORREF crKey,BLENDFUNCTION *pblend,DWORD dwFlags); - - typedef struct tagUPDATELAYEREDWINDOWINFO { - DWORD cbSize; - HDC hdcDst; - POINT CONST *pptDst; - SIZE CONST *psize; - HDC hdcSrc; - POINT CONST *pptSrc; - COLORREF crKey; - BLENDFUNCTION CONST *pblend; - DWORD dwFlags; - RECT CONST *prcDirty; - } UPDATELAYEREDWINDOWINFO,*PUPDATELAYEREDWINDOWINFO; - - WINUSERAPI WINBOOL WINAPI UpdateLayeredWindowIndirect(HWND hWnd,UPDATELAYEREDWINDOWINFO CONST *pULWInfo); - WINUSERAPI WINBOOL WINAPI GetLayeredWindowAttributes(HWND hwnd,COLORREF *pcrKey,BYTE *pbAlpha,DWORD *pdwFlags); - -#define PW_CLIENTONLY 0x00000001 - - WINUSERAPI WINBOOL WINAPI PrintWindow(HWND hwnd,HDC hdcBlt,UINT nFlags); - WINUSERAPI WINBOOL WINAPI SetLayeredWindowAttributes(HWND hwnd,COLORREF crKey,BYTE bAlpha,DWORD dwFlags); - -#define LWA_COLORKEY 0x00000001 -#define LWA_ALPHA 0x00000002 - -#define ULW_COLORKEY 0x00000001 -#define ULW_ALPHA 0x00000002 -#define ULW_OPAQUE 0x00000004 - -#define ULW_EX_NORESIZE 0x00000008 - - WINUSERAPI WINBOOL WINAPI ShowWindowAsync(HWND hWnd,int nCmdShow); - WINUSERAPI WINBOOL WINAPI FlashWindow(HWND hWnd,WINBOOL bInvert); - - typedef struct { - UINT cbSize; - HWND hwnd; - DWORD dwFlags; - UINT uCount; - DWORD dwTimeout; - } FLASHWINFO,*PFLASHWINFO; - - WINUSERAPI WINBOOL WINAPI FlashWindowEx(PFLASHWINFO pfwi); - -#define FLASHW_STOP 0 -#define FLASHW_CAPTION 0x00000001 -#define FLASHW_TRAY 0x00000002 -#define FLASHW_ALL (FLASHW_CAPTION | FLASHW_TRAY) -#define FLASHW_TIMER 0x00000004 -#define FLASHW_TIMERNOFG 0x0000000C - - WINUSERAPI WINBOOL WINAPI ShowOwnedPopups(HWND hWnd,WINBOOL fShow); - WINUSERAPI WINBOOL WINAPI OpenIcon(HWND hWnd); - WINUSERAPI WINBOOL WINAPI CloseWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI MoveWindow(HWND hWnd,int X,int Y,int nWidth,int nHeight,WINBOOL bRepaint); - WINUSERAPI WINBOOL WINAPI SetWindowPos(HWND hWnd,HWND hWndInsertAfter,int X,int Y,int cx,int cy,UINT uFlags); - WINUSERAPI WINBOOL WINAPI GetWindowPlacement(HWND hWnd,WINDOWPLACEMENT *lpwndpl); - WINUSERAPI WINBOOL WINAPI SetWindowPlacement(HWND hWnd,CONST WINDOWPLACEMENT *lpwndpl); - -#ifndef NODEFERWINDOWPOS - WINUSERAPI HDWP WINAPI BeginDeferWindowPos(int nNumWindows); - WINUSERAPI HDWP WINAPI DeferWindowPos(HDWP hWinPosInfo,HWND hWnd,HWND hWndInsertAfter,int x,int y,int cx,int cy,UINT uFlags); - WINUSERAPI WINBOOL WINAPI EndDeferWindowPos(HDWP hWinPosInfo); -#endif - - WINUSERAPI WINBOOL WINAPI IsWindowVisible(HWND hWnd); - WINUSERAPI WINBOOL WINAPI IsIconic(HWND hWnd); - WINUSERAPI WINBOOL WINAPI AnyPopup(VOID); - WINUSERAPI WINBOOL WINAPI BringWindowToTop(HWND hWnd); - WINUSERAPI WINBOOL WINAPI IsZoomed(HWND hWnd); - -#define SWP_NOSIZE 0x0001 -#define SWP_NOMOVE 0x0002 -#define SWP_NOZORDER 0x0004 -#define SWP_NOREDRAW 0x0008 -#define SWP_NOACTIVATE 0x0010 -#define SWP_FRAMECHANGED 0x0020 -#define SWP_SHOWWINDOW 0x0040 -#define SWP_HIDEWINDOW 0x0080 -#define SWP_NOCOPYBITS 0x0100 -#define SWP_NOOWNERZORDER 0x0200 -#define SWP_NOSENDCHANGING 0x0400 - -#define SWP_DRAWFRAME SWP_FRAMECHANGED -#define SWP_NOREPOSITION SWP_NOOWNERZORDER -#define SWP_DEFERERASE 0x2000 -#define SWP_ASYNCWINDOWPOS 0x4000 - -#define HWND_TOP ((HWND)0) -#define HWND_BOTTOM ((HWND)1) -#define HWND_TOPMOST ((HWND)-1) -#define HWND_NOTOPMOST ((HWND)-2) - -#ifndef NOCTLMGR - -#include - - typedef struct { - DWORD style; - DWORD dwExtendedStyle; - WORD cdit; - short x; - short y; - short cx; - short cy; - } DLGTEMPLATE; - - typedef DLGTEMPLATE *LPDLGTEMPLATEA; - typedef DLGTEMPLATE *LPDLGTEMPLATEW; - -#ifdef UNICODE - typedef LPDLGTEMPLATEW LPDLGTEMPLATE; -#else - typedef LPDLGTEMPLATEA LPDLGTEMPLATE; -#endif - - typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEA; - typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEW; - -#ifdef UNICODE - typedef LPCDLGTEMPLATEW LPCDLGTEMPLATE; -#else - typedef LPCDLGTEMPLATEA LPCDLGTEMPLATE; -#endif - - typedef struct { - DWORD style; - DWORD dwExtendedStyle; - short x; - short y; - short cx; - short cy; - WORD id; - } DLGITEMTEMPLATE; - - typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEA; - typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEW; - -#ifdef UNICODE - typedef PDLGITEMTEMPLATEW PDLGITEMTEMPLATE; -#else - typedef PDLGITEMTEMPLATEA PDLGITEMTEMPLATE; -#endif - - typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEA; - typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEW; - -#ifdef UNICODE - typedef LPDLGITEMTEMPLATEW LPDLGITEMTEMPLATE; -#else - typedef LPDLGITEMTEMPLATEA LPDLGITEMTEMPLATE; -#endif - -#include - -#ifdef UNICODE -#define CreateDialogParam CreateDialogParamW -#define CreateDialogIndirectParam CreateDialogIndirectParamW -#define CreateDialog CreateDialogW -#define CreateDialogIndirect CreateDialogIndirectW -#define DialogBoxParam DialogBoxParamW -#define DialogBoxIndirectParam DialogBoxIndirectParamW -#define DialogBox DialogBoxW -#define DialogBoxIndirect DialogBoxIndirectW -#define SetDlgItemText SetDlgItemTextW -#define GetDlgItemText GetDlgItemTextW -#define SendDlgItemMessage SendDlgItemMessageW -#define DefDlgProc DefDlgProcW -#else -#define CreateDialogParam CreateDialogParamA -#define CreateDialogIndirectParam CreateDialogIndirectParamA -#define CreateDialog CreateDialogA -#define CreateDialogIndirect CreateDialogIndirectA -#define DialogBoxParam DialogBoxParamA -#define DialogBoxIndirectParam DialogBoxIndirectParamA -#define DialogBox DialogBoxA -#define DialogBoxIndirect DialogBoxIndirectA -#define SetDlgItemText SetDlgItemTextA -#define GetDlgItemText GetDlgItemTextA -#define SendDlgItemMessage SendDlgItemMessageA -#define DefDlgProc DefDlgProcA -#endif - - WINUSERAPI HWND WINAPI CreateDialogParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI HWND WINAPI CreateDialogParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI HWND WINAPI CreateDialogIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI HWND WINAPI CreateDialogIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); -#define CreateDialogA(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamA(hInstance,lpName,hWndParent,lpDialogFunc,0L) -#define CreateDialogW(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamW(hInstance,lpName,hWndParent,lpDialogFunc,0L) -#define CreateDialogIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define CreateDialogIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) - WINUSERAPI INT_PTR WINAPI DialogBoxParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI INT_PTR WINAPI DialogBoxParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); -#define DialogBoxA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define DialogBoxW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define DialogBoxIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define DialogBoxIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) - WINUSERAPI WINBOOL WINAPI EndDialog(HWND hDlg,INT_PTR nResult); - WINUSERAPI HWND WINAPI GetDlgItem(HWND hDlg,int nIDDlgItem); - WINUSERAPI WINBOOL WINAPI SetDlgItemInt(HWND hDlg,int nIDDlgItem,UINT uValue,WINBOOL bSigned); - WINUSERAPI UINT WINAPI GetDlgItemInt(HWND hDlg,int nIDDlgItem,WINBOOL *lpTranslated,WINBOOL bSigned); - WINUSERAPI WINBOOL WINAPI SetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPCSTR lpString); - WINUSERAPI WINBOOL WINAPI SetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPCWSTR lpString); - WINUSERAPI UINT WINAPI GetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPSTR lpString,int cchMax); - WINUSERAPI UINT WINAPI GetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPWSTR lpString,int cchMax); - WINUSERAPI WINBOOL WINAPI CheckDlgButton(HWND hDlg,int nIDButton,UINT uCheck); - WINUSERAPI WINBOOL WINAPI CheckRadioButton(HWND hDlg,int nIDFirstButton,int nIDLastButton,int nIDCheckButton); - WINUSERAPI UINT WINAPI IsDlgButtonChecked(HWND hDlg,int nIDButton); - WINUSERAPI LRESULT WINAPI SendDlgItemMessageA(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendDlgItemMessageW(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI HWND WINAPI GetNextDlgGroupItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); - WINUSERAPI HWND WINAPI GetNextDlgTabItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); - WINUSERAPI int WINAPI GetDlgCtrlID(HWND hWnd); - WINUSERAPI long WINAPI GetDialogBaseUnits(VOID); - WINUSERAPI LRESULT WINAPI DefDlgProcA(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefDlgProcW(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); - -#define DLGWINDOWEXTRA 30 -#endif - -#ifndef NOMSG - -#ifdef UNICODE -#define CallMsgFilter CallMsgFilterW -#else -#define CallMsgFilter CallMsgFilterA -#endif - - WINUSERAPI WINBOOL WINAPI CallMsgFilterA(LPMSG lpMsg,int nCode); - WINUSERAPI WINBOOL WINAPI CallMsgFilterW(LPMSG lpMsg,int nCode); -#endif - -#ifndef NOCLIPBOARD - -#ifdef UNICODE -#define RegisterClipboardFormat RegisterClipboardFormatW -#define GetClipboardFormatName GetClipboardFormatNameW -#else -#define RegisterClipboardFormat RegisterClipboardFormatA -#define GetClipboardFormatName GetClipboardFormatNameA -#endif - - WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner); - WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID); - WINUSERAPI DWORD WINAPI GetClipboardSequenceNumber(VOID); - WINUSERAPI HWND WINAPI GetClipboardOwner(VOID); - WINUSERAPI HWND WINAPI SetClipboardViewer(HWND hWndNewViewer); - WINUSERAPI HWND WINAPI GetClipboardViewer(VOID); - WINUSERAPI WINBOOL WINAPI ChangeClipboardChain(HWND hWndRemove,HWND hWndNewNext); - WINUSERAPI HANDLE WINAPI SetClipboardData(UINT uFormat,HANDLE hMem); - WINUSERAPI HANDLE WINAPI GetClipboardData(UINT uFormat); - WINUSERAPI UINT WINAPI RegisterClipboardFormatA(LPCSTR lpszFormat); - WINUSERAPI UINT WINAPI RegisterClipboardFormatW(LPCWSTR lpszFormat); - WINUSERAPI int WINAPI CountClipboardFormats(VOID); - WINUSERAPI UINT WINAPI EnumClipboardFormats(UINT format); - WINUSERAPI int WINAPI GetClipboardFormatNameA(UINT format,LPSTR lpszFormatName,int cchMaxCount); - WINUSERAPI int WINAPI GetClipboardFormatNameW(UINT format,LPWSTR lpszFormatName,int cchMaxCount); - WINUSERAPI WINBOOL WINAPI EmptyClipboard(VOID); - WINUSERAPI WINBOOL WINAPI IsClipboardFormatAvailable(UINT format); - WINUSERAPI int WINAPI GetPriorityClipboardFormat(UINT *paFormatPriorityList,int cFormats); - WINUSERAPI HWND WINAPI GetOpenClipboardWindow(VOID); -#endif - -#ifdef UNICODE -#define CharToOem CharToOemW -#define OemToChar OemToCharW -#define CharToOemBuff CharToOemBuffW -#define OemToCharBuff OemToCharBuffW -#define CharUpper CharUpperW -#define CharUpperBuff CharUpperBuffW -#define CharLower CharLowerW -#define CharLowerBuff CharLowerBuffW -#define CharNext CharNextW -#define CharPrev CharPrevW -#else -#define CharToOem CharToOemA -#define OemToChar OemToCharA -#define CharToOemBuff CharToOemBuffA -#define OemToCharBuff OemToCharBuffA -#define CharUpper CharUpperA -#define CharUpperBuff CharUpperBuffA -#define CharLower CharLowerA -#define CharLowerBuff CharLowerBuffA -#define CharNext CharNextA -#define CharPrev CharPrevA -#endif - - WINUSERAPI WINBOOL WINAPI CharToOemA(LPCSTR lpszSrc,LPSTR lpszDst); - WINUSERAPI WINBOOL WINAPI CharToOemW(LPCWSTR lpszSrc,LPSTR lpszDst); - WINUSERAPI WINBOOL WINAPI OemToCharA(LPCSTR lpszSrc,LPSTR lpszDst); - WINUSERAPI WINBOOL WINAPI OemToCharW(LPCSTR lpszSrc,LPWSTR lpszDst); - WINUSERAPI WINBOOL WINAPI CharToOemBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); - WINUSERAPI WINBOOL WINAPI CharToOemBuffW(LPCWSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); - WINUSERAPI WINBOOL WINAPI OemToCharBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); - WINUSERAPI WINBOOL WINAPI OemToCharBuffW(LPCSTR lpszSrc,LPWSTR lpszDst,DWORD cchDstLength); - WINUSERAPI LPSTR WINAPI CharUpperA(LPSTR lpsz); - WINUSERAPI LPWSTR WINAPI CharUpperW(LPWSTR lpsz); - WINUSERAPI DWORD WINAPI CharUpperBuffA(LPSTR lpsz,DWORD cchLength); - WINUSERAPI DWORD WINAPI CharUpperBuffW(LPWSTR lpsz,DWORD cchLength); - WINUSERAPI LPSTR WINAPI CharLowerA(LPSTR lpsz); - WINUSERAPI LPWSTR WINAPI CharLowerW(LPWSTR lpsz); - WINUSERAPI DWORD WINAPI CharLowerBuffA(LPSTR lpsz,DWORD cchLength); - WINUSERAPI DWORD WINAPI CharLowerBuffW(LPWSTR lpsz,DWORD cchLength); - WINUSERAPI LPSTR WINAPI CharNextA(LPCSTR lpsz); - WINUSERAPI LPWSTR WINAPI CharNextW(LPCWSTR lpsz); - WINUSERAPI LPSTR WINAPI CharPrevA(LPCSTR lpszStart,LPCSTR lpszCurrent); - WINUSERAPI LPWSTR WINAPI CharPrevW(LPCWSTR lpszStart,LPCWSTR lpszCurrent); - WINUSERAPI LPSTR WINAPI CharNextExA(WORD CodePage,LPCSTR lpCurrentChar,DWORD dwFlags); - WINUSERAPI LPSTR WINAPI CharPrevExA(WORD CodePage,LPCSTR lpStart,LPCSTR lpCurrentChar,DWORD dwFlags); - -#define AnsiToOem CharToOemA -#define OemToAnsi OemToCharA -#define AnsiToOemBuff CharToOemBuffA -#define OemToAnsiBuff OemToCharBuffA -#define AnsiUpper CharUpperA -#define AnsiUpperBuff CharUpperBuffA -#define AnsiLower CharLowerA -#define AnsiLowerBuff CharLowerBuffA -#define AnsiNext CharNextA -#define AnsiPrev CharPrevA - -#ifndef NOLANGUAGE - -#ifdef UNICODE -#define IsCharAlpha IsCharAlphaW -#define IsCharAlphaNumeric IsCharAlphaNumericW -#define IsCharUpper IsCharUpperW -#define IsCharLower IsCharLowerW -#else -#define IsCharAlpha IsCharAlphaA -#define IsCharAlphaNumeric IsCharAlphaNumericA -#define IsCharUpper IsCharUpperA -#define IsCharLower IsCharLowerA -#endif - - WINUSERAPI WINBOOL WINAPI IsCharAlphaA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharAlphaW(WCHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericW(WCHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharUpperA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharUpperW(WCHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharLowerA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharLowerW(WCHAR ch); -#endif - -#ifdef UNICODE -#define GetKeyNameText GetKeyNameTextW -#define VkKeyScan VkKeyScanW -#define VkKeyScanEx VkKeyScanExW -#else -#define GetKeyNameText GetKeyNameTextA -#define VkKeyScan VkKeyScanA -#define VkKeyScanEx VkKeyScanExA -#endif - - WINUSERAPI HWND WINAPI SetFocus(HWND hWnd); - WINUSERAPI HWND WINAPI GetActiveWindow(VOID); - WINUSERAPI HWND WINAPI GetFocus(VOID); - WINUSERAPI UINT WINAPI GetKBCodePage(VOID); - WINUSERAPI SHORT WINAPI GetKeyState(int nVirtKey); - WINUSERAPI SHORT WINAPI GetAsyncKeyState(int vKey); - WINUSERAPI WINBOOL WINAPI GetKeyboardState(PBYTE lpKeyState); - WINUSERAPI WINBOOL WINAPI SetKeyboardState(LPBYTE lpKeyState); - WINUSERAPI int WINAPI GetKeyNameTextA(LONG lParam,LPSTR lpString,int cchSize); - WINUSERAPI int WINAPI GetKeyNameTextW(LONG lParam,LPWSTR lpString,int cchSize); - WINUSERAPI int WINAPI GetKeyboardType(int nTypeFlag); - WINUSERAPI int WINAPI ToAscii(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags); - WINUSERAPI int WINAPI ToAsciiEx(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags,HKL dwhkl); - WINUSERAPI int WINAPI ToUnicode(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags); - WINUSERAPI DWORD WINAPI OemKeyScan(WORD wOemChar); - WINUSERAPI SHORT WINAPI VkKeyScanA(CHAR ch); - WINUSERAPI SHORT WINAPI VkKeyScanW(WCHAR ch); - WINUSERAPI SHORT WINAPI VkKeyScanExA(CHAR ch,HKL dwhkl); - WINUSERAPI SHORT WINAPI VkKeyScanExW(WCHAR ch,HKL dwhkl); - -#define KEYEVENTF_EXTENDEDKEY 0x0001 -#define KEYEVENTF_KEYUP 0x0002 -#define KEYEVENTF_UNICODE 0x0004 -#define KEYEVENTF_SCANCODE 0x0008 - - WINUSERAPI VOID WINAPI keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,ULONG_PTR dwExtraInfo); - -#define MOUSEEVENTF_MOVE 0x0001 -#define MOUSEEVENTF_LEFTDOWN 0x0002 -#define MOUSEEVENTF_LEFTUP 0x0004 -#define MOUSEEVENTF_RIGHTDOWN 0x0008 -#define MOUSEEVENTF_RIGHTUP 0x0010 -#define MOUSEEVENTF_MIDDLEDOWN 0x0020 -#define MOUSEEVENTF_MIDDLEUP 0x0040 -#define MOUSEEVENTF_XDOWN 0x0080 -#define MOUSEEVENTF_XUP 0x0100 -#define MOUSEEVENTF_WHEEL 0x0800 -#define MOUSEEVENTF_VIRTUALDESK 0x4000 -#define MOUSEEVENTF_ABSOLUTE 0x8000 - - WINUSERAPI VOID WINAPI mouse_event(DWORD dwFlags,DWORD dx,DWORD dy,DWORD dwData,ULONG_PTR dwExtraInfo); - - typedef struct tagMOUSEINPUT { - LONG dx; - LONG dy; - DWORD mouseData; - DWORD dwFlags; - DWORD time; - ULONG_PTR dwExtraInfo; - } MOUSEINPUT,*PMOUSEINPUT,*LPMOUSEINPUT; - - typedef struct tagKEYBDINPUT { - WORD wVk; - WORD wScan; - DWORD dwFlags; - DWORD time; - ULONG_PTR dwExtraInfo; - } KEYBDINPUT,*PKEYBDINPUT,*LPKEYBDINPUT; - - typedef struct tagHARDWAREINPUT { - DWORD uMsg; - WORD wParamL; - WORD wParamH; - } HARDWAREINPUT,*PHARDWAREINPUT,*LPHARDWAREINPUT; - -#define INPUT_MOUSE 0 -#define INPUT_KEYBOARD 1 -#define INPUT_HARDWARE 2 - - typedef struct tagINPUT { - DWORD type; - union { - MOUSEINPUT mi; - KEYBDINPUT ki; - HARDWAREINPUT hi; - }; - } INPUT,*PINPUT,*LPINPUT; - - WINUSERAPI UINT WINAPI SendInput(UINT cInputs,LPINPUT pInputs,int cbSize); - - typedef struct tagLASTINPUTINFO { - UINT cbSize; - DWORD dwTime; - } LASTINPUTINFO,*PLASTINPUTINFO; - -#ifdef UNICODE -#define MapVirtualKey MapVirtualKeyW -#define MapVirtualKeyEx MapVirtualKeyExW -#else -#define MapVirtualKey MapVirtualKeyA -#define MapVirtualKeyEx MapVirtualKeyExA -#endif - - WINUSERAPI WINBOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii); - WINUSERAPI UINT WINAPI MapVirtualKeyA(UINT uCode,UINT uMapType); - WINUSERAPI UINT WINAPI MapVirtualKeyW(UINT uCode,UINT uMapType); - WINUSERAPI UINT WINAPI MapVirtualKeyExA(UINT uCode,UINT uMapType,HKL dwhkl); - WINUSERAPI UINT WINAPI MapVirtualKeyExW(UINT uCode,UINT uMapType,HKL dwhkl); - WINUSERAPI WINBOOL WINAPI GetInputState(VOID); - WINUSERAPI DWORD WINAPI GetQueueStatus(UINT flags); - WINUSERAPI HWND WINAPI GetCapture(VOID); - WINUSERAPI HWND WINAPI SetCapture(HWND hWnd); - WINUSERAPI WINBOOL WINAPI ReleaseCapture(VOID); - WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjects(DWORD nCount,CONST HANDLE *pHandles,WINBOOL fWaitAll,DWORD dwMilliseconds,DWORD dwWakeMask); - WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *pHandles,DWORD dwMilliseconds,DWORD dwWakeMask,DWORD dwFlags); - -#define MWMO_WAITALL 0x0001 -#define MWMO_ALERTABLE 0x0002 -#define MWMO_INPUTAVAILABLE 0x0004 - -#define QS_KEY 0x0001 -#define QS_MOUSEMOVE 0x0002 -#define QS_MOUSEBUTTON 0x0004 -#define QS_POSTMESSAGE 0x0008 -#define QS_TIMER 0x0010 -#define QS_PAINT 0x0020 -#define QS_SENDMESSAGE 0x0040 -#define QS_HOTKEY 0x0080 -#define QS_ALLPOSTMESSAGE 0x0100 -#define QS_RAWINPUT 0x0400 -#define QS_MOUSE (QS_MOUSEMOVE | QS_MOUSEBUTTON) -#define QS_INPUT (QS_MOUSE | QS_KEY | QS_RAWINPUT) -#define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) -#define QS_ALLINPUT (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE) - -#define USER_TIMER_MAXIMUM 0x7FFFFFFF -#define USER_TIMER_MINIMUM 0x0000000A - -#ifdef UNICODE -#define LoadAccelerators LoadAcceleratorsW -#define CreateAcceleratorTable CreateAcceleratorTableW -#define CopyAcceleratorTable CopyAcceleratorTableW -#else -#define LoadAccelerators LoadAcceleratorsA -#define CreateAcceleratorTable CreateAcceleratorTableA -#define CopyAcceleratorTable CopyAcceleratorTableA -#endif - - WINUSERAPI UINT_PTR WINAPI SetTimer(HWND hWnd,UINT_PTR nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc); - WINUSERAPI WINBOOL WINAPI KillTimer(HWND hWnd,UINT_PTR uIDEvent); - WINUSERAPI WINBOOL WINAPI IsWindowUnicode(HWND hWnd); - WINUSERAPI WINBOOL WINAPI EnableWindow(HWND hWnd,WINBOOL bEnable); - WINUSERAPI WINBOOL WINAPI IsWindowEnabled(HWND hWnd); - WINUSERAPI HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance,LPCSTR lpTableName); - WINUSERAPI HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance,LPCWSTR lpTableName); - WINUSERAPI HACCEL WINAPI CreateAcceleratorTableA(LPACCEL paccel,int cAccel); - WINUSERAPI HACCEL WINAPI CreateAcceleratorTableW(LPACCEL paccel,int cAccel); - WINUSERAPI WINBOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel); - WINUSERAPI int WINAPI CopyAcceleratorTableA(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); - WINUSERAPI int WINAPI CopyAcceleratorTableW(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); - -#ifndef NOMSG - -#ifdef UNICODE -#define TranslateAccelerator TranslateAcceleratorW -#else -#define TranslateAccelerator TranslateAcceleratorA -#endif - - WINUSERAPI int WINAPI TranslateAcceleratorA(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); - WINUSERAPI int WINAPI TranslateAcceleratorW(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); -#endif - -#ifndef NOSYSMETRICS - -#define SM_CXSCREEN 0 -#define SM_CYSCREEN 1 -#define SM_CXVSCROLL 2 -#define SM_CYHSCROLL 3 -#define SM_CYCAPTION 4 -#define SM_CXBORDER 5 -#define SM_CYBORDER 6 -#define SM_CXDLGFRAME 7 -#define SM_CYDLGFRAME 8 -#define SM_CYVTHUMB 9 -#define SM_CXHTHUMB 10 -#define SM_CXICON 11 -#define SM_CYICON 12 -#define SM_CXCURSOR 13 -#define SM_CYCURSOR 14 -#define SM_CYMENU 15 -#define SM_CXFULLSCREEN 16 -#define SM_CYFULLSCREEN 17 -#define SM_CYKANJIWINDOW 18 -#define SM_MOUSEPRESENT 19 -#define SM_CYVSCROLL 20 -#define SM_CXHSCROLL 21 -#define SM_DEBUG 22 -#define SM_SWAPBUTTON 23 -#define SM_RESERVED1 24 -#define SM_RESERVED2 25 -#define SM_RESERVED3 26 -#define SM_RESERVED4 27 -#define SM_CXMIN 28 -#define SM_CYMIN 29 -#define SM_CXSIZE 30 -#define SM_CYSIZE 31 -#define SM_CXFRAME 32 -#define SM_CYFRAME 33 -#define SM_CXMINTRACK 34 -#define SM_CYMINTRACK 35 -#define SM_CXDOUBLECLK 36 -#define SM_CYDOUBLECLK 37 -#define SM_CXICONSPACING 38 -#define SM_CYICONSPACING 39 -#define SM_MENUDROPALIGNMENT 40 -#define SM_PENWINDOWS 41 -#define SM_DBCSENABLED 42 -#define SM_CMOUSEBUTTONS 43 - -#define SM_CXFIXEDFRAME SM_CXDLGFRAME -#define SM_CYFIXEDFRAME SM_CYDLGFRAME -#define SM_CXSIZEFRAME SM_CXFRAME -#define SM_CYSIZEFRAME SM_CYFRAME - -#define SM_SECURE 44 -#define SM_CXEDGE 45 -#define SM_CYEDGE 46 -#define SM_CXMINSPACING 47 -#define SM_CYMINSPACING 48 -#define SM_CXSMICON 49 -#define SM_CYSMICON 50 -#define SM_CYSMCAPTION 51 -#define SM_CXSMSIZE 52 -#define SM_CYSMSIZE 53 -#define SM_CXMENUSIZE 54 -#define SM_CYMENUSIZE 55 -#define SM_ARRANGE 56 -#define SM_CXMINIMIZED 57 -#define SM_CYMINIMIZED 58 -#define SM_CXMAXTRACK 59 -#define SM_CYMAXTRACK 60 -#define SM_CXMAXIMIZED 61 -#define SM_CYMAXIMIZED 62 -#define SM_NETWORK 63 -#define SM_CLEANBOOT 67 -#define SM_CXDRAG 68 -#define SM_CYDRAG 69 -#define SM_SHOWSOUNDS 70 -#define SM_CXMENUCHECK 71 -#define SM_CYMENUCHECK 72 -#define SM_SLOWMACHINE 73 -#define SM_MIDEASTENABLED 74 -#define SM_MOUSEWHEELPRESENT 75 -#define SM_XVIRTUALSCREEN 76 -#define SM_YVIRTUALSCREEN 77 -#define SM_CXVIRTUALSCREEN 78 -#define SM_CYVIRTUALSCREEN 79 -#define SM_CMONITORS 80 -#define SM_SAMEDISPLAYFORMAT 81 -#define SM_IMMENABLED 82 -#define SM_CXFOCUSBORDER 83 -#define SM_CYFOCUSBORDER 84 -#define SM_TABLETPC 86 -#define SM_MEDIACENTER 87 -#define SM_STARTER 88 -#define SM_SERVERR2 89 -#define SM_CMETRICS 90 -#define SM_REMOTESESSION 0x1000 -#define SM_SHUTTINGDOWN 0x2000 -#define SM_REMOTECONTROL 0x2001 -#define SM_CARETBLINKINGENABLED 0x2002 - - WINUSERAPI int WINAPI GetSystemMetrics(int nIndex); -#endif - -#ifndef NOMENUS - -#ifdef UNICODE -#define LoadMenu LoadMenuW -#define LoadMenuIndirect LoadMenuIndirectW -#define ChangeMenu ChangeMenuW -#define GetMenuString GetMenuStringW -#define InsertMenu InsertMenuW -#define AppendMenu AppendMenuW -#define ModifyMenu ModifyMenuW -#else -#define LoadMenu LoadMenuA -#define LoadMenuIndirect LoadMenuIndirectA -#define ChangeMenu ChangeMenuA -#define GetMenuString GetMenuStringA -#define InsertMenu InsertMenuA -#define AppendMenu AppendMenuA -#define ModifyMenu ModifyMenuA -#endif - - WINUSERAPI HMENU WINAPI LoadMenuA(HINSTANCE hInstance,LPCSTR lpMenuName); - WINUSERAPI HMENU WINAPI LoadMenuW(HINSTANCE hInstance,LPCWSTR lpMenuName); - WINUSERAPI HMENU WINAPI LoadMenuIndirectA(CONST MENUTEMPLATEA *lpMenuTemplate); - WINUSERAPI HMENU WINAPI LoadMenuIndirectW(CONST MENUTEMPLATEW *lpMenuTemplate); - WINUSERAPI HMENU WINAPI GetMenu(HWND hWnd); - WINUSERAPI WINBOOL WINAPI SetMenu(HWND hWnd,HMENU hMenu); - WINUSERAPI WINBOOL WINAPI ChangeMenuA(HMENU hMenu,UINT cmd,LPCSTR lpszNewItem,UINT cmdInsert,UINT flags); - WINUSERAPI WINBOOL WINAPI ChangeMenuW(HMENU hMenu,UINT cmd,LPCWSTR lpszNewItem,UINT cmdInsert,UINT flags); - WINUSERAPI WINBOOL WINAPI HiliteMenuItem(HWND hWnd,HMENU hMenu,UINT uIDHiliteItem,UINT uHilite); - WINUSERAPI int WINAPI GetMenuStringA(HMENU hMenu,UINT uIDItem,LPSTR lpString,int cchMax,UINT flags); - WINUSERAPI int WINAPI GetMenuStringW(HMENU hMenu,UINT uIDItem,LPWSTR lpString,int cchMax,UINT flags); - WINUSERAPI UINT WINAPI GetMenuState(HMENU hMenu,UINT uId,UINT uFlags); - WINUSERAPI WINBOOL WINAPI DrawMenuBar(HWND hWnd); - -#define PMB_ACTIVE 0x00000001 - - WINUSERAPI HMENU WINAPI GetSystemMenu(HWND hWnd,WINBOOL bRevert); - WINUSERAPI HMENU WINAPI CreateMenu(VOID); - WINUSERAPI HMENU WINAPI CreatePopupMenu(VOID); - WINUSERAPI WINBOOL WINAPI DestroyMenu(HMENU hMenu); - WINUSERAPI DWORD WINAPI CheckMenuItem(HMENU hMenu,UINT uIDCheckItem,UINT uCheck); - WINUSERAPI WINBOOL WINAPI EnableMenuItem(HMENU hMenu,UINT uIDEnableItem,UINT uEnable); - WINUSERAPI HMENU WINAPI GetSubMenu(HMENU hMenu,int nPos); - WINUSERAPI UINT WINAPI GetMenuItemID(HMENU hMenu,int nPos); - WINUSERAPI int WINAPI GetMenuItemCount(HMENU hMenu); - WINUSERAPI WINBOOL WINAPI InsertMenuA(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI InsertMenuW(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI AppendMenuA(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI AppendMenuW(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI ModifyMenuA(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI ModifyMenuW(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI RemoveMenu(HMENU hMenu,UINT uPosition,UINT uFlags); - WINUSERAPI WINBOOL WINAPI DeleteMenu(HMENU hMenu,UINT uPosition,UINT uFlags); - WINUSERAPI WINBOOL WINAPI SetMenuItemBitmaps(HMENU hMenu,UINT uPosition,UINT uFlags,HBITMAP hBitmapUnchecked,HBITMAP hBitmapChecked); - WINUSERAPI LONG WINAPI GetMenuCheckMarkDimensions(VOID); - WINUSERAPI WINBOOL WINAPI TrackPopupMenu(HMENU hMenu,UINT uFlags,int x,int y,int nReserved,HWND hWnd,CONST RECT *prcRect); - -#define MNC_IGNORE 0 -#define MNC_CLOSE 1 -#define MNC_EXECUTE 2 -#define MNC_SELECT 3 - - typedef struct tagTPMPARAMS { - UINT cbSize; - RECT rcExclude; - } TPMPARAMS; - - typedef TPMPARAMS *LPTPMPARAMS; - - WINUSERAPI WINBOOL WINAPI TrackPopupMenuEx(HMENU,UINT,int,int,HWND,LPTPMPARAMS); - -#define MNS_NOCHECK 0x80000000 -#define MNS_MODELESS 0x40000000 -#define MNS_DRAGDROP 0x20000000 -#define MNS_AUTODISMISS 0x10000000 -#define MNS_NOTIFYBYPOS 0x08000000 -#define MNS_CHECKORBMP 0x04000000 - -#define MIM_MAXHEIGHT 0x00000001 -#define MIM_BACKGROUND 0x00000002 -#define MIM_HELPID 0x00000004 -#define MIM_MENUDATA 0x00000008 -#define MIM_STYLE 0x00000010 -#define MIM_APPLYTOSUBMENUS 0x80000000 - - typedef struct tagMENUINFO { - DWORD cbSize; - DWORD fMask; - DWORD dwStyle; - UINT cyMax; - HBRUSH hbrBack; - DWORD dwContextHelpID; - ULONG_PTR dwMenuData; - } MENUINFO,*LPMENUINFO; - - typedef MENUINFO CONST *LPCMENUINFO; - - WINUSERAPI WINBOOL WINAPI GetMenuInfo(HMENU,LPMENUINFO); - WINUSERAPI WINBOOL WINAPI SetMenuInfo(HMENU,LPCMENUINFO); - WINUSERAPI WINBOOL WINAPI EndMenu(VOID); - -#define MND_CONTINUE 0 -#define MND_ENDMENU 1 - - typedef struct tagMENUGETOBJECTINFO { - DWORD dwFlags; - UINT uPos; - HMENU hmenu; - PVOID riid; - PVOID pvObj; - } MENUGETOBJECTINFO,*PMENUGETOBJECTINFO; - -#define MNGOF_TOPGAP 0x00000001 -#define MNGOF_BOTTOMGAP 0x00000002 - -#define MNGO_NOINTERFACE 0x00000000 -#define MNGO_NOERROR 0x00000001 - -#define MIIM_STATE 0x00000001 -#define MIIM_ID 0x00000002 -#define MIIM_SUBMENU 0x00000004 -#define MIIM_CHECKMARKS 0x00000008 -#define MIIM_TYPE 0x00000010 -#define MIIM_DATA 0x00000020 - -#define MIIM_STRING 0x00000040 -#define MIIM_BITMAP 0x00000080 -#define MIIM_FTYPE 0x00000100 - -#define HBMMENU_CALLBACK ((HBITMAP) -1) -#define HBMMENU_SYSTEM ((HBITMAP) 1) -#define HBMMENU_MBAR_RESTORE ((HBITMAP) 2) -#define HBMMENU_MBAR_MINIMIZE ((HBITMAP) 3) -#define HBMMENU_MBAR_CLOSE ((HBITMAP) 5) -#define HBMMENU_MBAR_CLOSE_D ((HBITMAP) 6) -#define HBMMENU_MBAR_MINIMIZE_D ((HBITMAP) 7) -#define HBMMENU_POPUP_CLOSE ((HBITMAP) 8) -#define HBMMENU_POPUP_RESTORE ((HBITMAP) 9) -#define HBMMENU_POPUP_MAXIMIZE ((HBITMAP) 10) -#define HBMMENU_POPUP_MINIMIZE ((HBITMAP) 11) - - typedef struct tagMENUITEMINFOA { - UINT cbSize; - UINT fMask; - UINT fType; - UINT fState; - UINT wID; - HMENU hSubMenu; - HBITMAP hbmpChecked; - HBITMAP hbmpUnchecked; - ULONG_PTR dwItemData; - LPSTR dwTypeData; - UINT cch; - HBITMAP hbmpItem; - } MENUITEMINFOA,*LPMENUITEMINFOA; - - typedef struct tagMENUITEMINFOW { - UINT cbSize; - UINT fMask; - UINT fType; - UINT fState; - UINT wID; - HMENU hSubMenu; - HBITMAP hbmpChecked; - HBITMAP hbmpUnchecked; - ULONG_PTR dwItemData; - LPWSTR dwTypeData; - UINT cch; - HBITMAP hbmpItem; - } MENUITEMINFOW,*LPMENUITEMINFOW; - -#ifdef UNICODE - typedef MENUITEMINFOW MENUITEMINFO; - typedef LPMENUITEMINFOW LPMENUITEMINFO; -#else - typedef MENUITEMINFOA MENUITEMINFO; - typedef LPMENUITEMINFOA LPMENUITEMINFO; -#endif - typedef MENUITEMINFOA CONST *LPCMENUITEMINFOA; - typedef MENUITEMINFOW CONST *LPCMENUITEMINFOW; -#ifdef UNICODE - typedef LPCMENUITEMINFOW LPCMENUITEMINFO; -#else - typedef LPCMENUITEMINFOA LPCMENUITEMINFO; -#endif - -#ifdef UNICODE -#define InsertMenuItem InsertMenuItemW -#define GetMenuItemInfo GetMenuItemInfoW -#define SetMenuItemInfo SetMenuItemInfoW -#else -#define InsertMenuItem InsertMenuItemA -#define GetMenuItemInfo GetMenuItemInfoA -#define SetMenuItemInfo SetMenuItemInfoA -#endif - - WINUSERAPI WINBOOL WINAPI InsertMenuItemA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOA lpmi); - WINUSERAPI WINBOOL WINAPI InsertMenuItemW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOW lpmi); - WINUSERAPI WINBOOL WINAPI GetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOA lpmii); - WINUSERAPI WINBOOL WINAPI GetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOW lpmii); - WINUSERAPI WINBOOL WINAPI SetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOA lpmii); - WINUSERAPI WINBOOL WINAPI SetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOW lpmii); - -#define GMDI_USEDISABLED 0x0001L -#define GMDI_GOINTOPOPUPS 0x0002L - - WINUSERAPI UINT WINAPI GetMenuDefaultItem(HMENU hMenu,UINT fByPos,UINT gmdiFlags); - WINUSERAPI WINBOOL WINAPI SetMenuDefaultItem(HMENU hMenu,UINT uItem,UINT fByPos); - WINUSERAPI WINBOOL WINAPI GetMenuItemRect(HWND hWnd,HMENU hMenu,UINT uItem,LPRECT lprcItem); - WINUSERAPI int WINAPI MenuItemFromPoint(HWND hWnd,HMENU hMenu,POINT ptScreen); - -#define TPM_LEFTBUTTON 0x0000L -#define TPM_RIGHTBUTTON 0x0002L -#define TPM_LEFTALIGN 0x0000L -#define TPM_CENTERALIGN 0x0004L -#define TPM_RIGHTALIGN 0x0008L -#define TPM_TOPALIGN 0x0000L -#define TPM_VCENTERALIGN 0x0010L -#define TPM_BOTTOMALIGN 0x0020L - -#define TPM_HORIZONTAL 0x0000L -#define TPM_VERTICAL 0x0040L -#define TPM_NONOTIFY 0x0080L -#define TPM_RETURNCMD 0x0100L -#define TPM_RECURSE 0x0001L -#define TPM_HORPOSANIMATION 0x0400L -#define TPM_HORNEGANIMATION 0x0800L -#define TPM_VERPOSANIMATION 0x1000L -#define TPM_VERNEGANIMATION 0x2000L -#define TPM_NOANIMATION 0x4000L -#define TPM_LAYOUTRTL 0x8000L -#endif - - typedef struct tagDROPSTRUCT { - HWND hwndSource; - HWND hwndSink; - DWORD wFmt; - ULONG_PTR dwData; - POINT ptDrop; - DWORD dwControlData; - } DROPSTRUCT,*PDROPSTRUCT,*LPDROPSTRUCT; - -#define DOF_EXECUTABLE 0x8001 -#define DOF_DOCUMENT 0x8002 -#define DOF_DIRECTORY 0x8003 -#define DOF_MULTIPLE 0x8004 -#define DOF_PROGMAN 0x0001 -#define DOF_SHELLDATA 0x0002 - -#define DO_DROPFILE 0x454C4946L -#define DO_PRINTFILE 0x544E5250L - - WINUSERAPI DWORD WINAPI DragObject(HWND hwndParent,HWND hwndFrom,UINT fmt,ULONG_PTR data,HCURSOR hcur); - WINUSERAPI WINBOOL WINAPI DragDetect(HWND hwnd,POINT pt); - WINUSERAPI WINBOOL WINAPI DrawIcon(HDC hDC,int X,int Y,HICON hIcon); - -#ifndef NODRAWTEXT - -#define DT_TOP 0x00000000 -#define DT_LEFT 0x00000000 -#define DT_CENTER 0x00000001 -#define DT_RIGHT 0x00000002 -#define DT_VCENTER 0x00000004 -#define DT_BOTTOM 0x00000008 -#define DT_WORDBREAK 0x00000010 -#define DT_SINGLELINE 0x00000020 -#define DT_EXPANDTABS 0x00000040 -#define DT_TABSTOP 0x00000080 -#define DT_NOCLIP 0x00000100 -#define DT_EXTERNALLEADING 0x00000200 -#define DT_CALCRECT 0x00000400 -#define DT_NOPREFIX 0x00000800 -#define DT_INTERNAL 0x00001000 - -#define DT_EDITCONTROL 0x00002000 -#define DT_PATH_ELLIPSIS 0x00004000 -#define DT_END_ELLIPSIS 0x00008000 -#define DT_MODIFYSTRING 0x00010000 -#define DT_RTLREADING 0x00020000 -#define DT_WORD_ELLIPSIS 0x00040000 -#define DT_NOFULLWIDTHCHARBREAK 0x00080000 -#define DT_HIDEPREFIX 0x00100000 -#define DT_PREFIXONLY 0x00200000 - - typedef struct tagDRAWTEXTPARAMS { - UINT cbSize; - int iTabLength; - int iLeftMargin; - int iRightMargin; - UINT uiLengthDrawn; - } DRAWTEXTPARAMS,*LPDRAWTEXTPARAMS; - -#ifdef UNICODE -#define DrawText DrawTextW -#define DrawTextEx DrawTextExW -#else -#define DrawText DrawTextA -#define DrawTextEx DrawTextExA -#endif - - WINUSERAPI int WINAPI DrawTextA(HDC hdc,LPCSTR lpchText,int cchText,LPRECT lprc,UINT format); - WINUSERAPI int WINAPI DrawTextW(HDC hdc,LPCWSTR lpchText,int cchText,LPRECT lprc,UINT format); - WINUSERAPI int WINAPI DrawTextExA(HDC hdc,LPSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); - WINUSERAPI int WINAPI DrawTextExW(HDC hdc,LPWSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); -#endif - -#ifdef UNICODE -#define GrayString GrayStringW -#define DrawState DrawStateW -#define TabbedTextOut TabbedTextOutW -#define GetTabbedTextExtent GetTabbedTextExtentW -#else -#define GrayString GrayStringA -#define DrawState DrawStateA -#define TabbedTextOut TabbedTextOutA -#define GetTabbedTextExtent GetTabbedTextExtentA -#endif - - WINUSERAPI WINBOOL WINAPI GrayStringA(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); - WINUSERAPI WINBOOL WINAPI GrayStringW(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); - -#define DST_COMPLEX 0x0000 -#define DST_TEXT 0x0001 -#define DST_PREFIXTEXT 0x0002 -#define DST_ICON 0x0003 -#define DST_BITMAP 0x0004 - -#define DSS_NORMAL 0x0000 -#define DSS_UNION 0x0010 -#define DSS_DISABLED 0x0020 -#define DSS_MONO 0x0080 -#define DSS_HIDEPREFIX 0x0200 -#define DSS_PREFIXONLY 0x0400 -#define DSS_RIGHT 0x8000 - - WINUSERAPI WINBOOL WINAPI DrawStateA(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); - WINUSERAPI WINBOOL WINAPI DrawStateW(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); - WINUSERAPI LONG WINAPI TabbedTextOutA(HDC hdc,int x,int y,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); - WINUSERAPI LONG WINAPI TabbedTextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); - WINUSERAPI DWORD WINAPI GetTabbedTextExtentA(HDC hdc,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); - WINUSERAPI DWORD WINAPI GetTabbedTextExtentW(HDC hdc,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); - WINUSERAPI WINBOOL WINAPI UpdateWindow(HWND hWnd); - WINUSERAPI HWND WINAPI SetActiveWindow(HWND hWnd); - WINUSERAPI HWND WINAPI GetForegroundWindow(VOID); - WINUSERAPI WINBOOL WINAPI PaintDesktop(HDC hdc); - WINUSERAPI VOID WINAPI SwitchToThisWindow(HWND hwnd,WINBOOL fUnknown); - WINUSERAPI WINBOOL WINAPI SetForegroundWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI AllowSetForegroundWindow(DWORD dwProcessId); - -#define ASFW_ANY ((DWORD)-1) - - WINUSERAPI WINBOOL WINAPI LockSetForegroundWindow(UINT uLockCode); - -#define LSFW_LOCK 1 -#define LSFW_UNLOCK 2 - - WINUSERAPI HWND WINAPI WindowFromDC(HDC hDC); - WINUSERAPI HDC WINAPI GetDC(HWND hWnd); - WINUSERAPI HDC WINAPI GetDCEx(HWND hWnd,HRGN hrgnClip,DWORD flags); - -#define DCX_WINDOW 0x00000001L -#define DCX_CACHE 0x00000002L -#define DCX_NORESETATTRS 0x00000004L -#define DCX_CLIPCHILDREN 0x00000008L -#define DCX_CLIPSIBLINGS 0x00000010L -#define DCX_PARENTCLIP 0x00000020L -#define DCX_EXCLUDERGN 0x00000040L -#define DCX_INTERSECTRGN 0x00000080L -#define DCX_EXCLUDEUPDATE 0x00000100L -#define DCX_INTERSECTUPDATE 0x00000200L -#define DCX_LOCKWINDOWUPDATE 0x00000400L - -#define DCX_VALIDATE 0x00200000L - - WINUSERAPI HDC WINAPI GetWindowDC(HWND hWnd); - WINUSERAPI int WINAPI ReleaseDC(HWND hWnd,HDC hDC); - WINUSERAPI HDC WINAPI BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint); - WINUSERAPI WINBOOL WINAPI EndPaint(HWND hWnd,CONST PAINTSTRUCT *lpPaint); - WINUSERAPI WINBOOL WINAPI GetUpdateRect(HWND hWnd,LPRECT lpRect,WINBOOL bErase); - WINUSERAPI int WINAPI GetUpdateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); - WINUSERAPI int WINAPI SetWindowRgn(HWND hWnd,HRGN hRgn,WINBOOL bRedraw); - WINUSERAPI int WINAPI GetWindowRgn(HWND hWnd,HRGN hRgn); - WINUSERAPI int WINAPI GetWindowRgnBox(HWND hWnd,LPRECT lprc); - WINUSERAPI int WINAPI ExcludeUpdateRgn(HDC hDC,HWND hWnd); - WINUSERAPI WINBOOL WINAPI InvalidateRect(HWND hWnd,CONST RECT *lpRect,WINBOOL bErase); - WINUSERAPI WINBOOL WINAPI ValidateRect(HWND hWnd,CONST RECT *lpRect); - WINUSERAPI WINBOOL WINAPI InvalidateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); - WINUSERAPI WINBOOL WINAPI ValidateRgn(HWND hWnd,HRGN hRgn); - WINUSERAPI WINBOOL WINAPI RedrawWindow(HWND hWnd,CONST RECT *lprcUpdate,HRGN hrgnUpdate,UINT flags); - -#define RDW_INVALIDATE 0x0001 -#define RDW_INTERNALPAINT 0x0002 -#define RDW_ERASE 0x0004 - -#define RDW_VALIDATE 0x0008 -#define RDW_NOINTERNALPAINT 0x0010 -#define RDW_NOERASE 0x0020 - -#define RDW_NOCHILDREN 0x0040 -#define RDW_ALLCHILDREN 0x0080 - -#define RDW_UPDATENOW 0x0100 -#define RDW_ERASENOW 0x0200 - -#define RDW_FRAME 0x0400 -#define RDW_NOFRAME 0x0800 - - WINUSERAPI WINBOOL WINAPI LockWindowUpdate(HWND hWndLock); - WINUSERAPI WINBOOL WINAPI ScrollWindow(HWND hWnd,int XAmount,int YAmount,CONST RECT *lpRect,CONST RECT *lpClipRect); - WINUSERAPI WINBOOL WINAPI ScrollDC(HDC hDC,int dx,int dy,CONST RECT *lprcScroll,CONST RECT *lprcClip,HRGN hrgnUpdate,LPRECT lprcUpdate); - WINUSERAPI int WINAPI ScrollWindowEx(HWND hWnd,int dx,int dy,CONST RECT *prcScroll,CONST RECT *prcClip,HRGN hrgnUpdate,LPRECT prcUpdate,UINT flags); - -#define SW_SCROLLCHILDREN 0x0001 -#define SW_INVALIDATE 0x0002 -#define SW_ERASE 0x0004 -#define SW_SMOOTHSCROLL 0x0010 - -#ifndef NOSCROLL - WINUSERAPI int WINAPI SetScrollPos(HWND hWnd,int nBar,int nPos,WINBOOL bRedraw); - WINUSERAPI int WINAPI GetScrollPos(HWND hWnd,int nBar); - WINUSERAPI WINBOOL WINAPI SetScrollRange(HWND hWnd,int nBar,int nMinPos,int nMaxPos,WINBOOL bRedraw); - WINUSERAPI WINBOOL WINAPI GetScrollRange(HWND hWnd,int nBar,LPINT lpMinPos,LPINT lpMaxPos); - WINUSERAPI WINBOOL WINAPI ShowScrollBar(HWND hWnd,int wBar,WINBOOL bShow); - WINUSERAPI WINBOOL WINAPI EnableScrollBar(HWND hWnd,UINT wSBflags,UINT wArrows); - -#define ESB_ENABLE_BOTH 0x0000 -#define ESB_DISABLE_BOTH 0x0003 - -#define ESB_DISABLE_LEFT 0x0001 -#define ESB_DISABLE_RIGHT 0x0002 - -#define ESB_DISABLE_UP 0x0001 -#define ESB_DISABLE_DOWN 0x0002 - -#define ESB_DISABLE_LTUP ESB_DISABLE_LEFT -#define ESB_DISABLE_RTDN ESB_DISABLE_RIGHT -#endif - -#ifdef UNICODE -#define SetProp SetPropW -#define GetProp GetPropW -#define RemoveProp RemovePropW -#define EnumPropsEx EnumPropsExW -#define EnumProps EnumPropsW -#define SetWindowText SetWindowTextW -#define GetWindowText GetWindowTextW -#define GetWindowTextLength GetWindowTextLengthW -#else -#define SetProp SetPropA -#define GetProp GetPropA -#define RemoveProp RemovePropA -#define EnumPropsEx EnumPropsExA -#define EnumProps EnumPropsA -#define SetWindowText SetWindowTextA -#define GetWindowText GetWindowTextA -#define GetWindowTextLength GetWindowTextLengthA -#endif - - WINUSERAPI WINBOOL WINAPI SetPropA(HWND hWnd,LPCSTR lpString,HANDLE hData); - WINUSERAPI WINBOOL WINAPI SetPropW(HWND hWnd,LPCWSTR lpString,HANDLE hData); - WINUSERAPI HANDLE WINAPI GetPropA(HWND hWnd,LPCSTR lpString); - WINUSERAPI HANDLE WINAPI GetPropW(HWND hWnd,LPCWSTR lpString); - WINUSERAPI HANDLE WINAPI RemovePropA(HWND hWnd,LPCSTR lpString); - WINUSERAPI HANDLE WINAPI RemovePropW(HWND hWnd,LPCWSTR lpString); - WINUSERAPI int WINAPI EnumPropsExA(HWND hWnd,PROPENUMPROCEXA lpEnumFunc,LPARAM lParam); - WINUSERAPI int WINAPI EnumPropsExW(HWND hWnd,PROPENUMPROCEXW lpEnumFunc,LPARAM lParam); - WINUSERAPI int WINAPI EnumPropsA(HWND hWnd,PROPENUMPROCA lpEnumFunc); - WINUSERAPI int WINAPI EnumPropsW(HWND hWnd,PROPENUMPROCW lpEnumFunc); - WINUSERAPI WINBOOL WINAPI SetWindowTextA(HWND hWnd,LPCSTR lpString); - WINUSERAPI WINBOOL WINAPI SetWindowTextW(HWND hWnd,LPCWSTR lpString); - WINUSERAPI int WINAPI GetWindowTextA(HWND hWnd,LPSTR lpString,int nMaxCount); - WINUSERAPI int WINAPI GetWindowTextW(HWND hWnd,LPWSTR lpString,int nMaxCount); - WINUSERAPI int WINAPI GetWindowTextLengthA(HWND hWnd); - WINUSERAPI int WINAPI GetWindowTextLengthW(HWND hWnd); - WINUSERAPI WINBOOL WINAPI GetClientRect(HWND hWnd,LPRECT lpRect); - WINUSERAPI WINBOOL WINAPI GetWindowRect(HWND hWnd,LPRECT lpRect); - WINUSERAPI WINBOOL WINAPI AdjustWindowRect(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu); - WINUSERAPI WINBOOL WINAPI AdjustWindowRectEx(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu,DWORD dwExStyle); - -#define HELPINFO_WINDOW 0x0001 -#define HELPINFO_MENUITEM 0x0002 - - typedef struct tagHELPINFO { - UINT cbSize; - int iContextType; - int iCtrlId; - HANDLE hItemHandle; - DWORD_PTR dwContextId; - POINT MousePos; - } HELPINFO,*LPHELPINFO; - - WINUSERAPI WINBOOL WINAPI SetWindowContextHelpId(HWND,DWORD); - WINUSERAPI DWORD WINAPI GetWindowContextHelpId(HWND); - WINUSERAPI WINBOOL WINAPI SetMenuContextHelpId(HMENU,DWORD); - WINUSERAPI DWORD WINAPI GetMenuContextHelpId(HMENU); - -#ifndef NOMB - -#define MB_OK 0x00000000L -#define MB_OKCANCEL 0x00000001L -#define MB_ABORTRETRYIGNORE 0x00000002L -#define MB_YESNOCANCEL 0x00000003L -#define MB_YESNO 0x00000004L -#define MB_RETRYCANCEL 0x00000005L -#define MB_CANCELTRYCONTINUE 0x00000006L -#define MB_ICONHAND 0x00000010L -#define MB_ICONQUESTION 0x00000020L -#define MB_ICONEXCLAMATION 0x00000030L -#define MB_ICONASTERISK 0x00000040L -#define MB_USERICON 0x00000080L -#define MB_ICONWARNING MB_ICONEXCLAMATION -#define MB_ICONERROR MB_ICONHAND -#define MB_ICONINFORMATION MB_ICONASTERISK -#define MB_ICONSTOP MB_ICONHAND -#define MB_DEFBUTTON1 0x00000000L -#define MB_DEFBUTTON2 0x00000100L -#define MB_DEFBUTTON3 0x00000200L -#define MB_DEFBUTTON4 0x00000300L -#define MB_APPLMODAL 0x00000000L -#define MB_SYSTEMMODAL 0x00001000L -#define MB_TASKMODAL 0x00002000L -#define MB_HELP 0x00004000L -#define MB_NOFOCUS 0x00008000L -#define MB_SETFOREGROUND 0x00010000L -#define MB_DEFAULT_DESKTOP_ONLY 0x00020000L -#define MB_TOPMOST 0x00040000L -#define MB_RIGHT 0x00080000L -#define MB_RTLREADING 0x00100000L -#define MB_SERVICE_NOTIFICATION 0x00200000L -#define MB_SERVICE_NOTIFICATION_NT3X 0x00040000L -#define MB_TYPEMASK 0x0000000FL -#define MB_ICONMASK 0x000000F0L -#define MB_DEFMASK 0x00000F00L -#define MB_MODEMASK 0x00003000L -#define MB_MISCMASK 0x0000C000L - -#ifdef UNICODE -#define MessageBox MessageBoxW -#define MessageBoxEx MessageBoxExW -#else -#define MessageBox MessageBoxA -#define MessageBoxEx MessageBoxExA -#endif - - WINUSERAPI int WINAPI MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); - WINUSERAPI int WINAPI MessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); - WINUSERAPI int WINAPI MessageBoxExA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType,WORD wLanguageId); - WINUSERAPI int WINAPI MessageBoxExW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType,WORD wLanguageId); - - typedef VOID (CALLBACK *MSGBOXCALLBACK)(LPHELPINFO lpHelpInfo); - - typedef struct tagMSGBOXPARAMSA { - UINT cbSize; - HWND hwndOwner; - HINSTANCE hInstance; - LPCSTR lpszText; - LPCSTR lpszCaption; - DWORD dwStyle; - LPCSTR lpszIcon; - DWORD_PTR dwContextHelpId; - MSGBOXCALLBACK lpfnMsgBoxCallback; - DWORD dwLanguageId; - } MSGBOXPARAMSA,*PMSGBOXPARAMSA,*LPMSGBOXPARAMSA; - - typedef struct tagMSGBOXPARAMSW { - UINT cbSize; - HWND hwndOwner; - HINSTANCE hInstance; - LPCWSTR lpszText; - LPCWSTR lpszCaption; - DWORD dwStyle; - LPCWSTR lpszIcon; - DWORD_PTR dwContextHelpId; - MSGBOXCALLBACK lpfnMsgBoxCallback; - DWORD dwLanguageId; - } MSGBOXPARAMSW,*PMSGBOXPARAMSW,*LPMSGBOXPARAMSW; - -#ifdef UNICODE - typedef MSGBOXPARAMSW MSGBOXPARAMS; - typedef PMSGBOXPARAMSW PMSGBOXPARAMS; - typedef LPMSGBOXPARAMSW LPMSGBOXPARAMS; -#else - typedef MSGBOXPARAMSA MSGBOXPARAMS; - typedef PMSGBOXPARAMSA PMSGBOXPARAMS; - typedef LPMSGBOXPARAMSA LPMSGBOXPARAMS; -#endif - -#ifdef UNICODE -#define MessageBoxIndirect MessageBoxIndirectW -#else -#define MessageBoxIndirect MessageBoxIndirectA -#endif - - WINUSERAPI int WINAPI MessageBoxIndirectA(CONST MSGBOXPARAMSA *lpmbp); - WINUSERAPI int WINAPI MessageBoxIndirectW(CONST MSGBOXPARAMSW *lpmbp); - WINUSERAPI WINBOOL WINAPI MessageBeep(UINT uType); -#endif - - WINUSERAPI int WINAPI ShowCursor(WINBOOL bShow); - WINUSERAPI WINBOOL WINAPI SetCursorPos(int X,int Y); - WINUSERAPI HCURSOR WINAPI SetCursor(HCURSOR hCursor); - WINUSERAPI WINBOOL WINAPI GetCursorPos(LPPOINT lpPoint); - WINUSERAPI WINBOOL WINAPI ClipCursor(CONST RECT *lpRect); - WINUSERAPI WINBOOL WINAPI GetClipCursor(LPRECT lpRect); - WINUSERAPI HCURSOR WINAPI GetCursor(VOID); - WINUSERAPI WINBOOL WINAPI CreateCaret(HWND hWnd,HBITMAP hBitmap,int nWidth,int nHeight); - WINUSERAPI UINT WINAPI GetCaretBlinkTime(VOID); - WINUSERAPI WINBOOL WINAPI SetCaretBlinkTime(UINT uMSeconds); - WINUSERAPI WINBOOL WINAPI DestroyCaret(VOID); - WINUSERAPI WINBOOL WINAPI HideCaret(HWND hWnd); - WINUSERAPI WINBOOL WINAPI ShowCaret(HWND hWnd); - WINUSERAPI WINBOOL WINAPI SetCaretPos(int X,int Y); - WINUSERAPI WINBOOL WINAPI GetCaretPos(LPPOINT lpPoint); - WINUSERAPI WINBOOL WINAPI ClientToScreen(HWND hWnd,LPPOINT lpPoint); - WINUSERAPI WINBOOL WINAPI ScreenToClient(HWND hWnd,LPPOINT lpPoint); - WINUSERAPI int WINAPI MapWindowPoints(HWND hWndFrom,HWND hWndTo,LPPOINT lpPoints,UINT cPoints); - WINUSERAPI HWND WINAPI WindowFromPoint(POINT Point); - WINUSERAPI HWND WINAPI ChildWindowFromPoint(HWND hWndParent,POINT Point); - -#define CWP_ALL 0x0000 -#define CWP_SKIPINVISIBLE 0x0001 -#define CWP_SKIPDISABLED 0x0002 -#define CWP_SKIPTRANSPARENT 0x0004 - - WINUSERAPI HWND WINAPI ChildWindowFromPointEx(HWND hwnd,POINT pt,UINT flags); - -#ifndef NOCOLOR - -#define CTLCOLOR_MSGBOX 0 -#define CTLCOLOR_EDIT 1 -#define CTLCOLOR_LISTBOX 2 -#define CTLCOLOR_BTN 3 -#define CTLCOLOR_DLG 4 -#define CTLCOLOR_SCROLLBAR 5 -#define CTLCOLOR_STATIC 6 -#define CTLCOLOR_MAX 7 - -#define COLOR_SCROLLBAR 0 -#define COLOR_BACKGROUND 1 -#define COLOR_ACTIVECAPTION 2 -#define COLOR_INACTIVECAPTION 3 -#define COLOR_MENU 4 -#define COLOR_WINDOW 5 -#define COLOR_WINDOWFRAME 6 -#define COLOR_MENUTEXT 7 -#define COLOR_WINDOWTEXT 8 -#define COLOR_CAPTIONTEXT 9 -#define COLOR_ACTIVEBORDER 10 -#define COLOR_INACTIVEBORDER 11 -#define COLOR_APPWORKSPACE 12 -#define COLOR_HIGHLIGHT 13 -#define COLOR_HIGHLIGHTTEXT 14 -#define COLOR_BTNFACE 15 -#define COLOR_BTNSHADOW 16 -#define COLOR_GRAYTEXT 17 -#define COLOR_BTNTEXT 18 -#define COLOR_INACTIVECAPTIONTEXT 19 -#define COLOR_BTNHIGHLIGHT 20 - -#define COLOR_3DDKSHADOW 21 -#define COLOR_3DLIGHT 22 -#define COLOR_INFOTEXT 23 -#define COLOR_INFOBK 24 - -#define COLOR_HOTLIGHT 26 -#define COLOR_GRADIENTACTIVECAPTION 27 -#define COLOR_GRADIENTINACTIVECAPTION 28 -#define COLOR_MENUHILIGHT 29 -#define COLOR_MENUBAR 30 - -#define COLOR_DESKTOP COLOR_BACKGROUND -#define COLOR_3DFACE COLOR_BTNFACE -#define COLOR_3DSHADOW COLOR_BTNSHADOW -#define COLOR_3DHIGHLIGHT COLOR_BTNHIGHLIGHT -#define COLOR_3DHILIGHT COLOR_BTNHIGHLIGHT -#define COLOR_BTNHILIGHT COLOR_BTNHIGHLIGHT - - WINUSERAPI DWORD WINAPI GetSysColor(int nIndex); - WINUSERAPI HBRUSH WINAPI GetSysColorBrush(int nIndex); - WINUSERAPI WINBOOL WINAPI SetSysColors(int cElements,CONST INT *lpaElements,CONST COLORREF *lpaRgbValues); -#endif - - WINUSERAPI WINBOOL WINAPI DrawFocusRect(HDC hDC,CONST RECT *lprc); - WINUSERAPI int WINAPI FillRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); - WINUSERAPI int WINAPI FrameRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); - WINUSERAPI WINBOOL WINAPI InvertRect(HDC hDC,CONST RECT *lprc); - WINUSERAPI WINBOOL WINAPI SetRect(LPRECT lprc,int xLeft,int yTop,int xRight,int yBottom); - WINUSERAPI WINBOOL WINAPI SetRectEmpty(LPRECT lprc); - WINUSERAPI WINBOOL WINAPI CopyRect(LPRECT lprcDst,CONST RECT *lprcSrc); - WINUSERAPI WINBOOL WINAPI InflateRect(LPRECT lprc,int dx,int dy); - WINUSERAPI WINBOOL WINAPI IntersectRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); - WINUSERAPI WINBOOL WINAPI UnionRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); - WINUSERAPI WINBOOL WINAPI SubtractRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); - WINUSERAPI WINBOOL WINAPI OffsetRect(LPRECT lprc,int dx,int dy); - WINUSERAPI WINBOOL WINAPI IsRectEmpty(CONST RECT *lprc); - WINUSERAPI WINBOOL WINAPI EqualRect(CONST RECT *lprc1,CONST RECT *lprc2); - WINUSERAPI WINBOOL WINAPI PtInRect(CONST RECT *lprc,POINT pt); - -#ifndef NOWINOFFSETS - -#ifdef UNICODE -#define GetWindowLong GetWindowLongW -#define SetWindowLong SetWindowLongW -#else -#define GetWindowLong GetWindowLongA -#define SetWindowLong SetWindowLongA -#endif - - WINUSERAPI WORD WINAPI GetWindowWord(HWND hWnd,int nIndex); - WINUSERAPI WORD WINAPI SetWindowWord(HWND hWnd,int nIndex,WORD wNewWord); - WINUSERAPI LONG WINAPI GetWindowLongA(HWND hWnd,int nIndex); - WINUSERAPI LONG WINAPI GetWindowLongW(HWND hWnd,int nIndex); - WINUSERAPI LONG WINAPI SetWindowLongA(HWND hWnd,int nIndex,LONG dwNewLong); - WINUSERAPI LONG WINAPI SetWindowLongW(HWND hWnd,int nIndex,LONG dwNewLong); - -#ifdef _WIN64 - -#ifdef UNICODE -#define GetWindowLongPtr GetWindowLongPtrW -#define SetWindowLongPtr SetWindowLongPtrW -#else -#define GetWindowLongPtr GetWindowLongPtrA -#define SetWindowLongPtr SetWindowLongPtrA -#endif - - WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrA(HWND hWnd,int nIndex); - WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrW(HWND hWnd,int nIndex); - WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); - WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); -#else - -#ifdef UNICODE -#define GetWindowLongPtr GetWindowLongPtrW -#define SetWindowLongPtr SetWindowLongPtrW -#else -#define GetWindowLongPtr GetWindowLongPtrA -#define SetWindowLongPtr SetWindowLongPtrA -#endif - -#define GetWindowLongPtrA GetWindowLongA -#define GetWindowLongPtrW GetWindowLongW -#define SetWindowLongPtrA SetWindowLongA -#define SetWindowLongPtrW SetWindowLongW -#endif - -#ifdef UNICODE -#define GetClassLong GetClassLongW -#define SetClassLong SetClassLongW -#else -#define GetClassLong GetClassLongA -#define SetClassLong SetClassLongA -#endif - - WINUSERAPI WORD WINAPI GetClassWord(HWND hWnd,int nIndex); - WINUSERAPI WORD WINAPI SetClassWord(HWND hWnd,int nIndex,WORD wNewWord); - WINUSERAPI DWORD WINAPI GetClassLongA(HWND hWnd,int nIndex); - WINUSERAPI DWORD WINAPI GetClassLongW(HWND hWnd,int nIndex); - WINUSERAPI DWORD WINAPI SetClassLongA(HWND hWnd,int nIndex,LONG dwNewLong); - WINUSERAPI DWORD WINAPI SetClassLongW(HWND hWnd,int nIndex,LONG dwNewLong); - -#ifdef _WIN64 - -#ifdef UNICODE -#define GetClassLongPtr GetClassLongPtrW -#define SetClassLongPtr SetClassLongPtrW -#else -#define GetClassLongPtr GetClassLongPtrA -#define SetClassLongPtr SetClassLongPtrA -#endif - - WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrA(HWND hWnd,int nIndex); - WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrW(HWND hWnd,int nIndex); - WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); - WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); -#else -#ifdef UNICODE -#define GetClassLongPtr GetClassLongPtrW -#define SetClassLongPtr SetClassLongPtrW -#else -#define GetClassLongPtr GetClassLongPtrA -#define SetClassLongPtr SetClassLongPtrA -#endif - -#define GetClassLongPtrA GetClassLongA -#define GetClassLongPtrW GetClassLongW -#define SetClassLongPtrA SetClassLongA -#define SetClassLongPtrW SetClassLongW -#endif -#endif - -#ifdef UNICODE -#define FindWindow FindWindowW -#define FindWindowEx FindWindowExW -#define GetClassName GetClassNameW -#else -#define FindWindow FindWindowA -#define FindWindowEx FindWindowExA -#define GetClassName GetClassNameA -#endif - - WINUSERAPI WINBOOL WINAPI GetProcessDefaultLayout(DWORD *pdwDefaultLayout); - WINUSERAPI WINBOOL WINAPI SetProcessDefaultLayout(DWORD dwDefaultLayout); - WINUSERAPI HWND WINAPI GetDesktopWindow(VOID); - WINUSERAPI HWND WINAPI GetParent(HWND hWnd); - WINUSERAPI HWND WINAPI SetParent(HWND hWndChild,HWND hWndNewParent); - WINUSERAPI WINBOOL WINAPI EnumChildWindows(HWND hWndParent,WNDENUMPROC lpEnumFunc,LPARAM lParam); - WINUSERAPI HWND WINAPI FindWindowA(LPCSTR lpClassName,LPCSTR lpWindowName); - WINUSERAPI HWND WINAPI FindWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName); - WINUSERAPI HWND WINAPI FindWindowExA(HWND hWndParent,HWND hWndChildAfter,LPCSTR lpszClass,LPCSTR lpszWindow); - WINUSERAPI HWND WINAPI FindWindowExW(HWND hWndParent,HWND hWndChildAfter,LPCWSTR lpszClass,LPCWSTR lpszWindow); - WINUSERAPI HWND WINAPI GetShellWindow(VOID); - WINUSERAPI WINBOOL WINAPI RegisterShellHookWindow(HWND hwnd); - WINUSERAPI WINBOOL WINAPI DeregisterShellHookWindow(HWND hwnd); - WINUSERAPI WINBOOL WINAPI EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumThreadWindows(DWORD dwThreadId,WNDENUMPROC lpfn,LPARAM lParam); - -#define EnumTaskWindows(hTask,lpfn,lParam) EnumThreadWindows(HandleToUlong(hTask),lpfn,lParam) - - WINUSERAPI int WINAPI GetClassNameA(HWND hWnd,LPSTR lpClassName,int nMaxCount); - WINUSERAPI int WINAPI GetClassNameW(HWND hWnd,LPWSTR lpClassName,int nMaxCount); - WINUSERAPI HWND WINAPI GetTopWindow(HWND hWnd); - -#define GetNextWindow(hWnd,wCmd) GetWindow(hWnd,wCmd) -#define GetSysModalWindow() (NULL) -#define SetSysModalWindow(hWnd) (NULL) - - WINUSERAPI DWORD WINAPI GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId); - WINUSERAPI WINBOOL WINAPI IsGUIThread(WINBOOL bConvert); - -#define GetWindowTask(hWnd) ((HANDLE)(DWORD_PTR)GetWindowThreadProcessId(hWnd,NULL)) - - WINUSERAPI HWND WINAPI GetLastActivePopup(HWND hWnd); - -#define GW_HWNDFIRST 0 -#define GW_HWNDLAST 1 -#define GW_HWNDNEXT 2 -#define GW_HWNDPREV 3 -#define GW_OWNER 4 -#define GW_CHILD 5 -#define GW_ENABLEDPOPUP 6 -#define GW_MAX 6 - - WINUSERAPI HWND WINAPI GetWindow(HWND hWnd,UINT uCmd); - -#ifndef NOWH - -#ifdef UNICODE -#define SetWindowsHook SetWindowsHookW -#define SetWindowsHookEx SetWindowsHookExW -#else -#define SetWindowsHook SetWindowsHookA -#define SetWindowsHookEx SetWindowsHookExA -#endif - - WINUSERAPI HHOOK WINAPI SetWindowsHookA(int nFilterType,HOOKPROC pfnFilterProc); - WINUSERAPI HHOOK WINAPI SetWindowsHookW(int nFilterType,HOOKPROC pfnFilterProc); - WINUSERAPI WINBOOL WINAPI UnhookWindowsHook(int nCode,HOOKPROC pfnFilterProc); - WINUSERAPI HHOOK WINAPI SetWindowsHookExA(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); - WINUSERAPI HHOOK WINAPI SetWindowsHookExW(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); - WINUSERAPI WINBOOL WINAPI UnhookWindowsHookEx(HHOOK hhk); - WINUSERAPI LRESULT WINAPI CallNextHookEx(HHOOK hhk,int nCode,WPARAM wParam,LPARAM lParam); -#define DefHookProc(nCode,wParam,lParam,phhk) CallNextHookEx(*phhk,nCode,wParam,lParam) -#endif - -#ifndef NOMENUS - -#define MF_INSERT 0x00000000L -#define MF_CHANGE 0x00000080L -#define MF_APPEND 0x00000100L -#define MF_DELETE 0x00000200L -#define MF_REMOVE 0x00001000L -#define MF_BYCOMMAND 0x00000000L -#define MF_BYPOSITION 0x00000400L -#define MF_SEPARATOR 0x00000800L -#define MF_ENABLED 0x00000000L -#define MF_GRAYED 0x00000001L -#define MF_DISABLED 0x00000002L -#define MF_UNCHECKED 0x00000000L -#define MF_CHECKED 0x00000008L -#define MF_USECHECKBITMAPS 0x00000200L -#define MF_STRING 0x00000000L -#define MF_BITMAP 0x00000004L -#define MF_OWNERDRAW 0x00000100L -#define MF_POPUP 0x00000010L -#define MF_MENUBARBREAK 0x00000020L -#define MF_MENUBREAK 0x00000040L -#define MF_UNHILITE 0x00000000L -#define MF_HILITE 0x00000080L -#define MF_DEFAULT 0x00001000L -#define MF_SYSMENU 0x00002000L -#define MF_HELP 0x00004000L -#define MF_RIGHTJUSTIFY 0x00004000L -#define MF_MOUSESELECT 0x00008000L -#define MF_END 0x00000080L - -#define MFT_STRING MF_STRING -#define MFT_BITMAP MF_BITMAP -#define MFT_MENUBARBREAK MF_MENUBARBREAK -#define MFT_MENUBREAK MF_MENUBREAK -#define MFT_OWNERDRAW MF_OWNERDRAW -#define MFT_RADIOCHECK 0x00000200L -#define MFT_SEPARATOR MF_SEPARATOR -#define MFT_RIGHTORDER 0x00002000L -#define MFT_RIGHTJUSTIFY MF_RIGHTJUSTIFY - -#define MFS_GRAYED 0x00000003L -#define MFS_DISABLED MFS_GRAYED -#define MFS_CHECKED MF_CHECKED -#define MFS_HILITE MF_HILITE -#define MFS_ENABLED MF_ENABLED -#define MFS_UNCHECKED MF_UNCHECKED -#define MFS_UNHILITE MF_UNHILITE -#define MFS_DEFAULT MF_DEFAULT - - WINUSERAPI WINBOOL WINAPI CheckMenuRadioItem(HMENU hmenu,UINT first,UINT last,UINT check,UINT flags); - - typedef struct { - WORD versionNumber; - WORD offset; - } MENUITEMTEMPLATEHEADER,*PMENUITEMTEMPLATEHEADER; - - typedef struct { - WORD mtOption; - WORD mtID; - WCHAR mtString[1]; - } MENUITEMTEMPLATE,*PMENUITEMTEMPLATE; -#define MF_END 0x00000080L -#endif - -#ifndef NOSYSCOMMANDS - -#define SC_SIZE 0xF000 -#define SC_MOVE 0xF010 -#define SC_MINIMIZE 0xF020 -#define SC_MAXIMIZE 0xF030 -#define SC_NEXTWINDOW 0xF040 -#define SC_PREVWINDOW 0xF050 -#define SC_CLOSE 0xF060 -#define SC_VSCROLL 0xF070 -#define SC_HSCROLL 0xF080 -#define SC_MOUSEMENU 0xF090 -#define SC_KEYMENU 0xF100 -#define SC_ARRANGE 0xF110 -#define SC_RESTORE 0xF120 -#define SC_TASKLIST 0xF130 -#define SC_SCREENSAVE 0xF140 -#define SC_HOTKEY 0xF150 -#define SC_DEFAULT 0xF160 -#define SC_MONITORPOWER 0xF170 -#define SC_CONTEXTHELP 0xF180 -#define SC_SEPARATOR 0xF00F -#define SC_ICON SC_MINIMIZE -#define SC_ZOOM SC_MAXIMIZE -#endif - -#ifdef UNICODE -#define LoadBitmap LoadBitmapW -#define LoadCursor LoadCursorW -#define LoadCursorFromFile LoadCursorFromFileW -#else -#define LoadBitmap LoadBitmapA -#define LoadCursor LoadCursorA -#define LoadCursorFromFile LoadCursorFromFileA -#endif - - WINUSERAPI HBITMAP WINAPI LoadBitmapA(HINSTANCE hInstance,LPCSTR lpBitmapName); - WINUSERAPI HBITMAP WINAPI LoadBitmapW(HINSTANCE hInstance,LPCWSTR lpBitmapName); - WINUSERAPI HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance,LPCSTR lpCursorName); - WINUSERAPI HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance,LPCWSTR lpCursorName); - WINUSERAPI HCURSOR WINAPI LoadCursorFromFileA(LPCSTR lpFileName); - WINUSERAPI HCURSOR WINAPI LoadCursorFromFileW(LPCWSTR lpFileName); - WINUSERAPI HCURSOR WINAPI CreateCursor(HINSTANCE hInst,int xHotSpot,int yHotSpot,int nWidth,int nHeight,CONST VOID *pvANDPlane,CONST VOID *pvXORPlane); - WINUSERAPI WINBOOL WINAPI DestroyCursor(HCURSOR hCursor); - -#define CopyCursor(pcur) ((HCURSOR)CopyIcon((HICON)(pcur))) - -#define IDC_ARROW MAKEINTRESOURCE(32512) -#define IDC_IBEAM MAKEINTRESOURCE(32513) -#define IDC_WAIT MAKEINTRESOURCE(32514) -#define IDC_CROSS MAKEINTRESOURCE(32515) -#define IDC_UPARROW MAKEINTRESOURCE(32516) -#define IDC_SIZE MAKEINTRESOURCE(32640) -#define IDC_ICON MAKEINTRESOURCE(32641) -#define IDC_SIZENWSE MAKEINTRESOURCE(32642) -#define IDC_SIZENESW MAKEINTRESOURCE(32643) -#define IDC_SIZEWE MAKEINTRESOURCE(32644) -#define IDC_SIZENS MAKEINTRESOURCE(32645) -#define IDC_SIZEALL MAKEINTRESOURCE(32646) -#define IDC_NO MAKEINTRESOURCE(32648) -#define IDC_HAND MAKEINTRESOURCE(32649) -#define IDC_APPSTARTING MAKEINTRESOURCE(32650) -#define IDC_HELP MAKEINTRESOURCE(32651) - - WINUSERAPI WINBOOL WINAPI SetSystemCursor(HCURSOR hcur,DWORD id); - - typedef struct _ICONINFO { - WINBOOL fIcon; - DWORD xHotspot; - DWORD yHotspot; - HBITMAP hbmMask; - HBITMAP hbmColor; - } ICONINFO; - typedef ICONINFO *PICONINFO; - -#ifdef UNICODE -#define LoadIcon LoadIconW -#define PrivateExtractIcons PrivateExtractIconsW -#else -#define LoadIcon LoadIconA -#define PrivateExtractIcons PrivateExtractIconsA -#endif - - WINUSERAPI HICON WINAPI LoadIconA(HINSTANCE hInstance,LPCSTR lpIconName); - WINUSERAPI HICON WINAPI LoadIconW(HINSTANCE hInstance,LPCWSTR lpIconName); - WINUSERAPI UINT WINAPI PrivateExtractIconsA(LPCSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); - WINUSERAPI UINT WINAPI PrivateExtractIconsW(LPCWSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); - WINUSERAPI HICON WINAPI CreateIcon(HINSTANCE hInstance,int nWidth,int nHeight,BYTE cPlanes,BYTE cBitsPixel,CONST BYTE *lpbANDbits,CONST BYTE *lpbXORbits); - WINUSERAPI WINBOOL WINAPI DestroyIcon(HICON hIcon); - WINUSERAPI int WINAPI LookupIconIdFromDirectory(PBYTE presbits,WINBOOL fIcon); - WINUSERAPI int WINAPI LookupIconIdFromDirectoryEx(PBYTE presbits,WINBOOL fIcon,int cxDesired,int cyDesired,UINT Flags); - WINUSERAPI HICON WINAPI CreateIconFromResource(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer); - WINUSERAPI HICON WINAPI CreateIconFromResourceEx(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer,int cxDesired,int cyDesired,UINT Flags); - - typedef struct tagCURSORSHAPE { - int xHotSpot; - int yHotSpot; - int cx; - int cy; - int cbWidth; - BYTE Planes; - BYTE BitsPixel; - } CURSORSHAPE,*LPCURSORSHAPE; - -#define IMAGE_BITMAP 0 -#define IMAGE_ICON 1 -#define IMAGE_CURSOR 2 -#define IMAGE_ENHMETAFILE 3 - -#define LR_DEFAULTCOLOR 0x0000 -#define LR_MONOCHROME 0x0001 -#define LR_COLOR 0x0002 -#define LR_COPYRETURNORG 0x0004 -#define LR_COPYDELETEORG 0x0008 -#define LR_LOADFROMFILE 0x0010 -#define LR_LOADTRANSPARENT 0x0020 -#define LR_DEFAULTSIZE 0x0040 -#define LR_VGACOLOR 0x0080 -#define LR_LOADMAP3DCOLORS 0x1000 -#define LR_CREATEDIBSECTION 0x2000 -#define LR_COPYFROMRESOURCE 0x4000 -#define LR_SHARED 0x8000 - -#ifdef UNICODE -#define LoadImage LoadImageW -#else -#define LoadImage LoadImageA -#endif - - WINUSERAPI HANDLE WINAPI LoadImageA(HINSTANCE hInst,LPCSTR name,UINT type,int cx,int cy,UINT fuLoad); - WINUSERAPI HANDLE WINAPI LoadImageW(HINSTANCE hInst,LPCWSTR name,UINT type,int cx,int cy,UINT fuLoad); - WINUSERAPI HANDLE WINAPI CopyImage(HANDLE h,UINT type,int cx,int cy,UINT flags); - -#define DI_MASK 0x0001 -#define DI_IMAGE 0x0002 -#define DI_NORMAL 0x0003 -#define DI_COMPAT 0x0004 -#define DI_DEFAULTSIZE 0x0008 -#define DI_NOMIRROR 0x0010 - - WINUSERAPI WINBOOL WINAPI DrawIconEx(HDC hdc,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyWidth,UINT istepIfAniCur,HBRUSH hbrFlickerFreeDraw,UINT diFlags); - WINUSERAPI HICON WINAPI CreateIconIndirect(PICONINFO piconinfo); - WINUSERAPI HICON WINAPI CopyIcon(HICON hIcon); - WINUSERAPI WINBOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO piconinfo); - -#define RES_ICON 1 -#define RES_CURSOR 2 - -#ifdef OEMRESOURCE - -#define OBM_CLOSE 32754 -#define OBM_UPARROW 32753 -#define OBM_DNARROW 32752 -#define OBM_RGARROW 32751 -#define OBM_LFARROW 32750 -#define OBM_REDUCE 32749 -#define OBM_ZOOM 32748 -#define OBM_RESTORE 32747 -#define OBM_REDUCED 32746 -#define OBM_ZOOMD 32745 -#define OBM_RESTORED 32744 -#define OBM_UPARROWD 32743 -#define OBM_DNARROWD 32742 -#define OBM_RGARROWD 32741 -#define OBM_LFARROWD 32740 -#define OBM_MNARROW 32739 -#define OBM_COMBO 32738 -#define OBM_UPARROWI 32737 -#define OBM_DNARROWI 32736 -#define OBM_RGARROWI 32735 -#define OBM_LFARROWI 32734 - -#define OBM_OLD_CLOSE 32767 -#define OBM_SIZE 32766 -#define OBM_OLD_UPARROW 32765 -#define OBM_OLD_DNARROW 32764 -#define OBM_OLD_RGARROW 32763 -#define OBM_OLD_LFARROW 32762 -#define OBM_BTSIZE 32761 -#define OBM_CHECK 32760 -#define OBM_CHECKBOXES 32759 -#define OBM_BTNCORNERS 32758 -#define OBM_OLD_REDUCE 32757 -#define OBM_OLD_ZOOM 32756 -#define OBM_OLD_RESTORE 32755 - -#define OCR_NORMAL 32512 -#define OCR_IBEAM 32513 -#define OCR_WAIT 32514 -#define OCR_CROSS 32515 -#define OCR_UP 32516 -#define OCR_SIZE 32640 -#define OCR_ICON 32641 -#define OCR_SIZENWSE 32642 -#define OCR_SIZENESW 32643 -#define OCR_SIZEWE 32644 -#define OCR_SIZENS 32645 -#define OCR_SIZEALL 32646 -#define OCR_ICOCUR 32647 -#define OCR_NO 32648 -#define OCR_HAND 32649 -#define OCR_APPSTARTING 32650 - -#define OIC_SAMPLE 32512 -#define OIC_HAND 32513 -#define OIC_QUES 32514 -#define OIC_BANG 32515 -#define OIC_NOTE 32516 -#define OIC_WINLOGO 32517 -#define OIC_WARNING OIC_BANG -#define OIC_ERROR OIC_HAND -#define OIC_INFORMATION OIC_NOTE -#endif - -#define ORD_LANGDRIVER 1 - -#ifndef NOICONS - -#ifdef RC_INVOKED -#define IDI_APPLICATION 32512 -#define IDI_HAND 32513 -#define IDI_QUESTION 32514 -#define IDI_EXCLAMATION 32515 -#define IDI_ASTERISK 32516 -#define IDI_WINLOGO 32517 -#else -#define IDI_APPLICATION MAKEINTRESOURCE(32512) -#define IDI_HAND MAKEINTRESOURCE(32513) -#define IDI_QUESTION MAKEINTRESOURCE(32514) -#define IDI_EXCLAMATION MAKEINTRESOURCE(32515) -#define IDI_ASTERISK MAKEINTRESOURCE(32516) -#define IDI_WINLOGO MAKEINTRESOURCE(32517) -#endif - -#define IDI_WARNING IDI_EXCLAMATION -#define IDI_ERROR IDI_HAND -#define IDI_INFORMATION IDI_ASTERISK -#endif - -#ifdef UNICODE -#define LoadString LoadStringW -#else -#define LoadString LoadStringA -#endif - - WINUSERAPI int WINAPI LoadStringA(HINSTANCE hInstance,UINT uID,LPSTR lpBuffer,int cchBufferMax); - WINUSERAPI int WINAPI LoadStringW(HINSTANCE hInstance,UINT uID,LPWSTR lpBuffer,int cchBufferMax); - -#define IDOK 1 -#define IDCANCEL 2 -#define IDABORT 3 -#define IDRETRY 4 -#define IDIGNORE 5 -#define IDYES 6 -#define IDNO 7 -#define IDCLOSE 8 -#define IDHELP 9 -#define IDTRYAGAIN 10 -#define IDCONTINUE 11 - -#ifndef IDTIMEOUT -#define IDTIMEOUT 32000 -#endif - -#ifndef NOCTLMGR - -#ifndef NOWINSTYLES -#define ES_LEFT 0x0000L -#define ES_CENTER 0x0001L -#define ES_RIGHT 0x0002L -#define ES_MULTILINE 0x0004L -#define ES_UPPERCASE 0x0008L -#define ES_LOWERCASE 0x0010L -#define ES_PASSWORD 0x0020L -#define ES_AUTOVSCROLL 0x0040L -#define ES_AUTOHSCROLL 0x0080L -#define ES_NOHIDESEL 0x0100L -#define ES_OEMCONVERT 0x0400L -#define ES_READONLY 0x0800L -#define ES_WANTRETURN 0x1000L -#define ES_NUMBER 0x2000L -#endif - -#define EN_SETFOCUS 0x0100 -#define EN_KILLFOCUS 0x0200 -#define EN_CHANGE 0x0300 -#define EN_UPDATE 0x0400 -#define EN_ERRSPACE 0x0500 -#define EN_MAXTEXT 0x0501 -#define EN_HSCROLL 0x0601 -#define EN_VSCROLL 0x0602 -#define EN_ALIGN_LTR_EC 0x0700 -#define EN_ALIGN_RTL_EC 0x0701 - -#define EC_LEFTMARGIN 0x0001 -#define EC_RIGHTMARGIN 0x0002 -#define EC_USEFONTINFO 0xffff - -#define EMSIS_COMPOSITIONSTRING 0x0001 - -#define EIMES_GETCOMPSTRATONCE 0x0001 -#define EIMES_CANCELCOMPSTRINFOCUS 0x0002 -#define EIMES_COMPLETECOMPSTRKILLFOCUS 0x0004 - -#ifndef NOWINMESSAGES - -#define EM_GETSEL 0x00B0 -#define EM_SETSEL 0x00B1 -#define EM_GETRECT 0x00B2 -#define EM_SETRECT 0x00B3 -#define EM_SETRECTNP 0x00B4 -#define EM_SCROLL 0x00B5 -#define EM_LINESCROLL 0x00B6 -#define EM_SCROLLCARET 0x00B7 -#define EM_GETMODIFY 0x00B8 -#define EM_SETMODIFY 0x00B9 -#define EM_GETLINECOUNT 0x00BA -#define EM_LINEINDEX 0x00BB -#define EM_SETHANDLE 0x00BC -#define EM_GETHANDLE 0x00BD -#define EM_GETTHUMB 0x00BE -#define EM_LINELENGTH 0x00C1 -#define EM_REPLACESEL 0x00C2 -#define EM_GETLINE 0x00C4 -#define EM_LIMITTEXT 0x00C5 -#define EM_CANUNDO 0x00C6 -#define EM_UNDO 0x00C7 -#define EM_FMTLINES 0x00C8 -#define EM_LINEFROMCHAR 0x00C9 -#define EM_SETTABSTOPS 0x00CB -#define EM_SETPASSWORDCHAR 0x00CC -#define EM_EMPTYUNDOBUFFER 0x00CD -#define EM_GETFIRSTVISIBLELINE 0x00CE -#define EM_SETREADONLY 0x00CF -#define EM_SETWORDBREAKPROC 0x00D0 -#define EM_GETWORDBREAKPROC 0x00D1 -#define EM_GETPASSWORDCHAR 0x00D2 -#define EM_SETMARGINS 0x00D3 -#define EM_GETMARGINS 0x00D4 -#define EM_SETLIMITTEXT EM_LIMITTEXT -#define EM_GETLIMITTEXT 0x00D5 -#define EM_POSFROMCHAR 0x00D6 -#define EM_CHARFROMPOS 0x00D7 -#define EM_SETIMESTATUS 0x00D8 -#define EM_GETIMESTATUS 0x00D9 -#endif - -#define WB_LEFT 0 -#define WB_RIGHT 1 -#define WB_ISDELIMITER 2 - -#define BS_PUSHBUTTON 0x00000000L -#define BS_DEFPUSHBUTTON 0x00000001L -#define BS_CHECKBOX 0x00000002L -#define BS_AUTOCHECKBOX 0x00000003L -#define BS_RADIOBUTTON 0x00000004L -#define BS_3STATE 0x00000005L -#define BS_AUTO3STATE 0x00000006L -#define BS_GROUPBOX 0x00000007L -#define BS_USERBUTTON 0x00000008L -#define BS_AUTORADIOBUTTON 0x00000009L -#define BS_PUSHBOX 0x0000000AL -#define BS_OWNERDRAW 0x0000000BL -#define BS_TYPEMASK 0x0000000FL -#define BS_LEFTTEXT 0x00000020L -#define BS_TEXT 0x00000000L -#define BS_ICON 0x00000040L -#define BS_BITMAP 0x00000080L -#define BS_LEFT 0x00000100L -#define BS_RIGHT 0x00000200L -#define BS_CENTER 0x00000300L -#define BS_TOP 0x00000400L -#define BS_BOTTOM 0x00000800L -#define BS_VCENTER 0x00000C00L -#define BS_PUSHLIKE 0x00001000L -#define BS_MULTILINE 0x00002000L -#define BS_NOTIFY 0x00004000L -#define BS_FLAT 0x00008000L -#define BS_RIGHTBUTTON BS_LEFTTEXT - -#define BN_CLICKED 0 -#define BN_PAINT 1 -#define BN_HILITE 2 -#define BN_UNHILITE 3 -#define BN_DISABLE 4 -#define BN_DOUBLECLICKED 5 -#define BN_PUSHED BN_HILITE -#define BN_UNPUSHED BN_UNHILITE -#define BN_DBLCLK BN_DOUBLECLICKED -#define BN_SETFOCUS 6 -#define BN_KILLFOCUS 7 - -#define BM_GETCHECK 0x00F0 -#define BM_SETCHECK 0x00F1 -#define BM_GETSTATE 0x00F2 -#define BM_SETSTATE 0x00F3 -#define BM_SETSTYLE 0x00F4 -#define BM_CLICK 0x00F5 -#define BM_GETIMAGE 0x00F6 -#define BM_SETIMAGE 0x00F7 - -#define BST_UNCHECKED 0x0000 -#define BST_CHECKED 0x0001 -#define BST_INDETERMINATE 0x0002 -#define BST_PUSHED 0x0004 -#define BST_FOCUS 0x0008 - -#define SS_LEFT 0x00000000L -#define SS_CENTER 0x00000001L -#define SS_RIGHT 0x00000002L -#define SS_ICON 0x00000003L -#define SS_BLACKRECT 0x00000004L -#define SS_GRAYRECT 0x00000005L -#define SS_WHITERECT 0x00000006L -#define SS_BLACKFRAME 0x00000007L -#define SS_GRAYFRAME 0x00000008L -#define SS_WHITEFRAME 0x00000009L -#define SS_USERITEM 0x0000000AL -#define SS_SIMPLE 0x0000000BL -#define SS_LEFTNOWORDWRAP 0x0000000CL -#define SS_OWNERDRAW 0x0000000DL -#define SS_BITMAP 0x0000000EL -#define SS_ENHMETAFILE 0x0000000FL -#define SS_ETCHEDHORZ 0x00000010L -#define SS_ETCHEDVERT 0x00000011L -#define SS_ETCHEDFRAME 0x00000012L -#define SS_TYPEMASK 0x0000001FL -#define SS_REALSIZECONTROL 0x00000040L -#define SS_NOPREFIX 0x00000080L -#define SS_NOTIFY 0x00000100L -#define SS_CENTERIMAGE 0x00000200L -#define SS_RIGHTJUST 0x00000400L -#define SS_REALSIZEIMAGE 0x00000800L -#define SS_SUNKEN 0x00001000L -#define SS_EDITCONTROL 0x00002000L -#define SS_ENDELLIPSIS 0x00004000L -#define SS_PATHELLIPSIS 0x00008000L -#define SS_WORDELLIPSIS 0x0000C000L -#define SS_ELLIPSISMASK 0x0000C000L - -#ifndef NOWINMESSAGES - -#define STM_SETICON 0x0170 -#define STM_GETICON 0x0171 -#define STM_SETIMAGE 0x0172 -#define STM_GETIMAGE 0x0173 -#define STN_CLICKED 0 -#define STN_DBLCLK 1 -#define STN_ENABLE 2 -#define STN_DISABLE 3 -#define STM_MSGMAX 0x0174 -#endif - -#define WC_DIALOG (MAKEINTATOM(0x8002)) - -#define DWL_MSGRESULT 0 -#define DWL_DLGPROC 4 -#define DWL_USER 8 - -#ifdef _WIN64 - -#undef DWL_MSGRESULT -#undef DWL_DLGPROC -#undef DWL_USER -#endif - -#define DWLP_MSGRESULT 0 -#define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) -#define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) - -#ifndef NOMSG - -#ifdef UNICODE -#define IsDialogMessage IsDialogMessageW -#else -#define IsDialogMessage IsDialogMessageA -#endif - - WINUSERAPI WINBOOL WINAPI IsDialogMessageA(HWND hDlg,LPMSG lpMsg); - WINUSERAPI WINBOOL WINAPI IsDialogMessageW(HWND hDlg,LPMSG lpMsg); -#endif - -#ifdef UNICODE -#define DlgDirList DlgDirListW -#define DlgDirSelectEx DlgDirSelectExW -#define DlgDirListComboBox DlgDirListComboBoxW -#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExW -#else -#define DlgDirList DlgDirListA -#define DlgDirSelectEx DlgDirSelectExA -#define DlgDirListComboBox DlgDirListComboBoxA -#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExA -#endif - - WINUSERAPI WINBOOL WINAPI MapDialogRect(HWND hDlg,LPRECT lpRect); - WINUSERAPI int WINAPI DlgDirListA(HWND hDlg,LPSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); - WINUSERAPI int WINAPI DlgDirListW(HWND hDlg,LPWSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); - -#define DDL_READWRITE 0x0000 -#define DDL_READONLY 0x0001 -#define DDL_HIDDEN 0x0002 -#define DDL_SYSTEM 0x0004 -#define DDL_DIRECTORY 0x0010 -#define DDL_ARCHIVE 0x0020 - -#define DDL_POSTMSGS 0x2000 -#define DDL_DRIVES 0x4000 -#define DDL_EXCLUSIVE 0x8000 - - WINUSERAPI WINBOOL WINAPI DlgDirSelectExA(HWND hwndDlg,LPSTR lpString,int chCount,int idListBox); - WINUSERAPI WINBOOL WINAPI DlgDirSelectExW(HWND hwndDlg,LPWSTR lpString,int chCount,int idListBox); - WINUSERAPI int WINAPI DlgDirListComboBoxA(HWND hDlg,LPSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); - WINUSERAPI int WINAPI DlgDirListComboBoxW(HWND hDlg,LPWSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); - WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExA(HWND hwndDlg,LPSTR lpString,int cchOut,int idComboBox); - WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExW(HWND hwndDlg,LPWSTR lpString,int cchOut,int idComboBox); - -#define DS_ABSALIGN 0x01L -#define DS_SYSMODAL 0x02L -#define DS_LOCALEDIT 0x20L -#define DS_SETFONT 0x40L -#define DS_MODALFRAME 0x80L -#define DS_NOIDLEMSG 0x100L -#define DS_SETFOREGROUND 0x200L - -#define DS_3DLOOK 0x0004L -#define DS_FIXEDSYS 0x0008L -#define DS_NOFAILCREATE 0x0010L -#define DS_CONTROL 0x0400L -#define DS_CENTER 0x0800L -#define DS_CENTERMOUSE 0x1000L -#define DS_CONTEXTHELP 0x2000L - -#define DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS) - -#if(_WIN32_WCE >= 0x0500) -#define DS_USEPIXELS 0x8000L -#endif - -#define DM_GETDEFID (WM_USER+0) -#define DM_SETDEFID (WM_USER+1) -#define DM_REPOSITION (WM_USER+2) - -#define DC_HASDEFID 0x534B - -#define DLGC_WANTARROWS 0x0001 -#define DLGC_WANTTAB 0x0002 -#define DLGC_WANTALLKEYS 0x0004 -#define DLGC_WANTMESSAGE 0x0004 -#define DLGC_HASSETSEL 0x0008 -#define DLGC_DEFPUSHBUTTON 0x0010 -#define DLGC_UNDEFPUSHBUTTON 0x0020 -#define DLGC_RADIOBUTTON 0x0040 -#define DLGC_WANTCHARS 0x0080 -#define DLGC_STATIC 0x0100 -#define DLGC_BUTTON 0x2000 - -#define LB_CTLCODE 0L - -#define LB_OKAY 0 -#define LB_ERR (-1) -#define LB_ERRSPACE (-2) - -#define LBN_ERRSPACE (-2) -#define LBN_SELCHANGE 1 -#define LBN_DBLCLK 2 -#define LBN_SELCANCEL 3 -#define LBN_SETFOCUS 4 -#define LBN_KILLFOCUS 5 - -#ifndef NOWINMESSAGES - -#define LB_ADDSTRING 0x0180 -#define LB_INSERTSTRING 0x0181 -#define LB_DELETESTRING 0x0182 -#define LB_SELITEMRANGEEX 0x0183 -#define LB_RESETCONTENT 0x0184 -#define LB_SETSEL 0x0185 -#define LB_SETCURSEL 0x0186 -#define LB_GETSEL 0x0187 -#define LB_GETCURSEL 0x0188 -#define LB_GETTEXT 0x0189 -#define LB_GETTEXTLEN 0x018A -#define LB_GETCOUNT 0x018B -#define LB_SELECTSTRING 0x018C -#define LB_DIR 0x018D -#define LB_GETTOPINDEX 0x018E -#define LB_FINDSTRING 0x018F -#define LB_GETSELCOUNT 0x0190 -#define LB_GETSELITEMS 0x0191 -#define LB_SETTABSTOPS 0x0192 -#define LB_GETHORIZONTALEXTENT 0x0193 -#define LB_SETHORIZONTALEXTENT 0x0194 -#define LB_SETCOLUMNWIDTH 0x0195 -#define LB_ADDFILE 0x0196 -#define LB_SETTOPINDEX 0x0197 -#define LB_GETITEMRECT 0x0198 -#define LB_GETITEMDATA 0x0199 -#define LB_SETITEMDATA 0x019A -#define LB_SELITEMRANGE 0x019B -#define LB_SETANCHORINDEX 0x019C -#define LB_GETANCHORINDEX 0x019D -#define LB_SETCARETINDEX 0x019E -#define LB_GETCARETINDEX 0x019F -#define LB_SETITEMHEIGHT 0x01A0 -#define LB_GETITEMHEIGHT 0x01A1 -#define LB_FINDSTRINGEXACT 0x01A2 -#define LB_SETLOCALE 0x01A5 -#define LB_GETLOCALE 0x01A6 -#define LB_SETCOUNT 0x01A7 -#define LB_INITSTORAGE 0x01A8 -#define LB_ITEMFROMPOINT 0x01A9 -#if(_WIN32_WCE >= 0x0400) -#define LB_MULTIPLEADDSTRING 0x01B1 -#endif -#define LB_GETLISTBOXINFO 0x01B2 -#define LB_MSGMAX 0x01B3 -#endif - -#ifndef NOWINSTYLES - -#define LBS_NOTIFY 0x0001L -#define LBS_SORT 0x0002L -#define LBS_NOREDRAW 0x0004L -#define LBS_MULTIPLESEL 0x0008L -#define LBS_OWNERDRAWFIXED 0x0010L -#define LBS_OWNERDRAWVARIABLE 0x0020L -#define LBS_HASSTRINGS 0x0040L -#define LBS_USETABSTOPS 0x0080L -#define LBS_NOINTEGRALHEIGHT 0x0100L -#define LBS_MULTICOLUMN 0x0200L -#define LBS_WANTKEYBOARDINPUT 0x0400L -#define LBS_EXTENDEDSEL 0x0800L -#define LBS_DISABLENOSCROLL 0x1000L -#define LBS_NODATA 0x2000L -#define LBS_NOSEL 0x4000L -#define LBS_COMBOBOX 0x8000L - -#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER) -#endif - -#define CB_OKAY 0 -#define CB_ERR (-1) -#define CB_ERRSPACE (-2) - -#define CBN_ERRSPACE (-1) -#define CBN_SELCHANGE 1 -#define CBN_DBLCLK 2 -#define CBN_SETFOCUS 3 -#define CBN_KILLFOCUS 4 -#define CBN_EDITCHANGE 5 -#define CBN_EDITUPDATE 6 -#define CBN_DROPDOWN 7 -#define CBN_CLOSEUP 8 -#define CBN_SELENDOK 9 -#define CBN_SELENDCANCEL 10 - -#ifndef NOWINSTYLES - -#define CBS_SIMPLE 0x0001L -#define CBS_DROPDOWN 0x0002L -#define CBS_DROPDOWNLIST 0x0003L -#define CBS_OWNERDRAWFIXED 0x0010L -#define CBS_OWNERDRAWVARIABLE 0x0020L -#define CBS_AUTOHSCROLL 0x0040L -#define CBS_OEMCONVERT 0x0080L -#define CBS_SORT 0x0100L -#define CBS_HASSTRINGS 0x0200L -#define CBS_NOINTEGRALHEIGHT 0x0400L -#define CBS_DISABLENOSCROLL 0x0800L -#define CBS_UPPERCASE 0x2000L -#define CBS_LOWERCASE 0x4000L -#endif - -#ifndef NOWINMESSAGES -#define CB_GETEDITSEL 0x0140 -#define CB_LIMITTEXT 0x0141 -#define CB_SETEDITSEL 0x0142 -#define CB_ADDSTRING 0x0143 -#define CB_DELETESTRING 0x0144 -#define CB_DIR 0x0145 -#define CB_GETCOUNT 0x0146 -#define CB_GETCURSEL 0x0147 -#define CB_GETLBTEXT 0x0148 -#define CB_GETLBTEXTLEN 0x0149 -#define CB_INSERTSTRING 0x014A -#define CB_RESETCONTENT 0x014B -#define CB_FINDSTRING 0x014C -#define CB_SELECTSTRING 0x014D -#define CB_SETCURSEL 0x014E -#define CB_SHOWDROPDOWN 0x014F -#define CB_GETITEMDATA 0x0150 -#define CB_SETITEMDATA 0x0151 -#define CB_GETDROPPEDCONTROLRECT 0x0152 -#define CB_SETITEMHEIGHT 0x0153 -#define CB_GETITEMHEIGHT 0x0154 -#define CB_SETEXTENDEDUI 0x0155 -#define CB_GETEXTENDEDUI 0x0156 -#define CB_GETDROPPEDSTATE 0x0157 -#define CB_FINDSTRINGEXACT 0x0158 -#define CB_SETLOCALE 0x0159 -#define CB_GETLOCALE 0x015A -#define CB_GETTOPINDEX 0x015b -#define CB_SETTOPINDEX 0x015c -#define CB_GETHORIZONTALEXTENT 0x015d -#define CB_SETHORIZONTALEXTENT 0x015e -#define CB_GETDROPPEDWIDTH 0x015f -#define CB_SETDROPPEDWIDTH 0x0160 -#define CB_INITSTORAGE 0x0161 -#if(_WIN32_WCE >= 0x0400) -#define CB_MULTIPLEADDSTRING 0x0163 -#endif -#define CB_GETCOMBOBOXINFO 0x0164 -#define CB_MSGMAX 0x0165 -#endif - -#ifndef NOWINSTYLES - -#define SBS_HORZ 0x0000L -#define SBS_VERT 0x0001L -#define SBS_TOPALIGN 0x0002L -#define SBS_LEFTALIGN 0x0002L -#define SBS_BOTTOMALIGN 0x0004L -#define SBS_RIGHTALIGN 0x0004L -#define SBS_SIZEBOXTOPLEFTALIGN 0x0002L -#define SBS_SIZEBOXBOTTOMRIGHTALIGN 0x0004L -#define SBS_SIZEBOX 0x0008L -#define SBS_SIZEGRIP 0x0010L -#endif - -#ifndef NOWINMESSAGES -#define SBM_SETPOS 0x00E0 -#define SBM_GETPOS 0x00E1 -#define SBM_SETRANGE 0x00E2 -#define SBM_SETRANGEREDRAW 0x00E6 -#define SBM_GETRANGE 0x00E3 -#define SBM_ENABLE_ARROWS 0x00E4 -#define SBM_SETSCROLLINFO 0x00E9 -#define SBM_GETSCROLLINFO 0x00EA -#define SBM_GETSCROLLBARINFO 0x00EB - -#define SIF_RANGE 0x0001 -#define SIF_PAGE 0x0002 -#define SIF_POS 0x0004 -#define SIF_DISABLENOSCROLL 0x0008 -#define SIF_TRACKPOS 0x0010 -#define SIF_ALL (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS) - - typedef struct tagSCROLLINFO { - UINT cbSize; - UINT fMask; - int nMin; - int nMax; - UINT nPage; - int nPos; - int nTrackPos; - } SCROLLINFO,*LPSCROLLINFO; - typedef SCROLLINFO CONST *LPCSCROLLINFO; - - WINUSERAPI int WINAPI SetScrollInfo(HWND hwnd,int nBar,LPCSCROLLINFO lpsi,WINBOOL redraw); - WINUSERAPI WINBOOL WINAPI GetScrollInfo(HWND hwnd,int nBar,LPSCROLLINFO lpsi); -#endif -#endif - -#ifndef NOMDI - -#define MDIS_ALLCHILDSTYLES 0x0001 - -#define MDITILE_VERTICAL 0x0000 -#define MDITILE_HORIZONTAL 0x0001 -#define MDITILE_SKIPDISABLED 0x0002 -#define MDITILE_ZORDER 0x0004 - - typedef struct tagMDICREATESTRUCTA { - LPCSTR szClass; - LPCSTR szTitle; - HANDLE hOwner; - int x; - int y; - int cx; - int cy; - DWORD style; - LPARAM lParam; - } MDICREATESTRUCTA,*LPMDICREATESTRUCTA; - - typedef struct tagMDICREATESTRUCTW { - LPCWSTR szClass; - LPCWSTR szTitle; - HANDLE hOwner; - int x; - int y; - int cx; - int cy; - DWORD style; - LPARAM lParam; - } MDICREATESTRUCTW,*LPMDICREATESTRUCTW; - -#ifdef UNICODE - typedef MDICREATESTRUCTW MDICREATESTRUCT; - typedef LPMDICREATESTRUCTW LPMDICREATESTRUCT; -#else - typedef MDICREATESTRUCTA MDICREATESTRUCT; - typedef LPMDICREATESTRUCTA LPMDICREATESTRUCT; -#endif - - typedef struct tagCLIENTCREATESTRUCT { - HANDLE hWindowMenu; - UINT idFirstChild; - } CLIENTCREATESTRUCT,*LPCLIENTCREATESTRUCT; - -#ifdef UNICODE -#define DefFrameProc DefFrameProcW -#define DefMDIChildProc DefMDIChildProcW -#define CreateMDIWindow CreateMDIWindowW -#else -#define DefFrameProc DefFrameProcA -#define DefMDIChildProc DefMDIChildProcA -#define CreateMDIWindow CreateMDIWindowA -#endif - - WINUSERAPI LRESULT WINAPI DefFrameProcA(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefFrameProcW(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefMDIChildProcA(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefMDIChildProcW(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); - -#ifndef NOMSG - WINUSERAPI WINBOOL WINAPI TranslateMDISysAccel(HWND hWndClient,LPMSG lpMsg); -#endif - - WINUSERAPI UINT WINAPI ArrangeIconicWindows(HWND hWnd); - WINUSERAPI HWND WINAPI CreateMDIWindowA(LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); - WINUSERAPI HWND WINAPI CreateMDIWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); - WINUSERAPI WORD WINAPI TileWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); - WINUSERAPI WORD WINAPI CascadeWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); -#endif -#endif - -#ifndef NOHELP - - typedef DWORD HELPPOLY; - typedef struct tagMULTIKEYHELPA { - DWORD mkSize; - CHAR mkKeylist; - CHAR szKeyphrase[1]; - } MULTIKEYHELPA,*PMULTIKEYHELPA,*LPMULTIKEYHELPA; - - typedef struct tagMULTIKEYHELPW { - DWORD mkSize; - WCHAR mkKeylist; - WCHAR szKeyphrase[1]; - } MULTIKEYHELPW,*PMULTIKEYHELPW,*LPMULTIKEYHELPW; - -#ifdef UNICODE - typedef MULTIKEYHELPW MULTIKEYHELP; - typedef PMULTIKEYHELPW PMULTIKEYHELP; - typedef LPMULTIKEYHELPW LPMULTIKEYHELP; -#else - typedef MULTIKEYHELPA MULTIKEYHELP; - typedef PMULTIKEYHELPA PMULTIKEYHELP; - typedef LPMULTIKEYHELPA LPMULTIKEYHELP; -#endif - - typedef struct tagHELPWININFOA { - int wStructSize; - int x; - int y; - int dx; - int dy; - int wMax; - CHAR rgchMember[2]; - } HELPWININFOA,*PHELPWININFOA,*LPHELPWININFOA; - - typedef struct tagHELPWININFOW { - int wStructSize; - int x; - int y; - int dx; - int dy; - int wMax; - WCHAR rgchMember[2]; - } HELPWININFOW,*PHELPWININFOW,*LPHELPWININFOW; - -#ifdef UNICODE - typedef HELPWININFOW HELPWININFO; - typedef PHELPWININFOW PHELPWININFO; - typedef LPHELPWININFOW LPHELPWININFO; -#else - typedef HELPWININFOA HELPWININFO; - typedef PHELPWININFOA PHELPWININFO; - typedef LPHELPWININFOA LPHELPWININFO; -#endif - -#define HELP_CONTEXT 0x0001L -#define HELP_QUIT 0x0002L -#define HELP_INDEX 0x0003L -#define HELP_CONTENTS 0x0003L -#define HELP_HELPONHELP 0x0004L -#define HELP_SETINDEX 0x0005L -#define HELP_SETCONTENTS 0x0005L -#define HELP_CONTEXTPOPUP 0x0008L -#define HELP_FORCEFILE 0x0009L -#define HELP_KEY 0x0101L -#define HELP_COMMAND 0x0102L -#define HELP_PARTIALKEY 0x0105L -#define HELP_MULTIKEY 0x0201L -#define HELP_SETWINPOS 0x0203L -#define HELP_CONTEXTMENU 0x000a -#define HELP_FINDER 0x000b -#define HELP_WM_HELP 0x000c -#define HELP_SETPOPUP_POS 0x000d - -#define HELP_TCARD 0x8000 -#define HELP_TCARD_DATA 0x0010 -#define HELP_TCARD_OTHER_CALLER 0x0011 - -#define IDH_NO_HELP 28440 -#define IDH_MISSING_CONTEXT 28441 -#define IDH_GENERIC_HELP_BUTTON 28442 -#define IDH_OK 28443 -#define IDH_CANCEL 28444 -#define IDH_HELP 28445 - -#ifdef UNICODE -#define WinHelp WinHelpW -#else -#define WinHelp WinHelpA -#endif - - WINUSERAPI WINBOOL WINAPI WinHelpA(HWND hWndMain,LPCSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); - WINUSERAPI WINBOOL WINAPI WinHelpW(HWND hWndMain,LPCWSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); -#endif - -#define GR_GDIOBJECTS 0 -#define GR_USEROBJECTS 1 - - WINUSERAPI DWORD WINAPI GetGuiResources(HANDLE hProcess,DWORD uiFlags); - -#ifndef NOSYSPARAMSINFO - -#define SPI_GETBEEP 0x0001 -#define SPI_SETBEEP 0x0002 -#define SPI_GETMOUSE 0x0003 -#define SPI_SETMOUSE 0x0004 -#define SPI_GETBORDER 0x0005 -#define SPI_SETBORDER 0x0006 -#define SPI_GETKEYBOARDSPEED 0x000A -#define SPI_SETKEYBOARDSPEED 0x000B -#define SPI_LANGDRIVER 0x000C -#define SPI_ICONHORIZONTALSPACING 0x000D -#define SPI_GETSCREENSAVETIMEOUT 0x000E -#define SPI_SETSCREENSAVETIMEOUT 0x000F -#define SPI_GETSCREENSAVEACTIVE 0x0010 -#define SPI_SETSCREENSAVEACTIVE 0x0011 -#define SPI_GETGRIDGRANULARITY 0x0012 -#define SPI_SETGRIDGRANULARITY 0x0013 -#define SPI_SETDESKWALLPAPER 0x0014 -#define SPI_SETDESKPATTERN 0x0015 -#define SPI_GETKEYBOARDDELAY 0x0016 -#define SPI_SETKEYBOARDDELAY 0x0017 -#define SPI_ICONVERTICALSPACING 0x0018 -#define SPI_GETICONTITLEWRAP 0x0019 -#define SPI_SETICONTITLEWRAP 0x001A -#define SPI_GETMENUDROPALIGNMENT 0x001B -#define SPI_SETMENUDROPALIGNMENT 0x001C -#define SPI_SETDOUBLECLKWIDTH 0x001D -#define SPI_SETDOUBLECLKHEIGHT 0x001E -#define SPI_GETICONTITLELOGFONT 0x001F -#define SPI_SETDOUBLECLICKTIME 0x0020 -#define SPI_SETMOUSEBUTTONSWAP 0x0021 -#define SPI_SETICONTITLELOGFONT 0x0022 -#define SPI_GETFASTTASKSWITCH 0x0023 -#define SPI_SETFASTTASKSWITCH 0x0024 -#define SPI_SETDRAGFULLWINDOWS 0x0025 -#define SPI_GETDRAGFULLWINDOWS 0x0026 -#define SPI_GETNONCLIENTMETRICS 0x0029 -#define SPI_SETNONCLIENTMETRICS 0x002A -#define SPI_GETMINIMIZEDMETRICS 0x002B -#define SPI_SETMINIMIZEDMETRICS 0x002C -#define SPI_GETICONMETRICS 0x002D -#define SPI_SETICONMETRICS 0x002E -#define SPI_SETWORKAREA 0x002F -#define SPI_GETWORKAREA 0x0030 -#define SPI_SETPENWINDOWS 0x0031 - -#define SPI_GETHIGHCONTRAST 0x0042 -#define SPI_SETHIGHCONTRAST 0x0043 -#define SPI_GETKEYBOARDPREF 0x0044 -#define SPI_SETKEYBOARDPREF 0x0045 -#define SPI_GETSCREENREADER 0x0046 -#define SPI_SETSCREENREADER 0x0047 -#define SPI_GETANIMATION 0x0048 -#define SPI_SETANIMATION 0x0049 -#define SPI_GETFONTSMOOTHING 0x004A -#define SPI_SETFONTSMOOTHING 0x004B -#define SPI_SETDRAGWIDTH 0x004C -#define SPI_SETDRAGHEIGHT 0x004D -#define SPI_SETHANDHELD 0x004E -#define SPI_GETLOWPOWERTIMEOUT 0x004F -#define SPI_GETPOWEROFFTIMEOUT 0x0050 -#define SPI_SETLOWPOWERTIMEOUT 0x0051 -#define SPI_SETPOWEROFFTIMEOUT 0x0052 -#define SPI_GETLOWPOWERACTIVE 0x0053 -#define SPI_GETPOWEROFFACTIVE 0x0054 -#define SPI_SETLOWPOWERACTIVE 0x0055 -#define SPI_SETPOWEROFFACTIVE 0x0056 -#define SPI_SETCURSORS 0x0057 -#define SPI_SETICONS 0x0058 -#define SPI_GETDEFAULTINPUTLANG 0x0059 -#define SPI_SETDEFAULTINPUTLANG 0x005A -#define SPI_SETLANGTOGGLE 0x005B -#define SPI_GETWINDOWSEXTENSION 0x005C -#define SPI_SETMOUSETRAILS 0x005D -#define SPI_GETMOUSETRAILS 0x005E -#define SPI_SETSCREENSAVERRUNNING 0x0061 -#define SPI_SCREENSAVERRUNNING SPI_SETSCREENSAVERRUNNING -#define SPI_GETFILTERKEYS 0x0032 -#define SPI_SETFILTERKEYS 0x0033 -#define SPI_GETTOGGLEKEYS 0x0034 -#define SPI_SETTOGGLEKEYS 0x0035 -#define SPI_GETMOUSEKEYS 0x0036 -#define SPI_SETMOUSEKEYS 0x0037 -#define SPI_GETSHOWSOUNDS 0x0038 -#define SPI_SETSHOWSOUNDS 0x0039 -#define SPI_GETSTICKYKEYS 0x003A -#define SPI_SETSTICKYKEYS 0x003B -#define SPI_GETACCESSTIMEOUT 0x003C -#define SPI_SETACCESSTIMEOUT 0x003D -#define SPI_GETSERIALKEYS 0x003E -#define SPI_SETSERIALKEYS 0x003F -#define SPI_GETSOUNDSENTRY 0x0040 -#define SPI_SETSOUNDSENTRY 0x0041 -#define SPI_GETSNAPTODEFBUTTON 0x005F -#define SPI_SETSNAPTODEFBUTTON 0x0060 -#define SPI_GETMOUSEHOVERWIDTH 0x0062 -#define SPI_SETMOUSEHOVERWIDTH 0x0063 -#define SPI_GETMOUSEHOVERHEIGHT 0x0064 -#define SPI_SETMOUSEHOVERHEIGHT 0x0065 -#define SPI_GETMOUSEHOVERTIME 0x0066 -#define SPI_SETMOUSEHOVERTIME 0x0067 -#define SPI_GETWHEELSCROLLLINES 0x0068 -#define SPI_SETWHEELSCROLLLINES 0x0069 -#define SPI_GETMENUSHOWDELAY 0x006A -#define SPI_SETMENUSHOWDELAY 0x006B -#define SPI_GETSHOWIMEUI 0x006E -#define SPI_SETSHOWIMEUI 0x006F -#define SPI_GETMOUSESPEED 0x0070 -#define SPI_SETMOUSESPEED 0x0071 -#define SPI_GETSCREENSAVERRUNNING 0x0072 -#define SPI_GETDESKWALLPAPER 0x0073 - -#define SPI_GETACTIVEWINDOWTRACKING 0x1000 -#define SPI_SETACTIVEWINDOWTRACKING 0x1001 -#define SPI_GETMENUANIMATION 0x1002 -#define SPI_SETMENUANIMATION 0x1003 -#define SPI_GETCOMBOBOXANIMATION 0x1004 -#define SPI_SETCOMBOBOXANIMATION 0x1005 -#define SPI_GETLISTBOXSMOOTHSCROLLING 0x1006 -#define SPI_SETLISTBOXSMOOTHSCROLLING 0x1007 -#define SPI_GETGRADIENTCAPTIONS 0x1008 -#define SPI_SETGRADIENTCAPTIONS 0x1009 -#define SPI_GETKEYBOARDCUES 0x100A -#define SPI_SETKEYBOARDCUES 0x100B -#define SPI_GETMENUUNDERLINES SPI_GETKEYBOARDCUES -#define SPI_SETMENUUNDERLINES SPI_SETKEYBOARDCUES -#define SPI_GETACTIVEWNDTRKZORDER 0x100C -#define SPI_SETACTIVEWNDTRKZORDER 0x100D -#define SPI_GETHOTTRACKING 0x100E -#define SPI_SETHOTTRACKING 0x100F -#define SPI_GETMENUFADE 0x1012 -#define SPI_SETMENUFADE 0x1013 -#define SPI_GETSELECTIONFADE 0x1014 -#define SPI_SETSELECTIONFADE 0x1015 -#define SPI_GETTOOLTIPANIMATION 0x1016 -#define SPI_SETTOOLTIPANIMATION 0x1017 -#define SPI_GETTOOLTIPFADE 0x1018 -#define SPI_SETTOOLTIPFADE 0x1019 -#define SPI_GETCURSORSHADOW 0x101A -#define SPI_SETCURSORSHADOW 0x101B -#define SPI_GETMOUSESONAR 0x101C -#define SPI_SETMOUSESONAR 0x101D -#define SPI_GETMOUSECLICKLOCK 0x101E -#define SPI_SETMOUSECLICKLOCK 0x101F -#define SPI_GETMOUSEVANISH 0x1020 -#define SPI_SETMOUSEVANISH 0x1021 -#define SPI_GETFLATMENU 0x1022 -#define SPI_SETFLATMENU 0x1023 -#define SPI_GETDROPSHADOW 0x1024 -#define SPI_SETDROPSHADOW 0x1025 -#define SPI_GETBLOCKSENDINPUTRESETS 0x1026 -#define SPI_SETBLOCKSENDINPUTRESETS 0x1027 -#define SPI_GETUIEFFECTS 0x103E -#define SPI_SETUIEFFECTS 0x103F -#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 -#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 -#define SPI_GETACTIVEWNDTRKTIMEOUT 0x2002 -#define SPI_SETACTIVEWNDTRKTIMEOUT 0x2003 -#define SPI_GETFOREGROUNDFLASHCOUNT 0x2004 -#define SPI_SETFOREGROUNDFLASHCOUNT 0x2005 -#define SPI_GETCARETWIDTH 0x2006 -#define SPI_SETCARETWIDTH 0x2007 -#define SPI_GETMOUSECLICKLOCKTIME 0x2008 -#define SPI_SETMOUSECLICKLOCKTIME 0x2009 -#define SPI_GETFONTSMOOTHINGTYPE 0x200A -#define SPI_SETFONTSMOOTHINGTYPE 0x200B - -#define FE_FONTSMOOTHINGSTANDARD 0x0001 -#define FE_FONTSMOOTHINGCLEARTYPE 0x0002 -#define FE_FONTSMOOTHINGDOCKING 0x8000 - -#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C -#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D -#define SPI_GETFOCUSBORDERWIDTH 0x200E -#define SPI_SETFOCUSBORDERWIDTH 0x200F -#define SPI_GETFOCUSBORDERHEIGHT 0x2010 -#define SPI_SETFOCUSBORDERHEIGHT 0x2011 -#define SPI_GETFONTSMOOTHINGORIENTATION 0x2012 -#define SPI_SETFONTSMOOTHINGORIENTATION 0x2013 - -#define FE_FONTSMOOTHINGORIENTATIONBGR 0x0000 -#define FE_FONTSMOOTHINGORIENTATIONRGB 0x0001 - -#define SPIF_UPDATEINIFILE 0x0001 -#define SPIF_SENDWININICHANGE 0x0002 -#define SPIF_SENDCHANGE SPIF_SENDWININICHANGE - -#define METRICS_USEDEFAULT -1 -#ifdef _WINGDI_ -#ifndef NOGDI - typedef struct tagNONCLIENTMETRICSA { - UINT cbSize; - int iBorderWidth; - int iScrollWidth; - int iScrollHeight; - int iCaptionWidth; - int iCaptionHeight; - LOGFONTA lfCaptionFont; - int iSmCaptionWidth; - int iSmCaptionHeight; - LOGFONTA lfSmCaptionFont; - int iMenuWidth; - int iMenuHeight; - LOGFONTA lfMenuFont; - LOGFONTA lfStatusFont; - LOGFONTA lfMessageFont; - } NONCLIENTMETRICSA,*PNONCLIENTMETRICSA,*LPNONCLIENTMETRICSA; - - typedef struct tagNONCLIENTMETRICSW { - UINT cbSize; - int iBorderWidth; - int iScrollWidth; - int iScrollHeight; - int iCaptionWidth; - int iCaptionHeight; - LOGFONTW lfCaptionFont; - int iSmCaptionWidth; - int iSmCaptionHeight; - LOGFONTW lfSmCaptionFont; - int iMenuWidth; - int iMenuHeight; - LOGFONTW lfMenuFont; - LOGFONTW lfStatusFont; - LOGFONTW lfMessageFont; - } NONCLIENTMETRICSW,*PNONCLIENTMETRICSW,*LPNONCLIENTMETRICSW; - -#ifdef UNICODE - typedef NONCLIENTMETRICSW NONCLIENTMETRICS; - typedef PNONCLIENTMETRICSW PNONCLIENTMETRICS; - typedef LPNONCLIENTMETRICSW LPNONCLIENTMETRICS; -#else - typedef NONCLIENTMETRICSA NONCLIENTMETRICS; - typedef PNONCLIENTMETRICSA PNONCLIENTMETRICS; - typedef LPNONCLIENTMETRICSA LPNONCLIENTMETRICS; -#endif -#endif -#endif - -#define ARW_BOTTOMLEFT 0x0000L -#define ARW_BOTTOMRIGHT 0x0001L -#define ARW_TOPLEFT 0x0002L -#define ARW_TOPRIGHT 0x0003L -#define ARW_STARTMASK 0x0003L -#define ARW_STARTRIGHT 0x0001L -#define ARW_STARTTOP 0x0002L - -#define ARW_LEFT 0x0000L -#define ARW_RIGHT 0x0000L -#define ARW_UP 0x0004L -#define ARW_DOWN 0x0004L -#define ARW_HIDE 0x0008L - - typedef struct tagMINIMIZEDMETRICS { - UINT cbSize; - int iWidth; - int iHorzGap; - int iVertGap; - int iArrange; - } MINIMIZEDMETRICS,*PMINIMIZEDMETRICS,*LPMINIMIZEDMETRICS; - -#ifdef _WINGDI_ -#ifndef NOGDI - typedef struct tagICONMETRICSA { - UINT cbSize; - int iHorzSpacing; - int iVertSpacing; - int iTitleWrap; - LOGFONTA lfFont; - } ICONMETRICSA,*PICONMETRICSA,*LPICONMETRICSA; - - typedef struct tagICONMETRICSW { - UINT cbSize; - int iHorzSpacing; - int iVertSpacing; - int iTitleWrap; - LOGFONTW lfFont; - } ICONMETRICSW,*PICONMETRICSW,*LPICONMETRICSW; - -#ifdef UNICODE - typedef ICONMETRICSW ICONMETRICS; - typedef PICONMETRICSW PICONMETRICS; - typedef LPICONMETRICSW LPICONMETRICS; -#else - typedef ICONMETRICSA ICONMETRICS; - typedef PICONMETRICSA PICONMETRICS; - typedef LPICONMETRICSA LPICONMETRICS; -#endif -#endif -#endif - - typedef struct tagANIMATIONINFO { - UINT cbSize; - int iMinAnimate; - } ANIMATIONINFO,*LPANIMATIONINFO; - - typedef struct tagSERIALKEYSA { - UINT cbSize; - DWORD dwFlags; - LPSTR lpszActivePort; - LPSTR lpszPort; - UINT iBaudRate; - UINT iPortState; - UINT iActive; - } SERIALKEYSA,*LPSERIALKEYSA; - - typedef struct tagSERIALKEYSW { - UINT cbSize; - DWORD dwFlags; - LPWSTR lpszActivePort; - LPWSTR lpszPort; - UINT iBaudRate; - UINT iPortState; - UINT iActive; - } SERIALKEYSW,*LPSERIALKEYSW; - -#ifdef UNICODE - typedef SERIALKEYSW SERIALKEYS; - typedef LPSERIALKEYSW LPSERIALKEYS; -#else - typedef SERIALKEYSA SERIALKEYS; - typedef LPSERIALKEYSA LPSERIALKEYS; -#endif - -#define SERKF_SERIALKEYSON 0x00000001 -#define SERKF_AVAILABLE 0x00000002 -#define SERKF_INDICATOR 0x00000004 - - typedef struct tagHIGHCONTRASTA { - UINT cbSize; - DWORD dwFlags; - LPSTR lpszDefaultScheme; - } HIGHCONTRASTA,*LPHIGHCONTRASTA; - - typedef struct tagHIGHCONTRASTW { - UINT cbSize; - DWORD dwFlags; - LPWSTR lpszDefaultScheme; - } HIGHCONTRASTW,*LPHIGHCONTRASTW; - -#ifdef UNICODE - typedef HIGHCONTRASTW HIGHCONTRAST; - typedef LPHIGHCONTRASTW LPHIGHCONTRAST; -#else - typedef HIGHCONTRASTA HIGHCONTRAST; - typedef LPHIGHCONTRASTA LPHIGHCONTRAST; -#endif - -#define HCF_HIGHCONTRASTON 0x00000001 -#define HCF_AVAILABLE 0x00000002 -#define HCF_HOTKEYACTIVE 0x00000004 -#define HCF_CONFIRMHOTKEY 0x00000008 -#define HCF_HOTKEYSOUND 0x00000010 -#define HCF_INDICATOR 0x00000020 -#define HCF_HOTKEYAVAILABLE 0x00000040 -#define HCF_LOGONDESKTOP 0x00000100 -#define HCF_DEFAULTDESKTOP 0x00000200 - -#define CDS_UPDATEREGISTRY 0x00000001 -#define CDS_TEST 0x00000002 -#define CDS_FULLSCREEN 0x00000004 -#define CDS_GLOBAL 0x00000008 -#define CDS_SET_PRIMARY 0x00000010 -#define CDS_VIDEOPARAMETERS 0x00000020 -#define CDS_RESET 0x40000000 -#define CDS_NORESET 0x10000000 - -//gr #include - -#define DISP_CHANGE_SUCCESSFUL 0 -#define DISP_CHANGE_RESTART 1 -#define DISP_CHANGE_FAILED -1 -#define DISP_CHANGE_BADMODE -2 -#define DISP_CHANGE_NOTUPDATED -3 -#define DISP_CHANGE_BADFLAGS -4 -#define DISP_CHANGE_BADPARAM -5 -#define DISP_CHANGE_BADDUALVIEW -6 - -#ifdef _WINGDI_ -#ifndef NOGDI - -#ifdef UNICODE -#define ChangeDisplaySettings ChangeDisplaySettingsW -#define ChangeDisplaySettingsEx ChangeDisplaySettingsExW -#define EnumDisplaySettings EnumDisplaySettingsW -#define EnumDisplaySettingsEx EnumDisplaySettingsExW -#define EnumDisplayDevices EnumDisplayDevicesW -#else -#define ChangeDisplaySettings ChangeDisplaySettingsA -#define ChangeDisplaySettingsEx ChangeDisplaySettingsExA -#define EnumDisplaySettings EnumDisplaySettingsA -#define EnumDisplaySettingsEx EnumDisplaySettingsExA -#define EnumDisplayDevices EnumDisplayDevicesA -#endif - - WINUSERAPI LONG WINAPI ChangeDisplaySettingsA(LPDEVMODEA lpDevMode,DWORD dwFlags); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsW(LPDEVMODEW lpDevMode,DWORD dwFlags); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsExA(LPCSTR lpszDeviceName,LPDEVMODEA lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName,LPDEVMODEW lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); - -#define ENUM_CURRENT_SETTINGS ((DWORD)-1) -#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) - - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode); - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode); - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode,DWORD dwFlags); - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode,DWORD dwFlags); - -#define EDS_RAWMODE 0x00000002 - - WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesA(LPCSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEA lpDisplayDevice,DWORD dwFlags); - WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesW(LPCWSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEW lpDisplayDevice,DWORD dwFlags); -#endif -#endif - -#ifdef UNICODE -#define SystemParametersInfo SystemParametersInfoW -#else -#define SystemParametersInfo SystemParametersInfoA -#endif - - WINUSERAPI WINBOOL WINAPI SystemParametersInfoA(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); - WINUSERAPI WINBOOL WINAPI SystemParametersInfoW(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); -#endif - - typedef struct tagFILTERKEYS { - UINT cbSize; - DWORD dwFlags; - DWORD iWaitMSec; - DWORD iDelayMSec; - DWORD iRepeatMSec; - DWORD iBounceMSec; - } FILTERKEYS,*LPFILTERKEYS; - -#define FKF_FILTERKEYSON 0x00000001 -#define FKF_AVAILABLE 0x00000002 -#define FKF_HOTKEYACTIVE 0x00000004 -#define FKF_CONFIRMHOTKEY 0x00000008 -#define FKF_HOTKEYSOUND 0x00000010 -#define FKF_INDICATOR 0x00000020 -#define FKF_CLICKON 0x00000040 - - typedef struct tagSTICKYKEYS { - UINT cbSize; - DWORD dwFlags; - } STICKYKEYS,*LPSTICKYKEYS; - -#define SKF_STICKYKEYSON 0x00000001 -#define SKF_AVAILABLE 0x00000002 -#define SKF_HOTKEYACTIVE 0x00000004 -#define SKF_CONFIRMHOTKEY 0x00000008 -#define SKF_HOTKEYSOUND 0x00000010 -#define SKF_INDICATOR 0x00000020 -#define SKF_AUDIBLEFEEDBACK 0x00000040 -#define SKF_TRISTATE 0x00000080 -#define SKF_TWOKEYSOFF 0x00000100 -#define SKF_LALTLATCHED 0x10000000 -#define SKF_LCTLLATCHED 0x04000000 -#define SKF_LSHIFTLATCHED 0x01000000 -#define SKF_RALTLATCHED 0x20000000 -#define SKF_RCTLLATCHED 0x08000000 -#define SKF_RSHIFTLATCHED 0x02000000 -#define SKF_LWINLATCHED 0x40000000 -#define SKF_RWINLATCHED 0x80000000 -#define SKF_LALTLOCKED 0x00100000 -#define SKF_LCTLLOCKED 0x00040000 -#define SKF_LSHIFTLOCKED 0x00010000 -#define SKF_RALTLOCKED 0x00200000 -#define SKF_RCTLLOCKED 0x00080000 -#define SKF_RSHIFTLOCKED 0x00020000 -#define SKF_LWINLOCKED 0x00400000 -#define SKF_RWINLOCKED 0x00800000 - - typedef struct tagMOUSEKEYS { - UINT cbSize; - DWORD dwFlags; - DWORD iMaxSpeed; - DWORD iTimeToMaxSpeed; - DWORD iCtrlSpeed; - DWORD dwReserved1; - DWORD dwReserved2; - } MOUSEKEYS,*LPMOUSEKEYS; - -#define MKF_MOUSEKEYSON 0x00000001 -#define MKF_AVAILABLE 0x00000002 -#define MKF_HOTKEYACTIVE 0x00000004 -#define MKF_CONFIRMHOTKEY 0x00000008 -#define MKF_HOTKEYSOUND 0x00000010 -#define MKF_INDICATOR 0x00000020 -#define MKF_MODIFIERS 0x00000040 -#define MKF_REPLACENUMBERS 0x00000080 -#define MKF_LEFTBUTTONSEL 0x10000000 -#define MKF_RIGHTBUTTONSEL 0x20000000 -#define MKF_LEFTBUTTONDOWN 0x01000000 -#define MKF_RIGHTBUTTONDOWN 0x02000000 -#define MKF_MOUSEMODE 0x80000000 - - typedef struct tagACCESSTIMEOUT { - UINT cbSize; - DWORD dwFlags; - DWORD iTimeOutMSec; - } ACCESSTIMEOUT,*LPACCESSTIMEOUT; - -#define ATF_TIMEOUTON 0x00000001 -#define ATF_ONOFFFEEDBACK 0x00000002 - -#define SSGF_NONE 0 -#define SSGF_DISPLAY 3 - -#define SSTF_NONE 0 -#define SSTF_CHARS 1 -#define SSTF_BORDER 2 -#define SSTF_DISPLAY 3 - -#define SSWF_NONE 0 -#define SSWF_TITLE 1 -#define SSWF_WINDOW 2 -#define SSWF_DISPLAY 3 -#define SSWF_CUSTOM 4 - - typedef struct tagSOUNDSENTRYA { - UINT cbSize; - DWORD dwFlags; - DWORD iFSTextEffect; - DWORD iFSTextEffectMSec; - DWORD iFSTextEffectColorBits; - DWORD iFSGrafEffect; - DWORD iFSGrafEffectMSec; - DWORD iFSGrafEffectColor; - DWORD iWindowsEffect; - DWORD iWindowsEffectMSec; - LPSTR lpszWindowsEffectDLL; - DWORD iWindowsEffectOrdinal; - } SOUNDSENTRYA,*LPSOUNDSENTRYA; - - typedef struct tagSOUNDSENTRYW { - UINT cbSize; - DWORD dwFlags; - DWORD iFSTextEffect; - DWORD iFSTextEffectMSec; - DWORD iFSTextEffectColorBits; - DWORD iFSGrafEffect; - DWORD iFSGrafEffectMSec; - DWORD iFSGrafEffectColor; - DWORD iWindowsEffect; - DWORD iWindowsEffectMSec; - LPWSTR lpszWindowsEffectDLL; - DWORD iWindowsEffectOrdinal; - } SOUNDSENTRYW,*LPSOUNDSENTRYW; - -#ifdef UNICODE - typedef SOUNDSENTRYW SOUNDSENTRY; - typedef LPSOUNDSENTRYW LPSOUNDSENTRY; -#else - typedef SOUNDSENTRYA SOUNDSENTRY; - typedef LPSOUNDSENTRYA LPSOUNDSENTRY; -#endif - -#define SSF_SOUNDSENTRYON 0x00000001 -#define SSF_AVAILABLE 0x00000002 -#define SSF_INDICATOR 0x00000004 - - typedef struct tagTOGGLEKEYS { - UINT cbSize; - DWORD dwFlags; - } TOGGLEKEYS,*LPTOGGLEKEYS; - -#define TKF_TOGGLEKEYSON 0x00000001 -#define TKF_AVAILABLE 0x00000002 -#define TKF_HOTKEYACTIVE 0x00000004 -#define TKF_CONFIRMHOTKEY 0x00000008 -#define TKF_HOTKEYSOUND 0x00000010 -#define TKF_INDICATOR 0x00000020 - - WINUSERAPI VOID WINAPI SetDebugErrorLevel(DWORD dwLevel); - -#define SLE_ERROR 0x00000001 -#define SLE_MINORERROR 0x00000002 -#define SLE_WARNING 0x00000003 - - WINUSERAPI VOID WINAPI SetLastErrorEx(DWORD dwErrCode,DWORD dwType); - WINUSERAPI int WINAPI InternalGetWindowText(HWND hWnd,LPWSTR pString,int cchMaxCount); - -#ifdef WINNT - WINUSERAPI WINBOOL WINAPI EndTask(HWND hWnd,WINBOOL fShutDown,WINBOOL fForce); -#endif - -#define MONITOR_DEFAULTTONULL 0x00000000 -#define MONITOR_DEFAULTTOPRIMARY 0x00000001 -#define MONITOR_DEFAULTTONEAREST 0x00000002 - - WINUSERAPI HMONITOR WINAPI MonitorFromPoint(POINT pt,DWORD dwFlags); - WINUSERAPI HMONITOR WINAPI MonitorFromRect(LPCRECT lprc,DWORD dwFlags); - WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd,DWORD dwFlags); - -#define MONITORINFOF_PRIMARY 0x00000001 - -#ifndef CCHDEVICENAME -#define CCHDEVICENAME 32 -#endif - - typedef struct tagMONITORINFO { - DWORD cbSize; - RECT rcMonitor; - RECT rcWork; - DWORD dwFlags; - } MONITORINFO,*LPMONITORINFO; - -#ifdef __cplusplus - typedef struct tagMONITORINFOEXA : public tagMONITORINFO { - CHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXA,*LPMONITORINFOEXA; - - typedef struct tagMONITORINFOEXW : public tagMONITORINFO { - WCHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXW,*LPMONITORINFOEXW; - -#ifdef UNICODE - typedef MONITORINFOEXW MONITORINFOEX; - typedef LPMONITORINFOEXW LPMONITORINFOEX; -#else - typedef MONITORINFOEXA MONITORINFOEX; - typedef LPMONITORINFOEXA LPMONITORINFOEX; -#endif -#else - typedef struct tagMONITORINFOEXA { - MONITORINFO mi; - CHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXA,*LPMONITORINFOEXA; - - typedef struct tagMONITORINFOEXW { - MONITORINFO mi; - WCHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXW,*LPMONITORINFOEXW; -#ifdef UNICODE - typedef MONITORINFOEXW MONITORINFOEX; - typedef LPMONITORINFOEXW LPMONITORINFOEX; -#else - typedef MONITORINFOEXA MONITORINFOEX; - typedef LPMONITORINFOEXA LPMONITORINFOEX; -#endif -#endif - -#ifdef UNICODE -#define GetMonitorInfo GetMonitorInfoW -#else -#define GetMonitorInfo GetMonitorInfoA -#endif - - WINUSERAPI WINBOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor,LPMONITORINFO lpmi); - WINUSERAPI WINBOOL WINAPI GetMonitorInfoW(HMONITOR hMonitor,LPMONITORINFO lpmi); - - typedef WINBOOL (CALLBACK *MONITORENUMPROC)(HMONITOR,HDC,LPRECT,LPARAM); - - WINUSERAPI WINBOOL WINAPI EnumDisplayMonitors(HDC hdc,LPCRECT lprcClip,MONITORENUMPROC lpfnEnum,LPARAM dwData); - -#ifndef NOWINABLE - WINUSERAPI VOID WINAPI NotifyWinEvent(DWORD event,HWND hwnd,LONG idObject,LONG idChild); - - typedef VOID (CALLBACK *WINEVENTPROC)(HWINEVENTHOOK hWinEventHook,DWORD event,HWND hwnd,LONG idObject,LONG idChild,DWORD idEventThread,DWORD dwmsEventTime); - - WINUSERAPI HWINEVENTHOOK WINAPI SetWinEventHook(DWORD eventMin,DWORD eventMax,HMODULE hmodWinEventProc,WINEVENTPROC pfnWinEventProc,DWORD idProcess,DWORD idThread,DWORD dwFlags); - WINUSERAPI WINBOOL WINAPI IsWinEventHookInstalled(DWORD event); - -#define WINEVENT_OUTOFCONTEXT 0x0000 -#define WINEVENT_SKIPOWNTHREAD 0x0001 -#define WINEVENT_SKIPOWNPROCESS 0x0002 -#define WINEVENT_INCONTEXT 0x0004 - - WINUSERAPI WINBOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hWinEventHook); - -#define CHILDID_SELF 0 -#define INDEXID_OBJECT 0 -#define INDEXID_CONTAINER 0 - -#define OBJID_WINDOW ((LONG)0x00000000) -#define OBJID_SYSMENU ((LONG)0xFFFFFFFF) -#define OBJID_TITLEBAR ((LONG)0xFFFFFFFE) -#define OBJID_MENU ((LONG)0xFFFFFFFD) -#define OBJID_CLIENT ((LONG)0xFFFFFFFC) -#define OBJID_VSCROLL ((LONG)0xFFFFFFFB) -#define OBJID_HSCROLL ((LONG)0xFFFFFFFA) -#define OBJID_SIZEGRIP ((LONG)0xFFFFFFF9) -#define OBJID_CARET ((LONG)0xFFFFFFF8) -#define OBJID_CURSOR ((LONG)0xFFFFFFF7) -#define OBJID_ALERT ((LONG)0xFFFFFFF6) -#define OBJID_SOUND ((LONG)0xFFFFFFF5) -#define OBJID_QUERYCLASSNAMEIDX ((LONG)0xFFFFFFF4) -#define OBJID_NATIVEOM ((LONG)0xFFFFFFF0) - -#define EVENT_MIN 0x00000001 -#define EVENT_MAX 0x7FFFFFFF - -#define EVENT_SYSTEM_SOUND 0x0001 -#define EVENT_SYSTEM_ALERT 0x0002 -#define EVENT_SYSTEM_FOREGROUND 0x0003 -#define EVENT_SYSTEM_MENUSTART 0x0004 -#define EVENT_SYSTEM_MENUEND 0x0005 -#define EVENT_SYSTEM_MENUPOPUPSTART 0x0006 -#define EVENT_SYSTEM_MENUPOPUPEND 0x0007 -#define EVENT_SYSTEM_CAPTURESTART 0x0008 -#define EVENT_SYSTEM_CAPTUREEND 0x0009 -#define EVENT_SYSTEM_MOVESIZESTART 0x000A -#define EVENT_SYSTEM_MOVESIZEEND 0x000B -#define EVENT_SYSTEM_CONTEXTHELPSTART 0x000C -#define EVENT_SYSTEM_CONTEXTHELPEND 0x000D -#define EVENT_SYSTEM_DRAGDROPSTART 0x000E -#define EVENT_SYSTEM_DRAGDROPEND 0x000F -#define EVENT_SYSTEM_DIALOGSTART 0x0010 -#define EVENT_SYSTEM_DIALOGEND 0x0011 -#define EVENT_SYSTEM_SCROLLINGSTART 0x0012 -#define EVENT_SYSTEM_SCROLLINGEND 0x0013 -#define EVENT_SYSTEM_SWITCHSTART 0x0014 -#define EVENT_SYSTEM_SWITCHEND 0x0015 -#define EVENT_SYSTEM_MINIMIZESTART 0x0016 -#define EVENT_SYSTEM_MINIMIZEEND 0x0017 - -#define EVENT_CONSOLE_CARET 0x4001 -#define EVENT_CONSOLE_UPDATE_REGION 0x4002 -#define EVENT_CONSOLE_UPDATE_SIMPLE 0x4003 -#define EVENT_CONSOLE_UPDATE_SCROLL 0x4004 -#define EVENT_CONSOLE_LAYOUT 0x4005 -#define EVENT_CONSOLE_START_APPLICATION 0x4006 -#define EVENT_CONSOLE_END_APPLICATION 0x4007 - -#define CONSOLE_APPLICATION_16BIT 0x0001 - -#define CONSOLE_CARET_SELECTION 0x0001 -#define CONSOLE_CARET_VISIBLE 0x0002 - -#define EVENT_OBJECT_CREATE 0x8000 -#define EVENT_OBJECT_DESTROY 0x8001 -#define EVENT_OBJECT_SHOW 0x8002 -#define EVENT_OBJECT_HIDE 0x8003 -#define EVENT_OBJECT_REORDER 0x8004 - -#define EVENT_OBJECT_FOCUS 0x8005 -#define EVENT_OBJECT_SELECTION 0x8006 -#define EVENT_OBJECT_SELECTIONADD 0x8007 -#define EVENT_OBJECT_SELECTIONREMOVE 0x8008 -#define EVENT_OBJECT_SELECTIONWITHIN 0x8009 - -#define EVENT_OBJECT_STATECHANGE 0x800A - -#define EVENT_OBJECT_LOCATIONCHANGE 0x800B - -#define EVENT_OBJECT_NAMECHANGE 0x800C -#define EVENT_OBJECT_DESCRIPTIONCHANGE 0x800D -#define EVENT_OBJECT_VALUECHANGE 0x800E -#define EVENT_OBJECT_PARENTCHANGE 0x800F -#define EVENT_OBJECT_HELPCHANGE 0x8010 -#define EVENT_OBJECT_DEFACTIONCHANGE 0x8011 -#define EVENT_OBJECT_ACCELERATORCHANGE 0x8012 - -#define SOUND_SYSTEM_STARTUP 1 -#define SOUND_SYSTEM_SHUTDOWN 2 -#define SOUND_SYSTEM_BEEP 3 -#define SOUND_SYSTEM_ERROR 4 -#define SOUND_SYSTEM_QUESTION 5 -#define SOUND_SYSTEM_WARNING 6 -#define SOUND_SYSTEM_INFORMATION 7 -#define SOUND_SYSTEM_MAXIMIZE 8 -#define SOUND_SYSTEM_MINIMIZE 9 -#define SOUND_SYSTEM_RESTOREUP 10 -#define SOUND_SYSTEM_RESTOREDOWN 11 -#define SOUND_SYSTEM_APPSTART 12 -#define SOUND_SYSTEM_FAULT 13 -#define SOUND_SYSTEM_APPEND 14 -#define SOUND_SYSTEM_MENUCOMMAND 15 -#define SOUND_SYSTEM_MENUPOPUP 16 -#define CSOUND_SYSTEM 16 - -#define ALERT_SYSTEM_INFORMATIONAL 1 -#define ALERT_SYSTEM_WARNING 2 -#define ALERT_SYSTEM_ERROR 3 -#define ALERT_SYSTEM_QUERY 4 -#define ALERT_SYSTEM_CRITICAL 5 -#define CALERT_SYSTEM 6 - - typedef struct tagGUITHREADINFO { - DWORD cbSize; - DWORD flags; - HWND hwndActive; - HWND hwndFocus; - HWND hwndCapture; - HWND hwndMenuOwner; - HWND hwndMoveSize; - HWND hwndCaret; - RECT rcCaret; - } GUITHREADINFO,*PGUITHREADINFO,*LPGUITHREADINFO; - -#define GUI_CARETBLINKING 0x00000001 -#define GUI_INMOVESIZE 0x00000002 -#define GUI_INMENUMODE 0x00000004 -#define GUI_SYSTEMMENUMODE 0x00000008 -#define GUI_POPUPMENUMODE 0x00000010 -#define GUI_16BITTASK 0x00000020 - -#ifdef UNICODE -#define GetWindowModuleFileName GetWindowModuleFileNameW -#else -#define GetWindowModuleFileName GetWindowModuleFileNameA -#endif - - WINUSERAPI WINBOOL WINAPI GetGUIThreadInfo(DWORD idThread,PGUITHREADINFO pgui); - WINUSERAPI UINT WINAPI GetWindowModuleFileNameA(HWND hwnd,LPSTR pszFileName,UINT cchFileNameMax); - WINUSERAPI UINT WINAPI GetWindowModuleFileNameW(HWND hwnd,LPWSTR pszFileName,UINT cchFileNameMax); - -#ifndef NO_STATE_FLAGS -#define STATE_SYSTEM_UNAVAILABLE 0x00000001 -#define STATE_SYSTEM_SELECTED 0x00000002 -#define STATE_SYSTEM_FOCUSED 0x00000004 -#define STATE_SYSTEM_PRESSED 0x00000008 -#define STATE_SYSTEM_CHECKED 0x00000010 -#define STATE_SYSTEM_MIXED 0x00000020 -#define STATE_SYSTEM_INDETERMINATE STATE_SYSTEM_MIXED -#define STATE_SYSTEM_READONLY 0x00000040 -#define STATE_SYSTEM_HOTTRACKED 0x00000080 -#define STATE_SYSTEM_DEFAULT 0x00000100 -#define STATE_SYSTEM_EXPANDED 0x00000200 -#define STATE_SYSTEM_COLLAPSED 0x00000400 -#define STATE_SYSTEM_BUSY 0x00000800 -#define STATE_SYSTEM_FLOATING 0x00001000 -#define STATE_SYSTEM_MARQUEED 0x00002000 -#define STATE_SYSTEM_ANIMATED 0x00004000 -#define STATE_SYSTEM_INVISIBLE 0x00008000 -#define STATE_SYSTEM_OFFSCREEN 0x00010000 -#define STATE_SYSTEM_SIZEABLE 0x00020000 -#define STATE_SYSTEM_MOVEABLE 0x00040000 -#define STATE_SYSTEM_SELFVOICING 0x00080000 -#define STATE_SYSTEM_FOCUSABLE 0x00100000 -#define STATE_SYSTEM_SELECTABLE 0x00200000 -#define STATE_SYSTEM_LINKED 0x00400000 -#define STATE_SYSTEM_TRAVERSED 0x00800000 -#define STATE_SYSTEM_MULTISELECTABLE 0x01000000 -#define STATE_SYSTEM_EXTSELECTABLE 0x02000000 -#define STATE_SYSTEM_ALERT_LOW 0x04000000 -#define STATE_SYSTEM_ALERT_MEDIUM 0x08000000 -#define STATE_SYSTEM_ALERT_HIGH 0x10000000 -#define STATE_SYSTEM_PROTECTED 0x20000000 -#define STATE_SYSTEM_VALID 0x3FFFFFFF -#endif - -#define CCHILDREN_TITLEBAR 5 -#define CCHILDREN_SCROLLBAR 5 - - typedef struct tagCURSORINFO { - DWORD cbSize; - DWORD flags; - HCURSOR hCursor; - POINT ptScreenPos; - } CURSORINFO,*PCURSORINFO,*LPCURSORINFO; - -#define CURSOR_SHOWING 0x00000001 - - WINUSERAPI WINBOOL WINAPI GetCursorInfo(PCURSORINFO pci); - - typedef struct tagWINDOWINFO { - DWORD cbSize; - RECT rcWindow; - RECT rcClient; - DWORD dwStyle; - DWORD dwExStyle; - DWORD dwWindowStatus; - UINT cxWindowBorders; - UINT cyWindowBorders; - ATOM atomWindowType; - WORD wCreatorVersion; - } WINDOWINFO,*PWINDOWINFO,*LPWINDOWINFO; - -#define WS_ACTIVECAPTION 0x0001 - - WINUSERAPI WINBOOL WINAPI GetWindowInfo(HWND hwnd,PWINDOWINFO pwi); - - typedef struct tagTITLEBARINFO { - DWORD cbSize; - RECT rcTitleBar; - DWORD rgstate[CCHILDREN_TITLEBAR + 1]; - } TITLEBARINFO,*PTITLEBARINFO,*LPTITLEBARINFO; - - WINUSERAPI WINBOOL WINAPI GetTitleBarInfo(HWND hwnd,PTITLEBARINFO pti); - - typedef struct tagMENUBARINFO { - DWORD cbSize; - RECT rcBar; - HMENU hMenu; - HWND hwndMenu; - WINBOOL fBarFocused:1; - WINBOOL fFocused:1; - } MENUBARINFO,*PMENUBARINFO,*LPMENUBARINFO; - - WINUSERAPI WINBOOL WINAPI GetMenuBarInfo(HWND hwnd,LONG idObject,LONG idItem,PMENUBARINFO pmbi); - - typedef struct tagSCROLLBARINFO { - DWORD cbSize; - RECT rcScrollBar; - int dxyLineButton; - int xyThumbTop; - int xyThumbBottom; - int reserved; - DWORD rgstate[CCHILDREN_SCROLLBAR + 1]; - } SCROLLBARINFO,*PSCROLLBARINFO,*LPSCROLLBARINFO; - - WINUSERAPI WINBOOL WINAPI GetScrollBarInfo(HWND hwnd,LONG idObject,PSCROLLBARINFO psbi); - - typedef struct tagCOMBOBOXINFO { - DWORD cbSize; - RECT rcItem; - RECT rcButton; - DWORD stateButton; - HWND hwndCombo; - HWND hwndItem; - HWND hwndList; - } COMBOBOXINFO,*PCOMBOBOXINFO,*LPCOMBOBOXINFO; - - WINUSERAPI WINBOOL WINAPI GetComboBoxInfo(HWND hwndCombo,PCOMBOBOXINFO pcbi); - -#define GA_PARENT 1 -#define GA_ROOT 2 -#define GA_ROOTOWNER 3 - - WINUSERAPI HWND WINAPI GetAncestor(HWND hwnd,UINT gaFlags); - WINUSERAPI HWND WINAPI RealChildWindowFromPoint(HWND hwndParent,POINT ptParentClientCoords); - WINUSERAPI UINT WINAPI RealGetWindowClassA(HWND hwnd,LPSTR ptszClassName,UINT cchClassNameMax); - WINUSERAPI UINT WINAPI RealGetWindowClassW(HWND hwnd,LPWSTR ptszClassName,UINT cchClassNameMax); -#ifdef UNICODE -#define RealGetWindowClass RealGetWindowClassW -#else -#define RealGetWindowClass RealGetWindowClassA -#endif - - typedef struct tagALTTABINFO { - DWORD cbSize; - int cItems; - int cColumns; - int cRows; - int iColFocus; - int iRowFocus; - int cxItem; - int cyItem; - POINT ptStart; - } ALTTABINFO,*PALTTABINFO,*LPALTTABINFO; - -#ifdef UNICODE -#define GetAltTabInfo GetAltTabInfoW -#else -#define GetAltTabInfo GetAltTabInfoA -#endif - - WINUSERAPI WINBOOL WINAPI GetAltTabInfoA(HWND hwnd,int iItem,PALTTABINFO pati,LPSTR pszItemText,UINT cchItemText); - WINUSERAPI WINBOOL WINAPI GetAltTabInfoW(HWND hwnd,int iItem,PALTTABINFO pati,LPWSTR pszItemText,UINT cchItemText); - WINUSERAPI DWORD WINAPI GetListBoxInfo(HWND hwnd); -#endif - - WINUSERAPI WINBOOL WINAPI LockWorkStation(VOID); - WINUSERAPI WINBOOL WINAPI UserHandleGrantAccess(HANDLE hUserHandle,HANDLE hJob,WINBOOL bGrant); - - DECLARE_HANDLE(HRAWINPUT); - -#define GET_RAWINPUT_CODE_WPARAM(wParam) ((wParam) & 0xff) - -#define RIM_INPUT 0 -#define RIM_INPUTSINK 1 - - typedef struct tagRAWINPUTHEADER { - DWORD dwType; - DWORD dwSize; - HANDLE hDevice; - WPARAM wParam; - } RAWINPUTHEADER,*PRAWINPUTHEADER,*LPRAWINPUTHEADER; - -#define RIM_TYPEMOUSE 0 -#define RIM_TYPEKEYBOARD 1 -#define RIM_TYPEHID 2 - - typedef struct tagRAWMOUSE { - USHORT usFlags; - union { - ULONG ulButtons; - struct { - USHORT usButtonFlags; - USHORT usButtonData; - }; - }; - ULONG ulRawButtons; - LONG lLastX; - LONG lLastY; - ULONG ulExtraInformation; - } RAWMOUSE,*PRAWMOUSE,*LPRAWMOUSE; - -#define RI_MOUSE_LEFT_BUTTON_DOWN 0x0001 -#define RI_MOUSE_LEFT_BUTTON_UP 0x0002 -#define RI_MOUSE_RIGHT_BUTTON_DOWN 0x0004 -#define RI_MOUSE_RIGHT_BUTTON_UP 0x0008 -#define RI_MOUSE_MIDDLE_BUTTON_DOWN 0x0010 -#define RI_MOUSE_MIDDLE_BUTTON_UP 0x0020 - -#define RI_MOUSE_BUTTON_1_DOWN RI_MOUSE_LEFT_BUTTON_DOWN -#define RI_MOUSE_BUTTON_1_UP RI_MOUSE_LEFT_BUTTON_UP -#define RI_MOUSE_BUTTON_2_DOWN RI_MOUSE_RIGHT_BUTTON_DOWN -#define RI_MOUSE_BUTTON_2_UP RI_MOUSE_RIGHT_BUTTON_UP -#define RI_MOUSE_BUTTON_3_DOWN RI_MOUSE_MIDDLE_BUTTON_DOWN -#define RI_MOUSE_BUTTON_3_UP RI_MOUSE_MIDDLE_BUTTON_UP - -#define RI_MOUSE_BUTTON_4_DOWN 0x0040 -#define RI_MOUSE_BUTTON_4_UP 0x0080 -#define RI_MOUSE_BUTTON_5_DOWN 0x0100 -#define RI_MOUSE_BUTTON_5_UP 0x0200 - -#define RI_MOUSE_WHEEL 0x0400 - -#define MOUSE_MOVE_RELATIVE 0 -#define MOUSE_MOVE_ABSOLUTE 1 -#define MOUSE_VIRTUAL_DESKTOP 0x02 -#define MOUSE_ATTRIBUTES_CHANGED 0x04 - - typedef struct tagRAWKEYBOARD { - USHORT MakeCode; - USHORT Flags; - USHORT Reserved; - USHORT VKey; - UINT Message; - ULONG ExtraInformation; - } RAWKEYBOARD,*PRAWKEYBOARD,*LPRAWKEYBOARD; - -#define KEYBOARD_OVERRUN_MAKE_CODE 0xFF - -#define RI_KEY_MAKE 0 -#define RI_KEY_BREAK 1 -#define RI_KEY_E0 2 -#define RI_KEY_E1 4 -#define RI_KEY_TERMSRV_SET_LED 8 -#define RI_KEY_TERMSRV_SHADOW 0x10 - - typedef struct tagRAWHID { - DWORD dwSizeHid; - DWORD dwCount; - BYTE bRawData[1]; - } RAWHID,*PRAWHID,*LPRAWHID; - - typedef struct tagRAWINPUT { - RAWINPUTHEADER header; - union { - RAWMOUSE mouse; - RAWKEYBOARD keyboard; - RAWHID hid; - } data; - } RAWINPUT,*PRAWINPUT,*LPRAWINPUT; - -#ifdef _WIN64 -#define RAWINPUT_ALIGN(x) (((x) + sizeof(QWORD) - 1) & ~(sizeof(QWORD) - 1)) -#else -#define RAWINPUT_ALIGN(x) (((x) + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1)) -#endif - -#define NEXTRAWINPUTBLOCK(ptr) ((PRAWINPUT)RAWINPUT_ALIGN((ULONG_PTR)((PBYTE)(ptr) + (ptr)->header.dwSize))) - -#define RID_INPUT 0x10000003 -#define RID_HEADER 0x10000005 - - WINUSERAPI UINT WINAPI GetRawInputData(HRAWINPUT hRawInput,UINT uiCommand,LPVOID pData,PUINT pcbSize,UINT cbSizeHeader); - -#define RIDI_PREPARSEDDATA 0x20000005 -#define RIDI_DEVICENAME 0x20000007 -#define RIDI_DEVICEINFO 0x2000000b - - typedef struct tagRID_DEVICE_INFO_MOUSE { - DWORD dwId; - DWORD dwNumberOfButtons; - DWORD dwSampleRate; - } RID_DEVICE_INFO_MOUSE,*PRID_DEVICE_INFO_MOUSE; - - typedef struct tagRID_DEVICE_INFO_KEYBOARD { - DWORD dwType; - DWORD dwSubType; - DWORD dwKeyboardMode; - DWORD dwNumberOfFunctionKeys; - DWORD dwNumberOfIndicators; - DWORD dwNumberOfKeysTotal; - } RID_DEVICE_INFO_KEYBOARD,*PRID_DEVICE_INFO_KEYBOARD; - - typedef struct tagRID_DEVICE_INFO_HID { - DWORD dwVendorId; - DWORD dwProductId; - DWORD dwVersionNumber; - USHORT usUsagePage; - USHORT usUsage; - } RID_DEVICE_INFO_HID,*PRID_DEVICE_INFO_HID; - - typedef struct tagRID_DEVICE_INFO { - DWORD cbSize; - DWORD dwType; - union { - RID_DEVICE_INFO_MOUSE mouse; - RID_DEVICE_INFO_KEYBOARD keyboard; - RID_DEVICE_INFO_HID hid; - }; - } RID_DEVICE_INFO,*PRID_DEVICE_INFO,*LPRID_DEVICE_INFO; - -#ifdef UNICODE -#define GetRawInputDeviceInfo GetRawInputDeviceInfoW -#else -#define GetRawInputDeviceInfo GetRawInputDeviceInfoA -#endif - - WINUSERAPI UINT WINAPI GetRawInputDeviceInfoA(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); - WINUSERAPI UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); - WINUSERAPI UINT WINAPI GetRawInputBuffer(PRAWINPUT pData,PUINT pcbSize,UINT cbSizeHeader); - - typedef struct tagRAWINPUTDEVICE { - USHORT usUsagePage; - USHORT usUsage; - DWORD dwFlags; - HWND hwndTarget; - } RAWINPUTDEVICE,*PRAWINPUTDEVICE,*LPRAWINPUTDEVICE; - - typedef CONST RAWINPUTDEVICE *PCRAWINPUTDEVICE; - -#define RIDEV_REMOVE 0x00000001 -#define RIDEV_EXCLUDE 0x00000010 -#define RIDEV_PAGEONLY 0x00000020 -#define RIDEV_NOLEGACY 0x00000030 -#define RIDEV_INPUTSINK 0x00000100 -#define RIDEV_CAPTUREMOUSE 0x00000200 -#define RIDEV_NOHOTKEYS 0x00000200 -#define RIDEV_APPKEYS 0x00000400 -#define RIDEV_EXMODEMASK 0x000000F0 -#define RIDEV_EXMODE(mode) ((mode) & RIDEV_EXMODEMASK) - - WINUSERAPI WINBOOL WINAPI RegisterRawInputDevices(PCRAWINPUTDEVICE pRawInputDevices,UINT uiNumDevices,UINT cbSize); - WINUSERAPI UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices,PUINT puiNumDevices,UINT cbSize); - - typedef struct tagRAWINPUTDEVICELIST { - HANDLE hDevice; - DWORD dwType; - } RAWINPUTDEVICELIST,*PRAWINPUTDEVICELIST; - - WINUSERAPI UINT WINAPI GetRawInputDeviceList(PRAWINPUTDEVICELIST pRawInputDeviceList,PUINT puiNumDevices,UINT cbSize); - WINUSERAPI LRESULT WINAPI DefRawInputProc(PRAWINPUT *paRawInput,INT nInput,UINT cbSizeHeader); - -#endif /* NOUSER */ - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINUSER_ +#define _WINUSER_ + +#define WINUSERAPI DECLSPEC_IMPORT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#include + +#ifndef NOUSER + typedef HANDLE HDWP; + typedef VOID MENUTEMPLATEA; + typedef VOID MENUTEMPLATEW; + typedef PVOID LPMENUTEMPLATEA; + typedef PVOID LPMENUTEMPLATEW; + +#ifdef UNICODE + typedef MENUTEMPLATEW MENUTEMPLATE; + typedef LPMENUTEMPLATEW LPMENUTEMPLATE; +#else + typedef MENUTEMPLATEA MENUTEMPLATE; + typedef LPMENUTEMPLATEA LPMENUTEMPLATE; +#endif + + typedef LRESULT (CALLBACK *WNDPROC)(HWND,UINT,WPARAM,LPARAM); + typedef INT_PTR (CALLBACK *DLGPROC)(HWND,UINT,WPARAM,LPARAM); + typedef VOID (CALLBACK *TIMERPROC)(HWND,UINT,UINT_PTR,DWORD); + typedef WINBOOL (CALLBACK *GRAYSTRINGPROC)(HDC,LPARAM,int); + typedef WINBOOL (CALLBACK *WNDENUMPROC)(HWND,LPARAM); + typedef LRESULT (CALLBACK *HOOKPROC)(int code,WPARAM wParam,LPARAM lParam); + typedef VOID (CALLBACK *SENDASYNCPROC)(HWND,UINT,ULONG_PTR,LRESULT); + typedef WINBOOL (CALLBACK *PROPENUMPROCA)(HWND,LPCSTR,HANDLE); + typedef WINBOOL (CALLBACK *PROPENUMPROCW)(HWND,LPCWSTR,HANDLE); + typedef WINBOOL (CALLBACK *PROPENUMPROCEXA)(HWND,LPSTR,HANDLE,ULONG_PTR); + typedef WINBOOL (CALLBACK *PROPENUMPROCEXW)(HWND,LPWSTR,HANDLE,ULONG_PTR); + typedef int (CALLBACK *EDITWORDBREAKPROCA)(LPSTR lpch,int ichCurrent,int cch,int code); + typedef int (CALLBACK *EDITWORDBREAKPROCW)(LPWSTR lpch,int ichCurrent,int cch,int code); + typedef WINBOOL (CALLBACK *DRAWSTATEPROC)(HDC hdc,LPARAM lData,WPARAM wData,int cx,int cy); + +#ifdef UNICODE + typedef PROPENUMPROCW PROPENUMPROC; + typedef PROPENUMPROCEXW PROPENUMPROCEX; + typedef EDITWORDBREAKPROCW EDITWORDBREAKPROC; +#else + typedef PROPENUMPROCA PROPENUMPROC; + typedef PROPENUMPROCEXA PROPENUMPROCEX; + typedef EDITWORDBREAKPROCA EDITWORDBREAKPROC; +#endif + + typedef WINBOOL (CALLBACK *NAMEENUMPROCA)(LPSTR,LPARAM); + typedef WINBOOL (CALLBACK *NAMEENUMPROCW)(LPWSTR,LPARAM); + typedef NAMEENUMPROCA WINSTAENUMPROCA; + typedef NAMEENUMPROCA DESKTOPENUMPROCA; + typedef NAMEENUMPROCW WINSTAENUMPROCW; + typedef NAMEENUMPROCW DESKTOPENUMPROCW; + +#ifdef UNICODE + typedef WINSTAENUMPROCW WINSTAENUMPROC; + typedef DESKTOPENUMPROCW DESKTOPENUMPROC; +#else + typedef WINSTAENUMPROCA WINSTAENUMPROC; + typedef DESKTOPENUMPROCA DESKTOPENUMPROC; +#endif + +#define IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16)==0) +#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i)))) +#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i)))) +#ifdef UNICODE +#define MAKEINTRESOURCE MAKEINTRESOURCEW +#else +#define MAKEINTRESOURCE MAKEINTRESOURCEA +#endif + +#ifndef NORESOURCE + +#define RT_CURSOR MAKEINTRESOURCE(1) +#define RT_BITMAP MAKEINTRESOURCE(2) +#define RT_ICON MAKEINTRESOURCE(3) +#define RT_MENU MAKEINTRESOURCE(4) +#define RT_DIALOG MAKEINTRESOURCE(5) +#define RT_STRING MAKEINTRESOURCE(6) +#define RT_FONTDIR MAKEINTRESOURCE(7) +#define RT_FONT MAKEINTRESOURCE(8) +#define RT_ACCELERATOR MAKEINTRESOURCE(9) +#define RT_RCDATA MAKEINTRESOURCE(10) +#define RT_MESSAGETABLE MAKEINTRESOURCE(11) + +#define DIFFERENCE 11 +#define RT_GROUP_CURSOR MAKEINTRESOURCE((ULONG_PTR)RT_CURSOR + DIFFERENCE) +#define RT_GROUP_ICON MAKEINTRESOURCE((ULONG_PTR)RT_ICON + DIFFERENCE) +#define RT_VERSION MAKEINTRESOURCE(16) +#define RT_DLGINCLUDE MAKEINTRESOURCE(17) +#define RT_PLUGPLAY MAKEINTRESOURCE(19) +#define RT_VXD MAKEINTRESOURCE(20) +#define RT_ANICURSOR MAKEINTRESOURCE(21) +#define RT_ANIICON MAKEINTRESOURCE(22) +#define RT_HTML MAKEINTRESOURCE(23) +#ifdef RC_INVOKED +#define RT_MANIFEST 24 +#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 +#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 +#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3 +#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID 1 +#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID 16 +#else +#define RT_MANIFEST MAKEINTRESOURCE(24) +#define CREATEPROCESS_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) +#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(2) +#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(3) +#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) +#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(16) +#endif +#endif + +#ifdef UNICODE +#define wvsprintf wvsprintfW +#define wsprintf wsprintfW +#else +#define wvsprintf wvsprintfA +#define wsprintf wsprintfA +#endif + + WINUSERAPI int WINAPI wvsprintfA(LPSTR,LPCSTR,va_list arglist); + WINUSERAPI int WINAPI wvsprintfW(LPWSTR,LPCWSTR,va_list arglist); + WINUSERAPI int WINAPIV wsprintfA(LPSTR,LPCSTR,...); + WINUSERAPI int WINAPIV wsprintfW(LPWSTR,LPCWSTR,...); + +#define SETWALLPAPER_DEFAULT ((LPWSTR)-1) + +#ifndef NOSCROLL +#define SB_HORZ 0 +#define SB_VERT 1 +#define SB_CTL 2 +#define SB_BOTH 3 + +#define SB_LINEUP 0 +#define SB_LINELEFT 0 +#define SB_LINEDOWN 1 +#define SB_LINERIGHT 1 +#define SB_PAGEUP 2 +#define SB_PAGELEFT 2 +#define SB_PAGEDOWN 3 +#define SB_PAGERIGHT 3 +#define SB_THUMBPOSITION 4 +#define SB_THUMBTRACK 5 +#define SB_TOP 6 +#define SB_LEFT 6 +#define SB_BOTTOM 7 +#define SB_RIGHT 7 +#define SB_ENDSCROLL 8 +#endif + +#ifndef NOSHOWWINDOW +#define SW_HIDE 0 +#define SW_SHOWNORMAL 1 +#define SW_NORMAL 1 +#define SW_SHOWMINIMIZED 2 +#define SW_SHOWMAXIMIZED 3 +#define SW_MAXIMIZE 3 +#define SW_SHOWNOACTIVATE 4 +#define SW_SHOW 5 +#define SW_MINIMIZE 6 +#define SW_SHOWMINNOACTIVE 7 +#define SW_SHOWNA 8 +#define SW_RESTORE 9 +#define SW_SHOWDEFAULT 10 +#define SW_FORCEMINIMIZE 11 +#define SW_MAX 11 + +#define HIDE_WINDOW 0 +#define SHOW_OPENWINDOW 1 +#define SHOW_ICONWINDOW 2 +#define SHOW_FULLSCREEN 3 +#define SHOW_OPENNOACTIVATE 4 + +#define SW_PARENTCLOSING 1 +#define SW_OTHERZOOM 2 +#define SW_PARENTOPENING 3 +#define SW_OTHERUNZOOM 4 +#endif + +#define AW_HOR_POSITIVE 0x00000001 +#define AW_HOR_NEGATIVE 0x00000002 +#define AW_VER_POSITIVE 0x00000004 +#define AW_VER_NEGATIVE 0x00000008 +#define AW_CENTER 0x00000010 +#define AW_HIDE 0x00010000 +#define AW_ACTIVATE 0x00020000 +#define AW_SLIDE 0x00040000 +#define AW_BLEND 0x00080000 + +#define KF_EXTENDED 0x0100 +#define KF_DLGMODE 0x0800 +#define KF_MENUMODE 0x1000 +#define KF_ALTDOWN 0x2000 +#define KF_REPEAT 0x4000 +#define KF_UP 0x8000 + +#ifndef NOVIRTUALKEYCODES + +#define VK_LBUTTON 0x01 +#define VK_RBUTTON 0x02 +#define VK_CANCEL 0x03 +#define VK_MBUTTON 0x04 +#define VK_XBUTTON1 0x05 +#define VK_XBUTTON2 0x06 +#define VK_BACK 0x08 +#define VK_TAB 0x09 +#define VK_CLEAR 0x0C +#define VK_RETURN 0x0D +#define VK_SHIFT 0x10 +#define VK_CONTROL 0x11 +#define VK_MENU 0x12 +#define VK_PAUSE 0x13 +#define VK_CAPITAL 0x14 +#define VK_KANA 0x15 +#define VK_HANGEUL 0x15 +#define VK_HANGUL 0x15 +#define VK_JUNJA 0x17 +#define VK_FINAL 0x18 +#define VK_HANJA 0x19 +#define VK_KANJI 0x19 +#define VK_ESCAPE 0x1B +#define VK_CONVERT 0x1C +#define VK_NONCONVERT 0x1D +#define VK_ACCEPT 0x1E +#define VK_MODECHANGE 0x1F +#define VK_SPACE 0x20 +#define VK_PRIOR 0x21 +#define VK_NEXT 0x22 +#define VK_END 0x23 +#define VK_HOME 0x24 +#define VK_LEFT 0x25 +#define VK_UP 0x26 +#define VK_RIGHT 0x27 +#define VK_DOWN 0x28 +#define VK_SELECT 0x29 +#define VK_PRINT 0x2A +#define VK_EXECUTE 0x2B +#define VK_SNAPSHOT 0x2C +#define VK_INSERT 0x2D +#define VK_DELETE 0x2E +#define VK_HELP 0x2F + +#define VK_LWIN 0x5B +#define VK_RWIN 0x5C +#define VK_APPS 0x5D +#define VK_SLEEP 0x5F +#define VK_NUMPAD0 0x60 +#define VK_NUMPAD1 0x61 +#define VK_NUMPAD2 0x62 +#define VK_NUMPAD3 0x63 +#define VK_NUMPAD4 0x64 +#define VK_NUMPAD5 0x65 +#define VK_NUMPAD6 0x66 +#define VK_NUMPAD7 0x67 +#define VK_NUMPAD8 0x68 +#define VK_NUMPAD9 0x69 +#define VK_MULTIPLY 0x6A +#define VK_ADD 0x6B +#define VK_SEPARATOR 0x6C +#define VK_SUBTRACT 0x6D +#define VK_DECIMAL 0x6E +#define VK_DIVIDE 0x6F +#define VK_F1 0x70 +#define VK_F2 0x71 +#define VK_F3 0x72 +#define VK_F4 0x73 +#define VK_F5 0x74 +#define VK_F6 0x75 +#define VK_F7 0x76 +#define VK_F8 0x77 +#define VK_F9 0x78 +#define VK_F10 0x79 +#define VK_F11 0x7A +#define VK_F12 0x7B +#define VK_F13 0x7C +#define VK_F14 0x7D +#define VK_F15 0x7E +#define VK_F16 0x7F +#define VK_F17 0x80 +#define VK_F18 0x81 +#define VK_F19 0x82 +#define VK_F20 0x83 +#define VK_F21 0x84 +#define VK_F22 0x85 +#define VK_F23 0x86 +#define VK_F24 0x87 +#define VK_NUMLOCK 0x90 +#define VK_SCROLL 0x91 +#define VK_OEM_NEC_EQUAL 0x92 +#define VK_OEM_FJ_JISHO 0x92 +#define VK_OEM_FJ_MASSHOU 0x93 +#define VK_OEM_FJ_TOUROKU 0x94 +#define VK_OEM_FJ_LOYA 0x95 +#define VK_OEM_FJ_ROYA 0x96 +#define VK_LSHIFT 0xA0 +#define VK_RSHIFT 0xA1 +#define VK_LCONTROL 0xA2 +#define VK_RCONTROL 0xA3 +#define VK_LMENU 0xA4 +#define VK_RMENU 0xA5 +#define VK_BROWSER_BACK 0xA6 +#define VK_BROWSER_FORWARD 0xA7 +#define VK_BROWSER_REFRESH 0xA8 +#define VK_BROWSER_STOP 0xA9 +#define VK_BROWSER_SEARCH 0xAA +#define VK_BROWSER_FAVORITES 0xAB +#define VK_BROWSER_HOME 0xAC +#define VK_VOLUME_MUTE 0xAD +#define VK_VOLUME_DOWN 0xAE +#define VK_VOLUME_UP 0xAF +#define VK_MEDIA_NEXT_TRACK 0xB0 +#define VK_MEDIA_PREV_TRACK 0xB1 +#define VK_MEDIA_STOP 0xB2 +#define VK_MEDIA_PLAY_PAUSE 0xB3 +#define VK_LAUNCH_MAIL 0xB4 +#define VK_LAUNCH_MEDIA_SELECT 0xB5 +#define VK_LAUNCH_APP1 0xB6 +#define VK_LAUNCH_APP2 0xB7 +#define VK_OEM_1 0xBA +#define VK_OEM_PLUS 0xBB +#define VK_OEM_COMMA 0xBC +#define VK_OEM_MINUS 0xBD +#define VK_OEM_PERIOD 0xBE +#define VK_OEM_2 0xBF +#define VK_OEM_3 0xC0 +#define VK_OEM_4 0xDB +#define VK_OEM_5 0xDC +#define VK_OEM_6 0xDD +#define VK_OEM_7 0xDE +#define VK_OEM_8 0xDF +#define VK_OEM_AX 0xE1 +#define VK_OEM_102 0xE2 +#define VK_ICO_HELP 0xE3 +#define VK_ICO_00 0xE4 +#define VK_PROCESSKEY 0xE5 +#define VK_ICO_CLEAR 0xE6 +#define VK_PACKET 0xE7 +#define VK_OEM_RESET 0xE9 +#define VK_OEM_JUMP 0xEA +#define VK_OEM_PA1 0xEB +#define VK_OEM_PA2 0xEC +#define VK_OEM_PA3 0xED +#define VK_OEM_WSCTRL 0xEE +#define VK_OEM_CUSEL 0xEF +#define VK_OEM_ATTN 0xF0 +#define VK_OEM_FINISH 0xF1 +#define VK_OEM_COPY 0xF2 +#define VK_OEM_AUTO 0xF3 +#define VK_OEM_ENLW 0xF4 +#define VK_OEM_BACKTAB 0xF5 +#define VK_ATTN 0xF6 +#define VK_CRSEL 0xF7 +#define VK_EXSEL 0xF8 +#define VK_EREOF 0xF9 +#define VK_PLAY 0xFA +#define VK_ZOOM 0xFB +#define VK_NONAME 0xFC +#define VK_PA1 0xFD +#define VK_OEM_CLEAR 0xFE +#endif + +#ifndef NOWH + +#define WH_MIN (-1) +#define WH_MSGFILTER (-1) +#define WH_JOURNALRECORD 0 +#define WH_JOURNALPLAYBACK 1 +#define WH_KEYBOARD 2 +#define WH_GETMESSAGE 3 +#define WH_CALLWNDPROC 4 +#define WH_CBT 5 +#define WH_SYSMSGFILTER 6 +#define WH_MOUSE 7 +#define WH_HARDWARE 8 +#define WH_DEBUG 9 +#define WH_SHELL 10 +#define WH_FOREGROUNDIDLE 11 +#define WH_CALLWNDPROCRET 12 + +#define WH_KEYBOARD_LL 13 +#define WH_MOUSE_LL 14 + +#define WH_MAX 14 + +#define WH_MINHOOK WH_MIN +#define WH_MAXHOOK WH_MAX + +#define HC_ACTION 0 +#define HC_GETNEXT 1 +#define HC_SKIP 2 +#define HC_NOREMOVE 3 +#define HC_NOREM HC_NOREMOVE +#define HC_SYSMODALON 4 +#define HC_SYSMODALOFF 5 + +#define HCBT_MOVESIZE 0 +#define HCBT_MINMAX 1 +#define HCBT_QS 2 +#define HCBT_CREATEWND 3 +#define HCBT_DESTROYWND 4 +#define HCBT_ACTIVATE 5 +#define HCBT_CLICKSKIPPED 6 +#define HCBT_KEYSKIPPED 7 +#define HCBT_SYSCOMMAND 8 +#define HCBT_SETFOCUS 9 + + typedef struct tagCBT_CREATEWNDA { + struct tagCREATESTRUCTA *lpcs; + HWND hwndInsertAfter; + } CBT_CREATEWNDA,*LPCBT_CREATEWNDA; + + typedef struct tagCBT_CREATEWNDW { + struct tagCREATESTRUCTW *lpcs; + HWND hwndInsertAfter; + } CBT_CREATEWNDW,*LPCBT_CREATEWNDW; +#ifdef UNICODE + typedef CBT_CREATEWNDW CBT_CREATEWND; + typedef LPCBT_CREATEWNDW LPCBT_CREATEWND; +#else + typedef CBT_CREATEWNDA CBT_CREATEWND; + typedef LPCBT_CREATEWNDA LPCBT_CREATEWND; +#endif + + typedef struct tagCBTACTIVATESTRUCT + { + WINBOOL fMouse; + HWND hWndActive; + } CBTACTIVATESTRUCT,*LPCBTACTIVATESTRUCT; + + typedef struct tagWTSSESSION_NOTIFICATION { + DWORD cbSize; + DWORD dwSessionId; + + } WTSSESSION_NOTIFICATION,*PWTSSESSION_NOTIFICATION; + +#define WTS_CONSOLE_CONNECT 0x1 +#define WTS_CONSOLE_DISCONNECT 0x2 +#define WTS_REMOTE_CONNECT 0x3 +#define WTS_REMOTE_DISCONNECT 0x4 +#define WTS_SESSION_LOGON 0x5 +#define WTS_SESSION_LOGOFF 0x6 +#define WTS_SESSION_LOCK 0x7 +#define WTS_SESSION_UNLOCK 0x8 +#define WTS_SESSION_REMOTE_CONTROL 0x9 + +#define MSGF_DIALOGBOX 0 +#define MSGF_MESSAGEBOX 1 +#define MSGF_MENU 2 +#define MSGF_SCROLLBAR 5 +#define MSGF_NEXTWINDOW 6 +#define MSGF_MAX 8 +#define MSGF_USER 4096 + +#define HSHELL_WINDOWCREATED 1 +#define HSHELL_WINDOWDESTROYED 2 +#define HSHELL_ACTIVATESHELLWINDOW 3 + +#define HSHELL_WINDOWACTIVATED 4 +#define HSHELL_GETMINRECT 5 +#define HSHELL_REDRAW 6 +#define HSHELL_TASKMAN 7 +#define HSHELL_LANGUAGE 8 +#define HSHELL_SYSMENU 9 +#define HSHELL_ENDTASK 10 +#define HSHELL_ACCESSIBILITYSTATE 11 +#define HSHELL_APPCOMMAND 12 +#define HSHELL_WINDOWREPLACED 13 +#define HSHELL_WINDOWREPLACING 14 +#define HSHELL_HIGHBIT 0x8000 +#define HSHELL_FLASH (HSHELL_REDRAW|HSHELL_HIGHBIT) +#define HSHELL_RUDEAPPACTIVATED (HSHELL_WINDOWACTIVATED|HSHELL_HIGHBIT) + +#define ACCESS_STICKYKEYS 0x0001 +#define ACCESS_FILTERKEYS 0x0002 +#define ACCESS_MOUSEKEYS 0x0003 + +#define APPCOMMAND_BROWSER_BACKWARD 1 +#define APPCOMMAND_BROWSER_FORWARD 2 +#define APPCOMMAND_BROWSER_REFRESH 3 +#define APPCOMMAND_BROWSER_STOP 4 +#define APPCOMMAND_BROWSER_SEARCH 5 +#define APPCOMMAND_BROWSER_FAVORITES 6 +#define APPCOMMAND_BROWSER_HOME 7 +#define APPCOMMAND_VOLUME_MUTE 8 +#define APPCOMMAND_VOLUME_DOWN 9 +#define APPCOMMAND_VOLUME_UP 10 +#define APPCOMMAND_MEDIA_NEXTTRACK 11 +#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12 +#define APPCOMMAND_MEDIA_STOP 13 +#define APPCOMMAND_MEDIA_PLAY_PAUSE 14 +#define APPCOMMAND_LAUNCH_MAIL 15 +#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16 +#define APPCOMMAND_LAUNCH_APP1 17 +#define APPCOMMAND_LAUNCH_APP2 18 +#define APPCOMMAND_BASS_DOWN 19 +#define APPCOMMAND_BASS_BOOST 20 +#define APPCOMMAND_BASS_UP 21 +#define APPCOMMAND_TREBLE_DOWN 22 +#define APPCOMMAND_TREBLE_UP 23 +#define APPCOMMAND_MICROPHONE_VOLUME_MUTE 24 +#define APPCOMMAND_MICROPHONE_VOLUME_DOWN 25 +#define APPCOMMAND_MICROPHONE_VOLUME_UP 26 +#define APPCOMMAND_HELP 27 +#define APPCOMMAND_FIND 28 +#define APPCOMMAND_NEW 29 +#define APPCOMMAND_OPEN 30 +#define APPCOMMAND_CLOSE 31 +#define APPCOMMAND_SAVE 32 +#define APPCOMMAND_PRINT 33 +#define APPCOMMAND_UNDO 34 +#define APPCOMMAND_REDO 35 +#define APPCOMMAND_COPY 36 +#define APPCOMMAND_CUT 37 +#define APPCOMMAND_PASTE 38 +#define APPCOMMAND_REPLY_TO_MAIL 39 +#define APPCOMMAND_FORWARD_MAIL 40 +#define APPCOMMAND_SEND_MAIL 41 +#define APPCOMMAND_SPELL_CHECK 42 +#define APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE 43 +#define APPCOMMAND_MIC_ON_OFF_TOGGLE 44 +#define APPCOMMAND_CORRECTION_LIST 45 +#define APPCOMMAND_MEDIA_PLAY 46 +#define APPCOMMAND_MEDIA_PAUSE 47 +#define APPCOMMAND_MEDIA_RECORD 48 +#define APPCOMMAND_MEDIA_FAST_FORWARD 49 +#define APPCOMMAND_MEDIA_REWIND 50 +#define APPCOMMAND_MEDIA_CHANNEL_UP 51 +#define APPCOMMAND_MEDIA_CHANNEL_DOWN 52 + +#define FAPPCOMMAND_MOUSE 0x8000 +#define FAPPCOMMAND_KEY 0 +#define FAPPCOMMAND_OEM 0x1000 +#define FAPPCOMMAND_MASK 0xF000 + +#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK)) +#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK)) +#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM +#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam)) +#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam) + + typedef struct { + HWND hwnd; + RECT rc; + } SHELLHOOKINFO,*LPSHELLHOOKINFO; + + typedef struct tagEVENTMSG { + UINT message; + UINT paramL; + UINT paramH; + DWORD time; + HWND hwnd; + } EVENTMSG,*PEVENTMSGMSG,*NPEVENTMSGMSG,*LPEVENTMSGMSG; + + typedef struct tagEVENTMSG *PEVENTMSG,*NPEVENTMSG,*LPEVENTMSG; + + typedef struct tagCWPSTRUCT { + LPARAM lParam; + WPARAM wParam; + UINT message; + HWND hwnd; + } CWPSTRUCT,*PCWPSTRUCT,*NPCWPSTRUCT,*LPCWPSTRUCT; + + typedef struct tagCWPRETSTRUCT { + LRESULT lResult; + LPARAM lParam; + WPARAM wParam; + UINT message; + HWND hwnd; + } CWPRETSTRUCT,*PCWPRETSTRUCT,*NPCWPRETSTRUCT,*LPCWPRETSTRUCT; + +#define LLKHF_EXTENDED (KF_EXTENDED >> 8) +#define LLKHF_INJECTED 0x00000010 +#define LLKHF_ALTDOWN (KF_ALTDOWN >> 8) +#define LLKHF_UP (KF_UP >> 8) + +#define LLMHF_INJECTED 0x00000001 + + typedef struct tagKBDLLHOOKSTRUCT { + DWORD vkCode; + DWORD scanCode; + DWORD flags; + DWORD time; + ULONG_PTR dwExtraInfo; + } KBDLLHOOKSTRUCT,*LPKBDLLHOOKSTRUCT,*PKBDLLHOOKSTRUCT; + + typedef struct tagMSLLHOOKSTRUCT { + POINT pt; + DWORD mouseData; + DWORD flags; + DWORD time; + ULONG_PTR dwExtraInfo; + } MSLLHOOKSTRUCT,*LPMSLLHOOKSTRUCT,*PMSLLHOOKSTRUCT; + + typedef struct tagDEBUGHOOKINFO { + DWORD idThread; + DWORD idThreadInstaller; + LPARAM lParam; + WPARAM wParam; + int code; + } DEBUGHOOKINFO,*PDEBUGHOOKINFO,*NPDEBUGHOOKINFO,*LPDEBUGHOOKINFO; + + typedef struct tagMOUSEHOOKSTRUCT { + POINT pt; + HWND hwnd; + UINT wHitTestCode; + ULONG_PTR dwExtraInfo; + } MOUSEHOOKSTRUCT,*LPMOUSEHOOKSTRUCT,*PMOUSEHOOKSTRUCT; + +#ifdef __cplusplus + typedef struct tagMOUSEHOOKSTRUCTEX : public tagMOUSEHOOKSTRUCT { + DWORD mouseData; + } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; +#else + typedef struct tagMOUSEHOOKSTRUCTEX { + MOUSEHOOKSTRUCT _unnamed; + DWORD mouseData; + } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; +#endif + + typedef struct tagHARDWAREHOOKSTRUCT { + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + } HARDWAREHOOKSTRUCT,*LPHARDWAREHOOKSTRUCT,*PHARDWAREHOOKSTRUCT; +#endif + +#define HKL_PREV 0 +#define HKL_NEXT 1 + +#define KLF_ACTIVATE 0x00000001 +#define KLF_SUBSTITUTE_OK 0x00000002 +#define KLF_REORDER 0x00000008 +#define KLF_REPLACELANG 0x00000010 +#define KLF_NOTELLSHELL 0x00000080 +#define KLF_SETFORPROCESS 0x00000100 +#define KLF_SHIFTLOCK 0x00010000 +#define KLF_RESET 0x40000000 + +#define INPUTLANGCHANGE_SYSCHARSET 0x0001 +#define INPUTLANGCHANGE_FORWARD 0x0002 +#define INPUTLANGCHANGE_BACKWARD 0x0004 + +#define KL_NAMELENGTH 9 + +#ifdef UNICODE +#define LoadKeyboardLayout LoadKeyboardLayoutW +#define GetKeyboardLayoutName GetKeyboardLayoutNameW +#else +#define LoadKeyboardLayout LoadKeyboardLayoutA +#define GetKeyboardLayoutName GetKeyboardLayoutNameA +#endif + + WINUSERAPI HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID,UINT Flags); + WINUSERAPI HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID,UINT Flags); + WINUSERAPI HKL WINAPI ActivateKeyboardLayout(HKL hkl,UINT Flags); + WINUSERAPI int WINAPI ToUnicodeEx(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags,HKL dwhkl); + WINUSERAPI WINBOOL WINAPI UnloadKeyboardLayout(HKL hkl); + WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameA(LPSTR pwszKLID); + WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID); + WINUSERAPI int WINAPI GetKeyboardLayoutList(int nBuff,HKL *lpList); + WINUSERAPI HKL WINAPI GetKeyboardLayout(DWORD idThread); + + typedef struct tagMOUSEMOVEPOINT { + int x; + int y; + DWORD time; + ULONG_PTR dwExtraInfo; + } MOUSEMOVEPOINT,*PMOUSEMOVEPOINT,*LPMOUSEMOVEPOINT; + +#define GMMP_USE_DISPLAY_POINTS 1 +#define GMMP_USE_HIGH_RESOLUTION_POINTS 2 + + WINUSERAPI int WINAPI GetMouseMovePointsEx(UINT cbSize,LPMOUSEMOVEPOINT lppt,LPMOUSEMOVEPOINT lpptBuf,int nBufPoints,DWORD resolution); + +#ifndef NODESKTOP + +#define DESKTOP_READOBJECTS 0x0001L +#define DESKTOP_CREATEWINDOW 0x0002L +#define DESKTOP_CREATEMENU 0x0004L +#define DESKTOP_HOOKCONTROL 0x0008L +#define DESKTOP_JOURNALRECORD 0x0010L +#define DESKTOP_JOURNALPLAYBACK 0x0020L +#define DESKTOP_ENUMERATE 0x0040L +#define DESKTOP_WRITEOBJECTS 0x0080L +#define DESKTOP_SWITCHDESKTOP 0x0100L + +#define DF_ALLOWOTHERACCOUNTHOOK 0x0001L + +#ifdef _WINGDI_ +#ifndef NOGDI +#ifdef UNICODE +#define CreateDesktop CreateDesktopW +#else +#define CreateDesktop CreateDesktopA +#endif + + WINUSERAPI HDESK WINAPI CreateDesktopA(LPCSTR lpszDesktop,LPCSTR lpszDevice,LPDEVMODEA pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); + WINUSERAPI HDESK WINAPI CreateDesktopW(LPCWSTR lpszDesktop,LPCWSTR lpszDevice,LPDEVMODEW pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); +#endif +#endif + +#ifdef UNICODE +#define OpenDesktop OpenDesktopW +#define EnumDesktops EnumDesktopsW +#else +#define OpenDesktop OpenDesktopA +#define EnumDesktops EnumDesktopsA +#endif + + WINUSERAPI HDESK WINAPI OpenDesktopA(LPCSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI HDESK WINAPI OpenDesktopW(LPCWSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI HDESK WINAPI OpenInputDesktop(DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI WINBOOL WINAPI EnumDesktopsA(HWINSTA hwinsta,DESKTOPENUMPROCA lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumDesktopsW(HWINSTA hwinsta,DESKTOPENUMPROCW lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumDesktopWindows(HDESK hDesktop,WNDENUMPROC lpfn,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI SwitchDesktop(HDESK hDesktop); + WINUSERAPI WINBOOL WINAPI SetThreadDesktop(HDESK hDesktop); + WINUSERAPI WINBOOL WINAPI CloseDesktop(HDESK hDesktop); + WINUSERAPI HDESK WINAPI GetThreadDesktop(DWORD dwThreadId); +#endif + +#ifndef NOWINDOWSTATION +#define WINSTA_ENUMDESKTOPS 0x0001L +#define WINSTA_READATTRIBUTES 0x0002L +#define WINSTA_ACCESSCLIPBOARD 0x0004L +#define WINSTA_CREATEDESKTOP 0x0008L +#define WINSTA_WRITEATTRIBUTES 0x0010L +#define WINSTA_ACCESSGLOBALATOMS 0x0020L +#define WINSTA_EXITWINDOWS 0x0040L +#define WINSTA_ENUMERATE 0x0100L +#define WINSTA_READSCREEN 0x0200L +#define WINSTA_ALL_ACCESS (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN) + +#define CWF_CREATE_ONLY 0x0001L + +#define WSF_VISIBLE 0x0001L + +#ifdef UNICODE +#define CreateWindowStation CreateWindowStationW +#define OpenWindowStation OpenWindowStationW +#define EnumWindowStations EnumWindowStationsW +#else +#define CreateWindowStation CreateWindowStationA +#define OpenWindowStation OpenWindowStationA +#define EnumWindowStations EnumWindowStationsA +#endif + + WINUSERAPI HWINSTA WINAPI CreateWindowStationA(LPCSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); + WINUSERAPI HWINSTA WINAPI CreateWindowStationW(LPCWSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); + WINUSERAPI HWINSTA WINAPI OpenWindowStationA(LPCSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI HWINSTA WINAPI OpenWindowStationW(LPCWSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI WINBOOL WINAPI EnumWindowStationsA(WINSTAENUMPROCA lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumWindowStationsW(WINSTAENUMPROCW lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI CloseWindowStation(HWINSTA hWinSta); + WINUSERAPI WINBOOL WINAPI SetProcessWindowStation(HWINSTA hWinSta); + WINUSERAPI HWINSTA WINAPI GetProcessWindowStation(VOID); +#endif + +#ifndef NOSECURITY + WINUSERAPI WINBOOL WINAPI SetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID); + WINUSERAPI WINBOOL WINAPI GetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID,DWORD nLength,LPDWORD lpnLengthNeeded); + +#define UOI_FLAGS 1 +#define UOI_NAME 2 +#define UOI_TYPE 3 +#define UOI_USER_SID 4 + + typedef struct tagUSEROBJECTFLAGS { + WINBOOL fInherit; + WINBOOL fReserved; + DWORD dwFlags; + } USEROBJECTFLAGS,*PUSEROBJECTFLAGS; + +#ifdef UNICODE +#define GetUserObjectInformation GetUserObjectInformationW +#define SetUserObjectInformation SetUserObjectInformationW +#else +#define GetUserObjectInformation GetUserObjectInformationA +#define SetUserObjectInformation SetUserObjectInformationA +#endif + + WINUSERAPI WINBOOL WINAPI GetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); + WINUSERAPI WINBOOL WINAPI GetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); + WINUSERAPI WINBOOL WINAPI SetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); + WINUSERAPI WINBOOL WINAPI SetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); +#endif + + typedef struct tagWNDCLASSEXA { + UINT cbSize; + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName; + LPCSTR lpszClassName; + HICON hIconSm; + } WNDCLASSEXA,*PWNDCLASSEXA,*NPWNDCLASSEXA,*LPWNDCLASSEXA; + + typedef struct tagWNDCLASSEXW { + UINT cbSize; + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCWSTR lpszMenuName; + LPCWSTR lpszClassName; + + HICON hIconSm; + } WNDCLASSEXW,*PWNDCLASSEXW,*NPWNDCLASSEXW,*LPWNDCLASSEXW; + +#ifdef UNICODE + typedef WNDCLASSEXW WNDCLASSEX; + typedef PWNDCLASSEXW PWNDCLASSEX; + typedef NPWNDCLASSEXW NPWNDCLASSEX; + typedef LPWNDCLASSEXW LPWNDCLASSEX; +#else + typedef WNDCLASSEXA WNDCLASSEX; + typedef PWNDCLASSEXA PWNDCLASSEX; + typedef NPWNDCLASSEXA NPWNDCLASSEX; + typedef LPWNDCLASSEXA LPWNDCLASSEX; +#endif + + typedef struct tagWNDCLASSA { + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName; + LPCSTR lpszClassName; + } WNDCLASSA,*PWNDCLASSA,*NPWNDCLASSA,*LPWNDCLASSA; + + typedef struct tagWNDCLASSW { + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCWSTR lpszMenuName; + LPCWSTR lpszClassName; + } WNDCLASSW,*PWNDCLASSW,*NPWNDCLASSW,*LPWNDCLASSW; + +#ifdef UNICODE + typedef WNDCLASSW WNDCLASS; + typedef PWNDCLASSW PWNDCLASS; + typedef NPWNDCLASSW NPWNDCLASS; + typedef LPWNDCLASSW LPWNDCLASS; +#else + typedef WNDCLASSA WNDCLASS; + typedef PWNDCLASSA PWNDCLASS; + typedef NPWNDCLASSA NPWNDCLASS; + typedef LPWNDCLASSA LPWNDCLASS; +#endif + + WINUSERAPI WINBOOL WINAPI IsHungAppWindow(HWND hwnd); + WINUSERAPI VOID WINAPI DisableProcessWindowsGhosting(VOID); + +#ifndef NOMSG + typedef struct tagMSG { + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + DWORD time; + POINT pt; + } MSG,*PMSG,*NPMSG,*LPMSG; + +#define POINTSTOPOINT(pt,pts) { (pt).x = (LONG)(SHORT)LOWORD(*(LONG*)&pts); (pt).y = (LONG)(SHORT)HIWORD(*(LONG*)&pts); } + +#define POINTTOPOINTS(pt) (MAKELONG((short)((pt).x),(short)((pt).y))) +#define MAKEWPARAM(l,h) ((WPARAM)(DWORD)MAKELONG(l,h)) +#define MAKELPARAM(l,h) ((LPARAM)(DWORD)MAKELONG(l,h)) +#define MAKELRESULT(l,h) ((LRESULT)(DWORD)MAKELONG(l,h)) +#endif + +#ifndef NOWINOFFSETS +#define GWL_WNDPROC (-4) +#define GWL_HINSTANCE (-6) +#define GWL_HWNDPARENT (-8) +#define GWL_STYLE (-16) +#define GWL_EXSTYLE (-20) +#define GWL_USERDATA (-21) +#define GWL_ID (-12) + +#ifdef _WIN64 +#undef GWL_WNDPROC +#undef GWL_HINSTANCE +#undef GWL_HWNDPARENT +#undef GWL_USERDATA +#endif + +#define GWLP_WNDPROC (-4) +#define GWLP_HINSTANCE (-6) +#define GWLP_HWNDPARENT (-8) +#define GWLP_USERDATA (-21) +#define GWLP_ID (-12) + +#define GCL_MENUNAME (-8) +#define GCL_HBRBACKGROUND (-10) +#define GCL_HCURSOR (-12) +#define GCL_HICON (-14) +#define GCL_HMODULE (-16) +#define GCL_CBWNDEXTRA (-18) +#define GCL_CBCLSEXTRA (-20) +#define GCL_WNDPROC (-24) +#define GCL_STYLE (-26) +#define GCW_ATOM (-32) +#define GCL_HICONSM (-34) + +#ifdef _WIN64 + +#undef GCL_MENUNAME +#undef GCL_HBRBACKGROUND +#undef GCL_HCURSOR +#undef GCL_HICON +#undef GCL_HMODULE +#undef GCL_WNDPROC +#undef GCL_HICONSM +#endif + +#define GCLP_MENUNAME (-8) +#define GCLP_HBRBACKGROUND (-10) +#define GCLP_HCURSOR (-12) +#define GCLP_HICON (-14) +#define GCLP_HMODULE (-16) +#define GCLP_WNDPROC (-24) +#define GCLP_HICONSM (-34) +#endif + +#ifndef NOWINMESSAGES + +#define WM_NULL 0x0000 +#define WM_CREATE 0x0001 +#define WM_DESTROY 0x0002 +#define WM_MOVE 0x0003 +#define WM_SIZE 0x0005 + +#define WM_ACTIVATE 0x0006 + +#define WA_INACTIVE 0 +#define WA_ACTIVE 1 +#define WA_CLICKACTIVE 2 + +#define WM_SETFOCUS 0x0007 +#define WM_KILLFOCUS 0x0008 +#define WM_ENABLE 0x000A +#define WM_SETREDRAW 0x000B +#define WM_SETTEXT 0x000C +#define WM_GETTEXT 0x000D +#define WM_GETTEXTLENGTH 0x000E +#define WM_PAINT 0x000F +#define WM_CLOSE 0x0010 +#ifndef _WIN32_WCE +#define WM_QUERYENDSESSION 0x0011 +#define WM_QUERYOPEN 0x0013 +#define WM_ENDSESSION 0x0016 +#endif +#define WM_QUIT 0x0012 +#define WM_ERASEBKGND 0x0014 +#define WM_SYSCOLORCHANGE 0x0015 +#define WM_SHOWWINDOW 0x0018 +#define WM_WININICHANGE 0x001A +#define WM_SETTINGCHANGE WM_WININICHANGE +#define WM_DEVMODECHANGE 0x001B +#define WM_ACTIVATEAPP 0x001C +#define WM_FONTCHANGE 0x001D +#define WM_TIMECHANGE 0x001E +#define WM_CANCELMODE 0x001F +#define WM_SETCURSOR 0x0020 +#define WM_MOUSEACTIVATE 0x0021 +#define WM_CHILDACTIVATE 0x0022 +#define WM_QUEUESYNC 0x0023 + +#define WM_GETMINMAXINFO 0x0024 + + typedef struct tagMINMAXINFO { + POINT ptReserved; + POINT ptMaxSize; + POINT ptMaxPosition; + POINT ptMinTrackSize; + POINT ptMaxTrackSize; + } MINMAXINFO,*PMINMAXINFO,*LPMINMAXINFO; + +#define WM_PAINTICON 0x0026 +#define WM_ICONERASEBKGND 0x0027 +#define WM_NEXTDLGCTL 0x0028 +#define WM_SPOOLERSTATUS 0x002A +#define WM_DRAWITEM 0x002B +#define WM_MEASUREITEM 0x002C +#define WM_DELETEITEM 0x002D +#define WM_VKEYTOITEM 0x002E +#define WM_CHARTOITEM 0x002F +#define WM_SETFONT 0x0030 +#define WM_GETFONT 0x0031 +#define WM_SETHOTKEY 0x0032 +#define WM_GETHOTKEY 0x0033 +#define WM_QUERYDRAGICON 0x0037 +#define WM_COMPAREITEM 0x0039 +#ifndef _WIN32_WCE +#define WM_GETOBJECT 0x003D +#endif +#define WM_COMPACTING 0x0041 +#define WM_COMMNOTIFY 0x0044 +#define WM_WINDOWPOSCHANGING 0x0046 +#define WM_WINDOWPOSCHANGED 0x0047 + +#define WM_POWER 0x0048 + +#define PWR_OK 1 +#define PWR_FAIL (-1) +#define PWR_SUSPENDREQUEST 1 +#define PWR_SUSPENDRESUME 2 +#define PWR_CRITICALRESUME 3 + +#define WM_COPYDATA 0x004A +#define WM_CANCELJOURNAL 0x004B + + typedef struct tagCOPYDATASTRUCT { + ULONG_PTR dwData; + DWORD cbData; + PVOID lpData; + } COPYDATASTRUCT,*PCOPYDATASTRUCT; + + typedef struct tagMDINEXTMENU { + HMENU hmenuIn; + HMENU hmenuNext; + HWND hwndNext; + } MDINEXTMENU,*PMDINEXTMENU,*LPMDINEXTMENU; + +#define WM_NOTIFY 0x004E +#define WM_INPUTLANGCHANGEREQUEST 0x0050 +#define WM_INPUTLANGCHANGE 0x0051 +#define WM_TCARD 0x0052 +#define WM_HELP 0x0053 +#define WM_USERCHANGED 0x0054 +#define WM_NOTIFYFORMAT 0x0055 + +#define NFR_ANSI 1 +#define NFR_UNICODE 2 +#define NF_QUERY 3 +#define NF_REQUERY 4 + +#define WM_CONTEXTMENU 0x007B +#define WM_STYLECHANGING 0x007C +#define WM_STYLECHANGED 0x007D +#define WM_DISPLAYCHANGE 0x007E +#define WM_GETICON 0x007F +#define WM_SETICON 0x0080 + +#define WM_NCCREATE 0x0081 +#define WM_NCDESTROY 0x0082 +#define WM_NCCALCSIZE 0x0083 +#define WM_NCHITTEST 0x0084 +#define WM_NCPAINT 0x0085 +#define WM_NCACTIVATE 0x0086 +#define WM_GETDLGCODE 0x0087 +#ifndef _WIN32_WCE +#define WM_SYNCPAINT 0x0088 +#endif +#define WM_NCMOUSEMOVE 0x00A0 +#define WM_NCLBUTTONDOWN 0x00A1 +#define WM_NCLBUTTONUP 0x00A2 +#define WM_NCLBUTTONDBLCLK 0x00A3 +#define WM_NCRBUTTONDOWN 0x00A4 +#define WM_NCRBUTTONUP 0x00A5 +#define WM_NCRBUTTONDBLCLK 0x00A6 +#define WM_NCMBUTTONDOWN 0x00A7 +#define WM_NCMBUTTONUP 0x00A8 +#define WM_NCMBUTTONDBLCLK 0x00A9 + +#define WM_NCXBUTTONDOWN 0x00AB +#define WM_NCXBUTTONUP 0x00AC +#define WM_NCXBUTTONDBLCLK 0x00AD +#define WM_INPUT 0x00FF +#define WM_KEYFIRST 0x0100 +#define WM_KEYDOWN 0x0100 +#define WM_KEYUP 0x0101 +#define WM_CHAR 0x0102 +#define WM_DEADCHAR 0x0103 +#define WM_SYSKEYDOWN 0x0104 +#define WM_SYSKEYUP 0x0105 +#define WM_SYSCHAR 0x0106 +#define WM_SYSDEADCHAR 0x0107 +#define WM_UNICHAR 0x0109 +#define WM_KEYLAST 0x0109 +#define UNICODE_NOCHAR 0xFFFF +#define WM_IME_STARTCOMPOSITION 0x010D +#define WM_IME_ENDCOMPOSITION 0x010E +#define WM_IME_COMPOSITION 0x010F +#define WM_IME_KEYLAST 0x010F +#define WM_INITDIALOG 0x0110 +#define WM_COMMAND 0x0111 +#define WM_SYSCOMMAND 0x0112 +#define WM_TIMER 0x0113 +#define WM_HSCROLL 0x0114 +#define WM_VSCROLL 0x0115 +#define WM_INITMENU 0x0116 +#define WM_INITMENUPOPUP 0x0117 +#define WM_MENUSELECT 0x011F +#define WM_MENUCHAR 0x0120 +#define WM_ENTERIDLE 0x0121 +#ifndef _WIN32_WCE +#define WM_MENURBUTTONUP 0x0122 +#define WM_MENUDRAG 0x0123 +#define WM_MENUGETOBJECT 0x0124 +#define WM_UNINITMENUPOPUP 0x0125 +#define WM_MENUCOMMAND 0x0126 + +#ifndef _WIN32_WCE +#define WM_CHANGEUISTATE 0x0127 +#define WM_UPDATEUISTATE 0x0128 +#define WM_QUERYUISTATE 0x0129 + +#define UIS_SET 1 +#define UIS_CLEAR 2 +#define UIS_INITIALIZE 3 + +#define UISF_HIDEFOCUS 0x1 +#define UISF_HIDEACCEL 0x2 +#define UISF_ACTIVE 0x4 +#endif +#endif + +#define WM_CTLCOLORMSGBOX 0x0132 +#define WM_CTLCOLOREDIT 0x0133 +#define WM_CTLCOLORLISTBOX 0x0134 +#define WM_CTLCOLORBTN 0x0135 +#define WM_CTLCOLORDLG 0x0136 +#define WM_CTLCOLORSCROLLBAR 0x0137 +#define WM_CTLCOLORSTATIC 0x0138 +#define MN_GETHMENU 0x01E1 + +#define WM_MOUSEFIRST 0x0200 +#define WM_MOUSEMOVE 0x0200 +#define WM_LBUTTONDOWN 0x0201 +#define WM_LBUTTONUP 0x0202 +#define WM_LBUTTONDBLCLK 0x0203 +#define WM_RBUTTONDOWN 0x0204 +#define WM_RBUTTONUP 0x0205 +#define WM_RBUTTONDBLCLK 0x0206 +#define WM_MBUTTONDOWN 0x0207 +#define WM_MBUTTONUP 0x0208 +#define WM_MBUTTONDBLCLK 0x0209 +#define WM_MOUSEWHEEL 0x020A +#define WM_XBUTTONDOWN 0x020B +#define WM_XBUTTONUP 0x020C +#define WM_XBUTTONDBLCLK 0x020D +#define WM_MOUSELAST 0x020D + +#define WHEEL_DELTA 120 +#define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) + +#define WHEEL_PAGESCROLL (UINT_MAX) + +#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam)) +#define GET_NCHITTEST_WPARAM(wParam) ((short)LOWORD(wParam)) +#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) + +#define XBUTTON1 0x0001 +#define XBUTTON2 0x0002 + +#define WM_PARENTNOTIFY 0x0210 +#define WM_ENTERMENULOOP 0x0211 +#define WM_EXITMENULOOP 0x0212 + +#define WM_NEXTMENU 0x0213 +#define WM_SIZING 0x0214 +#define WM_CAPTURECHANGED 0x0215 +#define WM_MOVING 0x0216 + +#define WM_POWERBROADCAST 0x0218 + +#ifndef _WIN32_WCE +#define PBT_APMQUERYSUSPEND 0x0000 +#define PBT_APMQUERYSTANDBY 0x0001 + +#define PBT_APMQUERYSUSPENDFAILED 0x0002 +#define PBT_APMQUERYSTANDBYFAILED 0x0003 + +#define PBT_APMSUSPEND 0x0004 +#define PBT_APMSTANDBY 0x0005 + +#define PBT_APMRESUMECRITICAL 0x0006 +#define PBT_APMRESUMESUSPEND 0x0007 +#define PBT_APMRESUMESTANDBY 0x0008 + +#define PBTF_APMRESUMEFROMFAILURE 0x00000001 + +#define PBT_APMBATTERYLOW 0x0009 +#define PBT_APMPOWERSTATUSCHANGE 0x000A + +#define PBT_APMOEMEVENT 0x000B +#define PBT_APMRESUMEAUTOMATIC 0x0012 +#endif + +#define WM_DEVICECHANGE 0x0219 + +#define WM_MDICREATE 0x0220 +#define WM_MDIDESTROY 0x0221 +#define WM_MDIACTIVATE 0x0222 +#define WM_MDIRESTORE 0x0223 +#define WM_MDINEXT 0x0224 +#define WM_MDIMAXIMIZE 0x0225 +#define WM_MDITILE 0x0226 +#define WM_MDICASCADE 0x0227 +#define WM_MDIICONARRANGE 0x0228 +#define WM_MDIGETACTIVE 0x0229 + +#define WM_MDISETMENU 0x0230 +#define WM_ENTERSIZEMOVE 0x0231 +#define WM_EXITSIZEMOVE 0x0232 +#define WM_DROPFILES 0x0233 +#define WM_MDIREFRESHMENU 0x0234 + +#define WM_IME_SETCONTEXT 0x0281 +#define WM_IME_NOTIFY 0x0282 +#define WM_IME_CONTROL 0x0283 +#define WM_IME_COMPOSITIONFULL 0x0284 +#define WM_IME_SELECT 0x0285 +#define WM_IME_CHAR 0x0286 +#define WM_IME_REQUEST 0x0288 +#define WM_IME_KEYDOWN 0x0290 +#define WM_IME_KEYUP 0x0291 + +#define WM_MOUSEHOVER 0x02A1 +#define WM_MOUSELEAVE 0x02A3 +#define WM_NCMOUSEHOVER 0x02A0 +#define WM_NCMOUSELEAVE 0x02A2 +#define WM_WTSSESSION_CHANGE 0x02B1 +#define WM_TABLET_FIRST 0x02c0 +#define WM_TABLET_LAST 0x02df +#define WM_CUT 0x0300 +#define WM_COPY 0x0301 +#define WM_PASTE 0x0302 +#define WM_CLEAR 0x0303 +#define WM_UNDO 0x0304 +#define WM_RENDERFORMAT 0x0305 +#define WM_RENDERALLFORMATS 0x0306 +#define WM_DESTROYCLIPBOARD 0x0307 +#define WM_DRAWCLIPBOARD 0x0308 +#define WM_PAINTCLIPBOARD 0x0309 +#define WM_VSCROLLCLIPBOARD 0x030A +#define WM_SIZECLIPBOARD 0x030B +#define WM_ASKCBFORMATNAME 0x030C +#define WM_CHANGECBCHAIN 0x030D +#define WM_HSCROLLCLIPBOARD 0x030E +#define WM_QUERYNEWPALETTE 0x030F +#define WM_PALETTEISCHANGING 0x0310 +#define WM_PALETTECHANGED 0x0311 +#define WM_HOTKEY 0x0312 +#define WM_PRINT 0x0317 +#define WM_PRINTCLIENT 0x0318 +#define WM_APPCOMMAND 0x0319 +#define WM_THEMECHANGED 0x031A +#define WM_HANDHELDFIRST 0x0358 +#define WM_HANDHELDLAST 0x035F +#define WM_AFXFIRST 0x0360 +#define WM_AFXLAST 0x037F +#define WM_PENWINFIRST 0x0380 +#define WM_PENWINLAST 0x038F +#define WM_APP 0x8000 +#define WM_USER 0x0400 + +#define WMSZ_LEFT 1 +#define WMSZ_RIGHT 2 +#define WMSZ_TOP 3 +#define WMSZ_TOPLEFT 4 +#define WMSZ_TOPRIGHT 5 +#define WMSZ_BOTTOM 6 +#define WMSZ_BOTTOMLEFT 7 +#define WMSZ_BOTTOMRIGHT 8 + +#ifndef NONCMESSAGES + +#define HTERROR (-2) +#define HTTRANSPARENT (-1) +#define HTNOWHERE 0 +#define HTCLIENT 1 +#define HTCAPTION 2 +#define HTSYSMENU 3 +#define HTGROWBOX 4 +#define HTSIZE HTGROWBOX +#define HTMENU 5 +#define HTHSCROLL 6 +#define HTVSCROLL 7 +#define HTMINBUTTON 8 +#define HTMAXBUTTON 9 +#define HTLEFT 10 +#define HTRIGHT 11 +#define HTTOP 12 +#define HTTOPLEFT 13 +#define HTTOPRIGHT 14 +#define HTBOTTOM 15 +#define HTBOTTOMLEFT 16 +#define HTBOTTOMRIGHT 17 +#define HTBORDER 18 +#define HTREDUCE HTMINBUTTON +#define HTZOOM HTMAXBUTTON +#define HTSIZEFIRST HTLEFT +#define HTSIZELAST HTBOTTOMRIGHT +#define HTOBJECT 19 +#define HTCLOSE 20 +#define HTHELP 21 + +#define SMTO_NORMAL 0x0000 +#define SMTO_BLOCK 0x0001 +#define SMTO_ABORTIFHUNG 0x0002 +#define SMTO_NOTIMEOUTIFNOTHUNG 0x0008 +#endif + +#define MA_ACTIVATE 1 +#define MA_ACTIVATEANDEAT 2 +#define MA_NOACTIVATE 3 +#define MA_NOACTIVATEANDEAT 4 + +#define ICON_SMALL 0 +#define ICON_BIG 1 +#define ICON_SMALL2 2 + +#ifdef UNICODE +#define RegisterWindowMessage RegisterWindowMessageW +#else +#define RegisterWindowMessage RegisterWindowMessageA +#endif + + WINUSERAPI UINT WINAPI RegisterWindowMessageA(LPCSTR lpString); + WINUSERAPI UINT WINAPI RegisterWindowMessageW(LPCWSTR lpString); + +#define SIZE_RESTORED 0 +#define SIZE_MINIMIZED 1 +#define SIZE_MAXIMIZED 2 +#define SIZE_MAXSHOW 3 +#define SIZE_MAXHIDE 4 + +#define SIZENORMAL SIZE_RESTORED +#define SIZEICONIC SIZE_MINIMIZED +#define SIZEFULLSCREEN SIZE_MAXIMIZED +#define SIZEZOOMSHOW SIZE_MAXSHOW +#define SIZEZOOMHIDE SIZE_MAXHIDE + + typedef struct tagWINDOWPOS { + HWND hwnd; + HWND hwndInsertAfter; + int x; + int y; + int cx; + int cy; + UINT flags; + } WINDOWPOS,*LPWINDOWPOS,*PWINDOWPOS; + + typedef struct tagNCCALCSIZE_PARAMS { + RECT rgrc[3]; + PWINDOWPOS lppos; + } NCCALCSIZE_PARAMS,*LPNCCALCSIZE_PARAMS; + +#define WVR_ALIGNTOP 0x0010 +#define WVR_ALIGNLEFT 0x0020 +#define WVR_ALIGNBOTTOM 0x0040 +#define WVR_ALIGNRIGHT 0x0080 +#define WVR_HREDRAW 0x0100 +#define WVR_VREDRAW 0x0200 +#define WVR_REDRAW (WVR_HREDRAW | WVR_VREDRAW) +#define WVR_VALIDRECTS 0x0400 + +#ifndef NOKEYSTATES + +#define MK_LBUTTON 0x0001 +#define MK_RBUTTON 0x0002 +#define MK_SHIFT 0x0004 +#define MK_CONTROL 0x0008 +#define MK_MBUTTON 0x0010 +#define MK_XBUTTON1 0x0020 +#define MK_XBUTTON2 0x0040 +#endif + +#ifndef NOTRACKMOUSEEVENT +#define TME_HOVER 0x00000001 +#define TME_LEAVE 0x00000002 +#define TME_NONCLIENT 0x00000010 +#define TME_QUERY 0x40000000 +#define TME_CANCEL 0x80000000 + +#define HOVER_DEFAULT 0xFFFFFFFF +#endif + + typedef struct tagTRACKMOUSEEVENT { + DWORD cbSize; + DWORD dwFlags; + HWND hwndTrack; + DWORD dwHoverTime; + } TRACKMOUSEEVENT,*LPTRACKMOUSEEVENT; + + WINUSERAPI WINBOOL WINAPI TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack); +#endif + +#ifndef NOWINSTYLES + +#define WS_OVERLAPPED 0x00000000L +#define WS_POPUP 0x80000000L +#define WS_CHILD 0x40000000L +#define WS_MINIMIZE 0x20000000L +#define WS_VISIBLE 0x10000000L +#define WS_DISABLED 0x08000000L +#define WS_CLIPSIBLINGS 0x04000000L +#define WS_CLIPCHILDREN 0x02000000L +#define WS_MAXIMIZE 0x01000000L +#define WS_CAPTION 0x00C00000L +#define WS_BORDER 0x00800000L +#define WS_DLGFRAME 0x00400000L +#define WS_VSCROLL 0x00200000L +#define WS_HSCROLL 0x00100000L +#define WS_SYSMENU 0x00080000L +#define WS_THICKFRAME 0x00040000L +#define WS_GROUP 0x00020000L +#define WS_TABSTOP 0x00010000L +#define WS_MINIMIZEBOX 0x00020000L +#define WS_MAXIMIZEBOX 0x00010000L +#define WS_TILED WS_OVERLAPPED +#define WS_ICONIC WS_MINIMIZE +#define WS_SIZEBOX WS_THICKFRAME +#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW +#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) +#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU) +#define WS_CHILDWINDOW (WS_CHILD) + +#define WS_EX_DLGMODALFRAME 0x00000001L +#define WS_EX_NOPARENTNOTIFY 0x00000004L +#define WS_EX_TOPMOST 0x00000008L +#define WS_EX_ACCEPTFILES 0x00000010L +#define WS_EX_TRANSPARENT 0x00000020L +#define WS_EX_MDICHILD 0x00000040L +#define WS_EX_TOOLWINDOW 0x00000080L +#define WS_EX_WINDOWEDGE 0x00000100L +#define WS_EX_CLIENTEDGE 0x00000200L +#define WS_EX_CONTEXTHELP 0x00000400L +#define WS_EX_RIGHT 0x00001000L +#define WS_EX_LEFT 0x00000000L +#define WS_EX_RTLREADING 0x00002000L +#define WS_EX_LTRREADING 0x00000000L +#define WS_EX_LEFTSCROLLBAR 0x00004000L +#define WS_EX_RIGHTSCROLLBAR 0x00000000L +#define WS_EX_CONTROLPARENT 0x00010000L +#define WS_EX_STATICEDGE 0x00020000L +#define WS_EX_APPWINDOW 0x00040000L +#define WS_EX_OVERLAPPEDWINDOW (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE) +#define WS_EX_PALETTEWINDOW (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST) +#define WS_EX_LAYERED 0x00080000 +#define WS_EX_NOINHERITLAYOUT 0x00100000L +#define WS_EX_LAYOUTRTL 0x00400000L +#define WS_EX_COMPOSITED 0x02000000L +#define WS_EX_NOACTIVATE 0x08000000L + +#define CS_VREDRAW 0x0001 +#define CS_HREDRAW 0x0002 +#define CS_DBLCLKS 0x0008 +#define CS_OWNDC 0x0020 +#define CS_CLASSDC 0x0040 +#define CS_PARENTDC 0x0080 +#define CS_NOCLOSE 0x0200 +#define CS_SAVEBITS 0x0800 +#define CS_BYTEALIGNCLIENT 0x1000 +#define CS_BYTEALIGNWINDOW 0x2000 +#define CS_GLOBALCLASS 0x4000 +#define CS_IME 0x00010000 +#define CS_DROPSHADOW 0x00020000 +#endif + +#define PRF_CHECKVISIBLE 0x00000001L +#define PRF_NONCLIENT 0x00000002L +#define PRF_CLIENT 0x00000004L +#define PRF_ERASEBKGND 0x00000008L +#define PRF_CHILDREN 0x00000010L +#define PRF_OWNED 0x00000020L + +#define BDR_RAISEDOUTER 0x0001 +#define BDR_SUNKENOUTER 0x0002 +#define BDR_RAISEDINNER 0x0004 +#define BDR_SUNKENINNER 0x0008 + +#define BDR_OUTER (BDR_RAISEDOUTER | BDR_SUNKENOUTER) +#define BDR_INNER (BDR_RAISEDINNER | BDR_SUNKENINNER) +#define BDR_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) +#define BDR_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) + +#define EDGE_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) +#define EDGE_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) +#define EDGE_ETCHED (BDR_SUNKENOUTER | BDR_RAISEDINNER) +#define EDGE_BUMP (BDR_RAISEDOUTER | BDR_SUNKENINNER) + +#define BF_LEFT 0x0001 +#define BF_TOP 0x0002 +#define BF_RIGHT 0x0004 +#define BF_BOTTOM 0x0008 + +#define BF_TOPLEFT (BF_TOP | BF_LEFT) +#define BF_TOPRIGHT (BF_TOP | BF_RIGHT) +#define BF_BOTTOMLEFT (BF_BOTTOM | BF_LEFT) +#define BF_BOTTOMRIGHT (BF_BOTTOM | BF_RIGHT) +#define BF_RECT (BF_LEFT | BF_TOP | BF_RIGHT | BF_BOTTOM) + +#define BF_DIAGONAL 0x0010 + +#define BF_DIAGONAL_ENDTOPRIGHT (BF_DIAGONAL | BF_TOP | BF_RIGHT) +#define BF_DIAGONAL_ENDTOPLEFT (BF_DIAGONAL | BF_TOP | BF_LEFT) +#define BF_DIAGONAL_ENDBOTTOMLEFT (BF_DIAGONAL | BF_BOTTOM | BF_LEFT) +#define BF_DIAGONAL_ENDBOTTOMRIGHT (BF_DIAGONAL | BF_BOTTOM | BF_RIGHT) + +#define BF_MIDDLE 0x0800 +#define BF_SOFT 0x1000 +#define BF_ADJUST 0x2000 +#define BF_FLAT 0x4000 +#define BF_MONO 0x8000 + + WINUSERAPI WINBOOL WINAPI DrawEdge(HDC hdc,LPRECT qrc,UINT edge,UINT grfFlags); + +#define DFC_CAPTION 1 +#define DFC_MENU 2 +#define DFC_SCROLL 3 +#define DFC_BUTTON 4 +#define DFC_POPUPMENU 5 + +#define DFCS_CAPTIONCLOSE 0x0000 +#define DFCS_CAPTIONMIN 0x0001 +#define DFCS_CAPTIONMAX 0x0002 +#define DFCS_CAPTIONRESTORE 0x0003 +#define DFCS_CAPTIONHELP 0x0004 + +#define DFCS_MENUARROW 0x0000 +#define DFCS_MENUCHECK 0x0001 +#define DFCS_MENUBULLET 0x0002 +#define DFCS_MENUARROWRIGHT 0x0004 +#define DFCS_SCROLLUP 0x0000 +#define DFCS_SCROLLDOWN 0x0001 +#define DFCS_SCROLLLEFT 0x0002 +#define DFCS_SCROLLRIGHT 0x0003 +#define DFCS_SCROLLCOMBOBOX 0x0005 +#define DFCS_SCROLLSIZEGRIP 0x0008 +#define DFCS_SCROLLSIZEGRIPRIGHT 0x0010 + +#define DFCS_BUTTONCHECK 0x0000 +#define DFCS_BUTTONRADIOIMAGE 0x0001 +#define DFCS_BUTTONRADIOMASK 0x0002 +#define DFCS_BUTTONRADIO 0x0004 +#define DFCS_BUTTON3STATE 0x0008 +#define DFCS_BUTTONPUSH 0x0010 + +#define DFCS_INACTIVE 0x0100 +#define DFCS_PUSHED 0x0200 +#define DFCS_CHECKED 0x0400 + +#define DFCS_TRANSPARENT 0x0800 +#define DFCS_HOT 0x1000 + +#define DFCS_ADJUSTRECT 0x2000 +#define DFCS_FLAT 0x4000 +#define DFCS_MONO 0x8000 + + WINUSERAPI WINBOOL WINAPI DrawFrameControl(HDC,LPRECT,UINT,UINT); + +#define DC_ACTIVE 0x0001 +#define DC_SMALLCAP 0x0002 +#define DC_ICON 0x0004 +#define DC_TEXT 0x0008 +#define DC_INBUTTON 0x0010 +#define DC_GRADIENT 0x0020 +#define DC_BUTTONS 0x1000 + + WINUSERAPI WINBOOL WINAPI DrawCaption(HWND hwnd,HDC hdc,CONST RECT *lprect,UINT flags); + +#define IDANI_OPEN 1 +#define IDANI_CAPTION 3 + + WINUSERAPI WINBOOL WINAPI DrawAnimatedRects(HWND hwnd,int idAni,CONST RECT *lprcFrom,CONST RECT *lprcTo); + +#ifndef NOCLIPBOARD + +#define CF_TEXT 1 +#define CF_BITMAP 2 +#define CF_METAFILEPICT 3 +#define CF_SYLK 4 +#define CF_DIF 5 +#define CF_TIFF 6 +#define CF_OEMTEXT 7 +#define CF_DIB 8 +#define CF_PALETTE 9 +#define CF_PENDATA 10 +#define CF_RIFF 11 +#define CF_WAVE 12 +#define CF_UNICODETEXT 13 +#define CF_ENHMETAFILE 14 +#define CF_HDROP 15 +#define CF_LOCALE 16 +#define CF_DIBV5 17 +#define CF_MAX 18 + +#define CF_OWNERDISPLAY 0x0080 +#define CF_DSPTEXT 0x0081 +#define CF_DSPBITMAP 0x0082 +#define CF_DSPMETAFILEPICT 0x0083 +#define CF_DSPENHMETAFILE 0x008E + +#define CF_PRIVATEFIRST 0x0200 +#define CF_PRIVATELAST 0x02FF + +#define CF_GDIOBJFIRST 0x0300 +#define CF_GDIOBJLAST 0x03FF +#endif + +#define FVIRTKEY TRUE +#define FNOINVERT 0x02 +#define FSHIFT 0x04 +#define FCONTROL 0x08 +#define FALT 0x10 + + typedef struct tagACCEL { + BYTE fVirt; + WORD key; + WORD cmd; + } ACCEL,*LPACCEL; + + typedef struct tagPAINTSTRUCT { + HDC hdc; + WINBOOL fErase; + RECT rcPaint; + WINBOOL fRestore; + WINBOOL fIncUpdate; + BYTE rgbReserved[32]; + } PAINTSTRUCT,*PPAINTSTRUCT,*NPPAINTSTRUCT,*LPPAINTSTRUCT; + + typedef struct tagCREATESTRUCTA { + LPVOID lpCreateParams; + HINSTANCE hInstance; + HMENU hMenu; + HWND hwndParent; + int cy; + int cx; + int y; + int x; + LONG style; + LPCSTR lpszName; + LPCSTR lpszClass; + DWORD dwExStyle; + } CREATESTRUCTA,*LPCREATESTRUCTA; + + typedef struct tagCREATESTRUCTW { + LPVOID lpCreateParams; + HINSTANCE hInstance; + HMENU hMenu; + HWND hwndParent; + int cy; + int cx; + int y; + int x; + LONG style; + LPCWSTR lpszName; + LPCWSTR lpszClass; + DWORD dwExStyle; + } CREATESTRUCTW,*LPCREATESTRUCTW; + +#ifdef UNICODE + typedef CREATESTRUCTW CREATESTRUCT; + typedef LPCREATESTRUCTW LPCREATESTRUCT; +#else + typedef CREATESTRUCTA CREATESTRUCT; + typedef LPCREATESTRUCTA LPCREATESTRUCT; +#endif + + typedef struct tagWINDOWPLACEMENT { + UINT length; + UINT flags; + UINT showCmd; + POINT ptMinPosition; + POINT ptMaxPosition; + RECT rcNormalPosition; + } WINDOWPLACEMENT; + typedef WINDOWPLACEMENT *PWINDOWPLACEMENT,*LPWINDOWPLACEMENT; + +#define WPF_SETMINPOSITION 0x0001 +#define WPF_RESTORETOMAXIMIZED 0x0002 +#define WPF_ASYNCWINDOWPLACEMENT 0x0004 + + typedef struct tagNMHDR { + HWND hwndFrom; + UINT_PTR idFrom; + UINT code; + } NMHDR; + + typedef NMHDR *LPNMHDR; + + typedef struct tagSTYLESTRUCT { + DWORD styleOld; + DWORD styleNew; + } STYLESTRUCT,*LPSTYLESTRUCT; + +#define ODT_MENU 1 +#define ODT_LISTBOX 2 +#define ODT_COMBOBOX 3 +#define ODT_BUTTON 4 +#define ODT_STATIC 5 + +#define ODA_DRAWENTIRE 0x0001 +#define ODA_SELECT 0x0002 +#define ODA_FOCUS 0x0004 + +#define ODS_SELECTED 0x0001 +#define ODS_GRAYED 0x0002 +#define ODS_DISABLED 0x0004 +#define ODS_CHECKED 0x0008 +#define ODS_FOCUS 0x0010 +#define ODS_DEFAULT 0x0020 +#define ODS_COMBOBOXEDIT 0x1000 +#define ODS_HOTLIGHT 0x0040 +#define ODS_INACTIVE 0x0080 +#define ODS_NOACCEL 0x0100 +#define ODS_NOFOCUSRECT 0x0200 + + typedef struct tagMEASUREITEMSTRUCT { + UINT CtlType; + UINT CtlID; + UINT itemID; + UINT itemWidth; + UINT itemHeight; + ULONG_PTR itemData; + } MEASUREITEMSTRUCT,*PMEASUREITEMSTRUCT,*LPMEASUREITEMSTRUCT; + + typedef struct tagDRAWITEMSTRUCT { + UINT CtlType; + UINT CtlID; + UINT itemID; + UINT itemAction; + UINT itemState; + HWND hwndItem; + HDC hDC; + RECT rcItem; + ULONG_PTR itemData; + } DRAWITEMSTRUCT,*PDRAWITEMSTRUCT,*LPDRAWITEMSTRUCT; + + typedef struct tagDELETEITEMSTRUCT { + UINT CtlType; + UINT CtlID; + UINT itemID; + HWND hwndItem; + ULONG_PTR itemData; + } DELETEITEMSTRUCT,*PDELETEITEMSTRUCT,*LPDELETEITEMSTRUCT; + + typedef struct tagCOMPAREITEMSTRUCT { + UINT CtlType; + UINT CtlID; + HWND hwndItem; + UINT itemID1; + ULONG_PTR itemData1; + UINT itemID2; + ULONG_PTR itemData2; + DWORD dwLocaleId; + } COMPAREITEMSTRUCT,*PCOMPAREITEMSTRUCT,*LPCOMPAREITEMSTRUCT; + +#ifndef NOMSG +#ifdef UNICODE +#define GetMessage GetMessageW +#define DispatchMessage DispatchMessageW +#define PeekMessage PeekMessageW +#else +#define GetMessage GetMessageA +#define DispatchMessage DispatchMessageA +#define PeekMessage PeekMessageA +#endif + + WINUSERAPI WINBOOL WINAPI GetMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); + WINUSERAPI WINBOOL WINAPI GetMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); + WINUSERAPI WINBOOL WINAPI TranslateMessage(CONST MSG *lpMsg); + WINUSERAPI LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg); + WINUSERAPI LRESULT WINAPI DispatchMessageW(CONST MSG *lpMsg); + WINUSERAPI WINBOOL WINAPI SetMessageQueue(int cMessagesMax); + WINUSERAPI WINBOOL WINAPI PeekMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); + WINUSERAPI WINBOOL WINAPI PeekMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); + +#define PM_NOREMOVE 0x0000 +#define PM_REMOVE 0x0001 +#define PM_NOYIELD 0x0002 +#define PM_QS_INPUT (QS_INPUT << 16) +#define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16) +#define PM_QS_PAINT (QS_PAINT << 16) +#define PM_QS_SENDMESSAGE (QS_SENDMESSAGE << 16) +#endif + + WINUSERAPI WINBOOL WINAPI RegisterHotKey(HWND hWnd,int id,UINT fsModifiers,UINT vk); + WINUSERAPI WINBOOL WINAPI UnregisterHotKey(HWND hWnd,int id); + +#define MOD_ALT 0x0001 +#define MOD_CONTROL 0x0002 +#define MOD_SHIFT 0x0004 +#define MOD_WIN 0x0008 + +#define IDHOT_SNAPWINDOW (-1) +#define IDHOT_SNAPDESKTOP (-2) + +#ifdef WIN_INTERNAL +#ifndef LSTRING +#define NOLSTRING +#endif +#ifndef LFILEIO +#define NOLFILEIO +#endif +#endif + +#define ENDSESSION_LOGOFF 0x80000000 + +#define EWX_LOGOFF 0 +#define EWX_SHUTDOWN 0x00000001 +#define EWX_REBOOT 0x00000002 +#define EWX_FORCE 0x00000004 +#define EWX_POWEROFF 0x00000008 +#define EWX_FORCEIFHUNG 0x00000010 + +#define ExitWindows(dwReserved,Code) ExitWindowsEx(EWX_LOGOFF,0xFFFFFFFF) + +#ifdef UNICODE +#define SendMessage SendMessageW +#define SendMessageTimeout SendMessageTimeoutW +#define SendNotifyMessage SendNotifyMessageW +#define SendMessageCallback SendMessageCallbackW +#else +#define SendMessage SendMessageA +#define SendMessageTimeout SendMessageTimeoutA +#define SendNotifyMessage SendNotifyMessageA +#define SendMessageCallback SendMessageCallbackA +#endif + + WINUSERAPI WINBOOL WINAPI ExitWindowsEx(UINT uFlags,DWORD dwReason); + WINUSERAPI WINBOOL WINAPI SwapMouseButton(WINBOOL fSwap); + WINUSERAPI DWORD WINAPI GetMessagePos(VOID); + WINUSERAPI LONG WINAPI GetMessageTime(VOID); + WINUSERAPI LPARAM WINAPI GetMessageExtraInfo(VOID); + WINUSERAPI WINBOOL WINAPI IsWow64Message(VOID); + WINUSERAPI LPARAM WINAPI SetMessageExtraInfo(LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendMessageTimeoutA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); + WINUSERAPI LRESULT WINAPI SendMessageTimeoutW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); + WINUSERAPI WINBOOL WINAPI SendNotifyMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI SendNotifyMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI SendMessageCallbackA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); + WINUSERAPI WINBOOL WINAPI SendMessageCallbackW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); + + typedef struct { + UINT cbSize; + HDESK hdesk; + HWND hwnd; + LUID luid; + } BSMINFO,*PBSMINFO; + +#ifdef UNICODE +#define BroadcastSystemMessageEx BroadcastSystemMessageExW +#define BroadcastSystemMessage BroadcastSystemMessageW +#else +#define BroadcastSystemMessageEx BroadcastSystemMessageExA +#define BroadcastSystemMessage BroadcastSystemMessageA +#endif + + WINUSERAPI long WINAPI BroadcastSystemMessageExA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); + WINUSERAPI long WINAPI BroadcastSystemMessageExW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); + WINUSERAPI long WINAPI BroadcastSystemMessageA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI long WINAPI BroadcastSystemMessageW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); + +#define BSM_ALLCOMPONENTS 0x00000000 +#define BSM_VXDS 0x00000001 +#define BSM_NETDRIVER 0x00000002 +#define BSM_INSTALLABLEDRIVERS 0x00000004 +#define BSM_APPLICATIONS 0x00000008 +#define BSM_ALLDESKTOPS 0x00000010 + +#define BSF_QUERY 0x00000001 +#define BSF_IGNORECURRENTTASK 0x00000002 +#define BSF_FLUSHDISK 0x00000004 +#define BSF_NOHANG 0x00000008 +#define BSF_POSTMESSAGE 0x00000010 +#define BSF_FORCEIFHUNG 0x00000020 +#define BSF_NOTIMEOUTIFNOTHUNG 0x00000040 +#define BSF_ALLOWSFW 0x00000080 +#define BSF_SENDNOTIFYMESSAGE 0x00000100 +#define BSF_RETURNHDESK 0x00000200 +#define BSF_LUID 0x00000400 + +#define BROADCAST_QUERY_DENY 0x424D5144 + + typedef PVOID HDEVNOTIFY; + typedef HDEVNOTIFY *PHDEVNOTIFY; + +#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000 +#define DEVICE_NOTIFY_SERVICE_HANDLE 0x00000001 +#define DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 0x00000004 + +#ifdef UNICODE +#define RegisterDeviceNotification RegisterDeviceNotificationW +#define PostMessage PostMessageW +#define PostThreadMessage PostThreadMessageW +#define PostAppMessage PostAppMessageW +#define DefWindowProc DefWindowProcW +#define CallWindowProc CallWindowProcW +#define RegisterClass RegisterClassW +#define UnregisterClass UnregisterClassW +#define GetClassInfo GetClassInfoW +#define RegisterClassEx RegisterClassExW +#define GetClassInfoEx GetClassInfoExW +#else +#define RegisterDeviceNotification RegisterDeviceNotificationA +#define PostMessage PostMessageA +#define PostThreadMessage PostThreadMessageA +#define PostAppMessage PostAppMessageA +#define DefWindowProc DefWindowProcA +#define CallWindowProc CallWindowProcA +#define RegisterClass RegisterClassA +#define UnregisterClass UnregisterClassA +#define GetClassInfo GetClassInfoA +#define RegisterClassEx RegisterClassExA +#define GetClassInfoEx GetClassInfoExA +#endif + + WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); + WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationW(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); + WINUSERAPI WINBOOL WINAPI UnregisterDeviceNotification(HDEVNOTIFY Handle); + WINUSERAPI WINBOOL WINAPI PostMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI PostMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI PostThreadMessageA(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI PostThreadMessageW(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); +#define PostAppMessageA(idThread,wMsg,wParam,lParam) PostThreadMessageA((DWORD)idThread,wMsg,wParam,lParam) +#define PostAppMessageW(idThread,wMsg,wParam,lParam) PostThreadMessageW((DWORD)idThread,wMsg,wParam,lParam) + +#define HWND_BROADCAST ((HWND)0xffff) +#define HWND_MESSAGE ((HWND)-3) + + WINUSERAPI WINBOOL WINAPI AttachThreadInput(DWORD idAttach,DWORD idAttachTo,WINBOOL fAttach); + WINUSERAPI WINBOOL WINAPI ReplyMessage(LRESULT lResult); + WINUSERAPI WINBOOL WINAPI WaitMessage(VOID); + WINUSERAPI DWORD WINAPI WaitForInputIdle(HANDLE hProcess,DWORD dwMilliseconds); + WINUSERAPI LRESULT WINAPI DefWindowProcA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefWindowProcW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI VOID WINAPI PostQuitMessage(int nExitCode); + WINUSERAPI LRESULT WINAPI CallWindowProcA(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI CallWindowProcW(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI InSendMessage(VOID); + WINUSERAPI DWORD WINAPI InSendMessageEx(LPVOID lpReserved); + +#define ISMEX_NOSEND 0x00000000 +#define ISMEX_SEND 0x00000001 +#define ISMEX_NOTIFY 0x00000002 +#define ISMEX_CALLBACK 0x00000004 +#define ISMEX_REPLIED 0x00000008 + + WINUSERAPI UINT WINAPI GetDoubleClickTime(VOID); + WINUSERAPI WINBOOL WINAPI SetDoubleClickTime(UINT); + WINUSERAPI ATOM WINAPI RegisterClassA(CONST WNDCLASSA *lpWndClass); + WINUSERAPI ATOM WINAPI RegisterClassW(CONST WNDCLASSW *lpWndClass); + WINUSERAPI WINBOOL WINAPI UnregisterClassA(LPCSTR lpClassName,HINSTANCE hInstance); + WINUSERAPI WINBOOL WINAPI UnregisterClassW(LPCWSTR lpClassName,HINSTANCE hInstance); + WINUSERAPI WINBOOL WINAPI GetClassInfoA(HINSTANCE hInstance,LPCSTR lpClassName,LPWNDCLASSA lpWndClass); + WINUSERAPI WINBOOL WINAPI GetClassInfoW(HINSTANCE hInstance,LPCWSTR lpClassName,LPWNDCLASSW lpWndClass); + WINUSERAPI ATOM WINAPI RegisterClassExA(CONST WNDCLASSEXA *); + WINUSERAPI ATOM WINAPI RegisterClassExW(CONST WNDCLASSEXW *); + WINUSERAPI WINBOOL WINAPI GetClassInfoExA(HINSTANCE hInstance,LPCSTR lpszClass,LPWNDCLASSEXA lpwcx); + WINUSERAPI WINBOOL WINAPI GetClassInfoExW(HINSTANCE hInstance,LPCWSTR lpszClass,LPWNDCLASSEXW lpwcx); + +#define CW_USEDEFAULT ((int)0x80000000) + +#define HWND_DESKTOP ((HWND)0) + + typedef BOOLEAN (WINAPI *PREGISTERCLASSNAMEW)(LPCWSTR); + +#ifdef UNICODE +#define CreateWindowEx CreateWindowExW +#define CreateWindow CreateWindowW +#else +#define CreateWindowEx CreateWindowExA +#define CreateWindow CreateWindowA +#endif + + WINUSERAPI HWND WINAPI CreateWindowExA(DWORD dwExStyle,LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); + WINUSERAPI HWND WINAPI CreateWindowExW(DWORD dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); +#define CreateWindowA(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExA(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) +#define CreateWindowW(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExW(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) + WINUSERAPI WINBOOL WINAPI IsWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI IsMenu(HMENU hMenu); + WINUSERAPI WINBOOL WINAPI IsChild(HWND hWndParent,HWND hWnd); + WINUSERAPI WINBOOL WINAPI DestroyWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI ShowWindow(HWND hWnd,int nCmdShow); + WINUSERAPI WINBOOL WINAPI AnimateWindow(HWND hWnd,DWORD dwTime,DWORD dwFlags); + +#if defined(_WINGDI_) && !defined(NOGDI) + WINUSERAPI WINBOOL WINAPI UpdateLayeredWindow(HWND hWnd,HDC hdcDst,POINT *pptDst,SIZE *psize,HDC hdcSrc,POINT *pptSrc,COLORREF crKey,BLENDFUNCTION *pblend,DWORD dwFlags); + + typedef struct tagUPDATELAYEREDWINDOWINFO { + DWORD cbSize; + HDC hdcDst; + POINT CONST *pptDst; + SIZE CONST *psize; + HDC hdcSrc; + POINT CONST *pptSrc; + COLORREF crKey; + BLENDFUNCTION CONST *pblend; + DWORD dwFlags; + RECT CONST *prcDirty; + } UPDATELAYEREDWINDOWINFO,*PUPDATELAYEREDWINDOWINFO; + + WINUSERAPI WINBOOL WINAPI UpdateLayeredWindowIndirect(HWND hWnd,UPDATELAYEREDWINDOWINFO CONST *pULWInfo); + WINUSERAPI WINBOOL WINAPI GetLayeredWindowAttributes(HWND hwnd,COLORREF *pcrKey,BYTE *pbAlpha,DWORD *pdwFlags); + +#define PW_CLIENTONLY 0x00000001 + + WINUSERAPI WINBOOL WINAPI PrintWindow(HWND hwnd,HDC hdcBlt,UINT nFlags); + WINUSERAPI WINBOOL WINAPI SetLayeredWindowAttributes(HWND hwnd,COLORREF crKey,BYTE bAlpha,DWORD dwFlags); + +#define LWA_COLORKEY 0x00000001 +#define LWA_ALPHA 0x00000002 + +#define ULW_COLORKEY 0x00000001 +#define ULW_ALPHA 0x00000002 +#define ULW_OPAQUE 0x00000004 + +#define ULW_EX_NORESIZE 0x00000008 + + WINUSERAPI WINBOOL WINAPI ShowWindowAsync(HWND hWnd,int nCmdShow); + WINUSERAPI WINBOOL WINAPI FlashWindow(HWND hWnd,WINBOOL bInvert); + + typedef struct { + UINT cbSize; + HWND hwnd; + DWORD dwFlags; + UINT uCount; + DWORD dwTimeout; + } FLASHWINFO,*PFLASHWINFO; + + WINUSERAPI WINBOOL WINAPI FlashWindowEx(PFLASHWINFO pfwi); + +#define FLASHW_STOP 0 +#define FLASHW_CAPTION 0x00000001 +#define FLASHW_TRAY 0x00000002 +#define FLASHW_ALL (FLASHW_CAPTION | FLASHW_TRAY) +#define FLASHW_TIMER 0x00000004 +#define FLASHW_TIMERNOFG 0x0000000C + + WINUSERAPI WINBOOL WINAPI ShowOwnedPopups(HWND hWnd,WINBOOL fShow); + WINUSERAPI WINBOOL WINAPI OpenIcon(HWND hWnd); + WINUSERAPI WINBOOL WINAPI CloseWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI MoveWindow(HWND hWnd,int X,int Y,int nWidth,int nHeight,WINBOOL bRepaint); + WINUSERAPI WINBOOL WINAPI SetWindowPos(HWND hWnd,HWND hWndInsertAfter,int X,int Y,int cx,int cy,UINT uFlags); + WINUSERAPI WINBOOL WINAPI GetWindowPlacement(HWND hWnd,WINDOWPLACEMENT *lpwndpl); + WINUSERAPI WINBOOL WINAPI SetWindowPlacement(HWND hWnd,CONST WINDOWPLACEMENT *lpwndpl); + +#ifndef NODEFERWINDOWPOS + WINUSERAPI HDWP WINAPI BeginDeferWindowPos(int nNumWindows); + WINUSERAPI HDWP WINAPI DeferWindowPos(HDWP hWinPosInfo,HWND hWnd,HWND hWndInsertAfter,int x,int y,int cx,int cy,UINT uFlags); + WINUSERAPI WINBOOL WINAPI EndDeferWindowPos(HDWP hWinPosInfo); +#endif + + WINUSERAPI WINBOOL WINAPI IsWindowVisible(HWND hWnd); + WINUSERAPI WINBOOL WINAPI IsIconic(HWND hWnd); + WINUSERAPI WINBOOL WINAPI AnyPopup(VOID); + WINUSERAPI WINBOOL WINAPI BringWindowToTop(HWND hWnd); + WINUSERAPI WINBOOL WINAPI IsZoomed(HWND hWnd); + +#define SWP_NOSIZE 0x0001 +#define SWP_NOMOVE 0x0002 +#define SWP_NOZORDER 0x0004 +#define SWP_NOREDRAW 0x0008 +#define SWP_NOACTIVATE 0x0010 +#define SWP_FRAMECHANGED 0x0020 +#define SWP_SHOWWINDOW 0x0040 +#define SWP_HIDEWINDOW 0x0080 +#define SWP_NOCOPYBITS 0x0100 +#define SWP_NOOWNERZORDER 0x0200 +#define SWP_NOSENDCHANGING 0x0400 + +#define SWP_DRAWFRAME SWP_FRAMECHANGED +#define SWP_NOREPOSITION SWP_NOOWNERZORDER +#define SWP_DEFERERASE 0x2000 +#define SWP_ASYNCWINDOWPOS 0x4000 + +#define HWND_TOP ((HWND)0) +#define HWND_BOTTOM ((HWND)1) +#define HWND_TOPMOST ((HWND)-1) +#define HWND_NOTOPMOST ((HWND)-2) + +#ifndef NOCTLMGR + +#include + + typedef struct { + DWORD style; + DWORD dwExtendedStyle; + WORD cdit; + short x; + short y; + short cx; + short cy; + } DLGTEMPLATE; + + typedef DLGTEMPLATE *LPDLGTEMPLATEA; + typedef DLGTEMPLATE *LPDLGTEMPLATEW; + +#ifdef UNICODE + typedef LPDLGTEMPLATEW LPDLGTEMPLATE; +#else + typedef LPDLGTEMPLATEA LPDLGTEMPLATE; +#endif + + typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEA; + typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEW; + +#ifdef UNICODE + typedef LPCDLGTEMPLATEW LPCDLGTEMPLATE; +#else + typedef LPCDLGTEMPLATEA LPCDLGTEMPLATE; +#endif + + typedef struct { + DWORD style; + DWORD dwExtendedStyle; + short x; + short y; + short cx; + short cy; + WORD id; + } DLGITEMTEMPLATE; + + typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEA; + typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEW; + +#ifdef UNICODE + typedef PDLGITEMTEMPLATEW PDLGITEMTEMPLATE; +#else + typedef PDLGITEMTEMPLATEA PDLGITEMTEMPLATE; +#endif + + typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEA; + typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEW; + +#ifdef UNICODE + typedef LPDLGITEMTEMPLATEW LPDLGITEMTEMPLATE; +#else + typedef LPDLGITEMTEMPLATEA LPDLGITEMTEMPLATE; +#endif + +#include + +#ifdef UNICODE +#define CreateDialogParam CreateDialogParamW +#define CreateDialogIndirectParam CreateDialogIndirectParamW +#define CreateDialog CreateDialogW +#define CreateDialogIndirect CreateDialogIndirectW +#define DialogBoxParam DialogBoxParamW +#define DialogBoxIndirectParam DialogBoxIndirectParamW +#define DialogBox DialogBoxW +#define DialogBoxIndirect DialogBoxIndirectW +#define SetDlgItemText SetDlgItemTextW +#define GetDlgItemText GetDlgItemTextW +#define SendDlgItemMessage SendDlgItemMessageW +#define DefDlgProc DefDlgProcW +#else +#define CreateDialogParam CreateDialogParamA +#define CreateDialogIndirectParam CreateDialogIndirectParamA +#define CreateDialog CreateDialogA +#define CreateDialogIndirect CreateDialogIndirectA +#define DialogBoxParam DialogBoxParamA +#define DialogBoxIndirectParam DialogBoxIndirectParamA +#define DialogBox DialogBoxA +#define DialogBoxIndirect DialogBoxIndirectA +#define SetDlgItemText SetDlgItemTextA +#define GetDlgItemText GetDlgItemTextA +#define SendDlgItemMessage SendDlgItemMessageA +#define DefDlgProc DefDlgProcA +#endif + + WINUSERAPI HWND WINAPI CreateDialogParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI HWND WINAPI CreateDialogParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI HWND WINAPI CreateDialogIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI HWND WINAPI CreateDialogIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); +#define CreateDialogA(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamA(hInstance,lpName,hWndParent,lpDialogFunc,0L) +#define CreateDialogW(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamW(hInstance,lpName,hWndParent,lpDialogFunc,0L) +#define CreateDialogIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define CreateDialogIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) + WINUSERAPI INT_PTR WINAPI DialogBoxParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI INT_PTR WINAPI DialogBoxParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); +#define DialogBoxA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define DialogBoxW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define DialogBoxIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define DialogBoxIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) + WINUSERAPI WINBOOL WINAPI EndDialog(HWND hDlg,INT_PTR nResult); + WINUSERAPI HWND WINAPI GetDlgItem(HWND hDlg,int nIDDlgItem); + WINUSERAPI WINBOOL WINAPI SetDlgItemInt(HWND hDlg,int nIDDlgItem,UINT uValue,WINBOOL bSigned); + WINUSERAPI UINT WINAPI GetDlgItemInt(HWND hDlg,int nIDDlgItem,WINBOOL *lpTranslated,WINBOOL bSigned); + WINUSERAPI WINBOOL WINAPI SetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPCSTR lpString); + WINUSERAPI WINBOOL WINAPI SetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPCWSTR lpString); + WINUSERAPI UINT WINAPI GetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPSTR lpString,int cchMax); + WINUSERAPI UINT WINAPI GetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPWSTR lpString,int cchMax); + WINUSERAPI WINBOOL WINAPI CheckDlgButton(HWND hDlg,int nIDButton,UINT uCheck); + WINUSERAPI WINBOOL WINAPI CheckRadioButton(HWND hDlg,int nIDFirstButton,int nIDLastButton,int nIDCheckButton); + WINUSERAPI UINT WINAPI IsDlgButtonChecked(HWND hDlg,int nIDButton); + WINUSERAPI LRESULT WINAPI SendDlgItemMessageA(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendDlgItemMessageW(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI HWND WINAPI GetNextDlgGroupItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); + WINUSERAPI HWND WINAPI GetNextDlgTabItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); + WINUSERAPI int WINAPI GetDlgCtrlID(HWND hWnd); + WINUSERAPI long WINAPI GetDialogBaseUnits(VOID); + WINUSERAPI LRESULT WINAPI DefDlgProcA(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefDlgProcW(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); + +#define DLGWINDOWEXTRA 30 +#endif + +#ifndef NOMSG + +#ifdef UNICODE +#define CallMsgFilter CallMsgFilterW +#else +#define CallMsgFilter CallMsgFilterA +#endif + + WINUSERAPI WINBOOL WINAPI CallMsgFilterA(LPMSG lpMsg,int nCode); + WINUSERAPI WINBOOL WINAPI CallMsgFilterW(LPMSG lpMsg,int nCode); +#endif + +#ifndef NOCLIPBOARD + +#ifdef UNICODE +#define RegisterClipboardFormat RegisterClipboardFormatW +#define GetClipboardFormatName GetClipboardFormatNameW +#else +#define RegisterClipboardFormat RegisterClipboardFormatA +#define GetClipboardFormatName GetClipboardFormatNameA +#endif + + WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner); + WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID); + WINUSERAPI DWORD WINAPI GetClipboardSequenceNumber(VOID); + WINUSERAPI HWND WINAPI GetClipboardOwner(VOID); + WINUSERAPI HWND WINAPI SetClipboardViewer(HWND hWndNewViewer); + WINUSERAPI HWND WINAPI GetClipboardViewer(VOID); + WINUSERAPI WINBOOL WINAPI ChangeClipboardChain(HWND hWndRemove,HWND hWndNewNext); + WINUSERAPI HANDLE WINAPI SetClipboardData(UINT uFormat,HANDLE hMem); + WINUSERAPI HANDLE WINAPI GetClipboardData(UINT uFormat); + WINUSERAPI UINT WINAPI RegisterClipboardFormatA(LPCSTR lpszFormat); + WINUSERAPI UINT WINAPI RegisterClipboardFormatW(LPCWSTR lpszFormat); + WINUSERAPI int WINAPI CountClipboardFormats(VOID); + WINUSERAPI UINT WINAPI EnumClipboardFormats(UINT format); + WINUSERAPI int WINAPI GetClipboardFormatNameA(UINT format,LPSTR lpszFormatName,int cchMaxCount); + WINUSERAPI int WINAPI GetClipboardFormatNameW(UINT format,LPWSTR lpszFormatName,int cchMaxCount); + WINUSERAPI WINBOOL WINAPI EmptyClipboard(VOID); + WINUSERAPI WINBOOL WINAPI IsClipboardFormatAvailable(UINT format); + WINUSERAPI int WINAPI GetPriorityClipboardFormat(UINT *paFormatPriorityList,int cFormats); + WINUSERAPI HWND WINAPI GetOpenClipboardWindow(VOID); +#endif + +#ifdef UNICODE +#define CharToOem CharToOemW +#define OemToChar OemToCharW +#define CharToOemBuff CharToOemBuffW +#define OemToCharBuff OemToCharBuffW +#define CharUpper CharUpperW +#define CharUpperBuff CharUpperBuffW +#define CharLower CharLowerW +#define CharLowerBuff CharLowerBuffW +#define CharNext CharNextW +#define CharPrev CharPrevW +#else +#define CharToOem CharToOemA +#define OemToChar OemToCharA +#define CharToOemBuff CharToOemBuffA +#define OemToCharBuff OemToCharBuffA +#define CharUpper CharUpperA +#define CharUpperBuff CharUpperBuffA +#define CharLower CharLowerA +#define CharLowerBuff CharLowerBuffA +#define CharNext CharNextA +#define CharPrev CharPrevA +#endif + + WINUSERAPI WINBOOL WINAPI CharToOemA(LPCSTR lpszSrc,LPSTR lpszDst); + WINUSERAPI WINBOOL WINAPI CharToOemW(LPCWSTR lpszSrc,LPSTR lpszDst); + WINUSERAPI WINBOOL WINAPI OemToCharA(LPCSTR lpszSrc,LPSTR lpszDst); + WINUSERAPI WINBOOL WINAPI OemToCharW(LPCSTR lpszSrc,LPWSTR lpszDst); + WINUSERAPI WINBOOL WINAPI CharToOemBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); + WINUSERAPI WINBOOL WINAPI CharToOemBuffW(LPCWSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); + WINUSERAPI WINBOOL WINAPI OemToCharBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); + WINUSERAPI WINBOOL WINAPI OemToCharBuffW(LPCSTR lpszSrc,LPWSTR lpszDst,DWORD cchDstLength); + WINUSERAPI LPSTR WINAPI CharUpperA(LPSTR lpsz); + WINUSERAPI LPWSTR WINAPI CharUpperW(LPWSTR lpsz); + WINUSERAPI DWORD WINAPI CharUpperBuffA(LPSTR lpsz,DWORD cchLength); + WINUSERAPI DWORD WINAPI CharUpperBuffW(LPWSTR lpsz,DWORD cchLength); + WINUSERAPI LPSTR WINAPI CharLowerA(LPSTR lpsz); + WINUSERAPI LPWSTR WINAPI CharLowerW(LPWSTR lpsz); + WINUSERAPI DWORD WINAPI CharLowerBuffA(LPSTR lpsz,DWORD cchLength); + WINUSERAPI DWORD WINAPI CharLowerBuffW(LPWSTR lpsz,DWORD cchLength); + WINUSERAPI LPSTR WINAPI CharNextA(LPCSTR lpsz); + WINUSERAPI LPWSTR WINAPI CharNextW(LPCWSTR lpsz); + WINUSERAPI LPSTR WINAPI CharPrevA(LPCSTR lpszStart,LPCSTR lpszCurrent); + WINUSERAPI LPWSTR WINAPI CharPrevW(LPCWSTR lpszStart,LPCWSTR lpszCurrent); + WINUSERAPI LPSTR WINAPI CharNextExA(WORD CodePage,LPCSTR lpCurrentChar,DWORD dwFlags); + WINUSERAPI LPSTR WINAPI CharPrevExA(WORD CodePage,LPCSTR lpStart,LPCSTR lpCurrentChar,DWORD dwFlags); + +#define AnsiToOem CharToOemA +#define OemToAnsi OemToCharA +#define AnsiToOemBuff CharToOemBuffA +#define OemToAnsiBuff OemToCharBuffA +#define AnsiUpper CharUpperA +#define AnsiUpperBuff CharUpperBuffA +#define AnsiLower CharLowerA +#define AnsiLowerBuff CharLowerBuffA +#define AnsiNext CharNextA +#define AnsiPrev CharPrevA + +#ifndef NOLANGUAGE + +#ifdef UNICODE +#define IsCharAlpha IsCharAlphaW +#define IsCharAlphaNumeric IsCharAlphaNumericW +#define IsCharUpper IsCharUpperW +#define IsCharLower IsCharLowerW +#else +#define IsCharAlpha IsCharAlphaA +#define IsCharAlphaNumeric IsCharAlphaNumericA +#define IsCharUpper IsCharUpperA +#define IsCharLower IsCharLowerA +#endif + + WINUSERAPI WINBOOL WINAPI IsCharAlphaA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharAlphaW(WCHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericW(WCHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharUpperA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharUpperW(WCHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharLowerA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharLowerW(WCHAR ch); +#endif + +#ifdef UNICODE +#define GetKeyNameText GetKeyNameTextW +#define VkKeyScan VkKeyScanW +#define VkKeyScanEx VkKeyScanExW +#else +#define GetKeyNameText GetKeyNameTextA +#define VkKeyScan VkKeyScanA +#define VkKeyScanEx VkKeyScanExA +#endif + + WINUSERAPI HWND WINAPI SetFocus(HWND hWnd); + WINUSERAPI HWND WINAPI GetActiveWindow(VOID); + WINUSERAPI HWND WINAPI GetFocus(VOID); + WINUSERAPI UINT WINAPI GetKBCodePage(VOID); + WINUSERAPI SHORT WINAPI GetKeyState(int nVirtKey); + WINUSERAPI SHORT WINAPI GetAsyncKeyState(int vKey); + WINUSERAPI WINBOOL WINAPI GetKeyboardState(PBYTE lpKeyState); + WINUSERAPI WINBOOL WINAPI SetKeyboardState(LPBYTE lpKeyState); + WINUSERAPI int WINAPI GetKeyNameTextA(LONG lParam,LPSTR lpString,int cchSize); + WINUSERAPI int WINAPI GetKeyNameTextW(LONG lParam,LPWSTR lpString,int cchSize); + WINUSERAPI int WINAPI GetKeyboardType(int nTypeFlag); + WINUSERAPI int WINAPI ToAscii(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags); + WINUSERAPI int WINAPI ToAsciiEx(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags,HKL dwhkl); + WINUSERAPI int WINAPI ToUnicode(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags); + WINUSERAPI DWORD WINAPI OemKeyScan(WORD wOemChar); + WINUSERAPI SHORT WINAPI VkKeyScanA(CHAR ch); + WINUSERAPI SHORT WINAPI VkKeyScanW(WCHAR ch); + WINUSERAPI SHORT WINAPI VkKeyScanExA(CHAR ch,HKL dwhkl); + WINUSERAPI SHORT WINAPI VkKeyScanExW(WCHAR ch,HKL dwhkl); + +#define KEYEVENTF_EXTENDEDKEY 0x0001 +#define KEYEVENTF_KEYUP 0x0002 +#define KEYEVENTF_UNICODE 0x0004 +#define KEYEVENTF_SCANCODE 0x0008 + + WINUSERAPI VOID WINAPI keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,ULONG_PTR dwExtraInfo); + +#define MOUSEEVENTF_MOVE 0x0001 +#define MOUSEEVENTF_LEFTDOWN 0x0002 +#define MOUSEEVENTF_LEFTUP 0x0004 +#define MOUSEEVENTF_RIGHTDOWN 0x0008 +#define MOUSEEVENTF_RIGHTUP 0x0010 +#define MOUSEEVENTF_MIDDLEDOWN 0x0020 +#define MOUSEEVENTF_MIDDLEUP 0x0040 +#define MOUSEEVENTF_XDOWN 0x0080 +#define MOUSEEVENTF_XUP 0x0100 +#define MOUSEEVENTF_WHEEL 0x0800 +#define MOUSEEVENTF_VIRTUALDESK 0x4000 +#define MOUSEEVENTF_ABSOLUTE 0x8000 + + WINUSERAPI VOID WINAPI mouse_event(DWORD dwFlags,DWORD dx,DWORD dy,DWORD dwData,ULONG_PTR dwExtraInfo); + + typedef struct tagMOUSEINPUT { + LONG dx; + LONG dy; + DWORD mouseData; + DWORD dwFlags; + DWORD time; + ULONG_PTR dwExtraInfo; + } MOUSEINPUT,*PMOUSEINPUT,*LPMOUSEINPUT; + + typedef struct tagKEYBDINPUT { + WORD wVk; + WORD wScan; + DWORD dwFlags; + DWORD time; + ULONG_PTR dwExtraInfo; + } KEYBDINPUT,*PKEYBDINPUT,*LPKEYBDINPUT; + + typedef struct tagHARDWAREINPUT { + DWORD uMsg; + WORD wParamL; + WORD wParamH; + } HARDWAREINPUT,*PHARDWAREINPUT,*LPHARDWAREINPUT; + +#define INPUT_MOUSE 0 +#define INPUT_KEYBOARD 1 +#define INPUT_HARDWARE 2 + + typedef struct tagINPUT { + DWORD type; + union { + MOUSEINPUT mi; + KEYBDINPUT ki; + HARDWAREINPUT hi; + }; + } INPUT,*PINPUT,*LPINPUT; + + WINUSERAPI UINT WINAPI SendInput(UINT cInputs,LPINPUT pInputs,int cbSize); + + typedef struct tagLASTINPUTINFO { + UINT cbSize; + DWORD dwTime; + } LASTINPUTINFO,*PLASTINPUTINFO; + +#ifdef UNICODE +#define MapVirtualKey MapVirtualKeyW +#define MapVirtualKeyEx MapVirtualKeyExW +#else +#define MapVirtualKey MapVirtualKeyA +#define MapVirtualKeyEx MapVirtualKeyExA +#endif + + WINUSERAPI WINBOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii); + WINUSERAPI UINT WINAPI MapVirtualKeyA(UINT uCode,UINT uMapType); + WINUSERAPI UINT WINAPI MapVirtualKeyW(UINT uCode,UINT uMapType); + WINUSERAPI UINT WINAPI MapVirtualKeyExA(UINT uCode,UINT uMapType,HKL dwhkl); + WINUSERAPI UINT WINAPI MapVirtualKeyExW(UINT uCode,UINT uMapType,HKL dwhkl); + WINUSERAPI WINBOOL WINAPI GetInputState(VOID); + WINUSERAPI DWORD WINAPI GetQueueStatus(UINT flags); + WINUSERAPI HWND WINAPI GetCapture(VOID); + WINUSERAPI HWND WINAPI SetCapture(HWND hWnd); + WINUSERAPI WINBOOL WINAPI ReleaseCapture(VOID); + WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjects(DWORD nCount,CONST HANDLE *pHandles,WINBOOL fWaitAll,DWORD dwMilliseconds,DWORD dwWakeMask); + WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *pHandles,DWORD dwMilliseconds,DWORD dwWakeMask,DWORD dwFlags); + +#define MWMO_WAITALL 0x0001 +#define MWMO_ALERTABLE 0x0002 +#define MWMO_INPUTAVAILABLE 0x0004 + +#define QS_KEY 0x0001 +#define QS_MOUSEMOVE 0x0002 +#define QS_MOUSEBUTTON 0x0004 +#define QS_POSTMESSAGE 0x0008 +#define QS_TIMER 0x0010 +#define QS_PAINT 0x0020 +#define QS_SENDMESSAGE 0x0040 +#define QS_HOTKEY 0x0080 +#define QS_ALLPOSTMESSAGE 0x0100 +#define QS_RAWINPUT 0x0400 +#define QS_MOUSE (QS_MOUSEMOVE | QS_MOUSEBUTTON) +#define QS_INPUT (QS_MOUSE | QS_KEY | QS_RAWINPUT) +#define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) +#define QS_ALLINPUT (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE) + +#define USER_TIMER_MAXIMUM 0x7FFFFFFF +#define USER_TIMER_MINIMUM 0x0000000A + +#ifdef UNICODE +#define LoadAccelerators LoadAcceleratorsW +#define CreateAcceleratorTable CreateAcceleratorTableW +#define CopyAcceleratorTable CopyAcceleratorTableW +#else +#define LoadAccelerators LoadAcceleratorsA +#define CreateAcceleratorTable CreateAcceleratorTableA +#define CopyAcceleratorTable CopyAcceleratorTableA +#endif + + WINUSERAPI UINT_PTR WINAPI SetTimer(HWND hWnd,UINT_PTR nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc); + WINUSERAPI WINBOOL WINAPI KillTimer(HWND hWnd,UINT_PTR uIDEvent); + WINUSERAPI WINBOOL WINAPI IsWindowUnicode(HWND hWnd); + WINUSERAPI WINBOOL WINAPI EnableWindow(HWND hWnd,WINBOOL bEnable); + WINUSERAPI WINBOOL WINAPI IsWindowEnabled(HWND hWnd); + WINUSERAPI HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance,LPCSTR lpTableName); + WINUSERAPI HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance,LPCWSTR lpTableName); + WINUSERAPI HACCEL WINAPI CreateAcceleratorTableA(LPACCEL paccel,int cAccel); + WINUSERAPI HACCEL WINAPI CreateAcceleratorTableW(LPACCEL paccel,int cAccel); + WINUSERAPI WINBOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel); + WINUSERAPI int WINAPI CopyAcceleratorTableA(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); + WINUSERAPI int WINAPI CopyAcceleratorTableW(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); + +#ifndef NOMSG + +#ifdef UNICODE +#define TranslateAccelerator TranslateAcceleratorW +#else +#define TranslateAccelerator TranslateAcceleratorA +#endif + + WINUSERAPI int WINAPI TranslateAcceleratorA(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); + WINUSERAPI int WINAPI TranslateAcceleratorW(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); +#endif + +#ifndef NOSYSMETRICS + +#define SM_CXSCREEN 0 +#define SM_CYSCREEN 1 +#define SM_CXVSCROLL 2 +#define SM_CYHSCROLL 3 +#define SM_CYCAPTION 4 +#define SM_CXBORDER 5 +#define SM_CYBORDER 6 +#define SM_CXDLGFRAME 7 +#define SM_CYDLGFRAME 8 +#define SM_CYVTHUMB 9 +#define SM_CXHTHUMB 10 +#define SM_CXICON 11 +#define SM_CYICON 12 +#define SM_CXCURSOR 13 +#define SM_CYCURSOR 14 +#define SM_CYMENU 15 +#define SM_CXFULLSCREEN 16 +#define SM_CYFULLSCREEN 17 +#define SM_CYKANJIWINDOW 18 +#define SM_MOUSEPRESENT 19 +#define SM_CYVSCROLL 20 +#define SM_CXHSCROLL 21 +#define SM_DEBUG 22 +#define SM_SWAPBUTTON 23 +#define SM_RESERVED1 24 +#define SM_RESERVED2 25 +#define SM_RESERVED3 26 +#define SM_RESERVED4 27 +#define SM_CXMIN 28 +#define SM_CYMIN 29 +#define SM_CXSIZE 30 +#define SM_CYSIZE 31 +#define SM_CXFRAME 32 +#define SM_CYFRAME 33 +#define SM_CXMINTRACK 34 +#define SM_CYMINTRACK 35 +#define SM_CXDOUBLECLK 36 +#define SM_CYDOUBLECLK 37 +#define SM_CXICONSPACING 38 +#define SM_CYICONSPACING 39 +#define SM_MENUDROPALIGNMENT 40 +#define SM_PENWINDOWS 41 +#define SM_DBCSENABLED 42 +#define SM_CMOUSEBUTTONS 43 + +#define SM_CXFIXEDFRAME SM_CXDLGFRAME +#define SM_CYFIXEDFRAME SM_CYDLGFRAME +#define SM_CXSIZEFRAME SM_CXFRAME +#define SM_CYSIZEFRAME SM_CYFRAME + +#define SM_SECURE 44 +#define SM_CXEDGE 45 +#define SM_CYEDGE 46 +#define SM_CXMINSPACING 47 +#define SM_CYMINSPACING 48 +#define SM_CXSMICON 49 +#define SM_CYSMICON 50 +#define SM_CYSMCAPTION 51 +#define SM_CXSMSIZE 52 +#define SM_CYSMSIZE 53 +#define SM_CXMENUSIZE 54 +#define SM_CYMENUSIZE 55 +#define SM_ARRANGE 56 +#define SM_CXMINIMIZED 57 +#define SM_CYMINIMIZED 58 +#define SM_CXMAXTRACK 59 +#define SM_CYMAXTRACK 60 +#define SM_CXMAXIMIZED 61 +#define SM_CYMAXIMIZED 62 +#define SM_NETWORK 63 +#define SM_CLEANBOOT 67 +#define SM_CXDRAG 68 +#define SM_CYDRAG 69 +#define SM_SHOWSOUNDS 70 +#define SM_CXMENUCHECK 71 +#define SM_CYMENUCHECK 72 +#define SM_SLOWMACHINE 73 +#define SM_MIDEASTENABLED 74 +#define SM_MOUSEWHEELPRESENT 75 +#define SM_XVIRTUALSCREEN 76 +#define SM_YVIRTUALSCREEN 77 +#define SM_CXVIRTUALSCREEN 78 +#define SM_CYVIRTUALSCREEN 79 +#define SM_CMONITORS 80 +#define SM_SAMEDISPLAYFORMAT 81 +#define SM_IMMENABLED 82 +#define SM_CXFOCUSBORDER 83 +#define SM_CYFOCUSBORDER 84 +#define SM_TABLETPC 86 +#define SM_MEDIACENTER 87 +#define SM_STARTER 88 +#define SM_SERVERR2 89 +#define SM_CMETRICS 90 +#define SM_REMOTESESSION 0x1000 +#define SM_SHUTTINGDOWN 0x2000 +#define SM_REMOTECONTROL 0x2001 +#define SM_CARETBLINKINGENABLED 0x2002 + + WINUSERAPI int WINAPI GetSystemMetrics(int nIndex); +#endif + +#ifndef NOMENUS + +#ifdef UNICODE +#define LoadMenu LoadMenuW +#define LoadMenuIndirect LoadMenuIndirectW +#define ChangeMenu ChangeMenuW +#define GetMenuString GetMenuStringW +#define InsertMenu InsertMenuW +#define AppendMenu AppendMenuW +#define ModifyMenu ModifyMenuW +#else +#define LoadMenu LoadMenuA +#define LoadMenuIndirect LoadMenuIndirectA +#define ChangeMenu ChangeMenuA +#define GetMenuString GetMenuStringA +#define InsertMenu InsertMenuA +#define AppendMenu AppendMenuA +#define ModifyMenu ModifyMenuA +#endif + + WINUSERAPI HMENU WINAPI LoadMenuA(HINSTANCE hInstance,LPCSTR lpMenuName); + WINUSERAPI HMENU WINAPI LoadMenuW(HINSTANCE hInstance,LPCWSTR lpMenuName); + WINUSERAPI HMENU WINAPI LoadMenuIndirectA(CONST MENUTEMPLATEA *lpMenuTemplate); + WINUSERAPI HMENU WINAPI LoadMenuIndirectW(CONST MENUTEMPLATEW *lpMenuTemplate); + WINUSERAPI HMENU WINAPI GetMenu(HWND hWnd); + WINUSERAPI WINBOOL WINAPI SetMenu(HWND hWnd,HMENU hMenu); + WINUSERAPI WINBOOL WINAPI ChangeMenuA(HMENU hMenu,UINT cmd,LPCSTR lpszNewItem,UINT cmdInsert,UINT flags); + WINUSERAPI WINBOOL WINAPI ChangeMenuW(HMENU hMenu,UINT cmd,LPCWSTR lpszNewItem,UINT cmdInsert,UINT flags); + WINUSERAPI WINBOOL WINAPI HiliteMenuItem(HWND hWnd,HMENU hMenu,UINT uIDHiliteItem,UINT uHilite); + WINUSERAPI int WINAPI GetMenuStringA(HMENU hMenu,UINT uIDItem,LPSTR lpString,int cchMax,UINT flags); + WINUSERAPI int WINAPI GetMenuStringW(HMENU hMenu,UINT uIDItem,LPWSTR lpString,int cchMax,UINT flags); + WINUSERAPI UINT WINAPI GetMenuState(HMENU hMenu,UINT uId,UINT uFlags); + WINUSERAPI WINBOOL WINAPI DrawMenuBar(HWND hWnd); + +#define PMB_ACTIVE 0x00000001 + + WINUSERAPI HMENU WINAPI GetSystemMenu(HWND hWnd,WINBOOL bRevert); + WINUSERAPI HMENU WINAPI CreateMenu(VOID); + WINUSERAPI HMENU WINAPI CreatePopupMenu(VOID); + WINUSERAPI WINBOOL WINAPI DestroyMenu(HMENU hMenu); + WINUSERAPI DWORD WINAPI CheckMenuItem(HMENU hMenu,UINT uIDCheckItem,UINT uCheck); + WINUSERAPI WINBOOL WINAPI EnableMenuItem(HMENU hMenu,UINT uIDEnableItem,UINT uEnable); + WINUSERAPI HMENU WINAPI GetSubMenu(HMENU hMenu,int nPos); + WINUSERAPI UINT WINAPI GetMenuItemID(HMENU hMenu,int nPos); + WINUSERAPI int WINAPI GetMenuItemCount(HMENU hMenu); + WINUSERAPI WINBOOL WINAPI InsertMenuA(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI InsertMenuW(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI AppendMenuA(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI AppendMenuW(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI ModifyMenuA(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI ModifyMenuW(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI RemoveMenu(HMENU hMenu,UINT uPosition,UINT uFlags); + WINUSERAPI WINBOOL WINAPI DeleteMenu(HMENU hMenu,UINT uPosition,UINT uFlags); + WINUSERAPI WINBOOL WINAPI SetMenuItemBitmaps(HMENU hMenu,UINT uPosition,UINT uFlags,HBITMAP hBitmapUnchecked,HBITMAP hBitmapChecked); + WINUSERAPI LONG WINAPI GetMenuCheckMarkDimensions(VOID); + WINUSERAPI WINBOOL WINAPI TrackPopupMenu(HMENU hMenu,UINT uFlags,int x,int y,int nReserved,HWND hWnd,CONST RECT *prcRect); + +#define MNC_IGNORE 0 +#define MNC_CLOSE 1 +#define MNC_EXECUTE 2 +#define MNC_SELECT 3 + + typedef struct tagTPMPARAMS { + UINT cbSize; + RECT rcExclude; + } TPMPARAMS; + + typedef TPMPARAMS *LPTPMPARAMS; + + WINUSERAPI WINBOOL WINAPI TrackPopupMenuEx(HMENU,UINT,int,int,HWND,LPTPMPARAMS); + +#define MNS_NOCHECK 0x80000000 +#define MNS_MODELESS 0x40000000 +#define MNS_DRAGDROP 0x20000000 +#define MNS_AUTODISMISS 0x10000000 +#define MNS_NOTIFYBYPOS 0x08000000 +#define MNS_CHECKORBMP 0x04000000 + +#define MIM_MAXHEIGHT 0x00000001 +#define MIM_BACKGROUND 0x00000002 +#define MIM_HELPID 0x00000004 +#define MIM_MENUDATA 0x00000008 +#define MIM_STYLE 0x00000010 +#define MIM_APPLYTOSUBMENUS 0x80000000 + + typedef struct tagMENUINFO { + DWORD cbSize; + DWORD fMask; + DWORD dwStyle; + UINT cyMax; + HBRUSH hbrBack; + DWORD dwContextHelpID; + ULONG_PTR dwMenuData; + } MENUINFO,*LPMENUINFO; + + typedef MENUINFO CONST *LPCMENUINFO; + + WINUSERAPI WINBOOL WINAPI GetMenuInfo(HMENU,LPMENUINFO); + WINUSERAPI WINBOOL WINAPI SetMenuInfo(HMENU,LPCMENUINFO); + WINUSERAPI WINBOOL WINAPI EndMenu(VOID); + +#define MND_CONTINUE 0 +#define MND_ENDMENU 1 + + typedef struct tagMENUGETOBJECTINFO { + DWORD dwFlags; + UINT uPos; + HMENU hmenu; + PVOID riid; + PVOID pvObj; + } MENUGETOBJECTINFO,*PMENUGETOBJECTINFO; + +#define MNGOF_TOPGAP 0x00000001 +#define MNGOF_BOTTOMGAP 0x00000002 + +#define MNGO_NOINTERFACE 0x00000000 +#define MNGO_NOERROR 0x00000001 + +#define MIIM_STATE 0x00000001 +#define MIIM_ID 0x00000002 +#define MIIM_SUBMENU 0x00000004 +#define MIIM_CHECKMARKS 0x00000008 +#define MIIM_TYPE 0x00000010 +#define MIIM_DATA 0x00000020 + +#define MIIM_STRING 0x00000040 +#define MIIM_BITMAP 0x00000080 +#define MIIM_FTYPE 0x00000100 + +#define HBMMENU_CALLBACK ((HBITMAP) -1) +#define HBMMENU_SYSTEM ((HBITMAP) 1) +#define HBMMENU_MBAR_RESTORE ((HBITMAP) 2) +#define HBMMENU_MBAR_MINIMIZE ((HBITMAP) 3) +#define HBMMENU_MBAR_CLOSE ((HBITMAP) 5) +#define HBMMENU_MBAR_CLOSE_D ((HBITMAP) 6) +#define HBMMENU_MBAR_MINIMIZE_D ((HBITMAP) 7) +#define HBMMENU_POPUP_CLOSE ((HBITMAP) 8) +#define HBMMENU_POPUP_RESTORE ((HBITMAP) 9) +#define HBMMENU_POPUP_MAXIMIZE ((HBITMAP) 10) +#define HBMMENU_POPUP_MINIMIZE ((HBITMAP) 11) + + typedef struct tagMENUITEMINFOA { + UINT cbSize; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + ULONG_PTR dwItemData; + LPSTR dwTypeData; + UINT cch; + HBITMAP hbmpItem; + } MENUITEMINFOA,*LPMENUITEMINFOA; + + typedef struct tagMENUITEMINFOW { + UINT cbSize; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + ULONG_PTR dwItemData; + LPWSTR dwTypeData; + UINT cch; + HBITMAP hbmpItem; + } MENUITEMINFOW,*LPMENUITEMINFOW; + +#ifdef UNICODE + typedef MENUITEMINFOW MENUITEMINFO; + typedef LPMENUITEMINFOW LPMENUITEMINFO; +#else + typedef MENUITEMINFOA MENUITEMINFO; + typedef LPMENUITEMINFOA LPMENUITEMINFO; +#endif + typedef MENUITEMINFOA CONST *LPCMENUITEMINFOA; + typedef MENUITEMINFOW CONST *LPCMENUITEMINFOW; +#ifdef UNICODE + typedef LPCMENUITEMINFOW LPCMENUITEMINFO; +#else + typedef LPCMENUITEMINFOA LPCMENUITEMINFO; +#endif + +#ifdef UNICODE +#define InsertMenuItem InsertMenuItemW +#define GetMenuItemInfo GetMenuItemInfoW +#define SetMenuItemInfo SetMenuItemInfoW +#else +#define InsertMenuItem InsertMenuItemA +#define GetMenuItemInfo GetMenuItemInfoA +#define SetMenuItemInfo SetMenuItemInfoA +#endif + + WINUSERAPI WINBOOL WINAPI InsertMenuItemA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOA lpmi); + WINUSERAPI WINBOOL WINAPI InsertMenuItemW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOW lpmi); + WINUSERAPI WINBOOL WINAPI GetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOA lpmii); + WINUSERAPI WINBOOL WINAPI GetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOW lpmii); + WINUSERAPI WINBOOL WINAPI SetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOA lpmii); + WINUSERAPI WINBOOL WINAPI SetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOW lpmii); + +#define GMDI_USEDISABLED 0x0001L +#define GMDI_GOINTOPOPUPS 0x0002L + + WINUSERAPI UINT WINAPI GetMenuDefaultItem(HMENU hMenu,UINT fByPos,UINT gmdiFlags); + WINUSERAPI WINBOOL WINAPI SetMenuDefaultItem(HMENU hMenu,UINT uItem,UINT fByPos); + WINUSERAPI WINBOOL WINAPI GetMenuItemRect(HWND hWnd,HMENU hMenu,UINT uItem,LPRECT lprcItem); + WINUSERAPI int WINAPI MenuItemFromPoint(HWND hWnd,HMENU hMenu,POINT ptScreen); + +#define TPM_LEFTBUTTON 0x0000L +#define TPM_RIGHTBUTTON 0x0002L +#define TPM_LEFTALIGN 0x0000L +#define TPM_CENTERALIGN 0x0004L +#define TPM_RIGHTALIGN 0x0008L +#define TPM_TOPALIGN 0x0000L +#define TPM_VCENTERALIGN 0x0010L +#define TPM_BOTTOMALIGN 0x0020L + +#define TPM_HORIZONTAL 0x0000L +#define TPM_VERTICAL 0x0040L +#define TPM_NONOTIFY 0x0080L +#define TPM_RETURNCMD 0x0100L +#define TPM_RECURSE 0x0001L +#define TPM_HORPOSANIMATION 0x0400L +#define TPM_HORNEGANIMATION 0x0800L +#define TPM_VERPOSANIMATION 0x1000L +#define TPM_VERNEGANIMATION 0x2000L +#define TPM_NOANIMATION 0x4000L +#define TPM_LAYOUTRTL 0x8000L +#endif + + typedef struct tagDROPSTRUCT { + HWND hwndSource; + HWND hwndSink; + DWORD wFmt; + ULONG_PTR dwData; + POINT ptDrop; + DWORD dwControlData; + } DROPSTRUCT,*PDROPSTRUCT,*LPDROPSTRUCT; + +#define DOF_EXECUTABLE 0x8001 +#define DOF_DOCUMENT 0x8002 +#define DOF_DIRECTORY 0x8003 +#define DOF_MULTIPLE 0x8004 +#define DOF_PROGMAN 0x0001 +#define DOF_SHELLDATA 0x0002 + +#define DO_DROPFILE 0x454C4946L +#define DO_PRINTFILE 0x544E5250L + + WINUSERAPI DWORD WINAPI DragObject(HWND hwndParent,HWND hwndFrom,UINT fmt,ULONG_PTR data,HCURSOR hcur); + WINUSERAPI WINBOOL WINAPI DragDetect(HWND hwnd,POINT pt); + WINUSERAPI WINBOOL WINAPI DrawIcon(HDC hDC,int X,int Y,HICON hIcon); + +#ifndef NODRAWTEXT + +#define DT_TOP 0x00000000 +#define DT_LEFT 0x00000000 +#define DT_CENTER 0x00000001 +#define DT_RIGHT 0x00000002 +#define DT_VCENTER 0x00000004 +#define DT_BOTTOM 0x00000008 +#define DT_WORDBREAK 0x00000010 +#define DT_SINGLELINE 0x00000020 +#define DT_EXPANDTABS 0x00000040 +#define DT_TABSTOP 0x00000080 +#define DT_NOCLIP 0x00000100 +#define DT_EXTERNALLEADING 0x00000200 +#define DT_CALCRECT 0x00000400 +#define DT_NOPREFIX 0x00000800 +#define DT_INTERNAL 0x00001000 + +#define DT_EDITCONTROL 0x00002000 +#define DT_PATH_ELLIPSIS 0x00004000 +#define DT_END_ELLIPSIS 0x00008000 +#define DT_MODIFYSTRING 0x00010000 +#define DT_RTLREADING 0x00020000 +#define DT_WORD_ELLIPSIS 0x00040000 +#define DT_NOFULLWIDTHCHARBREAK 0x00080000 +#define DT_HIDEPREFIX 0x00100000 +#define DT_PREFIXONLY 0x00200000 + + typedef struct tagDRAWTEXTPARAMS { + UINT cbSize; + int iTabLength; + int iLeftMargin; + int iRightMargin; + UINT uiLengthDrawn; + } DRAWTEXTPARAMS,*LPDRAWTEXTPARAMS; + +#ifdef UNICODE +#define DrawText DrawTextW +#define DrawTextEx DrawTextExW +#else +#define DrawText DrawTextA +#define DrawTextEx DrawTextExA +#endif + + WINUSERAPI int WINAPI DrawTextA(HDC hdc,LPCSTR lpchText,int cchText,LPRECT lprc,UINT format); + WINUSERAPI int WINAPI DrawTextW(HDC hdc,LPCWSTR lpchText,int cchText,LPRECT lprc,UINT format); + WINUSERAPI int WINAPI DrawTextExA(HDC hdc,LPSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); + WINUSERAPI int WINAPI DrawTextExW(HDC hdc,LPWSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); +#endif + +#ifdef UNICODE +#define GrayString GrayStringW +#define DrawState DrawStateW +#define TabbedTextOut TabbedTextOutW +#define GetTabbedTextExtent GetTabbedTextExtentW +#else +#define GrayString GrayStringA +#define DrawState DrawStateA +#define TabbedTextOut TabbedTextOutA +#define GetTabbedTextExtent GetTabbedTextExtentA +#endif + + WINUSERAPI WINBOOL WINAPI GrayStringA(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); + WINUSERAPI WINBOOL WINAPI GrayStringW(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); + +#define DST_COMPLEX 0x0000 +#define DST_TEXT 0x0001 +#define DST_PREFIXTEXT 0x0002 +#define DST_ICON 0x0003 +#define DST_BITMAP 0x0004 + +#define DSS_NORMAL 0x0000 +#define DSS_UNION 0x0010 +#define DSS_DISABLED 0x0020 +#define DSS_MONO 0x0080 +#define DSS_HIDEPREFIX 0x0200 +#define DSS_PREFIXONLY 0x0400 +#define DSS_RIGHT 0x8000 + + WINUSERAPI WINBOOL WINAPI DrawStateA(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); + WINUSERAPI WINBOOL WINAPI DrawStateW(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); + WINUSERAPI LONG WINAPI TabbedTextOutA(HDC hdc,int x,int y,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); + WINUSERAPI LONG WINAPI TabbedTextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); + WINUSERAPI DWORD WINAPI GetTabbedTextExtentA(HDC hdc,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); + WINUSERAPI DWORD WINAPI GetTabbedTextExtentW(HDC hdc,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); + WINUSERAPI WINBOOL WINAPI UpdateWindow(HWND hWnd); + WINUSERAPI HWND WINAPI SetActiveWindow(HWND hWnd); + WINUSERAPI HWND WINAPI GetForegroundWindow(VOID); + WINUSERAPI WINBOOL WINAPI PaintDesktop(HDC hdc); + WINUSERAPI VOID WINAPI SwitchToThisWindow(HWND hwnd,WINBOOL fUnknown); + WINUSERAPI WINBOOL WINAPI SetForegroundWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI AllowSetForegroundWindow(DWORD dwProcessId); + +#define ASFW_ANY ((DWORD)-1) + + WINUSERAPI WINBOOL WINAPI LockSetForegroundWindow(UINT uLockCode); + +#define LSFW_LOCK 1 +#define LSFW_UNLOCK 2 + + WINUSERAPI HWND WINAPI WindowFromDC(HDC hDC); + WINUSERAPI HDC WINAPI GetDC(HWND hWnd); + WINUSERAPI HDC WINAPI GetDCEx(HWND hWnd,HRGN hrgnClip,DWORD flags); + +#define DCX_WINDOW 0x00000001L +#define DCX_CACHE 0x00000002L +#define DCX_NORESETATTRS 0x00000004L +#define DCX_CLIPCHILDREN 0x00000008L +#define DCX_CLIPSIBLINGS 0x00000010L +#define DCX_PARENTCLIP 0x00000020L +#define DCX_EXCLUDERGN 0x00000040L +#define DCX_INTERSECTRGN 0x00000080L +#define DCX_EXCLUDEUPDATE 0x00000100L +#define DCX_INTERSECTUPDATE 0x00000200L +#define DCX_LOCKWINDOWUPDATE 0x00000400L + +#define DCX_VALIDATE 0x00200000L + + WINUSERAPI HDC WINAPI GetWindowDC(HWND hWnd); + WINUSERAPI int WINAPI ReleaseDC(HWND hWnd,HDC hDC); + WINUSERAPI HDC WINAPI BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint); + WINUSERAPI WINBOOL WINAPI EndPaint(HWND hWnd,CONST PAINTSTRUCT *lpPaint); + WINUSERAPI WINBOOL WINAPI GetUpdateRect(HWND hWnd,LPRECT lpRect,WINBOOL bErase); + WINUSERAPI int WINAPI GetUpdateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); + WINUSERAPI int WINAPI SetWindowRgn(HWND hWnd,HRGN hRgn,WINBOOL bRedraw); + WINUSERAPI int WINAPI GetWindowRgn(HWND hWnd,HRGN hRgn); + WINUSERAPI int WINAPI GetWindowRgnBox(HWND hWnd,LPRECT lprc); + WINUSERAPI int WINAPI ExcludeUpdateRgn(HDC hDC,HWND hWnd); + WINUSERAPI WINBOOL WINAPI InvalidateRect(HWND hWnd,CONST RECT *lpRect,WINBOOL bErase); + WINUSERAPI WINBOOL WINAPI ValidateRect(HWND hWnd,CONST RECT *lpRect); + WINUSERAPI WINBOOL WINAPI InvalidateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); + WINUSERAPI WINBOOL WINAPI ValidateRgn(HWND hWnd,HRGN hRgn); + WINUSERAPI WINBOOL WINAPI RedrawWindow(HWND hWnd,CONST RECT *lprcUpdate,HRGN hrgnUpdate,UINT flags); + +#define RDW_INVALIDATE 0x0001 +#define RDW_INTERNALPAINT 0x0002 +#define RDW_ERASE 0x0004 + +#define RDW_VALIDATE 0x0008 +#define RDW_NOINTERNALPAINT 0x0010 +#define RDW_NOERASE 0x0020 + +#define RDW_NOCHILDREN 0x0040 +#define RDW_ALLCHILDREN 0x0080 + +#define RDW_UPDATENOW 0x0100 +#define RDW_ERASENOW 0x0200 + +#define RDW_FRAME 0x0400 +#define RDW_NOFRAME 0x0800 + + WINUSERAPI WINBOOL WINAPI LockWindowUpdate(HWND hWndLock); + WINUSERAPI WINBOOL WINAPI ScrollWindow(HWND hWnd,int XAmount,int YAmount,CONST RECT *lpRect,CONST RECT *lpClipRect); + WINUSERAPI WINBOOL WINAPI ScrollDC(HDC hDC,int dx,int dy,CONST RECT *lprcScroll,CONST RECT *lprcClip,HRGN hrgnUpdate,LPRECT lprcUpdate); + WINUSERAPI int WINAPI ScrollWindowEx(HWND hWnd,int dx,int dy,CONST RECT *prcScroll,CONST RECT *prcClip,HRGN hrgnUpdate,LPRECT prcUpdate,UINT flags); + +#define SW_SCROLLCHILDREN 0x0001 +#define SW_INVALIDATE 0x0002 +#define SW_ERASE 0x0004 +#define SW_SMOOTHSCROLL 0x0010 + +#ifndef NOSCROLL + WINUSERAPI int WINAPI SetScrollPos(HWND hWnd,int nBar,int nPos,WINBOOL bRedraw); + WINUSERAPI int WINAPI GetScrollPos(HWND hWnd,int nBar); + WINUSERAPI WINBOOL WINAPI SetScrollRange(HWND hWnd,int nBar,int nMinPos,int nMaxPos,WINBOOL bRedraw); + WINUSERAPI WINBOOL WINAPI GetScrollRange(HWND hWnd,int nBar,LPINT lpMinPos,LPINT lpMaxPos); + WINUSERAPI WINBOOL WINAPI ShowScrollBar(HWND hWnd,int wBar,WINBOOL bShow); + WINUSERAPI WINBOOL WINAPI EnableScrollBar(HWND hWnd,UINT wSBflags,UINT wArrows); + +#define ESB_ENABLE_BOTH 0x0000 +#define ESB_DISABLE_BOTH 0x0003 + +#define ESB_DISABLE_LEFT 0x0001 +#define ESB_DISABLE_RIGHT 0x0002 + +#define ESB_DISABLE_UP 0x0001 +#define ESB_DISABLE_DOWN 0x0002 + +#define ESB_DISABLE_LTUP ESB_DISABLE_LEFT +#define ESB_DISABLE_RTDN ESB_DISABLE_RIGHT +#endif + +#ifdef UNICODE +#define SetProp SetPropW +#define GetProp GetPropW +#define RemoveProp RemovePropW +#define EnumPropsEx EnumPropsExW +#define EnumProps EnumPropsW +#define SetWindowText SetWindowTextW +#define GetWindowText GetWindowTextW +#define GetWindowTextLength GetWindowTextLengthW +#else +#define SetProp SetPropA +#define GetProp GetPropA +#define RemoveProp RemovePropA +#define EnumPropsEx EnumPropsExA +#define EnumProps EnumPropsA +#define SetWindowText SetWindowTextA +#define GetWindowText GetWindowTextA +#define GetWindowTextLength GetWindowTextLengthA +#endif + + WINUSERAPI WINBOOL WINAPI SetPropA(HWND hWnd,LPCSTR lpString,HANDLE hData); + WINUSERAPI WINBOOL WINAPI SetPropW(HWND hWnd,LPCWSTR lpString,HANDLE hData); + WINUSERAPI HANDLE WINAPI GetPropA(HWND hWnd,LPCSTR lpString); + WINUSERAPI HANDLE WINAPI GetPropW(HWND hWnd,LPCWSTR lpString); + WINUSERAPI HANDLE WINAPI RemovePropA(HWND hWnd,LPCSTR lpString); + WINUSERAPI HANDLE WINAPI RemovePropW(HWND hWnd,LPCWSTR lpString); + WINUSERAPI int WINAPI EnumPropsExA(HWND hWnd,PROPENUMPROCEXA lpEnumFunc,LPARAM lParam); + WINUSERAPI int WINAPI EnumPropsExW(HWND hWnd,PROPENUMPROCEXW lpEnumFunc,LPARAM lParam); + WINUSERAPI int WINAPI EnumPropsA(HWND hWnd,PROPENUMPROCA lpEnumFunc); + WINUSERAPI int WINAPI EnumPropsW(HWND hWnd,PROPENUMPROCW lpEnumFunc); + WINUSERAPI WINBOOL WINAPI SetWindowTextA(HWND hWnd,LPCSTR lpString); + WINUSERAPI WINBOOL WINAPI SetWindowTextW(HWND hWnd,LPCWSTR lpString); + WINUSERAPI int WINAPI GetWindowTextA(HWND hWnd,LPSTR lpString,int nMaxCount); + WINUSERAPI int WINAPI GetWindowTextW(HWND hWnd,LPWSTR lpString,int nMaxCount); + WINUSERAPI int WINAPI GetWindowTextLengthA(HWND hWnd); + WINUSERAPI int WINAPI GetWindowTextLengthW(HWND hWnd); + WINUSERAPI WINBOOL WINAPI GetClientRect(HWND hWnd,LPRECT lpRect); + WINUSERAPI WINBOOL WINAPI GetWindowRect(HWND hWnd,LPRECT lpRect); + WINUSERAPI WINBOOL WINAPI AdjustWindowRect(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu); + WINUSERAPI WINBOOL WINAPI AdjustWindowRectEx(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu,DWORD dwExStyle); + +#define HELPINFO_WINDOW 0x0001 +#define HELPINFO_MENUITEM 0x0002 + + typedef struct tagHELPINFO { + UINT cbSize; + int iContextType; + int iCtrlId; + HANDLE hItemHandle; + DWORD_PTR dwContextId; + POINT MousePos; + } HELPINFO,*LPHELPINFO; + + WINUSERAPI WINBOOL WINAPI SetWindowContextHelpId(HWND,DWORD); + WINUSERAPI DWORD WINAPI GetWindowContextHelpId(HWND); + WINUSERAPI WINBOOL WINAPI SetMenuContextHelpId(HMENU,DWORD); + WINUSERAPI DWORD WINAPI GetMenuContextHelpId(HMENU); + +#ifndef NOMB + +#define MB_OK 0x00000000L +#define MB_OKCANCEL 0x00000001L +#define MB_ABORTRETRYIGNORE 0x00000002L +#define MB_YESNOCANCEL 0x00000003L +#define MB_YESNO 0x00000004L +#define MB_RETRYCANCEL 0x00000005L +#define MB_CANCELTRYCONTINUE 0x00000006L +#define MB_ICONHAND 0x00000010L +#define MB_ICONQUESTION 0x00000020L +#define MB_ICONEXCLAMATION 0x00000030L +#define MB_ICONASTERISK 0x00000040L +#define MB_USERICON 0x00000080L +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND +#define MB_DEFBUTTON1 0x00000000L +#define MB_DEFBUTTON2 0x00000100L +#define MB_DEFBUTTON3 0x00000200L +#define MB_DEFBUTTON4 0x00000300L +#define MB_APPLMODAL 0x00000000L +#define MB_SYSTEMMODAL 0x00001000L +#define MB_TASKMODAL 0x00002000L +#define MB_HELP 0x00004000L +#define MB_NOFOCUS 0x00008000L +#define MB_SETFOREGROUND 0x00010000L +#define MB_DEFAULT_DESKTOP_ONLY 0x00020000L +#define MB_TOPMOST 0x00040000L +#define MB_RIGHT 0x00080000L +#define MB_RTLREADING 0x00100000L +#define MB_SERVICE_NOTIFICATION 0x00200000L +#define MB_SERVICE_NOTIFICATION_NT3X 0x00040000L +#define MB_TYPEMASK 0x0000000FL +#define MB_ICONMASK 0x000000F0L +#define MB_DEFMASK 0x00000F00L +#define MB_MODEMASK 0x00003000L +#define MB_MISCMASK 0x0000C000L + +#ifdef UNICODE +#define MessageBox MessageBoxW +#define MessageBoxEx MessageBoxExW +#else +#define MessageBox MessageBoxA +#define MessageBoxEx MessageBoxExA +#endif + + WINUSERAPI int WINAPI MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); + WINUSERAPI int WINAPI MessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); + WINUSERAPI int WINAPI MessageBoxExA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType,WORD wLanguageId); + WINUSERAPI int WINAPI MessageBoxExW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType,WORD wLanguageId); + + typedef VOID (CALLBACK *MSGBOXCALLBACK)(LPHELPINFO lpHelpInfo); + + typedef struct tagMSGBOXPARAMSA { + UINT cbSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCSTR lpszText; + LPCSTR lpszCaption; + DWORD dwStyle; + LPCSTR lpszIcon; + DWORD_PTR dwContextHelpId; + MSGBOXCALLBACK lpfnMsgBoxCallback; + DWORD dwLanguageId; + } MSGBOXPARAMSA,*PMSGBOXPARAMSA,*LPMSGBOXPARAMSA; + + typedef struct tagMSGBOXPARAMSW { + UINT cbSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCWSTR lpszText; + LPCWSTR lpszCaption; + DWORD dwStyle; + LPCWSTR lpszIcon; + DWORD_PTR dwContextHelpId; + MSGBOXCALLBACK lpfnMsgBoxCallback; + DWORD dwLanguageId; + } MSGBOXPARAMSW,*PMSGBOXPARAMSW,*LPMSGBOXPARAMSW; + +#ifdef UNICODE + typedef MSGBOXPARAMSW MSGBOXPARAMS; + typedef PMSGBOXPARAMSW PMSGBOXPARAMS; + typedef LPMSGBOXPARAMSW LPMSGBOXPARAMS; +#else + typedef MSGBOXPARAMSA MSGBOXPARAMS; + typedef PMSGBOXPARAMSA PMSGBOXPARAMS; + typedef LPMSGBOXPARAMSA LPMSGBOXPARAMS; +#endif + +#ifdef UNICODE +#define MessageBoxIndirect MessageBoxIndirectW +#else +#define MessageBoxIndirect MessageBoxIndirectA +#endif + + WINUSERAPI int WINAPI MessageBoxIndirectA(CONST MSGBOXPARAMSA *lpmbp); + WINUSERAPI int WINAPI MessageBoxIndirectW(CONST MSGBOXPARAMSW *lpmbp); + WINUSERAPI WINBOOL WINAPI MessageBeep(UINT uType); +#endif + + WINUSERAPI int WINAPI ShowCursor(WINBOOL bShow); + WINUSERAPI WINBOOL WINAPI SetCursorPos(int X,int Y); + WINUSERAPI HCURSOR WINAPI SetCursor(HCURSOR hCursor); + WINUSERAPI WINBOOL WINAPI GetCursorPos(LPPOINT lpPoint); + WINUSERAPI WINBOOL WINAPI ClipCursor(CONST RECT *lpRect); + WINUSERAPI WINBOOL WINAPI GetClipCursor(LPRECT lpRect); + WINUSERAPI HCURSOR WINAPI GetCursor(VOID); + WINUSERAPI WINBOOL WINAPI CreateCaret(HWND hWnd,HBITMAP hBitmap,int nWidth,int nHeight); + WINUSERAPI UINT WINAPI GetCaretBlinkTime(VOID); + WINUSERAPI WINBOOL WINAPI SetCaretBlinkTime(UINT uMSeconds); + WINUSERAPI WINBOOL WINAPI DestroyCaret(VOID); + WINUSERAPI WINBOOL WINAPI HideCaret(HWND hWnd); + WINUSERAPI WINBOOL WINAPI ShowCaret(HWND hWnd); + WINUSERAPI WINBOOL WINAPI SetCaretPos(int X,int Y); + WINUSERAPI WINBOOL WINAPI GetCaretPos(LPPOINT lpPoint); + WINUSERAPI WINBOOL WINAPI ClientToScreen(HWND hWnd,LPPOINT lpPoint); + WINUSERAPI WINBOOL WINAPI ScreenToClient(HWND hWnd,LPPOINT lpPoint); + WINUSERAPI int WINAPI MapWindowPoints(HWND hWndFrom,HWND hWndTo,LPPOINT lpPoints,UINT cPoints); + WINUSERAPI HWND WINAPI WindowFromPoint(POINT Point); + WINUSERAPI HWND WINAPI ChildWindowFromPoint(HWND hWndParent,POINT Point); + +#define CWP_ALL 0x0000 +#define CWP_SKIPINVISIBLE 0x0001 +#define CWP_SKIPDISABLED 0x0002 +#define CWP_SKIPTRANSPARENT 0x0004 + + WINUSERAPI HWND WINAPI ChildWindowFromPointEx(HWND hwnd,POINT pt,UINT flags); + +#ifndef NOCOLOR + +#define CTLCOLOR_MSGBOX 0 +#define CTLCOLOR_EDIT 1 +#define CTLCOLOR_LISTBOX 2 +#define CTLCOLOR_BTN 3 +#define CTLCOLOR_DLG 4 +#define CTLCOLOR_SCROLLBAR 5 +#define CTLCOLOR_STATIC 6 +#define CTLCOLOR_MAX 7 + +#define COLOR_SCROLLBAR 0 +#define COLOR_BACKGROUND 1 +#define COLOR_ACTIVECAPTION 2 +#define COLOR_INACTIVECAPTION 3 +#define COLOR_MENU 4 +#define COLOR_WINDOW 5 +#define COLOR_WINDOWFRAME 6 +#define COLOR_MENUTEXT 7 +#define COLOR_WINDOWTEXT 8 +#define COLOR_CAPTIONTEXT 9 +#define COLOR_ACTIVEBORDER 10 +#define COLOR_INACTIVEBORDER 11 +#define COLOR_APPWORKSPACE 12 +#define COLOR_HIGHLIGHT 13 +#define COLOR_HIGHLIGHTTEXT 14 +#define COLOR_BTNFACE 15 +#define COLOR_BTNSHADOW 16 +#define COLOR_GRAYTEXT 17 +#define COLOR_BTNTEXT 18 +#define COLOR_INACTIVECAPTIONTEXT 19 +#define COLOR_BTNHIGHLIGHT 20 + +#define COLOR_3DDKSHADOW 21 +#define COLOR_3DLIGHT 22 +#define COLOR_INFOTEXT 23 +#define COLOR_INFOBK 24 + +#define COLOR_HOTLIGHT 26 +#define COLOR_GRADIENTACTIVECAPTION 27 +#define COLOR_GRADIENTINACTIVECAPTION 28 +#define COLOR_MENUHILIGHT 29 +#define COLOR_MENUBAR 30 + +#define COLOR_DESKTOP COLOR_BACKGROUND +#define COLOR_3DFACE COLOR_BTNFACE +#define COLOR_3DSHADOW COLOR_BTNSHADOW +#define COLOR_3DHIGHLIGHT COLOR_BTNHIGHLIGHT +#define COLOR_3DHILIGHT COLOR_BTNHIGHLIGHT +#define COLOR_BTNHILIGHT COLOR_BTNHIGHLIGHT + + WINUSERAPI DWORD WINAPI GetSysColor(int nIndex); + WINUSERAPI HBRUSH WINAPI GetSysColorBrush(int nIndex); + WINUSERAPI WINBOOL WINAPI SetSysColors(int cElements,CONST INT *lpaElements,CONST COLORREF *lpaRgbValues); +#endif + + WINUSERAPI WINBOOL WINAPI DrawFocusRect(HDC hDC,CONST RECT *lprc); + WINUSERAPI int WINAPI FillRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); + WINUSERAPI int WINAPI FrameRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); + WINUSERAPI WINBOOL WINAPI InvertRect(HDC hDC,CONST RECT *lprc); + WINUSERAPI WINBOOL WINAPI SetRect(LPRECT lprc,int xLeft,int yTop,int xRight,int yBottom); + WINUSERAPI WINBOOL WINAPI SetRectEmpty(LPRECT lprc); + WINUSERAPI WINBOOL WINAPI CopyRect(LPRECT lprcDst,CONST RECT *lprcSrc); + WINUSERAPI WINBOOL WINAPI InflateRect(LPRECT lprc,int dx,int dy); + WINUSERAPI WINBOOL WINAPI IntersectRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); + WINUSERAPI WINBOOL WINAPI UnionRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); + WINUSERAPI WINBOOL WINAPI SubtractRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); + WINUSERAPI WINBOOL WINAPI OffsetRect(LPRECT lprc,int dx,int dy); + WINUSERAPI WINBOOL WINAPI IsRectEmpty(CONST RECT *lprc); + WINUSERAPI WINBOOL WINAPI EqualRect(CONST RECT *lprc1,CONST RECT *lprc2); + WINUSERAPI WINBOOL WINAPI PtInRect(CONST RECT *lprc,POINT pt); + +#ifndef NOWINOFFSETS + +#ifdef UNICODE +#define GetWindowLong GetWindowLongW +#define SetWindowLong SetWindowLongW +#else +#define GetWindowLong GetWindowLongA +#define SetWindowLong SetWindowLongA +#endif + + WINUSERAPI WORD WINAPI GetWindowWord(HWND hWnd,int nIndex); + WINUSERAPI WORD WINAPI SetWindowWord(HWND hWnd,int nIndex,WORD wNewWord); + WINUSERAPI LONG WINAPI GetWindowLongA(HWND hWnd,int nIndex); + WINUSERAPI LONG WINAPI GetWindowLongW(HWND hWnd,int nIndex); + WINUSERAPI LONG WINAPI SetWindowLongA(HWND hWnd,int nIndex,LONG dwNewLong); + WINUSERAPI LONG WINAPI SetWindowLongW(HWND hWnd,int nIndex,LONG dwNewLong); + +#ifdef _WIN64 + +#ifdef UNICODE +#define GetWindowLongPtr GetWindowLongPtrW +#define SetWindowLongPtr SetWindowLongPtrW +#else +#define GetWindowLongPtr GetWindowLongPtrA +#define SetWindowLongPtr SetWindowLongPtrA +#endif + + WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrA(HWND hWnd,int nIndex); + WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrW(HWND hWnd,int nIndex); + WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); + WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); +#else + +#ifdef UNICODE +#define GetWindowLongPtr GetWindowLongPtrW +#define SetWindowLongPtr SetWindowLongPtrW +#else +#define GetWindowLongPtr GetWindowLongPtrA +#define SetWindowLongPtr SetWindowLongPtrA +#endif + +#define GetWindowLongPtrA GetWindowLongA +#define GetWindowLongPtrW GetWindowLongW +#define SetWindowLongPtrA SetWindowLongA +#define SetWindowLongPtrW SetWindowLongW +#endif + +#ifdef UNICODE +#define GetClassLong GetClassLongW +#define SetClassLong SetClassLongW +#else +#define GetClassLong GetClassLongA +#define SetClassLong SetClassLongA +#endif + + WINUSERAPI WORD WINAPI GetClassWord(HWND hWnd,int nIndex); + WINUSERAPI WORD WINAPI SetClassWord(HWND hWnd,int nIndex,WORD wNewWord); + WINUSERAPI DWORD WINAPI GetClassLongA(HWND hWnd,int nIndex); + WINUSERAPI DWORD WINAPI GetClassLongW(HWND hWnd,int nIndex); + WINUSERAPI DWORD WINAPI SetClassLongA(HWND hWnd,int nIndex,LONG dwNewLong); + WINUSERAPI DWORD WINAPI SetClassLongW(HWND hWnd,int nIndex,LONG dwNewLong); + +#ifdef _WIN64 + +#ifdef UNICODE +#define GetClassLongPtr GetClassLongPtrW +#define SetClassLongPtr SetClassLongPtrW +#else +#define GetClassLongPtr GetClassLongPtrA +#define SetClassLongPtr SetClassLongPtrA +#endif + + WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrA(HWND hWnd,int nIndex); + WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrW(HWND hWnd,int nIndex); + WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); + WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); +#else +#ifdef UNICODE +#define GetClassLongPtr GetClassLongPtrW +#define SetClassLongPtr SetClassLongPtrW +#else +#define GetClassLongPtr GetClassLongPtrA +#define SetClassLongPtr SetClassLongPtrA +#endif + +#define GetClassLongPtrA GetClassLongA +#define GetClassLongPtrW GetClassLongW +#define SetClassLongPtrA SetClassLongA +#define SetClassLongPtrW SetClassLongW +#endif +#endif + +#ifdef UNICODE +#define FindWindow FindWindowW +#define FindWindowEx FindWindowExW +#define GetClassName GetClassNameW +#else +#define FindWindow FindWindowA +#define FindWindowEx FindWindowExA +#define GetClassName GetClassNameA +#endif + + WINUSERAPI WINBOOL WINAPI GetProcessDefaultLayout(DWORD *pdwDefaultLayout); + WINUSERAPI WINBOOL WINAPI SetProcessDefaultLayout(DWORD dwDefaultLayout); + WINUSERAPI HWND WINAPI GetDesktopWindow(VOID); + WINUSERAPI HWND WINAPI GetParent(HWND hWnd); + WINUSERAPI HWND WINAPI SetParent(HWND hWndChild,HWND hWndNewParent); + WINUSERAPI WINBOOL WINAPI EnumChildWindows(HWND hWndParent,WNDENUMPROC lpEnumFunc,LPARAM lParam); + WINUSERAPI HWND WINAPI FindWindowA(LPCSTR lpClassName,LPCSTR lpWindowName); + WINUSERAPI HWND WINAPI FindWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName); + WINUSERAPI HWND WINAPI FindWindowExA(HWND hWndParent,HWND hWndChildAfter,LPCSTR lpszClass,LPCSTR lpszWindow); + WINUSERAPI HWND WINAPI FindWindowExW(HWND hWndParent,HWND hWndChildAfter,LPCWSTR lpszClass,LPCWSTR lpszWindow); + WINUSERAPI HWND WINAPI GetShellWindow(VOID); + WINUSERAPI WINBOOL WINAPI RegisterShellHookWindow(HWND hwnd); + WINUSERAPI WINBOOL WINAPI DeregisterShellHookWindow(HWND hwnd); + WINUSERAPI WINBOOL WINAPI EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumThreadWindows(DWORD dwThreadId,WNDENUMPROC lpfn,LPARAM lParam); + +#define EnumTaskWindows(hTask,lpfn,lParam) EnumThreadWindows(HandleToUlong(hTask),lpfn,lParam) + + WINUSERAPI int WINAPI GetClassNameA(HWND hWnd,LPSTR lpClassName,int nMaxCount); + WINUSERAPI int WINAPI GetClassNameW(HWND hWnd,LPWSTR lpClassName,int nMaxCount); + WINUSERAPI HWND WINAPI GetTopWindow(HWND hWnd); + +#define GetNextWindow(hWnd,wCmd) GetWindow(hWnd,wCmd) +#define GetSysModalWindow() (NULL) +#define SetSysModalWindow(hWnd) (NULL) + + WINUSERAPI DWORD WINAPI GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId); + WINUSERAPI WINBOOL WINAPI IsGUIThread(WINBOOL bConvert); + +#define GetWindowTask(hWnd) ((HANDLE)(DWORD_PTR)GetWindowThreadProcessId(hWnd,NULL)) + + WINUSERAPI HWND WINAPI GetLastActivePopup(HWND hWnd); + +#define GW_HWNDFIRST 0 +#define GW_HWNDLAST 1 +#define GW_HWNDNEXT 2 +#define GW_HWNDPREV 3 +#define GW_OWNER 4 +#define GW_CHILD 5 +#define GW_ENABLEDPOPUP 6 +#define GW_MAX 6 + + WINUSERAPI HWND WINAPI GetWindow(HWND hWnd,UINT uCmd); + +#ifndef NOWH + +#ifdef UNICODE +#define SetWindowsHook SetWindowsHookW +#define SetWindowsHookEx SetWindowsHookExW +#else +#define SetWindowsHook SetWindowsHookA +#define SetWindowsHookEx SetWindowsHookExA +#endif + + WINUSERAPI HHOOK WINAPI SetWindowsHookA(int nFilterType,HOOKPROC pfnFilterProc); + WINUSERAPI HHOOK WINAPI SetWindowsHookW(int nFilterType,HOOKPROC pfnFilterProc); + WINUSERAPI WINBOOL WINAPI UnhookWindowsHook(int nCode,HOOKPROC pfnFilterProc); + WINUSERAPI HHOOK WINAPI SetWindowsHookExA(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); + WINUSERAPI HHOOK WINAPI SetWindowsHookExW(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); + WINUSERAPI WINBOOL WINAPI UnhookWindowsHookEx(HHOOK hhk); + WINUSERAPI LRESULT WINAPI CallNextHookEx(HHOOK hhk,int nCode,WPARAM wParam,LPARAM lParam); +#define DefHookProc(nCode,wParam,lParam,phhk) CallNextHookEx(*phhk,nCode,wParam,lParam) +#endif + +#ifndef NOMENUS + +#define MF_INSERT 0x00000000L +#define MF_CHANGE 0x00000080L +#define MF_APPEND 0x00000100L +#define MF_DELETE 0x00000200L +#define MF_REMOVE 0x00001000L +#define MF_BYCOMMAND 0x00000000L +#define MF_BYPOSITION 0x00000400L +#define MF_SEPARATOR 0x00000800L +#define MF_ENABLED 0x00000000L +#define MF_GRAYED 0x00000001L +#define MF_DISABLED 0x00000002L +#define MF_UNCHECKED 0x00000000L +#define MF_CHECKED 0x00000008L +#define MF_USECHECKBITMAPS 0x00000200L +#define MF_STRING 0x00000000L +#define MF_BITMAP 0x00000004L +#define MF_OWNERDRAW 0x00000100L +#define MF_POPUP 0x00000010L +#define MF_MENUBARBREAK 0x00000020L +#define MF_MENUBREAK 0x00000040L +#define MF_UNHILITE 0x00000000L +#define MF_HILITE 0x00000080L +#define MF_DEFAULT 0x00001000L +#define MF_SYSMENU 0x00002000L +#define MF_HELP 0x00004000L +#define MF_RIGHTJUSTIFY 0x00004000L +#define MF_MOUSESELECT 0x00008000L +#define MF_END 0x00000080L + +#define MFT_STRING MF_STRING +#define MFT_BITMAP MF_BITMAP +#define MFT_MENUBARBREAK MF_MENUBARBREAK +#define MFT_MENUBREAK MF_MENUBREAK +#define MFT_OWNERDRAW MF_OWNERDRAW +#define MFT_RADIOCHECK 0x00000200L +#define MFT_SEPARATOR MF_SEPARATOR +#define MFT_RIGHTORDER 0x00002000L +#define MFT_RIGHTJUSTIFY MF_RIGHTJUSTIFY + +#define MFS_GRAYED 0x00000003L +#define MFS_DISABLED MFS_GRAYED +#define MFS_CHECKED MF_CHECKED +#define MFS_HILITE MF_HILITE +#define MFS_ENABLED MF_ENABLED +#define MFS_UNCHECKED MF_UNCHECKED +#define MFS_UNHILITE MF_UNHILITE +#define MFS_DEFAULT MF_DEFAULT + + WINUSERAPI WINBOOL WINAPI CheckMenuRadioItem(HMENU hmenu,UINT first,UINT last,UINT check,UINT flags); + + typedef struct { + WORD versionNumber; + WORD offset; + } MENUITEMTEMPLATEHEADER,*PMENUITEMTEMPLATEHEADER; + + typedef struct { + WORD mtOption; + WORD mtID; + WCHAR mtString[1]; + } MENUITEMTEMPLATE,*PMENUITEMTEMPLATE; +#define MF_END 0x00000080L +#endif + +#ifndef NOSYSCOMMANDS + +#define SC_SIZE 0xF000 +#define SC_MOVE 0xF010 +#define SC_MINIMIZE 0xF020 +#define SC_MAXIMIZE 0xF030 +#define SC_NEXTWINDOW 0xF040 +#define SC_PREVWINDOW 0xF050 +#define SC_CLOSE 0xF060 +#define SC_VSCROLL 0xF070 +#define SC_HSCROLL 0xF080 +#define SC_MOUSEMENU 0xF090 +#define SC_KEYMENU 0xF100 +#define SC_ARRANGE 0xF110 +#define SC_RESTORE 0xF120 +#define SC_TASKLIST 0xF130 +#define SC_SCREENSAVE 0xF140 +#define SC_HOTKEY 0xF150 +#define SC_DEFAULT 0xF160 +#define SC_MONITORPOWER 0xF170 +#define SC_CONTEXTHELP 0xF180 +#define SC_SEPARATOR 0xF00F +#define SC_ICON SC_MINIMIZE +#define SC_ZOOM SC_MAXIMIZE +#endif + +#ifdef UNICODE +#define LoadBitmap LoadBitmapW +#define LoadCursor LoadCursorW +#define LoadCursorFromFile LoadCursorFromFileW +#else +#define LoadBitmap LoadBitmapA +#define LoadCursor LoadCursorA +#define LoadCursorFromFile LoadCursorFromFileA +#endif + + WINUSERAPI HBITMAP WINAPI LoadBitmapA(HINSTANCE hInstance,LPCSTR lpBitmapName); + WINUSERAPI HBITMAP WINAPI LoadBitmapW(HINSTANCE hInstance,LPCWSTR lpBitmapName); + WINUSERAPI HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance,LPCSTR lpCursorName); + WINUSERAPI HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance,LPCWSTR lpCursorName); + WINUSERAPI HCURSOR WINAPI LoadCursorFromFileA(LPCSTR lpFileName); + WINUSERAPI HCURSOR WINAPI LoadCursorFromFileW(LPCWSTR lpFileName); + WINUSERAPI HCURSOR WINAPI CreateCursor(HINSTANCE hInst,int xHotSpot,int yHotSpot,int nWidth,int nHeight,CONST VOID *pvANDPlane,CONST VOID *pvXORPlane); + WINUSERAPI WINBOOL WINAPI DestroyCursor(HCURSOR hCursor); + +#define CopyCursor(pcur) ((HCURSOR)CopyIcon((HICON)(pcur))) + +#define IDC_ARROW MAKEINTRESOURCE(32512) +#define IDC_IBEAM MAKEINTRESOURCE(32513) +#define IDC_WAIT MAKEINTRESOURCE(32514) +#define IDC_CROSS MAKEINTRESOURCE(32515) +#define IDC_UPARROW MAKEINTRESOURCE(32516) +#define IDC_SIZE MAKEINTRESOURCE(32640) +#define IDC_ICON MAKEINTRESOURCE(32641) +#define IDC_SIZENWSE MAKEINTRESOURCE(32642) +#define IDC_SIZENESW MAKEINTRESOURCE(32643) +#define IDC_SIZEWE MAKEINTRESOURCE(32644) +#define IDC_SIZENS MAKEINTRESOURCE(32645) +#define IDC_SIZEALL MAKEINTRESOURCE(32646) +#define IDC_NO MAKEINTRESOURCE(32648) +#define IDC_HAND MAKEINTRESOURCE(32649) +#define IDC_APPSTARTING MAKEINTRESOURCE(32650) +#define IDC_HELP MAKEINTRESOURCE(32651) + + WINUSERAPI WINBOOL WINAPI SetSystemCursor(HCURSOR hcur,DWORD id); + + typedef struct _ICONINFO { + WINBOOL fIcon; + DWORD xHotspot; + DWORD yHotspot; + HBITMAP hbmMask; + HBITMAP hbmColor; + } ICONINFO; + typedef ICONINFO *PICONINFO; + +#ifdef UNICODE +#define LoadIcon LoadIconW +#define PrivateExtractIcons PrivateExtractIconsW +#else +#define LoadIcon LoadIconA +#define PrivateExtractIcons PrivateExtractIconsA +#endif + + WINUSERAPI HICON WINAPI LoadIconA(HINSTANCE hInstance,LPCSTR lpIconName); + WINUSERAPI HICON WINAPI LoadIconW(HINSTANCE hInstance,LPCWSTR lpIconName); + WINUSERAPI UINT WINAPI PrivateExtractIconsA(LPCSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); + WINUSERAPI UINT WINAPI PrivateExtractIconsW(LPCWSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); + WINUSERAPI HICON WINAPI CreateIcon(HINSTANCE hInstance,int nWidth,int nHeight,BYTE cPlanes,BYTE cBitsPixel,CONST BYTE *lpbANDbits,CONST BYTE *lpbXORbits); + WINUSERAPI WINBOOL WINAPI DestroyIcon(HICON hIcon); + WINUSERAPI int WINAPI LookupIconIdFromDirectory(PBYTE presbits,WINBOOL fIcon); + WINUSERAPI int WINAPI LookupIconIdFromDirectoryEx(PBYTE presbits,WINBOOL fIcon,int cxDesired,int cyDesired,UINT Flags); + WINUSERAPI HICON WINAPI CreateIconFromResource(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer); + WINUSERAPI HICON WINAPI CreateIconFromResourceEx(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer,int cxDesired,int cyDesired,UINT Flags); + + typedef struct tagCURSORSHAPE { + int xHotSpot; + int yHotSpot; + int cx; + int cy; + int cbWidth; + BYTE Planes; + BYTE BitsPixel; + } CURSORSHAPE,*LPCURSORSHAPE; + +#define IMAGE_BITMAP 0 +#define IMAGE_ICON 1 +#define IMAGE_CURSOR 2 +#define IMAGE_ENHMETAFILE 3 + +#define LR_DEFAULTCOLOR 0x0000 +#define LR_MONOCHROME 0x0001 +#define LR_COLOR 0x0002 +#define LR_COPYRETURNORG 0x0004 +#define LR_COPYDELETEORG 0x0008 +#define LR_LOADFROMFILE 0x0010 +#define LR_LOADTRANSPARENT 0x0020 +#define LR_DEFAULTSIZE 0x0040 +#define LR_VGACOLOR 0x0080 +#define LR_LOADMAP3DCOLORS 0x1000 +#define LR_CREATEDIBSECTION 0x2000 +#define LR_COPYFROMRESOURCE 0x4000 +#define LR_SHARED 0x8000 + +#ifdef UNICODE +#define LoadImage LoadImageW +#else +#define LoadImage LoadImageA +#endif + + WINUSERAPI HANDLE WINAPI LoadImageA(HINSTANCE hInst,LPCSTR name,UINT type,int cx,int cy,UINT fuLoad); + WINUSERAPI HANDLE WINAPI LoadImageW(HINSTANCE hInst,LPCWSTR name,UINT type,int cx,int cy,UINT fuLoad); + WINUSERAPI HANDLE WINAPI CopyImage(HANDLE h,UINT type,int cx,int cy,UINT flags); + +#define DI_MASK 0x0001 +#define DI_IMAGE 0x0002 +#define DI_NORMAL 0x0003 +#define DI_COMPAT 0x0004 +#define DI_DEFAULTSIZE 0x0008 +#define DI_NOMIRROR 0x0010 + + WINUSERAPI WINBOOL WINAPI DrawIconEx(HDC hdc,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyWidth,UINT istepIfAniCur,HBRUSH hbrFlickerFreeDraw,UINT diFlags); + WINUSERAPI HICON WINAPI CreateIconIndirect(PICONINFO piconinfo); + WINUSERAPI HICON WINAPI CopyIcon(HICON hIcon); + WINUSERAPI WINBOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO piconinfo); + +#define RES_ICON 1 +#define RES_CURSOR 2 + +#ifdef OEMRESOURCE + +#define OBM_CLOSE 32754 +#define OBM_UPARROW 32753 +#define OBM_DNARROW 32752 +#define OBM_RGARROW 32751 +#define OBM_LFARROW 32750 +#define OBM_REDUCE 32749 +#define OBM_ZOOM 32748 +#define OBM_RESTORE 32747 +#define OBM_REDUCED 32746 +#define OBM_ZOOMD 32745 +#define OBM_RESTORED 32744 +#define OBM_UPARROWD 32743 +#define OBM_DNARROWD 32742 +#define OBM_RGARROWD 32741 +#define OBM_LFARROWD 32740 +#define OBM_MNARROW 32739 +#define OBM_COMBO 32738 +#define OBM_UPARROWI 32737 +#define OBM_DNARROWI 32736 +#define OBM_RGARROWI 32735 +#define OBM_LFARROWI 32734 + +#define OBM_OLD_CLOSE 32767 +#define OBM_SIZE 32766 +#define OBM_OLD_UPARROW 32765 +#define OBM_OLD_DNARROW 32764 +#define OBM_OLD_RGARROW 32763 +#define OBM_OLD_LFARROW 32762 +#define OBM_BTSIZE 32761 +#define OBM_CHECK 32760 +#define OBM_CHECKBOXES 32759 +#define OBM_BTNCORNERS 32758 +#define OBM_OLD_REDUCE 32757 +#define OBM_OLD_ZOOM 32756 +#define OBM_OLD_RESTORE 32755 + +#define OCR_NORMAL 32512 +#define OCR_IBEAM 32513 +#define OCR_WAIT 32514 +#define OCR_CROSS 32515 +#define OCR_UP 32516 +#define OCR_SIZE 32640 +#define OCR_ICON 32641 +#define OCR_SIZENWSE 32642 +#define OCR_SIZENESW 32643 +#define OCR_SIZEWE 32644 +#define OCR_SIZENS 32645 +#define OCR_SIZEALL 32646 +#define OCR_ICOCUR 32647 +#define OCR_NO 32648 +#define OCR_HAND 32649 +#define OCR_APPSTARTING 32650 + +#define OIC_SAMPLE 32512 +#define OIC_HAND 32513 +#define OIC_QUES 32514 +#define OIC_BANG 32515 +#define OIC_NOTE 32516 +#define OIC_WINLOGO 32517 +#define OIC_WARNING OIC_BANG +#define OIC_ERROR OIC_HAND +#define OIC_INFORMATION OIC_NOTE +#endif + +#define ORD_LANGDRIVER 1 + +#ifndef NOICONS + +#ifdef RC_INVOKED +#define IDI_APPLICATION 32512 +#define IDI_HAND 32513 +#define IDI_QUESTION 32514 +#define IDI_EXCLAMATION 32515 +#define IDI_ASTERISK 32516 +#define IDI_WINLOGO 32517 +#else +#define IDI_APPLICATION MAKEINTRESOURCE(32512) +#define IDI_HAND MAKEINTRESOURCE(32513) +#define IDI_QUESTION MAKEINTRESOURCE(32514) +#define IDI_EXCLAMATION MAKEINTRESOURCE(32515) +#define IDI_ASTERISK MAKEINTRESOURCE(32516) +#define IDI_WINLOGO MAKEINTRESOURCE(32517) +#endif + +#define IDI_WARNING IDI_EXCLAMATION +#define IDI_ERROR IDI_HAND +#define IDI_INFORMATION IDI_ASTERISK +#endif + +#ifdef UNICODE +#define LoadString LoadStringW +#else +#define LoadString LoadStringA +#endif + + WINUSERAPI int WINAPI LoadStringA(HINSTANCE hInstance,UINT uID,LPSTR lpBuffer,int cchBufferMax); + WINUSERAPI int WINAPI LoadStringW(HINSTANCE hInstance,UINT uID,LPWSTR lpBuffer,int cchBufferMax); + +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 +#define IDCLOSE 8 +#define IDHELP 9 +#define IDTRYAGAIN 10 +#define IDCONTINUE 11 + +#ifndef IDTIMEOUT +#define IDTIMEOUT 32000 +#endif + +#ifndef NOCTLMGR + +#ifndef NOWINSTYLES +#define ES_LEFT 0x0000L +#define ES_CENTER 0x0001L +#define ES_RIGHT 0x0002L +#define ES_MULTILINE 0x0004L +#define ES_UPPERCASE 0x0008L +#define ES_LOWERCASE 0x0010L +#define ES_PASSWORD 0x0020L +#define ES_AUTOVSCROLL 0x0040L +#define ES_AUTOHSCROLL 0x0080L +#define ES_NOHIDESEL 0x0100L +#define ES_OEMCONVERT 0x0400L +#define ES_READONLY 0x0800L +#define ES_WANTRETURN 0x1000L +#define ES_NUMBER 0x2000L +#endif + +#define EN_SETFOCUS 0x0100 +#define EN_KILLFOCUS 0x0200 +#define EN_CHANGE 0x0300 +#define EN_UPDATE 0x0400 +#define EN_ERRSPACE 0x0500 +#define EN_MAXTEXT 0x0501 +#define EN_HSCROLL 0x0601 +#define EN_VSCROLL 0x0602 +#define EN_ALIGN_LTR_EC 0x0700 +#define EN_ALIGN_RTL_EC 0x0701 + +#define EC_LEFTMARGIN 0x0001 +#define EC_RIGHTMARGIN 0x0002 +#define EC_USEFONTINFO 0xffff + +#define EMSIS_COMPOSITIONSTRING 0x0001 + +#define EIMES_GETCOMPSTRATONCE 0x0001 +#define EIMES_CANCELCOMPSTRINFOCUS 0x0002 +#define EIMES_COMPLETECOMPSTRKILLFOCUS 0x0004 + +#ifndef NOWINMESSAGES + +#define EM_GETSEL 0x00B0 +#define EM_SETSEL 0x00B1 +#define EM_GETRECT 0x00B2 +#define EM_SETRECT 0x00B3 +#define EM_SETRECTNP 0x00B4 +#define EM_SCROLL 0x00B5 +#define EM_LINESCROLL 0x00B6 +#define EM_SCROLLCARET 0x00B7 +#define EM_GETMODIFY 0x00B8 +#define EM_SETMODIFY 0x00B9 +#define EM_GETLINECOUNT 0x00BA +#define EM_LINEINDEX 0x00BB +#define EM_SETHANDLE 0x00BC +#define EM_GETHANDLE 0x00BD +#define EM_GETTHUMB 0x00BE +#define EM_LINELENGTH 0x00C1 +#define EM_REPLACESEL 0x00C2 +#define EM_GETLINE 0x00C4 +#define EM_LIMITTEXT 0x00C5 +#define EM_CANUNDO 0x00C6 +#define EM_UNDO 0x00C7 +#define EM_FMTLINES 0x00C8 +#define EM_LINEFROMCHAR 0x00C9 +#define EM_SETTABSTOPS 0x00CB +#define EM_SETPASSWORDCHAR 0x00CC +#define EM_EMPTYUNDOBUFFER 0x00CD +#define EM_GETFIRSTVISIBLELINE 0x00CE +#define EM_SETREADONLY 0x00CF +#define EM_SETWORDBREAKPROC 0x00D0 +#define EM_GETWORDBREAKPROC 0x00D1 +#define EM_GETPASSWORDCHAR 0x00D2 +#define EM_SETMARGINS 0x00D3 +#define EM_GETMARGINS 0x00D4 +#define EM_SETLIMITTEXT EM_LIMITTEXT +#define EM_GETLIMITTEXT 0x00D5 +#define EM_POSFROMCHAR 0x00D6 +#define EM_CHARFROMPOS 0x00D7 +#define EM_SETIMESTATUS 0x00D8 +#define EM_GETIMESTATUS 0x00D9 +#endif + +#define WB_LEFT 0 +#define WB_RIGHT 1 +#define WB_ISDELIMITER 2 + +#define BS_PUSHBUTTON 0x00000000L +#define BS_DEFPUSHBUTTON 0x00000001L +#define BS_CHECKBOX 0x00000002L +#define BS_AUTOCHECKBOX 0x00000003L +#define BS_RADIOBUTTON 0x00000004L +#define BS_3STATE 0x00000005L +#define BS_AUTO3STATE 0x00000006L +#define BS_GROUPBOX 0x00000007L +#define BS_USERBUTTON 0x00000008L +#define BS_AUTORADIOBUTTON 0x00000009L +#define BS_PUSHBOX 0x0000000AL +#define BS_OWNERDRAW 0x0000000BL +#define BS_TYPEMASK 0x0000000FL +#define BS_LEFTTEXT 0x00000020L +#define BS_TEXT 0x00000000L +#define BS_ICON 0x00000040L +#define BS_BITMAP 0x00000080L +#define BS_LEFT 0x00000100L +#define BS_RIGHT 0x00000200L +#define BS_CENTER 0x00000300L +#define BS_TOP 0x00000400L +#define BS_BOTTOM 0x00000800L +#define BS_VCENTER 0x00000C00L +#define BS_PUSHLIKE 0x00001000L +#define BS_MULTILINE 0x00002000L +#define BS_NOTIFY 0x00004000L +#define BS_FLAT 0x00008000L +#define BS_RIGHTBUTTON BS_LEFTTEXT + +#define BN_CLICKED 0 +#define BN_PAINT 1 +#define BN_HILITE 2 +#define BN_UNHILITE 3 +#define BN_DISABLE 4 +#define BN_DOUBLECLICKED 5 +#define BN_PUSHED BN_HILITE +#define BN_UNPUSHED BN_UNHILITE +#define BN_DBLCLK BN_DOUBLECLICKED +#define BN_SETFOCUS 6 +#define BN_KILLFOCUS 7 + +#define BM_GETCHECK 0x00F0 +#define BM_SETCHECK 0x00F1 +#define BM_GETSTATE 0x00F2 +#define BM_SETSTATE 0x00F3 +#define BM_SETSTYLE 0x00F4 +#define BM_CLICK 0x00F5 +#define BM_GETIMAGE 0x00F6 +#define BM_SETIMAGE 0x00F7 + +#define BST_UNCHECKED 0x0000 +#define BST_CHECKED 0x0001 +#define BST_INDETERMINATE 0x0002 +#define BST_PUSHED 0x0004 +#define BST_FOCUS 0x0008 + +#define SS_LEFT 0x00000000L +#define SS_CENTER 0x00000001L +#define SS_RIGHT 0x00000002L +#define SS_ICON 0x00000003L +#define SS_BLACKRECT 0x00000004L +#define SS_GRAYRECT 0x00000005L +#define SS_WHITERECT 0x00000006L +#define SS_BLACKFRAME 0x00000007L +#define SS_GRAYFRAME 0x00000008L +#define SS_WHITEFRAME 0x00000009L +#define SS_USERITEM 0x0000000AL +#define SS_SIMPLE 0x0000000BL +#define SS_LEFTNOWORDWRAP 0x0000000CL +#define SS_OWNERDRAW 0x0000000DL +#define SS_BITMAP 0x0000000EL +#define SS_ENHMETAFILE 0x0000000FL +#define SS_ETCHEDHORZ 0x00000010L +#define SS_ETCHEDVERT 0x00000011L +#define SS_ETCHEDFRAME 0x00000012L +#define SS_TYPEMASK 0x0000001FL +#define SS_REALSIZECONTROL 0x00000040L +#define SS_NOPREFIX 0x00000080L +#define SS_NOTIFY 0x00000100L +#define SS_CENTERIMAGE 0x00000200L +#define SS_RIGHTJUST 0x00000400L +#define SS_REALSIZEIMAGE 0x00000800L +#define SS_SUNKEN 0x00001000L +#define SS_EDITCONTROL 0x00002000L +#define SS_ENDELLIPSIS 0x00004000L +#define SS_PATHELLIPSIS 0x00008000L +#define SS_WORDELLIPSIS 0x0000C000L +#define SS_ELLIPSISMASK 0x0000C000L + +#ifndef NOWINMESSAGES + +#define STM_SETICON 0x0170 +#define STM_GETICON 0x0171 +#define STM_SETIMAGE 0x0172 +#define STM_GETIMAGE 0x0173 +#define STN_CLICKED 0 +#define STN_DBLCLK 1 +#define STN_ENABLE 2 +#define STN_DISABLE 3 +#define STM_MSGMAX 0x0174 +#endif + +#define WC_DIALOG (MAKEINTATOM(0x8002)) + +#define DWL_MSGRESULT 0 +#define DWL_DLGPROC 4 +#define DWL_USER 8 + +#ifdef _WIN64 + +#undef DWL_MSGRESULT +#undef DWL_DLGPROC +#undef DWL_USER +#endif + +#define DWLP_MSGRESULT 0 +#define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) +#define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) + +#ifndef NOMSG + +#ifdef UNICODE +#define IsDialogMessage IsDialogMessageW +#else +#define IsDialogMessage IsDialogMessageA +#endif + + WINUSERAPI WINBOOL WINAPI IsDialogMessageA(HWND hDlg,LPMSG lpMsg); + WINUSERAPI WINBOOL WINAPI IsDialogMessageW(HWND hDlg,LPMSG lpMsg); +#endif + +#ifdef UNICODE +#define DlgDirList DlgDirListW +#define DlgDirSelectEx DlgDirSelectExW +#define DlgDirListComboBox DlgDirListComboBoxW +#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExW +#else +#define DlgDirList DlgDirListA +#define DlgDirSelectEx DlgDirSelectExA +#define DlgDirListComboBox DlgDirListComboBoxA +#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExA +#endif + + WINUSERAPI WINBOOL WINAPI MapDialogRect(HWND hDlg,LPRECT lpRect); + WINUSERAPI int WINAPI DlgDirListA(HWND hDlg,LPSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); + WINUSERAPI int WINAPI DlgDirListW(HWND hDlg,LPWSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); + +#define DDL_READWRITE 0x0000 +#define DDL_READONLY 0x0001 +#define DDL_HIDDEN 0x0002 +#define DDL_SYSTEM 0x0004 +#define DDL_DIRECTORY 0x0010 +#define DDL_ARCHIVE 0x0020 + +#define DDL_POSTMSGS 0x2000 +#define DDL_DRIVES 0x4000 +#define DDL_EXCLUSIVE 0x8000 + + WINUSERAPI WINBOOL WINAPI DlgDirSelectExA(HWND hwndDlg,LPSTR lpString,int chCount,int idListBox); + WINUSERAPI WINBOOL WINAPI DlgDirSelectExW(HWND hwndDlg,LPWSTR lpString,int chCount,int idListBox); + WINUSERAPI int WINAPI DlgDirListComboBoxA(HWND hDlg,LPSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); + WINUSERAPI int WINAPI DlgDirListComboBoxW(HWND hDlg,LPWSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); + WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExA(HWND hwndDlg,LPSTR lpString,int cchOut,int idComboBox); + WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExW(HWND hwndDlg,LPWSTR lpString,int cchOut,int idComboBox); + +#define DS_ABSALIGN 0x01L +#define DS_SYSMODAL 0x02L +#define DS_LOCALEDIT 0x20L +#define DS_SETFONT 0x40L +#define DS_MODALFRAME 0x80L +#define DS_NOIDLEMSG 0x100L +#define DS_SETFOREGROUND 0x200L + +#define DS_3DLOOK 0x0004L +#define DS_FIXEDSYS 0x0008L +#define DS_NOFAILCREATE 0x0010L +#define DS_CONTROL 0x0400L +#define DS_CENTER 0x0800L +#define DS_CENTERMOUSE 0x1000L +#define DS_CONTEXTHELP 0x2000L + +#define DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS) + +#if(_WIN32_WCE >= 0x0500) +#define DS_USEPIXELS 0x8000L +#endif + +#define DM_GETDEFID (WM_USER+0) +#define DM_SETDEFID (WM_USER+1) +#define DM_REPOSITION (WM_USER+2) + +#define DC_HASDEFID 0x534B + +#define DLGC_WANTARROWS 0x0001 +#define DLGC_WANTTAB 0x0002 +#define DLGC_WANTALLKEYS 0x0004 +#define DLGC_WANTMESSAGE 0x0004 +#define DLGC_HASSETSEL 0x0008 +#define DLGC_DEFPUSHBUTTON 0x0010 +#define DLGC_UNDEFPUSHBUTTON 0x0020 +#define DLGC_RADIOBUTTON 0x0040 +#define DLGC_WANTCHARS 0x0080 +#define DLGC_STATIC 0x0100 +#define DLGC_BUTTON 0x2000 + +#define LB_CTLCODE 0L + +#define LB_OKAY 0 +#define LB_ERR (-1) +#define LB_ERRSPACE (-2) + +#define LBN_ERRSPACE (-2) +#define LBN_SELCHANGE 1 +#define LBN_DBLCLK 2 +#define LBN_SELCANCEL 3 +#define LBN_SETFOCUS 4 +#define LBN_KILLFOCUS 5 + +#ifndef NOWINMESSAGES + +#define LB_ADDSTRING 0x0180 +#define LB_INSERTSTRING 0x0181 +#define LB_DELETESTRING 0x0182 +#define LB_SELITEMRANGEEX 0x0183 +#define LB_RESETCONTENT 0x0184 +#define LB_SETSEL 0x0185 +#define LB_SETCURSEL 0x0186 +#define LB_GETSEL 0x0187 +#define LB_GETCURSEL 0x0188 +#define LB_GETTEXT 0x0189 +#define LB_GETTEXTLEN 0x018A +#define LB_GETCOUNT 0x018B +#define LB_SELECTSTRING 0x018C +#define LB_DIR 0x018D +#define LB_GETTOPINDEX 0x018E +#define LB_FINDSTRING 0x018F +#define LB_GETSELCOUNT 0x0190 +#define LB_GETSELITEMS 0x0191 +#define LB_SETTABSTOPS 0x0192 +#define LB_GETHORIZONTALEXTENT 0x0193 +#define LB_SETHORIZONTALEXTENT 0x0194 +#define LB_SETCOLUMNWIDTH 0x0195 +#define LB_ADDFILE 0x0196 +#define LB_SETTOPINDEX 0x0197 +#define LB_GETITEMRECT 0x0198 +#define LB_GETITEMDATA 0x0199 +#define LB_SETITEMDATA 0x019A +#define LB_SELITEMRANGE 0x019B +#define LB_SETANCHORINDEX 0x019C +#define LB_GETANCHORINDEX 0x019D +#define LB_SETCARETINDEX 0x019E +#define LB_GETCARETINDEX 0x019F +#define LB_SETITEMHEIGHT 0x01A0 +#define LB_GETITEMHEIGHT 0x01A1 +#define LB_FINDSTRINGEXACT 0x01A2 +#define LB_SETLOCALE 0x01A5 +#define LB_GETLOCALE 0x01A6 +#define LB_SETCOUNT 0x01A7 +#define LB_INITSTORAGE 0x01A8 +#define LB_ITEMFROMPOINT 0x01A9 +#if(_WIN32_WCE >= 0x0400) +#define LB_MULTIPLEADDSTRING 0x01B1 +#endif +#define LB_GETLISTBOXINFO 0x01B2 +#define LB_MSGMAX 0x01B3 +#endif + +#ifndef NOWINSTYLES + +#define LBS_NOTIFY 0x0001L +#define LBS_SORT 0x0002L +#define LBS_NOREDRAW 0x0004L +#define LBS_MULTIPLESEL 0x0008L +#define LBS_OWNERDRAWFIXED 0x0010L +#define LBS_OWNERDRAWVARIABLE 0x0020L +#define LBS_HASSTRINGS 0x0040L +#define LBS_USETABSTOPS 0x0080L +#define LBS_NOINTEGRALHEIGHT 0x0100L +#define LBS_MULTICOLUMN 0x0200L +#define LBS_WANTKEYBOARDINPUT 0x0400L +#define LBS_EXTENDEDSEL 0x0800L +#define LBS_DISABLENOSCROLL 0x1000L +#define LBS_NODATA 0x2000L +#define LBS_NOSEL 0x4000L +#define LBS_COMBOBOX 0x8000L + +#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER) +#endif + +#define CB_OKAY 0 +#define CB_ERR (-1) +#define CB_ERRSPACE (-2) + +#define CBN_ERRSPACE (-1) +#define CBN_SELCHANGE 1 +#define CBN_DBLCLK 2 +#define CBN_SETFOCUS 3 +#define CBN_KILLFOCUS 4 +#define CBN_EDITCHANGE 5 +#define CBN_EDITUPDATE 6 +#define CBN_DROPDOWN 7 +#define CBN_CLOSEUP 8 +#define CBN_SELENDOK 9 +#define CBN_SELENDCANCEL 10 + +#ifndef NOWINSTYLES + +#define CBS_SIMPLE 0x0001L +#define CBS_DROPDOWN 0x0002L +#define CBS_DROPDOWNLIST 0x0003L +#define CBS_OWNERDRAWFIXED 0x0010L +#define CBS_OWNERDRAWVARIABLE 0x0020L +#define CBS_AUTOHSCROLL 0x0040L +#define CBS_OEMCONVERT 0x0080L +#define CBS_SORT 0x0100L +#define CBS_HASSTRINGS 0x0200L +#define CBS_NOINTEGRALHEIGHT 0x0400L +#define CBS_DISABLENOSCROLL 0x0800L +#define CBS_UPPERCASE 0x2000L +#define CBS_LOWERCASE 0x4000L +#endif + +#ifndef NOWINMESSAGES +#define CB_GETEDITSEL 0x0140 +#define CB_LIMITTEXT 0x0141 +#define CB_SETEDITSEL 0x0142 +#define CB_ADDSTRING 0x0143 +#define CB_DELETESTRING 0x0144 +#define CB_DIR 0x0145 +#define CB_GETCOUNT 0x0146 +#define CB_GETCURSEL 0x0147 +#define CB_GETLBTEXT 0x0148 +#define CB_GETLBTEXTLEN 0x0149 +#define CB_INSERTSTRING 0x014A +#define CB_RESETCONTENT 0x014B +#define CB_FINDSTRING 0x014C +#define CB_SELECTSTRING 0x014D +#define CB_SETCURSEL 0x014E +#define CB_SHOWDROPDOWN 0x014F +#define CB_GETITEMDATA 0x0150 +#define CB_SETITEMDATA 0x0151 +#define CB_GETDROPPEDCONTROLRECT 0x0152 +#define CB_SETITEMHEIGHT 0x0153 +#define CB_GETITEMHEIGHT 0x0154 +#define CB_SETEXTENDEDUI 0x0155 +#define CB_GETEXTENDEDUI 0x0156 +#define CB_GETDROPPEDSTATE 0x0157 +#define CB_FINDSTRINGEXACT 0x0158 +#define CB_SETLOCALE 0x0159 +#define CB_GETLOCALE 0x015A +#define CB_GETTOPINDEX 0x015b +#define CB_SETTOPINDEX 0x015c +#define CB_GETHORIZONTALEXTENT 0x015d +#define CB_SETHORIZONTALEXTENT 0x015e +#define CB_GETDROPPEDWIDTH 0x015f +#define CB_SETDROPPEDWIDTH 0x0160 +#define CB_INITSTORAGE 0x0161 +#if(_WIN32_WCE >= 0x0400) +#define CB_MULTIPLEADDSTRING 0x0163 +#endif +#define CB_GETCOMBOBOXINFO 0x0164 +#define CB_MSGMAX 0x0165 +#endif + +#ifndef NOWINSTYLES + +#define SBS_HORZ 0x0000L +#define SBS_VERT 0x0001L +#define SBS_TOPALIGN 0x0002L +#define SBS_LEFTALIGN 0x0002L +#define SBS_BOTTOMALIGN 0x0004L +#define SBS_RIGHTALIGN 0x0004L +#define SBS_SIZEBOXTOPLEFTALIGN 0x0002L +#define SBS_SIZEBOXBOTTOMRIGHTALIGN 0x0004L +#define SBS_SIZEBOX 0x0008L +#define SBS_SIZEGRIP 0x0010L +#endif + +#ifndef NOWINMESSAGES +#define SBM_SETPOS 0x00E0 +#define SBM_GETPOS 0x00E1 +#define SBM_SETRANGE 0x00E2 +#define SBM_SETRANGEREDRAW 0x00E6 +#define SBM_GETRANGE 0x00E3 +#define SBM_ENABLE_ARROWS 0x00E4 +#define SBM_SETSCROLLINFO 0x00E9 +#define SBM_GETSCROLLINFO 0x00EA +#define SBM_GETSCROLLBARINFO 0x00EB + +#define SIF_RANGE 0x0001 +#define SIF_PAGE 0x0002 +#define SIF_POS 0x0004 +#define SIF_DISABLENOSCROLL 0x0008 +#define SIF_TRACKPOS 0x0010 +#define SIF_ALL (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS) + + typedef struct tagSCROLLINFO { + UINT cbSize; + UINT fMask; + int nMin; + int nMax; + UINT nPage; + int nPos; + int nTrackPos; + } SCROLLINFO,*LPSCROLLINFO; + typedef SCROLLINFO CONST *LPCSCROLLINFO; + + WINUSERAPI int WINAPI SetScrollInfo(HWND hwnd,int nBar,LPCSCROLLINFO lpsi,WINBOOL redraw); + WINUSERAPI WINBOOL WINAPI GetScrollInfo(HWND hwnd,int nBar,LPSCROLLINFO lpsi); +#endif +#endif + +#ifndef NOMDI + +#define MDIS_ALLCHILDSTYLES 0x0001 + +#define MDITILE_VERTICAL 0x0000 +#define MDITILE_HORIZONTAL 0x0001 +#define MDITILE_SKIPDISABLED 0x0002 +#define MDITILE_ZORDER 0x0004 + + typedef struct tagMDICREATESTRUCTA { + LPCSTR szClass; + LPCSTR szTitle; + HANDLE hOwner; + int x; + int y; + int cx; + int cy; + DWORD style; + LPARAM lParam; + } MDICREATESTRUCTA,*LPMDICREATESTRUCTA; + + typedef struct tagMDICREATESTRUCTW { + LPCWSTR szClass; + LPCWSTR szTitle; + HANDLE hOwner; + int x; + int y; + int cx; + int cy; + DWORD style; + LPARAM lParam; + } MDICREATESTRUCTW,*LPMDICREATESTRUCTW; + +#ifdef UNICODE + typedef MDICREATESTRUCTW MDICREATESTRUCT; + typedef LPMDICREATESTRUCTW LPMDICREATESTRUCT; +#else + typedef MDICREATESTRUCTA MDICREATESTRUCT; + typedef LPMDICREATESTRUCTA LPMDICREATESTRUCT; +#endif + + typedef struct tagCLIENTCREATESTRUCT { + HANDLE hWindowMenu; + UINT idFirstChild; + } CLIENTCREATESTRUCT,*LPCLIENTCREATESTRUCT; + +#ifdef UNICODE +#define DefFrameProc DefFrameProcW +#define DefMDIChildProc DefMDIChildProcW +#define CreateMDIWindow CreateMDIWindowW +#else +#define DefFrameProc DefFrameProcA +#define DefMDIChildProc DefMDIChildProcA +#define CreateMDIWindow CreateMDIWindowA +#endif + + WINUSERAPI LRESULT WINAPI DefFrameProcA(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefFrameProcW(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefMDIChildProcA(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefMDIChildProcW(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); + +#ifndef NOMSG + WINUSERAPI WINBOOL WINAPI TranslateMDISysAccel(HWND hWndClient,LPMSG lpMsg); +#endif + + WINUSERAPI UINT WINAPI ArrangeIconicWindows(HWND hWnd); + WINUSERAPI HWND WINAPI CreateMDIWindowA(LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); + WINUSERAPI HWND WINAPI CreateMDIWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); + WINUSERAPI WORD WINAPI TileWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); + WINUSERAPI WORD WINAPI CascadeWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); +#endif +#endif + +#ifndef NOHELP + + typedef DWORD HELPPOLY; + typedef struct tagMULTIKEYHELPA { + DWORD mkSize; + CHAR mkKeylist; + CHAR szKeyphrase[1]; + } MULTIKEYHELPA,*PMULTIKEYHELPA,*LPMULTIKEYHELPA; + + typedef struct tagMULTIKEYHELPW { + DWORD mkSize; + WCHAR mkKeylist; + WCHAR szKeyphrase[1]; + } MULTIKEYHELPW,*PMULTIKEYHELPW,*LPMULTIKEYHELPW; + +#ifdef UNICODE + typedef MULTIKEYHELPW MULTIKEYHELP; + typedef PMULTIKEYHELPW PMULTIKEYHELP; + typedef LPMULTIKEYHELPW LPMULTIKEYHELP; +#else + typedef MULTIKEYHELPA MULTIKEYHELP; + typedef PMULTIKEYHELPA PMULTIKEYHELP; + typedef LPMULTIKEYHELPA LPMULTIKEYHELP; +#endif + + typedef struct tagHELPWININFOA { + int wStructSize; + int x; + int y; + int dx; + int dy; + int wMax; + CHAR rgchMember[2]; + } HELPWININFOA,*PHELPWININFOA,*LPHELPWININFOA; + + typedef struct tagHELPWININFOW { + int wStructSize; + int x; + int y; + int dx; + int dy; + int wMax; + WCHAR rgchMember[2]; + } HELPWININFOW,*PHELPWININFOW,*LPHELPWININFOW; + +#ifdef UNICODE + typedef HELPWININFOW HELPWININFO; + typedef PHELPWININFOW PHELPWININFO; + typedef LPHELPWININFOW LPHELPWININFO; +#else + typedef HELPWININFOA HELPWININFO; + typedef PHELPWININFOA PHELPWININFO; + typedef LPHELPWININFOA LPHELPWININFO; +#endif + +#define HELP_CONTEXT 0x0001L +#define HELP_QUIT 0x0002L +#define HELP_INDEX 0x0003L +#define HELP_CONTENTS 0x0003L +#define HELP_HELPONHELP 0x0004L +#define HELP_SETINDEX 0x0005L +#define HELP_SETCONTENTS 0x0005L +#define HELP_CONTEXTPOPUP 0x0008L +#define HELP_FORCEFILE 0x0009L +#define HELP_KEY 0x0101L +#define HELP_COMMAND 0x0102L +#define HELP_PARTIALKEY 0x0105L +#define HELP_MULTIKEY 0x0201L +#define HELP_SETWINPOS 0x0203L +#define HELP_CONTEXTMENU 0x000a +#define HELP_FINDER 0x000b +#define HELP_WM_HELP 0x000c +#define HELP_SETPOPUP_POS 0x000d + +#define HELP_TCARD 0x8000 +#define HELP_TCARD_DATA 0x0010 +#define HELP_TCARD_OTHER_CALLER 0x0011 + +#define IDH_NO_HELP 28440 +#define IDH_MISSING_CONTEXT 28441 +#define IDH_GENERIC_HELP_BUTTON 28442 +#define IDH_OK 28443 +#define IDH_CANCEL 28444 +#define IDH_HELP 28445 + +#ifdef UNICODE +#define WinHelp WinHelpW +#else +#define WinHelp WinHelpA +#endif + + WINUSERAPI WINBOOL WINAPI WinHelpA(HWND hWndMain,LPCSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); + WINUSERAPI WINBOOL WINAPI WinHelpW(HWND hWndMain,LPCWSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); +#endif + +#define GR_GDIOBJECTS 0 +#define GR_USEROBJECTS 1 + + WINUSERAPI DWORD WINAPI GetGuiResources(HANDLE hProcess,DWORD uiFlags); + +#ifndef NOSYSPARAMSINFO + +#define SPI_GETBEEP 0x0001 +#define SPI_SETBEEP 0x0002 +#define SPI_GETMOUSE 0x0003 +#define SPI_SETMOUSE 0x0004 +#define SPI_GETBORDER 0x0005 +#define SPI_SETBORDER 0x0006 +#define SPI_GETKEYBOARDSPEED 0x000A +#define SPI_SETKEYBOARDSPEED 0x000B +#define SPI_LANGDRIVER 0x000C +#define SPI_ICONHORIZONTALSPACING 0x000D +#define SPI_GETSCREENSAVETIMEOUT 0x000E +#define SPI_SETSCREENSAVETIMEOUT 0x000F +#define SPI_GETSCREENSAVEACTIVE 0x0010 +#define SPI_SETSCREENSAVEACTIVE 0x0011 +#define SPI_GETGRIDGRANULARITY 0x0012 +#define SPI_SETGRIDGRANULARITY 0x0013 +#define SPI_SETDESKWALLPAPER 0x0014 +#define SPI_SETDESKPATTERN 0x0015 +#define SPI_GETKEYBOARDDELAY 0x0016 +#define SPI_SETKEYBOARDDELAY 0x0017 +#define SPI_ICONVERTICALSPACING 0x0018 +#define SPI_GETICONTITLEWRAP 0x0019 +#define SPI_SETICONTITLEWRAP 0x001A +#define SPI_GETMENUDROPALIGNMENT 0x001B +#define SPI_SETMENUDROPALIGNMENT 0x001C +#define SPI_SETDOUBLECLKWIDTH 0x001D +#define SPI_SETDOUBLECLKHEIGHT 0x001E +#define SPI_GETICONTITLELOGFONT 0x001F +#define SPI_SETDOUBLECLICKTIME 0x0020 +#define SPI_SETMOUSEBUTTONSWAP 0x0021 +#define SPI_SETICONTITLELOGFONT 0x0022 +#define SPI_GETFASTTASKSWITCH 0x0023 +#define SPI_SETFASTTASKSWITCH 0x0024 +#define SPI_SETDRAGFULLWINDOWS 0x0025 +#define SPI_GETDRAGFULLWINDOWS 0x0026 +#define SPI_GETNONCLIENTMETRICS 0x0029 +#define SPI_SETNONCLIENTMETRICS 0x002A +#define SPI_GETMINIMIZEDMETRICS 0x002B +#define SPI_SETMINIMIZEDMETRICS 0x002C +#define SPI_GETICONMETRICS 0x002D +#define SPI_SETICONMETRICS 0x002E +#define SPI_SETWORKAREA 0x002F +#define SPI_GETWORKAREA 0x0030 +#define SPI_SETPENWINDOWS 0x0031 + +#define SPI_GETHIGHCONTRAST 0x0042 +#define SPI_SETHIGHCONTRAST 0x0043 +#define SPI_GETKEYBOARDPREF 0x0044 +#define SPI_SETKEYBOARDPREF 0x0045 +#define SPI_GETSCREENREADER 0x0046 +#define SPI_SETSCREENREADER 0x0047 +#define SPI_GETANIMATION 0x0048 +#define SPI_SETANIMATION 0x0049 +#define SPI_GETFONTSMOOTHING 0x004A +#define SPI_SETFONTSMOOTHING 0x004B +#define SPI_SETDRAGWIDTH 0x004C +#define SPI_SETDRAGHEIGHT 0x004D +#define SPI_SETHANDHELD 0x004E +#define SPI_GETLOWPOWERTIMEOUT 0x004F +#define SPI_GETPOWEROFFTIMEOUT 0x0050 +#define SPI_SETLOWPOWERTIMEOUT 0x0051 +#define SPI_SETPOWEROFFTIMEOUT 0x0052 +#define SPI_GETLOWPOWERACTIVE 0x0053 +#define SPI_GETPOWEROFFACTIVE 0x0054 +#define SPI_SETLOWPOWERACTIVE 0x0055 +#define SPI_SETPOWEROFFACTIVE 0x0056 +#define SPI_SETCURSORS 0x0057 +#define SPI_SETICONS 0x0058 +#define SPI_GETDEFAULTINPUTLANG 0x0059 +#define SPI_SETDEFAULTINPUTLANG 0x005A +#define SPI_SETLANGTOGGLE 0x005B +#define SPI_GETWINDOWSEXTENSION 0x005C +#define SPI_SETMOUSETRAILS 0x005D +#define SPI_GETMOUSETRAILS 0x005E +#define SPI_SETSCREENSAVERRUNNING 0x0061 +#define SPI_SCREENSAVERRUNNING SPI_SETSCREENSAVERRUNNING +#define SPI_GETFILTERKEYS 0x0032 +#define SPI_SETFILTERKEYS 0x0033 +#define SPI_GETTOGGLEKEYS 0x0034 +#define SPI_SETTOGGLEKEYS 0x0035 +#define SPI_GETMOUSEKEYS 0x0036 +#define SPI_SETMOUSEKEYS 0x0037 +#define SPI_GETSHOWSOUNDS 0x0038 +#define SPI_SETSHOWSOUNDS 0x0039 +#define SPI_GETSTICKYKEYS 0x003A +#define SPI_SETSTICKYKEYS 0x003B +#define SPI_GETACCESSTIMEOUT 0x003C +#define SPI_SETACCESSTIMEOUT 0x003D +#define SPI_GETSERIALKEYS 0x003E +#define SPI_SETSERIALKEYS 0x003F +#define SPI_GETSOUNDSENTRY 0x0040 +#define SPI_SETSOUNDSENTRY 0x0041 +#define SPI_GETSNAPTODEFBUTTON 0x005F +#define SPI_SETSNAPTODEFBUTTON 0x0060 +#define SPI_GETMOUSEHOVERWIDTH 0x0062 +#define SPI_SETMOUSEHOVERWIDTH 0x0063 +#define SPI_GETMOUSEHOVERHEIGHT 0x0064 +#define SPI_SETMOUSEHOVERHEIGHT 0x0065 +#define SPI_GETMOUSEHOVERTIME 0x0066 +#define SPI_SETMOUSEHOVERTIME 0x0067 +#define SPI_GETWHEELSCROLLLINES 0x0068 +#define SPI_SETWHEELSCROLLLINES 0x0069 +#define SPI_GETMENUSHOWDELAY 0x006A +#define SPI_SETMENUSHOWDELAY 0x006B +#define SPI_GETSHOWIMEUI 0x006E +#define SPI_SETSHOWIMEUI 0x006F +#define SPI_GETMOUSESPEED 0x0070 +#define SPI_SETMOUSESPEED 0x0071 +#define SPI_GETSCREENSAVERRUNNING 0x0072 +#define SPI_GETDESKWALLPAPER 0x0073 + +#define SPI_GETACTIVEWINDOWTRACKING 0x1000 +#define SPI_SETACTIVEWINDOWTRACKING 0x1001 +#define SPI_GETMENUANIMATION 0x1002 +#define SPI_SETMENUANIMATION 0x1003 +#define SPI_GETCOMBOBOXANIMATION 0x1004 +#define SPI_SETCOMBOBOXANIMATION 0x1005 +#define SPI_GETLISTBOXSMOOTHSCROLLING 0x1006 +#define SPI_SETLISTBOXSMOOTHSCROLLING 0x1007 +#define SPI_GETGRADIENTCAPTIONS 0x1008 +#define SPI_SETGRADIENTCAPTIONS 0x1009 +#define SPI_GETKEYBOARDCUES 0x100A +#define SPI_SETKEYBOARDCUES 0x100B +#define SPI_GETMENUUNDERLINES SPI_GETKEYBOARDCUES +#define SPI_SETMENUUNDERLINES SPI_SETKEYBOARDCUES +#define SPI_GETACTIVEWNDTRKZORDER 0x100C +#define SPI_SETACTIVEWNDTRKZORDER 0x100D +#define SPI_GETHOTTRACKING 0x100E +#define SPI_SETHOTTRACKING 0x100F +#define SPI_GETMENUFADE 0x1012 +#define SPI_SETMENUFADE 0x1013 +#define SPI_GETSELECTIONFADE 0x1014 +#define SPI_SETSELECTIONFADE 0x1015 +#define SPI_GETTOOLTIPANIMATION 0x1016 +#define SPI_SETTOOLTIPANIMATION 0x1017 +#define SPI_GETTOOLTIPFADE 0x1018 +#define SPI_SETTOOLTIPFADE 0x1019 +#define SPI_GETCURSORSHADOW 0x101A +#define SPI_SETCURSORSHADOW 0x101B +#define SPI_GETMOUSESONAR 0x101C +#define SPI_SETMOUSESONAR 0x101D +#define SPI_GETMOUSECLICKLOCK 0x101E +#define SPI_SETMOUSECLICKLOCK 0x101F +#define SPI_GETMOUSEVANISH 0x1020 +#define SPI_SETMOUSEVANISH 0x1021 +#define SPI_GETFLATMENU 0x1022 +#define SPI_SETFLATMENU 0x1023 +#define SPI_GETDROPSHADOW 0x1024 +#define SPI_SETDROPSHADOW 0x1025 +#define SPI_GETBLOCKSENDINPUTRESETS 0x1026 +#define SPI_SETBLOCKSENDINPUTRESETS 0x1027 +#define SPI_GETUIEFFECTS 0x103E +#define SPI_SETUIEFFECTS 0x103F +#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 +#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 +#define SPI_GETACTIVEWNDTRKTIMEOUT 0x2002 +#define SPI_SETACTIVEWNDTRKTIMEOUT 0x2003 +#define SPI_GETFOREGROUNDFLASHCOUNT 0x2004 +#define SPI_SETFOREGROUNDFLASHCOUNT 0x2005 +#define SPI_GETCARETWIDTH 0x2006 +#define SPI_SETCARETWIDTH 0x2007 +#define SPI_GETMOUSECLICKLOCKTIME 0x2008 +#define SPI_SETMOUSECLICKLOCKTIME 0x2009 +#define SPI_GETFONTSMOOTHINGTYPE 0x200A +#define SPI_SETFONTSMOOTHINGTYPE 0x200B + +#define FE_FONTSMOOTHINGSTANDARD 0x0001 +#define FE_FONTSMOOTHINGCLEARTYPE 0x0002 +#define FE_FONTSMOOTHINGDOCKING 0x8000 + +#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C +#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D +#define SPI_GETFOCUSBORDERWIDTH 0x200E +#define SPI_SETFOCUSBORDERWIDTH 0x200F +#define SPI_GETFOCUSBORDERHEIGHT 0x2010 +#define SPI_SETFOCUSBORDERHEIGHT 0x2011 +#define SPI_GETFONTSMOOTHINGORIENTATION 0x2012 +#define SPI_SETFONTSMOOTHINGORIENTATION 0x2013 + +#define FE_FONTSMOOTHINGORIENTATIONBGR 0x0000 +#define FE_FONTSMOOTHINGORIENTATIONRGB 0x0001 + +#define SPIF_UPDATEINIFILE 0x0001 +#define SPIF_SENDWININICHANGE 0x0002 +#define SPIF_SENDCHANGE SPIF_SENDWININICHANGE + +#define METRICS_USEDEFAULT -1 +#ifdef _WINGDI_ +#ifndef NOGDI + typedef struct tagNONCLIENTMETRICSA { + UINT cbSize; + int iBorderWidth; + int iScrollWidth; + int iScrollHeight; + int iCaptionWidth; + int iCaptionHeight; + LOGFONTA lfCaptionFont; + int iSmCaptionWidth; + int iSmCaptionHeight; + LOGFONTA lfSmCaptionFont; + int iMenuWidth; + int iMenuHeight; + LOGFONTA lfMenuFont; + LOGFONTA lfStatusFont; + LOGFONTA lfMessageFont; + } NONCLIENTMETRICSA,*PNONCLIENTMETRICSA,*LPNONCLIENTMETRICSA; + + typedef struct tagNONCLIENTMETRICSW { + UINT cbSize; + int iBorderWidth; + int iScrollWidth; + int iScrollHeight; + int iCaptionWidth; + int iCaptionHeight; + LOGFONTW lfCaptionFont; + int iSmCaptionWidth; + int iSmCaptionHeight; + LOGFONTW lfSmCaptionFont; + int iMenuWidth; + int iMenuHeight; + LOGFONTW lfMenuFont; + LOGFONTW lfStatusFont; + LOGFONTW lfMessageFont; + } NONCLIENTMETRICSW,*PNONCLIENTMETRICSW,*LPNONCLIENTMETRICSW; + +#ifdef UNICODE + typedef NONCLIENTMETRICSW NONCLIENTMETRICS; + typedef PNONCLIENTMETRICSW PNONCLIENTMETRICS; + typedef LPNONCLIENTMETRICSW LPNONCLIENTMETRICS; +#else + typedef NONCLIENTMETRICSA NONCLIENTMETRICS; + typedef PNONCLIENTMETRICSA PNONCLIENTMETRICS; + typedef LPNONCLIENTMETRICSA LPNONCLIENTMETRICS; +#endif +#endif +#endif + +#define ARW_BOTTOMLEFT 0x0000L +#define ARW_BOTTOMRIGHT 0x0001L +#define ARW_TOPLEFT 0x0002L +#define ARW_TOPRIGHT 0x0003L +#define ARW_STARTMASK 0x0003L +#define ARW_STARTRIGHT 0x0001L +#define ARW_STARTTOP 0x0002L + +#define ARW_LEFT 0x0000L +#define ARW_RIGHT 0x0000L +#define ARW_UP 0x0004L +#define ARW_DOWN 0x0004L +#define ARW_HIDE 0x0008L + + typedef struct tagMINIMIZEDMETRICS { + UINT cbSize; + int iWidth; + int iHorzGap; + int iVertGap; + int iArrange; + } MINIMIZEDMETRICS,*PMINIMIZEDMETRICS,*LPMINIMIZEDMETRICS; + +#ifdef _WINGDI_ +#ifndef NOGDI + typedef struct tagICONMETRICSA { + UINT cbSize; + int iHorzSpacing; + int iVertSpacing; + int iTitleWrap; + LOGFONTA lfFont; + } ICONMETRICSA,*PICONMETRICSA,*LPICONMETRICSA; + + typedef struct tagICONMETRICSW { + UINT cbSize; + int iHorzSpacing; + int iVertSpacing; + int iTitleWrap; + LOGFONTW lfFont; + } ICONMETRICSW,*PICONMETRICSW,*LPICONMETRICSW; + +#ifdef UNICODE + typedef ICONMETRICSW ICONMETRICS; + typedef PICONMETRICSW PICONMETRICS; + typedef LPICONMETRICSW LPICONMETRICS; +#else + typedef ICONMETRICSA ICONMETRICS; + typedef PICONMETRICSA PICONMETRICS; + typedef LPICONMETRICSA LPICONMETRICS; +#endif +#endif +#endif + + typedef struct tagANIMATIONINFO { + UINT cbSize; + int iMinAnimate; + } ANIMATIONINFO,*LPANIMATIONINFO; + + typedef struct tagSERIALKEYSA { + UINT cbSize; + DWORD dwFlags; + LPSTR lpszActivePort; + LPSTR lpszPort; + UINT iBaudRate; + UINT iPortState; + UINT iActive; + } SERIALKEYSA,*LPSERIALKEYSA; + + typedef struct tagSERIALKEYSW { + UINT cbSize; + DWORD dwFlags; + LPWSTR lpszActivePort; + LPWSTR lpszPort; + UINT iBaudRate; + UINT iPortState; + UINT iActive; + } SERIALKEYSW,*LPSERIALKEYSW; + +#ifdef UNICODE + typedef SERIALKEYSW SERIALKEYS; + typedef LPSERIALKEYSW LPSERIALKEYS; +#else + typedef SERIALKEYSA SERIALKEYS; + typedef LPSERIALKEYSA LPSERIALKEYS; +#endif + +#define SERKF_SERIALKEYSON 0x00000001 +#define SERKF_AVAILABLE 0x00000002 +#define SERKF_INDICATOR 0x00000004 + + typedef struct tagHIGHCONTRASTA { + UINT cbSize; + DWORD dwFlags; + LPSTR lpszDefaultScheme; + } HIGHCONTRASTA,*LPHIGHCONTRASTA; + + typedef struct tagHIGHCONTRASTW { + UINT cbSize; + DWORD dwFlags; + LPWSTR lpszDefaultScheme; + } HIGHCONTRASTW,*LPHIGHCONTRASTW; + +#ifdef UNICODE + typedef HIGHCONTRASTW HIGHCONTRAST; + typedef LPHIGHCONTRASTW LPHIGHCONTRAST; +#else + typedef HIGHCONTRASTA HIGHCONTRAST; + typedef LPHIGHCONTRASTA LPHIGHCONTRAST; +#endif + +#define HCF_HIGHCONTRASTON 0x00000001 +#define HCF_AVAILABLE 0x00000002 +#define HCF_HOTKEYACTIVE 0x00000004 +#define HCF_CONFIRMHOTKEY 0x00000008 +#define HCF_HOTKEYSOUND 0x00000010 +#define HCF_INDICATOR 0x00000020 +#define HCF_HOTKEYAVAILABLE 0x00000040 +#define HCF_LOGONDESKTOP 0x00000100 +#define HCF_DEFAULTDESKTOP 0x00000200 + +#define CDS_UPDATEREGISTRY 0x00000001 +#define CDS_TEST 0x00000002 +#define CDS_FULLSCREEN 0x00000004 +#define CDS_GLOBAL 0x00000008 +#define CDS_SET_PRIMARY 0x00000010 +#define CDS_VIDEOPARAMETERS 0x00000020 +#define CDS_RESET 0x40000000 +#define CDS_NORESET 0x10000000 + +//gr #include + +#define DISP_CHANGE_SUCCESSFUL 0 +#define DISP_CHANGE_RESTART 1 +#define DISP_CHANGE_FAILED -1 +#define DISP_CHANGE_BADMODE -2 +#define DISP_CHANGE_NOTUPDATED -3 +#define DISP_CHANGE_BADFLAGS -4 +#define DISP_CHANGE_BADPARAM -5 +#define DISP_CHANGE_BADDUALVIEW -6 + +#ifdef _WINGDI_ +#ifndef NOGDI + +#ifdef UNICODE +#define ChangeDisplaySettings ChangeDisplaySettingsW +#define ChangeDisplaySettingsEx ChangeDisplaySettingsExW +#define EnumDisplaySettings EnumDisplaySettingsW +#define EnumDisplaySettingsEx EnumDisplaySettingsExW +#define EnumDisplayDevices EnumDisplayDevicesW +#else +#define ChangeDisplaySettings ChangeDisplaySettingsA +#define ChangeDisplaySettingsEx ChangeDisplaySettingsExA +#define EnumDisplaySettings EnumDisplaySettingsA +#define EnumDisplaySettingsEx EnumDisplaySettingsExA +#define EnumDisplayDevices EnumDisplayDevicesA +#endif + + WINUSERAPI LONG WINAPI ChangeDisplaySettingsA(LPDEVMODEA lpDevMode,DWORD dwFlags); + WINUSERAPI LONG WINAPI ChangeDisplaySettingsW(LPDEVMODEW lpDevMode,DWORD dwFlags); + WINUSERAPI LONG WINAPI ChangeDisplaySettingsExA(LPCSTR lpszDeviceName,LPDEVMODEA lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); + WINUSERAPI LONG WINAPI ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName,LPDEVMODEW lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); + +#define ENUM_CURRENT_SETTINGS ((DWORD)-1) +#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) + + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode); + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode); + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode,DWORD dwFlags); + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode,DWORD dwFlags); + +#define EDS_RAWMODE 0x00000002 + + WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesA(LPCSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEA lpDisplayDevice,DWORD dwFlags); + WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesW(LPCWSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEW lpDisplayDevice,DWORD dwFlags); +#endif +#endif + +#ifdef UNICODE +#define SystemParametersInfo SystemParametersInfoW +#else +#define SystemParametersInfo SystemParametersInfoA +#endif + + WINUSERAPI WINBOOL WINAPI SystemParametersInfoA(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); + WINUSERAPI WINBOOL WINAPI SystemParametersInfoW(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); +#endif + + typedef struct tagFILTERKEYS { + UINT cbSize; + DWORD dwFlags; + DWORD iWaitMSec; + DWORD iDelayMSec; + DWORD iRepeatMSec; + DWORD iBounceMSec; + } FILTERKEYS,*LPFILTERKEYS; + +#define FKF_FILTERKEYSON 0x00000001 +#define FKF_AVAILABLE 0x00000002 +#define FKF_HOTKEYACTIVE 0x00000004 +#define FKF_CONFIRMHOTKEY 0x00000008 +#define FKF_HOTKEYSOUND 0x00000010 +#define FKF_INDICATOR 0x00000020 +#define FKF_CLICKON 0x00000040 + + typedef struct tagSTICKYKEYS { + UINT cbSize; + DWORD dwFlags; + } STICKYKEYS,*LPSTICKYKEYS; + +#define SKF_STICKYKEYSON 0x00000001 +#define SKF_AVAILABLE 0x00000002 +#define SKF_HOTKEYACTIVE 0x00000004 +#define SKF_CONFIRMHOTKEY 0x00000008 +#define SKF_HOTKEYSOUND 0x00000010 +#define SKF_INDICATOR 0x00000020 +#define SKF_AUDIBLEFEEDBACK 0x00000040 +#define SKF_TRISTATE 0x00000080 +#define SKF_TWOKEYSOFF 0x00000100 +#define SKF_LALTLATCHED 0x10000000 +#define SKF_LCTLLATCHED 0x04000000 +#define SKF_LSHIFTLATCHED 0x01000000 +#define SKF_RALTLATCHED 0x20000000 +#define SKF_RCTLLATCHED 0x08000000 +#define SKF_RSHIFTLATCHED 0x02000000 +#define SKF_LWINLATCHED 0x40000000 +#define SKF_RWINLATCHED 0x80000000 +#define SKF_LALTLOCKED 0x00100000 +#define SKF_LCTLLOCKED 0x00040000 +#define SKF_LSHIFTLOCKED 0x00010000 +#define SKF_RALTLOCKED 0x00200000 +#define SKF_RCTLLOCKED 0x00080000 +#define SKF_RSHIFTLOCKED 0x00020000 +#define SKF_LWINLOCKED 0x00400000 +#define SKF_RWINLOCKED 0x00800000 + + typedef struct tagMOUSEKEYS { + UINT cbSize; + DWORD dwFlags; + DWORD iMaxSpeed; + DWORD iTimeToMaxSpeed; + DWORD iCtrlSpeed; + DWORD dwReserved1; + DWORD dwReserved2; + } MOUSEKEYS,*LPMOUSEKEYS; + +#define MKF_MOUSEKEYSON 0x00000001 +#define MKF_AVAILABLE 0x00000002 +#define MKF_HOTKEYACTIVE 0x00000004 +#define MKF_CONFIRMHOTKEY 0x00000008 +#define MKF_HOTKEYSOUND 0x00000010 +#define MKF_INDICATOR 0x00000020 +#define MKF_MODIFIERS 0x00000040 +#define MKF_REPLACENUMBERS 0x00000080 +#define MKF_LEFTBUTTONSEL 0x10000000 +#define MKF_RIGHTBUTTONSEL 0x20000000 +#define MKF_LEFTBUTTONDOWN 0x01000000 +#define MKF_RIGHTBUTTONDOWN 0x02000000 +#define MKF_MOUSEMODE 0x80000000 + + typedef struct tagACCESSTIMEOUT { + UINT cbSize; + DWORD dwFlags; + DWORD iTimeOutMSec; + } ACCESSTIMEOUT,*LPACCESSTIMEOUT; + +#define ATF_TIMEOUTON 0x00000001 +#define ATF_ONOFFFEEDBACK 0x00000002 + +#define SSGF_NONE 0 +#define SSGF_DISPLAY 3 + +#define SSTF_NONE 0 +#define SSTF_CHARS 1 +#define SSTF_BORDER 2 +#define SSTF_DISPLAY 3 + +#define SSWF_NONE 0 +#define SSWF_TITLE 1 +#define SSWF_WINDOW 2 +#define SSWF_DISPLAY 3 +#define SSWF_CUSTOM 4 + + typedef struct tagSOUNDSENTRYA { + UINT cbSize; + DWORD dwFlags; + DWORD iFSTextEffect; + DWORD iFSTextEffectMSec; + DWORD iFSTextEffectColorBits; + DWORD iFSGrafEffect; + DWORD iFSGrafEffectMSec; + DWORD iFSGrafEffectColor; + DWORD iWindowsEffect; + DWORD iWindowsEffectMSec; + LPSTR lpszWindowsEffectDLL; + DWORD iWindowsEffectOrdinal; + } SOUNDSENTRYA,*LPSOUNDSENTRYA; + + typedef struct tagSOUNDSENTRYW { + UINT cbSize; + DWORD dwFlags; + DWORD iFSTextEffect; + DWORD iFSTextEffectMSec; + DWORD iFSTextEffectColorBits; + DWORD iFSGrafEffect; + DWORD iFSGrafEffectMSec; + DWORD iFSGrafEffectColor; + DWORD iWindowsEffect; + DWORD iWindowsEffectMSec; + LPWSTR lpszWindowsEffectDLL; + DWORD iWindowsEffectOrdinal; + } SOUNDSENTRYW,*LPSOUNDSENTRYW; + +#ifdef UNICODE + typedef SOUNDSENTRYW SOUNDSENTRY; + typedef LPSOUNDSENTRYW LPSOUNDSENTRY; +#else + typedef SOUNDSENTRYA SOUNDSENTRY; + typedef LPSOUNDSENTRYA LPSOUNDSENTRY; +#endif + +#define SSF_SOUNDSENTRYON 0x00000001 +#define SSF_AVAILABLE 0x00000002 +#define SSF_INDICATOR 0x00000004 + + typedef struct tagTOGGLEKEYS { + UINT cbSize; + DWORD dwFlags; + } TOGGLEKEYS,*LPTOGGLEKEYS; + +#define TKF_TOGGLEKEYSON 0x00000001 +#define TKF_AVAILABLE 0x00000002 +#define TKF_HOTKEYACTIVE 0x00000004 +#define TKF_CONFIRMHOTKEY 0x00000008 +#define TKF_HOTKEYSOUND 0x00000010 +#define TKF_INDICATOR 0x00000020 + + WINUSERAPI VOID WINAPI SetDebugErrorLevel(DWORD dwLevel); + +#define SLE_ERROR 0x00000001 +#define SLE_MINORERROR 0x00000002 +#define SLE_WARNING 0x00000003 + + WINUSERAPI VOID WINAPI SetLastErrorEx(DWORD dwErrCode,DWORD dwType); + WINUSERAPI int WINAPI InternalGetWindowText(HWND hWnd,LPWSTR pString,int cchMaxCount); + +#ifdef WINNT + WINUSERAPI WINBOOL WINAPI EndTask(HWND hWnd,WINBOOL fShutDown,WINBOOL fForce); +#endif + +#define MONITOR_DEFAULTTONULL 0x00000000 +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +#define MONITOR_DEFAULTTONEAREST 0x00000002 + + WINUSERAPI HMONITOR WINAPI MonitorFromPoint(POINT pt,DWORD dwFlags); + WINUSERAPI HMONITOR WINAPI MonitorFromRect(LPCRECT lprc,DWORD dwFlags); + WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd,DWORD dwFlags); + +#define MONITORINFOF_PRIMARY 0x00000001 + +#ifndef CCHDEVICENAME +#define CCHDEVICENAME 32 +#endif + + typedef struct tagMONITORINFO { + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; + } MONITORINFO,*LPMONITORINFO; + +#ifdef __cplusplus + typedef struct tagMONITORINFOEXA : public tagMONITORINFO { + CHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXA,*LPMONITORINFOEXA; + + typedef struct tagMONITORINFOEXW : public tagMONITORINFO { + WCHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXW,*LPMONITORINFOEXW; + +#ifdef UNICODE + typedef MONITORINFOEXW MONITORINFOEX; + typedef LPMONITORINFOEXW LPMONITORINFOEX; +#else + typedef MONITORINFOEXA MONITORINFOEX; + typedef LPMONITORINFOEXA LPMONITORINFOEX; +#endif +#else + typedef struct tagMONITORINFOEXA { + MONITORINFO mi; + CHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXA,*LPMONITORINFOEXA; + + typedef struct tagMONITORINFOEXW { + MONITORINFO mi; + WCHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXW,*LPMONITORINFOEXW; +#ifdef UNICODE + typedef MONITORINFOEXW MONITORINFOEX; + typedef LPMONITORINFOEXW LPMONITORINFOEX; +#else + typedef MONITORINFOEXA MONITORINFOEX; + typedef LPMONITORINFOEXA LPMONITORINFOEX; +#endif +#endif + +#ifdef UNICODE +#define GetMonitorInfo GetMonitorInfoW +#else +#define GetMonitorInfo GetMonitorInfoA +#endif + + WINUSERAPI WINBOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor,LPMONITORINFO lpmi); + WINUSERAPI WINBOOL WINAPI GetMonitorInfoW(HMONITOR hMonitor,LPMONITORINFO lpmi); + + typedef WINBOOL (CALLBACK *MONITORENUMPROC)(HMONITOR,HDC,LPRECT,LPARAM); + + WINUSERAPI WINBOOL WINAPI EnumDisplayMonitors(HDC hdc,LPCRECT lprcClip,MONITORENUMPROC lpfnEnum,LPARAM dwData); + +#ifndef NOWINABLE + WINUSERAPI VOID WINAPI NotifyWinEvent(DWORD event,HWND hwnd,LONG idObject,LONG idChild); + + typedef VOID (CALLBACK *WINEVENTPROC)(HWINEVENTHOOK hWinEventHook,DWORD event,HWND hwnd,LONG idObject,LONG idChild,DWORD idEventThread,DWORD dwmsEventTime); + + WINUSERAPI HWINEVENTHOOK WINAPI SetWinEventHook(DWORD eventMin,DWORD eventMax,HMODULE hmodWinEventProc,WINEVENTPROC pfnWinEventProc,DWORD idProcess,DWORD idThread,DWORD dwFlags); + WINUSERAPI WINBOOL WINAPI IsWinEventHookInstalled(DWORD event); + +#define WINEVENT_OUTOFCONTEXT 0x0000 +#define WINEVENT_SKIPOWNTHREAD 0x0001 +#define WINEVENT_SKIPOWNPROCESS 0x0002 +#define WINEVENT_INCONTEXT 0x0004 + + WINUSERAPI WINBOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hWinEventHook); + +#define CHILDID_SELF 0 +#define INDEXID_OBJECT 0 +#define INDEXID_CONTAINER 0 + +#define OBJID_WINDOW ((LONG)0x00000000) +#define OBJID_SYSMENU ((LONG)0xFFFFFFFF) +#define OBJID_TITLEBAR ((LONG)0xFFFFFFFE) +#define OBJID_MENU ((LONG)0xFFFFFFFD) +#define OBJID_CLIENT ((LONG)0xFFFFFFFC) +#define OBJID_VSCROLL ((LONG)0xFFFFFFFB) +#define OBJID_HSCROLL ((LONG)0xFFFFFFFA) +#define OBJID_SIZEGRIP ((LONG)0xFFFFFFF9) +#define OBJID_CARET ((LONG)0xFFFFFFF8) +#define OBJID_CURSOR ((LONG)0xFFFFFFF7) +#define OBJID_ALERT ((LONG)0xFFFFFFF6) +#define OBJID_SOUND ((LONG)0xFFFFFFF5) +#define OBJID_QUERYCLASSNAMEIDX ((LONG)0xFFFFFFF4) +#define OBJID_NATIVEOM ((LONG)0xFFFFFFF0) + +#define EVENT_MIN 0x00000001 +#define EVENT_MAX 0x7FFFFFFF + +#define EVENT_SYSTEM_SOUND 0x0001 +#define EVENT_SYSTEM_ALERT 0x0002 +#define EVENT_SYSTEM_FOREGROUND 0x0003 +#define EVENT_SYSTEM_MENUSTART 0x0004 +#define EVENT_SYSTEM_MENUEND 0x0005 +#define EVENT_SYSTEM_MENUPOPUPSTART 0x0006 +#define EVENT_SYSTEM_MENUPOPUPEND 0x0007 +#define EVENT_SYSTEM_CAPTURESTART 0x0008 +#define EVENT_SYSTEM_CAPTUREEND 0x0009 +#define EVENT_SYSTEM_MOVESIZESTART 0x000A +#define EVENT_SYSTEM_MOVESIZEEND 0x000B +#define EVENT_SYSTEM_CONTEXTHELPSTART 0x000C +#define EVENT_SYSTEM_CONTEXTHELPEND 0x000D +#define EVENT_SYSTEM_DRAGDROPSTART 0x000E +#define EVENT_SYSTEM_DRAGDROPEND 0x000F +#define EVENT_SYSTEM_DIALOGSTART 0x0010 +#define EVENT_SYSTEM_DIALOGEND 0x0011 +#define EVENT_SYSTEM_SCROLLINGSTART 0x0012 +#define EVENT_SYSTEM_SCROLLINGEND 0x0013 +#define EVENT_SYSTEM_SWITCHSTART 0x0014 +#define EVENT_SYSTEM_SWITCHEND 0x0015 +#define EVENT_SYSTEM_MINIMIZESTART 0x0016 +#define EVENT_SYSTEM_MINIMIZEEND 0x0017 + +#define EVENT_CONSOLE_CARET 0x4001 +#define EVENT_CONSOLE_UPDATE_REGION 0x4002 +#define EVENT_CONSOLE_UPDATE_SIMPLE 0x4003 +#define EVENT_CONSOLE_UPDATE_SCROLL 0x4004 +#define EVENT_CONSOLE_LAYOUT 0x4005 +#define EVENT_CONSOLE_START_APPLICATION 0x4006 +#define EVENT_CONSOLE_END_APPLICATION 0x4007 + +#define CONSOLE_APPLICATION_16BIT 0x0001 + +#define CONSOLE_CARET_SELECTION 0x0001 +#define CONSOLE_CARET_VISIBLE 0x0002 + +#define EVENT_OBJECT_CREATE 0x8000 +#define EVENT_OBJECT_DESTROY 0x8001 +#define EVENT_OBJECT_SHOW 0x8002 +#define EVENT_OBJECT_HIDE 0x8003 +#define EVENT_OBJECT_REORDER 0x8004 + +#define EVENT_OBJECT_FOCUS 0x8005 +#define EVENT_OBJECT_SELECTION 0x8006 +#define EVENT_OBJECT_SELECTIONADD 0x8007 +#define EVENT_OBJECT_SELECTIONREMOVE 0x8008 +#define EVENT_OBJECT_SELECTIONWITHIN 0x8009 + +#define EVENT_OBJECT_STATECHANGE 0x800A + +#define EVENT_OBJECT_LOCATIONCHANGE 0x800B + +#define EVENT_OBJECT_NAMECHANGE 0x800C +#define EVENT_OBJECT_DESCRIPTIONCHANGE 0x800D +#define EVENT_OBJECT_VALUECHANGE 0x800E +#define EVENT_OBJECT_PARENTCHANGE 0x800F +#define EVENT_OBJECT_HELPCHANGE 0x8010 +#define EVENT_OBJECT_DEFACTIONCHANGE 0x8011 +#define EVENT_OBJECT_ACCELERATORCHANGE 0x8012 + +#define SOUND_SYSTEM_STARTUP 1 +#define SOUND_SYSTEM_SHUTDOWN 2 +#define SOUND_SYSTEM_BEEP 3 +#define SOUND_SYSTEM_ERROR 4 +#define SOUND_SYSTEM_QUESTION 5 +#define SOUND_SYSTEM_WARNING 6 +#define SOUND_SYSTEM_INFORMATION 7 +#define SOUND_SYSTEM_MAXIMIZE 8 +#define SOUND_SYSTEM_MINIMIZE 9 +#define SOUND_SYSTEM_RESTOREUP 10 +#define SOUND_SYSTEM_RESTOREDOWN 11 +#define SOUND_SYSTEM_APPSTART 12 +#define SOUND_SYSTEM_FAULT 13 +#define SOUND_SYSTEM_APPEND 14 +#define SOUND_SYSTEM_MENUCOMMAND 15 +#define SOUND_SYSTEM_MENUPOPUP 16 +#define CSOUND_SYSTEM 16 + +#define ALERT_SYSTEM_INFORMATIONAL 1 +#define ALERT_SYSTEM_WARNING 2 +#define ALERT_SYSTEM_ERROR 3 +#define ALERT_SYSTEM_QUERY 4 +#define ALERT_SYSTEM_CRITICAL 5 +#define CALERT_SYSTEM 6 + + typedef struct tagGUITHREADINFO { + DWORD cbSize; + DWORD flags; + HWND hwndActive; + HWND hwndFocus; + HWND hwndCapture; + HWND hwndMenuOwner; + HWND hwndMoveSize; + HWND hwndCaret; + RECT rcCaret; + } GUITHREADINFO,*PGUITHREADINFO,*LPGUITHREADINFO; + +#define GUI_CARETBLINKING 0x00000001 +#define GUI_INMOVESIZE 0x00000002 +#define GUI_INMENUMODE 0x00000004 +#define GUI_SYSTEMMENUMODE 0x00000008 +#define GUI_POPUPMENUMODE 0x00000010 +#define GUI_16BITTASK 0x00000020 + +#ifdef UNICODE +#define GetWindowModuleFileName GetWindowModuleFileNameW +#else +#define GetWindowModuleFileName GetWindowModuleFileNameA +#endif + + WINUSERAPI WINBOOL WINAPI GetGUIThreadInfo(DWORD idThread,PGUITHREADINFO pgui); + WINUSERAPI UINT WINAPI GetWindowModuleFileNameA(HWND hwnd,LPSTR pszFileName,UINT cchFileNameMax); + WINUSERAPI UINT WINAPI GetWindowModuleFileNameW(HWND hwnd,LPWSTR pszFileName,UINT cchFileNameMax); + +#ifndef NO_STATE_FLAGS +#define STATE_SYSTEM_UNAVAILABLE 0x00000001 +#define STATE_SYSTEM_SELECTED 0x00000002 +#define STATE_SYSTEM_FOCUSED 0x00000004 +#define STATE_SYSTEM_PRESSED 0x00000008 +#define STATE_SYSTEM_CHECKED 0x00000010 +#define STATE_SYSTEM_MIXED 0x00000020 +#define STATE_SYSTEM_INDETERMINATE STATE_SYSTEM_MIXED +#define STATE_SYSTEM_READONLY 0x00000040 +#define STATE_SYSTEM_HOTTRACKED 0x00000080 +#define STATE_SYSTEM_DEFAULT 0x00000100 +#define STATE_SYSTEM_EXPANDED 0x00000200 +#define STATE_SYSTEM_COLLAPSED 0x00000400 +#define STATE_SYSTEM_BUSY 0x00000800 +#define STATE_SYSTEM_FLOATING 0x00001000 +#define STATE_SYSTEM_MARQUEED 0x00002000 +#define STATE_SYSTEM_ANIMATED 0x00004000 +#define STATE_SYSTEM_INVISIBLE 0x00008000 +#define STATE_SYSTEM_OFFSCREEN 0x00010000 +#define STATE_SYSTEM_SIZEABLE 0x00020000 +#define STATE_SYSTEM_MOVEABLE 0x00040000 +#define STATE_SYSTEM_SELFVOICING 0x00080000 +#define STATE_SYSTEM_FOCUSABLE 0x00100000 +#define STATE_SYSTEM_SELECTABLE 0x00200000 +#define STATE_SYSTEM_LINKED 0x00400000 +#define STATE_SYSTEM_TRAVERSED 0x00800000 +#define STATE_SYSTEM_MULTISELECTABLE 0x01000000 +#define STATE_SYSTEM_EXTSELECTABLE 0x02000000 +#define STATE_SYSTEM_ALERT_LOW 0x04000000 +#define STATE_SYSTEM_ALERT_MEDIUM 0x08000000 +#define STATE_SYSTEM_ALERT_HIGH 0x10000000 +#define STATE_SYSTEM_PROTECTED 0x20000000 +#define STATE_SYSTEM_VALID 0x3FFFFFFF +#endif + +#define CCHILDREN_TITLEBAR 5 +#define CCHILDREN_SCROLLBAR 5 + + typedef struct tagCURSORINFO { + DWORD cbSize; + DWORD flags; + HCURSOR hCursor; + POINT ptScreenPos; + } CURSORINFO,*PCURSORINFO,*LPCURSORINFO; + +#define CURSOR_SHOWING 0x00000001 + + WINUSERAPI WINBOOL WINAPI GetCursorInfo(PCURSORINFO pci); + + typedef struct tagWINDOWINFO { + DWORD cbSize; + RECT rcWindow; + RECT rcClient; + DWORD dwStyle; + DWORD dwExStyle; + DWORD dwWindowStatus; + UINT cxWindowBorders; + UINT cyWindowBorders; + ATOM atomWindowType; + WORD wCreatorVersion; + } WINDOWINFO,*PWINDOWINFO,*LPWINDOWINFO; + +#define WS_ACTIVECAPTION 0x0001 + + WINUSERAPI WINBOOL WINAPI GetWindowInfo(HWND hwnd,PWINDOWINFO pwi); + + typedef struct tagTITLEBARINFO { + DWORD cbSize; + RECT rcTitleBar; + DWORD rgstate[CCHILDREN_TITLEBAR + 1]; + } TITLEBARINFO,*PTITLEBARINFO,*LPTITLEBARINFO; + + WINUSERAPI WINBOOL WINAPI GetTitleBarInfo(HWND hwnd,PTITLEBARINFO pti); + + typedef struct tagMENUBARINFO { + DWORD cbSize; + RECT rcBar; + HMENU hMenu; + HWND hwndMenu; + WINBOOL fBarFocused:1; + WINBOOL fFocused:1; + } MENUBARINFO,*PMENUBARINFO,*LPMENUBARINFO; + + WINUSERAPI WINBOOL WINAPI GetMenuBarInfo(HWND hwnd,LONG idObject,LONG idItem,PMENUBARINFO pmbi); + + typedef struct tagSCROLLBARINFO { + DWORD cbSize; + RECT rcScrollBar; + int dxyLineButton; + int xyThumbTop; + int xyThumbBottom; + int reserved; + DWORD rgstate[CCHILDREN_SCROLLBAR + 1]; + } SCROLLBARINFO,*PSCROLLBARINFO,*LPSCROLLBARINFO; + + WINUSERAPI WINBOOL WINAPI GetScrollBarInfo(HWND hwnd,LONG idObject,PSCROLLBARINFO psbi); + + typedef struct tagCOMBOBOXINFO { + DWORD cbSize; + RECT rcItem; + RECT rcButton; + DWORD stateButton; + HWND hwndCombo; + HWND hwndItem; + HWND hwndList; + } COMBOBOXINFO,*PCOMBOBOXINFO,*LPCOMBOBOXINFO; + + WINUSERAPI WINBOOL WINAPI GetComboBoxInfo(HWND hwndCombo,PCOMBOBOXINFO pcbi); + +#define GA_PARENT 1 +#define GA_ROOT 2 +#define GA_ROOTOWNER 3 + + WINUSERAPI HWND WINAPI GetAncestor(HWND hwnd,UINT gaFlags); + WINUSERAPI HWND WINAPI RealChildWindowFromPoint(HWND hwndParent,POINT ptParentClientCoords); + WINUSERAPI UINT WINAPI RealGetWindowClassA(HWND hwnd,LPSTR ptszClassName,UINT cchClassNameMax); + WINUSERAPI UINT WINAPI RealGetWindowClassW(HWND hwnd,LPWSTR ptszClassName,UINT cchClassNameMax); +#ifdef UNICODE +#define RealGetWindowClass RealGetWindowClassW +#else +#define RealGetWindowClass RealGetWindowClassA +#endif + + typedef struct tagALTTABINFO { + DWORD cbSize; + int cItems; + int cColumns; + int cRows; + int iColFocus; + int iRowFocus; + int cxItem; + int cyItem; + POINT ptStart; + } ALTTABINFO,*PALTTABINFO,*LPALTTABINFO; + +#ifdef UNICODE +#define GetAltTabInfo GetAltTabInfoW +#else +#define GetAltTabInfo GetAltTabInfoA +#endif + + WINUSERAPI WINBOOL WINAPI GetAltTabInfoA(HWND hwnd,int iItem,PALTTABINFO pati,LPSTR pszItemText,UINT cchItemText); + WINUSERAPI WINBOOL WINAPI GetAltTabInfoW(HWND hwnd,int iItem,PALTTABINFO pati,LPWSTR pszItemText,UINT cchItemText); + WINUSERAPI DWORD WINAPI GetListBoxInfo(HWND hwnd); +#endif + + WINUSERAPI WINBOOL WINAPI LockWorkStation(VOID); + WINUSERAPI WINBOOL WINAPI UserHandleGrantAccess(HANDLE hUserHandle,HANDLE hJob,WINBOOL bGrant); + + DECLARE_HANDLE(HRAWINPUT); + +#define GET_RAWINPUT_CODE_WPARAM(wParam) ((wParam) & 0xff) + +#define RIM_INPUT 0 +#define RIM_INPUTSINK 1 + + typedef struct tagRAWINPUTHEADER { + DWORD dwType; + DWORD dwSize; + HANDLE hDevice; + WPARAM wParam; + } RAWINPUTHEADER,*PRAWINPUTHEADER,*LPRAWINPUTHEADER; + +#define RIM_TYPEMOUSE 0 +#define RIM_TYPEKEYBOARD 1 +#define RIM_TYPEHID 2 + + typedef struct tagRAWMOUSE { + USHORT usFlags; + union { + ULONG ulButtons; + struct { + USHORT usButtonFlags; + USHORT usButtonData; + }; + }; + ULONG ulRawButtons; + LONG lLastX; + LONG lLastY; + ULONG ulExtraInformation; + } RAWMOUSE,*PRAWMOUSE,*LPRAWMOUSE; + +#define RI_MOUSE_LEFT_BUTTON_DOWN 0x0001 +#define RI_MOUSE_LEFT_BUTTON_UP 0x0002 +#define RI_MOUSE_RIGHT_BUTTON_DOWN 0x0004 +#define RI_MOUSE_RIGHT_BUTTON_UP 0x0008 +#define RI_MOUSE_MIDDLE_BUTTON_DOWN 0x0010 +#define RI_MOUSE_MIDDLE_BUTTON_UP 0x0020 + +#define RI_MOUSE_BUTTON_1_DOWN RI_MOUSE_LEFT_BUTTON_DOWN +#define RI_MOUSE_BUTTON_1_UP RI_MOUSE_LEFT_BUTTON_UP +#define RI_MOUSE_BUTTON_2_DOWN RI_MOUSE_RIGHT_BUTTON_DOWN +#define RI_MOUSE_BUTTON_2_UP RI_MOUSE_RIGHT_BUTTON_UP +#define RI_MOUSE_BUTTON_3_DOWN RI_MOUSE_MIDDLE_BUTTON_DOWN +#define RI_MOUSE_BUTTON_3_UP RI_MOUSE_MIDDLE_BUTTON_UP + +#define RI_MOUSE_BUTTON_4_DOWN 0x0040 +#define RI_MOUSE_BUTTON_4_UP 0x0080 +#define RI_MOUSE_BUTTON_5_DOWN 0x0100 +#define RI_MOUSE_BUTTON_5_UP 0x0200 + +#define RI_MOUSE_WHEEL 0x0400 + +#define MOUSE_MOVE_RELATIVE 0 +#define MOUSE_MOVE_ABSOLUTE 1 +#define MOUSE_VIRTUAL_DESKTOP 0x02 +#define MOUSE_ATTRIBUTES_CHANGED 0x04 + + typedef struct tagRAWKEYBOARD { + USHORT MakeCode; + USHORT Flags; + USHORT Reserved; + USHORT VKey; + UINT Message; + ULONG ExtraInformation; + } RAWKEYBOARD,*PRAWKEYBOARD,*LPRAWKEYBOARD; + +#define KEYBOARD_OVERRUN_MAKE_CODE 0xFF + +#define RI_KEY_MAKE 0 +#define RI_KEY_BREAK 1 +#define RI_KEY_E0 2 +#define RI_KEY_E1 4 +#define RI_KEY_TERMSRV_SET_LED 8 +#define RI_KEY_TERMSRV_SHADOW 0x10 + + typedef struct tagRAWHID { + DWORD dwSizeHid; + DWORD dwCount; + BYTE bRawData[1]; + } RAWHID,*PRAWHID,*LPRAWHID; + + typedef struct tagRAWINPUT { + RAWINPUTHEADER header; + union { + RAWMOUSE mouse; + RAWKEYBOARD keyboard; + RAWHID hid; + } data; + } RAWINPUT,*PRAWINPUT,*LPRAWINPUT; + +#ifdef _WIN64 +#define RAWINPUT_ALIGN(x) (((x) + sizeof(QWORD) - 1) & ~(sizeof(QWORD) - 1)) +#else +#define RAWINPUT_ALIGN(x) (((x) + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1)) +#endif + +#define NEXTRAWINPUTBLOCK(ptr) ((PRAWINPUT)RAWINPUT_ALIGN((ULONG_PTR)((PBYTE)(ptr) + (ptr)->header.dwSize))) + +#define RID_INPUT 0x10000003 +#define RID_HEADER 0x10000005 + + WINUSERAPI UINT WINAPI GetRawInputData(HRAWINPUT hRawInput,UINT uiCommand,LPVOID pData,PUINT pcbSize,UINT cbSizeHeader); + +#define RIDI_PREPARSEDDATA 0x20000005 +#define RIDI_DEVICENAME 0x20000007 +#define RIDI_DEVICEINFO 0x2000000b + + typedef struct tagRID_DEVICE_INFO_MOUSE { + DWORD dwId; + DWORD dwNumberOfButtons; + DWORD dwSampleRate; + } RID_DEVICE_INFO_MOUSE,*PRID_DEVICE_INFO_MOUSE; + + typedef struct tagRID_DEVICE_INFO_KEYBOARD { + DWORD dwType; + DWORD dwSubType; + DWORD dwKeyboardMode; + DWORD dwNumberOfFunctionKeys; + DWORD dwNumberOfIndicators; + DWORD dwNumberOfKeysTotal; + } RID_DEVICE_INFO_KEYBOARD,*PRID_DEVICE_INFO_KEYBOARD; + + typedef struct tagRID_DEVICE_INFO_HID { + DWORD dwVendorId; + DWORD dwProductId; + DWORD dwVersionNumber; + USHORT usUsagePage; + USHORT usUsage; + } RID_DEVICE_INFO_HID,*PRID_DEVICE_INFO_HID; + + typedef struct tagRID_DEVICE_INFO { + DWORD cbSize; + DWORD dwType; + union { + RID_DEVICE_INFO_MOUSE mouse; + RID_DEVICE_INFO_KEYBOARD keyboard; + RID_DEVICE_INFO_HID hid; + }; + } RID_DEVICE_INFO,*PRID_DEVICE_INFO,*LPRID_DEVICE_INFO; + +#ifdef UNICODE +#define GetRawInputDeviceInfo GetRawInputDeviceInfoW +#else +#define GetRawInputDeviceInfo GetRawInputDeviceInfoA +#endif + + WINUSERAPI UINT WINAPI GetRawInputDeviceInfoA(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); + WINUSERAPI UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); + WINUSERAPI UINT WINAPI GetRawInputBuffer(PRAWINPUT pData,PUINT pcbSize,UINT cbSizeHeader); + + typedef struct tagRAWINPUTDEVICE { + USHORT usUsagePage; + USHORT usUsage; + DWORD dwFlags; + HWND hwndTarget; + } RAWINPUTDEVICE,*PRAWINPUTDEVICE,*LPRAWINPUTDEVICE; + + typedef CONST RAWINPUTDEVICE *PCRAWINPUTDEVICE; + +#define RIDEV_REMOVE 0x00000001 +#define RIDEV_EXCLUDE 0x00000010 +#define RIDEV_PAGEONLY 0x00000020 +#define RIDEV_NOLEGACY 0x00000030 +#define RIDEV_INPUTSINK 0x00000100 +#define RIDEV_CAPTUREMOUSE 0x00000200 +#define RIDEV_NOHOTKEYS 0x00000200 +#define RIDEV_APPKEYS 0x00000400 +#define RIDEV_EXMODEMASK 0x000000F0 +#define RIDEV_EXMODE(mode) ((mode) & RIDEV_EXMODEMASK) + + WINUSERAPI WINBOOL WINAPI RegisterRawInputDevices(PCRAWINPUTDEVICE pRawInputDevices,UINT uiNumDevices,UINT cbSize); + WINUSERAPI UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices,PUINT puiNumDevices,UINT cbSize); + + typedef struct tagRAWINPUTDEVICELIST { + HANDLE hDevice; + DWORD dwType; + } RAWINPUTDEVICELIST,*PRAWINPUTDEVICELIST; + + WINUSERAPI UINT WINAPI GetRawInputDeviceList(PRAWINPUTDEVICELIST pRawInputDeviceList,PUINT puiNumDevices,UINT cbSize); + WINUSERAPI LRESULT WINAPI DefRawInputProc(PRAWINPUT *paRawInput,INT nInput,UINT cbSizeHeader); + +#endif /* NOUSER */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/winver.h b/tcc/include/winapi/winver.h index 5c0f036b..bebd0453 100644 --- a/tcc/include/winapi/winver.h +++ b/tcc/include/winapi/winver.h @@ -1,160 +1,160 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef VER_H -#define VER_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define VS_FILE_INFO RT_VERSION -#define VS_VERSION_INFO 1 -#define VS_USER_DEFINED 100 - -#define VS_FFI_SIGNATURE 0xFEEF04BDL -#define VS_FFI_STRUCVERSION 0x00010000L -#define VS_FFI_FILEFLAGSMASK 0x0000003FL - -#define VS_FF_DEBUG 0x00000001L -#define VS_FF_PRERELEASE 0x00000002L -#define VS_FF_PATCHED 0x00000004L -#define VS_FF_PRIVATEBUILD 0x00000008L -#define VS_FF_INFOINFERRED 0x00000010L -#define VS_FF_SPECIALBUILD 0x00000020L - -#define VOS_UNKNOWN 0x00000000L -#define VOS_DOS 0x00010000L -#define VOS_OS216 0x00020000L -#define VOS_OS232 0x00030000L -#define VOS_NT 0x00040000L -#define VOS_WINCE 0x00050000L - -#define VOS__BASE 0x00000000L -#define VOS__WINDOWS16 0x00000001L -#define VOS__PM16 0x00000002L -#define VOS__PM32 0x00000003L -#define VOS__WINDOWS32 0x00000004L - -#define VOS_DOS_WINDOWS16 0x00010001L -#define VOS_DOS_WINDOWS32 0x00010004L -#define VOS_OS216_PM16 0x00020002L -#define VOS_OS232_PM32 0x00030003L -#define VOS_NT_WINDOWS32 0x00040004L - -#define VFT_UNKNOWN 0x00000000L -#define VFT_APP 0x00000001L -#define VFT_DLL 0x00000002L -#define VFT_DRV 0x00000003L -#define VFT_FONT 0x00000004L -#define VFT_VXD 0x00000005L -#define VFT_STATIC_LIB 0x00000007L - -#define VFT2_UNKNOWN 0x00000000L -#define VFT2_DRV_PRINTER 0x00000001L -#define VFT2_DRV_KEYBOARD 0x00000002L -#define VFT2_DRV_LANGUAGE 0x00000003L -#define VFT2_DRV_DISPLAY 0x00000004L -#define VFT2_DRV_MOUSE 0x00000005L -#define VFT2_DRV_NETWORK 0x00000006L -#define VFT2_DRV_SYSTEM 0x00000007L -#define VFT2_DRV_INSTALLABLE 0x00000008L -#define VFT2_DRV_SOUND 0x00000009L -#define VFT2_DRV_COMM 0x0000000AL -#define VFT2_DRV_INPUTMETHOD 0x0000000BL -#define VFT2_DRV_VERSIONED_PRINTER 0x0000000CL - -#define VFT2_FONT_RASTER 0x00000001L -#define VFT2_FONT_VECTOR 0x00000002L -#define VFT2_FONT_TRUETYPE 0x00000003L - -#define VFFF_ISSHAREDFILE 0x0001 - -#define VFF_CURNEDEST 0x0001 -#define VFF_FILEINUSE 0x0002 -#define VFF_BUFFTOOSMALL 0x0004 - -#define VIFF_FORCEINSTALL 0x0001 -#define VIFF_DONTDELETEOLD 0x0002 - -#define VIF_TEMPFILE 0x00000001L -#define VIF_MISMATCH 0x00000002L -#define VIF_SRCOLD 0x00000004L - -#define VIF_DIFFLANG 0x00000008L -#define VIF_DIFFCODEPG 0x00000010L -#define VIF_DIFFTYPE 0x00000020L - -#define VIF_WRITEPROT 0x00000040L -#define VIF_FILEINUSE 0x00000080L -#define VIF_OUTOFSPACE 0x00000100L -#define VIF_ACCESSVIOLATION 0x00000200L -#define VIF_SHARINGVIOLATION 0x00000400L -#define VIF_CANNOTCREATE 0x00000800L -#define VIF_CANNOTDELETE 0x00001000L -#define VIF_CANNOTRENAME 0x00002000L -#define VIF_CANNOTDELETECUR 0x00004000L -#define VIF_OUTOFMEMORY 0x00008000L - -#define VIF_CANNOTREADSRC 0x00010000L -#define VIF_CANNOTREADDST 0x00020000L - -#define VIF_BUFFTOOSMALL 0x00040000L -#define VIF_CANNOTLOADLZ32 0x00080000L -#define VIF_CANNOTLOADCABINET 0x00100000L - -#ifndef RC_INVOKED - - typedef struct tagVS_FIXEDFILEINFO - { - DWORD dwSignature; - DWORD dwStrucVersion; - DWORD dwFileVersionMS; - DWORD dwFileVersionLS; - DWORD dwProductVersionMS; - DWORD dwProductVersionLS; - DWORD dwFileFlagsMask; - DWORD dwFileFlags; - DWORD dwFileOS; - DWORD dwFileType; - DWORD dwFileSubtype; - DWORD dwFileDateMS; - DWORD dwFileDateLS; - } VS_FIXEDFILEINFO; - -#ifdef UNICODE -#define VerFindFile VerFindFileW -#define VerInstallFile VerInstallFileW -#define GetFileVersionInfoSize GetFileVersionInfoSizeW -#define GetFileVersionInfo GetFileVersionInfoW -#define VerLanguageName VerLanguageNameW -#define VerQueryValue VerQueryValueW -#else -#define VerFindFile VerFindFileA -#define VerInstallFile VerInstallFileA -#define GetFileVersionInfoSize GetFileVersionInfoSizeA -#define GetFileVersionInfo GetFileVersionInfoA -#define VerLanguageName VerLanguageNameA -#define VerQueryValue VerQueryValueA -#endif - - DWORD WINAPI VerFindFileA(DWORD uFlags,LPSTR szFileName,LPSTR szWinDir,LPSTR szAppDir,LPSTR szCurDir,PUINT lpuCurDirLen,LPSTR szDestDir,PUINT lpuDestDirLen); - DWORD WINAPI VerFindFileW(DWORD uFlags,LPWSTR szFileName,LPWSTR szWinDir,LPWSTR szAppDir,LPWSTR szCurDir,PUINT lpuCurDirLen,LPWSTR szDestDir,PUINT lpuDestDirLen); - DWORD WINAPI VerInstallFileA(DWORD uFlags,LPSTR szSrcFileName,LPSTR szDestFileName,LPSTR szSrcDir,LPSTR szDestDir,LPSTR szCurDir,LPSTR szTmpFile,PUINT lpuTmpFileLen); - DWORD WINAPI VerInstallFileW(DWORD uFlags,LPWSTR szSrcFileName,LPWSTR szDestFileName,LPWSTR szSrcDir,LPWSTR szDestDir,LPWSTR szCurDir,LPWSTR szTmpFile,PUINT lpuTmpFileLen); - DWORD WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename,LPDWORD lpdwHandle); - DWORD WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename,LPDWORD lpdwHandle); - WINBOOL WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); - WINBOOL WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); - DWORD WINAPI VerLanguageNameA(DWORD wLang,LPSTR szLang,DWORD nSize); - DWORD WINAPI VerLanguageNameW(DWORD wLang,LPWSTR szLang,DWORD nSize); - WINBOOL WINAPI VerQueryValueA(const LPVOID pBlock,LPSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); - WINBOOL WINAPI VerQueryValueW(const LPVOID pBlock,LPWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); -#endif - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef VER_H +#define VER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define VS_FILE_INFO RT_VERSION +#define VS_VERSION_INFO 1 +#define VS_USER_DEFINED 100 + +#define VS_FFI_SIGNATURE 0xFEEF04BDL +#define VS_FFI_STRUCVERSION 0x00010000L +#define VS_FFI_FILEFLAGSMASK 0x0000003FL + +#define VS_FF_DEBUG 0x00000001L +#define VS_FF_PRERELEASE 0x00000002L +#define VS_FF_PATCHED 0x00000004L +#define VS_FF_PRIVATEBUILD 0x00000008L +#define VS_FF_INFOINFERRED 0x00000010L +#define VS_FF_SPECIALBUILD 0x00000020L + +#define VOS_UNKNOWN 0x00000000L +#define VOS_DOS 0x00010000L +#define VOS_OS216 0x00020000L +#define VOS_OS232 0x00030000L +#define VOS_NT 0x00040000L +#define VOS_WINCE 0x00050000L + +#define VOS__BASE 0x00000000L +#define VOS__WINDOWS16 0x00000001L +#define VOS__PM16 0x00000002L +#define VOS__PM32 0x00000003L +#define VOS__WINDOWS32 0x00000004L + +#define VOS_DOS_WINDOWS16 0x00010001L +#define VOS_DOS_WINDOWS32 0x00010004L +#define VOS_OS216_PM16 0x00020002L +#define VOS_OS232_PM32 0x00030003L +#define VOS_NT_WINDOWS32 0x00040004L + +#define VFT_UNKNOWN 0x00000000L +#define VFT_APP 0x00000001L +#define VFT_DLL 0x00000002L +#define VFT_DRV 0x00000003L +#define VFT_FONT 0x00000004L +#define VFT_VXD 0x00000005L +#define VFT_STATIC_LIB 0x00000007L + +#define VFT2_UNKNOWN 0x00000000L +#define VFT2_DRV_PRINTER 0x00000001L +#define VFT2_DRV_KEYBOARD 0x00000002L +#define VFT2_DRV_LANGUAGE 0x00000003L +#define VFT2_DRV_DISPLAY 0x00000004L +#define VFT2_DRV_MOUSE 0x00000005L +#define VFT2_DRV_NETWORK 0x00000006L +#define VFT2_DRV_SYSTEM 0x00000007L +#define VFT2_DRV_INSTALLABLE 0x00000008L +#define VFT2_DRV_SOUND 0x00000009L +#define VFT2_DRV_COMM 0x0000000AL +#define VFT2_DRV_INPUTMETHOD 0x0000000BL +#define VFT2_DRV_VERSIONED_PRINTER 0x0000000CL + +#define VFT2_FONT_RASTER 0x00000001L +#define VFT2_FONT_VECTOR 0x00000002L +#define VFT2_FONT_TRUETYPE 0x00000003L + +#define VFFF_ISSHAREDFILE 0x0001 + +#define VFF_CURNEDEST 0x0001 +#define VFF_FILEINUSE 0x0002 +#define VFF_BUFFTOOSMALL 0x0004 + +#define VIFF_FORCEINSTALL 0x0001 +#define VIFF_DONTDELETEOLD 0x0002 + +#define VIF_TEMPFILE 0x00000001L +#define VIF_MISMATCH 0x00000002L +#define VIF_SRCOLD 0x00000004L + +#define VIF_DIFFLANG 0x00000008L +#define VIF_DIFFCODEPG 0x00000010L +#define VIF_DIFFTYPE 0x00000020L + +#define VIF_WRITEPROT 0x00000040L +#define VIF_FILEINUSE 0x00000080L +#define VIF_OUTOFSPACE 0x00000100L +#define VIF_ACCESSVIOLATION 0x00000200L +#define VIF_SHARINGVIOLATION 0x00000400L +#define VIF_CANNOTCREATE 0x00000800L +#define VIF_CANNOTDELETE 0x00001000L +#define VIF_CANNOTRENAME 0x00002000L +#define VIF_CANNOTDELETECUR 0x00004000L +#define VIF_OUTOFMEMORY 0x00008000L + +#define VIF_CANNOTREADSRC 0x00010000L +#define VIF_CANNOTREADDST 0x00020000L + +#define VIF_BUFFTOOSMALL 0x00040000L +#define VIF_CANNOTLOADLZ32 0x00080000L +#define VIF_CANNOTLOADCABINET 0x00100000L + +#ifndef RC_INVOKED + + typedef struct tagVS_FIXEDFILEINFO + { + DWORD dwSignature; + DWORD dwStrucVersion; + DWORD dwFileVersionMS; + DWORD dwFileVersionLS; + DWORD dwProductVersionMS; + DWORD dwProductVersionLS; + DWORD dwFileFlagsMask; + DWORD dwFileFlags; + DWORD dwFileOS; + DWORD dwFileType; + DWORD dwFileSubtype; + DWORD dwFileDateMS; + DWORD dwFileDateLS; + } VS_FIXEDFILEINFO; + +#ifdef UNICODE +#define VerFindFile VerFindFileW +#define VerInstallFile VerInstallFileW +#define GetFileVersionInfoSize GetFileVersionInfoSizeW +#define GetFileVersionInfo GetFileVersionInfoW +#define VerLanguageName VerLanguageNameW +#define VerQueryValue VerQueryValueW +#else +#define VerFindFile VerFindFileA +#define VerInstallFile VerInstallFileA +#define GetFileVersionInfoSize GetFileVersionInfoSizeA +#define GetFileVersionInfo GetFileVersionInfoA +#define VerLanguageName VerLanguageNameA +#define VerQueryValue VerQueryValueA +#endif + + DWORD WINAPI VerFindFileA(DWORD uFlags,LPSTR szFileName,LPSTR szWinDir,LPSTR szAppDir,LPSTR szCurDir,PUINT lpuCurDirLen,LPSTR szDestDir,PUINT lpuDestDirLen); + DWORD WINAPI VerFindFileW(DWORD uFlags,LPWSTR szFileName,LPWSTR szWinDir,LPWSTR szAppDir,LPWSTR szCurDir,PUINT lpuCurDirLen,LPWSTR szDestDir,PUINT lpuDestDirLen); + DWORD WINAPI VerInstallFileA(DWORD uFlags,LPSTR szSrcFileName,LPSTR szDestFileName,LPSTR szSrcDir,LPSTR szDestDir,LPSTR szCurDir,LPSTR szTmpFile,PUINT lpuTmpFileLen); + DWORD WINAPI VerInstallFileW(DWORD uFlags,LPWSTR szSrcFileName,LPWSTR szDestFileName,LPWSTR szSrcDir,LPWSTR szDestDir,LPWSTR szCurDir,LPWSTR szTmpFile,PUINT lpuTmpFileLen); + DWORD WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename,LPDWORD lpdwHandle); + DWORD WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename,LPDWORD lpdwHandle); + WINBOOL WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); + WINBOOL WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); + DWORD WINAPI VerLanguageNameA(DWORD wLang,LPSTR szLang,DWORD nSize); + DWORD WINAPI VerLanguageNameW(DWORD wLang,LPWSTR szLang,DWORD nSize); + WINBOOL WINAPI VerQueryValueA(const LPVOID pBlock,LPSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); + WINBOOL WINAPI VerQueryValueW(const LPVOID pBlock,LPWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/ws2ipdef.h b/tcc/include/winapi/ws2ipdef.h index 1f6c1c06..46ea46f1 100644 --- a/tcc/include/winapi/ws2ipdef.h +++ b/tcc/include/winapi/ws2ipdef.h @@ -1,21 +1,21 @@ -#ifndef _WS2IPDEF_H -#define _WS2IPDEF_H - -#if __GNUC__ >=3 -#pragma GCC system_header -#endif - -#include - -struct ip_mreq { - struct in_addr imr_multiaddr; - struct in_addr imr_interface; -}; - -struct ip_mreq_source { - struct in_addr imr_multiaddr; - struct in_addr imr_sourceaddr; - struct in_addr imr_interface; -}; - -#endif +#ifndef _WS2IPDEF_H +#define _WS2IPDEF_H + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#include + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_sourceaddr; + struct in_addr imr_interface; +}; + +#endif diff --git a/tcc/include/winapi/ws2tcpip.h b/tcc/include/winapi/ws2tcpip.h index ac45767d..bdcf8b45 100644 --- a/tcc/include/winapi/ws2tcpip.h +++ b/tcc/include/winapi/ws2tcpip.h @@ -1,391 +1,391 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WS2TCPIP_H -#define _WS2TCPIP_H - -#if __GNUC__ >=3 -#pragma GCC system_header -#endif - -#include - -struct ip_msfilter { - struct in_addr imsf_multiaddr; - struct in_addr imsf_interface; - u_long imsf_fmode; - u_long imsf_numsrc; - struct in_addr imsf_slist[1]; -}; - -#define IP_MSFILTER_SIZE(numsrc) (sizeof(struct ip_msfilter)-sizeof(struct in_addr) + (numsrc)*sizeof(struct in_addr)) - -#define MCAST_INCLUDE 0 -#define MCAST_EXCLUDE 1 - -#define SIO_GET_INTERFACE_LIST _IOR('t',127,u_long) - -#define SIO_GET_INTERFACE_LIST_EX _IOR('t',126,u_long) -#define SIO_SET_MULTICAST_FILTER _IOW('t',125,u_long) -#define SIO_GET_MULTICAST_FILTER _IOW('t',124 | IOC_IN,u_long) - -#define IP_OPTIONS 1 -#define IP_HDRINCL 2 -#define IP_TOS 3 -#define IP_TTL 4 -#define IP_MULTICAST_IF 9 -#define IP_MULTICAST_TTL 10 -#define IP_MULTICAST_LOOP 11 -#define IP_ADD_MEMBERSHIP 12 -#define IP_DROP_MEMBERSHIP 13 -#define IP_DONTFRAGMENT 14 -#define IP_ADD_SOURCE_MEMBERSHIP 15 -#define IP_DROP_SOURCE_MEMBERSHIP 16 -#define IP_BLOCK_SOURCE 17 -#define IP_UNBLOCK_SOURCE 18 -#define IP_PKTINFO 19 -#define IP_RECEIVE_BROADCAST 22 - -#define IPV6_HDRINCL 2 -#define IPV6_UNICAST_HOPS 4 -#define IPV6_MULTICAST_IF 9 -#define IPV6_MULTICAST_HOPS 10 -#define IPV6_MULTICAST_LOOP 11 -#define IPV6_ADD_MEMBERSHIP 12 -#define IPV6_DROP_MEMBERSHIP 13 -#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP -#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP -#define IPV6_PKTINFO 19 -#define IPV6_HOPLIMIT 21 -#define IPV6_PROTECTION_LEVEL 23 - -#define PROTECTION_LEVEL_UNRESTRICTED 10 -#define PROTECTION_LEVEL_DEFAULT 20 -#define PROTECTION_LEVEL_RESTRICTED 30 - -#define UDP_NOCHECKSUM 1 -#define UDP_CHECKSUM_COVERAGE 20 - -#define TCP_EXPEDITED_1122 0x0002 - -#ifndef s6_addr - -struct in6_addr { - __MINGW_EXTENSION union { - u_char Byte[16]; - u_short Word[8]; - } u; -}; - -#define in_addr6 in6_addr - -#define _S6_un u -#define _S6_u8 Byte -#define s6_addr _S6_un._S6_u8 - -#define s6_bytes u.Byte -#define s6_words u.Word -#endif - -typedef struct ipv6_mreq { - struct in6_addr ipv6mr_multiaddr; - unsigned int ipv6mr_interface; -} IPV6_MREQ; - -struct sockaddr_in6_old { - short sin6_family; - u_short sin6_port; - u_long sin6_flowinfo; - struct in6_addr sin6_addr; -}; - -struct sockaddr_in6 { - short sin6_family; - u_short sin6_port; - u_long sin6_flowinfo; - struct in6_addr sin6_addr; - u_long sin6_scope_id; -}; - -typedef struct in6_addr IN6_ADDR; -typedef struct in6_addr *PIN6_ADDR; -typedef struct in6_addr *LPIN6_ADDR; - -typedef struct sockaddr_in6 SOCKADDR_IN6; -typedef struct sockaddr_in6 *PSOCKADDR_IN6; -typedef struct sockaddr_in6 *LPSOCKADDR_IN6; - -#define SS_PORT(ssp) (((struct sockaddr_in*)(ssp))->sin_port) - -#define IN6ADDR_ANY_INIT { 0 } -#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } - -#ifdef __cplusplus -extern "C" { -#endif - - extern const struct in6_addr in6addr_any; - extern const struct in6_addr in6addr_loopback; - -#ifdef __cplusplus -} -#endif - -#define WS2TCPIP_INLINE __CRT_INLINE - -int IN6_ADDR_EQUAL(const struct in6_addr *,const struct in6_addr *); -int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *); -int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *); -int IN6_IS_ADDR_MULTICAST(const struct in6_addr *); -int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *); -int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *); -int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *); -int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *); -int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *); -int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *); -int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *); -int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *); -int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *); -int IN6ADDR_ISANY(const struct sockaddr_in6 *); -int IN6ADDR_ISLOOPBACK(const struct sockaddr_in6 *); -void IN6_SET_ADDR_UNSPECIFIED(struct in6_addr *); -void IN6_SET_ADDR_LOOPBACK(struct in6_addr *); -void IN6ADDR_SETANY(struct sockaddr_in6 *); -void IN6ADDR_SETLOOPBACK(struct sockaddr_in6 *); - -#ifndef __CRT__NO_INLINE -WS2TCPIP_INLINE int IN6_ADDR_EQUAL(const struct in6_addr *a,const struct in6_addr *b) { return (memcmp(a,b,sizeof(struct in6_addr))==0); } -WS2TCPIP_INLINE int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && (a->s6_words[6]==0) && (a->s6_words[7]==0)); } -WS2TCPIP_INLINE int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && (a->s6_words[6]==0) && (a->s6_words[7]==0x0100)); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MULTICAST(const struct in6_addr *a) { return (a->s6_bytes[0]==0xff); } -WS2TCPIP_INLINE int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *a) { return ((a->s6_bytes[0]==0xfe) && ((a->s6_bytes[1] & 0xc0)==0x80)); } -WS2TCPIP_INLINE int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *a) { return ((a->s6_bytes[0]==0xfe) && ((a->s6_bytes[1] & 0xc0)==0xc0)); } -WS2TCPIP_INLINE int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0xffff)); } -WS2TCPIP_INLINE int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && !((a->s6_words[6]==0) && (a->s6_addr[14]==0) && ((a->s6_addr[15]==0) || (a->s6_addr[15]==1)))); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==1); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==2); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==5); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==8); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==0xe); } -WS2TCPIP_INLINE int IN6ADDR_ISANY(const struct sockaddr_in6 *a) { return ((a->sin6_family==AF_INET6) && IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)); } -WS2TCPIP_INLINE int IN6ADDR_ISLOOPBACK(const struct sockaddr_in6 *a) { return ((a->sin6_family==AF_INET6) && IN6_IS_ADDR_LOOPBACK(&a->sin6_addr)); } -WS2TCPIP_INLINE void IN6_SET_ADDR_UNSPECIFIED(struct in6_addr *a) { memset(a->s6_bytes,0,sizeof(struct in6_addr)); } -WS2TCPIP_INLINE void IN6_SET_ADDR_LOOPBACK(struct in6_addr *a) { - memset(a->s6_bytes,0,sizeof(struct in6_addr)); - a->s6_bytes[15] = 1; -} -WS2TCPIP_INLINE void IN6ADDR_SETANY(struct sockaddr_in6 *a) { - a->sin6_family = AF_INET6; - a->sin6_port = 0; - a->sin6_flowinfo = 0; - IN6_SET_ADDR_UNSPECIFIED(&a->sin6_addr); - a->sin6_scope_id = 0; -} -WS2TCPIP_INLINE void IN6ADDR_SETLOOPBACK(struct sockaddr_in6 *a) { - a->sin6_family = AF_INET6; - a->sin6_port = 0; - a->sin6_flowinfo = 0; - IN6_SET_ADDR_LOOPBACK(&a->sin6_addr); - a->sin6_scope_id = 0; -} -#endif /* !__CRT__NO_INLINE */ - -typedef union sockaddr_gen { - struct sockaddr Address; - struct sockaddr_in AddressIn; - struct sockaddr_in6_old AddressIn6; -} sockaddr_gen; - -typedef struct _INTERFACE_INFO { - u_long iiFlags; - sockaddr_gen iiAddress; - sockaddr_gen iiBroadcastAddress; - sockaddr_gen iiNetmask; -} INTERFACE_INFO,*LPINTERFACE_INFO; - -typedef struct _INTERFACE_INFO_EX { - u_long iiFlags; - SOCKET_ADDRESS iiAddress; - SOCKET_ADDRESS iiBroadcastAddress; - SOCKET_ADDRESS iiNetmask; -} INTERFACE_INFO_EX,*LPINTERFACE_INFO_EX; - -#define IFF_UP 0x00000001 -#define IFF_BROADCAST 0x00000002 -#define IFF_LOOPBACK 0x00000004 -#define IFF_POINTTOPOINT 0x00000008 -#define IFF_MULTICAST 0x00000010 - -typedef struct in_pktinfo { - IN_ADDR ipi_addr; - UINT ipi_ifindex; -} IN_PKTINFO; - -C_ASSERT(sizeof(IN_PKTINFO)==8); - -typedef struct in6_pktinfo { - IN6_ADDR ipi6_addr; - UINT ipi6_ifindex; -} IN6_PKTINFO; - -C_ASSERT(sizeof(IN6_PKTINFO)==20); - -#define EAI_AGAIN WSATRY_AGAIN -#define EAI_BADFLAGS WSAEINVAL -#define EAI_FAIL WSANO_RECOVERY -#define EAI_FAMILY WSAEAFNOSUPPORT -#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY - -#define EAI_NONAME WSAHOST_NOT_FOUND -#define EAI_SERVICE WSATYPE_NOT_FOUND -#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT - -#define EAI_NODATA EAI_NONAME - -typedef struct addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - size_t ai_addrlen; - char *ai_canonname; - struct sockaddr *ai_addr; - struct addrinfo *ai_next; -} ADDRINFOA,*PADDRINFOA; - -typedef struct addrinfoW { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - size_t ai_addrlen; - PWSTR ai_canonname; - struct sockaddr *ai_addr; - struct addrinfoW *ai_next; -} ADDRINFOW,*PADDRINFOW; - -#ifdef UNICODE -typedef ADDRINFOW ADDRINFOT,*PADDRINFOT; -#else -typedef ADDRINFOA ADDRINFOT,*PADDRINFOT; -#endif - -typedef ADDRINFOA ADDRINFO,*LPADDRINFO; - -#define AI_PASSIVE 0x1 -#define AI_CANONNAME 0x2 -#define AI_NUMERICHOST 0x4 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef UNICODE -#define GetAddrInfo GetAddrInfoW -#else -#define GetAddrInfo GetAddrInfoA -#endif - - WINSOCK_API_LINKAGE int WSAAPI getaddrinfo(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res); - WINSOCK_API_LINKAGE int WSAAPI GetAddrInfoW(PCWSTR pNodeName,PCWSTR pServiceName,const ADDRINFOW *pHints,PADDRINFOW *ppResult); - -#define GetAddrInfoA getaddrinfo - -#if INCL_WINSOCK_API_TYPEDEFS - typedef int (WSAAPI *LPFN_GETADDRINFO)(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res); - typedef int (WSAAPI *LPFN_GETADDRINFOW)(PCWSTR pNodeName,PCWSTR pServiceName,const ADDRINFOW *pHints,PADDRINFOW *ppResult); - -#define LPFN_GETADDRINFOA LPFN_GETADDRINFO - -#ifdef UNICODE -#define LPFN_GETADDRINFOT LPFN_GETADDRINFOW -#else -#define LPFN_GETADDRINFOT LPFN_GETADDRINFOA -#endif -#endif - -#ifdef UNICODE -#define FreeAddrInfo FreeAddrInfoW -#else -#define FreeAddrInfo FreeAddrInfoA -#endif - - WINSOCK_API_LINKAGE void WSAAPI freeaddrinfo(LPADDRINFO pAddrInfo); - WINSOCK_API_LINKAGE void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo); - -#define FreeAddrInfoA freeaddrinfo - -#if INCL_WINSOCK_API_TYPEDEFS - typedef void (WSAAPI *LPFN_FREEADDRINFO)(struct addrinfo *ai); - typedef void (WSAAPI *LPFN_FREEADDRINFOW)(PADDRINFOW pAddrInfo); - -#define LPFN_FREEADDRINFOA LPFN_FREEADDRINFO - -#ifdef UNICODE -#define LPFN_FREEADDRINFOT LPFN_FREEADDRINFOW -#else -#define LPFN_FREEADDRINFOT LPFN_FREEADDRINFOA -#endif -#endif - -#pragma push_macro("socklen_t") -#undef socklen_t - - typedef int socklen_t; - -#ifdef UNICODE -#define GetNameInfo GetNameInfoW -#else -#define GetNameInfo GetNameInfoA -#endif - - WINSOCK_API_LINKAGE int WSAAPI getnameinfo(const struct sockaddr *sa,socklen_t salen,char *host,DWORD hostlen,char *serv,DWORD servlen,int flags); - WINSOCK_API_LINKAGE INT WSAAPI GetNameInfoW(const SOCKADDR *pSockaddr,socklen_t SockaddrLength,PWCHAR pNodeBuffer,DWORD NodeBufferSize,PWCHAR pServiceBuffer,DWORD ServiceBufferSize,INT Flags); - -#define GetNameInfoA getnameinfo - -#if INCL_WINSOCK_API_TYPEDEFS - typedef int (WSAAPI *LPFN_GETNAMEINFO)(const struct sockaddr *sa,socklen_t salen,char *host,DWORD hostlen,char *serv,DWORD servlen,int flags); - typedef INT (WSAAPI *LPFN_GETNAMEINFOW)(const SOCKADDR *pSockaddr,socklen_t SockaddrLength,PWCHAR pNodeBuffer,DWORD NodeBufferSize,PWCHAR pServiceBuffer,DWORD ServiceBufferSize,INT Flags); - -#define LPFN_GETNAMEINFOA LPFN_GETNAMEINFO - -#ifdef UNICODE -#define LPFN_GETNAMEINFOT LPFN_GETNAMEINFOW -#else -#define LPFN_GETNAMEINFOT LPFN_GETNAMEINFOA -#endif -#endif - -#pragma pop_macro("socklen_t") - -#ifdef UNICODE -#define gai_strerror gai_strerrorW -#else -#define gai_strerror gai_strerrorA -#endif - -#define GAI_STRERROR_BUFFER_SIZE 1024 - -char *gai_strerrorA (int); -WCHAR *gai_strerrorW(int); - -#define NI_MAXHOST 1025 -#define NI_MAXSERV 32 - -#define INET_ADDRSTRLEN 22 -#define INET6_ADDRSTRLEN 65 - -#define NI_NOFQDN 0x01 -#define NI_NUMERICHOST 0x02 -#define NI_NAMEREQD 0x04 -#define NI_NUMERICSERV 0x08 -#define NI_DGRAM 0x10 - -#ifdef __cplusplus -} -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WS2TCPIP_H +#define _WS2TCPIP_H + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#include + +struct ip_msfilter { + struct in_addr imsf_multiaddr; + struct in_addr imsf_interface; + u_long imsf_fmode; + u_long imsf_numsrc; + struct in_addr imsf_slist[1]; +}; + +#define IP_MSFILTER_SIZE(numsrc) (sizeof(struct ip_msfilter)-sizeof(struct in_addr) + (numsrc)*sizeof(struct in_addr)) + +#define MCAST_INCLUDE 0 +#define MCAST_EXCLUDE 1 + +#define SIO_GET_INTERFACE_LIST _IOR('t',127,u_long) + +#define SIO_GET_INTERFACE_LIST_EX _IOR('t',126,u_long) +#define SIO_SET_MULTICAST_FILTER _IOW('t',125,u_long) +#define SIO_GET_MULTICAST_FILTER _IOW('t',124 | IOC_IN,u_long) + +#define IP_OPTIONS 1 +#define IP_HDRINCL 2 +#define IP_TOS 3 +#define IP_TTL 4 +#define IP_MULTICAST_IF 9 +#define IP_MULTICAST_TTL 10 +#define IP_MULTICAST_LOOP 11 +#define IP_ADD_MEMBERSHIP 12 +#define IP_DROP_MEMBERSHIP 13 +#define IP_DONTFRAGMENT 14 +#define IP_ADD_SOURCE_MEMBERSHIP 15 +#define IP_DROP_SOURCE_MEMBERSHIP 16 +#define IP_BLOCK_SOURCE 17 +#define IP_UNBLOCK_SOURCE 18 +#define IP_PKTINFO 19 +#define IP_RECEIVE_BROADCAST 22 + +#define IPV6_HDRINCL 2 +#define IPV6_UNICAST_HOPS 4 +#define IPV6_MULTICAST_IF 9 +#define IPV6_MULTICAST_HOPS 10 +#define IPV6_MULTICAST_LOOP 11 +#define IPV6_ADD_MEMBERSHIP 12 +#define IPV6_DROP_MEMBERSHIP 13 +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#define IPV6_PKTINFO 19 +#define IPV6_HOPLIMIT 21 +#define IPV6_PROTECTION_LEVEL 23 + +#define PROTECTION_LEVEL_UNRESTRICTED 10 +#define PROTECTION_LEVEL_DEFAULT 20 +#define PROTECTION_LEVEL_RESTRICTED 30 + +#define UDP_NOCHECKSUM 1 +#define UDP_CHECKSUM_COVERAGE 20 + +#define TCP_EXPEDITED_1122 0x0002 + +#ifndef s6_addr + +struct in6_addr { + __MINGW_EXTENSION union { + u_char Byte[16]; + u_short Word[8]; + } u; +}; + +#define in_addr6 in6_addr + +#define _S6_un u +#define _S6_u8 Byte +#define s6_addr _S6_un._S6_u8 + +#define s6_bytes u.Byte +#define s6_words u.Word +#endif + +typedef struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned int ipv6mr_interface; +} IPV6_MREQ; + +struct sockaddr_in6_old { + short sin6_family; + u_short sin6_port; + u_long sin6_flowinfo; + struct in6_addr sin6_addr; +}; + +struct sockaddr_in6 { + short sin6_family; + u_short sin6_port; + u_long sin6_flowinfo; + struct in6_addr sin6_addr; + u_long sin6_scope_id; +}; + +typedef struct in6_addr IN6_ADDR; +typedef struct in6_addr *PIN6_ADDR; +typedef struct in6_addr *LPIN6_ADDR; + +typedef struct sockaddr_in6 SOCKADDR_IN6; +typedef struct sockaddr_in6 *PSOCKADDR_IN6; +typedef struct sockaddr_in6 *LPSOCKADDR_IN6; + +#define SS_PORT(ssp) (((struct sockaddr_in*)(ssp))->sin_port) + +#define IN6ADDR_ANY_INIT { 0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } + +#ifdef __cplusplus +extern "C" { +#endif + + extern const struct in6_addr in6addr_any; + extern const struct in6_addr in6addr_loopback; + +#ifdef __cplusplus +} +#endif + +#define WS2TCPIP_INLINE __CRT_INLINE + +int IN6_ADDR_EQUAL(const struct in6_addr *,const struct in6_addr *); +int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *); +int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *); +int IN6_IS_ADDR_MULTICAST(const struct in6_addr *); +int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *); +int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *); +int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *); +int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *); +int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *); +int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *); +int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *); +int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *); +int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *); +int IN6ADDR_ISANY(const struct sockaddr_in6 *); +int IN6ADDR_ISLOOPBACK(const struct sockaddr_in6 *); +void IN6_SET_ADDR_UNSPECIFIED(struct in6_addr *); +void IN6_SET_ADDR_LOOPBACK(struct in6_addr *); +void IN6ADDR_SETANY(struct sockaddr_in6 *); +void IN6ADDR_SETLOOPBACK(struct sockaddr_in6 *); + +#ifndef __CRT__NO_INLINE +WS2TCPIP_INLINE int IN6_ADDR_EQUAL(const struct in6_addr *a,const struct in6_addr *b) { return (memcmp(a,b,sizeof(struct in6_addr))==0); } +WS2TCPIP_INLINE int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && (a->s6_words[6]==0) && (a->s6_words[7]==0)); } +WS2TCPIP_INLINE int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && (a->s6_words[6]==0) && (a->s6_words[7]==0x0100)); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MULTICAST(const struct in6_addr *a) { return (a->s6_bytes[0]==0xff); } +WS2TCPIP_INLINE int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *a) { return ((a->s6_bytes[0]==0xfe) && ((a->s6_bytes[1] & 0xc0)==0x80)); } +WS2TCPIP_INLINE int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *a) { return ((a->s6_bytes[0]==0xfe) && ((a->s6_bytes[1] & 0xc0)==0xc0)); } +WS2TCPIP_INLINE int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0xffff)); } +WS2TCPIP_INLINE int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && !((a->s6_words[6]==0) && (a->s6_addr[14]==0) && ((a->s6_addr[15]==0) || (a->s6_addr[15]==1)))); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==1); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==2); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==5); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==8); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==0xe); } +WS2TCPIP_INLINE int IN6ADDR_ISANY(const struct sockaddr_in6 *a) { return ((a->sin6_family==AF_INET6) && IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)); } +WS2TCPIP_INLINE int IN6ADDR_ISLOOPBACK(const struct sockaddr_in6 *a) { return ((a->sin6_family==AF_INET6) && IN6_IS_ADDR_LOOPBACK(&a->sin6_addr)); } +WS2TCPIP_INLINE void IN6_SET_ADDR_UNSPECIFIED(struct in6_addr *a) { memset(a->s6_bytes,0,sizeof(struct in6_addr)); } +WS2TCPIP_INLINE void IN6_SET_ADDR_LOOPBACK(struct in6_addr *a) { + memset(a->s6_bytes,0,sizeof(struct in6_addr)); + a->s6_bytes[15] = 1; +} +WS2TCPIP_INLINE void IN6ADDR_SETANY(struct sockaddr_in6 *a) { + a->sin6_family = AF_INET6; + a->sin6_port = 0; + a->sin6_flowinfo = 0; + IN6_SET_ADDR_UNSPECIFIED(&a->sin6_addr); + a->sin6_scope_id = 0; +} +WS2TCPIP_INLINE void IN6ADDR_SETLOOPBACK(struct sockaddr_in6 *a) { + a->sin6_family = AF_INET6; + a->sin6_port = 0; + a->sin6_flowinfo = 0; + IN6_SET_ADDR_LOOPBACK(&a->sin6_addr); + a->sin6_scope_id = 0; +} +#endif /* !__CRT__NO_INLINE */ + +typedef union sockaddr_gen { + struct sockaddr Address; + struct sockaddr_in AddressIn; + struct sockaddr_in6_old AddressIn6; +} sockaddr_gen; + +typedef struct _INTERFACE_INFO { + u_long iiFlags; + sockaddr_gen iiAddress; + sockaddr_gen iiBroadcastAddress; + sockaddr_gen iiNetmask; +} INTERFACE_INFO,*LPINTERFACE_INFO; + +typedef struct _INTERFACE_INFO_EX { + u_long iiFlags; + SOCKET_ADDRESS iiAddress; + SOCKET_ADDRESS iiBroadcastAddress; + SOCKET_ADDRESS iiNetmask; +} INTERFACE_INFO_EX,*LPINTERFACE_INFO_EX; + +#define IFF_UP 0x00000001 +#define IFF_BROADCAST 0x00000002 +#define IFF_LOOPBACK 0x00000004 +#define IFF_POINTTOPOINT 0x00000008 +#define IFF_MULTICAST 0x00000010 + +typedef struct in_pktinfo { + IN_ADDR ipi_addr; + UINT ipi_ifindex; +} IN_PKTINFO; + +C_ASSERT(sizeof(IN_PKTINFO)==8); + +typedef struct in6_pktinfo { + IN6_ADDR ipi6_addr; + UINT ipi6_ifindex; +} IN6_PKTINFO; + +C_ASSERT(sizeof(IN6_PKTINFO)==20); + +#define EAI_AGAIN WSATRY_AGAIN +#define EAI_BADFLAGS WSAEINVAL +#define EAI_FAIL WSANO_RECOVERY +#define EAI_FAMILY WSAEAFNOSUPPORT +#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY + +#define EAI_NONAME WSAHOST_NOT_FOUND +#define EAI_SERVICE WSATYPE_NOT_FOUND +#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT + +#define EAI_NODATA EAI_NONAME + +typedef struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +} ADDRINFOA,*PADDRINFOA; + +typedef struct addrinfoW { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + PWSTR ai_canonname; + struct sockaddr *ai_addr; + struct addrinfoW *ai_next; +} ADDRINFOW,*PADDRINFOW; + +#ifdef UNICODE +typedef ADDRINFOW ADDRINFOT,*PADDRINFOT; +#else +typedef ADDRINFOA ADDRINFOT,*PADDRINFOT; +#endif + +typedef ADDRINFOA ADDRINFO,*LPADDRINFO; + +#define AI_PASSIVE 0x1 +#define AI_CANONNAME 0x2 +#define AI_NUMERICHOST 0x4 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef UNICODE +#define GetAddrInfo GetAddrInfoW +#else +#define GetAddrInfo GetAddrInfoA +#endif + + WINSOCK_API_LINKAGE int WSAAPI getaddrinfo(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res); + WINSOCK_API_LINKAGE int WSAAPI GetAddrInfoW(PCWSTR pNodeName,PCWSTR pServiceName,const ADDRINFOW *pHints,PADDRINFOW *ppResult); + +#define GetAddrInfoA getaddrinfo + +#if INCL_WINSOCK_API_TYPEDEFS + typedef int (WSAAPI *LPFN_GETADDRINFO)(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res); + typedef int (WSAAPI *LPFN_GETADDRINFOW)(PCWSTR pNodeName,PCWSTR pServiceName,const ADDRINFOW *pHints,PADDRINFOW *ppResult); + +#define LPFN_GETADDRINFOA LPFN_GETADDRINFO + +#ifdef UNICODE +#define LPFN_GETADDRINFOT LPFN_GETADDRINFOW +#else +#define LPFN_GETADDRINFOT LPFN_GETADDRINFOA +#endif +#endif + +#ifdef UNICODE +#define FreeAddrInfo FreeAddrInfoW +#else +#define FreeAddrInfo FreeAddrInfoA +#endif + + WINSOCK_API_LINKAGE void WSAAPI freeaddrinfo(LPADDRINFO pAddrInfo); + WINSOCK_API_LINKAGE void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo); + +#define FreeAddrInfoA freeaddrinfo + +#if INCL_WINSOCK_API_TYPEDEFS + typedef void (WSAAPI *LPFN_FREEADDRINFO)(struct addrinfo *ai); + typedef void (WSAAPI *LPFN_FREEADDRINFOW)(PADDRINFOW pAddrInfo); + +#define LPFN_FREEADDRINFOA LPFN_FREEADDRINFO + +#ifdef UNICODE +#define LPFN_FREEADDRINFOT LPFN_FREEADDRINFOW +#else +#define LPFN_FREEADDRINFOT LPFN_FREEADDRINFOA +#endif +#endif + +#pragma push_macro("socklen_t") +#undef socklen_t + + typedef int socklen_t; + +#ifdef UNICODE +#define GetNameInfo GetNameInfoW +#else +#define GetNameInfo GetNameInfoA +#endif + + WINSOCK_API_LINKAGE int WSAAPI getnameinfo(const struct sockaddr *sa,socklen_t salen,char *host,DWORD hostlen,char *serv,DWORD servlen,int flags); + WINSOCK_API_LINKAGE INT WSAAPI GetNameInfoW(const SOCKADDR *pSockaddr,socklen_t SockaddrLength,PWCHAR pNodeBuffer,DWORD NodeBufferSize,PWCHAR pServiceBuffer,DWORD ServiceBufferSize,INT Flags); + +#define GetNameInfoA getnameinfo + +#if INCL_WINSOCK_API_TYPEDEFS + typedef int (WSAAPI *LPFN_GETNAMEINFO)(const struct sockaddr *sa,socklen_t salen,char *host,DWORD hostlen,char *serv,DWORD servlen,int flags); + typedef INT (WSAAPI *LPFN_GETNAMEINFOW)(const SOCKADDR *pSockaddr,socklen_t SockaddrLength,PWCHAR pNodeBuffer,DWORD NodeBufferSize,PWCHAR pServiceBuffer,DWORD ServiceBufferSize,INT Flags); + +#define LPFN_GETNAMEINFOA LPFN_GETNAMEINFO + +#ifdef UNICODE +#define LPFN_GETNAMEINFOT LPFN_GETNAMEINFOW +#else +#define LPFN_GETNAMEINFOT LPFN_GETNAMEINFOA +#endif +#endif + +#pragma pop_macro("socklen_t") + +#ifdef UNICODE +#define gai_strerror gai_strerrorW +#else +#define gai_strerror gai_strerrorA +#endif + +#define GAI_STRERROR_BUFFER_SIZE 1024 + +char *gai_strerrorA (int); +WCHAR *gai_strerrorW(int); + +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 + +#define INET_ADDRSTRLEN 22 +#define INET6_ADDRSTRLEN 65 + +#define NI_NOFQDN 0x01 +#define NI_NUMERICHOST 0x02 +#define NI_NAMEREQD 0x04 +#define NI_NUMERICSERV 0x08 +#define NI_DGRAM 0x10 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tcc/lib/kernel32.def b/tcc/lib/kernel32.def index f03e17ba..41383556 100644 --- a/tcc/lib/kernel32.def +++ b/tcc/lib/kernel32.def @@ -1,770 +1,770 @@ -LIBRARY kernel32.dll - -EXPORTS -AddAtomA -AddAtomW -AllocConsole -AllocLSCallback -AllocSLCallback -AreFileApisANSI -BackupRead -BackupSeek -BackupWrite -Beep -BeginUpdateResourceA -BeginUpdateResourceW -BuildCommDCBA -BuildCommDCBAndTimeoutsA -BuildCommDCBAndTimeoutsW -BuildCommDCBW -CallNamedPipeA -CallNamedPipeW -Callback12 -Callback16 -Callback20 -Callback24 -Callback28 -Callback32 -Callback36 -Callback4 -Callback40 -Callback44 -Callback48 -Callback52 -Callback56 -Callback60 -Callback64 -Callback8 -CancelDeviceWakeupRequest -CancelIo -CancelWaitableTimer -ClearCommBreak -ClearCommError -CloseHandle -CloseProfileUserMapping -CloseSystemHandle -CommConfigDialogA -CommConfigDialogW -CompareFileTime -CompareStringA -CompareStringW -ConnectNamedPipe -ContinueDebugEvent -ConvertDefaultLocale -ConvertThreadToFiber -ConvertToGlobalHandle -CopyFileA -CopyFileExA -CopyFileExW -CopyFileW -CreateConsoleScreenBuffer -CreateDirectoryA -CreateDirectoryExA -CreateDirectoryExW -CreateDirectoryW -CreateEventA -CreateEventW -CreateFiber -CreateFileA -CreateFileMappingA -CreateFileMappingW -CreateFileW -CreateIoCompletionPort -CreateKernelThread -CreateMailslotA -CreateMailslotW -CreateMutexA -CreateMutexW -CreateNamedPipeA -CreateNamedPipeW -CreatePipe -CreateProcessA -CreateProcessW -CreateRemoteThread -CreateSemaphoreA -CreateSemaphoreW -CreateSocketHandle -CreateTapePartition -CreateThread -CreateToolhelp32Snapshot -CreateWaitableTimerA -CreateWaitableTimerW -DebugActiveProcess -DebugBreak -DefineDosDeviceA -DefineDosDeviceW -DeleteAtom -DeleteCriticalSection -DeleteFiber -DeleteFileA -DeleteFileW -DeviceIoControl -DisableThreadLibraryCalls -DisconnectNamedPipe -DosDateTimeToFileTime -DuplicateHandle -EndUpdateResourceA -EndUpdateResourceW -EnterCriticalSection -EnumCalendarInfoA -EnumCalendarInfoExA -EnumCalendarInfoExW -EnumCalendarInfoW -EnumDateFormatsA -EnumDateFormatsExA -EnumDateFormatsExW -EnumDateFormatsW -EnumLanguageGroupLocalesA -EnumLanguageGroupLocalesW -EnumResourceLanguagesA -EnumResourceLanguagesW -EnumResourceNamesA -EnumResourceNamesW -EnumResourceTypesA -EnumResourceTypesW -EnumSystemCodePagesA -EnumSystemCodePagesW -EnumSystemGeoID -EnumSystemLanguageGroupsA -EnumSystemLanguageGroupsW -EnumSystemLocalesA -EnumSystemLocalesW -EnumTimeFormatsA -EnumTimeFormatsW -EnumUILanguagesA -EnumUILanguagesW -EraseTape -EscapeCommFunction -ExitProcess -ExitThread -ExpandEnvironmentStringsA -ExpandEnvironmentStringsW -FT_Exit0 -FT_Exit12 -FT_Exit16 -FT_Exit20 -FT_Exit24 -FT_Exit28 -FT_Exit32 -FT_Exit36 -FT_Exit4 -FT_Exit40 -FT_Exit44 -FT_Exit48 -FT_Exit52 -FT_Exit56 -FT_Exit8 -FT_Prolog -FT_Thunk -FatalAppExitA -FatalAppExitW -FatalExit -FileTimeToDosDateTime -FileTimeToLocalFileTime -FileTimeToSystemTime -FillConsoleOutputAttribute -FillConsoleOutputCharacterA -FillConsoleOutputCharacterW -FindAtomA -FindAtomW -FindClose -FindCloseChangeNotification -FindFirstChangeNotificationA -FindFirstChangeNotificationW -FindFirstFileA -FindFirstFileExA -FindFirstFileExW -FindFirstFileW -FindNextChangeNotification -FindNextFileA -FindNextFileW -FindResourceA -FindResourceExA -FindResourceExW -FindResourceW -FlushConsoleInputBuffer -FlushFileBuffers -FlushInstructionCache -FlushViewOfFile -FoldStringA -FoldStringW -FormatMessageA -FormatMessageW -FreeConsole -FreeEnvironmentStringsA -FreeEnvironmentStringsW -FreeLSCallback -FreeLibrary -FreeLibraryAndExitThread -FreeResource -FreeSLCallback -GenerateConsoleCtrlEvent -GetACP -GetAtomNameA -GetAtomNameW -GetBinaryType -GetBinaryTypeA -GetBinaryTypeW -GetCPInfo -GetCPInfoExA -GetCPInfoExW -GetCalendarInfoA -GetCalendarInfoW -GetCommConfig -GetCommMask -GetCommModemStatus -GetCommProperties -GetCommState -GetCommTimeouts -GetCommandLineA -GetCommandLineW -GetCompressedFileSizeA -GetCompressedFileSizeW -GetComputerNameA -GetComputerNameW -GetConsoleCP -GetConsoleCursorInfo -GetConsoleMode -GetConsoleOutputCP -GetConsoleScreenBufferInfo -GetConsoleTitleA -GetConsoleTitleW -GetCurrencyFormatA -GetCurrencyFormatW -GetCurrentDirectoryA -GetCurrentDirectoryW -GetCurrentProcess -GetCurrentProcessId -GetCurrentThread -GetCurrentThreadId -GetDateFormatA -GetDateFormatW -GetDaylightFlag -GetDefaultCommConfigA -GetDefaultCommConfigW -GetDevicePowerState -GetDiskFreeSpaceA -GetDiskFreeSpaceExA -GetDiskFreeSpaceExW -GetDiskFreeSpaceW -GetDriveTypeA -GetDriveTypeW -GetEnvironmentStrings -GetEnvironmentStringsA -GetEnvironmentStringsW -GetEnvironmentVariableA -GetEnvironmentVariableW -GetErrorMode -GetExitCodeProcess -GetExitCodeThread -GetFileAttributesA -GetFileAttributesExA -GetFileAttributesExW -GetFileAttributesW -GetFileInformationByHandle -GetFileSize -GetFileTime -GetFileType -GetFullPathNameA -GetFullPathNameW -GetGeoInfoA -GetGeoInfoW -GetHandleContext -GetHandleInformation -GetLSCallbackTarget -GetLSCallbackTemplate -GetLargestConsoleWindowSize -GetLastError -GetLocalTime -GetLocaleInfoA -GetLocaleInfoW -GetLogicalDriveStringsA -GetLogicalDriveStringsW -GetLogicalDrives -GetLongPathNameA -GetLongPathNameW -GetMailslotInfo -GetModuleFileNameA -GetModuleFileNameW -GetModuleHandleA -GetModuleHandleW -GetModuleHandleExA -GetModuleHandleExW -GetNamedPipeHandleStateA -GetNamedPipeHandleStateW -GetNamedPipeInfo -GetNumberFormatA -GetNumberFormatW -GetNumberOfConsoleInputEvents -GetNumberOfConsoleMouseButtons -GetOEMCP -GetOverlappedResult -GetPriorityClass -GetPrivateProfileIntA -GetPrivateProfileIntW -GetPrivateProfileSectionA -GetPrivateProfileSectionNamesA -GetPrivateProfileSectionNamesW -GetPrivateProfileSectionW -GetPrivateProfileStringA -GetPrivateProfileStringW -GetPrivateProfileStructA -GetPrivateProfileStructW -GetProcAddress -GetProcessAffinityMask -GetProcessFlags -GetProcessHeap -GetProcessHeaps -GetProcessPriorityBoost -GetProcessShutdownParameters -GetProcessTimes -GetProcessVersion -GetProcessWorkingSetSize -GetProductName -GetProfileIntA -GetProfileIntW -GetProfileSectionA -GetProfileSectionW -GetProfileStringA -GetProfileStringW -GetQueuedCompletionStatus -GetSLCallbackTarget -GetSLCallbackTemplate -GetShortPathNameA -GetShortPathNameW -GetStartupInfoA -GetStartupInfoW -GetStdHandle -GetStringTypeA -GetStringTypeExA -GetStringTypeExW -GetStringTypeW -GetSystemDefaultLCID -GetSystemDefaultLangID -GetSystemDefaultUILanguage -GetSystemDirectoryA -GetSystemDirectoryW -GetSystemInfo -GetSystemPowerStatus -GetSystemTime -GetSystemTimeAdjustment -GetSystemTimeAsFileTime -GetTapeParameters -GetTapePosition -GetTapeStatus -GetTempFileNameA -GetTempFileNameW -GetTempPathA -GetTempPathW -GetThreadContext -GetThreadLocale -GetThreadPriority -GetThreadPriorityBoost -GetThreadSelectorEntry -GetThreadTimes -GetTickCount -GetTimeFormatA -GetTimeFormatW -GetTimeZoneInformation -GetUserDefaultLCID -GetUserDefaultLangID -GetUserDefaultUILanguage -GetUserGeoID -GetVersion -GetVersionExA -GetVersionExW -GetVolumeInformationA -GetVolumeInformationW -GetWindowsDirectoryA -GetWindowsDirectoryW -GetWriteWatch -GlobalAddAtomA -GlobalAddAtomW -GlobalAlloc -GlobalCompact -GlobalDeleteAtom -GlobalFindAtomA -GlobalFindAtomW -GlobalFix -GlobalFlags -GlobalFree -GlobalGetAtomNameA -GlobalGetAtomNameW -GlobalHandle -GlobalLock -GlobalMemoryStatus -GlobalReAlloc -GlobalSize -GlobalUnWire -GlobalUnfix -GlobalUnlock -GlobalWire -Heap32First -Heap32ListFirst -Heap32ListNext -Heap32Next -HeapAlloc -HeapCompact -HeapCreate -HeapDestroy -HeapFree -HeapLock -HeapReAlloc -HeapSetFlags -HeapSize -HeapUnlock -HeapValidate -HeapWalk -InitAtomTable -InitializeCriticalSection -InitializeCriticalSectionAndSpinCount -InterlockedCompareExchange -InterlockedDecrement -InterlockedExchange -InterlockedExchangeAdd -InterlockedIncrement -InvalidateNLSCache -IsBadCodePtr -IsBadHugeReadPtr -IsBadHugeWritePtr -IsBadReadPtr -IsBadStringPtrA -IsBadStringPtrW -IsBadWritePtr -IsDBCSLeadByte -IsDBCSLeadByteEx -IsDebuggerPresent -IsLSCallback -IsProcessorFeaturePresent -IsSLCallback -IsSystemResumeAutomatic -IsValidCodePage -IsValidLanguageGroup -IsValidLocale -K32Thk1632Epilog -K32Thk1632Prolog -K32_NtCreateFile -K32_RtlNtStatusToDosError -LCMapStringA -LCMapStringW -LeaveCriticalSection -LoadLibraryA -LoadLibraryExA -LoadLibraryExW -LoadLibraryW -LoadModule -LoadResource -LocalAlloc -LocalCompact -LocalFileTimeToFileTime -LocalFlags -LocalFree -LocalHandle -LocalLock -LocalReAlloc -LocalShrink -LocalSize -LocalUnlock -LockFile -LockFileEx -LockResource -MakeCriticalSectionGlobal -MapHInstLS -MapHInstLS_PN -MapHInstSL -MapHInstSL_PN -MapHModuleLS -MapHModuleSL -MapLS -MapSL -MapSLFix -MapViewOfFile -MapViewOfFileEx -Module32First -Module32Next -MoveFileA -MoveFileExA -MoveFileExW -MoveFileW -MulDiv -MultiByteToWideChar -NotifyNLSUserCache -OpenEventA -OpenEventW -OpenFile -OpenFileMappingA -OpenFileMappingW -OpenMutexA -OpenMutexW -OpenProcess -OpenProfileUserMapping -OpenSemaphoreA -OpenSemaphoreW -OpenThread -OpenVxDHandle -OpenWaitableTimerA -OpenWaitableTimerW -OutputDebugStringA -OutputDebugStringW -PeekConsoleInputA -PeekConsoleInputW -PeekNamedPipe -PostQueuedCompletionStatus -PrepareTape -Process32First -Process32Next -PulseEvent -PurgeComm -QT_Thunk -QueryDosDeviceA -QueryDosDeviceW -QueryNumberOfEventLogRecords -QueryOldestEventLogRecord -QueryPerformanceCounter -QueryPerformanceFrequency -QueueUserAPC -RaiseException -ReadConsoleA -ReadConsoleInputA -ReadConsoleInputW -ReadConsoleOutputA -ReadConsoleOutputAttribute -ReadConsoleOutputCharacterA -ReadConsoleOutputCharacterW -ReadConsoleOutputW -ReadConsoleW -ReadDirectoryChangesW -ReadFile -ReadFileEx -ReadFileScatter -ReadProcessMemory -RegisterServiceProcess -RegisterSysMsgHandler -ReinitializeCriticalSection -ReleaseMutex -ReleaseSemaphore -RemoveDirectoryA -RemoveDirectoryW -RequestDeviceWakeup -RequestWakeupLatency -ResetEvent -ResetNLSUserInfoCache -ResetWriteWatch -ResumeThread -RtlAddFunctionTable -RtlDeleteFunctionTable -RtlFillMemory -RtlInstallFunctionTableCallback -RtlMoveMemory -RtlUnwind -RtlUnwindEx -RtlZeroMemory -SMapLS -SMapLS_IP_EBP_12 -SMapLS_IP_EBP_16 -SMapLS_IP_EBP_20 -SMapLS_IP_EBP_24 -SMapLS_IP_EBP_28 -SMapLS_IP_EBP_32 -SMapLS_IP_EBP_36 -SMapLS_IP_EBP_40 -SMapLS_IP_EBP_8 -SUnMapLS -SUnMapLS_IP_EBP_12 -SUnMapLS_IP_EBP_16 -SUnMapLS_IP_EBP_20 -SUnMapLS_IP_EBP_24 -SUnMapLS_IP_EBP_28 -SUnMapLS_IP_EBP_32 -SUnMapLS_IP_EBP_36 -SUnMapLS_IP_EBP_40 -SUnMapLS_IP_EBP_8 -ScrollConsoleScreenBufferA -ScrollConsoleScreenBufferW -SearchPathA -SearchPathW -SetCalendarInfoA -SetCalendarInfoW -SetCommBreak -SetCommConfig -SetCommMask -SetCommState -SetCommTimeouts -SetComputerNameA -SetComputerNameW -SetConsoleActiveScreenBuffer -SetConsoleCP -SetConsoleCtrlHandler -SetConsoleCursorInfo -SetConsoleCursorPosition -SetConsoleMode -SetConsoleOutputCP -SetConsoleScreenBufferSize -SetConsoleTextAttribute -SetConsoleTitleA -SetConsoleTitleW -SetConsoleWindowInfo -SetCriticalSectionSpinCount -SetCurrentDirectoryA -SetCurrentDirectoryW -SetDaylightFlag -SetDefaultCommConfigA -SetDefaultCommConfigW -SetEndOfFile -SetEnvironmentVariableA -SetEnvironmentVariableW -SetErrorMode -SetEvent -SetFileApisToANSI -SetFileApisToOEM -SetFileAttributesA -SetFileAttributesW -SetFilePointer -SetFilePointerEx -SetFileTime -SetHandleContext -SetHandleCount -SetHandleInformation -SetLastError -SetLocalTime -SetLocaleInfoA -SetLocaleInfoW -SetMailslotInfo -SetMessageWaitingIndicator -SetNamedPipeHandleState -SetPriorityClass -SetProcessAffinityMask -SetProcessPriorityBoost -SetProcessShutdownParameters -SetProcessWorkingSetSize -SetStdHandle -SetSystemPowerState -SetSystemTime -SetSystemTimeAdjustment -SetTapeParameters -SetTapePosition -SetThreadAffinityMask -SetThreadContext -SetThreadExecutionState -SetThreadIdealProcessor -SetThreadLocale -SetThreadPriority -SetThreadPriorityBoost -SetTimeZoneInformation -SetUnhandledExceptionFilter -SetUserGeoID -SetVolumeLabelA -SetVolumeLabelW -SetWaitableTimer -SetupComm -SignalObjectAndWait -SignalSysMsgHandlers -SizeofResource -Sleep -SleepEx -SuspendThread -SwitchToFiber -SwitchToThread -SystemTimeToFileTime -SystemTimeToTzSpecificLocalTime -TerminateProcess -TerminateThread -Thread32First -Thread32Next -ThunkConnect32 -TlsAlloc -TlsAllocInternal -TlsFree -TlsFreeInternal -TlsGetValue -TlsSetValue -Toolhelp32ReadProcessMemory -TransactNamedPipe -TransmitCommChar -TryEnterCriticalSection -UTRegister -UTUnRegister -UnMapLS -UnMapSLFixArray -UnhandledExceptionFilter -UninitializeCriticalSection -UnlockFile -UnlockFileEx -UnmapViewOfFile -UpdateResourceA -UpdateResourceW -VerLanguageNameA -VerLanguageNameW -VirtualAlloc -VirtualAllocEx -VirtualFree -VirtualFreeEx -VirtualLock -VirtualProtect -VirtualProtectEx -VirtualQuery -VirtualQueryEx -VirtualUnlock -WaitCommEvent -WaitForDebugEvent -WaitForMultipleObjects -WaitForMultipleObjectsEx -WaitForSingleObject -WaitForSingleObjectEx -WaitNamedPipeA -WaitNamedPipeW -WideCharToMultiByte -WinExec -WriteConsoleA -WriteConsoleInputA -WriteConsoleInputW -WriteConsoleOutputA -WriteConsoleOutputAttribute -WriteConsoleOutputCharacterA -WriteConsoleOutputCharacterW -WriteConsoleOutputW -WriteConsoleW -WriteFile -WriteFileEx -WriteFileGather -WritePrivateProfileSectionA -WritePrivateProfileSectionW -WritePrivateProfileStringA -WritePrivateProfileStringW -WritePrivateProfileStructA -WritePrivateProfileStructW -WriteProcessMemory -WriteProfileSectionA -WriteProfileSectionW -WriteProfileStringA -WriteProfileStringW -WriteTapemark -_DebugOut -_DebugPrintf -_hread -_hwrite -_lclose -_lcreat -_llseek -_lopen -_lread -_lwrite -dprintf -lstrcat -lstrcatA -lstrcatW -lstrcmp -lstrcmpA -lstrcmpW -lstrcmpi -lstrcmpiA -lstrcmpiW -lstrcpy -lstrcpyA -lstrcpyW -lstrcpyn -lstrcpynA -lstrcpynW -lstrlen -lstrlenA -lstrlenW +LIBRARY kernel32.dll + +EXPORTS +AddAtomA +AddAtomW +AllocConsole +AllocLSCallback +AllocSLCallback +AreFileApisANSI +BackupRead +BackupSeek +BackupWrite +Beep +BeginUpdateResourceA +BeginUpdateResourceW +BuildCommDCBA +BuildCommDCBAndTimeoutsA +BuildCommDCBAndTimeoutsW +BuildCommDCBW +CallNamedPipeA +CallNamedPipeW +Callback12 +Callback16 +Callback20 +Callback24 +Callback28 +Callback32 +Callback36 +Callback4 +Callback40 +Callback44 +Callback48 +Callback52 +Callback56 +Callback60 +Callback64 +Callback8 +CancelDeviceWakeupRequest +CancelIo +CancelWaitableTimer +ClearCommBreak +ClearCommError +CloseHandle +CloseProfileUserMapping +CloseSystemHandle +CommConfigDialogA +CommConfigDialogW +CompareFileTime +CompareStringA +CompareStringW +ConnectNamedPipe +ContinueDebugEvent +ConvertDefaultLocale +ConvertThreadToFiber +ConvertToGlobalHandle +CopyFileA +CopyFileExA +CopyFileExW +CopyFileW +CreateConsoleScreenBuffer +CreateDirectoryA +CreateDirectoryExA +CreateDirectoryExW +CreateDirectoryW +CreateEventA +CreateEventW +CreateFiber +CreateFileA +CreateFileMappingA +CreateFileMappingW +CreateFileW +CreateIoCompletionPort +CreateKernelThread +CreateMailslotA +CreateMailslotW +CreateMutexA +CreateMutexW +CreateNamedPipeA +CreateNamedPipeW +CreatePipe +CreateProcessA +CreateProcessW +CreateRemoteThread +CreateSemaphoreA +CreateSemaphoreW +CreateSocketHandle +CreateTapePartition +CreateThread +CreateToolhelp32Snapshot +CreateWaitableTimerA +CreateWaitableTimerW +DebugActiveProcess +DebugBreak +DefineDosDeviceA +DefineDosDeviceW +DeleteAtom +DeleteCriticalSection +DeleteFiber +DeleteFileA +DeleteFileW +DeviceIoControl +DisableThreadLibraryCalls +DisconnectNamedPipe +DosDateTimeToFileTime +DuplicateHandle +EndUpdateResourceA +EndUpdateResourceW +EnterCriticalSection +EnumCalendarInfoA +EnumCalendarInfoExA +EnumCalendarInfoExW +EnumCalendarInfoW +EnumDateFormatsA +EnumDateFormatsExA +EnumDateFormatsExW +EnumDateFormatsW +EnumLanguageGroupLocalesA +EnumLanguageGroupLocalesW +EnumResourceLanguagesA +EnumResourceLanguagesW +EnumResourceNamesA +EnumResourceNamesW +EnumResourceTypesA +EnumResourceTypesW +EnumSystemCodePagesA +EnumSystemCodePagesW +EnumSystemGeoID +EnumSystemLanguageGroupsA +EnumSystemLanguageGroupsW +EnumSystemLocalesA +EnumSystemLocalesW +EnumTimeFormatsA +EnumTimeFormatsW +EnumUILanguagesA +EnumUILanguagesW +EraseTape +EscapeCommFunction +ExitProcess +ExitThread +ExpandEnvironmentStringsA +ExpandEnvironmentStringsW +FT_Exit0 +FT_Exit12 +FT_Exit16 +FT_Exit20 +FT_Exit24 +FT_Exit28 +FT_Exit32 +FT_Exit36 +FT_Exit4 +FT_Exit40 +FT_Exit44 +FT_Exit48 +FT_Exit52 +FT_Exit56 +FT_Exit8 +FT_Prolog +FT_Thunk +FatalAppExitA +FatalAppExitW +FatalExit +FileTimeToDosDateTime +FileTimeToLocalFileTime +FileTimeToSystemTime +FillConsoleOutputAttribute +FillConsoleOutputCharacterA +FillConsoleOutputCharacterW +FindAtomA +FindAtomW +FindClose +FindCloseChangeNotification +FindFirstChangeNotificationA +FindFirstChangeNotificationW +FindFirstFileA +FindFirstFileExA +FindFirstFileExW +FindFirstFileW +FindNextChangeNotification +FindNextFileA +FindNextFileW +FindResourceA +FindResourceExA +FindResourceExW +FindResourceW +FlushConsoleInputBuffer +FlushFileBuffers +FlushInstructionCache +FlushViewOfFile +FoldStringA +FoldStringW +FormatMessageA +FormatMessageW +FreeConsole +FreeEnvironmentStringsA +FreeEnvironmentStringsW +FreeLSCallback +FreeLibrary +FreeLibraryAndExitThread +FreeResource +FreeSLCallback +GenerateConsoleCtrlEvent +GetACP +GetAtomNameA +GetAtomNameW +GetBinaryType +GetBinaryTypeA +GetBinaryTypeW +GetCPInfo +GetCPInfoExA +GetCPInfoExW +GetCalendarInfoA +GetCalendarInfoW +GetCommConfig +GetCommMask +GetCommModemStatus +GetCommProperties +GetCommState +GetCommTimeouts +GetCommandLineA +GetCommandLineW +GetCompressedFileSizeA +GetCompressedFileSizeW +GetComputerNameA +GetComputerNameW +GetConsoleCP +GetConsoleCursorInfo +GetConsoleMode +GetConsoleOutputCP +GetConsoleScreenBufferInfo +GetConsoleTitleA +GetConsoleTitleW +GetCurrencyFormatA +GetCurrencyFormatW +GetCurrentDirectoryA +GetCurrentDirectoryW +GetCurrentProcess +GetCurrentProcessId +GetCurrentThread +GetCurrentThreadId +GetDateFormatA +GetDateFormatW +GetDaylightFlag +GetDefaultCommConfigA +GetDefaultCommConfigW +GetDevicePowerState +GetDiskFreeSpaceA +GetDiskFreeSpaceExA +GetDiskFreeSpaceExW +GetDiskFreeSpaceW +GetDriveTypeA +GetDriveTypeW +GetEnvironmentStrings +GetEnvironmentStringsA +GetEnvironmentStringsW +GetEnvironmentVariableA +GetEnvironmentVariableW +GetErrorMode +GetExitCodeProcess +GetExitCodeThread +GetFileAttributesA +GetFileAttributesExA +GetFileAttributesExW +GetFileAttributesW +GetFileInformationByHandle +GetFileSize +GetFileTime +GetFileType +GetFullPathNameA +GetFullPathNameW +GetGeoInfoA +GetGeoInfoW +GetHandleContext +GetHandleInformation +GetLSCallbackTarget +GetLSCallbackTemplate +GetLargestConsoleWindowSize +GetLastError +GetLocalTime +GetLocaleInfoA +GetLocaleInfoW +GetLogicalDriveStringsA +GetLogicalDriveStringsW +GetLogicalDrives +GetLongPathNameA +GetLongPathNameW +GetMailslotInfo +GetModuleFileNameA +GetModuleFileNameW +GetModuleHandleA +GetModuleHandleW +GetModuleHandleExA +GetModuleHandleExW +GetNamedPipeHandleStateA +GetNamedPipeHandleStateW +GetNamedPipeInfo +GetNumberFormatA +GetNumberFormatW +GetNumberOfConsoleInputEvents +GetNumberOfConsoleMouseButtons +GetOEMCP +GetOverlappedResult +GetPriorityClass +GetPrivateProfileIntA +GetPrivateProfileIntW +GetPrivateProfileSectionA +GetPrivateProfileSectionNamesA +GetPrivateProfileSectionNamesW +GetPrivateProfileSectionW +GetPrivateProfileStringA +GetPrivateProfileStringW +GetPrivateProfileStructA +GetPrivateProfileStructW +GetProcAddress +GetProcessAffinityMask +GetProcessFlags +GetProcessHeap +GetProcessHeaps +GetProcessPriorityBoost +GetProcessShutdownParameters +GetProcessTimes +GetProcessVersion +GetProcessWorkingSetSize +GetProductName +GetProfileIntA +GetProfileIntW +GetProfileSectionA +GetProfileSectionW +GetProfileStringA +GetProfileStringW +GetQueuedCompletionStatus +GetSLCallbackTarget +GetSLCallbackTemplate +GetShortPathNameA +GetShortPathNameW +GetStartupInfoA +GetStartupInfoW +GetStdHandle +GetStringTypeA +GetStringTypeExA +GetStringTypeExW +GetStringTypeW +GetSystemDefaultLCID +GetSystemDefaultLangID +GetSystemDefaultUILanguage +GetSystemDirectoryA +GetSystemDirectoryW +GetSystemInfo +GetSystemPowerStatus +GetSystemTime +GetSystemTimeAdjustment +GetSystemTimeAsFileTime +GetTapeParameters +GetTapePosition +GetTapeStatus +GetTempFileNameA +GetTempFileNameW +GetTempPathA +GetTempPathW +GetThreadContext +GetThreadLocale +GetThreadPriority +GetThreadPriorityBoost +GetThreadSelectorEntry +GetThreadTimes +GetTickCount +GetTimeFormatA +GetTimeFormatW +GetTimeZoneInformation +GetUserDefaultLCID +GetUserDefaultLangID +GetUserDefaultUILanguage +GetUserGeoID +GetVersion +GetVersionExA +GetVersionExW +GetVolumeInformationA +GetVolumeInformationW +GetWindowsDirectoryA +GetWindowsDirectoryW +GetWriteWatch +GlobalAddAtomA +GlobalAddAtomW +GlobalAlloc +GlobalCompact +GlobalDeleteAtom +GlobalFindAtomA +GlobalFindAtomW +GlobalFix +GlobalFlags +GlobalFree +GlobalGetAtomNameA +GlobalGetAtomNameW +GlobalHandle +GlobalLock +GlobalMemoryStatus +GlobalReAlloc +GlobalSize +GlobalUnWire +GlobalUnfix +GlobalUnlock +GlobalWire +Heap32First +Heap32ListFirst +Heap32ListNext +Heap32Next +HeapAlloc +HeapCompact +HeapCreate +HeapDestroy +HeapFree +HeapLock +HeapReAlloc +HeapSetFlags +HeapSize +HeapUnlock +HeapValidate +HeapWalk +InitAtomTable +InitializeCriticalSection +InitializeCriticalSectionAndSpinCount +InterlockedCompareExchange +InterlockedDecrement +InterlockedExchange +InterlockedExchangeAdd +InterlockedIncrement +InvalidateNLSCache +IsBadCodePtr +IsBadHugeReadPtr +IsBadHugeWritePtr +IsBadReadPtr +IsBadStringPtrA +IsBadStringPtrW +IsBadWritePtr +IsDBCSLeadByte +IsDBCSLeadByteEx +IsDebuggerPresent +IsLSCallback +IsProcessorFeaturePresent +IsSLCallback +IsSystemResumeAutomatic +IsValidCodePage +IsValidLanguageGroup +IsValidLocale +K32Thk1632Epilog +K32Thk1632Prolog +K32_NtCreateFile +K32_RtlNtStatusToDosError +LCMapStringA +LCMapStringW +LeaveCriticalSection +LoadLibraryA +LoadLibraryExA +LoadLibraryExW +LoadLibraryW +LoadModule +LoadResource +LocalAlloc +LocalCompact +LocalFileTimeToFileTime +LocalFlags +LocalFree +LocalHandle +LocalLock +LocalReAlloc +LocalShrink +LocalSize +LocalUnlock +LockFile +LockFileEx +LockResource +MakeCriticalSectionGlobal +MapHInstLS +MapHInstLS_PN +MapHInstSL +MapHInstSL_PN +MapHModuleLS +MapHModuleSL +MapLS +MapSL +MapSLFix +MapViewOfFile +MapViewOfFileEx +Module32First +Module32Next +MoveFileA +MoveFileExA +MoveFileExW +MoveFileW +MulDiv +MultiByteToWideChar +NotifyNLSUserCache +OpenEventA +OpenEventW +OpenFile +OpenFileMappingA +OpenFileMappingW +OpenMutexA +OpenMutexW +OpenProcess +OpenProfileUserMapping +OpenSemaphoreA +OpenSemaphoreW +OpenThread +OpenVxDHandle +OpenWaitableTimerA +OpenWaitableTimerW +OutputDebugStringA +OutputDebugStringW +PeekConsoleInputA +PeekConsoleInputW +PeekNamedPipe +PostQueuedCompletionStatus +PrepareTape +Process32First +Process32Next +PulseEvent +PurgeComm +QT_Thunk +QueryDosDeviceA +QueryDosDeviceW +QueryNumberOfEventLogRecords +QueryOldestEventLogRecord +QueryPerformanceCounter +QueryPerformanceFrequency +QueueUserAPC +RaiseException +ReadConsoleA +ReadConsoleInputA +ReadConsoleInputW +ReadConsoleOutputA +ReadConsoleOutputAttribute +ReadConsoleOutputCharacterA +ReadConsoleOutputCharacterW +ReadConsoleOutputW +ReadConsoleW +ReadDirectoryChangesW +ReadFile +ReadFileEx +ReadFileScatter +ReadProcessMemory +RegisterServiceProcess +RegisterSysMsgHandler +ReinitializeCriticalSection +ReleaseMutex +ReleaseSemaphore +RemoveDirectoryA +RemoveDirectoryW +RequestDeviceWakeup +RequestWakeupLatency +ResetEvent +ResetNLSUserInfoCache +ResetWriteWatch +ResumeThread +RtlAddFunctionTable +RtlDeleteFunctionTable +RtlFillMemory +RtlInstallFunctionTableCallback +RtlMoveMemory +RtlUnwind +RtlUnwindEx +RtlZeroMemory +SMapLS +SMapLS_IP_EBP_12 +SMapLS_IP_EBP_16 +SMapLS_IP_EBP_20 +SMapLS_IP_EBP_24 +SMapLS_IP_EBP_28 +SMapLS_IP_EBP_32 +SMapLS_IP_EBP_36 +SMapLS_IP_EBP_40 +SMapLS_IP_EBP_8 +SUnMapLS +SUnMapLS_IP_EBP_12 +SUnMapLS_IP_EBP_16 +SUnMapLS_IP_EBP_20 +SUnMapLS_IP_EBP_24 +SUnMapLS_IP_EBP_28 +SUnMapLS_IP_EBP_32 +SUnMapLS_IP_EBP_36 +SUnMapLS_IP_EBP_40 +SUnMapLS_IP_EBP_8 +ScrollConsoleScreenBufferA +ScrollConsoleScreenBufferW +SearchPathA +SearchPathW +SetCalendarInfoA +SetCalendarInfoW +SetCommBreak +SetCommConfig +SetCommMask +SetCommState +SetCommTimeouts +SetComputerNameA +SetComputerNameW +SetConsoleActiveScreenBuffer +SetConsoleCP +SetConsoleCtrlHandler +SetConsoleCursorInfo +SetConsoleCursorPosition +SetConsoleMode +SetConsoleOutputCP +SetConsoleScreenBufferSize +SetConsoleTextAttribute +SetConsoleTitleA +SetConsoleTitleW +SetConsoleWindowInfo +SetCriticalSectionSpinCount +SetCurrentDirectoryA +SetCurrentDirectoryW +SetDaylightFlag +SetDefaultCommConfigA +SetDefaultCommConfigW +SetEndOfFile +SetEnvironmentVariableA +SetEnvironmentVariableW +SetErrorMode +SetEvent +SetFileApisToANSI +SetFileApisToOEM +SetFileAttributesA +SetFileAttributesW +SetFilePointer +SetFilePointerEx +SetFileTime +SetHandleContext +SetHandleCount +SetHandleInformation +SetLastError +SetLocalTime +SetLocaleInfoA +SetLocaleInfoW +SetMailslotInfo +SetMessageWaitingIndicator +SetNamedPipeHandleState +SetPriorityClass +SetProcessAffinityMask +SetProcessPriorityBoost +SetProcessShutdownParameters +SetProcessWorkingSetSize +SetStdHandle +SetSystemPowerState +SetSystemTime +SetSystemTimeAdjustment +SetTapeParameters +SetTapePosition +SetThreadAffinityMask +SetThreadContext +SetThreadExecutionState +SetThreadIdealProcessor +SetThreadLocale +SetThreadPriority +SetThreadPriorityBoost +SetTimeZoneInformation +SetUnhandledExceptionFilter +SetUserGeoID +SetVolumeLabelA +SetVolumeLabelW +SetWaitableTimer +SetupComm +SignalObjectAndWait +SignalSysMsgHandlers +SizeofResource +Sleep +SleepEx +SuspendThread +SwitchToFiber +SwitchToThread +SystemTimeToFileTime +SystemTimeToTzSpecificLocalTime +TerminateProcess +TerminateThread +Thread32First +Thread32Next +ThunkConnect32 +TlsAlloc +TlsAllocInternal +TlsFree +TlsFreeInternal +TlsGetValue +TlsSetValue +Toolhelp32ReadProcessMemory +TransactNamedPipe +TransmitCommChar +TryEnterCriticalSection +UTRegister +UTUnRegister +UnMapLS +UnMapSLFixArray +UnhandledExceptionFilter +UninitializeCriticalSection +UnlockFile +UnlockFileEx +UnmapViewOfFile +UpdateResourceA +UpdateResourceW +VerLanguageNameA +VerLanguageNameW +VirtualAlloc +VirtualAllocEx +VirtualFree +VirtualFreeEx +VirtualLock +VirtualProtect +VirtualProtectEx +VirtualQuery +VirtualQueryEx +VirtualUnlock +WaitCommEvent +WaitForDebugEvent +WaitForMultipleObjects +WaitForMultipleObjectsEx +WaitForSingleObject +WaitForSingleObjectEx +WaitNamedPipeA +WaitNamedPipeW +WideCharToMultiByte +WinExec +WriteConsoleA +WriteConsoleInputA +WriteConsoleInputW +WriteConsoleOutputA +WriteConsoleOutputAttribute +WriteConsoleOutputCharacterA +WriteConsoleOutputCharacterW +WriteConsoleOutputW +WriteConsoleW +WriteFile +WriteFileEx +WriteFileGather +WritePrivateProfileSectionA +WritePrivateProfileSectionW +WritePrivateProfileStringA +WritePrivateProfileStringW +WritePrivateProfileStructA +WritePrivateProfileStructW +WriteProcessMemory +WriteProfileSectionA +WriteProfileSectionW +WriteProfileStringA +WriteProfileStringW +WriteTapemark +_DebugOut +_DebugPrintf +_hread +_hwrite +_lclose +_lcreat +_llseek +_lopen +_lread +_lwrite +dprintf +lstrcat +lstrcatA +lstrcatW +lstrcmp +lstrcmpA +lstrcmpW +lstrcmpi +lstrcmpiA +lstrcmpiW +lstrcpy +lstrcpyA +lstrcpyW +lstrcpyn +lstrcpynA +lstrcpynW +lstrlen +lstrlenA +lstrlenW diff --git a/tcc/lib/msvcrt.def b/tcc/lib/msvcrt.def index e8f6ab91..4321b5d6 100644 --- a/tcc/lib/msvcrt.def +++ b/tcc/lib/msvcrt.def @@ -1,1320 +1,1320 @@ -LIBRARY msvcrt.dll - -EXPORTS -??0__non_rtti_object@@QEAA@AEBV0@@Z -??0__non_rtti_object@@QEAA@PEBD@Z -??0bad_cast@@AAE@PBQBD@Z -??0bad_cast@@AEAA@PEBQEBD@Z -??0bad_cast@@QAE@ABQBD@Z -??0bad_cast@@QEAA@AEBQEBD@Z -??0bad_cast@@QEAA@AEBV0@@Z -??0bad_cast@@QEAA@PEBD@Z -??0bad_typeid@@QEAA@AEBV0@@Z -??0bad_typeid@@QEAA@PEBD@Z -??0exception@@QEAA@AEBQEBD@Z -??0exception@@QEAA@AEBQEBDH@Z -??0exception@@QEAA@AEBV0@@Z -??0exception@@QEAA@XZ -??1__non_rtti_object@@UEAA@XZ -??1bad_cast@@UEAA@XZ -??1bad_typeid@@UEAA@XZ -??1exception@@UEAA@XZ -??1type_info@@UEAA@XZ -??2@YAPEAX_K@Z -??2@YAPEAX_KHPEBDH@Z -??3@YAXPEAX@Z -??4__non_rtti_object@@QEAAAEAV0@AEBV0@@Z -??4bad_cast@@QEAAAEAV0@AEBV0@@Z -??4bad_typeid@@QEAAAEAV0@AEBV0@@Z -??4exception@@QEAAAEAV0@AEBV0@@Z -??8type_info@@QEBAHAEBV0@@Z -??9type_info@@QEBAHAEBV0@@Z -??_7__non_rtti_object@@6B@ -??_7bad_cast@@6B@ -??_7bad_typeid@@6B@ -??_7exception@@6B@ -??_Fbad_cast@@QEAAXXZ -??_Fbad_typeid@@QEAAXXZ -??_U@YAPEAX_K@Z -??_U@YAPEAX_KHPEBDH@Z -??_V@YAXPEAX@Z -?_query_new_handler@@YAP6AH_K@ZXZ -?_query_new_mode@@YAHXZ -?_set_new_handler@@YAP6AH_K@ZP6AH0@Z@Z -?_set_new_mode@@YAHH@Z -?_set_se_translator@@YAP6AXIPEAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z -?before@type_info@@QEBAHAEBV1@@Z -?name@type_info@@QEBAPEBDXZ -?raw_name@type_info@@QEBAPEBDXZ -?set_new_handler@@YAP6AXXZP6AXXZ@Z -?set_terminate@@YAP6AXXZP6AXXZ@Z -?set_unexpected@@YAP6AXXZP6AXXZ@Z -?terminate@@YAXXZ -?unexpected@@YAXXZ -?what@exception@@UEBAPEBDXZ -_CrtCheckMemory -_CrtDbgBreak -_CrtDbgReport -_CrtDbgReportV -_CrtDbgReportW -_CrtDbgReportWV -_CrtDoForAllClientObjects -_CrtDumpMemoryLeaks -_CrtIsMemoryBlock -_CrtIsValidHeapPointer -_CrtIsValidPointer -_CrtMemCheckpoint -_CrtMemDifference -_CrtMemDumpAllObjectsSince -_CrtMemDumpStatistics -_CrtReportBlockType -_CrtSetAllocHook -_CrtSetBreakAlloc -_CrtSetDbgBlockType -_CrtSetDbgFlag -_CrtSetDumpClient -_CrtSetReportFile -_CrtSetReportHook -_CrtSetReportHook2 -_CrtSetReportMode -_CxxThrowException -_Getdays -_Getmonths -_Gettnames -_HUGE -_Strftime -_W_Getdays -_W_Getmonths -_W_Gettnames -_Wcsftime -_XcptFilter -__AdjustPointer -__C_specific_handler -__CppXcptFilter -__CxxFrameHandler -__CxxFrameHandler2 -__CxxFrameHandler3 -__DestructExceptionObject -__ExceptionPtrAssign -__ExceptionPtrCompare -__ExceptionPtrCopy -__ExceptionPtrCopyException -__ExceptionPtrCreate -__ExceptionPtrCurrentException -__ExceptionPtrDestroy -__ExceptionPtrRethrow -__ExceptionPtrSwap -__ExceptionPtrToBool -__RTCastToVoid -__RTDynamicCast -__RTtypeid -__STRINGTOLD -___lc_codepage_func -___lc_collate_cp_func -___lc_handle_func -___mb_cur_max_func -___setlc_active_func -___unguarded_readlc_active_add_func -__argc -__argv -__badioinfo -__crtCompareStringA -__crtCompareStringW -__crtGetLocaleInfoW -__crtGetStringTypeW -__crtLCMapStringA -__crtLCMapStringW -__daylight -__dllonexit -__doserrno -__dstbias -__fpecode -__getmainargs -__initenv -__iob_func -__isascii -__iscsym -__iscsymf -__lc_codepage -__lc_collate_cp -__lc_handle -__lconv_init -__mb_cur_max -__pctype_func -__pioinfo -__pwctype_func -__pxcptinfoptrs -__set_app_type -__setlc_active -__setusermatherr -__strncnt -__threadhandle -__threadid -__toascii -__unDName -__unDNameEx -__uncaught_exception -__unguarded_readlc_active -__wargv -__wcserror -__wcserror_s -__wcsncnt -__wgetmainargs -__winitenv -_abs64 -_access -_access_s -_acmdln -_aexit_rtn -_aligned_free -_aligned_free_dbg -_aligned_malloc -_aligned_malloc_dbg -_aligned_offset_malloc -_aligned_offset_malloc_dbg -_aligned_offset_realloc -_aligned_offset_realloc_dbg -_aligned_realloc -_aligned_realloc_dbg -_amsg_exit -_assert -_atodbl -_atodbl_l -_atof_l -_atoflt_l -_atoi64 -_atoi64_l -_atoi_l -_atol_l -_atoldbl -_atoldbl_l -_beep -_beginthread -_beginthreadex -_c_exit -_cabs -_callnewh -_calloc_dbg -_cexit -_cgets -_cgets_s -_cgetws -_cgetws_s -_chdir -_chdrive -_chgsign -_chgsignf -_chmod -_chsize -_chsize_s -_chvalidator -_chvalidator_l -_clearfp -_close -_commit -_commode -_control87 -_controlfp -_controlfp_s -_copysign -_copysignf -_cprintf -_cprintf_l -_cprintf_p -_cprintf_p_l -_cprintf_s -_cprintf_s_l -_cputs -_cputws -_creat -_create_locale -_crtAssertBusy -_crtBreakAlloc -_crtDbgFlag -_cscanf -_cscanf_l -_cscanf_s -_cscanf_s_l -_ctime32 -_ctime32_s -_ctime64 -_ctime64_s -_ctype -_cwait -_cwprintf -_cwprintf_l -_cwprintf_p -_cwprintf_p_l -_cwprintf_s -_cwprintf_s_l -_cwscanf -_cwscanf_l -_cwscanf_s -_cwscanf_s_l -_daylight -_difftime32 -_difftime64 -_dstbias -_dup -_dup2 -_ecvt -_ecvt_s -_endthread -_endthreadex -_environ -_eof -_errno -_execl -_execle -_execlp -_execlpe -_execv -_execve -_execvp -_execvpe -_exit -_expand -_expand_dbg -_fcloseall -_fcvt -_fcvt_s -_fdopen -_fgetchar -_fgetwchar -_filbuf -_fileinfo -_filelength -_filelengthi64 -_fileno -_findclose -_findfirst -_findfirst64 -_findfirsti64 -_findnext -_findnext64 -_findnexti64 -_finite -_finitef -_flsbuf -_flushall -_fmode -_fpclass -_fpclassf -_fpreset -_fprintf_l -_fprintf_p -_fprintf_p_l -_fprintf_s_l -_fputchar -_fputwchar -_free_dbg -_free_locale -_freea -_freea_s -_fscanf_l -_fscanf_s_l -_fseeki64 -_fsopen -_fstat -_fstat64 -_fstati64 -_ftime -_ftime32 -_ftime32_s -_ftime64 -_ftime64_s -_fullpath -_fullpath_dbg -_futime -_futime32 -_futime64 -_fwprintf_l -_fwprintf_p -_fwprintf_p_l -_fwprintf_s_l -_fwscanf_l -_fwscanf_s_l -_gcvt -_gcvt_s -_get_current_locale -_get_doserrno -_get_environ -_get_errno -_get_fileinfo -_get_fmode -_get_heap_handle -_get_osfhandle -_get_osplatform -_get_osver -_get_output_format -_get_pgmptr -_get_sbh_threshold -_get_wenviron -_get_winmajor -_get_winminor -_get_winver -_get_wpgmptr -_getch -_getche -_getcwd -_getdcwd -_getdiskfree -_getdrive -_getdrives -_getmaxstdio -_getmbcp -_getpid -_getsystime -_getw -_getwch -_getwche -_getws -_gmtime32 -_gmtime32_s -_gmtime64 -_gmtime64_s -_heapchk -_heapmin -_heapset -_heapwalk -_hypot -_hypotf -_i64toa -_i64toa_s -_i64tow -_i64tow_s -_initterm -_initterm_e -_invalid_parameter -_iob -_isalnum_l -_isalpha_l -_isatty -_iscntrl_l -_isctype -_isctype_l -_isdigit_l -_isgraph_l -_isleadbyte_l -_islower_l -_ismbbalnum -_ismbbalnum_l -_ismbbalpha -_ismbbalpha_l -_ismbbgraph -_ismbbgraph_l -_ismbbkalnum -_ismbbkalnum_l -_ismbbkana -_ismbbkana_l -_ismbbkprint -_ismbbkprint_l -_ismbbkpunct -_ismbbkpunct_l -_ismbblead -_ismbblead_l -_ismbbprint -_ismbbprint_l -_ismbbpunct -_ismbbpunct_l -_ismbbtrail -_ismbbtrail_l -_ismbcalnum -_ismbcalnum_l -_ismbcalpha -_ismbcalpha_l -_ismbcdigit -_ismbcdigit_l -_ismbcgraph -_ismbcgraph_l -_ismbchira -_ismbchira_l -_ismbckata -_ismbckata_l -_ismbcl0 -_ismbcl0_l -_ismbcl1 -_ismbcl1_l -_ismbcl2 -_ismbcl2_l -_ismbclegal -_ismbclegal_l -_ismbclower -_ismbclower_l -_ismbcprint -_ismbcprint_l -_ismbcpunct -_ismbcpunct_l -_ismbcspace -_ismbcspace_l -_ismbcsymbol -_ismbcsymbol_l -_ismbcupper -_ismbcupper_l -_ismbslead -_ismbslead_l -_ismbstrail -_ismbstrail_l -_isnan -_isnanf -_isprint_l -_isspace_l -_isupper_l -_iswalnum_l -_iswalpha_l -_iswcntrl_l -_iswctype_l -_iswdigit_l -_iswgraph_l -_iswlower_l -_iswprint_l -_iswpunct_l -_iswspace_l -_iswupper_l -_iswxdigit_l -_isxdigit_l -_itoa -_itoa_s -_itow -_itow_s -_j0 -_j1 -_jn -_kbhit -_lfind -_lfind_s -_local_unwind -_localtime32 -_localtime32_s -_localtime64 -_localtime64_s -_lock -_locking -_logb -_logbf -_lrotl -_lrotr -_lsearch -_lsearch_s -_lseek -_lseeki64 -_ltoa -_ltoa_s -_ltow -_ltow_s -_makepath -_makepath_s -_malloc_dbg -_mbbtombc -_mbbtombc_l -_mbbtype -_mbcasemap -_mbccpy -_mbccpy_l -_mbccpy_s -_mbccpy_s_l -_mbcjistojms -_mbcjistojms_l -_mbcjmstojis -_mbcjmstojis_l -_mbclen -_mbclen_l -_mbctohira -_mbctohira_l -_mbctokata -_mbctokata_l -_mbctolower -_mbctolower_l -_mbctombb -_mbctombb_l -_mbctoupper -_mbctoupper_l -_mbctype -_mblen_l -_mbsbtype -_mbsbtype_l -_mbscat -_mbscat_s -_mbscat_s_l -_mbschr -_mbschr_l -_mbscmp -_mbscmp_l -_mbscoll -_mbscoll_l -_mbscpy -_mbscpy_s -_mbscpy_s_l -_mbscspn -_mbscspn_l -_mbsdec -_mbsdec_l -_mbsdup -_mbsicmp -_mbsicmp_l -_mbsicoll -_mbsicoll_l -_mbsinc -_mbsinc_l -_mbslen -_mbslen_l -_mbslwr -_mbslwr_l -_mbslwr_s -_mbslwr_s_l -_mbsnbcat -_mbsnbcat_l -_mbsnbcat_s -_mbsnbcat_s_l -_mbsnbcmp -_mbsnbcmp_l -_mbsnbcnt -_mbsnbcnt_l -_mbsnbcoll -_mbsnbcoll_l -_mbsnbcpy -_mbsnbcpy_l -_mbsnbcpy_s -_mbsnbcpy_s_l -_mbsnbicmp -_mbsnbicmp_l -_mbsnbicoll -_mbsnbicoll_l -_mbsnbset -_mbsnbset_l -_mbsnbset_s -_mbsnbset_s_l -_mbsncat -_mbsncat_l -_mbsncat_s -_mbsncat_s_l -_mbsnccnt -_mbsnccnt_l -_mbsncmp -_mbsncmp_l -_mbsncoll -_mbsncoll_l -_mbsncpy -_mbsncpy_l -_mbsncpy_s -_mbsncpy_s_l -_mbsnextc -_mbsnextc_l -_mbsnicmp -_mbsnicmp_l -_mbsnicoll -_mbsnicoll_l -_mbsninc -_mbsninc_l -_mbsnlen -_mbsnlen_l -_mbsnset -_mbsnset_l -_mbsnset_s -_mbsnset_s_l -_mbspbrk -_mbspbrk_l -_mbsrchr -_mbsrchr_l -_mbsrev -_mbsrev_l -_mbsset -_mbsset_l -_mbsset_s -_mbsset_s_l -_mbsspn -_mbsspn_l -_mbsspnp -_mbsspnp_l -_mbsstr -_mbsstr_l -_mbstok -_mbstok_l -_mbstok_s -_mbstok_s_l -_mbstowcs_l -_mbstowcs_s_l -_mbstrlen -_mbstrlen_l -_mbstrnlen -_mbstrnlen_l -_mbsupr -_mbsupr_l -_mbsupr_s -_mbsupr_s_l -_mbtowc_l -_memccpy -_memicmp -_memicmp_l -_mkdir -_mkgmtime -_mkgmtime32 -_mkgmtime64 -_mktemp -_mktemp_s -_mktime32 -_mktime64 -_msize -_msize_dbg -_nextafter -_nextafterf -_onexit -_open -_open_osfhandle -_osplatform -_osver -_pclose -_pctype -_pgmptr -_pipe -_popen -_printf_l -_printf_p -_printf_p_l -_printf_s_l -_purecall -_putch -_putenv -_putenv_s -_putw -_putwch -_putws -_pwctype -_read -_realloc_dbg -_resetstkoflw -_rmdir -_rmtmp -_rotl -_rotl64 -_rotr -_rotr64 -_scalb -_scalbf -_scanf_l -_scanf_s_l -_scprintf -_scprintf_l -_scprintf_p_l -_scwprintf -_scwprintf_l -_scwprintf_p_l -_searchenv -_searchenv_s -_set_controlfp -_set_doserrno -_set_errno -_set_error_mode -_set_fileinfo -_set_fmode -_set_output_format -_set_sbh_threshold -_seterrormode -_setjmp -_setjmpex -_setmaxstdio -_setmbcp -_setmode -_setsystime -_sleep -_snprintf -_snprintf_c -_snprintf_c_l -_snprintf_l -_snprintf_s -_snprintf_s_l -_snscanf -_snscanf_l -_snscanf_s -_snscanf_s_l -_snwprintf -_snwprintf_l -_snwprintf_s -_snwprintf_s_l -_snwscanf -_snwscanf_l -_snwscanf_s -_snwscanf_s_l -_sopen -_sopen_s -_spawnl -_spawnle -_spawnlp -_spawnlpe -_spawnv -_spawnve -_spawnvp -_spawnvpe -_splitpath -_splitpath_s -_sprintf_l -_sprintf_p_l -_sprintf_s_l -_sscanf_l -_sscanf_s_l -_stat -_stat64 -_stati64 -_statusfp -_strcmpi -_strcoll_l -_strdate -_strdate_s -_strdup -_strdup_dbg -_strerror -_strerror_s -_stricmp -_stricmp_l -_stricoll -_stricoll_l -_strlwr -_strlwr_l -_strlwr_s -_strlwr_s_l -_strncoll -_strncoll_l -_strnicmp -_strnicmp_l -_strnicoll -_strnicoll_l -_strnset -_strnset_s -_strrev -_strset -_strset_s -_strtime -_strtime_s -_strtod_l -_strtoi64 -_strtoi64_l -_strtol_l -_strtoui64 -_strtoui64_l -_strtoul_l -_strupr -_strupr_l -_strupr_s -_strupr_s_l -_strxfrm_l -_swab -_swprintf -_swprintf_c -_swprintf_c_l -_swprintf_p_l -_swprintf_s_l -_swscanf_l -_swscanf_s_l -_sys_errlist -_sys_nerr -_tell -_telli64 -_tempnam -_tempnam_dbg -_time32 -_time64 -_timezone -_tolower -_tolower_l -_toupper -_toupper_l -_towlower_l -_towupper_l -_tzname -_tzset -_ui64toa -_ui64toa_s -_ui64tow -_ui64tow_s -_ultoa -_ultoa_s -_ultow -_ultow_s -_umask -_umask_s -_ungetch -_ungetwch -_unlink -_unlock -_utime -_utime32 -_utime64 -_vcprintf -_vcprintf_l -_vcprintf_p -_vcprintf_p_l -_vcprintf_s -_vcprintf_s_l -_vcwprintf -_vcwprintf_l -_vcwprintf_p -_vcwprintf_p_l -_vcwprintf_s -_vcwprintf_s_l -_vfprintf_l -_vfprintf_p -_vfprintf_p_l -_vfprintf_s_l -_vfwprintf_l -_vfwprintf_p -_vfwprintf_p_l -_vfwprintf_s_l -_vprintf_l -_vprintf_p -_vprintf_p_l -_vprintf_s_l -_vscprintf -_vscprintf_l -_vscprintf_p_l -_vscwprintf -_vscwprintf_l -_vscwprintf_p_l -_vsnprintf -_vsnprintf_c -_vsnprintf_c_l -_vsnprintf_l -_vsnprintf_s -_vsnprintf_s_l -_vsnwprintf -_vsnwprintf_l -_vsnwprintf_s -_vsnwprintf_s_l -_vsprintf_l -_vsprintf_p -_vsprintf_p_l -_vsprintf_s_l -_vswprintf -_vswprintf_c -_vswprintf_c_l -_vswprintf_l -_vswprintf_p_l -_vswprintf_s_l -_vwprintf_l -_vwprintf_p -_vwprintf_p_l -_vwprintf_s_l -_waccess -_waccess_s -_wasctime -_wasctime_s -_wassert -_wchdir -_wchmod -_wcmdln -_wcreat -_wcscoll_l -_wcsdup -_wcsdup_dbg -_wcserror -_wcserror_s -_wcsftime_l -_wcsicmp -_wcsicmp_l -_wcsicoll -_wcsicoll_l -_wcslwr -_wcslwr_l -_wcslwr_s -_wcslwr_s_l -_wcsncoll -_wcsncoll_l -_wcsnicmp -_wcsnicmp_l -_wcsnicoll -_wcsnicoll_l -_wcsnset -_wcsnset_s -_wcsrev -_wcsset -_wcsset_s -_wcstod_l -_wcstoi64 -_wcstoi64_l -_wcstol_l -_wcstombs_l -_wcstombs_s_l -_wcstoui64 -_wcstoui64_l -_wcstoul_l -_wcsupr -_wcsupr_l -_wcsupr_s -_wcsupr_s_l -_wcsxfrm_l -_wctime -_wctime32 -_wctime32_s -_wctime64 -_wctime64_s -_wctomb_l -_wctomb_s_l -_wctype -_wenviron -_wexecl -_wexecle -_wexeclp -_wexeclpe -_wexecv -_wexecve -_wexecvp -_wexecvpe -_wfdopen -_wfindfirst -_wfindfirst64 -_wfindfirsti64 -_wfindnext -_wfindnext64 -_wfindnexti64 -_wfopen -_wfopen_s -_wfreopen -_wfreopen_s -_wfsopen -_wfullpath -_wfullpath_dbg -_wgetcwd -_wgetdcwd -_wgetenv -_wgetenv_s -_winmajor -_winminor -_winput_s -_winver -_wmakepath -_wmakepath_s -_wmkdir -_wmktemp -_wmktemp_s -_wopen -_woutput_s -_wperror -_wpgmptr -_wpopen -_wprintf_l -_wprintf_p -_wprintf_p_l -_wprintf_s_l -_wputenv -_wputenv_s -_wremove -_wrename -_write -_wrmdir -_wscanf_l -_wscanf_s_l -_wsearchenv -_wsearchenv_s -_wsetlocale -_wsopen -_wsopen_s -_wspawnl -_wspawnle -_wspawnlp -_wspawnlpe -_wspawnv -_wspawnve -_wspawnvp -_wspawnvpe -_wsplitpath -_wsplitpath_s -_wstat -_wstat64 -_wstati64 -_wstrdate -_wstrdate_s -_wstrtime -_wstrtime_s -_wsystem -_wtempnam -_wtempnam_dbg -_wtmpnam -_wtmpnam_s -_wtof -_wtof_l -_wtoi -_wtoi64 -_wtoi64_l -_wtoi_l -_wtol -_wtol_l -_wunlink -_wutime -_wutime32 -_wutime64 -_y0 -_y1 -_yn -abort -abs -acos -acosf -asctime -asctime_s -asin -asinf -atan -atan2 -atan2f -atanf -atexit -atof -atoi -atol -bsearch -bsearch_s -btowc -calloc -ceil -ceilf -clearerr -clearerr_s -clock -cos -cosf -cosh -coshf -ctime -difftime -div -exit -exp -expf -fabs -fclose -feof -ferror -fflush -fgetc -fgetpos -fgets -fgetwc -fgetws -floor -floorf -fmod -fmodf -fopen -fopen_s -fprintf -fprintf_s -fputc -fputs -fputwc -fputws -fread -free -freopen -freopen_s -frexp -fscanf -fscanf_s -fseek -fsetpos -ftell -fwprintf -fwprintf_s -fwrite -fwscanf -fwscanf_s -getc -getchar -getenv -getenv_s -gets -getwc -getwchar -gmtime -is_wctype -isalnum -isalpha -iscntrl -isdigit -isgraph -isleadbyte -islower -isprint -ispunct -isspace -isupper -iswalnum -iswalpha -iswascii -iswcntrl -iswctype -iswdigit -iswgraph -iswlower -iswprint -iswpunct -iswspace -iswupper -iswxdigit -isxdigit -labs -ldexp -ldiv -localeconv -localtime -log -log10 -log10f -logf -longjmp -malloc -mblen -mbrlen -mbrtowc -mbsdup_dbg -mbsrtowcs -mbsrtowcs_s -mbstowcs -mbstowcs_s -mbtowc -memchr -memcmp -memcpy -memcpy_s -memmove -memmove_s -memset -mktime -modf -modff -perror -pow -powf -printf -printf_s -putc -putchar -puts -putwc -putwchar -qsort -qsort_s -raise -rand -rand_s -realloc -remove -rename -rewind -scanf -scanf_s -setbuf -setjmp -setlocale -setvbuf -signal -sin -sinf -sinh -sinhf -sprintf -sprintf_s -sqrt -sqrtf -srand -sscanf -sscanf_s -strcat -strcat_s -strchr -strcmp -strcoll -strcpy -strcpy_s -strcspn -strerror -strerror_s -strftime -strlen -strncat -strncat_s -strncmp -strncpy -strncpy_s -strnlen -strpbrk -strrchr -strspn -strstr -strtod -strtok -strtok_s -strtol -strtoul -strxfrm -swprintf -swprintf_s -swscanf -swscanf_s -system -tan -tanf -tanh -tanhf -time -tmpfile -tmpfile_s -tmpnam -tmpnam_s -tolower -toupper -towlower -towupper -ungetc -ungetwc -utime -vfprintf -vfprintf_s -vfwprintf -vfwprintf_s -vprintf -vprintf_s -vsnprintf -vsprintf -vsprintf_s -vswprintf -vswprintf_s -vwprintf -vwprintf_s -wcrtomb -wcrtomb_s -wcscat -wcscat_s -wcschr -wcscmp -wcscoll -wcscpy -wcscpy_s -wcscspn -wcsftime -wcslen -wcsncat -wcsncat_s -wcsncmp -wcsncpy -wcsncpy_s -wcsnlen -wcspbrk -wcsrchr -wcsrtombs -wcsrtombs_s -wcsspn -wcsstr -wcstod -wcstok -wcstok_s -wcstol -wcstombs -wcstombs_s -wcstoul -wcsxfrm -wctob -wctomb -wctomb_s -wprintf -wprintf_s -wscanf -wscanf_s +LIBRARY msvcrt.dll + +EXPORTS +??0__non_rtti_object@@QEAA@AEBV0@@Z +??0__non_rtti_object@@QEAA@PEBD@Z +??0bad_cast@@AAE@PBQBD@Z +??0bad_cast@@AEAA@PEBQEBD@Z +??0bad_cast@@QAE@ABQBD@Z +??0bad_cast@@QEAA@AEBQEBD@Z +??0bad_cast@@QEAA@AEBV0@@Z +??0bad_cast@@QEAA@PEBD@Z +??0bad_typeid@@QEAA@AEBV0@@Z +??0bad_typeid@@QEAA@PEBD@Z +??0exception@@QEAA@AEBQEBD@Z +??0exception@@QEAA@AEBQEBDH@Z +??0exception@@QEAA@AEBV0@@Z +??0exception@@QEAA@XZ +??1__non_rtti_object@@UEAA@XZ +??1bad_cast@@UEAA@XZ +??1bad_typeid@@UEAA@XZ +??1exception@@UEAA@XZ +??1type_info@@UEAA@XZ +??2@YAPEAX_K@Z +??2@YAPEAX_KHPEBDH@Z +??3@YAXPEAX@Z +??4__non_rtti_object@@QEAAAEAV0@AEBV0@@Z +??4bad_cast@@QEAAAEAV0@AEBV0@@Z +??4bad_typeid@@QEAAAEAV0@AEBV0@@Z +??4exception@@QEAAAEAV0@AEBV0@@Z +??8type_info@@QEBAHAEBV0@@Z +??9type_info@@QEBAHAEBV0@@Z +??_7__non_rtti_object@@6B@ +??_7bad_cast@@6B@ +??_7bad_typeid@@6B@ +??_7exception@@6B@ +??_Fbad_cast@@QEAAXXZ +??_Fbad_typeid@@QEAAXXZ +??_U@YAPEAX_K@Z +??_U@YAPEAX_KHPEBDH@Z +??_V@YAXPEAX@Z +?_query_new_handler@@YAP6AH_K@ZXZ +?_query_new_mode@@YAHXZ +?_set_new_handler@@YAP6AH_K@ZP6AH0@Z@Z +?_set_new_mode@@YAHH@Z +?_set_se_translator@@YAP6AXIPEAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z +?before@type_info@@QEBAHAEBV1@@Z +?name@type_info@@QEBAPEBDXZ +?raw_name@type_info@@QEBAPEBDXZ +?set_new_handler@@YAP6AXXZP6AXXZ@Z +?set_terminate@@YAP6AXXZP6AXXZ@Z +?set_unexpected@@YAP6AXXZP6AXXZ@Z +?terminate@@YAXXZ +?unexpected@@YAXXZ +?what@exception@@UEBAPEBDXZ +_CrtCheckMemory +_CrtDbgBreak +_CrtDbgReport +_CrtDbgReportV +_CrtDbgReportW +_CrtDbgReportWV +_CrtDoForAllClientObjects +_CrtDumpMemoryLeaks +_CrtIsMemoryBlock +_CrtIsValidHeapPointer +_CrtIsValidPointer +_CrtMemCheckpoint +_CrtMemDifference +_CrtMemDumpAllObjectsSince +_CrtMemDumpStatistics +_CrtReportBlockType +_CrtSetAllocHook +_CrtSetBreakAlloc +_CrtSetDbgBlockType +_CrtSetDbgFlag +_CrtSetDumpClient +_CrtSetReportFile +_CrtSetReportHook +_CrtSetReportHook2 +_CrtSetReportMode +_CxxThrowException +_Getdays +_Getmonths +_Gettnames +_HUGE +_Strftime +_W_Getdays +_W_Getmonths +_W_Gettnames +_Wcsftime +_XcptFilter +__AdjustPointer +__C_specific_handler +__CppXcptFilter +__CxxFrameHandler +__CxxFrameHandler2 +__CxxFrameHandler3 +__DestructExceptionObject +__ExceptionPtrAssign +__ExceptionPtrCompare +__ExceptionPtrCopy +__ExceptionPtrCopyException +__ExceptionPtrCreate +__ExceptionPtrCurrentException +__ExceptionPtrDestroy +__ExceptionPtrRethrow +__ExceptionPtrSwap +__ExceptionPtrToBool +__RTCastToVoid +__RTDynamicCast +__RTtypeid +__STRINGTOLD +___lc_codepage_func +___lc_collate_cp_func +___lc_handle_func +___mb_cur_max_func +___setlc_active_func +___unguarded_readlc_active_add_func +__argc +__argv +__badioinfo +__crtCompareStringA +__crtCompareStringW +__crtGetLocaleInfoW +__crtGetStringTypeW +__crtLCMapStringA +__crtLCMapStringW +__daylight +__dllonexit +__doserrno +__dstbias +__fpecode +__getmainargs +__initenv +__iob_func +__isascii +__iscsym +__iscsymf +__lc_codepage +__lc_collate_cp +__lc_handle +__lconv_init +__mb_cur_max +__pctype_func +__pioinfo +__pwctype_func +__pxcptinfoptrs +__set_app_type +__setlc_active +__setusermatherr +__strncnt +__threadhandle +__threadid +__toascii +__unDName +__unDNameEx +__uncaught_exception +__unguarded_readlc_active +__wargv +__wcserror +__wcserror_s +__wcsncnt +__wgetmainargs +__winitenv +_abs64 +_access +_access_s +_acmdln +_aexit_rtn +_aligned_free +_aligned_free_dbg +_aligned_malloc +_aligned_malloc_dbg +_aligned_offset_malloc +_aligned_offset_malloc_dbg +_aligned_offset_realloc +_aligned_offset_realloc_dbg +_aligned_realloc +_aligned_realloc_dbg +_amsg_exit +_assert +_atodbl +_atodbl_l +_atof_l +_atoflt_l +_atoi64 +_atoi64_l +_atoi_l +_atol_l +_atoldbl +_atoldbl_l +_beep +_beginthread +_beginthreadex +_c_exit +_cabs +_callnewh +_calloc_dbg +_cexit +_cgets +_cgets_s +_cgetws +_cgetws_s +_chdir +_chdrive +_chgsign +_chgsignf +_chmod +_chsize +_chsize_s +_chvalidator +_chvalidator_l +_clearfp +_close +_commit +_commode +_control87 +_controlfp +_controlfp_s +_copysign +_copysignf +_cprintf +_cprintf_l +_cprintf_p +_cprintf_p_l +_cprintf_s +_cprintf_s_l +_cputs +_cputws +_creat +_create_locale +_crtAssertBusy +_crtBreakAlloc +_crtDbgFlag +_cscanf +_cscanf_l +_cscanf_s +_cscanf_s_l +_ctime32 +_ctime32_s +_ctime64 +_ctime64_s +_ctype +_cwait +_cwprintf +_cwprintf_l +_cwprintf_p +_cwprintf_p_l +_cwprintf_s +_cwprintf_s_l +_cwscanf +_cwscanf_l +_cwscanf_s +_cwscanf_s_l +_daylight +_difftime32 +_difftime64 +_dstbias +_dup +_dup2 +_ecvt +_ecvt_s +_endthread +_endthreadex +_environ +_eof +_errno +_execl +_execle +_execlp +_execlpe +_execv +_execve +_execvp +_execvpe +_exit +_expand +_expand_dbg +_fcloseall +_fcvt +_fcvt_s +_fdopen +_fgetchar +_fgetwchar +_filbuf +_fileinfo +_filelength +_filelengthi64 +_fileno +_findclose +_findfirst +_findfirst64 +_findfirsti64 +_findnext +_findnext64 +_findnexti64 +_finite +_finitef +_flsbuf +_flushall +_fmode +_fpclass +_fpclassf +_fpreset +_fprintf_l +_fprintf_p +_fprintf_p_l +_fprintf_s_l +_fputchar +_fputwchar +_free_dbg +_free_locale +_freea +_freea_s +_fscanf_l +_fscanf_s_l +_fseeki64 +_fsopen +_fstat +_fstat64 +_fstati64 +_ftime +_ftime32 +_ftime32_s +_ftime64 +_ftime64_s +_fullpath +_fullpath_dbg +_futime +_futime32 +_futime64 +_fwprintf_l +_fwprintf_p +_fwprintf_p_l +_fwprintf_s_l +_fwscanf_l +_fwscanf_s_l +_gcvt +_gcvt_s +_get_current_locale +_get_doserrno +_get_environ +_get_errno +_get_fileinfo +_get_fmode +_get_heap_handle +_get_osfhandle +_get_osplatform +_get_osver +_get_output_format +_get_pgmptr +_get_sbh_threshold +_get_wenviron +_get_winmajor +_get_winminor +_get_winver +_get_wpgmptr +_getch +_getche +_getcwd +_getdcwd +_getdiskfree +_getdrive +_getdrives +_getmaxstdio +_getmbcp +_getpid +_getsystime +_getw +_getwch +_getwche +_getws +_gmtime32 +_gmtime32_s +_gmtime64 +_gmtime64_s +_heapchk +_heapmin +_heapset +_heapwalk +_hypot +_hypotf +_i64toa +_i64toa_s +_i64tow +_i64tow_s +_initterm +_initterm_e +_invalid_parameter +_iob +_isalnum_l +_isalpha_l +_isatty +_iscntrl_l +_isctype +_isctype_l +_isdigit_l +_isgraph_l +_isleadbyte_l +_islower_l +_ismbbalnum +_ismbbalnum_l +_ismbbalpha +_ismbbalpha_l +_ismbbgraph +_ismbbgraph_l +_ismbbkalnum +_ismbbkalnum_l +_ismbbkana +_ismbbkana_l +_ismbbkprint +_ismbbkprint_l +_ismbbkpunct +_ismbbkpunct_l +_ismbblead +_ismbblead_l +_ismbbprint +_ismbbprint_l +_ismbbpunct +_ismbbpunct_l +_ismbbtrail +_ismbbtrail_l +_ismbcalnum +_ismbcalnum_l +_ismbcalpha +_ismbcalpha_l +_ismbcdigit +_ismbcdigit_l +_ismbcgraph +_ismbcgraph_l +_ismbchira +_ismbchira_l +_ismbckata +_ismbckata_l +_ismbcl0 +_ismbcl0_l +_ismbcl1 +_ismbcl1_l +_ismbcl2 +_ismbcl2_l +_ismbclegal +_ismbclegal_l +_ismbclower +_ismbclower_l +_ismbcprint +_ismbcprint_l +_ismbcpunct +_ismbcpunct_l +_ismbcspace +_ismbcspace_l +_ismbcsymbol +_ismbcsymbol_l +_ismbcupper +_ismbcupper_l +_ismbslead +_ismbslead_l +_ismbstrail +_ismbstrail_l +_isnan +_isnanf +_isprint_l +_isspace_l +_isupper_l +_iswalnum_l +_iswalpha_l +_iswcntrl_l +_iswctype_l +_iswdigit_l +_iswgraph_l +_iswlower_l +_iswprint_l +_iswpunct_l +_iswspace_l +_iswupper_l +_iswxdigit_l +_isxdigit_l +_itoa +_itoa_s +_itow +_itow_s +_j0 +_j1 +_jn +_kbhit +_lfind +_lfind_s +_local_unwind +_localtime32 +_localtime32_s +_localtime64 +_localtime64_s +_lock +_locking +_logb +_logbf +_lrotl +_lrotr +_lsearch +_lsearch_s +_lseek +_lseeki64 +_ltoa +_ltoa_s +_ltow +_ltow_s +_makepath +_makepath_s +_malloc_dbg +_mbbtombc +_mbbtombc_l +_mbbtype +_mbcasemap +_mbccpy +_mbccpy_l +_mbccpy_s +_mbccpy_s_l +_mbcjistojms +_mbcjistojms_l +_mbcjmstojis +_mbcjmstojis_l +_mbclen +_mbclen_l +_mbctohira +_mbctohira_l +_mbctokata +_mbctokata_l +_mbctolower +_mbctolower_l +_mbctombb +_mbctombb_l +_mbctoupper +_mbctoupper_l +_mbctype +_mblen_l +_mbsbtype +_mbsbtype_l +_mbscat +_mbscat_s +_mbscat_s_l +_mbschr +_mbschr_l +_mbscmp +_mbscmp_l +_mbscoll +_mbscoll_l +_mbscpy +_mbscpy_s +_mbscpy_s_l +_mbscspn +_mbscspn_l +_mbsdec +_mbsdec_l +_mbsdup +_mbsicmp +_mbsicmp_l +_mbsicoll +_mbsicoll_l +_mbsinc +_mbsinc_l +_mbslen +_mbslen_l +_mbslwr +_mbslwr_l +_mbslwr_s +_mbslwr_s_l +_mbsnbcat +_mbsnbcat_l +_mbsnbcat_s +_mbsnbcat_s_l +_mbsnbcmp +_mbsnbcmp_l +_mbsnbcnt +_mbsnbcnt_l +_mbsnbcoll +_mbsnbcoll_l +_mbsnbcpy +_mbsnbcpy_l +_mbsnbcpy_s +_mbsnbcpy_s_l +_mbsnbicmp +_mbsnbicmp_l +_mbsnbicoll +_mbsnbicoll_l +_mbsnbset +_mbsnbset_l +_mbsnbset_s +_mbsnbset_s_l +_mbsncat +_mbsncat_l +_mbsncat_s +_mbsncat_s_l +_mbsnccnt +_mbsnccnt_l +_mbsncmp +_mbsncmp_l +_mbsncoll +_mbsncoll_l +_mbsncpy +_mbsncpy_l +_mbsncpy_s +_mbsncpy_s_l +_mbsnextc +_mbsnextc_l +_mbsnicmp +_mbsnicmp_l +_mbsnicoll +_mbsnicoll_l +_mbsninc +_mbsninc_l +_mbsnlen +_mbsnlen_l +_mbsnset +_mbsnset_l +_mbsnset_s +_mbsnset_s_l +_mbspbrk +_mbspbrk_l +_mbsrchr +_mbsrchr_l +_mbsrev +_mbsrev_l +_mbsset +_mbsset_l +_mbsset_s +_mbsset_s_l +_mbsspn +_mbsspn_l +_mbsspnp +_mbsspnp_l +_mbsstr +_mbsstr_l +_mbstok +_mbstok_l +_mbstok_s +_mbstok_s_l +_mbstowcs_l +_mbstowcs_s_l +_mbstrlen +_mbstrlen_l +_mbstrnlen +_mbstrnlen_l +_mbsupr +_mbsupr_l +_mbsupr_s +_mbsupr_s_l +_mbtowc_l +_memccpy +_memicmp +_memicmp_l +_mkdir +_mkgmtime +_mkgmtime32 +_mkgmtime64 +_mktemp +_mktemp_s +_mktime32 +_mktime64 +_msize +_msize_dbg +_nextafter +_nextafterf +_onexit +_open +_open_osfhandle +_osplatform +_osver +_pclose +_pctype +_pgmptr +_pipe +_popen +_printf_l +_printf_p +_printf_p_l +_printf_s_l +_purecall +_putch +_putenv +_putenv_s +_putw +_putwch +_putws +_pwctype +_read +_realloc_dbg +_resetstkoflw +_rmdir +_rmtmp +_rotl +_rotl64 +_rotr +_rotr64 +_scalb +_scalbf +_scanf_l +_scanf_s_l +_scprintf +_scprintf_l +_scprintf_p_l +_scwprintf +_scwprintf_l +_scwprintf_p_l +_searchenv +_searchenv_s +_set_controlfp +_set_doserrno +_set_errno +_set_error_mode +_set_fileinfo +_set_fmode +_set_output_format +_set_sbh_threshold +_seterrormode +_setjmp +_setjmpex +_setmaxstdio +_setmbcp +_setmode +_setsystime +_sleep +_snprintf +_snprintf_c +_snprintf_c_l +_snprintf_l +_snprintf_s +_snprintf_s_l +_snscanf +_snscanf_l +_snscanf_s +_snscanf_s_l +_snwprintf +_snwprintf_l +_snwprintf_s +_snwprintf_s_l +_snwscanf +_snwscanf_l +_snwscanf_s +_snwscanf_s_l +_sopen +_sopen_s +_spawnl +_spawnle +_spawnlp +_spawnlpe +_spawnv +_spawnve +_spawnvp +_spawnvpe +_splitpath +_splitpath_s +_sprintf_l +_sprintf_p_l +_sprintf_s_l +_sscanf_l +_sscanf_s_l +_stat +_stat64 +_stati64 +_statusfp +_strcmpi +_strcoll_l +_strdate +_strdate_s +_strdup +_strdup_dbg +_strerror +_strerror_s +_stricmp +_stricmp_l +_stricoll +_stricoll_l +_strlwr +_strlwr_l +_strlwr_s +_strlwr_s_l +_strncoll +_strncoll_l +_strnicmp +_strnicmp_l +_strnicoll +_strnicoll_l +_strnset +_strnset_s +_strrev +_strset +_strset_s +_strtime +_strtime_s +_strtod_l +_strtoi64 +_strtoi64_l +_strtol_l +_strtoui64 +_strtoui64_l +_strtoul_l +_strupr +_strupr_l +_strupr_s +_strupr_s_l +_strxfrm_l +_swab +_swprintf +_swprintf_c +_swprintf_c_l +_swprintf_p_l +_swprintf_s_l +_swscanf_l +_swscanf_s_l +_sys_errlist +_sys_nerr +_tell +_telli64 +_tempnam +_tempnam_dbg +_time32 +_time64 +_timezone +_tolower +_tolower_l +_toupper +_toupper_l +_towlower_l +_towupper_l +_tzname +_tzset +_ui64toa +_ui64toa_s +_ui64tow +_ui64tow_s +_ultoa +_ultoa_s +_ultow +_ultow_s +_umask +_umask_s +_ungetch +_ungetwch +_unlink +_unlock +_utime +_utime32 +_utime64 +_vcprintf +_vcprintf_l +_vcprintf_p +_vcprintf_p_l +_vcprintf_s +_vcprintf_s_l +_vcwprintf +_vcwprintf_l +_vcwprintf_p +_vcwprintf_p_l +_vcwprintf_s +_vcwprintf_s_l +_vfprintf_l +_vfprintf_p +_vfprintf_p_l +_vfprintf_s_l +_vfwprintf_l +_vfwprintf_p +_vfwprintf_p_l +_vfwprintf_s_l +_vprintf_l +_vprintf_p +_vprintf_p_l +_vprintf_s_l +_vscprintf +_vscprintf_l +_vscprintf_p_l +_vscwprintf +_vscwprintf_l +_vscwprintf_p_l +_vsnprintf +_vsnprintf_c +_vsnprintf_c_l +_vsnprintf_l +_vsnprintf_s +_vsnprintf_s_l +_vsnwprintf +_vsnwprintf_l +_vsnwprintf_s +_vsnwprintf_s_l +_vsprintf_l +_vsprintf_p +_vsprintf_p_l +_vsprintf_s_l +_vswprintf +_vswprintf_c +_vswprintf_c_l +_vswprintf_l +_vswprintf_p_l +_vswprintf_s_l +_vwprintf_l +_vwprintf_p +_vwprintf_p_l +_vwprintf_s_l +_waccess +_waccess_s +_wasctime +_wasctime_s +_wassert +_wchdir +_wchmod +_wcmdln +_wcreat +_wcscoll_l +_wcsdup +_wcsdup_dbg +_wcserror +_wcserror_s +_wcsftime_l +_wcsicmp +_wcsicmp_l +_wcsicoll +_wcsicoll_l +_wcslwr +_wcslwr_l +_wcslwr_s +_wcslwr_s_l +_wcsncoll +_wcsncoll_l +_wcsnicmp +_wcsnicmp_l +_wcsnicoll +_wcsnicoll_l +_wcsnset +_wcsnset_s +_wcsrev +_wcsset +_wcsset_s +_wcstod_l +_wcstoi64 +_wcstoi64_l +_wcstol_l +_wcstombs_l +_wcstombs_s_l +_wcstoui64 +_wcstoui64_l +_wcstoul_l +_wcsupr +_wcsupr_l +_wcsupr_s +_wcsupr_s_l +_wcsxfrm_l +_wctime +_wctime32 +_wctime32_s +_wctime64 +_wctime64_s +_wctomb_l +_wctomb_s_l +_wctype +_wenviron +_wexecl +_wexecle +_wexeclp +_wexeclpe +_wexecv +_wexecve +_wexecvp +_wexecvpe +_wfdopen +_wfindfirst +_wfindfirst64 +_wfindfirsti64 +_wfindnext +_wfindnext64 +_wfindnexti64 +_wfopen +_wfopen_s +_wfreopen +_wfreopen_s +_wfsopen +_wfullpath +_wfullpath_dbg +_wgetcwd +_wgetdcwd +_wgetenv +_wgetenv_s +_winmajor +_winminor +_winput_s +_winver +_wmakepath +_wmakepath_s +_wmkdir +_wmktemp +_wmktemp_s +_wopen +_woutput_s +_wperror +_wpgmptr +_wpopen +_wprintf_l +_wprintf_p +_wprintf_p_l +_wprintf_s_l +_wputenv +_wputenv_s +_wremove +_wrename +_write +_wrmdir +_wscanf_l +_wscanf_s_l +_wsearchenv +_wsearchenv_s +_wsetlocale +_wsopen +_wsopen_s +_wspawnl +_wspawnle +_wspawnlp +_wspawnlpe +_wspawnv +_wspawnve +_wspawnvp +_wspawnvpe +_wsplitpath +_wsplitpath_s +_wstat +_wstat64 +_wstati64 +_wstrdate +_wstrdate_s +_wstrtime +_wstrtime_s +_wsystem +_wtempnam +_wtempnam_dbg +_wtmpnam +_wtmpnam_s +_wtof +_wtof_l +_wtoi +_wtoi64 +_wtoi64_l +_wtoi_l +_wtol +_wtol_l +_wunlink +_wutime +_wutime32 +_wutime64 +_y0 +_y1 +_yn +abort +abs +acos +acosf +asctime +asctime_s +asin +asinf +atan +atan2 +atan2f +atanf +atexit +atof +atoi +atol +bsearch +bsearch_s +btowc +calloc +ceil +ceilf +clearerr +clearerr_s +clock +cos +cosf +cosh +coshf +ctime +difftime +div +exit +exp +expf +fabs +fclose +feof +ferror +fflush +fgetc +fgetpos +fgets +fgetwc +fgetws +floor +floorf +fmod +fmodf +fopen +fopen_s +fprintf +fprintf_s +fputc +fputs +fputwc +fputws +fread +free +freopen +freopen_s +frexp +fscanf +fscanf_s +fseek +fsetpos +ftell +fwprintf +fwprintf_s +fwrite +fwscanf +fwscanf_s +getc +getchar +getenv +getenv_s +gets +getwc +getwchar +gmtime +is_wctype +isalnum +isalpha +iscntrl +isdigit +isgraph +isleadbyte +islower +isprint +ispunct +isspace +isupper +iswalnum +iswalpha +iswascii +iswcntrl +iswctype +iswdigit +iswgraph +iswlower +iswprint +iswpunct +iswspace +iswupper +iswxdigit +isxdigit +labs +ldexp +ldiv +localeconv +localtime +log +log10 +log10f +logf +longjmp +malloc +mblen +mbrlen +mbrtowc +mbsdup_dbg +mbsrtowcs +mbsrtowcs_s +mbstowcs +mbstowcs_s +mbtowc +memchr +memcmp +memcpy +memcpy_s +memmove +memmove_s +memset +mktime +modf +modff +perror +pow +powf +printf +printf_s +putc +putchar +puts +putwc +putwchar +qsort +qsort_s +raise +rand +rand_s +realloc +remove +rename +rewind +scanf +scanf_s +setbuf +setjmp +setlocale +setvbuf +signal +sin +sinf +sinh +sinhf +sprintf +sprintf_s +sqrt +sqrtf +srand +sscanf +sscanf_s +strcat +strcat_s +strchr +strcmp +strcoll +strcpy +strcpy_s +strcspn +strerror +strerror_s +strftime +strlen +strncat +strncat_s +strncmp +strncpy +strncpy_s +strnlen +strpbrk +strrchr +strspn +strstr +strtod +strtok +strtok_s +strtol +strtoul +strxfrm +swprintf +swprintf_s +swscanf +swscanf_s +system +tan +tanf +tanh +tanhf +time +tmpfile +tmpfile_s +tmpnam +tmpnam_s +tolower +toupper +towlower +towupper +ungetc +ungetwc +utime +vfprintf +vfprintf_s +vfwprintf +vfwprintf_s +vprintf +vprintf_s +vsnprintf +vsprintf +vsprintf_s +vswprintf +vswprintf_s +vwprintf +vwprintf_s +wcrtomb +wcrtomb_s +wcscat +wcscat_s +wcschr +wcscmp +wcscoll +wcscpy +wcscpy_s +wcscspn +wcsftime +wcslen +wcsncat +wcsncat_s +wcsncmp +wcsncpy +wcsncpy_s +wcsnlen +wcspbrk +wcsrchr +wcsrtombs +wcsrtombs_s +wcsspn +wcsstr +wcstod +wcstok +wcstok_s +wcstol +wcstombs +wcstombs_s +wcstoul +wcsxfrm +wctob +wctomb +wctomb_s +wprintf +wprintf_s +wscanf +wscanf_s diff --git a/tcc/lib/user32.def b/tcc/lib/user32.def index a034dac2..f9863c54 100644 --- a/tcc/lib/user32.def +++ b/tcc/lib/user32.def @@ -1,658 +1,658 @@ -LIBRARY user32.dll - -EXPORTS -ActivateKeyboardLayout -AdjustWindowRect -AdjustWindowRectEx -AlignRects -AllowSetForegroundWindow -AnimateWindow -AnyPopup -AppendMenuA -AppendMenuW -ArrangeIconicWindows -AttachThreadInput -BeginDeferWindowPos -BeginPaint -BlockInput -BringWindowToTop -BroadcastSystemMessage -BroadcastSystemMessageA -BroadcastSystemMessageW -CalcChildScroll -CallMsgFilter -CallMsgFilterA -CallMsgFilterW -CallNextHookEx -CallWindowProcA -CallWindowProcW -CascadeChildWindows -CascadeWindows -ChangeClipboardChain -ChangeDisplaySettingsA -ChangeDisplaySettingsExA -ChangeDisplaySettingsExW -ChangeDisplaySettingsW -ChangeMenuA -ChangeMenuW -CharLowerA -CharLowerBuffA -CharLowerBuffW -CharLowerW -CharNextA -CharNextExA -CharNextExW -CharNextW -CharPrevA -CharPrevExA -CharPrevExW -CharPrevW -CharToOemA -CharToOemBuffA -CharToOemBuffW -CharToOemW -CharUpperA -CharUpperBuffA -CharUpperBuffW -CharUpperW -CheckDlgButton -CheckMenuItem -CheckMenuRadioItem -CheckRadioButton -ChildWindowFromPoint -ChildWindowFromPointEx -ClientThreadConnect -ClientToScreen -ClipCursor -CloseClipboard -CloseDesktop -CloseWindow -CloseWindowStation -CopyAcceleratorTableA -CopyAcceleratorTableW -CopyIcon -CopyImage -CopyRect -CountClipboardFormats -CreateAcceleratorTableA -CreateAcceleratorTableW -CreateCaret -CreateCursor -CreateDesktopA -CreateDesktopW -CreateDialogIndirectParamA -CreateDialogIndirectParamW -CreateDialogParamA -CreateDialogParamW -CreateIcon -CreateIconFromResource -CreateIconFromResourceEx -CreateIconIndirect -CreateMDIWindowA -CreateMDIWindowW -CreateMenu -CreatePopupMenu -CreateWindowExA -CreateWindowExW -CreateWindowStationA -CreateWindowStationW -DdeAbandonTransaction -DdeAccessData -DdeAddData -DdeClientTransaction -DdeCmpStringHandles -DdeConnect -DdeConnectList -DdeCreateDataHandle -DdeCreateStringHandleA -DdeCreateStringHandleW -DdeDisconnect -DdeDisconnectList -DdeEnableCallback -DdeFreeDataHandle -DdeFreeStringHandle -DdeGetData -DdeGetLastError -DdeImpersonateClient -DdeInitializeA -DdeInitializeW -DdeKeepStringHandle -DdeNameService -DdePostAdvise -DdeQueryConvInfo -DdeQueryNextServer -DdeQueryStringA -DdeQueryStringW -DdeReconnect -DdeSetQualityOfService -DdeSetUserHandle -DdeUnaccessData -DdeUninitialize -DefDlgProcA -DefDlgProcW -DefFrameProcA -DefFrameProcW -DefMDIChildProcA -DefMDIChildProcW -DefWindowProcA -DefWindowProcW -DeferWindowPos -DeleteMenu -DestroyAcceleratorTable -DestroyCaret -DestroyCursor -DestroyIcon -DestroyMenu -DestroyWindow -DialogBoxIndirectParamA -DialogBoxIndirectParamW -DialogBoxParamA -DialogBoxParamW -DispatchMessageA -DispatchMessageW -DlgDirListA -DlgDirListComboBoxA -DlgDirListComboBoxW -DlgDirListW -DlgDirSelectComboBoxExA -DlgDirSelectComboBoxExW -DlgDirSelectExA -DlgDirSelectExW -DragDetect -DragObject -DrawAnimatedRects -DrawCaption -DrawCaptionTempA -DrawCaptionTempW -DrawEdge -DrawFocusRect -DrawFrame -DrawFrameControl -DrawIcon -DrawIconEx -DrawMenuBar -DrawMenuBarTemp -DrawStateA -DrawStateW -DrawTextA -DrawTextExA -DrawTextExW -DrawTextW -EditWndProc -EmptyClipboard -EnableMenuItem -EnableScrollBar -EnableWindow -EndDeferWindowPos -EndDialog -EndMenu -EndPaint -EndTask -EnumChildWindows -EnumClipboardFormats -EnumDesktopWindows -EnumDesktopsA -EnumDesktopsW -EnumDisplayDevicesA -EnumDisplayDevicesW -EnumDisplayMonitors -EnumDisplaySettingsA -EnumDisplaySettingsExA -EnumDisplaySettingsExW -EnumDisplaySettingsW -EnumPropsA -EnumPropsExA -EnumPropsExW -EnumPropsW -EnumThreadWindows -EnumWindowStationsA -EnumWindowStationsW -EnumWindows -EqualRect -ExcludeUpdateRgn -ExitWindowsEx -FillRect -FindWindowA -FindWindowExA -FindWindowExW -FindWindowW -FlashWindow -FlashWindowEx -FrameRect -FreeDDElParam -GetActiveWindow -GetAltTabInfo -GetAncestor -GetAsyncKeyState -GetCapture -GetCaretBlinkTime -GetCaretPos -GetClassInfoA -GetClassInfoExA -GetClassInfoExW -GetClassInfoW -GetClassLongA -GetClassLongW -GetClassNameA -GetClassNameW -GetClassWord -GetClientRect -GetClipCursor -GetClipboardData -GetClipboardFormatNameA -GetClipboardFormatNameW -GetClipboardOwner -GetClipboardSequenceNumber -GetClipboardViewer -GetComboBoxInfo -GetCursor -GetCursorInfo -GetCursorPos -GetDC -GetDCEx -GetDesktopWindow -GetDialogBaseUnits -GetDlgCtrlID -GetDlgItem -GetDlgItemInt -GetDlgItemTextA -GetDlgItemTextW -GetDoubleClickTime -GetFocus -GetForegroundWindow -GetGUIThreadInfo -GetGuiResources -GetIconInfo -GetInputDesktop -GetInputState -GetInternalWindowPos -GetKBCodePage -GetKeyNameTextA -GetKeyNameTextW -GetKeyState -GetKeyboardLayout -GetKeyboardLayoutList -GetKeyboardLayoutNameA -GetKeyboardLayoutNameW -GetKeyboardState -GetKeyboardType -GetLastActivePopup -GetListBoxInfo -GetMenu -GetMenuBarInfo -GetMenuCheckMarkDimensions -GetMenuContextHelpId -GetMenuDefaultItem -GetMenuInfo -GetMenuItemCount -GetMenuItemID -GetMenuItemInfoA -GetMenuItemInfoW -GetMenuItemRect -GetMenuState -GetMenuStringA -GetMenuStringW -GetMessageA -GetMessageExtraInfo -GetMessagePos -GetMessageTime -GetMessageW -GetMonitorInfoA -GetMonitorInfoW -GetMouseMovePoints -GetMouseMovePointsEx -GetNextDlgGroupItem -GetNextDlgTabItem -GetNextQueueWindow -GetOpenClipboardWindow -GetParent -GetPriorityClipboardFormat -GetProcessDefaultLayout -GetProcessWindowStation -GetPropA -GetPropW -GetQueueStatus -GetScrollBarInfo -GetScrollInfo -GetScrollPos -GetScrollRange -GetShellWindow -GetSubMenu -GetSysColor -GetSysColorBrush -GetSystemMenu -GetSystemMetrics -GetTabbedTextExtentA -GetTabbedTextExtentW -GetThreadDesktop -GetTitleBarInfo -GetTopWindow -GetUpdateRect -GetUpdateRgn -GetUserObjectInformationA -GetUserObjectInformationW -GetUserObjectSecurity -GetWindow -GetWindowContextHelpId -GetWindowDC -GetWindowInfo -GetWindowLongPtrA -GetWindowLongPtrW -SetWindowLongPtrA -SetWindowLongPtrW -GetWindowLongA -GetWindowLongW -GetWindowModuleFileNameA -GetWindowModuleFileNameW -GetWindowPlacement -GetWindowRect -GetWindowRgn -GetWindowTextA -GetWindowTextLengthA -GetWindowTextLengthW -GetWindowTextW -GetWindowThreadProcessId -GetWindowWord -GrayStringA -GrayStringW -HasSystemSleepStarted -HideCaret -HiliteMenuItem -IMPGetIMEA -IMPGetIMEW -IMPQueryIMEA -IMPQueryIMEW -IMPSetIMEA -IMPSetIMEW -ImpersonateDdeClientWindow -InSendMessage -InSendMessageEx -InflateRect -InitSharedTable -InitTask -InsertMenuA -InsertMenuItemA -InsertMenuItemW -InsertMenuW -InternalGetWindowText -IntersectRect -InvalidateRect -InvalidateRgn -InvertRect -IsCharAlphaA -IsCharAlphaNumericA -IsCharAlphaNumericW -IsCharAlphaW -IsCharLowerA -IsCharLowerW -IsCharUpperA -IsCharUpperW -IsChild -IsClipboardFormatAvailable -IsDialogMessage -IsDialogMessageA -IsDialogMessageW -IsDlgButtonChecked -IsHungThread -IsIconic -IsMenu -IsRectEmpty -IsWindow -IsWindowEnabled -IsWindowUnicode -IsWindowVisible -IsZoomed -KillTimer -LoadAcceleratorsA -LoadAcceleratorsW -LoadBitmapA -LoadBitmapW -LoadCursorA -LoadCursorFromFileA -LoadCursorFromFileW -LoadCursorW -LoadIconA -LoadIconW -LoadImageA -LoadImageW -LoadKeyboardLayoutA -LoadKeyboardLayoutW -LoadMenuA -LoadMenuIndirectA -LoadMenuIndirectW -LoadMenuW -LoadStringA -LoadStringW -LockSetForegroundWindow -LockWindowStation -LockWindowUpdate -LookupIconIdFromDirectory -LookupIconIdFromDirectoryEx -MapDialogRect -MapVirtualKeyA -MapVirtualKeyExA -MapVirtualKeyExW -MapVirtualKeyW -MapWindowPoints -MenuItemFromPoint -MessageBeep -MessageBoxA -MessageBoxExA -MessageBoxExW -MessageBoxIndirectA -MessageBoxIndirectW -MessageBoxW -ModifyAccess -ModifyMenuA -ModifyMenuW -MonitorFromPoint -MonitorFromRect -MonitorFromWindow -MoveWindow -MsgWaitForMultipleObjects -MsgWaitForMultipleObjectsEx -NotifyWinEvent -OemKeyScan -OemToCharA -OemToCharBuffA -OemToCharBuffW -OemToCharW -OffsetRect -OpenClipboard -OpenDesktopA -OpenDesktopW -OpenIcon -OpenInputDesktop -OpenWindowStationA -OpenWindowStationW -PackDDElParam -PaintDesktop -PeekMessageA -PeekMessageW -PlaySoundEvent -PostMessageA -PostMessageW -PostQuitMessage -PostThreadMessageA -PostThreadMessageW -PtInRect -RealChildWindowFromPoint -RealGetWindowClass -RedrawWindow -RegisterClassA -RegisterClassExA -RegisterClassExW -RegisterClassW -RegisterClipboardFormatA -RegisterClipboardFormatW -RegisterDeviceNotificationA -RegisterDeviceNotificationW -RegisterHotKey -RegisterLogonProcess -RegisterNetworkCapabilities -RegisterSystemThread -RegisterTasklist -RegisterWindowMessageA -RegisterWindowMessageW -ReleaseCapture -ReleaseDC -RemoveMenu -RemovePropA -RemovePropW -ReplyMessage -ReuseDDElParam -ScreenToClient -ScrollDC -ScrollWindow -ScrollWindowEx -SendDlgItemMessageA -SendDlgItemMessageW -SendIMEMessageExA -SendIMEMessageExW -SendInput -SendMessageA -SendMessageCallbackA -SendMessageCallbackW -SendMessageTimeoutA -SendMessageTimeoutW -SendMessageW -SendNotifyMessageA -SendNotifyMessageW -SetActiveWindow -SetCapture -SetCaretBlinkTime -SetCaretPos -SetClassLongA -SetClassLongW -SetClassWord -SetClipboardData -SetClipboardViewer -SetCursor -SetCursorPos -SetDebugErrorLevel -SetDeskWallpaper -SetDesktopBitmap -SetDlgItemInt -SetDlgItemTextA -SetDlgItemTextW -SetDoubleClickTime -SetFocus -SetForegroundWindow -SetInternalWindowPos -SetKeyboardState -SetLastErrorEx -SetLogonNotifyWindow -SetMenu -SetMenuContextHelpId -SetMenuDefaultItem -SetMenuInfo -SetMenuItemBitmaps -SetMenuItemInfoA -SetMenuItemInfoW -SetMessageExtraInfo -SetMessageQueue -SetParent -SetProcessDefaultLayout -SetProcessWindowStation -SetPropA -SetPropW -SetRect -SetRectEmpty -SetScrollInfo -SetScrollPos -SetScrollRange -SetShellWindow -SetSysColors -SetSysColorsTemp -SetSystemCursor -SetThreadDesktop -SetTimer -SetUserObjectInformationA -SetUserObjectInformationW -SetUserObjectSecurity -SetWinEventHook -SetWindowContextHelpId -SetWindowFullScreenState -SetWindowLongA -SetWindowLongW -SetWindowPlacement -SetWindowPos -SetWindowRgn -SetWindowTextA -SetWindowTextW -SetWindowWord -SetWindowsHookA -SetWindowsHookExA -SetWindowsHookExW -SetWindowsHookW -ShowCaret -ShowCursor -ShowOwnedPopups -ShowScrollBar -ShowWindow -ShowWindowAsync -SubtractRect -SwapMouseButton -SwitchDesktop -SwitchToThisWindow -SysErrorBox -SystemParametersInfoA -SystemParametersInfoW -TabbedTextOutA -TabbedTextOutW -TileChildWindows -TileWindows -ToAscii -ToAsciiEx -ToUnicode -ToUnicodeEx -TrackMouseEvent -TrackPopupMenu -TrackPopupMenuEx -TranslateAccelerator -TranslateAcceleratorA -TranslateAcceleratorW -TranslateMDISysAccel -TranslateMessage -UnhookWinEvent -UnhookWindowsHook -UnhookWindowsHookEx -UnionRect -UnloadKeyboardLayout -UnlockWindowStation -UnpackDDElParam -UnregisterClassA -UnregisterClassW -UnregisterDeviceNotification -UnregisterHotKey -UpdateWindow -UserClientDllInitialize -UserIsSystemResumeAutomatic -UserSetDeviceHoldState -UserSignalProc -UserTickleTimer -ValidateRect -ValidateRgn -VkKeyScanA -VkKeyScanExA -VkKeyScanExW -VkKeyScanW -WINNLSEnableIME -WINNLSGetEnableStatus -WINNLSGetIMEHotkey -WNDPROC_CALLBACK -WaitForInputIdle -WaitMessage -WinHelpA -WinHelpW -WinOldAppHackoMatic -WindowFromDC -WindowFromPoint -YieldTask -_SetProcessDefaultLayout -keybd_event -mouse_event -wsprintfA -wsprintfW -wvsprintfA -wvsprintfW +LIBRARY user32.dll + +EXPORTS +ActivateKeyboardLayout +AdjustWindowRect +AdjustWindowRectEx +AlignRects +AllowSetForegroundWindow +AnimateWindow +AnyPopup +AppendMenuA +AppendMenuW +ArrangeIconicWindows +AttachThreadInput +BeginDeferWindowPos +BeginPaint +BlockInput +BringWindowToTop +BroadcastSystemMessage +BroadcastSystemMessageA +BroadcastSystemMessageW +CalcChildScroll +CallMsgFilter +CallMsgFilterA +CallMsgFilterW +CallNextHookEx +CallWindowProcA +CallWindowProcW +CascadeChildWindows +CascadeWindows +ChangeClipboardChain +ChangeDisplaySettingsA +ChangeDisplaySettingsExA +ChangeDisplaySettingsExW +ChangeDisplaySettingsW +ChangeMenuA +ChangeMenuW +CharLowerA +CharLowerBuffA +CharLowerBuffW +CharLowerW +CharNextA +CharNextExA +CharNextExW +CharNextW +CharPrevA +CharPrevExA +CharPrevExW +CharPrevW +CharToOemA +CharToOemBuffA +CharToOemBuffW +CharToOemW +CharUpperA +CharUpperBuffA +CharUpperBuffW +CharUpperW +CheckDlgButton +CheckMenuItem +CheckMenuRadioItem +CheckRadioButton +ChildWindowFromPoint +ChildWindowFromPointEx +ClientThreadConnect +ClientToScreen +ClipCursor +CloseClipboard +CloseDesktop +CloseWindow +CloseWindowStation +CopyAcceleratorTableA +CopyAcceleratorTableW +CopyIcon +CopyImage +CopyRect +CountClipboardFormats +CreateAcceleratorTableA +CreateAcceleratorTableW +CreateCaret +CreateCursor +CreateDesktopA +CreateDesktopW +CreateDialogIndirectParamA +CreateDialogIndirectParamW +CreateDialogParamA +CreateDialogParamW +CreateIcon +CreateIconFromResource +CreateIconFromResourceEx +CreateIconIndirect +CreateMDIWindowA +CreateMDIWindowW +CreateMenu +CreatePopupMenu +CreateWindowExA +CreateWindowExW +CreateWindowStationA +CreateWindowStationW +DdeAbandonTransaction +DdeAccessData +DdeAddData +DdeClientTransaction +DdeCmpStringHandles +DdeConnect +DdeConnectList +DdeCreateDataHandle +DdeCreateStringHandleA +DdeCreateStringHandleW +DdeDisconnect +DdeDisconnectList +DdeEnableCallback +DdeFreeDataHandle +DdeFreeStringHandle +DdeGetData +DdeGetLastError +DdeImpersonateClient +DdeInitializeA +DdeInitializeW +DdeKeepStringHandle +DdeNameService +DdePostAdvise +DdeQueryConvInfo +DdeQueryNextServer +DdeQueryStringA +DdeQueryStringW +DdeReconnect +DdeSetQualityOfService +DdeSetUserHandle +DdeUnaccessData +DdeUninitialize +DefDlgProcA +DefDlgProcW +DefFrameProcA +DefFrameProcW +DefMDIChildProcA +DefMDIChildProcW +DefWindowProcA +DefWindowProcW +DeferWindowPos +DeleteMenu +DestroyAcceleratorTable +DestroyCaret +DestroyCursor +DestroyIcon +DestroyMenu +DestroyWindow +DialogBoxIndirectParamA +DialogBoxIndirectParamW +DialogBoxParamA +DialogBoxParamW +DispatchMessageA +DispatchMessageW +DlgDirListA +DlgDirListComboBoxA +DlgDirListComboBoxW +DlgDirListW +DlgDirSelectComboBoxExA +DlgDirSelectComboBoxExW +DlgDirSelectExA +DlgDirSelectExW +DragDetect +DragObject +DrawAnimatedRects +DrawCaption +DrawCaptionTempA +DrawCaptionTempW +DrawEdge +DrawFocusRect +DrawFrame +DrawFrameControl +DrawIcon +DrawIconEx +DrawMenuBar +DrawMenuBarTemp +DrawStateA +DrawStateW +DrawTextA +DrawTextExA +DrawTextExW +DrawTextW +EditWndProc +EmptyClipboard +EnableMenuItem +EnableScrollBar +EnableWindow +EndDeferWindowPos +EndDialog +EndMenu +EndPaint +EndTask +EnumChildWindows +EnumClipboardFormats +EnumDesktopWindows +EnumDesktopsA +EnumDesktopsW +EnumDisplayDevicesA +EnumDisplayDevicesW +EnumDisplayMonitors +EnumDisplaySettingsA +EnumDisplaySettingsExA +EnumDisplaySettingsExW +EnumDisplaySettingsW +EnumPropsA +EnumPropsExA +EnumPropsExW +EnumPropsW +EnumThreadWindows +EnumWindowStationsA +EnumWindowStationsW +EnumWindows +EqualRect +ExcludeUpdateRgn +ExitWindowsEx +FillRect +FindWindowA +FindWindowExA +FindWindowExW +FindWindowW +FlashWindow +FlashWindowEx +FrameRect +FreeDDElParam +GetActiveWindow +GetAltTabInfo +GetAncestor +GetAsyncKeyState +GetCapture +GetCaretBlinkTime +GetCaretPos +GetClassInfoA +GetClassInfoExA +GetClassInfoExW +GetClassInfoW +GetClassLongA +GetClassLongW +GetClassNameA +GetClassNameW +GetClassWord +GetClientRect +GetClipCursor +GetClipboardData +GetClipboardFormatNameA +GetClipboardFormatNameW +GetClipboardOwner +GetClipboardSequenceNumber +GetClipboardViewer +GetComboBoxInfo +GetCursor +GetCursorInfo +GetCursorPos +GetDC +GetDCEx +GetDesktopWindow +GetDialogBaseUnits +GetDlgCtrlID +GetDlgItem +GetDlgItemInt +GetDlgItemTextA +GetDlgItemTextW +GetDoubleClickTime +GetFocus +GetForegroundWindow +GetGUIThreadInfo +GetGuiResources +GetIconInfo +GetInputDesktop +GetInputState +GetInternalWindowPos +GetKBCodePage +GetKeyNameTextA +GetKeyNameTextW +GetKeyState +GetKeyboardLayout +GetKeyboardLayoutList +GetKeyboardLayoutNameA +GetKeyboardLayoutNameW +GetKeyboardState +GetKeyboardType +GetLastActivePopup +GetListBoxInfo +GetMenu +GetMenuBarInfo +GetMenuCheckMarkDimensions +GetMenuContextHelpId +GetMenuDefaultItem +GetMenuInfo +GetMenuItemCount +GetMenuItemID +GetMenuItemInfoA +GetMenuItemInfoW +GetMenuItemRect +GetMenuState +GetMenuStringA +GetMenuStringW +GetMessageA +GetMessageExtraInfo +GetMessagePos +GetMessageTime +GetMessageW +GetMonitorInfoA +GetMonitorInfoW +GetMouseMovePoints +GetMouseMovePointsEx +GetNextDlgGroupItem +GetNextDlgTabItem +GetNextQueueWindow +GetOpenClipboardWindow +GetParent +GetPriorityClipboardFormat +GetProcessDefaultLayout +GetProcessWindowStation +GetPropA +GetPropW +GetQueueStatus +GetScrollBarInfo +GetScrollInfo +GetScrollPos +GetScrollRange +GetShellWindow +GetSubMenu +GetSysColor +GetSysColorBrush +GetSystemMenu +GetSystemMetrics +GetTabbedTextExtentA +GetTabbedTextExtentW +GetThreadDesktop +GetTitleBarInfo +GetTopWindow +GetUpdateRect +GetUpdateRgn +GetUserObjectInformationA +GetUserObjectInformationW +GetUserObjectSecurity +GetWindow +GetWindowContextHelpId +GetWindowDC +GetWindowInfo +GetWindowLongPtrA +GetWindowLongPtrW +SetWindowLongPtrA +SetWindowLongPtrW +GetWindowLongA +GetWindowLongW +GetWindowModuleFileNameA +GetWindowModuleFileNameW +GetWindowPlacement +GetWindowRect +GetWindowRgn +GetWindowTextA +GetWindowTextLengthA +GetWindowTextLengthW +GetWindowTextW +GetWindowThreadProcessId +GetWindowWord +GrayStringA +GrayStringW +HasSystemSleepStarted +HideCaret +HiliteMenuItem +IMPGetIMEA +IMPGetIMEW +IMPQueryIMEA +IMPQueryIMEW +IMPSetIMEA +IMPSetIMEW +ImpersonateDdeClientWindow +InSendMessage +InSendMessageEx +InflateRect +InitSharedTable +InitTask +InsertMenuA +InsertMenuItemA +InsertMenuItemW +InsertMenuW +InternalGetWindowText +IntersectRect +InvalidateRect +InvalidateRgn +InvertRect +IsCharAlphaA +IsCharAlphaNumericA +IsCharAlphaNumericW +IsCharAlphaW +IsCharLowerA +IsCharLowerW +IsCharUpperA +IsCharUpperW +IsChild +IsClipboardFormatAvailable +IsDialogMessage +IsDialogMessageA +IsDialogMessageW +IsDlgButtonChecked +IsHungThread +IsIconic +IsMenu +IsRectEmpty +IsWindow +IsWindowEnabled +IsWindowUnicode +IsWindowVisible +IsZoomed +KillTimer +LoadAcceleratorsA +LoadAcceleratorsW +LoadBitmapA +LoadBitmapW +LoadCursorA +LoadCursorFromFileA +LoadCursorFromFileW +LoadCursorW +LoadIconA +LoadIconW +LoadImageA +LoadImageW +LoadKeyboardLayoutA +LoadKeyboardLayoutW +LoadMenuA +LoadMenuIndirectA +LoadMenuIndirectW +LoadMenuW +LoadStringA +LoadStringW +LockSetForegroundWindow +LockWindowStation +LockWindowUpdate +LookupIconIdFromDirectory +LookupIconIdFromDirectoryEx +MapDialogRect +MapVirtualKeyA +MapVirtualKeyExA +MapVirtualKeyExW +MapVirtualKeyW +MapWindowPoints +MenuItemFromPoint +MessageBeep +MessageBoxA +MessageBoxExA +MessageBoxExW +MessageBoxIndirectA +MessageBoxIndirectW +MessageBoxW +ModifyAccess +ModifyMenuA +ModifyMenuW +MonitorFromPoint +MonitorFromRect +MonitorFromWindow +MoveWindow +MsgWaitForMultipleObjects +MsgWaitForMultipleObjectsEx +NotifyWinEvent +OemKeyScan +OemToCharA +OemToCharBuffA +OemToCharBuffW +OemToCharW +OffsetRect +OpenClipboard +OpenDesktopA +OpenDesktopW +OpenIcon +OpenInputDesktop +OpenWindowStationA +OpenWindowStationW +PackDDElParam +PaintDesktop +PeekMessageA +PeekMessageW +PlaySoundEvent +PostMessageA +PostMessageW +PostQuitMessage +PostThreadMessageA +PostThreadMessageW +PtInRect +RealChildWindowFromPoint +RealGetWindowClass +RedrawWindow +RegisterClassA +RegisterClassExA +RegisterClassExW +RegisterClassW +RegisterClipboardFormatA +RegisterClipboardFormatW +RegisterDeviceNotificationA +RegisterDeviceNotificationW +RegisterHotKey +RegisterLogonProcess +RegisterNetworkCapabilities +RegisterSystemThread +RegisterTasklist +RegisterWindowMessageA +RegisterWindowMessageW +ReleaseCapture +ReleaseDC +RemoveMenu +RemovePropA +RemovePropW +ReplyMessage +ReuseDDElParam +ScreenToClient +ScrollDC +ScrollWindow +ScrollWindowEx +SendDlgItemMessageA +SendDlgItemMessageW +SendIMEMessageExA +SendIMEMessageExW +SendInput +SendMessageA +SendMessageCallbackA +SendMessageCallbackW +SendMessageTimeoutA +SendMessageTimeoutW +SendMessageW +SendNotifyMessageA +SendNotifyMessageW +SetActiveWindow +SetCapture +SetCaretBlinkTime +SetCaretPos +SetClassLongA +SetClassLongW +SetClassWord +SetClipboardData +SetClipboardViewer +SetCursor +SetCursorPos +SetDebugErrorLevel +SetDeskWallpaper +SetDesktopBitmap +SetDlgItemInt +SetDlgItemTextA +SetDlgItemTextW +SetDoubleClickTime +SetFocus +SetForegroundWindow +SetInternalWindowPos +SetKeyboardState +SetLastErrorEx +SetLogonNotifyWindow +SetMenu +SetMenuContextHelpId +SetMenuDefaultItem +SetMenuInfo +SetMenuItemBitmaps +SetMenuItemInfoA +SetMenuItemInfoW +SetMessageExtraInfo +SetMessageQueue +SetParent +SetProcessDefaultLayout +SetProcessWindowStation +SetPropA +SetPropW +SetRect +SetRectEmpty +SetScrollInfo +SetScrollPos +SetScrollRange +SetShellWindow +SetSysColors +SetSysColorsTemp +SetSystemCursor +SetThreadDesktop +SetTimer +SetUserObjectInformationA +SetUserObjectInformationW +SetUserObjectSecurity +SetWinEventHook +SetWindowContextHelpId +SetWindowFullScreenState +SetWindowLongA +SetWindowLongW +SetWindowPlacement +SetWindowPos +SetWindowRgn +SetWindowTextA +SetWindowTextW +SetWindowWord +SetWindowsHookA +SetWindowsHookExA +SetWindowsHookExW +SetWindowsHookW +ShowCaret +ShowCursor +ShowOwnedPopups +ShowScrollBar +ShowWindow +ShowWindowAsync +SubtractRect +SwapMouseButton +SwitchDesktop +SwitchToThisWindow +SysErrorBox +SystemParametersInfoA +SystemParametersInfoW +TabbedTextOutA +TabbedTextOutW +TileChildWindows +TileWindows +ToAscii +ToAsciiEx +ToUnicode +ToUnicodeEx +TrackMouseEvent +TrackPopupMenu +TrackPopupMenuEx +TranslateAccelerator +TranslateAcceleratorA +TranslateAcceleratorW +TranslateMDISysAccel +TranslateMessage +UnhookWinEvent +UnhookWindowsHook +UnhookWindowsHookEx +UnionRect +UnloadKeyboardLayout +UnlockWindowStation +UnpackDDElParam +UnregisterClassA +UnregisterClassW +UnregisterDeviceNotification +UnregisterHotKey +UpdateWindow +UserClientDllInitialize +UserIsSystemResumeAutomatic +UserSetDeviceHoldState +UserSignalProc +UserTickleTimer +ValidateRect +ValidateRgn +VkKeyScanA +VkKeyScanExA +VkKeyScanExW +VkKeyScanW +WINNLSEnableIME +WINNLSGetEnableStatus +WINNLSGetIMEHotkey +WNDPROC_CALLBACK +WaitForInputIdle +WaitMessage +WinHelpA +WinHelpW +WinOldAppHackoMatic +WindowFromDC +WindowFromPoint +YieldTask +_SetProcessDefaultLayout +keybd_event +mouse_event +wsprintfA +wsprintfW +wvsprintfA +wvsprintfW diff --git a/tcc/libtcc/libtcc.def b/tcc/libtcc/libtcc.def index ae5751e5..c4f357af 100644 --- a/tcc/libtcc/libtcc.def +++ b/tcc/libtcc/libtcc.def @@ -1,41 +1,41 @@ -LIBRARY libtcc.dll - -EXPORTS -_tcc_error -_tcc_error_noabort -_tcc_warning -tcc_add_file -tcc_add_include_path -tcc_add_library -tcc_add_library_err -tcc_add_library_path -tcc_add_symbol -tcc_add_sysinclude_path -tcc_basename -tcc_compile_string -tcc_define_symbol -tcc_delete -tcc_enter_state -tcc_exit_state -tcc_fileextension -tcc_free -tcc_get_dllexports -tcc_get_error_func -tcc_get_error_opaque -tcc_get_symbol -tcc_list_symbols -tcc_malloc -tcc_mallocz -tcc_new -tcc_output_file -tcc_parse_args -tcc_print_stats -tcc_realloc -tcc_relocate -tcc_run -tcc_set_error_func -tcc_set_lib_path -tcc_set_options -tcc_set_output_type -tcc_strdup -tcc_undefine_symbol +LIBRARY libtcc.dll + +EXPORTS +_tcc_error +_tcc_error_noabort +_tcc_warning +tcc_add_file +tcc_add_include_path +tcc_add_library +tcc_add_library_err +tcc_add_library_path +tcc_add_symbol +tcc_add_sysinclude_path +tcc_basename +tcc_compile_string +tcc_define_symbol +tcc_delete +tcc_enter_state +tcc_exit_state +tcc_fileextension +tcc_free +tcc_get_dllexports +tcc_get_error_func +tcc_get_error_opaque +tcc_get_symbol +tcc_list_symbols +tcc_malloc +tcc_mallocz +tcc_new +tcc_output_file +tcc_parse_args +tcc_print_stats +tcc_realloc +tcc_relocate +tcc_run +tcc_set_error_func +tcc_set_lib_path +tcc_set_options +tcc_set_output_type +tcc_strdup +tcc_undefine_symbol diff --git a/tcc/libtcc/libtcc.h b/tcc/libtcc/libtcc.h index 25d247a7..3c4e3bc2 100644 --- a/tcc/libtcc/libtcc.h +++ b/tcc/libtcc/libtcc.h @@ -1,111 +1,111 @@ -#ifndef LIBTCC_H -#define LIBTCC_H - -#ifndef LIBTCCAPI -# define LIBTCCAPI -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct TCCState; - -typedef struct TCCState TCCState; - -typedef void (*TCCErrorFunc)(void *opaque, const char *msg); - -/* create a new TCC compilation context */ -LIBTCCAPI TCCState *tcc_new(void); - -/* free a TCC compilation context */ -LIBTCCAPI void tcc_delete(TCCState *s); - -/* set CONFIG_TCCDIR at runtime */ -LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); - -/* set error/warning display callback */ -LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func); - -/* return error/warning callback */ -LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s); - -/* return error/warning callback opaque pointer */ -LIBTCCAPI void *tcc_get_error_opaque(TCCState *s); - -/* set options as from command line (multiple supported) */ -LIBTCCAPI void tcc_set_options(TCCState *s, const char *str); - -/*****************************/ -/* preprocessor */ - -/* add include path */ -LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname); - -/* add in system include path */ -LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname); - -/* define preprocessor symbol 'sym'. value can be NULL, sym can be "sym=val" */ -LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value); - -/* undefine preprocess symbol 'sym' */ -LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym); - -/*****************************/ -/* compiling */ - -/* add a file (C file, dll, object, library, ld script). Return -1 if error. */ -LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); - -/* compile a string containing a C source. Return -1 if error. */ -LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); - -/*****************************/ -/* linking commands */ - -/* set output type. MUST BE CALLED before any compilation */ -LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); -#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */ -#define TCC_OUTPUT_EXE 2 /* executable file */ -#define TCC_OUTPUT_DLL 3 /* dynamic library */ -#define TCC_OUTPUT_OBJ 4 /* object file */ -#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */ - -/* equivalent to -Lpath option */ -LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); - -/* the library name is the same as the argument of the '-l' option */ -LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname); - -/* add a symbol to the compiled program */ -LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val); - -/* output an executable, library or object file. DO NOT call - tcc_relocate() before. */ -LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename); - -/* link and run main() function and return its value. DO NOT call - tcc_relocate() before. */ -LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); - -/* do all relocations (needed before using tcc_get_symbol()) */ -LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); -/* possible values for 'ptr': - - TCC_RELOCATE_AUTO : Allocate and manage memory internally - - NULL : return required memory size for the step below - - memory address : copy code to memory passed by the caller - returns -1 if error. */ -#define TCC_RELOCATE_AUTO (void*)1 - -/* return symbol value or NULL if not found */ -LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); - -/* return symbol value or NULL if not found */ -LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, - void (*symbol_cb)(void *ctx, const char *name, const void *val)); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef LIBTCC_H +#define LIBTCC_H + +#ifndef LIBTCCAPI +# define LIBTCCAPI +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct TCCState; + +typedef struct TCCState TCCState; + +typedef void (*TCCErrorFunc)(void *opaque, const char *msg); + +/* create a new TCC compilation context */ +LIBTCCAPI TCCState *tcc_new(void); + +/* free a TCC compilation context */ +LIBTCCAPI void tcc_delete(TCCState *s); + +/* set CONFIG_TCCDIR at runtime */ +LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); + +/* set error/warning display callback */ +LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func); + +/* return error/warning callback */ +LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s); + +/* return error/warning callback opaque pointer */ +LIBTCCAPI void *tcc_get_error_opaque(TCCState *s); + +/* set options as from command line (multiple supported) */ +LIBTCCAPI void tcc_set_options(TCCState *s, const char *str); + +/*****************************/ +/* preprocessor */ + +/* add include path */ +LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname); + +/* add in system include path */ +LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname); + +/* define preprocessor symbol 'sym'. value can be NULL, sym can be "sym=val" */ +LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value); + +/* undefine preprocess symbol 'sym' */ +LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym); + +/*****************************/ +/* compiling */ + +/* add a file (C file, dll, object, library, ld script). Return -1 if error. */ +LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); + +/* compile a string containing a C source. Return -1 if error. */ +LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); + +/*****************************/ +/* linking commands */ + +/* set output type. MUST BE CALLED before any compilation */ +LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); +#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */ +#define TCC_OUTPUT_EXE 2 /* executable file */ +#define TCC_OUTPUT_DLL 3 /* dynamic library */ +#define TCC_OUTPUT_OBJ 4 /* object file */ +#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */ + +/* equivalent to -Lpath option */ +LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); + +/* the library name is the same as the argument of the '-l' option */ +LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname); + +/* add a symbol to the compiled program */ +LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val); + +/* output an executable, library or object file. DO NOT call + tcc_relocate() before. */ +LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename); + +/* link and run main() function and return its value. DO NOT call + tcc_relocate() before. */ +LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); + +/* do all relocations (needed before using tcc_get_symbol()) */ +LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); +/* possible values for 'ptr': + - TCC_RELOCATE_AUTO : Allocate and manage memory internally + - NULL : return required memory size for the step below + - memory address : copy code to memory passed by the caller + returns -1 if error. */ +#define TCC_RELOCATE_AUTO (void*)1 + +/* return symbol value or NULL if not found */ +LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); + +/* return symbol value or NULL if not found */ +LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, + void (*symbol_cb)(void *ctx, const char *name, const void *val)); + +#ifdef __cplusplus +} +#endif + +#endif From 7a452b0543f3f1ce82519492e8cceba9659f38a0 Mon Sep 17 00:00:00 2001 From: gxia0005 Date: Thu, 30 Apr 2026 15:02:27 +1000 Subject: [PATCH 7/9] Revert "renormalize files" This reverts commit 56f08f94a192b90175b52295593c2a7afd9eeed3. --- AMB Editor/RUN.bat | 14 +- AMB Editor/TODO | 20 +- AMB Editor/amb_editor.c | 4382 +- AMB Editor/amb_file.c | 3072 +- AMB Editor/details_window.c | 322 +- AMB Editor/hello_claude.txt | 46 +- AMB Editor/preview.c | 766 +- AMB Editor/wav_file.c | 258 +- AMB Editor/win32_selections.h | 312 +- Art/.gitignore | 48 +- Art/DayNight/.gitignore | 46 +- C3X.h | 4666 +- DayNight/civ3_city_lights.py | 1042 +- DayNight/civ3_day_night.py | 1892 +- DayNight/civ3_day_night_orig.py | 1202 +- DayNight/civ3_postprocess_pixels.py | 560 +- DayNight/find_least_used_colors.py | 196 +- DayNight/find_unused_palette_indexes.py | 214 +- DayNight/generate.sh | 416 +- DayNight/protected_pixels.py | 148 +- DayNight/swap_green_magenta_indices.py | 226 +- Ghidra scripts/Civ3TypesFromHeader.py | 600 +- Ghidra scripts/ExportProgForPython.py | 208 +- Ghidra scripts/ListReturnAddresses.py | 122 +- README.md | 554 +- Sound Test/BUILD_LINUX.sh | 2 +- civ_prog_objects.csv | 1928 +- correlator/CLAUDE.md | 198 +- correlator/correlator.py | 1568 +- default.c3x_config.ini | 2354 +- default.districts_config.txt | 942 +- default.districts_natural_wonders_config.txt | 556 +- default.districts_wonders_config.txt | 466 +- injected_code.c | 74228 +++++++++-------- lend/README.md | 62 +- lend/ld32.c | 160 +- lend/ld32.h | 508 +- tcc/include/_mingw.h | 328 +- tcc/include/assert.h | 124 +- tcc/include/conio.h | 818 +- tcc/include/ctype.h | 562 +- tcc/include/dir.h | 62 +- tcc/include/direct.h | 136 +- tcc/include/dirent.h | 270 +- tcc/include/dos.h | 110 +- tcc/include/errno.h | 150 +- tcc/include/excpt.h | 246 +- tcc/include/fcntl.h | 104 +- tcc/include/fenv.h | 216 +- tcc/include/float.h | 144 +- tcc/include/inttypes.h | 594 +- tcc/include/io.h | 836 +- tcc/include/iso646.h | 72 +- tcc/include/limits.h | 232 +- tcc/include/locale.h | 182 +- tcc/include/malloc.h | 362 +- tcc/include/math.h | 994 +- tcc/include/mem.h | 26 +- tcc/include/memory.h | 80 +- tcc/include/process.h | 352 +- tcc/include/sec_api/conio_s.h | 84 +- tcc/include/sec_api/crtdbg_s.h | 38 +- tcc/include/sec_api/io_s.h | 66 +- tcc/include/sec_api/mbstring_s.h | 104 +- tcc/include/sec_api/search_s.h | 50 +- tcc/include/sec_api/stdio_s.h | 290 +- tcc/include/sec_api/stdlib_s.h | 134 +- tcc/include/sec_api/stralign_s.h | 60 +- tcc/include/sec_api/string_s.h | 82 +- tcc/include/sec_api/sys/timeb_s.h | 68 +- tcc/include/sec_api/tchar_s.h | 532 +- tcc/include/sec_api/time_s.h | 122 +- tcc/include/sec_api/wchar_s.h | 256 +- tcc/include/setjmp.h | 320 +- tcc/include/share.h | 56 +- tcc/include/signal.h | 126 +- tcc/include/stdalign.h | 32 +- tcc/include/stdarg.h | 28 +- tcc/include/stdatomic.h | 250 +- tcc/include/stdbool.h | 22 +- tcc/include/stddef.h | 78 +- tcc/include/stdint.h | 424 +- tcc/include/stdio.h | 858 +- tcc/include/stdlib.h | 1160 +- tcc/include/stdnoreturn.h | 14 +- tcc/include/string.h | 328 +- tcc/include/sys/fcntl.h | 26 +- tcc/include/sys/file.h | 28 +- tcc/include/sys/locking.h | 60 +- tcc/include/sys/stat.h | 580 +- tcc/include/sys/time.h | 138 +- tcc/include/sys/timeb.h | 266 +- tcc/include/sys/types.h | 236 +- tcc/include/sys/unistd.h | 28 +- tcc/include/sys/utime.h | 292 +- tcc/include/tcc/tcc_libm.h | 1236 +- tcc/include/tccdefs.h | 568 +- tcc/include/tcclib.h | 160 +- tcc/include/tchar.h | 2204 +- tcc/include/tgmath.h | 178 +- tcc/include/time.h | 574 +- tcc/include/uchar.h | 66 +- tcc/include/vadefs.h | 22 +- tcc/include/values.h | 8 +- tcc/include/varargs.h | 24 +- tcc/include/wchar.h | 1746 +- tcc/include/wctype.h | 344 +- tcc/include/winapi/basetsd.h | 298 +- tcc/include/winapi/basetyps.h | 170 +- tcc/include/winapi/guiddef.h | 312 +- tcc/include/winapi/poppack.h | 16 +- tcc/include/winapi/pshpack1.h | 16 +- tcc/include/winapi/pshpack2.h | 16 +- tcc/include/winapi/pshpack4.h | 16 +- tcc/include/winapi/pshpack8.h | 16 +- tcc/include/winapi/qos.h | 144 +- tcc/include/winapi/winbase.h | 5902 +- tcc/include/winapi/wincon.h | 602 +- tcc/include/winapi/windef.h | 586 +- tcc/include/winapi/windows.h | 254 +- tcc/include/winapi/winerror.h | 6332 +- tcc/include/winapi/wingdi.h | 8160 +- tcc/include/winapi/winnls.h | 1556 +- tcc/include/winapi/winnt.h | 11670 +-- tcc/include/winapi/winreg.h | 544 +- tcc/include/winapi/winsock2.h | 2948 +- tcc/include/winapi/winuser.h | 11302 +-- tcc/include/winapi/winver.h | 320 +- tcc/include/winapi/ws2ipdef.h | 42 +- tcc/include/winapi/ws2tcpip.h | 782 +- tcc/lib/kernel32.def | 1540 +- tcc/lib/msvcrt.def | 2640 +- tcc/lib/user32.def | 1316 +- tcc/libtcc/libtcc.def | 82 +- tcc/libtcc/libtcc.h | 222 +- 135 files changed, 91738 insertions(+), 91736 deletions(-) diff --git a/AMB Editor/RUN.bat b/AMB Editor/RUN.bat index 83d7fa48..1f3c1caf 100644 --- a/AMB Editor/RUN.bat +++ b/AMB Editor/RUN.bat @@ -1,8 +1,8 @@ -@echo off - -REM See INSTALL.bat for explanation of this line -PUSHD "%~dp0" - -..\tcc\tcc.exe -m32 -run -lmsvcrt -luser32 -lkernel32 -ladvapi32 -lcomdlg32 amb_editor.c - +@echo off + +REM See INSTALL.bat for explanation of this line +PUSHD "%~dp0" + +..\tcc\tcc.exe -m32 -run -lmsvcrt -luser32 -lkernel32 -ladvapi32 -lcomdlg32 amb_editor.c + POPD \ No newline at end of file diff --git a/AMB Editor/TODO b/AMB Editor/TODO index 40b03198..974b1f0e 100644 --- a/AMB Editor/TODO +++ b/AMB Editor/TODO @@ -1,10 +1,10 @@ -- See if the Kmap params do anything useful - -Low priority: -- ArcherRun.amb is missing WAV file names for breath sounds. This is fixable. -- Add row on HopliteAttackA.amb doesn't work properly b/c of the orphan sound track -- Put asterisk in window title if there are unsaved changes -- Warning when you run multiple instances of the editor. Doing so breaks playing of previews. -- Option to create a "new" AMB file -- Consider moving all .c files into a source folder -- Consider adding a column with program numbers +- See if the Kmap params do anything useful + +Low priority: +- ArcherRun.amb is missing WAV file names for breath sounds. This is fixable. +- Add row on HopliteAttackA.amb doesn't work properly b/c of the orphan sound track +- Put asterisk in window title if there are unsaved changes +- Warning when you run multiple instances of the editor. Doing so breaks playing of previews. +- Option to create a "new" AMB file +- Consider moving all .c files into a source folder +- Consider adding a column with program numbers diff --git a/AMB Editor/amb_editor.c b/AMB Editor/amb_editor.c index a448315b..cdd05fda 100644 --- a/AMB Editor/amb_editor.c +++ b/AMB Editor/amb_editor.c @@ -1,2191 +1,2191 @@ -#include -#include -#include -#include -#include -#include - -// Defines the things we need from commctrl.h, commdlg.h, and any other headers that are not available -#include "win32_selections.h" - - - -#define PATH_BUFFER_SIZE 1024 -typedef char Path[PATH_BUFFER_SIZE]; - -Path g_iniCiv3InstallPath; -Path g_iniSoundDLLPath; -Path g_iniTempDirectory; - -void PathAppend(Path path, const char* append) -{ - size_t len = strlen(path); - - // No space at end of buffer - if (len >= PATH_BUFFER_SIZE - 1) - return; - - // Add backslash if needed - if (len > 0 && path[len - 1] != '\\') { - path[len] = '\\'; - path[len + 1] = '\0'; - len++; - } - - // Append the new part - strncpy(path + len, append, PATH_BUFFER_SIZE - len); - path[PATH_BUFFER_SIZE - 1] = '\0'; -} - -bool PathRemoveFileSpec(Path path) -{ - char* lastSlash = strrchr(path, '\\'); - if (lastSlash) { - *lastSlash = '\0'; - return true; - } - return false; -} - - - -#include "amb_file.c" -#include "preview.c" -#include "wav_file.c" - - - -// Forward declarations for ListView functions -void AddListViewColumn(HWND hListView, int index, char *title, int width); -int AddListViewItem(HWND hListView, int index, const char *text); -void SetListViewItemText(HWND hListView, int row, int col, const char *text, BOOL allowRepopulation); -void ClearListView(HWND hListView); -void PopulateAmbListView(void); -BOOL ApplyEditToAmbFile(HWND hwnd, int row, int col, const char *newText, char * outFormattedText, int formattedTextBufferSize); -BOOL IsValidInteger(const char *str); -BOOL GetWavFileDuration(const char* filePath, float* outDuration); -BOOL CheckWavFileExists(const char* wavFileName); -BOOL HasMissingWavFiles(char* missingFiles, int bufferSize); -void MatchDurationToWav(HWND hwndListView); -void LoadAmbFileWithDialog(HWND hwnd); -void SaveAmbFileDirectly(HWND hwnd); -void SaveAmbFileAs(HWND hwnd); -void UpdateOverallDuration(void); - -// Currently loaded AMB file -AmbFile g_ambFile = {0}; - -AmbFile g_fileSnapshots[100] = {0}; -int g_snapshotCount = 0, - g_redoCount = 0; - -void ClearFileSnapshots() -{ - memset(g_fileSnapshots, 0, sizeof g_fileSnapshots); - g_snapshotCount = g_redoCount = 0; -} - -// Saves a copy of the currently loaded file onto the stack of snapshots so any changes to the file can be reverted. If the stack is full, drops the -// oldest item. -void SnapshotCurrentFile() -{ - g_redoCount = 0; - - int snapshotCapacity = (sizeof g_fileSnapshots) / (sizeof g_fileSnapshots[0]); - if (g_snapshotCount == snapshotCapacity) { - memmove(&g_fileSnapshots[0], &g_fileSnapshots[1], (snapshotCapacity - 1) * (sizeof g_fileSnapshots[0])); - g_snapshotCount--; - } - - memcpy(&g_fileSnapshots[g_snapshotCount], &g_ambFile, sizeof(AmbFile)); - g_snapshotCount++; -} - -void Undo() -{ - static AmbFile tempAmb; - - if (g_snapshotCount > 0) { - // Swap most recent snapshot with the current file - memcpy(&tempAmb, &g_ambFile, sizeof(AmbFile)); - memcpy(&g_ambFile, &g_fileSnapshots[g_snapshotCount - 1], sizeof(AmbFile)); - memcpy(&g_fileSnapshots[g_snapshotCount - 1], &tempAmb, sizeof(AmbFile)); - - g_snapshotCount--; - g_redoCount++; - - PopulateAmbListView(); // Refresh the ListView to reflect changes - } else - MessageBeep(MB_ICONERROR); -} - -void Redo() -{ - static AmbFile tempAmb; - - if (g_redoCount > 0) { - // Swap oldest redo (stored one above the newest undo on the stack) with the current file - memcpy(&tempAmb, &g_fileSnapshots[g_snapshotCount], sizeof(AmbFile)); - memcpy(&g_fileSnapshots[g_snapshotCount], &g_ambFile, sizeof(AmbFile)); - memcpy(&g_ambFile, &tempAmb, sizeof(AmbFile)); - - g_snapshotCount++; - g_redoCount--; - - PopulateAmbListView(); // Refresh the ListView to reflect changes - } else - MessageBeep(MB_ICONERROR); -} - -// Function declarations -BOOL WINAPI GetOpenFileNameA(LPOPENFILENAMEA lpofn); -BOOL WINAPI GetSaveFileNameA(LPOPENFILENAMEA lpofn); - -// Menu IDs -#define IDM_FILE_OPEN 1001 -#define IDM_FILE_SAVE 1002 -#define IDM_FILE_SAVE_AS 1003 -#define IDM_FILE_DETAILS 1004 -#define IDM_FILE_EXIT 1005 -#define IDM_EDIT_UNDO 1006 -#define IDM_EDIT_REDO 1007 -#define IDM_EDIT_DELETE 1008 -#define IDM_EDIT_ADD 1009 -#define IDM_EDIT_MATCH_WAV 1010 -#define IDM_EDIT_PRUNE 1011 -#define IDM_HELP_ABOUT 1012 - -// Accelerator table for hotkeys -ACCEL g_accelTable[] = { - {FCONTROL | FVIRTKEY, 'O', IDM_FILE_OPEN}, // Ctrl+O - {FCONTROL | FVIRTKEY, 'S', IDM_FILE_SAVE}, // Ctrl+S - {FCONTROL | FVIRTKEY, 'Z', IDM_EDIT_UNDO}, // Ctrl+Z - {FCONTROL | FVIRTKEY, 'Y', IDM_EDIT_REDO}, // Ctrl+Y - {FVIRTKEY, VK_DELETE, IDM_EDIT_DELETE}, // Delete - {FVIRTKEY, VK_INSERT, IDM_EDIT_ADD} // Insert -}; - -// Control IDs -#define ID_PATH_EDIT 102 -#define ID_PLAY_BUTTON 103 -#define ID_STOP_BUTTON 104 -#define ID_AMB_LISTVIEW 105 - -// ListView Column Indices -typedef enum { - COL_TIME = 0, - COL_DURATION, - COL_WAV_FILE, - COL_SPEED_RANDOM, - COL_SPEED_MIN, - COL_SPEED_MAX, - COL_VOLUME_RANDOM, - COL_VOLUME_MIN, - COL_VOLUME_MAX -} ListViewColumn; - -// Track info structure to associate ListView rows with AMB data -typedef struct { - int trackIndex; // MIDI track index - int kmapIndex; // Index of Kmap chunk - int prgmIndex; // Index of Prgm chunk - int kmapItemIndex; // Index of item within Kmap -} AmbRowInfo; - -// Temporary structure for sorting rows by timestamp -typedef struct { - AmbRowInfo rowInfo; - float timestamp; - float duration; - char timeStr[32]; - char durationStr[32]; - char wavFileName[256]; - char speedMaxStr[32]; - char speedMinStr[32]; - char volumeMaxStr[32]; - char volumeMinStr[32]; - bool hasSpeedRandom; - bool hasVolumeRandom; -} RowData; - -// Comparison function for sorting rows by timestamp -int CompareRowsByTimestamp(const void *a, const void *b) -{ - const RowData *rowA = (const RowData *)a; - const RowData *rowB = (const RowData *)b; - - if (rowA->timestamp < rowB->timestamp) return -1; - if (rowA->timestamp > rowB->timestamp) return 1; - return 0; -} - -// Global variables -Path g_civ3MainPath = {0}; -HWND g_hwndPathEdit = NULL; -HWND g_hwndMainWindow = NULL; -HWND g_hwndPlayButton = NULL; -HWND g_hwndStopButton = NULL; -HWND g_hwndListView = NULL; -HWND g_hwndDurationLabel = NULL; -HBRUSH g_hBackgroundBrush = NULL; // Brush for window background color - -// Track info for each row in the ListView -AmbRowInfo g_rowInfo[MAX_SOUND_TRACKS]; -int g_rowCount = 0; // Number of rows in the ListView - -// Custom path helpers -bool PathFileExists(const Path path) -{ - DWORD attr = GetFileAttributes(path); - return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY)); -} - -bool PathIsDirectory(const Path path) -{ - DWORD attr = GetFileAttributes(path); - return (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)); -} - -// Function to browse for an AMB file to open -bool BrowseForAmbFile(HWND hwnd, Path filePath) -{ - // Initialize the OPENFILENAME structure - OPENFILENAMEA ofn; - ZeroMemory(&ofn, sizeof(ofn)); - - // Set up buffer - ZeroMemory(filePath, PATH_BUFFER_SIZE); - - // Setup the open file dialog - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hwnd; - ofn.lpstrFile = filePath; - ofn.nMaxFile = PATH_BUFFER_SIZE; - ofn.lpstrFilter = "AMB Files\0*.amb\0All Files\0*.*\0"; - ofn.nFilterIndex = 1; - ofn.lpstrTitle = "Select an AMB file to open"; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER; - - // Set initial directory to Civ3 install path if found - if (strlen(g_civ3MainPath) > 0) { - ofn.lpstrInitialDir = g_civ3MainPath; - } - - // Show the dialog and get result - return GetOpenFileNameA(&ofn); -} - -// Load an AMB file selected by the user -void LoadAmbFileWithDialog(HWND hwnd) -{ - Path ambFilePath = {0}; - - if (BrowseForAmbFile(hwnd, ambFilePath)) { - if (LoadAmbFile(ambFilePath, &g_ambFile) && g_hwndMainWindow != NULL) { - ClearFileSnapshots(); - - // Extract the filename part from the path - char *fileName = strrchr(ambFilePath, '\\'); - if (fileName) { - fileName++; // Skip past the backslash - } else { - fileName = (char*)ambFilePath; // No backslash found, use the whole path - } - - char windowTitle[100]; - snprintf(windowTitle, sizeof windowTitle, "%s - AMB Editor", fileName); - windowTitle[(sizeof windowTitle) - 1] = '\0'; - SetWindowText(g_hwndMainWindow, windowTitle); - - // Populate the ListView with the loaded AMB file data - PopulateAmbListView(); - } - } -} - -// Browse for a file to save -BOOL BrowseForSaveFile(HWND hwnd, Path filePath) -{ - OPENFILENAMEA ofn; - ZeroMemory(&ofn, sizeof(ofn)); - - // Initialize the filePath with current file if any - if (g_ambFile.filePath[0] != '\0') { - strcpy(filePath, g_ambFile.filePath); - } - - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hwnd; - ofn.lpstrFilter = "AMB Files (*.amb)\0*.amb\0All Files (*.*)\0*.*\0"; - ofn.lpstrFile = filePath; - ofn.nMaxFile = PATH_BUFFER_SIZE; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_EXPLORER; - ofn.lpstrDefExt = "amb"; - ofn.lpstrTitle = "Save AMB File"; - - return GetSaveFileNameA(&ofn); -} - -// Save AMB file directly (without dialog) -void SaveAmbFileDirectly(HWND hwnd) -{ - if (g_ambFile.filePath[0] == '\0') { - MessageBox(hwnd, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Try to save to the current file path - if (SaveAmbFile(&g_ambFile, g_ambFile.filePath)) { - // Success - file saved silently - return; - } - - // Failed to save (likely permissions issue) - fall back to Save As silently - SaveAmbFileAs(hwnd); -} - -// Save AMB file with Save As dialog -void SaveAmbFileAs(HWND hwnd) -{ - if (g_ambFile.filePath[0] == '\0') { - MessageBox(hwnd, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); - return; - } - - Path filePath = {0}; - - if (BrowseForSaveFile(hwnd, filePath)) { - // Try to save the AMB file - if (SaveAmbFile(&g_ambFile, filePath)) { - // Update the current file path to the new location - strcpy(g_ambFile.filePath, filePath); - - // Extract the filename part from the path and update window title - char *fileName = strrchr(filePath, '\\'); - if (fileName) { - fileName++; // Skip past the backslash - } else { - fileName = (char*)filePath; // No backslash found, use the whole path - } - - char windowTitle[100]; - snprintf(windowTitle, sizeof windowTitle, "%s - AMB Editor", fileName); - windowTitle[(sizeof windowTitle) - 1] = '\0'; - SetWindowText(g_hwndMainWindow, windowTitle); - } else { - MessageBox(hwnd, "Failed to save AMB file. Check file permissions and try again.", "Error", MB_OK | MB_ICONERROR); - } - } -} - -// Function to check if a directory is the main Civ3 folder -bool IsCiv3MainFolder(const Path folderPath) -{ - Path testPath; - - // Check for Art folder - strcpy(testPath, folderPath); - PathAppend(testPath, "Art"); - if (!PathIsDirectory(testPath)) { - return false; - } - - // Check for civ3PTW folder - strcpy(testPath, folderPath); - PathAppend(testPath, "civ3PTW"); - if (!PathIsDirectory(testPath)) { - return false; - } - - return true; -} - -// Function to search parent folders for Civ3 install -bool FindCiv3InstallBySearch(const Path startPath) -{ - Path testPath; - - // Start with working directory - strcpy(testPath, startPath); - - // Go up up to 10 parent directories - for (int i = 0; i < 10; i++) { - // Check current directory and subdirectories for main Civ3 folder - WIN32_FIND_DATA findData; - HANDLE hFind; - Path searchPath; - - strcpy(searchPath, testPath); - PathAppend(searchPath, "*"); - - hFind = FindFirstFile(searchPath, &findData); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && - strcmp(findData.cFileName, ".") != 0 && - strcmp(findData.cFileName, "..") != 0) { - - Path subDirPath; - strcpy(subDirPath, testPath); - PathAppend(subDirPath, findData.cFileName); - - if (IsCiv3MainFolder(subDirPath)) { - // Found main Civ3 directory - strcpy(g_civ3MainPath, subDirPath); - FindClose(hFind); - return true; - } - } - } while (FindNextFile(hFind, &findData)); - FindClose(hFind); - } - - // Move up a directory - if (!PathRemoveFileSpec(testPath)) { - break; // Cannot go up further - } - } - - return false; -} - -// Function to find Civ3 install from registry -bool FindCiv3InstallFromRegistry() -{ - HKEY hKey; - char regValue[PATH_BUFFER_SIZE]; - DWORD valueSize = sizeof(regValue); - DWORD valueType; - - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Infogrames Interactive\\Civilization III", - 0, KEY_READ, &hKey) == ERROR_SUCCESS) { - - if (RegQueryValueEx(hKey, "Install_Path", NULL, &valueType, - (LPBYTE)regValue, &valueSize) == ERROR_SUCCESS) { - - if (valueType == REG_SZ) { - regValue[(sizeof regValue) - 1] = '\0'; // RegQueryValueEx is not guaranteed to return null terminated strings - strcpy(g_civ3MainPath, regValue); - - RegCloseKey(hKey); - return true; - } - } - RegCloseKey(hKey); - } - - return false; -} - -bool GetSoundDLLPath(HWND hwnd, Path outSoundDLLPath) -{ - // First, check if INI has a sound.dll path specified - if (strlen(g_iniSoundDLLPath) > 0) { - strcpy(outSoundDLLPath, g_iniSoundDLLPath); - return true; - } - - // Otherwise, check if Conquests\sound.dll exists in the main Civ3 install - if (strlen(g_civ3MainPath) > 0) { - Path conquestsSoundPath; - strcpy(conquestsSoundPath, g_civ3MainPath); - PathAppend(conquestsSoundPath, "Conquests"); - PathAppend(conquestsSoundPath, "sound.dll"); - - if (PathFileExists(conquestsSoundPath)) { - strcpy(outSoundDLLPath, conquestsSoundPath); - return true; - } - } - - // If neither works, ask the user to locate sound.dll - int result = MessageBox(hwnd, - "Playing a preview requires sound.dll from your Civ 3 Conquests install. This could not be found automatically. " - "Would you like to locate sound.dll manually?", - "DLL not found", MB_YESNO | MB_ICONQUESTION); - if (result == IDYES) { - Path path = {0}; - - OPENFILENAMEA ofn; - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hwnd; - ofn.lpstrFile = path; - ofn.nMaxFile = PATH_BUFFER_SIZE; - ofn.lpstrFilter = "DLL Files\0*.dll\0All Files\0*.*\0"; - ofn.nFilterIndex = 1; - ofn.lpstrTitle = "Select sound.dll from your Civ 3 Conquests install"; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER; - - if (GetOpenFileNameA(&ofn)) { - if (PathFileExists(path)) { - strcpy(outSoundDLLPath, path); - return true; - } - } - } - - return false; -} - -// Find Civ3 installation using all available methods -bool FindCiv3Installation(HWND hwnd) -{ - Path cwdPath; - GetCurrentDirectory(PATH_BUFFER_SIZE, cwdPath); - - // Search parent folders first. If that doesn't work, check the registry. - if (FindCiv3InstallBySearch(cwdPath)) { - return true; - } else - return FindCiv3InstallFromRegistry(); -} - -// Create the play and stop buttons -void CreatePlaybackButtons(HWND hwnd) -{ - // Create Play button - g_hwndPlayButton = CreateWindow( - "BUTTON", - "Play Preview", - WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, - 20, 20, 100, 30, - hwnd, (HMENU)ID_PLAY_BUTTON, GetModuleHandle(NULL), NULL - ); - - // Create Stop button - g_hwndStopButton = CreateWindow( - "BUTTON", - "Stop", - WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, - 130, 20, 80, 30, - hwnd, (HMENU)ID_STOP_BUTTON, GetModuleHandle(NULL), NULL - ); -} - -// Add a column to the ListView -void AddListViewColumn(HWND hListView, int index, char *title, int width) -{ - LVCOLUMNA lvc = {0}; - lvc.mask = LVCF_TEXT | LVCF_WIDTH; - lvc.pszText = title; - lvc.cx = width; - - SendMessage(hListView, LVM_INSERTCOLUMN, index, (LPARAM)&lvc); -} - -// Add a row to the ListView -int AddListViewItem(HWND hListView, int index, const char *text) -{ - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = index; - lvi.iSubItem = 0; - lvi.pszText = (LPSTR)text; - - return SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&lvi); -} - -// Set text in a ListView cell -void SetListViewItemText(HWND hListView, int row, int col, const char *text, BOOL allowRepopulation) -{ - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = row; - lvi.iSubItem = col; - lvi.pszText = (LPSTR)text; - - SendMessage(hListView, LVM_SETITEM, 0, (LPARAM)&lvi); - - // Check if we need to repopulate when time changes - if (allowRepopulation && col == COL_TIME) { - PopulateAmbListView(); - } -} - -// Clear all items from the ListView -void ClearListView(HWND hListView) -{ - SendMessage(hListView, LVM_DELETEALLITEMS, 0, 0); -} - -// Check if a WAV file exists in the AMB file's directory -BOOL CheckWavFileExists(const char* wavFileName) -{ - if (!wavFileName || strlen(wavFileName) == 0 || g_ambFile.filePath[0] == '\0') { - return FALSE; - } - - // Construct full path to WAV file - Path wavFilePath; - strcpy(wavFilePath, g_ambFile.filePath); - PathRemoveFileSpec(wavFilePath); // Remove filename, keep directory - PathAppend(wavFilePath, wavFileName); - - // Check if file exists - return PathFileExists(wavFilePath); -} - -// Check if any WAV files are missing and return a list of missing files -BOOL HasMissingWavFiles(char* missingFiles, int bufferSize) -{ - if (!missingFiles || bufferSize == 0 || g_ambFile.filePath[0] == '\0') { - return FALSE; - } - - missingFiles[0] = '\0'; // Initialize as empty string - BOOL hasMissing = FALSE; - - // Check each row in the ListView for missing WAV files - for (int i = 0; i < g_rowCount; i++) { - AmbRowInfo *rowInfo = &g_rowInfo[i]; - if (rowInfo->kmapIndex >= 0 && rowInfo->kmapIndex < g_ambFile.kmapChunkCount && - rowInfo->kmapItemIndex >= 0 && rowInfo->kmapItemIndex < g_ambFile.kmapChunks[rowInfo->kmapIndex].itemCount) { - - KmapChunk *kmap = &g_ambFile.kmapChunks[rowInfo->kmapIndex]; - const char *wavFileName = kmap->items[rowInfo->kmapItemIndex].wavFileName; - - // Ignore empty WAV file names since those don't interfere with playback - if ((wavFileName[0] != '\0') && !CheckWavFileExists(wavFileName)) { - hasMissing = TRUE; - - // Add to missing files list if there's space - if (strlen(missingFiles) > 0) { - strncat(missingFiles, "\n", bufferSize - strlen(missingFiles) - 1); - } - strncat(missingFiles, wavFileName, bufferSize - strlen(missingFiles) - 1); - } - } - } - - return hasMissing; -} - -// Function to check if a string is a valid integer -BOOL IsValidInteger(const char *str) -{ - // Allow for a leading + or - sign - if (*str == '+' || *str == '-') { - str++; - } - - // Empty string or just a sign isn't a valid integer - if (*str == '\0') { - return FALSE; - } - - // Check that all characters are digits - while (*str) { - if (!isdigit(*str)) { - return FALSE; - } - str++; - } - - return TRUE; -} - - - - -// Defines void ShowAmbDetailsWindow(HWND hwndParent) -#include "details_window.c" - - - -// Returns the index of the Prgm chunk referred to by the given sound track. If the track does not validly refer to any Prgm, returns -1. In order for -// the track to be valid, the channel numbers of all events must match and specify a valid Prgm index and the program change event must specify the -// corresponding program number. -int GetReferencedPrgmIfValid(int trackIndex) -{ - SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; - - int prgmIndex = track->programChange.programNumber - 1; - - if ((prgmIndex < 0) || (prgmIndex >= g_ambFile.prgmChunkCount)) - return -1; - - for (int i = 0; i < track->controlChangeCount; i++) - if (track->controlChanges[i].channelNumber != prgmIndex) - return -1; - - if ((track->programChange.channelNumber != prgmIndex) || - (track->noteOn .channelNumber != prgmIndex) || - (track->noteOff .channelNumber != prgmIndex)) - return -1; - - return prgmIndex; -} - -// Populate the ListView with AMB file data -void PopulateAmbListView(void) -{ - if (g_hwndListView == NULL) { - MessageBox(NULL, "ListView control is NULL", "Debug", MB_OK); - return; - } - - // Clear any existing data - ClearListView(g_hwndListView); - - // Reset row info - g_rowCount = 0; - memset(g_rowInfo, 0, sizeof(g_rowInfo)); - - // Check if we have valid AMB data - if (g_ambFile.kmapChunkCount == 0 || g_ambFile.prgmChunkCount == 0 || g_ambFile.midi.trackCount == 0) { - MessageBox(NULL, "AMB file has missing data or is invalid", "Debug", MB_OK); - return; - } - - // Calculate seconds per tick for timing - float secondsPerTick = 0.0f; - if (g_ambFile.midi.ticksPerQuarterNote > 0) { - secondsPerTick = g_ambFile.midi.secondsPerQuarterNote / g_ambFile.midi.ticksPerQuarterNote; - } - - // Collect all row data before sorting - RowData rowData[MAX_SOUND_TRACKS]; - int rowDataCount = 0; - - // Process each MIDI sound track - int soundTrackCount = g_ambFile.midi.trackCount - 1; // Minus one to exclude the info track - for (int trackIndex = 0; trackIndex < soundTrackCount; trackIndex++) { - SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; - - int prgmIndex = GetReferencedPrgmIfValid(trackIndex); - if (prgmIndex < 0) - continue; // No valid Prgm, skip this track - PrgmChunk *matchingPrgm = &g_ambFile.prgmChunks[prgmIndex]; - - // Get the var name from the matching Prgm chunk - const char *varName = matchingPrgm->varName; - - // Find corresponding Kmap chunk with the same var name - KmapChunk *matchingKmap = NULL; - int kmapIndex = -1; - for (int i = 0; i < g_ambFile.kmapChunkCount; i++) { - if (strcmp(g_ambFile.kmapChunks[i].varName, varName) == 0) { - matchingKmap = &g_ambFile.kmapChunks[i]; - kmapIndex = i; - break; - } - } - - if (matchingKmap == NULL || matchingKmap->itemCount == 0) { - continue; // Skip if no matching Kmap found or no items in Kmap - } - - float timestamp = track->deltaTimeNoteOn * secondsPerTick; - float duration = track->deltaTimeNoteOff * secondsPerTick; - - // Check flags for randomization settings (LSB = speed random, bit 1 = volume random) - bool hasSpeedRandom = (matchingPrgm->flags & 0x01) != 0; - bool hasVolumeRandom = (matchingPrgm->flags & 0x02) != 0; - - // For each item in the kmap (usually just one WAV file per track) - for (int j = 0; j < matchingKmap->itemCount; j++) { - if (rowDataCount >= MAX_SOUND_TRACKS) { - break; // Prevent overflow - } - - // Collect row data - RowData *row = &rowData[rowDataCount]; - row->rowInfo.trackIndex = trackIndex; - row->rowInfo.kmapIndex = kmapIndex; - row->rowInfo.prgmIndex = prgmIndex; - row->rowInfo.kmapItemIndex = j; - row->timestamp = timestamp; - row->duration = duration; - row->hasSpeedRandom = hasSpeedRandom; - row->hasVolumeRandom = hasVolumeRandom; - - // Format strings - snprintf(row->timeStr, sizeof(row->timeStr), "%04.3f", timestamp); - snprintf(row->durationStr, sizeof(row->durationStr), "%04.3f", duration); - strncpy(row->wavFileName, matchingKmap->items[j].wavFileName, sizeof(row->wavFileName) - 1); - row->wavFileName[sizeof(row->wavFileName) - 1] = '\0'; - snprintf(row->speedMaxStr, sizeof(row->speedMaxStr), "%d", matchingPrgm->maxRandomSpeed); - snprintf(row->speedMinStr, sizeof(row->speedMinStr), "%d", matchingPrgm->minRandomSpeed); - snprintf(row->volumeMaxStr, sizeof(row->volumeMaxStr), "%d", matchingPrgm->maxRandomVolume); - snprintf(row->volumeMinStr, sizeof(row->volumeMinStr), "%d", matchingPrgm->minRandomVolume); - - rowDataCount++; - } - } - - // Sort rows by timestamp - qsort(rowData, rowDataCount, sizeof(RowData), CompareRowsByTimestamp); - - // Add sorted rows to ListView - for (int i = 0; i < rowDataCount; i++) { - RowData *row = &rowData[i]; - - // Add the item to the ListView - int listRow = AddListViewItem(g_hwndListView, 0x7FFFFFFF, row->timeStr); - if (listRow >= 0) { - // Store the track info for this row - g_rowInfo[g_rowCount] = row->rowInfo; - g_rowCount++; - - // Set all the column values - SetListViewItemText(g_hwndListView, listRow, COL_DURATION, row->durationStr, FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_WAV_FILE, row->wavFileName, FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_SPEED_RANDOM, row->hasSpeedRandom ? "Yes" : "No", FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_SPEED_MIN, row->speedMinStr, FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_SPEED_MAX, row->speedMaxStr, FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_RANDOM, row->hasVolumeRandom ? "Yes" : "No", FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_MIN, row->volumeMinStr, FALSE); - SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_MAX, row->volumeMaxStr, FALSE); - } - } - - // Update the overall duration display - UpdateOverallDuration(); -} - -// Handle the beginning of a ListView label edit -BOOL HandleBeginLabelEdit(HWND hwnd, NMLVDISPINFOA *pInfo) -{ - // You can reject edits for specific columns or rows if needed - // For now, allow editing all cells - return TRUE; // Return TRUE to allow the edit, FALSE to prevent it -} - -// Apply an edit to the AMB file data structure. Returns TRUE if the edit was accepted or FALSE if it was invalid. If the edit was accepted, the new -// text is written to outFormattedText in a way that is consistent with the usual format of the ListView display (e.g. float fields are formatted -// to 3 decimal places). If the new text exactly matches the current cell text, the edit is accepted but no snapshot is taken and no AMB data is modified. -// outFormattedText must not be NULL and formattedTextBufferSize must be at least 1. -BOOL ApplyEditToAmbFile(HWND hwnd, int row, int col, const char *newText, char * outFormattedText, int formattedTextBufferSize) -{ - // Make sure we have valid row info - if (row >= g_rowCount) { - MessageBox(hwnd, "Invalid row index", "Error", MB_OK | MB_ICONERROR); - return FALSE; - } - - // Get the track information for this row - AmbRowInfo *rowInfo = &g_rowInfo[row]; - int trackIndex = rowInfo->trackIndex; - int kmapIndex = rowInfo->kmapIndex; - int prgmIndex = rowInfo->prgmIndex; - int kmapItemIndex = rowInfo->kmapItemIndex; - - // Check if indices are valid - if (trackIndex < 0 || trackIndex >= g_ambFile.midi.trackCount || - kmapIndex < 0 || kmapIndex >= g_ambFile.kmapChunkCount || - prgmIndex < 0 || prgmIndex >= g_ambFile.prgmChunkCount || - kmapItemIndex < 0 || kmapItemIndex >= g_ambFile.kmapChunks[kmapIndex].itemCount) { - - MessageBox(hwnd, "Invalid track indices", "Error", MB_OK | MB_ICONERROR); - return FALSE; - } - - // Check if new text matches the current value in the cell - if so, accept without changing anything - char currentText[256] = {0}; - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = row; - lvi.iSubItem = col; - lvi.pszText = currentText; - lvi.cchTextMax = sizeof(currentText); - SendMessage(g_hwndListView, LVM_GETITEMTEXT, row, (LPARAM)&lvi); - - if (strcmp(newText, currentText) == 0) { - // Text unchanged - accept edit but don't modify data or take snapshot - strncpy(outFormattedText, newText, formattedTextBufferSize); - outFormattedText[formattedTextBufferSize - 1] = '\0'; - return TRUE; - } - - // Get references to the actual AMB data structures - PrgmChunk *prgm = &g_ambFile.prgmChunks[prgmIndex]; - KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; - - // Update the appropriate field based on the column that was edited - BOOL newTextIsValid = TRUE; - switch (col) { - case COL_TIME: - { - char * afterParsing; - float newTime = strtod(newText, &afterParsing); - if (afterParsing != newText) { - SnapshotCurrentFile(); - - float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; - g_ambFile.midi.soundTracks[trackIndex].deltaTimeNoteOn = round(newTime * ticksPerSecond); - - snprintf(outFormattedText, formattedTextBufferSize, "%04.3f", newTime); - - // Update overall duration since timestamp changed - UpdateOverallDuration(); - - } else { - newTextIsValid = FALSE; - } - } - break; - - case COL_DURATION: - { - char * afterParsing; - float newDuration = strtod(newText, &afterParsing); - if (afterParsing != newText) { - SnapshotCurrentFile(); - - float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; - g_ambFile.midi.soundTracks[trackIndex].deltaTimeNoteOff = round(newDuration * ticksPerSecond); - - snprintf(outFormattedText, formattedTextBufferSize, "%04.3f", newDuration); - - // Update overall duration since duration changed - UpdateOverallDuration(); - - } else { - newTextIsValid = FALSE; - } - } - break; - - case COL_WAV_FILE: // WAV filename - // Reject the edit if the new text contains a slash - if ((strchr(newText, '\\') == NULL) && (strchr(newText, '/') == NULL)) { - SnapshotCurrentFile(); - - // Write new text to kmap item - strncpy(kmap->items[kmapItemIndex].wavFileName, newText, sizeof(kmap->items[kmapItemIndex].wavFileName) - 1); - kmap->items[kmapItemIndex].wavFileName[sizeof(kmap->items[kmapItemIndex].wavFileName) - 1] = '\0'; - - // Update Kmap size - kmap->size = ComputeKmapChunkSize(kmap); - - // Write new text to formatted output - strncpy(outFormattedText, newText, formattedTextBufferSize); - } else { - newTextIsValid = FALSE; - } - break; - - case COL_SPEED_RANDOM: // Speed Random flag - { - if (strcmp(newText, "Yes") == 0 || strcmp(newText, "No") == 0) { - SnapshotCurrentFile(); - - if (strcmp(newText, "Yes") == 0) { - prgm->flags |= 0x01; // Set bit 0 - } else { - prgm->flags &= ~0x01; // Clear bit 0 - } - - strncpy(outFormattedText, (prgm->flags & 0x01) ? "Yes" : "No", formattedTextBufferSize); - } else { - newTextIsValid = FALSE; - } - } - break; - - case COL_SPEED_MIN: // Speed Min - if (IsValidInteger(newText)) { - SnapshotCurrentFile(); - prgm->minRandomSpeed = atoi(newText); - snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->minRandomSpeed); - } else { - newTextIsValid = FALSE; - } - break; - - case COL_SPEED_MAX: // Speed Max - if (IsValidInteger(newText)) { - SnapshotCurrentFile(); - prgm->maxRandomSpeed = atoi(newText); - snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->maxRandomSpeed); - } else { - newTextIsValid = FALSE; - } - break; - - case COL_VOLUME_RANDOM: // Volume Random flag - { - if (strcmp(newText, "Yes") == 0 || strcmp(newText, "No") == 0) { - SnapshotCurrentFile(); - - if (strcmp(newText, "Yes") == 0) { - prgm->flags |= 0x02; // Set bit 1 - } else { - prgm->flags &= ~0x02; // Clear bit 1 - } - - strncpy(outFormattedText, (prgm->flags & 0x02) ? "Yes" : "No", formattedTextBufferSize); - } else { - newTextIsValid = FALSE; - } - } - break; - - case COL_VOLUME_MIN: // Volume Min - if (IsValidInteger(newText)) { - SnapshotCurrentFile(); - prgm->minRandomVolume = atoi(newText); - snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->minRandomVolume); - } else { - newTextIsValid = FALSE; - } - break; - - case COL_VOLUME_MAX: // Volume Max - if (IsValidInteger(newText)) { - SnapshotCurrentFile(); - prgm->maxRandomVolume = atoi(newText); - snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->maxRandomVolume); - } else { - newTextIsValid = FALSE; - } - break; - } - - // Play error beep if new text didn't validate. If it did that means we wrote something to outFormattedText so make sure it's null terminated. - if (! newTextIsValid) - MessageBeep(MB_ICONERROR); - else - outFormattedText[formattedTextBufferSize - 1] = '\0'; - - return newTextIsValid; -} - -void DeleteKmapChunk(int kmapIndex) -{ - // Shift all Kmap chunks after this one forward - for (int i = kmapIndex; i < g_ambFile.kmapChunkCount - 1; i++) { - memcpy(&g_ambFile.kmapChunks[i], &g_ambFile.kmapChunks[i + 1], sizeof(KmapChunk)); - } - g_ambFile.kmapChunkCount--; -} - -void DeletePrgmChunk(int prgmIndex) -{ - // Shift all Prgm chunks after this one forward - for (int i = prgmIndex; i < g_ambFile.prgmChunkCount - 1; i++) { - memcpy(&g_ambFile.prgmChunks[i], &g_ambFile.prgmChunks[i + 1], sizeof(PrgmChunk)); - } - g_ambFile.prgmChunkCount--; - - // Update the number field of any remaining Prgm chunks - they are 1-based - for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { - g_ambFile.prgmChunks[i].number = i + 1; - } - - // Update channelNumber in all MIDI sound tracks for any that reference - // Prgm chunks with indices greater than the one we deleted - for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track - SoundTrack *track = &g_ambFile.midi.soundTracks[i]; - - // Check all control change events - for (int j = 0; j < track->controlChangeCount; j++) { - if (track->controlChanges[j].channelNumber > prgmIndex) { - track->controlChanges[j].channelNumber--; - } - } - - // Check program change event - if (track->programChange.channelNumber > prgmIndex) { - track->programChange.channelNumber--; - } - - // Update programNumber if it references deleted program or those after it - // Note: programNumbers are 1-based (matching the Prgm number field) - if (track->programChange.programNumber == prgmIndex + 1) { - // This is referencing the deleted program - we'd need to update it - // to a valid program or potentially disable this track - // For now, if there are other programs, use the first available one - if (g_ambFile.prgmChunkCount > 0) { - track->programChange.programNumber = 1; // Use first available program (1-based) - } - } - else if (track->programChange.programNumber > prgmIndex + 1) { - // This references a program that got shifted down, so update the index - track->programChange.programNumber--; - } - - // Check note on event - if (track->noteOn.channelNumber > prgmIndex) { - track->noteOn.channelNumber--; - } - - // Check note off event - if (track->noteOff.channelNumber > prgmIndex) { - track->noteOff.channelNumber--; - } - } -} - -void DeleteSoundTrack(int trackIndex) -{ - for (int i = trackIndex; i < g_ambFile.midi.trackCount - 2; i++) { // -2 because we skip info track (0) and want to leave room for the last valid track - memcpy(&g_ambFile.midi.soundTracks[i], &g_ambFile.midi.soundTracks[i + 1], sizeof(SoundTrack)); - } - g_ambFile.midi.trackCount--; -} - -void DeleteRow(int row) -{ - // If no file loaded or row is invalid, do nothing - if (g_ambFile.filePath[0] == '\0' || row < 0 || row >= g_rowCount) { - MessageBox(NULL, "Invalid row or no AMB file loaded", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Get the references to the chunks and tracks we need to work with - AmbRowInfo *rowInfo = &g_rowInfo[row]; - int trackIndex = rowInfo->trackIndex; - int kmapIndex = rowInfo->kmapIndex; - int prgmIndex = rowInfo->prgmIndex; - - // Take a snapshot before making changes - SnapshotCurrentFile(); - - // First, check if the Kmap chunk is referenced by other Prgm chunks - KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; - const char *kmapVarName = kmap->varName; - int kmapReferenceCount = 0; - - for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { - if (strcmp(g_ambFile.prgmChunks[i].varName, kmapVarName) == 0) { - kmapReferenceCount++; - } - } - - // Delete the Kmap chunk if it's only referenced by the Prgm we're deleting - if (kmapReferenceCount <= 1) { - DeleteKmapChunk(kmapIndex); - } - - // Next, check if the Prgm chunk is referenced by other MIDI tracks - int prgmReferenceCount = 0; - for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track - if (GetReferencedPrgmIfValid(i) == prgmIndex) - prgmReferenceCount++; - } - - // Delete the Prgm chunk if it's only referenced by the track we're deleting - if (prgmReferenceCount <= 1) { - DeletePrgmChunk(prgmIndex); - } - - // Delete the MIDI track - DeleteSoundTrack(trackIndex); - - // Refresh the ListView to show updated AMB data - PopulateAmbListView(); -} - -void AddRow() -{ - // If no file is loaded or we're already at the limit of how many sound tracks, prgm chunks, or kmap chunks we can have one file, report an - // error then return. - if (g_ambFile.filePath[0] == '\0') { - MessageBox(NULL, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); - return; - } - - if (g_ambFile.kmapChunkCount >= MAX_CHUNKS) { - MessageBox(NULL, "Cannot add more rows: Maximum number of Kmap chunks reached.", "Error", MB_OK | MB_ICONERROR); - return; - } - - if (g_ambFile.prgmChunkCount >= MAX_CHUNKS) { - MessageBox(NULL, "Cannot add more rows: Maximum number of Prgm chunks reached.", "Error", MB_OK | MB_ICONERROR); - return; - } - - if (g_ambFile.midi.trackCount >= MAX_SOUND_TRACKS + 1) { // +1 because first track is info track - MessageBox(NULL, "Cannot add more rows: Maximum number of sound tracks reached.", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Snapshot file - SnapshotCurrentFile(); - - // Find a unique name - char uniqueName[32]; - int nameCounter = 1; - bool nameIsUnique; - - do { - snprintf(uniqueName, sizeof(uniqueName), "NewTrack%d", nameCounter++); - nameIsUnique = true; - - // Check if this name is already used as a track name - for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track - if (strcmp(g_ambFile.midi.soundTracks[i].trackName.name, uniqueName) == 0) { - nameIsUnique = false; - break; - } - } - - // Check if this name is already used as a var name or effect name - if (nameIsUnique) { - for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { - if (strcmp(g_ambFile.prgmChunks[i].varName, uniqueName) == 0 || - strcmp(g_ambFile.prgmChunks[i].effectName, uniqueName) == 0) { - nameIsUnique = false; - break; - } - } - } - - // Check if this name is already used as a kmap var name - if (nameIsUnique) { - for (int i = 0; i < g_ambFile.kmapChunkCount; i++) { - if (strcmp(g_ambFile.kmapChunks[i].varName, uniqueName) == 0) { - nameIsUnique = false; - break; - } - } - } - } while (!nameIsUnique && nameCounter < 1000); // Prevent infinite loop - - if (!nameIsUnique) { - MessageBox(NULL, "Failed to generate a unique name for new row.", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Create a Kmap chunk - int kmapIndex = g_ambFile.kmapChunkCount; - KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; - - // Initialize the Kmap chunk - memset(kmap, 0, sizeof(KmapChunk)); - - kmap->flags = 2; // Standard flags value in Civ3 AMBs - kmap->itemCount = 1; - kmap->itemSize = 12; - - // Set the varName to our unique name - strcpy(kmap->varName, uniqueName); - - // Initialize the Kmap item - static const unsigned char kmapItemData[12] = { 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }; - memcpy(kmap->items[0].data, kmapItemData, 12); - strcpy(kmap->items[0].wavFileName, "<.wav file name>"); - - // Calculate the size of the Kmap chunk - kmap->size = ComputeKmapChunkSize(kmap); - - // Increment the Kmap count - g_ambFile.kmapChunkCount++; - - // Create a Prgm chunk - int prgmIndex = g_ambFile.prgmChunkCount; - PrgmChunk *prgm = &g_ambFile.prgmChunks[prgmIndex]; - - // Initialize the Prgm chunk - memset(prgm, 0, sizeof(PrgmChunk)); - - // Fill in names and set number (1-based) - strcpy(prgm->effectName, uniqueName); - strcpy(prgm->varName, uniqueName); - prgm->number = prgmIndex + 1; - - // Calculate the size of the Prgm chunk - prgm->size = ComputePrgmChunkSize(prgm); - - // Increment the Prgm count - g_ambFile.prgmChunkCount++; - - // Create a sound track - int trackIndex = g_ambFile.midi.trackCount - 1; // Index for the new track (after info track) - SoundTrack *track = &g_ambFile.midi.soundTracks[trackIndex]; - - // Initialize the sound track - memset(track, 0, sizeof(SoundTrack)); - - // Set track name - track->deltaTimeTrackName = 0; - strcpy(track->trackName.name, uniqueName); - - // Add one control change event - track->controlChangeCount = 1; - track->deltaTimeControlChanges[0] = 0; - track->controlChanges[0].channelNumber = prgmIndex; // 0-based index - track->controlChanges[0].controllerNumber = 32; - track->controlChanges[0].value = 0; - - // Set program change event - track->deltaTimeProgramChange = 0; - track->programChange.channelNumber = prgmIndex; // 0-based index - track->programChange.programNumber = prgmIndex + 1; // 1-based number - - // Find a unique key for the note on/off events - int keyValue = 60; // Start at middle C - bool keyIsUnique; - - do { - keyIsUnique = true; - - // Check if this key is already used in any other track - for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track - if (i != trackIndex && g_ambFile.midi.soundTracks[i].noteOn.key == keyValue) { - keyIsUnique = false; - keyValue++; - break; - } - } - } while (!keyIsUnique && keyValue < 127); - - // Set note on event - track->deltaTimeNoteOn = 0; - track->noteOn.channelNumber = prgmIndex; // 0-based index - track->noteOn.key = keyValue; - track->noteOn.velocity = 64; // Medium velocity - - // Set note off event - one second after note on - float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; - track->deltaTimeNoteOff = (int)ticksPerSecond; // 1 second duration - track->noteOff.channelNumber = prgmIndex; // 0-based index - track->noteOff.key = keyValue; - track->noteOff.velocity = 64; // Same as note on - - // Set end of track - track->deltaTimeEndOfTrack = 0; - - // Calculate the size of the sound track - track->size = ComputeSoundTrackSize(track); - - // Increment the track count - g_ambFile.midi.trackCount++; - - // Refresh the ListView - PopulateAmbListView(); -} - -void Prune() -{ - if (g_ambFile.filePath[0] == '\0') { - MessageBox(NULL, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Make sure the ListView is up to date. We're going to delete any Kmap or Prgm chunks and any sound tracks that don't appear in it. - PopulateAmbListView(); - - int unneededKmapCount = 0; - int unneededPrgmCount = 0; - int unneededTrackCount = 0; - bool tookSnapshot = false; - - for (int kmapIndex = g_ambFile.kmapChunkCount - 1; kmapIndex >= 0; kmapIndex--) { - bool inAnyRow = false; - for (int i = 0; i < g_rowCount; i++) { - if (g_rowInfo[i].kmapIndex == kmapIndex) { - inAnyRow = true; - break; - } - } - if (! inAnyRow) { - if (! tookSnapshot) { - SnapshotCurrentFile(); - tookSnapshot = true; - } - DeleteKmapChunk(kmapIndex); - unneededKmapCount++; - } - } - - for (int prgmIndex = g_ambFile.prgmChunkCount - 1; prgmIndex >= 0; prgmIndex--) { - bool inAnyRow = false; - for (int i = 0; i < g_rowCount; i++) { - if (g_rowInfo[i].prgmIndex == prgmIndex) { - inAnyRow = true; - break; - } - } - if (! inAnyRow) { - if (! tookSnapshot) { - SnapshotCurrentFile(); - tookSnapshot = true; - } - DeletePrgmChunk(prgmIndex); - unneededPrgmCount++; - } - } - - for (int trackIndex = g_ambFile.midi.trackCount - 2; trackIndex >= 0; trackIndex--) { // Skip info track - bool inAnyRow = false; - for (int i = 0; i < g_rowCount; i++) { - if (g_rowInfo[i].trackIndex == trackIndex) { - inAnyRow = true; - break; - } - } - if (! inAnyRow) { - if (! tookSnapshot) { - SnapshotCurrentFile(); - tookSnapshot = true; - } - DeleteSoundTrack(trackIndex); - unneededTrackCount++; - } - } - - if ((unneededKmapCount == 0) && (unneededPrgmCount == 0) && (unneededTrackCount == 0)) { - MessageBox(NULL, "The AMB data has no superfluous parts.", "Nothing to do", MB_OK | MB_ICONINFORMATION); - } else { - char msg[300] = {0}; - snprintf (msg, (sizeof msg) - 1, "Deleted %d unused Kmap chunk%s, %d unused Prgm chunk%s, and %d unused or invalid MIDI track%s.", - unneededKmapCount , unneededKmapCount == 1 ? "" : "s", - unneededPrgmCount , unneededPrgmCount == 1 ? "" : "s", - unneededTrackCount, unneededTrackCount == 1 ? "" : "s"); - MessageBox(NULL, msg, "Pruning results", MB_OK | MB_ICONINFORMATION); - - PopulateAmbListView(); - } -} - -// Handle the end of a ListView label edit -BOOL HandleEndLabelEdit(HWND hwnd, NMLVDISPINFOA *pInfo) -{ - // Check if the edit was cancelled - if (pInfo->item.pszText == NULL) { - return FALSE; // Edit was cancelled, no update needed - } - - // Get the row and column (subitem) being edited - int row = pInfo->item.iItem; - int col = pInfo->item.iSubItem; - char *newText = pInfo->item.pszText; - - // Apply the edit to the AMB file data structure - char formattedText[256]; - BOOL editAccepted = ApplyEditToAmbFile(hwnd, row, col, newText, formattedText, sizeof formattedText); - if (editAccepted) { - SetListViewItemText(g_hwndListView, row, col, formattedText, TRUE); - } - return editAccepted; -} - -// Global variables to track the current edit control's position -int g_editRow = -1; -int g_editCol = -1; -HWND g_hwndEdit = NULL; -WNDPROC g_oldEditProc = NULL; // Original window procedure for the edit control - -// Custom window procedure for the edit control to handle keyboard input -LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_KEYDOWN: - switch (wParam) - { - case VK_RETURN: - // Enter key - accept changes and destroy edit control - if (g_hwndEdit != NULL && g_editRow >= 0 && g_editCol >= 0) { - char buffer[256]; - GetWindowText(g_hwndEdit, buffer, sizeof(buffer)); - - // Apply the edit to the AMB file data structure and update the ListView with the formatted text - char formattedBuffer[256]; - if (ApplyEditToAmbFile(GetParent(GetParent(hwnd)), g_editRow, g_editCol, buffer, formattedBuffer, sizeof formattedBuffer)) { - SetListViewItemText(g_hwndListView, g_editRow, g_editCol, formattedBuffer, TRUE); - } - - // Destroy the edit control - DestroyWindow(g_hwndEdit); - g_hwndEdit = NULL; - g_editRow = -1; - g_editCol = -1; - } - return 0; - - case VK_ESCAPE: - // Escape key - cancel edit - if (g_hwndEdit != NULL) { - DestroyWindow(g_hwndEdit); - g_hwndEdit = NULL; - g_editRow = -1; - g_editCol = -1; - } - return 0; - } - break; - } - - // Call the original window procedure for other messages - return CallWindowProc(g_oldEditProc, hwnd, uMsg, wParam, lParam); -} - -// Returns the currently selected row and whether or not any was selected. Optionally displays an error when none is selected. -bool GetSelectedRow(char const * errorMsg, int * outSelectedRow) -{ - int rowCount = SendMessage(g_hwndListView, LVM_GETITEMCOUNT, 0, 0); - for (int i = 0; i < rowCount; i++) { - UINT state = SendMessage(g_hwndListView, LVM_GETITEMSTATE, i, LVIS_SELECTED); - if (state & LVIS_SELECTED) { - *outSelectedRow = i; - return true; - } - } - - // If we get here, no row was selected - if (errorMsg) - MessageBox(NULL, errorMsg, "Information", MB_OK | MB_ICONINFORMATION); - return false; -} - -// Function to match duration to WAV file for the selected row -void MatchDurationToWav(HWND hwndListView) -{ - int selectedRow; - if (! GetSelectedRow("Please select a row to match duration", &selectedRow)) - return; - - // Make sure we have valid row info - if (selectedRow >= g_rowCount) { - MessageBox(NULL, "Invalid row selection", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Get the WAV filename from the selected row - char wavFileName[256] = {0}; - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = selectedRow; - lvi.iSubItem = COL_WAV_FILE; - lvi.pszText = wavFileName; - lvi.cchTextMax = sizeof(wavFileName); - SendMessage(hwndListView, LVM_GETITEMTEXT, selectedRow, (LPARAM)&lvi); - - if (strlen(wavFileName) == 0) { - MessageBox(NULL, "No WAV filename found in selected row", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Construct full path to WAV file (assuming it's in the same directory as the AMB file) - Path wavFilePath; - strcpy(wavFilePath, g_ambFile.filePath); - PathRemoveFileSpec(wavFilePath); // Remove filename, keep directory - PathAppend(wavFilePath, wavFileName); - - // Get WAV file duration - float wavDuration; - if (!GetWavFileDuration(wavFilePath, &wavDuration)) { - char errorMsg[512]; - snprintf(errorMsg, sizeof(errorMsg), "Could not read duration from WAV file:\n%s\n\nMake sure the file exists and is a valid WAV file.", wavFilePath); - MessageBox(NULL, errorMsg, "Error", MB_OK | MB_ICONERROR); - return; - } - - // Convert duration to string and apply it to the AMB file - char durationStr[32]; - snprintf(durationStr, sizeof(durationStr), "%.3f", wavDuration); - - char formattedText[256]; - if (ApplyEditToAmbFile(GetParent(hwndListView), selectedRow, COL_DURATION, durationStr, formattedText, sizeof(formattedText))) { - SetListViewItemText(hwndListView, selectedRow, COL_DURATION, formattedText, TRUE); - } else { - MessageBeep(MB_ICONERROR); - } -} - -// Function to programmatically start editing a ListView subitem -void EditListViewSubItem(HWND hwndListView, int row, int col) -{ - // First select the item - LVITEMA lvi = {0}; - lvi.stateMask = LVIS_SELECTED; - lvi.state = LVIS_SELECTED; - SendMessage(hwndListView, LVM_SETITEMSTATE, row, (LPARAM)&lvi); - - // For subitems, we need to create a custom edit control - // First get the text of the subitem - char buffer[256] = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = row; - lvi.iSubItem = col; - lvi.pszText = buffer; - lvi.cchTextMax = sizeof(buffer); - SendMessage(hwndListView, LVM_GETITEMTEXT, row, (LPARAM)&lvi); - - // Create a structure for LVM_GETSUBITEMRECT - // The struct needs to have subItem in top and flags in left - RECT rect; - memset(&rect, 0, sizeof(RECT)); - rect.top = col; // subItem index - rect.left = LVIR_BOUNDS; // Type of rectangle (LVIR_BOUNDS for entire cell) - SendMessage(hwndListView, LVM_GETSUBITEMRECT, row, (LPARAM)&rect); - - // If we already have an edit control, destroy it - if (g_hwndEdit != NULL) { - DestroyWindow(g_hwndEdit); - g_hwndEdit = NULL; - } - - // For column 0 (Time), we need to adjust the width to match the column width - // instead of using the full row width that LVIR_BOUNDS returns - if (col == COL_TIME) { - // Get the width of column 0 - LVCOLUMNA lvc = {0}; - lvc.mask = LVCF_WIDTH; - SendMessage(hwndListView, LVM_GETCOLUMN, COL_TIME, (LPARAM)&lvc); - - // Adjust the rectangle to match the column width - rect.right = rect.left + lvc.cx; - } - - // Create an edit control over the subitem - g_hwndEdit = CreateWindow( - "EDIT", buffer, - WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, - hwndListView, (HMENU)1000, GetModuleHandle(NULL), NULL); - - if (g_hwndEdit) { - // Store which row and column we're editing - g_editRow = row; - g_editCol = col; - - // Subclass the edit control to handle keyboard input - g_oldEditProc = (WNDPROC)SetWindowLongPtr(g_hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditSubclassProc); - - // Set focus to the edit control and select all text - SetFocus(g_hwndEdit); - SendMessage(g_hwndEdit, EM_SETSEL, 0, -1); - } -} - -// Calculate and update the overall duration display -void UpdateOverallDuration(void) -{ - if (g_hwndDurationLabel == NULL) { - return; - } - - float maxEndTime = 0.0f; - - // Check if we have valid AMB data - if (g_ambFile.kmapChunkCount == 0 || g_ambFile.prgmChunkCount == 0 || g_ambFile.midi.trackCount == 0) { - SetWindowText(g_hwndDurationLabel, "Overall Duration: 0.000 sec"); - return; - } - - // Calculate seconds per tick for timing - float secondsPerTick = 0.0f; - if (g_ambFile.midi.ticksPerQuarterNote > 0) { - secondsPerTick = g_ambFile.midi.secondsPerQuarterNote / g_ambFile.midi.ticksPerQuarterNote; - } - - // Process each MIDI sound track to find the longest duration - int soundTrackCount = g_ambFile.midi.trackCount - 1; // Minus one to exclude the info track - for (int trackIndex = 0; trackIndex < soundTrackCount; trackIndex++) { - SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; - - int prgmIndex = GetReferencedPrgmIfValid(trackIndex); - if (prgmIndex < 0) - continue; // No valid Prgm, skip this track - - float timestamp = track->deltaTimeNoteOn * secondsPerTick; - float duration = track->deltaTimeNoteOff * secondsPerTick; - float endTime = timestamp + duration; - - if (endTime > maxEndTime) { - maxEndTime = endTime; - } - } - - // Update the label text - char durationText[64] = {0}; - snprintf(durationText, sizeof(durationText) - 1, "Overall Duration: %04.3f sec", maxEndTime); - SetWindowText(g_hwndDurationLabel, durationText); -} - -// Create and initialize the ListView control -void CreateAmbListView(HWND hwnd) -{ - // Create ListView control below the playback buttons - g_hwndListView = CreateWindow( - WC_LISTVIEW, - "", - WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_NOHSCROLL | LVS_EDITLABELS, - 20, 70, // x, y position (below the buttons) - 835, 460, // width, height (fill most of the window) - hwnd, - (HMENU)ID_AMB_LISTVIEW, - GetModuleHandle(NULL), - NULL - ); - - if (g_hwndListView == NULL) { - MessageBox(hwnd, "Could not create ListView control", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Set extended ListView styles - DWORD exStyle = LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES; - SendMessage(g_hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle); - - // Add columns to the ListView - AddListViewColumn(g_hwndListView, COL_TIME, "Time (sec.)", 85); - AddListViewColumn(g_hwndListView, COL_DURATION, "Duration (sec.)", 95); - AddListViewColumn(g_hwndListView, COL_WAV_FILE, "WAV File", 235); - AddListViewColumn(g_hwndListView, COL_SPEED_RANDOM, "Speed Rnd", 70); - AddListViewColumn(g_hwndListView, COL_SPEED_MIN, "Speed Min", 70); - AddListViewColumn(g_hwndListView, COL_SPEED_MAX, "Speed Max", 70); - AddListViewColumn(g_hwndListView, COL_VOLUME_RANDOM, "Vol. Rnd", 70); - AddListViewColumn(g_hwndListView, COL_VOLUME_MIN, "Vol. Min", 70); - AddListViewColumn(g_hwndListView, COL_VOLUME_MAX, "Vol. Max", 70); - - // Create duration label below the ListView - g_hwndDurationLabel = CreateWindow( - "STATIC", - "Overall Duration: 0.000 sec", - WS_CHILD | WS_VISIBLE | SS_LEFT, - 20, 540, // x, y position (below the ListView) - 250, 20, // width, height - hwnd, - NULL, - GetModuleHandle(NULL), - NULL - ); -} - -LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_CREATE: - // Read INI settings - { - Path iniFullPath; - GetCurrentDirectory(PATH_BUFFER_SIZE, iniFullPath); - PathAppend(iniFullPath, "amb_editor.ini"); - - GetPrivateProfileString("Paths", "civ_3_install_path", "", g_iniCiv3InstallPath, PATH_BUFFER_SIZE, iniFullPath); - GetPrivateProfileString("Paths", "sound_dll_path" , "", g_iniSoundDLLPath , PATH_BUFFER_SIZE, iniFullPath); - GetPrivateProfileString("Paths", "temp_directory" , "", g_iniTempDirectory , PATH_BUFFER_SIZE, iniFullPath); - } - - // If we've been given a specific Civ 3 install path in the INI, use that. Otherwise search for one. - if (strlen(g_iniCiv3InstallPath) > 0) { - strcpy(g_civ3MainPath, g_iniCiv3InstallPath); - } else { - FindCiv3Installation(hwnd); - } - - g_hwndMainWindow = hwnd; - - // Create playback buttons - CreatePlaybackButtons(hwnd); - - // Create the AMB ListView control - CreateAmbListView(hwnd); - - return 0; - - case WM_COMMAND: - // Handle menu commands - switch (LOWORD(wParam)) - { - case IDM_FILE_OPEN: - // Show open file dialog to load an AMB file - LoadAmbFileWithDialog(hwnd); - return 0; - - case IDM_FILE_SAVE: - // Save AMB file directly - SaveAmbFileDirectly(hwnd); - return 0; - - case IDM_FILE_SAVE_AS: - // Show save file dialog to save AMB file as - SaveAmbFileAs(hwnd); - return 0; - - case IDM_FILE_DETAILS: - // Show window with AMB file details - ShowAmbDetailsWindow(hwnd); - return 0; - - case IDM_FILE_EXIT: - // Exit the application - PostMessage(hwnd, WM_CLOSE, 0, 0); - return 0; - - case IDM_EDIT_UNDO: - // Perform undo operation - Undo(); - return 0; - - case IDM_EDIT_REDO: - // Perform redo operation - Redo(); - return 0; - - case IDM_EDIT_ADD: - // Add a new row - AddRow(); - return 0; - - case IDM_EDIT_DELETE: - { - // Delete the selected row - int selectedRow; - if (GetSelectedRow("Please select a row to delete", &selectedRow)) - DeleteRow(selectedRow); - - return 0; - } - - case IDM_EDIT_MATCH_WAV: - // Match duration to WAV file - MatchDurationToWav(g_hwndListView); - return 0; - - case IDM_EDIT_PRUNE: - Prune(); - return 0; - - case IDM_HELP_ABOUT: - // Show about dialog - MessageBox(hwnd, - "This is a tool for inspecting and modifying the AMB sound files used by Sid Meier's Civilization III.\n\n" - "Last updated in C3X Release 23\n\n" - "For more info, see README.txt", - "About AMB Editor", - MB_OK | MB_ICONINFORMATION); - return 0; - - case ID_PLAY_BUTTON: - // Handle Play button click - if (g_ambFile.filePath[0] != '\0') { - bool encounteredError = false; - - // Check that the preview player is initialized. If it's not, try to initialize it. - if (! previewPlayerIsInitialized) { - Path soundDLLPath; - if (GetSoundDLLPath(hwnd, soundDLLPath)) { - InitializePreviewPlayer(hwnd, soundDLLPath); - } - if (! previewPlayerIsInitialized) - encounteredError = true; - } - - // Check for missing WAV files before attempting preview - if (! encounteredError) { - char missingFiles[1024]; - if (HasMissingWavFiles(missingFiles, sizeof(missingFiles))) { - char errorMsg[1280]; - snprintf(errorMsg, sizeof(errorMsg), - "Cannot preview AMB file because the following WAV files are missing:\n\n%s\n\nPlease ensure all WAV files are present in the AMB file's directory.", - missingFiles); - MessageBox(hwnd, errorMsg, "Missing WAV Files", MB_OK | MB_ICONERROR); - } - } - - if (! encounteredError) - PreviewAmbFile(g_iniTempDirectory, &g_ambFile); - } else { - MessageBox(hwnd, "No AMB file loaded. Please open an AMB file first.", - "Error", MB_OK | MB_ICONINFORMATION); - } - return 0; - - case ID_STOP_BUTTON: - // Handle Stop button click - StopAmbPreview(); - return 0; - - // Check if the command is from the edit control created for subitem editing - default: - if (LOWORD(wParam) == 1000 && HIWORD(wParam) == EN_KILLFOCUS) { - // When the edit control loses focus, get its text and update the list view item - if (g_hwndEdit != NULL && g_editRow >= 0 && g_editCol >= 0) { - char buffer[256]; - GetWindowText(g_hwndEdit, buffer, sizeof(buffer)); - - // Apply the edit to the AMB file data structure - char formattedBuffer[256]; - if (ApplyEditToAmbFile(hwnd, g_editRow, g_editCol, buffer, formattedBuffer, sizeof formattedBuffer)) { - SetListViewItemText(g_hwndListView, g_editRow, g_editCol, formattedBuffer, TRUE); - } - - // Destroy the edit control - DestroyWindow(g_hwndEdit); - g_hwndEdit = NULL; - g_editRow = -1; - g_editCol = -1; - } - return 0; - } - } - break; - - case WM_NOTIFY: - // Handle control notifications - { - NMHDR *nmhdr = (NMHDR *)lParam; - - // Check if the notification is from our ListView - if (nmhdr->hwndFrom == g_hwndListView) { - switch (nmhdr->code) { - case LVN_BEGINLABELEDIT: - // Notification when a label edit begins - return HandleBeginLabelEdit(hwnd, (NMLVDISPINFOA *)lParam); - - case LVN_ENDLABELEDIT: - // Notification when a label edit ends - return HandleEndLabelEdit(hwnd, (NMLVDISPINFOA *)lParam); - - case NM_DBLCLK: - // Handle double-click on a ListView item to edit the cell - { - NMITEMACTIVATE *nia = (NMITEMACTIVATE *)lParam; - // Only process if a valid item was clicked - if (nia->iItem != -1) { - // Check if this is a boolean column - if (nia->iSubItem == COL_SPEED_RANDOM || nia->iSubItem == COL_VOLUME_RANDOM) { - // Toggle the boolean value directly - char currentText[32]; - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = nia->iItem; - lvi.iSubItem = nia->iSubItem; - lvi.pszText = currentText; - lvi.cchTextMax = sizeof(currentText); - SendMessage(g_hwndListView, LVM_GETITEMTEXT, nia->iItem, (LPARAM)&lvi); - - // Toggle: if current is "Yes", change to "No", otherwise change to "Yes" - const char *newText = (strcmp(currentText, "Yes") == 0) ? "No" : "Yes"; - - // Apply the toggle to the AMB file data structure - char formattedText[256]; - if (ApplyEditToAmbFile(hwnd, nia->iItem, nia->iSubItem, newText, formattedText, sizeof(formattedText))) { - SetListViewItemText(g_hwndListView, nia->iItem, nia->iSubItem, formattedText, TRUE); - } - } else { - // For non-boolean columns, start editing the subitem that was clicked - EditListViewSubItem(g_hwndListView, nia->iItem, nia->iSubItem); - } - - // Tell the system we handled this message - SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); - return TRUE; - } - } - break; - - case NM_CUSTOMDRAW: - // Handle custom drawing for ListView - { - LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam; - - switch (lplvcd->nmcd.dwDrawStage) { - case CDDS_PREPAINT: - // Tell Windows we want to be notified for each item - return CDRF_NOTIFYITEMDRAW; - - case CDDS_ITEMPREPAINT: - // Tell Windows we want to be notified for each subitem - return CDRF_NOTIFYSUBITEMDRAW; - - case CDDS_SUBITEM | CDDS_ITEMPREPAINT: - // Custom draw for individual cells - { - int item = (int)lplvcd->nmcd.dwItemSpec; - int subItem = lplvcd->iSubItem; - - // Check if this is the WAV file column - if (subItem == COL_WAV_FILE) { - // Get the WAV filename for this row - char wavFileName[256] = {0}; - LVITEMA lvi = {0}; - lvi.mask = LVIF_TEXT; - lvi.iItem = item; - lvi.iSubItem = COL_WAV_FILE; - lvi.pszText = wavFileName; - lvi.cchTextMax = sizeof(wavFileName); - SendMessage(g_hwndListView, LVM_GETITEMTEXT, item, (LPARAM)&lvi); - - // Check if WAV file exists - if (!CheckWavFileExists(wavFileName)) { - // Set text color to red for missing files - lplvcd->clrText = RGB(255, 0, 0); - } else { - // Use default text color - lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); - } - - return CDRF_NEWFONT; - } else if (subItem == COL_SPEED_MIN || subItem == COL_SPEED_MAX || - subItem == COL_VOLUME_MIN || subItem == COL_VOLUME_MAX) { - // Check if min/max columns should be grayed out based on flags - if (item < g_rowCount) { - AmbRowInfo *rowInfo = &g_rowInfo[item]; - if (rowInfo->prgmIndex >= 0 && rowInfo->prgmIndex < g_ambFile.prgmChunkCount) { - PrgmChunk *prgm = &g_ambFile.prgmChunks[rowInfo->prgmIndex]; - - BOOL shouldGrayOut = FALSE; - if (subItem == COL_SPEED_MIN || subItem == COL_SPEED_MAX) { - // Gray out if speed random is disabled (flags & 1 == 0) - shouldGrayOut = !(prgm->flags & 0x01); - } else { - // Gray out if volume random is disabled (flags & 2 == 0) - shouldGrayOut = !(prgm->flags & 0x02); - } - - if (shouldGrayOut) { - lplvcd->clrText = GetSysColor(COLOR_GRAYTEXT); - } else { - lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); - } - - return CDRF_NEWFONT; - } - } - - // Fallback to default color - lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); - return CDRF_NEWFONT; - } else { - // For all other columns, use default text color - lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); - return CDRF_NEWFONT; - } - } - } - } - return CDRF_DODEFAULT; - } - } - } - break; - - case WM_ERASEBKGND: - { - // Handle window background erasure - HDC hdc = (HDC)wParam; - RECT rect; - GetClientRect(hwnd, &rect); - FillRect(hdc, &rect, g_hBackgroundBrush); - return 1; // Return non-zero to indicate we processed this message - } - - case WM_CTLCOLORDLG: - case WM_CTLCOLORSTATIC: - case WM_CTLCOLORBTN: - // Set background color for dialog, static controls, and buttons - return (LRESULT)g_hBackgroundBrush; - - case WM_CLOSE: - DestroyWindow(hwnd); - return 0; - - case WM_DESTROY: - // Clean up resources - if (g_hBackgroundBrush != NULL) { - DeleteObject(g_hBackgroundBrush); - g_hBackgroundBrush = NULL; - } - DeinitializePreviewPlayer(); - PostQuitMessage(0); - return 0; - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -// Create a simple menu -HMENU CreateAmbEditorMenu() -{ - HMENU hMenu, hFileMenu, hEditMenu, hHelpMenu; - - hMenu = CreateMenu(); - - // File menu - hFileMenu = CreatePopupMenu(); - AppendMenu(hFileMenu, MF_STRING, IDM_FILE_OPEN, "&Open AMB File...\tCtrl+O"); - AppendMenu(hFileMenu, MF_STRING, IDM_FILE_SAVE, "&Save\tCtrl+S"); - AppendMenu(hFileMenu, MF_STRING, IDM_FILE_SAVE_AS, "Save &As..."); - AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hFileMenu, MF_STRING, IDM_FILE_DETAILS, "&View AMB Details"); - AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hFileMenu, MF_STRING, IDM_FILE_EXIT, "E&xit"); - - // Edit menu - hEditMenu = CreatePopupMenu(); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_UNDO, "&Undo\tCtrl+Z"); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_REDO, "&Redo\tCtrl+Y"); - AppendMenu(hEditMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_ADD, "&Add Row\tIns"); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_DELETE, "&Delete Row\tDel"); - AppendMenu(hEditMenu, MF_SEPARATOR, 0, NULL); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_MATCH_WAV, "&Match duration to WAV"); - AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_PRUNE, "&Prune"); - - // Help menu - hHelpMenu = CreatePopupMenu(); - AppendMenu(hHelpMenu, MF_STRING, IDM_HELP_ABOUT, "&About..."); - - // Add menus to the main menu - AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, "&File"); - AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hEditMenu, "&Edit"); - AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hHelpMenu, "&Help"); - - return hMenu; -} - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ - // Register the window class - const char CLASS_NAME[] = "AMB Editor Window Class"; - - // Create a pleasant beige brush for the background - RGB(245, 245, 220) is a nice beige color - g_hBackgroundBrush = CreateSolidBrush(RGB(245, 235, 200)); - - WNDCLASS wc = {0}; - wc.lpfnWndProc = WindowProc; - wc.hInstance = hInstance; - wc.lpszClassName = CLASS_NAME; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = g_hBackgroundBrush; - - RegisterClass(&wc); - - // Create menu - HMENU hMenu = CreateAmbEditorMenu(); - - // Create the window - HWND hwnd = CreateWindowEx( - 0, // Optional window styles - CLASS_NAME, // Window class - "AMB Editor", // Window title - WS_OVERLAPPEDWINDOW, // Window style - - // Size and position - CW_USEDEFAULT, CW_USEDEFAULT, 895, 620, - - NULL, // Parent window - hMenu, // Menu - hInstance, // Instance handle - NULL // Additional application data - ); - - if (hwnd == NULL) { - return 0; - } - - ShowWindow(hwnd, nCmdShow); - - // Create accelerator table - HACCEL hAccel = CreateAcceleratorTable(g_accelTable, sizeof(g_accelTable) / sizeof(g_accelTable[0])); - - // Run the message loop - MSG msg = {0}; - while (GetMessage(&msg, NULL, 0, 0)) { - if (!TranslateAccelerator(hwnd, hAccel, &msg)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - return (int)msg.wParam; -} +#include +#include +#include +#include +#include +#include + +// Defines the things we need from commctrl.h, commdlg.h, and any other headers that are not available +#include "win32_selections.h" + + + +#define PATH_BUFFER_SIZE 1024 +typedef char Path[PATH_BUFFER_SIZE]; + +Path g_iniCiv3InstallPath; +Path g_iniSoundDLLPath; +Path g_iniTempDirectory; + +void PathAppend(Path path, const char* append) +{ + size_t len = strlen(path); + + // No space at end of buffer + if (len >= PATH_BUFFER_SIZE - 1) + return; + + // Add backslash if needed + if (len > 0 && path[len - 1] != '\\') { + path[len] = '\\'; + path[len + 1] = '\0'; + len++; + } + + // Append the new part + strncpy(path + len, append, PATH_BUFFER_SIZE - len); + path[PATH_BUFFER_SIZE - 1] = '\0'; +} + +bool PathRemoveFileSpec(Path path) +{ + char* lastSlash = strrchr(path, '\\'); + if (lastSlash) { + *lastSlash = '\0'; + return true; + } + return false; +} + + + +#include "amb_file.c" +#include "preview.c" +#include "wav_file.c" + + + +// Forward declarations for ListView functions +void AddListViewColumn(HWND hListView, int index, char *title, int width); +int AddListViewItem(HWND hListView, int index, const char *text); +void SetListViewItemText(HWND hListView, int row, int col, const char *text, BOOL allowRepopulation); +void ClearListView(HWND hListView); +void PopulateAmbListView(void); +BOOL ApplyEditToAmbFile(HWND hwnd, int row, int col, const char *newText, char * outFormattedText, int formattedTextBufferSize); +BOOL IsValidInteger(const char *str); +BOOL GetWavFileDuration(const char* filePath, float* outDuration); +BOOL CheckWavFileExists(const char* wavFileName); +BOOL HasMissingWavFiles(char* missingFiles, int bufferSize); +void MatchDurationToWav(HWND hwndListView); +void LoadAmbFileWithDialog(HWND hwnd); +void SaveAmbFileDirectly(HWND hwnd); +void SaveAmbFileAs(HWND hwnd); +void UpdateOverallDuration(void); + +// Currently loaded AMB file +AmbFile g_ambFile = {0}; + +AmbFile g_fileSnapshots[100] = {0}; +int g_snapshotCount = 0, + g_redoCount = 0; + +void ClearFileSnapshots() +{ + memset(g_fileSnapshots, 0, sizeof g_fileSnapshots); + g_snapshotCount = g_redoCount = 0; +} + +// Saves a copy of the currently loaded file onto the stack of snapshots so any changes to the file can be reverted. If the stack is full, drops the +// oldest item. +void SnapshotCurrentFile() +{ + g_redoCount = 0; + + int snapshotCapacity = (sizeof g_fileSnapshots) / (sizeof g_fileSnapshots[0]); + if (g_snapshotCount == snapshotCapacity) { + memmove(&g_fileSnapshots[0], &g_fileSnapshots[1], (snapshotCapacity - 1) * (sizeof g_fileSnapshots[0])); + g_snapshotCount--; + } + + memcpy(&g_fileSnapshots[g_snapshotCount], &g_ambFile, sizeof(AmbFile)); + g_snapshotCount++; +} + +void Undo() +{ + static AmbFile tempAmb; + + if (g_snapshotCount > 0) { + // Swap most recent snapshot with the current file + memcpy(&tempAmb, &g_ambFile, sizeof(AmbFile)); + memcpy(&g_ambFile, &g_fileSnapshots[g_snapshotCount - 1], sizeof(AmbFile)); + memcpy(&g_fileSnapshots[g_snapshotCount - 1], &tempAmb, sizeof(AmbFile)); + + g_snapshotCount--; + g_redoCount++; + + PopulateAmbListView(); // Refresh the ListView to reflect changes + } else + MessageBeep(MB_ICONERROR); +} + +void Redo() +{ + static AmbFile tempAmb; + + if (g_redoCount > 0) { + // Swap oldest redo (stored one above the newest undo on the stack) with the current file + memcpy(&tempAmb, &g_fileSnapshots[g_snapshotCount], sizeof(AmbFile)); + memcpy(&g_fileSnapshots[g_snapshotCount], &g_ambFile, sizeof(AmbFile)); + memcpy(&g_ambFile, &tempAmb, sizeof(AmbFile)); + + g_snapshotCount++; + g_redoCount--; + + PopulateAmbListView(); // Refresh the ListView to reflect changes + } else + MessageBeep(MB_ICONERROR); +} + +// Function declarations +BOOL WINAPI GetOpenFileNameA(LPOPENFILENAMEA lpofn); +BOOL WINAPI GetSaveFileNameA(LPOPENFILENAMEA lpofn); + +// Menu IDs +#define IDM_FILE_OPEN 1001 +#define IDM_FILE_SAVE 1002 +#define IDM_FILE_SAVE_AS 1003 +#define IDM_FILE_DETAILS 1004 +#define IDM_FILE_EXIT 1005 +#define IDM_EDIT_UNDO 1006 +#define IDM_EDIT_REDO 1007 +#define IDM_EDIT_DELETE 1008 +#define IDM_EDIT_ADD 1009 +#define IDM_EDIT_MATCH_WAV 1010 +#define IDM_EDIT_PRUNE 1011 +#define IDM_HELP_ABOUT 1012 + +// Accelerator table for hotkeys +ACCEL g_accelTable[] = { + {FCONTROL | FVIRTKEY, 'O', IDM_FILE_OPEN}, // Ctrl+O + {FCONTROL | FVIRTKEY, 'S', IDM_FILE_SAVE}, // Ctrl+S + {FCONTROL | FVIRTKEY, 'Z', IDM_EDIT_UNDO}, // Ctrl+Z + {FCONTROL | FVIRTKEY, 'Y', IDM_EDIT_REDO}, // Ctrl+Y + {FVIRTKEY, VK_DELETE, IDM_EDIT_DELETE}, // Delete + {FVIRTKEY, VK_INSERT, IDM_EDIT_ADD} // Insert +}; + +// Control IDs +#define ID_PATH_EDIT 102 +#define ID_PLAY_BUTTON 103 +#define ID_STOP_BUTTON 104 +#define ID_AMB_LISTVIEW 105 + +// ListView Column Indices +typedef enum { + COL_TIME = 0, + COL_DURATION, + COL_WAV_FILE, + COL_SPEED_RANDOM, + COL_SPEED_MIN, + COL_SPEED_MAX, + COL_VOLUME_RANDOM, + COL_VOLUME_MIN, + COL_VOLUME_MAX +} ListViewColumn; + +// Track info structure to associate ListView rows with AMB data +typedef struct { + int trackIndex; // MIDI track index + int kmapIndex; // Index of Kmap chunk + int prgmIndex; // Index of Prgm chunk + int kmapItemIndex; // Index of item within Kmap +} AmbRowInfo; + +// Temporary structure for sorting rows by timestamp +typedef struct { + AmbRowInfo rowInfo; + float timestamp; + float duration; + char timeStr[32]; + char durationStr[32]; + char wavFileName[256]; + char speedMaxStr[32]; + char speedMinStr[32]; + char volumeMaxStr[32]; + char volumeMinStr[32]; + bool hasSpeedRandom; + bool hasVolumeRandom; +} RowData; + +// Comparison function for sorting rows by timestamp +int CompareRowsByTimestamp(const void *a, const void *b) +{ + const RowData *rowA = (const RowData *)a; + const RowData *rowB = (const RowData *)b; + + if (rowA->timestamp < rowB->timestamp) return -1; + if (rowA->timestamp > rowB->timestamp) return 1; + return 0; +} + +// Global variables +Path g_civ3MainPath = {0}; +HWND g_hwndPathEdit = NULL; +HWND g_hwndMainWindow = NULL; +HWND g_hwndPlayButton = NULL; +HWND g_hwndStopButton = NULL; +HWND g_hwndListView = NULL; +HWND g_hwndDurationLabel = NULL; +HBRUSH g_hBackgroundBrush = NULL; // Brush for window background color + +// Track info for each row in the ListView +AmbRowInfo g_rowInfo[MAX_SOUND_TRACKS]; +int g_rowCount = 0; // Number of rows in the ListView + +// Custom path helpers +bool PathFileExists(const Path path) +{ + DWORD attr = GetFileAttributes(path); + return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY)); +} + +bool PathIsDirectory(const Path path) +{ + DWORD attr = GetFileAttributes(path); + return (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)); +} + +// Function to browse for an AMB file to open +bool BrowseForAmbFile(HWND hwnd, Path filePath) +{ + // Initialize the OPENFILENAME structure + OPENFILENAMEA ofn; + ZeroMemory(&ofn, sizeof(ofn)); + + // Set up buffer + ZeroMemory(filePath, PATH_BUFFER_SIZE); + + // Setup the open file dialog + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = filePath; + ofn.nMaxFile = PATH_BUFFER_SIZE; + ofn.lpstrFilter = "AMB Files\0*.amb\0All Files\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrTitle = "Select an AMB file to open"; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER; + + // Set initial directory to Civ3 install path if found + if (strlen(g_civ3MainPath) > 0) { + ofn.lpstrInitialDir = g_civ3MainPath; + } + + // Show the dialog and get result + return GetOpenFileNameA(&ofn); +} + +// Load an AMB file selected by the user +void LoadAmbFileWithDialog(HWND hwnd) +{ + Path ambFilePath = {0}; + + if (BrowseForAmbFile(hwnd, ambFilePath)) { + if (LoadAmbFile(ambFilePath, &g_ambFile) && g_hwndMainWindow != NULL) { + ClearFileSnapshots(); + + // Extract the filename part from the path + char *fileName = strrchr(ambFilePath, '\\'); + if (fileName) { + fileName++; // Skip past the backslash + } else { + fileName = (char*)ambFilePath; // No backslash found, use the whole path + } + + char windowTitle[100]; + snprintf(windowTitle, sizeof windowTitle, "%s - AMB Editor", fileName); + windowTitle[(sizeof windowTitle) - 1] = '\0'; + SetWindowText(g_hwndMainWindow, windowTitle); + + // Populate the ListView with the loaded AMB file data + PopulateAmbListView(); + } + } +} + +// Browse for a file to save +BOOL BrowseForSaveFile(HWND hwnd, Path filePath) +{ + OPENFILENAMEA ofn; + ZeroMemory(&ofn, sizeof(ofn)); + + // Initialize the filePath with current file if any + if (g_ambFile.filePath[0] != '\0') { + strcpy(filePath, g_ambFile.filePath); + } + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = "AMB Files (*.amb)\0*.amb\0All Files (*.*)\0*.*\0"; + ofn.lpstrFile = filePath; + ofn.nMaxFile = PATH_BUFFER_SIZE; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_EXPLORER; + ofn.lpstrDefExt = "amb"; + ofn.lpstrTitle = "Save AMB File"; + + return GetSaveFileNameA(&ofn); +} + +// Save AMB file directly (without dialog) +void SaveAmbFileDirectly(HWND hwnd) +{ + if (g_ambFile.filePath[0] == '\0') { + MessageBox(hwnd, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Try to save to the current file path + if (SaveAmbFile(&g_ambFile, g_ambFile.filePath)) { + // Success - file saved silently + return; + } + + // Failed to save (likely permissions issue) - fall back to Save As silently + SaveAmbFileAs(hwnd); +} + +// Save AMB file with Save As dialog +void SaveAmbFileAs(HWND hwnd) +{ + if (g_ambFile.filePath[0] == '\0') { + MessageBox(hwnd, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); + return; + } + + Path filePath = {0}; + + if (BrowseForSaveFile(hwnd, filePath)) { + // Try to save the AMB file + if (SaveAmbFile(&g_ambFile, filePath)) { + // Update the current file path to the new location + strcpy(g_ambFile.filePath, filePath); + + // Extract the filename part from the path and update window title + char *fileName = strrchr(filePath, '\\'); + if (fileName) { + fileName++; // Skip past the backslash + } else { + fileName = (char*)filePath; // No backslash found, use the whole path + } + + char windowTitle[100]; + snprintf(windowTitle, sizeof windowTitle, "%s - AMB Editor", fileName); + windowTitle[(sizeof windowTitle) - 1] = '\0'; + SetWindowText(g_hwndMainWindow, windowTitle); + } else { + MessageBox(hwnd, "Failed to save AMB file. Check file permissions and try again.", "Error", MB_OK | MB_ICONERROR); + } + } +} + +// Function to check if a directory is the main Civ3 folder +bool IsCiv3MainFolder(const Path folderPath) +{ + Path testPath; + + // Check for Art folder + strcpy(testPath, folderPath); + PathAppend(testPath, "Art"); + if (!PathIsDirectory(testPath)) { + return false; + } + + // Check for civ3PTW folder + strcpy(testPath, folderPath); + PathAppend(testPath, "civ3PTW"); + if (!PathIsDirectory(testPath)) { + return false; + } + + return true; +} + +// Function to search parent folders for Civ3 install +bool FindCiv3InstallBySearch(const Path startPath) +{ + Path testPath; + + // Start with working directory + strcpy(testPath, startPath); + + // Go up up to 10 parent directories + for (int i = 0; i < 10; i++) { + // Check current directory and subdirectories for main Civ3 folder + WIN32_FIND_DATA findData; + HANDLE hFind; + Path searchPath; + + strcpy(searchPath, testPath); + PathAppend(searchPath, "*"); + + hFind = FindFirstFile(searchPath, &findData); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + strcmp(findData.cFileName, ".") != 0 && + strcmp(findData.cFileName, "..") != 0) { + + Path subDirPath; + strcpy(subDirPath, testPath); + PathAppend(subDirPath, findData.cFileName); + + if (IsCiv3MainFolder(subDirPath)) { + // Found main Civ3 directory + strcpy(g_civ3MainPath, subDirPath); + FindClose(hFind); + return true; + } + } + } while (FindNextFile(hFind, &findData)); + FindClose(hFind); + } + + // Move up a directory + if (!PathRemoveFileSpec(testPath)) { + break; // Cannot go up further + } + } + + return false; +} + +// Function to find Civ3 install from registry +bool FindCiv3InstallFromRegistry() +{ + HKEY hKey; + char regValue[PATH_BUFFER_SIZE]; + DWORD valueSize = sizeof(regValue); + DWORD valueType; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Infogrames Interactive\\Civilization III", + 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + + if (RegQueryValueEx(hKey, "Install_Path", NULL, &valueType, + (LPBYTE)regValue, &valueSize) == ERROR_SUCCESS) { + + if (valueType == REG_SZ) { + regValue[(sizeof regValue) - 1] = '\0'; // RegQueryValueEx is not guaranteed to return null terminated strings + strcpy(g_civ3MainPath, regValue); + + RegCloseKey(hKey); + return true; + } + } + RegCloseKey(hKey); + } + + return false; +} + +bool GetSoundDLLPath(HWND hwnd, Path outSoundDLLPath) +{ + // First, check if INI has a sound.dll path specified + if (strlen(g_iniSoundDLLPath) > 0) { + strcpy(outSoundDLLPath, g_iniSoundDLLPath); + return true; + } + + // Otherwise, check if Conquests\sound.dll exists in the main Civ3 install + if (strlen(g_civ3MainPath) > 0) { + Path conquestsSoundPath; + strcpy(conquestsSoundPath, g_civ3MainPath); + PathAppend(conquestsSoundPath, "Conquests"); + PathAppend(conquestsSoundPath, "sound.dll"); + + if (PathFileExists(conquestsSoundPath)) { + strcpy(outSoundDLLPath, conquestsSoundPath); + return true; + } + } + + // If neither works, ask the user to locate sound.dll + int result = MessageBox(hwnd, + "Playing a preview requires sound.dll from your Civ 3 Conquests install. This could not be found automatically. " + "Would you like to locate sound.dll manually?", + "DLL not found", MB_YESNO | MB_ICONQUESTION); + if (result == IDYES) { + Path path = {0}; + + OPENFILENAMEA ofn; + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = path; + ofn.nMaxFile = PATH_BUFFER_SIZE; + ofn.lpstrFilter = "DLL Files\0*.dll\0All Files\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrTitle = "Select sound.dll from your Civ 3 Conquests install"; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetOpenFileNameA(&ofn)) { + if (PathFileExists(path)) { + strcpy(outSoundDLLPath, path); + return true; + } + } + } + + return false; +} + +// Find Civ3 installation using all available methods +bool FindCiv3Installation(HWND hwnd) +{ + Path cwdPath; + GetCurrentDirectory(PATH_BUFFER_SIZE, cwdPath); + + // Search parent folders first. If that doesn't work, check the registry. + if (FindCiv3InstallBySearch(cwdPath)) { + return true; + } else + return FindCiv3InstallFromRegistry(); +} + +// Create the play and stop buttons +void CreatePlaybackButtons(HWND hwnd) +{ + // Create Play button + g_hwndPlayButton = CreateWindow( + "BUTTON", + "Play Preview", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, + 20, 20, 100, 30, + hwnd, (HMENU)ID_PLAY_BUTTON, GetModuleHandle(NULL), NULL + ); + + // Create Stop button + g_hwndStopButton = CreateWindow( + "BUTTON", + "Stop", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, + 130, 20, 80, 30, + hwnd, (HMENU)ID_STOP_BUTTON, GetModuleHandle(NULL), NULL + ); +} + +// Add a column to the ListView +void AddListViewColumn(HWND hListView, int index, char *title, int width) +{ + LVCOLUMNA lvc = {0}; + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + lvc.pszText = title; + lvc.cx = width; + + SendMessage(hListView, LVM_INSERTCOLUMN, index, (LPARAM)&lvc); +} + +// Add a row to the ListView +int AddListViewItem(HWND hListView, int index, const char *text) +{ + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = index; + lvi.iSubItem = 0; + lvi.pszText = (LPSTR)text; + + return SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&lvi); +} + +// Set text in a ListView cell +void SetListViewItemText(HWND hListView, int row, int col, const char *text, BOOL allowRepopulation) +{ + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = row; + lvi.iSubItem = col; + lvi.pszText = (LPSTR)text; + + SendMessage(hListView, LVM_SETITEM, 0, (LPARAM)&lvi); + + // Check if we need to repopulate when time changes + if (allowRepopulation && col == COL_TIME) { + PopulateAmbListView(); + } +} + +// Clear all items from the ListView +void ClearListView(HWND hListView) +{ + SendMessage(hListView, LVM_DELETEALLITEMS, 0, 0); +} + +// Check if a WAV file exists in the AMB file's directory +BOOL CheckWavFileExists(const char* wavFileName) +{ + if (!wavFileName || strlen(wavFileName) == 0 || g_ambFile.filePath[0] == '\0') { + return FALSE; + } + + // Construct full path to WAV file + Path wavFilePath; + strcpy(wavFilePath, g_ambFile.filePath); + PathRemoveFileSpec(wavFilePath); // Remove filename, keep directory + PathAppend(wavFilePath, wavFileName); + + // Check if file exists + return PathFileExists(wavFilePath); +} + +// Check if any WAV files are missing and return a list of missing files +BOOL HasMissingWavFiles(char* missingFiles, int bufferSize) +{ + if (!missingFiles || bufferSize == 0 || g_ambFile.filePath[0] == '\0') { + return FALSE; + } + + missingFiles[0] = '\0'; // Initialize as empty string + BOOL hasMissing = FALSE; + + // Check each row in the ListView for missing WAV files + for (int i = 0; i < g_rowCount; i++) { + AmbRowInfo *rowInfo = &g_rowInfo[i]; + if (rowInfo->kmapIndex >= 0 && rowInfo->kmapIndex < g_ambFile.kmapChunkCount && + rowInfo->kmapItemIndex >= 0 && rowInfo->kmapItemIndex < g_ambFile.kmapChunks[rowInfo->kmapIndex].itemCount) { + + KmapChunk *kmap = &g_ambFile.kmapChunks[rowInfo->kmapIndex]; + const char *wavFileName = kmap->items[rowInfo->kmapItemIndex].wavFileName; + + // Ignore empty WAV file names since those don't interfere with playback + if ((wavFileName[0] != '\0') && !CheckWavFileExists(wavFileName)) { + hasMissing = TRUE; + + // Add to missing files list if there's space + if (strlen(missingFiles) > 0) { + strncat(missingFiles, "\n", bufferSize - strlen(missingFiles) - 1); + } + strncat(missingFiles, wavFileName, bufferSize - strlen(missingFiles) - 1); + } + } + } + + return hasMissing; +} + +// Function to check if a string is a valid integer +BOOL IsValidInteger(const char *str) +{ + // Allow for a leading + or - sign + if (*str == '+' || *str == '-') { + str++; + } + + // Empty string or just a sign isn't a valid integer + if (*str == '\0') { + return FALSE; + } + + // Check that all characters are digits + while (*str) { + if (!isdigit(*str)) { + return FALSE; + } + str++; + } + + return TRUE; +} + + + + +// Defines void ShowAmbDetailsWindow(HWND hwndParent) +#include "details_window.c" + + + +// Returns the index of the Prgm chunk referred to by the given sound track. If the track does not validly refer to any Prgm, returns -1. In order for +// the track to be valid, the channel numbers of all events must match and specify a valid Prgm index and the program change event must specify the +// corresponding program number. +int GetReferencedPrgmIfValid(int trackIndex) +{ + SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; + + int prgmIndex = track->programChange.programNumber - 1; + + if ((prgmIndex < 0) || (prgmIndex >= g_ambFile.prgmChunkCount)) + return -1; + + for (int i = 0; i < track->controlChangeCount; i++) + if (track->controlChanges[i].channelNumber != prgmIndex) + return -1; + + if ((track->programChange.channelNumber != prgmIndex) || + (track->noteOn .channelNumber != prgmIndex) || + (track->noteOff .channelNumber != prgmIndex)) + return -1; + + return prgmIndex; +} + +// Populate the ListView with AMB file data +void PopulateAmbListView(void) +{ + if (g_hwndListView == NULL) { + MessageBox(NULL, "ListView control is NULL", "Debug", MB_OK); + return; + } + + // Clear any existing data + ClearListView(g_hwndListView); + + // Reset row info + g_rowCount = 0; + memset(g_rowInfo, 0, sizeof(g_rowInfo)); + + // Check if we have valid AMB data + if (g_ambFile.kmapChunkCount == 0 || g_ambFile.prgmChunkCount == 0 || g_ambFile.midi.trackCount == 0) { + MessageBox(NULL, "AMB file has missing data or is invalid", "Debug", MB_OK); + return; + } + + // Calculate seconds per tick for timing + float secondsPerTick = 0.0f; + if (g_ambFile.midi.ticksPerQuarterNote > 0) { + secondsPerTick = g_ambFile.midi.secondsPerQuarterNote / g_ambFile.midi.ticksPerQuarterNote; + } + + // Collect all row data before sorting + RowData rowData[MAX_SOUND_TRACKS]; + int rowDataCount = 0; + + // Process each MIDI sound track + int soundTrackCount = g_ambFile.midi.trackCount - 1; // Minus one to exclude the info track + for (int trackIndex = 0; trackIndex < soundTrackCount; trackIndex++) { + SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; + + int prgmIndex = GetReferencedPrgmIfValid(trackIndex); + if (prgmIndex < 0) + continue; // No valid Prgm, skip this track + PrgmChunk *matchingPrgm = &g_ambFile.prgmChunks[prgmIndex]; + + // Get the var name from the matching Prgm chunk + const char *varName = matchingPrgm->varName; + + // Find corresponding Kmap chunk with the same var name + KmapChunk *matchingKmap = NULL; + int kmapIndex = -1; + for (int i = 0; i < g_ambFile.kmapChunkCount; i++) { + if (strcmp(g_ambFile.kmapChunks[i].varName, varName) == 0) { + matchingKmap = &g_ambFile.kmapChunks[i]; + kmapIndex = i; + break; + } + } + + if (matchingKmap == NULL || matchingKmap->itemCount == 0) { + continue; // Skip if no matching Kmap found or no items in Kmap + } + + float timestamp = track->deltaTimeNoteOn * secondsPerTick; + float duration = track->deltaTimeNoteOff * secondsPerTick; + + // Check flags for randomization settings (LSB = speed random, bit 1 = volume random) + bool hasSpeedRandom = (matchingPrgm->flags & 0x01) != 0; + bool hasVolumeRandom = (matchingPrgm->flags & 0x02) != 0; + + // For each item in the kmap (usually just one WAV file per track) + for (int j = 0; j < matchingKmap->itemCount; j++) { + if (rowDataCount >= MAX_SOUND_TRACKS) { + break; // Prevent overflow + } + + // Collect row data + RowData *row = &rowData[rowDataCount]; + row->rowInfo.trackIndex = trackIndex; + row->rowInfo.kmapIndex = kmapIndex; + row->rowInfo.prgmIndex = prgmIndex; + row->rowInfo.kmapItemIndex = j; + row->timestamp = timestamp; + row->duration = duration; + row->hasSpeedRandom = hasSpeedRandom; + row->hasVolumeRandom = hasVolumeRandom; + + // Format strings + snprintf(row->timeStr, sizeof(row->timeStr), "%04.3f", timestamp); + snprintf(row->durationStr, sizeof(row->durationStr), "%04.3f", duration); + strncpy(row->wavFileName, matchingKmap->items[j].wavFileName, sizeof(row->wavFileName) - 1); + row->wavFileName[sizeof(row->wavFileName) - 1] = '\0'; + snprintf(row->speedMaxStr, sizeof(row->speedMaxStr), "%d", matchingPrgm->maxRandomSpeed); + snprintf(row->speedMinStr, sizeof(row->speedMinStr), "%d", matchingPrgm->minRandomSpeed); + snprintf(row->volumeMaxStr, sizeof(row->volumeMaxStr), "%d", matchingPrgm->maxRandomVolume); + snprintf(row->volumeMinStr, sizeof(row->volumeMinStr), "%d", matchingPrgm->minRandomVolume); + + rowDataCount++; + } + } + + // Sort rows by timestamp + qsort(rowData, rowDataCount, sizeof(RowData), CompareRowsByTimestamp); + + // Add sorted rows to ListView + for (int i = 0; i < rowDataCount; i++) { + RowData *row = &rowData[i]; + + // Add the item to the ListView + int listRow = AddListViewItem(g_hwndListView, 0x7FFFFFFF, row->timeStr); + if (listRow >= 0) { + // Store the track info for this row + g_rowInfo[g_rowCount] = row->rowInfo; + g_rowCount++; + + // Set all the column values + SetListViewItemText(g_hwndListView, listRow, COL_DURATION, row->durationStr, FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_WAV_FILE, row->wavFileName, FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_SPEED_RANDOM, row->hasSpeedRandom ? "Yes" : "No", FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_SPEED_MIN, row->speedMinStr, FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_SPEED_MAX, row->speedMaxStr, FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_RANDOM, row->hasVolumeRandom ? "Yes" : "No", FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_MIN, row->volumeMinStr, FALSE); + SetListViewItemText(g_hwndListView, listRow, COL_VOLUME_MAX, row->volumeMaxStr, FALSE); + } + } + + // Update the overall duration display + UpdateOverallDuration(); +} + +// Handle the beginning of a ListView label edit +BOOL HandleBeginLabelEdit(HWND hwnd, NMLVDISPINFOA *pInfo) +{ + // You can reject edits for specific columns or rows if needed + // For now, allow editing all cells + return TRUE; // Return TRUE to allow the edit, FALSE to prevent it +} + +// Apply an edit to the AMB file data structure. Returns TRUE if the edit was accepted or FALSE if it was invalid. If the edit was accepted, the new +// text is written to outFormattedText in a way that is consistent with the usual format of the ListView display (e.g. float fields are formatted +// to 3 decimal places). If the new text exactly matches the current cell text, the edit is accepted but no snapshot is taken and no AMB data is modified. +// outFormattedText must not be NULL and formattedTextBufferSize must be at least 1. +BOOL ApplyEditToAmbFile(HWND hwnd, int row, int col, const char *newText, char * outFormattedText, int formattedTextBufferSize) +{ + // Make sure we have valid row info + if (row >= g_rowCount) { + MessageBox(hwnd, "Invalid row index", "Error", MB_OK | MB_ICONERROR); + return FALSE; + } + + // Get the track information for this row + AmbRowInfo *rowInfo = &g_rowInfo[row]; + int trackIndex = rowInfo->trackIndex; + int kmapIndex = rowInfo->kmapIndex; + int prgmIndex = rowInfo->prgmIndex; + int kmapItemIndex = rowInfo->kmapItemIndex; + + // Check if indices are valid + if (trackIndex < 0 || trackIndex >= g_ambFile.midi.trackCount || + kmapIndex < 0 || kmapIndex >= g_ambFile.kmapChunkCount || + prgmIndex < 0 || prgmIndex >= g_ambFile.prgmChunkCount || + kmapItemIndex < 0 || kmapItemIndex >= g_ambFile.kmapChunks[kmapIndex].itemCount) { + + MessageBox(hwnd, "Invalid track indices", "Error", MB_OK | MB_ICONERROR); + return FALSE; + } + + // Check if new text matches the current value in the cell - if so, accept without changing anything + char currentText[256] = {0}; + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = row; + lvi.iSubItem = col; + lvi.pszText = currentText; + lvi.cchTextMax = sizeof(currentText); + SendMessage(g_hwndListView, LVM_GETITEMTEXT, row, (LPARAM)&lvi); + + if (strcmp(newText, currentText) == 0) { + // Text unchanged - accept edit but don't modify data or take snapshot + strncpy(outFormattedText, newText, formattedTextBufferSize); + outFormattedText[formattedTextBufferSize - 1] = '\0'; + return TRUE; + } + + // Get references to the actual AMB data structures + PrgmChunk *prgm = &g_ambFile.prgmChunks[prgmIndex]; + KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; + + // Update the appropriate field based on the column that was edited + BOOL newTextIsValid = TRUE; + switch (col) { + case COL_TIME: + { + char * afterParsing; + float newTime = strtod(newText, &afterParsing); + if (afterParsing != newText) { + SnapshotCurrentFile(); + + float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; + g_ambFile.midi.soundTracks[trackIndex].deltaTimeNoteOn = round(newTime * ticksPerSecond); + + snprintf(outFormattedText, formattedTextBufferSize, "%04.3f", newTime); + + // Update overall duration since timestamp changed + UpdateOverallDuration(); + + } else { + newTextIsValid = FALSE; + } + } + break; + + case COL_DURATION: + { + char * afterParsing; + float newDuration = strtod(newText, &afterParsing); + if (afterParsing != newText) { + SnapshotCurrentFile(); + + float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; + g_ambFile.midi.soundTracks[trackIndex].deltaTimeNoteOff = round(newDuration * ticksPerSecond); + + snprintf(outFormattedText, formattedTextBufferSize, "%04.3f", newDuration); + + // Update overall duration since duration changed + UpdateOverallDuration(); + + } else { + newTextIsValid = FALSE; + } + } + break; + + case COL_WAV_FILE: // WAV filename + // Reject the edit if the new text contains a slash + if ((strchr(newText, '\\') == NULL) && (strchr(newText, '/') == NULL)) { + SnapshotCurrentFile(); + + // Write new text to kmap item + strncpy(kmap->items[kmapItemIndex].wavFileName, newText, sizeof(kmap->items[kmapItemIndex].wavFileName) - 1); + kmap->items[kmapItemIndex].wavFileName[sizeof(kmap->items[kmapItemIndex].wavFileName) - 1] = '\0'; + + // Update Kmap size + kmap->size = ComputeKmapChunkSize(kmap); + + // Write new text to formatted output + strncpy(outFormattedText, newText, formattedTextBufferSize); + } else { + newTextIsValid = FALSE; + } + break; + + case COL_SPEED_RANDOM: // Speed Random flag + { + if (strcmp(newText, "Yes") == 0 || strcmp(newText, "No") == 0) { + SnapshotCurrentFile(); + + if (strcmp(newText, "Yes") == 0) { + prgm->flags |= 0x01; // Set bit 0 + } else { + prgm->flags &= ~0x01; // Clear bit 0 + } + + strncpy(outFormattedText, (prgm->flags & 0x01) ? "Yes" : "No", formattedTextBufferSize); + } else { + newTextIsValid = FALSE; + } + } + break; + + case COL_SPEED_MIN: // Speed Min + if (IsValidInteger(newText)) { + SnapshotCurrentFile(); + prgm->minRandomSpeed = atoi(newText); + snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->minRandomSpeed); + } else { + newTextIsValid = FALSE; + } + break; + + case COL_SPEED_MAX: // Speed Max + if (IsValidInteger(newText)) { + SnapshotCurrentFile(); + prgm->maxRandomSpeed = atoi(newText); + snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->maxRandomSpeed); + } else { + newTextIsValid = FALSE; + } + break; + + case COL_VOLUME_RANDOM: // Volume Random flag + { + if (strcmp(newText, "Yes") == 0 || strcmp(newText, "No") == 0) { + SnapshotCurrentFile(); + + if (strcmp(newText, "Yes") == 0) { + prgm->flags |= 0x02; // Set bit 1 + } else { + prgm->flags &= ~0x02; // Clear bit 1 + } + + strncpy(outFormattedText, (prgm->flags & 0x02) ? "Yes" : "No", formattedTextBufferSize); + } else { + newTextIsValid = FALSE; + } + } + break; + + case COL_VOLUME_MIN: // Volume Min + if (IsValidInteger(newText)) { + SnapshotCurrentFile(); + prgm->minRandomVolume = atoi(newText); + snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->minRandomVolume); + } else { + newTextIsValid = FALSE; + } + break; + + case COL_VOLUME_MAX: // Volume Max + if (IsValidInteger(newText)) { + SnapshotCurrentFile(); + prgm->maxRandomVolume = atoi(newText); + snprintf(outFormattedText, formattedTextBufferSize, "%d", prgm->maxRandomVolume); + } else { + newTextIsValid = FALSE; + } + break; + } + + // Play error beep if new text didn't validate. If it did that means we wrote something to outFormattedText so make sure it's null terminated. + if (! newTextIsValid) + MessageBeep(MB_ICONERROR); + else + outFormattedText[formattedTextBufferSize - 1] = '\0'; + + return newTextIsValid; +} + +void DeleteKmapChunk(int kmapIndex) +{ + // Shift all Kmap chunks after this one forward + for (int i = kmapIndex; i < g_ambFile.kmapChunkCount - 1; i++) { + memcpy(&g_ambFile.kmapChunks[i], &g_ambFile.kmapChunks[i + 1], sizeof(KmapChunk)); + } + g_ambFile.kmapChunkCount--; +} + +void DeletePrgmChunk(int prgmIndex) +{ + // Shift all Prgm chunks after this one forward + for (int i = prgmIndex; i < g_ambFile.prgmChunkCount - 1; i++) { + memcpy(&g_ambFile.prgmChunks[i], &g_ambFile.prgmChunks[i + 1], sizeof(PrgmChunk)); + } + g_ambFile.prgmChunkCount--; + + // Update the number field of any remaining Prgm chunks - they are 1-based + for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { + g_ambFile.prgmChunks[i].number = i + 1; + } + + // Update channelNumber in all MIDI sound tracks for any that reference + // Prgm chunks with indices greater than the one we deleted + for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track + SoundTrack *track = &g_ambFile.midi.soundTracks[i]; + + // Check all control change events + for (int j = 0; j < track->controlChangeCount; j++) { + if (track->controlChanges[j].channelNumber > prgmIndex) { + track->controlChanges[j].channelNumber--; + } + } + + // Check program change event + if (track->programChange.channelNumber > prgmIndex) { + track->programChange.channelNumber--; + } + + // Update programNumber if it references deleted program or those after it + // Note: programNumbers are 1-based (matching the Prgm number field) + if (track->programChange.programNumber == prgmIndex + 1) { + // This is referencing the deleted program - we'd need to update it + // to a valid program or potentially disable this track + // For now, if there are other programs, use the first available one + if (g_ambFile.prgmChunkCount > 0) { + track->programChange.programNumber = 1; // Use first available program (1-based) + } + } + else if (track->programChange.programNumber > prgmIndex + 1) { + // This references a program that got shifted down, so update the index + track->programChange.programNumber--; + } + + // Check note on event + if (track->noteOn.channelNumber > prgmIndex) { + track->noteOn.channelNumber--; + } + + // Check note off event + if (track->noteOff.channelNumber > prgmIndex) { + track->noteOff.channelNumber--; + } + } +} + +void DeleteSoundTrack(int trackIndex) +{ + for (int i = trackIndex; i < g_ambFile.midi.trackCount - 2; i++) { // -2 because we skip info track (0) and want to leave room for the last valid track + memcpy(&g_ambFile.midi.soundTracks[i], &g_ambFile.midi.soundTracks[i + 1], sizeof(SoundTrack)); + } + g_ambFile.midi.trackCount--; +} + +void DeleteRow(int row) +{ + // If no file loaded or row is invalid, do nothing + if (g_ambFile.filePath[0] == '\0' || row < 0 || row >= g_rowCount) { + MessageBox(NULL, "Invalid row or no AMB file loaded", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Get the references to the chunks and tracks we need to work with + AmbRowInfo *rowInfo = &g_rowInfo[row]; + int trackIndex = rowInfo->trackIndex; + int kmapIndex = rowInfo->kmapIndex; + int prgmIndex = rowInfo->prgmIndex; + + // Take a snapshot before making changes + SnapshotCurrentFile(); + + // First, check if the Kmap chunk is referenced by other Prgm chunks + KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; + const char *kmapVarName = kmap->varName; + int kmapReferenceCount = 0; + + for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { + if (strcmp(g_ambFile.prgmChunks[i].varName, kmapVarName) == 0) { + kmapReferenceCount++; + } + } + + // Delete the Kmap chunk if it's only referenced by the Prgm we're deleting + if (kmapReferenceCount <= 1) { + DeleteKmapChunk(kmapIndex); + } + + // Next, check if the Prgm chunk is referenced by other MIDI tracks + int prgmReferenceCount = 0; + for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track + if (GetReferencedPrgmIfValid(i) == prgmIndex) + prgmReferenceCount++; + } + + // Delete the Prgm chunk if it's only referenced by the track we're deleting + if (prgmReferenceCount <= 1) { + DeletePrgmChunk(prgmIndex); + } + + // Delete the MIDI track + DeleteSoundTrack(trackIndex); + + // Refresh the ListView to show updated AMB data + PopulateAmbListView(); +} + +void AddRow() +{ + // If no file is loaded or we're already at the limit of how many sound tracks, prgm chunks, or kmap chunks we can have one file, report an + // error then return. + if (g_ambFile.filePath[0] == '\0') { + MessageBox(NULL, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); + return; + } + + if (g_ambFile.kmapChunkCount >= MAX_CHUNKS) { + MessageBox(NULL, "Cannot add more rows: Maximum number of Kmap chunks reached.", "Error", MB_OK | MB_ICONERROR); + return; + } + + if (g_ambFile.prgmChunkCount >= MAX_CHUNKS) { + MessageBox(NULL, "Cannot add more rows: Maximum number of Prgm chunks reached.", "Error", MB_OK | MB_ICONERROR); + return; + } + + if (g_ambFile.midi.trackCount >= MAX_SOUND_TRACKS + 1) { // +1 because first track is info track + MessageBox(NULL, "Cannot add more rows: Maximum number of sound tracks reached.", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Snapshot file + SnapshotCurrentFile(); + + // Find a unique name + char uniqueName[32]; + int nameCounter = 1; + bool nameIsUnique; + + do { + snprintf(uniqueName, sizeof(uniqueName), "NewTrack%d", nameCounter++); + nameIsUnique = true; + + // Check if this name is already used as a track name + for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track + if (strcmp(g_ambFile.midi.soundTracks[i].trackName.name, uniqueName) == 0) { + nameIsUnique = false; + break; + } + } + + // Check if this name is already used as a var name or effect name + if (nameIsUnique) { + for (int i = 0; i < g_ambFile.prgmChunkCount; i++) { + if (strcmp(g_ambFile.prgmChunks[i].varName, uniqueName) == 0 || + strcmp(g_ambFile.prgmChunks[i].effectName, uniqueName) == 0) { + nameIsUnique = false; + break; + } + } + } + + // Check if this name is already used as a kmap var name + if (nameIsUnique) { + for (int i = 0; i < g_ambFile.kmapChunkCount; i++) { + if (strcmp(g_ambFile.kmapChunks[i].varName, uniqueName) == 0) { + nameIsUnique = false; + break; + } + } + } + } while (!nameIsUnique && nameCounter < 1000); // Prevent infinite loop + + if (!nameIsUnique) { + MessageBox(NULL, "Failed to generate a unique name for new row.", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Create a Kmap chunk + int kmapIndex = g_ambFile.kmapChunkCount; + KmapChunk *kmap = &g_ambFile.kmapChunks[kmapIndex]; + + // Initialize the Kmap chunk + memset(kmap, 0, sizeof(KmapChunk)); + + kmap->flags = 2; // Standard flags value in Civ3 AMBs + kmap->itemCount = 1; + kmap->itemSize = 12; + + // Set the varName to our unique name + strcpy(kmap->varName, uniqueName); + + // Initialize the Kmap item + static const unsigned char kmapItemData[12] = { 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }; + memcpy(kmap->items[0].data, kmapItemData, 12); + strcpy(kmap->items[0].wavFileName, "<.wav file name>"); + + // Calculate the size of the Kmap chunk + kmap->size = ComputeKmapChunkSize(kmap); + + // Increment the Kmap count + g_ambFile.kmapChunkCount++; + + // Create a Prgm chunk + int prgmIndex = g_ambFile.prgmChunkCount; + PrgmChunk *prgm = &g_ambFile.prgmChunks[prgmIndex]; + + // Initialize the Prgm chunk + memset(prgm, 0, sizeof(PrgmChunk)); + + // Fill in names and set number (1-based) + strcpy(prgm->effectName, uniqueName); + strcpy(prgm->varName, uniqueName); + prgm->number = prgmIndex + 1; + + // Calculate the size of the Prgm chunk + prgm->size = ComputePrgmChunkSize(prgm); + + // Increment the Prgm count + g_ambFile.prgmChunkCount++; + + // Create a sound track + int trackIndex = g_ambFile.midi.trackCount - 1; // Index for the new track (after info track) + SoundTrack *track = &g_ambFile.midi.soundTracks[trackIndex]; + + // Initialize the sound track + memset(track, 0, sizeof(SoundTrack)); + + // Set track name + track->deltaTimeTrackName = 0; + strcpy(track->trackName.name, uniqueName); + + // Add one control change event + track->controlChangeCount = 1; + track->deltaTimeControlChanges[0] = 0; + track->controlChanges[0].channelNumber = prgmIndex; // 0-based index + track->controlChanges[0].controllerNumber = 32; + track->controlChanges[0].value = 0; + + // Set program change event + track->deltaTimeProgramChange = 0; + track->programChange.channelNumber = prgmIndex; // 0-based index + track->programChange.programNumber = prgmIndex + 1; // 1-based number + + // Find a unique key for the note on/off events + int keyValue = 60; // Start at middle C + bool keyIsUnique; + + do { + keyIsUnique = true; + + // Check if this key is already used in any other track + for (int i = 0; i < g_ambFile.midi.trackCount - 1; i++) { // Skip info track + if (i != trackIndex && g_ambFile.midi.soundTracks[i].noteOn.key == keyValue) { + keyIsUnique = false; + keyValue++; + break; + } + } + } while (!keyIsUnique && keyValue < 127); + + // Set note on event + track->deltaTimeNoteOn = 0; + track->noteOn.channelNumber = prgmIndex; // 0-based index + track->noteOn.key = keyValue; + track->noteOn.velocity = 64; // Medium velocity + + // Set note off event - one second after note on + float ticksPerSecond = g_ambFile.midi.ticksPerQuarterNote / g_ambFile.midi.secondsPerQuarterNote; + track->deltaTimeNoteOff = (int)ticksPerSecond; // 1 second duration + track->noteOff.channelNumber = prgmIndex; // 0-based index + track->noteOff.key = keyValue; + track->noteOff.velocity = 64; // Same as note on + + // Set end of track + track->deltaTimeEndOfTrack = 0; + + // Calculate the size of the sound track + track->size = ComputeSoundTrackSize(track); + + // Increment the track count + g_ambFile.midi.trackCount++; + + // Refresh the ListView + PopulateAmbListView(); +} + +void Prune() +{ + if (g_ambFile.filePath[0] == '\0') { + MessageBox(NULL, "No AMB file loaded. Please load a file first.", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Make sure the ListView is up to date. We're going to delete any Kmap or Prgm chunks and any sound tracks that don't appear in it. + PopulateAmbListView(); + + int unneededKmapCount = 0; + int unneededPrgmCount = 0; + int unneededTrackCount = 0; + bool tookSnapshot = false; + + for (int kmapIndex = g_ambFile.kmapChunkCount - 1; kmapIndex >= 0; kmapIndex--) { + bool inAnyRow = false; + for (int i = 0; i < g_rowCount; i++) { + if (g_rowInfo[i].kmapIndex == kmapIndex) { + inAnyRow = true; + break; + } + } + if (! inAnyRow) { + if (! tookSnapshot) { + SnapshotCurrentFile(); + tookSnapshot = true; + } + DeleteKmapChunk(kmapIndex); + unneededKmapCount++; + } + } + + for (int prgmIndex = g_ambFile.prgmChunkCount - 1; prgmIndex >= 0; prgmIndex--) { + bool inAnyRow = false; + for (int i = 0; i < g_rowCount; i++) { + if (g_rowInfo[i].prgmIndex == prgmIndex) { + inAnyRow = true; + break; + } + } + if (! inAnyRow) { + if (! tookSnapshot) { + SnapshotCurrentFile(); + tookSnapshot = true; + } + DeletePrgmChunk(prgmIndex); + unneededPrgmCount++; + } + } + + for (int trackIndex = g_ambFile.midi.trackCount - 2; trackIndex >= 0; trackIndex--) { // Skip info track + bool inAnyRow = false; + for (int i = 0; i < g_rowCount; i++) { + if (g_rowInfo[i].trackIndex == trackIndex) { + inAnyRow = true; + break; + } + } + if (! inAnyRow) { + if (! tookSnapshot) { + SnapshotCurrentFile(); + tookSnapshot = true; + } + DeleteSoundTrack(trackIndex); + unneededTrackCount++; + } + } + + if ((unneededKmapCount == 0) && (unneededPrgmCount == 0) && (unneededTrackCount == 0)) { + MessageBox(NULL, "The AMB data has no superfluous parts.", "Nothing to do", MB_OK | MB_ICONINFORMATION); + } else { + char msg[300] = {0}; + snprintf (msg, (sizeof msg) - 1, "Deleted %d unused Kmap chunk%s, %d unused Prgm chunk%s, and %d unused or invalid MIDI track%s.", + unneededKmapCount , unneededKmapCount == 1 ? "" : "s", + unneededPrgmCount , unneededPrgmCount == 1 ? "" : "s", + unneededTrackCount, unneededTrackCount == 1 ? "" : "s"); + MessageBox(NULL, msg, "Pruning results", MB_OK | MB_ICONINFORMATION); + + PopulateAmbListView(); + } +} + +// Handle the end of a ListView label edit +BOOL HandleEndLabelEdit(HWND hwnd, NMLVDISPINFOA *pInfo) +{ + // Check if the edit was cancelled + if (pInfo->item.pszText == NULL) { + return FALSE; // Edit was cancelled, no update needed + } + + // Get the row and column (subitem) being edited + int row = pInfo->item.iItem; + int col = pInfo->item.iSubItem; + char *newText = pInfo->item.pszText; + + // Apply the edit to the AMB file data structure + char formattedText[256]; + BOOL editAccepted = ApplyEditToAmbFile(hwnd, row, col, newText, formattedText, sizeof formattedText); + if (editAccepted) { + SetListViewItemText(g_hwndListView, row, col, formattedText, TRUE); + } + return editAccepted; +} + +// Global variables to track the current edit control's position +int g_editRow = -1; +int g_editCol = -1; +HWND g_hwndEdit = NULL; +WNDPROC g_oldEditProc = NULL; // Original window procedure for the edit control + +// Custom window procedure for the edit control to handle keyboard input +LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_KEYDOWN: + switch (wParam) + { + case VK_RETURN: + // Enter key - accept changes and destroy edit control + if (g_hwndEdit != NULL && g_editRow >= 0 && g_editCol >= 0) { + char buffer[256]; + GetWindowText(g_hwndEdit, buffer, sizeof(buffer)); + + // Apply the edit to the AMB file data structure and update the ListView with the formatted text + char formattedBuffer[256]; + if (ApplyEditToAmbFile(GetParent(GetParent(hwnd)), g_editRow, g_editCol, buffer, formattedBuffer, sizeof formattedBuffer)) { + SetListViewItemText(g_hwndListView, g_editRow, g_editCol, formattedBuffer, TRUE); + } + + // Destroy the edit control + DestroyWindow(g_hwndEdit); + g_hwndEdit = NULL; + g_editRow = -1; + g_editCol = -1; + } + return 0; + + case VK_ESCAPE: + // Escape key - cancel edit + if (g_hwndEdit != NULL) { + DestroyWindow(g_hwndEdit); + g_hwndEdit = NULL; + g_editRow = -1; + g_editCol = -1; + } + return 0; + } + break; + } + + // Call the original window procedure for other messages + return CallWindowProc(g_oldEditProc, hwnd, uMsg, wParam, lParam); +} + +// Returns the currently selected row and whether or not any was selected. Optionally displays an error when none is selected. +bool GetSelectedRow(char const * errorMsg, int * outSelectedRow) +{ + int rowCount = SendMessage(g_hwndListView, LVM_GETITEMCOUNT, 0, 0); + for (int i = 0; i < rowCount; i++) { + UINT state = SendMessage(g_hwndListView, LVM_GETITEMSTATE, i, LVIS_SELECTED); + if (state & LVIS_SELECTED) { + *outSelectedRow = i; + return true; + } + } + + // If we get here, no row was selected + if (errorMsg) + MessageBox(NULL, errorMsg, "Information", MB_OK | MB_ICONINFORMATION); + return false; +} + +// Function to match duration to WAV file for the selected row +void MatchDurationToWav(HWND hwndListView) +{ + int selectedRow; + if (! GetSelectedRow("Please select a row to match duration", &selectedRow)) + return; + + // Make sure we have valid row info + if (selectedRow >= g_rowCount) { + MessageBox(NULL, "Invalid row selection", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Get the WAV filename from the selected row + char wavFileName[256] = {0}; + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = selectedRow; + lvi.iSubItem = COL_WAV_FILE; + lvi.pszText = wavFileName; + lvi.cchTextMax = sizeof(wavFileName); + SendMessage(hwndListView, LVM_GETITEMTEXT, selectedRow, (LPARAM)&lvi); + + if (strlen(wavFileName) == 0) { + MessageBox(NULL, "No WAV filename found in selected row", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Construct full path to WAV file (assuming it's in the same directory as the AMB file) + Path wavFilePath; + strcpy(wavFilePath, g_ambFile.filePath); + PathRemoveFileSpec(wavFilePath); // Remove filename, keep directory + PathAppend(wavFilePath, wavFileName); + + // Get WAV file duration + float wavDuration; + if (!GetWavFileDuration(wavFilePath, &wavDuration)) { + char errorMsg[512]; + snprintf(errorMsg, sizeof(errorMsg), "Could not read duration from WAV file:\n%s\n\nMake sure the file exists and is a valid WAV file.", wavFilePath); + MessageBox(NULL, errorMsg, "Error", MB_OK | MB_ICONERROR); + return; + } + + // Convert duration to string and apply it to the AMB file + char durationStr[32]; + snprintf(durationStr, sizeof(durationStr), "%.3f", wavDuration); + + char formattedText[256]; + if (ApplyEditToAmbFile(GetParent(hwndListView), selectedRow, COL_DURATION, durationStr, formattedText, sizeof(formattedText))) { + SetListViewItemText(hwndListView, selectedRow, COL_DURATION, formattedText, TRUE); + } else { + MessageBeep(MB_ICONERROR); + } +} + +// Function to programmatically start editing a ListView subitem +void EditListViewSubItem(HWND hwndListView, int row, int col) +{ + // First select the item + LVITEMA lvi = {0}; + lvi.stateMask = LVIS_SELECTED; + lvi.state = LVIS_SELECTED; + SendMessage(hwndListView, LVM_SETITEMSTATE, row, (LPARAM)&lvi); + + // For subitems, we need to create a custom edit control + // First get the text of the subitem + char buffer[256] = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = row; + lvi.iSubItem = col; + lvi.pszText = buffer; + lvi.cchTextMax = sizeof(buffer); + SendMessage(hwndListView, LVM_GETITEMTEXT, row, (LPARAM)&lvi); + + // Create a structure for LVM_GETSUBITEMRECT + // The struct needs to have subItem in top and flags in left + RECT rect; + memset(&rect, 0, sizeof(RECT)); + rect.top = col; // subItem index + rect.left = LVIR_BOUNDS; // Type of rectangle (LVIR_BOUNDS for entire cell) + SendMessage(hwndListView, LVM_GETSUBITEMRECT, row, (LPARAM)&rect); + + // If we already have an edit control, destroy it + if (g_hwndEdit != NULL) { + DestroyWindow(g_hwndEdit); + g_hwndEdit = NULL; + } + + // For column 0 (Time), we need to adjust the width to match the column width + // instead of using the full row width that LVIR_BOUNDS returns + if (col == COL_TIME) { + // Get the width of column 0 + LVCOLUMNA lvc = {0}; + lvc.mask = LVCF_WIDTH; + SendMessage(hwndListView, LVM_GETCOLUMN, COL_TIME, (LPARAM)&lvc); + + // Adjust the rectangle to match the column width + rect.right = rect.left + lvc.cx; + } + + // Create an edit control over the subitem + g_hwndEdit = CreateWindow( + "EDIT", buffer, + WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + hwndListView, (HMENU)1000, GetModuleHandle(NULL), NULL); + + if (g_hwndEdit) { + // Store which row and column we're editing + g_editRow = row; + g_editCol = col; + + // Subclass the edit control to handle keyboard input + g_oldEditProc = (WNDPROC)SetWindowLongPtr(g_hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditSubclassProc); + + // Set focus to the edit control and select all text + SetFocus(g_hwndEdit); + SendMessage(g_hwndEdit, EM_SETSEL, 0, -1); + } +} + +// Calculate and update the overall duration display +void UpdateOverallDuration(void) +{ + if (g_hwndDurationLabel == NULL) { + return; + } + + float maxEndTime = 0.0f; + + // Check if we have valid AMB data + if (g_ambFile.kmapChunkCount == 0 || g_ambFile.prgmChunkCount == 0 || g_ambFile.midi.trackCount == 0) { + SetWindowText(g_hwndDurationLabel, "Overall Duration: 0.000 sec"); + return; + } + + // Calculate seconds per tick for timing + float secondsPerTick = 0.0f; + if (g_ambFile.midi.ticksPerQuarterNote > 0) { + secondsPerTick = g_ambFile.midi.secondsPerQuarterNote / g_ambFile.midi.ticksPerQuarterNote; + } + + // Process each MIDI sound track to find the longest duration + int soundTrackCount = g_ambFile.midi.trackCount - 1; // Minus one to exclude the info track + for (int trackIndex = 0; trackIndex < soundTrackCount; trackIndex++) { + SoundTrack * track = &g_ambFile.midi.soundTracks[trackIndex]; + + int prgmIndex = GetReferencedPrgmIfValid(trackIndex); + if (prgmIndex < 0) + continue; // No valid Prgm, skip this track + + float timestamp = track->deltaTimeNoteOn * secondsPerTick; + float duration = track->deltaTimeNoteOff * secondsPerTick; + float endTime = timestamp + duration; + + if (endTime > maxEndTime) { + maxEndTime = endTime; + } + } + + // Update the label text + char durationText[64] = {0}; + snprintf(durationText, sizeof(durationText) - 1, "Overall Duration: %04.3f sec", maxEndTime); + SetWindowText(g_hwndDurationLabel, durationText); +} + +// Create and initialize the ListView control +void CreateAmbListView(HWND hwnd) +{ + // Create ListView control below the playback buttons + g_hwndListView = CreateWindow( + WC_LISTVIEW, + "", + WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_NOHSCROLL | LVS_EDITLABELS, + 20, 70, // x, y position (below the buttons) + 835, 460, // width, height (fill most of the window) + hwnd, + (HMENU)ID_AMB_LISTVIEW, + GetModuleHandle(NULL), + NULL + ); + + if (g_hwndListView == NULL) { + MessageBox(hwnd, "Could not create ListView control", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Set extended ListView styles + DWORD exStyle = LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES; + SendMessage(g_hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle); + + // Add columns to the ListView + AddListViewColumn(g_hwndListView, COL_TIME, "Time (sec.)", 85); + AddListViewColumn(g_hwndListView, COL_DURATION, "Duration (sec.)", 95); + AddListViewColumn(g_hwndListView, COL_WAV_FILE, "WAV File", 235); + AddListViewColumn(g_hwndListView, COL_SPEED_RANDOM, "Speed Rnd", 70); + AddListViewColumn(g_hwndListView, COL_SPEED_MIN, "Speed Min", 70); + AddListViewColumn(g_hwndListView, COL_SPEED_MAX, "Speed Max", 70); + AddListViewColumn(g_hwndListView, COL_VOLUME_RANDOM, "Vol. Rnd", 70); + AddListViewColumn(g_hwndListView, COL_VOLUME_MIN, "Vol. Min", 70); + AddListViewColumn(g_hwndListView, COL_VOLUME_MAX, "Vol. Max", 70); + + // Create duration label below the ListView + g_hwndDurationLabel = CreateWindow( + "STATIC", + "Overall Duration: 0.000 sec", + WS_CHILD | WS_VISIBLE | SS_LEFT, + 20, 540, // x, y position (below the ListView) + 250, 20, // width, height + hwnd, + NULL, + GetModuleHandle(NULL), + NULL + ); +} + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + // Read INI settings + { + Path iniFullPath; + GetCurrentDirectory(PATH_BUFFER_SIZE, iniFullPath); + PathAppend(iniFullPath, "amb_editor.ini"); + + GetPrivateProfileString("Paths", "civ_3_install_path", "", g_iniCiv3InstallPath, PATH_BUFFER_SIZE, iniFullPath); + GetPrivateProfileString("Paths", "sound_dll_path" , "", g_iniSoundDLLPath , PATH_BUFFER_SIZE, iniFullPath); + GetPrivateProfileString("Paths", "temp_directory" , "", g_iniTempDirectory , PATH_BUFFER_SIZE, iniFullPath); + } + + // If we've been given a specific Civ 3 install path in the INI, use that. Otherwise search for one. + if (strlen(g_iniCiv3InstallPath) > 0) { + strcpy(g_civ3MainPath, g_iniCiv3InstallPath); + } else { + FindCiv3Installation(hwnd); + } + + g_hwndMainWindow = hwnd; + + // Create playback buttons + CreatePlaybackButtons(hwnd); + + // Create the AMB ListView control + CreateAmbListView(hwnd); + + return 0; + + case WM_COMMAND: + // Handle menu commands + switch (LOWORD(wParam)) + { + case IDM_FILE_OPEN: + // Show open file dialog to load an AMB file + LoadAmbFileWithDialog(hwnd); + return 0; + + case IDM_FILE_SAVE: + // Save AMB file directly + SaveAmbFileDirectly(hwnd); + return 0; + + case IDM_FILE_SAVE_AS: + // Show save file dialog to save AMB file as + SaveAmbFileAs(hwnd); + return 0; + + case IDM_FILE_DETAILS: + // Show window with AMB file details + ShowAmbDetailsWindow(hwnd); + return 0; + + case IDM_FILE_EXIT: + // Exit the application + PostMessage(hwnd, WM_CLOSE, 0, 0); + return 0; + + case IDM_EDIT_UNDO: + // Perform undo operation + Undo(); + return 0; + + case IDM_EDIT_REDO: + // Perform redo operation + Redo(); + return 0; + + case IDM_EDIT_ADD: + // Add a new row + AddRow(); + return 0; + + case IDM_EDIT_DELETE: + { + // Delete the selected row + int selectedRow; + if (GetSelectedRow("Please select a row to delete", &selectedRow)) + DeleteRow(selectedRow); + + return 0; + } + + case IDM_EDIT_MATCH_WAV: + // Match duration to WAV file + MatchDurationToWav(g_hwndListView); + return 0; + + case IDM_EDIT_PRUNE: + Prune(); + return 0; + + case IDM_HELP_ABOUT: + // Show about dialog + MessageBox(hwnd, + "This is a tool for inspecting and modifying the AMB sound files used by Sid Meier's Civilization III.\n\n" + "Last updated in C3X Release 23\n\n" + "For more info, see README.txt", + "About AMB Editor", + MB_OK | MB_ICONINFORMATION); + return 0; + + case ID_PLAY_BUTTON: + // Handle Play button click + if (g_ambFile.filePath[0] != '\0') { + bool encounteredError = false; + + // Check that the preview player is initialized. If it's not, try to initialize it. + if (! previewPlayerIsInitialized) { + Path soundDLLPath; + if (GetSoundDLLPath(hwnd, soundDLLPath)) { + InitializePreviewPlayer(hwnd, soundDLLPath); + } + if (! previewPlayerIsInitialized) + encounteredError = true; + } + + // Check for missing WAV files before attempting preview + if (! encounteredError) { + char missingFiles[1024]; + if (HasMissingWavFiles(missingFiles, sizeof(missingFiles))) { + char errorMsg[1280]; + snprintf(errorMsg, sizeof(errorMsg), + "Cannot preview AMB file because the following WAV files are missing:\n\n%s\n\nPlease ensure all WAV files are present in the AMB file's directory.", + missingFiles); + MessageBox(hwnd, errorMsg, "Missing WAV Files", MB_OK | MB_ICONERROR); + } + } + + if (! encounteredError) + PreviewAmbFile(g_iniTempDirectory, &g_ambFile); + } else { + MessageBox(hwnd, "No AMB file loaded. Please open an AMB file first.", + "Error", MB_OK | MB_ICONINFORMATION); + } + return 0; + + case ID_STOP_BUTTON: + // Handle Stop button click + StopAmbPreview(); + return 0; + + // Check if the command is from the edit control created for subitem editing + default: + if (LOWORD(wParam) == 1000 && HIWORD(wParam) == EN_KILLFOCUS) { + // When the edit control loses focus, get its text and update the list view item + if (g_hwndEdit != NULL && g_editRow >= 0 && g_editCol >= 0) { + char buffer[256]; + GetWindowText(g_hwndEdit, buffer, sizeof(buffer)); + + // Apply the edit to the AMB file data structure + char formattedBuffer[256]; + if (ApplyEditToAmbFile(hwnd, g_editRow, g_editCol, buffer, formattedBuffer, sizeof formattedBuffer)) { + SetListViewItemText(g_hwndListView, g_editRow, g_editCol, formattedBuffer, TRUE); + } + + // Destroy the edit control + DestroyWindow(g_hwndEdit); + g_hwndEdit = NULL; + g_editRow = -1; + g_editCol = -1; + } + return 0; + } + } + break; + + case WM_NOTIFY: + // Handle control notifications + { + NMHDR *nmhdr = (NMHDR *)lParam; + + // Check if the notification is from our ListView + if (nmhdr->hwndFrom == g_hwndListView) { + switch (nmhdr->code) { + case LVN_BEGINLABELEDIT: + // Notification when a label edit begins + return HandleBeginLabelEdit(hwnd, (NMLVDISPINFOA *)lParam); + + case LVN_ENDLABELEDIT: + // Notification when a label edit ends + return HandleEndLabelEdit(hwnd, (NMLVDISPINFOA *)lParam); + + case NM_DBLCLK: + // Handle double-click on a ListView item to edit the cell + { + NMITEMACTIVATE *nia = (NMITEMACTIVATE *)lParam; + // Only process if a valid item was clicked + if (nia->iItem != -1) { + // Check if this is a boolean column + if (nia->iSubItem == COL_SPEED_RANDOM || nia->iSubItem == COL_VOLUME_RANDOM) { + // Toggle the boolean value directly + char currentText[32]; + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = nia->iItem; + lvi.iSubItem = nia->iSubItem; + lvi.pszText = currentText; + lvi.cchTextMax = sizeof(currentText); + SendMessage(g_hwndListView, LVM_GETITEMTEXT, nia->iItem, (LPARAM)&lvi); + + // Toggle: if current is "Yes", change to "No", otherwise change to "Yes" + const char *newText = (strcmp(currentText, "Yes") == 0) ? "No" : "Yes"; + + // Apply the toggle to the AMB file data structure + char formattedText[256]; + if (ApplyEditToAmbFile(hwnd, nia->iItem, nia->iSubItem, newText, formattedText, sizeof(formattedText))) { + SetListViewItemText(g_hwndListView, nia->iItem, nia->iSubItem, formattedText, TRUE); + } + } else { + // For non-boolean columns, start editing the subitem that was clicked + EditListViewSubItem(g_hwndListView, nia->iItem, nia->iSubItem); + } + + // Tell the system we handled this message + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); + return TRUE; + } + } + break; + + case NM_CUSTOMDRAW: + // Handle custom drawing for ListView + { + LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam; + + switch (lplvcd->nmcd.dwDrawStage) { + case CDDS_PREPAINT: + // Tell Windows we want to be notified for each item + return CDRF_NOTIFYITEMDRAW; + + case CDDS_ITEMPREPAINT: + // Tell Windows we want to be notified for each subitem + return CDRF_NOTIFYSUBITEMDRAW; + + case CDDS_SUBITEM | CDDS_ITEMPREPAINT: + // Custom draw for individual cells + { + int item = (int)lplvcd->nmcd.dwItemSpec; + int subItem = lplvcd->iSubItem; + + // Check if this is the WAV file column + if (subItem == COL_WAV_FILE) { + // Get the WAV filename for this row + char wavFileName[256] = {0}; + LVITEMA lvi = {0}; + lvi.mask = LVIF_TEXT; + lvi.iItem = item; + lvi.iSubItem = COL_WAV_FILE; + lvi.pszText = wavFileName; + lvi.cchTextMax = sizeof(wavFileName); + SendMessage(g_hwndListView, LVM_GETITEMTEXT, item, (LPARAM)&lvi); + + // Check if WAV file exists + if (!CheckWavFileExists(wavFileName)) { + // Set text color to red for missing files + lplvcd->clrText = RGB(255, 0, 0); + } else { + // Use default text color + lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); + } + + return CDRF_NEWFONT; + } else if (subItem == COL_SPEED_MIN || subItem == COL_SPEED_MAX || + subItem == COL_VOLUME_MIN || subItem == COL_VOLUME_MAX) { + // Check if min/max columns should be grayed out based on flags + if (item < g_rowCount) { + AmbRowInfo *rowInfo = &g_rowInfo[item]; + if (rowInfo->prgmIndex >= 0 && rowInfo->prgmIndex < g_ambFile.prgmChunkCount) { + PrgmChunk *prgm = &g_ambFile.prgmChunks[rowInfo->prgmIndex]; + + BOOL shouldGrayOut = FALSE; + if (subItem == COL_SPEED_MIN || subItem == COL_SPEED_MAX) { + // Gray out if speed random is disabled (flags & 1 == 0) + shouldGrayOut = !(prgm->flags & 0x01); + } else { + // Gray out if volume random is disabled (flags & 2 == 0) + shouldGrayOut = !(prgm->flags & 0x02); + } + + if (shouldGrayOut) { + lplvcd->clrText = GetSysColor(COLOR_GRAYTEXT); + } else { + lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); + } + + return CDRF_NEWFONT; + } + } + + // Fallback to default color + lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); + return CDRF_NEWFONT; + } else { + // For all other columns, use default text color + lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT); + return CDRF_NEWFONT; + } + } + } + } + return CDRF_DODEFAULT; + } + } + } + break; + + case WM_ERASEBKGND: + { + // Handle window background erasure + HDC hdc = (HDC)wParam; + RECT rect; + GetClientRect(hwnd, &rect); + FillRect(hdc, &rect, g_hBackgroundBrush); + return 1; // Return non-zero to indicate we processed this message + } + + case WM_CTLCOLORDLG: + case WM_CTLCOLORSTATIC: + case WM_CTLCOLORBTN: + // Set background color for dialog, static controls, and buttons + return (LRESULT)g_hBackgroundBrush; + + case WM_CLOSE: + DestroyWindow(hwnd); + return 0; + + case WM_DESTROY: + // Clean up resources + if (g_hBackgroundBrush != NULL) { + DeleteObject(g_hBackgroundBrush); + g_hBackgroundBrush = NULL; + } + DeinitializePreviewPlayer(); + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +// Create a simple menu +HMENU CreateAmbEditorMenu() +{ + HMENU hMenu, hFileMenu, hEditMenu, hHelpMenu; + + hMenu = CreateMenu(); + + // File menu + hFileMenu = CreatePopupMenu(); + AppendMenu(hFileMenu, MF_STRING, IDM_FILE_OPEN, "&Open AMB File...\tCtrl+O"); + AppendMenu(hFileMenu, MF_STRING, IDM_FILE_SAVE, "&Save\tCtrl+S"); + AppendMenu(hFileMenu, MF_STRING, IDM_FILE_SAVE_AS, "Save &As..."); + AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hFileMenu, MF_STRING, IDM_FILE_DETAILS, "&View AMB Details"); + AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hFileMenu, MF_STRING, IDM_FILE_EXIT, "E&xit"); + + // Edit menu + hEditMenu = CreatePopupMenu(); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_UNDO, "&Undo\tCtrl+Z"); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_REDO, "&Redo\tCtrl+Y"); + AppendMenu(hEditMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_ADD, "&Add Row\tIns"); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_DELETE, "&Delete Row\tDel"); + AppendMenu(hEditMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_MATCH_WAV, "&Match duration to WAV"); + AppendMenu(hEditMenu, MF_STRING, IDM_EDIT_PRUNE, "&Prune"); + + // Help menu + hHelpMenu = CreatePopupMenu(); + AppendMenu(hHelpMenu, MF_STRING, IDM_HELP_ABOUT, "&About..."); + + // Add menus to the main menu + AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, "&File"); + AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hEditMenu, "&Edit"); + AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hHelpMenu, "&Help"); + + return hMenu; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + // Register the window class + const char CLASS_NAME[] = "AMB Editor Window Class"; + + // Create a pleasant beige brush for the background - RGB(245, 245, 220) is a nice beige color + g_hBackgroundBrush = CreateSolidBrush(RGB(245, 235, 200)); + + WNDCLASS wc = {0}; + wc.lpfnWndProc = WindowProc; + wc.hInstance = hInstance; + wc.lpszClassName = CLASS_NAME; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = g_hBackgroundBrush; + + RegisterClass(&wc); + + // Create menu + HMENU hMenu = CreateAmbEditorMenu(); + + // Create the window + HWND hwnd = CreateWindowEx( + 0, // Optional window styles + CLASS_NAME, // Window class + "AMB Editor", // Window title + WS_OVERLAPPEDWINDOW, // Window style + + // Size and position + CW_USEDEFAULT, CW_USEDEFAULT, 895, 620, + + NULL, // Parent window + hMenu, // Menu + hInstance, // Instance handle + NULL // Additional application data + ); + + if (hwnd == NULL) { + return 0; + } + + ShowWindow(hwnd, nCmdShow); + + // Create accelerator table + HACCEL hAccel = CreateAcceleratorTable(g_accelTable, sizeof(g_accelTable) / sizeof(g_accelTable[0])); + + // Run the message loop + MSG msg = {0}; + while (GetMessage(&msg, NULL, 0, 0)) { + if (!TranslateAccelerator(hwnd, hAccel, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return (int)msg.wParam; +} diff --git a/AMB Editor/amb_file.c b/AMB Editor/amb_file.c index 6a98b128..530e8e02 100644 --- a/AMB Editor/amb_file.c +++ b/AMB Editor/amb_file.c @@ -1,1536 +1,1536 @@ -// This file gets #included into amb_editor.c - -#include -#include -#include -#include -#include - -#define MAX_CHUNKS 30 // No AMB in Civ 3 has more than 12 Kmap or Prgm chunks -#define MAX_SOUND_TRACKS 30 // No AMB in Civ 3 has more than 12 sound tracks -#define MAX_CONTROL_CHANGES 2 // No AMB in Civ 3 has more than 2 control changes per track -#define MAX_ITEMS 2 // No AMB in Civ 3 has more than 1 item - -// AMB file structures for Civ 3 -typedef struct { - int size; - int number; - int flags; - int maxRandomSpeed; - int minRandomSpeed; - int maxRandomVolume; - int minRandomVolume; - char effectName[256]; - char varName[256]; -} PrgmChunk; - -typedef struct { - unsigned char data[12]; - char wavFileName[256]; -} KmapItem; - -typedef struct { - int size; - int flags; - int param1; - int param2; - char varName[256]; - int itemCount; - int itemSize; - KmapItem items[MAX_ITEMS]; -} KmapChunk; - -typedef struct { - int size; - int dataSize; - unsigned char data[12]; - unsigned char extraData[512]; - int extraDataSize; -} GlblChunk; - -// MIDI event types - specific to Civ3 AMB files -typedef struct { - char name[256]; // Always "Seq-1" in Civ3 AMBs -} TrackNameEvent; - -typedef struct { - int hr, mn, se, fr, ff; -} SMPTEOffsetEvent; - -typedef struct { - int nn, dd, cc, bb; -} TimeSignatureEvent; - -typedef struct { - int microsecondsPerQuarterNote; -} SetTempoEvent; - -typedef struct { - int channelNumber, controllerNumber, value; -} ControlChangeEvent; - -typedef struct { - int channelNumber, programNumber; -} ProgramChangeEvent; - -typedef struct { - int channelNumber, key, velocity; -} NoteOffEvent; - -typedef struct { - int channelNumber, key, velocity; -} NoteOnEvent; - -// Specific track structures for Civ3 AMB files -typedef struct { - int size; - int deltaTimeTrackName; - TrackNameEvent trackName; - int deltaTimeSMPTEOffset; - SMPTEOffsetEvent smpteOffset; - int deltaTimeTimeSignature; - TimeSignatureEvent timeSignature; - int deltaTimeSetTempo; - SetTempoEvent setTempo; - int deltaTimeEndOfTrack; -} InfoTrack; - -typedef struct { - int size; - int deltaTimeTrackName; - TrackNameEvent trackName; - int controlChangeCount; - int deltaTimeControlChanges[MAX_CONTROL_CHANGES]; - ControlChangeEvent controlChanges[MAX_CONTROL_CHANGES]; - int deltaTimeProgramChange; - ProgramChangeEvent programChange; - int deltaTimeNoteOn; - NoteOnEvent noteOn; - int deltaTimeNoteOff; - NoteOffEvent noteOff; - int deltaTimeEndOfTrack; -} SoundTrack; - -typedef struct { - short format; - short trackCount; - short ticksPerQuarterNote; - float secondsPerQuarterNote; - InfoTrack infoTrack; - SoundTrack soundTracks[MAX_SOUND_TRACKS]; -} MidiData; - -typedef struct { - Path filePath; - - // Chunks - PrgmChunk prgmChunks[MAX_CHUNKS]; - int prgmChunkCount; - - KmapChunk kmapChunks[MAX_CHUNKS]; - int kmapChunkCount; - - GlblChunk glblChunk; - bool hasGlblChunk; - - MidiData midi; -} AmbFile; - -// Helper functions for file parsing and writing -unsigned int ReadAmbInt(FILE *file, bool isUnsigned) { - unsigned char buffer[4]; - fread(buffer, 1, 4, file); - - // Little endian - unsigned int result = - (buffer[0]) | - (buffer[1] << 8) | - (buffer[2] << 16) | - (buffer[3] << 24); - - if (!isUnsigned && (result & 0x80000000)) { - // Convert to signed if needed - return (int)result; - } - - return result; -} - -// Helper functions for file writing -void WriteAmbInt(FILE *file, unsigned int value, bool isUnsigned) { - unsigned char buffer[4]; - - // Little endian - buffer[0] = value & 0xFF; - buffer[1] = (value >> 8) & 0xFF; - buffer[2] = (value >> 16) & 0xFF; - buffer[3] = (value >> 24) & 0xFF; - - fwrite(buffer, 1, 4, file); -} - -void WriteMidiInt(FILE *file, unsigned int value, bool isUnsigned) { - unsigned char buffer[4]; - - // Big endian - buffer[0] = (value >> 24) & 0xFF; - buffer[1] = (value >> 16) & 0xFF; - buffer[2] = (value >> 8) & 0xFF; - buffer[3] = value & 0xFF; - - fwrite(buffer, 1, 4, file); -} - -void WriteMidiShort(FILE *file, unsigned short value, bool isUnsigned) { - unsigned char buffer[2]; - - // Big endian - buffer[0] = (value >> 8) & 0xFF; - buffer[1] = value & 0xFF; - - fwrite(buffer, 1, 2, file); -} - -void WriteMidiVarInt(FILE *file, unsigned int value) { - unsigned char buffer[4]; - int numBytes = 0; - - // Build the bytes from least significant to most significant - do { - buffer[numBytes++] = (value & 0x7F) | (numBytes > 0 ? 0x80 : 0); - value >>= 7; - } while (value > 0 && numBytes < 4); - - // Write the bytes in reverse order - for (int i = numBytes - 1; i >= 0; i--) { - // Clear the continuation bit for the last byte - if (i == 0) { - buffer[i] &= 0x7F; - } - fwrite(&buffer[i], 1, 1, file); - } -} - -void WriteString(FILE *file, const char *str) { - // Write null-terminated string - fwrite(str, 1, strlen(str) + 1, file); -} - -unsigned int ReadMidiInt(FILE *file, bool isUnsigned) { - unsigned char buffer[4]; - fread(buffer, 1, 4, file); - - // Big endian - unsigned int result = - (buffer[0] << 24) | - (buffer[1] << 16) | - (buffer[2] << 8) | - (buffer[3]); - - if (!isUnsigned && (result & 0x80000000)) { - // Convert to signed if needed - return (int)result; - } - - return result; -} - -unsigned short ReadMidiShort(FILE *file, bool isUnsigned) { - unsigned char buffer[2]; - fread(buffer, 1, 2, file); - - // Big endian - unsigned short result = (buffer[0] << 8) | buffer[1]; - - if (!isUnsigned && (result & 0x8000)) { - // Convert to signed if needed - return (short)result; - } - - return result; -} - -unsigned int ReadMidiVarInt(FILE *file) { - unsigned int result = 0; - unsigned char byte; - - do { - fread(&byte, 1, 1, file); - result = (result << 7) | (byte & 0x7F); - } while (byte & 0x80); - - return result; -} - -void ReadString(FILE *file, char *buffer, int maxLength) { - int i = 0; - char byte; - - while (i < maxLength - 1) { - fread(&byte, 1, 1, file); - if (byte == 0) { - break; - } - buffer[i++] = byte; - } - - buffer[i] = '\0'; -} - -// Parse AMB file chunks -bool ParsePrgmChunk(FILE *file, PrgmChunk *chunk) { - chunk->size = ReadAmbInt(file, true); - chunk->number = ReadAmbInt(file, true); - chunk->flags = ReadAmbInt(file, false); - chunk->maxRandomSpeed = ReadAmbInt(file, false); - chunk->minRandomSpeed = ReadAmbInt(file, false); - chunk->maxRandomVolume = ReadAmbInt(file, false); - chunk->minRandomVolume = ReadAmbInt(file, false); - - // Read end marker - unsigned int endMarker = ReadAmbInt(file, true); - if (endMarker != 0xFA) { - MessageBox(NULL, "Expected 0xFA marker before strings in Prgm chunk", "Error", MB_OK | MB_ICONERROR); - return false; - } - - ReadString(file, chunk->effectName, sizeof(chunk->effectName)); - ReadString(file, chunk->varName, sizeof(chunk->varName)); - - return true; -} - -bool ParseKmapChunk(FILE *file, KmapChunk *chunk) { - chunk->size = ReadAmbInt(file, true); - chunk->flags = ReadAmbInt(file, true); - chunk->param1 = ReadAmbInt(file, true); - chunk->param2 = ReadAmbInt(file, true); - - ReadString(file, chunk->varName, sizeof(chunk->varName)); - - chunk->itemCount = ReadAmbInt(file, true); - - if ((chunk->flags & 6) != 0) { - chunk->itemSize = ReadAmbInt(file, true); - } else { - chunk->itemSize = 0; - } - - // Read items - for (int i = 0; i < chunk->itemCount && i < MAX_ITEMS; i++) { - if ((chunk->flags & 6) == 0) { - // Not used in Civ3 - int aint1 = ReadAmbInt(file, true); - int aint2 = ReadAmbInt(file, true); - } else { - // Read the 12-byte data block - fread(chunk->items[i].data, 1, chunk->itemSize, file); - } - - ReadString(file, chunk->items[i].wavFileName, sizeof(chunk->items[i].wavFileName)); - } - - // Read end marker - unsigned int endMarker = ReadAmbInt(file, true); - if (endMarker != 0xFA) { - MessageBox(NULL, "Expected 0xFA marker at end of Kmap chunk", "Error", MB_OK | MB_ICONERROR); - return false; - } - - return true; -} - -bool ParseGlblChunk(FILE *file, GlblChunk *chunk) { - chunk->size = ReadAmbInt(file, true); - long startPos = ftell(file); - - chunk->dataSize = ReadAmbInt(file, true); - fread(chunk->data, 1, chunk->dataSize, file); - - // Read any extra data - long currentPos = ftell(file); - long remainingSize = chunk->size - (currentPos - startPos); - - if (remainingSize > 0 && remainingSize < sizeof(chunk->extraData)) { - fread(chunk->extraData, 1, remainingSize, file); - chunk->extraDataSize = (int)remainingSize; - } else { - chunk->extraDataSize = 0; - } - - return true; -} - -// Parse TrackName event from MIDI file -bool ParseTrackNameEvent(FILE *file, TrackNameEvent *event) { - unsigned char metaType; - fread(&metaType, 1, 1, file); - - if (metaType != 0x03) { - MessageBox(NULL, "Expected TrackName event (0x03)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned int length = ReadMidiVarInt(file); - memset(event->name, 0, sizeof(event->name)); - fread(event->name, 1, length < sizeof(event->name) ? length : sizeof(event->name) - 1, file); - - return true; -} - -// Parse SMPTEOffset event from MIDI file -bool ParseSMPTEOffsetEvent(FILE *file, SMPTEOffsetEvent *event) { - unsigned char metaType; - fread(&metaType, 1, 1, file); - - if (metaType != 0x54) { - MessageBox(NULL, "Expected SMPTEOffset event (0x54)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned char length; - fread(&length, 1, 1, file); - - if (length != 5) { - MessageBox(NULL, "Invalid SMPTEOffset event length (expected 5)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - event->hr = fgetc(file); - event->mn = fgetc(file); - event->se = fgetc(file); - event->fr = fgetc(file); - event->ff = fgetc(file); - - return true; -} - -// Parse TimeSignature event from MIDI file -bool ParseTimeSignatureEvent(FILE *file, TimeSignatureEvent *event) { - unsigned char metaType; - fread(&metaType, 1, 1, file); - - if (metaType != 0x58) { - MessageBox(NULL, "Expected TimeSignature event (0x58)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned char length; - fread(&length, 1, 1, file); - - if (length != 4) { - MessageBox(NULL, "Invalid TimeSignature event length (expected 4)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - event->nn = fgetc(file); - event->dd = fgetc(file); - event->cc = fgetc(file); - event->bb = fgetc(file); - - return true; -} - -// Parse SetTempo event from MIDI file -bool ParseSetTempoEvent(FILE *file, SetTempoEvent *event) { - unsigned char metaType; - fread(&metaType, 1, 1, file); - - if (metaType != 0x51) { - MessageBox(NULL, "Expected SetTempo event (0x51)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned char length; - fread(&length, 1, 1, file); - - if (length != 3) { - MessageBox(NULL, "Invalid SetTempo event length (expected 3)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned char tempo[3]; - fread(tempo, 1, 3, file); - event->microsecondsPerQuarterNote = (tempo[0] << 16) | (tempo[1] << 8) | tempo[2]; - - return true; -} - -// Parse EndOfTrack event from MIDI file -bool ParseEndOfTrackEvent(FILE *file) { - unsigned char metaType; - fread(&metaType, 1, 1, file); - - if (metaType != 0x2F) { - MessageBox(NULL, "Expected EndOfTrack event (0x2F)", "Error", MB_OK | MB_ICONERROR); - return false; - } - - unsigned char zero; - fread(&zero, 1, 1, file); // Should be zero - - return true; -} - -// Parse ControlChange event from MIDI file -bool ParseControlChangeEvent(FILE *file, ControlChangeEvent *event, int *channelNumber) { - unsigned char statusByte; - fread(&statusByte, 1, 1, file); - - // Check if the status byte indicates a control change event (0xBn) - if ((statusByte >> 4) != 0xB) { - // If channelNumber pointer is provided, we're expecting running status - if (channelNumber != NULL) { - // Put the byte back for reading data - fseek(file, -1, SEEK_CUR); - event->channelNumber = *channelNumber; - } else { - MessageBox(NULL, "Expected ControlChange event (0xBn)", "Error", MB_OK | MB_ICONERROR); - return false; - } - } else { - event->channelNumber = statusByte & 0x0F; - // Save channel number for possible running status - if (channelNumber != NULL) { - *channelNumber = event->channelNumber; - } - } - - event->controllerNumber = fgetc(file); - event->value = fgetc(file); - - return true; -} - -// Parse ProgramChange event from MIDI file -bool ParseProgramChangeEvent(FILE *file, ProgramChangeEvent *event, int *channelNumber) { - unsigned char statusByte; - fread(&statusByte, 1, 1, file); - - // Check if the status byte indicates a program change event (0xCn) - if ((statusByte >> 4) != 0xC) { - // If channelNumber pointer is provided, we're expecting running status - if (channelNumber != NULL) { - // Put the byte back for reading data - fseek(file, -1, SEEK_CUR); - event->channelNumber = *channelNumber; - } else { - MessageBox(NULL, "Expected ProgramChange event (0xCn)", "Error", MB_OK | MB_ICONERROR); - return false; - } - } else { - event->channelNumber = statusByte & 0x0F; - // Save channel number for possible running status - if (channelNumber != NULL) { - *channelNumber = event->channelNumber; - } - } - - event->programNumber = fgetc(file); - - return true; -} - -// Parse NoteOn event from MIDI file -bool ParseNoteOnEvent(FILE *file, NoteOnEvent *event, int *channelNumber) { - unsigned char statusByte; - fread(&statusByte, 1, 1, file); - - // Check if the status byte indicates a note on event (0x9n) - if ((statusByte >> 4) != 0x9) { - // If channelNumber pointer is provided, we're expecting running status - if (channelNumber != NULL) { - // Put the byte back for reading data - fseek(file, -1, SEEK_CUR); - event->channelNumber = *channelNumber; - } else { - MessageBox(NULL, "Expected NoteOn event (0x9n)", "Error", MB_OK | MB_ICONERROR); - return false; - } - } else { - event->channelNumber = statusByte & 0x0F; - // Save channel number for possible running status - if (channelNumber != NULL) { - *channelNumber = event->channelNumber; - } - } - - event->key = fgetc(file); - event->velocity = fgetc(file); - - return true; -} - -// Parse NoteOff event from MIDI file -bool ParseNoteOffEvent(FILE *file, NoteOffEvent *event, int *channelNumber) { - unsigned char statusByte; - fread(&statusByte, 1, 1, file); - - // Check if the status byte indicates a note off event (0x8n) - if ((statusByte >> 4) != 0x8) { - // Check if it's a note on with velocity 0 (equivalent to note off) - if ((statusByte >> 4) == 0x9) { - event->channelNumber = statusByte & 0x0F; - event->key = fgetc(file); - event->velocity = fgetc(file); - - // Check if velocity is 0 (note off) - if (event->velocity > 0) { - MessageBox(NULL, "Expected NoteOff event but got NoteOn with velocity > 0", "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Save channel number for possible running status - if (channelNumber != NULL) { - *channelNumber = event->channelNumber; - } - - return true; - } - - // If channelNumber pointer is provided, we're expecting running status - if (channelNumber != NULL) { - // Put the byte back for reading data - fseek(file, -1, SEEK_CUR); - event->channelNumber = *channelNumber; - } else { - MessageBox(NULL, "Expected NoteOff event (0x8n)", "Error", MB_OK | MB_ICONERROR); - return false; - } - } else { - event->channelNumber = statusByte & 0x0F; - // Save channel number for possible running status - if (channelNumber != NULL) { - *channelNumber = event->channelNumber; - } - } - - event->key = fgetc(file); - event->velocity = fgetc(file); - - return true; -} - -// Parse InfoTrack from MIDI file -bool ParseInfoTrack(FILE *file, InfoTrack *track) { - // Read the file tag - char trackTag[5] = {0}; - fread(trackTag, 1, 4, file); - - if (strcmp(trackTag, "MTrk") != 0) { - char errMsg[256]; - sprintf(errMsg, "Invalid MIDI info track header: expected 'MTrk', got '%.4s'", trackTag); - MessageBox(NULL, errMsg, "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Read track chunk size - track->size = ReadMidiInt(file, true); - long startPos = ftell(file); - - // Read events in the InfoTrack - - // 1. TrackName event - track->deltaTimeTrackName = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for TrackName", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseTrackNameEvent(file, &track->trackName)) return false; - - // 2. SMPTEOffset event - track->deltaTimeSMPTEOffset = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for SMPTEOffset", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseSMPTEOffsetEvent(file, &track->smpteOffset)) return false; - - // 3. TimeSignature event - track->deltaTimeTimeSignature = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for TimeSignature", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseTimeSignatureEvent(file, &track->timeSignature)) return false; - - // 4. SetTempo event - track->deltaTimeSetTempo = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for SetTempo", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseSetTempoEvent(file, &track->setTempo)) return false; - - // 5. EndOfTrack event - track->deltaTimeEndOfTrack = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for EndOfTrack", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseEndOfTrackEvent(file)) return false; - - // Ensure we've read exactly the size of the track - long currentPos = ftell(file); - if (currentPos != startPos + track->size) { - MessageBox(NULL, "Info track size mismatch", "Error", MB_OK | MB_ICONERROR); - return false; - } - - return true; -} - -// Parse SoundTrack from MIDI file -bool ParseSoundTrack(FILE *file, SoundTrack *track) { - // Read the file tag - char trackTag[5] = {0}; - fread(trackTag, 1, 4, file); - - if (strcmp(trackTag, "MTrk") != 0) { - char errMsg[256]; - sprintf(errMsg, "Invalid MIDI sound track header: expected 'MTrk', got '%.4s'", trackTag); - MessageBox(NULL, errMsg, "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Read track chunk size - track->size = ReadMidiInt(file, true); - long startPos = ftell(file); - - // Initialize control change count - track->controlChangeCount = 0; - - // 1. TrackName event - track->deltaTimeTrackName = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for TrackName", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseTrackNameEvent(file, &track->trackName)) return false; - - // 2. ControlChange events (1 or 2) - unsigned char nextByte; - int currentChannelNumber = -1; // For running status - - // Peek at the next byte to determine event type - long peekPos = ftell(file); - track->deltaTimeControlChanges[0] = ReadMidiVarInt(file); - nextByte = fgetc(file); - fseek(file, peekPos, SEEK_SET); // Go back to where we were - - // Check for control change events (0xBn) - while (((nextByte >> 4) == 0xB || currentChannelNumber != -1) && - track->controlChangeCount < MAX_CONTROL_CHANGES) { - - // Read the delta time - track->deltaTimeControlChanges[track->controlChangeCount] = ReadMidiVarInt(file); - - // Parse the control change event - if (!ParseControlChangeEvent(file, &track->controlChanges[track->controlChangeCount], ¤tChannelNumber)) { - return false; - } - - track->controlChangeCount++; - - // Peek at the next byte to determine if there's another control change - if (track->controlChangeCount < MAX_CONTROL_CHANGES) { - peekPos = ftell(file); - int testDeltaTime = ReadMidiVarInt(file); - nextByte = fgetc(file); - fseek(file, peekPos, SEEK_SET); // Go back to where we were - - // If next byte is not a control change and not a running status, break - if ((nextByte >> 4) != 0xB && (nextByte & 0x80) != 0) { - currentChannelNumber = -1; // Reset running status - break; - } - } - } - - // 3. ProgramChange event - track->deltaTimeProgramChange = ReadMidiVarInt(file); - if (!ParseProgramChangeEvent(file, &track->programChange, NULL)) return false; - - // 4. NoteOn event - track->deltaTimeNoteOn = ReadMidiVarInt(file); - if (!ParseNoteOnEvent(file, &track->noteOn, NULL)) return false; - - // 5. NoteOff event - track->deltaTimeNoteOff = ReadMidiVarInt(file); - if (!ParseNoteOffEvent(file, &track->noteOff, NULL)) return false; - - // 6. EndOfTrack event - track->deltaTimeEndOfTrack = ReadMidiVarInt(file); - if (fgetc(file) != 0xFF) { // Meta event marker - MessageBox(NULL, "Expected Meta event marker (0xFF) for EndOfTrack", "Error", MB_OK | MB_ICONERROR); - return false; - } - if (!ParseEndOfTrackEvent(file)) return false; - - // Ensure we've read exactly the size of the track - long currentPos = ftell(file); - if (currentPos != startPos + track->size) { - MessageBox(NULL, "Sound track size mismatch", "Error", MB_OK | MB_ICONERROR); - return false; - } - - return true; -} - -bool ParseMidi(FILE *file, MidiData *midi) { - // Read header size - unsigned char sizeBytes[4]; - fread(sizeBytes, 1, 4, file); - - // Values for MIDI header should be big-endian (MSB first) - int headerSize = (sizeBytes[0] << 24) | (sizeBytes[1] << 16) | (sizeBytes[2] << 8) | sizeBytes[3]; - - // The header size should be 6 for standard MIDI files - if (headerSize != 6) { - MessageBox(NULL, "Invalid MIDI header size", "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Read format, track count, and division - unsigned char formatBytes[2], trackCountBytes[2], divisionBytes[2]; - - fread(formatBytes, 1, 2, file); - fread(trackCountBytes, 1, 2, file); - fread(divisionBytes, 1, 2, file); - - // Interpret as big-endian values - midi->format = (formatBytes[0] << 8) | formatBytes[1]; - midi->trackCount = (trackCountBytes[0] << 8) | trackCountBytes[1]; - midi->ticksPerQuarterNote = (divisionBytes[0] << 8) | divisionBytes[1]; - - if (midi->format != 1) { - MessageBox(NULL, "Unsupported MIDI format", "Error", MB_OK | MB_ICONERROR); - return false; - } - - if (midi->trackCount < 2 || midi->trackCount > (MAX_SOUND_TRACKS + 1)) { - MessageBox(NULL, "Invalid MIDI track count", "Error", MB_OK | MB_ICONERROR); - return false; - } - - if ((midi->ticksPerQuarterNote & 0x8000) != 0) { - MessageBox(NULL, "Unsupported MIDI time division format", "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Parse InfoTrack (first track) - if (!ParseInfoTrack(file, &midi->infoTrack)) { - return false; - } - - // Set seconds per quarter note from the tempo in the InfoTrack - midi->secondsPerQuarterNote = midi->infoTrack.setTempo.microsecondsPerQuarterNote / 1000000.0f; - - // Parse SoundTracks - int soundTrackCount = midi->trackCount - 1; // First track is InfoTrack - - for (int i = 0; i < soundTrackCount && i < MAX_SOUND_TRACKS; i++) { - if (!ParseSoundTrack(file, &midi->soundTracks[i])) { - return false; - } - } - - return true; -} - -// Load AMB file -bool LoadAmbFile(const Path filePath, AmbFile * out) { - FILE *file = fopen(filePath, "rb"); - if (!file) { - MessageBox(NULL, "Failed to open AMB file", "Error", MB_OK | MB_ICONERROR); - return false; - } - - // Initialize AMB file structure - memset(out, 0, sizeof *out); - strcpy(out->filePath, filePath); - - // Parse all chunks - bool success = true; - while (!feof(file)) { - char tag[5] = {0}; - if (fread(tag, 1, 4, file) != 4) { - break; // End of file - } - - if (strcmp(tag, "prgm") == 0) { - if (out->prgmChunkCount < MAX_CHUNKS) { - if (!ParsePrgmChunk(file, &out->prgmChunks[out->prgmChunkCount++])) { - success = false; - break; - } - } else { - MessageBox(NULL, "Too many Prgm chunks", "Error", MB_OK | MB_ICONERROR); - success = false; - break; - } - } else if (strcmp(tag, "kmap") == 0) { - if (out->kmapChunkCount < MAX_CHUNKS) { - if (!ParseKmapChunk(file, &out->kmapChunks[out->kmapChunkCount++])) { - success = false; - break; - } - } else { - MessageBox(NULL, "Too many Kmap chunks", "Error", MB_OK | MB_ICONERROR); - success = false; - break; - } - } else if (strcmp(tag, "glbl") == 0) { - if (!out->hasGlblChunk) { - if (!ParseGlblChunk(file, &out->glblChunk)) { - success = false; - break; - } - out->hasGlblChunk = true; - } else { - MessageBox(NULL, "Multiple Glbl chunks not supported", "Error", MB_OK | MB_ICONERROR); - success = false; - break; - } - } else if (strcmp(tag, "MThd") == 0) { - // MIDI header detected, parse the MIDI data - // Don't need to go back, ParseMidi now expects to be positioned after the tag - if (!ParseMidi(file, &out->midi)) { - success = false; - break; - } - } else { - char message[256]; - sprintf(message, "Unknown chunk tag: %s", tag); - MessageBox(NULL, message, "Error", MB_OK | MB_ICONERROR); - success = false; - break; - } - } - - fclose(file); - - return success; -} - -int ComputePrgmChunkSize(PrgmChunk const * chunk) { - // size = 28 bytes for 7 4-byte ints + 2 null terminators + lengths of the two strings - // All Prgm chunks in the AMBs that ship with Civ 3 are confirmed to follow this rule - return 30 + strlen(chunk->effectName) + strlen(chunk->varName); -} - -// Functions to write AMB file chunks -bool WritePrgmChunk(FILE *file, PrgmChunk const * chunk) { - // Write tag - fwrite("prgm", 1, 4, file); - - // Write chunk data - WriteAmbInt(file, chunk->size, true); - WriteAmbInt(file, chunk->number, true); - WriteAmbInt(file, chunk->flags, false); - WriteAmbInt(file, chunk->maxRandomSpeed, false); - WriteAmbInt(file, chunk->minRandomSpeed, false); - WriteAmbInt(file, chunk->maxRandomVolume, false); - WriteAmbInt(file, chunk->minRandomVolume, false); - - // Write end marker before strings - WriteAmbInt(file, 0xFA, true); - - // Write strings - WriteString(file, chunk->effectName); - WriteString(file, chunk->varName); - - return true; -} - -int ComputeKmapChunkSize(KmapChunk const * chunk) { - // size w/o items = 20 bytes for 5 4-byte ints + length of var name + null terminator + end indicator - int size = 25 + strlen(chunk->varName); - for (int i = 0; i < chunk->itemCount; i++) - // size of each item = 12 bytes unknown data + length of wav file name + null terminator - size += 12 + strlen(chunk->items[i].wavFileName) + 1; - // This rule matches the size of all Kmap chunks in the Civ 3 AMBs except two, both in GalleyAttack.amb. Those chunks are broken, however, and - // don't play any sound. - return size; -} - -bool WriteKmapChunk(FILE *file, KmapChunk const * chunk) { - // Write tag - fwrite("kmap", 1, 4, file); - - // Write chunk data - WriteAmbInt(file, chunk->size, true); - WriteAmbInt(file, chunk->flags, true); - WriteAmbInt(file, chunk->param1, true); - WriteAmbInt(file, chunk->param2, true); - - // Write variable name - WriteString(file, chunk->varName); - - // Write item count - WriteAmbInt(file, chunk->itemCount, true); - - // Write item size if needed - if ((chunk->flags & 6) != 0) { - WriteAmbInt(file, chunk->itemSize, true); - } - - // Write items - for (int i = 0; i < chunk->itemCount && i < MAX_ITEMS; i++) { - if ((chunk->flags & 6) == 0) { - // Not used in Civ3, but we should still write placeholder data - WriteAmbInt(file, 0, true); // Placeholder for aint1 - WriteAmbInt(file, 0, true); // Placeholder for aint2 - } else { - // Write the data block - fwrite(chunk->items[i].data, 1, chunk->itemSize, file); - } - - // Write WAV filename - WriteString(file, chunk->items[i].wavFileName); - } - - // Write end marker - WriteAmbInt(file, 0xFA, true); - - return true; -} - -bool WriteGlblChunk(FILE *file, GlblChunk const * chunk) { - // Write tag - fwrite("glbl", 1, 4, file); - - // Write chunk size - WriteAmbInt(file, chunk->size, true); - - // Write data size - WriteAmbInt(file, chunk->dataSize, true); - - // Write data - fwrite(chunk->data, 1, chunk->dataSize, file); - - // Write extra data if present - if (chunk->extraDataSize > 0) { - fwrite(chunk->extraData, 1, chunk->extraDataSize, file); - } - - return true; -} - -// Function to write TrackName event to MIDI file -void WriteTrackNameEvent(FILE *file, const TrackNameEvent *event) { - fputc(0x03, file); // Track name meta event type - - // Length of the name - WriteMidiVarInt(file, strlen(event->name)); - - // Name data - fwrite(event->name, 1, strlen(event->name), file); -} - -// Function to write SMPTEOffset event to MIDI file -void WriteSMPTEOffsetEvent(FILE *file, const SMPTEOffsetEvent *event) { - fputc(0x54, file); // SMPTE offset meta event type - fputc(0x05, file); // Length is always 5 - - // SMPTE data - fputc(event->hr, file); - fputc(event->mn, file); - fputc(event->se, file); - fputc(event->fr, file); - fputc(event->ff, file); -} - -// Function to write TimeSignature event to MIDI file -void WriteTimeSignatureEvent(FILE *file, const TimeSignatureEvent *event) { - fputc(0x58, file); // Time signature meta event type - fputc(0x04, file); // Length is always 4 - - // Time signature data - fputc(event->nn, file); - fputc(event->dd, file); - fputc(event->cc, file); - fputc(event->bb, file); -} - -// Function to write SetTempo event to MIDI file -void WriteSetTempoEvent(FILE *file, const SetTempoEvent *event) { - fputc(0x51, file); // Set tempo meta event type - fputc(0x03, file); // Length is always 3 - - // Tempo data (microseconds per quarter note) - unsigned int tempo = event->microsecondsPerQuarterNote; - fputc((tempo >> 16) & 0xFF, file); - fputc((tempo >> 8) & 0xFF, file); - fputc(tempo & 0xFF, file); -} - -// Function to write EndOfTrack event to MIDI file -void WriteEndOfTrackEvent(FILE *file) { - fputc(0x2F, file); // End of track meta event type - fputc(0x00, file); // Length is always 0 -} - -// Function to write ControlChange event to MIDI file -void WriteControlChangeEvent(FILE *file, const ControlChangeEvent *event) { - // Control change status byte: 0xBn, where n is the channel number - fputc(0xB0 | (event->channelNumber & 0x0F), file); - - // Controller number and value - fputc(event->controllerNumber & 0x7F, file); - fputc(event->value & 0x7F, file); -} - -// Function to write ProgramChange event to MIDI file -void WriteProgramChangeEvent(FILE *file, const ProgramChangeEvent *event) { - // Program change status byte: 0xCn, where n is the channel number - fputc(0xC0 | (event->channelNumber & 0x0F), file); - - // Program number - fputc(event->programNumber & 0x7F, file); -} - -// Function to write NoteOn event to MIDI file -void WriteNoteOnEvent(FILE *file, const NoteOnEvent *event) { - // Note on status byte: 0x9n, where n is the channel number - fputc(0x90 | (event->channelNumber & 0x0F), file); - - // Key and velocity - fputc(event->key & 0x7F, file); - fputc(event->velocity & 0x7F, file); -} - -// Function to write NoteOff event to MIDI file -void WriteNoteOffEvent(FILE *file, const NoteOffEvent *event) { - // Note off status byte: 0x8n, where n is the channel number - fputc(0x80 | (event->channelNumber & 0x0F), file); - - // Key and velocity - fputc(event->key & 0x7F, file); - fputc(event->velocity & 0x7F, file); -} - -// Function to write InfoTrack to MIDI file -void WriteInfoTrack(FILE *file, const InfoTrack *track) { - // Write track tag - fwrite("MTrk", 1, 4, file); - - // We need to calculate track size, so we'll save the current position, - // write a placeholder, write the events, then come back and update it - long sizePos = ftell(file); - - // Write placeholder for size - WriteMidiInt(file, 0, true); - - // Save position at start of track data - long startPos = ftell(file); - - // Write all events in sequence - - // 1. TrackName event - WriteMidiVarInt(file, track->deltaTimeTrackName); - fputc(0xFF, file); // Meta event marker - WriteTrackNameEvent(file, &track->trackName); - - // 2. SMPTEOffset event - WriteMidiVarInt(file, track->deltaTimeSMPTEOffset); - fputc(0xFF, file); // Meta event marker - WriteSMPTEOffsetEvent(file, &track->smpteOffset); - - // 3. TimeSignature event - WriteMidiVarInt(file, track->deltaTimeTimeSignature); - fputc(0xFF, file); // Meta event marker - WriteTimeSignatureEvent(file, &track->timeSignature); - - // 4. SetTempo event - WriteMidiVarInt(file, track->deltaTimeSetTempo); - fputc(0xFF, file); // Meta event marker - WriteSetTempoEvent(file, &track->setTempo); - - // 5. EndOfTrack event - WriteMidiVarInt(file, track->deltaTimeEndOfTrack); - fputc(0xFF, file); // Meta event marker - WriteEndOfTrackEvent(file); - - // Get end position and calculate size - long endPos = ftell(file); - unsigned int trackSize = (unsigned int)(endPos - startPos); - - // Go back and write the actual size - fseek(file, sizePos, SEEK_SET); - WriteMidiInt(file, trackSize, true); - - // Return to the end of the track - fseek(file, endPos, SEEK_SET); -} - -// Function to write SoundTrack to MIDI file -unsigned int WriteSoundTrack(FILE *file, const SoundTrack *track) { - // Write track tag - fwrite("MTrk", 1, 4, file); - - // We need to calculate track size, so we'll save the current position, - // write a placeholder, write the events, then come back and update it - long sizePos = ftell(file); - - // Write placeholder for size - WriteMidiInt(file, 0, true); - - // Save position at start of track data - long startPos = ftell(file); - - // Write all events in sequence - - // 1. TrackName event - WriteMidiVarInt(file, track->deltaTimeTrackName); - fputc(0xFF, file); // Meta event marker - WriteTrackNameEvent(file, &track->trackName); - - // 2. ControlChange events (1 or 2) - for (int i = 0; i < track->controlChangeCount; i++) { - WriteMidiVarInt(file, track->deltaTimeControlChanges[i]); - WriteControlChangeEvent(file, &track->controlChanges[i]); - } - - // 3. ProgramChange event - WriteMidiVarInt(file, track->deltaTimeProgramChange); - WriteProgramChangeEvent(file, &track->programChange); - - // 4. NoteOn event - WriteMidiVarInt(file, track->deltaTimeNoteOn); - WriteNoteOnEvent(file, &track->noteOn); - - // 5. NoteOff event - WriteMidiVarInt(file, track->deltaTimeNoteOff); - WriteNoteOffEvent(file, &track->noteOff); - - // 6. EndOfTrack event - WriteMidiVarInt(file, track->deltaTimeEndOfTrack); - fputc(0xFF, file); // Meta event marker - WriteEndOfTrackEvent(file); - - // Get end position and calculate size - long endPos = ftell(file); - unsigned int trackSize = (unsigned int)(endPos - startPos); - - // Go back and write the actual size - fseek(file, sizePos, SEEK_SET); - WriteMidiInt(file, trackSize, true); - - // Return to the end of the track - fseek(file, endPos, SEEK_SET); - - return trackSize; -} - -int ComputeSoundTrackSize(SoundTrack const * track) { - FILE *memFile = tmpfile(); - unsigned int size = WriteSoundTrack(memFile, track); - fclose(memFile); - return size; -} - -bool WriteMidi(FILE *file, MidiData const * midi) { - // Write MIDI header - fwrite("MThd", 1, 4, file); - - // Header size is always 6 - WriteMidiInt(file, 6, true); - - // Write format, track count, and division - WriteMidiShort(file, midi->format, false); - WriteMidiShort(file, midi->trackCount, false); - WriteMidiShort(file, midi->ticksPerQuarterNote, false); - - // Write InfoTrack - WriteInfoTrack(file, &midi->infoTrack); - - // Write SoundTracks - int soundTrackCount = midi->trackCount - 1; // First track is InfoTrack - - for (int i = 0; i < soundTrackCount && i < MAX_SOUND_TRACKS; i++) { - WriteSoundTrack(file, &midi->soundTracks[i]); - } - - return true; -} - -// Function to save AMB file to the specified path -bool SaveAmbFile(AmbFile const * amb, const Path filePath) { - FILE *file = fopen(filePath, "wb"); - if (!file) { - return false; - } - - bool success = true; - - // Write Prgm chunks - for (int i = 0; i < amb->prgmChunkCount; i++) { - if (!WritePrgmChunk(file, &amb->prgmChunks[i])) { - success = false; - break; - } - } - - // Write Kmap chunks - if (success) { - for (int i = 0; i < amb->kmapChunkCount; i++) { - if (!WriteKmapChunk(file, &amb->kmapChunks[i])) { - success = false; - break; - } - } - } - - // Write Glbl chunk if present - if (success && amb->hasGlblChunk) { - if (!WriteGlblChunk(file, &amb->glblChunk)) { - success = false; - } - } - - // Write MIDI data - if (success) { - if (!WriteMidi(file, &amb->midi)) { - success = false; - } - } - - fclose(file); - - // Remove the file if we failed - if (!success) { - remove(filePath); - } - - return success; -} - -// Utility function to get sound track count -int GetSoundTrackCount(const MidiData *midi) { - return midi->trackCount - 1; // First track is InfoTrack -} - -// Function to describe the loaded AMB file (for debugging) -void DescribeAmbFile(AmbFile const * amb, char *buffer, size_t bufferSize) { - char *pos = buffer; - int remainingSize = (int)bufferSize; - - // Describe file path - int written = snprintf(pos, remainingSize, "File: %s\r\n\r\n", amb->filePath); - pos += written; - remainingSize -= written; - - // Describe Prgm chunks - for (int i = 0; i < amb->prgmChunkCount && remainingSize > 0; i++) { - PrgmChunk *chunk = &amb->prgmChunks[i]; - written = snprintf(pos, remainingSize, - "Prgm #%d:\r\n" - " Size: %d\r\n" - " Number: %d\r\n" - " Flags: %d\r\n" - " Max Random Speed: %d\r\n" - " Min Random Speed: %d\r\n" - " Max Random Volume: %d\r\n" - " Min Random Volume: %d\r\n" - " Effect Name: '%s'\r\n" - " Var Name: '%s'\r\n\r\n", - i + 1, chunk->size, chunk->number, chunk->flags, - chunk->maxRandomSpeed, chunk->minRandomSpeed, - chunk->maxRandomVolume, chunk->minRandomVolume, - chunk->effectName, chunk->varName); - pos += written; - remainingSize -= written; - } - - // Describe Kmap chunks - for (int i = 0; i < amb->kmapChunkCount && remainingSize > 0; i++) { - KmapChunk *chunk = &amb->kmapChunks[i]; - written = snprintf(pos, remainingSize, - "Kmap #%d:\r\n" - " Size: %d\r\n" - " Flags: %d\r\n" - " Param1: %d\r\n" - " Param2: %d\r\n" - " Var Name: '%s'\r\n" - " Item Count: %d\r\n" - " Item Size: %d\r\n", - i + 1, chunk->size, chunk->flags, - chunk->param1, chunk->param2, - chunk->varName, chunk->itemCount, chunk->itemSize); - pos += written; - remainingSize -= written; - - // Describe Kmap items - for (int j = 0; j < chunk->itemCount && remainingSize > 0; j++) { - written = snprintf(pos, remainingSize, - " Item #%d: WAV File: '%s'\r\n", - j + 1, chunk->items[j].wavFileName); - pos += written; - remainingSize -= written; - } - - written = snprintf(pos, remainingSize, "\r\n"); - pos += written; - remainingSize -= written; - } - - // Describe Glbl chunk - if (amb->hasGlblChunk && remainingSize > 0) { - GlblChunk const * chunk = &amb->glblChunk; - written = snprintf(pos, remainingSize, - "Glbl:\r\n" - " Size: %d\r\n" - " Data Size: %d\r\n\r\n", - chunk->size, chunk->dataSize); - pos += written; - remainingSize -= written; - } - - // Describe MIDI data - if (remainingSize > 0) { - written = snprintf(pos, remainingSize, - "MIDI:\r\n" - " Format: %d\r\n" - " Track Count: %d\r\n" - " Ticks Per Quarter Note: %d\r\n" - " Seconds Per Quarter Note: %.6f\r\n\r\n", - amb->midi.format, amb->midi.trackCount, - amb->midi.ticksPerQuarterNote, amb->midi.secondsPerQuarterNote); - pos += written; - remainingSize -= written; - - // Describe InfoTrack - if (remainingSize > 0) { - InfoTrack const *infoTrack = &amb->midi.infoTrack; - float secondsPerTick = amb->midi.secondsPerQuarterNote / amb->midi.ticksPerQuarterNote; - float timestamp = 0.0f; - - written = snprintf(pos, remainingSize, - " InfoTrack:\r\n" - " Size: %d\r\n", - infoTrack->size); - pos += written; - remainingSize -= written; - - // Track name event - timestamp += infoTrack->deltaTimeTrackName * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: TrackName '%s'\r\n", - timestamp, infoTrack->trackName.name); - pos += written; - remainingSize -= written; - - // SMPTE offset event - timestamp += infoTrack->deltaTimeSMPTEOffset * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: SMPTEOffset %d %d %d %d %d\r\n", - timestamp, infoTrack->smpteOffset.hr, - infoTrack->smpteOffset.mn, - infoTrack->smpteOffset.se, - infoTrack->smpteOffset.fr, - infoTrack->smpteOffset.ff); - pos += written; - remainingSize -= written; - - // Time signature event - timestamp += infoTrack->deltaTimeTimeSignature * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: TimeSignature %d %d %d %d\r\n", - timestamp, infoTrack->timeSignature.nn, - infoTrack->timeSignature.dd, - infoTrack->timeSignature.cc, - infoTrack->timeSignature.bb); - pos += written; - remainingSize -= written; - - // Set tempo event - timestamp += infoTrack->deltaTimeSetTempo * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: SetTempo %d\r\n", - timestamp, infoTrack->setTempo.microsecondsPerQuarterNote); - pos += written; - remainingSize -= written; - - // End of track event - timestamp += infoTrack->deltaTimeEndOfTrack * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: EndOfTrack\r\n\r\n", - timestamp); - pos += written; - remainingSize -= written; - } - - // Describe each SoundTrack - int soundTrackCount = GetSoundTrackCount(&amb->midi); - for (int i = 0; i < soundTrackCount && remainingSize > 0; i++) { - SoundTrack const *soundTrack = &amb->midi.soundTracks[i]; - float secondsPerTick = amb->midi.secondsPerQuarterNote / amb->midi.ticksPerQuarterNote; - float timestamp = 0.0f; - - written = snprintf(pos, remainingSize, - " SoundTrack #%d:\r\n" - " Size: %d\r\n", - i + 1, soundTrack->size); - pos += written; - remainingSize -= written; - - // Track name event - timestamp += soundTrack->deltaTimeTrackName * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: TrackName '%s'\r\n", - timestamp, soundTrack->trackName.name); - pos += written; - remainingSize -= written; - - // Control change events - for (int j = 0; j < soundTrack->controlChangeCount && remainingSize > 0; j++) { - timestamp += soundTrack->deltaTimeControlChanges[j] * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: ControlChange %d %d %d\r\n", - timestamp, soundTrack->controlChanges[j].channelNumber, - soundTrack->controlChanges[j].controllerNumber, - soundTrack->controlChanges[j].value); - pos += written; - remainingSize -= written; - } - - // Program change event - timestamp += soundTrack->deltaTimeProgramChange * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: ProgramChange %d %d\r\n", - timestamp, soundTrack->programChange.channelNumber, - soundTrack->programChange.programNumber); - pos += written; - remainingSize -= written; - - // Note on event - timestamp += soundTrack->deltaTimeNoteOn * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: NoteOn %d %d %d\r\n", - timestamp, soundTrack->noteOn.channelNumber, - soundTrack->noteOn.key, - soundTrack->noteOn.velocity); - pos += written; - remainingSize -= written; - - // Note off event - timestamp += soundTrack->deltaTimeNoteOff * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: NoteOff %d %d %d\r\n", - timestamp, soundTrack->noteOff.channelNumber, - soundTrack->noteOff.key, - soundTrack->noteOff.velocity); - pos += written; - remainingSize -= written; - - // End of track event - timestamp += soundTrack->deltaTimeEndOfTrack * secondsPerTick; - written = snprintf(pos, remainingSize, - " %.3f: EndOfTrack\r\n\r\n", - timestamp); - pos += written; - remainingSize -= written; - } - } -} +// This file gets #included into amb_editor.c + +#include +#include +#include +#include +#include + +#define MAX_CHUNKS 30 // No AMB in Civ 3 has more than 12 Kmap or Prgm chunks +#define MAX_SOUND_TRACKS 30 // No AMB in Civ 3 has more than 12 sound tracks +#define MAX_CONTROL_CHANGES 2 // No AMB in Civ 3 has more than 2 control changes per track +#define MAX_ITEMS 2 // No AMB in Civ 3 has more than 1 item + +// AMB file structures for Civ 3 +typedef struct { + int size; + int number; + int flags; + int maxRandomSpeed; + int minRandomSpeed; + int maxRandomVolume; + int minRandomVolume; + char effectName[256]; + char varName[256]; +} PrgmChunk; + +typedef struct { + unsigned char data[12]; + char wavFileName[256]; +} KmapItem; + +typedef struct { + int size; + int flags; + int param1; + int param2; + char varName[256]; + int itemCount; + int itemSize; + KmapItem items[MAX_ITEMS]; +} KmapChunk; + +typedef struct { + int size; + int dataSize; + unsigned char data[12]; + unsigned char extraData[512]; + int extraDataSize; +} GlblChunk; + +// MIDI event types - specific to Civ3 AMB files +typedef struct { + char name[256]; // Always "Seq-1" in Civ3 AMBs +} TrackNameEvent; + +typedef struct { + int hr, mn, se, fr, ff; +} SMPTEOffsetEvent; + +typedef struct { + int nn, dd, cc, bb; +} TimeSignatureEvent; + +typedef struct { + int microsecondsPerQuarterNote; +} SetTempoEvent; + +typedef struct { + int channelNumber, controllerNumber, value; +} ControlChangeEvent; + +typedef struct { + int channelNumber, programNumber; +} ProgramChangeEvent; + +typedef struct { + int channelNumber, key, velocity; +} NoteOffEvent; + +typedef struct { + int channelNumber, key, velocity; +} NoteOnEvent; + +// Specific track structures for Civ3 AMB files +typedef struct { + int size; + int deltaTimeTrackName; + TrackNameEvent trackName; + int deltaTimeSMPTEOffset; + SMPTEOffsetEvent smpteOffset; + int deltaTimeTimeSignature; + TimeSignatureEvent timeSignature; + int deltaTimeSetTempo; + SetTempoEvent setTempo; + int deltaTimeEndOfTrack; +} InfoTrack; + +typedef struct { + int size; + int deltaTimeTrackName; + TrackNameEvent trackName; + int controlChangeCount; + int deltaTimeControlChanges[MAX_CONTROL_CHANGES]; + ControlChangeEvent controlChanges[MAX_CONTROL_CHANGES]; + int deltaTimeProgramChange; + ProgramChangeEvent programChange; + int deltaTimeNoteOn; + NoteOnEvent noteOn; + int deltaTimeNoteOff; + NoteOffEvent noteOff; + int deltaTimeEndOfTrack; +} SoundTrack; + +typedef struct { + short format; + short trackCount; + short ticksPerQuarterNote; + float secondsPerQuarterNote; + InfoTrack infoTrack; + SoundTrack soundTracks[MAX_SOUND_TRACKS]; +} MidiData; + +typedef struct { + Path filePath; + + // Chunks + PrgmChunk prgmChunks[MAX_CHUNKS]; + int prgmChunkCount; + + KmapChunk kmapChunks[MAX_CHUNKS]; + int kmapChunkCount; + + GlblChunk glblChunk; + bool hasGlblChunk; + + MidiData midi; +} AmbFile; + +// Helper functions for file parsing and writing +unsigned int ReadAmbInt(FILE *file, bool isUnsigned) { + unsigned char buffer[4]; + fread(buffer, 1, 4, file); + + // Little endian + unsigned int result = + (buffer[0]) | + (buffer[1] << 8) | + (buffer[2] << 16) | + (buffer[3] << 24); + + if (!isUnsigned && (result & 0x80000000)) { + // Convert to signed if needed + return (int)result; + } + + return result; +} + +// Helper functions for file writing +void WriteAmbInt(FILE *file, unsigned int value, bool isUnsigned) { + unsigned char buffer[4]; + + // Little endian + buffer[0] = value & 0xFF; + buffer[1] = (value >> 8) & 0xFF; + buffer[2] = (value >> 16) & 0xFF; + buffer[3] = (value >> 24) & 0xFF; + + fwrite(buffer, 1, 4, file); +} + +void WriteMidiInt(FILE *file, unsigned int value, bool isUnsigned) { + unsigned char buffer[4]; + + // Big endian + buffer[0] = (value >> 24) & 0xFF; + buffer[1] = (value >> 16) & 0xFF; + buffer[2] = (value >> 8) & 0xFF; + buffer[3] = value & 0xFF; + + fwrite(buffer, 1, 4, file); +} + +void WriteMidiShort(FILE *file, unsigned short value, bool isUnsigned) { + unsigned char buffer[2]; + + // Big endian + buffer[0] = (value >> 8) & 0xFF; + buffer[1] = value & 0xFF; + + fwrite(buffer, 1, 2, file); +} + +void WriteMidiVarInt(FILE *file, unsigned int value) { + unsigned char buffer[4]; + int numBytes = 0; + + // Build the bytes from least significant to most significant + do { + buffer[numBytes++] = (value & 0x7F) | (numBytes > 0 ? 0x80 : 0); + value >>= 7; + } while (value > 0 && numBytes < 4); + + // Write the bytes in reverse order + for (int i = numBytes - 1; i >= 0; i--) { + // Clear the continuation bit for the last byte + if (i == 0) { + buffer[i] &= 0x7F; + } + fwrite(&buffer[i], 1, 1, file); + } +} + +void WriteString(FILE *file, const char *str) { + // Write null-terminated string + fwrite(str, 1, strlen(str) + 1, file); +} + +unsigned int ReadMidiInt(FILE *file, bool isUnsigned) { + unsigned char buffer[4]; + fread(buffer, 1, 4, file); + + // Big endian + unsigned int result = + (buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + (buffer[3]); + + if (!isUnsigned && (result & 0x80000000)) { + // Convert to signed if needed + return (int)result; + } + + return result; +} + +unsigned short ReadMidiShort(FILE *file, bool isUnsigned) { + unsigned char buffer[2]; + fread(buffer, 1, 2, file); + + // Big endian + unsigned short result = (buffer[0] << 8) | buffer[1]; + + if (!isUnsigned && (result & 0x8000)) { + // Convert to signed if needed + return (short)result; + } + + return result; +} + +unsigned int ReadMidiVarInt(FILE *file) { + unsigned int result = 0; + unsigned char byte; + + do { + fread(&byte, 1, 1, file); + result = (result << 7) | (byte & 0x7F); + } while (byte & 0x80); + + return result; +} + +void ReadString(FILE *file, char *buffer, int maxLength) { + int i = 0; + char byte; + + while (i < maxLength - 1) { + fread(&byte, 1, 1, file); + if (byte == 0) { + break; + } + buffer[i++] = byte; + } + + buffer[i] = '\0'; +} + +// Parse AMB file chunks +bool ParsePrgmChunk(FILE *file, PrgmChunk *chunk) { + chunk->size = ReadAmbInt(file, true); + chunk->number = ReadAmbInt(file, true); + chunk->flags = ReadAmbInt(file, false); + chunk->maxRandomSpeed = ReadAmbInt(file, false); + chunk->minRandomSpeed = ReadAmbInt(file, false); + chunk->maxRandomVolume = ReadAmbInt(file, false); + chunk->minRandomVolume = ReadAmbInt(file, false); + + // Read end marker + unsigned int endMarker = ReadAmbInt(file, true); + if (endMarker != 0xFA) { + MessageBox(NULL, "Expected 0xFA marker before strings in Prgm chunk", "Error", MB_OK | MB_ICONERROR); + return false; + } + + ReadString(file, chunk->effectName, sizeof(chunk->effectName)); + ReadString(file, chunk->varName, sizeof(chunk->varName)); + + return true; +} + +bool ParseKmapChunk(FILE *file, KmapChunk *chunk) { + chunk->size = ReadAmbInt(file, true); + chunk->flags = ReadAmbInt(file, true); + chunk->param1 = ReadAmbInt(file, true); + chunk->param2 = ReadAmbInt(file, true); + + ReadString(file, chunk->varName, sizeof(chunk->varName)); + + chunk->itemCount = ReadAmbInt(file, true); + + if ((chunk->flags & 6) != 0) { + chunk->itemSize = ReadAmbInt(file, true); + } else { + chunk->itemSize = 0; + } + + // Read items + for (int i = 0; i < chunk->itemCount && i < MAX_ITEMS; i++) { + if ((chunk->flags & 6) == 0) { + // Not used in Civ3 + int aint1 = ReadAmbInt(file, true); + int aint2 = ReadAmbInt(file, true); + } else { + // Read the 12-byte data block + fread(chunk->items[i].data, 1, chunk->itemSize, file); + } + + ReadString(file, chunk->items[i].wavFileName, sizeof(chunk->items[i].wavFileName)); + } + + // Read end marker + unsigned int endMarker = ReadAmbInt(file, true); + if (endMarker != 0xFA) { + MessageBox(NULL, "Expected 0xFA marker at end of Kmap chunk", "Error", MB_OK | MB_ICONERROR); + return false; + } + + return true; +} + +bool ParseGlblChunk(FILE *file, GlblChunk *chunk) { + chunk->size = ReadAmbInt(file, true); + long startPos = ftell(file); + + chunk->dataSize = ReadAmbInt(file, true); + fread(chunk->data, 1, chunk->dataSize, file); + + // Read any extra data + long currentPos = ftell(file); + long remainingSize = chunk->size - (currentPos - startPos); + + if (remainingSize > 0 && remainingSize < sizeof(chunk->extraData)) { + fread(chunk->extraData, 1, remainingSize, file); + chunk->extraDataSize = (int)remainingSize; + } else { + chunk->extraDataSize = 0; + } + + return true; +} + +// Parse TrackName event from MIDI file +bool ParseTrackNameEvent(FILE *file, TrackNameEvent *event) { + unsigned char metaType; + fread(&metaType, 1, 1, file); + + if (metaType != 0x03) { + MessageBox(NULL, "Expected TrackName event (0x03)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned int length = ReadMidiVarInt(file); + memset(event->name, 0, sizeof(event->name)); + fread(event->name, 1, length < sizeof(event->name) ? length : sizeof(event->name) - 1, file); + + return true; +} + +// Parse SMPTEOffset event from MIDI file +bool ParseSMPTEOffsetEvent(FILE *file, SMPTEOffsetEvent *event) { + unsigned char metaType; + fread(&metaType, 1, 1, file); + + if (metaType != 0x54) { + MessageBox(NULL, "Expected SMPTEOffset event (0x54)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned char length; + fread(&length, 1, 1, file); + + if (length != 5) { + MessageBox(NULL, "Invalid SMPTEOffset event length (expected 5)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + event->hr = fgetc(file); + event->mn = fgetc(file); + event->se = fgetc(file); + event->fr = fgetc(file); + event->ff = fgetc(file); + + return true; +} + +// Parse TimeSignature event from MIDI file +bool ParseTimeSignatureEvent(FILE *file, TimeSignatureEvent *event) { + unsigned char metaType; + fread(&metaType, 1, 1, file); + + if (metaType != 0x58) { + MessageBox(NULL, "Expected TimeSignature event (0x58)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned char length; + fread(&length, 1, 1, file); + + if (length != 4) { + MessageBox(NULL, "Invalid TimeSignature event length (expected 4)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + event->nn = fgetc(file); + event->dd = fgetc(file); + event->cc = fgetc(file); + event->bb = fgetc(file); + + return true; +} + +// Parse SetTempo event from MIDI file +bool ParseSetTempoEvent(FILE *file, SetTempoEvent *event) { + unsigned char metaType; + fread(&metaType, 1, 1, file); + + if (metaType != 0x51) { + MessageBox(NULL, "Expected SetTempo event (0x51)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned char length; + fread(&length, 1, 1, file); + + if (length != 3) { + MessageBox(NULL, "Invalid SetTempo event length (expected 3)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned char tempo[3]; + fread(tempo, 1, 3, file); + event->microsecondsPerQuarterNote = (tempo[0] << 16) | (tempo[1] << 8) | tempo[2]; + + return true; +} + +// Parse EndOfTrack event from MIDI file +bool ParseEndOfTrackEvent(FILE *file) { + unsigned char metaType; + fread(&metaType, 1, 1, file); + + if (metaType != 0x2F) { + MessageBox(NULL, "Expected EndOfTrack event (0x2F)", "Error", MB_OK | MB_ICONERROR); + return false; + } + + unsigned char zero; + fread(&zero, 1, 1, file); // Should be zero + + return true; +} + +// Parse ControlChange event from MIDI file +bool ParseControlChangeEvent(FILE *file, ControlChangeEvent *event, int *channelNumber) { + unsigned char statusByte; + fread(&statusByte, 1, 1, file); + + // Check if the status byte indicates a control change event (0xBn) + if ((statusByte >> 4) != 0xB) { + // If channelNumber pointer is provided, we're expecting running status + if (channelNumber != NULL) { + // Put the byte back for reading data + fseek(file, -1, SEEK_CUR); + event->channelNumber = *channelNumber; + } else { + MessageBox(NULL, "Expected ControlChange event (0xBn)", "Error", MB_OK | MB_ICONERROR); + return false; + } + } else { + event->channelNumber = statusByte & 0x0F; + // Save channel number for possible running status + if (channelNumber != NULL) { + *channelNumber = event->channelNumber; + } + } + + event->controllerNumber = fgetc(file); + event->value = fgetc(file); + + return true; +} + +// Parse ProgramChange event from MIDI file +bool ParseProgramChangeEvent(FILE *file, ProgramChangeEvent *event, int *channelNumber) { + unsigned char statusByte; + fread(&statusByte, 1, 1, file); + + // Check if the status byte indicates a program change event (0xCn) + if ((statusByte >> 4) != 0xC) { + // If channelNumber pointer is provided, we're expecting running status + if (channelNumber != NULL) { + // Put the byte back for reading data + fseek(file, -1, SEEK_CUR); + event->channelNumber = *channelNumber; + } else { + MessageBox(NULL, "Expected ProgramChange event (0xCn)", "Error", MB_OK | MB_ICONERROR); + return false; + } + } else { + event->channelNumber = statusByte & 0x0F; + // Save channel number for possible running status + if (channelNumber != NULL) { + *channelNumber = event->channelNumber; + } + } + + event->programNumber = fgetc(file); + + return true; +} + +// Parse NoteOn event from MIDI file +bool ParseNoteOnEvent(FILE *file, NoteOnEvent *event, int *channelNumber) { + unsigned char statusByte; + fread(&statusByte, 1, 1, file); + + // Check if the status byte indicates a note on event (0x9n) + if ((statusByte >> 4) != 0x9) { + // If channelNumber pointer is provided, we're expecting running status + if (channelNumber != NULL) { + // Put the byte back for reading data + fseek(file, -1, SEEK_CUR); + event->channelNumber = *channelNumber; + } else { + MessageBox(NULL, "Expected NoteOn event (0x9n)", "Error", MB_OK | MB_ICONERROR); + return false; + } + } else { + event->channelNumber = statusByte & 0x0F; + // Save channel number for possible running status + if (channelNumber != NULL) { + *channelNumber = event->channelNumber; + } + } + + event->key = fgetc(file); + event->velocity = fgetc(file); + + return true; +} + +// Parse NoteOff event from MIDI file +bool ParseNoteOffEvent(FILE *file, NoteOffEvent *event, int *channelNumber) { + unsigned char statusByte; + fread(&statusByte, 1, 1, file); + + // Check if the status byte indicates a note off event (0x8n) + if ((statusByte >> 4) != 0x8) { + // Check if it's a note on with velocity 0 (equivalent to note off) + if ((statusByte >> 4) == 0x9) { + event->channelNumber = statusByte & 0x0F; + event->key = fgetc(file); + event->velocity = fgetc(file); + + // Check if velocity is 0 (note off) + if (event->velocity > 0) { + MessageBox(NULL, "Expected NoteOff event but got NoteOn with velocity > 0", "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Save channel number for possible running status + if (channelNumber != NULL) { + *channelNumber = event->channelNumber; + } + + return true; + } + + // If channelNumber pointer is provided, we're expecting running status + if (channelNumber != NULL) { + // Put the byte back for reading data + fseek(file, -1, SEEK_CUR); + event->channelNumber = *channelNumber; + } else { + MessageBox(NULL, "Expected NoteOff event (0x8n)", "Error", MB_OK | MB_ICONERROR); + return false; + } + } else { + event->channelNumber = statusByte & 0x0F; + // Save channel number for possible running status + if (channelNumber != NULL) { + *channelNumber = event->channelNumber; + } + } + + event->key = fgetc(file); + event->velocity = fgetc(file); + + return true; +} + +// Parse InfoTrack from MIDI file +bool ParseInfoTrack(FILE *file, InfoTrack *track) { + // Read the file tag + char trackTag[5] = {0}; + fread(trackTag, 1, 4, file); + + if (strcmp(trackTag, "MTrk") != 0) { + char errMsg[256]; + sprintf(errMsg, "Invalid MIDI info track header: expected 'MTrk', got '%.4s'", trackTag); + MessageBox(NULL, errMsg, "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Read track chunk size + track->size = ReadMidiInt(file, true); + long startPos = ftell(file); + + // Read events in the InfoTrack + + // 1. TrackName event + track->deltaTimeTrackName = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for TrackName", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseTrackNameEvent(file, &track->trackName)) return false; + + // 2. SMPTEOffset event + track->deltaTimeSMPTEOffset = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for SMPTEOffset", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseSMPTEOffsetEvent(file, &track->smpteOffset)) return false; + + // 3. TimeSignature event + track->deltaTimeTimeSignature = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for TimeSignature", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseTimeSignatureEvent(file, &track->timeSignature)) return false; + + // 4. SetTempo event + track->deltaTimeSetTempo = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for SetTempo", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseSetTempoEvent(file, &track->setTempo)) return false; + + // 5. EndOfTrack event + track->deltaTimeEndOfTrack = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for EndOfTrack", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseEndOfTrackEvent(file)) return false; + + // Ensure we've read exactly the size of the track + long currentPos = ftell(file); + if (currentPos != startPos + track->size) { + MessageBox(NULL, "Info track size mismatch", "Error", MB_OK | MB_ICONERROR); + return false; + } + + return true; +} + +// Parse SoundTrack from MIDI file +bool ParseSoundTrack(FILE *file, SoundTrack *track) { + // Read the file tag + char trackTag[5] = {0}; + fread(trackTag, 1, 4, file); + + if (strcmp(trackTag, "MTrk") != 0) { + char errMsg[256]; + sprintf(errMsg, "Invalid MIDI sound track header: expected 'MTrk', got '%.4s'", trackTag); + MessageBox(NULL, errMsg, "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Read track chunk size + track->size = ReadMidiInt(file, true); + long startPos = ftell(file); + + // Initialize control change count + track->controlChangeCount = 0; + + // 1. TrackName event + track->deltaTimeTrackName = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for TrackName", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseTrackNameEvent(file, &track->trackName)) return false; + + // 2. ControlChange events (1 or 2) + unsigned char nextByte; + int currentChannelNumber = -1; // For running status + + // Peek at the next byte to determine event type + long peekPos = ftell(file); + track->deltaTimeControlChanges[0] = ReadMidiVarInt(file); + nextByte = fgetc(file); + fseek(file, peekPos, SEEK_SET); // Go back to where we were + + // Check for control change events (0xBn) + while (((nextByte >> 4) == 0xB || currentChannelNumber != -1) && + track->controlChangeCount < MAX_CONTROL_CHANGES) { + + // Read the delta time + track->deltaTimeControlChanges[track->controlChangeCount] = ReadMidiVarInt(file); + + // Parse the control change event + if (!ParseControlChangeEvent(file, &track->controlChanges[track->controlChangeCount], ¤tChannelNumber)) { + return false; + } + + track->controlChangeCount++; + + // Peek at the next byte to determine if there's another control change + if (track->controlChangeCount < MAX_CONTROL_CHANGES) { + peekPos = ftell(file); + int testDeltaTime = ReadMidiVarInt(file); + nextByte = fgetc(file); + fseek(file, peekPos, SEEK_SET); // Go back to where we were + + // If next byte is not a control change and not a running status, break + if ((nextByte >> 4) != 0xB && (nextByte & 0x80) != 0) { + currentChannelNumber = -1; // Reset running status + break; + } + } + } + + // 3. ProgramChange event + track->deltaTimeProgramChange = ReadMidiVarInt(file); + if (!ParseProgramChangeEvent(file, &track->programChange, NULL)) return false; + + // 4. NoteOn event + track->deltaTimeNoteOn = ReadMidiVarInt(file); + if (!ParseNoteOnEvent(file, &track->noteOn, NULL)) return false; + + // 5. NoteOff event + track->deltaTimeNoteOff = ReadMidiVarInt(file); + if (!ParseNoteOffEvent(file, &track->noteOff, NULL)) return false; + + // 6. EndOfTrack event + track->deltaTimeEndOfTrack = ReadMidiVarInt(file); + if (fgetc(file) != 0xFF) { // Meta event marker + MessageBox(NULL, "Expected Meta event marker (0xFF) for EndOfTrack", "Error", MB_OK | MB_ICONERROR); + return false; + } + if (!ParseEndOfTrackEvent(file)) return false; + + // Ensure we've read exactly the size of the track + long currentPos = ftell(file); + if (currentPos != startPos + track->size) { + MessageBox(NULL, "Sound track size mismatch", "Error", MB_OK | MB_ICONERROR); + return false; + } + + return true; +} + +bool ParseMidi(FILE *file, MidiData *midi) { + // Read header size + unsigned char sizeBytes[4]; + fread(sizeBytes, 1, 4, file); + + // Values for MIDI header should be big-endian (MSB first) + int headerSize = (sizeBytes[0] << 24) | (sizeBytes[1] << 16) | (sizeBytes[2] << 8) | sizeBytes[3]; + + // The header size should be 6 for standard MIDI files + if (headerSize != 6) { + MessageBox(NULL, "Invalid MIDI header size", "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Read format, track count, and division + unsigned char formatBytes[2], trackCountBytes[2], divisionBytes[2]; + + fread(formatBytes, 1, 2, file); + fread(trackCountBytes, 1, 2, file); + fread(divisionBytes, 1, 2, file); + + // Interpret as big-endian values + midi->format = (formatBytes[0] << 8) | formatBytes[1]; + midi->trackCount = (trackCountBytes[0] << 8) | trackCountBytes[1]; + midi->ticksPerQuarterNote = (divisionBytes[0] << 8) | divisionBytes[1]; + + if (midi->format != 1) { + MessageBox(NULL, "Unsupported MIDI format", "Error", MB_OK | MB_ICONERROR); + return false; + } + + if (midi->trackCount < 2 || midi->trackCount > (MAX_SOUND_TRACKS + 1)) { + MessageBox(NULL, "Invalid MIDI track count", "Error", MB_OK | MB_ICONERROR); + return false; + } + + if ((midi->ticksPerQuarterNote & 0x8000) != 0) { + MessageBox(NULL, "Unsupported MIDI time division format", "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Parse InfoTrack (first track) + if (!ParseInfoTrack(file, &midi->infoTrack)) { + return false; + } + + // Set seconds per quarter note from the tempo in the InfoTrack + midi->secondsPerQuarterNote = midi->infoTrack.setTempo.microsecondsPerQuarterNote / 1000000.0f; + + // Parse SoundTracks + int soundTrackCount = midi->trackCount - 1; // First track is InfoTrack + + for (int i = 0; i < soundTrackCount && i < MAX_SOUND_TRACKS; i++) { + if (!ParseSoundTrack(file, &midi->soundTracks[i])) { + return false; + } + } + + return true; +} + +// Load AMB file +bool LoadAmbFile(const Path filePath, AmbFile * out) { + FILE *file = fopen(filePath, "rb"); + if (!file) { + MessageBox(NULL, "Failed to open AMB file", "Error", MB_OK | MB_ICONERROR); + return false; + } + + // Initialize AMB file structure + memset(out, 0, sizeof *out); + strcpy(out->filePath, filePath); + + // Parse all chunks + bool success = true; + while (!feof(file)) { + char tag[5] = {0}; + if (fread(tag, 1, 4, file) != 4) { + break; // End of file + } + + if (strcmp(tag, "prgm") == 0) { + if (out->prgmChunkCount < MAX_CHUNKS) { + if (!ParsePrgmChunk(file, &out->prgmChunks[out->prgmChunkCount++])) { + success = false; + break; + } + } else { + MessageBox(NULL, "Too many Prgm chunks", "Error", MB_OK | MB_ICONERROR); + success = false; + break; + } + } else if (strcmp(tag, "kmap") == 0) { + if (out->kmapChunkCount < MAX_CHUNKS) { + if (!ParseKmapChunk(file, &out->kmapChunks[out->kmapChunkCount++])) { + success = false; + break; + } + } else { + MessageBox(NULL, "Too many Kmap chunks", "Error", MB_OK | MB_ICONERROR); + success = false; + break; + } + } else if (strcmp(tag, "glbl") == 0) { + if (!out->hasGlblChunk) { + if (!ParseGlblChunk(file, &out->glblChunk)) { + success = false; + break; + } + out->hasGlblChunk = true; + } else { + MessageBox(NULL, "Multiple Glbl chunks not supported", "Error", MB_OK | MB_ICONERROR); + success = false; + break; + } + } else if (strcmp(tag, "MThd") == 0) { + // MIDI header detected, parse the MIDI data + // Don't need to go back, ParseMidi now expects to be positioned after the tag + if (!ParseMidi(file, &out->midi)) { + success = false; + break; + } + } else { + char message[256]; + sprintf(message, "Unknown chunk tag: %s", tag); + MessageBox(NULL, message, "Error", MB_OK | MB_ICONERROR); + success = false; + break; + } + } + + fclose(file); + + return success; +} + +int ComputePrgmChunkSize(PrgmChunk const * chunk) { + // size = 28 bytes for 7 4-byte ints + 2 null terminators + lengths of the two strings + // All Prgm chunks in the AMBs that ship with Civ 3 are confirmed to follow this rule + return 30 + strlen(chunk->effectName) + strlen(chunk->varName); +} + +// Functions to write AMB file chunks +bool WritePrgmChunk(FILE *file, PrgmChunk const * chunk) { + // Write tag + fwrite("prgm", 1, 4, file); + + // Write chunk data + WriteAmbInt(file, chunk->size, true); + WriteAmbInt(file, chunk->number, true); + WriteAmbInt(file, chunk->flags, false); + WriteAmbInt(file, chunk->maxRandomSpeed, false); + WriteAmbInt(file, chunk->minRandomSpeed, false); + WriteAmbInt(file, chunk->maxRandomVolume, false); + WriteAmbInt(file, chunk->minRandomVolume, false); + + // Write end marker before strings + WriteAmbInt(file, 0xFA, true); + + // Write strings + WriteString(file, chunk->effectName); + WriteString(file, chunk->varName); + + return true; +} + +int ComputeKmapChunkSize(KmapChunk const * chunk) { + // size w/o items = 20 bytes for 5 4-byte ints + length of var name + null terminator + end indicator + int size = 25 + strlen(chunk->varName); + for (int i = 0; i < chunk->itemCount; i++) + // size of each item = 12 bytes unknown data + length of wav file name + null terminator + size += 12 + strlen(chunk->items[i].wavFileName) + 1; + // This rule matches the size of all Kmap chunks in the Civ 3 AMBs except two, both in GalleyAttack.amb. Those chunks are broken, however, and + // don't play any sound. + return size; +} + +bool WriteKmapChunk(FILE *file, KmapChunk const * chunk) { + // Write tag + fwrite("kmap", 1, 4, file); + + // Write chunk data + WriteAmbInt(file, chunk->size, true); + WriteAmbInt(file, chunk->flags, true); + WriteAmbInt(file, chunk->param1, true); + WriteAmbInt(file, chunk->param2, true); + + // Write variable name + WriteString(file, chunk->varName); + + // Write item count + WriteAmbInt(file, chunk->itemCount, true); + + // Write item size if needed + if ((chunk->flags & 6) != 0) { + WriteAmbInt(file, chunk->itemSize, true); + } + + // Write items + for (int i = 0; i < chunk->itemCount && i < MAX_ITEMS; i++) { + if ((chunk->flags & 6) == 0) { + // Not used in Civ3, but we should still write placeholder data + WriteAmbInt(file, 0, true); // Placeholder for aint1 + WriteAmbInt(file, 0, true); // Placeholder for aint2 + } else { + // Write the data block + fwrite(chunk->items[i].data, 1, chunk->itemSize, file); + } + + // Write WAV filename + WriteString(file, chunk->items[i].wavFileName); + } + + // Write end marker + WriteAmbInt(file, 0xFA, true); + + return true; +} + +bool WriteGlblChunk(FILE *file, GlblChunk const * chunk) { + // Write tag + fwrite("glbl", 1, 4, file); + + // Write chunk size + WriteAmbInt(file, chunk->size, true); + + // Write data size + WriteAmbInt(file, chunk->dataSize, true); + + // Write data + fwrite(chunk->data, 1, chunk->dataSize, file); + + // Write extra data if present + if (chunk->extraDataSize > 0) { + fwrite(chunk->extraData, 1, chunk->extraDataSize, file); + } + + return true; +} + +// Function to write TrackName event to MIDI file +void WriteTrackNameEvent(FILE *file, const TrackNameEvent *event) { + fputc(0x03, file); // Track name meta event type + + // Length of the name + WriteMidiVarInt(file, strlen(event->name)); + + // Name data + fwrite(event->name, 1, strlen(event->name), file); +} + +// Function to write SMPTEOffset event to MIDI file +void WriteSMPTEOffsetEvent(FILE *file, const SMPTEOffsetEvent *event) { + fputc(0x54, file); // SMPTE offset meta event type + fputc(0x05, file); // Length is always 5 + + // SMPTE data + fputc(event->hr, file); + fputc(event->mn, file); + fputc(event->se, file); + fputc(event->fr, file); + fputc(event->ff, file); +} + +// Function to write TimeSignature event to MIDI file +void WriteTimeSignatureEvent(FILE *file, const TimeSignatureEvent *event) { + fputc(0x58, file); // Time signature meta event type + fputc(0x04, file); // Length is always 4 + + // Time signature data + fputc(event->nn, file); + fputc(event->dd, file); + fputc(event->cc, file); + fputc(event->bb, file); +} + +// Function to write SetTempo event to MIDI file +void WriteSetTempoEvent(FILE *file, const SetTempoEvent *event) { + fputc(0x51, file); // Set tempo meta event type + fputc(0x03, file); // Length is always 3 + + // Tempo data (microseconds per quarter note) + unsigned int tempo = event->microsecondsPerQuarterNote; + fputc((tempo >> 16) & 0xFF, file); + fputc((tempo >> 8) & 0xFF, file); + fputc(tempo & 0xFF, file); +} + +// Function to write EndOfTrack event to MIDI file +void WriteEndOfTrackEvent(FILE *file) { + fputc(0x2F, file); // End of track meta event type + fputc(0x00, file); // Length is always 0 +} + +// Function to write ControlChange event to MIDI file +void WriteControlChangeEvent(FILE *file, const ControlChangeEvent *event) { + // Control change status byte: 0xBn, where n is the channel number + fputc(0xB0 | (event->channelNumber & 0x0F), file); + + // Controller number and value + fputc(event->controllerNumber & 0x7F, file); + fputc(event->value & 0x7F, file); +} + +// Function to write ProgramChange event to MIDI file +void WriteProgramChangeEvent(FILE *file, const ProgramChangeEvent *event) { + // Program change status byte: 0xCn, where n is the channel number + fputc(0xC0 | (event->channelNumber & 0x0F), file); + + // Program number + fputc(event->programNumber & 0x7F, file); +} + +// Function to write NoteOn event to MIDI file +void WriteNoteOnEvent(FILE *file, const NoteOnEvent *event) { + // Note on status byte: 0x9n, where n is the channel number + fputc(0x90 | (event->channelNumber & 0x0F), file); + + // Key and velocity + fputc(event->key & 0x7F, file); + fputc(event->velocity & 0x7F, file); +} + +// Function to write NoteOff event to MIDI file +void WriteNoteOffEvent(FILE *file, const NoteOffEvent *event) { + // Note off status byte: 0x8n, where n is the channel number + fputc(0x80 | (event->channelNumber & 0x0F), file); + + // Key and velocity + fputc(event->key & 0x7F, file); + fputc(event->velocity & 0x7F, file); +} + +// Function to write InfoTrack to MIDI file +void WriteInfoTrack(FILE *file, const InfoTrack *track) { + // Write track tag + fwrite("MTrk", 1, 4, file); + + // We need to calculate track size, so we'll save the current position, + // write a placeholder, write the events, then come back and update it + long sizePos = ftell(file); + + // Write placeholder for size + WriteMidiInt(file, 0, true); + + // Save position at start of track data + long startPos = ftell(file); + + // Write all events in sequence + + // 1. TrackName event + WriteMidiVarInt(file, track->deltaTimeTrackName); + fputc(0xFF, file); // Meta event marker + WriteTrackNameEvent(file, &track->trackName); + + // 2. SMPTEOffset event + WriteMidiVarInt(file, track->deltaTimeSMPTEOffset); + fputc(0xFF, file); // Meta event marker + WriteSMPTEOffsetEvent(file, &track->smpteOffset); + + // 3. TimeSignature event + WriteMidiVarInt(file, track->deltaTimeTimeSignature); + fputc(0xFF, file); // Meta event marker + WriteTimeSignatureEvent(file, &track->timeSignature); + + // 4. SetTempo event + WriteMidiVarInt(file, track->deltaTimeSetTempo); + fputc(0xFF, file); // Meta event marker + WriteSetTempoEvent(file, &track->setTempo); + + // 5. EndOfTrack event + WriteMidiVarInt(file, track->deltaTimeEndOfTrack); + fputc(0xFF, file); // Meta event marker + WriteEndOfTrackEvent(file); + + // Get end position and calculate size + long endPos = ftell(file); + unsigned int trackSize = (unsigned int)(endPos - startPos); + + // Go back and write the actual size + fseek(file, sizePos, SEEK_SET); + WriteMidiInt(file, trackSize, true); + + // Return to the end of the track + fseek(file, endPos, SEEK_SET); +} + +// Function to write SoundTrack to MIDI file +unsigned int WriteSoundTrack(FILE *file, const SoundTrack *track) { + // Write track tag + fwrite("MTrk", 1, 4, file); + + // We need to calculate track size, so we'll save the current position, + // write a placeholder, write the events, then come back and update it + long sizePos = ftell(file); + + // Write placeholder for size + WriteMidiInt(file, 0, true); + + // Save position at start of track data + long startPos = ftell(file); + + // Write all events in sequence + + // 1. TrackName event + WriteMidiVarInt(file, track->deltaTimeTrackName); + fputc(0xFF, file); // Meta event marker + WriteTrackNameEvent(file, &track->trackName); + + // 2. ControlChange events (1 or 2) + for (int i = 0; i < track->controlChangeCount; i++) { + WriteMidiVarInt(file, track->deltaTimeControlChanges[i]); + WriteControlChangeEvent(file, &track->controlChanges[i]); + } + + // 3. ProgramChange event + WriteMidiVarInt(file, track->deltaTimeProgramChange); + WriteProgramChangeEvent(file, &track->programChange); + + // 4. NoteOn event + WriteMidiVarInt(file, track->deltaTimeNoteOn); + WriteNoteOnEvent(file, &track->noteOn); + + // 5. NoteOff event + WriteMidiVarInt(file, track->deltaTimeNoteOff); + WriteNoteOffEvent(file, &track->noteOff); + + // 6. EndOfTrack event + WriteMidiVarInt(file, track->deltaTimeEndOfTrack); + fputc(0xFF, file); // Meta event marker + WriteEndOfTrackEvent(file); + + // Get end position and calculate size + long endPos = ftell(file); + unsigned int trackSize = (unsigned int)(endPos - startPos); + + // Go back and write the actual size + fseek(file, sizePos, SEEK_SET); + WriteMidiInt(file, trackSize, true); + + // Return to the end of the track + fseek(file, endPos, SEEK_SET); + + return trackSize; +} + +int ComputeSoundTrackSize(SoundTrack const * track) { + FILE *memFile = tmpfile(); + unsigned int size = WriteSoundTrack(memFile, track); + fclose(memFile); + return size; +} + +bool WriteMidi(FILE *file, MidiData const * midi) { + // Write MIDI header + fwrite("MThd", 1, 4, file); + + // Header size is always 6 + WriteMidiInt(file, 6, true); + + // Write format, track count, and division + WriteMidiShort(file, midi->format, false); + WriteMidiShort(file, midi->trackCount, false); + WriteMidiShort(file, midi->ticksPerQuarterNote, false); + + // Write InfoTrack + WriteInfoTrack(file, &midi->infoTrack); + + // Write SoundTracks + int soundTrackCount = midi->trackCount - 1; // First track is InfoTrack + + for (int i = 0; i < soundTrackCount && i < MAX_SOUND_TRACKS; i++) { + WriteSoundTrack(file, &midi->soundTracks[i]); + } + + return true; +} + +// Function to save AMB file to the specified path +bool SaveAmbFile(AmbFile const * amb, const Path filePath) { + FILE *file = fopen(filePath, "wb"); + if (!file) { + return false; + } + + bool success = true; + + // Write Prgm chunks + for (int i = 0; i < amb->prgmChunkCount; i++) { + if (!WritePrgmChunk(file, &amb->prgmChunks[i])) { + success = false; + break; + } + } + + // Write Kmap chunks + if (success) { + for (int i = 0; i < amb->kmapChunkCount; i++) { + if (!WriteKmapChunk(file, &amb->kmapChunks[i])) { + success = false; + break; + } + } + } + + // Write Glbl chunk if present + if (success && amb->hasGlblChunk) { + if (!WriteGlblChunk(file, &amb->glblChunk)) { + success = false; + } + } + + // Write MIDI data + if (success) { + if (!WriteMidi(file, &amb->midi)) { + success = false; + } + } + + fclose(file); + + // Remove the file if we failed + if (!success) { + remove(filePath); + } + + return success; +} + +// Utility function to get sound track count +int GetSoundTrackCount(const MidiData *midi) { + return midi->trackCount - 1; // First track is InfoTrack +} + +// Function to describe the loaded AMB file (for debugging) +void DescribeAmbFile(AmbFile const * amb, char *buffer, size_t bufferSize) { + char *pos = buffer; + int remainingSize = (int)bufferSize; + + // Describe file path + int written = snprintf(pos, remainingSize, "File: %s\r\n\r\n", amb->filePath); + pos += written; + remainingSize -= written; + + // Describe Prgm chunks + for (int i = 0; i < amb->prgmChunkCount && remainingSize > 0; i++) { + PrgmChunk *chunk = &amb->prgmChunks[i]; + written = snprintf(pos, remainingSize, + "Prgm #%d:\r\n" + " Size: %d\r\n" + " Number: %d\r\n" + " Flags: %d\r\n" + " Max Random Speed: %d\r\n" + " Min Random Speed: %d\r\n" + " Max Random Volume: %d\r\n" + " Min Random Volume: %d\r\n" + " Effect Name: '%s'\r\n" + " Var Name: '%s'\r\n\r\n", + i + 1, chunk->size, chunk->number, chunk->flags, + chunk->maxRandomSpeed, chunk->minRandomSpeed, + chunk->maxRandomVolume, chunk->minRandomVolume, + chunk->effectName, chunk->varName); + pos += written; + remainingSize -= written; + } + + // Describe Kmap chunks + for (int i = 0; i < amb->kmapChunkCount && remainingSize > 0; i++) { + KmapChunk *chunk = &amb->kmapChunks[i]; + written = snprintf(pos, remainingSize, + "Kmap #%d:\r\n" + " Size: %d\r\n" + " Flags: %d\r\n" + " Param1: %d\r\n" + " Param2: %d\r\n" + " Var Name: '%s'\r\n" + " Item Count: %d\r\n" + " Item Size: %d\r\n", + i + 1, chunk->size, chunk->flags, + chunk->param1, chunk->param2, + chunk->varName, chunk->itemCount, chunk->itemSize); + pos += written; + remainingSize -= written; + + // Describe Kmap items + for (int j = 0; j < chunk->itemCount && remainingSize > 0; j++) { + written = snprintf(pos, remainingSize, + " Item #%d: WAV File: '%s'\r\n", + j + 1, chunk->items[j].wavFileName); + pos += written; + remainingSize -= written; + } + + written = snprintf(pos, remainingSize, "\r\n"); + pos += written; + remainingSize -= written; + } + + // Describe Glbl chunk + if (amb->hasGlblChunk && remainingSize > 0) { + GlblChunk const * chunk = &amb->glblChunk; + written = snprintf(pos, remainingSize, + "Glbl:\r\n" + " Size: %d\r\n" + " Data Size: %d\r\n\r\n", + chunk->size, chunk->dataSize); + pos += written; + remainingSize -= written; + } + + // Describe MIDI data + if (remainingSize > 0) { + written = snprintf(pos, remainingSize, + "MIDI:\r\n" + " Format: %d\r\n" + " Track Count: %d\r\n" + " Ticks Per Quarter Note: %d\r\n" + " Seconds Per Quarter Note: %.6f\r\n\r\n", + amb->midi.format, amb->midi.trackCount, + amb->midi.ticksPerQuarterNote, amb->midi.secondsPerQuarterNote); + pos += written; + remainingSize -= written; + + // Describe InfoTrack + if (remainingSize > 0) { + InfoTrack const *infoTrack = &amb->midi.infoTrack; + float secondsPerTick = amb->midi.secondsPerQuarterNote / amb->midi.ticksPerQuarterNote; + float timestamp = 0.0f; + + written = snprintf(pos, remainingSize, + " InfoTrack:\r\n" + " Size: %d\r\n", + infoTrack->size); + pos += written; + remainingSize -= written; + + // Track name event + timestamp += infoTrack->deltaTimeTrackName * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: TrackName '%s'\r\n", + timestamp, infoTrack->trackName.name); + pos += written; + remainingSize -= written; + + // SMPTE offset event + timestamp += infoTrack->deltaTimeSMPTEOffset * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: SMPTEOffset %d %d %d %d %d\r\n", + timestamp, infoTrack->smpteOffset.hr, + infoTrack->smpteOffset.mn, + infoTrack->smpteOffset.se, + infoTrack->smpteOffset.fr, + infoTrack->smpteOffset.ff); + pos += written; + remainingSize -= written; + + // Time signature event + timestamp += infoTrack->deltaTimeTimeSignature * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: TimeSignature %d %d %d %d\r\n", + timestamp, infoTrack->timeSignature.nn, + infoTrack->timeSignature.dd, + infoTrack->timeSignature.cc, + infoTrack->timeSignature.bb); + pos += written; + remainingSize -= written; + + // Set tempo event + timestamp += infoTrack->deltaTimeSetTempo * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: SetTempo %d\r\n", + timestamp, infoTrack->setTempo.microsecondsPerQuarterNote); + pos += written; + remainingSize -= written; + + // End of track event + timestamp += infoTrack->deltaTimeEndOfTrack * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: EndOfTrack\r\n\r\n", + timestamp); + pos += written; + remainingSize -= written; + } + + // Describe each SoundTrack + int soundTrackCount = GetSoundTrackCount(&amb->midi); + for (int i = 0; i < soundTrackCount && remainingSize > 0; i++) { + SoundTrack const *soundTrack = &amb->midi.soundTracks[i]; + float secondsPerTick = amb->midi.secondsPerQuarterNote / amb->midi.ticksPerQuarterNote; + float timestamp = 0.0f; + + written = snprintf(pos, remainingSize, + " SoundTrack #%d:\r\n" + " Size: %d\r\n", + i + 1, soundTrack->size); + pos += written; + remainingSize -= written; + + // Track name event + timestamp += soundTrack->deltaTimeTrackName * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: TrackName '%s'\r\n", + timestamp, soundTrack->trackName.name); + pos += written; + remainingSize -= written; + + // Control change events + for (int j = 0; j < soundTrack->controlChangeCount && remainingSize > 0; j++) { + timestamp += soundTrack->deltaTimeControlChanges[j] * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: ControlChange %d %d %d\r\n", + timestamp, soundTrack->controlChanges[j].channelNumber, + soundTrack->controlChanges[j].controllerNumber, + soundTrack->controlChanges[j].value); + pos += written; + remainingSize -= written; + } + + // Program change event + timestamp += soundTrack->deltaTimeProgramChange * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: ProgramChange %d %d\r\n", + timestamp, soundTrack->programChange.channelNumber, + soundTrack->programChange.programNumber); + pos += written; + remainingSize -= written; + + // Note on event + timestamp += soundTrack->deltaTimeNoteOn * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: NoteOn %d %d %d\r\n", + timestamp, soundTrack->noteOn.channelNumber, + soundTrack->noteOn.key, + soundTrack->noteOn.velocity); + pos += written; + remainingSize -= written; + + // Note off event + timestamp += soundTrack->deltaTimeNoteOff * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: NoteOff %d %d %d\r\n", + timestamp, soundTrack->noteOff.channelNumber, + soundTrack->noteOff.key, + soundTrack->noteOff.velocity); + pos += written; + remainingSize -= written; + + // End of track event + timestamp += soundTrack->deltaTimeEndOfTrack * secondsPerTick; + written = snprintf(pos, remainingSize, + " %.3f: EndOfTrack\r\n\r\n", + timestamp); + pos += written; + remainingSize -= written; + } + } +} diff --git a/AMB Editor/details_window.c b/AMB Editor/details_window.c index 0bb7f313..e2885f44 100644 --- a/AMB Editor/details_window.c +++ b/AMB Editor/details_window.c @@ -1,161 +1,161 @@ -// This file gets #included into amb_editor.c - -// Global variables for the AMB details window -HWND g_hwndDetailsWindow = NULL; -HWND g_hwndDetailsTextbox = NULL; -WNDPROC g_origDetailsWindowProc = NULL; - -// Window procedure for the details window -LRESULT CALLBACK DetailsWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_SIZE: - // Resize the textbox to fill the window - if (g_hwndDetailsTextbox != NULL) { - RECT rcClient; - GetClientRect(hwnd, &rcClient); - SetWindowPos(g_hwndDetailsTextbox, NULL, - 0, 0, - rcClient.right, rcClient.bottom, - SWP_NOZORDER); - } - return 0; - - case WM_CLOSE: - DestroyWindow(hwnd); - return 0; - - case WM_DESTROY: - g_hwndDetailsWindow = NULL; - g_hwndDetailsTextbox = NULL; - return 0; - } - - return CallWindowProc(g_origDetailsWindowProc, hwnd, uMsg, wParam, lParam); -} - -// Function to show the AMB details window -void ShowAmbDetailsWindow(HWND hwndParent) -{ - // Check if we have a valid AMB file loaded - if (g_ambFile.filePath[0] == '\0') { - MessageBox(hwndParent, "No AMB file loaded. Please open an AMB file first.", - "Error", MB_OK | MB_ICONERROR); - return; - } - - // If the window already exists, just bring it to the front - if (g_hwndDetailsWindow != NULL) { - SetForegroundWindow(g_hwndDetailsWindow); - return; - } - - // Create a new window for the details - HINSTANCE hInstance = GetModuleHandle(NULL); - WNDCLASS wc = {0}; - - // Check if the window class is already registered - if (!GetClassInfo(hInstance, "AMBDetailsWindowClass", &wc)) { - // Register a window class for the details window - wc.lpfnWndProc = DefWindowProc; - wc.hInstance = hInstance; - wc.lpszClassName = "AMBDetailsWindowClass"; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); - - if (!RegisterClass(&wc)) { - MessageBox(hwndParent, "Failed to register window class", "Error", MB_OK | MB_ICONERROR); - return; - } - } - - // Extract filename from the full path for the window title - const char *fileName = strrchr(g_ambFile.filePath, '\\'); - if (fileName) { - fileName++; // Skip past the backslash - } else { - fileName = g_ambFile.filePath; // No backslash found, use the whole path - } - - char windowTitle[100] = {0}; - snprintf(windowTitle, sizeof(windowTitle) - 1, "%s - AMB Details", fileName); - - // Create the details window - g_hwndDetailsWindow = CreateWindowEx( - WS_EX_CLIENTEDGE, - "AMBDetailsWindowClass", - windowTitle, - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 600, 500, - hwndParent, - NULL, - hInstance, - NULL - ); - - if (g_hwndDetailsWindow == NULL) { - MessageBox(hwndParent, "Failed to create details window", "Error", MB_OK | MB_ICONERROR); - return; - } - - // Subclass the window to handle resize events - g_origDetailsWindowProc = (WNDPROC)SetWindowLongPtr(g_hwndDetailsWindow, GWLP_WNDPROC, (LONG_PTR)DetailsWindowProc); - - // Create a multiline read-only text box to display the details - g_hwndDetailsTextbox = CreateWindowEx( - WS_EX_CLIENTEDGE, - "EDIT", - "", - WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | - ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY, - 0, 0, 0, 0, // Will be resized in WM_SIZE handler - g_hwndDetailsWindow, - NULL, - hInstance, - NULL - ); - - if (g_hwndDetailsTextbox == NULL) { - MessageBox(hwndParent, "Failed to create textbox control", "Error", MB_OK | MB_ICONERROR); - DestroyWindow(g_hwndDetailsWindow); - g_hwndDetailsWindow = NULL; - return; - } - - // Set a monospaced font for the textbox - HFONT hFont = CreateFont(14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, - DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "Courier New"); - if (hFont != NULL) { - SendMessage(g_hwndDetailsTextbox, WM_SETFONT, (WPARAM)hFont, TRUE); - } - - // Generate the AMB file details - char *details = (char *)malloc(50000); - if (details) { - DescribeAmbFile(&g_ambFile, details, 50000); - - // Set the text in the textbox - SetWindowText(g_hwndDetailsTextbox, details); - - free(details); - } else { - MessageBox(hwndParent, "Failed to allocate memory for details", "Error", MB_OK | MB_ICONERROR); - DestroyWindow(g_hwndDetailsWindow); - g_hwndDetailsWindow = NULL; - return; - } - - // Force the window to resize the textbox initially - RECT rcClient; - GetClientRect(g_hwndDetailsWindow, &rcClient); - SetWindowPos(g_hwndDetailsTextbox, NULL, - 0, 0, - rcClient.right, rcClient.bottom, - SWP_NOZORDER); - - // Show the window - ShowWindow(g_hwndDetailsWindow, SW_SHOW); - UpdateWindow(g_hwndDetailsWindow); -} +// This file gets #included into amb_editor.c + +// Global variables for the AMB details window +HWND g_hwndDetailsWindow = NULL; +HWND g_hwndDetailsTextbox = NULL; +WNDPROC g_origDetailsWindowProc = NULL; + +// Window procedure for the details window +LRESULT CALLBACK DetailsWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_SIZE: + // Resize the textbox to fill the window + if (g_hwndDetailsTextbox != NULL) { + RECT rcClient; + GetClientRect(hwnd, &rcClient); + SetWindowPos(g_hwndDetailsTextbox, NULL, + 0, 0, + rcClient.right, rcClient.bottom, + SWP_NOZORDER); + } + return 0; + + case WM_CLOSE: + DestroyWindow(hwnd); + return 0; + + case WM_DESTROY: + g_hwndDetailsWindow = NULL; + g_hwndDetailsTextbox = NULL; + return 0; + } + + return CallWindowProc(g_origDetailsWindowProc, hwnd, uMsg, wParam, lParam); +} + +// Function to show the AMB details window +void ShowAmbDetailsWindow(HWND hwndParent) +{ + // Check if we have a valid AMB file loaded + if (g_ambFile.filePath[0] == '\0') { + MessageBox(hwndParent, "No AMB file loaded. Please open an AMB file first.", + "Error", MB_OK | MB_ICONERROR); + return; + } + + // If the window already exists, just bring it to the front + if (g_hwndDetailsWindow != NULL) { + SetForegroundWindow(g_hwndDetailsWindow); + return; + } + + // Create a new window for the details + HINSTANCE hInstance = GetModuleHandle(NULL); + WNDCLASS wc = {0}; + + // Check if the window class is already registered + if (!GetClassInfo(hInstance, "AMBDetailsWindowClass", &wc)) { + // Register a window class for the details window + wc.lpfnWndProc = DefWindowProc; + wc.hInstance = hInstance; + wc.lpszClassName = "AMBDetailsWindowClass"; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + + if (!RegisterClass(&wc)) { + MessageBox(hwndParent, "Failed to register window class", "Error", MB_OK | MB_ICONERROR); + return; + } + } + + // Extract filename from the full path for the window title + const char *fileName = strrchr(g_ambFile.filePath, '\\'); + if (fileName) { + fileName++; // Skip past the backslash + } else { + fileName = g_ambFile.filePath; // No backslash found, use the whole path + } + + char windowTitle[100] = {0}; + snprintf(windowTitle, sizeof(windowTitle) - 1, "%s - AMB Details", fileName); + + // Create the details window + g_hwndDetailsWindow = CreateWindowEx( + WS_EX_CLIENTEDGE, + "AMBDetailsWindowClass", + windowTitle, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 600, 500, + hwndParent, + NULL, + hInstance, + NULL + ); + + if (g_hwndDetailsWindow == NULL) { + MessageBox(hwndParent, "Failed to create details window", "Error", MB_OK | MB_ICONERROR); + return; + } + + // Subclass the window to handle resize events + g_origDetailsWindowProc = (WNDPROC)SetWindowLongPtr(g_hwndDetailsWindow, GWLP_WNDPROC, (LONG_PTR)DetailsWindowProc); + + // Create a multiline read-only text box to display the details + g_hwndDetailsTextbox = CreateWindowEx( + WS_EX_CLIENTEDGE, + "EDIT", + "", + WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | + ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY, + 0, 0, 0, 0, // Will be resized in WM_SIZE handler + g_hwndDetailsWindow, + NULL, + hInstance, + NULL + ); + + if (g_hwndDetailsTextbox == NULL) { + MessageBox(hwndParent, "Failed to create textbox control", "Error", MB_OK | MB_ICONERROR); + DestroyWindow(g_hwndDetailsWindow); + g_hwndDetailsWindow = NULL; + return; + } + + // Set a monospaced font for the textbox + HFONT hFont = CreateFont(14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "Courier New"); + if (hFont != NULL) { + SendMessage(g_hwndDetailsTextbox, WM_SETFONT, (WPARAM)hFont, TRUE); + } + + // Generate the AMB file details + char *details = (char *)malloc(50000); + if (details) { + DescribeAmbFile(&g_ambFile, details, 50000); + + // Set the text in the textbox + SetWindowText(g_hwndDetailsTextbox, details); + + free(details); + } else { + MessageBox(hwndParent, "Failed to allocate memory for details", "Error", MB_OK | MB_ICONERROR); + DestroyWindow(g_hwndDetailsWindow); + g_hwndDetailsWindow = NULL; + return; + } + + // Force the window to resize the textbox initially + RECT rcClient; + GetClientRect(g_hwndDetailsWindow, &rcClient); + SetWindowPos(g_hwndDetailsTextbox, NULL, + 0, 0, + rcClient.right, rcClient.bottom, + SWP_NOZORDER); + + // Show the window + ShowWindow(g_hwndDetailsWindow, SW_SHOW); + UpdateWindow(g_hwndDetailsWindow); +} diff --git a/AMB Editor/hello_claude.txt b/AMB Editor/hello_claude.txt index d45c845f..bfa69e3d 100644 --- a/AMB Editor/hello_claude.txt +++ b/AMB Editor/hello_claude.txt @@ -1,24 +1,24 @@ -Hello Claude! Welcome to the AMB Editor project. - -## What This Is -You're working on a Windows C program that edits AMB files - special sound files used by Civilization III (circa 2001). This is apparently the first reverse-engineered editor for this format. AMB files contain MIDI timing data plus references to WAV files, with various audio parameters like volume/speed randomization. - -## Technical Overview -- **Compiler**: Uses TCC (Tiny C Compiler) via RUN.bat - don't try to compile with GCC on Linux -- **UI**: Win32 ListView control with extensive custom drawing for visual feedback -- **File Structure**: AMB files contain MIDI tracks, Prgm chunks (audio parameters), and Kmap chunks (WAV file references) -- **Key Pattern**: The `g_rowInfo[]` array maps ListView rows to the underlying AMB data structures - -## Important Features -- **Visual Feedback**: WAV filenames turn red if files don't exist, min/max values gray out when randomization is disabled -- **Timestamp Sorting**: ListView rows are sorted by play time and auto-re-sort when times change -- **Undo/Redo**: Uses snapshot system - always call `SnapshotCurrentFile()` before data changes -- **Smart Editing**: `SetListViewItemText()` has an `allowRepopulation` flag to prevent recursion during sorting - -## Code Conventions -- Use enum values (COL_TIME, etc.) instead of bare integers for columns -- Boolean fields display as "Yes"/"No" but are stored as flags (bit 0 = speed random, bit 1 = volume random) -- Float fields format to 3 decimal places -- Minimize message boxes - users found them annoying - +Hello Claude! Welcome to the AMB Editor project. + +## What This Is +You're working on a Windows C program that edits AMB files - special sound files used by Civilization III (circa 2001). This is apparently the first reverse-engineered editor for this format. AMB files contain MIDI timing data plus references to WAV files, with various audio parameters like volume/speed randomization. + +## Technical Overview +- **Compiler**: Uses TCC (Tiny C Compiler) via RUN.bat - don't try to compile with GCC on Linux +- **UI**: Win32 ListView control with extensive custom drawing for visual feedback +- **File Structure**: AMB files contain MIDI tracks, Prgm chunks (audio parameters), and Kmap chunks (WAV file references) +- **Key Pattern**: The `g_rowInfo[]` array maps ListView rows to the underlying AMB data structures + +## Important Features +- **Visual Feedback**: WAV filenames turn red if files don't exist, min/max values gray out when randomization is disabled +- **Timestamp Sorting**: ListView rows are sorted by play time and auto-re-sort when times change +- **Undo/Redo**: Uses snapshot system - always call `SnapshotCurrentFile()` before data changes +- **Smart Editing**: `SetListViewItemText()` has an `allowRepopulation` flag to prevent recursion during sorting + +## Code Conventions +- Use enum values (COL_TIME, etc.) instead of bare integers for columns +- Boolean fields display as "Yes"/"No" but are stored as flags (bit 0 = speed random, bit 1 = volume random) +- Float fields format to 3 decimal places +- Minimize message boxes - users found them annoying + The codebase is well-structured with clear separation between AMB file handling, UI management, and data validation. Most recent work focused on improving the user experience with better visual feedback and timestamp-based organization. \ No newline at end of file diff --git a/AMB Editor/preview.c b/AMB Editor/preview.c index 12c2a7d0..8576b917 100644 --- a/AMB Editor/preview.c +++ b/AMB Editor/preview.c @@ -1,383 +1,383 @@ - -// This file gets #included into amb_editor.c - -// Forward declarations for functions defined in amb_editor.c -extern bool PathIsDirectory(const char* path); -extern bool PathFileExists(const char* path); - -// Using fastcall to substitute for lack of thiscall on a C compiler, as usual. This is the dummy second param. -#define __ 0 - -typedef struct WaveDevice WaveDevice; - -typedef struct { - void * omitted[4]; - int (__fastcall * Initialize) (WaveDevice *, int, HWND, unsigned); - void * omitted_2[38]; -} WaveDeviceVTable; - -struct WaveDevice { - WaveDeviceVTable * vtable; - // other fields omitted -}; - -typedef struct MidiDevice MidiDevice; - -typedef struct { - void * omitted[4]; - int (__fastcall * Initialize)(MidiDevice *, int, HWND, unsigned); - void * omitted_2[38]; -} MidiDeviceVTable; - -struct MidiDevice { - MidiDeviceVTable * vtable; - // other fields omitted -}; - -typedef struct SoundCore SoundCore; - -typedef struct { - void * omitted[4]; - int (__fastcall * LoadFile)(SoundCore *, int, char const *); // takes file path - void * omitted_2[2]; - int (__fastcall * Play)(SoundCore *); - int (__fastcall * Stop)(SoundCore *); - void * omitted_3[7]; - void (__fastcall * SetVolume)(SoundCore *, int, int); // volume is >= 0 and <= 127 - void * omitted_4[5]; - int (__fastcall * M22)(SoundCore *); - void * omitted_5; - int (__fastcall * M24)(SoundCore *); - void * omitted_6[2]; - int (__fastcall * SetFlags)(SoundCore *, int, unsigned); - void * omitted_7[22]; - int (__fastcall * M50)(SoundCore *); - void * omitted_8[26]; -} SoundCoreVTable; - -struct SoundCore { - SoundCoreVTable * vtable; - // many more fields omitted -}; - -enum sound_core_type { - SCT_DETECT_FROM_FILE_EXT = 0, // Does not work - SCT_WAV, - SCT_MIDI, - SCT_AIF, - SCT_4, - SCT_AMB, - SCT_6, - SCT_7, - SCT_8 -}; - -bool previewPlayerIsInitialized = false; - -HMODULE soundModule = NULL; -int (__cdecl * InitSoundTimer)(int param_1, int param_2) = NULL; -int (__cdecl * CreateSound)(SoundCore ** out_sound_core, char const * file_path, int sound_core_type) = NULL; -int (__cdecl * DeleteSound)(SoundCore * sound_core) = NULL; -int (__cdecl * CreateWaveDevice)(WaveDevice ** out, unsigned param_2) = NULL; -int (__cdecl * CreateMidiDevice)(MidiDevice ** out, unsigned param_2) = NULL; - -WaveDevice * waveDevice = NULL; -MidiDevice * midiDevice = NULL; - -SoundCore * playingCore = NULL; - -void InitializePreviewPlayer(HWND window, char *soundDLLPath) -{ - if (previewPlayerIsInitialized) - return; - - char errorMsg[1000] = {0}; - Path savedCWD; - Path soundDLLDir; - char* fileName; - - // Save current directory - GetCurrentDirectory(sizeof(savedCWD), savedCWD); - - // Extract directory and filename from sound.dll path - strcpy(soundDLLDir, soundDLLPath); - char* lastSlash = strrchr(soundDLLDir, '\\'); - if (lastSlash) { - fileName = lastSlash + 1; // point to filename part - *lastSlash = '\0'; // truncate to get directory - SetCurrentDirectory(soundDLLDir); - } else { - // No path separators, assume it's just a filename - fileName = soundDLLPath; - } - - soundModule = LoadLibraryA(fileName); - if (soundModule == NULL) { - DWORD error = GetLastError(); - char errorString[256]; - if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, error, 0, errorString, sizeof(errorString), NULL) == 0) { - snprintf(errorMsg, sizeof(errorMsg) - 1, "Failed to load sound.dll: Error code %lu", error); - } else { - snprintf(errorMsg, sizeof(errorMsg) - 1, "Failed to load sound.dll: %s", errorString); - } - goto done; - } - - InitSoundTimer = (void *)GetProcAddress(soundModule, "init_sound_timer"); - CreateSound = (void *)GetProcAddress(soundModule, "create_sound"); - DeleteSound = (void *)GetProcAddress(soundModule, "delete_sound"); - CreateWaveDevice = (void *)GetProcAddress(soundModule, (LPCSTR)5); // Use ordinal b/c name is mangled - CreateMidiDevice = (void *)GetProcAddress(soundModule, (LPCSTR)7); - - if (InitSoundTimer == NULL || CreateSound == NULL || DeleteSound == NULL || - CreateWaveDevice == NULL || CreateMidiDevice == NULL) { - snprintf(errorMsg, sizeof(errorMsg) - 1, - "Failed to load required functions from sound.dll. This may not be a valid Civ3 sound.dll file."); - goto done; - } - - InitSoundTimer(0, 0); - - CreateWaveDevice(&waveDevice, 0); - waveDevice->vtable->Initialize(waveDevice, __, window, 2); // Civ 3 passes 2 for second param (flags) - - CreateMidiDevice(&midiDevice, 0); - midiDevice->vtable->Initialize(midiDevice, __, window, 0); - -done: - // Restore original directory - SetCurrentDirectory(savedCWD); - - if (strlen(errorMsg) > 0) { - MessageBox(NULL, errorMsg, "Couldn't load sound.dll", MB_ICONERROR); - if (soundModule != NULL) { - FreeLibrary(soundModule); - soundModule = NULL; - } - previewPlayerIsInitialized = false; - } else - previewPlayerIsInitialized = true; -} - -void StopAmbPreview() -{ - if (playingCore != NULL) { - playingCore->vtable->Stop(playingCore); - DeleteSound(playingCore); - playingCore = NULL; - } -} - -void DeinitializePreviewPlayer() -{ - if (previewPlayerIsInitialized) { - StopAmbPreview(); - FreeLibrary(soundModule); - previewPlayerIsInitialized = false; - } -} - -#define TEMP_FOLDER "AMBEditorTemp" -#ifndef MAX_PATH -#define MAX_PATH 260 -#endif - -// Helper function to clear .wav and .amb files from numbered directories -void ClearTempDirectory(const char *baseTempDir) -{ - WIN32_FIND_DATA findData; - char searchPattern[MAX_PATH] = {0}; - char numberedDirPath[MAX_PATH] = {0}; - - snprintf(searchPattern, sizeof(searchPattern) - 1, "%s\\*", baseTempDir); - HANDLE hFind = FindFirstFile(searchPattern, &findData); - - if (hFind != INVALID_HANDLE_VALUE) { - do { - // Skip . and .. directory entries - if (strcmp(findData.cFileName, ".") == 0 || - strcmp(findData.cFileName, "..") == 0) { - continue; - } - - // Check if this is a numbered directory (1, 2, 3, etc.) - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - char *endPtr; - long dirNumber = strtol(findData.cFileName, &endPtr, 10); - - // If the entire filename is a number, it's a numbered directory - if (*endPtr == '\0' && dirNumber > 0) { - snprintf(numberedDirPath, sizeof(numberedDirPath) - 1, "%s\\%s", baseTempDir, findData.cFileName); - - // Delete .wav and .amb files from this numbered directory - WIN32_FIND_DATA fileData; - char fileSearchPattern[MAX_PATH] = {0}; - char filePath[MAX_PATH] = {0}; - - snprintf(fileSearchPattern, sizeof(fileSearchPattern) - 1, "%s\\*.*", numberedDirPath); - HANDLE hFileFind = FindFirstFile(fileSearchPattern, &fileData); - - if (hFileFind != INVALID_HANDLE_VALUE) { - do { - if (strcmp(fileData.cFileName, ".") != 0 && - strcmp(fileData.cFileName, "..") != 0 && - !(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - - char *extension = strrchr(fileData.cFileName, '.'); - if (extension != NULL) { - if (_stricmp(extension, ".wav") == 0 || _stricmp(extension, ".amb") == 0) { - snprintf(filePath, sizeof(filePath) - 1, "%s\\%s", numberedDirPath, fileData.cFileName); - DeleteFile(filePath); - } - } - } - } while (FindNextFile(hFileFind, &fileData)); - FindClose(hFileFind); - } - - // Try to remove the empty directory - RemoveDirectory(numberedDirPath); - } - } - } while (FindNextFile(hFind, &findData)); - FindClose(hFind); - } -} - -// Prepare temporary directory for AMB previewing, creating a numbered subfolder -BOOL PrepareTempDirectory(Path forcedTempPath, char *tempDirPath, size_t tempDirPathSize) -{ - char tempPath[MAX_PATH] = {0}; - char baseTempDir[MAX_PATH] = {0}; - - // Check if forcedTempPath is provided and non-empty - if (strlen(forcedTempPath) > 0) { - // Validate that the forced temp path exists and is a directory - if (!PathIsDirectory(forcedTempPath)) { - return FALSE; - } - strncpy(baseTempDir, forcedTempPath, (sizeof baseTempDir) - 1); - } else { - // Get the system temp directory - DWORD result = GetTempPath(MAX_PATH, tempPath); - if (result == 0 || result > MAX_PATH) { - return FALSE; - } - - // Create our base temp folder in the system temp directory - snprintf(baseTempDir, sizeof(baseTempDir) - 1, "%s%s", tempPath, TEMP_FOLDER); - } - - // Create the directory if it doesn't exist - if (!PathIsDirectory(baseTempDir)) { - if (!CreateDirectory(baseTempDir, NULL)) { - return FALSE; - } - } - - // Clear .wav and .amb files from numbered directories within the base temp directory - ClearTempDirectory(baseTempDir); - - // Find an unused numbered subfolder - char numberedPath[MAX_PATH] = {0}; - int folderNumber = 1; - - while (folderNumber <= 9999) { // Reasonable upper limit - snprintf(numberedPath, sizeof(numberedPath) - 1, "%s\\%d", baseTempDir, folderNumber); - - if (!PathIsDirectory(numberedPath)) { - // This number is available, create the directory - if (CreateDirectory(numberedPath, NULL)) { - // Update the output path to the numbered folder - snprintf(tempDirPath, tempDirPathSize - 1, "%s", numberedPath); - return TRUE; - } else { - return FALSE; - } - } - - folderNumber++; - } - - // If we couldn't find an unused number, fail - return FALSE; -} - -// Copy WAV files referenced by the AMB to the temp directory -BOOL CopyWavFilesToTempDir(AmbFile const * ambFile, char *tempDirPath) -{ - Path sourcePath = {0}; - Path targetPath = {0}; - BOOL success = TRUE; - - // Get the directory of the original AMB file to find the WAV files - Path ambDir; - strcpy(ambDir, ambFile->filePath); - - // Find the last backslash in the path - char *lastBackslash = strrchr(ambDir, '\\'); - if (lastBackslash != NULL) { - *lastBackslash = '\0'; // Truncate the path at the last backslash - } - - // For each Kmap chunk, copy any referenced WAV files - for (int i = 0; i < ambFile->kmapChunkCount; i++) { - KmapChunk const * chunk = &ambFile->kmapChunks[i]; - - // For each item in the Kmap chunk, copy its WAV file - for (int j = 0; j < chunk->itemCount && j < MAX_ITEMS; j++) { - const char *wavFileName = chunk->items[j].wavFileName; - - // Skip if no WAV file is specified - if (strlen(wavFileName) == 0) { - continue; - } - - // Construct the source and target paths - snprintf(sourcePath, PATH_BUFFER_SIZE - 1, "%s\\%s", ambDir, wavFileName); - snprintf(targetPath, PATH_BUFFER_SIZE - 1, "%s\\%s", tempDirPath, wavFileName); - - // Copy the file - if (!CopyFile(sourcePath, targetPath, FALSE)) { - success = FALSE; - } - } - } - - return success; -} - -void PreviewAmbFile(Path forcedTempPath, AmbFile const * amb) -{ - if (! previewPlayerIsInitialized) - return; - - StopAmbPreview(); - - // Save the AMB to a temporary file first. Begin by preparing a temp directory - Path tempFilePath = {0}; - Path tempDirPath = {0}; - bool success = false; - if (PrepareTempDirectory(forcedTempPath, tempDirPath, PATH_BUFFER_SIZE)) { - // Generate a temp file path for the AMB - snprintf(tempFilePath, PATH_BUFFER_SIZE - 1, "%s\\temp.amb", tempDirPath); - - // Save the current AMB to the temp file - if (SaveAmbFile(amb, tempFilePath)) { - // Copy all WAV files referenced by the AMB to the temp directory - if (CopyWavFilesToTempDir(amb, tempDirPath)) { - success = true; - } - } - } - - // Play the temp copy if it was created successfully - if (success) { - CreateSound(&playingCore, NULL, SCT_AMB); - if (playingCore != NULL) { - playingCore->vtable->LoadFile(playingCore, __, tempFilePath); - playingCore->vtable->Play(playingCore); - } - } -} + +// This file gets #included into amb_editor.c + +// Forward declarations for functions defined in amb_editor.c +extern bool PathIsDirectory(const char* path); +extern bool PathFileExists(const char* path); + +// Using fastcall to substitute for lack of thiscall on a C compiler, as usual. This is the dummy second param. +#define __ 0 + +typedef struct WaveDevice WaveDevice; + +typedef struct { + void * omitted[4]; + int (__fastcall * Initialize) (WaveDevice *, int, HWND, unsigned); + void * omitted_2[38]; +} WaveDeviceVTable; + +struct WaveDevice { + WaveDeviceVTable * vtable; + // other fields omitted +}; + +typedef struct MidiDevice MidiDevice; + +typedef struct { + void * omitted[4]; + int (__fastcall * Initialize)(MidiDevice *, int, HWND, unsigned); + void * omitted_2[38]; +} MidiDeviceVTable; + +struct MidiDevice { + MidiDeviceVTable * vtable; + // other fields omitted +}; + +typedef struct SoundCore SoundCore; + +typedef struct { + void * omitted[4]; + int (__fastcall * LoadFile)(SoundCore *, int, char const *); // takes file path + void * omitted_2[2]; + int (__fastcall * Play)(SoundCore *); + int (__fastcall * Stop)(SoundCore *); + void * omitted_3[7]; + void (__fastcall * SetVolume)(SoundCore *, int, int); // volume is >= 0 and <= 127 + void * omitted_4[5]; + int (__fastcall * M22)(SoundCore *); + void * omitted_5; + int (__fastcall * M24)(SoundCore *); + void * omitted_6[2]; + int (__fastcall * SetFlags)(SoundCore *, int, unsigned); + void * omitted_7[22]; + int (__fastcall * M50)(SoundCore *); + void * omitted_8[26]; +} SoundCoreVTable; + +struct SoundCore { + SoundCoreVTable * vtable; + // many more fields omitted +}; + +enum sound_core_type { + SCT_DETECT_FROM_FILE_EXT = 0, // Does not work + SCT_WAV, + SCT_MIDI, + SCT_AIF, + SCT_4, + SCT_AMB, + SCT_6, + SCT_7, + SCT_8 +}; + +bool previewPlayerIsInitialized = false; + +HMODULE soundModule = NULL; +int (__cdecl * InitSoundTimer)(int param_1, int param_2) = NULL; +int (__cdecl * CreateSound)(SoundCore ** out_sound_core, char const * file_path, int sound_core_type) = NULL; +int (__cdecl * DeleteSound)(SoundCore * sound_core) = NULL; +int (__cdecl * CreateWaveDevice)(WaveDevice ** out, unsigned param_2) = NULL; +int (__cdecl * CreateMidiDevice)(MidiDevice ** out, unsigned param_2) = NULL; + +WaveDevice * waveDevice = NULL; +MidiDevice * midiDevice = NULL; + +SoundCore * playingCore = NULL; + +void InitializePreviewPlayer(HWND window, char *soundDLLPath) +{ + if (previewPlayerIsInitialized) + return; + + char errorMsg[1000] = {0}; + Path savedCWD; + Path soundDLLDir; + char* fileName; + + // Save current directory + GetCurrentDirectory(sizeof(savedCWD), savedCWD); + + // Extract directory and filename from sound.dll path + strcpy(soundDLLDir, soundDLLPath); + char* lastSlash = strrchr(soundDLLDir, '\\'); + if (lastSlash) { + fileName = lastSlash + 1; // point to filename part + *lastSlash = '\0'; // truncate to get directory + SetCurrentDirectory(soundDLLDir); + } else { + // No path separators, assume it's just a filename + fileName = soundDLLPath; + } + + soundModule = LoadLibraryA(fileName); + if (soundModule == NULL) { + DWORD error = GetLastError(); + char errorString[256]; + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, 0, errorString, sizeof(errorString), NULL) == 0) { + snprintf(errorMsg, sizeof(errorMsg) - 1, "Failed to load sound.dll: Error code %lu", error); + } else { + snprintf(errorMsg, sizeof(errorMsg) - 1, "Failed to load sound.dll: %s", errorString); + } + goto done; + } + + InitSoundTimer = (void *)GetProcAddress(soundModule, "init_sound_timer"); + CreateSound = (void *)GetProcAddress(soundModule, "create_sound"); + DeleteSound = (void *)GetProcAddress(soundModule, "delete_sound"); + CreateWaveDevice = (void *)GetProcAddress(soundModule, (LPCSTR)5); // Use ordinal b/c name is mangled + CreateMidiDevice = (void *)GetProcAddress(soundModule, (LPCSTR)7); + + if (InitSoundTimer == NULL || CreateSound == NULL || DeleteSound == NULL || + CreateWaveDevice == NULL || CreateMidiDevice == NULL) { + snprintf(errorMsg, sizeof(errorMsg) - 1, + "Failed to load required functions from sound.dll. This may not be a valid Civ3 sound.dll file."); + goto done; + } + + InitSoundTimer(0, 0); + + CreateWaveDevice(&waveDevice, 0); + waveDevice->vtable->Initialize(waveDevice, __, window, 2); // Civ 3 passes 2 for second param (flags) + + CreateMidiDevice(&midiDevice, 0); + midiDevice->vtable->Initialize(midiDevice, __, window, 0); + +done: + // Restore original directory + SetCurrentDirectory(savedCWD); + + if (strlen(errorMsg) > 0) { + MessageBox(NULL, errorMsg, "Couldn't load sound.dll", MB_ICONERROR); + if (soundModule != NULL) { + FreeLibrary(soundModule); + soundModule = NULL; + } + previewPlayerIsInitialized = false; + } else + previewPlayerIsInitialized = true; +} + +void StopAmbPreview() +{ + if (playingCore != NULL) { + playingCore->vtable->Stop(playingCore); + DeleteSound(playingCore); + playingCore = NULL; + } +} + +void DeinitializePreviewPlayer() +{ + if (previewPlayerIsInitialized) { + StopAmbPreview(); + FreeLibrary(soundModule); + previewPlayerIsInitialized = false; + } +} + +#define TEMP_FOLDER "AMBEditorTemp" +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +// Helper function to clear .wav and .amb files from numbered directories +void ClearTempDirectory(const char *baseTempDir) +{ + WIN32_FIND_DATA findData; + char searchPattern[MAX_PATH] = {0}; + char numberedDirPath[MAX_PATH] = {0}; + + snprintf(searchPattern, sizeof(searchPattern) - 1, "%s\\*", baseTempDir); + HANDLE hFind = FindFirstFile(searchPattern, &findData); + + if (hFind != INVALID_HANDLE_VALUE) { + do { + // Skip . and .. directory entries + if (strcmp(findData.cFileName, ".") == 0 || + strcmp(findData.cFileName, "..") == 0) { + continue; + } + + // Check if this is a numbered directory (1, 2, 3, etc.) + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + char *endPtr; + long dirNumber = strtol(findData.cFileName, &endPtr, 10); + + // If the entire filename is a number, it's a numbered directory + if (*endPtr == '\0' && dirNumber > 0) { + snprintf(numberedDirPath, sizeof(numberedDirPath) - 1, "%s\\%s", baseTempDir, findData.cFileName); + + // Delete .wav and .amb files from this numbered directory + WIN32_FIND_DATA fileData; + char fileSearchPattern[MAX_PATH] = {0}; + char filePath[MAX_PATH] = {0}; + + snprintf(fileSearchPattern, sizeof(fileSearchPattern) - 1, "%s\\*.*", numberedDirPath); + HANDLE hFileFind = FindFirstFile(fileSearchPattern, &fileData); + + if (hFileFind != INVALID_HANDLE_VALUE) { + do { + if (strcmp(fileData.cFileName, ".") != 0 && + strcmp(fileData.cFileName, "..") != 0 && + !(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + + char *extension = strrchr(fileData.cFileName, '.'); + if (extension != NULL) { + if (_stricmp(extension, ".wav") == 0 || _stricmp(extension, ".amb") == 0) { + snprintf(filePath, sizeof(filePath) - 1, "%s\\%s", numberedDirPath, fileData.cFileName); + DeleteFile(filePath); + } + } + } + } while (FindNextFile(hFileFind, &fileData)); + FindClose(hFileFind); + } + + // Try to remove the empty directory + RemoveDirectory(numberedDirPath); + } + } + } while (FindNextFile(hFind, &findData)); + FindClose(hFind); + } +} + +// Prepare temporary directory for AMB previewing, creating a numbered subfolder +BOOL PrepareTempDirectory(Path forcedTempPath, char *tempDirPath, size_t tempDirPathSize) +{ + char tempPath[MAX_PATH] = {0}; + char baseTempDir[MAX_PATH] = {0}; + + // Check if forcedTempPath is provided and non-empty + if (strlen(forcedTempPath) > 0) { + // Validate that the forced temp path exists and is a directory + if (!PathIsDirectory(forcedTempPath)) { + return FALSE; + } + strncpy(baseTempDir, forcedTempPath, (sizeof baseTempDir) - 1); + } else { + // Get the system temp directory + DWORD result = GetTempPath(MAX_PATH, tempPath); + if (result == 0 || result > MAX_PATH) { + return FALSE; + } + + // Create our base temp folder in the system temp directory + snprintf(baseTempDir, sizeof(baseTempDir) - 1, "%s%s", tempPath, TEMP_FOLDER); + } + + // Create the directory if it doesn't exist + if (!PathIsDirectory(baseTempDir)) { + if (!CreateDirectory(baseTempDir, NULL)) { + return FALSE; + } + } + + // Clear .wav and .amb files from numbered directories within the base temp directory + ClearTempDirectory(baseTempDir); + + // Find an unused numbered subfolder + char numberedPath[MAX_PATH] = {0}; + int folderNumber = 1; + + while (folderNumber <= 9999) { // Reasonable upper limit + snprintf(numberedPath, sizeof(numberedPath) - 1, "%s\\%d", baseTempDir, folderNumber); + + if (!PathIsDirectory(numberedPath)) { + // This number is available, create the directory + if (CreateDirectory(numberedPath, NULL)) { + // Update the output path to the numbered folder + snprintf(tempDirPath, tempDirPathSize - 1, "%s", numberedPath); + return TRUE; + } else { + return FALSE; + } + } + + folderNumber++; + } + + // If we couldn't find an unused number, fail + return FALSE; +} + +// Copy WAV files referenced by the AMB to the temp directory +BOOL CopyWavFilesToTempDir(AmbFile const * ambFile, char *tempDirPath) +{ + Path sourcePath = {0}; + Path targetPath = {0}; + BOOL success = TRUE; + + // Get the directory of the original AMB file to find the WAV files + Path ambDir; + strcpy(ambDir, ambFile->filePath); + + // Find the last backslash in the path + char *lastBackslash = strrchr(ambDir, '\\'); + if (lastBackslash != NULL) { + *lastBackslash = '\0'; // Truncate the path at the last backslash + } + + // For each Kmap chunk, copy any referenced WAV files + for (int i = 0; i < ambFile->kmapChunkCount; i++) { + KmapChunk const * chunk = &ambFile->kmapChunks[i]; + + // For each item in the Kmap chunk, copy its WAV file + for (int j = 0; j < chunk->itemCount && j < MAX_ITEMS; j++) { + const char *wavFileName = chunk->items[j].wavFileName; + + // Skip if no WAV file is specified + if (strlen(wavFileName) == 0) { + continue; + } + + // Construct the source and target paths + snprintf(sourcePath, PATH_BUFFER_SIZE - 1, "%s\\%s", ambDir, wavFileName); + snprintf(targetPath, PATH_BUFFER_SIZE - 1, "%s\\%s", tempDirPath, wavFileName); + + // Copy the file + if (!CopyFile(sourcePath, targetPath, FALSE)) { + success = FALSE; + } + } + } + + return success; +} + +void PreviewAmbFile(Path forcedTempPath, AmbFile const * amb) +{ + if (! previewPlayerIsInitialized) + return; + + StopAmbPreview(); + + // Save the AMB to a temporary file first. Begin by preparing a temp directory + Path tempFilePath = {0}; + Path tempDirPath = {0}; + bool success = false; + if (PrepareTempDirectory(forcedTempPath, tempDirPath, PATH_BUFFER_SIZE)) { + // Generate a temp file path for the AMB + snprintf(tempFilePath, PATH_BUFFER_SIZE - 1, "%s\\temp.amb", tempDirPath); + + // Save the current AMB to the temp file + if (SaveAmbFile(amb, tempFilePath)) { + // Copy all WAV files referenced by the AMB to the temp directory + if (CopyWavFilesToTempDir(amb, tempDirPath)) { + success = true; + } + } + } + + // Play the temp copy if it was created successfully + if (success) { + CreateSound(&playingCore, NULL, SCT_AMB); + if (playingCore != NULL) { + playingCore->vtable->LoadFile(playingCore, __, tempFilePath); + playingCore->vtable->Play(playingCore); + } + } +} diff --git a/AMB Editor/wav_file.c b/AMB Editor/wav_file.c index 7dc8b2d9..93092b26 100644 --- a/AMB Editor/wav_file.c +++ b/AMB Editor/wav_file.c @@ -1,130 +1,130 @@ -#include -#include - -// WAV file header structures -typedef struct { - char riff[4]; // "RIFF" - DWORD fileSize; // File size - 8 - char wave[4]; // "WAVE" -} RiffHeader; - -typedef struct { - char fmt[4]; // "fmt " - DWORD chunkSize; // Size of fmt chunk data - WORD audioFormat; // 1 = PCM - WORD numChannels; // 1 = mono, 2 = stereo - DWORD sampleRate; // Sample rate (Hz) - DWORD byteRate; // Bytes per second - WORD blockAlign; // Bytes per sample frame - WORD bitsPerSample; // Bits per sample -} FmtChunk; - -typedef struct { - char data[4]; // "data" - DWORD dataSize; // Size of audio data -} DataChunkHeader; - -// Read WAV file duration -// Returns TRUE on success, FALSE on failure -// Duration is returned in seconds through outDuration parameter -BOOL GetWavFileDuration(const char* filePath, float* outDuration) -{ - HANDLE hFile = INVALID_HANDLE_VALUE; - RiffHeader riffHeader; - FmtChunk fmtChunk; - DataChunkHeader dataHeader; - DWORD bytesRead; - BOOL success = FALSE; - - if (!filePath || !outDuration) { - return FALSE; - } - - // Open the file - hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return FALSE; - } - - // Read RIFF header - if (!ReadFile(hFile, &riffHeader, sizeof(RiffHeader), &bytesRead, NULL) || - bytesRead != sizeof(RiffHeader)) { - goto cleanup; - } - - // Verify RIFF and WAVE signatures - if (memcmp(riffHeader.riff, "RIFF", 4) != 0 || - memcmp(riffHeader.wave, "WAVE", 4) != 0) { - goto cleanup; - } - - // Read fmt chunk - if (!ReadFile(hFile, &fmtChunk, sizeof(FmtChunk), &bytesRead, NULL) || - bytesRead != sizeof(FmtChunk)) { - goto cleanup; - } - - // Verify fmt signature and basic PCM format - if (memcmp(fmtChunk.fmt, "fmt ", 4) != 0 || - fmtChunk.audioFormat != 1 || // PCM format - fmtChunk.numChannels == 0 || - fmtChunk.sampleRate == 0 || - fmtChunk.bitsPerSample == 0) { - goto cleanup; - } - - // Skip any extra fmt chunk data beyond the standard 16 bytes - if (fmtChunk.chunkSize > 16) { - DWORD extraBytes = fmtChunk.chunkSize - 16; - SetFilePointer(hFile, extraBytes, NULL, FILE_CURRENT); - } - - // Look for data chunk - char chunkId[4]; - DWORD chunkSize; - BOOL foundData = FALSE; - - while (!foundData) { - // Read chunk header (ID + size) - if (!ReadFile(hFile, chunkId, 4, &bytesRead, NULL) || bytesRead != 4) { - goto cleanup; - } - if (!ReadFile(hFile, &chunkSize, 4, &bytesRead, NULL) || bytesRead != 4) { - goto cleanup; - } - - if (memcmp(chunkId, "data", 4) == 0) { - // Found data chunk - dataHeader.dataSize = chunkSize; - foundData = TRUE; - } else { - // Skip this chunk - if (SetFilePointer(hFile, chunkSize, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { - goto cleanup; - } - } - } - - if (!foundData || dataHeader.dataSize == 0) { - goto cleanup; - } - - // Calculate duration: data_size / (sample_rate * channels * bytes_per_sample) - DWORD bytesPerSample = (fmtChunk.bitsPerSample + 7) / 8; // Round up to nearest byte - DWORD bytesPerSecond = fmtChunk.sampleRate * fmtChunk.numChannels * bytesPerSample; - - if (bytesPerSecond == 0) { - goto cleanup; - } - - *outDuration = (float)dataHeader.dataSize / (float)bytesPerSecond; - success = TRUE; - -cleanup: - if (hFile != INVALID_HANDLE_VALUE) { - CloseHandle(hFile); - } - - return success; +#include +#include + +// WAV file header structures +typedef struct { + char riff[4]; // "RIFF" + DWORD fileSize; // File size - 8 + char wave[4]; // "WAVE" +} RiffHeader; + +typedef struct { + char fmt[4]; // "fmt " + DWORD chunkSize; // Size of fmt chunk data + WORD audioFormat; // 1 = PCM + WORD numChannels; // 1 = mono, 2 = stereo + DWORD sampleRate; // Sample rate (Hz) + DWORD byteRate; // Bytes per second + WORD blockAlign; // Bytes per sample frame + WORD bitsPerSample; // Bits per sample +} FmtChunk; + +typedef struct { + char data[4]; // "data" + DWORD dataSize; // Size of audio data +} DataChunkHeader; + +// Read WAV file duration +// Returns TRUE on success, FALSE on failure +// Duration is returned in seconds through outDuration parameter +BOOL GetWavFileDuration(const char* filePath, float* outDuration) +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + RiffHeader riffHeader; + FmtChunk fmtChunk; + DataChunkHeader dataHeader; + DWORD bytesRead; + BOOL success = FALSE; + + if (!filePath || !outDuration) { + return FALSE; + } + + // Open the file + hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return FALSE; + } + + // Read RIFF header + if (!ReadFile(hFile, &riffHeader, sizeof(RiffHeader), &bytesRead, NULL) || + bytesRead != sizeof(RiffHeader)) { + goto cleanup; + } + + // Verify RIFF and WAVE signatures + if (memcmp(riffHeader.riff, "RIFF", 4) != 0 || + memcmp(riffHeader.wave, "WAVE", 4) != 0) { + goto cleanup; + } + + // Read fmt chunk + if (!ReadFile(hFile, &fmtChunk, sizeof(FmtChunk), &bytesRead, NULL) || + bytesRead != sizeof(FmtChunk)) { + goto cleanup; + } + + // Verify fmt signature and basic PCM format + if (memcmp(fmtChunk.fmt, "fmt ", 4) != 0 || + fmtChunk.audioFormat != 1 || // PCM format + fmtChunk.numChannels == 0 || + fmtChunk.sampleRate == 0 || + fmtChunk.bitsPerSample == 0) { + goto cleanup; + } + + // Skip any extra fmt chunk data beyond the standard 16 bytes + if (fmtChunk.chunkSize > 16) { + DWORD extraBytes = fmtChunk.chunkSize - 16; + SetFilePointer(hFile, extraBytes, NULL, FILE_CURRENT); + } + + // Look for data chunk + char chunkId[4]; + DWORD chunkSize; + BOOL foundData = FALSE; + + while (!foundData) { + // Read chunk header (ID + size) + if (!ReadFile(hFile, chunkId, 4, &bytesRead, NULL) || bytesRead != 4) { + goto cleanup; + } + if (!ReadFile(hFile, &chunkSize, 4, &bytesRead, NULL) || bytesRead != 4) { + goto cleanup; + } + + if (memcmp(chunkId, "data", 4) == 0) { + // Found data chunk + dataHeader.dataSize = chunkSize; + foundData = TRUE; + } else { + // Skip this chunk + if (SetFilePointer(hFile, chunkSize, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { + goto cleanup; + } + } + } + + if (!foundData || dataHeader.dataSize == 0) { + goto cleanup; + } + + // Calculate duration: data_size / (sample_rate * channels * bytes_per_sample) + DWORD bytesPerSample = (fmtChunk.bitsPerSample + 7) / 8; // Round up to nearest byte + DWORD bytesPerSecond = fmtChunk.sampleRate * fmtChunk.numChannels * bytesPerSample; + + if (bytesPerSecond == 0) { + goto cleanup; + } + + *outDuration = (float)dataHeader.dataSize / (float)bytesPerSecond; + success = TRUE; + +cleanup: + if (hFile != INVALID_HANDLE_VALUE) { + CloseHandle(hFile); + } + + return success; } \ No newline at end of file diff --git a/AMB Editor/win32_selections.h b/AMB Editor/win32_selections.h index 08161058..863fe227 100644 --- a/AMB Editor/win32_selections.h +++ b/AMB Editor/win32_selections.h @@ -1,156 +1,156 @@ - -// This file contains only the Win32 definitions needed by the AMB editor. Normally one would #include the needed header files, however that's not -// possible because they aren't available with TCC. - -// Common Control definitions (normally from commctrl.h) -#define WC_LISTVIEW "SysListView32" -#define LVS_REPORT 0x0001 -#define LVS_SHOWSELALWAYS 0x0008 -#define LVS_SINGLESEL 0x0004 -#define LVS_EDITLABELS 0x0200 -#define LVS_NOHSCROLL 0x8000 -#define LVM_INSERTCOLUMN (LVM_FIRST + 27) -#define LVM_INSERTITEM (LVM_FIRST + 7) -#define LVM_SETITEM (LVM_FIRST + 6) -#define LVM_SETITEMSTATE (LVM_FIRST + 43) -#define LVM_GETITEMCOUNT (LVM_FIRST + 4) -#define LVM_DELETEALLITEMS (LVM_FIRST + 9) -#define LVM_GETITEMSTATE (LVM_FIRST + 44) -#define LVM_FIRST 0x1000 -#define LVCF_TEXT 0x0004 -#define LVCF_WIDTH 0x0002 -#define LVIF_TEXT 0x0001 -#define LVIF_STATE 0x0008 -#define LVIS_STATEIMAGEMASK 0xF000 -#define LVIS_SELECTED 0x0002 -#define LVS_EX_GRIDLINES 0x00000001 -#define LVS_EX_FULLROWSELECT 0x00000020 -#define LVS_EX_CHECKBOXES 0x00000004 -#define LVM_SETEXTENDEDLISTVIEWSTYLE (LVM_FIRST + 54) -#define LVM_GETEXTENDEDLISTVIEWSTYLE (LVM_FIRST + 55) -#define LVN_FIRST (-100) -#define LVN_BEGINLABELEDIT (LVN_FIRST-5) -#define LVN_ENDLABELEDIT (LVN_FIRST-6) -#define LVN_COLUMNCLICK (LVN_FIRST-8) -#define NM_CUSTOMDRAW (NM_FIRST-12) -#define LVM_GETEDITCONTROL (LVM_FIRST + 24) -#define LVM_EDITLABEL (LVM_FIRST + 23) -#define LVM_GETITEMTEXT (LVM_FIRST + 45) -#define LVM_GETSUBITEMRECT (LVM_FIRST + 56) -#define LVM_GETCOLUMN (LVM_FIRST + 25) -#define EM_SETSEL 0x00B1 -#define LVIR_BOUNDS 0 -#define LVIR_ICON 1 -#define LVIR_LABEL 2 -#define LVIR_SELECTBOUNDS 3 - -// Custom draw constants -#define CDDS_PREPAINT 0x00000001 -#define CDDS_POSTPAINT 0x00000002 -#define CDDS_PREERASE 0x00000003 -#define CDDS_POSTERASE 0x00000004 -#define CDDS_ITEM 0x00010000 -#define CDDS_ITEMPREPAINT (CDDS_ITEM | CDDS_PREPAINT) -#define CDDS_ITEMPOSTPAINT (CDDS_ITEM | CDDS_POSTPAINT) -#define CDDS_SUBITEM 0x00020000 -#define CDRF_DODEFAULT 0x00000000 -#define CDRF_NEWFONT 0x00000002 -#define CDRF_SKIPDEFAULT 0x00000004 -#define CDRF_NOTIFYPOSTPAINT 0x00000010 -#define CDRF_NOTIFYITEMDRAW 0x00000020 -#define CDRF_NOTIFYSUBITEMDRAW 0x00000020 - -typedef struct tagLVCOLUMNA { - UINT mask; - int fmt; - int cx; - LPSTR pszText; - int cchTextMax; - int iSubItem; - int iImage; - int iOrder; -} LVCOLUMNA, *LPLVCOLUMNA; - -typedef struct tagLVITEMA { - UINT mask; - int iItem; - int iSubItem; - UINT state; - UINT stateMask; - LPSTR pszText; - int cchTextMax; - int iImage; - LPARAM lParam; - int iIndent; -} LVITEMA, *LPLVITEMA; - -typedef struct tagNMLVDISPINFOA { - NMHDR hdr; - LVITEMA item; -} NMLVDISPINFOA, *LPNMLVDISPINFOA; - -typedef struct tagNMITEMACTIVATE { - NMHDR hdr; - int iItem; - int iSubItem; - UINT uNewState; - UINT uOldState; - UINT uChanged; - POINT ptAction; - LPARAM lParam; - UINT uKeyFlags; -} NMITEMACTIVATE, *LPNMITEMACTIVATE; - -typedef struct tagNMCUSTOMDRAWINFO { - NMHDR hdr; - DWORD dwDrawStage; - HDC hdc; - RECT rc; - DWORD_PTR dwItemSpec; - UINT uItemState; - LPARAM lItemlParam; -} NMCUSTOMDRAW, *LPNMCUSTOMDRAW; - -typedef struct tagNMLVCUSTOMDRAW { - NMCUSTOMDRAW nmcd; - COLORREF clrText; - COLORREF clrTextBk; - int iSubItem; -} NMLVCUSTOMDRAW, *LPNMLVCUSTOMDRAW; - -#define NM_FIRST (0U- 0U) -#define NM_DBLCLK (NM_FIRST-3) -#define EN_KILLFOCUS 0x0200 - -// Minimal declarations for common dialogs (normally from commdlg.h) -#define OFN_PATHMUSTEXIST 0x00000800 -#define OFN_FILEMUSTEXIST 0x00001000 -#define OFN_HIDEREADONLY 0x00000004 -#define OFN_NOCHANGEDIR 0x00000008 -#define OFN_EXPLORER 0x00080000 - -typedef struct tagOFNA { - DWORD lStructSize; - HWND hwndOwner; - HINSTANCE hInstance; - LPCSTR lpstrFilter; - LPSTR lpstrCustomFilter; - DWORD nMaxCustFilter; - DWORD nFilterIndex; - LPSTR lpstrFile; - DWORD nMaxFile; - LPSTR lpstrFileTitle; - DWORD nMaxFileTitle; - LPCSTR lpstrInitialDir; - LPCSTR lpstrTitle; - DWORD Flags; - WORD nFileOffset; - WORD nFileExtension; - LPCSTR lpstrDefExt; - LPARAM lCustData; - LPVOID lpfnHook; - LPCSTR lpTemplateName; - void* pvReserved; - DWORD dwReserved; - DWORD FlagsEx; -} OPENFILENAMEA, *LPOPENFILENAMEA; + +// This file contains only the Win32 definitions needed by the AMB editor. Normally one would #include the needed header files, however that's not +// possible because they aren't available with TCC. + +// Common Control definitions (normally from commctrl.h) +#define WC_LISTVIEW "SysListView32" +#define LVS_REPORT 0x0001 +#define LVS_SHOWSELALWAYS 0x0008 +#define LVS_SINGLESEL 0x0004 +#define LVS_EDITLABELS 0x0200 +#define LVS_NOHSCROLL 0x8000 +#define LVM_INSERTCOLUMN (LVM_FIRST + 27) +#define LVM_INSERTITEM (LVM_FIRST + 7) +#define LVM_SETITEM (LVM_FIRST + 6) +#define LVM_SETITEMSTATE (LVM_FIRST + 43) +#define LVM_GETITEMCOUNT (LVM_FIRST + 4) +#define LVM_DELETEALLITEMS (LVM_FIRST + 9) +#define LVM_GETITEMSTATE (LVM_FIRST + 44) +#define LVM_FIRST 0x1000 +#define LVCF_TEXT 0x0004 +#define LVCF_WIDTH 0x0002 +#define LVIF_TEXT 0x0001 +#define LVIF_STATE 0x0008 +#define LVIS_STATEIMAGEMASK 0xF000 +#define LVIS_SELECTED 0x0002 +#define LVS_EX_GRIDLINES 0x00000001 +#define LVS_EX_FULLROWSELECT 0x00000020 +#define LVS_EX_CHECKBOXES 0x00000004 +#define LVM_SETEXTENDEDLISTVIEWSTYLE (LVM_FIRST + 54) +#define LVM_GETEXTENDEDLISTVIEWSTYLE (LVM_FIRST + 55) +#define LVN_FIRST (-100) +#define LVN_BEGINLABELEDIT (LVN_FIRST-5) +#define LVN_ENDLABELEDIT (LVN_FIRST-6) +#define LVN_COLUMNCLICK (LVN_FIRST-8) +#define NM_CUSTOMDRAW (NM_FIRST-12) +#define LVM_GETEDITCONTROL (LVM_FIRST + 24) +#define LVM_EDITLABEL (LVM_FIRST + 23) +#define LVM_GETITEMTEXT (LVM_FIRST + 45) +#define LVM_GETSUBITEMRECT (LVM_FIRST + 56) +#define LVM_GETCOLUMN (LVM_FIRST + 25) +#define EM_SETSEL 0x00B1 +#define LVIR_BOUNDS 0 +#define LVIR_ICON 1 +#define LVIR_LABEL 2 +#define LVIR_SELECTBOUNDS 3 + +// Custom draw constants +#define CDDS_PREPAINT 0x00000001 +#define CDDS_POSTPAINT 0x00000002 +#define CDDS_PREERASE 0x00000003 +#define CDDS_POSTERASE 0x00000004 +#define CDDS_ITEM 0x00010000 +#define CDDS_ITEMPREPAINT (CDDS_ITEM | CDDS_PREPAINT) +#define CDDS_ITEMPOSTPAINT (CDDS_ITEM | CDDS_POSTPAINT) +#define CDDS_SUBITEM 0x00020000 +#define CDRF_DODEFAULT 0x00000000 +#define CDRF_NEWFONT 0x00000002 +#define CDRF_SKIPDEFAULT 0x00000004 +#define CDRF_NOTIFYPOSTPAINT 0x00000010 +#define CDRF_NOTIFYITEMDRAW 0x00000020 +#define CDRF_NOTIFYSUBITEMDRAW 0x00000020 + +typedef struct tagLVCOLUMNA { + UINT mask; + int fmt; + int cx; + LPSTR pszText; + int cchTextMax; + int iSubItem; + int iImage; + int iOrder; +} LVCOLUMNA, *LPLVCOLUMNA; + +typedef struct tagLVITEMA { + UINT mask; + int iItem; + int iSubItem; + UINT state; + UINT stateMask; + LPSTR pszText; + int cchTextMax; + int iImage; + LPARAM lParam; + int iIndent; +} LVITEMA, *LPLVITEMA; + +typedef struct tagNMLVDISPINFOA { + NMHDR hdr; + LVITEMA item; +} NMLVDISPINFOA, *LPNMLVDISPINFOA; + +typedef struct tagNMITEMACTIVATE { + NMHDR hdr; + int iItem; + int iSubItem; + UINT uNewState; + UINT uOldState; + UINT uChanged; + POINT ptAction; + LPARAM lParam; + UINT uKeyFlags; +} NMITEMACTIVATE, *LPNMITEMACTIVATE; + +typedef struct tagNMCUSTOMDRAWINFO { + NMHDR hdr; + DWORD dwDrawStage; + HDC hdc; + RECT rc; + DWORD_PTR dwItemSpec; + UINT uItemState; + LPARAM lItemlParam; +} NMCUSTOMDRAW, *LPNMCUSTOMDRAW; + +typedef struct tagNMLVCUSTOMDRAW { + NMCUSTOMDRAW nmcd; + COLORREF clrText; + COLORREF clrTextBk; + int iSubItem; +} NMLVCUSTOMDRAW, *LPNMLVCUSTOMDRAW; + +#define NM_FIRST (0U- 0U) +#define NM_DBLCLK (NM_FIRST-3) +#define EN_KILLFOCUS 0x0200 + +// Minimal declarations for common dialogs (normally from commdlg.h) +#define OFN_PATHMUSTEXIST 0x00000800 +#define OFN_FILEMUSTEXIST 0x00001000 +#define OFN_HIDEREADONLY 0x00000004 +#define OFN_NOCHANGEDIR 0x00000008 +#define OFN_EXPLORER 0x00080000 + +typedef struct tagOFNA { + DWORD lStructSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCSTR lpstrFilter; + LPSTR lpstrCustomFilter; + DWORD nMaxCustFilter; + DWORD nFilterIndex; + LPSTR lpstrFile; + DWORD nMaxFile; + LPSTR lpstrFileTitle; + DWORD nMaxFileTitle; + LPCSTR lpstrInitialDir; + LPCSTR lpstrTitle; + DWORD Flags; + WORD nFileOffset; + WORD nFileExtension; + LPCSTR lpstrDefExt; + LPARAM lCustData; + LPVOID lpfnHook; + LPCSTR lpTemplateName; + void* pvReserved; + DWORD dwReserved; + DWORD FlagsEx; +} OPENFILENAMEA, *LPOPENFILENAMEA; diff --git a/Art/.gitignore b/Art/.gitignore index a0a982d9..5ab70449 100644 --- a/Art/.gitignore +++ b/Art/.gitignore @@ -1,25 +1,25 @@ -Seasons/ -0100/ -0200/ -0300/ -0400/ -0500/ -0600/ -0700/ -0800/ -0900/ -1000/ -1100/ - -1300/ -1400/ -1500/ -1600/ -1700/ -1800/ -1900/ -2000/ -2100/ -2200/ -2300/ +Seasons/ +0100/ +0200/ +0300/ +0400/ +0500/ +0600/ +0700/ +0800/ +0900/ +1000/ +1100/ + +1300/ +1400/ +1500/ +1600/ +1700/ +1800/ +1900/ +2000/ +2100/ +2200/ +2300/ 2400/ \ No newline at end of file diff --git a/Art/DayNight/.gitignore b/Art/DayNight/.gitignore index bfb96e82..37ab4d22 100644 --- a/Art/DayNight/.gitignore +++ b/Art/DayNight/.gitignore @@ -1,24 +1,24 @@ -0100/ -0200/ -0300/ -0400/ -0500/ -0600/ -0700/ -0800/ -0900/ -1000/ -1100/ -1200/ -1300/ -1400/ -1500/ -1600/ -1700/ -1800/ -1900/ -2000/ -2100/ -2200/ -2300/ +0100/ +0200/ +0300/ +0400/ +0500/ +0600/ +0700/ +0800/ +0900/ +1000/ +1100/ +1200/ +1300/ +1400/ +1500/ +1600/ +1700/ +1800/ +1900/ +2000/ +2100/ +2200/ +2300/ 2400/ \ No newline at end of file diff --git a/C3X.h b/C3X.h index 8d3cc092..65c1770a 100644 --- a/C3X.h +++ b/C3X.h @@ -1,2333 +1,2333 @@ -#include - -#define NOVIRTUALKEYCODES // Keycodes defined in Civ3Conquests.h instead -#include "windows.h" - -typedef unsigned char byte; - -// Use fastcall as substitute for thiscall because TCC doesn't recognize thiscall -#define __fastcall __attribute__((fastcall)) -#include "Civ3Conquests.h" - -#define MOD_VERSION 2700 -#define MOD_PREVIEW_VERSION 2 - -#define COUNT_TILE_HIGHLIGHTS 11 -#define MAX_BUILDING_PREREQS_FOR_UNIT 10 - -#define COUNT_SPECIAL_DISTRICT_TYPES 10 -#define USED_SPECIAL_DISTRICT_TYPES 11 -#define MAX_DYNAMIC_DISTRICT_TYPES 22 -#define COUNT_DISTRICT_TYPES (COUNT_SPECIAL_DISTRICT_TYPES + MAX_DYNAMIC_DISTRICT_TYPES) -#define MAX_WONDER_DISTRICT_TYPES 32 -#define MAX_NATURAL_WONDER_DISTRICT_TYPES 32 -#define MAX_DISTRICT_VARIANT_COUNT 5 -#define MAX_DISTRICT_ERA_COUNT 4 -#define MAX_DISTRICT_COLUMN_COUNT 10 -#define C3X_DISTRICT_COMMAND_BASE (-11000000) - -// Initialize to zero. Implementation is in common.c -struct table { - void * block; - size_t capacity_exponent; // Actual capacity is 1 << capacity_exponent - size_t len; -}; - -// Initialize to zero. Implementation in common.c -struct buffer { - byte * contents; - int length; - int capacity; -}; - -// A mill is a city improvement that spawns a resource. These are read from the "buildings_generating_resources" key in the config but are called -// "mills" internally for brevity. -enum mill_flag { - MF_LOCAL = 1, - MF_NO_TECH_REQ = 2, - MF_YIELDS = 4, - MF_SHOW_BONUS = 8, - MF_HIDE_NON_BONUS = 16 -}; -struct mill { - short improv_id; - short resource_id; - short flags; -}; - -#define ERA_ALIAS_LIST_CAPACITY 4 // Must not exceed 32 so we can store all genders as bits in an int - -// A list of per-era aliases for a civ's noun, adjective, or formal name. -struct civ_era_alias_list { - char * key; - char * aliases[ERA_ALIAS_LIST_CAPACITY]; -}; - -// A list of per-era aliases for a civ's leader's name, including genders and (optionally) titles. -struct leader_era_alias_list { - char * key; - char * aliases[ERA_ALIAS_LIST_CAPACITY]; - int gender_bits; // Gender of each alias. Like LeaderGender in the Race object, 0 for male and 1 for female. - char * titles[ERA_ALIAS_LIST_CAPACITY]; // Title for each alias. May be NULL. -}; - -struct unit_type_limit { - int per_civ; - int per_city; - int cities_per; -}; - -struct work_area_improvement { - short improv_id; - int work_area_radius_limit; - int work_area_radius_bonus; -}; - -enum retreat_rules { - RR_STANDARD = 0, - RR_NONE, - RR_ALL_UNITS, - RR_IF_FASTER, - RR_IF_NOT_SLOWER, - RR_IF_FAST_AND_NOT_SLOWER, -}; - -enum line_drawing_override { - LDO_NEVER = 0, - LDO_WINE, - LDO_ALWAYS -}; - -enum minimap_doubling_mode { - MDM_NEVER = 0, - MDM_HIGH_DEF, - MDM_ALWAYS -}; - -enum unit_cycle_search_criteria { - UCSC_STANDARD = 0, - UCSC_SIMILAR_NEAR_START, - UCSC_SIMILAR_NEAR_DESTINATION -}; - -enum no_ai_patrol_override { - NAPO_ZERO = 0, - NAPO_ONE, - NAPO_NONE -}; - -enum barbarian_activity_override { - BAO_NONE = -2, - - // The values for these levels must match what the game uses internally for Map.World.Final_Barbarians_Activity - BAO_NO_BARBARIANS = -1, - BAO_SEDENTARY = 0, - BAO_ROAMING = 1, - BAO_RESTLESS = 2, - BAO_RAGING = 3, - BAO_RANDOM = 4 -}; - -enum special_defensive_bombard_rules { - SDBR_LETHAL = 1, - SDBR_NOT_INVISIBLE = 2, - SDBR_AERIAL = 4, - SDBR_BLITZ = 8, - SDBR_DOCKED_VS_LAND = 16, -}; - -enum special_zone_of_control_rules { - SZOCR_LETHAL = 1, - SZOCR_AERIAL = 2, - SZOCR_AMPHIBIOUS = 4, - SZOCR_NOT_FROM_INSIDE = 8, -}; - -enum land_transport_rules { - LTR_LOAD_ONTO_BOAT = 1, - LTR_JOIN_ARMY = 2, - LTR_NO_DEFENSE_FROM_INSIDE = 4, - LTR_NO_ESCAPE = 8, -}; - -enum special_helicopter_rules { - SHR_ALLOW_ON_CARRIERS = 1, - SHR_PASSENGER_AIRDROP = 2, - SHR_NO_DEFENSE_FROM_INSIDE = 4, - SHR_NO_ESCAPE = 8, -}; - -enum work_area_limit { - WAL_NONE = 0, - WAL_CULTURAL, - WAL_CULTURAL_MIN_2, - WAL_CULTURAL_OR_ADJACENT -}; - -enum day_night_cycle_mode { - DNCM_OFF = 0, - DNCM_TIMER, - DNCM_USER_TIME, - DNCM_EVERY_TURN, - DNCM_SPECIFIED -}; - -enum distribution_hub_yield_division_mode { - DHYDM_FLAT = 0, - DHYDM_SCALE_BY_CITY_COUNT -}; - -enum ai_distribution_hub_build_strategy { - ADHBS_AUTO = 0, - ADHBS_BY_CITY_COUNT -}; - -enum ai_auto_build_great_wall_strategy { - AAGWS_ALL_BORDERS = 0, - AAGWS_OTHER_CIV_BORDERED_ONLY -}; - -enum perfume_kind { - PK_PRODUCTION = 0, - PK_TECHNOLOGY, - PK_GOVERNMENT, - - COUNT_PERFUME_KINDS -}; - -struct unit_counter_group { - char * name; - int * type_ids; - int count_type_ids; -}; - -// Attacker/defender match modes -#define UCM_ANY -1 // * Any unit type -#define UCM_GROUP -2 // Match using the group_name field - -struct counter_rule { - // Attacker side - int attacker_match; // UnitTypeID, or UCM_ANY / UCM_GROUP - char * attacker_group; // Used when attacker_match == UCM_GROUP - - // Defender side - int defender_match; - char * defender_group; - - // Environment conditions (0 / false means no restriction) - unsigned int terrain_mask; // SquareTypes mask, 0 = no restriction - bool only_in_city; - int district_id; // -1 = no restriction - char * district_name; // Resolved after district configs are loaded - bool ignore_terrain; // true = set defender terrain defense to 0 - - // Effects (percent values, 100 = no change) - int self_atk_pct; - int self_def_pct; - int enemy_atk_pct; - int enemy_def_pct; -}; - -struct c3x_config { - bool enable_stack_bombard; - bool enable_disorder_warning; - bool allow_stealth_attack_against_single_unit; - bool show_detailed_city_production_info; - int limit_railroad_movement; - bool limited_railroads_work_like_fast_roads; - int limit_units_per_tile[3]; // Limits for land, sea, and air units respectively - bool exclude_cities_from_units_per_tile_limit; - struct table exclude_types_from_units_per_tile_limit; - bool enable_free_buildings_from_small_wonders; - bool enable_stack_unit_commands; - bool skip_repeated_tile_improv_replacement_asks; - bool autofill_best_gold_amount_when_trading; - int minimum_city_separation; - bool disallow_founding_next_to_foreign_city; - bool enable_trade_screen_scroll; - bool group_units_on_right_click_menu; - bool gray_out_units_on_menu_with_no_remaining_moves; - bool put_movement_icons_on_units_on_menu; - bool describe_states_of_units_on_menu; - int anarchy_length_percent; - bool show_golden_age_turns_remaining; - bool show_zoc_attacks_from_mid_stack; - bool show_armies_performing_defensive_bombard; - bool cut_research_spending_to_avoid_bankruptcy; - bool dont_pause_for_love_the_king_messages; - bool reverse_specialist_order_with_shift; - bool toggle_zoom_with_z_on_city_screen; - bool enable_mouse_wheel_zoom; - bool dont_give_king_names_in_non_regicide_games; - bool no_elvis_easter_egg; - bool disable_worker_automation; - bool enable_land_sea_intersections; - bool disallow_trespassing; - bool show_detailed_tile_info; - struct table perfume_specs[COUNT_PERFUME_KINDS]; // Each table maps strings to i31b's. Each i31b combines an amount and whether it's a percent - struct table building_unit_prereqs; // A mapping from int keys to int values. The keys are unit type IDs. If an ID is present as a key in the - // table that means that unit type has one or more prereq buildings. The associated value is either a - // pointer to a list of MAX_BUILDING_PREREQS_FOR_UNITS improvement IDs or a single encoded improv ID. The - // contents of the list are NOT encoded and unused slots store -1. Encoding an ID is done by left-shifting - // it one place then inserting a 1 in the LSB. This way encoded IDs can be told apart from list pointers - // by checking the LSB (1 => encoded improv ID, 0 => list pointer). - struct mill * mills; - int count_mills; - bool warn_about_unrecognized_names; - bool enable_ai_production_ranking; - bool enable_ai_city_location_desirability_display; - bool show_ai_city_location_desirability_if_settler; - bool zero_corruption_when_off; - bool disallow_land_units_from_affecting_water_tiles; - bool dont_end_units_turn_after_airdrop; - bool allow_airdrop_without_airport; - bool enable_negative_pop_pollution; - enum retreat_rules land_retreat_rules; - enum retreat_rules sea_retreat_rules; - bool allow_defensive_retreat_on_water; - struct table limit_defensive_retreat_on_water_to_types; // Table mapping unit type IDs to 1's; used as a hash set - int ai_multi_city_start; - int max_tries_to_place_fp_city; - int * ai_multi_start_extra_palaces; - int count_ai_multi_start_extra_palaces; - int ai_multi_start_extra_palaces_capacity; - bool promote_wonder_decorruption_effect; - bool allow_military_leaders_to_hurry_wonders; - bool allow_multiple_battle_created_units_per_player; - int ai_research_multiplier; - int ai_settler_perfume_on_founding; - int ai_settler_perfume_on_founding_duration; - bool aggressively_penalize_bankruptcy; - bool no_penalty_exception_for_agri_fresh_water_city_tiles; - bool suppress_hypertext_links_exceeded_popup; - bool indicate_non_upgradability_in_pedia; - bool show_message_after_dodging_sam; - bool include_stealth_attack_cancel_option; - bool intercept_recon_missions; - bool charge_one_move_for_recon_and_interception; - bool polish_precision_striking; - bool enable_stealth_attack_via_bombardment; - bool immunize_aircraft_against_bombardment; - bool replay_ai_moves_in_hotseat_games; - struct table ptw_arty_types; // Table mapping unit type IDs to 1's; used as a hash set - struct table can_bombard_only_sea_tiles; // Table mapping unit type IDs to 1's; used as a hash set - bool restore_unit_directions_on_game_load; - bool apply_grid_ini_setting_on_game_load; - bool charm_flag_triggers_ptw_like_targeting; - bool city_icons_show_unit_effects_not_trade; - bool ignore_king_ability_for_defense_priority; - bool show_untradable_techs_on_trade_screen; - bool disallow_useless_bombard_vs_airfields; - enum line_drawing_override draw_lines_using_gdi_plus; - bool compact_luxury_display_on_city_screen; - bool compact_strategic_resource_display_on_city_screen; - bool warn_when_chosen_building_would_replace_another; - bool do_not_unassign_workers_from_polluted_tiles; - bool do_not_make_capital_cities_appear_larger; - bool show_territory_colors_on_water_tiles_in_minimap; - bool convert_some_popups_into_online_mp_messages; - bool enable_debug_mode_switch; - bool accentuate_cities_on_minimap; - enum minimap_doubling_mode double_minimap_size; - bool allow_multipage_civilopedia_descriptions; - enum unit_cycle_search_criteria unit_cycle_search_criteria; - bool reformat_turns_remaining_on_domestic_advisor_screen; - bool expand_civilopedia_unit_stats; - bool enable_city_capture_by_barbarians; - bool share_visibility_in_hotseat; - bool share_wonders_in_hotseat; - bool allow_precision_strikes_against_tile_improvements; - bool dont_end_units_turn_after_bombarding_barricade; - bool remove_land_artillery_target_restrictions; - bool allow_bombard_of_other_improvs_on_occupied_airfield; - bool show_total_city_count; - bool strengthen_forbidden_palace_ocn_effect; - int extra_unit_maintenance_per_shields; - enum special_zone_of_control_rules special_zone_of_control_rules; - enum special_defensive_bombard_rules special_defensive_bombard_rules; - struct civ_era_alias_list * civ_era_alias_lists; - int count_civ_era_alias_lists; - struct leader_era_alias_list * leader_era_alias_lists; - int count_leader_era_alias_lists; - struct table unit_limits; // Maps unit type names (strings) to pointers to limit objects (struct unit_type_limit *) - bool allow_upgrades_in_any_city; - bool do_not_generate_volcanos; - bool do_not_pollute_impassable_tiles; - bool show_hp_of_stealth_attack_options; - bool exclude_invisible_units_from_stealth_attack; - bool exclude_passengers_from_stealth_attack; - bool convert_to_landmark_after_planting_forest; - int chance_for_nukes_to_destroy_max_one_hp_units; - bool allow_sale_of_aqueducts_and_hospitals; - bool no_cross_shore_detection; - int city_work_radius; - bool auto_zoom_city_screen_for_large_work_areas; - enum work_area_limit work_area_limit; - struct work_area_improvement * work_area_improvements; - int count_work_area_improvements; - int rebase_range_multiplier; - bool limit_unit_loading_to_one_transport_per_turn; - bool prevent_old_units_from_upgrading_past_ability_block; - bool introduce_all_human_players_at_start_of_hotseat_game; - bool allow_unload_from_army; - enum land_transport_rules land_transport_rules; - bool allow_adjacent_resources_of_different_types; - bool allow_corruption_in_capital; - int special_capital_decorruption_effect; - int luxury_randomized_appearance_rate_percent; - int tiles_per_non_luxury_resource; - bool no_land_anti_air_from_inside_naval_transport; - enum special_helicopter_rules special_helicopter_rules; - bool prevent_enslaving_by_bombardment; - int years_to_double_building_culture; - int tourism_time_scale_percent; - bool allow_sale_of_small_wonders; - enum no_ai_patrol_override override_no_ai_patrol; - enum barbarian_activity_override override_barbarian_activity_level_for_scenario_maps; - bool initialize_preplaced_scenario_leaders_as_mgls; - bool enable_unit_counters; - struct unit_counter_group * unit_counter_groups; - int count_unit_counter_groups; - struct counter_rule * counter_rules; - int count_counter_rules; - bool use_civ4_style_best_defender; - - bool enable_trade_net_x; - bool optimize_improvement_loops; - bool measure_turn_times; - - bool use_offensive_artillery_ai; - bool dont_escort_unflagged_units; - int ai_build_artillery_ratio; - int ai_artillery_value_damage_percent; - int ai_build_bomber_ratio; - bool replace_leader_unit_ai; - bool fix_ai_army_composition; - bool enable_pop_unit_ai; - bool enable_caravan_unit_ai; - int max_ai_naval_escorts; - int ai_worker_requirement_percent; - - bool remove_unit_limit; - bool remove_city_improvement_limit; - int city_limit; - bool remove_cap_on_turn_limit; - bool remove_era_limit; - - bool patch_submarine_bug; - bool patch_science_age_bug; - bool patch_pedia_texture_bug; - bool patch_blocked_disembark_freeze; - bool patch_houseboat_bug; - bool patch_intercept_lost_turn_bug; - bool patch_phantom_resource_bug; - bool patch_maintenance_persisting_for_obsolete_buildings; - bool patch_barbarian_diagonal_bug; - bool patch_disease_stopping_tech_flag_bug; - bool patch_division_by_zero_in_ai_alliance_eval; - bool patch_empty_army_movement; - bool patch_empty_army_combat_crash; - bool delete_off_map_ai_units; - bool fix_overlapping_specialist_yield_icons; - bool patch_premature_truncation_of_found_paths; - bool patch_zero_production_crash; - bool patch_ai_can_form_army_without_special_ability; - bool patch_ai_can_sacrifice_without_special_ability; - bool patch_crash_in_leader_unit_ai; - bool patch_failure_to_find_new_city_build; - bool patch_passengers_out_of_order_on_menu; - - bool prevent_autorazing; - bool prevent_razing_by_players; - - bool allow_extraterritorial_colonies; - int per_extraterritorial_colony_relation_penalty; - - bool draw_forests_over_roads_and_railroads; - - bool enable_named_tiles; - - char * aircraft_victory_animation; // NULL if set to "none" in config - - int day_night_cycle_mode; - int elapsed_minutes_per_day_night_hour_transition; - int fixed_hours_per_turn_for_day_night_cycle; - int pinned_hour_for_day_night_cycle; - - bool enable_natural_wonders; - bool add_natural_wonders_to_scenarios_if_none; - bool show_natural_wonder_name_on_map; - int minimum_natural_wonder_separation; - - bool enable_districts; - bool enable_neighborhood_districts; - bool enable_wonder_districts; - bool enable_distribution_hub_districts; - bool enable_aerodrome_districts; - bool enable_port_districts; - bool enable_bridge_districts; - bool enable_canal_districts; - bool enable_central_rail_hub_districts; - bool enable_energy_grid_districts; - bool enable_great_wall_districts; - - bool cities_with_mutual_district_receive_buildings; - bool cities_with_mutual_district_receive_wonders; - bool show_message_when_building_received_by_mutual_district; - bool show_message_when_building_lost_to_destroyed_district; - - bool air_units_use_aerodrome_districts_not_cities; - bool naval_units_use_port_districts_not_cities; - - int maximum_pop_before_neighborhood_needed; - int per_neighborhood_pop_growth_enabled; - int neighborhood_needed_message_frequency; - bool destroying_neighborhood_reduces_pop; - - bool completed_wonder_districts_can_be_destroyed; - bool destroyed_wonders_can_be_built_again; - - int distribution_hub_yield_division_mode; - int distribution_hub_food_yield_divisor; - int distribution_hub_shield_yield_divisor; - int ai_distribution_hub_build_strategy; - int ai_ideal_distribution_hub_count_per_100_cities; - int max_distribution_hub_count_per_100_cities; - int central_rail_hub_distribution_food_bonus_percent; - int central_rail_hub_distribution_shield_bonus_percent; - - bool workers_can_enter_coast; - bool expand_water_tile_checks_to_city_work_area; - int max_contiguous_bridge_districts; - int max_contiguous_canal_districts; - int ai_canal_eval_min_bisected_land_tiles; - int ai_bridge_canal_eval_block_size; - int ai_bridge_eval_lake_tile_threshold; - bool ai_can_replace_existing_districts_with_canals; - bool ai_builds_bridges; - bool ai_builds_canals; - - bool ai_defends_districts; - int ai_city_district_max_build_wait_turns; - - bool disable_great_wall_city_defense_bonus; - bool great_wall_districts_impassible_by_others; - bool auto_build_great_wall_around_territory; - char * great_wall_auto_build_wonder_name; - int great_wall_auto_build_wonder_improv_id; - int ai_auto_build_great_wall_strategy; - - bool enable_city_work_radii_highlights; -}; - -enum stackable_command { - SC_BOMBARD = 0, - SC_BOMB, - SC_FORTRESS, - SC_MINE, - SC_IRRIGATE, - SC_CHOP_FOREST, - SC_CHOP_JUNGLE, - SC_PLANT, - SC_CLEAN_POLLUTION, - SC_ROAD, - SC_RAILROAD, - SC_FORTIFY, - SC_UPGRADE, - SC_DISBAND, - COUNT_STACKABLE_COMMANDS -}; - -enum stackable_command_kind { - SCK_BOMBARD = 0, - SCK_TERRAFORM, - SCK_UNIT_MGMT, - COUNT_STACKABLE_COMMAND_KINDS -}; - -struct sc_button_info { - enum Unit_Command_Values command; - enum stackable_command_kind kind; - int tile_sheet_column, - tile_sheet_row; -} const sc_button_infos[COUNT_STACKABLE_COMMANDS] = { - /* Bombard */ { .command = UCV_Bombard , .kind = SCK_BOMBARD , .tile_sheet_column = 3, .tile_sheet_row = 1 }, - /* Bomb */ { .command = UCV_Bombing , .kind = SCK_BOMBARD , .tile_sheet_column = 5, .tile_sheet_row = 4 }, - /* Fortress */ { .command = UCV_Build_Fortress , .kind = SCK_TERRAFORM, .tile_sheet_column = 0, .tile_sheet_row = 3 }, - /* Mine */ { .command = UCV_Build_Mine , .kind = SCK_TERRAFORM, .tile_sheet_column = 1, .tile_sheet_row = 3 }, - /* Irrigate */ { .command = UCV_Irrigate , .kind = SCK_TERRAFORM, .tile_sheet_column = 2, .tile_sheet_row = 3 }, - /* Chop For. */ { .command = UCV_Clear_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 3, .tile_sheet_row = 3 }, - /* Chop Jun. */ { .command = UCV_Clear_Jungle , .kind = SCK_TERRAFORM, .tile_sheet_column = 4, .tile_sheet_row = 3 }, - /* Plant */ { .command = UCV_Plant_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 5, .tile_sheet_row = 3 }, - /* Clean Pol. */ { .command = UCV_Clear_Pollution, .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 3 }, - /* Road */ { .command = UCV_Build_Road , .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 2 }, - /* Railroad */ { .command = UCV_Build_Railroad , .kind = SCK_TERRAFORM, .tile_sheet_column = 7, .tile_sheet_row = 2 }, - /* Fortify */ { .command = UCV_Fortify , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 2, .tile_sheet_row = 0 }, - /* Upgrade */ { .command = UCV_Upgrade_Unit , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 7, .tile_sheet_row = 1 }, - /* Disband */ { .command = UCV_Disband , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 3, .tile_sheet_row = 0 }, -}; - -enum init_state { - IS_UNINITED = 0, - IS_OK, - IS_INIT_FAILED -}; - -enum c3x_label { - CL_NEVER_COMPLETES = 0, - CL_HALTED, - CL_SURPLUS, - CL_SURPLUS_NONE, - CL_SURPLUS_NA, - CL_SB_TOOLTIP, - CL_CHOPPED, - CL_OFF, - CL_MOD_INFO_BUTTON_TEXT, - CL_VERSION, - CL_CONFIG_FILES_LOADED, - CL_CREATING_CITIES, - CL_MCS_FAILED_SANITY_CHECK, - CL_MCS_ADJACENT_CITIES, - CL_MCS_MISSING_CITIES, - CL_OBSOLETED_BY, - CL_NO_STEALTH_ATTACK, - CL_DODGED_SAM, - CL_PREVIEW, - CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP, - CL_TOTAL_CITIES, - - // Offense, Defense, Artillery, etc. - CL_FIRST_UNIT_STRAT, - CL_LAST_UNIT_STRAT = CL_FIRST_UNIT_STRAT + 19, - - // Unit actions for right-click menu - CL_IDLE, - CL_FORTIFIED, - CL_SENTRY, - CL_MINING, - CL_IRRIGATING, - CL_BUILDING_FORTRESS, - CL_BUILDING_ROAD, - CL_BUILDING_RAILROAD, - CL_PLANTING_FOREST, - CL_CLEARING_FOREST, - CL_CLEARING_WETLANDS, - CL_CLEARING_DAMAGE, - CL_BUILDING_AIRFIELD, - CL_BUILDING_RADAR_TOWER, - CL_BUILDING_OUTPOST, - CL_BUILDING_BARRICADE, - CL_BUILDING_COLONY, - CL_INTERCEPTING, - CL_MOVING, - CL_AUTOMATED, - CL_EXPLORING, - CL_BOMBARDING, - - // Generic "Building" phrase for Districts right-click menu - CL_BUILDING, - - // Districts-related texts - CL_REQUIRES, - CL_TO_GROW, - CL_DISTRICT_DESTROYED_BY_VOLCANO, - CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT, - CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD, - - CL_RECEIVED, - CL_FROM_SHARED, - CL_WITH, - - CL_APOSTROPHE_S, - CL_AND, - CL_OTHER_BUILDINGS_HAVE_BEEN, - CL_LOST_DUE_TO_DESTROYED, - - // Districts config mismatch checked on game load - CL_DISTRICT_ID, - CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW, - CL_DISTRICT_NAME_MISMATCH, - CL_SAVE_FILE_HAD, - CL_CURRENT_CONFIG_HAS_ONLY, - CL_WARNING_DISTRICTS_CONFIG_MISMATCH, - CL_MAY_BE_OTHER_ERRORS_AS_WELL, - CL_DISTRICTS_IN_SAVE_FILE, - CL_CURRENTLY_CONFIGURED_DISTRICTS, - - // Tile naming - CL_NAME_TILE, - CL_RENAME_TILE, - - // "Action" for passenger units - CL_TRANSPORTED, - - CL_IN_STATE_27, - CL_IN_STATE_28, - CL_IN_STATE_29, - CL_IN_STATE_30, - CL_IN_STATE_33, - - // For unit stats on Civilopedia - CL_HP_BONUS, - CL_WORKER_STRENGTH, - - CL_AGRICULTURAL, - CL_COMMERCIAL, - CL_EXPANSIONIST, - CL_INDUSTRIOUS, - CL_MILITARISTIC, - CL_RELIGIOUS, - CL_SCIENTIFIC, - CL_SEAFARING, - - COUNT_C3X_LABELS -}; - -struct worker_job_and_location { - enum Worker_Jobs job; - int tile_x, tile_y; -}; - -struct ai_prod_valuation { - int order_type; - int order_id; - int point_value; -}; - -enum unit_rcm_icon { - URCMI_UNMOVED = 0, - URCMI_MOVED_CAN_ATTACK, - URCMI_MOVED_NO_ATTACK, - URCMI_CANT_MOVE, - - COUNT_UNIT_RCM_ICONS -}; - -enum unit_rcm_icon_set { - URCMIS_ATTACKER = 0, - URCMIS_NONCOMBAT, - URCMIS_BUSY_ATTACKER, - URCMIS_BUSY_NONCOMBAT, - - COUNT_UNIT_RCM_ICON_SETS -}; - -enum city_gain_reason { - CGR_FOUNDED = 0, - CGR_CONQUERED, - CGR_CONVERTED, // covers culture flips & bribes - CGR_TRADED, - CGR_POPPED_FROM_HUT, - CGR_PLACED_FOR_AI_RESPAWN, - CGR_PLACED_FOR_SCENARIO, - CGR_PLACED_FOR_AI_MULTI_CITY_START, -}; - -enum city_loss_reason { - CLR_DESTROYED = 0, // means city was razed for any reason (inc. by conqueror) - CLR_CONQUERED, - CLR_CONVERTED, // covers culture flips & bribes - CLR_TRADED -}; - -enum { - MAX_DISTRICT_DEPENDENTS = 64 -}; - -enum { - DEFAULT_DISTRICT_BUILDABLE_MASK = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain) | (1 << SQ_Hills) -}; - -enum { - MAX_DISTRICT_BONUS_ENTRIES = 16 -}; - -enum district_bonus_entry_type { - DBET_TILE = 0, - DBET_BUILDING = 1 -}; - -enum great_wall_auto_build_state { - GWABS_NOT_STARTED = 0, - GWABS_RUNNING, - GWABS_DONE -}; - -struct district_bonus_entry { - enum district_bonus_entry_type type; - int bonus; - enum SquareTypes tile_type; - int building_id; - char const * building_name; -}; - -struct district_bonus_list { - int count; - struct district_bonus_entry entries[MAX_DISTRICT_BONUS_ENTRIES]; -}; - -enum district_render_strategy { - DRS_BY_COUNT = 0, - DRS_BY_BUILDING = 1 -}; - -enum district_ai_build_strategy { - DABS_DISTRICT = 0, - DABS_TILE_IMPROVEMENT = 1 -}; - -struct district_config { - enum Unit_Command_Values command; - char const * name; - char const * display_name; - char const * tooltip; - char const * advance_prereqs[MAX_DISTRICT_DEPENDENTS]; - int advance_prereq_count; - char const * obsoleted_by; - char const * resource_prereqs[MAX_DISTRICT_DEPENDENTS]; - char const * resource_prereq_on_tile; - char const * dependent_improvements[MAX_DISTRICT_DEPENDENTS]; - char const * wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; - char const * natural_wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; - char const * buildable_on_districts[MAX_DISTRICT_DEPENDENTS]; - char const * buildable_adjacent_to_districts[MAX_DISTRICT_DEPENDENTS]; - char const * img_paths[10]; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_without_removal_mask; - unsigned int buildable_on_overlays_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - bool allow_multiple; - bool vary_img_by_era; - bool vary_img_by_culture; - enum district_render_strategy render_strategy; - enum district_ai_build_strategy ai_build_strategy; - bool is_dynamic; - bool align_to_coast; - bool draw_over_resources; - bool allow_irrigation_from; - bool auto_add_road; - bool auto_add_railroad; - int custom_width; - int custom_height; - int x_offset; - int y_offset; - int resource_prereq_count; - int dependent_improvement_max_index; - int wonder_prereq_count; - int natural_wonder_prereq_count; - int buildable_on_district_count; - int buildable_adjacent_to_district_count; - int img_path_count; - int img_column_count; - bool has_img_column_count_override; - int btn_tile_sheet_column; - int btn_tile_sheet_row; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - struct district_bonus_list culture_bonus_extras; - struct district_bonus_list science_bonus_extras; - struct district_bonus_list food_bonus_extras; - struct district_bonus_list gold_bonus_extras; - struct district_bonus_list shield_bonus_extras; - struct district_bonus_list happiness_bonus_extras; - struct district_bonus_list defense_bonus_extras; - int defense_bonus_percent; - bool heal_units_in_one_turn; - bool impassible; - bool impassible_to_wheeled; - char const * generated_resource; - int generated_resource_id; - short generated_resource_flags; - int buildable_on_district_ids[MAX_DISTRICT_DEPENDENTS]; - int buildable_on_district_id_count; - bool has_buildable_on_districts; - int buildable_adjacent_to_district_ids[MAX_DISTRICT_DEPENDENTS]; - int buildable_adjacent_to_district_id_count; - bool has_buildable_adjacent_to; - bool has_buildable_adjacent_to_districts; - bool has_buildable_without_removal; - bool has_buildable_on_overlays; - bool has_buildable_adjacent_to_overlays; - bool has_buildable_on_rivers; - char const * buildable_by_civs[32]; - int buildable_by_civ_count; - bool has_buildable_by_civs; - int buildable_by_civ_traits_ids[8]; - int buildable_by_civ_traits_id_count; - bool has_buildable_by_civ_traits; - int buildable_by_civ_govs_ids[5]; - int buildable_by_civ_govs_id_count; - bool has_buildable_by_civ_govs; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_buildable_by_civ_cultures; - bool buildable_by_war_allies; - bool buildable_by_pact_allies; -}; - -struct wonder_district_config { - char const * wonder_name; - char const * img_path; - int index, - img_row, - img_column, - img_construct_row, - img_construct_column, - img_alt_dir_construct_row, - img_alt_dir_construct_column, - img_alt_dir_row, - img_alt_dir_column, - custom_width, - custom_height; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - char const * buildable_by_civs[32]; - int buildable_by_civ_count; - bool has_buildable_by_civs; - int buildable_by_civ_traits_ids[8]; - int buildable_by_civ_traits_id_count; - bool has_buildable_by_civ_traits; - int buildable_by_civ_govs_ids[5]; - int buildable_by_civ_govs_id_count; - bool has_buildable_by_civ_govs; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_buildable_by_civ_cultures; - bool enable_img_alt_dir; - bool is_dynamic; - bool has_buildable_adjacent_to; - bool has_buildable_adjacent_to_overlays; -}; - -enum square_type_extras { - SQ_INVALID = -1, - SQ_RIVER = SQ_Ocean + 1, - SQ_SNOW_VOLCANO, - SQ_SNOW_FOREST, - SQ_SNOW_MOUNTAIN -}; - -enum district_overlay_mask_bits { - DOM_MINE = 1u << 0, - DOM_IRRIGATION = 1u << 1, - DOM_FORTRESS = 1u << 2, - DOM_BARRICADE = 1u << 3, - DOM_OUTPOST = 1u << 4, - DOM_RADAR_TOWER = 1u << 5, - DOM_JUNGLE = 1u << 6, - DOM_FOREST = 1u << 7, - DOM_SWAMP = 1u << 8, - DOM_RIVER = 1u << 9, - DOM_AIRFIELD = 1u << 10 -}; - -struct natural_wonder_district_config { - char const * name; - char const * img_path; - enum SquareTypes terrain_type; - enum SquareTypes adjacent_to; - enum direction adjacency_dir; - int index; - int img_row; - int img_column; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - bool impassible; - bool impassible_to_wheeled; - bool is_dynamic; -}; - -struct natural_wonder_candidate { - Tile * tile; - short x, y; -}; - -struct natural_wonder_candidate_list { - struct natural_wonder_candidate * entries; - int count; - int capacity; -}; - -struct wonder_location { - short x; - short y; -}; - -const struct district_config special_district_defaults[USED_SPECIAL_DISTRICT_TYPES] = { - { - .command = UCV_Build_Neighborhood, .name = "Neighborhood", .tooltip = "Build Neighborhood", .display_name = "Neighborhood", - .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = true, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {"Neighborhood_AMER.pcx", "Neighborhood_EURO.pcx", "Neighborhood_ROMAN.pcx", "Neighborhood_MIDEAST.pcx", "Neighborhood_ASIAN.pcx"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 5, .img_column_count = 4, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, - .culture_bonus = 1, .science_bonus = 1, .food_bonus = 0, .gold_bonus = 1, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 25, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - - }, - { - .command = UCV_Build_WonderDistrict, .name = "Wonder District", .tooltip = "Build Wonder District", .display_name = "Wonder District", - .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {"WonderDistrict.pcx"}, - .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Coast) | (1 << SQ_Mountains)), - .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 1, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - - }, - { - .command = UCV_Build_DistributionHub, .name = "Distribution Hub", .tooltip = "Build Distribution Hub", .display_name = "Distribution Hub", - .advance_prereqs = {"Construction"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {"DistributionHub.pcx"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 2, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - - }, - { - .command = UCV_Build_Aerodrome, .name = "Aerodrome", .tooltip = "Build Aerodrome", .display_name = "Aerodrome", - .advance_prereqs = {"Flight"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 1, - .img_paths = {"Aerodrome.pcx"}, .dependent_improvements = {"Airport"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 1, .img_column_count = 2, .btn_tile_sheet_column = 3, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = -1, .name = "Natural Wonder", .tooltip = NULL, .display_name = "Natural Wonder", - .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, - .img_paths = {0}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, - .img_path_count = 0, .img_column_count = 0, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_Port, .name = "Port", .tooltip = "Build Port", .display_name = "Port", - .advance_prereqs = {"Map Making"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 2, .align_to_coast = true, - .img_paths = {"Port_NW.pcx", "Port_NE.pcx", "Port_SE.pcx", "Port_SW.pcx"}, .dependent_improvements = {"Harbor", "Commercial Dock"}, - .buildable_square_types_mask = (1 << SQ_Coast), - .img_path_count = 4, .img_column_count = 4, .btn_tile_sheet_column = 4, .btn_tile_sheet_row = 0, .align_to_coast = true, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_CentralRailHub, .name = "Central Rail Hub", .tooltip = "Build Central Rail Hub", .display_name = "Central Rail Hub", - .advance_prereqs = {"Steam Power"}, .advance_prereq_count = 1, .resource_prereqs = {"Iron", "Coal"}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 2, .dependent_improvement_max_index = 0, - .img_paths = {"CentralRailHub_AMER.pcx", "CentralRailHub_EURO.pcx", "CentralRailHub_ROMAN.pcx", "CentralRailHub_MIDEAST.pcx", "CentralRailHub_ASIAN.pcx"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .auto_add_road = true, .auto_add_railroad = true, - .img_path_count = 5, .img_column_count = 2, .btn_tile_sheet_column = 5, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_EnergyGrid, .name = "Energy Grid", .tooltip = "Build Energy Grid", .display_name = "Energy Grid", - .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 4, - .img_paths = {"EnergyGrid.pcx"}, .dependent_improvements = {"Coal Plant", "Hydro Plant", "Nuclear Plant", "Solar Plant"}, - .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .custom_height = 84, - .img_path_count = 1, .img_column_count = 5, .btn_tile_sheet_column = 6, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 2, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_Bridge, .name = "Bridge", .tooltip = "Build Bridge", .display_name = "Bridge", - .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, - .img_paths = {"Bridge.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, - .buildable_square_types_mask = (1 << SQ_Coast), .auto_add_road = true, - .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 7, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_Canal, .name = "Canal", .tooltip = "Build Canal", .display_name = "Canal", - .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, - .img_paths = {"Canal.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, - .buildable_square_types_mask = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain), - .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 8, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - }, - { - .command = UCV_Build_GreatWall, .name = "Great Wall", .tooltip = "Build Great Wall", .display_name = "Great Wall", - .advance_prereqs = {0}, .advance_prereq_count = 0, .obsoleted_by = "Metallurgy", .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, - .img_paths = {"GreatWall.pcx"}, .dependent_improvements = {0}, .custom_height = 88, .wonder_prereqs = {"The Great Wall"}, .wonder_prereq_count = 1, - .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Mountains) | (1 << SQ_Forest) | (1 << SQ_Swamp) | (1 << SQ_Jungle) | (1 << SQ_Volcano)), .draw_over_resources = true, - .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 9, .btn_tile_sheet_row = 0, - .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 50, - .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 - } -}; - -struct parsed_district_definition { - char * name; - char * display_name; - char * tooltip; - char * advance_prereqs[5]; - int advance_prereq_count; - char * obsoleted_by; - char * resource_prereqs[5]; - char * resource_prereq_on_tile; - char * dependent_improvements[5]; - char * wonder_prereqs[5]; - char * natural_wonder_prereqs[5]; - char * buildable_on_districts[5]; - char * buildable_adjacent_to_districts[5]; - char * img_paths[5]; - int resource_prereq_count; - int dependent_improvement_max_index; - int wonder_prereq_count; - int natural_wonder_prereq_count; - int buildable_on_district_count; - int buildable_adjacent_to_district_count; - int img_path_count; - int img_column_count; - bool allow_multiple; - bool vary_img_by_era; - bool vary_img_by_culture; - enum district_render_strategy render_strategy; - enum district_ai_build_strategy ai_build_strategy; - bool align_to_coast; - bool draw_over_resources; - bool allow_irrigation_from; - bool auto_add_road; - bool auto_add_railroad; - bool impassible; - bool impassible_to_wheeled; - int custom_width; - int custom_height; - int x_offset; - int y_offset; - int btn_tile_sheet_column; - int btn_tile_sheet_row; - int defense_bonus_percent; - bool heal_units_in_one_turn; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - struct district_bonus_list culture_bonus_extras; - struct district_bonus_list science_bonus_extras; - struct district_bonus_list food_bonus_extras; - struct district_bonus_list gold_bonus_extras; - struct district_bonus_list shield_bonus_extras; - struct district_bonus_list happiness_bonus_extras; - struct district_bonus_list defense_bonus_extras; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_without_removal_mask; - unsigned int buildable_on_overlays_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - char * buildable_by_civs[32]; - int buildable_by_civ_count; - bool buildable_by_war_allies; - bool buildable_by_pact_allies; - bool has_name; - bool has_tooltip; - bool has_advance_prereqs; - bool has_obsoleted_by; - bool has_resource_prereqs; - bool has_dependent_improvements; - bool has_wonder_prereqs; - bool has_natural_wonder_prereqs; - bool has_display_name; - bool has_img_paths; - bool has_img_column_count; - bool has_allow_multiple; - bool has_vary_img_by_era; - bool has_vary_img_by_culture; - bool has_render_strategy; - bool has_ai_build_strategy; - bool has_align_to_coast; - bool has_draw_over_resources; - bool has_custom_width; - bool has_custom_height; - bool has_x_offset; - bool has_y_offset; - bool has_btn_tile_sheet_column; - bool has_btn_tile_sheet_row; - bool has_defense_bonus_percent; - bool has_heal_units_in_one_turn; - bool has_culture_bonus; - bool has_science_bonus; - bool has_food_bonus; - bool has_gold_bonus; - bool has_shield_bonus; - bool has_happiness_bonus; - bool has_buildable_on; - bool has_buildable_adjacent_to; - bool has_buildable_without_removal; - bool has_buildable_on_overlays; - bool has_buildable_adjacent_to_overlays; - bool has_buildable_on_rivers; - bool has_resource_prereq_on_tile; - bool has_buildable_by_civs; - bool has_buildable_by_war_allies; - bool has_buildable_by_pact_allies; - char * generated_resource; - short generated_resource_flags; - bool has_generated_resource; - char * buildable_by_civ_traits[10]; - int buildable_by_civ_traits_count; - int buildable_by_civ_traits_ids[10]; - int buildable_by_civ_traits_id_count; - bool has_buildable_by_civ_traits; - char * buildable_by_civ_govs[10]; - int buildable_by_civ_govs_count; - int buildable_by_civ_govs_ids[32]; - int buildable_by_civ_govs_id_count; - bool has_buildable_by_civ_govs; - char * buildable_by_civ_cultures[5]; - int buildable_by_civ_cultures_count; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_buildable_by_civ_cultures; - bool has_buildable_on_districts; - bool has_buildable_adjacent_to_districts; - bool has_allow_irrigation_from; - bool has_auto_add_road; - bool has_auto_add_railroad; - bool has_impassible; - bool has_impassible_to_wheeled; -}; - -struct parsed_wonder_definition { - char * name; - char * img_path; - int img_row; - int img_column; - int img_construct_row; - int img_construct_column; - int img_alt_dir_construct_row; - int img_alt_dir_construct_column; - int img_alt_dir_row; - int img_alt_dir_column; - int custom_width; - int custom_height; - bool enable_img_alt_dir; - unsigned int buildable_square_types_mask; - unsigned int buildable_adjacent_to_square_types_mask; - unsigned int buildable_adjacent_to_overlays_mask; - bool buildable_on_rivers; - bool buildable_adjacent_to_allows_city; - char * buildable_by_civs[32]; - int buildable_by_civ_count; - char * buildable_by_civ_traits[10]; - int buildable_by_civ_traits_count; - int buildable_by_civ_traits_ids[10]; - int buildable_by_civ_traits_id_count; - char * buildable_by_civ_govs[10]; - int buildable_by_civ_govs_count; - int buildable_by_civ_govs_ids[32]; - int buildable_by_civ_govs_id_count; - char * buildable_by_civ_cultures[5]; - int buildable_by_civ_cultures_count; - int buildable_by_civ_cultures_ids[5]; - int buildable_by_civ_cultures_id_count; - bool has_name; - bool has_img_path; - bool has_img_row; - bool has_img_column; - bool has_img_construct_row; - bool has_img_construct_column; - bool has_img_alt_dir_construct_row; - bool has_img_alt_dir_construct_column; - bool has_img_alt_dir_row; - bool has_img_alt_dir_column; - bool has_custom_width; - bool has_custom_height; - bool has_enable_img_alt_dir; - bool has_buildable_on; - bool has_buildable_adjacent_to; - bool has_buildable_adjacent_to_overlays; - bool has_buildable_on_rivers; - bool has_buildable_by_civs; - bool has_buildable_by_civ_traits; - bool has_buildable_by_civ_govs; - bool has_buildable_by_civ_cultures; -}; - -struct parsed_natural_wonder_definition { - char * name; - char * img_path; - enum SquareTypes terrain_type; - enum SquareTypes adjacent_to; - enum direction adjacency_dir; - int img_row; - int img_column; - int culture_bonus; - int science_bonus; - int food_bonus; - int gold_bonus; - int shield_bonus; - int happiness_bonus; - bool impassible; - bool impassible_to_wheeled; - bool has_name; - bool has_img_path; - bool has_img_row; - bool has_img_column; - bool has_terrain_type; - bool has_adjacent_to; - bool has_adjacency_dir; - bool has_culture_bonus; - bool has_science_bonus; - bool has_food_bonus; - bool has_gold_bonus; - bool has_shield_bonus; - bool has_happiness_bonus; - bool has_impassible; - bool has_impassible_to_wheeled; -}; - -struct scenario_district_entry { - int tile_x; - int tile_y; - int has_coordinates; - char * district_name; - int has_district_name; - char * wonder_city_name; - int has_wonder_city; - char * wonder_name; - int has_wonder_name; -}; - -struct scenario_named_tile_entry { - int tile_x; - int tile_y; - int has_coordinates; - char * name; - int has_name; -}; - -struct distribution_hub_record { - Tile * tile; - int tile_x; - int tile_y; - int civ_id; - int food_yield; - int shield_yield; - int raw_food_yield; - int raw_shield_yield; -}; - -struct ai_best_feasible_order { - City_Order order; - int value; -}; - -struct district_building_prereq_list { - int count; - int district_ids[MAX_DISTRICT_DEPENDENTS]; -}; - -struct pending_district_request { - City * city; - int city_id; - int civ_id; - int district_id; - int assigned_worker_id; - int target_x; - int target_y; - int worker_assigned_turn; -}; - -struct ai_candidate_bridge_or_canal_entry { - int district_id; - short owner_civ_id; - short * tile_x; - short * tile_y; - short tile_count; - short assigned_tile_index; - int assigned_worker_id; - bool completed; - struct pending_district_request pending_req; - int tile_capacity; -}; - -struct district_worker_record { - Unit * worker; - int unit_id; - int continent_id; - struct pending_district_request * pending_req; -}; - -enum wonder_district_state { - WDS_UNUSED = 0, // Wonder district built, no wonder assigned - WDS_UNDER_CONSTRUCTION, // Reserved by a city for wonder construction - WDS_COMPLETED, // Wonder completed on this district - WDS_RUINED // (Future) Wonder was destroyed -}; - -struct wonder_district_info { - enum wonder_district_state state; - City * city; // City that reserved/completed (NULL if unused) - int city_id; - int wonder_index; // Wonder index (-1 if unused/reserved, valid if completed) -}; - -struct natural_wonder_district_info { - int natural_wonder_id; -}; - -enum district_state { - DS_UNDER_CONSTRUCTION = 0, - DS_COMPLETED = 1 -}; - -struct district_instance { - enum district_state state; - int district_id; // Index into district_configs array - int tile_x; - int tile_y; - int built_by_civ_id; - int completed_turn; - struct wonder_district_info wonder_info; // Only used if district_id is a wonder district - struct natural_wonder_district_info natural_wonder_info; // Only used if district_id is a natural wonder district -}; - -enum extra_resource_tile_type { - ERT_MILL_RESOURCE = 0, - ERT_DISTRICT_RESOURCE -}; - -struct extra_resource_tile { - Tile * tile; - enum extra_resource_tile_type type; - union { - struct { - City * city; - struct mill * mill; - } mill_info; - struct { - struct district_instance * inst; - struct district_config * cfg; - } district_info; - }; -}; - -struct named_tile_entry { - int tile_x; - int tile_y; - char name[100]; -}; - -struct highlighted_city_radius_tile_info { - int highlight_level; -}; - -struct injected_state { - // ========== - // These fields are valid at any time in the injected code because they're set by the patcher { - // ========== - - int mod_version; - // "mod relative directory" is the mod dir relative to the conquests dir. Usually it's "C3X_Rn" but it might be deeper. - // It must be non-empty and must not have an ending backslash. - char mod_rel_dir[MAX_PATH]; - - enum init_state sc_img_state; - enum init_state tile_highlight_state; - enum init_state mod_info_button_images_state; - enum init_state disabled_command_img_state; - enum init_state unit_rcm_icon_state; - enum init_state red_food_icon_state; - enum init_state distribution_hub_icons_img_state; - enum init_state tile_already_worked_zoomed_out_sprite_init_state; - enum init_state day_night_cycle_img_state; - enum init_state large_minimap_frame_img_state; - - // ========== - // } These fields are valid at any time after patch_init_floating_point runs (which is at the program launch). { - // ========== - - struct c3x_config base_config; - - // Windows modules - HMODULE kernel32; - HMODULE user32; - HMODULE msvcrt; - HMODULE msimg32; - - // Win32 API functions - WINBOOL (WINAPI * VirtualProtect) (LPVOID, SIZE_T, DWORD, PDWORD); - WINBOOL (WINAPI * CloseHandle) (HANDLE); - HANDLE (WINAPI * CreateFileA) (LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); - DWORD (WINAPI * GetFileSize) (HANDLE, LPDWORD); - WINBOOL (WINAPI * ReadFile) (HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); - HMODULE (WINAPI * LoadLibraryA) (LPCSTR); - BOOL (WINAPI * FreeLibrary) (HMODULE); - int (WINAPI * MultiByteToWideChar) (UINT, DWORD, LPCCH, int, LPWSTR, int); - int (WINAPI * WideCharToMultiByte) (UINT, DWORD, LPCWCH, int, LPSTR, int, LPCCH, LPBOOL); - int (WINAPI * GetLastError) (); - BOOL (WINAPI * QueryPerformanceCounter) (LARGE_INTEGER *); - BOOL (WINAPI * QueryPerformanceFrequency) (LARGE_INTEGER *); - void (WINAPI * GetLocalTime) (LPSYSTEMTIME); - - // Win32 funcs from user32.dll - int (WINAPI * MessageBoxA) (HWND, LPCSTR, LPCSTR, UINT); - - // Win32 funcs from Msimg32.dll - BOOL (WINAPI * TransparentBlt) (HDC, int, int, int, int, HDC, int, int, int, int, UINT); - - // C standard library functions - int (* snprintf) (char *, size_t, char const *, ...); - void * (* malloc) (size_t); - void * (* calloc) (size_t, size_t); - void * (* realloc) (void *, size_t); - void (* free) (void *); - long (* strtol) (char const *, char **, int); - float (* strtof) (char const *, char **); - int (* strcmp) (char const *, char const *); - int (* strncmp) (char const *, char const *, size_t); - int (* _stricmp) (char const *, char const *); - size_t (* strlen) (char const *); - char * (* strncpy) (char *, char const *, size_t); - char * (* strcpy) (char *, char const *); - char * (* strdup) (char const *); - char * (* strstr) (char const *, char const *); - void (* qsort) (void *, size_t, size_t, int (*) (void const *, void const *)); - int (* memcmp) (void const *, void const *, size_t); - void * (* memcpy) (void *, void const *, size_t); - void * (* memmove) (void *, void const *, size_t); - int (* tolower) (int); - int (* toupper) (int); - - Unit * sb_next_up; // The unit currently doing a stack bombard or NULL otherwise. Gets set to NULL if the unit is despawned. - - Trade_Net * trade_net; // Pointer to the trade net object. If it hasn't been moved by the mod, this equals p_original_trade_net. - int city_limit; // Stores the current actual city limit. Not necessarily the same as the stride of the trade net matrix or the config setting. - - enum init_state trade_net_addrs_load_state; - int * trade_net_addrs; - - HMODULE trade_net_x; - void (__stdcall * set_exe_version) (int); - void * (__stdcall * create_tnx_cache) (Map *); - void (__stdcall * destroy_tnx_cache) (void *); - void (__stdcall * set_up_before_building_network) (void *); - int (__stdcall * get_move_cost_for_sea_trade) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags, int neighbor_index, Trade_Net_Distance_Info * dist_info); - void (__stdcall * flood_fill_road_network) (void * tnx_cache, int from_x, int from_y, int civ_id); - bool (__stdcall * try_drawing_sea_trade_route) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags); - - void * tnx_cache; // Cache object used by Trade Net X. Initially NULL, must be recreated every time a new map is loaded. - enum init_state tnx_init_state; - bool is_computing_city_connections; // Set to true only while Trade_Net::recompute_city_connections is running - bool keep_tnx_cache; - - // This flag gets set whenever a trade deal is signed or broken for a resource that's an input to a mill. It's necessary to call - // recompute_resources in that case since a mill may have been de/activated by the change. We can't call it right when the change happens as - // that can crash the game for reasons I don't completely understand. I believe it's because the recomputation can't be done while some other - // econ logic is running. Instead, we set this variable then recompute before obsolete data would be an issue. Specifically, this is done: - // - When any player or AI begins their production phase - // - When the player zooms to any city - // - When the player opens the shift + right-click production chooser menu - // - When the player visits any advisor - // - When the player selects any unit - bool must_recompute_resources_for_mill_inputs; - - bool is_placing_scenario_things; // Set to true only while Map::place_scenario_things is running - - bool paused_for_popup; // Set to true while a popup, map message, or the diplo screen is open - long long time_spent_paused_during_popup; // Tracks time spent waiting for the three things above - - // This variable is increased with the time elapsed during every call to Trade_Net::recompute_city_connections. Time is measured using - // Windows performance counter. - long long time_spent_computing_city_connections; - int count_calls_to_recompute_city_connections; - - long long time_spent_filling_roads; - - struct c3x_config current_config; - - // Keeps a record of all configs currently loaded. Useful to know. "name" is the file name for configs that come from files, which is all of - // them except for the base config, whose name is "(base)". - struct loaded_config_name { - char * name; - struct loaded_config_name * next; - } * loaded_config_names; - - char current_districts_config_path[MAX_PATH]; - - char mod_script_path[MAX_PATH]; - - char * c3x_labels[COUNT_C3X_LABELS]; - - int have_job_and_loc_to_skip; // 0 or 1 if the variable below has anything actionable in it. Gets cleared to 0 after every turn. - struct worker_job_and_location to_skip; - - struct table saved_code_areas; - - int * unit_menu_duplicates; // NULL initialized, allocated to an array of 0x100 ints when needed - bool named_tile_menu_active; - int named_tile_menu_tile_x; - int named_tile_menu_tile_y; - - // List of temporary ints. Initializes to NULL/0/0, used with functions "memoize" and "clear_memo" - int * memo; - int memo_len; - int memo_capacity; - - // Array mapping cultural neighbor indices to the standard indices that correspond to the same tiles. Generated at program start. - byte * cultural_ni_to_standard; - - // Array mapping standard neighbor indices to the smallest work radius that includes the corresponding tile. Ex., if a given n.i. corresponds - // to one of the adjacent tiles, maps to 1, if it's in the fat cross but not adjacent, maps to 2, and so forth, out into the extended area. - char ni_to_work_radius[256]; - - // The maximum number of tiles workable by cities including the city tile itself (21 under standard game rules). Updated whenever the - // city_work_radius config value gets changed. - int workable_tile_count; - - // The civ ID of the player from whose perspective we're currently showing city loc desirability, or -1 if none. Initialized to -1. - int city_loc_display_perspective; - - // These are all bit fields that run parallel to player bits. Each bit indicates whether or not that name was replaced with an era-specific - // version for that player. This allows us to tell the difference between custom names set by human players and replacements made by the mod. - int aliased_civ_noun_bits; - int aliased_civ_adjective_bits; - int aliased_civ_formal_name_bits; - int aliased_leader_name_bits; - int aliased_leader_title_bits; - - // Stores resource access bits for resources beyond the first 32, used to fix the phantom resource bug. Initialized to NULL/0 and allocated as - // necessary by get_extra_resource_bits. Contains an array of groups of unsigned ints. There is one group per city (allocated lazily so you - // must use the getter) and the number of ints in each group depends on the number of resources defined in the scenario, one for every 32 - // after the first 32. - unsigned * extra_available_resources; - int extra_available_resources_capacity; // In number of cities. - - // These lists store interception events per-player during the interturn so we can clear the interception state on fighters that have done so - // at the beginning of their next turn. The point of this is to imitate the base game behavior where fighters that perform an interception are - // knocked out of the interception state. We can't knock them out immediately b/c that will prevent them from doing multiple interceptions per - // turn, so instead we record the event in these lists and reset their state later. - struct interceptor_reset_list { - struct interception { - int unit_id; - int x, y; - } * items; - int count; - int capacity; - } interceptor_reset_lists[32]; - - // Records the turn number on which each player has most recently founded a city. This is intended to be used for the temp settler perfume - // after founding feature so it may not be set if that feature is not activated or applicable. Defaults to -1. - int turn_no_of_last_founding_for_settler_perfume[32]; - - // Stores the byte offsets into the c3x_config struct of all boolean/integer config options, accessible using the options' names as - // strings. Used when reading in a config INI file. - struct table boolean_config_offsets; - struct table integer_config_offsets; - - // Maps unit types IDs to AI strategy indices (0 = offense, 1 = defense, 2 = artillery, etc.). If a unit type ID is in this table, that means - // it's one of several duplicate types created to spread multiple AI strategies out so each type has only one. - struct table unit_type_alt_strategies; - - // Stores a linked list of unit type duplicates. Maps unit type IDs to the next duplicate ID. Use list_unit_type_duplicates to get the list of - // the duplicates of a particular type as an array. - struct table unit_type_duplicates; - - // Tracks the number of "extra" defensive bombards units have performed, by their IDs. If the "blitz" special defensive bombard rule is - // activated, units with blitz get an extra chance to perform DB for each movement point they have beyond the first. - struct table extra_defensive_bombards; - - // Table mapping unit IDs to how many times that unit has airdropped on the current turn. This is used to prevent units from airdropping - // multiple times. That doesn't matter for the base game but stops the dont-end-turn-after-airdrop setting from letting units airdrop an - // unlimited number of times. - struct table airdrops_this_turn; - - // Stores city improvement bits for improvs beyond the first 256 - struct table extra_city_improvs; - - // These variables store the number of units of each type that each player has - int unit_type_count_init_bits; // Player bits tracking which unit type count tables have been initialized. - struct table unit_type_counts[32]; // One table per player. Each one maps unit type ids (ints) to counts (ints) - - // ========== - // } These fields are valid only after init_stackable_command_buttons has been called. { - // ========== - - struct sc_button_image_set { - Sprite imgs[4]; - } sc_button_image_sets[COUNT_STACKABLE_COMMANDS]; - - int sb_activated_by_button; // Gets set to 1 when the player clicks on the SB button so that perform_action_on_tile knows - // to do stack instead of regular bombard. This is necessary since the SB button actually just activates regular bombard. - // The proper way to implement the SB button would be to give it its own mode action but that's difficult to do because - // the existing mode actions are baked into the code. Implementing it this way I estimate is less fragile and requires - // less patching. The hard part is knowing when to clear this flag so that the player doesn't activate SB, cancel it, then - // activate regular bombard and get SB instead. One trick to make this easier is to look for the change of cursor away - // from the little bomb indicator instead of trying to intercept every relevant UI event. This flag is changed in these - // circumstances: - // (1) At init, the flag is cleared, of course. - // (2) Pressing the SB button sets the flag and pressing another unit command button clears it. - // (3) If handle_cursor_change_in_jgl is called and the main_screen_form's Mode_Action isn't (air) bombard, the flag - // is cleared. That covers every case of switching off SB mode except one, when the player presses a key to switch - // off of SB to regular bombard, that's what case (4) is for. - // (4) The flag is cleared when the player presses the B key or (if the unit is capable of precision strikes) the P key. - // One final complication, that I only discovered after trying to implement this, is that when clicking on the map with a - // mode action, the cursor is cleared before the action is carried out. So we have to intercept that map click as well for - // a total of 4 UI functions patched to make this damn button work. I doubt this is optimal but it works and I've wasted - // enough time on this already. That click interceptor sets a flag value of 2 to indicate this annoying state. - - // ========== - // } This field is only valid after init_disabled_command_buttons has been called and disabled_command_img_state equals IS_OK { - // ========== - - Sprite disabled_build_city_button_img; - - // ========== - // } This field is only valid after init_unit_rcm_icons has been called and unit_rcm_icon_state equals IS_OK { - // ========== - - // Sprites are stored together as sets, so the first COUNT_UNIT_RCM_ICONS elements are those from the first set, then the same number from the - // second set, etc. - Sprite unit_rcm_icons[COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS]; - - // ========== - // } These fields are valid only after init_tile_highlights as been called. { - // ========== - - Sprite tile_highlights[COUNT_TILE_HIGHLIGHTS]; - - // ========== - // } This one is valid only if init_mod_info_button_images has been called and mod_info_button_images_state equals IS_OK { - // ========== - - Sprite mod_info_button_images[3]; - - // ========== - // } This one is valid only if init_red_food_icon has been called and red_food_icon_state equals IS_OK { - // ========== - - Sprite red_food_icon; - - // ========== - // } These are valid only if init_large_minimap_frame has been called and large_minimap_frame_img_state equals IS_OK { - // ========== - - Sprite double_size_box_left_color_pcx, double_size_box_left_alpha_pcx; - - // ========== - // } These fields are temporary/situational { - // ========== - - int saved_road_movement_rate; // Valid when railroad movement limit is applied (limit_railroad_movement > 0) and BIC data has been loaded - int road_mp_cost; // The cost of moving one tile along a road, in MP. Valid after BIC data was loaded. - int railroad_mp_cost_per_move; // The cost of moving one tile along a railroad, in MP, per move available to the unit. This is measured per - // move since the cost of moving along a railroad is scaled by the total number of moves available to the - // unit. Valid after BIC data was loaded. - - int saved_barb_culture_group; // Valid when barb city capturing is enabled and BIC data has been loaded - - Leader * leader_param_for_patch_get_wonder_city_id; // Valid in patch_get_wonder_city_id when called from - // Leader_recompute_auto_improvements - - int show_popup_was_called; // Set to 1 in show_popup. Used in patch_Leader_can_do_worker_job to check if the replacement - // popup was shown. - - // Used to control trade screen scroll - int open_diplo_form_straight_to_trade; // Initialized to 0, gets set to 1 by patch_DiploForm_do_diplomacy to signal - // to patch_DiploForm_m68_Show_Dialog to open the diplo form straight into trade mode. - int trade_screen_scroll_to_id; // Set by patch_DiploForm_m82_handle_key_event to signal to do_diplomacy that the form - // was closed in order to scroll to the civ with the set ID. -1 indicates no scrolling. - Button * trade_scroll_button_left; // initialized to NULL - Button * trade_scroll_button_right; // initialized to NULL - Sprite * trade_scroll_button_images; // inited to NULL, array of 6 images: normal, rollover, and highlight for left & right - enum init_state trade_scroll_button_state; - int eligible_for_trade_scroll; - - char ask_gold_default[32]; - - // Set in patch_ai_choose_production, used by the various bits of injected code that run during the AI production choosing process. - City * ai_considering_production_for_city; - - // This variable stores what improvement or unit the AI is evaluating inside ai_choose_production. It gets set inside two call replacements, - // first inside the loop over improvements then again inside a loop over unit types. The var is used by the intercept consideration functions - // which run at the end of each loop iteration. - City_Order ai_considering_order; - int handling_ai_district_fallback; - - // Used in the code that adds additional info to the tile info box - bool tile_info_open; - int viewing_tile_info_x, viewing_tile_info_y; - - // Used in patch_Tile_m43_Get_field_30_for_city_loc_eval to change how the AI evaluates overlap between cities - int ai_evaling_city_loc_x, ai_evaling_city_loc_y; - int ai_evaling_city_field_30_get_counter; - - // Stores a list of the production options in a given city and the point value the AI would assign to each. The list is populated by - // rank_ai_production_options, items are added by record_improv_val which gets called by some code injected into one of the loops in - // ai_choose_production. These vars are initialized to zero. - struct ai_prod_valuation * ai_prod_valuations; - int count_ai_prod_valuations; - int ai_prod_valuations_capacity; - - // Used for generating resources from buildings and districts - struct extra_resource_tile * resource_tiles; - int count_resource_tiles; - int resource_tiles_capacity; - struct extra_resource_tile * got_resource_tile; - int saved_tile_count; // Stores the actual tile count in case p_bic_data->Map.TileCount was temporarily overwritten. Set to -1 when empty. - byte * mill_input_resource_bits; // Array of bits, one for each resource. Stores whether or not each one is an input to any mill. - - // Used for displaying yields from generated resources on the city screen - int tourism_icon_counter; // Incremented each time a tourism yield icon (normally commerce) is drawn. Reset between improvs. - int convert_displayed_tourism_to_food, convert_displayed_tourism_to_shields; // Number of commerce tourism icons to convert to food, shields - int combined_tourism_and_mill_commerce; // Number of commerce tourism icons to display inc. from mills, maybe negative - - int drawing_icons_for_improv_id; // Stores the improv ID whose icons we're drawing. -1 while not drawing. - - PCX_Image * resources_sheet; // Sprite sheet of resource icons, i.e. resources.pcx - - Sprite tile_already_worked_zoomed_out_sprite; // Valid only if init state is OK - - // Only for use by patch_City_Form_draw_yields_on_worked_tiles and patch_Sprite_draw_already_worked_tile_img - bool do_not_draw_already_worked_tile_img; - - // Stores the trade offer object being modified when the user right-clicks on a gold offer/ask on the trade table. Gets set by a special - // function call replacement (see apply_machine_code_edits for details). - TradeOffer * modifying_gold_trade; - - // Initialized to NULL and reset to NULL after Unit::bombard_tile returns. Gets set just before the call to Unit::play_bombard_fire_animation - // from inside bombard_tile. The value is the unit on the bombarded tile specifically targeted by the attack, if applicable. - Unit * bombard_stealth_target; - - // Set to zero when Unit::select_stealth_attack_target is called then checked inside in the call to PopupSelection::add_item and set to - // 1. This variable lets the add_item replacement function run special code for only the first item added, in order to insert an additional - // first option to cancel the stealth attack. - int added_any_stealth_target; - - // Initialized to zero. Temporarily set to 1 across a call to patch_Unit_select_stealth_attack_target to request that the selected target must - // be suitable for attack via bombardment. - int selecting_stealth_target_for_bombard; - - // Set in rand_int_to_dodge_city_aa and read immediately after in Unit_get_defense_to_dodge_city_aa. Allows us to determine whether the dodge - // roll was successful in order to popup the message. - int result_of_roll_to_dodge_city_aa; - - // Initialized to NULL. If set to non-NULL, the next call to show_map_message will consume that value and use it as the text on the - // message. Used to implement show_map_specific_text. - char const * map_message_text_override; - - // Initialized to NULL. If set to non-NULL, the next call to do_load_game will consume this value and use it as the file path of the game to - // load instead of opening the file picker. - char const * load_file_path_override; - - // A set of player bits indicating which players should see a replay of the AI's moves. Normally all zero, gets filled in by - // patch_perform_interturn_in_main_loop only when/as appropriate. As replays are played (in patch_show_movement_phase_popup), the - // corresponding bits are cleared. - int replay_for_players; - - // Used by patch_perform_interturn_in_main_loop to determine which players need to see the replay. Clear before interturn processing, then - // every time an AI unit moves onto or bombards a tile, any players that have vision on that tile will have their bit set in this var. - int players_saw_ai_unit; - - // Initialized to 0. If set to non-zero, the next call to do_load_game will consume the value and skip the intro popup. - int suppress_intro_after_load_popup; - - struct improv_id_list { - int * items; - int count; - int capacity; - } water_trade_improvs, air_trade_improvs, combat_defense_improvs; - - // Used by the fix for the barbarian diagonal bug - int barb_diag_patch_dy_fix; - - // Initialized to 0. If 1, barbarian activity is force activated b/c there are barb cities on the map that need to do production. - int force_barb_activity_for_cities; - - // Used as a stand-in for an actual tile where needed. In particular, this object is returned from various get_tile and tile_at replacements - // when we need to override the visibility data to implement hotseat shared vis. - Tile * dummy_tile; - - // When the game checks visibility for a tile, it accesses all four visibility fields with separate calls to Map::get_tile and/or tile_at. We - // replace the first call, maybe altering its return to implement shared visibility, cache the return in this variable, then re-use the cached - // value for the next three calls. - Tile * tile_returned_for_visibility_check; - - // Initialized to all -1. If set, the unit with the specified ID will always be the top unit displayed on the specified tile. If the unit is - // not on that tile, there is no effect. This is only intended to be used on a temporary basis. - struct unit_display_override { - int unit_id, tile_x, tile_y; - } unit_display_override; - - // Set in patch_Fighter_get_odds_for_main_combat_loop, read by patch_Unit_get_attack/defense_strength. - // Stores counter multipliers for the current combat. Active only during Fighter_get_combat_odds call. - struct { - bool active; - Unit * attacker; - Unit * defender; - int attacker_atk_pct; // Attacker attack multiplier (combines forward self-atk and reverse enemy-atk) - int defender_def_pct; // Defender defense multiplier (combines forward enemy-def and reverse self-def) - bool ignore_terrain; - } counter_combat_ctx; - - // Used to extract which unit (if any) exerted zone of control from within Fighter::apply_zone_of_control. - Unit * zoc_interceptor; - - // Set when Fighter::apply_zone_of_control is called to store the defending unit, used by the injected filter and Unit::move_to_adjacent_tile. - // Cleared at each call to move_to_adjacent_tile and by Unit::despawn. - Unit * zoc_defender; - - // Set to the bombarding unit while Unit::bombard_tile is running. NULL otherwise. - Unit * bombarding_unit; - - // Normally set to NULL. When a unit bombards a tile (the tile itself, not something on it), set to point to that unit during the call to - // Unit::attack_tile. Used to stop the unit from losing all of its movement if configured. - Unit * unit_bombard_attacking_tile; - - // Set to the coords of the tile being attacked while Unit::attack_tile is running, -1 otherwise. - int attacking_tile_x, attacking_tile_y; - - // Cleared to false when Fighter::apply_zone_of_control is called. The interceptor must be unfortified to ensure it plays its animation. If - // that happens, this flag is set so that apply_zone_of_control knows to refortify the unit after the ZoC process is done. - bool refortify_interceptor_after_zoc; - - // These flags are used to turn off lethal ZoC for units that capture an enemy on the tile they're moving into. Without this rule, the unit - // might get killed by ZoC but the captured units will remain on a tile that was never actually entered (that tile might have an enemy city - // for extra weirdness). Here's how it works: - // 1. The moving_unit_to_adjacent_tile flag is set when Unit::move_to_adjacent_tile is called. - // 2. If that flag is set and a unit is captured (detected by intercepting the calls to Leader::spawn_unit inside Unit::do_capture_units) - // then temporarily_disallow_lethal_zoc is set. - // 3. If temporar... is set, the code to filter ZoC interceptors acts as if lethal ZoC were turned off. - // 4. Both flags are cleared when Unit::move_to_adjacent_tile returns. - bool temporarily_disallow_lethal_zoc; - bool moving_unit_to_adjacent_tile; - - // Tracks temporary transport bypass when letting workers step onto coast tiles without a boat - Unit * coast_walk_unit; - bool coast_walk_transport_override; - enum UnitStateType coast_walk_prev_state; - int coast_walk_prev_container; - bool coast_walk_restore_goto_path; - int coast_walk_prev_path_len; - int coast_walk_prev_path_dest_x; - int coast_walk_prev_path_dest_y; - Unit * move_spend_override_unit; - int move_spend_override_value; - - // Used to record info about a defensive bomardment event during Fighter::fight. Gets set by Fighter::damage_by_defensive_bombardment and - // cleared when Fighter::fight returns. - struct defensive_bombard_event { - Unit * bombarder; - Unit * defender; - bool damage_done, defender_was_destroyed, saved_animation_setting; - } dbe; - - // Set to true IFF we're showing a replay of AI moves in hotseat mode - bool showing_hotseat_replay; - - // Set to true only during the first call to get_tile_occupier_id from Trade_Net::get_movement_cost. While this is set, we need to edit unit - // visibility to patch the submarine bug. - bool getting_tile_occupier_for_ai_pathfinding; - - bool running_on_wine; // Set to 1 IFF we're running in Wine, as opposed to actual Windows - - // gdi_plus.init_state is valid any time after patch_init_floating_point. All the other fields are only valid after set_up_gdi_plus has been - // called and gdi_plus.init_state equals IS_OK. - struct gdi_plus { - enum init_state init_state; - HMODULE module; - ULONG_PTR token; - void * gp_graphics; - - int (__stdcall * CreateFromHDC) (HDC hdc, void ** p_gp_graphics); - int (__stdcall * DeleteGraphics) (void * gp_graphics); - int (__stdcall * SetSmoothingMode) (void * graphics, int smoothing_mode); - int (__stdcall * SetPenDashStyle) (void * gp_pen, int dash_style); - int (__stdcall * CreatePen1) (unsigned int argb_color, float width, int gp_unit, void ** p_gp_pen); - int (__stdcall * DeletePen) (void * gp_pen); - int (__stdcall * DrawLineI) (void * gp_graphics, void * gp_pen, int x1, int y1, int x2, int y2); - } gdi_plus; - - // These variables track the states of some OpenGL parameters. They're updated whenever methods like OpenGLRenderer::set_color are called. - unsigned int ogl_color; - int ogl_line_width; - bool ogl_line_stipple_enabled; - - // Records how many units of each type we're going to upgrade to during an upgrade-all. This info will be used to impose the unit type limit - // during the upgrade. Keep in mind units all get upgraded from the same type but might end up as different types after upgrade-all. - struct penciled_in_upgrade { - int unit_type_id; - int count; - } * penciled_in_upgrades; - int penciled_in_upgrade_count; - int penciled_in_upgrade_capacity; - - // While in Leader::do_capture_city, the city in question is stored in this var. Otherwise it's NULL. - City * currently_capturing_city; - - // While a game is being saved or loaded, this variable points to the save file's MappedFile object. Otherwise it's NULL. - MappedFile * accessing_save_file; - - // Used in patch_work_simple_job. If a method sets this variable while that method is running then at the end it sets the given tile as LM. - Tile * lmify_tile_after_working_simple_job; - - // Reset to zero every time City_Form::draw is called. Incremented everything a strategic resource is drawn on the city screen. - int drawn_strat_resource_count; - - int * charmed_types_converted_to_ptw_arty; - int count_charmed_types_converted_to_ptw_arty; - int charmed_types_converted_to_ptw_arty_capacity; - - // While Unit::is_visible_to_civ is running, this var is set to the unit in question. Otherwise it's NULL. - Unit * checking_visibility_for_unit; - - // Normally false. When true, calls to bounce_trespassing_units won't kick out invisible units even if they're revealed. - bool do_not_bounce_invisible_units; - - // Normally false. When true, Unit::despawn also despawns any passenger units inside instead of making exceptions in some cases. - bool always_despawn_passengers; - - // Normally false. When true, calls to Unit::score_kill will not enslave. - bool do_not_enslave_units; - - // If limit_unit_loading_to_one_transport_per_turn is on, maps unit IDs to the ID of the transport unit they're tied to for the current turn. - struct table unit_transport_ties; - - // Initialized to NULL/0, used in patch_City_add_happiness_from_buildings - short * saved_improv_counts; - int saved_improv_counts_capacity; - - // Used to de-overlap specialist yield icons (option name fix_overlapping_specialist_yield_icons) - int specialist_icon_drawing_running_x; - - // Initialized to 0, used to draw multipage descriptions in the Civilopedia - struct civilopedia_multipage_description { - bool drawing_lines; - int line_count; - int shown_page; // zero-based - int last_page; // also zero-based - Civilopedia_Article * article; - Button * effects_btn; - Button * previous_btn; - } cmpd; - - // When expand_civilopedia_unit_stats is on, all the game's calls to draw_and_wrap_text to draw the second column of unit stats are - // intercepted to draw nothing and store their strings here. Then we possible add some entries of our own. The game will add up to 6 entries - // and we'll add up to 4. - char * pedia_unit_stats_second_column_strs[10]; - - // Day-Night cycle data - int current_day_night_cycle; - bool day_night_cycle_unstarted; // If current_day_night_cycle has not been set, f.e. because it's the first turn of a new game. - bool day_night_cycle_img_proxies_indexed; - LARGE_INTEGER last_day_night_cycle_update_time; - - struct table day_night_sprite_proxy_by_hour[24]; - - struct wonder_district_image_set { - Sprite img; - Sprite construct_img; - Sprite alt_dir_img; - Sprite alt_dir_construct_img; - } wonder_district_img_sets[MAX_WONDER_DISTRICT_TYPES]; - - struct natural_wonder_district_image_set { - Sprite img; - } natural_wonder_img_sets[MAX_NATURAL_WONDER_DISTRICT_TYPES]; - struct natural_wonder_label_draw_info { - int text_left; - int text_top; - int text_width; - int font_size; - char const * text; - }; - - struct day_night_cycle_img_set - { - SpriteList Std_Terrain_Images[9]; - SpriteList LM_Terrain_Images[9]; - Sprite City_Images[80]; - Sprite Destroyed_City_Images[3]; - Sprite Resources[36]; - Sprite ResourcesShadows[36]; - Sprite Terrain_Buldings_Barbarian_Camp; - Sprite Terrain_Buldings_Mines; - Sprite Victory_Image; - Sprite Flood_Plains_Images[16]; - Sprite Fog_Of_War_Images[81]; - Sprite Polar_Icecaps_Images[32]; - Sprite Railroads_Images[272]; - Sprite Roads_Images[256]; - Sprite Minor_Roads_Images[256]; - Sprite Terrain_Buldings_Airfields[2]; - Sprite Terrain_Buldings_Airfields_Shadow[2]; - Sprite Terrain_Buldings_Camp[4]; - Sprite Terrain_Buldings_Fortress[4]; - Sprite Terrain_Buldings_Barricade[4]; - Sprite Goody_Huts_Images[8]; - Sprite Terrain_Buldings_Outposts[3]; - Sprite Terrain_Buldings_Outposts_Shadow[3]; - Sprite Pollution[25]; - Sprite Craters[25]; - Sprite Terrain_Buldings_Radar; - Sprite Terrain_Buldings_Radar_Shadow; - Sprite Tnt_Images[18]; - Sprite Waterfalls_Images[4]; - Sprite LM_Terrain[7]; - Sprite Marsh_Large[8]; - Sprite Marsh_Small[10]; - Sprite Volcanos_Images[16]; - Sprite Volcanos_Forests_Images[16]; - Sprite Volcanos_Jungles_Images[16]; - Sprite Volcanos_Snow_Images[16]; - Sprite Grassland_Forests_Large[8]; - Sprite Plains_Forests_Large[8]; - Sprite Tundra_Forests_Large[8]; - Sprite Grassland_Forests_Small[10]; - Sprite Plains_Forests_Small[10]; - Sprite Tundra_Forests_Small[10]; - Sprite Grassland_Forests_Pines[12]; - Sprite Plains_Forests_Pines[12]; - Sprite Tundra_Forests_Pines[12]; - Sprite Irrigation_Desert_Images[16]; - Sprite Irrigation_Plains_Images[16]; - Sprite Irrigation_Images[16]; - Sprite Irrigation_Tundra_Images[16]; - Sprite Grassland_Jungles_Large[8]; - Sprite Grassland_Jungles_Small[12]; - Sprite Mountains_Images[16]; - Sprite Mountains_Forests_Images[16]; - Sprite Mountains_Jungles_Images[16]; - Sprite Mountains_Snow_Images[16]; - Sprite Hills_Images[16]; - Sprite Hills_Forests_Images[16]; - Sprite Hills_Jungle_Images[16]; - Sprite Delta_Rivers_Images[16]; - Sprite Mountain_Rivers_Images[16]; - Sprite Territory_Images[8]; - Sprite LM_Mountains_Images[16]; - Sprite LM_Forests_Large_Images[8]; - Sprite LM_Forests_Small_Images[10]; - Sprite LM_Forests_Pines_Images[12]; - Sprite LM_Hills_Images[16]; - Sprite District_Images[COUNT_DISTRICT_TYPES][MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [district][variant][era][column] - Sprite Abandoned_District_Image; - Sprite Abandoned_Maritime_District_Image; - struct wonder_district_image_set Wonder_District_Images[MAX_WONDER_DISTRICT_TYPES]; - struct natural_wonder_district_image_set Natural_Wonder_Images[MAX_NATURAL_WONDER_DISTRICT_TYPES]; - } day_night_cycle_imgs[24]; - - // Districts - enum init_state dc_img_state; - enum init_state dc_btn_img_state; - enum init_state dc_icons_img_state; - - struct district_config district_configs[COUNT_DISTRICT_TYPES]; - struct wonder_district_config wonder_district_configs[MAX_WONDER_DISTRICT_TYPES]; - struct natural_wonder_district_config natural_wonder_configs[MAX_NATURAL_WONDER_DISTRICT_TYPES]; - -struct district_image_set { - Sprite imgs[MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [variant][era][column] -} district_img_sets[COUNT_DISTRICT_TYPES]; - Sprite abandoned_district_img; - Sprite abandoned_maritime_district_img; - -struct district_button_image_set { - Sprite imgs[4]; -} district_btn_img_sets[COUNT_DISTRICT_TYPES]; - - // Building ID keys -> district ID. If a building ID is present in the - // table that means that building can only be built if there is a corresponding district is present in the city radius. - struct table district_building_prereqs; - - // Tile pointer IDs -> district_instance pointer. Maps tiles to dynamically allocated - // district_instance structs tracking district type and state (UNDER_CONSTRUCTION or COMPLETED). - // For wonder districts, the wonder_info field tracks wonder-specific state (unused, reserved, completed, ruined), - // which city reserved/completed the wonder, and which wonder index is on this district. - struct table district_tile_map; - struct table named_tile_map; - - // Tracks per-turn airlift usage for aerodrome districts (tile pointer -> civ bitmask). - struct table aerodrome_airlift_usage; - - // Command ID keys -> district ID. Used to identify which district - // a unit command (e.g., build order) corresponds to. - struct table command_id_to_district_id; - - // Array of 32 tables (one per civ) of pending district requests keyed by city & district (values are struct pending_district_request pointers). - struct table city_pending_district_requests[32]; - - // City pointer keys -> improvement ID. Tracks which improvements (buildings/wonders) - // requiring districts a city has ordered to be built (pending district completion). - struct table city_pending_building_orders; - - // AI cache mapping city pointer keys -> AI_Order pointer. Stores the best feasible - // production order for AI cities to optimize decision-making. - struct table ai_best_feasible_orders; - - // String building/wonder name keys -> int building/improvement ID. - // Used to look up building IDs by their text names from the game data. - struct table building_name_to_id; - - struct district_infos { - int advance_prereq_ids[MAX_DISTRICT_DEPENDENTS]; // Tech IDs that enable the district (all required) - int advance_prereq_count; - int obsoleted_by_id; - int resource_prereq_ids[MAX_DISTRICT_DEPENDENTS]; - int resource_prereq_count; - int resource_prereq_on_tile_id; - int wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; - int wonder_prereq_count; - int natural_wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; - int natural_wonder_prereq_count; - int dependent_building_count; - int dependent_building_ids[MAX_DISTRICT_DEPENDENTS]; // Building types the district enables - } district_infos[COUNT_DISTRICT_TYPES]; - - // District tracking counters: total = special (hard-coded) + dynamic (from config/scenario) - // next_custom_dynamic_command_index assigns unique command IDs for custom dynamic commands - int district_count; - int special_district_count; - int dynamic_district_count; - int wonder_district_count; - int natural_wonder_count; - int next_custom_dynamic_command_index; - - // Distribution Hub tracking: records keyed by tile plus per-tile coverage counts; dirty/refresh flags - // control when totals are recalculated - struct table distribution_hub_records; - struct table distribution_hub_coverage_counts; - bool distribution_hub_totals_dirty; - bool distribution_hub_refresh_in_progress; - - // Distribution Hub UI sprites loaded from PCX files for rendering food/shield icons in city interface - // *_icons_remaining counters track how many icons to draw from each source (non-district, district, hub, corruption) - Sprite distribution_hub_shield_icon; - Sprite distribution_hub_corruption_icon; - Sprite distribution_hub_food_icon; - Sprite distribution_hub_eaten_food_icon; - Sprite distribution_hub_shield_icon_small; - Sprite distribution_hub_food_icon_small; - int non_district_shield_icons_remaining; - int corruption_shield_icons_remaining; - int district_shield_icons_remaining; - int distribution_hub_shield_icons_remaining; - int district_corruption_icons_remaining; - int distribution_hub_corruption_icons_remaining; - - // District UI sprites loaded from PCX files for rendering yield icons (science, commerce, shield, food, culture, happiness) - // Available in both regular and small sizes for different UI contexts in city interface - Sprite district_science_icon; - Sprite district_commerce_icon; - Sprite district_shield_icon; - Sprite district_corruption_icon; - Sprite district_food_icon; - Sprite district_food_eaten_icon; - Sprite district_happiness_icon_small; - Sprite district_shield_icon_small; - Sprite district_commerce_icon_small; - Sprite district_food_icon_small; - Sprite district_science_icon_small; - Sprite district_culture_icon_small; - Sprite district_unhappiness_icon_small; - Sprite district_negative_shield_icon_small; - Sprite district_negative_commerce_icon_small; - Sprite district_negative_food_icon_small; - Sprite district_negative_science_icon_small; - Sprite district_negative_culture_icon_small; - - // Guard to prevent recursive sharing when auto-adding buildings across cities - bool sharing_buildings_by_districts_in_progress; - - // Worker tracking: 32 tables (one per civ), each mapping unit_id -> district_worker_record pointer - struct table district_worker_tables[32]; - - // Natural Wonder labels: table mapping natural wonder name strings to their IDs, count of defined natural wonders, - struct table natural_wonder_name_to_id; - - struct ai_candidate_bridge_or_canal_entry * ai_candidate_bridge_or_canals; - int ai_candidate_bridge_or_canals_count; - int ai_candidate_bridge_or_canals_capacity; - bool ai_candidate_bridge_or_canals_initialized; - - // City work radius highlighting: flag to enable/disable, table mapping tile pointers to highlight_level for visual feedback - bool highlight_city_radii; - struct table highlighted_city_radius_tile_pointers; - - // Initialized to 0. Every time Main_Screen_Form::m82_handle_key_event receives an event with is_down == 0, the virtual key code is prepended - // to this list. - int last_main_screen_key_up_events[5]; - - // Stores the parameters to Unit::can_load while it's running, NULL otherwise. - Unit * can_load_transport, * can_load_passenger; - - // Current tile being rendered in Map_Renderer_m19_Draw_Tile_by_XY_and_Flags. For use within various Map_Renderer::impl_m*_Draw_* functions. Nulled out after the render function is complete - Tile * current_render_tile; - struct district_instance * current_render_tile_district; - int current_render_tile_x, current_render_tile_y; - - // Used in patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp and so on for flagging whether to draw forests over roads on the tile being rendered - bool draw_forests_over_roads_on_tile; - - // Set to true once the auto-build process for the Great Wall is complete to avoid running it again - enum great_wall_auto_build_state great_wall_auto_build; - Tile * focused_tile; - - // Stores the improve ID currently being evaluated inside patch_City_can_build_improvement. - int current_evaluating_improve_id; - - // Stores the index in the list of target civs currently being drawn on the espionage form. Used to replace the civ name with its era-specific alias. - int espionage_form_drawing_target_index; - - // Tracks information about the last unit that was selected. These fields are updated when a new unit is selected or when the selected unit - // moves or is destroyed. - struct { - int initial_x, initial_y; // Stores the unit's location when it was selected - int last_x, last_y, type_id; // Stores the unit's current or last available location and type id - Unit * ptr; // A pointer to the unit, may be NULL if the unit was destroyed - } last_selected_unit; - - // Maps unit IDs to the level at which they are waiting. Units with lower levels move first. Units that have not been set to wait are not in the table. - struct table waiting_units; - - // Set to true when waiting_units has been initialized by loading from the save. Causes the game to skip clearing the table when setting up - // unit cycling for the turn. - bool have_loaded_waiting_units; - - // Used in patch_Unit_do_capture_units and patch_Unit_despawn - Unit ** extra_capture_despawns; - int count_extra_capture_despawns; - int extra_capture_despawns_capacity; - - // ========== - // } - // ========== -}; - -enum object_job { - OJ_DEFINE = 0, - OJ_INLEAD, // Patch this function with an inlead - OJ_REPL_VPTR, // Patch this function by replacing a pointer to it. The address column is the addr of the VPTR not the function itself. - OJ_REPL_CALL, // Patch a single function call. The address column is the addr of the call instruction, name refers to the new target function, type is not used. - OJ_REPL_VIS, // Patch a cluster of four function calls that make up a check of tile visibility. See implementation for details. - OJ_EXT_WALUP, // "EXTend Work Area LuP" Patch a jump instruction at the end of a "lup" (loop) over a city's workable area to extend it - OJ_IGNORE -}; - -struct civ_prog_object { - enum object_job job; - int addr; - char const * name; - char const * type; -}; +#include + +#define NOVIRTUALKEYCODES // Keycodes defined in Civ3Conquests.h instead +#include "windows.h" + +typedef unsigned char byte; + +// Use fastcall as substitute for thiscall because TCC doesn't recognize thiscall +#define __fastcall __attribute__((fastcall)) +#include "Civ3Conquests.h" + +#define MOD_VERSION 2700 +#define MOD_PREVIEW_VERSION 2 + +#define COUNT_TILE_HIGHLIGHTS 11 +#define MAX_BUILDING_PREREQS_FOR_UNIT 10 + +#define COUNT_SPECIAL_DISTRICT_TYPES 10 +#define USED_SPECIAL_DISTRICT_TYPES 11 +#define MAX_DYNAMIC_DISTRICT_TYPES 22 +#define COUNT_DISTRICT_TYPES (COUNT_SPECIAL_DISTRICT_TYPES + MAX_DYNAMIC_DISTRICT_TYPES) +#define MAX_WONDER_DISTRICT_TYPES 32 +#define MAX_NATURAL_WONDER_DISTRICT_TYPES 32 +#define MAX_DISTRICT_VARIANT_COUNT 5 +#define MAX_DISTRICT_ERA_COUNT 4 +#define MAX_DISTRICT_COLUMN_COUNT 10 +#define C3X_DISTRICT_COMMAND_BASE (-11000000) + +// Initialize to zero. Implementation is in common.c +struct table { + void * block; + size_t capacity_exponent; // Actual capacity is 1 << capacity_exponent + size_t len; +}; + +// Initialize to zero. Implementation in common.c +struct buffer { + byte * contents; + int length; + int capacity; +}; + +// A mill is a city improvement that spawns a resource. These are read from the "buildings_generating_resources" key in the config but are called +// "mills" internally for brevity. +enum mill_flag { + MF_LOCAL = 1, + MF_NO_TECH_REQ = 2, + MF_YIELDS = 4, + MF_SHOW_BONUS = 8, + MF_HIDE_NON_BONUS = 16 +}; +struct mill { + short improv_id; + short resource_id; + short flags; +}; + +#define ERA_ALIAS_LIST_CAPACITY 4 // Must not exceed 32 so we can store all genders as bits in an int + +// A list of per-era aliases for a civ's noun, adjective, or formal name. +struct civ_era_alias_list { + char * key; + char * aliases[ERA_ALIAS_LIST_CAPACITY]; +}; + +// A list of per-era aliases for a civ's leader's name, including genders and (optionally) titles. +struct leader_era_alias_list { + char * key; + char * aliases[ERA_ALIAS_LIST_CAPACITY]; + int gender_bits; // Gender of each alias. Like LeaderGender in the Race object, 0 for male and 1 for female. + char * titles[ERA_ALIAS_LIST_CAPACITY]; // Title for each alias. May be NULL. +}; + +struct unit_type_limit { + int per_civ; + int per_city; + int cities_per; +}; + +struct work_area_improvement { + short improv_id; + int work_area_radius_limit; + int work_area_radius_bonus; +}; + +enum retreat_rules { + RR_STANDARD = 0, + RR_NONE, + RR_ALL_UNITS, + RR_IF_FASTER, + RR_IF_NOT_SLOWER, + RR_IF_FAST_AND_NOT_SLOWER, +}; + +enum line_drawing_override { + LDO_NEVER = 0, + LDO_WINE, + LDO_ALWAYS +}; + +enum minimap_doubling_mode { + MDM_NEVER = 0, + MDM_HIGH_DEF, + MDM_ALWAYS +}; + +enum unit_cycle_search_criteria { + UCSC_STANDARD = 0, + UCSC_SIMILAR_NEAR_START, + UCSC_SIMILAR_NEAR_DESTINATION +}; + +enum no_ai_patrol_override { + NAPO_ZERO = 0, + NAPO_ONE, + NAPO_NONE +}; + +enum barbarian_activity_override { + BAO_NONE = -2, + + // The values for these levels must match what the game uses internally for Map.World.Final_Barbarians_Activity + BAO_NO_BARBARIANS = -1, + BAO_SEDENTARY = 0, + BAO_ROAMING = 1, + BAO_RESTLESS = 2, + BAO_RAGING = 3, + BAO_RANDOM = 4 +}; + +enum special_defensive_bombard_rules { + SDBR_LETHAL = 1, + SDBR_NOT_INVISIBLE = 2, + SDBR_AERIAL = 4, + SDBR_BLITZ = 8, + SDBR_DOCKED_VS_LAND = 16, +}; + +enum special_zone_of_control_rules { + SZOCR_LETHAL = 1, + SZOCR_AERIAL = 2, + SZOCR_AMPHIBIOUS = 4, + SZOCR_NOT_FROM_INSIDE = 8, +}; + +enum land_transport_rules { + LTR_LOAD_ONTO_BOAT = 1, + LTR_JOIN_ARMY = 2, + LTR_NO_DEFENSE_FROM_INSIDE = 4, + LTR_NO_ESCAPE = 8, +}; + +enum special_helicopter_rules { + SHR_ALLOW_ON_CARRIERS = 1, + SHR_PASSENGER_AIRDROP = 2, + SHR_NO_DEFENSE_FROM_INSIDE = 4, + SHR_NO_ESCAPE = 8, +}; + +enum work_area_limit { + WAL_NONE = 0, + WAL_CULTURAL, + WAL_CULTURAL_MIN_2, + WAL_CULTURAL_OR_ADJACENT +}; + +enum day_night_cycle_mode { + DNCM_OFF = 0, + DNCM_TIMER, + DNCM_USER_TIME, + DNCM_EVERY_TURN, + DNCM_SPECIFIED +}; + +enum distribution_hub_yield_division_mode { + DHYDM_FLAT = 0, + DHYDM_SCALE_BY_CITY_COUNT +}; + +enum ai_distribution_hub_build_strategy { + ADHBS_AUTO = 0, + ADHBS_BY_CITY_COUNT +}; + +enum ai_auto_build_great_wall_strategy { + AAGWS_ALL_BORDERS = 0, + AAGWS_OTHER_CIV_BORDERED_ONLY +}; + +enum perfume_kind { + PK_PRODUCTION = 0, + PK_TECHNOLOGY, + PK_GOVERNMENT, + + COUNT_PERFUME_KINDS +}; + +struct unit_counter_group { + char * name; + int * type_ids; + int count_type_ids; +}; + +// Attacker/defender match modes +#define UCM_ANY -1 // * Any unit type +#define UCM_GROUP -2 // Match using the group_name field + +struct counter_rule { + // Attacker side + int attacker_match; // UnitTypeID, or UCM_ANY / UCM_GROUP + char * attacker_group; // Used when attacker_match == UCM_GROUP + + // Defender side + int defender_match; + char * defender_group; + + // Environment conditions (0 / false means no restriction) + unsigned int terrain_mask; // SquareTypes mask, 0 = no restriction + bool only_in_city; + int district_id; // -1 = no restriction + char * district_name; // Resolved after district configs are loaded + bool ignore_terrain; // true = set defender terrain defense to 0 + + // Effects (percent values, 100 = no change) + int self_atk_pct; + int self_def_pct; + int enemy_atk_pct; + int enemy_def_pct; +}; + +struct c3x_config { + bool enable_stack_bombard; + bool enable_disorder_warning; + bool allow_stealth_attack_against_single_unit; + bool show_detailed_city_production_info; + int limit_railroad_movement; + bool limited_railroads_work_like_fast_roads; + int limit_units_per_tile[3]; // Limits for land, sea, and air units respectively + bool exclude_cities_from_units_per_tile_limit; + struct table exclude_types_from_units_per_tile_limit; + bool enable_free_buildings_from_small_wonders; + bool enable_stack_unit_commands; + bool skip_repeated_tile_improv_replacement_asks; + bool autofill_best_gold_amount_when_trading; + int minimum_city_separation; + bool disallow_founding_next_to_foreign_city; + bool enable_trade_screen_scroll; + bool group_units_on_right_click_menu; + bool gray_out_units_on_menu_with_no_remaining_moves; + bool put_movement_icons_on_units_on_menu; + bool describe_states_of_units_on_menu; + int anarchy_length_percent; + bool show_golden_age_turns_remaining; + bool show_zoc_attacks_from_mid_stack; + bool show_armies_performing_defensive_bombard; + bool cut_research_spending_to_avoid_bankruptcy; + bool dont_pause_for_love_the_king_messages; + bool reverse_specialist_order_with_shift; + bool toggle_zoom_with_z_on_city_screen; + bool enable_mouse_wheel_zoom; + bool dont_give_king_names_in_non_regicide_games; + bool no_elvis_easter_egg; + bool disable_worker_automation; + bool enable_land_sea_intersections; + bool disallow_trespassing; + bool show_detailed_tile_info; + struct table perfume_specs[COUNT_PERFUME_KINDS]; // Each table maps strings to i31b's. Each i31b combines an amount and whether it's a percent + struct table building_unit_prereqs; // A mapping from int keys to int values. The keys are unit type IDs. If an ID is present as a key in the + // table that means that unit type has one or more prereq buildings. The associated value is either a + // pointer to a list of MAX_BUILDING_PREREQS_FOR_UNITS improvement IDs or a single encoded improv ID. The + // contents of the list are NOT encoded and unused slots store -1. Encoding an ID is done by left-shifting + // it one place then inserting a 1 in the LSB. This way encoded IDs can be told apart from list pointers + // by checking the LSB (1 => encoded improv ID, 0 => list pointer). + struct mill * mills; + int count_mills; + bool warn_about_unrecognized_names; + bool enable_ai_production_ranking; + bool enable_ai_city_location_desirability_display; + bool show_ai_city_location_desirability_if_settler; + bool zero_corruption_when_off; + bool disallow_land_units_from_affecting_water_tiles; + bool dont_end_units_turn_after_airdrop; + bool allow_airdrop_without_airport; + bool enable_negative_pop_pollution; + enum retreat_rules land_retreat_rules; + enum retreat_rules sea_retreat_rules; + bool allow_defensive_retreat_on_water; + struct table limit_defensive_retreat_on_water_to_types; // Table mapping unit type IDs to 1's; used as a hash set + int ai_multi_city_start; + int max_tries_to_place_fp_city; + int * ai_multi_start_extra_palaces; + int count_ai_multi_start_extra_palaces; + int ai_multi_start_extra_palaces_capacity; + bool promote_wonder_decorruption_effect; + bool allow_military_leaders_to_hurry_wonders; + bool allow_multiple_battle_created_units_per_player; + int ai_research_multiplier; + int ai_settler_perfume_on_founding; + int ai_settler_perfume_on_founding_duration; + bool aggressively_penalize_bankruptcy; + bool no_penalty_exception_for_agri_fresh_water_city_tiles; + bool suppress_hypertext_links_exceeded_popup; + bool indicate_non_upgradability_in_pedia; + bool show_message_after_dodging_sam; + bool include_stealth_attack_cancel_option; + bool intercept_recon_missions; + bool charge_one_move_for_recon_and_interception; + bool polish_precision_striking; + bool enable_stealth_attack_via_bombardment; + bool immunize_aircraft_against_bombardment; + bool replay_ai_moves_in_hotseat_games; + struct table ptw_arty_types; // Table mapping unit type IDs to 1's; used as a hash set + struct table can_bombard_only_sea_tiles; // Table mapping unit type IDs to 1's; used as a hash set + bool restore_unit_directions_on_game_load; + bool apply_grid_ini_setting_on_game_load; + bool charm_flag_triggers_ptw_like_targeting; + bool city_icons_show_unit_effects_not_trade; + bool ignore_king_ability_for_defense_priority; + bool show_untradable_techs_on_trade_screen; + bool disallow_useless_bombard_vs_airfields; + enum line_drawing_override draw_lines_using_gdi_plus; + bool compact_luxury_display_on_city_screen; + bool compact_strategic_resource_display_on_city_screen; + bool warn_when_chosen_building_would_replace_another; + bool do_not_unassign_workers_from_polluted_tiles; + bool do_not_make_capital_cities_appear_larger; + bool show_territory_colors_on_water_tiles_in_minimap; + bool convert_some_popups_into_online_mp_messages; + bool enable_debug_mode_switch; + bool accentuate_cities_on_minimap; + enum minimap_doubling_mode double_minimap_size; + bool allow_multipage_civilopedia_descriptions; + enum unit_cycle_search_criteria unit_cycle_search_criteria; + bool reformat_turns_remaining_on_domestic_advisor_screen; + bool expand_civilopedia_unit_stats; + bool enable_city_capture_by_barbarians; + bool share_visibility_in_hotseat; + bool share_wonders_in_hotseat; + bool allow_precision_strikes_against_tile_improvements; + bool dont_end_units_turn_after_bombarding_barricade; + bool remove_land_artillery_target_restrictions; + bool allow_bombard_of_other_improvs_on_occupied_airfield; + bool show_total_city_count; + bool strengthen_forbidden_palace_ocn_effect; + int extra_unit_maintenance_per_shields; + enum special_zone_of_control_rules special_zone_of_control_rules; + enum special_defensive_bombard_rules special_defensive_bombard_rules; + struct civ_era_alias_list * civ_era_alias_lists; + int count_civ_era_alias_lists; + struct leader_era_alias_list * leader_era_alias_lists; + int count_leader_era_alias_lists; + struct table unit_limits; // Maps unit type names (strings) to pointers to limit objects (struct unit_type_limit *) + bool allow_upgrades_in_any_city; + bool do_not_generate_volcanos; + bool do_not_pollute_impassable_tiles; + bool show_hp_of_stealth_attack_options; + bool exclude_invisible_units_from_stealth_attack; + bool exclude_passengers_from_stealth_attack; + bool convert_to_landmark_after_planting_forest; + int chance_for_nukes_to_destroy_max_one_hp_units; + bool allow_sale_of_aqueducts_and_hospitals; + bool no_cross_shore_detection; + int city_work_radius; + bool auto_zoom_city_screen_for_large_work_areas; + enum work_area_limit work_area_limit; + struct work_area_improvement * work_area_improvements; + int count_work_area_improvements; + int rebase_range_multiplier; + bool limit_unit_loading_to_one_transport_per_turn; + bool prevent_old_units_from_upgrading_past_ability_block; + bool introduce_all_human_players_at_start_of_hotseat_game; + bool allow_unload_from_army; + enum land_transport_rules land_transport_rules; + bool allow_adjacent_resources_of_different_types; + bool allow_corruption_in_capital; + int special_capital_decorruption_effect; + int luxury_randomized_appearance_rate_percent; + int tiles_per_non_luxury_resource; + bool no_land_anti_air_from_inside_naval_transport; + enum special_helicopter_rules special_helicopter_rules; + bool prevent_enslaving_by_bombardment; + int years_to_double_building_culture; + int tourism_time_scale_percent; + bool allow_sale_of_small_wonders; + enum no_ai_patrol_override override_no_ai_patrol; + enum barbarian_activity_override override_barbarian_activity_level_for_scenario_maps; + bool initialize_preplaced_scenario_leaders_as_mgls; + bool enable_unit_counters; + struct unit_counter_group * unit_counter_groups; + int count_unit_counter_groups; + struct counter_rule * counter_rules; + int count_counter_rules; + bool use_civ4_style_best_defender; + + bool enable_trade_net_x; + bool optimize_improvement_loops; + bool measure_turn_times; + + bool use_offensive_artillery_ai; + bool dont_escort_unflagged_units; + int ai_build_artillery_ratio; + int ai_artillery_value_damage_percent; + int ai_build_bomber_ratio; + bool replace_leader_unit_ai; + bool fix_ai_army_composition; + bool enable_pop_unit_ai; + bool enable_caravan_unit_ai; + int max_ai_naval_escorts; + int ai_worker_requirement_percent; + + bool remove_unit_limit; + bool remove_city_improvement_limit; + int city_limit; + bool remove_cap_on_turn_limit; + bool remove_era_limit; + + bool patch_submarine_bug; + bool patch_science_age_bug; + bool patch_pedia_texture_bug; + bool patch_blocked_disembark_freeze; + bool patch_houseboat_bug; + bool patch_intercept_lost_turn_bug; + bool patch_phantom_resource_bug; + bool patch_maintenance_persisting_for_obsolete_buildings; + bool patch_barbarian_diagonal_bug; + bool patch_disease_stopping_tech_flag_bug; + bool patch_division_by_zero_in_ai_alliance_eval; + bool patch_empty_army_movement; + bool patch_empty_army_combat_crash; + bool delete_off_map_ai_units; + bool fix_overlapping_specialist_yield_icons; + bool patch_premature_truncation_of_found_paths; + bool patch_zero_production_crash; + bool patch_ai_can_form_army_without_special_ability; + bool patch_ai_can_sacrifice_without_special_ability; + bool patch_crash_in_leader_unit_ai; + bool patch_failure_to_find_new_city_build; + bool patch_passengers_out_of_order_on_menu; + + bool prevent_autorazing; + bool prevent_razing_by_players; + + bool allow_extraterritorial_colonies; + int per_extraterritorial_colony_relation_penalty; + + bool draw_forests_over_roads_and_railroads; + + bool enable_named_tiles; + + char * aircraft_victory_animation; // NULL if set to "none" in config + + int day_night_cycle_mode; + int elapsed_minutes_per_day_night_hour_transition; + int fixed_hours_per_turn_for_day_night_cycle; + int pinned_hour_for_day_night_cycle; + + bool enable_natural_wonders; + bool add_natural_wonders_to_scenarios_if_none; + bool show_natural_wonder_name_on_map; + int minimum_natural_wonder_separation; + + bool enable_districts; + bool enable_neighborhood_districts; + bool enable_wonder_districts; + bool enable_distribution_hub_districts; + bool enable_aerodrome_districts; + bool enable_port_districts; + bool enable_bridge_districts; + bool enable_canal_districts; + bool enable_central_rail_hub_districts; + bool enable_energy_grid_districts; + bool enable_great_wall_districts; + + bool cities_with_mutual_district_receive_buildings; + bool cities_with_mutual_district_receive_wonders; + bool show_message_when_building_received_by_mutual_district; + bool show_message_when_building_lost_to_destroyed_district; + + bool air_units_use_aerodrome_districts_not_cities; + bool naval_units_use_port_districts_not_cities; + + int maximum_pop_before_neighborhood_needed; + int per_neighborhood_pop_growth_enabled; + int neighborhood_needed_message_frequency; + bool destroying_neighborhood_reduces_pop; + + bool completed_wonder_districts_can_be_destroyed; + bool destroyed_wonders_can_be_built_again; + + int distribution_hub_yield_division_mode; + int distribution_hub_food_yield_divisor; + int distribution_hub_shield_yield_divisor; + int ai_distribution_hub_build_strategy; + int ai_ideal_distribution_hub_count_per_100_cities; + int max_distribution_hub_count_per_100_cities; + int central_rail_hub_distribution_food_bonus_percent; + int central_rail_hub_distribution_shield_bonus_percent; + + bool workers_can_enter_coast; + bool expand_water_tile_checks_to_city_work_area; + int max_contiguous_bridge_districts; + int max_contiguous_canal_districts; + int ai_canal_eval_min_bisected_land_tiles; + int ai_bridge_canal_eval_block_size; + int ai_bridge_eval_lake_tile_threshold; + bool ai_can_replace_existing_districts_with_canals; + bool ai_builds_bridges; + bool ai_builds_canals; + + bool ai_defends_districts; + int ai_city_district_max_build_wait_turns; + + bool disable_great_wall_city_defense_bonus; + bool great_wall_districts_impassible_by_others; + bool auto_build_great_wall_around_territory; + char * great_wall_auto_build_wonder_name; + int great_wall_auto_build_wonder_improv_id; + int ai_auto_build_great_wall_strategy; + + bool enable_city_work_radii_highlights; +}; + +enum stackable_command { + SC_BOMBARD = 0, + SC_BOMB, + SC_FORTRESS, + SC_MINE, + SC_IRRIGATE, + SC_CHOP_FOREST, + SC_CHOP_JUNGLE, + SC_PLANT, + SC_CLEAN_POLLUTION, + SC_ROAD, + SC_RAILROAD, + SC_FORTIFY, + SC_UPGRADE, + SC_DISBAND, + COUNT_STACKABLE_COMMANDS +}; + +enum stackable_command_kind { + SCK_BOMBARD = 0, + SCK_TERRAFORM, + SCK_UNIT_MGMT, + COUNT_STACKABLE_COMMAND_KINDS +}; + +struct sc_button_info { + enum Unit_Command_Values command; + enum stackable_command_kind kind; + int tile_sheet_column, + tile_sheet_row; +} const sc_button_infos[COUNT_STACKABLE_COMMANDS] = { + /* Bombard */ { .command = UCV_Bombard , .kind = SCK_BOMBARD , .tile_sheet_column = 3, .tile_sheet_row = 1 }, + /* Bomb */ { .command = UCV_Bombing , .kind = SCK_BOMBARD , .tile_sheet_column = 5, .tile_sheet_row = 4 }, + /* Fortress */ { .command = UCV_Build_Fortress , .kind = SCK_TERRAFORM, .tile_sheet_column = 0, .tile_sheet_row = 3 }, + /* Mine */ { .command = UCV_Build_Mine , .kind = SCK_TERRAFORM, .tile_sheet_column = 1, .tile_sheet_row = 3 }, + /* Irrigate */ { .command = UCV_Irrigate , .kind = SCK_TERRAFORM, .tile_sheet_column = 2, .tile_sheet_row = 3 }, + /* Chop For. */ { .command = UCV_Clear_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 3, .tile_sheet_row = 3 }, + /* Chop Jun. */ { .command = UCV_Clear_Jungle , .kind = SCK_TERRAFORM, .tile_sheet_column = 4, .tile_sheet_row = 3 }, + /* Plant */ { .command = UCV_Plant_Forest , .kind = SCK_TERRAFORM, .tile_sheet_column = 5, .tile_sheet_row = 3 }, + /* Clean Pol. */ { .command = UCV_Clear_Pollution, .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 3 }, + /* Road */ { .command = UCV_Build_Road , .kind = SCK_TERRAFORM, .tile_sheet_column = 6, .tile_sheet_row = 2 }, + /* Railroad */ { .command = UCV_Build_Railroad , .kind = SCK_TERRAFORM, .tile_sheet_column = 7, .tile_sheet_row = 2 }, + /* Fortify */ { .command = UCV_Fortify , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 2, .tile_sheet_row = 0 }, + /* Upgrade */ { .command = UCV_Upgrade_Unit , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 7, .tile_sheet_row = 1 }, + /* Disband */ { .command = UCV_Disband , .kind = SCK_UNIT_MGMT, .tile_sheet_column = 3, .tile_sheet_row = 0 }, +}; + +enum init_state { + IS_UNINITED = 0, + IS_OK, + IS_INIT_FAILED +}; + +enum c3x_label { + CL_NEVER_COMPLETES = 0, + CL_HALTED, + CL_SURPLUS, + CL_SURPLUS_NONE, + CL_SURPLUS_NA, + CL_SB_TOOLTIP, + CL_CHOPPED, + CL_OFF, + CL_MOD_INFO_BUTTON_TEXT, + CL_VERSION, + CL_CONFIG_FILES_LOADED, + CL_CREATING_CITIES, + CL_MCS_FAILED_SANITY_CHECK, + CL_MCS_ADJACENT_CITIES, + CL_MCS_MISSING_CITIES, + CL_OBSOLETED_BY, + CL_NO_STEALTH_ATTACK, + CL_DODGED_SAM, + CL_PREVIEW, + CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP, + CL_TOTAL_CITIES, + + // Offense, Defense, Artillery, etc. + CL_FIRST_UNIT_STRAT, + CL_LAST_UNIT_STRAT = CL_FIRST_UNIT_STRAT + 19, + + // Unit actions for right-click menu + CL_IDLE, + CL_FORTIFIED, + CL_SENTRY, + CL_MINING, + CL_IRRIGATING, + CL_BUILDING_FORTRESS, + CL_BUILDING_ROAD, + CL_BUILDING_RAILROAD, + CL_PLANTING_FOREST, + CL_CLEARING_FOREST, + CL_CLEARING_WETLANDS, + CL_CLEARING_DAMAGE, + CL_BUILDING_AIRFIELD, + CL_BUILDING_RADAR_TOWER, + CL_BUILDING_OUTPOST, + CL_BUILDING_BARRICADE, + CL_BUILDING_COLONY, + CL_INTERCEPTING, + CL_MOVING, + CL_AUTOMATED, + CL_EXPLORING, + CL_BOMBARDING, + + // Generic "Building" phrase for Districts right-click menu + CL_BUILDING, + + // Districts-related texts + CL_REQUIRES, + CL_TO_GROW, + CL_DISTRICT_DESTROYED_BY_VOLCANO, + CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT, + CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD, + + CL_RECEIVED, + CL_FROM_SHARED, + CL_WITH, + + CL_APOSTROPHE_S, + CL_AND, + CL_OTHER_BUILDINGS_HAVE_BEEN, + CL_LOST_DUE_TO_DESTROYED, + + // Districts config mismatch checked on game load + CL_DISTRICT_ID, + CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW, + CL_DISTRICT_NAME_MISMATCH, + CL_SAVE_FILE_HAD, + CL_CURRENT_CONFIG_HAS_ONLY, + CL_WARNING_DISTRICTS_CONFIG_MISMATCH, + CL_MAY_BE_OTHER_ERRORS_AS_WELL, + CL_DISTRICTS_IN_SAVE_FILE, + CL_CURRENTLY_CONFIGURED_DISTRICTS, + + // Tile naming + CL_NAME_TILE, + CL_RENAME_TILE, + + // "Action" for passenger units + CL_TRANSPORTED, + + CL_IN_STATE_27, + CL_IN_STATE_28, + CL_IN_STATE_29, + CL_IN_STATE_30, + CL_IN_STATE_33, + + // For unit stats on Civilopedia + CL_HP_BONUS, + CL_WORKER_STRENGTH, + + CL_AGRICULTURAL, + CL_COMMERCIAL, + CL_EXPANSIONIST, + CL_INDUSTRIOUS, + CL_MILITARISTIC, + CL_RELIGIOUS, + CL_SCIENTIFIC, + CL_SEAFARING, + + COUNT_C3X_LABELS +}; + +struct worker_job_and_location { + enum Worker_Jobs job; + int tile_x, tile_y; +}; + +struct ai_prod_valuation { + int order_type; + int order_id; + int point_value; +}; + +enum unit_rcm_icon { + URCMI_UNMOVED = 0, + URCMI_MOVED_CAN_ATTACK, + URCMI_MOVED_NO_ATTACK, + URCMI_CANT_MOVE, + + COUNT_UNIT_RCM_ICONS +}; + +enum unit_rcm_icon_set { + URCMIS_ATTACKER = 0, + URCMIS_NONCOMBAT, + URCMIS_BUSY_ATTACKER, + URCMIS_BUSY_NONCOMBAT, + + COUNT_UNIT_RCM_ICON_SETS +}; + +enum city_gain_reason { + CGR_FOUNDED = 0, + CGR_CONQUERED, + CGR_CONVERTED, // covers culture flips & bribes + CGR_TRADED, + CGR_POPPED_FROM_HUT, + CGR_PLACED_FOR_AI_RESPAWN, + CGR_PLACED_FOR_SCENARIO, + CGR_PLACED_FOR_AI_MULTI_CITY_START, +}; + +enum city_loss_reason { + CLR_DESTROYED = 0, // means city was razed for any reason (inc. by conqueror) + CLR_CONQUERED, + CLR_CONVERTED, // covers culture flips & bribes + CLR_TRADED +}; + +enum { + MAX_DISTRICT_DEPENDENTS = 64 +}; + +enum { + DEFAULT_DISTRICT_BUILDABLE_MASK = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain) | (1 << SQ_Hills) +}; + +enum { + MAX_DISTRICT_BONUS_ENTRIES = 16 +}; + +enum district_bonus_entry_type { + DBET_TILE = 0, + DBET_BUILDING = 1 +}; + +enum great_wall_auto_build_state { + GWABS_NOT_STARTED = 0, + GWABS_RUNNING, + GWABS_DONE +}; + +struct district_bonus_entry { + enum district_bonus_entry_type type; + int bonus; + enum SquareTypes tile_type; + int building_id; + char const * building_name; +}; + +struct district_bonus_list { + int count; + struct district_bonus_entry entries[MAX_DISTRICT_BONUS_ENTRIES]; +}; + +enum district_render_strategy { + DRS_BY_COUNT = 0, + DRS_BY_BUILDING = 1 +}; + +enum district_ai_build_strategy { + DABS_DISTRICT = 0, + DABS_TILE_IMPROVEMENT = 1 +}; + +struct district_config { + enum Unit_Command_Values command; + char const * name; + char const * display_name; + char const * tooltip; + char const * advance_prereqs[MAX_DISTRICT_DEPENDENTS]; + int advance_prereq_count; + char const * obsoleted_by; + char const * resource_prereqs[MAX_DISTRICT_DEPENDENTS]; + char const * resource_prereq_on_tile; + char const * dependent_improvements[MAX_DISTRICT_DEPENDENTS]; + char const * wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; + char const * natural_wonder_prereqs[MAX_DISTRICT_DEPENDENTS]; + char const * buildable_on_districts[MAX_DISTRICT_DEPENDENTS]; + char const * buildable_adjacent_to_districts[MAX_DISTRICT_DEPENDENTS]; + char const * img_paths[10]; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_without_removal_mask; + unsigned int buildable_on_overlays_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + bool allow_multiple; + bool vary_img_by_era; + bool vary_img_by_culture; + enum district_render_strategy render_strategy; + enum district_ai_build_strategy ai_build_strategy; + bool is_dynamic; + bool align_to_coast; + bool draw_over_resources; + bool allow_irrigation_from; + bool auto_add_road; + bool auto_add_railroad; + int custom_width; + int custom_height; + int x_offset; + int y_offset; + int resource_prereq_count; + int dependent_improvement_max_index; + int wonder_prereq_count; + int natural_wonder_prereq_count; + int buildable_on_district_count; + int buildable_adjacent_to_district_count; + int img_path_count; + int img_column_count; + bool has_img_column_count_override; + int btn_tile_sheet_column; + int btn_tile_sheet_row; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + struct district_bonus_list culture_bonus_extras; + struct district_bonus_list science_bonus_extras; + struct district_bonus_list food_bonus_extras; + struct district_bonus_list gold_bonus_extras; + struct district_bonus_list shield_bonus_extras; + struct district_bonus_list happiness_bonus_extras; + struct district_bonus_list defense_bonus_extras; + int defense_bonus_percent; + bool heal_units_in_one_turn; + bool impassible; + bool impassible_to_wheeled; + char const * generated_resource; + int generated_resource_id; + short generated_resource_flags; + int buildable_on_district_ids[MAX_DISTRICT_DEPENDENTS]; + int buildable_on_district_id_count; + bool has_buildable_on_districts; + int buildable_adjacent_to_district_ids[MAX_DISTRICT_DEPENDENTS]; + int buildable_adjacent_to_district_id_count; + bool has_buildable_adjacent_to; + bool has_buildable_adjacent_to_districts; + bool has_buildable_without_removal; + bool has_buildable_on_overlays; + bool has_buildable_adjacent_to_overlays; + bool has_buildable_on_rivers; + char const * buildable_by_civs[32]; + int buildable_by_civ_count; + bool has_buildable_by_civs; + int buildable_by_civ_traits_ids[8]; + int buildable_by_civ_traits_id_count; + bool has_buildable_by_civ_traits; + int buildable_by_civ_govs_ids[5]; + int buildable_by_civ_govs_id_count; + bool has_buildable_by_civ_govs; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_buildable_by_civ_cultures; + bool buildable_by_war_allies; + bool buildable_by_pact_allies; +}; + +struct wonder_district_config { + char const * wonder_name; + char const * img_path; + int index, + img_row, + img_column, + img_construct_row, + img_construct_column, + img_alt_dir_construct_row, + img_alt_dir_construct_column, + img_alt_dir_row, + img_alt_dir_column, + custom_width, + custom_height; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + char const * buildable_by_civs[32]; + int buildable_by_civ_count; + bool has_buildable_by_civs; + int buildable_by_civ_traits_ids[8]; + int buildable_by_civ_traits_id_count; + bool has_buildable_by_civ_traits; + int buildable_by_civ_govs_ids[5]; + int buildable_by_civ_govs_id_count; + bool has_buildable_by_civ_govs; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_buildable_by_civ_cultures; + bool enable_img_alt_dir; + bool is_dynamic; + bool has_buildable_adjacent_to; + bool has_buildable_adjacent_to_overlays; +}; + +enum square_type_extras { + SQ_INVALID = -1, + SQ_RIVER = SQ_Ocean + 1, + SQ_SNOW_VOLCANO, + SQ_SNOW_FOREST, + SQ_SNOW_MOUNTAIN +}; + +enum district_overlay_mask_bits { + DOM_MINE = 1u << 0, + DOM_IRRIGATION = 1u << 1, + DOM_FORTRESS = 1u << 2, + DOM_BARRICADE = 1u << 3, + DOM_OUTPOST = 1u << 4, + DOM_RADAR_TOWER = 1u << 5, + DOM_JUNGLE = 1u << 6, + DOM_FOREST = 1u << 7, + DOM_SWAMP = 1u << 8, + DOM_RIVER = 1u << 9, + DOM_AIRFIELD = 1u << 10 +}; + +struct natural_wonder_district_config { + char const * name; + char const * img_path; + enum SquareTypes terrain_type; + enum SquareTypes adjacent_to; + enum direction adjacency_dir; + int index; + int img_row; + int img_column; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + bool impassible; + bool impassible_to_wheeled; + bool is_dynamic; +}; + +struct natural_wonder_candidate { + Tile * tile; + short x, y; +}; + +struct natural_wonder_candidate_list { + struct natural_wonder_candidate * entries; + int count; + int capacity; +}; + +struct wonder_location { + short x; + short y; +}; + +const struct district_config special_district_defaults[USED_SPECIAL_DISTRICT_TYPES] = { + { + .command = UCV_Build_Neighborhood, .name = "Neighborhood", .tooltip = "Build Neighborhood", .display_name = "Neighborhood", + .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = true, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {"Neighborhood_AMER.pcx", "Neighborhood_EURO.pcx", "Neighborhood_ROMAN.pcx", "Neighborhood_MIDEAST.pcx", "Neighborhood_ASIAN.pcx"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 5, .img_column_count = 4, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, + .culture_bonus = 1, .science_bonus = 1, .food_bonus = 0, .gold_bonus = 1, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 25, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + + }, + { + .command = UCV_Build_WonderDistrict, .name = "Wonder District", .tooltip = "Build Wonder District", .display_name = "Wonder District", + .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {"WonderDistrict.pcx"}, + .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Coast) | (1 << SQ_Mountains)), + .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 1, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + + }, + { + .command = UCV_Build_DistributionHub, .name = "Distribution Hub", .tooltip = "Build Distribution Hub", .display_name = "Distribution Hub", + .advance_prereqs = {"Construction"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {"DistributionHub.pcx"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 1, .img_column_count = 1, .btn_tile_sheet_column = 2, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + + }, + { + .command = UCV_Build_Aerodrome, .name = "Aerodrome", .tooltip = "Build Aerodrome", .display_name = "Aerodrome", + .advance_prereqs = {"Flight"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 1, + .img_paths = {"Aerodrome.pcx"}, .dependent_improvements = {"Airport"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 1, .img_column_count = 2, .btn_tile_sheet_column = 3, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = -1, .name = "Natural Wonder", .tooltip = NULL, .display_name = "Natural Wonder", + .advance_prereqs = {0}, .advance_prereq_count = 0, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, .dependent_improvements = {0}, + .img_paths = {0}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, + .img_path_count = 0, .img_column_count = 0, .btn_tile_sheet_column = 0, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_Port, .name = "Port", .tooltip = "Build Port", .display_name = "Port", + .advance_prereqs = {"Map Making"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 2, .align_to_coast = true, + .img_paths = {"Port_NW.pcx", "Port_NE.pcx", "Port_SE.pcx", "Port_SW.pcx"}, .dependent_improvements = {"Harbor", "Commercial Dock"}, + .buildable_square_types_mask = (1 << SQ_Coast), + .img_path_count = 4, .img_column_count = 4, .btn_tile_sheet_column = 4, .btn_tile_sheet_row = 0, .align_to_coast = true, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_CentralRailHub, .name = "Central Rail Hub", .tooltip = "Build Central Rail Hub", .display_name = "Central Rail Hub", + .advance_prereqs = {"Steam Power"}, .advance_prereq_count = 1, .resource_prereqs = {"Iron", "Coal"}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 2, .dependent_improvement_max_index = 0, + .img_paths = {"CentralRailHub_AMER.pcx", "CentralRailHub_EURO.pcx", "CentralRailHub_ROMAN.pcx", "CentralRailHub_MIDEAST.pcx", "CentralRailHub_ASIAN.pcx"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .auto_add_road = true, .auto_add_railroad = true, + .img_path_count = 5, .img_column_count = 2, .btn_tile_sheet_column = 5, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_EnergyGrid, .name = "Energy Grid", .tooltip = "Build Energy Grid", .display_name = "Energy Grid", + .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 4, + .img_paths = {"EnergyGrid.pcx"}, .dependent_improvements = {"Coal Plant", "Hydro Plant", "Nuclear Plant", "Solar Plant"}, + .buildable_square_types_mask = DEFAULT_DISTRICT_BUILDABLE_MASK, .custom_height = 84, + .img_path_count = 1, .img_column_count = 5, .btn_tile_sheet_column = 6, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 2, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_Bridge, .name = "Bridge", .tooltip = "Build Bridge", .display_name = "Bridge", + .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, + .img_paths = {"Bridge.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, + .buildable_square_types_mask = (1 << SQ_Coast), .auto_add_road = true, + .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 7, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_Canal, .name = "Canal", .tooltip = "Build Canal", .display_name = "Canal", + .advance_prereqs = {"Industrialization"}, .advance_prereq_count = 1, .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = true, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, + .img_paths = {"Canal.pcx"}, .dependent_improvements = {0}, .custom_width = 176, .custom_height = 112, .y_offset = 24, .x_offset = 0, + .buildable_square_types_mask = (1 << SQ_Desert) | (1 << SQ_Plains) | (1 << SQ_Grassland) | (1 << SQ_Tundra) | (1 << SQ_FloodPlain), + .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 8, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 0, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + }, + { + .command = UCV_Build_GreatWall, .name = "Great Wall", .tooltip = "Build Great Wall", .display_name = "Great Wall", + .advance_prereqs = {0}, .advance_prereq_count = 0, .obsoleted_by = "Metallurgy", .resource_prereqs = {0}, .resource_prereq_on_tile = NULL, .allow_multiple = true, .vary_img_by_era = false, .vary_img_by_culture = false, .is_dynamic = false, .resource_prereq_count = 0, .dependent_improvement_max_index = 0, + .img_paths = {"GreatWall.pcx"}, .dependent_improvements = {0}, .custom_height = 88, .wonder_prereqs = {"The Great Wall"}, .wonder_prereq_count = 1, + .buildable_square_types_mask = (unsigned int)(DEFAULT_DISTRICT_BUILDABLE_MASK | (1 << SQ_Mountains) | (1 << SQ_Forest) | (1 << SQ_Swamp) | (1 << SQ_Jungle) | (1 << SQ_Volcano)), .draw_over_resources = true, + .img_path_count = 1, .img_column_count = 9, .btn_tile_sheet_column = 9, .btn_tile_sheet_row = 0, + .culture_bonus = 0, .science_bonus = 0, .food_bonus = 0, .gold_bonus = 0, .shield_bonus = 0, .happiness_bonus = 0, .defense_bonus_percent = 50, + .generated_resource = NULL, .generated_resource_id = -1, .generated_resource_flags = 0 + } +}; + +struct parsed_district_definition { + char * name; + char * display_name; + char * tooltip; + char * advance_prereqs[5]; + int advance_prereq_count; + char * obsoleted_by; + char * resource_prereqs[5]; + char * resource_prereq_on_tile; + char * dependent_improvements[5]; + char * wonder_prereqs[5]; + char * natural_wonder_prereqs[5]; + char * buildable_on_districts[5]; + char * buildable_adjacent_to_districts[5]; + char * img_paths[5]; + int resource_prereq_count; + int dependent_improvement_max_index; + int wonder_prereq_count; + int natural_wonder_prereq_count; + int buildable_on_district_count; + int buildable_adjacent_to_district_count; + int img_path_count; + int img_column_count; + bool allow_multiple; + bool vary_img_by_era; + bool vary_img_by_culture; + enum district_render_strategy render_strategy; + enum district_ai_build_strategy ai_build_strategy; + bool align_to_coast; + bool draw_over_resources; + bool allow_irrigation_from; + bool auto_add_road; + bool auto_add_railroad; + bool impassible; + bool impassible_to_wheeled; + int custom_width; + int custom_height; + int x_offset; + int y_offset; + int btn_tile_sheet_column; + int btn_tile_sheet_row; + int defense_bonus_percent; + bool heal_units_in_one_turn; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + struct district_bonus_list culture_bonus_extras; + struct district_bonus_list science_bonus_extras; + struct district_bonus_list food_bonus_extras; + struct district_bonus_list gold_bonus_extras; + struct district_bonus_list shield_bonus_extras; + struct district_bonus_list happiness_bonus_extras; + struct district_bonus_list defense_bonus_extras; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_without_removal_mask; + unsigned int buildable_on_overlays_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + char * buildable_by_civs[32]; + int buildable_by_civ_count; + bool buildable_by_war_allies; + bool buildable_by_pact_allies; + bool has_name; + bool has_tooltip; + bool has_advance_prereqs; + bool has_obsoleted_by; + bool has_resource_prereqs; + bool has_dependent_improvements; + bool has_wonder_prereqs; + bool has_natural_wonder_prereqs; + bool has_display_name; + bool has_img_paths; + bool has_img_column_count; + bool has_allow_multiple; + bool has_vary_img_by_era; + bool has_vary_img_by_culture; + bool has_render_strategy; + bool has_ai_build_strategy; + bool has_align_to_coast; + bool has_draw_over_resources; + bool has_custom_width; + bool has_custom_height; + bool has_x_offset; + bool has_y_offset; + bool has_btn_tile_sheet_column; + bool has_btn_tile_sheet_row; + bool has_defense_bonus_percent; + bool has_heal_units_in_one_turn; + bool has_culture_bonus; + bool has_science_bonus; + bool has_food_bonus; + bool has_gold_bonus; + bool has_shield_bonus; + bool has_happiness_bonus; + bool has_buildable_on; + bool has_buildable_adjacent_to; + bool has_buildable_without_removal; + bool has_buildable_on_overlays; + bool has_buildable_adjacent_to_overlays; + bool has_buildable_on_rivers; + bool has_resource_prereq_on_tile; + bool has_buildable_by_civs; + bool has_buildable_by_war_allies; + bool has_buildable_by_pact_allies; + char * generated_resource; + short generated_resource_flags; + bool has_generated_resource; + char * buildable_by_civ_traits[10]; + int buildable_by_civ_traits_count; + int buildable_by_civ_traits_ids[10]; + int buildable_by_civ_traits_id_count; + bool has_buildable_by_civ_traits; + char * buildable_by_civ_govs[10]; + int buildable_by_civ_govs_count; + int buildable_by_civ_govs_ids[32]; + int buildable_by_civ_govs_id_count; + bool has_buildable_by_civ_govs; + char * buildable_by_civ_cultures[5]; + int buildable_by_civ_cultures_count; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_buildable_by_civ_cultures; + bool has_buildable_on_districts; + bool has_buildable_adjacent_to_districts; + bool has_allow_irrigation_from; + bool has_auto_add_road; + bool has_auto_add_railroad; + bool has_impassible; + bool has_impassible_to_wheeled; +}; + +struct parsed_wonder_definition { + char * name; + char * img_path; + int img_row; + int img_column; + int img_construct_row; + int img_construct_column; + int img_alt_dir_construct_row; + int img_alt_dir_construct_column; + int img_alt_dir_row; + int img_alt_dir_column; + int custom_width; + int custom_height; + bool enable_img_alt_dir; + unsigned int buildable_square_types_mask; + unsigned int buildable_adjacent_to_square_types_mask; + unsigned int buildable_adjacent_to_overlays_mask; + bool buildable_on_rivers; + bool buildable_adjacent_to_allows_city; + char * buildable_by_civs[32]; + int buildable_by_civ_count; + char * buildable_by_civ_traits[10]; + int buildable_by_civ_traits_count; + int buildable_by_civ_traits_ids[10]; + int buildable_by_civ_traits_id_count; + char * buildable_by_civ_govs[10]; + int buildable_by_civ_govs_count; + int buildable_by_civ_govs_ids[32]; + int buildable_by_civ_govs_id_count; + char * buildable_by_civ_cultures[5]; + int buildable_by_civ_cultures_count; + int buildable_by_civ_cultures_ids[5]; + int buildable_by_civ_cultures_id_count; + bool has_name; + bool has_img_path; + bool has_img_row; + bool has_img_column; + bool has_img_construct_row; + bool has_img_construct_column; + bool has_img_alt_dir_construct_row; + bool has_img_alt_dir_construct_column; + bool has_img_alt_dir_row; + bool has_img_alt_dir_column; + bool has_custom_width; + bool has_custom_height; + bool has_enable_img_alt_dir; + bool has_buildable_on; + bool has_buildable_adjacent_to; + bool has_buildable_adjacent_to_overlays; + bool has_buildable_on_rivers; + bool has_buildable_by_civs; + bool has_buildable_by_civ_traits; + bool has_buildable_by_civ_govs; + bool has_buildable_by_civ_cultures; +}; + +struct parsed_natural_wonder_definition { + char * name; + char * img_path; + enum SquareTypes terrain_type; + enum SquareTypes adjacent_to; + enum direction adjacency_dir; + int img_row; + int img_column; + int culture_bonus; + int science_bonus; + int food_bonus; + int gold_bonus; + int shield_bonus; + int happiness_bonus; + bool impassible; + bool impassible_to_wheeled; + bool has_name; + bool has_img_path; + bool has_img_row; + bool has_img_column; + bool has_terrain_type; + bool has_adjacent_to; + bool has_adjacency_dir; + bool has_culture_bonus; + bool has_science_bonus; + bool has_food_bonus; + bool has_gold_bonus; + bool has_shield_bonus; + bool has_happiness_bonus; + bool has_impassible; + bool has_impassible_to_wheeled; +}; + +struct scenario_district_entry { + int tile_x; + int tile_y; + int has_coordinates; + char * district_name; + int has_district_name; + char * wonder_city_name; + int has_wonder_city; + char * wonder_name; + int has_wonder_name; +}; + +struct scenario_named_tile_entry { + int tile_x; + int tile_y; + int has_coordinates; + char * name; + int has_name; +}; + +struct distribution_hub_record { + Tile * tile; + int tile_x; + int tile_y; + int civ_id; + int food_yield; + int shield_yield; + int raw_food_yield; + int raw_shield_yield; +}; + +struct ai_best_feasible_order { + City_Order order; + int value; +}; + +struct district_building_prereq_list { + int count; + int district_ids[MAX_DISTRICT_DEPENDENTS]; +}; + +struct pending_district_request { + City * city; + int city_id; + int civ_id; + int district_id; + int assigned_worker_id; + int target_x; + int target_y; + int worker_assigned_turn; +}; + +struct ai_candidate_bridge_or_canal_entry { + int district_id; + short owner_civ_id; + short * tile_x; + short * tile_y; + short tile_count; + short assigned_tile_index; + int assigned_worker_id; + bool completed; + struct pending_district_request pending_req; + int tile_capacity; +}; + +struct district_worker_record { + Unit * worker; + int unit_id; + int continent_id; + struct pending_district_request * pending_req; +}; + +enum wonder_district_state { + WDS_UNUSED = 0, // Wonder district built, no wonder assigned + WDS_UNDER_CONSTRUCTION, // Reserved by a city for wonder construction + WDS_COMPLETED, // Wonder completed on this district + WDS_RUINED // (Future) Wonder was destroyed +}; + +struct wonder_district_info { + enum wonder_district_state state; + City * city; // City that reserved/completed (NULL if unused) + int city_id; + int wonder_index; // Wonder index (-1 if unused/reserved, valid if completed) +}; + +struct natural_wonder_district_info { + int natural_wonder_id; +}; + +enum district_state { + DS_UNDER_CONSTRUCTION = 0, + DS_COMPLETED = 1 +}; + +struct district_instance { + enum district_state state; + int district_id; // Index into district_configs array + int tile_x; + int tile_y; + int built_by_civ_id; + int completed_turn; + struct wonder_district_info wonder_info; // Only used if district_id is a wonder district + struct natural_wonder_district_info natural_wonder_info; // Only used if district_id is a natural wonder district +}; + +enum extra_resource_tile_type { + ERT_MILL_RESOURCE = 0, + ERT_DISTRICT_RESOURCE +}; + +struct extra_resource_tile { + Tile * tile; + enum extra_resource_tile_type type; + union { + struct { + City * city; + struct mill * mill; + } mill_info; + struct { + struct district_instance * inst; + struct district_config * cfg; + } district_info; + }; +}; + +struct named_tile_entry { + int tile_x; + int tile_y; + char name[100]; +}; + +struct highlighted_city_radius_tile_info { + int highlight_level; +}; + +struct injected_state { + // ========== + // These fields are valid at any time in the injected code because they're set by the patcher { + // ========== + + int mod_version; + // "mod relative directory" is the mod dir relative to the conquests dir. Usually it's "C3X_Rn" but it might be deeper. + // It must be non-empty and must not have an ending backslash. + char mod_rel_dir[MAX_PATH]; + + enum init_state sc_img_state; + enum init_state tile_highlight_state; + enum init_state mod_info_button_images_state; + enum init_state disabled_command_img_state; + enum init_state unit_rcm_icon_state; + enum init_state red_food_icon_state; + enum init_state distribution_hub_icons_img_state; + enum init_state tile_already_worked_zoomed_out_sprite_init_state; + enum init_state day_night_cycle_img_state; + enum init_state large_minimap_frame_img_state; + + // ========== + // } These fields are valid at any time after patch_init_floating_point runs (which is at the program launch). { + // ========== + + struct c3x_config base_config; + + // Windows modules + HMODULE kernel32; + HMODULE user32; + HMODULE msvcrt; + HMODULE msimg32; + + // Win32 API functions + WINBOOL (WINAPI * VirtualProtect) (LPVOID, SIZE_T, DWORD, PDWORD); + WINBOOL (WINAPI * CloseHandle) (HANDLE); + HANDLE (WINAPI * CreateFileA) (LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); + DWORD (WINAPI * GetFileSize) (HANDLE, LPDWORD); + WINBOOL (WINAPI * ReadFile) (HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); + HMODULE (WINAPI * LoadLibraryA) (LPCSTR); + BOOL (WINAPI * FreeLibrary) (HMODULE); + int (WINAPI * MultiByteToWideChar) (UINT, DWORD, LPCCH, int, LPWSTR, int); + int (WINAPI * WideCharToMultiByte) (UINT, DWORD, LPCWCH, int, LPSTR, int, LPCCH, LPBOOL); + int (WINAPI * GetLastError) (); + BOOL (WINAPI * QueryPerformanceCounter) (LARGE_INTEGER *); + BOOL (WINAPI * QueryPerformanceFrequency) (LARGE_INTEGER *); + void (WINAPI * GetLocalTime) (LPSYSTEMTIME); + + // Win32 funcs from user32.dll + int (WINAPI * MessageBoxA) (HWND, LPCSTR, LPCSTR, UINT); + + // Win32 funcs from Msimg32.dll + BOOL (WINAPI * TransparentBlt) (HDC, int, int, int, int, HDC, int, int, int, int, UINT); + + // C standard library functions + int (* snprintf) (char *, size_t, char const *, ...); + void * (* malloc) (size_t); + void * (* calloc) (size_t, size_t); + void * (* realloc) (void *, size_t); + void (* free) (void *); + long (* strtol) (char const *, char **, int); + float (* strtof) (char const *, char **); + int (* strcmp) (char const *, char const *); + int (* strncmp) (char const *, char const *, size_t); + int (* _stricmp) (char const *, char const *); + size_t (* strlen) (char const *); + char * (* strncpy) (char *, char const *, size_t); + char * (* strcpy) (char *, char const *); + char * (* strdup) (char const *); + char * (* strstr) (char const *, char const *); + void (* qsort) (void *, size_t, size_t, int (*) (void const *, void const *)); + int (* memcmp) (void const *, void const *, size_t); + void * (* memcpy) (void *, void const *, size_t); + void * (* memmove) (void *, void const *, size_t); + int (* tolower) (int); + int (* toupper) (int); + + Unit * sb_next_up; // The unit currently doing a stack bombard or NULL otherwise. Gets set to NULL if the unit is despawned. + + Trade_Net * trade_net; // Pointer to the trade net object. If it hasn't been moved by the mod, this equals p_original_trade_net. + int city_limit; // Stores the current actual city limit. Not necessarily the same as the stride of the trade net matrix or the config setting. + + enum init_state trade_net_addrs_load_state; + int * trade_net_addrs; + + HMODULE trade_net_x; + void (__stdcall * set_exe_version) (int); + void * (__stdcall * create_tnx_cache) (Map *); + void (__stdcall * destroy_tnx_cache) (void *); + void (__stdcall * set_up_before_building_network) (void *); + int (__stdcall * get_move_cost_for_sea_trade) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags, int neighbor_index, Trade_Net_Distance_Info * dist_info); + void (__stdcall * flood_fill_road_network) (void * tnx_cache, int from_x, int from_y, int civ_id); + bool (__stdcall * try_drawing_sea_trade_route) (Trade_Net * trade_net, void * tnx_cache, int from_x, int from_y, int to_x, int to_y, int civ_id, unsigned int flags); + + void * tnx_cache; // Cache object used by Trade Net X. Initially NULL, must be recreated every time a new map is loaded. + enum init_state tnx_init_state; + bool is_computing_city_connections; // Set to true only while Trade_Net::recompute_city_connections is running + bool keep_tnx_cache; + + // This flag gets set whenever a trade deal is signed or broken for a resource that's an input to a mill. It's necessary to call + // recompute_resources in that case since a mill may have been de/activated by the change. We can't call it right when the change happens as + // that can crash the game for reasons I don't completely understand. I believe it's because the recomputation can't be done while some other + // econ logic is running. Instead, we set this variable then recompute before obsolete data would be an issue. Specifically, this is done: + // - When any player or AI begins their production phase + // - When the player zooms to any city + // - When the player opens the shift + right-click production chooser menu + // - When the player visits any advisor + // - When the player selects any unit + bool must_recompute_resources_for_mill_inputs; + + bool is_placing_scenario_things; // Set to true only while Map::place_scenario_things is running + + bool paused_for_popup; // Set to true while a popup, map message, or the diplo screen is open + long long time_spent_paused_during_popup; // Tracks time spent waiting for the three things above + + // This variable is increased with the time elapsed during every call to Trade_Net::recompute_city_connections. Time is measured using + // Windows performance counter. + long long time_spent_computing_city_connections; + int count_calls_to_recompute_city_connections; + + long long time_spent_filling_roads; + + struct c3x_config current_config; + + // Keeps a record of all configs currently loaded. Useful to know. "name" is the file name for configs that come from files, which is all of + // them except for the base config, whose name is "(base)". + struct loaded_config_name { + char * name; + struct loaded_config_name * next; + } * loaded_config_names; + + char current_districts_config_path[MAX_PATH]; + + char mod_script_path[MAX_PATH]; + + char * c3x_labels[COUNT_C3X_LABELS]; + + int have_job_and_loc_to_skip; // 0 or 1 if the variable below has anything actionable in it. Gets cleared to 0 after every turn. + struct worker_job_and_location to_skip; + + struct table saved_code_areas; + + int * unit_menu_duplicates; // NULL initialized, allocated to an array of 0x100 ints when needed + bool named_tile_menu_active; + int named_tile_menu_tile_x; + int named_tile_menu_tile_y; + + // List of temporary ints. Initializes to NULL/0/0, used with functions "memoize" and "clear_memo" + int * memo; + int memo_len; + int memo_capacity; + + // Array mapping cultural neighbor indices to the standard indices that correspond to the same tiles. Generated at program start. + byte * cultural_ni_to_standard; + + // Array mapping standard neighbor indices to the smallest work radius that includes the corresponding tile. Ex., if a given n.i. corresponds + // to one of the adjacent tiles, maps to 1, if it's in the fat cross but not adjacent, maps to 2, and so forth, out into the extended area. + char ni_to_work_radius[256]; + + // The maximum number of tiles workable by cities including the city tile itself (21 under standard game rules). Updated whenever the + // city_work_radius config value gets changed. + int workable_tile_count; + + // The civ ID of the player from whose perspective we're currently showing city loc desirability, or -1 if none. Initialized to -1. + int city_loc_display_perspective; + + // These are all bit fields that run parallel to player bits. Each bit indicates whether or not that name was replaced with an era-specific + // version for that player. This allows us to tell the difference between custom names set by human players and replacements made by the mod. + int aliased_civ_noun_bits; + int aliased_civ_adjective_bits; + int aliased_civ_formal_name_bits; + int aliased_leader_name_bits; + int aliased_leader_title_bits; + + // Stores resource access bits for resources beyond the first 32, used to fix the phantom resource bug. Initialized to NULL/0 and allocated as + // necessary by get_extra_resource_bits. Contains an array of groups of unsigned ints. There is one group per city (allocated lazily so you + // must use the getter) and the number of ints in each group depends on the number of resources defined in the scenario, one for every 32 + // after the first 32. + unsigned * extra_available_resources; + int extra_available_resources_capacity; // In number of cities. + + // These lists store interception events per-player during the interturn so we can clear the interception state on fighters that have done so + // at the beginning of their next turn. The point of this is to imitate the base game behavior where fighters that perform an interception are + // knocked out of the interception state. We can't knock them out immediately b/c that will prevent them from doing multiple interceptions per + // turn, so instead we record the event in these lists and reset their state later. + struct interceptor_reset_list { + struct interception { + int unit_id; + int x, y; + } * items; + int count; + int capacity; + } interceptor_reset_lists[32]; + + // Records the turn number on which each player has most recently founded a city. This is intended to be used for the temp settler perfume + // after founding feature so it may not be set if that feature is not activated or applicable. Defaults to -1. + int turn_no_of_last_founding_for_settler_perfume[32]; + + // Stores the byte offsets into the c3x_config struct of all boolean/integer config options, accessible using the options' names as + // strings. Used when reading in a config INI file. + struct table boolean_config_offsets; + struct table integer_config_offsets; + + // Maps unit types IDs to AI strategy indices (0 = offense, 1 = defense, 2 = artillery, etc.). If a unit type ID is in this table, that means + // it's one of several duplicate types created to spread multiple AI strategies out so each type has only one. + struct table unit_type_alt_strategies; + + // Stores a linked list of unit type duplicates. Maps unit type IDs to the next duplicate ID. Use list_unit_type_duplicates to get the list of + // the duplicates of a particular type as an array. + struct table unit_type_duplicates; + + // Tracks the number of "extra" defensive bombards units have performed, by their IDs. If the "blitz" special defensive bombard rule is + // activated, units with blitz get an extra chance to perform DB for each movement point they have beyond the first. + struct table extra_defensive_bombards; + + // Table mapping unit IDs to how many times that unit has airdropped on the current turn. This is used to prevent units from airdropping + // multiple times. That doesn't matter for the base game but stops the dont-end-turn-after-airdrop setting from letting units airdrop an + // unlimited number of times. + struct table airdrops_this_turn; + + // Stores city improvement bits for improvs beyond the first 256 + struct table extra_city_improvs; + + // These variables store the number of units of each type that each player has + int unit_type_count_init_bits; // Player bits tracking which unit type count tables have been initialized. + struct table unit_type_counts[32]; // One table per player. Each one maps unit type ids (ints) to counts (ints) + + // ========== + // } These fields are valid only after init_stackable_command_buttons has been called. { + // ========== + + struct sc_button_image_set { + Sprite imgs[4]; + } sc_button_image_sets[COUNT_STACKABLE_COMMANDS]; + + int sb_activated_by_button; // Gets set to 1 when the player clicks on the SB button so that perform_action_on_tile knows + // to do stack instead of regular bombard. This is necessary since the SB button actually just activates regular bombard. + // The proper way to implement the SB button would be to give it its own mode action but that's difficult to do because + // the existing mode actions are baked into the code. Implementing it this way I estimate is less fragile and requires + // less patching. The hard part is knowing when to clear this flag so that the player doesn't activate SB, cancel it, then + // activate regular bombard and get SB instead. One trick to make this easier is to look for the change of cursor away + // from the little bomb indicator instead of trying to intercept every relevant UI event. This flag is changed in these + // circumstances: + // (1) At init, the flag is cleared, of course. + // (2) Pressing the SB button sets the flag and pressing another unit command button clears it. + // (3) If handle_cursor_change_in_jgl is called and the main_screen_form's Mode_Action isn't (air) bombard, the flag + // is cleared. That covers every case of switching off SB mode except one, when the player presses a key to switch + // off of SB to regular bombard, that's what case (4) is for. + // (4) The flag is cleared when the player presses the B key or (if the unit is capable of precision strikes) the P key. + // One final complication, that I only discovered after trying to implement this, is that when clicking on the map with a + // mode action, the cursor is cleared before the action is carried out. So we have to intercept that map click as well for + // a total of 4 UI functions patched to make this damn button work. I doubt this is optimal but it works and I've wasted + // enough time on this already. That click interceptor sets a flag value of 2 to indicate this annoying state. + + // ========== + // } This field is only valid after init_disabled_command_buttons has been called and disabled_command_img_state equals IS_OK { + // ========== + + Sprite disabled_build_city_button_img; + + // ========== + // } This field is only valid after init_unit_rcm_icons has been called and unit_rcm_icon_state equals IS_OK { + // ========== + + // Sprites are stored together as sets, so the first COUNT_UNIT_RCM_ICONS elements are those from the first set, then the same number from the + // second set, etc. + Sprite unit_rcm_icons[COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS]; + + // ========== + // } These fields are valid only after init_tile_highlights as been called. { + // ========== + + Sprite tile_highlights[COUNT_TILE_HIGHLIGHTS]; + + // ========== + // } This one is valid only if init_mod_info_button_images has been called and mod_info_button_images_state equals IS_OK { + // ========== + + Sprite mod_info_button_images[3]; + + // ========== + // } This one is valid only if init_red_food_icon has been called and red_food_icon_state equals IS_OK { + // ========== + + Sprite red_food_icon; + + // ========== + // } These are valid only if init_large_minimap_frame has been called and large_minimap_frame_img_state equals IS_OK { + // ========== + + Sprite double_size_box_left_color_pcx, double_size_box_left_alpha_pcx; + + // ========== + // } These fields are temporary/situational { + // ========== + + int saved_road_movement_rate; // Valid when railroad movement limit is applied (limit_railroad_movement > 0) and BIC data has been loaded + int road_mp_cost; // The cost of moving one tile along a road, in MP. Valid after BIC data was loaded. + int railroad_mp_cost_per_move; // The cost of moving one tile along a railroad, in MP, per move available to the unit. This is measured per + // move since the cost of moving along a railroad is scaled by the total number of moves available to the + // unit. Valid after BIC data was loaded. + + int saved_barb_culture_group; // Valid when barb city capturing is enabled and BIC data has been loaded + + Leader * leader_param_for_patch_get_wonder_city_id; // Valid in patch_get_wonder_city_id when called from + // Leader_recompute_auto_improvements + + int show_popup_was_called; // Set to 1 in show_popup. Used in patch_Leader_can_do_worker_job to check if the replacement + // popup was shown. + + // Used to control trade screen scroll + int open_diplo_form_straight_to_trade; // Initialized to 0, gets set to 1 by patch_DiploForm_do_diplomacy to signal + // to patch_DiploForm_m68_Show_Dialog to open the diplo form straight into trade mode. + int trade_screen_scroll_to_id; // Set by patch_DiploForm_m82_handle_key_event to signal to do_diplomacy that the form + // was closed in order to scroll to the civ with the set ID. -1 indicates no scrolling. + Button * trade_scroll_button_left; // initialized to NULL + Button * trade_scroll_button_right; // initialized to NULL + Sprite * trade_scroll_button_images; // inited to NULL, array of 6 images: normal, rollover, and highlight for left & right + enum init_state trade_scroll_button_state; + int eligible_for_trade_scroll; + + char ask_gold_default[32]; + + // Set in patch_ai_choose_production, used by the various bits of injected code that run during the AI production choosing process. + City * ai_considering_production_for_city; + + // This variable stores what improvement or unit the AI is evaluating inside ai_choose_production. It gets set inside two call replacements, + // first inside the loop over improvements then again inside a loop over unit types. The var is used by the intercept consideration functions + // which run at the end of each loop iteration. + City_Order ai_considering_order; + int handling_ai_district_fallback; + + // Used in the code that adds additional info to the tile info box + bool tile_info_open; + int viewing_tile_info_x, viewing_tile_info_y; + + // Used in patch_Tile_m43_Get_field_30_for_city_loc_eval to change how the AI evaluates overlap between cities + int ai_evaling_city_loc_x, ai_evaling_city_loc_y; + int ai_evaling_city_field_30_get_counter; + + // Stores a list of the production options in a given city and the point value the AI would assign to each. The list is populated by + // rank_ai_production_options, items are added by record_improv_val which gets called by some code injected into one of the loops in + // ai_choose_production. These vars are initialized to zero. + struct ai_prod_valuation * ai_prod_valuations; + int count_ai_prod_valuations; + int ai_prod_valuations_capacity; + + // Used for generating resources from buildings and districts + struct extra_resource_tile * resource_tiles; + int count_resource_tiles; + int resource_tiles_capacity; + struct extra_resource_tile * got_resource_tile; + int saved_tile_count; // Stores the actual tile count in case p_bic_data->Map.TileCount was temporarily overwritten. Set to -1 when empty. + byte * mill_input_resource_bits; // Array of bits, one for each resource. Stores whether or not each one is an input to any mill. + + // Used for displaying yields from generated resources on the city screen + int tourism_icon_counter; // Incremented each time a tourism yield icon (normally commerce) is drawn. Reset between improvs. + int convert_displayed_tourism_to_food, convert_displayed_tourism_to_shields; // Number of commerce tourism icons to convert to food, shields + int combined_tourism_and_mill_commerce; // Number of commerce tourism icons to display inc. from mills, maybe negative + + int drawing_icons_for_improv_id; // Stores the improv ID whose icons we're drawing. -1 while not drawing. + + PCX_Image * resources_sheet; // Sprite sheet of resource icons, i.e. resources.pcx + + Sprite tile_already_worked_zoomed_out_sprite; // Valid only if init state is OK + + // Only for use by patch_City_Form_draw_yields_on_worked_tiles and patch_Sprite_draw_already_worked_tile_img + bool do_not_draw_already_worked_tile_img; + + // Stores the trade offer object being modified when the user right-clicks on a gold offer/ask on the trade table. Gets set by a special + // function call replacement (see apply_machine_code_edits for details). + TradeOffer * modifying_gold_trade; + + // Initialized to NULL and reset to NULL after Unit::bombard_tile returns. Gets set just before the call to Unit::play_bombard_fire_animation + // from inside bombard_tile. The value is the unit on the bombarded tile specifically targeted by the attack, if applicable. + Unit * bombard_stealth_target; + + // Set to zero when Unit::select_stealth_attack_target is called then checked inside in the call to PopupSelection::add_item and set to + // 1. This variable lets the add_item replacement function run special code for only the first item added, in order to insert an additional + // first option to cancel the stealth attack. + int added_any_stealth_target; + + // Initialized to zero. Temporarily set to 1 across a call to patch_Unit_select_stealth_attack_target to request that the selected target must + // be suitable for attack via bombardment. + int selecting_stealth_target_for_bombard; + + // Set in rand_int_to_dodge_city_aa and read immediately after in Unit_get_defense_to_dodge_city_aa. Allows us to determine whether the dodge + // roll was successful in order to popup the message. + int result_of_roll_to_dodge_city_aa; + + // Initialized to NULL. If set to non-NULL, the next call to show_map_message will consume that value and use it as the text on the + // message. Used to implement show_map_specific_text. + char const * map_message_text_override; + + // Initialized to NULL. If set to non-NULL, the next call to do_load_game will consume this value and use it as the file path of the game to + // load instead of opening the file picker. + char const * load_file_path_override; + + // A set of player bits indicating which players should see a replay of the AI's moves. Normally all zero, gets filled in by + // patch_perform_interturn_in_main_loop only when/as appropriate. As replays are played (in patch_show_movement_phase_popup), the + // corresponding bits are cleared. + int replay_for_players; + + // Used by patch_perform_interturn_in_main_loop to determine which players need to see the replay. Clear before interturn processing, then + // every time an AI unit moves onto or bombards a tile, any players that have vision on that tile will have their bit set in this var. + int players_saw_ai_unit; + + // Initialized to 0. If set to non-zero, the next call to do_load_game will consume the value and skip the intro popup. + int suppress_intro_after_load_popup; + + struct improv_id_list { + int * items; + int count; + int capacity; + } water_trade_improvs, air_trade_improvs, combat_defense_improvs; + + // Used by the fix for the barbarian diagonal bug + int barb_diag_patch_dy_fix; + + // Initialized to 0. If 1, barbarian activity is force activated b/c there are barb cities on the map that need to do production. + int force_barb_activity_for_cities; + + // Used as a stand-in for an actual tile where needed. In particular, this object is returned from various get_tile and tile_at replacements + // when we need to override the visibility data to implement hotseat shared vis. + Tile * dummy_tile; + + // When the game checks visibility for a tile, it accesses all four visibility fields with separate calls to Map::get_tile and/or tile_at. We + // replace the first call, maybe altering its return to implement shared visibility, cache the return in this variable, then re-use the cached + // value for the next three calls. + Tile * tile_returned_for_visibility_check; + + // Initialized to all -1. If set, the unit with the specified ID will always be the top unit displayed on the specified tile. If the unit is + // not on that tile, there is no effect. This is only intended to be used on a temporary basis. + struct unit_display_override { + int unit_id, tile_x, tile_y; + } unit_display_override; + + // Set in patch_Fighter_get_odds_for_main_combat_loop, read by patch_Unit_get_attack/defense_strength. + // Stores counter multipliers for the current combat. Active only during Fighter_get_combat_odds call. + struct { + bool active; + Unit * attacker; + Unit * defender; + int attacker_atk_pct; // Attacker attack multiplier (combines forward self-atk and reverse enemy-atk) + int defender_def_pct; // Defender defense multiplier (combines forward enemy-def and reverse self-def) + bool ignore_terrain; + } counter_combat_ctx; + + // Used to extract which unit (if any) exerted zone of control from within Fighter::apply_zone_of_control. + Unit * zoc_interceptor; + + // Set when Fighter::apply_zone_of_control is called to store the defending unit, used by the injected filter and Unit::move_to_adjacent_tile. + // Cleared at each call to move_to_adjacent_tile and by Unit::despawn. + Unit * zoc_defender; + + // Set to the bombarding unit while Unit::bombard_tile is running. NULL otherwise. + Unit * bombarding_unit; + + // Normally set to NULL. When a unit bombards a tile (the tile itself, not something on it), set to point to that unit during the call to + // Unit::attack_tile. Used to stop the unit from losing all of its movement if configured. + Unit * unit_bombard_attacking_tile; + + // Set to the coords of the tile being attacked while Unit::attack_tile is running, -1 otherwise. + int attacking_tile_x, attacking_tile_y; + + // Cleared to false when Fighter::apply_zone_of_control is called. The interceptor must be unfortified to ensure it plays its animation. If + // that happens, this flag is set so that apply_zone_of_control knows to refortify the unit after the ZoC process is done. + bool refortify_interceptor_after_zoc; + + // These flags are used to turn off lethal ZoC for units that capture an enemy on the tile they're moving into. Without this rule, the unit + // might get killed by ZoC but the captured units will remain on a tile that was never actually entered (that tile might have an enemy city + // for extra weirdness). Here's how it works: + // 1. The moving_unit_to_adjacent_tile flag is set when Unit::move_to_adjacent_tile is called. + // 2. If that flag is set and a unit is captured (detected by intercepting the calls to Leader::spawn_unit inside Unit::do_capture_units) + // then temporarily_disallow_lethal_zoc is set. + // 3. If temporar... is set, the code to filter ZoC interceptors acts as if lethal ZoC were turned off. + // 4. Both flags are cleared when Unit::move_to_adjacent_tile returns. + bool temporarily_disallow_lethal_zoc; + bool moving_unit_to_adjacent_tile; + + // Tracks temporary transport bypass when letting workers step onto coast tiles without a boat + Unit * coast_walk_unit; + bool coast_walk_transport_override; + enum UnitStateType coast_walk_prev_state; + int coast_walk_prev_container; + bool coast_walk_restore_goto_path; + int coast_walk_prev_path_len; + int coast_walk_prev_path_dest_x; + int coast_walk_prev_path_dest_y; + Unit * move_spend_override_unit; + int move_spend_override_value; + + // Used to record info about a defensive bomardment event during Fighter::fight. Gets set by Fighter::damage_by_defensive_bombardment and + // cleared when Fighter::fight returns. + struct defensive_bombard_event { + Unit * bombarder; + Unit * defender; + bool damage_done, defender_was_destroyed, saved_animation_setting; + } dbe; + + // Set to true IFF we're showing a replay of AI moves in hotseat mode + bool showing_hotseat_replay; + + // Set to true only during the first call to get_tile_occupier_id from Trade_Net::get_movement_cost. While this is set, we need to edit unit + // visibility to patch the submarine bug. + bool getting_tile_occupier_for_ai_pathfinding; + + bool running_on_wine; // Set to 1 IFF we're running in Wine, as opposed to actual Windows + + // gdi_plus.init_state is valid any time after patch_init_floating_point. All the other fields are only valid after set_up_gdi_plus has been + // called and gdi_plus.init_state equals IS_OK. + struct gdi_plus { + enum init_state init_state; + HMODULE module; + ULONG_PTR token; + void * gp_graphics; + + int (__stdcall * CreateFromHDC) (HDC hdc, void ** p_gp_graphics); + int (__stdcall * DeleteGraphics) (void * gp_graphics); + int (__stdcall * SetSmoothingMode) (void * graphics, int smoothing_mode); + int (__stdcall * SetPenDashStyle) (void * gp_pen, int dash_style); + int (__stdcall * CreatePen1) (unsigned int argb_color, float width, int gp_unit, void ** p_gp_pen); + int (__stdcall * DeletePen) (void * gp_pen); + int (__stdcall * DrawLineI) (void * gp_graphics, void * gp_pen, int x1, int y1, int x2, int y2); + } gdi_plus; + + // These variables track the states of some OpenGL parameters. They're updated whenever methods like OpenGLRenderer::set_color are called. + unsigned int ogl_color; + int ogl_line_width; + bool ogl_line_stipple_enabled; + + // Records how many units of each type we're going to upgrade to during an upgrade-all. This info will be used to impose the unit type limit + // during the upgrade. Keep in mind units all get upgraded from the same type but might end up as different types after upgrade-all. + struct penciled_in_upgrade { + int unit_type_id; + int count; + } * penciled_in_upgrades; + int penciled_in_upgrade_count; + int penciled_in_upgrade_capacity; + + // While in Leader::do_capture_city, the city in question is stored in this var. Otherwise it's NULL. + City * currently_capturing_city; + + // While a game is being saved or loaded, this variable points to the save file's MappedFile object. Otherwise it's NULL. + MappedFile * accessing_save_file; + + // Used in patch_work_simple_job. If a method sets this variable while that method is running then at the end it sets the given tile as LM. + Tile * lmify_tile_after_working_simple_job; + + // Reset to zero every time City_Form::draw is called. Incremented everything a strategic resource is drawn on the city screen. + int drawn_strat_resource_count; + + int * charmed_types_converted_to_ptw_arty; + int count_charmed_types_converted_to_ptw_arty; + int charmed_types_converted_to_ptw_arty_capacity; + + // While Unit::is_visible_to_civ is running, this var is set to the unit in question. Otherwise it's NULL. + Unit * checking_visibility_for_unit; + + // Normally false. When true, calls to bounce_trespassing_units won't kick out invisible units even if they're revealed. + bool do_not_bounce_invisible_units; + + // Normally false. When true, Unit::despawn also despawns any passenger units inside instead of making exceptions in some cases. + bool always_despawn_passengers; + + // Normally false. When true, calls to Unit::score_kill will not enslave. + bool do_not_enslave_units; + + // If limit_unit_loading_to_one_transport_per_turn is on, maps unit IDs to the ID of the transport unit they're tied to for the current turn. + struct table unit_transport_ties; + + // Initialized to NULL/0, used in patch_City_add_happiness_from_buildings + short * saved_improv_counts; + int saved_improv_counts_capacity; + + // Used to de-overlap specialist yield icons (option name fix_overlapping_specialist_yield_icons) + int specialist_icon_drawing_running_x; + + // Initialized to 0, used to draw multipage descriptions in the Civilopedia + struct civilopedia_multipage_description { + bool drawing_lines; + int line_count; + int shown_page; // zero-based + int last_page; // also zero-based + Civilopedia_Article * article; + Button * effects_btn; + Button * previous_btn; + } cmpd; + + // When expand_civilopedia_unit_stats is on, all the game's calls to draw_and_wrap_text to draw the second column of unit stats are + // intercepted to draw nothing and store their strings here. Then we possible add some entries of our own. The game will add up to 6 entries + // and we'll add up to 4. + char * pedia_unit_stats_second_column_strs[10]; + + // Day-Night cycle data + int current_day_night_cycle; + bool day_night_cycle_unstarted; // If current_day_night_cycle has not been set, f.e. because it's the first turn of a new game. + bool day_night_cycle_img_proxies_indexed; + LARGE_INTEGER last_day_night_cycle_update_time; + + struct table day_night_sprite_proxy_by_hour[24]; + + struct wonder_district_image_set { + Sprite img; + Sprite construct_img; + Sprite alt_dir_img; + Sprite alt_dir_construct_img; + } wonder_district_img_sets[MAX_WONDER_DISTRICT_TYPES]; + + struct natural_wonder_district_image_set { + Sprite img; + } natural_wonder_img_sets[MAX_NATURAL_WONDER_DISTRICT_TYPES]; + struct natural_wonder_label_draw_info { + int text_left; + int text_top; + int text_width; + int font_size; + char const * text; + }; + + struct day_night_cycle_img_set + { + SpriteList Std_Terrain_Images[9]; + SpriteList LM_Terrain_Images[9]; + Sprite City_Images[80]; + Sprite Destroyed_City_Images[3]; + Sprite Resources[36]; + Sprite ResourcesShadows[36]; + Sprite Terrain_Buldings_Barbarian_Camp; + Sprite Terrain_Buldings_Mines; + Sprite Victory_Image; + Sprite Flood_Plains_Images[16]; + Sprite Fog_Of_War_Images[81]; + Sprite Polar_Icecaps_Images[32]; + Sprite Railroads_Images[272]; + Sprite Roads_Images[256]; + Sprite Minor_Roads_Images[256]; + Sprite Terrain_Buldings_Airfields[2]; + Sprite Terrain_Buldings_Airfields_Shadow[2]; + Sprite Terrain_Buldings_Camp[4]; + Sprite Terrain_Buldings_Fortress[4]; + Sprite Terrain_Buldings_Barricade[4]; + Sprite Goody_Huts_Images[8]; + Sprite Terrain_Buldings_Outposts[3]; + Sprite Terrain_Buldings_Outposts_Shadow[3]; + Sprite Pollution[25]; + Sprite Craters[25]; + Sprite Terrain_Buldings_Radar; + Sprite Terrain_Buldings_Radar_Shadow; + Sprite Tnt_Images[18]; + Sprite Waterfalls_Images[4]; + Sprite LM_Terrain[7]; + Sprite Marsh_Large[8]; + Sprite Marsh_Small[10]; + Sprite Volcanos_Images[16]; + Sprite Volcanos_Forests_Images[16]; + Sprite Volcanos_Jungles_Images[16]; + Sprite Volcanos_Snow_Images[16]; + Sprite Grassland_Forests_Large[8]; + Sprite Plains_Forests_Large[8]; + Sprite Tundra_Forests_Large[8]; + Sprite Grassland_Forests_Small[10]; + Sprite Plains_Forests_Small[10]; + Sprite Tundra_Forests_Small[10]; + Sprite Grassland_Forests_Pines[12]; + Sprite Plains_Forests_Pines[12]; + Sprite Tundra_Forests_Pines[12]; + Sprite Irrigation_Desert_Images[16]; + Sprite Irrigation_Plains_Images[16]; + Sprite Irrigation_Images[16]; + Sprite Irrigation_Tundra_Images[16]; + Sprite Grassland_Jungles_Large[8]; + Sprite Grassland_Jungles_Small[12]; + Sprite Mountains_Images[16]; + Sprite Mountains_Forests_Images[16]; + Sprite Mountains_Jungles_Images[16]; + Sprite Mountains_Snow_Images[16]; + Sprite Hills_Images[16]; + Sprite Hills_Forests_Images[16]; + Sprite Hills_Jungle_Images[16]; + Sprite Delta_Rivers_Images[16]; + Sprite Mountain_Rivers_Images[16]; + Sprite Territory_Images[8]; + Sprite LM_Mountains_Images[16]; + Sprite LM_Forests_Large_Images[8]; + Sprite LM_Forests_Small_Images[10]; + Sprite LM_Forests_Pines_Images[12]; + Sprite LM_Hills_Images[16]; + Sprite District_Images[COUNT_DISTRICT_TYPES][MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [district][variant][era][column] + Sprite Abandoned_District_Image; + Sprite Abandoned_Maritime_District_Image; + struct wonder_district_image_set Wonder_District_Images[MAX_WONDER_DISTRICT_TYPES]; + struct natural_wonder_district_image_set Natural_Wonder_Images[MAX_NATURAL_WONDER_DISTRICT_TYPES]; + } day_night_cycle_imgs[24]; + + // Districts + enum init_state dc_img_state; + enum init_state dc_btn_img_state; + enum init_state dc_icons_img_state; + + struct district_config district_configs[COUNT_DISTRICT_TYPES]; + struct wonder_district_config wonder_district_configs[MAX_WONDER_DISTRICT_TYPES]; + struct natural_wonder_district_config natural_wonder_configs[MAX_NATURAL_WONDER_DISTRICT_TYPES]; + +struct district_image_set { + Sprite imgs[MAX_DISTRICT_VARIANT_COUNT][4][MAX_DISTRICT_COLUMN_COUNT]; // [variant][era][column] +} district_img_sets[COUNT_DISTRICT_TYPES]; + Sprite abandoned_district_img; + Sprite abandoned_maritime_district_img; + +struct district_button_image_set { + Sprite imgs[4]; +} district_btn_img_sets[COUNT_DISTRICT_TYPES]; + + // Building ID keys -> district ID. If a building ID is present in the + // table that means that building can only be built if there is a corresponding district is present in the city radius. + struct table district_building_prereqs; + + // Tile pointer IDs -> district_instance pointer. Maps tiles to dynamically allocated + // district_instance structs tracking district type and state (UNDER_CONSTRUCTION or COMPLETED). + // For wonder districts, the wonder_info field tracks wonder-specific state (unused, reserved, completed, ruined), + // which city reserved/completed the wonder, and which wonder index is on this district. + struct table district_tile_map; + struct table named_tile_map; + + // Tracks per-turn airlift usage for aerodrome districts (tile pointer -> civ bitmask). + struct table aerodrome_airlift_usage; + + // Command ID keys -> district ID. Used to identify which district + // a unit command (e.g., build order) corresponds to. + struct table command_id_to_district_id; + + // Array of 32 tables (one per civ) of pending district requests keyed by city & district (values are struct pending_district_request pointers). + struct table city_pending_district_requests[32]; + + // City pointer keys -> improvement ID. Tracks which improvements (buildings/wonders) + // requiring districts a city has ordered to be built (pending district completion). + struct table city_pending_building_orders; + + // AI cache mapping city pointer keys -> AI_Order pointer. Stores the best feasible + // production order for AI cities to optimize decision-making. + struct table ai_best_feasible_orders; + + // String building/wonder name keys -> int building/improvement ID. + // Used to look up building IDs by their text names from the game data. + struct table building_name_to_id; + + struct district_infos { + int advance_prereq_ids[MAX_DISTRICT_DEPENDENTS]; // Tech IDs that enable the district (all required) + int advance_prereq_count; + int obsoleted_by_id; + int resource_prereq_ids[MAX_DISTRICT_DEPENDENTS]; + int resource_prereq_count; + int resource_prereq_on_tile_id; + int wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; + int wonder_prereq_count; + int natural_wonder_prereq_ids[MAX_DISTRICT_DEPENDENTS]; + int natural_wonder_prereq_count; + int dependent_building_count; + int dependent_building_ids[MAX_DISTRICT_DEPENDENTS]; // Building types the district enables + } district_infos[COUNT_DISTRICT_TYPES]; + + // District tracking counters: total = special (hard-coded) + dynamic (from config/scenario) + // next_custom_dynamic_command_index assigns unique command IDs for custom dynamic commands + int district_count; + int special_district_count; + int dynamic_district_count; + int wonder_district_count; + int natural_wonder_count; + int next_custom_dynamic_command_index; + + // Distribution Hub tracking: records keyed by tile plus per-tile coverage counts; dirty/refresh flags + // control when totals are recalculated + struct table distribution_hub_records; + struct table distribution_hub_coverage_counts; + bool distribution_hub_totals_dirty; + bool distribution_hub_refresh_in_progress; + + // Distribution Hub UI sprites loaded from PCX files for rendering food/shield icons in city interface + // *_icons_remaining counters track how many icons to draw from each source (non-district, district, hub, corruption) + Sprite distribution_hub_shield_icon; + Sprite distribution_hub_corruption_icon; + Sprite distribution_hub_food_icon; + Sprite distribution_hub_eaten_food_icon; + Sprite distribution_hub_shield_icon_small; + Sprite distribution_hub_food_icon_small; + int non_district_shield_icons_remaining; + int corruption_shield_icons_remaining; + int district_shield_icons_remaining; + int distribution_hub_shield_icons_remaining; + int district_corruption_icons_remaining; + int distribution_hub_corruption_icons_remaining; + + // District UI sprites loaded from PCX files for rendering yield icons (science, commerce, shield, food, culture, happiness) + // Available in both regular and small sizes for different UI contexts in city interface + Sprite district_science_icon; + Sprite district_commerce_icon; + Sprite district_shield_icon; + Sprite district_corruption_icon; + Sprite district_food_icon; + Sprite district_food_eaten_icon; + Sprite district_happiness_icon_small; + Sprite district_shield_icon_small; + Sprite district_commerce_icon_small; + Sprite district_food_icon_small; + Sprite district_science_icon_small; + Sprite district_culture_icon_small; + Sprite district_unhappiness_icon_small; + Sprite district_negative_shield_icon_small; + Sprite district_negative_commerce_icon_small; + Sprite district_negative_food_icon_small; + Sprite district_negative_science_icon_small; + Sprite district_negative_culture_icon_small; + + // Guard to prevent recursive sharing when auto-adding buildings across cities + bool sharing_buildings_by_districts_in_progress; + + // Worker tracking: 32 tables (one per civ), each mapping unit_id -> district_worker_record pointer + struct table district_worker_tables[32]; + + // Natural Wonder labels: table mapping natural wonder name strings to their IDs, count of defined natural wonders, + struct table natural_wonder_name_to_id; + + struct ai_candidate_bridge_or_canal_entry * ai_candidate_bridge_or_canals; + int ai_candidate_bridge_or_canals_count; + int ai_candidate_bridge_or_canals_capacity; + bool ai_candidate_bridge_or_canals_initialized; + + // City work radius highlighting: flag to enable/disable, table mapping tile pointers to highlight_level for visual feedback + bool highlight_city_radii; + struct table highlighted_city_radius_tile_pointers; + + // Initialized to 0. Every time Main_Screen_Form::m82_handle_key_event receives an event with is_down == 0, the virtual key code is prepended + // to this list. + int last_main_screen_key_up_events[5]; + + // Stores the parameters to Unit::can_load while it's running, NULL otherwise. + Unit * can_load_transport, * can_load_passenger; + + // Current tile being rendered in Map_Renderer_m19_Draw_Tile_by_XY_and_Flags. For use within various Map_Renderer::impl_m*_Draw_* functions. Nulled out after the render function is complete + Tile * current_render_tile; + struct district_instance * current_render_tile_district; + int current_render_tile_x, current_render_tile_y; + + // Used in patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp and so on for flagging whether to draw forests over roads on the tile being rendered + bool draw_forests_over_roads_on_tile; + + // Set to true once the auto-build process for the Great Wall is complete to avoid running it again + enum great_wall_auto_build_state great_wall_auto_build; + Tile * focused_tile; + + // Stores the improve ID currently being evaluated inside patch_City_can_build_improvement. + int current_evaluating_improve_id; + + // Stores the index in the list of target civs currently being drawn on the espionage form. Used to replace the civ name with its era-specific alias. + int espionage_form_drawing_target_index; + + // Tracks information about the last unit that was selected. These fields are updated when a new unit is selected or when the selected unit + // moves or is destroyed. + struct { + int initial_x, initial_y; // Stores the unit's location when it was selected + int last_x, last_y, type_id; // Stores the unit's current or last available location and type id + Unit * ptr; // A pointer to the unit, may be NULL if the unit was destroyed + } last_selected_unit; + + // Maps unit IDs to the level at which they are waiting. Units with lower levels move first. Units that have not been set to wait are not in the table. + struct table waiting_units; + + // Set to true when waiting_units has been initialized by loading from the save. Causes the game to skip clearing the table when setting up + // unit cycling for the turn. + bool have_loaded_waiting_units; + + // Used in patch_Unit_do_capture_units and patch_Unit_despawn + Unit ** extra_capture_despawns; + int count_extra_capture_despawns; + int extra_capture_despawns_capacity; + + // ========== + // } + // ========== +}; + +enum object_job { + OJ_DEFINE = 0, + OJ_INLEAD, // Patch this function with an inlead + OJ_REPL_VPTR, // Patch this function by replacing a pointer to it. The address column is the addr of the VPTR not the function itself. + OJ_REPL_CALL, // Patch a single function call. The address column is the addr of the call instruction, name refers to the new target function, type is not used. + OJ_REPL_VIS, // Patch a cluster of four function calls that make up a check of tile visibility. See implementation for details. + OJ_EXT_WALUP, // "EXTend Work Area LuP" Patch a jump instruction at the end of a "lup" (loop) over a city's workable area to extend it + OJ_IGNORE +}; + +struct civ_prog_object { + enum object_job job; + int addr; + char const * name; + char const * type; +}; diff --git a/DayNight/civ3_city_lights.py b/DayNight/civ3_city_lights.py index 55cfd5d7..794f4637 100644 --- a/DayNight/civ3_city_lights.py +++ b/DayNight/civ3_city_lights.py @@ -1,521 +1,521 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -Civ 3 city lights compositor for *_lights.pcx -- Recursive over Data/1200 → writes siblings 0100..2400 -- Multiple --light-key values (union mask) -- **Per-light-key styles** via --light-style: per-key core/glow colors and optional overrides -- Night (19..24,1..6): also replaces non-lights file -- Pins magenta #ff00ff to palette index 255; removes #00ff00 from palette -""" - -import argparse, os, math, shutil -from typing import List, Tuple, Dict, Optional -from PIL import Image, ImageChops, ImageFilter -from argparse import RawTextHelpFormatter - -MAGENTA = (255, 0, 255) -GREEN = (0, 255, 0) - -# ---------- parsing ---------- - -def parse_rgb_one(s: str) -> Tuple[int,int,int]: - s = s.strip() - if s.startswith("#"): - s = s[1:]; assert len(s)==6, "Hex color must be #rrggbb" - return int(s[0:2],16), int(s[2:4],16), int(s[4:6],16) - if "," in s: - a = [int(p) for p in s.split(",")]; assert len(a)==3, "RGB must be R,G,B" - return tuple(max(0,min(255,v)) for v in a) # type: ignore - raise ValueError("Color must be '#rrggbb' or 'R,G,B'") - -def parse_rgb_list(values: List[str]) -> List[Tuple[int,int,int]]: - out: List[Tuple[int,int,int]] = [] - for raw in values or []: - tokens = [t for t in raw.replace(";", " ").split() if t] - for tok in tokens: - out.append(parse_rgb_one(tok)) - if not out: out = [(0,254,255)] - dedup, seen = [], set() - for c in out: - if c not in seen: seen.add(c); dedup.append(c) - return dedup - -def parse_styles(values: List[str]) -> Dict[Tuple[int,int,int], Dict[str,object]]: - """ - --light-style "key=#00feff; core=#fff87a; glow=#ff8a20; core_gain=1.6; halo_gain=4.0; halo_sep=0.75; halo_gamma=1.35; core_radius=1.2; halo_radius=14; highlight=0.6" - Accepts ';' or ',' separators. Only 'key' is required; others override globals for that key. - """ - styles: Dict[Tuple[int,int,int], Dict[str,object]] = {} - for raw in values or []: - parts = [p.strip() for p in raw.replace(",", ";").split(";") if p.strip()] - kv: Dict[str,str] = {} - for p in parts: - if "=" in p: - k,v = p.split("=",1); kv[k.strip().lower()] = v.strip() - if "key" not in kv: raise SystemExit("Each --light-style must include key=") - key_rgb = parse_rgb_one(kv["key"]) - entry: Dict[str,object] = {} - if "core" in kv: entry["core_color"] = parse_rgb_one(kv["core"]) - if "glow" in kv: entry["glow_color"] = parse_rgb_one(kv["glow"]) - for numk in ["core_gain","halo_gain","core_radius","halo_radius","halo_sep","halo_gamma","highlight","size_boost","size_radius","size_gamma"]: - if numk in kv: - entry[numk] = float(kv[numk]) - styles[key_rgb] = entry - return styles - -# ---------- time window ---------- - -def hour_weight_lights(hour_1_24: int, start: float = 18.0, end: float = 6.0, floor: float = 0.80) -> float: - h = float(hour_1_24) % 24.0 - inwin = (h >= start) or (h <= end) - if not inwin: return 0.0 - L = (24.0 - start) + end - p = (h - start) if (h >= start) else ((24.0 - start) + h) - mid = 0.5*L; t = abs(p - mid)/mid - w = floor + (1.0 - floor)*0.5*(1.0 + math.cos(math.pi * t)) - return max(0.0, min(1.0, w)) - -def is_night_hour(hour_1_24: int) -> bool: - return (18 <= hour_1_24 <= 24) or (1 <= hour_1_24 <= 6) - -# ---------- palette ---------- - -def get_palette(image: Image.Image) -> List[int]: - pal = image.getpalette() or [] - if len(pal) < 256*3: pal += [0]*(256*3 - len(pal)) - return pal[:256*3] - -def put_palette(image: Image.Image, palette: List[int]) -> None: - if len(palette) < 256*3: palette += [0]*(256*3 - len(palette)) - image.putpalette(palette[:256*3]) - -def ensure_palette_has_colors(image: Image.Image, colors: List[Tuple[int,int,int]]) -> List[int]: - pal = get_palette(image) - to_add = [c for c in colors if find_color_index(pal,c)==-1] - if not to_add: return pal - hist = image.histogram() if image.mode=='P' else None - candidates = sorted(range(256), key=(lambda i: hist[i])) if (hist and len(hist)==256) else list(range(255,-1,-1)) - protected=set() - for rgb in colors+[MAGENTA]: - idx = find_color_index(pal, rgb) - if idx!=-1: protected.add(idx) - replace=[] - for i in candidates: - if i in protected: continue - replace.append(i) - if len(replace)>=len(to_add): break - if len(replace) int: - r,g,b = rgb - for i in range(256): - if palette[3*i]==r and palette[3*i+1]==g and palette[3*i+2]==b: return i - return -1 - -def quantize_to_p_256(img: Image.Image) -> Image.Image: - try: - dnone = Image.Dither.NONE - except Exception: - dnone = getattr(Image, "NONE", 0) - rgb = img.convert('RGB') - try: - return rgb.quantize(colors=256, method=Image.FASTOCTREE, dither=dnone) - except Exception: - return rgb.quantize(colors=256, dither=dnone) - -def force_magenta_at_255(im: Image.Image) -> int: - pal = get_palette(im) - old255 = (pal[3*255], pal[3*255+1], pal[3*255+2]) - idx_mag = find_color_index(pal, MAGENTA) - if idx_mag == -1: - pal = ensure_palette_has_colors(im, [MAGENTA]); put_palette(im, pal) - pal = get_palette(im); idx_mag = find_color_index(pal, MAGENTA) - if idx_mag == 255: return 255 - pal[3*255:3*255+3]=list(MAGENTA); pal[3*idx_mag:3*idx_mag+3]=list(old255) - put_palette(im, pal); return idx_mag - -# ---------- image ops ---------- - -def color_equal(img_rgb: Image.Image, color: Tuple[int,int,int]) -> Image.Image: - w,h = img_rgb.size - solid = Image.new('RGB',(w,h),color) - diff = ImageChops.difference(img_rgb, solid) - return diff.convert('L').point(lambda v: 255 if v==0 else 0, mode='L') - -def apply_gamma_L(imgL: Image.Image, gamma: float) -> Image.Image: - gamma = max(0.05, float(gamma)) - lut = [min(255, int(round((i/255.0) ** gamma * 255))) for i in range(256)] - return imgL.point(lut, mode='L') - -def scale_L(imgL: Image.Image, factor: float) -> Image.Image: - factor = max(0.0, float(factor)) - return imgL.point(lambda v: 255 if v*factor >= 255 else int(v*factor)) - -def screen_blend(a: Image.Image, b: Image.Image) -> Image.Image: - try: - return ImageChops.screen(a,b) - except AttributeError: - return ImageChops.invert(ImageChops.multiply(ImageChops.invert(a), ImageChops.invert(b))) - -# ---------- masks & glows ---------- - -def build_interior_mask(base_bg: Image.Image, clip: bool, erode_px: int) -> Image.Image: - if not clip: return Image.new('L', base_bg.size, 255) - base_rgb = base_bg.convert('RGB') - mag = color_equal(base_rgb, MAGENTA) - grn = color_equal(base_rgb, GREEN) - interior = ImageChops.invert(ImageChops.add(mag, grn, scale=1.0)) - if erode_px>0: - k = max(1,int(erode_px)); interior = interior.filter(ImageFilter.MinFilter(2*k+1)) - return interior - -def build_glow_maps(mask_bin: Image.Image, interior_mask: Image.Image, wtime: float, - core_radius: float, halo_radius: float, - core_gain: float, halo_gain: float, - size_boost: float, size_radius: float, size_gamma: float, - halo_sep: float, halo_gamma: float): - blur_core = mask_bin.filter(ImageFilter.GaussianBlur(radius=core_radius)) - blur_halo = mask_bin.filter(ImageFilter.GaussianBlur(radius=halo_radius)) - - if size_boost>0.0 and size_radius>0: - density = mask_bin.filter(ImageFilter.BoxBlur(radius=size_radius)).convert('L') - density = apply_gamma_L(density, max(0.05, size_gamma)) - boost = scale_L(density, size_boost * wtime) - blur_core = ImageChops.add(blur_core, boost, scale=1.0) - blur_halo = ImageChops.add(blur_halo, boost, scale=1.0) - - halo_sep = max(0.0, min(1.0, halo_sep)) - halo_only = ImageChops.subtract(blur_halo, blur_core.point(lambda v:int(v*halo_sep)), scale=1.0, offset=0) if halo_sep>0 else blur_halo - halo_only = apply_gamma_L(halo_only, halo_gamma) - - core_alpha = scale_L(blur_core, wtime*max(0.0, core_gain)) - halo_alpha = scale_L(halo_only, wtime*max(0.0, halo_gain)) - core_alpha = ImageChops.multiply(core_alpha, interior_mask) - halo_alpha = ImageChops.multiply(halo_alpha, interior_mask) - return core_alpha, halo_alpha - -def layer_from_alpha(color: Tuple[int,int,int], alphaL: Image.Image) -> Image.Image: - w,h = alphaL.size - solid = Image.new('RGB',(w,h),color) - return Image.composite(solid, Image.new('RGB',(w,h),(0,0,0)), alphaL) - -# ---------- compositor with per-key styles ---------- - -def build_composite_with_styles(base_bg_rgba: Image.Image, - mask_source_rgb: Image.Image, - hour_1_24: int, - keys: List[Tuple[int,int,int]], - styles: Dict[Tuple[int,int,int], Dict[str,object]], - # global defaults: - core_radius: float, halo_radius: float, - core_gain: float, halo_gain: float, - core_color: Tuple[int,int,int], - glow_color: Tuple[int,int,int], - size_boost: float, size_radius: float, size_gamma: float, - clip_interior: bool, clip_erode: int, - highlight_gain: float, blend_mode: str, - halo_sep: float, halo_gamma: float) -> Image.Image: - wtime = hour_weight_lights(hour_1_24) - if wtime <= 0.0: # just return unchanged base (still save with palette fix later) - return base_bg_rgba.copy() - - interior = build_interior_mask(base_bg_rgba, clip_interior, clip_erode) - comp = base_bg_rgba.convert('RGB') - - # Ensure every styled key is included in keys - keys_set = {k for k in keys} - for k in styles.keys(): - keys_set.add(k) - keys_order = list(keys_set) - - for key_rgb in keys_order: - # Per-key mask - mask_bin = color_equal(mask_source_rgb, key_rgb) - if mask_bin.getbbox() is None: - continue - - st = styles.get(key_rgb, {}) - k_core_color = st.get("core_color", core_color) - k_glow_color = st.get("glow_color", glow_color) - k_core_gain = float(st.get("core_gain", core_gain)) - k_halo_gain = float(st.get("halo_gain", halo_gain)) - k_core_rad = float(st.get("core_radius", core_radius)) - k_halo_rad = float(st.get("halo_radius", halo_radius)) - k_halo_sep = float(st.get("halo_sep", halo_sep)) - k_halo_gamma = float(st.get("halo_gamma", halo_gamma)) - k_size_boost = float(st.get("size_boost", size_boost)) - k_size_radius= float(st.get("size_radius", size_radius)) - k_size_gamma = float(st.get("size_gamma", size_gamma)) - k_highlight = float(st.get("highlight", highlight_gain)) - - core_alpha, halo_alpha = build_glow_maps( - mask_bin, interior, wtime, - k_core_rad, k_halo_rad, - k_core_gain, k_halo_gain, - k_size_boost, k_size_radius, k_size_gamma, - k_halo_sep, k_halo_gamma - ) - core_layer = layer_from_alpha(k_core_color, core_alpha) - halo_layer = layer_from_alpha(k_glow_color, halo_alpha) - - if blend_mode == "add": - comp = ImageChops.add(comp, core_layer, scale=1.0) - comp = ImageChops.add(comp, halo_layer, scale=1.0) - else: - comp = screen_blend(comp, core_layer) - comp = screen_blend(comp, halo_layer) - - if k_highlight > 0.0: - hl = scale_L(core_alpha, k_highlight) - comp = ImageChops.add(comp, Image.composite(Image.new('RGB',comp.size,(255,255,255)), - Image.new('RGB',comp.size,(0,0,0)), hl), scale=1.0) - - return comp.convert('RGBA') - -# ---------- save with palette fixes ---------- - -def save_with_palette_and_magic(comp_rgba: Image.Image, out_path: str, base_for_magic_rgb: Image.Image) -> None: - imP = quantize_to_p_256(comp_rgba) - pal_after = ensure_palette_has_colors(imP, [MAGENTA]); put_palette(imP, pal_after) - replacement_idx = force_magenta_at_255(imP) - dst_px = imP.load(); src_px = base_for_magic_rgb.load(); w,h = imP.size - for y in range(h): - for x in range(w): - r,g,b = src_px[x,y]; cur = dst_px[x,y] - if (r,g,b)==MAGENTA: - dst_px[x,y]=255 - elif (r,g,b)==GREEN: - dst_px[x,y]=255 - elif cur==255 and replacement_idx!=255: - dst_px[x,y]=replacement_idx - # Remove #00ff00 from palette entirely if present. - pal_after = get_palette(imP) - for i in range(256): - if (pal_after[3*i], pal_after[3*i+1], pal_after[3*i+2]) == GREEN: - pal_after[3*i:3*i+3] = [0, 0, 0] - put_palette(imP, pal_after) - os.makedirs(os.path.dirname(out_path), exist_ok=True) - imP.save(out_path, format='PCX') - -# ---------- driver ---------- - -def process_tree(data_dir: str, noon_subfolder: str, - light_keys: List[Tuple[int,int,int]], - styles: Dict[Tuple[int,int,int], Dict[str,object]], - core_radius: float, halo_radius: float, - core_gain: float, halo_gain: float, - core_color: Tuple[int,int,int], glow_color: Tuple[int,int,int], - size_boost: float, size_radius: float, size_gamma: float, - clip_interior: bool, clip_erode: int, - highlight_gain: float, blend_mode: str, - halo_sep: float, halo_gamma: float, - only_hour: Optional[int]=None, only_file: Optional[str]=None) -> None: - - base_dir = os.path.join(data_dir, noon_subfolder) - if not os.path.isdir(base_dir): raise SystemExit(f"No such folder: {base_dir}") - - hours = [h for h in range(100, 2500, 100) if h != 1200] - if only_hour is not None: - if only_hour == 1200: raise SystemExit("1200 is the base. Choose another hour.") - if only_hour % 100 != 0 or only_hour < 100 or only_hour > 2400: - raise SystemExit("--only-hour must be one of 100,200,...,2400.") - hours = [only_hour] - - norm_only = os.path.normcase(only_file) if only_file else None - - # Ensure styled keys are included even if not explicitly listed in --light-key - for k in styles.keys(): - if k not in light_keys: - light_keys.append(k) - - for dirpath, _, filenames in os.walk(base_dir): - rel_dir = os.path.relpath(dirpath, base_dir); rel_dir = "" if rel_dir=="." else rel_dir - for hhh in hours: - os.makedirs(os.path.join(data_dir, f"{hhh:04d}", rel_dir), exist_ok=True) - - lights_files = [f for f in filenames if f.lower().endswith("_lights.pcx")] - for lights_name in lights_files: - if norm_only: - rel_file = os.path.normcase(os.path.join(rel_dir, lights_name)) - if norm_only != os.path.normcase(lights_name) and norm_only != rel_file: continue - - plain_name = lights_name[:-len("_lights.pcx")] + ".pcx" - noon_lights = os.path.join(dirpath, lights_name) - noon_plain = os.path.join(dirpath, plain_name) - - for hhh in hours: - hour_1_24 = hhh // 100 - hour_dir = os.path.join(data_dir, f"{hhh:04d}", rel_dir) - out_lights= os.path.join(hour_dir, lights_name) - out_plain = os.path.join(hour_dir, plain_name) - print(f"Processing {hhh:04d}: {lights_name} -> {out_lights}") - - if os.path.exists(out_plain): - base_bg = Image.open(out_plain).convert('RGBA'); base_rgb = Image.open(out_plain).convert('RGB') - elif os.path.exists(noon_plain): - base_bg = Image.open(noon_plain).convert('RGBA'); base_rgb = Image.open(noon_plain).convert('RGB') - else: - base_bg = Image.open(noon_lights).convert('RGBA'); base_rgb = Image.open(noon_lights).convert('RGB') - - mask_src = Image.open(noon_lights).convert('RGB') - - comp = build_composite_with_styles( - base_bg_rgba=base_bg, mask_source_rgb=mask_src, hour_1_24=hour_1_24, - keys=light_keys, styles=styles, - core_radius=core_radius, halo_radius=halo_radius, - core_gain=core_gain, halo_gain=halo_gain, - core_color=core_color, glow_color=glow_color, - size_boost=size_boost, size_radius=size_radius, size_gamma=size_gamma, - clip_interior=clip_interior, clip_erode=clip_erode, - highlight_gain=highlight_gain, blend_mode=blend_mode, - halo_sep=halo_sep, halo_gamma=halo_gamma - ) - - if is_night_hour(hour_1_24): - # At night, also write/replace the plain file with the composite - save_with_palette_and_magic(comp, out_plain, base_rgb) - - # ---- Night-only cleanup: remove the hour's *_lights.pcx copy ---- - if os.path.exists(out_lights) and ("annotations" not in out_lights.lower()): - try: - os.remove(out_lights) - except Exception as e: - print(f"WARNING: Could not delete {out_lights}: {e}") - else: - # Daytime: ensure a plain exists; prefer noon_plain if available - if not os.path.exists(out_plain): - if os.path.exists(noon_plain): - os.makedirs(os.path.dirname(out_plain), exist_ok=True) - shutil.copyfile(noon_plain, out_plain) - else: - save_with_palette_and_magic(base_bg, out_plain, base_rgb) - - -def main(): - parser = argparse.ArgumentParser( - description=( - "Render glowing city lights from *_lights.pcx files.\n" - "• Multiple light-keys supported (+ per-key styles)\n" - "• Night hours (19..24,1..6) also overwrite the paired non-lights file\n" - "• MAGENTA pinned to index 255; GREEN removed from palette if present" - ), - formatter_class=RawTextHelpFormatter, - epilog=( - "Examples:\n" - " Basic (one key):\n" - " python civ3_city_lights.py --data ./Data --noon 1200 \\\n" - " --light-key \"#00feff\" --core-color \"#fff87a\" --glow-color \"#ff8a20\"\n" - "\n" - " Multiple keys with per-key styles:\n" - " python civ3_city_lights.py --data ./Data --noon 1200 \\\n" - " --light-key \"#00feff\" --light-key \"#fe00ff\" \\\n" - " --light-style \"key=#00feff; core=#fff87a; glow=#ff9a2b; halo_gain=18; halo_radius=14\" \\\n" - " --light-style \"key=#fe00ff; core=#ffd0ff; glow=#e07aff; core_gain=1.4; halo_gain=12\"\n" - "\n" - " Make large light clusters pop more:\n" - " --size-boost 1.2 --size-radius 4 --size-gamma 0.8\n" - "\n" - "Notes:\n" - " • Increase --halo-radius and --halo-gain for a bigger, softer glow.\n" - " • If you see a dark ring between core/halo, reduce --halo-sep or increase --halo-gamma.\n" - " • 'screen' blend is safer for colors; 'add' is punchier but can clip highlights." - ) - ) - - # Required paths - parser.add_argument("--data", required=True, - help="Path to the Data root (contains the noon folder). Sibling hour folders 0100..2400 will be created here.") - parser.add_argument("--noon", default="1200", - help="Name of the noon subfolder under --data (default: 1200).") - - # Scope limiting - parser.add_argument("--only-hour", type=int, - help="Process a single hour (100..2400 step 100, excluding 1200). Example: --only-hour 2400") - parser.add_argument("--only-file", - help="Process a single *_lights.pcx (filename or relative path under the noon folder).") - - # Light keys & per-key styles - parser.add_argument("--light-key", action="append", default=["#00feff"], - help=( - "Placeholder color(s) in *_lights.pcx that mark light sources.\n" - "Repeat the flag for multiple keys. Accepts '#rrggbb' or 'R,G,B'.\n" - "Keys referenced in --light-style are auto-included; you don't need to repeat them." - )) - parser.add_argument("--light-style", action="append", default=[], - help=( - "Per-key overrides (tints/strengths/shapes). Format (use ';' or ',' between fields):\n" - " \"key=#00feff; core=#fff87a; glow=#ff8a20; core_gain=1.6; halo_gain=4.0;\n" - " halo_sep=0.75; halo_gamma=1.35; core_radius=1.2; halo_radius=14; highlight=0.6\"\n" - "Only 'key' is required. Any provided numeric field overrides the global default\n" - "for that key. Colors accept '#rrggbb' or 'R,G,B'." - )) - - # Global defaults (each can be overridden per-key via --light-style) - parser.add_argument("--core-radius", type=float, default=1.1, - help="Gaussian blur radius (pixels) of the bright core. Higher = wider/softer core.") - parser.add_argument("--halo-radius", type=float, default=13.0, - help="Gaussian blur radius (pixels) of the outer halo. Higher = glow spreads further outward.") - parser.add_argument("--core-gain", type=float, default=2.1, - help="Intensity multiplier for the core alpha (brightness/opacity of the center). Higher = brighter core.") - parser.add_argument("--halo-gain", type=float, default=20.0, - help="Intensity multiplier for the halo alpha (strength of the outer glow). Higher = stronger/fatter halo.") - parser.add_argument("--core-color", type=str, default="#ff8a20", - help="Tint color for the bright core (e.g., '#fff87a' for warm yellow).") - parser.add_argument("--glow-color", type=str, default="#dc6a00", - help="Tint color for the outer halo (e.g., '#ff8a20' for orange).") - parser.add_argument("--highlight-gain", type=float, default=0.6, - help="Extra white highlight added from the core mask (0..~1 typical). Higher = hotter specular highlight.") - - # Size-aware modulation (lets larger light clusters feel brighter/bigger) - parser.add_argument("--size-boost", type=float, default=1.1, - help="How much cluster size increases intensity (0 disables). Higher = large groups pop more.") - parser.add_argument("--size-radius", type=float, default=3.5, - help="Neighborhood radius (pixels) when measuring cluster size. Higher = smoother/broader size effect.") - parser.add_argument("--size-gamma", type=float, default=0.75, - help="Gamma on the size map. <1 emphasizes medium clusters; >1 favors only the largest clusters.") - - # Clipping against magenta/green background - parser.add_argument("--clip-interior", type=str, default="yes", choices=["yes","no"], - help="If 'yes', lights only affect non-transparent interior (avoids glow on MAGENTA/GREEN). Recommended: yes.") - parser.add_argument("--clip-erode", type=int, default=0, - help="Erode the interior mask by N pixels. Higher = more conservative (keeps glow off edges).") - - # Halo shaping & blend mode - parser.add_argument("--halo-sep", type=float, default=0.75, - help="0..1: subtracts a fraction of the core from the halo. 0 = seamless merge; 1 = distinct outer ring.") - parser.add_argument("--halo-gamma", type=float, default=1.4, - help="Gamma on the halo-only mask. >1 pushes energy outward (softer tail); <1 concentrates near source.") - parser.add_argument("--blend-mode", type=str, default="screen", choices=["screen","add"], - help="How layers combine. 'screen' (default) is safer; 'add' is punchier but can clip highlights.") - - args = parser.parse_args() - - light_keys = parse_rgb_list(args.light_key) - styles = parse_styles(args.light_style) - core_color = parse_rgb_one(args.core_color) - glow_color = parse_rgb_one(args.glow_color) - - process_tree( - data_dir=args.data, noon_subfolder=args.noon, - light_keys=light_keys, styles=styles, - core_radius=args.core_radius, halo_radius=args.halo_radius, - core_gain=args.core_gain, halo_gain=args.halo_gain, - core_color=core_color, glow_color=glow_color, - size_boost=args.size_boost, size_radius=args.size_radius, size_gamma=args.size_gamma, - clip_interior=(args.clip_interior=="yes"), - clip_erode=args.clip_erode, - highlight_gain=args.highlight_gain, blend_mode=args.blend_mode, - halo_sep=args.halo_sep, halo_gamma=args.halo_gamma, - only_hour=args.only_hour, only_file=args.only_file - ) - - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Civ 3 city lights compositor for *_lights.pcx +- Recursive over Data/1200 → writes siblings 0100..2400 +- Multiple --light-key values (union mask) +- **Per-light-key styles** via --light-style: per-key core/glow colors and optional overrides +- Night (19..24,1..6): also replaces non-lights file +- Pins magenta #ff00ff to palette index 255; removes #00ff00 from palette +""" + +import argparse, os, math, shutil +from typing import List, Tuple, Dict, Optional +from PIL import Image, ImageChops, ImageFilter +from argparse import RawTextHelpFormatter + +MAGENTA = (255, 0, 255) +GREEN = (0, 255, 0) + +# ---------- parsing ---------- + +def parse_rgb_one(s: str) -> Tuple[int,int,int]: + s = s.strip() + if s.startswith("#"): + s = s[1:]; assert len(s)==6, "Hex color must be #rrggbb" + return int(s[0:2],16), int(s[2:4],16), int(s[4:6],16) + if "," in s: + a = [int(p) for p in s.split(",")]; assert len(a)==3, "RGB must be R,G,B" + return tuple(max(0,min(255,v)) for v in a) # type: ignore + raise ValueError("Color must be '#rrggbb' or 'R,G,B'") + +def parse_rgb_list(values: List[str]) -> List[Tuple[int,int,int]]: + out: List[Tuple[int,int,int]] = [] + for raw in values or []: + tokens = [t for t in raw.replace(";", " ").split() if t] + for tok in tokens: + out.append(parse_rgb_one(tok)) + if not out: out = [(0,254,255)] + dedup, seen = [], set() + for c in out: + if c not in seen: seen.add(c); dedup.append(c) + return dedup + +def parse_styles(values: List[str]) -> Dict[Tuple[int,int,int], Dict[str,object]]: + """ + --light-style "key=#00feff; core=#fff87a; glow=#ff8a20; core_gain=1.6; halo_gain=4.0; halo_sep=0.75; halo_gamma=1.35; core_radius=1.2; halo_radius=14; highlight=0.6" + Accepts ';' or ',' separators. Only 'key' is required; others override globals for that key. + """ + styles: Dict[Tuple[int,int,int], Dict[str,object]] = {} + for raw in values or []: + parts = [p.strip() for p in raw.replace(",", ";").split(";") if p.strip()] + kv: Dict[str,str] = {} + for p in parts: + if "=" in p: + k,v = p.split("=",1); kv[k.strip().lower()] = v.strip() + if "key" not in kv: raise SystemExit("Each --light-style must include key=") + key_rgb = parse_rgb_one(kv["key"]) + entry: Dict[str,object] = {} + if "core" in kv: entry["core_color"] = parse_rgb_one(kv["core"]) + if "glow" in kv: entry["glow_color"] = parse_rgb_one(kv["glow"]) + for numk in ["core_gain","halo_gain","core_radius","halo_radius","halo_sep","halo_gamma","highlight","size_boost","size_radius","size_gamma"]: + if numk in kv: + entry[numk] = float(kv[numk]) + styles[key_rgb] = entry + return styles + +# ---------- time window ---------- + +def hour_weight_lights(hour_1_24: int, start: float = 18.0, end: float = 6.0, floor: float = 0.80) -> float: + h = float(hour_1_24) % 24.0 + inwin = (h >= start) or (h <= end) + if not inwin: return 0.0 + L = (24.0 - start) + end + p = (h - start) if (h >= start) else ((24.0 - start) + h) + mid = 0.5*L; t = abs(p - mid)/mid + w = floor + (1.0 - floor)*0.5*(1.0 + math.cos(math.pi * t)) + return max(0.0, min(1.0, w)) + +def is_night_hour(hour_1_24: int) -> bool: + return (18 <= hour_1_24 <= 24) or (1 <= hour_1_24 <= 6) + +# ---------- palette ---------- + +def get_palette(image: Image.Image) -> List[int]: + pal = image.getpalette() or [] + if len(pal) < 256*3: pal += [0]*(256*3 - len(pal)) + return pal[:256*3] + +def put_palette(image: Image.Image, palette: List[int]) -> None: + if len(palette) < 256*3: palette += [0]*(256*3 - len(palette)) + image.putpalette(palette[:256*3]) + +def ensure_palette_has_colors(image: Image.Image, colors: List[Tuple[int,int,int]]) -> List[int]: + pal = get_palette(image) + to_add = [c for c in colors if find_color_index(pal,c)==-1] + if not to_add: return pal + hist = image.histogram() if image.mode=='P' else None + candidates = sorted(range(256), key=(lambda i: hist[i])) if (hist and len(hist)==256) else list(range(255,-1,-1)) + protected=set() + for rgb in colors+[MAGENTA]: + idx = find_color_index(pal, rgb) + if idx!=-1: protected.add(idx) + replace=[] + for i in candidates: + if i in protected: continue + replace.append(i) + if len(replace)>=len(to_add): break + if len(replace) int: + r,g,b = rgb + for i in range(256): + if palette[3*i]==r and palette[3*i+1]==g and palette[3*i+2]==b: return i + return -1 + +def quantize_to_p_256(img: Image.Image) -> Image.Image: + try: + dnone = Image.Dither.NONE + except Exception: + dnone = getattr(Image, "NONE", 0) + rgb = img.convert('RGB') + try: + return rgb.quantize(colors=256, method=Image.FASTOCTREE, dither=dnone) + except Exception: + return rgb.quantize(colors=256, dither=dnone) + +def force_magenta_at_255(im: Image.Image) -> int: + pal = get_palette(im) + old255 = (pal[3*255], pal[3*255+1], pal[3*255+2]) + idx_mag = find_color_index(pal, MAGENTA) + if idx_mag == -1: + pal = ensure_palette_has_colors(im, [MAGENTA]); put_palette(im, pal) + pal = get_palette(im); idx_mag = find_color_index(pal, MAGENTA) + if idx_mag == 255: return 255 + pal[3*255:3*255+3]=list(MAGENTA); pal[3*idx_mag:3*idx_mag+3]=list(old255) + put_palette(im, pal); return idx_mag + +# ---------- image ops ---------- + +def color_equal(img_rgb: Image.Image, color: Tuple[int,int,int]) -> Image.Image: + w,h = img_rgb.size + solid = Image.new('RGB',(w,h),color) + diff = ImageChops.difference(img_rgb, solid) + return diff.convert('L').point(lambda v: 255 if v==0 else 0, mode='L') + +def apply_gamma_L(imgL: Image.Image, gamma: float) -> Image.Image: + gamma = max(0.05, float(gamma)) + lut = [min(255, int(round((i/255.0) ** gamma * 255))) for i in range(256)] + return imgL.point(lut, mode='L') + +def scale_L(imgL: Image.Image, factor: float) -> Image.Image: + factor = max(0.0, float(factor)) + return imgL.point(lambda v: 255 if v*factor >= 255 else int(v*factor)) + +def screen_blend(a: Image.Image, b: Image.Image) -> Image.Image: + try: + return ImageChops.screen(a,b) + except AttributeError: + return ImageChops.invert(ImageChops.multiply(ImageChops.invert(a), ImageChops.invert(b))) + +# ---------- masks & glows ---------- + +def build_interior_mask(base_bg: Image.Image, clip: bool, erode_px: int) -> Image.Image: + if not clip: return Image.new('L', base_bg.size, 255) + base_rgb = base_bg.convert('RGB') + mag = color_equal(base_rgb, MAGENTA) + grn = color_equal(base_rgb, GREEN) + interior = ImageChops.invert(ImageChops.add(mag, grn, scale=1.0)) + if erode_px>0: + k = max(1,int(erode_px)); interior = interior.filter(ImageFilter.MinFilter(2*k+1)) + return interior + +def build_glow_maps(mask_bin: Image.Image, interior_mask: Image.Image, wtime: float, + core_radius: float, halo_radius: float, + core_gain: float, halo_gain: float, + size_boost: float, size_radius: float, size_gamma: float, + halo_sep: float, halo_gamma: float): + blur_core = mask_bin.filter(ImageFilter.GaussianBlur(radius=core_radius)) + blur_halo = mask_bin.filter(ImageFilter.GaussianBlur(radius=halo_radius)) + + if size_boost>0.0 and size_radius>0: + density = mask_bin.filter(ImageFilter.BoxBlur(radius=size_radius)).convert('L') + density = apply_gamma_L(density, max(0.05, size_gamma)) + boost = scale_L(density, size_boost * wtime) + blur_core = ImageChops.add(blur_core, boost, scale=1.0) + blur_halo = ImageChops.add(blur_halo, boost, scale=1.0) + + halo_sep = max(0.0, min(1.0, halo_sep)) + halo_only = ImageChops.subtract(blur_halo, blur_core.point(lambda v:int(v*halo_sep)), scale=1.0, offset=0) if halo_sep>0 else blur_halo + halo_only = apply_gamma_L(halo_only, halo_gamma) + + core_alpha = scale_L(blur_core, wtime*max(0.0, core_gain)) + halo_alpha = scale_L(halo_only, wtime*max(0.0, halo_gain)) + core_alpha = ImageChops.multiply(core_alpha, interior_mask) + halo_alpha = ImageChops.multiply(halo_alpha, interior_mask) + return core_alpha, halo_alpha + +def layer_from_alpha(color: Tuple[int,int,int], alphaL: Image.Image) -> Image.Image: + w,h = alphaL.size + solid = Image.new('RGB',(w,h),color) + return Image.composite(solid, Image.new('RGB',(w,h),(0,0,0)), alphaL) + +# ---------- compositor with per-key styles ---------- + +def build_composite_with_styles(base_bg_rgba: Image.Image, + mask_source_rgb: Image.Image, + hour_1_24: int, + keys: List[Tuple[int,int,int]], + styles: Dict[Tuple[int,int,int], Dict[str,object]], + # global defaults: + core_radius: float, halo_radius: float, + core_gain: float, halo_gain: float, + core_color: Tuple[int,int,int], + glow_color: Tuple[int,int,int], + size_boost: float, size_radius: float, size_gamma: float, + clip_interior: bool, clip_erode: int, + highlight_gain: float, blend_mode: str, + halo_sep: float, halo_gamma: float) -> Image.Image: + wtime = hour_weight_lights(hour_1_24) + if wtime <= 0.0: # just return unchanged base (still save with palette fix later) + return base_bg_rgba.copy() + + interior = build_interior_mask(base_bg_rgba, clip_interior, clip_erode) + comp = base_bg_rgba.convert('RGB') + + # Ensure every styled key is included in keys + keys_set = {k for k in keys} + for k in styles.keys(): + keys_set.add(k) + keys_order = list(keys_set) + + for key_rgb in keys_order: + # Per-key mask + mask_bin = color_equal(mask_source_rgb, key_rgb) + if mask_bin.getbbox() is None: + continue + + st = styles.get(key_rgb, {}) + k_core_color = st.get("core_color", core_color) + k_glow_color = st.get("glow_color", glow_color) + k_core_gain = float(st.get("core_gain", core_gain)) + k_halo_gain = float(st.get("halo_gain", halo_gain)) + k_core_rad = float(st.get("core_radius", core_radius)) + k_halo_rad = float(st.get("halo_radius", halo_radius)) + k_halo_sep = float(st.get("halo_sep", halo_sep)) + k_halo_gamma = float(st.get("halo_gamma", halo_gamma)) + k_size_boost = float(st.get("size_boost", size_boost)) + k_size_radius= float(st.get("size_radius", size_radius)) + k_size_gamma = float(st.get("size_gamma", size_gamma)) + k_highlight = float(st.get("highlight", highlight_gain)) + + core_alpha, halo_alpha = build_glow_maps( + mask_bin, interior, wtime, + k_core_rad, k_halo_rad, + k_core_gain, k_halo_gain, + k_size_boost, k_size_radius, k_size_gamma, + k_halo_sep, k_halo_gamma + ) + core_layer = layer_from_alpha(k_core_color, core_alpha) + halo_layer = layer_from_alpha(k_glow_color, halo_alpha) + + if blend_mode == "add": + comp = ImageChops.add(comp, core_layer, scale=1.0) + comp = ImageChops.add(comp, halo_layer, scale=1.0) + else: + comp = screen_blend(comp, core_layer) + comp = screen_blend(comp, halo_layer) + + if k_highlight > 0.0: + hl = scale_L(core_alpha, k_highlight) + comp = ImageChops.add(comp, Image.composite(Image.new('RGB',comp.size,(255,255,255)), + Image.new('RGB',comp.size,(0,0,0)), hl), scale=1.0) + + return comp.convert('RGBA') + +# ---------- save with palette fixes ---------- + +def save_with_palette_and_magic(comp_rgba: Image.Image, out_path: str, base_for_magic_rgb: Image.Image) -> None: + imP = quantize_to_p_256(comp_rgba) + pal_after = ensure_palette_has_colors(imP, [MAGENTA]); put_palette(imP, pal_after) + replacement_idx = force_magenta_at_255(imP) + dst_px = imP.load(); src_px = base_for_magic_rgb.load(); w,h = imP.size + for y in range(h): + for x in range(w): + r,g,b = src_px[x,y]; cur = dst_px[x,y] + if (r,g,b)==MAGENTA: + dst_px[x,y]=255 + elif (r,g,b)==GREEN: + dst_px[x,y]=255 + elif cur==255 and replacement_idx!=255: + dst_px[x,y]=replacement_idx + # Remove #00ff00 from palette entirely if present. + pal_after = get_palette(imP) + for i in range(256): + if (pal_after[3*i], pal_after[3*i+1], pal_after[3*i+2]) == GREEN: + pal_after[3*i:3*i+3] = [0, 0, 0] + put_palette(imP, pal_after) + os.makedirs(os.path.dirname(out_path), exist_ok=True) + imP.save(out_path, format='PCX') + +# ---------- driver ---------- + +def process_tree(data_dir: str, noon_subfolder: str, + light_keys: List[Tuple[int,int,int]], + styles: Dict[Tuple[int,int,int], Dict[str,object]], + core_radius: float, halo_radius: float, + core_gain: float, halo_gain: float, + core_color: Tuple[int,int,int], glow_color: Tuple[int,int,int], + size_boost: float, size_radius: float, size_gamma: float, + clip_interior: bool, clip_erode: int, + highlight_gain: float, blend_mode: str, + halo_sep: float, halo_gamma: float, + only_hour: Optional[int]=None, only_file: Optional[str]=None) -> None: + + base_dir = os.path.join(data_dir, noon_subfolder) + if not os.path.isdir(base_dir): raise SystemExit(f"No such folder: {base_dir}") + + hours = [h for h in range(100, 2500, 100) if h != 1200] + if only_hour is not None: + if only_hour == 1200: raise SystemExit("1200 is the base. Choose another hour.") + if only_hour % 100 != 0 or only_hour < 100 or only_hour > 2400: + raise SystemExit("--only-hour must be one of 100,200,...,2400.") + hours = [only_hour] + + norm_only = os.path.normcase(only_file) if only_file else None + + # Ensure styled keys are included even if not explicitly listed in --light-key + for k in styles.keys(): + if k not in light_keys: + light_keys.append(k) + + for dirpath, _, filenames in os.walk(base_dir): + rel_dir = os.path.relpath(dirpath, base_dir); rel_dir = "" if rel_dir=="." else rel_dir + for hhh in hours: + os.makedirs(os.path.join(data_dir, f"{hhh:04d}", rel_dir), exist_ok=True) + + lights_files = [f for f in filenames if f.lower().endswith("_lights.pcx")] + for lights_name in lights_files: + if norm_only: + rel_file = os.path.normcase(os.path.join(rel_dir, lights_name)) + if norm_only != os.path.normcase(lights_name) and norm_only != rel_file: continue + + plain_name = lights_name[:-len("_lights.pcx")] + ".pcx" + noon_lights = os.path.join(dirpath, lights_name) + noon_plain = os.path.join(dirpath, plain_name) + + for hhh in hours: + hour_1_24 = hhh // 100 + hour_dir = os.path.join(data_dir, f"{hhh:04d}", rel_dir) + out_lights= os.path.join(hour_dir, lights_name) + out_plain = os.path.join(hour_dir, plain_name) + print(f"Processing {hhh:04d}: {lights_name} -> {out_lights}") + + if os.path.exists(out_plain): + base_bg = Image.open(out_plain).convert('RGBA'); base_rgb = Image.open(out_plain).convert('RGB') + elif os.path.exists(noon_plain): + base_bg = Image.open(noon_plain).convert('RGBA'); base_rgb = Image.open(noon_plain).convert('RGB') + else: + base_bg = Image.open(noon_lights).convert('RGBA'); base_rgb = Image.open(noon_lights).convert('RGB') + + mask_src = Image.open(noon_lights).convert('RGB') + + comp = build_composite_with_styles( + base_bg_rgba=base_bg, mask_source_rgb=mask_src, hour_1_24=hour_1_24, + keys=light_keys, styles=styles, + core_radius=core_radius, halo_radius=halo_radius, + core_gain=core_gain, halo_gain=halo_gain, + core_color=core_color, glow_color=glow_color, + size_boost=size_boost, size_radius=size_radius, size_gamma=size_gamma, + clip_interior=clip_interior, clip_erode=clip_erode, + highlight_gain=highlight_gain, blend_mode=blend_mode, + halo_sep=halo_sep, halo_gamma=halo_gamma + ) + + if is_night_hour(hour_1_24): + # At night, also write/replace the plain file with the composite + save_with_palette_and_magic(comp, out_plain, base_rgb) + + # ---- Night-only cleanup: remove the hour's *_lights.pcx copy ---- + if os.path.exists(out_lights) and ("annotations" not in out_lights.lower()): + try: + os.remove(out_lights) + except Exception as e: + print(f"WARNING: Could not delete {out_lights}: {e}") + else: + # Daytime: ensure a plain exists; prefer noon_plain if available + if not os.path.exists(out_plain): + if os.path.exists(noon_plain): + os.makedirs(os.path.dirname(out_plain), exist_ok=True) + shutil.copyfile(noon_plain, out_plain) + else: + save_with_palette_and_magic(base_bg, out_plain, base_rgb) + + +def main(): + parser = argparse.ArgumentParser( + description=( + "Render glowing city lights from *_lights.pcx files.\n" + "• Multiple light-keys supported (+ per-key styles)\n" + "• Night hours (19..24,1..6) also overwrite the paired non-lights file\n" + "• MAGENTA pinned to index 255; GREEN removed from palette if present" + ), + formatter_class=RawTextHelpFormatter, + epilog=( + "Examples:\n" + " Basic (one key):\n" + " python civ3_city_lights.py --data ./Data --noon 1200 \\\n" + " --light-key \"#00feff\" --core-color \"#fff87a\" --glow-color \"#ff8a20\"\n" + "\n" + " Multiple keys with per-key styles:\n" + " python civ3_city_lights.py --data ./Data --noon 1200 \\\n" + " --light-key \"#00feff\" --light-key \"#fe00ff\" \\\n" + " --light-style \"key=#00feff; core=#fff87a; glow=#ff9a2b; halo_gain=18; halo_radius=14\" \\\n" + " --light-style \"key=#fe00ff; core=#ffd0ff; glow=#e07aff; core_gain=1.4; halo_gain=12\"\n" + "\n" + " Make large light clusters pop more:\n" + " --size-boost 1.2 --size-radius 4 --size-gamma 0.8\n" + "\n" + "Notes:\n" + " • Increase --halo-radius and --halo-gain for a bigger, softer glow.\n" + " • If you see a dark ring between core/halo, reduce --halo-sep or increase --halo-gamma.\n" + " • 'screen' blend is safer for colors; 'add' is punchier but can clip highlights." + ) + ) + + # Required paths + parser.add_argument("--data", required=True, + help="Path to the Data root (contains the noon folder). Sibling hour folders 0100..2400 will be created here.") + parser.add_argument("--noon", default="1200", + help="Name of the noon subfolder under --data (default: 1200).") + + # Scope limiting + parser.add_argument("--only-hour", type=int, + help="Process a single hour (100..2400 step 100, excluding 1200). Example: --only-hour 2400") + parser.add_argument("--only-file", + help="Process a single *_lights.pcx (filename or relative path under the noon folder).") + + # Light keys & per-key styles + parser.add_argument("--light-key", action="append", default=["#00feff"], + help=( + "Placeholder color(s) in *_lights.pcx that mark light sources.\n" + "Repeat the flag for multiple keys. Accepts '#rrggbb' or 'R,G,B'.\n" + "Keys referenced in --light-style are auto-included; you don't need to repeat them." + )) + parser.add_argument("--light-style", action="append", default=[], + help=( + "Per-key overrides (tints/strengths/shapes). Format (use ';' or ',' between fields):\n" + " \"key=#00feff; core=#fff87a; glow=#ff8a20; core_gain=1.6; halo_gain=4.0;\n" + " halo_sep=0.75; halo_gamma=1.35; core_radius=1.2; halo_radius=14; highlight=0.6\"\n" + "Only 'key' is required. Any provided numeric field overrides the global default\n" + "for that key. Colors accept '#rrggbb' or 'R,G,B'." + )) + + # Global defaults (each can be overridden per-key via --light-style) + parser.add_argument("--core-radius", type=float, default=1.1, + help="Gaussian blur radius (pixels) of the bright core. Higher = wider/softer core.") + parser.add_argument("--halo-radius", type=float, default=13.0, + help="Gaussian blur radius (pixels) of the outer halo. Higher = glow spreads further outward.") + parser.add_argument("--core-gain", type=float, default=2.1, + help="Intensity multiplier for the core alpha (brightness/opacity of the center). Higher = brighter core.") + parser.add_argument("--halo-gain", type=float, default=20.0, + help="Intensity multiplier for the halo alpha (strength of the outer glow). Higher = stronger/fatter halo.") + parser.add_argument("--core-color", type=str, default="#ff8a20", + help="Tint color for the bright core (e.g., '#fff87a' for warm yellow).") + parser.add_argument("--glow-color", type=str, default="#dc6a00", + help="Tint color for the outer halo (e.g., '#ff8a20' for orange).") + parser.add_argument("--highlight-gain", type=float, default=0.6, + help="Extra white highlight added from the core mask (0..~1 typical). Higher = hotter specular highlight.") + + # Size-aware modulation (lets larger light clusters feel brighter/bigger) + parser.add_argument("--size-boost", type=float, default=1.1, + help="How much cluster size increases intensity (0 disables). Higher = large groups pop more.") + parser.add_argument("--size-radius", type=float, default=3.5, + help="Neighborhood radius (pixels) when measuring cluster size. Higher = smoother/broader size effect.") + parser.add_argument("--size-gamma", type=float, default=0.75, + help="Gamma on the size map. <1 emphasizes medium clusters; >1 favors only the largest clusters.") + + # Clipping against magenta/green background + parser.add_argument("--clip-interior", type=str, default="yes", choices=["yes","no"], + help="If 'yes', lights only affect non-transparent interior (avoids glow on MAGENTA/GREEN). Recommended: yes.") + parser.add_argument("--clip-erode", type=int, default=0, + help="Erode the interior mask by N pixels. Higher = more conservative (keeps glow off edges).") + + # Halo shaping & blend mode + parser.add_argument("--halo-sep", type=float, default=0.75, + help="0..1: subtracts a fraction of the core from the halo. 0 = seamless merge; 1 = distinct outer ring.") + parser.add_argument("--halo-gamma", type=float, default=1.4, + help="Gamma on the halo-only mask. >1 pushes energy outward (softer tail); <1 concentrates near source.") + parser.add_argument("--blend-mode", type=str, default="screen", choices=["screen","add"], + help="How layers combine. 'screen' (default) is safer; 'add' is punchier but can clip highlights.") + + args = parser.parse_args() + + light_keys = parse_rgb_list(args.light_key) + styles = parse_styles(args.light_style) + core_color = parse_rgb_one(args.core_color) + glow_color = parse_rgb_one(args.glow_color) + + process_tree( + data_dir=args.data, noon_subfolder=args.noon, + light_keys=light_keys, styles=styles, + core_radius=args.core_radius, halo_radius=args.halo_radius, + core_gain=args.core_gain, halo_gain=args.halo_gain, + core_color=core_color, glow_color=glow_color, + size_boost=args.size_boost, size_radius=args.size_radius, size_gamma=args.size_gamma, + clip_interior=(args.clip_interior=="yes"), + clip_erode=args.clip_erode, + highlight_gain=args.highlight_gain, blend_mode=args.blend_mode, + halo_sep=args.halo_sep, halo_gamma=args.halo_gamma, + only_hour=args.only_hour, only_file=args.only_file + ) + + +if __name__ == "__main__": + main() diff --git a/DayNight/civ3_day_night.py b/DayNight/civ3_day_night.py index d9e6ba23..bd76e3ac 100644 --- a/DayNight/civ3_day_night.py +++ b/DayNight/civ3_day_night.py @@ -1,946 +1,946 @@ -#!/usr/bin/env python3 -""" -civ3_daynight_pcx.py — v4.4 (remove #00FF00 from palette entirely) - -Highlights: -- Half-hour (or any divisor of an hour) time slices via --step-minutes. -- Green→Magenta pixel remap (on by default). -- NEW: After pixel remap, ANY palette entries exactly #00FF00 are replaced with black (#000000), - so #00FF00 no longer exists anywhere in the palette. -- Palette-only tinting; indices preserved (except the optional index remap). -- Noon-neutral zone keeps ~10:00–14:00 close to base 1200. -- Stronger nighttime blue response using the existing --blue knob, - with an additional night-only hue shift (blue up, red/green down). - -Tested knobs (your current favorites work unchanged): - --warmth 1.05 --blue 2.0 --darkness 1.1 --desat 0.85 --sat 1.2 --contrast 1.08 - --sunrise-center 5.0 --sunset-center 18.0 --twilight-width 3.0 - --noon-blend 0.7 --noon-sigma 1.0 -""" - -import argparse -import shutil -from pathlib import Path -from typing import Iterable, List, Sequence, Tuple, Set, Dict, Optional - -from PIL import Image -from civ3_city_lights import is_night_hour -from protected_pixels import PROTECTED_RANGES_ENT_COMPLEX - -# Fallback behavior if the palette is full and we cannot allocate a new index -PROTECTED_FALLBACK_NEIGHBOR_RADIUS = 1 # 1 => 3x3 window, 2 => 5x5, etc. -PROTECTED_GAP_BRIDGE = 1 - -from collections import defaultdict, Counter -from math import sqrt - - -# --------------------------- Helpers for protected ranges --------------------------- - -def _bridge_small_gaps( - ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], - max_gap: int, -) -> List[Tuple[Tuple[int, int], Tuple[int, int]]]: - """ - Merge/bridge adjacent horizontal ranges on the same scanline (same y) - when the gap between them is <= max_gap. Ranges are inclusive. - Input items are ((x1, y), (x2, y)). Non-horizontal ranges are kept as-is. - """ - if max_gap <= 0 or not ranges: - return list(ranges) - - by_y = defaultdict(list) - for (x1, y1), (x2, y2) in ranges: - if y1 != y2: - # Not horizontal; keep separate - by_y[(y1, y2, 'nonh')].append((min(x1, x2), max(x1, x2), y1, y2)) - continue - by_y[y1].append((min(x1, x2), max(x1, x2))) - - out: List[Tuple[Tuple[int, int], Tuple[int, int]]] = [] - - # Re-emit any non-horizontal entries unchanged - for key, spans in list(by_y.items()): - if isinstance(key, tuple) and key[-1] == 'nonh': - for x1, x2, y1, y2 in spans: - out.append(((x1, y1), (x2, y2))) - del by_y[key] - - # Bridge gaps on horizontal scanlines - for y, spans in by_y.items(): - spans.sort() - cur_x1, cur_x2 = spans[0] - for nx1, nx2 in spans[1:]: - gap = nx1 - cur_x2 - 1 # inclusive ranges - if gap <= max_gap: - cur_x2 = max(cur_x2, nx2) - else: - out.append(((cur_x1, y), (cur_x2, y))) - cur_x1, cur_x2 = nx1, nx2 - out.append(((cur_x1, y), (cur_x2, y))) - - return out - - -def clamp_byte(x: float) -> int: - return int(max(0, min(255, round(x)))) - - -def _nudge_if_reserved(nrgb, reserved_set, orig_rgb): - if nrgb in reserved_set: - # Nudge 1 toward original to avoid exact collision - r0, g0, b0 = orig_rgb - r, g, b = nrgb - - def nudge(c, c0): - return clamp_byte(c - 1 if c > c0 else c + 1 if c < c0 else c) - - return (nudge(r, r0), nudge(g, g0), nudge(b, b0)) - return nrgb - - -def _rgb_of_index(pal: List[int], idx: int) -> Tuple[int, int, int]: - return pal[3 * idx], pal[3 * idx + 1], pal[3 * idx + 2] - - -def _color_dist2(a: Tuple[int, int, int], b: Tuple[int, int, int]) -> float: - dr, dg, db = a[0] - b[0], a[1] - b[1], a[2] - b[2] - return dr * dr + dg * dg + db * db - - -def _index_pixel_counts(im: Image.Image) -> Dict[int, int]: - colors = im.getcolors(maxcolors=256 * 256) or [] - return {int(idx): int(cnt) for (cnt, idx) in colors} - - -def _indices_used_in_coords( - im: Image.Image, - ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], -) -> Set[int]: - w, h = im.size - px = im.load() - s: Set[int] = set() - for (x1, y1), (x2, y2) in ranges: - x_start, x_end = (x1, x2) if x1 <= x2 else (x2, x1) - y_start, y_end = (y1, y2) if y1 <= y2 else (y2, y1) - for y in range(max(0, y_start), min(h, y_end + 1)): - for x in range(max(0, x_start), min(w, x_end + 1)): - s.add(int(px[x, y])) - return s - - -def _find_nearest_index( - pal: List[int], - src_idx: int, - allowed: Iterable[int], -) -> Optional[int]: - src_rgb = _rgb_of_index(pal, src_idx) - best = None - best_d2 = 1e18 - for j in allowed: - if j == src_idx: - continue - d2 = _color_dist2(src_rgb, _rgb_of_index(pal, j)) - if d2 < best_d2: - best_d2 = d2 - best = int(j) - return best - - -def _used_palette_indices(im: Image.Image) -> Set[int]: - """ - Return the set of palette indices actually used by the image. - """ - colors = im.getcolors(maxcolors=256 * 256) or [] - used: Set[int] = set() - for _, idx in colors: - used.add(int(idx)) - return used - - -def _free_palette_slots( - im: Image.Image, - pal: List[int], - needed: int, - *, - protected_source_indices: Set[int], # indices that appear inside protected coords - reserved_by_color_rgbs: Set[Tuple[int, int, int]], # magenta/green/light-keys as RGB -) -> int: - """ - Try to free up to `needed` palette slots by remapping the *least-used* indices - (that are NOT protected and NOT reserved-by-color) to their nearest-color neighbors. - Returns the number of slots actually freed. Pixels are rewritten in-place. - """ - if needed <= 0: - return 0 - - w, h = im.size - px = im.load() - counts = _index_pixel_counts(im) - used_indices = set(counts.keys()) - - # Build sets for constraints - reserved_by_color_indices: Set[int] = set() - for i in range(256): - if i in used_indices: - rgb = (pal[3 * i], pal[3 * i + 1], pal[3 * i + 2]) - if rgb in reserved_by_color_rgbs: - reserved_by_color_indices.add(i) - - forbidden = set(protected_source_indices) | reserved_by_color_indices - - # Candidates we are allowed to merge away - candidates = [i for i in used_indices if i not in forbidden] - - if not candidates: - return 0 - - # Sort by ascending usage (least used first) - candidates.sort(key=lambda i: counts.get(i, 0)) - - freed = 0 - allowed_targets = set(used_indices) - forbidden - - for src_idx in candidates: - if freed >= needed: - break - if src_idx not in used_indices: - continue - - options = allowed_targets - {src_idx} - if not options: - continue - - tgt = _find_nearest_index(pal, src_idx, options) - if tgt is None: - continue - - # Remap all pixels from src_idx -> tgt - for y in range(h): - for x in range(w): - if px[x, y] == src_idx: - px[x, y] = tgt - - used_indices.discard(src_idx) - allowed_targets.discard(src_idx) - freed += 1 - - return freed - - -def _sample_neighbor_index(px, x: int, y: int, w: int, h: int, r: int) -> Optional[int]: - """ - Return the most common palette index in the (2r+1)x(2r+1) neighborhood - around (x,y), excluding the center pixel. If nothing valid, return None. - """ - if r <= 0: - return None - xs = range(max(0, x - r), min(w, x + r + 1)) - ys = range(max(0, y - r), min(h, y + r + 1)) - counts = Counter() - for yy in ys: - for xx in xs: - if xx == x and yy == y: - continue - counts[int(px[xx, yy])] += 1 - return counts.most_common(1)[0][0] if counts else None - - -def _protect_exact_pixels_by_index( - im: Image.Image, - pal: List[int], - ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], - reserved_by_color_rgbs: Set[Tuple[int, int, int]] = set(), -) -> Set[int]: - """ - Ensure protected coords keep their original (noon) colors by duplicating indices. - If the palette is full, first free slots by merging least-used non-protected indices - into nearest neighbors. If still short on slots, fall back to neighbor sampling. - Returns set of dedicated reserved indices. - """ - assert im.mode == "P", "Image must be paletted ('P')" - w, h = im.size - px = im.load() - - protected_src_indices = _indices_used_in_coords(im, ranges) - - used_now = _used_palette_indices(im) - free_now = [i for i in range(256) if i not in used_now] - need = max(0, len(protected_src_indices) - len(free_now)) - - if need > 0: - _ = _free_palette_slots( - im, - pal, - need, - protected_source_indices=protected_src_indices, - reserved_by_color_rgbs=reserved_by_color_rgbs, - ) - - # Recompute used/free after freeing - used = _used_palette_indices(im) - free_pool = [i for i in range(256) if i not in used] - - index_map: Dict[int, int] = {} - reserved_indices: Set[int] = set() - - radius = int(PROTECTED_FALLBACK_NEIGHBOR_RADIUS) - - # Duplicate on first encounter of a src index - for (x1, y1), (x2, y2) in ranges: - x_start, x_end = (x1, x2) if x1 <= x2 else (x2, x1) - y_start, y_end = (y1, y2) if y1 <= y2 else (y2, y1) - - for y in range(y_start, y_end + 1): - if not (0 <= y < h): - continue - for x in range(x_start, x_end + 1): - if not (0 <= x < w): - continue - - orig_idx = int(px[x, y]) - - dup = index_map.get(orig_idx) - if dup is not None: - px[x, y] = dup - continue - - if free_pool: - dup_idx = free_pool.pop(0) - r, g, b = pal[3 * orig_idx: 3 * orig_idx + 3] - pal[3 * dup_idx + 0] = r - pal[3 * dup_idx + 1] = g - pal[3 * dup_idx + 2] = b - index_map[orig_idx] = dup_idx - reserved_indices.add(dup_idx) - px[x, y] = dup_idx - continue - - # LAST RESORT: neighbor sampling - neighbor_idx = _sample_neighbor_index(px, x, y, w, h, radius) - if neighbor_idx is not None: - px[x, y] = int(neighbor_idx) - else: - print(f"WARNING: No palette slots and no neighbors for ({x},{y}).") - - return reserved_indices - - -# --------------------------- CLI & helpers --------------------------- - -def parse_rgb(s: str) -> Tuple[int, int, int]: - s = s.strip() - if s.startswith("#"): - s = s[1:] - if len(s) != 6: - raise ValueError(f"Bad hex color: #{s}") - return tuple(int(s[i:i + 2], 16) for i in (0, 2, 4)) # type: ignore - if "," in s: - parts = [p.strip() for p in s.split(",")] - if len(parts) != 3: - raise ValueError(f"Bad RGB list: {s}") - return tuple(int(p) for p in parts) # type: ignore - raise ValueError(f"Unrecognized color format: {s}") - - -def time_labels(step_minutes: int) -> List[str]: - """ - Generate HHMM labels from step to 23:59 stepwise; exclude 0000; add 2400. - For step=60: 0100..2300 + 2400 - For step=30: 0030, 0100, 0130..2330 + 2400 - """ - if step_minutes <= 0 or 60 % step_minutes != 0: - raise ValueError("--step-minutes must be a positive divisor of 60 (e.g., 5,10,15,20,30,60).") - labels: List[str] = [] - total_minutes = 24 * 60 - m = step_minutes - while m < total_minutes: - h = m // 60 - mm = m % 60 - labels.append(f"{h:02d}{mm:02d}") - m += step_minutes - labels.append("2400") - return labels - - -# --------------------------- TONEMAP MODEL --------------------------- - -def _gauss(x: float, mu: float, sigma: float) -> float: - from math import exp - if sigma <= 0.0: - return 0.0 - return exp(-0.5 * ((x - mu) / sigma) ** 2) - - -def hour_adjustments( - hour_value: float, - *, - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, -) -> dict: - """ - hour_value can be fractional (e.g., 19.5 for 19:30). Period is 24h. - Returns a dict with per-channel multipliers, gray blend, brightness, - and 'night' + 'blue_push' factors for night-only hue shift. - """ - from math import cos, pi - - h = hour_value % 24.0 - - # Daylight (cosine): 1 at noon, ~0 at midnight - daylight = max(0.0, cos(pi * (h - 12.0) / 12.0)) # 0..1 - night = 1.0 - daylight - - # Warmth around sunrise/sunset - warmth = 0.85 * (_gauss(h, sunrise_center, twilight_sigma) + - _gauss(h, sunset_center, twilight_sigma)) - warmth *= warmth_scale - - # Brightness: darker at night; scaled by darkness_scale (>1 = darker nights) - base_brightness = 0.60 + 0.40 * daylight - night_darkening = 1.0 - (0.12 * (darkness_scale - 1.0) * night) - brightness = base_brightness * night_darkening - - # Channel multipliers - r_mul = 0.97 + 0.12 * daylight + 0.30 * warmth - g_mul = 0.97 + 0.12 * daylight + 0.12 * warmth - b_mul = 0.97 + 0.12 * daylight - 0.18 * warmth + (0.28 * blue_scale) * night - - # Desaturation (toward gray) stronger at night; scaled by desat_scale - gray_blend = (0.10 + 0.50 * night) * desat_scale - gray_blend = min(max(gray_blend, 0.0), 0.85) - - # Night-only blue push factor (extra hue shift at night) - blue_push = max(0.0, blue_scale - 1.0) * night # 0 at day, up to (blue-1) at night - - # Clamp gentle bounds - r_mul = min(max(r_mul, 0.65), 1.45) - g_mul = min(max(g_mul, 0.65), 1.40) - b_mul = min(max(b_mul, 0.65), 1.55) - - return dict( - brightness=brightness, - r_mul=r_mul, - g_mul=g_mul, - b_mul=b_mul, - gray_blend=gray_blend, - night=night, - blue_push=blue_push, - ) - - -def _apply_saturation(rgb: Tuple[float, float, float], sat: float) -> Tuple[float, float, float]: - r, g, b = rgb - gray = (r + g + b) / 3.0 - r = gray + (r - gray) * sat - g = gray + (g - gray) * sat - b = gray + (b - gray) * sat - return r, g, b - - -def _apply_contrast(rgb: Tuple[float, float, float], contrast: float) -> Tuple[float, float, float]: - r, g, b = rgb - r = 128 + (r - 128) * contrast - g = 128 + (g - 128) * contrast - b = 128 + (b - 128) * contrast - return r, g, b - - -def _apply_night_blue_push( - rgb: Tuple[float, float, float], - blue_push: float, -) -> Tuple[float, float, float]: - """ - Extra night-only hue shift: - - Slightly reduces R and G - - Increases B - 'blue_push' is ~ (blue_scale - 1) * night, so this is zero in daytime. - """ - if blue_push <= 0.0: - return rgb - r, g, b = rgb - c = blue_push - r *= (1.0 - 0.15 * c) - g *= (1.0 - 0.10 * c) - b *= (1.0 + 0.35 * c) - return r, g, b - - -def tint_rgb( - rgb: Tuple[int, int, int], - params: dict, - *, - sat_boost: float, - contrast: float, -) -> Tuple[int, int, int]: - r, g, b = rgb - r_f = r * params["r_mul"] * params["brightness"] - g_f = g * params["g_mul"] * params["brightness"] - b_f = b * params["b_mul"] * params["brightness"] - - gray = (r_f + g_f + b_f) / 3.0 - t = params["gray_blend"] - r_f = (1 - t) * r_f + t * gray - g_f = (1 - t) * g_f + t * gray - b_f = (1 - t) * b_f + t * gray - - # Global saturation, then extra night-only blue hue push, then contrast - r_f, g_f, b_f = _apply_saturation((r_f, g_f, b_f), sat_boost) - r_f, g_f, b_f = _apply_night_blue_push((r_f, g_f, b_f), params.get("blue_push", 0.0)) - r_f, g_f, b_f = _apply_contrast((r_f, g_f, b_f), contrast) - - return (clamp_byte(r_f), clamp_byte(g_f), clamp_byte(b_f)) - - -# --------------------------- Noon-neutral weighting --------------------------- - -def _smoothstep01(t: float) -> float: - """Cubic smoothstep on [0,1].""" - if t <= 0.0: - return 0.0 - if t >= 1.0: - return 1.0 - return t * t * (3.0 - 2.0 * t) - - -def _interval_membership(x: float, a: float, b: float, soft: float) -> float: - """ - Smooth membership of time-of-day x (0..24) inside interval [a,b] (hours), - with soft edge width 'soft' (hours). Supports wrapped intervals (a>b). - Returns 0..1. - """ - x = x % 24.0 - a = a % 24.0 - b = b % 24.0 - soft = max(0.0, soft) - - def segment_membership(x: float, s: float, e: float, soft: float) -> float: - if soft <= 0.0: - return 1.0 if (s <= x <= e) else 0.0 - - if s - soft <= x < s: - t = (x - (s - soft)) / soft - return _smoothstep01(t) - - if s <= x <= e: - return 1.0 - - if e < x <= e + soft: - t = (x - e) / soft - return 1.0 - _smoothstep01(t) - - return 0.0 - - if a <= b: - return segment_membership(x, a, b, soft) - else: - m1 = segment_membership(x, a, 24.0, soft) - m2 = segment_membership(x, 0.0, b, soft) - return max(m1, m2) - - -def _noon_weight(hour_value: float, blend: float, sigma: float, - w_start: float, w_end: float, w_soft: float) -> float: - """ - Combined noon weight in 0..1: - - Gaussian around 12:00 with width 'sigma' (hours), scaled by 'blend'. - - Smooth interval window [w_start, w_end] with soft edges 'w_soft', - also scaled by 'blend'. - """ - try: - h = hour_value % 24.0 - except Exception: - h = 0.0 - blend = float(blend) if blend is not None else 0.0 - sigma = float(sigma) if sigma is not None else 0.0 - w_start = float(w_start) if w_start is not None else 10.0 - w_end = float(w_end) if w_end is not None else 14.0 - w_soft = max(0.0, float(w_soft) if w_soft is not None else 0.7) - - if blend <= 0.0: - return 0.0 - - from math import exp - d = abs(h - 12.0) - d = min(d, 24.0 - d) - g = exp(-0.5 * (d / sigma) ** 2) if sigma > 0.0 else 0.0 - g *= blend - - window_m = _interval_membership(h, w_start, w_end, w_soft) * blend - - w = max(g, window_m) - if w < 0.0: - return 0.0 - if w > 1.0: - return 1.0 - return w - - -# --------------------------- Palette helpers --------------------------- - -def get_palette(img: Image.Image) -> List[int]: - pal = img.getpalette() - if pal is None: - raise ValueError("Image has no palette (mode must be 'P').") - if len(pal) < 256 * 3: - pal = pal + [0] * (256 * 3 - len(pal)) - return pal[:256 * 3] - - -def set_palette(img: Image.Image, pal: Sequence[int]) -> None: - if len(pal) != 256 * 3: - raise ValueError("Palette must be exactly 256*3 entries.") - img.putpalette(list(pal)) - - -def find_color_index(pal: Sequence[int], color: Tuple[int, int, int]) -> int: - cr, cg, cb = color - for i in range(256): - r, g, b = pal[3 * i: 3 * i + 3] - if r == cr and g == cg and b == cb: - return i - return -1 - - -# --------------------------- Green removal (NEW) --------------------------- - -def remap_all_green_to_magenta_and_blacken_palette( - im: Image.Image, - pal: List[int], - *, - green: Tuple[int, int, int] = (0, 255, 0), - magenta: Tuple[int, int, int] = (255, 0, 255), - black: Tuple[int, int, int] = (0, 0, 0), -) -> Image.Image: - """ - 1) Remap pixels from ANY palette index that is exactly green -> magenta index. - 2) Replace ANY palette entry that is exactly green with black. - This removes #00FF00 from the palette entirely. - """ - magenta_idx = find_color_index(pal, magenta) - if magenta_idx < 0: - return im # can't remap without magenta entry - - green_indices: List[int] = [] - for i in range(256): - r, g, b = pal[3 * i: 3 * i + 3] - if (r, g, b) == green: - green_indices.append(i) - - if not green_indices: - return im - - # Remap pixels: any green index -> magenta index - lut = list(range(256)) - for gi in green_indices: - lut[gi] = magenta_idx - im = im.point(lut, mode="P") - - # Replace those palette entries with black - for gi in green_indices: - pal[3 * gi + 0] = black[0] - pal[3 * gi + 1] = black[1] - pal[3 * gi + 2] = black[2] - - return im - - -# --------------------------- Core operations --------------------------- - -def adjust_palette_for_time( - pal: List[int], - hour_value: float, - reserved_colors: Iterable[Tuple[int, int, int]], - *, - reserved_indices: Iterable[int] = (), - # look controls - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sat_boost: float, - contrast: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, - # noon neutral zone controls - noon_blend: float, - noon_sigma: float, - noon_window_start: float, - noon_window_end: float, - noon_window_soft: float, -) -> List[int]: - params = hour_adjustments( - hour_value, - warmth_scale=warmth_scale, - blue_scale=blue_scale, - darkness_scale=darkness_scale, - desat_scale=desat_scale, - sunrise_center=sunrise_center, - sunset_center=sunset_center, - twilight_sigma=twilight_sigma, - ) - reserved_color_set = set(reserved_colors) - reserved_index_set = set(int(i) for i in reserved_indices) - - noon_w = _noon_weight( - hour_value, noon_blend, noon_sigma, - noon_window_start, noon_window_end, noon_window_soft - ) - - sat_eff = 1.0 + (sat_boost - 1.0) * (1.0 - noon_w) - contrast_eff = 1.0 + (contrast - 1.0) * (1.0 - noon_w) - - out = pal[:] # copy - for i in range(256): - r, g, b = pal[3 * i: 3 * i + 3] - - # Skip EXACT indices first (highest priority) - if i in reserved_index_set: - out[3 * i + 0], out[3 * i + 1], out[3 * i + 2] = r, g, b - continue - - # Then skip by color (magenta + user light-keys) - if (r, g, b) in reserved_color_set: - out[3 * i + 0], out[3 * i + 1], out[3 * i + 2] = r, g, b - continue - - nr, ng, nb = tint_rgb((r, g, b), params, sat_boost=sat_eff, contrast=contrast_eff) - - if noon_w > 0.0: - nr = int(round((1.0 - noon_w) * nr + noon_w * r)) - ng = int(round((1.0 - noon_w) * ng + noon_w * g)) - nb = int(round((1.0 - noon_w) * nb + noon_w * b)) - - nr, ng, nb = _nudge_if_reserved((nr, ng, nb), reserved_color_set, (r, g, b)) - - out[3 * i + 0] = nr - out[3 * i + 1] = ng - out[3 * i + 2] = nb - - return out - - -# --------------------------- File ops --------------------------- - -def copy_noon_to_label(noon_dir: Path, label_dir: Path) -> List[Path]: - label_dir.mkdir(parents=True, exist_ok=True) - copied: List[Path] = [] - for src in noon_dir.iterdir(): - if not src.is_file() or src.suffix.lower() != ".pcx": - continue - dst = label_dir / src.name - shutil.copy2(src, dst) - copied.append(dst) - return copied - - -def label_to_hour_value(label: str) -> float: - """Convert 'HHMM' or '2400' to hour value (fractional hours).""" - if label == "2400": - return 0.0 - h = int(label[:2]) - m = int(label[2:]) - return (h % 24) + (m / 60.0) - - -def process_time_label( - label: str, - base_dir: Path, - noon_label: str, - reserved_colors: Iterable[Tuple[int, int, int]], - *, - do_index_remap: bool, - # look controls... - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sat_boost: float, - contrast: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, - # noon neutral controls... - noon_blend: float, - noon_sigma: float, - noon_window_start: float, - noon_window_end: float, - noon_window_soft: float, -) -> None: - noon_dir = base_dir / noon_label - out_dir = base_dir / label - hour_value = label_to_hour_value(label) - - copied_files = copy_noon_to_label(noon_dir, out_dir) - - for pcx_path in copied_files: - with Image.open(pcx_path) as im: - if im.mode != "P": - im = im.convert("P") - pal = get_palette(im) - - # Optional green→magenta pixel remap AND remove green from palette (set to black) - if do_index_remap: - im = remap_all_green_to_magenta_and_blacken_palette(im, pal) - - effective_reserved_colors: List[Tuple[int, int, int]] = list(reserved_colors) - reserved_by_color_rgbs = set(effective_reserved_colors) - - # Initialize to empty for non-EntertainmentComplex files - reserved_idx: Set[int] = set() - - # If this is an Entertainment Complex, protect EXACT pixels by duplicating indices - if "EntertainmentComplex" in pcx_path.name and is_night_hour(24 if int(hour_value) == 0 else int(hour_value)): - ranges = PROTECTED_RANGES_ENT_COMPLEX - ranges = _bridge_small_gaps(ranges, PROTECTED_GAP_BRIDGE) - reserved_idx = _protect_exact_pixels_by_index( - im, pal, ranges, reserved_by_color_rgbs=reserved_by_color_rgbs - ) - - new_pal = adjust_palette_for_time( - pal, hour_value, effective_reserved_colors, - reserved_indices=reserved_idx, - warmth_scale=warmth_scale, - blue_scale=blue_scale, - darkness_scale=darkness_scale, - desat_scale=desat_scale, - sat_boost=sat_boost, - contrast=contrast, - sunrise_center=sunrise_center, - sunset_center=sunset_center, - twilight_sigma=twilight_sigma, - noon_blend=noon_blend, - noon_sigma=noon_sigma, - noon_window_start=noon_window_start, - noon_window_end=noon_window_end, - noon_window_soft=noon_window_soft, - ) - - set_palette(im, new_pal) - im.save(pcx_path, format="PCX") - - -# --------------------------- Main --------------------------- - -def main(): - p = argparse.ArgumentParser(description="Civ3 PCX day/night generator with variable time steps and noon-neutral zone.") - p.add_argument("--data", required=True, - help="Parent folder containing the noon folder and sibling time folders (e.g., NightDay).") - p.add_argument("--noon", default="1200", - help="Name of the noon folder (default: 1200).") - p.add_argument("--only-hour", default=None, - help="Process only a single time label (e.g., 1900, 1930, or 2400).") - p.add_argument("--step-minutes", type=int, default=60, - help="Time step in minutes; must divide 60 (e.g., 5,10,15,20,30,60). Default: 60.") - - p.add_argument("--light-key", action="append", default=[], - help="Reserved color that must not change. Repeatable. '#RRGGBB' or 'R,G,B'.") - - # Look/feel controls - p.add_argument("--warmth", type=float, default=1.10, - help="Scale for sunrise/sunset warmth (1.0 = base).") - p.add_argument("--blue", type=float, default=1.12, - help="Scale for night-time blue emphasis (1.0 = base).") - p.add_argument("--darkness", type=float, default=1.08, - help="Scale for extra night darkening (1.0 = base).") - p.add_argument("--desat", type=float, default=0.85, - help="Scale for dusk/night desaturation toward gray (lower = richer).") - p.add_argument("--sat", type=float, default=1.05, - help="Global saturation multiplier after tint (1.0 = none).") - p.add_argument("--contrast", type=float, default=1.03, - help="Global contrast multiplier around mid 128 (1.0 = none).") - - # Curve placement/width - p.add_argument("--sunrise-center", type=float, default=6.0, - help="Hour center for sunrise warmth bump (0-23).") - p.add_argument("--sunset-center", type=float, default=18.0, - help="Hour center for sunset warmth bump (0-23).") - p.add_argument("--twilight-width", type=float, default=1.8, - help="Sigma for sunrise/sunset warmth spread (higher = broader).") - - # Noon-neutral zone controls - p.add_argument("--noon-blend", type=float, default=1.0, - help="0..1 strength to blend toward base palette near 12:00 (0=off).") - p.add_argument("--noon-sigma", type=float, default=1.1, - help="Gaussian width (hours) around 12:00 (larger = broader).") - p.add_argument("--noon-window-start", type=float, default=10.0, - help="Start hour of the noon-like window (default 10.0).") - p.add_argument("--noon-window-end", type=float, default=14.0, - help="End hour of the noon-like window (default 14.0).") - p.add_argument("--noon-window-soft", type=float, default=0.7, - help="Soft edge (hours) for window ramps (0=hard).") - - # Index remap control - g = p.add_mutually_exclusive_group() - g.add_argument("--keep-green-index", action="store_true", - help="Do NOT remap green pixels to magenta; also do NOT remove #00FF00 from the palette.") - g.add_argument("--map-green-index", dest="map_green_index", action="store_true", - help="Force remap green pixels to magenta and replace any #00FF00 palette entries with black (default behavior).") - - args = p.parse_args() - - base_dir = Path(args.data).expanduser().resolve() - noon_dir = base_dir / args.noon - if not noon_dir.is_dir(): - raise SystemExit(f"Noon folder not found: {noon_dir}") - - # Reserved colors: - # - Magenta is kept stable - # - Green is NOT reserved anymore because we remove it from the palette when remapping is enabled - reserved: List[Tuple[int, int, int]] = [(255, 0, 255)] - for s in args.light_key: - reserved.append(parse_rgb(s)) - - # Determine remap behavior (default ON) - do_index_remap = not args.keep_green_index or args.map_green_index - - labels = [lbl for lbl in time_labels(args.step_minutes) if lbl != args.noon] - - # only-hour (accept 0000 -> 2400) - if args.only_hour: - only = "2400" if args.only_hour == "0000" else args.only_hour - if only == args.noon: - print(f"--only-hour {only} is the noon source; nothing to do.") - return - if only not in labels: - raise SystemExit(f"--only-hour must be one of: {', '.join(labels)}") - labels = [only] - - print(f"Base: {base_dir}") - print(f"Noon source: {noon_dir}") - print(f"Time step: {args.step_minutes} minutes") - print(f"Green pixels→magenta + remove #00FF00 from palette: {'ON' if do_index_remap else 'OFF'}") - print(f"Generating labels: {', '.join(labels)}") - - for lbl in labels: - print(f" -> Generating {lbl} ...") - process_time_label( - lbl, base_dir, args.noon, reserved, - do_index_remap=do_index_remap, - warmth_scale=args.warmth, - blue_scale=args.blue, - darkness_scale=args.darkness, - desat_scale=args.desat, - sat_boost=args.sat, - contrast=args.contrast, - sunrise_center=args.sunrise_center, - sunset_center=args.sunset_center, - twilight_sigma=args.twilight_width, - noon_blend=args.noon_blend, - noon_sigma=args.noon_sigma, - noon_window_start=args.noon_window_start, - noon_window_end=args.noon_window_end, - noon_window_soft=args.noon_window_soft, - ) - - print("Done.") - - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +""" +civ3_daynight_pcx.py — v4.4 (remove #00FF00 from palette entirely) + +Highlights: +- Half-hour (or any divisor of an hour) time slices via --step-minutes. +- Green→Magenta pixel remap (on by default). +- NEW: After pixel remap, ANY palette entries exactly #00FF00 are replaced with black (#000000), + so #00FF00 no longer exists anywhere in the palette. +- Palette-only tinting; indices preserved (except the optional index remap). +- Noon-neutral zone keeps ~10:00–14:00 close to base 1200. +- Stronger nighttime blue response using the existing --blue knob, + with an additional night-only hue shift (blue up, red/green down). + +Tested knobs (your current favorites work unchanged): + --warmth 1.05 --blue 2.0 --darkness 1.1 --desat 0.85 --sat 1.2 --contrast 1.08 + --sunrise-center 5.0 --sunset-center 18.0 --twilight-width 3.0 + --noon-blend 0.7 --noon-sigma 1.0 +""" + +import argparse +import shutil +from pathlib import Path +from typing import Iterable, List, Sequence, Tuple, Set, Dict, Optional + +from PIL import Image +from civ3_city_lights import is_night_hour +from protected_pixels import PROTECTED_RANGES_ENT_COMPLEX + +# Fallback behavior if the palette is full and we cannot allocate a new index +PROTECTED_FALLBACK_NEIGHBOR_RADIUS = 1 # 1 => 3x3 window, 2 => 5x5, etc. +PROTECTED_GAP_BRIDGE = 1 + +from collections import defaultdict, Counter +from math import sqrt + + +# --------------------------- Helpers for protected ranges --------------------------- + +def _bridge_small_gaps( + ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], + max_gap: int, +) -> List[Tuple[Tuple[int, int], Tuple[int, int]]]: + """ + Merge/bridge adjacent horizontal ranges on the same scanline (same y) + when the gap between them is <= max_gap. Ranges are inclusive. + Input items are ((x1, y), (x2, y)). Non-horizontal ranges are kept as-is. + """ + if max_gap <= 0 or not ranges: + return list(ranges) + + by_y = defaultdict(list) + for (x1, y1), (x2, y2) in ranges: + if y1 != y2: + # Not horizontal; keep separate + by_y[(y1, y2, 'nonh')].append((min(x1, x2), max(x1, x2), y1, y2)) + continue + by_y[y1].append((min(x1, x2), max(x1, x2))) + + out: List[Tuple[Tuple[int, int], Tuple[int, int]]] = [] + + # Re-emit any non-horizontal entries unchanged + for key, spans in list(by_y.items()): + if isinstance(key, tuple) and key[-1] == 'nonh': + for x1, x2, y1, y2 in spans: + out.append(((x1, y1), (x2, y2))) + del by_y[key] + + # Bridge gaps on horizontal scanlines + for y, spans in by_y.items(): + spans.sort() + cur_x1, cur_x2 = spans[0] + for nx1, nx2 in spans[1:]: + gap = nx1 - cur_x2 - 1 # inclusive ranges + if gap <= max_gap: + cur_x2 = max(cur_x2, nx2) + else: + out.append(((cur_x1, y), (cur_x2, y))) + cur_x1, cur_x2 = nx1, nx2 + out.append(((cur_x1, y), (cur_x2, y))) + + return out + + +def clamp_byte(x: float) -> int: + return int(max(0, min(255, round(x)))) + + +def _nudge_if_reserved(nrgb, reserved_set, orig_rgb): + if nrgb in reserved_set: + # Nudge 1 toward original to avoid exact collision + r0, g0, b0 = orig_rgb + r, g, b = nrgb + + def nudge(c, c0): + return clamp_byte(c - 1 if c > c0 else c + 1 if c < c0 else c) + + return (nudge(r, r0), nudge(g, g0), nudge(b, b0)) + return nrgb + + +def _rgb_of_index(pal: List[int], idx: int) -> Tuple[int, int, int]: + return pal[3 * idx], pal[3 * idx + 1], pal[3 * idx + 2] + + +def _color_dist2(a: Tuple[int, int, int], b: Tuple[int, int, int]) -> float: + dr, dg, db = a[0] - b[0], a[1] - b[1], a[2] - b[2] + return dr * dr + dg * dg + db * db + + +def _index_pixel_counts(im: Image.Image) -> Dict[int, int]: + colors = im.getcolors(maxcolors=256 * 256) or [] + return {int(idx): int(cnt) for (cnt, idx) in colors} + + +def _indices_used_in_coords( + im: Image.Image, + ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], +) -> Set[int]: + w, h = im.size + px = im.load() + s: Set[int] = set() + for (x1, y1), (x2, y2) in ranges: + x_start, x_end = (x1, x2) if x1 <= x2 else (x2, x1) + y_start, y_end = (y1, y2) if y1 <= y2 else (y2, y1) + for y in range(max(0, y_start), min(h, y_end + 1)): + for x in range(max(0, x_start), min(w, x_end + 1)): + s.add(int(px[x, y])) + return s + + +def _find_nearest_index( + pal: List[int], + src_idx: int, + allowed: Iterable[int], +) -> Optional[int]: + src_rgb = _rgb_of_index(pal, src_idx) + best = None + best_d2 = 1e18 + for j in allowed: + if j == src_idx: + continue + d2 = _color_dist2(src_rgb, _rgb_of_index(pal, j)) + if d2 < best_d2: + best_d2 = d2 + best = int(j) + return best + + +def _used_palette_indices(im: Image.Image) -> Set[int]: + """ + Return the set of palette indices actually used by the image. + """ + colors = im.getcolors(maxcolors=256 * 256) or [] + used: Set[int] = set() + for _, idx in colors: + used.add(int(idx)) + return used + + +def _free_palette_slots( + im: Image.Image, + pal: List[int], + needed: int, + *, + protected_source_indices: Set[int], # indices that appear inside protected coords + reserved_by_color_rgbs: Set[Tuple[int, int, int]], # magenta/green/light-keys as RGB +) -> int: + """ + Try to free up to `needed` palette slots by remapping the *least-used* indices + (that are NOT protected and NOT reserved-by-color) to their nearest-color neighbors. + Returns the number of slots actually freed. Pixels are rewritten in-place. + """ + if needed <= 0: + return 0 + + w, h = im.size + px = im.load() + counts = _index_pixel_counts(im) + used_indices = set(counts.keys()) + + # Build sets for constraints + reserved_by_color_indices: Set[int] = set() + for i in range(256): + if i in used_indices: + rgb = (pal[3 * i], pal[3 * i + 1], pal[3 * i + 2]) + if rgb in reserved_by_color_rgbs: + reserved_by_color_indices.add(i) + + forbidden = set(protected_source_indices) | reserved_by_color_indices + + # Candidates we are allowed to merge away + candidates = [i for i in used_indices if i not in forbidden] + + if not candidates: + return 0 + + # Sort by ascending usage (least used first) + candidates.sort(key=lambda i: counts.get(i, 0)) + + freed = 0 + allowed_targets = set(used_indices) - forbidden + + for src_idx in candidates: + if freed >= needed: + break + if src_idx not in used_indices: + continue + + options = allowed_targets - {src_idx} + if not options: + continue + + tgt = _find_nearest_index(pal, src_idx, options) + if tgt is None: + continue + + # Remap all pixels from src_idx -> tgt + for y in range(h): + for x in range(w): + if px[x, y] == src_idx: + px[x, y] = tgt + + used_indices.discard(src_idx) + allowed_targets.discard(src_idx) + freed += 1 + + return freed + + +def _sample_neighbor_index(px, x: int, y: int, w: int, h: int, r: int) -> Optional[int]: + """ + Return the most common palette index in the (2r+1)x(2r+1) neighborhood + around (x,y), excluding the center pixel. If nothing valid, return None. + """ + if r <= 0: + return None + xs = range(max(0, x - r), min(w, x + r + 1)) + ys = range(max(0, y - r), min(h, y + r + 1)) + counts = Counter() + for yy in ys: + for xx in xs: + if xx == x and yy == y: + continue + counts[int(px[xx, yy])] += 1 + return counts.most_common(1)[0][0] if counts else None + + +def _protect_exact_pixels_by_index( + im: Image.Image, + pal: List[int], + ranges: Sequence[Tuple[Tuple[int, int], Tuple[int, int]]], + reserved_by_color_rgbs: Set[Tuple[int, int, int]] = set(), +) -> Set[int]: + """ + Ensure protected coords keep their original (noon) colors by duplicating indices. + If the palette is full, first free slots by merging least-used non-protected indices + into nearest neighbors. If still short on slots, fall back to neighbor sampling. + Returns set of dedicated reserved indices. + """ + assert im.mode == "P", "Image must be paletted ('P')" + w, h = im.size + px = im.load() + + protected_src_indices = _indices_used_in_coords(im, ranges) + + used_now = _used_palette_indices(im) + free_now = [i for i in range(256) if i not in used_now] + need = max(0, len(protected_src_indices) - len(free_now)) + + if need > 0: + _ = _free_palette_slots( + im, + pal, + need, + protected_source_indices=protected_src_indices, + reserved_by_color_rgbs=reserved_by_color_rgbs, + ) + + # Recompute used/free after freeing + used = _used_palette_indices(im) + free_pool = [i for i in range(256) if i not in used] + + index_map: Dict[int, int] = {} + reserved_indices: Set[int] = set() + + radius = int(PROTECTED_FALLBACK_NEIGHBOR_RADIUS) + + # Duplicate on first encounter of a src index + for (x1, y1), (x2, y2) in ranges: + x_start, x_end = (x1, x2) if x1 <= x2 else (x2, x1) + y_start, y_end = (y1, y2) if y1 <= y2 else (y2, y1) + + for y in range(y_start, y_end + 1): + if not (0 <= y < h): + continue + for x in range(x_start, x_end + 1): + if not (0 <= x < w): + continue + + orig_idx = int(px[x, y]) + + dup = index_map.get(orig_idx) + if dup is not None: + px[x, y] = dup + continue + + if free_pool: + dup_idx = free_pool.pop(0) + r, g, b = pal[3 * orig_idx: 3 * orig_idx + 3] + pal[3 * dup_idx + 0] = r + pal[3 * dup_idx + 1] = g + pal[3 * dup_idx + 2] = b + index_map[orig_idx] = dup_idx + reserved_indices.add(dup_idx) + px[x, y] = dup_idx + continue + + # LAST RESORT: neighbor sampling + neighbor_idx = _sample_neighbor_index(px, x, y, w, h, radius) + if neighbor_idx is not None: + px[x, y] = int(neighbor_idx) + else: + print(f"WARNING: No palette slots and no neighbors for ({x},{y}).") + + return reserved_indices + + +# --------------------------- CLI & helpers --------------------------- + +def parse_rgb(s: str) -> Tuple[int, int, int]: + s = s.strip() + if s.startswith("#"): + s = s[1:] + if len(s) != 6: + raise ValueError(f"Bad hex color: #{s}") + return tuple(int(s[i:i + 2], 16) for i in (0, 2, 4)) # type: ignore + if "," in s: + parts = [p.strip() for p in s.split(",")] + if len(parts) != 3: + raise ValueError(f"Bad RGB list: {s}") + return tuple(int(p) for p in parts) # type: ignore + raise ValueError(f"Unrecognized color format: {s}") + + +def time_labels(step_minutes: int) -> List[str]: + """ + Generate HHMM labels from step to 23:59 stepwise; exclude 0000; add 2400. + For step=60: 0100..2300 + 2400 + For step=30: 0030, 0100, 0130..2330 + 2400 + """ + if step_minutes <= 0 or 60 % step_minutes != 0: + raise ValueError("--step-minutes must be a positive divisor of 60 (e.g., 5,10,15,20,30,60).") + labels: List[str] = [] + total_minutes = 24 * 60 + m = step_minutes + while m < total_minutes: + h = m // 60 + mm = m % 60 + labels.append(f"{h:02d}{mm:02d}") + m += step_minutes + labels.append("2400") + return labels + + +# --------------------------- TONEMAP MODEL --------------------------- + +def _gauss(x: float, mu: float, sigma: float) -> float: + from math import exp + if sigma <= 0.0: + return 0.0 + return exp(-0.5 * ((x - mu) / sigma) ** 2) + + +def hour_adjustments( + hour_value: float, + *, + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, +) -> dict: + """ + hour_value can be fractional (e.g., 19.5 for 19:30). Period is 24h. + Returns a dict with per-channel multipliers, gray blend, brightness, + and 'night' + 'blue_push' factors for night-only hue shift. + """ + from math import cos, pi + + h = hour_value % 24.0 + + # Daylight (cosine): 1 at noon, ~0 at midnight + daylight = max(0.0, cos(pi * (h - 12.0) / 12.0)) # 0..1 + night = 1.0 - daylight + + # Warmth around sunrise/sunset + warmth = 0.85 * (_gauss(h, sunrise_center, twilight_sigma) + + _gauss(h, sunset_center, twilight_sigma)) + warmth *= warmth_scale + + # Brightness: darker at night; scaled by darkness_scale (>1 = darker nights) + base_brightness = 0.60 + 0.40 * daylight + night_darkening = 1.0 - (0.12 * (darkness_scale - 1.0) * night) + brightness = base_brightness * night_darkening + + # Channel multipliers + r_mul = 0.97 + 0.12 * daylight + 0.30 * warmth + g_mul = 0.97 + 0.12 * daylight + 0.12 * warmth + b_mul = 0.97 + 0.12 * daylight - 0.18 * warmth + (0.28 * blue_scale) * night + + # Desaturation (toward gray) stronger at night; scaled by desat_scale + gray_blend = (0.10 + 0.50 * night) * desat_scale + gray_blend = min(max(gray_blend, 0.0), 0.85) + + # Night-only blue push factor (extra hue shift at night) + blue_push = max(0.0, blue_scale - 1.0) * night # 0 at day, up to (blue-1) at night + + # Clamp gentle bounds + r_mul = min(max(r_mul, 0.65), 1.45) + g_mul = min(max(g_mul, 0.65), 1.40) + b_mul = min(max(b_mul, 0.65), 1.55) + + return dict( + brightness=brightness, + r_mul=r_mul, + g_mul=g_mul, + b_mul=b_mul, + gray_blend=gray_blend, + night=night, + blue_push=blue_push, + ) + + +def _apply_saturation(rgb: Tuple[float, float, float], sat: float) -> Tuple[float, float, float]: + r, g, b = rgb + gray = (r + g + b) / 3.0 + r = gray + (r - gray) * sat + g = gray + (g - gray) * sat + b = gray + (b - gray) * sat + return r, g, b + + +def _apply_contrast(rgb: Tuple[float, float, float], contrast: float) -> Tuple[float, float, float]: + r, g, b = rgb + r = 128 + (r - 128) * contrast + g = 128 + (g - 128) * contrast + b = 128 + (b - 128) * contrast + return r, g, b + + +def _apply_night_blue_push( + rgb: Tuple[float, float, float], + blue_push: float, +) -> Tuple[float, float, float]: + """ + Extra night-only hue shift: + - Slightly reduces R and G + - Increases B + 'blue_push' is ~ (blue_scale - 1) * night, so this is zero in daytime. + """ + if blue_push <= 0.0: + return rgb + r, g, b = rgb + c = blue_push + r *= (1.0 - 0.15 * c) + g *= (1.0 - 0.10 * c) + b *= (1.0 + 0.35 * c) + return r, g, b + + +def tint_rgb( + rgb: Tuple[int, int, int], + params: dict, + *, + sat_boost: float, + contrast: float, +) -> Tuple[int, int, int]: + r, g, b = rgb + r_f = r * params["r_mul"] * params["brightness"] + g_f = g * params["g_mul"] * params["brightness"] + b_f = b * params["b_mul"] * params["brightness"] + + gray = (r_f + g_f + b_f) / 3.0 + t = params["gray_blend"] + r_f = (1 - t) * r_f + t * gray + g_f = (1 - t) * g_f + t * gray + b_f = (1 - t) * b_f + t * gray + + # Global saturation, then extra night-only blue hue push, then contrast + r_f, g_f, b_f = _apply_saturation((r_f, g_f, b_f), sat_boost) + r_f, g_f, b_f = _apply_night_blue_push((r_f, g_f, b_f), params.get("blue_push", 0.0)) + r_f, g_f, b_f = _apply_contrast((r_f, g_f, b_f), contrast) + + return (clamp_byte(r_f), clamp_byte(g_f), clamp_byte(b_f)) + + +# --------------------------- Noon-neutral weighting --------------------------- + +def _smoothstep01(t: float) -> float: + """Cubic smoothstep on [0,1].""" + if t <= 0.0: + return 0.0 + if t >= 1.0: + return 1.0 + return t * t * (3.0 - 2.0 * t) + + +def _interval_membership(x: float, a: float, b: float, soft: float) -> float: + """ + Smooth membership of time-of-day x (0..24) inside interval [a,b] (hours), + with soft edge width 'soft' (hours). Supports wrapped intervals (a>b). + Returns 0..1. + """ + x = x % 24.0 + a = a % 24.0 + b = b % 24.0 + soft = max(0.0, soft) + + def segment_membership(x: float, s: float, e: float, soft: float) -> float: + if soft <= 0.0: + return 1.0 if (s <= x <= e) else 0.0 + + if s - soft <= x < s: + t = (x - (s - soft)) / soft + return _smoothstep01(t) + + if s <= x <= e: + return 1.0 + + if e < x <= e + soft: + t = (x - e) / soft + return 1.0 - _smoothstep01(t) + + return 0.0 + + if a <= b: + return segment_membership(x, a, b, soft) + else: + m1 = segment_membership(x, a, 24.0, soft) + m2 = segment_membership(x, 0.0, b, soft) + return max(m1, m2) + + +def _noon_weight(hour_value: float, blend: float, sigma: float, + w_start: float, w_end: float, w_soft: float) -> float: + """ + Combined noon weight in 0..1: + - Gaussian around 12:00 with width 'sigma' (hours), scaled by 'blend'. + - Smooth interval window [w_start, w_end] with soft edges 'w_soft', + also scaled by 'blend'. + """ + try: + h = hour_value % 24.0 + except Exception: + h = 0.0 + blend = float(blend) if blend is not None else 0.0 + sigma = float(sigma) if sigma is not None else 0.0 + w_start = float(w_start) if w_start is not None else 10.0 + w_end = float(w_end) if w_end is not None else 14.0 + w_soft = max(0.0, float(w_soft) if w_soft is not None else 0.7) + + if blend <= 0.0: + return 0.0 + + from math import exp + d = abs(h - 12.0) + d = min(d, 24.0 - d) + g = exp(-0.5 * (d / sigma) ** 2) if sigma > 0.0 else 0.0 + g *= blend + + window_m = _interval_membership(h, w_start, w_end, w_soft) * blend + + w = max(g, window_m) + if w < 0.0: + return 0.0 + if w > 1.0: + return 1.0 + return w + + +# --------------------------- Palette helpers --------------------------- + +def get_palette(img: Image.Image) -> List[int]: + pal = img.getpalette() + if pal is None: + raise ValueError("Image has no palette (mode must be 'P').") + if len(pal) < 256 * 3: + pal = pal + [0] * (256 * 3 - len(pal)) + return pal[:256 * 3] + + +def set_palette(img: Image.Image, pal: Sequence[int]) -> None: + if len(pal) != 256 * 3: + raise ValueError("Palette must be exactly 256*3 entries.") + img.putpalette(list(pal)) + + +def find_color_index(pal: Sequence[int], color: Tuple[int, int, int]) -> int: + cr, cg, cb = color + for i in range(256): + r, g, b = pal[3 * i: 3 * i + 3] + if r == cr and g == cg and b == cb: + return i + return -1 + + +# --------------------------- Green removal (NEW) --------------------------- + +def remap_all_green_to_magenta_and_blacken_palette( + im: Image.Image, + pal: List[int], + *, + green: Tuple[int, int, int] = (0, 255, 0), + magenta: Tuple[int, int, int] = (255, 0, 255), + black: Tuple[int, int, int] = (0, 0, 0), +) -> Image.Image: + """ + 1) Remap pixels from ANY palette index that is exactly green -> magenta index. + 2) Replace ANY palette entry that is exactly green with black. + This removes #00FF00 from the palette entirely. + """ + magenta_idx = find_color_index(pal, magenta) + if magenta_idx < 0: + return im # can't remap without magenta entry + + green_indices: List[int] = [] + for i in range(256): + r, g, b = pal[3 * i: 3 * i + 3] + if (r, g, b) == green: + green_indices.append(i) + + if not green_indices: + return im + + # Remap pixels: any green index -> magenta index + lut = list(range(256)) + for gi in green_indices: + lut[gi] = magenta_idx + im = im.point(lut, mode="P") + + # Replace those palette entries with black + for gi in green_indices: + pal[3 * gi + 0] = black[0] + pal[3 * gi + 1] = black[1] + pal[3 * gi + 2] = black[2] + + return im + + +# --------------------------- Core operations --------------------------- + +def adjust_palette_for_time( + pal: List[int], + hour_value: float, + reserved_colors: Iterable[Tuple[int, int, int]], + *, + reserved_indices: Iterable[int] = (), + # look controls + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sat_boost: float, + contrast: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, + # noon neutral zone controls + noon_blend: float, + noon_sigma: float, + noon_window_start: float, + noon_window_end: float, + noon_window_soft: float, +) -> List[int]: + params = hour_adjustments( + hour_value, + warmth_scale=warmth_scale, + blue_scale=blue_scale, + darkness_scale=darkness_scale, + desat_scale=desat_scale, + sunrise_center=sunrise_center, + sunset_center=sunset_center, + twilight_sigma=twilight_sigma, + ) + reserved_color_set = set(reserved_colors) + reserved_index_set = set(int(i) for i in reserved_indices) + + noon_w = _noon_weight( + hour_value, noon_blend, noon_sigma, + noon_window_start, noon_window_end, noon_window_soft + ) + + sat_eff = 1.0 + (sat_boost - 1.0) * (1.0 - noon_w) + contrast_eff = 1.0 + (contrast - 1.0) * (1.0 - noon_w) + + out = pal[:] # copy + for i in range(256): + r, g, b = pal[3 * i: 3 * i + 3] + + # Skip EXACT indices first (highest priority) + if i in reserved_index_set: + out[3 * i + 0], out[3 * i + 1], out[3 * i + 2] = r, g, b + continue + + # Then skip by color (magenta + user light-keys) + if (r, g, b) in reserved_color_set: + out[3 * i + 0], out[3 * i + 1], out[3 * i + 2] = r, g, b + continue + + nr, ng, nb = tint_rgb((r, g, b), params, sat_boost=sat_eff, contrast=contrast_eff) + + if noon_w > 0.0: + nr = int(round((1.0 - noon_w) * nr + noon_w * r)) + ng = int(round((1.0 - noon_w) * ng + noon_w * g)) + nb = int(round((1.0 - noon_w) * nb + noon_w * b)) + + nr, ng, nb = _nudge_if_reserved((nr, ng, nb), reserved_color_set, (r, g, b)) + + out[3 * i + 0] = nr + out[3 * i + 1] = ng + out[3 * i + 2] = nb + + return out + + +# --------------------------- File ops --------------------------- + +def copy_noon_to_label(noon_dir: Path, label_dir: Path) -> List[Path]: + label_dir.mkdir(parents=True, exist_ok=True) + copied: List[Path] = [] + for src in noon_dir.iterdir(): + if not src.is_file() or src.suffix.lower() != ".pcx": + continue + dst = label_dir / src.name + shutil.copy2(src, dst) + copied.append(dst) + return copied + + +def label_to_hour_value(label: str) -> float: + """Convert 'HHMM' or '2400' to hour value (fractional hours).""" + if label == "2400": + return 0.0 + h = int(label[:2]) + m = int(label[2:]) + return (h % 24) + (m / 60.0) + + +def process_time_label( + label: str, + base_dir: Path, + noon_label: str, + reserved_colors: Iterable[Tuple[int, int, int]], + *, + do_index_remap: bool, + # look controls... + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sat_boost: float, + contrast: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, + # noon neutral controls... + noon_blend: float, + noon_sigma: float, + noon_window_start: float, + noon_window_end: float, + noon_window_soft: float, +) -> None: + noon_dir = base_dir / noon_label + out_dir = base_dir / label + hour_value = label_to_hour_value(label) + + copied_files = copy_noon_to_label(noon_dir, out_dir) + + for pcx_path in copied_files: + with Image.open(pcx_path) as im: + if im.mode != "P": + im = im.convert("P") + pal = get_palette(im) + + # Optional green→magenta pixel remap AND remove green from palette (set to black) + if do_index_remap: + im = remap_all_green_to_magenta_and_blacken_palette(im, pal) + + effective_reserved_colors: List[Tuple[int, int, int]] = list(reserved_colors) + reserved_by_color_rgbs = set(effective_reserved_colors) + + # Initialize to empty for non-EntertainmentComplex files + reserved_idx: Set[int] = set() + + # If this is an Entertainment Complex, protect EXACT pixels by duplicating indices + if "EntertainmentComplex" in pcx_path.name and is_night_hour(24 if int(hour_value) == 0 else int(hour_value)): + ranges = PROTECTED_RANGES_ENT_COMPLEX + ranges = _bridge_small_gaps(ranges, PROTECTED_GAP_BRIDGE) + reserved_idx = _protect_exact_pixels_by_index( + im, pal, ranges, reserved_by_color_rgbs=reserved_by_color_rgbs + ) + + new_pal = adjust_palette_for_time( + pal, hour_value, effective_reserved_colors, + reserved_indices=reserved_idx, + warmth_scale=warmth_scale, + blue_scale=blue_scale, + darkness_scale=darkness_scale, + desat_scale=desat_scale, + sat_boost=sat_boost, + contrast=contrast, + sunrise_center=sunrise_center, + sunset_center=sunset_center, + twilight_sigma=twilight_sigma, + noon_blend=noon_blend, + noon_sigma=noon_sigma, + noon_window_start=noon_window_start, + noon_window_end=noon_window_end, + noon_window_soft=noon_window_soft, + ) + + set_palette(im, new_pal) + im.save(pcx_path, format="PCX") + + +# --------------------------- Main --------------------------- + +def main(): + p = argparse.ArgumentParser(description="Civ3 PCX day/night generator with variable time steps and noon-neutral zone.") + p.add_argument("--data", required=True, + help="Parent folder containing the noon folder and sibling time folders (e.g., NightDay).") + p.add_argument("--noon", default="1200", + help="Name of the noon folder (default: 1200).") + p.add_argument("--only-hour", default=None, + help="Process only a single time label (e.g., 1900, 1930, or 2400).") + p.add_argument("--step-minutes", type=int, default=60, + help="Time step in minutes; must divide 60 (e.g., 5,10,15,20,30,60). Default: 60.") + + p.add_argument("--light-key", action="append", default=[], + help="Reserved color that must not change. Repeatable. '#RRGGBB' or 'R,G,B'.") + + # Look/feel controls + p.add_argument("--warmth", type=float, default=1.10, + help="Scale for sunrise/sunset warmth (1.0 = base).") + p.add_argument("--blue", type=float, default=1.12, + help="Scale for night-time blue emphasis (1.0 = base).") + p.add_argument("--darkness", type=float, default=1.08, + help="Scale for extra night darkening (1.0 = base).") + p.add_argument("--desat", type=float, default=0.85, + help="Scale for dusk/night desaturation toward gray (lower = richer).") + p.add_argument("--sat", type=float, default=1.05, + help="Global saturation multiplier after tint (1.0 = none).") + p.add_argument("--contrast", type=float, default=1.03, + help="Global contrast multiplier around mid 128 (1.0 = none).") + + # Curve placement/width + p.add_argument("--sunrise-center", type=float, default=6.0, + help="Hour center for sunrise warmth bump (0-23).") + p.add_argument("--sunset-center", type=float, default=18.0, + help="Hour center for sunset warmth bump (0-23).") + p.add_argument("--twilight-width", type=float, default=1.8, + help="Sigma for sunrise/sunset warmth spread (higher = broader).") + + # Noon-neutral zone controls + p.add_argument("--noon-blend", type=float, default=1.0, + help="0..1 strength to blend toward base palette near 12:00 (0=off).") + p.add_argument("--noon-sigma", type=float, default=1.1, + help="Gaussian width (hours) around 12:00 (larger = broader).") + p.add_argument("--noon-window-start", type=float, default=10.0, + help="Start hour of the noon-like window (default 10.0).") + p.add_argument("--noon-window-end", type=float, default=14.0, + help="End hour of the noon-like window (default 14.0).") + p.add_argument("--noon-window-soft", type=float, default=0.7, + help="Soft edge (hours) for window ramps (0=hard).") + + # Index remap control + g = p.add_mutually_exclusive_group() + g.add_argument("--keep-green-index", action="store_true", + help="Do NOT remap green pixels to magenta; also do NOT remove #00FF00 from the palette.") + g.add_argument("--map-green-index", dest="map_green_index", action="store_true", + help="Force remap green pixels to magenta and replace any #00FF00 palette entries with black (default behavior).") + + args = p.parse_args() + + base_dir = Path(args.data).expanduser().resolve() + noon_dir = base_dir / args.noon + if not noon_dir.is_dir(): + raise SystemExit(f"Noon folder not found: {noon_dir}") + + # Reserved colors: + # - Magenta is kept stable + # - Green is NOT reserved anymore because we remove it from the palette when remapping is enabled + reserved: List[Tuple[int, int, int]] = [(255, 0, 255)] + for s in args.light_key: + reserved.append(parse_rgb(s)) + + # Determine remap behavior (default ON) + do_index_remap = not args.keep_green_index or args.map_green_index + + labels = [lbl for lbl in time_labels(args.step_minutes) if lbl != args.noon] + + # only-hour (accept 0000 -> 2400) + if args.only_hour: + only = "2400" if args.only_hour == "0000" else args.only_hour + if only == args.noon: + print(f"--only-hour {only} is the noon source; nothing to do.") + return + if only not in labels: + raise SystemExit(f"--only-hour must be one of: {', '.join(labels)}") + labels = [only] + + print(f"Base: {base_dir}") + print(f"Noon source: {noon_dir}") + print(f"Time step: {args.step_minutes} minutes") + print(f"Green pixels→magenta + remove #00FF00 from palette: {'ON' if do_index_remap else 'OFF'}") + print(f"Generating labels: {', '.join(labels)}") + + for lbl in labels: + print(f" -> Generating {lbl} ...") + process_time_label( + lbl, base_dir, args.noon, reserved, + do_index_remap=do_index_remap, + warmth_scale=args.warmth, + blue_scale=args.blue, + darkness_scale=args.darkness, + desat_scale=args.desat, + sat_boost=args.sat, + contrast=args.contrast, + sunrise_center=args.sunrise_center, + sunset_center=args.sunset_center, + twilight_sigma=args.twilight_width, + noon_blend=args.noon_blend, + noon_sigma=args.noon_sigma, + noon_window_start=args.noon_window_start, + noon_window_end=args.noon_window_end, + noon_window_soft=args.noon_window_soft, + ) + + print("Done.") + + +if __name__ == "__main__": + main() diff --git a/DayNight/civ3_day_night_orig.py b/DayNight/civ3_day_night_orig.py index 10ee2ab6..81bd1805 100644 --- a/DayNight/civ3_day_night_orig.py +++ b/DayNight/civ3_day_night_orig.py @@ -1,602 +1,602 @@ -#!/usr/bin/env python3 -""" -civ3_daynight_pcx.py — v4.3 (stronger nighttime blue + stable noon-neutral zone) - -Highlights: -- Half-hour (or any divisor of an hour) time slices via --step-minutes. -- Green→Magenta index remap (on by default). -- Palette-only tinting; indices preserved (except the optional index remap). -- Noon-neutral zone keeps ~10:00–14:00 close to base 1200. -- NEW: Stronger nighttime blue response using the existing --blue knob, - with an additional night-only hue shift (blue up, red/green down). - -Tested knobs (your current favorites work unchanged): - --warmth 1.05 --blue 2.0 --darkness 1.1 --desat 0.85 --sat 1.2 --contrast 1.08 - --sunrise-center 5.0 --sunset-center 18.0 --twilight-width 3.0 - --noon-blend 0.7 --noon-sigma 1.0 -""" - -import argparse -import shutil -from pathlib import Path -from typing import Iterable, List, Sequence, Tuple - -from PIL import Image - - -# --------------------------- CLI & helpers --------------------------- - -def parse_rgb(s: str) -> Tuple[int, int, int]: - s = s.strip() - if s.startswith("#"): - s = s[1:] - if len(s) != 6: - raise ValueError(f"Bad hex color: #{s}") - return tuple(int(s[i:i+2], 16) for i in (0, 2, 4)) # type: ignore - if "," in s: - parts = [p.strip() for p in s.split(",")] - if len(parts) != 3: - raise ValueError(f"Bad RGB list: {s}") - return tuple(int(p) for p in parts) # type: ignore - raise ValueError(f"Unrecognized color format: {s}") - - -def time_labels(step_minutes: int) -> List[str]: - """ - Generate HHMM labels from step to 23:59 stepwise; exclude 0000; add 2400. - For step=60: 0100..2300 + 2400 - For step=30: 0030, 0100, 0130..2330 + 2400 - """ - if step_minutes <= 0 or 60 % step_minutes != 0: - raise ValueError("--step-minutes must be a positive divisor of 60 (e.g., 5,10,15,20,30,60).") - labels: List[str] = [] - total_minutes = 24 * 60 - m = step_minutes - while m < total_minutes: - h = m // 60 - mm = m % 60 - labels.append(f"{h:02d}{mm:02d}") - m += step_minutes - labels.append("2400") - return labels - - -def clamp_byte(x: float) -> int: - return int(max(0, min(255, round(x)))) - - -# --------------------------- TONEMAP MODEL --------------------------- - -def _gauss(x: float, mu: float, sigma: float) -> float: - from math import exp - if sigma <= 0.0: - return 0.0 - return exp(-0.5 * ((x - mu) / sigma) ** 2) - - -def hour_adjustments( - hour_value: float, - *, - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, -) -> dict: - """ - hour_value can be fractional (e.g., 19.5 for 19:30). Period is 24h. - Returns a dict with per-channel multipliers, gray blend, brightness, - and 'night' + 'blue_push' factors for night-only hue shift. - """ - from math import cos, pi - - h = hour_value % 24.0 - - # Daylight (cosine): 1 at noon, ~0 at midnight - daylight = max(0.0, cos(pi * (h - 12.0) / 12.0)) # 0..1 - night = 1.0 - daylight - - # Warmth around sunrise/sunset - warmth = 0.85 * (_gauss(h, sunrise_center, twilight_sigma) + - _gauss(h, sunset_center, twilight_sigma)) - warmth *= warmth_scale - - # Brightness: darker at night; scaled by darkness_scale (>1 = darker nights) - base_brightness = 0.60 + 0.40 * daylight - night_darkening = 1.0 - (0.12 * (darkness_scale - 1.0) * night) - brightness = base_brightness * night_darkening - - # Channel multipliers - r_mul = 0.97 + 0.12 * daylight + 0.30 * warmth - g_mul = 0.97 + 0.12 * daylight + 0.12 * warmth - b_mul = 0.97 + 0.12 * daylight - 0.18 * warmth + (0.28 * blue_scale) * night - - # Desaturation (toward gray) stronger at night; scaled by desat_scale - gray_blend = (0.10 + 0.50 * night) * desat_scale - gray_blend = min(max(gray_blend, 0.0), 0.85) - - # Night-only blue push factor (extra hue shift at night) - # - grows with (blue_scale - 1) and with 'night' - # - kept separate from b_mul so daytime remains unchanged - blue_push = max(0.0, blue_scale - 1.0) * night # 0 at day, up to (blue-1) at night - - # Clamp gentle bounds - r_mul = min(max(r_mul, 0.65), 1.45) - g_mul = min(max(g_mul, 0.65), 1.40) - b_mul = min(max(b_mul, 0.65), 1.55) - - return dict( - brightness=brightness, - r_mul=r_mul, - g_mul=g_mul, - b_mul=b_mul, - gray_blend=gray_blend, - night=night, - blue_push=blue_push, - ) - - -def _apply_saturation(rgb: Tuple[float, float, float], sat: float) -> Tuple[float, float, float]: - r, g, b = rgb - gray = (r + g + b) / 3.0 - r = gray + (r - gray) * sat - g = gray + (g - gray) * sat - b = gray + (b - gray) * sat - return r, g, b - - -def _apply_contrast(rgb: Tuple[float, float, float], contrast: float) -> Tuple[float, float, float]: - r, g, b = rgb - r = 128 + (r - 128) * contrast - g = 128 + (g - 128) * contrast - b = 128 + (b - 128) * contrast - return r, g, b - - -def _apply_night_blue_push( - rgb: Tuple[float, float, float], - blue_push: float, -) -> Tuple[float, float, float]: - """ - Extra night-only hue shift: - - Slightly reduces R and G - - Increases B - 'blue_push' is ~ (blue_scale - 1) * night, so this is zero in daytime. - Coefficients tuned to be visible but not cartoonish; adjust if needed. - """ - if blue_push <= 0.0: - return rgb - r, g, b = rgb - c = blue_push # c in [0..(blue-1)] scaled by night - # Gentle but noticeable: at c=1 (e.g., --blue 2.0 at full night) - r *= (1.0 - 0.15 * c) - g *= (1.0 - 0.10 * c) - b *= (1.0 + 0.35 * c) - return r, g, b - - -def tint_rgb( - rgb: Tuple[int, int, int], - params: dict, - *, - sat_boost: float, - contrast: float, -) -> Tuple[int, int, int]: - r, g, b = rgb - r_f = r * params["r_mul"] * params["brightness"] - g_f = g * params["g_mul"] * params["brightness"] - b_f = b * params["b_mul"] * params["brightness"] - - gray = (r_f + g_f + b_f) / 3.0 - t = params["gray_blend"] - r_f = (1 - t) * r_f + t * gray - g_f = (1 - t) * g_f + t * gray - b_f = (1 - t) * b_f + t * gray - - # Global saturation, then extra night-only blue hue push, then contrast - r_f, g_f, b_f = _apply_saturation((r_f, g_f, b_f), sat_boost) - r_f, g_f, b_f = _apply_night_blue_push((r_f, g_f, b_f), params.get("blue_push", 0.0)) - r_f, g_f, b_f = _apply_contrast((r_f, g_f, b_f), contrast) - - return (clamp_byte(r_f), clamp_byte(g_f), clamp_byte(b_f)) - - -# --------------------------- Noon-neutral weighting --------------------------- - -def _smoothstep01(t: float) -> float: - """Cubic smoothstep on [0,1].""" - if t <= 0.0: - return 0.0 - if t >= 1.0: - return 1.0 - return t * t * (3.0 - 2.0 * t) - - -def _interval_membership(x: float, a: float, b: float, soft: float) -> float: - """ - Smooth membership of time-of-day x (0..24) inside interval [a,b] (hours), - with soft edge width 'soft' (hours). Supports wrapped intervals (a>b). - Returns 0..1. - """ - x = x % 24.0 - a = a % 24.0 - b = b % 24.0 - soft = max(0.0, soft) - - def segment_membership(x: float, s: float, e: float, soft: float) -> float: - # Non-wrapped segment s <= e in [0,24] - if soft <= 0.0: - return 1.0 if (s <= x <= e) else 0.0 - - # Left ramp [s-soft, s] - if s - soft <= x < s: - t = (x - (s - soft)) / soft # 0..1 - return _smoothstep01(t) - - # Core [s, e] - if s <= x <= e: - return 1.0 - - # Right ramp [e, e+soft] - if e < x <= e + soft: - t = (x - e) / soft # 0..1 - return 1.0 - _smoothstep01(t) - - return 0.0 - - if a <= b: - return segment_membership(x, a, b, soft) - else: - # Wrapped interval: union of [a,24) and [0,b] - m1 = segment_membership(x, a, 24.0, soft) - m2 = segment_membership(x, 0.0, b, soft) - return max(m1, m2) - - -def _noon_weight(hour_value: float, blend: float, sigma: float, - w_start: float, w_end: float, w_soft: float) -> float: - """ - Combined noon weight in 0..1: - - Gaussian around 12:00 with width 'sigma' (hours), scaled by 'blend'. - - Smooth interval window [w_start, w_end] with soft edges 'w_soft', - also scaled by 'blend'. - - The final weight is max of both components, clamped 0..1. - """ - try: - h = hour_value % 24.0 - except Exception: - h = 0.0 - blend = float(blend) if blend is not None else 0.0 - sigma = float(sigma) if sigma is not None else 0.0 - w_start = float(w_start) if w_start is not None else 10.0 - w_end = float(w_end) if w_end is not None else 14.0 - w_soft = max(0.0, float(w_soft) if w_soft is not None else 0.7) - - if blend <= 0.0: - return 0.0 - - # Gaussian around noon - from math import exp - d = abs(h - 12.0) - d = min(d, 24.0 - d) - g = exp(-0.5 * (d / sigma) ** 2) if sigma > 0.0 else 0.0 - g *= blend - - # Smooth window - window_m = _interval_membership(h, w_start, w_end, w_soft) * blend - - w = max(g, window_m) - if w < 0.0: - return 0.0 - if w > 1.0: - return 1.0 - return w - - -# --------------------------- Palette helpers --------------------------- - -def get_palette(img: Image.Image) -> List[int]: - pal = img.getpalette() - if pal is None: - raise ValueError("Image has no palette (mode must be 'P').") - if len(pal) < 256 * 3: - pal = pal + [0] * (256 * 3 - len(pal)) - return pal[:256 * 3] - - -def set_palette(img: Image.Image, pal: Sequence[int]) -> None: - if len(pal) != 256 * 3: - raise ValueError("Palette must be exactly 256*3 entries.") - img.putpalette(list(pal)) - - -def find_color_index(pal: Sequence[int], color: Tuple[int, int, int]) -> int: - cr, cg, cb = color - for i in range(256): - r, g, b = pal[3*i:3*i+3] - if r == cr and g == cg and b == cb: - return i - return -1 - - -# --------------------------- Core operations --------------------------- - -def adjust_palette_for_time( - pal: List[int], - hour_value: float, - reserved_colors: Iterable[Tuple[int, int, int]], - *, - # look controls - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sat_boost: float, - contrast: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, - # noon neutral zone controls - noon_blend: float, - noon_sigma: float, - noon_window_start: float, - noon_window_end: float, - noon_window_soft: float, -) -> List[int]: - params = hour_adjustments( - hour_value, - warmth_scale=warmth_scale, - blue_scale=blue_scale, - darkness_scale=darkness_scale, - desat_scale=desat_scale, - sunrise_center=sunrise_center, - sunset_center=sunset_center, - twilight_sigma=twilight_sigma, - ) - reserved = set(reserved_colors) - - # Noon weight (0..1): stronger near 10:00–14:00, peak at 12:00 - noon_w = _noon_weight( - hour_value, noon_blend, noon_sigma, - noon_window_start, noon_window_end, noon_window_soft - ) - - # Damp sat/contrast near noon to avoid “pop” - sat_eff = 1.0 + (sat_boost - 1.0) * (1.0 - noon_w) - contrast_eff = 1.0 + (contrast - 1.0) * (1.0 - noon_w) - - out = pal[:] # copy - for i in range(256): - r, g, b = pal[3 * i:3 * i + 3] - rgb = (r, g, b) - - if rgb in reserved: - out[3 * i + 0] = r - out[3 * i + 1] = g - out[3 * i + 2] = b - continue - - nr, ng, nb = tint_rgb(rgb, params, sat_boost=sat_eff, contrast=contrast_eff) - - if noon_w > 0.0: - # Blend back toward the original (noon) palette color at the SAME index - nr = int(round((1.0 - noon_w) * nr + noon_w * r)) - ng = int(round((1.0 - noon_w) * ng + noon_w * g)) - nb = int(round((1.0 - noon_w) * nb + noon_w * b)) - - out[3 * i + 0] = nr - out[3 * i + 1] = ng - out[3 * i + 2] = nb - - return out - - -def remap_green_to_magenta_indices(img: Image.Image, pal: Sequence[int]) -> Image.Image: - green_idx = find_color_index(pal, (0, 255, 0)) - magenta_idx = find_color_index(pal, (255, 0, 255)) - if green_idx < 0 or magenta_idx < 0 or green_idx == magenta_idx: - return img - lut = [magenta_idx if i == green_idx else i for i in range(256)] - return img.point(lut, mode="P") - - -# --------------------------- File ops --------------------------- - -def copy_noon_to_label(noon_dir: Path, label_dir: Path) -> List[Path]: - label_dir.mkdir(parents=True, exist_ok=True) - copied: List[Path] = [] - for src in noon_dir.glob("*.pcx"): - dst = label_dir / src.name - shutil.copy2(src, dst) - copied.append(dst) - return copied - - -def label_to_hour_value(label: str) -> float: - """Convert 'HHMM' or '2400' to hour value (fractional hours).""" - if label == "2400": - return 0.0 - h = int(label[:2]) - m = int(label[2:]) - return (h % 24) + (m / 60.0) - - -def process_time_label( - label: str, - base_dir: Path, - noon_label: str, - reserved_colors: Iterable[Tuple[int, int, int]], - *, - do_index_remap: bool, - # look controls - warmth_scale: float, - blue_scale: float, - darkness_scale: float, - desat_scale: float, - sat_boost: float, - contrast: float, - sunrise_center: float, - sunset_center: float, - twilight_sigma: float, - # noon neutral controls - noon_blend: float, - noon_sigma: float, - noon_window_start: float, - noon_window_end: float, - noon_window_soft: float, -) -> None: - noon_dir = base_dir / noon_label - out_dir = base_dir / label - hour_value = label_to_hour_value(label) - - copied_files = copy_noon_to_label(noon_dir, out_dir) - - for pcx_path in copied_files: - with Image.open(pcx_path) as im: - if im.mode != "P": - im = im.convert("P") - pal = get_palette(im) - - if do_index_remap: - im = remap_green_to_magenta_indices(im, pal) - - new_pal = adjust_palette_for_time( - pal, hour_value, reserved_colors, - warmth_scale=warmth_scale, - blue_scale=blue_scale, - darkness_scale=darkness_scale, - desat_scale=desat_scale, - sat_boost=sat_boost, - contrast=contrast, - sunrise_center=sunrise_center, - sunset_center=sunset_center, - twilight_sigma=twilight_sigma, - noon_blend=noon_blend, - noon_sigma=noon_sigma, - noon_window_start=noon_window_start, - noon_window_end=noon_window_end, - noon_window_soft=noon_window_soft, - ) - set_palette(im, new_pal) - im.save(pcx_path, format="PCX") - - -# --------------------------- Main --------------------------- - -def main(): - p = argparse.ArgumentParser(description="Civ3 PCX day/night generator with variable time steps and noon-neutral zone.") - p.add_argument("--data", required=True, - help="Parent folder containing the noon folder and sibling time folders (e.g., NightDay).") - p.add_argument("--noon", default="1200", - help="Name of the noon folder (default: 1200).") - p.add_argument("--only-hour", default=None, - help="Process only a single time label (e.g., 1900, 1930, or 2400).") - p.add_argument("--step-minutes", type=int, default=60, - help="Time step in minutes; must divide 60 (e.g., 5,10,15,20,30,60). Default: 60.") - - p.add_argument("--light-key", action="append", default=[], - help="Reserved color that must not change. Repeatable. '#RRGGBB' or 'R,G,B'.") - - # Look/feel controls - p.add_argument("--warmth", type=float, default=1.10, - help="Scale for sunrise/sunset warmth (1.0 = base).") - p.add_argument("--blue", type=float, default=1.12, - help="Scale for night-time blue emphasis (1.0 = base).") - p.add_argument("--darkness", type=float, default=1.08, - help="Scale for extra night darkening (1.0 = base).") - p.add_argument("--desat", type=float, default=0.85, - help="Scale for dusk/night desaturation toward gray (lower = richer).") - p.add_argument("--sat", type=float, default=1.05, - help="Global saturation multiplier after tint (1.0 = none).") - p.add_argument("--contrast", type=float, default=1.03, - help="Global contrast multiplier around mid 128 (1.0 = none).") - - # Curve placement/width - p.add_argument("--sunrise-center", type=float, default=6.0, - help="Hour center for sunrise warmth bump (0-23).") - p.add_argument("--sunset-center", type=float, default=18.0, - help="Hour center for sunset warmth bump (0-23).") - p.add_argument("--twilight-width", type=float, default=1.8, - help="Sigma for sunrise/sunset warmth spread (higher = broader).") - - # Noon-neutral zone controls (defaults keep ~10:00–14:00 close to noon) - p.add_argument("--noon-blend", type=float, default=0.85, - help="0..1 strength to blend toward base palette near 12:00 (0=off).") - p.add_argument("--noon-sigma", type=float, default=1.1, - help="Gaussian width (hours) around 12:00 (larger = broader).") - p.add_argument("--noon-window-start", type=float, default=10.0, - help="Start hour of the noon-like window (default 10.0).") - p.add_argument("--noon-window-end", type=float, default=14.0, - help="End hour of the noon-like window (default 14.0).") - p.add_argument("--noon-window-soft", type=float, default=0.7, - help="Soft edge (hours) for window ramps (0=hard).") - - # Index remap control - g = p.add_mutually_exclusive_group() - g.add_argument("--keep-green-index", action="store_true", - help="Do NOT remap green index to magenta; leave pixel indices unchanged.") - g.add_argument("--map-green-index", dest="map_green_index", action="store_true", - help="Force remap green index to magenta (default behavior).") - - args = p.parse_args() - - base_dir = Path(args.data).expanduser().resolve() - noon_dir = base_dir / args.noon - if not noon_dir.is_dir(): - raise SystemExit(f"Noon folder not found: {noon_dir}") - - # Reserved colors (Magenta + Green + user light-keys) - reserved: List[Tuple[int, int, int]] = [(255, 0, 255), (0, 255, 0)] - for s in args.light_key: - reserved.append(parse_rgb(s)) - - # Determine remap behavior (default ON) - do_index_remap = not args.keep_green_index or args.map_green_index - - # Build time labels for the given step, then exclude noon folder itself - labels = [lbl for lbl in time_labels(args.step_minutes) if lbl != args.noon] - - # only-hour (accept 0000 -> 2400) - if args.only_hour: - only = "2400" if args.only_hour == "0000" else args.only_hour - if only == args.noon: - print(f"--only-hour {only} is the noon source; nothing to do.") - return - if only not in labels: - raise SystemExit(f"--only-hour must be one of: {', '.join(labels)}") - labels = [only] - - print(f"Base: {base_dir}") - print(f"Noon source: {noon_dir}") - print(f"Time step: {args.step_minutes} minutes") - print(f"Index remap green→magenta: {'ON' if do_index_remap else 'OFF'}") - print(f"Generating labels: {', '.join(labels)}") - - for lbl in labels: - print(f" -> Generating {lbl} ...") - process_time_label( - lbl, base_dir, args.noon, reserved, - do_index_remap=do_index_remap, - warmth_scale=args.warmth, - blue_scale=args.blue, - darkness_scale=args.darkness, - desat_scale=args.desat, - sat_boost=args.sat, - contrast=args.contrast, - sunrise_center=args.sunrise_center, - sunset_center=args.sunset_center, - twilight_sigma=args.twilight_width, - noon_blend=args.noon_blend, - noon_sigma=args.noon_sigma, - noon_window_start=args.noon_window_start, - noon_window_end=args.noon_window_end, - noon_window_soft=args.noon_window_soft, - ) - - print("Done.") - - -if __name__ == "__main__": +#!/usr/bin/env python3 +""" +civ3_daynight_pcx.py — v4.3 (stronger nighttime blue + stable noon-neutral zone) + +Highlights: +- Half-hour (or any divisor of an hour) time slices via --step-minutes. +- Green→Magenta index remap (on by default). +- Palette-only tinting; indices preserved (except the optional index remap). +- Noon-neutral zone keeps ~10:00–14:00 close to base 1200. +- NEW: Stronger nighttime blue response using the existing --blue knob, + with an additional night-only hue shift (blue up, red/green down). + +Tested knobs (your current favorites work unchanged): + --warmth 1.05 --blue 2.0 --darkness 1.1 --desat 0.85 --sat 1.2 --contrast 1.08 + --sunrise-center 5.0 --sunset-center 18.0 --twilight-width 3.0 + --noon-blend 0.7 --noon-sigma 1.0 +""" + +import argparse +import shutil +from pathlib import Path +from typing import Iterable, List, Sequence, Tuple + +from PIL import Image + + +# --------------------------- CLI & helpers --------------------------- + +def parse_rgb(s: str) -> Tuple[int, int, int]: + s = s.strip() + if s.startswith("#"): + s = s[1:] + if len(s) != 6: + raise ValueError(f"Bad hex color: #{s}") + return tuple(int(s[i:i+2], 16) for i in (0, 2, 4)) # type: ignore + if "," in s: + parts = [p.strip() for p in s.split(",")] + if len(parts) != 3: + raise ValueError(f"Bad RGB list: {s}") + return tuple(int(p) for p in parts) # type: ignore + raise ValueError(f"Unrecognized color format: {s}") + + +def time_labels(step_minutes: int) -> List[str]: + """ + Generate HHMM labels from step to 23:59 stepwise; exclude 0000; add 2400. + For step=60: 0100..2300 + 2400 + For step=30: 0030, 0100, 0130..2330 + 2400 + """ + if step_minutes <= 0 or 60 % step_minutes != 0: + raise ValueError("--step-minutes must be a positive divisor of 60 (e.g., 5,10,15,20,30,60).") + labels: List[str] = [] + total_minutes = 24 * 60 + m = step_minutes + while m < total_minutes: + h = m // 60 + mm = m % 60 + labels.append(f"{h:02d}{mm:02d}") + m += step_minutes + labels.append("2400") + return labels + + +def clamp_byte(x: float) -> int: + return int(max(0, min(255, round(x)))) + + +# --------------------------- TONEMAP MODEL --------------------------- + +def _gauss(x: float, mu: float, sigma: float) -> float: + from math import exp + if sigma <= 0.0: + return 0.0 + return exp(-0.5 * ((x - mu) / sigma) ** 2) + + +def hour_adjustments( + hour_value: float, + *, + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, +) -> dict: + """ + hour_value can be fractional (e.g., 19.5 for 19:30). Period is 24h. + Returns a dict with per-channel multipliers, gray blend, brightness, + and 'night' + 'blue_push' factors for night-only hue shift. + """ + from math import cos, pi + + h = hour_value % 24.0 + + # Daylight (cosine): 1 at noon, ~0 at midnight + daylight = max(0.0, cos(pi * (h - 12.0) / 12.0)) # 0..1 + night = 1.0 - daylight + + # Warmth around sunrise/sunset + warmth = 0.85 * (_gauss(h, sunrise_center, twilight_sigma) + + _gauss(h, sunset_center, twilight_sigma)) + warmth *= warmth_scale + + # Brightness: darker at night; scaled by darkness_scale (>1 = darker nights) + base_brightness = 0.60 + 0.40 * daylight + night_darkening = 1.0 - (0.12 * (darkness_scale - 1.0) * night) + brightness = base_brightness * night_darkening + + # Channel multipliers + r_mul = 0.97 + 0.12 * daylight + 0.30 * warmth + g_mul = 0.97 + 0.12 * daylight + 0.12 * warmth + b_mul = 0.97 + 0.12 * daylight - 0.18 * warmth + (0.28 * blue_scale) * night + + # Desaturation (toward gray) stronger at night; scaled by desat_scale + gray_blend = (0.10 + 0.50 * night) * desat_scale + gray_blend = min(max(gray_blend, 0.0), 0.85) + + # Night-only blue push factor (extra hue shift at night) + # - grows with (blue_scale - 1) and with 'night' + # - kept separate from b_mul so daytime remains unchanged + blue_push = max(0.0, blue_scale - 1.0) * night # 0 at day, up to (blue-1) at night + + # Clamp gentle bounds + r_mul = min(max(r_mul, 0.65), 1.45) + g_mul = min(max(g_mul, 0.65), 1.40) + b_mul = min(max(b_mul, 0.65), 1.55) + + return dict( + brightness=brightness, + r_mul=r_mul, + g_mul=g_mul, + b_mul=b_mul, + gray_blend=gray_blend, + night=night, + blue_push=blue_push, + ) + + +def _apply_saturation(rgb: Tuple[float, float, float], sat: float) -> Tuple[float, float, float]: + r, g, b = rgb + gray = (r + g + b) / 3.0 + r = gray + (r - gray) * sat + g = gray + (g - gray) * sat + b = gray + (b - gray) * sat + return r, g, b + + +def _apply_contrast(rgb: Tuple[float, float, float], contrast: float) -> Tuple[float, float, float]: + r, g, b = rgb + r = 128 + (r - 128) * contrast + g = 128 + (g - 128) * contrast + b = 128 + (b - 128) * contrast + return r, g, b + + +def _apply_night_blue_push( + rgb: Tuple[float, float, float], + blue_push: float, +) -> Tuple[float, float, float]: + """ + Extra night-only hue shift: + - Slightly reduces R and G + - Increases B + 'blue_push' is ~ (blue_scale - 1) * night, so this is zero in daytime. + Coefficients tuned to be visible but not cartoonish; adjust if needed. + """ + if blue_push <= 0.0: + return rgb + r, g, b = rgb + c = blue_push # c in [0..(blue-1)] scaled by night + # Gentle but noticeable: at c=1 (e.g., --blue 2.0 at full night) + r *= (1.0 - 0.15 * c) + g *= (1.0 - 0.10 * c) + b *= (1.0 + 0.35 * c) + return r, g, b + + +def tint_rgb( + rgb: Tuple[int, int, int], + params: dict, + *, + sat_boost: float, + contrast: float, +) -> Tuple[int, int, int]: + r, g, b = rgb + r_f = r * params["r_mul"] * params["brightness"] + g_f = g * params["g_mul"] * params["brightness"] + b_f = b * params["b_mul"] * params["brightness"] + + gray = (r_f + g_f + b_f) / 3.0 + t = params["gray_blend"] + r_f = (1 - t) * r_f + t * gray + g_f = (1 - t) * g_f + t * gray + b_f = (1 - t) * b_f + t * gray + + # Global saturation, then extra night-only blue hue push, then contrast + r_f, g_f, b_f = _apply_saturation((r_f, g_f, b_f), sat_boost) + r_f, g_f, b_f = _apply_night_blue_push((r_f, g_f, b_f), params.get("blue_push", 0.0)) + r_f, g_f, b_f = _apply_contrast((r_f, g_f, b_f), contrast) + + return (clamp_byte(r_f), clamp_byte(g_f), clamp_byte(b_f)) + + +# --------------------------- Noon-neutral weighting --------------------------- + +def _smoothstep01(t: float) -> float: + """Cubic smoothstep on [0,1].""" + if t <= 0.0: + return 0.0 + if t >= 1.0: + return 1.0 + return t * t * (3.0 - 2.0 * t) + + +def _interval_membership(x: float, a: float, b: float, soft: float) -> float: + """ + Smooth membership of time-of-day x (0..24) inside interval [a,b] (hours), + with soft edge width 'soft' (hours). Supports wrapped intervals (a>b). + Returns 0..1. + """ + x = x % 24.0 + a = a % 24.0 + b = b % 24.0 + soft = max(0.0, soft) + + def segment_membership(x: float, s: float, e: float, soft: float) -> float: + # Non-wrapped segment s <= e in [0,24] + if soft <= 0.0: + return 1.0 if (s <= x <= e) else 0.0 + + # Left ramp [s-soft, s] + if s - soft <= x < s: + t = (x - (s - soft)) / soft # 0..1 + return _smoothstep01(t) + + # Core [s, e] + if s <= x <= e: + return 1.0 + + # Right ramp [e, e+soft] + if e < x <= e + soft: + t = (x - e) / soft # 0..1 + return 1.0 - _smoothstep01(t) + + return 0.0 + + if a <= b: + return segment_membership(x, a, b, soft) + else: + # Wrapped interval: union of [a,24) and [0,b] + m1 = segment_membership(x, a, 24.0, soft) + m2 = segment_membership(x, 0.0, b, soft) + return max(m1, m2) + + +def _noon_weight(hour_value: float, blend: float, sigma: float, + w_start: float, w_end: float, w_soft: float) -> float: + """ + Combined noon weight in 0..1: + - Gaussian around 12:00 with width 'sigma' (hours), scaled by 'blend'. + - Smooth interval window [w_start, w_end] with soft edges 'w_soft', + also scaled by 'blend'. + - The final weight is max of both components, clamped 0..1. + """ + try: + h = hour_value % 24.0 + except Exception: + h = 0.0 + blend = float(blend) if blend is not None else 0.0 + sigma = float(sigma) if sigma is not None else 0.0 + w_start = float(w_start) if w_start is not None else 10.0 + w_end = float(w_end) if w_end is not None else 14.0 + w_soft = max(0.0, float(w_soft) if w_soft is not None else 0.7) + + if blend <= 0.0: + return 0.0 + + # Gaussian around noon + from math import exp + d = abs(h - 12.0) + d = min(d, 24.0 - d) + g = exp(-0.5 * (d / sigma) ** 2) if sigma > 0.0 else 0.0 + g *= blend + + # Smooth window + window_m = _interval_membership(h, w_start, w_end, w_soft) * blend + + w = max(g, window_m) + if w < 0.0: + return 0.0 + if w > 1.0: + return 1.0 + return w + + +# --------------------------- Palette helpers --------------------------- + +def get_palette(img: Image.Image) -> List[int]: + pal = img.getpalette() + if pal is None: + raise ValueError("Image has no palette (mode must be 'P').") + if len(pal) < 256 * 3: + pal = pal + [0] * (256 * 3 - len(pal)) + return pal[:256 * 3] + + +def set_palette(img: Image.Image, pal: Sequence[int]) -> None: + if len(pal) != 256 * 3: + raise ValueError("Palette must be exactly 256*3 entries.") + img.putpalette(list(pal)) + + +def find_color_index(pal: Sequence[int], color: Tuple[int, int, int]) -> int: + cr, cg, cb = color + for i in range(256): + r, g, b = pal[3*i:3*i+3] + if r == cr and g == cg and b == cb: + return i + return -1 + + +# --------------------------- Core operations --------------------------- + +def adjust_palette_for_time( + pal: List[int], + hour_value: float, + reserved_colors: Iterable[Tuple[int, int, int]], + *, + # look controls + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sat_boost: float, + contrast: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, + # noon neutral zone controls + noon_blend: float, + noon_sigma: float, + noon_window_start: float, + noon_window_end: float, + noon_window_soft: float, +) -> List[int]: + params = hour_adjustments( + hour_value, + warmth_scale=warmth_scale, + blue_scale=blue_scale, + darkness_scale=darkness_scale, + desat_scale=desat_scale, + sunrise_center=sunrise_center, + sunset_center=sunset_center, + twilight_sigma=twilight_sigma, + ) + reserved = set(reserved_colors) + + # Noon weight (0..1): stronger near 10:00–14:00, peak at 12:00 + noon_w = _noon_weight( + hour_value, noon_blend, noon_sigma, + noon_window_start, noon_window_end, noon_window_soft + ) + + # Damp sat/contrast near noon to avoid “pop” + sat_eff = 1.0 + (sat_boost - 1.0) * (1.0 - noon_w) + contrast_eff = 1.0 + (contrast - 1.0) * (1.0 - noon_w) + + out = pal[:] # copy + for i in range(256): + r, g, b = pal[3 * i:3 * i + 3] + rgb = (r, g, b) + + if rgb in reserved: + out[3 * i + 0] = r + out[3 * i + 1] = g + out[3 * i + 2] = b + continue + + nr, ng, nb = tint_rgb(rgb, params, sat_boost=sat_eff, contrast=contrast_eff) + + if noon_w > 0.0: + # Blend back toward the original (noon) palette color at the SAME index + nr = int(round((1.0 - noon_w) * nr + noon_w * r)) + ng = int(round((1.0 - noon_w) * ng + noon_w * g)) + nb = int(round((1.0 - noon_w) * nb + noon_w * b)) + + out[3 * i + 0] = nr + out[3 * i + 1] = ng + out[3 * i + 2] = nb + + return out + + +def remap_green_to_magenta_indices(img: Image.Image, pal: Sequence[int]) -> Image.Image: + green_idx = find_color_index(pal, (0, 255, 0)) + magenta_idx = find_color_index(pal, (255, 0, 255)) + if green_idx < 0 or magenta_idx < 0 or green_idx == magenta_idx: + return img + lut = [magenta_idx if i == green_idx else i for i in range(256)] + return img.point(lut, mode="P") + + +# --------------------------- File ops --------------------------- + +def copy_noon_to_label(noon_dir: Path, label_dir: Path) -> List[Path]: + label_dir.mkdir(parents=True, exist_ok=True) + copied: List[Path] = [] + for src in noon_dir.glob("*.pcx"): + dst = label_dir / src.name + shutil.copy2(src, dst) + copied.append(dst) + return copied + + +def label_to_hour_value(label: str) -> float: + """Convert 'HHMM' or '2400' to hour value (fractional hours).""" + if label == "2400": + return 0.0 + h = int(label[:2]) + m = int(label[2:]) + return (h % 24) + (m / 60.0) + + +def process_time_label( + label: str, + base_dir: Path, + noon_label: str, + reserved_colors: Iterable[Tuple[int, int, int]], + *, + do_index_remap: bool, + # look controls + warmth_scale: float, + blue_scale: float, + darkness_scale: float, + desat_scale: float, + sat_boost: float, + contrast: float, + sunrise_center: float, + sunset_center: float, + twilight_sigma: float, + # noon neutral controls + noon_blend: float, + noon_sigma: float, + noon_window_start: float, + noon_window_end: float, + noon_window_soft: float, +) -> None: + noon_dir = base_dir / noon_label + out_dir = base_dir / label + hour_value = label_to_hour_value(label) + + copied_files = copy_noon_to_label(noon_dir, out_dir) + + for pcx_path in copied_files: + with Image.open(pcx_path) as im: + if im.mode != "P": + im = im.convert("P") + pal = get_palette(im) + + if do_index_remap: + im = remap_green_to_magenta_indices(im, pal) + + new_pal = adjust_palette_for_time( + pal, hour_value, reserved_colors, + warmth_scale=warmth_scale, + blue_scale=blue_scale, + darkness_scale=darkness_scale, + desat_scale=desat_scale, + sat_boost=sat_boost, + contrast=contrast, + sunrise_center=sunrise_center, + sunset_center=sunset_center, + twilight_sigma=twilight_sigma, + noon_blend=noon_blend, + noon_sigma=noon_sigma, + noon_window_start=noon_window_start, + noon_window_end=noon_window_end, + noon_window_soft=noon_window_soft, + ) + set_palette(im, new_pal) + im.save(pcx_path, format="PCX") + + +# --------------------------- Main --------------------------- + +def main(): + p = argparse.ArgumentParser(description="Civ3 PCX day/night generator with variable time steps and noon-neutral zone.") + p.add_argument("--data", required=True, + help="Parent folder containing the noon folder and sibling time folders (e.g., NightDay).") + p.add_argument("--noon", default="1200", + help="Name of the noon folder (default: 1200).") + p.add_argument("--only-hour", default=None, + help="Process only a single time label (e.g., 1900, 1930, or 2400).") + p.add_argument("--step-minutes", type=int, default=60, + help="Time step in minutes; must divide 60 (e.g., 5,10,15,20,30,60). Default: 60.") + + p.add_argument("--light-key", action="append", default=[], + help="Reserved color that must not change. Repeatable. '#RRGGBB' or 'R,G,B'.") + + # Look/feel controls + p.add_argument("--warmth", type=float, default=1.10, + help="Scale for sunrise/sunset warmth (1.0 = base).") + p.add_argument("--blue", type=float, default=1.12, + help="Scale for night-time blue emphasis (1.0 = base).") + p.add_argument("--darkness", type=float, default=1.08, + help="Scale for extra night darkening (1.0 = base).") + p.add_argument("--desat", type=float, default=0.85, + help="Scale for dusk/night desaturation toward gray (lower = richer).") + p.add_argument("--sat", type=float, default=1.05, + help="Global saturation multiplier after tint (1.0 = none).") + p.add_argument("--contrast", type=float, default=1.03, + help="Global contrast multiplier around mid 128 (1.0 = none).") + + # Curve placement/width + p.add_argument("--sunrise-center", type=float, default=6.0, + help="Hour center for sunrise warmth bump (0-23).") + p.add_argument("--sunset-center", type=float, default=18.0, + help="Hour center for sunset warmth bump (0-23).") + p.add_argument("--twilight-width", type=float, default=1.8, + help="Sigma for sunrise/sunset warmth spread (higher = broader).") + + # Noon-neutral zone controls (defaults keep ~10:00–14:00 close to noon) + p.add_argument("--noon-blend", type=float, default=0.85, + help="0..1 strength to blend toward base palette near 12:00 (0=off).") + p.add_argument("--noon-sigma", type=float, default=1.1, + help="Gaussian width (hours) around 12:00 (larger = broader).") + p.add_argument("--noon-window-start", type=float, default=10.0, + help="Start hour of the noon-like window (default 10.0).") + p.add_argument("--noon-window-end", type=float, default=14.0, + help="End hour of the noon-like window (default 14.0).") + p.add_argument("--noon-window-soft", type=float, default=0.7, + help="Soft edge (hours) for window ramps (0=hard).") + + # Index remap control + g = p.add_mutually_exclusive_group() + g.add_argument("--keep-green-index", action="store_true", + help="Do NOT remap green index to magenta; leave pixel indices unchanged.") + g.add_argument("--map-green-index", dest="map_green_index", action="store_true", + help="Force remap green index to magenta (default behavior).") + + args = p.parse_args() + + base_dir = Path(args.data).expanduser().resolve() + noon_dir = base_dir / args.noon + if not noon_dir.is_dir(): + raise SystemExit(f"Noon folder not found: {noon_dir}") + + # Reserved colors (Magenta + Green + user light-keys) + reserved: List[Tuple[int, int, int]] = [(255, 0, 255), (0, 255, 0)] + for s in args.light_key: + reserved.append(parse_rgb(s)) + + # Determine remap behavior (default ON) + do_index_remap = not args.keep_green_index or args.map_green_index + + # Build time labels for the given step, then exclude noon folder itself + labels = [lbl for lbl in time_labels(args.step_minutes) if lbl != args.noon] + + # only-hour (accept 0000 -> 2400) + if args.only_hour: + only = "2400" if args.only_hour == "0000" else args.only_hour + if only == args.noon: + print(f"--only-hour {only} is the noon source; nothing to do.") + return + if only not in labels: + raise SystemExit(f"--only-hour must be one of: {', '.join(labels)}") + labels = [only] + + print(f"Base: {base_dir}") + print(f"Noon source: {noon_dir}") + print(f"Time step: {args.step_minutes} minutes") + print(f"Index remap green→magenta: {'ON' if do_index_remap else 'OFF'}") + print(f"Generating labels: {', '.join(labels)}") + + for lbl in labels: + print(f" -> Generating {lbl} ...") + process_time_label( + lbl, base_dir, args.noon, reserved, + do_index_remap=do_index_remap, + warmth_scale=args.warmth, + blue_scale=args.blue, + darkness_scale=args.darkness, + desat_scale=args.desat, + sat_boost=args.sat, + contrast=args.contrast, + sunrise_center=args.sunrise_center, + sunset_center=args.sunset_center, + twilight_sigma=args.twilight_width, + noon_blend=args.noon_blend, + noon_sigma=args.noon_sigma, + noon_window_start=args.noon_window_start, + noon_window_end=args.noon_window_end, + noon_window_soft=args.noon_window_soft, + ) + + print("Done.") + + +if __name__ == "__main__": main() \ No newline at end of file diff --git a/DayNight/civ3_postprocess_pixels.py b/DayNight/civ3_postprocess_pixels.py index c60ce452..eb8a26c0 100644 --- a/DayNight/civ3_postprocess_pixels.py +++ b/DayNight/civ3_postprocess_pixels.py @@ -1,280 +1,280 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -Civ3 post-process: remove GREEN (#00ff00) pixels from PCX outputs. - -Rules ------ -• Recursively scan under Data/*hour* folders (0100..2400 etc.), skipping the noon folder. -• Only touch files that have a corresponding "*_lights.pcx" in the same directory: - - For "NAME.pcx" → process only if "NAME_lights.pcx" exists. - - For "NAME_lights.pcx" → always process (it is the corresponding lights file). -• By default, only replace *isolated* green pixels: a green pixel whose neighbors within - --isolation-radius (default 1, i.e. the 8-connected ring) contain no other green pixels. -• With --remove-all-green, replace *all* green pixels. -• Replacement uses *neighbor palette indices* so the palette stays unchanged. - If no non-green neighbors exist, fall back to nearest palette color to local RGB average. - -Usage ------ - python civ3_fix_green.py --data ./Data --noon 1200 --verbose - # knobs: - # --isolation-radius 1 (1 = 8-neighborhood) - # --search-radius 3 - # --max-radius 5 - # --remove-all-green -""" - -import argparse, os, collections -from typing import Tuple, List, Set -from PIL import Image - -GREEN = (0, 255, 0) -MAGENTA = (255, 0, 255) - -# ---------- palette helpers ---------- - -def get_palette(im: Image.Image) -> List[int]: - pal = im.getpalette() or [] - if len(pal) < 256*3: - pal += [0]*(256*3 - len(pal)) - return pal[:256*3] - -def find_color_index(pal: List[int], rgb: Tuple[int,int,int]) -> int: - r,g,b = rgb - for i in range(256): - if pal[3*i] == r and pal[3*i+1] == g and pal[3*i+2] == b: - return i - return -1 - -def nearest_palette_index(target_rgb: Tuple[int,int,int], pal: List[int], banned: Set[int]) -> int: - """Choose the palette index (not in banned) whose RGB is nearest (Euclidean).""" - tr,tg,tb = target_rgb - best_i, best_d = None, 10**9 - for i in range(256): - if i in banned: continue - r,g,b = pal[3*i], pal[3*i+1], pal[3*i+2] - dr, dg, db = tr-r, tg-g, tb-b - d = dr*dr + dg*dg + db*db - if d < best_d: - best_d, best_i = d, i - return best_i if best_i is not None else 0 - -# ---------- neighborhood ops ---------- - -def has_green_neighbor(rgb_img: Image.Image, x: int, y: int, radius: int) -> bool: - """Return True if any neighbor within Chebyshev radius is GREEN (#00ff00).""" - w, h = rgb_img.size - px = rgb_img.load() - r = max(1, int(radius)) - for yy in range(max(0, y-r), min(h, y+r+1)): - for xx in range(max(0, x-r), min(w, x+r+1)): - if xx == x and yy == y: - continue - if px[xx,yy] == GREEN: - return True - return False - -def gather_neighbor_indices(idx_img: Image.Image, rgb_img: Image.Image, - x: int, y: int, radius: int, - green_idx: int, mag_idx: int) -> List[int]: - """Collect neighbor indices around (x,y) within Chebyshev radius; exclude green/magenta.""" - w, h = idx_img.size - px_idx = idx_img.load() - px_rgb = rgb_img.load() - out = [] - r = max(1, int(radius)) - for yy in range(max(0, y-r), min(h, y+r+1)): - for xx in range(max(0, x-r), min(w, x+r+1)): - if xx == x and yy == y: continue - i = px_idx[xx, yy] - r0,g0,b0 = px_rgb[xx, yy] - if (r0,g0,b0) == GREEN or (r0,g0,b0) == MAGENTA: - continue - if i == green_idx or i == mag_idx: - continue - out.append(i) - return out - -def local_average_rgb(rgb_img: Image.Image, x: int, y: int, radius: int, - skip_colors: Set[Tuple[int,int,int]]) -> Tuple[int,int,int]: - """Average RGB in a square window, skipping listed colors; falls back to (0,0,0).""" - w, h = rgb_img.size - px = rgb_img.load() - total = [0,0,0] - n = 0 - r = max(1, int(radius)) - for yy in range(max(0, y-r), min(h, y+r+1)): - for xx in range(max(0, x-r), min(w, x+r+1)): - c = px[xx, yy] - if c in skip_colors: - continue - total[0] += c[0]; total[1] += c[1]; total[2] += c[2] - n += 1 - if n == 0: - return (0,0,0) - return (total[0]//n, total[1]//n, total[2]//n) - -# ---------- core fixer ---------- - -def fix_green_in_image(path: str, isolation_radius: int, search_radius: int, max_radius: int, - remove_all_green: bool, verbose: bool=False) -> int: - """ - Returns number of pixels changed (only isolated greens are touched). - """ - try: - imP = Image.open(path) - except Exception: - return 0 - if imP.mode != 'P': - return 0 - - pal = get_palette(imP) - green_idx = find_color_index(pal, GREEN) - mag_idx = find_color_index(pal, MAGENTA) - - imRGB = imP.convert('RGB') - px = imRGB.load() - w, h = imRGB.size - - # Collect target green pixels - coords = [] - if remove_all_green: - for y in range(h): - for x in range(w): - if px[x, y] == GREEN: - coords.append((x, y)) - else: - for y in range(h): - for x in range(w): - if px[x, y] == GREEN and not has_green_neighbor(imRGB, x, y, isolation_radius): - coords.append((x, y)) - - if not coords: - return 0 - - outP = imP.copy() - out_px = outP.load() - banned_indices = set() - if green_idx != -1: banned_indices.add(green_idx) - if mag_idx != -1: banned_indices.add(mag_idx) - - changed = 0 - for (x,y) in coords: - if remove_all_green and mag_idx != -1: - out_px[x, y] = mag_idx - changed += 1 - continue - - picked_index = None - - # 1) Most frequent neighbor index (expand search out to max_radius if needed) - r = max(1, int(search_radius)) - m = max(r, int(max_radius)) - while r <= m and picked_index is None: - neigh = gather_neighbor_indices(imP, imRGB, x, y, r, green_idx, mag_idx) - if neigh: - cnt = collections.Counter(neigh) - picked_index = cnt.most_common(1)[0][0] - break - r += 1 - - # 2) Fallback: nearest palette color to local average (excluding banned) - if picked_index is None: - avg_rgb = local_average_rgb(imRGB, x, y, radius=m, skip_colors={GREEN, MAGENTA}) - picked_index = nearest_palette_index(avg_rgb, pal, banned_indices) - - if picked_index is not None: - out_px[x,y] = picked_index - changed += 1 - - if changed > 0: - outP.putpalette(pal) # keep palette exactly the same - outP.save(path, format='PCX') - if verbose: - if remove_all_green: - print(f"[fixed] {path}: {changed} green px") - else: - print(f"[fixed] {path}: {changed} isolated green px") - else: - if verbose: - print(f"[ok] {path}: no isolated green px") - - return changed - -# ---------- file selection logic ---------- - -def has_corresponding_lights(dirpath: str, fname: str) -> bool: - """ - Return True iff this file should be processed according to the rule: - • If fname ends with '_lights.pcx' → True. - • Else if a sibling '_lights.pcx' exists → True. - • Otherwise False. - """ - name_lower = fname.lower() - if name_lower.endswith("_lights.pcx"): - return True - if not name_lower.endswith(".pcx"): - return False - stem = fname[:-4] # remove '.pcx' - lights_name = stem + "_lights.pcx" - return os.path.exists(os.path.join(dirpath, lights_name)) - -def walk_and_fix(data_dir: str, noon_folder: str, - isolation_radius: int, search_radius: int, max_radius: int, - remove_all_green: bool, only_hour: int=None, verbose: bool=False) -> None: - noon_abs = os.path.normpath(os.path.join(data_dir, noon_folder)) - annotations_abs = os.path.normpath(os.path.join(data_dir, "Annotations")) - targets = [] - - if only_hour is not None: - hour_name = f"{only_hour:04d}" - hour_abs = os.path.normpath(os.path.join(data_dir, hour_name)) - if os.path.isdir(hour_abs): - targets.append(hour_abs) - else: - print(f"[warn] Hour folder not found: {hour_abs}") - else: - for name in os.listdir(data_dir): - sub = os.path.normpath(os.path.join(data_dir, name)) - if not os.path.isdir(sub): continue - if os.path.normcase(sub) == os.path.normcase(noon_abs): continue - if os.path.normcase(sub) == os.path.normcase(annotations_abs): continue - targets.append(sub) - - total_changed = 0 - for root in targets: - for dirpath, _, filenames in os.walk(root): - for fname in filenames: - if not fname.lower().endswith(".pcx"): - continue - if not has_corresponding_lights(dirpath, fname): - continue - path = os.path.join(dirpath, fname) - total_changed += fix_green_in_image( - path, isolation_radius, search_radius, max_radius, - remove_all_green, verbose=verbose - ) - - print(f"Done. Total isolated green pixels fixed: {total_changed}") - -def main(): - ap = argparse.ArgumentParser(description="Remove #00ff00 pixels from PCX outputs (only files with a matching _lights.pcx).") - ap.add_argument("--data", required=True, help="Path to Data root (contains noon + hour folders).") - ap.add_argument("--noon", default="1200", help="Name of noon folder to SKIP. Default: 1200") - ap.add_argument("--only-hour", type=int, help="Restrict to a single hour folder (e.g., 2400)") - ap.add_argument("--isolation-radius", type=int, default=1, help="Green is 'isolated' if no other green is found within this Chebyshev radius. Default: 1 (8-neighborhood)") - ap.add_argument("--search-radius", type=int, default=3, help="Neighbor radius (pixels) for index voting. Default: 3") - ap.add_argument("--max-radius", type=int, default=5, help="Max expansion radius if no neighbor found. Default: 5") - ap.add_argument("--remove-all-green", action="store_true", help="Replace all #00ff00 pixels (default: only isolated).") - ap.add_argument("--verbose", action="store_true", help="Print per-file changes.") - args = ap.parse_args() - - walk_and_fix( - args.data, args.noon, args.isolation_radius, args.search_radius, args.max_radius, - args.remove_all_green, args.only_hour, verbose=args.verbose - ) - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Civ3 post-process: remove GREEN (#00ff00) pixels from PCX outputs. + +Rules +----- +• Recursively scan under Data/*hour* folders (0100..2400 etc.), skipping the noon folder. +• Only touch files that have a corresponding "*_lights.pcx" in the same directory: + - For "NAME.pcx" → process only if "NAME_lights.pcx" exists. + - For "NAME_lights.pcx" → always process (it is the corresponding lights file). +• By default, only replace *isolated* green pixels: a green pixel whose neighbors within + --isolation-radius (default 1, i.e. the 8-connected ring) contain no other green pixels. +• With --remove-all-green, replace *all* green pixels. +• Replacement uses *neighbor palette indices* so the palette stays unchanged. + If no non-green neighbors exist, fall back to nearest palette color to local RGB average. + +Usage +----- + python civ3_fix_green.py --data ./Data --noon 1200 --verbose + # knobs: + # --isolation-radius 1 (1 = 8-neighborhood) + # --search-radius 3 + # --max-radius 5 + # --remove-all-green +""" + +import argparse, os, collections +from typing import Tuple, List, Set +from PIL import Image + +GREEN = (0, 255, 0) +MAGENTA = (255, 0, 255) + +# ---------- palette helpers ---------- + +def get_palette(im: Image.Image) -> List[int]: + pal = im.getpalette() or [] + if len(pal) < 256*3: + pal += [0]*(256*3 - len(pal)) + return pal[:256*3] + +def find_color_index(pal: List[int], rgb: Tuple[int,int,int]) -> int: + r,g,b = rgb + for i in range(256): + if pal[3*i] == r and pal[3*i+1] == g and pal[3*i+2] == b: + return i + return -1 + +def nearest_palette_index(target_rgb: Tuple[int,int,int], pal: List[int], banned: Set[int]) -> int: + """Choose the palette index (not in banned) whose RGB is nearest (Euclidean).""" + tr,tg,tb = target_rgb + best_i, best_d = None, 10**9 + for i in range(256): + if i in banned: continue + r,g,b = pal[3*i], pal[3*i+1], pal[3*i+2] + dr, dg, db = tr-r, tg-g, tb-b + d = dr*dr + dg*dg + db*db + if d < best_d: + best_d, best_i = d, i + return best_i if best_i is not None else 0 + +# ---------- neighborhood ops ---------- + +def has_green_neighbor(rgb_img: Image.Image, x: int, y: int, radius: int) -> bool: + """Return True if any neighbor within Chebyshev radius is GREEN (#00ff00).""" + w, h = rgb_img.size + px = rgb_img.load() + r = max(1, int(radius)) + for yy in range(max(0, y-r), min(h, y+r+1)): + for xx in range(max(0, x-r), min(w, x+r+1)): + if xx == x and yy == y: + continue + if px[xx,yy] == GREEN: + return True + return False + +def gather_neighbor_indices(idx_img: Image.Image, rgb_img: Image.Image, + x: int, y: int, radius: int, + green_idx: int, mag_idx: int) -> List[int]: + """Collect neighbor indices around (x,y) within Chebyshev radius; exclude green/magenta.""" + w, h = idx_img.size + px_idx = idx_img.load() + px_rgb = rgb_img.load() + out = [] + r = max(1, int(radius)) + for yy in range(max(0, y-r), min(h, y+r+1)): + for xx in range(max(0, x-r), min(w, x+r+1)): + if xx == x and yy == y: continue + i = px_idx[xx, yy] + r0,g0,b0 = px_rgb[xx, yy] + if (r0,g0,b0) == GREEN or (r0,g0,b0) == MAGENTA: + continue + if i == green_idx or i == mag_idx: + continue + out.append(i) + return out + +def local_average_rgb(rgb_img: Image.Image, x: int, y: int, radius: int, + skip_colors: Set[Tuple[int,int,int]]) -> Tuple[int,int,int]: + """Average RGB in a square window, skipping listed colors; falls back to (0,0,0).""" + w, h = rgb_img.size + px = rgb_img.load() + total = [0,0,0] + n = 0 + r = max(1, int(radius)) + for yy in range(max(0, y-r), min(h, y+r+1)): + for xx in range(max(0, x-r), min(w, x+r+1)): + c = px[xx, yy] + if c in skip_colors: + continue + total[0] += c[0]; total[1] += c[1]; total[2] += c[2] + n += 1 + if n == 0: + return (0,0,0) + return (total[0]//n, total[1]//n, total[2]//n) + +# ---------- core fixer ---------- + +def fix_green_in_image(path: str, isolation_radius: int, search_radius: int, max_radius: int, + remove_all_green: bool, verbose: bool=False) -> int: + """ + Returns number of pixels changed (only isolated greens are touched). + """ + try: + imP = Image.open(path) + except Exception: + return 0 + if imP.mode != 'P': + return 0 + + pal = get_palette(imP) + green_idx = find_color_index(pal, GREEN) + mag_idx = find_color_index(pal, MAGENTA) + + imRGB = imP.convert('RGB') + px = imRGB.load() + w, h = imRGB.size + + # Collect target green pixels + coords = [] + if remove_all_green: + for y in range(h): + for x in range(w): + if px[x, y] == GREEN: + coords.append((x, y)) + else: + for y in range(h): + for x in range(w): + if px[x, y] == GREEN and not has_green_neighbor(imRGB, x, y, isolation_radius): + coords.append((x, y)) + + if not coords: + return 0 + + outP = imP.copy() + out_px = outP.load() + banned_indices = set() + if green_idx != -1: banned_indices.add(green_idx) + if mag_idx != -1: banned_indices.add(mag_idx) + + changed = 0 + for (x,y) in coords: + if remove_all_green and mag_idx != -1: + out_px[x, y] = mag_idx + changed += 1 + continue + + picked_index = None + + # 1) Most frequent neighbor index (expand search out to max_radius if needed) + r = max(1, int(search_radius)) + m = max(r, int(max_radius)) + while r <= m and picked_index is None: + neigh = gather_neighbor_indices(imP, imRGB, x, y, r, green_idx, mag_idx) + if neigh: + cnt = collections.Counter(neigh) + picked_index = cnt.most_common(1)[0][0] + break + r += 1 + + # 2) Fallback: nearest palette color to local average (excluding banned) + if picked_index is None: + avg_rgb = local_average_rgb(imRGB, x, y, radius=m, skip_colors={GREEN, MAGENTA}) + picked_index = nearest_palette_index(avg_rgb, pal, banned_indices) + + if picked_index is not None: + out_px[x,y] = picked_index + changed += 1 + + if changed > 0: + outP.putpalette(pal) # keep palette exactly the same + outP.save(path, format='PCX') + if verbose: + if remove_all_green: + print(f"[fixed] {path}: {changed} green px") + else: + print(f"[fixed] {path}: {changed} isolated green px") + else: + if verbose: + print(f"[ok] {path}: no isolated green px") + + return changed + +# ---------- file selection logic ---------- + +def has_corresponding_lights(dirpath: str, fname: str) -> bool: + """ + Return True iff this file should be processed according to the rule: + • If fname ends with '_lights.pcx' → True. + • Else if a sibling '_lights.pcx' exists → True. + • Otherwise False. + """ + name_lower = fname.lower() + if name_lower.endswith("_lights.pcx"): + return True + if not name_lower.endswith(".pcx"): + return False + stem = fname[:-4] # remove '.pcx' + lights_name = stem + "_lights.pcx" + return os.path.exists(os.path.join(dirpath, lights_name)) + +def walk_and_fix(data_dir: str, noon_folder: str, + isolation_radius: int, search_radius: int, max_radius: int, + remove_all_green: bool, only_hour: int=None, verbose: bool=False) -> None: + noon_abs = os.path.normpath(os.path.join(data_dir, noon_folder)) + annotations_abs = os.path.normpath(os.path.join(data_dir, "Annotations")) + targets = [] + + if only_hour is not None: + hour_name = f"{only_hour:04d}" + hour_abs = os.path.normpath(os.path.join(data_dir, hour_name)) + if os.path.isdir(hour_abs): + targets.append(hour_abs) + else: + print(f"[warn] Hour folder not found: {hour_abs}") + else: + for name in os.listdir(data_dir): + sub = os.path.normpath(os.path.join(data_dir, name)) + if not os.path.isdir(sub): continue + if os.path.normcase(sub) == os.path.normcase(noon_abs): continue + if os.path.normcase(sub) == os.path.normcase(annotations_abs): continue + targets.append(sub) + + total_changed = 0 + for root in targets: + for dirpath, _, filenames in os.walk(root): + for fname in filenames: + if not fname.lower().endswith(".pcx"): + continue + if not has_corresponding_lights(dirpath, fname): + continue + path = os.path.join(dirpath, fname) + total_changed += fix_green_in_image( + path, isolation_radius, search_radius, max_radius, + remove_all_green, verbose=verbose + ) + + print(f"Done. Total isolated green pixels fixed: {total_changed}") + +def main(): + ap = argparse.ArgumentParser(description="Remove #00ff00 pixels from PCX outputs (only files with a matching _lights.pcx).") + ap.add_argument("--data", required=True, help="Path to Data root (contains noon + hour folders).") + ap.add_argument("--noon", default="1200", help="Name of noon folder to SKIP. Default: 1200") + ap.add_argument("--only-hour", type=int, help="Restrict to a single hour folder (e.g., 2400)") + ap.add_argument("--isolation-radius", type=int, default=1, help="Green is 'isolated' if no other green is found within this Chebyshev radius. Default: 1 (8-neighborhood)") + ap.add_argument("--search-radius", type=int, default=3, help="Neighbor radius (pixels) for index voting. Default: 3") + ap.add_argument("--max-radius", type=int, default=5, help="Max expansion radius if no neighbor found. Default: 5") + ap.add_argument("--remove-all-green", action="store_true", help="Replace all #00ff00 pixels (default: only isolated).") + ap.add_argument("--verbose", action="store_true", help="Print per-file changes.") + args = ap.parse_args() + + walk_and_fix( + args.data, args.noon, args.isolation_radius, args.search_radius, args.max_radius, + args.remove_all_green, args.only_hour, verbose=args.verbose + ) + +if __name__ == "__main__": + main() diff --git a/DayNight/find_least_used_colors.py b/DayNight/find_least_used_colors.py index 0895da6d..05a50c00 100644 --- a/DayNight/find_least_used_colors.py +++ b/DayNight/find_least_used_colors.py @@ -1,98 +1,98 @@ -#!/usr/bin/env python3 -""" -least_used_pcx_colors.py - -Reads a paletted (8-bit, mode 'P') PCX file and prints the top 5 least used -colors among indices [0..254] by default. - -Output columns: index, HTML color (#RRGGBB), count - -Usage: - python least_used_pcx_colors.py path/to/image.pcx - # include colors that never appear: - python least_used_pcx_colors.py image.pcx --include-zeros - # change the highest considered index: - python least_used_pcx_colors.py image.pcx --max-index 255 -""" - -import argparse -import sys -from PIL import Image - -def idx_to_hex(rgb_tuple): - r, g, b = rgb_tuple - return f"#{r:02X}{g:02X}{b:02X}" - -def main(): - parser = argparse.ArgumentParser(description="Find least-used colors in a paletted PCX.") - parser.add_argument("pcx_path", help="Path to the PCX file (8-bit paletted).") - parser.add_argument("--include-zeros", action="store_true", default=True, - help="Include palette indices that occur 0 times.") - parser.add_argument("--max-index", type=int, default=254, - help="Highest palette index to consider (default: 254).") - parser.add_argument("--top", type=int, default=10, - help="How many least-used colors to return (default: 10).") - args = parser.parse_args() - - # Open image - try: - im = Image.open(args.pcx_path) - except Exception as e: - print(f"Error: failed to open '{args.pcx_path}': {e}", file=sys.stderr) - sys.exit(1) - - # Require paletted image to avoid quantization changing counts - if im.mode != "P": - print(f"Error: '{args.pcx_path}' is mode '{im.mode}', not an 8-bit paletted image ('P').", file=sys.stderr) - sys.exit(2) - - # Get palette (list of [R, G, B, R, G, B, ...], up to 256*3 entries) - pal = im.getpalette() - if not pal: - print("Error: No palette data found.", file=sys.stderr) - sys.exit(3) - - # Build palette as list of (R,G,B) - palette_colors = [(pal[i], pal[i+1], pal[i+2]) for i in range(0, len(pal), 3)] - max_considered = min(args.max_index, len(palette_colors) - 1) - - # Histogram: for 'P' images, 256 bins (0..255) - hist = im.histogram() - if len(hist) < 256: - # Shouldn't happen for 'P', but guard anyway - hist += [0] * (256 - len(hist)) - - # Build (count, index, html) entries for chosen range - entries = [] - for idx in range(0, max_considered + 1): - count = hist[idx] if idx < len(hist) else 0 - # Some palettes might be shorter than 256 entries; guard for safety - if idx < len(palette_colors): - html = idx_to_hex(palette_colors[idx]) - else: - # If palette entry missing, treat as black (or skip); choose to skip - html = None - - if html is None: - continue # skip indices without a palette color - - if args.include_zeros or count > 0: - entries.append((count, idx, html)) - - if not entries: - print("No colors to report in the specified index range.") - sys.exit(0) - - # Sort by count ascending, then by index to stabilize ties - entries.sort(key=lambda t: (t[0], t[1])) - - # Take top N least-used - top_n = entries[:args.top] - - # Print header and results - print("index\thtml\tcount") - for count, idx, html in top_n: - print(f"{idx}\t{html}\t{count}") - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +""" +least_used_pcx_colors.py + +Reads a paletted (8-bit, mode 'P') PCX file and prints the top 5 least used +colors among indices [0..254] by default. + +Output columns: index, HTML color (#RRGGBB), count + +Usage: + python least_used_pcx_colors.py path/to/image.pcx + # include colors that never appear: + python least_used_pcx_colors.py image.pcx --include-zeros + # change the highest considered index: + python least_used_pcx_colors.py image.pcx --max-index 255 +""" + +import argparse +import sys +from PIL import Image + +def idx_to_hex(rgb_tuple): + r, g, b = rgb_tuple + return f"#{r:02X}{g:02X}{b:02X}" + +def main(): + parser = argparse.ArgumentParser(description="Find least-used colors in a paletted PCX.") + parser.add_argument("pcx_path", help="Path to the PCX file (8-bit paletted).") + parser.add_argument("--include-zeros", action="store_true", default=True, + help="Include palette indices that occur 0 times.") + parser.add_argument("--max-index", type=int, default=254, + help="Highest palette index to consider (default: 254).") + parser.add_argument("--top", type=int, default=10, + help="How many least-used colors to return (default: 10).") + args = parser.parse_args() + + # Open image + try: + im = Image.open(args.pcx_path) + except Exception as e: + print(f"Error: failed to open '{args.pcx_path}': {e}", file=sys.stderr) + sys.exit(1) + + # Require paletted image to avoid quantization changing counts + if im.mode != "P": + print(f"Error: '{args.pcx_path}' is mode '{im.mode}', not an 8-bit paletted image ('P').", file=sys.stderr) + sys.exit(2) + + # Get palette (list of [R, G, B, R, G, B, ...], up to 256*3 entries) + pal = im.getpalette() + if not pal: + print("Error: No palette data found.", file=sys.stderr) + sys.exit(3) + + # Build palette as list of (R,G,B) + palette_colors = [(pal[i], pal[i+1], pal[i+2]) for i in range(0, len(pal), 3)] + max_considered = min(args.max_index, len(palette_colors) - 1) + + # Histogram: for 'P' images, 256 bins (0..255) + hist = im.histogram() + if len(hist) < 256: + # Shouldn't happen for 'P', but guard anyway + hist += [0] * (256 - len(hist)) + + # Build (count, index, html) entries for chosen range + entries = [] + for idx in range(0, max_considered + 1): + count = hist[idx] if idx < len(hist) else 0 + # Some palettes might be shorter than 256 entries; guard for safety + if idx < len(palette_colors): + html = idx_to_hex(palette_colors[idx]) + else: + # If palette entry missing, treat as black (or skip); choose to skip + html = None + + if html is None: + continue # skip indices without a palette color + + if args.include_zeros or count > 0: + entries.append((count, idx, html)) + + if not entries: + print("No colors to report in the specified index range.") + sys.exit(0) + + # Sort by count ascending, then by index to stabilize ties + entries.sort(key=lambda t: (t[0], t[1])) + + # Take top N least-used + top_n = entries[:args.top] + + # Print header and results + print("index\thtml\tcount") + for count, idx, html in top_n: + print(f"{idx}\t{html}\t{count}") + +if __name__ == "__main__": + main() diff --git a/DayNight/find_unused_palette_indexes.py b/DayNight/find_unused_palette_indexes.py index edcaa816..52bcb74c 100644 --- a/DayNight/find_unused_palette_indexes.py +++ b/DayNight/find_unused_palette_indexes.py @@ -1,107 +1,107 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -pcx_palette_unused.py — find unused palette slots in PCX files - -Usage: - python3 pcx_palette_unused.py --folder ./Data/1200 --exclude-255 yes - -What it prints: - • Per-file: which palette indexes are unused (and their RGB in that file) - • Intersection across all files (indexes unused everywhere) - • Top candidate RGBs that were unused most often across files -""" - -import argparse, os, collections -from PIL import Image - -def get_palette(im): - pal = im.getpalette() or [] - if len(pal) < 256*3: pal += [0]*(256*3 - len(pal)) - return pal[:256*3] - -def main(): - ap = argparse.ArgumentParser(description="List unused palette indexes/colors in PCX files") - ap.add_argument("--folder", required=True, help="Folder to scan (recursively)") - ap.add_argument("--exclude-255", default="yes", choices=["yes","no"], - help="Exclude index 255 (magenta) from 'unused' lists (default: yes)") - args = ap.parse_args() - exclude_255 = (args.exclude_255 == "yes") - - per_file_unused = [] - all_files = [] - - # Count how often a specific RGB appears in an unused slot across files - rgb_unused_counter = collections.Counter() - - # Intersection accumulator for indexes (0..254 if exclude_255 else 0..255) - index_domain = list(range(0, 255 if exclude_255 else 256)) - global_intersection = set(index_domain) - - for root, _, files in os.walk(args.folder): - for name in files: - if not name.lower().endswith(".pcx"): - continue - path = os.path.join(root, name) - try: - im = Image.open(path) - if im.mode != "P": - # Most Civ3 PCX files are 'P'; warn if not. - print(f"[warn] {path}: not paletted ('{im.mode}'); attempting to interpret anyway.") - im = im.convert("P") - pal = get_palette(im) - - # Which indexes are used in pixels? - used = set(im.getdata()) - domain = set(index_domain) - unused = sorted(domain - used) - - # Aggregate RGBs for unused slots (per-file) - for idx in unused: - r,g,b = pal[3*idx], pal[3*idx+1], pal[3*idx+2] - rgb_unused_counter[(r,g,b)] += 1 - - per_file_unused.append((path, unused, pal)) - all_files.append(path) - global_intersection &= set(unused) - - except Exception as e: - print(f"[error] {path}: {e}") - - # Output - print("\n=== Per-file unused palette indexes ===") - for path, unused, pal in per_file_unused: - print(f"\n{path}") - if not unused: - print(" (none)") - else: - print(f" {len(unused)} unused indexes:") - # show up to 32 entries to keep readable - preview = unused if len(unused) <= 32 else (unused[:16] + ["..."] + unused[-15:]) - print(" ", preview) - # show a few RGBs - rgb_preview = [] - for idx in unused[:12]: - r,g,b = pal[3*idx], pal[3*idx+1], pal[3*idx+2] - rgb_preview.append(f"{idx:3d}:#{r:02x}{g:02x}{b:02x}") - if rgb_preview: - print(" sample RGBs:", ", ".join(rgb_preview)) - - print("\n=== Indexes unused in EVERY scanned file ===") - if not all_files: - print(" (no files)") - else: - inter_sorted = sorted(global_intersection) - print(f" count={len(inter_sorted)}") - print(" ", inter_sorted[:64] if len(inter_sorted)<=64 else (inter_sorted[:32]+["..."]+inter_sorted[-31:])) - - print("\n=== Top candidate RGBs (unused across many files) ===") - if not rgb_unused_counter: - print(" (none)") - else: - for (r,g,b), cnt in rgb_unused_counter.most_common(20): - print(f" #{r:02x}{g:02x}{b:02x} unused-in-files={cnt}") - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +pcx_palette_unused.py — find unused palette slots in PCX files + +Usage: + python3 pcx_palette_unused.py --folder ./Data/1200 --exclude-255 yes + +What it prints: + • Per-file: which palette indexes are unused (and their RGB in that file) + • Intersection across all files (indexes unused everywhere) + • Top candidate RGBs that were unused most often across files +""" + +import argparse, os, collections +from PIL import Image + +def get_palette(im): + pal = im.getpalette() or [] + if len(pal) < 256*3: pal += [0]*(256*3 - len(pal)) + return pal[:256*3] + +def main(): + ap = argparse.ArgumentParser(description="List unused palette indexes/colors in PCX files") + ap.add_argument("--folder", required=True, help="Folder to scan (recursively)") + ap.add_argument("--exclude-255", default="yes", choices=["yes","no"], + help="Exclude index 255 (magenta) from 'unused' lists (default: yes)") + args = ap.parse_args() + exclude_255 = (args.exclude_255 == "yes") + + per_file_unused = [] + all_files = [] + + # Count how often a specific RGB appears in an unused slot across files + rgb_unused_counter = collections.Counter() + + # Intersection accumulator for indexes (0..254 if exclude_255 else 0..255) + index_domain = list(range(0, 255 if exclude_255 else 256)) + global_intersection = set(index_domain) + + for root, _, files in os.walk(args.folder): + for name in files: + if not name.lower().endswith(".pcx"): + continue + path = os.path.join(root, name) + try: + im = Image.open(path) + if im.mode != "P": + # Most Civ3 PCX files are 'P'; warn if not. + print(f"[warn] {path}: not paletted ('{im.mode}'); attempting to interpret anyway.") + im = im.convert("P") + pal = get_palette(im) + + # Which indexes are used in pixels? + used = set(im.getdata()) + domain = set(index_domain) + unused = sorted(domain - used) + + # Aggregate RGBs for unused slots (per-file) + for idx in unused: + r,g,b = pal[3*idx], pal[3*idx+1], pal[3*idx+2] + rgb_unused_counter[(r,g,b)] += 1 + + per_file_unused.append((path, unused, pal)) + all_files.append(path) + global_intersection &= set(unused) + + except Exception as e: + print(f"[error] {path}: {e}") + + # Output + print("\n=== Per-file unused palette indexes ===") + for path, unused, pal in per_file_unused: + print(f"\n{path}") + if not unused: + print(" (none)") + else: + print(f" {len(unused)} unused indexes:") + # show up to 32 entries to keep readable + preview = unused if len(unused) <= 32 else (unused[:16] + ["..."] + unused[-15:]) + print(" ", preview) + # show a few RGBs + rgb_preview = [] + for idx in unused[:12]: + r,g,b = pal[3*idx], pal[3*idx+1], pal[3*idx+2] + rgb_preview.append(f"{idx:3d}:#{r:02x}{g:02x}{b:02x}") + if rgb_preview: + print(" sample RGBs:", ", ".join(rgb_preview)) + + print("\n=== Indexes unused in EVERY scanned file ===") + if not all_files: + print(" (no files)") + else: + inter_sorted = sorted(global_intersection) + print(f" count={len(inter_sorted)}") + print(" ", inter_sorted[:64] if len(inter_sorted)<=64 else (inter_sorted[:32]+["..."]+inter_sorted[-31:])) + + print("\n=== Top candidate RGBs (unused across many files) ===") + if not rgb_unused_counter: + print(" (none)") + else: + for (r,g,b), cnt in rgb_unused_counter.most_common(20): + print(f" #{r:02x}{g:02x}{b:02x} unused-in-files={cnt}") + +if __name__ == "__main__": + main() diff --git a/DayNight/generate.sh b/DayNight/generate.sh index 02e69713..15e9c8f0 100644 --- a/DayNight/generate.sh +++ b/DayNight/generate.sh @@ -1,208 +1,208 @@ -#!/usr/bin/env bash - -set -euo pipefail - -### === CONFIG === -# Assumed to be run from DayNight/ directory - -DAYNIGHT_ANNOTATION_DIR="../Art/DayNight/Annotations" -DAYNIGHT_DATA_DIR="../Art/DayNight" -DISTRICT_ANNOTATION_DIR="../Art/Districts/Annotations" -DISTRICT_DATA_DIR="../Art/Districts" - -ANNOTATION_DIR="../Art/DayNight/Annotations" -DATA_DIR="../Art/DayNight" - -NOON_SUBFOLDER="1200" -ONLY_HOUR="" # set empty "" to process all hours - -# ---- Day/Night settings ---- -WARMTH=1.7 # Scale for sunrise/sunset warmth (1.0 = base) -BLUE=1.6 # Scale for night-time blue emphasis (1.0 = base) -DARKNESS=3.0 # Scale for extra night darkening (1.0 = base) -DESAT=0.8 # Scale for dusk/night desaturation toward gray (lower = richer) -SAT=1.1 # Global saturation multiplier after tint (1.0 = none) -CONTRAST=1.08 # Global contrast multiplier around mid 128 (1.0 = none) -SUNRISE_CENTER=6.0 # Hour center for sunrise warmth bump (0-23) -SUNSET_CENTER=18.0 # Hour center for sunset warmth bump (0-23) -TWILIGHT_WIDTH=2.6 # Sigma for sunrise/sunset warmth spread (higher = broader) -NOON_BLEND=0.5 # 0..1 strength to blend toward base palette near 12:00 (0=off) -NOON_SIGMA=1.0 # Gaussian width (hours) around 12:00 (larger = broader) - -# Examples -# --warmth 1.05 --blue 1.25 --darkness 1.15 --desat 0.9 --sat 1.02 --contrast 1.04 # Moody, cooler nights -# --warmth 1.3 --blue 1.05 --darkness 1.05 --desat 0.8 --sat 1.08 --contrast 1.04 # Warm, cinematic evenings -# --warmth 1.1 --blue 1.12 --darkness 1.08 --desat 0.85 --sat 1.05 --contrast 1.03 # Balanced -# --warmth 1.2 --blue 1.1 --darkness 1.05 --desat 0.7 --sat 1.1 --contrast 1.0 # Soft, painted look -# --warmth 1.15 --blue 1.2 --darkness 1.12 --desat 0.85 --sat 1.0 --contrast 1.08 # Crisp, high contrast nights - -# Light keys are the annotation colors used to indicate where lights should be at night. -# Each has a different configuration (LIGHT_STYLES, below). The light annotations are in -# /1200/*_light.pcx files. -LIGHT_KEYS=( - # Main colors - "#F6915E" # Orange - "#FEF500" # Yellow - - # Supporting colors, mostly on modern buildings - "#00feff" # Teal - "#E4080A" # Red - "#BD15D0" # Purple - "#2D9C01" # Green - "#FF25C8" # Pink - "#0A02EB" # Blue - "#8262ED" # Indigo -) - -LIGHT_STYLES=( - # Orange - softer, ambient lighting - "key=#F6915E; core=#ff8a20; glow=#dc6a00; core_gain=1.0; highlight_gain=0.0; size_radius=1.5; size_boost=0.05; halo_gain=6.0; halo_radius=1.0; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Yellow - intense, bright, focused lighting - "key=#FEF500; core=#ff8a20; glow=#dc6a00; core_gain=2.5; highlight_gain=1.0; size_radius=6.5; size_boost=1.5; halo_gain=20.0; halo_radius=0.1; core_radius=1.1; halo_gamma=1.3; size_gamma=0.75;" - - # Red - mostly modern building tops, individual pixels - "key=#E4080A; core=#E4080A; glow=#E4080A; core_gain=1.0; highlight_gain=0.0; size_radius=0.5; size_boost=0.0; halo_gain=6.0; halo_radius=1.0; core_radius=0.5; halo_gamma=0.9; size_gamma=0.0; blend_mode=add;" - - # Teal - "key=#00feff; core=#00feff; glow=#00feff; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Purple - "key=#BD15D0; core=#BD15D0; glow=#BD15D0; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Green - "key=#2D9C01; core=#2D9C01; glow=#2D9C01; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Pink - "key=#FF25C8; core=#FF25C8; glow=#FF25C8; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Blue - "key=#0A02EB; core=#0A02EB; glow=#0A02EB; core_gain=0.2; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" - - # Indigo - "key=#8262ED; core=#7521DC; glow=#7521DC; core_gain=0.2; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" -) - -# ---- City Lights settings ---- -CORE_COLOR="#ff8a20" # Tint color for the bright core (e.g., '#fff87a' for warm yellow) -GLOW_COLOR="#dc6a00" # Tint color for the outer halo (e.g., '#ff8a20' for orange) -CORE_RADIUS=1.1 # Gaussian blur radius (pixels) of the bright core. Higher = wider/softer core -CORE_GAIN=2.5 # Intensity multiplier for the core alpha (brightness/opacity of the center) -HALO_RADIUS=13 # Gaussian blur radius (pixels) of the outer halo. Higher = glow spreads further outward -HALO_GAIN=20.0 # Intensity multiplier for the halo alpha (strength of the outer glow) -HALO_SEP=0.75 # 0..1: subtracts a fraction of the core from the halo. 0 = seamless merge; 1 = distinct outer ring -HALO_GAMMA=1.3 # Gamma on the halo-only mask. >1 pushes energy outward (softer tail); <1 concentrates near source -HIGHLIGHT_GAIN=0.5 # Extra white highlight added from the core mask (0..~1 typical). Higher = hotter specular highlight -SIZE_BOOST=1.7 # How much cluster size increases intensity (0 disables). Higher = large groups pop more -SIZE_RADIUS=6.5 # Neighborhood radius (pixels) when measuring cluster size. Higher = smoother/broader size effect -SIZE_GAMMA=0.75 # Gamma on the size map. <1 emphasizes medium clusters; >1 favors only the largest clusters -CLIP_INTERIOR="yes" # If 'yes', lights only affect non-transparent interior (avoids glow on MAGENTA/GREEN). Recommended: yes. -CLIP_ERODE=0 # Erode the interior mask by N pixels. Higher = more conservative (keeps glow off edges) -BLEND_MODE="screen" # How layers combine. 'screen' (default) is safer; 'add' is punchier but can clip highlights - -# Notes: -# • Increase --halo-radius and --halo-gain for a bigger, softer glow. -# • If you see a dark ring between core/halo, reduce --halo-sep or increase --halo-gamma. -# • 'screen' blend is safer for colors; 'add' is punchier but can clip highlights." - -### === BUILD ARGS === -LK_ARGS=() -for c in "${LIGHT_KEYS[@]}"; do LK_ARGS+=( --light-key "$c" ); done - -STYLE_ARGS=() -for s in "${LIGHT_STYLES[@]}"; do STYLE_ARGS+=( --light-style "$s" ); done - -process_art_set() { - local data_dir="$1" - local annotation_dir="$2" - - if [[ ! -d "$data_dir" ]]; then - echo "Skipping missing data directory: $data_dir" >&2 - return - fi - if [[ ! -d "$annotation_dir" ]]; then - echo "Skipping missing annotation directory: $annotation_dir" >&2 - return - fi - - echo "Processing art set in $data_dir" - - mkdir -p "$data_dir/$NOON_SUBFOLDER" - shopt -s nullglob - local -a annotation_files=("$annotation_dir"/*) - shopt -u nullglob - if (( ${#annotation_files[@]} == 0 )); then - echo "No annotation files found in $annotation_dir" >&2 - else - cp "${annotation_files[@]}" "$data_dir/$NOON_SUBFOLDER" - fi - - local -a dn_args=( - --data "$data_dir" - --noon "$NOON_SUBFOLDER" - --warmth "$WARMTH" - --blue "$BLUE" - --darkness "$DARKNESS" - --desat "$DESAT" - --sat "$SAT" - --contrast "$CONTRAST" - --sunrise-center "$SUNRISE_CENTER" - --sunset-center "$SUNSET_CENTER" - --twilight-width "$TWILIGHT_WIDTH" - --noon-blend "$NOON_BLEND" - --noon-sigma "$NOON_SIGMA" - "${LK_ARGS[@]}" - ) - - local -a cl_args=( - --data "$data_dir" --noon "$NOON_SUBFOLDER" - "${LK_ARGS[@]}" "${STYLE_ARGS[@]}" - --core-color "$CORE_COLOR" --glow-color "$GLOW_COLOR" - --core-radius "$CORE_RADIUS" --halo-radius "$HALO_RADIUS" - --core-gain "$CORE_GAIN" --halo-gain "$HALO_GAIN" - --highlight-gain "$HIGHLIGHT_GAIN" - --size-boost "$SIZE_BOOST" --size-radius "$SIZE_RADIUS" --size-gamma "$SIZE_GAMMA" - --clip-interior "$CLIP_INTERIOR" --clip-erode "$CLIP_ERODE" - --halo-sep "$HALO_SEP" --halo-gamma "$HALO_GAMMA" - --blend-mode "$BLEND_MODE" - ) - - local -a pp_args=( - --data "$data_dir" - --noon "$NOON_SUBFOLDER" - --verbose - --remove-all-green - ) - - if [[ -n "${ONLY_HOUR}" ]]; then - dn_args+=( --only-hour "$ONLY_HOUR" ) - cl_args+=( --only-hour "$ONLY_HOUR" ) - pp_args+=( --only-hour "$ONLY_HOUR" ) - fi - - python civ3_day_night.py "${dn_args[@]}" - python civ3_city_lights.py "${cl_args[@]}" - python civ3_postprocess_pixels.py "${pp_args[@]}" - - ### === CLEANUP: remove *_lights.pcx from hour subfolders (excluding annotation dir) === - # If ONLY_HOUR is set, restrict cleanup to that single folder & noon folder; otherwise clean all 4-digit hour folders. - if [[ -n "${ONLY_HOUR}" ]]; then - # Only the specified hour - if [[ -d "$data_dir/$ONLY_HOUR" ]]; then - find "$data_dir/$ONLY_HOUR" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true - fi - # Also clean the noon folder - if [[ -d "$data_dir/$NOON_SUBFOLDER" ]]; then - find "$data_dir/$NOON_SUBFOLDER" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true - fi - else - # All hour-named subfolders under data_dir (e.g., 0000, 0100, ..., 2400) - # Do not touch the external $annotation_dir. - while IFS= read -r -d '' hour_dir; do - find "${hour_dir}" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true - done < <(find "$data_dir" -mindepth 1 -maxdepth 1 -type d -regex '.*/[0-9]{4}$' -print0) - fi -} - -process_art_set "$DAYNIGHT_DATA_DIR" "$DAYNIGHT_ANNOTATION_DIR" -process_art_set "$DISTRICT_DATA_DIR" "$DISTRICT_ANNOTATION_DIR" +#!/usr/bin/env bash + +set -euo pipefail + +### === CONFIG === +# Assumed to be run from DayNight/ directory + +DAYNIGHT_ANNOTATION_DIR="../Art/DayNight/Annotations" +DAYNIGHT_DATA_DIR="../Art/DayNight" +DISTRICT_ANNOTATION_DIR="../Art/Districts/Annotations" +DISTRICT_DATA_DIR="../Art/Districts" + +ANNOTATION_DIR="../Art/DayNight/Annotations" +DATA_DIR="../Art/DayNight" + +NOON_SUBFOLDER="1200" +ONLY_HOUR="" # set empty "" to process all hours + +# ---- Day/Night settings ---- +WARMTH=1.7 # Scale for sunrise/sunset warmth (1.0 = base) +BLUE=1.6 # Scale for night-time blue emphasis (1.0 = base) +DARKNESS=3.0 # Scale for extra night darkening (1.0 = base) +DESAT=0.8 # Scale for dusk/night desaturation toward gray (lower = richer) +SAT=1.1 # Global saturation multiplier after tint (1.0 = none) +CONTRAST=1.08 # Global contrast multiplier around mid 128 (1.0 = none) +SUNRISE_CENTER=6.0 # Hour center for sunrise warmth bump (0-23) +SUNSET_CENTER=18.0 # Hour center for sunset warmth bump (0-23) +TWILIGHT_WIDTH=2.6 # Sigma for sunrise/sunset warmth spread (higher = broader) +NOON_BLEND=0.5 # 0..1 strength to blend toward base palette near 12:00 (0=off) +NOON_SIGMA=1.0 # Gaussian width (hours) around 12:00 (larger = broader) + +# Examples +# --warmth 1.05 --blue 1.25 --darkness 1.15 --desat 0.9 --sat 1.02 --contrast 1.04 # Moody, cooler nights +# --warmth 1.3 --blue 1.05 --darkness 1.05 --desat 0.8 --sat 1.08 --contrast 1.04 # Warm, cinematic evenings +# --warmth 1.1 --blue 1.12 --darkness 1.08 --desat 0.85 --sat 1.05 --contrast 1.03 # Balanced +# --warmth 1.2 --blue 1.1 --darkness 1.05 --desat 0.7 --sat 1.1 --contrast 1.0 # Soft, painted look +# --warmth 1.15 --blue 1.2 --darkness 1.12 --desat 0.85 --sat 1.0 --contrast 1.08 # Crisp, high contrast nights + +# Light keys are the annotation colors used to indicate where lights should be at night. +# Each has a different configuration (LIGHT_STYLES, below). The light annotations are in +# /1200/*_light.pcx files. +LIGHT_KEYS=( + # Main colors + "#F6915E" # Orange + "#FEF500" # Yellow + + # Supporting colors, mostly on modern buildings + "#00feff" # Teal + "#E4080A" # Red + "#BD15D0" # Purple + "#2D9C01" # Green + "#FF25C8" # Pink + "#0A02EB" # Blue + "#8262ED" # Indigo +) + +LIGHT_STYLES=( + # Orange - softer, ambient lighting + "key=#F6915E; core=#ff8a20; glow=#dc6a00; core_gain=1.0; highlight_gain=0.0; size_radius=1.5; size_boost=0.05; halo_gain=6.0; halo_radius=1.0; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Yellow - intense, bright, focused lighting + "key=#FEF500; core=#ff8a20; glow=#dc6a00; core_gain=2.5; highlight_gain=1.0; size_radius=6.5; size_boost=1.5; halo_gain=20.0; halo_radius=0.1; core_radius=1.1; halo_gamma=1.3; size_gamma=0.75;" + + # Red - mostly modern building tops, individual pixels + "key=#E4080A; core=#E4080A; glow=#E4080A; core_gain=1.0; highlight_gain=0.0; size_radius=0.5; size_boost=0.0; halo_gain=6.0; halo_radius=1.0; core_radius=0.5; halo_gamma=0.9; size_gamma=0.0; blend_mode=add;" + + # Teal + "key=#00feff; core=#00feff; glow=#00feff; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Purple + "key=#BD15D0; core=#BD15D0; glow=#BD15D0; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Green + "key=#2D9C01; core=#2D9C01; glow=#2D9C01; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Pink + "key=#FF25C8; core=#FF25C8; glow=#FF25C8; core_gain=0.6; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Blue + "key=#0A02EB; core=#0A02EB; glow=#0A02EB; core_gain=0.2; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" + + # Indigo + "key=#8262ED; core=#7521DC; glow=#7521DC; core_gain=0.2; highlight_gain=0.0; size_radius=0.9; size_boost=0.3; halo_gain=8.0; halo_radius=0.1; core_radius=0.5; halo_gamma=1.5; size_gamma=0.1;" +) + +# ---- City Lights settings ---- +CORE_COLOR="#ff8a20" # Tint color for the bright core (e.g., '#fff87a' for warm yellow) +GLOW_COLOR="#dc6a00" # Tint color for the outer halo (e.g., '#ff8a20' for orange) +CORE_RADIUS=1.1 # Gaussian blur radius (pixels) of the bright core. Higher = wider/softer core +CORE_GAIN=2.5 # Intensity multiplier for the core alpha (brightness/opacity of the center) +HALO_RADIUS=13 # Gaussian blur radius (pixels) of the outer halo. Higher = glow spreads further outward +HALO_GAIN=20.0 # Intensity multiplier for the halo alpha (strength of the outer glow) +HALO_SEP=0.75 # 0..1: subtracts a fraction of the core from the halo. 0 = seamless merge; 1 = distinct outer ring +HALO_GAMMA=1.3 # Gamma on the halo-only mask. >1 pushes energy outward (softer tail); <1 concentrates near source +HIGHLIGHT_GAIN=0.5 # Extra white highlight added from the core mask (0..~1 typical). Higher = hotter specular highlight +SIZE_BOOST=1.7 # How much cluster size increases intensity (0 disables). Higher = large groups pop more +SIZE_RADIUS=6.5 # Neighborhood radius (pixels) when measuring cluster size. Higher = smoother/broader size effect +SIZE_GAMMA=0.75 # Gamma on the size map. <1 emphasizes medium clusters; >1 favors only the largest clusters +CLIP_INTERIOR="yes" # If 'yes', lights only affect non-transparent interior (avoids glow on MAGENTA/GREEN). Recommended: yes. +CLIP_ERODE=0 # Erode the interior mask by N pixels. Higher = more conservative (keeps glow off edges) +BLEND_MODE="screen" # How layers combine. 'screen' (default) is safer; 'add' is punchier but can clip highlights + +# Notes: +# • Increase --halo-radius and --halo-gain for a bigger, softer glow. +# • If you see a dark ring between core/halo, reduce --halo-sep or increase --halo-gamma. +# • 'screen' blend is safer for colors; 'add' is punchier but can clip highlights." + +### === BUILD ARGS === +LK_ARGS=() +for c in "${LIGHT_KEYS[@]}"; do LK_ARGS+=( --light-key "$c" ); done + +STYLE_ARGS=() +for s in "${LIGHT_STYLES[@]}"; do STYLE_ARGS+=( --light-style "$s" ); done + +process_art_set() { + local data_dir="$1" + local annotation_dir="$2" + + if [[ ! -d "$data_dir" ]]; then + echo "Skipping missing data directory: $data_dir" >&2 + return + fi + if [[ ! -d "$annotation_dir" ]]; then + echo "Skipping missing annotation directory: $annotation_dir" >&2 + return + fi + + echo "Processing art set in $data_dir" + + mkdir -p "$data_dir/$NOON_SUBFOLDER" + shopt -s nullglob + local -a annotation_files=("$annotation_dir"/*) + shopt -u nullglob + if (( ${#annotation_files[@]} == 0 )); then + echo "No annotation files found in $annotation_dir" >&2 + else + cp "${annotation_files[@]}" "$data_dir/$NOON_SUBFOLDER" + fi + + local -a dn_args=( + --data "$data_dir" + --noon "$NOON_SUBFOLDER" + --warmth "$WARMTH" + --blue "$BLUE" + --darkness "$DARKNESS" + --desat "$DESAT" + --sat "$SAT" + --contrast "$CONTRAST" + --sunrise-center "$SUNRISE_CENTER" + --sunset-center "$SUNSET_CENTER" + --twilight-width "$TWILIGHT_WIDTH" + --noon-blend "$NOON_BLEND" + --noon-sigma "$NOON_SIGMA" + "${LK_ARGS[@]}" + ) + + local -a cl_args=( + --data "$data_dir" --noon "$NOON_SUBFOLDER" + "${LK_ARGS[@]}" "${STYLE_ARGS[@]}" + --core-color "$CORE_COLOR" --glow-color "$GLOW_COLOR" + --core-radius "$CORE_RADIUS" --halo-radius "$HALO_RADIUS" + --core-gain "$CORE_GAIN" --halo-gain "$HALO_GAIN" + --highlight-gain "$HIGHLIGHT_GAIN" + --size-boost "$SIZE_BOOST" --size-radius "$SIZE_RADIUS" --size-gamma "$SIZE_GAMMA" + --clip-interior "$CLIP_INTERIOR" --clip-erode "$CLIP_ERODE" + --halo-sep "$HALO_SEP" --halo-gamma "$HALO_GAMMA" + --blend-mode "$BLEND_MODE" + ) + + local -a pp_args=( + --data "$data_dir" + --noon "$NOON_SUBFOLDER" + --verbose + --remove-all-green + ) + + if [[ -n "${ONLY_HOUR}" ]]; then + dn_args+=( --only-hour "$ONLY_HOUR" ) + cl_args+=( --only-hour "$ONLY_HOUR" ) + pp_args+=( --only-hour "$ONLY_HOUR" ) + fi + + python civ3_day_night.py "${dn_args[@]}" + python civ3_city_lights.py "${cl_args[@]}" + python civ3_postprocess_pixels.py "${pp_args[@]}" + + ### === CLEANUP: remove *_lights.pcx from hour subfolders (excluding annotation dir) === + # If ONLY_HOUR is set, restrict cleanup to that single folder & noon folder; otherwise clean all 4-digit hour folders. + if [[ -n "${ONLY_HOUR}" ]]; then + # Only the specified hour + if [[ -d "$data_dir/$ONLY_HOUR" ]]; then + find "$data_dir/$ONLY_HOUR" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true + fi + # Also clean the noon folder + if [[ -d "$data_dir/$NOON_SUBFOLDER" ]]; then + find "$data_dir/$NOON_SUBFOLDER" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true + fi + else + # All hour-named subfolders under data_dir (e.g., 0000, 0100, ..., 2400) + # Do not touch the external $annotation_dir. + while IFS= read -r -d '' hour_dir; do + find "${hour_dir}" -maxdepth 1 -type f -iname '*_lights.pcx' -delete || true + done < <(find "$data_dir" -mindepth 1 -maxdepth 1 -type d -regex '.*/[0-9]{4}$' -print0) + fi +} + +process_art_set "$DAYNIGHT_DATA_DIR" "$DAYNIGHT_ANNOTATION_DIR" +process_art_set "$DISTRICT_DATA_DIR" "$DISTRICT_ANNOTATION_DIR" diff --git a/DayNight/protected_pixels.py b/DayNight/protected_pixels.py index 15645f32..103ed5d7 100644 --- a/DayNight/protected_pixels.py +++ b/DayNight/protected_pixels.py @@ -1,75 +1,75 @@ -# --------------------------- Config: protected coords --------------------------- -# Pixels in these ranges remain unchanged ONLY in files with "EntertainmentComplex" in the name. -# Each entry is ((x1, y1), (x2, y2)) inclusive, typically horizontal runs. -PROTECTED_RANGES_ENT_COMPLEX = [ - # Each row of pairs represents a horizontal line of pixels, giving the illusion of lit ground - - # Ancient colosseum - ((159, 18), (169, 18)), - ((157, 19), (170, 19)), - ((155, 20), (171, 20)), - ((153, 21), (172, 21)), - ((158, 22), (166, 22)), - - # Middle ages colosseum - ((159, 81), (169, 81)), - ((157, 82), (170, 82)), - ((155, 83), (171, 83)), - ((153, 84), (172, 84)), - ((158, 85), (166, 85)), - - # Industrial age stadium - ((165, 147), (171, 147)), - ((163, 148), (171, 148)), - ((161, 149), (175, 149)), - ((159, 150), (176, 150)), - ((158, 151), (178, 151)), - ((155, 152), (180, 152)), - ((157, 151), (178, 151)), - ((155, 152), (181, 152)), - ((154, 153), (182, 153)), - ((152, 154), (183, 154)), - ((151, 155), (184, 155)), - ((149, 156), (185, 156)), - ((148, 157), (184, 157)), - ((146, 158), (186, 158)), - ((146, 159), (186, 159)), - ((145, 160), (185, 160)), - ((146, 161), (185, 161)), - ((147, 162), (184, 162)), - ((148, 163), (183, 163)), - ((151, 164), (178, 164)), - ((155, 165), (176, 165)), - ((157, 166), (175, 166)), - - # Modern age stadium - ((161, 208), (163, 208)), - ((159, 209), (165, 209)), - ((157, 210), (167, 210)), - ((155, 211), (169, 211)), - ((153, 212), (171, 212)), - ((151, 213), (173, 213)), - ((149, 214), (175, 214)), - ((147, 215), (177, 215)), - ((146, 216), (179, 216)), - ((148, 217), (181, 217)), - ((151, 218), (183, 218)), - ((151, 219), (185, 219)), - ((150, 220), (186, 220)), - ((150, 221), (167, 221)), ((169, 221), (184, 221)), # Light key in the middle - ((148, 222), (165, 222)), ((173, 222), (183, 222)), # Stadium light in the middle - ((149, 223), (165, 223)), ((173, 223), (181, 223)), - ((151, 224), (165, 224)), ((173, 224), (179, 224)), - ((151, 225), (165, 225)), ((173, 225), (177, 225)), - ((152, 226), (168, 226)), ((170, 226), (175, 226)), - ((154, 227), (168, 227)), ((170, 227), (174, 227)), - ((155, 228), (168, 228)), ((170, 228), (172, 228)), - ((157, 229), (168, 229)), ((170, 229), (171, 229)), - ((161, 230), (168, 230)), ((170, 230), (172, 230)), - ((163, 231), (168, 231)), ((170, 231), (171, 231)), - ((161, 232), (168, 232)), - ((161, 233), (168, 233)), - ((162, 234), (167, 234)), - ((161, 235), (165, 235)), - ((161, 236), (163, 236)) +# --------------------------- Config: protected coords --------------------------- +# Pixels in these ranges remain unchanged ONLY in files with "EntertainmentComplex" in the name. +# Each entry is ((x1, y1), (x2, y2)) inclusive, typically horizontal runs. +PROTECTED_RANGES_ENT_COMPLEX = [ + # Each row of pairs represents a horizontal line of pixels, giving the illusion of lit ground + + # Ancient colosseum + ((159, 18), (169, 18)), + ((157, 19), (170, 19)), + ((155, 20), (171, 20)), + ((153, 21), (172, 21)), + ((158, 22), (166, 22)), + + # Middle ages colosseum + ((159, 81), (169, 81)), + ((157, 82), (170, 82)), + ((155, 83), (171, 83)), + ((153, 84), (172, 84)), + ((158, 85), (166, 85)), + + # Industrial age stadium + ((165, 147), (171, 147)), + ((163, 148), (171, 148)), + ((161, 149), (175, 149)), + ((159, 150), (176, 150)), + ((158, 151), (178, 151)), + ((155, 152), (180, 152)), + ((157, 151), (178, 151)), + ((155, 152), (181, 152)), + ((154, 153), (182, 153)), + ((152, 154), (183, 154)), + ((151, 155), (184, 155)), + ((149, 156), (185, 156)), + ((148, 157), (184, 157)), + ((146, 158), (186, 158)), + ((146, 159), (186, 159)), + ((145, 160), (185, 160)), + ((146, 161), (185, 161)), + ((147, 162), (184, 162)), + ((148, 163), (183, 163)), + ((151, 164), (178, 164)), + ((155, 165), (176, 165)), + ((157, 166), (175, 166)), + + # Modern age stadium + ((161, 208), (163, 208)), + ((159, 209), (165, 209)), + ((157, 210), (167, 210)), + ((155, 211), (169, 211)), + ((153, 212), (171, 212)), + ((151, 213), (173, 213)), + ((149, 214), (175, 214)), + ((147, 215), (177, 215)), + ((146, 216), (179, 216)), + ((148, 217), (181, 217)), + ((151, 218), (183, 218)), + ((151, 219), (185, 219)), + ((150, 220), (186, 220)), + ((150, 221), (167, 221)), ((169, 221), (184, 221)), # Light key in the middle + ((148, 222), (165, 222)), ((173, 222), (183, 222)), # Stadium light in the middle + ((149, 223), (165, 223)), ((173, 223), (181, 223)), + ((151, 224), (165, 224)), ((173, 224), (179, 224)), + ((151, 225), (165, 225)), ((173, 225), (177, 225)), + ((152, 226), (168, 226)), ((170, 226), (175, 226)), + ((154, 227), (168, 227)), ((170, 227), (174, 227)), + ((155, 228), (168, 228)), ((170, 228), (172, 228)), + ((157, 229), (168, 229)), ((170, 229), (171, 229)), + ((161, 230), (168, 230)), ((170, 230), (172, 230)), + ((163, 231), (168, 231)), ((170, 231), (171, 231)), + ((161, 232), (168, 232)), + ((161, 233), (168, 233)), + ((162, 234), (167, 234)), + ((161, 235), (165, 235)), + ((161, 236), (163, 236)) ] \ No newline at end of file diff --git a/DayNight/swap_green_magenta_indices.py b/DayNight/swap_green_magenta_indices.py index f2cbf8ca..8c71412d 100644 --- a/DayNight/swap_green_magenta_indices.py +++ b/DayNight/swap_green_magenta_indices.py @@ -1,113 +1,113 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import argparse -from pathlib import Path -from typing import List, Tuple, Optional - -from PIL import Image - -GREEN = (0, 255, 0) # #00ff00 -MAGENTA = (255, 0, 255) # #ff00ff -GREEN_TARGET_IDX = 254 -MAGENTA_TARGET_IDX = 255 - -def chunk_palette(pal: List[int]) -> List[Tuple[int, int, int]]: - """Convert flat [r,g,b,...] list to list of 256 (r,g,b) tuples.""" - return [(pal[i], pal[i+1], pal[i+2]) for i in range(0, 256*3, 3)] - -def flatten_palette(pal_tuples: List[Tuple[int, int, int]]) -> List[int]: - """Convert list of (r,g,b) tuples back to flat list.""" - flat: List[int] = [] - for r, g, b in pal_tuples: - flat.extend([r, g, b]) - return flat - -def find_color_index(pal_tuples: List[Tuple[int, int, int]], color: Tuple[int, int, int]) -> Optional[int]: - """Return first index of exact color match, else None.""" - try: - return pal_tuples.index(color) - except ValueError: - return None - -def compute_mapping(idx_green: int, idx_magenta: int) -> List[int]: - """ - Build a 256-length LUT mapping old index -> new index so that: - - old idx_green goes to GREEN_TARGET_IDX - - old GREEN_TARGET_IDX goes to idx_green - - old idx_magenta goes to MAGENTA_TARGET_IDX - - old MAGENTA_TARGET_IDX goes to idx_magenta - Other indices map to themselves. - Handles overlap cases gracefully (e.g., green already at 254, magenta already at 255, - or the two are swapped). - """ - lut = list(range(256)) - # Swap pair for green <-> 254 - lut[idx_green] = GREEN_TARGET_IDX - lut[GREEN_TARGET_IDX] = idx_green - - # Swap pair for magenta <-> 255 - lut[idx_magenta] = MAGENTA_TARGET_IDX - lut[MAGENTA_TARGET_IDX] = idx_magenta - - return lut - -def remap_palette(old_pal: List[Tuple[int, int, int]], lut: List[int]) -> List[Tuple[int, int, int]]: - """ - Produce a new palette consistent with the index remap. - If pixels with old index i become new index lut[i], - then new_palette[lut[i]] should equal old_palette[i]. - """ - new_pal = [(0, 0, 0)] * 256 - for old_idx, rgb in enumerate(old_pal): - new_idx = lut[old_idx] - new_pal[new_idx] = rgb - return new_pal - -def process(path: Path) -> None: - with Image.open(path) as im: - if im.mode != "P": - raise ValueError(f"{path} is mode '{im.mode}', not paletted 'P'. Aborting to avoid altering colors.") - pal = im.getpalette() - if pal is None: - raise ValueError("Image has no palette.") - if len(pal) < 256 * 3: - raise ValueError(f"Palette has {len(pal)//3} colors, but 256 are required.") - pal_tuples = chunk_palette(pal) - - idx_green = find_color_index(pal_tuples, GREEN) - idx_magenta = find_color_index(pal_tuples, MAGENTA) - if idx_green is None: - raise ValueError("Exact green #00ff00 not found in palette.") - if idx_magenta is None: - raise ValueError("Exact magenta #ff00ff not found in palette.") - - # Build pixel index remap LUT (length 256) - lut = compute_mapping(idx_green, idx_magenta) - - # Remap pixel indices using Image.point(LUT) - # point() expects a 256-length sequence for 'P' images. - im_remapped = im.point(lut) - - # Reorder the palette to match the remapped indices - new_pal_tuples = remap_palette(pal_tuples, lut) - new_pal_flat = flatten_palette(new_pal_tuples) - im_remapped.putpalette(new_pal_flat) - - # Sanity check: confirm targets are now correct - final_pal = chunk_palette(im_remapped.getpalette()) - assert final_pal[GREEN_TARGET_IDX] == GREEN, "Post-remap sanity check failed for green at index 254." - assert final_pal[MAGENTA_TARGET_IDX] == MAGENTA, "Post-remap sanity check failed for magenta at index 255." - - # Overwrite the original file - im_remapped.save(path, format="PCX") - -def main(): - parser = argparse.ArgumentParser(description="Swap #00ff00 and #ff00ff into palette indices 254 and 255 in a 256-color PCX, remapping pixels and palette accordingly.") - parser.add_argument("pcx_path", type=Path, help="Path to the .pcx file") - args = parser.parse_args() - - process(args.pcx_path) - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import argparse +from pathlib import Path +from typing import List, Tuple, Optional + +from PIL import Image + +GREEN = (0, 255, 0) # #00ff00 +MAGENTA = (255, 0, 255) # #ff00ff +GREEN_TARGET_IDX = 254 +MAGENTA_TARGET_IDX = 255 + +def chunk_palette(pal: List[int]) -> List[Tuple[int, int, int]]: + """Convert flat [r,g,b,...] list to list of 256 (r,g,b) tuples.""" + return [(pal[i], pal[i+1], pal[i+2]) for i in range(0, 256*3, 3)] + +def flatten_palette(pal_tuples: List[Tuple[int, int, int]]) -> List[int]: + """Convert list of (r,g,b) tuples back to flat list.""" + flat: List[int] = [] + for r, g, b in pal_tuples: + flat.extend([r, g, b]) + return flat + +def find_color_index(pal_tuples: List[Tuple[int, int, int]], color: Tuple[int, int, int]) -> Optional[int]: + """Return first index of exact color match, else None.""" + try: + return pal_tuples.index(color) + except ValueError: + return None + +def compute_mapping(idx_green: int, idx_magenta: int) -> List[int]: + """ + Build a 256-length LUT mapping old index -> new index so that: + - old idx_green goes to GREEN_TARGET_IDX + - old GREEN_TARGET_IDX goes to idx_green + - old idx_magenta goes to MAGENTA_TARGET_IDX + - old MAGENTA_TARGET_IDX goes to idx_magenta + Other indices map to themselves. + Handles overlap cases gracefully (e.g., green already at 254, magenta already at 255, + or the two are swapped). + """ + lut = list(range(256)) + # Swap pair for green <-> 254 + lut[idx_green] = GREEN_TARGET_IDX + lut[GREEN_TARGET_IDX] = idx_green + + # Swap pair for magenta <-> 255 + lut[idx_magenta] = MAGENTA_TARGET_IDX + lut[MAGENTA_TARGET_IDX] = idx_magenta + + return lut + +def remap_palette(old_pal: List[Tuple[int, int, int]], lut: List[int]) -> List[Tuple[int, int, int]]: + """ + Produce a new palette consistent with the index remap. + If pixels with old index i become new index lut[i], + then new_palette[lut[i]] should equal old_palette[i]. + """ + new_pal = [(0, 0, 0)] * 256 + for old_idx, rgb in enumerate(old_pal): + new_idx = lut[old_idx] + new_pal[new_idx] = rgb + return new_pal + +def process(path: Path) -> None: + with Image.open(path) as im: + if im.mode != "P": + raise ValueError(f"{path} is mode '{im.mode}', not paletted 'P'. Aborting to avoid altering colors.") + pal = im.getpalette() + if pal is None: + raise ValueError("Image has no palette.") + if len(pal) < 256 * 3: + raise ValueError(f"Palette has {len(pal)//3} colors, but 256 are required.") + pal_tuples = chunk_palette(pal) + + idx_green = find_color_index(pal_tuples, GREEN) + idx_magenta = find_color_index(pal_tuples, MAGENTA) + if idx_green is None: + raise ValueError("Exact green #00ff00 not found in palette.") + if idx_magenta is None: + raise ValueError("Exact magenta #ff00ff not found in palette.") + + # Build pixel index remap LUT (length 256) + lut = compute_mapping(idx_green, idx_magenta) + + # Remap pixel indices using Image.point(LUT) + # point() expects a 256-length sequence for 'P' images. + im_remapped = im.point(lut) + + # Reorder the palette to match the remapped indices + new_pal_tuples = remap_palette(pal_tuples, lut) + new_pal_flat = flatten_palette(new_pal_tuples) + im_remapped.putpalette(new_pal_flat) + + # Sanity check: confirm targets are now correct + final_pal = chunk_palette(im_remapped.getpalette()) + assert final_pal[GREEN_TARGET_IDX] == GREEN, "Post-remap sanity check failed for green at index 254." + assert final_pal[MAGENTA_TARGET_IDX] == MAGENTA, "Post-remap sanity check failed for magenta at index 255." + + # Overwrite the original file + im_remapped.save(path, format="PCX") + +def main(): + parser = argparse.ArgumentParser(description="Swap #00ff00 and #ff00ff into palette indices 254 and 255 in a 256-color PCX, remapping pixels and palette accordingly.") + parser.add_argument("pcx_path", type=Path, help="Path to the .pcx file") + args = parser.parse_args() + + process(args.pcx_path) + +if __name__ == "__main__": + main() diff --git a/Ghidra scripts/Civ3TypesFromHeader.py b/Ghidra scripts/Civ3TypesFromHeader.py index f493e034..cf9517cf 100644 --- a/Ghidra scripts/Civ3TypesFromHeader.py +++ b/Ghidra scripts/Civ3TypesFromHeader.py @@ -1,300 +1,300 @@ -#Script to read in type info from Civ3Conquests.h -#@author -#@category _NEW_ -#@keybinding -#@menupath -#@toolbar - -# IMPORTANT NOTE if you're using this script for the first time in a new project. You need to copy certain -# Windows types (HBITMAP, etc.) from Ghidra's VS category into the Civ3Conquests.exe category otherwise -# getDataTypes won't be able to find them. Specifically, you need to copy over the subcategories "wingdi.h" -# and "WinDef.h". I took them from windows_vs12_32 but it probably works with other VS versions too. - -import re - -from ghidra.program.model.data import DataTypeManager, CategoryPath, ArrayDataType, PointerDataType, StructureDataType - -decl = re.compile (r"(\w+) (\w+);") -array_decl = re.compile (r"(\w+) (\w+)\[(\d+)\];") -ptr_decl = re.compile (r"(\w+) \*(\w+);") -ptr_ptr_decl = re.compile (r"(\w+) \*\*(\w+);") -arr_ptr_decl = re.compile (r"(\w+) \*(\w+)\[(\d+)\];") - -int_type = getDataTypes ("int")[0] -int_array_type = ArrayDataType (int_type, 5, 4) # DataType, NumElements, ElementLength -int_ptr_type = PointerDataType (int_type) -generic_ptr_type = PointerDataType () - -# If try_get_type is set to true, returns None instead of raising an exception on failure. -known_types = {} -def get_type (name, try_get_type=False): - if name in known_types: - return known_types[name] - else: - types = getDataTypes (name) - L = len (types) - if L == 1: - known_types[name] = types[0] - return types[0] - elif try_get_type: - return None - elif L > 1: - raise Exception ("Ambiguous type name: \"" + name + "\"") - else: - raise Exception ("Unknown type name: \"" + name + "\"") - -def get_pointer_type (name): - if name != "void": - return PointerDataType (get_type (name)) - else: - return PointerDataType () - -def trim_struct_name (name): - if name.startswith ("struct_"): - return name[7:] - elif name.startswith ("class_"): - return name[6:] - else: - return name - -# print (dir (currentProgram.getDataTypeManager ())) -# print (dir (currentProgram.getDataTypeManager ().getRootCategory ())) -# print (currentProgram.getDataTypeManager ().getRootCategory ().getCategories ()) -# print ("===") -# print (currentProgram.getDataTypeManager ().getDataTypes ("HBITMAP")) -# x = get_type ("HBITMAP") -dtm = currentProgram.getDataTypeManager () -# print (cat) -# for n in range (dtm.getCategoryCount ()): -# print (currentProgram.getDataTypeManager ().getCategory (n)) -# print (currentProgram.getDataTypeManager ().getDataType ("windows_vs12_32/", "HBITMAP")) - - -# dtm = currentProgram.getDataTypeManager () -# transaction = dtm.startTransaction ("Test categories") -# cat = dtm.createCategory (CategoryPath ("/TestCreateCategory")) -# ss = StructureDataType ("TestRecursiveStruct", 0) -# pss = PointerDataType (ss) -# ss.add (pss, "node", "recursive reference") -# cat.addDataType (ss, None) -# dtm.endTransaction (transaction, True) -# raise Exception ("stop here") - -# print (Array) -# print (len (getDataTypes ("Difficulty[5]"))) -# print (len (getDataTypes ("Difficulty *"))) - - - -# diff = getDataTypes ("Difficulty")[0] -# print (dir (diff)) -# newcomp = diff.add (generic_ptr_type, "testing_add_void_ptr_comp", "Hopefully this is a void *.") -# print (dir (newcomp)) -# raise Exception ("done now") - - -filepath = askString ("Enter path to file containing declarations", "Filepath:") -# cat_name = askString ("Enter name for destination category", "Category name:") - - -# Open file, split into lines, strip them, and discard empty and comment ones -lines = [] -with open (filepath, "r") as f: - for L in f.read ().split ("\n"): - L = L.strip () - if (len (L) > 0) and not L.startswith ("//"): - lines.append (L) - -# Each component is a tuple of four items: (kind, base, name, param). kind can be "simple", "array", -# "pointer", or "array of pointers". simple types only have a base type and name; pointer types -# use the 'param' to store the number of levels of indirection; arrays use 'param' to store the -# array count. Examples: -# int x; --> ("simple", "int", "x", None) -# char name[24]; --> ("array", "char", "name", 24) -# Foo *f; --> ("pointer", "Foo", "f", 1) -# Foo **f; --> ("pointer", "Foo", "f", 2) -# short *fs[2]; --> ("array of pointers", "short", "fs", 2) -# The point of parsing into this components form before creating the DataTypes is so that we can -# sort the list of struct by dependency. -def parse_components (lines): - tr = [] - for line in lines: - m = re.match (decl, line) - if m is not None: - # comps.append ((get_type (m.group (1)), m.group (2))) - tr.append (("simple", trim_struct_name (m.group (1)), m.group (2), None)) - continue - m = re.match (array_decl, line) - if m is not None: - # t = get_type (m.group (1)) - # comps.append ((ArrayDataType (t, int (m.group (3)), t.getLength ()), m.group (2))) - tr.append (("array", trim_struct_name (m.group (1)), m.group (2), int (m.group (3)))) - continue - m = re.match (ptr_decl, line) - if m is not None: - # t = PointerDataType (get_type (m.group (1))) if m.group (1) != "void" else PointerDataType () - # comps.append ((t, m.group (2))) - tr.append (("pointer", trim_struct_name (m.group (1)), m.group (2), 1)) - continue - m = re.match (ptr_ptr_decl, line) - if m is not None: - tr.append (("pointer", trim_struct_name (m.group (1)), m.group (2), 2)) - continue - m = re.match (arr_ptr_decl, line) - if m is not None: - tr.append (("array of pointers", trim_struct_name (m.group (1)), m.group (2), int (m.group (3)))) - continue - raise Exception ("The following line didn't match any pattern:\n\t" + line) - return tr - -# Find all structs in the file. Each entry in this list is a tuple of (name, is_union, components) -def extract_structs (lines): - tr = [] - n = 0 - while n < len (lines): - is_union = lines[n].startswith ("union ") - if lines[n].startswith ("struct ") or is_union: - struct_name = trim_struct_name (lines[n].split (" ")[1]) - if lines[n+1] != "{": raise Exception ("Expected '{' after struct") - n += 2 - struct_lines = [] - while lines[n] != "};": - struct_lines.append (lines[n]) - n += 1 - tr.append ((struct_name, is_union, parse_components (struct_lines))) - elif lines[n].startswith ("enum "): - # ignore enums for now - if lines[n+1] != "{": raise Exception ("Expected '{' after enum") - n += 2 - while lines[n] != "};": - n += 1 - else: - raise Exception ("Invalid line (expected struct or enum):\n\t" + lines[n]) - n += 1 - return tr - -structs = extract_structs (lines) - -def find_unknown_types (structs): - struct_names = {} - tr = [] - for s in structs: - struct_names[s[0]] = True - for s in structs: - struct_name, is_union, comps = s - for c in comps: - kind, base, comp_name, param = c - if (base != "void") and (base not in struct_names) and (get_type (base, True) is None): - tr.append (struct_name + "." + comp_name) - return tr - -unknown_types = find_unknown_types (structs) -if len (unknown_types) > 0: - print ("Couldn't get types for the following struct members:\n\t" + "\n\t".join (unknown_types)) - raise Exception ("Unknown or ambiguous types") - -# Returns list of structs sorted by dependency, i.e., the list reordered so that every struct B that's -# dependent on the definition of some struct A comes after A in the list. Assumes all structs are -# forward declared, i.e., if one refers to another through a pointer that doesn't count as a dependency. -def sort_structs_by_dependency (structs): - tr = [] - sorted_structs = {} - cant_satisfy_deps = lambda (sym): (sym != "void") and (sym not in sorted_structs) and (get_type (sym, True) is None) - while True: - sorted_any_this_pass = False - for s in structs: - struct_name, is_union, comps = s - if struct_name not in sorted_structs: - can_append = True - for c in comps: - kind, base, name, param = c - if (kind == "simple" or kind == "array") and cant_satisfy_deps (base): - can_append = False - break - if can_append: - tr.append (s) - sorted_structs[struct_name] = True - sorted_any_this_pass = True - # if done - if len (sorted_structs.keys ()) == len (structs): # done - break - # if not done and failed to sort any this pass - elif not sorted_any_this_pass: - raise Exception ("Some structs contain invalid (ambiguous, unknown) types or circular dependencies") - # else proceed to next pass - return tr - -structs = sort_structs_by_dependency (structs) - -# Quick and dirty code to just print the struct decls out in sorted order. Had to rewrite the sorting function -# because otherwise all dependencies are solved by the program's database (all these have already been imported -# after all). -# -# def sort_by_deps_2 (structs): -# tr = [] -# sorted_structs = {} -# unsorted_structs = {s[0] : True for s in structs} -# while True: -# sorted_any_this_pass = False -# for s in structs: -# struct_name, is_union, comps = s -# if struct_name not in sorted_structs: -# can_append = True -# for c in comps: -# kind, base, name, param = c -# if (kind == "simple" or kind == "array") and base in unsorted_structs: -# can_append = False -# break -# if can_append: -# tr.append (s) -# sorted_structs[struct_name] = True -# unsorted_structs.pop (struct_name) -# sorted_any_this_pass = True -# if len (tr) == len (structs): -# break -# elif not sorted_any_this_pass: -# raise Exception ("Failed to sort some structs") -# return tr -# structs = sort_by_deps_2 (structs) -# for s in structs: -# struct_name, is_union, comps = s -# t = "struct" if not is_union else "union" -# print (t + " " + struct_name) -# raise Exception ("Stop here") - -# Create all struct types first before filling them in so that recursive references work -struct_types = {} -for s in structs: - struct_name, is_union, comps = s - struct_types[struct_name] = StructureDataType (struct_name, 0) - known_types[struct_name] = struct_types[struct_name] - -# Fill in all struct components -for s in structs: - struct_name, is_union, comps = s - st = struct_types[struct_name] - for c in comps: - kind, base, comp_name, param = c - if kind == "simple": - st.add (get_type (base), comp_name, "") - elif kind == "array": - t = get_type (base) - st.add (ArrayDataType (t, param, t.getLength ()), comp_name, "") - elif kind == "pointer": - p = get_pointer_type (base) - for n in range (param - 1): - p = PointerDataType (p) - st.add (p, comp_name, "") - elif kind == "array of pointers": - p = get_pointer_type (base) - st.add (ArrayDataType (p, param, p.getLength ()), comp_name, "") - -# Add the structs to the type database -# Adding to a category doesn't work, it just dumps all the types in the main program category too. -# I can't be bothered to figure out how to make it work. -transaction = dtm.startTransaction ("Add structs from " + filepath) -# cat = dtm.createCategory (CategoryPath ("/" + cat_name)) -for s in struct_types.values (): - dtm.addDataType (s, None) -dtm.endTransaction (transaction, True) - +#Script to read in type info from Civ3Conquests.h +#@author +#@category _NEW_ +#@keybinding +#@menupath +#@toolbar + +# IMPORTANT NOTE if you're using this script for the first time in a new project. You need to copy certain +# Windows types (HBITMAP, etc.) from Ghidra's VS category into the Civ3Conquests.exe category otherwise +# getDataTypes won't be able to find them. Specifically, you need to copy over the subcategories "wingdi.h" +# and "WinDef.h". I took them from windows_vs12_32 but it probably works with other VS versions too. + +import re + +from ghidra.program.model.data import DataTypeManager, CategoryPath, ArrayDataType, PointerDataType, StructureDataType + +decl = re.compile (r"(\w+) (\w+);") +array_decl = re.compile (r"(\w+) (\w+)\[(\d+)\];") +ptr_decl = re.compile (r"(\w+) \*(\w+);") +ptr_ptr_decl = re.compile (r"(\w+) \*\*(\w+);") +arr_ptr_decl = re.compile (r"(\w+) \*(\w+)\[(\d+)\];") + +int_type = getDataTypes ("int")[0] +int_array_type = ArrayDataType (int_type, 5, 4) # DataType, NumElements, ElementLength +int_ptr_type = PointerDataType (int_type) +generic_ptr_type = PointerDataType () + +# If try_get_type is set to true, returns None instead of raising an exception on failure. +known_types = {} +def get_type (name, try_get_type=False): + if name in known_types: + return known_types[name] + else: + types = getDataTypes (name) + L = len (types) + if L == 1: + known_types[name] = types[0] + return types[0] + elif try_get_type: + return None + elif L > 1: + raise Exception ("Ambiguous type name: \"" + name + "\"") + else: + raise Exception ("Unknown type name: \"" + name + "\"") + +def get_pointer_type (name): + if name != "void": + return PointerDataType (get_type (name)) + else: + return PointerDataType () + +def trim_struct_name (name): + if name.startswith ("struct_"): + return name[7:] + elif name.startswith ("class_"): + return name[6:] + else: + return name + +# print (dir (currentProgram.getDataTypeManager ())) +# print (dir (currentProgram.getDataTypeManager ().getRootCategory ())) +# print (currentProgram.getDataTypeManager ().getRootCategory ().getCategories ()) +# print ("===") +# print (currentProgram.getDataTypeManager ().getDataTypes ("HBITMAP")) +# x = get_type ("HBITMAP") +dtm = currentProgram.getDataTypeManager () +# print (cat) +# for n in range (dtm.getCategoryCount ()): +# print (currentProgram.getDataTypeManager ().getCategory (n)) +# print (currentProgram.getDataTypeManager ().getDataType ("windows_vs12_32/", "HBITMAP")) + + +# dtm = currentProgram.getDataTypeManager () +# transaction = dtm.startTransaction ("Test categories") +# cat = dtm.createCategory (CategoryPath ("/TestCreateCategory")) +# ss = StructureDataType ("TestRecursiveStruct", 0) +# pss = PointerDataType (ss) +# ss.add (pss, "node", "recursive reference") +# cat.addDataType (ss, None) +# dtm.endTransaction (transaction, True) +# raise Exception ("stop here") + +# print (Array) +# print (len (getDataTypes ("Difficulty[5]"))) +# print (len (getDataTypes ("Difficulty *"))) + + + +# diff = getDataTypes ("Difficulty")[0] +# print (dir (diff)) +# newcomp = diff.add (generic_ptr_type, "testing_add_void_ptr_comp", "Hopefully this is a void *.") +# print (dir (newcomp)) +# raise Exception ("done now") + + +filepath = askString ("Enter path to file containing declarations", "Filepath:") +# cat_name = askString ("Enter name for destination category", "Category name:") + + +# Open file, split into lines, strip them, and discard empty and comment ones +lines = [] +with open (filepath, "r") as f: + for L in f.read ().split ("\n"): + L = L.strip () + if (len (L) > 0) and not L.startswith ("//"): + lines.append (L) + +# Each component is a tuple of four items: (kind, base, name, param). kind can be "simple", "array", +# "pointer", or "array of pointers". simple types only have a base type and name; pointer types +# use the 'param' to store the number of levels of indirection; arrays use 'param' to store the +# array count. Examples: +# int x; --> ("simple", "int", "x", None) +# char name[24]; --> ("array", "char", "name", 24) +# Foo *f; --> ("pointer", "Foo", "f", 1) +# Foo **f; --> ("pointer", "Foo", "f", 2) +# short *fs[2]; --> ("array of pointers", "short", "fs", 2) +# The point of parsing into this components form before creating the DataTypes is so that we can +# sort the list of struct by dependency. +def parse_components (lines): + tr = [] + for line in lines: + m = re.match (decl, line) + if m is not None: + # comps.append ((get_type (m.group (1)), m.group (2))) + tr.append (("simple", trim_struct_name (m.group (1)), m.group (2), None)) + continue + m = re.match (array_decl, line) + if m is not None: + # t = get_type (m.group (1)) + # comps.append ((ArrayDataType (t, int (m.group (3)), t.getLength ()), m.group (2))) + tr.append (("array", trim_struct_name (m.group (1)), m.group (2), int (m.group (3)))) + continue + m = re.match (ptr_decl, line) + if m is not None: + # t = PointerDataType (get_type (m.group (1))) if m.group (1) != "void" else PointerDataType () + # comps.append ((t, m.group (2))) + tr.append (("pointer", trim_struct_name (m.group (1)), m.group (2), 1)) + continue + m = re.match (ptr_ptr_decl, line) + if m is not None: + tr.append (("pointer", trim_struct_name (m.group (1)), m.group (2), 2)) + continue + m = re.match (arr_ptr_decl, line) + if m is not None: + tr.append (("array of pointers", trim_struct_name (m.group (1)), m.group (2), int (m.group (3)))) + continue + raise Exception ("The following line didn't match any pattern:\n\t" + line) + return tr + +# Find all structs in the file. Each entry in this list is a tuple of (name, is_union, components) +def extract_structs (lines): + tr = [] + n = 0 + while n < len (lines): + is_union = lines[n].startswith ("union ") + if lines[n].startswith ("struct ") or is_union: + struct_name = trim_struct_name (lines[n].split (" ")[1]) + if lines[n+1] != "{": raise Exception ("Expected '{' after struct") + n += 2 + struct_lines = [] + while lines[n] != "};": + struct_lines.append (lines[n]) + n += 1 + tr.append ((struct_name, is_union, parse_components (struct_lines))) + elif lines[n].startswith ("enum "): + # ignore enums for now + if lines[n+1] != "{": raise Exception ("Expected '{' after enum") + n += 2 + while lines[n] != "};": + n += 1 + else: + raise Exception ("Invalid line (expected struct or enum):\n\t" + lines[n]) + n += 1 + return tr + +structs = extract_structs (lines) + +def find_unknown_types (structs): + struct_names = {} + tr = [] + for s in structs: + struct_names[s[0]] = True + for s in structs: + struct_name, is_union, comps = s + for c in comps: + kind, base, comp_name, param = c + if (base != "void") and (base not in struct_names) and (get_type (base, True) is None): + tr.append (struct_name + "." + comp_name) + return tr + +unknown_types = find_unknown_types (structs) +if len (unknown_types) > 0: + print ("Couldn't get types for the following struct members:\n\t" + "\n\t".join (unknown_types)) + raise Exception ("Unknown or ambiguous types") + +# Returns list of structs sorted by dependency, i.e., the list reordered so that every struct B that's +# dependent on the definition of some struct A comes after A in the list. Assumes all structs are +# forward declared, i.e., if one refers to another through a pointer that doesn't count as a dependency. +def sort_structs_by_dependency (structs): + tr = [] + sorted_structs = {} + cant_satisfy_deps = lambda (sym): (sym != "void") and (sym not in sorted_structs) and (get_type (sym, True) is None) + while True: + sorted_any_this_pass = False + for s in structs: + struct_name, is_union, comps = s + if struct_name not in sorted_structs: + can_append = True + for c in comps: + kind, base, name, param = c + if (kind == "simple" or kind == "array") and cant_satisfy_deps (base): + can_append = False + break + if can_append: + tr.append (s) + sorted_structs[struct_name] = True + sorted_any_this_pass = True + # if done + if len (sorted_structs.keys ()) == len (structs): # done + break + # if not done and failed to sort any this pass + elif not sorted_any_this_pass: + raise Exception ("Some structs contain invalid (ambiguous, unknown) types or circular dependencies") + # else proceed to next pass + return tr + +structs = sort_structs_by_dependency (structs) + +# Quick and dirty code to just print the struct decls out in sorted order. Had to rewrite the sorting function +# because otherwise all dependencies are solved by the program's database (all these have already been imported +# after all). +# +# def sort_by_deps_2 (structs): +# tr = [] +# sorted_structs = {} +# unsorted_structs = {s[0] : True for s in structs} +# while True: +# sorted_any_this_pass = False +# for s in structs: +# struct_name, is_union, comps = s +# if struct_name not in sorted_structs: +# can_append = True +# for c in comps: +# kind, base, name, param = c +# if (kind == "simple" or kind == "array") and base in unsorted_structs: +# can_append = False +# break +# if can_append: +# tr.append (s) +# sorted_structs[struct_name] = True +# unsorted_structs.pop (struct_name) +# sorted_any_this_pass = True +# if len (tr) == len (structs): +# break +# elif not sorted_any_this_pass: +# raise Exception ("Failed to sort some structs") +# return tr +# structs = sort_by_deps_2 (structs) +# for s in structs: +# struct_name, is_union, comps = s +# t = "struct" if not is_union else "union" +# print (t + " " + struct_name) +# raise Exception ("Stop here") + +# Create all struct types first before filling them in so that recursive references work +struct_types = {} +for s in structs: + struct_name, is_union, comps = s + struct_types[struct_name] = StructureDataType (struct_name, 0) + known_types[struct_name] = struct_types[struct_name] + +# Fill in all struct components +for s in structs: + struct_name, is_union, comps = s + st = struct_types[struct_name] + for c in comps: + kind, base, comp_name, param = c + if kind == "simple": + st.add (get_type (base), comp_name, "") + elif kind == "array": + t = get_type (base) + st.add (ArrayDataType (t, param, t.getLength ()), comp_name, "") + elif kind == "pointer": + p = get_pointer_type (base) + for n in range (param - 1): + p = PointerDataType (p) + st.add (p, comp_name, "") + elif kind == "array of pointers": + p = get_pointer_type (base) + st.add (ArrayDataType (p, param, p.getLength ()), comp_name, "") + +# Add the structs to the type database +# Adding to a category doesn't work, it just dumps all the types in the main program category too. +# I can't be bothered to figure out how to make it work. +transaction = dtm.startTransaction ("Add structs from " + filepath) +# cat = dtm.createCategory (CategoryPath ("/" + cat_name)) +for s in struct_types.values (): + dtm.addDataType (s, None) +dtm.endTransaction (transaction, True) + diff --git a/Ghidra scripts/ExportProgForPython.py b/Ghidra scripts/ExportProgForPython.py index 83791620..124990d5 100644 --- a/Ghidra scripts/ExportProgForPython.py +++ b/Ghidra scripts/ExportProgForPython.py @@ -1,104 +1,104 @@ -# ExportProgForPython.py -# Exports all functions from a Ghidra project to a JSON file for easy consumption by Python scripts -#@author Claude -#@category Export -#@keybinding ctrl shift E -#@menupath Tools.Export.Functions For Python -#@toolbar - -import json -import os -from ghidra.program.model.listing import CodeUnit -from ghidra.util.task import TaskMonitor - -def get_function_bytes(func): - """Gets the raw bytes of a function""" - result = [] - minAddr = func.getEntryPoint() - maxAddr = func.getBody().getMaxAddress() - - currentAddr = minAddr - while currentAddr <= maxAddr and currentAddr is not None: - if func.getBody().contains(currentAddr): - byte_value = getByte(currentAddr) - result.append(byte_value & 0xff) # Convert to unsigned byte - currentAddr = currentAddr.next() - - return result - -def get_function_disassembly(func): - """Gets the disassembled instructions of a function""" - listing = currentProgram.getListing() - disasm = [] - - minAddr = func.getEntryPoint() - maxAddr = func.getBody().getMaxAddress() - - currentAddr = minAddr - while currentAddr <= maxAddr and currentAddr is not None: - if func.getBody().contains(currentAddr): - instr = listing.getCodeUnitAt(currentAddr) - if instr is not None: - disasm.append({ - "address": str(instr.getAddress()), - "instruction": instr.toString() - }) - if instr.getLength() > 1: - currentAddr = currentAddr.add(instr.getLength() - 1) - currentAddr = currentAddr.next() - - return disasm - -def count_references(func): - """Counts the references to a function""" - ref_count = 0 - refManager = currentProgram.getReferenceManager() - references = refManager.getReferencesTo(func.getEntryPoint()) - - for ref in references: - if ref.getReferenceType().isCall() or ref.getReferenceType().isJump(): - ref_count += 1 - - return ref_count - -def run(): - output_file = askFile("Select Output File", "Save") - - monitor.setMessage("Exporting functions...") - - # Get all functions - function_manager = currentProgram.getFunctionManager() - functions = function_manager.getFunctions(True) # True to get all functions - - results = [] - - for func in functions: - monitor.setMessage("Processing " + func.getName()) - - # Get function details - try: - function_data = { - "name": func.getName(), - "address": str(func.getEntryPoint()), - "raw_bytes": get_function_bytes(func), - "disassembly": get_function_disassembly(func), - "reference_count": count_references(func) - } - except: - print("Error processing function at {}".format(func.getEntryPoint())) - continue - - results.append(function_data) - - # Check if the task has been cancelled - if monitor.isCancelled(): - break - - # Write the results to a JSON file - with open(output_file.getAbsolutePath(), 'w') as f: - json.dump(results, f, indent=2) - - print("Exported {} functions to {}".format(len(results), output_file.getAbsolutePath())) - -# Run the script -run() +# ExportProgForPython.py +# Exports all functions from a Ghidra project to a JSON file for easy consumption by Python scripts +#@author Claude +#@category Export +#@keybinding ctrl shift E +#@menupath Tools.Export.Functions For Python +#@toolbar + +import json +import os +from ghidra.program.model.listing import CodeUnit +from ghidra.util.task import TaskMonitor + +def get_function_bytes(func): + """Gets the raw bytes of a function""" + result = [] + minAddr = func.getEntryPoint() + maxAddr = func.getBody().getMaxAddress() + + currentAddr = minAddr + while currentAddr <= maxAddr and currentAddr is not None: + if func.getBody().contains(currentAddr): + byte_value = getByte(currentAddr) + result.append(byte_value & 0xff) # Convert to unsigned byte + currentAddr = currentAddr.next() + + return result + +def get_function_disassembly(func): + """Gets the disassembled instructions of a function""" + listing = currentProgram.getListing() + disasm = [] + + minAddr = func.getEntryPoint() + maxAddr = func.getBody().getMaxAddress() + + currentAddr = minAddr + while currentAddr <= maxAddr and currentAddr is not None: + if func.getBody().contains(currentAddr): + instr = listing.getCodeUnitAt(currentAddr) + if instr is not None: + disasm.append({ + "address": str(instr.getAddress()), + "instruction": instr.toString() + }) + if instr.getLength() > 1: + currentAddr = currentAddr.add(instr.getLength() - 1) + currentAddr = currentAddr.next() + + return disasm + +def count_references(func): + """Counts the references to a function""" + ref_count = 0 + refManager = currentProgram.getReferenceManager() + references = refManager.getReferencesTo(func.getEntryPoint()) + + for ref in references: + if ref.getReferenceType().isCall() or ref.getReferenceType().isJump(): + ref_count += 1 + + return ref_count + +def run(): + output_file = askFile("Select Output File", "Save") + + monitor.setMessage("Exporting functions...") + + # Get all functions + function_manager = currentProgram.getFunctionManager() + functions = function_manager.getFunctions(True) # True to get all functions + + results = [] + + for func in functions: + monitor.setMessage("Processing " + func.getName()) + + # Get function details + try: + function_data = { + "name": func.getName(), + "address": str(func.getEntryPoint()), + "raw_bytes": get_function_bytes(func), + "disassembly": get_function_disassembly(func), + "reference_count": count_references(func) + } + except: + print("Error processing function at {}".format(func.getEntryPoint())) + continue + + results.append(function_data) + + # Check if the task has been cancelled + if monitor.isCancelled(): + break + + # Write the results to a JSON file + with open(output_file.getAbsolutePath(), 'w') as f: + json.dump(results, f, indent=2) + + print("Exported {} functions to {}".format(len(results), output_file.getAbsolutePath())) + +# Run the script +run() diff --git a/Ghidra scripts/ListReturnAddresses.py b/Ghidra scripts/ListReturnAddresses.py index 13e52479..3df3983b 100644 --- a/Ghidra scripts/ListReturnAddresses.py +++ b/Ghidra scripts/ListReturnAddresses.py @@ -1,61 +1,61 @@ -# List all return addresses for a given function -# @author Claude -# @category Analysis -# @keybinding -# @menupath -# @toolbar - -from ghidra.program.model.symbol import RefType - -def main(): - # Get the current function or prompt user to select one - current_function = getFunctionContaining(currentAddress) - - if current_function is None: - print("No function selected. Please place cursor in a function.") - return - - function_name = current_function.getName() - function_entry = current_function.getEntryPoint() - - print("Function: {} @ {}".format(function_name, function_entry)) - print("=" * 60) - print("") - - # Get all references to this function - references = getReferencesTo(function_entry) - - call_count = 0 - for ref in references: - ref_type = ref.getReferenceType() - - # Only process CALL references - if ref_type.isCall(): - call_count += 1 - from_address = ref.getFromAddress() - caller_function = getFunctionContaining(from_address) - - if caller_function is not None: - caller_name = caller_function.getName() - else: - caller_name = "" - - # Get the instruction at the call site - call_instruction = getInstructionAt(from_address) - - if call_instruction is not None: - # Return address is the address after the call instruction - return_address = from_address.add(call_instruction.getLength()) - - print("Call Site #{}: {}".format(call_count, from_address)) - print(" Caller Function: {}".format(caller_name)) - print(" Return Address: {}".format(return_address)) - print("") - else: - print("Warning: Could not find instruction at {}".format(from_address)) - - print("=" * 60) - print("Total calls found: {}".format(call_count)) - -if __name__ == "__main__": - main() +# List all return addresses for a given function +# @author Claude +# @category Analysis +# @keybinding +# @menupath +# @toolbar + +from ghidra.program.model.symbol import RefType + +def main(): + # Get the current function or prompt user to select one + current_function = getFunctionContaining(currentAddress) + + if current_function is None: + print("No function selected. Please place cursor in a function.") + return + + function_name = current_function.getName() + function_entry = current_function.getEntryPoint() + + print("Function: {} @ {}".format(function_name, function_entry)) + print("=" * 60) + print("") + + # Get all references to this function + references = getReferencesTo(function_entry) + + call_count = 0 + for ref in references: + ref_type = ref.getReferenceType() + + # Only process CALL references + if ref_type.isCall(): + call_count += 1 + from_address = ref.getFromAddress() + caller_function = getFunctionContaining(from_address) + + if caller_function is not None: + caller_name = caller_function.getName() + else: + caller_name = "" + + # Get the instruction at the call site + call_instruction = getInstructionAt(from_address) + + if call_instruction is not None: + # Return address is the address after the call instruction + return_address = from_address.add(call_instruction.getLength()) + + print("Call Site #{}: {}".format(call_count, from_address)) + print(" Caller Function: {}".format(caller_name)) + print(" Return Address: {}".format(return_address)) + print("") + else: + print("Warning: Could not find instruction at {}".format(from_address)) + + print("=" * 60) + print("Total calls found: {}".format(call_count)) + +if __name__ == "__main__": + main() diff --git a/README.md b/README.md index ca4e2e9f..ba7ecab2 100644 --- a/README.md +++ b/README.md @@ -1,277 +1,277 @@ - -**C3X** is a mod that makes many improvements to the Civ 3 Conquests EXE. It adds quality of life features including stack unit commands (shown below) and an end-of-turn warning for cities about to riot. C3X also fixes many long standing bugs, including the infamous submarine bug, deepens the AI's ability to fight by enabling it to use artillery and army units, and reduces turn times by correcting a major inefficiency in the game's trade network calculation. C3X also forms a platform for other mods by enabling various gameplay changes not possible through the editor. Examples include resource generation from buildings, era-specific names for leaders and civs, limited trespassing and railroad movement like in Civ 4, and a broad expansion of the zone of control and defensive bombard abilities. - -|![Demo of stack unit commands in C3X. Holding the control key causes all workers on a tile to build a railroad and causes all bombers to bombard a target.](Misc%20Images/new%20stack%20demo/output_gimp_with_msgs_optimized.gif)| -|:--:| -|Stack unit commands. Holding the control key converts most unit action buttons into stack buttons, which issue their commands to all units of the same type on the same tile. Similarly, holding control when selecting a tile to bombard performs a stack bombard. Also note the grouping of units and movement indicators on the right-click menus.| - -C3X's primary home is on CivFanatics, see: [main mod page](https://forums.civfanatics.com/resources/c3x.28759/), [releases](https://forums.civfanatics.com/resources/c3x.28759/updates), [discussion thread](https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/latest) - -## Video Overview -See this video by Suede for a demonstration of how to install the mod and of some of its convenience features. -[![C3X: Incredible Quality of Life mod for Civ 3, Video by Suede CivIII](http://img.youtube.com/vi/VxQ5dVABJcQ/0.jpg)](http://www.youtube.com/watch?v=VxQ5dVABJcQ) - -## Installation Details -Extract the mod, keeping it in its own folder, then copy that folder to your main Conquests directory (i.e. the folder containing Civ3Conquests.exe). Then activate the mod by double-clicking the INSTALL.bat script. You should get a message reporting that the installation was successful. You can also try RUN.bat, which launches a modded version of Civ 3 without installation, however I have received several reports that that script doesn't work for some people. - -Notes about installation: -1. If your Civ 3 is installed inside Program Files then it may be necessary to run INSTALL.bat as administrator due to Windows restrictions on editing the contents of Program Files. -2. When installing, the mod will create a backup of the original unmodded executable named "Civ3Conquests-Unmodded.exe". -3. To uninstall the mod, delete the modded executable then rename the backed up version mentioned above to "Civ3Conquests.exe". -4. It is not necessary to uninstall the mod before installing a different version. -5. Even after installation, the mod still depends on some files in the mod folder, so you need to keep it around. -6. R�mulo Prado reports that RUN.bat started working for him after he installed the MS Visual C++ Redistributables versions 2005 and 2019 (while installing GOG Galaxy). - -## Configuration -All aspects of C3X are configurable through INI text files. The basic INI file is called "default.c3x_config.ini" and is located in the mod folder. For example, if you want to turn off grouping of units on the right-click menu (that's what gives you "3x Spearman" instead of 3 identical Spearman entries), you could open that file in any text editor, find the line `group_units_on_right_click_menu = true`, and set it to `false`. - -However, because the default config file gets updated with each new release of the mod, it's recommended to put changes like the one above in a new file named "custom.c3x\_config.ini". C3X supports up to three different config files, the default config, a scenario config named "scenario.c3x\_config.ini" located in a scenario's search folder, and a custom config. They are loaded in that order. Scenario configs are intended to contain rule settings relevant to a particular scenario and custom configs are intended to function like user preferences. For a quick example of a scenario config, see [this post](https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-28#post-16212316). - -## Compatibility -C3X is compatible with the GOG and Steam versions of Civ 3 Complete and also with the DRM-free executable available through PCGames.de. If you have a CD version of the game, you can replace its EXE with the one from PCGames.de then install C3X on top of that. For more info about the PCGames.de executable, see this thread: [Civ 3, Windows Update KB3086255, & SafeDisc](https://forums.civfanatics.com/threads/civ-3-windows-update-kb3086255-safedisc.552308/). - -For info about running C3X on Mac, see this thread: [Installing, Playing and Modding C3C on Apple Silicon](https://forums.civfanatics.com/threads/installing-playing-and-modding-c3c-on-apple-silicon.681540/) - -C3X is compatible with existing saves and saves created with the mod active will still be loadable by the base game. - -Online multiplayer is not officially supported but some features of the mod will work. Others will not, including stack unit commands. I have also received reports that C3X can cause crashes in online MP. In general, online play is something I'd like to support but haven't gotten around to yet. - -## Feature Highlights -#### Disorder Warning: -![C3X disorder warning feature. The domestic advisor is popping up to warn about unhappy cities before the end of a turn.](Misc%20Images/disorder_warning.jpg) - -If you try to end the turn with unhappy cities, the domestic advisor will pop up to warn you and give you the option to continue that turn. - -#### AI Enhancements: -Numerous changes have been made to improve the AI's behavior, especially in combat. It can now use its artillery units in the field, i.e., it will take them out of its cities to bombard enemy cities or incoming enemy units. The AI's production of artillery has been significantly increased so that it can take advantage of this ability. The other major change is that the AI can now use armies properly, it builds them when it can and fills them with units, usually the strongest available. There are many smaller changes as well to fix bugs and improve heuristics. Some more details are available as comments in the config file. - -#### Trade Screen Improvements: -![C3X trade screen arrows. Shows the top of the leader window with arrows on either side.](Misc%20Images/c3x_trade_screen_arrows.jpg) - -When negotiating with the AI, you can quickly switch back and forth between civs using the added arrow buttons (arrow keys work as well). When asking for or offering gold, the set amount popup will appear with the best amount already filled in. Best amount means, when asking for gold on an acceptable trade, the most you could get, and when offering gold on an unacceptable trade, the least you need to pay. - -#### Optimization: -A major inefficiency in the game's sea trade computation has been fixed. This eliminates one major cause of slow turns in the late game, especially on large maps with many coastal cities and many wars. For details about the problem and how C3X solves it, see [this post](https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-83#post-16536108). - -#### Adjustable Movement Rules: -The functions governing unit movement have been modified to enable various adjustments to the game's movement rules not possible through the editor. As with all other engine extensions, the rules are not changed from vanilla Conquests unless the config file is edited. - -Unlimited railroad movement can be turned off. The non-unlimited railroads can function like they do in Civ 4, meaning that all units will move the same distance along them regardless of how many moves they have, or they can function like an upgraded version of regular roads that have a lower movement cost. The relevant config variables are "limit\_railroad\_movement" and "limited\_railroads\_work\_like\_fast\_roads". - -Enabling land/sea intersections allows sea units to travel over the thin isthmus that exists on the diagonal path between two land tiles. More specifically, imagine a diamond of four tiles with land terrain on the north & south tiles and water on the east & west ones. With land/sea intersections enabled, naval units can pass between the east and west tiles. - -It is possible to disallow trespassing, which will prevent units from entering another civ's borders without a right of passage agreement, similar to the rules in Civ 4. Invisible and hidden nationality units are allowed to trespass in any case. It is also possible to impose a stack limit, which will prevent units from entering tiles that already have more than a set number of units occupying them. The stack limit can be set separately for land, sea, and air units. - -#### Small Wonder Free Improvements: -The free improvements wonder effect (granaries from Pyramids etc.) now works on small wonders. Note to modders, to set this effect you must use a third party editor like Quintillus' ([thread link](https://forums.civfanatics.com/threads/cross-platform-editor-for-conquests-now-available.377188/)) because the option is grayed out in the standard editor. Even worse, if you set the effect then work on the BIQ in the standard editor, the effect won't be saved, so you'd need to set it every time or work exclusively in Quintillus' editor. - -#### No-Raze & Limit Removals: -The no-raze and no-unit-limit features of earlier modded EXEs have been re-implemented as part of C3X. To enable no-raze, edit the config. There are separate options to prevent autorazing (the forced destruction of size 1 cities) and razing by player's choice. In addition to removing the unit limit, C3X also removes the limit of 256 city improvement types, and lifts the city limit to 2048. - -## Full Feature List -All C3X features are listed below. See the default config (default.c3x\_config.ini) for descriptions. -
- Included in C3X - - #### Convenience features - - Stack unit commands - - Stack bombard - - Worker buttons (irrigate, road, etc.) become stack buttons by holding CTRL - - Stack fortify, upgrade, and disband also with CTRL - - Disorder warning - - Detailed city production info - - Buttons on trade screen to quickly switch between civs - - Ask/offer gold popup autofills best amount - - Skip repeated popups asking to replace a tile improvement - - Group units on right click menu - - Show coordinates and chopped status in tile info box - - Show golden age turns remaining - - No special king unit names in non-regicide games - - Option to disable worker automation - - On the city screen, hold shift when clicking a specialist to switch to the previous type - - Automatically cut research spending to avoid bankruptcy - - Remove pause for "we love the king" messages - - Suppress "maximum hypertext links exceeded" popup - - Civilopedia indicates when units go obsolete but cannot be upgraded - - Message appears after bomber dodges interception by air defense buildings - - Option to replay AI moves for all human players in hotseat mode - - Restore unit directions on game load - - Option to remove Elvis Easter egg - - Harbor/airport city icons indicate unit effects not trade abilities - - Disallow useless bombard attacks vs airfields - - Display total city count (disabled by default, appears on demographics screen) - - Fix graphical issues when running on Wine - - Option to pack the lists of luxuries and strategic resources more tightly into their boxes on the city screen - - Right-click menu enhancements - - Place icons next to units showing movement and combat status - - Replace Wake/Activate with descriptions of what the units are doing - - Gray out units if they have no remaining moves - - Apply GridOn setting from conquests.ini after loading a save - - Option to have a warning when the building you've selected to build would replace another already built in the city - - Option not to unassign workers from tiles that become polluted - - Pressing the Z key on the city screen toggles the zoom level of the map display - - Option not to draw capital cities larger than they really are - - Allow Civilopedia descriptions for units, civilizations, and game concepts to span multiple pages - - Double size of minimap when running in high definition (>= 1920 horizontal pixels) - - Option to show some popup messages as online-multiplayer-style notifications - - Option to switch debug mode on or off for games in progress - - Option to tint coast and sea tiles on minimap based on cultural borders - #### Optimization - - Optimize computation of trade networks - - For details, see the info text file in the Trade Net X folder - - Optimize improvement loops - - Option to measure turn times - #### AI Enhancements - - Allow AI to use artillery in the field - - Force AI to build more artillery and bombers - - Replace leader unit AI to fix bugs and improve behavior - - Fix bug preventing AI from filling its armies - - Improve AI army composition to discourage mixing types & exclude HN units - - AI routine for "pop units", which are modded units whose only purpose is to be joined into cities - - AI routine for "caravan units", which are modded units whose only purpose is to be disbanded for shields - - Can limit the number of escorts the AI assigns to its naval transports and carriers - - Adjustable AI worker requirement - - Option to stop AI from escorting units without the "requires escort" flag - - Option to draw small shadows underneath city dots on the minimap to make them more visible - #### Bugs Fixed - - AI pathfinding collides with invisible units (called the "submarine bug") - - Science age beakers not actually awarded - - Pink line in Civilopedia - - Crash when doing disembark-all on transport containing immobile unit(s) - - Crash possible when AI civ is left alive with only a settler on a transport (called the "houseboat bug") - - Resources beyond the first 32 share access records in cities not on the main trade network (called the "phantom resource bug") - - Air units lose a turn after being set to intercept - - Cached building maintenance amounts not updated when buildings are obsoleted - - Barbarian long-range search for targets is limited to tiles directly NW or SE - - "Disables Diseases From Flood Plains" tech flag hardcoded to tech #8 (off by default) - - Possible division by zero in AI logic to evaluate proposed alliances - - Available movement computed incorrectly for empty armies - - Off-map AI units may crash the game (fixed by deleting them at the start of their turns) - - Pathfinder improperly truncates long paths, sending AI units on nonsensical or invalid paths - - Cities with zero production crash the game due to division by zero - - Icons for different kinds of specialist yields are drawn on top of, instead of next to, one another - - AI players may sacrifice units without the "sacrifice" special ability - - AI players may build armies with leader units that don't have the "build army" special ability - - Possible crash in base game leader unit AI - #### AMB Editor - - A program for inspecting and modifying the special .amb sound files used by Civ 3. - - For more info, see README.txt in the AMB Editor folder - #### Limits Removed - - Removed unit limit - - Removed city improvement limit - - Lift city limit to 2048 and allow it to be configured - - Remove cap on turn limit - #### Engine Extensions - - Adjustable minimum city distance - - Option to limit railroad movement, as in Civ 4 or by converting them to fast roads - - Option to limit how many units can share each tile - - Enable free improvements from small wonders - - Option to share visibility among all human players in a hotseat game - - Option to prevent autoraze and razing by players - - Trespassing prevention - - Land/sea intersections - - Adjustable anarchy length - - Unit limits (stops players from producing units of a given type once they reach a maximum quantity) - - "Perfume" city production options, technologies, and governments to control how likely the AI is to choose them - - Reveal AI logic - - Press P in city screen to see AI point value for each available build - - Press L on map to see how desirable the AI finds each tile as a city location - - Corruption can be completely removed with "OFF" government setting - - Disallow land units from working or settling water tiles - - Option to let units move after airdropping - - Buildings can generate resources - - Buildings can be set as prerequisites for unit production - - Can cancel out pop pollution with negative pollution amount on building flagged as removing pop pollution - - Option to modify rules for retreat eligibility - - AI multi-city start - - Starter cities can begin with improvements, including "extra palaces" which respawn like the real palace - - Option to strengthen the corruption reducing effect of wonders to match the palace's - - Option to allow military great leaders to hurry wonders - - Option to multiply AI research rate by any amount - - Option to aggressively penalize bankrupt players - - Option to remove exception to tile penalty for city tiles with fresh water and Agri trait - - Artillery can be set to use PTW-like targeting against cities - - Recon missions can be made vulnerable to interception - - Option to charge one move for recon missions and interception - - Stealth attack changes - - Option to perform stealth attack even when there's only one target - - Enable stealth attacks via bombardment - - Allow players to opt out of stealth attacks - - Option to show unit hitpoints on the stealth attack target selection popup - - Option to prevent stealth attacks from targeting units that are invisible and unrevealed - - Polish precision striking by land or sea units - - Use regular bombard animation instead of flying animation - - Use bombard range instead of operational range - - Despawn unit if cruise missile - - Cannot be intercepted - - Option to immunize aircraft against bombardment - - Option to ignore king flag on defense, so kings aren't always last to defend in a stack - - Option to show untradable techs on trade screen - - Barbarian city capture & production (experimental) - - Option to allow land units to bombard aircraft and naval units in cities - - Zone of control changes - - Allow land-to-sea and sea-to-land attacks, only using bombard stat - - May be lethal - - May be exerted by air units - - Show attack animation even when attacker is not at the top of its stack - - Defensive bombard changes - - May be lethal - - May be performed by air units - - Invisible, undetected units may be made immune - - May be performed multiple times per turn with blitz - - Naval units in a city may perform defensive bombard vs land attackers - - Allow precision strikes to target tile improvements - - Option not to end a unit's turn after it bombards a barricade - - Option to allow bombardment of other improvements on a tile with an occupied airfield - - Option to boost OCN increase from forbidden palaces in non-communal governments - - Option to allow airdrops without airports - - Can increase unit maintenance costs based on their build costs - - Civ and leader names can vary by era - - Option to allow upgrades in any city - - Option to stop the map generator from placing volcanos - - Option to stop pollution from appearing on impassable tiles - - Option to make planting forests produce LM forest terrain - - Adjustable chance for max one HP units to be destroyed by nuclear strikes - - Option to allow sale of buildings like aqueducts that uncap population growth - - Option stopping non-sea detector units from revealing invisible sea units and vice-versa - - Adjustable city work area size - - Radius of area can be set from 1 to 7 tiles (2 is the standard) - - Area can also be limited by a city's cultural level or buildings - - Option to throttle AI's expansion by temporarily applying perfume to settlers each time it founds a city - - Option to block the galley chaining exploit by preventing units from loading into two different transports on the same turn - - Adjustable rebase range as multiple of operational range - - Option to share wonders among human players in hotseat mode - - Enable tile graphics to cycle over day and night, see "Day/Night Cycle" section of default config for details - - Can adjust time to double building culture - - Option to prevent units from upgrading past an intermediate type that does not have the upgrade ability - - Can adjust times to generate tourism gold - - Option to put all human players in contact with each other at the start of a hotseat game - - Enable districts, an elaborate change to the game's economy inspired by Civ 6 - - The districts feature is a large mod on its own. See its thread: https://forums.civfanatics.com/threads/c3x-districts.700590/ - - Land transport changes - - Land transports may be loaded into naval transports - - Empty LTs may join armies - - Units inside an LT may be prevented from defending their tile, performing defensive bombard, or intercepting air units - - Units inside an LT can be destroyed when the LT itself is destroyed or captured - - Resource placement changes - - Can relax the rule preventing resources from appearing next to others of a different type - - Adjust the overall appearance rate for luxuries that do not have a fixed rate set - - Control the overall appearance rate of bonus resources - - Option to allow sale of small wonders - - Option to allow units to be unloaded from armies - - Option to prevent land anti-air units from intercepting overflying aircraft while they're loaded in a naval transport - - Option to prevent units from being enslaved after being destroyed by lethal bombard named prevent_enslaving_by_bombardment -
- -## How It Works -Some parts of the mod (bug fixes, no-raze, no unit limit) are really just hex edits that are applied to the Civ program code. The real secret sauce is a system to compile and inject arbitrary C code into the process which makes it practical to implement new features in the game. The heart of the system is TCC (Tiny C Compiler) and much work puzzling out the functions and structs inside the executable. Much thanks to Antal1987 for figuring out most of the structs years before I came along, [his work is posted here](https://github.com/Antal1987/C3CPatchFramework)). - -C3X is open source. The C code that gets injected into the game's EXE is located in injected_code.c and the code to perform the injection is located in ep.c. You're invited to explore the source code if you're interested. - -## Special Thanks -1. Antal1987 for his work reverse engineering Civ3 -2. Rmulo Prado for his help testing the mod -3. Civinator for the German translation. See: https://www.civforum.de/showthread.php?113285-Der-Flintlock-Deutsch-Patch -4. Vaughn Parker for generously commissioning the port to the PCGames.de EXE and many other features -5. instafluff0 for contributing the districts and day/night cycle features -6. Philiquaz and dobragab for their contributions + +**C3X** is a mod that makes many improvements to the Civ 3 Conquests EXE. It adds quality of life features including stack unit commands (shown below) and an end-of-turn warning for cities about to riot. C3X also fixes many long standing bugs, including the infamous submarine bug, deepens the AI's ability to fight by enabling it to use artillery and army units, and reduces turn times by correcting a major inefficiency in the game's trade network calculation. C3X also forms a platform for other mods by enabling various gameplay changes not possible through the editor. Examples include resource generation from buildings, era-specific names for leaders and civs, limited trespassing and railroad movement like in Civ 4, and a broad expansion of the zone of control and defensive bombard abilities. + +|![Demo of stack unit commands in C3X. Holding the control key causes all workers on a tile to build a railroad and causes all bombers to bombard a target.](Misc%20Images/new%20stack%20demo/output_gimp_with_msgs_optimized.gif)| +|:--:| +|Stack unit commands. Holding the control key converts most unit action buttons into stack buttons, which issue their commands to all units of the same type on the same tile. Similarly, holding control when selecting a tile to bombard performs a stack bombard. Also note the grouping of units and movement indicators on the right-click menus.| + +C3X's primary home is on CivFanatics, see: [main mod page](https://forums.civfanatics.com/resources/c3x.28759/), [releases](https://forums.civfanatics.com/resources/c3x.28759/updates), [discussion thread](https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/latest) + +## Video Overview +See this video by Suede for a demonstration of how to install the mod and of some of its convenience features. +[![C3X: Incredible Quality of Life mod for Civ 3, Video by Suede CivIII](http://img.youtube.com/vi/VxQ5dVABJcQ/0.jpg)](http://www.youtube.com/watch?v=VxQ5dVABJcQ) + +## Installation Details +Extract the mod, keeping it in its own folder, then copy that folder to your main Conquests directory (i.e. the folder containing Civ3Conquests.exe). Then activate the mod by double-clicking the INSTALL.bat script. You should get a message reporting that the installation was successful. You can also try RUN.bat, which launches a modded version of Civ 3 without installation, however I have received several reports that that script doesn't work for some people. + +Notes about installation: +1. If your Civ 3 is installed inside Program Files then it may be necessary to run INSTALL.bat as administrator due to Windows restrictions on editing the contents of Program Files. +2. When installing, the mod will create a backup of the original unmodded executable named "Civ3Conquests-Unmodded.exe". +3. To uninstall the mod, delete the modded executable then rename the backed up version mentioned above to "Civ3Conquests.exe". +4. It is not necessary to uninstall the mod before installing a different version. +5. Even after installation, the mod still depends on some files in the mod folder, so you need to keep it around. +6. R�mulo Prado reports that RUN.bat started working for him after he installed the MS Visual C++ Redistributables versions 2005 and 2019 (while installing GOG Galaxy). + +## Configuration +All aspects of C3X are configurable through INI text files. The basic INI file is called "default.c3x_config.ini" and is located in the mod folder. For example, if you want to turn off grouping of units on the right-click menu (that's what gives you "3x Spearman" instead of 3 identical Spearman entries), you could open that file in any text editor, find the line `group_units_on_right_click_menu = true`, and set it to `false`. + +However, because the default config file gets updated with each new release of the mod, it's recommended to put changes like the one above in a new file named "custom.c3x\_config.ini". C3X supports up to three different config files, the default config, a scenario config named "scenario.c3x\_config.ini" located in a scenario's search folder, and a custom config. They are loaded in that order. Scenario configs are intended to contain rule settings relevant to a particular scenario and custom configs are intended to function like user preferences. For a quick example of a scenario config, see [this post](https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-28#post-16212316). + +## Compatibility +C3X is compatible with the GOG and Steam versions of Civ 3 Complete and also with the DRM-free executable available through PCGames.de. If you have a CD version of the game, you can replace its EXE with the one from PCGames.de then install C3X on top of that. For more info about the PCGames.de executable, see this thread: [Civ 3, Windows Update KB3086255, & SafeDisc](https://forums.civfanatics.com/threads/civ-3-windows-update-kb3086255-safedisc.552308/). + +For info about running C3X on Mac, see this thread: [Installing, Playing and Modding C3C on Apple Silicon](https://forums.civfanatics.com/threads/installing-playing-and-modding-c3c-on-apple-silicon.681540/) + +C3X is compatible with existing saves and saves created with the mod active will still be loadable by the base game. + +Online multiplayer is not officially supported but some features of the mod will work. Others will not, including stack unit commands. I have also received reports that C3X can cause crashes in online MP. In general, online play is something I'd like to support but haven't gotten around to yet. + +## Feature Highlights +#### Disorder Warning: +![C3X disorder warning feature. The domestic advisor is popping up to warn about unhappy cities before the end of a turn.](Misc%20Images/disorder_warning.jpg) + +If you try to end the turn with unhappy cities, the domestic advisor will pop up to warn you and give you the option to continue that turn. + +#### AI Enhancements: +Numerous changes have been made to improve the AI's behavior, especially in combat. It can now use its artillery units in the field, i.e., it will take them out of its cities to bombard enemy cities or incoming enemy units. The AI's production of artillery has been significantly increased so that it can take advantage of this ability. The other major change is that the AI can now use armies properly, it builds them when it can and fills them with units, usually the strongest available. There are many smaller changes as well to fix bugs and improve heuristics. Some more details are available as comments in the config file. + +#### Trade Screen Improvements: +![C3X trade screen arrows. Shows the top of the leader window with arrows on either side.](Misc%20Images/c3x_trade_screen_arrows.jpg) + +When negotiating with the AI, you can quickly switch back and forth between civs using the added arrow buttons (arrow keys work as well). When asking for or offering gold, the set amount popup will appear with the best amount already filled in. Best amount means, when asking for gold on an acceptable trade, the most you could get, and when offering gold on an unacceptable trade, the least you need to pay. + +#### Optimization: +A major inefficiency in the game's sea trade computation has been fixed. This eliminates one major cause of slow turns in the late game, especially on large maps with many coastal cities and many wars. For details about the problem and how C3X solves it, see [this post](https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-83#post-16536108). + +#### Adjustable Movement Rules: +The functions governing unit movement have been modified to enable various adjustments to the game's movement rules not possible through the editor. As with all other engine extensions, the rules are not changed from vanilla Conquests unless the config file is edited. + +Unlimited railroad movement can be turned off. The non-unlimited railroads can function like they do in Civ 4, meaning that all units will move the same distance along them regardless of how many moves they have, or they can function like an upgraded version of regular roads that have a lower movement cost. The relevant config variables are "limit\_railroad\_movement" and "limited\_railroads\_work\_like\_fast\_roads". + +Enabling land/sea intersections allows sea units to travel over the thin isthmus that exists on the diagonal path between two land tiles. More specifically, imagine a diamond of four tiles with land terrain on the north & south tiles and water on the east & west ones. With land/sea intersections enabled, naval units can pass between the east and west tiles. + +It is possible to disallow trespassing, which will prevent units from entering another civ's borders without a right of passage agreement, similar to the rules in Civ 4. Invisible and hidden nationality units are allowed to trespass in any case. It is also possible to impose a stack limit, which will prevent units from entering tiles that already have more than a set number of units occupying them. The stack limit can be set separately for land, sea, and air units. + +#### Small Wonder Free Improvements: +The free improvements wonder effect (granaries from Pyramids etc.) now works on small wonders. Note to modders, to set this effect you must use a third party editor like Quintillus' ([thread link](https://forums.civfanatics.com/threads/cross-platform-editor-for-conquests-now-available.377188/)) because the option is grayed out in the standard editor. Even worse, if you set the effect then work on the BIQ in the standard editor, the effect won't be saved, so you'd need to set it every time or work exclusively in Quintillus' editor. + +#### No-Raze & Limit Removals: +The no-raze and no-unit-limit features of earlier modded EXEs have been re-implemented as part of C3X. To enable no-raze, edit the config. There are separate options to prevent autorazing (the forced destruction of size 1 cities) and razing by player's choice. In addition to removing the unit limit, C3X also removes the limit of 256 city improvement types, and lifts the city limit to 2048. + +## Full Feature List +All C3X features are listed below. See the default config (default.c3x\_config.ini) for descriptions. +
+ Included in C3X + + #### Convenience features + - Stack unit commands + - Stack bombard + - Worker buttons (irrigate, road, etc.) become stack buttons by holding CTRL + - Stack fortify, upgrade, and disband also with CTRL + - Disorder warning + - Detailed city production info + - Buttons on trade screen to quickly switch between civs + - Ask/offer gold popup autofills best amount + - Skip repeated popups asking to replace a tile improvement + - Group units on right click menu + - Show coordinates and chopped status in tile info box + - Show golden age turns remaining + - No special king unit names in non-regicide games + - Option to disable worker automation + - On the city screen, hold shift when clicking a specialist to switch to the previous type + - Automatically cut research spending to avoid bankruptcy + - Remove pause for "we love the king" messages + - Suppress "maximum hypertext links exceeded" popup + - Civilopedia indicates when units go obsolete but cannot be upgraded + - Message appears after bomber dodges interception by air defense buildings + - Option to replay AI moves for all human players in hotseat mode + - Restore unit directions on game load + - Option to remove Elvis Easter egg + - Harbor/airport city icons indicate unit effects not trade abilities + - Disallow useless bombard attacks vs airfields + - Display total city count (disabled by default, appears on demographics screen) + - Fix graphical issues when running on Wine + - Option to pack the lists of luxuries and strategic resources more tightly into their boxes on the city screen + - Right-click menu enhancements + - Place icons next to units showing movement and combat status + - Replace Wake/Activate with descriptions of what the units are doing + - Gray out units if they have no remaining moves + - Apply GridOn setting from conquests.ini after loading a save + - Option to have a warning when the building you've selected to build would replace another already built in the city + - Option not to unassign workers from tiles that become polluted + - Pressing the Z key on the city screen toggles the zoom level of the map display + - Option not to draw capital cities larger than they really are + - Allow Civilopedia descriptions for units, civilizations, and game concepts to span multiple pages + - Double size of minimap when running in high definition (>= 1920 horizontal pixels) + - Option to show some popup messages as online-multiplayer-style notifications + - Option to switch debug mode on or off for games in progress + - Option to tint coast and sea tiles on minimap based on cultural borders + #### Optimization + - Optimize computation of trade networks + - For details, see the info text file in the Trade Net X folder + - Optimize improvement loops + - Option to measure turn times + #### AI Enhancements + - Allow AI to use artillery in the field + - Force AI to build more artillery and bombers + - Replace leader unit AI to fix bugs and improve behavior + - Fix bug preventing AI from filling its armies + - Improve AI army composition to discourage mixing types & exclude HN units + - AI routine for "pop units", which are modded units whose only purpose is to be joined into cities + - AI routine for "caravan units", which are modded units whose only purpose is to be disbanded for shields + - Can limit the number of escorts the AI assigns to its naval transports and carriers + - Adjustable AI worker requirement + - Option to stop AI from escorting units without the "requires escort" flag + - Option to draw small shadows underneath city dots on the minimap to make them more visible + #### Bugs Fixed + - AI pathfinding collides with invisible units (called the "submarine bug") + - Science age beakers not actually awarded + - Pink line in Civilopedia + - Crash when doing disembark-all on transport containing immobile unit(s) + - Crash possible when AI civ is left alive with only a settler on a transport (called the "houseboat bug") + - Resources beyond the first 32 share access records in cities not on the main trade network (called the "phantom resource bug") + - Air units lose a turn after being set to intercept + - Cached building maintenance amounts not updated when buildings are obsoleted + - Barbarian long-range search for targets is limited to tiles directly NW or SE + - "Disables Diseases From Flood Plains" tech flag hardcoded to tech #8 (off by default) + - Possible division by zero in AI logic to evaluate proposed alliances + - Available movement computed incorrectly for empty armies + - Off-map AI units may crash the game (fixed by deleting them at the start of their turns) + - Pathfinder improperly truncates long paths, sending AI units on nonsensical or invalid paths + - Cities with zero production crash the game due to division by zero + - Icons for different kinds of specialist yields are drawn on top of, instead of next to, one another + - AI players may sacrifice units without the "sacrifice" special ability + - AI players may build armies with leader units that don't have the "build army" special ability + - Possible crash in base game leader unit AI + #### AMB Editor + - A program for inspecting and modifying the special .amb sound files used by Civ 3. + - For more info, see README.txt in the AMB Editor folder + #### Limits Removed + - Removed unit limit + - Removed city improvement limit + - Lift city limit to 2048 and allow it to be configured + - Remove cap on turn limit + #### Engine Extensions + - Adjustable minimum city distance + - Option to limit railroad movement, as in Civ 4 or by converting them to fast roads + - Option to limit how many units can share each tile + - Enable free improvements from small wonders + - Option to share visibility among all human players in a hotseat game + - Option to prevent autoraze and razing by players + - Trespassing prevention + - Land/sea intersections + - Adjustable anarchy length + - Unit limits (stops players from producing units of a given type once they reach a maximum quantity) + - "Perfume" city production options, technologies, and governments to control how likely the AI is to choose them + - Reveal AI logic + - Press P in city screen to see AI point value for each available build + - Press L on map to see how desirable the AI finds each tile as a city location + - Corruption can be completely removed with "OFF" government setting + - Disallow land units from working or settling water tiles + - Option to let units move after airdropping + - Buildings can generate resources + - Buildings can be set as prerequisites for unit production + - Can cancel out pop pollution with negative pollution amount on building flagged as removing pop pollution + - Option to modify rules for retreat eligibility + - AI multi-city start + - Starter cities can begin with improvements, including "extra palaces" which respawn like the real palace + - Option to strengthen the corruption reducing effect of wonders to match the palace's + - Option to allow military great leaders to hurry wonders + - Option to multiply AI research rate by any amount + - Option to aggressively penalize bankrupt players + - Option to remove exception to tile penalty for city tiles with fresh water and Agri trait + - Artillery can be set to use PTW-like targeting against cities + - Recon missions can be made vulnerable to interception + - Option to charge one move for recon missions and interception + - Stealth attack changes + - Option to perform stealth attack even when there's only one target + - Enable stealth attacks via bombardment + - Allow players to opt out of stealth attacks + - Option to show unit hitpoints on the stealth attack target selection popup + - Option to prevent stealth attacks from targeting units that are invisible and unrevealed + - Polish precision striking by land or sea units + - Use regular bombard animation instead of flying animation + - Use bombard range instead of operational range + - Despawn unit if cruise missile + - Cannot be intercepted + - Option to immunize aircraft against bombardment + - Option to ignore king flag on defense, so kings aren't always last to defend in a stack + - Option to show untradable techs on trade screen + - Barbarian city capture & production (experimental) + - Option to allow land units to bombard aircraft and naval units in cities + - Zone of control changes + - Allow land-to-sea and sea-to-land attacks, only using bombard stat + - May be lethal + - May be exerted by air units + - Show attack animation even when attacker is not at the top of its stack + - Defensive bombard changes + - May be lethal + - May be performed by air units + - Invisible, undetected units may be made immune + - May be performed multiple times per turn with blitz + - Naval units in a city may perform defensive bombard vs land attackers + - Allow precision strikes to target tile improvements + - Option not to end a unit's turn after it bombards a barricade + - Option to allow bombardment of other improvements on a tile with an occupied airfield + - Option to boost OCN increase from forbidden palaces in non-communal governments + - Option to allow airdrops without airports + - Can increase unit maintenance costs based on their build costs + - Civ and leader names can vary by era + - Option to allow upgrades in any city + - Option to stop the map generator from placing volcanos + - Option to stop pollution from appearing on impassable tiles + - Option to make planting forests produce LM forest terrain + - Adjustable chance for max one HP units to be destroyed by nuclear strikes + - Option to allow sale of buildings like aqueducts that uncap population growth + - Option stopping non-sea detector units from revealing invisible sea units and vice-versa + - Adjustable city work area size + - Radius of area can be set from 1 to 7 tiles (2 is the standard) + - Area can also be limited by a city's cultural level or buildings + - Option to throttle AI's expansion by temporarily applying perfume to settlers each time it founds a city + - Option to block the galley chaining exploit by preventing units from loading into two different transports on the same turn + - Adjustable rebase range as multiple of operational range + - Option to share wonders among human players in hotseat mode + - Enable tile graphics to cycle over day and night, see "Day/Night Cycle" section of default config for details + - Can adjust time to double building culture + - Option to prevent units from upgrading past an intermediate type that does not have the upgrade ability + - Can adjust times to generate tourism gold + - Option to put all human players in contact with each other at the start of a hotseat game + - Enable districts, an elaborate change to the game's economy inspired by Civ 6 + - The districts feature is a large mod on its own. See its thread: https://forums.civfanatics.com/threads/c3x-districts.700590/ + - Land transport changes + - Land transports may be loaded into naval transports + - Empty LTs may join armies + - Units inside an LT may be prevented from defending their tile, performing defensive bombard, or intercepting air units + - Units inside an LT can be destroyed when the LT itself is destroyed or captured + - Resource placement changes + - Can relax the rule preventing resources from appearing next to others of a different type + - Adjust the overall appearance rate for luxuries that do not have a fixed rate set + - Control the overall appearance rate of bonus resources + - Option to allow sale of small wonders + - Option to allow units to be unloaded from armies + - Option to prevent land anti-air units from intercepting overflying aircraft while they're loaded in a naval transport + - Option to prevent units from being enslaved after being destroyed by lethal bombard named prevent_enslaving_by_bombardment +
+ +## How It Works +Some parts of the mod (bug fixes, no-raze, no unit limit) are really just hex edits that are applied to the Civ program code. The real secret sauce is a system to compile and inject arbitrary C code into the process which makes it practical to implement new features in the game. The heart of the system is TCC (Tiny C Compiler) and much work puzzling out the functions and structs inside the executable. Much thanks to Antal1987 for figuring out most of the structs years before I came along, [his work is posted here](https://github.com/Antal1987/C3CPatchFramework)). + +C3X is open source. The C code that gets injected into the game's EXE is located in injected_code.c and the code to perform the injection is located in ep.c. You're invited to explore the source code if you're interested. + +## Special Thanks +1. Antal1987 for his work reverse engineering Civ3 +2. Rmulo Prado for his help testing the mod +3. Civinator for the German translation. See: https://www.civforum.de/showthread.php?113285-Der-Flintlock-Deutsch-Patch +4. Vaughn Parker for generously commissioning the port to the PCGames.de EXE and many other features +5. instafluff0 for contributing the districts and day/night cycle features +6. Philiquaz and dobragab for their contributions diff --git a/Sound Test/BUILD_LINUX.sh b/Sound Test/BUILD_LINUX.sh index 8d2994f6..a952361f 100644 --- a/Sound Test/BUILD_LINUX.sh +++ b/Sound Test/BUILD_LINUX.sh @@ -1 +1 @@ -i686-w64-mingw32-g++ --static sound_test.cpp -o sound_test.exe +i686-w64-mingw32-g++ --static sound_test.cpp -o sound_test.exe diff --git a/civ_prog_objects.csv b/civ_prog_objects.csv index 82c39193..02f6830b 100644 --- a/civ_prog_objects.csv +++ b/civ_prog_objects.csv @@ -1,964 +1,964 @@ -JOB, GOG ADDR, STEAM ADDR, PCG ADDR, NAME, TYPE -define, 0, 1, 2, "exe_version_index", "int" -define, 0x9C3508, 0x9E5D08, 0x9C34C8, "p_bic_data", "BIC *" -define, 0xA52E80, 0xA75680, 0xA52E40, "p_units", "Units *" -define, 0xA52DD4, 0xA755D0, 0xA52D94, "p_tile_units", "TileUnits *" -define, 0xA52E68, 0xA75668, 0xA52E28, "p_cities", "Cities *" -define, 0xA52E50, 0xA75650, 0xA52E10, "p_colonies", "Base_List *" -define, 0xA52E98, 0xA75698, 0xA52E58, "leaders", "Leader *" -define, 0xB3CEA0, 0xB5F6A0, 0xB3CE60, "city_sprites", "Sprite *" -define, 0xB3E7D0, 0xB60FD0, 0xB3E790, "destroyed_city_sprites", "Sprite *" -define, 0x9F8700, 0xA1AF00, 0x9F86C0, "p_main_screen_form", "Main_Screen_Form *" -define, 0xA52658, 0xA74E50, 0xA52618, "p_game", "Game *" -define, 0xCB8B38, 0xCDB440, 0xCB8AF8, "temp_ui_strs", "char[10][4096]" -define, 0x665188, 0x68219C, 0x665188, "ADDR_ADDR_OUTPUTDEBUGSTRINGA", "void *" -define, 0x665280, 0x6822E0, 0x665280, "ADDR_ADDR_GETASYNCKEYSTATE", "void *" -define, 0x665168, 0x682130, 0x665168, "ADDR_ADDR_GETPROCADDRESS", "void *" -define, 0x6650E4, 0x6820B8, 0x6650E4, "ADDR_ADDR_GETMODULEHANDLEA", "void *" -define, 0x66527C, 0x6822E4, 0x66527C, "ADDR_ADDR_MESSAGEBOXA", "void *" -repl vptr, 0x73A8FC, 0x756C74, 0x73A8D4, "init_floating_point", "void (__stdcall *) (void)" -define, 0x5B6B01, 0x5C5458, 0x5B6811, "ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK", "void *" -define, 0x569503, 0x575933, 0x5694B3, "ADDR_UNIT_COUNT_CHECK", "void *" -define, 0x594B35, 0x5A2357, 0x594855, "ADDR_ERA_COUNT_CHECK", "void *" -define, 0x5601EF, 0x56C2E3, 0x56019F, "ADDR_SCIENCE_AGE_BUG_PATCH", "void *" -define, 0x4CD0B1, 0x4D5151, 0x4CD171, "ADDR_PEDIA_TEXTURE_BUG_PATCH", "void *" -define, 0x5640AC, 0x570385, 0x56405C, "ADDR_AUTORAZE_BYPASS", "void *" -repl vptr, 0x66CB50, 0x689C3C, 0x66CB50, "Leader_impl_would_raze_city", "bool (__fastcall *) (Leader * this, int edx, City * city)" -repl vptr, 0x66B44C, 0x68854C, 0x66B44C, "Main_Screen_Form_handle_left_click_on_map_1", "void (__fastcall *) (Main_Screen_Form * this, int edx, int param_1, int param_2)" -inlead, 0x4EA210, 0x4F3000, 0x4EA2D0, "Main_Screen_Form_handle_right_click_on_tile", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" -inlead, 0x4E8850, 0x4F14E0, 0x4E8910, "Main_Screen_Form_open_right_click_menu", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" -define, 0x499FE0, 0x49F9F0, 0x49A070, "is_online_game", "char (__stdcall *) (void)" -define, 0x437A70, 0x439620, 0x437AF0, "tile_at", "Tile * (__cdecl *) (int x, int y)" -define, 0x426C80, 0x4283C0, 0x426D00, "TileUnits_TileUnitID_to_UnitID", "int (__fastcall *) (TileUnits * this, int edx, int tile_unit_id, int * out_UnitItem_field_0)" -inlead, 0x5C1410, 0x5CFFA0, 0x5C1120, "Unit_bombard_tile", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -inlead, 0x5BE820, 0x5CD420, 0x5BE530, "Unit_get_defense_strength", "int (__fastcall *) (Unit * this)" -inlead, 0x5BB650, 0x5CA190, 0x5BB360, "Unit_is_visible_to_civ", "char (__fastcall *) (Unit * this, int edx, int civ_id, int param_2)" -define, 0x5EA6C0, 0x5F9F10, 0x5EA5F0, "Tile_has_city", "char (__fastcall *) (Tile * this)" -define, 0x5EA6E0, 0x5F9F30, 0x5EA610, "Tile_has_colony", "bool (__fastcall *) (Tile * this)" -define, 0x5BE5B0, 0x5CD180, 0x5BE2C0, "Unit_get_max_hp", "int (__fastcall *) (Unit * this)" -define, 0x5E4EF0, 0x5F4750, 0x5E4E20, "UnitType_has_ability", "bool (__fastcall *) (UnitType * this, int edx, enum UnitTypeAbilities a)" -define, 0x5CDDF0, 0x5DCEB0, 0x5CDD10, "get_max_move_points", "int (__cdecl *) (UnitType * unit_type, int civ_id)" -inlead, 0x5BE470, 0x5CD030, 0x5BE180, "Unit_get_max_move_points", "int (__fastcall *) (Unit * this)" -define, 0x60B370, 0x625850, 0x60B290, "Button_set_tooltip", "int (__fastcall *) (Button * this, int edx, char * str)" -define, 0x5FC420, 0x60FC10, 0x5FC300, "PCX_Image_construct", "PCX_Image * (__fastcall *) (PCX_Image * this)" -define, 0x5FC820, 0x610360, 0x5FC700, "PCX_Image_read_file", "int (__fastcall *) (PCX_Image * this, int edx, char * file_path, PCX_Color_Table * out_color_table, int ct_start, int ct_count, unsigned flags)" -define, 0x5F7E50, 0x608170, 0x5F7D80, "Sprite_construct", "Sprite * (__fastcall *) (Sprite * this)" -define, 0x5F7F90, 0x6083D0, 0x5F7EC0, "Sprite_slice_pcx", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * img, int up_left_x, int up_left_y, int w, int h, int arg6, int arg7)" -define, 0x49FC50, 0x4A6790, 0x49FCE0, "get_popup_form", "PopupForm * (__stdcall *) ()" -define, 0x61C5A0, 0x63E390, 0x61C4D0, "set_popup_str_param", "int (__cdecl *) (int param_index, char * str, int param_3, int param_4)" -define, 0x61C570, 0x63E350, 0x61C4A0, "set_popup_int_param", "int (__cdecl *) (int param_index, int value)" -inlead, 0x611530, 0x62DAF0, 0x611460, "show_popup", "int (__fastcall *) (void * this, int edx, int param_1, int param_2)" -define, 0x4ACD20, 0x4B3CC0, 0x4ACDB0, "City_zoom_to", "void (__fastcall *) (City *this, int edx, int param_1)" -inlead, 0x4ACB50, 0x4B3AF0, 0x4ACBE0, "City_has_improvement", "char (__fastcall *) (City * this, int edx, int i_improvement, char include_auto_improvements)" -inlead, 0x4E6DB0, 0x4EF820, 0x4E6E70, "Main_Screen_Form_perform_action_on_tile", "void (__fastcall *) (Main_Screen_Form * this, int edx, enum Unit_Mode_Actions action, int x, int y)" -inlead, 0x550BB0, 0x55BCE0, 0x550B60, "Main_GUI_set_up_unit_command_buttons", "void (__fastcall *) (Main_GUI * this)" -inlead, 0x5577F0, 0x563600, 0x5577A0, "Main_GUI_handle_button_press", "void (__fastcall *) (Main_GUI * this, int edx, int button_id)" -inlead, 0x4E05F0, 0x4E8F90, 0x4E06B0, "Main_Screen_Form_handle_key_down", "int (__fastcall *) (Main_Screen_Form * this, int edx, int char_code, int virtual_key_code)" -inlead, 0x6268A0, 0x64B410, 0x624C00, "handle_cursor_change_in_jgl", "int (__stdcall *) ()" -inlead, 0x555F80, 0x561B90, 0x555F30, "Main_GUI_handle_click_in_status_panel", "void (__fastcall *) (Main_GUI * this, int edx, int mouse_x, int mouse_y)" -define, 0x54CAD0, 0x557980, 0x54CB30, "get_font", "Object_66C3FC * (__cdecl *) (int size, FontStyleFlags style)" -define, 0x5FD750, 0x611850, 0x5FD630, "PCX_Image_draw_centered_text", "int (__fastcall *) (PCX_Image *this, int edx, Object_66C3FC * font, char * str, int x, int y, int width, int str_len)" -inlead, 0x4196F0, 0x41A5D0, 0x419770, "City_Form_draw", "void (__fastcall *) (City_Form * this)" -inlead, 0x41B4C0, 0x41C610, 0x41B540, "City_Form_print_production_info", "void (__fastcall *) (City_Form *this, int edx, String256 * out_strs, int str_capacity)" -define, 0x4ACD70, 0x4B3D30, 0x4ACE00, "City_get_order_cost", "int (__fastcall *) (City * this)" -define, 0x4ACD40, 0x4B3CE0, 0x4ACDD0, "City_get_order_progress", "int (__fastcall *) (City * this)" -inlead, 0x57F360, 0x58C080, 0x57F0C0, "Trade_Net_get_movement_cost", "int (__fastcall *) (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned flags, int neighbor_index, Trade_Net_Distance_Info * dist_info)" -define, 0x57F0A0, 0x58BDB0, 0x57EE00, "Trade_Net_have_trade_connection", "bool (__fastcall *) (Trade_Net * this, int edx, City * a, City * b, int civ_id)" -define, 0x57F130, 0x58BE40, 0x57EE90, "Trade_Net_is_tile_connected_to_city", "bool (__fastcall *) (Trade_Net * this, int edx, City * city, int tile_x, int tile_y)" -inlead, 0x591BB0, 0x59F1D0, 0x5918D0, "do_save_game", "int (__cdecl *) (char const * file_path, char param_2, GUID * guid)" -define, 0x4BCFF0, 0x4C4660, 0x4BD080, "City_recompute_happiness", "void (__fastcall *) (City * this)" -define, 0x4B05D0, 0x4B7590, 0x4B0660, "City_recompute_production", "void (__fastcall *) (City * this)" -define, 0x4B07C0, 0x4B7770, 0x4B0850, "City_recompute_commerce", "void (__fastcall *) (City * this)" -inlead, 0x4B0B70, 0x4B7B20, 0x4B0C00, "City_recompute_culture_income", "void (__fastcall *) (City * this)" -inlead, 0x4B2680, 0x4B9600, 0x4B2710, "City_update_culture", "void (__fastcall *) (City * this)" -define, 0x4B0C60, 0x4B7C10, 0x4B0CF0, "City_recompute_cultural_level", "void (__fastcall *) (City *this, int edx, char param_1, char param_2, char param_3)" -define, 0x4B10F0, 0x4B80A0, 0x4B1180, "recompute_food_eaten_production_commerce_and_happiness", "void (__fastcall *) (City *this)" -inlead, 0x55A560, 0x566470, 0x55A510, "Leader_recompute_auto_improvements", "void (__fastcall *) (Leader * this)" -inlead, 0x539030, 0x543650, 0x5390B0, "Game_get_wonder_city_id", "int (__fastcall *) (Game * this, int edx, int wonder_improvement_id)" -define, 0x55A62E, 0x566538, 0x55A5DE, "ADDR_SMALL_WONDER_FREE_IMPROVS_RETURN", "int" -define, 0x55A5C6, 0x5664D4, 0x55A576, "ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER", "void *" -repl vptr, 0x66B46C, 0x68856C, 0x66B46C, "Main_Screen_Form_handle_key_up", "int (__fastcall *) (Main_Screen_Form * this, int edx, int virtual_key_code)" -define, 0x4DAA70, 0x4E3430, 0x4DAB30, "Main_Screen_Form_issue_command", "char (__fastcall *) (Main_Screen_Form * this, int edx, int command, Unit * unit)" -define, 0x609D60, 0x6233C0, 0x609C80, "clear_something_1", "void (__stdcall *) ()" -define, 0x6207B0, 0x644F10, 0x6206E0, "Timer_clear", "void (__fastcall *) (Timer * this)" -inlead, 0x55EFA0, 0x56B030, 0x55EF50, "Leader_can_do_worker_job", "char (__fastcall *) (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing)" -define, 0x56A7C0, 0x576C60, 0x56A770, "Leader_can_build_unit", "bool (__fastcall *) (Leader * this, int edx, int unit_type_id, int param_2, bool allow_kings)" -define, 0x455288, 0x457458, 0x455308, "ADDR_CHECK_ARTILLERY_IN_CITY", "void *" -inlead, 0x455140, 0x457310, 0x4551C0, "Unit_ai_move_artillery", "void (__fastcall *) (Unit * this)" -define, 0x5E6E50, 0x5F66A0, 0x5E6D80, "neighbor_index_to_diff", "void (__cdecl *) (int neighbor_index, int * out_x, int * out_y)" -define, 0x5B3040, 0x5C1970, 0x5B2D50, "Unit_set_state", "void (__fastcall *) (Unit * this, int edx, int new_state)" -define, 0x5B2F10, 0x5C1840, 0x5B2C20, "Unit_set_escortee", "void (__fastcall *) (Unit * this, int edx, int escortee)" -inlead, 0x44D980, 0x44F9E0, 0x44DA00, "Unit_seek_colony", "int (__fastcall *) (Unit *this, int edx, bool for_own_defense, int max_distance)" -repl call, 0x4527BE, 0x4548E3, 0x45283E, "Tile_has_district_or_colony", "" -define, 0xA526B4, 0xA74EAC, 0xA52674, "p_rand_object", "void *" -define, 0x60BAB0, 0x626440, 0x60B9E0, "rand_int", "int (__fastcall *) (void * this, int edx, int lim)" -inlead, 0x42C8A0, 0x42E430, 0x42C920, "City_ai_choose_production", "void (__fastcall *) (City * this, int edx, City_Order * out)" -inlead, 0x4C04E0, 0x4C7AB0, 0x4C0570, "City_can_build_unit", "bool (__fastcall *) (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings)" -repl call, 0x5C536C, 0x5D404D, 0x5C507C, "Unit_get_max_move_points_for_disembarking", "" -inlead, 0x5C5420, 0x5D4120, 0x5C5130, "Unit_disembark_passengers", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -define, 0xCAA330, 0xCCCB98, 0xCAA2F0, "p_null_tile", "Tile *" -define, 0x45A35F, 0x45C56F, 0x45A3DF, "ADDR_HOUSEBOAT_BUG_PATCH", "byte *" -define, 0x45A386, 0x45C596, 0x45A406, "ADDR_HOUSEBOAT_BUG_PATCH_END", "byte *" -define, 0xB72888, 0xB950A8, 0xB72848, "p_original_trade_net", "Trade_Net *" -inlead, 0x580540, 0x58D270, 0x5802A0, "Trade_Net_set_unit_path", "int (__fastcall *) (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp)" -define, 0x5B3290, 0x5C1BE0, 0x5B2FA0, "Unit_pop_next_move_from_path", "byte (__fastcall *) (Unit * this)" -inlead, 0x45FED0, 0x4622A0, 0x45FF50, "Unit_ai_move_leader", "void (__fastcall *) (Unit * this)" -define, 0x5B2B20, 0x5C1440, 0x5B2830, "Unit_next_escorter_id", "int (__fastcall *) (Unit * this, int edx, int * index, bool begin_iterating)" -define, 0x5BC300, 0x5CAE50, 0x5BC010, "Unit_disband", "void (__fastcall *) (Unit * this)" -inlead, 0x5C00A0, 0x5CEC20, 0x5BFDB0, "Unit_can_hurry_production", "bool (__fastcall *) (Unit * this, int edx, City * city, bool exclude_cheap_improvements)" -inlead, 0x5B3AB0, 0x5C2400, 0x5B37C0, "Unit_can_pillage", "bool (__fastcall *) (Unit *this, int edx, int tile_x, int tile_y)" -inlead, 0x5CCBB0, 0x5DBB50, 0x5CC8C0, "Unit_can_pass_between", "bool (__fastcall *) (Unit *this, int edx, int from_x, int from_y, int to_x, int to_y, byte param_5)" -define, 0x5C0420, 0x5CEFC0, 0x5C0130, "Unit_hurry_production", "void (__fastcall *) (Unit * this)" -define, 0x5C0300, 0x5CEE90, 0x5C0010, "Unit_ai_can_start_science_age", "bool (__fastcall *) (Unit * this)" -define, 0x5C03B0, 0x5CEF50, 0x5C00C0, "Unit_start_science_age", "void (__fastcall *) (Unit * this)" -inlead, 0x5BC980, 0x5CB510, 0x5BC690, "Unit_ai_can_form_army", "bool (__fastcall *) (Unit * this)" -define, 0x5BCA20, 0x5CB5B0, 0x5BC730, "Unit_form_army", "Unit * (__fastcall *) (Unit * this)" -repl vptr, 0x66DD28, 0x68AE08, 0x66DD28, "impl_ai_is_good_army_addition", "bool (__fastcall *) (Unit * this, int edx, Unit * candidate)" -repl vptr, 0x666578, 0x6835CC, 0x666578, "PopupForm_set_text_key_and_flags", "void (__fastcall *) (PopupForm * this, int edx, char * script_path, char * text_key, int param_3, int param_4, int param_5, int param_6)" -define, 0xA35200, 0xA57A00, 0xA351C0, "p_diplo_form", "DiploForm *" -define, 0x649A8B, 0x6683E1, 0x6499CF, "new", "void * (__cdecl *) (unsigned num_bytes)" -define, 0x666AC4, 0x683B1C, 0x666AC4, "p_trade_offer_vtable", "TradeOfferVTable *" -define, 0x440EE0, 0x442CD0, 0x440F60, "Leader_consider_trade", "DiploMessage (__fastcall *) (Leader * this, int edx, TradeOfferList * receiving, TradeOfferList * paying, int other_party_civ_id, byte param_4, bool param_5, byte param_6, byte param_7, int * out_advantage, int * param_9, int * param_10)" -define, 0x509325, 0x51334D, 0x5093C5, "ADDR_SETUP_INITIAL_GOLD_ASK_RETURN", "int" -define, 0x50BCC8, 0x515DA1, 0x50BD68, "ADDR_SETUP_MODIFY_GOLD_ASK_RETURN", "int" -define, 0x509669, 0x51366E, 0x509709, "ADDR_SETUP_INITIAL_GOLD_OFFER_RETURN", "int" -define, 0x50BF10, 0x516008, 0x50BFB0, "ADDR_SETUP_MODIFY_GOLD_OFFER_RETURN", "int" -define, 14, 14, 14, "TRADE_GOLD_SETTER_IS_LUMP_SUM_OFFSET", "int" -define, 0x50BEBD, 0x515FB4, 0x50BF5D, "ADDR_PRINT_GOLD_AMOUNT_1", "byte *" -define, 0x50BC75, 0x515D4D, 0x50BD15, "ADDR_PRINT_GOLD_AMOUNT_2", "byte *" -inlead, 0x5F3160, 0x603000, 0x5F3090, "Map_check_city_location", "CityLocValidity (__fastcall *) (Map *this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile)" -repl vptr, 0x66C1E8, 0x6892D8, 0x66C1E8, "DiploForm_m68_Show_Dialog", "int (__fastcall *) (DiploForm * this, int edx, int param_1, void * param_2, void * param_3)" -repl vptr, 0x66C220, 0x689310, 0x66C220, "DiploForm_m82_handle_key_event", "void (__fastcall *) (DiploForm * this, int edx, int virtual_key_code, int is_down)" -define, 0xA526C0, 0xA74EB8, 0xA52680, "p_player_bits", "unsigned *" -define, 0x50D830, 0x517970, 0x50D8D0, "DiploForm_close", "void (__fastcall *) (DiploForm *)" -inlead, 0x505F40, 0x50FD30, 0x505FE0, "DiploForm_do_diplomacy", "void (__fastcall *) (DiploForm * this, int edx, int diplo_message, int param_2, int civ_id, int do_not_request_audience, int war_negotiation, int disallow_proposal, TradeOfferList * our_offers, TradeOfferList * their_offers)" -define, 0x440E10, 0x442C00, 0x440E90, "Leader_ai_would_meet_with", "bool (__fastcall *) (Leader * this, int edx, int civ_id)" -repl vptr, 0x66C130, 0x689220, 0x66C130, "DiploForm_m22_Draw", "void (__fastcall *) (DiploForm * this)" -define, 0x609F50, 0x623C40, 0x609E70, "Button_construct", "Button * (__fastcall *) (Button * this)" -define, 0x60B050, 0x625450, 0x60AF70, "Button_initialize", "int (__fastcall *) (Button * this, int edx, char * text, int control_id, int x, int y, int width, int height, Base_Form * parent, int param_8)" -define, 0x5161C0, 0x51F9B0, 0x516260, "DiploForm_set_their_message", "int (__fastcall *) (DiploForm * this, int edx, DiploMessage msg, int message_arg, int param_3)" -define, 0x516260, 0x51FA50, 0x516300, "DiploForm_reset_our_message_choices", "void (__fastcall *) (DiploForm *)" -define, 0x649FA7, 0x6076E0, 0x649EEB, "civ_prog_malloc", "void * (__cdecl *) (unsigned _Size)" -define, 0x649EBE, 0x668816, 0x649E02, "civ_prog_free", "void (__cdecl *) (void * p)" -inlead, 0x61A480, 0x63B9F0, 0x61A3B0, "Context_Menu_open", "int (__fastcall *) (Context_Menu * this, int edx, int x, int y, int param_3)" -define, 0x4E993C, 0x4F273A, 0x4E99FC, "ADDR_OPEN_UNIT_MENU_RETURN", "int" -define, 0x61B0C0, 0x63C940, 0x61AFF0, "Context_Menu_widen_for_text", "void (__fastcall *) (Context_Menu * this, int edx, char * text)" -inlead, 0x61A110, 0x63B420, 0x61A040, "Context_Menu_add_item_and_set_color", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, char * text, int red)" -define, 0x61A160, 0x63B480, 0x61A090, "Context_Menu_add_separator", "int (__fastcall *) (Context_Menu * this, int edx, int item_id)" -inlead, 0x45C750, 0x45EA70, 0x45C7D0, "Unit_ai_move_terraformer", "void (__fastcall *) (Unit * this)" -inlead, 0x4B1DC0, 0x4B8D50, 0x4B1E50, "City_requires_improvement_to_grow", "int (__fastcall *) (City * this)" -inlead, 0x4DD530, 0x4E5F00, 0x4DD5F0, "maybe_show_improvement_needed_for_growth_dialog", "void (__fastcall *) (void * this, int edx, City * city, int * param_2)" -repl call, 0x5213E3, 0x52B3F3, 0x521483, "City_requires_improvement_to_grow_besides_neighborhood", "" -inlead, 0x5C1AD0, 0x5D0670, 0x5C17E0, "Unit_can_perform_command", "bool (__fastcall *) (Unit * this, int edx, int unit_command_value)" -inlead, 0x5B39D0, 0x5C2320, 0x5B36E0, "Unit_join_city", "void (__fastcall *) (Unit * this, int edx, City * city)" -define, 0x5C0740, 0x5CF2E0, 0x5C0450, "Unit_upgrade", "Unit * (__fastcall *) (Unit * this, int edx, bool ignore_cost)" -define, 0x5C04D0, 0x5CF070, 0x5C01E0, "Unit_get_upgrade_cost", "int (__fastcall *) (Unit * this)" -define, 0xCADC18, 0xCD0510, 0xCADBD8, "script_dot_txt_file_path", "char *" -inlead, 0x5B5CD0, 0x5C4620, 0x5B59E0, "Unit_can_move_to_adjacent_tile", "AdjacentMoveValidity (__fastcall *) (Unit * this, int edx, int neighbor_index, int param_2)" -define, 0x5F3F50, 0x603DD0, 0x5F3E80, "Map_compute_neighbor_index", "int (__fastcall *) (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim)" -repl call, 0x5CCC85, 0x5DBC1F, 0x5CC995, "Map_compute_neighbor_index_for_pass_between", "" -repl call, 0x42FC69, 0x43173F, 0x42FCE9, "Improvement_has_wonder_com_bonus_for_ai_prod", "" -define, 0x5FEF70, 0x613F70, 0x5FEE50, "PCX_Image_draw_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int str_len)" -repl call, 0x5AAB93, 0x5B9899, 0x5AA8A3, "PCX_Image_draw_no_tile_info", "" -repl call, 0x5AB00A, 0x5B97E8, 0x5AAD1A, "PCX_Image_draw_tile_info_terrain", "" -define, 0x4E3C60, 0x4EC4B0, 0x4E3D20, "Main_Screen_Form_get_tile_coords_under_mouse", "int (__fastcall *) (Main_Screen_Form * this, int edx, int mouse_x, int mouse_y, int * out_tile_x, int * out_tile_y)" -inlead, 0x5AA820, 0x5B8F40, 0x5AA530, "open_tile_info", "void (__fastcall *) (void * this, int edx, int mouse_x, int mouse_y, int civ_id)" -inlead, 0x53A860, 0x544B80, 0x53A8E0, "get_anarchy_length", "int (__stdcall *) (int leader_id)" -repl call, 0x5557DE, 0x56136E, 0x55578E, "PCX_Image_process_tech_ga_status", "" -define, 0x5FE560, 0x612F50, 0x5FE440, "PCX_Image_process_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str)" -define, 0xA526AC, 0xA74EA4, 0xA5266C, "p_current_turn_no", "int *" -define, 0xCADC0C, 0xCD0504, 0xCADBCC, "p_labels", "char ***" -define, 497, 498, 497, "LBL_GOLDEN_AGE", "int" -define, 0xA5267C, 0xA74E74, 0xA5263C, "p_toggleable_rules", "int *" -define, 0xA52680, 0xA74E78, 0xA52640, "p_debug_mode_bits", "unsigned *" -repl call, 0x569A10, 0x575E4A, 0x5699C0, "Unit_check_king_ability_while_spawning", "" -define, 0x5BC8B0, 0x5CB430, 0x5BC5C0, "Unit_has_ability", "bool (__fastcall *) (Unit * this, int edx, enum UnitTypeAbilities a)" -define, 0xA52658, 0xA74E50, 0xA52618, "p_match", "void *" -inlead, 0x442480, 0x444250, 0x442500, "Match_ai_eval_city_location", "int (__fastcall *) (void * this, int edx, int x, int y, int civ_id, bool param_4, int * out_breakdown)" -define, 0x430FBA, 0x432A6D, 0x43103A, "ADDR_INTERCEPT_AI_IMPROV_VALUE", "void *" -define, 7, 6, 7, "AI_CONSIDERATION_INTERCEPT_LEN", "int" -define, 0x433C7C, 0x435712, 0x433CFC, "ADDR_INTERCEPT_AI_UNIT_VALUE", "void *" -inlead, 0x4B1190, 0x4B8140, 0x4B1220, "City_compute_corrupted_yield", "int (__fastcall *) (City * this, int edx, int gross_yield, bool is_production)" -define, 0x610B30, 0x62CE00, 0x610A60, "PopupForm_add_text", "byte (__fastcall *) (PopupForm * this, int edx, char * text, bool param_2)" -define, 0x6193A0, 0x639AD0, 0x6192D0, "PopupSelection_add_item", "int (__fastcall *) (PopupSelection * this, int edx, char * text, int value)" -inlead, 0x59AB50, 0x5A8660, 0x59A870, "load_scenario", "unsigned (__fastcall *) (BIC * this, int edx, char * param_1, unsigned * param_2)" -define, 0x59B499, 0x5A8FD9, 0x59B1B9, "ADDR_LOAD_SCENARIO_PREVIEW_RETURN", "int" -define, 0x59AD27, 0x5A8872, 0x59AA47, "ADDR_LOAD_SCENARIO_RESUME_SAVE_2_RETURN", "int" -repl vptr, 0x6659F8, 0x682A5C, 0x6659F8, "City_Form_m82_handle_key_event", "void (__fastcall *) (City_Form * this, int edx, int virtual_key_code, int is_down)" -define, 0x437540, 0x4390F0, 0x4375C0, "Improvement_has_wonder_flag", "bool (__fastcall *) (Improvement * this, int edx, enum ImprovementTypeWonderFeatures flag)" -define, 0x437710, 0x4392F0, 0x437790, "UnitType_has_ai_strategy", "bool (__fastcall *) (UnitType * this, int edx, byte n)" -repl call, 0x431038, 0x432AE7, 0x4310B8, "UnitType_has_strat_0_for_ai_prod", "" -define, 0x44CE50, 0x44EE40, 0x44CED0, "Unit_find_transport", "Unit * (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C5F70, 0x5D4D50, 0x5C5C80, "Unit_select_transport", "Unit * (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, bool should_show_popup)" -inlead, 0x5C5110, 0x5D3DF0, 0x5C4E20, "Unit_load", "void (__fastcall *) (Unit * this, int edx, Unit * transport)" -define, 0xA526BC, 0xA74EB4, 0xA5267C, "p_human_player_bits", "int *" -inlead, 0x5F8130, 0x6085D0, 0x5F8060, "Sprite_draw_on_map", "int (__fastcall *) (Sprite * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7)" -repl vptr, 0x66A554, 0x687660, 0x66A554, "Map_Renderer_m19_Draw_Tile_by_XY_and_Flags", "void (__fastcall *) (Map_Renderer * this, int edx, int param_1, int pixel_x, int pixel_y, Map_Renderer * map_renderer, int param_5, int tile_x, int tile_y, int param_8)" -repl vptr, 0x66A624, 0x687730, 0x66A624, "Map_Renderer_m71_Draw_Tiles", "void (__fastcall *) (Map_Renderer * this, int edx, int param_1, int param_2, int param_3)" -repl vptr, 0x66B520, 0x688620, 0x66B520, "Main_Screen_Form_m82_handle_key_event", "void (__fastcall *) (Main_Screen_Form * this, int edx, int virtual_key_code, int is_down)" -repl call, 0x5C190B, 0x5D0493, 0x5C161B, "Unit_get_move_points_after_airdrop", "" -repl call, 0x4D93E0, 0x4E1D70, 0x4D94A0, "Unit_get_move_points_after_set_to_intercept", "" -repl vptr, 0x66E738, 0x68B810, 0x66E738, "Parameters_Form_m68_Show_Dialog", "int (__fastcall *) (Parameters_Form * this, int edx, int arg_1, void * arg_2, void * arg_3)" -define, 0x598580, 0x5A5E30, 0x5982A0, "BIC_get_asset_path", "char * (__fastcall *) (BIC * this, int edx, char * str, bool show_error_popup)" -define, 0x5F8080, 0x608500, 0x5F7FB0, "Sprite_slice_pcx_with_color_table", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * img, int up_left_x, int up_left_y, int w, int h, int arg6, int arg7)" -define, 0x5FD320, 0x611210, 0x5FD200, "PCX_Image_set_font", "int (__fastcall *) (PCX_Image * this, int edx, Object_66C3FC * font, int arg_2, int arg_3, int arg_4)" -define, 0x57EEC4, 0x58BBE8, 0x57EC24, "ADDR_INTERCEPT_SET_RESOURCE_BIT", "void *" -inlead, 0x4ADE30, 0x4B4E10, 0x4ADEC0, "City_has_resource", "bool (__fastcall *) (City * this, int edx, int resource_id)" -define, 0x4ADDC0, 0x4B4DA0, 0x4ADE50, "City_has_trade_connection_to_capital", "bool (__fastcall *) (City * this)" -define, 0x55EEB0, 0x56AF50, 0x55EE60, "Leader_has_resources_for_job_at", "bool (__fastcall *) (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y)" -inlead, 0x57E450, 0x58B1A0, 0x57E1B0, "Trade_Net_recompute_resources", "void (__fastcall *) (Trade_Net * this, int edx, bool skip_popups)" -define, 0x561440, 0x56D5A0, 0x5613F0, "Leader_has_tech", "bool (__fastcall *) (Leader * this, int edx, int id)" -inlead, 0x4BED80, 0x4C6350, 0x4BEE10, "City_cycle_specialist_type", "bool (__fastcall *) (City * this, int edx, int mouse_x, int mouse_y, Citizen * citizen, City_Form * city_form)" -inlead, 0x4B1C10, 0x4B8BC0, 0x4B1CA0, "City_get_total_pollution", "int (__fastcall *) (City * this)" -define, 0x4B1B40, 0x4B8B00, 0x4B1BD0, "City_get_pollution_from_buildings", "int (__fastcall *) (City * this)" -inlead, 0x4B1A50, 0x4B8A10, 0x4B1AE0, "City_get_pollution_from_pop", "int (__fastcall *) (City * this)" -inlead, 0x4ACF40, 0x4B3F20, 0x4ACFD0, "City_add_or_remove_improvement", "void (__fastcall *) (City * this, int edx, int improv_id, int add, bool param_3)" -define, 0x57E943, 0x58B68E, 0x57E6A3, "ADDR_RESOURCE_TILE_COUNT_MASK", "void *" -define, 0x57E5EB, 0x58B328, 0x57E34B, "ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE", "void *" -define, 0x5DA1A0, 0x5E9710, 0x5DA0D0, "Tile_get_resource_visible_to", "int (__fastcall *) (Tile * this, int edx, int civ_id)" -inlead, 0x5EA7F0, 0x5FA040, 0x5EA720, "Tile_m17_Check_Irrigation", "bool (__fastcall *) (Tile * this, int edx, int visible_to_civ_id)" -define, 0x5D16A0, 0x5E0900, 0x5D15D0, "Map_get_tile", "Tile * (__fastcall *) (Map * this, int edx, int index)" -repl call, 0x57E602, 0x58B345, 0x57E362, "Map_get_tile_when_recomputing_resources_1", "" -repl call, 0x57E629, 0x58B36C, 0x57E389, "Map_get_tile_when_recomputing_resources_2", "" -repl call, 0x57E618, 0x58B35B, 0x57E378, "Map_get_tile_when_recomputing_resources_3", "" -repl call, 0x57E64A, 0x58B397, 0x57E3AA, "Map_get_tile_when_recomputing_resources_4", "" -repl call, 0x57E672, 0x58B3B7, 0x57E3D2, "Map_get_tile_when_recomputing_resources_5", "" -repl call, 0x57E679, 0x58B3BE, 0x57E3D9, "Tile_get_visible_resource_when_recomputing", "" -inlead, 0x4A47C0, 0x4AB470, 0x4A4850, "Fighter_begin", "void (__fastcall *) (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender)" -define, 0x441ED0, 0x443CC0, 0x441F50, "Map_get_x_dist", "int (__fastcall *) (Map * this, int edx, int x1, int x2)" -define, 0x437970, 0x439520, 0x4379F0, "Map_get_y_dist", "int (__fastcall *) (Map * this, int edx, int y1, int y2)" -inlead, 0x5D7180, 0x5E65E0, 0x5D70B0, "Map_calc_food_yield_at", "int (__fastcall *) (Map * this, int edx, int tile_x, int tile_y, int tile_base_type, int civ_id, int imagine_fully_improved, City * city)" -inlead, 0x5D75F0, 0x5E6A20, 0x5D7520, "Map_calc_shield_yield_at", "int (__fastcall *) (Map *this, int edx, int tile_x, int tile_y, int civ_id, City *city, int param_5, int param_6)" -define, 0x5663C0, 0x572730, 0x566370, "Leader_create_city", "City * (__fastcall *) (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6)" -inlead, 0x5D3030, 0x5E2330, 0x5D2F60, "Map_process_after_placing", "void (__fastcall *) (Map * this, int edx, bool param_1)" -inlead, 0x5BBBC0, 0x5CA720, 0x5BB8D0, "Unit_despawn", "void (__fastcall *) (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7)" -inlead, 0x5BD220, 0x5CBDE0, 0x5BCF30, "Unit_move", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -define, 0x558700, 0x564590, 0x5586B0, "Main_GUI_label_loading_bar", "void (__fastcall *) (Main_GUI * this, int edx, int param_1, char *text)" -define, 0x48DE43, 0x4920E3, 0x48DED3, "ADDR_TURN_METALIMIT_1", "byte *" -define, 0x4946E1, 0x4990CA, 0x494771, "ADDR_TURN_METALIMIT_2", "byte *" -define, 0x54E2E0, 0x55925B, 0x54E340, "ADDR_TURN_METALIMIT_3", "byte *" -define, 0x54E2E7, 0x559262, 0x54E347, "ADDR_TURN_METALIMIT_4", "byte *" -define, 0x584163, 0x59100F, 0x583EC3, "ADDR_TURN_METALIMIT_5", "byte *" -define, 0x5817B2, 0x58E4E2, 0x581512, "ADDR_TURN_METALIMIT_6", "byte *" -define, 0x492100, 0x496751, 0x492190, "ADDR_TURN_METALIMIT_7", "byte *" -inlead, 0x4ACA50, 0x4B39F0, 0x4ACAE0, "City_get_net_commerce", "int (__fastcall *) (City * this, int edx, int kind, bool include_science_age)" -inlead, 0x55DFD0, 0x56A070, 0x55DF80, "Leader_pay_unit_maintenance", "void (__fastcall *) (Leader * this)" -define, 0x55CFB0, 0x569040, 0x55CF60, "Leader_sum_improvements_maintenance", "int (__fastcall *) (Leader * this, int edx, int govt_id)" -define, 0x560972, 0x56CA7F, 0x560922, "ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT", "byte *" -define, 0x55DD50, 0x569DF0, 0x55DD00, "Leader_compute_income", "int (__fastcall *) (Leader * this)" -define, 0x5612F0, 0x56D420, 0x5612A0, "Leader_recompute_economy", "void (__fastcall *) (Leader * this)" -repl call, 0x560C16, 0x56CD25, 0x560BC6, "Leader_sum_improv_maintenance_to_pay_1", "" -repl call, 0x560C64, 0x56CDA8, 0x560C14, "Leader_sum_improv_maintenance_to_pay_2", "" -inlead, 0x4ACDF0, 0x4B3DD0, 0x4ACE80, "City_get_improvement_maintenance", "int (__fastcall *) (City * this, int edx, int improv_id)" -define, 0x4C2350, 0x4C9B30, 0x4C2370, "Leader_set_treasury", "void (__fastcall *) (Leader * this, int edx, int amount)" -define, 0x4B3400, 0x4BA3A0, 0x4B3490, "City_sell_improvement", "void (__fastcall *) (City * this, int edx, int improv_id, bool set_status_bit)" -define, 0x9E85F0, 0xA0ADF0, 0x9E85B0, "p_civilopedia_form", "Civilopedia_Form *" -define, 0x4CBE10, 0x4D3E50, 0x4CBED0, "Civilopedia_open", "void (__fastcall *) (void * this, int edx, char * key, bool param_2)" -define, 0x53A960, 0x544C80, 0x53A9E0, "get_unit_support_info", "void (__stdcall *) (int civ_id, int govt_id, int * out_cost_per_unit, int * out_count_free_units)" -define, 0x55D2A0, 0x569330, 0x55D250, "Leader_get_free_unit_count", "int (__fastcall *) (Leader * this, int edx, int govt_id)" -inlead, 0x55D030, 0x5690C0, 0x55CFE0, "Leader_count_maintenance_free_units", "int (__fastcall *) (Leader * this)" -define, 0x56D7D0, 0x57A1B0, 0x56D740, "get_tile_occupier_id", "int (__cdecl *) (int x, int y, int pov_civ_id, bool respect_unit_invisibility)" -repl call, 0x4585F4, 0x45A7A2, 0x458674, "get_tile_occupier_id_in_Unit_ai_move_naval_power_unit", "" -inlead, 0x4ED220, 0x4F6140, 0x4ED2E0, "Main_Screen_Form_show_map_message", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause)" -repl call, 0x4BE664, 0x4C5C66, 0x4BE6F4, "Main_Screen_Form_show_wltk_message", "" -repl call, 0x4BE71B, 0x4C5D1D, 0x4BE7AB, "Main_Screen_Form_show_wltk_ended_message", "" -define, 0xA52678, 0xA74E70, 0xA52638, "p_preferences", "unsigned *" -inlead, 0x4AFAB0, 0x4B6A70, 0x4AFB40, "City_set_production", "void (__fastcall *) (City * this, int edx, int order_type, int order_id, bool ask_to_confirm)" -define, 0x4B0AC0, 0x4B7A70, 0x4B0B50, "City_get_income_from_wealth_build", "int (__fastcall *) (City * this)" -define, 0x64C91E, 0x66AFD7, 0x64C85E, "print_int", "char * (__cdecl *) (int val, char * str, unsigned base)" -repl call, 0x5D759A, 0x5E69D2, 0x5D74CA, "Tile_has_city_for_agri_penalty_exception", "" -repl call, 0x564528, 0x570873, 0x5644D8, "show_popup_option_1_razes", "" -repl call, 0x4DA1E6, 0x4E2B96, 0x4DA2A6, "show_popup_option_2_razes", "" -define, 0x619E70, 0x63B090, 0x619DA0, "Context_Menu_add_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, char * text, bool checkbox, Sprite * image)" -repl call, 0x4E9808, 0x4F25EF, 0x4E98C8, "Context_Menu_add_abandon_city", "" -define, 0x60F6A0, 0x62B460, 0x60F5D0, "TextBuffer_check_ptr", "char * (__fastcall *) (TextBuffer * this, int edx, char * str)" -repl call, 0x4D5525, 0x4DDCF6, 0x4D55E5, "TextBuffer_check_pedia_upgrades_to_ptr_1", "" -repl call, 0x4D5676, 0x4DDE50, 0x4D5736, "TextBuffer_check_pedia_upgrades_to_ptr_2", "" -define, 0x5C68A0, 0x5D5700, 0x5C65B0, "Unit_try_flying_over_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y)" -inlead, 0x5C74A0, 0x5D6330, 0x5C71B0, "Unit_perform_air_recon", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -repl call, 0x5C6E34, 0x5D5CBB, 0x5C6B44, "Unit_get_interceptor_max_moves", "" -repl call, 0x5C7108, 0x5D5FAA, 0x5C6E18, "Unit_get_moves_after_interception", "" -repl call, 0x5C7114, 0x5D5FB6, 0x5C6E24, "Unit_set_state_after_interception", "" -inlead, 0x561220, 0x56D350, 0x5611D0, "Leader_begin_unit_turns", "void (__fastcall *) (Leader * this)" -define, 0x4A1FA0, 0x4A8BB0, 0x4A2030, "Fighter_find_defender_against_bombardment", "Unit * (__fastcall *) (Fighter * this, int edx, Unit * bombarder, int tile_x, int tile_y, int bombarder_civ_id, bool land_lethal, bool sea_lethal)" -repl call, 0x4A3ED9, 0x4AAB85, 0x4A3F69, "Fighter_find_actual_bombard_defender", "" -repl call, 0x4A2BAA, 0x4A97F6, 0x4A2C3A, "Fighter_find_actual_bombard_defender", "" -define, 0x4A7280, 0x4ADF40, 0x4A7310, "Fighter_eval_tile_vulnerability", "int (__fastcall *) (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y)" -repl call, 0x45861F, 0x45A7CD, 0x45869F, "Fighter_eval_tile_vulnerability_in_Unit_ai_move_naval_power_unit", "" -inlead, 0x5C6290, 0x5D50E0, 0x5C5FA0, "Unit_select", "void (__fastcall *) (Unit *this)" -inlead, 0x5B6820, 0x5C5180, 0x5B6530, "Unit_select_stealth_attack_target", "bool (__fastcall *) (Unit * this, int edx, int target_civ_id, int x, int y, bool allow_popup, Unit ** out_selected_target)" -repl call, 0x5C73FF, 0x5D629C, 0x5C710F, "Unit_try_flying_for_precision_strike", "" -define, 0x5C1210, 0x5CFDA0, 0x5C0F20, "Unit_play_bombard_fire_animation", "int (__fastcall *) (Unit * this, int edx, int x, int y)" -define, 0x5CA860, 0x5D97A0, 0x5CA570, "Unit_play_bombing_animation", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -repl call, 0x5C7429, 0x5D62BA, 0x5C7139, "Unit_play_bombing_anim_for_precision_strike", "" -repl call, 0x5C143D, 0x5CFFCD, 0x5C114D, "Unit_play_anim_for_bombard_tile", "" -repl call, 0x5B6A1B, 0x5C5368, 0x5B672B, "PopupSelection_add_stealth_attack_target", "" -inlead, 0x4D94F0, 0x4E1E80, 0x4D95B0, "Main_Screen_Form_issue_precision_strike_cmd", "void (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit)" -repl call, 0x4A3E92, 0x4AAB40, 0x4A3F22, "rand_bombard_target", "" -repl call, 0x5B6549, 0x5C4EA9, 0x5B6259, "Tile_check_water_for_stealth_attack", "" -inlead, 0x5B64C0, 0x5C4E20, 0x5B61D0, "Unit_can_stealth_attack", "bool (__fastcall *) (Unit * this, int edx, Unit * target)" -define, 0x61BCA0, 0x63D770, 0x61BBD0, "process_text_snippet", "int (__cdecl *) (char * in, char * out)" -repl call, 0x4D788A, 0x4E01EA, 0x4D794A, "process_text_for_map_message", "" -repl call, 0x5C6997, 0x5D5812, 0x5C66A7, "rand_int_to_dodge_city_aa", "" -repl call, 0x5C69A7, 0x5D5822, 0x5C66B7, "Unit_get_defense_to_dodge_city_aa", "" -repl call, 0x4A2179, 0x4A8D8A, 0x4A2209, "Unit_get_defense_to_find_bombard_defender", "" -define, 0x585B00, 0x592D50, 0x585860, "get_int_from_conquests_ini", "int (__cdecl *) (LPCSTR key, int param_2, int param_3)" -repl call, 0x59301E, 0x5A0756, 0x592D3E, "get_WindowsFileBox_from_ini", "" -define, 0x4A0670, 0x4A71F0, 0x4A0700, "open_load_game_file_picker", "char const * (__fastcall *) (void * this)" -repl call, 0x593054, 0x5A078A, 0x592D74, "do_open_load_game_file_picker", "" -inlead, 0x592D90, 0x5A0490, 0x592AB0, "do_load_game", "void * (__cdecl *) (char * param_1)" -define, 0x4F5EF0, 0x4FF290, 0x4F5FB0, "perform_interturn", "void (__cdecl *) ()" -repl call, 0x4F6759, 0x4FFB21, 0x4F6819, "perform_interturn_in_main_loop", "" -repl call, 0x4F59E6, 0x4FED88, 0x4F5AA6, "show_movement_phase_popup", "" -repl call, 0x5936F3, 0x5A0E8C, 0x593413, "show_intro_after_load_popup", "" -define, 0xA527B4, 0xA74FAC, 0xA52774, "p_is_pbem_game", "byte *" -define, 0xA52991, 0xA75189, 0xA52951, "p_is_offline_mp_game", "byte *" -inlead, 0x4A3A70, 0x4AA6F0, 0x4A3B00, "Fighter_do_bombard_tile", "void (__fastcall *) (Fighter * this, int edx, Unit * unit, int neighbor_index, int param_3, int param_4)" -define, 0x74AF60, 0x765300, 0x74AF20, "p_mp_object", "void *" -define, 0x4697B0, 0x46BF90, 0x469830, "mp_check_current_combat", "bool (__fastcall *) (void * this, int edx, int mp_tile_x, int mp_tile_y)" -define, 0x4A2650, 0x4A9290, 0x4A26E0, "Fighter_damage_city_by_bombardment", "bool (__fastcall *) (Fighter * this, int edx, Unit * unit, City * city, int damage_kind, int min_fire_rate)" -define, 0x426BD0, 0x428310, 0x426C50, "Map_in_range", "bool (__fastcall *) (Map * this, int edx, int x, int y)" -inlead, 0x4AE030, 0x4B5010, 0x4AE0C0, "City_can_trade_via_water", "bool (__fastcall *) (City * this)" -repl call, 0x4E67f4, 0x4EF255, 0x4E68B4, "City_shows_harbor_icon", "" -inlead, 0x4ADF90, 0x4B4F70, 0x4AE020, "City_can_trade_via_air", "bool (__fastcall *) (City * this)" -repl call, 0x4E6842, 0x4EF2A7, 0x4E6902, "City_shows_airport_icon", "" -define, 0x4B1F90, 0x4B8F10, 0x4B2020, "City_count_improvements_with_flag", "int (__fastcall *) (City * this, int edx, enum ImprovementTypeFlags flag)" -repl call, 0x4A12EC, 0x4A7E9C, 0x4A137C, "Unit_check_king_for_defense_priority", "" -repl call, 0x4A131A, 0x4A7ECA, 0x4A13AA, "Unit_check_king_for_defense_priority", "" -repl call, 0x4A133D, 0x4A7EED, 0x4A13CD, "Unit_check_king_for_defense_priority", "" -repl call, 0x4A144C, 0x4A7FFC, 0x4A14DC, "Unit_check_king_for_defense_priority", "" -repl call, 0x4A1477, 0x4A8027, 0x4A1507, "Unit_check_king_for_defense_priority", "" -repl call, 0x4A149F, 0x4A804F, 0x4A152F, "Unit_check_king_for_defense_priority", "" -repl call, 0x598EC5, 0x5A686D, 0x598BE5, "get_local_time_for_unit_ini", "" -repl call, 0x598AEC, 0x5A63F8, 0x59880C, "get_local_time_for_unit_ini", "" -define, 0x581330, 0x58E060, 0x581090, "Trade_Net_get_direction_from_internal_map", "int (__fastcall *) (Trade_Net * this, int edx, int x, int y, bool use_data_2_else_4)" -inlead, 0x50EC10, 0x518F00, 0x50ECB0, "DiploForm_assemble_tradable_items", "void (__fastcall *) (DiploForm * this)" -repl call, 0x50FAD9, 0x519D8B, 0x50FB79, "Leader_could_buy_tech_for_trade_screen", "" -repl call, 0x50FB9C, 0x519E42, 0x50FC3C, "Leader_could_buy_tech_for_trade_screen", "" -inlead, 0x4C10B0, 0x4C86A0, 0x4C1140, "City_get_building_defense_bonus", "int (__fastcall *) (City * this)" -define, 0x55A8D0, 0x5667E0, 0x55A880, "Leader_count_wonders_with_flag", "int (__fastcall *) (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city)" -repl vptr, 0x66DD04, 0x68ADE4, 0x66DD04, "Unit_eval_escort_requirement", "int (__fastcall *) (Unit * this)" -inlead, 0x561860, 0x56D9E0, 0x561810, "Leader_unlock_technology", "void (__fastcall *) (Leader * this, int edx, int tech_id, bool param_2, bool param_3, bool param_4)" -define, 0x55CF10, 0x568F90, 0x55CEC0, "Leader_recompute_buildings_maintenance", "void (__fastcall *) (Leader *this)" -define, 0x5683F7, 0x5747F2, 0x5683A7, "ADDR_UNLOCK_TECH_AT_INIT_1", "int" -define, 0x56847F, 0x57487A, 0x56842F, "ADDR_UNLOCK_TECH_AT_INIT_3", "int" -define, 0x5688DC, 0x574CD6, 0x56888C, "ADDR_UNLOCK_TECH_AT_INIT_2", "int" -define, 0x5621DE, 0x56E33D, 0x56217E, "ADDR_UNLOCK_TECH_RECURSE", "int" -repl call, 0x4212E7, 0x422847, 0x421367, "City_get_improv_maintenance_for_ui", "" -define, 0x563473, 0x56F723, 0x563423, "ADDR_CAPTURE_CITY_BARB_BRANCH", "byte *" -define, 0x56082B, 0x56C938, 0x5607DB, "ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP", "byte *" -define, 0x560838, 0x56C945, 0x5607E8, "ADDR_PROD_PHASE_BARB_DONE_JUMP", "byte *" -define, 0x426C00, 0x428340, 0x426C80, "Map_wrap_horiz", "int (__fastcall *) (Map * this, int edx, int x)" -define, 0x426C40, 0x428380, 0x426CC0, "Map_wrap_vert", "int (__fastcall *) (Map * this, int edx, int y)" -repl call, 0x44FEC3, 0x451F64, 0x44FF43, "neighbor_index_to_diff_for_barb_ai", "" -repl call, 0x44FEF0, 0x451F91, 0x44FF70, "Map_wrap_vert_for_barb_ai", "" -inlead, 0x5604B0, 0x56C5A0, 0x560460, "Leader_do_production_phase", "void (__fastcall *) (Leader * this)" -define, 0x5DF900, 0x5EF150, 0x5DF830, "count_set_bits", "int (__cdecl *) (unsigned int bit_field)" -repl call, 0x5604F8, 0x56C5E8, 0x5604A8, "count_player_bits_for_barb_prod", "" -repl call, 0x4C5208, 0x4CCAC6, 0x4C5228, "Map_get_tile_to_check_visibility", "" -repl vis, 0x4C5289, 0x4CCB4D, 0x4C52A9, "", "" -repl call, 0x4C5333, 0x4CCBEE, 0x4C5353, "Map_get_tile_to_check_visibility", "" -repl call, 0x4C35E4, 0x4CAE49, 0x4C3604, "Map_get_tile_to_check_visibility", "" -repl call, 0x4C3577, 0x4CADDC, 0x4C3597, "Map_get_tile_to_check_visibility", "" -repl call, 0x578A67, 0x585B87, 0x5789D7, "Map_get_tile_to_check_visibility", "" -repl call, 0x4C37E2, 0x4CB062, 0x4C3802, "Map_get_tile_to_check_visibility", "" -repl call, 0x4EDEF4, 0x4F6E44, 0x4EDFB4, "Map_get_tile_to_check_visibility", "" -repl vis, 0x4F0D82, 0x4F9ED2, 0x4F0E42, "", "" -repl call, 0x5AAA7A, 0x5B9196, 0x5AA78A, "Map_get_tile_to_check_visibility", "" -repl vis, 0x4EA2C3, 0x4F30B4, 0x4EA383, "", "" -repl vis, 0x4A1E90, 0x4A8A9E, 0x4A1F20, "", "" -repl call, 0x449941, 0x44B891, 0x4499C1, "Map_get_tile_to_check_visibility", "" -repl vis, 0x44997D, 0x44B8CF, 0x4499FD, "", "" -repl vis, 0x4EFC7A, 0x4F8C6B, 0x4EFD3A, "", "" -repl vis, 0x5B71B2, 0x5C5B43, 0x5B6EC2, "", "" -repl vis, 0x5B75EF, 0x5C5F53, 0x5B72FF, "", "" -repl vis, 0x5B7883, 0x5C6255, 0x5B7593, "", "" -repl vis, 0x5B7CC0, 0x5c66a9, 0x5B79D0, "", "" -repl vis, 0x5B808E, 0x5c6a80, 0x5B7D9E, "", "" -repl vis, 0x5B95A2, 0x5c802a, 0x5B92B2, "", "" -repl vis, 0x5BFD8A, 0x5ce91c, 0x5BFA9A, "", "" -repl vis, 0x5C4863, 0x5d351b, 0x5C4573, "", "" -repl vis, 0x5C4A3E, 0x5d3722, 0x5C474E, "", "" -repl vis, 0x5C4AD4, 0x5D37C3, 0x5C47E4, "", "" -repl vis, 0x5C4B90, 0x5D3884, 0x5C48A0, "", "" -repl vis, 0x5C4C41, 0x5D3925, 0x5C4951, "", "" -repl vis, 0x5C6A62, 0x5D58D9, 0x5C6772, "", "" -repl vis, 0x5C6F21, 0x5D5DA7, 0x5C6C31, "", "" -repl vis, 0x5C7F40, 0x5D6E00, 0x5C7C50, "", "" -repl vis, 0x5C8614, 0x5D7521, 0x5C8324, "", "" -repl vis, 0x5C8752, 0x5D7666, 0x5C8462, "", "" -repl vis, 0x5C8F8B, 0x5D7ECE, 0x5C8C9B, "", "" -repl vis, 0x5B9878, 0x5C8330, 0x5B9588, "", "" -repl vis, 0x5B992A, 0x5C83E2, 0x5B963A, "", "" -repl vis, 0x5B99E6, 0x5C84A7, 0x5B96F6, "", "" -repl vis, 0x5B9A97, 0x5C8559, 0x5B97A7, "", "" -repl vis, 0x5B9E54, 0x5C892B, 0x5B9B64, "", "" -repl vis, 0x57F4E4, 0x58C20D, 0x57F244, "", "" -repl vis, 0x57FC67, 0x58C8E4, 0x57F9C7, "", "" -repl call, 0x57F9B6, 0x58C62B, 0x57F716, "Map_get_tile_to_check_visibility", "" -repl call, 0x57F9F2, 0x58C667, 0x57F752, "Map_get_tile_to_check_visibility", "" -inlead, 0x4ED120, 0x4F6040, 0x4ED1E0, "Main_Screen_Form_is_unit_visible_to_player", "bool (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * unit)" -repl vptr, 0x670270, 0x68D31C, 0x670270, "Tile_m42_Get_Overlays", "unsigned (__fastcall *) (Tile * this, int edx, byte visible_to_civ)" -repl vptr, 0x6702E4, 0x68D390, 0x6702E4, "Tile_m71_Check_Worker_Job", "int (__fastcall *) (Tile * this)" -inlead, 0x5DBF10, 0x5EB460, 0x5DBE40, "Tile_get_road_bonus", "int (__fastcall *) (Tile * this)" -define, 0x5DBEC0, 0x5EB410, 0x5DBDF0, "Tile_get_mining_bonus", "int (__fastcall *) (Tile * this)" -define, 0x4EDF20, 0x4F6E70, 0x4EDFE0, "Unit_check_contact_bit_6", "bool (__fastcall *) (Unit * this, int edx, int civ_id)" -repl call, 0x4E8942, 0x4F15D0, 0x4E8A02, "Unit_check_contact_bit_6_on_right_click", "" -repl call, 0x4EA330, 0x4F3121, 0x4EA3F0, "Unit_check_contact_bit_6_on_right_click", "" -inlead, 0x4A8350, 0x4AF030, 0x4A83E0, "Leader_is_tile_visible", "bool (__fastcall *) (Leader * this, int edx, int x, int y)" -repl call, 0x4A784E, 0x4AE509, 0x4a78DE, "Tile_check_water_for_sea_zoc", "" -define, 0x4A79C2, 0x4AE66D, 0x4A7A52, "ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC", "byte *" -define, 0x4A7CAA, 0x4AE962, 0x4A7D3A, "ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC", "byte *" -repl call, 0x4A7BF2, 0x4AE8AA, 0x4A7C82, "Tile_check_water_for_land_zoc", "" -inlead, 0x5BE6E0, 0x5CD2C0, 0x5BE3F0, "Unit_get_attack_strength", "int (__fastcall *) (Unit * this)" -repl call, 0x4A79CA, 0x4AE675, 0x4A7A5A, "Unit_get_attack_strength_for_sea_zoc", "" -repl call, 0x4A7B15, 0x4AE7BE, 0x4A7BA5, "Unit_get_attack_strength_for_sea_zoc", "" -repl call, 0x4A7B20, 0x4AE7C9, 0x4A7BB0, "Unit_get_attack_strength_for_sea_zoc", "" -repl call, 0x4A7CB2, 0x4AE96A, 0x4A7D42, "Unit_get_attack_strength_for_land_zoc", "" -repl call, 0x4A7DFD, 0x4AEAB3, 0x4A7E8D, "Unit_get_attack_strength_for_land_zoc", "" -repl call, 0x4A7E08, 0x4AEABE, 0x4A7E98, "Unit_get_attack_strength_for_land_zoc", "" -inlead, 0x4E3E90, 0x4EC6E0, 0x4E3F50, "Main_Screen_Form_find_visible_unit", "Unit * (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * excluded)" -define, 0x4F00F0, 0x4F9100, 0x4F01B0, "Animator_play_one_shot_unit_animation", "void (__fastcall *) (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3)" -repl call, 0x4A81A4, 0x4AEE83, 0x4A8234, "Animator_play_zoc_animation", "" -repl call, 0x4A81E2, 0x4AEEC1, 0x4A8272, "Animator_play_zoc_animation", "" -inlead, 0x4A76B0, 0x4AE370, 0x4A7740, "Fighter_apply_zone_of_control", "void (__fastcall *) (Fighter * this, int edx, Unit * unit, int from_x, int from_y, int to_x, int to_y)" -define, 0x4A1CD0, 0x4A88E0, 0x4A1D60, "Fighter_check_combat_anim_visibility", "bool (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender, bool param_3)" -repl call, 0x4A7F71, 0x4AEC36, 0x4A8001, "Fighter_check_zoc_anim_visibility", "" -define, 0x4A7F61, 0x4AEC26, 0x4A7FF1, "ADDR_ZOC_CHECK_ATTACKER_ANIM_FIELD_111", "byte *" -define, 0x4A770A, 0x4AE3CA, 0x4A779A, "ADDR_SKIP_ZOC_FOR_ONE_HP_LAND_UNIT", "byte *" -define, 0x4A7745, 0x4AE405, 0x4A77D5, "ADDR_SKIP_ZOC_FOR_ONE_HP_SEA_UNIT", "byte *" -inlead, 0x5B8FC0, 0x5C7A40, 0x5B8CD0, "Unit_move_to_adjacent_tile", "int (__fastcall *) (Unit * this, int edx, int neighbor_index, bool param_2, int param_3, byte param_4)" -repl call, 0x5B91B4, 0x5C7C32, 0x5B8EC4, "Tile_check_water_for_canal_move_to_adjacent_tile_dest", "" -repl call, 0x5B945B, 0x5C7EDE, 0x5B916B, "Trade_Net_get_move_cost_after_zoc", "" -repl call, 0x5B9471, 0x5C7EF4, 0x5B9181, "Unit_can_move_after_zoc", "" -repl call, 0x5B94E4, 0x5C7F67, 0x5B91F4, "Unit_get_max_move_points_for_bridge_exit", "" -repl vptr, 0x66DD40, 0x68AE20, 0x66DD40, "Unit_teleport", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad)" -define, 0x5BEF00, 0x5CDB10, 0x5BEC10, "Unit_score_kill", "void (__fastcall *) (Unit * this, int edx, Unit * victim, bool was_attacking)" -define, 0x5BF558, 0x5CE0EA, 0x5BF268, "ADDR_EXISTING_BATTLE_CREATED_UNIT_CHECK", "void *" -inlead, 0x4A1AE0, 0x4A86E0, 0x4A1B70, "Fighter_find_defensive_bombarder", "Unit * (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender)" -define, 0x5BCA90, 0x5CB620, 0x5BC7A0, "Unit_get_containing_army", "Unit * (__fastcall *) (Unit * this)" -define, 0x4A0ED0, 0x4A7A90, 0x4A0F60, "Fighter_get_combat_odds", "int (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses)" -repl call, 0x4A5AF9, 0x4AC799, 0x4A5B89, "Fighter_get_odds_for_main_combat_loop", "" -define, 0x4A3280, 0x4A9ED0, 0x4A3310, "Fighter_damage_by_defensive_bombard", "void (__fastcall *) (Fighter * this, int edx, Unit * bombarder, Unit * defender)" -repl call, 0x4A57C5, 0x4AC477, 0x4A5855, "Fighter_damage_by_db_in_main_loop", "" -inlead, 0x4A53A0, 0x4AC060, 0x4A5430, "Fighter_fight", "byte (__fastcall *) (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender_or_null)" -repl call, 0x4A6EB7, 0x4ADB60, 0x4A6F47, "Unit_score_kill_by_defender", "" -define, 0x5C8180, 0x5D7060, 0x5C7E90, "Unit_play_attack_animation", "void (__fastcall *) (Unit * this, int edx, int direction)" -repl call, 0x4A5791, 0x4AC443, 0x4A5821, "Unit_play_attack_anim_for_def_bombard", "" -define, 0x578780, 0x5858A0, 0x5786F0, "Navigator_Data_reset", "void (__fastcall *) (Navigator_Data * this)" -inlead, 0x536080, 0x540670, 0x536100, "initialize_map_music", "void (__cdecl *) (int civ_id, int era_id, bool param_3)" -inlead, 0x535FB0, 0x5405A0, 0x536030, "deinitialize_map_music", "void (__stdcall *) ()" -inlead, 0x5C7350, 0x5D61F0, 0x5C7060, "Unit_do_precision_strike", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -define, 0x5B5790, 0x5C40E0, 0x5B54A0, "Unit_confirm_war", "bool (__fastcall *) (Unit * this, int edx, int against_civ_id, bool allow_map_message)" -inlead, 0x5C37B0, 0x5D23F0, 0x5C34C0, "Unit_check_precision_strike_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5B5280, 0x5C3BF0, 0x5B4F90, "Unit_attack_tile", "void (__fastcall *) (Unit * this, int edx, int x, int y, int bombarding)" -repl call, 0x5C33F6, 0x5D2026, 0x5C3106, "Map_get_tile_to_check_visibility", "" -repl call, 0x52C39A, 0x5367DC, 0x52C42A, "Map_get_tile_to_check_visibility", "" -repl call, 0x52C146, 0x536586, 0x52C1D6, "Map_get_tile_to_check_visibility", "" -repl call, 0x52BED0, 0x536310, 0x52BF60, "Map_get_tile_to_check_visibility", "" -repl call, 0x5B555E, 0x5C3EBF, 0x5B526E, "Unit_get_max_moves_after_barricade_attack", "" -define, 0x56D2C0, 0x579C40, 0x56D230, "city_at", "City * (__cdecl *) (int x, int y)" -repl call, 0x4A2018, 0x4A8C28, 0x4A20A8, "city_at_in_find_bombard_defender", "" -inlead, 0x5C3510, 0x5D2140, 0x5C3220, "Unit_check_bombard_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C5160, 0x5D3E40, 0x5C4E70, "Unit_can_disembark_anything", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -repl call, 0x52C912, 0x536D92, 0x52C9A2, "Unit_get_defense_for_bombardable_unit_check", "" -repl call, 0x57F627, 0x58C356, 0x57F387, "get_tile_occupier_for_ai_path", "" -repl call, 0x56D9D1, 0x57A3C2, 0x56D941, "Unit_is_tile_occupier_visible", "" -repl vptr, 0x66BF68, 0x68905C, 0x66BF68, "Demographics_Form_m22_draw", "void (__fastcall *) (Demographics_Form * this)" -define, 0x600070, 0x615570, 0x5FFF50, "PCX_Image_fill_area", "int (__fastcall *) (PCX_Image * this, int edx, RECT * rect, int color)" -define, 0x5FD360, 0x611290, 0x5FD240, "PCX_Image_set_text_effects", "void (__fastcall *) (PCX_Image * this, int edx, int text_color, int shadow_color, int shadow_offset_x, int shadow_offset_y)" -inlead, 0x5676C0, 0x573AB0, 0x567670, "Leader_get_optimal_city_number", "int (__fastcall *) (Leader * this)" -inlead, 0x55AA10, 0x566930, 0x55A9C0, "Leader_count_wonders_with_small_flag", "int (__fastcall *) (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null)" -repl call, 0x567706, 0x573AF6, 0x5676B6, "Leader_count_forbidden_palaces_for_ocn", "" -repl call, 0x550F99, 0x55C0E1, 0x550F49, "Unit_can_do_worker_command_for_button_setup", "" -repl call, 0x55132D, 0x55C484, 0x5512DD, "Unit_can_do_worker_command_for_button_setup", "" -define, 0x55B1A0, 0x567100, 0x55B150, "Leader_reveal_tile", "void (__fastcall *) (Leader * this, int edx, int x, int y)" -define, 0x5FCB10, 0x610790, 0x5FC9F0, "PCX_Image_draw_onto", "int (__fastcall *) (PCX_Image * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y)" -define, 0x5DBF60, 0x5EB4B0, 0x5DBE90, "Tile_get_terrain_move_cost", "int (__fastcall *) (Tile * this)" -define, 0x56D340, 0x579CC0, 0x56D2B0, "get_combat_occupier", "int (__cdecl *) (int tile_x, int tile_y, int civ_id, byte ignore_visibility)" -repl call, 0x45871C, 0x45A8C9, 0x45879C, "get_combat_occupier_in_Unit_ai_move_naval_power_unit", "" -define, 0x561480, 0x56D5E0, 0x561430, "Leader_has_tech_with_flag", "bool (__fastcall *) (Leader * this, int edx, enum AdvanceTypeFlags flag)" -inlead, 0x57D980, 0x58A680, 0x57D6E0, "Trade_Net_recompute_city_connections", "void (__fastcall *) (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id)" -inlead, 0x62B1A0, 0x64E220, 0x6274B0, "OpenGLRenderer_initialize", "int (__fastcall *) (OpenGLRenderer * this, int edx, PCX_Image * texture)" -inlead, 0x62B450, 0x64E510, 0x627760, "OpenGLRenderer_draw_line", "void (__fastcall *) (OpenGLRenderer * this, int edx, int x1, int y1, int x2, int y2)" -inlead, 0x62B490, 0x64E560, 0x6277A0, "OpenGLRenderer_set_color", "void (__fastcall *) (OpenGLRenderer * this, int edx, unsigned int rgb555)" -inlead, 0x62B570, 0x64E600, 0x627880, "OpenGLRenderer_set_opacity", "void (__fastcall *) (OpenGLRenderer * this, int edx, unsigned int alpha)" -inlead, 0x62B5B0, 0x64E660, 0x6278C0, "OpenGLRenderer_set_line_width", "void (__fastcall *) (OpenGLRenderer * this, int edx, int width)" -inlead, 0x62B5D0, 0x64E690, 0x6278E0, "OpenGLRenderer_enable_line_dashing", "void (__fastcall *) (OpenGLRenderer * this)" -inlead, 0x62B5F0, 0x64E6C0, 0x627900, "OpenGLRenderer_disable_line_dashing", "void (__fastcall *) (OpenGLRenderer * this)" -repl call, 0x5BFBFF, 0x5CE79A, 0x5BF90F, "Tile_check_water_for_retreat_on_defense", "bool (__fastcall *) (Tile * this)" -inlead, 0x5D2150, 0x5E13F0, 0x5D2080, "Map_build_trade_network", "void (__fastcall *) (Map * this)" -inlead, 0x57DE90, 0x58ABD0, 0x57DBF0, "Trade_Net_recompute_city_cons_and_res", "void (__fastcall *) (Trade_Net * this, int edx, bool param_1)" -repl call, 0x57DAF1, 0x58A7F9, 0x57D851, "Trade_Net_set_unit_path_to_fill_road_net", "" -repl call, 0x57DE29, 0x58AB4E, 0x57DB89, "Trade_Net_set_unit_path_to_find_sea_route", "" -define, 0x5EA6E0, 0x5F9F30, 0x5EA610, "Tile_has_colony", "bool (__fastcall *) (Tile * this)" -repl call, 0x5C1559, 0x5D00ED, 0x5C1269, "City_count_airports_for_airdrop", "" -define, 0x437CF0, 0x4398A0, 0x437D70, "Leader_get_city_count_on_continent", "int (__fastcall *) (Leader * this, int edx, int cont_id)" -repl call, 0x42EB3F, 0x430615, 0x42EBBF, "Leader_get_cont_city_count_for_worker_req", "" -repl call, 0x42EBCA, 0x430698, 0x42EC4A, "Leader_get_cont_city_count_for_worker_req", "" -repl call, 0x42EAD2, 0x4305AE, 0x42EB52, "Leader_get_city_count_for_worker_prod_cap", "" -inlead, 0x55D310, 0x5693A0, 0x55D2C0, "Leader_sum_unit_maintenance", "int (__fastcall *) (Leader * this, int edx, int government_id)" -define, 0xA52684, 0xA74E7C, 0xA52644, "p_game_difficulty", "int *" -define, 0x5CD960, 0x5DC940, 0x5CD880, "Unit_is_terrain_impassable", "bool (__fastcall *) (Unit * this, int edx, int terrain_type_index)" -define, 0x41CD22, 0x41E04C, 0x41CDA2, "ADDR_LUXURY_BOX_ROW_HEIGHT", "byte *" -define, 0x30, 0x38, 0x30, "LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET", "int" -define, 0x740A00, 0x75ADA0, 0x7409C0, "p_city_form", "City_Form *" -inlead, 0x5F82E0, 0x6087E0, 0x5F8210, "Sprite_draw", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table)" -repl call, 0x421295, 0x4227F5, 0x421315, "Sprite_draw_improv_img_on_city_form", "" -inlead, 0x421240, 0x4227A0, 0x4212C0, "draw_improv_icons_on_city_screen", "void (__cdecl *) (Base_List_Control * control, int improv_id, int item_index, int offset_x, int offset_y)" -define, 0x4B0710, 0x4B76C0, 0x4B07A0, "City_get_tourism_amount", "int (__fastcall *) (City * this, int edx, int improv_id)" -repl call, 0x42138C, 0x4228EC, 0x42140C, "City_get_tourism_amount_to_draw", "" -repl call, 0x4213FF, 0x42295F, 0x42147F, "Sprite_draw_tourism_gold", "" -repl call, 0x4BA075, 0x4C16E5, 0x4BA105, "City_calc_tile_yield_while_gathering", "" -repl call, 0x4B0512, 0x4B74D2, 0x4B05A2, "City_calc_tile_yield_while_gathering", "" -repl call, 0x4ADA3F, 0x4B4A28, 0x4ADACF, "City_calc_tile_yield_while_gathering", "" -repl call, 0x4B0F04, 0x4B7EB4, 0x4B0F94, "City_calc_tile_yield_while_gathering", "" -repl call, 0x4B25EF, 0x4B9576, 0x4B267F, "City_calc_tile_yield_while_gathering", "" -repl call, 0x4BA645, 0x4C1CA4, 0x4BA6D5, "City_calc_tile_yield_while_gathering", "" -inlead, 0x4B0E80, 0x4B7E30, 0x4B0F10, "City_recompute_yields_and_happiness", "void (__fastcall *) (City * this)" -inlead, 0x55EC80, 0x56AD30, 0x55EC30, "Leader_record_export", "bool (__fastcall *) (Leader * this, int edx, int importer_civ_id, int resource_id)" -inlead, 0x55ED60, 0x56AE10, 0x55ED10, "Leader_erase_export", "bool (__fastcall *) (Leader * this, int edx, int importer_civ_id, int resource_id)" -inlead, 0x4216A0, 0x422BF0, 0x421720, "City_Form_open", "void (__fastcall *) (City_Form * this, int edx, City * city, int param_2)" -define, 0x4B0330, 0x4B72F0, 0x4B03C0, "City_calc_tile_yield_at", "int (__fastcall *) (City * this, int edx, int yield_type, int tile_x, int tile_y)" -repl vptr, 0x66dd10, 0x68adf0, 0x66dd10, "Unit_has_enough_escorters_present", "bool (__fastcall *) (Unit * this)" -repl vptr, 0x66dd14, 0x68adf4, 0x66dd14, "Unit_check_escorter_health", "void (__fastcall *) (Unit * this, int edx, bool * has_any_escort_present, bool * any_escorter_cant_heal)" -inlead, 0x5694D0, 0x575900, 0x569480, "Leader_spawn_unit", "Unit * (__fastcall *) (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id)" -repl call, 0x5B7BA8, 0x5C69B8, 0x5B78B8, "Leader_spawn_captured_unit", "" -repl call, 0x5B7FCA, 0x5C657E, 0x5B7CDA, "Leader_spawn_captured_unit", "" -repl call, 0x5B74D8, 0x5C5E41, 0x5B71E8, "Leader_spawn_captured_unit", "" -inlead, 0x55E190, 0x56A220, 0x55E140, "Leader_enter_new_era", "void (__fastcall *) (Leader * this, int edx, bool param_1, bool no_online_sync)" -define, 0x55A270, 0x566180, 0x55A220, "Leader_get_name", "char * (__fastcall *) (Leader * this)" -define, 0x55A370, 0x566280, 0x55A320, "Leader_get_gender", "int (__fastcall *) (Leader * this)" -define, 0x55A210, 0x566120, 0x55A1C0, "Leader_get_civ_adjective", "char * (__fastcall *) (Leader * this)" -define, 0x55A240, 0x566150, 0x55A1F0, "Leader_get_civ_noun", "char * (__fastcall *) (Leader * this)" -define, 0x55A340, 0x566250, 0x55A2F0, "Leader_get_civ_formal_name", "char * (__fastcall *) (Leader * this)" -define, 0x55A2C0, 0x5661D0, 0x55A270, "Leader_get_title", "char * (__fastcall *) (Leader * this)" -repl call, 0x593614, 0x5A0DAE, 0x593334, "Leader_get_player_title_for_intro_popup", "" -inlead, 0x4A8240, 0x4AEF20, 0x4A82D0, "Fighter_animate_start_of_combat", "void (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender)" -define, 0x61A2E0, 0x63B710, 0x61A210, "Context_Menu_disable_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id)" -define, 0x61A380, 0x63B7E0, 0x61A2B0, "Context_Menu_put_image_on_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, Sprite * image)" -inlead, 0x4B8BA0, 0x4C0210, 0x4B8C30, "City_spawn_unit_if_done", "void (__fastcall *) (City * this)" -inlead, 0x5C0620, 0x5CF1C0, 0x5C0330, "Unit_can_upgrade", "bool (__fastcall *) (Unit * this)" -define, 0x4C0690, 0x4C7C50, 0x4C0720, "City_get_upgraded_type_id", "int (__fastcall *) (City * this, int edx, int unit_type_id)" -inlead, 0x56AAE0, 0x576F90, 0x56AA90, "Leader_upgrade_all_units", "void (__fastcall *) (Leader * this, int edx, int type_id)" -inlead, 0x4DE8B0, 0x4E7290, 0x4DE970, "Main_Screen_Form_upgrade_all_units", "void (__fastcall *) (Main_Screen_Form * this, int edx, int type_id)" -repl call, 0x56AB65, 0x577017, 0x56AB15, "Unit_can_perform_upgrade_all", "" -repl call, 0x4DE93C, 0x4E7316, 0x4DE9FC, "Unit_can_perform_upgrade_all", "" -repl call, 0x4BE89A, 0x4C5E80, 0x4BE92A, "Leader_spawn_unit_from_building", "" -repl call, 0x5C0727, 0x5CF2C7, 0x5C0437, "City_count_improvs_enabling_upgrade", "" -repl call, 0x5C0700, 0x5CF2A0, 0x5C0410, "City_count_improvs_enabling_upgrade", "" -repl call, 0x5C0715, 0x5CF2B5, 0x5C0425, "City_count_improvs_enabling_upgrade", "" -inlead, 0x4AECC0, 0x4B5C80, 0x4AED50, "City_raze", "void (__fastcall *) (City * this, int edx, int civ_id_responsible, bool checking_elimination)" -define, 0x563410, 0x56F6C0, 0x5633C0, "Leader_capture_city", "bool (__fastcall *) (Leader * this, int edx, City * city, Unit * unit, bool involuntary, bool converted)" -repl call, 0x55BA76, 0x567D20, 0x55BA26, "Leader_create_city_from_hut", "" -repl call, 0x568F57, 0x57538A, 0x568F07, "Leader_create_city_for_ai_respawn", "" -repl call, 0x5B35D3, 0x5C1F22, 0x5B32E3, "Leader_create_city_for_founding", "" -repl call, 0x5D2B8F, 0x5E1E68, 0x5D2ABF, "Leader_create_city_for_scenario", "" -inlead, 0x564800, 0x570BB0, 0x5647B0, "Leader_do_capture_city", "bool (__fastcall *) (Leader * this, int edx, City * city, bool involuntary, bool converted)" -define, 0x4BB410, 0x4C2A60, 0x4BB4A0, "City_count_citizens_of_race", "int (__fastcall *) (City * this, int edx, int race_id)" -define, 0x5A6060, 0x5B4350, 0x5A5D60, "count_units_at", "int (__cdecl *) (int x, int y, enum unit_filter filter, int arg_a, int arg_b, int arg_c)" -inlead, 0x4B9C60, 0x4C12E0, 0x4B9CF0, "City_draw_hud_icon", "void (__fastcall *) (City * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y)" -inlead, 0x4B9BB0, 0x4C1230, 0x4B9C40, "City_has_hud_icon", "bool (__fastcall *) (City * this)" -inlead, 0x4BFBF0, 0x4C71B0, 0x4BFC80, "City_draw_on_map", "void (__fastcall *) (City * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7)" -inlead, 0x4E7E30, 0x4F08F0, 0x4E7EF0, "MenuUnitItem_write_text_to_temp_str", "void (__fastcall *) (MenuUnitItem * this)" -define, 0xCAB2D8, 0xCCDB88, 0xCAB298, "temp_str", "char[4096]" -repl call, 0x5EDD89, 0x5FD7BE, 0x5EDCB9, "Tile_m74_Set_Square_Type_for_hill_gen", "" -inlead, 0x5D1EA0, 0x5E1140, 0x5D1DD0, "Map_place_scenario_things", "void (__fastcall *) (Map * this)" -repl vptr, 0x66C3EC, 0x6894D8, 0x66C3EC, "Advisor_Base_Form_domestic_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -repl vptr, 0x66F8CC, 0x68C988, 0x66F8CC, "Advisor_Base_Form_trade_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -repl vptr, 0x66E0CC, 0x68B1B8, 0x66E0CC, "Advisor_Base_Form_military_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -repl vptr, 0x66CAAC, 0x689B9C, 0x66CAAC, "Advisor_Base_Form_foreign_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -repl vptr, 0x66BD3C, 0x688E34, 0x66BD3C, "Advisor_Base_Form_cultural_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -repl vptr, 0x66F59C, 0x68C658, 0x66F59C, "Advisor_Base_Form_science_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" -inlead, 0x4E79B0, 0x4F0470, 0x4E7A70, "Main_Screen_Form_open_quick_build_chooser", "void (__fastcall *) (Main_Screen_Form * this, int edx, City * city, int mouse_x, int mouse_y)" -repl call, 0x4E9941, 0x4F273F, 0x4E9A01, "Context_Menu_get_selected_item_on_unit_rcm", "int (__fastcall *) (Context_Menu * this)" -define, 256, 257, 256, "LBL_WAKE", "int" -define, 255, 256, 255, "LBL_ACTIVATE", "int" -define, 0x4C1280, 0x4C8860, 0x4C1310, "City_sum_buildings_naval_power", "int (__fastcall *) (City * this)" -repl call, 0x4A78EE, 0x4AE5A5, 0x4A797E, "City_sum_buildings_naval_power_for_zoc", "" -define, 0x5BE9E0, 0x5CD600, 0x5BE6F0, "Unit_count_contained_units", "int (__fastcall *) (Unit * this)" -repl call, 0x4B3089, 0x4BA00B, 0x4B3119, "Tile_check_water_to_block_pollution", "" -repl call, 0x4F416E, 0x4FD448, 0x4F422E, "Tile_set_flag_for_eruption_damage", "" -inlead, 0x4AF5D0, 0x4B6590, 0x4AF660, "City_confirm_production_switch", "bool (__fastcall *) (City * this, int edx, int order_type, int order_id)" -define, 0x62AEE0, 0x64DE20, 0x6271F0, "MappedFile_open", "void * (__fastcall *) (MappedFile * this, int edx, char * file_name, int sequential_access)" -repl call, 0x592160, 0x59F790, 0x591E80, "MappedFile_open_to_load_game", "" -define, 0x62AFA0, 0x64DF40, 0x6272B0, "MappedFile_create_file", "void * (__fastcall *) (MappedFile * this, int edx, LPCSTR file_path, unsigned file_size, int is_shared)" -repl call, 0x591CF1, 0x59F321, 0x591A11, "MappedFile_create_file_to_save_game", "" -define, 0x62B0C0, 0x64E0B0, 0x6273D0, "MappedFile_deinit", "void (__fastcall *) (MappedFile * this)" -repl call, 0x592322, 0x59F973, 0x592042, "MappedFile_deinit_after_saving_or_loading", "" -repl call, 0x591D9F, 0x59F3D0, 0x591ABF, "MappedFile_deinit_after_saving_or_loading", "" -repl vptr, 0x6701E4, 0x68D290, 0x6701E4, "Tile_m7_Check_Barbarian_Camp", "bool (__fastcall *) (Tile * this, int edx, int visible_to_civ)" -define, 0x44FBA5, 0x451C45, 0x44FC25, "ADDR_CHECK_BARB_CAMP_TO_DEFEND_RETURN", "int" -inlead, 0x590030, 0x59D690, 0x58FD50, "move_game_data", "int (__cdecl *) (byte * buffer, bool save_else_load)" -inlead, 0x5C14B0, 0x5D0040, 0x5C11C0, "Unit_can_airdrop", "bool (__fastcall *) (Unit * this)" -inlead, 0x5DF8D0, 0x5EF120, 0x5DF800, "City_Improvements_contains", "bool (__fastcall *) (City_Improvements * this, int edx, int id)" -inlead, 0x5DF890, 0x5EF0E0, 0x5DF7C0, "City_Improvements_set", "void (__fastcall *) (City_Improvements * this, int edx, int id, bool add_else_remove)" -repl call, 0x4B47C9, 0x4BB7B9, 0x4B4859, "Leader_has_tech_to_stop_disease", "" -define, 0x5D59E0, 0x5E4E20, 0x5D5910, "Map_change_tile_terrain", "void (__fastcall *) (Map * this, int edx, enum SquareTypes new_terrain_type, int x, int y)" -repl call, 0x461833, 0x463CAF, 0x4618B3, "Map_change_tile_terrain_by_worker", "" -inlead, 0x461470, 0x4638C0, 0x4614F0, "Unit_work_simple_job", "void (__fastcall *) (Unit * this, int edx, int job_id)" -define, 0x5C8B30, 0x5D7A50, 0x5C8840, "Unit_animate_cruise_missile_strike", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -repl call, 0x5B550E, 0x5C3E6F, 0x5B521E, "Unit_play_attack_animation_vs_tile", "" -repl call, 0x5B4C0E, 0x5C355E, 0x5B491E, "Map_compute_neighbor_index_for_cm_strike", "" -define, 0x5FF0E0, 0x614190, 0x5FEFC0, "PCX_Image_do_draw_centered_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len)" -repl call, 0x41AF59, 0x41C067, 0x41AFD9, "PCX_Image_do_draw_cntd_text_for_strat_res", "" -repl call, 0x41AE9F, 0x41BFA9, 0x41AF1F, "Sprite_draw_strat_res_on_city_screen", "" -define, 0x41AE1B, 0x41BF23, 0x41AE9B, "ADDR_MOST_STRAT_RES_ON_CITY_SCREEN", "void *" -inlead, 0x5BEB60, 0x5CD780, 0x5BE870, "Unit_can_heal_at", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5BECE0, 0x5CD900, 0x5BE9F0, "Unit_heal_at_start_of_turn", "void (__fastcall *) (Unit * this)" -define, 0x469590, 0x46BD40, 0x469610, "check_online_skip_flag", "bool (__stdcall *) (int unit_id)" -inlead, 0x448BF0, 0x44AB10, 0x448C70, "Leader_ai_eval_technology", "int (__fastcall *) (Leader * this, int edx, int id, bool param_2, bool param_3)" -inlead, 0x4446C0, 0x4464C0, 0x444740, "Leader_ai_eval_government", "int (__fastcall *) (Leader * this, int edx, int id)" -define, 0x474140, 0x476F70, 0x4741C0, "mp_despawn", "void (__fastcall *) (void * this, int edx, int unit_id, int civ_id_responsible, byte param_3, byte param_4, byte param_5, byte param_6)" -repl call, 0x5B483F, 0x5C3199, 0x5B454F, "Unit_despawn_after_killed_by_nuke", "" -repl call, 0x5B4374, 0x5C2CC4, 0x5B4084, "Unit_despawn_after_killed_by_nuke", "" -repl call, 0x5B4832, 0x5C318C, 0x5B4542, "mp_despawn_after_killed_by_nuke", "" -repl call, 0x5B4367, 0x5C2CB7, 0x5B4077, "mp_despawn_after_killed_by_nuke", "" -define, 0x4B3290, 0x4BA210, 0x4B3320, "City_has_unprotected_improv", "bool (__fastcall *) (City * this, int edx, int id)" -repl call, 0x422BE5, 0x4241A5, 0x422C65, "City_has_unprotected_improv_to_sell", "" -repl call, 0x5BB966, 0x5CA4B6, 0x5BB676, "UnitType_has_detector_ability_for_vis_check", "" -repl call, 0x5BB938, 0x5CA47F, 0x5BB648, "UnitType_has_detector_ability_for_vis_check", "" -repl call, 0x0FF, 0x5CA49B, 0x0FF, "UnitType_has_detector_ability_for_vis_check", "" -inlead, 0x5C33A0, 0x5D1FD0, 0x5C30B0, "Unit_check_airdrop_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C3C80, 0x5D28B0, 0x5C3990, "Unit_find_telepad_on_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y, bool show_selection_popup, Unit ** out_unit_telepad)" -inlead, 0x44B870, 0x44D840, 0x44B8F0, "Unit_ai_eval_airdrop_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C3460, 0x5D2090, 0x5C3170, "Unit_check_airlift_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C4F60, 0x5D3C40, 0x5C4C70, "Unit_can_airlift", "bool (__fastcall *) (Unit * this)" -inlead, 0x5C5040, 0x5D3D20, 0x5C4D50, "Unit_airlift", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -repl call, 0x450C9C, 0x452D98, 0x450D1C, "City_count_airports_for_ai_airlift_target", "" -repl call, 0x452A3A, 0x454B5F, 0x452ABA, "City_count_airports_for_ai_airlift_target", "" -inlead, 0x44F040, 0x4510E0, 0x44F0C0, "Unit_ai_go_to_capital", "bool (__fastcall *) (Unit * this)" -inlead, 0x5C3900, 0x5D2540, 0x5C3610, "Unit_check_rebase_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x5C3860, 0x5D24A0, 0x5C3570, "Unit_is_in_rebase_range", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -define, 0x5C71C0, 0x5D6060, 0x5C6ED0, "Unit_rebase", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -define, 0x5E6D20, 0x5F6580, 0x5E6C50, "diff_to_neighbor_index", "int (__cdecl *) (int dx, int dy, int lim)" -repl call, 0x421060, 0x4225BA, 0x4210E0, "Map_compute_ni_for_work_area", "" -repl vptr, 0x670190, 0x68D240, 0x670190, "Map_m28_find_cnter_neigh_point_for_work_area", "int (__fastcall *) (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim)" -define, 0x4C538E, 0x4CCC47, 0x4C53AE, "ADDR_FIND_CENTER_NP_SPOTLIGHT_RET", "int" -define, 0x4DF9E0, 0x4E8390, 0x4DFAA0, "Main_Screen_Form_bring_tile_into_view", "void (__fastcall *) (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5)" -repl call, 0x421853, 0x422DC1, 0x4218D3, "Main_Screen_Form_bring_cnter_view_city_focus", "" -repl call, 0x41BBB1, 0x41CD89, 0x41BC31, "Main_Screen_Form_bring_cnter_view_city_arrow", "" -repl call, 0x41BDB5, 0x41CFCD, 0x41BE35, "Main_Screen_Form_bring_cnter_view_city_arrow", "" -define, 0x4BBC80, 0x4C32D0, 0x4BBD10, "City_stop_working_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" -define, 0x4BB6F0, 0x4C2D50, 0x4BB780, "City_start_working_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" -repl call, 0x4ADA69, 0x4B4A51, 0x4ADAF9, "ni_to_diff_for_work_area", "" -repl call, 0x4ADAF4, 0x4B4AD8, 0x4ADB84, "ni_to_diff_for_work_area", "" -ext walup, 0x4ADB6F, 0x4B4B53, 0x4ADBFF, "", "" -repl call, 0x4AE49F, 0x4B5485, 0x4AE52F, "ni_to_diff_for_work_area", "" -ext walup, 0x4AE525, 0x4B550B, 0x4AE5B5, "", "" -repl call, 0x4AE7C2, 0x4B57A1, 0x4AE852, "ni_to_diff_for_work_area", "" -define, 0x4B0470, 0x4B7430, 0x4B0500, "City_add_or_remove_tile_yield", "void (__fastcall *) (City * this, int edx, int neighbor_index, bool add_else_remove)" -repl call, 0x4AE831, 0x4B5806, 0x4AE8C1, "City_add_or_remove_tile_yield_conv_ni", "" -ext walup, 0x4AE842, 0x4B580F, 0x4AE8D2, "", "" -repl call, 0x4AEF35, 0x4B5F13, 0x4AEFC5, "ni_to_diff_for_work_area", "" -repl call, 0x4AEFAF, 0x4B5F83, 0x4AF03F, "ni_to_diff_for_work_area", "" -ext walup, 0x4AF034, 0x4B5FFF, 0x4AF0C4, "", "" -ext walup, 0x4AF0CE, 0x4B6099, 0x4AF15E, "", "" -repl call, 0x4AF355, 0x4B631E, 0x4AF3E5, "ni_to_diff_for_work_area", "" -ext walup, 0x4AF3D7, 0x4B63A0, 0x4AF467, "", "" -repl call, 0x4AF4F6, 0x4B64B9, 0x4AF586, "ni_to_diff_for_work_area", "" -ext walup, 0x4AF5A6, 0x4B656B, 0x4AF636, "", "" -repl call, 0x4B0F2D, 0x4B7EDD, 0x4B0FBD, "ni_to_diff_for_work_area", "" -repl call, 0x4B0FC3, 0x4B7F73, 0x4B1053, "ni_to_diff_for_work_area", "" -ext walup, 0x4B1047, 0x4B7FF7, 0x4B10D7, "", "" -repl call, 0x4B2414, 0x4B93AD, 0x4B24A4, "ni_to_diff_for_work_area", "" -repl call, 0x4B247D, 0x4B9412, 0x4B250D, "City_add_or_remove_tile_yield_conv_ni", "" -ext walup, 0x4B2490, 0x4B941B, 0x4B2520, "", "" -define, 0x4C2680, 0x4C9EB0, 0x4C26A0, "City_is_neighboring_tile_in_area", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" -repl call, 0x4B260C, 0x4B9593, 0x4B269C, "City_is_neighboring_tile_in_area_conv_ni", "" -repl call, 0x4B261A, 0x4B95A1, 0x4B26AA, "City_add_or_remove_tile_yield_conv_ni", "" -ext walup, 0x4B2623, 0x4B95AA, 0x4B26B3, "", "" -repl call, 0x4BA09E, 0x4C170E, 0x4BA12E, "ni_to_diff_for_work_area", "" -repl call, 0x4BA124, 0x4C1790, 0x4BA1B4, "ni_to_diff_for_work_area", "" -ext walup, 0x4BA19E, 0x4C180A, 0x4BA22E, "", "" -repl call, 0x435459, 0x436F39, 0x4354D9, "ni_to_diff_for_work_area", "" -ext walup, 0x43550D, 0x436FED, 0x43558D, "", "" -repl call, 0x43688D, 0x4382FD, 0x43690D, "ni_to_diff_for_work_area", "" -ext walup, 0x436988, 0x4383F8, 0x436A08, "", "" -inlead, 0x4BB4D0, 0x4C2B20, 0x4BB560, "City_controls_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index, bool consider_enemy_units)" -repl call, 0x43564F, 0x43712B, 0x4356CF, "City_controls_tile_conv_ni", "" -repl call, 0x435667, 0x437143, 0x4356E7, "ni_to_diff_for_work_area", "" -repl call, 0x4356E3, 0x4371B9, 0x435763, "City_stop_working_tile_conv_ni", "" -ext walup, 0x4356F6, 0x4371C2, 0x435776, "", "" -repl call, 0x435729, 0x4371F1, 0x4357A9, "ni_to_diff_for_work_area", "" -repl call, 0x4357A1, 0x437269, 0x435821, "City_controls_tile_conv_ni", "" -ext walup, 0x4357D7, 0x43728F, 0x435857, "", "" -repl call, 0x4357E8, 0x4372A0, 0x435868, "City_start_working_tile_conv_ni", "" -repl call, 0x435895, 0x43733F, 0x435915, "ni_to_diff_for_work_area", "" -repl call, 0x435925, 0x4373D1, 0x4359A5, "City_controls_tile_conv_ni", "" -ext walup, 0x43595B, 0x4373F7, 0x4359DB, "", "" -repl call, 0x43597C, 0x437418, 0x4359FC, "ni_to_diff_for_work_area", "" -repl call, 0x435A91, 0x43752D, 0x435B11, "City_start_working_tile_conv_ni", "" -repl call, 0x5BD837, 0x5CC412, 0x5BD547, "Map_compute_ni_for_work_area", "" -repl vptr, 0x66DCB8, 0x68AD9C, 0x66DCB8, "City_find_best_tile_to_work", "int (__fastcall *) (City * this, int edx, Unit * worker, bool param_2)" -repl call, 0x436328, 0x437DBB, 0x4363A8, "ni_to_diff_for_work_area", "" -ext walup, 0x436805, 0x438273, 0x436885, "", "" -repl call, 0x420CC5, 0x422219, 0x420D45, "ni_to_diff_for_work_area", "" -repl call, 0x420DD7, 0x422327, 0x420E57, "ni_to_diff_for_work_area", "" -ext walup, 0x420F05, 0x422466, 0x420F85, "", "" -repl call, 0x420F3A, 0x42249A, 0x420FBA, "ni_to_diff_for_work_area", "" -ext walup, 0x421182, 0x4226D7, 0x421202, "", "" -repl call, 0x4AFCE0, 0x4B6C9C, 0x4AFD70, "City_is_neighboring_tile_in_area_conv_ni", "" -repl call, 0x4AFCEE, 0x4B6CAA, 0x4AFD7E, "City_add_or_remove_tile_yield_conv_ni", "" -ext walup, 0x4AFCF7, 0x4B6CB3, 0x4AFD87, "", "" -repl call, 0x4BA663, 0x4C1CC2, 0x4BA6F3, "City_is_neighboring_tile_in_area_conv_ni", "" -repl call, 0x4BA671, 0x4C1CD0, 0x4BA701, "City_add_or_remove_tile_yield_conv_ni", "" -ext walup, 0x4BA67A, 0x4C1CD9, 0x4BA70A, "", "" -repl call, 0x42053D, 0x421A1D, 0x4205BD, "Map_compute_ni_for_work_area", "" -repl call, 0x435D78, 0x437802, 0x435DF8, "Map_compute_ni_for_work_area", "" -repl call, 0x5DA3B6, 0x5E9925, 0x5DA2E6, "Map_compute_ni_for_work_area", "" -repl vptr, 0x66DCAC, 0x68AD90, 0x66DCAC, "City_find_min_value_tile", "int (__fastcall *) (City * this)" -repl call, 0x420ECD, 0x422426, 0x420F4D, "Sprite_draw_already_worked_tile_img", "" -repl call, 0x420668, 0x421B48, 0x4206E8, "Map_compute_ni_for_work_area", "" -define, 0x420672, 0x421B52, 0x4206F2, "ADDR_REDUNDANT_CHECK_ON_WORK_AREA_HOVER", "byte *" -repl call, 0x5668EE, 0x572C9B, 0x56689E, "Map_compute_ni_for_work_area", "" -define, 0x420547, 0x421A27, 0x4205C7, "ADDR_CITY_FORM_LEFT_CLICK_JUMP", "byte *" -define, 0x4BB4EB, 0x4C2B3C, 0x4BB57B, "ADDR_CONTROLS_TILE_JUMP", "byte *" -repl call, 0x5DA4D1, 0x5E9A48, 0x5DA401, "ni_to_diff_for_work_area", "" -ext walup, 0x5DA555, 0x5E9ACC, 0x5DA485, "", "" -repl call, 0x4C0309, 0x4C78FE, 0x4C0399, "ni_to_diff_for_work_area", "" -ext walup, 0x4C03EA, 0x4C79D9, 0x4C047A, "", "" -repl call, 0x442603, 0x4443D2, 0x442683, "Tile_m43_Get_field_30_for_city_loc_eval", "" -repl call, 0x4427B9, 0x444585, 0x442839, "Tile_m43_Get_field_30_for_city_loc_eval", "" -repl call, 0x4B2FC1, 0x4B9F41, 0x4B3051, "rand_int_to_place_pollution", "" -repl call, 0x4B2FF4, 0x4B9F76, 0x4B3084, "ni_to_diff_for_work_area", "" -define, 0x4B2FEB, 0x4B9F6E, 0x4B307B, "ADDR_SPAWN_POLLUTION_MOD", "byte *" -ext walup, 0x4B309F, 0x4BA025, 0x4B312F, "", "" -repl call, 0x43535D, 0x436E49, 0x4353DD, "ni_to_diff_for_work_area", "" -repl call, 0x4353CA, 0x436EB6, 0x43544A, "City_controls_tile_conv_ni", "" -ext walup, 0x43540B, 0x436EEF, 0x43548B, "", "" -define, 0x4E3B10, 0x4EC360, 0x4E3BD0, "Main_Screen_Form_tile_to_screen_coords", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int * out_x, int * out_y)" -repl call, 0x420C68, 0x4221BC, 0x420CE8, "Main_Screen_Form_t2s_coords_to_draw_yields", "" -repl call, 0x420887, 0x421D88, 0x420907, "Main_Screen_Form_t2s_coords_to_draw_yields", "" -inlead, 0x420C40, 0x422190, 0x420CC0, "City_Form_draw_yields_on_worked_tiles", "void (__fastcall *) (City_Form * this)" -inlead, 0x420860, 0x421D60, 0x4208E0, "City_Form_draw_highlighted_yields", "bool (__fastcall *) (City_Form * this, int edx, int tile_x, int tile_y, int neighbor_index)" -inlead, 0x420F20, 0x422480, 0x420FA0, "City_Form_draw_border_around_workable_tiles", "void (__fastcall *) (City_Form * this)" -inlead, 0x4229F0, 0x423FA0, 0x422A70, "City_Form_draw_food_income_icons", "void (__fastcall *) (City_Form * this)" -inlead, 0x4BFAB0, 0x4C7070, 0x4BFB40, "City_draw_production_income_icons", "void (__fastcall *) (City * this, int edx, int canvas, int * rect_ptr)" -repl call, 0x4BFBB7, 0x4C7177, 0x4BFC47, "Sprite_draw_production_income_icon", "" -repl call, 0x421095, 0x4225EF, 0x421115, "Main_Screen_Form_t2s_coords_to_draw_yields", "" -repl call, 0x420FC5, 0x422525, 0x421045, "Map_get_tile_for_work_area_drawing", "" -repl call, 0x420DA2, 0x4222F8, 0x420E22, "Map_get_tile_for_work_area_drawing", "" -repl call, 0x5DA3BE, 0x5E992D, 0x5DA2EE, "City_stop_working_polluted_tile", "" -repl vptr, 0x66DCB0, 0x68AD94, 0x66DCB0, "City_manage_by_governor", "void (__fastcall *) (City * this, int edx, bool param_1)" -define, 0x5DA3CC, 0x5E993B, 0x5DA2FC, "ADDR_MANAGE_CITY_AFTER_POLLUTION_RETURN", "int" -define, 0x56D040, 0x5799C0, 0x56CFB0, "find_nearest_city", "City * (__cdecl *) (int tile_x, int tile_y, int owner_id, int continent_id, int ignore_owner_id, int perspective_id, City * ignore_city)" -repl call, 0x438A5B, 0x43A5E6, 0x438ADB, "find_nearest_city_for_ai_alliance_eval", "" -define, 0x9C34EC, 0x9E5CE4, 0x9C34AC, "p_nearest_city_distance", "int *" -define, 0x565400, 0x571790, 0x5653B0, "Leader_bounce_trespassing_units", "void (__fastcall *) (Leader * this, int edx, int against_civ_id)" -inlead, 0x446840, 0x448650, 0x4468C0, "Leader_begin_turn", "void (__fastcall *) (Leader * this)" -repl call, 0x5654AC, 0x571841, 0x56545C, "Unit_is_visible_to_civ_for_bouncing", "" -inlead, 0x5025B0, 0x50C230, 0x502650, "Leader_make_peace", "void (__fastcall *) (Leader * this, int edx, int civ_id)" -inlead, 0x5C5BD0, 0x5D4970, 0x5C58E0, "Unit_can_load", "bool (__fastcall *) (Unit * this, int edx, Unit * passenger)" -repl call, 0x5CDE34, 0x5DCEF4, 0x5CDD54, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x5CDE4C, 0x5DCF0C, 0x5CDD6C, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x5C7774, 0x5D6624, 0x5C7484, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x57F6F4, 0x58C41E, 0x57F454, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x57FF93, 0x58CCA6, 0x57FCF3, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x580486, 0x58D1B5, 0x5801E6, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x464BA9, 0x46715E, 0x464C29, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x46514C, 0x46771C, 0x4651CC, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x465560, 0x467B41, 0x4655E0, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x58067D, 0x58D39A, 0x5803DD, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x565693, 0x571A45, 0x565643, "Leader_count_any_shared_wonders_with_flag", "" -inlead, 0x4BD420, 0x4C4A80, 0x4BD4B0, "City_add_happiness_from_buildings", "void (__fastcall *) (City * this, int edx, int * inout_happiness, int * inout_unhappiness)" -define, 0x4BDDE0, 0x4C5410, 0x4BDE70, "City_count_other_buildings_on_continent", "int (__fastcall *) (City * this, int edx, int improv_id)" -repl call, 0x4BD5F0, 0x4C4C50, 0x4BD680, "City_count_other_cont_happiness_buildings", "" -repl call, 0x5C056D, 0x5CF10D, 0x5C027D, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4ACEFE, 0x4B3ED3, 0x4ACF8E, "Leader_count_any_shared_wonders_with_flag", "" -inlead, 0x562380, 0x56E4F0, 0x562330, "Leader_update_great_library_unlocks", "void (__fastcall *) (Leader * this)" -repl call, 0x562390, 0x56E4FB, 0x562340, "Leader_count_any_shared_wonders_with_flag", "" -define, 0x4B5050, 0x4BC030, 0x4B50E0, "City_can_take_outside_shields", "bool (__fastcall *) (City * this, int edx, int param_1)" -define, 0x56A210, 0x5766B0, 0x56A1C0, "Leader_get_unit_cost", "int (__fastcall *) (Leader * this, int edx, int id, bool ignore_difficulty)" -repl call, 0x4A101C, 0x4A7BDC, 0x4A10AC, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4A10B8, 0x4A7C70, 0x4A1148, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4C0D41, 0x4C8341, 0x4C0DD1, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4C0D87, 0x4C8387, 0x4C0E17, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4C118D, 0x4C8779, 0x4C121D, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4BD95E, 0x4C4FB4, 0x4BD9EE, "Leader_count_any_shared_wonders_with_flag", "" -repl call, 0x4B24E5, 0x4B946C, 0x4B2575, "Leader_count_any_shared_wonders_with_flag", "" -inlead, 0x55A7E0, 0x5666F0, 0x55A790, "Leader_has_wonder_doubling_happiness_from", "bool (__fastcall *) (Leader * this, int edx, int improv_id)" -inlead, 0x56A2A0, 0x576740, 0x56A250, "Leader_can_build_city_improvement", "bool (__fastcall *) (Leader * this, int edx, int i_improv, bool param_2)" -repl call, 0x4BF828, 0x4C6DD8, 0x4BF8B8, "Sprite_draw_citizen_head", "" -repl call, 0x4BF95D, 0x4C6F0D, 0x4BF9ED, "Sprite_draw_entertainer_yield_icon", "" -repl call, 0x4BF912, 0x4C6EC2, 0x4BF9A2, "Sprite_draw_scientist_yield_icon", "" -repl call, 0x4BF8C0, 0x4C6E70, 0x4BF950, "Sprite_draw_tax_collector_yield_icon", "" -repl call, 0x4BF9E1, 0x4C6FA1, 0x4BFA71, "Sprite_draw_civil_engineer_yield_icon", "" -repl call, 0x4BFA45, 0x4C7005, 0x4BFAD5, "Sprite_draw_police_officer_yield_icon", "" -inlead, 0x4B9270, 0x4C08E0, 0x4B9300, "City_add_building_if_done", "void (__fastcall *) (City * this)" -define, 0x9C34E4, 0x9E5CDC, 0x9C34A4, "p_zoom_to_city_after_update", "bool *" -define, 0x5812BA, 0x58DFE7, 0x58101A, "ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN", "byte *" -inlead, 0x4BFD40, 0x4C7300, 0x4BFDD0, "City_get_turns_to_build", "int (__fastcall *) (City * this, int edx, int order_type, int order_id, bool param_3)" -repl call, 0x4C06C0, 0x4C7C80, 0x4C0750, "City_can_build_upgrade_type", "" -define, 0x4C1F80, 0x4C96B0, 0x4C2010, "Hash_Table_look_up", "bool (__fastcall *) (Hash_Table * this, int edx, int key, int * out_value)" -inlead, 0x557720, 0x563530, 0x5576D0, "Main_GUI_position_elements", "void (__fastcall *) (Main_GUI * this)" -define, 0x5FE8A0, 0x613550, 0x5FE780, "PCX_Image_get_text_line_height", "int (__fastcall *) (PCX_Image * this)" -repl vptr, 0x66AFF0, 0x6880F0, 0x66AFF0, "Civilopedia_Article_m01_Draw_GCON_or_RACE", "void (__fastcall *) (Civilopedia_Article * this)" -repl vptr, 0x66AFA8, 0x6880A8, 0x66AFA8, "Civilopedia_Article_m01_Draw_UNIT", "void (__fastcall *) (Civilopedia_Article * this)" -repl call, 0x5FF8B5, 0X614B5D, 0x5FF795, "PCX_Image_do_draw_centered_text_in_wrap_func", "" -repl call, 0x5FF7E0, 0x614A5F, 0x5FF6C0, "PCX_Image_draw_text_in_wrap_func", "" -repl call, 0x0FF, 0x614A7A, 0x0FF, "PCX_Image_draw_text_no_len_in_wrap_func", "" -repl vptr, 0x66B1B8, 0x6882B8, 0x66B1B8, "Civilopedia_Form_m68_Show_Dialog", "int (__fastcall *) (Civilopedia_Form * this, int edx, int param_1, void * param_2, void * param_3)" -repl vptr, 0x66B17C, 0x68827C, 0x66B17C, "Civilopedia_Form_m53_On_Control_Click", "void (__fastcall *) (Civilopedia_Form * this, int edx, CivilopediaControlID control_id)" -repl vptr, 0x66B100, 0x688200, 0x66B100, "Civilopedia_Form_m22_Draw", "void (__fastcall *) (Civilopedia_Form * this)" -repl call, 0x4CC5AA, 0x4D462E, 0x4CC66A, "Button_initialize_civilopedia_description", "" -define, 0x179, 0x17A, 0x179, "LBL_EFFECTS", "int" -define, 0x17A, 0x17B, 0x17A, "LBL_PREVIOUS", "int" -define, 0x128, 0x129, 0x128, "LBL_MORE", "int" -define, 0x537700, 0x541D30, 0x537780, "play_sound_effect", "void (__cdecl *) (int sound_effect)" -repl call, 0x578CD9, 0x585DF3, 0x578C49, "Tile_check_water_for_navigator_cell_coloring", "" -inlead, 0x49F5C0, 0x4A6080, 0x49F650, "PopupForm_impl_begin_showing_popup", "int (__fastcall *) (PopupForm * this)" -repl call, 0x49F5CB, 0x4A608B, 0x49F65B, "is_online_game_for_show_popup", "" -define, 0x4EEC40, 0x4F7BE0, 0x4EED00, "Animator_update", "void (__fastcall *) (Animator * this)" -inlead, 0x5C32F0, 0x5D1F20, 0x5C3000, "Unit_ai_can_sacrifice", "bool (__fastcall *) (Unit * this, int edx, bool requires_city)" -inlead, 0x4C5A10, 0x4CD2C0, 0x4C5A30, "Map_Renderer_load_images", "void (__fastcall *) (Map_Renderer *this, int edx)" -define, 0x446114, 0x447EF6, 0x446194, "ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN", "byte *" -define, 0x5663F0, 0x57275D, 0x5663A0, "ADDR_CITY_LIM_CMP_IN_CREATE_CITY", "byte *" -define, 0x4F8D76, 0x5024E6, 0x4F8E36, "ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR", "byte *" -define, 0x4C2420, 0x4C9C10, 0x4C2440, "Buildings_Info_get_age_in_years", "int (__fastcall *) (Buildings_Info * this, int edx, int building_index)" -repl call, 0x4B073C, 0x4B76F0, 0x4B07CC, "Buildings_Info_get_age_in_years_for_tourism", "" -define, 0x501CD0, 0x50B960, 0x501D70, "Leader_make_contact", "void (__fastcall *) (Leader * this, int edx, int civ_id, bool no_online_sync)" -define, 0x5F83E0, 0x608910, 0x5F8310, "Sprite_draw_for_hud", "int (__fastcall *) (Sprite * this, int edx, Sprite * alpha, int param_2, PCX_Image * canvas, int x, int y, int param_6)" -repl call, 0x55374D, 0x55EDF8, 0x5536FD, "Sprite_draw_minimap_frame", "" -define, 0x5792AB, 0x5863CB, 0x57921B, "ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT", "byte *" -repl call, 0x44580E, 0x44760E, 0x44588E, "Unit_has_king_ability_for_find_unsupported", "" -define, 0x4BFD20, 0x4C72E0, 0x4BFDB0, "City_get_turns_to_build_2", "int (__fastcall *) (City * this, int edx, City_Order * order, bool param_2)" -repl call, 0x45FF66, 0x462336, 0x45FFE6, "City_get_turns_to_build_2_for_ai_move_leader", "" -repl call, 0x4600F8, 0x4624E5, 0x460178, "City_get_turns_to_build_2_for_ai_move_leader", "" -define, 0x50FDB3, 0x51A057, 0x50FE53, "ADDR_MAX_TRADABLE_CITY_ID", "byte *" -define, 0x505B21, 0x50F8EB, 0x505BC1, "ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR", "byte *" -define, 0x51000C, 0x51A2AC, 0x5100AC, "ADDR_MAX_TRADABLE_UNIT_ID", "byte *" -define, 0x505B67, 0x50F931, 0x505C07, "ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR", "byte *" -repl vptr, 0x66A52C, 0x687638, 0x66A52C, "Map_Renderer_m09_Draw_Tile_Resources", "void (__fastcall *) (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" -repl vptr, 0x66A538, 0x687644, 0x66A538, "Map_Renderer_m12_Draw_Tile_Buildings", "void (__fastcall *) (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" -inlead, 0x5F61A0, 0x605F50, 0x5F60D0, "Map_Renderer_m11_Draw_Tile_Irrigation", "void (__fastcall *) (Map_Renderer *this, int edx, int visible_to_civ, int tile_x, int tile_y, int param_4, int param_5, int param_6)" -repl call, 0x5F5580, 0x6053D2, 0x5F54B0, "Tile_has_city_or_district", "" -repl call, 0x5F5816, 0x605639, 0x5F5746, "Tile_has_city_or_district", "" -repl call, 0x5F5ABB, 0x6058AF, 0x5F59EB, "Tile_has_city_or_district", "" -repl call, 0x5F5D75, 0x605B31, 0x5F5CA5, "Tile_has_city_or_district", "" -inlead, 0x56CEB0, 0x579830, 0x56CE20, "get_building_defense_bonus_at", "int (__cdecl *) (int x, int y, int param_3)" -define, 0x4B0540, 0x4B7500, 0x4B05D0, "City_update_food_consumption", "void (__fastcall *) (City * this)" -define, 0x5660E0, 0x572460, 0x566090, "Leader_get_food_cost_factor", "int (__fastcall *) (Leader *this, int edx, bool ignore_difficulty)" -define, 0x427540, 0x428C90, 0x4275C0, "City_get_size_class", "int (__fastcall *) (City *this)" -inlead, 0x5B39A0, 0x5C22F0, 0x5B36B0, "is_not_pop_capped_or_starving", "bool (__stdcall *) (City * city)" -inlead, 0x4068E0, 0x406E40, 0x406910, "set_worker_animation", "void (__fastcall *) (void * this, int edx, Unit * unit, int job_id)" -define, 0x5C66D0, 0x5D5520, 0x5C63E0, "get_worker_remaining_turns_to_complete", "int (__fastcall *) (Unit * this, int edx, int job_id)" -inlead, 0x435BA0, 0x437630, 0x435C20, "City_instruct_worker", "bool (__fastcall *) (City * this, int edx, int tile_x, int tile_y, bool param_3, Unit * worker)" -repl vptr, 0x66A528, 0x687634, 0x66A528, "Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp", "void (__fastcall *) (Map_Renderer * this, int edx, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" -repl vptr, 0x66A5D8, 0x6876E4, 0x66A5D8, "Map_Renderer_m52_Draw_Roads", "void (__fastcall *) (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" -repl vptr, 0x66A5D0, 0x6876DC, 0x66A5D0, "Map_Renderer_m52_Draw_Railroads", "void (__fastcall *) (Map_Renderer * this, int edx, int sprite_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" -inlead, 0x5EB580, 0x5FADD0, 0x5EB4B0, "Map_impl_generate", "void (__fastcall *) (Map * this, int edx, int seed, bool is_multiplayer_game, int num_seafaring_civs)" -inlead, 0x4E5580, 0x4EDEB0, 0x4E5640, "Main_Screen_Form_draw_city_hud", "void (__fastcall *) (Main_Screen_Form * this, int edx, PCX_Image * canvas)" -inlead, 0x4BFF80, 0x4C7580, 0x4C0010, "City_can_build_improvement", "bool (__fastcall *) (City * this, int edx, int i_improv, bool apply_strict_rules)" -repl call, 0x5C1C53, 0x5D07F6, 0x5C1963, "Unit_has_army_ability_to_perform_unload", "" -inlead, 0x5C59B0, 0x5D4740, 0x5C56C0, "Unit_disembark", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -define, 0x4A12D0, 0x4A7E80, 0x4A1360, "Fighter_prefer_first_defender_1", "bool (__fastcall *) (Fighter * this, int edx, Unit * first, int first_strength, Unit * second, int second_strength, bool param_5)" -repl call, 0x5C5C82, 0x5D4A23, 0x5C5992, "Unit_has_ability_no_load_non_army_passengers", "" -repl call, 0x5C5C93, 0x5D4A34, 0x5C59A3, "Unit_has_ability_no_load_transport_into_army", "" -inlead, 0x4A1590, 0x4A8140, 0x4A1620, "Fighter_unit_can_defend", "bool (__fastcall *) (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y)" -define, 0x558F70, 0x564E30, 0x558F20, "Leader_is_enemy_unit", "bool (__fastcall *) (Leader * this, int edx, Unit * unit)" -repl call, 0x5C6C5B, 0x5D5AD4, 0x5C696B, "Leader_is_enemy_unit_for_ground_aa", "" -repl call, 0x5BC013, 0x5CAB6A, 0x5BBD23, "Unit_has_army_ability_for_passenger_despawn", "" -define, 0x4A63F4, 0x4AD09E, 0x4A6484, "DESPAWN_TO_FIGHT_1_RETURN", "int" -define, 0x4A6EF7, 0x4ADBAB, 0x4A6F87, "DESPAWN_TO_FIGHT_2_RETURN", "int" -define, 0x4A4436, 0x4AB104, 0x4A44C6, "DESPAWN_TO_DO_BOMBARD_TILE_RETURN", "int" -define, 0x4A31C6, 0x4A9E19, 0x4A3256, "DESPAWN_TO_CRUISE_MISSILE_DEFENDER_RETURN", "int" -define, 0x5659E2, 0x571D83, 0x565992, "DESPAWN_TO_BOUNCE_TRESPASSING_UNITS_RETURN", "int" -define, 0x5B4844, 0x5C319E, 0x5B4554, "DESPAWN_TO_NUKE_DAMAGE_RETURN", "int" -define, 0x5B8462, 0x5C6E78, 0x5B8172, "DESPAWN_TO_DO_CAPTURE_UNITS_RETURN", "int" -define, 0x5BC0A2, 0x5CABF1, 0x5BBDB2, "DESPAWN_RECURSIVE_RETURN", "int" -define, 0x5C7030, 0x5D5EBB, 0x5C6D40, "DESPAWN_TO_TRY_FLYING_OVER_TILE_RETURN", "int" -repl call, 0x5B8D95, 0x5C7801, 0x5B8AA5, "count_units_at_in_try_capturing", "" -define, 0x5F35C2, 0x603442, 0x5F34F2, "ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9", "byte *" -inlead, 0x5F22A0, 0x6020D0, 0x5F21D0, "Map_generate_resources", "void (__fastcall *) (Map * this, int edx, int secondary_seed)" -define, 0x5F2C25, 0x602AF6, 0x5F2B55, "ADDR_RESOURCE_GEN_TILE_COUNT_DIV", "byte *" -repl call, 0x5BFA0C, 0x5CE59E, 0x5BF71C, "rand_int_to_enslave", "" -repl call, 0x52A165, 0x53452B, 0x52A205, "Sprite_draw_espionage_screen_target_civ_bkg", "" -repl call, 0x52A1C1, 0x534587, 0x52A261, "Civilopedia_Article_get_name_for_esp_screen", "" -define, 0xA422F8, 0xA64AF8, 0xA422B8, "p_espionage_form", "Espionage_Form *" -define, 0x680758, 0x69D768, 0x680758, "animation_names", "char **" -define, 0x5BF2FB, 0x5CDE95, 0x5BF00B, "ADDR_SKIP_VICTORY_ANIM_IF_AIR", "byte *" -repl call, 0x5BF4D5, 0x5CE066, 0x5BF1E5, "Animator_play_one_shot_victory_animation", "" -inlead, 0x4DBFC0, 0x4E4990, 0x4DC080, "Main_Screen_Form_assemble_selectable_units", "void (__fastcall *) (Main_Screen_Form * this)" -inlead, 0x4DBA70, 0x4E4440, 0x4DBB30, "Main_Screen_Form_set_selected_unit", "void (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit, bool param_2)" -inlead, 0x4DBD70, 0x4E4740, 0x4DBE30, "Main_Screen_Form_find_next_unit_for_cycling", "Unit * (__fastcall *) (Main_Screen_Form * this)" -define, 0x4EDD40, 0x4F6C90, 0x4EDE00, "UnitIDList_insert_before", "void (__fastcall *) (UnitIDList * this, int edx, int id, UnitIDItem * item)" -define, 0x5BE970, 0x5CD590, 0x5BE680, "Unit_can_cycle_to", "bool (__fastcall *) (Unit * this)" -define, 0x4DABB2, 0x4E3570, 0x4DAC72, "SET_SELECTED_UNIT_TO_ISSUE_WAIT_COMMAND_RET", "int" -repl vptr, 0x66DCD0, 0x68ADB4, 0x66DCD0, "City_m22", "void (__fastcall *) (City * this, int edx, bool param_1)" -define, 0x4B95D7, 0x4C0C43, 0x4B9667, "CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_1", "int" -define, 0x4B96C9, 0x4C0D35, 0x4B9759, "CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_2", "int" -define, 0x4B90D6, 0x4C0743, 0x4B9166, "CITY_M22_TO_SPAWN_UNIT_IF_DONE_RETURN", "int" -inlead, 0x5B6CE0, 0x5C5670, 0x5B69F0, "Unit_do_capture_units", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, int owner_civ_id)" -define, 0xA38C18, 0xA5B418, 0xA38BD8, "p_advisor_internal_form", "Advisor_Internal_Form *" -repl call, 0x51DC54, 0x527A41, 0x51DCF4, "PCX_Image_process_dom_adv_turn_count_text", "" -define, 0x4B1205, 0x4B81B5, 0x4B1295, "ADDR_CORRUPTION_CAPITAL_CHECK", "byte *" -define, 0x4B12C0, 0x4B8272, 0x4B1350, "ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT", "byte *" -define, 0xCCF76C, 0xCF1DC4, 0xCCF724, "p_code_page", "unsigned *" -define, 0x4ED5F0, 0x4F6520, 0x4ED6B0, "MenuUnitList_get_length", "int (__fastcall *) (MenuUnitList * this)" -repl call, 0x4E8BD4, 0x4F1895, 0x4E8C94, "MenuUnitList_get_length_before_sorting", "" -define, 0x4E7E00, 0x4F08C0, 0x4E7EC0, "MenuUnitItem_should_appear_after", "bool (__fastcall *) (MenuUnitItem * this, int edx, MenuUnitItem * other)" -define, 0xA52B6C, 0xA75364, 0xA52B2C, "p_allow_ai_patrol", "bool *" -define, 0x5F1F50, 0x601D30, 0x5F1E80, "Map_finalize_params", "void (__fastcall *) (Map * this)" -repl call, 0x5D1888, 0x5E0B0E, 0x5D17B8, "Map_finalize_params_for_scenario_map", "" -define, 518, 519, 518, "LBL_NO_BARBARIANS", "int" -define, 545, 546, 545, "LBL_RANDOM_BARBS", "int" -define, 0x4BA230, 0x4C18A0, 0x4BA2C0, "City_remove_population", "void (__fastcall *) (City * this, int edx, int num_pops, int race_id, char param_3)" -define, 0x4AE280, 0x4B5260, 0x4AE310, "City_get_largest_adjacent_sea", "int (__fastcall *) (City * this)" -repl call, 0x4C008E, 0x4C7686, 0x4C011E, "City_get_largest_adjacent_sea_within_work_area", "" -repl call, 0x4C010F, 0x4C7707, 0x4C019F, "Map_impl_has_fresh_water_within_work_area", "" -repl call, 0x4C0173, 0x4C776C, 0x4C0203, "Map_impl_is_near_river_within_work_area", "" -repl call, 0x4C01AF, 0x4C77A8, 0x4C023F, "Map_impl_is_near_river_within_work_area", "" -repl call, 0x4C01CF, 0x4C77C8, 0x4C025F, "Map_impl_is_near_lake_within_work_area", "" -inlead, 0x458120, 0x45A2E0, 0x4581A0, "Unit_ai_move_naval_power_unit", "void (__fastcall *) (Unit * this)" -inlead, 0x45A170, 0x45C380, 0x45A1F0, "Unit_ai_move_naval_transport", "void (__fastcall *) (Unit * this)" -inlead, 0x460620, 0x462A20, 0x4606A0, "Unit_ai_move_naval_missile_transport", "void (__fastcall *) (Unit * this)" -inlead, 0x44C130, 0x44E110, 0x44C1B0, "Unit_ai_eval_pillage_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" -inlead, 0x456840, 0x458A50, 0x4568C0, "Unit_ai_move_air_bombard_unit", "void (__fastcall *) (Unit * this)" -inlead, 0x4579E0, 0x459BB0, 0x457A60, "Unit_ai_move_air_defense_unit", "void (__fastcall *) (Unit * this)" -inlead, 0x459CE0, 0x45BF00, 0x459D60, "Unit_ai_move_air_transport", "void (__fastcall *) (Unit * this)" -define, 0x5C1920, 0x5D04B0, 0x5C1630, "Unit_airdrop", "void (__fastcall *) (Unit * this, int edx, int x, int y)" -repl call, 0x4C0D87, 0x4C8387, 0x4C0E17, "Leader_count_wonders_with_flag_ignore_great_wall", "" -repl call, 0x5D3D67, 0x5E30FC, 0x5D3C97, "Tile_has_colony_ignore_extraterritorial", "" -inlead, 0x440100, 0x441ED0, 0x440180, "Leader_get_attitude_toward", "int (__fastcall *) (Leader * this, int edx, int civ_id, int param_2)" -inlead, 0x5D7080, 0x5E64E0, 0x5D6FB0, "Map_check_colony_location", "int (__fastcall *) (Map * this, int edx, int tile_x, int tile_y, int civ_id)" -inlead, 0x5BCE60, 0x5CBA10, 0x5BCB70, "Unit_select_army_member_for_combat", "Unit * (__fastcall *) (Unit * this, int edx, int param_1, char param_2)" -inlead, 0x44C340, 0x44E330, 0x44C3C0, "Unit_ai_eval_bombard_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, int param_3)" -define, 0x5CD770, 0x5DC720, 0x5CD690, "UnitIDList_insert_after", "void (__fastcall *) (UnitIDList * this, int edx, int id, UnitIDItem * item)" -repl call, 0x5BBBA6, 0x5CA70C, 0x5BB8B6, "UnitIDList_insert_after_init", "" -define, 0x5BCC90, 0x5CB840, 0x5BC9A0, "Unit_load_into_army", "void (__fastcall *) (Unit * this, int edx, Unit * loadee)" -repl call, 0x5B9FEC, 0x5C8AB3, 0x5B9CFC, "Unit_load_into_army_after_move_to_adj_tile", "" -define, 0x5FF750, 0x6149E0, 0x5FF630, "PCX_Image_draw_and_wrap_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int width)" -repl call, 0x4D5283, 0x4DDA46, 0x4D5343, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -repl call, 0x4D52EA, 0x4DDAAE, 0x4D53AA, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -repl call, 0x4D5340, 0x4DDB05, 0x4D5400, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -repl call, 0x4D5396, 0x4DDB5C, 0x4D5456, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -repl call, 0x4D5400, 0x4DDBC5, 0x4D54C0, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -repl call, 0x4D5464, 0x4DDC29, 0x4D5524, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" -define, 0x1A5, 0x1A6, 0x1A5, "LBL_OPERATIONAL_RANGE", "int" -define, 0x4D519C, 0x4DD953, 0x4D525C, "ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS", "byte *" -define, 0x1A8, 0x1A9, 0x1A8, "LBL_BOMBARD_RANGE", "int" -ignore, 0x5FC710, 0x0, 0x0, "PCX_Image_create_and_init_jgl_image", "int (__fastcall *) (PCX_Image * this, int edx, int width, int height, int bit_depth, int param_4, int param_5, int param_6)" -ignore, 0x5FCC50, 0x0, 0x0, "PCX_Image_draw_region_to_location", "void (__fastcall *) (PCX_Image * this, int edx, PCX_Image * canvas, int src_x, int src_y, int dest_x, int dest_y, int width, int height)" -ignore, 0x600050, 0x0, 0x0, "PCX_Image_fill", "void (__fastcall *) (PCX_Image * this, int edx, int color)" -ignore, 0x5FFF10, 0x0, 0x0, "PCX_Image_set_color_table", "int (__fastcall *) (PCX_Image * this, int edx, PCX_Color_Table * color_table)" -ignore, 0x4507B0, 0x452860, 0x0, "Unit_ai_move_offensive_unit", "void (__fastcall *) (Unit * this)" -ignore, 0x558F70, 0x0, 0x0, "Leader_is_enemy_unit", "char (__fastcall *) (Leader * this, int edx, Unit * unit)" -ignore, 0x4BFD40, 0x0, 0x0, "City_get_turns_to_build", "int (__fastcall *) (City * this, int edx, int order_type, int order_id, char param_3)" -ignore, 0x4E3D90, 0x0, 0x0, "Main_Screen_Form_is_unit_hidden_from_player", "bool (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit)" -ignore, 0x4E8850, 0x4F14E0, 0x4E8910, "Main_Screen_Form_open_right_click_unit_menu", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" -ignore, 0x5CCBB0, 0x0, 0x0, "Unit_can_pass_between", "PassBetweenValidity (__fastcall *) (Unit * this, int edx, int from_x, int from_y, int to_x, int to_y, byte param_5)" -ignore, 0x452510, 0x454600, 0x452590, "ai_move_defensive_unit", "void (__fastcall *) (Unit * this)" -ignore, 0x5E78E0, 0x5F7130, 0x0, "General_load", "void (__fastcall *) (General * this, int edx, byte ** buffer)" -ignore, 0x5E7020, 0x5F6870, 0x0, "General_clear", "void (__fastcall *) (General * this)" -ignore, 0x605010, 0x61C6A0, 0x604F00, "Base_Form_impl_m01_Show_Enabled", "void (__fastcall *) (Base_Form * this, int edx, byte flags)" -ignore, 0x74AF60, 0x0, 0x0, "p_sync_object", "void *" -ignore, 0x5C0E20, 0x5CF9C0, 0x5C0B30, "Unit_begin_bombarding_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y)" -ignore, 0x57F623, 0x58C352, 0x57F383, "ADDR_SUB_BUG_PATCH", "void *" -define, 0xCC2BB0, 0xCE54BC, 0xCC2B70, "p_got_leader_gender", "int *" -ignore, 0x49D070, 0x4A3AF0, 0x49D100, "Advisor_GUI_open", "void (__fastcall *) (Advisor_GUI * this, int edx, AdvisorKind kind)" -ignore, 0x4BF660, 0x4C6C10, 0x4BF6F0, "City_draw_citizens", "void (__fastcall *) (City * this, int edx, PCX_Image * canvas, RECT * rect, char param_3)" -ignore, 0x4B9F60, 0x4C15D0, 0x4B9FF0, "City_add_population", "void (__fastcall *) (City * this, int edx, int num, int race_id)" -ignore, 0x670234, 0x68D2E0, 0x670234, "Tile_m27_Check_Shield_Bonus", "bool (__fastcall *) (Tile * this)" -ignore, 0x5f3448, 0x6032DF, 0x5F3378, "CHECK_SHIELD_BONUS_TO_CAN_SPAWN_RES_RETURN", "int" - +JOB, GOG ADDR, STEAM ADDR, PCG ADDR, NAME, TYPE +define, 0, 1, 2, "exe_version_index", "int" +define, 0x9C3508, 0x9E5D08, 0x9C34C8, "p_bic_data", "BIC *" +define, 0xA52E80, 0xA75680, 0xA52E40, "p_units", "Units *" +define, 0xA52DD4, 0xA755D0, 0xA52D94, "p_tile_units", "TileUnits *" +define, 0xA52E68, 0xA75668, 0xA52E28, "p_cities", "Cities *" +define, 0xA52E50, 0xA75650, 0xA52E10, "p_colonies", "Base_List *" +define, 0xA52E98, 0xA75698, 0xA52E58, "leaders", "Leader *" +define, 0xB3CEA0, 0xB5F6A0, 0xB3CE60, "city_sprites", "Sprite *" +define, 0xB3E7D0, 0xB60FD0, 0xB3E790, "destroyed_city_sprites", "Sprite *" +define, 0x9F8700, 0xA1AF00, 0x9F86C0, "p_main_screen_form", "Main_Screen_Form *" +define, 0xA52658, 0xA74E50, 0xA52618, "p_game", "Game *" +define, 0xCB8B38, 0xCDB440, 0xCB8AF8, "temp_ui_strs", "char[10][4096]" +define, 0x665188, 0x68219C, 0x665188, "ADDR_ADDR_OUTPUTDEBUGSTRINGA", "void *" +define, 0x665280, 0x6822E0, 0x665280, "ADDR_ADDR_GETASYNCKEYSTATE", "void *" +define, 0x665168, 0x682130, 0x665168, "ADDR_ADDR_GETPROCADDRESS", "void *" +define, 0x6650E4, 0x6820B8, 0x6650E4, "ADDR_ADDR_GETMODULEHANDLEA", "void *" +define, 0x66527C, 0x6822E4, 0x66527C, "ADDR_ADDR_MESSAGEBOXA", "void *" +repl vptr, 0x73A8FC, 0x756C74, 0x73A8D4, "init_floating_point", "void (__stdcall *) (void)" +define, 0x5B6B01, 0x5C5458, 0x5B6811, "ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK", "void *" +define, 0x569503, 0x575933, 0x5694B3, "ADDR_UNIT_COUNT_CHECK", "void *" +define, 0x594B35, 0x5A2357, 0x594855, "ADDR_ERA_COUNT_CHECK", "void *" +define, 0x5601EF, 0x56C2E3, 0x56019F, "ADDR_SCIENCE_AGE_BUG_PATCH", "void *" +define, 0x4CD0B1, 0x4D5151, 0x4CD171, "ADDR_PEDIA_TEXTURE_BUG_PATCH", "void *" +define, 0x5640AC, 0x570385, 0x56405C, "ADDR_AUTORAZE_BYPASS", "void *" +repl vptr, 0x66CB50, 0x689C3C, 0x66CB50, "Leader_impl_would_raze_city", "bool (__fastcall *) (Leader * this, int edx, City * city)" +repl vptr, 0x66B44C, 0x68854C, 0x66B44C, "Main_Screen_Form_handle_left_click_on_map_1", "void (__fastcall *) (Main_Screen_Form * this, int edx, int param_1, int param_2)" +inlead, 0x4EA210, 0x4F3000, 0x4EA2D0, "Main_Screen_Form_handle_right_click_on_tile", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" +inlead, 0x4E8850, 0x4F14E0, 0x4E8910, "Main_Screen_Form_open_right_click_menu", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" +define, 0x499FE0, 0x49F9F0, 0x49A070, "is_online_game", "char (__stdcall *) (void)" +define, 0x437A70, 0x439620, 0x437AF0, "tile_at", "Tile * (__cdecl *) (int x, int y)" +define, 0x426C80, 0x4283C0, 0x426D00, "TileUnits_TileUnitID_to_UnitID", "int (__fastcall *) (TileUnits * this, int edx, int tile_unit_id, int * out_UnitItem_field_0)" +inlead, 0x5C1410, 0x5CFFA0, 0x5C1120, "Unit_bombard_tile", "void (__fastcall *) (Unit * this, int edx, int x, int y)" +inlead, 0x5BE820, 0x5CD420, 0x5BE530, "Unit_get_defense_strength", "int (__fastcall *) (Unit * this)" +inlead, 0x5BB650, 0x5CA190, 0x5BB360, "Unit_is_visible_to_civ", "char (__fastcall *) (Unit * this, int edx, int civ_id, int param_2)" +define, 0x5EA6C0, 0x5F9F10, 0x5EA5F0, "Tile_has_city", "char (__fastcall *) (Tile * this)" +define, 0x5EA6E0, 0x5F9F30, 0x5EA610, "Tile_has_colony", "bool (__fastcall *) (Tile * this)" +define, 0x5BE5B0, 0x5CD180, 0x5BE2C0, "Unit_get_max_hp", "int (__fastcall *) (Unit * this)" +define, 0x5E4EF0, 0x5F4750, 0x5E4E20, "UnitType_has_ability", "bool (__fastcall *) (UnitType * this, int edx, enum UnitTypeAbilities a)" +define, 0x5CDDF0, 0x5DCEB0, 0x5CDD10, "get_max_move_points", "int (__cdecl *) (UnitType * unit_type, int civ_id)" +inlead, 0x5BE470, 0x5CD030, 0x5BE180, "Unit_get_max_move_points", "int (__fastcall *) (Unit * this)" +define, 0x60B370, 0x625850, 0x60B290, "Button_set_tooltip", "int (__fastcall *) (Button * this, int edx, char * str)" +define, 0x5FC420, 0x60FC10, 0x5FC300, "PCX_Image_construct", "PCX_Image * (__fastcall *) (PCX_Image * this)" +define, 0x5FC820, 0x610360, 0x5FC700, "PCX_Image_read_file", "int (__fastcall *) (PCX_Image * this, int edx, char * file_path, PCX_Color_Table * out_color_table, int ct_start, int ct_count, unsigned flags)" +define, 0x5F7E50, 0x608170, 0x5F7D80, "Sprite_construct", "Sprite * (__fastcall *) (Sprite * this)" +define, 0x5F7F90, 0x6083D0, 0x5F7EC0, "Sprite_slice_pcx", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * img, int up_left_x, int up_left_y, int w, int h, int arg6, int arg7)" +define, 0x49FC50, 0x4A6790, 0x49FCE0, "get_popup_form", "PopupForm * (__stdcall *) ()" +define, 0x61C5A0, 0x63E390, 0x61C4D0, "set_popup_str_param", "int (__cdecl *) (int param_index, char * str, int param_3, int param_4)" +define, 0x61C570, 0x63E350, 0x61C4A0, "set_popup_int_param", "int (__cdecl *) (int param_index, int value)" +inlead, 0x611530, 0x62DAF0, 0x611460, "show_popup", "int (__fastcall *) (void * this, int edx, int param_1, int param_2)" +define, 0x4ACD20, 0x4B3CC0, 0x4ACDB0, "City_zoom_to", "void (__fastcall *) (City *this, int edx, int param_1)" +inlead, 0x4ACB50, 0x4B3AF0, 0x4ACBE0, "City_has_improvement", "char (__fastcall *) (City * this, int edx, int i_improvement, char include_auto_improvements)" +inlead, 0x4E6DB0, 0x4EF820, 0x4E6E70, "Main_Screen_Form_perform_action_on_tile", "void (__fastcall *) (Main_Screen_Form * this, int edx, enum Unit_Mode_Actions action, int x, int y)" +inlead, 0x550BB0, 0x55BCE0, 0x550B60, "Main_GUI_set_up_unit_command_buttons", "void (__fastcall *) (Main_GUI * this)" +inlead, 0x5577F0, 0x563600, 0x5577A0, "Main_GUI_handle_button_press", "void (__fastcall *) (Main_GUI * this, int edx, int button_id)" +inlead, 0x4E05F0, 0x4E8F90, 0x4E06B0, "Main_Screen_Form_handle_key_down", "int (__fastcall *) (Main_Screen_Form * this, int edx, int char_code, int virtual_key_code)" +inlead, 0x6268A0, 0x64B410, 0x624C00, "handle_cursor_change_in_jgl", "int (__stdcall *) ()" +inlead, 0x555F80, 0x561B90, 0x555F30, "Main_GUI_handle_click_in_status_panel", "void (__fastcall *) (Main_GUI * this, int edx, int mouse_x, int mouse_y)" +define, 0x54CAD0, 0x557980, 0x54CB30, "get_font", "Object_66C3FC * (__cdecl *) (int size, FontStyleFlags style)" +define, 0x5FD750, 0x611850, 0x5FD630, "PCX_Image_draw_centered_text", "int (__fastcall *) (PCX_Image *this, int edx, Object_66C3FC * font, char * str, int x, int y, int width, int str_len)" +inlead, 0x4196F0, 0x41A5D0, 0x419770, "City_Form_draw", "void (__fastcall *) (City_Form * this)" +inlead, 0x41B4C0, 0x41C610, 0x41B540, "City_Form_print_production_info", "void (__fastcall *) (City_Form *this, int edx, String256 * out_strs, int str_capacity)" +define, 0x4ACD70, 0x4B3D30, 0x4ACE00, "City_get_order_cost", "int (__fastcall *) (City * this)" +define, 0x4ACD40, 0x4B3CE0, 0x4ACDD0, "City_get_order_progress", "int (__fastcall *) (City * this)" +inlead, 0x57F360, 0x58C080, 0x57F0C0, "Trade_Net_get_movement_cost", "int (__fastcall *) (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned flags, int neighbor_index, Trade_Net_Distance_Info * dist_info)" +define, 0x57F0A0, 0x58BDB0, 0x57EE00, "Trade_Net_have_trade_connection", "bool (__fastcall *) (Trade_Net * this, int edx, City * a, City * b, int civ_id)" +define, 0x57F130, 0x58BE40, 0x57EE90, "Trade_Net_is_tile_connected_to_city", "bool (__fastcall *) (Trade_Net * this, int edx, City * city, int tile_x, int tile_y)" +inlead, 0x591BB0, 0x59F1D0, 0x5918D0, "do_save_game", "int (__cdecl *) (char const * file_path, char param_2, GUID * guid)" +define, 0x4BCFF0, 0x4C4660, 0x4BD080, "City_recompute_happiness", "void (__fastcall *) (City * this)" +define, 0x4B05D0, 0x4B7590, 0x4B0660, "City_recompute_production", "void (__fastcall *) (City * this)" +define, 0x4B07C0, 0x4B7770, 0x4B0850, "City_recompute_commerce", "void (__fastcall *) (City * this)" +inlead, 0x4B0B70, 0x4B7B20, 0x4B0C00, "City_recompute_culture_income", "void (__fastcall *) (City * this)" +inlead, 0x4B2680, 0x4B9600, 0x4B2710, "City_update_culture", "void (__fastcall *) (City * this)" +define, 0x4B0C60, 0x4B7C10, 0x4B0CF0, "City_recompute_cultural_level", "void (__fastcall *) (City *this, int edx, char param_1, char param_2, char param_3)" +define, 0x4B10F0, 0x4B80A0, 0x4B1180, "recompute_food_eaten_production_commerce_and_happiness", "void (__fastcall *) (City *this)" +inlead, 0x55A560, 0x566470, 0x55A510, "Leader_recompute_auto_improvements", "void (__fastcall *) (Leader * this)" +inlead, 0x539030, 0x543650, 0x5390B0, "Game_get_wonder_city_id", "int (__fastcall *) (Game * this, int edx, int wonder_improvement_id)" +define, 0x55A62E, 0x566538, 0x55A5DE, "ADDR_SMALL_WONDER_FREE_IMPROVS_RETURN", "int" +define, 0x55A5C6, 0x5664D4, 0x55A576, "ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER", "void *" +repl vptr, 0x66B46C, 0x68856C, 0x66B46C, "Main_Screen_Form_handle_key_up", "int (__fastcall *) (Main_Screen_Form * this, int edx, int virtual_key_code)" +define, 0x4DAA70, 0x4E3430, 0x4DAB30, "Main_Screen_Form_issue_command", "char (__fastcall *) (Main_Screen_Form * this, int edx, int command, Unit * unit)" +define, 0x609D60, 0x6233C0, 0x609C80, "clear_something_1", "void (__stdcall *) ()" +define, 0x6207B0, 0x644F10, 0x6206E0, "Timer_clear", "void (__fastcall *) (Timer * this)" +inlead, 0x55EFA0, 0x56B030, 0x55EF50, "Leader_can_do_worker_job", "char (__fastcall *) (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing)" +define, 0x56A7C0, 0x576C60, 0x56A770, "Leader_can_build_unit", "bool (__fastcall *) (Leader * this, int edx, int unit_type_id, int param_2, bool allow_kings)" +define, 0x455288, 0x457458, 0x455308, "ADDR_CHECK_ARTILLERY_IN_CITY", "void *" +inlead, 0x455140, 0x457310, 0x4551C0, "Unit_ai_move_artillery", "void (__fastcall *) (Unit * this)" +define, 0x5E6E50, 0x5F66A0, 0x5E6D80, "neighbor_index_to_diff", "void (__cdecl *) (int neighbor_index, int * out_x, int * out_y)" +define, 0x5B3040, 0x5C1970, 0x5B2D50, "Unit_set_state", "void (__fastcall *) (Unit * this, int edx, int new_state)" +define, 0x5B2F10, 0x5C1840, 0x5B2C20, "Unit_set_escortee", "void (__fastcall *) (Unit * this, int edx, int escortee)" +inlead, 0x44D980, 0x44F9E0, 0x44DA00, "Unit_seek_colony", "int (__fastcall *) (Unit *this, int edx, bool for_own_defense, int max_distance)" +repl call, 0x4527BE, 0x4548E3, 0x45283E, "Tile_has_district_or_colony", "" +define, 0xA526B4, 0xA74EAC, 0xA52674, "p_rand_object", "void *" +define, 0x60BAB0, 0x626440, 0x60B9E0, "rand_int", "int (__fastcall *) (void * this, int edx, int lim)" +inlead, 0x42C8A0, 0x42E430, 0x42C920, "City_ai_choose_production", "void (__fastcall *) (City * this, int edx, City_Order * out)" +inlead, 0x4C04E0, 0x4C7AB0, 0x4C0570, "City_can_build_unit", "bool (__fastcall *) (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings)" +repl call, 0x5C536C, 0x5D404D, 0x5C507C, "Unit_get_max_move_points_for_disembarking", "" +inlead, 0x5C5420, 0x5D4120, 0x5C5130, "Unit_disembark_passengers", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +define, 0xCAA330, 0xCCCB98, 0xCAA2F0, "p_null_tile", "Tile *" +define, 0x45A35F, 0x45C56F, 0x45A3DF, "ADDR_HOUSEBOAT_BUG_PATCH", "byte *" +define, 0x45A386, 0x45C596, 0x45A406, "ADDR_HOUSEBOAT_BUG_PATCH_END", "byte *" +define, 0xB72888, 0xB950A8, 0xB72848, "p_original_trade_net", "Trade_Net *" +inlead, 0x580540, 0x58D270, 0x5802A0, "Trade_Net_set_unit_path", "int (__fastcall *) (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp)" +define, 0x5B3290, 0x5C1BE0, 0x5B2FA0, "Unit_pop_next_move_from_path", "byte (__fastcall *) (Unit * this)" +inlead, 0x45FED0, 0x4622A0, 0x45FF50, "Unit_ai_move_leader", "void (__fastcall *) (Unit * this)" +define, 0x5B2B20, 0x5C1440, 0x5B2830, "Unit_next_escorter_id", "int (__fastcall *) (Unit * this, int edx, int * index, bool begin_iterating)" +define, 0x5BC300, 0x5CAE50, 0x5BC010, "Unit_disband", "void (__fastcall *) (Unit * this)" +inlead, 0x5C00A0, 0x5CEC20, 0x5BFDB0, "Unit_can_hurry_production", "bool (__fastcall *) (Unit * this, int edx, City * city, bool exclude_cheap_improvements)" +inlead, 0x5B3AB0, 0x5C2400, 0x5B37C0, "Unit_can_pillage", "bool (__fastcall *) (Unit *this, int edx, int tile_x, int tile_y)" +inlead, 0x5CCBB0, 0x5DBB50, 0x5CC8C0, "Unit_can_pass_between", "bool (__fastcall *) (Unit *this, int edx, int from_x, int from_y, int to_x, int to_y, byte param_5)" +define, 0x5C0420, 0x5CEFC0, 0x5C0130, "Unit_hurry_production", "void (__fastcall *) (Unit * this)" +define, 0x5C0300, 0x5CEE90, 0x5C0010, "Unit_ai_can_start_science_age", "bool (__fastcall *) (Unit * this)" +define, 0x5C03B0, 0x5CEF50, 0x5C00C0, "Unit_start_science_age", "void (__fastcall *) (Unit * this)" +inlead, 0x5BC980, 0x5CB510, 0x5BC690, "Unit_ai_can_form_army", "bool (__fastcall *) (Unit * this)" +define, 0x5BCA20, 0x5CB5B0, 0x5BC730, "Unit_form_army", "Unit * (__fastcall *) (Unit * this)" +repl vptr, 0x66DD28, 0x68AE08, 0x66DD28, "impl_ai_is_good_army_addition", "bool (__fastcall *) (Unit * this, int edx, Unit * candidate)" +repl vptr, 0x666578, 0x6835CC, 0x666578, "PopupForm_set_text_key_and_flags", "void (__fastcall *) (PopupForm * this, int edx, char * script_path, char * text_key, int param_3, int param_4, int param_5, int param_6)" +define, 0xA35200, 0xA57A00, 0xA351C0, "p_diplo_form", "DiploForm *" +define, 0x649A8B, 0x6683E1, 0x6499CF, "new", "void * (__cdecl *) (unsigned num_bytes)" +define, 0x666AC4, 0x683B1C, 0x666AC4, "p_trade_offer_vtable", "TradeOfferVTable *" +define, 0x440EE0, 0x442CD0, 0x440F60, "Leader_consider_trade", "DiploMessage (__fastcall *) (Leader * this, int edx, TradeOfferList * receiving, TradeOfferList * paying, int other_party_civ_id, byte param_4, bool param_5, byte param_6, byte param_7, int * out_advantage, int * param_9, int * param_10)" +define, 0x509325, 0x51334D, 0x5093C5, "ADDR_SETUP_INITIAL_GOLD_ASK_RETURN", "int" +define, 0x50BCC8, 0x515DA1, 0x50BD68, "ADDR_SETUP_MODIFY_GOLD_ASK_RETURN", "int" +define, 0x509669, 0x51366E, 0x509709, "ADDR_SETUP_INITIAL_GOLD_OFFER_RETURN", "int" +define, 0x50BF10, 0x516008, 0x50BFB0, "ADDR_SETUP_MODIFY_GOLD_OFFER_RETURN", "int" +define, 14, 14, 14, "TRADE_GOLD_SETTER_IS_LUMP_SUM_OFFSET", "int" +define, 0x50BEBD, 0x515FB4, 0x50BF5D, "ADDR_PRINT_GOLD_AMOUNT_1", "byte *" +define, 0x50BC75, 0x515D4D, 0x50BD15, "ADDR_PRINT_GOLD_AMOUNT_2", "byte *" +inlead, 0x5F3160, 0x603000, 0x5F3090, "Map_check_city_location", "CityLocValidity (__fastcall *) (Map *this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile)" +repl vptr, 0x66C1E8, 0x6892D8, 0x66C1E8, "DiploForm_m68_Show_Dialog", "int (__fastcall *) (DiploForm * this, int edx, int param_1, void * param_2, void * param_3)" +repl vptr, 0x66C220, 0x689310, 0x66C220, "DiploForm_m82_handle_key_event", "void (__fastcall *) (DiploForm * this, int edx, int virtual_key_code, int is_down)" +define, 0xA526C0, 0xA74EB8, 0xA52680, "p_player_bits", "unsigned *" +define, 0x50D830, 0x517970, 0x50D8D0, "DiploForm_close", "void (__fastcall *) (DiploForm *)" +inlead, 0x505F40, 0x50FD30, 0x505FE0, "DiploForm_do_diplomacy", "void (__fastcall *) (DiploForm * this, int edx, int diplo_message, int param_2, int civ_id, int do_not_request_audience, int war_negotiation, int disallow_proposal, TradeOfferList * our_offers, TradeOfferList * their_offers)" +define, 0x440E10, 0x442C00, 0x440E90, "Leader_ai_would_meet_with", "bool (__fastcall *) (Leader * this, int edx, int civ_id)" +repl vptr, 0x66C130, 0x689220, 0x66C130, "DiploForm_m22_Draw", "void (__fastcall *) (DiploForm * this)" +define, 0x609F50, 0x623C40, 0x609E70, "Button_construct", "Button * (__fastcall *) (Button * this)" +define, 0x60B050, 0x625450, 0x60AF70, "Button_initialize", "int (__fastcall *) (Button * this, int edx, char * text, int control_id, int x, int y, int width, int height, Base_Form * parent, int param_8)" +define, 0x5161C0, 0x51F9B0, 0x516260, "DiploForm_set_their_message", "int (__fastcall *) (DiploForm * this, int edx, DiploMessage msg, int message_arg, int param_3)" +define, 0x516260, 0x51FA50, 0x516300, "DiploForm_reset_our_message_choices", "void (__fastcall *) (DiploForm *)" +define, 0x649FA7, 0x6076E0, 0x649EEB, "civ_prog_malloc", "void * (__cdecl *) (unsigned _Size)" +define, 0x649EBE, 0x668816, 0x649E02, "civ_prog_free", "void (__cdecl *) (void * p)" +inlead, 0x61A480, 0x63B9F0, 0x61A3B0, "Context_Menu_open", "int (__fastcall *) (Context_Menu * this, int edx, int x, int y, int param_3)" +define, 0x4E993C, 0x4F273A, 0x4E99FC, "ADDR_OPEN_UNIT_MENU_RETURN", "int" +define, 0x61B0C0, 0x63C940, 0x61AFF0, "Context_Menu_widen_for_text", "void (__fastcall *) (Context_Menu * this, int edx, char * text)" +inlead, 0x61A110, 0x63B420, 0x61A040, "Context_Menu_add_item_and_set_color", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, char * text, int red)" +define, 0x61A160, 0x63B480, 0x61A090, "Context_Menu_add_separator", "int (__fastcall *) (Context_Menu * this, int edx, int item_id)" +inlead, 0x45C750, 0x45EA70, 0x45C7D0, "Unit_ai_move_terraformer", "void (__fastcall *) (Unit * this)" +inlead, 0x4B1DC0, 0x4B8D50, 0x4B1E50, "City_requires_improvement_to_grow", "int (__fastcall *) (City * this)" +inlead, 0x4DD530, 0x4E5F00, 0x4DD5F0, "maybe_show_improvement_needed_for_growth_dialog", "void (__fastcall *) (void * this, int edx, City * city, int * param_2)" +repl call, 0x5213E3, 0x52B3F3, 0x521483, "City_requires_improvement_to_grow_besides_neighborhood", "" +inlead, 0x5C1AD0, 0x5D0670, 0x5C17E0, "Unit_can_perform_command", "bool (__fastcall *) (Unit * this, int edx, int unit_command_value)" +inlead, 0x5B39D0, 0x5C2320, 0x5B36E0, "Unit_join_city", "void (__fastcall *) (Unit * this, int edx, City * city)" +define, 0x5C0740, 0x5CF2E0, 0x5C0450, "Unit_upgrade", "Unit * (__fastcall *) (Unit * this, int edx, bool ignore_cost)" +define, 0x5C04D0, 0x5CF070, 0x5C01E0, "Unit_get_upgrade_cost", "int (__fastcall *) (Unit * this)" +define, 0xCADC18, 0xCD0510, 0xCADBD8, "script_dot_txt_file_path", "char *" +inlead, 0x5B5CD0, 0x5C4620, 0x5B59E0, "Unit_can_move_to_adjacent_tile", "AdjacentMoveValidity (__fastcall *) (Unit * this, int edx, int neighbor_index, int param_2)" +define, 0x5F3F50, 0x603DD0, 0x5F3E80, "Map_compute_neighbor_index", "int (__fastcall *) (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim)" +repl call, 0x5CCC85, 0x5DBC1F, 0x5CC995, "Map_compute_neighbor_index_for_pass_between", "" +repl call, 0x42FC69, 0x43173F, 0x42FCE9, "Improvement_has_wonder_com_bonus_for_ai_prod", "" +define, 0x5FEF70, 0x613F70, 0x5FEE50, "PCX_Image_draw_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int str_len)" +repl call, 0x5AAB93, 0x5B9899, 0x5AA8A3, "PCX_Image_draw_no_tile_info", "" +repl call, 0x5AB00A, 0x5B97E8, 0x5AAD1A, "PCX_Image_draw_tile_info_terrain", "" +define, 0x4E3C60, 0x4EC4B0, 0x4E3D20, "Main_Screen_Form_get_tile_coords_under_mouse", "int (__fastcall *) (Main_Screen_Form * this, int edx, int mouse_x, int mouse_y, int * out_tile_x, int * out_tile_y)" +inlead, 0x5AA820, 0x5B8F40, 0x5AA530, "open_tile_info", "void (__fastcall *) (void * this, int edx, int mouse_x, int mouse_y, int civ_id)" +inlead, 0x53A860, 0x544B80, 0x53A8E0, "get_anarchy_length", "int (__stdcall *) (int leader_id)" +repl call, 0x5557DE, 0x56136E, 0x55578E, "PCX_Image_process_tech_ga_status", "" +define, 0x5FE560, 0x612F50, 0x5FE440, "PCX_Image_process_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str)" +define, 0xA526AC, 0xA74EA4, 0xA5266C, "p_current_turn_no", "int *" +define, 0xCADC0C, 0xCD0504, 0xCADBCC, "p_labels", "char ***" +define, 497, 498, 497, "LBL_GOLDEN_AGE", "int" +define, 0xA5267C, 0xA74E74, 0xA5263C, "p_toggleable_rules", "int *" +define, 0xA52680, 0xA74E78, 0xA52640, "p_debug_mode_bits", "unsigned *" +repl call, 0x569A10, 0x575E4A, 0x5699C0, "Unit_check_king_ability_while_spawning", "" +define, 0x5BC8B0, 0x5CB430, 0x5BC5C0, "Unit_has_ability", "bool (__fastcall *) (Unit * this, int edx, enum UnitTypeAbilities a)" +define, 0xA52658, 0xA74E50, 0xA52618, "p_match", "void *" +inlead, 0x442480, 0x444250, 0x442500, "Match_ai_eval_city_location", "int (__fastcall *) (void * this, int edx, int x, int y, int civ_id, bool param_4, int * out_breakdown)" +define, 0x430FBA, 0x432A6D, 0x43103A, "ADDR_INTERCEPT_AI_IMPROV_VALUE", "void *" +define, 7, 6, 7, "AI_CONSIDERATION_INTERCEPT_LEN", "int" +define, 0x433C7C, 0x435712, 0x433CFC, "ADDR_INTERCEPT_AI_UNIT_VALUE", "void *" +inlead, 0x4B1190, 0x4B8140, 0x4B1220, "City_compute_corrupted_yield", "int (__fastcall *) (City * this, int edx, int gross_yield, bool is_production)" +define, 0x610B30, 0x62CE00, 0x610A60, "PopupForm_add_text", "byte (__fastcall *) (PopupForm * this, int edx, char * text, bool param_2)" +define, 0x6193A0, 0x639AD0, 0x6192D0, "PopupSelection_add_item", "int (__fastcall *) (PopupSelection * this, int edx, char * text, int value)" +inlead, 0x59AB50, 0x5A8660, 0x59A870, "load_scenario", "unsigned (__fastcall *) (BIC * this, int edx, char * param_1, unsigned * param_2)" +define, 0x59B499, 0x5A8FD9, 0x59B1B9, "ADDR_LOAD_SCENARIO_PREVIEW_RETURN", "int" +define, 0x59AD27, 0x5A8872, 0x59AA47, "ADDR_LOAD_SCENARIO_RESUME_SAVE_2_RETURN", "int" +repl vptr, 0x6659F8, 0x682A5C, 0x6659F8, "City_Form_m82_handle_key_event", "void (__fastcall *) (City_Form * this, int edx, int virtual_key_code, int is_down)" +define, 0x437540, 0x4390F0, 0x4375C0, "Improvement_has_wonder_flag", "bool (__fastcall *) (Improvement * this, int edx, enum ImprovementTypeWonderFeatures flag)" +define, 0x437710, 0x4392F0, 0x437790, "UnitType_has_ai_strategy", "bool (__fastcall *) (UnitType * this, int edx, byte n)" +repl call, 0x431038, 0x432AE7, 0x4310B8, "UnitType_has_strat_0_for_ai_prod", "" +define, 0x44CE50, 0x44EE40, 0x44CED0, "Unit_find_transport", "Unit * (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C5F70, 0x5D4D50, 0x5C5C80, "Unit_select_transport", "Unit * (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, bool should_show_popup)" +inlead, 0x5C5110, 0x5D3DF0, 0x5C4E20, "Unit_load", "void (__fastcall *) (Unit * this, int edx, Unit * transport)" +define, 0xA526BC, 0xA74EB4, 0xA5267C, "p_human_player_bits", "int *" +inlead, 0x5F8130, 0x6085D0, 0x5F8060, "Sprite_draw_on_map", "int (__fastcall *) (Sprite * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7)" +repl vptr, 0x66A554, 0x687660, 0x66A554, "Map_Renderer_m19_Draw_Tile_by_XY_and_Flags", "void (__fastcall *) (Map_Renderer * this, int edx, int param_1, int pixel_x, int pixel_y, Map_Renderer * map_renderer, int param_5, int tile_x, int tile_y, int param_8)" +repl vptr, 0x66A624, 0x687730, 0x66A624, "Map_Renderer_m71_Draw_Tiles", "void (__fastcall *) (Map_Renderer * this, int edx, int param_1, int param_2, int param_3)" +repl vptr, 0x66B520, 0x688620, 0x66B520, "Main_Screen_Form_m82_handle_key_event", "void (__fastcall *) (Main_Screen_Form * this, int edx, int virtual_key_code, int is_down)" +repl call, 0x5C190B, 0x5D0493, 0x5C161B, "Unit_get_move_points_after_airdrop", "" +repl call, 0x4D93E0, 0x4E1D70, 0x4D94A0, "Unit_get_move_points_after_set_to_intercept", "" +repl vptr, 0x66E738, 0x68B810, 0x66E738, "Parameters_Form_m68_Show_Dialog", "int (__fastcall *) (Parameters_Form * this, int edx, int arg_1, void * arg_2, void * arg_3)" +define, 0x598580, 0x5A5E30, 0x5982A0, "BIC_get_asset_path", "char * (__fastcall *) (BIC * this, int edx, char * str, bool show_error_popup)" +define, 0x5F8080, 0x608500, 0x5F7FB0, "Sprite_slice_pcx_with_color_table", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * img, int up_left_x, int up_left_y, int w, int h, int arg6, int arg7)" +define, 0x5FD320, 0x611210, 0x5FD200, "PCX_Image_set_font", "int (__fastcall *) (PCX_Image * this, int edx, Object_66C3FC * font, int arg_2, int arg_3, int arg_4)" +define, 0x57EEC4, 0x58BBE8, 0x57EC24, "ADDR_INTERCEPT_SET_RESOURCE_BIT", "void *" +inlead, 0x4ADE30, 0x4B4E10, 0x4ADEC0, "City_has_resource", "bool (__fastcall *) (City * this, int edx, int resource_id)" +define, 0x4ADDC0, 0x4B4DA0, 0x4ADE50, "City_has_trade_connection_to_capital", "bool (__fastcall *) (City * this)" +define, 0x55EEB0, 0x56AF50, 0x55EE60, "Leader_has_resources_for_job_at", "bool (__fastcall *) (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y)" +inlead, 0x57E450, 0x58B1A0, 0x57E1B0, "Trade_Net_recompute_resources", "void (__fastcall *) (Trade_Net * this, int edx, bool skip_popups)" +define, 0x561440, 0x56D5A0, 0x5613F0, "Leader_has_tech", "bool (__fastcall *) (Leader * this, int edx, int id)" +inlead, 0x4BED80, 0x4C6350, 0x4BEE10, "City_cycle_specialist_type", "bool (__fastcall *) (City * this, int edx, int mouse_x, int mouse_y, Citizen * citizen, City_Form * city_form)" +inlead, 0x4B1C10, 0x4B8BC0, 0x4B1CA0, "City_get_total_pollution", "int (__fastcall *) (City * this)" +define, 0x4B1B40, 0x4B8B00, 0x4B1BD0, "City_get_pollution_from_buildings", "int (__fastcall *) (City * this)" +inlead, 0x4B1A50, 0x4B8A10, 0x4B1AE0, "City_get_pollution_from_pop", "int (__fastcall *) (City * this)" +inlead, 0x4ACF40, 0x4B3F20, 0x4ACFD0, "City_add_or_remove_improvement", "void (__fastcall *) (City * this, int edx, int improv_id, int add, bool param_3)" +define, 0x57E943, 0x58B68E, 0x57E6A3, "ADDR_RESOURCE_TILE_COUNT_MASK", "void *" +define, 0x57E5EB, 0x58B328, 0x57E34B, "ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE", "void *" +define, 0x5DA1A0, 0x5E9710, 0x5DA0D0, "Tile_get_resource_visible_to", "int (__fastcall *) (Tile * this, int edx, int civ_id)" +inlead, 0x5EA7F0, 0x5FA040, 0x5EA720, "Tile_m17_Check_Irrigation", "bool (__fastcall *) (Tile * this, int edx, int visible_to_civ_id)" +define, 0x5D16A0, 0x5E0900, 0x5D15D0, "Map_get_tile", "Tile * (__fastcall *) (Map * this, int edx, int index)" +repl call, 0x57E602, 0x58B345, 0x57E362, "Map_get_tile_when_recomputing_resources_1", "" +repl call, 0x57E629, 0x58B36C, 0x57E389, "Map_get_tile_when_recomputing_resources_2", "" +repl call, 0x57E618, 0x58B35B, 0x57E378, "Map_get_tile_when_recomputing_resources_3", "" +repl call, 0x57E64A, 0x58B397, 0x57E3AA, "Map_get_tile_when_recomputing_resources_4", "" +repl call, 0x57E672, 0x58B3B7, 0x57E3D2, "Map_get_tile_when_recomputing_resources_5", "" +repl call, 0x57E679, 0x58B3BE, 0x57E3D9, "Tile_get_visible_resource_when_recomputing", "" +inlead, 0x4A47C0, 0x4AB470, 0x4A4850, "Fighter_begin", "void (__fastcall *) (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender)" +define, 0x441ED0, 0x443CC0, 0x441F50, "Map_get_x_dist", "int (__fastcall *) (Map * this, int edx, int x1, int x2)" +define, 0x437970, 0x439520, 0x4379F0, "Map_get_y_dist", "int (__fastcall *) (Map * this, int edx, int y1, int y2)" +inlead, 0x5D7180, 0x5E65E0, 0x5D70B0, "Map_calc_food_yield_at", "int (__fastcall *) (Map * this, int edx, int tile_x, int tile_y, int tile_base_type, int civ_id, int imagine_fully_improved, City * city)" +inlead, 0x5D75F0, 0x5E6A20, 0x5D7520, "Map_calc_shield_yield_at", "int (__fastcall *) (Map *this, int edx, int tile_x, int tile_y, int civ_id, City *city, int param_5, int param_6)" +define, 0x5663C0, 0x572730, 0x566370, "Leader_create_city", "City * (__fastcall *) (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6)" +inlead, 0x5D3030, 0x5E2330, 0x5D2F60, "Map_process_after_placing", "void (__fastcall *) (Map * this, int edx, bool param_1)" +inlead, 0x5BBBC0, 0x5CA720, 0x5BB8D0, "Unit_despawn", "void (__fastcall *) (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7)" +inlead, 0x5BD220, 0x5CBDE0, 0x5BCF30, "Unit_move", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +define, 0x558700, 0x564590, 0x5586B0, "Main_GUI_label_loading_bar", "void (__fastcall *) (Main_GUI * this, int edx, int param_1, char *text)" +define, 0x48DE43, 0x4920E3, 0x48DED3, "ADDR_TURN_METALIMIT_1", "byte *" +define, 0x4946E1, 0x4990CA, 0x494771, "ADDR_TURN_METALIMIT_2", "byte *" +define, 0x54E2E0, 0x55925B, 0x54E340, "ADDR_TURN_METALIMIT_3", "byte *" +define, 0x54E2E7, 0x559262, 0x54E347, "ADDR_TURN_METALIMIT_4", "byte *" +define, 0x584163, 0x59100F, 0x583EC3, "ADDR_TURN_METALIMIT_5", "byte *" +define, 0x5817B2, 0x58E4E2, 0x581512, "ADDR_TURN_METALIMIT_6", "byte *" +define, 0x492100, 0x496751, 0x492190, "ADDR_TURN_METALIMIT_7", "byte *" +inlead, 0x4ACA50, 0x4B39F0, 0x4ACAE0, "City_get_net_commerce", "int (__fastcall *) (City * this, int edx, int kind, bool include_science_age)" +inlead, 0x55DFD0, 0x56A070, 0x55DF80, "Leader_pay_unit_maintenance", "void (__fastcall *) (Leader * this)" +define, 0x55CFB0, 0x569040, 0x55CF60, "Leader_sum_improvements_maintenance", "int (__fastcall *) (Leader * this, int edx, int govt_id)" +define, 0x560972, 0x56CA7F, 0x560922, "ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT", "byte *" +define, 0x55DD50, 0x569DF0, 0x55DD00, "Leader_compute_income", "int (__fastcall *) (Leader * this)" +define, 0x5612F0, 0x56D420, 0x5612A0, "Leader_recompute_economy", "void (__fastcall *) (Leader * this)" +repl call, 0x560C16, 0x56CD25, 0x560BC6, "Leader_sum_improv_maintenance_to_pay_1", "" +repl call, 0x560C64, 0x56CDA8, 0x560C14, "Leader_sum_improv_maintenance_to_pay_2", "" +inlead, 0x4ACDF0, 0x4B3DD0, 0x4ACE80, "City_get_improvement_maintenance", "int (__fastcall *) (City * this, int edx, int improv_id)" +define, 0x4C2350, 0x4C9B30, 0x4C2370, "Leader_set_treasury", "void (__fastcall *) (Leader * this, int edx, int amount)" +define, 0x4B3400, 0x4BA3A0, 0x4B3490, "City_sell_improvement", "void (__fastcall *) (City * this, int edx, int improv_id, bool set_status_bit)" +define, 0x9E85F0, 0xA0ADF0, 0x9E85B0, "p_civilopedia_form", "Civilopedia_Form *" +define, 0x4CBE10, 0x4D3E50, 0x4CBED0, "Civilopedia_open", "void (__fastcall *) (void * this, int edx, char * key, bool param_2)" +define, 0x53A960, 0x544C80, 0x53A9E0, "get_unit_support_info", "void (__stdcall *) (int civ_id, int govt_id, int * out_cost_per_unit, int * out_count_free_units)" +define, 0x55D2A0, 0x569330, 0x55D250, "Leader_get_free_unit_count", "int (__fastcall *) (Leader * this, int edx, int govt_id)" +inlead, 0x55D030, 0x5690C0, 0x55CFE0, "Leader_count_maintenance_free_units", "int (__fastcall *) (Leader * this)" +define, 0x56D7D0, 0x57A1B0, 0x56D740, "get_tile_occupier_id", "int (__cdecl *) (int x, int y, int pov_civ_id, bool respect_unit_invisibility)" +repl call, 0x4585F4, 0x45A7A2, 0x458674, "get_tile_occupier_id_in_Unit_ai_move_naval_power_unit", "" +inlead, 0x4ED220, 0x4F6140, 0x4ED2E0, "Main_Screen_Form_show_map_message", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause)" +repl call, 0x4BE664, 0x4C5C66, 0x4BE6F4, "Main_Screen_Form_show_wltk_message", "" +repl call, 0x4BE71B, 0x4C5D1D, 0x4BE7AB, "Main_Screen_Form_show_wltk_ended_message", "" +define, 0xA52678, 0xA74E70, 0xA52638, "p_preferences", "unsigned *" +inlead, 0x4AFAB0, 0x4B6A70, 0x4AFB40, "City_set_production", "void (__fastcall *) (City * this, int edx, int order_type, int order_id, bool ask_to_confirm)" +define, 0x4B0AC0, 0x4B7A70, 0x4B0B50, "City_get_income_from_wealth_build", "int (__fastcall *) (City * this)" +define, 0x64C91E, 0x66AFD7, 0x64C85E, "print_int", "char * (__cdecl *) (int val, char * str, unsigned base)" +repl call, 0x5D759A, 0x5E69D2, 0x5D74CA, "Tile_has_city_for_agri_penalty_exception", "" +repl call, 0x564528, 0x570873, 0x5644D8, "show_popup_option_1_razes", "" +repl call, 0x4DA1E6, 0x4E2B96, 0x4DA2A6, "show_popup_option_2_razes", "" +define, 0x619E70, 0x63B090, 0x619DA0, "Context_Menu_add_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, char * text, bool checkbox, Sprite * image)" +repl call, 0x4E9808, 0x4F25EF, 0x4E98C8, "Context_Menu_add_abandon_city", "" +define, 0x60F6A0, 0x62B460, 0x60F5D0, "TextBuffer_check_ptr", "char * (__fastcall *) (TextBuffer * this, int edx, char * str)" +repl call, 0x4D5525, 0x4DDCF6, 0x4D55E5, "TextBuffer_check_pedia_upgrades_to_ptr_1", "" +repl call, 0x4D5676, 0x4DDE50, 0x4D5736, "TextBuffer_check_pedia_upgrades_to_ptr_2", "" +define, 0x5C68A0, 0x5D5700, 0x5C65B0, "Unit_try_flying_over_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y)" +inlead, 0x5C74A0, 0x5D6330, 0x5C71B0, "Unit_perform_air_recon", "void (__fastcall *) (Unit * this, int edx, int x, int y)" +repl call, 0x5C6E34, 0x5D5CBB, 0x5C6B44, "Unit_get_interceptor_max_moves", "" +repl call, 0x5C7108, 0x5D5FAA, 0x5C6E18, "Unit_get_moves_after_interception", "" +repl call, 0x5C7114, 0x5D5FB6, 0x5C6E24, "Unit_set_state_after_interception", "" +inlead, 0x561220, 0x56D350, 0x5611D0, "Leader_begin_unit_turns", "void (__fastcall *) (Leader * this)" +define, 0x4A1FA0, 0x4A8BB0, 0x4A2030, "Fighter_find_defender_against_bombardment", "Unit * (__fastcall *) (Fighter * this, int edx, Unit * bombarder, int tile_x, int tile_y, int bombarder_civ_id, bool land_lethal, bool sea_lethal)" +repl call, 0x4A3ED9, 0x4AAB85, 0x4A3F69, "Fighter_find_actual_bombard_defender", "" +repl call, 0x4A2BAA, 0x4A97F6, 0x4A2C3A, "Fighter_find_actual_bombard_defender", "" +define, 0x4A7280, 0x4ADF40, 0x4A7310, "Fighter_eval_tile_vulnerability", "int (__fastcall *) (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y)" +repl call, 0x45861F, 0x45A7CD, 0x45869F, "Fighter_eval_tile_vulnerability_in_Unit_ai_move_naval_power_unit", "" +inlead, 0x5C6290, 0x5D50E0, 0x5C5FA0, "Unit_select", "void (__fastcall *) (Unit *this)" +inlead, 0x5B6820, 0x5C5180, 0x5B6530, "Unit_select_stealth_attack_target", "bool (__fastcall *) (Unit * this, int edx, int target_civ_id, int x, int y, bool allow_popup, Unit ** out_selected_target)" +repl call, 0x5C73FF, 0x5D629C, 0x5C710F, "Unit_try_flying_for_precision_strike", "" +define, 0x5C1210, 0x5CFDA0, 0x5C0F20, "Unit_play_bombard_fire_animation", "int (__fastcall *) (Unit * this, int edx, int x, int y)" +define, 0x5CA860, 0x5D97A0, 0x5CA570, "Unit_play_bombing_animation", "void (__fastcall *) (Unit * this, int edx, int x, int y)" +repl call, 0x5C7429, 0x5D62BA, 0x5C7139, "Unit_play_bombing_anim_for_precision_strike", "" +repl call, 0x5C143D, 0x5CFFCD, 0x5C114D, "Unit_play_anim_for_bombard_tile", "" +repl call, 0x5B6A1B, 0x5C5368, 0x5B672B, "PopupSelection_add_stealth_attack_target", "" +inlead, 0x4D94F0, 0x4E1E80, 0x4D95B0, "Main_Screen_Form_issue_precision_strike_cmd", "void (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit)" +repl call, 0x4A3E92, 0x4AAB40, 0x4A3F22, "rand_bombard_target", "" +repl call, 0x5B6549, 0x5C4EA9, 0x5B6259, "Tile_check_water_for_stealth_attack", "" +inlead, 0x5B64C0, 0x5C4E20, 0x5B61D0, "Unit_can_stealth_attack", "bool (__fastcall *) (Unit * this, int edx, Unit * target)" +define, 0x61BCA0, 0x63D770, 0x61BBD0, "process_text_snippet", "int (__cdecl *) (char * in, char * out)" +repl call, 0x4D788A, 0x4E01EA, 0x4D794A, "process_text_for_map_message", "" +repl call, 0x5C6997, 0x5D5812, 0x5C66A7, "rand_int_to_dodge_city_aa", "" +repl call, 0x5C69A7, 0x5D5822, 0x5C66B7, "Unit_get_defense_to_dodge_city_aa", "" +repl call, 0x4A2179, 0x4A8D8A, 0x4A2209, "Unit_get_defense_to_find_bombard_defender", "" +define, 0x585B00, 0x592D50, 0x585860, "get_int_from_conquests_ini", "int (__cdecl *) (LPCSTR key, int param_2, int param_3)" +repl call, 0x59301E, 0x5A0756, 0x592D3E, "get_WindowsFileBox_from_ini", "" +define, 0x4A0670, 0x4A71F0, 0x4A0700, "open_load_game_file_picker", "char const * (__fastcall *) (void * this)" +repl call, 0x593054, 0x5A078A, 0x592D74, "do_open_load_game_file_picker", "" +inlead, 0x592D90, 0x5A0490, 0x592AB0, "do_load_game", "void * (__cdecl *) (char * param_1)" +define, 0x4F5EF0, 0x4FF290, 0x4F5FB0, "perform_interturn", "void (__cdecl *) ()" +repl call, 0x4F6759, 0x4FFB21, 0x4F6819, "perform_interturn_in_main_loop", "" +repl call, 0x4F59E6, 0x4FED88, 0x4F5AA6, "show_movement_phase_popup", "" +repl call, 0x5936F3, 0x5A0E8C, 0x593413, "show_intro_after_load_popup", "" +define, 0xA527B4, 0xA74FAC, 0xA52774, "p_is_pbem_game", "byte *" +define, 0xA52991, 0xA75189, 0xA52951, "p_is_offline_mp_game", "byte *" +inlead, 0x4A3A70, 0x4AA6F0, 0x4A3B00, "Fighter_do_bombard_tile", "void (__fastcall *) (Fighter * this, int edx, Unit * unit, int neighbor_index, int param_3, int param_4)" +define, 0x74AF60, 0x765300, 0x74AF20, "p_mp_object", "void *" +define, 0x4697B0, 0x46BF90, 0x469830, "mp_check_current_combat", "bool (__fastcall *) (void * this, int edx, int mp_tile_x, int mp_tile_y)" +define, 0x4A2650, 0x4A9290, 0x4A26E0, "Fighter_damage_city_by_bombardment", "bool (__fastcall *) (Fighter * this, int edx, Unit * unit, City * city, int damage_kind, int min_fire_rate)" +define, 0x426BD0, 0x428310, 0x426C50, "Map_in_range", "bool (__fastcall *) (Map * this, int edx, int x, int y)" +inlead, 0x4AE030, 0x4B5010, 0x4AE0C0, "City_can_trade_via_water", "bool (__fastcall *) (City * this)" +repl call, 0x4E67f4, 0x4EF255, 0x4E68B4, "City_shows_harbor_icon", "" +inlead, 0x4ADF90, 0x4B4F70, 0x4AE020, "City_can_trade_via_air", "bool (__fastcall *) (City * this)" +repl call, 0x4E6842, 0x4EF2A7, 0x4E6902, "City_shows_airport_icon", "" +define, 0x4B1F90, 0x4B8F10, 0x4B2020, "City_count_improvements_with_flag", "int (__fastcall *) (City * this, int edx, enum ImprovementTypeFlags flag)" +repl call, 0x4A12EC, 0x4A7E9C, 0x4A137C, "Unit_check_king_for_defense_priority", "" +repl call, 0x4A131A, 0x4A7ECA, 0x4A13AA, "Unit_check_king_for_defense_priority", "" +repl call, 0x4A133D, 0x4A7EED, 0x4A13CD, "Unit_check_king_for_defense_priority", "" +repl call, 0x4A144C, 0x4A7FFC, 0x4A14DC, "Unit_check_king_for_defense_priority", "" +repl call, 0x4A1477, 0x4A8027, 0x4A1507, "Unit_check_king_for_defense_priority", "" +repl call, 0x4A149F, 0x4A804F, 0x4A152F, "Unit_check_king_for_defense_priority", "" +repl call, 0x598EC5, 0x5A686D, 0x598BE5, "get_local_time_for_unit_ini", "" +repl call, 0x598AEC, 0x5A63F8, 0x59880C, "get_local_time_for_unit_ini", "" +define, 0x581330, 0x58E060, 0x581090, "Trade_Net_get_direction_from_internal_map", "int (__fastcall *) (Trade_Net * this, int edx, int x, int y, bool use_data_2_else_4)" +inlead, 0x50EC10, 0x518F00, 0x50ECB0, "DiploForm_assemble_tradable_items", "void (__fastcall *) (DiploForm * this)" +repl call, 0x50FAD9, 0x519D8B, 0x50FB79, "Leader_could_buy_tech_for_trade_screen", "" +repl call, 0x50FB9C, 0x519E42, 0x50FC3C, "Leader_could_buy_tech_for_trade_screen", "" +inlead, 0x4C10B0, 0x4C86A0, 0x4C1140, "City_get_building_defense_bonus", "int (__fastcall *) (City * this)" +define, 0x55A8D0, 0x5667E0, 0x55A880, "Leader_count_wonders_with_flag", "int (__fastcall *) (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city)" +repl vptr, 0x66DD04, 0x68ADE4, 0x66DD04, "Unit_eval_escort_requirement", "int (__fastcall *) (Unit * this)" +inlead, 0x561860, 0x56D9E0, 0x561810, "Leader_unlock_technology", "void (__fastcall *) (Leader * this, int edx, int tech_id, bool param_2, bool param_3, bool param_4)" +define, 0x55CF10, 0x568F90, 0x55CEC0, "Leader_recompute_buildings_maintenance", "void (__fastcall *) (Leader *this)" +define, 0x5683F7, 0x5747F2, 0x5683A7, "ADDR_UNLOCK_TECH_AT_INIT_1", "int" +define, 0x56847F, 0x57487A, 0x56842F, "ADDR_UNLOCK_TECH_AT_INIT_3", "int" +define, 0x5688DC, 0x574CD6, 0x56888C, "ADDR_UNLOCK_TECH_AT_INIT_2", "int" +define, 0x5621DE, 0x56E33D, 0x56217E, "ADDR_UNLOCK_TECH_RECURSE", "int" +repl call, 0x4212E7, 0x422847, 0x421367, "City_get_improv_maintenance_for_ui", "" +define, 0x563473, 0x56F723, 0x563423, "ADDR_CAPTURE_CITY_BARB_BRANCH", "byte *" +define, 0x56082B, 0x56C938, 0x5607DB, "ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP", "byte *" +define, 0x560838, 0x56C945, 0x5607E8, "ADDR_PROD_PHASE_BARB_DONE_JUMP", "byte *" +define, 0x426C00, 0x428340, 0x426C80, "Map_wrap_horiz", "int (__fastcall *) (Map * this, int edx, int x)" +define, 0x426C40, 0x428380, 0x426CC0, "Map_wrap_vert", "int (__fastcall *) (Map * this, int edx, int y)" +repl call, 0x44FEC3, 0x451F64, 0x44FF43, "neighbor_index_to_diff_for_barb_ai", "" +repl call, 0x44FEF0, 0x451F91, 0x44FF70, "Map_wrap_vert_for_barb_ai", "" +inlead, 0x5604B0, 0x56C5A0, 0x560460, "Leader_do_production_phase", "void (__fastcall *) (Leader * this)" +define, 0x5DF900, 0x5EF150, 0x5DF830, "count_set_bits", "int (__cdecl *) (unsigned int bit_field)" +repl call, 0x5604F8, 0x56C5E8, 0x5604A8, "count_player_bits_for_barb_prod", "" +repl call, 0x4C5208, 0x4CCAC6, 0x4C5228, "Map_get_tile_to_check_visibility", "" +repl vis, 0x4C5289, 0x4CCB4D, 0x4C52A9, "", "" +repl call, 0x4C5333, 0x4CCBEE, 0x4C5353, "Map_get_tile_to_check_visibility", "" +repl call, 0x4C35E4, 0x4CAE49, 0x4C3604, "Map_get_tile_to_check_visibility", "" +repl call, 0x4C3577, 0x4CADDC, 0x4C3597, "Map_get_tile_to_check_visibility", "" +repl call, 0x578A67, 0x585B87, 0x5789D7, "Map_get_tile_to_check_visibility", "" +repl call, 0x4C37E2, 0x4CB062, 0x4C3802, "Map_get_tile_to_check_visibility", "" +repl call, 0x4EDEF4, 0x4F6E44, 0x4EDFB4, "Map_get_tile_to_check_visibility", "" +repl vis, 0x4F0D82, 0x4F9ED2, 0x4F0E42, "", "" +repl call, 0x5AAA7A, 0x5B9196, 0x5AA78A, "Map_get_tile_to_check_visibility", "" +repl vis, 0x4EA2C3, 0x4F30B4, 0x4EA383, "", "" +repl vis, 0x4A1E90, 0x4A8A9E, 0x4A1F20, "", "" +repl call, 0x449941, 0x44B891, 0x4499C1, "Map_get_tile_to_check_visibility", "" +repl vis, 0x44997D, 0x44B8CF, 0x4499FD, "", "" +repl vis, 0x4EFC7A, 0x4F8C6B, 0x4EFD3A, "", "" +repl vis, 0x5B71B2, 0x5C5B43, 0x5B6EC2, "", "" +repl vis, 0x5B75EF, 0x5C5F53, 0x5B72FF, "", "" +repl vis, 0x5B7883, 0x5C6255, 0x5B7593, "", "" +repl vis, 0x5B7CC0, 0x5c66a9, 0x5B79D0, "", "" +repl vis, 0x5B808E, 0x5c6a80, 0x5B7D9E, "", "" +repl vis, 0x5B95A2, 0x5c802a, 0x5B92B2, "", "" +repl vis, 0x5BFD8A, 0x5ce91c, 0x5BFA9A, "", "" +repl vis, 0x5C4863, 0x5d351b, 0x5C4573, "", "" +repl vis, 0x5C4A3E, 0x5d3722, 0x5C474E, "", "" +repl vis, 0x5C4AD4, 0x5D37C3, 0x5C47E4, "", "" +repl vis, 0x5C4B90, 0x5D3884, 0x5C48A0, "", "" +repl vis, 0x5C4C41, 0x5D3925, 0x5C4951, "", "" +repl vis, 0x5C6A62, 0x5D58D9, 0x5C6772, "", "" +repl vis, 0x5C6F21, 0x5D5DA7, 0x5C6C31, "", "" +repl vis, 0x5C7F40, 0x5D6E00, 0x5C7C50, "", "" +repl vis, 0x5C8614, 0x5D7521, 0x5C8324, "", "" +repl vis, 0x5C8752, 0x5D7666, 0x5C8462, "", "" +repl vis, 0x5C8F8B, 0x5D7ECE, 0x5C8C9B, "", "" +repl vis, 0x5B9878, 0x5C8330, 0x5B9588, "", "" +repl vis, 0x5B992A, 0x5C83E2, 0x5B963A, "", "" +repl vis, 0x5B99E6, 0x5C84A7, 0x5B96F6, "", "" +repl vis, 0x5B9A97, 0x5C8559, 0x5B97A7, "", "" +repl vis, 0x5B9E54, 0x5C892B, 0x5B9B64, "", "" +repl vis, 0x57F4E4, 0x58C20D, 0x57F244, "", "" +repl vis, 0x57FC67, 0x58C8E4, 0x57F9C7, "", "" +repl call, 0x57F9B6, 0x58C62B, 0x57F716, "Map_get_tile_to_check_visibility", "" +repl call, 0x57F9F2, 0x58C667, 0x57F752, "Map_get_tile_to_check_visibility", "" +inlead, 0x4ED120, 0x4F6040, 0x4ED1E0, "Main_Screen_Form_is_unit_visible_to_player", "bool (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * unit)" +repl vptr, 0x670270, 0x68D31C, 0x670270, "Tile_m42_Get_Overlays", "unsigned (__fastcall *) (Tile * this, int edx, byte visible_to_civ)" +repl vptr, 0x6702E4, 0x68D390, 0x6702E4, "Tile_m71_Check_Worker_Job", "int (__fastcall *) (Tile * this)" +inlead, 0x5DBF10, 0x5EB460, 0x5DBE40, "Tile_get_road_bonus", "int (__fastcall *) (Tile * this)" +define, 0x5DBEC0, 0x5EB410, 0x5DBDF0, "Tile_get_mining_bonus", "int (__fastcall *) (Tile * this)" +define, 0x4EDF20, 0x4F6E70, 0x4EDFE0, "Unit_check_contact_bit_6", "bool (__fastcall *) (Unit * this, int edx, int civ_id)" +repl call, 0x4E8942, 0x4F15D0, 0x4E8A02, "Unit_check_contact_bit_6_on_right_click", "" +repl call, 0x4EA330, 0x4F3121, 0x4EA3F0, "Unit_check_contact_bit_6_on_right_click", "" +inlead, 0x4A8350, 0x4AF030, 0x4A83E0, "Leader_is_tile_visible", "bool (__fastcall *) (Leader * this, int edx, int x, int y)" +repl call, 0x4A784E, 0x4AE509, 0x4a78DE, "Tile_check_water_for_sea_zoc", "" +define, 0x4A79C2, 0x4AE66D, 0x4A7A52, "ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC", "byte *" +define, 0x4A7CAA, 0x4AE962, 0x4A7D3A, "ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC", "byte *" +repl call, 0x4A7BF2, 0x4AE8AA, 0x4A7C82, "Tile_check_water_for_land_zoc", "" +inlead, 0x5BE6E0, 0x5CD2C0, 0x5BE3F0, "Unit_get_attack_strength", "int (__fastcall *) (Unit * this)" +repl call, 0x4A79CA, 0x4AE675, 0x4A7A5A, "Unit_get_attack_strength_for_sea_zoc", "" +repl call, 0x4A7B15, 0x4AE7BE, 0x4A7BA5, "Unit_get_attack_strength_for_sea_zoc", "" +repl call, 0x4A7B20, 0x4AE7C9, 0x4A7BB0, "Unit_get_attack_strength_for_sea_zoc", "" +repl call, 0x4A7CB2, 0x4AE96A, 0x4A7D42, "Unit_get_attack_strength_for_land_zoc", "" +repl call, 0x4A7DFD, 0x4AEAB3, 0x4A7E8D, "Unit_get_attack_strength_for_land_zoc", "" +repl call, 0x4A7E08, 0x4AEABE, 0x4A7E98, "Unit_get_attack_strength_for_land_zoc", "" +inlead, 0x4E3E90, 0x4EC6E0, 0x4E3F50, "Main_Screen_Form_find_visible_unit", "Unit * (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * excluded)" +define, 0x4F00F0, 0x4F9100, 0x4F01B0, "Animator_play_one_shot_unit_animation", "void (__fastcall *) (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3)" +repl call, 0x4A81A4, 0x4AEE83, 0x4A8234, "Animator_play_zoc_animation", "" +repl call, 0x4A81E2, 0x4AEEC1, 0x4A8272, "Animator_play_zoc_animation", "" +inlead, 0x4A76B0, 0x4AE370, 0x4A7740, "Fighter_apply_zone_of_control", "void (__fastcall *) (Fighter * this, int edx, Unit * unit, int from_x, int from_y, int to_x, int to_y)" +define, 0x4A1CD0, 0x4A88E0, 0x4A1D60, "Fighter_check_combat_anim_visibility", "bool (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender, bool param_3)" +repl call, 0x4A7F71, 0x4AEC36, 0x4A8001, "Fighter_check_zoc_anim_visibility", "" +define, 0x4A7F61, 0x4AEC26, 0x4A7FF1, "ADDR_ZOC_CHECK_ATTACKER_ANIM_FIELD_111", "byte *" +define, 0x4A770A, 0x4AE3CA, 0x4A779A, "ADDR_SKIP_ZOC_FOR_ONE_HP_LAND_UNIT", "byte *" +define, 0x4A7745, 0x4AE405, 0x4A77D5, "ADDR_SKIP_ZOC_FOR_ONE_HP_SEA_UNIT", "byte *" +inlead, 0x5B8FC0, 0x5C7A40, 0x5B8CD0, "Unit_move_to_adjacent_tile", "int (__fastcall *) (Unit * this, int edx, int neighbor_index, bool param_2, int param_3, byte param_4)" +repl call, 0x5B91B4, 0x5C7C32, 0x5B8EC4, "Tile_check_water_for_canal_move_to_adjacent_tile_dest", "" +repl call, 0x5B945B, 0x5C7EDE, 0x5B916B, "Trade_Net_get_move_cost_after_zoc", "" +repl call, 0x5B9471, 0x5C7EF4, 0x5B9181, "Unit_can_move_after_zoc", "" +repl call, 0x5B94E4, 0x5C7F67, 0x5B91F4, "Unit_get_max_move_points_for_bridge_exit", "" +repl vptr, 0x66DD40, 0x68AE20, 0x66DD40, "Unit_teleport", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad)" +define, 0x5BEF00, 0x5CDB10, 0x5BEC10, "Unit_score_kill", "void (__fastcall *) (Unit * this, int edx, Unit * victim, bool was_attacking)" +define, 0x5BF558, 0x5CE0EA, 0x5BF268, "ADDR_EXISTING_BATTLE_CREATED_UNIT_CHECK", "void *" +inlead, 0x4A1AE0, 0x4A86E0, 0x4A1B70, "Fighter_find_defensive_bombarder", "Unit * (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender)" +define, 0x5BCA90, 0x5CB620, 0x5BC7A0, "Unit_get_containing_army", "Unit * (__fastcall *) (Unit * this)" +define, 0x4A0ED0, 0x4A7A90, 0x4A0F60, "Fighter_get_combat_odds", "int (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses)" +repl call, 0x4A5AF9, 0x4AC799, 0x4A5B89, "Fighter_get_odds_for_main_combat_loop", "" +define, 0x4A3280, 0x4A9ED0, 0x4A3310, "Fighter_damage_by_defensive_bombard", "void (__fastcall *) (Fighter * this, int edx, Unit * bombarder, Unit * defender)" +repl call, 0x4A57C5, 0x4AC477, 0x4A5855, "Fighter_damage_by_db_in_main_loop", "" +inlead, 0x4A53A0, 0x4AC060, 0x4A5430, "Fighter_fight", "byte (__fastcall *) (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender_or_null)" +repl call, 0x4A6EB7, 0x4ADB60, 0x4A6F47, "Unit_score_kill_by_defender", "" +define, 0x5C8180, 0x5D7060, 0x5C7E90, "Unit_play_attack_animation", "void (__fastcall *) (Unit * this, int edx, int direction)" +repl call, 0x4A5791, 0x4AC443, 0x4A5821, "Unit_play_attack_anim_for_def_bombard", "" +define, 0x578780, 0x5858A0, 0x5786F0, "Navigator_Data_reset", "void (__fastcall *) (Navigator_Data * this)" +inlead, 0x536080, 0x540670, 0x536100, "initialize_map_music", "void (__cdecl *) (int civ_id, int era_id, bool param_3)" +inlead, 0x535FB0, 0x5405A0, 0x536030, "deinitialize_map_music", "void (__stdcall *) ()" +inlead, 0x5C7350, 0x5D61F0, 0x5C7060, "Unit_do_precision_strike", "void (__fastcall *) (Unit * this, int edx, int x, int y)" +define, 0x5B5790, 0x5C40E0, 0x5B54A0, "Unit_confirm_war", "bool (__fastcall *) (Unit * this, int edx, int against_civ_id, bool allow_map_message)" +inlead, 0x5C37B0, 0x5D23F0, 0x5C34C0, "Unit_check_precision_strike_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5B5280, 0x5C3BF0, 0x5B4F90, "Unit_attack_tile", "void (__fastcall *) (Unit * this, int edx, int x, int y, int bombarding)" +repl call, 0x5C33F6, 0x5D2026, 0x5C3106, "Map_get_tile_to_check_visibility", "" +repl call, 0x52C39A, 0x5367DC, 0x52C42A, "Map_get_tile_to_check_visibility", "" +repl call, 0x52C146, 0x536586, 0x52C1D6, "Map_get_tile_to_check_visibility", "" +repl call, 0x52BED0, 0x536310, 0x52BF60, "Map_get_tile_to_check_visibility", "" +repl call, 0x5B555E, 0x5C3EBF, 0x5B526E, "Unit_get_max_moves_after_barricade_attack", "" +define, 0x56D2C0, 0x579C40, 0x56D230, "city_at", "City * (__cdecl *) (int x, int y)" +repl call, 0x4A2018, 0x4A8C28, 0x4A20A8, "city_at_in_find_bombard_defender", "" +inlead, 0x5C3510, 0x5D2140, 0x5C3220, "Unit_check_bombard_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C5160, 0x5D3E40, 0x5C4E70, "Unit_can_disembark_anything", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +repl call, 0x52C912, 0x536D92, 0x52C9A2, "Unit_get_defense_for_bombardable_unit_check", "" +repl call, 0x57F627, 0x58C356, 0x57F387, "get_tile_occupier_for_ai_path", "" +repl call, 0x56D9D1, 0x57A3C2, 0x56D941, "Unit_is_tile_occupier_visible", "" +repl vptr, 0x66BF68, 0x68905C, 0x66BF68, "Demographics_Form_m22_draw", "void (__fastcall *) (Demographics_Form * this)" +define, 0x600070, 0x615570, 0x5FFF50, "PCX_Image_fill_area", "int (__fastcall *) (PCX_Image * this, int edx, RECT * rect, int color)" +define, 0x5FD360, 0x611290, 0x5FD240, "PCX_Image_set_text_effects", "void (__fastcall *) (PCX_Image * this, int edx, int text_color, int shadow_color, int shadow_offset_x, int shadow_offset_y)" +inlead, 0x5676C0, 0x573AB0, 0x567670, "Leader_get_optimal_city_number", "int (__fastcall *) (Leader * this)" +inlead, 0x55AA10, 0x566930, 0x55A9C0, "Leader_count_wonders_with_small_flag", "int (__fastcall *) (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null)" +repl call, 0x567706, 0x573AF6, 0x5676B6, "Leader_count_forbidden_palaces_for_ocn", "" +repl call, 0x550F99, 0x55C0E1, 0x550F49, "Unit_can_do_worker_command_for_button_setup", "" +repl call, 0x55132D, 0x55C484, 0x5512DD, "Unit_can_do_worker_command_for_button_setup", "" +define, 0x55B1A0, 0x567100, 0x55B150, "Leader_reveal_tile", "void (__fastcall *) (Leader * this, int edx, int x, int y)" +define, 0x5FCB10, 0x610790, 0x5FC9F0, "PCX_Image_draw_onto", "int (__fastcall *) (PCX_Image * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y)" +define, 0x5DBF60, 0x5EB4B0, 0x5DBE90, "Tile_get_terrain_move_cost", "int (__fastcall *) (Tile * this)" +define, 0x56D340, 0x579CC0, 0x56D2B0, "get_combat_occupier", "int (__cdecl *) (int tile_x, int tile_y, int civ_id, byte ignore_visibility)" +repl call, 0x45871C, 0x45A8C9, 0x45879C, "get_combat_occupier_in_Unit_ai_move_naval_power_unit", "" +define, 0x561480, 0x56D5E0, 0x561430, "Leader_has_tech_with_flag", "bool (__fastcall *) (Leader * this, int edx, enum AdvanceTypeFlags flag)" +inlead, 0x57D980, 0x58A680, 0x57D6E0, "Trade_Net_recompute_city_connections", "void (__fastcall *) (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id)" +inlead, 0x62B1A0, 0x64E220, 0x6274B0, "OpenGLRenderer_initialize", "int (__fastcall *) (OpenGLRenderer * this, int edx, PCX_Image * texture)" +inlead, 0x62B450, 0x64E510, 0x627760, "OpenGLRenderer_draw_line", "void (__fastcall *) (OpenGLRenderer * this, int edx, int x1, int y1, int x2, int y2)" +inlead, 0x62B490, 0x64E560, 0x6277A0, "OpenGLRenderer_set_color", "void (__fastcall *) (OpenGLRenderer * this, int edx, unsigned int rgb555)" +inlead, 0x62B570, 0x64E600, 0x627880, "OpenGLRenderer_set_opacity", "void (__fastcall *) (OpenGLRenderer * this, int edx, unsigned int alpha)" +inlead, 0x62B5B0, 0x64E660, 0x6278C0, "OpenGLRenderer_set_line_width", "void (__fastcall *) (OpenGLRenderer * this, int edx, int width)" +inlead, 0x62B5D0, 0x64E690, 0x6278E0, "OpenGLRenderer_enable_line_dashing", "void (__fastcall *) (OpenGLRenderer * this)" +inlead, 0x62B5F0, 0x64E6C0, 0x627900, "OpenGLRenderer_disable_line_dashing", "void (__fastcall *) (OpenGLRenderer * this)" +repl call, 0x5BFBFF, 0x5CE79A, 0x5BF90F, "Tile_check_water_for_retreat_on_defense", "bool (__fastcall *) (Tile * this)" +inlead, 0x5D2150, 0x5E13F0, 0x5D2080, "Map_build_trade_network", "void (__fastcall *) (Map * this)" +inlead, 0x57DE90, 0x58ABD0, 0x57DBF0, "Trade_Net_recompute_city_cons_and_res", "void (__fastcall *) (Trade_Net * this, int edx, bool param_1)" +repl call, 0x57DAF1, 0x58A7F9, 0x57D851, "Trade_Net_set_unit_path_to_fill_road_net", "" +repl call, 0x57DE29, 0x58AB4E, 0x57DB89, "Trade_Net_set_unit_path_to_find_sea_route", "" +define, 0x5EA6E0, 0x5F9F30, 0x5EA610, "Tile_has_colony", "bool (__fastcall *) (Tile * this)" +repl call, 0x5C1559, 0x5D00ED, 0x5C1269, "City_count_airports_for_airdrop", "" +define, 0x437CF0, 0x4398A0, 0x437D70, "Leader_get_city_count_on_continent", "int (__fastcall *) (Leader * this, int edx, int cont_id)" +repl call, 0x42EB3F, 0x430615, 0x42EBBF, "Leader_get_cont_city_count_for_worker_req", "" +repl call, 0x42EBCA, 0x430698, 0x42EC4A, "Leader_get_cont_city_count_for_worker_req", "" +repl call, 0x42EAD2, 0x4305AE, 0x42EB52, "Leader_get_city_count_for_worker_prod_cap", "" +inlead, 0x55D310, 0x5693A0, 0x55D2C0, "Leader_sum_unit_maintenance", "int (__fastcall *) (Leader * this, int edx, int government_id)" +define, 0xA52684, 0xA74E7C, 0xA52644, "p_game_difficulty", "int *" +define, 0x5CD960, 0x5DC940, 0x5CD880, "Unit_is_terrain_impassable", "bool (__fastcall *) (Unit * this, int edx, int terrain_type_index)" +define, 0x41CD22, 0x41E04C, 0x41CDA2, "ADDR_LUXURY_BOX_ROW_HEIGHT", "byte *" +define, 0x30, 0x38, 0x30, "LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET", "int" +define, 0x740A00, 0x75ADA0, 0x7409C0, "p_city_form", "City_Form *" +inlead, 0x5F82E0, 0x6087E0, 0x5F8210, "Sprite_draw", "int (__fastcall *) (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table)" +repl call, 0x421295, 0x4227F5, 0x421315, "Sprite_draw_improv_img_on_city_form", "" +inlead, 0x421240, 0x4227A0, 0x4212C0, "draw_improv_icons_on_city_screen", "void (__cdecl *) (Base_List_Control * control, int improv_id, int item_index, int offset_x, int offset_y)" +define, 0x4B0710, 0x4B76C0, 0x4B07A0, "City_get_tourism_amount", "int (__fastcall *) (City * this, int edx, int improv_id)" +repl call, 0x42138C, 0x4228EC, 0x42140C, "City_get_tourism_amount_to_draw", "" +repl call, 0x4213FF, 0x42295F, 0x42147F, "Sprite_draw_tourism_gold", "" +repl call, 0x4BA075, 0x4C16E5, 0x4BA105, "City_calc_tile_yield_while_gathering", "" +repl call, 0x4B0512, 0x4B74D2, 0x4B05A2, "City_calc_tile_yield_while_gathering", "" +repl call, 0x4ADA3F, 0x4B4A28, 0x4ADACF, "City_calc_tile_yield_while_gathering", "" +repl call, 0x4B0F04, 0x4B7EB4, 0x4B0F94, "City_calc_tile_yield_while_gathering", "" +repl call, 0x4B25EF, 0x4B9576, 0x4B267F, "City_calc_tile_yield_while_gathering", "" +repl call, 0x4BA645, 0x4C1CA4, 0x4BA6D5, "City_calc_tile_yield_while_gathering", "" +inlead, 0x4B0E80, 0x4B7E30, 0x4B0F10, "City_recompute_yields_and_happiness", "void (__fastcall *) (City * this)" +inlead, 0x55EC80, 0x56AD30, 0x55EC30, "Leader_record_export", "bool (__fastcall *) (Leader * this, int edx, int importer_civ_id, int resource_id)" +inlead, 0x55ED60, 0x56AE10, 0x55ED10, "Leader_erase_export", "bool (__fastcall *) (Leader * this, int edx, int importer_civ_id, int resource_id)" +inlead, 0x4216A0, 0x422BF0, 0x421720, "City_Form_open", "void (__fastcall *) (City_Form * this, int edx, City * city, int param_2)" +define, 0x4B0330, 0x4B72F0, 0x4B03C0, "City_calc_tile_yield_at", "int (__fastcall *) (City * this, int edx, int yield_type, int tile_x, int tile_y)" +repl vptr, 0x66dd10, 0x68adf0, 0x66dd10, "Unit_has_enough_escorters_present", "bool (__fastcall *) (Unit * this)" +repl vptr, 0x66dd14, 0x68adf4, 0x66dd14, "Unit_check_escorter_health", "void (__fastcall *) (Unit * this, int edx, bool * has_any_escort_present, bool * any_escorter_cant_heal)" +inlead, 0x5694D0, 0x575900, 0x569480, "Leader_spawn_unit", "Unit * (__fastcall *) (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id)" +repl call, 0x5B7BA8, 0x5C69B8, 0x5B78B8, "Leader_spawn_captured_unit", "" +repl call, 0x5B7FCA, 0x5C657E, 0x5B7CDA, "Leader_spawn_captured_unit", "" +repl call, 0x5B74D8, 0x5C5E41, 0x5B71E8, "Leader_spawn_captured_unit", "" +inlead, 0x55E190, 0x56A220, 0x55E140, "Leader_enter_new_era", "void (__fastcall *) (Leader * this, int edx, bool param_1, bool no_online_sync)" +define, 0x55A270, 0x566180, 0x55A220, "Leader_get_name", "char * (__fastcall *) (Leader * this)" +define, 0x55A370, 0x566280, 0x55A320, "Leader_get_gender", "int (__fastcall *) (Leader * this)" +define, 0x55A210, 0x566120, 0x55A1C0, "Leader_get_civ_adjective", "char * (__fastcall *) (Leader * this)" +define, 0x55A240, 0x566150, 0x55A1F0, "Leader_get_civ_noun", "char * (__fastcall *) (Leader * this)" +define, 0x55A340, 0x566250, 0x55A2F0, "Leader_get_civ_formal_name", "char * (__fastcall *) (Leader * this)" +define, 0x55A2C0, 0x5661D0, 0x55A270, "Leader_get_title", "char * (__fastcall *) (Leader * this)" +repl call, 0x593614, 0x5A0DAE, 0x593334, "Leader_get_player_title_for_intro_popup", "" +inlead, 0x4A8240, 0x4AEF20, 0x4A82D0, "Fighter_animate_start_of_combat", "void (__fastcall *) (Fighter * this, int edx, Unit * attacker, Unit * defender)" +define, 0x61A2E0, 0x63B710, 0x61A210, "Context_Menu_disable_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id)" +define, 0x61A380, 0x63B7E0, 0x61A2B0, "Context_Menu_put_image_on_item", "int (__fastcall *) (Context_Menu * this, int edx, int item_id, Sprite * image)" +inlead, 0x4B8BA0, 0x4C0210, 0x4B8C30, "City_spawn_unit_if_done", "void (__fastcall *) (City * this)" +inlead, 0x5C0620, 0x5CF1C0, 0x5C0330, "Unit_can_upgrade", "bool (__fastcall *) (Unit * this)" +define, 0x4C0690, 0x4C7C50, 0x4C0720, "City_get_upgraded_type_id", "int (__fastcall *) (City * this, int edx, int unit_type_id)" +inlead, 0x56AAE0, 0x576F90, 0x56AA90, "Leader_upgrade_all_units", "void (__fastcall *) (Leader * this, int edx, int type_id)" +inlead, 0x4DE8B0, 0x4E7290, 0x4DE970, "Main_Screen_Form_upgrade_all_units", "void (__fastcall *) (Main_Screen_Form * this, int edx, int type_id)" +repl call, 0x56AB65, 0x577017, 0x56AB15, "Unit_can_perform_upgrade_all", "" +repl call, 0x4DE93C, 0x4E7316, 0x4DE9FC, "Unit_can_perform_upgrade_all", "" +repl call, 0x4BE89A, 0x4C5E80, 0x4BE92A, "Leader_spawn_unit_from_building", "" +repl call, 0x5C0727, 0x5CF2C7, 0x5C0437, "City_count_improvs_enabling_upgrade", "" +repl call, 0x5C0700, 0x5CF2A0, 0x5C0410, "City_count_improvs_enabling_upgrade", "" +repl call, 0x5C0715, 0x5CF2B5, 0x5C0425, "City_count_improvs_enabling_upgrade", "" +inlead, 0x4AECC0, 0x4B5C80, 0x4AED50, "City_raze", "void (__fastcall *) (City * this, int edx, int civ_id_responsible, bool checking_elimination)" +define, 0x563410, 0x56F6C0, 0x5633C0, "Leader_capture_city", "bool (__fastcall *) (Leader * this, int edx, City * city, Unit * unit, bool involuntary, bool converted)" +repl call, 0x55BA76, 0x567D20, 0x55BA26, "Leader_create_city_from_hut", "" +repl call, 0x568F57, 0x57538A, 0x568F07, "Leader_create_city_for_ai_respawn", "" +repl call, 0x5B35D3, 0x5C1F22, 0x5B32E3, "Leader_create_city_for_founding", "" +repl call, 0x5D2B8F, 0x5E1E68, 0x5D2ABF, "Leader_create_city_for_scenario", "" +inlead, 0x564800, 0x570BB0, 0x5647B0, "Leader_do_capture_city", "bool (__fastcall *) (Leader * this, int edx, City * city, bool involuntary, bool converted)" +define, 0x4BB410, 0x4C2A60, 0x4BB4A0, "City_count_citizens_of_race", "int (__fastcall *) (City * this, int edx, int race_id)" +define, 0x5A6060, 0x5B4350, 0x5A5D60, "count_units_at", "int (__cdecl *) (int x, int y, enum unit_filter filter, int arg_a, int arg_b, int arg_c)" +inlead, 0x4B9C60, 0x4C12E0, 0x4B9CF0, "City_draw_hud_icon", "void (__fastcall *) (City * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y)" +inlead, 0x4B9BB0, 0x4C1230, 0x4B9C40, "City_has_hud_icon", "bool (__fastcall *) (City * this)" +inlead, 0x4BFBF0, 0x4C71B0, 0x4BFC80, "City_draw_on_map", "void (__fastcall *) (City * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7)" +inlead, 0x4E7E30, 0x4F08F0, 0x4E7EF0, "MenuUnitItem_write_text_to_temp_str", "void (__fastcall *) (MenuUnitItem * this)" +define, 0xCAB2D8, 0xCCDB88, 0xCAB298, "temp_str", "char[4096]" +repl call, 0x5EDD89, 0x5FD7BE, 0x5EDCB9, "Tile_m74_Set_Square_Type_for_hill_gen", "" +inlead, 0x5D1EA0, 0x5E1140, 0x5D1DD0, "Map_place_scenario_things", "void (__fastcall *) (Map * this)" +repl vptr, 0x66C3EC, 0x6894D8, 0x66C3EC, "Advisor_Base_Form_domestic_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +repl vptr, 0x66F8CC, 0x68C988, 0x66F8CC, "Advisor_Base_Form_trade_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +repl vptr, 0x66E0CC, 0x68B1B8, 0x66E0CC, "Advisor_Base_Form_military_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +repl vptr, 0x66CAAC, 0x689B9C, 0x66CAAC, "Advisor_Base_Form_foreign_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +repl vptr, 0x66BD3C, 0x688E34, 0x66BD3C, "Advisor_Base_Form_cultural_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +repl vptr, 0x66F59C, 0x68C658, 0x66F59C, "Advisor_Base_Form_science_m95", "bool (__fastcall *) (Advisor_Base_Form * this)" +inlead, 0x4E79B0, 0x4F0470, 0x4E7A70, "Main_Screen_Form_open_quick_build_chooser", "void (__fastcall *) (Main_Screen_Form * this, int edx, City * city, int mouse_x, int mouse_y)" +repl call, 0x4E9941, 0x4F273F, 0x4E9A01, "Context_Menu_get_selected_item_on_unit_rcm", "int (__fastcall *) (Context_Menu * this)" +define, 256, 257, 256, "LBL_WAKE", "int" +define, 255, 256, 255, "LBL_ACTIVATE", "int" +define, 0x4C1280, 0x4C8860, 0x4C1310, "City_sum_buildings_naval_power", "int (__fastcall *) (City * this)" +repl call, 0x4A78EE, 0x4AE5A5, 0x4A797E, "City_sum_buildings_naval_power_for_zoc", "" +define, 0x5BE9E0, 0x5CD600, 0x5BE6F0, "Unit_count_contained_units", "int (__fastcall *) (Unit * this)" +repl call, 0x4B3089, 0x4BA00B, 0x4B3119, "Tile_check_water_to_block_pollution", "" +repl call, 0x4F416E, 0x4FD448, 0x4F422E, "Tile_set_flag_for_eruption_damage", "" +inlead, 0x4AF5D0, 0x4B6590, 0x4AF660, "City_confirm_production_switch", "bool (__fastcall *) (City * this, int edx, int order_type, int order_id)" +define, 0x62AEE0, 0x64DE20, 0x6271F0, "MappedFile_open", "void * (__fastcall *) (MappedFile * this, int edx, char * file_name, int sequential_access)" +repl call, 0x592160, 0x59F790, 0x591E80, "MappedFile_open_to_load_game", "" +define, 0x62AFA0, 0x64DF40, 0x6272B0, "MappedFile_create_file", "void * (__fastcall *) (MappedFile * this, int edx, LPCSTR file_path, unsigned file_size, int is_shared)" +repl call, 0x591CF1, 0x59F321, 0x591A11, "MappedFile_create_file_to_save_game", "" +define, 0x62B0C0, 0x64E0B0, 0x6273D0, "MappedFile_deinit", "void (__fastcall *) (MappedFile * this)" +repl call, 0x592322, 0x59F973, 0x592042, "MappedFile_deinit_after_saving_or_loading", "" +repl call, 0x591D9F, 0x59F3D0, 0x591ABF, "MappedFile_deinit_after_saving_or_loading", "" +repl vptr, 0x6701E4, 0x68D290, 0x6701E4, "Tile_m7_Check_Barbarian_Camp", "bool (__fastcall *) (Tile * this, int edx, int visible_to_civ)" +define, 0x44FBA5, 0x451C45, 0x44FC25, "ADDR_CHECK_BARB_CAMP_TO_DEFEND_RETURN", "int" +inlead, 0x590030, 0x59D690, 0x58FD50, "move_game_data", "int (__cdecl *) (byte * buffer, bool save_else_load)" +inlead, 0x5C14B0, 0x5D0040, 0x5C11C0, "Unit_can_airdrop", "bool (__fastcall *) (Unit * this)" +inlead, 0x5DF8D0, 0x5EF120, 0x5DF800, "City_Improvements_contains", "bool (__fastcall *) (City_Improvements * this, int edx, int id)" +inlead, 0x5DF890, 0x5EF0E0, 0x5DF7C0, "City_Improvements_set", "void (__fastcall *) (City_Improvements * this, int edx, int id, bool add_else_remove)" +repl call, 0x4B47C9, 0x4BB7B9, 0x4B4859, "Leader_has_tech_to_stop_disease", "" +define, 0x5D59E0, 0x5E4E20, 0x5D5910, "Map_change_tile_terrain", "void (__fastcall *) (Map * this, int edx, enum SquareTypes new_terrain_type, int x, int y)" +repl call, 0x461833, 0x463CAF, 0x4618B3, "Map_change_tile_terrain_by_worker", "" +inlead, 0x461470, 0x4638C0, 0x4614F0, "Unit_work_simple_job", "void (__fastcall *) (Unit * this, int edx, int job_id)" +define, 0x5C8B30, 0x5D7A50, 0x5C8840, "Unit_animate_cruise_missile_strike", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +repl call, 0x5B550E, 0x5C3E6F, 0x5B521E, "Unit_play_attack_animation_vs_tile", "" +repl call, 0x5B4C0E, 0x5C355E, 0x5B491E, "Map_compute_neighbor_index_for_cm_strike", "" +define, 0x5FF0E0, 0x614190, 0x5FEFC0, "PCX_Image_do_draw_centered_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len)" +repl call, 0x41AF59, 0x41C067, 0x41AFD9, "PCX_Image_do_draw_cntd_text_for_strat_res", "" +repl call, 0x41AE9F, 0x41BFA9, 0x41AF1F, "Sprite_draw_strat_res_on_city_screen", "" +define, 0x41AE1B, 0x41BF23, 0x41AE9B, "ADDR_MOST_STRAT_RES_ON_CITY_SCREEN", "void *" +inlead, 0x5BEB60, 0x5CD780, 0x5BE870, "Unit_can_heal_at", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5BECE0, 0x5CD900, 0x5BE9F0, "Unit_heal_at_start_of_turn", "void (__fastcall *) (Unit * this)" +define, 0x469590, 0x46BD40, 0x469610, "check_online_skip_flag", "bool (__stdcall *) (int unit_id)" +inlead, 0x448BF0, 0x44AB10, 0x448C70, "Leader_ai_eval_technology", "int (__fastcall *) (Leader * this, int edx, int id, bool param_2, bool param_3)" +inlead, 0x4446C0, 0x4464C0, 0x444740, "Leader_ai_eval_government", "int (__fastcall *) (Leader * this, int edx, int id)" +define, 0x474140, 0x476F70, 0x4741C0, "mp_despawn", "void (__fastcall *) (void * this, int edx, int unit_id, int civ_id_responsible, byte param_3, byte param_4, byte param_5, byte param_6)" +repl call, 0x5B483F, 0x5C3199, 0x5B454F, "Unit_despawn_after_killed_by_nuke", "" +repl call, 0x5B4374, 0x5C2CC4, 0x5B4084, "Unit_despawn_after_killed_by_nuke", "" +repl call, 0x5B4832, 0x5C318C, 0x5B4542, "mp_despawn_after_killed_by_nuke", "" +repl call, 0x5B4367, 0x5C2CB7, 0x5B4077, "mp_despawn_after_killed_by_nuke", "" +define, 0x4B3290, 0x4BA210, 0x4B3320, "City_has_unprotected_improv", "bool (__fastcall *) (City * this, int edx, int id)" +repl call, 0x422BE5, 0x4241A5, 0x422C65, "City_has_unprotected_improv_to_sell", "" +repl call, 0x5BB966, 0x5CA4B6, 0x5BB676, "UnitType_has_detector_ability_for_vis_check", "" +repl call, 0x5BB938, 0x5CA47F, 0x5BB648, "UnitType_has_detector_ability_for_vis_check", "" +repl call, 0x0FF, 0x5CA49B, 0x0FF, "UnitType_has_detector_ability_for_vis_check", "" +inlead, 0x5C33A0, 0x5D1FD0, 0x5C30B0, "Unit_check_airdrop_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C3C80, 0x5D28B0, 0x5C3990, "Unit_find_telepad_on_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y, bool show_selection_popup, Unit ** out_unit_telepad)" +inlead, 0x44B870, 0x44D840, 0x44B8F0, "Unit_ai_eval_airdrop_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C3460, 0x5D2090, 0x5C3170, "Unit_check_airlift_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C4F60, 0x5D3C40, 0x5C4C70, "Unit_can_airlift", "bool (__fastcall *) (Unit * this)" +inlead, 0x5C5040, 0x5D3D20, 0x5C4D50, "Unit_airlift", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +repl call, 0x450C9C, 0x452D98, 0x450D1C, "City_count_airports_for_ai_airlift_target", "" +repl call, 0x452A3A, 0x454B5F, 0x452ABA, "City_count_airports_for_ai_airlift_target", "" +inlead, 0x44F040, 0x4510E0, 0x44F0C0, "Unit_ai_go_to_capital", "bool (__fastcall *) (Unit * this)" +inlead, 0x5C3900, 0x5D2540, 0x5C3610, "Unit_check_rebase_target", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x5C3860, 0x5D24A0, 0x5C3570, "Unit_is_in_rebase_range", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +define, 0x5C71C0, 0x5D6060, 0x5C6ED0, "Unit_rebase", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +define, 0x5E6D20, 0x5F6580, 0x5E6C50, "diff_to_neighbor_index", "int (__cdecl *) (int dx, int dy, int lim)" +repl call, 0x421060, 0x4225BA, 0x4210E0, "Map_compute_ni_for_work_area", "" +repl vptr, 0x670190, 0x68D240, 0x670190, "Map_m28_find_cnter_neigh_point_for_work_area", "int (__fastcall *) (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim)" +define, 0x4C538E, 0x4CCC47, 0x4C53AE, "ADDR_FIND_CENTER_NP_SPOTLIGHT_RET", "int" +define, 0x4DF9E0, 0x4E8390, 0x4DFAA0, "Main_Screen_Form_bring_tile_into_view", "void (__fastcall *) (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5)" +repl call, 0x421853, 0x422DC1, 0x4218D3, "Main_Screen_Form_bring_cnter_view_city_focus", "" +repl call, 0x41BBB1, 0x41CD89, 0x41BC31, "Main_Screen_Form_bring_cnter_view_city_arrow", "" +repl call, 0x41BDB5, 0x41CFCD, 0x41BE35, "Main_Screen_Form_bring_cnter_view_city_arrow", "" +define, 0x4BBC80, 0x4C32D0, 0x4BBD10, "City_stop_working_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" +define, 0x4BB6F0, 0x4C2D50, 0x4BB780, "City_start_working_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" +repl call, 0x4ADA69, 0x4B4A51, 0x4ADAF9, "ni_to_diff_for_work_area", "" +repl call, 0x4ADAF4, 0x4B4AD8, 0x4ADB84, "ni_to_diff_for_work_area", "" +ext walup, 0x4ADB6F, 0x4B4B53, 0x4ADBFF, "", "" +repl call, 0x4AE49F, 0x4B5485, 0x4AE52F, "ni_to_diff_for_work_area", "" +ext walup, 0x4AE525, 0x4B550B, 0x4AE5B5, "", "" +repl call, 0x4AE7C2, 0x4B57A1, 0x4AE852, "ni_to_diff_for_work_area", "" +define, 0x4B0470, 0x4B7430, 0x4B0500, "City_add_or_remove_tile_yield", "void (__fastcall *) (City * this, int edx, int neighbor_index, bool add_else_remove)" +repl call, 0x4AE831, 0x4B5806, 0x4AE8C1, "City_add_or_remove_tile_yield_conv_ni", "" +ext walup, 0x4AE842, 0x4B580F, 0x4AE8D2, "", "" +repl call, 0x4AEF35, 0x4B5F13, 0x4AEFC5, "ni_to_diff_for_work_area", "" +repl call, 0x4AEFAF, 0x4B5F83, 0x4AF03F, "ni_to_diff_for_work_area", "" +ext walup, 0x4AF034, 0x4B5FFF, 0x4AF0C4, "", "" +ext walup, 0x4AF0CE, 0x4B6099, 0x4AF15E, "", "" +repl call, 0x4AF355, 0x4B631E, 0x4AF3E5, "ni_to_diff_for_work_area", "" +ext walup, 0x4AF3D7, 0x4B63A0, 0x4AF467, "", "" +repl call, 0x4AF4F6, 0x4B64B9, 0x4AF586, "ni_to_diff_for_work_area", "" +ext walup, 0x4AF5A6, 0x4B656B, 0x4AF636, "", "" +repl call, 0x4B0F2D, 0x4B7EDD, 0x4B0FBD, "ni_to_diff_for_work_area", "" +repl call, 0x4B0FC3, 0x4B7F73, 0x4B1053, "ni_to_diff_for_work_area", "" +ext walup, 0x4B1047, 0x4B7FF7, 0x4B10D7, "", "" +repl call, 0x4B2414, 0x4B93AD, 0x4B24A4, "ni_to_diff_for_work_area", "" +repl call, 0x4B247D, 0x4B9412, 0x4B250D, "City_add_or_remove_tile_yield_conv_ni", "" +ext walup, 0x4B2490, 0x4B941B, 0x4B2520, "", "" +define, 0x4C2680, 0x4C9EB0, 0x4C26A0, "City_is_neighboring_tile_in_area", "bool (__fastcall *) (City * this, int edx, int neighbor_index)" +repl call, 0x4B260C, 0x4B9593, 0x4B269C, "City_is_neighboring_tile_in_area_conv_ni", "" +repl call, 0x4B261A, 0x4B95A1, 0x4B26AA, "City_add_or_remove_tile_yield_conv_ni", "" +ext walup, 0x4B2623, 0x4B95AA, 0x4B26B3, "", "" +repl call, 0x4BA09E, 0x4C170E, 0x4BA12E, "ni_to_diff_for_work_area", "" +repl call, 0x4BA124, 0x4C1790, 0x4BA1B4, "ni_to_diff_for_work_area", "" +ext walup, 0x4BA19E, 0x4C180A, 0x4BA22E, "", "" +repl call, 0x435459, 0x436F39, 0x4354D9, "ni_to_diff_for_work_area", "" +ext walup, 0x43550D, 0x436FED, 0x43558D, "", "" +repl call, 0x43688D, 0x4382FD, 0x43690D, "ni_to_diff_for_work_area", "" +ext walup, 0x436988, 0x4383F8, 0x436A08, "", "" +inlead, 0x4BB4D0, 0x4C2B20, 0x4BB560, "City_controls_tile", "bool (__fastcall *) (City * this, int edx, int neighbor_index, bool consider_enemy_units)" +repl call, 0x43564F, 0x43712B, 0x4356CF, "City_controls_tile_conv_ni", "" +repl call, 0x435667, 0x437143, 0x4356E7, "ni_to_diff_for_work_area", "" +repl call, 0x4356E3, 0x4371B9, 0x435763, "City_stop_working_tile_conv_ni", "" +ext walup, 0x4356F6, 0x4371C2, 0x435776, "", "" +repl call, 0x435729, 0x4371F1, 0x4357A9, "ni_to_diff_for_work_area", "" +repl call, 0x4357A1, 0x437269, 0x435821, "City_controls_tile_conv_ni", "" +ext walup, 0x4357D7, 0x43728F, 0x435857, "", "" +repl call, 0x4357E8, 0x4372A0, 0x435868, "City_start_working_tile_conv_ni", "" +repl call, 0x435895, 0x43733F, 0x435915, "ni_to_diff_for_work_area", "" +repl call, 0x435925, 0x4373D1, 0x4359A5, "City_controls_tile_conv_ni", "" +ext walup, 0x43595B, 0x4373F7, 0x4359DB, "", "" +repl call, 0x43597C, 0x437418, 0x4359FC, "ni_to_diff_for_work_area", "" +repl call, 0x435A91, 0x43752D, 0x435B11, "City_start_working_tile_conv_ni", "" +repl call, 0x5BD837, 0x5CC412, 0x5BD547, "Map_compute_ni_for_work_area", "" +repl vptr, 0x66DCB8, 0x68AD9C, 0x66DCB8, "City_find_best_tile_to_work", "int (__fastcall *) (City * this, int edx, Unit * worker, bool param_2)" +repl call, 0x436328, 0x437DBB, 0x4363A8, "ni_to_diff_for_work_area", "" +ext walup, 0x436805, 0x438273, 0x436885, "", "" +repl call, 0x420CC5, 0x422219, 0x420D45, "ni_to_diff_for_work_area", "" +repl call, 0x420DD7, 0x422327, 0x420E57, "ni_to_diff_for_work_area", "" +ext walup, 0x420F05, 0x422466, 0x420F85, "", "" +repl call, 0x420F3A, 0x42249A, 0x420FBA, "ni_to_diff_for_work_area", "" +ext walup, 0x421182, 0x4226D7, 0x421202, "", "" +repl call, 0x4AFCE0, 0x4B6C9C, 0x4AFD70, "City_is_neighboring_tile_in_area_conv_ni", "" +repl call, 0x4AFCEE, 0x4B6CAA, 0x4AFD7E, "City_add_or_remove_tile_yield_conv_ni", "" +ext walup, 0x4AFCF7, 0x4B6CB3, 0x4AFD87, "", "" +repl call, 0x4BA663, 0x4C1CC2, 0x4BA6F3, "City_is_neighboring_tile_in_area_conv_ni", "" +repl call, 0x4BA671, 0x4C1CD0, 0x4BA701, "City_add_or_remove_tile_yield_conv_ni", "" +ext walup, 0x4BA67A, 0x4C1CD9, 0x4BA70A, "", "" +repl call, 0x42053D, 0x421A1D, 0x4205BD, "Map_compute_ni_for_work_area", "" +repl call, 0x435D78, 0x437802, 0x435DF8, "Map_compute_ni_for_work_area", "" +repl call, 0x5DA3B6, 0x5E9925, 0x5DA2E6, "Map_compute_ni_for_work_area", "" +repl vptr, 0x66DCAC, 0x68AD90, 0x66DCAC, "City_find_min_value_tile", "int (__fastcall *) (City * this)" +repl call, 0x420ECD, 0x422426, 0x420F4D, "Sprite_draw_already_worked_tile_img", "" +repl call, 0x420668, 0x421B48, 0x4206E8, "Map_compute_ni_for_work_area", "" +define, 0x420672, 0x421B52, 0x4206F2, "ADDR_REDUNDANT_CHECK_ON_WORK_AREA_HOVER", "byte *" +repl call, 0x5668EE, 0x572C9B, 0x56689E, "Map_compute_ni_for_work_area", "" +define, 0x420547, 0x421A27, 0x4205C7, "ADDR_CITY_FORM_LEFT_CLICK_JUMP", "byte *" +define, 0x4BB4EB, 0x4C2B3C, 0x4BB57B, "ADDR_CONTROLS_TILE_JUMP", "byte *" +repl call, 0x5DA4D1, 0x5E9A48, 0x5DA401, "ni_to_diff_for_work_area", "" +ext walup, 0x5DA555, 0x5E9ACC, 0x5DA485, "", "" +repl call, 0x4C0309, 0x4C78FE, 0x4C0399, "ni_to_diff_for_work_area", "" +ext walup, 0x4C03EA, 0x4C79D9, 0x4C047A, "", "" +repl call, 0x442603, 0x4443D2, 0x442683, "Tile_m43_Get_field_30_for_city_loc_eval", "" +repl call, 0x4427B9, 0x444585, 0x442839, "Tile_m43_Get_field_30_for_city_loc_eval", "" +repl call, 0x4B2FC1, 0x4B9F41, 0x4B3051, "rand_int_to_place_pollution", "" +repl call, 0x4B2FF4, 0x4B9F76, 0x4B3084, "ni_to_diff_for_work_area", "" +define, 0x4B2FEB, 0x4B9F6E, 0x4B307B, "ADDR_SPAWN_POLLUTION_MOD", "byte *" +ext walup, 0x4B309F, 0x4BA025, 0x4B312F, "", "" +repl call, 0x43535D, 0x436E49, 0x4353DD, "ni_to_diff_for_work_area", "" +repl call, 0x4353CA, 0x436EB6, 0x43544A, "City_controls_tile_conv_ni", "" +ext walup, 0x43540B, 0x436EEF, 0x43548B, "", "" +define, 0x4E3B10, 0x4EC360, 0x4E3BD0, "Main_Screen_Form_tile_to_screen_coords", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int * out_x, int * out_y)" +repl call, 0x420C68, 0x4221BC, 0x420CE8, "Main_Screen_Form_t2s_coords_to_draw_yields", "" +repl call, 0x420887, 0x421D88, 0x420907, "Main_Screen_Form_t2s_coords_to_draw_yields", "" +inlead, 0x420C40, 0x422190, 0x420CC0, "City_Form_draw_yields_on_worked_tiles", "void (__fastcall *) (City_Form * this)" +inlead, 0x420860, 0x421D60, 0x4208E0, "City_Form_draw_highlighted_yields", "bool (__fastcall *) (City_Form * this, int edx, int tile_x, int tile_y, int neighbor_index)" +inlead, 0x420F20, 0x422480, 0x420FA0, "City_Form_draw_border_around_workable_tiles", "void (__fastcall *) (City_Form * this)" +inlead, 0x4229F0, 0x423FA0, 0x422A70, "City_Form_draw_food_income_icons", "void (__fastcall *) (City_Form * this)" +inlead, 0x4BFAB0, 0x4C7070, 0x4BFB40, "City_draw_production_income_icons", "void (__fastcall *) (City * this, int edx, int canvas, int * rect_ptr)" +repl call, 0x4BFBB7, 0x4C7177, 0x4BFC47, "Sprite_draw_production_income_icon", "" +repl call, 0x421095, 0x4225EF, 0x421115, "Main_Screen_Form_t2s_coords_to_draw_yields", "" +repl call, 0x420FC5, 0x422525, 0x421045, "Map_get_tile_for_work_area_drawing", "" +repl call, 0x420DA2, 0x4222F8, 0x420E22, "Map_get_tile_for_work_area_drawing", "" +repl call, 0x5DA3BE, 0x5E992D, 0x5DA2EE, "City_stop_working_polluted_tile", "" +repl vptr, 0x66DCB0, 0x68AD94, 0x66DCB0, "City_manage_by_governor", "void (__fastcall *) (City * this, int edx, bool param_1)" +define, 0x5DA3CC, 0x5E993B, 0x5DA2FC, "ADDR_MANAGE_CITY_AFTER_POLLUTION_RETURN", "int" +define, 0x56D040, 0x5799C0, 0x56CFB0, "find_nearest_city", "City * (__cdecl *) (int tile_x, int tile_y, int owner_id, int continent_id, int ignore_owner_id, int perspective_id, City * ignore_city)" +repl call, 0x438A5B, 0x43A5E6, 0x438ADB, "find_nearest_city_for_ai_alliance_eval", "" +define, 0x9C34EC, 0x9E5CE4, 0x9C34AC, "p_nearest_city_distance", "int *" +define, 0x565400, 0x571790, 0x5653B0, "Leader_bounce_trespassing_units", "void (__fastcall *) (Leader * this, int edx, int against_civ_id)" +inlead, 0x446840, 0x448650, 0x4468C0, "Leader_begin_turn", "void (__fastcall *) (Leader * this)" +repl call, 0x5654AC, 0x571841, 0x56545C, "Unit_is_visible_to_civ_for_bouncing", "" +inlead, 0x5025B0, 0x50C230, 0x502650, "Leader_make_peace", "void (__fastcall *) (Leader * this, int edx, int civ_id)" +inlead, 0x5C5BD0, 0x5D4970, 0x5C58E0, "Unit_can_load", "bool (__fastcall *) (Unit * this, int edx, Unit * passenger)" +repl call, 0x5CDE34, 0x5DCEF4, 0x5CDD54, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x5CDE4C, 0x5DCF0C, 0x5CDD6C, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x5C7774, 0x5D6624, 0x5C7484, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x57F6F4, 0x58C41E, 0x57F454, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x57FF93, 0x58CCA6, 0x57FCF3, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x580486, 0x58D1B5, 0x5801E6, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x464BA9, 0x46715E, 0x464C29, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x46514C, 0x46771C, 0x4651CC, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x465560, 0x467B41, 0x4655E0, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x58067D, 0x58D39A, 0x5803DD, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x565693, 0x571A45, 0x565643, "Leader_count_any_shared_wonders_with_flag", "" +inlead, 0x4BD420, 0x4C4A80, 0x4BD4B0, "City_add_happiness_from_buildings", "void (__fastcall *) (City * this, int edx, int * inout_happiness, int * inout_unhappiness)" +define, 0x4BDDE0, 0x4C5410, 0x4BDE70, "City_count_other_buildings_on_continent", "int (__fastcall *) (City * this, int edx, int improv_id)" +repl call, 0x4BD5F0, 0x4C4C50, 0x4BD680, "City_count_other_cont_happiness_buildings", "" +repl call, 0x5C056D, 0x5CF10D, 0x5C027D, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4ACEFE, 0x4B3ED3, 0x4ACF8E, "Leader_count_any_shared_wonders_with_flag", "" +inlead, 0x562380, 0x56E4F0, 0x562330, "Leader_update_great_library_unlocks", "void (__fastcall *) (Leader * this)" +repl call, 0x562390, 0x56E4FB, 0x562340, "Leader_count_any_shared_wonders_with_flag", "" +define, 0x4B5050, 0x4BC030, 0x4B50E0, "City_can_take_outside_shields", "bool (__fastcall *) (City * this, int edx, int param_1)" +define, 0x56A210, 0x5766B0, 0x56A1C0, "Leader_get_unit_cost", "int (__fastcall *) (Leader * this, int edx, int id, bool ignore_difficulty)" +repl call, 0x4A101C, 0x4A7BDC, 0x4A10AC, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4A10B8, 0x4A7C70, 0x4A1148, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4C0D41, 0x4C8341, 0x4C0DD1, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4C0D87, 0x4C8387, 0x4C0E17, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4C118D, 0x4C8779, 0x4C121D, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4BD95E, 0x4C4FB4, 0x4BD9EE, "Leader_count_any_shared_wonders_with_flag", "" +repl call, 0x4B24E5, 0x4B946C, 0x4B2575, "Leader_count_any_shared_wonders_with_flag", "" +inlead, 0x55A7E0, 0x5666F0, 0x55A790, "Leader_has_wonder_doubling_happiness_from", "bool (__fastcall *) (Leader * this, int edx, int improv_id)" +inlead, 0x56A2A0, 0x576740, 0x56A250, "Leader_can_build_city_improvement", "bool (__fastcall *) (Leader * this, int edx, int i_improv, bool param_2)" +repl call, 0x4BF828, 0x4C6DD8, 0x4BF8B8, "Sprite_draw_citizen_head", "" +repl call, 0x4BF95D, 0x4C6F0D, 0x4BF9ED, "Sprite_draw_entertainer_yield_icon", "" +repl call, 0x4BF912, 0x4C6EC2, 0x4BF9A2, "Sprite_draw_scientist_yield_icon", "" +repl call, 0x4BF8C0, 0x4C6E70, 0x4BF950, "Sprite_draw_tax_collector_yield_icon", "" +repl call, 0x4BF9E1, 0x4C6FA1, 0x4BFA71, "Sprite_draw_civil_engineer_yield_icon", "" +repl call, 0x4BFA45, 0x4C7005, 0x4BFAD5, "Sprite_draw_police_officer_yield_icon", "" +inlead, 0x4B9270, 0x4C08E0, 0x4B9300, "City_add_building_if_done", "void (__fastcall *) (City * this)" +define, 0x9C34E4, 0x9E5CDC, 0x9C34A4, "p_zoom_to_city_after_update", "bool *" +define, 0x5812BA, 0x58DFE7, 0x58101A, "ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN", "byte *" +inlead, 0x4BFD40, 0x4C7300, 0x4BFDD0, "City_get_turns_to_build", "int (__fastcall *) (City * this, int edx, int order_type, int order_id, bool param_3)" +repl call, 0x4C06C0, 0x4C7C80, 0x4C0750, "City_can_build_upgrade_type", "" +define, 0x4C1F80, 0x4C96B0, 0x4C2010, "Hash_Table_look_up", "bool (__fastcall *) (Hash_Table * this, int edx, int key, int * out_value)" +inlead, 0x557720, 0x563530, 0x5576D0, "Main_GUI_position_elements", "void (__fastcall *) (Main_GUI * this)" +define, 0x5FE8A0, 0x613550, 0x5FE780, "PCX_Image_get_text_line_height", "int (__fastcall *) (PCX_Image * this)" +repl vptr, 0x66AFF0, 0x6880F0, 0x66AFF0, "Civilopedia_Article_m01_Draw_GCON_or_RACE", "void (__fastcall *) (Civilopedia_Article * this)" +repl vptr, 0x66AFA8, 0x6880A8, 0x66AFA8, "Civilopedia_Article_m01_Draw_UNIT", "void (__fastcall *) (Civilopedia_Article * this)" +repl call, 0x5FF8B5, 0X614B5D, 0x5FF795, "PCX_Image_do_draw_centered_text_in_wrap_func", "" +repl call, 0x5FF7E0, 0x614A5F, 0x5FF6C0, "PCX_Image_draw_text_in_wrap_func", "" +repl call, 0x0FF, 0x614A7A, 0x0FF, "PCX_Image_draw_text_no_len_in_wrap_func", "" +repl vptr, 0x66B1B8, 0x6882B8, 0x66B1B8, "Civilopedia_Form_m68_Show_Dialog", "int (__fastcall *) (Civilopedia_Form * this, int edx, int param_1, void * param_2, void * param_3)" +repl vptr, 0x66B17C, 0x68827C, 0x66B17C, "Civilopedia_Form_m53_On_Control_Click", "void (__fastcall *) (Civilopedia_Form * this, int edx, CivilopediaControlID control_id)" +repl vptr, 0x66B100, 0x688200, 0x66B100, "Civilopedia_Form_m22_Draw", "void (__fastcall *) (Civilopedia_Form * this)" +repl call, 0x4CC5AA, 0x4D462E, 0x4CC66A, "Button_initialize_civilopedia_description", "" +define, 0x179, 0x17A, 0x179, "LBL_EFFECTS", "int" +define, 0x17A, 0x17B, 0x17A, "LBL_PREVIOUS", "int" +define, 0x128, 0x129, 0x128, "LBL_MORE", "int" +define, 0x537700, 0x541D30, 0x537780, "play_sound_effect", "void (__cdecl *) (int sound_effect)" +repl call, 0x578CD9, 0x585DF3, 0x578C49, "Tile_check_water_for_navigator_cell_coloring", "" +inlead, 0x49F5C0, 0x4A6080, 0x49F650, "PopupForm_impl_begin_showing_popup", "int (__fastcall *) (PopupForm * this)" +repl call, 0x49F5CB, 0x4A608B, 0x49F65B, "is_online_game_for_show_popup", "" +define, 0x4EEC40, 0x4F7BE0, 0x4EED00, "Animator_update", "void (__fastcall *) (Animator * this)" +inlead, 0x5C32F0, 0x5D1F20, 0x5C3000, "Unit_ai_can_sacrifice", "bool (__fastcall *) (Unit * this, int edx, bool requires_city)" +inlead, 0x4C5A10, 0x4CD2C0, 0x4C5A30, "Map_Renderer_load_images", "void (__fastcall *) (Map_Renderer *this, int edx)" +define, 0x446114, 0x447EF6, 0x446194, "ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN", "byte *" +define, 0x5663F0, 0x57275D, 0x5663A0, "ADDR_CITY_LIM_CMP_IN_CREATE_CITY", "byte *" +define, 0x4F8D76, 0x5024E6, 0x4F8E36, "ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR", "byte *" +define, 0x4C2420, 0x4C9C10, 0x4C2440, "Buildings_Info_get_age_in_years", "int (__fastcall *) (Buildings_Info * this, int edx, int building_index)" +repl call, 0x4B073C, 0x4B76F0, 0x4B07CC, "Buildings_Info_get_age_in_years_for_tourism", "" +define, 0x501CD0, 0x50B960, 0x501D70, "Leader_make_contact", "void (__fastcall *) (Leader * this, int edx, int civ_id, bool no_online_sync)" +define, 0x5F83E0, 0x608910, 0x5F8310, "Sprite_draw_for_hud", "int (__fastcall *) (Sprite * this, int edx, Sprite * alpha, int param_2, PCX_Image * canvas, int x, int y, int param_6)" +repl call, 0x55374D, 0x55EDF8, 0x5536FD, "Sprite_draw_minimap_frame", "" +define, 0x5792AB, 0x5863CB, 0x57921B, "ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT", "byte *" +repl call, 0x44580E, 0x44760E, 0x44588E, "Unit_has_king_ability_for_find_unsupported", "" +define, 0x4BFD20, 0x4C72E0, 0x4BFDB0, "City_get_turns_to_build_2", "int (__fastcall *) (City * this, int edx, City_Order * order, bool param_2)" +repl call, 0x45FF66, 0x462336, 0x45FFE6, "City_get_turns_to_build_2_for_ai_move_leader", "" +repl call, 0x4600F8, 0x4624E5, 0x460178, "City_get_turns_to_build_2_for_ai_move_leader", "" +define, 0x50FDB3, 0x51A057, 0x50FE53, "ADDR_MAX_TRADABLE_CITY_ID", "byte *" +define, 0x505B21, 0x50F8EB, 0x505BC1, "ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR", "byte *" +define, 0x51000C, 0x51A2AC, 0x5100AC, "ADDR_MAX_TRADABLE_UNIT_ID", "byte *" +define, 0x505B67, 0x50F931, 0x505C07, "ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR", "byte *" +repl vptr, 0x66A52C, 0x687638, 0x66A52C, "Map_Renderer_m09_Draw_Tile_Resources", "void (__fastcall *) (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" +repl vptr, 0x66A538, 0x687644, 0x66A538, "Map_Renderer_m12_Draw_Tile_Buildings", "void (__fastcall *) (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" +inlead, 0x5F61A0, 0x605F50, 0x5F60D0, "Map_Renderer_m11_Draw_Tile_Irrigation", "void (__fastcall *) (Map_Renderer *this, int edx, int visible_to_civ, int tile_x, int tile_y, int param_4, int param_5, int param_6)" +repl call, 0x5F5580, 0x6053D2, 0x5F54B0, "Tile_has_city_or_district", "" +repl call, 0x5F5816, 0x605639, 0x5F5746, "Tile_has_city_or_district", "" +repl call, 0x5F5ABB, 0x6058AF, 0x5F59EB, "Tile_has_city_or_district", "" +repl call, 0x5F5D75, 0x605B31, 0x5F5CA5, "Tile_has_city_or_district", "" +inlead, 0x56CEB0, 0x579830, 0x56CE20, "get_building_defense_bonus_at", "int (__cdecl *) (int x, int y, int param_3)" +define, 0x4B0540, 0x4B7500, 0x4B05D0, "City_update_food_consumption", "void (__fastcall *) (City * this)" +define, 0x5660E0, 0x572460, 0x566090, "Leader_get_food_cost_factor", "int (__fastcall *) (Leader *this, int edx, bool ignore_difficulty)" +define, 0x427540, 0x428C90, 0x4275C0, "City_get_size_class", "int (__fastcall *) (City *this)" +inlead, 0x5B39A0, 0x5C22F0, 0x5B36B0, "is_not_pop_capped_or_starving", "bool (__stdcall *) (City * city)" +inlead, 0x4068E0, 0x406E40, 0x406910, "set_worker_animation", "void (__fastcall *) (void * this, int edx, Unit * unit, int job_id)" +define, 0x5C66D0, 0x5D5520, 0x5C63E0, "get_worker_remaining_turns_to_complete", "int (__fastcall *) (Unit * this, int edx, int job_id)" +inlead, 0x435BA0, 0x437630, 0x435C20, "City_instruct_worker", "bool (__fastcall *) (City * this, int edx, int tile_x, int tile_y, bool param_3, Unit * worker)" +repl vptr, 0x66A528, 0x687634, 0x66A528, "Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp", "void (__fastcall *) (Map_Renderer * this, int edx, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" +repl vptr, 0x66A5D8, 0x6876E4, 0x66A5D8, "Map_Renderer_m52_Draw_Roads", "void (__fastcall *) (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" +repl vptr, 0x66A5D0, 0x6876DC, 0x66A5D0, "Map_Renderer_m52_Draw_Railroads", "void (__fastcall *) (Map_Renderer * this, int edx, int sprite_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y)" +inlead, 0x5EB580, 0x5FADD0, 0x5EB4B0, "Map_impl_generate", "void (__fastcall *) (Map * this, int edx, int seed, bool is_multiplayer_game, int num_seafaring_civs)" +inlead, 0x4E5580, 0x4EDEB0, 0x4E5640, "Main_Screen_Form_draw_city_hud", "void (__fastcall *) (Main_Screen_Form * this, int edx, PCX_Image * canvas)" +inlead, 0x4BFF80, 0x4C7580, 0x4C0010, "City_can_build_improvement", "bool (__fastcall *) (City * this, int edx, int i_improv, bool apply_strict_rules)" +repl call, 0x5C1C53, 0x5D07F6, 0x5C1963, "Unit_has_army_ability_to_perform_unload", "" +inlead, 0x5C59B0, 0x5D4740, 0x5C56C0, "Unit_disembark", "void (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +define, 0x4A12D0, 0x4A7E80, 0x4A1360, "Fighter_prefer_first_defender_1", "bool (__fastcall *) (Fighter * this, int edx, Unit * first, int first_strength, Unit * second, int second_strength, bool param_5)" +repl call, 0x5C5C82, 0x5D4A23, 0x5C5992, "Unit_has_ability_no_load_non_army_passengers", "" +repl call, 0x5C5C93, 0x5D4A34, 0x5C59A3, "Unit_has_ability_no_load_transport_into_army", "" +inlead, 0x4A1590, 0x4A8140, 0x4A1620, "Fighter_unit_can_defend", "bool (__fastcall *) (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y)" +define, 0x558F70, 0x564E30, 0x558F20, "Leader_is_enemy_unit", "bool (__fastcall *) (Leader * this, int edx, Unit * unit)" +repl call, 0x5C6C5B, 0x5D5AD4, 0x5C696B, "Leader_is_enemy_unit_for_ground_aa", "" +repl call, 0x5BC013, 0x5CAB6A, 0x5BBD23, "Unit_has_army_ability_for_passenger_despawn", "" +define, 0x4A63F4, 0x4AD09E, 0x4A6484, "DESPAWN_TO_FIGHT_1_RETURN", "int" +define, 0x4A6EF7, 0x4ADBAB, 0x4A6F87, "DESPAWN_TO_FIGHT_2_RETURN", "int" +define, 0x4A4436, 0x4AB104, 0x4A44C6, "DESPAWN_TO_DO_BOMBARD_TILE_RETURN", "int" +define, 0x4A31C6, 0x4A9E19, 0x4A3256, "DESPAWN_TO_CRUISE_MISSILE_DEFENDER_RETURN", "int" +define, 0x5659E2, 0x571D83, 0x565992, "DESPAWN_TO_BOUNCE_TRESPASSING_UNITS_RETURN", "int" +define, 0x5B4844, 0x5C319E, 0x5B4554, "DESPAWN_TO_NUKE_DAMAGE_RETURN", "int" +define, 0x5B8462, 0x5C6E78, 0x5B8172, "DESPAWN_TO_DO_CAPTURE_UNITS_RETURN", "int" +define, 0x5BC0A2, 0x5CABF1, 0x5BBDB2, "DESPAWN_RECURSIVE_RETURN", "int" +define, 0x5C7030, 0x5D5EBB, 0x5C6D40, "DESPAWN_TO_TRY_FLYING_OVER_TILE_RETURN", "int" +repl call, 0x5B8D95, 0x5C7801, 0x5B8AA5, "count_units_at_in_try_capturing", "" +define, 0x5F35C2, 0x603442, 0x5F34F2, "ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9", "byte *" +inlead, 0x5F22A0, 0x6020D0, 0x5F21D0, "Map_generate_resources", "void (__fastcall *) (Map * this, int edx, int secondary_seed)" +define, 0x5F2C25, 0x602AF6, 0x5F2B55, "ADDR_RESOURCE_GEN_TILE_COUNT_DIV", "byte *" +repl call, 0x5BFA0C, 0x5CE59E, 0x5BF71C, "rand_int_to_enslave", "" +repl call, 0x52A165, 0x53452B, 0x52A205, "Sprite_draw_espionage_screen_target_civ_bkg", "" +repl call, 0x52A1C1, 0x534587, 0x52A261, "Civilopedia_Article_get_name_for_esp_screen", "" +define, 0xA422F8, 0xA64AF8, 0xA422B8, "p_espionage_form", "Espionage_Form *" +define, 0x680758, 0x69D768, 0x680758, "animation_names", "char **" +define, 0x5BF2FB, 0x5CDE95, 0x5BF00B, "ADDR_SKIP_VICTORY_ANIM_IF_AIR", "byte *" +repl call, 0x5BF4D5, 0x5CE066, 0x5BF1E5, "Animator_play_one_shot_victory_animation", "" +inlead, 0x4DBFC0, 0x4E4990, 0x4DC080, "Main_Screen_Form_assemble_selectable_units", "void (__fastcall *) (Main_Screen_Form * this)" +inlead, 0x4DBA70, 0x4E4440, 0x4DBB30, "Main_Screen_Form_set_selected_unit", "void (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit, bool param_2)" +inlead, 0x4DBD70, 0x4E4740, 0x4DBE30, "Main_Screen_Form_find_next_unit_for_cycling", "Unit * (__fastcall *) (Main_Screen_Form * this)" +define, 0x4EDD40, 0x4F6C90, 0x4EDE00, "UnitIDList_insert_before", "void (__fastcall *) (UnitIDList * this, int edx, int id, UnitIDItem * item)" +define, 0x5BE970, 0x5CD590, 0x5BE680, "Unit_can_cycle_to", "bool (__fastcall *) (Unit * this)" +define, 0x4DABB2, 0x4E3570, 0x4DAC72, "SET_SELECTED_UNIT_TO_ISSUE_WAIT_COMMAND_RET", "int" +repl vptr, 0x66DCD0, 0x68ADB4, 0x66DCD0, "City_m22", "void (__fastcall *) (City * this, int edx, bool param_1)" +define, 0x4B95D7, 0x4C0C43, 0x4B9667, "CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_1", "int" +define, 0x4B96C9, 0x4C0D35, 0x4B9759, "CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_2", "int" +define, 0x4B90D6, 0x4C0743, 0x4B9166, "CITY_M22_TO_SPAWN_UNIT_IF_DONE_RETURN", "int" +inlead, 0x5B6CE0, 0x5C5670, 0x5B69F0, "Unit_do_capture_units", "bool (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, int owner_civ_id)" +define, 0xA38C18, 0xA5B418, 0xA38BD8, "p_advisor_internal_form", "Advisor_Internal_Form *" +repl call, 0x51DC54, 0x527A41, 0x51DCF4, "PCX_Image_process_dom_adv_turn_count_text", "" +define, 0x4B1205, 0x4B81B5, 0x4B1295, "ADDR_CORRUPTION_CAPITAL_CHECK", "byte *" +define, 0x4B12C0, 0x4B8272, 0x4B1350, "ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT", "byte *" +define, 0xCCF76C, 0xCF1DC4, 0xCCF724, "p_code_page", "unsigned *" +define, 0x4ED5F0, 0x4F6520, 0x4ED6B0, "MenuUnitList_get_length", "int (__fastcall *) (MenuUnitList * this)" +repl call, 0x4E8BD4, 0x4F1895, 0x4E8C94, "MenuUnitList_get_length_before_sorting", "" +define, 0x4E7E00, 0x4F08C0, 0x4E7EC0, "MenuUnitItem_should_appear_after", "bool (__fastcall *) (MenuUnitItem * this, int edx, MenuUnitItem * other)" +define, 0xA52B6C, 0xA75364, 0xA52B2C, "p_allow_ai_patrol", "bool *" +define, 0x5F1F50, 0x601D30, 0x5F1E80, "Map_finalize_params", "void (__fastcall *) (Map * this)" +repl call, 0x5D1888, 0x5E0B0E, 0x5D17B8, "Map_finalize_params_for_scenario_map", "" +define, 518, 519, 518, "LBL_NO_BARBARIANS", "int" +define, 545, 546, 545, "LBL_RANDOM_BARBS", "int" +define, 0x4BA230, 0x4C18A0, 0x4BA2C0, "City_remove_population", "void (__fastcall *) (City * this, int edx, int num_pops, int race_id, char param_3)" +define, 0x4AE280, 0x4B5260, 0x4AE310, "City_get_largest_adjacent_sea", "int (__fastcall *) (City * this)" +repl call, 0x4C008E, 0x4C7686, 0x4C011E, "City_get_largest_adjacent_sea_within_work_area", "" +repl call, 0x4C010F, 0x4C7707, 0x4C019F, "Map_impl_has_fresh_water_within_work_area", "" +repl call, 0x4C0173, 0x4C776C, 0x4C0203, "Map_impl_is_near_river_within_work_area", "" +repl call, 0x4C01AF, 0x4C77A8, 0x4C023F, "Map_impl_is_near_river_within_work_area", "" +repl call, 0x4C01CF, 0x4C77C8, 0x4C025F, "Map_impl_is_near_lake_within_work_area", "" +inlead, 0x458120, 0x45A2E0, 0x4581A0, "Unit_ai_move_naval_power_unit", "void (__fastcall *) (Unit * this)" +inlead, 0x45A170, 0x45C380, 0x45A1F0, "Unit_ai_move_naval_transport", "void (__fastcall *) (Unit * this)" +inlead, 0x460620, 0x462A20, 0x4606A0, "Unit_ai_move_naval_missile_transport", "void (__fastcall *) (Unit * this)" +inlead, 0x44C130, 0x44E110, 0x44C1B0, "Unit_ai_eval_pillage_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y)" +inlead, 0x456840, 0x458A50, 0x4568C0, "Unit_ai_move_air_bombard_unit", "void (__fastcall *) (Unit * this)" +inlead, 0x4579E0, 0x459BB0, 0x457A60, "Unit_ai_move_air_defense_unit", "void (__fastcall *) (Unit * this)" +inlead, 0x459CE0, 0x45BF00, 0x459D60, "Unit_ai_move_air_transport", "void (__fastcall *) (Unit * this)" +define, 0x5C1920, 0x5D04B0, 0x5C1630, "Unit_airdrop", "void (__fastcall *) (Unit * this, int edx, int x, int y)" +repl call, 0x4C0D87, 0x4C8387, 0x4C0E17, "Leader_count_wonders_with_flag_ignore_great_wall", "" +repl call, 0x5D3D67, 0x5E30FC, 0x5D3C97, "Tile_has_colony_ignore_extraterritorial", "" +inlead, 0x440100, 0x441ED0, 0x440180, "Leader_get_attitude_toward", "int (__fastcall *) (Leader * this, int edx, int civ_id, int param_2)" +inlead, 0x5D7080, 0x5E64E0, 0x5D6FB0, "Map_check_colony_location", "int (__fastcall *) (Map * this, int edx, int tile_x, int tile_y, int civ_id)" +inlead, 0x5BCE60, 0x5CBA10, 0x5BCB70, "Unit_select_army_member_for_combat", "Unit * (__fastcall *) (Unit * this, int edx, int param_1, char param_2)" +inlead, 0x44C340, 0x44E330, 0x44C3C0, "Unit_ai_eval_bombard_target", "int (__fastcall *) (Unit * this, int edx, int tile_x, int tile_y, int param_3)" +define, 0x5CD770, 0x5DC720, 0x5CD690, "UnitIDList_insert_after", "void (__fastcall *) (UnitIDList * this, int edx, int id, UnitIDItem * item)" +repl call, 0x5BBBA6, 0x5CA70C, 0x5BB8B6, "UnitIDList_insert_after_init", "" +define, 0x5BCC90, 0x5CB840, 0x5BC9A0, "Unit_load_into_army", "void (__fastcall *) (Unit * this, int edx, Unit * loadee)" +repl call, 0x5B9FEC, 0x5C8AB3, 0x5B9CFC, "Unit_load_into_army_after_move_to_adj_tile", "" +define, 0x5FF750, 0x6149E0, 0x5FF630, "PCX_Image_draw_and_wrap_text", "int (__fastcall *) (PCX_Image * this, int edx, char * str, int x, int y, int width)" +repl call, 0x4D5283, 0x4DDA46, 0x4D5343, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +repl call, 0x4D52EA, 0x4DDAAE, 0x4D53AA, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +repl call, 0x4D5340, 0x4DDB05, 0x4D5400, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +repl call, 0x4D5396, 0x4DDB5C, 0x4D5456, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +repl call, 0x4D5400, 0x4DDBC5, 0x4D54C0, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +repl call, 0x4D5464, 0x4DDC29, 0x4D5524, "PCX_Image_draw_pedia_unit_stats_2nd_column", "" +define, 0x1A5, 0x1A6, 0x1A5, "LBL_OPERATIONAL_RANGE", "int" +define, 0x4D519C, 0x4DD953, 0x4D525C, "ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS", "byte *" +define, 0x1A8, 0x1A9, 0x1A8, "LBL_BOMBARD_RANGE", "int" +ignore, 0x5FC710, 0x0, 0x0, "PCX_Image_create_and_init_jgl_image", "int (__fastcall *) (PCX_Image * this, int edx, int width, int height, int bit_depth, int param_4, int param_5, int param_6)" +ignore, 0x5FCC50, 0x0, 0x0, "PCX_Image_draw_region_to_location", "void (__fastcall *) (PCX_Image * this, int edx, PCX_Image * canvas, int src_x, int src_y, int dest_x, int dest_y, int width, int height)" +ignore, 0x600050, 0x0, 0x0, "PCX_Image_fill", "void (__fastcall *) (PCX_Image * this, int edx, int color)" +ignore, 0x5FFF10, 0x0, 0x0, "PCX_Image_set_color_table", "int (__fastcall *) (PCX_Image * this, int edx, PCX_Color_Table * color_table)" +ignore, 0x4507B0, 0x452860, 0x0, "Unit_ai_move_offensive_unit", "void (__fastcall *) (Unit * this)" +ignore, 0x558F70, 0x0, 0x0, "Leader_is_enemy_unit", "char (__fastcall *) (Leader * this, int edx, Unit * unit)" +ignore, 0x4BFD40, 0x0, 0x0, "City_get_turns_to_build", "int (__fastcall *) (City * this, int edx, int order_type, int order_id, char param_3)" +ignore, 0x4E3D90, 0x0, 0x0, "Main_Screen_Form_is_unit_hidden_from_player", "bool (__fastcall *) (Main_Screen_Form * this, int edx, Unit * unit)" +ignore, 0x4E8850, 0x4F14E0, 0x4E8910, "Main_Screen_Form_open_right_click_unit_menu", "void (__fastcall *) (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y)" +ignore, 0x5CCBB0, 0x0, 0x0, "Unit_can_pass_between", "PassBetweenValidity (__fastcall *) (Unit * this, int edx, int from_x, int from_y, int to_x, int to_y, byte param_5)" +ignore, 0x452510, 0x454600, 0x452590, "ai_move_defensive_unit", "void (__fastcall *) (Unit * this)" +ignore, 0x5E78E0, 0x5F7130, 0x0, "General_load", "void (__fastcall *) (General * this, int edx, byte ** buffer)" +ignore, 0x5E7020, 0x5F6870, 0x0, "General_clear", "void (__fastcall *) (General * this)" +ignore, 0x605010, 0x61C6A0, 0x604F00, "Base_Form_impl_m01_Show_Enabled", "void (__fastcall *) (Base_Form * this, int edx, byte flags)" +ignore, 0x74AF60, 0x0, 0x0, "p_sync_object", "void *" +ignore, 0x5C0E20, 0x5CF9C0, 0x5C0B30, "Unit_begin_bombarding_tile", "bool (__fastcall *) (Unit * this, int edx, int x, int y)" +ignore, 0x57F623, 0x58C352, 0x57F383, "ADDR_SUB_BUG_PATCH", "void *" +define, 0xCC2BB0, 0xCE54BC, 0xCC2B70, "p_got_leader_gender", "int *" +ignore, 0x49D070, 0x4A3AF0, 0x49D100, "Advisor_GUI_open", "void (__fastcall *) (Advisor_GUI * this, int edx, AdvisorKind kind)" +ignore, 0x4BF660, 0x4C6C10, 0x4BF6F0, "City_draw_citizens", "void (__fastcall *) (City * this, int edx, PCX_Image * canvas, RECT * rect, char param_3)" +ignore, 0x4B9F60, 0x4C15D0, 0x4B9FF0, "City_add_population", "void (__fastcall *) (City * this, int edx, int num, int race_id)" +ignore, 0x670234, 0x68D2E0, 0x670234, "Tile_m27_Check_Shield_Bonus", "bool (__fastcall *) (Tile * this)" +ignore, 0x5f3448, 0x6032DF, 0x5F3378, "CHECK_SHIELD_BONUS_TO_CAN_SPAWN_RES_RETURN", "int" + diff --git a/correlator/CLAUDE.md b/correlator/CLAUDE.md index 9488ead0..d75c43b7 100644 --- a/correlator/CLAUDE.md +++ b/correlator/CLAUDE.md @@ -1,100 +1,100 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Codebase Overview - -This is the **correlator** subdirectory of the C3X project - a Python tool designed to correlate functions between different versions of the Civilization III: Conquests executable (GOG vs Steam versions). The correlator helps with reverse engineering by matching functions across different builds using multiple similarity metrics. - -### Main Components - -- **correlator.py**: Primary Python script that analyzes exported function data from Ghidra -- **gog.json** & **steam.json**: Large JSON files (90MB+) containing function exports from Ghidra analysis -- Located within the larger C3X project, which is a comprehensive mod for Civilization III: Conquests - -## How to Run - -### Basic Function Lookup -```bash -python correlator.py -``` -Example: `python correlator.py 00100400` - -### Test Mode (Validate Similarity Algorithm) -```bash -python correlator.py --test -``` - -### Address Analysis Mode -```bash -python correlator.py --analyze -``` -Analyzes address differences between functions with identical names in both executables. - -### Custom Similarity Weights -```bash -python correlator.py
-python correlator.py --test -``` -Examples: -- `python correlator.py 00100400 0.4 0.3 0.1 0.2` -- `python correlator.py --test 0.4 0.3 0.1 0.2` - -## Core Architecture - -### Input Data Format -The tool expects JSON files exported from Ghidra containing function metadata: -- `name`: Function name (real names vs auto-generated "FUN_" names) -- `address`: Memory address as hex string -- `raw_bytes`: Array of function bytecode -- `disassembly`: Array of instruction objects with addresses and instruction strings -- `reference_count`: Number of references to the function - -### Similarity Algorithm -The correlator uses a weighted combination of four metrics: -- **Size similarity**: Based on raw byte count (default weight: 0.35) -- **Reference similarity**: Based on reference count (default weight: 0.27) -- **Address similarity**: Based on address proximity (default weight: 0.03) -- **Opcode similarity**: Based on instruction pattern matching using n-grams (default weight: 0.35) - -### Key Functions -- `find_most_similar_function()`: Core matching algorithm -- `test_name_matching()`: Validation using functions with identical real names -- `load_ghidra_export()`: JSON data loader with feature preprocessing -- `analyze_address_differences()`: Address offset analysis -- `calculate_opcode_similarity()`: Instruction pattern matching using 2-grams and 3-grams - -### Performance Optimizations -- **Opcode preprocessing**: N-grams are precomputed during JSON loading to avoid repeated calculations -- **Progress reporting**: Shows preprocessing progress for large datasets -- **Cached features**: Stores `_bigrams` and `_trigrams` sets in function objects - -## Context - Parent C3X Project - -This correlator is part of the larger C3X mod project, which: -- Modifies the Civilization III: Conquests executable -- Uses TCC (Tiny C Compiler) for code injection -- Requires reverse engineering to match functions across game versions -- The correlator specifically helps identify corresponding functions between GOG and Steam builds - -## Dependencies - -- Python 3 (standard library only - json, sys, os, typing, collections) -- No external packages required -- Requires pre-generated JSON exports from Ghidra analysis - -## Usage Notes - -- JSON files are extremely large (90MB+) - initial loading includes preprocessing that takes 10-30 seconds -- Test mode validates the similarity algorithm against functions with identical real names (~82% accuracy with default weights) -- Address lookups are case-insensitive and handle "0x" prefixes -- The tool normalizes addresses by converting to integers to ignore leading zeros -- Real function names exclude auto-generated patterns: "FUN_", "thunk_", "Unwind@", "__", "FID_conflict:" -- Address analysis shows average absolute difference of ~86,852 bytes between matching functions - -## Current Performance - -With optimized default weights (0.35/0.27/0.03/0.35), the correlator achieves: -- ~82% correct matches on functions with real names -- Significantly improved accuracy through opcode pattern matching +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Codebase Overview + +This is the **correlator** subdirectory of the C3X project - a Python tool designed to correlate functions between different versions of the Civilization III: Conquests executable (GOG vs Steam versions). The correlator helps with reverse engineering by matching functions across different builds using multiple similarity metrics. + +### Main Components + +- **correlator.py**: Primary Python script that analyzes exported function data from Ghidra +- **gog.json** & **steam.json**: Large JSON files (90MB+) containing function exports from Ghidra analysis +- Located within the larger C3X project, which is a comprehensive mod for Civilization III: Conquests + +## How to Run + +### Basic Function Lookup +```bash +python correlator.py +``` +Example: `python correlator.py 00100400` + +### Test Mode (Validate Similarity Algorithm) +```bash +python correlator.py --test +``` + +### Address Analysis Mode +```bash +python correlator.py --analyze +``` +Analyzes address differences between functions with identical names in both executables. + +### Custom Similarity Weights +```bash +python correlator.py
+python correlator.py --test +``` +Examples: +- `python correlator.py 00100400 0.4 0.3 0.1 0.2` +- `python correlator.py --test 0.4 0.3 0.1 0.2` + +## Core Architecture + +### Input Data Format +The tool expects JSON files exported from Ghidra containing function metadata: +- `name`: Function name (real names vs auto-generated "FUN_" names) +- `address`: Memory address as hex string +- `raw_bytes`: Array of function bytecode +- `disassembly`: Array of instruction objects with addresses and instruction strings +- `reference_count`: Number of references to the function + +### Similarity Algorithm +The correlator uses a weighted combination of four metrics: +- **Size similarity**: Based on raw byte count (default weight: 0.35) +- **Reference similarity**: Based on reference count (default weight: 0.27) +- **Address similarity**: Based on address proximity (default weight: 0.03) +- **Opcode similarity**: Based on instruction pattern matching using n-grams (default weight: 0.35) + +### Key Functions +- `find_most_similar_function()`: Core matching algorithm +- `test_name_matching()`: Validation using functions with identical real names +- `load_ghidra_export()`: JSON data loader with feature preprocessing +- `analyze_address_differences()`: Address offset analysis +- `calculate_opcode_similarity()`: Instruction pattern matching using 2-grams and 3-grams + +### Performance Optimizations +- **Opcode preprocessing**: N-grams are precomputed during JSON loading to avoid repeated calculations +- **Progress reporting**: Shows preprocessing progress for large datasets +- **Cached features**: Stores `_bigrams` and `_trigrams` sets in function objects + +## Context - Parent C3X Project + +This correlator is part of the larger C3X mod project, which: +- Modifies the Civilization III: Conquests executable +- Uses TCC (Tiny C Compiler) for code injection +- Requires reverse engineering to match functions across game versions +- The correlator specifically helps identify corresponding functions between GOG and Steam builds + +## Dependencies + +- Python 3 (standard library only - json, sys, os, typing, collections) +- No external packages required +- Requires pre-generated JSON exports from Ghidra analysis + +## Usage Notes + +- JSON files are extremely large (90MB+) - initial loading includes preprocessing that takes 10-30 seconds +- Test mode validates the similarity algorithm against functions with identical real names (~82% accuracy with default weights) +- Address lookups are case-insensitive and handle "0x" prefixes +- The tool normalizes addresses by converting to integers to ignore leading zeros +- Real function names exclude auto-generated patterns: "FUN_", "thunk_", "Unwind@", "__", "FID_conflict:" +- Address analysis shows average absolute difference of ~86,852 bytes between matching functions + +## Current Performance + +With optimized default weights (0.35/0.27/0.03/0.35), the correlator achieves: +- ~82% correct matches on functions with real names +- Significantly improved accuracy through opcode pattern matching - Balanced approach using both structural (size/references) and algorithmic (opcodes) similarity \ No newline at end of file diff --git a/correlator/correlator.py b/correlator/correlator.py index b617ace9..bbe13688 100644 --- a/correlator/correlator.py +++ b/correlator/correlator.py @@ -1,784 +1,784 @@ -#!/usr/bin/env python3 - -import json -import sys -import os -from typing import List, Dict, Any - -def precompute_function_features(functions): - """Precompute expensive features for all functions""" - print(f"Precomputing opcode features for {len(functions)} functions...") - for i, func in enumerate(functions): - if i % 1000 == 0 and i > 0: - print(f" Processed {i}/{len(functions)} functions...") - - opcodes = extract_opcodes(func.get("disassembly", [])) - func['_bigrams'] = set(get_opcode_ngrams(opcodes, 2)) - func['_trigrams'] = set(get_opcode_ngrams(opcodes, 3)) - print(f" Completed preprocessing {len(functions)} functions") - -def load_ghidra_export(filepath: str) -> List[Dict[str, Any]]: - """ - Load function data exported from Ghidra by ExportProgForPython.py - - The expected JSON format is: - [ - { - "name": "function_name", # String: Name of the function - "address": "00100400", # String: Address of function entry point - "raw_bytes": [72, 131, 236, ...], # List[int]: Raw bytes of the function - "disassembly": [ # List[Dict]: Disassembled instructions - { - "address": "00100400", # String: Instruction address - "instruction": "SUB RSP, 0x20" # String: Disassembled instruction - }, - ... - ], - "reference_count": 5 # Int: Number of references to this function - }, - ... - ] - - Args: - filepath: Path to the exported JSON file - - Returns: - List of function data dictionaries - """ - try: - with open(filepath, 'r') as f: - data = json.load(f) - - print(f"Successfully loaded {len(data)} functions from {filepath}") - - # Precompute opcode features - precompute_function_features(data) - - return data - except json.JSONDecodeError: - print(f"Error: {filepath} contains invalid JSON") - return [] - except FileNotFoundError: - print(f"Error: File {filepath} not found") - return [] - -def find_function_by_address(functions, address): - """Find a function by its address, ignoring leading zeros and '0x' prefix""" - # Normalize the input address: remove '0x' prefix and convert to integer - if address.lower().startswith("0x"): - address = address[2:] - # Convert to integer to ignore leading zeros - normalized_address = int(address, 16) - - for function in functions: - func_addr = function["address"] - if func_addr.lower().startswith("0x"): - func_addr = func_addr[2:] - # Convert to integer to ignore leading zeros - func_addr_int = int(func_addr, 16) - - if func_addr_int == normalized_address: - return function - return None - -def calculate_size_similarity(func1, func2): - """Calculate similarity based on function size (number of bytes)""" - size1 = len(func1["raw_bytes"]) - size2 = len(func2["raw_bytes"]) - - # Calculate similarity score (1.0 is perfect match) - if size1 == 0 or size2 == 0: - return 0.0 - - # Use the ratio of the smaller to the larger size - return min(size1, size2) / max(size1, size2) - -def calculate_reference_similarity(func1, func2): - """Calculate similarity based on reference count""" - ref1 = func1["reference_count"] - ref2 = func2["reference_count"] - - # Calculate similarity score (1.0 is perfect match) - if ref1 == 0 and ref2 == 0: - return 1.0 # Both have 0 references, perfect match - elif ref1 == 0 or ref2 == 0: - return 0.0 # One has references, the other doesn't - - # Use the ratio of the smaller to the larger reference count - return min(ref1, ref2) / max(ref1, ref2) - -def extract_opcodes(disassembly): - """Extract just the instruction mnemonics from disassembly""" - if not disassembly: - return [] - return [instr["instruction"].split()[0] for instr in disassembly] - -def get_opcode_ngrams(opcodes, n=2): - """Generate n-grams from opcode sequence""" - if len(opcodes) < n: - return [] - return [tuple(opcodes[i:i+n]) for i in range(len(opcodes)-n+1)] - -def jaccard_similarity(set1, set2): - """Calculate Jaccard similarity between two sets""" - if not set1 and not set2: - return 1.0 - if not set1 or not set2: - return 0.0 - intersection = len(set1 & set2) - union = len(set1 | set2) - return intersection / union - -def calculate_opcode_similarity(func1, func2): - """Calculate similarity based on instruction opcode patterns using precomputed n-grams""" - # Use precomputed n-grams if available, otherwise compute on the fly - bigrams1 = func1.get('_bigrams') - bigrams2 = func2.get('_bigrams') - trigrams1 = func1.get('_trigrams') - trigrams2 = func2.get('_trigrams') - - if bigrams1 is None or bigrams2 is None or trigrams1 is None or trigrams2 is None: - # Fallback to computing on the fly (for backward compatibility) - opcodes1 = extract_opcodes(func1.get("disassembly", [])) - opcodes2 = extract_opcodes(func2.get("disassembly", [])) - - if not opcodes1 and not opcodes2: - return 1.0 - if not opcodes1 or not opcodes2: - return 0.0 - - bigrams1 = set(get_opcode_ngrams(opcodes1, 2)) - bigrams2 = set(get_opcode_ngrams(opcodes2, 2)) - trigrams1 = set(get_opcode_ngrams(opcodes1, 3)) - trigrams2 = set(get_opcode_ngrams(opcodes2, 3)) - - # Calculate similarities using precomputed or computed n-grams - bigram_sim = jaccard_similarity(bigrams1, bigrams2) - trigram_sim = jaccard_similarity(trigrams1, trigrams2) - - # Weight trigrams more heavily as they capture more specific patterns - return (bigram_sim * 0.4) + (trigram_sim * 0.6) - -def calculate_address_similarity(func1, func2, max_diff=86852): - """Calculate similarity based on address proximity""" - addr1 = int(func1["address"], 16) - addr2 = int(func2["address"], 16) - diff = abs(addr1 - addr2) - - # Convert to similarity score (1.0 is perfect match, 0.0 is max_diff or greater) - if diff >= max_diff: - return 0.0 - return 1.0 - (diff / max_diff) - -def calculate_combined_similarity(func1, func2, size_weight=0.35, ref_weight=0.27, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852): - """Calculate weighted combination of size, reference, address, and opcode similarity""" - size_sim = calculate_size_similarity(func1, func2) - ref_sim = calculate_reference_similarity(func1, func2) - addr_sim = calculate_address_similarity(func1, func2, max_addr_diff) - opcode_sim = calculate_opcode_similarity(func1, func2) - - # Apply weights - return (size_sim * size_weight) + (ref_sim * ref_weight) + (addr_sim * addr_weight) + (opcode_sim * opcode_weight) - -def find_most_similar_function(target_function, candidate_functions, size_weight=0.35, ref_weight=0.27, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852): - """Find the most similar function based on weighted combination of size, reference count, address, and opcodes""" - best_matches = [] - best_score = -1 - - # Calculate similarity threshold to consider a match almost identical - SIMILARITY_THRESHOLD = 0.999 - - for candidate in candidate_functions: - score = calculate_combined_similarity(target_function, candidate, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff) - - # Round to 4 decimal places to avoid floating point comparison issues - score = round(score, 4) - - if score > best_score: - # New best score, clear previous matches - best_score = score - best_matches = [candidate] - elif score == best_score: - # Same score, add to list of matches - best_matches.append(candidate) - - return best_matches, best_score - -def is_real_name(name): - """Check if a function has a real name or is an auto-generated name""" - return name and not any([name.startswith(x) for x in ["FUN_", "thunk_", "Unwind@", "__", "FID_conflict:"]]) - -def find_named_functions(functions): - """Return list of functions with real names (not auto-generated)""" - return [f for f in functions if is_real_name(f["name"])] - -def group_by_name(functions): - """Group functions by name, filtering out duplicates""" - name_groups = {} - for func in functions: - name = func["name"] - if name not in name_groups: - name_groups[name] = [] - name_groups[name].append(func) - - # Only keep names that have a single function - return {name: funcs[0] for name, funcs in name_groups.items() if len(funcs) == 1} - -# Global arrays to store match examples for inspection -correct_matches = [] -incorrect_matches = [] -ambiguous_matches = [] - -def test_name_matching(steam_functions, gog_functions, size_weight, ref_weight, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852, comparison_label="Steam"): - """Test how well our similarity metric matches already-named functions""" - global correct_matches, incorrect_matches, ambiguous_matches - - # Clear previous examples - correct_matches.clear() - incorrect_matches.clear() - ambiguous_matches.clear() - - print(f"Testing name matching between GOG and {comparison_label} with weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") - - # Get named functions from comparison file - named_steam_funcs = find_named_functions(steam_functions) - print(f"Found {len(named_steam_funcs)} named functions in comparison file ({comparison_label})") - - # Group by name, excluding duplicates - steam_name_map = group_by_name(named_steam_funcs) - print(f"After removing duplicates: {len(steam_name_map)} unique named functions") - - # Keep track of total for progress - total = 0 - - # Progress tracking - progress_step = max(1, len(steam_name_map) // 20) # Show progress in ~5% increments - - print(f"\nTesting matches for {len(steam_name_map)} functions...") - - for idx, (name, steam_func) in enumerate(steam_name_map.items()): - # Show progress - if idx % progress_step == 0: - print(f"Progress: {idx}/{len(steam_name_map)} ({idx/len(steam_name_map)*100:.1f}%)") - - # Find most similar functions in GOG - best_matches, similarity_score = find_most_similar_function( - steam_func, - gog_functions, - size_weight=size_weight, - ref_weight=ref_weight, - addr_weight=addr_weight, - opcode_weight=opcode_weight, - max_addr_diff=max_addr_diff - ) - - total += 1 - - # Check if best match has the same name - if len(best_matches) > 1: - # Ambiguous match (multiple with same score) - ambiguous_matches.append({ - 'steam_func': steam_func, - 'gog_matches': best_matches, - 'similarity_score': similarity_score - }) - else: - best_match = best_matches[0] - if best_match["name"] == name: - correct_matches.append({ - 'steam_func': steam_func, - 'gog_match': best_match, - 'similarity_score': similarity_score - }) - else: - incorrect_matches.append({ - 'steam_func': steam_func, - 'gog_match': best_match, - 'similarity_score': similarity_score - }) - - # Print final statistics - print("\nMatching Results:") - print(f"Total functions tested: {total}") - print(f"Correct matches: {len(correct_matches)} ({len(correct_matches)/total*100:.2f}%)") - print(f"Incorrect matches: {len(incorrect_matches)} ({len(incorrect_matches)/total*100:.2f}%)") - print(f"Ambiguous matches: {len(ambiguous_matches)} ({len(ambiguous_matches)/total*100:.2f}%)") - - return len(correct_matches) / total # Return success rate - -def analyze_address_differences(): - """Analyze address differences between functions with identical real names""" - global gog_functions, steam_functions - - if not gog_functions or not steam_functions: - print("Function data not loaded. Run main() first.") - return - - print("Finding functions with identical real names in both executables...") - - # Get functions with real names from both executables - steam_named = {f['name']: f for f in steam_functions if is_real_name(f['name'])} - gog_named = {f['name']: f for f in gog_functions if is_real_name(f['name'])} - - # Find functions that exist in both with identical names - common_names = set(steam_named.keys()) & set(gog_named.keys()) - print(f"Found {len(common_names)} functions with identical real names in both executables") - - if not common_names: - print("No matching named functions found.") - return - - address_diffs = [] - for name in common_names: - steam_func = steam_named[name] - gog_func = gog_named[name] - - steam_addr = int(steam_func['address'], 16) - gog_addr = int(gog_func['address'], 16) - diff = gog_addr - steam_addr - - address_diffs.append({ - 'function_name': name, - 'steam_addr': steam_addr, - 'gog_addr': gog_addr, - 'difference': diff, - 'abs_difference': abs(diff) - }) - - # Sort by absolute difference to see patterns - address_diffs.sort(key=lambda x: x['abs_difference']) - - # Calculate statistics - diffs = [item['abs_difference'] for item in address_diffs] - min_diff = min(diffs) - max_diff = max(diffs) - avg_diff = sum(diffs) / len(diffs) - - # Find most common difference - from collections import Counter - diff_counts = Counter(diffs) - most_common_diff = diff_counts.most_common(1)[0] - - print(f"\nAddress difference statistics:") - print(f" Min difference: 0x{min_diff:08x} ({min_diff})") - print(f" Max difference: 0x{max_diff:08x} ({max_diff})") - print(f" Average difference: 0x{int(avg_diff):08x} ({int(avg_diff)})") - print(f" Most common difference: 0x{most_common_diff[0]:08x} ({most_common_diff[0]}) - appears {most_common_diff[1]} times") - - # Show distribution of differences - print(f"\nTop 10 most common differences:") - for diff, count in diff_counts.most_common(10): - print(f" 0x{diff:08x} ({diff:8d}): {count:3d} functions") - - # Show some examples - print(f"\nFirst 10 examples (sorted by absolute difference):") - for i, item in enumerate(address_diffs[:10]): - print(f" {item['function_name']:30s} Steam: 0x{item['steam_addr']:08x} GOG: 0x{item['gog_addr']:08x} Diff: 0x{item['difference']:08x} (abs: 0x{item['abs_difference']:08x})") - - return address_diffs - -def generate_training_data(): - """Generate training data from functions with known matches and mismatches""" - global gog_functions, steam_functions - - if not gog_functions or not steam_functions: - print("Function data not loaded. Run main() first.") - return [], [] - - print("Generating training data for logistic regression...") - - # Get functions with real names from both executables - steam_named = {f['name']: f for f in steam_functions if is_real_name(f['name'])} - gog_named = {f['name']: f for f in gog_functions if is_real_name(f['name'])} - - # Find functions that exist in both with identical names (positive examples) - common_names = set(steam_named.keys()) & set(gog_named.keys()) - print(f"Found {len(common_names)} positive examples (identical names)") - - features = [] - labels = [] - - # Positive examples: functions with identical names - for name in common_names: - steam_func = steam_named[name] - gog_func = gog_named[name] - - # Calculate all similarity features - size_sim = calculate_size_similarity(steam_func, gog_func) - ref_sim = calculate_reference_similarity(steam_func, gog_func) - addr_sim = calculate_address_similarity(steam_func, gog_func) - opcode_sim = calculate_opcode_similarity(steam_func, gog_func) - - features.append([size_sim, ref_sim, addr_sim, opcode_sim]) - labels.append(1) # Correct match - - # Negative examples: generate mismatches - # For each positive example, find some functions that are NOT matches - print("Generating negative examples...") - import random - random.seed(42) # For reproducibility - - negative_count = 0 - target_negatives = len(common_names) * 2 # 2:1 ratio of negatives to positives - - steam_funcs_list = list(steam_named.values()) - gog_funcs_list = list(gog_named.values()) - - for _ in range(target_negatives): - if negative_count >= target_negatives: - break - - # Pick random functions that don't have the same name - steam_func = random.choice(steam_funcs_list) - gog_func = random.choice(gog_funcs_list) - - # Skip if they actually match - if steam_func['name'] == gog_func['name']: - continue - - # Calculate similarity features - size_sim = calculate_size_similarity(steam_func, gog_func) - ref_sim = calculate_reference_similarity(steam_func, gog_func) - addr_sim = calculate_address_similarity(steam_func, gog_func) - opcode_sim = calculate_opcode_similarity(steam_func, gog_func) - - features.append([size_sim, ref_sim, addr_sim, opcode_sim]) - labels.append(0) # Incorrect match - negative_count += 1 - - print(f"Generated {len([l for l in labels if l == 1])} positive and {len([l for l in labels if l == 0])} negative examples") - return features, labels - -def train_logistic_regression(): - """Train logistic regression model to learn optimal feature weights""" - try: - from sklearn.linear_model import LogisticRegression - from sklearn.model_selection import cross_val_score - from sklearn.preprocessing import StandardScaler - import numpy as np - except ImportError: - print("Error: scikit-learn not available. Install with: pip install scikit-learn") - return None - - # Generate training data - features, labels = generate_training_data() - if not features: - print("No training data generated") - return None - - features = np.array(features) - labels = np.array(labels) - - print(f"Training on {len(features)} examples...") - - # Standardize features (important for logistic regression) - scaler = StandardScaler() - features_scaled = scaler.fit_transform(features) - - # Train logistic regression with L2 regularization - model = LogisticRegression(random_state=42, max_iter=1000) - model.fit(features_scaled, labels) - - # Evaluate with cross-validation - cv_scores = cross_val_score(model, features_scaled, labels, cv=5) - print(f"Cross-validation accuracy: {cv_scores.mean():.3f} (+/- {cv_scores.std() * 2:.3f})") - - # Get feature importance (coefficients) - coefficients = model.coef_[0] - feature_names = ['Size', 'References', 'Address', 'Opcode'] - - print("\nLearned feature coefficients:") - for name, coef in zip(feature_names, coefficients): - print(f" {name}: {coef:.4f}") - - # Convert to normalized weights (positive, sum to 1) - # Take absolute values and normalize - abs_coefficients = np.abs(coefficients) - normalized_weights = abs_coefficients / np.sum(abs_coefficients) - - print("\nNormalized weights for correlator:") - for name, weight in zip(feature_names, normalized_weights): - print(f" {name}: {weight:.3f}") - - print(f"\nSuggested command line:") - print(f"python correlator.py --test {normalized_weights[0]:.3f} {normalized_weights[1]:.3f} {normalized_weights[2]:.3f} {normalized_weights[3]:.3f}") - - return { - 'model': model, - 'scaler': scaler, - 'weights': normalized_weights, - 'coefficients': coefficients, - 'cv_accuracy': cv_scores.mean() - } - -def process_multiple_addresses(addresses, gog_functions, steam_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label="Steam"): - """Process multiple addresses and find matches for each""" - results = [] - - print(f"Processing {len(addresses)} addresses with default weights...") - print(f"Using weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") - print("=" * 80) - - for i, address in enumerate(addresses): - print(f"\n[{i+1}/{len(addresses)}] Processing address: {address}") - print("-" * 40) - - # Find the target function in gog.json - target_function = find_function_by_address(gog_functions, address) - if not target_function: - print(f"No function found at address {address} in gog.json") - results.append({ - 'address': address, - 'found': False, - 'error': f"No function found at address {address}" - }) - continue - - target_size = len(target_function["raw_bytes"]) - print(f"Found target function: {target_function['name']} at {target_function['address']}") - print(f"Function size: {target_size} bytes, References: {target_function['reference_count']}") - - # Find the most similar function in comparison file - best_matches, similarity_score = find_most_similar_function( - target_function, - steam_functions, - size_weight=size_weight, - ref_weight=ref_weight, - addr_weight=addr_weight, - opcode_weight=opcode_weight, - max_addr_diff=max_addr_diff - ) - - print(f"Combined similarity score: {similarity_score:.4f}") - - # Store results - match_data = [] - for match in best_matches: - match_size = len(match['raw_bytes']) - size_sim = calculate_size_similarity(target_function, match) - ref_sim = calculate_reference_similarity(target_function, match) - addr_sim = calculate_address_similarity(target_function, match, max_addr_diff) - opcode_sim = calculate_opcode_similarity(target_function, match) - - match_info = { - 'name': match['name'], - 'address': match['address'], - 'size': match_size, - 'references': match['reference_count'], - 'size_similarity': size_sim, - 'ref_similarity': ref_sim, - 'addr_similarity': addr_sim, - 'opcode_similarity': opcode_sim - } - match_data.append(match_info) - - print(f"Best match in {comparison_label}: {match['name']} at {match['address']}") - print(f" Size: {match_size} bytes (similarity: {size_sim:.4f})") - print(f" References: {match['reference_count']} (similarity: {ref_sim:.4f})") - print(f" Address similarity: {addr_sim:.4f}") - print(f" Opcode similarity: {opcode_sim:.4f}") - - if len(best_matches) > 1: - print(f"WARNING: Found {len(best_matches)} functions with the same similarity score!") - - results.append({ - 'address': address, - 'found': True, - 'target_function': { - 'name': target_function['name'], - 'address': target_function['address'], - 'size': target_size, - 'references': target_function['reference_count'] - }, - 'matches': match_data, - 'similarity_score': similarity_score, - 'match_count': len(best_matches) - }) - - return results - -def main(): - global gog_functions, steam_functions - - # Check for --pcg flag first (before loading files) - use_pcg = "--pcg" in sys.argv - if use_pcg: - # Remove --pcg from argv so it doesn't interfere with other parsing - sys.argv = [arg for arg in sys.argv if arg != "--pcg"] - - # Set default weights - size_weight = 0.35 - ref_weight = 0.27 - addr_weight = 0.03 - opcode_weight = 0.35 - max_addr_diff = 86852 # Average from analysis - - # Load functions from both files - comparison_file = "pcg.json" if use_pcg else "steam.json" - comparison_label = "PCGames.de" if use_pcg else "Steam" - - gog_functions = load_ghidra_export("gog.json") - steam_functions = load_ghidra_export(comparison_file) - - if not gog_functions or not steam_functions: - print("Error loading function data. Exiting.") - sys.exit(1) - - # Check for analysis mode - if len(sys.argv) >= 2 and sys.argv[1] == "--analyze": - analyze_address_differences() - return - - # Check for ML training mode - if len(sys.argv) >= 2 and sys.argv[1] == "--train": - train_logistic_regression() - return - - # Check for list mode - if len(sys.argv) >= 2 and sys.argv[1] == "--list": - if len(sys.argv) < 3: - print("Error: --list requires at least one address") - sys.exit(1) - addresses = sys.argv[2:] - - results = process_multiple_addresses(addresses, gog_functions, steam_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label) - - # Print summary - print("\n" + "=" * 80) - print("SUMMARY") - print("=" * 80) - - found_count = sum(1 for r in results if r['found']) - print(f"Total addresses processed: {len(results)}") - print(f"Functions found: {found_count}") - print(f"Functions not found: {len(results) - found_count}") - - if found_count > 0: - avg_score = sum(r['similarity_score'] for r in results if r['found']) / found_count - print(f"Average similarity score: {avg_score:.4f}") - - ambiguous_count = sum(1 for r in results if r['found'] and r['match_count'] > 1) - if ambiguous_count > 0: - print(f"Ambiguous matches (multiple with same score): {ambiguous_count}") - - return - - # Check for test mode - if len(sys.argv) >= 2 and sys.argv[1] == "--test": - # If weights are provided, use them - if len(sys.argv) >= 4: - try: - size_weight = float(sys.argv[2]) - ref_weight = float(sys.argv[3]) - if len(sys.argv) >= 5: - addr_weight = float(sys.argv[4]) - if len(sys.argv) >= 6: - opcode_weight = float(sys.argv[5]) - # Normalize weights if they don't sum to 1 - total = size_weight + ref_weight + addr_weight + opcode_weight - if total != 1.0: - size_weight /= total - ref_weight /= total - addr_weight /= total - opcode_weight /= total - except ValueError: - print("Error: Weights must be numeric values") - sys.exit(1) - - # Run test mode - test_name_matching(steam_functions, gog_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label) - return - - # Normal mode - lookup a specific function - if len(sys.argv) < 2: - print("Usage:") - print(" python correlator.py [size_weight] [ref_weight] [addr_weight] [opcode_weight] [--pcg]") - print(" python correlator.py --list ... [--pcg]") - print(" python correlator.py --test [size_weight] [ref_weight] [addr_weight] [opcode_weight] [--pcg]") - print(" python correlator.py --analyze [--pcg]") - print(" python correlator.py --train [--pcg]") - print("\nOptions:") - print(" --pcg Use pcg.json (PCGames.de version) instead of steam.json for comparison") - print("\nExamples:") - print(" python correlator.py 00401000") - print(" python correlator.py 00401000 --pcg") - print(" python correlator.py 00401000 0.4 0.3 0.1 0.2") - print(" python correlator.py --list 00401000 00402000 00403000") - print(" python correlator.py --list 00401000 00402000 --pcg") - print(" python correlator.py --test") - print(" python correlator.py --test --pcg") - print(" python correlator.py --test 0.4 0.3 0.1 0.2 --pcg") - print(" python correlator.py --train # Learn optimal weights with ML") - return - - target_address = sys.argv[1] - - # Allow overriding weights through command line - if len(sys.argv) >= 4: - try: - size_weight = float(sys.argv[2]) - ref_weight = float(sys.argv[3]) - if len(sys.argv) >= 5: - addr_weight = float(sys.argv[4]) - if len(sys.argv) >= 6: - opcode_weight = float(sys.argv[5]) - # Normalize weights if they don't sum to 1 - total = size_weight + ref_weight + addr_weight + opcode_weight - if total != 1.0: - size_weight /= total - ref_weight /= total - addr_weight /= total - opcode_weight /= total - except ValueError: - print("Error: Weights must be numeric values") - sys.exit(1) - - # Find the target function in gog.json - target_function = find_function_by_address(gog_functions, target_address) - if not target_function: - print(f"No function found at address {target_address} in gog.json") - sys.exit(1) - - target_size = len(target_function["raw_bytes"]) - print(f"Found target function: {target_function['name']} at {target_function['address']}") - print(f"Function size: {target_size} bytes") - print(f"References: {target_function['reference_count']}") - print(f"Using weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") - - # Find the most similar function in comparison file - best_matches, similarity_score = find_most_similar_function( - target_function, - steam_functions, - size_weight=size_weight, - ref_weight=ref_weight, - addr_weight=addr_weight, - opcode_weight=opcode_weight, - max_addr_diff=max_addr_diff - ) - - print(f"\nBest matches in {comparison_label}:") - print(f"Combined similarity score: {similarity_score:.4f}") - - if len(best_matches) > 1: - print(f"\nWARNING: Found {len(best_matches)} functions with the same similarity score!") - - for i, match in enumerate(best_matches): - match_size = len(match['raw_bytes']) - size_sim = calculate_size_similarity(target_function, match) - ref_sim = calculate_reference_similarity(target_function, match) - addr_sim = calculate_address_similarity(target_function, match, max_addr_diff) - opcode_sim = calculate_opcode_similarity(target_function, match) - - print(f"\nMatch {i+1}:") - print(f"Function: {match['name']} at {match['address']}") - print(f"Size: {match_size} bytes (similarity: {size_sim:.4f})") - print(f"References: {match['reference_count']} (similarity: {ref_sim:.4f})") - print(f"Address similarity: {addr_sim:.4f}") - print(f"Opcode similarity: {opcode_sim:.4f}") - - # Show size difference as percentage - size_diff_pct = abs(target_size - match_size) / target_size * 100 - print(f"Size difference: {abs(target_size - match_size)} bytes ({size_diff_pct:.1f}%)") - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 + +import json +import sys +import os +from typing import List, Dict, Any + +def precompute_function_features(functions): + """Precompute expensive features for all functions""" + print(f"Precomputing opcode features for {len(functions)} functions...") + for i, func in enumerate(functions): + if i % 1000 == 0 and i > 0: + print(f" Processed {i}/{len(functions)} functions...") + + opcodes = extract_opcodes(func.get("disassembly", [])) + func['_bigrams'] = set(get_opcode_ngrams(opcodes, 2)) + func['_trigrams'] = set(get_opcode_ngrams(opcodes, 3)) + print(f" Completed preprocessing {len(functions)} functions") + +def load_ghidra_export(filepath: str) -> List[Dict[str, Any]]: + """ + Load function data exported from Ghidra by ExportProgForPython.py + + The expected JSON format is: + [ + { + "name": "function_name", # String: Name of the function + "address": "00100400", # String: Address of function entry point + "raw_bytes": [72, 131, 236, ...], # List[int]: Raw bytes of the function + "disassembly": [ # List[Dict]: Disassembled instructions + { + "address": "00100400", # String: Instruction address + "instruction": "SUB RSP, 0x20" # String: Disassembled instruction + }, + ... + ], + "reference_count": 5 # Int: Number of references to this function + }, + ... + ] + + Args: + filepath: Path to the exported JSON file + + Returns: + List of function data dictionaries + """ + try: + with open(filepath, 'r') as f: + data = json.load(f) + + print(f"Successfully loaded {len(data)} functions from {filepath}") + + # Precompute opcode features + precompute_function_features(data) + + return data + except json.JSONDecodeError: + print(f"Error: {filepath} contains invalid JSON") + return [] + except FileNotFoundError: + print(f"Error: File {filepath} not found") + return [] + +def find_function_by_address(functions, address): + """Find a function by its address, ignoring leading zeros and '0x' prefix""" + # Normalize the input address: remove '0x' prefix and convert to integer + if address.lower().startswith("0x"): + address = address[2:] + # Convert to integer to ignore leading zeros + normalized_address = int(address, 16) + + for function in functions: + func_addr = function["address"] + if func_addr.lower().startswith("0x"): + func_addr = func_addr[2:] + # Convert to integer to ignore leading zeros + func_addr_int = int(func_addr, 16) + + if func_addr_int == normalized_address: + return function + return None + +def calculate_size_similarity(func1, func2): + """Calculate similarity based on function size (number of bytes)""" + size1 = len(func1["raw_bytes"]) + size2 = len(func2["raw_bytes"]) + + # Calculate similarity score (1.0 is perfect match) + if size1 == 0 or size2 == 0: + return 0.0 + + # Use the ratio of the smaller to the larger size + return min(size1, size2) / max(size1, size2) + +def calculate_reference_similarity(func1, func2): + """Calculate similarity based on reference count""" + ref1 = func1["reference_count"] + ref2 = func2["reference_count"] + + # Calculate similarity score (1.0 is perfect match) + if ref1 == 0 and ref2 == 0: + return 1.0 # Both have 0 references, perfect match + elif ref1 == 0 or ref2 == 0: + return 0.0 # One has references, the other doesn't + + # Use the ratio of the smaller to the larger reference count + return min(ref1, ref2) / max(ref1, ref2) + +def extract_opcodes(disassembly): + """Extract just the instruction mnemonics from disassembly""" + if not disassembly: + return [] + return [instr["instruction"].split()[0] for instr in disassembly] + +def get_opcode_ngrams(opcodes, n=2): + """Generate n-grams from opcode sequence""" + if len(opcodes) < n: + return [] + return [tuple(opcodes[i:i+n]) for i in range(len(opcodes)-n+1)] + +def jaccard_similarity(set1, set2): + """Calculate Jaccard similarity between two sets""" + if not set1 and not set2: + return 1.0 + if not set1 or not set2: + return 0.0 + intersection = len(set1 & set2) + union = len(set1 | set2) + return intersection / union + +def calculate_opcode_similarity(func1, func2): + """Calculate similarity based on instruction opcode patterns using precomputed n-grams""" + # Use precomputed n-grams if available, otherwise compute on the fly + bigrams1 = func1.get('_bigrams') + bigrams2 = func2.get('_bigrams') + trigrams1 = func1.get('_trigrams') + trigrams2 = func2.get('_trigrams') + + if bigrams1 is None or bigrams2 is None or trigrams1 is None or trigrams2 is None: + # Fallback to computing on the fly (for backward compatibility) + opcodes1 = extract_opcodes(func1.get("disassembly", [])) + opcodes2 = extract_opcodes(func2.get("disassembly", [])) + + if not opcodes1 and not opcodes2: + return 1.0 + if not opcodes1 or not opcodes2: + return 0.0 + + bigrams1 = set(get_opcode_ngrams(opcodes1, 2)) + bigrams2 = set(get_opcode_ngrams(opcodes2, 2)) + trigrams1 = set(get_opcode_ngrams(opcodes1, 3)) + trigrams2 = set(get_opcode_ngrams(opcodes2, 3)) + + # Calculate similarities using precomputed or computed n-grams + bigram_sim = jaccard_similarity(bigrams1, bigrams2) + trigram_sim = jaccard_similarity(trigrams1, trigrams2) + + # Weight trigrams more heavily as they capture more specific patterns + return (bigram_sim * 0.4) + (trigram_sim * 0.6) + +def calculate_address_similarity(func1, func2, max_diff=86852): + """Calculate similarity based on address proximity""" + addr1 = int(func1["address"], 16) + addr2 = int(func2["address"], 16) + diff = abs(addr1 - addr2) + + # Convert to similarity score (1.0 is perfect match, 0.0 is max_diff or greater) + if diff >= max_diff: + return 0.0 + return 1.0 - (diff / max_diff) + +def calculate_combined_similarity(func1, func2, size_weight=0.35, ref_weight=0.27, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852): + """Calculate weighted combination of size, reference, address, and opcode similarity""" + size_sim = calculate_size_similarity(func1, func2) + ref_sim = calculate_reference_similarity(func1, func2) + addr_sim = calculate_address_similarity(func1, func2, max_addr_diff) + opcode_sim = calculate_opcode_similarity(func1, func2) + + # Apply weights + return (size_sim * size_weight) + (ref_sim * ref_weight) + (addr_sim * addr_weight) + (opcode_sim * opcode_weight) + +def find_most_similar_function(target_function, candidate_functions, size_weight=0.35, ref_weight=0.27, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852): + """Find the most similar function based on weighted combination of size, reference count, address, and opcodes""" + best_matches = [] + best_score = -1 + + # Calculate similarity threshold to consider a match almost identical + SIMILARITY_THRESHOLD = 0.999 + + for candidate in candidate_functions: + score = calculate_combined_similarity(target_function, candidate, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff) + + # Round to 4 decimal places to avoid floating point comparison issues + score = round(score, 4) + + if score > best_score: + # New best score, clear previous matches + best_score = score + best_matches = [candidate] + elif score == best_score: + # Same score, add to list of matches + best_matches.append(candidate) + + return best_matches, best_score + +def is_real_name(name): + """Check if a function has a real name or is an auto-generated name""" + return name and not any([name.startswith(x) for x in ["FUN_", "thunk_", "Unwind@", "__", "FID_conflict:"]]) + +def find_named_functions(functions): + """Return list of functions with real names (not auto-generated)""" + return [f for f in functions if is_real_name(f["name"])] + +def group_by_name(functions): + """Group functions by name, filtering out duplicates""" + name_groups = {} + for func in functions: + name = func["name"] + if name not in name_groups: + name_groups[name] = [] + name_groups[name].append(func) + + # Only keep names that have a single function + return {name: funcs[0] for name, funcs in name_groups.items() if len(funcs) == 1} + +# Global arrays to store match examples for inspection +correct_matches = [] +incorrect_matches = [] +ambiguous_matches = [] + +def test_name_matching(steam_functions, gog_functions, size_weight, ref_weight, addr_weight=0.03, opcode_weight=0.35, max_addr_diff=86852, comparison_label="Steam"): + """Test how well our similarity metric matches already-named functions""" + global correct_matches, incorrect_matches, ambiguous_matches + + # Clear previous examples + correct_matches.clear() + incorrect_matches.clear() + ambiguous_matches.clear() + + print(f"Testing name matching between GOG and {comparison_label} with weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") + + # Get named functions from comparison file + named_steam_funcs = find_named_functions(steam_functions) + print(f"Found {len(named_steam_funcs)} named functions in comparison file ({comparison_label})") + + # Group by name, excluding duplicates + steam_name_map = group_by_name(named_steam_funcs) + print(f"After removing duplicates: {len(steam_name_map)} unique named functions") + + # Keep track of total for progress + total = 0 + + # Progress tracking + progress_step = max(1, len(steam_name_map) // 20) # Show progress in ~5% increments + + print(f"\nTesting matches for {len(steam_name_map)} functions...") + + for idx, (name, steam_func) in enumerate(steam_name_map.items()): + # Show progress + if idx % progress_step == 0: + print(f"Progress: {idx}/{len(steam_name_map)} ({idx/len(steam_name_map)*100:.1f}%)") + + # Find most similar functions in GOG + best_matches, similarity_score = find_most_similar_function( + steam_func, + gog_functions, + size_weight=size_weight, + ref_weight=ref_weight, + addr_weight=addr_weight, + opcode_weight=opcode_weight, + max_addr_diff=max_addr_diff + ) + + total += 1 + + # Check if best match has the same name + if len(best_matches) > 1: + # Ambiguous match (multiple with same score) + ambiguous_matches.append({ + 'steam_func': steam_func, + 'gog_matches': best_matches, + 'similarity_score': similarity_score + }) + else: + best_match = best_matches[0] + if best_match["name"] == name: + correct_matches.append({ + 'steam_func': steam_func, + 'gog_match': best_match, + 'similarity_score': similarity_score + }) + else: + incorrect_matches.append({ + 'steam_func': steam_func, + 'gog_match': best_match, + 'similarity_score': similarity_score + }) + + # Print final statistics + print("\nMatching Results:") + print(f"Total functions tested: {total}") + print(f"Correct matches: {len(correct_matches)} ({len(correct_matches)/total*100:.2f}%)") + print(f"Incorrect matches: {len(incorrect_matches)} ({len(incorrect_matches)/total*100:.2f}%)") + print(f"Ambiguous matches: {len(ambiguous_matches)} ({len(ambiguous_matches)/total*100:.2f}%)") + + return len(correct_matches) / total # Return success rate + +def analyze_address_differences(): + """Analyze address differences between functions with identical real names""" + global gog_functions, steam_functions + + if not gog_functions or not steam_functions: + print("Function data not loaded. Run main() first.") + return + + print("Finding functions with identical real names in both executables...") + + # Get functions with real names from both executables + steam_named = {f['name']: f for f in steam_functions if is_real_name(f['name'])} + gog_named = {f['name']: f for f in gog_functions if is_real_name(f['name'])} + + # Find functions that exist in both with identical names + common_names = set(steam_named.keys()) & set(gog_named.keys()) + print(f"Found {len(common_names)} functions with identical real names in both executables") + + if not common_names: + print("No matching named functions found.") + return + + address_diffs = [] + for name in common_names: + steam_func = steam_named[name] + gog_func = gog_named[name] + + steam_addr = int(steam_func['address'], 16) + gog_addr = int(gog_func['address'], 16) + diff = gog_addr - steam_addr + + address_diffs.append({ + 'function_name': name, + 'steam_addr': steam_addr, + 'gog_addr': gog_addr, + 'difference': diff, + 'abs_difference': abs(diff) + }) + + # Sort by absolute difference to see patterns + address_diffs.sort(key=lambda x: x['abs_difference']) + + # Calculate statistics + diffs = [item['abs_difference'] for item in address_diffs] + min_diff = min(diffs) + max_diff = max(diffs) + avg_diff = sum(diffs) / len(diffs) + + # Find most common difference + from collections import Counter + diff_counts = Counter(diffs) + most_common_diff = diff_counts.most_common(1)[0] + + print(f"\nAddress difference statistics:") + print(f" Min difference: 0x{min_diff:08x} ({min_diff})") + print(f" Max difference: 0x{max_diff:08x} ({max_diff})") + print(f" Average difference: 0x{int(avg_diff):08x} ({int(avg_diff)})") + print(f" Most common difference: 0x{most_common_diff[0]:08x} ({most_common_diff[0]}) - appears {most_common_diff[1]} times") + + # Show distribution of differences + print(f"\nTop 10 most common differences:") + for diff, count in diff_counts.most_common(10): + print(f" 0x{diff:08x} ({diff:8d}): {count:3d} functions") + + # Show some examples + print(f"\nFirst 10 examples (sorted by absolute difference):") + for i, item in enumerate(address_diffs[:10]): + print(f" {item['function_name']:30s} Steam: 0x{item['steam_addr']:08x} GOG: 0x{item['gog_addr']:08x} Diff: 0x{item['difference']:08x} (abs: 0x{item['abs_difference']:08x})") + + return address_diffs + +def generate_training_data(): + """Generate training data from functions with known matches and mismatches""" + global gog_functions, steam_functions + + if not gog_functions or not steam_functions: + print("Function data not loaded. Run main() first.") + return [], [] + + print("Generating training data for logistic regression...") + + # Get functions with real names from both executables + steam_named = {f['name']: f for f in steam_functions if is_real_name(f['name'])} + gog_named = {f['name']: f for f in gog_functions if is_real_name(f['name'])} + + # Find functions that exist in both with identical names (positive examples) + common_names = set(steam_named.keys()) & set(gog_named.keys()) + print(f"Found {len(common_names)} positive examples (identical names)") + + features = [] + labels = [] + + # Positive examples: functions with identical names + for name in common_names: + steam_func = steam_named[name] + gog_func = gog_named[name] + + # Calculate all similarity features + size_sim = calculate_size_similarity(steam_func, gog_func) + ref_sim = calculate_reference_similarity(steam_func, gog_func) + addr_sim = calculate_address_similarity(steam_func, gog_func) + opcode_sim = calculate_opcode_similarity(steam_func, gog_func) + + features.append([size_sim, ref_sim, addr_sim, opcode_sim]) + labels.append(1) # Correct match + + # Negative examples: generate mismatches + # For each positive example, find some functions that are NOT matches + print("Generating negative examples...") + import random + random.seed(42) # For reproducibility + + negative_count = 0 + target_negatives = len(common_names) * 2 # 2:1 ratio of negatives to positives + + steam_funcs_list = list(steam_named.values()) + gog_funcs_list = list(gog_named.values()) + + for _ in range(target_negatives): + if negative_count >= target_negatives: + break + + # Pick random functions that don't have the same name + steam_func = random.choice(steam_funcs_list) + gog_func = random.choice(gog_funcs_list) + + # Skip if they actually match + if steam_func['name'] == gog_func['name']: + continue + + # Calculate similarity features + size_sim = calculate_size_similarity(steam_func, gog_func) + ref_sim = calculate_reference_similarity(steam_func, gog_func) + addr_sim = calculate_address_similarity(steam_func, gog_func) + opcode_sim = calculate_opcode_similarity(steam_func, gog_func) + + features.append([size_sim, ref_sim, addr_sim, opcode_sim]) + labels.append(0) # Incorrect match + negative_count += 1 + + print(f"Generated {len([l for l in labels if l == 1])} positive and {len([l for l in labels if l == 0])} negative examples") + return features, labels + +def train_logistic_regression(): + """Train logistic regression model to learn optimal feature weights""" + try: + from sklearn.linear_model import LogisticRegression + from sklearn.model_selection import cross_val_score + from sklearn.preprocessing import StandardScaler + import numpy as np + except ImportError: + print("Error: scikit-learn not available. Install with: pip install scikit-learn") + return None + + # Generate training data + features, labels = generate_training_data() + if not features: + print("No training data generated") + return None + + features = np.array(features) + labels = np.array(labels) + + print(f"Training on {len(features)} examples...") + + # Standardize features (important for logistic regression) + scaler = StandardScaler() + features_scaled = scaler.fit_transform(features) + + # Train logistic regression with L2 regularization + model = LogisticRegression(random_state=42, max_iter=1000) + model.fit(features_scaled, labels) + + # Evaluate with cross-validation + cv_scores = cross_val_score(model, features_scaled, labels, cv=5) + print(f"Cross-validation accuracy: {cv_scores.mean():.3f} (+/- {cv_scores.std() * 2:.3f})") + + # Get feature importance (coefficients) + coefficients = model.coef_[0] + feature_names = ['Size', 'References', 'Address', 'Opcode'] + + print("\nLearned feature coefficients:") + for name, coef in zip(feature_names, coefficients): + print(f" {name}: {coef:.4f}") + + # Convert to normalized weights (positive, sum to 1) + # Take absolute values and normalize + abs_coefficients = np.abs(coefficients) + normalized_weights = abs_coefficients / np.sum(abs_coefficients) + + print("\nNormalized weights for correlator:") + for name, weight in zip(feature_names, normalized_weights): + print(f" {name}: {weight:.3f}") + + print(f"\nSuggested command line:") + print(f"python correlator.py --test {normalized_weights[0]:.3f} {normalized_weights[1]:.3f} {normalized_weights[2]:.3f} {normalized_weights[3]:.3f}") + + return { + 'model': model, + 'scaler': scaler, + 'weights': normalized_weights, + 'coefficients': coefficients, + 'cv_accuracy': cv_scores.mean() + } + +def process_multiple_addresses(addresses, gog_functions, steam_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label="Steam"): + """Process multiple addresses and find matches for each""" + results = [] + + print(f"Processing {len(addresses)} addresses with default weights...") + print(f"Using weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") + print("=" * 80) + + for i, address in enumerate(addresses): + print(f"\n[{i+1}/{len(addresses)}] Processing address: {address}") + print("-" * 40) + + # Find the target function in gog.json + target_function = find_function_by_address(gog_functions, address) + if not target_function: + print(f"No function found at address {address} in gog.json") + results.append({ + 'address': address, + 'found': False, + 'error': f"No function found at address {address}" + }) + continue + + target_size = len(target_function["raw_bytes"]) + print(f"Found target function: {target_function['name']} at {target_function['address']}") + print(f"Function size: {target_size} bytes, References: {target_function['reference_count']}") + + # Find the most similar function in comparison file + best_matches, similarity_score = find_most_similar_function( + target_function, + steam_functions, + size_weight=size_weight, + ref_weight=ref_weight, + addr_weight=addr_weight, + opcode_weight=opcode_weight, + max_addr_diff=max_addr_diff + ) + + print(f"Combined similarity score: {similarity_score:.4f}") + + # Store results + match_data = [] + for match in best_matches: + match_size = len(match['raw_bytes']) + size_sim = calculate_size_similarity(target_function, match) + ref_sim = calculate_reference_similarity(target_function, match) + addr_sim = calculate_address_similarity(target_function, match, max_addr_diff) + opcode_sim = calculate_opcode_similarity(target_function, match) + + match_info = { + 'name': match['name'], + 'address': match['address'], + 'size': match_size, + 'references': match['reference_count'], + 'size_similarity': size_sim, + 'ref_similarity': ref_sim, + 'addr_similarity': addr_sim, + 'opcode_similarity': opcode_sim + } + match_data.append(match_info) + + print(f"Best match in {comparison_label}: {match['name']} at {match['address']}") + print(f" Size: {match_size} bytes (similarity: {size_sim:.4f})") + print(f" References: {match['reference_count']} (similarity: {ref_sim:.4f})") + print(f" Address similarity: {addr_sim:.4f}") + print(f" Opcode similarity: {opcode_sim:.4f}") + + if len(best_matches) > 1: + print(f"WARNING: Found {len(best_matches)} functions with the same similarity score!") + + results.append({ + 'address': address, + 'found': True, + 'target_function': { + 'name': target_function['name'], + 'address': target_function['address'], + 'size': target_size, + 'references': target_function['reference_count'] + }, + 'matches': match_data, + 'similarity_score': similarity_score, + 'match_count': len(best_matches) + }) + + return results + +def main(): + global gog_functions, steam_functions + + # Check for --pcg flag first (before loading files) + use_pcg = "--pcg" in sys.argv + if use_pcg: + # Remove --pcg from argv so it doesn't interfere with other parsing + sys.argv = [arg for arg in sys.argv if arg != "--pcg"] + + # Set default weights + size_weight = 0.35 + ref_weight = 0.27 + addr_weight = 0.03 + opcode_weight = 0.35 + max_addr_diff = 86852 # Average from analysis + + # Load functions from both files + comparison_file = "pcg.json" if use_pcg else "steam.json" + comparison_label = "PCGames.de" if use_pcg else "Steam" + + gog_functions = load_ghidra_export("gog.json") + steam_functions = load_ghidra_export(comparison_file) + + if not gog_functions or not steam_functions: + print("Error loading function data. Exiting.") + sys.exit(1) + + # Check for analysis mode + if len(sys.argv) >= 2 and sys.argv[1] == "--analyze": + analyze_address_differences() + return + + # Check for ML training mode + if len(sys.argv) >= 2 and sys.argv[1] == "--train": + train_logistic_regression() + return + + # Check for list mode + if len(sys.argv) >= 2 and sys.argv[1] == "--list": + if len(sys.argv) < 3: + print("Error: --list requires at least one address") + sys.exit(1) + addresses = sys.argv[2:] + + results = process_multiple_addresses(addresses, gog_functions, steam_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label) + + # Print summary + print("\n" + "=" * 80) + print("SUMMARY") + print("=" * 80) + + found_count = sum(1 for r in results if r['found']) + print(f"Total addresses processed: {len(results)}") + print(f"Functions found: {found_count}") + print(f"Functions not found: {len(results) - found_count}") + + if found_count > 0: + avg_score = sum(r['similarity_score'] for r in results if r['found']) / found_count + print(f"Average similarity score: {avg_score:.4f}") + + ambiguous_count = sum(1 for r in results if r['found'] and r['match_count'] > 1) + if ambiguous_count > 0: + print(f"Ambiguous matches (multiple with same score): {ambiguous_count}") + + return + + # Check for test mode + if len(sys.argv) >= 2 and sys.argv[1] == "--test": + # If weights are provided, use them + if len(sys.argv) >= 4: + try: + size_weight = float(sys.argv[2]) + ref_weight = float(sys.argv[3]) + if len(sys.argv) >= 5: + addr_weight = float(sys.argv[4]) + if len(sys.argv) >= 6: + opcode_weight = float(sys.argv[5]) + # Normalize weights if they don't sum to 1 + total = size_weight + ref_weight + addr_weight + opcode_weight + if total != 1.0: + size_weight /= total + ref_weight /= total + addr_weight /= total + opcode_weight /= total + except ValueError: + print("Error: Weights must be numeric values") + sys.exit(1) + + # Run test mode + test_name_matching(steam_functions, gog_functions, size_weight, ref_weight, addr_weight, opcode_weight, max_addr_diff, comparison_label) + return + + # Normal mode - lookup a specific function + if len(sys.argv) < 2: + print("Usage:") + print(" python correlator.py [size_weight] [ref_weight] [addr_weight] [opcode_weight] [--pcg]") + print(" python correlator.py --list ... [--pcg]") + print(" python correlator.py --test [size_weight] [ref_weight] [addr_weight] [opcode_weight] [--pcg]") + print(" python correlator.py --analyze [--pcg]") + print(" python correlator.py --train [--pcg]") + print("\nOptions:") + print(" --pcg Use pcg.json (PCGames.de version) instead of steam.json for comparison") + print("\nExamples:") + print(" python correlator.py 00401000") + print(" python correlator.py 00401000 --pcg") + print(" python correlator.py 00401000 0.4 0.3 0.1 0.2") + print(" python correlator.py --list 00401000 00402000 00403000") + print(" python correlator.py --list 00401000 00402000 --pcg") + print(" python correlator.py --test") + print(" python correlator.py --test --pcg") + print(" python correlator.py --test 0.4 0.3 0.1 0.2 --pcg") + print(" python correlator.py --train # Learn optimal weights with ML") + return + + target_address = sys.argv[1] + + # Allow overriding weights through command line + if len(sys.argv) >= 4: + try: + size_weight = float(sys.argv[2]) + ref_weight = float(sys.argv[3]) + if len(sys.argv) >= 5: + addr_weight = float(sys.argv[4]) + if len(sys.argv) >= 6: + opcode_weight = float(sys.argv[5]) + # Normalize weights if they don't sum to 1 + total = size_weight + ref_weight + addr_weight + opcode_weight + if total != 1.0: + size_weight /= total + ref_weight /= total + addr_weight /= total + opcode_weight /= total + except ValueError: + print("Error: Weights must be numeric values") + sys.exit(1) + + # Find the target function in gog.json + target_function = find_function_by_address(gog_functions, target_address) + if not target_function: + print(f"No function found at address {target_address} in gog.json") + sys.exit(1) + + target_size = len(target_function["raw_bytes"]) + print(f"Found target function: {target_function['name']} at {target_function['address']}") + print(f"Function size: {target_size} bytes") + print(f"References: {target_function['reference_count']}") + print(f"Using weights: Size={size_weight:.2f}, References={ref_weight:.2f}, Address={addr_weight:.2f}, Opcode={opcode_weight:.2f}") + + # Find the most similar function in comparison file + best_matches, similarity_score = find_most_similar_function( + target_function, + steam_functions, + size_weight=size_weight, + ref_weight=ref_weight, + addr_weight=addr_weight, + opcode_weight=opcode_weight, + max_addr_diff=max_addr_diff + ) + + print(f"\nBest matches in {comparison_label}:") + print(f"Combined similarity score: {similarity_score:.4f}") + + if len(best_matches) > 1: + print(f"\nWARNING: Found {len(best_matches)} functions with the same similarity score!") + + for i, match in enumerate(best_matches): + match_size = len(match['raw_bytes']) + size_sim = calculate_size_similarity(target_function, match) + ref_sim = calculate_reference_similarity(target_function, match) + addr_sim = calculate_address_similarity(target_function, match, max_addr_diff) + opcode_sim = calculate_opcode_similarity(target_function, match) + + print(f"\nMatch {i+1}:") + print(f"Function: {match['name']} at {match['address']}") + print(f"Size: {match_size} bytes (similarity: {size_sim:.4f})") + print(f"References: {match['reference_count']} (similarity: {ref_sim:.4f})") + print(f"Address similarity: {addr_sim:.4f}") + print(f"Opcode similarity: {opcode_sim:.4f}") + + # Show size difference as percentage + size_diff_pct = abs(target_size - match_size) / target_size * 100 + print(f"Size difference: {abs(target_size - match_size)} bytes ({size_diff_pct:.1f}%)") + +if __name__ == "__main__": + main() diff --git a/default.c3x_config.ini b/default.c3x_config.ini index 9b548f93..13d15a78 100644 --- a/default.c3x_config.ini +++ b/default.c3x_config.ini @@ -1,1177 +1,1177 @@ -[====================================================== C3X RELEASE 27 PREVIEW 2 DEFAULT CONFIG =====================================================] -[======================================================================= NOTE =======================================================================] -[Instead of editing this file, changes to the settings should be placed in either the scenario or custom config files. The scenario config file must ] -[be named scenario.c3x_config.ini and must be located in your scenario search folder. Of course it only applies if you are using a scenario. The ] -[custom config file must be named custom.c3x_config.ini and located in the C3X folder, which is the folder where this file is. When creating scenario] -[or custom configs, it is only necessary to include the settings you wish to change. ] -[====================================================================================================================================================] - -[============================] -[=== CONVENIENCE FEATURES ===] -[============================] - -enable_stack_bombard = true -enable_stack_unit_commands = true -enable_disorder_warning = true -show_detailed_city_production_info = true -enable_trade_screen_scroll = true -autofill_best_gold_amount_when_trading = true -skip_repeated_tile_improv_replacement_asks = true -group_units_on_right_click_menu = true - -; On the right click menu, units with no remaining moves will appear in gray text -gray_out_units_on_menu_with_no_remaining_moves = true - -; Places an icon next to units on the right-click menu showing their remaining moves & status. The icon is green for unmoved units, red for units that -; have exhausted all their moves, and yellow for those in between. Additionally it contains a little sword for units that can still attack and is -; colored blue for fighters set to intercept. -put_movement_icons_on_units_on_menu = true - -; Replaces the "Wake" or "Activate" text on the right-click menu with more descriptive words indicating what the unit is currently doing. For example, -; "Moving", "Intercepting", or "Working". -describe_states_of_units_on_menu = true - -show_detailed_tile_info = true -show_golden_age_turns_remaining = true - -; This option causes the game to show attack animations for units exerting zone of control from the middle of their tile's stack. Otherwise the game -; will only show such animations for units that are the top visible unit on their tiles. It was presumably an oversight by the original developers -; that units exerting zone of control do not temporarily become the visible unit on their tiles (unlike, for example, defensive bombard). -show_zoc_attacks_from_mid_stack = true - -; Fixes the defensive bombard animation being skipped when the unit performing defensive bombard is inside an army. -show_armies_performing_defensive_bombard = true - -cut_research_spending_to_avoid_bankruptcy = true -dont_pause_for_love_the_king_messages = true - -; Holding shift when clicking a specialist on the city screen will switch to the previous, instead of the next, specialist type -reverse_specialist_order_with_shift = true - -; Pressing the Z key on the city screen will zoom the map in/out -toggle_zoom_with_z_on_city_screen = true - -; When king units are spawned they're named after the leader of their civ. This is undesirable in modded games where the king flag is often used -; on units that aren't intended to be actual kings. This setting helps by bypassing the king unit naming logic when regicide is not enabled. -dont_give_king_names_in_non_regicide_games = true - -; One of the game's "Easter eggs" is that all king-flagged units appear as Elvis Presley on his birthday (Jan 8). This can be annoying when playing -; mods that make wide use of the king flag. -no_elvis_easter_egg = false - -; Removes option to automate workers from the human player. Useful for those who never want to use automation but sometimes accidentally activate it. -disable_worker_automation = false - -; There is a limit to how many links can appear on each Civilopedia page. Some mods exceed that limit. The problem is that the game throws up a popup -; when the limit is exceeded, one popup for each link beyond the limit. That can result in dozens of annoying, useless popups. This option stops them -; from appearing. Note: the game may also crash if the number of links far exceeds the limit. This option does not stop the crash, just the popups. -suppress_hypertext_links_exceeded_popup = true - -; Replaces the text "Upgrades To" with "Obsoleted By" in the Civilopedia for unit types that go obsolete but cannot be upgraded to their successors. -indicate_non_upgradability_in_pedia = true - -; Shows a message when a bomber gets intercepted by enemy air defense buildings but succeedes on its roll to avoid damage. Without this message, there -; is no indication that anything happened in that case except for the bomber losing one movement point. -show_message_after_dodging_sam = true - -; Normally only the last human player in a hotseat game gets to see the AIs move their units since the game processes the interturn while that player -; is still seated. This setting shows the AI moves to the other players in the game. It works by creating a save just before the interturn processing -; happens and then, at the start of the other players' turns, loads the save, sets that player as the seated one, reprocesses the interturn, then -; resumes the original game. -; Note: If the game is manually saved and reloaded, the replay will be lost. So it is recommended to save the game only after all human players have -; seen the replay, i.e. during the last or second to last human players' turns. -replay_ai_moves_in_hotseat_games = false - -; Normally, when you load a save, all units face southeast because the game didn't record which direction they were facing when the save was -; created. However, the game does record which tile they were on before their most recent move, so it is possible to deduce which direction they -; should be facing. That's what this option does. -restore_unit_directions_on_game_load = true - -; The game stores your map grid setting (on or off) in conquests.ini. It applies that setting after creating a new game, but not after loading a -; save. That was presumably an oversight and is corrected by this config option. -apply_grid_ini_setting_on_game_load = true - -; Causes cities to display harbor/airport icons if they have buildings that grant the relevant unit effects (produce veterans & heal in one turn) -; instead of buildings that grant sea/air trade. This makes no difference under the standard rules but is useful with mods that separate the unit -; effects and trade abilities into different buildings. -city_icons_show_unit_effects_not_trade = true - -; The game rules do not permit aircraft in an airfield to be damaged by bombardment. The interface allows players to order such bombardments anyway -; since its logic to check target validity is incomplete. This option completes the logic, causing the interface to reject attempts to bombard an -; airfield which would have no effect. -disallow_useless_bombard_vs_airfields = true - -; This option fixes a graphical bug that appears when the game is run on Linux using Wine. The bug is caused by the game using both Windows GDI and -; OpenGL to draw to the same canvas. Because the game only uses OpenGL to draw lines, it's relatively easy to solve this issue by reimplementing line -; drawing using Windows GDI+ instead. There are three possible settings for this option: -; never: Self-explanatory -; wine: This change will only be applied if the mod detects the game is running on Wine -; always: This change will always be applied, even on an actual Windows system -draw_lines_using_gdi_plus = wine - -; This option reduces the vertical distance between rows in the list of luxuries on the city screen. This allows up to 11 luxuries to be displayed -; neatly inside the box. -compact_luxury_display_on_city_screen = false - -; Similar to the option above, this one packs the strategic resources more tightly into the box on the upper left of the city screen. This allows up -; to 13 resources to be displayed there. -compact_strategic_resource_display_on_city_screen = false - -; Causes the domestic advisor to ask for confirmation before setting city production to a building that would replace another already built in the -; city. It's similar to how the domestic advisor warns you before a production switch would waste shields. Useful for modded games where you might not -; know which buildings replace which. -warn_when_chosen_building_would_replace_another = false - -; This option keeps citizens working the tiles they've been assigned to when pollution spawns there instead of converting them to specialists. This -; reduces micromanage but comes at the cost of the specialist yields. -do_not_unassign_workers_from_polluted_tiles = false - -; Normally the game draws capital cities one level larger than normal. I.e., a capital city at size 1 - 6 uses the graphic for cities at size 7 - 12, -; and a capital at size 7+ uses the graphic for cities 13+. This option turns that off, so capitals use the standard city graphics. -do_not_make_capital_cities_appear_larger = false - -; Tints coast and sea tiles on the minimap based on the culture that controls them, like is normally done for land tiles. -show_territory_colors_on_water_tiles_in_minimap = false - -; In offline games, shows some popup messages as online-multiplayer-style notes to the left of the screen instead of advisor popups that pause -; gameplay until dismissed. The point is to minimize interruptions during turn processing. Affects popups with the following text keys: -; SUMMARY_END_GOLDEN_AGE, SUMMARY_END_SCIENCE_AGE, SUMMARY_NEW_SMALL_WONDER, WONDERPRODUCE, MAKEPEACE, MUTUALPROTECTIONPACT, MILITARYALLIANCE, -; SUMMARY_DECLARE_WAR, TRADEEMBARGOENDS, SUMMARY_CIV_DESTROYED_BY_CIV, SUMMARY_CIV_DESTROYED, LOSTGOOD, TRADEEMBARGO, MILITARYALLIANCEWARONUS, -; MILITARYALLIANCEAGAINSTUS, and SUMMARY_TRAVELERS_REPORT. -convert_some_popups_into_online_mp_messages = false - -; If enabled, pressing the keys d e b u g to type "debug", in-game will allow you to activate debug mode for a game in progress. Typing that with -; debug mode already on will deactivate it. -enable_debug_mode_switch = true - -; Places a small shadow below city dots on the minimap to make them more easily visible especially against light-colored territory. This feature does -; not quite work properly so is left off by default. Its issues are (1) the shadows may not fully appear until you toggle the minimap from territory -; to geography mode and back again and (2) the shadows may appear in geography mode. -accentuate_cities_on_minimap = false - -; Makes the minimap twice as large. Possible values are "never", "always", and "high-def". The first two are self-explanatory; if set to "high-def", -; the minimap's size will be doubled when the game is run at a horizontal resolution of at least 1920 pixels. -double_minimap_size = high-def - -; Allows descriptions for units, civilizations, and game concepts to span multiple pages. If a DESC entry of one of those types is too long for one -; page, it will automatically be divided into multiple with buttons added for navigation. -allow_multipage_civilopedia_descriptions = true - -; Controls how the game searches for the next unit to autoselect. The possible choices are: -; standard: Base game behavior -; similar-near-start: The game will search for similar units near the starting point of the last selected unit. That means, when a unit is selected, -; the game remembers its location then searches out from there for a similar unit when cycling to the next one. Distance is prioritized over -; similarity, meaning the game will select all units on the starting tile no matter how dissimilar before any on nearby tiles. -; similar-near-destination: Like similar-near-start except the search goes outward from whatever tile the last selected unit was last on. -unit_cycle_search_criteria = standard - -; On the domestic advisor screen, tweaks how the number of turns remaining on each city build are displayed to improve readability. Instead of -; "(1turn)" or "(7turns)", the game will display "(1 Turn)" or "(7 Turns)" -reformat_turns_remaining_on_domestic_advisor_screen = true - -; On unit Civilopedia pages, shows the movement stat for aircraft, bombard range for tactical nukes, and HP bonus & worker strength if non-zero. -expand_civilopedia_unit_stats = true - -[====================] -[=== OPTIMIZATION ===] -[====================] - -; Rewrites the game's trade network computation logic to improve speed. On large maps with many cities, this computation takes up most of the -; interturn time so speeding it up greatly improves turn times. For more info, see the text file in the Trade Net X folder. -enable_trade_net_x = true - -; Rewrites parts of the game logic to improve efficiency. Those parts check every possible improvement defined in the scenario when they really only -; need to check a few. For example, to determine whether a city can trade via air, it's very wasteful to check every improvement since the vast -; majority of them do not enable air trade. This option can improve turn times very significantly in some circumstances. -optimize_improvement_loops = true - -; Displays a popup after each turn has been processed showing the time elapsed, including specifically how much time was spent recomputing trade -; networks. NOTE: Turning this on will skip all animations during the interturn so they don't contribute to the time. You aren't meant to play the -; game with this option left on. -measure_turn_times = false - -[=======================] -[=== AI ENHANCEMENTS ===] -[=======================] - -; Allows artillery unit AI to grab escorts from city defenders, causing the AI to use its artillery offensively instead of leaving it in its cities. -use_offensive_artillery_ai = true - -; If true, the AI will not escort its units unless they have the "requires escort" flag set in the editor. This allows modders to remove the escort -; requirement from certain types of units, for example artillery with non-zero defense. -dont_escort_unflagged_units = false - -; Set to a number to encourage the AI to build more artillery, set to false or <= 0 for no change in AI unit build choices. The number is how many -; artillery units the AI will try to keep around for every 100 non-artillery combat land units it has. The encouragement only applies if the AI is -; already above a minimum of one defensive unit per city and one offensive unit per two cities. Default: 16. -ai_build_artillery_ratio = 16 - -; The above option controls how many artillery the AI will keep around, this one controls how aggressively it builds up to that limit. More -; specifically it controls how valuable (in percent) the AI thinks artillery is as a damage dealer compared to attacking units. Default: 50. -ai_artillery_value_damage_percent = 50 - -; Like the artillery ratio, shifts the AI's build priority from fighters to bombers to keep around this many bombers per 100 fighters. Default: 70. -ai_build_bomber_ratio = 70 - -; Completely replaces the leader unit AI with custom code. The custom version is similar in spirit to the original but fixes several major issues: -; 1. It fixes a bug that allowed the AI to rush any kind of city production, including units and (with an MGL) wonders -; 2. Prioritizes army formation over rushing production when appropriate -; 3. When rushing, prioritizes wonders and costly improvements in high value cities -replace_leader_unit_ai = true - -; Replaces the AI code that determines whether a unit would be a good addition to an army. The replacement code fixes a major bug that prevented the -; AI from filling its armies, prevents the AI from including hidden nationality units in armies to avoid crashes, and removes some logic that -; encouraged the AI to mix unit types in armies. -fix_ai_army_composition = true - -; "Pop units" are special units whose only purpose is to be joined into cities to increase their population. Normally the AI does not know what to do -; with these units, so this option enables a routine that causes them to search for & join an appropriate city. Pop units only appear in some mods -; (for example Tides of Crimson). Under the standard game rules, this option has no effect. In order to function as a pop unit, a unit must use the -; terraform AI strategy, have no worker actions except join city, have a pop cost of at least 1, and have zero attack, defense, & bombard strengths. -enable_pop_unit_ai = true - -; "Caravan units" are special units whose only purpose is to be disbanded to contribute shields to a city. The name comes from the Civ 2 caravan. -; Caravan units may appear in some mods; under the standard game rules, this option has no effect. In order to function as a caravan unit, a unit must -; use the terraform AI strategy, have no worker actions enabled, have the ability to disband, and have zero attack, defense, & bombard strengths. -enable_caravan_unit_ai = true - -; In the base game, the AI will assign 1, 2, or 3 escort units to its naval transports and carriers depending in their shield cost and the number of -; units they're carrying. This option lets you reduce the upper limit on the number of escorts assigned. You can limit the number of escorts to 2, 1, -; or even 0. Setting this option >= 3 will result in base game behavior. The purpose of reducing the limit is to free up the AI's naval power units. -max_ai_naval_escorts = 3 - -; This controls how many workers the AI feels it needs as a percentage of the base amount. For example, if set to 150 (the default), the AI will build -; about 50% more workers than normal. Set to 100 for base game behavior. For more info, see: -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-95#post-16587093 -ai_worker_requirement_percent = 150 - -[=================] -[=== BUG FIXES ===] -[=================] - -; Descriptions of bugs and their fixes: -; SUBMARINE BUG -- The AI runs into invisible units (such as submarines) belonging to other players because it blindly follows paths produced for -; it by the game's pathfinder, which does not see invisible units. After colliding with an invisible unit, the AI initiates combat, declaring war if -; necessary. The mod fixes this bug by modifying the pathfinder so it sees invisible units belonging to other non-hostile players so it can route -; around them. -; SCIENCE AGE BUG -- The bonus science points generated by a scientific golden age are not actually counted towards research progress. They appear -; only on the interface. This is because of a small oversight in the code. There is a setting which controls whether or not science age bonus points -; are included while gathering all research points. It's turned off while gathering points to update research progress. The fix is to turn it on. -; PEDIA TEXTURE BUG -- There is a one pixel wide pink line on the right edge of the Civilopedia screen. This is because the width of the -; Civilopedia background texture is set one pixel too small inside the EXE. This is fixed simply by replacing the width with the correct value. -; BLOCKED DISEMBARK FREEZE -- When using "disembark all" (which the AI always does) on a boat containing units that can't be disembarked, the game -; may freeze as it endlessly tries to disembark them. The root of the problem is that the game's logic to check if there are any disembarkable units -; left on the boat is incomplete. There are two cases that it misses. First, it does not consider the "immobile" unit flag. This is fixed by making -; immobile units appear to have no remaining movement points for this bit of logic so they are correctly considered non-disembarkable. Second, it does -; not consider escort relationships (e.g. for settlers). If a unit has a non-disembarkable escorter then it also can't be disembarked because the game -; will always try to move its escorter ahead of it. The solution here is to clear all escort relationships for ship passengers before disembarking. -; HOUSEBOAT BUG -- The game may crash when an AI player is left alive with only a settler on a boat. This happens because the AI's logic tries to -; check the location of its capital city without considering that there may be no capital. The fix is to modify this logic so that when it looks up -; the location of a non-existent capital, it receives a valid "dummy" location that it can process without crashing. See also: -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16084386 -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16085242 -; INTERCEPT LOST TURN BUG -- When a human player sets a fighter to intercept mode, the game discards all of its remaining movement points, hence it -; cannot intercept during the next interturn. This bug does not affect the AI and is part of the interface logic, not the game logic. I presume it was -; inserted by a programmer who did not understand how the game's unit cycling works. The fix simply restores fighters' discarded moves. -; PHANTOM RESOURCE BUG -- The game only stores one full list of available resources per player. That list contains how many sources of each -; resource type are avaiable in that player's capital and all connected cities. Cities off the capital's network have reduced lists of just 32 bits, -; recording yes-or-no availability for up to 32 resources. Resources beyond the first 32 will share bits in those reduced lists. Specifically, the -; 33rd resource shares the same bit as the 1st, the 34th the same as the 2nd, and so forth. This causes "phantom" resources. For example, if a mod has -; horses set as the 1st resource and steel as the 33rd, then any city off its capital's trade network with access to horses will also have access to -; steel and vice-versa. The fix for this issue is straight forward but not simple. The jist is the mod allocates additional space for the reduced -; lists so they're not limited to 32 bits, rather have enough bits for every resource in the game. After that it's necessary to modify the code that -; accesses the reduced lists so it can make use of the additional space. -; MAINTENANCE PERSISTING FOR OBSOLETE BUILDINGS -- Players are not supposed to pay maintenance for obsolete city improvements however they often do -; because the game does not recompute maintenance after a player unlocks a technology that obsoletes a city improvement. There is a related exploit in -; that, after triggering a recomputation of maintenance, players can then sell their obsolete buildings to have the maintenance deducted again, -; effectively getting credited for the cost of maintenance. The mod fixes both issues. It recomputes maintenance costs when a player unlocks a -; technology that obsoletes a city improvement and it stops the game from deducting the maintenance cost of an obsolete city imp. when it's sold. -; BARBARIAN DIAGONAL BUG -- Barbarians can only search for targets on adjacent tiles or on tiles that are up to 12 steps directly SE or NW of their -; position. The intended behavior was for them to search for targets on all surrounding tiles up to 6 steps away. This bug was caused by a small, -; sloppy programming mistake that can be corrected with a small edit. For details, see: -; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-70#post-16434678 -; DISEASE CURING TECH FLAG BUG -- In the base game, the tech flag "Disables Diseases From Flood Plains" (applied to Sanitation) does nothing and -; instead flood plains disease stops once players discover Writing. This happens because that flag is encoded as number 8 and, instead of checking if -; players have a tech with that flag, the code mistakenly checks if players have tech #8, which is Writing under the standard rules. Correcting this -; bug causes a lot more disease, which is a major annoyance, and so this bug fix is turned off by default. -; DIVISION BY ZERO IN AI ALLIANCE EVAL -- When considering whether to agree to a military alliance, the AI computes the distance from its capital to -; the nearest city belonging to the target of the alliance and divides by that distance. For unknown reasons, in rare cases that distance may be zero, -; which crashes the program due to division by zero. The mod fixes this issue by inserting a bit of logic after the distance is computed to check if -; it's zero and, if so, set it to one. -; EMPTY ARMY MOVEMENT -- Empty armies have one less than a full move's worth of movement points regardless of how many moves their unit type has set -; in the editor. Under the standard game rules, this means they can only move two tiles along roads. The cause is a small mistake in the logic that -; attempts to find the slowest member among units in the army. The mod fixes this bug by reimplementing the max movement point calculation for armies. -; PREMATURE TRUNCATION OF FOUND PATHS -- If the game attempts to find a path for a unit that's more than 256 tiles long, the path will not be -; returned properly from the pathfinder. That's because the pathfinder stops reconstructing the final path once it reaches a length of 256. That -; creates a serious problem for long paths because reconstruction works from the end of the path toward the start, so stopping early produces an -; incorrect path that begins in the middle. The fix is simply to multiply the maximum length by 10 (to 2560). Removing the limit entirely risks -; allowing infinite loops. This bug is rarely visible in-game, it usually appears as AI naval units following inappropriate or invalid paths. -; ZERO PRODUCTION CRASH -- If a city has zero production, which is possible using specialists modded to produce negative shields, the game will -; crash due to a division by zero. -; AI CAN SACRIFICE WITHOUT SPECIAL ABILITY -- The base game function that gates the AI's ability to sacrifice units does not check whether the unit -; in question has the sacrifice special ability set on its type. Thus, AIs are allowed to sacrifice any captured units as long as they have the -; required tech. The mod fixes this by patching the gating function to insert the missing condition. -; AI CAN FORM ARMY WITHOUT SPECIAL ABILITY -- Similar to the above issue, the AI's ability to form armies with leader units is not gated by those -; units having the "build army" special ability. -; CRASH IN LEADER UNIT AI -- The base game's AI routine for leader units may crash due to uninitialized variables. -; FAILURE TO FIND NEW CITY BUILD -- After a city completes production, the game searches for a new build for it. If that city is owned by the seated -; player, whatever the game finds will be filled in as the default option in the domestic advisor popup asking the player to choose a new build. If -; the search fails to find anything, there will be no default option, the dropdown selector will not be initialized, and the game will crash when it -; tries to open the popup. To fix this, the mod detects when the game has failed to find a new build option and fills in Wealth instead or, failing -; that, any unit or improvement that the city can build. -; PASSENGERS OUT OF ORDER ON MENU -- When there are multiple doubly-contained units (meaning units contained in other units that are themselves -; contained in something, like a unit in an army on a transport) on a tile, the game will not always show the passenger units in the correct locations -; on the right-click menu. To fix this, the mod double checks the order of the entries on the menu to make sure that passenger units are listed just -; after the unit they're contained in. -; PATCH EMPTY ARMY COMBAT CRASH -- Guards a crash in the army combat selection routine by returning the army unit itself if it has no contained -; units (prevents divide-by-zero in the vanilla selection loop). - -patch_submarine_bug = true -patch_science_age_bug = true -patch_pedia_texture_bug = true -patch_blocked_disembark_freeze = true -patch_houseboat_bug = true -patch_intercept_lost_turn_bug = true -patch_phantom_resource_bug = true -patch_maintenance_persisting_for_obsolete_buildings = true -patch_barbarian_diagonal_bug = true -patch_disease_stopping_tech_flag_bug = false -patch_division_by_zero_in_ai_alliance_eval = true -patch_empty_army_movement = true -patch_premature_truncation_of_found_paths = true -patch_zero_production_crash = true -patch_ai_can_sacrifice_without_special_ability = true -patch_ai_can_form_army_without_special_ability = true -patch_crash_in_leader_unit_ai = true -patch_failure_to_find_new_city_build = true -patch_passengers_out_of_order_on_menu = true -patch_empty_army_combat_crash = true - -; At the beginning of each AI player's turn, deletes any units of theirs that are not on a valid tile. This addresses a rare crash that can occur when -; the unit AI invokes the pathfinder for an off-map unit. I don't know how AI units can end up off the map in the first place. -delete_off_map_ai_units = true - -; On the city screen, the icons for different kinds of specialist yields get drawn over top of, instead of beside, one another. This setting fixes -; that so they are displayed properly. -fix_overlapping_specialist_yield_icons = true - -[======================] -[=== LIMITS REMOVED ===] -[======================] - -remove_unit_limit = true -remove_city_improvement_limit = true - -; The city limit can be configured up to a maximum of 2048 or down to a minimum of 0. For base game behavior, set to 512. -city_limit = 2048 - -; Increases the cap on the game turn limit from 1000 to 1000000 -remove_cap_on_turn_limit = true - -; Be warned: the no era limit feature is incomplete, untested, and not likely to work at this time -remove_era_limit = false - -[=========================] -[=== ENGINE EXTENSIONS ===] -[=========================] - -; These "NoRaze" options can stop cities from being destroyed. "Autorazing" refers to the automatic destruction of size one, cultureless cities. If -; autorazing is prevented, players will be given the option to keep the city. If razing by players is prevented, neither the human player nor AIs will -; be allowed to raze or abandon cities. -prevent_autorazing = false -prevent_razing_by_players = false - -; These options allow you to adjust the minimum allowed distance between cities. minimum_city_separation controls the minimum number of tiles between -; cities so, e.g, if it's set to 1, cities cannot be founded adjacent to one another, there must be at least one open tile separating them. A setting -; of 1 there corresponds to the standard game rules. disallow_founding_next_to_foreign_city is an optional additional restriction. If it's enabled, -; cities may not be founded adjacent to a city belonging to another civ regardless of the minimum separation. It is only relevant when the minimum -; separation is set to zero. -minimum_city_separation = 1 -disallow_founding_next_to_foreign_city = true - -; Set to a number to limit railroad movement to that many tiles per turn. To return to infinite railroad movement, set to false or a number <=0. By -; default, all units travel the same distance along limited rails like in Civ 4, but this can be changed by toggling the next option below. -; NOTE: For best results, the railroad limit should be a multiple of the "movement rate along roads" set in the editor (usually 3). The limitation -; will work in any case, but setting the limit this way helps avoid an integer overflow issue inside the pathfinder that may cause it to fail to find -; the shortest paths for units with a large number of available moves. -limit_railroad_movement = false - -; If set to true, limited railroads will work like fast roads instead of Civ 4 style railroads. The movement rate along fast roads is determined by -; the limit_railroad_movement setting above. If that setting is false or <= 0, this option does nothing. -limited_railroads_work_like_fast_roads = false - -; This option lets you put a limit on how many units may occupy each tile. The limit applies separately for land, sea, and air units. You may set the -; limit differently for each of those classes by setting this option to a list of three numbers. If you set it to a single number, that limit amount -; will apply to all three. If you set it to false or a number <= 0, no limit will apply, as in the base game. Some examples: -; To limit tiles to 5 land, 5 sea, and 5 air units: limit_units_per_tile = 5 -; To limit tiles to 5 land and sea units but 10 air units: limit_units_per_tile = [5 5 10] -; To limit only air units to 10 per tile: limit_units_per_tile = [false false 10] -; To have no limit (as in the standard game rules): limit_units_per_tile = false -; NOTE: The two options below let you exclude cities or certain unit types from the limit. -limit_units_per_tile = false - -; Allows an unlimited number of units to occupy tiles with cities when the unit limit is in force. When the limit (option above) is deactivated, this -; option does nothing. -exclude_cities_from_units_per_tile_limit = false - -; Allows certain unit types to be exempt from the stack limit. Units of these types will not be stopped by the limit and will not count toward it -; (will not stop others). This option is a space separated list of unit type names. Multi-word names must be wrapped in quotes. For example: -; [Worker Settler Flak "Mobile SAM"] -; This option does nothing if limit_units_per_tile is set to false. -exclude_types_from_units_per_tile_limit = [] - -enable_free_buildings_from_small_wonders = true -allow_stealth_attack_against_single_unit = false -disallow_trespassing = false -enable_land_sea_intersections = false - -; All anarchy lengths will be multiplied by this amount as a percent. For example, if set to 50, anarchy length will be reduced by half. Set to 100 -; for standard game behavior. There is a minimum anarchy length of 2 turns, but you can remove anarchy entirely by setting this option < 0. -anarchy_length_percent = 100 - -; Add perfume to an improvement or unit type to encourage the AI to build it more often. When choosing what to buld, the AI computes a point value for -; each of its options and the mod will add the perfume amount to the point total for each named option. For reference, point values are often in the -; hundreds for the most desirable options. You can see the point value the AI gives to every available build by pressing P while viewing one of its -; cities. Perfume amounts can also be specified as a percentage, ex. a perfume amount of 15% will increase the AI's evaluation by 15% and an amount of -; -50% will reduce it by half. -; production_perfume is a list of names and amounts, each one looks like "name": amount -; Here's an example: ["Granary": 15, "Colosseum": -20%, "Courthouse": 30] -; The quotation marks around a name are not necessary if the name is all one word (i.e. does not include spaces) and is made up of only letters, -; digits (0-9), periods, hyphens, or underscores. The category of letters includes the normal English a-z and A-Z as well as accented variants -; (e.g. ä, ö, ñ, ç) and all other non-English letters available in the Windows-1252 encoding (e.g. ß, þ, æ). -production_perfume = [] - -; Add perfume to a technology to change how valuable the AI judges the tech to be. Each point of perfume is worth roughly one gold in trade, and also -; affects what the AI chooses to research. The format matches production_perfume above, ex.: [Medicine: 500, Fascism: -50%, "Replacable Parts": 20%]. -technology_perfume = [] - -; Add perfume to a government to encourage or discourage the AI from switching to that type. The format follows the other perfume options, ex.: -; [Republic: 10%, Fascism: -30%]. Unfortunately I don't know how much each point is worth in this context. I also don't know how perfuming governments -; affects the AI's willingness to overthrow its current govt. The perfume for sure applies when the AI is selecting a new govt type after anarchy. -government_perfume = [] - -; The AI production ranking is the point value the AI gives to each available build in some city. To view it, press P while viewing an AI city. -enable_ai_production_ranking = true - -; Shades/highlights each tile to show how desirable the AI considers it as a city location. To activate, press L while in game. The scale goes from -; white (least desirable) to red (most desirable) with yellow in between. Also the exact number the AI gives any tile can be seen on its info box. -; If show_ai_city_location_desirability_if_settler is true, the desirability overlay will automatically appear when a settler is selected. -enable_ai_city_location_desirability_display = true -show_ai_city_location_desirability_if_settler = false - -; Setting a government's corruption level to "OFF" will remove all corruption, as expected, instead of maximizing it -zero_corruption_when_off = true - -; Prevents land settlers/workers on transports from settling/improving water tiles. This option does not affect the vanilla game but is useful for -; mods that enable city building or improvement of water tiles. -disallow_land_units_from_affecting_water_tiles = true - -; Allows units to move after airdropping by making airdrops cost no movement. Under the standard game rules, units lose all their remaining moves -; after airdropping. Units will be prevented from airdropping more than once in the same turn. -dont_end_units_turn_after_airdrop = false - -allow_airdrop_without_airport = false -enable_negative_pop_pollution = true - -; Here it's possible to set buildings as prerequisites for unit production. It's possible for a unit type to have multiple prereq buildings up to a -; maximum of 10, and all must be present in a city for the unit to be buildable. -; The format is a list of building names and unit type names, each one looks like "building name": "unit type 1" "unit type 2" ... -; Quotation marks around names can be omitted like in production_perfume (see above). -; Here's an example: -; [Factory: Tank "Modern Armor", -; Barracks: Swordsman Cavalry Tank "Modern Armor", -; Airport: Bomber] -building_prereqs_for_units = [] - -; Here it's possible to set buildings to generate resources. Those resources can be added to the trade network or limited to the building's city. The -; format is a list of building name and resource name pairs with optional "local", "no-tech-req", "yields", "show-bonus", and/or "hide-non-bonus" -; settings before each resource name. Example: -; ["Steel Mill": Steel, Terrace: yields show-bonus Rice, "Coal Liquefaction": local Oil, Supercollider: local no-tech-req Antimatter, -; "Hydro Plant": local "Electric Power"] -; Quotation marks around names can be omitted like in production_perfume (see above). -; The "local" setting means that the produced resource will not be added to the trade network, it will be available only in the building's city. -; The "no-tech-req" setting means that the resource will be produced even for players who do not have the technology to reveal it on the map. -; The "yields" setting means that the resource's tile yields will be added to the city as if it were on a worked tile. -; The "show-bonus" setting means that an icon for the generated resource will be displayed on the city screen even if it's a bonus resource. -; The "hide-non-bonus" setting is the opposite of show-bonus. It means an icon will NOT be shown if the resource is of strategic or luxury type. -; Buildings will not generate resources if the resource requirement for the building itself is not met. This makes it possible to set up resource -; production chains. Note for modders: Production chains require the input resources to be listed before the outputs in the scenario data, when the -; inputs also come from buildings. For example if you have iron ore on the map, a building that requires it and produces iron, and a building that -; requires iron and produces steel, iron must be listed before steel in the scenario data or the chain won't work. This is because building resource -; generation is calculated in the same order as the generated resources appear in the scenario data. This limitation does not apply to map resources -; (iron ore in the example) as access to all map resources is calculated first before any building resources. -buildings_generating_resources = [] - -; Shows a warning in case some of the unit, building, or resource names in this config file don't match anything in the scenario data. -warn_about_unrecognized_names = true - -; Overrides the rules for when units are eligible to retreat based on their movement. The possible options are: -; standard: No change from base game rules -; none: No units will ever retreat -; all-units: All non-immobile units may retreat, even if they have only one move or are up against a faster opponent -; if-faster: Units may retreat when they are faster than their opponent, for example a cavalry may retreat from a knight -; if-not-slower: Units may retreat when they are at least as fast as their opponent, for example a knight may retreat from another knight but not -; from a cavalry, and an infantry may retreat from another infantry -; if-fast-and-not-slower: Like if-not-slower but only fast (2+ move) units may retreat -; These settings don't change the fact that units cannot retreat when they start combat with 1 HP or are defending a city. They also do not change -; that naval units cannot retreat defensively (there is a separate option for that below). -land_retreat_rules = standard -sea_retreat_rules = standard - -; Under the base game rules, no unit may retreat defensively if it's located on a water tile. This option removes this special rule so naval units can -; retreat defensively like land units do. See also: the sea_retreat_rules option above and the limit_defensive_retreat_on_water_to_types option below. -allow_defensive_retreat_on_water = false - -; If any unit types are listed here, defensive retreat on water tiles will be limited to those types. Otherwise, all types may retreat that way. The -; list is separated by spaces and multi-word type names must be wrapped in quotation marks. For example, setting to: -; [Submarine "Nuclear Submarine"] -; would mean that only those submarine naval units could retreat defensively. This option does nothing if allow_defensive_retreat_on_water is false. -limit_defensive_retreat_on_water_to_types = [] - -; The multi-city start spawns in multiple cities for AI players at the start of the game instead of their usual one settler. This option controls the -; number of cities the AI starts with. E.g., if it's set to 2, the AI starts with 2 cities. If it's set <= 0, the game starts like normal. The mod can -; also add improvements to the AI's extra cities, which are intended to work like extra palaces, see ai_multi_start_extra_palaces. -ai_multi_city_start = 0 - -; This option only applies if ai_multi_city_start is set > 1. It controls how many tiles the mod will randomly check while searching for a suitable -; location for each of the AI's extra starter cities. Default: 10000. -max_tries_to_place_fp_city = 10000 - -; This option only applies if ai_multi_city_start is set > 1. It specifies a list of improvements to be added to the AI's additional cities. E.g: -; ["Forbidden Palace" Courthouse] -; If the AI multi-city start is set to 3+ with the above extra palaces, the AI players will start with 3+ cities and the first one will have the -; Palace like normal, the second will have the Forbidden Palace, and the third will have a courthouse, any after that will start empty. -; Additionally, any small wonders listed here with the "reduces corruption" effect will be considered "extra palaces" for the AI. They will respawn -; like the real Palace. In other words, if an AI loses a city with an extra palace, it will reappear in another one of its cities following the same -; logic the game uses to select a new Palace location. If the AI is missing an extra palace and acquires a new city, that extra palace will -; automatically be added to the new city. -ai_multi_start_extra_palaces = [] - -; Turning this on makes small or great wonders with the "reduces corruption" effect, such as the Forbidden Palace, as effective at reducing corruption -; as the palace itself. This reduces corruption not only in the city that contains such a wonder, it also reduces distance and rank corruption in -; nearby cities as if the city were an additional capital. -promote_wonder_decorruption_effect = false - -allow_military_leaders_to_hurry_wonders = false -allow_multiple_battle_created_units_per_player = false - -; The AI's beaker production will be multiplied by this amount, as a percent. A value of 100 gives you the standard game behavior, a value of 75 -; reduces AI research by 25%, a value of 200 doubles AI research, and so on. -ai_research_multiplier = 100 - -; Each time an AI player founds a city, the given amount of perfume will be applied to its settlers over the given duration in number of turns. The -; perfume effect declines steadily to zero over the duration. The perfume amount may be specified as a percentage. The purpose of these options is to -; slow the AI's expansion with negative perfume. -; NOTE: The AI has a very strong tendency to build settlers so you'll need to set these options quite high to slow it down significantly. For example, -; a perfume of -200% over a 30 turn duration left the AI with about half as many cities after 50 turns in my test. -ai_settler_perfume_on_founding = 0 -ai_settler_perfume_on_founding_duration = 0 - -; If a player can't afford to pay maintenance on their buildings and units, the game will forcibly lower expenses and raise money by (in order): -; 1. Selling buildings, excluding those that are maintenance-free or contribute to gold production even indirectly -; 2. Disbanding units, excluding free ones -; 3. Switching cities to building Wealth -; For AI players, the game alternates the order of (1) and (2) each turn. Also for AIs, on every third turn, the game will cut their research spending -; as much as necessary to avoid bankruptcy. -aggressively_penalize_bankruptcy = false - -; Under the standard game rules, the Despotism tile penalty does not apply to food yield from city tiles of Agricultural civs with fresh water. Set -; this option to true to remove that exception to the penalty. -no_penalty_exception_for_agri_fresh_water_city_tiles = false - -; Adds an option to the stealth attack target selection popup that allows the player to opt out of doing a stealth attack. If selected, the unit will -; attack normally, targeting the tile's top defender. Similarly, if stealth bombardment is canceled, the unit will bombard normally and may target -; buildings or population if attacking a city. -include_stealth_attack_cancel_option = false - -; Aircraft flying a recon mission can be intercepted by enemy fighters or ground AA as if they were flying a bombing mission -intercept_recon_missions = false - -; Under the standard rules, performing a recon mission or intercepting an attacker causes a unit to lose all of its remaining moves. Setting this -; option to true causes those actions to only consume one move. This makes them consistent with other air missions like bombing. Note: fighters will -; only be able to intercept multiple times in one turn if they have the blitz ability. -charge_one_move_for_recon_and_interception = false - -; In the base game, precision striking was only intended to be used by bombers. This option extends the precision strike logic to cover land & sea -; artillery and cruise missiles. Specifically what it does is: -; 1. Fixes the animations, so land & sea artillery will play their bombard animations and cruise missiles will play their strike animation -; 2. Makes it so that the strikable range depends on the bombard range for land & sea units instead of operational range -; 3. Despawns cruise missiles after they've performed a precision strike -polish_precision_striking = true - -; Enables units to perform stealth attacks when they bombard or bomb a target. Like regular stealth attacks this opens a popup allowing the player to -; choose a specific unit to target. The attacking unit must have the stealth attack special action checked, must have a list of stealth attack targets -; set, and the target tile must be visible. -enable_stealth_attack_via_bombardment = false - -; Prevents aircraft from being damaged by bombardment or bombing -immunize_aircraft_against_bombardment = false - -; Unit type names listed here will use PTW-like targeting when bombarding cities. PTW-like means there is a 1-in-3 chance they will target each of -; population, buildings, and units. This is unlike Conquests artillery targeting, which always goes after units first. Items in the list are separated -; by spaces and multi-word items must be wrapped in quotation marks like for perfume specs. Example: [Catapult Cannon Artillery "Radar Artillery"] -ptw_like_artillery_targeting = [] - -; Changes the meaning of the charm attack flag to indicate PTW-like targeting. This is a matter of convenience. It allows modders to specify PTW -; targeting using an editor, instead of the list above, at the cost of losing the charm attack function. -charm_flag_triggers_ptw_like_targeting = false - -; Unit types listed here won't be allowed to bombard land tiles. Same format as ptw_like_artillery_targeting, example: [Submarine "Torpedo Bomber"] -can_bombard_only_sea_tiles = [] - -; Units with the king ability will defend like normal, instead of always being the last to defend in a stack. Useful for mods that use the king flag -; for special purposes. Does not apply in regicide games. -ignore_king_ability_for_defense_priority = false - -; Untradable techs will appear grayed out on the trade screen. This lets you see which untradable techs the AI has just like for tradable -; ones. "Untradable" means techs that have been flagged as "cannot be traded" in the editor. This option only matters for modded games as there are no -; untradable techs in the standard game. -show_untradable_techs_on_trade_screen = false - -; Barbarians will capture cities instead of ransacking them. This option also modifies the game's production logic so barbarian cities can build -; things, grow, and even do research. -; This feature is EXPERIMENTAL at the moment. It basically works but hasn't been extensively tested. For example, I don't know what would happen if -; the barb player were to win the game. -; Because of how barb city production works under the hood, it requires barb activity to be turned on in order to work. The mod will handle this -; automatically. If this option is enabled, there is at least one barb city on the map, and the barb activity level is set to 0 (no barbarians), the -; level will be increased to 1 (sedentary) in order not to block barb city production. -enable_city_capture_by_barbarians = false - -; A list of modifications to the rules for defensive bombard. "Defensive bombard" is the free shot a bombard unit gets when the stack it's in is -; attacked. The possible options are: -; lethal: Attackers may be destroyed by defensive bombard if the bombarding unit has the appropriate lethal land/sea bombard ability. -; aerial: Air units may perform defensive bombard if they can perform bombing missions. -; not-invisible: Attacking units are immune to defensive bombard if they are invisible and not detected. -; blitz: Units with blitz may perform defensive bombard multiple times per turn, once for each move they have. -; docked-vs-land: Docked ships (i.e. in a city) can perform defensive bombard against land units attacking their city. -; For example, to activate all options, set to [lethal aerial not-invisible blitz docked-vs-land]. The order of items in the list does not matter. You -; can also activate all options by setting to [all] (with or without the brackets). -special_defensive_bombard_rules = [] - -; A list of modifications to the rules for zone of control, like above for defensive bombard. The possibilities are: -; amphibious: Land units may exert zone of control over sea units and vice-versa. This can only be done using bombard strength, not attack -; strength. It also requires non-zero bombard range. -; lethal: Units may be destroyed by zone of control. The intercepting unit must have the lethal bombard ability in order to do this, even if it's -; using its attack strength to exert ZoC. -; aerial: Air units can exert zone of control if their type has the "Zone of Control" option checked. Additionally, they must be able to perform the -; bombing mission, have non-zero bombard strength, and non-zero operational range. -; not-from-inside: Land units may not exert zone of control while inside a transport (armies do not count as transports) -; Like for defensive bombard, all options can be activated by setting to [all] (with or without the brackets), and order does not matter. -special_zone_of_control_rules = [] - -; All human players in a hotseat game will share visibility -share_visibility_in_hotseat = false - -; All human players in a hotseat game will share the effects of the wonders they've built, great or small. This applies to all civ-wide effects, for -; example if any human player builds Leonardo's Workshop, all human players get half price upgrades. Notes: -; 1. If a human player receiving the shared effect of a small wonder and that SW has no non-shared effects, it becomes unbuildable for that player. -; 2. Building and army requirements for wonders are shared as well. For example, all human players are allowed to build Battlefield Medicine once all -; of them combined have five hospitals. -; 3. For the Great Library effect, known AI civs are shared as well. If an AI has contact with any human player, it is considered to be in contact -; with all of them for the purpose of granting techs to human players. -share_wonders_in_hotseat = false - -allow_precision_strikes_against_tile_improvements = false -dont_end_units_turn_after_bombarding_barricade = false - -; Allows land units to bombard aircraft and naval units in cities -; This does not override the immunity of aircraft vs bombardment, if that option is also activated. -remove_land_artillery_target_restrictions = false - -; Allows tile improvements on a tile with an occupied airfield to be destroyed by bombardment, not including the airfield itself. For example, under -; the standard game rules, if you bombard a tile with a road, airfield, and fighter on it, you will do no damage because the attack will target the -; fighter which is invulnerable (aircraft in an airfield cannot be damaged by bombardment). This option allows such an attack to bypass the fighter -; and hit the tile instead, as long as that tile has an improvement other than the airfield. -allow_bombard_of_other_improvs_on_occupied_airfield = false - -; Displays the total number of cities in the game on the demographics screen (press F11). -show_total_city_count = false - -; Under the standard game rules, each forbidden-palace-like building in an empire increases its optimal city number (OCN) by 37.5% of the base number, -; except if the empire is running a government with communal corruption, in which case the increase is 100% of the base. With this option enabled, the -; communal corruption rule is always in force, so each forbidden palace always increases the OCN by an amount equal to the base number. -; NOTE: The "base" optimal city number comes from the map size. It's the number set on the "World Sizes" tab in the editor. -strengthen_forbidden_palace_ocn_effect = false - -; This option allows you to increase the maintenance cost of units depending on their shield cost. For every X shields that the unit costs to build -; (where X is the setting below), the unit's maintenance increases by one unit's worth. For example, if set to 100, units that cost 0-99 shields will -; have normal maintenace, units costing 100-199 shields will cost double, those costing 200-299 will cost triple, etc. (Note the final cost in GPT -; depends on gov't type). Set <= 0 to disable. -extra_unit_maintenance_per_shields = 0 - -; This option renames players' civs depending on their eras. The format is a list of names each associated with a list of replacements. There is one -; replacement for each era or, if the list is shorter than the number of eras, no replacement will be done in the later eras. Example: -; [Rome: Rome "Byzantine Empire" Italy Italy, -; Roman: Roman Byzantine Italian Italian, -; France: Gaul, French: Gaulic] -; In this example, Rome will be renamed to "Rome" in the first era, "Byzantine Empire" in the second, and "Italy" in the third and fourth. The -; adjectives will be replaced to match. France/French will be renamed to Gaul/Gaulic only in the first era. -; Spaces are used to separate words so if a name or replacement has multiple words it's necessary to use quotation marks to group them together like -; for "Byzantine Empire" in the example. -; The replacements apply to civ nouns, adjectives, and formal names. If a player has put in a custom name, that will not be replaced. -civ_aliases_by_era = [] - -; This option works like the one above except it replaces leader names instead of civ names. Each replacement name may be followed by (M) or (F) to -; specify gender. Example: -; ["Joan d'Arc": Vercingetorix (M) "Joan d'Arc" (F) Napoleon (M) "De Gaulle" (M)] -; If no gender is specified then the game will use whatever gender was set in the scenario data for that civ's leader. That means (F) could be omitted -; in the above example since the leader of France is already female. -; Additionally you can include a replacement title after the gender separated by a comma. Here's the example with titles added: -; ["Joan d'Arc": Vercingetorix (M, King) "Joan d'Arc" (F) Napoleon (M, Emperor) "De Gaulle" (M, President)] -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 -; 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. -; 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. -unit_limits = [] - -; Removes barracks/harbor/airport requirement from upgrades -allow_upgrades_in_any_city = false - -; Stops the game from placing volcanos during map generation. Any tiles that would have been volcanos will be mountains instead. -do_not_generate_volcanos = false - -; Stops the game from placing pollution on impassable tiles -do_not_pollute_impassable_tiles = false - -; Includes the hitpoints of each possible target on the stealth attack selection popup. This makes it easier to pick out weakened units. -show_hp_of_stealth_attack_options = false - -; Stops invisible units from being targeted by stealth attacks. They can still be targeted if they've been revealed by the attacking civ. -exclude_invisible_units_from_stealth_attack = false - -; Stops units from being targeted by stealth attack if they are contained in another unit such as a naval or land transport, or a helicopter. -exclude_passengers_from_stealth_attack = false - -; Normally planting a forest always produces the regular non-LM forest terrain. This option changes that so it instead produces LM forest. -convert_to_landmark_after_planting_forest = false - -; This option specifies how likely it is (in percent) for a combat land or sea unit with a maximum of one HP to be destroyed when struck by a -; nuke. Set to 100 for base game behavior. -chance_for_nukes_to_destroy_max_one_hp_units = 100 - -; Allows you to sell aqueducts and hospitals as well as any modded buildings that uncap population growth. A city must be below the pop cap for a sale -; to be allowed, i.e., under the standard rules, aqueducts may only be sold in cities of pop <= 6 and for hospitals pop <= 12. -allow_sale_of_aqueducts_and_hospitals = false - -; Allows you to sell Small Wonders. This may be useful to relocate Forbidden Palace-like Small Wonders. -allow_sale_of_small_wonders = false - -; This option makes it so that only sea units with the "detect invisible" ability can reveal invisible sea units, and likewise for non-sea units. -no_cross_shore_detection = false - -; Controls the size of the area in which cities can work tiles. The value corresponds to cultural border expansions. For example, setting this to 1 -; means cities would only be able to work tiles within their level 1 cultural borders, meaning the eight tiles neighboring the city's own -; tile. Setting to 2 gives you the game's standard rule that cities may work tiles within their level 2 cultural borders, which they attain after one -; expansion. Setting to 3 allows them to work within level 3 borders and so forth. -; Notes: (1) If the city can work tiles in the fourth ring or farther, the map view on the city screen will be zoomed out when you enter it if -; auto_zoom_city_screen_for_large_work_areas is true. Otherwise it's not possible to show the entire work area. You can zoom back in by pressing Z. -; (2) The next option below can limit cities' workable areas to be smaller than the radius set here, based on their culture. (3) This option has a -; minimum value of 1 and a maximum of 7. -city_work_radius = 2 -auto_zoom_city_screen_for_large_work_areas = true - -; This option can reduce the size of the area cities can work based on their cultural level. -; Possible values are: -; none: Standard game rules apply; cities can work any tile that's within the work radius and within their owner's borders. -; cultural: Cities may only work tiles that are within their direct cultural borders, e.g. a city with zero culture may only work the 8 surrounding -; tiles. After one expansion, it may work the standard 20, after a second expansion it may work the third ring, and so on. -; cultural-min-2: Like "cultural" except cities can always work their standard 20 tiles. -; cultural-or-adjacent: Cities can work tiles in their direct cultural borders plus any tiles adjacent to those. -work_area_limit = none - -; This option can also reduce the size of the area cities can work based on improvements present. -; This mechanic works in tandem with the above work_area_limit condition - tiles cannot be worked if the tiles do not also meet the cultural work area limit requirement. -; If left empty, this mechanic is not used. -; Improvements may be defined to grant a certain radius work area, and the highest radius present is used as the work radius for a city. eg ["Harbor": 3] -; Improvements may also grant a bonus radius, these are added on after the highest radius is found. [Factory: 3, "Mass Transit": 2 extra] -; An entry written as default or "default" will always be present for any given city, and represents an always-present virtual improvement. eg. ["default": 2] gives vanilla behaviour. -work_area_improvements = [] - -; The maximum distance it's possible to rebase an aircraft equals its operational range times this value. For standard game rules, set to 6. -rebase_range_multiplier = 6 - -; This option prevents units from loading into two different transports on the same turn. Once a unit has been loaded into a transport, it becomes -; tied to that transport for the remainder of the turn and cannot be loaded into any other. Loading into armies is not affected. The purpose of this -; option is to make the galley chaining exploit impossible. -limit_unit_loading_to_one_transport_per_turn = false - -; In the base game, if you set Cavalry to upgrade to Tank but don't give it the upgrade ability, intending to make Cavalry obsolete when Tanks become -; available but not upgradable to them, you'll be left with the strange situation that older units such as Knights are allowed to upgrade to Tanks -; even though Cavalry are not. This option makes it so that Knights upgrade to Cavalry in that case. In general, it makes it so that upgrade chains -; stop at the type along the chain that does not have the upgrade ability. -; NOTE: The chain is only stopped if the civ in question can build the unit type. The example above is simplified. In the actual rules, Cavalry -; upgrades to Sipahi, which upgrades to Cossack. Blocking the upgrade chain at Cavalry would prevent Ottomans and Russia from upgrading to their -; unique units, so the mod won't do that. You must clear the upgrade ability from Sipahi and Cossack as well to block those civs there instead. -prevent_old_units_from_upgrading_past_ability_block = false - -; Buildings double their culture production this many years after they were built. For standard game rules, set to 1000. -years_to_double_building_culture = 1000 - -; Controls how long it takes for wonders to produce tourism gold as a percent of the standard rate. For example, if set to 200, it would take 2000 -; years to begin generating 2 GPT tourism, instead of the standard 1000 years, and 3000 years for 4 GPT, instead of the standard 1500. This setting is -; effectively a scaling factor on the tourism time thresholds. For standard rules, set to 100. -tourism_time_scale_percent = 100 - -; On the first turn of a hotseat game, all human players will be given diplomatic contact with each other. -introduce_all_human_players_at_start_of_hotseat_game = false - -; Allows units to be unloaded from an army. The army type must have the "unload" ability set in the editor. -allow_unload_from_army = false - -; Allow colonies to be built on tiles inside another civ's territory (for strategic/luxury resources); applies a relation penalty with the other civ, per each colony. -allow_extraterritorial_colonies = false -per_extraterritorial_colony_relation_penalty = 3 - -; A list of rule modifications to make land transports more practical. Works like special_defensive_bombard_rules. The possibilities are: -; load-onto-boat: Allows land transports to be loaded into naval units -; join-army: Allows empty land transports to join armies -; no-defense-from-inside: Prevents units inside a land transport from defending their tile, performing defensive bombard, or intercepting air units -; no-escape: Destroys the passengers inside a land tranport when the transport itself is destroyed or captured -land_transport_rules = [] - -; Prevents land anti-air units from intercepting overflying units while they're loaded in a naval transport -no_land_anti_air_from_inside_naval_transport = false - -; A list of rule modifications for air units with transport capacity called "helicopters" for short. Works like special_defensive_bombard_rules. The -; possibilities are: -; allow-on-carriers: Allows helicopters to be rebased or loaded onto carriers -; passenger-airdrop: Allows paratroopers inside a helicopter on a carrier to perform airdrops -; no-defense-from-inside: Prevents units inside a helicopter from defending their tile, performing defensive bombard, or intercepting air -; units. Also destroys passengers when the helicopter is destroyed in most circumstances in order to avoid problems such as a helicopter being -; captured by a land unit leaving its passengers alive on the same tile. -; no-escape: In all circumstances, destroys the passengers inside a helicopter when the heli itself is destroyed or captured -special_helicopter_rules = [] - -; Stops units from enslaving a target they've destroyed by bombarding as opposed to direct combat -prevent_enslaving_by_bombardment = false - -; Relaxes a rule that prevents resources from appearing directly next to another resource of a different type -allow_adjacent_resources_of_different_types = false - -; Controls the overall number of luxury resources placed on the map for luxury types that don't have a fixed appearance rate set in the editor. Under -; the standard rules, no luxuries have appearance rates set. Without a set rate, the game randomly chooses a rate between 50 and 100, biased toward -; the middle (75). This setting is a percent scaling on that range, so setting it to 150 means luxuries would have their rate randomized between 75 -; and 150, setting to 50 means a range of 25 to 50, and so on. For base game behavior, set to 100. -luxury_randomized_appearance_rate_percent = 100 - -; During map generation, the game places bonus resources until the total number of strategic and bonus resources reaches the tile count divided by -; this number. Raising this setting causes fewer bonus resources to be generated and lowering it increases them. For the standard rate, set to 32. -tiles_per_non_luxury_resource = 32 - -; Normally the corruption rate in the capital is fixed at zero. Setting this to true removes that, allowing corruption to appear in the capital. The -; capital also has a strong inherent bonus reducing corruption so even when this setting is on, it will usually have zero corruption. To reduce that -; bonus, see the special_capital_decorruption_effect option below. -allow_corruption_in_capital = false - -; Controls the special decorruption bonus that's applied to the capital. This bonus is incorporated into the decorrupting effect from buildings in the -; city and each point is equivalent in strength to one courthouse. For standard game rules, set to 10. This option does nothing unless -; allow_corruption_in_capital is set to true. Min value 0, max 100. -special_capital_decorruption_effect = 10 - -; Overrides the NoAIPatrol setting from conquests.ini. Possible values are: -; none: No override, use the setting from the INI like normal -; one: Set NoAIPatrol to 1, disabling AI patrol behavior -; zero: Set NoAIPatrol to 0, allowing AI units to patrol -; The purpose of this option is to enable you to configure NoAIPatrol like a C3X setting instead of globally. In particlar, it allows you to configure -; NoAIPatrol on or off on a per-scenario basis. -override_no_ai_patrol = one - -; Overrides the barbarian activity level when starting a new game for a scenario with a custom map. Normally, in that case, the game will use the -; barbarian settings kept in conquests.ini, ignoring what was set for the map in the editor. This option allows you to set an activity level on a -; per-scenario basis like other C3X settings. -; The possible values are "none" for no override, i.e. base game behavior, or one of the selectable barbarian activity levels: "No Barbarians", -; Sedentary, Roaming, Restless, Raging, or Random. You can specify either the original English names just listed or the custom/translated names in -; labels.txt. The value is not case sensitive. -override_barbarian_activity_level_for_scenario_maps = none - -; Leader units placed on the map as part of a scenario do not have their leader types filled in properly, which means they behave differently than -; proper military leaders would. In particular, they are allowed to hurry production of great wonders and spaceship parts. This option fills in their -; types at the start of the game so they behave like normal MGLs spawned during a game. -initialize_preplaced_scenario_leaders_as_mgls = false - -enable_unit_counters = false - -; Civ 4 style best defender selection. -; When this is on (and enable_unit_counters is also true), every time an attack happens the engine picks the -; defender that is HARDEST for the current attacker to beat (the unit with the highest defender win rate -; once unit-counter rules are applied), instead of the vanilla "highest defense strength" rule. The same -; unit is also forced to the top of the enemy stack on the map whenever a player has an attacker selected, -; so the displayed unit stays in sync with what would actually fight. Re-targeting is automatic: switching -; the selected attacker (different counter match-ups) updates which enemy unit is shown as the best defender. -; Notes: -; - Has no effect when enable_unit_counters = false (then there's nothing to differentiate beyond defense). -; - Applies to both human and AI attackers, so the rule is consistent. -; - Does not change ranged-bombard or defensive-bombard target selection, only normal attacks. -use_civ4_style_best_defender = false - -; unit_group allows you gruop your units in a group,please refer to building_prereqs_for_units for the format. -; This function will not work if enable_unit_counters is false. -unit_group = [] -; ── counter_rule format ────────────────────────────────────────────────────────────── -; -; counter_rule = [Friendly vs Enemy Effect... Conditions...] -; -; 【Friendly / Enemy】 -; This can be one of the following three options: -; · The specific unit type, such as "Archer" (must match the name in BIQ exactly; names containing spaces must be enclosed in quotation marks) -; · A unit group name, such as melee (i.e. the group defined in the unit_group section above) -; · "*" represents any unit type (the asterisk must be enclosed in quotation marks) -; -; 【Effect】(Expressed as a percentage; when multiple rules apply to the same battle, their effects are multiplied.) -; -; "self" always refers to the first unit, and "enemy" always refers to the second unit, regardless of who is attacking whom: -; self-atk value — The unit’s attack power becomes N% of its original value -; Example: self-atk 150 = attack power ×1.5; self-atk 50 = attack power ×0.5 -; self-def value — Your defence becomes N% of the original value; -; enemy-atk value — The enemy’s attack becomes N% of the original value; -; enemy-def value — The enemy’s defence becomes N% of the original value; -; -; 【Conditions】(Optional; leaving blank indicates no restrictions; conditions take effect only when all are met simultaneously) -; in-city —— Takes effect only when the enemy is on a city tile -; terrain terrain_name -- Takes effect only when the enemy is on a tile of the specified terrain -; Uses the same lower-case English terrain tokens as districts_config buildable_on, not BIQ/localized names. -; Examples: grassland, hills, coast, snow-forest, snow-mountain, snow-volcano, lake -; ignore-terrain —— Ignores the enemy’s terrain defence bonus (sets their terrain bonus to zero) -; Can be used in conjunction with enemy-def; when used together, ignore-terrain takes precedence -; district district_name -- Only takes effect when the enemy is in a specified district (enable_districts must be enabled) -; District names are resolved after districts_config loads, so dynamic district names are supported. -; -; 【Examples】 -; counter_rule = [ranged vs melee self-atk 125] -; → When a ranged unit attacks a melee unit, its attack power is multiplied by 1.25 -; -; counter_rule = ["Knight" vs melee in-city enemy-def 150] -; → When knights attack melee units within a city, the enemy’s defence is multiplied by 1.5 -; -; counter_rule = ["Musketman" vs "Medival Infantry" terrain grassland self-atk 125] -; → When musketeers attack medieval infantry on grassland terrain, their attack power is multiplied by 1.25 -; -; counter_rule = ["Knight" vs "*" ignore-terrain self-atk 150] -; → When a Knight attacks any unit, its attack power is multiplied by 1.5 and it ignores the enemy’s terrain bonus. -; counter_rule = [Archer vs Swordsman self-atk 130 self-def 120] -; → When an archer attacks a swordsman: Archer’s attack power ×130% -; When a swordsman attacks an archer: Archer’s defence ×120% -; -; ───────────────────────────────────────────────────────────────────────────── - -counter_rule = [] - -[==================] -[=== AESTHETICS ===] -[==================] - -; If a tile has a forest, render it on top of roads and railroads, instead of underneath them. -draw_forests_over_roads_and_railroads = true - -; This allows you to set a victory animation for air units. Can be set to the name of any animation that is loaded by the game, specifically one of: -; blank, default, run, attack1, attack2, attack3, death, fortify, fidget, victory, capture, fortress, build, road, mine, irrigate, jungle, forest, plant -; Note that bomber units already have their bombing animations in the victory slot so "victory" is not a good choice here. For standard game behavior, -; set to "none". -aircraft_victory_animation = none - -; Enables naming tiles via the right-click menu and displays those names on the map. -enable_named_tiles = true - -[=======================] -[=== DAY/NIGHT CYCLE ===] -[=======================] - -; How the day/night cycle operates in the game. If enabled, terrain, cities, resources, landmarks and terrain buildings will change appearance based on -; the time of day, with 24 possible stages (one for each hour). The base game art is used for 12pm. If set to 'off', only base game art will be used. -; Day/night cycle should not be used if you are using non-standard terrain art or resources. Doing so may result in visual glitches or missing art. -; Note that day/night cycle art is not bundled directly with C3X and must be downloaded separately at https://forums.civfanatics.com/resources/day-night-cycle-in-civ-3-using-c3x.32520/ -; The possible values are: -; off: Only base game art used -; timer: Increment based on time elapsed since last hour transition (e.g., transition to next hour every 3 minutes) -; user-time: Match the user's system clock to determine hour of the day -; every-turn: Increment every turn by a fixed amount of hours -; specified: Pin the hour to a specific value (so hour of day is always the same) -day_night_cycle_mode = off - -; If day_night_cycle_mode is set to 'timer', minimum minutes of real time to elapse before transitioning to the next hour in the cycle. -; This is checked only at the end of the turn, so actual minutes may exceed this number. -elapsed_minutes_per_day_night_hour_transition = 3 - -; If day_night_cycle_mode is set to 'timer' or 'every-turn', the number of hours to transition. This should be a value between 1 and 12 inclusive. -fixed_hours_per_turn_for_day_night_cycle = 1 - -; If day_night_cycle_mode is set to 'specified', the hour of the day to pin the cycle to. This should be a value between 0 (midnight) and 23 (11pm) inclusive. -pinned_hour_for_day_night_cycle = 0 - -[=======================] -[=== NATURAL WONDERS ===] -[=======================] - -; Show or hide natural wonders on the map. When disabled, natural wonders will not appear on the map. -enable_natural_wonders = true - -; If a new scenario is loaded which has no natural wonders defined, add natural wonders. -add_natural_wonders_to_scenarios_if_none = false - -; Show the names of natural wonders on the map below their image. -show_natural_wonder_name_on_map = true - -; Minimum separation (in tiles) between natural wonders when generating the map. This helps prevent clustering of natural wonders. -minimum_natural_wonder_separation = 10 - -[=================] -[=== DISTRICTS ===] -[=================] - -; Districts are Civ6-inspired structures built by workers that enable buildings, provide bonuses, and make cities feel more alive. When enabled, -; districts appear on the map and can be required for certain buildings (configured in default.districts_config.txt). Districts occupy tiles within a -; city's work radius, making those tiles unworkable. They can provide bonuses (food, shields, gold, science, culture, defense) to all cities within -; their work radius. If multiple cities share a district, they can optionally share its buildings and wonders (see options below). Districts with -; pollution or enemy units yield no bonuses. Destroyed districts remove dependent buildings from affected cities unless they have another district of -; that type in range. The five district types below can be enabled independently: -; enable_districts: Enables standard configurable districts (by default: Encampment, Campus, Holy Site, Commercial Hub, Entertainment Complex, Industrial Zone). -; Configured is done in default.districts_config.txt, user.districts_config.txt, and scenario.districts_config.txt -; enable_neighborhood_districts: Enables population growth past a configurable limit (see maximum_pop_before_neighborhood_needed below) -; enable_wonder_districts: Wonders require a dedicated district tile, making them visible on the map and optionally destructible. -; Configured in default.districts_wonders_config.txt, user.districts_wonders_config.txt, and scenario.districts_wonders_config.txt -; enable_distribution_hub_districts: Special districts that distribute food/shields from surrounding tiles to all connected cities -; enable_aerodrome_districts: Air units can only be built/based at Aerodrome districts instead of cities (if air_units_use_aerodrome_districts_not_cities is true) -; enable_port_districts: Enables Port districts, which serve as coastal district tiles for naval production/basing when naval_units_use_port_districts_not_cities is on. -; enable_bridge_districts: Enables Bridge districts on coastal water; completed bridges let land units cross water tiles. -; enable_canal_districts: Enables Canal districts on land; completed canals let naval units traverse land tiles between water bodies. -; enable_central_rail_hub_districts: Enables Central Rail Hub districts used for rail-era infrastructure (e.g., Mass Transit). -; enable_energy_grid_districts: Enables Energy Grid districts associated with power plant infrastructure. -; enable_great_wall_districts: Enables Great Wall districts (wall-like tiles that can block others if great_wall_districts_impassible_by_others is on). -enable_districts = false -enable_neighborhood_districts = false -enable_wonder_districts = false -enable_distribution_hub_districts = false -enable_aerodrome_districts = false -enable_port_districts = false -enable_bridge_districts = false -enable_canal_districts = false -enable_central_rail_hub_districts = false -enable_energy_grid_districts = false -enable_great_wall_districts = false - -; When multiple cities share a district (i.e., the same district tile is within multiple cities' work radii), these options control whether those -; cities automatically share the benefits of buildings and wonders constructed in that district. For example, if Rome and Veii both have the same -; Encampment in their work radius and Rome builds a Barracks in that Encampment, enabling cities_with_mutual_district_receive_buildings will cause -; Veii to automatically receive a Barracks as well. Similarly, cities_with_mutual_district_receive_wonders extends this sharing to Great and Small -; Wonders. This encourages strategic district placement between cities and can reduce micromanagement in dense urban areas. -; Note: receiving buildings is only assessed twice: when a city completes a building, and when a city is founded nearby. A city receiving a building -; cannot in turn recursively share it with third, fourth, fifth, etc. cities in a chain. Only applies if enable_districts is set to true. -cities_with_mutual_district_receive_buildings = true -cities_with_mutual_district_receive_wonders = true -show_message_when_building_received_by_mutual_district = true -show_message_when_building_lost_to_destroyed_district = true - -; When enabled, air units can only be built in cities with an Aerodrome district in their work radius and must be based at Aerodrome districts instead -; of cities. Air units will spawn on Aerodromes and can only land on Aerodromes, vanilla airfields, or carriers. Airlifts and airdrops are similarly -; limited to Aerodromes. This adds strategic depth by requiring infrastructure for air power and making air bases visible and vulnerable on the map. -; Only applies when enable_aerodrome_districts is also set to true. -air_units_use_aerodrome_districts_not_cities = true - -; When enabled, naval units can only be built in cities with a Port district in their work radius and cannot enter city tiles directly. Naval unit -; healing must be done at Port districts, and travel between continents, lakes and so on can instead only be done via Canal districts (via enable_canal_districts), -; rather than cities on an isthmus. Additionally, a city cannot build naval units until it has a Port district in range. Only applies when enable_port_districts is set to true. -naval_units_use_port_districts_not_cities = true - -; Neighborhood district limit population growth. Once a city reaches maximum_pop_before_neighborhood_needed, it cannot -; grow further until it has at least one Neighborhood district in its work radius. Each Neighborhood then enables additional population growth equal to -; per_neighborhood_pop_growth_enabled. For example, with maximum set to 6 and per_neighborhood set to 2, a city can grow to pop 6 without -; Neighborhoods, requires 1 Neighborhood to reach pop 8, requires 2 Neighborhoods to reach pop 10, and so on. Neighborhood bonuses (+1 gold and +1 -; culture, by default) only apply if the city actually needs them based on its population. Periodic popups will remind you when a Neighborhood is needed. Only -; applies when enable_neighborhood_districts is set to true. neighborhood_needed_message_frequency sets how often (in turns) the reminder message appears; -; set to 0 to disable. -; If destroying_neighborhood_reduces_pop is true, losing a Neighborhood district reduces the city's population down to the new cap. -maximum_pop_before_neighborhood_needed = 6 -per_neighborhood_pop_growth_enabled = 3 -neighborhood_needed_message_frequency = 4 -destroying_neighborhood_reduces_pop = true - -; These options control the vulnerability and rebuildability of completed Wonders in Wonder districts. When completed_wonder_districts_can_be_destroyed -; is enabled, completed Wonders (both Great and Small) can be pillaged or destroyed by enemies, making them valuable strategic targets that must be -; defended. When destroyed_wonders_can_be_built_again is enabled, destroyed Wonders become available again for any civ to build, putting them back -; into play. Only applies when enable_wonder_districts is set to true. -completed_wonder_districts_can_be_destroyed = true -destroyed_wonders_can_be_built_again = true - -; Distribution Hubs work as "breadbaskets" and mining areas far from urban centers, minimizing local city potential but benefiting the entire civilization. -; Distribution Hubs make surrounding tiles unworkable and instead distribute their raw food and shield yields to ALL connected cities in your civilization. -; "Divisors" for food and shields multiply the sqrt-based divisor in scale-by-city-count mode, and are a straight divider in flat mode. Yields are subject -; to corruption as with regular shields. -; -; ai_ideal_distribution_hub_count_per_100_cities controls how many hubs the AI tries to maintain per 100 cities if distribution_hub_yield_division_mode -; is set to "flat" (e.g., 25 means the AI aims for 1 hub per 4 cities). -; -; distribution_hub_yield_division_mode controls how a hub splits its collected food/shields across connected cities: -; flat: Divide raw yields by the configured divisors (distribution_hub_food_yield_divisor & distribution_hub_shield_yield_divisor) -; scale-by-city-count: Bonuses gradually reduce as more cities plug into the hub. Formula: floor(raw_yield / (sqrt(connected_city_count) * divisor)) -; -; ai_distribution_hub_build_strategy controls how the AI decides to build distribution hubs: -; by-city-count: AI builds hubs based on its ideal hub count per 100 cities -; auto: AI dynamically assesses need based on city growth and food/shield deficits across civ -distribution_hub_yield_division_mode = scale-by-city-count -ai_distribution_hub_build_strategy = auto -distribution_hub_food_yield_divisor = 2 -distribution_hub_shield_yield_divisor = 2 -ai_ideal_distribution_hub_count_per_100_cities = 50 -max_distribution_hub_count_per_100_cities = 50 - -; Bonus percent applied to Distribution Hub food and shield yields for cities that have a Central Rail Hub district in their work radius. -central_rail_hub_distribution_food_bonus_percent = 25 -central_rail_hub_distribution_shield_bonus_percent = 25 - -; District placement and AI bridge/canal behavior: -; expand_water_tile_checks_to_city_work_area: Use the full city work radius (not just adjacent tiles) for river/lake/sea checks (e.g. to build a port if a -; city has coast within its work area, even if not adjacent to the sea). -; Note that this does not affect Aqueducts or Coastal Fortresses, which still require direct city adjacency. -; workers_can_enter_coast: Allow workers to move onto coast tiles without embarking. -; max_contiguous_bridge_districts: Maximum number of contiguous bridge district tiles allowed in a line (0 = no limit). -; max_contiguous_canal_districts: Maximum number of contiguous canal district tiles allowed in a line (0 = no limit). -; ai_canal_eval_min_bisected_land_tiles: Minimum land tiles required on each side for the AI to consider a canal candidate. -; ai_bridge_canal_eval_block_size: Map block size used when scanning for AI bridge/canal candidates. -; ai_bridge_eval_lake_tile_threshold: Water bodies at or below this size are treated as lakes for AI bridge evaluation. -; ai_can_replace_existing_districts_with_canals: Allow the AI to build canal/bridge districts over existing non-wonder districts. -; ai_builds_bridges: Allow the AI to construct bridge districts. -; ai_builds_canals: Allow the AI to construct canal districts. -expand_water_tile_checks_to_city_work_area = true -workers_can_enter_coast = true -max_contiguous_bridge_districts = 3 -max_contiguous_canal_districts = 5 -ai_canal_eval_min_bisected_land_tiles = 20 -ai_bridge_canal_eval_block_size = 10 -ai_bridge_eval_lake_tile_threshold = 5 -ai_can_replace_existing_districts_with_canals = true -ai_builds_bridges = true -ai_builds_canals = true - -; When enabled, AI defensive units will actively seek out and defend districts within their territory, treating them as valuable assets like colonies. -; The AI prioritizes defending Wonder districts (if destructible wonders are enabled) over regular districts, searching within a 20-tile radius for -; districts that need protection from nearby enemy units. This makes districts meaningful strategic targets and ensures the AI protects its -; infrastructure. Only applies when enable_districts is set to true. -ai_defends_districts = true - -; As AI cities queue up districts needed, the max number of turns to wait for a worker to build it before the request is dropped -; until the AI city is triggered to build the district again (e.g., by trying to build a building that depends on it) -ai_city_district_max_build_wait_turns = 20 - -; Great Wall behavior: -; disable_great_wall_city_defense_bonus: Disables the Great Wall wonder's city defense doubling effect. Only takes effect if districts and great wall districts are enabled. -; great_wall_districts_impassible_by_others: Great Wall district tiles block movement by other civs (unless obsolete). -; auto_build_great_wall_around_territory: Auto-place Great Wall districts along your borders when the specified wonder is built. -; great_wall_auto_build_wonder_name: Name of the wonder that triggers auto-building (empty disables auto-build). -; ai_auto_build_great_wall_strategy: How AI uses auto-built Great Wall: all-borders (any border tiles) or other-civ-bordered-only (only borders touching another civ). -disable_great_wall_city_defense_bonus = false -great_wall_districts_impassible_by_others = true -auto_build_great_wall_around_territory = true -great_wall_auto_build_wonder_name = "The Great Wall" -ai_auto_build_great_wall_strategy = other-civ-bordered-only - -; When enabled, holding down the Control key while a worker is selected will highlight all tiles within the work radii of nearby cities. City centers -; are highlighted more brightly, while tiles that fall within multiple cities' work radii are highlighted more intensely. This visual aid helps you -; strategically place districts and improvements by showing which cities will be affected. The highlights update dynamically as you move the worker -; around the map. Only applies when enable_districts is set to true. -enable_city_work_radii_highlights = true +[====================================================== C3X RELEASE 27 PREVIEW 2 DEFAULT CONFIG =====================================================] +[======================================================================= NOTE =======================================================================] +[Instead of editing this file, changes to the settings should be placed in either the scenario or custom config files. The scenario config file must ] +[be named scenario.c3x_config.ini and must be located in your scenario search folder. Of course it only applies if you are using a scenario. The ] +[custom config file must be named custom.c3x_config.ini and located in the C3X folder, which is the folder where this file is. When creating scenario] +[or custom configs, it is only necessary to include the settings you wish to change. ] +[====================================================================================================================================================] + +[============================] +[=== CONVENIENCE FEATURES ===] +[============================] + +enable_stack_bombard = true +enable_stack_unit_commands = true +enable_disorder_warning = true +show_detailed_city_production_info = true +enable_trade_screen_scroll = true +autofill_best_gold_amount_when_trading = true +skip_repeated_tile_improv_replacement_asks = true +group_units_on_right_click_menu = true + +; On the right click menu, units with no remaining moves will appear in gray text +gray_out_units_on_menu_with_no_remaining_moves = true + +; Places an icon next to units on the right-click menu showing their remaining moves & status. The icon is green for unmoved units, red for units that +; have exhausted all their moves, and yellow for those in between. Additionally it contains a little sword for units that can still attack and is +; colored blue for fighters set to intercept. +put_movement_icons_on_units_on_menu = true + +; Replaces the "Wake" or "Activate" text on the right-click menu with more descriptive words indicating what the unit is currently doing. For example, +; "Moving", "Intercepting", or "Working". +describe_states_of_units_on_menu = true + +show_detailed_tile_info = true +show_golden_age_turns_remaining = true + +; This option causes the game to show attack animations for units exerting zone of control from the middle of their tile's stack. Otherwise the game +; will only show such animations for units that are the top visible unit on their tiles. It was presumably an oversight by the original developers +; that units exerting zone of control do not temporarily become the visible unit on their tiles (unlike, for example, defensive bombard). +show_zoc_attacks_from_mid_stack = true + +; Fixes the defensive bombard animation being skipped when the unit performing defensive bombard is inside an army. +show_armies_performing_defensive_bombard = true + +cut_research_spending_to_avoid_bankruptcy = true +dont_pause_for_love_the_king_messages = true + +; Holding shift when clicking a specialist on the city screen will switch to the previous, instead of the next, specialist type +reverse_specialist_order_with_shift = true + +; Pressing the Z key on the city screen will zoom the map in/out +toggle_zoom_with_z_on_city_screen = true + +; When king units are spawned they're named after the leader of their civ. This is undesirable in modded games where the king flag is often used +; on units that aren't intended to be actual kings. This setting helps by bypassing the king unit naming logic when regicide is not enabled. +dont_give_king_names_in_non_regicide_games = true + +; One of the game's "Easter eggs" is that all king-flagged units appear as Elvis Presley on his birthday (Jan 8). This can be annoying when playing +; mods that make wide use of the king flag. +no_elvis_easter_egg = false + +; Removes option to automate workers from the human player. Useful for those who never want to use automation but sometimes accidentally activate it. +disable_worker_automation = false + +; There is a limit to how many links can appear on each Civilopedia page. Some mods exceed that limit. The problem is that the game throws up a popup +; when the limit is exceeded, one popup for each link beyond the limit. That can result in dozens of annoying, useless popups. This option stops them +; from appearing. Note: the game may also crash if the number of links far exceeds the limit. This option does not stop the crash, just the popups. +suppress_hypertext_links_exceeded_popup = true + +; Replaces the text "Upgrades To" with "Obsoleted By" in the Civilopedia for unit types that go obsolete but cannot be upgraded to their successors. +indicate_non_upgradability_in_pedia = true + +; Shows a message when a bomber gets intercepted by enemy air defense buildings but succeedes on its roll to avoid damage. Without this message, there +; is no indication that anything happened in that case except for the bomber losing one movement point. +show_message_after_dodging_sam = true + +; Normally only the last human player in a hotseat game gets to see the AIs move their units since the game processes the interturn while that player +; is still seated. This setting shows the AI moves to the other players in the game. It works by creating a save just before the interturn processing +; happens and then, at the start of the other players' turns, loads the save, sets that player as the seated one, reprocesses the interturn, then +; resumes the original game. +; Note: If the game is manually saved and reloaded, the replay will be lost. So it is recommended to save the game only after all human players have +; seen the replay, i.e. during the last or second to last human players' turns. +replay_ai_moves_in_hotseat_games = false + +; Normally, when you load a save, all units face southeast because the game didn't record which direction they were facing when the save was +; created. However, the game does record which tile they were on before their most recent move, so it is possible to deduce which direction they +; should be facing. That's what this option does. +restore_unit_directions_on_game_load = true + +; The game stores your map grid setting (on or off) in conquests.ini. It applies that setting after creating a new game, but not after loading a +; save. That was presumably an oversight and is corrected by this config option. +apply_grid_ini_setting_on_game_load = true + +; Causes cities to display harbor/airport icons if they have buildings that grant the relevant unit effects (produce veterans & heal in one turn) +; instead of buildings that grant sea/air trade. This makes no difference under the standard rules but is useful with mods that separate the unit +; effects and trade abilities into different buildings. +city_icons_show_unit_effects_not_trade = true + +; The game rules do not permit aircraft in an airfield to be damaged by bombardment. The interface allows players to order such bombardments anyway +; since its logic to check target validity is incomplete. This option completes the logic, causing the interface to reject attempts to bombard an +; airfield which would have no effect. +disallow_useless_bombard_vs_airfields = true + +; This option fixes a graphical bug that appears when the game is run on Linux using Wine. The bug is caused by the game using both Windows GDI and +; OpenGL to draw to the same canvas. Because the game only uses OpenGL to draw lines, it's relatively easy to solve this issue by reimplementing line +; drawing using Windows GDI+ instead. There are three possible settings for this option: +; never: Self-explanatory +; wine: This change will only be applied if the mod detects the game is running on Wine +; always: This change will always be applied, even on an actual Windows system +draw_lines_using_gdi_plus = wine + +; This option reduces the vertical distance between rows in the list of luxuries on the city screen. This allows up to 11 luxuries to be displayed +; neatly inside the box. +compact_luxury_display_on_city_screen = false + +; Similar to the option above, this one packs the strategic resources more tightly into the box on the upper left of the city screen. This allows up +; to 13 resources to be displayed there. +compact_strategic_resource_display_on_city_screen = false + +; Causes the domestic advisor to ask for confirmation before setting city production to a building that would replace another already built in the +; city. It's similar to how the domestic advisor warns you before a production switch would waste shields. Useful for modded games where you might not +; know which buildings replace which. +warn_when_chosen_building_would_replace_another = false + +; This option keeps citizens working the tiles they've been assigned to when pollution spawns there instead of converting them to specialists. This +; reduces micromanage but comes at the cost of the specialist yields. +do_not_unassign_workers_from_polluted_tiles = false + +; Normally the game draws capital cities one level larger than normal. I.e., a capital city at size 1 - 6 uses the graphic for cities at size 7 - 12, +; and a capital at size 7+ uses the graphic for cities 13+. This option turns that off, so capitals use the standard city graphics. +do_not_make_capital_cities_appear_larger = false + +; Tints coast and sea tiles on the minimap based on the culture that controls them, like is normally done for land tiles. +show_territory_colors_on_water_tiles_in_minimap = false + +; In offline games, shows some popup messages as online-multiplayer-style notes to the left of the screen instead of advisor popups that pause +; gameplay until dismissed. The point is to minimize interruptions during turn processing. Affects popups with the following text keys: +; SUMMARY_END_GOLDEN_AGE, SUMMARY_END_SCIENCE_AGE, SUMMARY_NEW_SMALL_WONDER, WONDERPRODUCE, MAKEPEACE, MUTUALPROTECTIONPACT, MILITARYALLIANCE, +; SUMMARY_DECLARE_WAR, TRADEEMBARGOENDS, SUMMARY_CIV_DESTROYED_BY_CIV, SUMMARY_CIV_DESTROYED, LOSTGOOD, TRADEEMBARGO, MILITARYALLIANCEWARONUS, +; MILITARYALLIANCEAGAINSTUS, and SUMMARY_TRAVELERS_REPORT. +convert_some_popups_into_online_mp_messages = false + +; If enabled, pressing the keys d e b u g to type "debug", in-game will allow you to activate debug mode for a game in progress. Typing that with +; debug mode already on will deactivate it. +enable_debug_mode_switch = true + +; Places a small shadow below city dots on the minimap to make them more easily visible especially against light-colored territory. This feature does +; not quite work properly so is left off by default. Its issues are (1) the shadows may not fully appear until you toggle the minimap from territory +; to geography mode and back again and (2) the shadows may appear in geography mode. +accentuate_cities_on_minimap = false + +; Makes the minimap twice as large. Possible values are "never", "always", and "high-def". The first two are self-explanatory; if set to "high-def", +; the minimap's size will be doubled when the game is run at a horizontal resolution of at least 1920 pixels. +double_minimap_size = high-def + +; Allows descriptions for units, civilizations, and game concepts to span multiple pages. If a DESC entry of one of those types is too long for one +; page, it will automatically be divided into multiple with buttons added for navigation. +allow_multipage_civilopedia_descriptions = true + +; Controls how the game searches for the next unit to autoselect. The possible choices are: +; standard: Base game behavior +; similar-near-start: The game will search for similar units near the starting point of the last selected unit. That means, when a unit is selected, +; the game remembers its location then searches out from there for a similar unit when cycling to the next one. Distance is prioritized over +; similarity, meaning the game will select all units on the starting tile no matter how dissimilar before any on nearby tiles. +; similar-near-destination: Like similar-near-start except the search goes outward from whatever tile the last selected unit was last on. +unit_cycle_search_criteria = standard + +; On the domestic advisor screen, tweaks how the number of turns remaining on each city build are displayed to improve readability. Instead of +; "(1turn)" or "(7turns)", the game will display "(1 Turn)" or "(7 Turns)" +reformat_turns_remaining_on_domestic_advisor_screen = true + +; On unit Civilopedia pages, shows the movement stat for aircraft, bombard range for tactical nukes, and HP bonus & worker strength if non-zero. +expand_civilopedia_unit_stats = true + +[====================] +[=== OPTIMIZATION ===] +[====================] + +; Rewrites the game's trade network computation logic to improve speed. On large maps with many cities, this computation takes up most of the +; interturn time so speeding it up greatly improves turn times. For more info, see the text file in the Trade Net X folder. +enable_trade_net_x = true + +; Rewrites parts of the game logic to improve efficiency. Those parts check every possible improvement defined in the scenario when they really only +; need to check a few. For example, to determine whether a city can trade via air, it's very wasteful to check every improvement since the vast +; majority of them do not enable air trade. This option can improve turn times very significantly in some circumstances. +optimize_improvement_loops = true + +; Displays a popup after each turn has been processed showing the time elapsed, including specifically how much time was spent recomputing trade +; networks. NOTE: Turning this on will skip all animations during the interturn so they don't contribute to the time. You aren't meant to play the +; game with this option left on. +measure_turn_times = false + +[=======================] +[=== AI ENHANCEMENTS ===] +[=======================] + +; Allows artillery unit AI to grab escorts from city defenders, causing the AI to use its artillery offensively instead of leaving it in its cities. +use_offensive_artillery_ai = true + +; If true, the AI will not escort its units unless they have the "requires escort" flag set in the editor. This allows modders to remove the escort +; requirement from certain types of units, for example artillery with non-zero defense. +dont_escort_unflagged_units = false + +; Set to a number to encourage the AI to build more artillery, set to false or <= 0 for no change in AI unit build choices. The number is how many +; artillery units the AI will try to keep around for every 100 non-artillery combat land units it has. The encouragement only applies if the AI is +; already above a minimum of one defensive unit per city and one offensive unit per two cities. Default: 16. +ai_build_artillery_ratio = 16 + +; The above option controls how many artillery the AI will keep around, this one controls how aggressively it builds up to that limit. More +; specifically it controls how valuable (in percent) the AI thinks artillery is as a damage dealer compared to attacking units. Default: 50. +ai_artillery_value_damage_percent = 50 + +; Like the artillery ratio, shifts the AI's build priority from fighters to bombers to keep around this many bombers per 100 fighters. Default: 70. +ai_build_bomber_ratio = 70 + +; Completely replaces the leader unit AI with custom code. The custom version is similar in spirit to the original but fixes several major issues: +; 1. It fixes a bug that allowed the AI to rush any kind of city production, including units and (with an MGL) wonders +; 2. Prioritizes army formation over rushing production when appropriate +; 3. When rushing, prioritizes wonders and costly improvements in high value cities +replace_leader_unit_ai = true + +; Replaces the AI code that determines whether a unit would be a good addition to an army. The replacement code fixes a major bug that prevented the +; AI from filling its armies, prevents the AI from including hidden nationality units in armies to avoid crashes, and removes some logic that +; encouraged the AI to mix unit types in armies. +fix_ai_army_composition = true + +; "Pop units" are special units whose only purpose is to be joined into cities to increase their population. Normally the AI does not know what to do +; with these units, so this option enables a routine that causes them to search for & join an appropriate city. Pop units only appear in some mods +; (for example Tides of Crimson). Under the standard game rules, this option has no effect. In order to function as a pop unit, a unit must use the +; terraform AI strategy, have no worker actions except join city, have a pop cost of at least 1, and have zero attack, defense, & bombard strengths. +enable_pop_unit_ai = true + +; "Caravan units" are special units whose only purpose is to be disbanded to contribute shields to a city. The name comes from the Civ 2 caravan. +; Caravan units may appear in some mods; under the standard game rules, this option has no effect. In order to function as a caravan unit, a unit must +; use the terraform AI strategy, have no worker actions enabled, have the ability to disband, and have zero attack, defense, & bombard strengths. +enable_caravan_unit_ai = true + +; In the base game, the AI will assign 1, 2, or 3 escort units to its naval transports and carriers depending in their shield cost and the number of +; units they're carrying. This option lets you reduce the upper limit on the number of escorts assigned. You can limit the number of escorts to 2, 1, +; or even 0. Setting this option >= 3 will result in base game behavior. The purpose of reducing the limit is to free up the AI's naval power units. +max_ai_naval_escorts = 3 + +; This controls how many workers the AI feels it needs as a percentage of the base amount. For example, if set to 150 (the default), the AI will build +; about 50% more workers than normal. Set to 100 for base game behavior. For more info, see: +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-95#post-16587093 +ai_worker_requirement_percent = 150 + +[=================] +[=== BUG FIXES ===] +[=================] + +; Descriptions of bugs and their fixes: +; SUBMARINE BUG -- The AI runs into invisible units (such as submarines) belonging to other players because it blindly follows paths produced for +; it by the game's pathfinder, which does not see invisible units. After colliding with an invisible unit, the AI initiates combat, declaring war if +; necessary. The mod fixes this bug by modifying the pathfinder so it sees invisible units belonging to other non-hostile players so it can route +; around them. +; SCIENCE AGE BUG -- The bonus science points generated by a scientific golden age are not actually counted towards research progress. They appear +; only on the interface. This is because of a small oversight in the code. There is a setting which controls whether or not science age bonus points +; are included while gathering all research points. It's turned off while gathering points to update research progress. The fix is to turn it on. +; PEDIA TEXTURE BUG -- There is a one pixel wide pink line on the right edge of the Civilopedia screen. This is because the width of the +; Civilopedia background texture is set one pixel too small inside the EXE. This is fixed simply by replacing the width with the correct value. +; BLOCKED DISEMBARK FREEZE -- When using "disembark all" (which the AI always does) on a boat containing units that can't be disembarked, the game +; may freeze as it endlessly tries to disembark them. The root of the problem is that the game's logic to check if there are any disembarkable units +; left on the boat is incomplete. There are two cases that it misses. First, it does not consider the "immobile" unit flag. This is fixed by making +; immobile units appear to have no remaining movement points for this bit of logic so they are correctly considered non-disembarkable. Second, it does +; not consider escort relationships (e.g. for settlers). If a unit has a non-disembarkable escorter then it also can't be disembarked because the game +; will always try to move its escorter ahead of it. The solution here is to clear all escort relationships for ship passengers before disembarking. +; HOUSEBOAT BUG -- The game may crash when an AI player is left alive with only a settler on a boat. This happens because the AI's logic tries to +; check the location of its capital city without considering that there may be no capital. The fix is to modify this logic so that when it looks up +; the location of a non-existent capital, it receives a valid "dummy" location that it can process without crashing. See also: +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16084386 +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-10#post-16085242 +; INTERCEPT LOST TURN BUG -- When a human player sets a fighter to intercept mode, the game discards all of its remaining movement points, hence it +; cannot intercept during the next interturn. This bug does not affect the AI and is part of the interface logic, not the game logic. I presume it was +; inserted by a programmer who did not understand how the game's unit cycling works. The fix simply restores fighters' discarded moves. +; PHANTOM RESOURCE BUG -- The game only stores one full list of available resources per player. That list contains how many sources of each +; resource type are avaiable in that player's capital and all connected cities. Cities off the capital's network have reduced lists of just 32 bits, +; recording yes-or-no availability for up to 32 resources. Resources beyond the first 32 will share bits in those reduced lists. Specifically, the +; 33rd resource shares the same bit as the 1st, the 34th the same as the 2nd, and so forth. This causes "phantom" resources. For example, if a mod has +; horses set as the 1st resource and steel as the 33rd, then any city off its capital's trade network with access to horses will also have access to +; steel and vice-versa. The fix for this issue is straight forward but not simple. The jist is the mod allocates additional space for the reduced +; lists so they're not limited to 32 bits, rather have enough bits for every resource in the game. After that it's necessary to modify the code that +; accesses the reduced lists so it can make use of the additional space. +; MAINTENANCE PERSISTING FOR OBSOLETE BUILDINGS -- Players are not supposed to pay maintenance for obsolete city improvements however they often do +; because the game does not recompute maintenance after a player unlocks a technology that obsoletes a city improvement. There is a related exploit in +; that, after triggering a recomputation of maintenance, players can then sell their obsolete buildings to have the maintenance deducted again, +; effectively getting credited for the cost of maintenance. The mod fixes both issues. It recomputes maintenance costs when a player unlocks a +; technology that obsoletes a city improvement and it stops the game from deducting the maintenance cost of an obsolete city imp. when it's sold. +; BARBARIAN DIAGONAL BUG -- Barbarians can only search for targets on adjacent tiles or on tiles that are up to 12 steps directly SE or NW of their +; position. The intended behavior was for them to search for targets on all surrounding tiles up to 6 steps away. This bug was caused by a small, +; sloppy programming mistake that can be corrected with a small edit. For details, see: +; https://forums.civfanatics.com/threads/c3x-exe-mod-including-bug-fixes-stack-bombard-and-much-more.666881/page-70#post-16434678 +; DISEASE CURING TECH FLAG BUG -- In the base game, the tech flag "Disables Diseases From Flood Plains" (applied to Sanitation) does nothing and +; instead flood plains disease stops once players discover Writing. This happens because that flag is encoded as number 8 and, instead of checking if +; players have a tech with that flag, the code mistakenly checks if players have tech #8, which is Writing under the standard rules. Correcting this +; bug causes a lot more disease, which is a major annoyance, and so this bug fix is turned off by default. +; DIVISION BY ZERO IN AI ALLIANCE EVAL -- When considering whether to agree to a military alliance, the AI computes the distance from its capital to +; the nearest city belonging to the target of the alliance and divides by that distance. For unknown reasons, in rare cases that distance may be zero, +; which crashes the program due to division by zero. The mod fixes this issue by inserting a bit of logic after the distance is computed to check if +; it's zero and, if so, set it to one. +; EMPTY ARMY MOVEMENT -- Empty armies have one less than a full move's worth of movement points regardless of how many moves their unit type has set +; in the editor. Under the standard game rules, this means they can only move two tiles along roads. The cause is a small mistake in the logic that +; attempts to find the slowest member among units in the army. The mod fixes this bug by reimplementing the max movement point calculation for armies. +; PREMATURE TRUNCATION OF FOUND PATHS -- If the game attempts to find a path for a unit that's more than 256 tiles long, the path will not be +; returned properly from the pathfinder. That's because the pathfinder stops reconstructing the final path once it reaches a length of 256. That +; creates a serious problem for long paths because reconstruction works from the end of the path toward the start, so stopping early produces an +; incorrect path that begins in the middle. The fix is simply to multiply the maximum length by 10 (to 2560). Removing the limit entirely risks +; allowing infinite loops. This bug is rarely visible in-game, it usually appears as AI naval units following inappropriate or invalid paths. +; ZERO PRODUCTION CRASH -- If a city has zero production, which is possible using specialists modded to produce negative shields, the game will +; crash due to a division by zero. +; AI CAN SACRIFICE WITHOUT SPECIAL ABILITY -- The base game function that gates the AI's ability to sacrifice units does not check whether the unit +; in question has the sacrifice special ability set on its type. Thus, AIs are allowed to sacrifice any captured units as long as they have the +; required tech. The mod fixes this by patching the gating function to insert the missing condition. +; AI CAN FORM ARMY WITHOUT SPECIAL ABILITY -- Similar to the above issue, the AI's ability to form armies with leader units is not gated by those +; units having the "build army" special ability. +; CRASH IN LEADER UNIT AI -- The base game's AI routine for leader units may crash due to uninitialized variables. +; FAILURE TO FIND NEW CITY BUILD -- After a city completes production, the game searches for a new build for it. If that city is owned by the seated +; player, whatever the game finds will be filled in as the default option in the domestic advisor popup asking the player to choose a new build. If +; the search fails to find anything, there will be no default option, the dropdown selector will not be initialized, and the game will crash when it +; tries to open the popup. To fix this, the mod detects when the game has failed to find a new build option and fills in Wealth instead or, failing +; that, any unit or improvement that the city can build. +; PASSENGERS OUT OF ORDER ON MENU -- When there are multiple doubly-contained units (meaning units contained in other units that are themselves +; contained in something, like a unit in an army on a transport) on a tile, the game will not always show the passenger units in the correct locations +; on the right-click menu. To fix this, the mod double checks the order of the entries on the menu to make sure that passenger units are listed just +; after the unit they're contained in. +; PATCH EMPTY ARMY COMBAT CRASH -- Guards a crash in the army combat selection routine by returning the army unit itself if it has no contained +; units (prevents divide-by-zero in the vanilla selection loop). + +patch_submarine_bug = true +patch_science_age_bug = true +patch_pedia_texture_bug = true +patch_blocked_disembark_freeze = true +patch_houseboat_bug = true +patch_intercept_lost_turn_bug = true +patch_phantom_resource_bug = true +patch_maintenance_persisting_for_obsolete_buildings = true +patch_barbarian_diagonal_bug = true +patch_disease_stopping_tech_flag_bug = false +patch_division_by_zero_in_ai_alliance_eval = true +patch_empty_army_movement = true +patch_premature_truncation_of_found_paths = true +patch_zero_production_crash = true +patch_ai_can_sacrifice_without_special_ability = true +patch_ai_can_form_army_without_special_ability = true +patch_crash_in_leader_unit_ai = true +patch_failure_to_find_new_city_build = true +patch_passengers_out_of_order_on_menu = true +patch_empty_army_combat_crash = true + +; At the beginning of each AI player's turn, deletes any units of theirs that are not on a valid tile. This addresses a rare crash that can occur when +; the unit AI invokes the pathfinder for an off-map unit. I don't know how AI units can end up off the map in the first place. +delete_off_map_ai_units = true + +; On the city screen, the icons for different kinds of specialist yields get drawn over top of, instead of beside, one another. This setting fixes +; that so they are displayed properly. +fix_overlapping_specialist_yield_icons = true + +[======================] +[=== LIMITS REMOVED ===] +[======================] + +remove_unit_limit = true +remove_city_improvement_limit = true + +; The city limit can be configured up to a maximum of 2048 or down to a minimum of 0. For base game behavior, set to 512. +city_limit = 2048 + +; Increases the cap on the game turn limit from 1000 to 1000000 +remove_cap_on_turn_limit = true + +; Be warned: the no era limit feature is incomplete, untested, and not likely to work at this time +remove_era_limit = false + +[=========================] +[=== ENGINE EXTENSIONS ===] +[=========================] + +; These "NoRaze" options can stop cities from being destroyed. "Autorazing" refers to the automatic destruction of size one, cultureless cities. If +; autorazing is prevented, players will be given the option to keep the city. If razing by players is prevented, neither the human player nor AIs will +; be allowed to raze or abandon cities. +prevent_autorazing = false +prevent_razing_by_players = false + +; These options allow you to adjust the minimum allowed distance between cities. minimum_city_separation controls the minimum number of tiles between +; cities so, e.g, if it's set to 1, cities cannot be founded adjacent to one another, there must be at least one open tile separating them. A setting +; of 1 there corresponds to the standard game rules. disallow_founding_next_to_foreign_city is an optional additional restriction. If it's enabled, +; cities may not be founded adjacent to a city belonging to another civ regardless of the minimum separation. It is only relevant when the minimum +; separation is set to zero. +minimum_city_separation = 1 +disallow_founding_next_to_foreign_city = true + +; Set to a number to limit railroad movement to that many tiles per turn. To return to infinite railroad movement, set to false or a number <=0. By +; default, all units travel the same distance along limited rails like in Civ 4, but this can be changed by toggling the next option below. +; NOTE: For best results, the railroad limit should be a multiple of the "movement rate along roads" set in the editor (usually 3). The limitation +; will work in any case, but setting the limit this way helps avoid an integer overflow issue inside the pathfinder that may cause it to fail to find +; the shortest paths for units with a large number of available moves. +limit_railroad_movement = false + +; If set to true, limited railroads will work like fast roads instead of Civ 4 style railroads. The movement rate along fast roads is determined by +; the limit_railroad_movement setting above. If that setting is false or <= 0, this option does nothing. +limited_railroads_work_like_fast_roads = false + +; This option lets you put a limit on how many units may occupy each tile. The limit applies separately for land, sea, and air units. You may set the +; limit differently for each of those classes by setting this option to a list of three numbers. If you set it to a single number, that limit amount +; will apply to all three. If you set it to false or a number <= 0, no limit will apply, as in the base game. Some examples: +; To limit tiles to 5 land, 5 sea, and 5 air units: limit_units_per_tile = 5 +; To limit tiles to 5 land and sea units but 10 air units: limit_units_per_tile = [5 5 10] +; To limit only air units to 10 per tile: limit_units_per_tile = [false false 10] +; To have no limit (as in the standard game rules): limit_units_per_tile = false +; NOTE: The two options below let you exclude cities or certain unit types from the limit. +limit_units_per_tile = false + +; Allows an unlimited number of units to occupy tiles with cities when the unit limit is in force. When the limit (option above) is deactivated, this +; option does nothing. +exclude_cities_from_units_per_tile_limit = false + +; Allows certain unit types to be exempt from the stack limit. Units of these types will not be stopped by the limit and will not count toward it +; (will not stop others). This option is a space separated list of unit type names. Multi-word names must be wrapped in quotes. For example: +; [Worker Settler Flak "Mobile SAM"] +; This option does nothing if limit_units_per_tile is set to false. +exclude_types_from_units_per_tile_limit = [] + +enable_free_buildings_from_small_wonders = true +allow_stealth_attack_against_single_unit = false +disallow_trespassing = false +enable_land_sea_intersections = false + +; All anarchy lengths will be multiplied by this amount as a percent. For example, if set to 50, anarchy length will be reduced by half. Set to 100 +; for standard game behavior. There is a minimum anarchy length of 2 turns, but you can remove anarchy entirely by setting this option < 0. +anarchy_length_percent = 100 + +; Add perfume to an improvement or unit type to encourage the AI to build it more often. When choosing what to buld, the AI computes a point value for +; each of its options and the mod will add the perfume amount to the point total for each named option. For reference, point values are often in the +; hundreds for the most desirable options. You can see the point value the AI gives to every available build by pressing P while viewing one of its +; cities. Perfume amounts can also be specified as a percentage, ex. a perfume amount of 15% will increase the AI's evaluation by 15% and an amount of +; -50% will reduce it by half. +; production_perfume is a list of names and amounts, each one looks like "name": amount +; Here's an example: ["Granary": 15, "Colosseum": -20%, "Courthouse": 30] +; The quotation marks around a name are not necessary if the name is all one word (i.e. does not include spaces) and is made up of only letters, +; digits (0-9), periods, hyphens, or underscores. The category of letters includes the normal English a-z and A-Z as well as accented variants +; (e.g. ä, ö, ñ, ç) and all other non-English letters available in the Windows-1252 encoding (e.g. ß, þ, æ). +production_perfume = [] + +; Add perfume to a technology to change how valuable the AI judges the tech to be. Each point of perfume is worth roughly one gold in trade, and also +; affects what the AI chooses to research. The format matches production_perfume above, ex.: [Medicine: 500, Fascism: -50%, "Replacable Parts": 20%]. +technology_perfume = [] + +; Add perfume to a government to encourage or discourage the AI from switching to that type. The format follows the other perfume options, ex.: +; [Republic: 10%, Fascism: -30%]. Unfortunately I don't know how much each point is worth in this context. I also don't know how perfuming governments +; affects the AI's willingness to overthrow its current govt. The perfume for sure applies when the AI is selecting a new govt type after anarchy. +government_perfume = [] + +; The AI production ranking is the point value the AI gives to each available build in some city. To view it, press P while viewing an AI city. +enable_ai_production_ranking = true + +; Shades/highlights each tile to show how desirable the AI considers it as a city location. To activate, press L while in game. The scale goes from +; white (least desirable) to red (most desirable) with yellow in between. Also the exact number the AI gives any tile can be seen on its info box. +; If show_ai_city_location_desirability_if_settler is true, the desirability overlay will automatically appear when a settler is selected. +enable_ai_city_location_desirability_display = true +show_ai_city_location_desirability_if_settler = false + +; Setting a government's corruption level to "OFF" will remove all corruption, as expected, instead of maximizing it +zero_corruption_when_off = true + +; Prevents land settlers/workers on transports from settling/improving water tiles. This option does not affect the vanilla game but is useful for +; mods that enable city building or improvement of water tiles. +disallow_land_units_from_affecting_water_tiles = true + +; Allows units to move after airdropping by making airdrops cost no movement. Under the standard game rules, units lose all their remaining moves +; after airdropping. Units will be prevented from airdropping more than once in the same turn. +dont_end_units_turn_after_airdrop = false + +allow_airdrop_without_airport = false +enable_negative_pop_pollution = true + +; Here it's possible to set buildings as prerequisites for unit production. It's possible for a unit type to have multiple prereq buildings up to a +; maximum of 10, and all must be present in a city for the unit to be buildable. +; The format is a list of building names and unit type names, each one looks like "building name": "unit type 1" "unit type 2" ... +; Quotation marks around names can be omitted like in production_perfume (see above). +; Here's an example: +; [Factory: Tank "Modern Armor", +; Barracks: Swordsman Cavalry Tank "Modern Armor", +; Airport: Bomber] +building_prereqs_for_units = [] + +; Here it's possible to set buildings to generate resources. Those resources can be added to the trade network or limited to the building's city. The +; format is a list of building name and resource name pairs with optional "local", "no-tech-req", "yields", "show-bonus", and/or "hide-non-bonus" +; settings before each resource name. Example: +; ["Steel Mill": Steel, Terrace: yields show-bonus Rice, "Coal Liquefaction": local Oil, Supercollider: local no-tech-req Antimatter, +; "Hydro Plant": local "Electric Power"] +; Quotation marks around names can be omitted like in production_perfume (see above). +; The "local" setting means that the produced resource will not be added to the trade network, it will be available only in the building's city. +; The "no-tech-req" setting means that the resource will be produced even for players who do not have the technology to reveal it on the map. +; The "yields" setting means that the resource's tile yields will be added to the city as if it were on a worked tile. +; The "show-bonus" setting means that an icon for the generated resource will be displayed on the city screen even if it's a bonus resource. +; The "hide-non-bonus" setting is the opposite of show-bonus. It means an icon will NOT be shown if the resource is of strategic or luxury type. +; Buildings will not generate resources if the resource requirement for the building itself is not met. This makes it possible to set up resource +; production chains. Note for modders: Production chains require the input resources to be listed before the outputs in the scenario data, when the +; inputs also come from buildings. For example if you have iron ore on the map, a building that requires it and produces iron, and a building that +; requires iron and produces steel, iron must be listed before steel in the scenario data or the chain won't work. This is because building resource +; generation is calculated in the same order as the generated resources appear in the scenario data. This limitation does not apply to map resources +; (iron ore in the example) as access to all map resources is calculated first before any building resources. +buildings_generating_resources = [] + +; Shows a warning in case some of the unit, building, or resource names in this config file don't match anything in the scenario data. +warn_about_unrecognized_names = true + +; Overrides the rules for when units are eligible to retreat based on their movement. The possible options are: +; standard: No change from base game rules +; none: No units will ever retreat +; all-units: All non-immobile units may retreat, even if they have only one move or are up against a faster opponent +; if-faster: Units may retreat when they are faster than their opponent, for example a cavalry may retreat from a knight +; if-not-slower: Units may retreat when they are at least as fast as their opponent, for example a knight may retreat from another knight but not +; from a cavalry, and an infantry may retreat from another infantry +; if-fast-and-not-slower: Like if-not-slower but only fast (2+ move) units may retreat +; These settings don't change the fact that units cannot retreat when they start combat with 1 HP or are defending a city. They also do not change +; that naval units cannot retreat defensively (there is a separate option for that below). +land_retreat_rules = standard +sea_retreat_rules = standard + +; Under the base game rules, no unit may retreat defensively if it's located on a water tile. This option removes this special rule so naval units can +; retreat defensively like land units do. See also: the sea_retreat_rules option above and the limit_defensive_retreat_on_water_to_types option below. +allow_defensive_retreat_on_water = false + +; If any unit types are listed here, defensive retreat on water tiles will be limited to those types. Otherwise, all types may retreat that way. The +; list is separated by spaces and multi-word type names must be wrapped in quotation marks. For example, setting to: +; [Submarine "Nuclear Submarine"] +; would mean that only those submarine naval units could retreat defensively. This option does nothing if allow_defensive_retreat_on_water is false. +limit_defensive_retreat_on_water_to_types = [] + +; The multi-city start spawns in multiple cities for AI players at the start of the game instead of their usual one settler. This option controls the +; number of cities the AI starts with. E.g., if it's set to 2, the AI starts with 2 cities. If it's set <= 0, the game starts like normal. The mod can +; also add improvements to the AI's extra cities, which are intended to work like extra palaces, see ai_multi_start_extra_palaces. +ai_multi_city_start = 0 + +; This option only applies if ai_multi_city_start is set > 1. It controls how many tiles the mod will randomly check while searching for a suitable +; location for each of the AI's extra starter cities. Default: 10000. +max_tries_to_place_fp_city = 10000 + +; This option only applies if ai_multi_city_start is set > 1. It specifies a list of improvements to be added to the AI's additional cities. E.g: +; ["Forbidden Palace" Courthouse] +; If the AI multi-city start is set to 3+ with the above extra palaces, the AI players will start with 3+ cities and the first one will have the +; Palace like normal, the second will have the Forbidden Palace, and the third will have a courthouse, any after that will start empty. +; Additionally, any small wonders listed here with the "reduces corruption" effect will be considered "extra palaces" for the AI. They will respawn +; like the real Palace. In other words, if an AI loses a city with an extra palace, it will reappear in another one of its cities following the same +; logic the game uses to select a new Palace location. If the AI is missing an extra palace and acquires a new city, that extra palace will +; automatically be added to the new city. +ai_multi_start_extra_palaces = [] + +; Turning this on makes small or great wonders with the "reduces corruption" effect, such as the Forbidden Palace, as effective at reducing corruption +; as the palace itself. This reduces corruption not only in the city that contains such a wonder, it also reduces distance and rank corruption in +; nearby cities as if the city were an additional capital. +promote_wonder_decorruption_effect = false + +allow_military_leaders_to_hurry_wonders = false +allow_multiple_battle_created_units_per_player = false + +; The AI's beaker production will be multiplied by this amount, as a percent. A value of 100 gives you the standard game behavior, a value of 75 +; reduces AI research by 25%, a value of 200 doubles AI research, and so on. +ai_research_multiplier = 100 + +; Each time an AI player founds a city, the given amount of perfume will be applied to its settlers over the given duration in number of turns. The +; perfume effect declines steadily to zero over the duration. The perfume amount may be specified as a percentage. The purpose of these options is to +; slow the AI's expansion with negative perfume. +; NOTE: The AI has a very strong tendency to build settlers so you'll need to set these options quite high to slow it down significantly. For example, +; a perfume of -200% over a 30 turn duration left the AI with about half as many cities after 50 turns in my test. +ai_settler_perfume_on_founding = 0 +ai_settler_perfume_on_founding_duration = 0 + +; If a player can't afford to pay maintenance on their buildings and units, the game will forcibly lower expenses and raise money by (in order): +; 1. Selling buildings, excluding those that are maintenance-free or contribute to gold production even indirectly +; 2. Disbanding units, excluding free ones +; 3. Switching cities to building Wealth +; For AI players, the game alternates the order of (1) and (2) each turn. Also for AIs, on every third turn, the game will cut their research spending +; as much as necessary to avoid bankruptcy. +aggressively_penalize_bankruptcy = false + +; Under the standard game rules, the Despotism tile penalty does not apply to food yield from city tiles of Agricultural civs with fresh water. Set +; this option to true to remove that exception to the penalty. +no_penalty_exception_for_agri_fresh_water_city_tiles = false + +; Adds an option to the stealth attack target selection popup that allows the player to opt out of doing a stealth attack. If selected, the unit will +; attack normally, targeting the tile's top defender. Similarly, if stealth bombardment is canceled, the unit will bombard normally and may target +; buildings or population if attacking a city. +include_stealth_attack_cancel_option = false + +; Aircraft flying a recon mission can be intercepted by enemy fighters or ground AA as if they were flying a bombing mission +intercept_recon_missions = false + +; Under the standard rules, performing a recon mission or intercepting an attacker causes a unit to lose all of its remaining moves. Setting this +; option to true causes those actions to only consume one move. This makes them consistent with other air missions like bombing. Note: fighters will +; only be able to intercept multiple times in one turn if they have the blitz ability. +charge_one_move_for_recon_and_interception = false + +; In the base game, precision striking was only intended to be used by bombers. This option extends the precision strike logic to cover land & sea +; artillery and cruise missiles. Specifically what it does is: +; 1. Fixes the animations, so land & sea artillery will play their bombard animations and cruise missiles will play their strike animation +; 2. Makes it so that the strikable range depends on the bombard range for land & sea units instead of operational range +; 3. Despawns cruise missiles after they've performed a precision strike +polish_precision_striking = true + +; Enables units to perform stealth attacks when they bombard or bomb a target. Like regular stealth attacks this opens a popup allowing the player to +; choose a specific unit to target. The attacking unit must have the stealth attack special action checked, must have a list of stealth attack targets +; set, and the target tile must be visible. +enable_stealth_attack_via_bombardment = false + +; Prevents aircraft from being damaged by bombardment or bombing +immunize_aircraft_against_bombardment = false + +; Unit type names listed here will use PTW-like targeting when bombarding cities. PTW-like means there is a 1-in-3 chance they will target each of +; population, buildings, and units. This is unlike Conquests artillery targeting, which always goes after units first. Items in the list are separated +; by spaces and multi-word items must be wrapped in quotation marks like for perfume specs. Example: [Catapult Cannon Artillery "Radar Artillery"] +ptw_like_artillery_targeting = [] + +; Changes the meaning of the charm attack flag to indicate PTW-like targeting. This is a matter of convenience. It allows modders to specify PTW +; targeting using an editor, instead of the list above, at the cost of losing the charm attack function. +charm_flag_triggers_ptw_like_targeting = false + +; Unit types listed here won't be allowed to bombard land tiles. Same format as ptw_like_artillery_targeting, example: [Submarine "Torpedo Bomber"] +can_bombard_only_sea_tiles = [] + +; Units with the king ability will defend like normal, instead of always being the last to defend in a stack. Useful for mods that use the king flag +; for special purposes. Does not apply in regicide games. +ignore_king_ability_for_defense_priority = false + +; Untradable techs will appear grayed out on the trade screen. This lets you see which untradable techs the AI has just like for tradable +; ones. "Untradable" means techs that have been flagged as "cannot be traded" in the editor. This option only matters for modded games as there are no +; untradable techs in the standard game. +show_untradable_techs_on_trade_screen = false + +; Barbarians will capture cities instead of ransacking them. This option also modifies the game's production logic so barbarian cities can build +; things, grow, and even do research. +; This feature is EXPERIMENTAL at the moment. It basically works but hasn't been extensively tested. For example, I don't know what would happen if +; the barb player were to win the game. +; Because of how barb city production works under the hood, it requires barb activity to be turned on in order to work. The mod will handle this +; automatically. If this option is enabled, there is at least one barb city on the map, and the barb activity level is set to 0 (no barbarians), the +; level will be increased to 1 (sedentary) in order not to block barb city production. +enable_city_capture_by_barbarians = false + +; A list of modifications to the rules for defensive bombard. "Defensive bombard" is the free shot a bombard unit gets when the stack it's in is +; attacked. The possible options are: +; lethal: Attackers may be destroyed by defensive bombard if the bombarding unit has the appropriate lethal land/sea bombard ability. +; aerial: Air units may perform defensive bombard if they can perform bombing missions. +; not-invisible: Attacking units are immune to defensive bombard if they are invisible and not detected. +; blitz: Units with blitz may perform defensive bombard multiple times per turn, once for each move they have. +; docked-vs-land: Docked ships (i.e. in a city) can perform defensive bombard against land units attacking their city. +; For example, to activate all options, set to [lethal aerial not-invisible blitz docked-vs-land]. The order of items in the list does not matter. You +; can also activate all options by setting to [all] (with or without the brackets). +special_defensive_bombard_rules = [] + +; A list of modifications to the rules for zone of control, like above for defensive bombard. The possibilities are: +; amphibious: Land units may exert zone of control over sea units and vice-versa. This can only be done using bombard strength, not attack +; strength. It also requires non-zero bombard range. +; lethal: Units may be destroyed by zone of control. The intercepting unit must have the lethal bombard ability in order to do this, even if it's +; using its attack strength to exert ZoC. +; aerial: Air units can exert zone of control if their type has the "Zone of Control" option checked. Additionally, they must be able to perform the +; bombing mission, have non-zero bombard strength, and non-zero operational range. +; not-from-inside: Land units may not exert zone of control while inside a transport (armies do not count as transports) +; Like for defensive bombard, all options can be activated by setting to [all] (with or without the brackets), and order does not matter. +special_zone_of_control_rules = [] + +; All human players in a hotseat game will share visibility +share_visibility_in_hotseat = false + +; All human players in a hotseat game will share the effects of the wonders they've built, great or small. This applies to all civ-wide effects, for +; example if any human player builds Leonardo's Workshop, all human players get half price upgrades. Notes: +; 1. If a human player receiving the shared effect of a small wonder and that SW has no non-shared effects, it becomes unbuildable for that player. +; 2. Building and army requirements for wonders are shared as well. For example, all human players are allowed to build Battlefield Medicine once all +; of them combined have five hospitals. +; 3. For the Great Library effect, known AI civs are shared as well. If an AI has contact with any human player, it is considered to be in contact +; with all of them for the purpose of granting techs to human players. +share_wonders_in_hotseat = false + +allow_precision_strikes_against_tile_improvements = false +dont_end_units_turn_after_bombarding_barricade = false + +; Allows land units to bombard aircraft and naval units in cities +; This does not override the immunity of aircraft vs bombardment, if that option is also activated. +remove_land_artillery_target_restrictions = false + +; Allows tile improvements on a tile with an occupied airfield to be destroyed by bombardment, not including the airfield itself. For example, under +; the standard game rules, if you bombard a tile with a road, airfield, and fighter on it, you will do no damage because the attack will target the +; fighter which is invulnerable (aircraft in an airfield cannot be damaged by bombardment). This option allows such an attack to bypass the fighter +; and hit the tile instead, as long as that tile has an improvement other than the airfield. +allow_bombard_of_other_improvs_on_occupied_airfield = false + +; Displays the total number of cities in the game on the demographics screen (press F11). +show_total_city_count = false + +; Under the standard game rules, each forbidden-palace-like building in an empire increases its optimal city number (OCN) by 37.5% of the base number, +; except if the empire is running a government with communal corruption, in which case the increase is 100% of the base. With this option enabled, the +; communal corruption rule is always in force, so each forbidden palace always increases the OCN by an amount equal to the base number. +; NOTE: The "base" optimal city number comes from the map size. It's the number set on the "World Sizes" tab in the editor. +strengthen_forbidden_palace_ocn_effect = false + +; This option allows you to increase the maintenance cost of units depending on their shield cost. For every X shields that the unit costs to build +; (where X is the setting below), the unit's maintenance increases by one unit's worth. For example, if set to 100, units that cost 0-99 shields will +; have normal maintenace, units costing 100-199 shields will cost double, those costing 200-299 will cost triple, etc. (Note the final cost in GPT +; depends on gov't type). Set <= 0 to disable. +extra_unit_maintenance_per_shields = 0 + +; This option renames players' civs depending on their eras. The format is a list of names each associated with a list of replacements. There is one +; replacement for each era or, if the list is shorter than the number of eras, no replacement will be done in the later eras. Example: +; [Rome: Rome "Byzantine Empire" Italy Italy, +; Roman: Roman Byzantine Italian Italian, +; France: Gaul, French: Gaulic] +; In this example, Rome will be renamed to "Rome" in the first era, "Byzantine Empire" in the second, and "Italy" in the third and fourth. The +; adjectives will be replaced to match. France/French will be renamed to Gaul/Gaulic only in the first era. +; Spaces are used to separate words so if a name or replacement has multiple words it's necessary to use quotation marks to group them together like +; for "Byzantine Empire" in the example. +; The replacements apply to civ nouns, adjectives, and formal names. If a player has put in a custom name, that will not be replaced. +civ_aliases_by_era = [] + +; This option works like the one above except it replaces leader names instead of civ names. Each replacement name may be followed by (M) or (F) to +; specify gender. Example: +; ["Joan d'Arc": Vercingetorix (M) "Joan d'Arc" (F) Napoleon (M) "De Gaulle" (M)] +; If no gender is specified then the game will use whatever gender was set in the scenario data for that civ's leader. That means (F) could be omitted +; in the above example since the leader of France is already female. +; Additionally you can include a replacement title after the gender separated by a comma. Here's the example with titles added: +; ["Joan d'Arc": Vercingetorix (M, King) "Joan d'Arc" (F) Napoleon (M, Emperor) "De Gaulle" (M, President)] +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 +; 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. +; 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. +unit_limits = [] + +; Removes barracks/harbor/airport requirement from upgrades +allow_upgrades_in_any_city = false + +; Stops the game from placing volcanos during map generation. Any tiles that would have been volcanos will be mountains instead. +do_not_generate_volcanos = false + +; Stops the game from placing pollution on impassable tiles +do_not_pollute_impassable_tiles = false + +; Includes the hitpoints of each possible target on the stealth attack selection popup. This makes it easier to pick out weakened units. +show_hp_of_stealth_attack_options = false + +; Stops invisible units from being targeted by stealth attacks. They can still be targeted if they've been revealed by the attacking civ. +exclude_invisible_units_from_stealth_attack = false + +; Stops units from being targeted by stealth attack if they are contained in another unit such as a naval or land transport, or a helicopter. +exclude_passengers_from_stealth_attack = false + +; Normally planting a forest always produces the regular non-LM forest terrain. This option changes that so it instead produces LM forest. +convert_to_landmark_after_planting_forest = false + +; This option specifies how likely it is (in percent) for a combat land or sea unit with a maximum of one HP to be destroyed when struck by a +; nuke. Set to 100 for base game behavior. +chance_for_nukes_to_destroy_max_one_hp_units = 100 + +; Allows you to sell aqueducts and hospitals as well as any modded buildings that uncap population growth. A city must be below the pop cap for a sale +; to be allowed, i.e., under the standard rules, aqueducts may only be sold in cities of pop <= 6 and for hospitals pop <= 12. +allow_sale_of_aqueducts_and_hospitals = false + +; Allows you to sell Small Wonders. This may be useful to relocate Forbidden Palace-like Small Wonders. +allow_sale_of_small_wonders = false + +; This option makes it so that only sea units with the "detect invisible" ability can reveal invisible sea units, and likewise for non-sea units. +no_cross_shore_detection = false + +; Controls the size of the area in which cities can work tiles. The value corresponds to cultural border expansions. For example, setting this to 1 +; means cities would only be able to work tiles within their level 1 cultural borders, meaning the eight tiles neighboring the city's own +; tile. Setting to 2 gives you the game's standard rule that cities may work tiles within their level 2 cultural borders, which they attain after one +; expansion. Setting to 3 allows them to work within level 3 borders and so forth. +; Notes: (1) If the city can work tiles in the fourth ring or farther, the map view on the city screen will be zoomed out when you enter it if +; auto_zoom_city_screen_for_large_work_areas is true. Otherwise it's not possible to show the entire work area. You can zoom back in by pressing Z. +; (2) The next option below can limit cities' workable areas to be smaller than the radius set here, based on their culture. (3) This option has a +; minimum value of 1 and a maximum of 7. +city_work_radius = 2 +auto_zoom_city_screen_for_large_work_areas = true + +; This option can reduce the size of the area cities can work based on their cultural level. +; Possible values are: +; none: Standard game rules apply; cities can work any tile that's within the work radius and within their owner's borders. +; cultural: Cities may only work tiles that are within their direct cultural borders, e.g. a city with zero culture may only work the 8 surrounding +; tiles. After one expansion, it may work the standard 20, after a second expansion it may work the third ring, and so on. +; cultural-min-2: Like "cultural" except cities can always work their standard 20 tiles. +; cultural-or-adjacent: Cities can work tiles in their direct cultural borders plus any tiles adjacent to those. +work_area_limit = none + +; This option can also reduce the size of the area cities can work based on improvements present. +; This mechanic works in tandem with the above work_area_limit condition - tiles cannot be worked if the tiles do not also meet the cultural work area limit requirement. +; If left empty, this mechanic is not used. +; Improvements may be defined to grant a certain radius work area, and the highest radius present is used as the work radius for a city. eg ["Harbor": 3] +; Improvements may also grant a bonus radius, these are added on after the highest radius is found. [Factory: 3, "Mass Transit": 2 extra] +; An entry written as default or "default" will always be present for any given city, and represents an always-present virtual improvement. eg. ["default": 2] gives vanilla behaviour. +work_area_improvements = [] + +; The maximum distance it's possible to rebase an aircraft equals its operational range times this value. For standard game rules, set to 6. +rebase_range_multiplier = 6 + +; This option prevents units from loading into two different transports on the same turn. Once a unit has been loaded into a transport, it becomes +; tied to that transport for the remainder of the turn and cannot be loaded into any other. Loading into armies is not affected. The purpose of this +; option is to make the galley chaining exploit impossible. +limit_unit_loading_to_one_transport_per_turn = false + +; In the base game, if you set Cavalry to upgrade to Tank but don't give it the upgrade ability, intending to make Cavalry obsolete when Tanks become +; available but not upgradable to them, you'll be left with the strange situation that older units such as Knights are allowed to upgrade to Tanks +; even though Cavalry are not. This option makes it so that Knights upgrade to Cavalry in that case. In general, it makes it so that upgrade chains +; stop at the type along the chain that does not have the upgrade ability. +; NOTE: The chain is only stopped if the civ in question can build the unit type. The example above is simplified. In the actual rules, Cavalry +; upgrades to Sipahi, which upgrades to Cossack. Blocking the upgrade chain at Cavalry would prevent Ottomans and Russia from upgrading to their +; unique units, so the mod won't do that. You must clear the upgrade ability from Sipahi and Cossack as well to block those civs there instead. +prevent_old_units_from_upgrading_past_ability_block = false + +; Buildings double their culture production this many years after they were built. For standard game rules, set to 1000. +years_to_double_building_culture = 1000 + +; Controls how long it takes for wonders to produce tourism gold as a percent of the standard rate. For example, if set to 200, it would take 2000 +; years to begin generating 2 GPT tourism, instead of the standard 1000 years, and 3000 years for 4 GPT, instead of the standard 1500. This setting is +; effectively a scaling factor on the tourism time thresholds. For standard rules, set to 100. +tourism_time_scale_percent = 100 + +; On the first turn of a hotseat game, all human players will be given diplomatic contact with each other. +introduce_all_human_players_at_start_of_hotseat_game = false + +; Allows units to be unloaded from an army. The army type must have the "unload" ability set in the editor. +allow_unload_from_army = false + +; Allow colonies to be built on tiles inside another civ's territory (for strategic/luxury resources); applies a relation penalty with the other civ, per each colony. +allow_extraterritorial_colonies = false +per_extraterritorial_colony_relation_penalty = 3 + +; A list of rule modifications to make land transports more practical. Works like special_defensive_bombard_rules. The possibilities are: +; load-onto-boat: Allows land transports to be loaded into naval units +; join-army: Allows empty land transports to join armies +; no-defense-from-inside: Prevents units inside a land transport from defending their tile, performing defensive bombard, or intercepting air units +; no-escape: Destroys the passengers inside a land tranport when the transport itself is destroyed or captured +land_transport_rules = [] + +; Prevents land anti-air units from intercepting overflying units while they're loaded in a naval transport +no_land_anti_air_from_inside_naval_transport = false + +; A list of rule modifications for air units with transport capacity called "helicopters" for short. Works like special_defensive_bombard_rules. The +; possibilities are: +; allow-on-carriers: Allows helicopters to be rebased or loaded onto carriers +; passenger-airdrop: Allows paratroopers inside a helicopter on a carrier to perform airdrops +; no-defense-from-inside: Prevents units inside a helicopter from defending their tile, performing defensive bombard, or intercepting air +; units. Also destroys passengers when the helicopter is destroyed in most circumstances in order to avoid problems such as a helicopter being +; captured by a land unit leaving its passengers alive on the same tile. +; no-escape: In all circumstances, destroys the passengers inside a helicopter when the heli itself is destroyed or captured +special_helicopter_rules = [] + +; Stops units from enslaving a target they've destroyed by bombarding as opposed to direct combat +prevent_enslaving_by_bombardment = false + +; Relaxes a rule that prevents resources from appearing directly next to another resource of a different type +allow_adjacent_resources_of_different_types = false + +; Controls the overall number of luxury resources placed on the map for luxury types that don't have a fixed appearance rate set in the editor. Under +; the standard rules, no luxuries have appearance rates set. Without a set rate, the game randomly chooses a rate between 50 and 100, biased toward +; the middle (75). This setting is a percent scaling on that range, so setting it to 150 means luxuries would have their rate randomized between 75 +; and 150, setting to 50 means a range of 25 to 50, and so on. For base game behavior, set to 100. +luxury_randomized_appearance_rate_percent = 100 + +; During map generation, the game places bonus resources until the total number of strategic and bonus resources reaches the tile count divided by +; this number. Raising this setting causes fewer bonus resources to be generated and lowering it increases them. For the standard rate, set to 32. +tiles_per_non_luxury_resource = 32 + +; Normally the corruption rate in the capital is fixed at zero. Setting this to true removes that, allowing corruption to appear in the capital. The +; capital also has a strong inherent bonus reducing corruption so even when this setting is on, it will usually have zero corruption. To reduce that +; bonus, see the special_capital_decorruption_effect option below. +allow_corruption_in_capital = false + +; Controls the special decorruption bonus that's applied to the capital. This bonus is incorporated into the decorrupting effect from buildings in the +; city and each point is equivalent in strength to one courthouse. For standard game rules, set to 10. This option does nothing unless +; allow_corruption_in_capital is set to true. Min value 0, max 100. +special_capital_decorruption_effect = 10 + +; Overrides the NoAIPatrol setting from conquests.ini. Possible values are: +; none: No override, use the setting from the INI like normal +; one: Set NoAIPatrol to 1, disabling AI patrol behavior +; zero: Set NoAIPatrol to 0, allowing AI units to patrol +; The purpose of this option is to enable you to configure NoAIPatrol like a C3X setting instead of globally. In particlar, it allows you to configure +; NoAIPatrol on or off on a per-scenario basis. +override_no_ai_patrol = one + +; Overrides the barbarian activity level when starting a new game for a scenario with a custom map. Normally, in that case, the game will use the +; barbarian settings kept in conquests.ini, ignoring what was set for the map in the editor. This option allows you to set an activity level on a +; per-scenario basis like other C3X settings. +; The possible values are "none" for no override, i.e. base game behavior, or one of the selectable barbarian activity levels: "No Barbarians", +; Sedentary, Roaming, Restless, Raging, or Random. You can specify either the original English names just listed or the custom/translated names in +; labels.txt. The value is not case sensitive. +override_barbarian_activity_level_for_scenario_maps = none + +; Leader units placed on the map as part of a scenario do not have their leader types filled in properly, which means they behave differently than +; proper military leaders would. In particular, they are allowed to hurry production of great wonders and spaceship parts. This option fills in their +; types at the start of the game so they behave like normal MGLs spawned during a game. +initialize_preplaced_scenario_leaders_as_mgls = false + +enable_unit_counters = false + +; Civ 4 style best defender selection. +; When this is on (and enable_unit_counters is also true), every time an attack happens the engine picks the +; defender that is HARDEST for the current attacker to beat (the unit with the highest defender win rate +; once unit-counter rules are applied), instead of the vanilla "highest defense strength" rule. The same +; unit is also forced to the top of the enemy stack on the map whenever a player has an attacker selected, +; so the displayed unit stays in sync with what would actually fight. Re-targeting is automatic: switching +; the selected attacker (different counter match-ups) updates which enemy unit is shown as the best defender. +; Notes: +; - Has no effect when enable_unit_counters = false (then there's nothing to differentiate beyond defense). +; - Applies to both human and AI attackers, so the rule is consistent. +; - Does not change ranged-bombard or defensive-bombard target selection, only normal attacks. +use_civ4_style_best_defender = false + +; unit_group allows you gruop your units in a group,please refer to building_prereqs_for_units for the format. +; This function will not work if enable_unit_counters is false. +unit_group = [] +; ── counter_rule format ────────────────────────────────────────────────────────────── +; +; counter_rule = [Friendly vs Enemy Effect... Conditions...] +; +; 【Friendly / Enemy】 +; This can be one of the following three options: +; · The specific unit type, such as "Archer" (must match the name in BIQ exactly; names containing spaces must be enclosed in quotation marks) +; · A unit group name, such as melee (i.e. the group defined in the unit_group section above) +; · "*" represents any unit type (the asterisk must be enclosed in quotation marks) +; +; 【Effect】(Expressed as a percentage; when multiple rules apply to the same battle, their effects are multiplied.) +; +; "self" always refers to the first unit, and "enemy" always refers to the second unit, regardless of who is attacking whom: +; self-atk value — The unit’s attack power becomes N% of its original value +; Example: self-atk 150 = attack power ×1.5; self-atk 50 = attack power ×0.5 +; self-def value — Your defence becomes N% of the original value; +; enemy-atk value — The enemy’s attack becomes N% of the original value; +; enemy-def value — The enemy’s defence becomes N% of the original value; +; +; 【Conditions】(Optional; leaving blank indicates no restrictions; conditions take effect only when all are met simultaneously) +; in-city —— Takes effect only when the enemy is on a city tile +; terrain terrain_name -- Takes effect only when the enemy is on a tile of the specified terrain +; Uses the same lower-case English terrain tokens as districts_config buildable_on, not BIQ/localized names. +; Examples: grassland, hills, coast, snow-forest, snow-mountain, snow-volcano, lake +; ignore-terrain —— Ignores the enemy’s terrain defence bonus (sets their terrain bonus to zero) +; Can be used in conjunction with enemy-def; when used together, ignore-terrain takes precedence +; district district_name -- Only takes effect when the enemy is in a specified district (enable_districts must be enabled) +; District names are resolved after districts_config loads, so dynamic district names are supported. +; +; 【Examples】 +; counter_rule = [ranged vs melee self-atk 125] +; → When a ranged unit attacks a melee unit, its attack power is multiplied by 1.25 +; +; counter_rule = ["Knight" vs melee in-city enemy-def 150] +; → When knights attack melee units within a city, the enemy’s defence is multiplied by 1.5 +; +; counter_rule = ["Musketman" vs "Medival Infantry" terrain grassland self-atk 125] +; → When musketeers attack medieval infantry on grassland terrain, their attack power is multiplied by 1.25 +; +; counter_rule = ["Knight" vs "*" ignore-terrain self-atk 150] +; → When a Knight attacks any unit, its attack power is multiplied by 1.5 and it ignores the enemy’s terrain bonus. +; counter_rule = [Archer vs Swordsman self-atk 130 self-def 120] +; → When an archer attacks a swordsman: Archer’s attack power ×130% +; When a swordsman attacks an archer: Archer’s defence ×120% +; +; ───────────────────────────────────────────────────────────────────────────── + +counter_rule = [] + +[==================] +[=== AESTHETICS ===] +[==================] + +; If a tile has a forest, render it on top of roads and railroads, instead of underneath them. +draw_forests_over_roads_and_railroads = true + +; This allows you to set a victory animation for air units. Can be set to the name of any animation that is loaded by the game, specifically one of: +; blank, default, run, attack1, attack2, attack3, death, fortify, fidget, victory, capture, fortress, build, road, mine, irrigate, jungle, forest, plant +; Note that bomber units already have their bombing animations in the victory slot so "victory" is not a good choice here. For standard game behavior, +; set to "none". +aircraft_victory_animation = none + +; Enables naming tiles via the right-click menu and displays those names on the map. +enable_named_tiles = true + +[=======================] +[=== DAY/NIGHT CYCLE ===] +[=======================] + +; How the day/night cycle operates in the game. If enabled, terrain, cities, resources, landmarks and terrain buildings will change appearance based on +; the time of day, with 24 possible stages (one for each hour). The base game art is used for 12pm. If set to 'off', only base game art will be used. +; Day/night cycle should not be used if you are using non-standard terrain art or resources. Doing so may result in visual glitches or missing art. +; Note that day/night cycle art is not bundled directly with C3X and must be downloaded separately at https://forums.civfanatics.com/resources/day-night-cycle-in-civ-3-using-c3x.32520/ +; The possible values are: +; off: Only base game art used +; timer: Increment based on time elapsed since last hour transition (e.g., transition to next hour every 3 minutes) +; user-time: Match the user's system clock to determine hour of the day +; every-turn: Increment every turn by a fixed amount of hours +; specified: Pin the hour to a specific value (so hour of day is always the same) +day_night_cycle_mode = off + +; If day_night_cycle_mode is set to 'timer', minimum minutes of real time to elapse before transitioning to the next hour in the cycle. +; This is checked only at the end of the turn, so actual minutes may exceed this number. +elapsed_minutes_per_day_night_hour_transition = 3 + +; If day_night_cycle_mode is set to 'timer' or 'every-turn', the number of hours to transition. This should be a value between 1 and 12 inclusive. +fixed_hours_per_turn_for_day_night_cycle = 1 + +; If day_night_cycle_mode is set to 'specified', the hour of the day to pin the cycle to. This should be a value between 0 (midnight) and 23 (11pm) inclusive. +pinned_hour_for_day_night_cycle = 0 + +[=======================] +[=== NATURAL WONDERS ===] +[=======================] + +; Show or hide natural wonders on the map. When disabled, natural wonders will not appear on the map. +enable_natural_wonders = true + +; If a new scenario is loaded which has no natural wonders defined, add natural wonders. +add_natural_wonders_to_scenarios_if_none = false + +; Show the names of natural wonders on the map below their image. +show_natural_wonder_name_on_map = true + +; Minimum separation (in tiles) between natural wonders when generating the map. This helps prevent clustering of natural wonders. +minimum_natural_wonder_separation = 10 + +[=================] +[=== DISTRICTS ===] +[=================] + +; Districts are Civ6-inspired structures built by workers that enable buildings, provide bonuses, and make cities feel more alive. When enabled, +; districts appear on the map and can be required for certain buildings (configured in default.districts_config.txt). Districts occupy tiles within a +; city's work radius, making those tiles unworkable. They can provide bonuses (food, shields, gold, science, culture, defense) to all cities within +; their work radius. If multiple cities share a district, they can optionally share its buildings and wonders (see options below). Districts with +; pollution or enemy units yield no bonuses. Destroyed districts remove dependent buildings from affected cities unless they have another district of +; that type in range. The five district types below can be enabled independently: +; enable_districts: Enables standard configurable districts (by default: Encampment, Campus, Holy Site, Commercial Hub, Entertainment Complex, Industrial Zone). +; Configured is done in default.districts_config.txt, user.districts_config.txt, and scenario.districts_config.txt +; enable_neighborhood_districts: Enables population growth past a configurable limit (see maximum_pop_before_neighborhood_needed below) +; enable_wonder_districts: Wonders require a dedicated district tile, making them visible on the map and optionally destructible. +; Configured in default.districts_wonders_config.txt, user.districts_wonders_config.txt, and scenario.districts_wonders_config.txt +; enable_distribution_hub_districts: Special districts that distribute food/shields from surrounding tiles to all connected cities +; enable_aerodrome_districts: Air units can only be built/based at Aerodrome districts instead of cities (if air_units_use_aerodrome_districts_not_cities is true) +; enable_port_districts: Enables Port districts, which serve as coastal district tiles for naval production/basing when naval_units_use_port_districts_not_cities is on. +; enable_bridge_districts: Enables Bridge districts on coastal water; completed bridges let land units cross water tiles. +; enable_canal_districts: Enables Canal districts on land; completed canals let naval units traverse land tiles between water bodies. +; enable_central_rail_hub_districts: Enables Central Rail Hub districts used for rail-era infrastructure (e.g., Mass Transit). +; enable_energy_grid_districts: Enables Energy Grid districts associated with power plant infrastructure. +; enable_great_wall_districts: Enables Great Wall districts (wall-like tiles that can block others if great_wall_districts_impassible_by_others is on). +enable_districts = false +enable_neighborhood_districts = false +enable_wonder_districts = false +enable_distribution_hub_districts = false +enable_aerodrome_districts = false +enable_port_districts = false +enable_bridge_districts = false +enable_canal_districts = false +enable_central_rail_hub_districts = false +enable_energy_grid_districts = false +enable_great_wall_districts = false + +; When multiple cities share a district (i.e., the same district tile is within multiple cities' work radii), these options control whether those +; cities automatically share the benefits of buildings and wonders constructed in that district. For example, if Rome and Veii both have the same +; Encampment in their work radius and Rome builds a Barracks in that Encampment, enabling cities_with_mutual_district_receive_buildings will cause +; Veii to automatically receive a Barracks as well. Similarly, cities_with_mutual_district_receive_wonders extends this sharing to Great and Small +; Wonders. This encourages strategic district placement between cities and can reduce micromanagement in dense urban areas. +; Note: receiving buildings is only assessed twice: when a city completes a building, and when a city is founded nearby. A city receiving a building +; cannot in turn recursively share it with third, fourth, fifth, etc. cities in a chain. Only applies if enable_districts is set to true. +cities_with_mutual_district_receive_buildings = true +cities_with_mutual_district_receive_wonders = true +show_message_when_building_received_by_mutual_district = true +show_message_when_building_lost_to_destroyed_district = true + +; When enabled, air units can only be built in cities with an Aerodrome district in their work radius and must be based at Aerodrome districts instead +; of cities. Air units will spawn on Aerodromes and can only land on Aerodromes, vanilla airfields, or carriers. Airlifts and airdrops are similarly +; limited to Aerodromes. This adds strategic depth by requiring infrastructure for air power and making air bases visible and vulnerable on the map. +; Only applies when enable_aerodrome_districts is also set to true. +air_units_use_aerodrome_districts_not_cities = true + +; When enabled, naval units can only be built in cities with a Port district in their work radius and cannot enter city tiles directly. Naval unit +; healing must be done at Port districts, and travel between continents, lakes and so on can instead only be done via Canal districts (via enable_canal_districts), +; rather than cities on an isthmus. Additionally, a city cannot build naval units until it has a Port district in range. Only applies when enable_port_districts is set to true. +naval_units_use_port_districts_not_cities = true + +; Neighborhood district limit population growth. Once a city reaches maximum_pop_before_neighborhood_needed, it cannot +; grow further until it has at least one Neighborhood district in its work radius. Each Neighborhood then enables additional population growth equal to +; per_neighborhood_pop_growth_enabled. For example, with maximum set to 6 and per_neighborhood set to 2, a city can grow to pop 6 without +; Neighborhoods, requires 1 Neighborhood to reach pop 8, requires 2 Neighborhoods to reach pop 10, and so on. Neighborhood bonuses (+1 gold and +1 +; culture, by default) only apply if the city actually needs them based on its population. Periodic popups will remind you when a Neighborhood is needed. Only +; applies when enable_neighborhood_districts is set to true. neighborhood_needed_message_frequency sets how often (in turns) the reminder message appears; +; set to 0 to disable. +; If destroying_neighborhood_reduces_pop is true, losing a Neighborhood district reduces the city's population down to the new cap. +maximum_pop_before_neighborhood_needed = 6 +per_neighborhood_pop_growth_enabled = 3 +neighborhood_needed_message_frequency = 4 +destroying_neighborhood_reduces_pop = true + +; These options control the vulnerability and rebuildability of completed Wonders in Wonder districts. When completed_wonder_districts_can_be_destroyed +; is enabled, completed Wonders (both Great and Small) can be pillaged or destroyed by enemies, making them valuable strategic targets that must be +; defended. When destroyed_wonders_can_be_built_again is enabled, destroyed Wonders become available again for any civ to build, putting them back +; into play. Only applies when enable_wonder_districts is set to true. +completed_wonder_districts_can_be_destroyed = true +destroyed_wonders_can_be_built_again = true + +; Distribution Hubs work as "breadbaskets" and mining areas far from urban centers, minimizing local city potential but benefiting the entire civilization. +; Distribution Hubs make surrounding tiles unworkable and instead distribute their raw food and shield yields to ALL connected cities in your civilization. +; "Divisors" for food and shields multiply the sqrt-based divisor in scale-by-city-count mode, and are a straight divider in flat mode. Yields are subject +; to corruption as with regular shields. +; +; ai_ideal_distribution_hub_count_per_100_cities controls how many hubs the AI tries to maintain per 100 cities if distribution_hub_yield_division_mode +; is set to "flat" (e.g., 25 means the AI aims for 1 hub per 4 cities). +; +; distribution_hub_yield_division_mode controls how a hub splits its collected food/shields across connected cities: +; flat: Divide raw yields by the configured divisors (distribution_hub_food_yield_divisor & distribution_hub_shield_yield_divisor) +; scale-by-city-count: Bonuses gradually reduce as more cities plug into the hub. Formula: floor(raw_yield / (sqrt(connected_city_count) * divisor)) +; +; ai_distribution_hub_build_strategy controls how the AI decides to build distribution hubs: +; by-city-count: AI builds hubs based on its ideal hub count per 100 cities +; auto: AI dynamically assesses need based on city growth and food/shield deficits across civ +distribution_hub_yield_division_mode = scale-by-city-count +ai_distribution_hub_build_strategy = auto +distribution_hub_food_yield_divisor = 2 +distribution_hub_shield_yield_divisor = 2 +ai_ideal_distribution_hub_count_per_100_cities = 50 +max_distribution_hub_count_per_100_cities = 50 + +; Bonus percent applied to Distribution Hub food and shield yields for cities that have a Central Rail Hub district in their work radius. +central_rail_hub_distribution_food_bonus_percent = 25 +central_rail_hub_distribution_shield_bonus_percent = 25 + +; District placement and AI bridge/canal behavior: +; expand_water_tile_checks_to_city_work_area: Use the full city work radius (not just adjacent tiles) for river/lake/sea checks (e.g. to build a port if a +; city has coast within its work area, even if not adjacent to the sea). +; Note that this does not affect Aqueducts or Coastal Fortresses, which still require direct city adjacency. +; workers_can_enter_coast: Allow workers to move onto coast tiles without embarking. +; max_contiguous_bridge_districts: Maximum number of contiguous bridge district tiles allowed in a line (0 = no limit). +; max_contiguous_canal_districts: Maximum number of contiguous canal district tiles allowed in a line (0 = no limit). +; ai_canal_eval_min_bisected_land_tiles: Minimum land tiles required on each side for the AI to consider a canal candidate. +; ai_bridge_canal_eval_block_size: Map block size used when scanning for AI bridge/canal candidates. +; ai_bridge_eval_lake_tile_threshold: Water bodies at or below this size are treated as lakes for AI bridge evaluation. +; ai_can_replace_existing_districts_with_canals: Allow the AI to build canal/bridge districts over existing non-wonder districts. +; ai_builds_bridges: Allow the AI to construct bridge districts. +; ai_builds_canals: Allow the AI to construct canal districts. +expand_water_tile_checks_to_city_work_area = true +workers_can_enter_coast = true +max_contiguous_bridge_districts = 3 +max_contiguous_canal_districts = 5 +ai_canal_eval_min_bisected_land_tiles = 20 +ai_bridge_canal_eval_block_size = 10 +ai_bridge_eval_lake_tile_threshold = 5 +ai_can_replace_existing_districts_with_canals = true +ai_builds_bridges = true +ai_builds_canals = true + +; When enabled, AI defensive units will actively seek out and defend districts within their territory, treating them as valuable assets like colonies. +; The AI prioritizes defending Wonder districts (if destructible wonders are enabled) over regular districts, searching within a 20-tile radius for +; districts that need protection from nearby enemy units. This makes districts meaningful strategic targets and ensures the AI protects its +; infrastructure. Only applies when enable_districts is set to true. +ai_defends_districts = true + +; As AI cities queue up districts needed, the max number of turns to wait for a worker to build it before the request is dropped +; until the AI city is triggered to build the district again (e.g., by trying to build a building that depends on it) +ai_city_district_max_build_wait_turns = 20 + +; Great Wall behavior: +; disable_great_wall_city_defense_bonus: Disables the Great Wall wonder's city defense doubling effect. Only takes effect if districts and great wall districts are enabled. +; great_wall_districts_impassible_by_others: Great Wall district tiles block movement by other civs (unless obsolete). +; auto_build_great_wall_around_territory: Auto-place Great Wall districts along your borders when the specified wonder is built. +; great_wall_auto_build_wonder_name: Name of the wonder that triggers auto-building (empty disables auto-build). +; ai_auto_build_great_wall_strategy: How AI uses auto-built Great Wall: all-borders (any border tiles) or other-civ-bordered-only (only borders touching another civ). +disable_great_wall_city_defense_bonus = false +great_wall_districts_impassible_by_others = true +auto_build_great_wall_around_territory = true +great_wall_auto_build_wonder_name = "The Great Wall" +ai_auto_build_great_wall_strategy = other-civ-bordered-only + +; When enabled, holding down the Control key while a worker is selected will highlight all tiles within the work radii of nearby cities. City centers +; are highlighted more brightly, while tiles that fall within multiple cities' work radii are highlighted more intensely. This visual aid helps you +; strategically place districts and improvements by showing which cities will be affected. The highlights update dynamically as you move the worker +; around the map. Only applies when enable_districts is set to true. +enable_city_work_radii_highlights = true diff --git a/default.districts_config.txt b/default.districts_config.txt index 0e174808..da740387 100644 --- a/default.districts_config.txt +++ b/default.districts_config.txt @@ -1,471 +1,471 @@ -[======================================================================= NOTE =======================================================================] -[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] -[be named scenario.districts_config.txt and must be located in your scenario search folder. Of course it only applies if you are using a scenario. ] -[The user config file must be named user.districts_config.txt and located in the C3X folder, which is the folder where this file is. When creating ] -[scenario or user configs, note that all districts defined here will be removed and only your scenario or user-defined districts will be used ] -[====================================================================================================================================================] - -[ - ; District config fields (each District block begins with "#District") - ; - name : Text (required). Internal district name; must be unique. - ; - display_name : Text. Name shown to user; defaults to name. - ; - tooltip : Text. Shown when hovering over build action button. - ; - img_paths : Comma-separated PCX filenames under Art/Districts/1200/. - 1 for single image, 5 for culture variants (AMER, EURO, ROMAN, MIDEAST, ASIAN). Order matters. - ; - img_column_count : Number. Overrides the number of sprite columns per image (derived from dependent_improvs if omitted). - ; - render_strategy : "by-count" | "by-building". Whether the PCX files show all buildings together, or one building per column. (default: "by-count") - ; - draw_over_resources : 0 or 1. If a resource is also on the tile, draw the district on top. (default: 0) - ; - vary_img_by_era : 0 or 1. If 1, each PCX image must have 4 rows, 1 for each era. - ; - vary_img_by_culture : 0 or 1. If 1, img_paths should list 5 files (AMER, EURO, ROMAN, MIDEAST, ASIAN). - ; - btn_tile_sheet_row : Number. Row index in the district button tile sheet (0-based). - ; - btn_tile_sheet_column : Number. Column index in the district button tile sheet (0-based). - ; - dependent_improvs : Comma-separated city improvement names. Cities can't build these improvements until they have this district. - ; - generated_resource : Resource name plus optional flags: local, yields, no-tech-req. District generates resource if tile connected by road. - ; - advance_prereqs : Comma-separated tech names. District cannot be built unless all techs are discovered. - ; - obsoleted_by : Tech name that obsoletes this district. District cannot built after discovery. - ; - resource_prereqs : Comma-separated resource names. The tile must be connected to cities with all required resources to be built. - ; - resource_prereq_on_tile : Resource name required on the district tile. District cannot be built unless resource is on same tile. - ; - wonder_prereqs : Comma-separated wonder names. District cannot be built unless all Wonders are built by same civ. - ; - natural_wonder_prereqs : Comma-separated natural wonder names. District cannot be built unless all Natural Wonders are within civ's territory. - ; - buildable_on : Comma-separated tile types: desert, plains, grassland, tundra, floodplain, hill, mountain, volcano, - ; coast, sea, ocean, snow-forest, snow-mountain, snow-volcano, lake. (tile must be one of these) - ; - buildable_on_overlays : Comma-separated overlays: irrigation, mine, fortress, barricade, jungle, forest, marsh, airfield. (optional; tile must be one of these). - ; - buildable_on_districts : Comma-separated district names (tile must already have a completed district of any of these types, which it would replace). - ; - buildable_on_rivers : 0 or 1. If 1, district tile must be on a river. - ; - buildable_without_removal : Comma-separated overlays: jungle, forest, marsh. (optional; tile *may* have these, workers don't need to remove them first). - ; - buildable_adjacent_to : Same as buildable_on, plus "city". - ; - buildable_adjacent_to_overlays : Same as buildable_on_overlays. - ; - buildable_adjacent_to_districts : Comma-separated district names (adjacent tile must have a completed district of any of these types). - ; - buildable_by_civs : Comma-separated civ names (e.g., Romans, Egyptians). - ; - buildable_by_civ_traits : Comma-separated trait names (e.g., Commercial, Militaristic). - ; - buildable_by_civ_govs : Comma-separated government names (e.g., Republic, Monarchy). - ; - buildable_by_civ_cultures : Comma-separated culture names (e.g., EURO, ASIAN). - ; - buildable_by_war_allies : 0 or 1. Can build if war allied with a civ that can build it. - ; - buildable_by_pact_allies : 0 or 1. Can build if mutual defense pact allied with a civ that can build it. - ; - ai_build_strategy : "district" | "tile-improvement". If "tile_improvement", the AI may build many. (default: "district") - ; - defense_bonus_percent : Number, with optional "Name: bonus" entries (Name = building or tile type, each added to base bonus if true. Negative values allowed). - ; - culture_bonus : Number, with optional "Name: bonus" entries (same pattern as defense_bonus_percent). - ; - science_bonus : Number, with optional "Name: bonus" entries. - ; - food_bonus : Number, with optional "Name: bonus" entries. - ; - gold_bonus : Number, with optional "Name: bonus" entries. - ; - shield_bonus : Number, with optional "Name: bonus" entries. - ; - happiness_bonus : Number, with optional "Name: bonus" entries. - ; - custom_width : Number (pixels). Override sprite width. (default: 128) - ; - custom_height : Number (pixels). Override sprite height. (default: 64) - ; - x_offset : Number (pixels). Push the sprite farther to the right (or left, if negative). (default: 0) - ; - y_offset : Number (pixels). Push the sprite farther down (or up, if negative). (default: 0) - ; - align_to_coast : 0 or 1. Aligns art to coastline, slightly adjusting x & y pixels. (default: 0) - ; - auto_add_road : 0 or 1. Auto-add road on completion. (default: 0) - ; - auto_add_railroad : 0 or 1. Auto-add railroad on completion. (default: 0) - ; - impassible : 0 or 1. If 1, completed district tile is impassible to units. (default: 0) - ; - impassible_to_wheeled : 0 or 1. If 1, completed district tile is impassible to wheeled units unless connected by road. (default: 0) - ; - allow_irrigation_from : 0 or 1. District can act as an irrigation source. (default: 0) - ; - allow_multiple : 0 or 1. If 1, multiple copies can exist per city. (default: 0) - ; - heal_units_in_one_turn : 0 or 1. Friendly units fully heal when ending turn here. (default: 0) -] - -[=========================================================================] -[=========================STANDARD DISTRICTS==============================] -[=========================================================================] - -#District -name = Encampment -tooltip = Build Encampment -img_paths = Encampment.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 0 -vary_img_by_era = 1 -vary_img_by_culture = 0 -advance_prereqs = Warrior Code -dependent_improvs = Barracks,"SAM Missile Battery" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -heal_units_in_one_turn = 1 -defense_bonus_percent = 50, Barracks: 25, hill: 25 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 1, Barracks: 1 -happiness_bonus = 0 - -#District -name = Holy Site -tooltip = Build Holy Site -img_paths = HolySite_AMER.pcx, HolySite_EURO.pcx, HolySite_ROMAN.pcx, HolySite_MIDEAST.pcx, HolySite_ASIAN.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 1 -vary_img_by_era = 0 -vary_img_by_culture = 1 -advance_prereqs = "Ceremonial Burial" -dependent_improvs = Temple,Cathedral -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 2, Temple: 2, Cathedral: 2 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Campus -tooltip = Build Campus -img_paths = Campus.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 2 -vary_img_by_era = 1 -vary_img_by_culture = 0 -advance_prereqs = Literature -dependent_improvs = Library, University -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 1, Library: 2, University: 2 -science_bonus = 1, Library: 2, University: 2 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Entertainment Complex -tooltip = Build Entertainment Complex -img_paths = EntertainmentComplex_AMER.pcx, EntertainmentComplex_EURO.pcx, EntertainmentComplex_ROMAN.pcx, EntertainmentComplex_MIDEAST.pcx, EntertainmentComplex_ASIAN.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 3 -vary_img_by_era = 1 -vary_img_by_culture = 1 -advance_prereqs = Construction -dependent_improvs = Colosseum -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 1, Colosseum: 1 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 2, Colosseum: 1 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Commercial Hub -tooltip = Build Commercial Hub -img_paths = CommercialHub_AMER.pcx, CommercialHub_EURO.pcx, CommercialHub_ROMAN.pcx, CommercialHub_MIDEAST.pcx, CommercialHub_ASIAN.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 4 -vary_img_by_era = 1 -vary_img_by_culture = 1 -advance_prereqs = Currency -dependent_improvs = Marketplace, Bank, "Stock Exchange" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0, Marketplace: 1 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 2, Marketplace: 1, Bank: 1, "Stock Exchange": 1, river: 2 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Industrial Zone -tooltip = Build Industrial Zone -img_paths = IndustrialZone.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 5 -vary_img_by_era = 1 -vary_img_by_culture = 0 -advance_prereqs = Industrialization -dependent_improvs = Factory, "Manufacturing Plant" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 2, Factory: 2, "Manufacturing Plant": 2, river: 2 -happiness_bonus = 0 - -#District -name = Data Center -tooltip = Build Data Center -img_paths = DataCenter.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 6 -vary_img_by_era = 1 -vary_img_by_culture = 0 -advance_prereqs = Computers -dependent_improvs = "Research Lab" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 4, "Research Lab": 4 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = -2 - -#District -name = Offshore Extraction Zone -tooltip = Build Offshore Extraction Zone -img_paths = OffshoreExtractionZone.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 7 -vary_img_by_era = 0 -vary_img_by_culture = 0 -advance_prereqs = Miniaturization -dependent_improvs = Offshore Platform -buildable_on = coast -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 2 -happiness_bonus = 0 - -#District -name = Park -tooltip = Build Park -img_paths = Park.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 8 -vary_img_by_era = 1 -vary_img_by_culture = 0 -advance_prereqs = Engineering -dependent_improvs = -buildable_on_overlays = forest -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 2 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 2 - -#District -name = Ski Resort -tooltip = Build Ski Resort -img_paths = SkiResort.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 9 -vary_img_by_era = 0 -vary_img_by_culture = 0 -advance_prereqs = Electricity -dependent_improvs = -buildable_on = snow-mountain -custom_height = 88 -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 2 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 4 -shield_bonus = 0 -happiness_bonus = 2 - -#District -name = Water Park -tooltip = Build Water Park -img_paths = WaterPark.pcx -btn_tile_sheet_row = 1 -btn_tile_sheet_column = 10 -vary_img_by_era = 0 -vary_img_by_culture = 0 -advance_prereqs = Miniaturization -dependent_improvs = -buildable_on = coast -custom_height = 88 -defense_bonus_percent = 0 -allow_multiple = 0 -culture_bonus = 2 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 4 -shield_bonus = -2 -happiness_bonus = 2 - -[========================================================================] -[=========================SPECIAL DISTRICTS==============================] -[========================================================================] - -#District -name = Neighborhood -tooltip = Build Neighborhood -buildable_on = desert,plains,grassland,tundra,floodplain,hill -advance_prereqs = -auto_add_road = 1 -defense_bonus_percent = 25 -allow_multiple = 1 -culture_bonus = 1 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 1 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Wonder District -tooltip = Build Wonder District -buildable_on = desert,plains,grassland,tundra,floodplain,hill,coast,mountain -advance_prereqs = -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Distribution Hub -tooltip = Build Distribution Hub -buildable_on = desert,plains,grassland,tundra,floodplain,hill -advance_prereqs = Construction -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Aerodrome -tooltip = Build Aerodrome -buildable_on = desert,plains,grassland,tundra,floodplain,hill -advance_prereqs = Flight -dependent_improvs = Airport -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Port -tooltip = Build Port -buildable_on = coast -advance_prereqs = Map Making -dependent_improvs = Harbor, "Commercial Dock" -heal_units_in_one_turn = 1 -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 2 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Central Rail Hub -tooltip = Build Central Rail Hub -btn_tile_sheet_row = 0 -btn_tile_sheet_column = 5 -vary_img_by_era = 1 -vary_img_by_culture = 1 -advance_prereqs = Steam Power -resource_prereqs = Iron, Coal -dependent_improvs = "Mass Transit System" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -auto_add_railroad = 1 -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 4 -happiness_bonus = 0 - -#District -name = Energy Grid -tooltip = Build Energy Grid -btn_tile_sheet_row = 0 -btn_tile_sheet_column = 6 -vary_img_by_era = 1 -vary_img_by_culture = 0 -custom_height = 88 -advance_prereqs = Industrialization -dependent_improvs = "Coal Plant", "Hydro Plant", "Nuclear Plant", "Solar Plant" -buildable_on = desert,plains,grassland,tundra,floodplain,hill -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 2 -happiness_bonus = 0 - -#District -name = Bridge -tooltip = Build Bridge -btn_tile_sheet_row = 0 -btn_tile_sheet_column = 7 -custom_height = 112 -custom_width = 176 -y_offset = 24 -x_offset = 0 -advance_prereqs = Industrialization -buildable_on = coast -auto_add_road = 1 -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Canal -tooltip = Build Canal -btn_tile_sheet_row = 0 -btn_tile_sheet_column = 8 -custom_height = 112 -custom_width = 176 -y_offset = 24 -x_offset = 0 -advance_prereqs = Industrialization -buildable_on = desert,plains,grassland,tundra,floodplain -defense_bonus_percent = 0 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 - -#District -name = Great Wall -btn_tile_sheet_row = 0 -btn_tile_sheet_column = 9 -tooltip = Build Great Wall -obsoleted_by = Metallurgy -wonder_prereqs = "The Great Wall" -buildable_on = desert,plains,grassland,tundra,floodplain,mountain,hill,volcano -buildable_without_removal = forest,marsh,jungle -draw_over_resources = 1 -defense_bonus_percent = 50 -allow_multiple = 1 -culture_bonus = 0 -science_bonus = 0 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 0 +[======================================================================= NOTE =======================================================================] +[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] +[be named scenario.districts_config.txt and must be located in your scenario search folder. Of course it only applies if you are using a scenario. ] +[The user config file must be named user.districts_config.txt and located in the C3X folder, which is the folder where this file is. When creating ] +[scenario or user configs, note that all districts defined here will be removed and only your scenario or user-defined districts will be used ] +[====================================================================================================================================================] + +[ + ; District config fields (each District block begins with "#District") + ; - name : Text (required). Internal district name; must be unique. + ; - display_name : Text. Name shown to user; defaults to name. + ; - tooltip : Text. Shown when hovering over build action button. + ; - img_paths : Comma-separated PCX filenames under Art/Districts/1200/. + 1 for single image, 5 for culture variants (AMER, EURO, ROMAN, MIDEAST, ASIAN). Order matters. + ; - img_column_count : Number. Overrides the number of sprite columns per image (derived from dependent_improvs if omitted). + ; - render_strategy : "by-count" | "by-building". Whether the PCX files show all buildings together, or one building per column. (default: "by-count") + ; - draw_over_resources : 0 or 1. If a resource is also on the tile, draw the district on top. (default: 0) + ; - vary_img_by_era : 0 or 1. If 1, each PCX image must have 4 rows, 1 for each era. + ; - vary_img_by_culture : 0 or 1. If 1, img_paths should list 5 files (AMER, EURO, ROMAN, MIDEAST, ASIAN). + ; - btn_tile_sheet_row : Number. Row index in the district button tile sheet (0-based). + ; - btn_tile_sheet_column : Number. Column index in the district button tile sheet (0-based). + ; - dependent_improvs : Comma-separated city improvement names. Cities can't build these improvements until they have this district. + ; - generated_resource : Resource name plus optional flags: local, yields, no-tech-req. District generates resource if tile connected by road. + ; - advance_prereqs : Comma-separated tech names. District cannot be built unless all techs are discovered. + ; - obsoleted_by : Tech name that obsoletes this district. District cannot built after discovery. + ; - resource_prereqs : Comma-separated resource names. The tile must be connected to cities with all required resources to be built. + ; - resource_prereq_on_tile : Resource name required on the district tile. District cannot be built unless resource is on same tile. + ; - wonder_prereqs : Comma-separated wonder names. District cannot be built unless all Wonders are built by same civ. + ; - natural_wonder_prereqs : Comma-separated natural wonder names. District cannot be built unless all Natural Wonders are within civ's territory. + ; - buildable_on : Comma-separated tile types: desert, plains, grassland, tundra, floodplain, hill, mountain, volcano, + ; coast, sea, ocean, snow-forest, snow-mountain, snow-volcano, lake. (tile must be one of these) + ; - buildable_on_overlays : Comma-separated overlays: irrigation, mine, fortress, barricade, jungle, forest, marsh, airfield. (optional; tile must be one of these). + ; - buildable_on_districts : Comma-separated district names (tile must already have a completed district of any of these types, which it would replace). + ; - buildable_on_rivers : 0 or 1. If 1, district tile must be on a river. + ; - buildable_without_removal : Comma-separated overlays: jungle, forest, marsh. (optional; tile *may* have these, workers don't need to remove them first). + ; - buildable_adjacent_to : Same as buildable_on, plus "city". + ; - buildable_adjacent_to_overlays : Same as buildable_on_overlays. + ; - buildable_adjacent_to_districts : Comma-separated district names (adjacent tile must have a completed district of any of these types). + ; - buildable_by_civs : Comma-separated civ names (e.g., Romans, Egyptians). + ; - buildable_by_civ_traits : Comma-separated trait names (e.g., Commercial, Militaristic). + ; - buildable_by_civ_govs : Comma-separated government names (e.g., Republic, Monarchy). + ; - buildable_by_civ_cultures : Comma-separated culture names (e.g., EURO, ASIAN). + ; - buildable_by_war_allies : 0 or 1. Can build if war allied with a civ that can build it. + ; - buildable_by_pact_allies : 0 or 1. Can build if mutual defense pact allied with a civ that can build it. + ; - ai_build_strategy : "district" | "tile-improvement". If "tile_improvement", the AI may build many. (default: "district") + ; - defense_bonus_percent : Number, with optional "Name: bonus" entries (Name = building or tile type, each added to base bonus if true. Negative values allowed). + ; - culture_bonus : Number, with optional "Name: bonus" entries (same pattern as defense_bonus_percent). + ; - science_bonus : Number, with optional "Name: bonus" entries. + ; - food_bonus : Number, with optional "Name: bonus" entries. + ; - gold_bonus : Number, with optional "Name: bonus" entries. + ; - shield_bonus : Number, with optional "Name: bonus" entries. + ; - happiness_bonus : Number, with optional "Name: bonus" entries. + ; - custom_width : Number (pixels). Override sprite width. (default: 128) + ; - custom_height : Number (pixels). Override sprite height. (default: 64) + ; - x_offset : Number (pixels). Push the sprite farther to the right (or left, if negative). (default: 0) + ; - y_offset : Number (pixels). Push the sprite farther down (or up, if negative). (default: 0) + ; - align_to_coast : 0 or 1. Aligns art to coastline, slightly adjusting x & y pixels. (default: 0) + ; - auto_add_road : 0 or 1. Auto-add road on completion. (default: 0) + ; - auto_add_railroad : 0 or 1. Auto-add railroad on completion. (default: 0) + ; - impassible : 0 or 1. If 1, completed district tile is impassible to units. (default: 0) + ; - impassible_to_wheeled : 0 or 1. If 1, completed district tile is impassible to wheeled units unless connected by road. (default: 0) + ; - allow_irrigation_from : 0 or 1. District can act as an irrigation source. (default: 0) + ; - allow_multiple : 0 or 1. If 1, multiple copies can exist per city. (default: 0) + ; - heal_units_in_one_turn : 0 or 1. Friendly units fully heal when ending turn here. (default: 0) +] + +[=========================================================================] +[=========================STANDARD DISTRICTS==============================] +[=========================================================================] + +#District +name = Encampment +tooltip = Build Encampment +img_paths = Encampment.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 0 +vary_img_by_era = 1 +vary_img_by_culture = 0 +advance_prereqs = Warrior Code +dependent_improvs = Barracks,"SAM Missile Battery" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +heal_units_in_one_turn = 1 +defense_bonus_percent = 50, Barracks: 25, hill: 25 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 1, Barracks: 1 +happiness_bonus = 0 + +#District +name = Holy Site +tooltip = Build Holy Site +img_paths = HolySite_AMER.pcx, HolySite_EURO.pcx, HolySite_ROMAN.pcx, HolySite_MIDEAST.pcx, HolySite_ASIAN.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 1 +vary_img_by_era = 0 +vary_img_by_culture = 1 +advance_prereqs = "Ceremonial Burial" +dependent_improvs = Temple,Cathedral +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 2, Temple: 2, Cathedral: 2 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Campus +tooltip = Build Campus +img_paths = Campus.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 2 +vary_img_by_era = 1 +vary_img_by_culture = 0 +advance_prereqs = Literature +dependent_improvs = Library, University +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 1, Library: 2, University: 2 +science_bonus = 1, Library: 2, University: 2 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Entertainment Complex +tooltip = Build Entertainment Complex +img_paths = EntertainmentComplex_AMER.pcx, EntertainmentComplex_EURO.pcx, EntertainmentComplex_ROMAN.pcx, EntertainmentComplex_MIDEAST.pcx, EntertainmentComplex_ASIAN.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 3 +vary_img_by_era = 1 +vary_img_by_culture = 1 +advance_prereqs = Construction +dependent_improvs = Colosseum +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 1, Colosseum: 1 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 2, Colosseum: 1 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Commercial Hub +tooltip = Build Commercial Hub +img_paths = CommercialHub_AMER.pcx, CommercialHub_EURO.pcx, CommercialHub_ROMAN.pcx, CommercialHub_MIDEAST.pcx, CommercialHub_ASIAN.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 4 +vary_img_by_era = 1 +vary_img_by_culture = 1 +advance_prereqs = Currency +dependent_improvs = Marketplace, Bank, "Stock Exchange" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0, Marketplace: 1 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 2, Marketplace: 1, Bank: 1, "Stock Exchange": 1, river: 2 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Industrial Zone +tooltip = Build Industrial Zone +img_paths = IndustrialZone.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 5 +vary_img_by_era = 1 +vary_img_by_culture = 0 +advance_prereqs = Industrialization +dependent_improvs = Factory, "Manufacturing Plant" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 2, Factory: 2, "Manufacturing Plant": 2, river: 2 +happiness_bonus = 0 + +#District +name = Data Center +tooltip = Build Data Center +img_paths = DataCenter.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 6 +vary_img_by_era = 1 +vary_img_by_culture = 0 +advance_prereqs = Computers +dependent_improvs = "Research Lab" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 4, "Research Lab": 4 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = -2 + +#District +name = Offshore Extraction Zone +tooltip = Build Offshore Extraction Zone +img_paths = OffshoreExtractionZone.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 7 +vary_img_by_era = 0 +vary_img_by_culture = 0 +advance_prereqs = Miniaturization +dependent_improvs = Offshore Platform +buildable_on = coast +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 2 +happiness_bonus = 0 + +#District +name = Park +tooltip = Build Park +img_paths = Park.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 8 +vary_img_by_era = 1 +vary_img_by_culture = 0 +advance_prereqs = Engineering +dependent_improvs = +buildable_on_overlays = forest +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 2 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 2 + +#District +name = Ski Resort +tooltip = Build Ski Resort +img_paths = SkiResort.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 9 +vary_img_by_era = 0 +vary_img_by_culture = 0 +advance_prereqs = Electricity +dependent_improvs = +buildable_on = snow-mountain +custom_height = 88 +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 2 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 4 +shield_bonus = 0 +happiness_bonus = 2 + +#District +name = Water Park +tooltip = Build Water Park +img_paths = WaterPark.pcx +btn_tile_sheet_row = 1 +btn_tile_sheet_column = 10 +vary_img_by_era = 0 +vary_img_by_culture = 0 +advance_prereqs = Miniaturization +dependent_improvs = +buildable_on = coast +custom_height = 88 +defense_bonus_percent = 0 +allow_multiple = 0 +culture_bonus = 2 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 4 +shield_bonus = -2 +happiness_bonus = 2 + +[========================================================================] +[=========================SPECIAL DISTRICTS==============================] +[========================================================================] + +#District +name = Neighborhood +tooltip = Build Neighborhood +buildable_on = desert,plains,grassland,tundra,floodplain,hill +advance_prereqs = +auto_add_road = 1 +defense_bonus_percent = 25 +allow_multiple = 1 +culture_bonus = 1 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 1 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Wonder District +tooltip = Build Wonder District +buildable_on = desert,plains,grassland,tundra,floodplain,hill,coast,mountain +advance_prereqs = +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Distribution Hub +tooltip = Build Distribution Hub +buildable_on = desert,plains,grassland,tundra,floodplain,hill +advance_prereqs = Construction +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Aerodrome +tooltip = Build Aerodrome +buildable_on = desert,plains,grassland,tundra,floodplain,hill +advance_prereqs = Flight +dependent_improvs = Airport +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Port +tooltip = Build Port +buildable_on = coast +advance_prereqs = Map Making +dependent_improvs = Harbor, "Commercial Dock" +heal_units_in_one_turn = 1 +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 2 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Central Rail Hub +tooltip = Build Central Rail Hub +btn_tile_sheet_row = 0 +btn_tile_sheet_column = 5 +vary_img_by_era = 1 +vary_img_by_culture = 1 +advance_prereqs = Steam Power +resource_prereqs = Iron, Coal +dependent_improvs = "Mass Transit System" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +auto_add_railroad = 1 +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 4 +happiness_bonus = 0 + +#District +name = Energy Grid +tooltip = Build Energy Grid +btn_tile_sheet_row = 0 +btn_tile_sheet_column = 6 +vary_img_by_era = 1 +vary_img_by_culture = 0 +custom_height = 88 +advance_prereqs = Industrialization +dependent_improvs = "Coal Plant", "Hydro Plant", "Nuclear Plant", "Solar Plant" +buildable_on = desert,plains,grassland,tundra,floodplain,hill +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 2 +happiness_bonus = 0 + +#District +name = Bridge +tooltip = Build Bridge +btn_tile_sheet_row = 0 +btn_tile_sheet_column = 7 +custom_height = 112 +custom_width = 176 +y_offset = 24 +x_offset = 0 +advance_prereqs = Industrialization +buildable_on = coast +auto_add_road = 1 +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Canal +tooltip = Build Canal +btn_tile_sheet_row = 0 +btn_tile_sheet_column = 8 +custom_height = 112 +custom_width = 176 +y_offset = 24 +x_offset = 0 +advance_prereqs = Industrialization +buildable_on = desert,plains,grassland,tundra,floodplain +defense_bonus_percent = 0 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 + +#District +name = Great Wall +btn_tile_sheet_row = 0 +btn_tile_sheet_column = 9 +tooltip = Build Great Wall +obsoleted_by = Metallurgy +wonder_prereqs = "The Great Wall" +buildable_on = desert,plains,grassland,tundra,floodplain,mountain,hill,volcano +buildable_without_removal = forest,marsh,jungle +draw_over_resources = 1 +defense_bonus_percent = 50 +allow_multiple = 1 +culture_bonus = 0 +science_bonus = 0 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 0 diff --git a/default.districts_natural_wonders_config.txt b/default.districts_natural_wonders_config.txt index 1d43b444..e09ed806 100644 --- a/default.districts_natural_wonders_config.txt +++ b/default.districts_natural_wonders_config.txt @@ -1,279 +1,279 @@ -[======================================================================= NOTE =======================================================================] -[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] -[be named scenario.districts_natural_wonders_config.txt and must be located in your scenario search folder. Of course it only applies if you are ] -[using a scenario. The user config file must be named user.districts_natural_wonders_config.txt and located in the C3X folder, which is the folder ] -[where this file is. When creating scenario or user configs, note that all natural wonders defined here will be removed and only your scenario or ] -[user-defined districts will be used. ] -[====================================================================================================================================================] - -[ - ; Natural Wonder config fields (each Wonder block begins with "#Wonder") - ; - name : Text (required). Internal natural wonder name; must be unique. - ; - terrain_type : Text (required). Base terrain: desert, plains, grassland, jungle, tundra, floodplain, marsh, hill, mountain, - forest, volcano, snow-forest, snow-mountain, snow-volcano, coast, sea, ocean. - ; - adjacent_to : Text. Optional adjacency requirement: same list as buildable square types plus river, any (no requirement). - ; - adjacency_dir : Text. Optional direction filter for adjacent_to (northeast, east, southeast, south, southwest, west, northwest, north). - ; - img_path : Text (required). PCX filename (under Art/Districts/1200/). - ; - img_row : Number (required). Row index in the PCX (0-based). - ; - img_column : Number (required). Column index in the PCX (0-based). - ; - culture_bonus : Number. Culture yield bonus when worked. - ; - science_bonus : Number. Science yield bonus when worked. - ; - food_bonus : Number. Food yield bonus when worked. - ; - gold_bonus : Number. Gold yield bonus when worked. - ; - shield_bonus : Number. Shield yield bonus when worked. - ; - happiness_bonus : Number. Happiness bonus when worked. - ; - impassible : 0 or 1. If 1, completed natural wonder tile is impassible to units. (default: 0) - ; - impassible_to_wheeled : 0 or 1. If 1, completed natural wonder tile is impassible to wheeled units unless connected by road. (default: 0) -] - -#Wonder -name = Angel Falls -terrain_type = grassland -adjacent_to = river -adjacency_dir = southeast -img_path = NaturalWonders.pcx -img_row = 0 -img_column = 0 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Yosemite -terrain_type = grassland -adjacent_to = forest -img_path = NaturalWonders.pcx -img_row = 0 -img_column = 1 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Mount Fuji -terrain_type = grassland -img_path = NaturalWonders.pcx -img_row = 0 -img_column = 2 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Yellowstone -terrain_type = grassland -adjacent_to = forest -img_path = NaturalWonders.pcx -img_row = 0 -img_column = 3 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Mount Everest -terrain_type = grassland -adjacent_to = snow-mountains -img_path = NaturalWonders.pcx -img_row = 1 -img_column = 0 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Zhangjiajie Mountains -terrain_type = jungle -adjacent_to = jungle -img_path = NaturalWonders.pcx -img_row = 1 -img_column = 1 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Mount Kilimanjaro -terrain_type = grassland -img_path = NaturalWonders.pcx -img_row = 1 -img_column = 2 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Great Barrier Reef -terrain_type = sea -adjacent_to = coast -img_path = NaturalWonders.pcx -img_row = 1 -img_column = 3 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Matterhorn -terrain_type = grassland -adjacent_to = snow-mountains -img_path = NaturalWonders.pcx -img_row = 2 -img_column = 0 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Moraine Lake -terrain_type = grassland -adjacent_to = mountains -img_path = NaturalWonders.pcx -img_row = 2 -img_column = 1 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Tropical Rainforest -terrain_type = jungle -adjacent_to = jungle -img_path = NaturalWonders.pcx -img_row = 2 -img_column = 2 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Wadi Rum -terrain_type = desert -adjacent_to = desert -img_path = NaturalWonders.pcx -img_row = 2 -img_column = 3 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Eyjafjallajokull -terrain_type = tundra -adjacent_to = tundra -img_path = NaturalWonders.pcx -img_row = 3 -img_column = 0 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Ha Long Bay -terrain_type = coast -adjacent_to = sea -img_path = NaturalWonders.pcx -img_row = 3 -img_column = 1 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Lofoten Skerries -terrain_type = coast -adjacent_to = tundra -img_path = NaturalWonders.pcx -img_row = 3 -img_column = 2 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Geirangerfjord -terrain_type = tundra -adjacent_to = coast -adjacency_dir = south -img_path = NaturalWonders.pcx -img_row = 3 -img_column = 3 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Delicate Arch -terrain_type = desert -adjacent_to = desert -img_path = NaturalWonders.pcx -img_row = 4 -img_column = 0 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 -happiness_bonus = 1 - -#Wonder -name = Savanna -terrain_type = plains -adjacent_to = plains -img_path = NaturalWonders.pcx -img_row = 4 -img_column = 1 -culture_bonus = 2 -science_bonus = 1 -food_bonus = 0 -gold_bonus = 0 -shield_bonus = 0 +[======================================================================= NOTE =======================================================================] +[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] +[be named scenario.districts_natural_wonders_config.txt and must be located in your scenario search folder. Of course it only applies if you are ] +[using a scenario. The user config file must be named user.districts_natural_wonders_config.txt and located in the C3X folder, which is the folder ] +[where this file is. When creating scenario or user configs, note that all natural wonders defined here will be removed and only your scenario or ] +[user-defined districts will be used. ] +[====================================================================================================================================================] + +[ + ; Natural Wonder config fields (each Wonder block begins with "#Wonder") + ; - name : Text (required). Internal natural wonder name; must be unique. + ; - terrain_type : Text (required). Base terrain: desert, plains, grassland, jungle, tundra, floodplain, marsh, hill, mountain, + forest, volcano, snow-forest, snow-mountain, snow-volcano, coast, sea, ocean. + ; - adjacent_to : Text. Optional adjacency requirement: same list as buildable square types plus river, any (no requirement). + ; - adjacency_dir : Text. Optional direction filter for adjacent_to (northeast, east, southeast, south, southwest, west, northwest, north). + ; - img_path : Text (required). PCX filename (under Art/Districts/1200/). + ; - img_row : Number (required). Row index in the PCX (0-based). + ; - img_column : Number (required). Column index in the PCX (0-based). + ; - culture_bonus : Number. Culture yield bonus when worked. + ; - science_bonus : Number. Science yield bonus when worked. + ; - food_bonus : Number. Food yield bonus when worked. + ; - gold_bonus : Number. Gold yield bonus when worked. + ; - shield_bonus : Number. Shield yield bonus when worked. + ; - happiness_bonus : Number. Happiness bonus when worked. + ; - impassible : 0 or 1. If 1, completed natural wonder tile is impassible to units. (default: 0) + ; - impassible_to_wheeled : 0 or 1. If 1, completed natural wonder tile is impassible to wheeled units unless connected by road. (default: 0) +] + +#Wonder +name = Angel Falls +terrain_type = grassland +adjacent_to = river +adjacency_dir = southeast +img_path = NaturalWonders.pcx +img_row = 0 +img_column = 0 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Yosemite +terrain_type = grassland +adjacent_to = forest +img_path = NaturalWonders.pcx +img_row = 0 +img_column = 1 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Mount Fuji +terrain_type = grassland +img_path = NaturalWonders.pcx +img_row = 0 +img_column = 2 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Yellowstone +terrain_type = grassland +adjacent_to = forest +img_path = NaturalWonders.pcx +img_row = 0 +img_column = 3 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Mount Everest +terrain_type = grassland +adjacent_to = snow-mountains +img_path = NaturalWonders.pcx +img_row = 1 +img_column = 0 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Zhangjiajie Mountains +terrain_type = jungle +adjacent_to = jungle +img_path = NaturalWonders.pcx +img_row = 1 +img_column = 1 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Mount Kilimanjaro +terrain_type = grassland +img_path = NaturalWonders.pcx +img_row = 1 +img_column = 2 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Great Barrier Reef +terrain_type = sea +adjacent_to = coast +img_path = NaturalWonders.pcx +img_row = 1 +img_column = 3 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Matterhorn +terrain_type = grassland +adjacent_to = snow-mountains +img_path = NaturalWonders.pcx +img_row = 2 +img_column = 0 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Moraine Lake +terrain_type = grassland +adjacent_to = mountains +img_path = NaturalWonders.pcx +img_row = 2 +img_column = 1 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Tropical Rainforest +terrain_type = jungle +adjacent_to = jungle +img_path = NaturalWonders.pcx +img_row = 2 +img_column = 2 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Wadi Rum +terrain_type = desert +adjacent_to = desert +img_path = NaturalWonders.pcx +img_row = 2 +img_column = 3 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Eyjafjallajokull +terrain_type = tundra +adjacent_to = tundra +img_path = NaturalWonders.pcx +img_row = 3 +img_column = 0 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Ha Long Bay +terrain_type = coast +adjacent_to = sea +img_path = NaturalWonders.pcx +img_row = 3 +img_column = 1 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Lofoten Skerries +terrain_type = coast +adjacent_to = tundra +img_path = NaturalWonders.pcx +img_row = 3 +img_column = 2 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Geirangerfjord +terrain_type = tundra +adjacent_to = coast +adjacency_dir = south +img_path = NaturalWonders.pcx +img_row = 3 +img_column = 3 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Delicate Arch +terrain_type = desert +adjacent_to = desert +img_path = NaturalWonders.pcx +img_row = 4 +img_column = 0 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 +happiness_bonus = 1 + +#Wonder +name = Savanna +terrain_type = plains +adjacent_to = plains +img_path = NaturalWonders.pcx +img_row = 4 +img_column = 1 +culture_bonus = 2 +science_bonus = 1 +food_bonus = 0 +gold_bonus = 0 +shield_bonus = 0 happiness_bonus = 1 \ No newline at end of file diff --git a/default.districts_wonders_config.txt b/default.districts_wonders_config.txt index 48d5bca1..36478d22 100644 --- a/default.districts_wonders_config.txt +++ b/default.districts_wonders_config.txt @@ -1,233 +1,233 @@ -[======================================================================= NOTE =======================================================================] -[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] -[be named scenario.districts_wonders_config.txt and must be located in your scenario search folder. Of course it only applies if you are using a ] -[scenario. The user config file must be named user.districts_wonders_config.txt and located in the C3X folder, which is the folder where this file ] -[is. When creating scenario or user configs, note that all wonders defined here will be removed and only your scenario or user-defined districts will] -[be used. ] -[====================================================================================================================================================] - -[ - ; Wonder config fields (each Wonder block begins with "#Wonder") - ; - name : Text (required). Must match the in-game Wonder improvement name. - ; - buildable_on : Comma-separated tile types: desert, plains, grassland, tundra, floodplain, hills, mountains, volcano, - coast, sea, ocean, snow-forest, snow-mountains, snow-volcano, lake. - ; - buildable_on_rivers : 0 or 1. If 1, Wonder can only be built if tile has river. - ; - buildable_adjacent_to : Same as buildable_on, plus "city". - ; - buildable_adjacent_to_overlays : Same overlay list as districts. - ; - buildable_by_civs : Comma-separated civ names (e.g., Romans, Egyptians). - ; - buildable_by_civ_traits : Comma-separated trait names (e.g., Commercial, Militaristic). - ; - buildable_by_civ_govs : Comma-separated government names (e.g., Republic, Monarchy). - ; - buildable_by_civ_cultures : Comma-separated culture names (e.g., EURO, ASIAN). - ; - img_path : Text. PCX filename (under Art/Districts/1200/). Defaults to Wonders.pcx if omitted. - ; - img_construct_row : Number (required). Row index in the PCX for the "under construction" wonder art (0-based). - ; - img_construct_column : Number (required). Column index in the PCX for the "under construction" wonder art (0-based). - ; - img_row : Number (required). Row index in the PCX for the completed wonder art (0-based). - ; - img_column : Number (required). Column index in the PCX for the completed wonder art (0-based). - ; - enable_img_alt_dir : 0 or 1. If 1, use alternate art when river/city direction implies a flip (see img_alt_dir_* fields). - ; - img_alt_dir_construct_row : Number. Row index for alternate "under construction" art (0-based). - ; - img_alt_dir_construct_column : Number. Column index for alternate "under construction" art (0-based). - ; - img_alt_dir_row : Number. Row index for alternate completed art (0-based). - ; - img_alt_dir_column : Number. Column index for alternate completed art (0-based). - ; - custom_width : Number (pixels). Override wonder sprite width. (default: 128) - ; - custom_height : Number (pixels). Override wonder sprite height. (default: 64) -] - -#Wonder -name = The Pyramids -buildable_on = desert -img_path = Wonders.pcx -img_construct_row = 0 -img_construct_column = 0 -img_row = 0 -img_column = 1 - -#Wonder -name = The Hanging Gardens -img_path = Wonders.pcx -img_construct_row = 0 -img_construct_column = 2 -img_row = 0 -img_column = 3 - -#Wonder -name = The Oracle -buildable_on = hills -img_path = Wonders.pcx -img_construct_row = 1 -img_construct_column = 0 -img_row = 1 -img_column = 1 - -#Wonder -name = The Temple of Artemis -img_path = Wonders.pcx -img_construct_row = 1 -img_construct_column = 2 -img_row = 1 -img_column = 3 - -#Wonder -name = The Mausoleum of Mausollos -img_path = Wonders.pcx -img_construct_row = 2 -img_construct_column = 0 -img_row = 2 -img_column = 1 - -#Wonder -name = The Statue of Zeus -img_path = Wonders.pcx -img_construct_row = 2 -img_construct_column = 2 -img_row = 2 -img_column = 3 - -#Wonder -name = The Great Library -img_path = Wonders.pcx -img_construct_row = 3 -img_construct_column = 0 -img_row = 3 -img_column = 1 - -#Wonder -name = Copernicus' Observatory -img_path = Wonders.pcx -img_construct_row = 3 -img_construct_column = 2 -img_row = 3 -img_column = 3 - -#Wonder -name = JS Bach's Cathedral -img_path = Wonders_2.pcx -img_construct_row = 0 -img_construct_column = 0 -img_row = 0 -img_column = 1 - -#Wonder -name = Newton's University -img_path = Wonders_2.pcx -img_construct_row = 0 -img_construct_column = 2 -img_row = 0 -img_column = 3 - -#Wonder -name = SETI program -img_path = Wonders_2.pcx -img_construct_row = 1 -img_construct_column = 0 -img_row = 1 -img_column = 1 - -#Wonder -name = Shakespeare's Theater -img_path = Wonders_2.pcx -img_construct_row = 1 -img_construct_column = 2 -img_row = 1 -img_column = 3 - -#Wonder -name = Sistine Chapel -img_path = Wonders_2.pcx -img_construct_row = 2 -img_construct_column = 0 -img_row = 2 -img_column = 1 - -#Wonder -name = The Great Lighthouse -buildable_on = coast -img_path = Wonders_2.pcx -img_construct_row = 2 -img_construct_column = 2 -img_row = 2 -img_column = 3 - -#Wonder -name = The Colossus -buildable_on = coast -enable_img_alt_dir = 1 -img_path = Wonders_2.pcx -img_construct_row = 3 -img_construct_column = 0 -img_row = 3 -img_column = 1 -img_alt_dir_construct_row = 3 -img_alt_dir_construct_column = 2 -img_alt_dir_row = 3 -img_alt_dir_column = 3 - -#Wonder -name = Hoover Dam -buildable_on = mountains -buildable_on_rivers = 1 -enable_img_alt_dir = 1 -img_path = Wonders_3.pcx -img_construct_row = 0 -img_construct_column = 0 -img_row = 0 -img_column = 1 -img_alt_dir_construct_row = 0 -img_alt_dir_construct_column = 2 -img_alt_dir_row = 0 -img_alt_dir_column = 3 - -#Wonder -name = Apollo Program -img_path = SmallWonders.pcx -img_construct_row = 0 -img_construct_column = 0 -img_row = 0 -img_column = 1 - -#Wonder -name = Forbidden Palace -img_path = SmallWonders.pcx -img_construct_row = 0 -img_construct_column = 2 -img_row = 0 -img_column = 3 - -#Wonder -name = Intelligence Agency -img_path = SmallWonders.pcx -img_construct_row = 1 -img_construct_column = 0 -img_row = 1 -img_column = 1 - -#Wonder -name = The Pentagon -img_path = SmallWonders.pcx -img_construct_row = 1 -img_construct_column = 2 -img_row = 1 -img_column = 3 - -#Wonder -name = Military Academy -img_path = SmallWonders.pcx -img_construct_row = 2 -img_construct_column = 0 -img_row = 2 -img_column = 1 - -#Wonder -name = Iron Works -img_path = SmallWonders.pcx -img_construct_row = 2 -img_construct_column = 2 -img_row = 2 -img_column = 3 - -#Wonder -name = Wall Street -img_path = SmallWonders.pcx -img_construct_row = 3 -img_construct_column = 0 -img_row = 3 -img_column = 1 +[======================================================================= NOTE =======================================================================] +[Instead of editing this file, changes to the settings should be placed in either the scenario or user config files. The scenario config file must ] +[be named scenario.districts_wonders_config.txt and must be located in your scenario search folder. Of course it only applies if you are using a ] +[scenario. The user config file must be named user.districts_wonders_config.txt and located in the C3X folder, which is the folder where this file ] +[is. When creating scenario or user configs, note that all wonders defined here will be removed and only your scenario or user-defined districts will] +[be used. ] +[====================================================================================================================================================] + +[ + ; Wonder config fields (each Wonder block begins with "#Wonder") + ; - name : Text (required). Must match the in-game Wonder improvement name. + ; - buildable_on : Comma-separated tile types: desert, plains, grassland, tundra, floodplain, hills, mountains, volcano, + coast, sea, ocean, snow-forest, snow-mountains, snow-volcano, lake. + ; - buildable_on_rivers : 0 or 1. If 1, Wonder can only be built if tile has river. + ; - buildable_adjacent_to : Same as buildable_on, plus "city". + ; - buildable_adjacent_to_overlays : Same overlay list as districts. + ; - buildable_by_civs : Comma-separated civ names (e.g., Romans, Egyptians). + ; - buildable_by_civ_traits : Comma-separated trait names (e.g., Commercial, Militaristic). + ; - buildable_by_civ_govs : Comma-separated government names (e.g., Republic, Monarchy). + ; - buildable_by_civ_cultures : Comma-separated culture names (e.g., EURO, ASIAN). + ; - img_path : Text. PCX filename (under Art/Districts/1200/). Defaults to Wonders.pcx if omitted. + ; - img_construct_row : Number (required). Row index in the PCX for the "under construction" wonder art (0-based). + ; - img_construct_column : Number (required). Column index in the PCX for the "under construction" wonder art (0-based). + ; - img_row : Number (required). Row index in the PCX for the completed wonder art (0-based). + ; - img_column : Number (required). Column index in the PCX for the completed wonder art (0-based). + ; - enable_img_alt_dir : 0 or 1. If 1, use alternate art when river/city direction implies a flip (see img_alt_dir_* fields). + ; - img_alt_dir_construct_row : Number. Row index for alternate "under construction" art (0-based). + ; - img_alt_dir_construct_column : Number. Column index for alternate "under construction" art (0-based). + ; - img_alt_dir_row : Number. Row index for alternate completed art (0-based). + ; - img_alt_dir_column : Number. Column index for alternate completed art (0-based). + ; - custom_width : Number (pixels). Override wonder sprite width. (default: 128) + ; - custom_height : Number (pixels). Override wonder sprite height. (default: 64) +] + +#Wonder +name = The Pyramids +buildable_on = desert +img_path = Wonders.pcx +img_construct_row = 0 +img_construct_column = 0 +img_row = 0 +img_column = 1 + +#Wonder +name = The Hanging Gardens +img_path = Wonders.pcx +img_construct_row = 0 +img_construct_column = 2 +img_row = 0 +img_column = 3 + +#Wonder +name = The Oracle +buildable_on = hills +img_path = Wonders.pcx +img_construct_row = 1 +img_construct_column = 0 +img_row = 1 +img_column = 1 + +#Wonder +name = The Temple of Artemis +img_path = Wonders.pcx +img_construct_row = 1 +img_construct_column = 2 +img_row = 1 +img_column = 3 + +#Wonder +name = The Mausoleum of Mausollos +img_path = Wonders.pcx +img_construct_row = 2 +img_construct_column = 0 +img_row = 2 +img_column = 1 + +#Wonder +name = The Statue of Zeus +img_path = Wonders.pcx +img_construct_row = 2 +img_construct_column = 2 +img_row = 2 +img_column = 3 + +#Wonder +name = The Great Library +img_path = Wonders.pcx +img_construct_row = 3 +img_construct_column = 0 +img_row = 3 +img_column = 1 + +#Wonder +name = Copernicus' Observatory +img_path = Wonders.pcx +img_construct_row = 3 +img_construct_column = 2 +img_row = 3 +img_column = 3 + +#Wonder +name = JS Bach's Cathedral +img_path = Wonders_2.pcx +img_construct_row = 0 +img_construct_column = 0 +img_row = 0 +img_column = 1 + +#Wonder +name = Newton's University +img_path = Wonders_2.pcx +img_construct_row = 0 +img_construct_column = 2 +img_row = 0 +img_column = 3 + +#Wonder +name = SETI program +img_path = Wonders_2.pcx +img_construct_row = 1 +img_construct_column = 0 +img_row = 1 +img_column = 1 + +#Wonder +name = Shakespeare's Theater +img_path = Wonders_2.pcx +img_construct_row = 1 +img_construct_column = 2 +img_row = 1 +img_column = 3 + +#Wonder +name = Sistine Chapel +img_path = Wonders_2.pcx +img_construct_row = 2 +img_construct_column = 0 +img_row = 2 +img_column = 1 + +#Wonder +name = The Great Lighthouse +buildable_on = coast +img_path = Wonders_2.pcx +img_construct_row = 2 +img_construct_column = 2 +img_row = 2 +img_column = 3 + +#Wonder +name = The Colossus +buildable_on = coast +enable_img_alt_dir = 1 +img_path = Wonders_2.pcx +img_construct_row = 3 +img_construct_column = 0 +img_row = 3 +img_column = 1 +img_alt_dir_construct_row = 3 +img_alt_dir_construct_column = 2 +img_alt_dir_row = 3 +img_alt_dir_column = 3 + +#Wonder +name = Hoover Dam +buildable_on = mountains +buildable_on_rivers = 1 +enable_img_alt_dir = 1 +img_path = Wonders_3.pcx +img_construct_row = 0 +img_construct_column = 0 +img_row = 0 +img_column = 1 +img_alt_dir_construct_row = 0 +img_alt_dir_construct_column = 2 +img_alt_dir_row = 0 +img_alt_dir_column = 3 + +#Wonder +name = Apollo Program +img_path = SmallWonders.pcx +img_construct_row = 0 +img_construct_column = 0 +img_row = 0 +img_column = 1 + +#Wonder +name = Forbidden Palace +img_path = SmallWonders.pcx +img_construct_row = 0 +img_construct_column = 2 +img_row = 0 +img_column = 3 + +#Wonder +name = Intelligence Agency +img_path = SmallWonders.pcx +img_construct_row = 1 +img_construct_column = 0 +img_row = 1 +img_column = 1 + +#Wonder +name = The Pentagon +img_path = SmallWonders.pcx +img_construct_row = 1 +img_construct_column = 2 +img_row = 1 +img_column = 3 + +#Wonder +name = Military Academy +img_path = SmallWonders.pcx +img_construct_row = 2 +img_construct_column = 0 +img_row = 2 +img_column = 1 + +#Wonder +name = Iron Works +img_path = SmallWonders.pcx +img_construct_row = 2 +img_construct_column = 2 +img_row = 2 +img_column = 3 + +#Wonder +name = Wall Street +img_path = SmallWonders.pcx +img_construct_row = 3 +img_construct_column = 0 +img_row = 3 +img_column = 1 diff --git a/injected_code.c b/injected_code.c index 730d9d07..b83a38de 100644 --- a/injected_code.c +++ b/injected_code.c @@ -1,37113 +1,37115 @@ -#include "stdlib.h" -#include "stdio.h" - -#include "C3X.h" - -void (WINAPI ** p_OutputDebugStringA) (char * lpOutputString) = ADDR_ADDR_OUTPUTDEBUGSTRINGA; -short (WINAPI ** p_GetAsyncKeyState) (int vKey) = ADDR_ADDR_GETASYNCKEYSTATE; -FARPROC (WINAPI ** p_GetProcAddress) (HMODULE hModule, char const * lpProcName) = ADDR_ADDR_GETPROCADDRESS; -HMODULE (WINAPI ** p_GetModuleHandleA) (char const * lpModuleName) = ADDR_ADDR_GETMODULEHANDLEA; -int (WINAPI ** p_MessageBoxA) (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) = ADDR_ADDR_MESSAGEBOXA; - -struct injected_state * is = ADDR_INJECTED_STATE; - -// To be used as placeholder second argument so that we can imitate thiscall convention with fastcall -#define __ 0 - -// Many Windows and C standard library functions have to be loaded dynamically with GetProcAddress and the addresses are stored in the injected -// state. This is covered up with macros, which is not something I would normally do, but in this case it's very useful because it means the code in -// common.c can be shared by the patcher and the injected code. -#define VirtualProtect is->VirtualProtect -#define CloseHandle is->CloseHandle -#define CreateFileA is->CreateFileA -#define GetFileSize is->GetFileSize -#define ReadFile is->ReadFile -#define LoadLibraryA is->LoadLibraryA -#define FreeLibrary is->FreeLibrary -#define MessageBoxA is->MessageBoxA -#define MultiByteToWideChar is->MultiByteToWideChar -#define WideCharToMultiByte is->WideCharToMultiByte -#define GetLastError is->GetLastError -#define QueryPerformanceCounter is->QueryPerformanceCounter -#define QueryPerformanceFrequency is->QueryPerformanceFrequency -#define GetLocalTime is->GetLocalTime -#define TransparentBlt is->TransparentBlt -#define snprintf is->snprintf -#define malloc is->malloc -#define calloc is->calloc -#define realloc is->realloc -#define free is->free -#define strtol is->strtol -#define strtof is->strtof -#define strncmp is->strncmp -#define strcmp is->strcmp -#define _stricmp is->_stricmp -#define strlen is->strlen -#define strncpy is->strncpy -#define strcpy is->strcpy -#define strdup is->strdup -#define strstr is->strstr -#define qsort is->qsort -#define memcmp is->memcmp -#define memcpy is->memcpy -#define tolower is->tolower -#define toupper is->toupper - -#include "common.c" - -#define TRADE_SCROLL_BUTTON_ID_LEFT 0x222001 -#define TRADE_SCROLL_BUTTON_ID_RIGHT 0x222002 - -// Must match size of button images in descbox.pcx -#define MOD_INFO_BUTTON_WIDTH 102 -#define MOD_INFO_BUTTON_HEIGHT 17 - -#define MOD_INFO_BUTTON_ID 0x222003 - -#define PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID 0x222004 -#define PEDIA_MULTIPAGE_PREV_BUTTON_ID 0x222005 - -#define TILE_FLAG_ROAD 0x1 -#define TILE_FLAG_RAILROAD 0x2 -#define TILE_FLAG_MINE 0x4 -#define TILE_FLAG_IRRIGATION 0x8 - -#define NEIGHBORHOOD_DISTRICT_ID 0 -#define WONDER_DISTRICT_ID 1 -#define DISTRIBUTION_HUB_DISTRICT_ID 2 -#define AERODROME_DISTRICT_ID 3 -#define NATURAL_WONDER_DISTRICT_ID 4 -#define PORT_DISTRICT_ID 5 -#define CENTRAL_RAIL_HUB_DISTRICT_ID 6 -#define ENERGY_GRID_DISTRICT_ID 7 -#define BRIDGE_DISTRICT_ID 8 -#define CANAL_DISTRICT_ID 9 -#define GREAT_WALL_DISTRICT_ID 10 - -#define MAX_DISTRICT_VARIANT_COUNT 5 -#define MAX_DISTRICT_ERA_COUNT 4 -#define MAX_DISTRICT_COLUMN_COUNT 10 - -// Max grid of tiles that an AI will evaluate a candidate bridge or canal for, -// used to limit computational complexity -#define AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES 10 - -enum { NAMED_TILE_MENU_ID = 0x90 }; - -char const * const hotseat_replay_save_path = "Saves\\Auto\\ai-move-replay-before-interturn.SAV"; -char const * const hotseat_resume_save_path = "Saves\\Auto\\ai-move-replay-resume.SAV"; - -// Need to define memmove for use by TCC when generated code for functions that return a struct -void * -memmove (void * dest, void const * src, size_t size) -{ - return is->memmove (dest, src, size); -} - -// Also need to define memset for some reason -void * -memset (void * dest, int ch, size_t count) -{ - for (size_t n = 0; n < count; n++) - ((char *)dest)[n] = ch; - return dest; -} - -// Computes num/denom randomly rounded off so that E[rand_div (x,y)] = (float)x/y -// As an example: E[rand_div (6, 5)] = 1.2, it will return 1 with 80% probability and 2 with 20% prob. -int -rand_div (int num, int denom) -{ - int q = num / denom, - r = num % denom; - return q + (rand_int (p_rand_object, __, denom) < r); -} - -bool -are_tiles_adjacent (int ax, int ay, int bx, int by) -{ - int x_dist = int_abs (ax - bx), - y_dist = int_abs (ay - by); - - // Handle edge wrapping by counting from the opposite direction if it would be shorter - if (p_bic_data->Map.Flags & 1) { // if map wraps horizontally - int width = p_bic_data->Map.Width; - if (x_dist > (width>>1)) - x_dist = width - x_dist; - } - if (p_bic_data->Map.Flags & 2) { // if map wraps vertically - int height = p_bic_data->Map.Height; - if (y_dist > (height>>1)) - y_dist = height - y_dist; - } - - return (x_dist + y_dist) == 2; -} - -int -compute_wrapped_component (int diff, int size, bool wraps) -{ - if (! wraps || (size <= 0)) - return diff; - - int half = size >> 1; - if (diff > half) - diff = size - diff; - return diff; -} - -void -compute_wrapped_deltas (int ax, int ay, int bx, int by, int * out_dx, int * out_dy) -{ - int dx = int_abs (ax - bx); - int dy = int_abs (ay - by); - bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; - bool wraps_vert = (p_bic_data->Map.Flags & 2) != 0; - dx = compute_wrapped_component (dx, p_bic_data->Map.Width, wraps_horiz); - dy = compute_wrapped_component (dy, p_bic_data->Map.Height, wraps_vert); - if (out_dx != NULL) - *out_dx = dx; - if (out_dy != NULL) - *out_dy = dy; -} - -int -compute_wrapped_manhattan_distance (int ax, int ay, int bx, int by) -{ - int dx, dy; - compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); - return dx + dy; -} - -int -compute_wrapped_chebyshev_distance (int ax, int ay, int bx, int by) -{ - int dx, dy; - compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); - return (dx > dy) ? dx : dy; -} - -bool -tile_has_resource (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - int resource_type = tile->vtable->m39_Get_Resource_Type (tile); - return (resource_type >= 0) && (resource_type < p_bic_data->ResourceTypeCount); -} - -City * -get_city_ptr (int id) -{ - if ((p_cities->Cities != NULL) && - (id >= 0) && (id <= p_cities->LastIndex)) { - City_Body * body = p_cities->Cities[id].City; - if (body != NULL) { - City * city = (City *)((char *)body - offsetof (City, Body)); - if (city != NULL) - return city; - } - } - return NULL; -} - -// Forward declarations for unit counter system (defined after their dependencies) -enum recognizable_parse_result parse_unit_counter_group (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_group); -enum recognizable_parse_result parse_counter_rule (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_rule); - -// Declare various functions needed for districts and hard to untangle and reorder here -void __fastcall patch_City_recompute_yields_and_happiness (City * this); -void __fastcall patch_Map_build_trade_network (Map * this); -bool __fastcall patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value); -bool __fastcall patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y); -bool __fastcall patch_City_has_resource (City * this, int edx, int resource_id); -bool __fastcall patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2); -char __fastcall patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing); -void __fastcall patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7); -bool can_build_district_on_tile (Tile * tile, int district_id, int civ_id); -bool city_can_build_district (City * city, int district_id); -bool leader_can_build_district (Leader * leader, int district_id); -bool wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id); -bool find_civ_trait_id_by_name (struct string_slice const * name, int * out_id); -bool find_civ_culture_id_by_name (struct string_slice const * name, int * out_id); -Tile * find_tile_for_district (City * city, int district_id, int * out_x, int * out_y); -struct district_instance * get_district_instance (Tile * tile); -struct named_tile_entry * get_named_tile_entry (Tile * tile); -bool city_has_required_district (City * city, int district_id); -bool district_is_complete (Tile * tile, int district_id); -bool city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id); -void clear_city_district_request (City * city, int district_id); -void set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y); -bool city_radius_contains_tile (City * city, int tile_x, int tile_y); -void on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y); -bool ai_move_district_worker (Unit * worker, struct district_worker_record * rec); -bool has_active_building (City * city, int improv_id); -bool tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv); -void recompute_distribution_hub_totals (); -void get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y); -void wrap_tile_coords (Map * map, int * x, int * y); -int count_neighborhoods_in_city_radius (City * city); -int count_utilized_neighborhoods_in_city_radius (City * city); -char * copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes); -bool city_has_resource_r (City * city, int resource_id, int max_generated_resource_id); - -struct pause_for_popup { - bool done; // Set to true to exit for loop - bool redundant; // If true, this pause would overlap a previous one and so should not be counted - long long ts_before; -}; - -struct pause_for_popup -pfp_init () -{ - struct pause_for_popup tr; - tr.done = false; - tr.redundant = is->paused_for_popup; - if (! tr.redundant) { - is->paused_for_popup = true; - QueryPerformanceCounter ((LARGE_INTEGER *)&tr.ts_before); - } - return tr; -} - -void -pfp_finish (struct pause_for_popup * pfp) -{ - if ((! pfp->redundant) && (! pfp->done)) { - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - is->time_spent_paused_during_popup += ts_after - pfp->ts_before; - is->paused_for_popup = false; - } - pfp->done = true; -} - -#define WITH_PAUSE_FOR_POPUP for (struct pause_for_popup pfp = pfp_init (); ! pfp.done; pfp_finish (&pfp)) - -int __fastcall -patch_show_popup (void * this, int edx, int param_1, int param_2) -{ - int tr; - WITH_PAUSE_FOR_POPUP { - is->show_popup_was_called = 1; - tr = show_popup (this, __, param_1, param_2); - } - return tr; -} - -void -pop_up_in_game_error (char const * msg) -{ - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); - PopupForm_add_text (popup, __, (char *)msg, false); - patch_show_popup (popup, __, 0, 0); -} - -void -memoize (int val) -{ - if (is->memo_len < is->memo_capacity) - is->memo[is->memo_len++] = val; - else { - int new_capacity = not_below (100, 2 * is->memo_capacity); - int * new_memo = malloc (new_capacity * sizeof is->memo[0]); - if (new_memo != NULL) { - for (int n = 0; n < is->memo_len; n++) - new_memo[n] = is->memo[n]; - free (is->memo); - is->memo = new_memo; - is->memo_capacity = new_capacity; - is->memo[is->memo_len++] = val; - } - } - -} - -void -clear_memo () -{ - is->memo_len = 0; -} - -// The maximum possible cultural neighbor index. We don't bother dealing with indices beyond this b/c it's the last tile in the seventh ring. Also -// equals one less than the tile count up to & inc. the seventh ring b/c of the zeroth tile. -#define MAX_CULTURAL_NI 192 - -// Number of workable tiles including the city center for each workable radius -unsigned char const workable_tile_counts[8] = {1, 9, 21, 37, 61, 89, 137, 193}; - -char const cultural_ni_to_diffs[(MAX_CULTURAL_NI + 1) * 2] = -{ - 0, 0, - -// first ring - 1, -1, 2, 0, 1, 1, 0, 2, -1, 1, -2, 0, -1, -1, - 0, -2, - -// second ring - 1, -3, 2, -2, 3, -1, 3, 1, 2, 2, 1, 3, -1, 3, -2, 2, - -3, 1, -3, -1, -2, -2, -1, -3, - -// third ring - 0, -4, 4, 0, 0, 4, -4, 0, 2, -4, 3, -3, 4, -2, 4, 2, - 3, 3, 2, 4, -2, 4, -3, 3, -4, 2, -4, -2, -3, -3, -2, -4, - -// fourth ring - 1, -5, 5, -1, 5, 1, 1, 5, -1, 5, -5, 1, -5, -1, -1, -5, - 0, -6, 6, 0, 0, 6, -6, 0, 3, -5, 4, -4, 5, -3, 5, 3, - 4, 4, 3, 5, -3, 5, -4, 4, -5, 3, -5, -3, -4, -4, -3, -5, - -// fifth ring - 1, -7, 2, -6, 6, -2, 7, -1, 7, 1, 6, 2, 2, 6, 1, 7, - -1, 7, -2, 6, -6, 2, -7, 1, -7, -1, -6, -2, -2, -6, -1, -7, - 4, -6, 5, -5, 6, -4, 6, 4, 5, 5, 4, 6, -4, 6, -5, 5, - -6, 4, -6, -4, -5, -5, -4, -6, - -// sixth ring - 0, -8, 8, 0, 0, 8, -8, 0, 1, -9, 2, -8, 3, -7, 7, -3, - 8, -2, 9, -1, 9, 1, 8, 2, 7, 3, 3, 7, 2, 8, 1, 9, - -1, 9, -2, 8, -3, 7, -7, 3, -8, 2, -9, 1, -9, -1, -8, -2, - -7, -3, -3, -7, -2, -8, -1, -9, 4, -8, 5, -7, 6, -6, 7, -5, - 8, -4, 8, 4, 7, 5, 6, 6, 5, 7, 4, 8, -4, 8, -5, 7, - -6, 6, -7, 5, -8, 4, -8, -4, -7, -5, -6, -6, -5, -7, -4, -8, - -// seventh ring - 0, -10, 10, 0, 0, 10, -10, 0, 1, -11, 2, -10, 3, -9, 9, -3, - 10, -2, 11, -1, 11, 1, 10, 2, 9, 3, 3, 9, 2, 10, 1, 11, - -1, 11, -2, 10, -3, 9, -9, 3, -10, 2, -11, 1, -11, -1, -10, -2, - -9, -3, -3, -9, -2, -10, -1, -11, 4, -10, 5, -9, 6, -8, 7, -7, - 8, -6, 9, -5, 10, -4, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, - 5, 9, 4, 10, -4, 10, -5, 9, -6, 8, -7, 7, -8, 6, -9, 5, - -10, 4, -10, -4, -9, -5, -8, -6, -7, -7, -6, -8, -5, -9, -4, -10 -}; - -// Like neighbor_index_to_diff, but enumerates tiles in an order that matches cultural border expansion. Only valid for 0 <= neighbor_index <= MAX_CULTURAL_NI. -void __cdecl -patch_ni_to_diff_for_work_area (int neighbor_index, int * x_disp, int * y_disp) -{ - if (neighbor_index <= 0) { - *x_disp = *y_disp = 0; - return; - } else if (neighbor_index > MAX_CULTURAL_NI) - neighbor_index = neighbor_index % (MAX_CULTURAL_NI + 1); - - int i = neighbor_index << 1; - char const * p = &cultural_ni_to_diffs[neighbor_index << 1]; - *x_disp = p[0]; - *y_disp = p[1]; -} - -int __fastcall -patch_City_find_min_value_tile (City * this) -{ - int tr = City_find_min_value_tile (this); - - // The original function has been edited to enumerate tiles in our custom order matching cultural borders instead of the game's original - // order. It returns a neighbor index from that enumeration. We must convert it to standard order if it's beyond the range where the two - // enumerations overlap. - if (tr >= 21) - tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; - - return tr; -} - -int __fastcall -patch_City_find_best_tile_to_work (City * this, int edx, Unit * worker, bool param_2) -{ - int tr = City_find_best_tile_to_work (this, __, worker, param_2); - if (tr >= 21) - tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; - return tr; -} - -bool __fastcall -City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 21) && (neighbor_index <= MAX_CULTURAL_NI)) - neighbor_index = is->cultural_ni_to_standard[neighbor_index]; - return City_stop_working_tile (this, __, neighbor_index); -} - -int __fastcall -patch_Map_compute_ni_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - // Within the first two rings, there's no difference b/w the standard and custom "work area" neighbor indices so fall back to the base game's - // function in that case. - if (is->workable_tile_count <= 21) - return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); - - // If the work area has been expanded, compute the neighbor index then check that it's within the area. Ignore the limit we were passed and - // instead use the number of tiles in the workable area, doubled to cover the difference between cultural vs standard enumeration. - else { - int ni = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, 2 * is->workable_tile_count); - if ((ni >= 0) && (ni <= ARRAY_LEN (is->ni_to_work_radius)) && - (is->ni_to_work_radius[ni] >= 0) && - (is->ni_to_work_radius[ni] <= is->current_config.city_work_radius)) - return ni; - else - return -1; - } -} - -int __fastcall -patch_Map_m28_find_cnter_neigh_point_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - int ret_addr = ((int *)&x_home)[-1]; - if (ret_addr != ADDR_FIND_CENTER_NP_SPOTLIGHT_RET) - return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); - else - return patch_Map_compute_ni_for_work_area (this, __, x_home, y_home, x_neigh, y_neigh, 500); -} - -int -get_work_ring_limit_by_culture (City * city) -{ - if (is->current_config.work_area_limit == WAL_NONE) - return INT_MAX; - else { - int lower_lim = (is->current_config.work_area_limit == WAL_CULTURAL_MIN_2) ? 2 : 1; - return not_below (lower_lim, city->Body.cultural_level); - } -} - -int -get_work_ring_limit_by_improvements (City * city) -{ - if (is->current_config.count_work_area_improvements == 0) - return INT_MAX; - else { - int maxRadius = 0; - int bonusRadius = 0; - for (int n = 0; n < is->current_config.count_work_area_improvements; n++) { - struct work_area_improvement * work_area_improvement = &is->current_config.work_area_improvements[n]; - if (work_area_improvement->work_area_radius_limit > maxRadius && - (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { - maxRadius = work_area_improvement->work_area_radius_limit; - } - if (work_area_improvement->work_area_radius_bonus > 0 && - (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { - bonusRadius += work_area_improvement->work_area_radius_bonus; - } - } - return maxRadius + bonusRadius; - } -} - -int -get_work_ring_limit_total (City * city) -{ - int cultureLimit = get_work_ring_limit_by_culture(city); - int improvementLimit = get_work_ring_limit_by_improvements(city); - if (cultureLimit < improvementLimit) - return cultureLimit; - return improvementLimit; -} - -bool __fastcall -patch_City_controls_tile (City * this, int edx, int neighbor_index, bool consider_enemy_units) -{ - // Check that this tile is not outside the city's work area. We've deleted a check from the base game code that verifies the n.i. is within 21 - // tiles so we can replicate it here in a way that also works for an expanded work area. - int work_radius = ((neighbor_index >= 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) ? is->ni_to_work_radius[neighbor_index] : -1; - if ((work_radius > is->current_config.city_work_radius) || (work_radius < 0)) - return false; - - int work_ring_limit = get_work_ring_limit_total (this); - if (work_radius > work_ring_limit) { - - // May consider this tile within the limit if any adjacent tiles are within the limit & within borders - bool exempt_from_limit; - if (is->current_config.work_area_limit != WAL_CULTURAL_OR_ADJACENT) - exempt_from_limit = false; - else if (neighbor_index >= 9) { - exempt_from_limit = false; - int center_x, center_y; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, ¢er_x, ¢er_y); - int neighbors_checked = 0; - for (int ni = 1; ni < ARRAY_LEN (is->ni_to_work_radius); ni++) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, ni, &nx, &ny); - if (are_tiles_adjacent (center_x, center_y, nx, ny)) { - neighbors_checked++; - int wr = is->ni_to_work_radius[ni]; - Tile * neighbor; - if (((wr >= 0) && (wr <= work_ring_limit)) && - (neighbor = tile_at (nx, ny)) && - (neighbor->vtable->m38_Get_Territory_OwnerID (neighbor) == this->Body.CivID)) { - exempt_from_limit = true; - break; - } - } - if (neighbors_checked == 8) - break; - } - } else - exempt_from_limit = true; - - if (! exempt_from_limit) - return false; - } - - if (neighbor_index >= 0) { - int tile_x, tile_y; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - // Check if the tile itself is a completed district (includes natural wonders) - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id)) - return false; - - // Check if the tile is covered by a distribution hub - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - return false; - } - } - } - } - - return City_controls_tile (this, __, neighbor_index, consider_enemy_units); -} - -bool __fastcall -patch_City_controls_tile_conv_ni (City * this, int edx, int neighbor_index, bool consider_enemy_units) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return patch_City_controls_tile (this, __, is->cultural_ni_to_standard[neighbor_index], consider_enemy_units); - else - return false; -} - -bool __fastcall -patch_City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return City_stop_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); - else - return false; -} - -bool __fastcall -patch_City_start_working_tile_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return City_start_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); - else - return false; -} - -void __fastcall -patch_City_add_or_remove_tile_yield_conv_ni (City * this, int edx, int neighbor_index, bool add_else_remove) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - City_add_or_remove_tile_yield (this, __, is->cultural_ni_to_standard[neighbor_index], add_else_remove); -} - -bool __fastcall -patch_City_is_neighboring_tile_in_area_conv_ni (City * this, int edx, int neighbor_index) -{ - if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) - return City_is_neighboring_tile_in_area (this, __, is->cultural_ni_to_standard[neighbor_index]); - else - return false; -} - -int -get_city_screen_center_y (City * city) -{ - int y = city->Body.Y; - if (p_bic_data->is_zoomed_out) - return y + 7; // when zoomed out, shift map up to center city - else if (is->current_config.city_work_radius >= 3) - return y + 4; // when work radius is 3, shift map up one extra tile so as not to overlap citizen heads - else - return y + 2; // base game behavior -} - -void __fastcall -patch_Main_Screen_Form_bring_cnter_view_city_focus (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) -{ - // If the city we're viewing can work tiles in the 4+ ring then zoom out the map display to show them - int effective_radius = not_above (get_work_ring_limit_total (p_city_form->CurrentCity), is->current_config.city_work_radius); - if (is->current_config.work_area_limit == WAL_CULTURAL_OR_ADJACENT) - effective_radius = not_above (is->current_config.city_work_radius, effective_radius + 1); - if (effective_radius >= 4 && is->current_config.auto_zoom_city_screen_for_large_work_areas) - p_bic_data->is_zoomed_out = true; - - Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); -} - -void __fastcall -patch_Main_Screen_Form_bring_cnter_view_city_arrow (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) -{ - Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); -} - -void tile_index_to_coords (Map * map, int index, int * out_x, int * out_y); - -Tile * __fastcall -patch_Map_get_tile_for_work_area_drawing (Map * this, int edx, int index) -{ - Tile * tr = Map_get_tile (this, __, index); - - if (tr != p_null_tile) { - int x, y; - tile_index_to_coords (this, index, &x, &y); - City * viewing_city = p_city_form->CurrentCity; - int ni = Map_compute_neighbor_index (this, __, viewing_city->Body.X, viewing_city->Body.Y, x, y, 1000); - if ((ni > 0) && ! patch_City_controls_tile (viewing_city, __, ni, false)) - tr = p_null_tile; - } - - return tr; -} - -// Resets is->current_config to the base config and updates the list of config names. Does NOT re-apply machine code edits. -void -reset_to_base_config () -{ - struct c3x_config * cc = &is->current_config; - - for (int n = 0; n < ARRAY_LEN (cc->limit_units_per_tile); n++) - cc->limit_units_per_tile[n] = 0; - - table_deinit (&cc->exclude_types_from_units_per_tile_limit); - - for (int n = 0; n < COUNT_PERFUME_KINDS; n++) - stable_deinit (&cc->perfume_specs[n]); - - // Free building-unit prereqs table - FOR_TABLE_ENTRIES (tei, &cc->building_unit_prereqs) { - if ((tei.value & 1) == 0) - free ((void *)tei.value); - } - table_deinit (&cc->building_unit_prereqs); - - // Free list of mills - if (cc->mills != NULL) { - free (cc->mills); - cc->mills = NULL; - cc->count_mills = 0; - } - - // Free list of AI multi-city start extra palaces - if (cc->ai_multi_start_extra_palaces != NULL) { - free (cc->ai_multi_start_extra_palaces); - cc->ai_multi_start_extra_palaces = NULL; - cc->count_ai_multi_start_extra_palaces = 0; - cc->ai_multi_start_extra_palaces_capacity = 0; - } - - table_deinit (&cc->limit_defensive_retreat_on_water_to_types); - table_deinit (&cc->can_bombard_only_sea_tiles); - - // Free set of PTW artillery types and list of converted types - table_deinit (&cc->ptw_arty_types); - if (is->charmed_types_converted_to_ptw_arty != NULL) { - free (is->charmed_types_converted_to_ptw_arty); - is->charmed_types_converted_to_ptw_arty = NULL; - is->count_charmed_types_converted_to_ptw_arty = 0; - is->charmed_types_converted_to_ptw_arty_capacity = 0; - } - - // Free era alias lists - if (cc->civ_era_alias_lists != NULL) { - for (int n = 0; n < cc->count_civ_era_alias_lists; n++) { - struct civ_era_alias_list * list = &cc->civ_era_alias_lists[n]; - free (list->key); - for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) - free (list->aliases[k]); - } - free (cc->civ_era_alias_lists); - cc->civ_era_alias_lists = NULL; - cc->count_civ_era_alias_lists = 0; - } - if (cc->leader_era_alias_lists != NULL) { - for (int n = 0; n < cc->count_leader_era_alias_lists; n++) { - struct leader_era_alias_list * list = &cc->leader_era_alias_lists[n]; - free (list->key); - for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) { - free (list->aliases[k]); - free (list->titles[k]); - } - } - free (cc->leader_era_alias_lists); - cc->leader_era_alias_lists = NULL; - cc->count_leader_era_alias_lists = 0; - } - - // Free list of work_area_improvements - if (cc->work_area_improvements != NULL) { - free (cc->work_area_improvements); - cc->work_area_improvements = NULL; - cc->count_work_area_improvements = 0; - } - - // Free aircraft victory animation string - if (cc->aircraft_victory_animation != NULL) { - free (cc->aircraft_victory_animation); - cc->aircraft_victory_animation = NULL; - } - - if (cc->great_wall_auto_build_wonder_name != NULL) { - free (cc->great_wall_auto_build_wonder_name); - cc->great_wall_auto_build_wonder_name = NULL; - } - - if (cc->unit_counter_groups != NULL) { - for (int n = 0; n < cc->count_unit_counter_groups; n++) { - free (cc->unit_counter_groups[n].name); - free (cc->unit_counter_groups[n].type_ids); - } - free (cc->unit_counter_groups); - cc->unit_counter_groups = NULL; - cc->count_unit_counter_groups = 0; - } - - if (cc->counter_rules != NULL) { - for (int n = 0; n < cc->count_counter_rules; n++) { - free (cc->counter_rules[n].attacker_group); - free (cc->counter_rules[n].defender_group); - free (cc->counter_rules[n].district_name); - } - free (cc->counter_rules); - cc->counter_rules = NULL; - cc->count_counter_rules = 0; - } - - // Free unit limits table - FOR_TABLE_ENTRIES (tei, &cc->unit_limits) - free ((void *)tei.value); - stable_deinit (&cc->unit_limits); - - // Free the linked list of loaded config names and the string name contained in each one - if (is->loaded_config_names != NULL) { - struct loaded_config_name * next = is->loaded_config_names; - while (next != NULL) { - struct loaded_config_name * to_free = next; - next = next->next; - free (to_free->name); - free (to_free); - } - } - - // Overwrite the current config with the base config - memcpy (&is->current_config, &is->base_config, sizeof is->current_config); - - // These fields are heap-allocated and must not be inherited from base_config - // (base_config never owns valid pointers for them) - is->current_config.unit_counter_groups = NULL; - is->current_config.count_unit_counter_groups = 0; - is->current_config.counter_rules = NULL; - is->current_config.count_counter_rules = 0; - - // Recreate loaded config names list with just the base config - is->loaded_config_names = malloc (sizeof *is->loaded_config_names); - is->loaded_config_names->name = strdup ("(base)"); - is->loaded_config_names->next = NULL; - - // Update IS variable that's tied to a config value - is->workable_tile_count = workable_tile_counts[is->current_config.city_work_radius]; -} - -struct id_list { - int length; - int capacity; - int ids[0]; -}; - -struct id_list * -alloc_id_list (int capacity, struct id_list const * copy) -{ - struct id_list * tr = malloc ((sizeof *tr) + capacity * sizeof(tr->ids[0])); - tr->length = 0; - tr->capacity = capacity; - if (copy != NULL) { - int new_len = not_above (capacity, copy->length); - for (int n = 0; n < new_len; n++) - tr->ids[n] = copy->ids[n]; - tr->length = new_len; - } - return tr; -} - -// This is the largest ID that will be stored inline inside sidtables. The amount here must be smaller than any pointer we'd get from malloc since the -// sidtable code compares values against this amount to determine which are inlined values versus pointers. -#define SID_TABLE_MAX_INLINE_ID 10000 - -void -sidtable_deinit (struct table * t) -{ - FOR_TABLE_ENTRIES (tei, t) { - free ((void *)tei.key); - if (tei.value > SID_TABLE_MAX_INLINE_ID) - free ((void *)tei.value); - } - table_deinit (t); -} - -void -sidtable_append (struct table * t, struct string_slice const * key, int id) -{ - // Expand or allocate table as needed - if (t->len >= table_capacity (t) / 2) - table__expand (t, hash_str, compare_str_keys); - - size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); - int * entry = &((int *)TABLE__BASE (t))[2*index]; - if (table__is_occupied (t, index)) { // If key is already in the table - int prev_val = entry[1]; - if (prev_val <= SID_TABLE_MAX_INLINE_ID) { // If prev value is an id, convert it to a list - struct id_list * new_list = alloc_id_list (2, NULL); - new_list->ids[0] = prev_val; - new_list->ids[1] = id; - new_list->length = 2; - entry[1] = (int)new_list; - } else { // Else, prev value is a list so append the new ID to it - struct id_list * list = (void *)prev_val; - if (list->length >= list->capacity) { // Expand list if necessary - struct id_list * new_list = alloc_id_list (2 * list->capacity, list); - entry[1] = (int)new_list; - free (list); - list = new_list; - } - list->ids[list->length] = id; - list->length++; - } - } else { // Key is not in the table, add it for the first time - entry[0] = (int)extract_slice (key); - if (id <= SID_TABLE_MAX_INLINE_ID) // Write ID inline if possible - entry[1] = id; - else { // Otherwise create a list for this one ID - struct id_list * new_list = alloc_id_list (2, NULL); - new_list->ids[0] = id; - new_list->length = 1; - entry[1] = (int)new_list; - } - table__set_occupation (t, index, 1); - t->len++; - } -} - -bool -sidtable_get_by_index (struct table const * t, size_t index, int ** out_ids, int * out_count) -{ - size_t capacity = table_capacity (t); - if ((capacity > 0) && (index < capacity) && table__is_occupied (t, index)) { - int * entry = &((int *)TABLE__BASE (t))[2*index]; - int val = entry[1]; - if (val <= SID_TABLE_MAX_INLINE_ID) { // Value is an ID - *out_ids = &entry[1]; - *out_count = 1; - } else { - struct id_list * list = (void *)val; - *out_ids = &list->ids[0]; - *out_count = list->length; - } - return true; - } else - return false; -} - -bool -sidtable_look_up (struct table const * t, char const * key, int ** out_ids, int * out_count) -{ - if (t->len > 0) { - size_t index = table__place (t, compare_str_keys, (int)key, hash_str ((int)key)); - return sidtable_get_by_index (t, index, out_ids, out_count); - } else - return false; -} - -bool -sidtable_look_up_slice (struct table const * t, struct string_slice const * key, int ** out_ids, int * out_count) -{ - if (t->len > 0) { - size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); - return sidtable_get_by_index (t, index, out_ids, out_count); - } else - return false; -} - -struct error_line { - char text[200]; - struct error_line * next; -}; - -struct error_line * -add_error_line (struct error_line ** p_lines) -{ - struct error_line * tr = calloc (1, sizeof *tr); - - struct error_line ** p_prev = p_lines; - while (*p_prev != NULL) - p_prev = &(*p_prev)->next; - *p_prev = tr; - - return tr; -} - -void -add_unrecognized_line (struct error_line ** p_lines, struct string_slice const * name) -{ - struct error_line * line = add_error_line (p_lines); - char s[100]; - snprintf (line->text, sizeof line->text, "^ %.*s", name->len, name->str); - line->text[(sizeof line->text) - 1] = '\0'; -} - -void -free_error_lines (struct error_line * lines) -{ - while (lines != NULL) { - struct error_line * next = lines->next; - free (lines); - lines = next; - } -} - -bool -find_improv_id_by_name (struct string_slice const * name, int * out) -{ - Improvement * improv; - if (name->len <= sizeof improv->Name) - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { - *out = n; - return true; - } - return false; -} - -// start_id specifies where the search will start. It's useful for finding multiple type IDs with the same name, which commonly happens due to the -// game duplicating unit types. -bool -find_unit_type_id_by_name (struct string_slice const * name, int start_id, int * out) -{ - UnitType * unit_type; - if (name->len <= sizeof unit_type->Name) - for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) - if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { - *out = n; - return true; - } - return false; -} - -bool -find_resource_id_by_name (struct string_slice const * name, int * out) -{ - Resource_Type * res_type; - if (name->len <= sizeof res_type->Name) - for (int n = 0; n < p_bic_data->ResourceTypeCount; n++) - if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { - *out = n; - return true; - } - return false; -} - -bool -find_animation_type_by_name (struct string_slice const * name, bool lower_case, AnimationType * out) -{ - for (int n_anim = 0; n_anim < COUNT_ANIMATION_TYPES; n_anim++) - if (strlen (animation_names[n_anim]) == name->len) { - bool all_chars_match = true; - for (int k = 0; k < name->len; k++) { - int c = animation_names[n_anim][k]; - if (lower_case) - c = tolower (c); - if (c != name->str[k]) { - all_chars_match = false; - break; - } - } - if (all_chars_match) { - *out = n_anim; - return true; - } - } - return false; -} - -enum game_object_kind { - GOK_UNIT_TYPE = 0, - GOK_BUILDING, - GOK_RESOURCE, - GOK_TECHNOLOGY, - GOK_GOVERNMENT, - - COUNT_GAME_OBJECT_KINDS -}; - -bool -find_game_object_id_by_name (enum game_object_kind kind, struct string_slice const * name, int start_id, int * out) -{ - switch (kind) { - case GOK_UNIT_TYPE: { - UnitType * unit_type; - if (name->len <= sizeof unit_type->Name) - for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) - if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { - *out = n; - return true; - } - return false; - } - case GOK_BUILDING: { - Improvement * improv; - if (name->len <= sizeof improv->Name) - for (int n = start_id; n < p_bic_data->ImprovementsCount; n++) - if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { - *out = n; - return true; - } - return false; - } - case GOK_RESOURCE: { - Resource_Type * res_type; - if (name->len <= sizeof res_type->Name) - for (int n = start_id; n < p_bic_data->ResourceTypeCount; n++) - if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { - *out = n; - return true; - } - return false; - } - case GOK_TECHNOLOGY: { - Advance * adv; - if (name->len <= sizeof adv->Name) - for (int n = start_id; n < p_bic_data->AdvanceCount; n++) - if (slice_matches_str (name, p_bic_data->Advances[n].Name)) { - *out = n; - return true; - } - return false; - } - case GOK_GOVERNMENT: { - Government * govt; - if (name->len <= sizeof govt->Name) - for (int n = start_id; n < p_bic_data->GovernmentsCount; n++) - if (slice_matches_str (name, p_bic_data->Governments[n].Name.S)) { - *out = n; - return true; - } - return false; - } - default: - return false; - } -} - -// Converts a build name (like "Spearman" or "Granary") into a City_Order struct. Returns whether or not any improvement or unit type was found under -// the given name. -bool -find_city_order_by_name (struct string_slice const * name, City_Order * out) -{ - int id; - if (find_improv_id_by_name (name, &id)) { - out->OrderID = id; - out->OrderType = COT_Improvement; - return true; - } else if (find_unit_type_id_by_name (name, 0, &id)) { - out->OrderID = id; - out->OrderType = COT_Unit; - return true; - } else - return false; -} - -// Returns a list of AI strat duplicates of the unit type with the given id. This means a list of all other unit types that are identical to the given -// one except were separated out so each can have only one AI strategy. Returns the total number of duplicates, which may be greater than dup_ids_len. -int -list_unit_type_duplicates (int type_id, int * out_dup_ids, int dup_ids_len) -{ - // type_id may be a duplicate itself. Find the base type so we can start assembling the array from there. Otherwise we may miss some. - int alt_for_id = p_bic_data->UnitTypes[type_id].alternate_strategy_for_id; - int base_type_id = (alt_for_id >= 0) ? alt_for_id : type_id; - - int tr = 0, current = base_type_id; - while (1) { - if (current != type_id) { - if (tr < dup_ids_len) - out_dup_ids[tr] = current; - tr++; - } - int next; - if (itable_look_up (&is->unit_type_duplicates, current, &next)) - current = next; - else - break; - } - - return tr; -} - -// A "recognizable" is something that contains the name of a unit, building, etc. When parsing one, it's possible for it to be grammatically valid but -// contain a name that doesn't match anything in the scenario data. That's a special kind of error. In that case, we record the error to report in a -// popup and continue parsing. -enum recognizable_parse_result { - RPR_OK = 0, - RPR_UNRECOGNIZED, - RPR_PARSE_ERROR -}; - -struct perfume_spec { - char name[36]; // Must be large enough to fit the name of a unit type or improvement - i31b value; // Int component stores amount, bool stores whether it's a percentage or not -}; - -enum recognizable_parse_result -parse_perfume_spec (char ** p_cursor, enum perfume_kind kind, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - char * cur = *p_cursor; - struct string_slice name; - City_Order unused_city_order; - int unused_id; - i31b value; - if (parse_string (&cur, &name) && - skip_punctuation (&cur, ':') && - parse_i31b (&cur, &value)) { - *p_cursor = cur; - - if (((kind == PK_PRODUCTION) && find_city_order_by_name (&name, &unused_city_order)) || - ((kind == PK_TECHNOLOGY) && find_game_object_id_by_name (GOK_TECHNOLOGY, &name, 0, &unused_id)) || - ((kind == PK_GOVERNMENT) && find_game_object_id_by_name (GOK_GOVERNMENT, &name, 0, &unused_id))) { - struct perfume_spec * out = out_perfume_spec; - snprintf (out->name, sizeof out->name, "%.*s", name.len, name.str); - out->name[(sizeof out->name) - 1] = '\0'; - out->value = value; - return RPR_OK; - } else { - add_unrecognized_line (p_unrecognized_lines, &name); - return RPR_UNRECOGNIZED; - } - } else - return RPR_PARSE_ERROR; -} - -enum recognizable_parse_result -parse_production_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - return parse_perfume_spec (p_cursor, PK_PRODUCTION, p_unrecognized_lines, out_perfume_spec); -} - -enum recognizable_parse_result -parse_technology_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - return parse_perfume_spec (p_cursor, PK_TECHNOLOGY, p_unrecognized_lines, out_perfume_spec); -} - -enum recognizable_parse_result -parse_government_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) -{ - return parse_perfume_spec (p_cursor, PK_GOVERNMENT, p_unrecognized_lines, out_perfume_spec); -} - -enum recognizable_parse_result -parse_mill (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_mill) -{ - char * cur = *p_cursor; - struct string_slice improv_name; - if (parse_string (&cur, &improv_name) && - skip_punctuation (&cur, ':')) { - - short flags = 0; - struct string_slice resource_name; - while (1) { - if (! parse_string (&cur, &resource_name)) - return RPR_PARSE_ERROR; - else if (slice_matches_str (&resource_name, "local")) flags |= MF_LOCAL; - else if (slice_matches_str (&resource_name, "no-tech-req")) flags |= MF_NO_TECH_REQ; - else if (slice_matches_str (&resource_name, "yields")) flags |= MF_YIELDS; - else if (slice_matches_str (&resource_name, "show-bonus")) flags |= MF_SHOW_BONUS; - else if (slice_matches_str (&resource_name, "hide-non-bonus")) flags |= MF_HIDE_NON_BONUS; - else - break; - } - - *p_cursor = cur; - int improv_id, resource_id; - int any_unrecognized = 0; - if (! find_improv_id_by_name (&improv_name, &improv_id)) { - add_unrecognized_line (p_unrecognized_lines, &improv_name); - any_unrecognized = 1; - } - if (! find_resource_id_by_name (&resource_name, &resource_id)) { - add_unrecognized_line (p_unrecognized_lines, &resource_name); - any_unrecognized = 1; - } - if (any_unrecognized) - return RPR_UNRECOGNIZED; - else { - struct mill * out = out_mill; - out->improv_id = improv_id; - out->resource_id = resource_id; - out->flags = flags; - return RPR_OK; - } - } else - return RPR_PARSE_ERROR; -} - -enum recognizable_parse_result -parse_era_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_or_civ_alias_list, bool leader_else_civ_name) -{ - char * cur = *p_cursor; - struct string_slice key; - if (parse_string (&cur, &key) && - skip_punctuation (&cur, ':')) { - - char * aliases[ERA_ALIAS_LIST_CAPACITY] = {0}; - char * titles[ERA_ALIAS_LIST_CAPACITY] = {0}; - int alias_count = 0, - female_bits = 0, - gender_specified_bits = 0; // For each alias, set to 1 if a gender was specified - struct string_slice alias; - while (1) { - if (parse_string (&cur, &alias)) { - if (alias_count < ERA_ALIAS_LIST_CAPACITY) - aliases[alias_count] = extract_slice (&alias); - - // If we're parsing a list of leader names, read in the gender & title if present - if (leader_else_civ_name) { - char * inner_cur = cur; - struct string_slice gender; - struct string_slice title = {0}; - if ( skip_punctuation (&inner_cur, '(') - && parse_string (&inner_cur, &gender) - && ( skip_punctuation (&inner_cur, ')') - || ( skip_punctuation (&inner_cur, ',') - && parse_string (&inner_cur, &title) - && skip_punctuation (&inner_cur, ')'))) - && ( slice_matches_str (&gender, "M") - || slice_matches_str (&gender, "m") - || slice_matches_str (&gender, "F") - || slice_matches_str (&gender, "f"))) { - if (alias_count < 32) { - if (slice_matches_str (&gender, "F") || slice_matches_str (&gender, "f")) - female_bits |= 1 << alias_count; - gender_specified_bits |= 1 << alias_count; - } - if (title.len > 0) - titles[alias_count] = extract_slice (&title); - cur = inner_cur; - } - } - - alias_count++; - } else - break; - } - if (alias_count == 0) - return RPR_PARSE_ERROR; - - *p_cursor = cur; - - // Check that "key" matches a noun, adjective, or formal name of any civ ("race") in the scenario data. Store that civ. - Race * race_matching_key = NULL; { - for (int n = 0; n < p_bic_data->RacesCount; n++) { - Race * race = &p_bic_data->Races[n]; - if ( ( leader_else_civ_name - && slice_matches_str (&key, race->LeaderName)) - || ( (! leader_else_civ_name) - && ( slice_matches_str (&key, race->AdjectiveName) - || slice_matches_str (&key, race->CountryName) - || slice_matches_str (&key, race->SingularName)))) { - race_matching_key = race; - break; - } - } - } - if (race_matching_key == NULL) { - add_unrecognized_line (p_unrecognized_lines, &key); - return RPR_UNRECOGNIZED; - } - - if (leader_else_civ_name) { - struct leader_era_alias_list * out = out_leader_or_civ_alias_list; - memset (out, 0, sizeof *out); // Make sure unspecified aliases & titles are NULL - out->key = extract_slice (&key); - for (int n = 0; n < alias_count; n++) { - out->aliases[n] = aliases[n]; - out->titles[n] = titles[n]; - } - - // Set gender bits - int unreplaced_bits = (race_matching_key->LeaderGender == 0) ? 0 : ~0; - out->gender_bits = (unreplaced_bits & ~gender_specified_bits) | female_bits; - - - } else { - struct civ_era_alias_list * out = out_leader_or_civ_alias_list; - memset (out, 0, sizeof *out); - out->key = extract_slice (&key); - for (int n = 0; n < alias_count; n++) - out->aliases[n] = aliases[n]; - } - - return RPR_OK; - } else - return RPR_PARSE_ERROR; -} - - -enum recognizable_parse_result -parse_civ_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_civ_era_alias_list) -{ - return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_civ_era_alias_list, false); -} - -enum recognizable_parse_result -parse_leader_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_era_alias_list) -{ - return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_leader_era_alias_list, true); -} - -struct parsed_unit_type_limit { - char name[32]; // Same length as Name in Unit_Type - struct unit_type_limit limit; -}; - -enum recognizable_parse_result -parse_unit_type_limit (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_unit_type_limit) -{ - char * cur = *p_cursor; - struct parsed_unit_type_limit * out = out_parsed_unit_type_limit; - - struct string_slice name; - struct unit_type_limit limit = {0}; - if (skip_white_space (&cur) && - parse_string (&cur, &name) && - (name.len < (sizeof out->name)) && - skip_punctuation (&cur, ':')) { - - do { - int num; - if (! parse_int (&cur, &num)) - return RPR_PARSE_ERROR; - - struct string_slice ss; - if (parse_string (&cur, &ss)) { - if (slice_matches_str (&ss, "per-city")) - limit.per_city += num; - else if (slice_matches_str (&ss, "cities-per")) - limit.cities_per += num; - else - return RPR_PARSE_ERROR; - } else - limit.per_civ += num; - - } 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 { - add_unrecognized_line (p_unrecognized_lines, &name); - *p_cursor = cur; - return RPR_UNRECOGNIZED; - } - - } else - return RPR_PARSE_ERROR; -} - -enum recognizable_parse_result -parse_work_area_improvement (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_work_area_improvement) -{ - char * cur = *p_cursor; - struct work_area_improvement * out = out_parsed_work_area_improvement; - out->improv_id = -1; - out->work_area_radius_limit = 0; - out->work_area_radius_bonus = 0; - - struct string_slice improv_name; - if (skip_white_space (&cur) && - parse_string (&cur, &improv_name) && - skip_punctuation (&cur, ':')) { - - int num; - if (! parse_int (&cur, &num)) - return RPR_PARSE_ERROR; - - struct string_slice ss; - if (parse_string (&cur, &ss)) { - if (slice_matches_str (&ss, "extra")) - out->work_area_radius_bonus = num; - else - return RPR_PARSE_ERROR; - } else - out->work_area_radius_limit = num; - - int improv_id; - if (slice_matches_str (&improv_name, "default")) { - out->improv_id = -1; - *p_cursor = cur; - return RPR_OK; - } else if (find_improv_id_by_name (&improv_name, &improv_id)) { - out->improv_id = improv_id; - *p_cursor = cur; - return RPR_OK; - } else { - add_unrecognized_line (p_unrecognized_lines, &improv_name); - *p_cursor = cur; - return RPR_UNRECOGNIZED; - } - - } else - return RPR_PARSE_ERROR; -} - -// Recognizable items are appended to out_list/count, which must have been previously initialized (NULL/0 is valid for an empty list). -// If an error occurs while reading, returns the location of the error inside the slice, specifically the number of characters before the unreadable -// item. If no error occurs, returns -1. -int -read_recognizables (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - int item_size, - enum recognizable_parse_result (* parse_item) (char **, struct error_line **, void *), - void ** inout_list, - int * inout_count) -{ - if (s->len <= 0) - return -1; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - - bool success = false; - void * new_items = NULL; - int count_new_items = 0; - int new_items_capacity = 0; - void * temp_item = malloc (item_size); - - while (1) { - enum recognizable_parse_result result = parse_item (&cursor, p_unrecognized_lines, temp_item); - if (result != RPR_PARSE_ERROR) { - if (result == RPR_OK) { - reserve (item_size, &new_items, &new_items_capacity, count_new_items); - memcpy ((byte *)new_items + count_new_items * item_size, temp_item, item_size); - count_new_items++; - } - - if (skip_punctuation (&cursor, ',') && skip_white_space (&cursor)) - continue; - else if (skip_horiz_space (&cursor) && (*cursor == '\0')) { - success = true; - break; - } else - break; - } else - break; - } - - if (success && (count_new_items > 0)) { - *inout_list = realloc (*inout_list, (*inout_count + count_new_items) * item_size); - memcpy ((byte *)*inout_list + *inout_count * item_size, new_items, count_new_items * item_size); - *inout_count += count_new_items; - } - free (temp_item); - free (new_items); - free (extracted_slice); - return success ? -1 : cursor - extracted_slice; -} - -// Reads a "sidtable" from text. A sidtable maps strings to IDs of scenario objects. The string keys are also expected to be a type of scenario -// object. This method reads text such as: -// Factory: Battleship, Stable: Horseman Knight Cavalry, "Siege Workshop": Catapult Trebuchet -// and converts it to a table mapping "Factory", "Stable", and "Siege Workshop" to the corresponding unit type IDs. All new entries are appended to -// the given table; existing entries are not removed. -// Like read_recognizables, this method returns -1 for success or the location of an error if there is one. -int -read_sidtable (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - enum game_object_kind key_kind, - enum game_object_kind list_elem_kind, - struct table * sidtable) -{ - if (s->len <= 0) - return -1; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - while (1) { - struct string_slice key; - if (skip_white_space (&cursor) && parse_string (&cursor, &key)) { - int unused; - bool recognized_key = find_game_object_id_by_name (key_kind, &key, 0, &unused); - if (! recognized_key) - add_unrecognized_line (p_unrecognized_lines, &key); - if (! skip_punctuation (&cursor, ':')) - break; - struct string_slice elem_name; - while (skip_white_space (&cursor) && parse_string (&cursor, &elem_name)) { - bool recognized_elem = false; - int elem_id = -1; - while (find_game_object_id_by_name (list_elem_kind, &elem_name, elem_id + 1, &elem_id)) { - recognized_elem = true; - if (recognized_key) - sidtable_append (sidtable, &key, elem_id); - } - if (! recognized_elem) - add_unrecognized_line (p_unrecognized_lines, &elem_name); - } - skip_punctuation (&cursor, ','); - } else { - success = (*cursor == '\0'); - break; - } - } - - free (extracted_slice); - return success ? -1 : cursor - extracted_slice; -} - -// Like read_recognizables, returns -1 for success or the location of an error if there is one -int -read_building_unit_prereqs (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - struct table * building_unit_prereqs) -{ - if (s->len <= 0) - return -1; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - struct prereq { - int building_id; - struct string_slice unit_type_name; - } * new_prereqs = NULL; - int new_prereqs_capacity = 0; - int count_new_prereqs = 0; - - while (1) { - struct string_slice building_name; - if (skip_white_space (&cursor) && parse_string (&cursor, &building_name)) { - int building_id; - bool have_building_id = find_improv_id_by_name (&building_name, &building_id); - if (! have_building_id) - add_unrecognized_line (p_unrecognized_lines, &building_name); - if (! skip_punctuation (&cursor, ':')) - break; - struct string_slice unit_type_name; - while (skip_white_space (&cursor) && parse_string (&cursor, &unit_type_name)) { - int unused; - if (find_unit_type_id_by_name (&unit_type_name, 0, &unused)) { // if there is any by this name, later we'll deal with the possibility of multiple - if (have_building_id) { - reserve (sizeof new_prereqs[0], (void **)&new_prereqs, &new_prereqs_capacity, count_new_prereqs); - new_prereqs[count_new_prereqs++] = (struct prereq) { .building_id = building_id, .unit_type_name = unit_type_name }; - } - } else - add_unrecognized_line (p_unrecognized_lines, &unit_type_name); - } - skip_punctuation (&cursor, ','); - } else { - success = (*cursor == '\0'); - break; - } - } - - // If parsing succeeded, add the new prereq rules to the table - if (success) - for (int n = 0; n < count_new_prereqs; n++) { - struct prereq * prereq = &new_prereqs[n]; - - int unit_type_id = -1; - while (find_unit_type_id_by_name (&prereq->unit_type_name, unit_type_id + 1, &unit_type_id)) { - - // If this unit type ID is not already in the table, insert it paired with the encoded building ID - int prev_val; - if (! itable_look_up (building_unit_prereqs, unit_type_id, &prev_val)) - itable_insert (building_unit_prereqs, unit_type_id, (prereq->building_id << 1) | 1); - - // If the unit type ID is already associated with a building ID, create a list for both the old and new building IDs - else if (prev_val & 1) { - int * list = malloc (MAX_BUILDING_PREREQS_FOR_UNIT * sizeof *list); - for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) - list[n] = -1; - list[0] = prev_val >> 1; // Decode - list[1] = prereq->building_id; - itable_insert (building_unit_prereqs, unit_type_id, (int)list); - - // Otherwise, it's already associated with a list. Search the list for a free spot and fill it with the new building ID - } else { - int * list = (int *)prev_val; - for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) - if (list[n] < 0) { - list[n] = prereq->building_id; - break; - } - } - } - } - - - free (new_prereqs); - free (extracted_slice); - return success ? -1 : cursor - extracted_slice; -} - -// Reads a space-separated list of unit types like: -// Worker Galley "Gallic Swordsman" -// Looks up the type ID(s) for each name and inserts them into the unit_types table associated with a value of 1. -bool -read_unit_type_list (struct string_slice const * s, struct error_line ** p_unrecognized_lines, struct table * unit_types) -{ - if (s->len <= 0) - return true; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - while (1) { - struct string_slice name; - if (parse_string (&cursor, &name)) { - - int id = -1; - bool matched_any = false; - while (find_unit_type_id_by_name (&name, id + 1, &id)) { - itable_insert (unit_types, id, 1); - matched_any = true; - } - - if (! matched_any) - add_unrecognized_line (p_unrecognized_lines, &name); - - } else { - skip_white_space (&cursor); - success = *cursor == '\0'; - break; - } - } - - free (extracted_slice); - return success; -} - -bool -read_ai_multi_start_extra_palaces (struct string_slice const * s, - struct error_line ** p_unrecognized_lines, - int ** p_ai_multi_start_extra_palaces, - int * p_count_ai_multi_start_extra_palaces, - int * p_ai_multi_start_extra_palaces_capacity) -{ - if (s->len <= 0) - return true; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - bool success = false; - - while (1) { - struct string_slice name; - if (parse_string (&cursor, &name)) { - int id; - if (find_improv_id_by_name (&name, &id)) { - int count = *p_count_ai_multi_start_extra_palaces; - reserve (sizeof **p_ai_multi_start_extra_palaces, (void **)p_ai_multi_start_extra_palaces, p_ai_multi_start_extra_palaces_capacity, count); - (*p_ai_multi_start_extra_palaces)[count] = id; - *p_count_ai_multi_start_extra_palaces = count + 1; - } else - add_unrecognized_line (p_unrecognized_lines, &name); - - } else { - skip_white_space (&cursor); - success = *cursor == '\0'; - break; - } - } - - free (extracted_slice); - return success; -} - -bool -read_retreat_rules (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "standard" )) { *out_val = RR_STANDARD; return true; } - else if (slice_matches_str (&trimmed, "none" )) { *out_val = RR_NONE; return true; } - else if (slice_matches_str (&trimmed, "all-units" )) { *out_val = RR_ALL_UNITS; return true; } - else if (slice_matches_str (&trimmed, "if-faster" )) { *out_val = RR_IF_FASTER; return true; } - else if (slice_matches_str (&trimmed, "if-not-slower" )) { *out_val = RR_IF_NOT_SLOWER; return true; } - else if (slice_matches_str (&trimmed, "if-fast-and-not-slower")) { *out_val = RR_IF_FAST_AND_NOT_SLOWER; return true; } - else - return false; -} - -bool -read_line_drawing_override (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "never" )) { *out_val = LDO_NEVER; return true; } - else if (slice_matches_str (&trimmed, "wine" )) { *out_val = LDO_WINE; return true; } - else if (slice_matches_str (&trimmed, "always")) { *out_val = LDO_ALWAYS; return true; } - else - return false; -} - -bool -read_minimap_doubling_mode (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "never" )) { *out_val = MDM_NEVER; return true; } - else if (slice_matches_str (&trimmed, "high-def")) { *out_val = MDM_HIGH_DEF; return true; } - else if (slice_matches_str (&trimmed, "always" )) { *out_val = MDM_ALWAYS; return true; } - else - return false; -} - -bool -read_unit_cycle_search_criteria (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "standard" )) { *out_val = UCSC_STANDARD; return true; } - else if (slice_matches_str (&trimmed, "similar-near-start" )) { *out_val = UCSC_SIMILAR_NEAR_START; return true; } - else if (slice_matches_str (&trimmed, "similar-near-destination")) { *out_val = UCSC_SIMILAR_NEAR_DESTINATION; return true; } - else - return false; -} - -bool -read_no_ai_patrol_override (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "zero")) { *out_val = NAPO_ZERO; return true; } - else if (slice_matches_str (&trimmed, "one" )) { *out_val = NAPO_ONE; return true; } - else if (slice_matches_str (&trimmed, "none")) { *out_val = NAPO_NONE; return true; } - else - return false; -} - -bool -read_work_area_limit (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "none" )) { *out_val = WAL_NONE; return true; } - else if (slice_matches_str (&trimmed, "cultural" )) { *out_val = WAL_CULTURAL; return true; } - else if (slice_matches_str (&trimmed, "cultural-min-2" )) { *out_val = WAL_CULTURAL_MIN_2; return true; } - else if (slice_matches_str (&trimmed, "cultural-or-adjacent")) { *out_val = WAL_CULTURAL_OR_ADJACENT; return true; } - else - return false; -} - -bool -read_day_night_cycle_mode (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "off" )) { *out_val = DNCM_OFF; return true; } - else if (slice_matches_str (&trimmed, "timer" )) { *out_val = DNCM_TIMER; return true; } - else if (slice_matches_str (&trimmed, "user-time" )) { *out_val = DNCM_USER_TIME; return true; } - else if (slice_matches_str (&trimmed, "every-turn")) { *out_val = DNCM_EVERY_TURN; return true; } - else if (slice_matches_str (&trimmed, "specified" )) { *out_val = DNCM_SPECIFIED; return true; } - else - return false; -} - -bool -read_distribution_hub_yield_division_mode (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "flat" )) { *out_val = DHYDM_FLAT; return true; } - else if (slice_matches_str (&trimmed, "scale-by-city-count" )) { *out_val = DHYDM_SCALE_BY_CITY_COUNT; return true; } - else - return false; -} - -bool -read_ai_distribution_hub_build_strategy (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "auto" )) { *out_val = ADHBS_AUTO; return true; } - else if (slice_matches_str (&trimmed, "by-city-count" )) { *out_val = ADHBS_BY_CITY_COUNT; return true; } - else - return false; -} - -bool -read_ai_auto_build_great_wall_strategy (struct string_slice const * s, int * out_val) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (slice_matches_str (&trimmed, "all-borders" )) { *out_val = AAGWS_ALL_BORDERS; return true; } - else if (slice_matches_str (&trimmed, "other-civ-bordered-only")) { *out_val = AAGWS_OTHER_CIV_BORDERED_ONLY; return true; } - else - return false; -} - -bool -read_tile_terrain_type_value (struct string_slice const * s, enum SquareTypes * out_type) -{ - if (s == NULL || out_type == NULL) - return false; - - struct string_slice trimmed = trim_string_slice (s, 1); - if (trimmed.len <= 0) - return false; - - struct { - char const * name; - int value; - } const entries[] = { - {"desert", SQ_Desert}, - {"deserts", SQ_Desert}, - {"plain", SQ_Plains}, - {"plains", SQ_Plains}, - {"grassland", SQ_Grassland}, - {"grasslands", SQ_Grassland}, - {"tundra", SQ_Tundra}, - {"tundras", SQ_Tundra}, - {"floodplain", SQ_FloodPlain}, - {"floodplains", SQ_FloodPlain}, - {"hill", SQ_Hills}, - {"hills", SQ_Hills}, - {"mountain", SQ_Mountains}, - {"mountains", SQ_Mountains}, - {"forest", SQ_Forest}, - {"forests", SQ_Forest}, - {"jungle", SQ_Jungle}, - {"jungles", SQ_Jungle}, - {"marsh", SQ_Swamp}, - {"marshes", SQ_Swamp}, - {"swamp", SQ_Swamp}, - {"swamps", SQ_Swamp}, - {"volcano", SQ_Volcano}, - {"volcanos", SQ_Volcano}, - {"coast", SQ_Coast}, - {"coasts", SQ_Coast}, - {"sea", SQ_Sea}, - {"seas", SQ_Sea}, - {"ocean", SQ_Ocean}, - {"oceans", SQ_Ocean}, - {"river", SQ_RIVER}, - {"rivers", SQ_RIVER}, - {"snow-volcano", SQ_SNOW_VOLCANO}, - {"snow-volcanos", SQ_SNOW_VOLCANO}, - {"snow-forest", SQ_SNOW_FOREST}, - {"snow-forests", SQ_SNOW_FOREST}, - {"snow-mountain", SQ_SNOW_MOUNTAIN}, - {"snow-mountains", SQ_SNOW_MOUNTAIN}, - {"any", SQ_INVALID} - }; - - for (int i = 0; i < (int)ARRAY_LEN (entries); i++) { - if (slice_matches_str (&trimmed, entries[i].name)) { - *out_type = (enum SquareTypes)entries[i].value; - return true; - } - } - - return false; -} - -unsigned int -square_type_mask_bit (enum SquareTypes type) -{ - if ((int)type < 0 || type > SQ_SNOW_MOUNTAIN) - return 0; - return (unsigned int)(1u << type); -} - -unsigned int -district_buildable_mine_mask_bit (void) -{ - return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 1)); -} - -unsigned int -district_buildable_irrigation_mask_bit (void) -{ - return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 2)); -} - -unsigned int -district_buildable_lake_mask_bit (void) -{ - return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 3)); -} - -unsigned int -all_square_types_mask (void) -{ - return (unsigned int)((1u << (SQ_SNOW_MOUNTAIN + 1)) - 1); -} - -unsigned int -district_default_buildable_mask (void) -{ - return (unsigned int)DEFAULT_DISTRICT_BUILDABLE_MASK; -} - -bool -tile_has_snow_mountain (Tile * tile) -{ - return (tile != NULL) && (tile != p_null_tile) && tile->vtable->m29_Check_Mountain_Snowcap (tile); -} - -bool -tile_is_lake (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (! tile->vtable->m35_Check_Is_Water (tile)) - return false; - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - return false; - - int lake_size_threshold = 21; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - return continent->Body.TileCount <= lake_size_threshold; -} - -bool -tile_has_snow_volcano (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Volcano) - return false; - - int overlays = tile->vtable->m43_Get_field_30 (tile); - return (overlays & 0x100000) != 0; -} - -bool -tile_has_snow_forest (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Forest) - return false; - - int overlays = tile->vtable->m43_Get_field_30 (tile); - return (overlays & 0x100000) != 0; -} - -bool -tile_matches_square_type (Tile * tile, enum SquareTypes type) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - switch (type) { - case SQ_SNOW_MOUNTAIN: - return tile_has_snow_mountain (tile); - case SQ_SNOW_VOLCANO: - return tile_has_snow_volcano (tile); - case SQ_SNOW_FOREST: - return tile_has_snow_forest (tile); - case SQ_RIVER: - return tile->vtable->m37_Get_River_Code (tile) != 0; - default: - return tile->vtable->m50_Get_Square_BaseType (tile) == type; - } -} - -bool -tile_matches_square_type_mask (Tile * tile, unsigned int mask) -{ - if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) - return false; - - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - unsigned int base_bit = square_type_mask_bit (base_type); - if ((base_bit != 0) && ((mask & base_bit) != 0)) - return true; - - enum SquareTypes const special_types[] = {SQ_RIVER, SQ_SNOW_MOUNTAIN, SQ_SNOW_VOLCANO, SQ_SNOW_FOREST}; - for (int i = 0; i < (int)ARRAY_LEN (special_types); i++) { - enum SquareTypes stype = special_types[i]; - unsigned int bit = square_type_mask_bit (stype); - if ((mask & bit) && tile_matches_square_type (tile, stype)) - return true; - } - - unsigned int mine_bit = district_buildable_mine_mask_bit (); - if ((mask & mine_bit) && tile->vtable->m18_Check_Mines (tile, __, 0)) - return true; - - unsigned int irrigation_bit = district_buildable_irrigation_mask_bit (); - if ((mask & irrigation_bit) && tile->vtable->m17_Check_Irrigation (tile, __, 0)) - return true; - - unsigned int lake_bit = district_buildable_lake_mask_bit (); - if ((mask & lake_bit) && tile_is_lake (tile)) - return true; - - return false; -} - -bool -tile_matches_overlay_mask (Tile * tile, unsigned int mask) -{ - if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) - return false; - - unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); - if ((mask & DOM_MINE) && ((overlays & TILE_FLAG_MINE) != 0)) - return true; - if ((mask & DOM_IRRIGATION) && ((overlays & 0x00000008) != 0)) - return true; - if ((mask & DOM_FORTRESS) && ((overlays & 0x00000010) != 0)) - return true; - if ((mask & DOM_BARRICADE) && ((overlays & 0x10000000) != 0)) - return true; - if ((mask & DOM_OUTPOST) && ((overlays & 0x80000000) != 0)) - return true; - if ((mask & DOM_RADAR_TOWER) && ((overlays & 0x40000000) != 0)) - return true; - if ((mask & DOM_AIRFIELD) && ((overlays & 0x20000000) != 0)) - return true; - if ((mask & DOM_JUNGLE) && tile_matches_square_type (tile, SQ_Jungle)) - return true; - if ((mask & DOM_FOREST) && tile_matches_square_type (tile, SQ_Forest)) - return true; - if ((mask & DOM_SWAMP) && tile_matches_square_type (tile, SQ_Swamp)) - return true; - if ((mask & DOM_RIVER) && tile_matches_square_type (tile, SQ_RIVER)) - return true; - - return false; -} - -bool -read_natural_wonder_terrain_type (struct string_slice const * s, enum SquareTypes * out_type) -{ - enum SquareTypes parsed; - if (! read_tile_terrain_type_value (s, &parsed)) - return false; - - switch (parsed) { - case SQ_Desert: - case SQ_Plains: - case SQ_Grassland: - case SQ_Jungle: - case SQ_Tundra: - case SQ_FloodPlain: - case SQ_Swamp: - case SQ_Hills: - case SQ_Mountains: - case SQ_Forest: - case SQ_Volcano: - case SQ_SNOW_MOUNTAIN: - case SQ_SNOW_FOREST: - case SQ_SNOW_VOLCANO: - case SQ_Coast: - case SQ_Sea: - case SQ_Ocean: - *out_type = parsed; - return true; - - default: - return false; - } -} - -bool -read_direction_value (struct string_slice const * s, enum direction * out_dir) -{ - if (s == NULL || out_dir == NULL) - return false; - - struct string_slice trimmed = trim_string_slice (s, 1); - if (trimmed.len <= 0) - return false; - - if (slice_matches_str (&trimmed, "northeast")) { *out_dir = DIR_NE; return true; } - else if (slice_matches_str (&trimmed, "east" )) { *out_dir = DIR_E; return true; } - else if (slice_matches_str (&trimmed, "southeast")) { *out_dir = DIR_SE; return true; } - else if (slice_matches_str (&trimmed, "south" )) { *out_dir = DIR_S; return true; } - else if (slice_matches_str (&trimmed, "southwest")) { *out_dir = DIR_SW; return true; } - else if (slice_matches_str (&trimmed, "west" )) { *out_dir = DIR_W; return true; } - else if (slice_matches_str (&trimmed, "northwest")) { *out_dir = DIR_NW; return true; } - else if (slice_matches_str (&trimmed, "north" )) { *out_dir = DIR_N; return true; } - else - return false; -} - -bool -read_barbarian_activity_override (struct string_slice const * s, enum barbarian_activity_override * out) -{ - struct string_slice trimmed = trim_string_slice (s, 1); - if (trimmed.len <= 0) - return false; - - bool found = false; - char * extracted = extract_slice (s); - - struct { - char * str; - enum barbarian_activity_override value; - } possibilities[] = {{ .str = "none" , .value = BAO_NONE }, - { .str = (*p_labels)[LBL_NO_BARBARIANS ], .value = BAO_NO_BARBARIANS }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 1], .value = BAO_SEDENTARY }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 2], .value = BAO_ROAMING }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 3], .value = BAO_RESTLESS }, - { .str = (*p_labels)[LBL_NO_BARBARIANS + 4], .value = BAO_RAGING }, - { .str = (*p_labels)[LBL_RANDOM_BARBS] , .value = BAO_RANDOM }, - { .str = "No Barbarians" , .value = BAO_NO_BARBARIANS }, - { .str = "Sedentary" , .value = BAO_SEDENTARY }, - { .str = "Roaming" , .value = BAO_ROAMING }, - { .str = "Restless" , .value = BAO_RESTLESS }, - { .str = "Raging" , .value = BAO_RAGING }, - { .str = "Random" , .value = BAO_RANDOM }}; - - // Check for exact match - for (int n = 0; n < ARRAY_LEN (possibilities); n++) - if (0 == strcmp (extracted, possibilities[n].str)) { - *out = possibilities[n].value; - found = true; - break; - } - - // If not found, check again ignoring case - if (! found) - for (int n = 0; n < ARRAY_LEN (possibilities); n++) - if (0 == _stricmp (extracted, possibilities[n].str)) { - *out = possibilities[n].value; - found = true; - break; - } - - free (extracted); - return found; -} - -struct parsable_field_bit { - char * name; - int bit_value; -}; - -bool -read_bit_field (struct string_slice const * s, struct parsable_field_bit const * bits, int count_bits, int * out_field) -{ - struct string_slice trimmed = trim_string_slice (s, 0); - s = &trimmed; - - int tr; - if (s->len <= 0) - tr = 0; - else if (slice_matches_str (s, "all")) - tr = ~0; - else { - tr = 0; - char * cursor = &s->str[0]; - char * s_end = &s->str[s->len]; - while (1) { - struct string_slice name; - - if (cursor >= s_end) - break; - else if (! parse_string (&cursor, &name)) { - skip_white_space (&cursor); - if (cursor >= s_end) - break; - else - return false; // Invalid character in value - } - - bool matched_any = false; - for (int n = 0; n < count_bits; n++) - if (slice_matches_str (&name, bits[n].name)) { - tr |= bits[n].bit_value; - matched_any = true; - break; - } - if (! matched_any) - return false; - } - } - *out_field = tr; - return true; -} - -int -read_units_per_tile_limit (struct string_slice const * s, int * out_limits) -{ - int single_val; - if (read_int (s, &single_val)) { - out_limits[0] = out_limits[1] = out_limits[2] = single_val; - return true; - - } else { - bool success = false; - char * extracted_slice = extract_slice (s); - char * cursor = extracted_slice; - int vals[3]; - if (parse_int (&cursor, &vals[0]) && parse_int (&cursor, &vals[1]) && parse_int (&cursor, &vals[2]) && - skip_horiz_space (&cursor) && (*cursor == '\0')) { - for (int n = 0; n < ARRAY_LEN (vals); n++) - out_limits[n] = vals[n]; - success = true; - } - free (extracted_slice); - return success; - } -} - -struct config_parsing { - char * file_path; - char * text; - char * cursor; - struct string_slice key; - int displayed_error_message; -}; - -enum config_parse_error { - CPE_GENERIC, - CPE_BAD_VALUE, - CPE_BAD_BOOL_VALUE, - CPE_BAD_INT_VALUE, - CPE_BAD_STACK_LIMIT_VALUE, - CPE_BAD_KEY -}; - -void -handle_config_error_at (struct config_parsing * p, char * error_loc, enum config_parse_error err) -{ - char err_msg[1000]; - if (! p->displayed_error_message) { - int line_no = 1; - for (char * c = p->text; c < error_loc; c++) - line_no += *c == '\n'; - - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); - snprintf (err_msg, sizeof err_msg, "Error reading \"%s\" on line %d.", p->file_path, line_no); - err_msg[(sizeof err_msg) - 1] = '\0'; - PopupForm_add_text (popup, __, err_msg, false); - - if (err == CPE_GENERIC) { - if (p->key.str != NULL) - snprintf (err_msg, sizeof err_msg, "^The last key successfully read was \"%.*s\".", p->key.len, p->key.str); - else - snprintf (err_msg, sizeof err_msg, "^Error occurred before any keys could be read."); - } else if (err == CPE_BAD_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid.", p->key.len, p->key.str); - else if (err == CPE_BAD_BOOL_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"true\" or \"false\".", p->key.len, p->key.str); - else if (err == CPE_BAD_INT_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected an integer.", p->key.len, p->key.str); - else if (err == CPE_BAD_STACK_LIMIT_VALUE) - snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"false\", an integer, or a list of exactly three of those.", p->key.len, p->key.str); - else if (err == CPE_BAD_KEY) - snprintf (err_msg, sizeof err_msg, "^The key name \"%.*s\" is not recognized.", p->key.len, p->key.str); - err_msg[(sizeof err_msg) - 1] = '\0'; - PopupForm_add_text (popup, __, err_msg, false); - - patch_show_popup (popup, __, 0, 0); - p->displayed_error_message = 1; - } -} - -void -handle_config_error (struct config_parsing * p, enum config_parse_error err) -{ - handle_config_error_at (p, p->cursor, err); -} - -// Loads a config from the given file, layering it on top of is->current_config and appending its name to the list of loaded configs. Does NOT -// re-apply machine code edits. -void -load_config (char const * file_path, int path_is_relative_to_mod_dir) -{ - char err_msg[1000]; - struct c3x_config * cfg = &is->current_config; - - int full_path_size = 2 * MAX_PATH; - char * full_path = malloc (full_path_size); - if (path_is_relative_to_mod_dir) - snprintf (full_path, full_path_size, "%s\\%s", is->mod_rel_dir, file_path); - else - strncpy (full_path, file_path, full_path_size); - full_path[full_path_size - 1] = '\0'; - - char * text; { - char * utf8_text = file_to_string (full_path); - if (utf8_text == NULL) { - free (full_path); - return; - } - text = convert_from_utf8 (utf8_text, *p_code_page); - free (utf8_text); - if (text == NULL) { - snprintf (err_msg, sizeof err_msg, "Failed to re-encode contents of \"%s\". This file must contain UTF-8 text and only characters usable by Civ 3.", full_path); - err_msg[(sizeof err_msg) - 1] = '\0'; - pop_up_in_game_error (err_msg); - free (full_path); - return; - } - } - - struct perfume_spec_list { - struct perfume_spec * items; - int count; - } perfume_spec_lists[COUNT_PERFUME_KINDS] = {0}; - - struct parsed_unit_type_limit * parsed_unit_type_limits = NULL; - int parsed_unit_type_limit_count = 0; - - struct config_parsing p = { .file_path = full_path, .text = text, .cursor = text, .key = {0}, .displayed_error_message = 0 }; - struct error_line * unrecognized_lines = NULL; - while (1) { - skip_horiz_space (&p.cursor); - if (*p.cursor == '\0') - break; - else if (*p.cursor == '\n') - p.cursor++; // Continue to next line - else if (*p.cursor == ';') - skip_to_line_end (&p.cursor); // Skip comment line - else if (*p.cursor == '[') - skip_to_line_end (&p.cursor); // Skip section line - else if (parse_string (&p.cursor, &p.key) && skip_punctuation (&p.cursor, '=')) { // Parse key and equals sign - - struct string_slice value; - if (parse_string (&p.cursor, &value) || parse_bracketed_block (&p.cursor, &value)) { // Parse value - int ival, offset, recog_err_offset; - - // if key is for a boolean option - if (stable_look_up_slice (&is->boolean_config_offsets, &p.key, &offset)) { - if (read_int (&value, &ival)) - *((char *)cfg + offset) = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - - // if key is for an integer option - } else if (stable_look_up_slice (&is->integer_config_offsets, &p.key, &offset)) { - if (read_int (&value, &ival)) - *(int *)((byte *)cfg + offset) = ival; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - - // Handle city_work_radius separately from the other int options so we can clamp it and update the count var - } else if (slice_matches_str (&p.key, "city_work_radius")) { - if (read_int (&value, &ival)) { - cfg->city_work_radius = clamp (1, 7, ival); - is->workable_tile_count = workable_tile_counts[cfg->city_work_radius]; - } else - handle_config_error (&p, CPE_BAD_INT_VALUE); - - // if key is for something special - } else if (slice_matches_str (&p.key, "limit_units_per_tile")) { - if (! read_units_per_tile_limit (&value, &cfg->limit_units_per_tile[0])) - handle_config_error (&p, CPE_BAD_STACK_LIMIT_VALUE); - } else if (slice_matches_str (&p.key, "production_perfume") || slice_matches_str (&p.key, "perfume_specs")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct perfume_spec), - parse_production_perfume_spec, - (void **)&perfume_spec_lists[PK_PRODUCTION].items, - &perfume_spec_lists[PK_PRODUCTION].count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "technology_perfume")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct perfume_spec), - parse_technology_perfume_spec, - (void **)&perfume_spec_lists[PK_TECHNOLOGY].items, - &perfume_spec_lists[PK_TECHNOLOGY].count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "government_perfume")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct perfume_spec), - parse_government_perfume_spec, - (void **)&perfume_spec_lists[PK_GOVERNMENT].items, - &perfume_spec_lists[PK_GOVERNMENT].count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "building_prereqs_for_units")) { - if (0 <= (recog_err_offset = read_building_unit_prereqs (&value, &unrecognized_lines, &cfg->building_unit_prereqs))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "buildings_generating_resources")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct mill), - parse_mill, - (void **)&cfg->mills, - &cfg->count_mills))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_multi_start_extra_palaces")) { - if (! read_ai_multi_start_extra_palaces (&value, - &unrecognized_lines, - &cfg->ai_multi_start_extra_palaces, - &cfg->count_ai_multi_start_extra_palaces, - &cfg->ai_multi_start_extra_palaces_capacity)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_settler_perfume_on_founding")) { - if (! read_i31b (&value, &cfg->ai_settler_perfume_on_founding)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "land_retreat_rules")) { - if (! read_retreat_rules (&value, (int *)&cfg->land_retreat_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "sea_retreat_rules")) { - if (! read_retreat_rules (&value, (int *)&cfg->sea_retreat_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "draw_lines_using_gdi_plus")) { - if (! read_line_drawing_override (&value, (int *)&cfg->draw_lines_using_gdi_plus)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "double_minimap_size")) { - if (! read_minimap_doubling_mode (&value, (int *)&cfg->double_minimap_size)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "unit_cycle_search_criteria")) { - if (! read_unit_cycle_search_criteria (&value, (int *)&cfg->unit_cycle_search_criteria)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "override_no_ai_patrol")) { - if (! read_no_ai_patrol_override (&value, (int *)&cfg->override_no_ai_patrol)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "override_barbarian_activity_level_for_scenario_maps")) { - if (! read_barbarian_activity_override (&value, &cfg->override_barbarian_activity_level_for_scenario_maps)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "special_defensive_bombard_rules")) { - struct parsable_field_bit bits[] = { - {"lethal" , SDBR_LETHAL}, - {"not-invisible" , SDBR_NOT_INVISIBLE}, - {"aerial" , SDBR_AERIAL}, - {"blitz" , SDBR_BLITZ}, - {"docked-vs-land", SDBR_DOCKED_VS_LAND}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_defensive_bombard_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "special_zone_of_control_rules")) { - struct parsable_field_bit bits[] = { - {"lethal" , SZOCR_LETHAL}, - {"aerial" , SZOCR_AERIAL}, - {"amphibious" , SZOCR_AMPHIBIOUS}, - {"not-from-inside", SZOCR_NOT_FROM_INSIDE}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_zone_of_control_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "land_transport_rules")) { - struct parsable_field_bit bits[] = { - {"load-onto-boat" , LTR_LOAD_ONTO_BOAT}, - {"join-army" , LTR_JOIN_ARMY}, - {"no-defense-from-inside", LTR_NO_DEFENSE_FROM_INSIDE}, - {"no-escape" , LTR_NO_ESCAPE}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->land_transport_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "special_helicopter_rules")) { - struct parsable_field_bit bits[] = { - {"allow-on-carriers" , SHR_ALLOW_ON_CARRIERS}, - {"passenger-airdrop" , SHR_PASSENGER_AIRDROP}, - {"no-defense-from-inside", SHR_NO_DEFENSE_FROM_INSIDE}, - {"no-escape" , SHR_NO_ESCAPE}, - }; - if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_helicopter_rules)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "work_area_limit")) { - if (! read_work_area_limit (&value, (int *)&cfg->work_area_limit)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "work_area_improvements")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct work_area_improvement), - parse_work_area_improvement, - (void **)&cfg->work_area_improvements, - &cfg->count_work_area_improvements))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "day_night_cycle_mode")) { - if (! read_day_night_cycle_mode (&value, (int *)&cfg->day_night_cycle_mode)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "distribution_hub_yield_division_mode")) { - if (! read_distribution_hub_yield_division_mode (&value, (int *)&cfg->distribution_hub_yield_division_mode)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_distribution_hub_build_strategy")) { - if (! read_ai_distribution_hub_build_strategy (&value, (int *)&cfg->ai_distribution_hub_build_strategy)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ai_auto_build_great_wall_strategy")) { - if (! read_ai_auto_build_great_wall_strategy (&value, (int *)&cfg->ai_auto_build_great_wall_strategy)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "great_wall_auto_build_wonder_name")) { - if (cfg->great_wall_auto_build_wonder_name != NULL) { - free (cfg->great_wall_auto_build_wonder_name); - cfg->great_wall_auto_build_wonder_name = NULL; - } - cfg->great_wall_auto_build_wonder_name = copy_trimmed_string_or_null (&value, 1); - cfg->great_wall_auto_build_wonder_improv_id = -1; - } else if (slice_matches_str (&p.key, "exclude_types_from_units_per_tile_limit")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->exclude_types_from_units_per_tile_limit)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "limit_defensive_retreat_on_water_to_types")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->limit_defensive_retreat_on_water_to_types)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "ptw_like_artillery_targeting")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->ptw_arty_types)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "can_bombard_only_sea_tiles")) { - if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->can_bombard_only_sea_tiles)) - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "civ_aliases_by_era")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct civ_era_alias_list), - parse_civ_name_alias_list, - (void **)&cfg->civ_era_alias_lists, - &cfg->count_civ_era_alias_lists))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "leader_aliases_by_era")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct leader_era_alias_list), - parse_leader_name_alias_list, - (void **)&cfg->leader_era_alias_lists, - &cfg->count_leader_era_alias_lists))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "unit_limits")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct parsed_unit_type_limit), - parse_unit_type_limit, - (void **)&parsed_unit_type_limits, - &parsed_unit_type_limit_count))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "aircraft_victory_animation")) { - struct string_slice trimmed = trim_string_slice (&value, 1); - bool value_ok = false; - if (slice_matches_str (&trimmed, "none")) { - if (cfg->aircraft_victory_animation != NULL) { - free (cfg->aircraft_victory_animation); - cfg->aircraft_victory_animation = NULL; - } - value_ok = true; - } else if (trimmed.len > 0) { - AnimationType unused; - if (find_animation_type_by_name (&trimmed, true, &unused)) { - if (cfg->aircraft_victory_animation != NULL) - free (cfg->aircraft_victory_animation); - cfg->aircraft_victory_animation = extract_slice (&trimmed); - value_ok = true; - } - } - if (! value_ok) - handle_config_error (&p, CPE_BAD_VALUE); - - // if key is for an obsolete option - } else if (slice_matches_str (&p.key, "patch_disembark_immobile_bug")) { - if (read_int (&value, &ival)) - cfg->patch_blocked_disembark_freeze = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "anarchy_length_reduction_percent")) { - if (read_int (&value, &ival)) - cfg->anarchy_length_percent = 100 - ival; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - } else if (slice_matches_str (&p.key, "adjust_minimum_city_separation")) { - if (read_int (&value, &ival)) - cfg->minimum_city_separation = ival + 1; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - } else if (slice_matches_str (&p.key, "reduce_max_escorts_per_ai_transport")) { - if (read_int (&value, &ival)) - cfg->max_ai_naval_escorts = 3 - ival; - else - handle_config_error (&p, CPE_BAD_INT_VALUE); - } else if (slice_matches_str (&p.key, "retreat_rules")) { - int rules; - if (read_retreat_rules (&value, &rules)) { - cfg->land_retreat_rules = rules; - cfg->sea_retreat_rules = rules; - } else - handle_config_error (&p, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "halve_ai_research_rate")) { - if (read_int (&value, &ival)) { - if (ival) // halving = true => set multiplier to 50, otherwise do nothing - cfg->ai_research_multiplier = 50; - } else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "enable_ai_two_city_start")) { - if (read_int (&value, &ival)) - cfg->ai_multi_city_start = (ival != 0) ? 2 : 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "polish_non_air_precision_striking")) { - if (read_int (&value, &ival)) - cfg->polish_precision_striking = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "promote_forbidden_palace_decorruption")) { - if (read_int (&value, &ival)) - cfg->promote_wonder_decorruption_effect = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "move_trade_net_object")) { - ; // No nothing. This setting no longer serves any purpose. - - // if key was previously misspelled - } else if (slice_matches_str (&p.key, "share_visibility_in_hoseat")) { - if (read_int (&value, &ival)) - cfg->share_visibility_in_hotseat = ival != 0; - else - handle_config_error (&p, CPE_BAD_BOOL_VALUE); - } else if (slice_matches_str (&p.key, "unit_group")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct unit_counter_group), - parse_unit_counter_group, - (void **)&cfg->unit_counter_groups, - &cfg->count_unit_counter_groups))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - } else if (slice_matches_str (&p.key, "counter_rule")) { - if (0 <= (recog_err_offset = read_recognizables (&value, - &unrecognized_lines, - sizeof (struct counter_rule), - parse_counter_rule, - (void **)&cfg->counter_rules, - &cfg->count_counter_rules))) - handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); - - } else { - handle_config_error (&p, CPE_BAD_KEY); - } - - - } else { // Failed to parse value - handle_config_error (&p, CPE_BAD_VALUE); - skip_to_line_end (&p.cursor); - } - - } else { // Failed to categorize line - handle_config_error (&p, CPE_GENERIC); - skip_to_line_end (&p.cursor); - } - } - - if (cfg->warn_about_unrecognized_names && (unrecognized_lines != NULL)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "Unrecognized names in %s:", full_path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - for (struct error_line * line = unrecognized_lines; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - patch_show_popup (popup, __, 0, 0); - } - - // Copy perfume specs from lists to tables - for (int n = 0; n < COUNT_PERFUME_KINDS; n++) { - struct table * table = &cfg->perfume_specs[n]; - struct perfume_spec_list * list = &perfume_spec_lists[n]; - if (list->items != NULL) { - for (int k = 0; k < list->count; k++) { - struct perfume_spec * ps = &list->items[k]; - stable_insert (table, ps->name, ps->value); - } - free (list->items); - } - } - - // Copy unit type limits from list to table - if (parsed_unit_type_limits != NULL) { - for (int n = 0; n < parsed_unit_type_limit_count; n++) { - struct parsed_unit_type_limit * parsed_lim = &parsed_unit_type_limits[n]; - struct unit_type_limit * lim_values = malloc (sizeof *lim_values); - *lim_values = parsed_lim->limit; - stable_insert (&cfg->unit_limits, parsed_lim->name, (int)lim_values); - } - free (parsed_unit_type_limits); - } - - free (text); - free_error_lines (unrecognized_lines); - - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = full_path; - new_lcn->next = NULL; - - top_lcn->next = new_lcn; -} - -bool -tile_coords_from_ptr (Map * map, Tile * tile, int * out_x, int * out_y) -{ - if ((tile == NULL) || (tile == p_null_tile) || (map == NULL)) - return false; - - int tile_count = map->TileCount; - for (int index = 0; index < tile_count; index++) { - Tile * candidate = Map_get_tile (map, __, index); - if (candidate == tile) { - tile_index_to_coords (map, index, out_x, out_y); - return true; - } - } - - return false; -} - -int -get_pending_district_request_key (int city_id, int district_id) -{ - if ((city_id < 0) || (district_id < 0)) - return -1; - unsigned int key = ((unsigned int)city_id << 16) | (unsigned int)(district_id & 0xffff); - return (int)key; -} - -struct pending_district_request * -find_pending_district_request (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0)) - return NULL; - - int civ_id = city->Body.CivID; - int city_id = city->Body.ID; - int key = get_pending_district_request_key (city_id, district_id); - if (key < 0) - return NULL; - - int stored; - if (itable_look_up (&is->city_pending_district_requests[civ_id], key, &stored)) { - struct pending_district_request * req = (struct pending_district_request *)stored; - if ((req != NULL) && (req->civ_id == civ_id) && (req->city_id == city_id) && (req->district_id == district_id)) { - if (req->city != city) - req->city = city; - return req; - } - } - return NULL; -} - -struct pending_district_request * -create_pending_district_request (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return NULL; - - struct pending_district_request * existing = find_pending_district_request (city, district_id); - if (existing != NULL) - return existing; - - int civ_id = city->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) - return NULL; - - struct pending_district_request * req = (struct pending_district_request *)calloc (1, sizeof *req); - if (req == NULL) - return NULL; - - req->city = city; - req->city_id = city->Body.ID; - req->civ_id = civ_id; - req->district_id = district_id; - req->assigned_worker_id = -1; - req->target_x = -1; - req->target_y = -1; - req->worker_assigned_turn = 0; - - int key = get_pending_district_request_key (req->city_id, district_id); - if (key < 0) { - free (req); - return NULL; - } - - char ss[200]; - snprintf (ss, sizeof ss, "create_pending_district_request: Creating pending district request for city %s (ID %d) district ID %d with key %d\n", - city->Body.CityName, city->Body.ID, district_id, key); - (*p_OutputDebugStringA) (ss); - - itable_insert (&is->city_pending_district_requests[civ_id], key, (int)req); - return req; -} - -struct pending_district_request * -find_pending_district_request_by_coords (City * city_or_null, int tile_x, int tile_y, int district_id) -{ - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - - int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((civ_id < 0) || (civ_id >= 32)) - return NULL; - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req == NULL) continue; - if (req->district_id != district_id) continue; - if (city_or_null != NULL) { - int city_id = city_or_null->Body.ID; - if (req->city_id != city_id) - continue; - req->city = city_or_null; - req->civ_id = city_or_null->Body.CivID; - } - if ((req->target_x == tile_x) && (req->target_y == tile_y)) - return req; - } - return NULL; -} - -bool -is_tile_earmarked_for_district (int tile_x, int tile_y) -{ - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req == NULL) continue; - if ((req->target_x == tile_x) && (req->target_y == tile_y)) - return true; - } - return false; -} - -struct district_instance * -get_district_instance (Tile * tile) -{ - if (tile == NULL || tile == p_null_tile) - return NULL; - - int stored_ptr; - if (! itable_look_up (&is->district_tile_map, (int)tile, &stored_ptr)) - return NULL; - - struct district_instance * inst = (struct district_instance *)stored_ptr; - - if ((inst == NULL) || (inst->district_id < 0) || (inst->district_id >= is->district_count)) - return NULL; - - return inst; -} - -struct wonder_district_info * -get_wonder_district_info (Tile * tile) -{ - if (tile == NULL || tile == p_null_tile) - return NULL; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return NULL; - - return &inst->wonder_info; -} - -void -remove_district_instance (Tile * tile) -{ - if (tile == NULL || tile == p_null_tile) - return; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - free (inst); - itable_remove (&is->district_tile_map, (int)tile); - } -} - -void -district_instance_set_coords (struct district_instance * inst, int tile_x, int tile_y) -{ - if (inst == NULL) - return; - - // Normalize coordinates to map bounds for consistency - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - inst->tile_x = tile_x; - inst->tile_y = tile_y; -} - -struct district_instance * -ensure_district_instance (Tile * tile, int district_id, int tile_x, int tile_y) -{ - if (tile == NULL || tile == p_null_tile) - return NULL; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - return inst; - } - - inst = (struct district_instance *)calloc (1, sizeof(struct district_instance)); - if (inst == NULL) - return NULL; - - inst->state = DS_UNDER_CONSTRUCTION; - inst->district_id = district_id; - inst->built_by_civ_id = -1; - inst->completed_turn = -1; - - // Initialize wonder_info (only relevant for wonder districts) - inst->wonder_info.state = WDS_UNUSED; - inst->wonder_info.city = NULL; - inst->wonder_info.city_id = -1; - inst->wonder_info.wonder_index = -1; - inst->natural_wonder_info.natural_wonder_id = -1; - - district_instance_set_coords (inst, tile_x, tile_y); - itable_insert (&is->district_tile_map, (int)tile, (int)inst); - return inst; -} - -bool -district_instance_get_coords (struct district_instance * inst, Tile * tile, int * out_x, int * out_y) -{ - if ((inst == NULL) || (out_x == NULL) || (out_y == NULL)) - return false; - - int x = inst->tile_x; - int y = inst->tile_y; - if ((x >= 0) && (y >= 0)) { - *out_x = x; - *out_y = y; - return true; - } - - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile_coords_from_ptr (&p_bic_data->Map, tile, &x, &y)) { - district_instance_set_coords (inst, x, y); - *out_x = x; - *out_y = y; - return true; - } - - return false; -} - -struct natural_wonder_district_config const * -get_natural_wonder_config_by_id (int natural_wonder_id) -{ - if (! is->current_config.enable_natural_wonders) - return NULL; - if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) - return NULL; - return &is->natural_wonder_configs[natural_wonder_id]; -} - -void -assign_natural_wonder_to_tile (Tile * tile, int tile_x, int tile_y, int natural_wonder_id) -{ - if (! is->current_config.enable_natural_wonders) - return; - if ((tile == NULL) || (tile == p_null_tile)) - return; - if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) - return; - - if (get_natural_wonder_config_by_id (natural_wonder_id) == NULL) - return; - - struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, tile_x, tile_y); - if (inst == NULL) - return; - - inst->district_id = NATURAL_WONDER_DISTRICT_ID; - inst->state = DS_COMPLETED; - inst->natural_wonder_info.natural_wonder_id = natural_wonder_id; - set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); -} - -int -apply_district_bonus_entries (struct district_instance * inst, - struct district_bonus_list const * extras, - int district_id) -{ - if ((inst == NULL) || (extras == NULL) || (extras->count <= 0)) - return 0; - - int tile_x = inst->tile_x; - int tile_y = inst->tile_y; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return 0; - - int bonus = 0; - for (int i = 0; i < extras->count; i++) { - struct district_bonus_entry const * entry = &extras->entries[i]; - if (entry->type == DBET_TILE) { - if (tile_matches_square_type (tile, entry->tile_type)) - bonus += entry->bonus; - } else if (entry->type == DBET_BUILDING) { - if (entry->building_id >= 0 && - tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, entry->building_id)) - bonus += entry->bonus; - } - } - - return bonus; -} - -void -get_effective_district_yields (struct district_instance * inst, - struct district_config const * cfg, - int * out_food, - int * out_shields, - int * out_gold, - int * out_science, - int * out_culture, - int * out_happiness) -{ - int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; - - if (cfg != NULL && is->current_config.enable_districts) { - food = cfg->food_bonus; - shields = cfg->shield_bonus; - gold = cfg->gold_bonus; - science = cfg->science_bonus; - culture = cfg->culture_bonus; - happiness = cfg->happiness_bonus; - - int district_id = (inst != NULL) ? inst->district_id : -1; - food += apply_district_bonus_entries (inst, &cfg->food_bonus_extras, district_id); - shields += apply_district_bonus_entries (inst, &cfg->shield_bonus_extras, district_id); - gold += apply_district_bonus_entries (inst, &cfg->gold_bonus_extras, district_id); - science += apply_district_bonus_entries (inst, &cfg->science_bonus_extras, district_id); - culture += apply_district_bonus_entries (inst, &cfg->culture_bonus_extras, district_id); - happiness += apply_district_bonus_entries (inst, &cfg->happiness_bonus_extras, district_id); - } - - if (inst != NULL && is->current_config.enable_natural_wonders && inst->district_id == NATURAL_WONDER_DISTRICT_ID) { - struct natural_wonder_district_config const * nwcfg = get_natural_wonder_config_by_id (inst->natural_wonder_info.natural_wonder_id); - if (nwcfg != NULL) { - food += nwcfg->food_bonus; - shields += nwcfg->shield_bonus; - gold += nwcfg->gold_bonus; - science += nwcfg->science_bonus; - culture += nwcfg->culture_bonus; - happiness += nwcfg->happiness_bonus; - } - } - - if (out_food != NULL) - *out_food = food; - if (out_shields != NULL) - *out_shields = shields; - if (out_gold != NULL) - *out_gold = gold; - if (out_science != NULL) - *out_science = science; - if (out_culture != NULL) - *out_culture = culture; - if (out_happiness != NULL) - *out_happiness = happiness; -} - -int -natural_wonder_min_distance_sq (int x, - int y, - struct wonder_location const * placements, - int placement_count) -{ - if ((placements == NULL) || (placement_count <= 0)) - return INT_MAX; - - int best = INT_MAX; - for (int i = 0; i < placement_count; i++) { - int dx, dy; - compute_wrapped_deltas (x, y, placements[i].x, placements[i].y, &dx, &dy); - int dist_sq = dx * dx + dy * dy; - if (dist_sq < best) - best = dist_sq; - } - return best; -} - -bool -continent_has_natural_wonder (int continent_id, - struct wonder_location const * placements, - int placement_count) -{ - if (continent_id < 0) - return false; - if ((placements == NULL) || (placement_count <= 0)) - return false; - - for (int i = 0; i < placement_count; i++) { - Tile * placed_tile = tile_at (placements[i].x, placements[i].y); - if ((placed_tile == NULL) || (placed_tile == p_null_tile)) - continue; - int placed_continent_id = placed_tile->vtable->m46_Get_ContinentID (placed_tile); - if (placed_continent_id == continent_id) - return true; - } - - return false; -} - -bool -natural_wonder_candidate_list_push (struct natural_wonder_candidate_list * list, Tile * tile, int tile_x, int tile_y) -{ - if (list == NULL) - return false; - - if (list->count >= list->capacity) { - int new_capacity = (list->capacity > 0) ? (list->capacity * 2) : 8; - struct natural_wonder_candidate * grown = - (struct natural_wonder_candidate *)realloc (list->entries, new_capacity * sizeof *grown); - if (grown == NULL) - return false; - list->entries = grown; - list->capacity = new_capacity; - } - - struct natural_wonder_candidate * entry = &list->entries[list->count++]; - entry->tile = tile; - entry->x = (short)tile_x; - entry->y = (short)tile_y; - return true; -} - -bool -natural_wonder_tile_is_clear (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (tile->CityID >= 0) return false; - if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return false; - if (tile->vtable->m15_Check_Goody_Hut (tile, __, 0)) return false; - if (tile->vtable->m39_Get_Resource_Type (tile) >= 0) return false; - if (tile->vtable->m18_Check_Mines (tile, __, 0)) return false; - if (get_district_instance (tile) != NULL) return false; - - // Check if this tile is a starting location for any civ - int tile_index = (p_bic_data->Map.Width >> 1) * tile_y + ((tile_x >> 1) & 0x7FFF); - for (int civ = 0; civ < p_bic_data->Map.Civ_Count; civ++) { - if (p_bic_data->Map.Starting_Locations[civ] == tile_index) { - return false; - } - } - - return true; -} - -bool -district_exists_within_distance (int tile_x, int tile_y, int district_id, int civ_id, int min_distance) -{ - if ((district_id < 0) || (district_id >= is->district_count) || (min_distance < 0)) - return false; - - for (int dist = 0; dist <= min_distance; dist++) { - struct vertex { - int x, y; - } vertices[4] = { - {tile_x , tile_y - 2*dist}, - {tile_x + 2*dist, tile_y }, - {tile_x , tile_y + 2*dist}, - {tile_x - 2*dist, tile_y } - }; - - int edge_dirs[4] = {3, 5, 7, 1}; - int edge_len = (dist == 0) ? 1 : 2 * dist; - - for (int vert = 0; vert < 4; vert++) { - wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); - int dx, dy; - neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); - for (int j = 0; j < edge_len; j++) { - int cx = vertices[vert].x + j * dx; - int cy = vertices[vert].y + j * dy; - wrap_tile_coords (&p_bic_data->Map, &cx, &cy); - - Tile * tile = tile_at (cx, cy); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if ((civ_id >= 0) && (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id)) - continue; - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == district_id)) - return true; - } - } - } - - return false; -} - -void -detach_workers_from_request (struct pending_district_request * req) -{ - if (req == NULL) - return; - - int civ_id = req->civ_id; - if ((civ_id < 0) || (civ_id >= 32)) { - for (int civ = 0; civ < 32; civ++) { - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - if ((rec != NULL) && (rec->pending_req == req)) - rec->pending_req = NULL; - } - } - return; - } - - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - if ((rec != NULL) && (rec->pending_req == req)) - rec->pending_req = NULL; - } -} - -void -remove_pending_district_request (struct pending_district_request * req) -{ - if (req == NULL) - return; - - int civ_id = req->civ_id; - if ((civ_id < 0) || (civ_id >= 32)) - return; - - int key = get_pending_district_request_key (req->city_id, req->district_id); - - detach_workers_from_request (req); - - if ((req->target_x >= 0) && (req->target_y >= 0)) { - Tile * tile = tile_at (req->target_x, req->target_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && - (inst->district_id == req->district_id) && - (inst->state != DS_COMPLETED)) - remove_district_instance (tile); - } - } - - if (key >= 0) - itable_remove (&is->city_pending_district_requests[civ_id], key); - req->city = NULL; - req->city_id = -1; - req->civ_id = -1; - free (req); -} - -bool __fastcall -patch_Leader_impl_would_raze_city (Leader * this, int edx, City * city) -{ - return is->current_config.prevent_razing_by_players ? false : Leader_impl_would_raze_city (this, __, city); -} - -int __fastcall patch_Unit_get_max_move_points (Unit * this); - -// This function is used to fix a bug where the game would freeze when using disembark all on a transport that contained an immobile unit. The bug -// comes from the fact that the function to disembark all units loops continuously over units in the transport until there are none left that -// can be disembarked. The problem is the logic to check disembarkability erroneously reports immobile units as disembarkable when they're not, -// so the program gets stuck in an infinite loop. The fix affects the function that checks disembarkability, replacing a call to -// Unit_get_max_move_points with a call to the function below. This function returns zero for immobile units, causing the caller to report -// (correctly) that the unit cannot be disembarked. -int __fastcall -patch_Unit_get_max_move_points_for_disembarking (Unit * this) -{ - if (is->current_config.patch_blocked_disembark_freeze && - UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Immobile)) - return 0; - else - return patch_Unit_get_max_move_points (this); -} - -// Unit::move_to_adjacent_tile uses a separate "spend all remaining movement when disembarking" branch for land units moving from water to land. -// Bridge districts still look like water tiles to that stock logic, so stepping off a bridge can incorrectly consume the whole turn. When the -// wrapper around move_to_adjacent_tile detects bridge->land movement, it precomputes the correct spent-moves total and exposes it here. -int __fastcall -patch_Unit_get_max_move_points_for_bridge_exit (Unit * this) -{ - if ((this != NULL) && (this == is->move_spend_override_unit)) - return is->move_spend_override_value; - else - return patch_Unit_get_max_move_points (this); -} - -// This func implements GA remaining turns indicator. It intercepts a call to some kind of text processing function when it's called to process the -// text in the lower right (containing current research, GA status, & mobilization) and splices in the number of remaining GA turns if in a GA. -int __fastcall -patch_PCX_Image_process_tech_ga_status (PCX_Image * this, int edx, char * str) -{ - Leader * player = &leaders[p_main_screen_form->Player_CivID]; - if (is->current_config.show_golden_age_turns_remaining && - (*p_current_turn_no < player->Golden_Age_End)) { - int turns_left = player->Golden_Age_End - *p_current_turn_no; - char const * ga_label = (*p_labels)[LBL_GOLDEN_AGE]; - char const * ga_str_start = strstr (str, ga_label); - if (ga_str_start != NULL) { - char s[250]; - char const * ga_str_end = ga_str_start + strlen (ga_label); - snprintf (s, sizeof s, "%.*s (%d)%s", ga_str_end - str, str, turns_left, ga_str_end); - s[(sizeof s) - 1] = '\0'; - strncpy (str, s, sizeof s); - } - } - return PCX_Image_process_text (this, __, str); -} - -bool __fastcall -patch_Leader_is_tile_visible (Leader * this, int edx, int x, int y) -{ - Tile_Body * tile = &tile_at (x, y)->Body; - unsigned vis_bits = tile->FOWStatus | tile->V3 | tile->Visibility | tile->field_D0_Visibility; - if (vis_bits & (1 << this->ID)) - return true; - else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND - ((1 << this->ID) & *p_human_player_bits) && // "this" is a human player AND - (vis_bits & *p_human_player_bits)) // any human player has visibility on the tile - return true; - else - return false; -} - -bool __fastcall -patch_Main_Screen_Form_is_unit_visible_to_player (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * unit) -{ - return (unit->Body.CivID == this->Player_CivID) || patch_Leader_is_tile_visible (&leaders[this->Player_CivID], __, tile_x, tile_y); -} - -enum direction -reverse_dir (enum direction dir) -{ - enum direction const reversed[] = { - DIR_ZERO, // DIR_ZERO - DIR_SW , // DIR_NE - DIR_W , // DIR_E - DIR_NW , // DIR_SE - DIR_N , // DIR_S - DIR_NE , // DIR_SW - DIR_E , // DIR_W - DIR_SE , // DIR_NW - DIR_S , // DIR_N - }; - int n = (int)dir; - if ((n >= 0) && (n < ARRAY_LEN (reversed))) - return reversed[n]; - else - return DIR_ZERO; -} - -bool -direction_to_offset (enum direction dir, int * out_dx, int * out_dy) -{ - int dx = 0, dy = 0; - - switch (dir) { - case DIR_NE: dx = 1; dy = -1; break; - case DIR_E: dx = 2; dy = 0; break; - case DIR_SE: dx = 1; dy = 1; break; - case DIR_S: dx = 0; dy = 2; break; - case DIR_SW: dx = -1; dy = 1; break; - case DIR_W: dx = -2; dy = 0; break; - case DIR_NW: dx = -1; dy = -1; break; - case DIR_N: dx = 0; dy = -2; break; - case DIR_ZERO: - default: - return false; - } - - if (out_dx != NULL) - *out_dx = dx; - if (out_dy != NULL) - *out_dy = dy; - return true; -} - -int -direction_to_neighbor_bit (enum direction dir) -{ - switch (dir) { - case DIR_NE: return 1; - case DIR_E: return 2; - case DIR_SE: return 3; - case DIR_S: return 4; - case DIR_SW: return 5; - case DIR_W: return 6; - case DIR_NW: return 7; - case DIR_N: return 0; // Matches engine behaviour where neighbor index 8 maps to 0 - default: - return -1; - } -} - -bool -get_primary_river_direction (Tile * tile, enum direction * out_dir) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - char river_bits = tile->vtable->m37_Get_River_Code (tile); - if (river_bits == 0) - return false; - - enum direction dirs[] = {DIR_E, DIR_W, DIR_SE, DIR_NE, DIR_SW, DIR_NW, DIR_S, DIR_N}; - for (int i = 0; i < (int)ARRAY_LEN (dirs); i++) { - int bit = direction_to_neighbor_bit (dirs[i]); - if ((bit >= 0) && ((river_bits & (1 << bit)) != 0)) { - if (out_dir != NULL) - *out_dir = dirs[i]; - return true; - } - } - - return false; -} - -void -wrap_tile_coords (Map * map, int * x, int * y) -{ - if (map->Flags & 1) { - if (*x < 0) *x += map->Width; - else if (*x >= map->Width) *x -= map->Width; - } - if (map->Flags & 2) { - if (*y < 0) *y += map->Height; - else if (*y >= map->Height) *y -= map->Height; - } -} - -void -tile_index_to_coords (Map * map, int index, int * out_x, int * out_y) -{ - if ((index >= 0) && (index < map->TileCount)) { - int width = map->Width; - int double_row = index / width, double_row_rem = index % width; - if (double_row_rem < width/2) { - *out_x = 2 * double_row_rem; - *out_y = 2 * double_row; - } else { - *out_x = 1 + 2 * (double_row_rem - width/2); - *out_y = 2 * double_row + 1; - } - } else - *out_x = *out_y = -1; -} - -int -tile_coords_to_index (Map * map, int x, int y) -{ - if ((map == NULL) || (x < 0) || (y < 0) || (x >= map->Width) || (y >= map->Height)) - return -1; - - int width = map->Width; - int row = y / 2; - if ((y & 1) == 0) { - return row * width + (x / 2); - } else { - return row * width + (width / 2) + (x / 2); - } -} - -Tile * -tile_at_index (Map * map, int i) -{ - int x, y; - tile_index_to_coords (map, i, &x, &y); - return tile_at (x, y); -} - -void -get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y) -{ - int dx, dy; - neighbor_index_to_diff (neighbor_index, &dx, &dy); - *out_x = x + dx; - *out_y = y + dy; - wrap_tile_coords (map, out_x, out_y); -} - -Tile * __stdcall -tile_at_city_or_null (City * city_or_null) -{ - if (city_or_null) - return tile_at (city_or_null->Body.X, city_or_null->Body.Y); - else - return p_null_tile; -} - -Unit * -get_unit_ptr (int id) -{ - if ((p_units->Units != NULL) && - (id >= 0) && (id <= p_units->LastIndex)) { - Unit_Body * body = p_units->Units[id].Unit; - if (body != NULL) { - Unit * unit = (Unit *)((char *)body - offsetof (Unit, Body)); - if (unit != NULL) - return unit; - } - } - return NULL; -} - -bool -is_land_transport (Unit * unit) -{ - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - return type->Unit_Class == UTC_Land && type->Transport_Capacity > 0 && ! Unit_has_ability (unit, __, UTA_Army); -} - -bool -is_in_land_transport (Unit * unit) -{ - Unit * container = get_unit_ptr (unit->Body.Container_Unit); - return container != NULL && is_land_transport (container); -} - -// Checks if the unit is inside a transport (either helicopter or land transport) from which it is not allowed to defend according to the mod config. -bool -cannot_defend_inside_transport (Unit * unit) -{ - Unit * container = get_unit_ptr (unit->Body.Container_Unit); - if (container != NULL) { - if ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && is_land_transport (container)) - return true; - - if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return true; - } - return false; -} - -struct unit_tile_iter { - int id; - int item_index; - Unit * unit; -}; - -void -uti_next (struct unit_tile_iter * uti) -{ - if (((p_tile_units->Base.Items == NULL) || (uti->item_index < 0)) || - (uti->item_index > p_tile_units->Base.LastIndex)) { - uti->item_index = -1; - uti->id = p_tile_units->DefaultValue; - } else { - Base_List_Item * item = &p_tile_units->Base.Items[uti->item_index]; - uti->item_index = item->V; - uti->id = (int)item->Object; - } - uti->unit = get_unit_ptr (uti->id); -} - -struct unit_tile_iter -uti_init (Tile * tile) -{ - struct unit_tile_iter tr; - int tile_unit_id = tile->vtable->m40_get_TileUnit_ID (tile); - tr.id = TileUnits_TileUnitID_to_UnitID (p_tile_units, __, tile_unit_id, &tr.item_index); - tr.unit = get_unit_ptr (tr.id); - return tr; -} - -#define FOR_UNITS_ON(uti_name, tile) for (struct unit_tile_iter uti_name = uti_init (tile); uti_name.id != -1; uti_next (&uti_name)) - -bool -tile_has_enemy_unit (Tile * tile, int civ_id) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - if ((civ_id < 0) || (civ_id >= 32)) - return false; - - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit == NULL) || (unit->Body.Container_Unit >= 0)) - continue; - if (unit->Body.CivID == civ_id) - continue; - if (unit->vtable->is_enemy_of_civ (unit, __, civ_id, 0)) - return true; - } - - return false; -} - -struct citizen_iter { - int index; - Citizens * list; - Citizen_Base * ctzn; -}; - -void -ci_next (struct citizen_iter * ci) -{ - while (1) { - ci->index++; - if (ci->index > ci->list->LastIndex) { - ci->ctzn = NULL; - break; - } else { - Citizen_Body * body = ci->list->Items[ci->index].Body; - if ((body != NULL) && ((int)body != offsetof (Citizen_Base, Body))) { - ci->ctzn = (Citizen_Base *)((int)body - offsetof (Citizen_Base, Body)); - break; - } - } - } -} - -struct citizen_iter -ci_init (City * city) -{ - struct citizen_iter tr; - tr.index = -1; - tr.list = &city->Body.Citizens; - tr.ctzn = NULL; - if (city->Body.Citizens.Items != NULL) - ci_next (&tr); - return tr; -} - -#define FOR_CITIZENS_IN(ci_name, city) for (struct citizen_iter ci_name = ci_init (city); (ci_name.list->Items != NULL) && (ci_name.index <= ci.list->LastIndex); ci_next (&ci_name)) - -struct city_of_iter { - int city_id; - int civ_id; - City * city; -}; - -void -coi_next (struct city_of_iter * coi) -{ - coi->city_id++; - while (coi->city_id <= p_cities->LastIndex) { - City_Body * body = p_cities->Cities[coi->city_id].City; - if ((body != NULL) && ((int)body != offsetof (City, Body)) && (body->CivID == coi->civ_id)) { - coi->city = (City *)((char *)body - offsetof (City, Body)); - break; - } - coi->city_id++; - } -} - -struct city_of_iter -coi_init (int civ_id) -{ - struct city_of_iter tr = { .city_id = -1, .civ_id = civ_id, .city = NULL }; - if (p_cities->Cities != NULL) - coi_next (&tr); - else - tr.city_id = p_cities->LastIndex + 1; - return tr; -} - -#define FOR_CITIES_OF(coi_name, civ_id) for (struct city_of_iter coi_name = coi_init (civ_id); coi_name.city_id <= p_cities->LastIndex; coi_next (&coi_name)) - -struct tiles_around_iter { - int center_x, center_y; - int n, num_tiles; - Tile * tile; - int tile_x, tile_y; -}; - -void -tai_next (struct tiles_around_iter * tai) -{ - tai->tile = p_null_tile; - while ((tai->n < tai->num_tiles) && (tai->tile == p_null_tile)) { - tai->n += 1; - int tx, ty; - get_neighbor_coords (&p_bic_data->Map, tai->center_x, tai->center_y, tai->n, &tx, &ty); - if ((tx >= 0) && (tx < p_bic_data->Map.Width) && (ty >= 0) && (ty < p_bic_data->Map.Height)) { - tai->tile = tile_at (tx, ty); - tai->tile_x = tx; - tai->tile_y = ty; - } - } -} - -struct tiles_around_iter -tai_init (int num_tiles, int x, int y) -{ - struct tiles_around_iter tr; - tr.center_x = x; - tr.center_y = y; - tr.n = 0; - tr.num_tiles = num_tiles; - tr.tile = tile_at (x, y); - tr.tile_x = x; - tr.tile_y = y; - return tr; -} - -#define FOR_TILES_AROUND(tai_name, _num_tiles, _x, _y) for (struct tiles_around_iter tai_name = tai_init (_num_tiles, _x, _y); (tai_name.n < tai_name.num_tiles); tai_next (&tai_name)) - -enum work_area_iter_output_type { - WAIO_ANY, - WAIO_DISTRICTS, - WAIO_CITIES, -}; - -struct work_area_iter { - int center_x, center_y; - int n, num_tiles; - int civ_id; - int dx, dy; - int tile_x, tile_y; - Tile * tile; - City * city; - struct district_instance * district_inst; - enum work_area_iter_output_type output_type; - bool completed_districts_only; -}; - -void -wai_next (struct work_area_iter * wai) -{ - wai->tile = p_null_tile; - wai->district_inst = NULL; - while ((wai->n + 1) < wai->num_tiles) { - wai->n += 1; - patch_ni_to_diff_for_work_area (wai->n, &wai->dx, &wai->dy); - wai->tile_x = wai->center_x + wai->dx; - wai->tile_y = wai->center_y + wai->dy; - wrap_tile_coords (&p_bic_data->Map, &wai->tile_x, &wai->tile_y); - Tile * candidate = tile_at (wai->tile_x, wai->tile_y); - if ((candidate == NULL) || (candidate == p_null_tile)) - continue; - if ((wai->civ_id < 0) || (candidate->vtable->m38_Get_Territory_OwnerID (candidate) != wai->civ_id)) - continue; - if (tile_has_enemy_unit (candidate, wai->civ_id)) - continue; - if (candidate->vtable->m20_Check_Pollution (candidate, __, 0)) - continue; - City * city; - if (wai->output_type == WAIO_CITIES) { - if (candidate->CityID < 0) - continue; - city = get_city_ptr (candidate->vtable->m45_Get_City_ID (candidate)); - if (city == NULL || city->Body.CivID != wai->civ_id) - continue; - } - struct district_instance * inst = get_district_instance (candidate); - if (wai->output_type == WAIO_DISTRICTS) { - if (inst == NULL) - continue; - int district_id = inst->district_id; - if (wai->completed_districts_only && (! district_is_complete (candidate, district_id))) - continue; - } - wai->city = city; - wai->district_inst = inst; - wai->tile = candidate; - break; - } - if (wai->tile == p_null_tile) - wai->n = wai->num_tiles; -} - -struct work_area_iter -wai_init_common (int x, int y, enum work_area_iter_output_type output, bool completed_districts_only) -{ - struct work_area_iter tr; - tr.center_x = x; - tr.center_y = y; - tr.n = -1; - tr.num_tiles = is->workable_tile_count; - Tile * center_tile = tile_at (x, y); - if ((center_tile == NULL) || (center_tile == p_null_tile)) - tr.civ_id = -1; - else - tr.civ_id = center_tile->vtable->m38_Get_Territory_OwnerID (center_tile); - tr.tile = p_null_tile; - tr.district_inst = NULL; - tr.dx = 0; - tr.dy = 0; - tr.tile_x = 0; - tr.tile_y = 0; - tr.output_type = output; - tr.completed_districts_only = completed_districts_only; - wai_next (&tr); - return tr; -} - -struct work_area_iter -wai_init (int x, int y) -{ - return wai_init_common (x, y, false, false); -} - -struct work_area_iter -wai_init_districts (int x, int y, bool completed_only) -{ - return wai_init_common (x, y, WAIO_DISTRICTS, completed_only); -} - -struct work_area_iter -wai_init_cities (int x, int y) -{ - struct work_area_iter tr = wai_init_common (x, y, WAIO_CITIES, false); - return tr; -} - -#define FOR_WORK_AREA_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) -#define FOR_DISTRICTS_AROUND(wai_name, _x, _y, _completed_only) for (struct work_area_iter wai_name = wai_init_districts (_x, _y, _completed_only); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) -#define FOR_CITIES_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init_cities (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) -#define FOR_AERODROMES_AROUND(unit_ptr) \ - for (struct table_entry_iter _tei = tei_init (&is->district_tile_map); \ - _tei.index < _tei.capacity; \ - tei_next (&_tei)) \ - for (Tile * aerodrome_tile = (Tile *)_tei.key; \ - (aerodrome_tile != NULL) && (aerodrome_tile != p_null_tile); \ - aerodrome_tile = NULL) \ - for (struct district_instance * aerodrome_inst = (struct district_instance *)_tei.value; \ - (aerodrome_inst != NULL) && \ - (aerodrome_inst->district_id == AERODROME_DISTRICT_ID) && \ - district_is_complete (aerodrome_tile, AERODROME_DISTRICT_ID); \ - aerodrome_inst = NULL) \ - for (int aerodrome_x = 0, aerodrome_y = 0; \ - district_instance_get_coords (aerodrome_inst, aerodrome_tile, &aerodrome_x, &aerodrome_y) && \ - (aerodrome_tile->vtable->m38_Get_Territory_OwnerID (aerodrome_tile) == (unit_ptr)->Body.CivID) && \ - patch_Unit_is_in_rebase_range ((unit_ptr), __, aerodrome_x, aerodrome_y); \ - aerodrome_x = 0, aerodrome_y = 0) - -struct tile_rings_iter { - int center_x, center_y; - int const * rings; - int ring_count; - int r_idx; - int ni; - int tile_x, tile_y; - int current_ring; - Tile * tile; -}; - -void -tri_next (struct tile_rings_iter * tri) -{ - tri->tile = p_null_tile; - while (tri->r_idx < tri->ring_count) { - int ring_no = tri->rings[tri->r_idx]; - if ((ring_no <= 0) || (ring_no >= 8)) { - tri->r_idx += 1; - tri->ni = -1; - continue; - } - int start_ni = workable_tile_counts[ring_no - 1]; - int end_ni = workable_tile_counts[ring_no]; - if (tri->ni < start_ni) - tri->ni = start_ni; - else if ((tri->ni + 1) < end_ni) - tri->ni += 1; - else { - tri->r_idx += 1; - tri->ni = -1; - continue; - } - tri->current_ring = ring_no; - int dx, dy; - patch_ni_to_diff_for_work_area (tri->ni, &dx, &dy); - int tx = tri->center_x + dx; - int ty = tri->center_y + dy; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - tri->tile_x = tx; - tri->tile_y = ty; - Tile * candidate = tile_at (tx, ty); - if ((candidate == NULL) || (candidate == p_null_tile)) - continue; - tri->tile = candidate; - break; - } - if (tri->tile == p_null_tile) { - tri->r_idx = tri->ring_count; - tri->ni = -1; - } -} - -struct tile_rings_iter -tri_init (int x, int y, int const * rings, int ring_count) -{ - struct tile_rings_iter tr; - tr.center_x = x; - tr.center_y = y; - tr.rings = rings; - tr.ring_count = ring_count; - tr.r_idx = 0; - tr.ni = -1; - tr.tile_x = 0; - tr.tile_y = 0; - tr.current_ring = 0; - tr.tile = p_null_tile; - tri_next (&tr); - return tr; -} - -#define FOR_TILE_RINGS_AROUND(tri_name, _x, _y, _rings, _ring_count) for (struct tile_rings_iter tri_name = tri_init (_x, _y, _rings, _ring_count); (tri_name.r_idx < tri_name.ring_count); tri_next (&tri_name)) - -bool -tile_square_type_is (Tile * tile, enum SquareTypes type) -{ - return tile_matches_square_type (tile, type); -} - -bool -district_is_buildable_on_tile (struct district_config const * cfg, Tile * tile) -{ - if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - unsigned int mask = cfg->buildable_square_types_mask; - if (mask == 0) - mask = district_default_buildable_mask (); - - bool square_matches = tile_matches_square_type_mask (tile, mask); - bool overlay_allowed = false; - bool overlay_required = false; - - if (cfg->has_buildable_without_removal) - overlay_allowed = tile_matches_overlay_mask (tile, cfg->buildable_without_removal_mask); - - if (cfg->has_buildable_on_overlays) { - overlay_required = tile_matches_overlay_mask (tile, cfg->buildable_on_overlays_mask); - if (! overlay_required) - return false; - } - if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) - return false; - - if (! square_matches && ! overlay_allowed && ! overlay_required) - return false; - - if (cfg->has_buildable_on_districts) { - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - - int existing_district_id = inst->district_id; - if (! district_is_complete (tile, existing_district_id)) - return false; - - bool matches = false; - for (int i = 0; i < cfg->buildable_on_district_id_count; i++) { - if (cfg->buildable_on_district_ids[i] == existing_district_id) { - matches = true; - break; - } - } - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to || cfg->has_buildable_adjacent_to_districts || cfg->has_buildable_adjacent_to_overlays) { - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - return false; - - if (cfg->has_buildable_adjacent_to) { - bool matches = false; - bool city_adjacent = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (Tile_has_city (tai.tile)) { - city_adjacent = true; - if (cfg->buildable_adjacent_to_allows_city) - matches = true; - } - if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) - matches = true; - if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) - break; - } - if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) - return false; - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to_overlays) { - bool matches = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { - matches = true; - break; - } - } - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to_districts) { - bool matches = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - struct district_instance * adj_inst = get_district_instance (tai.tile); - if (adj_inst == NULL) - continue; - int adj_district_id = adj_inst->district_id; - if (! district_is_complete (tai.tile, adj_district_id)) - continue; - for (int i = 0; i < cfg->buildable_adjacent_to_district_id_count; i++) { - if (cfg->buildable_adjacent_to_district_ids[i] == adj_district_id) { - matches = true; - break; - } - } - if (matches) - break; - } - if (! matches) - return false; - } - } - - return true; -} - -bool -is_coastal_island (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - if (tile->vtable->m35_Check_Is_Water (tile)) - return false; - - bool has_neighbor = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - return false; - - has_neighbor = true; - if (! adj->vtable->m35_Check_Is_Water (adj)) - return false; - - if (adj->vtable->m50_Get_Square_BaseType (adj) != SQ_Coast) - return false; - } - - return has_neighbor; -} - -bool -natural_wonder_adjacent_requirement_met (struct natural_wonder_district_config const * cfg, - Tile * tile, - int tile_x, - int tile_y) -{ - enum SquareTypes required = cfg->adjacent_to; - if (required == (enum SquareTypes)SQ_INVALID) - return true; - - if (required == SQ_RIVER) { - char river_bits = tile->vtable->m37_Get_River_Code (tile); - if (cfg->adjacency_dir != DIR_ZERO) { - int bit = direction_to_neighbor_bit (cfg->adjacency_dir); - if (bit < 0) - return false; - return (river_bits & (1 << bit)) != 0; - } else - return river_bits != 0; - } - - if (cfg->adjacency_dir != DIR_ZERO) { - int dx, dy; - if (! direction_to_offset (cfg->adjacency_dir, &dx, &dy)) - return false; - int nx = tile_x + dx; - int ny = tile_y + dy; - wrap_tile_coords (&p_bic_data->Map, &nx, &ny); - Tile * neighbor = tile_at (nx, ny); - return tile_square_type_is (neighbor, required); - } - - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_square_type_is (tai.tile, required)) - return true; - } - - return false; -} - -int -count_diagonal_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) -{ - if (type == (enum SquareTypes)SQ_INVALID) - return 0; - - enum direction dirs[4] = {DIR_NE, DIR_NW, DIR_SE, DIR_SW}; - int count = 0; - for (int i = 0; i < 4; i++) { - int dx, dy; - if (! direction_to_offset (dirs[i], &dx, &dy)) - continue; - int nx = tile_x + dx; - int ny = tile_y + dy; - wrap_tile_coords (&p_bic_data->Map, &nx, &ny); - Tile * neighbor = tile_at (nx, ny); - if (tile_square_type_is (neighbor, type)) - count += 1; - } - return count; -} - -int -count_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) -{ - if (type == (enum SquareTypes)SQ_INVALID) - return 0; - - int count = 0; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_square_type_is (tai.tile, type)) - count += 1; - } - return count; -} - -bool -natural_wonder_terrain_matches (struct natural_wonder_district_config const * cfg, Tile * tile, int tile_x, int tile_y) -{ - if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - if (! tile_matches_square_type (tile, cfg->terrain_type)) - return false; - - if (cfg->terrain_type == SQ_Coast) { - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - return false; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - if ((continent == NULL) || (continent->Body.TileCount <= 5)) - return false; - } - - if (is_coastal_island (tile, tile_x, tile_y)) - return false; - - if ((cfg->adjacent_to != SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 0)) - return false; - - if ((cfg->adjacent_to == SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 4)) - return false; - - if (! natural_wonder_adjacent_requirement_met (cfg, tile, tile_x, tile_y)) - return false; - - return true; -} - -struct district_worker_record * -get_tracked_worker_record (Unit * worker) -{ - if (worker == NULL) return NULL; - int civ_id = worker->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) return NULL; - - int value; - if (itable_look_up (&is->district_worker_tables[civ_id], worker->Body.ID, &value)) - return (struct district_worker_record *)value; - return NULL; -} - -struct district_worker_record * -ensure_tracked_worker_record (Unit * worker) -{ - if (worker == NULL) return NULL; - int civ_id = worker->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) return NULL; - - struct district_worker_record * rec = get_tracked_worker_record (worker); - if (rec != NULL) return rec; - - rec = (struct district_worker_record *)calloc (1, sizeof *rec); - if (rec == NULL) return NULL; - - rec->worker = worker; - rec->unit_id = worker->Body.ID; - Tile * tile = tile_at (worker->Body.X, worker->Body.Y); - rec->continent_id = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m46_Get_ContinentID (tile) : -1; - rec->pending_req = NULL; - - itable_insert (&is->district_worker_tables[civ_id], worker->Body.ID, (int)rec); - return rec; -} - -void -remove_tracked_worker_record (int civ_id, int unit_id) -{ - if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) - return; - - int value; - if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) - return; - - struct district_worker_record * rec = (struct district_worker_record *)value; - if (rec->pending_req != NULL) { - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - } - - itable_remove (&is->district_worker_tables[civ_id], unit_id); - free (rec); -} - -void -clear_tracked_worker_assignment (struct district_worker_record * rec) -{ - if (rec == NULL) - return; - - if (rec->pending_req != NULL) { - if (rec->pending_req->assigned_worker_id == rec->unit_id) - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - } -} - -void -clear_tracked_worker_assignment_by_id (int civ_id, int unit_id) -{ - if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) - return; - - int value; - if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) - return; - - struct district_worker_record * rec = (struct district_worker_record *)value; - if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == unit_id)) - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - if ((rec->worker == NULL) || (get_unit_ptr (unit_id) == NULL)) - remove_tracked_worker_record (civ_id, unit_id); -} - -void -clear_all_tracked_workers (void) -{ - for (int civ = 0; civ < 32; civ++) { - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - if (rec == NULL) - continue; - if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == rec->unit_id)) - rec->pending_req->assigned_worker_id = -1; - rec->pending_req = NULL; - free (rec); - } - is->district_worker_tables[civ].len = 0; - if (is->district_worker_tables[civ].block != NULL) { - free (is->district_worker_tables[civ].block); - is->district_worker_tables[civ].block = NULL; - } - is->district_worker_tables[civ].capacity_exponent = 0; - } -} - -bool is_worker (Unit * unit) -{ - if (unit == NULL) - return false; - - int unit_type_id = unit->Body.UnitTypeID; - int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; - - if (worker_actions == 0 || !(worker_actions & (UCV_Build_Road | UCV_Build_Mine | UCV_Irrigate))) { - return false; - } - - return true; -} - -void -update_tracked_worker_for_unit (Unit * worker) -{ - if (worker == NULL || ! is->current_config.enable_districts) return; - - int civ_id = worker->Body.CivID; - int type_id = worker->Body.UnitTypeID; - if ((civ_id < 0) || (civ_id >= 32)) return; - if ((*p_human_player_bits & (1 << civ_id)) != 0) return; - - char ss[200]; - snprintf (ss, sizeof ss, "Updating tracked worker for unit %d of type %d\n", worker->Body.ID, type_id); - (*p_OutputDebugStringA) (ss); - - if (! is_worker (worker)) { - remove_tracked_worker_record(worker->Body.CivID, worker->Body.ID); - return; - } - - ensure_tracked_worker_record (worker); -} - -bool -assign_worker_to_district (struct pending_district_request * req, Unit * worker, City * city, int district_id, int tile_x, int tile_y) -{ - if (worker == NULL || city == NULL) - return false; - if (req == NULL) - return false; - - req->city = city; - req->city_id = city->Body.ID; - req->civ_id = city->Body.CivID; - req->assigned_worker_id = worker->Body.ID; - req->worker_assigned_turn = *p_current_turn_no; - req->target_x = tile_x; - req->target_y = tile_y; - worker->Body.Auto_CityID = city->Body.ID; - - char ss[200]; - snprintf (ss, sizeof ss, "assign_worker_to_district: Assigned worker unit %d to build district %d in city %s at (%d,%d)\n", - worker->Body.ID, district_id, city->Body.CityName, tile_x, tile_y); - (*p_OutputDebugStringA) (ss); - - struct district_worker_record * record = ensure_tracked_worker_record (worker); - if (record != NULL) { - record->pending_req = req; - } - - return ai_move_district_worker (worker, record); -} - -bool -worker_is_available_for_district (Unit * worker) -{ - if (worker == NULL) - return false; - - int civ_id = worker->Body.CivID; - if ((civ_id < 0) || (civ_id >= 32)) return false; - if ((*p_human_player_bits & (1 << civ_id)) != 0) return false; - - int type_id = worker->Body.UnitTypeID; - if ((type_id < 0) || (type_id >= p_bic_data->UnitTypeCount)) return false; - - struct district_worker_record * record = get_tracked_worker_record (worker); - if (record == NULL) - return false; - - return record->pending_req == NULL; -} - -Unit * -find_best_worker_for_district (Leader * leader, City * city, int district_id, int target_x, int target_y) -{ - char ss[200]; - - if ((leader == NULL) || (city == NULL)) { - snprintf (ss, sizeof ss, "Invalid leader or city when finding best worker for district %d\n", district_id); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - int civ_id = leader->ID; - if ((civ_id < 0) || (civ_id >= 32)) { - snprintf (ss, sizeof ss, "Invalid civ_id %d when finding best worker for district %d\n", civ_id, district_id); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - if (is->district_worker_tables[civ_id].len == 0) { - snprintf (ss, sizeof ss, "No tracked workers for civ %d when finding best worker for district %d\n", civ_id, district_id); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - Tile * target_tile = tile_at (target_x, target_y); - if ((target_tile == NULL) || (target_tile == p_null_tile)) { - snprintf (ss, sizeof ss, "Invalid target tile (%d,%d) when finding best worker for district %d in city %s\n", - target_x, target_y, district_id, city->Body.CityName); - (*p_OutputDebugStringA) (ss); - return NULL; - } - - int target_continent_id = target_tile->vtable->m46_Get_ContinentID (target_tile); - Unit * best_worker = NULL; - int best_dist = INT_MAX; - - snprintf (ss, sizeof ss, "Finding best worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); - (*p_OutputDebugStringA) (ss); - - FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { - struct district_worker_record * rec = (struct district_worker_record *)tei.value; - - if (rec == NULL) { - continue; - } - - Unit * candidate_worker = get_unit_ptr (rec->unit_id); - if ((candidate_worker == NULL) || (candidate_worker->Body.CivID != civ_id)) { - remove_tracked_worker_record (civ_id, rec->unit_id); - continue; - } - rec->worker = candidate_worker; - - if (! worker_is_available_for_district (candidate_worker)) { - continue; - } - - Tile * worker_tile = tile_at (candidate_worker->Body.X, candidate_worker->Body.Y); - if ((worker_tile == NULL) || (worker_tile == p_null_tile)) { - continue; - } - - int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); - if ((target_continent_id >= 0) && (worker_continent_id != target_continent_id)) { - continue; - } - - int dist = compute_wrapped_chebyshev_distance (candidate_worker->Body.X, candidate_worker->Body.Y, target_x, target_y); - - if (dist < best_dist) { - best_worker = candidate_worker; - best_dist = dist; - if (dist == 0) - return best_worker; - } - } - - return best_worker; -} - -void -process_pending_district_request (Leader * leader, struct pending_district_request * req) -{ - if ((leader == NULL) || (req == NULL)) - return; - - City * city = get_city_ptr (req->city_id); - if (city == NULL) { - remove_pending_district_request (req); - return; - } - req->city = city; - - int district_id = req->district_id; - int civ_id = req->civ_id; - - if (city->Body.CivID != civ_id) { - clear_city_district_request (city, district_id); - return; - } - - if (district_id < 0 || district_id >= is->district_count) return; - - // Check if city already has the district if not a neighborhood or distribution hub - if (district_id != NEIGHBORHOOD_DISTRICT_ID && - district_id != DISTRIBUTION_HUB_DISTRICT_ID && - is->district_configs[district_id].allow_multiple == false && - city_has_required_district (city, district_id)) { - - // Clear the request - clear_city_district_request (city, district_id); - return; - } - - // Assigned worker is no longer valid; clear assignment - if (req->assigned_worker_id >= 0) { - Unit * assigned = get_unit_ptr (req->assigned_worker_id); - if (assigned != NULL) { - // Check if more than allowed turns have elapsed since assignment and worker is not at target tile - bool worker_at_target = (assigned->Body.X == req->target_x) && (assigned->Body.Y == req->target_y); - if ((*p_current_turn_no - req->worker_assigned_turn) > is->current_config.ai_city_district_max_build_wait_turns && !worker_at_target) { - clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); - req->assigned_worker_id = -1; - req->worker_assigned_turn = *p_current_turn_no; - } else { - return; - } - } else { - // Assigned worker is null, make sure we get a new one - clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); - req->assigned_worker_id = -1; - } - } - - struct district_instance * inst = NULL; - int target_x = 0; - int target_y = 0; - Tile * tile = find_tile_for_district (city, district_id, &target_x, &target_y); - if ((tile == NULL) || (tile == p_null_tile)) { - clear_city_district_request (city, district_id); - return; - } - wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); - - char ss[200]; - snprintf (ss, sizeof ss, "Assigning worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); - (*p_OutputDebugStringA) (ss); - - Unit * worker = find_best_worker_for_district (leader, city, district_id, target_x, target_y); - if (worker == NULL) - return; - - snprintf (ss, sizeof ss, "Found worker %d for district %d in city %s at (%d,%d)\n", - worker->Body.ID, district_id, city->Body.CityName, target_x, target_y); - (*p_OutputDebugStringA) (ss); - - assign_worker_to_district (req, worker, city, district_id, target_x, target_y); -} - -void -assign_workers_for_pending_districts (Leader * leader) -{ - if ((leader == NULL) || ! is->current_config.enable_districts) - return; - - int civ_id = leader->ID; - if ((civ_id < 0) || (civ_id >= 32)) - return; - - if ((*p_human_player_bits & (1 << civ_id)) != 0) - return; - - int pending_count = is->city_pending_district_requests[civ_id].len; - if (pending_count <= 0) - return; - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req == NULL) - continue; - - City * city = get_city_ptr (req->city_id); - if (city == NULL) { - remove_pending_district_request (req); - continue; - } - - req->city = city; - if (city->Body.CivID != req->civ_id) { - remove_pending_district_request (req); - continue; - } - - process_pending_district_request (leader, req); - } -} - -City * -find_closest_owned_city_for_tile (int civ_id, int tile_x, int tile_y) -{ - City * best_city = NULL; - int best_dist = INT_MAX; - - FOR_CITIES_OF (coi, civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - - int dist = compute_wrapped_chebyshev_distance (city->Body.X, city->Body.Y, tile_x, tile_y); - if (dist < best_dist) { - best_dist = dist; - best_city = city; - } - } - - return best_city; -} - -bool -ai_candidate_bridge_or_canal_is_buildable_for_civ (struct ai_candidate_bridge_or_canal_entry * entry, int civ_id, int * out_tile_index) -{ - if ((entry == NULL) || (entry->tile_count <= 0)) - return false; - - int pending_index = -1; - for (int ti = 0; ti < entry->tile_count; ti++) { - int tx = entry->tile_x[ti]; - int ty = entry->tile_y[ti]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (owner != civ_id) - return false; - if (tile->CityID >= 0) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - if (inst->district_id == entry->district_id) - continue; - if (inst->district_id == WONDER_DISTRICT_ID) - return false; - if (! is->current_config.ai_can_replace_existing_districts_with_canals) { - return false; - } - } - - if (pending_index < 0) - pending_index = ti; - } - - if (pending_index < 0) { - entry->completed = true; - return false; - } - - if (out_tile_index != NULL) - *out_tile_index = pending_index; - - return true; -} - -void -release_ai_candidate_bridge_or_canal_worker (struct ai_candidate_bridge_or_canal_entry * entry) -{ - if ((entry == NULL) || (entry->assigned_worker_id < 0)) - return; - - int civ_id = entry->pending_req.civ_id; - if ((civ_id >= 0) && (civ_id < 32)) - clear_tracked_worker_assignment_by_id (civ_id, entry->assigned_worker_id); - - entry->assigned_worker_id = -1; - entry->assigned_tile_index = -1; - entry->pending_req.city = NULL; - entry->pending_req.city_id = -1; - entry->pending_req.civ_id = -1; - entry->pending_req.district_id = -1; - entry->pending_req.assigned_worker_id = -1; - entry->pending_req.target_x = -1; - entry->pending_req.target_y = -1; - entry->pending_req.worker_assigned_turn = 0; -} - -void -reset_ai_candidate_bridge_or_canals (void) -{ - if (is->ai_candidate_bridge_or_canals != NULL) { - for (int i = 0; i < is->ai_candidate_bridge_or_canals_capacity; i++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[i]; - if (entry->tile_x != NULL) - free (entry->tile_x); - if (entry->tile_y != NULL) - free (entry->tile_y); - } - free (is->ai_candidate_bridge_or_canals); - is->ai_candidate_bridge_or_canals = NULL; - } - is->ai_candidate_bridge_or_canals_capacity = 0; - is->ai_candidate_bridge_or_canals_count = 0; - is->ai_candidate_bridge_or_canals_initialized = false; -} - -bool -tile_has_district_at (int tile_x, int tile_y, int district_id) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - return (inst != NULL) && (inst->district_id == district_id) && (district_is_complete (tile, district_id)); -} - -bool -tile_is_land (int civ_id, int tile_x, int tile_y, bool must_be_same_owner) -{ - if (must_be_same_owner && (civ_id <= 0)) - return false; - - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - return (tile != NULL) && (tile != p_null_tile) && (! tile->vtable->m35_Check_Is_Water (tile)) && - ((! must_be_same_owner) || (tile->Territory_OwnerID == civ_id)); -} - -bool -tile_is_water (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - return (tile != NULL) && (tile != p_null_tile) && (tile->vtable->m35_Check_Is_Water (tile)); -} - -bool -ensure_ai_candidate_bridge_or_canals_capacity (int required) -{ - if (required <= 0) - return true; - if (required <= is->ai_candidate_bridge_or_canals_capacity) - return true; - int new_capacity = (is->ai_candidate_bridge_or_canals_capacity > 0) ? is->ai_candidate_bridge_or_canals_capacity * 2 : 4; - if (new_capacity < required) - new_capacity = required; - struct ai_candidate_bridge_or_canal_entry * larger = (struct ai_candidate_bridge_or_canal_entry *)realloc ( - is->ai_candidate_bridge_or_canals, new_capacity * sizeof *larger); - if (larger == NULL) - return false; - for (int i = is->ai_candidate_bridge_or_canals_capacity; i < new_capacity; i++) { - struct ai_candidate_bridge_or_canal_entry * entry = &larger[i]; - entry->tile_x = NULL; - entry->tile_y = NULL; - entry->tile_capacity = 0; - entry->district_id = -1; - entry->owner_civ_id = -1; - entry->tile_count = 0; - entry->assigned_tile_index = -1; - entry->assigned_worker_id = -1; - entry->completed = false; - struct pending_district_request * req = &entry->pending_req; - req->city = NULL; - req->city_id = -1; - req->civ_id = -1; - req->district_id = -1; - req->assigned_worker_id = -1; - req->target_x = -1; - req->target_y = -1; - req->worker_assigned_turn = 0; - } - is->ai_candidate_bridge_or_canals = larger; - is->ai_candidate_bridge_or_canals_capacity = new_capacity; - return true; -} - -bool -canal_has_different_adjacent_seas (int tile_x, int tile_y, int civ_id) -{ - struct water_pair { - int dx1, dy1; - int dx2, dy2; - }; - - const struct water_pair pairs[] = { - { 1, -1, -1, 1 }, // NE + SW - { 1, 1, -1, -1 }, // SE + NW - }; - - Map * map = &p_bic_data->Map; - bool require_owner = (civ_id >= 0); - - for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { - int ax = tile_x + pairs[i].dx1; - int ay = tile_y + pairs[i].dy1; - wrap_tile_coords (map, &ax, &ay); - Tile * first = tile_at (ax, ay); - if ((first == NULL) || (first == p_null_tile)) - continue; - if (! first->vtable->m35_Check_Is_Water (first)) - continue; - if (require_owner && (first->vtable->m38_Get_Territory_OwnerID (first) != civ_id)) - continue; - - int bx = tile_x + pairs[i].dx2; - int by = tile_y + pairs[i].dy2; - wrap_tile_coords (map, &bx, &by); - Tile * second = tile_at (bx, by); - if ((second == NULL) || (second == p_null_tile)) - continue; - if (! second->vtable->m35_Check_Is_Water (second)) - continue; - if (require_owner && (second->vtable->m38_Get_Territory_OwnerID (second) != civ_id)) - continue; - - int sea_a = first->vtable->m46_Get_ContinentID (first); - int sea_b = second->vtable->m46_Get_ContinentID (second); - if ((sea_a >= 0) && (sea_b >= 0) && (sea_a != sea_b)) - return true; - } - - return false; -} - -// Check if two water tiles can reach each other via water within a radius, excluding a blocked tile -bool -water_tiles_connected_within_radius (int start_x, int start_y, int target_x, int target_y, int block_x, int block_y, int radius) -{ - // Simple BFS using a fixed-size visited array for tiles within radius - // workable_tile_counts[6] = 137 tiles for radius 6 - int max_tiles = 137; - int visited_x[137]; - int visited_y[137]; - int visited_count = 0; - int queue_x[137]; - int queue_y[137]; - int queue_head = 0; - int queue_tail = 0; - - queue_x[queue_tail] = start_x; - queue_y[queue_tail] = start_y; - queue_tail++; - visited_x[visited_count] = start_x; - visited_y[visited_count] = start_y; - visited_count++; - - while (queue_head < queue_tail) { - int cx = queue_x[queue_head]; - int cy = queue_y[queue_head]; - queue_head++; - - // Check 8 adjacent tiles - FOR_TILES_AROUND (tai, 9, cx, cy) { - if (tai.n == 0) - continue; - int nx = tai.tile_x; - int ny = tai.tile_y; - - // Found target - if (nx == target_x && ny == target_y) - return true; - - // Skip blocked tile (the isthmus) - if (nx == block_x && ny == block_y) - continue; - - // Check if within radius of original start - int dx = nx - start_x; - int dy = ny - start_y; - if (dx < 0) dx = -dx; - if (dy < 0) dy = -dy; - // Use Chebyshev distance approximation for hex grid - int dist = (dx + dy + ((dx > dy) ? dx : dy)) / 2; - if (dist > radius) - continue; - - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (! adj->vtable->m35_Check_Is_Water (adj)) - continue; - - // Check if already visited - bool already_visited = false; - for (int i = 0; i < visited_count; i++) { - if (visited_x[i] == nx && visited_y[i] == ny) { - already_visited = true; - break; - } - } - if (already_visited) - continue; - - // Add to queue and visited - if (visited_count < max_tiles && queue_tail < max_tiles) { - visited_x[visited_count] = nx; - visited_y[visited_count] = ny; - visited_count++; - queue_x[queue_tail] = nx; - queue_y[queue_tail] = ny; - queue_tail++; - } - } - } - return false; -} - -// Check if tile separates adjacent water tiles that are not connected within a small radius -bool -canal_has_same_sea_isthmus (int tile_x, int tile_y, int civ_id, int check_radius) -{ - // If another canal exists nearby, this isn't a unique isthmus target. - FOR_TILES_AROUND (tai, workable_tile_counts[2], tile_x, tile_y) { - if (tai.n == 0) - continue; - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - continue; - struct district_instance * adj_inst = get_district_instance (adj); - if ((adj_inst != NULL) && (adj_inst->district_id == CANAL_DISTRICT_ID)) - return false; - } - - // Check opposite diagonal water tiles that are not connected within radius 2 - struct water_pair { - int dx1, dy1; - int dx2, dy2; - }; - - const struct water_pair pairs[] = { - { 1, -1, -1, 1 }, // NE + SW - { 1, 1, -1, -1 }, // SE + NW - }; - - for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { - int ax = tile_x + pairs[i].dx1; - int ay = tile_y + pairs[i].dy1; - wrap_tile_coords (&p_bic_data->Map, &ax, &ay); - Tile * first = tile_at (ax, ay); - if ((first == NULL) || (first == p_null_tile)) - continue; - if (! first->vtable->m35_Check_Is_Water (first)) - continue; - - int bx = tile_x + pairs[i].dx2; - int by = tile_y + pairs[i].dy2; - wrap_tile_coords (&p_bic_data->Map, &bx, &by); - Tile * second = tile_at (bx, by); - if ((second == NULL) || (second == p_null_tile)) - continue; - if (! second->vtable->m35_Check_Is_Water (second)) - continue; - - if (! water_tiles_connected_within_radius ( - ax, ay, - bx, by, - tile_x, tile_y, 2)) { - return true; - } - } - return false; -} - -bool -bridge_tile_connects_two_continents (int tile_x, int tile_y, int civ_id) -{ - struct bridge_pair { - int dx1, dy1; - int dx2, dy2; - }; - - Map * map = &p_bic_data->Map; - const struct bridge_pair pairs[] = { - {0, -2, 0, 2}, - {-2, 0, 2, 0}, - {-1, -1, 1, 1}, - {-1, 1, 1, -1}, - }; - - bool require_owner = (civ_id >= 0); - - for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { - int ax = tile_x + pairs[i].dx1; - int ay = tile_y + pairs[i].dy1; - wrap_tile_coords (map, &ax, &ay); - if (! tile_is_land (civ_id, ax, ay, require_owner)) - continue; - Tile * first = tile_at (ax, ay); - if ((first == NULL) || (first == p_null_tile)) - continue; - - int bx = tile_x + pairs[i].dx2; - int by = tile_y + pairs[i].dy2; - wrap_tile_coords (map, &bx, &by); - if (! tile_is_land (civ_id, bx, by, require_owner)) - continue; - Tile * second = tile_at (bx, by); - if ((second == NULL) || (second == p_null_tile)) - continue; - - int cont_a = first->vtable->m46_Get_ContinentID (first); - int cont_b = second->vtable->m46_Get_ContinentID (second); - if ((cont_a >= 0) && (cont_b >= 0) && (cont_a != cont_b)) - return true; - } - - return false; -} - -bool -tile_point_in_block (int tile_x, int tile_y, int block_x0, int block_y0, int block_x1, int block_y1) -{ - return (tile_x >= block_x0) && (tile_x < block_x1) && (tile_y >= block_y0) && (tile_y < block_y1); -} - -bool -tile_is_coastal_water (int tile_x, int tile_y) -{ - Map * map = &p_bic_data->Map; - wrap_tile_coords (map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - if (! tile->vtable->m35_Check_Is_Water (tile)) - return false; - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - return base_type == SQ_Coast; -} - -bool -tile_exists_at (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - return (tile != NULL) && (tile != p_null_tile); -} - -bool -tile_is_reserved_in_district_tile_map (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return false; - int existing = 0; - return itable_look_up (&is->district_tile_map, (int)tile, &existing); -} - -bool -tile_has_diagonal_water (int tile_x, int tile_y) -{ - Map * map = &p_bic_data->Map; - int const adj_dx[4] = { 1, 1, -1, -1 }; - int const adj_dy[4] = { -1, 1, -1, 1 }; - - for (int i = 0; i < 4; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * tile = tile_at (nx, ny); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m35_Check_Is_Water (tile)) - return true; - } - return false; -} - -bool -tile_part_of_existing_candidate (int tile_x, int tile_y) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if (entry->tile_count <= 0) - continue; - for (int ti = 0; ti < entry->tile_count; ti++) { - if ((entry->tile_x[ti] == tile_x) && (entry->tile_y[ti] == tile_y)) - return true; - } - } - return false; -} - -bool -tile_has_bridge_or_canal_nearby (int tile_x, int tile_y) -{ - FOR_TILES_AROUND (tai, workable_tile_counts[1], tile_x, tile_y) { - Tile * adj = tai.tile; - if ((adj == NULL) || (adj == p_null_tile)) - continue; - struct district_instance * inst = get_district_instance (adj); - if ((inst != NULL) && - ((inst->district_id == BRIDGE_DISTRICT_ID) || (inst->district_id == CANAL_DISTRICT_ID))) - return true; - if (tile_part_of_existing_candidate (tai.tile_x, tai.tile_y)) - return true; - } - return false; -} - -bool -add_ai_candidate_entry (int district_id, short owner_civ_id, short * xs, short * ys, int count) -{ - if (count <= 0) - return false; - if (! ensure_ai_candidate_bridge_or_canals_capacity (is->ai_candidate_bridge_or_canals_count + 1)) - return false; - - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[is->ai_candidate_bridge_or_canals_count]; - entry->tile_x = (short *)malloc (sizeof *entry->tile_x * count); - entry->tile_y = (short *)malloc (sizeof *entry->tile_y * count); - if ((entry->tile_x == NULL) || (entry->tile_y == NULL)) { - if (entry->tile_x != NULL) - free (entry->tile_x); - if (entry->tile_y != NULL) - free (entry->tile_y); - return false; - } - - entry->district_id = district_id; - entry->owner_civ_id = owner_civ_id; - entry->tile_count = (short)count; - entry->tile_capacity = count; - entry->assigned_tile_index = -1; - entry->assigned_worker_id = -1; - entry->completed = false; - for (int ti = 0; ti < count; ti++) { - entry->tile_x[ti] = xs[ti]; - entry->tile_y[ti] = ys[ti]; - } - - struct pending_district_request * req = &entry->pending_req; - req->city = NULL; - req->city_id = -1; - req->civ_id = owner_civ_id; - req->district_id = district_id; - req->assigned_worker_id = -1; - req->target_x = -1; - req->target_y = -1; - req->worker_assigned_turn = 0; - - is->ai_candidate_bridge_or_canals_count++; - return true; -} - -int -find_bridge_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, - int contiguous_limit, int candidate_capacity, - short * out_x, short * out_y, short * out_owner) -{ - const int dirs[4][2] = { - { 0, -2 }, { -2, 0 }, { -1, -1 }, { -1, 1 } - }; - - int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - if (candidate_capacity > 0 && max_len > candidate_capacity) - max_len = candidate_capacity; - - for (int length = 1; length <= max_len; length++) { - for (int ti = 0; ti < map->TileCount; ti++) { - int tx = -1; - int ty = -1; - tile_index_to_coords (map, ti, &tx, &ty); - if (! tile_point_in_block (tx, ty, block_x0, block_y0, block_x1, block_y1)) - continue; - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile_has_resource (tile)) - continue; - if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], tile)) - continue; - if (tile_is_reserved_in_district_tile_map (tx, ty)) - continue; - short owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - for (int di = 0; di < (int)(sizeof (dirs) / sizeof (dirs[0])); di++) { - int dx = dirs[di][0]; - int dy = dirs[di][1]; - int end_x = tx + dx * (length - 1); - int end_y = ty + dy * (length - 1); - wrap_tile_coords (map, &end_x, &end_y); - if (! tile_point_in_block (end_x, end_y, block_x0, block_y0, block_x1, block_y1)) - continue; - - bool ok = true; - for (int step = 0; step < length; step++) { - int cx = tx + dx * step; - int cy = ty + dy * step; - wrap_tile_coords (map, &cx, &cy); - if (! tile_point_in_block (cx, cy, block_x0, block_y0, block_x1, block_y1)) { - ok = false; - break; - } - if (! tile_exists_at (cx, cy)) { - ok = false; - break; - } - if (! tile_is_coastal_water (cx, cy)) { - ok = false; - break; - } - Tile * bridge_tile = tile_at (cx, cy); - if ((bridge_tile == NULL) || (bridge_tile == p_null_tile)) { - ok = false; - break; - } - if (tile_has_resource (bridge_tile)) { - ok = false; - break; - } - if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], bridge_tile)) { - ok = false; - break; - } - if (tile_has_bridge_or_canal_nearby (cx, cy)) { - ok = false; - break; - } - if (tile_is_reserved_in_district_tile_map (cx, cy)) { - ok = false; - break; - } - if (tile_part_of_existing_candidate (cx, cy)) { - ok = false; - break; - } - } - if (! ok) - continue; - - int land_ax = tx - dx; - int land_ay = ty - dy; - wrap_tile_coords (map, &land_ax, &land_ay); - if (! tile_point_in_block (land_ax, land_ay, block_x0, block_y0, block_x1, block_y1)) - continue; - if (! tile_exists_at (land_ax, land_ay)) - continue; - if (! tile_is_land (-1, land_ax, land_ay, false)) - continue; - Tile * land_a = tile_at (land_ax, land_ay); - if ((land_a == NULL) || (land_a == p_null_tile)) - continue; - - int land_bx = tx + dx * length; - int land_by = ty + dy * length; - wrap_tile_coords (map, &land_bx, &land_by); - if (! tile_point_in_block (land_bx, land_by, block_x0, block_y0, block_x1, block_y1)) - continue; - if (! tile_exists_at (land_bx, land_by)) - continue; - if (! tile_is_land (-1, land_bx, land_by, false)) - continue; - Tile * land_b = tile_at (land_bx, land_by); - if ((land_b == NULL) || (land_b == p_null_tile)) - continue; - - int cont_a = land_a->vtable->m46_Get_ContinentID (land_a); - int cont_b = land_b->vtable->m46_Get_ContinentID (land_b); - if ((cont_a < 0) || (cont_b < 0) || (cont_a == cont_b)) - continue; - - for (int step = 0; step < length; step++) { - int cx = tx + dx * step; - int cy = ty + dy * step; - wrap_tile_coords (map, &cx, &cy); - out_x[step] = (short)cx; - out_y[step] = (short)cy; - } - *out_owner = owner; - return length; - } - } - } - return 0; -} - -int -gather_canal_line (int start_x, int start_y, int dx, int dy, int limit, - int block_x0, int block_y0, int block_x1, int block_y1, - short * out_x, short * out_y) -{ - int effective_limit = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, limit); - - if (! tile_is_land (-1, start_x, start_y, false)) - return 0; - if (tile_part_of_existing_candidate (start_x, start_y)) - return 0; - - short back_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - short back_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - short forward_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - short forward_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - int back_count = 0; - int forward_count = 0; - int remaining = effective_limit - 1; - Map * map = &p_bic_data->Map; - - int cx = start_x; - int cy = start_y; - while ((remaining > 0) && (back_count < effective_limit)) { - int nx = cx - dx; - int ny = cy - dy; - wrap_tile_coords (map, &nx, &ny); - if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) - break; - if (! tile_is_land (-1, nx, ny, false)) - break; - if (tile_part_of_existing_candidate (nx, ny)) - break; - back_x[back_count] = (short)nx; - back_y[back_count] = (short)ny; - back_count++; - remaining--; - cx = nx; - cy = ny; - } - - cx = start_x; - cy = start_y; - while ((remaining > 0) && (forward_count < effective_limit)) { - int nx = cx + dx; - int ny = cy + dy; - wrap_tile_coords (map, &nx, &ny); - if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) - break; - if (! tile_is_land (-1, nx, ny, false)) - break; - if (tile_part_of_existing_candidate (nx, ny)) - break; - forward_x[forward_count] = (short)nx; - forward_y[forward_count] = (short)ny; - forward_count++; - remaining--; - cx = nx; - cy = ny; - } - - int write = 0; - for (int bi = back_count - 1; bi >= 0; bi--) { - out_x[write] = back_x[bi]; - out_y[write] = back_y[bi]; - write++; - } - out_x[write] = (short)start_x; - out_y[write] = (short)start_y; - write++; - for (int fi = 0; fi < forward_count; fi++) { - out_x[write] = forward_x[fi]; - out_y[write] = forward_y[fi]; - write++; - } - - return write; -} - -bool -cluster_connects_two_seas_or_isthmus (short * xs, short * ys, int count) -{ - for (int i = 0; i < count; i++) { - if (canal_has_different_adjacent_seas (xs[i], ys[i], -1)) - return true; - if (canal_has_same_sea_isthmus (xs[i], ys[i], -1, 2)) - return true; - } - return false; -} - -int -find_canal_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, - int contiguous_limit, int candidate_capacity, - short * out_x, short * out_y, short * out_owner) -{ - const int dir_dx[8] = { 0, 1, 2, 1, 0, -1, -2, -1 }; - const int dir_dy[8] = { -2, -1, 0, 1, 2, 1, 0, -1 }; - - int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - if (candidate_capacity > 0 && max_len > candidate_capacity) - max_len = candidate_capacity; - - int tile_count = map->TileCount; - int * visit = (int *)malloc (sizeof (*visit) * tile_count); - int * queue_x = (int *)malloc (sizeof (*queue_x) * tile_count); - int * queue_y = (int *)malloc (sizeof (*queue_y) * tile_count); - if ((visit == NULL) || (queue_x == NULL) || (queue_y == NULL)) { - if (visit != NULL) - free (visit); - if (queue_x != NULL) - free (queue_x); - if (queue_y != NULL) - free (queue_y); - return 0; - } - for (int i = 0; i < tile_count; i++) - visit[i] = 0; - - int visit_mark = 1; - - for (int length = 1; length <= max_len; length++) { - for (int ti = 0; ti < map->TileCount; ti++) { - int start_x = -1; - int start_y = -1; - tile_index_to_coords (map, ti, &start_x, &start_y); - if (! tile_point_in_block (start_x, start_y, block_x0, block_y0, block_x1, block_y1)) - continue; - if (! tile_is_land (-1, start_x, start_y, false)) - continue; - if (tile_part_of_existing_candidate (start_x, start_y)) - continue; - if (tile_has_bridge_or_canal_nearby (start_x, start_y)) - continue; - if (tile_is_reserved_in_district_tile_map (start_x, start_y)) - continue; - Tile * start_tile = tile_at (start_x, start_y); - if ((start_tile == NULL) || (start_tile == p_null_tile)) - continue; - if (tile_has_resource (start_tile)) - continue; - if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], start_tile)) - continue; - int continent_id = start_tile->vtable->m46_Get_ContinentID (start_tile); - if (continent_id < 0) - continue; - short owner = start_tile->vtable->m38_Get_Territory_OwnerID (start_tile); - - int stack_len = 1; - int dir_stack[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - int path_dir[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; - out_x[0] = (short)start_x; - out_y[0] = (short)start_y; - dir_stack[0] = -1; - path_dir[0] = -1; - - while (stack_len > 0) { - int depth = stack_len - 1; - int cx = out_x[depth]; - int cy = out_y[depth]; - - if (depth + 1 == length) { - bool endpoints_ok = false; - if (length == 1) { - int ex = out_x[0]; - int ey = out_y[0]; - bool pair_ok = false; - if (tile_is_water (ex, ey - 2) && tile_is_water (ex, ey + 2)) pair_ok = true; - if (tile_is_water (ex - 2, ey) && tile_is_water (ex + 2, ey)) pair_ok = true; - if (tile_is_water (ex - 1, ey - 1) && tile_is_water (ex + 1, ey + 1)) pair_ok = true; - if (tile_is_water (ex - 1, ey + 1) && tile_is_water (ex + 1, ey - 1)) pair_ok = true; - if (pair_ok && tile_has_diagonal_water (ex, ey)) - endpoints_ok = true; - } else { - int first_dir = path_dir[1]; - int last_dir = path_dir[length - 1]; - int sx = out_x[0]; - int sy = out_y[0]; - int ex = out_x[length - 1]; - int ey = out_y[length - 1]; - bool start_water = tile_is_water (sx - dir_dx[first_dir], sy - dir_dy[first_dir]); - bool end_water = tile_is_water (ex + dir_dx[last_dir], ey + dir_dy[last_dir]); - if (start_water && end_water && - tile_has_diagonal_water (sx, sy) && - tile_has_diagonal_water (ex, ey)) - endpoints_ok = true; - } - - bool buildable = true; - if (endpoints_ok) { - for (int pi = 0; pi < length; pi++) { - Tile * path_tile = tile_at (out_x[pi], out_y[pi]); - if ((path_tile == NULL) || (path_tile == p_null_tile) || - tile_has_resource (path_tile) || - (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], path_tile)) || - tile_is_reserved_in_district_tile_map (out_x[pi], out_y[pi])) { - buildable = false; - break; - } - if (tile_has_bridge_or_canal_nearby (out_x[pi], out_y[pi])) { - buildable = false; - break; - } - } - } else { - buildable = false; - } - - if (buildable) { - // Collect adjacent land tiles for component checks - int adj_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; - int adj_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; - int adj_count = 0; - for (int pi = 0; pi < length; pi++) { - int px = out_x[pi]; - int py = out_y[pi]; - for (int di = 0; di < 8; di++) { - int nx = px + dir_dx[di]; - int ny = py + dir_dy[di]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_is_land (-1, nx, ny, false)) - continue; - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) - continue; - bool in_path = false; - for (int pj = 0; pj < length; pj++) { - if ((out_x[pj] == nx) && (out_y[pj] == ny)) { - in_path = true; - break; - } - } - if (in_path) - continue; - bool seen = false; - for (int aj = 0; aj < adj_count; aj++) { - if ((adj_x[aj] == nx) && (adj_y[aj] == ny)) { - seen = true; - break; - } - } - if (! seen && (adj_count < (int)(sizeof (adj_x) / sizeof (adj_x[0])))) { - adj_x[adj_count] = nx; - adj_y[adj_count] = ny; - adj_count++; - } - } - } - - if (adj_count >= 2) { - int best1 = 0; - int best2 = 0; - int min_land = is->current_config.ai_canal_eval_min_bisected_land_tiles; - if (min_land < 1) - min_land = 1; - visit_mark++; - if (visit_mark == 0) { - visit_mark = 1; - for (int i = 0; i < tile_count; i++) - visit[i] = 0; - } - - for (int ai = 0; ai < adj_count; ai++) { - int aidx = tile_coords_to_index (map, adj_x[ai], adj_y[ai]); - if ((aidx < 0) || (visit[aidx] == visit_mark)) - continue; - - int comp_size = 0; - int head = 0; - int tail = 0; - visit[aidx] = visit_mark; - queue_x[tail] = adj_x[ai]; - queue_y[tail] = adj_y[ai]; - tail++; - - while (head < tail) { - int qx = queue_x[head]; - int qy = queue_y[head]; - head++; - comp_size++; - for (int di = 0; di < 8; di++) { - int nx = qx + dir_dx[di]; - int ny = qy + dir_dy[di]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_is_land (-1, nx, ny, false)) - continue; - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) - continue; - bool blocked = false; - for (int pj = 0; pj < length; pj++) { - if ((out_x[pj] == nx) && (out_y[pj] == ny)) { - blocked = true; - break; - } - } - if (blocked) - continue; - int nidx = tile_coords_to_index (map, nx, ny); - if ((nidx < 0) || (visit[nidx] == visit_mark)) - continue; - visit[nidx] = visit_mark; - queue_x[tail] = nx; - queue_y[tail] = ny; - tail++; - } - } - - if (comp_size > best1) { - best2 = best1; - best1 = comp_size; - } else if (comp_size > best2) { - best2 = comp_size; - } - } - - if ((best1 >= min_land) && (best2 >= min_land)) { - *out_owner = owner; - free (visit); - free (queue_x); - free (queue_y); - return length; - } - } - } - dir_stack[depth] = -1; - stack_len--; - continue; - } - - int next_dir = dir_stack[depth] + 1; - bool advanced = false; - while (next_dir < 8) { - int ndx = dir_dx[next_dir]; - int ndy = dir_dy[next_dir]; - int nx = cx + ndx; - int ny = cy + ndy; - wrap_tile_coords (map, &nx, &ny); - dir_stack[depth] = next_dir; - - if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) { - next_dir++; - continue; - } - if (! tile_is_land (-1, nx, ny, false)) { - next_dir++; - continue; - } - if (tile_part_of_existing_candidate (nx, ny)) { - next_dir++; - continue; - } - if (tile_is_reserved_in_district_tile_map (nx, ny)) { - next_dir++; - continue; - } - Tile * next_tile = tile_at (nx, ny); - if ((next_tile == NULL) || (next_tile == p_null_tile)) { - next_dir++; - continue; - } - if (tile_has_resource (next_tile)) { - next_dir++; - continue; - } - if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], next_tile)) { - next_dir++; - continue; - } - if (tile_has_bridge_or_canal_nearby (nx, ny)) { - next_dir++; - continue; - } - if (next_tile->vtable->m46_Get_ContinentID (next_tile) != continent_id) { - next_dir++; - continue; - } - bool dup = false; - for (int pi = 0; pi < depth + 1; pi++) { - if ((out_x[pi] == nx) && (out_y[pi] == ny)) { - dup = true; - break; - } - } - if (dup) { - next_dir++; - continue; - } - - if (depth >= 1) { - int prev_dir = dir_stack[depth - 1]; - int diff = next_dir - prev_dir; - if (diff < 0) - diff += 8; - if (diff > 4) - diff = 8 - diff; - if (diff > 1) { - next_dir++; - continue; - } - } - - out_x[depth + 1] = (short)nx; - out_y[depth + 1] = (short)ny; - dir_stack[depth + 1] = -1; - path_dir[depth + 1] = next_dir; - stack_len++; - advanced = true; - break; - } - - if (! advanced) { - dir_stack[depth] = -1; - stack_len--; - } - } - } - } - - free (visit); - free (queue_x); - free (queue_y); - return 0; -} - -void -generate_ai_bridge_candidates_by_block (Map * map, int block_size, int contiguous_limit) -{ - if ((map == NULL) || (block_size <= 0)) - return; - - int width = map->Width; - int height = map->Height; - if ((width <= 0) || (height <= 0)) - return; - - if (block_size < 1) - block_size = 1; - - int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - - short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); - short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); - if ((candidate_x == NULL) || (candidate_y == NULL)) { - if (candidate_x != NULL) - free (candidate_x); - if (candidate_y != NULL) - free (candidate_y); - return; - } - - for (int base_y = 0; base_y < height; base_y += block_size) { - int block_y1 = base_y + block_size; - if (block_y1 > height) - block_y1 = height; - for (int base_x = 0; base_x < width; base_x += block_size) { - int block_x1 = base_x + block_size; - if (block_x1 > width) - block_x1 = width; - short owner = -1; - int count = find_bridge_candidate_in_block ( - map, base_x, base_y, block_x1, block_y1, - contiguous_limit, candidate_capacity, - candidate_x, candidate_y, &owner); - if (count <= 0) - continue; - if (! add_ai_candidate_entry (BRIDGE_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { - free (candidate_x); - free (candidate_y); - return; - } - } - } - - free (candidate_x); - free (candidate_y); -} - -void -generate_ai_canal_candidates_by_block (Map * map, int block_size, int contiguous_limit) -{ - if ((map == NULL) || (block_size <= 0)) - return; - - int width = map->Width; - int height = map->Height; - if ((width <= 0) || (height <= 0)) - return; - - if (block_size < 1) - block_size = 1; - - int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); - - short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); - short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); - if ((candidate_x == NULL) || (candidate_y == NULL)) { - if (candidate_x != NULL) - free (candidate_x); - if (candidate_y != NULL) - free (candidate_y); - return; - } - - for (int base_y = 0; base_y < height; base_y += block_size) { - int block_y1 = base_y + block_size; - if (block_y1 > height) - block_y1 = height; - for (int base_x = 0; base_x < width; base_x += block_size) { - int block_x1 = base_x + block_size; - if (block_x1 > width) - block_x1 = width; - short owner = -1; - int count = find_canal_candidate_in_block ( - map, base_x, base_y, block_x1, block_y1, - contiguous_limit, candidate_capacity, - candidate_x, candidate_y, &owner); - if (count <= 0) - continue; - if (! add_ai_candidate_entry (CANAL_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { - free (candidate_x); - free (candidate_y); - return; - } - } - } - - free (candidate_x); - free (candidate_y); -} - -void -generate_ai_canal_and_bridge_targets () -{ - if (is->ai_candidate_bridge_or_canals_initialized) - return; - if ((! is->current_config.enable_canal_districts) && (! is->current_config.enable_bridge_districts)) - return; - - Map * map = &p_bic_data->Map; - int width = map->Width; - int height = map->Height; - if ((width <= 0) || (height <= 0)) - return; - - int block_size = is->current_config.ai_bridge_canal_eval_block_size; - if (block_size <= 0) - block_size = 10; - - if (is->current_config.enable_bridge_districts && is->current_config.ai_builds_bridges) { - generate_ai_bridge_candidates_by_block ( - map, - block_size, - is->current_config.max_contiguous_bridge_districts); - } - - if (is->current_config.enable_canal_districts && is->current_config.ai_builds_canals) { - generate_ai_canal_candidates_by_block ( - map, - block_size, - is->current_config.max_contiguous_canal_districts); - } - - is->ai_candidate_bridge_or_canals_initialized = true; -} - -void -assign_workers_for_ai_candidate_bridge_or_canals (Leader * leader) -{ - if ((leader == NULL) || (is->ai_candidate_bridge_or_canals_count <= 0)) - return; - - int civ_id = leader->ID; - if ((*p_human_player_bits & (1 << civ_id)) != 0) - return; - - if (! leader_can_build_district (leader, CANAL_DISTRICT_ID) && ! leader_can_build_district (leader, BRIDGE_DISTRICT_ID)) - return; - - if (! is->ai_candidate_bridge_or_canals_initialized) { - reset_ai_candidate_bridge_or_canals (); - generate_ai_canal_and_bridge_targets (); - } - - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if (entry->completed) - continue; - - int district_id = entry->district_id; - if ((district_id == CANAL_DISTRICT_ID) && (! is->current_config.enable_canal_districts)) continue; - if ((district_id == BRIDGE_DISTRICT_ID) && (! is->current_config.enable_bridge_districts)) continue; - if (! leader_can_build_district (leader, district_id)) continue; - - if (entry->assigned_worker_id >= 0) { - Unit * worker = get_unit_ptr (entry->assigned_worker_id); - if (worker == NULL) { - release_ai_candidate_bridge_or_canal_worker (entry); - } else if ((entry->assigned_tile_index >= 0) && (entry->assigned_tile_index < entry->tile_count)) { - int tx = entry->tile_x[entry->assigned_tile_index]; - int ty = entry->tile_y[entry->assigned_tile_index]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - Tile * tile = tile_at (tx, ty); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && inst->district_id == district_id && district_is_complete (tile, district_id)) { - release_ai_candidate_bridge_or_canal_worker (entry); - } - } - } - if (entry->assigned_worker_id >= 0) - continue; - } - - int target_idx = -1; - if (! ai_candidate_bridge_or_canal_is_buildable_for_civ (entry, civ_id, &target_idx)) { - release_ai_candidate_bridge_or_canal_worker (entry); - continue; - } - - if (target_idx < 0) - continue; - - City * city = find_closest_owned_city_for_tile (civ_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); - if (city == NULL) - continue; - - Unit * worker = find_best_worker_for_district (leader, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); - if (worker == NULL) - continue; - - memset (&entry->pending_req, 0, sizeof entry->pending_req); - entry->pending_req.district_id = district_id; - entry->pending_req.civ_id = civ_id; - if (! assign_worker_to_district (&entry->pending_req, worker, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx])) - continue; - - entry->assigned_worker_id = worker->Body.ID; - entry->assigned_tile_index = target_idx; - } -} - -void -recompute_city_yields_with_districts (City * city) -{ - if (city == NULL) - return; - - bool prev_flag = is->distribution_hub_refresh_in_progress; - is->distribution_hub_refresh_in_progress = true; - patch_City_recompute_yields_and_happiness (city); - is->distribution_hub_refresh_in_progress = prev_flag; -} - -enum UnitStateType __fastcall -patch_City_instruct_worker (City * this, int edx, int tile_x, int tile_y, bool param_3, Unit * worker) -{ - return City_instruct_worker (this, __, tile_x, tile_y, param_3, worker); -} - -int -find_wonder_config_index_by_improvement_id (int improv_id) -{ - if (improv_id < 0) - return -1; - - char ss[200]; - - for (int wi = 0; wi < is->wonder_district_count; wi++) { - int bid = -1; - if (stable_look_up (&is->building_name_to_id, is->wonder_district_configs[wi].wonder_name, &bid) && - (bid == improv_id)) { - return wi; - } - } - - return -1; -} - -void set_wonder_built_flag (int improv_id, bool is_built); - -unsigned int -wonder_buildable_square_type_mask (struct wonder_district_config const * cfg) -{ - if (cfg == NULL) - return district_default_buildable_mask (); - - unsigned int mask = cfg->buildable_square_types_mask; - if (mask == 0) - mask = district_default_buildable_mask (); - return mask; -} - -unsigned int -wonder_buildable_mask_for_improvement (int improv_id) -{ - int windex = find_wonder_config_index_by_improvement_id (improv_id); - if (windex < 0) - return district_default_buildable_mask (); - return wonder_buildable_square_type_mask (&is->wonder_district_configs[windex]); -} - -bool -wonder_is_buildable_on_square_type (struct wonder_district_config const * cfg, Tile * tile) -{ - if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - if (! tile_matches_square_type_mask (tile, wonder_buildable_square_type_mask (cfg))) - return false; - - if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) - return false; - - if (cfg->has_buildable_adjacent_to) { - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - return false; - - bool matches = false; - bool city_adjacent = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (Tile_has_city (tai.tile)) { - city_adjacent = true; - if (cfg->buildable_adjacent_to_allows_city) - matches = true; - } - if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) - matches = true; - if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) - break; - } - if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) - return false; - if (! matches) - return false; - } - - if (cfg->has_buildable_adjacent_to_overlays) { - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - return false; - - bool matches = false; - FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { - if (tai.n == 0) - continue; - if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { - matches = true; - break; - } - } - if (! matches) - return false; - } - - return true; -} - -bool -wonder_is_buildable_on_tile (Tile * tile, int wonder_improv_id) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); - if (windex < 0) - return tile_matches_square_type_mask (tile, district_default_buildable_mask ()); - - return wonder_is_buildable_on_square_type (&is->wonder_district_configs[windex], tile); -} - -bool -wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id) -{ - if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) - return false; - if ((civ_id < 0) || (civ_id >= 32)) - return false; - - int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); - if (windex < 0) - return true; - - struct wonder_district_config const * cfg = &is->wonder_district_configs[windex]; - Leader * leader = &leaders[civ_id]; - - if (cfg->has_buildable_by_civs) { - bool civ_match = false; - if (cfg->buildable_by_civ_count > 0) { - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - for (int i = 0; i < cfg->buildable_by_civ_count; i++) { - char const * civ_name = cfg->buildable_by_civs[i]; - if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; - if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; - if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; - if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; - if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; - } - } - if (! civ_match) - return false; - } - - if (cfg->has_buildable_by_civ_traits) { - if (cfg->buildable_by_civ_traits_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL || race->vtable == NULL) - return false; - bool trait_match = false; - for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { - int trait_id = cfg->buildable_by_civ_traits_ids[i]; - if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { - trait_match = true; - break; - } - } - if (! trait_match) - return false; - } - - if (cfg->has_buildable_by_civ_govs) { - if (cfg->buildable_by_civ_govs_id_count <= 0) - return false; - int gov_id = leader->GovernmentType; - bool gov_match = false; - for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { - if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { - gov_match = true; - break; - } - } - if (! gov_match) - return false; - } - - if (cfg->has_buildable_by_civ_cultures) { - if (cfg->buildable_by_civ_cultures_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - int culture_id = race->CultureGroupID; - bool culture_match = false; - for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { - if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { - culture_match = true; - break; - } - } - if (! culture_match) - return false; - } - - return true; -} - -int -get_wonder_improvement_id_from_index (int windex) -{ - if ((windex < 0) || (windex >= is->wonder_district_count)) - return -1; - - char const * wonder_name = is->wonder_district_configs[windex].wonder_name; - if ((wonder_name == NULL) || (wonder_name[0] == '\0')) - return -1; - - int improv_id; - if (stable_look_up (&is->building_name_to_id, (char *)wonder_name, &improv_id)) - return improv_id; - else - return -1; -} - -void -remember_pending_building_order (City * city, int improvement_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (improvement_id < 0)) - return; - - if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) - return; - - itable_insert (&is->city_pending_building_orders, (int)city, improvement_id); -} - -bool -look_up_pending_building_order (City * city, int * out_improv_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (out_improv_id == NULL)) - return false; - - return itable_look_up (&is->city_pending_building_orders, (int)city, out_improv_id); -} - -void -forget_pending_building_order (City * city) -{ - if (! is->current_config.enable_districts || - (city == NULL)) - return; - - itable_remove (&is->city_pending_building_orders, (int)city); -} - -bool -is_wonder_or_small_wonder_already_being_built (City * city, int improv_id) -{ - if ((city == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) - return false; - - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) - return false; - - int civ_id = city->Body.CivID; - FOR_CITIES_OF (coi, civ_id) { - City * other_city = coi.city; - if ((other_city == NULL) || (other_city == city)) - continue; - - if ((other_city->Body.Order_Type == COT_Improvement) && - (other_city->Body.Order_ID == improv_id)) - return true; - } - - return false; -} - -struct district_building_prereq_list * -get_district_building_prereq_list (int improv_id) -{ - if (improv_id < 0) - return NULL; - - int stored = 0; - if (! itable_look_up (&is->district_building_prereqs, improv_id, &stored)) - return NULL; - return (struct district_building_prereq_list *)stored; -} - -bool -district_building_prereq_list_contains (struct district_building_prereq_list * list, int district_id) -{ - if ((list == NULL) || (district_id < 0)) - return false; - for (int i = 0; i < list->count; i++) { - if (list->district_ids[i] == district_id) - return true; - } - return false; -} - -void -add_district_building_prereq (int improv_id, int district_id) -{ - if ((improv_id < 0) || (district_id < 0)) - return; - - struct district_building_prereq_list * list = get_district_building_prereq_list (improv_id); - if (list == NULL) { - list = calloc (1, sizeof *list); - if (list == NULL) - return; - list->count = 0; - itable_insert (&is->district_building_prereqs, improv_id, (int)list); - } - - if (district_building_prereq_list_contains (list, district_id)) - return; - - if (list->count >= ARRAY_LEN (list->district_ids)) - return; - - list->district_ids[list->count++] = district_id; -} - -bool -city_has_river_district (City * city, int district_id) -{ - if (city == NULL) - return false; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if (wai.district_inst->district_id != district_id) - continue; - if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) - return true; - } - return false; -} - -bool -city_has_any_prereq_district_for_improvement (City * city, - struct district_building_prereq_list * list, - bool requires_river, - bool allow_wonder_district) -{ - if ((city == NULL) || (list == NULL)) - return false; - - for (int i = 0; i < list->count; i++) { - int district_id = list->district_ids[i]; - if (district_id < 0) - continue; - if (! allow_wonder_district && district_id == WONDER_DISTRICT_ID) - continue; - if (requires_river) { - if (city_has_river_district (city, district_id)) - return true; - } else if (city_has_required_district (city, district_id)) { - return true; - } - } - return false; -} - -int -pick_missing_district_for_improvement (City * city, struct district_building_prereq_list * list) -{ - if ((list == NULL) || (list->count <= 0)) - return -1; - - int fallback = -1; - for (int i = 0; i < list->count; i++) { - int district_id = list->district_ids[i]; - if (district_id < 0) - continue; - if (fallback < 0) - fallback = district_id; - if ((city != NULL) && leader_can_build_district (&leaders[city->Body.CivID], district_id)) - return district_id; - } - return fallback; -} - - -bool -district_is_complete(Tile * tile, int district_id) -{ - if ((tile == NULL) || (tile == p_null_tile) || - (district_id < 0) || (district_id >= is->district_count)) - return false; - - bool is_natural_wonder = (district_id == NATURAL_WONDER_DISTRICT_ID); - bool districts_disabled = ! is->current_config.enable_districts; - bool natural_wonders_disabled = ! is->current_config.enable_natural_wonders; - struct district_config const * cfg = &is->district_configs[district_id]; - - if (districts_disabled && (!is_natural_wonder || natural_wonders_disabled)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != district_id) - return false; - - // If already marked COMPLETED, just return true - if (inst->state == DS_COMPLETED) - return true; - - // State is UNDER_CONSTRUCTION - check if tile has mines now - bool has_mines = tile->vtable->m18_Check_Mines (tile, __, 0) != 0; - - if (! has_mines) { - // Still under construction - check if we should clean it up - bool worker_present = false; - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit != NULL) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { - worker_present = true; - break; - } - } - if (! worker_present) { - remove_district_instance (tile); - } - return false; - } - - // Mark as completed and run one-time side effects - inst->state = DS_COMPLETED; - inst->completed_turn = *p_current_turn_no; - - int tile_x, tile_y; - if (district_instance_get_coords (inst, tile, &tile_x, &tile_y)) { - set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - if (cfg->auto_add_road) { - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - if (! has_road) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_ROAD, tile_x, tile_y); - } - - if (cfg->auto_add_railroad) { - bool has_railroad = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; - if (! has_railroad) { - if ((territory_owner >= 0) && patch_Leader_can_do_worker_job (&leaders[territory_owner], __, WJ_Build_Railroad, tile_x, tile_y, 0)) { - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_RAILROAD, tile_x, tile_y); - } - } - } - - // Activate distribution hub if applicable - if (is->current_config.enable_distribution_hub_districts && - (district_id == DISTRIBUTION_HUB_DISTRICT_ID)) { - on_distribution_hub_completed (tile, tile_x, tile_y); - } - - // Remove forest/swamp if applicable - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - if ((base_type == SQ_Forest) || (base_type == SQ_Swamp)) { - int new_terrain_type = tile->vtable->m71_Check_Worker_Job (tile); - if (new_terrain_type >= 0) - Map_change_tile_terrain (&p_bic_data->Map, __, (enum SquareTypes)new_terrain_type, tile_x, tile_y); - } - - char ss[200]; - snprintf (ss, sizeof ss, "District %d completed at tile (%d,%d)\n", district_id, tile_x, tile_y); - (*p_OutputDebugStringA) (ss); - - // Check if this was an AI-requested district - struct pending_district_request * req = find_pending_district_request_by_coords (NULL, tile_x, tile_y, district_id); - if (req != NULL) { - City * requesting_city = get_city_ptr (req->city_id); - if (requesting_city != NULL) { - req->city = requesting_city; - snprintf (ss, sizeof ss, "District %d at tile (%d,%d) was ordered by city %s\n", - district_id, tile_x, tile_y, requesting_city->Body.CityName); - (*p_OutputDebugStringA) (ss); - - // Check if city has pending building order that depends on this district - int pending_improv_id; - if (look_up_pending_building_order (requesting_city, &pending_improv_id)) { - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (pending_improv_id); - if (district_building_prereq_list_contains (prereq_list, district_id)) { - snprintf (ss, sizeof ss, "City %s setting production to improvement %d\n", - requesting_city->Body.CityName, pending_improv_id); - (*p_OutputDebugStringA) (ss); - - // Check if another city is already building this wonder/small wonder - bool can_set_production = true; - if (is_wonder_or_small_wonder_already_being_built (requesting_city, pending_improv_id)) { - snprintf (ss, sizeof ss, "City %s cannot build improvement %d - already being built elsewhere\n", - requesting_city->Body.CityName, pending_improv_id); - (*p_OutputDebugStringA) (ss); - can_set_production = false; - } - - // Set city production to the pending improvement - if (can_set_production && City_can_build_improvement (requesting_city, __, pending_improv_id, false)) { - snprintf (ss, sizeof ss, "City %s can now build improvement %d\n", - requesting_city->Body.CityName, pending_improv_id); - (*p_OutputDebugStringA) (ss); - City_set_production (requesting_city, __, COT_Improvement, pending_improv_id, false); - } - - // Clear the pending building order - forget_pending_building_order (requesting_city); - } - } - - // Clear worker assignment so worker is freed up for other tasks - if (req->assigned_worker_id >= 0) { - snprintf (ss, sizeof ss, "Clearing worker assignment for unit %d\n", req->assigned_worker_id); - (*p_OutputDebugStringA) (ss); - int civ_id = req->civ_id; - clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); - } - } - - // Remove the pending district request - remove_pending_district_request (req); - } - } - - return true; -} - -void -mark_city_needs_district (City * city, int district_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (district_id < 0) || (district_id >= is->district_count)) - return; - - create_pending_district_request (city, district_id); -} - -void -set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return; - - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - - City * assigned_city = NULL; - int assigned_city_id = tile->Body.CityAreaID; - if (assigned_city_id >= 0) - assigned_city = get_city_ptr (assigned_city_id); - - if (assigned_city != NULL) { - int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, - assigned_city->Body.X, assigned_city->Body.Y, tile_x, tile_y, 1000); - bool removed_assignment = false; - if ((neighbor_index > 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) - removed_assignment = City_stop_working_tile (assigned_city, __, neighbor_index); - if (! removed_assignment) - tile->Body.CityAreaID = -1; - if (! removed_assignment) - recompute_city_yields_with_districts (assigned_city); - } else - tile->Body.CityAreaID = -1; - - if (p_cities->Cities != NULL) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city == NULL) || (city == assigned_city)) - continue; - int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, - city->Body.X, city->Body.Y, tile_x, tile_y, 1000); - if ((neighbor_index <= 0) || (neighbor_index >= ARRAY_LEN (is->ni_to_work_radius))) - continue; - int work_radius = is->ni_to_work_radius[neighbor_index]; - if ((work_radius < 0) || (work_radius > is->current_config.city_work_radius)) - continue; - recompute_city_yields_with_districts (city); - } - } -} - -struct distribution_hub_record * -get_distribution_hub_record (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - - int stored; - if (itable_look_up (&is->distribution_hub_records, (int)tile, &stored)) - return (struct distribution_hub_record *)stored; - else - return NULL; -} - -City * -get_connected_city_for_distribution_hub (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return NULL; - - Tile * tile = rec->tile; - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - - City * best_city = NULL; - int best_distance = INT_MAX; - int best_y = INT_MAX; - int best_x = INT_MAX; - int best_id = INT_MAX; - - FOR_CITIES_OF (coi, rec->civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, city, rec->tile_x, rec->tile_y)) - continue; - - int distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, city->Body.X, city->Body.Y); - if ((best_city == NULL) || - (distance < best_distance) || - ((distance == best_distance) && (city->Body.Y < best_y)) || - ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X < best_x)) || - ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X == best_x) && (city->Body.ID < best_id))) { - best_city = city; - best_distance = distance; - best_y = city->Body.Y; - best_x = city->Body.X; - best_id = city->Body.ID; - } - } - - return best_city; -} - -bool -distribution_hub_accessible_to_city (struct distribution_hub_record * rec, City * city) -{ - if ((rec == NULL) || (city == NULL)) - return false; - - if (city->Body.CivID != rec->civ_id) - return false; - - City * anchor_city = get_connected_city_for_distribution_hub (rec); - if (anchor_city == NULL) - return false; - - if (anchor_city == city) - return true; - - return Trade_Net_have_trade_connection (is->trade_net, __, anchor_city, city, rec->civ_id); -} - -void -get_distribution_hub_yields_for_city (City * city, int * out_food, int * out_shields) -{ - int food = 0; - int shields = 0; - - if ((city != NULL) && - is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts) { - if (is->distribution_hub_totals_dirty && - ! is->distribution_hub_refresh_in_progress) - recompute_distribution_hub_totals (); - - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (distribution_hub_accessible_to_city (rec, city)) { - food += rec->food_yield; - shields += rec->shield_yield; - } - } - } - - if (city_has_required_district (city, CENTRAL_RAIL_HUB_DISTRICT_ID)) { - food += (food * is->current_config.central_rail_hub_distribution_food_bonus_percent) / 100; - shields += (shields * is->current_config.central_rail_hub_distribution_shield_bonus_percent) / 100; - } - - if (out_food != NULL) - *out_food = food; - if (out_shields != NULL) - *out_shields = shields; -} - -void -adjust_distribution_hub_coverage (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return; - - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if ((area_tile == NULL) || (area_tile == p_null_tile)) - continue; - int tx = tai.tile_x; - int ty = tai.tile_y; - - if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) - continue; - if (Tile_has_city (area_tile)) - continue; - if (get_district_instance (area_tile) != NULL) - continue; - - struct wonder_district_info * area_info = get_wonder_district_info (area_tile); - if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) - continue; - - int key = (int)area_tile; - int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); - itable_insert (&is->distribution_hub_coverage_counts, key, prev + 1); - - if (area_tile->Body.CityAreaID >= 0) { - set_tile_unworkable_for_all_cities (area_tile, tx, ty); - area_tile->Body.CityAreaID = -1; - } - } -} - -void -release_distribution_hub_coverage (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return; - - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if ((area_tile == NULL) || (area_tile == p_null_tile)) - continue; - - int key = (int)area_tile; - int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); - if (prev <= 0) - continue; - - if (prev == 1) - itable_remove (&is->distribution_hub_coverage_counts, key); - else - itable_insert (&is->distribution_hub_coverage_counts, key, prev - 1); - } -} - -void -clear_distribution_hub_tables (void) -{ - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - free (rec); - } - table_deinit (&is->distribution_hub_records); - table_deinit (&is->distribution_hub_coverage_counts); - is->distribution_hub_totals_dirty = true; -} - -bool -city_radius_contains_tile (City * city, int tile_x, int tile_y) -{ - if (city == NULL) - return false; - - int ni = patch_Map_compute_ni_for_work_area (&p_bic_data->Map, __, city->Body.X, city->Body.Y, tile_x, tile_y, is->workable_tile_count); - return ni >= 0; -} - -void -recompute_distribution_hub_yields (struct distribution_hub_record * rec) -{ - if (rec == NULL) - return; - - Tile * tile = tile_at (rec->tile_x, rec->tile_y); - rec->tile = tile; - - if ((tile == NULL) || - (tile == p_null_tile) || - ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID) || - tile->vtable->m20_Check_Pollution (tile, __, 0) || - tile_has_enemy_unit (tile, rec->civ_id)) { - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - return; - } - - int food_sum = 0; - int shield_sum = 0; - City * anchor_city = get_connected_city_for_distribution_hub (rec); - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if (area_tile == p_null_tile) - continue; - int tx = tai.tile_x; - int ty = tai.tile_y; - - // Only include tiles that belong to the distribution hub owner - if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) - continue; - - // Skip city tiles - if (Tile_has_city (area_tile)) - continue; - - // Skip tiles with enemy units - if (tile_has_enemy_unit (area_tile, rec->civ_id)) - continue; - - // Skip tiles with pollution - if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) - continue; - - // Skip tiles that are other districts (but not this hub itself) - struct district_instance * area_district = get_district_instance (area_tile); - if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) - continue; - - // Skip tiles with completed wonders - struct wonder_district_info * area_info = get_wonder_district_info (area_tile); - if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) - continue; - - // Check if another hub of the same civ is closer to this tile - int my_distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, tx, ty); - bool tile_belongs_to_me = true; - - FOR_TABLE_ENTRIES (other_tei, &is->distribution_hub_records) { - struct distribution_hub_record * other_rec = (struct distribution_hub_record *)other_tei.value; - if ((other_rec == NULL) || (other_rec == rec)) - continue; - if (other_rec->civ_id != rec->civ_id) - continue; - - int other_distance = compute_wrapped_manhattan_distance (other_rec->tile_x, other_rec->tile_y, tx, ty); - if (other_distance < my_distance) { - tile_belongs_to_me = false; - break; - } - if (other_distance == my_distance) { - // Tie-breaking: prefer hub with lower Y, then lower X - if (other_rec->tile_y < rec->tile_y) { - tile_belongs_to_me = false; - break; - } - if ((other_rec->tile_y == rec->tile_y) && (other_rec->tile_x < rec->tile_x)) { - tile_belongs_to_me = false; - break; - } - } - } - - if (! tile_belongs_to_me) - continue; - - food_sum += City_calc_tile_yield_at (anchor_city, __, 0, tx, ty); - shield_sum += City_calc_tile_yield_at (anchor_city, __, 1, tx, ty); - } - - rec->raw_food_yield = food_sum; - rec->raw_shield_yield = shield_sum; - - int food_div = is->current_config.distribution_hub_food_yield_divisor; - int shield_div = is->current_config.distribution_hub_shield_yield_divisor; - if (food_div <= 0) - food_div = 1; - if (shield_div <= 0) - shield_div = 1; - - int connected_city_count = 0; - if (anchor_city != NULL) { - FOR_CITIES_OF (coi, rec->civ_id) { - City * other_city = coi.city; - if ((other_city != NULL) && distribution_hub_accessible_to_city (rec, other_city)) - connected_city_count++; - } - } - if (connected_city_count <= 0) - connected_city_count = 1; - - if (is->current_config.distribution_hub_yield_division_mode == DHYDM_SCALE_BY_CITY_COUNT) { - int city_root = 1; - while ((city_root + 1) * (city_root + 1) <= connected_city_count) - city_root++; - int city_food_divisor = city_root * food_div; - int city_shield_divisor = city_root * shield_div; - if (city_food_divisor < 1) city_food_divisor = 1; - if (city_shield_divisor < 1) city_shield_divisor = 1; - rec->food_yield = food_sum / city_food_divisor; - rec->shield_yield = shield_sum / city_shield_divisor; - } else { - rec->food_yield = food_sum / food_div; - rec->shield_yield = shield_sum / shield_div; - } -} - -void -remove_distribution_hub_record (Tile * tile) -{ - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec == NULL) - return; - - int affected_civ_id = rec->civ_id; - release_distribution_hub_coverage (rec); - itable_remove (&is->distribution_hub_records, (int)tile); - free (rec); - is->distribution_hub_totals_dirty = true; - recompute_distribution_hub_totals (); - - // Recalculate yields for all cities of this civ - if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * target_city = get_city_ptr (city_index); - if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) - recompute_city_yields_with_districts (target_city); - } - } -} - -void -recompute_distribution_hub_totals () -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_distribution_hub_districts) { - is->distribution_hub_totals_dirty = false; - return; - } - - struct table new_coverage_counts = {0}; - struct table newly_covered_tiles = {0}; - - clear_memo (); - int civs_needing_recalc[32] = {0}; - - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - Tile * tile = (Tile *)tei.key; - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (rec == NULL) - continue; - - Tile * current_tile = tile_at (rec->tile_x, rec->tile_y); - if ((current_tile == NULL) || - (current_tile == p_null_tile) || - ! district_is_complete (current_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { - memoize (tei.key); - continue; - } - - rec->tile = current_tile; - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - - int old_civ_id = rec->civ_id; - rec->civ_id = current_tile->vtable->m38_Get_Territory_OwnerID (current_tile); - - if (old_civ_id != rec->civ_id) - civs_needing_recalc[old_civ_id] = 1; - civs_needing_recalc[rec->civ_id] = 1; - - City * anchor = get_connected_city_for_distribution_hub (rec); - - if ((anchor == NULL) || - current_tile->vtable->m20_Check_Pollution (current_tile, __, 0) || - tile_has_enemy_unit (current_tile, rec->civ_id)) - continue; - - FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { - Tile * area_tile = tai.tile; - if (area_tile == p_null_tile) - continue; - int tx = tai.tile_x; - int ty = tai.tile_y; - - if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) - continue; - if (Tile_has_city (area_tile)) - continue; - if (tile_has_enemy_unit (area_tile, rec->civ_id)) - continue; - if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) - continue; - - struct district_instance * area_district = get_district_instance (area_tile); - if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) - continue; - - struct wonder_district_info * area_info = get_wonder_district_info (area_tile); - if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) - continue; - - int key = (int)area_tile; - int prev_cover_pass = itable_look_up_or (&new_coverage_counts, key, 0); - int prev_cover_old = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); - itable_insert (&new_coverage_counts, key, prev_cover_pass + 1); - if ((prev_cover_pass == 0) && (prev_cover_old <= 0)) - itable_insert (&newly_covered_tiles, key, 1); - } - } - - for (int i = 0; i < is->memo_len; i++) - remove_distribution_hub_record ((Tile *)is->memo[i]); - clear_memo (); - - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (rec == NULL) - continue; - - City * anchor = get_connected_city_for_distribution_hub (rec); - if (anchor == NULL) { - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - continue; - } - - recompute_distribution_hub_yields (rec); - } - - table_deinit (&is->distribution_hub_coverage_counts); - is->distribution_hub_coverage_counts = new_coverage_counts; - memset (&new_coverage_counts, 0, sizeof new_coverage_counts); - - FOR_TABLE_ENTRIES (tei, &newly_covered_tiles) { - Tile * covered_tile = (Tile *)tei.key; - if ((covered_tile == NULL) || (covered_tile == p_null_tile)) - continue; - int tx, ty; - if (! tile_coords_from_ptr (&p_bic_data->Map, covered_tile, &tx, &ty)) - continue; - set_tile_unworkable_for_all_cities (covered_tile, tx, ty); - covered_tile->Body.CityAreaID = -1; - } - table_deinit (&newly_covered_tiles); - - // Recalculate yields for cities of civs whose distribution hub ownership changed - for (int civ_id = 0; civ_id < 32; civ_id++) { - if (civs_needing_recalc[civ_id] && (p_cities->Cities != NULL)) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city != NULL) && (city->Body.CivID == civ_id)) - recompute_city_yields_with_districts (city); - } - } - } - - is->distribution_hub_totals_dirty = false; -} - -void -on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y) -{ - if (! is->current_config.enable_districts || ! is->current_config.enable_distribution_hub_districts) - return; - - int tile_owner = -1; - if ((tile != NULL) && (tile != p_null_tile)) - tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec != NULL) { - int old_civ_id = rec->civ_id; - rec->tile = tile; - rec->tile_x = tile_x; - rec->tile_y = tile_y; - - release_distribution_hub_coverage (rec); - rec->civ_id = tile_owner; - is->distribution_hub_totals_dirty = true; - recompute_distribution_hub_totals (); - - if (old_civ_id != tile_owner) { - // Recompute for old civ - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * target_city = get_city_ptr (city_index); - if ((target_city != NULL) && (target_city->Body.CivID == old_civ_id)) - recompute_city_yields_with_districts (target_city); - } - } - } - - rec = malloc (sizeof *rec); - if (rec == NULL) - return; - rec->tile = tile; - rec->tile_x = tile_x; - rec->tile_y = tile_y; - rec->civ_id = tile_owner; - rec->food_yield = 0; - rec->shield_yield = 0; - rec->raw_food_yield = 0; - rec->raw_shield_yield = 0; - itable_insert (&is->distribution_hub_records, (int)tile, (int)rec); - adjust_distribution_hub_coverage (rec); - - is->distribution_hub_totals_dirty = true; - recompute_distribution_hub_totals (); - - // Recalculate yields for all cities of this civ - int affected_civ_id = rec->civ_id; - if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * target_city = get_city_ptr (city_index); - if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) - recompute_city_yields_with_districts (target_city); - } - } -} - -void -refresh_distribution_hubs_for_city (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_distribution_hub_districts || - (city == NULL)) - return; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int tx = wai.tile_x, ty = wai.tile_y; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID) - continue; - on_distribution_hub_completed (tile, tx, ty); - } -} - -bool -is_space_char (char c) -{ - switch (c) { - case ' ': - case '\t': - case '\n': - case '\r': - case '\f': - case '\v': - return true; - default: - return false; - } -} - -enum key_value_parse_status { - KVP_SUCCESS, - KVP_NO_EQUALS, - KVP_EMPTY_KEY -}; - -enum key_value_parse_status -parse_trimmed_key_value (struct string_slice const * trimmed, - struct string_slice * out_key, - struct string_slice * out_value) -{ - if ((trimmed == NULL) || (trimmed->len <= 0)) - return KVP_NO_EQUALS; - - char * equals = NULL; - for (int i = 0; i < trimmed->len; i++) { - if (trimmed->str[i] == '=') { - equals = trimmed->str + i; - break; - } - } - if (equals == NULL) - return KVP_NO_EQUALS; - - struct string_slice key = { .str = trimmed->str, .len = (int)(equals - trimmed->str) }; - key = trim_string_slice (&key, 0); - if (key.len == 0) - return KVP_EMPTY_KEY; - - struct string_slice value = { .str = equals + 1, .len = (int)((trimmed->str + trimmed->len) - (equals + 1)) }; - *out_key = key; - *out_value = trim_string_slice (&value, 0); - return KVP_SUCCESS; -} - -void -add_key_parse_error (struct error_line ** parse_errors, - int line_number, - struct string_slice const * key, - struct string_slice const * value, - char const * message_suffix) -{ - struct error_line * err = add_error_line (parse_errors); - char * key_str = extract_slice (key); - char * value_str = (value != NULL) ? extract_slice (value) : NULL; - if (value_str != NULL) - snprintf (err->text, sizeof err->text, "^ Line %d: %s \"%s\" %s", line_number, key_str, value_str, message_suffix); - else - snprintf (err->text, sizeof err->text, "^ Line %d: %s %s", line_number, key_str, message_suffix); - err->text[(sizeof err->text) - 1] = '\0'; - if (value_str != NULL) - free (value_str); - free (key_str); -} - -void -add_unrecognized_key_error (struct error_line ** unrecognized_keys, - int line_number, - struct string_slice const * key) -{ - struct error_line * err_line = add_error_line (unrecognized_keys); - char * key_str = extract_slice (key); - snprintf (err_line->text, sizeof err_line->text, "^ Line %d: %s", line_number, key_str); - err_line->text[(sizeof err_line->text) - 1] = '\0'; - free (key_str); -} - -char * -copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes) -{ - struct string_slice trimmed = trim_string_slice (slice, remove_quotes); - if (trimmed.len == 0) - return NULL; - return extract_slice (&trimmed); -} - -void -free_bonus_entry_list (struct district_bonus_list * list) -{ - if (list == NULL) - return; - - for (int i = 0; i < list->count; i++) { - if (list->entries[i].type == DBET_BUILDING && - list->entries[i].building_name != NULL) { - free ((void *)list->entries[i].building_name); - list->entries[i].building_name = NULL; - } - } - list->count = 0; -} - -void -free_bonus_entry_list_override (struct district_bonus_list * list, - struct district_bonus_list const * defaults) -{ - if (list == NULL) - return; - - for (int i = 0; i < list->count; i++) { - if (list->entries[i].type == DBET_BUILDING && - list->entries[i].building_name != NULL) { - char const * default_name = NULL; - if ((defaults != NULL) && (i < defaults->count)) - default_name = defaults->entries[i].building_name; - if (list->entries[i].building_name != default_name) - free ((void *)list->entries[i].building_name); - list->entries[i].building_name = NULL; - } - } - list->count = (defaults != NULL) ? defaults->count : 0; -} - -void -move_bonus_entry_list (struct district_bonus_list * dest, - struct district_bonus_list * src) -{ - if ((dest == NULL) || (src == NULL)) - return; - - dest->count = src->count; - for (int i = 0; i < src->count; i++) { - dest->entries[i] = src->entries[i]; - src->entries[i].building_name = NULL; - } - src->count = 0; -} - -void -free_dynamic_district_config (struct district_config * cfg) -{ - if (cfg == NULL) - return; - - if (! cfg->is_dynamic) - return; - - char const * name_ptr = cfg->name; - if (cfg->name != NULL) { - free ((void *)cfg->name); - cfg->name = NULL; - } - if ((cfg->display_name != NULL) && - (cfg->display_name != name_ptr)) { - free ((void *)cfg->display_name); - cfg->display_name = NULL; - } - if (cfg->tooltip != NULL) { - free ((void *)cfg->tooltip); - cfg->tooltip = NULL; - } - for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { - if (cfg->advance_prereqs[i] != NULL) { - free ((void *)cfg->advance_prereqs[i]); - cfg->advance_prereqs[i] = NULL; - } - } - cfg->advance_prereq_count = 0; - if (cfg->obsoleted_by != NULL) { - free ((void *)cfg->obsoleted_by); - cfg->obsoleted_by = NULL; - } - - for (int i = 0; i < 5; i++) { - if (cfg->resource_prereqs[i] != NULL) { - free ((void *)cfg->resource_prereqs[i]); - cfg->resource_prereqs[i] = NULL; - } - } - - if (cfg->resource_prereq_on_tile != NULL) { - free ((void *)cfg->resource_prereq_on_tile); - cfg->resource_prereq_on_tile = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { - if (cfg->wonder_prereqs[i] != NULL) { - free ((void *)cfg->wonder_prereqs[i]); - cfg->wonder_prereqs[i] = NULL; - } - } - cfg->wonder_prereq_count = 0; - - for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { - if (cfg->natural_wonder_prereqs[i] != NULL) { - free ((void *)cfg->natural_wonder_prereqs[i]); - cfg->natural_wonder_prereqs[i] = NULL; - } - } - cfg->natural_wonder_prereq_count = 0; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { - if (cfg->buildable_on_districts[i] != NULL) { - free ((void *)cfg->buildable_on_districts[i]); - cfg->buildable_on_districts[i] = NULL; - } - } - cfg->buildable_on_district_count = 0; - cfg->buildable_on_district_id_count = 0; - cfg->has_buildable_on_districts = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { - if (cfg->buildable_adjacent_to_districts[i] != NULL) { - free ((void *)cfg->buildable_adjacent_to_districts[i]); - cfg->buildable_adjacent_to_districts[i] = NULL; - } - } - cfg->buildable_adjacent_to_district_count = 0; - cfg->buildable_adjacent_to_district_id_count = 0; - cfg->has_buildable_adjacent_to = false; - cfg->has_buildable_adjacent_to_districts = false; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - if (cfg->buildable_by_civs[i] != NULL) { - free ((void *)cfg->buildable_by_civs[i]); - cfg->buildable_by_civs[i] = NULL; - } - } - cfg->buildable_by_civ_count = 0; - cfg->has_buildable_by_civs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) - cfg->buildable_by_civ_traits_ids[i] = -1; - cfg->buildable_by_civ_traits_id_count = 0; - cfg->has_buildable_by_civ_traits = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) - cfg->buildable_by_civ_govs_ids[i] = -1; - cfg->buildable_by_civ_govs_id_count = 0; - cfg->has_buildable_by_civ_govs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) - cfg->buildable_by_civ_cultures_ids[i] = -1; - cfg->buildable_by_civ_cultures_id_count = 0; - cfg->has_buildable_by_civ_cultures = false; - - for (int i = 0; i < 5; i++) { - if (cfg->dependent_improvements[i] != NULL) { - free ((void *)cfg->dependent_improvements[i]); - cfg->dependent_improvements[i] = NULL; - } - } - - for (int i = 0; i < 10; i++) { - if (cfg->img_paths[i] != NULL) { - free ((void *)cfg->img_paths[i]); - cfg->img_paths[i] = NULL; - } - } - - free_bonus_entry_list (&cfg->culture_bonus_extras); - free_bonus_entry_list (&cfg->science_bonus_extras); - free_bonus_entry_list (&cfg->food_bonus_extras); - free_bonus_entry_list (&cfg->gold_bonus_extras); - free_bonus_entry_list (&cfg->shield_bonus_extras); - free_bonus_entry_list (&cfg->happiness_bonus_extras); - free_bonus_entry_list (&cfg->defense_bonus_extras); - - memset (cfg, 0, sizeof *cfg); -} - -void -free_dynamic_wonder_config (struct wonder_district_config * cfg) -{ - if (cfg == NULL) - return; - - if (! cfg->is_dynamic) - return; - - if (cfg->wonder_name != NULL) { - free ((void *)cfg->wonder_name); - cfg->wonder_name = NULL; - } - - if (cfg->img_path != NULL) { - free ((void *)cfg->img_path); - cfg->img_path = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - if (cfg->buildable_by_civs[i] != NULL) { - free ((void *)cfg->buildable_by_civs[i]); - cfg->buildable_by_civs[i] = NULL; - } - } - cfg->buildable_by_civ_count = 0; - cfg->has_buildable_by_civs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) - cfg->buildable_by_civ_traits_ids[i] = -1; - cfg->buildable_by_civ_traits_id_count = 0; - cfg->has_buildable_by_civ_traits = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) - cfg->buildable_by_civ_govs_ids[i] = -1; - cfg->buildable_by_civ_govs_id_count = 0; - cfg->has_buildable_by_civ_govs = false; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) - cfg->buildable_by_civ_cultures_ids[i] = -1; - cfg->buildable_by_civ_cultures_id_count = 0; - cfg->has_buildable_by_civ_cultures = false; - - memset (cfg, 0, sizeof *cfg); -} - -void -free_dynamic_natural_wonder_config (struct natural_wonder_district_config * cfg) -{ - if (cfg == NULL) - return; - - if (! cfg->is_dynamic) - return; - - if (cfg->name != NULL) { - free ((void *)cfg->name); - cfg->name = NULL; - } - - if (cfg->img_path != NULL) { - free ((void *)cfg->img_path); - cfg->img_path = NULL; - } - - memset (cfg, 0, sizeof *cfg); - cfg->adjacent_to = (enum SquareTypes)SQ_INVALID; - cfg->adjacency_dir = DIR_ZERO; -} - -enum Unit_Command_Values -allocate_dynamic_district_command (char const * name) -{ - int offset = is->next_custom_dynamic_command_index; - is->next_custom_dynamic_command_index += 1; - int value = C3X_DISTRICT_COMMAND_BASE - (offset + 1); - return (enum Unit_Command_Values)value; -} - -void -free_special_district_override_strings (struct district_config * cfg, struct district_config const * defaults) -{ - if (cfg == NULL || defaults == NULL) - return; - - if ((cfg->display_name != NULL) && - (cfg->display_name != cfg->name) && - (cfg->display_name != defaults->display_name)) { - free ((void *)cfg->display_name); - cfg->display_name = NULL; - } - if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) { - free ((void *)cfg->tooltip); - cfg->tooltip = NULL; - } - for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { - char const * default_value = (defaults != NULL && i < defaults->advance_prereq_count) - ? defaults->advance_prereqs[i] - : NULL; - if ((cfg->advance_prereqs[i] != NULL) && - (cfg->advance_prereqs[i] != default_value)) { - free ((void *)cfg->advance_prereqs[i]); - } - cfg->advance_prereqs[i] = NULL; - } - cfg->advance_prereq_count = 0; - if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) { - free ((void *)cfg->obsoleted_by); - cfg->obsoleted_by = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { - char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; - if ((cfg->resource_prereqs[i] != NULL) && - (cfg->resource_prereqs[i] != default_value)) - free ((void *)cfg->resource_prereqs[i]); - cfg->resource_prereqs[i] = NULL; - } - cfg->resource_prereq_count = defaults->resource_prereq_count; - - if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) { - free ((void *)cfg->resource_prereq_on_tile); - cfg->resource_prereq_on_tile = NULL; - } - - for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { - char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; - if ((cfg->wonder_prereqs[i] != NULL) && - (cfg->wonder_prereqs[i] != default_value)) - free ((void *)cfg->wonder_prereqs[i]); - cfg->wonder_prereqs[i] = NULL; - } - cfg->wonder_prereq_count = defaults->wonder_prereq_count; - - for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { - char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; - if ((cfg->natural_wonder_prereqs[i] != NULL) && - (cfg->natural_wonder_prereqs[i] != default_value)) - free ((void *)cfg->natural_wonder_prereqs[i]); - cfg->natural_wonder_prereqs[i] = NULL; - } - cfg->natural_wonder_prereq_count = defaults->natural_wonder_prereq_count; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { - char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; - if ((cfg->buildable_on_districts[i] != NULL) && - (cfg->buildable_on_districts[i] != default_value)) { - free ((void *)cfg->buildable_on_districts[i]); - } - cfg->buildable_on_districts[i] = NULL; - } - cfg->buildable_on_district_count = defaults->buildable_on_district_count; - cfg->buildable_on_district_id_count = defaults->buildable_on_district_id_count; - cfg->has_buildable_on_districts = defaults->has_buildable_on_districts; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { - char const * default_value = (i < defaults->buildable_adjacent_to_district_count) - ? defaults->buildable_adjacent_to_districts[i] - : NULL; - if ((cfg->buildable_adjacent_to_districts[i] != NULL) && - (cfg->buildable_adjacent_to_districts[i] != default_value)) { - free ((void *)cfg->buildable_adjacent_to_districts[i]); - } - cfg->buildable_adjacent_to_districts[i] = NULL; - } - cfg->buildable_adjacent_to_district_count = defaults->buildable_adjacent_to_district_count; - cfg->buildable_adjacent_to_district_id_count = defaults->buildable_adjacent_to_district_id_count; - cfg->has_buildable_adjacent_to = defaults->has_buildable_adjacent_to; - cfg->has_buildable_adjacent_to_districts = defaults->has_buildable_adjacent_to_districts; - - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; - if ((cfg->buildable_by_civs[i] != NULL) && - (cfg->buildable_by_civs[i] != default_value)) { - free ((void *)cfg->buildable_by_civs[i]); - } - cfg->buildable_by_civs[i] = NULL; - } - cfg->buildable_by_civ_count = defaults->buildable_by_civ_count; - cfg->has_buildable_by_civs = defaults->has_buildable_by_civs; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) - cfg->buildable_by_civ_traits_ids[i] = -1; - cfg->buildable_by_civ_traits_id_count = defaults->buildable_by_civ_traits_id_count; - cfg->has_buildable_by_civ_traits = defaults->has_buildable_by_civ_traits; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) - cfg->buildable_by_civ_govs_ids[i] = -1; - cfg->buildable_by_civ_govs_id_count = defaults->buildable_by_civ_govs_id_count; - cfg->has_buildable_by_civ_govs = defaults->has_buildable_by_civ_govs; - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) - cfg->buildable_by_civ_cultures_ids[i] = -1; - cfg->buildable_by_civ_cultures_id_count = defaults->buildable_by_civ_cultures_id_count; - cfg->has_buildable_by_civ_cultures = defaults->has_buildable_by_civ_cultures; - cfg->buildable_by_war_allies = defaults->buildable_by_war_allies; - cfg->buildable_by_pact_allies = defaults->buildable_by_pact_allies; - - for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { - char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; - if ((cfg->dependent_improvements[i] != NULL) && - (cfg->dependent_improvements[i] != default_value)) { - free ((void *)cfg->dependent_improvements[i]); - } - cfg->dependent_improvements[i] = NULL; - } - cfg->dependent_improvement_max_index = defaults->dependent_improvement_max_index; - - for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { - char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; - if ((cfg->img_paths[i] != NULL) && - (cfg->img_paths[i] != default_value)) { - free ((void *)cfg->img_paths[i]); - } - cfg->img_paths[i] = NULL; - } - cfg->img_path_count = defaults->img_path_count; - - free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); - free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); - free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); - free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); - free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); - free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); - free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); -} - -void -reset_regular_district_configs (void) -{ - for (int i = USED_SPECIAL_DISTRICT_TYPES; i < COUNT_DISTRICT_TYPES; i++) { - if (is->district_configs[i].is_dynamic) - free_dynamic_district_config (&is->district_configs[i]); - } - - for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) - free_special_district_override_strings (&is->district_configs[i], &special_district_defaults[i]); - - memset (is->district_configs, 0, sizeof is->district_configs); - for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) - is->district_configs[i] = special_district_defaults[i]; - - is->special_district_count = USED_SPECIAL_DISTRICT_TYPES; - is->dynamic_district_count = 0; - is->district_count = is->special_district_count; - is->next_custom_dynamic_command_index = 0; -} - -void -reset_wonder_district_configs (void) -{ - for (int i = 0; i < MAX_WONDER_DISTRICT_TYPES; i++) { - if (is->wonder_district_configs[i].is_dynamic) - free_dynamic_wonder_config (&is->wonder_district_configs[i]); - } - - memset (is->wonder_district_configs, 0, sizeof is->wonder_district_configs); - is->wonder_district_count = 0; -} - -void -reset_natural_wonder_configs (void) -{ - for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { - if (is->natural_wonder_configs[i].is_dynamic) - free_dynamic_natural_wonder_config (&is->natural_wonder_configs[i]); - } - - memset (is->natural_wonder_configs, 0, sizeof is->natural_wonder_configs); - for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { - is->natural_wonder_configs[i].adjacent_to = (enum SquareTypes)SQ_INVALID; - is->natural_wonder_configs[i].adjacency_dir = DIR_ZERO; - } - for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) - is->natural_wonder_img_sets[i].img.vtable = NULL; - stable_deinit (&is->natural_wonder_name_to_id); - is->natural_wonder_count = 0; -} - -void -clear_dynamic_district_definitions (void) -{ - reset_regular_district_configs (); - reset_wonder_district_configs (); - reset_natural_wonder_configs (); - reset_ai_candidate_bridge_or_canals (); -} - -void -init_parsed_district_definition (struct parsed_district_definition * def) -{ - memset (def, 0, sizeof *def); - def->img_path_count = -1; - def->defense_bonus_percent = 0; - def->render_strategy = DRS_BY_COUNT; - def->ai_build_strategy = DABS_DISTRICT; - def->buildable_square_types_mask = district_default_buildable_mask (); - def->buildable_adjacent_to_square_types_mask = 0; - def->buildable_without_removal_mask = 0; - def->buildable_on_overlays_mask = 0; - def->buildable_adjacent_to_overlays_mask = 0; - def->buildable_on_rivers = false; - def->buildable_adjacent_to_allows_city = false; -} - -void -free_parsed_district_definition (struct parsed_district_definition * def) -{ - if (def == NULL) - return; - - if (def->display_name != NULL) { - free (def->display_name); - def->display_name = NULL; - } - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - if (def->tooltip != NULL) { - free (def->tooltip); - def->tooltip = NULL; - } - for (int i = 0; i < def->advance_prereq_count; i++) { - if (def->advance_prereqs[i] != NULL) { - free (def->advance_prereqs[i]); - def->advance_prereqs[i] = NULL; - } - } - def->advance_prereq_count = 0; - for (int i = 0; i < ARRAY_LEN (def->buildable_on_districts); i++) { - if (def->buildable_on_districts[i] != NULL) { - free (def->buildable_on_districts[i]); - def->buildable_on_districts[i] = NULL; - } - } - for (int i = 0; i < ARRAY_LEN (def->buildable_adjacent_to_districts); i++) { - if (def->buildable_adjacent_to_districts[i] != NULL) { - free (def->buildable_adjacent_to_districts[i]); - def->buildable_adjacent_to_districts[i] = NULL; - } - } - if (def->obsoleted_by != NULL) { - free (def->obsoleted_by); - def->obsoleted_by = NULL; - } - - for (int i = 0; i < def->resource_prereq_count; i++) { - if (def->resource_prereqs[i] != NULL) { - free (def->resource_prereqs[i]); - def->resource_prereqs[i] = NULL; - } - } - def->resource_prereq_count = 0; - - if (def->resource_prereq_on_tile != NULL) { - free (def->resource_prereq_on_tile); - def->resource_prereq_on_tile = NULL; - } - - for (int i = 0; i < def->wonder_prereq_count; i++) { - if (def->wonder_prereqs[i] != NULL) { - free (def->wonder_prereqs[i]); - def->wonder_prereqs[i] = NULL; - } - } - def->wonder_prereq_count = 0; - - for (int i = 0; i < def->natural_wonder_prereq_count; i++) { - if (def->natural_wonder_prereqs[i] != NULL) { - free (def->natural_wonder_prereqs[i]); - def->natural_wonder_prereqs[i] = NULL; - } - } - def->natural_wonder_prereq_count = 0; - def->buildable_adjacent_to_district_count = 0; - - for (int i = 0; i < def->buildable_by_civ_count; i++) { - if (def->buildable_by_civs[i] != NULL) { - free (def->buildable_by_civs[i]); - def->buildable_by_civs[i] = NULL; - } - } - def->buildable_by_civ_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - - for (int i = 0; i < def->dependent_improvement_max_index; i++) { - if (def->dependent_improvements[i] != NULL) { - free (def->dependent_improvements[i]); - def->dependent_improvements[i] = NULL; - } - } - def->dependent_improvement_max_index = 0; - - for (int i = 0; i < def->img_path_count; i++) { - if (def->img_paths[i] != NULL) { - free (def->img_paths[i]); - def->img_paths[i] = NULL; - } - } - def->img_path_count = 0; - - if (def->generated_resource != NULL) { - free (def->generated_resource); - def->generated_resource = NULL; - } - - free_bonus_entry_list (&def->culture_bonus_extras); - free_bonus_entry_list (&def->science_bonus_extras); - free_bonus_entry_list (&def->food_bonus_extras); - free_bonus_entry_list (&def->gold_bonus_extras); - free_bonus_entry_list (&def->shield_bonus_extras); - free_bonus_entry_list (&def->happiness_bonus_extras); - free_bonus_entry_list (&def->defense_bonus_extras); - - init_parsed_district_definition (def); -} - -int -find_special_district_index_by_name (char const * name) -{ - if (name == NULL) - return -1; - - for (int i = 0; i < is->special_district_count; i++) { - if ((is->district_configs[i].name != NULL) && - (strcmp (is->district_configs[i].name, name) == 0)) - return i; - } - return -1; -} - - -// --------------------------------------------------------------- -// Unit counter system -// --------------------------------------------------------------- - -bool -read_counter_rule_terrain_mask (struct string_slice const * terrain_name, unsigned int * out_mask) -{ - if ((terrain_name == NULL) || (out_mask == NULL)) - return false; - - struct string_slice trimmed = trim_string_slice (terrain_name, 1); - if (trimmed.len <= 0) - return false; - - if (slice_matches_str (&trimmed, "lake") || slice_matches_str (&trimmed, "lakes")) { - *out_mask = district_buildable_lake_mask_bit (); - return true; - } - - enum SquareTypes parsed; - if (! read_tile_terrain_type_value (&trimmed, &parsed)) - return false; - - if (parsed == (enum SquareTypes)SQ_INVALID) - *out_mask = all_square_types_mask () | district_buildable_lake_mask_bit (); - else - *out_mask = square_type_mask_bit (parsed); - - return *out_mask != 0; -} - -struct unit_counter_group * -find_unit_counter_group_by_name (struct c3x_config * cfg, char const * name) -{ - for (int i = 0; i < cfg->count_unit_counter_groups; i++) { - struct unit_counter_group * g = &cfg->unit_counter_groups[i]; - if (g->name && strcmp (g->name, name) == 0) - return g; - } - return NULL; -} - -bool -unit_type_in_group (struct unit_counter_group * g, int type_id) -{ - char const * name = p_bic_data->UnitTypes[type_id].Name; - for (int i = 0; i < g->count_type_ids; i++) - if (strcmp (p_bic_data->UnitTypes[g->type_ids[i]].Name, name) == 0) - return true; - return false; -} - -bool -unit_matches_counter_side (struct c3x_config * cfg, int type_id, - int match, char * group_name) -{ - if (match == UCM_ANY) - return true; - if (match == UCM_GROUP) { - struct unit_counter_group * g = - find_unit_counter_group_by_name (cfg, group_name); - return g && unit_type_in_group (g, type_id); - } - // Direct unit type match: compare by name rather than exact ID so that - // AI strategy duplicates (same name, different ID) are also matched. - return strcmp (p_bic_data->UnitTypes[match].Name, - p_bic_data->UnitTypes[type_id].Name) == 0; -} - -enum recognizable_parse_result -parse_unit_counter_group (char ** p_cursor, - struct error_line ** p_unrecognized_lines, - void * out_group) -{ - char * cur = *p_cursor; - struct string_slice group_name; - if (! (parse_string (&cur, &group_name) && skip_punctuation (&cur, ':'))) - return RPR_PARSE_ERROR; - - struct unit_counter_group * g = out_group; - g->name = extract_slice (&group_name); - g->type_ids = NULL; - g->count_type_ids = 0; - - int any_unrecognized = 0; - struct string_slice type_name; - while (parse_string (&cur, &type_name)) { - // Loop through all unit types with this name, including AI strategy - // duplicates (same name, different ID), which the game creates internally. - int type_id = 0; - bool found_any = false; - while (find_unit_type_id_by_name (&type_name, type_id, &type_id)) { - g->type_ids = realloc (g->type_ids, - (g->count_type_ids + 1) * sizeof (int)); - g->type_ids[g->count_type_ids++] = type_id; - found_any = true; - type_id++; // continue search from next index - } - if (! found_any) { - add_unrecognized_line (p_unrecognized_lines, &type_name); - any_unrecognized = 1; - } - if (! skip_punctuation (&cur, ',')) - break; - } - *p_cursor = cur; - return any_unrecognized ? RPR_UNRECOGNIZED : RPR_OK; -} - -enum recognizable_parse_result -parse_counter_rule (char ** p_cursor, - struct error_line ** p_unrecognized_lines, - void * out_rule) -{ - char * cur = *p_cursor; - struct string_slice attacker_name, vs_token, defender_name; - - if (! parse_string (&cur, &attacker_name)) - return RPR_PARSE_ERROR; - if (! (parse_string (&cur, &vs_token) && - slice_matches_str (&vs_token, "vs"))) - return RPR_PARSE_ERROR; - if (! parse_string (&cur, &defender_name)) - return RPR_PARSE_ERROR; - - struct counter_rule * r = out_rule; - *r = (struct counter_rule) { - .attacker_match = UCM_ANY, - .defender_match = UCM_ANY, - .terrain_mask = 0, - .district_id = -1, - .district_name = NULL, - .self_atk_pct = 100, - .self_def_pct = 100, - .enemy_atk_pct = 100, - .enemy_def_pct = 100, - }; - - if (! slice_matches_str (&attacker_name, "*")) { - int type_id; - if (find_unit_type_id_by_name (&attacker_name, 0, &type_id)) - r->attacker_match = type_id; - else { - r->attacker_match = UCM_GROUP; - r->attacker_group = extract_slice (&attacker_name); - } - } - - if (! slice_matches_str (&defender_name, "*")) { - int type_id; - if (find_unit_type_id_by_name (&defender_name, 0, &type_id)) - r->defender_match = type_id; - else { - r->defender_match = UCM_GROUP; - r->defender_group = extract_slice (&defender_name); - } - } - - struct string_slice token; - while (parse_string (&cur, &token)) { - if (slice_matches_str (&token, "in-city")) { - r->only_in_city = true; - } else if (slice_matches_str (&token, "ignore-terrain")) { - r->ignore_terrain = true; - } else if (slice_matches_str (&token, "self-atk")) { - if (! parse_int (&cur, &r->self_atk_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "self-def")) { - if (! parse_int (&cur, &r->self_def_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "enemy-atk")) { - if (! parse_int (&cur, &r->enemy_atk_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "enemy-def")) { - if (! parse_int (&cur, &r->enemy_def_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "terrain")) { - struct string_slice terrain_name; - if (! parse_string (&cur, &terrain_name)) - return RPR_PARSE_ERROR; - if (! read_counter_rule_terrain_mask (&terrain_name, &r->terrain_mask)) { - add_unrecognized_line (p_unrecognized_lines, &terrain_name); - return RPR_UNRECOGNIZED; - } - } else if (slice_matches_str (&token, "district")) { - struct string_slice district_name; - if (! parse_string (&cur, &district_name)) - return RPR_PARSE_ERROR; - free (r->district_name); - r->district_name = extract_slice (&district_name); - r->district_id = -1; - } else { - break; - } - } - - *p_cursor = cur; - return RPR_OK; -} - -void -apply_counter_rules (struct c3x_config * cfg, - Unit * attacker, Unit * defender, Tile * def_tile, - int * out_attacker_atk, int * out_defender_def, - bool * out_ignore_terrain) -{ - int a_type = attacker->Body.UnitTypeID; - int d_type = defender->Body.UnitTypeID; - bool in_city = Tile_has_city (def_tile); - - int aa = 100, dd = 100; - bool ignore = false; - - for (int i = 0; i < cfg->count_counter_rules; i++) { - struct counter_rule * r = &cfg->counter_rules[i]; - - // Check forward match (attacker=rule attacker side, defender=rule defender side) - // Applied fields: self-atk (attacker attack), enemy-def (defender defense) - bool forward = unit_matches_counter_side (cfg, a_type, - r->attacker_match, r->attacker_group) && - unit_matches_counter_side (cfg, d_type, - r->defender_match, r->defender_group); - - // Check reverse match (attacker=rule defender side, defender=rule attacker side) - // Applied fields: self-def (rule attacker side is now defending), enemy-atk (rule defender side is now attacking) - bool reverse = unit_matches_counter_side (cfg, a_type, - r->defender_match, r->defender_group) && - unit_matches_counter_side (cfg, d_type, - r->attacker_match, r->attacker_group); - - if (! forward && ! reverse) - continue; - - // Environment checks are based on the defender's tile - if (r->only_in_city && ! in_city) - continue; - if (r->terrain_mask != 0 && - ! tile_matches_square_type_mask (def_tile, r->terrain_mask)) - continue; - if (r->district_name != NULL && - ! ((r->district_id != -1) && - cfg->enable_districts && - district_is_complete (def_tile, r->district_id))) - continue; - - if (forward) { - aa = aa * r->self_atk_pct / 100; // self-atk: attacker attack - dd = dd * r->enemy_def_pct / 100; // enemy-def: defender defense - } - if (reverse) { - aa = aa * r->enemy_atk_pct / 100; // enemy-atk: rule defender side now acts as attacker - dd = dd * r->self_def_pct / 100; // self-def: rule attacker side now acts as defender - } - if (forward || reverse) - ignore = ignore || r->ignore_terrain; - } - - *out_attacker_atk = aa; - *out_defender_def = dd; - *out_ignore_terrain = ignore; -} - -bool -district_is_included_by_final_config (int district_id) -{ - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - if (! is->current_config.enable_districts) - return false; - - switch (district_id) { - case NEIGHBORHOOD_DISTRICT_ID: return is->current_config.enable_neighborhood_districts; - case WONDER_DISTRICT_ID: return is->current_config.enable_wonder_districts; - case DISTRIBUTION_HUB_DISTRICT_ID: return is->current_config.enable_distribution_hub_districts; - case AERODROME_DISTRICT_ID: return is->current_config.enable_aerodrome_districts; - case PORT_DISTRICT_ID: return is->current_config.enable_port_districts; - case CENTRAL_RAIL_HUB_DISTRICT_ID: return is->current_config.enable_central_rail_hub_districts; - case ENERGY_GRID_DISTRICT_ID: return is->current_config.enable_energy_grid_districts; - case BRIDGE_DISTRICT_ID: return is->current_config.enable_bridge_districts; - case CANAL_DISTRICT_ID: return is->current_config.enable_canal_districts; - case GREAT_WALL_DISTRICT_ID: return is->current_config.enable_great_wall_districts; - default: return true; - } -} - -bool -ensure_culture_variant_art (struct district_config * cfg, int section_start_line) -{ - if ((cfg == NULL) || (! cfg->vary_img_by_culture)) - return true; - - const int required_variants = 5; - const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); - if (cfg->img_path_count <= 0) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] load_dynamic_district_configs: district \"%s\" requires culture-specific art but none provided (line %d)\n", cfg->name, section_start_line); - (*p_OutputDebugStringA) (ss); - return false; - } - - while ((cfg->img_path_count < required_variants) && - (cfg->img_path_count < max_img_paths)) { - cfg->img_paths[cfg->img_path_count] = strdup (cfg->img_paths[0]); - cfg->img_path_count += 1; - } - - return true; -} - -bool -parse_config_string_list (char * value_text, - char ** dest, - int capacity, - int * out_count, - struct error_line ** parse_errors, - int line_number, - char const * key) -{ - for (int i = 0; i < capacity; i++) { - if (dest[i] != NULL) { - free (dest[i]); - dest[i] = NULL; - } - } - *out_count = 0; - - if (value_text == NULL || *value_text == '\0') - return true; - - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - if (*cursor == '\0') - break; - - char * item_start; - char * item_end; - if (*cursor == '"') { - cursor++; - item_start = cursor; - while ((*cursor != '\0') && (*cursor != '"')) - cursor++; - if (*cursor != '"') { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (missing closing quote)", line_number, key); - err->text[(sizeof err->text) - 1] = '\0'; - for (int j = 0; j < capacity; j++) { - if (dest[j] != NULL) { - free (dest[j]); - dest[j] = NULL; - } - } - *out_count = 0; - return false; - } - item_end = cursor; - cursor++; - } else { - item_start = cursor; - while ((*cursor != '\0') && (*cursor != ',')) - cursor++; - item_end = cursor; - } - - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - - int item_len = item_end - item_start; - if (item_len > 0) { - if (*out_count < capacity) { - char * copy = malloc (item_len + 1); - if (copy == NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (out of memory)", line_number, key); - err->text[(sizeof err->text) - 1] = '\0'; - for (int j = 0; j < capacity; j++) { - if (dest[j] != NULL) { - free (dest[j]); - dest[j] = NULL; - } - } - *out_count = 0; - return false; - } - memcpy (copy, item_start, item_len); - copy[item_len] = '\0'; - dest[*out_count] = copy; - *out_count += 1; - } - } - - while (is_space_char (*cursor)) - cursor++; - - if (*cursor == ',') { - cursor++; - continue; - } - if (*cursor == '\0') - break; - } - - return true; -} - -bool -parse_buildable_square_type_mask (struct string_slice const * value, - unsigned int * out_mask, - struct error_line ** parse_errors, - int line_number, - char const * key_name, - bool * out_allow_city) -{ - char * value_text = trim_and_extract_slice (value, 0); - unsigned int mask = 0; - int entry_count = 0; - bool allow_city = false; - bool allow_city_token = (key_name != NULL) && (strcmp (key_name, "buildable_adjacent_to") == 0); - if (key_name == NULL) - key_name = "buildable_on"; - - if (value_text != NULL) { - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - char * item_start = cursor; - while ((*cursor != '\0') && (*cursor != ',')) - cursor++; - - char * item_end = cursor; - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - - struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; - if (item_slice.len > 0) { - if (slice_matches_str (&item_slice, "city")) { - if (! allow_city_token) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - allow_city = true; - entry_count += 1; - } else if (slice_matches_str (&item_slice, "lake")) { - mask |= district_buildable_lake_mask_bit (); - entry_count += 1; - } else { - enum SquareTypes parsed; - if (read_tile_terrain_type_value (&item_slice, &parsed)) { - if ((parsed == SQ_RIVER) || - (parsed == SQ_Forest) || - (parsed == SQ_Jungle) || - (parsed == SQ_Swamp)) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - if (parsed == (enum SquareTypes)SQ_INVALID) { - mask = all_square_types_mask (); - mask &= ~(square_type_mask_bit (SQ_Forest) | - square_type_mask_bit (SQ_Jungle) | - square_type_mask_bit (SQ_Swamp)); - } else - mask |= square_type_mask_bit (parsed); - entry_count += 1; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - } - } - - if (*cursor == ',') { - cursor++; - continue; - } - break; - } - } - - if (value_text != NULL) - free (value_text); - - if ((entry_count == 0) || ((mask == 0) && ! allow_city)) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one tile terrain type)", line_number, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - return false; - } - - *out_mask = mask; - if (out_allow_city != NULL) - *out_allow_city = allow_city; - return true; -} - -bool -parse_buildable_overlay_mask (struct string_slice const * value, - unsigned int * out_mask, - struct error_line ** parse_errors, - int line_number, - char const * key_name) -{ - char * value_text = trim_and_extract_slice (value, 0); - unsigned int mask = 0; - unsigned int allowed_mask = (DOM_MINE | DOM_IRRIGATION | DOM_FORTRESS | DOM_BARRICADE | - DOM_OUTPOST | DOM_RADAR_TOWER | DOM_JUNGLE | DOM_FOREST | - DOM_SWAMP | DOM_RIVER | DOM_AIRFIELD); - int entry_count = 0; - - if (key_name == NULL) - key_name = "buildable_without_removal"; - if (strcmp (key_name, "buildable_without_removal") == 0) - allowed_mask = (DOM_JUNGLE | DOM_FOREST | DOM_SWAMP); - else if (strcmp (key_name, "buildable_on_overlays") == 0) - allowed_mask &= ~DOM_RIVER; - - if (value_text != NULL) { - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - char * item_start = cursor; - while ((*cursor != '\0') && (*cursor != ',')) - cursor++; - - char * item_end = cursor; - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - - struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; - if (item_slice.len > 0) { - unsigned int bit = 0; - if (slice_matches_str (&item_slice, "mine")) { - bit = DOM_MINE; - } else if (slice_matches_str (&item_slice, "irrigation")) { - bit = DOM_IRRIGATION; - } else if (slice_matches_str (&item_slice, "fortress")) { - bit = DOM_FORTRESS; - } else if (slice_matches_str (&item_slice, "barricade")) { - bit = DOM_BARRICADE; - } else if (slice_matches_str (&item_slice, "outpost")) { - bit = DOM_OUTPOST; - } else if (slice_matches_str (&item_slice, "radar-tower")) { - bit = DOM_RADAR_TOWER; - } else if (slice_matches_str (&item_slice, "airfield")) { - bit = DOM_AIRFIELD; - } else if (slice_matches_str (&item_slice, "jungle")) { - bit = DOM_JUNGLE; - } else if (slice_matches_str (&item_slice, "jungles")) { - bit = DOM_JUNGLE; - } else if (slice_matches_str (&item_slice, "forest")) { - bit = DOM_FOREST; - } else if (slice_matches_str (&item_slice, "forests")) { - bit = DOM_FOREST; - } else if (slice_matches_str (&item_slice, "marsh")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "marshes")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "swamp")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "swamps")) { - bit = DOM_SWAMP; - } else if (slice_matches_str (&item_slice, "river")) { - bit = DOM_RIVER; - } else if (slice_matches_str (&item_slice, "rivers")) { - bit = DOM_RIVER; - } - - if (bit != 0) { - if ((allowed_mask & bit) == 0) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - mask |= bit; - entry_count += 1; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - free (value_text); - return false; - } - } - - if (*cursor == ',') { - cursor++; - continue; - } - break; - } - } - - if (value_text != NULL) - free (value_text); - - if ((entry_count == 0) || (mask == 0)) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one overlay)", line_number, key_name); - err->text[(sizeof err->text) - 1] = '\0'; - return false; - } - - *out_mask = mask; - return true; -} - -bool -parse_district_bonus_entries (struct string_slice const * value, - int * out_base_bonus, - struct district_bonus_list * out_extras, - struct error_line ** parse_errors, - int line_number, - struct string_slice const * key) -{ - if ((out_base_bonus == NULL) || (out_extras == NULL)) { - add_key_parse_error (parse_errors, line_number, key, value, "(invalid bonus target)"); - return false; - } - - char * value_text = trim_and_extract_slice (value, 0); - free_bonus_entry_list (out_extras); - *out_base_bonus = 0; - - if ((value_text == NULL) || (*value_text == '\0')) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); - free (value_text); - return false; - } - - bool got_base = false; - int base_bonus = 0; - - char * cursor = value_text; - while (1) { - while (is_space_char (*cursor)) - cursor++; - - if (*cursor == '\0') - break; - - char * item_start = cursor; - bool in_quotes = false; - while (*cursor != '\0') { - if (*cursor == '"') - in_quotes = ! in_quotes; - if ((! in_quotes) && (*cursor == ',')) - break; - cursor++; - } - - char * item_end = cursor; - while ((item_end > item_start) && is_space_char (item_end[-1])) - item_end--; - while ((item_start < item_end) && is_space_char (*item_start)) - item_start++; - - if (item_end > item_start) { - struct string_slice item = { .str = item_start, .len = (int)(item_end - item_start) }; - - if (! got_base) { - struct string_slice base_slice = trim_string_slice (&item, 0); - if (! read_int (&base_slice, &base_bonus)) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - got_base = true; - } else { - char * colon = NULL; - in_quotes = false; - for (char * p = item_start; p < item_end; p++) { - if (*p == '"') - in_quotes = ! in_quotes; - if ((! in_quotes) && (*p == ':')) { - colon = p; - break; - } - } - - if (colon == NULL) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected \"name: bonus\" entry)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - struct string_slice name_slice = { .str = item_start, .len = (int)(colon - item_start) }; - struct string_slice bonus_slice = { .str = colon + 1, .len = (int)(item_end - (colon + 1)) }; - struct string_slice trimmed_name = trim_string_slice (&name_slice, 1); - struct string_slice trimmed_bonus = trim_string_slice (&bonus_slice, 0); - - if (trimmed_name.len <= 0) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus name)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - int bonus_value = 0; - if (! read_int (&trimmed_bonus, &bonus_value)) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus value)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - if (out_extras->count >= MAX_DISTRICT_BONUS_ENTRIES) { - add_key_parse_error (parse_errors, line_number, key, value, "(too many bonus entries)"); - free_bonus_entry_list (out_extras); - free (value_text); - return false; - } - - struct district_bonus_entry * entry = &out_extras->entries[out_extras->count++]; - entry->bonus = bonus_value; - entry->building_id = -1; - entry->building_name = NULL; - - enum SquareTypes parsed_type; - if (read_tile_terrain_type_value (&trimmed_name, &parsed_type)) { - entry->type = DBET_TILE; - entry->tile_type = parsed_type; - } else { - entry->type = DBET_BUILDING; - entry->tile_type = (enum SquareTypes)SQ_INVALID; - entry->building_name = extract_slice (&trimmed_name); - } - } - } - - if (*cursor == ',') { - cursor++; - continue; - } - if (*cursor == '\0') - break; - } - - free (value_text); - - if (! got_base) { - add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); - free_bonus_entry_list (out_extras); - return false; - } - - *out_base_bonus = base_bonus; - return true; -} - -bool -override_special_district_from_definition (struct parsed_district_definition * def, int section_start_line) -{ - if ((! def->has_name) || (def->name == NULL)) - return false; - - int index = find_special_district_index_by_name (def->name); - if (index < 0) - return false; - - struct district_config * cfg = &is->district_configs[index]; - struct district_config const * defaults = &special_district_defaults[index]; - - free (def->name); - def->name = NULL; - def->has_name = false; - - if (def->has_display_name) { - if ((cfg->display_name != NULL) && - (cfg->display_name != cfg->name) && - (cfg->display_name != defaults->display_name)) - free ((void *)cfg->display_name); - cfg->display_name = def->display_name; - def->display_name = NULL; - } - - if (def->has_tooltip) { - if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) - free ((void *)cfg->tooltip); - cfg->tooltip = def->tooltip; - def->tooltip = NULL; - } - - if (def->has_advance_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { - char const * default_value = (i < defaults->advance_prereq_count) ? defaults->advance_prereqs[i] : NULL; - if ((cfg->advance_prereqs[i] != NULL) && - (cfg->advance_prereqs[i] != default_value)) - free ((void *)cfg->advance_prereqs[i]); - cfg->advance_prereqs[i] = NULL; - } - - cfg->advance_prereq_count = def->advance_prereq_count; - const int max_entries = ARRAY_LEN (cfg->advance_prereqs); - if (cfg->advance_prereq_count > max_entries) - cfg->advance_prereq_count = max_entries; - for (int i = 0; i < cfg->advance_prereq_count; i++) { - cfg->advance_prereqs[i] = def->advance_prereqs[i]; - def->advance_prereqs[i] = NULL; - } - def->advance_prereq_count = 0; - } - - if (def->has_obsoleted_by) { - if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) - free ((void *)cfg->obsoleted_by); - cfg->obsoleted_by = def->obsoleted_by; - def->obsoleted_by = NULL; - } - - if (def->has_resource_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { - char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; - if ((cfg->resource_prereqs[i] != NULL) && - (cfg->resource_prereqs[i] != default_value)) - free ((void *)cfg->resource_prereqs[i]); - cfg->resource_prereqs[i] = NULL; - } - - cfg->resource_prereq_count = def->resource_prereq_count; - const int max_entries = ARRAY_LEN (cfg->resource_prereqs); - if (cfg->resource_prereq_count > max_entries) - cfg->resource_prereq_count = max_entries; - for (int i = 0; i < cfg->resource_prereq_count; i++) { - cfg->resource_prereqs[i] = def->resource_prereqs[i]; - def->resource_prereqs[i] = NULL; - } - } - - if (def->has_resource_prereq_on_tile) { - if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) - free ((void *)cfg->resource_prereq_on_tile); - cfg->resource_prereq_on_tile = def->resource_prereq_on_tile; - def->resource_prereq_on_tile = NULL; - } - - if (def->has_wonder_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { - char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; - if ((cfg->wonder_prereqs[i] != NULL) && - (cfg->wonder_prereqs[i] != default_value)) - free ((void *)cfg->wonder_prereqs[i]); - cfg->wonder_prereqs[i] = NULL; - } - - cfg->wonder_prereq_count = def->wonder_prereq_count; - const int max_entries = ARRAY_LEN (cfg->wonder_prereqs); - if (cfg->wonder_prereq_count > max_entries) - cfg->wonder_prereq_count = max_entries; - for (int i = 0; i < cfg->wonder_prereq_count; i++) { - cfg->wonder_prereqs[i] = def->wonder_prereqs[i]; - def->wonder_prereqs[i] = NULL; - } - } - - if (def->has_natural_wonder_prereqs) { - for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { - char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; - if ((cfg->natural_wonder_prereqs[i] != NULL) && - (cfg->natural_wonder_prereqs[i] != default_value)) - free ((void *)cfg->natural_wonder_prereqs[i]); - cfg->natural_wonder_prereqs[i] = NULL; - } - - cfg->natural_wonder_prereq_count = def->natural_wonder_prereq_count; - const int max_entries = ARRAY_LEN (cfg->natural_wonder_prereqs); - if (cfg->natural_wonder_prereq_count > max_entries) - cfg->natural_wonder_prereq_count = max_entries; - for (int i = 0; i < cfg->natural_wonder_prereq_count; i++) { - cfg->natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; - def->natural_wonder_prereqs[i] = NULL; - } - } - - if (def->has_buildable_on_districts) { - for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { - char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; - if ((cfg->buildable_on_districts[i] != NULL) && - (cfg->buildable_on_districts[i] != default_value)) - free ((void *)cfg->buildable_on_districts[i]); - cfg->buildable_on_districts[i] = NULL; - } - - cfg->buildable_on_district_count = def->buildable_on_district_count; - const int max_entries = ARRAY_LEN (cfg->buildable_on_districts); - if (cfg->buildable_on_district_count > max_entries) - cfg->buildable_on_district_count = max_entries; - for (int i = 0; i < cfg->buildable_on_district_count; i++) { - cfg->buildable_on_districts[i] = def->buildable_on_districts[i]; - def->buildable_on_districts[i] = NULL; - } - cfg->buildable_on_district_id_count = 0; - cfg->has_buildable_on_districts = true; - } - - if (def->has_buildable_adjacent_to_districts) { - for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { - char const * default_value = (i < defaults->buildable_adjacent_to_district_count) - ? defaults->buildable_adjacent_to_districts[i] - : NULL; - if ((cfg->buildable_adjacent_to_districts[i] != NULL) && - (cfg->buildable_adjacent_to_districts[i] != default_value)) - free ((void *)cfg->buildable_adjacent_to_districts[i]); - cfg->buildable_adjacent_to_districts[i] = NULL; - } - - cfg->buildable_adjacent_to_district_count = def->buildable_adjacent_to_district_count; - const int max_entries = ARRAY_LEN (cfg->buildable_adjacent_to_districts); - if (cfg->buildable_adjacent_to_district_count > max_entries) - cfg->buildable_adjacent_to_district_count = max_entries; - for (int i = 0; i < cfg->buildable_adjacent_to_district_count; i++) { - cfg->buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; - def->buildable_adjacent_to_districts[i] = NULL; - } - cfg->buildable_adjacent_to_district_id_count = 0; - cfg->has_buildable_adjacent_to_districts = true; - } - - if (def->has_buildable_by_civs) { - for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { - char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; - if ((cfg->buildable_by_civs[i] != NULL) && - (cfg->buildable_by_civs[i] != default_value)) - free ((void *)cfg->buildable_by_civs[i]); - cfg->buildable_by_civs[i] = NULL; - } - cfg->buildable_by_civ_count = def->buildable_by_civ_count; - const int max_civ_names = ARRAY_LEN (cfg->buildable_by_civs); - if (cfg->buildable_by_civ_count > max_civ_names) - cfg->buildable_by_civ_count = max_civ_names; - for (int i = 0; i < cfg->buildable_by_civ_count; i++) { - cfg->buildable_by_civs[i] = def->buildable_by_civs[i]; - def->buildable_by_civs[i] = NULL; - } - cfg->has_buildable_by_civs = true; - } - - if (def->has_buildable_by_civ_traits) { - cfg->buildable_by_civ_traits_id_count = def->buildable_by_civ_traits_id_count; - const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_traits_ids); - if (cfg->buildable_by_civ_traits_id_count > max_entries) - cfg->buildable_by_civ_traits_id_count = max_entries; - for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) - cfg->buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; - cfg->has_buildable_by_civ_traits = true; - } - - if (def->has_buildable_by_civ_govs) { - cfg->buildable_by_civ_govs_id_count = def->buildable_by_civ_govs_id_count; - const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_govs_ids); - if (cfg->buildable_by_civ_govs_id_count > max_entries) - cfg->buildable_by_civ_govs_id_count = max_entries; - for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) - cfg->buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; - cfg->has_buildable_by_civ_govs = true; - } - - if (def->has_buildable_by_civ_cultures) { - cfg->buildable_by_civ_cultures_id_count = def->buildable_by_civ_cultures_id_count; - const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); - if (cfg->buildable_by_civ_cultures_id_count > max_entries) - cfg->buildable_by_civ_cultures_id_count = max_entries; - for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) - cfg->buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; - cfg->has_buildable_by_civ_cultures = true; - } - - if (def->has_buildable_by_war_allies) - cfg->buildable_by_war_allies = def->buildable_by_war_allies; - if (def->has_buildable_by_pact_allies) - cfg->buildable_by_pact_allies = def->buildable_by_pact_allies; - - if (def->has_allow_multiple) - cfg->allow_multiple = def->allow_multiple; - if (def->has_vary_img_by_era) - cfg->vary_img_by_era = def->vary_img_by_era; - if (def->has_vary_img_by_culture) - cfg->vary_img_by_culture = def->vary_img_by_culture; - if (def->has_render_strategy) - cfg->render_strategy = def->render_strategy; - if (def->has_ai_build_strategy) - cfg->ai_build_strategy = def->ai_build_strategy; - if (def->has_align_to_coast) - cfg->align_to_coast = def->align_to_coast; - if (def->has_draw_over_resources) - cfg->draw_over_resources = def->draw_over_resources; - if (def->has_allow_irrigation_from) - cfg->allow_irrigation_from = def->allow_irrigation_from; - if (def->has_auto_add_road) - cfg->auto_add_road = def->auto_add_road; - if (def->has_auto_add_railroad) - cfg->auto_add_railroad = def->auto_add_railroad; - if (def->has_custom_width) - cfg->custom_width = def->custom_width; - if (def->has_custom_height) - cfg->custom_height = def->custom_height; - if (def->has_x_offset) - cfg->x_offset = def->x_offset; - if (def->has_y_offset) - cfg->y_offset = def->y_offset; - if (def->has_btn_tile_sheet_column) - cfg->btn_tile_sheet_column = def->btn_tile_sheet_column; - if (def->has_btn_tile_sheet_row) - cfg->btn_tile_sheet_row = def->btn_tile_sheet_row; - if (def->has_defense_bonus_percent) { - cfg->defense_bonus_percent = def->defense_bonus_percent; - free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); - move_bonus_entry_list (&cfg->defense_bonus_extras, &def->defense_bonus_extras); - } - if (def->has_heal_units_in_one_turn) - cfg->heal_units_in_one_turn = def->heal_units_in_one_turn; - if (def->has_impassible) - cfg->impassible = def->impassible; - if (def->has_impassible_to_wheeled) - cfg->impassible_to_wheeled = def->impassible_to_wheeled; - if (def->has_culture_bonus) { - cfg->culture_bonus = def->culture_bonus; - free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); - move_bonus_entry_list (&cfg->culture_bonus_extras, &def->culture_bonus_extras); - } - if (def->has_science_bonus) { - cfg->science_bonus = def->science_bonus; - free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); - move_bonus_entry_list (&cfg->science_bonus_extras, &def->science_bonus_extras); - } - if (def->has_food_bonus) { - cfg->food_bonus = def->food_bonus; - free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); - move_bonus_entry_list (&cfg->food_bonus_extras, &def->food_bonus_extras); - } - if (def->has_gold_bonus) { - cfg->gold_bonus = def->gold_bonus; - free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); - move_bonus_entry_list (&cfg->gold_bonus_extras, &def->gold_bonus_extras); - } - if (def->has_shield_bonus) { - cfg->shield_bonus = def->shield_bonus; - free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); - move_bonus_entry_list (&cfg->shield_bonus_extras, &def->shield_bonus_extras); - } - if (def->has_happiness_bonus) { - cfg->happiness_bonus = def->happiness_bonus; - free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); - move_bonus_entry_list (&cfg->happiness_bonus_extras, &def->happiness_bonus_extras); - } - if (def->has_buildable_on) - cfg->buildable_square_types_mask = def->buildable_square_types_mask; - if (def->has_buildable_adjacent_to) { - cfg->buildable_adjacent_to_square_types_mask = def->buildable_adjacent_to_square_types_mask; - cfg->has_buildable_adjacent_to = true; - cfg->buildable_adjacent_to_allows_city = def->buildable_adjacent_to_allows_city; - } - if (def->has_buildable_without_removal) { - cfg->buildable_without_removal_mask = def->buildable_without_removal_mask; - cfg->has_buildable_without_removal = true; - } - if (def->has_buildable_on_overlays) { - cfg->buildable_on_overlays_mask = def->buildable_on_overlays_mask; - cfg->has_buildable_on_overlays = true; - } - if (def->has_buildable_on_rivers) - cfg->buildable_on_rivers = def->buildable_on_rivers; - if (def->has_buildable_adjacent_to_overlays) { - cfg->buildable_adjacent_to_overlays_mask = def->buildable_adjacent_to_overlays_mask; - cfg->has_buildable_adjacent_to_overlays = true; - } - - if (def->has_generated_resource) { - if ((cfg->generated_resource != NULL) && (cfg->generated_resource != defaults->generated_resource)) - free ((void *)cfg->generated_resource); - cfg->generated_resource = def->generated_resource; - def->generated_resource = NULL; - cfg->generated_resource_flags = def->generated_resource_flags; - cfg->generated_resource_id = -1; - } - - if (def->has_dependent_improvements) { - for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { - char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; - if ((cfg->dependent_improvements[i] != NULL) && - (cfg->dependent_improvements[i] != default_value)) - free ((void *)cfg->dependent_improvements[i]); - cfg->dependent_improvements[i] = NULL; - } - - cfg->dependent_improvement_max_index = def->dependent_improvement_max_index; - const int max_entries = ARRAY_LEN (cfg->dependent_improvements); - if (cfg->dependent_improvement_max_index > max_entries) - cfg->dependent_improvement_max_index = max_entries; - for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { - cfg->dependent_improvements[i] = def->dependent_improvements[i]; - def->dependent_improvements[i] = NULL; - } - if (! def->has_img_column_count) { - cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->dependent_improvement_max_index + 1); - cfg->has_img_column_count_override = false; - } - } - - if (def->has_img_paths) { - for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { - char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; - if ((cfg->img_paths[i] != NULL) && - (cfg->img_paths[i] != default_value)) - free ((void *)cfg->img_paths[i]); - cfg->img_paths[i] = NULL; - } - - cfg->img_path_count = def->img_path_count; - const int max_img_paths = ARRAY_LEN (cfg->img_paths); - if (cfg->img_path_count > max_img_paths) - cfg->img_path_count = max_img_paths; - for (int i = 0; i < cfg->img_path_count; i++) { - cfg->img_paths[i] = def->img_paths[i]; - def->img_paths[i] = NULL; - } - } - - if (def->has_img_column_count) { - cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->img_column_count); - cfg->has_img_column_count_override = true; - } - - if (! ensure_culture_variant_art (cfg, section_start_line)) { - free_special_district_override_strings (cfg, defaults); - *cfg = *defaults; - return false; - } - - return true; -} - -bool -add_dynamic_district_from_definition (struct parsed_district_definition * def, int section_start_line) -{ - if ((! def->has_name) || (def->name == NULL)) - return false; - - if ((! def->has_img_paths) || (def->img_path_count <= 0)) - return false; - - int existing_index = -1; - for (int i = is->special_district_count; i < is->district_count; i++) { - if ((is->district_configs[i].name != NULL) && - (strcmp (is->district_configs[i].name, def->name) == 0)) { - existing_index = i; - break; - } - } - - bool reusing_existing = existing_index >= 0; - int dest_index = reusing_existing ? existing_index : (is->special_district_count + is->dynamic_district_count); - - if ((! reusing_existing) && (dest_index >= COUNT_DISTRICT_TYPES)) - return false; - - enum Unit_Command_Values preserved_command = 0; - if (reusing_existing) - preserved_command = is->district_configs[dest_index].command; - - struct district_config new_cfg; - memset (&new_cfg, 0, sizeof new_cfg); - new_cfg.is_dynamic = true; - - new_cfg.name = def->name; - def->name = NULL; - if (def->has_display_name) { - new_cfg.display_name = def->display_name; - if (new_cfg.display_name == NULL) - new_cfg.display_name = new_cfg.name; - def->display_name = NULL; - } else { - new_cfg.display_name = new_cfg.name; - } - - if (def->has_tooltip) { - new_cfg.tooltip = def->tooltip; - def->tooltip = NULL; - } else if (new_cfg.name != NULL) { - char buffer[128]; - snprintf (buffer, sizeof buffer, "Build %s", new_cfg.name); - new_cfg.tooltip = strdup (buffer); - } - - if (def->has_advance_prereqs) { - new_cfg.advance_prereq_count = def->advance_prereq_count; - const int max_entries = ARRAY_LEN (new_cfg.advance_prereqs); - if (new_cfg.advance_prereq_count > max_entries) - new_cfg.advance_prereq_count = max_entries; - for (int i = 0; i < new_cfg.advance_prereq_count; i++) { - new_cfg.advance_prereqs[i] = def->advance_prereqs[i]; - def->advance_prereqs[i] = NULL; - } - def->advance_prereq_count = 0; - } - - if (def->has_obsoleted_by) { - new_cfg.obsoleted_by = def->obsoleted_by; - def->obsoleted_by = NULL; - } - - new_cfg.resource_prereq_count = def->has_resource_prereqs ? def->resource_prereq_count : 0; - const int max_resource_entries = ARRAY_LEN (new_cfg.resource_prereqs); - if (new_cfg.resource_prereq_count > max_resource_entries) - new_cfg.resource_prereq_count = max_resource_entries; - for (int i = 0; i < new_cfg.resource_prereq_count; i++) { - new_cfg.resource_prereqs[i] = def->resource_prereqs[i]; - def->resource_prereqs[i] = NULL; - } - - if (def->has_resource_prereq_on_tile) { - new_cfg.resource_prereq_on_tile = def->resource_prereq_on_tile; - def->resource_prereq_on_tile = NULL; - } - - new_cfg.wonder_prereq_count = def->has_wonder_prereqs ? def->wonder_prereq_count : 0; - const int max_required_wonders = ARRAY_LEN (new_cfg.wonder_prereqs); - if (new_cfg.wonder_prereq_count > max_required_wonders) - new_cfg.wonder_prereq_count = max_required_wonders; - for (int i = 0; i < new_cfg.wonder_prereq_count; i++) { - new_cfg.wonder_prereqs[i] = def->wonder_prereqs[i]; - def->wonder_prereqs[i] = NULL; - } - - new_cfg.natural_wonder_prereq_count = def->has_natural_wonder_prereqs ? def->natural_wonder_prereq_count : 0; - const int max_required_natural_wonders = ARRAY_LEN (new_cfg.natural_wonder_prereqs); - if (new_cfg.natural_wonder_prereq_count > max_required_natural_wonders) - new_cfg.natural_wonder_prereq_count = max_required_natural_wonders; - for (int i = 0; i < new_cfg.natural_wonder_prereq_count; i++) { - new_cfg.natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; - def->natural_wonder_prereqs[i] = NULL; - } - - new_cfg.buildable_on_district_count = def->has_buildable_on_districts ? def->buildable_on_district_count : 0; - const int max_buildable_on_districts = ARRAY_LEN (new_cfg.buildable_on_districts); - if (new_cfg.buildable_on_district_count > max_buildable_on_districts) - new_cfg.buildable_on_district_count = max_buildable_on_districts; - for (int i = 0; i < new_cfg.buildable_on_district_count; i++) { - new_cfg.buildable_on_districts[i] = def->buildable_on_districts[i]; - def->buildable_on_districts[i] = NULL; - } - new_cfg.buildable_on_district_id_count = 0; - new_cfg.has_buildable_on_districts = def->has_buildable_on_districts; - - new_cfg.buildable_adjacent_to_district_count = def->has_buildable_adjacent_to_districts ? def->buildable_adjacent_to_district_count : 0; - const int max_adjacent_to_districts = ARRAY_LEN (new_cfg.buildable_adjacent_to_districts); - if (new_cfg.buildable_adjacent_to_district_count > max_adjacent_to_districts) - new_cfg.buildable_adjacent_to_district_count = max_adjacent_to_districts; - for (int i = 0; i < new_cfg.buildable_adjacent_to_district_count; i++) { - new_cfg.buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; - def->buildable_adjacent_to_districts[i] = NULL; - } - new_cfg.buildable_adjacent_to_district_id_count = 0; - new_cfg.has_buildable_adjacent_to_districts = def->has_buildable_adjacent_to_districts; - - new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; - const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); - if (new_cfg.buildable_by_civ_count > max_civ_names) - new_cfg.buildable_by_civ_count = max_civ_names; - for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { - new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; - def->buildable_by_civs[i] = NULL; - } - - new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; - - new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; - const int max_buildable_traits = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); - if (new_cfg.buildable_by_civ_traits_id_count > max_buildable_traits) - new_cfg.buildable_by_civ_traits_id_count = max_buildable_traits; - for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) - new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; - new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; - - new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; - const int max_buildable_govs = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); - if (new_cfg.buildable_by_civ_govs_id_count > max_buildable_govs) - new_cfg.buildable_by_civ_govs_id_count = max_buildable_govs; - for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) - new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; - new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; - - new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; - const int max_buildable_cultures = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); - if (new_cfg.buildable_by_civ_cultures_id_count > max_buildable_cultures) - new_cfg.buildable_by_civ_cultures_id_count = max_buildable_cultures; - for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) - new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; - new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; - - new_cfg.buildable_by_war_allies = def->has_buildable_by_war_allies ? def->buildable_by_war_allies : false; - new_cfg.buildable_by_pact_allies = def->has_buildable_by_pact_allies ? def->buildable_by_pact_allies : false; - - new_cfg.allow_multiple = def->has_allow_multiple ? def->allow_multiple : false; - new_cfg.vary_img_by_era = def->has_vary_img_by_era ? def->vary_img_by_era : false; - new_cfg.vary_img_by_culture = def->has_vary_img_by_culture ? def->vary_img_by_culture : false; - new_cfg.render_strategy = def->has_render_strategy ? def->render_strategy : DRS_BY_COUNT; - new_cfg.ai_build_strategy = def->has_ai_build_strategy ? def->ai_build_strategy : DABS_DISTRICT; - new_cfg.align_to_coast = def->has_align_to_coast ? def->align_to_coast : false; - new_cfg.draw_over_resources = def->has_draw_over_resources ? def->draw_over_resources : false; - new_cfg.allow_irrigation_from = def->has_allow_irrigation_from ? def->allow_irrigation_from : false; - new_cfg.auto_add_road = def->has_auto_add_road ? def->auto_add_road : false; - new_cfg.auto_add_railroad = def->has_auto_add_railroad ? def->auto_add_railroad : false; - new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; - new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; - new_cfg.x_offset = def->has_x_offset ? def->x_offset : 0; - new_cfg.y_offset = def->has_y_offset ? def->y_offset : 0; - new_cfg.btn_tile_sheet_column = def->has_btn_tile_sheet_column ? def->btn_tile_sheet_column : 0; - new_cfg.btn_tile_sheet_row = def->has_btn_tile_sheet_row ? def->btn_tile_sheet_row : 0; - new_cfg.defense_bonus_percent = def->has_defense_bonus_percent ? def->defense_bonus_percent : 0; - new_cfg.heal_units_in_one_turn = def->has_heal_units_in_one_turn ? def->heal_units_in_one_turn : false; - new_cfg.impassible = def->has_impassible ? def->impassible : false; - new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; - new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; - new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; - new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; - new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; - new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; - new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; - new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); - new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; - new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; - new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; - new_cfg.buildable_without_removal_mask = def->has_buildable_without_removal ? def->buildable_without_removal_mask : 0; - new_cfg.has_buildable_without_removal = def->has_buildable_without_removal; - new_cfg.buildable_on_overlays_mask = def->has_buildable_on_overlays ? def->buildable_on_overlays_mask : 0; - new_cfg.has_buildable_on_overlays = def->has_buildable_on_overlays; - new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; - new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; - new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; - - if (def->has_culture_bonus) - move_bonus_entry_list (&new_cfg.culture_bonus_extras, &def->culture_bonus_extras); - if (def->has_science_bonus) - move_bonus_entry_list (&new_cfg.science_bonus_extras, &def->science_bonus_extras); - if (def->has_food_bonus) - move_bonus_entry_list (&new_cfg.food_bonus_extras, &def->food_bonus_extras); - if (def->has_gold_bonus) - move_bonus_entry_list (&new_cfg.gold_bonus_extras, &def->gold_bonus_extras); - if (def->has_shield_bonus) - move_bonus_entry_list (&new_cfg.shield_bonus_extras, &def->shield_bonus_extras); - if (def->has_happiness_bonus) - move_bonus_entry_list (&new_cfg.happiness_bonus_extras, &def->happiness_bonus_extras); - if (def->has_defense_bonus_percent) - move_bonus_entry_list (&new_cfg.defense_bonus_extras, &def->defense_bonus_extras); - - if (def->has_generated_resource) { - new_cfg.generated_resource = def->generated_resource; - def->generated_resource = NULL; - new_cfg.generated_resource_flags = def->generated_resource_flags; - new_cfg.generated_resource_id = -1; - } else { - new_cfg.generated_resource = NULL; - new_cfg.generated_resource_id = -1; - new_cfg.generated_resource_flags = 0; - } - - new_cfg.dependent_improvement_max_index = def->has_dependent_improvements ? def->dependent_improvement_max_index : 0; - const int max_dependent_entries = ARRAY_LEN (is->district_configs[0].dependent_improvements); - if (new_cfg.dependent_improvement_max_index > max_dependent_entries) - new_cfg.dependent_improvement_max_index = max_dependent_entries; - for (int i = 0; i < new_cfg.dependent_improvement_max_index; i++) { - new_cfg.dependent_improvements[i] = def->dependent_improvements[i]; - def->dependent_improvements[i] = NULL; - } - - new_cfg.img_path_count = def->img_path_count; - const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); - if (new_cfg.img_path_count > max_img_paths) - new_cfg.img_path_count = max_img_paths; - for (int i = 0; i < new_cfg.img_path_count; i++) { - new_cfg.img_paths[i] = def->img_paths[i]; - def->img_paths[i] = NULL; - } - - if (! ensure_culture_variant_art (&new_cfg, section_start_line)) { - free_dynamic_district_config (&new_cfg); - return false; - } - - new_cfg.img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, def->has_img_column_count ? def->img_column_count : new_cfg.dependent_improvement_max_index + 1); - new_cfg.has_img_column_count_override = def->has_img_column_count; - - if (reusing_existing) - new_cfg.command = preserved_command; - else - new_cfg.command = allocate_dynamic_district_command (new_cfg.name); - - struct district_config * dest_cfg = &is->district_configs[dest_index]; - if (reusing_existing) { - enum Unit_Command_Values saved_command = preserved_command; - free_dynamic_district_config (dest_cfg); - *dest_cfg = new_cfg; - dest_cfg->command = saved_command; - } else { - free_dynamic_district_config (dest_cfg); - *dest_cfg = new_cfg; - is->dynamic_district_count += 1; - is->district_count = is->special_district_count + is->dynamic_district_count; - } - - return true; -} - -void -finalize_parsed_district_definition (struct parsed_district_definition * def, int section_start_line) -{ - if ((! def->has_name) || (def->name == NULL)) - return; - - if (! override_special_district_from_definition (def, section_start_line)) - add_dynamic_district_from_definition (def, section_start_line); - - free_parsed_district_definition (def); -} - -void -handle_district_definition_key (struct parsed_district_definition * def, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if (slice_matches_str (key, "name")) { - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - char * name_copy = copy_trimmed_string_or_null (value, 1); - if (name_copy == NULL) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else { - def->name = name_copy; - def->has_name = true; - } - - } else if (slice_matches_str (key, "display_name")) { - if (def->display_name != NULL) { - free (def->display_name); - def->display_name = NULL; - } - def->display_name = copy_trimmed_string_or_null (value, 1); - def->has_display_name = true; - - } else if (slice_matches_str (key, "tooltip")) { - if (def->tooltip != NULL) { - free (def->tooltip); - def->tooltip = NULL; - } - def->tooltip = copy_trimmed_string_or_null (value, 1); - def->has_tooltip = true; - - } else if (slice_matches_str (key, "advance_prereqs") || slice_matches_str (key, "advance_prereq")) { - for (int i = 0; i < def->advance_prereq_count; i++) { - if (def->advance_prereqs[i] != NULL) { - free (def->advance_prereqs[i]); - def->advance_prereqs[i] = NULL; - } - } - def->advance_prereq_count = 0; - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->advance_prereqs, - ARRAY_LEN (def->advance_prereqs), - &list_count, - parse_errors, - line_number, - "advance_prereqs")) { - def->advance_prereq_count = list_count; - def->has_advance_prereqs = true; - } else { - def->advance_prereq_count = 0; - def->has_advance_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "obsoleted_by")) { - if (def->obsoleted_by != NULL) { - free (def->obsoleted_by); - def->obsoleted_by = NULL; - } - def->obsoleted_by = copy_trimmed_string_or_null (value, 1); - def->has_obsoleted_by = true; - - } else if (slice_matches_str (key, "resource_prereqs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->resource_prereqs, - ARRAY_LEN (def->resource_prereqs), - &list_count, - parse_errors, - line_number, - "resource_prereqs")) { - def->resource_prereq_count = list_count; - def->has_resource_prereqs = true; - } else { - def->resource_prereq_count = 0; - def->has_resource_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "resource_prereq_on_tile")) { - if (def->resource_prereq_on_tile != NULL) { - free (def->resource_prereq_on_tile); - def->resource_prereq_on_tile = NULL; - } - def->resource_prereq_on_tile = copy_trimmed_string_or_null (value, 1); - def->has_resource_prereq_on_tile = true; - - } else if (slice_matches_str (key, "wonder_prereqs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->wonder_prereqs, - ARRAY_LEN (def->wonder_prereqs), - &list_count, - parse_errors, - line_number, - "wonder_prereqs")) { - def->wonder_prereq_count = list_count; - def->has_wonder_prereqs = true; - } else { - def->wonder_prereq_count = 0; - def->has_wonder_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "natural_wonder_prereqs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->natural_wonder_prereqs, - ARRAY_LEN (def->natural_wonder_prereqs), - &list_count, - parse_errors, - line_number, - "natural_wonder_prereqs")) { - def->natural_wonder_prereq_count = list_count; - def->has_natural_wonder_prereqs = true; - } else { - def->natural_wonder_prereq_count = 0; - def->has_natural_wonder_prereqs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_on_districts")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_on_districts, - ARRAY_LEN (def->buildable_on_districts), - &list_count, - parse_errors, - line_number, - "buildable_on_districts")) { - def->buildable_on_district_count = list_count; - def->has_buildable_on_districts = true; - } else { - def->buildable_on_district_count = 0; - def->has_buildable_on_districts = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_adjacent_to_districts")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_adjacent_to_districts, - ARRAY_LEN (def->buildable_adjacent_to_districts), - &list_count, - parse_errors, - line_number, - "buildable_adjacent_to_districts")) { - def->buildable_adjacent_to_district_count = list_count; - def->has_buildable_adjacent_to_districts = true; - } else { - def->buildable_adjacent_to_district_count = 0; - def->has_buildable_adjacent_to_districts = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civs, - ARRAY_LEN (def->buildable_by_civs), - &list_count, - parse_errors, - line_number, - "buildable_by_civs")) { - def->buildable_by_civ_count = list_count; - def->has_buildable_by_civs = true; - } else { - def->buildable_by_civ_count = 0; - def->has_buildable_by_civs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_traits")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_traits, - ARRAY_LEN (def->buildable_by_civ_traits), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_traits")) { - def->buildable_by_civ_traits_count = list_count; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - char const * trait_name = def->buildable_by_civ_traits[i]; - if ((trait_name == NULL) || (trait_name[0] == '\0')) - continue; - int trait_id = -1; - struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; - if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { - if (def->buildable_by_civ_traits_ids[k] == trait_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) - def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->has_buildable_by_civ_traits = true; - } else { - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - def->has_buildable_by_civ_traits = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_govs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_govs, - ARRAY_LEN (def->buildable_by_civ_govs), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_govs")) { - def->buildable_by_civ_govs_count = list_count; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - char const * gov_name = def->buildable_by_civ_govs[i]; - if ((gov_name == NULL) || (gov_name[0] == '\0')) - continue; - int gov_id = -1; - struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; - if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { - if (def->buildable_by_civ_govs_ids[k] == gov_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) - def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->has_buildable_by_civ_govs = true; - } else { - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - def->has_buildable_by_civ_govs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_cultures, - ARRAY_LEN (def->buildable_by_civ_cultures), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_cultures")) { - def->buildable_by_civ_cultures_count = list_count; - def->buildable_by_civ_cultures_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - char const * culture_name = def->buildable_by_civ_cultures[i]; - if ((culture_name == NULL) || (culture_name[0] == '\0')) - continue; - int culture_id = -1; - struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; - if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { - if (def->buildable_by_civ_cultures_ids[k] == culture_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) - def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->has_buildable_by_civ_cultures = true; - } else { - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - def->has_buildable_by_civ_cultures = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_war_allies")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_by_war_allies = (ival != 0); - def->has_buildable_by_war_allies = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "buildable_by_pact_allies")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_by_pact_allies = (ival != 0); - def->has_buildable_by_pact_allies = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "img_paths")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->img_paths, - ARRAY_LEN (def->img_paths), - &list_count, - parse_errors, - line_number, - "img_paths")) { - def->img_path_count = list_count; - def->has_img_paths = true; - } else { - def->img_path_count = 0; - def->has_img_paths = false; - } - free (value_text); - - } else if (slice_matches_str (key, "img_column_count")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_column_count = ival; - def->has_img_column_count = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "dependent_improvs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->dependent_improvements, - ARRAY_LEN (def->dependent_improvements), - &list_count, - parse_errors, - line_number, - "dependent_improvs")) { - def->dependent_improvement_max_index = list_count; - def->has_dependent_improvements = true; - } else { - def->dependent_improvement_max_index = 0; - def->has_dependent_improvements = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_on")) { - unsigned int mask; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { - def->buildable_square_types_mask = mask; - def->has_buildable_on = true; - } - - } else if (slice_matches_str (key, "buildable_without_removal")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_without_removal")) { - def->buildable_without_removal_mask = mask; - def->has_buildable_without_removal = true; - } else { - def->has_buildable_without_removal = false; - } - - } else if (slice_matches_str (key, "buildable_on_overlays")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_on_overlays")) { - def->buildable_on_overlays_mask = mask; - def->has_buildable_on_overlays = true; - } else { - def->has_buildable_on_overlays = false; - } - - } else if (slice_matches_str (key, "buildable_on_rivers")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_on_rivers = (ival != 0); - def->has_buildable_on_rivers = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "buildable_adjacent_to")) { - unsigned int mask; - def->buildable_adjacent_to_allows_city = false; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { - def->buildable_adjacent_to_square_types_mask = mask; - def->has_buildable_adjacent_to = true; - } - - } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { - def->buildable_adjacent_to_overlays_mask = mask; - def->has_buildable_adjacent_to_overlays = true; - } else { - def->has_buildable_adjacent_to_overlays = false; - } - - } else if (slice_matches_str (key, "allow_multiple")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->allow_multiple = (ival != 0); - def->has_allow_multiple = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "vary_img_by_era")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->vary_img_by_era = (ival != 0); - def->has_vary_img_by_era = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "vary_img_by_culture")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->vary_img_by_culture = (ival != 0); - def->has_vary_img_by_culture = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "render_strategy")) { - char * strategy = copy_trimmed_string_or_null (value, 1); - if (strategy == NULL) { - def->has_render_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else if (strcmp (strategy, "by-count") == 0) { - def->render_strategy = DRS_BY_COUNT; - def->has_render_strategy = true; - } else if (strcmp (strategy, "by-building") == 0) { - def->render_strategy = DRS_BY_BUILDING; - def->has_render_strategy = true; - } else { - def->has_render_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected \"by-count\" or \"by-building\")"); - } - if (strategy != NULL) - free (strategy); - - } else if (slice_matches_str (key, "ai_build_strategy")) { - char * strategy = copy_trimmed_string_or_null (value, 1); - if (strategy == NULL) { - def->has_ai_build_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else if (strcmp (strategy, "district") == 0) { - def->ai_build_strategy = DABS_DISTRICT; - def->has_ai_build_strategy = true; - } else if (strcmp (strategy, "tile-improvement") == 0) { - def->ai_build_strategy = DABS_TILE_IMPROVEMENT; - def->has_ai_build_strategy = true; - } else { - def->has_ai_build_strategy = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected \"district\" or \"tile-improvement\")"); - } - if (strategy != NULL) - free (strategy); - - } else if (slice_matches_str (key, "align_to_coast")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->align_to_coast = (ival != 0); - def->has_align_to_coast = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "draw_over_resources")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->draw_over_resources = (ival != 0); - def->has_draw_over_resources = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "allow_irrigation_from")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->allow_irrigation_from = (ival != 0); - def->has_allow_irrigation_from = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "auto_add_road")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->auto_add_road = (ival != 0); - def->has_auto_add_road = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "auto_add_railroad")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->auto_add_railroad = (ival != 0); - def->has_auto_add_railroad = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "impassible")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible = (ival != 0); - def->has_impassible = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "impassible_to_wheeled")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible_to_wheeled = (ival != 0); - def->has_impassible_to_wheeled = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "custom_width")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_width = ival; - def->has_custom_width = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "custom_height")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_height = ival; - def->has_custom_height = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "x_offset")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->x_offset = ival; - def->has_x_offset = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "y_offset")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->y_offset = ival; - def->has_y_offset = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "btn_tile_sheet_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->btn_tile_sheet_column = ival; - def->has_btn_tile_sheet_column = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "btn_tile_sheet_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->btn_tile_sheet_row = ival; - def->has_btn_tile_sheet_row = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "defense_bonus_percent")) { - if (parse_district_bonus_entries (value, &def->defense_bonus_percent, &def->defense_bonus_extras, parse_errors, line_number, key)) { - def->has_defense_bonus_percent = true; - } else { - def->has_defense_bonus_percent = false; - } - - } else if (slice_matches_str (key, "heal_units_in_one_turn")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->heal_units_in_one_turn = (ival != 0); - def->has_heal_units_in_one_turn = true; - } else - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - - } else if (slice_matches_str (key, "culture_bonus")) { - if (parse_district_bonus_entries (value, &def->culture_bonus, &def->culture_bonus_extras, parse_errors, line_number, key)) { - def->has_culture_bonus = true; - } else { - def->has_culture_bonus = false; - } - - } else if (slice_matches_str (key, "science_bonus")) { - if (parse_district_bonus_entries (value, &def->science_bonus, &def->science_bonus_extras, parse_errors, line_number, key)) { - def->has_science_bonus = true; - } else { - def->has_science_bonus = false; - } - - } else if (slice_matches_str (key, "food_bonus")) { - if (parse_district_bonus_entries (value, &def->food_bonus, &def->food_bonus_extras, parse_errors, line_number, key)) { - def->has_food_bonus = true; - } else { - def->has_food_bonus = false; - } - - } else if (slice_matches_str (key, "gold_bonus")) { - if (parse_district_bonus_entries (value, &def->gold_bonus, &def->gold_bonus_extras, parse_errors, line_number, key)) { - def->has_gold_bonus = true; - } else { - def->has_gold_bonus = false; - } - - } else if (slice_matches_str (key, "shield_bonus")) { - if (parse_district_bonus_entries (value, &def->shield_bonus, &def->shield_bonus_extras, parse_errors, line_number, key)) { - def->has_shield_bonus = true; - } else { - def->has_shield_bonus = false; - } - - } else if (slice_matches_str (key, "happiness_bonus")) { - if (parse_district_bonus_entries (value, &def->happiness_bonus, &def->happiness_bonus_extras, parse_errors, line_number, key)) { - def->has_happiness_bonus = true; - } else { - def->has_happiness_bonus = false; - } - - } else if (slice_matches_str (key, "generated_resource")) { - if (def->generated_resource != NULL) { - free (def->generated_resource); - def->generated_resource = NULL; - } - def->generated_resource_flags = 0; - - char * value_text = trim_and_extract_slice (value, 0); - if ((value_text == NULL) || (*value_text == '\0')) { - def->generated_resource = NULL; - def->has_generated_resource = true; - } else { - char * cursor = value_text; - struct string_slice resource_name = {0}; - struct string_slice token; - bool ok = true; - while (skip_white_space (&cursor) && parse_string (&cursor, &token)) { - if (slice_matches_str (&token, "local")) - def->generated_resource_flags |= MF_LOCAL; - else if (slice_matches_str (&token, "no-tech-req")) - def->generated_resource_flags |= MF_NO_TECH_REQ; - else if (slice_matches_str (&token, "yields")) - def->generated_resource_flags |= MF_YIELDS; - else if (resource_name.str == NULL) - resource_name = token; - else { - ok = false; - break; - } - } - - if (! ok || (resource_name.str == NULL)) { - def->generated_resource = NULL; - def->has_generated_resource = false; - def->generated_resource_flags = 0; - add_key_parse_error (parse_errors, line_number, key, value, - "(expected resource name plus optional flags: local, yields, no-tech-req)"); - } else { - def->generated_resource = extract_slice (&resource_name); - def->has_generated_resource = true; - } - } - free (value_text); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -bool -line_is_empty_or_comment (struct string_slice const * trimmed) -{ - return ((trimmed == NULL) || (trimmed->len == 0) || (trimmed->str[0] == ';') || (trimmed->str[0] == '[')); -} - -bool -file_exists_at_path (char const * path) -{ - if ((path == NULL) || (path[0] == '\0')) - return false; - - HANDLE file = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (file == INVALID_HANDLE_VALUE) - return false; - - CloseHandle (file); - return true; -} - -void -load_dynamic_district_config_file (char const * file_path, - int path_is_relative_to_mod_dir, - int log_missing, - int drop_existing_configs) -{ - char path[MAX_PATH]; - if (path_is_relative_to_mod_dir) { - if (is->mod_rel_dir == NULL) - return; - snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); - } else { - strncpy (path, file_path, sizeof path); - } - path[(sizeof path) - 1] = '\0'; - - char * text = file_to_string (path); - if (text == NULL) { - if (log_missing) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] Districts config file not found: %s", path); - (*p_OutputDebugStringA) (ss); - } - return; - } - - if (drop_existing_configs) - reset_regular_district_configs (); - - struct parsed_district_definition def; - init_parsed_district_definition (&def); - bool in_section = false; - int section_start_line = 0; - int line_number = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - bool has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if ((directive.len > 0) && slice_matches_str (&directive, "District")) { - if (in_section) - finalize_parsed_district_definition (&def, section_start_line); - in_section = true; - section_start_line = line_number; - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); - if (status == KVP_NO_EQUALS) { - char * line_text = extract_slice (&trimmed); - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); - err->text[(sizeof err->text) - 1] = '\0'; - free (line_text); - cursor = has_newline ? line_end + 1 : line_end; - continue; - } else if (status == KVP_EMPTY_KEY) { - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); - err->text[(sizeof err->text) - 1] = '\0'; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - handle_district_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) - finalize_parsed_district_definition (&def, section_start_line); - - free_parsed_district_definition (&def); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - snprintf (is->current_districts_config_path, sizeof is->current_districts_config_path, path); - - if (parse_errors != NULL || unrecognized_keys != NULL) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "District Config errors in %s:", path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - if (parse_errors != NULL) { - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", false); - PopupForm_add_text (popup, __, "Unrecognized keys:", false); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - patch_show_popup (popup, __, 0, 0); - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); - } -} - -void -load_dynamic_district_configs () -{ - char * scenario_filename = "scenario.districts_config.txt"; - char * scenario_district_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - if ((scenario_district_config_path != NULL) && - (0 != strcmp (scenario_filename, scenario_district_config_path)) && - file_exists_at_path (scenario_district_config_path)) { - load_dynamic_district_config_file (scenario_district_config_path, 0, 0, 1); - return; - } - - if (is->mod_rel_dir != NULL) { - char user_path[MAX_PATH]; - snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_config.txt"); - user_path[(sizeof user_path) - 1] = '\0'; - if (file_exists_at_path (user_path)) { - load_dynamic_district_config_file ("user.districts_config.txt", 1, 0, 1); - return; - } - } - - load_dynamic_district_config_file ("default.districts_config.txt", 1, 1, 1); -} - -void -init_parsed_wonder_definition (struct parsed_wonder_definition * def) -{ - memset (def, 0, sizeof *def); - def->buildable_square_types_mask = district_default_buildable_mask (); - def->buildable_adjacent_to_square_types_mask = 0; - def->buildable_adjacent_to_overlays_mask = 0; - def->buildable_on_rivers = false; - def->buildable_adjacent_to_allows_city = false; - for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_traits_ids); i++) - def->buildable_by_civ_traits_ids[i] = -1; - for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_govs_ids); i++) - def->buildable_by_civ_govs_ids[i] = -1; - for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_cultures_ids); i++) - def->buildable_by_civ_cultures_ids[i] = -1; -} - -void -free_parsed_wonder_definition (struct parsed_wonder_definition * def) -{ - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - - for (int i = 0; i < def->buildable_by_civ_count; i++) { - if (def->buildable_by_civs[i] != NULL) { - free (def->buildable_by_civs[i]); - def->buildable_by_civs[i] = NULL; - } - } - def->buildable_by_civ_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - - init_parsed_wonder_definition (def); -} - -bool -add_dynamic_wonder_from_definition (struct parsed_wonder_definition * def, int section_start_line) -{ - int existing_index = -1; - for (int i = 0; i < is->wonder_district_count; i++) { - if ((is->wonder_district_configs[i].wonder_name != NULL) && - (strcmp (is->wonder_district_configs[i].wonder_name, def->name) == 0)) { - existing_index = i; - break; - } - } - - int dest = (existing_index >= 0) ? existing_index : is->wonder_district_count; - if ((dest < 0) || (dest >= MAX_WONDER_DISTRICT_TYPES)) - return false; - - struct wonder_district_config new_cfg; - memset (&new_cfg, 0, sizeof new_cfg); - new_cfg.index = dest; - new_cfg.is_dynamic = true; - new_cfg.wonder_name = strdup (def->name); - new_cfg.img_path = (def->img_path != NULL) ? strdup (def->img_path) : strdup ("Wonders.pcx"); - new_cfg.img_row = def->img_row; - new_cfg.img_column = def->img_column; - new_cfg.img_construct_row = def->img_construct_row; - new_cfg.img_construct_column = def->img_construct_column; - new_cfg.img_alt_dir_construct_row = def->img_alt_dir_construct_row; - new_cfg.img_alt_dir_construct_column = def->img_alt_dir_construct_column; - new_cfg.img_alt_dir_row = def->img_alt_dir_row; - new_cfg.img_alt_dir_column = def->img_alt_dir_column; - new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; - new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; - new_cfg.enable_img_alt_dir = def->enable_img_alt_dir; - new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); - new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; - new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; - new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; - new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; - new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; - const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); - if (new_cfg.buildable_by_civ_count > max_civ_names) - new_cfg.buildable_by_civ_count = max_civ_names; - for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { - new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; - def->buildable_by_civs[i] = NULL; - } - new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; - new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; - const int max_trait_entries = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); - if (new_cfg.buildable_by_civ_traits_id_count > max_trait_entries) - new_cfg.buildable_by_civ_traits_id_count = max_trait_entries; - for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) - new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; - new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; - new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; - const int max_gov_entries = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); - if (new_cfg.buildable_by_civ_govs_id_count > max_gov_entries) - new_cfg.buildable_by_civ_govs_id_count = max_gov_entries; - for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) - new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; - new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; - new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; - const int max_culture_entries = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); - if (new_cfg.buildable_by_civ_cultures_id_count > max_culture_entries) - new_cfg.buildable_by_civ_cultures_id_count = max_culture_entries; - for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) - new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; - new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; - new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; - new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; - - if (existing_index >= 0) { - struct wonder_district_config * cfg = &is->wonder_district_configs[existing_index]; - free_dynamic_wonder_config (cfg); - *cfg = new_cfg; - cfg->index = existing_index; - } else { - struct wonder_district_config * cfg = &is->wonder_district_configs[dest]; - free_dynamic_wonder_config (cfg); - *cfg = new_cfg; - is->wonder_district_count += 1; - } - - return true; -} - -void -finalize_parsed_wonder_definition (struct parsed_wonder_definition * def, - int section_start_line, - struct error_line ** parse_errors) -{ - bool ok = true; - - if ((! def->has_name) || (def->name == NULL)) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_construct_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_row (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_construct_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_column (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (def->enable_img_alt_dir) { - if (! def->has_img_alt_dir_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_row (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_alt_dir_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_column (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_alt_dir_construct_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_row (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_alt_dir_construct_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_column (value is required when enable_img_alt_dir is set)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - } - - if (ok) - add_dynamic_wonder_from_definition (def, section_start_line); - - free_parsed_wonder_definition (def); -} - -void -handle_wonder_definition_key (struct parsed_wonder_definition * def, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if (slice_matches_str (key, "name")) { - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else { - char * name_copy = extract_slice (&unquoted); - if (name_copy == NULL) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); - } else { - def->name = name_copy; - def->has_name = true; - } - } - - } else if (slice_matches_str (key, "img_path")) { - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_img_path = false; - } else { - char * path_copy = extract_slice (&unquoted); - if (path_copy == NULL) { - def->has_img_path = false; - } else { - def->img_path = path_copy; - def->has_img_path = true; - } - } - - } else if (slice_matches_str (key, "img_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_row = ival; - def->has_img_row = true; - } else { - def->has_img_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_column = ival; - def->has_img_column = true; - } else { - def->has_img_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_construct_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_construct_row = ival; - def->has_img_construct_row = true; - } else { - def->has_img_construct_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_construct_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_construct_column = ival; - def->has_img_construct_column = true; - } else { - def->has_img_construct_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_construct_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_construct_row = ival; - def->has_img_alt_dir_construct_row = true; - } else { - def->has_img_alt_dir_construct_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_construct_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_construct_column = ival; - def->has_img_alt_dir_construct_column = true; - } else { - def->has_img_alt_dir_construct_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_row = ival; - def->has_img_alt_dir_row = true; - } else { - def->has_img_alt_dir_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_alt_dir_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_alt_dir_column = ival; - def->has_img_alt_dir_column = true; - } else { - def->has_img_alt_dir_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "custom_width")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_width = ival; - def->has_custom_width = true; - } else { - def->has_custom_width = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "custom_height")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->custom_height = ival; - def->has_custom_height = true; - } else { - def->has_custom_height = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "enable_img_alt_dir")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->enable_img_alt_dir = (ival != 0); - def->has_enable_img_alt_dir = true; - } else { - def->has_enable_img_alt_dir = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "buildable_on")) { - unsigned int mask; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { - def->buildable_square_types_mask = mask; - def->has_buildable_on = true; - } else { - def->has_buildable_on = false; - } - - } else if (slice_matches_str (key, "buildable_on_rivers")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->buildable_on_rivers = (ival != 0); - def->has_buildable_on_rivers = true; - } else { - def->has_buildable_on_rivers = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "buildable_adjacent_to")) { - unsigned int mask; - def->buildable_adjacent_to_allows_city = false; - if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { - def->buildable_adjacent_to_square_types_mask = mask; - def->has_buildable_adjacent_to = true; - } else { - def->has_buildable_adjacent_to = false; - } - - } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { - unsigned int mask; - if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { - def->buildable_adjacent_to_overlays_mask = mask; - def->has_buildable_adjacent_to_overlays = true; - } else { - def->has_buildable_adjacent_to_overlays = false; - } - - } else if (slice_matches_str (key, "buildable_by_civs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civs, - ARRAY_LEN (def->buildable_by_civs), - &list_count, - parse_errors, - line_number, - "buildable_by_civs")) { - def->buildable_by_civ_count = list_count; - def->has_buildable_by_civs = true; - } else { - def->buildable_by_civ_count = 0; - def->has_buildable_by_civs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_traits")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_traits, - ARRAY_LEN (def->buildable_by_civ_traits), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_traits")) { - def->buildable_by_civ_traits_count = list_count; - def->buildable_by_civ_traits_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - char const * trait_name = def->buildable_by_civ_traits[i]; - if ((trait_name == NULL) || (trait_name[0] == '\0')) - continue; - int trait_id = -1; - struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; - if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { - if (def->buildable_by_civ_traits_ids[k] == trait_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) - def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { - if (def->buildable_by_civ_traits[i] != NULL) { - free (def->buildable_by_civ_traits[i]); - def->buildable_by_civ_traits[i] = NULL; - } - } - def->buildable_by_civ_traits_count = 0; - def->has_buildable_by_civ_traits = true; - } else { - def->buildable_by_civ_traits_count = 0; - def->buildable_by_civ_traits_id_count = 0; - def->has_buildable_by_civ_traits = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_govs")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_govs, - ARRAY_LEN (def->buildable_by_civ_govs), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_govs")) { - def->buildable_by_civ_govs_count = list_count; - def->buildable_by_civ_govs_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - char const * gov_name = def->buildable_by_civ_govs[i]; - if ((gov_name == NULL) || (gov_name[0] == '\0')) - continue; - int gov_id = -1; - struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; - if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { - if (def->buildable_by_civ_govs_ids[k] == gov_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) - def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { - if (def->buildable_by_civ_govs[i] != NULL) { - free (def->buildable_by_civ_govs[i]); - def->buildable_by_civ_govs[i] = NULL; - } - } - def->buildable_by_civ_govs_count = 0; - def->has_buildable_by_civ_govs = true; - } else { - def->buildable_by_civ_govs_count = 0; - def->buildable_by_civ_govs_id_count = 0; - def->has_buildable_by_civ_govs = false; - } - free (value_text); - - } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { - char * value_text = trim_and_extract_slice (value, 0); - int list_count = 0; - if (parse_config_string_list (value_text, - def->buildable_by_civ_cultures, - ARRAY_LEN (def->buildable_by_civ_cultures), - &list_count, - parse_errors, - line_number, - "buildable_by_civ_cultures")) { - def->buildable_by_civ_cultures_count = list_count; - def->buildable_by_civ_cultures_id_count = 0; - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - char const * culture_name = def->buildable_by_civ_cultures[i]; - if ((culture_name == NULL) || (culture_name[0] == '\0')) - continue; - int culture_id = -1; - struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; - if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { - bool already_listed = false; - for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { - if (def->buildable_by_civ_cultures_ids[k] == culture_id) { - already_listed = true; - break; - } - } - if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) - def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { - if (def->buildable_by_civ_cultures[i] != NULL) { - free (def->buildable_by_civ_cultures[i]); - def->buildable_by_civ_cultures[i] = NULL; - } - } - def->buildable_by_civ_cultures_count = 0; - def->has_buildable_by_civ_cultures = true; - } else { - def->buildable_by_civ_cultures_count = 0; - def->buildable_by_civ_cultures_id_count = 0; - def->has_buildable_by_civ_cultures = false; - } - free (value_text); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -void -load_dynamic_wonder_config_file (char const * file_path, - int path_is_relative_to_mod_dir, - int log_missing, - int drop_existing_configs) -{ - char path[MAX_PATH]; - if (path_is_relative_to_mod_dir) { - if (is->mod_rel_dir == NULL) - return; - snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); - } else { - strncpy (path, file_path, sizeof path); - } - path[(sizeof path) - 1] = '\0'; - - char * text = file_to_string (path); - if (text == NULL) { - if (log_missing) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] Wonders config file not found: %s", path); - (*p_OutputDebugStringA) (ss); - } - return; - } - - if (drop_existing_configs) - reset_wonder_district_configs (); - - struct parsed_wonder_definition def; - init_parsed_wonder_definition (&def); - bool in_section = false; - int section_start_line = 0; - int line_number = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - bool has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { - if (in_section) - finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); - in_section = true; - section_start_line = line_number; - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); - if (status == KVP_NO_EQUALS) { - char * line_text = extract_slice (&trimmed); - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); - err->text[(sizeof err->text) - 1] = '\0'; - free (line_text); - cursor = has_newline ? line_end + 1 : line_end; - continue; - } else if (status == KVP_EMPTY_KEY) { - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); - err->text[(sizeof err->text) - 1] = '\0'; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - handle_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) - finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); - - free_parsed_wonder_definition (&def); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - - if (parse_errors != NULL || unrecognized_keys != NULL) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "Wonder District Config errors in %s:", path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - if (parse_errors != NULL) { - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", false); - PopupForm_add_text (popup, __, "Unrecognized keys:", false); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - patch_show_popup (popup, __, 0, 0); - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); - } -} - -void -load_dynamic_wonder_configs () -{ - char * scenario_filename = "scenario.districts_wonders_config.txt"; - char * scenario_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - if ((scenario_wonder_config_path != NULL) && - (0 != strcmp (scenario_filename, scenario_wonder_config_path)) && - file_exists_at_path (scenario_wonder_config_path)) { - load_dynamic_wonder_config_file (scenario_wonder_config_path, 0, 0, 1); - return; - } - - if (is->mod_rel_dir != NULL) { - char user_path[MAX_PATH]; - snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_wonders_config.txt"); - user_path[(sizeof user_path) - 1] = '\0'; - if (file_exists_at_path (user_path)) { - load_dynamic_wonder_config_file ("user.districts_wonders_config.txt", 1, 0, 1); - return; - } - } - - load_dynamic_wonder_config_file ("default.districts_wonders_config.txt", 1, 1, 1); -} - -void -init_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) -{ - memset (def, 0, sizeof *def); - def->terrain_type = SQ_Grassland; - def->adjacent_to = (enum SquareTypes)SQ_INVALID; - def->adjacency_dir = DIR_ZERO; -} - -void -free_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) -{ - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - init_parsed_natural_wonder_definition (def); -} - -bool -add_natural_wonder_from_definition (struct parsed_natural_wonder_definition * def, int section_start_line) -{ - if ((def == NULL) || (def->name == NULL)) - return false; - - int existing_index; - bool has_existing = stable_look_up (&is->natural_wonder_name_to_id, def->name, &existing_index); - - int dest = has_existing ? existing_index : is->natural_wonder_count; - if ((dest < 0) || (dest >= MAX_NATURAL_WONDER_DISTRICT_TYPES)) - return false; - - struct natural_wonder_district_config new_cfg; - memset (&new_cfg, 0, sizeof new_cfg); - new_cfg.index = dest; - new_cfg.is_dynamic = true; - new_cfg.adjacent_to = (enum SquareTypes)SQ_INVALID; - new_cfg.adjacency_dir = DIR_ZERO; - - char * name_copy = strdup (def->name); - if (name_copy == NULL) - return false; - new_cfg.name = name_copy; - - char const * img_path_src = def->img_path; - char * img_copy = strdup (img_path_src); - if (img_copy == NULL) { - free (name_copy); - return false; - } - new_cfg.img_path = img_copy; - new_cfg.img_row = def->img_row; - new_cfg.img_column = def->img_column; - new_cfg.terrain_type = def->terrain_type; - new_cfg.adjacent_to = def->adjacent_to; - new_cfg.adjacency_dir = def->adjacency_dir; - new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; - new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; - new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; - new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; - new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; - new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; - new_cfg.impassible = def->has_impassible ? def->impassible : false; - new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; - - if (has_existing) { - struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[existing_index]; - free_dynamic_natural_wonder_config (cfg); - *cfg = new_cfg; - } else { - struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[dest]; - free_dynamic_natural_wonder_config (cfg); - *cfg = new_cfg; - is->natural_wonder_count = dest + 1; - stable_insert (&is->natural_wonder_name_to_id, new_cfg.name, dest); - } - - return true; -} - -void -finalize_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def, - int section_start_line, - struct error_line ** parse_errors) -{ - bool ok = true; - - if ((! def->has_name) || (def->name == NULL)) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_row) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_img_column) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - if (! def->has_terrain_type) { - ok = false; - if (parse_errors != NULL) { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: terrain_type (value is required)", section_start_line); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - if (ok) - add_natural_wonder_from_definition (def, section_start_line); - - free_parsed_natural_wonder_definition (def); -} - -void -handle_natural_wonder_definition_key (struct parsed_natural_wonder_definition * def, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if (slice_matches_str (key, "name")) { - if (def->name != NULL) { - free (def->name); - def->name = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); - } else { - char * name_copy = extract_slice (&unquoted); - if (name_copy == NULL) { - def->has_name = false; - add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); - } else { - def->name = name_copy; - def->has_name = true; - } - } - - } else if (slice_matches_str (key, "terrain_type")) { - enum SquareTypes terrain; - if (read_natural_wonder_terrain_type (value, &terrain)) { - def->terrain_type = terrain; - def->has_terrain_type = true; - } else { - def->has_terrain_type = false; - add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized terrain type)"); - } - - } else if (slice_matches_str (key, "adjacent_to")) { - enum SquareTypes adj; - if (read_tile_terrain_type_value (value, &adj)) { - def->adjacent_to = adj; - def->has_adjacent_to = true; - } else { - def->adjacent_to = (enum SquareTypes)SQ_INVALID; - def->has_adjacent_to = false; - add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized tile terrain type)"); - } - - } else if (slice_matches_str (key, "adjacency_dir")) { - enum direction dir; - if (read_direction_value (value, &dir)) { - def->adjacency_dir = dir; - def->has_adjacency_dir = true; - } else { - def->adjacency_dir = DIR_ZERO; - def->has_adjacency_dir = false; - add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized direction)"); - } - - } else if (slice_matches_str (key, "img_path")) { - if (def->img_path != NULL) { - free (def->img_path); - def->img_path = NULL; - } - - struct string_slice unquoted = trim_string_slice (value, 1); - if (unquoted.len == 0) { - def->has_img_path = false; - } else { - char * path_copy = extract_slice (&unquoted); - if (path_copy == NULL) { - def->has_img_path = false; - } else { - def->img_path = path_copy; - def->has_img_path = true; - } - } - - } else if (slice_matches_str (key, "img_row")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_row = ival; - def->has_img_row = true; - } else { - def->has_img_row = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "img_column")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->img_column = ival; - def->has_img_column = true; - } else { - def->has_img_column = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "culture_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->culture_bonus = ival; - def->has_culture_bonus = true; - } else { - def->has_culture_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "science_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->science_bonus = ival; - def->has_science_bonus = true; - } else { - def->has_science_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "food_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->food_bonus = ival; - def->has_food_bonus = true; - } else { - def->has_food_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "gold_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->gold_bonus = ival; - def->has_gold_bonus = true; - } else { - def->has_gold_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "shield_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->shield_bonus = ival; - def->has_shield_bonus = true; - } else { - def->has_shield_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "happiness_bonus")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->happiness_bonus = ival; - def->has_happiness_bonus = true; - } else { - def->has_happiness_bonus = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "impassible")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible = (ival != 0); - def->has_impassible = true; - } else { - def->has_impassible = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else if (slice_matches_str (key, "impassible_to_wheeled")) { - struct string_slice val_slice = *value; - int ival; - if (read_int (&val_slice, &ival)) { - def->impassible_to_wheeled = (ival != 0); - def->has_impassible_to_wheeled = true; - } else { - def->has_impassible_to_wheeled = false; - add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); - } - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -void -load_natural_wonder_config_file (char const * file_path, - int path_is_relative_to_mod_dir, - int log_missing, - int drop_existing_configs) -{ - char path[MAX_PATH]; - if (path_is_relative_to_mod_dir) { - if (is->mod_rel_dir == NULL) - return; - snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); - } else { - strncpy (path, file_path, sizeof path); - } - path[(sizeof path) - 1] = '\0'; - - char * text = file_to_string (path); - if (text == NULL) { - if (log_missing) { - char ss[256]; - snprintf (ss, sizeof ss, "[C3X] Natural wonders config file not found: %s", path); - (*p_OutputDebugStringA) (ss); - } - return; - } - - if (drop_existing_configs) - reset_natural_wonder_configs (); - - struct parsed_natural_wonder_definition def; - init_parsed_natural_wonder_definition (&def); - bool in_section = false; - int section_start_line = 0; - int line_number = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - bool has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { - if (in_section) - finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); - in_section = true; - section_start_line = line_number; - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); - if (status == KVP_NO_EQUALS) { - char * line_text = extract_slice (&trimmed); - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); - err->text[(sizeof err->text) - 1] = '\0'; - free (line_text); - cursor = has_newline ? line_end + 1 : line_end; - continue; - } else if (status == KVP_EMPTY_KEY) { - struct error_line * err = add_error_line (&parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); - err->text[(sizeof err->text) - 1] = '\0'; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - handle_natural_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) - finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); - - free_parsed_natural_wonder_definition (&def); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - - if (parse_errors != NULL || unrecognized_keys != NULL) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[200]; - snprintf (s, sizeof s, "Natural Wonder Config errors in %s:", path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, false); - if (parse_errors != NULL) { - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", false); - PopupForm_add_text (popup, __, "Unrecognized keys:", false); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - patch_show_popup (popup, __, 0, 0); - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); - } -} - -void -load_natural_wonder_configs () -{ - char * scenario_filename = "scenario.districts_natural_wonders_config.txt"; - char * scenario_natural_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - if ((scenario_natural_wonder_config_path != NULL) && - (0 != strcmp (scenario_filename, scenario_natural_wonder_config_path)) && - file_exists_at_path (scenario_natural_wonder_config_path)) { - load_natural_wonder_config_file (scenario_natural_wonder_config_path, 0, 0, 1); - return; - } - - if (is->mod_rel_dir != NULL) { - char user_path[MAX_PATH]; - snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_natural_wonders_config.txt"); - user_path[(sizeof user_path) - 1] = '\0'; - if (file_exists_at_path (user_path)) { - load_natural_wonder_config_file ("user.districts_natural_wonders_config.txt", 1, 0, 1); - return; - } - } - - load_natural_wonder_config_file ("default.districts_natural_wonders_config.txt", 1, 1, 1); -} - -bool -district_config_has_dependent_improvement (struct district_config * cfg, char const * name) -{ - if ((cfg == NULL) || (name == NULL) || (name[0] == '\0')) - return false; - - for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { - char const * existing = cfg->dependent_improvements[i]; - if ((existing != NULL) && (strcmp (existing, name) == 0)) - return true; - } - return false; -} - -bool -find_civ_trait_id_by_name (struct string_slice const * name, int * out_id) -{ - if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) - return false; - - struct trait_entry { enum c3x_label label; char const * fallback_name; int id; } traits[] = { - {CL_AGRICULTURAL, "Agricultural", 6}, - {CL_COMMERCIAL, "Commercial", 1}, - {CL_EXPANSIONIST, "Expansionist", 2}, - {CL_INDUSTRIOUS, "Industrious", 5}, - {CL_MILITARISTIC, "Militaristic", 0}, - {CL_RELIGIOUS, "Religious", 4}, - {CL_SCIENTIFIC, "Scientific", 3}, - {CL_SEAFARING, "Seafaring", 7} - }; - - for (int i = 0; i < ARRAY_LEN (traits); i++) { - char const * localized_name = is->c3x_labels[traits[i].label]; - if (((localized_name != NULL) && (localized_name[0] != '\0') && slice_matches_str (name, localized_name)) - || slice_matches_str (name, traits[i].fallback_name)) { - *out_id = traits[i].id; - return true; - } - } - - return false; -} - -bool -find_civ_culture_id_by_name (struct string_slice const * name, int * out_id) -{ - if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) - return false; - - struct culture_entry { char const * name; int id; } cultures[] = { - {"American", 0}, - {"AMERICAN", 0}, - {"AMER", 0}, - {"European", 1}, - {"EUROPEAN", 1}, - {"EURO", 1}, - {"Roman", 2}, - {"ROMAN", 2}, - {"Mid East", 3}, - {"Mideast", 3}, - {"MIDEAST", 3}, - {"Asian", 4}, - {"ASIAN", 4} - }; - - for (int i = 0; i < ARRAY_LEN (cultures); i++) { - if (slice_matches_str (name, cultures[i].name)) { - *out_id = cultures[i].id; - return true; - } - } - - return false; -} - -int -find_district_index_by_name (char const * name) -{ - if ((name == NULL) || (name[0] == '\0')) - return -1; - - for (int i = 0; i < is->district_count; i++) { - char const * existing = is->district_configs[i].name; - if ((existing != NULL) && (strcmp (existing, name) == 0)) - return i; - } - - return -1; -} - -void -resolve_counter_rule_districts (struct error_line ** parse_errors) -{ - struct c3x_config * cfg = &is->current_config; - - for (int i = 0; i < cfg->count_counter_rules; i++) { - struct counter_rule * rule = &cfg->counter_rules[i]; - rule->district_id = -1; - - if ((rule->district_name == NULL) || (rule->district_name[0] == '\0')) - continue; - - int district_id = find_district_index_by_name (rule->district_name); - if (district_id >= 0) { - rule->district_id = district_id; - } else { - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ counter_rule district \"%s\" not found", rule->district_name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } -} - -int -find_wonder_district_index_by_name (char const * name) -{ - if ((name == NULL) || (name[0] == '\0')) - return -1; - - int improv_id; - if (! stable_look_up (&is->building_name_to_id, (char *)name, &improv_id)) - return -1; - - return find_wonder_config_index_by_improvement_id (improv_id); -} - -int -find_natural_wonder_index_by_name (char const * name) -{ - if ((name == NULL) || (name[0] == '\0') || (is == NULL)) - return -1; - - for (int i = 0; i < is->natural_wonder_count; i++) { - char const * existing = is->natural_wonder_configs[i].name; - if ((existing != NULL) && (strcmp (existing, name) == 0)) - return i; - } - return -1; -} - -void -set_wonders_dependent_on_wonder_district (void) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_wonder_districts) - return; - - struct district_config * cfg = &is->district_configs[WONDER_DISTRICT_ID]; - for (int wi = 0; wi < is->wonder_district_count; wi++) { - char const * wonder_name = is->wonder_district_configs[wi].wonder_name; - if ((wonder_name == NULL) || (wonder_name[0] == '\0')) - continue; - if (district_config_has_dependent_improvement (cfg, wonder_name)) - continue; - - int dest = cfg->dependent_improvement_max_index; - if (dest >= ARRAY_LEN (cfg->dependent_improvements)) { - continue; - } - - char * copy = strdup (wonder_name); - if (copy == NULL) { - continue; - } - - cfg->dependent_improvements[dest] = copy; - cfg->dependent_improvement_max_index = dest + 1; - } - - if (! cfg->has_img_column_count_override && - (cfg->img_column_count < cfg->dependent_improvement_max_index + 1)) - cfg->img_column_count = cfg->dependent_improvement_max_index + 1; -} - -void -resolve_district_bonus_building_entries (struct district_bonus_list * list, - char const * district_name, - char const * bonus_name, - struct error_line ** parse_errors) -{ - if (list == NULL) - return; - - for (int i = 0; i < list->count; i++) { - struct district_bonus_entry * entry = &list->entries[i]; - if (entry->type != DBET_BUILDING) - continue; - if ((entry->building_name == NULL) || (entry->building_name[0] == '\0')) { - entry->building_id = -1; - continue; - } - - int improv_id; - struct string_slice improv_name = { .str = (char *)entry->building_name, .len = (int)strlen (entry->building_name) }; - if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { - entry->building_id = improv_id; - stable_insert (&is->building_name_to_id, improv_name.str, improv_id); - } else { - entry->building_id = -1; - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": %s entry \"%.*s\" not found", - district_name, bonus_name, improv_name.len, improv_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } -} - -void parse_building_and_tech_ids () -{ - struct c3x_config * cfg = &is->current_config; - char ss[200]; - struct error_line * district_parse_errors = NULL; - struct error_line * wonder_parse_errors = NULL; - - cfg->great_wall_auto_build_wonder_improv_id = -1; - if (cfg->enable_districts && - cfg->enable_great_wall_districts && - cfg->auto_build_great_wall_around_territory && - cfg->great_wall_auto_build_wonder_name != NULL && - cfg->great_wall_auto_build_wonder_name[0] != '\0') { - struct string_slice wonder_name = { - .str = cfg->great_wall_auto_build_wonder_name, - .len = strlen (cfg->great_wall_auto_build_wonder_name) - }; - if (! find_improv_id_by_name (&wonder_name, &cfg->great_wall_auto_build_wonder_improv_id)) { - snprintf (ss, sizeof ss, - "Error reading config: The value for \"great_wall_auto_build_wonder_name\" is invalid: \"%s\"", - cfg->great_wall_auto_build_wonder_name); - ss[(sizeof ss) - 1] = '\0'; - pop_up_in_game_error (ss); - } - } - - for (int i = 0; i < is->district_count; i++) { - char const * district_name = (is->district_configs[i].name != NULL) ? is->district_configs[i].name : "District"; - if (! district_is_included_by_final_config (i)) { - is->district_infos[i].advance_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) - is->district_infos[i].advance_prereq_ids[j] = -1; - is->district_infos[i].obsoleted_by_id = -1; - is->district_infos[i].resource_prereq_count = 0; - for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) - is->district_infos[i].resource_prereq_ids[j] = -1; - is->district_infos[i].resource_prereq_on_tile_id = -1; - is->district_infos[i].wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) - is->district_infos[i].wonder_prereq_ids[j] = -1; - is->district_infos[i].natural_wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) - is->district_infos[i].natural_wonder_prereq_ids[j] = -1; - is->district_infos[i].dependent_building_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) - is->district_infos[i].dependent_building_ids[j] = -1; - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) - is->district_configs[i].buildable_on_district_ids[j] = -1; - is->district_configs[i].buildable_on_district_id_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) - is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; - is->district_configs[i].buildable_adjacent_to_district_id_count = 0; - is->district_configs[i].generated_resource_id = -1; - continue; - } - if ((is->district_configs[i].name != NULL) && - (is->district_configs[i].command != 0) && - (is->district_configs[i].command != -1)) - itable_insert (&is->command_id_to_district_id, is->district_configs[i].command, i); - is->district_infos[i].advance_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) - is->district_infos[i].advance_prereq_ids[j] = -1; - is->district_infos[i].obsoleted_by_id = -1; - is->district_infos[i].resource_prereq_count = 0; - for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) - is->district_infos[i].resource_prereq_ids[j] = -1; - is->district_infos[i].resource_prereq_on_tile_id = -1; - is->district_infos[i].wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) - is->district_infos[i].wonder_prereq_ids[j] = -1; - is->district_infos[i].natural_wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) - is->district_infos[i].natural_wonder_prereq_ids[j] = -1; - - // Map advance prereqs to districts - int stored_tech_count = 0; - for (int j = 0; j < is->district_configs[i].advance_prereq_count; j++) { - char const * prereq = is->district_configs[i].advance_prereqs[j]; - if (prereq == NULL || prereq[0] == '\0') - continue; - int tech_id; - struct string_slice tech_name = { .str = (char *)prereq, .len = (int)strlen (prereq) }; - if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { - snprintf (ss, sizeof ss, "Found tech prereq \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); - (*p_OutputDebugStringA) (ss); - if (stored_tech_count < ARRAY_LEN (is->district_infos[i].advance_prereq_ids)) { - is->district_infos[i].advance_prereq_ids[stored_tech_count] = tech_id; - stored_tech_count++; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": advance_prereqs entry \"%.*s\" not found", district_name, tech_name.len, tech_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].advance_prereq_count = stored_tech_count; - - // Map obsoleted_by to tech ID - if (is->district_configs[i].obsoleted_by != NULL && is->district_configs[i].obsoleted_by != "") { - int tech_id; - struct string_slice tech_name = { .str = (char *)is->district_configs[i].obsoleted_by, .len = (int)strlen (is->district_configs[i].obsoleted_by) }; - if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { - snprintf (ss, sizeof ss, "Found tech obsoleted_by \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); - (*p_OutputDebugStringA) (ss); - is->district_infos[i].obsoleted_by_id = tech_id; - } else { - is->district_infos[i].obsoleted_by_id = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": obsoleted_by \"%.*s\" not found", district_name, tech_name.len, tech_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - // Map resource prereqs to districts (multiple resources now supported) - int stored_res_count = 0; - for (int j = 0; j < is->district_configs[i].resource_prereq_count; j++) { - if (is->district_configs[i].resource_prereqs[j] == "" || is->district_configs[i].resource_prereqs[j] == NULL) - continue; - int res_id; - struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereqs[j], .len = (int)strlen (is->district_configs[i].resource_prereqs[j]) }; - if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { - snprintf (ss, sizeof ss, "Found resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); - (*p_OutputDebugStringA) (ss); - if (stored_res_count < ARRAY_LEN (is->district_infos[i].resource_prereq_ids)) { - is->district_infos[i].resource_prereq_ids[stored_res_count] = res_id; - stored_res_count++; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq \"%.*s\" not found", district_name, res_name.len, res_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].resource_prereq_count = stored_res_count; - if (is->district_configs[i].resource_prereq_on_tile != NULL && is->district_configs[i].resource_prereq_on_tile != "") { - int res_id; - struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereq_on_tile, .len = (int)strlen (is->district_configs[i].resource_prereq_on_tile) }; - if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { - snprintf (ss, sizeof ss, "Found on-tile resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); - (*p_OutputDebugStringA) (ss); - is->district_infos[i].resource_prereq_on_tile_id = res_id; - } else { - is->district_infos[i].resource_prereq_on_tile_id = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq_on_tile \"%.*s\" not found", district_name, res_name.len, res_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - int stored_wonder_count = 0; - for (int j = 0; j < is->district_configs[i].wonder_prereq_count; j++) { - if (is->district_configs[i].wonder_prereqs[j] == "" || is->district_configs[i].wonder_prereqs[j] == NULL) - continue; - int improv_id; - struct string_slice wonder_name = { .str = (char *)is->district_configs[i].wonder_prereqs[j], .len = (int)strlen (is->district_configs[i].wonder_prereqs[j]) }; - if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { - if (stored_wonder_count < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids)) { - is->district_infos[i].wonder_prereq_ids[stored_wonder_count] = improv_id; - stored_wonder_count += 1; - } - stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": wonder_prereqs entry \"%.*s\" not found", district_name, wonder_name.len, wonder_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].wonder_prereq_count = stored_wonder_count; - - int stored_natural_wonder_count = 0; - for (int j = 0; j < is->district_configs[i].natural_wonder_prereq_count; j++) { - if (is->district_configs[i].natural_wonder_prereqs[j] == "" || is->district_configs[i].natural_wonder_prereqs[j] == NULL) - continue; - int natural_wonder_id = -1; - char const * name = is->district_configs[i].natural_wonder_prereqs[j]; - if (stable_look_up (&is->natural_wonder_name_to_id, (char *)name, &natural_wonder_id)) { - if (stored_natural_wonder_count < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids)) { - is->district_infos[i].natural_wonder_prereq_ids[stored_natural_wonder_count] = natural_wonder_id; - stored_natural_wonder_count += 1; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": natural_wonder_prereqs entry \"%s\" not found", district_name, name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_infos[i].natural_wonder_prereq_count = stored_natural_wonder_count; - - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) - is->district_configs[i].buildable_on_district_ids[j] = -1; - is->district_configs[i].buildable_on_district_id_count = 0; - - if (is->district_configs[i].has_buildable_on_districts) { - int stored_buildable_on_count = 0; - for (int j = 0; j < is->district_configs[i].buildable_on_district_count; j++) { - char const * name = is->district_configs[i].buildable_on_districts[j]; - if (name == NULL || name[0] == '\0') - continue; - int other_district_id = find_district_index_by_name (name); - if (other_district_id >= 0) { - if (stored_buildable_on_count < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids)) { - is->district_configs[i].buildable_on_district_ids[stored_buildable_on_count] = other_district_id; - stored_buildable_on_count += 1; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_on_districts entry \"%s\" not found", district_name, name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_configs[i].buildable_on_district_id_count = stored_buildable_on_count; - } - - for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) - is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; - is->district_configs[i].buildable_adjacent_to_district_id_count = 0; - - if (is->district_configs[i].has_buildable_adjacent_to_districts) { - int stored_adjacent_count = 0; - for (int j = 0; j < is->district_configs[i].buildable_adjacent_to_district_count; j++) { - char const * name = is->district_configs[i].buildable_adjacent_to_districts[j]; - if (name == NULL || name[0] == '\0') - continue; - int other_district_id = find_district_index_by_name (name); - if (other_district_id >= 0) { - if (stored_adjacent_count < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids)) { - is->district_configs[i].buildable_adjacent_to_district_ids[stored_adjacent_count] = other_district_id; - stored_adjacent_count += 1; - } - } else { - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_adjacent_to_districts entry \"%s\" not found", district_name, name); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - is->district_configs[i].buildable_adjacent_to_district_id_count = stored_adjacent_count; - } - - // Resolve generated resource name to ID - if (is->district_configs[i].generated_resource != NULL && is->district_configs[i].generated_resource != "") { - int res_id; - struct string_slice res_name = { .str = (char *)is->district_configs[i].generated_resource, .len = (int)strlen (is->district_configs[i].generated_resource) }; - if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { - snprintf (ss, sizeof ss, "Found generated resource \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); - (*p_OutputDebugStringA) (ss); - is->district_configs[i].generated_resource_id = res_id; - } else { - is->district_configs[i].generated_resource_id = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": generated_resource \"%.*s\" not found", district_name, res_name.len, res_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - // Map improvement prereqs to districts - int stored_count = 0; - for (int j = 0; j < is->district_configs[i].dependent_improvement_max_index; j++) { - int improv_id; - if (is->district_configs[i].dependent_improvements[j] == "" || is->district_configs[i].dependent_improvements[j] == NULL) - continue; - - // Gate wonder district prereqs behind enable_wonder_districts - if ((is->district_configs[i].command == UCV_Build_WonderDistrict) && (! cfg->enable_wonder_districts)) - continue; - - struct string_slice improv_name = { .str = (char *)is->district_configs[i].dependent_improvements[j], .len = (int)strlen (is->district_configs[i].dependent_improvements[j]) }; - if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { - snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for district \"%s\", ID %d\n", improv_name.len, improv_name.str, district_name, improv_id); - (*p_OutputDebugStringA) (ss); - if (stored_count < ARRAY_LEN (is->district_infos[i].dependent_building_ids)) { - is->district_infos[i].dependent_building_ids[stored_count] = improv_id; - stored_count += 1; - } - add_district_building_prereq (improv_id, i); - stable_insert (&is->building_name_to_id, improv_name.str, improv_id); - } else { - is->district_infos[i].dependent_building_ids[j] = -1; - struct error_line * err = add_error_line (&district_parse_errors); - snprintf (err->text, sizeof err->text, "^ District \"%s\": dependent_improvs entry \"%.*s\" not found", district_name, improv_name.len, improv_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - is->district_infos[i].dependent_building_count = stored_count; - } - - resolve_district_bonus_building_entries (&is->district_configs[i].culture_bonus_extras, district_name, "culture_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].science_bonus_extras, district_name, "science_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].food_bonus_extras, district_name, "food_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].gold_bonus_extras, district_name, "gold_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].shield_bonus_extras, district_name, "shield_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].happiness_bonus_extras, district_name, "happiness_bonus", &district_parse_errors); - resolve_district_bonus_building_entries (&is->district_configs[i].defense_bonus_extras, district_name, "defense_bonus_percent", &district_parse_errors); - } - - resolve_counter_rule_districts (&district_parse_errors); - - // Map wonder names to their improvement IDs for rendering under-construction wonders - for (int wi = 0; wi < is->wonder_district_count; wi++) { - if (is->wonder_district_configs[wi].wonder_name == NULL || is->wonder_district_configs[wi].wonder_name[0] == '\0') - continue; - - int improv_id; - struct string_slice wonder_name = { .str = (char *)is->wonder_district_configs[wi].wonder_name, .len = (int)strlen (is->wonder_district_configs[wi].wonder_name) }; - if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { - snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for wonder district \"%s\", ID %d\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name, improv_id); - (*p_OutputDebugStringA) (ss); - stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); - } else { - snprintf (ss, sizeof ss, "Could not find improvement prereq \"%.*s\" for wonder district \"%s\"\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name); - (*p_OutputDebugStringA) (ss); - struct error_line * err = add_error_line (&wonder_parse_errors); - snprintf (err->text, sizeof err->text, "^ Wonder district \"%s\": improvement \"%.*s\" not found", (is->wonder_district_configs[wi].wonder_name != NULL) ? is->wonder_district_configs[wi].wonder_name : "Wonder District", wonder_name.len, wonder_name.str); - err->text[(sizeof err->text) - 1] = '\0'; - } - } - - if ((district_parse_errors != NULL) || (wonder_parse_errors != NULL)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - - if (district_parse_errors != NULL) { - char header[256]; - if (is->current_districts_config_path[0] != '\0') - snprintf (header, sizeof header, "District Config errors in %s:", is->current_districts_config_path); - else - snprintf (header, sizeof header, "District Config lookup errors:"); - header[(sizeof header) - 1] = '\0'; - PopupForm_add_text (popup, __, header, false); - for (struct error_line * line = district_parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - - if ((district_parse_errors != NULL) && (wonder_parse_errors != NULL)) - PopupForm_add_text (popup, __, "", false); - - if (wonder_parse_errors != NULL) { - char header[256]; - snprintf (header, sizeof header, "Wonder District Config lookup errors:"); - header[(sizeof header) - 1] = '\0'; - PopupForm_add_text (popup, __, header, false); - for (struct error_line * line = wonder_parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, false); - } - - patch_show_popup (popup, __, 0, 0); - free_error_lines (district_parse_errors); - free_error_lines (wonder_parse_errors); - } -} - -void -load_districts_config () -{ - clear_dynamic_district_definitions (); - load_dynamic_district_configs (); - load_dynamic_wonder_configs (); - load_natural_wonder_configs (); - is->district_count = is->special_district_count + is->dynamic_district_count; - - set_wonders_dependent_on_wonder_district (); - parse_building_and_tech_ids (); -} - -void -place_natural_wonders_on_map (void) -{ - if (! is->current_config.enable_natural_wonders) - return; - - int wonder_count = is->natural_wonder_count; - if (wonder_count <= 0) - return; - - struct natural_wonder_candidate_list * candidate_lists = (struct natural_wonder_candidate_list *)calloc (wonder_count, sizeof *candidate_lists); - bool * already_placed = (bool *)calloc (wonder_count, sizeof *already_placed); - - if ((candidate_lists == NULL) || (already_placed == NULL)) { - if (candidate_lists != NULL) free (candidate_lists); - if (already_placed != NULL) free (already_placed); - return; - } - - struct wonder_location * placements = NULL; - int placement_count = 0; - int placement_capacity = 0; - int existing_count = 0; - - // Record existing natural wonders - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - - int wonder_id = inst->natural_wonder_info.natural_wonder_id; - if ((wonder_id < 0) || (wonder_id >= wonder_count)) - continue; - - already_placed[wonder_id] = true; - - Tile * tile = (Tile *)tei.key; - int tile_x, tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - continue; - - if (placement_count >= placement_capacity) { - int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; - struct wonder_location * grown = - (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); - if (grown == NULL) - continue; - placements = grown; - placement_capacity = new_capacity; - } - - if (placements != NULL) { - placements[placement_count++] = (struct wonder_location){ - .x = (short)tile_x, - .y = (short)tile_y - }; - existing_count += 1; - } - } - - // Build candidate lists - int map_width = p_bic_data->Map.Width; - int map_height = p_bic_data->Map.Height; - int minimum_separation = is->current_config.minimum_natural_wonder_separation; - - for (int y = 0; y < map_height; y++) { - for (int x = 0; x < map_width; x++) { - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - if (! natural_wonder_tile_is_clear (tile, x, y)) continue; - if (district_exists_within_distance (x, y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; - - for (int ni = 0; ni < wonder_count; ni++) { - if (already_placed[ni]) - continue; - - struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; - if (cfg->name == NULL) - continue; - - if (! natural_wonder_terrain_matches (cfg, tile, x, y)) - continue; - - natural_wonder_candidate_list_push (&candidate_lists[ni], tile, x, y); - } - } - } - - bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; - int newly_placed = 0; - int * wonder_order = (int *)malloc (wonder_count * sizeof *wonder_order); - if (wonder_order != NULL) { - for (int i = 0; i < wonder_count; i++) - wonder_order[i] = i; - for (int i = wonder_count - 1; i > 0; i--) { - int swap_index = rand_int (p_rand_object, __, i + 1); - int temp = wonder_order[i]; - wonder_order[i] = wonder_order[swap_index]; - wonder_order[swap_index] = temp; - } - } - - for (int order_index = 0; order_index < wonder_count; order_index++) { - int ni = (wonder_order != NULL) ? wonder_order[order_index] : order_index; - if (already_placed[ni]) - continue; - - struct natural_wonder_candidate_list * list = &candidate_lists[ni]; - if (list->count == 0) { - char msg[256]; - snprintf (msg, sizeof msg, "[C3X] No valid tiles to place natural wonder \"%s\".\n", - (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); - (*p_OutputDebugStringA) (msg); - continue; - } - - int best_index = -1; - int best_dist = -1; - int best_adjacent_count = -1; - int best_target_diff = INT_MAX; - int best_rand = INT_MAX; - int best_same_type_count = -1; - int best_continent_priority = INT_MAX; - int target_x = (wonder_count > 0) - ? (int)(((long long)(2 * ni + 1) * map_width) / (2 * wonder_count)) - : (map_width >> 1); - - for (int ci = 0; ci < list->count; ci++) { - struct natural_wonder_candidate * cand = &list->entries[ci]; - Tile * tile = cand->tile; - if ((tile == NULL) || (tile == p_null_tile)) continue; - if (get_district_instance (tile) != NULL) continue; - if (! natural_wonder_tile_is_clear (tile, cand->x, cand->y)) continue; - if (! natural_wonder_terrain_matches (&is->natural_wonder_configs[ni], tile, cand->x, cand->y)) continue; - if (district_exists_within_distance (cand->x, cand->y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; - - int min_dist_sq = natural_wonder_min_distance_sq (cand->x, cand->y, placements, placement_count); - if (min_dist_sq == INT_MAX) { - int span = (map_width * map_width) + (map_height * map_height); - if (span <= 0) - span = INT_MAX; - min_dist_sq = span; - } - - int dx_raw = int_abs (cand->x - target_x); - int dx_adjusted = compute_wrapped_component (dx_raw, map_width, wraps_horiz); - int rand_val = rand_int (p_rand_object, __, 0x7FFF); - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - int continent_priority = 1; - if ((continent_id >= 0) && ! continent_has_natural_wonder (continent_id, placements, placement_count)) - continent_priority = 0; - - bool adjacency_bonus_active = - (is->natural_wonder_configs[ni].adjacent_to != (enum SquareTypes)SQ_INVALID) && - (is->natural_wonder_configs[ni].adjacency_dir == DIR_ZERO); - int adjacency_count = -1; - if (adjacency_bonus_active) - adjacency_count = count_adjacent_tiles_of_type (cand->x, cand->y, - is->natural_wonder_configs[ni].adjacent_to); - - int same_type_count = count_adjacent_tiles_of_type (cand->x, cand->y, - is->natural_wonder_configs[ni].terrain_type); - - bool better = false; - if (continent_priority < best_continent_priority) - better = true; - else if (continent_priority > best_continent_priority) - continue; - - if (! better && adjacency_bonus_active) { - if (adjacency_count > best_adjacent_count) - better = true; - else if (adjacency_count < best_adjacent_count) - continue; - } - - if (! better) { - if (same_type_count > best_same_type_count) - better = true; - else if (same_type_count < best_same_type_count) - continue; - } - - if (! better) { - if ((min_dist_sq > best_dist) || - ((min_dist_sq == best_dist) && (dx_adjusted < best_target_diff)) || - ((min_dist_sq == best_dist) && (dx_adjusted == best_target_diff) && (rand_val < best_rand))) - better = true; - else - continue; - } - - best_dist = min_dist_sq; - best_target_diff = dx_adjusted; - best_rand = rand_val; - best_index = ci; - best_continent_priority = continent_priority; - if (adjacency_bonus_active) - best_adjacent_count = adjacency_count; - best_same_type_count = same_type_count; - } - - if (best_index < 0) { - char msg[256]; - snprintf (msg, sizeof msg, "[C3X] Could not find a suitable tile for natural wonder \"%s\" after filtering.\n", - (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); - (*p_OutputDebugStringA) (msg); - continue; - } - - struct natural_wonder_candidate * chosen = &list->entries[best_index]; - assign_natural_wonder_to_tile (chosen->tile, chosen->x, chosen->y, ni); - - if (placement_count >= placement_capacity) { - int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; - struct wonder_location * grown = - (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); - if (grown != NULL) { - placements = grown; - placement_capacity = new_capacity; - } - } - - if ((placements != NULL) && (placement_count < placement_capacity)) { - placements[placement_count++] = (struct wonder_location){ - .x = chosen->x, - .y = chosen->y - }; - } - - newly_placed += 1; - - char msg[256]; - snprintf (msg, sizeof msg, "[C3X] Placed natural wonder \"%s\" at (%d,%d).\n", - (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder", - chosen->x, chosen->y); - (*p_OutputDebugStringA) (msg); - } - - char summary[256]; - snprintf (summary, sizeof summary, "[C3X] Natural wonder placement complete. Newly placed: %d, already present: %d.\n", - newly_placed, existing_count); - (*p_OutputDebugStringA) (summary); - - for (int ni = 0; ni < wonder_count; ni++) - free (candidate_lists[ni].entries); - free (wonder_order); - free (candidate_lists); - free (already_placed); - free (placements); -} - -void -init_scenario_district_entry (struct scenario_district_entry * entry) -{ - if (entry == NULL) - return; - - memset (entry, 0, sizeof *entry); -} - -void -init_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) -{ - if (entry == NULL) - return; - - memset (entry, 0, sizeof *entry); -} - -void -free_scenario_district_entry (struct scenario_district_entry * entry) -{ - if (entry == NULL) - return; - - if (entry->district_name != NULL) { - free (entry->district_name); - entry->district_name = NULL; - } - if (entry->wonder_city_name != NULL) { - free (entry->wonder_city_name); - entry->wonder_city_name = NULL; - } - if (entry->wonder_name != NULL) { - free (entry->wonder_name); - entry->wonder_name = NULL; - } - entry->has_coordinates = 0; - entry->has_district_name = 0; - entry->has_wonder_city = 0; - entry->has_wonder_name = 0; -} - -void -free_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) -{ - if (entry == NULL) - return; - - if (entry->name != NULL) { - free (entry->name); - entry->name = NULL; - } - entry->has_coordinates = 0; - entry->has_name = 0; -} - -void -add_scenario_district_error (struct error_line ** parse_errors, - int line_number, - char const * message) -{ - if (message == NULL) - return; - - struct error_line * err = add_error_line (parse_errors); - snprintf (err->text, sizeof err->text, "^ Line %d: %s", line_number, message); - err->text[(sizeof err->text) - 1] = '\0'; -} - -int -parse_scenario_district_coordinates (struct string_slice const * value, int * out_x, int * out_y) -{ - if ((value == NULL) || (out_x == NULL) || (out_y == NULL)) - return 0; - - char * text = trim_and_extract_slice (value, 0); - if (text == NULL) - return 0; - - char * cursor = text; - int success = 0; - int x, y; - if (parse_int (&cursor, &x) && - skip_punctuation (&cursor, ',') && - parse_int (&cursor, &y)) { - skip_horiz_space (&cursor); - success = (*cursor == '\0'); - if (success) { - *out_x = x; - *out_y = y; - } - } - - free (text); - return success; -} - -int -finalize_scenario_district_entry (struct scenario_district_entry * entry, - int section_start_line, - struct error_line ** parse_errors) -{ - int success = 1; - if ((entry == NULL) || (parse_errors == NULL)) - return 0; - - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return 1; - } - - if (! entry->has_coordinates) - add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); - if ((! entry->has_district_name) || (entry->district_name == NULL) || (entry->district_name[0] == '\0')) - add_scenario_district_error (parse_errors, section_start_line, "district (value is required)"); - - if ((! entry->has_coordinates) || (! entry->has_district_name) || - (entry->district_name == NULL) || (entry->district_name[0] == '\0')) - success = 0; - - int map_x = entry->tile_x; - int map_y = entry->tile_y; - if (success) { - wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); - Tile * tile = tile_at (map_x, map_y); - if ((tile == NULL) || (tile == p_null_tile)) { - add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); - success = 0; - } else { - int district_id = find_district_index_by_name (entry->district_name); - if ((district_id < 0) || (district_id >= is->district_count)) { - char msg[200]; - snprintf (msg, sizeof msg, "district (unrecognized name: \"%s\")", entry->district_name); - add_scenario_district_error (parse_errors, section_start_line, msg); - success = 0; - } else { - if ((district_id == NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_natural_wonders) { - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return 1; - } - if ((district_id != NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_districts) { - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return 1; - } - struct district_instance * inst = ensure_district_instance (tile, district_id, map_x, map_y); - if (inst == NULL) { - add_scenario_district_error (parse_errors, section_start_line, "Failed to create district instance"); - success = 0; - } else { - inst->district_id = district_id; - district_instance_set_coords (inst, map_x, map_y); - inst->state = DS_COMPLETED; - inst->wonder_info.state = WDS_UNUSED; - inst->wonder_info.city = NULL; - inst->wonder_info.city_id = -1; - inst->wonder_info.wonder_index = -1; - inst->natural_wonder_info.natural_wonder_id = -1; - - if (district_id == WONDER_DISTRICT_ID) { - int has_city = entry->has_wonder_city && - (entry->wonder_city_name != NULL) && (entry->wonder_city_name[0] != '\0'); - int has_wonder = entry->has_wonder_name && - (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); - if (! has_city || ! has_wonder) { - add_scenario_district_error (parse_errors, section_start_line, "Wonder district requires both wonder_city and wonder_name"); - success = 0; - } else { - int wonder_index = find_wonder_district_index_by_name (entry->wonder_name); - if (wonder_index < 0) { - char msg[200]; - snprintf (msg, sizeof msg, "wonder_name (unrecognized wonder: \"%s\")", entry->wonder_name); - add_scenario_district_error (parse_errors, section_start_line, msg); - success = 0; - } else { - inst->wonder_info.city = NULL; - inst->wonder_info.city_id = -1; - inst->wonder_info.state = WDS_COMPLETED; - inst->wonder_info.wonder_index = wonder_index; - } - } - } else if (district_id == NATURAL_WONDER_DISTRICT_ID) { - int has_name = entry->has_wonder_name && - (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); - if (! has_name) { - add_scenario_district_error (parse_errors, section_start_line, "Natural Wonder district requires wonder_name"); - success = 0; - } else { - int natural_index = find_natural_wonder_index_by_name (entry->wonder_name); - if (natural_index < 0) { - char msg[200]; - snprintf (msg, sizeof msg, "wonder_name (unrecognized natural wonder: \"%s\")", entry->wonder_name); - add_scenario_district_error (parse_errors, section_start_line, msg); - success = 0; - } else - inst->natural_wonder_info.natural_wonder_id = natural_index; - } - if (entry->has_wonder_city) - add_scenario_district_error (parse_errors, section_start_line, "wonder_city ignored for Natural Wonder district entries"); - } else if (entry->has_wonder_city || entry->has_wonder_name) { - add_scenario_district_error (parse_errors, section_start_line, "wonder_* fields only valid for Wonder or Natural Wonder district entries"); - } - - if (success) { - if (district_id != NATURAL_WONDER_DISTRICT_ID && !tile->vtable->m18_Check_Mines (tile, __, 0)) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, map_x, map_y); - set_tile_unworkable_for_all_cities (tile, map_x, map_y); - } - } - } - } - } - - free_scenario_district_entry (entry); - init_scenario_district_entry (entry); - return success; -} - -bool -tile_can_be_named (Tile * tile, int tile_x, int tile_y) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) - return false; - return true; -} - -void -remove_named_tile_entry (Tile * tile) -{ - struct named_tile_entry * entry = get_named_tile_entry (tile); - if (entry == NULL) - return; - itable_remove (&is->named_tile_map, (int)tile); - free (entry); -} - -void -set_named_tile_entry (Tile * tile, int tile_x, int tile_y, char const * name) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return; - if ((name == NULL) || (name[0] == '\0')) { - remove_named_tile_entry (tile); - return; - } - - struct named_tile_entry * entry = get_named_tile_entry (tile); - if (entry == NULL) { - entry = calloc (1, sizeof *entry); - if (entry == NULL) - return; - itable_insert (&is->named_tile_map, (int)tile, (int)entry); - } - entry->tile_x = tile_x; - entry->tile_y = tile_y; - strncpy (entry->name, name, sizeof entry->name); - entry->name[(sizeof entry->name) - 1] = '\0'; -} - -int -finalize_scenario_named_tile_entry (struct scenario_named_tile_entry * entry, - int section_start_line, - struct error_line ** parse_errors) -{ - int success = 1; - if ((entry == NULL) || (parse_errors == NULL)) - return 0; - - if (! is->current_config.enable_named_tiles) { - free_scenario_named_tile_entry (entry); - init_scenario_named_tile_entry (entry); - return 1; - } - - if (! entry->has_coordinates) - add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); - if ((! entry->has_name) || (entry->name == NULL) || (entry->name[0] == '\0')) - add_scenario_district_error (parse_errors, section_start_line, "name (value is required)"); - - if ((! entry->has_coordinates) || (! entry->has_name) || - (entry->name == NULL) || (entry->name[0] == '\0')) - success = 0; - - int map_x = entry->tile_x; - int map_y = entry->tile_y; - if (success) { - wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); - Tile * tile = tile_at (map_x, map_y); - if ((tile == NULL) || (tile == p_null_tile)) { - add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); - success = 0; - } else if (! tile_can_be_named (tile, map_x, map_y)) { - add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile cannot be named)"); - success = 0; - } else { - set_named_tile_entry (tile, map_x, map_y, entry->name); - } - } - - free_scenario_named_tile_entry (entry); - init_scenario_named_tile_entry (entry); - return success; -} - -void -handle_scenario_district_key (struct scenario_district_entry * entry, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if ((entry == NULL) || (key == NULL) || (value == NULL)) - return; - - if (slice_matches_str (key, "coordinates")) { - int x, y; - if (parse_scenario_district_coordinates (value, &x, &y)) { - entry->tile_x = x; - entry->tile_y = y; - entry->has_coordinates = 1; - } else - add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); - - } else if (slice_matches_str (key, "district")) { - if (entry->district_name != NULL) { - free (entry->district_name); - entry->district_name = NULL; - } - entry->district_name = copy_trimmed_string_or_null (value, 1); - entry->has_district_name = (entry->district_name != NULL); - if (! entry->has_district_name) - add_scenario_district_error (parse_errors, line_number, "district (value is required)"); - - } else if (slice_matches_str (key, "wonder_city")) { - if (entry->wonder_city_name != NULL) { - free (entry->wonder_city_name); - entry->wonder_city_name = NULL; - } - entry->wonder_city_name = copy_trimmed_string_or_null (value, 1); - entry->has_wonder_city = (entry->wonder_city_name != NULL); - - } else if (slice_matches_str (key, "wonder_name")) { - if (entry->wonder_name != NULL) { - free (entry->wonder_name); - entry->wonder_name = NULL; - } - entry->wonder_name = copy_trimmed_string_or_null (value, 1); - entry->has_wonder_name = (entry->wonder_name != NULL); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -void -handle_scenario_named_tile_key (struct scenario_named_tile_entry * entry, - struct string_slice const * key, - struct string_slice const * value, - int line_number, - struct error_line ** parse_errors, - struct error_line ** unrecognized_keys) -{ - if ((entry == NULL) || (key == NULL) || (value == NULL)) - return; - - if (slice_matches_str (key, "coordinates")) { - int x, y; - if (parse_scenario_district_coordinates (value, &x, &y)) { - entry->tile_x = x; - entry->tile_y = y; - entry->has_coordinates = 1; - } else - add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); - - } else if (slice_matches_str (key, "name")) { - if (entry->name != NULL) { - free (entry->name); - entry->name = NULL; - } - entry->name = copy_trimmed_string_or_null (value, 1); - entry->has_name = (entry->name != NULL); - if (! entry->has_name) - add_scenario_district_error (parse_errors, line_number, "name (value is required)"); - - } else - add_unrecognized_key_error (unrecognized_keys, line_number, key); -} - -// Parses a .c3x.txt file corresponding to the given scenario file path, loading district instances as specified. -// -// The expected file format itself is very simple. Example: -// -// ``` -// DISTRICTS -// -// #District -// coordinates = 12,28 -// district = Entertainment Complex -// -// #District -// coordinates = 9,23 -// district = Wonder District -// wonder_city = Rome -// wonder_name = The Pyramids -// -// #District -// coordinates = 10,30 -// district = Natural Wonder -// wonder_name = Mount Everest -// -// #NamedTile -// coordinates = 41,23 -// name = Tiber River -// ``` -// -// Details at https://github.com/instafluff0/Civ3_Editor_Fork_for_C3X_Districts -void -load_scenario_districts_from_file () -{ - char * scenario_filename = "scenario.districts.txt"; - char * scenario_districts_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); - - // BIC_get_asset_path returns the file name when it can't find the file - if ((scenario_districts_path == NULL) || (0 == strcmp (scenario_filename, scenario_districts_path))) - return; - - char * text = file_to_string (scenario_districts_path); - if (text == NULL) - return; - - struct scenario_district_entry entry; - struct scenario_named_tile_entry named_entry; - init_scenario_district_entry (&entry); - init_scenario_named_tile_entry (&named_entry); - int in_section = 0; - int section_start_line = 0; - int section_type = 0; - int line_number = 0; - int header_seen = 0; - struct error_line * unrecognized_keys = NULL; - struct error_line * parse_errors = NULL; - - char * cursor = text; - while (*cursor != '\0') { - line_number += 1; - - char * line_start = cursor; - char * line_end = cursor; - while ((*line_end != '\0') && (*line_end != '\n')) - line_end++; - - int line_len = line_end - line_start; - int has_newline = (*line_end == '\n'); - if (has_newline) - *line_end = '\0'; - - struct string_slice line_slice = { .str = line_start, .len = line_len }; - struct string_slice trimmed = trim_string_slice (&line_slice, 0); - if (line_is_empty_or_comment (&trimmed)) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - // Keep support for legacy header, technically not needed - if (! header_seen) { - if (slice_matches_str (&trimmed, "DISTRICTS")) { - header_seen = 1; - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - } - - if (trimmed.str[0] == '#') { - struct string_slice directive = trimmed; - directive.str += 1; - directive.len -= 1; - directive = trim_string_slice (&directive, 0); - if (slice_matches_str (&directive, "District")) { - if (in_section) { - if (section_type == 1) - finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); - else if (section_type == 2) - finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); - } - in_section = 1; - section_type = 1; - section_start_line = line_number; - free_scenario_district_entry (&entry); - init_scenario_district_entry (&entry); - } else if (slice_matches_str (&directive, "NamedTile")) { - if (in_section) { - if (section_type == 1) - finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); - else if (section_type == 2) - finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); - } - in_section = 1; - section_type = 2; - section_start_line = line_number; - free_scenario_named_tile_entry (&named_entry); - init_scenario_named_tile_entry (&named_entry); - } - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - if (! in_section) { - cursor = has_newline ? line_end + 1 : line_end; - continue; - } - - struct string_slice key_slice = {0}; - struct string_slice value_slice = {0}; - switch (parse_trimmed_key_value (&trimmed, &key_slice, &value_slice)) { - case KVP_NO_EQUALS: - add_scenario_district_error (&parse_errors, line_number, "(expected '=')"); - break; - case KVP_EMPTY_KEY: - add_scenario_district_error (&parse_errors, line_number, "(missing key)"); - break; - case KVP_SUCCESS: - if (section_type == 1) - handle_scenario_district_key (&entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - else if (section_type == 2) - handle_scenario_named_tile_key (&named_entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); - break; - } - - cursor = has_newline ? line_end + 1 : line_end; - } - - if (in_section) { - if (section_type == 1) - finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); - else if (section_type == 2) - finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); - } - - free_scenario_district_entry (&entry); - free_scenario_named_tile_entry (&named_entry); - free (text); - - // Append to loaded config names list - struct loaded_config_name * top_lcn = is->loaded_config_names; - while (top_lcn->next != NULL) - top_lcn = top_lcn->next; - - struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); - new_lcn->name = strdup (scenario_districts_path); - new_lcn->next = NULL; - - top_lcn->next = new_lcn; - - if ((parse_errors != NULL) || (unrecognized_keys != NULL)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char header[256]; - snprintf (header, sizeof header, "District scenario file issues in %s:", scenario_districts_path); - header[(sizeof header) - 1] = '\0'; - PopupForm_add_text (popup, __, header, 0); - if (parse_errors != NULL) - for (struct error_line * line = parse_errors; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, 0); - if (unrecognized_keys != NULL) { - PopupForm_add_text (popup, __, "", 0); - PopupForm_add_text (popup, __, "Unrecognized keys:", 0); - for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) - PopupForm_add_text (popup, __, line->text, 0); - } - patch_show_popup (popup, __, 0, 0); - } - - free_error_lines (parse_errors); - free_error_lines (unrecognized_keys); -} - -void -deinit_district_images (void) -{ - if (is->dc_img_state == IS_OK) { - for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) { - for (int variant = 0; variant < ARRAY_LEN (is->district_img_sets[dc].imgs); variant++) - for (int era = 0; era < 4; era++) - for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc].imgs[variant][era]); col++) { - Sprite * sprite = &is->district_img_sets[dc].imgs[variant][era][col]; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - } - - for (int wi = 0; wi < MAX_WONDER_DISTRICT_TYPES; wi++) { - struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; - if (set->img.vtable != NULL) - set->img.vtable->destruct (&set->img, __, 0); - if (set->construct_img.vtable != NULL) - set->construct_img.vtable->destruct (&set->construct_img, __, 0); - if (set->alt_dir_img.vtable != NULL) - set->alt_dir_img.vtable->destruct (&set->alt_dir_img, __, 0); - if (set->alt_dir_construct_img.vtable != NULL) - set->alt_dir_construct_img.vtable->destruct (&set->alt_dir_construct_img, __, 0); - } - - for (int ni = 0; ni < MAX_NATURAL_WONDER_DISTRICT_TYPES; ni++) { - Sprite * sprite = &is->natural_wonder_img_sets[ni].img; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - - if (is->abandoned_district_img.vtable != NULL) - is->abandoned_district_img.vtable->destruct (&is->abandoned_district_img, __, 0); - if (is->abandoned_maritime_district_img.vtable != NULL) - is->abandoned_maritime_district_img.vtable->destruct (&is->abandoned_maritime_district_img, __, 0); - } - - is->dc_img_state = IS_UNINITED; -} - -void -clear_highlighted_worker_tiles_for_districts () -{ - FOR_TABLE_ENTRIES (tei, &is->highlighted_city_radius_tile_pointers) { - struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)tei.value; - if (info != NULL) - free (info); - } - table_deinit (&is->highlighted_city_radius_tile_pointers); -} - - -void -reset_district_state (bool reset_tile_map) -{ - clear_all_tracked_workers (); - deinit_district_images (); - clear_highlighted_worker_tiles_for_districts (); - - FOR_TABLE_ENTRIES (tei, &is->district_building_prereqs) { - struct district_building_prereq_list * list = (struct district_building_prereq_list *)tei.value; - if (list != NULL) - free (list); - } - table_deinit (&is->district_building_prereqs); - table_deinit (&is->command_id_to_district_id); - stable_deinit (&is->building_name_to_id); - if (reset_tile_map) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst != NULL) - free (inst); - } - table_deinit (&is->district_tile_map); - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if (entry != NULL) - free (entry); - } - table_deinit (&is->named_tile_map); - } - - clear_distribution_hub_tables (); - - is->distribution_hub_totals_dirty = true; - - clear_dynamic_district_definitions (); - is->district_count = is->special_district_count; - - for (int i = 0; i < COUNT_DISTRICT_TYPES; i++) { - is->district_infos[i].advance_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) - is->district_infos[i].advance_prereq_ids[j] = -1; - is->district_infos[i].obsoleted_by_id = -1; - is->district_infos[i].resource_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].resource_prereq_ids); j++) - is->district_infos[i].resource_prereq_ids[j] = -1; - is->district_infos[i].resource_prereq_on_tile_id = -1; - is->district_infos[i].wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) - is->district_infos[i].wonder_prereq_ids[j] = -1; - is->district_infos[i].natural_wonder_prereq_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) - is->district_infos[i].natural_wonder_prereq_ids[j] = -1; - is->district_infos[i].dependent_building_count = 0; - for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) - is->district_infos[i].dependent_building_ids[j] = -1; - } - - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req != NULL) - free (req); - } - table_deinit (&is->city_pending_district_requests[civ_id]); - } - table_deinit (&is->city_pending_building_orders); - - is->great_wall_auto_build = GWABS_NOT_STARTED; -} - -void -clear_city_district_request (City * city, int district_id) -{ - if (! is->current_config.enable_districts || - (city == NULL) || - (district_id < 0) || (district_id >= is->district_count)) - return; - - struct pending_district_request * req = find_pending_district_request (city, district_id); - if (req == NULL) - return; - - remove_pending_district_request (req); - - int pending_improv_id; - if (look_up_pending_building_order (city, &pending_improv_id)) { - int required_district_id; - if (city_requires_district_for_improvement (city, pending_improv_id, &required_district_id)) { - if (required_district_id == district_id) - forget_pending_building_order (city); - } - } -} - -bool -district_resource_prereqs_met_r (Tile * tile, int tile_x, int tile_y, int district_id, int max_req_resource_id) -{ - if ((tile == NULL) || (tile == p_null_tile) || - (district_id < 0) || (district_id >= is->district_count)) - return false; - - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - struct district_infos * info = &is->district_infos[district_id]; - int on_tile_req = info->resource_prereq_on_tile_id; - if (on_tile_req >= 0) { - int res_here = (owner >= 0) ? Tile_get_resource_visible_to (tile, __, owner) : -1; - if (res_here != on_tile_req) - return false; - } - - // If no resource prereqs, then the check passes - if (info->resource_prereq_count <= 0) - return true; - - if (owner < 0) - return false; - - // Check resource prereqs - ALL must be present - for (int i = 0; i < info->resource_prereq_count; i++) { - int resource_req = info->resource_prereq_ids[i]; - if (resource_req < 0) - continue; - if (resource_req > max_req_resource_id) - return false; - - bool has_resource = false; - bool is_bonus_resource = p_bic_data->ResourceTypes[resource_req].Class == RC_Bonus; - - FOR_CITIES_OF (coi, owner) { - City * req_city = coi.city; - if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, req_city, tile_x, tile_y)) - continue; - if (! city_has_resource_r (req_city, resource_req, max_req_resource_id)) - if (! is_bonus_resource) - continue; - else { - int civ_id = req_city->Body.CivID; - FOR_TILES_AROUND (tai, is->workable_tile_count, req_city->Body.X, req_city->Body.Y) { - Tile * radius_tile = tai.tile; - if ((radius_tile == NULL) || (radius_tile == p_null_tile)) - continue; - if (radius_tile->vtable->m38_Get_Territory_OwnerID (radius_tile) != civ_id) - continue; - if (Tile_get_resource_visible_to (radius_tile, __, civ_id) == resource_req) { - has_resource = true; - break; - } - } - if (has_resource) - break; - continue; - } - - has_resource = true; - break; - } - - // If this required resource is not available, the check fails - if (!has_resource) - return false; - } - - return true; -} - -bool -district_resource_prereqs_met (Tile * tile, int tile_x, int tile_y, int district_id) -{ - return district_resource_prereqs_met_r (tile, tile_x, tile_y, district_id, INT_MAX); -} - -int -count_contiguous_bridge_districts (int tile_x, int tile_y, int dx, int dy) -{ - Map * map = &p_bic_data->Map; - int nx = tile_x + dx; - int ny = tile_y + dy; - int count = 0; - int max_steps = map->Width + map->Height; - - for (int step = 0; step < max_steps; step++) { - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) - break; - count++; - nx += dx; - ny += dy; - } - - return count; -} - -int -count_contiguous_canal_districts (int tile_x, int tile_y, int max_count) -{ - if (max_count <= 0) - return 0; - - Map * map = &p_bic_data->Map; - int limit = max_count + 1; - int capacity = limit; - if (capacity < 1) - capacity = 1; - - int * xs = malloc (sizeof (*xs) * capacity); - int * ys = malloc (sizeof (*ys) * capacity); - if ((xs == NULL) || (ys == NULL)) { - if (xs != NULL) - free (xs); - if (ys != NULL) - free (ys); - return limit; - } - - int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; - int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; - int head = 0; - int tail = 0; - int count = 0; - - xs[tail] = tile_x; - ys[tail] = tile_y; - tail++; - - while (head < tail) { - int cx = xs[head]; - int cy = ys[head]; - head++; - count++; - if (count >= limit) - break; - - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) - continue; - - bool seen = false; - for (int j = 0; j < tail; j++) { - if ((xs[j] == nx) && (ys[j] == ny)) { - seen = true; - break; - } - } - if (seen) - continue; - - if (tail < capacity) { - xs[tail] = nx; - ys[tail] = ny; - tail++; - } else { - count = limit; - head = tail; - break; - } - } - } - - free (xs); - free (ys); - - return count; -} - -bool -district_line_is_straight (int tile_x, int tile_y, int district_id) -{ - Map * map = &p_bic_data->Map; - int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; - int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; - - for (int i = 0; i < 8; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, district_id)) - continue; - - int cand_dx = -adj_dx[i]; - int cand_dy = -adj_dy[i]; - - for (int j = 0; j < 8; j++) { - int ox = nx + adj_dx[j]; - int oy = ny + adj_dy[j]; - wrap_tile_coords (map, &ox, &oy); - if ((ox == tile_x) && (oy == tile_y)) - continue; - if (! tile_has_district_at (ox, oy, district_id)) - continue; - - if (! ((adj_dx[j] == cand_dx) && (adj_dy[j] == cand_dy)) && - ! ((adj_dx[j] == -cand_dx) && (adj_dy[j] == -cand_dy))) - return false; - } - } - - return true; -} - -bool -bridge_district_tile_is_valid (int tile_x, int tile_y) -{ - if (! tile_is_coastal_water (tile_x, tile_y)) - return false; - - bool has_adjacent_land_or_bridge = false; - Map * map = &p_bic_data->Map; - int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; - int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; - - for (int i = 0; i < 8; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (tile_is_land (-1, nx, ny, false) || tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) { - has_adjacent_land_or_bridge = true; - break; - } - } - if (! has_adjacent_land_or_bridge) - return false; - - if (is->current_config.max_contiguous_bridge_districts > 0) { - int max_bridges = is->current_config.max_contiguous_bridge_districts; - - int ns_count = count_contiguous_bridge_districts (tile_x, tile_y, 0, -2) + - count_contiguous_bridge_districts (tile_x, tile_y, 0, 2); - if (ns_count >= max_bridges) - return false; - - int we_count = count_contiguous_bridge_districts (tile_x, tile_y, -2, 0) + - count_contiguous_bridge_districts (tile_x, tile_y, 2, 0); - if (we_count >= max_bridges) - return false; - - int swne_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, 1) + - count_contiguous_bridge_districts (tile_x, tile_y, 1, -1); - if (swne_count >= max_bridges) - return false; - - int nwse_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, -1) + - count_contiguous_bridge_districts (tile_x, tile_y, 1, 1); - if (nwse_count >= max_bridges) - return false; - } - - return district_line_is_straight (tile_x, tile_y, BRIDGE_DISTRICT_ID); -} - -bool -canal_district_tile_is_valid (int tile_x, int tile_y) -{ - if (tile_is_water (tile_x, tile_y)) - return false; - - if (is->current_config.max_contiguous_canal_districts > 0) { - int count = count_contiguous_canal_districts (tile_x, tile_y, is->current_config.max_contiguous_canal_districts); - if (count > is->current_config.max_contiguous_canal_districts) - return false; - } - - Map * map = &p_bic_data->Map; - int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; - int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; - - for (int i = 0; i < 8; i++) { - int nx = tile_x + adj_dx[i]; - int ny = tile_y + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * tile = tile_at (nx, ny); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m35_Check_Is_Water (tile)) - return true; - - if (tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && - district_is_complete (tile, CANAL_DISTRICT_ID)) - return true; - } - } - - return false; -} - -bool -can_build_district_on_tile (Tile * tile, int district_id, int civ_id) -{ - if ((! is->current_config.enable_districts) || - (tile == NULL) || (tile == p_null_tile) || - (tile->CityID >= 0) || - tile->vtable->m21_Check_Crates (tile, __, 0) || - tile->vtable->m20_Check_Pollution (tile, __, 0) || - (district_id < 0) || (district_id >= is->district_count)) - return false; - - struct district_config const * cfg = &is->district_configs[district_id]; - if (cfg->command == -1) - return false; - - if ((cfg->command == UCV_Build_Neighborhood) && !is->current_config.enable_neighborhood_districts) return false; - if ((cfg->command == UCV_Build_WonderDistrict) && !is->current_config.enable_wonder_districts) return false; - if ((cfg->command == UCV_Build_DistributionHub) && !is->current_config.enable_distribution_hub_districts) return false; - if ((cfg->command == UCV_Build_Aerodrome) && !is->current_config.enable_aerodrome_districts) return false; - if ((cfg->command == UCV_Build_Port) && !is->current_config.enable_port_districts) return false; - if ((cfg->command == UCV_Build_Bridge) && !is->current_config.enable_bridge_districts) return false; - if ((cfg->command == UCV_Build_CentralRailHub) && !is->current_config.enable_central_rail_hub_districts) return false; - if ((cfg->command == UCV_Build_EnergyGrid) && !is->current_config.enable_energy_grid_districts) return false; - if ((cfg->command == UCV_Build_GreatWall) && !is->current_config.enable_great_wall_districts) return false; - - if (! district_is_buildable_on_tile (cfg, tile)) - return false; - - int tile_x = 0, tile_y = 0; - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - - if (! leader_can_build_district (&leaders[civ_id], district_id)) - return false; - - if (! district_resource_prereqs_met (tile, tile_x, tile_y, district_id)) - return false; - - if ((district_id == CANAL_DISTRICT_ID) && (! canal_district_tile_is_valid (tile_x, tile_y))) - return false; - - if ((district_id == BRIDGE_DISTRICT_ID) && (! bridge_district_tile_is_valid (tile_x, tile_y))) - return false; - - struct district_instance * existing_inst = get_district_instance (tile); - struct district_infos const * info = &is->district_infos[district_id]; - int existing_district_id = (existing_inst != NULL) ? existing_inst->district_id : -1; - bool district_completed = district_is_complete (tile, existing_district_id); - - if ((existing_district_id == district_id) && district_completed) - return false; - if ((existing_district_id >= 0) && (existing_district_id != district_id) && (! district_completed)) - return false; - - if (! cfg->allow_multiple) { - if (district_exists_within_distance (tile_x, tile_y, district_id, civ_id, is->current_config.city_work_radius)) - return false; - } - - return true; -} - -bool -district_is_obsolete_for_civ (int district_id, int civ_id) -{ - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - int obsolete_id = is->district_infos[district_id].obsoleted_by_id; - if (obsolete_id < 0) - return false; - - return Leader_has_tech (&leaders[civ_id], __, obsolete_id); -} - -bool -tile_has_obsolete_district_for_civ (Tile * tile, int civ_id) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - - int district_id = inst->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - if (! district_is_complete (tile, district_id)) - return false; - - return district_is_obsolete_for_civ (district_id, civ_id); -} - -bool -tile_suitable_for_district (Tile * tile, int district_id, City * city, bool * out_has_resource) -{ - bool has_resource = false; - if ((tile != NULL) && (tile != p_null_tile)) - has_resource = tile_has_resource (tile); - if (out_has_resource != NULL) - *out_has_resource = has_resource; - - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (tile->CityID >= 0) return false; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) return false; - if (! can_build_district_on_tile (tile, district_id, city->Body.CivID)) return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - if (tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - return true; - - // Unused wonder districts can be repurposed, completed cannot - if (district_id == WONDER_DISTRICT_ID && inst->state == DS_COMPLETED) { - struct wonder_district_info * winfo = &inst->wonder_info; - if (winfo->state == WDS_COMPLETED) - return false; - } - - return false; - } - - return true; -} - -bool -can_generate_resource (int for_civ_id, struct mill * mill) -{ - int req_tech_id = (mill->flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[mill->resource_id].RequireID; - return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); -} - -bool -district_can_generate_resource (int for_civ_id, struct district_config * dc) -{ - if (dc->generated_resource_id < 0) - return false; - int req_tech_id = (dc->generated_resource_flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[dc->generated_resource_id].RequireID; - return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); -} - -bool -district_generates_resource_for_civ (Tile * tile, struct district_instance * inst, struct district_config * dc, int civ_id) -{ - if ((tile == NULL) || (tile == p_null_tile) || (inst == NULL) || (dc == NULL)) - return false; - if (inst->state != DS_COMPLETED) - return false; - if (dc->generated_resource_id < 0) - return false; - if (! district_can_generate_resource (civ_id, dc)) - return false; - - int tile_x = 0, tile_y = 0; - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - return district_resource_prereqs_met_r (tile, tile_x, tile_y, inst->district_id, dc->generated_resource_id - 1); -} - -void -calculate_city_center_district_bonus (City * city, int * out_food, int * out_shields, int * out_gold) -{ - if (out_food != NULL) - *out_food = 0; - if (out_shields != NULL) - *out_shields = 0; - if (out_gold != NULL) - *out_gold = 0; - - if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) - return; - - int bonus_food = 0; - int bonus_shields = 0; - int bonus_gold = 0; - - int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - int neighborhoods_counted = 0; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) - continue; - Tile * tile = wai.tile; - - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - if (is->current_config.enable_neighborhood_districts && - (district_id == NEIGHBORHOOD_DISTRICT_ID)) { - if (neighborhoods_counted >= utilized_neighborhoods) - continue; - neighborhoods_counted++; - } - - struct district_config * cfg = &is->district_configs[district_id]; - int food_bonus = 0, shield_bonus = 0, gold_bonus = 0; - get_effective_district_yields (inst, cfg, &food_bonus, &shield_bonus, &gold_bonus, NULL, NULL, NULL); - bonus_food += food_bonus; - bonus_shields += shield_bonus; - bonus_gold += gold_bonus; - - if ((cfg->generated_resource_id >= 0) && (cfg->generated_resource_flags & MF_YIELDS)) { - int res_id = cfg->generated_resource_id; - if (district_generates_resource_for_civ (tile, inst, cfg, city->Body.CivID)) { - Resource_Type * res = &p_bic_data->ResourceTypes[res_id]; - bonus_food += res->Food; - bonus_shields += res->Shield; - bonus_gold += res->Commerce; - } - } - } - - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { - int hub_food = 0; - int hub_shields = 0; - get_distribution_hub_yields_for_city (city, &hub_food, &hub_shields); - bonus_food += hub_food; - bonus_shields += hub_shields; - } - - if (out_food != NULL) - *out_food = bonus_food; - if (out_shields != NULL) - *out_shields = bonus_shields; - if (out_gold != NULL) - *out_gold = bonus_gold; -} - -int __fastcall -patch_Map_calc_food_yield_at (Map * this, int edx, int tile_x, int tile_y, int tile_base_type, int civ_id, int imagine_fully_improved, City * city) -{ - if (! is->current_config.enable_districts) - return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id)) { - return 0; - } - } - - return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); -} - -int __fastcall -patch_Map_calc_shield_yield_at (Map * this, int edx, int tile_x, int tile_y, int civ_id, City * city, int param_5, int param_6) -{ - if (! is->current_config.enable_districts) - return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id)) { - return 0; - } - } - - return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); -} - -int -compute_city_tile_yield_sum (City * city, int tile_x, int tile_y) -{ - if (city == NULL) - return 0; - int food = City_calc_tile_yield_at (city, __, YK_FOOD, tile_x, tile_y); - int shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, tile_x, tile_y); - int commerce = City_calc_tile_yield_at (city, __, YK_COMMERCE, tile_x, tile_y); - return food + shields + commerce; -} - -int * -get_water_continent_ids_connected_via_canal (Tile * tile, int * out_count) -{ - if (out_count != NULL) - *out_count = 0; - if (! is->current_config.enable_canal_districts) - return NULL; - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - if (! tile->vtable->m35_Check_Is_Water (tile)) - return NULL; - - int origin_continent_id = tile->vtable->m46_Get_ContinentID (tile); - int continent_count = p_bic_data->Map.Continent_Count; - if ((origin_continent_id < 0) || (origin_continent_id >= continent_count)) - return NULL; - - Map * map = &p_bic_data->Map; - int tile_count = map->TileCount; - if (tile_count <= 0) - return NULL; - - // Use a BFS over completed canal tiles, starting from those touching the origin water body. - int * queue_xs = malloc (sizeof (*queue_xs) * tile_count); - int * queue_ys = malloc (sizeof (*queue_ys) * tile_count); - int * ids = malloc (sizeof (*ids) * continent_count); - bool * seen = calloc (continent_count, sizeof (*seen)); - if ((queue_xs == NULL) || (queue_ys == NULL) || (ids == NULL) || (seen == NULL)) { - if (queue_xs != NULL) - free (queue_xs); - if (queue_ys != NULL) - free (queue_ys); - if (ids != NULL) - free (ids); - if (seen != NULL) - free (seen); - return NULL; - } - - seen[origin_continent_id] = true; - - int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; - int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; - int head = 0; - int tail = 0; - - // Seed queue with completed canal districts adjacent to the origin water body. - for (int index = 0; index < tile_count; index++) { - Tile * cand = Map_get_tile (map, __, index); - if ((cand == NULL) || (cand == p_null_tile)) - continue; - - int cx = 0, cy = 0; - tile_index_to_coords (map, index, &cx, &cy); - if (! tile_has_district_at (cx, cy, CANAL_DISTRICT_ID)) - continue; - - struct district_instance * inst = get_district_instance (cand); - if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || - (! district_is_complete (cand, CANAL_DISTRICT_ID))) - continue; - - bool adjacent_to_origin = false; - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (! adj->vtable->m35_Check_Is_Water (adj)) - continue; - int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); - if (adj_continent_id == origin_continent_id) { - adjacent_to_origin = true; - break; - } - } - if (! adjacent_to_origin) - continue; - - bool seen_canal = false; - for (int j = 0; j < tail; j++) { - if ((queue_xs[j] == cx) && (queue_ys[j] == cy)) { - seen_canal = true; - break; - } - } - if (! seen_canal && (tail < tile_count)) { - queue_xs[tail] = cx; - queue_ys[tail] = cy; - tail++; - } - } - - int id_count = 0; - - while (head < tail) { - int cx = queue_xs[head]; - int cy = queue_ys[head]; - head++; - - // Record all water bodies adjacent to this canal tile. - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - if (! adj->vtable->m35_Check_Is_Water (adj)) - continue; - - int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); - if ((adj_continent_id < 0) || (adj_continent_id >= continent_count)) - continue; - if (! seen[adj_continent_id]) { - seen[adj_continent_id] = true; - ids[id_count] = adj_continent_id; - id_count++; - } - } - - // Traverse to neighboring completed canal districts. - for (int i = 0; i < 8; i++) { - int nx = cx + adj_dx[i]; - int ny = cy + adj_dy[i]; - wrap_tile_coords (map, &nx, &ny); - if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) - continue; - - Tile * adj = tile_at (nx, ny); - if ((adj == NULL) || (adj == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (adj); - if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || (! district_is_complete (adj, CANAL_DISTRICT_ID))) - continue; - - bool seen_canal = false; - for (int j = 0; j < tail; j++) { - if ((queue_xs[j] == nx) && (queue_ys[j] == ny)) { - seen_canal = true; - break; - } - } - if (! seen_canal && (tail < tile_count)) { - queue_xs[tail] = nx; - queue_ys[tail] = ny; - tail++; - } - } - } - - free (queue_xs); - free (queue_ys); - free (seen); - - if (out_count != NULL) - *out_count = id_count; - if (id_count <= 0) { - free (ids); - return NULL; - } - - return ids; -} - -Tile * -find_tile_for_neighborhood_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - - // Search in order: ring 1, then rings 2..N - // Ring order array: 1, 2, 3, ..., city_work_radius - int ring_order[8]; - int ring_count = 0; - for (int r = 1; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - - Tile * best_tile = NULL; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - bool has_resource = false; - if (is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - continue; - } - - if (! tile_suitable_for_district (tile, NEIGHBORHOOD_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - if (get_district_instance (tile) != NULL && - ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -find_tile_for_port_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - int threshold_for_body_of_water = 21; // Mimic vanilla behavior so AI doesn't build ports in small lakes - - // Search in order: ring 1, then rings 2..N - int ring_order[8]; - int ring_count = 0; - for (int r = 1; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - - Tile * best_tile = NULL; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - bool has_resource = false; - if (is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - continue; - } - - if (! tile_suitable_for_district (tile, PORT_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - if (get_district_instance (tile) != NULL && - ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - continue; - if (! tile->vtable->m35_Check_Is_Water (tile)) - continue; - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - bool large_enough_body = (continent->Body.TileCount >= threshold_for_body_of_water); - if (! large_enough_body) { - int connected_count = 0; - int * connected_ids = get_water_continent_ids_connected_via_canal (tile, &connected_count); - for (int i = 0; i < connected_count; i++) { - int connected_id = connected_ids[i]; - if ((connected_id < 0) || (connected_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * connected_continent = &p_bic_data->Map.Continents[connected_id]; - if (connected_continent->Body.TileCount >= threshold_for_body_of_water) { - large_enough_body = true; - break; - } - } - if (connected_ids != NULL) - free (connected_ids); - } - if (! large_enough_body) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -find_tile_for_wonder_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - int target_improv_id = -1; - if (look_up_pending_building_order (city, &target_improv_id)) { - if ((target_improv_id < 0) || - (target_improv_id >= p_bic_data->ImprovementsCount) || - ((p_bic_data->Improvements[target_improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0)) - target_improv_id = -1; - } - if (target_improv_id < 0) { - int order_id = city->Body.Order_ID; - if ((city->Body.Order_Type == COT_Improvement) && - (order_id >= 0) && - (order_id < p_bic_data->ImprovementsCount)) { - Improvement * order = &p_bic_data->Improvements[order_id]; - if (order->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - target_improv_id = order_id; - } - } - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - - // Search in order: ring 2, then rings 3..N, then ring 1 as last resort - int ring_order[8]; - int ring_count = 0; - ring_order[ring_count++] = 2; - for (int r = 3; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - ring_order[ring_count++] = 1; - - Tile * best_tile = NULL; - bool has_resource = false; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - if (! tile_suitable_for_district (tile, WONDER_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - if (! wonder_is_buildable_on_tile (tile, target_improv_id)) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -find_tile_for_distribution_hub_district (City * city, int * out_x, int * out_y) -{ - if (city == NULL) - return NULL; - - const int resource_penalty = 100; - const int yield_weight = 40; - const int city_distance_weight = 8; - const int capital_distance_weight = 45; - const int desired_min_capital_distance = 8; - const int proximity_penalty_scale = 300; - const int different_continent_bonus = 500; - - Tile * best_tile = NULL; - int best_score = INT_MIN; - int best_adjusted_yield = INT_MIN; - int best_distance = -1; - int best_distance_to_capital = -1; - bool best_has_resource = true; - - int civ_id = city->Body.CivID; - bool has_capital = false; - int capital_x = 0; - int capital_y = 0; - int capital_continent_id = -1; - - City * capital = get_city_ptr (leaders[civ_id].CapitalID); - if (capital != NULL) { - has_capital = true; - capital_x = capital->Body.X; - capital_y = capital->Body.Y; - Tile * capital_tile = tile_at (capital_x, capital_y); - if ((capital_tile != NULL) && (capital_tile != p_null_tile)) - capital_continent_id = capital_tile->vtable->m46_Get_ContinentID (capital_tile); - } - - FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { - int tx = wai.tile_x, ty = wai.tile_y; - Tile * tile = wai.tile; - bool has_resource; - if (! tile_suitable_for_district (tile, DISTRIBUTION_HUB_DISTRICT_ID, city, &has_resource)) - continue; - if (has_resource) - continue; - - int chebyshev = compute_wrapped_chebyshev_distance (tx, ty, city->Body.X, city->Body.Y); - if (chebyshev <= 1) - continue; - - bool too_close_to_existing_hub_or_city = false; - for (int m = 0; m < workable_tile_counts[2]; m++) { - int ndx, ndy; - patch_ni_to_diff_for_work_area (m, &ndx, &ndy); - int nx = tx + ndx, ny = ty + ndy; - wrap_tile_coords (&p_bic_data->Map, &nx, &ny); - Tile * nearby_tile = tile_at (nx, ny); - if ((nearby_tile != NULL) && (nearby_tile != p_null_tile)) { - struct district_instance * nearby_inst = get_district_instance (nearby_tile); - if ((nearby_inst != NULL) && - (nearby_inst->district_id == DISTRIBUTION_HUB_DISTRICT_ID) && - district_is_complete (nearby_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { - too_close_to_existing_hub_or_city = true; - break; - } - else if (nearby_tile->CityID >= 0) { - too_close_to_existing_hub_or_city = true; - break; - } - } - } - if (too_close_to_existing_hub_or_city) - continue; - - int raw_yield = compute_city_tile_yield_sum (city, tx, ty); - int adjusted_yield = raw_yield - (has_resource ? resource_penalty : 0); - int distance = compute_wrapped_manhattan_distance (tx, ty, city->Body.X, city->Body.Y); - int distance_to_capital = has_capital - ? compute_wrapped_manhattan_distance (tx, ty, capital_x, capital_y) - : 0; - - int proximity_penalty = 0; - if (has_capital && (distance_to_capital < desired_min_capital_distance)) - proximity_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; - - int continent_bonus = 0; - if ((capital_continent_id >= 0) && (tile != NULL) && (tile != p_null_tile)) { - int tile_continent_id = tile->vtable->m46_Get_ContinentID (tile); - if ((tile_continent_id >= 0) && (tile_continent_id != capital_continent_id)) - continent_bonus = different_continent_bonus; - } - - int score = - adjusted_yield * yield_weight + - distance * city_distance_weight + - distance_to_capital * capital_distance_weight - - proximity_penalty + - continent_bonus; - - if ((score > best_score) || - ((score == best_score) && (distance_to_capital > best_distance_to_capital)) || - ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield > best_adjusted_yield)) || - ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance > best_distance)) || - ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance == best_distance) && (! has_resource && best_has_resource))) { - best_tile = tile; - best_score = score; - best_adjusted_yield = adjusted_yield; - best_distance = distance; - best_distance_to_capital = distance_to_capital; - best_has_resource = has_resource; - *out_x = tx; - *out_y = ty; - } - } - - return best_tile; -} - -bool -city_can_build_district (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos const * info = &is->district_infos[district_id]; - - if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) - return false; - - if ((info->resource_prereq_count > 0) || (info->resource_prereq_on_tile_id >= 0)) { - bool resource_prereqs_met = false; - - FOR_TILES_AROUND (tai, is->workable_tile_count, city->Body.X, city->Body.Y) { - Tile * tile = tai.tile; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) - continue; - if (! district_resource_prereqs_met_r (tile, tai.tile_x, tai.tile_y, district_id, INT_MAX)) - continue; - - resource_prereqs_met = true; - break; - } - - if (! resource_prereqs_met) - return false; - } - - // Check if district does not allow multiple and city already has one - if (! cfg->allow_multiple && city_has_required_district (city, district_id)) - return false; - - return true; -} - -bool -leader_has_wonder_prereq (Leader * leader, struct district_infos const * info) -{ - if (info == NULL) - return false; - if (info->wonder_prereq_count <= 0) - return true; - if ((leader == NULL) || (leader->Improvement_Counts == NULL)) - return false; - - for (int i = 0; i < info->wonder_prereq_count; i++) { - int improv_id = info->wonder_prereq_ids[i]; - if (improv_id >= 0 && leader->Improvement_Counts[improv_id] > 0) - return true; - } - - return false; -} - -bool -leader_has_natural_wonder_prereq_in_territory (int civ_id, struct district_infos const * info) -{ - if (info == NULL) - return false; - if (info->natural_wonder_prereq_count <= 0) - return true; - if (! is->current_config.enable_natural_wonders) - return false; - - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - - int wonder_id = inst->natural_wonder_info.natural_wonder_id; - if (wonder_id < 0) - continue; - - bool matches = false; - for (int i = 0; i < info->natural_wonder_prereq_count; i++) { - if (info->natural_wonder_prereq_ids[i] == wonder_id) { - matches = true; - break; - } - } - if (! matches) - continue; - - Tile * tile = (Tile *)tei.key; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; - } - - return false; -} - -int -count_distribution_hubs_for_civ (int civ_id) -{ - int current = 0; - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if ((rec != NULL) && (rec->civ_id == civ_id)) - current++; - } - return current; -} - -bool -leader_can_natively_build_district (Leader * leader, int district_id) -{ - if ((leader == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos const * info = &is->district_infos[district_id]; - - for (int i = 0; i < info->advance_prereq_count; i++) { - int prereq_id = info->advance_prereq_ids[i]; - if ((prereq_id >= 0) && ! Leader_has_tech (leader, __, prereq_id)) - return false; - } - int obsolete_id = info->obsoleted_by_id; - if ((obsolete_id >= 0) && Leader_has_tech (leader, __, obsolete_id)) - return false; - - if (! leader_has_wonder_prereq (leader, info)) - return false; - - if (! leader_has_natural_wonder_prereq_in_territory (leader->ID, info)) - return false; - - if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) { - int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; - if (max_per_100 > 0) { - int city_count = leader->Cities_Count; - int max_allowed = (city_count * max_per_100 + 99) / 100; - if (max_allowed <= 0) - return false; - - int current = count_distribution_hubs_for_civ (leader->ID); - if (current >= max_allowed) - return false; - } - } - - if (cfg->has_buildable_by_civs) { - bool civ_match = false; - if (cfg->buildable_by_civ_count > 0) { - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - for (int i = 0; i < cfg->buildable_by_civ_count; i++) { - char const * civ_name = cfg->buildable_by_civs[i]; - if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; - if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; - if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; - if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; - if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; - } - } - if (! civ_match) - return false; - } - - if (cfg->has_buildable_by_civ_traits) { - if (cfg->buildable_by_civ_traits_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL || race->vtable == NULL) - return false; - bool trait_match = false; - for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { - int trait_id = cfg->buildable_by_civ_traits_ids[i]; - if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { - trait_match = true; - break; - } - } - if (! trait_match) - return false; - } - - if (cfg->has_buildable_by_civ_govs) { - if (cfg->buildable_by_civ_govs_id_count <= 0) - return false; - int gov_id = leader->GovernmentType; - bool gov_match = false; - for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { - if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { - gov_match = true; - break; - } - } - if (! gov_match) - return false; - } - - if (cfg->has_buildable_by_civ_cultures) { - if (cfg->buildable_by_civ_cultures_id_count <= 0) - return false; - Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) - ? &p_bic_data->Races[leader->RaceID] - : NULL; - if (race == NULL) - return false; - int culture_id = race->CultureGroupID; - bool culture_match = false; - for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { - if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { - culture_match = true; - break; - } - } - if (! culture_match) - return false; - } - - return true; -} - -bool -leader_has_war_ally_district_access (Leader * leader, int district_id) -{ - if (leader == NULL) - return false; - - int self_id = leader->ID; - for (int civ_id = 0; civ_id < 32; civ_id++) { - if (civ_id == self_id) - continue; - Leader * other = &leaders[civ_id]; - if (other->Military_Allies[self_id] != 0 && leader_can_natively_build_district (other, district_id)) - return true; - } - - return false; -} - -bool -leader_has_pact_ally_district_access (Leader * leader, int district_id) -{ - if (leader == NULL) - return false; - - int self_id = leader->ID; - for (int civ_id = 0; civ_id < 32; civ_id++) { - if (civ_id == self_id) - continue; - Leader * other = &leaders[civ_id]; - if (((leader->Relation_Treaties[civ_id] & 1) != 0 && // 1 = peace treaty - (leader->Relation_Treaties[civ_id] & 4) != 0) && // 4 = mutual protection pact - leader_can_natively_build_district (other, district_id)) { - return true; - } - } - - return false; -} - -bool -leader_can_build_district (Leader * leader, int district_id) -{ - bool can_natively_build = leader_can_natively_build_district (leader, district_id); - - if (can_natively_build) - return true; - - struct district_config const * cfg = &is->district_configs[district_id]; - if (cfg->buildable_by_war_allies && leader_has_war_ally_district_access (leader, district_id)) - return true; - if (cfg->buildable_by_pact_allies && leader_has_pact_ally_district_access (leader, district_id)) - return true; - - return can_natively_build; -} - -Tile * -find_tile_for_district (City * city, int district_id, int * out_x, int * out_y) -{ - if ((city == NULL) || (out_x == NULL) || (out_y == NULL)) - return NULL; - if ((district_id < 0) || (district_id >= is->district_count)) - return NULL; - - // Check if city can build this district at all - if (! city_can_build_district (city, district_id)) - return NULL; - - if (district_id == NEIGHBORHOOD_DISTRICT_ID) - return find_tile_for_neighborhood_district (city, out_x, out_y); - if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) - return find_tile_for_distribution_hub_district (city, out_x, out_y); - if (district_id == PORT_DISTRICT_ID) - return find_tile_for_port_district (city, out_x, out_y); - if (district_id == WONDER_DISTRICT_ID) - return find_tile_for_wonder_district (city, out_x, out_y); - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int city_work_radius = is->current_config.city_work_radius; - - // Search in order: ring 2, then rings 3..N, then ring 1 as last resort - // Ring order array: 2, 3, 4, ..., city_work_radius, 1 - int ring_order[8]; - int ring_count = 0; - ring_order[ring_count++] = 2; - for (int r = 3; r <= city_work_radius; r++) - ring_order[ring_count++] = r; - ring_order[ring_count++] = 1; - - Tile * best_tile = NULL; - struct district_config * cfg = &is->district_configs[district_id]; - int best_yield = INT_MAX; - int best_x = -1, best_y = -1; - int current_ring = -1; - - FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { - if (tri.current_ring != current_ring) { - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - current_ring = tri.current_ring; - best_tile = NULL; - best_yield = INT_MAX; - } - - Tile * tile = tri.tile; - bool has_resource = false; - if (is->current_config.enable_distribution_hub_districts) { - int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); - if (covered > 0) - continue; - } - - if (! tile_suitable_for_district (tile, district_id, city, &has_resource)) - continue; - if (cfg->resource_prereq_on_tile < 0 && has_resource) - continue; - if (get_district_instance (tile) != NULL && ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) - continue; - - int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); - if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { - best_yield = yield; - best_tile = tile; - best_x = tri.tile_x; - best_y = tri.tile_y; - } - } - - if (best_tile != NULL) { - *out_x = best_x; - *out_y = best_y; - return best_tile; - } - - return NULL; -} - -Tile * -get_completed_district_tile_for_city (City * city, int district_id, int * out_x, int * out_y) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return NULL; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - struct district_instance * inst = wai.district_inst; - - if (inst->district_id != district_id) - continue; - - // For wonder districts, filter based on wonder_district_state - if (district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = &inst->wonder_info; - // Must be either unused or under construction by this city - if (info->state == WDS_COMPLETED) - continue; - if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) - continue; - if (info->state == WDS_UNDER_CONSTRUCTION) { - info->city = city; - info->city_id = city->Body.ID; - } - } - - if (out_x != NULL) - *out_x = x; - if (out_y != NULL) - *out_y = y; - return candidate; - } - - return NULL; -} - -bool -tile_has_friendly_aerodrome_district (Tile * tile, int civ_id, bool require_available) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_aerodrome_districts || - (tile == NULL) || - (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != AERODROME_DISTRICT_ID) - return false; - - if (! district_is_complete (tile, AERODROME_DISTRICT_ID)) - return false; - - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (territory_owner != civ_id) - return false; - - if (require_available) { - int usage_mask; - if (itable_look_up (&is->aerodrome_airlift_usage, (int)tile, &usage_mask) && - (usage_mask & (1 << civ_id))) - return false; - } - - return true; -} - -bool -tile_has_friendly_port_district (Tile * tile, int civ_id) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - (tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != PORT_DISTRICT_ID)) - return false; - - if (! district_is_complete (tile, PORT_DISTRICT_ID)) - return false; - - return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; -} - -bool -city_has_required_district (City * city, int district_id) -{ - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - if (get_completed_district_tile_for_city (city, district_id, NULL, NULL) != NULL) { - clear_city_district_request (city, district_id); - return true; - } - return false; -} - -bool -city_has_wonder_district_with_no_completed_wonder (City * city, int wonder_improv_id) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - Tile * candidate = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - - struct wonder_district_info * info = get_wonder_district_info (candidate); - bool buildable = wonder_is_buildable_on_tile (candidate, wonder_improv_id); - if (info == NULL) return true; - if (info->state == WDS_COMPLETED) continue; - if (info->state == WDS_UNUSED && buildable) return true; - if (info->state == WDS_UNDER_CONSTRUCTION && buildable && info->city_id == city->Body.ID) { - info->city = city; - return true; // Reserved by this city - } - } - - return false; -} - -int __fastcall patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city); -int __fastcall patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null); -void __fastcall patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3); - - -void __fastcall -patch_Main_Screen_Form_show_map_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) -{ - WITH_PAUSE_FOR_POPUP { - Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, pause); - } -} - -int __cdecl -patch_process_text_for_map_message (char * in, char * out) -{ - if (is->map_message_text_override != NULL) { - strcpy (out, is->map_message_text_override); - is->map_message_text_override = NULL; - return 0; - } else - return process_text_snippet (in, out); -} - -// Works like show_map_message but takes a bit of text to display instead of a key for script.txt -void -show_map_specific_text (int tile_x, int tile_y, char const * text, bool pause) -{ - is->map_message_text_override = text; - patch_Main_Screen_Form_show_map_message (p_main_screen_form, __, tile_x, tile_y, "LANDCONQUER", pause); // Use any key here. It will be overridden. -} - -bool __fastcall -patch_City_has_improvement (City * this, int edx, int improv_id, bool include_auto_improvements) -{ - bool tr = City_has_improvement (this, __, improv_id, include_auto_improvements); - - // Check if the improvement is provided for free by another human player's wonder if we're in a hotseat game and the config option is on - if ((! tr) && - include_auto_improvements && - is->current_config.share_wonders_in_hotseat && - ((1 << this->Body.CivID) & *p_human_player_bits) && - (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // if we're in a hotseat game - - // Loop over every other human player in the game and check if the city would have the improv if they were its owner - int actual_owner_id = this->Body.CivID; - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != actual_owner_id)) { - this->Body.CivID = n_player; - if (City_has_improvement (this, __, improv_id, include_auto_improvements)) { - tr = true; - break; - } - } - player_bits >>= 1; - n_player++; - } - this->Body.CivID = actual_owner_id; - - } - - return tr; -} - -int -count_neighborhoods_in_city_radius (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return 0; - - int count = 0; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - struct district_instance * inst = wai.district_inst; - if (inst != NULL && - inst->district_id >= 0 && inst->district_id < is->district_count && - inst->district_id == NEIGHBORHOOD_DISTRICT_ID) - count++; - } - return count; -} - -int -count_utilized_neighborhoods_in_city_radius (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return 0; - - int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; - if (base_cap <= 0) - return 0; - - int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; - if (per_neighborhood <= 0) - return 0; - - int pop = city->Body.Population.Size; - if (pop <= base_cap) - return 0; - - int excess_pop = pop - base_cap; - int utilized = (excess_pop + per_neighborhood - 1) / per_neighborhood; - int total_neighborhoods = count_neighborhoods_in_city_radius (city); - - if (utilized > total_neighborhoods) - utilized = total_neighborhoods; - - return utilized; -} - -int -get_neighborhood_pop_cap (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return -1; - - int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; - if (base_cap <= 0) - return -1; - - int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; - if (per_neighborhood < 0) - per_neighborhood = 0; - - int neighborhoods = count_neighborhoods_in_city_radius (city); - long long cap = (long long)base_cap + (long long)per_neighborhood * neighborhoods; - if (cap < base_cap) - cap = base_cap; - - return (int)cap; -} - -bool -city_is_at_neighborhood_cap (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return false; - - int cap = get_neighborhood_pop_cap (city); - if (cap <= 0) - return false; - - return city->Body.Population.Size >= cap; -} - -void -ensure_neighborhood_request_for_city (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_neighborhood_districts || - (city == NULL)) - return; - - if (! leader_can_build_district (&leaders[city->Body.CivID], NEIGHBORHOOD_DISTRICT_ID)) - return; - - mark_city_needs_district (city, NEIGHBORHOOD_DISTRICT_ID); -} - -void -calculate_district_culture_science_bonuses (City * city, int * culture_bonus, int * science_bonus) -{ - if (culture_bonus != NULL) - *culture_bonus = 0; - if (science_bonus != NULL) - *science_bonus = 0; - - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders) || (city == NULL)) - return; - - int total_culture = 0; - int total_science = 0; - int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) - continue; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - struct district_config const * cfg = &is->district_configs[district_id]; - int district_culture_bonus = 0; - int district_science_bonus = 0; - get_effective_district_yields (inst, cfg, NULL, NULL, NULL, &district_science_bonus, &district_culture_bonus, NULL); - - bool is_neighborhood = (cfg->command == UCV_Build_Neighborhood); - if (is_neighborhood) { - if (utilized_neighborhoods > 0) { - total_culture += district_culture_bonus; - total_science += district_science_bonus; - utilized_neighborhoods--; - } - } else { - total_culture += district_culture_bonus; - total_science += district_science_bonus; - } - } - - if (culture_bonus != NULL) - *culture_bonus = total_culture; - if (science_bonus != NULL) - *science_bonus = total_science; -} - -void -calculate_district_happiness_bonus (City * city, int * happiness_bonus) -{ - if (happiness_bonus != NULL) - *happiness_bonus = 0; - - if (! is->current_config.enable_districts || (city == NULL)) - return; - - int total_happy = 0; - int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) - continue; - - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - struct district_config const * cfg = &is->district_configs[district_id]; - - bool is_neighborhood = district_id == NEIGHBORHOOD_DISTRICT_ID; - if (is_neighborhood && (utilized_neighborhoods <= 0)) - continue; - - if (is_neighborhood) - utilized_neighborhoods--; - - int district_happy = 0; - get_effective_district_yields (inst, cfg, NULL, NULL, NULL, NULL, NULL, &district_happy); - if (district_happy != 0) - total_happy += district_happy; - } - - if (happiness_bonus != NULL) - *happiness_bonus = total_happy; -} - -int __fastcall -patch_City_requires_improvement_to_grow (City * this) -{ - int required_improv = City_requires_improvement_to_grow (this); - if ((required_improv == -1) && - (this != NULL) && - is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - city_is_at_neighborhood_cap (this)) { - return 0; // Neighborhood sentinel - } - - return required_improv; -} - -// Replacement check specifically for stalled growth check function, -// where we can't pass through the neighborhood sentinel. That function itself -// doesn't block growth, it just triggers the dialog, so safe to skip it if -// neighborhoods are needed. -int __fastcall -patch_City_requires_improvement_to_grow_besides_neighborhood (City * this) -{ - return City_requires_improvement_to_grow (this); -} - -void __fastcall -patch_maybe_show_improvement_needed_for_growth_dialog (void * this, int edx, City * city, int * param_2) -{ - int required_improv_id = (int)param_2; - if (is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - (required_improv_id == 0)) // Neighborhood sentinel - return; - - maybe_show_improvement_needed_for_growth_dialog (this, __, city, param_2); -} - -void -maybe_show_neighborhood_growth_warning (City * city) -{ - if ((city == NULL) || ! (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts)) return; - int requirement = patch_City_requires_improvement_to_grow (city); - if (requirement != 0) return; // Neighborhood sentinel not present - if (city->Body.FoodIncome <= 0) return; // Not growing - if (is_online_game ()) return; - int civ_id = city->Body.CivID; - if (civ_id != p_main_screen_form->Player_CivID) return; - if ((*p_human_player_bits & (1u << civ_id)) == 0) return; - - unsigned int turn_no = (unsigned int)*p_current_turn_no; - unsigned int throttle = ((unsigned int)city->Body.X << 5) ^ (unsigned int)city->Body.Y; - int frequency = is->current_config.neighborhood_needed_message_frequency; - if ((frequency <= 0) || (((turn_no + throttle) % frequency) != 0)) - return; - - char msg[160]; - char const * city_name = city->Body.CityName; - snprintf (msg, sizeof msg, "%s %s %s %s", - city_name, - is->c3x_labels[CL_REQUIRES], - is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name, - is->c3x_labels[CL_TO_GROW] - ); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); -} - -bool __stdcall -patch_is_not_pop_capped_or_starving (City * city) -{ - bool tr = is_not_pop_capped_or_starving (city); - if (! tr) return false; - - if (is->current_config.enable_districts) { - if (city_is_at_neighborhood_cap (city)) - return false; - } - - return true; -} - -bool -remove_building_if_no_district (City * city, int district_id, int building_id) -{ - if ((city == NULL) || (building_id < 0)) return false; - if (! patch_City_has_improvement (city, __, building_id, false)) return false; - if (city_has_required_district (city, district_id)) return false; - - patch_City_add_or_remove_improvement (city, __, building_id, 0, false); - return true; -} - -bool -city_has_other_completed_wonder_district_for_improvement (City * city, int wonder_improv_id, int removed_x, int removed_y) -{ - if (! (is->current_config.enable_districts && is->current_config.enable_wonder_districts) || - (city == NULL) || (wonder_improv_id < 0)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - if ((x == removed_x) && (y == removed_y)) - continue; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if (info->state != WDS_COMPLETED) - continue; - - int candidate_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); - if (candidate_improv_id != wonder_improv_id) - continue; - - return true; - } - - return false; -} - -void -remove_shared_wonder_if_no_other_district (City * city, int wonder_improv_id, int removed_x, int removed_y) -{ - if ((city == NULL) || (wonder_improv_id < 0)) - return; - - if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) - return; - - if (leaders[city->Body.CivID].Small_Wonders[wonder_improv_id] == city->Body.ID) - return; - - if (city_has_other_completed_wonder_district_for_improvement (city, wonder_improv_id, removed_x, removed_y)) - return; - - patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); -} - -void -reduce_city_population_due_to_lost_neighborhood (City * city) -{ - if (city == NULL) - return; - - if (! (is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - is->current_config.destroying_neighborhood_reduces_pop)) - return; - - int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; - int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; - if ((base_cap <= 0) || (per_neighborhood <= 0)) - return; - - int neighborhoods = count_neighborhoods_in_city_radius (city); - int cap = base_cap + (per_neighborhood * neighborhoods); - if (cap < base_cap) - cap = base_cap; - - int pop = city->Body.Population.Size; - if (pop <= cap) - return; - - int to_remove = pop - cap; - int removed = 0; - while (to_remove-- > 0) { - City_remove_population (city, __, 1, -1, '\0'); - removed++; - } - - if ((removed > 0) && - ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && - (city->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[160]; - snprintf (msg, sizeof msg, "%s %s %s", - city->Body.CityName, - is->c3x_labels[CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD], - is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name - ); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } -} - -bool -city_has_other_completed_district (City * city, int district_id, int removed_x, int removed_y) -{ - if (! is->current_config.enable_districts || - (city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - if ((x == removed_x) && (y == removed_y)) - continue; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != district_id) - continue; - - return true; - } - - return false; -} - -bool -district_instance_is_redundant (struct district_instance * inst, Tile * tile) -{ - if (! is->current_config.enable_districts || - (inst == NULL) || - (tile == NULL) || (tile == p_null_tile)) - return false; - - int district_id = inst->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - return false; - - if (! district_is_complete (tile, district_id)) - return false; - - if (district_id == NEIGHBORHOOD_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID) - return false; - - int tile_x = inst->tile_x; - int tile_y = inst->tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - return false; - - int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - - if (district_id == WONDER_DISTRICT_ID) - return inst->wonder_info.state == WDS_UNUSED; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - if (! city_has_other_completed_district (wai.city, district_id, tile_x, tile_y)) - return false; - } - - return true; -} - -bool -any_nearby_city_would_lose_district_benefits (int district_id, int civ_id, int removed_x, int removed_y) -{ - if (! is->current_config.enable_districts) - return false; - - if (district_id < 0 || district_id >= is->district_count) - return false; - - struct district_infos * info = &is->district_infos[district_id]; - - // If there are no dependent buildings, no city can lose benefits - if (info->dependent_building_count == 0) - return false; - - // Check all cities within work radius of the removed district - FOR_CITIES_AROUND (wai, removed_x, removed_y) { - City * city = wai.city; - - // Check if this city has another completed district of the same type nearby (excluding the one being removed) - if (city_has_other_completed_district (city, district_id, removed_x, removed_y)) - continue; - - // This city doesn't have another district, check if it has any dependent buildings - for (int i = 0; i < info->dependent_building_count; i++) { - int building_id = info->dependent_building_ids[i]; - if (building_id >= 0 && patch_City_has_improvement (city, __, building_id, false)) - return true; - } - } - - return false; -} - -void -remove_dependent_buildings_for_district (int district_id, int center_x, int center_y) -{ - if (! is->current_config.enable_districts || (district_id < 0) || (district_id >= is->district_count)) - return; - - struct district_infos * info = &is->district_infos[district_id]; - - if ((center_x < 0) || (center_y < 0) || - (center_x >= p_bic_data->Map.Width) || (center_y >= p_bic_data->Map.Height)) - return; - - FOR_CITIES_AROUND (wai, center_x, center_y) { - City * city = wai.city; - - if (city_has_other_completed_district (city, district_id, center_x, center_y)) - continue; - - int removed_count = 0; - int first_building_id = -1; - - for (int i = 0; i < info->dependent_building_count; i++) { - int building_id = info->dependent_building_ids[i]; - if (building_id >= 0) { - // This also loops through tiles around the city but is not redundant, as the city - // may have multiple districts of the same type in its radius (eg outside radius of this particular district) - if (remove_building_if_no_district (city, district_id, building_id)) { - if (removed_count == 0) - first_building_id = building_id; - removed_count++; - } - } - } - - if ((removed_count > 0) && - is->current_config.show_message_when_building_lost_to_destroyed_district && - ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && - (city->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[200]; - char const * district_name = is->district_configs[district_id].name; - char const * building_name = (first_building_id >= 0) ? p_bic_data->Improvements[first_building_id].Name.S : ""; - - if (removed_count == 1) - snprintf (msg, sizeof msg, "%s%s %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_APOSTROPHE_S], - building_name, - is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], - district_name); - else - snprintf (msg, sizeof msg, "%s%s %s %s %d %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_APOSTROPHE_S], - building_name, - is->c3x_labels[CL_AND], - removed_count - 1, - is->c3x_labels[CL_OTHER_BUILDINGS_HAVE_BEEN], - is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], - district_name); - - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - } -} - -void -remove_wonder_improvement_for_destroyed_district (int wonder_improv_id) -{ - if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) - return; - - if ((p_cities == NULL) || (p_cities->Cities == NULL)) - return; - - for (int idx = 0; idx <= p_cities->LastIndex; idx++) { - City * city = get_city_ptr (idx); - if (city == NULL) - continue; - if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) - continue; - - patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); - } -} - -void -handle_district_removed (Tile * tile, int district_id, int center_x, int center_y, bool leave_ruins) -{ - if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.enable_districts) - return; - - int wonder_windex = -1; - int wonder_improv_id = -1; - - // Get wonder district info before removing - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info != NULL && info->state == WDS_COMPLETED) - wonder_windex = info->wonder_index; - - int actual_district_id = district_id; - if (actual_district_id < 0) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) - actual_district_id = inst->district_id; - } - - remove_district_instance (tile); - - bool removed_neighborhood = actual_district_id == NEIGHBORHOOD_DISTRICT_ID; - - if (is->current_config.enable_wonder_districts && - (actual_district_id == WONDER_DISTRICT_ID) && - (wonder_windex >= 0)) - wonder_improv_id = get_wonder_improvement_id_from_index (wonder_windex); - - if (wonder_improv_id >= 0 && is->current_config.completed_wonder_districts_can_be_destroyed) - remove_wonder_improvement_for_destroyed_district (wonder_improv_id); - - if (is->current_config.enable_distribution_hub_districts && - (actual_district_id == DISTRIBUTION_HUB_DISTRICT_ID)) - remove_distribution_hub_record (tile); - - if (district_id >= 0) - remove_dependent_buildings_for_district (district_id, center_x, center_y); - - // Make the tile workable again by resetting CityAreaID and recomputing yields for nearby cities - tile->Body.CityAreaID = -1; - - int tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - - FOR_CITIES_AROUND (wai, center_x, center_y) { - if (removed_neighborhood) - reduce_city_population_due_to_lost_neighborhood (wai.city); - recompute_city_yields_with_districts (wai.city); - } - - if (leave_ruins && (tile->vtable->m60_Set_Ruins != NULL)) { - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, center_x, center_y); - tile->vtable->m60_Set_Ruins (tile, __, 1); - } - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -bool -city_has_active_wonder_for_district (City * city) -{ - struct district_infos * info = &is->district_infos[WONDER_DISTRICT_ID]; - for (int n = 0; n < ARRAY_LEN (info->dependent_building_ids); n++) { - int building_id = info->dependent_building_ids[n]; - if ((building_id >= 0) && has_active_building (city, building_id)) - return true; - } - return false; -} - -bool -city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id) -{ - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); - if ((prereq_list == NULL) || (prereq_list->count <= 0)) - return false; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder = false; - - // Special logic for handling rivers - bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; - bool has_prereq = false; - - if (is->current_config.enable_wonder_districts && - district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) { - is_wonder = true; - if (! wonder_is_buildable_by_civ (improv_id, city->Body.CivID)) { - if (out_district_id != NULL) - *out_district_id = -1; - return false; - } - if (requires_river) { - bool has_river_wonder_district = false; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if (wai.district_inst->district_id != WONDER_DISTRICT_ID) - continue; - if (wai.tile->vtable->m37_Get_River_Code (wai.tile) == 0) - continue; - if (! wonder_is_buildable_on_tile (wai.tile, improv_id)) - continue; - struct wonder_district_info * info = get_wonder_district_info (wai.tile); - if (info == NULL) { - has_river_wonder_district = true; - break; - } - if (info->state == WDS_COMPLETED) - continue; - if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) - continue; - has_river_wonder_district = true; - break; - } - if (has_river_wonder_district) - has_prereq = true; - } else if (city_has_wonder_district_with_no_completed_wonder (city, improv_id)) { - has_prereq = true; - } - } - - if (! has_prereq && city_has_any_prereq_district_for_improvement (city, prereq_list, requires_river, !is_wonder)) - has_prereq = true; - - if (has_prereq) - return false; - - if (out_district_id != NULL) - *out_district_id = pick_missing_district_for_improvement (city, prereq_list); - return true; -} - -void -clear_best_feasible_order (City * city) -{ - int key = (int)city; - int stored_int; - if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) { - struct ai_best_feasible_order * stored = (struct ai_best_feasible_order *)stored_int; - free (stored); - itable_remove (&is->ai_best_feasible_orders, key); - } -} - -void -record_best_feasible_order (City * city, City_Order const * order, int value) -{ - int key = (int)city; - int stored_int; - struct ai_best_feasible_order * stored; - if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) - stored = (struct ai_best_feasible_order *)stored_int; - else { - stored = malloc (sizeof *stored); - if (stored == NULL) - return; - stored->order = *order; - stored->value = value; - itable_insert (&is->ai_best_feasible_orders, key, (int)stored); - return; - } - - if (value > stored->value) { - stored->order = *order; - stored->value = value; - } -} - -struct ai_best_feasible_order * -get_best_feasible_order (City * city) -{ - int stored_int; - if (itable_look_up (&is->ai_best_feasible_orders, (int)city, &stored_int)) - return (struct ai_best_feasible_order *)stored_int; - else - return NULL; -} - -bool -city_is_currently_building_wonder (City * city) -{ - if ((city == NULL) || (city->Body.Order_Type != COT_Improvement)) - return false; - int order_id = city->Body.Order_ID; - if ((order_id < 0) || (order_id >= p_bic_data->ImprovementsCount)) - return false; - return (p_bic_data->Improvements[order_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; -} - -bool -wonder_district_tile_under_construction (Tile * tile, int tile_x, int tile_y, int * out_windex) -{ - if (! is->current_config.enable_wonder_districts || - (tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != WONDER_DISTRICT_ID) - return false; - - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info == NULL || info->state != WDS_UNDER_CONSTRUCTION) - return false; - - City * reserved_city = get_city_ptr (info->city_id); - if (reserved_city == NULL) - return false; - info->city = reserved_city; - info->city_id = reserved_city->Body.ID; - - // Verify the reserved city is still building a wonder - if (! city_is_currently_building_wonder (reserved_city)) - return false; - - // Verify this tile is within the reserved city's radius - if (! city_radius_contains_tile (reserved_city, tile_x, tile_y)) - return false; - - // Get the wonder index for the wonder being built - if (out_windex != NULL) { - int order_id = reserved_city->Body.Order_ID; - int windex = find_wonder_config_index_by_improvement_id (order_id); - *out_windex = windex; - } - - return true; -} - -bool -city_needs_wonder_district (City * city) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - - int pending_improv_id; - if (look_up_pending_building_order (city, &pending_improv_id)) { - // Check if it's actually a wonder - if ((pending_improv_id >= 0) && (pending_improv_id < p_bic_data->ImprovementsCount)) { - Improvement * improv = &p_bic_data->Improvements[pending_improv_id]; - if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - return true; - } - } - if (city_is_currently_building_wonder (city)) - return true; - if (city_has_active_wonder_for_district (city)) - return true; - return false; -} - -bool -city_has_assigned_wonder_district (City * city, Tile * ignore_tile, int wonder_improv_id) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - if (candidate == ignore_tile) - continue; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = inst ? &inst->wonder_info : NULL; - if ((info != NULL) && - (info->state == WDS_UNDER_CONSTRUCTION) && - (info->city_id == city->Body.ID)) { - info->city = city; - if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) { - info->state = WDS_UNUSED; - info->city = NULL; - info->city_id = -1; - info->wonder_index = -1; - continue; - } - return true; - } - } - - return false; -} - -bool -free_wonder_district_for_city (City * city) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) - return false; - if (city_needs_wonder_district (city)) - return false; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { - int x = wai.tile_x, y = wai.tile_y; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info != NULL && info->state == WDS_COMPLETED) - continue; // Don't remove completed wonder districts - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - continue; - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - - handle_district_removed (tile, WONDER_DISTRICT_ID, city->Body.X, city->Body.Y, false); - return true; - } - - return false; -} - -bool -reserve_wonder_district_for_city (City * city, int wonder_improv_id) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return false; - if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) - return false; - - if (city_has_assigned_wonder_district (city, NULL, wonder_improv_id)) - return true; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * candidate = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if (info->state == WDS_COMPLETED) continue; - if (info->state == WDS_UNDER_CONSTRUCTION) { - if (info->city_id == city->Body.ID) { - info->city = city; - return true; - } - continue; - } - if (city_has_assigned_wonder_district (city, candidate, wonder_improv_id)) - return true; - - // Reserve this Wonder district for this city - info->state = WDS_UNDER_CONSTRUCTION; - info->city = city; - info->city_id = city->Body.ID; - info->wonder_index = -1; - return true; - } - - return false; -} - -void -release_wonder_district_reservation (City * city) -{ - if (! is->current_config.enable_wonder_districts || (city == NULL)) - return; - - // Find and remove any reservations for this city - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if ((info != NULL) && - (info->state == WDS_UNDER_CONSTRUCTION) && - (info->city_id == city->Body.ID)) { - info->city = city; - info->state = WDS_UNUSED; - info->city = NULL; - info->city_id = -1; - info->wonder_index = -1; - } - } -} - -void -handle_district_destroyed_by_attack (Tile * tile, int tile_x, int tile_y, bool leave_ruins) -{ - if (! is->current_config.enable_districts || tile == NULL || tile == p_null_tile) - return; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - int district_id = inst->district_id; - - // If this is a Wonder District with a completed wonder and wonders can't be destroyed, restore overlay and keep district - if (is->current_config.enable_wonder_districts) { - struct wonder_district_info * info = get_wonder_district_info (tile); - if ((district_id == WONDER_DISTRICT_ID) && - (info != NULL && info->state == WDS_COMPLETED) && - (! is->current_config.completed_wonder_districts_can_be_destroyed)) { - unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); - if ((overlays & TILE_FLAG_MINE) == 0) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - return; - } - } - if (district_id == BRIDGE_DISTRICT_ID || district_id == CANAL_DISTRICT_ID) { - enum UnitTypeClasses target_class = (district_id == BRIDGE_DISTRICT_ID) ? UTC_Land : UTC_Sea; - clear_memo (); - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if (unit == NULL) - continue; - int unit_type_id = unit->Body.UnitTypeID; - if ((unit_type_id < 0) || (unit_type_id >= p_bic_data->UnitTypeCount)) - continue; - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - bool matches = (type->Unit_Class == target_class); - if (! matches && unit->Body.Container_Unit >= 0) { - Unit * container = get_unit_ptr (unit->Body.Container_Unit); - if (container != NULL) { - int container_type_id = container->Body.UnitTypeID; - if ((container_type_id >= 0) && (container_type_id < p_bic_data->UnitTypeCount)) { - UnitType * container_type = &p_bic_data->UnitTypes[container_type_id]; - matches = (container_type->Unit_Class == target_class); - } - } - } - if (matches) { - bool already = false; - for (int n = 0; n < is->memo_len; n++) - if (is->memo[n] == unit->Body.ID) { - already = true; - break; - } - if (! already) - memoize (unit->Body.ID); - } - } - for (int n = 0; n < is->memo_len; n++) { - Unit * to_despawn = get_unit_ptr (is->memo[n]); - if (to_despawn != NULL) - patch_Unit_despawn (to_despawn, __, 0, 1, 0, 0, 0, 0, 0); - } - clear_memo (); - } - handle_district_removed (tile, district_id, tile_x, tile_y, leave_ruins); - } -} - -bool -has_active_building (City * city, int improv_id) -{ - Leader * owner = &leaders[city->Body.CivID]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - return patch_City_has_improvement (city, __, improv_id, 1) && // building is physically present in city AND - ((improv->ObsoleteID < 0) || (! Leader_has_tech (owner, __, improv->ObsoleteID))) && // building is not obsolete AND - ((improv->GovernmentID < 0) || (improv->GovernmentID == owner->GovernmentType)); // building is not restricted to a different govt -} - -void -init_unit_type_count (Leader * leader) -{ - int id = leader->ID; - struct table * counts = &is->unit_type_counts[id]; - - if (counts->len > 0) - table_deinit (counts); - - if (p_units->Units != NULL) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit_Body * body = p_units->Units[n].Unit; - if ((body != NULL) && ((int)body != offsetof (Unit, Body)) && (body->CivID == id)) { - int prev_count = itable_look_up_or (counts, body->UnitTypeID, 0); - itable_insert (counts, body->UnitTypeID, prev_count + 1); - } - } - - is->unit_type_count_init_bits |= 1 << id; -} - -int -get_unit_type_count (Leader * leader, int unit_type_id) -{ - int id = leader->ID; - struct table * counts = &is->unit_type_counts[id]; - - if ((is->unit_type_count_init_bits & 1<ID; - struct table * counts = &is->unit_type_counts[id]; - if ((is->unit_type_count_init_bits & (1 << id)) == 0) - init_unit_type_count (leader); - - int prev_amount = itable_look_up_or (counts, unit_type_id, 0); - itable_insert (counts, unit_type_id, prev_amount + amount); -} - -// If this unit type is limited, returns true and writes how many units of the type the given player is allowed to "out_limit". If the type is not -// limited, returns false. -bool -get_unit_limit (Leader * leader, int unit_type_id, int * out_limit) -{ - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - struct unit_type_limit * lim; - 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; - if (lim->cities_per != 0) - tr += city_count / lim->cities_per; - *out_limit = tr; - return true; - } else - return false; -} - -// This this unit type is limited, returns true and writes to "out_available" how many units the given player can add before reaching the limit. If -// the type is not limited, returns false. -bool -get_available_unit_count (Leader * leader, int unit_type_id, int * out_available) -{ - int limit; - if (get_unit_limit (leader, unit_type_id, &limit)) { - int count = get_unit_type_count (leader, unit_type_id); - int dups[30]; - int dups_count = list_unit_type_duplicates (unit_type_id, dups, ARRAY_LEN (dups)); - for (int n = 0; n < dups_count; n++) - count += get_unit_type_count (leader, dups[n]); - - *out_available = limit - count; - return true; - } else - return false; -} - -int -add_i31b_to_int (int base, i31b addition) -{ - int amount; - bool percent; - i31b_unpack (addition, &amount, &percent); - if (! percent) - return base + amount; - else { - int fraction = (base * int_abs (amount) + 50) / 100; - return (amount >= 0) ? base + fraction : base - fraction; - } -} - -int -apply_perfume (enum perfume_kind kind, char const * name, int base_amount) -{ - i31b perfume_value; - if (stable_look_up (&is->current_config.perfume_specs[kind], name, &perfume_value)) - return add_i31b_to_int (base_amount, perfume_value); - else - return base_amount; -} - -int __stdcall -intercept_consideration (int valuation) -{ - City * city = is->ai_considering_production_for_city; - City_Order * order = &is->ai_considering_order; - - // Apply perfume - char * order_name; { - if (order->OrderType == COT_Improvement) - order_name = p_bic_data->Improvements[order->OrderID].Name.S; - else - order_name = p_bic_data->UnitTypes[order->OrderID].Name; - } - valuation = apply_perfume (PK_PRODUCTION, order_name, valuation); - - // Apply temp AI settler perfume - if ((order->OrderType == COT_Unit) && - (p_bic_data->UnitTypes[order->OrderID].AI_Strategy & UTAI_Settle) && - (is->current_config.ai_settler_perfume_on_founding != 0) && - (is->current_config.ai_settler_perfume_on_founding_duration != 0) && - (is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID] >= 0)) { - int turns_since_founding = *p_current_turn_no - is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID]; - int duration = is->current_config.ai_settler_perfume_on_founding_duration; - if (turns_since_founding < duration) { - i31b perfume = is->current_config.ai_settler_perfume_on_founding; - - // Scale amount by turns remaining - { - int amount; - bool percent; - i31b_unpack (perfume, &amount, &percent); - - int percent_remaining = (100 * (duration - turns_since_founding)) / duration; - amount = (amount * percent_remaining + 50) / 100; - - perfume = i31b_pack (amount, percent); - } - - valuation = add_i31b_to_int (valuation, perfume); - } - } - - if (is->current_config.enable_districts && - (city != NULL) && - ((*p_human_player_bits & (1 << city->Body.CivID)) == 0)) { - bool feasible = false; - switch (order->OrderType) { - case COT_Improvement: - if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->ImprovementsCount) && - (! city_requires_district_for_improvement (city, order->OrderID, NULL))) - feasible = true; - break; - case COT_Unit: - if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->UnitTypeCount)) - feasible = true; - break; - default: - break; - } - if (feasible) - record_best_feasible_order (city, order, valuation); - } - - // Expand the list of valuations if necessary - reserve (sizeof is->ai_prod_valuations[0], (void **)&is->ai_prod_valuations, &is->ai_prod_valuations_capacity, is->count_ai_prod_valuations); - - // Record this valuation - int n = is->count_ai_prod_valuations++; - is->ai_prod_valuations[n] = (struct ai_prod_valuation) { - .order_type = order->OrderType, - .order_id = order->OrderID, - .point_value = valuation - }; - - return valuation; -} - -// Returns a pointer to a bitfield that can be used to record resource access for resource IDs >= 32. This procedure can work with any city ID since -// it allocates and zero-initializes these bit fields as necessary. The given resource ID must be at least 32. The index of the bit for that resource -// within the field is resource_id%32. -unsigned * -get_extra_resource_bits (int city_id, int resource_id) -{ - int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); - int ints_per_city = 1 + extra_resource_count/32; - if (city_id >= is->extra_available_resources_capacity) { - int new_capacity = city_id + 100; - unsigned * new_array = calloc (new_capacity * ints_per_city, sizeof new_array[0]); - if (is->extra_available_resources != NULL) { - memcpy (new_array, is->extra_available_resources, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); - free (is->extra_available_resources); - } - is->extra_available_resources = new_array; - is->extra_available_resources_capacity = new_capacity; - } - return &is->extra_available_resources[city_id * ints_per_city + (resource_id-32)/32]; -} - -void __stdcall -intercept_set_resource_bit (City * city, int resource_id) -{ - if (resource_id < 32) - city->Body.Available_Resources |= 1 << resource_id; - else - *get_extra_resource_bits (city->Body.ID, resource_id) |= 1 << (resource_id&31); -} - -// Must forward declare this function since there's a circular dependency between it and patch_City_has_resource -bool has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id); - -bool __fastcall -patch_City_has_resource (City * this, int edx, int resource_id) -{ - return city_has_resource_r (this, resource_id, INT_MAX); -} - -bool -city_has_resource_r (City * this, int resource_id, int max_generated_resource_id) -{ - bool tr; - if ((this == NULL) || (resource_id < 0) || (resource_id >= p_bic_data->ResourceTypeCount)) - return false; - if (resource_id > max_generated_resource_id) - return false; - - if (is->current_config.patch_phantom_resource_bug && - (resource_id >= 32) && (resource_id < p_bic_data->ResourceTypeCount) && - (! City_has_trade_connection_to_capital (this))) { - unsigned bits = (this->Body.ID < is->extra_available_resources_capacity) ? *get_extra_resource_bits (this->Body.ID, resource_id) : 0; - tr = (bits >> (resource_id&31)) & 1; - } else - tr = City_has_resource (this, __, resource_id); - - // Check if access to this resource is provided by a building in the city - if (! tr) - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if ((mill->resource_id == resource_id) && - (mill->flags & MF_LOCAL) && - can_generate_resource (this->Body.CivID, mill) && - has_active_building (this, mill->improv_id) && - has_resources_required_by_building_r (this, mill->improv_id, mill->resource_id - 1)) { - tr = true; - break; - } - } - - // Check if access to this resource is provided by a district in the city's work radius - if ((! tr) && is->current_config.enable_districts) { - FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { - struct district_instance * di = wai.district_inst; - int district_id = di->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - continue; - - struct district_config * dc = &is->district_configs[district_id]; - if ((dc->generated_resource_id == resource_id) && - (dc->generated_resource_flags & MF_LOCAL) && - district_generates_resource_for_civ (wai.tile, di, dc, this->Body.CivID)) { - tr = true; - break; - } - } - } - - return tr; -} - -// Checks if the resource requirements for an improvement are satisfied in a given city. The "max_req_resource_id" parameter is to guard against -// infinite loops in case of circular resource dependencies due to mills. The way it works is that resource requirements can only be satisfied if -// their ID is not greater than that limit. This function is called recursively by patch_City_has_resource and in the recursive calls, the limit is -// set to be below the resource ID provided by the mill being considered. So, when considering resource production chains, the limit approaches zero -// with each recursive call, hence infinite loops are not possible. -bool -has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id) -{ - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if (! (improv->ImprovementFlags & ITF_Required_Goods_Must_Be_In_City_Radius)) { - for (int n = 0; n < 2; n++) { - int res_id = (&improv->Resource1ID)[n]; - if ((res_id >= 0) && - ((res_id > max_req_resource_id) || (! city_has_resource_r (city, res_id, max_req_resource_id)))) - return false; - } - return true; - } else { - int * targets = &improv->Resource1ID; - if ((targets[0] < 0) && (targets[1] < 0)) - return true; - int finds[2] = {0, 0}; - - int civ_id = city->Body.CivID; - for (int n = 0; n < is->workable_tile_count; n++) { - int dx, dy; - patch_ni_to_diff_for_work_area (n, &dx, &dy); - int x = city->Body.X + dx, y = city->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &x, &y); - Tile * tile = tile_at (x, y); - if (tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id) { - int res_here = Tile_get_resource_visible_to (tile, __, civ_id); - if (res_here >= 0) { - finds[0] |= targets[0] == res_here; - finds[1] |= targets[1] == res_here; - } - } - } - - return ((targets[0] < 0) || finds[0]) && ((targets[1] < 0) || finds[1]); - } -} - -bool -has_resources_required_by_building (City * city, int improv_id) -{ - return has_resources_required_by_building_r (city, improv_id, INT_MAX); -} - -void __fastcall -patch_City_recompute_commerce (City * this) -{ - City_recompute_commerce (this); - - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - int science_bonus = 0; - calculate_district_culture_science_bonuses (this, NULL, &science_bonus); - - if (science_bonus != 0) { - this->Body.Science += science_bonus; - if (this->Body.Science < 0) - this->Body.Science = 0; - } -} - -void __fastcall -patch_City_recompute_yields_and_happiness (City * this) -{ - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts && - ! is->distribution_hub_refresh_in_progress && - is->distribution_hub_totals_dirty) - recompute_distribution_hub_totals (); - - City_recompute_yields_and_happiness (this); -} - -void __fastcall -patch_City_update_culture (City * this) -{ - City_update_culture (this); - - if ((this == NULL) || ! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - int culture_bonus = 0; - calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); - - if (culture_bonus == 0) - return; - - int culture_income = this->Body.CultureIncome + culture_bonus; - if (culture_income < 0) - culture_income = 0; - this->Body.CultureIncome = culture_income; - - int civ_id = this->Body.CivID; - int total_culture = this->Body.Total_Cultures[civ_id] + culture_bonus; - if (total_culture < 0) - total_culture = 0; - this->Body.Total_Cultures[civ_id] = total_culture; - - City_recompute_cultural_level (this, __, '\0', '\0', '\0'); -} - -void __fastcall -patch_City_recompute_culture_income (City * this) -{ - City_recompute_culture_income (this); - - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - int culture_bonus = 0; - calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); - - if (culture_bonus != 0) { - this->Body.CultureIncome += culture_bonus; - if (this->Body.CultureIncome < 0) - this->Body.CultureIncome = 0; - } -} - -// Recomputes yields in cities with active mills that depend on input resources. Intended to be called when an input resource has been potentially -// gained or lost. Recomputes only for the cities of a given leader or, if NULL, for all cities on the map. -void -recompute_mill_yields_after_resource_change (Leader * leader_or_null) -{ - if (p_cities->Cities != NULL) - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city != NULL) && - ((leader_or_null == NULL) || (city->Body.CivID == leader_or_null->ID))) { - bool any_relevant_mills = false; - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - Improvement * mill_improv = &p_bic_data->Improvements[mill->improv_id]; - if ((mill->flags & MF_YIELDS) && - ((mill_improv->Resource1ID >= 0) || (mill_improv->Resource2ID >= 0)) && - has_active_building (city, mill->improv_id)) { - any_relevant_mills = true; - break; - } - } - if (any_relevant_mills) - patch_City_recompute_yields_and_happiness (city); - } - } -} - - -int -resource_tile_resource_id (struct extra_resource_tile const * rt) -{ - if (rt == NULL) - return -1; - if (rt->type == ERT_MILL_RESOURCE) { - return (rt->mill_info.mill != NULL) ? rt->mill_info.mill->resource_id : -1; - } else if (rt->district_info.cfg != NULL) { - return rt->district_info.cfg->generated_resource_id; - } - return -1; -} - -int -compare_resource_tiles (void const * vp_a, void const * vp_b) -{ - struct extra_resource_tile const * a = vp_a, * b = vp_b; - return resource_tile_resource_id (a) - resource_tile_resource_id (b); -} - -void __fastcall -patch_Trade_Net_recompute_resources (Trade_Net * this, int edx, bool skip_popups) -{ - int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); - int ints_per_city = 1 + extra_resource_count/32; - memset (is->extra_available_resources, 0, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); - - // Assemble list of mill tiles - is->count_resource_tiles = 0; - if (p_cities->Cities != NULL) - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if (city != NULL) - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if (((mill->flags & MF_LOCAL) == 0) && - has_active_building (city, mill->improv_id) && - can_generate_resource (city->Body.CivID, mill)) { - Tile * resource_tile = tile_at (city->Body.X, city->Body.Y); - if ((resource_tile == NULL) || (resource_tile == p_null_tile)) - continue; - reserve (sizeof is->resource_tiles[0], - (void **)&is->resource_tiles, - &is->resource_tiles_capacity, - is->count_resource_tiles); - is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { - .tile = resource_tile, - .type = ERT_MILL_RESOURCE, - .mill_info = { - .city = city, - .mill = mill - } - }; - } - } - } - if (is->current_config.enable_districts) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * district_tile = (Tile *)tei.key; - struct district_instance * inst = (struct district_instance *)tei.value; - if ((district_tile == NULL) || (district_tile == p_null_tile) || (inst == NULL) || (inst->state != DS_COMPLETED)) - continue; - - int district_id = inst->district_id; - if ((district_id < 0) || (district_id >= is->district_count)) - continue; - - struct district_config * cfg = &is->district_configs[district_id]; - if ((cfg == NULL) || (cfg->generated_resource_id < 0)) - continue; - - int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); - if (owner_id < 0) - continue; - if ((cfg->generated_resource_flags & MF_LOCAL) != 0) - continue; - if (! district_can_generate_resource (owner_id, cfg)) - continue; - - reserve (sizeof is->resource_tiles[0], - (void **)&is->resource_tiles, - &is->resource_tiles_capacity, - is->count_resource_tiles); - is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { - .tile = district_tile, - .type = ERT_DISTRICT_RESOURCE, - .district_info = { - .inst = inst, - .cfg = cfg - } - }; - } - } - qsort (is->resource_tiles, is->count_resource_tiles, sizeof is->resource_tiles[0], compare_resource_tiles); - - is->got_resource_tile = NULL; - is->saved_tile_count = p_bic_data->Map.TileCount; - p_bic_data->Map.TileCount += is->count_resource_tiles; - Trade_Net_recompute_resources (this, __, skip_popups); - - // Restore the tile count if necessary. It may have already been restored by patch_Map_Renderer_m71_Draw_Tiles. This happens when the call to - // recompute_resources above opens a popup message about connecting a resource for the first time, which triggers redraw of the map. - if (is->saved_tile_count >= 0) { - p_bic_data->Map.TileCount = is->saved_tile_count; - is->saved_tile_count = -1; - } - - recompute_mill_yields_after_resource_change (NULL); - - is->must_recompute_resources_for_mill_inputs = false; -} - -Tile * -get_resource_tile (int index) -{ - struct extra_resource_tile * rt = &is->resource_tiles[index]; - is->got_resource_tile = rt; - return rt->tile; -} - -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_1 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_2 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_3 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_4 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } -Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_5 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } - -int __fastcall -patch_Tile_get_visible_resource_when_recomputing (Tile * tile, int edx, int civ_id) -{ - if (is->got_resource_tile != NULL) { - struct extra_resource_tile * rt = is->got_resource_tile; - is->got_resource_tile = NULL; - if (rt->type == ERT_MILL_RESOURCE) { - if ((rt->mill_info.city != NULL) && (rt->mill_info.mill != NULL) && - has_resources_required_by_building (rt->mill_info.city, rt->mill_info.mill->improv_id)) - return rt->mill_info.mill->resource_id; - else - return -1; - } else { - Tile * district_tile = rt->tile; - struct district_instance * inst = rt->district_info.inst; - struct district_config * cfg = rt->district_info.cfg; - if ((district_tile != NULL) && (district_tile != p_null_tile) && (inst != NULL) && - (cfg != NULL) && (inst->state == DS_COMPLETED)) { - int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); - if ((owner_id == civ_id) && district_generates_resource_for_civ (district_tile, inst, cfg, owner_id)) - return cfg->generated_resource_id; - } - return -1; - } - } - - int base_resource = Tile_get_resource_visible_to (tile, __, civ_id); - return base_resource; -} - -int WINAPI -patch_MessageBoxA (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) -{ - if (is->current_config.suppress_hypertext_links_exceeded_popup && - (strcmp (lpText, "Maximum hypertext links exceeded!") == 0)) - return IDOK; - else - return MessageBoxA (hWnd, lpText, lpCaption, uType); -} - -char * __fastcall -do_capture_modified_gold_trade (TradeOffer * trade_offer, int edx, int val, char * str, unsigned base) -{ - is->modifying_gold_trade = trade_offer; - return print_int (val, str, base); -} - -// Here the order of the registers matches the order that they're pushed by the pusha instruction -struct register_set { - int edi, esi, ebp, esp, ebx, edx, ecx, eax; -}; - -// Return 1 to allow the candidate unit to exert ZoC, 0 to exclude it. A pointer to the candidate is in esi. -int __stdcall -filter_zoc_candidate (struct register_set * reg) -{ - Unit * candidate = (Unit *)reg->esi, - * defender = is->zoc_defender; - - UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID], - * defender_type = &p_bic_data->UnitTypes[defender ->Body.UnitTypeID]; - - enum UnitTypeClasses candidate_class = candidate_type->Unit_Class, - defender_class = defender_type ->Unit_Class; - - bool lethal = ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) != 0) && (! is->temporarily_disallow_lethal_zoc); - bool aerial = (is->current_config.special_zone_of_control_rules & SZOCR_AERIAL ) != 0, - amphibious = (is->current_config.special_zone_of_control_rules & SZOCR_AMPHIBIOUS) != 0; - - // Exclude air units if aerial ZoC is not enabled and exclude land-to-sea & sea-to-land ZoC if amphibious is not enabled - if ((! aerial) && (candidate_class == UTC_Air)) - return 0; - if ((! amphibious) && - (((candidate_class == UTC_Land) && (defender_class == UTC_Sea )) || - ((candidate_class == UTC_Sea ) && (defender_class == UTC_Land)))) - return 0; - - // In case of cross-domain ZoC, filter out units with zero bombard strength or range. They can't use their attack strength in this case, so - // without bombard they can be ruled out. Don't forget units may have non-zero bombard strength and zero range for defensive bombard. - int range = (candidate_class != UTC_Air) ? candidate_type->Bombard_Range : candidate_type->OperationalRange; - if ((candidate_class != defender_class) && ((candidate_type->Bombard_Strength <= 0) || (range <= 0))) - return 0; - - // Require lethal config option & lethal bombard against one HP defender - if ((Unit_get_max_hp (defender) - defender->Body.Damage <= 1) && - ((! lethal) || - ((defender_class == UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Sea_Bombardment)) || - ((defender_class != UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Land_Bombardment)))) - return 0; - - // Air units require the bombing action to perform ZoC - if ((candidate_class == UTC_Air) && ! (candidate_type->Air_Missions & UCV_Bombing)) - return 0; - - // Exclude land units in transports if configured - if ((is->current_config.special_zone_of_control_rules & SZOCR_NOT_FROM_INSIDE) && candidate_class == UTC_Land) { - Unit * container = get_unit_ptr (candidate->Body.Container_Unit); - if ((container != NULL) && ! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)) - return 0; - } - - return 1; -} - -#define TRADE_NET_REF_COUNT 315 -#define TRADE_NET_INSTR_COUNT_GOG 22 -#define TRADE_NET_INSTR_COUNT_STEAM 23 -#define TRADE_NET_INSTR_COUNT_PCG 22 -#define TRADE_NET_ADDR_TOTAL_COUNT ((TRADE_NET_REF_COUNT * 3) + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM + TRADE_NET_INSTR_COUNT_PCG) - -int * -load_trade_net_addrs () -{ - if (is->trade_net_addrs_load_state == IS_OK) - return is->trade_net_addrs; - else if (is->trade_net_addrs_load_state == IS_INIT_FAILED) - return NULL; - - bool success = false; - char err_msg[300] = {0}; - - is->trade_net_addrs = calloc (3 * TRADE_NET_ADDR_TOTAL_COUNT, sizeof is->trade_net_addrs[0]); - if (! is->trade_net_addrs) { - snprintf (err_msg, (sizeof err_msg) - 1, "Bad alloc"); - goto done; - } - - char file_path[MAX_PATH] = {0}; - snprintf (file_path, (sizeof file_path) - 1, "%s\\trade_net_addresses.txt", is->mod_rel_dir); - char * refs_file = file_to_string (file_path); - if (! refs_file) { - snprintf (err_msg, (sizeof err_msg) - 1, "Couldn't load %s", file_path); - goto done; - } - - char * cursor = refs_file; - int loaded_count = 0; - while (true) { - if (*cursor == '#') { // comment line - skip_line (&cursor); - continue; - } - - skip_horiz_space (&cursor); - if (*cursor == '\n') { // empty line - cursor++; - continue; - } else if (*cursor == '\0') // end of file - break; - - // otherwise we must be on a line with some addresses - int ref; - bool got_any_addresses = false; - while (parse_int (&cursor, &ref)) { - if (loaded_count >= TRADE_NET_ADDR_TOTAL_COUNT) { - snprintf (err_msg, (sizeof err_msg) - 1, "Too many values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); - goto done; - } - is->trade_net_addrs[loaded_count] = ref; - loaded_count++; - got_any_addresses = true; - } - - if (! got_any_addresses) { - snprintf (err_msg, (sizeof err_msg) - 1, "Parse error"); - goto done; - } - } - - if (loaded_count < TRADE_NET_ADDR_TOTAL_COUNT) { - snprintf (err_msg, (sizeof err_msg) - 1, "Too few values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); - goto done; - } - - success = true; - -done: - free (refs_file); - if (! success) { - char full_err_msg[300] = {0}; - snprintf (full_err_msg, (sizeof full_err_msg) - 1, "Failed to load trade net refs: %s", err_msg); - MessageBox (NULL, full_err_msg, NULL, MB_ICONERROR); - is->trade_net_addrs_load_state = IS_INIT_FAILED; - return NULL; - } else { - is->trade_net_addrs_load_state = IS_OK; - return is->trade_net_addrs; - } -} - -unsigned short * __fastcall -patch_get_pixel_to_draw_city_dot (JGL_Image * this, int edx, int x, int y) -{ - unsigned short * tr = this->vtable->m07_m05_Get_Pixel (this, __, x, y); - - if ((x + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Width2) && (y + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Height2)) { - unsigned short * below = this->vtable->m07_m05_Get_Pixel (this, __, x + 1, y + 1); - if (below != NULL) - *below = 0; - } - - return tr; -} - -enum branch_kind { BK_CALL, BK_JUMP }; - -byte * -emit_branch (enum branch_kind kind, byte * cursor, void const * target) -{ - int offset = (int)target - ((int)cursor + 5); - *cursor++ = (kind == BK_CALL) ? 0xE8 : 0xE9; - return int_to_bytes (cursor, offset); -} - -// Just calls VirtualProtect and displays an error message if it fails. Made for use by the WITH_MEM_PROTECTION macro. -bool -check_virtual_protect (LPVOID addr, SIZE_T size, DWORD flags, PDWORD old_protect) -{ - if (VirtualProtect (addr, size, flags, old_protect)) - return true; - else { - char err_msg[1000]; - snprintf (err_msg, sizeof err_msg, "VirtualProtect failed! Args:\n Address: 0x%p\n Size: %d\n Flags: 0x%x", addr, size, flags); - err_msg[(sizeof err_msg) - 1] = '\0'; - MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); - return false; - } -} - -#define WITH_MEM_PROTECTION(addr, size, flags) \ - for (DWORD old_protect, unused, iter_count = 0; \ - (iter_count == 0) && check_virtual_protect (addr, size, flags, &old_protect); \ - VirtualProtect (addr, size, old_protect, &unused), iter_count++) - -void __fastcall adjust_sliders_preproduction (Leader * this); - -struct saved_code_area { - int size; - byte original_contents[]; -}; - -// Saves an area of base game code and optionally replaces it with no-ops. The area can be restored with restore_code_area. This method assumes that -// the necessary memory protection has already been set on the area, specifically that it can be written to. The method will do nothing if the area -// has already been saved with the same size. It's an error to re-save an address with a different size or overlap two saved areas. -void -save_code_area (byte * addr, int size, bool nopify) -{ - struct saved_code_area * sca; - if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { - if (sca->size != 0) { - if (sca->size != size) { - char s[200]; - snprintf (s, sizeof s, "Save code area conflict: address %p was already saved with size %d, conflicting with new size %d.", addr, sca->size, size); - s[(sizeof s) - 1] = '\0'; - pop_up_in_game_error (s); - } - return; - } - } else { - sca = malloc (size + sizeof *sca); - itable_insert (&is->saved_code_areas, (int)addr, (int)sca); - } - sca->size = size; - memcpy (&sca->original_contents, addr, size); - if (nopify) - memset (addr, 0x90, size); -} - -// Restores a saved chunk of code to its original contents. Does nothing if the area hasn't been saved. Assumes the appropriate memory protection has -// already been set. -void -restore_code_area (byte * addr) -{ - struct saved_code_area * sca; - if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { - memcpy (addr, &sca->original_contents, sca->size); - sca->size = 0; - } -} - -bool -is_code_area_saved (byte * addr) -{ - struct saved_code_area * sca; - return itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca) && (sca->size > 0); -} - -// Nopifies or restores an area depending on if yes_or_no is 1 or 0. Sets the necessary memory protections. -void -set_nopification (int yes_or_no, byte * addr, int size) -{ - WITH_MEM_PROTECTION (addr, size, PAGE_EXECUTE_READWRITE) { - if (yes_or_no) - save_code_area (addr, size, true); - else - restore_code_area (addr); - } -} - -void -apply_machine_code_edits (struct c3x_config const * cfg, bool at_program_start) -{ - DWORD old_protect, unused; - - // Allow stealth attack against single unit - WITH_MEM_PROTECTION (ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK = cfg->allow_stealth_attack_against_single_unit ? 0 : 1; - - // Enable small wonders providing free buildings - WITH_MEM_PROTECTION (ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER, 10, PAGE_EXECUTE_READWRITE) { - byte normal[8] = {0x83, 0xE1, 0x04, 0x80, 0xF9, 0x04, 0x0F, 0x85}; // and ecx, 4; cmp ecx, 4; jnz [offset] - byte modded[8] = {0x83, 0xE1, 0x0C, 0x80, 0xF9, 0x00, 0x0F, 0x84}; // and ecx, 12; cmp ecx, 0; jz [offset] - for (int n = 0; n < 8; n++) - ((byte *)ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER)[n] = cfg->enable_free_buildings_from_small_wonders ? modded[n] : normal[n]; - } - - // Bypass artillery in city check - // replacing 0x74 (= jump if [city ptr is] zero) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_CHECK_ARTILLERY_IN_CITY, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_CHECK_ARTILLERY_IN_CITY = cfg->use_offensive_artillery_ai ? 0xEB : 0x74; - - // Remove unit limit - if (! at_program_start) { - // Replace 0x7C (= jump if less than [unit limit]) with 0xEB (= uncond. jump) in Leader::spawn_unit - WITH_MEM_PROTECTION (ADDR_UNIT_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_UNIT_COUNT_CHECK = cfg->remove_unit_limit ? 0xEB : 0x7C; - - // Increase max ID to search for tradable units by 10x if limit removed - WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_UNIT_ID, 4, PAGE_EXECUTE_READWRITE) - int_to_bytes (ADDR_MAX_TRADABLE_UNIT_ID, cfg->remove_unit_limit ? 81920 : 8192); - - // Reallocate diplo_form->tradable_units array so it's 10x long if limit removed - civ_prog_free (p_diplo_form->tradable_units); - int tradable_units_len = cfg->remove_unit_limit ? 81920 : 8192, - tradable_units_size = tradable_units_len * sizeof (TradableItem); - p_diplo_form->tradable_units = new (tradable_units_size); - for (int n = 0; n < tradable_units_len; n++) - p_diplo_form->tradable_units[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 - - // Patch the size limit on some code that clears the tradable units array when starting a new game - WITH_MEM_PROTECTION (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) - int_to_bytes (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, tradable_units_size); - } - - // Remove the standard rule that blocks battle-created units while the player already has one - set_nopification (cfg->allow_multiple_battle_created_units_per_player, ADDR_EXISTING_BATTLE_CREATED_UNIT_CHECK, 6); - - // Bypass air unit check when drawing pedia stats. If it passes, the check will draw the op. range instead of movement in the first column. - // replacing 0x75 (= jnz) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS, 1, PAGE_EXECUTE_READWRITE) - *ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS = is->current_config.expand_civilopedia_unit_stats ? 0xEB : 0x75; - - // Remove era limit - // replacing 0x74 (= jump if zero [after cmp'ing era count with 4]) with 0xEB - WITH_MEM_PROTECTION (ADDR_ERA_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_ERA_COUNT_CHECK = cfg->remove_era_limit ? 0xEB : 0x74; - - // Fix science age bug - // Similar in nature to the sub bug, the function that measures a city's research output accepts a flag that determines whether or not it - // takes science ages into account. It's mistakenly not set by the code that gathers all research points to increment tech progress (but it - // is set elsewhere in code for the interface). The patch simply sets this flag. - WITH_MEM_PROTECTION (ADDR_SCIENCE_AGE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_SCIENCE_AGE_BUG_PATCH = cfg->patch_science_age_bug ? 1 : 0; - - // Pedia pink line bug fix - // The size of the pedia background texture is hard-coded into the EXE and in the base game it's one pixel too small. This shows up in game as - // a one pixel wide pink line along the right edge of the civilopedia. This patch simply increases the texture width by one. - WITH_MEM_PROTECTION (ADDR_PEDIA_TEXTURE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_PEDIA_TEXTURE_BUG_PATCH = cfg->patch_pedia_texture_bug ? 0xA6 : 0xA5; - - // Fix for houseboat bug - // See my posts on CFC for an explanation of the bug and its fix: - // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16084386 - // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16085242 - WITH_MEM_PROTECTION (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, PAGE_EXECUTE_READWRITE) { - if (cfg->patch_houseboat_bug) { - save_code_area (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, true); - byte * cursor = ADDR_HOUSEBOAT_BUG_PATCH; - *cursor++ = 0x50; // push eax - int call_offset = (int)&tile_at_city_or_null - ((int)cursor + 5); - *cursor++ = 0xE8; // call - cursor = int_to_bytes (cursor, call_offset); - } else - restore_code_area (ADDR_HOUSEBOAT_BUG_PATCH); - } - - // NoRaze - WITH_MEM_PROTECTION (ADDR_AUTORAZE_BYPASS, 2, PAGE_EXECUTE_READWRITE) { - byte normal[2] = {0x0F, 0x85}; // jnz - byte bypass[2] = {0x90, 0xE9}; // nop, jmp - for (int n = 0; n < 2; n++) - ((byte *)ADDR_AUTORAZE_BYPASS)[n] = cfg->prevent_autorazing ? bypass[n] : normal[n]; - } - - // Overwrite the instruction(s) where the AI's production choosing code compares the value of what it's currently considering to the best - // option so far. This is done twice since improvements and units are handled in separate loops. The instr(s) are overwritten with a jump to - // an "airlock", which is a bit of code that wraps the call to intercept_consideration. The contents of the airlocks are prepared by the - // patcher in init_consideration_airlocks. - // TODO: This instruction replacement could be done in the patcher too and that might be a better place for it. Think about this. - for (int n = 0; n < 2; n++) { - void * addr_intercept = (n == 0) ? ADDR_INTERCEPT_AI_IMPROV_VALUE : ADDR_INTERCEPT_AI_UNIT_VALUE; - void * addr_airlock = (n == 0) ? ADDR_IMPROV_CONSIDERATION_AIRLOCK : ADDR_UNIT_CONSIDERATION_AIRLOCK; - - WITH_MEM_PROTECTION (addr_intercept, AI_CONSIDERATION_INTERCEPT_LEN, PAGE_EXECUTE_READWRITE) { - byte * cursor = addr_intercept; - - // write jump to airlock - *cursor++ = 0xE9; - int offset = (int)addr_airlock - ((int)addr_intercept + 5); - cursor = int_to_bytes (cursor, offset); - - // fill the rest of the space with NOPs - while (cursor < (byte *)addr_intercept + AI_CONSIDERATION_INTERCEPT_LEN) - *cursor++ = 0x90; // nop - } - } - - // Overwrite instruction that sets bits in City.Body.Available_Resources with a jump to the airlock - WITH_MEM_PROTECTION (ADDR_INTERCEPT_SET_RESOURCE_BIT, 6, PAGE_EXECUTE_READWRITE) { - byte * cursor = ADDR_INTERCEPT_SET_RESOURCE_BIT; - if (cfg->patch_phantom_resource_bug) { - *cursor++ = 0xE9; - int offset = (int)ADDR_SET_RESOURCE_BIT_AIRLOCK - ((int)ADDR_INTERCEPT_SET_RESOURCE_BIT + 5); - cursor = int_to_bytes (cursor, offset); - *cursor++ = 0x90; // nop - } else { - byte original[6] = {0x09, 0xB0, 0x9C, 0x00, 0x00, 0x00}; // or dword ptr [eax+0x9C], esi - for (int n = 0; n < 6; n++) - cursor[n] = original[n]; - } - } - - // Enlarge the mask that's applied to p_bic_data->Map.TileCount in the loop over lines in Trade_Net::recompute_resources. This lets us loop - // over more than 0xFFFF tiles. - WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_MASK, 1, PAGE_EXECUTE_READWRITE) { - *(byte *)ADDR_RESOURCE_TILE_COUNT_MASK = (cfg->count_mills > 0) ? 0xFF : 0x00; - } - // Similarly, enlarge the cmp instruction that jumps over the entire loop when the tile count is zero. Do this by simply removing the operand - // override prefix byte (0x66), overwriting it with a nop (0x90). This converts the instruction "cmp word ptr [bic_data.Map.TileCount], di" - // into "nop; cmp dword ptr [bic_data.Map.TileCount], edi" - WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE, 1, PAGE_EXECUTE_READWRITE) { - *(byte *)ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE = 0x90; - } - - byte * addr_turn_metalimits[] = {ADDR_TURN_METALIMIT_1, ADDR_TURN_METALIMIT_2, ADDR_TURN_METALIMIT_3, ADDR_TURN_METALIMIT_4, - ADDR_TURN_METALIMIT_5, ADDR_TURN_METALIMIT_6, ADDR_TURN_METALIMIT_7}; - for (int n = 0; n < ARRAY_LEN (addr_turn_metalimits); n++) { - byte * addr = addr_turn_metalimits[n]; - WITH_MEM_PROTECTION (addr, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (addr, cfg->remove_cap_on_turn_limit ? 1000000 : 1000); - } - } - - // Overwrite the human-ness test and call to Leader::ai_adjust_sliders that happens during the preproduction player update method. The new - // code calls adjust_sliders_preproduction for all players. - WITH_MEM_PROTECTION (ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT, 9, PAGE_EXECUTE_READWRITE) { - byte * cursor = ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT; - *cursor++ = 0x8B; *cursor++ = 0xCE; // mov ecx, esi - cursor = emit_branch (BK_CALL, cursor, adjust_sliders_preproduction); - for (; cursor < ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT + 9; cursor++) - *cursor = 0x90; // nop - } - - // Set up a special intercept of the base game's calls to print_int in order to grab a pointer to a gold TradeOffer object being modified. The - // calls to print_int happen in the context of creating the default text to be placed in the set-gold-amount popup. Conveniently, a pointer to - // the TradeOffer object is always stored in register ecx when this call happens. It's not easily accessible since print_int uses the cdecl - // convention so we must use an airlock-like thing to effectively convert the calling convention to fastcall. The first part of this code - // simply replaces the call to print_int with a call to the airlock-like thing, and the second part initializes its contents. - byte * addr_print_gold_amounts[] = {ADDR_PRINT_GOLD_AMOUNT_1, ADDR_PRINT_GOLD_AMOUNT_2}; - for (int n = 0; n < ARRAY_LEN (addr_print_gold_amounts); n++) { - byte * addr = addr_print_gold_amounts[n]; - WITH_MEM_PROTECTION (addr, 5, PAGE_EXECUTE_READWRITE) - emit_branch (BK_CALL, addr, ADDR_CAPTURE_MODIFIED_GOLD_TRADE); - } - WITH_MEM_PROTECTION (ADDR_CAPTURE_MODIFIED_GOLD_TRADE, 32, PAGE_EXECUTE_READWRITE) { - byte * cursor = ADDR_CAPTURE_MODIFIED_GOLD_TRADE; - - // Repush all of the arguments to print_int onto the stack, they will be consumed by do_capture_modified_gold_trade since it's - // fastcall. The original args don't need to be removed b/c we're replacing a cdecl function so that's the caller's - // responsibility. The TradeOffer pointer is already in ECX, so that's fine as long as we don't touch that register. - byte repush[] = {0xFF, 0x74, 0x24, 0x0C}; // push [esp+0xC] - for (int n = 0; n < 3; n++) - for (int k = 0; k < ARRAY_LEN (repush); k++) - *cursor++ = repush[k]; - - cursor = emit_branch (BK_CALL, cursor, do_capture_modified_gold_trade); // call do_capture_modified_gold_trade - *cursor++ = 0xC3; // ret - } - - // Edit branch in capture_city to never run code for barbs, this allows barbs to capture cities - WITH_MEM_PROTECTION (ADDR_CAPTURE_CITY_BARB_BRANCH, 2, PAGE_EXECUTE_READWRITE) { - byte normal[2] = {0x0F, 0x85}; // jnz - byte bypass[2] = {0x90, 0xE9}; // nop, jmp - for (int n = 0; n < 2; n++) - ((byte *)ADDR_CAPTURE_CITY_BARB_BRANCH)[n] = cfg->enable_city_capture_by_barbarians ? bypass[n] : normal[n]; - } - - // After the production phase is done for the barb player, there are two jump instructions skipping the production code for civs. Replacing - // those jumps lets us run the civ production code for the barbs as well. - WITH_MEM_PROTECTION (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, PAGE_EXECUTE_READWRITE) { - if (cfg->enable_city_capture_by_barbarians) { - save_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, true); - byte jump_to_civ[6] = {0x0F, 0x8D, 0x0C, 0x00, 0x00, 0x00}; // jge +0x12 - for (int n = 0; n < 6; n++) - ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP[n] = jump_to_civ[n]; - } else - restore_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP); - } - set_nopification (cfg->enable_city_capture_by_barbarians, ADDR_PROD_PHASE_BARB_DONE_JUMP, 5); - - for (int domain = 0; domain < 2; domain++) { - byte * addr_skip = (domain == 0) ? ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC : ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC, - * addr_airlock = (domain == 0) ? ADDR_SEA_ZOC_FILTER_AIRLOCK : ADDR_LAND_ZOC_FILTER_AIRLOCK; - - WITH_MEM_PROTECTION (addr_skip, 6, PAGE_EXECUTE_READWRITE) { - if ((cfg->special_zone_of_control_rules != 0) && ! is_code_area_saved (addr_skip)) { - byte * original_target = addr_skip + 6 + int_from_bytes (addr_skip + 2); // target addr of jump instr we're replacing - save_code_area (addr_skip, 6, true); - - // Initialize airlock. The airlock preserves all registers and calls filter_zoc_candidate then either follows or skips the - // original jump depending on what it returns. If zero is returned, follows the jump, skipping a bunch of code and filtering - // out the unit as a candidate for ZoC. - WITH_MEM_PROTECTION (addr_airlock, INLEAD_SIZE, PAGE_READWRITE) { - byte * cursor = addr_airlock; - *cursor++ = 0x60; // pusha - *cursor++ = 0x54; // push esp - cursor = emit_branch (BK_CALL, cursor, filter_zoc_candidate); - *cursor++ = 0x83; *cursor++ = 0xF8; *cursor++ = 0x01; // cmp eax, 1 - *cursor++ = 0x75; *cursor++ = 0x06; // jne 6 - *cursor++ = 0x61; // popa - cursor = emit_branch (BK_JUMP, cursor, addr_skip + 6); - *cursor++ = 0x61; // popa - cursor = emit_branch (BK_JUMP, cursor, original_target); - } - - // Write jump to airlock - emit_branch (BK_JUMP, addr_skip, addr_airlock); - } else if (cfg->special_zone_of_control_rules == 0) - restore_code_area (addr_skip); - } - } - - set_nopification ( cfg->special_zone_of_control_rules != 0, ADDR_ZOC_CHECK_ATTACKER_ANIM_FIELD_111, 6); - set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_LAND_UNIT , 6); - set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_SEA_UNIT , 6); - - WITH_MEM_PROTECTION (ADDR_LUXURY_BOX_ROW_HEIGHT, 4, PAGE_EXECUTE_READWRITE) { - byte normal [4] = {0x8B, 0x44, 0x24, LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET}; // mov eax, dword ptr [esp + LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET] - byte compact[4] = {0x31, 0xC0, 0xB0, 0x10}; // xor eax, eax; mov al, 0x10 - for (int n = 0; n < 4; n++) - ADDR_LUXURY_BOX_ROW_HEIGHT[n] = cfg->compact_luxury_display_on_city_screen ? compact[n] : normal[n]; - } - - WITH_MEM_PROTECTION (ADDR_MOST_STRAT_RES_ON_CITY_SCREEN, 1, PAGE_EXECUTE_READWRITE) { - *(byte *)ADDR_MOST_STRAT_RES_ON_CITY_SCREEN = cfg->compact_strategic_resource_display_on_city_screen ? 13 : 8; - } - - // Remove a check that a returned neighbor index is within the 21 tile work area in code related to hoving the mouse over the work area on the - // city screen. This check is redundant and could be removed always, but only do so if work area is expanded. - set_nopification (cfg->city_work_radius > 2, ADDR_REDUNDANT_CHECK_ON_WORK_AREA_HOVER, 6); - - // Skip redundant check of clicked tile's neighbor index in City_Form::handle_left_click. - WITH_MEM_PROTECTION (ADDR_CITY_FORM_LEFT_CLICK_JUMP, 1, PAGE_EXECUTE_READWRITE) { - *ADDR_CITY_FORM_LEFT_CLICK_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) - } - - // Skip check that neighbor index passed to City::controls_tile is within work radius. This check is now implemented in the patch func. - WITH_MEM_PROTECTION (ADDR_CONTROLS_TILE_JUMP, 1, PAGE_EXECUTE_READWRITE) { - *ADDR_CONTROLS_TILE_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) - } - - // When searching for a tile on which to spawn pollution, the game wraps its search around by using remainder after division. Here, we replace - // the dividend to match a potentially expanded city work area. - WITH_MEM_PROTECTION (ADDR_SPAWN_POLLUTION_MOD, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_SPAWN_POLLUTION_MOD, is->workable_tile_count - 1); - } - - WITH_MEM_PROTECTION (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, cfg->patch_premature_truncation_of_found_paths ? 2560 : 256); - } - - int * trade_net_addrs; - bool already_moved_trade_net = is->trade_net != p_original_trade_net, - want_moved_trade_net = cfg->city_limit > 512; - int lifted_city_limit_exp = 11; - int lifted_city_limit = 1 << lifted_city_limit_exp; - if ((! at_program_start) && - ((trade_net_addrs = load_trade_net_addrs ()) != NULL) && - ((already_moved_trade_net && ! want_moved_trade_net) || (want_moved_trade_net && ! already_moved_trade_net))) { - // Allocate a new trade net object if necessary. To construct it, all we have to do is zero a few fields and set the vptr. Otherwise, - // set the allocated object aside for deletion later. Also set new & old addresses to the locations we're moving to & from. - Trade_Net * to_free = NULL; - int p_old, p_new; - if (want_moved_trade_net) { - is->trade_net = calloc (1, (sizeof (Trade_Net)) - (4 * 512 * 512) + (4 * lifted_city_limit * lifted_city_limit)); - is->city_limit = lifted_city_limit; - is->trade_net->vtable = p_original_trade_net->vtable; - p_old = (int)p_original_trade_net; - p_new = (int)is->trade_net; - } else { - to_free = is->trade_net; - is->city_limit = 512; - p_old = (int)is->trade_net; - p_new = (int)p_original_trade_net; - is->trade_net = p_original_trade_net; - } - already_moved_trade_net = is->trade_net != p_original_trade_net; // Keep this variable up to date - - // Patch all references from the "old" object to the "new" one - int offset; - bool popped_up_error = false; - char err_msg[200] = {0}; - int * refs; { - if (exe_version_index == 0) - refs = trade_net_addrs; - else if (exe_version_index == 1) // Steam version, skip refs and instructions for GOG - refs = &trade_net_addrs[TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; - else // PCGames.de version, skip two sets of refs and instrs for GOG & Steam - refs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; - } - for (int n_ref = 0; n_ref < TRADE_NET_REF_COUNT; n_ref++) { - int addr = refs[n_ref]; - WITH_MEM_PROTECTION ((void *)(addr - 10), 20, PAGE_EXECUTE_READWRITE) { - byte * instr = (byte *)addr; - if ((instr[0] == 0xB9) && (int_from_bytes (&instr[1]) == p_old)) // move trade net ptr to ecx - int_to_bytes (&instr[1], p_new); - else if ((instr[0] == 0xC7) && (instr[1] == 0x05) && (int_from_bytes (&instr[2]) == p_old)) // write trade net vtable ptr - int_to_bytes (&instr[2], p_new); - else if ((instr[0] == 0x81) && (instr[1] == 0xFE) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp esi, trade net location - ; // Do not patch this location because it's the upper limit for a memcpy - else if ((instr[0] == 0x81) && (instr[1] == 0xFF) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp edi, trade net location - ; // Same - else if ((instr[0] == 0x81) && (instr[1] == 0xFA) && (int_from_bytes (&instr[2]) == (int)&p_original_trade_net->Data2)) // cmp edx, trade net data2 location - ; // Same - else if (((instr[0] == 0xA3) || (instr[0] == 0xA1)) && // move eax to field or vice-versa - (offset = int_from_bytes (&instr[1]) - p_old, (offset >= 0) && (offset < 100))) - int_to_bytes (&instr[1], p_new + offset); - else if ((instr[0] == 0x89) && ((instr[1] >= 0x0D) && (instr[1] <= 0x3D)) && // move other regs to field - (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) - int_to_bytes (&instr[2], p_new + offset); - else if ((instr[0] == 0x8B) && ((instr[1] == 0x35) || (instr[1] == 0x3D) || (instr[1] == 0x0D)) && // mov field to esi, edi or ecx - (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) - int_to_bytes (&instr[2], p_new + offset); - else if (! popped_up_error) { - snprintf (err_msg, (sizeof err_msg) - 1, "Can't move trade net object from address 0x%x. Pattern doesn't match.", addr); - MessageBox (NULL, err_msg, NULL, MB_ICONERROR); - popped_up_error = true; - } - } - } - - // Patch all instructions that involve the stride of Trade_Net.Matrix - int * addrs, addr_count; { - if (exe_version_index == 0) { - addrs = &trade_net_addrs[TRADE_NET_REF_COUNT]; - addr_count = TRADE_NET_INSTR_COUNT_GOG; - } else if (exe_version_index == 1) { - addrs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; - addr_count = TRADE_NET_INSTR_COUNT_STEAM; - } else { - addrs = &trade_net_addrs[3 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; - addr_count = TRADE_NET_INSTR_COUNT_GOG; - } - for (int n = 0; n < addr_count; n++) { - byte * instr = (byte *)addrs[n]; - WITH_MEM_PROTECTION (instr, 10, PAGE_EXECUTE_READWRITE) { - if (! want_moved_trade_net) - restore_code_area (instr); - - else { - if ((instr[0] == 0xC1) && (instr[1] >= 0xE0) && (instr[1] <= 0xE7)) { // shl - save_code_area (instr, 3, false); - // shift amount is either 9 (1<<9 == 512) or 11 (1<<11 == 4*512, stride in bytes) - // in the second case, replace with lifted_exp + 2 to convert to bytes - instr[2] = lifted_city_limit_exp + ((instr[2] == 11) ? 2 : 0); - - } else if ((instr[0] == 0x81) && (instr[1] >= 0xC0) && (instr[1] <= 0xC7)) { // add - save_code_area (instr, 6, false); - int amount = int_from_bytes (&instr[2]); - // amount is either 512 or 4*512, replace with lifted_lim or 4*lifted_lim - int_to_bytes (&instr[2], (amount == 512) ? lifted_city_limit : 4*lifted_city_limit); - - } else if ((instr[0] == 0x8D) && (instr[1] == 0x9C) && (instr[2] == 0x90)) { // lea - save_code_area (instr, 7, false); - int offset = 4 * lifted_city_limit + 0x38; // stride in bytes plus 0x38 offset to Matrix in Trade_Net object - int_to_bytes (&instr[3], offset); - - } else if (instr[0] == 0xB9) { // mov - save_code_area (instr, 5, false); - int_to_bytes (&instr[1], lifted_city_limit * lifted_city_limit); - - } else if (! popped_up_error) { - snprintf (err_msg, (sizeof err_msg) - 1, "Can't patch matrix stride at address 0x%x. Pattern doesn't match.", (int)instr); - MessageBox (NULL, err_msg, NULL, MB_ICONERROR); - popped_up_error = true; - } - } - } - } - } - - // Reallocate diplo_form->tradable_cities array so it matches the city limit - civ_prog_free (p_diplo_form->tradable_cities); - int tradable_cities_len = want_moved_trade_net ? lifted_city_limit : 512, - tradable_cities_size = tradable_cities_len * sizeof (TradableItem); - p_diplo_form->tradable_cities = new (tradable_cities_size); - for (int n = 0; n < tradable_cities_len; n++) - p_diplo_form->tradable_cities[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 - - // Patch the size limit on some code that clears the tradable cities array when starting a new game - WITH_MEM_PROTECTION (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, tradable_cities_size); - } - - if (to_free) { - to_free->vtable->destruct (to_free, __, 0); - free (to_free); - } - } - - // Set is->city_limit and patch two instructions that contain the limit - is->city_limit = clamp (0, already_moved_trade_net ? lifted_city_limit : 512, cfg->city_limit); - WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN, 6, PAGE_EXECUTE_READWRITE) { - int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN[2], is->city_limit); - } - WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CREATE_CITY, 5, PAGE_EXECUTE_READWRITE) { - int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CREATE_CITY[1], is->city_limit); - } - WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_CITY_ID, 4, PAGE_EXECUTE_READWRITE) { - int_to_bytes (ADDR_MAX_TRADABLE_CITY_ID, already_moved_trade_net ? lifted_city_limit : 512); - } - - WITH_MEM_PROTECTION (ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR, 6, PAGE_EXECUTE_READWRITE) { - byte * instr = ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR; - if (cfg->years_to_double_building_culture == 1000) - restore_code_area (instr); - else { - if (instr[0] == 0x3D) { // in GOG and PCG EXEs, instr is cmp eax, 0x3E8 - save_code_area (instr, 5, false); - int_to_bytes (&instr[1], cfg->years_to_double_building_culture); - } else if (instr[0] == 0x3B) { // in Steam EXE, instr is cmp eax, dword ptr 0x688C9C - save_code_area (instr, 6, true); - instr[0] = 0x3D; - int_to_bytes (&instr[1], cfg->years_to_double_building_culture); - } - } - } - - WITH_MEM_PROTECTION (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, PAGE_EXECUTE_READWRITE) { - if (cfg->accentuate_cities_on_minimap) { - save_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, false); - emit_branch (BK_JUMP, ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL); - } else - restore_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT); - } - WITH_MEM_PROTECTION (ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { - byte * code = ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL; - code[0] = 0x55; code[1] = 0x53; // write push ebp and push ebx, two overwritten instrs before the call - emit_branch (BK_CALL, &code[2], &patch_get_pixel_to_draw_city_dot); // call patch func - emit_branch (BK_JUMP, &code[7], ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT + 5); // jump back to original code - } - - // Bypass adjacent resource of different type check - // replacing 0x7D (= jge) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9, 1, PAGE_EXECUTE_READWRITE) - *(byte *)ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9 = cfg->allow_adjacent_resources_of_different_types ? 0xEB : 0x7D; - - WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, PAGE_EXECUTE_READWRITE) { - if (cfg->tiles_per_non_luxury_resource == 32) - restore_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV); - else { - save_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, true); - - // Jump to replacement division logic, kept in an inlead because it doesn't fit in 7 bytes - emit_branch (BK_JUMP, ADDR_RESOURCE_GEN_TILE_COUNT_DIV, ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL); - - // Fill in the replacement division logic. Instead of computing tile_count>>5, compute tile_count/cfg->tiles_per_non_luxury_resource. - WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { - int d = not_below (1, cfg->tiles_per_non_luxury_resource); - byte d0 = d & 0xFF, - d1 = (d >> 8) & 0xFF, - d2 = (d >> 16) & 0xFF, - d3 = d >> 24; - - byte * cursor = ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL; - - // In the Steam EXE, the limit (tile_count/32 by default) must be left in ecx. For the other EXEs, edx. - if (exe_version_index == 1) { - byte new_div[] = { - 0x50, // push eax - 0x52, // push edx - 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count - 0x0F, 0xB7, 0xD2, // movzx edx, dx - 0x89, 0xD0, // mov eax, edx - 0x31, 0xD2, // xor edx, edx - 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} - 0xF7, 0xF1, // div ecx - 0x89, 0xC1, // mov ecx, eax - 0x5A, // pop edx - 0x58 // pop eax - }; - for (int n = 0; n < ARRAY_LEN (new_div); n++) - *cursor++ = new_div[n]; - - } else { - byte new_div[] = { - 0x50, // push eax - 0x51, // push ecx - 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count - 0x0F, 0xB7, 0xD2, // movzx edx, dx - 0x89, 0xD0, // mov eax, edx - 0x31, 0xD2, // xor edx, edx - 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} - 0xF7, 0xF1, // div ecx - 0x89, 0xC2, // mov edx, eax - 0x59, // pop ecx - 0x58 // pop eax - }; - for (int n = 0; n < ARRAY_LEN (new_div); n++) - *cursor++ = new_div[n]; - } - - cursor = emit_branch (BK_JUMP, cursor, ADDR_RESOURCE_GEN_TILE_COUNT_DIV + 7); - } - } - } - - // Disable a jump that skips playing victory animations for air units if they've been configured to have a victory anim - set_nopification (cfg->aircraft_victory_animation != NULL, ADDR_SKIP_VICTORY_ANIM_IF_AIR, 6); - - // Bypass capital check to return zero corruption - // replacing 0x75 (= jnz) with 0xEB (= uncond. jump) - WITH_MEM_PROTECTION (ADDR_CORRUPTION_CAPITAL_CHECK, 1, PAGE_EXECUTE_READWRITE) - *ADDR_CORRUPTION_CAPITAL_CHECK = cfg->allow_corruption_in_capital ? 0xEB : 0x75; - - // Insert amount added to building decorruption effect just for the capital - WITH_MEM_PROTECTION (ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT, 3, PAGE_EXECUTE_READWRITE) - *(ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT + 2) = clamp (0, 100, cfg->special_capital_decorruption_effect); -} - -void -get_mod_art_path (char const * file_name, char * out_path, int path_buf_size) -{ - char s[1000]; - snprintf (s, sizeof s, "Art\\%s", file_name); - s[(sizeof s) - 1] = '\0'; - - char * scenario_path = BIC_get_asset_path (p_bic_data, __, s, false); - if (0 != strcmp (scenario_path, s)) // get_asset_path returns its input when the file is not found - snprintf (out_path, path_buf_size, "%s", scenario_path); - else - snprintf (out_path, path_buf_size, "%s\\Art\\%s", is->mod_rel_dir, file_name); - out_path[path_buf_size - 1] = '\0'; -} - - -Sprite* -SpriteList_at(SpriteList *list, int i) { - return &list->field_0[i]; -} - -void -set_path(String260 *dst, const char *p) { - snprintf(dst->S, sizeof(dst->S), "%s", p); -} - -void -slice_grid(Sprite *out, PCX_Image *img, - int tile_w, int tile_h, int full_w, int full_h) -{ - for (int y = 0; y < full_h; y += tile_h) - for (int x = 0; x < full_w; x += tile_w) - Sprite_slice_pcx(out++, __, img, x, y, tile_w, tile_h, 1, 1); -} - -void -slice_grid_into_list(SpriteList *bucket, PCX_Image *img, - int tile_w, int tile_h, int full_w, int full_h) -{ - int k = 0; - for (int y = 0; y < full_h; y += tile_h) - for (int x = 0; x < full_w; x += tile_w) - Sprite_slice_pcx(SpriteList_at(bucket, k++), __, img, x, y, tile_w, tile_h, 1, 1); -} - -void -join_path(char *out, size_t out_sz, const char *dir, const char *file) -{ - size_t n = strlen(dir); - int need_sep = (n > 0 && dir[n-1] != '/' && dir[n-1] != '\\'); - snprintf(out, out_sz, "%s%s%s", dir, need_sep ? "\\" : "", file); -} - -void -read_in_dir(PCX_Image *img, - const char *art_dir, - const char *filename, - String260 *store) { - char pbuf[512]; - join_path(pbuf, sizeof pbuf, art_dir, filename); - if (store) { - // assumes: typedef struct { char S[260]; } String260; - snprintf(store->S, sizeof store->S, "%s", pbuf); - } - - char temp_path[2*MAX_PATH]; - - snprintf(temp_path, sizeof temp_path, "%s\\%s", art_dir, filename); - PCX_Image_read_file(img, __, temp_path, NULL, 0, 0x100, 2); -} - -bool load_day_night_hour_images(struct day_night_cycle_img_set *this, const char *art_dir, const char *hour) -{ - char ss[200]; - PCX_Image img; - PCX_Image_construct(&img); - - // Std terrain (9 sheets): 6x9 of 128x64 over 0x480x0x240 - const char *STD_SHEETS[9] = { - "xtgc.pcx", "xpgc.pcx", "xdgc.pcx", "xdpc.pcx", "xdgp.pcx", "xggc.pcx", - "wCSO.pcx", "wSSS.pcx", "wOOO.pcx" - }; - for (int i = 0; i < 9; ++i) { - read_in_dir(&img, art_dir, STD_SHEETS[i], NULL); - if (img.JGL.Image == NULL) return false; - slice_grid_into_list(&this->Std_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); - } - - // LM terrain (9): same slicing - const char *LMT_SHEETS[9] = { - "lxtgc.pcx", "lxpgc.pcx", "lxdgc.pcx", "lxdpc.pcx", "lxdgp.pcx", "lxggc.pcx", - "lwCSO.pcx", "lwSSS.pcx", "lwOOO.pcx" - }; - for (int i = 0; i < 9; ++i) { - read_in_dir(&img, art_dir, LMT_SHEETS[i], NULL); - if (img.JGL.Image == NULL) return false; - slice_grid_into_list(&this->LM_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); - } - - // Polar icecaps: 8x4 of 128x64 - read_in_dir(&img, art_dir, "polarICEcaps-final.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Polar_Icecaps_Images, &img, 0x80, 0x40, 0x400, 0x100); - - // Hills / LM Hills: 4x3 of 128x72 - read_in_dir(&img, art_dir, "xhills.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); - read_in_dir(&img, art_dir, "hill forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Hills_Forests_Images, &img, 0x80, 0x48, 0x200, 0x120); - read_in_dir(&img, art_dir, "hill jungle.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Hills_Jungle_Images, &img, 0x80, 0x48, 0x200, 0x120); - read_in_dir(&img, art_dir, "LMHills.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->LM_Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); - - // Flood plains: 4x4 of 128x64 - read_in_dir(&img, art_dir, "floodplains.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Flood_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); - - // Delta + Mountain rivers: 4x4 each, interleaved across one contiguous block - { - const char *RIV_SHEETS[2] = { "deltaRivers.pcx", "mtnRivers.pcx" }; - Sprite *contig = this->Delta_Rivers_Images; // Mountain_Rivers_Images follows - for (int s = 0; s < 2; ++s) { - read_in_dir(&img, art_dir, RIV_SHEETS[s], NULL); - if (img.JGL.Image == NULL) return false; - Sprite *p = contig + s; // even=delta, odd=mountain - for (int y = 0; y < 0x100; y += 0x40) - for (int x = 0; x < 0x200; x += 0x80) { - Sprite_slice_pcx(p, __, &img, x, y, 0x80, 0x40, 1, 1); - p += 2; - } - } - } - - // Waterfalls: 4x1 of 128x64 - read_in_dir(&img, art_dir, "waterfalls.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Waterfalls_Images, &img, 0x80, 0x40, 0x200, 0x40); - - // Irrigation (desert/plains/normal/tundra): each 4x4 of 128x64 - read_in_dir(&img, art_dir, "irrigation DESETT.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Desert_Images, &img, 0x80, 0x40, 0x200, 0x100); - read_in_dir(&img, art_dir, "irrigation PLAINS.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); - read_in_dir(&img, art_dir, "irrigation.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Images, &img, 0x80, 0x40, 0x200, 0x100); - read_in_dir(&img, art_dir, "irrigation TUNDRA.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Irrigation_Tundra_Images, &img, 0x80, 0x40, 0x200, 0x100); - - // Volcanos (plain/forests/jungles/snow): 4x4 of 128x88 - read_in_dir(&img, art_dir, "Volcanos.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Volcanos forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Volcanos jungles.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Volcanos-snow.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Volcanos_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); - - // Marsh: Large band then Small band (tiles 128x88) - read_in_dir(&img, art_dir, "marsh.pcx", NULL); - if (img.JGL.Image == NULL) return false; - // Large (2 rows, 4 cols) - { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Marsh_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - // Small (2 rows, 5 cols) - { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Marsh_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - // LM mountains + standard mountains (plain/forests/jungles/snow): 4x4 of 128x88 - read_in_dir(&img, art_dir, "LMMountains.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->LM_Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Mountains.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "mountain forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "mountain jungles.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); - read_in_dir(&img, art_dir, "Mountains-snow.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Mountains_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); - - // Roads (16x16) and Railroads (16x17), tiles 128x64 - read_in_dir(&img, art_dir, "roads.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Roads_Images, &img, 0x80, 0x40, 0x800, 0x400); - read_in_dir(&img, art_dir, "railroads.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Railroads_Images, &img, 0x80, 0x40, 0x800, 0x440); - - // LM Forests (Large 2x4, Small 2x6, Pines 2x6), tiles 128x88 - read_in_dir(&img, art_dir, "LMForests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->LM_Forests_Large_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->LM_Forests_Small_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->LM_Forests_Pines_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - // Grassland/Plains/Tundra forests & jungles (bands; tiles 128x88) — order is important - read_in_dir(&img, art_dir, "grassland forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - // Jungles Large, Small - { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Jungles_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Jungles_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - // Forests Large, Small, Pines - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Grassland_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - read_in_dir(&img, art_dir, "plains forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Plains_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Plains_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Plains_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - read_in_dir(&img, art_dir, "tundra forests.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) - Sprite_slice_pcx(&this->Tundra_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) - Sprite_slice_pcx(&this->Tundra_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) - Sprite_slice_pcx(&this->Tundra_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } - - // LM Terrain (7 single 128x64, vertical strip) - read_in_dir(&img, art_dir, "landmark_terrain.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i = 0, y = 0; i < 7; ++i, y += 0x40) - Sprite_slice_pcx(&this->LM_Terrain[i], __, &img, 0, y, 0x80, 0x40, 1, 1); - - // TNT (same odd ordering as original) - read_in_dir(&img, art_dir, "tnt.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[6+i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[9+i], __, &img, x, 0x40, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[12+i], __, &img, x, 0x80, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[0+i], __, &img, x, 0xC0, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[15+i], __, &img, x, 0x100, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[3+i], __, &img, x, 0x140, 0x80, 0x40, 1, 1); - - // Goody huts: 8 tiles, x=(i%3)*0x80, y=(i/3)*0x40 - read_in_dir(&img, art_dir, "goodyhuts.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i = 0; i < 8; ++i) { - int x = (i % 3) << 7; - int y = (i / 3) << 6; - Sprite_slice_pcx(&this->Goody_Huts_Images[i], __, &img, x, y, 0x80, 0x40, 1, 1); - } - - // Terrain buildings (fortress/camp/barbarian camp/mines/barricade) - read_in_dir(&img, art_dir, "TerrainBuildings.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Fortress[i], __, &img, 0x00, y, 0x80, 0x40, 1, 1); - for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Camp[i], __, &img, 0x80, y, 0x80, 0x40, 1, 1); - Sprite_slice_pcx(&this->Terrain_Buldings_Barbarian_Camp, __, &img, 0x100, 0x00, 0x80, 0x40, 1, 1); - Sprite_slice_pcx(&this->Terrain_Buldings_Mines, __, &img, 0x100, 0x40, 0x80, 0x40, 1, 1); - for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Barricade[i], __, &img, 0x180, y, 0x80, 0x40, 1, 1); - - // Pollution & Craters (5x5 of 128x64) - read_in_dir(&img, art_dir, "pollution.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Pollution, &img, 0x80, 0x40, 0x280, 0x140); - read_in_dir(&img, art_dir, "craters.pcx", NULL); - if (img.JGL.Image == NULL) return false; - slice_grid(this->Craters, &img, 0x80, 0x40, 0x280, 0x140); - - // Airfields / Outposts / Radar - read_in_dir(&img, art_dir, "x_airfields and detect.pcx", NULL); - if (img.JGL.Image == NULL) return false; - for (int i=0, x=0; i<2; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Airfields[i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); - for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Outposts[i], __, &img, x, 0x40, 0x80, 0x80, 1, 1); - Sprite_slice_pcx(&this->Terrain_Buldings_Radar, __, &img, 0x00, 0xC0, 0x80, 0x80, 1, 1); - - // Victory (single 128x64) - read_in_dir(&img, art_dir, "x_victory.pcx", NULL); - if (img.JGL.Image == NULL) return false; - Sprite_slice_pcx(&this->Victory_Image, __, &img, 0, 0, 0x80, 0x40, 1, 1); - - // Resources - read_in_dir(&img, art_dir, "resources.pcx", NULL); - if (img.JGL.Image == NULL) return false; - size_t k = 0; - for (int r = 0, y = 1; r < 6; ++r, y += 50) { - for (int c = 0, x = 1; c < 6; ++c, x += 50) { - Sprite_slice_pcx(&this->Resources[k++], __, &img, x, y, 49, 49, 1, 1); - } - } - - // Base cities - static const char *CITY_BASE[5] = { - "rAMER.pcx", "rEURO.pcx", "rROMAN.pcx", "rMIDEAST.pcx", "rASIAN.pcx" - }; - for (int culture = 0; culture < 5; culture++) { - read_in_dir(&img, art_dir, CITY_BASE[culture], NULL); - if (img.JGL.Image == NULL) return false; - int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; - int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; - int y = 0; - for (int era = 0; era < 4; ++era, y += sprite_h) { - int x = 0; - for (int size = 0; size < 3; ++size, x += sprite_w) { - const int idx = culture + 5*era + 20*size; - Sprite_slice_pcx(&this->City_Images[idx], __, &img, x, y, sprite_w, sprite_h, 1, 1); - } - } - } - - // Walled cities - static const char *CITY_WALL[5] = { - "AMERWALL.pcx", "EUROWALL.pcx", "ROMANWALL.pcx", "MIDEASTWALL.pcx", "ASIANWALL.pcx" - }; - for (int culture = 0; culture < 5; ++culture) { - read_in_dir(&img, art_dir, CITY_WALL[culture], NULL); - if (img.JGL.Image == NULL) return false; - int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image); - int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; - int y = 0; - for (int era = 0; era < 4; ++era, y += sprite_h) { - const int size = 3; // walled towns are a special category - const int idx = culture + 5*era + 20*size; - Sprite_slice_pcx(&this->City_Images[idx], __, &img, 0, y, sprite_w, sprite_h, 1, 1); - } - } - - // Destroyed cities - read_in_dir(&img, art_dir, "DESTROY.pcx", NULL); - if (img.JGL.Image == NULL) return false; - { - int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; - int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image); - int x = 0; - for (int i = 0; i < 3; ++i, x += sprite_w) - Sprite_slice_pcx(&this->Destroyed_City_Images[i], __, &img, x, 0, sprite_w, sprite_h, 1, 1); - } - - // Districts (if enabled) - if (is->current_config.enable_districts) { - char art_dir[200]; - char temp_path[2*MAX_PATH]; - snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - for (int dc = 0; dc < is->district_count; dc++) { - struct district_config const * cfg = &is->district_configs[dc]; - int variant_capacity = ARRAY_LEN (this->District_Images[dc]); - int variant_count = cfg->img_path_count; - if (variant_count <= 0) - continue; - if (variant_count > variant_capacity) - variant_count = variant_capacity; - - int era_count = cfg->vary_img_by_era ? 4 : 1; - int column_count = cfg->img_column_count; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - - for (int variant_i = 0; variant_i < variant_count; variant_i++) { - const char * img_path = cfg->img_paths[variant_i]; - if ((img_path == NULL) || (img_path[0] == '\0')) - continue; - - read_in_dir (&img, temp_path, img_path, NULL); - if (img.JGL.Image == NULL) - return false; - - for (int era = 0; era < era_count; era++) { - for (int col = 0; col < column_count; col++) { - int tile_x = sprite_width * col; - int tile_y = sprite_height * era; - Sprite_slice_pcx (&this->District_Images[dc][variant_i][era][col], __, &img, tile_x, tile_y, sprite_width, sprite_height, 1, 1); - } - } - } - } - - // Abandoned district art (land + maritime) for this hour - read_in_dir (&img, temp_path, "Abandoned.pcx", NULL); - if (img.JGL.Image == NULL) - return false; - Sprite_slice_pcx (&this->Abandoned_District_Image, __, &img, 0, 0, 128, 64, 1, 1); - Sprite_slice_pcx (&this->Abandoned_Maritime_District_Image, __, &img, 128, 0, 128, 64, 1, 1); - - // Load wonder district images (dynamically per wonder) for this hour - if (is->current_config.enable_wonder_districts) { - char const * last_img_path = NULL; - PCX_Image wpcx; - PCX_Image_construct (&wpcx); - bool pcx_loaded = false; - - for (int wi = 0; wi < is->wonder_district_count; wi++) { - struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; - char const * img_path = cfg->img_path; - if (img_path == NULL) - img_path = "Wonders.pcx"; - - // Load new image file if different from previous - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - - read_in_dir (&wpcx, temp_path, img_path, NULL); - - if (wpcx.JGL.Image == NULL) { - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - struct wonder_district_image_set * set = &this->Wonder_District_Images[wi]; - - Sprite_construct (&set->img); - int x = 128 * cfg->img_column; - int y = 64 * cfg->img_row; - Sprite_slice_pcx (&set->img, __, &wpcx, x, y, 128, 64, 1, 1); - - Sprite_construct (&set->construct_img); - int cx = 128 * cfg->img_construct_column; - int cy = 64 * cfg->img_construct_row; - Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, 128, 64, 1, 1); - - if (cfg->enable_img_alt_dir) { - Sprite_construct (&set->alt_dir_img); - int ax = 128 * cfg->img_alt_dir_column; - int ay = 64 * cfg->img_alt_dir_row; - Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, 128, 64, 1, 1); - - Sprite_construct (&set->alt_dir_construct_img); - int acx = 128 * cfg->img_alt_dir_construct_column; - int acy = 64 * cfg->img_alt_dir_construct_row; - Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, 128, 64, 1, 1); - } - } - - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - wpcx.vtable->destruct (&wpcx, __, 0); - } - - } - - if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { - char art_dir[200]; - char temp_path[2*MAX_PATH]; - snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - - char const * last_img_path = NULL; - PCX_Image nwpcx; - PCX_Image_construct (&nwpcx); - bool pcx_loaded = false; - - for (int ni = 0; ni < is->natural_wonder_count; ni++) { - struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; - if ((cfg->img_path == NULL) || (cfg->img_path[0] == '\0')) - continue; - - char const * img_path = cfg->img_path; - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - - read_in_dir (&nwpcx, temp_path, img_path, NULL); - - if (nwpcx.JGL.Image == NULL) { - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - Sprite_construct (&this->Natural_Wonder_Images[ni].img); - int x = 128 * cfg->img_column; - int y = 88 * cfg->img_row; - Sprite_slice_pcx (&this->Natural_Wonder_Images[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); - } - - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - nwpcx.vtable->destruct (&nwpcx, __, 0); - } - - img.vtable->destruct (&img, __, 0); - - return true; -} - -Sprite * -get_sprite_proxy_for_current_hour(Sprite *s) { - int v; - int hour = is->current_day_night_cycle; // 0..23 - if (itable_look_up(&is->day_night_sprite_proxy_by_hour[hour], (int)s, &v)) - return (Sprite *)v; - return NULL; // not proxied, fall back to s -} - -void -insert_spritelist_proxies(SpriteList *ss, SpriteList *ps, int hour, int len1, int len2) { - for (int i = 0; i < len1; i++) { - for (int j = 0; j < len2; j++) { - Sprite *s = &ss[i].field_0[j]; - Sprite *p = &ps[i].field_0[j]; - if (s && p) { - itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); - } - } - } -} - -void -insert_sprite_proxies(Sprite *ss, Sprite *ps, int hour, int len) { - for (int i = 0; i < len; i++) { - Sprite *s = &ss[i]; - Sprite *p = &ps[i]; - if (s && p) { - itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); - } - } -} - -void -insert_sprite_proxy(Sprite *s, Sprite *p, int hour) { - if (s && p) { - itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); - } -} - -void -build_sprite_proxies_24(Map_Renderer *mr) { - for (int h = 0; h < 24; ++h) { - insert_sprite_proxies(city_sprites, is->day_night_cycle_imgs[h].City_Images, h, 80); - insert_sprite_proxies(destroyed_city_sprites, is->day_night_cycle_imgs[h].Destroyed_City_Images, h, 3); - insert_sprite_proxies(mr->Resources, is->day_night_cycle_imgs[h].Resources, h, 36); - insert_spritelist_proxies(mr->Std_Terrain_Images, is->day_night_cycle_imgs[h].Std_Terrain_Images, h, 9, 81); - insert_spritelist_proxies(mr->LM_Terrain_Images, is->day_night_cycle_imgs[h].LM_Terrain_Images, h, 9, 81); - insert_sprite_proxy(&mr->Terrain_Buldings_Barbarian_Camp, &is->day_night_cycle_imgs[h].Terrain_Buldings_Barbarian_Camp, h); - insert_sprite_proxy(&mr->Terrain_Buldings_Mines, &is->day_night_cycle_imgs[h].Terrain_Buldings_Mines, h); - insert_sprite_proxy(&mr->Victory_Image, &is->day_night_cycle_imgs[h].Victory_Image, h); - insert_sprite_proxy(&mr->Terrain_Buldings_Radar, &is->day_night_cycle_imgs[h].Terrain_Buldings_Radar, h); - insert_sprite_proxies(mr->Flood_Plains_Images, is->day_night_cycle_imgs[h].Flood_Plains_Images, h, 16); - insert_sprite_proxies(mr->Polar_Icecaps_Images, is->day_night_cycle_imgs[h].Polar_Icecaps_Images, h, 32); - insert_sprite_proxies(mr->Roads_Images, is->day_night_cycle_imgs[h].Roads_Images, h, 256); - insert_sprite_proxies(mr->Railroads_Images, is->day_night_cycle_imgs[h].Railroads_Images, h, 272); - insert_sprite_proxies(mr->Terrain_Buldings_Airfields, is->day_night_cycle_imgs[h].Terrain_Buldings_Airfields, h, 2); - insert_sprite_proxies(mr->Terrain_Buldings_Camp, is->day_night_cycle_imgs[h].Terrain_Buldings_Camp, h, 4); - insert_sprite_proxies(mr->Terrain_Buldings_Fortress, is->day_night_cycle_imgs[h].Terrain_Buldings_Fortress, h, 4); - insert_sprite_proxies(mr->Terrain_Buldings_Barricade, is->day_night_cycle_imgs[h].Terrain_Buldings_Barricade, h, 4); - insert_sprite_proxies(mr->Goody_Huts_Images, is->day_night_cycle_imgs[h].Goody_Huts_Images, h, 8); - insert_sprite_proxies(mr->Terrain_Buldings_Outposts, is->day_night_cycle_imgs[h].Terrain_Buldings_Outposts, h, 3); - insert_sprite_proxies(mr->Pollution, is->day_night_cycle_imgs[h].Pollution, h, 25); - insert_sprite_proxies(mr->Craters, is->day_night_cycle_imgs[h].Craters, h, 25); - insert_sprite_proxies(mr->Tnt_Images, is->day_night_cycle_imgs[h].Tnt_Images, h, 18); - insert_sprite_proxies(mr->Waterfalls_Images, is->day_night_cycle_imgs[h].Waterfalls_Images, h, 4); - insert_sprite_proxies(mr->LM_Terrain, is->day_night_cycle_imgs[h].LM_Terrain, h, 7); - insert_sprite_proxies(mr->Marsh_Large, is->day_night_cycle_imgs[h].Marsh_Large, h, 8); - insert_sprite_proxies(mr->Marsh_Small, is->day_night_cycle_imgs[h].Marsh_Small, h, 10); - insert_sprite_proxies(mr->Volcanos_Images, is->day_night_cycle_imgs[h].Volcanos_Images, h, 16); - insert_sprite_proxies(mr->Volcanos_Forests_Images, is->day_night_cycle_imgs[h].Volcanos_Forests_Images, h, 16); - insert_sprite_proxies(mr->Volcanos_Jungles_Images, is->day_night_cycle_imgs[h].Volcanos_Jungles_Images, h, 16); - insert_sprite_proxies(mr->Volcanos_Snow_Images, is->day_night_cycle_imgs[h].Volcanos_Snow_Images, h, 16); - insert_sprite_proxies(mr->Grassland_Forests_Large, is->day_night_cycle_imgs[h].Grassland_Forests_Large, h, 8); - insert_sprite_proxies(mr->Plains_Forests_Large, is->day_night_cycle_imgs[h].Plains_Forests_Large, h, 8); - insert_sprite_proxies(mr->Tundra_Forests_Large, is->day_night_cycle_imgs[h].Tundra_Forests_Large, h, 8); - insert_sprite_proxies(mr->Grassland_Forests_Small, is->day_night_cycle_imgs[h].Grassland_Forests_Small, h, 10); - insert_sprite_proxies(mr->Plains_Forests_Small, is->day_night_cycle_imgs[h].Plains_Forests_Small, h, 10); - insert_sprite_proxies(mr->Tundra_Forests_Small, is->day_night_cycle_imgs[h].Tundra_Forests_Small, h, 10); - insert_sprite_proxies(mr->Grassland_Forests_Pines, is->day_night_cycle_imgs[h].Grassland_Forests_Pines, h, 12); - insert_sprite_proxies(mr->Plains_Forests_Pines, is->day_night_cycle_imgs[h].Plains_Forests_Pines, h, 12); - insert_sprite_proxies(mr->Tundra_Forests_Pines, is->day_night_cycle_imgs[h].Tundra_Forests_Pines, h, 12); - insert_sprite_proxies(mr->Irrigation_Desert_Images, is->day_night_cycle_imgs[h].Irrigation_Desert_Images, h, 16); - insert_sprite_proxies(mr->Irrigation_Plains_Images, is->day_night_cycle_imgs[h].Irrigation_Plains_Images, h, 16); - insert_sprite_proxies(mr->Irrigation_Images, is->day_night_cycle_imgs[h].Irrigation_Images, h, 16); - insert_sprite_proxies(mr->Irrigation_Tundra_Images, is->day_night_cycle_imgs[h].Irrigation_Tundra_Images, h, 16); - insert_sprite_proxies(mr->Grassland_Jungles_Large, is->day_night_cycle_imgs[h].Grassland_Jungles_Large, h, 8); - insert_sprite_proxies(mr->Grassland_Jungles_Small, is->day_night_cycle_imgs[h].Grassland_Jungles_Small, h, 12); - insert_sprite_proxies(mr->Mountains_Images, is->day_night_cycle_imgs[h].Mountains_Images, h, 16); - insert_sprite_proxies(mr->Mountains_Forests_Images, is->day_night_cycle_imgs[h].Mountains_Forests_Images, h, 16); - insert_sprite_proxies(mr->Mountains_Jungles_Images, is->day_night_cycle_imgs[h].Mountains_Jungles_Images, h, 16); - insert_sprite_proxies(mr->Mountains_Snow_Images, is->day_night_cycle_imgs[h].Mountains_Snow_Images, h, 16); - insert_sprite_proxies(mr->Hills_Images, is->day_night_cycle_imgs[h].Hills_Images, h, 16); - insert_sprite_proxies(mr->Hills_Forests_Images, is->day_night_cycle_imgs[h].Hills_Forests_Images, h, 16); - insert_sprite_proxies(mr->Hills_Jungle_Images, is->day_night_cycle_imgs[h].Hills_Jungle_Images, h, 16); - insert_sprite_proxies(mr->Delta_Rivers_Images, is->day_night_cycle_imgs[h].Delta_Rivers_Images, h, 16); - insert_sprite_proxies(mr->Mountain_Rivers_Images, is->day_night_cycle_imgs[h].Mountain_Rivers_Images, h, 16); - insert_sprite_proxies(mr->LM_Mountains_Images, is->day_night_cycle_imgs[h].LM_Mountains_Images, h, 16); - insert_sprite_proxies(mr->LM_Forests_Large_Images, is->day_night_cycle_imgs[h].LM_Forests_Large_Images, h, 8); - insert_sprite_proxies(mr->LM_Forests_Small_Images, is->day_night_cycle_imgs[h].LM_Forests_Small_Images, h, 10); - insert_sprite_proxies(mr->LM_Forests_Pines_Images, is->day_night_cycle_imgs[h].LM_Forests_Pines_Images, h, 12); - insert_sprite_proxies(mr->LM_Hills_Images, is->day_night_cycle_imgs[h].LM_Hills_Images, h, 16); - - if (is->current_config.enable_districts) { - for (int dc = 0; dc < is->district_count; dc++) { - struct district_config const * cfg = &is->district_configs[dc]; - int variant_capacity = ARRAY_LEN (is->district_img_sets[dc].imgs); - int variant_count = cfg->img_path_count; - if (variant_count <= 0) - continue; - if (variant_count > variant_capacity) - variant_count = variant_capacity; - - int era_count = cfg->vary_img_by_era ? 4 : 1; - int column_count = cfg->img_column_count; - - for (int variant_i = 0; variant_i < variant_count; variant_i++) { - if ((cfg->img_paths[variant_i] == NULL) || (cfg->img_paths[variant_i][0] == '\0')) - continue; - for (int era = 0; era < era_count; era++) { - for (int col = 0; col < column_count; col++) { - Sprite * base = &is->district_img_sets[dc].imgs[variant_i][era][col]; - Sprite * proxy = &is->day_night_cycle_imgs[h].District_Images[dc][variant_i][era][col]; - insert_sprite_proxy (base, proxy, h); - } - } - } - } - - insert_sprite_proxy (&is->abandoned_district_img, &is->day_night_cycle_imgs[h].Abandoned_District_Image, h); - insert_sprite_proxy (&is->abandoned_maritime_district_img, &is->day_night_cycle_imgs[h].Abandoned_Maritime_District_Image, h); - - // Wonder districts - if (is->current_config.enable_wonder_districts) { - for (int wi = 0; wi < is->wonder_district_count; wi++) { - Sprite * base_img = &is->wonder_district_img_sets[wi].img; - Sprite * proxy_img = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].img; - insert_sprite_proxy (base_img, proxy_img, h); - - Sprite * base_construct = &is->wonder_district_img_sets[wi].construct_img; - Sprite * proxy_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].construct_img; - insert_sprite_proxy (base_construct, proxy_construct, h); - - if (is->wonder_district_img_sets[wi].alt_dir_img.vtable != NULL) { - Sprite * base_alt = &is->wonder_district_img_sets[wi].alt_dir_img; - Sprite * proxy_alt = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_img; - insert_sprite_proxy (base_alt, proxy_alt, h); - } - - if (is->wonder_district_img_sets[wi].alt_dir_construct_img.vtable != NULL) { - Sprite * base_alt_construct = &is->wonder_district_img_sets[wi].alt_dir_construct_img; - Sprite * proxy_alt_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_construct_img; - insert_sprite_proxy (base_alt_construct, proxy_alt_construct, h); - } - } - } - } - - // Natural wonders - if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { - for (int ni = 0; ni < is->natural_wonder_count; ni++) { - Sprite * base_nw = &is->natural_wonder_img_sets[ni].img; - Sprite * proxy_nw = &is->day_night_cycle_imgs[h].Natural_Wonder_Images[ni].img; - insert_sprite_proxy (base_nw, proxy_nw, h); - } - } - } - is->day_night_cycle_img_proxies_indexed = true; -} - -void -init_day_night_images() -{ - if (is->day_night_cycle_img_state != IS_UNINITED) - return; - - const char *hour_strs[24] = { - "2400", "0100", "0200", "0300", "0400", "0500", "0600", "0700", - "0800", "0900", "1000", "1100", "1200", "1300", "1400", "1500", - "1600", "1700", "1800", "1900", "2000", "2100", "2200", "2300" - }; - - for (int i = 0; i < 24; i++) { - - char art_dir[200]; - char temp_path[2*MAX_PATH]; - snprintf (art_dir, sizeof art_dir, "DayNight/%s", hour_strs[i]); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - bool success = load_day_night_hour_images (&is->day_night_cycle_imgs[i], temp_path, hour_strs[i]); - - if (!success) { - char ss[200]; - snprintf(ss, sizeof ss, "Failed to load day/night cycle images for hour %s, reverting to base game art.", hour_strs[i]); - pop_up_in_game_error (ss); - - is->day_night_cycle_img_state = IS_INIT_FAILED; - return; - } - } - - Map_Renderer * mr = &p_bic_data->Map.Renderer; - build_sprite_proxies_24(mr); - - is->day_night_cycle_img_state = IS_OK; -} - -void -deindex_day_night_image_proxies() -{ - if (!is->day_night_cycle_img_proxies_indexed) - return; - - for (int i = 0; i < 24; i++) { - table_deinit (&is->day_night_sprite_proxy_by_hour[i]); - } - is->day_night_cycle_img_proxies_indexed = false; -} - -int -calculate_current_day_night_cycle_hour () -{ - int output = 12; // Default to noon - int increment = is->current_config.fixed_hours_per_turn_for_day_night_cycle; - - switch (is->current_config.day_night_cycle_mode) { - - // Disabled. This shouldn't be possible, but default to noon to be safe - case DNCM_OFF: - return output; - - // Time elapsed since last update - case DNCM_TIMER: { - LARGE_INTEGER perf_freq; - QueryPerformanceFrequency(&perf_freq); - - if (is->day_night_cycle_unstarted) { - is->current_day_night_cycle = output; - QueryPerformanceCounter(&is->last_day_night_cycle_update_time); - } - - LARGE_INTEGER time_now; - QueryPerformanceCounter(&time_now); - - double elapsed_seconds = - (double)(time_now.QuadPart - is->last_day_night_cycle_update_time.QuadPart) / - (double)perf_freq.QuadPart; - - if (elapsed_seconds > (double)is->current_config.elapsed_minutes_per_day_night_hour_transition * 60.0) { - output = is->current_day_night_cycle + increment; - is->last_day_night_cycle_update_time = time_now; - } else { - output = is->current_day_night_cycle; - } - break; - } - - // Match user's current time - case DNCM_USER_TIME: { - LPSYSTEMTIME lpSystemTime = (LPSYSTEMTIME)malloc(sizeof(SYSTEMTIME)); - GetLocalTime (lpSystemTime); - output = lpSystemTime->wHour; - free (lpSystemTime); - break; - } - - // Increment fixed amount each interturn - case DNCM_EVERY_TURN: { - if (is->day_night_cycle_unstarted) { - increment = 0; - is->current_day_night_cycle = output; - } - output = is->current_day_night_cycle + increment; - break; - } - - // Pin the hour to a specific value - case DNCM_SPECIFIED: { - output = is->current_config.pinned_hour_for_day_night_cycle; - break; - } - } - - // If midnight or over, restart at 0 or later - if (output > 23) output = output - 24; - - // Clamp to valid range of 0-23 in case of weird config values - output = clamp (0, 23, output); - is->day_night_cycle_unstarted = false; - - return output; -} - -void __fastcall -patch_Map_Renderer_load_images (Map_Renderer *this, int edx) -{ - Map_Renderer_load_images(this, __); - - // Initialize day/night cycle and re-calculate hour, if applicable - if (is->current_config.day_night_cycle_mode != DNCM_OFF) { - is->current_day_night_cycle = calculate_current_day_night_cycle_hour (); - - if (is->day_night_cycle_img_state == IS_UNINITED) { - init_day_night_images (); - } - - if (is->day_night_cycle_img_state == IS_OK) { - - // Sprite proxies are deindexed during each load event as sprite instances (really only Resources, which are reloaded) may change. - if (!is->day_night_cycle_img_proxies_indexed) { - build_sprite_proxies_24(this); - } - } - } -} - -void -patch_init_floating_point () -{ - init_floating_point (); - - // NOTE: At this point the program is done with the CRT initialization stuff and will start calling constructors for global - // objects as soon as this function returns. This is a good place to inject code that will run at program start. - - // Specify metadata about all boolean options on the mod config. We'll use this info to set up the table of offsets (for easy parsing) and to - // fill out the base config. - struct boolean_config_option { - char * name; - bool base_val; - int offset; - } boolean_config_options[] = { - {"enable_stack_bombard" , true , offsetof (struct c3x_config, enable_stack_bombard)}, - {"enable_disorder_warning" , true , offsetof (struct c3x_config, enable_disorder_warning)}, - {"allow_stealth_attack_against_single_unit" , false, offsetof (struct c3x_config, allow_stealth_attack_against_single_unit)}, - {"show_detailed_city_production_info" , true , offsetof (struct c3x_config, show_detailed_city_production_info)}, - {"limited_railroads_work_like_fast_roads" , false, offsetof (struct c3x_config, limited_railroads_work_like_fast_roads)}, - {"exclude_cities_from_units_per_tile_limit" , false, offsetof (struct c3x_config, exclude_cities_from_units_per_tile_limit)}, - {"enable_free_buildings_from_small_wonders" , true , offsetof (struct c3x_config, enable_free_buildings_from_small_wonders)}, - {"enable_stack_unit_commands" , true , offsetof (struct c3x_config, enable_stack_unit_commands)}, - {"skip_repeated_tile_improv_replacement_asks" , true , offsetof (struct c3x_config, skip_repeated_tile_improv_replacement_asks)}, - {"autofill_best_gold_amount_when_trading" , true , offsetof (struct c3x_config, autofill_best_gold_amount_when_trading)}, - {"disallow_founding_next_to_foreign_city" , true , offsetof (struct c3x_config, disallow_founding_next_to_foreign_city)}, - {"enable_trade_screen_scroll" , true , offsetof (struct c3x_config, enable_trade_screen_scroll)}, - {"group_units_on_right_click_menu" , true , offsetof (struct c3x_config, group_units_on_right_click_menu)}, - {"gray_out_units_on_menu_with_no_remaining_moves" , true , offsetof (struct c3x_config, gray_out_units_on_menu_with_no_remaining_moves)}, - {"put_movement_icons_on_units_on_menu" , true , offsetof (struct c3x_config, put_movement_icons_on_units_on_menu)}, - {"describe_states_of_units_on_menu" , true , offsetof (struct c3x_config, describe_states_of_units_on_menu)}, - {"show_golden_age_turns_remaining" , true , offsetof (struct c3x_config, show_golden_age_turns_remaining)}, - {"show_zoc_attacks_from_mid_stack" , true , offsetof (struct c3x_config, show_zoc_attacks_from_mid_stack)}, - {"show_armies_performing_defensive_bombard" , true , offsetof (struct c3x_config, show_armies_performing_defensive_bombard)}, - {"cut_research_spending_to_avoid_bankruptcy" , true , offsetof (struct c3x_config, cut_research_spending_to_avoid_bankruptcy)}, - {"dont_pause_for_love_the_king_messages" , true , offsetof (struct c3x_config, dont_pause_for_love_the_king_messages)}, - {"reverse_specialist_order_with_shift" , true , offsetof (struct c3x_config, reverse_specialist_order_with_shift)}, - {"toggle_zoom_with_z_on_city_screen" , true , offsetof (struct c3x_config, toggle_zoom_with_z_on_city_screen)}, - {"dont_give_king_names_in_non_regicide_games" , true , offsetof (struct c3x_config, dont_give_king_names_in_non_regicide_games)}, - {"no_elvis_easter_egg" , false, offsetof (struct c3x_config, no_elvis_easter_egg)}, - {"disable_worker_automation" , false, offsetof (struct c3x_config, disable_worker_automation)}, - {"enable_land_sea_intersections" , false, offsetof (struct c3x_config, enable_land_sea_intersections)}, - {"disallow_trespassing" , false, offsetof (struct c3x_config, disallow_trespassing)}, - {"show_detailed_tile_info" , true , offsetof (struct c3x_config, show_detailed_tile_info)}, - {"warn_about_unrecognized_names" , true , offsetof (struct c3x_config, warn_about_unrecognized_names)}, - {"enable_ai_production_ranking" , true , offsetof (struct c3x_config, enable_ai_production_ranking)}, - {"enable_ai_city_location_desirability_display" , true, offsetof (struct c3x_config, enable_ai_city_location_desirability_display)}, - {"show_ai_city_location_desirability_if_settler" , false, offsetof (struct c3x_config, show_ai_city_location_desirability_if_settler)}, - {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, - {"zero_corruption_when_off" , true , offsetof (struct c3x_config, zero_corruption_when_off)}, - {"disallow_land_units_from_affecting_water_tiles" , true , offsetof (struct c3x_config, disallow_land_units_from_affecting_water_tiles)}, - {"dont_end_units_turn_after_airdrop" , false, offsetof (struct c3x_config, dont_end_units_turn_after_airdrop)}, - {"allow_airdrop_without_airport" , false, offsetof (struct c3x_config, allow_airdrop_without_airport)}, - {"enable_negative_pop_pollution" , true , offsetof (struct c3x_config, enable_negative_pop_pollution)}, - {"allow_defensive_retreat_on_water" , false, offsetof (struct c3x_config, allow_defensive_retreat_on_water)}, - {"promote_wonder_decorruption_effect" , false, offsetof (struct c3x_config, promote_wonder_decorruption_effect)}, - {"allow_military_leaders_to_hurry_wonders" , false, offsetof (struct c3x_config, allow_military_leaders_to_hurry_wonders)}, - {"allow_multiple_battle_created_units_per_player" , false, offsetof (struct c3x_config, allow_multiple_battle_created_units_per_player)}, - {"aggressively_penalize_bankruptcy" , false, offsetof (struct c3x_config, aggressively_penalize_bankruptcy)}, - {"no_penalty_exception_for_agri_fresh_water_city_tiles" , false, offsetof (struct c3x_config, no_penalty_exception_for_agri_fresh_water_city_tiles)}, - {"use_offensive_artillery_ai" , true , offsetof (struct c3x_config, use_offensive_artillery_ai)}, - {"dont_escort_unflagged_units" , false, offsetof (struct c3x_config, dont_escort_unflagged_units)}, - {"replace_leader_unit_ai" , true , offsetof (struct c3x_config, replace_leader_unit_ai)}, - {"fix_ai_army_composition" , true , offsetof (struct c3x_config, fix_ai_army_composition)}, - {"enable_pop_unit_ai" , true , offsetof (struct c3x_config, enable_pop_unit_ai)}, - {"enable_caravan_unit_ai" , true , offsetof (struct c3x_config, enable_caravan_unit_ai)}, - {"remove_unit_limit" , true , offsetof (struct c3x_config, remove_unit_limit)}, - {"remove_city_improvement_limit" , true , offsetof (struct c3x_config, remove_city_improvement_limit)}, - {"remove_cap_on_turn_limit" , true , offsetof (struct c3x_config, remove_cap_on_turn_limit)}, - {"remove_era_limit" , false, offsetof (struct c3x_config, remove_era_limit)}, - {"patch_submarine_bug" , true , offsetof (struct c3x_config, patch_submarine_bug)}, - {"patch_science_age_bug" , true , offsetof (struct c3x_config, patch_science_age_bug)}, - {"patch_pedia_texture_bug" , true , offsetof (struct c3x_config, patch_pedia_texture_bug)}, - {"patch_blocked_disembark_freeze" , true , offsetof (struct c3x_config, patch_blocked_disembark_freeze)}, - {"patch_houseboat_bug" , true , offsetof (struct c3x_config, patch_houseboat_bug)}, - {"patch_intercept_lost_turn_bug" , true , offsetof (struct c3x_config, patch_intercept_lost_turn_bug)}, - {"patch_phantom_resource_bug" , true , offsetof (struct c3x_config, patch_phantom_resource_bug)}, - {"patch_maintenance_persisting_for_obsolete_buildings" , true , offsetof (struct c3x_config, patch_maintenance_persisting_for_obsolete_buildings)}, - {"patch_barbarian_diagonal_bug" , true , offsetof (struct c3x_config, patch_barbarian_diagonal_bug)}, - {"patch_disease_stopping_tech_flag_bug" , false, offsetof (struct c3x_config, patch_disease_stopping_tech_flag_bug)}, - {"patch_division_by_zero_in_ai_alliance_eval" , true , offsetof (struct c3x_config, patch_division_by_zero_in_ai_alliance_eval)}, - {"patch_empty_army_movement" , true , offsetof (struct c3x_config, patch_empty_army_movement)}, - {"patch_empty_army_combat_crash" , true , offsetof (struct c3x_config, patch_empty_army_combat_crash)}, - {"patch_premature_truncation_of_found_paths" , true , offsetof (struct c3x_config, patch_premature_truncation_of_found_paths)}, - {"patch_zero_production_crash" , true , offsetof (struct c3x_config, patch_zero_production_crash)}, - {"patch_ai_can_form_army_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_form_army_without_special_ability)}, - {"patch_ai_can_sacrifice_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_sacrifice_without_special_ability)}, - {"patch_crash_in_leader_unit_ai" , true , offsetof (struct c3x_config, patch_crash_in_leader_unit_ai)}, - {"patch_failure_to_find_new_city_build" , true , offsetof (struct c3x_config, patch_failure_to_find_new_city_build)}, - {"patch_passengers_out_of_order_on_menu" , true , offsetof (struct c3x_config, patch_passengers_out_of_order_on_menu)}, - {"delete_off_map_ai_units" , true , offsetof (struct c3x_config, delete_off_map_ai_units)}, - {"fix_overlapping_specialist_yield_icons" , true , offsetof (struct c3x_config, fix_overlapping_specialist_yield_icons)}, - {"prevent_autorazing" , false, offsetof (struct c3x_config, prevent_autorazing)}, - {"prevent_razing_by_players" , false, offsetof (struct c3x_config, prevent_razing_by_players)}, - {"suppress_hypertext_links_exceeded_popup" , true , offsetof (struct c3x_config, suppress_hypertext_links_exceeded_popup)}, - {"indicate_non_upgradability_in_pedia" , true , offsetof (struct c3x_config, indicate_non_upgradability_in_pedia)}, - {"show_message_after_dodging_sam" , true , offsetof (struct c3x_config, show_message_after_dodging_sam)}, - {"include_stealth_attack_cancel_option" , false, offsetof (struct c3x_config, include_stealth_attack_cancel_option)}, - {"intercept_recon_missions" , false, offsetof (struct c3x_config, intercept_recon_missions)}, - {"charge_one_move_for_recon_and_interception" , false, offsetof (struct c3x_config, charge_one_move_for_recon_and_interception)}, - {"polish_precision_striking" , true , offsetof (struct c3x_config, polish_precision_striking)}, - {"enable_stealth_attack_via_bombardment" , false, offsetof (struct c3x_config, enable_stealth_attack_via_bombardment)}, - {"immunize_aircraft_against_bombardment" , false, offsetof (struct c3x_config, immunize_aircraft_against_bombardment)}, - {"replay_ai_moves_in_hotseat_games" , false, offsetof (struct c3x_config, replay_ai_moves_in_hotseat_games)}, - {"restore_unit_directions_on_game_load" , true , offsetof (struct c3x_config, restore_unit_directions_on_game_load)}, - {"apply_grid_ini_setting_on_game_load" , true , offsetof (struct c3x_config, apply_grid_ini_setting_on_game_load)}, - {"charm_flag_triggers_ptw_like_targeting" , false, offsetof (struct c3x_config, charm_flag_triggers_ptw_like_targeting)}, - {"city_icons_show_unit_effects_not_trade" , true , offsetof (struct c3x_config, city_icons_show_unit_effects_not_trade)}, - {"ignore_king_ability_for_defense_priority" , false, offsetof (struct c3x_config, ignore_king_ability_for_defense_priority)}, - {"show_untradable_techs_on_trade_screen" , false, offsetof (struct c3x_config, show_untradable_techs_on_trade_screen)}, - {"disallow_useless_bombard_vs_airfields" , true , offsetof (struct c3x_config, disallow_useless_bombard_vs_airfields)}, - {"compact_luxury_display_on_city_screen" , false, offsetof (struct c3x_config, compact_luxury_display_on_city_screen)}, - {"compact_strategic_resource_display_on_city_screen" , false, offsetof (struct c3x_config, compact_strategic_resource_display_on_city_screen)}, - {"warn_when_chosen_building_would_replace_another" , false, offsetof (struct c3x_config, warn_when_chosen_building_would_replace_another)}, - {"do_not_unassign_workers_from_polluted_tiles" , false, offsetof (struct c3x_config, do_not_unassign_workers_from_polluted_tiles)}, - {"do_not_make_capital_cities_appear_larger" , false, offsetof (struct c3x_config, do_not_make_capital_cities_appear_larger)}, - {"show_territory_colors_on_water_tiles_in_minimap" , false, offsetof (struct c3x_config, show_territory_colors_on_water_tiles_in_minimap)}, - {"convert_some_popups_into_online_mp_messages" , false, offsetof (struct c3x_config, convert_some_popups_into_online_mp_messages)}, - {"enable_debug_mode_switch" , false, offsetof (struct c3x_config, enable_debug_mode_switch)}, - {"accentuate_cities_on_minimap" , false, offsetof (struct c3x_config, accentuate_cities_on_minimap)}, - {"allow_multipage_civilopedia_descriptions" , true , offsetof (struct c3x_config, allow_multipage_civilopedia_descriptions)}, - {"reformat_turns_remaining_on_domestic_advisor_screen" , true , offsetof (struct c3x_config, reformat_turns_remaining_on_domestic_advisor_screen)}, - {"expand_civilopedia_unit_stats" , true , offsetof (struct c3x_config, expand_civilopedia_unit_stats)}, - {"enable_trade_net_x" , true , offsetof (struct c3x_config, enable_trade_net_x)}, - {"optimize_improvement_loops" , true , offsetof (struct c3x_config, optimize_improvement_loops)}, - {"measure_turn_times" , false, offsetof (struct c3x_config, measure_turn_times)}, - {"enable_city_capture_by_barbarians" , false, offsetof (struct c3x_config, enable_city_capture_by_barbarians)}, - {"share_visibility_in_hotseat" , false, offsetof (struct c3x_config, share_visibility_in_hotseat)}, - {"share_wonders_in_hotseat" , false, offsetof (struct c3x_config, share_wonders_in_hotseat)}, - {"allow_precision_strikes_against_tile_improvements" , false, offsetof (struct c3x_config, allow_precision_strikes_against_tile_improvements)}, - {"dont_end_units_turn_after_bombarding_barricade" , false, offsetof (struct c3x_config, dont_end_units_turn_after_bombarding_barricade)}, - {"remove_land_artillery_target_restrictions" , false, offsetof (struct c3x_config, remove_land_artillery_target_restrictions)}, - {"allow_bombard_of_other_improvs_on_occupied_airfield" , false, offsetof (struct c3x_config, allow_bombard_of_other_improvs_on_occupied_airfield)}, - {"show_total_city_count" , false, offsetof (struct c3x_config, show_total_city_count)}, - {"strengthen_forbidden_palace_ocn_effect" , false, offsetof (struct c3x_config, strengthen_forbidden_palace_ocn_effect)}, - {"allow_upgrades_in_any_city" , false, offsetof (struct c3x_config, allow_upgrades_in_any_city)}, - {"do_not_generate_volcanos" , false, offsetof (struct c3x_config, do_not_generate_volcanos)}, - {"do_not_pollute_impassable_tiles" , false, offsetof (struct c3x_config, do_not_pollute_impassable_tiles)}, - {"show_hp_of_stealth_attack_options" , false, offsetof (struct c3x_config, show_hp_of_stealth_attack_options)}, - {"exclude_invisible_units_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_invisible_units_from_stealth_attack)}, - {"exclude_passengers_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_passengers_from_stealth_attack)}, - {"convert_to_landmark_after_planting_forest" , false, offsetof (struct c3x_config, convert_to_landmark_after_planting_forest)}, - {"allow_sale_of_aqueducts_and_hospitals" , false, offsetof (struct c3x_config, allow_sale_of_aqueducts_and_hospitals)}, - {"no_cross_shore_detection" , false, offsetof (struct c3x_config, no_cross_shore_detection)}, - {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, - {"limit_unit_loading_to_one_transport_per_turn" , false, offsetof (struct c3x_config, limit_unit_loading_to_one_transport_per_turn)}, - {"prevent_old_units_from_upgrading_past_ability_block" , false, offsetof (struct c3x_config, prevent_old_units_from_upgrading_past_ability_block)}, - {"allow_extraterritorial_colonies" , false, offsetof (struct c3x_config, allow_extraterritorial_colonies)}, - {"draw_forests_over_roads_and_railroads" , false, offsetof (struct c3x_config, draw_forests_over_roads_and_railroads)}, - {"enable_districts" , false, offsetof (struct c3x_config, enable_districts)}, - {"enable_neighborhood_districts" , false, offsetof (struct c3x_config, enable_neighborhood_districts)}, - {"enable_wonder_districts" , false, offsetof (struct c3x_config, enable_wonder_districts)}, - {"enable_natural_wonders" , false, offsetof (struct c3x_config, enable_natural_wonders)}, - {"add_natural_wonders_to_scenarios_if_none" , false, offsetof (struct c3x_config, add_natural_wonders_to_scenarios_if_none)}, - {"enable_named_tiles" , false, offsetof (struct c3x_config, enable_named_tiles)}, - {"enable_distribution_hub_districts" , false, offsetof (struct c3x_config, enable_distribution_hub_districts)}, - {"enable_aerodrome_districts" , false, offsetof (struct c3x_config, enable_aerodrome_districts)}, - {"enable_port_districts" , false, offsetof (struct c3x_config, enable_port_districts)}, - {"enable_bridge_districts" , false, offsetof (struct c3x_config, enable_bridge_districts)}, - {"enable_canal_districts" , false, offsetof (struct c3x_config, enable_canal_districts)}, - {"enable_central_rail_hub_districts" , false, offsetof (struct c3x_config, enable_central_rail_hub_districts)}, - {"enable_energy_grid_districts" , false, offsetof (struct c3x_config, enable_energy_grid_districts)}, - {"enable_great_wall_districts" , false, offsetof (struct c3x_config, enable_great_wall_districts)}, - {"completed_wonder_districts_can_be_destroyed" , false, offsetof (struct c3x_config, completed_wonder_districts_can_be_destroyed)}, - {"destroyed_wonders_can_be_built_again" , false, offsetof (struct c3x_config, destroyed_wonders_can_be_built_again)}, - {"cities_with_mutual_district_receive_buildings" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_buildings)}, - {"cities_with_mutual_district_receive_wonders" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_wonders)}, - {"show_message_when_building_received_by_mutual_district", false, offsetof (struct c3x_config, show_message_when_building_received_by_mutual_district)}, - {"show_message_when_building_lost_to_destroyed_district" , false, offsetof (struct c3x_config, show_message_when_building_lost_to_destroyed_district)}, - {"destroying_neighborhood_reduces_pop" , false, offsetof (struct c3x_config, destroying_neighborhood_reduces_pop)}, - {"air_units_use_aerodrome_districts_not_cities" , false, offsetof (struct c3x_config, air_units_use_aerodrome_districts_not_cities)}, - {"naval_units_use_port_districts_not_cities" , false, offsetof (struct c3x_config, naval_units_use_port_districts_not_cities)}, - {"show_natural_wonder_name_on_map" , false, offsetof (struct c3x_config, show_natural_wonder_name_on_map)}, - {"ai_defends_districts" , false, offsetof (struct c3x_config, ai_defends_districts)}, - {"great_wall_districts_impassible_by_others" , false, offsetof (struct c3x_config, great_wall_districts_impassible_by_others)}, - {"auto_build_great_wall_around_territory" , false, offsetof (struct c3x_config, auto_build_great_wall_around_territory)}, - {"disable_great_wall_city_defense_bonus" , false, offsetof (struct c3x_config, disable_great_wall_city_defense_bonus)}, - {"expand_water_tile_checks_to_city_work_area" , false, offsetof (struct c3x_config, expand_water_tile_checks_to_city_work_area)}, - {"ai_can_replace_existing_districts_with_canals" , false, offsetof (struct c3x_config, ai_can_replace_existing_districts_with_canals)}, - {"ai_builds_bridges" , false, offsetof (struct c3x_config, ai_builds_bridges)}, - {"ai_builds_canals" , false, offsetof (struct c3x_config, ai_builds_canals)}, - {"workers_can_enter_coast" , false, offsetof (struct c3x_config, workers_can_enter_coast)}, - {"enable_city_work_radii_highlights" , false, offsetof (struct c3x_config, enable_city_work_radii_highlights)}, - {"introduce_all_human_players_at_start_of_hotseat_game" , false, offsetof (struct c3x_config, introduce_all_human_players_at_start_of_hotseat_game)}, - {"allow_unload_from_army" , false, offsetof (struct c3x_config, allow_unload_from_army)}, - {"no_land_anti_air_from_inside_naval_transport" , false, offsetof (struct c3x_config, no_land_anti_air_from_inside_naval_transport)}, - {"prevent_enslaving_by_bombardment" , false, offsetof (struct c3x_config, prevent_enslaving_by_bombardment)}, - {"allow_adjacent_resources_of_different_types" , false, offsetof (struct c3x_config, allow_adjacent_resources_of_different_types)}, - {"allow_corruption_in_capital" , false, offsetof (struct c3x_config, allow_corruption_in_capital)}, - {"allow_sale_of_small_wonders" , false, offsetof (struct c3x_config, allow_sale_of_small_wonders)}, - {"initialize_preplaced_scenario_leaders_as_mgls" , false, offsetof (struct c3x_config, initialize_preplaced_scenario_leaders_as_mgls)}, - {"enable_unit_counters" , false, offsetof (struct c3x_config, enable_unit_counters)}, - {"use_civ4_style_best_defender" , false, offsetof (struct c3x_config, use_civ4_style_best_defender)}, - }; - - struct integer_config_option { - char * name; - int base_val; - int offset; - } integer_config_options[] = { - {"limit_railroad_movement" , 0, offsetof (struct c3x_config, limit_railroad_movement)}, - {"minimum_city_separation" , 1, offsetof (struct c3x_config, minimum_city_separation)}, - {"anarchy_length_percent" , 100, offsetof (struct c3x_config, anarchy_length_percent)}, - {"ai_multi_city_start" , 0, offsetof (struct c3x_config, ai_multi_city_start)}, - {"max_tries_to_place_fp_city" , 10000, offsetof (struct c3x_config, max_tries_to_place_fp_city)}, - {"ai_research_multiplier" , 100, offsetof (struct c3x_config, ai_research_multiplier)}, - {"ai_settler_perfume_on_founding_duration" , 0, offsetof (struct c3x_config, ai_settler_perfume_on_founding_duration)}, - {"extra_unit_maintenance_per_shields" , 0, offsetof (struct c3x_config, extra_unit_maintenance_per_shields)}, - {"ai_build_artillery_ratio" , 16, offsetof (struct c3x_config, ai_build_artillery_ratio)}, - {"ai_artillery_value_damage_percent" , 50, offsetof (struct c3x_config, ai_artillery_value_damage_percent)}, - {"ai_build_bomber_ratio" , 70, offsetof (struct c3x_config, ai_build_bomber_ratio)}, - {"max_ai_naval_escorts" , 3, offsetof (struct c3x_config, max_ai_naval_escorts)}, - {"ai_worker_requirement_percent" , 150, offsetof (struct c3x_config, ai_worker_requirement_percent)}, - {"chance_for_nukes_to_destroy_max_one_hp_units" , 100, offsetof (struct c3x_config, chance_for_nukes_to_destroy_max_one_hp_units)}, - {"rebase_range_multiplier" , 6, offsetof (struct c3x_config, rebase_range_multiplier)}, - {"elapsed_minutes_per_day_night_hour_transition" , 3, offsetof (struct c3x_config, elapsed_minutes_per_day_night_hour_transition)}, - {"fixed_hours_per_turn_for_day_night_cycle" , 1, offsetof (struct c3x_config, fixed_hours_per_turn_for_day_night_cycle)}, - {"pinned_hour_for_day_night_cycle" , 0, offsetof (struct c3x_config, pinned_hour_for_day_night_cycle)}, - {"years_to_double_building_culture" , 1000, offsetof (struct c3x_config, years_to_double_building_culture)}, - {"tourism_time_scale_percent" , 100, offsetof (struct c3x_config, tourism_time_scale_percent)}, - {"luxury_randomized_appearance_rate_percent" , 100, offsetof (struct c3x_config, luxury_randomized_appearance_rate_percent)}, - {"tiles_per_non_luxury_resource" , 32, offsetof (struct c3x_config, tiles_per_non_luxury_resource)}, - {"special_capital_decorruption_effect" , 10, offsetof (struct c3x_config, special_capital_decorruption_effect)}, - {"city_limit" , 2048, offsetof (struct c3x_config, city_limit)}, - {"maximum_pop_before_neighborhood_needed" , 8, offsetof (struct c3x_config, maximum_pop_before_neighborhood_needed)}, - {"per_neighborhood_pop_growth_enabled" , 2, offsetof (struct c3x_config, per_neighborhood_pop_growth_enabled)}, - {"minimum_natural_wonder_separation" , 10, offsetof (struct c3x_config, minimum_natural_wonder_separation)}, - {"distribution_hub_food_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_food_yield_divisor)}, - {"distribution_hub_shield_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_shield_yield_divisor)}, - {"ai_ideal_distribution_hub_count_per_100_cities" , 1, offsetof (struct c3x_config, ai_ideal_distribution_hub_count_per_100_cities)}, - {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, - {"max_distribution_hub_count_per_100_cities" , 50, offsetof (struct c3x_config, max_distribution_hub_count_per_100_cities)}, - {"central_rail_hub_distribution_food_bonus_percent" , 25, offsetof (struct c3x_config, central_rail_hub_distribution_food_bonus_percent)}, - {"central_rail_hub_distribution_shield_bonus_percent", 25, offsetof (struct c3x_config, central_rail_hub_distribution_shield_bonus_percent)}, - {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, - {"max_contiguous_bridge_districts" , 3, offsetof (struct c3x_config, max_contiguous_bridge_districts)}, - {"max_contiguous_canal_districts" , 5, offsetof (struct c3x_config, max_contiguous_canal_districts)}, - {"ai_canal_eval_min_bisected_land_tiles" , 10, offsetof (struct c3x_config, ai_canal_eval_min_bisected_land_tiles)}, - {"ai_bridge_canal_eval_block_size" , 20, offsetof (struct c3x_config, ai_bridge_canal_eval_block_size)}, - {"ai_bridge_eval_lake_tile_threshold" , 6, offsetof (struct c3x_config, ai_bridge_eval_lake_tile_threshold)}, - {"ai_city_district_max_build_wait_turns" , 20, offsetof (struct c3x_config, ai_city_district_max_build_wait_turns)}, - {"per_extraterritorial_colony_relation_penalty" , 0, offsetof (struct c3x_config, per_extraterritorial_colony_relation_penalty)}, - }; - - is->kernel32 = (*p_GetModuleHandleA) ("kernel32.dll"); - is->user32 = (*p_GetModuleHandleA) ("user32.dll"); - is->msvcrt = (*p_GetModuleHandleA) ("msvcrt.dll"); - - // Remember the function names here are macros that expand to is->... - VirtualProtect = (void *)(*p_GetProcAddress) (is->kernel32, "VirtualProtect"); - CloseHandle = (void *)(*p_GetProcAddress) (is->kernel32, "CloseHandle"); - CreateFileA = (void *)(*p_GetProcAddress) (is->kernel32, "CreateFileA"); - GetFileSize = (void *)(*p_GetProcAddress) (is->kernel32, "GetFileSize"); - ReadFile = (void *)(*p_GetProcAddress) (is->kernel32, "ReadFile"); - LoadLibraryA = (void *)(*p_GetProcAddress) (is->kernel32, "LoadLibraryA"); - FreeLibrary = (void *)(*p_GetProcAddress) (is->kernel32, "FreeLibrary"); - MultiByteToWideChar = (void *)(*p_GetProcAddress) (is->kernel32, "MultiByteToWideChar"); - WideCharToMultiByte = (void *)(*p_GetProcAddress) (is->kernel32, "WideCharToMultiByte"); - GetLastError = (void *)(*p_GetProcAddress) (is->kernel32, "GetLastError"); - QueryPerformanceCounter = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceCounter"); - QueryPerformanceFrequency = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceFrequency"); - GetLocalTime = (void *)(*p_GetProcAddress) (is->kernel32, "GetLocalTime"); - MessageBoxA = (void *)(*p_GetProcAddress) (is->user32, "MessageBoxA"); - is->msimg32 = LoadLibraryA ("Msimg32.dll"); - TransparentBlt = (void *)(*p_GetProcAddress) (is->msimg32, "TransparentBlt"); - snprintf = (void *)(*p_GetProcAddress) (is->msvcrt, "_snprintf"); - malloc = (void *)(*p_GetProcAddress) (is->msvcrt, "malloc"); - calloc = (void *)(*p_GetProcAddress) (is->msvcrt, "calloc"); - realloc = (void *)(*p_GetProcAddress) (is->msvcrt, "realloc"); - free = (void *)(*p_GetProcAddress) (is->msvcrt, "free"); - strtol = (void *)(*p_GetProcAddress) (is->msvcrt, "strtol"); - strcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strcmp"); - strncmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strncmp"); - _stricmp = (void *)(*p_GetProcAddress) (is->msvcrt, "_stricmp"); - strlen = (void *)(*p_GetProcAddress) (is->msvcrt, "strlen"); - strncpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strncpy"); - strcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strcpy"); - strdup = (void *)(*p_GetProcAddress) (is->msvcrt, "_strdup"); - strstr = (void *)(*p_GetProcAddress) (is->msvcrt, "strstr"); - qsort = (void *)(*p_GetProcAddress) (is->msvcrt, "qsort"); - memcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "memcmp"); - memcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "memcpy"); - tolower = (void *)(*p_GetProcAddress) (is->msvcrt, "tolower"); - toupper = (void *)(*p_GetProcAddress) (is->msvcrt, "toupper"); - is->memmove = (void *)(*p_GetProcAddress) (is->msvcrt, "memmove"); // No #define for this one, instead it has a wrapper func - - // Intercept the game's calls to MessageBoxA. We can't do this through the patcher since that would interfere with the runtime loader. - WITH_MEM_PROTECTION (p_MessageBoxA, 4, PAGE_READWRITE) - *p_MessageBoxA = patch_MessageBoxA; - - // Set file path to mod's script.txt - snprintf (is->mod_script_path, sizeof is->mod_script_path, "%s\\Text\\c3x-script.txt", is->mod_rel_dir); - is->mod_script_path[(sizeof is->mod_script_path) - 1] = '\0'; - - // Fill in base config - struct c3x_config base_config = {0}; - base_config.land_retreat_rules = RR_STANDARD; - base_config.sea_retreat_rules = RR_STANDARD; - base_config.ai_settler_perfume_on_founding = 0; - base_config.work_area_limit = WAL_NONE; - base_config.draw_lines_using_gdi_plus = LDO_WINE; - base_config.double_minimap_size = MDM_HIGH_DEF; - base_config.override_no_ai_patrol = NAPO_NONE; - base_config.override_barbarian_activity_level_for_scenario_maps = BAO_NONE; - base_config.unit_cycle_search_criteria = UCSC_STANDARD; - base_config.city_work_radius = 2; - base_config.day_night_cycle_mode = DNCM_OFF; - base_config.distribution_hub_yield_division_mode = DHYDM_FLAT; - base_config.ai_distribution_hub_build_strategy = ADHBS_BY_CITY_COUNT; - base_config.ai_auto_build_great_wall_strategy = AAGWS_ALL_BORDERS; - base_config.great_wall_auto_build_wonder_improv_id = -1; - for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) - *((char *)&base_config + boolean_config_options[n].offset) = boolean_config_options[n].base_val; - for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) - *(int *)((byte *)&base_config + integer_config_options[n].offset) = integer_config_options[n].base_val; - memcpy (&is->base_config, &base_config, sizeof base_config); - - // Load labels - { - for (int n = 0; n < COUNT_C3X_LABELS; n++) - is->c3x_labels[n] = ""; - - char labels_path[MAX_PATH]; - snprintf (labels_path, sizeof labels_path, "%s\\Text\\c3x-labels.txt", is->mod_rel_dir); - labels_path[(sizeof labels_path) - 1] = '\0'; - char * labels_file_contents = file_to_string (labels_path); - - if (labels_file_contents != NULL) { - char * cursor = labels_file_contents; - int n = 0; - while ((n < COUNT_C3X_LABELS) && (*cursor != '\0')) { - if (*cursor == '\n') - cursor++; - else if ((cursor[0] == '\r') && (cursor[1] == '\n')) - cursor += 2; - else if (*cursor == ';') { - while ((*cursor != '\0') && (*cursor != '\n')) - cursor++; - } else { - char * line_start = cursor; - while ((*cursor != '\0') && (*cursor != '\r') && (*cursor != '\n')) - cursor++; - int line_len = cursor - line_start; - if (NULL != (is->c3x_labels[n] = malloc (line_len + 1))) { - strncpy (is->c3x_labels[n], line_start, line_len); - is->c3x_labels[n][line_len] = '\0'; - } - n++; - } - } - free (labels_file_contents); - - } else { - char err_msg[500]; - snprintf (err_msg, sizeof err_msg, "Couldn't read labels from %s\nPlease make sure the file exists. If you moved the modded EXE you must move the mod folder after it.", labels_path); - err_msg[(sizeof err_msg) - 1] = '\0'; - MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); - } - } - - is->sb_next_up = NULL; - is->trade_net = p_original_trade_net; - is->city_limit = 512; - is->trade_net_addrs_load_state = IS_UNINITED; - is->trade_net_addrs = NULL; - is->tnx_cache = NULL; - is->is_computing_city_connections = false; - is->keep_tnx_cache = false; - is->must_recompute_resources_for_mill_inputs = false; - is->is_placing_scenario_things = false; - is->paused_for_popup = false; - is->time_spent_paused_during_popup = 0; - is->time_spent_computing_city_connections = 0; - is->count_calls_to_recompute_city_connections = 0; - - is->have_job_and_loc_to_skip = 0; - - // Initialize trade screen scroll vars - is->open_diplo_form_straight_to_trade = 0; - is->trade_screen_scroll_to_id = -1; - is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; - is->trade_scroll_button_images = NULL; - is->trade_scroll_button_state = IS_UNINITED; - is->eligible_for_trade_scroll = 0; - - memset (&is->saved_code_areas, 0, sizeof is->saved_code_areas); - - is->unit_menu_duplicates = NULL; - - is->memo = NULL; - is->memo_len = 0; - is->memo_capacity = 0; - - // Fill in array mapping cultural NIs to standard ones. - is->cultural_ni_to_standard = malloc (MAX_CULTURAL_NI + 1); - for (int n = 0; n <= MAX_CULTURAL_NI; n++) { - char const * p = &cultural_ni_to_diffs[n << 1]; - is->cultural_ni_to_standard[n] = diff_to_neighbor_index (p[0], p[1], 1000); - } - - // Fill in array mapping standard NIs to work radii AKA work ring numbers - for (int n = 0; n < ARRAY_LEN (is->ni_to_work_radius); n++) { - int work_radius = -1; - int dx, dy; - neighbor_index_to_diff (n, &dx, &dy); - for (int ring_no = 0; ring_no <= 7; ring_no++) { - for (int k = workable_tile_counts[ring_no-1]; k < workable_tile_counts[ring_no]; k++) { - char const * p = &cultural_ni_to_diffs[k<<1]; - if ((p[0] == dx) && (p[1] == dy)) { - work_radius = ring_no; - break; - } - } - if (work_radius != -1) - break; - } - is->ni_to_work_radius[n] = work_radius; - } - - is->city_loc_display_perspective = -1; - - is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; - - is->extra_available_resources = NULL; - is->extra_available_resources_capacity = 0; - - memset (is->interceptor_reset_lists, 0, sizeof is->interceptor_reset_lists); - - is->ai_prod_valuations = NULL; - is->count_ai_prod_valuations = 0; - is->ai_prod_valuations_capacity = 0; - - is->resource_tiles = NULL; - is->count_resource_tiles = 0; - is->resource_tiles_capacity = 0; - is->got_resource_tile = NULL; - is->saved_tile_count = -1; - is->mill_input_resource_bits = NULL; - - is->drawing_icons_for_improv_id = -1; - - is->resources_sheet = NULL; - - is->modifying_gold_trade = NULL; - - is->bombard_stealth_target = NULL; - is->selecting_stealth_target_for_bombard = 0; - - is->map_message_text_override = NULL; - - is->load_file_path_override = NULL; - - is->replay_for_players = 0; - - is->suppress_intro_after_load_popup = 0; - - is->force_barb_activity_for_cities = 0; - - is->dummy_tile = calloc (1, sizeof *is->dummy_tile); - - is->bombarding_unit = NULL; - - is->unit_bombard_attacking_tile = NULL; - is->attacking_tile_x = is->attacking_tile_y = -1; - - is->temporarily_disallow_lethal_zoc = false; - is->moving_unit_to_adjacent_tile = false; - is->showing_hotseat_replay = false; - is->getting_tile_occupier_for_ai_pathfinding = false; - - is->running_on_wine = false; { - HMODULE ntdll = (*p_GetModuleHandleA) ("ntdll.dll"); - is->running_on_wine = (ntdll != NULL) && ((*p_GetProcAddress) (ntdll, "wine_get_version") != NULL); - } - - is->gdi_plus.init_state = IS_UNINITED; - - is->water_trade_improvs = (struct improv_id_list) {0}; - is->air_trade_improvs = (struct improv_id_list) {0}; - is->combat_defense_improvs = (struct improv_id_list) {0}; - - is->unit_display_override = (struct unit_display_override) {-1, -1, -1}; - - is->dbe = (struct defensive_bombard_event) {0}; - - memset (&is->boolean_config_offsets, 0, sizeof is->boolean_config_offsets); - for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) - stable_insert (&is->boolean_config_offsets, boolean_config_options[n].name, boolean_config_options[n].offset); - memset (&is->integer_config_offsets, 0, sizeof is->integer_config_offsets); - for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) - stable_insert (&is->integer_config_offsets, integer_config_options[n].name, integer_config_options[n].offset); - - memset (&is->unit_type_alt_strategies, 0, sizeof is->unit_type_alt_strategies); - memset (&is->unit_type_duplicates , 0, sizeof is->unit_type_duplicates); - memset (&is->extra_defensive_bombards, 0, sizeof is->extra_defensive_bombards); - memset (&is->airdrops_this_turn , 0, sizeof is->airdrops_this_turn); - memset (&is->unit_transport_ties , 0, sizeof is->unit_transport_ties); - memset (&is->extra_city_improvs , 0, sizeof is->extra_city_improvs); - - is->unit_type_count_init_bits = 0; - for (int n = 0; n < 32; n++) - memset (&is->unit_type_counts[n], 0, sizeof is->unit_type_counts[n]); - - is->penciled_in_upgrades = NULL; - is->penciled_in_upgrade_count = is->penciled_in_upgrade_capacity = 0; - - is->currently_capturing_city = NULL; - is->accessing_save_file = NULL; - - is->drawn_strat_resource_count = 0; - - is->charmed_types_converted_to_ptw_arty = NULL; - is->count_charmed_types_converted_to_ptw_arty = 0; - is->charmed_types_converted_to_ptw_arty_capacity = 0; - - is->checking_visibility_for_unit = NULL; - - is->do_not_bounce_invisible_units = false; - is->always_despawn_passengers = false; - is->do_not_enslave_units = false; - - is->saved_improv_counts = NULL; - is->saved_improv_counts_capacity = 0; - - memset (is->last_main_screen_key_up_events, 0, sizeof is->last_main_screen_key_up_events); - - reset_district_state (true); - - is->natural_wonder_count = 0; - - is->sharing_buildings_by_districts_in_progress = false; - is->can_load_transport = is->can_load_passenger = NULL; - - is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; - is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; - is->last_selected_unit.ptr = NULL; - - is->waiting_units = (struct table) {0}; - is->have_loaded_waiting_units = false; - - is->extra_capture_despawns = NULL; - is->count_extra_capture_despawns = 0; - is->extra_capture_despawns_capacity = 0; - - is->loaded_config_names = NULL; - reset_to_base_config (); - apply_machine_code_edits (&is->current_config, true); -} - -void -init_stackable_command_buttons () -{ - if (is->sc_img_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - for (int n = 0; n < 4; n++) - Sprite_construct (&is->sc_button_image_sets[sc].imgs[n]); - - char temp_path[2*MAX_PATH]; - - is->sb_activated_by_button = 0; - is->sc_img_state = IS_INIT_FAILED; - - char const * filenames[4] = {"StackedNormButtons.pcx", "StackedRolloverButtons.pcx", "StackedHighlightedButtons.pcx", "StackedButtonsAlpha.pcx"}; - for (int n = 0; n < 4; n++) { - get_mod_art_path (filenames[n], temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - for (int k = 0; k < 4; k++) { - Sprite * sprite = &is->sc_button_image_sets[sc].imgs[k]; - sprite->vtable->destruct (sprite, __, 0); - } - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) { - int x = 32 * sc_button_infos[sc].tile_sheet_column, - y = 32 * sc_button_infos[sc].tile_sheet_row; - Sprite_slice_pcx (&is->sc_button_image_sets[sc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); - } - - pcx.vtable->clear_JGL (&pcx); - } - - is->sc_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -void -init_disabled_command_buttons () -{ - if (is->disabled_command_img_state != IS_UNINITED) - return; - - is->disabled_command_img_state = IS_INIT_FAILED; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("DisabledButtons.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load disabled command buttons sprite sheet.\n"); - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - Sprite_construct (&is->disabled_build_city_button_img); - Sprite_slice_pcx (&is->disabled_build_city_button_img, __, &pcx, 32*5, 32*2, 32, 32, 1, 0); - - is->disabled_command_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_stackable_command_buttons () -{ - if (is->sc_img_state == IS_OK) - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - for (int n = 0; n < 4; n++) { - Sprite * sprite = &is->sc_button_image_sets[sc].imgs[n]; - sprite->vtable->destruct (sprite, __, 0); - } - is->sc_img_state = IS_UNINITED; -} - -void -deinit_disabled_command_buttons () -{ - Sprite * sprite = &is->disabled_build_city_button_img; - if (is->disabled_command_img_state == IS_OK) - sprite->vtable->destruct (sprite, __, 0); - memset (sprite, 0, sizeof *sprite); - is->disabled_command_img_state = IS_UNINITED; -} - -void -init_tile_highlights () -{ - if (is->tile_highlight_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - - is->tile_highlight_state = IS_INIT_FAILED; - - snprintf (temp_path, sizeof temp_path, "%s\\Art\\TileHighlights.pcx", is->mod_rel_dir); - temp_path[(sizeof temp_path) - 1] = '\0'; - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); - goto cleanup; - } - - for (int n = 0; n < COUNT_TILE_HIGHLIGHTS; n++) - Sprite_slice_pcx (&is->tile_highlights[n], __, &pcx, 128*n, 0, 128, 64, 1, 0); - - is->tile_highlight_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -init_unit_rcm_icons () -{ - if (is->unit_rcm_icon_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("UnitRCMIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image == NULL) || - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 57) || - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 64)) { - (*p_OutputDebugStringA) ("[C3X] PCX file for unit RCM icons failed to load or is too small.\n"); - goto cleanup; - } - - for (int set = 0; set < COUNT_UNIT_RCM_ICON_SETS; set++) { - Sprite * icons = &is->unit_rcm_icons[set * COUNT_UNIT_RCM_ICONS]; - for (int n = 0; n < COUNT_UNIT_RCM_ICONS; n++) { - Sprite_construct (&icons[n]); - Sprite_slice_pcx (&icons[n], __, &pcx, 1 + 14*set, 1 + 16*n, 14, 15, 1, 0); - } - } - - is->unit_rcm_icon_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_unit_rcm_icons () -{ - if (is->unit_rcm_icon_state == IS_OK) { - int total_icon_count = COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS; - for (int n = 0; n < total_icon_count; n++) { - Sprite * sprite = &is->unit_rcm_icons[n]; - sprite->vtable->destruct (sprite, __, 0); - } - is->unit_rcm_icon_state = IS_UNINITED; - } -} - -void -init_red_food_icon () -{ - if (is->red_food_icon_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("MoreCityIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image != NULL) && - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) >= 32) && - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) == 32)) { - Sprite_construct (&is->red_food_icon); - Sprite_slice_pcx (&is->red_food_icon, __, &pcx, 1, 1, 30, 30, 1, 1); - is->red_food_icon_state = IS_OK; - } else { - (*p_OutputDebugStringA) ("[C3X] PCX file for red food icon failed to load or is not the correct size.\n"); - is->red_food_icon_state = IS_INIT_FAILED; - } - - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_red_food_icon () -{ - if (is->red_food_icon_state == IS_OK) - is->red_food_icon.vtable->destruct (&is->red_food_icon, __, 0); - is->red_food_icon_state = IS_UNINITED; -} - -enum init_state -init_large_minimap_frame () -{ - if (is->large_minimap_frame_img_state != IS_UNINITED) - return is->large_minimap_frame_img_state; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - - get_mod_art_path ("interface\\DoubleSizeBoxLeftColor.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image != NULL) { - Sprite_construct (&is->double_size_box_left_color_pcx); - int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), - height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); - Sprite_slice_pcx (&is->double_size_box_left_color_pcx, __, &pcx, 0, 0, width, height, 1, 1); - } else { - pcx.vtable->destruct (&pcx, __, 0); - return is->large_minimap_frame_img_state = IS_INIT_FAILED; - } - - get_mod_art_path ("interface\\DoubleSizeBoxLeftAlpha.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image != NULL) { - Sprite_construct (&is->double_size_box_left_alpha_pcx); - int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), - height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); - Sprite_slice_pcx (&is->double_size_box_left_alpha_pcx, __, &pcx, 0, 0, width, height, 1, 1); - } else { - is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); - pcx.vtable->destruct (&pcx, __, 0); - return is->large_minimap_frame_img_state = IS_INIT_FAILED;; - } - - pcx.vtable->destruct (&pcx, __, 0); - return is->large_minimap_frame_img_state = IS_OK; -} - -void -deinit_large_minimap_frame () -{ - if (is->large_minimap_frame_img_state == IS_OK) { - is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); - is->double_size_box_left_alpha_pcx.vtable->destruct (&is->double_size_box_left_alpha_pcx, __, 0); - } - is->large_minimap_frame_img_state = IS_UNINITED; -} - -int __cdecl -patch_get_tile_occupier_for_ai_path (int x, int y, int pov_civ_id, bool respect_unit_invisibility) -{ - is->getting_tile_occupier_for_ai_pathfinding = true; - return get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); - is->getting_tile_occupier_for_ai_pathfinding = false; -} - -char __fastcall patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2); - -char __fastcall -patch_Unit_is_tile_occupier_visible (Unit * this, int edx, int civ_id, int param_2) -{ - // Here's the fix for the submarine bug: If we're constructing a path for an AI unit, ignore unit invisibility so the pathfinder will path - // around instead of over other civ's units. We must carve out an exception if the AI is at war with the unit in question. In that case if it - // "accidentally" paths over the unit, it should get stuck in combat like the human player would. - if (is->current_config.patch_submarine_bug && - is->getting_tile_occupier_for_ai_pathfinding && - ! this->vtable->is_enemy_of_civ (this, __, civ_id, 0)) - return 1; - else - return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); -} - -void do_trade_scroll (DiploForm * diplo, int forward); - -void __cdecl -activate_trade_scroll_button (int control_id) -{ - do_trade_scroll (p_diplo_form, control_id == TRADE_SCROLL_BUTTON_ID_RIGHT); -} - -void -init_trade_scroll_buttons (DiploForm * diplo_form) -{ - if (is->trade_scroll_button_state != IS_UNINITED) - return; - - char temp_path[2*MAX_PATH]; - PCX_Image pcx; - PCX_Image_construct (&pcx); - get_mod_art_path ("TradeScrollButtons.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - is->trade_scroll_button_state = IS_INIT_FAILED; - (*p_OutputDebugStringA) ("[C3X] Failed to load TradeScrollButtons.pcx\n"); - goto cleanup; - } - - // Stores normal, rollover, and highlight images, in that order, first for the left button then for the right - is->trade_scroll_button_images = calloc (6, sizeof is->trade_scroll_button_images[0]); - for (int n = 0; n < 6; n++) - Sprite_construct (&is->trade_scroll_button_images[n]); - Sprite * imgs = is->trade_scroll_button_images; - - for (int right = 0; right < 2; right++) - for (int n = 0; n < 3; n++) - Sprite_slice_pcx (&imgs[n + 3*right], __, &pcx, right ? 44 : 0, 1 + 48*n, 43, 47, 1, 1); - - for (int right = 0; right < 2; right++) { - Button * b = new (sizeof *b); - - Button_construct (b); - int id = right ? TRADE_SCROLL_BUTTON_ID_RIGHT : TRADE_SCROLL_BUTTON_ID_LEFT; - Button_initialize (b, __, NULL, id, right ? 622 : 358, 50, 43, 47, (Base_Form *)diplo_form, 0); - for (int n = 0; n < 3; n++) - b->Images[n] = &imgs[n + 3*right]; - - b->activation_handler = &activate_trade_scroll_button; - b->field_630[0] = 0; // TODO: Is this necessary? It's done by the base game code when creating the city screen scroll buttons - - if (! right) - is->trade_scroll_button_left = b; - else - is->trade_scroll_button_right = b; - } - - is->trade_scroll_button_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -deinit_trade_scroll_buttons () -{ - if (is->trade_scroll_button_state == IS_OK) { - is->trade_scroll_button_left ->vtable->destruct ((Base_Form *)is->trade_scroll_button_left , __, 0); - is->trade_scroll_button_right->vtable->destruct ((Base_Form *)is->trade_scroll_button_right, __, 0); - is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; - for (int n = 0; n < 6; n++) { - Sprite * sprite = &is->trade_scroll_button_images[n]; - sprite->vtable->destruct (sprite, __, 0); - } - free (is->trade_scroll_button_images); - is->trade_scroll_button_images = NULL; - } - is->trade_scroll_button_state = IS_UNINITED; -} - -void -init_mod_info_button_images () -{ - if (is->mod_info_button_images_state != IS_UNINITED) - return; - - is->mod_info_button_images_state = IS_INIT_FAILED; - - PCX_Image * descbox_pcx = new (sizeof *descbox_pcx); - PCX_Image_construct (descbox_pcx); - char * descbox_path = BIC_get_asset_path (p_bic_data, __, "art\\civilopedia\\descbox.pcx", true); - PCX_Image_read_file (descbox_pcx, __, descbox_path, NULL, 0, 0x100, 1); - if (descbox_pcx->JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load descbox.pcx\n"); - return; - } - - for (int n = 0; n < 3; n++) { - Sprite_construct (&is->mod_info_button_images[n]); - Sprite_slice_pcx_with_color_table (&is->mod_info_button_images[n], __, descbox_pcx, 1 + n * 103, 1, MOD_INFO_BUTTON_WIDTH, - MOD_INFO_BUTTON_HEIGHT, 1, 1); - } - - is->mod_info_button_images_state = IS_OK; -} - -int -count_escorters (Unit * unit) -{ - IDLS * idls = &unit->Body.IDLS; - if (idls->escorters.contents != NULL) { - int tr = 0; - for (int * p_escorter_id = idls->escorters.contents; p_escorter_id < idls->escorters.contents_end; p_escorter_id++) - tr += NULL != get_unit_ptr (*p_escorter_id); - return tr; - } else - return 0; -} - -// If "unit" belongs to the AI, records that all players that have visibility on (x, y) have seen an AI unit -void -record_ai_unit_seen (Unit * unit, int x, int y) -{ - if (0 == (*p_human_player_bits & 1<Body.CivID)) { - Tile * tile = tile_at (x, y); - if ((tile != NULL) && (tile != p_null_tile)) { - Tile_Body * body = &tile->Body; - is->players_saw_ai_unit |= body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility; - } - } -} - -void -recompute_resources_if_necessary () -{ - if (is->must_recompute_resources_for_mill_inputs) - patch_Trade_Net_recompute_resources (is->trade_net, __, false); -} - -void __fastcall -patch_Unit_bombard_tile (Unit * this, int edx, int x, int y) -{ - Tile * target_tile = NULL; - bool had_district_before = false; - int tile_x = x; - int tile_y = y; - struct district_instance * inst; - - if (is->current_config.enable_districts) { - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - target_tile = tile_at (tile_x, tile_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - inst = get_district_instance (target_tile); - had_district_before = (inst != NULL); - } - } - - is->bombarding_unit = this; - record_ai_unit_seen (this, x, y); - Unit_bombard_tile (this, __, x, y); - is->bombard_stealth_target = NULL; - is->bombarding_unit = NULL; - - if (had_district_before && target_tile != NULL && target_tile != p_null_tile && inst->district_id != NATURAL_WONDER_DISTRICT_ID) { - unsigned int overlays = target_tile->vtable->m42_Get_Overlays (target_tile, __, 0); - if ((overlays & TILE_FLAG_MINE) == 0) - handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, false); - } -} - -void __fastcall -patch_Unit_move (Unit * this, int edx, int tile_x, int tile_y) -{ - record_ai_unit_seen (this, tile_x, tile_y); - - Unit_move (this, __, tile_x, tile_y); - - if (this == is->last_selected_unit.ptr) { - is->last_selected_unit.last_x = this->Body.X; - is->last_selected_unit.last_y = this->Body.Y; - } -} - -// Returns true if the unit has attacked & does not have blitz or if it's run out of movement points for the turn -bool -has_exhausted_attack (Unit * unit) -{ - return (unit->Body.Moves >= patch_Unit_get_max_move_points (unit)) || - ((unit->Body.Status & USF_USED_ATTACK) && ! UnitType_has_ability (&p_bic_data->UnitTypes[unit->Body.UnitTypeID], __, UTA_Blitz)); -} - -// Returns whether or not the unit type is a combat type and can do damage on offense (as opposed to only being able to defend). This includes units -// that can only do damage by bombarding and nuclear weapons. -bool -is_offensive_combat_type (UnitType * unit_type) -{ - return (unit_type->Attack > 0) || - ((((unit_type->Special_Actions & UCV_Bombard) | (unit_type->Air_Missions & UCV_Bombing)) & 0x0FFFFFFF) && // (type can perform bombard or bombing AND - ((unit_type->Bombard_Strength > 0) || UnitType_has_ability (unit_type, __, UTA_Nuclear_Weapon))); // (unit has bombard strength OR is a nuclear weapon)) -} - -bool -can_damage_bombarding (UnitType * attacker_type, Unit * defender, Tile * defender_tile) -{ - Unit * container; - if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - (container = get_unit_ptr (defender->Body.Container_Unit)) != NULL && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return false; - - UnitType * defender_type = &p_bic_data->UnitTypes[defender->Body.UnitTypeID]; - if (defender_type->Unit_Class == UTC_Land) { - int has_lethal_land_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Land_Bombardment); - return defender->Body.Damage + (! has_lethal_land_bombard) < Unit_get_max_hp (defender); - } else if (defender_type->Unit_Class == UTC_Sea) { - // Land artillery can't normally damage ships in port - if ((attacker_type->Unit_Class == UTC_Land) && (! is->current_config.remove_land_artillery_target_restrictions) && Tile_has_city (defender_tile)) - return false; - int has_lethal_sea_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Sea_Bombardment); - return defender->Body.Damage + (! has_lethal_sea_bombard) < Unit_get_max_hp (defender); - } else if (defender_type->Unit_Class == UTC_Air) { - if (is->current_config.immunize_aircraft_against_bombardment) - return false; - // Can't damage aircraft in an airfield by bombarding, the attack doesn't even go off - if ((defender_tile->vtable->m42_Get_Overlays (defender_tile, __, 0) & 0x20000000) != 0) - return false; - // Land artillery can't normally damage aircraft but naval artillery and other aircraft can. Lethal bombard doesn't apply; anything - // that can damage can kill. - return (attacker_type->Unit_Class != UTC_Land) || is->current_config.remove_land_artillery_target_restrictions; - } else // UTC_Space? UTC_Alternate_Dimension??? - return false; -} - -char __fastcall -patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2) -{ - // Save the previous value here b/c this function gets called recursively - Unit * prev_checking = is->checking_visibility_for_unit; - is->checking_visibility_for_unit = this; - - char base_vis = Unit_is_visible_to_civ (this, __, civ_id, param_2); - if ((! base_vis) && // if unit is not visible to civ_id AND - is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND - ((1 << civ_id) & *p_human_player_bits) && // civ_id is a human player AND - (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game - - // Check if the unit is visible to any other human player in the game - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && - (n_player != civ_id) && - Unit_is_visible_to_civ (this, __, n_player, param_2)) - return 1; - player_bits >>= 1; - n_player++; - } - } - - is->checking_visibility_for_unit = prev_checking; - return base_vis; -} - -bool -has_any_destructible_improvements (City * city) -{ - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * improv = &p_bic_data->Improvements[n]; - if (((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) && // if improv is not a wonder AND - ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && // it's not the palace AND - (improv->SpaceshipPart < 0) && // it's not a spaceship part AND - patch_City_has_improvement (city, __, n, 0)) // it's present in the city ignoring free improvements - return true; - } - return false; -} - -int const destructible_overlays = - 0x00000003 | // road, railroad - 0x00000004 | // mine - 0x00000008 | // irrigation - 0x00000010 | // fortress - 0x10000000 | // barricade - 0x20000000 | // airfield - 0x40000000 | // radar - 0x80000000; // outpost - -bool -has_any_destructible_overlays (Tile * tile, bool precision_strike) -{ - int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); - if ((overlays & destructible_overlays) == 0) - return false; - else { - if (! precision_strike) - return true; - else { - if (overlays == 0x20000000) { // if tile ONLY has an airfield - int any_aircraft_on_tile = 0; { - FOR_UNITS_ON (uti, tile) - if (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class == UTC_Air) { - any_aircraft_on_tile = 1; - break; - } - } - return ! any_aircraft_on_tile; - } else - return true; - } - } -} - -void __fastcall -patch_Main_Screen_Form_perform_action_on_tile (Main_Screen_Form * this, int edx, enum Unit_Mode_Actions action, int x, int y) -{ - if ((! is->current_config.enable_stack_bombard) || // if stack bombard is disabled OR - (! ((action == UMA_Bombard) || (action == UMA_Air_Bombard))) || // action is not bombard OR - ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) && // (control key is not down AND - ((is->sc_img_state != IS_UNINITED) && (is->sb_activated_by_button == 0))) || // (button flag is valid AND not set)) OR - is_online_game ()) { // is online game - Main_Screen_Form_perform_action_on_tile (this, __, action, x, y); - return; - } - - // Save preferences so we can restore them at the end of the stack bombard operation. We might change them to turn off combat animations. - unsigned init_prefs = *p_preferences; - - clear_memo (); - - wrap_tile_coords (&p_bic_data->Map, &x, &y); - Tile * base_tile = tile_at (this->Current_Unit->Body.X, this->Current_Unit->Body.Y); - Tile * target_tile = tile_at (x, y); - int attacker_type_id = this->Current_Unit->Body.UnitTypeID; - UnitType * attacker_type = &p_bic_data->UnitTypes[attacker_type_id]; - int civ_id = this->Current_Unit->Body.CivID; - - // Count & memoize attackers - int selected_unit_id = this->Current_Unit->Body.ID; - FOR_UNITS_ON (uti, base_tile) - if ((uti.id != selected_unit_id) && - (uti.unit->Body.CivID == civ_id) && - (uti.unit->Body.UnitTypeID == attacker_type_id) && - ((uti.unit->Body.Container_Unit < 0) || (attacker_type->Unit_Class == UTC_Air)) && - (uti.unit->Body.UnitState == 0) && - ! has_exhausted_attack (uti.unit)) - memoize (uti.id); - int count_attackers = is->memo_len; - - // Count & memoize targets (also count air units while we're at it) - int num_air_units_on_target_tile = 0; - FOR_UNITS_ON (uti, target_tile) { - num_air_units_on_target_tile += UTC_Air == p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; - if ((uti.unit->Body.CivID != civ_id) && - (Unit_get_defense_strength (uti.unit) > 0) && - (uti.unit->Body.Container_Unit < 0) && - patch_Unit_is_visible_to_civ (uti.unit, __, civ_id, 0) && - can_damage_bombarding (attacker_type, uti.unit, target_tile)) - memoize (uti.id); - } - int count_targets = is->memo_len - count_attackers; - - // Now our attackers and targets arrays will just be pointers into the memo - int * attackers = &is->memo[0], * targets = &is->memo[count_attackers]; - - int attacking_units = 0, attacking_tile = 0; - City * target_city = NULL; - if (count_targets > 0) - attacking_units = 1; - else if (Tile_has_city (target_tile)) - target_city = get_city_ptr (target_tile->vtable->m45_Get_City_ID (target_tile)); - else { - // Make sure not to set attacking_tile when the tile has an airfield and air units (but no land units) on - // it. In that case we can't damage the airfield and if we try to anyway, the units will waste their moves - // without attacking. - int has_airfield = (target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & 0x20000000) != 0; - attacking_tile = (! has_airfield) || (num_air_units_on_target_tile == 0); - } - - is->sb_next_up = this->Current_Unit; - int i_next_attacker = 0; - int anything_left_to_attack; - int last_attack_didnt_happen; - do { - // If combat animations were enabled when the stack bombard operation started, reset the preference according to the state of the - // shift key (down => skip animations, up => show them). - if (init_prefs & P_ANIMATE_BATTLES) { - if ((*p_GetAsyncKeyState) (VK_SHIFT) >> 8) - *p_preferences &= ~P_ANIMATE_BATTLES; - else - *p_preferences |= P_ANIMATE_BATTLES; - } - - int moves_before_bombard = is->sb_next_up->Body.Moves; - - patch_Unit_bombard_tile (is->sb_next_up, __, x, y); - // At this point sb_next_up may have become NULL if the unit was a bomber that got shot down. - - // Check if the last unit sent into battle actually did anything. If it didn't we should at least skip over - // it to avoid an infinite loop, but actually the only time this should happen is if the player is not at - // war with the targeted civ and chose not to declare when prompted. In this case it's better to just stop - // trying to attack so as to not spam the player with prompts. - last_attack_didnt_happen = (is->sb_next_up == NULL) || (is->sb_next_up->Body.Moves == moves_before_bombard); - - if ((is->sb_next_up == NULL) || has_exhausted_attack (is->sb_next_up)) { - is->sb_next_up = NULL; - while ((i_next_attacker < count_attackers) && (is->sb_next_up == NULL)) - is->sb_next_up = get_unit_ptr (attackers[i_next_attacker++]); - } - - if (attacking_units) { - anything_left_to_attack = 0; - for (int n = 0; n < count_targets; n++) { - Unit * unit = get_unit_ptr (targets[n]); - - // Make sure this unit is still a valid target. Keep in mind it's possible for new units to be created during the - // stack bombard operation if the attackers have lethal bombard and the enslave ability. - if ((unit != NULL) && (unit->Body.X == x) && (unit->Body.Y == y) && (unit->Body.CivID != civ_id)) { - - if (can_damage_bombarding (attacker_type, unit, target_tile)) { - anything_left_to_attack = 1; - break; - } - } - } - } else if (target_city != NULL) - anything_left_to_attack = (target_city->Body.Population.Size > 1) || has_any_destructible_improvements (target_city); - else if (attacking_tile) - anything_left_to_attack = has_any_destructible_overlays (target_tile, false); - else - anything_left_to_attack = 0; - } while ((is->sb_next_up != NULL) && anything_left_to_attack && (! last_attack_didnt_happen)); - - is->sb_activated_by_button = 0; - is->sb_next_up = NULL; - *p_preferences = init_prefs; - this->GUI.Base.vtable->m73_call_m22_Draw ((Base_Form *)&this->GUI); -} - -void -set_up_stack_bombard_buttons (Main_GUI * this) -{ - if (is_online_game () || (! is->current_config.enable_stack_bombard)) - return; - - init_stackable_command_buttons (); - if (is->sc_img_state != IS_OK) - return; - - // Find button that the original method set to (air) bombard, then find the next unused button after that. - Command_Button * bombard_button = NULL, * free_button = NULL; { - int i_bombard_button; - for (int n = 0; n < 42; n++) - if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && - (this->Unit_Command_Buttons[n].Command == UCV_Bombard || this->Unit_Command_Buttons[n].Command == UCV_Bombing)) { - bombard_button = &this->Unit_Command_Buttons[n]; - i_bombard_button = n; - break; - } - if (bombard_button != NULL) - for (int n = i_bombard_button + 1; n < 42; n++) - if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { - free_button = &this->Unit_Command_Buttons[n]; - break; - } - } - - if ((bombard_button == NULL) || (free_button == NULL)) - return; - - // Set up free button for stack bombard - free_button->Command = bombard_button->Command; - free_button->field_6D8 = bombard_button->field_6D8; - struct sc_button_image_set * img_set = - (bombard_button->Command == UCV_Bombing) ? &is->sc_button_image_sets[SC_BOMB] : &is->sc_button_image_sets[SC_BOMBARD]; - for (int n = 0; n < 4; n++) - free_button->Button.Images[n] = &img_set->imgs[n]; - free_button->Button.field_664 = bombard_button->Button.field_664; - // FUN_005559E0 is also called in the original code. I don't know what it actually does but I'm pretty sure it doesn't - // matter for our purposes. - Button_set_tooltip (&free_button->Button, __, is->c3x_labels[CL_SB_TOOLTIP]); - free_button->Button.field_5FC[13] = bombard_button->Button.field_5FC[13]; - free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); -} - -void -init_district_command_buttons () -{ - if (is_online_game () || is->dc_btn_img_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) - for (int n = 0; n < 4; n++) - Sprite_construct (&is->district_btn_img_sets[dc].imgs[n]); - - char temp_path[2*MAX_PATH]; - - is->dc_btn_img_state = IS_INIT_FAILED; - - // For each button sprite type (normal, rollover, highlighted, alpha) - char const * filenames[4] = { - "Districts\\WorkerDistrictButtonsNorm.pcx", "Districts\\WorkerDistrictButtonsRollover.pcx", - "Districts\\WorkerDistrictButtonsHighlighted.pcx", "Districts\\WorkerDistrictButtonsAlpha.pcx" - }; - for (int n = 0; n < 4; n++) { - get_mod_art_path (filenames[n], temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if (pcx.JGL.Image == NULL) { - (*p_OutputDebugStringA) ("[C3X] Failed to load work district command buttons sprite sheet.\n"); - for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) - for (int k = 0; k < 4; k++) { - Sprite * sprite = &is->district_btn_img_sets[dc].imgs[k]; - sprite->vtable->destruct (sprite, __, 0); - } - pcx.vtable->destruct (&pcx, __, 0); - - char ss[200]; - snprintf (ss, sizeof ss, "[C3X] Failed to load district command button images from %s", temp_path); - pop_up_in_game_error (ss); - - return; - } - - // For each district type - int district_count = is->district_count; - if (district_count > COUNT_DISTRICT_TYPES) - district_count = COUNT_DISTRICT_TYPES; - for (int dc = 0; dc < district_count; dc++) { - int x = 32 * is->district_configs[dc].btn_tile_sheet_column, - y = 32 * is->district_configs[dc].btn_tile_sheet_row; - Sprite_slice_pcx (&is->district_btn_img_sets[dc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); - } - - pcx.vtable->clear_JGL (&pcx); - } - - is->dc_btn_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -int -parse_turns_from_tooltip (char const * tooltip) -{ - if ((tooltip == NULL) || (*tooltip == '\0')) - return -1; - - char const * last_paren = NULL; - for (char const * cursor = tooltip; *cursor != '\0'; cursor++) - if (*cursor == '(') - last_paren = cursor; - if (last_paren == NULL) - return -1; - - char const * digit_ptr = last_paren + 1; - while (*digit_ptr == ' ') - digit_ptr++; - - int turns = 0; - bool have_digit = false; - while ((*digit_ptr >= '0') && (*digit_ptr <= '9')) { - have_digit = true; - turns = (turns * 10) + (*digit_ptr - '0'); - digit_ptr++; - } - return have_digit ? turns : -1; -} - -void -compute_highlighted_worker_tiles_for_districts () -{ - if (is_online_game () - || ! is->current_config.enable_districts - || ! is->current_config.enable_city_work_radii_highlights) - return; - - Unit * selected_unit = p_main_screen_form->Current_Unit; - if (selected_unit == NULL) - return; - - int unit_type_id = selected_unit->Body.UnitTypeID; - if (p_bic_data->UnitTypes[unit_type_id].Worker_Actions == 0) - return; - - if (is->tile_highlight_state == IS_UNINITED) - init_tile_highlights (); - if (is->tile_highlight_state != IS_OK) - return; - - int worker_civ_id = selected_unit->Body.CivID; - if ((p_cities == NULL) || (p_cities->Cities == NULL)) - return; - - // Loop over all cities owned by this civ and tally their workable tiles - FOR_CITIES_OF (coi, worker_civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - - // Highlight city center so players can easily see which cities contribute - Tile * city_center_tile = tile_at (city->Body.X, city->Body.Y); - if ((city_center_tile != NULL) && (city_center_tile != p_null_tile)) { - int stored_ptr; - if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, &stored_ptr)) { - struct highlighted_city_radius_tile_info * info = malloc (sizeof (struct highlighted_city_radius_tile_info)); - info->highlight_level = 0; - itable_insert (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, (int)info); - } - } - - // Add all workable tiles around the city (excluding city center) - for (int n = 1; n < is->workable_tile_count; n++) { - int dx, dy; - patch_ni_to_diff_for_work_area (n, &dx, &dy); - int tile_x = city->Body.X + dx; - int tile_y = city->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - - Tile * workable_tile = tile_at (tile_x, tile_y); - if ((workable_tile == NULL) || (workable_tile == p_null_tile)) continue; - if (workable_tile->vtable->m38_Get_Territory_OwnerID (workable_tile) != worker_civ_id) continue; - - // Upsert into highlighted_city_radius_tile_pointers - int stored_ptr; - struct highlighted_city_radius_tile_info * info; - if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, &stored_ptr)) { - info = malloc (sizeof (struct highlighted_city_radius_tile_info)); - info->highlight_level = 0; - itable_insert (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, (int)info); - } else { - info = (struct highlighted_city_radius_tile_info *)stored_ptr; - info->highlight_level += 3; - } - } - } -} - -void -set_up_district_buttons (Main_GUI * this) -{ - if (is_online_game () || ! is->current_config.enable_districts) return; - if (is->dc_btn_img_state == IS_UNINITED) init_district_command_buttons (); - if (is->dc_btn_img_state != IS_OK) return; - - Unit * selected_unit = p_main_screen_form->Current_Unit; - if (selected_unit == NULL || ! is_worker(selected_unit)) return; - - Tile * tile = tile_at (selected_unit->Body.X, selected_unit->Body.Y); - if ((tile == NULL) || (tile == p_null_tile) || (tile->CityID >= 0)) return; - - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - if (tile->vtable->m21_Check_Crates (tile, __, 0)) return; - if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return; - - Command_Button * fortify_button = NULL; - int i_starting_button; - int mine_turns = -1; - for (int n = 0; n < 42; n++) { - if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && - (this->Unit_Command_Buttons[n].Command == UCV_Fortify)) { - fortify_button = &this->Unit_Command_Buttons[n]; - i_starting_button = n; - } - if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { - mine_turns = parse_turns_from_tooltip (this->Unit_Command_Buttons[n].Button.ToolTip); - } - if (fortify_button != NULL && mine_turns >= 0) - break; - } - - if (fortify_button == NULL) - return; - - i_starting_button = -1; - - // Check if there's already a district on this tile. If so, and the unit can build mines, - // ensure the mine button is enabled so the worker can continue construction. - int existing_district_id = -1; - struct district_instance * existing_inst = get_district_instance (tile); - if (existing_inst != NULL) { - existing_district_id = existing_inst->district_id; - if (is->current_config.enable_natural_wonders && existing_inst->district_id == NATURAL_WONDER_DISTRICT_ID) { - return; - } - if (patch_Unit_can_perform_command(selected_unit, __, UCV_Build_Mine)) { - for (int n = 0; n < 42; n++) { - if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { - Command_Button * mine_button = &this->Unit_Command_Buttons[n]; - if (base_type == SQ_Coast) { - mine_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&mine_button->Button); - break; - } - if ((mine_button->Button.Base_Data.Status2 & 1) == 0) { - mine_button->Button.field_5FC[13] = 0; - mine_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&mine_button->Button, __, 0); - } - break; - } - } - } - } - - bool district_completed = district_is_complete (tile, existing_district_id); - - // First pass: collect which district types should be shown - int active_districts[COUNT_DISTRICT_TYPES]; - int active_count = 0; - - for (int dc = 0; dc < is->district_count; dc++) { - - if (is->district_configs[dc].command == -1) - continue; - - bool already_building = false; - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if (unit != NULL && is_worker(unit) && existing_inst != NULL && existing_inst->district_id == dc) { - // If there's a worker on the tile and it's building this district, - // show the button so more workers can contribute. This works around an - // issue where a specific district requiring irrigation no longer - // is buildable by other workers because initial construction removes the - // required irrigation overlay upon construction start - already_building = true; - break; - } - } - - if (existing_district_id == dc && district_completed) continue; - if ((existing_district_id >= 0) && (existing_district_id != dc) && (! district_completed)) continue; - - if (! can_build_district_on_tile (tile, dc, selected_unit->Body.CivID) && ! already_building) - continue; - - // This district should be shown - active_districts[active_count++] = dc; - } - - - if (active_count == 0) - return; - - // Calculate centered starting position - // For odd counts, center perfectly; for even counts, favor left of center - int center_pos = 6; - i_starting_button = center_pos - (active_count / 2); - if (i_starting_button < 0) - i_starting_button = 0; - - // Second pass: render the buttons - for (int idx = 0; idx < active_count; idx++) { - int dc = active_districts[idx]; - - Command_Button * free_button = NULL; - for (int n = i_starting_button; n < 42; n++) { - if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { - free_button = &this->Unit_Command_Buttons[n]; - i_starting_button = n + 1; - break; - } - } - - if (free_button == NULL) - return; - - // Set up free button for creating district - free_button->Command = is->district_configs[dc].command; - - // Replace the button's image with the district image. Disabling & re-enabling and - // clearing field_5FC[13] are all necessary to trigger a redraw. - free_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&free_button->Button); - free_button->field_6D8 = fortify_button->field_6D8; - for (int k = 0; k < 4; k++) - free_button->Button.Images[k] = &is->district_btn_img_sets[dc].imgs[k]; - free_button->Button.field_664 = fortify_button->Button.field_664; - if (mine_turns >= 0) { - char tooltip[256]; - char const * turn_word = (mine_turns == 1) ? "turn" : "turns"; - snprintf (tooltip, sizeof tooltip, "%s (%d %s)", is->district_configs[dc].tooltip, mine_turns, turn_word); - tooltip[(sizeof tooltip) - 1] = '\0'; - Button_set_tooltip (&free_button->Button, __, tooltip); - } else - Button_set_tooltip (&free_button->Button, __, (char *)is->district_configs[dc].tooltip); - free_button->Button.field_5FC[13] = 0; - free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); - } -} - -void -set_up_stack_worker_buttons (Main_GUI * this) -{ - if ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // (control key is not down OR - (! is->current_config.enable_stack_unit_commands) || // stack worker commands not enabled OR - is_online_game ()) // is online game - return; - - init_stackable_command_buttons (); - if (is->sc_img_state != IS_OK) - return; - - // For each unit command button - for (int n = 0; n < 42; n++) { - Command_Button * cb = &this->Unit_Command_Buttons[n]; - - // If it's enabled and not a bombard button (those are handled in the function above) - if (((cb->Button.Base_Data.Status2 & 1) != 0) && - (cb->Command != UCV_Bombard) && (cb->Command != UCV_Bombing)) { - - // Find the stackable worker command that this button controls, if there is one, and check that - // the button isn't already showing the stack image for that command. Note: this check is important - // b/c this function gets called repeatedly while the CTRL key is held down. - for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) - if ((cb->Command == sc_button_infos[sc].command) && - (cb->Button.Images[0] != &is->sc_button_image_sets[sc].imgs[0])) { - - // Replace the button's image with the stack image. Disabling & re-enabling and - // clearing field_5FC[13] are all necessary to trigger a redraw. - cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); - for (int k = 0; k < 4; k++) - cb->Button.Images[k] = &is->sc_button_image_sets[sc].imgs[k]; - cb->Button.field_5FC[13] = 0; - cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); - - break; - } - } - } -} - -CityLocValidity __fastcall patch_Map_check_city_location (Map * this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile); - -void __fastcall -patch_Main_GUI_set_up_unit_command_buttons (Main_GUI * this) -{ - // Recompute resources now if needed because of a trade deal involving mill inputs. In rare cases the change in deals might affect a mill that - // produces a resource that's used for a worker job. - recompute_resources_if_necessary (); - - Main_GUI_set_up_unit_command_buttons (this); - set_up_stack_bombard_buttons (this); - set_up_stack_worker_buttons (this); - - if (is->current_config.enable_districts) { - set_up_district_buttons (this); - } - - // If the minimum city separation is increased, then gray out the found city button if we're too close to another city. - if ((is->current_config.minimum_city_separation > 1) && (p_main_screen_form->Current_Unit != NULL) && (is->disabled_command_img_state == IS_OK)) { - Unit_Body * selected_unit = &p_main_screen_form->Current_Unit->Body; - - // For each unit command button - for (int n = 0; n < 42; n++) { - Command_Button * cb = &this->Unit_Command_Buttons[n]; - - // If it's enabled, set to city founding, and the current city location is too close to another city - if (((cb->Button.Base_Data.Status2 & 1) != 0) && - (cb->Command == UCV_Build_City) && - (patch_Map_check_city_location (&p_bic_data->Map, __, selected_unit->X, selected_unit->Y, selected_unit->CivID, false) == CLV_CITY_TOO_CLOSE)) { - - // Replace the button's image with the disabled image, as in set_up_stack_worker_buttons. - cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); - for (int k = 0; k < 3; k++) - cb->Button.Images[k] = &is->disabled_build_city_button_img; - cb->Button.field_5FC[13] = 0; - - char tooltip[200]; { - memset (tooltip, 0, sizeof tooltip); - char * label = is->c3x_labels[CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP], - * to_replace = "$NUM0", - * replace_location = strstr (label, to_replace); - if (replace_location != NULL) - snprintf (tooltip, sizeof tooltip, "%.*s%d%s", replace_location - label, label, is->current_config.minimum_city_separation, replace_location + strlen (to_replace)); - else - snprintf (tooltip, sizeof tooltip, "%s", label); - tooltip[(sizeof tooltip) - 1] = '\0'; - } - Button_set_tooltip (&cb->Button, __, tooltip); - - cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); - - } - } - } -} - -void -clear_highlighted_worker_tiles_and_redraw () -{ - clear_highlighted_worker_tiles_for_districts (); - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -void -check_happiness_at_end_of_turn () -{ - int num_unhappy_cities = 0; - City * first_unhappy_city = NULL; - FOR_CITIES_OF (coi, p_main_screen_form->Player_CivID) { - City_recompute_happiness (coi.city); - int num_happy = 0, num_unhappy = 0; - FOR_CITIZENS_IN (ci, coi.city) { - num_happy += ci.ctzn->Body.Mood == CMT_Happy; - num_unhappy += ci.ctzn->Body.Mood == CMT_Unhappy; - } - if (num_unhappy > num_happy) { - num_unhappy_cities++; - if (first_unhappy_city == NULL) - first_unhappy_city = coi.city; - } - } - - if (first_unhappy_city != NULL) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, first_unhappy_city->Body.CityName, -1, -1); - if (num_unhappy_cities > 1) - set_popup_int_param (1, num_unhappy_cities - 1); - char * key = (num_unhappy_cities > 1) ? "C3X_DISORDER_WARNING_MULTIPLE" : "C3X_DISORDER_WARNING_ONE"; - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, key, -1, 0, 0, 0); - int response = patch_show_popup (popup, __, 0, 0); - - if (response == 2) { // zoom to city - p_main_screen_form->turn_end_flag = 1; - City_zoom_to (first_unhappy_city, __, 0); - } else if (response == 1) // just cancel turn end - p_main_screen_form->turn_end_flag = 1; - // else do nothing, let turn end - - } -} - -void -do_trade_scroll (DiploForm * diplo, int forward) -{ - int increment = forward ? 1 : -1; - int id = -1; - for (int n = (diplo->other_party_civ_id + increment) & 31; n != diplo->other_party_civ_id; n = (n + increment) & 31) - if ((n != 0) && // if N is not barbs AND - (n != p_main_screen_form->Player_CivID) && // N is not the player's AND - (*p_player_bits & (1U << n)) && // N belongs to an active player AND - (leaders[p_main_screen_form->Player_CivID].Contacts[n] & 1) && // N has contact with the player AND - Leader_ai_would_meet_with (&leaders[n], __, p_main_screen_form->Player_CivID)) { // AI is willing to meet - id = n; - break; - } - - if (id >= 0) { - is->trade_screen_scroll_to_id = id; - DiploForm_close (diplo); - // Note extra code needs to get run here if the other player is not an AI - } -} - -void __fastcall -patch_DiploForm_m82_handle_key_event (DiploForm * this, int edx, int virtual_key_code, int is_down) -{ - if (is->eligible_for_trade_scroll && - (this->mode == 2) && - ((virtual_key_code == VK_LEFT) || (virtual_key_code == VK_RIGHT)) && - (! is_down)) - do_trade_scroll (this, virtual_key_code == VK_RIGHT); - else - DiploForm_m82_handle_key_event (this, __, virtual_key_code, is_down); -} - -int __fastcall -patch_DiploForm_m68_Show_Dialog (DiploForm * this, int edx, int param_1, void * param_2, void * param_3) -{ - if (is->open_diplo_form_straight_to_trade) { - is->open_diplo_form_straight_to_trade = 0; - - // Done by the base game but not necessary as far as I can tell - // void (__cdecl * FUN_00537700) (int) = 0x537700; - // FUN_00537700 (0x15); - // this->field_E9C[0] = this->field_E9C[0] + 1; - - // Set diplo screen mode to two-way trade negotation - this->mode = 2; - - // Set AI's diplo message to something like "what did you have in mind" - int iVar35 = DiploForm_set_their_message (this, __, DM_AI_PROPOSAL_RESPONSE, 0, 0x1A8); - this->field_1390[0] = DM_AI_PROPOSAL_RESPONSE; - this->field_1390[1] = 0; - this->field_1390[2] = iVar35; - - // Reset player message options. This will replace the propose deal, declare war, and leave options with the usual "nevermind" option - // that appears for negotiations. - DiploForm_reset_our_message_choices (this); - - // Done by the base game but not necessary as far as I can tell - // void (__fastcall * FUN_004C89A0) (void *) = 0x4C89A0; - // FUN_004C89A0 (&this->field_1BF4[0]); - - } - - return DiploForm_m68_Show_Dialog (this, __, param_1, param_2, param_3); -} - -void __fastcall -patch_DiploForm_do_diplomacy (DiploForm * this, int edx, int diplo_message, int param_2, int civ_id, int do_not_request_audience, int war_negotiation, int disallow_proposal, TradeOfferList * our_offers, TradeOfferList * their_offers) -{ - is->open_diplo_form_straight_to_trade = 0; - is->trade_screen_scroll_to_id = -1; - - // Trade screen scroll is disabled in online games b/c there's extra synchronization we'd need to do to open or close the diplo screen with - // a human player. - is->eligible_for_trade_scroll = is->current_config.enable_trade_screen_scroll && (! is_online_game ()); - - if (is->eligible_for_trade_scroll && (is->trade_scroll_button_state == IS_UNINITED)) - init_trade_scroll_buttons (this); - - WITH_PAUSE_FOR_POPUP { - DiploForm_do_diplomacy (this, __, diplo_message, param_2, civ_id, do_not_request_audience, war_negotiation, disallow_proposal, our_offers, their_offers); - - while (is->trade_screen_scroll_to_id >= 0) { - int scroll_to_id = is->trade_screen_scroll_to_id; - is->trade_screen_scroll_to_id = -1; - is->open_diplo_form_straight_to_trade = 1; - DiploForm_do_diplomacy (this, __, DM_AI_COUNTER, 0, scroll_to_id, 1, 0, 0, NULL, NULL); - } - } - - is->open_diplo_form_straight_to_trade = 0; - is->eligible_for_trade_scroll = 0; -} - -void __fastcall -patch_DiploForm_m22_Draw (DiploForm * this) -{ - if (is->trade_scroll_button_state == IS_OK) { - Button * left = is->trade_scroll_button_left, - * right = is->trade_scroll_button_right; - if (is->eligible_for_trade_scroll && (this->mode == 2)) { - left ->vtable->m01_Show_Enabled ((Base_Form *)left , __, 0); - right->vtable->m01_Show_Enabled ((Base_Form *)right, __, 0); - left ->vtable->m73_call_m22_Draw ((Base_Form *)left); - right->vtable->m73_call_m22_Draw ((Base_Form *)right); - } else { - left ->vtable->m02_Show_Disabled ((Base_Form *)left); - right->vtable->m02_Show_Disabled ((Base_Form *)right); - } - } - - DiploForm_m22_Draw (this); -} - -void -intercept_end_of_turn () -{ - if (is->current_config.enable_disorder_warning) { - check_happiness_at_end_of_turn (); - if (p_main_screen_form->turn_end_flag == 1) // Check if player cancelled turn ending in the disorder warning popup - return; - } - - // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - - if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { - is->city_loc_display_perspective = -1; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw - } - - // Clear things that don't apply across turns - is->have_job_and_loc_to_skip = 0; -} - -bool -is_worker_or_settler_command (int unit_command_value) -{ - return (unit_command_value & 0x20000000) || - ((unit_command_value >= UCV_Build_Remote_Colony) && (unit_command_value <= UCV_Auto_Save_Tiles)); -} - -bool -command_would_replace_district (int unit_command_value) -{ - // Note: Roads & railroads, etc. can coexist with the district - return (unit_command_value == UCV_Build_Mine) || - (unit_command_value == UCV_Irrigate) || - (unit_command_value == UCV_Plant_Forest) || - (unit_command_value == UCV_Build_Outpost) || - (unit_command_value == UCV_Build_Fortress) || - (unit_command_value == UCV_Build_Barricade) || - (unit_command_value == UCV_Build_Airfield) || - (unit_command_value == UCV_Build_Radar_Tower) || - (unit_command_value == UCV_Build_Colony); -} - -bool -handle_worker_command_that_may_replace_district (Unit * unit, int unit_command_value, bool * removed_existing) -{ - if (removed_existing != NULL) - *removed_existing = false; - - if ((! is->current_config.enable_districts) || (unit == NULL)) return true; - if (! is_worker_or_settler_command (unit_command_value)) return true; - if (! command_would_replace_district (unit_command_value)) return true; - if (! patch_Unit_can_perform_command (unit, __, unit_command_value)) return true; - - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - if ((tile == NULL) || (tile == p_null_tile)) - return true; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (! district_is_complete (tile, inst->district_id))) - return true; - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) - return false; - - int district_id = inst->district_id; - int civ_id = unit->Body.CivID; - bool redundant_district = district_instance_is_redundant (inst, tile); - bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (district_id, civ_id, tile_x, tile_y); - if (redundant_district) - would_lose_buildings = false; - - bool remove_existing = redundant_district; - if (inst != NULL && district_id >= 0 && district_id < is->district_count) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char *)is->district_configs[district_id].display_name, -1, -1); - set_popup_str_param (1, (char *)is->district_configs[district_id].display_name, -1, -1); - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - would_lose_buildings - ? "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT" - : "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT_SAFE", - -1, 0, 0, 0); - int sel = patch_show_popup (popup, __, 0, 0); - if (sel != 0) - return false; - remove_existing = true; - } - - if (remove_existing) { - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - handle_district_removed (tile, district_id, tile_x, tile_y, false); - if (removed_existing != NULL) - *removed_existing = true; - } - - return true; -} - -bool __fastcall - patch_Unit_can_upgrade (Unit * this) -{ - bool base = Unit_can_upgrade (this); - int available; - City * city = city_at (this->Body.X, this->Body.Y); - if (base && - (city != NULL) && - get_available_unit_count (&leaders[this->Body.CivID], City_get_upgraded_type_id (city, __, this->Body.UnitTypeID), &available) && - (available <= 0)) - return false; - else - return base; -} - -bool -is_district_command (int unit_command_value) -{ - int district_id = -1; - if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) - return false; - - return district_id != NATURAL_WONDER_DISTRICT_ID; -} - -int __fastcall -patch_Map_check_colony_location (Map * this, int edx, int tile_x, int tile_y, int civ_id) -{ - int base = Map_check_colony_location (this, __, tile_x, tile_y, civ_id); - Tile * tile = tile_at (tile_x, tile_y); - - if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.allow_extraterritorial_colonies) - return base; - - if (tile->vtable->m35_Check_Is_Water (tile)) return base; - if (Tile_has_city (tile) || Tile_has_colony (tile)) return base; - - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_id < 0) || (owner_id == civ_id)) return base; - - int resource_type = Tile_get_resource_visible_to (tile, __, civ_id); - if ((resource_type < 0) || (resource_type >= p_bic_data->ResourceTypeCount)) return base; - - int req_tech = p_bic_data->ResourceTypes[resource_type].RequireID; - if ((req_tech >= 0) && (! Leader_has_tech (&leaders[civ_id], __, req_tech))) return base; - - int res_class = p_bic_data->ResourceTypes[resource_type].Class; - if ((res_class != RC_Strategic) && (res_class != RC_Luxury)) return base; - if (tile->vtable->m26_Check_Tile_Building (tile)) - return 6; - - return 0; -} - -bool __fastcall -patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value) -{ - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - // No worker or settler commands allowed on natural wonders - if ((tile != NULL) && (tile != p_null_tile) && is->current_config.enable_natural_wonders) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && - (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) { - if (is_worker_or_settler_command (unit_command_value) || is_district_command (unit_command_value)) - return false; - } - } - - if (is_district_command (unit_command_value)) { - int district_id; - if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) - return false; - - return is_worker (this) && can_build_district_on_tile (tile, district_id, this->Body.CivID); - } - // Extra check for colony founding if extraterritorial colonies allowed - else if (unit_command_value == UCV_Build_Colony || unit_command_value == UCV_Build_Remote_Colony) { - if (is->current_config.allow_extraterritorial_colonies && is_worker (this)) { - return patch_Map_check_colony_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID) == 0; - } - } - // Extra check for road building if bridge districts allowed - else if (unit_command_value == UCV_Build_Road) { - struct district_instance * inst = get_district_instance (tile); - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - if (!has_road && (inst != NULL) && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) - return true; - } - // Extra check for railroad building if bridge districts allowed - else if (unit_command_value == UCV_Build_Railroad) { - struct district_instance * inst = get_district_instance (tile); - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; - if ((inst != NULL) && is_worker (this) && has_road && - ! has_rail && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) { - int req_tech = p_bic_data->WorkerJobs[WJ_Build_Railroad].RequireID; - if ((req_tech < 0) || - ((req_tech != p_bic_data->AdvanceCount) && - Leader_has_tech (&leaders[this->Body.CivID], __, req_tech))) { - if (Leader_has_resources_for_job_at (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y)) - return true; - } - } - } - else if (unit_command_value == UCV_Build_Mine) { - bool has_district = (tile != NULL) && (tile != p_null_tile) && (get_district_instance (tile) != NULL); - - if (has_district) { - return Tile_get_mining_bonus (tile) > 0; - } - } else if (unit_command_value == UCV_Pillage) { - return patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y); - } - } - if (is->current_config.disable_worker_automation && - (this->Body.CivID == p_main_screen_form->Player_CivID) && - (unit_command_value == UCV_Automate)) - return false; - else if (is->current_config.disallow_land_units_from_affecting_water_tiles && - is_worker_or_settler_command (unit_command_value)) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - enum UnitTypeClasses class = p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class; - return ((class != UTC_Land) || (! tile->vtable->m35_Check_Is_Water (tile))) && - Unit_can_perform_command (this, __, unit_command_value); - } - - return Unit_can_perform_command (this, __, unit_command_value); -} - -void __fastcall -patch_Unit_join_city (Unit * this, int edx, City * city) -{ - if (is->current_config.enable_districts && is_worker (this)) { - int civ_id = this->Body.CivID; - bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; - if (! is_human) { - struct district_worker_record * rec = get_tracked_worker_record (this); - if ((rec != NULL) && (rec->pending_req != NULL)) { - ai_move_district_worker (this, rec); - return; - } - - Tile * worker_tile = tile_at (this->Body.X, this->Body.Y); - if ((worker_tile != NULL) && (worker_tile != p_null_tile)) { - int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); - - if ((civ_id >= 0) && (civ_id < 32)) { - struct pending_district_request * same_city_req = NULL; - struct pending_district_request * same_continent_req = NULL; - - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req == NULL) || (req->assigned_worker_id >= 0)) - continue; - if ((req->civ_id != civ_id) || (req->city_id < 0)) - continue; - - City * req_city = get_city_ptr (req->city_id); - if (req_city == NULL) - continue; - - if (city != NULL && req_city->Body.ID == city->Body.ID) { - same_city_req = req; - break; - } - - Tile * req_city_tile = tile_at (req_city->Body.X, req_city->Body.Y); - if ((req_city_tile != NULL) && (req_city_tile != p_null_tile)) { - int req_continent_id = req_city_tile->vtable->m46_Get_ContinentID (req_city_tile); - if (req_continent_id == worker_continent_id) { - same_continent_req = req; - } - } - } - - struct pending_district_request * chosen_req = (same_city_req != NULL) ? same_city_req : same_continent_req; - if (chosen_req != NULL) { - City * req_city = get_city_ptr (chosen_req->city_id); - if (req_city != NULL) { - int target_x = 0; - int target_y = 0; - Tile * target_tile = find_tile_for_district (req_city, chosen_req->district_id, &target_x, &target_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); - assign_worker_to_district (chosen_req, this, req_city, chosen_req->district_id, target_x, target_y); - return; - } - } - } - } - } - } - } - - Unit_join_city (this, __, city); -} - -bool __fastcall -patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y) -{ - bool base = Unit_can_pillage (this, __, tile_x, tile_y); - - if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return base; - - int district_id = inst->district_id; - if (is->current_config.enable_natural_wonders && - (district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) - return false; - - if (! district_is_complete (tile, district_id)) - return true; - - if (district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info == NULL || info->state != WDS_COMPLETED) - return true; - return is->current_config.completed_wonder_districts_can_be_destroyed; - } - - return true; -} - -bool __fastcall -patch_Unit_can_do_worker_command_for_button_setup (Unit * this, int edx, int unit_command_value) -{ - bool base = patch_Unit_can_perform_command (this, __, unit_command_value); - - // If the command is to build a city and it can't be done because another city is already too close, and the minimum separation was changed - // from its standard value, then return true here so that the build city button will be added anyway. We'll gray it out later. Check that the - // grayed out button image is initialized now so we don't activate the build city button then find out later we can't gray it out. - if ((! base) && - (unit_command_value == UCV_Build_City) && - (is->current_config.minimum_city_separation > 1) && - (patch_Map_check_city_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID, false) == CLV_CITY_TOO_CLOSE) && - (init_disabled_command_buttons (), is->disabled_command_img_state == IS_OK)) - return true; - - else - return base; -} - -int -compare_helpers (void const * vp_a, void const * vp_b) -{ - Unit * a = get_unit_ptr (*(int *)vp_a), - * b = get_unit_ptr (*(int *)vp_b); - if ((a != NULL) && (b != NULL)) { - // Compute how many movement points each has left (ML = moves left) - int ml_a = patch_Unit_get_max_move_points (a) - a->Body.Moves, - ml_b = patch_Unit_get_max_move_points (b) - b->Body.Moves; - - // Whichever one has more MP left comes first in the array - if (ml_a > ml_b) return 1; - else if (ml_b > ml_a) return -1; - else return 0; - } else - // If at least one of the unit ids is invalid, might as well sort it later in the array - return (a != NULL) ? -1 : ((b != NULL) ? 1 : 0); -} - -void -issue_stack_worker_command (Unit * unit, int command) -{ - int tile_x = unit->Body.X; - int tile_y = unit->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - int unit_type_id = unit->Body.UnitTypeID; - int unit_id = unit->Body.ID; - - // Put together a list of helpers and store it on the memo. Helpers are just other workers on the same tile that can be issued the same command. - clear_memo (); - FOR_UNITS_ON (uti, tile) - if ((uti.id != unit_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) { - // check if the clicked command is among worker actions that this unit type can perform - int actions = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Worker_Actions; - int command_without_category = command & 0x0FFFFFFF; - if ((actions & command_without_category) == command_without_category) - memoize (uti.id); - } - - // Sort the list of helpers so that the ones with the fewest remaining movement points are listed first. - qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_helpers); - - Unit * next_up = unit; - int i_next_helper = 0; - int last_action_didnt_happen; - do { - int state_before_action = next_up->Body.UnitState; - Main_Screen_Form_issue_command (p_main_screen_form, __, command, next_up); - last_action_didnt_happen = (next_up->Body.UnitState == state_before_action); - - // Call this update function to cause the worker to actually perform the action. Otherwise - // it only gets queued, the worker keeps is movement points, and the action doesn't get done - // until the interturn. - if (! last_action_didnt_happen) - next_up->vtable->update_while_active (next_up); - - next_up = NULL; - while ((i_next_helper < is->memo_len) && (next_up == NULL)) - next_up = get_unit_ptr (is->memo[i_next_helper++]); - } while ((next_up != NULL) && (! last_action_didnt_happen)); -} - -void -issue_district_worker_command (Unit * unit, int command) -{ - if (! is->current_config.enable_districts) - return; - - if (unit == NULL) - return; - - int tile_x = unit->Body.X; - int tile_y = unit->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return; - - if (! is_worker(unit)) - return; - - int district_id = -1; - if (! itable_look_up (&is->command_id_to_district_id, command, &district_id)) - return; - if ((district_id < 0) || (district_id >= is->district_count)) - return; - - if (! leader_can_build_district (&leaders[unit->Body.CivID], district_id)) - return; - - // Disallow placing districts on invalid terrain, pollution, or cratered tiles - if (tile->vtable->m21_Check_Crates (tile, __, 0)) - return; - if (tile->vtable->m20_Check_Pollution (tile, __, 0)) - return; - - if (! district_is_buildable_on_tile (&is->district_configs[district_id], tile)) - return; - - // If District will be replaced by another District - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete(tile, inst->district_id)) { - int existing_district_id = inst->district_id; - int inst_x, inst_y; - if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) - return; - - int civ_id = unit->Body.CivID; - bool redundant_district = district_instance_is_redundant (inst, tile); - bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, inst_x, inst_y); - if (redundant_district) - would_lose_buildings = false; - - bool remove_existing = false; - - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char*)is->district_configs[existing_district_id].display_name, -1, -1); - set_popup_str_param (1, (char*)is->district_configs[existing_district_id].display_name, -1, -1); - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - would_lose_buildings - ? "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT" - : "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT_SAFE", - -1, 0, 0, 0 - ); - - int sel = patch_show_popup (popup, __, 0, 0); - if (sel == 0) - remove_existing = true; - else - return; - - if (remove_existing) { - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); - handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); - } - } - - // If District will replace an improvement - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); - - if (removable_flags != 0) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_BUILD_DISTRICT_OVER_IMPROVEMENT", -1, 0, 0, 0); - int sel = patch_show_popup (popup, __, 0, 0); - if (sel != 0) - return; - } - - if (removable_flags != 0) - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - - inst = ensure_district_instance (tile, district_id, tile_x, tile_y); - inst->built_by_civ_id = unit->Body.CivID; - if (inst != NULL) - inst->state = DS_UNDER_CONSTRUCTION; - - Unit_set_state (unit, __, UnitState_Build_Mines); - unit->Body.Job_ID = WJ_Build_Mines; -} - -void -issue_stack_unit_mgmt_command (Unit * unit, int command) -{ - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - int unit_type_id = unit->Body.UnitTypeID; - int unit_id = unit->Body.ID; - - PopupForm * popup = get_popup_form (); - - clear_memo (); - - if (command == UCV_Fortify) { - // This probably won't work for online games since "fortify all" does additional work in that case. See Main_Screen_Form::fortify_all. - // I don't like how this method doesn't place units in the fortified pose. One workaround is so use - // Main_Screen_Form::issue_fortify_command, but that plays the entire fortify animation for each unit which is a major annoyance for - // large stacks. The base game's "fortify all" function also doesn't set the pose so I don't see any easy way to fix this. - FOR_UNITS_ON (uti, tile) - if ((uti.unit->Body.UnitTypeID == unit_type_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - (uti.unit->Body.CivID == unit->Body.CivID) && - (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) - Unit_set_state (uti.unit, __, UnitState_Fortifying); - - } else if (command == UCV_Upgrade_Unit) { - int our_treasury = leaders[unit->Body.CivID].Gold_Encoded + leaders[unit->Body.CivID].Gold_Decrement; - - // If the unit type we're upgrading to is limited, find out how many we can add. Keep that in "available". If the type is not limited, - // leave available set to INT_MAX. - int available = INT_MAX; { - City * city; - int upgrade_id; - if ((is->current_config.unit_limits.len > 0) && - patch_Unit_can_perform_command (unit, __, UCV_Upgrade_Unit) && - (NULL != (city = city_at (unit->Body.X, unit->Body.Y))) && - (0 < (upgrade_id = City_get_upgraded_type_id (city, __, unit_type_id)))) - get_available_unit_count (&leaders[unit->Body.CivID], upgrade_id, &available); - } - - int cost = 0; - FOR_UNITS_ON (uti, tile) - if ((available > 0) && - (uti.unit->Body.UnitTypeID == unit_type_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - patch_Unit_can_perform_command (uti.unit, __, UCV_Upgrade_Unit)) { - cost += Unit_get_upgrade_cost (uti.unit); - available--; - memoize (uti.id); - } - - if (cost <= our_treasury) { - set_popup_str_param (0, p_bic_data->UnitTypes[unit_type_id].Name, -1, -1); - set_popup_int_param (0, is->memo_len); - set_popup_int_param (1, cost); - popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "UPGRADE_ALL", -1, 0, 0, 0); - if (patch_show_popup (popup, __, 0, 0) == 0) - for (int n = 0; n < is->memo_len; n++) { - Unit * to_upgrade = get_unit_ptr (is->memo[n]); - if (to_upgrade != NULL) - Unit_upgrade (to_upgrade, __, false); - } - - } else { - set_popup_int_param (0, cost); - int param_5 = is_online_game () ? 0x4000 : 0; // As in base code - popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "NO_GOLD_TO_UPGRADE_ALL", -1, 0, param_5, 0); - patch_show_popup (popup, __, 0, 0); - } - - } else if (command == UCV_Disband) { - FOR_UNITS_ON (uti, tile) - if ((uti.unit->Body.UnitTypeID == unit_type_id) && - (uti.unit->Body.Container_Unit < 0) && - (uti.unit->Body.UnitState == 0) && - (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) - memoize (uti.id); - - if (is->memo_len > 0) { - set_popup_int_param (0, is->memo_len); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_STACK_DISBAND", -1, 0, 0, 0); - if (patch_show_popup (popup, __, 0, 0) == 0) { - for (int n = 0; n < is->memo_len; n++) { - Unit * to_disband = get_unit_ptr (is->memo[n]); - if (to_disband) - Unit_disband (to_disband); - } - } - } - } -} - -void __fastcall -patch_Main_GUI_handle_button_press (Main_GUI * this, int edx, int button_id) -{ - // Set SB flag according to case (2) - if (button_id < 42) { - if ((is->sc_img_state == IS_OK) && - ((this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMBARD].imgs[0]) || - (this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMB ].imgs[0]))) - is->sb_activated_by_button = 1; - else - is->sb_activated_by_button = 0; - } - - int command = this->Unit_Command_Buttons[button_id].Command; - - // Clear any highlighted tiles - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - - if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { - is->city_loc_display_perspective = -1; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw - } - - // If a district, run district build logic - if (is->current_config.enable_districts && is_district_command (command)) { - clear_something_1 (); - Timer_clear (&this->timer_1); - issue_district_worker_command (p_main_screen_form->Current_Unit, command); - return; - } - - // Check if command is a worker build command (not a district) and a district exists on the tile - if (is->current_config.enable_districts && p_main_screen_form->Current_Unit != NULL) { - - bool removed_existing = false; - if (! handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) - return; - if (removed_existing) { - clear_something_1 (); - Timer_clear (&this->timer_1); - Main_GUI_handle_button_press (this, __, button_id); - return; - } - } - - struct sc_button_info const * stack_button_info; { - stack_button_info = NULL; - if (button_id < 42) // If button pressed was a unit command button - for (int n = 0; n < COUNT_STACKABLE_COMMANDS; n++) - if (command == sc_button_infos[n].command) { - stack_button_info = &sc_button_infos[n]; - break; - } - } - - if ((stack_button_info == NULL) || // If there's no stack command for the pressed button OR - (! is->current_config.enable_stack_unit_commands) || // stack unit commands are not enabled OR - (((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // CTRL key is not down OR - (p_main_screen_form->Current_Unit == NULL) || // no unit is selected OR - is_online_game ()) { // is online game - Main_GUI_handle_button_press (this, __, button_id); - return; - } - - enum stackable_command_kind kind = stack_button_info->kind; - if ((kind == SCK_TERRAFORM) || (kind == SCK_UNIT_MGMT)) { - // Replicate behavior of function we're replacing - clear_something_1 (); - Timer_clear (&this->timer_1); - - if (kind == SCK_TERRAFORM) - issue_stack_worker_command (p_main_screen_form->Current_Unit, stack_button_info->command); - else if (kind == SCK_UNIT_MGMT) - issue_stack_unit_mgmt_command (p_main_screen_form->Current_Unit, stack_button_info->command); - } else - Main_GUI_handle_button_press (this, __, button_id); -} - -bool __fastcall -patch_Main_Screen_Form_issue_command (Main_Screen_Form * this, int edx, int command, Unit * unit) -{ - Unit * target_unit = unit; - if (target_unit == NULL) - target_unit = this->Current_Unit; - - if (is->current_config.enable_districts) { - bool removed_existing = false; - if (! handle_worker_command_that_may_replace_district (target_unit, command, &removed_existing)) - return false; - } - - return Main_Screen_Form_issue_command (this, __, command, unit); -} - -bool -is_command_button_active (Main_GUI * main_gui, enum Unit_Command_Values command) -{ - Command_Button * buttons = main_gui->Unit_Command_Buttons; - for (int n = 0; n < 42; n++) - if (((buttons[n].Button.Base_Data.Status2 & 1) != 0) && (buttons[n].Command == command)) - return true; - return false; -} - -int __fastcall -patch_Main_Screen_Form_handle_key_down (Main_Screen_Form * this, int edx, int char_code, int virtual_key_code) -{ - // Set SB flag according to case (4) - int precision_strike_is_available = is_command_button_active (&this->GUI, UCV_Precision_Bombing); - if ((virtual_key_code == VK_B) || (precision_strike_is_available && (virtual_key_code == VK_P))) - is->sb_activated_by_button = 0; - - if ((virtual_key_code & 0xFF) == VK_CONTROL) { - set_up_stack_worker_buttons (&this->GUI); - - if (is->current_config.enable_city_work_radii_highlights && - ! is->highlight_city_radii) { - Unit * unit = p_main_screen_form->Current_Unit; - if (unit != NULL) { - is->highlight_city_radii = true; - compute_highlighted_worker_tiles_for_districts (); - this->vtable->m73_call_m22_Draw ((Base_Form *)this); - } - } - } else { - if (is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - } - - char original_turn_end_flag = this->turn_end_flag; - int tr = Main_Screen_Form_handle_key_down (this, __, char_code, virtual_key_code); - if ((original_turn_end_flag == 1) && (this->turn_end_flag == 0)) - intercept_end_of_turn (); - - return tr; -} - -int -patch_handle_cursor_change_in_jgl () -{ - // Set SB flag according to case (3) and the annoying state - if ((is->sb_activated_by_button != 2) && - (p_main_screen_form->Mode_Action != UMA_Bombard) && - (p_main_screen_form->Mode_Action != UMA_Air_Bombard)) - is->sb_activated_by_button = 0; - - return handle_cursor_change_in_jgl (); -} - -void __fastcall -patch_Main_Screen_Form_handle_left_click_on_map_1 (Main_Screen_Form * this, int edx, int param_1, int param_2) -{ - if (is->sb_activated_by_button == 1) - is->sb_activated_by_button = 2; - Main_Screen_Form_handle_left_click_on_map_1 (this, __, param_1, param_2); - is->sb_activated_by_button = 0; -} - - -void __fastcall -patch_Main_GUI_handle_click_in_status_panel (Main_GUI * this, int edx, int mouse_x, int mouse_y) -{ - char original_turn_end_flag = p_main_screen_form->turn_end_flag; - Main_GUI_handle_click_in_status_panel (this, __, mouse_x, mouse_y); - if ((original_turn_end_flag == 1) && (p_main_screen_form->turn_end_flag == 0)) - intercept_end_of_turn (); -} - -// Gets effective shields generated per turn, including civil engineers, disorder, and anarchy. -int -get_city_production_rate (City * city, enum City_Order_Types order_type, int order_id) -{ - int in_disorder = city->Body.Status & CSF_Civil_Disorder, - in_anarchy = p_bic_data->Governments[leaders[city->Body.CivID].GovernmentType].b_Transition_Type, - getting_tile_shields = (! in_disorder) && (! in_anarchy); - - if (order_type == COT_Improvement) { - int building_wealth = (p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0; - int specialist_shields = 0; - FOR_CITIZENS_IN (ci, city) - if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) // I don't know what is check is for but it's done in the base code - specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; - return (getting_tile_shields ? city->Body.ProductionIncome : 0) + ((! building_wealth) ? specialist_shields : 0); - } else if ((order_type == COT_Unit) && getting_tile_shields) - return city->Body.ProductionIncome; - else - return 0; -} - -void __fastcall -patch_City_Form_open (City_Form * this, int edx, City * city, int param_2) -{ - recompute_resources_if_necessary (); - - WITH_PAUSE_FOR_POPUP { - City_Form_open (this, __, city, param_2); - } -} - -void -init_district_icons () -{ - if (is->dc_icons_img_state != IS_UNINITED) - return; - - char ss[200]; - snprintf (ss, sizeof ss, "[C3X] init_district_icons: state=%d\n", is->dc_icons_img_state); - (*p_OutputDebugStringA) (ss); - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("Districts/DistrictIncomeIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image == NULL) || - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { - (*p_OutputDebugStringA) ("[C3X] PCX file for district icons failed to load or is too small.\n"); - is->dc_icons_img_state = IS_INIT_FAILED; - goto cleanup; - } - - // Extract science icon (index 1) - Sprite_construct (&is->district_science_icon); - Sprite_slice_pcx (&is->district_science_icon, __, &pcx, 1 + 1*31, 1, 30, 30, 1, 1); - - // Extract commerce icon (index 2) - Sprite_construct (&is->district_commerce_icon); - Sprite_slice_pcx (&is->district_commerce_icon, __, &pcx, 1 + 2*31, 1, 30, 30, 1, 1); - - // Extract shield icon (index 4) - Sprite_construct (&is->district_shield_icon); - Sprite_slice_pcx (&is->district_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); - - // Extract corruption icon (index 5) - Sprite_construct (&is->district_corruption_icon); - Sprite_slice_pcx (&is->district_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); - - // Extract food icon (index 6) - Sprite_construct (&is->district_food_icon); - Sprite_slice_pcx (&is->district_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); - - // Extract food eaten icon (index 7) - Sprite_construct (&is->district_food_eaten_icon); - Sprite_slice_pcx (&is->district_food_eaten_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); - - // Extract small happiness icon (index 12) - Sprite_construct (&is->district_happiness_icon_small); - Sprite_slice_pcx (&is->district_happiness_icon_small, __, &pcx, 1 + 12*31, 1, 30, 30, 1, 1); - - // Extract small shield icon (index 13) - Sprite_construct (&is->district_shield_icon_small); - Sprite_slice_pcx (&is->district_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); - - // Extract small commerce icon (index 14) - Sprite_construct (&is->district_commerce_icon_small); - Sprite_slice_pcx (&is->district_commerce_icon_small, __, &pcx, 1 + 14*31, 1, 30, 30, 1, 1); - - // Extract small food icon (index 15: x = 1 + 15*31 = 466, width 30) - Sprite_construct (&is->district_food_icon_small); - Sprite_slice_pcx (&is->district_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); - - // Extract small science icon (index 16) - Sprite_construct (&is->district_science_icon_small); - Sprite_slice_pcx (&is->district_science_icon_small, __, &pcx, 1 + 16*31, 1, 30, 30, 1, 1); - - // Extract small culture icon (index 18) - Sprite_construct (&is->district_culture_icon_small); - Sprite_slice_pcx (&is->district_culture_icon_small, __, &pcx, 1 + 18*31, 1, 30, 30, 1, 1); - - // Load Negatives (mostly red) from here - - // Extract negative small commerce icon (index 17) - Sprite_construct (&is->district_negative_commerce_icon_small); - Sprite_slice_pcx (&is->district_negative_commerce_icon_small, __, &pcx, 1 + 17*31, 1, 30, 30, 1, 1); - - // Extract small unhappiness icon (index 19) - Sprite_construct (&is->district_unhappiness_icon_small); - Sprite_slice_pcx (&is->district_unhappiness_icon_small, __, &pcx, 1 + 19*31, 1, 30, 30, 1, 1); - - // Extract negative small shield icon (index 20) - Sprite_construct (&is->district_negative_shield_icon_small); - Sprite_slice_pcx (&is->district_negative_shield_icon_small, __, &pcx, 1 + 20*31, 1, 30, 30, 1, 1); - - // Extract negative small culture icon (index 21) - Sprite_construct (&is->district_negative_culture_icon_small); - Sprite_slice_pcx (&is->district_negative_culture_icon_small, __, &pcx, 1 + 21*31, 1, 30, 30, 1, 1); - - // Extract negative small culture icon (index 22) - Sprite_construct (&is->district_negative_food_icon_small); - Sprite_slice_pcx (&is->district_negative_food_icon_small, __, &pcx, 1 + 22*31, 1, 30, 30, 1, 1); - - // Extract negative small science icon (index 23) - Sprite_construct (&is->district_negative_science_icon_small); - Sprite_slice_pcx (&is->district_negative_science_icon_small, __, &pcx, 1 + 23*31, 1, 30, 30, 1, 1); - - is->dc_icons_img_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void __fastcall -patch_City_Form_draw (City_Form * this) -{ - // Recompute city form production rect location every time because the config might have changed. Doing it here is also easier than - // patching the constructor. - int form_top = (p_bic_data->ScreenHeight - this->Background_Image.Height) / 2; - this->Production_Storage_Indicator.top = form_top + 621 + (is->current_config.show_detailed_city_production_info ? 34 : 0); - - is->drawn_strat_resource_count = 0; - - // Make sure culture income (including from districts) is up to date before the draw event - if (is->current_config.enable_districts) - patch_City_recompute_culture_income(this->CurrentCity); - - City_Form_draw (this); - - if (is->current_config.show_detailed_city_production_info) { - City * city = this->CurrentCity; - int order_type = city->Body.Order_Type, - order_id = city->Body.Order_ID, - order_progress = City_get_order_progress (city), - order_cost = City_get_order_cost (city), - prod_rate = get_city_production_rate (city, order_type, order_id), - building_wealth = (order_type == COT_Improvement) && ((p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0); - - int turns_left, surplus; { - if (prod_rate > 0) { - turns_left = (order_cost - order_progress) / prod_rate; - if ((order_cost - order_progress) % prod_rate != 0) - turns_left++; - if (turns_left < 1) - turns_left = 1; - surplus = (turns_left * prod_rate) - (order_cost - order_progress); - } else { - turns_left = 9999; - surplus = 0; - } - } - - char line1[100]; { - if (prod_rate > 0) { - if (! building_wealth) - snprintf (line1, sizeof line1, "%s %d %s", this->Labels.To_Build, turns_left, (turns_left == 1) ? this->Labels.Single_Turn : this->Labels.Multiple_Turns); - else - snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_NEVER_COMPLETES]); - } else - snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_HALTED]); - line1[(sizeof line1) - 1] = '\0'; - } - - char line2[100]; { - if (! building_wealth) { - int percent_complete = order_cost > 0 ? ((10000 * order_progress) / order_cost + 50) / 100 : 100; - snprintf (line2, sizeof line2, "%d / %d (%d%s)", order_progress, order_cost, percent_complete, this->Labels.Percent); - } else - snprintf (line2, sizeof line2, "---"); - line2[(sizeof line2) - 1] = '\0'; - } - - char line3[100]; { - if ((! building_wealth) && (prod_rate > 0)) { - int s_per, s_rem; { - if (turns_left > 1) { - s_per = surplus / turns_left; - s_rem = surplus % turns_left; - } else { - s_per = surplus; - s_rem = 0; - } - } - char * s_lab = is->c3x_labels[CL_SURPLUS]; - if ((s_per != 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d + %d %s", s_lab, s_rem, s_per, this->Labels.Per_Turn); - else if ((s_per == 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d", s_lab, s_rem); - else if ((s_per != 0) && (s_rem == 0)) snprintf (line3, sizeof line3, "%s: %d %s", s_lab, s_per, this->Labels.Per_Turn); - else snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NONE]); - } else - snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NA]); - line3[(sizeof line3) - 1] = '\0'; - } - - Object_66C3FC * font = get_font (10, FSF_NONE); - int left = this->Production_Storage_Indicator.left, - top = this->Production_Storage_Indicator.top, - width = this->Production_Storage_Indicator.right - left; - PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line1, left, top - 42, width, strlen (line1)); - PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line2, left, top - 28, width, strlen (line2)); - PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line3, left, top - 14, width, strlen (line3)); - } - - // Draw district commerce bonuses (gold and science) - if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) - return; - - // Lazy load district icons - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - if (is->dc_icons_img_state != IS_OK) - return; - - City * city = this->CurrentCity; - if (city == NULL) - return; - - // Calculate district gold and science bonuses by iterating workable tiles - int district_gold = 0; - int city_civ_id = city->Body.CivID; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - if ((wai.dx == 0) && (wai.dy == 0)) continue; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - struct district_config const * cfg = &is->district_configs[district_id]; - int gold_bonus = 0; - get_effective_district_yields (inst, cfg, NULL, NULL, &gold_bonus, NULL, NULL, NULL); - district_gold += gold_bonus; - } - - Leader * leader = &leaders[city_civ_id]; - int gold_proportion = (district_gold * leader->gold_slider) / 10; - int science_proportion = (district_gold * leader->science_slider) / 10; - - // Draw district gold icons - if (gold_proportion > 0) { - Sprite * gold_sprite = &is->district_commerce_icon; - int sprite_width = gold_sprite->Width; - int sprite_height = gold_sprite->Height; - - struct tagRECT * gold_rect = &this->Gold_Income_Rect; - int total_gold = City_get_net_commerce (city, __, 2, true); - - // Calculate spacing - int spacing = sprite_width; - if ((total_gold > 1) && (total_gold * sprite_width != (gold_rect->right - gold_rect->left))) { - int rect_width = gold_rect->right - gold_rect->left; - if (rect_width <= total_gold * sprite_width) { - spacing = (rect_width - sprite_width) / (total_gold - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > sprite_width) - spacing = sprite_width; - } - } - - // Draw from right to left - int x_offset = 0; - int y_offset = 5; - for (int i = 0; i < gold_proportion && i < total_gold; i++) { - int x = gold_rect->right - x_offset - sprite_width; - int y = gold_rect->top + ((gold_rect->bottom - gold_rect->top >> 1) - - (sprite_height >> 1)) + y_offset; - - Sprite_draw (gold_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); - x_offset += spacing; - } - } - - // Draw district science icons - if (science_proportion > 0) { - Sprite * science_sprite = &is->district_commerce_icon; - int sprite_width = science_sprite->Width; - int sprite_height = science_sprite->Height; - - struct tagRECT * science_rect = &this->Science_Income_Rect; - int total_science = City_get_net_commerce (city, __, 1, true); - - // Calculate spacing - int spacing = sprite_width; - if ((total_science > 1) && (total_science * sprite_width != (science_rect->right - science_rect->left))) { - int rect_width = science_rect->right - science_rect->left; - if (rect_width <= total_science * sprite_width) { - spacing = (rect_width - sprite_width) / (total_science - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > sprite_width) - spacing = sprite_width; - } - } - - // Draw from right to left - int x_offset = 0; - int y_offset = 5; - for (int i = 0; i < science_proportion && i < total_science; i++) { - int x = science_rect->right - x_offset - sprite_width; - int y = science_rect->top + ((science_rect->bottom - science_rect->top >> 1) - - (sprite_height >> 1)) + y_offset; - - Sprite_draw (science_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); - x_offset += spacing; - } - } -} - -void __fastcall -patch_City_Form_print_production_info (City_Form *this, int edx, String256 * out_strs, int str_capacity) -{ - City_Form_print_production_info (this, __, out_strs, str_capacity); - if (is->current_config.show_detailed_city_production_info) - out_strs[1].S[0] = '\0'; -} - -int __fastcall -patch_Sprite_draw_strat_res_on_city_screen (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - if (is->current_config.compact_strategic_resource_display_on_city_screen) - pixel_x -= 13 * is->drawn_strat_resource_count + 17; - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -int __fastcall -patch_PCX_Image_do_draw_cntd_text_for_strat_res (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) -{ - if (is->current_config.compact_strategic_resource_display_on_city_screen) - x -= 13 * is->drawn_strat_resource_count + 17; - int tr = PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); - is->drawn_strat_resource_count++; - return tr; -} - -int __fastcall -patch_City_get_turns_to_build (City * this, int edx, enum City_Order_Types order_type, int order_id, bool param_3) -{ - // To fix the zero production crash, return 9999 when the city's total production rate is zero, avoiding a division by zero. That's only - // possible when producing an improvement due to negative shields from specialists. The original logic attempts to return 9999 in case of zero - // production but checks for that before including shields from specialists. - if (is->current_config.patch_zero_production_crash && (order_type == COT_Improvement)) { - - int specialist_shields = 0; - FOR_CITIZENS_IN (ci, this) - if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) - specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; - - // Return 9999 if the denominator in the base function's calculation would be zero. Note the base calc is incorrect in that it - // considers specialist shields to count toward Wealth, however we're not going to address that issue here, just stop the crash. - if (this->Body.ProductionIncome + specialist_shields <= 0) - return 9999; - } - - return City_get_turns_to_build (this, __, order_type, order_id, param_3); -} - -bool -is_below_stack_limit (Tile * tile, int civ_id, int type_id) -{ - enum UnitTypeClasses class = p_bic_data->UnitTypes[type_id].Unit_Class; - - int stack_limit = is->current_config.limit_units_per_tile[class]; - if (stack_limit <= 0) - return true; - - if (is->current_config.exclude_cities_from_units_per_tile_limit && - get_city_ptr (tile->CityID) != NULL) - return true; - - if (itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, type_id, 0)) - return true; - - FOR_UNITS_ON (uti, tile) { - // If there is a foreign unit on the tile then consider it as being below the stack limit. This ensures that the stack limit doesn't - // block combat between players. - if (uti.unit->Body.CivID != civ_id) - return true; - - int uti_type_id = uti.unit->Body.UnitTypeID; - if ((uti.unit->Body.Container_Unit < 0) && - (class == p_bic_data->UnitTypes[uti_type_id].Unit_Class) && - ! itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, uti_type_id, 0)) { - stack_limit -= 1; - if (stack_limit <= 0) - return false; - } - } - return true; -} - -// Returns the ID of the civ this move is trespassing against, or 0 if it's not trespassing. -int -check_trespassing (int civ_id, Tile * from, Tile * to) -{ - int from_territory_id = from->vtable->m38_Get_Territory_OwnerID (from), - to_territory_id = to ->vtable->m38_Get_Territory_OwnerID (to); - if ((civ_id > 0) && - (to_territory_id != civ_id) && - (to_territory_id > 0) && - (to_territory_id != from_territory_id) && - (! leaders[civ_id].At_War[to_territory_id]) && - ((leaders[civ_id].Relation_Treaties[to_territory_id] & 2) == 0)) // Check right of passage - return to_territory_id; - else - return 0; -} - -bool -is_allowed_to_trespass (Unit * unit) -{ - int type_id = unit->Body.UnitTypeID; - if ((type_id >= 0) && (type_id < p_bic_data->UnitTypeCount)) { - UnitType * type = &p_bic_data->UnitTypes[type_id]; - return UnitType_has_ability (type, __, UTA_Hidden_Nationality) || UnitType_has_ability (type, __, UTA_Invisible); - } else - return false; -} - -bool -get_tile_district_impassibility (Tile * tile, bool * out_impassible, bool * out_impassible_to_wheeled) -{ - if (out_impassible != NULL) - *out_impassible = false; - if (out_impassible_to_wheeled != NULL) - *out_impassible_to_wheeled = false; - - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - if (! district_is_complete (tile, inst->district_id)) - return false; - - if (inst->district_id == NATURAL_WONDER_DISTRICT_ID) { - if (! is->current_config.enable_natural_wonders) - return false; - int natural_id = inst->natural_wonder_info.natural_wonder_id; - if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) - return false; - if (out_impassible != NULL) - *out_impassible = is->natural_wonder_configs[natural_id].impassible; - if (out_impassible_to_wheeled != NULL) - *out_impassible_to_wheeled = is->natural_wonder_configs[natural_id].impassible_to_wheeled; - return true; - } - - if (! is->current_config.enable_districts) - return false; - if ((inst->district_id < 0) || (inst->district_id >= is->district_count)) - return false; - - if (out_impassible != NULL) - *out_impassible = is->district_configs[inst->district_id].impassible; - if (out_impassible_to_wheeled != NULL) - *out_impassible_to_wheeled = is->district_configs[inst->district_id].impassible_to_wheeled; - return true; -} - -AdjacentMoveValidity __fastcall -patch_Unit_can_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, int param_2) -{ - AdjacentMoveValidity base_validity = Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2); - - if (is->current_config.enable_districts) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - Tile * dest = tile_at (nx, ny); - - // Let workers step onto coast tiles when the config flag is enabled (base logic treats this as an invalid sea move) - if (is->current_config.workers_can_enter_coast && is_worker (this) && - ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { - if ((dest != NULL) && - dest->vtable->m35_Check_Is_Water (dest) && - (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) - base_validity = AMV_OK; - } - - // Allow land units to enter bridge tiles - if (is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && - ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { - if ((dest != NULL) && (dest != p_null_tile)) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { - base_validity = AMV_OK; - } - } - } - - // Allow naval units to enter completed canal tiles - if (is->current_config.enable_canal_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && - ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { - if ((dest != NULL) && (dest != p_null_tile)) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { - base_validity = AMV_OK; - } - } - } - - if ((base_validity == AMV_OK) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { - if ((dest != NULL) && (dest != p_null_tile) && Tile_has_city (dest)) - return AMV_INVALID_SEA_MOVE; - } - } - - // Apply unit count per tile limit - int type_id = this->Body.UnitTypeID; - if ((base_validity == AMV_OK) && (is->current_config.limit_units_per_tile[p_bic_data->UnitTypes[type_id].Unit_Class] > 0)) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - if (! is_below_stack_limit (tile_at (nx, ny), this->Body.CivID, type_id)) - return AMV_CANNOT_PASS_BETWEEN; - } - - // Apply trespassing restriction - if (is->current_config.disallow_trespassing && (base_validity == AMV_OK)) { - Tile * from = tile_at (this->Body.X, this->Body.Y); - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - int trespasses_against_civ_id = check_trespassing (this->Body.CivID, from, tile_at (nx, ny)); - if ((trespasses_against_civ_id > 0) && (! is_allowed_to_trespass (this))) - // The tile might be occupied by a unit belonging to a civ other than the one that owns the territory (against whom we'd be - // trespassing). In this case we must forbid the move entirely since TRIGGERS_WAR will not stop it if we're at war with the - // occupying civ. This fixes a bug where units could trespass by attacking an enemy unit across a border. They would then get - // stuck halfway between tiles if they won. - return (trespasses_against_civ_id == get_tile_occupier_id (nx, ny, this->Body.CivID, false)) ? AMV_TRIGGERS_WAR : AMV_CANNOT_PASS_BETWEEN; - } - - return base_validity; -} - -bool -great_wall_blocks_civ (Tile * tile, int civ_id) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_great_wall_districts || - ! is->current_config.great_wall_districts_impassible_by_others) - return false; - - if ((tile == NULL) || (tile == p_null_tile)) - return false; - - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (owner_id <= 0) - return false; - if (owner_id == civ_id) - return false; - if ((civ_id > 0) && ((leaders[civ_id].Relation_Treaties[owner_id] & 2) != 0)) // 2 = right of passage - return false; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID)) - return false; - - if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) - return false; - - if (district_is_obsolete_for_civ (GREAT_WALL_DISTRICT_ID, civ_id)) - return false; - - return true; -} - -int __fastcall -patch_Trade_Net_get_movement_cost (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned flags, int neighbor_index, Trade_Net_Distance_Info * dist_info) -{ - if (is->is_computing_city_connections && // if this call came while rebuilding the trade network AND - (is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL) && // Trade Net X is set up AND - (unit == NULL) && ((flags == 0x1009) || (flags == 0x9))) // this call can be accelerated by TNX - return is->get_move_cost_for_sea_trade (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags, neighbor_index, dist_info); - - int base_cost = Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, neighbor_index, dist_info); - - bool districts_enabled = is->current_config.enable_districts; - if (districts_enabled) { - Tile * to = tile_at (to_x, to_y); - bool to_valid = (to != NULL) && (to != p_null_tile); - struct district_instance * to_inst = NULL; - bool to_inst_complete = false; - if (to_valid) { - to_inst = get_district_instance (to); - if (to_inst != NULL) - to_inst_complete = district_is_complete (to, to_inst->district_id); - } - - if ((unit != NULL) && great_wall_blocks_civ (to, unit->Body.CivID)) - return -1; - if ((unit != NULL) && to_valid) { - bool impassible = false; - bool impassible_to_wheeled = false; - if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { - if (impassible) - return -1; - if (impassible_to_wheeled && Unit_has_ability (unit, __, UTA_Wheeled)) { - Tile * from = tile_at (from_x, from_y); - bool connected_by_road = (from != NULL) && (to != NULL) && - (from->vtable->m25_Check_Roads (from, __, 0) != 0) && - (to->vtable->m25_Check_Roads (to, __, 0) != 0); - if (! connected_by_road) - return -1; - } - } - } - - // Let the pathfinder consider coastal tiles reachable for workers when the config flag is on - if (is->current_config.workers_can_enter_coast && - (base_cost < 0) && (unit != NULL) && is_worker (unit) && - to_valid && - to->vtable->m35_Check_Is_Water (to) && - (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) - base_cost = Unit_get_max_move_points (unit); - - // Let the pathfinder consider bridge tiles reachable for land units - if (is->current_config.enable_bridge_districts && - (base_cost < 0) && (unit != NULL) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == BRIDGE_DISTRICT_ID)) - base_cost = Unit_get_max_move_points (unit); - - // Let the pathfinder consider canal tiles reachable for naval units - if (is->current_config.enable_canal_districts && - (base_cost < 0) && (unit != NULL) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == CANAL_DISTRICT_ID)) - base_cost = Unit_get_max_move_points (unit); - - // Treat roads/rails on bridge districts like land roads/rails for movement cost. - if ((unit != NULL) && - is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land)) { - Tile * from = tile_at (from_x, from_y); - if ((from != NULL) && (from != p_null_tile) && to_valid) { - struct district_instance * from_inst = get_district_instance (from); - bool from_bridge = (from_inst != NULL) && - (from_inst->district_id == BRIDGE_DISTRICT_ID) && - district_is_complete (from, from_inst->district_id); - bool to_bridge = (to_inst != NULL) && - to_inst_complete && - (to_inst->district_id == BRIDGE_DISTRICT_ID); - if (from_bridge || to_bridge) { - bool from_rail = from->vtable->m23_Check_Railroads (from, __, 0) != 0; - bool to_rail = to->vtable->m23_Check_Railroads (to, __, 0) != 0; - bool from_road = from->vtable->m25_Check_Roads (from, __, 0) != 0; - bool to_road = to->vtable->m25_Check_Roads (to, __, 0) != 0; - if (from_rail && to_rail) - base_cost = 0; - else if (from_road && to_road) - base_cost = 1; - } - } - } - - if ((unit != NULL) && - (base_cost >= 0) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && - to_valid && Tile_has_city (to)) - return -1; - } - - // Apply unit count per tile limit - if ((unit != NULL) && ! is_below_stack_limit (tile_at (to_x, to_y), unit->Body.CivID, unit->Body.UnitTypeID)) - return -1; - - // Apply trespassing restriction - if (is->current_config.disallow_trespassing && - check_trespassing (civ_id, tile_at (from_x, from_y), tile_at (to_x, to_y)) && - ((unit == NULL) || (! is_allowed_to_trespass (unit)))) - return -1; - - // Adjust movement cost to enforce limited railroad movement - if ((is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0)) { - if ((unit != NULL) && (base_cost == 0)) { // Railroad move - if (! is->current_config.limited_railroads_work_like_fast_roads) { // If Civ 4 style RR, scale cost by type's moves - int type_moves_available = patch_Unit_get_max_move_points (unit) / p_bic_data->General.RoadsMovementRate; - return type_moves_available * is->railroad_mp_cost_per_move; - } else - return is->railroad_mp_cost_per_move; - } else if (base_cost == 1) // Road move - return is->road_mp_cost; - } - - return base_cost; -} - -int __fastcall -patch_Trade_Net_set_unit_path (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) -{ - int tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); - - bool may_require_length_fix = (is->current_config.limit_railroad_movement > 0) && // if railroad movement is limited AND - (tr > 0) && (out_path_length_in_mp != NULL) && // path was found AND caller wants to know its length AND - (unit != NULL); // the path is for an actual unit - - // We might have to correct the path length returned by the base game's pathfinder. This occurs when railroad movement is limited and the - // unit's total MP exceeds what can be stored in a one-byte integer. The cause of the incorrect length is that the pathfinder internally - // stores the remaining moves at each node of the search in a single byte. This correction fixes the bug (reported several times) that ETAs - // shown in the interface are wrong. - if (may_require_length_fix && (patch_Unit_get_max_move_points (unit) > 255)) { // Need to recompute path length if unit's total MP can overflow a uint8 - - // First memoize the cost of taking each step along the path. This must be done separately because the pathfinder's internal data only - // lets us traverse the path backwards. - { - // Must pass cached "distance info" to Trade_Net::get_movement_cost. Trade_Net stores two sets of cached data, which one was - // used depends on the flags. I believe one is intended to be used for city trade connections and the other for unit movement. - Trade_Net_Distance_Info * dist_info = (flags & 1) ? this->Data2 : this->Data4; - - clear_memo (); - int x = to_x, y = to_y; - do { - // "flags & 1" again determines whether Data2 or Data4 was used. - enum direction dir = Trade_Net_get_direction_from_internal_map (this, __, x, y, flags & 1); - if (dir == DIR_ZERO) - break; - - int prev_x, prev_y; { - int dx, dy; - neighbor_index_to_diff (dir, &dx, &dy); - prev_x = x + dx; prev_y = y + dy; - wrap_tile_coords (&p_bic_data->Map, &prev_x, &prev_y); - } - - memoize (patch_Trade_Net_get_movement_cost (this, __, prev_x, prev_y, x, y, unit, civ_id, flags, reverse_dir (dir), dist_info)); - x = prev_x; y = prev_y; - } while (! ((x == from_x) && (y == from_y))); - } - - // Now walk the path forwards tracking how much MP the unit would spend. We must be aware that the unit can't spend more MP than it - // has. For example, if a unit with 1 move walks onto an unimproved mountain, that effectively costs only 1 move, not 3. - int mp_remaining = patch_Unit_get_max_move_points (unit) - unit->Body.Moves, - mp_spent = 0; - for (int n = is->memo_len - 1; n >= 0; n--) { - int cost = is->memo[n]; - if (cost < mp_remaining) { - mp_spent += cost; - mp_remaining -= cost; - } else { - mp_spent += mp_remaining; - mp_remaining = patch_Unit_get_max_move_points (unit); - } - } - *out_path_length_in_mp = mp_spent; - - // Also, if this is a move between adjacent tiles, make sure the path length doesn't exceed the unit's remaining MP. Otherwise, the game may - // erroneously show an ETA of >1 turn. - } else if (may_require_length_fix && are_tiles_adjacent (from_x, from_y, to_x, to_y)) - *out_path_length_in_mp = not_above (patch_Unit_get_max_move_points (unit) - unit->Body.Moves, *out_path_length_in_mp); - - return tr; -} - -int __fastcall -patch_Trade_Net_set_unit_path_to_find_sea_route (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) -{ - // Accelerate this call with TNX if possible - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { - bool route_exists = is->try_drawing_sea_trade_route (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags); - return route_exists ? 1 : 0; - } else - return Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); -} - -// Renames this leader and their civ based on their era. Era-specific names come from the config file. If this leader has a custom name set by the -// human player, this method does nothing. -void -apply_era_specific_names (Leader * leader) -{ - int leader_bit = 1 << leader->ID; - Race * race = &p_bic_data->Races[leader->RaceID]; - - struct replaceable_name { - char * base_name; - int * tracking_bits; - char * buf; - int buf_size; - } replaceable_names[] = { - {race->vtable->GetAdjectiveName (race), &is->aliased_civ_adjective_bits , leader->tribe_customization.civ_adjective , sizeof leader->tribe_customization.civ_adjective}, - {race->vtable->GetSingularName (race) , &is->aliased_civ_noun_bits , leader->tribe_customization.civ_noun , sizeof leader->tribe_customization.civ_noun}, - {race->vtable->GetCountryName (race) , &is->aliased_civ_formal_name_bits, leader->tribe_customization.civ_formal_name, sizeof leader->tribe_customization.civ_formal_name} - }; - - // Apply replacements to civ noun, adjective, and formal name - for (int n = 0; n < ARRAY_LEN (replaceable_names); n++) { - struct replaceable_name * repl = &replaceable_names[n]; - if ((*repl->tracking_bits & leader_bit) || (repl->buf[0] == '\0')) { - char * replacement = NULL; - if (leader->Era < ERA_ALIAS_LIST_CAPACITY) - // Search through the list of aliases in reverse order so that, if the same key was listed multiple times, the last - // appearance overrides the earlier ones. This is important b/c when configs are loaded, their aliases get appended to - // the list. - for (int k = is->current_config.count_civ_era_alias_lists - 1; k >= 0; k--) { - struct civ_era_alias_list * list = &is->current_config.civ_era_alias_lists[k]; - if (strcmp (list->key, repl->base_name) == 0) { - replacement = list->aliases[leader->Era]; - break; - } - } - if (replacement != NULL) { - strncpy (repl->buf, replacement, repl->buf_size); - repl->buf[repl->buf_size - 1] = '\0'; - *repl->tracking_bits |= leader_bit; - } else { - repl->buf[0] = '\0'; - *repl->tracking_bits &= ~leader_bit; - } - } - } - - // Apply replacement to leader name, gender, and title - if ((is->aliased_leader_name_bits & leader_bit) || (leader->tribe_customization.leader_name[0] == '\0')) { - char * base_name = race->vtable->GetLeaderName (race); - char * replacement_name = NULL; - char * replacement_title = NULL; - int replacement_gender; // Only used if replacement_name is - if (leader->Era < ERA_ALIAS_LIST_CAPACITY) - for (int k = is->current_config.count_leader_era_alias_lists - 1; k >= 0; k--) { - struct leader_era_alias_list * list = &is->current_config.leader_era_alias_lists[k]; - if (strcmp (list->key, base_name) == 0) { - replacement_name = list->aliases[leader->Era]; - replacement_title = list->titles[leader->Era]; - replacement_gender = (list->gender_bits >> leader->Era) & 1; - break; - } - } - if (replacement_name != NULL) { - TribeCustomization * tc = &leader->tribe_customization; - strncpy (tc->leader_name, replacement_name, sizeof tc->leader_name); - tc->leader_name[(sizeof tc->leader_name) - 1] = '\0'; - tc->leader_gender = replacement_gender; - is->aliased_leader_name_bits |= leader_bit; - - // If this replacement name has a special title and this player does not have a custom title set, replace the title. - if ((replacement_title != NULL) && ((is->aliased_leader_title_bits & leader_bit) || (tc->leader_title[0] == '\0'))) { - strncpy (tc->leader_title, replacement_title, sizeof tc->leader_title); - tc->leader_title[(sizeof tc->leader_title) - 1] = '\0'; - is->aliased_leader_title_bits |= leader_bit; - - // If the current name has no title and the player's title was previously replaced, undo the replacement. - } else if ((replacement_title == NULL) && (is->aliased_leader_title_bits & leader_bit)) { - leader->tribe_customization.leader_title[0] = '\0'; - is->aliased_leader_title_bits &= ~leader_bit; - } - } else { - leader->tribe_customization.leader_name[0] = '\0'; - // Don't need to clear custom leader gender since it's not used unless a custom name was set - is->aliased_leader_name_bits &= ~leader_bit; - - // Remove title replacement if present - if (is->aliased_leader_title_bits & leader_bit) { - leader->tribe_customization.leader_title[0] = '\0'; - is->aliased_leader_title_bits &= ~leader_bit; - } - } - } -} - -int __cdecl -patch_do_save_game (char const * file_path, char param_2, GUID * guid) -{ - // Do not save the modified road movement rate, if it was modified to limit railroad movement - int restore_rmr = (is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0); - int rmr; - if (restore_rmr) { - rmr = p_bic_data->General.RoadsMovementRate; - p_bic_data->General.RoadsMovementRate = is->saved_road_movement_rate; - } - - // Do not save the modified barb culture group ID - int restore_barb_culture_group = is->current_config.enable_city_capture_by_barbarians && (is->saved_barb_culture_group >= 0); - int barb_culture; - if (restore_barb_culture_group) { - barb_culture = p_bic_data->Races[leaders[0].RaceID].CultureGroupID; - p_bic_data->Races[leaders[0].RaceID].CultureGroupID = is->saved_barb_culture_group; - } - - // Do not save names that were replaced with era-specific versions - for (int n = 0; n < 32; n++) { - Leader * leader = &leaders[n]; - int leader_bit = 1 << leader->ID; - if (is->aliased_civ_noun_bits & leader_bit) leader->tribe_customization.civ_noun [0] = '\0'; - if (is->aliased_civ_adjective_bits & leader_bit) leader->tribe_customization.civ_adjective [0] = '\0'; - if (is->aliased_civ_formal_name_bits & leader_bit) leader->tribe_customization.civ_formal_name[0] = '\0'; - if (is->aliased_leader_name_bits & leader_bit) leader->tribe_customization.leader_name [0] = '\0'; - if (is->aliased_leader_title_bits & leader_bit) leader->tribe_customization.leader_title [0] = '\0'; - } - is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; - - // Do not save unit types with the charm bits cleared if they were cleared by convertion to PTW targeting. The special actions field must not - // include the top category bits that are part of the UCV_* enum - for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { - UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; - converted_type->Special_Actions |= (0x00FFFFFF & UCV_Charm_Bombard); - } - - int tr = do_save_game (file_path, param_2, guid); - - if (restore_rmr) - p_bic_data->General.RoadsMovementRate = rmr; - if (restore_barb_culture_group) - p_bic_data->Races[leaders[0].RaceID].CultureGroupID = barb_culture; - - // Reapply era aliases - for (int n = 0; n < 32; n++) - if (*p_player_bits & (1 << n)) - apply_era_specific_names (&leaders[n]); - - // Reclear charm bits on converted types - for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { - UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; - converted_type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); - } - - return tr; -} - -void -record_unit_type_alt_strategy (int type_id) -{ - int ai_strat_index; { - int ai_strat_bits = p_bic_data->UnitTypes[type_id].AI_Strategy; - if ((ai_strat_bits & ai_strat_bits - 1) != 0) // Sanity check: must only have one strat (one bit) set - return; - ai_strat_index = 0; - while ((ai_strat_bits & 1) == 0) { - ai_strat_index++; - ai_strat_bits >>= 1; - } - } - - itable_insert (&is->unit_type_alt_strategies, type_id, ai_strat_index); -} - -void -append_improv_id_to_list (struct improv_id_list * list, int id) -{ - reserve (sizeof list->items[0], (void **)&list->items, &list->capacity, list->count); - list->items[list->count] = id; - list->count += 1; -} - -unsigned __fastcall -patch_load_scenario (BIC * this, int edx, char * param_1, unsigned * param_2) -{ - int ret_addr = ((int *)¶m_1)[-1]; - - // Destroy TNX cache from previous map. A new one will be created when needed. - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { - is->destroy_tnx_cache (is->tnx_cache); - is->tnx_cache = NULL; - } - - unsigned tr = load_scenario (this, __, param_1, param_2); - char * scenario_path = param_1; - - // There are two cases when load_scenario is called that we don't want to run our own code. These are (1) when the scenario is loaded to - // generate a preview (map, etc.) for the "Civ Content" or "Conquests" menu and (2) when the function is called recursively. The recursive - // call is done, I believe, only when loading saves using the default rules. The game first tries to load custom rules then falls back on - // loading the default rules. In any case, we want to ignore that call so we don't run the same code twice. - if ((ret_addr == ADDR_LOAD_SCENARIO_PREVIEW_RETURN) || (ret_addr == ADDR_LOAD_SCENARIO_RESUME_SAVE_2_RETURN)) - return tr; - - reset_to_base_config (); - load_config ("default.c3x_config.ini", 1); - char * scenario_config_file_name = "scenario.c3x_config.ini"; - char * scenario_config_path = BIC_get_asset_path (p_bic_data, __, scenario_config_file_name, false); - - // BIC_get_asset_path returns the file name when it can't find the file - if (0 != strcmp (scenario_config_file_name, scenario_config_path)) { - load_config (scenario_config_path, 0); - } - load_config ("custom.c3x_config.ini", 1); - apply_machine_code_edits (&is->current_config, false); - - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - reset_district_state (true); - load_districts_config (); - } - - // Initialize Trade Net X - if (is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_UNINITED)) { - char path[MAX_PATH]; - snprintf (path, sizeof path, "%s\\Trade Net X\\TradeNetX.dll", is->mod_rel_dir); - path[(sizeof path) - 1] = '\0'; - is->trade_net_x = LoadLibraryA (path); - if (is->trade_net_x != NULL) { - is->set_exe_version = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_exe_version"); - is->create_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "create_tnx_cache"); - is->destroy_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "destroy_tnx_cache"); - is->set_up_before_building_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_up_before_building_network"); - is->get_move_cost_for_sea_trade = (void *)(*p_GetProcAddress) (is->trade_net_x, "get_move_cost_for_sea_trade"); - is->flood_fill_road_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "flood_fill_road_network"); - is->try_drawing_sea_trade_route = (void *)(*p_GetProcAddress) (is->trade_net_x, "try_drawing_sea_trade_route"); - - is->set_exe_version (exe_version_index); - - // Run tests - if (0) { - int (__stdcall * test) () = (void *)(*p_GetProcAddress) (is->trade_net_x, "test"); - int failed_test_count = test (); - if (failed_test_count > 0) - MessageBoxA (NULL, "Failed some tests in Trade Net X!", NULL, MB_ICONWARNING); - else - MessageBoxA (NULL, "All tests in Trade Net X passed.", "Success", MB_ICONINFORMATION); - } - - is->tnx_init_state = IS_OK; - } else { - MessageBoxA (NULL, "Failed to load Trade Net X!", NULL, MB_ICONERROR); - is->tnx_init_state = IS_INIT_FAILED; - } - - // Deinitialize Trade Net X - } else if ((! is->current_config.enable_trade_net_x) && (is->tnx_init_state == IS_OK)) { - FreeLibrary (is->trade_net_x); - is->trade_net_x = NULL; - is->tnx_init_state = IS_UNINITED; - } - - // This scenario might use different mod art assets than the old one - deinit_stackable_command_buttons (); - deinit_disabled_command_buttons (); - deinit_trade_scroll_buttons (); - deinit_unit_rcm_icons (); - deinit_red_food_icon (); - deinit_large_minimap_frame (); - if (is->tile_already_worked_zoomed_out_sprite_init_state != IS_UNINITED) { - enum init_state * state = &is->tile_already_worked_zoomed_out_sprite_init_state; - if (*state == IS_OK) { - Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; - sprite->vtable->destruct (sprite, __, 0); - } - *state = IS_UNINITED; - } - - // Need to clear this since the resource count might have changed - if (is->extra_available_resources != NULL) { - free (is->extra_available_resources); - is->extra_available_resources = NULL; - is->extra_available_resources_capacity = 0; - } - - // Similarly, these don't carry over between games - for (int n = 0; n < 32; n++) - is->interceptor_reset_lists[n].count = 0; - is->replay_for_players = 0; - table_deinit (&is->extra_defensive_bombards); - table_deinit (&is->airdrops_this_turn); - table_deinit (&is->unit_transport_ties); - is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; - is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; - is->last_selected_unit.ptr = NULL; - table_deinit (&is->waiting_units); - is->have_loaded_waiting_units = false; - - // Clear extra city improvement bits - FOR_TABLE_ENTRIES (tei, &is->extra_city_improvs) - free ((void *)tei.value); - table_deinit (&is->extra_city_improvs); - - // Clear unit type counts - for (int n = 0; n < 32; n++) - table_deinit (&is->unit_type_counts[n]); - is->unit_type_count_init_bits = 0; - - // Clear last city founding turn numbers - for (int n = 0; n < 32; n++) - is->turn_no_of_last_founding_for_settler_perfume[n] = -1; - - // Load resources.pcx - { - PCX_Image * rs = is->resources_sheet; - if (rs != NULL) - rs->vtable->destruct (rs, __, 0); - else - rs = malloc (sizeof *rs); - memset (rs, 0, sizeof *rs); - PCX_Image_construct (rs); - - char * resources_pcx_path = BIC_get_asset_path (p_bic_data, __, "Art\\resources.pcx", true); - PCX_Image_read_file (rs, __, resources_pcx_path, NULL, 0, 0x100, 2); - is->resources_sheet = rs; - } - - // Recreate table of alt strategies mapping duplicates to their strategies - table_deinit (&is->unit_type_alt_strategies); - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; - if (alt_for_id >= 0) { - record_unit_type_alt_strategy (n); - record_unit_type_alt_strategy (alt_for_id); // Record the original too so we know it has alternatives - } - } - - // Recreate table of duplicates mapping unit types to the next duplicate - table_deinit (&is->unit_type_duplicates); - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; - if (alt_for_id >= 0) { - - // Find the type ID of the last duplicate in the list. alt_for_id refers to the original unit that was duplicated possibly - // multiple times. Begin searching there and, each time we find another duplicate, use its ID to continue the search. When - // we're done last_dup_id will be set to whichever ID in the list of duplicates is not already associated with another. - int last_dup_id = alt_for_id; { - int next; - while (itable_look_up (&is->unit_type_duplicates, last_dup_id, &next)) - last_dup_id = next; - } - - // Add this unit type to the end of the list of duplicates - itable_insert (&is->unit_type_duplicates, last_dup_id, n); - } - } - - // Convert charm-flagged units to using PTW targeting if necessary - if (is->current_config.charm_flag_triggers_ptw_like_targeting) { - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if (type->Special_Actions & UCV_Charm_Bombard) { - // Also add it to the list of converted types - reserve (sizeof is->charmed_types_converted_to_ptw_arty[0], // item size - (void **)&is->charmed_types_converted_to_ptw_arty, // ptr to items - &is->charmed_types_converted_to_ptw_arty_capacity, // ptr to capacity - is->count_charmed_types_converted_to_ptw_arty); // count - is->charmed_types_converted_to_ptw_arty[is->count_charmed_types_converted_to_ptw_arty] = n; - is->count_charmed_types_converted_to_ptw_arty += 1; - - // Add this type ID to the table - itable_insert (&is->current_config.ptw_arty_types, n, 1); - - // Clear the charm flag, taking care not to clear the category bit. This is necessary for the PTW targeting to work - // since the logic to implement it only applies to the non-charm code path. It wouldn't make sense to have both charm - // attack and PTW targeting anyway, since charm attack already works that way vs cities. - type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); - } - } - } - - // Pick out which resources are used as mill inputs - if (is->mill_input_resource_bits) - free (is->mill_input_resource_bits); - is->mill_input_resource_bits = calloc (1, 1 + p_bic_data->ResourceTypeCount / 8); - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - for (int k = 0; k < 2; k++) { - int resource_id = (&p_bic_data->Improvements[mill->improv_id].Resource1ID)[k]; - if ((resource_id >= 0) && (resource_id < p_bic_data->ResourceTypeCount)) { - byte bit = 1 << (resource_id & 7); - is->mill_input_resource_bits[resource_id>>3] |= bit; - } - } - } - - // Recreate lists of water & air trade improvements - is->water_trade_improvs .count = 0; - is->air_trade_improvs .count = 0; - is->combat_defense_improvs.count = 0; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - enum ImprovementTypeFlags flags = p_bic_data->Improvements[n].ImprovementFlags; - if (flags & ITF_Allows_Water_Trade) append_improv_id_to_list (&is->water_trade_improvs , n); - if (flags & ITF_Allows_Air_Trade) append_improv_id_to_list (&is->air_trade_improvs , n); - if (p_bic_data->Improvements[n].Combat_Defence != 0) append_improv_id_to_list (&is->combat_defense_improvs, n); - } - - // Set up for limiting railroad movement - if (is->current_config.limit_railroad_movement > 0) { - // Bit 0x200 of field_484 indicates whether or not the last call to load_scenario loaded the General section of the BIQ. The game will - // skip loading of that section and many others when loading a game with the same standard scenario as the then-current one, common - // when loading an autosave. - bool loaded_general = (this->field_848 & 0x200) != 0; - - // For the base RMR, use the saved rate if it's valid and we haven't loaded a new rate as part of the General section. Otherwise, use - // the rate from that section. - int base_rmr = (loaded_general || is->saved_road_movement_rate <= 0) ? p_bic_data->General.RoadsMovementRate : is->saved_road_movement_rate; - - int g = gcd (base_rmr, is->current_config.limit_railroad_movement); // Scale down all MP costs by this common divisor to help against - // overflow of 8-bit integers inside the pathfinder. - is->saved_road_movement_rate = base_rmr; - p_bic_data->General.RoadsMovementRate = base_rmr * is->current_config.limit_railroad_movement / g; // Full move in MP - is->road_mp_cost = is->current_config.limit_railroad_movement / g; - is->railroad_mp_cost_per_move = base_rmr / g; - } else { - is->saved_road_movement_rate = -1; - is->road_mp_cost = 1; - is->railroad_mp_cost_per_move = 0; - } - - // If barb city capturing is enabled and the barbs have the non-existent "none" culture group (index -1), switch them to the first real - // culture group. The "none" group produces corrupt graphics and crashes. - int * barb_culture_group = &p_bic_data->Races[leaders[0].RaceID].CultureGroupID; - if (is->current_config.enable_city_capture_by_barbarians && (*barb_culture_group < 0)) { - is->saved_barb_culture_group = *barb_culture_group; - *barb_culture_group = 0; - } else - is->saved_barb_culture_group = -1; - - // Clear old alias bits - is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; - - // Apply no AI patrol override - if (is->current_config.override_no_ai_patrol == NAPO_ZERO) - *p_allow_ai_patrol = true; - else if (is->current_config.override_no_ai_patrol == NAPO_ONE) - *p_allow_ai_patrol = false; - else if (is->current_config.override_no_ai_patrol == NAPO_NONE) - *p_allow_ai_patrol = 0 == get_int_from_conquests_ini ("NoAIPatrol", 1, 0); - - // Clear day/night cycle vars and deindex sprite proxies, if necessary. - if (is->current_config.day_night_cycle_mode != DNCM_OFF) { - is->day_night_cycle_unstarted = true; - is->current_day_night_cycle = 12; - if (is->day_night_cycle_img_proxies_indexed) { - deindex_day_night_image_proxies (); - } - } - - return tr; -} - -void __fastcall -patch_Leader_recompute_auto_improvements (Leader * this) -{ - is->leader_param_for_patch_get_wonder_city_id = this; - Leader_recompute_auto_improvements (this); -} - -int __fastcall -patch_Game_get_wonder_city_id (Game * this, int edx, int wonder_improvement_id) -{ - int ret_addr = ((int *)&wonder_improvement_id)[-1]; - if ((is->current_config.enable_free_buildings_from_small_wonders) && (ret_addr == ADDR_SMALL_WONDER_FREE_IMPROVS_RETURN)) { - Leader * leader = is->leader_param_for_patch_get_wonder_city_id; - Improvement * improv = &p_bic_data->Improvements[wonder_improvement_id]; - if ((improv->Characteristics & ITC_Small_Wonder) != 0) { - // Need to check if Small_Wonders array is NULL b/c recompute_auto_improvements gets called with leaders that are absent/dead. - return (leader->Small_Wonders != NULL) ? leader->Small_Wonders[wonder_improvement_id] : -1; - } - } - return Game_get_wonder_city_id (this, __, wonder_improvement_id); -} - -int __fastcall -patch_Main_Screen_Form_handle_key_up (Main_Screen_Form * this, int edx, int virtual_key_code) -{ - if ((virtual_key_code & 0xFF) == VK_CONTROL) { - patch_Main_GUI_set_up_unit_command_buttons (&this->GUI); - - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - } - - return Main_Screen_Form_handle_key_up (this, __, virtual_key_code); -} - -char __fastcall -patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing) -{ - char tr; - bool is_ai = ((*p_human_player_bits & (1 << this->ID)) == 0); - bool skip_replacement_logic = - (p_main_screen_form->Player_CivID == this->ID) && is->current_config.skip_repeated_tile_improv_replacement_asks; - - Tile * tile = tile_at (tile_x, tile_y); - - // If districts on, short-circuit any potential AI workers accidentally building in another civ's territory. - if (is->current_config.enable_districts && is_ai && (tile != NULL) && (tile != p_null_tile)) { - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (territory_owner > 0 && territory_owner != this->ID) - return 0; - } - - // Check if AI is trying to change a district tile (before calling vanilla logic) - if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && - is_ai) { - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { - int district_id = inst->district_id; - bool allow_ai_change = false; - - // Allow AI to modify obsolete districts - if (district_is_obsolete_for_civ (district_id, this->ID)) - allow_ai_change = true; - - // Allow if district could be used as a prerequisite for other buildable districts - if (! allow_ai_change) { - for (int other_id = 0; other_id < is->district_count; other_id++) { - if (other_id == district_id) - continue; - struct district_config const * other_cfg = &is->district_configs[other_id]; - if (! other_cfg->has_buildable_on_districts) - continue; - for (int i = 0; i < other_cfg->buildable_on_district_id_count; i++) { - if (other_cfg->buildable_on_district_ids[i] == district_id) { - if (leader_can_build_district (this, other_id)) - allow_ai_change = true; - break; - } - } - if (allow_ai_change) - break; - } - } - - // Allow AI to build roads/rails on bridge districts - if (! allow_ai_change && (district_id == BRIDGE_DISTRICT_ID) && - (job == WJ_Build_Road || job == WJ_Build_Railroad)) - allow_ai_change = true; - - // For Wonder Districts: check if unused (can be replaced) - if (! allow_ai_change && is->current_config.enable_wonder_districts && (district_id == WONDER_DISTRICT_ID)) { - struct wonder_district_info * info = get_wonder_district_info (tile); - - // If there's a reservation (wonder being built) or completed wonder, block replacement - if (info != NULL && info->state != WDS_UNUSED) - return 0; - - // Wonder district is unused - fall through to normal tech checks - } - else if (! allow_ai_change && is->current_config.enable_natural_wonders && (district_id == NATURAL_WONDER_DISTRICT_ID)) { - return 0; - } - else if (! allow_ai_change) { - // For all other district types: AI should not change them - return 0; - } - } - } - } - - if (! skip_replacement_logic) - tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); - else if (is->have_job_and_loc_to_skip && - (is->to_skip.job == job) && (is->to_skip.tile_x == tile_x) && (is->to_skip.tile_y == tile_y)) - tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, 0); - else { - is->show_popup_was_called = 0; - tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); - if (is->show_popup_was_called && tr) { // Check that the popup was shown and the player chose to replace - is->to_skip = (struct worker_job_and_location) { .job = job, .tile_x = tile_x, .tile_y = tile_y }; - is->have_job_and_loc_to_skip = 1; - } - } - - if (! tr && is->current_config.enable_districts && (job == WJ_Build_Mines)) { - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && - inst->district_id >= 0 && inst->district_id < is->district_count && - ! tile->vtable->m35_Check_Is_Water (tile) && - (tile->CityID < 0) && - ! tile->vtable->m18_Check_Mines (tile, __, 0)) { - int tile_x = 0, tile_y = 0; - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - int owner_civ = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_civ == this->ID) || (owner_civ == 0)) { - if (leader_can_build_district (this, inst->district_id) && - district_resource_prereqs_met (tile, tile_x, tile_y, inst->district_id)) - tr = 1; - } - } - } - } - - if (! tr && is->current_config.enable_districts && is->current_config.enable_bridge_districts && - (job == WJ_Build_Road || job == WJ_Build_Railroad)) { - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { - bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; - if (job == WJ_Build_Road) { - if (! has_road) - tr = 1; - } else { - bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; - if (has_road && ! has_rail) { - int req_tech = p_bic_data->WorkerJobs[job].RequireID; - if ((req_tech < 0) || - ((req_tech != p_bic_data->AdvanceCount) && - Leader_has_tech (&leaders[this->ID], __, req_tech))) { - if (Leader_has_resources_for_job_at (&leaders[this->ID], __, job, tile_x, tile_y)) - tr = 1; - } - } - } - } - } - } - - return tr; -} - -bool __fastcall -patch_Unit_can_hurry_production (Unit * this, int edx, City * city, bool exclude_cheap_improvements) -{ - if (is->current_config.allow_military_leaders_to_hurry_wonders && Unit_has_ability (this, __, UTA_Leader)) { - LeaderKind actual_kind = this->Body.leader_kind; - this->Body.leader_kind = LK_Scientific; - bool tr = Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); - this->Body.leader_kind = actual_kind; - return tr; - } else - return Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); -} - -bool __fastcall -patch_Unit_can_load (Unit * this, int edx, Unit * passenger) -{ - is->can_load_transport = this; - is->can_load_passenger = passenger; - bool tr; - - // If this potential passenger is tied to a different transport, do not allow it to load into this one - int tied_transport_id = -1; - if (is->current_config.limit_unit_loading_to_one_transport_per_turn && - (! Unit_has_ability (this, __, UTA_Army)) && - itable_look_up (&is->unit_transport_ties, passenger->Body.ID, &tied_transport_id) && - (this->Body.ID != tied_transport_id)) - tr = false; - - else - tr = Unit_can_load (this, __, passenger); - - is->can_load_transport = is->can_load_passenger = NULL; - return tr; -} - -void __fastcall -patch_Unit_load (Unit * this, int edx, Unit * transport) -{ - Unit_load (this, __, transport); - - // Tie the unit to the transport if configured to do so - if (is->current_config.limit_unit_loading_to_one_transport_per_turn && ! Unit_has_ability (transport, __, UTA_Army)) - itable_insert (&is->unit_transport_ties, this->Body.ID, transport->Body.ID); -} - -bool -any_enemies_near (Leader const * me, int tile_x, int tile_y, enum UnitTypeClasses class, int num_tiles) -{ - bool tr = false; - FOR_TILES_AROUND (tai, num_tiles, tile_x, tile_y) { - int enemy_on_this_tile = 0; - FOR_UNITS_ON (uti, tai.tile) { - UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; - if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0) && - (((int)class < 0) || (unit_type->Unit_Class == class))) { - if (me->At_War[uti.unit->Body.CivID]) { - if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { - enemy_on_this_tile = 1; - break; - } - } else - break; - } - } - if (enemy_on_this_tile) { - tr = true; - break; - } - } - return tr; -} - -bool -any_enemies_near_unit (Unit * unit, int num_tiles) -{ - UnitType * unit_type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - return any_enemies_near (&leaders[unit->Body.CivID], unit->Body.X, unit->Body.Y, unit_type->Unit_Class, num_tiles); -} - -void __fastcall -patch_Unit_ai_move_artillery (Unit * this) -{ - if ((! is->current_config.use_offensive_artillery_ai) || - ((this->Body.UnitTypeID < 0) || (this->Body.UnitTypeID >= p_bic_data->UnitTypeCount))) // Check for invalid unit type id which appears sometimes, IDK why - goto base_impl; - - Tile * on_tile = tile_at (this->Body.X, this->Body.Y); - City * in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); - UnitType const * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - int num_escorters_req = this->vtable->eval_escort_requirement (this); - - if ((in_city == NULL) || (count_escorters (this) >= num_escorters_req)) - goto base_impl; - - // Don't assign escort if there are any enemies around because in that case it might be a serious mistake to take a defender out of the city - if (any_enemies_near_unit (this, 37)) - goto base_impl; - - // Find the strongest healthy defender the city has and assign that unit as an escort but make sure doing so doesn't leave the city - // defenseless. I think picking the strongest defender is the right choice here because the artillery pair is more likely to come under - // attack than a city and also leaving obsolete units in the city gives them a chance to upgrade. - int num_defenders = 0; - Unit * best_defender = NULL; - int best_defender_strength = -1; - FOR_UNITS_ON (uti, on_tile) { - Unit_Body * body = &uti.unit->Body; - UnitType * type = &p_bic_data->UnitTypes[body->UnitTypeID]; - if ((type->AI_Strategy & UTAI_Defence) && - (! UnitType_has_ability (type, __, UTA_Immobile)) && - (body->Damage == 0) && - ((body->UnitState == 0) || (body->UnitState == UnitState_Fortifying)) && - (body->escortee < 0)) { - num_defenders++; - int str = type->Defence * Unit_get_max_hp (uti.unit); - if (str > best_defender_strength) { - best_defender = uti.unit; - best_defender_strength = str; - } - } - } - if ((num_defenders >= 2) && (best_defender != NULL)) { - Unit_set_state (best_defender, __, 0); - Unit_set_escortee (best_defender, __, this->Body.ID); - } - -base_impl: - Unit_ai_move_artillery (this); - - // Recompute these since the unit might have moved - on_tile = tile_at (this->Body.X, this->Body.Y); - in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); - - // Load the unit into a transport for a naval invasion if it's just sitting in a city with nothing else to do - if (is->current_config.use_offensive_artillery_ai && - (in_city != NULL) && - (this->Body.Moves == 0) && - (this->Body.UnitState == UnitState_Fortifying) && - (this->Body.Container_Unit < 0)) { - Unit * transport = Unit_find_transport (this, __, this->Body.X, this->Body.Y); - if (transport != NULL) { - - int transport_capacity = p_bic_data->UnitTypes[transport->Body.UnitTypeID].Transport_Capacity; - int units_in_transport, arty_in_transport; { - units_in_transport = arty_in_transport = 0; - FOR_UNITS_ON (uti, on_tile) - if (uti.unit->Body.Container_Unit == transport->Body.ID) { - units_in_transport++; - arty_in_transport += (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].AI_Strategy & UTAI_Artillery) != 0; - } - } - - // Check that there's space for the arty unit and an escort, and that the transport does not have more than one arty per three - // spaces so we're less likely to assemble invasion forces composed of nothing but artillery. - if ((units_in_transport + 2 <= transport_capacity) && - (arty_in_transport < not_below (1, transport_capacity / 3))) { - Unit_set_escortee (this, __, -1); - patch_Unit_load (this, __, transport); - } - } - } -} - -// Estimates the number of turns necessary to move the given unit to the given tile and writes it to *out_num_turns. Returns 0 if there is no path -// from the unit's current position to the given tile, 1 otherwise. -int -estimate_travel_time (Unit * unit, int to_tile_x, int to_tile_y, int * out_num_turns) -{ - int dist_in_mp; - patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, to_tile_x, to_tile_y, unit, unit->Body.CivID, 1, &dist_in_mp); - dist_in_mp += unit->Body.Moves; // Add MP already spent this turn to the distance - int max_mp = patch_Unit_get_max_move_points (unit); - if ((dist_in_mp >= 0) && (max_mp > 0)) { - *out_num_turns = dist_in_mp / max_mp; - return 1; - } else - return 0; // No path or unit cannot move -} - -City * -find_nearest_established_city (Unit * unit, int continent_id) -{ - int lowest_unattractiveness = INT_MAX; - City * least_unattractive_city = NULL; - FOR_CITIES_OF (coi,unit->Body.CivID) { - Tile * city_tile = tile_at (coi.city->Body.X, coi.city->Body.Y); - if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { - int dist_in_turns; - if (! estimate_travel_time (unit, coi.city->Body.X, coi.city->Body.Y, &dist_in_turns)) - continue; - int unattractiveness = 10 * dist_in_turns; - unattractiveness = (10 + unattractiveness) / (10 + coi.city->Body.Population.Size); - if (coi.city->Body.CultureIncome > 0) - unattractiveness /= 5; - if (unattractiveness < lowest_unattractiveness) { - lowest_unattractiveness = unattractiveness; - least_unattractive_city = coi.city; - } - } - } - return least_unattractive_city; -} - -bool __fastcall -patch_Unit_ai_can_form_army (Unit * this) -{ - int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.patch_ai_can_form_army_without_special_ability && ((type->Special_Actions & build_army_action) == 0)) - return false; - else - return Unit_ai_can_form_army (this); -} - -void __fastcall -patch_Unit_ai_move_leader (Unit * this) -{ - if (! is->current_config.replace_leader_unit_ai) { - Unit_ai_move_leader (this); - return; - } - - Tile * tile = tile_at (this->Body.X, this->Body.Y); - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - - // Disband the unit if it's on a continent with no cities of its civ. This is what the original logic does. - if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { - Unit_disband (this); - return; - } - - // Flee if the unit is near an enemy without adequate escort - int has_adequate_escort; { - int escorter_count = 0; - int any_healthy_escorters = 0; - int index; - for (int escorter_id = Unit_next_escorter_id (this, __, &index, true); escorter_id >= 0; escorter_id = Unit_next_escorter_id (this, __, &index, false)) { - Unit * escorter = get_unit_ptr (escorter_id); - if ((escorter != NULL) && (escorter->Body.X == this->Body.X) && (escorter->Body.Y == this->Body.Y)) { - escorter_count++; - int remaining_health = Unit_get_max_hp (escorter) - escorter->Body.Damage; - any_healthy_escorters |= (remaining_health >= 3) || (escorter->Body.Damage == 0); - } - } - has_adequate_escort = (escorter_count > 0) && any_healthy_escorters; - } - if ((! has_adequate_escort) && any_enemies_near_unit (this, 49)) { - Unit_set_state (this, __, UnitState_Fleeing); - bool done = this->vtable->work (this); - if (done || (this->Body.UnitState != 0)) - return; - } - - // Move along path if the unit already has one set - byte next_move = Unit_pop_next_move_from_path (this); - if (next_move > 0) { - this->vtable->Move (this, __, next_move, 0); - return; - } - - // Start a science age if we can - // It would be nice to compute a value for this and compare it to the option of rushing production but it's hard to come up with a valuation - if (is->current_config.patch_science_age_bug && Unit_ai_can_start_science_age (this)) { - Unit_start_science_age (this); - return; - } - - // Estimate the value of creating an army. First test if that's even a possiblity and if not leave the value at -1 so rushing production is - // always preferable (note we can't use Unit_ai_can_form_army for this b/c it returns false for units not in a city). The value of forming - // an army is "infinite" if we don't already have one and otherwise it depends on the army unit's shield cost +/- 25% for each point of - // aggression divided by the number of armies already in the field. - int num_armies = leaders[this->Body.CivID].Armies_Count; - int form_army_value = -1; - int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits - if ((this->Body.leader_kind & LK_Military) && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & build_army_action) && - ((num_armies + 1) * p_bic_data->General.ArmySupportCities <= leaders[this->Body.CivID].Cities_Count) && - (p_bic_data->General.BuildArmyUnitID >= 0) && - (p_bic_data->General.BuildArmyUnitID < p_bic_data->UnitTypeCount)) { - if (num_armies < 1) - form_army_value = INT_MAX; - else { - form_army_value = p_bic_data->UnitTypes[p_bic_data->General.BuildArmyUnitID].Cost; - int aggression_level = p_bic_data->Races[leaders[this->Body.CivID].RaceID].AggressionLevel; // aggression level varies between -2 and +2 - form_army_value = (form_army_value * (4 + aggression_level)) / 4; - if (num_armies > 1) - form_army_value /= num_armies; - } - } - - // Estimate the value of rushing production in every city on this continent and remember the highest one - City * best_rush_loc = NULL; - int best_rush_value = -1; - FOR_CITIES_OF (coi, this->Body.CivID) { - City * city = coi.city; - Tile * city_tile = tile_at (city->Body.X, city->Body.Y); - if ((continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) && - patch_Unit_can_hurry_production (this, __, city, false)) { - // Base value is equal to the number of shields rushing would save - int value = City_get_order_cost (city) - City_get_order_progress (city) - city->Body.ProductionIncome; - if (value <= 0) - continue; - - // Consider distance: Reduce the value by the number of shields produced while the leader is en route to rush. - int dist_in_turns; - if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) - continue; // no path or unit cannot move - value -= dist_in_turns * city->Body.ProductionIncome; - if (value <= 0) - continue; - - // Consider corruption: Scale down the value of rushing an improvement by the corruption rate of the city. - // This is to reflect the fact that infrastructure is more valuable in less corrupt cities. But do not apply - // this to wonders since their benefit is in most cases not lessened by local corruption. - Improvement * improv = (city->Body.Order_Type == COT_Improvement) ? &p_bic_data->Improvements[city->Body.Order_ID] : NULL; - int is_wonder = (improv != NULL) && (0 != (improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder))); - if ((improv != NULL) && (! is_wonder)) { - int good_shields = city->Body.ProductionIncome; - int corrupt_shields = city->Body.ProductionLoss; - if (good_shields + corrupt_shields > 0) - value = (value * good_shields) / (good_shields + corrupt_shields); - else - continue; - } - - if ((value > 0) && (value > best_rush_value)) { - best_rush_loc = city; - best_rush_value = value; - } - } - } - - // Hurry production or form an army depending on the estimated values of doing so. We might have to move to a (different) city if that's where - // we want to rush production or if we want to form an army but aren't already in a city. - City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); - City * moving_to_city = NULL; - if ((best_rush_loc != NULL) && (best_rush_value > form_army_value)) { - if (best_rush_loc == in_city) { - Unit_hurry_production (this); - return; - } else - moving_to_city = best_rush_loc; - } else if ((form_army_value > -1) && patch_Unit_ai_can_form_army (this)) { - Unit_form_army (this); - return; - } else if (in_city == NULL) { - // Nothing to do. Try to find a close, established city to move to & wait in. - moving_to_city = find_nearest_established_city (this, continent_id); - } - if (moving_to_city) { - int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); - if (first_move > 0) { - Unit_set_escortee (this, __, -1); - this->vtable->Move (this, __, first_move, 0); - return; - } - } - - // Nothing to do, nowhere to go, just fortify in place. - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -int -measure_strength_in_army (UnitType * type) -{ - return ((type->Attack + type->Defence) * (4 + type->Hit_Point_Bonus)) / 4; -} - -bool __fastcall -patch_impl_ai_is_good_army_addition (Unit * this, int edx, Unit * candidate) -{ - if (! is->current_config.fix_ai_army_composition) - return impl_ai_is_good_army_addition (this, __, candidate); - - UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - if (((candidate_type->AI_Strategy & UTAI_Offence) == 0) || - UnitType_has_ability (candidate_type, __, UTA_Hidden_Nationality)) - return false; - - int num_units_in_army = 0, - army_min_speed = INT_MAX, - army_min_strength = INT_MAX; - FOR_UNITS_ON (uti, tile) { - if (uti.unit->Body.Container_Unit == this->Body.ID) { - num_units_in_army++; - int movement = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Movement; - if (movement < army_min_speed) - army_min_speed = movement; - int member_strength = measure_strength_in_army (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]); - if (member_strength < army_min_strength) - army_min_strength = member_strength; - } - } - - return (num_units_in_army == 0) || - ((candidate_type->Movement >= army_min_speed) && - (measure_strength_in_army (candidate_type) >= army_min_strength)); -} - -int -rate_artillery (UnitType * type) -{ - int tr = type->Attack + type->Defence + 2 * type->Bombard_Strength * type->FireRate; - - // include movement - int moves = type->Movement; - if (moves >= 2) - tr = tr * (moves + 1) / 2; - - // include range - int range = type->Bombard_Range; - if (range >= 2) - tr = tr * (range + 1) / 2; - - // include extra hp - if (type->Hit_Point_Bonus > 0) - tr = tr * (4 + type->Hit_Point_Bonus) / 4; - - return tr; -} - -int -rate_bomber (UnitType * type) -{ - int tr = type->Bombard_Strength * type->FireRate + type->Defence; - - // include range - tr = tr * (10 + type->OperationalRange) / 10; - - // include cost - tr = (tr * 100) / (100 + type->Cost); - - // include abilities - if (UnitType_has_ability (type, __, UTA_Blitz)) - tr = tr * (type->Movement + 1) / 2; - if (UnitType_has_ability (type, __, UTA_Lethal_Land_Bombardment)) - tr = tr * 3 / 2; - if (UnitType_has_ability (type, __, UTA_Lethal_Sea_Bombardment)) - tr = tr * 5 / 4; - if (UnitType_has_ability (type, __, UTA_Stealth)) - tr = tr * 3 / 2; - - // include extra hp - if (type->Hit_Point_Bonus > 0) - tr = tr * (4 + type->Hit_Point_Bonus) / 4; - - return tr; -} - -bool __fastcall -patch_City_can_build_unit (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) -{ - bool base = City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); - - if (base) { - // Apply building prereqs - int building_prereq; - if (itable_look_up (&is->current_config.building_unit_prereqs, unit_type_id, &building_prereq)) { - // If the prereq is an encoded building ID - if (building_prereq & 1) { - if (! has_active_building (this, building_prereq >> 1)) - return false; - - // Else it's a pointer to a list of building IDs - } else { - int * list = (int *)building_prereq; - for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) - if ((list[n] >= 0) && ! has_active_building (this, list[n])) - return false; - } - } - - // Apply unit type limit - int available; - if (get_available_unit_count (&leaders[this->Body.CivID], unit_type_id, &available) && (available <= 0)) - return false; - } - - if (is->current_config.enable_districts) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - - // Bail if tech reqs are not met - int prereq_id = type->AdvReq; - if (prereq_id >= 0 && ! Leader_has_tech (&leaders[this->Body.CivID], __, prereq_id)) - return false; - - if (! Leader_can_build_unit (&leaders[this->Body.CivID], __, unit_type_id, 1, false)) - return false; - - // Superficially allow the AI to choose the unit for scoring and production. - // If a disallowed air/naval unit is chosen in ai_choose_production, we'll swap it out for a feasible fallback later - // after prioritizing the aerodrome/port to be built - if (! is_human && ( - (type->Unit_Class == UTC_Air || city_can_build_district (this, AERODROME_DISTRICT_ID)) || - (type->Unit_Class == UTC_Sea || city_can_build_district (this, PORT_DISTRICT_ID))) - ) - return base; - - // Air units - if (type->Unit_Class == UTC_Air) { - if (is->current_config.enable_aerodrome_districts && is->current_config.air_units_use_aerodrome_districts_not_cities) { - if (find_pending_district_request (this, AERODROME_DISTRICT_ID) != NULL) - return false; - if (! city_can_build_district (this, AERODROME_DISTRICT_ID)) - return false; - return city_has_required_district (this, AERODROME_DISTRICT_ID); - } - // Naval units - } else if (type->Unit_Class == UTC_Sea) { - if (is->current_config.enable_port_districts && is->current_config.naval_units_use_port_districts_not_cities) { - if (find_pending_district_request (this, PORT_DISTRICT_ID) != NULL) - return false; - if (! city_can_build_district (this, PORT_DISTRICT_ID)) - return false; - return city_has_required_district (this, PORT_DISTRICT_ID); - } - } - } - - return base; -} - -int __fastcall -patch_City_get_largest_adjacent_sea_within_work_area (City * this) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - int improv_id = is->current_evaluating_improve_id; - if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { - - // If Coastal Fortress, default to original logic (city must be next to coast) - if (p_bic_data->Improvements[improv_id].Naval_Bombard_Defence > 0) - return City_get_largest_adjacent_sea (this); - } - int lake_size_threshold = 21; - int largest_size = 0; - int largest_continent_id = -1; - FOR_WORK_AREA_AROUND (wai, this->Body.X, this->Body.Y) { - if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { - int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - if (continent->Body.TileCount <= lake_size_threshold && ! is->current_config.enable_canal_districts) - continue; - if (p_bic_data->Map.Continents[continent_id].Body.TileCount > largest_size) { - largest_size = p_bic_data->Map.Continents[continent_id].Body.TileCount; - largest_continent_id = continent_id; - } - } - } - return largest_continent_id; - } - return City_get_largest_adjacent_sea (this); -} - -bool __fastcall -patch_Map_impl_is_near_river_within_work_area (Map * this, int edx, int x, int y, int num_tiles) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - FOR_WORK_AREA_AROUND (wai, x, y) { - if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) { - return true; - } - } - return false; - } - - return this->vtable->is_near_river (this, __, x, y, num_tiles); -} - -bool __fastcall -patch_Map_impl_is_near_lake_within_work_area (Map * this, int edx, int x, int y, int num_tiles) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - int lake_size_threshold = 21; - FOR_WORK_AREA_AROUND (wai, x, y) { - if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { - int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); - if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) - continue; - Continent * continent = &p_bic_data->Map.Continents[continent_id]; - if (continent->Body.TileCount <= lake_size_threshold) - return true; - } - } - return false; - } - - return this->vtable->is_near_lake (this, __, x, y, num_tiles); -} - -bool __fastcall -patch_Map_impl_has_fresh_water_within_work_area (Map * this, int edx, int tile_x, int tile_y) -{ - if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { - int improv_id = is->current_evaluating_improve_id; - if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { - - // If an Aqueduct, default to original logic (city must be next to coast) - if ((p_bic_data->Improvements[improv_id].ImprovementFlags & ITF_Allows_City_Level_2) != 0) - return this->vtable->has_fresh_water (this, __, tile_x, tile_y); - } - if (patch_Map_impl_is_near_river_within_work_area (this, __, tile_x, tile_y, 1)) - return true; - if (patch_Map_impl_is_near_lake_within_work_area (this, __, tile_x, tile_y, 1)) - return true; - return false; - } - - return this->vtable->has_fresh_water (this, __, tile_x, tile_y); -} - -bool -city_meets_district_prereqs_to_build_improvement (City * city, int i_improv, bool apply_strict_rules) -{ - // Different logic for human vs AI players - bool is_human = (*p_human_player_bits & (1 << city->Body.CivID)) != 0; - - Improvement * improv = &p_bic_data->Improvements[i_improv]; - bool is_wonder = is->current_config.enable_wonder_districts && (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)); - if (is_wonder && ! wonder_is_buildable_by_civ (i_improv, city->Body.CivID)) - return false; - - bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; - - // Check if the improvement requires a district - bool needs_district = city_requires_district_for_improvement (city, i_improv, NULL); - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); - - // District is either not needed or already built - if (! needs_district) - return true; - - if (prereq_list == NULL) - return false; - - bool has_buildable_candidate = false; - bool has_wonder_candidate = false; - bool has_non_wonder_candidate = false; - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) - continue; - has_buildable_candidate = true; - if (district_id == WONDER_DISTRICT_ID) - has_wonder_candidate = true; - else - has_non_wonder_candidate = true; - } - if (! has_buildable_candidate) - return false; - - // Check that we have the necessary terrain - bool has_terrain_for_district = false; - bool has_terrain_for_wonder = false; - bool has_river_terrain_for_district = false; - FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { - Tile * tile = wai.tile; - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) - continue; - if (! tile_suitable_for_district (tile, district_id, city, NULL)) - continue; - - if (is_wonder && district_id == WONDER_DISTRICT_ID) { - if (! wonder_is_buildable_on_tile (tile, i_improv)) - continue; - } - - has_terrain_for_district = true; - if (requires_river && tile->vtable->m37_Get_River_Code (tile) != 0) - has_river_terrain_for_district = true; - - if (is_wonder && district_id == WONDER_DISTRICT_ID) { - if (! requires_river || tile->vtable->m37_Get_River_Code (tile) != 0) { - has_terrain_for_wonder = true; - } - } - } - } - - bool requires_wonder_terrain = is_wonder && has_wonder_candidate && ! has_non_wonder_candidate; - if (! has_terrain_for_district || - (requires_river && ! has_river_terrain_for_district) || - (requires_wonder_terrain && ! has_terrain_for_wonder)) { - return false; - } - - // If human has everything needed except a built district (which is buildable), allow relaxed checks so UI can gray entry out - if (is_human) { - return ! apply_strict_rules; - } - - // If AI already has a pending district request for this required district, return false - // to prevent wasting a turn trying to choose this improvement - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - if (find_pending_district_request (city, district_id) != NULL) - return false; - } - - // Superficially allow the AI to choose the improvement for scoring and production. - // If a disallowed improvement is chosen in ai_choose_production, we'll swap it out for a feasible fallback later - // after prioritizing the district to be built - return true; -} - -bool __fastcall -patch_City_can_build_improvement (City * this, int edx, int i_improv, bool apply_strict_rules) -{ - is->current_evaluating_improve_id = i_improv; - - char ss[200]; - snprintf (ss, sizeof ss, "patch_City_can_build_improvement:evaluating improvement %s (%d)\n", - p_bic_data->Improvements[i_improv].Name.S, i_improv); - (*p_OutputDebugStringA) (ss); - - // First defer to the base game's logic - bool base = City_can_build_improvement (this, __, i_improv, apply_strict_rules); - if (! base) return false; - if (! is->current_config.enable_districts) return base; - - bool can_build = city_meets_district_prereqs_to_build_improvement (this, i_improv, apply_strict_rules); - is->current_evaluating_improve_id = -1; - - return can_build; -} - -bool -ai_handle_district_production_requirements (City * city, City_Order * out) -{ - clear_best_feasible_order (city); - bool swapped_to_fallback = false; - City_Order fallback_order = {0}; - int required_district_id = -1; - bool should_mark_district = false; - - char ss[200]; - - if (is->current_config.enable_districts && - (out->OrderID >= 0)) { - bool needs_wonder_district = false; - bool requires_district = false; - bool needs_district = false; - - if ((out->OrderType == COT_Unit) && - (out->OrderID < p_bic_data->UnitTypeCount)) { - UnitType * type = &p_bic_data->UnitTypes[out->OrderID]; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { - required_district_id = AERODROME_DISTRICT_ID; - needs_district = true; - should_mark_district = true; - } else if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (city, PORT_DISTRICT_ID))) { - required_district_id = PORT_DISTRICT_ID; - needs_district = true; - should_mark_district = true; - } - } else if ((out->OrderType == COT_Improvement) && - (out->OrderID < p_bic_data->ImprovementsCount)) { - // Check if AI is trying to build a wonder without an incomplete wonder district - requires_district = city_requires_district_for_improvement (city, out->OrderID, &required_district_id); - if (is->current_config.enable_wonder_districts) { - Improvement * improv = &p_bic_data->Improvements[out->OrderID]; - if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && - (! city_has_wonder_district_with_no_completed_wonder (city, out->OrderID))) { - snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: City %d (%s) needs wonder district to build wonder improvement %d\n", - city->Body.ID, city->Body.CityName, out->OrderID); - (*p_OutputDebugStringA) (ss); - needs_wonder_district = true; - if (required_district_id < 0) { - required_district_id = WONDER_DISTRICT_ID; - } - } - } - needs_district = needs_wonder_district || requires_district; - } - - if (needs_district) { - struct ai_best_feasible_order * stored = get_best_feasible_order (city); - if (stored != NULL) { - bool fallback_is_feasible = true; - if (stored->order.OrderType == COT_Improvement) { - if ((stored->order.OrderID < 0) || - (stored->order.OrderID >= p_bic_data->ImprovementsCount)) - fallback_is_feasible = false; - - // Check if fallback requires a district the city doesn't have - if (fallback_is_feasible && - city_requires_district_for_improvement (city, stored->order.OrderID, NULL)) - fallback_is_feasible = false; - - // If original order was a wonder, ensure fallback is not also a wonder - if (fallback_is_feasible && needs_wonder_district) { - Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; - if (fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - fallback_is_feasible = false; - } - - // If fallback is a wonder, check if it has an incomplete wonder district - if (fallback_is_feasible && is->current_config.enable_wonder_districts) { - Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; - if ((fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && - (! city_has_wonder_district_with_no_completed_wonder (city, stored->order.OrderID))) - fallback_is_feasible = false; - } - } else if (stored->order.OrderType == COT_Unit) { - if ((stored->order.OrderID < 0) || - (stored->order.OrderID >= p_bic_data->UnitTypeCount)) - fallback_is_feasible = false; - if (fallback_is_feasible) { - UnitType * type = &p_bic_data->UnitTypes[stored->order.OrderID]; - if (type->Unit_Class != UTC_Land) - fallback_is_feasible = false; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (city, AERODROME_DISTRICT_ID))) - fallback_is_feasible = false; - if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (city, PORT_DISTRICT_ID))) - fallback_is_feasible = false; - } - } else - fallback_is_feasible = false; - - if (fallback_is_feasible) { - if (out->OrderType == COT_Improvement) { - // Remember pending building order for any improvement that requires a district - snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: Remembering fallback pending building order for city %d (%s): order type %d id %d\n", - city->Body.ID, city->Body.CityName, out->OrderType, out->OrderID); - (*p_OutputDebugStringA) (ss); - remember_pending_building_order (city, out->OrderID); - } - - fallback_order = stored->order; - swapped_to_fallback = true; - } - } - } - } - - if (swapped_to_fallback) { - *out = fallback_order; - } - if ((swapped_to_fallback || should_mark_district) && (required_district_id >= 0)) - mark_city_needs_district (city, required_district_id); - - clear_best_feasible_order (city); - return swapped_to_fallback; -} - -void __fastcall -patch_City_ai_choose_production (City * this, int edx, City_Order * out) -{ - is->ai_considering_production_for_city = this; - City_ai_choose_production (this, __, out); - - char ss[200]; - snprintf (ss, sizeof ss, "patch_City_ai_choose_production: City %d (%s) chose order type %d id %d\n", - this->Body.ID, this->Body.CityName, out->OrderType, out->OrderID); - (*p_OutputDebugStringA) (ss); - - if (is->current_config.enable_districts) { - if (ai_handle_district_production_requirements (this, out)) { - return; - } - } - - Leader * me = &leaders[this->Body.CivID]; - int arty_ratio = is->current_config.ai_build_artillery_ratio; - int bomber_ratio = is->current_config.ai_build_bomber_ratio; - - // Check if AI-build-more-artillery mod option is activated and this city is building something that we might want to switch to artillery - if ((arty_ratio > 0) && - (out->OrderType == COT_Unit) && - (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && - (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & (UTAI_Offence | UTAI_Defence))) { - - // Check how many offense/defense/artillery units this AI has already built. We'll only force it to build arty if it has a minimum - // of one defender per city, one attacker per two cities, and of course if it's below the ratio limit. - int num_attackers = me->AI_Strategy_Unit_Counts[0], - num_defenders = me->AI_Strategy_Unit_Counts[1], - num_artillery = me->AI_Strategy_Unit_Counts[2]; - if ((num_attackers > me->Cities_Count / 2) && - (num_defenders > me->Cities_Count) && - (100*num_artillery < arty_ratio*(num_attackers + num_defenders))) { - - // Loop over all build options to determine the best artillery unit available. Record its attack power and also find & record - // the highest attack power available from any offensive unit so we can compare them. - int best_arty_type_id = -1, - best_arty_rating = -1, - best_arty_strength = -1, - best_attacker_strength = -1; - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if ((type->AI_Strategy & (UTAI_Artillery | UTAI_Offence)) && - patch_City_can_build_unit (this, __, n, 1, 0, 0)) { - if (type->AI_Strategy & UTAI_Artillery) { - int this_rating = rate_artillery (&p_bic_data->UnitTypes[n]); - if (this_rating > best_arty_rating) { - best_arty_type_id = n; - best_arty_rating = this_rating; - best_arty_strength = type->Bombard_Strength * type->FireRate; - } - } else { // attacker - int this_strength = (type->Attack * (4 + type->Hit_Point_Bonus)) / 4; - if (this_strength > best_attacker_strength) - best_attacker_strength = this_strength; - } - } - } - - // Randomly switch city production to the artillery unit if we found one - if (best_arty_type_id >= 0) { - int chance = 12 * arty_ratio / 10; - - // Scale the chance of switching by the ratio of the attack power the artillery would provide to the attack power - // of the strongest offensive unit. This way the AI will rapidly build artillery up to the ratio limit only when - // artillery are its best way of dealing damage. - // Some example numbers: - // | Best attacker (str) | Best arty (str) | Chance w/ ratio = 20, damage% = 50 - // | Swordsman (3) | Catapult (4) | 16 - // | Knight (4) | Trebuchet (6) | 18 - // | Cavalry (6) | Cannon (8) | 16 - // | Cavalry (6) | Artillery (24) | 48 - // | Tank (16) | Artillery (24) | 18 - if (best_attacker_strength > 0) - chance = (chance * best_arty_strength * is->current_config.ai_artillery_value_damage_percent) / (best_attacker_strength * 100); - - if (rand_int (p_rand_object, __, 100) < chance) - out->OrderID = best_arty_type_id; - } - } - - } else if ((bomber_ratio > 0) && - (out->OrderType == COT_Unit) && - (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && - (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & UTAI_Air_Defence)) { - int num_fighters = me->AI_Strategy_Unit_Counts[7], - num_bombers = me->AI_Strategy_Unit_Counts[6]; - if (100 * num_bombers < bomber_ratio * num_fighters) { - int best_bomber_type_id = -1, - best_bomber_rating = -1; - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if ((type->AI_Strategy & UTAI_Air_Bombard) && - patch_City_can_build_unit (this, __, n, 1, 0, 0)) { - int this_rating = rate_bomber (&p_bic_data->UnitTypes[n]); - if (this_rating > best_bomber_rating) { - best_bomber_type_id = n; - best_bomber_rating = this_rating; - } - } - } - - if (best_bomber_type_id >= 0) { - int chance = 12 * bomber_ratio / 10; - if (rand_int (p_rand_object, __, 100) < chance) - out->OrderID = best_bomber_type_id; - } - } - } - - is->ai_considering_production_for_city = NULL; -} - -int __fastcall -patch_Unit_disembark_passengers (Unit * this, int edx, int tile_x, int tile_y) -{ - // Break any escort relationships if the escorting unit can't move onto the target tile. This prevents a freeze where the game continues - // trying to disembark units because an escortee looks like it could be disembarked except it can't because it won't move if its escorter - // can't be moved first. - Tile * tile = tile_at (this->Body.X, this->Body.Y), - * target = tile_at (tile_x , tile_y); - if (is->current_config.patch_blocked_disembark_freeze && (tile != NULL) && (target != NULL)) { - enum SquareTypes target_terrain = target->vtable->m50_Get_Square_BaseType (target); - FOR_UNITS_ON (uti, tile) { - Unit * escortee = get_unit_ptr (uti.unit->Body.escortee); - if ( (escortee != NULL) - && (uti.unit->Body.Container_Unit == this->Body.ID) - && (escortee->Body.Container_Unit == this->Body.ID) - && ( UnitType_has_ability (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID], __, UTA_Immobile) - || ( is->current_config.disallow_trespassing - && check_trespassing (uti.unit->Body.CivID, tile, target) - && ! is_allowed_to_trespass (uti.unit)) - || Unit_is_terrain_impassable (uti.unit, __, target_terrain))) - Unit_set_escortee (uti.unit, __, -1); - } - } - - return Unit_disembark_passengers (this, __, tile_x, tile_y); -} - -// Returns whether or not the current deal being offered to the AI on the trade screen would be accepted. How advantageous the AI thinks the -// trade is for itself is stored in out_their_advantage if it's not NULL. This advantage is measured in gold, if it's positive it means the -// AI thinks it's gaining that much value from the trade and if it's negative it thinks it would be losing that much. I don't know what would -// happen if this function were called while the trade screen is not active. -bool -is_current_offer_acceptable (int * out_their_advantage) -{ - int their_id = p_diplo_form->other_party_civ_id; - - DiploMessage consideration = Leader_consider_trade ( - &leaders[their_id], - __, - &p_diplo_form->our_offer_lists[their_id], - &p_diplo_form->their_offer_lists[their_id], - p_main_screen_form->Player_CivID, - 0, true, 0, 0, - out_their_advantage, - NULL, NULL); - - return consideration == DM_AI_ACCEPT; -} - -// Adds an offer of gold to the list and returns it. If one already exists in the list, returns a pointer to it. -TradeOffer * -offer_gold (TradeOfferList * list, int is_lump_sum, int * is_new_offer) -{ - if (list->length > 0) - for (TradeOffer * offer = list->first; offer != NULL; offer = offer->next) - if ((offer->kind == 7) && (offer->param_1 == is_lump_sum)) { - *is_new_offer = 0; - return offer; - } - - TradeOffer * tr = new (sizeof *tr); - *tr = (struct TradeOffer) { - .vtable = p_trade_offer_vtable, - .kind = 7, // TODO: Replace with enum - .param_1 = is_lump_sum, - .param_2 = 0, - .next = NULL, - .prev = NULL - }; - - if (list->length > 0) { - tr->prev = list->last; - list->last->next = tr; - list->last = tr; - list->length += 1; - } else { - list->last = list->first = tr; - list->length = 1; - } - - *is_new_offer = 1; - return tr; -} - -// Removes offer from list of offers but does not free it. Assumes offer is in the list. -void -remove_offer (TradeOfferList * list, TradeOffer * offer) -{ - if (list->length == 1) { - list->first = list->last = NULL; - list->length = 0; - } else if (list->length > 1) { - TradeOffer * prev = offer->prev, * next = offer->next; - if (prev) - prev->next = next; - if (next) - next->prev = prev; - if (list->first == offer) - list->first = next; - if (list->last == offer) - list->last = prev; - list->length -= 1; - } - offer->prev = offer->next = NULL; -} - -void __fastcall -patch_PopupForm_set_text_key_and_flags (PopupForm * this, int edx, char * script_path, char * text_key, int param_3, int param_4, int param_5, int param_6) -{ - int * p_stack = (int *)&script_path; - int ret_addr = p_stack[-1]; - - int is_initial_gold_trade = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_INITIAL_GOLD_OFFER_RETURN), - is_modifying_gold_trade = (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN ) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_OFFER_RETURN); - - // This function gets called from all over the place, check that it's being called to setup the set gold amount popup in the trade screen - if (is->current_config.autofill_best_gold_amount_when_trading && (is_initial_gold_trade || is_modifying_gold_trade)) { - int asking = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN); - int is_lump_sum = is_initial_gold_trade ? - p_stack[TRADE_GOLD_SETTER_IS_LUMP_SUM_OFFSET] : // Read this variable from the caller's frame - is->modifying_gold_trade->param_1; - - int their_id = p_diplo_form->other_party_civ_id, - our_id = p_main_screen_form->Player_CivID; - - // This variable will store the result of the optimization process and it's what will be used as the final amount presented to the - // player in the popup and left in the TradeOffer object (if applicable). Default to zero for new offers and the previous amount when - // modifying an offer. When modifying, we also zero the amount on the table b/c the optimization process only works properly from that - // starting point. - int best_amount = 0; - if (is_modifying_gold_trade) { - best_amount = is->modifying_gold_trade->param_2; - is->modifying_gold_trade->param_2 = 0; - } - - int their_advantage; - bool is_original_acceptable = is_current_offer_acceptable (&their_advantage); - - // if (we're asking for money on an acceptable trade and are offering something) OR (we're offering money on an unacceptable trade and - // are asking for something) - if (( asking && is_original_acceptable && (p_diplo_form->our_offer_lists[their_id] .length > 0)) || - ((! asking) && (! is_original_acceptable) && (p_diplo_form->their_offer_lists[their_id].length > 0))) { - - TradeOfferList * offers = asking ? &p_diplo_form->their_offer_lists[their_id] : &p_diplo_form->our_offer_lists[their_id]; - int test_offer_is_new; - TradeOffer * test_offer = offer_gold (offers, is_lump_sum, &test_offer_is_new); - - // When asking for gold, start at zero and work upwards. When offering gold it's more complicated. For lump sum - // offers, start with our entire treasury and work downward. For GPT offers, start with an upper bound and work - // downward. The upper bound depends on how much the AI thinks it's losing on the trade (in gold) divided by 20 - // (b/c 20 turn deal) with a lot of extra headroom just to make sure. - int starting_amount; { - if (asking) - starting_amount = 0; - else { - if (is_lump_sum) - starting_amount = leaders[our_id].Gold_Encoded + leaders[our_id].Gold_Decrement; - else { - int guess = not_below (0, 0 - their_advantage) / 20; - starting_amount = 10 + guess * 2; - } - } - } - - // Check if optimization is still possible. It's not if we're offering gold and our maximum offer is unacceptable - test_offer->param_2 = starting_amount; - if (asking || is_current_offer_acceptable (NULL)) { - - best_amount = starting_amount; - for (int step_size = asking ? 1000 : -1000; step_size != 0; step_size /= 10) { - test_offer->param_2 = best_amount; - while (1) { - test_offer->param_2 += step_size; - if (test_offer->param_2 < 0) - break; - else if (is_current_offer_acceptable (NULL)) - best_amount = test_offer->param_2; - else - break; - } - } - } - - // Annoying little edge case: The limitation on AIs not to trade more than their entire treasury is handled in the - // interface not the trade evaluation logic so we have to limit our gold request here to their treasury (otherwise - // the amount will default to how much they would pay if they had infinite money). - int their_treasury = leaders[their_id].Gold_Encoded + leaders[their_id].Gold_Decrement; - if (asking && is_lump_sum && (best_amount > their_treasury)) - best_amount = their_treasury; - - // Restore the trade table to its original state. Remove & free test_offer if it was newly created, otherwise put back its - // original amount. - if (test_offer_is_new) { - remove_offer (offers, test_offer); - test_offer->vtable->destruct (test_offer, __, 1); - } - - // If we're offering gold on a trade that's already acceptable, the optimal amount is zero. We must handle this explicitly in case - // we're modifying an amount already on the table. If we didn't, the above condition wouldn't optimize the amount and we'd default to - // the original amount. - } else if ((! asking) && is_original_acceptable) - best_amount = 0; - - if (is_modifying_gold_trade) - is->modifying_gold_trade->param_2 = best_amount; - snprintf (is->ask_gold_default, sizeof is->ask_gold_default, "%d", best_amount); - is->ask_gold_default[(sizeof is->ask_gold_default) - 1] = '\0'; - PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, (int)is->ask_gold_default, param_5, param_6); - } else - PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, param_4, param_5, param_6); -} - -CityLocValidity __fastcall -patch_Map_check_city_location (Map *this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile) -{ - if (is->current_config.enable_natural_wonders) { - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { - return CLV_BLOCKED; - } - } - } - - int min_sep = is->current_config.minimum_city_separation; - CityLocValidity base_result = Map_check_city_location (this, __, tile_x, tile_y, civ_id, check_for_city_on_tile); - - // If minimum separation is one, make no change - if (min_sep == 1) - return base_result; - - // If minimum separation is <= 0, ignore the CITY_TOO_CLOSE objection to city placement unless the location is next to a city belonging to - // another civ and the settings forbid founding there. - else if ((min_sep <= 0) && (base_result == CLV_CITY_TOO_CLOSE)) { - if (is->current_config.disallow_founding_next_to_foreign_city) - for (int n = 1; n <= 8; n++) { - int x, y; - get_neighbor_coords (&p_bic_data->Map, tile_x, tile_y, n, &x, &y); - City * city = city_at (x, y); - if ((city != NULL) && (city->Body.CivID != civ_id)) - return CLV_CITY_TOO_CLOSE; - } - return CLV_OK; - - // If we have an increased separation we might have to exclude some locations the base code allows. - } else if ((min_sep > 1) && (base_result == CLV_OK)) { - // Check tiles around (x, y) for a city. Because the base result is CLV_OK, we don't have to check neighboring tiles, just those at - // distance 2, 3, ... up to (an including) the minimum separation - for (int dist = 2; dist <= min_sep; dist++) { - - // vertices stores the unwrapped coords of the tiles at the vertices of the square of tiles at distance "dist" around - // (tile_x, tile_y). The order of the vertices is north, east, south, west. - struct vertex { - int x, y; - } vertices[4] = { - {tile_x , tile_y - 2*dist}, - {tile_x + 2*dist, tile_y }, - {tile_x , tile_y + 2*dist}, - {tile_x - 2*dist, tile_y } - }; - - // neighbor index for direction of tiles along edge starting from each vertex - // values correspond to directions: southeast, southwest, northwest, northeast - int edge_dirs[4] = {3, 5, 7, 1}; - - // Loop over verts and check tiles along their associated edges. The N vert is associated with the NE edge, the E vert with - // the SE edge, etc. - for (int vert = 0; vert < 4; vert++) { - wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); - int dx, dy; - neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); - for (int j = 0; j < 2*dist; j++) { // loop over tiles along this edge - int cx = vertices[vert].x + j * dx, - cy = vertices[vert].y + j * dy; - wrap_tile_coords (&p_bic_data->Map, &cx, &cy); - if (city_at (cx, cy)) - return CLV_CITY_TOO_CLOSE; - } - } - - } - return base_result; - - } else - return base_result; -} - -bool -is_zero_strength (UnitType * ut) -{ - return (ut->Attack == 0) && (ut->Defence == 0); -} - -bool -is_captured (Unit_Body * u) -{ - return (u->RaceID >= 0) && (u->CivID >= 0) && (u->CivID < 32) && leaders[u->CivID].RaceID != u->RaceID; -} - -// Decides whether or not units "a" and "b" are duplicates, i.e., whether they are interchangeable. -// If surface_only is set, the function checks only surface-level characteristics, meaning those that are visible to other players. -bool -are_units_duplicate (Unit_Body * a, Unit_Body * b, bool surface_only) -{ - UnitType * a_type = &p_bic_data->UnitTypes[a->UnitTypeID], - * b_type = &p_bic_data->UnitTypes[b->UnitTypeID]; - - // If only doing a surface comparison, look through the alternate strategy types to the base types. The difference b/w the alt types is only - // their AI strategies, and that isn't considered a surface feature. - if (surface_only) { - while (a_type->alternate_strategy_for_id >= 0) - a_type = &p_bic_data->UnitTypes[a_type->alternate_strategy_for_id]; - while (b_type->alternate_strategy_for_id >= 0) - b_type = &p_bic_data->UnitTypes[b_type->alternate_strategy_for_id]; - } - - // a and b are duplicates "on the surface" if... - bool are_surface_duplicates = - // ... they belong to the same player ... - (a->CivID == b->CivID) && - - // ... they have the same type that is not [a leader OR army] AND not a transport AND ... - (a_type == b_type) && - (! (UnitType_has_ability (a_type, __, UTA_Leader) || UnitType_has_ability (a_type, __, UTA_Army))) && - (a_type->Transport_Capacity == 0) && - - // ... they've taken the same amount of damage AND have the same charm status AND ... - (a->Damage == b->Damage) && (a->charmed == b->charmed) && - - // ... they're either both fortified or both not AND ... - (! (a->UnitState == UnitState_Fortifying) ^ (b->UnitState == UnitState_Fortifying)) && - - // ... [they have the same experience level OR are zero strength units] AND ... - ((a->Combat_Experience == b->Combat_Experience) || is_zero_strength (a_type)) && - - // ... [they are both not contained in any unit OR they are both contained in the same unit] AND ... - (((a->Container_Unit < 0) && (b->Container_Unit < 0)) || (a->Container_Unit == b->Container_Unit)) && - - // ... neither one is carrying a princess AND ... - ((a->carrying_princess_of_race < 0) && (b->carrying_princess_of_race < 0)) && - - // ... [they are both captured units OR are both native units] AND ... - (! (is_captured (a) ^ is_captured (b))) && - - // ... their custom names are identical. - (0 == strncmp (a->Custom_Name.S, b->Custom_Name.S, sizeof (a->Custom_Name))); - - if ((! are_surface_duplicates) || surface_only) - return are_surface_duplicates; - - // a and b are additionally "deep", i.e. in all ways, duplicates if... - bool are_deep_duplicates = - // ... they've used up the same number of moves AND ... - (a->Moves == b->Moves) && - - // ... they have matching statuses (has attacked this turn, etc.) AND states (is fortified, is doing worker action, etc.) AND automation status AND ... - (a->Status == b->Status) && (a->UnitState == b->UnitState) && (a->automated == b->automated) && - - // ... they have both done the same number of airdrops this turn. - (itable_look_up_or (&is->airdrops_this_turn, a->ID, 0) == itable_look_up_or (&is->airdrops_this_turn, b->ID, 0)); - - return are_deep_duplicates; -} - -bool -is_busy (Unit * unit) -{ - int state = unit->Body.UnitState; - return ((state >= UnitState_Build_Mines) && (state <= UnitState_Explore)) || - (state == UnitState_Auto_Bombard) || (state == UnitState_Auto_Air_Bombard) || - unit->Body.automated; -} - -int __fastcall -patch_Context_Menu_add_item_and_set_color (Context_Menu * this, int edx, int item_id, char * text, int red) -{ - // Initialize the array of duplicate counts. The array is 0x100 items long because that's the maximum number of items a menu can have. - if (is->current_config.group_units_on_right_click_menu && - (is->unit_menu_duplicates == NULL)) { - unsigned dups_size = 0x100 * sizeof is->unit_menu_duplicates[0]; - is->unit_menu_duplicates = malloc (dups_size); - memset (is->unit_menu_duplicates, 0, dups_size); - } - - // Check if this menu item is a valid unit and grab pointers to its info - int unit_id; - Unit_Body * unit_body; - bool disable = false, put_icon = false; - int icon_index = 0; - if ((0 <= (unit_id = item_id - (0x13 + p_bic_data->UnitTypeCount))) && - (NULL != (unit_body = p_units->Units[unit_id].Unit)) && - (unit_body->UnitTypeID >= 0) && (unit_body->UnitTypeID < p_bic_data->UnitTypeCount)) { - - if (is->current_config.group_units_on_right_click_menu) { - // Loop over all existing menu items and check if any of them is a unit that's a duplicate of the one being added - for (int n = 0; n < this->Item_Count; n++) { - Context_Menu_Item * item = &this->Items[n]; - int dup_unit_id = this->Items[n].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount); - Unit_Body * dup_body; - if ((dup_unit_id >= 0) && - (NULL != (dup_body = p_units->Units[dup_unit_id].Unit)) && - are_units_duplicate (unit_body, dup_body, unit_body->CivID != p_main_screen_form->Player_CivID)) { - // The new item is a duplicate of the nth. Mark that in the duplicate counts array and return without actually - // adding the item. It doesn't matter what value we return because the caller doesn't use it. - is->unit_menu_duplicates[n] += 1; - return 0; - } - } - } - - if (unit_body->CivID == p_main_screen_form->Player_CivID) { - Unit * unit = (Unit *)((int)unit_body - offsetof (Unit, Body)); - UnitType * unit_type = &p_bic_data->UnitTypes[unit_body->UnitTypeID]; - bool no_moves_left = unit_body->Moves >= patch_Unit_get_max_move_points (unit); - if (no_moves_left && is->current_config.gray_out_units_on_menu_with_no_remaining_moves) - disable = true; - - // Put an icon next to this unit if we're configured to do so and it's not in an army - Unit * container; - if (is->current_config.put_movement_icons_on_units_on_menu && - ((NULL == (container = get_unit_ptr (unit_body->Container_Unit))) || - (! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)))) { - put_icon = true; - - bool attacker = is_offensive_combat_type (unit_type) || (Unit_has_ability (unit, __, UTA_Army) && (Unit_count_contained_units (unit) >= 1)), - busy = is_busy (unit); - - int icon_set_index = ((int)busy << 1) + (int)(! attacker); - - int icon_row; { - if (no_moves_left) - icon_row = URCMI_CANT_MOVE; - else if (unit_body->Moves == 0) - icon_row = URCMI_UNMOVED; - else if (! attacker) - icon_row = URCMI_MOVED_NO_ATTACK; - else - icon_row = (! has_exhausted_attack (unit)) ? URCMI_MOVED_CAN_ATTACK : URCMI_MOVED_NO_ATTACK; - } - - icon_index = icon_set_index * COUNT_UNIT_RCM_ICONS + icon_row; - } - } - } - - int tr = Context_Menu_add_item_and_set_color (this, __, item_id, text, red); - - if (disable) - Context_Menu_disable_item (this, __, item_id); - - if (put_icon) { - init_unit_rcm_icons (); - if (is->unit_rcm_icon_state == IS_OK) - Context_Menu_put_image_on_item (this, __, item_id, &is->unit_rcm_icons[icon_index]); - } - - return tr; -} - -int __fastcall -patch_Context_Menu_open (Context_Menu * this, int edx, int x, int y, int param_3) -{ - int * p_stack = (int *)&x; - int ret_addr = p_stack[-1]; - - if (is->current_config.enable_named_tiles && - is->named_tile_menu_active) { - int tile_x = is->named_tile_menu_tile_x; - int tile_y = is->named_tile_menu_tile_y; - Tile * tile = tile_at (tile_x, tile_y); - if (tile_can_be_named (tile, tile_x, tile_y)) { - struct named_tile_entry * entry = get_named_tile_entry (tile); - char menu_text[64]; - if ((entry != NULL) && (entry->name[0] != '\0')) - snprintf (menu_text, sizeof menu_text, "%s %s", is->c3x_labels[CL_RENAME_TILE], entry->name); - else - strcpy (menu_text,is->c3x_labels[CL_NAME_TILE]); - if (this->Item_Count > 0) - Context_Menu_add_separator (this, __, 0); - Context_Menu_add_item (this, __, NAMED_TILE_MENU_ID, menu_text, false, (Sprite *)0x0); - } - } - - if (is->current_config.group_units_on_right_click_menu && - (ret_addr == ADDR_OPEN_UNIT_MENU_RETURN) && - (is->unit_menu_duplicates != NULL)) { - - // Change the menu text to include the duplicate counts. This is pretty straight forward except for a couple little issues: we must - // use the game's internal malloc & free for compatibility with the base code and must call a function that widens the menu form, - // as necessary, to accommodate the longer strings. - for (int n = 0; n < this->Item_Count; n++) - if (is->unit_menu_duplicates[n] > 0) { - Context_Menu_Item * item = &this->Items[n]; - unsigned new_text_len = strlen (item->Text) + 20; - char * new_text = civ_prog_malloc (new_text_len); - - // Print entry text including dup count to new_text. Biggest complication here is that we want to print the dup count - // after any leading spaces to preserve indentation. - { - int num_spaces = 0; - while (item->Text[num_spaces] == ' ') - num_spaces++; - snprintf (new_text, new_text_len, "%.*s%dx %s", num_spaces, item->Text, is->unit_menu_duplicates[n] + 1, &item->Text[num_spaces]); - new_text[new_text_len - 1] = '\0'; - } - - civ_prog_free (item->Text); - item->Text = new_text; - Context_Menu_widen_for_text (this, __, new_text); - } - - // Clear the duplicate counts - memset (is->unit_menu_duplicates, 0, 0x100 * sizeof is->unit_menu_duplicates[0]); - } - - return Context_Menu_open (this, __, x, y, param_3); -} - -bool -is_material_unit (UnitType const * type, bool * out_is_pop_else_caravan) -{ - int join_city_action = UCV_Join_City & 0x0FFFFFFF; // To get the join city action code, use the command value and mask out the top 4 category bits - int disband_action = UCV_Disband & 0x0FFFFFFF; - if ((type->Attack | type->Defence | type->Bombard_Strength) == 0) { // if non-combat unit - if ((type->PopulationCost > 0) && (type->Worker_Actions == join_city_action)) { - *out_is_pop_else_caravan = true; - return true; - } else if ((type->Standard_Actions & disband_action) && (type->Worker_Actions == 0)) { - *out_is_pop_else_caravan = false; - return true; - } else - return false; - } else - return false; -} - -void -ai_move_material_unit (Unit * this) -{ - int type_id = this->Body.UnitTypeID; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - UnitType * type = &p_bic_data->UnitTypes[type_id]; - - // Determine whether this is a pop unit (will search for a city to join) or a caravan (will search for a city to disband) - int join_city_action = UCV_Join_City & 0x0FFFFFFF; - bool pop_else_caravan = type->Worker_Actions == join_city_action; - - int continent_id = tile->vtable->m46_Get_ContinentID (tile); - - // This part of the code follows how the replacement leader AI works. Basically it disbands the unit if it's on a continent with no - // friendly cities, then flees if it's in danger, then moves it along a set path if it has one. - if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { - Unit_disband (this); - return; - } - if (any_enemies_near_unit (this, 49)) { - Unit_set_state (this, __, UnitState_Fleeing); - bool done = this->vtable->work (this); - if (done || (this->Body.UnitState != 0)) - return; - } - byte next_move = Unit_pop_next_move_from_path (this); - if (next_move > 0) { - this->vtable->Move (this, __, next_move, 0); - return; - } - - // Find the best city to act on - City * best_city = NULL; - int best_city_value = pop_else_caravan ? -1 : 0; // min value to act is 0 for pop units, 1 for caravans - FOR_CITIES_OF (coi, this->Body.CivID) { - City * city = coi.city; - Tile * city_tile = tile_at (city->Body.X, city->Body.Y); - if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { - - if (pop_else_caravan) { - // Skip this city if it can't support another citizen - if ((city->Body.FoodIncome <= 0) || - (City_requires_improvement_to_grow (city) > -1)) - continue; - } else { - // Skip this city if its current build can't be rushed - if (! City_can_take_outside_shields (city, __, 0)) - continue; - } - - // Consider distance. - int dist_in_turns; - if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) - continue; // No path or unit cannot move - - int value; - if (pop_else_caravan) - value = 1000 / (10 + dist_in_turns); // Base value of 100 * 10 / (10 + dist_in_turn) - else { - // value is number of useful shields we'd get by moving to this city and disbanding there - int shields_per_turn = get_city_production_rate (city, city->Body.Order_Type, city->Body.Order_ID), - shields_to_complete_build = City_get_order_cost (city) - City_get_order_progress (city) - shields_per_turn, - disband_value = Leader_get_unit_cost (&leaders[city->Body.CivID], __, type_id, false) >> 2; - value = not_above (shields_to_complete_build, disband_value) - shields_per_turn * dist_in_turns; - } - - // Scale value by city corruption rate for pop units or caravan units targeting cities building improvs - if (pop_else_caravan || (city->Body.Order_Type == COT_Improvement)) { - int good_shields = city->Body.ProductionIncome, - corrupt_shields = city->Body.ProductionLoss; - if (good_shields + corrupt_shields > 0) - value = (value * good_shields) / (good_shields + corrupt_shields); - else - value = -1; - } - - if (value > best_city_value) { - best_city = city; - best_city_value = value; - } - } - } - - // Join city if we're already in the city we want to join, otherwise move to that city. If we couldn't find a city to join, go to the - // nearest established city and wait. - City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); - City * moving_to_city = NULL; - if (best_city != NULL) { - if (best_city == in_city) { - if (pop_else_caravan && patch_Unit_can_perform_command (this, __, UCV_Join_City)) { - Unit_join_city (this, __, in_city); - return; - } else if ((! pop_else_caravan) && patch_Unit_can_perform_command (this, __, UCV_Disband)) { - Unit_disband (this); - return; - } - } else - moving_to_city = best_city; - } else if (in_city == NULL) - moving_to_city = find_nearest_established_city (this, continent_id); - - if (moving_to_city) { - int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); - if (first_move > 0) { - Unit_set_escortee (this, __, -1); - this->vtable->Move (this, __, first_move, 0); - return; - } - } - - // Nothing to do, nowhere to go, just fortify in place. - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -int __stdcall -patch_get_anarchy_length (int leader_id) -{ - int base = get_anarchy_length (leader_id); - int multiplier = is->current_config.anarchy_length_percent; - if (multiplier != 100) { - // Anarchy cannot be less than 2 turns or you'll get an instant government switch. Only let that happen when the percent multiplier is - // set below zero, indicating a desire for no anarchy. Otherwise we can't reduce anarchy below 2 turns. - if (multiplier < 0) - return 1; - else if (base <= 2) - return base; - else - return not_below (2, rand_div (base * multiplier, 100)); - } else - return base; -} - -bool __fastcall -patch_Unit_check_king_ability_while_spawning (Unit * this, int edx, enum UnitTypeAbilities a) -{ - if (is->current_config.dont_give_king_names_in_non_regicide_games && - ((*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) == 0)) - return false; - else - return Unit_has_ability (this, __, a); -} - -int __fastcall -patch_Map_compute_neighbor_index_for_pass_between (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - if (is->current_config.enable_land_sea_intersections) - return 0; - else - return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); -} - -// This call replacement used to be part of improvement perfuming but now its only purpose is to set ai_considering_order when -// ai_choose_production is looping over improvements. -bool __fastcall -patch_Improvement_has_wonder_com_bonus_for_ai_prod (Improvement * this, int edx, enum ImprovementTypeWonderFeatures flag) -{ - is->ai_considering_order.OrderID = this - p_bic_data->Improvements; - is->ai_considering_order.OrderType = COT_Improvement; - return Improvement_has_wonder_flag (this, __, flag); -} - -// Similarly, this one sets the var when looping over unit types. -bool __fastcall -patch_UnitType_has_strat_0_for_ai_prod (UnitType * this, int edx, byte n) -{ - is->ai_considering_order.OrderID = this - p_bic_data->UnitTypes; - is->ai_considering_order.OrderType = COT_Unit; - return UnitType_has_ai_strategy (this, __, n); -} - -int -compare_ai_prod_valuations (void const * vp_a, void const * vp_b) -{ - struct ai_prod_valuation const * a = vp_a, - * b = vp_b; - if (a->point_value > b->point_value) return -1; - else if (b->point_value > a->point_value) return 1; - else return 0; -} - -void -rank_ai_production_options (City * city) -{ - is->count_ai_prod_valuations = 0; - City_Order unused; - patch_City_ai_choose_production (city, __, &unused); // records valuations in is->ai_prod_valuations - qsort (is->ai_prod_valuations, is->count_ai_prod_valuations, sizeof is->ai_prod_valuations[0], compare_ai_prod_valuations); -} - -void __fastcall -patch_City_Form_m82_handle_key_event (City_Form * this, int edx, int virtual_key_code, int is_down) -{ - if (is->current_config.enable_ai_production_ranking && - (~*p_human_player_bits & (1 << this->CurrentCity->Body.CivID)) && - (virtual_key_code == VK_P) && is_down) { - rank_ai_production_options (this->CurrentCity); - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_AI_PROD_RANKING", -1, 0, 0, 0); - char s[200]; - for (int n = 0; n < is->count_ai_prod_valuations; n++) { - struct ai_prod_valuation const * val = &is->ai_prod_valuations[n]; - char * name = (val->order_type == COT_Improvement) ? p_bic_data->Improvements[val->order_id].Name.S : p_bic_data->UnitTypes[val->order_id].Name; - - int show_strategy = -1; - if (val->order_type == COT_Unit) - itable_look_up (&is->unit_type_alt_strategies, val->order_id, &show_strategy); - - if ((show_strategy >= 0) && (show_strategy <= CL_LAST_UNIT_STRAT - CL_FIRST_UNIT_STRAT)) - snprintf (s, sizeof s, "^%d %s (%s)", val->point_value, name, is->c3x_labels[CL_FIRST_UNIT_STRAT + show_strategy]); - else - snprintf (s, sizeof s, "^%d %s", val->point_value, name); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - patch_show_popup (popup, __, 0, 0); - - } else if (is->current_config.toggle_zoom_with_z_on_city_screen && - (virtual_key_code == VK_Z) && is_down) { - p_bic_data->is_zoomed_out = ! p_bic_data->is_zoomed_out; - Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, this->CurrentCity->Body.X, get_city_screen_center_y (this->CurrentCity), 0, true, false); // also redraws map - this->Base.vtable->m73_call_m22_Draw ((Base_Form *)this); - } - - City_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); -} - -bool -can_harvest_shields_from_forest (Tile * tile) -{ - int flags = tile->vtable->m43_Get_field_30 (tile); - return (flags & 0x10000000) == 0; -} - -void __fastcall -patch_open_tile_info (void * this, int edx, int mouse_x, int mouse_y, int civ_id) -{ - int tx, ty; - if (is->current_config.show_detailed_tile_info && - (! Main_Screen_Form_get_tile_coords_under_mouse (p_main_screen_form, __, mouse_x, mouse_y, &tx, &ty))) { - is->viewing_tile_info_x = tx; - is->viewing_tile_info_y = ty; - is->tile_info_open = true; - } else - is->viewing_tile_info_x = is->viewing_tile_info_y = -1; - - open_tile_info (this, __, mouse_x, mouse_y, civ_id); - - is->tile_info_open = false; -} - -int __fastcall -patch_Match_ai_eval_city_location (void * this, int edx, int x, int y, int civ_id, bool param_4, int * out_breakdown) -{ - is->ai_evaling_city_loc_x = x; - is->ai_evaling_city_loc_y = y; - is->ai_evaling_city_field_30_get_counter = 0; - - return Match_ai_eval_city_location (this, __, x, y, civ_id, param_4, out_breakdown); -} - -bool -is_explored (Tile * tile, int civ_id) -{ - unsigned explored_bits = tile->Body.Fog_Of_War; - int in_debug_mode = (*p_debug_mode_bits & 8) != 0; // checking bit 3 here b/c that's how resource visibility is checked in open_tile_info - if (in_debug_mode || (explored_bits & (1 << civ_id))) - return true; - else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND - ((1 << civ_id) & *p_human_player_bits) && // "civ_id" is a human player AND - (explored_bits & *p_human_player_bits)) // any human player has visibility on the tile - return true; - else - return false; -} - -// On the GOG executable, this function intercepts the call to draw the "No information available" text on a unexplored (black) tile. In that case we -// replace that text with the coords. But on the Steam EXE this func also intercepts the call that draws the resource name on the visible tile info -// box b/c the call site is reused via a jump. So we must check that the tile is actually unexplored before replacing the text so that the resource -// name doesn't get overwritten. -int __fastcall -patch_PCX_Image_draw_no_tile_info (PCX_Image * this, int edx, char * str, int x, int y, int str_len) -{ - Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if ((tile != p_null_tile) && ! is_explored (tile, p_main_screen_form->Player_CivID)) { - char s[100]; - snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); - s[(sizeof s) - 1] = '\0'; - return PCX_Image_draw_text (this, __, s, x, y, strlen (s)); - } else - return PCX_Image_draw_text (this, __, str, x, y, str_len); -} - -int __fastcall -patch_PCX_Image_draw_tile_info_terrain (PCX_Image * this, int edx, char * str, int x, int y, int str_len) -{ - Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if (tile != p_null_tile) { - bool show_district_name = false; - - char s[200]; - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - // Draw district name to the right of terrain name if tile has one - struct district_instance * dist = get_district_instance (tile); - - if (dist != NULL) { - show_district_name = true; - char const * display_name = is->district_configs[dist->district_id].display_name; - if ((display_name == NULL) || (display_name[0] == '\0')) - display_name = is->district_configs[dist->district_id].name; - - // If it's a wonder district with a completed wonder, show the wonder name instead - if ((dist->district_id == WONDER_DISTRICT_ID) && - (dist->wonder_info.state == WDS_COMPLETED) && - (dist->wonder_info.wonder_index >= 0) && - (dist->wonder_info.wonder_index < is->wonder_district_count)) { - char const * wonder_name = is->wonder_district_configs[dist->wonder_info.wonder_index].wonder_name; - if ((wonder_name != NULL) && (wonder_name[0] != '\0')) { - display_name = wonder_name; - } - } else if ((dist->district_id == NATURAL_WONDER_DISTRICT_ID) && - (dist->natural_wonder_info.natural_wonder_id >= 0) && - (dist->natural_wonder_info.natural_wonder_id < is->natural_wonder_count)) { - int natural_id = dist->natural_wonder_info.natural_wonder_id; - char const * natural_name = is->natural_wonder_configs[natural_id].name; - if ((natural_name != NULL) && (natural_name[0] != '\0')) { - display_name = natural_name; - } - } - - snprintf (s, sizeof s, "%s", display_name); - PCX_Image_draw_text (this, __, s, x + 68, y, strlen (s)); - } - } - - // Show sprites & sheet indexes if in debug mode - int is_debug_mode = (*p_debug_mode_bits & 4) != 0; - if (is_debug_mode) { - int sheet_index = (tile->SquareParts >> 8) & 0xFF; - int sprite_index = tile->SquareParts & 0xFF; - snprintf (s, sizeof s, "%d, %d", sheet_index, sprite_index); - PCX_Image_draw_text (this, __, s, x, y - 18, strlen (s)); - } - - // Draw tile coords on line below terrain name - snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); - PCX_Image_draw_text (this, __, s, x, y + 14, strlen (s)); - - if ((is->city_loc_display_perspective >= 0) && - ((1 << is->city_loc_display_perspective) & *p_player_bits)) { - int eval = patch_Match_ai_eval_city_location (p_match, __, is->viewing_tile_info_x, is->viewing_tile_info_y, is->city_loc_display_perspective, false, NULL); - if (eval > 0) { - snprintf (s, sizeof s, "%d", eval - 1000000); - PCX_Image_draw_text (this, __, s, x + 95, y, strlen (s)); - } - } - - // If tile has been chopped and district name not shown (uses same space), indicate that to the right of the terrain name - if (! can_harvest_shields_from_forest (tile) && !show_district_name) - PCX_Image_draw_text (this, __, is->c3x_labels[CL_CHOPPED], x + 145, y, strlen (is->c3x_labels[CL_CHOPPED])); - } - return PCX_Image_draw_text (this, __, str, x, y, str_len); -} - -int __fastcall -patch_City_compute_corrupted_yield (City * this, int edx, int gross_yield, bool is_production) -{ - Leader * leader = &leaders[this->Body.CivID]; - - if (is->current_config.zero_corruption_when_off && - (p_bic_data->Governments[leader->GovernmentType].CorruptionAndWaste == CWT_Off)) - return 0; - - int tr = City_compute_corrupted_yield (this, __, gross_yield, is_production); - - if (is->current_config.promote_wonder_decorruption_effect) { - int actual_capital_id = leader->CapitalID; - for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { - Improvement * improv = &p_bic_data->Improvements[improv_id]; - City * pseudo_capital = NULL; - if (improv->SmallWonderFlags & ITSW_Reduces_Corruption) { - if (improv->Characteristics & ITC_Small_Wonder) { - pseudo_capital = get_city_ptr (leader->Small_Wonders[improv_id]); - } else if (improv->Characteristics & ITC_Wonder) { - pseudo_capital = get_city_ptr (Game_get_wonder_city_id(p_game, __, improv_id)); - } - - if (pseudo_capital != NULL && pseudo_capital->Body.CivID == this->Body.CivID && pseudo_capital->Body.ID != actual_capital_id) { - leader->CapitalID = pseudo_capital->Body.ID; - int fp_corrupted_yield = City_compute_corrupted_yield (this, __, gross_yield, is_production); - if (fp_corrupted_yield < tr) - tr = fp_corrupted_yield; - } - } - } - leader->CapitalID = actual_capital_id; - } - - return tr; -} - -int __fastcall -patch_Sprite_draw (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - Sprite * to_draw = get_sprite_proxy_for_current_hour(this); - return Sprite_draw(to_draw ? to_draw : this, __, canvas, pixel_x, pixel_y, color_table); -} - -int __fastcall -patch_Sprite_draw_on_map (Sprite * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) -{ - Sprite * to_draw = get_sprite_proxy_for_current_hour(this); - return Sprite_draw_on_map(to_draw ? to_draw : this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); -} - -bool -is_or_could_become_grassland (Tile * tile) -{ - enum SquareTypes sq_type = tile->vtable->m50_Get_Square_BaseType (tile), - underlying_type = tile->vtable->m49_Get_Square_RealType (tile); - int worker_job_id = p_bic_data->TileTypes[sq_type].WorkerJobID; - return sq_type == SQ_Grassland || - (underlying_type == SQ_Grassland && (worker_job_id == WJ_Clean_Forest || worker_job_id == WJ_Clear_Swamp)) || - tile->vtable->m72_Get_Pollution_Effect (tile) == SQ_Grassland; -} - -void __fastcall -patch_Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (Map_Renderer * this, int edx, int param_1, int pixel_x, int pixel_y, Map_Renderer * map_renderer, int param_5, int tile_x, int tile_y, int param_8) -{ - Map * map = &p_bic_data->Map; - Tile * tile = tile_at (tile_x, tile_y); - - is->current_render_tile = tile; - is->current_render_tile_x = tile_x; - is->current_render_tile_y = tile_y; - is->current_render_tile_district = get_district_instance (tile); - - Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (this, __, param_1, pixel_x, pixel_y, map_renderer, param_5, tile_x, tile_y, param_8); - - is->current_render_tile = NULL; - is->current_render_tile_x = -1; - is->current_render_tile_y = -1; - is->current_render_tile_district = NULL; - - if ((is->city_loc_display_perspective >= 0) && - (! map->vtable->m10_Get_Map_Zoom (map)) && // Turn off display when zoomed out. Need another set of highlight images for that. - ((1 << is->city_loc_display_perspective) & *p_player_bits) && - (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. - - init_tile_highlights (); - if (is->tile_highlight_state == IS_OK) { - int eval = patch_Match_ai_eval_city_location (p_match, __, tile_x, tile_y, is->city_loc_display_perspective, false, NULL); - if (eval > 0) { - int step_size = 10; - int midpoint = (COUNT_TILE_HIGHLIGHTS % 2 == 0) ? 1000000 : (1000000 - step_size/2); - int grade = (eval >= midpoint) ? (eval - midpoint) / step_size : (eval - midpoint) / step_size - 1; - int i_highlight = clamp (0, COUNT_TILE_HIGHLIGHTS - 1, COUNT_TILE_HIGHLIGHTS/2 + grade); - Sprite_draw_on_map (&is->tile_highlights[i_highlight], __, this, pixel_x, pixel_y, 1, 1, 1, 0); - } - } - } - - // Districts-related highlights - if (is->current_config.enable_districts && - (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. - init_tile_highlights (); - if (is->tile_highlight_state == IS_OK) { - - // Draw city work radius highlights for selected worker - if (is->current_config.enable_city_work_radii_highlights && - is->highlight_city_radii) { - - if ((tile != NULL) && (tile != p_null_tile)) { - int stored_ptr; - if (itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)tile, &stored_ptr)) { - struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)stored_ptr; - Sprite_draw_on_map (&is->tile_highlights[clamp(0, COUNT_TILE_HIGHLIGHTS - 1, info->highlight_level)], __, this, pixel_x, pixel_y, 1, 1, 1, 0); - } - } - } - - // If focusing on a tile after Great Wall completed, highlight the tile while getting user confirmation - if (is->focused_tile != NULL && is->focused_tile == tile) { - Sprite_draw_on_map (&is->tile_highlights[10], __, this, pixel_x, pixel_y, 1, 1, 1, 0); - } - } - } -} - -// We determine at the start of the game where *any* AI player might want to build canals and bridges. -// This is done up front in a single pass, as re-assessing every single turn per AI is wasteful and the -// geography of the map doesn't change. This function adds all the candidates as districts, effectively -// drawing them directly on the map. We don't use it in a normal game, but this is extremely useful for -// debugging so good to keep it around. For debugging, just call it immediately after -// generate_ai_canal_and_bridge_targets () -void -insert_ai_candidate_bridge_or_canals_into_district_tile_map () -{ - if ((is->ai_candidate_bridge_or_canals_count <= 0) || (! is->ai_candidate_bridge_or_canals_initialized)) - return; - - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if (entry == NULL) - continue; - - char ss[256]; - snprintf (ss, sizeof ss, "Entry %d: district %d owner %d tiles %d completed %d\n", - ei, entry->district_id, entry->owner_civ_id, entry->tile_count, entry->completed ? 1 : 0); - (*p_OutputDebugStringA)(ss); - - for (int ti = 0; ti < entry->tile_count; ti++) { - int tx = entry->tile_x[ti]; - int ty = entry->tile_y[ti]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - snprintf (ss, sizeof ss, " (%d,%d)%s\n", tx, ty, (ti == entry->assigned_tile_index) ? " [assigned]" : ""); - (*p_OutputDebugStringA)(ss); - } - } - - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - if ((entry == NULL) || (entry->completed)) - continue; - - for (int ti = 0; ti < entry->tile_count; ti++) { - int tx = entry->tile_x[ti]; - int ty = entry->tile_y[ti]; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int key = (int)tile; - int existing; - if (itable_look_up (&is->district_tile_map, key, &existing)) - continue; - - struct district_instance * inst = (struct district_instance *)calloc (1, sizeof *inst); - if (inst == NULL) - continue; - inst->state = DS_COMPLETED; - inst->district_id = entry->district_id; - inst->tile_x = tx; - inst->tile_y = ty; - - itable_insert (&is->district_tile_map, key, (int)inst); - } - } -} - -void __fastcall -patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (Map_Renderer * this, int edx, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (! is->current_config.draw_forests_over_roads_and_railroads) { - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - Tile * tile = is->current_render_tile; - if ((tile == NULL) || (tile == p_null_tile)) - return; - - if ((tile->vtable->m50_Get_Square_BaseType (tile) == SQ_Forest) && - (*tile->vtable->m25_Check_Roads)(tile, __, 0)) { - is->draw_forests_over_roads_on_tile = true; - return; - } - - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Map_Renderer_m52_Draw_Roads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - // Don't draw roads if a bridge is here - if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { - Tile * tile = is->current_render_tile; - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * dist = get_district_instance (tile); - if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { - return; - } - } - } - - Map_Renderer_m52_Draw_Roads (this, __, image_index, map_renderer, pixel_x, pixel_y); - - if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) - return; - - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Map_Renderer_m52_Draw_Railroads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - // Don't draw railroads if a bridge is here - if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { - Tile * tile = is->current_render_tile; - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * dist = get_district_instance (tile); - if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { - return; - } - } - } - - Map_Renderer_m52_Draw_Railroads (this, __, image_index, map_renderer, pixel_x, pixel_y); - - if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) - return; - - Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Main_Screen_Form_m82_handle_key_event (Main_Screen_Form * this, int edx, int virtual_key_code, int is_down) -{ - char s[200]; - int * last_events = is->last_main_screen_key_up_events; - bool in_game = *p_player_bits != 0; // Player bits all zero indicates we aren't currently in a game. Need to check for this because UI events - // on the main menu also pass through this function. - - if (! is_down) { - for (int n = ARRAY_LEN (is->last_main_screen_key_up_events) - 1; n > 0; n--) - last_events[n] = last_events[n - 1]; - last_events[0] = virtual_key_code; - } - - if (is->current_config.enable_ai_city_location_desirability_display && - (virtual_key_code == VK_L) && is_down && - (! (is_command_button_active (&this->GUI, UCV_Load) || is_command_button_active (&this->GUI, UCV_Unload))) && - in_game) { - int is_debug_mode = (*p_debug_mode_bits & 4) != 0; // This is how the check is done in open_tile_info. Actually there are two debug - // mode bits (4 and 8) and I don't know what the difference is. - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CITY_LOC_HIGHLIGHTS", -1, 0, 0x40, 0); - snprintf (s, sizeof s, " %s", is->c3x_labels[CL_OFF]); - s[(sizeof s) - 1] = '\0'; - PopupSelection_add_item (&popup->selection, __, s, 0); - for (int n = 1; n < 32; n++) - if ((*p_player_bits & (1 << n)) && - (is_debug_mode || (n == p_main_screen_form->Player_CivID))) { - Race * race = &p_bic_data->Races[leaders[n].RaceID]; - snprintf (s, sizeof s, " (%d) %s", n, race->vtable->GetLeaderName (race)); - s[(sizeof s) - 1] = '\0'; - PopupSelection_add_item (&popup->selection, __, s, n); - } - int sel = patch_show_popup (popup, __, 0, 0); - if (sel >= 0) { // -1 indicates popup was closed without making a selection - is->city_loc_display_perspective = (sel >= 1) ? sel : -1; - this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw - } - - } else if (is->current_config.enable_debug_mode_switch && - (in_game && ! is_down) && - (last_events[4] == VK_D) && (last_events[3] == VK_E) && (last_events[2] == VK_B) && (last_events[1] == VK_U) && (last_events[0] == VK_G)) { - PopupForm * popup = get_popup_form (); - if ((*p_debug_mode_bits & 0xC) != 0) { // Consider debug mode on if either bit is set - *p_debug_mode_bits &= ~0xC; - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - PopupForm_add_text (popup, __, "Debug mode deactivated.", 0); - patch_show_popup (popup, __, 0, 0); - } else { - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_DEBUG_ACTIVATION", -1, 0, 0, 0); - int sel = patch_show_popup (popup, __, 0, 0); - if (sel == 0) { - *p_debug_mode_bits |= 0xC; - *(bool *)((int)p_human_player_bits + 37) = true; // Set MegaTrainerXL flag indicating edited save - } - } - this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw - - // Worker keyboard shortcuts that would normally go to patch_Main_Screen_Form_issue_command - // unfortunately get short-circuited if a district is on a tile and the default popup to replace a "mine" is shown. - // The only way to catch these beforehand I've found it is to intercept the key event here. - } else if (is->current_config.enable_districts && - p_main_screen_form->Current_Unit != NULL && - is_down && - is_worker (p_main_screen_form->Current_Unit)) { - int command = -1; - bool removed_existing = false; - if (virtual_key_code == VK_M && is_command_button_active (&this->GUI, UCV_Build_Mine)) command = UCV_Build_Mine; - else if (virtual_key_code == VK_I && is_command_button_active (&this->GUI, UCV_Irrigate)) command = UCV_Irrigate; - else if (virtual_key_code == VK_N && is_command_button_active (&this->GUI, UCV_Plant_Forest)) command = UCV_Plant_Forest; - - if (handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) { - Main_Screen_Form_issue_command (this, __, command, p_main_screen_form->Current_Unit); - } - } - -after_district_key_handling: - Main_Screen_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); -} - -int __fastcall -patch_Unit_get_move_points_after_airdrop (Unit * this) -{ - int prev_airdrop_count = itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0); - itable_insert (&is->airdrops_this_turn, this->Body.ID, prev_airdrop_count + 1); - - return is->current_config.dont_end_units_turn_after_airdrop ? this->Body.Moves : patch_Unit_get_max_move_points (this); -} - -int __fastcall -patch_Unit_get_move_points_after_set_to_intercept (Unit * this) -{ - return is->current_config.patch_intercept_lost_turn_bug ? this->Body.Moves : patch_Unit_get_max_move_points (this); -} - -void __cdecl -activate_mod_info_button (int control_id) -{ - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - char s[500]; - char version_letter = 'A' + MOD_VERSION%100; - - if (MOD_PREVIEW_VERSION == 0) - snprintf (s, sizeof s, "%s: %d%c", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' '); - else - snprintf (s, sizeof s, "%s: %d%c%s %d", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' ', is->c3x_labels[CL_PREVIEW], MOD_PREVIEW_VERSION); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_CONFIG_FILES_LOADED]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - int n = 1; - for (struct loaded_config_name * lcn = is->loaded_config_names; lcn != NULL; lcn = lcn->next) { - snprintf (s, sizeof s, "^ %d. %s", n, lcn->name); - s[(sizeof s) - 1] = '\0'; - n++; - PopupForm_add_text (popup, __, s, 0); - } - - patch_show_popup (popup, __, 0, 0); -} - -int __fastcall -patch_Parameters_Form_m68_Show_Dialog (Parameters_Form * this, int edx, int param_1, void * param_2, void * param_3) -{ - init_mod_info_button_images (); - - // "b" is the mod info button. It's created each time the preferences form (or "parameters" form as Antal called it) is opened and destroyed - // every time the form is closed. This is the easiest way since it matches how the base game works. At first I tried creating the button once - // but then it will only appear once since its attachment to the prefs form is lost when the form is destroyed on closure. I tried reattaching - // the button to each newly created form but wasn't able to make that work. - Button * b = NULL; - if (is->mod_info_button_images_state == IS_OK) { - b = malloc (sizeof *b); - Button_construct (b); - - Button_initialize (b, __, - is->c3x_labels[CL_MOD_INFO_BUTTON_TEXT], // text - MOD_INFO_BUTTON_ID, // control ID - (p_bic_data->ScreenWidth - 1024) / 2 + 891, // location x - (p_bic_data->ScreenHeight - 768) / 2 + 31, // location y - MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height - (Base_Form *)this, // parent - 0); // ? - - for (int n = 0; n < 3; n++) - b->Images[n] = &is->mod_info_button_images[n]; - PCX_Image_set_font (&b->Base_Data.Canvas, __, get_font (15, FSF_NONE), 0, 0, 0); - b->activation_handler = &activate_mod_info_button; - - // Need to draw once manually or the button won't look right - b->vtable->m73_call_m22_Draw ((Base_Form *)b); - } - - int tr = Parameters_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); - - if (b != NULL) { - b->vtable->destruct ((Base_Form *)b, __, 0); - free (b); - } - - return tr; -} - -bool __fastcall -patch_City_cycle_specialist_type (City * this, int edx, int mouse_x, int mouse_y, Citizen * citizen, City_Form * city_form) -{ - int specialist_count = 0; { - Leader * city_owner = &leaders[this->Body.CivID]; - for (int n = 0; n < p_bic_data->CitizenTypeCount; n++) - specialist_count += (n != p_bic_data->default_citizen_type) && - Leader_has_tech (city_owner, __, p_bic_data->CitizenTypes[n].RequireID); - } - int shift_down = (*p_GetAsyncKeyState) (VK_SHIFT) >> 8; - int original_worker_type = citizen->WorkerType; - - // The return value of this function is not actually used by either of the two original callers. - bool tr = City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); - - // Cycle all the way around back to the previous specialist type, if appropriate. - // If the worker type was not changed after the first call to cycle_specialist_type, that indicates that the player was asked to disable - // governor management and chose not to. Do not try to cycle backwards in that case or else we'll spam the player with more popups. - if (is->current_config.reverse_specialist_order_with_shift && - shift_down && (specialist_count > 2) && (citizen->WorkerType != original_worker_type)) { - for (int n = 0; n < specialist_count - 2; n++) - City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); - } - - return tr; -} - -int __fastcall -patch_City_get_pollution_from_pop (City * this) -{ - if (! is->current_config.enable_negative_pop_pollution) - return City_get_pollution_from_pop (this); - - int base_pollution = this->Body.Population.Size - p_bic_data->General.MaximumSize_City; - if (base_pollution <= 0) - return 0; - - // Consider improvements - int net_pollution = base_pollution; - int any_cleaning_improvs = 0; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * improv = &p_bic_data->Improvements[n]; - if ((improv->ImprovementFlags & ITF_Removes_Population_Pollution) && has_active_building (this, n)) { - any_cleaning_improvs = 1; - if (improv->Pollution < 0) - net_pollution += improv->Pollution; - } - } - - if (net_pollution <= 0) - return 0; - else if (any_cleaning_improvs) - return 1; - else - return net_pollution; -} - -// The original version of this function in the base game contains a duplicate of the logic that computes the total pollution from buildings and -// pop. By re-implementing it to use the get_pollution_from_* functions, we ensure that our changes to get_pollution_from_pop will be accounted for. -// Note: This function is called from two places, one is the city screen and the other I'm not sure about. The pollution spawning logic works by -// calling the get_pollution_from_* funcs directly. -int __fastcall -patch_City_get_total_pollution (City * this) -{ - return City_get_pollution_from_buildings (this) + patch_City_get_pollution_from_pop (this); -} - -void remove_extra_palaces (City * city, City * excluded_destination); - -void -set_wonder_built_flag (int improv_id, bool is_built) -{ - if ((p_match == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) - return; - - byte * built_flags = *(byte **)((byte *)p_match + 0x4fc); - if (built_flags == NULL) - return; - - built_flags[improv_id] = is_built; -} - -bool -choose_defensive_unit_order (City * city, City_Order * out_order) -{ - if ((city == NULL) || (out_order == NULL)) - return false; - - for (int pass = 0; pass < 3; pass++) { - int best_unit_id = -1; - int best_defence = -1; - - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { - UnitType * type = &p_bic_data->UnitTypes[n]; - if (! patch_City_can_build_unit (city, __, n, 1, 0, 0)) - continue; - - int defence = type->Defence; - if ((pass < 2) && (defence <= 0)) - continue; - if ((pass <= 1) && (type->Unit_Class != UTC_Land)) - continue; - if ((pass == 0) && ((type->AI_Strategy & UTAI_Defence) == 0)) - continue; - - if (defence > best_defence) { - best_defence = defence; - best_unit_id = n; - } - } - - if (best_unit_id >= 0) { - out_order->OrderType = COT_Unit; - out_order->OrderID = best_unit_id; - return true; - } - } - - return false; -} - -// When a city adds a building that depends on a district, optionally mirror that -// building to all other same-civ cities that can also work the district tile. -void -copy_building_with_cities_in_radius (City * source, int improv_id, int required_district_id, int tile_x, int tile_y) -{ - if (! is->current_config.enable_districts) return; - if (source == NULL) return; - - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - - if (is_wonder) { - if (! is->current_config.cities_with_mutual_district_receive_wonders) - return; - } else if (! is->current_config.cities_with_mutual_district_receive_buildings) - return; - - // If a Wonder, we know the specific tile it is at, so determine which other cities have that in work radius. - if (is_wonder) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile == p_null_tile) return; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != source->Body.CivID) return; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL || inst->district_id != required_district_id) return; - if (! district_is_complete (tile, required_district_id)) return; - - FOR_CITIES_OF (coi, source->Body.CivID) { - City * city = coi.city; - if (city == NULL) continue; - if (city == source) continue; - - if (! city_radius_contains_tile (city, tile_x, tile_y)) - continue; - - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) - continue; - - if (! patch_City_has_improvement (city, __, improv_id, false)) { - City_add_or_remove_improvement (city, __, improv_id, 1, false); - } - } - } - // Else there may be multiple district instances of this type, so check each tile around the city - else { - FOR_DISTRICTS_AROUND (wai, source->Body.X, source->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * tile = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != required_district_id) continue; - - FOR_CITIES_OF (coi, source->Body.CivID) { - City * city = coi.city; - if (city == NULL) continue; - if (city == source) continue; - - if (! city_radius_contains_tile (city, x, y)) - continue; - - if (! patch_City_has_improvement (city, __, improv_id, false)) { - City_add_or_remove_improvement (city, __, improv_id, 1, false); - - // If city already building it, switch to a defensive unit instead - int current_improv_id = city->Body.Order_ID; - if (current_improv_id == improv_id) { - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - // Show message to user - if (is->current_config.show_message_when_building_received_by_mutual_district && - city->Body.CivID == p_main_screen_form->Player_CivID) { - char msg[300]; - snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_RECEIVED], - p_bic_data->Improvements[improv_id].Name.S, - is->c3x_labels[CL_FROM_SHARED], - is->district_configs[required_district_id].name, - is->c3x_labels[CL_WITH], - source->Body.CityName); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - } - } - } - } -} - -void -grant_existing_district_buildings_to_city (City * city) -{ - if (! is->current_config.enable_districts || - (! is->current_config.cities_with_mutual_district_receive_buildings && - ! is->current_config.cities_with_mutual_district_receive_wonders) || - (city == NULL)) - return; - - int civ_id = city->Body.CivID; - int current_improv_id = city->Body.Order_ID; - bool prev_flag = is->sharing_buildings_by_districts_in_progress; - is->sharing_buildings_by_districts_in_progress = true; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - Tile * tile = wai.tile; - - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - struct district_infos * info = &is->district_infos[district_id]; - if (info->dependent_building_count <= 0) - continue; - - FOR_CITIES_OF (coi, civ_id) { - City * other = coi.city; - if ((other == NULL) || (other == city)) - continue; - - if (! city_radius_contains_tile (other, wai.tile_x, wai.tile_y)) - continue; - - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != other->Body.CivID) - continue; - - for (int i = 0; i < info->dependent_building_count; i++) { - int building_id = info->dependent_building_ids[i]; - if (building_id < 0) - continue; - - Improvement * building = &p_bic_data->Improvements[building_id]; - bool is_wonder = (building->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - - if (is_wonder) - continue; - - if (! patch_City_has_improvement (other, __, building_id, false)) - continue; - - if (patch_City_has_improvement (city, __, building_id, false)) - continue; - - City_add_or_remove_improvement (city, __, building_id, 1, false); - - // If city already building it, switch to a defensive unit instead - if (current_improv_id == building_id) { - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - if (is->current_config.show_message_when_building_received_by_mutual_district && - city->Body.CivID == p_main_screen_form->Player_CivID) { - char msg[300]; - snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", - city->Body.CityName, - is->c3x_labels[CL_RECEIVED], - p_bic_data->Improvements[building_id].Name.S, - is->c3x_labels[CL_FROM_SHARED], - is->district_configs[district_id].name, - is->c3x_labels[CL_WITH], - other->Body.CityName); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - } - } - } - - is->sharing_buildings_by_districts_in_progress = prev_flag; -} - -void -auto_build_great_wall_districts_for_civ (int civ_id) -{ - if ((! is->current_config.enable_districts) || - (! is->current_config.enable_great_wall_districts) || - (! is->current_config.auto_build_great_wall_around_territory) || - (is->great_wall_auto_build == GWABS_DONE) || - (civ_id < 0) || - is->is_placing_scenario_things) - return; - - bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; - - if ((GREAT_WALL_DISTRICT_ID < 0) || (GREAT_WALL_DISTRICT_ID >= is->district_count)) { - is->great_wall_auto_build = GWABS_DONE; - return; - } - - init_tile_highlights (); - - struct district_config const * cfg = &is->district_configs[GREAT_WALL_DISTRICT_ID]; - if ((cfg->command == -1) || (! leader_can_build_district (&leaders[civ_id], GREAT_WALL_DISTRICT_ID))) { - is->great_wall_auto_build = GWABS_DONE; - return; - } - - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_BEGIN_GREAT_WALL_AUTO_BUILD", -1, 0, 0, 0); - if (civ_id == p_main_screen_form->Player_CivID) - patch_show_popup (popup, __, 0, 0); - - is->great_wall_auto_build = GWABS_RUNNING; - - unsigned int const replaceable_flags = TILE_FLAG_MINE | TILE_FLAG_IRRIGATION; - bool require_other_civ_border = (! is_human) && is->current_config.ai_auto_build_great_wall_strategy == AAGWS_OTHER_CIV_BORDERED_ONLY; - - for (int index = 0; index < p_bic_data->Map.TileCount; index++) { - int x, y; - tile_index_to_coords (&p_bic_data->Map, index, &x, &y); - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->CityID >= 0) - continue; - if (tile->vtable->m35_Check_Is_Water (tile)) - continue; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) - continue; - - bool has_border = false; - bool has_other_civ_border = false; - FOR_TILES_AROUND (tai, 9, x, y) { - if (tai.n == 0) - continue; - Tile * neighbor = tai.tile; - if (neighbor->vtable->m35_Check_Is_Water (neighbor)) - continue; - int owner_id = neighbor->vtable->m38_Get_Territory_OwnerID (neighbor); - if (owner_id != civ_id) { - has_border = true; - if (owner_id > 0) { - has_other_civ_border = true; - break; - } - } - } - if (! has_border) - continue; - if (require_other_civ_border && (! has_other_civ_border)) - continue; - - if (! district_is_buildable_on_tile (cfg, tile)) - continue; - if (! district_resource_prereqs_met (tile, x, y, GREAT_WALL_DISTRICT_ID)) - continue; - - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == GREAT_WALL_DISTRICT_ID)) { - if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) { - inst->state = DS_COMPLETED; - if (! tile->vtable->m18_Check_Mines (tile, __, 0)) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); - set_tile_unworkable_for_all_cities (tile, x, y); - } - continue; - } - - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int replace_flags = overlay_flags & replaceable_flags; - bool has_district = (inst != NULL); - int existing_district_id = -1; - if (has_district) - existing_district_id = inst->district_id; - - if (is_human && civ_id == p_main_screen_form->Player_CivID) { - is->focused_tile = tile; - Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, x, y, 0, true, false); - - char * popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL"; - set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); - - if (has_district) { - bool redundant_district = district_instance_is_redundant (inst, tile); - bool would_lose_buildings; - would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, x, y); - if (redundant_district) - would_lose_buildings = false; - if ((existing_district_id >= 0) && (existing_district_id < is->district_count)) { - set_popup_str_param (1, (char *)is->district_configs[existing_district_id].display_name, -1, -1); - } - popup_key = would_lose_buildings - ? "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT" - : "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT_SAFE"; - } else if (replace_flags != 0) { - popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_IMPROVEMENT"; - } - - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - popup_key, - -1, 0, 0, 0); - - int sel = patch_show_popup (popup, __, 0, 0); - if (sel != 0) - continue; - } - - if (has_district || (replace_flags != 0)) { - if (has_district) { - int inst_x = x, inst_y = y; - if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) - continue; - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); - handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); - } - - if (replace_flags != 0) - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, replace_flags, x, y); - } - - if (get_district_instance (tile) != NULL) - continue; - - inst = ensure_district_instance (tile, GREAT_WALL_DISTRICT_ID, x, y); - if (inst == NULL) - continue; - - inst->district_id = GREAT_WALL_DISTRICT_ID; - district_instance_set_coords (inst, x, y); - inst->state = DS_COMPLETED; - if (! tile->vtable->m18_Check_Mines (tile, __, 0)) - tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); - set_tile_unworkable_for_all_cities (tile, x, y); - } - - is->great_wall_auto_build = GWABS_DONE; - is->focused_tile = NULL; -} - -//We need to forwards-declare this -void __fastcall -patch_City_manage_by_governor (City * this, int edx, bool manage_professions); - -void __fastcall -patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3) -{ - int init_maintenance = this->Body.Improvements_Maintenance; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - bool is_wonder_removal = (! add) && - ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && - (! is->is_placing_scenario_things); - int init_work_area_radius = get_work_ring_limit_total(this); - - // The enable_negative_pop_pollution feature changes the rules so that improvements flagged as removing pop pollution and having a negative - // pollution amount contribute to the city's pop pollution instead of building pollution. Here we make sure that such improvements do not - // contribute to building pollution by temporarily zeroing out their pollution stat when they're added to or removed from a city. - if (is->current_config.enable_negative_pop_pollution && - (improv->ImprovementFlags & ITF_Removes_Population_Pollution) && - (improv->Pollution < 0)) { - int saved_pollution_amount = improv->Pollution; - improv->Pollution = 0; - City_add_or_remove_improvement (this, __, improv_id, add, param_3); - improv->Pollution = saved_pollution_amount; - } else - City_add_or_remove_improvement (this, __, improv_id, add, param_3); - - if (is->current_config.enable_districts && is_wonder_removal && ((improv->Characteristics & ITC_Wonder) != 0)) { - if (is->current_config.destroyed_wonders_can_be_built_again) - set_wonder_built_flag (improv_id, false); - - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, improv->Name.S, -1, -1); - popup->vtable->set_text_key_and_flags ( - popup, __, is->mod_script_path, - is->current_config.destroyed_wonders_can_be_built_again ? "C3X_DISTRICT_WONDER_DESTROYED_REBUILD" : "C3X_DISTRICT_WONDER_DESTROYED", - -1, 0, 0, 0 - ); - patch_show_popup (popup, __, 0, 0); - } - - // If the city just finished a wonder and was using a wonder district for that, set the wonder - // as completed (which switches the art over and prevents the tile from being used again) - int x, y; - if (add && is->current_config.enable_districts && is->current_config.enable_wonder_districts) { - if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { - int matched_windex = find_wonder_config_index_by_improvement_id (improv_id); - - if (matched_windex >= 0) { - FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { - x = wai.tile_x; - y = wai.tile_y; - Tile * t = wai.tile; - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - if (! wonder_is_buildable_on_tile (t, improv_id)) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if (info->state != WDS_UNDER_CONSTRUCTION) continue; - if (info->city_id != this->Body.ID) continue; - - // Mark this wonder district as completed with the wonder - info->city = this; - info->city_id = this->Body.ID; - info->state = WDS_COMPLETED; - info->wonder_index = matched_windex; - break; - } - } - } - } - - int gw_auto_build_improv_id = is->current_config.great_wall_auto_build_wonder_improv_id; - if (add && is->current_config.enable_districts && - is->current_config.auto_build_great_wall_around_territory && - (gw_auto_build_improv_id >= 0) && (improv_id == gw_auto_build_improv_id)) - auto_build_great_wall_districts_for_civ (this->Body.CivID); - - //Calculate if work_area has shrunk, and if so, redistribute citizens. - int post_work_area_radius = get_work_ring_limit_total(this); - if (post_work_area_radius < init_work_area_radius) { - patch_City_manage_by_governor(this, __, false); - } - - // Update things in case we've added or removed a mill. This is only necessary while in-game. If the game is still loading the scenario, it - // will recompute resources after it's done and we'll recompute yields and happiness ourselves. - if (! is->is_placing_scenario_things) { - // Collect info about this mill, if in fact the added or removed improvement is a mill. If it's not, all these vars will be left - // false. "generates_input" tracks whether or not the mill generates a resource that's an input for another mill. - bool is_non_local_mill, is_yielding_mill, generates_input; { - is_non_local_mill = is_yielding_mill = generates_input = false; - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if (mill->improv_id == improv_id) { - is_non_local_mill |= (mill->flags & MF_LOCAL) == 0; - is_yielding_mill |= (mill->flags & MF_YIELDS) != 0; - generates_input |= (is->mill_input_resource_bits[mill->resource_id >> 3] & (1 << (mill->resource_id & 7))) != 0; - } - } - } - - // If the mill generates a resource that's added to the trade network or it's generating an input (potentially used locally to - // generate a traded resource) then rebuild the resource network. This is not necessary if the improvement also affects trade routes - // since the base method will have already done this recomputation. - if ((is_non_local_mill || generates_input) && - ((improv->ImprovementFlags & ITF_Allows_Water_Trade) == 0) && - ((improv->ImprovementFlags & ITF_Allows_Air_Trade) == 0) && - ((improv->WonderFlags & ITW_Safe_Sea_Travel) == 0)) - patch_Trade_Net_recompute_resources (is->trade_net, __, 0); - - // If the mill adds yields or might be a link in a resource production chain that does, recompute yields in the city. - if (is_yielding_mill || generates_input) - patch_City_recompute_yields_and_happiness (this); - } - - // Adding or removing an obsolete improvement should not change the total maintenance since obsolete improvs shouldn't cost maintenance. In - // the base game, they usually do since the game doesn't update maintenance costs when buildings are obsoleted, but with that bug patched we - // can enforce the correct behavior. - if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && - (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) - this->Body.Improvements_Maintenance = init_maintenance; - - // If AI MCS is enabled and we've added the Palace to a city, then remove any extra palaces from that city. If we're in the process of - // capturing a city, it's necessary to exclude that city as a possible destination for removed extra palaces. - if ((is->current_config.ai_multi_city_start > 1) && - (! is->is_placing_scenario_things) && - add && (improv->ImprovementFlags & ITF_Center_of_Empire) && - ((*p_human_player_bits & (1 << this->Body.CivID)) == 0)) - remove_extra_palaces (this, is->currently_capturing_city); - - // If sharing wonders in hotseat mode, we must recompute improvement maintenance for all human players when any one of them gains or loses a - // wonder that grants free improvements. - if ((! is->is_placing_scenario_things) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->Body.CivID) & *p_human_player_bits)) { // is this city owned by a human player - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->Body.CivID)) - Leader_recompute_buildings_maintenance (&leaders[n_player]); - player_bits >>= 1; - n_player++; - } - } - - // Optionally share district-dependent buildings or wonders to other cities in range of the same district - bool allow_wonder_sharing = is->current_config.cities_with_mutual_district_receive_wonders; - bool allow_building_sharing = is->current_config.cities_with_mutual_district_receive_buildings; - - if ((! is->is_placing_scenario_things) && add && - is->current_config.enable_districts && (allow_building_sharing || allow_wonder_sharing) && - (! is->sharing_buildings_by_districts_in_progress)) { - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); - if (prereq_list != NULL) { - bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; - if ((! is_wonder && allow_building_sharing) || (is_wonder && allow_wonder_sharing)) { - is->sharing_buildings_by_districts_in_progress = true; - for (int i = 0; i < prereq_list->count; i++) { - int district_id = prereq_list->district_ids[i]; - if (district_id < 0) - continue; - copy_building_with_cities_in_radius (this, improv_id, district_id, x, y); - } - is->sharing_buildings_by_districts_in_progress = false; - } - } - } -} - -void __fastcall -patch_Fighter_begin (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender) -{ - Fighter_begin (this, __, attacker, attack_direction, defender); - - // Apply override of retreat eligibility - // Must use this->defender instead of the defender argument since the argument is often NULL, in which case Fighter_begin finds a defender on - // the target tile and stores it in this->defender. Also must check that against NULL since Fighter_begin might fail to find a defender. - enum UnitTypeClasses class = p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID].Unit_Class; - if ((this->defender != NULL) && ((class == UTC_Land) || (class == UTC_Sea))) { - enum retreat_rules retreat_rules = (class == UTC_Land) ? is->current_config.land_retreat_rules : is->current_config.sea_retreat_rules; - if (retreat_rules != RR_STANDARD) { - int attacker_max_mp = patch_Unit_get_max_move_points (this->attacker), - defender_max_mp = patch_Unit_get_max_move_points (this->defender); - - if (retreat_rules == RR_NONE) - this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 0; - else if (retreat_rules == RR_ALL_UNITS) - this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 1; - else if (retreat_rules == RR_IF_FASTER) { - this->attacker_eligible_to_retreat = attacker_max_mp > defender_max_mp; - this->defender_eligible_to_retreat = defender_max_mp > attacker_max_mp; - } else if (retreat_rules == RR_IF_NOT_SLOWER) { - this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp; - this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp; - } else if (retreat_rules == RR_IF_FAST_AND_NOT_SLOWER) { - this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp && attacker_max_mp > p_bic_data->General.RoadsMovementRate; - this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp && defender_max_mp > p_bic_data->General.RoadsMovementRate; - } - - // Prevent immobile units from retreating - this->attacker_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID], __, UTA_Immobile); - this->defender_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->defender->Body.UnitTypeID], __, UTA_Immobile); - - // Prevent defender from retreating if in a city - this->defender_eligible_to_retreat &= city_at (this->defender_location_x, this->defender_location_y) == NULL; - } - } -} - -void __fastcall -patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) -{ - // Determine whether this despawn happened involuntarily, i.e. whether it's because of the actions of a player other than its owner. This - // includes cases where the unit was destroyed in combat, captured, kicked from territory with nowhere to go, etc. - int ret_addr = ((int *)&civ_id_responsible)[-1]; - bool involuntary = - ret_addr == DESPAWN_TO_FIGHT_1_RETURN || ret_addr == DESPAWN_TO_FIGHT_2_RETURN - || ret_addr == DESPAWN_TO_DO_BOMBARD_TILE_RETURN || ret_addr == DESPAWN_TO_CRUISE_MISSILE_DEFENDER_RETURN - || ret_addr == DESPAWN_TO_BOUNCE_TRESPASSING_UNITS_RETURN || ret_addr == DESPAWN_TO_NUKE_DAMAGE_RETURN - || ret_addr == DESPAWN_RECURSIVE_RETURN || ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN - || ret_addr == DESPAWN_TO_TRY_FLYING_OVER_TILE_RETURN; - - int owner_id = this->Body.CivID; - int type_id = this->Body.UnitTypeID; - UnitType * type = &p_bic_data->UnitTypes[type_id]; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - // Clear extra DBs, airdrops, wait records, and transport ties used by this unit - itable_remove (&is->extra_defensive_bombards, this->Body.ID); - itable_remove (&is->airdrops_this_turn, this->Body.ID); - itable_remove (&is->waiting_units, this->Body.ID); - itable_remove (&is->unit_transport_ties, this->Body.ID); - - // If we're despawning the stored ZoC defender, clear that variable so we don't despawn it again in check_life_after_zoc - if (this == is->zoc_defender) - is->zoc_defender = NULL; - - if (this == is->sb_next_up) - is->sb_next_up = NULL; - - if (this == is->last_selected_unit.ptr) - is->last_selected_unit.ptr = NULL; - - // Remove this unit from the list of extra units to despawn after capturing - int original_count = is->count_extra_capture_despawns; - for (int n_src = 0, n_dest = 0; n_src < original_count; n_src++) { - if (is->extra_capture_despawns[n_src] != this) { - is->extra_capture_despawns[n_dest] = is->extra_capture_despawns[n_src]; - n_dest++; - } else - is->count_extra_capture_despawns -= 1; - } - - // If the unit being despawned is a land transport or helicopter, we may have to make sure to despawn its passengers as well because the base - // game won't. In general, the passengers are lost if the transport was despawned involuntarily, i.e. because of another player's attack or - // something like that, or if the passengers couldn't survive outside the transport, specifically because it's a helicopter at sea. - bool must_despawn_passengers = false; { - if (is_land_transport (this)) - must_despawn_passengers = involuntary && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); - - else if (type->Unit_Class == UTC_Air && type->Transport_Capacity > 0) { // if "this" is a helicopter - Unit * container = get_unit_ptr (this->Body.Container_Unit); - bool on_carrier = container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea && - Unit_has_ability (container, __, UTA_Transports_Only_Aircraft); - bool passengers_could_survive = Tile_has_city (tile) || ! tile->vtable->m35_Check_Is_Water (tile); - - // If no-defense-from-inside is off, passengers in helicopters will fight to defend their tile, so they wouldn't be left - // inside the helicopter when their tile is taken. If it's on, an occupied heli can be destroyed or captured by a land unit, - // and we must make sure to despawn the passengers in that case because they can't remain on the tile. Hence, - // no-defense-from-inside implies no-escape in almost all circumstances (nukes are the exception). - enum special_helicopter_rules special_rules = is->current_config.special_helicopter_rules; - if (((special_rules & SHR_ALLOW_ON_CARRIERS) && on_carrier) || (special_rules & (SHR_NO_DEFENSE_FROM_INSIDE | SHR_NO_ESCAPE))) - must_despawn_passengers = involuntary || ! passengers_could_survive; - } - } - - bool prev_always_despawn_passengers = is->always_despawn_passengers; - - if (must_despawn_passengers) { - // If we've been called from do_capture_units, record the passengers in the list of units to be despawned after do_capture_units - // returns. We can't simply despawn the units now even by setting always_despawn_passengers because the despawning messes up an - // iterator over tile units inside do_capture_units. - if (ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN) { - FOR_UNITS_ON (uti, tile) - if (uti.unit->Body.Container_Unit == this->Body.ID) { - reserve (sizeof is->extra_capture_despawns[0], // item size - (void **)&is->extra_capture_despawns, // ptr to items - &is->extra_capture_despawns_capacity, // ptr to capacity - is->count_extra_capture_despawns); // count - is->extra_capture_despawns[is->count_extra_capture_despawns] = uti.unit; - is->count_extra_capture_despawns += 1; - } - - } else - is->always_despawn_passengers = true; - } - - Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); - - is->always_despawn_passengers = prev_always_despawn_passengers; - - change_unit_type_count (&leaders[owner_id], type_id, -1); -} - -bool __fastcall -patch_Unit_do_capture_units (Unit * this, int edx, int tile_x, int tile_y, int owner_civ_id) -{ - is->count_extra_capture_despawns = 0; - - bool tr = Unit_do_capture_units (this, __, tile_x, tile_y, owner_civ_id); - - // Here we rely on patch_Unit_despawn to remove despawned units from the list - while (is->count_extra_capture_despawns > 0) - patch_Unit_despawn (is->extra_capture_despawns[0], __, this->Body.ID, 0, 0, 0, 0, 0, 0); - - return tr; -} - -void __fastcall -patch_Map_Renderer_m71_Draw_Tiles (Map_Renderer * this, int edx, int param_1, int param_2, int param_3) -{ - // Restore the tile count if it was saved by recompute_resources. This is necessary because the Draw_Tiles method loops over all tiles. - if (is->saved_tile_count >= 0) { - p_bic_data->Map.TileCount = is->saved_tile_count; - is->saved_tile_count = -1; - } - - Map_Renderer_m71_Draw_Tiles (this, __, param_1, param_2, param_3); -} - -struct named_tile_entry * -get_named_tile_entry (Tile * tile) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return NULL; - int stored_ptr = 0; - if (! itable_look_up (&is->named_tile_map, (int)tile, &stored_ptr)) - return NULL; - return (struct named_tile_entry *)stored_ptr; -} - -bool -prompt_for_named_tile (char const * seed_name, char * out_name, int out_len) -{ - if ((out_name == NULL) || (out_len <= 0)) - return false; - out_name[0] = '\0'; - - PopupForm * popup = get_popup_form (); - if (popup == NULL) - return false; - - char seed_buf[101]; - if (seed_name == NULL) - seed_name = ""; - strncpy (seed_buf, seed_name, sizeof seed_buf); - seed_buf[(sizeof seed_buf) - 1] = '\0'; - if (seed_buf[0] == '\0') - strncpy (seed_buf, "Tile", sizeof seed_buf); - - set_popup_str_param (0, seed_buf, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "RENAME_CITY", 0x64, (int)seed_buf, 0x44, 0); - int sel = patch_show_popup (popup, __, 0, 0); - is->focused_tile = NULL; - if (sel != 0) - return false; - - if (temp_ui_strs[0][0] == '\0') - return true; - - strncpy (out_name, temp_ui_strs[0], out_len); - out_name[out_len - 1] = '\0'; - return true; -} - -void -handle_named_tile_menu_selection (void) -{ - int tile_x = is->named_tile_menu_tile_x; - int tile_y = is->named_tile_menu_tile_y; - Tile * tile = tile_at (tile_x, tile_y); - if (! tile_can_be_named (tile, tile_x, tile_y)) - return; - - init_tile_highlights (); - - struct named_tile_entry * entry = get_named_tile_entry (tile); - char const * current_name = (entry != NULL) ? entry->name : ""; - char new_name[100]; - is->focused_tile = tile; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - bool got_name = prompt_for_named_tile (current_name, new_name, sizeof new_name); - is->focused_tile = NULL; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - if (! got_name) - return; - - set_named_tile_entry (tile, tile_x, tile_y, new_name); - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -void __fastcall -patch_Main_Screen_Form_handle_right_click_on_tile (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) -{ - if (is->current_config.enable_named_tiles) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile_can_be_named (tile, tile_x, tile_y) && ! Tile_has_city (tile)) { - is->named_tile_menu_active = true; - is->named_tile_menu_tile_x = tile_x; - is->named_tile_menu_tile_y = tile_y; - Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); - is->named_tile_menu_active = false; - return; - } - } - - Main_Screen_Form_handle_right_click_on_tile (this, __, tile_x, tile_y, mouse_x, mouse_y); -} - -void __fastcall -patch_Main_Screen_Form_open_right_click_menu (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) -{ - bool set_active = false; - if (!is->named_tile_menu_active && is->current_config.enable_named_tiles) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile_can_be_named (tile, tile_x, tile_y)) { - is->named_tile_menu_active = true; - is->named_tile_menu_tile_x = tile_x; - is->named_tile_menu_tile_y = tile_y; - set_active = true; - } - } - Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); - if (set_active) - is->named_tile_menu_active = false; -} - -void -draw_map_tile_text (Main_Screen_Form * this, PCX_Image * canvas, char * text, int screen_x, int screen_y, int base_screen_height, int y_offset) -{ - int is_zoomed_out = (p_bic_data->is_zoomed_out != false); - int scale = is_zoomed_out ? 2 : 1; - int screen_width = 128 / scale; - int screen_height = base_screen_height / scale; - int text_width = screen_width - (is_zoomed_out ? 4 : 8); - if (text_width < 12) - text_width = screen_width; - - int text_left = screen_x + (screen_width - text_width) / 2; - int draw_y = screen_y - y_offset; - int text_top = draw_y + screen_height + (is_zoomed_out ? 2 : 4); - - Object_66C3FC * font = get_font (10, FSF_NONE); - if (font != NULL) { - PCX_Image_set_text_effects (canvas, __, 0x80FFFFFF, 0x80000000, 1, 1); - PCX_Image_draw_centered_text (canvas, __, font, text, text_left, text_top - 10, text_width, strlen (text)); - } -} - -void __fastcall -patch_Main_Screen_Form_draw_city_hud (Main_Screen_Form * this, int edx, PCX_Image * canvas) -{ - Main_Screen_Form_draw_city_hud (this, __, canvas); - - bool draw_natural_wonders = is->current_config.enable_natural_wonders && - is->current_config.show_natural_wonder_name_on_map; - bool draw_named_tiles = is->current_config.enable_named_tiles; - if (!draw_natural_wonders && !draw_named_tiles) - return; - - if (canvas == NULL) - canvas = &this->Base_Data.Canvas; - - if ((canvas == NULL) || (canvas->JGL.Image == NULL)) - return; - - if (draw_natural_wonders) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - - int natural_id = inst->natural_wonder_info.natural_wonder_id; - if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) - continue; - - struct natural_wonder_district_config const * nw_cfg = &is->natural_wonder_configs[natural_id]; - if ((nw_cfg == NULL) || (nw_cfg->name == NULL) || (nw_cfg->name[0] == '\0')) - continue; - - Tile * tile = (Tile *)tei.key; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int tile_x, tile_y; - if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - continue; - - int screen_x, screen_y; - Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); - - draw_map_tile_text (this, canvas, (char *)nw_cfg->name, screen_x, screen_y, 88, 88 - 64); - } - } - - if (draw_named_tiles) { - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if ((entry == NULL) || (entry->name[0] == '\0')) - continue; - - Tile * tile = (Tile *)tei.key; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int tile_x, tile_y; - if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) { - tile_x = entry->tile_x; - tile_y = entry->tile_y; - tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - } - - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) - continue; - - int screen_x, screen_y; - Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); - - draw_map_tile_text (this, canvas, entry->name, screen_x, screen_y, 64, 3); - } - } -} - -// Returns whether or not city has an "extra palace", a concept used by the AI multi-city start. Extra palaces are small wonders that reduce -// corruption (e.g. forbidden palace) that are listed under the ai_multi_start_extra_palaces config option. -bool -has_extra_palace (City * city) -{ - for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { - int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) && - (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && - (leaders[city->Body.CivID].Small_Wonders[improv_id] == city->Body.ID)) { - return true; - } - } - return false; -} - -// Removes any extra palaces from this city to other cities owned by the same player (if possible). Does not check that the city belongs to an AI or -// that AI MCS is enabled. -void -remove_extra_palaces (City * city, City * excluded_destination) -{ - Leader * leader = &leaders[city->Body.CivID]; - int extra_palace_lost; - do { - // Search for an extra palace in the city and delete it. Remember its ID so we can put it elsewhere. - extra_palace_lost = -1; - for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { - int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) && - (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && - (leader->Small_Wonders[improv_id] == city->Body.ID)) { - patch_City_add_or_remove_improvement (city, __, improv_id, 0, false); - extra_palace_lost = improv_id; - break; - } - } - - // Replace the lost extra palace like what happens to the real palace - if (extra_palace_lost >= 0) { - int best_rating = -1; - City * best_location = NULL; - FOR_CITIES_OF (coi, leader->ID) { - City * candidate = coi.city; - if ((candidate != city) && - (candidate->Body.ID != leader->CapitalID) && - (candidate != excluded_destination) && - ! has_extra_palace (candidate)) { - - // Rate this candidate as a possible (extra) palace location. The criteria we use to rate it are identical to - // what the base game uses to find a new location for the palace. - int rating = 0; - rating += candidate->Body.Population.Size; - rating += count_units_at (candidate->Body.X, candidate->Body.Y, UF_4, -1, 0, -1); - rating += 2 * City_count_citizens_of_race (candidate, __, leader->RaceID); - FOR_TILES_AROUND (tai, 0x121, candidate->Body.X, candidate->Body.Y) { - if (tai.n == 0) - continue; - City * neighbor = get_city_ptr (tai.tile->CityID); - if ((neighbor != NULL) && (neighbor != city) && (neighbor->Body.CivID == leader->ID)) { - int size = neighbor->Body.Population.Size; - if (size > p_bic_data->General.MaximumSize_City) rating += 3; - else if (size > p_bic_data->General.MaximumSize_Town) rating += 2; - else rating += 1; - } - } - - if (rating > best_rating) { - best_rating = rating; - best_location = candidate; - } - } - } - - if (best_location != NULL) - City_add_or_remove_improvement (best_location, __, extra_palace_lost, 1, false); - } - } while (extra_palace_lost >= 0); -} - -// Give a city any completed wonder districts in work radius, if cities_with_mutual_district_receive_wonders is true. -// This is essentially for cases where the original Wonder-constructing city is lost and a new city is built -// that can work the same wonder district tile. -void -grant_nearby_wonders_to_city (City * city) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_wonder_districts || - ! is->current_config.cities_with_mutual_district_receive_wonders || - (city == NULL)) - return; - - bool prev_flag = is->sharing_buildings_by_districts_in_progress; - is->sharing_buildings_by_districts_in_progress = true; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int x = wai.tile_x, y = wai.tile_y; - Tile * tile = wai.tile; - - // Make sure Wonder is completed - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) continue; - struct wonder_district_info * info = &inst->wonder_info; - if ((info == NULL) || (info->state != WDS_COMPLETED)) continue; - - // Check that city doesn't already have the Wonder - int improv_id = get_wonder_improvement_id_from_index (info->wonder_index); - if (improv_id < 0) continue; - - if (patch_City_has_improvement (city, __, improv_id, false)) continue; - - // Small wonders use Leader.Small_Wonders as their canonical owner record. If the city - // just changed hands and the new owner already has that small wonder elsewhere, do not - // re-grant it from the nearby district or the capture can recreate a duplicate. - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) != 0) { - City * owning_city = get_city_ptr (leaders[city->Body.CivID].Small_Wonders[improv_id]); - if ((owning_city != NULL) && - (owning_city->Body.CivID == city->Body.CivID) && - ! city_radius_contains_tile (owning_city, x, y)) - continue; - } - - // Add the Wonder to the city - patch_City_add_or_remove_improvement (city, __, improv_id, 1, false); - } - - is->sharing_buildings_by_districts_in_progress = prev_flag; -} - -void -on_gain_city (Leader * leader, City * city, enum city_gain_reason reason) -{ - if (reason == CGR_FOUNDED) - is->turn_no_of_last_founding_for_settler_perfume[leader->ID] = *p_current_turn_no; - - // Handle extra palaces for AI multi-city start - if (((*p_human_player_bits & (1<ID)) == 0) && // If leader is an AI AND - (is->current_config.ai_multi_city_start > 1) && // AI multi-city start is enabled AND - (leader->Cities_Count > 1) && // city is not the only one the AI has (i.e. it's not the capital) AND - (reason != CGR_PLACED_FOR_SCENARIO) && (reason != CGR_PLACED_FOR_AI_MULTI_CITY_START)) { // city was not placed before the game started - - // Find an extra palace that this player does not already have - int free_extra_palace = -1; - for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { - int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) && - (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && - (NULL == get_city_ptr (leader->Small_Wonders[improv_id]))) { - free_extra_palace = improv_id; - break; - } - } - - // Place that extra palace here - if (free_extra_palace >= 0) - City_add_or_remove_improvement (city, __, free_extra_palace, 1, false); - } - - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - patch_City_recompute_yields_and_happiness (city); - patch_City_recompute_culture_income (city); - } - - if (is->current_config.enable_districts) { - - // Remove any district previously on the tile, if city just founded - if (reason == CGR_FOUNDED) { - Tile * city_tile = tile_at (city->Body.X, city->Body.Y); - if ((city_tile != NULL) && (city_tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (city_tile); - if (inst != NULL) - handle_district_removed (city_tile, inst->district_id, city->Body.X, city->Body.Y, false); - } - } - - bool receive_buildings = is->current_config.cities_with_mutual_district_receive_buildings; - bool receive_wonders = is->current_config.cities_with_mutual_district_receive_wonders; - - // Grant buildings and wonders from nearby completed districts owned by other cities of same civ, if enabled - if (receive_buildings) { - grant_existing_district_buildings_to_city (city); - } - - // Grant wonders nearby in same territory, regardless of city (i.e., orphaned wonders from destroyed cities), if enabled - if (receive_wonders) { - grant_nearby_wonders_to_city (city); - } - - if (is->current_config.enable_distribution_hub_districts) { - refresh_distribution_hubs_for_city (city); - } - } -} - -void -on_lose_city (Leader * leader, City * city, enum city_loss_reason reason) -{ - // If leader is an AI and AI MCS is enabled, remove any extra palaces the city has - if (((*p_human_player_bits & (1<ID)) == 0) && - (is->current_config.ai_multi_city_start > 1)) - remove_extra_palaces (city, NULL); - - if (is->current_config.enable_districts) { - if (is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; - - forget_pending_building_order (city); - for (int district_id = 0; district_id < is->district_count; district_id++) - clear_city_district_request (city, district_id); - - if (is->current_config.enable_wonder_districts) - release_wonder_district_reservation (city); - } else if (is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; -} - -// Returns -1 if the location is unusable, 0-9 if it's usable but doesn't satisfy all criteria, and 10 if it couldn't be better -int -eval_starting_location (Map * map, int const * alt_starting_locs, int alt_starting_loc_count, int tile_x, int tile_y, int civ_id) -{ - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != p_null_tile) && - (patch_Map_check_city_location (map, __, tile_x, tile_y, civ_id, true) == CLV_OK) && - (tile->vtable->m15_Check_Goody_Hut (tile, __, 0) == 0) && - (tile->vtable->m40_get_TileUnit_ID (tile) == -1)) { - int tr = 0; - - // Avoid this location if it's too close to another starting location. If it's much too close, it's ruled out entirely. - int closest_dist = INT_MAX; - for (int n = 1; n <= map->Civ_Count; n++) - if (map->Starting_Locations[n] >= 0) { - int other_x, other_y; - tile_index_to_coords (map, map->Starting_Locations[n], &other_x, &other_y); - int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); - if (dist < closest_dist) - closest_dist = dist; - } - for (int n = 0; n < alt_starting_loc_count; n++) - if (alt_starting_locs[n] >= 0) { - int other_x, other_y; - tile_index_to_coords (map, alt_starting_locs[n], &other_x, &other_y); - int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); - if (dist < closest_dist) - closest_dist = dist; - } - if (closest_dist < map->Civ_Distance/3) - return -1; - else if (closest_dist >= 2*map->Civ_Distance/3) - tr += 1; - - // Avoid tiny islands - // tr += map->vtable->m33_Get_Continent (map, __, tile->ContinentID)->Body.TileCount >= 20; - - // Avoid garbage terrain, e.g. all desert or tundra - int break_even_food_tiles = 0; - FOR_TILES_AROUND (tai, 21, tile_x, tile_y) { - if (tai.n == 0) - continue; // Skip tile that would be covered by the city - int tile_food = patch_Map_calc_food_yield_at (map, __, tai.tile_x, tai.tile_y, tai.tile->vtable->m50_Get_Square_BaseType (tai.tile), civ_id, 0, NULL); - int food_required = p_bic_data->General.FoodPerCitizen + (tai.tile->vtable->m35_Check_Is_Water (tai.tile) ? 1 : 0); - break_even_food_tiles += tile_food >= food_required; - } - tr += break_even_food_tiles >= 2; - - // Avoid wasting a food bonus - tr += (tile->ResourceType < 0) || (tile->ResourceType >= p_bic_data->ResourceTypeCount) || - (p_bic_data->ResourceTypes[tile->ResourceType].Food == 0); - - int max_score = 3; - return (10*tr)/max_score; - } else - return -1; -} - -City * -create_starter_city (Map * map, int civ_id, int tile_index) -{ - int x, y; - tile_index_to_coords (map, tile_index, &x, &y); - City * tr = Leader_create_city (&leaders[civ_id], __, x, y, leaders[civ_id].RaceID, -1, NULL, true); - if (tr != NULL) - on_gain_city (&leaders[civ_id], tr, CGR_PLACED_FOR_AI_MULTI_CITY_START); - return tr; -} - -void -set_up_ai_multi_city_start (Map * map, int city_count) -{ - // Set of bits determining which players are eligible for the two-city start - int eligibility_bits = 0, - count_eligible_civs = 0; - for (int n = 1; n < 32; n++) - if ((*p_player_bits & 1<Starting_Locations[n]) != p_null_tile)) { // has a valid starting location - eligibility_bits |= 1 << n; - count_eligible_civs++; - } - - if ((city_count < 1) || (count_eligible_civs == 0)) // if we have nothing to do - return; - - char load_text[50]; - snprintf (load_text, sizeof load_text, "%s...", is->c3x_labels[CL_CREATING_CITIES]); - load_text[(sizeof load_text) - 1] = '\0'; - Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); - - // Generate alternate sets of starting locations. We need one set for each extra city we're going to create per player. Each set only needs to - // include starting locations for eligible players, all others will be left as -1. - int alt_starting_loc_count = 32 * (city_count - 1); - int * alt_starting_locs = malloc (alt_starting_loc_count * sizeof *alt_starting_locs); { - for (int n = 0; n < alt_starting_loc_count; n++) - alt_starting_locs[n] = -1; - - for (int i_loc = 0; i_loc < alt_starting_loc_count; i_loc++) { - int civ_id = i_loc % 32; - if ((civ_id != 0) && (eligibility_bits & 1<current_config.max_tries_to_place_fp_city; try++) { - int i_loc = rand_int (p_rand_object, __, map->TileCount); - int x_loc, y_loc; - tile_index_to_coords (map, i_loc, &x_loc, &y_loc); - if ((x_loc >= 0) && (y_loc >= 0)) { - int val = eval_starting_location (map, alt_starting_locs, alt_starting_loc_count, x_loc, y_loc, civ_id); - if (val >= 10) { - best_loc_index = i_loc; - break; - } else if (val > best_loc_val) { - best_loc_val = val; - best_loc_index = i_loc; - } - } - } - - if (best_loc_index >= 0) - alt_starting_locs[i_loc] = best_loc_index; - } - } - } - - int count_cities_created = 0; - int count_eligible_civs_handled = 0; - for (int civ_id = 1; civ_id < 32; civ_id++) - if (eligibility_bits & 1<Starting_Locations[civ_id]; - - // Create the first starting city for the AI. This one is its capital and is located at its actual starting - // location. Afterward, delete its starting settler so it's as if the settler founded the city. - { - Unit * starting_settler = NULL; - FOR_UNITS_ON (tai, tile_at_index (map, sloc)) { - if (p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].AI_Strategy & UTAI_Settle) { - starting_settler = tai.unit; - break; - } - } - - create_starter_city (map, civ_id, sloc); - count_cities_created++; - - if (starting_settler != NULL) - patch_Unit_despawn (starting_settler, __, 0, 1, 0, 0, 0, 0, 0); - - } - - // Memoize all of the AI's starting units - clear_memo (); - FOR_UNITS_ON (tai, tile_at_index (map, sloc)) - memoize ((int)tai.unit); - - int extra_city_count = 0; - for (int i_city = 1; i_city < city_count; i_city++) { - int loc = alt_starting_locs[(i_city-1)*32 + civ_id]; - City * city; - if ((loc >= 0) && - (NULL != (city = create_starter_city (map, civ_id, loc)))) { - count_cities_created++; - extra_city_count++; - - // Spawn palace substitute in new city - if (extra_city_count-1 < is->current_config.count_ai_multi_start_extra_palaces) - patch_City_add_or_remove_improvement (city, __, is->current_config.ai_multi_start_extra_palaces[extra_city_count - 1], 1, true); - - // Move starting units over to the new city. Do this by moving every Nth unit where N is the number of extra - // cities we've founded so far plus one. ("Extra" cities are the ones created after the capital.) E.g., if - // this is the 1st city after the capital, move every 2nd unit to it. If it's the 2nd, move every 3rd, etc. - for (int n = 0; n < is->memo_len; n++) - if (n % (extra_city_count+1) == extra_city_count) - patch_Unit_move ((Unit *)is->memo[n], __, city->Body.X, city->Body.Y); - - } - } - - // Update progress report - count_eligible_civs_handled++; - int progress = 100 * count_eligible_civs_handled / count_eligible_civs; - snprintf (load_text, sizeof load_text, "%s %d%%", is->c3x_labels[CL_CREATING_CITIES], progress); - load_text[(sizeof load_text) - 1] = '\0'; - Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); - - } - - free (alt_starting_locs); - - // Sanity check - int any_adjacent_cities = 0; { - if (p_cities->Cities != NULL) - for (int city_index = 0; (city_index <= p_cities->LastIndex) && ! any_adjacent_cities; city_index++) { - City * city = get_city_ptr (city_index); - if (city != NULL) - FOR_TILES_AROUND (tai, 9, city->Body.X, city->Body.Y) - if ((tai.n > 0) && (NULL != get_city_ptr (tai.tile->vtable->m45_Get_City_ID (tai.tile)))) { - any_adjacent_cities = 1; - break; - } - } - } - int any_missing_fp_cities = (count_cities_created < city_count * count_eligible_civs); - if (any_adjacent_cities || any_missing_fp_cities) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); - char s[100]; - snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_FAILED_SANITY_CHECK]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - if (any_adjacent_cities) { - snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_ADJACENT_CITIES]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - if (any_missing_fp_cities) { - snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_MISSING_CITIES]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - patch_show_popup (popup, __, 0, 0); - } -} - -void __fastcall -patch_Map_process_after_placing (Map * this, int edx, bool param_1) -{ - if ((is->current_config.ai_multi_city_start > 0) && (*p_current_turn_no == 0)) - set_up_ai_multi_city_start (this, is->current_config.ai_multi_city_start); - - Map_process_after_placing (this, __, param_1); -} - -void __fastcall -patch_Map_impl_generate (Map * this, int edx, int seed, bool is_multiplayer_game, int num_seafaring_civs) -{ - Map_impl_generate (this, __, seed, is_multiplayer_game, num_seafaring_civs); - - if (is->current_config.enable_natural_wonders) - place_natural_wonders_on_map (); -} - -int __fastcall -patch_City_get_net_commerce (City * this, int edx, int kind, bool include_science_age) -{ - int base = City_get_net_commerce (this, __, kind, include_science_age); - - if ((kind == 1) && // beakers, as opposed to 2 which is gold - (is->current_config.ai_research_multiplier != 100) && - ((*p_human_player_bits & 1<Body.CivID) == 0)) - return (base * is->current_config.ai_research_multiplier + 50) / 100; - else - return base; -} - -// Cuts research spending while total expenditures > treasury. Returns whether spending has been cut. -bool -cut_unaffordable_research_spending (Leader * leader, bool skip_popup) -{ - // The rate cap limits AI players' spending on the gold slider (in Leader::ai_adjust_sliders) however it does not apply to human players when - // adjusting sliders manually on the domestic advisor screen. - int gold_rate_cap = ((*p_human_player_bits & 1<ID) != 0) ? 10 : p_bic_data->Governments[leader->GovernmentType].RateCap; - - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - bool reduced_spending = false; - while (leader->science_slider > 0 && - leader->gold_slider < gold_rate_cap && - treasury + Leader_compute_income (leader) < 0) { - leader->science_slider -= 1; - leader->gold_slider += 1; - Leader_recompute_economy (leader); - reduced_spending = true; - } - if (reduced_spending && ! skip_popup && leader->ID == p_main_screen_form->Player_CivID) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_CUT_RESEARCH_SPENDING", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - return reduced_spending; -} - -void __fastcall -adjust_sliders_preproduction (Leader * this) -{ - if ((*p_human_player_bits & 1<ID) == 0) { - // Replicate the behavior of the original code for AI players. (apply_machine_code_edits overwrites an equivalent branch & call in the - // original code with a call to this method.) - this->vtable->ai_adjust_sliders (this); - - // If aggressively penalize bankruptcy is on, cut the AI's research spending if it can't afford it. This may be redundant as - // ai_adjust_sliders will already cut AI spending but maybe not all the way to zero. Do this only every third turn so the AI is not - // completely prevented from researching. - if (is->current_config.aggressively_penalize_bankruptcy && (*p_current_turn_no + this->ID) % 3 == 0) - cut_unaffordable_research_spending (this, true); - - // If human player would go bankrupt, try reducing their research spending to avoid that - } else if (is->current_config.cut_research_spending_to_avoid_bankruptcy) - cut_unaffordable_research_spending (this, false); -} - -int __fastcall -patch_City_get_improvement_maintenance (City * this, int edx, int improv_id) -{ - // Check if this improvment is provided for free by another player via shared wonder effects - int civ_id = this->Body.CivID; - bool free_from_sharing = false; - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << civ_id) & *p_human_player_bits)) { // is this city owned by a human player - - // Check if any other human player in the game has this improv in their auto improvs table, including for this city's continent - bool has_free_improv = false; - Tile * city_tile = tile_at (this->Body.X, this->Body.Y); - int continent_id = city_tile->vtable->m46_Get_ContinentID (city_tile); - int cont_coded_key = (continent_id + 1) * p_bic_data->ImprovementsCount + improv_id;; - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != civ_id)) - if (Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, improv_id , NULL) || - Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, cont_coded_key, NULL)) { - free_from_sharing = true; - break; - } - player_bits >>= 1; - n_player++; - } - } - - if (! free_from_sharing) - return City_get_improvement_maintenance (this, __, improv_id); - else - return 0; -} - -int __fastcall -patch_Leader_count_maintenance_free_units (Leader * this) -{ - if ((is->current_config.extra_unit_maintenance_per_shields <= 0) && (this->ID != 0)) - return Leader_count_maintenance_free_units (this); - else { - int tr = 0; - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if ((unit != NULL) && (unit->Body.CivID == this->ID)) { - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - - // If this is a free unit - if ((unit->Body.RaceID != this->RaceID) || (type->requires_support == 0)) - tr++; - - // If this unit belongs to the barbs and has a tribe ID set (indicating it was spawned in a barb camp) then count it - // as a free unit in order not to bankrupt the barb player if the barb player controls any cities. A tribe ID of 75 is - // the generic ID that's assigned to barb units when they're spawned with no specific tribe ID. - else if ((unit->Body.CivID == 0) && (unit->Body.barb_tribe_id >= 0) && (unit->Body.barb_tribe_id < 75)) - tr++; - - // Otherwise, if we're configured to apply extra maintenance based on shield cost, reduce the free unit count by - // however many times this unit's cost is above the threshold for extra maintenace. It's alright if the resulting free - // unit count is negative since all callers of this function subtract its return value from the total unit count to - // obtain the count of units that must be paid for. - else if (is->current_config.extra_unit_maintenance_per_shields > 0) - tr -= type->Cost / is->current_config.extra_unit_maintenance_per_shields; - } - } - return tr; - } -} - -int __fastcall -patch_Leader_sum_unit_maintenance (Leader * this, int edx, int government_id) -{ - if (is->current_config.extra_unit_maintenance_per_shields <= 0) - return Leader_sum_unit_maintenance (this, __, government_id); - else if (this->Cities_Count > 0) { - int maint_free_count = patch_Leader_count_maintenance_free_units (this); - int cost_per_unit, base_free_count; - get_unit_support_info (this->ID, government_id, &cost_per_unit, &base_free_count); - int ai_free_count; { - if (*p_human_player_bits & 1<ID) - ai_free_count = 0; - else { - Difficulty_Level * difficulty = &p_bic_data->DifficultyLevels[*p_game_difficulty]; - ai_free_count = difficulty->Bonus_For_Each_City * this->Cities_Count + difficulty->Additional_Free_Support; - } - } - return not_below (0, (this->Unit_Count - base_free_count - ai_free_count - maint_free_count) * cost_per_unit); - } else - return 0; -} - -int -sum_improvements_maintenance_to_pay (Leader * leader, int govt_id) -{ - if (is->current_config.aggressively_penalize_bankruptcy) - // We're going to replace the logic that charges maintenance, and the replacement will charge both unit & building maintenance b/c - // they're intertwined under the new rules. Return zero here so the base game code doesn't charge any building maintenance on its own. - return 0; - else - return Leader_sum_improvements_maintenance (leader, __, govt_id); -} - -// The sum_improvements_maintenance function is called in two places as part of the randomization of whether improv or unit maintenance gets paid -// first. Redirect both of these calls to one function of our own. -int __fastcall patch_Leader_sum_improv_maintenance_to_pay_1 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } -int __fastcall patch_Leader_sum_improv_maintenance_to_pay_2 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } - -int -compare_buildings_to_sell (void const * a, void const * b) -{ - int maint_a = (*(int const *)a >> 26) & 31, - maint_b = (*(int const *)b >> 26) & 31; - return maint_b - maint_a; -} - -// Returns the final improv cost after buildings were sold -int -sell_unaffordable_buildings (Leader * leader, int improv_cost, int unit_cost) -{ - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - - clear_memo (); - - // Memoize all buildings this player owns that we might potentially sell. B/c the memo can only contain ints, we must pack the maintenance - // cost, improv ID, and city ID all into one int. The city ID is stored in the lowest 13 bits, then the improv ID in the next 13, and finally - // the maintenance amount in the 5 above those. - FOR_CITIES_OF (coi, leader->ID) - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * improv = &p_bic_data->Improvements[n]; - - int unsellable_flags = - ITF_Center_of_Empire | - ITF_50_Luxury_Output | - ITF_50_Tax_Output | - ITF_Reduces_Corruption | - ITF_Increases_Luxury_Trade | - ITF_Allows_City_Level_2 | - ITF_Allows_City_Level_3 | - ITF_Capitalization | - ITF_Allows_Water_Trade | - ITF_Allows_Air_Trade | - ITF_Increases_Shields_In_Water | - ITF_Increases_Food_In_Water | - ITF_Increases_Trade_In_Water; - - // Only sell improvements that aren't contributing gold, even indirectly through e.g. happiness or boosting shield production - // for Wealth - bool sellable = - ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) == 0) && - ((improv->ImprovementFlags & unsellable_flags) == 0) && - (improv->Happy_Faces_All <= 0) && (improv->Happy_Faces <= 0) && - (improv->Production <= 0); - - if (sellable && patch_City_has_improvement (coi.city, __, n, 0)) { - int maint = patch_City_get_improvement_maintenance (coi.city, __, n); - if (maint > 0) - memoize ((not_above (31, maint) << 26) | (n << 13) | coi.city_id); - } - } - - // Sort the list of buildings so the highest maintenance ones come first - qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_buildings_to_sell); - - // Sell buildings until we can cover maintenance costs or until we run out of ones to sell - int count_sold = 0; - while ((improv_cost + unit_cost > treasury) && (count_sold < is->memo_len)) { - int improv_id = ((1<<13) - 1) & (is->memo[count_sold] >> 13), - city_id = ((1<<13) - 1) & is->memo[count_sold]; - City * city = get_city_ptr (city_id); - improv_cost -= patch_City_get_improvement_maintenance (city, __, improv_id); - City_sell_improvement (city, __, improv_id, false); - treasury = leader->Gold_Encoded + leader->Gold_Decrement; - count_sold++; - } - - // Show popup informing the player that their buildings were force sold - if ((leader->ID == p_main_screen_form->Player_CivID) && ! is_online_game ()) { - PopupForm * popup = get_popup_form (); - if (count_sold == 1) { - int improv_id = ((1<<13) - 1) & (is->memo[0] >> 13), - city_id = ((1<<13) - 1) & is->memo[0]; - set_popup_str_param (0, get_city_ptr (city_id)->Body.CityName , -1, -1); - set_popup_str_param (1, p_bic_data->Improvements[improv_id].Name.S, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_SINGLE_IMPROV", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } else if (count_sold > 1) { - set_popup_int_param (0, count_sold); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_MULTIPLE_IMPROVS", -1, 0, 0, 0); - - // Add list of sold improvements to popup - for (int n = 0; n < count_sold; n++) { - int improv_id = ((1<<13) - 1) & (is->memo[n] >> 13), - city_id = ((1<<13) - 1) & is->memo[n]; - char s[200]; - snprintf (s, sizeof s, "^ %s in %s", - p_bic_data->Improvements[improv_id].Name.S, - get_city_ptr (city_id)->Body.CityName); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - - patch_show_popup (popup, __, 0, 0); - } - } - - return improv_cost; -} - -// Returns the final unit cost after disbanding -int -disband_unaffordable_units (Leader * leader, int improv_cost, int unit_cost, int cost_per_unit) -{ - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - int count_disbanded = 0; - Unit * to_disband; - char first_disbanded_name[32]; - while ((improv_cost + unit_cost > treasury) && - (unit_cost > 0) && - (NULL != (to_disband = leader->vtable->find_unsupported_unit (leader)))) { - if (count_disbanded == 0) { - char const * name_src = (to_disband->Body.Custom_Name.S[0] == '\0') - ? p_bic_data->UnitTypes[to_disband->Body.UnitTypeID].Name - : to_disband->Body.Custom_Name.S; - strncpy (first_disbanded_name, name_src, sizeof first_disbanded_name); - first_disbanded_name[(sizeof first_disbanded_name) - 1] = '\0'; - } - Unit_disband (to_disband); - count_disbanded++; - unit_cost -= cost_per_unit; - } - - // Show popup informing the player that their units were disbanded - if (leader->ID == p_main_screen_form->Player_CivID) { - PopupForm * popup = get_popup_form (); - if (count_disbanded == 1) { - set_popup_str_param (0, first_disbanded_name, -1, -1); - int online_flag = is_online_game () ? 0x4000 : 0; - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_SINGLE_UNIT", -1, 0, online_flag, 0); - patch_show_popup (popup, __, 0, 0); - } else if ((count_disbanded > 1) && ! is_online_game ()) { - set_popup_int_param (0, count_disbanded); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_MULTIPLE_UNITS", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - } - - return unit_cost; -} - -int -compare_cities_by_production (void const * vp_id_a, void const * vp_id_b) -{ - City * a = get_city_ptr (*(int const *)vp_id_a), - * b = get_city_ptr (*(int const *)vp_id_b); - return a->Body.ProductionIncome - b->Body.ProductionIncome; -} - -void -charge_maintenance_with_aggressive_penalties (Leader * leader) -{ - int cost_per_unit; - get_unit_support_info (leader->ID, leader->GovernmentType, &cost_per_unit, NULL); - - int improv_cost = Leader_sum_improvements_maintenance (leader, __, leader->GovernmentType); - - int unit_cost = 0; { - if (leader->Cities_Count > 0) // Players with no cities don't pay unit maintenance, per the original game rules - if (cost_per_unit > 0) { - int count_free_units = Leader_get_free_unit_count (leader, __, leader->GovernmentType) + patch_Leader_count_maintenance_free_units (leader); - unit_cost += not_below (0, (leader->Unit_Count - count_free_units) * cost_per_unit); - } - } - - int treasury = leader->Gold_Encoded + leader->Gold_Decrement; - if (improv_cost + unit_cost > treasury) { - - // For AIs, alternate between selling buildings and disbanding units when maintenance can't be paid - if (((1<ID & *p_human_player_bits) != 0) || ((leader->ID + *p_current_turn_no) % 2 == 0)) { - improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); - unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); - } else { - unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); - improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); - } - - treasury = leader->Gold_Encoded + leader->Gold_Decrement; // Update b/c selling buildings recovers some gold - - // If the player still can't afford maintenance, even after all that, start switching their cities to Wealth - int wealth_income = 0; - if (improv_cost + unit_cost > treasury + wealth_income) { - // Memoize all cities not already building wealth and sort by production (lowest first) - clear_memo (); - FOR_CITIES_OF (coi, leader->ID) - if ((coi.city->Body.Status & CSF_Capitalization) == 0) - memoize (coi.city_id); - qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_cities_by_production); - - int wealth_improv_id = -1; { - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { - wealth_improv_id = n; - break; - } - } - - if (wealth_improv_id >= 0) { - int n = 0, - switched_any = 0; - - while ((n < is->memo_len) && (improv_cost + unit_cost > treasury + wealth_income)) { - City * city = get_city_ptr (is->memo[n]); - City_set_production (city, __, COT_Improvement, wealth_improv_id, false); - switched_any = 1; - wealth_income += City_get_income_from_wealth_build (city); - n++; - } - - if (switched_any && (leader->ID == p_main_screen_form->Player_CivID)) { - PopupForm * popup = get_popup_form (); - Improvement * wealth = &p_bic_data->Improvements[wealth_improv_id]; - set_popup_str_param (0, wealth->Name.S, -1, -1); - set_popup_str_param (1, wealth->CivilopediaEntry.S, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_BUILD_WEALTH", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - } - } - } - - Leader_set_treasury (leader, __, treasury - improv_cost - unit_cost); -} - -bool __fastcall -patch_Unit_has_king_ability_for_find_unsupported (Unit * this, int edx, enum UnitTypeAbilities king_ability) -{ - // If we're set to aggressively penalize bankruptcy and this unit doesn't require support, return that it is a king so it doesn't get - // disbanded. - if (is->current_config.aggressively_penalize_bankruptcy && ! p_bic_data->UnitTypes[this->Body.UnitTypeID].requires_support) - return true; - - else - return Unit_has_ability (this, __, king_ability); -} - -void __fastcall -patch_Leader_pay_unit_maintenance (Leader * this) -{ - if (! is->current_config.aggressively_penalize_bankruptcy) - Leader_pay_unit_maintenance (this); - else - charge_maintenance_with_aggressive_penalties (this); -} - -void __fastcall -patch_Main_Screen_Form_show_wltk_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) -{ - patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); -} - -void __fastcall -patch_Main_Screen_Form_show_wltk_ended_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) -{ - patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); -} - -char __fastcall -patch_Tile_has_city_for_agri_penalty_exception (Tile * this) -{ - return is->current_config.no_penalty_exception_for_agri_fresh_water_city_tiles ? 0 : Tile_has_city (this); -} - -int -show_razing_popup (void * popup_object, int popup_param_1, int popup_param_2, int razing_option) -{ - int response = patch_show_popup (popup_object, __, popup_param_1, popup_param_2); - if (is->current_config.prevent_razing_by_players && (response == razing_option)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_RAZE", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - return 0; - } - return response; -} - -int __fastcall patch_show_popup_option_1_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 1); } -int __fastcall patch_show_popup_option_2_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 2); } - -int __fastcall -patch_Context_Menu_add_abandon_city (Context_Menu * this, int edx, int item_id, char * text, bool checkbox, Sprite * image) -{ - if (is->current_config.prevent_razing_by_players) - return 0; // Return value is ignored by the caller - else - return Context_Menu_add_item (this, __, item_id, text, checkbox, image); -} - -char * -check_pedia_upgrades_to_ptr (TextBuffer * this, char * str) -{ - Civilopedia_Form * pedia = p_civilopedia_form; - UnitType * unit_type = NULL; - if (is->current_config.indicate_non_upgradability_in_pedia && - (pedia->Current_Article_ID >= 0) && (pedia->Current_Article_ID <= pedia->Max_Article_ID) && - (NULL != (unit_type = pedia->Articles[pedia->Current_Article_ID]->unit_type)) && - ((unit_type->Special_Actions & UCV_Upgrade_Unit) == 0)) - return is->c3x_labels[CL_OBSOLETED_BY]; - else - return TextBuffer_check_ptr (this, __, str); -} - -char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_1 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } -char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_2 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } - -bool __fastcall -patch_Unit_select_stealth_attack_target (Unit * this, int edx, int target_civ_id, int x, int y, bool allow_popup, Unit ** out_selected_target) -{ - is->added_any_stealth_target = 0; - return Unit_select_stealth_attack_target (this, __, target_civ_id, x, y, allow_popup, out_selected_target); -} - -bool __fastcall -patch_Unit_can_stealth_attack (Unit * this, int edx, Unit * target) -{ - bool tr = Unit_can_stealth_attack (this, __, target); - - // If we're selecting a target for stealth attack via bombardment, we must filter out candidates we can't damage that way - if (tr && is->selecting_stealth_target_for_bombard && - ! can_damage_bombarding (&p_bic_data->UnitTypes[this->Body.UnitTypeID], target, tile_at (target->Body.X, target->Body.Y))) - return false; - - else if (tr && is->current_config.exclude_invisible_units_from_stealth_attack && ! patch_Unit_is_visible_to_civ (target, __, this->Body.CivID, 1)) - return false; - - else if (tr && is->current_config.exclude_passengers_from_stealth_attack && get_unit_ptr (target->Body.Container_Unit) != NULL) - return false; - - else - return tr; -} - -int __fastcall -patch_Tile_check_water_for_stealth_attack (Tile * this) -{ - // When stealth attack bombard is enabled, remove a special rule inside can_stealth_attack that prevents land units from stealth attacking - // onto sea tiles. This allows land artillery to stealth attack naval units. - return is->current_config.enable_stealth_attack_via_bombardment ? 0 : this->vtable->m35_Check_Is_Water (this); -} - -int __fastcall -patch_PopupSelection_add_stealth_attack_target (PopupSelection * this, int edx, char * text, int value) -{ - if (is->current_config.include_stealth_attack_cancel_option && (! is->added_any_stealth_target)) { - PopupSelection_add_item (this, __, is->c3x_labels[CL_NO_STEALTH_ATTACK], -1); - is->added_any_stealth_target = 1; - } - - Unit * unit; - if (is->current_config.show_hp_of_stealth_attack_options && - ((unit = get_unit_ptr (value)) != NULL)) { - char s[500]; - int max_hp = Unit_get_max_hp (unit); - snprintf (s, sizeof s, "(%d/%d) %s", max_hp - unit->Body.Damage, max_hp, text); - s[(sizeof s) - 1] = '\0'; - return PopupSelection_add_item (this, __, s, value); - } else - return PopupSelection_add_item (this, __, text, value); -} - -void __fastcall -patch_Unit_perform_air_recon (Unit * this, int edx, int x, int y) -{ - int moves_plus_one = this->Body.Moves + p_bic_data->General.RoadsMovementRate; - - bool was_intercepted = false; - if (is->current_config.intercept_recon_missions) { - // Temporarily add vision on the target tile so the game plays the animation if the unit is show down by ground AA - Tile_Body * tile = &tile_at (x, y)->Body; - int saved_vis = tile->Visibility; - tile->Visibility |= 1 << this->Body.CivID; - was_intercepted = Unit_try_flying_over_tile (this, __, x, y); - tile->Visibility = saved_vis; - } - - if (! was_intercepted) { - Unit_perform_air_recon (this, __, x, y); - if (is->current_config.charge_one_move_for_recon_and_interception) - this->Body.Moves = moves_plus_one; - } -} - -int __fastcall -patch_Unit_get_interceptor_max_moves (Unit * this) -{ - // Stop fighters from intercepting multiple times per turn without blitz - if (is->current_config.charge_one_move_for_recon_and_interception && - (this->Body.Status & USF_USED_ATTACK != 0) && ! UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Blitz)) - return 0; - - else - return patch_Unit_get_max_move_points (this); -} - -int __fastcall -patch_Unit_get_moves_after_interception (Unit * this) -{ - if (is->current_config.charge_one_move_for_recon_and_interception) { - this->Body.Status |= USF_USED_ATTACK; // Set status bit indicating that the interceptor has attacked this turn - return this->Body.Moves + p_bic_data->General.RoadsMovementRate; - } else - return patch_Unit_get_max_move_points (this); -} - -void __fastcall -patch_Unit_set_state_after_interception (Unit * this, int edx, int new_state) -{ - if (! is->current_config.charge_one_move_for_recon_and_interception) - Unit_set_state (this, __, new_state); - - // If fighters are supposed to be able to intercept multiple times per turn, then we can't knock them out of the interception state as soon as - // they intercept something like in the base game. Instead, record this interception event so that we can clear their state at the start of - // their next turn. - else { - struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->Body.CivID]; - reserve (sizeof irl->items[0], (void **)&irl->items, &irl->capacity, irl->count); - irl->items[irl->count++] = (struct interception) { - .unit_id = this->Body.ID, - .x = this->Body.X, - .y = this->Body.Y - }; - } -} - -// Goes through every entry in a table with unit IDs as keys and filters out any that belong to the given owner (or are invalid). -void -remove_unit_id_entries_owned_by (struct table * t, int owner_id) -{ - if (t->len > 0) { - clear_memo (); - FOR_TABLE_ENTRIES (tei, t) { - Unit * unit = get_unit_ptr (tei.key); - if ((unit == NULL) || (unit->Body.CivID == owner_id)) - memoize (tei.key); - } - for (int n = 0; n < is->memo_len; n++) - itable_remove (t, is->memo[n]); - } -} - -void __fastcall -patch_Leader_begin_turn (Leader * this) -{ - if (is->aerodrome_airlift_usage.len > 0) { - int civ_bit = 1 << this->ID; - clear_memo (); - FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { - int mask = tei.value; - if (mask & civ_bit) { - int new_mask = mask & ~civ_bit; - memoize (tei.key); - memoize (new_mask); - } - } - for (int n = 0; n < is->memo_len; n += 2) { - int key = is->memo[n]; - int new_mask = is->memo[n + 1]; - if (new_mask == 0) - itable_remove (&is->aerodrome_airlift_usage, key); - else - itable_insert (&is->aerodrome_airlift_usage, key, new_mask); - } - clear_memo (); - } - - // Eject trespassers - is->do_not_bounce_invisible_units = true; - if (is->current_config.disallow_trespassing && (*p_current_turn_no > 0)) - for (int n = 1; n < 32; n++) - if ((*p_player_bits & (1 << n)) && - (n != this->ID) && - (! this->At_War[n]) && - ((this->Relation_Treaties[n] & 2) == 0)) // Check right of passage - Leader_bounce_trespassing_units (&leaders[n], __, this->ID); - is->do_not_bounce_invisible_units = false; - - if (is->current_config.introduce_all_human_players_at_start_of_hotseat_game && - (*p_current_turn_no == 0) && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((*p_human_player_bits & (1 << this->ID)) != 0)) - for (int n = 0; n < 32; n++) - if (*p_human_player_bits & (1 << n)) - Leader_make_contact (this, __, n, false); - - Leader_begin_turn (this); -} - -void __fastcall -patch_Leader_begin_unit_turns (Leader * this) -{ - // Reset the states of all fighters that performed an interception on the previous turn. - struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->ID]; - for (int n = 0; n < irl->count; n++) { - struct interception * record = &irl->items[n]; - Unit * interceptor = get_unit_ptr (record->unit_id); - if ((interceptor != NULL) && - (interceptor->Body.CivID == this->ID) && - (interceptor->Body.X == record->x) && - (interceptor->Body.Y == record->y) && - (interceptor->Body.UnitState == UnitState_Intercept)) - Unit_set_state (interceptor, __, 0); - } - irl->count = 0; - - // Reset extra defensive bombard and airdrop counters - remove_unit_id_entries_owned_by (&is->extra_defensive_bombards, this->ID); - remove_unit_id_entries_owned_by (&is->airdrops_this_turn , this->ID); - remove_unit_id_entries_owned_by (&is->unit_transport_ties , this->ID); - - clear_memo (); - if (is->current_config.delete_off_map_ai_units && - ((*p_human_player_bits & (1 << this->ID)) == 0) && - (p_units->Units != NULL)) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit_Body * body = p_units->Units[n].Unit; - if ((body != NULL) && - ((int)body != offsetof (Unit, Body)) && - (body->CivID == this->ID) && - ! Map_in_range (&p_bic_data->Map, __, body->X, body->Y)) - memoize (body->ID); - } - for (int n = 0; n < is->memo_len; n++) - patch_Unit_despawn (get_unit_ptr (is->memo[n]), __, 0, 1, 0, 0, 0, 0, 0); - - Leader_begin_unit_turns (this); -} - -Unit * __fastcall -patch_Fighter_find_actual_bombard_defender (Fighter * this, int edx, Unit * bombarder, int tile_x, int tile_y, int bombarder_civ_id, bool land_lethal, bool sea_lethal) -{ - if (is->bombard_stealth_target == NULL) - return Fighter_find_defender_against_bombardment (this, __, bombarder, tile_x, tile_y, bombarder_civ_id, land_lethal, sea_lethal); - else - return is->bombard_stealth_target; -} - -Unit * -select_stealth_attack_bombard_target (Unit * unit, int tile_x, int tile_y) -{ - bool land_lethal = Unit_has_ability (unit, __, UTA_Lethal_Land_Bombardment), - sea_lethal = Unit_has_ability (unit, __, UTA_Lethal_Sea_Bombardment); - Unit * defender = Fighter_find_defender_against_bombardment (&p_bic_data->fighter, __, unit, tile_x, tile_y, unit->Body.CivID, land_lethal, sea_lethal); - if (defender != NULL) { - Unit * target; - is->selecting_stealth_target_for_bombard = 1; - bool got_one = patch_Unit_select_stealth_attack_target (unit, __, defender->Body.CivID, tile_x, tile_y, true, &target); - is->selecting_stealth_target_for_bombard = 0; - return got_one ? target : NULL; - } else - return NULL; -} - -bool __fastcall -patch_Unit_try_flying_for_precision_strike (Unit * this, int edx, int x, int y) -{ - bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); - if (is->current_config.polish_precision_striking && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) && - ! is_cruise_missile) - // This method returns -1 when some kind of error occurs. In that case, return true implying the unit was shot down so the caller - // doesn't do anything more. Otherwise, return false so it goes ahead and applies damage. - return Unit_play_bombard_fire_animation (this, __, x, y) == -1; - - else if (is->current_config.polish_precision_striking && is_cruise_missile) { - Unit_animate_cruise_missile_strike (this, __, x, y); - return false; - - } else - return Unit_try_flying_over_tile (this, __, x, y); -} - -void __fastcall -patch_Unit_play_bombing_anim_for_precision_strike (Unit * this, int edx, int x, int y) -{ - // Only play the bombing animation here if we haven't already played an animation in the above method. We don't want to play all animations - // here since the bombard fire animation can fail for whatever reason but this method can't handle failure. - bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); - if ((! is->current_config.polish_precision_striking) || - ((p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && ! is_cruise_missile)) - Unit_play_bombing_animation (this, __, x, y); -} - -int __fastcall -patch_Unit_play_anim_for_bombard_tile (Unit * this, int edx, int x, int y) -{ - Unit * stealth_attack_target = NULL; - if (((p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && - is->current_config.enable_stealth_attack_via_bombardment && - (! is_online_game ()) && - patch_Leader_is_tile_visible (&leaders[this->Body.CivID], __, x, y)) - is->bombard_stealth_target = select_stealth_attack_bombard_target (this, x, y); - - return Unit_play_bombard_fire_animation (this, __, x, y); -} - -void __fastcall -patch_Main_Screen_Form_issue_precision_strike_cmd (Main_Screen_Form * this, int edx, Unit * unit) -{ - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - if ((! is->current_config.polish_precision_striking) || (type->Unit_Class == UTC_Air)) - Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); - else { - // issue_precision_strike_cmd will use the unit type's operational range. To make it use bombard range instead, place that value in - // the operational range field temporarily. Conveniently, it's only necessary to do this temporary switch once, here, because the main - // screen form stores a copy of the range for its own use and the method to actually perform the strike doesn't check the range. - int saved_op_range = type->OperationalRange; - type->OperationalRange = type->Bombard_Range; - Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); - type->OperationalRange = saved_op_range; - } -} - -int __fastcall -patch_Map_compute_neighbor_index_for_cm_strike (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) -{ - int tr = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); - - if ((tr >= 0) && - (is->bombarding_unit != NULL) && - ((p_bic_data->UnitTypes[is->bombarding_unit->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && - is->current_config.enable_stealth_attack_via_bombardment && - (! is_online_game ()) && - patch_Leader_is_tile_visible (&leaders[is->bombarding_unit->Body.CivID], __, x_neigh, y_neigh)) - is->bombard_stealth_target = select_stealth_attack_bombard_target (is->bombarding_unit, x_neigh, y_neigh); - - return tr; -} - -int __fastcall -patch_rand_bombard_target (void * this, int edx, int lim) -{ - // If we have a bombard stealth attack target set then return 2 so that the bombard damage will be applied to units not pop or buildings. - return (is->bombard_stealth_target == NULL) ? rand_int (this, __, lim) : 2; -} - -int __fastcall -patch_rand_int_to_dodge_city_aa (void * this, int edx, int lim) -{ - int tr = rand_int (this, __, lim); - is->result_of_roll_to_dodge_city_aa = tr; - return tr; -} - -int __fastcall -patch_Unit_get_defense_to_dodge_city_aa (Unit * this) -{ - int defense = Unit_get_defense_strength (this); - if (is->current_config.show_message_after_dodging_sam && - (defense > is->result_of_roll_to_dodge_city_aa) && - (this->Body.CivID == p_main_screen_form->Player_CivID)) - show_map_specific_text (this->Body.X, this->Body.Y, is->c3x_labels[CL_DODGED_SAM], 0); - return defense; -} - -int __fastcall -patch_Unit_get_defense_to_find_bombard_defender (Unit * this) -{ - // The caller is filtering out candidates with zero defense strength as possible targets to receive damage from bombardment. We can return 0 - // here to make sure "this" unit is not targeted. - - Unit * container; - - if (is->current_config.immunize_aircraft_against_bombardment && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air)) - return 0; - - else if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return 0; - - else - return Unit_get_defense_strength (this); -} - -int __cdecl -patch_get_WindowsFileBox_from_ini (LPCSTR key, int param_2, int param_3) -{ - // If the file path has already been determined, then avoid using the Windows file picker. This makes the later code to insert the path easier - // since we only have to intercept the opening of the civ-style file picker instead of both that and the Windows one. - if (is->load_file_path_override == NULL) - return get_int_from_conquests_ini (key, param_2, param_3); - else - return 0; -} - -char const * __fastcall -patch_do_open_load_game_file_picker (void * this) -{ - if (is->load_file_path_override != NULL) { - char const * tr = is->load_file_path_override; - is->load_file_path_override = NULL; - return tr; - } else - return open_load_game_file_picker (this); -} - -int __fastcall -patch_show_intro_after_load_popup (void * this, int edx, int param_1, int param_2) -{ - if (! is->suppress_intro_after_load_popup) - return patch_show_popup (this, __, param_1, param_2); - else { - is->suppress_intro_after_load_popup = 0; - return 0; - } -} - -void __fastcall patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id); - -void * __cdecl -patch_do_load_game (char * param_1) -{ - void * tr = do_load_game (param_1); - - if (is->current_config.restore_unit_directions_on_game_load && (p_units->Units != NULL)) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if ((unit != NULL) && (unit->Body.UnitState != UnitState_Fortifying)) { - if (Map_in_range (&p_bic_data->Map, __, unit->Body.X, unit->Body.Y) && - Map_in_range (&p_bic_data->Map, __, unit->Body.PrevMoveX, unit->Body.PrevMoveY)) { - int dx = unit->Body.X - unit->Body.PrevMoveX, dy = unit->Body.Y - unit->Body.PrevMoveY; - int dir = -1; - if ((dx == 1) && (dy == -1)) dir = DIR_NE; - else if ((dx == 2) && (dy == 0)) dir = DIR_E; - else if ((dx == 1) && (dy == 1)) dir = DIR_SE; - else if ((dx == 0) && (dy == 2)) dir = DIR_S; - else if ((dx == -1) && (dy == 1)) dir = DIR_SW; - else if ((dx == -2) && (dy == 0)) dir = DIR_W; - else if ((dx == -1) && (dy == -1)) dir = DIR_NW; - else if ((dx == 0) && (dy == -2)) dir = DIR_N; - if (dir >= 0) - unit->Body.Animation.summary.direction = dir; - } - } - } - - // Apply era aliases - for (int n = 0; n < 32; n++) - if (*p_player_bits & (1 << n)) - apply_era_specific_names (&leaders[n]); - - if (is->current_config.apply_grid_ini_setting_on_game_load) { - int grid_on = get_int_from_conquests_ini ("GridOn", 0, 0); - Map_Renderer * mr = &p_bic_data->Map.Renderer; - if (grid_on && ! mr->MapGrid_Flag) - mr->vtable->m68_Toggle_Grid (mr); - } - - return tr; -} - -void * -load_game_ex (char const * file_path, int suppress_intro_popup) -{ - is->suppress_intro_after_load_popup = suppress_intro_popup; - is->load_file_path_override = file_path; - return patch_do_load_game (NULL); -} - -int __fastcall -patch_show_movement_phase_popup (void * this, int edx, int param_1, int param_2) -{ - int tr = patch_show_popup (this, __, param_1, param_2); - - int player_civ_id = p_main_screen_form->Player_CivID; - int replay_for_players = is->replay_for_players; // Store this b/c it gets reset on game load - if (replay_for_players & 1<showing_hotseat_replay = true; - - patch_do_save_game (hotseat_resume_save_path, 1, 0); - load_game_ex (hotseat_replay_save_path, 1); - p_main_screen_form->Player_CivID = player_civ_id; - - // Re-enable the GUI so the minimap is visible during the replay. We must also reset the minimap & redraw it so that it reflects the - // player we just seated (above) instead of leftover data from the last player. - Main_GUI * main_gui = &p_main_screen_form->GUI; - main_gui->is_enabled = 1; - Navigator_Data_reset (&main_gui->Navigator_Data); - main_gui->Base.vtable->m73_call_m22_Draw ((Base_Form *)main_gui); - - perform_interturn (); - load_game_ex (hotseat_resume_save_path, 1); - p_main_screen_form->is_now_loading_game = 0; - - // Restore the replay_for_players variable b/c it gets cleared when loading a game. Also mask out the bit for the player we just - // showed the replay to. - is->replay_for_players = replay_for_players & ~(1<showing_hotseat_replay = false; - } - - return tr; -} - -// Returns a set of player bits containing only those players that are human and can see at least one AI unit. For speed and simplicity, does not -// account for units' invisibility ability, units are considered visible as long as they're on a visible tile. -int -find_human_players_seeing_ai_units () -{ - int tr = 0; - Map * map = &p_bic_data->Map; - if (map->Tiles != NULL) - for (int n_tile = 0; n_tile < map->TileCount; n_tile++) { - Tile * tile = map->Tiles[n_tile]; - Tile_Body * body = &tile->Body; - int human_vis_bits = (body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility) & *p_human_player_bits; - if (human_vis_bits != 0) // If any human players can see this tile - for (int n_player = 0; n_player < 32; n_player++) - if (human_vis_bits & 1<TileUnitID, &unused); - Unit * unit = get_unit_ptr (unit_id); - if ((unit != NULL) && - ((*p_human_player_bits & 1<Body.CivID) == 0)) { - tr |= 1<current_config.replay_ai_moves_in_hotseat_games && - (*p_is_offline_mp_game && ! *p_is_pbem_game); // offline MP but not PBEM => we're in a hotseat game - int ai_unit_vis_before; - if (save_replay) { - ai_unit_vis_before = find_human_players_seeing_ai_units (); - int toggleable_rules = *p_toggleable_rules; - *p_toggleable_rules |= TR_PRESERVE_RANDOM_SEED; // Make sure preserve random seed is on for the replay save - patch_do_save_game (hotseat_replay_save_path, 1, 0); - *p_toggleable_rules = toggleable_rules; - } - - is->players_saw_ai_unit = 0; // Clear bits. After perform_interturn, each set bit will indicate a player that has seen an AI unit move - long long ts_before; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); - is->time_spent_paused_during_popup = 0; - is->time_spent_computing_city_connections = 0; - is->count_calls_to_recompute_city_connections = 0; - unsigned saved_prefs = *p_preferences; - if (is->current_config.measure_turn_times) - *p_preferences &= ~(P_ANIMATE_BATTLES | P_SHOW_FRIEND_MOVES | P_SHOW_ENEMY_MOVES); - - perform_interturn (); - - if (is->current_config.day_night_cycle_mode) { - if (is->day_night_cycle_img_state == IS_OK) { - int new_hour = calculate_current_day_night_cycle_hour (); - if (new_hour != is->current_day_night_cycle) { - is->current_day_night_cycle = new_hour; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - } - } - } - - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_for_districts (); - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); - } - - if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { - is->city_loc_display_perspective = -1; - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw - } - - if (is->current_config.measure_turn_times) { - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - long long perf_freq; - QueryPerformanceFrequency ((LARGE_INTEGER *)&perf_freq); - int turn_time_in_ms = 1000 * (ts_after - ts_before - is->time_spent_paused_during_popup) / perf_freq; - int city_con_time_in_ms = 1000 * is->time_spent_computing_city_connections / perf_freq; - int road_time_in_ms = 1000 * is->time_spent_filling_roads / perf_freq; - - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - char msg[1000]; - - struct c3x_opt { - bool is_active; - char * name; - } opts[] = {{is->current_config.optimize_improvement_loops, "improv. loops"}, - {is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_OK), "trade net x"}}; - char opt_list[1000]; - memset (opt_list, 0, sizeof opt_list); - strncpy (opt_list, "^C3X optimizations: ", sizeof opt_list); - bool any_active_opts = false; - for (int n = 0; n < ARRAY_LEN (opts); n++) - if (opts[n].is_active) { - char * cursor = &opt_list[strlen (opt_list)]; - snprintf (cursor, opt_list + (sizeof opt_list) - cursor, "%s%s", any_active_opts ? ", " : "", opts[n].name); - any_active_opts = true; - } - if (! any_active_opts) { - char * cursor = &opt_list[strlen (opt_list)]; - strncpy (cursor, "None", opt_list + (sizeof opt_list) - cursor); - } - PopupForm_add_text (popup, __, (char *)opt_list, false); - - snprintf (msg, sizeof msg, "^Turn time: %d.%03d sec", turn_time_in_ms/1000, turn_time_in_ms%1000); - PopupForm_add_text (popup, __, (char *)msg, false); - snprintf (msg, sizeof msg, "^ Recomputing city connections: %d.%03d sec (%d calls)", - city_con_time_in_ms/1000, city_con_time_in_ms%1000, - is->count_calls_to_recompute_city_connections); - PopupForm_add_text (popup, __, (char *)msg, false); - snprintf (msg, sizeof msg, "^ Flood filling road network: %d.%03d sec", - road_time_in_ms/1000, road_time_in_ms%1000); - PopupForm_add_text (popup, __, (char *)msg, false); - patch_show_popup (popup, __, 0, 0); - - *p_preferences = saved_prefs; - } - - if (save_replay) { - int last_human_player_bit = 0; { - for (int n = 0; n < 32; n++) - if (*p_human_player_bits & 1<replay_for_players = (ai_unit_vis_before | (is->players_saw_ai_unit & *p_human_player_bits)) & ~last_human_player_bit; - } -} - -void __cdecl -patch_initialize_map_music (int civ_id, int era_id, bool param_3) -{ - if (! is->showing_hotseat_replay) - initialize_map_music (civ_id, era_id, param_3); -} - -void __stdcall -patch_deinitialize_map_music () -{ - if (! is->showing_hotseat_replay) - deinitialize_map_music (); -} - -void __fastcall -patch_Fighter_do_bombard_tile (Fighter * this, int edx, Unit * unit, int neighbor_index, int mp_tile_x, int mp_tile_y) -{ - // Unit::score_kill will be called if the bombarder destroys its target, and that is the only way score_kill can be called while this method - // is running. So if we're configured to stop enslaving from bombard, turn off enslaving while it's running. - is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; - - // Check if we're going to do PTW-like targeting, if not fall back on the base game's do_bombard_tile method. We'll also fall back on that - // method in the case where we're in an online game and the bombard can't happen b/c the tile is occupied by another battle. In that case, no - // bombard is possible but we'll call the base method anyway since it will show a little message saying as much. - if (itable_look_up_or (&is->current_config.ptw_arty_types, unit->Body.UnitTypeID, 0) && - (is->bombard_stealth_target == NULL) && - ! (is_online_game () && mp_check_current_combat (p_mp_object, __, mp_tile_x, mp_tile_y))) { - - City * city; { - int dx, dy; - neighbor_index_to_diff (neighbor_index, &dx, &dy); - int tile_x = unit->Body.X + dx, tile_y = unit->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - city = city_at (tile_x, tile_y); - } - - int rv; - if ((city != NULL) && ((rv = rand_int (p_rand_object, __, 3)) < 2)) - Fighter_damage_city_by_bombardment (this, __, unit, city, rv, 0); - else - Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); - - } else - Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); - - is->do_not_enslave_units = false; -} - -bool __fastcall -patch_Unit_check_king_for_defense_priority (Unit * this, int edx, enum UnitTypeAbilities king_ability) -{ - return (! is->current_config.ignore_king_ability_for_defense_priority) || (*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) ? - Unit_has_ability (this, __, king_ability) : - false; -} - -void WINAPI -patch_get_local_time_for_unit_ini (LPSYSTEMTIME lpSystemTime) -{ - GetLocalTime (lpSystemTime); - if (is->current_config.no_elvis_easter_egg && (lpSystemTime->wMonth == 1) && (lpSystemTime->wDay == 8)) - lpSystemTime->wDay = 9; -} - -bool __fastcall -patch_Leader_could_buy_tech_for_trade_screen (Leader * this, int edx, int tech_id, int from_civ_id) -{ - // Temporarily remove the untradable flag so this tech is listed on the screen instead of skipped over. After all the items have been - // assembled, we'll go back and disable the untradable techs. - if (is->current_config.show_untradable_techs_on_trade_screen) { - int saved_flags = p_bic_data->Advances[tech_id].Flags; - p_bic_data->Advances[tech_id].Flags &= ~ATF_Cannot_Be_Traded; - bool tr = this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); - p_bic_data->Advances[tech_id].Flags = saved_flags; - return tr; - - } else - return this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); -} - -void __fastcall -patch_DiploForm_assemble_tradable_items (DiploForm * this) -{ - DiploForm_assemble_tradable_items (this); - - // Disable (gray out) all untradable techs - if (is->current_config.show_untradable_techs_on_trade_screen) - for (int n = 0; n < p_bic_data->AdvanceCount; n++) - if (p_bic_data->Advances[n].Flags & ATF_Cannot_Be_Traded) { - this->tradable_technologies[n].can_be_bought = 0; - this->tradable_technologies[n].can_be_sold = 0; - } -} - -bool __fastcall -patch_City_can_trade_via_water (City * this) -{ - if (is->current_config.optimize_improvement_loops) { - for (int n = 0; n < is->water_trade_improvs.count; n++) - if (has_active_building (this, is->water_trade_improvs.items[n])) - return true; - return false; - } else - return City_can_trade_via_water (this); -} - -bool __fastcall -patch_City_can_trade_via_air (City * this) -{ - if (is->current_config.optimize_improvement_loops) { - for (int n = 0; n < is->air_trade_improvs.count; n++) - if (has_active_building (this, is->air_trade_improvs.items[n])) - return true; - return false; - } else - return City_can_trade_via_air (this); -} - -int __fastcall -patch_City_get_building_defense_bonus (City * this) -{ - bool cancel_great_wall_boost = is->current_config.enable_districts && - is->current_config.enable_great_wall_districts && - is->current_config.disable_great_wall_city_defense_bonus; - - if (is->current_config.optimize_improvement_loops || cancel_great_wall_boost) { - int tr = 0; - int is_size_level_1 = (this->Body.Population.Size <= p_bic_data->General.MaximumSize_City) && - (this->Body.Population.Size <= p_bic_data->General.MaximumSize_Town); - for (int n = 0; n < is->combat_defense_improvs.count; n++) { - int improv_id = is->combat_defense_improvs.items[n]; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((is_size_level_1 || (improv->Combat_Bombard == 0)) && has_active_building (this, improv_id)) { - int multiplier; - if ((improv->Combat_Bombard > 0) && - (! cancel_great_wall_boost) && - (patch_Leader_count_any_shared_wonders_with_flag (&leaders[(this->Body).CivID], __, ITW_Doubles_City_Defenses, NULL) > 0)) - multiplier = 2; - else - multiplier = 1; - - int building_defense = multiplier * improv->Combat_Defence; - if (building_defense > tr) - tr = building_defense; - } - } - return tr; - } else - return City_get_building_defense_bonus (this); -} - -bool __fastcall -patch_City_shows_harbor_icon (City * this) -{ - return is->current_config.city_icons_show_unit_effects_not_trade ? - City_count_improvements_with_flag (this, __, ITF_Veteran_Sea_Units) > 0 : - patch_City_can_trade_via_water (this); -} - -bool __fastcall -patch_City_shows_airport_icon (City * this) -{ - return is->current_config.city_icons_show_unit_effects_not_trade ? - City_count_improvements_with_flag (this, __, ITF_Veteran_Air_Units) > 0 : - patch_City_can_trade_via_air (this); -} - -int __fastcall -patch_Unit_eval_escort_requirement (Unit * this) -{ - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - int ai_strat = type->AI_Strategy; - bool owned_by_ai = (*p_human_player_bits & 1<Body.CivID) == 0; // We must not reduce the escort requirement for human-owned units - // because that will interfere with group movement of units. - - // Apply special escort rules - if (owned_by_ai && is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) - return 0; - else if (owned_by_ai && is->current_config.use_offensive_artillery_ai && (ai_strat & UTAI_Artillery)) - return 1; - - else { - int base = Unit_eval_escort_requirement (this); - if (owned_by_ai && (ai_strat & (UTAI_Naval_Transport | UTAI_Naval_Carrier | UTAI_Naval_Missile_Transport))) - return not_above (is->current_config.max_ai_naval_escorts, base); - else - return base; - } -} - -bool __fastcall -patch_Unit_has_enough_escorters_present (Unit * this) -{ - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) - return true; - else - return Unit_has_enough_escorters_present (this); -} - -void __fastcall -patch_Unit_check_escorter_health (Unit * this, int edx, bool * has_any_escort_present, bool * any_escorter_cant_heal) -{ - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) { - *has_any_escort_present = true; - *any_escorter_cant_heal = true; // Returning true here indicates the unit should not stop to wait for its escorter(s) to heal. - } else - Unit_check_escorter_health (this, __, has_any_escort_present, any_escorter_cant_heal); -} - -void __fastcall -patch_Leader_unlock_technology (Leader * this, int edx, int tech_id, bool param_2, bool param_3, bool param_4) -{ - int * p_stack = (int *)&tech_id; - int ret_addr = p_stack[-1]; - - Leader_unlock_technology (this, __, tech_id, param_2, param_3, param_4); - - // If this method was not called during game initialization - if ((ret_addr != ADDR_UNLOCK_TECH_AT_INIT_1) && - (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_2) && - (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_3)) { - - // If this tech obsoletes some building and we're configured to fix the maintenance bug then recompute city maintenance. - if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings) { - bool obsoletes_anything = false; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (p_bic_data->Improvements[n].ObsoleteID == tech_id) { - obsoletes_anything = true; - break; - } - if (obsoletes_anything) - Leader_recompute_buildings_maintenance (this); - } - } -} - -int __fastcall -patch_City_get_improv_maintenance_for_ui (City * this, int edx, int improv_id) -{ - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && - (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) - return 0; - else - return patch_City_get_improvement_maintenance (this, __, improv_id); -} - -// Patch for barbarian diagonal bug. This bug is a small mistake in the original code, maybe a copy+paste error. The original code tries to loop over -// tiles around the barb unit by incrementing a neighbor index and coverting it to tile coords (like normal). The problem is that after it converts -// the neighbor index to dx and dy, it adds dx to both coords of the unit's position instead of using dy. The fix is simply to subtract off dx and add -// in dy when the Y coord is passed to Map::wrap_vert. -void __cdecl -patch_neighbor_index_to_diff_for_barb_ai (int neighbor_index, int * out_x, int * out_y) -{ - neighbor_index_to_diff (neighbor_index, out_x, out_y); - is->barb_diag_patch_dy_fix = *out_y - *out_x; -} -int __fastcall -patch_Map_wrap_vert_for_barb_ai (Map * this, int edx, int y) -{ - return Map_wrap_vert (this, __, is->current_config.patch_barbarian_diagonal_bug ? (y + is->barb_diag_patch_dy_fix) : y); -} - -int -count_workable_tiles_for_city (City * city) -{ - if (city == NULL) - return 0; - - int workable = 0; - FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { - Tile * tile = wai.tile; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - if (tile->Body.CityAreaID != city->Body.ID) - continue; - - struct district_instance * inst = get_district_instance (tile); - if ((inst != NULL) && district_is_complete (tile, inst->district_id)) - continue; - - workable++; - } - return workable; -} - -int -compute_auto_distribution_hub_goal (Leader * leader, int city_count) -{ - int total_unused_tiles = 0; - int stagnating_cities = 0; - int slow_growth_cities = 0; - int very_low_production_cities = 0; - int low_production_cities = 0; - - FOR_CITIES_OF (coi, leader->ID) { - City * city = coi.city; - if (city == NULL) - continue; - - int pop_size = city->Body.Population.Size; - int workable_tiles = count_workable_tiles_for_city (city); - if ((workable_tiles > 0) && (pop_size < workable_tiles)) - total_unused_tiles += workable_tiles - pop_size; - - int net_food = city->Body.FoodIncome; - if (net_food <= 0) - stagnating_cities++; - else if (net_food <= 2) - slow_growth_cities++; - - int net_shields = city->Body.ProductionIncome + city->Body.ProductionLoss; - if (net_shields < 0) - net_shields = 0; - if (net_shields <= 3) - very_low_production_cities++; - else if (net_shields <= 6) - low_production_cities++; - } - - int base_desired = (city_count + 3) / 4; - - int tiles_per_chunk = is->workable_tile_count; - if (tiles_per_chunk <= 0) - tiles_per_chunk = 1; - int unused_bonus = (total_unused_tiles + tiles_per_chunk * 3 - 1) / (tiles_per_chunk * 3); - - int food_pressure = stagnating_cities * 2 + slow_growth_cities; - int food_bonus = (food_pressure + 2) / 3; - - int production_pressure = very_low_production_cities * 2 + low_production_cities; - int production_bonus = (production_pressure + 2) / 3; - - int desired = base_desired + unused_bonus + food_bonus + production_bonus; - int max_reasonable = (city_count + 1) / 2; - int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; - if (max_per_100 > 0) { - int capped = (city_count * max_per_100 + 99) / 100; - if (capped >= 0) - max_reasonable = capped; - } - if (desired > max_reasonable) - desired = max_reasonable; - if (desired < 1) - desired = 1; - - return desired; -} - -void -ai_update_distribution_hub_goal_for_leader (Leader * leader) -{ - if (leader == NULL) - return; - if (! is->current_config.enable_districts || - ! is->current_config.enable_distribution_hub_districts) - return; - - int civ_id = leader->ID; - if ((1 << civ_id) & *p_human_player_bits) - return; - - int city_count = leader->Cities_Count; - if (city_count <= 0) - return; - - int desired = 0; - if (is->current_config.ai_distribution_hub_build_strategy == ADHBS_AUTO) - desired = compute_auto_distribution_hub_goal (leader, city_count); - else { - int ideal_per_100 = is->current_config.ai_ideal_distribution_hub_count_per_100_cities; - if (ideal_per_100 <= 0) - return; - desired = (city_count * ideal_per_100) / 100; - } - if (desired <= 0) - return; - - int current = 0; - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if ((rec != NULL) && (rec->civ_id == civ_id)) - current++; - } - - int in_progress = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * tile = (Tile *)tei.key; - int mapped_district_id = tei.value; - if ((tile != NULL) && - (mapped_district_id == DISTRIBUTION_HUB_DISTRICT_ID) && - ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID)) { - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (owner == civ_id) - in_progress++; - } - } - - int pending = 0; - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req != NULL) && (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID)) - pending++; - } - - int planned = current + in_progress + pending; - if (planned >= desired) - return; - - City * capital = get_city_ptr (leader->CapitalID); - bool has_capital = (capital != NULL); - int capital_x = has_capital ? capital->Body.X : 0; - int capital_y = has_capital ? capital->Body.Y : 0; - - const int yield_weight = 40; - const int capital_distance_weight = 45; - const int desired_min_capital_distance = 8; - const int proximity_penalty_scale = 300; - - while (planned < desired) { - City * best_city = NULL; - int best_tile_x = 0; - int best_tile_y = 0; - int best_score = INT_MIN; - - FOR_CITIES_OF (coi, civ_id) { - City * city = coi.city; - if (city == NULL) - continue; - if (city_has_required_district (city, DISTRIBUTION_HUB_DISTRICT_ID)) - continue; - - if (find_pending_district_request (city, DISTRIBUTION_HUB_DISTRICT_ID) != NULL) - continue; - - int tile_x, tile_y; - Tile * candidate = find_tile_for_district (city, DISTRIBUTION_HUB_DISTRICT_ID, &tile_x, &tile_y); - if (candidate == NULL) - continue; - - int yield_sum = compute_city_tile_yield_sum (city, tile_x, tile_y); - int distance_to_capital = 0; - if (has_capital) - distance_to_capital = compute_wrapped_manhattan_distance (city->Body.X, city->Body.Y, capital_x, capital_y); - - int closeness_penalty = 0; - if (has_capital && (distance_to_capital < desired_min_capital_distance)) - closeness_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; - - int score = yield_sum * yield_weight + distance_to_capital * capital_distance_weight - closeness_penalty; - if (tile_has_resource (candidate)) - score -= 500; - - if (score > best_score) { - best_score = score; - best_city = city; - best_tile_x = tile_x; - best_tile_y = tile_y; - } - } - - if (best_city == NULL) - break; - - mark_city_needs_district (best_city, DISTRIBUTION_HUB_DISTRICT_ID); - planned++; - } -} - -bool -assign_ai_fallback_production (City * city, int disallowed_improvement_id) -{ - if (city == NULL) - return false; - - City_Order new_order = { .OrderID = -1, .OrderType = 0 }; - patch_City_ai_choose_production (city, __, &new_order); - - bool order_ok = false; - if (new_order.OrderType == COT_Improvement) { - if ((new_order.OrderID >= 0) && - (new_order.OrderID < p_bic_data->ImprovementsCount) && - (new_order.OrderID != disallowed_improvement_id) && - ! city_requires_district_for_improvement (city, new_order.OrderID, NULL) && - ! is_wonder_or_small_wonder_already_being_built (city, new_order.OrderID)) - order_ok = true; - } else if (new_order.OrderType == COT_Unit) { - if ((new_order.OrderID >= 0) && - (new_order.OrderID < p_bic_data->UnitTypeCount) && - (p_bic_data->UnitTypes[new_order.OrderID].Unit_Class == UTC_Land) && - patch_City_can_build_unit (city, __, new_order.OrderID, 1, 0, 0)) - order_ok = true; - } - - char ss[200]; - snprintf (ss, sizeof ss, "assign_ai_fallback_production: Remembering fallback pending building order for city %d (%s): id %d\n", - city->Body.ID, city->Body.CityName, disallowed_improvement_id); - (*p_OutputDebugStringA) (ss); - remember_pending_building_order (city, disallowed_improvement_id); - - if (order_ok) { - City_set_production (city, __, new_order.OrderType, new_order.OrderID, false); - return true; - } - - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) { - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - return true; - } - } - - return false; -} - -void __fastcall -patch_Leader_do_production_phase (Leader * this) -{ - recompute_resources_if_necessary (); - - if (is->current_config.enable_districts) { - assign_workers_for_pending_districts (this); - - if ((is->current_config.enable_canal_districts || is->current_config.enable_bridge_districts) && - (is->current_config.ai_builds_bridges || is->current_config.ai_builds_canals)) - assign_workers_for_ai_candidate_bridge_or_canals (this); - - bool ai_player = ((*p_human_player_bits & (1 << this->ID)) == 0); - int auto_dynamic_district_ids[COUNT_DISTRICT_TYPES]; - int auto_dynamic_district_count = 0; - - // For dynamic districts, the AI will never be triggered to build them if they have no dependent buildings. - // Determine which dynamic districts the AI could build. In the city loop after, mark which cities need them - if (ai_player) { - for (int district_id = is->special_district_count; district_id < is->district_count; district_id++) { - struct district_config * cfg = &is->district_configs[district_id]; - struct district_infos * info = &is->district_infos[district_id]; - - if (info->dependent_building_count > 0) continue; - if (cfg->command == -1) continue; - - if (! leader_can_build_district (this, district_id)) - continue; - - if (auto_dynamic_district_count < ARRAY_LEN (auto_dynamic_district_ids)) - auto_dynamic_district_ids[auto_dynamic_district_count++] = district_id; - } - } - - // Special exception for AI to build Central Rail Hub, which is available in Industrial era but Mass Transit, - // the only building dependent on it, is in the Modern era. Without this the AI wouldn't build in Industrial era. - if (is->current_config.enable_central_rail_hub_districts) { - if (leader_can_build_district (this, CENTRAL_RAIL_HUB_DISTRICT_ID)) - auto_dynamic_district_ids[auto_dynamic_district_count++] = CENTRAL_RAIL_HUB_DISTRICT_ID; - } - - if (is->current_config.enable_distribution_hub_districts) { - if (leader_can_build_district (this, DISTRIBUTION_HUB_DISTRICT_ID)) - ai_update_distribution_hub_goal_for_leader (this); - } - - FOR_CITIES_OF (coi, this->ID) { - City * city = coi.city; - if (city == NULL) continue; - - bool at_neighborhood_cap = is->current_config.enable_neighborhood_districts && city_is_at_neighborhood_cap (city); - - // Mark any needed dynamic districts for AI players. This isn't the most intelligent approach (we're not weighing district benefits), - // but it's simple and works reasonably well - if (ai_player && (auto_dynamic_district_count > 0)) { - for (int i = 0; i < auto_dynamic_district_count; i++) { - int district_id = auto_dynamic_district_ids[i]; - - if (city_has_required_district (city, district_id)) continue; - if (! city_can_build_district (city, district_id)) continue; - if (find_pending_district_request (city, district_id) != NULL) continue; - - int target_x = 0, target_y = 0; - if (find_tile_for_district (city, district_id, &target_x, &target_y) == NULL) - continue; - - mark_city_needs_district (city, district_id); - } - } - - if (at_neighborhood_cap) { - if (! ai_player) - maybe_show_neighborhood_growth_warning (city); - else - ensure_neighborhood_request_for_city (city); - } - - if (city->Body.Order_Type == COT_Unit) { - int unit_id = city->Body.Order_ID; - int req_district_id = -1; - bool needs_halt = false; - - if ((unit_id >= 0) && (unit_id < p_bic_data->UnitTypeCount)) { - UnitType * type = &p_bic_data->UnitTypes[unit_id]; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { - req_district_id = AERODROME_DISTRICT_ID; - needs_halt = true; - } else if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (city, PORT_DISTRICT_ID))) { - req_district_id = PORT_DISTRICT_ID; - needs_halt = true; - } - } - - if (needs_halt) { - char ss[200]; - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting unit %d due to missing district %d\n", - city->Body.ID, city->Body.CityName, unit_id, req_district_id); - (*p_OutputDebugStringA) (ss); - - if (ai_player) - mark_city_needs_district (city, req_district_id); - - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - - continue; - } - } - - if (city->Body.Order_Type != COT_Improvement) continue; - int i_improv = city->Body.Order_ID; - - // Check if production needs to be halted due to missing district - int req_district_id = -1; - char const * district_description = NULL; - bool needs_halt = false; - - // Check buildings & wonders dependent on districts - if (city_requires_district_for_improvement (city, i_improv, &req_district_id)) { - if (req_district_id >= 0) { - needs_halt = true; - district_description = is->district_configs[req_district_id].name; - } - } - - // Wonders - char ss[200]; - if (is->current_config.enable_wonder_districts) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: Checking wonder improv %d for city %d (%s)\n", - i_improv, city->Body.ID, city->Body.CityName); - (*p_OutputDebugStringA) (ss); - if (city_is_currently_building_wonder (city)) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) is building wonder improv %d\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - bool wonder_requires_district = false; - if (i_improv >= 0) { - struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); - if (district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) - wonder_requires_district = true; - } - - if (wonder_requires_district) { - bool has_wonder_district = reserve_wonder_district_for_city (city, i_improv); - if (! has_wonder_district) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) lacks Wonder District for wonder improv %d\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - needs_halt = true; - req_district_id = WONDER_DISTRICT_ID; - district_description = "Wonder District"; - } - } else { - release_wonder_district_reservation (city); - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) wonder improv %d does not require Wonder District\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - } - } else { - release_wonder_district_reservation (city); - } - } - - // If production needs to be halted, handle the reassignment and messaging - if (needs_halt) { - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting improv %d due to missing district %d\n", - city->Body.ID, city->Body.CityName, i_improv, req_district_id); - (*p_OutputDebugStringA) (ss); - // Switch production to another option - if (ai_player) { - mark_city_needs_district (city, req_district_id); - assign_ai_fallback_production (city, i_improv); - } else { - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (city, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - // Show message to human player - if (! ai_player && (city->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[160]; - char const * bname = p_bic_data->Improvements[i_improv].Name.S; - snprintf (msg, sizeof msg, "%s %s %s", bname, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_description); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (city->Body.X, city->Body.Y, msg, true); - } - continue; - } - snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) improv %d passed missing district check\n", - city->Body.ID, city->Body.CityName, i_improv); - (*p_OutputDebugStringA) (ss); - } - } - - // Force-activate the barbs if there are any barb cities on the map and barb city capturing is enabled. This is necessary for barb city - // production to work given how it's currently implemented. - if (is->current_config.enable_city_capture_by_barbarians && (this->ID == 0)) { - int any_barb_cities = 0; - FOR_CITIES_OF (coi, this->ID) { - any_barb_cities = 1; - break; - } - if (any_barb_cities) - is->force_barb_activity_for_cities = 1; - } - - // If barbs are force-activated, make sure their activity level is at least 1 (sedentary). - int * p_barb_activity = &p_bic_data->Map.World.Final_Barbarians_Activity; - int saved_barb_activity = *p_barb_activity; - if (is->force_barb_activity_for_cities && (*p_barb_activity <= 0)) - *p_barb_activity = 1; - - Leader_do_production_phase (this); - - if (is->force_barb_activity_for_cities) { - *p_barb_activity = saved_barb_activity; - is->force_barb_activity_for_cities = 0; - } -} - -// This function counts the number of players in the game. The return value will be compared to the number of cities on the map to determine if there -// are enough cities (per player) to unlock barb production. If barb activity is forced on, return zero so that the check always passes. -int __cdecl -patch_count_player_bits_for_barb_prod (unsigned int bit_field) -{ - return is->force_barb_activity_for_cities ? 0 : count_set_bits (bit_field); -} - -Tile * __fastcall -patch_Map_get_tile_to_check_visibility (Map * this, int edx, int index) -{ - Tile * tr = Map_get_tile (this, __, index); - int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; - if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { - int human_bits = *p_human_player_bits; - is->dummy_tile->Body.Fog_Of_War = tr->Body.Fog_Of_War | ((tr->Body.Fog_Of_War & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.FOWStatus = tr->Body.FOWStatus | ((tr->Body.FOWStatus & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.V3 = tr->Body.V3 | ((tr->Body.V3 & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.Visibility = tr->Body.Visibility | ((tr->Body.Visibility & human_bits) != 0 ? human_bits : 0); - is->dummy_tile->Body.field_D0_Visibility = tr->Body.field_D0_Visibility | ((tr->Body.field_D0_Visibility & human_bits) != 0 ? human_bits : 0); - tr = is->dummy_tile; - } - is->tile_returned_for_visibility_check = tr; - return tr; -} - -Tile * __fastcall -patch_Map_get_tile_to_check_visibility_again (Map * this, int edx, int index) -{ - return is->tile_returned_for_visibility_check; -} - -// Same as above except this method uses the FOWStatus field instead of Fog_Of_War -Tile * __fastcall -patch_Map_get_tile_for_fow_status_check (Map * this, int edx, int index) -{ - Tile * tile = Map_get_tile (this, __, index); - int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; - if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { - is->dummy_tile->Body.FOWStatus = ((tile->Body.FOWStatus & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; - return is->dummy_tile; - } else - return tile; -} - -Tile * __cdecl -patch_tile_at_to_check_visibility (int x, int y) -{ - return patch_Map_get_tile_to_check_visibility (&p_bic_data->Map, __, (p_bic_data->Map.Width >> 1) * y + (x >> 1)); -} - -Tile * __cdecl -patch_tile_at_to_check_visibility_again (int x, int y) -{ - return is->tile_returned_for_visibility_check; -} - -unsigned __fastcall -patch_Tile_m42_Get_Overlays (Tile * this, int edx, byte visible_to_civ) -{ - unsigned base_vis_overlays = Tile_m42_Get_Overlays (this, __, visible_to_civ); - if ((visible_to_civ != 0) && // if we're seeing from a player's persp. instead of seeing the actual overlays AND - is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND - ((1 << visible_to_civ) & *p_human_player_bits) && // the perspective is of a human player AND - (base_vis_overlays != this->Overlays) && // that player can't already see all the actual overlays AND - (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game - - // Check if there's another human player that can see the actual overlays. If so, give that info to this player and return it. - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != visible_to_civ) && - (Tile_m42_Get_Overlays (this, __, n_player) == this->Overlays)) { - this->Body.Visibile_Overlays[visible_to_civ] = this->Overlays; - return this->Overlays; - } - player_bits >>= 1; - n_player++; - } - - return base_vis_overlays; - } else - return base_vis_overlays; -} - -int __fastcall -patch_Tile_check_water_for_sea_zoc (Tile * this) -{ - if ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) - return this->vtable->m35_Check_Is_Water (this); - else - return 1; // The caller will skip ZoC logic if this is a land tile without a city because the targeted unit is a sea unit. Instead - // return 1, so all tiles are considered sea tiles, so we can run the ZoC logic for land units or air units on land. -} - -int __fastcall -patch_Tile_check_water_for_land_zoc (Tile * this) -{ - // Same as above except this time we want to consider all tiles to be land - return ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) ? - this->vtable->m35_Check_Is_Water (this) : - 0; -} - - -int __fastcall -patch_Unit_get_attack_strength_for_sea_zoc (Unit * this) -{ - return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) ? Unit_get_attack_strength (this) : 0; -} - -int __fastcall -patch_Unit_get_attack_strength_for_land_zoc (Unit * this) -{ - return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) ? Unit_get_attack_strength (this) : 0; -} - -// Forward declaration; defined further below near patch_Fighter_get_odds_for_main_combat_loop -// where its dependencies (apply_counter_rules, Fighter_get_combat_odds, counter_combat_ctx) live. -Unit * find_civ4_best_defender_against (Unit * attacker, Tile * tile, int tile_x, int tile_y); - -Unit * __fastcall -patch_Main_Screen_Form_find_visible_unit (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * excluded) -{ - struct unit_display_override * override = &is->unit_display_override; - if ((override->unit_id >= 0) && (override->tile_x == tile_x) && (override->tile_y == tile_y)) { - Unit * unit = get_unit_ptr (override->unit_id); - if (unit != NULL) { - if ((unit->Body.X == tile_x) && (unit->Body.Y == tile_y)) - return unit; - } - } - - // Civ 4-style 'best defender' display: when a player selects an attacker, the unit at the top of the enemy stack - // should be the one with the lowest win rate against that attacker. - // Only takes effect when both `use_civ4_style_best_defender` and `enable_unit_counters` are enabled, - // and provided the currently selected unit belongs to the local player and there is an enemy unit on the target square. - // - if (is->current_config.use_civ4_style_best_defender && - is->current_config.enable_unit_counters && - (this->Current_Unit != NULL) && - (this->Current_Unit->Body.CivID == this->Player_CivID) && - ((this->Current_Unit->Body.X != tile_x) || (this->Current_Unit->Body.Y != tile_y))) { - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile) && - tile_has_enemy_unit (tile, this->Current_Unit->Body.CivID)) { - Unit * best = find_civ4_best_defender_against (this->Current_Unit, tile, tile_x, tile_y); - if ((best != NULL) && (best != excluded)) - return best; - } - } - - return Main_Screen_Form_find_visible_unit (this, __, tile_x, tile_y, excluded); -} - -void __fastcall -patch_Animator_play_zoc_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) -{ - if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Air) - Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); -} - -bool __fastcall -patch_Fighter_check_zoc_anim_visibility (Fighter * this, int edx, Unit * attacker, Unit * defender, bool param_3) -{ - // If we've reached this point in the code (in the calling method) then a unit has been selected to exert zone of control and it has passed - // its dice roll to cause damage. Stash its pointer for possible use later. - is->zoc_interceptor = attacker; - - // If an air unit was selected, pre-emptively undo the damage from ZoC since we'll want to run our own bit of logic to do that (the air unit - // may still get shot down). Return false from this function to skip over all of the animation logic in the caller since it wouldn't work for - // aircraft. - if (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Air) { - defender->Body.Damage -= 1; - return false; - - // Repeat a check done by the caller. We've deleted this check to ensure that this function always gets called so we can grab the interceptor. - } else if (attacker->Body.Animation.field_111 == 0) - return false; - - else { - bool tr = Fighter_check_combat_anim_visibility (this, __, attacker, defender, param_3); - - // If necessary, set up to ensure the unit's attack animation is visible. This means forcing it to the top of its stack and - // temporarily unfortifying it if it's fortified. (If it's fortified, the animation is occasionally not visible. Don't know why.) - if (tr && is->current_config.show_zoc_attacks_from_mid_stack) { - is->unit_display_override = (struct unit_display_override) { attacker->Body.ID, attacker->Body.X, attacker->Body.Y }; - if (attacker->Body.UnitState == UnitState_Fortifying) { - Unit_set_state (attacker, __, 0); - is->refortify_interceptor_after_zoc = true; - } - } - - return tr; - } -} - -int __fastcall -patch_City_sum_buildings_naval_power_for_zoc (City * this) -{ - // Cancel out city's naval power if the unit has only one HP left. This prevents coastal fortresses from knocking that last hit point off - // passing units when lethal ZoC is enabled, because to make that work we delete an earlier check excusing 1-HP units from ZoC. - if ((is->zoc_defender != NULL) && - ((Unit_get_max_hp (is->zoc_defender) - is->zoc_defender->Body.Damage) <= 1)) - return 0; - - else - return City_sum_buildings_naval_power (this); -} - -void __fastcall -patch_Fighter_apply_zone_of_control (Fighter * this, int edx, Unit * unit, int from_x, int from_y, int to_x, int to_y) -{ - is->zoc_interceptor = NULL; - is->zoc_defender = unit; - is->refortify_interceptor_after_zoc = false; - struct unit_display_override saved_udo = is->unit_display_override; - Fighter_apply_zone_of_control (this, __, unit, from_x, from_y, to_x, to_y); - - // Actually exert ZoC if an air unit managed to do so. - if ((is->zoc_interceptor != NULL) && (p_bic_data->UnitTypes[is->zoc_interceptor->Body.UnitTypeID].Unit_Class == UTC_Air)) { - bool intercepted = Unit_try_flying_over_tile (is->zoc_interceptor, __, from_x, from_y); - if (! intercepted) { - Unit_play_bombing_animation (is->zoc_interceptor, __, from_x, from_y); - unit->Body.Damage = not_below (0, unit->Body.Damage + 1); - } - } - - if (is->refortify_interceptor_after_zoc) - Unit_set_state (is->zoc_interceptor, __, UnitState_Fortifying); - is->unit_display_override = saved_udo; -} - -// These two patches replace two function calls in Unit::move_to_adjacent_tile that come immediately after the unit has been subjected to zone of -// control. These calls recheck that the move is valid, not sure why. Here they're patched to indicate that the move in invalid when the unit was -// previously killed by ZoC. This causes move_to_adjacent_tile to return early without running the code that would place the unit on the destination -// tile and, for example, capturing an enemy city there. -int __fastcall -patch_Trade_Net_get_move_cost_after_zoc (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned param_7, int neighbor_index, Trade_Net_Distance_Info * dist_info) -{ - return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (unit) - unit->Body.Damage) > 0) ? - patch_Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, param_7, neighbor_index, dist_info) : - -1; -} - -AdjacentMoveValidity __fastcall -patch_Unit_can_move_after_zoc (Unit * this, int edx, int neighbor_index, int param_2) -{ - return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (this) - this->Body.Damage) > 0) ? - patch_Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2) : - AMV_1; -} - -// Checks unit's HP after it was possibly hit by ZoC and deals with the consequences if it's dead. Does nothing if config option to make ZoC lethal -// isn't set or if interceptor is NULL. Returns true if the unit was killed, false otherwise. -bool -check_life_after_zoc (Unit * unit, Unit * interceptor) -{ - if ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) && (interceptor != NULL) && - ((Unit_get_max_hp (unit) - unit->Body.Damage) <= 0)) { - - // Call Unit::score_kill but turn off enslaving if we're configured to stop enslaving after bombardment and the ZoC was performed by - // bombardment, which is always the case for cross-domain ZoC or when bombard str > attack. - UnitType * interceptor_type = &p_bic_data->UnitTypes[interceptor->Body.UnitTypeID]; - if (is->current_config.prevent_enslaving_by_bombardment && - ((p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != interceptor_type->Unit_Class) || - (interceptor_type->Bombard_Strength >= Unit_get_attack_strength (interceptor)))) - is->do_not_enslave_units = true; - Unit_score_kill (interceptor, __, unit, false); - is->do_not_enslave_units = false; - - if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (&p_bic_data->fighter, __, interceptor, unit, true)) - Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, unit, AT_DEATH, false); - - bool prev_always_despawn_passengers = is->always_despawn_passengers; - is->always_despawn_passengers = is_land_transport (unit) && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); - patch_Unit_despawn (unit, __, interceptor->Body.CivID, 0, 0, 0, 0, 0, 0); - is->always_despawn_passengers = prev_always_despawn_passengers; - - return true; - } else - return false; -} - -int __fastcall -patch_Unit_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, bool param_2, int param_3, byte param_4) -{ - is->moving_unit_to_adjacent_tile = true; - is->move_spend_override_unit = NULL; - is->move_spend_override_value = 0; - - bool const allow_worker_coast = is->current_config.enable_districts && is->current_config.workers_can_enter_coast && is_worker (this); - bool const allow_bridge_walk = is->current_config.enable_districts && - is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land); - bool const allow_canal_sail = is->current_config.enable_districts && - is->current_config.enable_canal_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea); - bool coast_override_active = false; - enum UnitStateType prev_state = this->Body.UnitState; - int prev_container = this->Body.Container_Unit; - bool restore_goto_path = prev_state == UnitState_Go_To; - int prev_path_len = this->Body.path_len; - int prev_path_dest_x = this->Body.path_dest_x; - int prev_path_dest_y = this->Body.path_dest_y; - - if (allow_worker_coast || allow_bridge_walk || allow_canal_sail) { - int nx, ny; - get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); - Tile * dest = tile_at (nx, ny); - if (dest != NULL) { - if (allow_bridge_walk && ! dest->vtable->m35_Check_Is_Water (dest)) { - Tile * src = tile_at (this->Body.X, this->Body.Y); - if ((src != NULL) && (src != p_null_tile)) { - struct district_instance * src_inst = get_district_instance (src); - bool from_bridge = (src_inst != NULL) && - (src_inst->district_id == BRIDGE_DISTRICT_ID) && - district_is_complete (src, src_inst->district_id); - if (from_bridge) { - int move_cost = patch_Trade_Net_get_movement_cost ( - is->trade_net, __, - this->Body.X, this->Body.Y, nx, ny, - this, this->Body.CivID, 0, neighbor_index, NULL); - if (move_cost >= 0) { - int spent_moves = this->Body.Moves + move_cost; - is->move_spend_override_unit = this; - is->move_spend_override_value = not_above (spent_moves, patch_Unit_get_max_move_points (this)); - } - } - } - } - - bool should_override = false; - if (allow_worker_coast && - dest->vtable->m35_Check_Is_Water (dest) && - (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - if (is_human) { - should_override = true; - } else { - struct district_worker_record * rec = get_tracked_worker_record (this); - struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; - if (req != NULL) { - City * req_city = (req->city != NULL) ? req->city : get_city_ptr (req->city_id); - if ((req->district_id >= 0) && - (req->district_id < is->district_count) && - (req_city != NULL) && - city_radius_contains_tile (req_city, nx, ny) && - (req->target_x == nx) && (req->target_y == ny)) { - struct district_config const * cfg = &is->district_configs[req->district_id]; - if ((cfg->buildable_square_types_mask & (1 << SQ_Coast)) != 0) - should_override = true; - } - } - } - } - - if (! should_override && allow_bridge_walk) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && - (inst->district_id == BRIDGE_DISTRICT_ID) && - district_is_complete (dest, inst->district_id)) - should_override = true; - } - - if (! should_override && allow_canal_sail) { - struct district_instance * inst = get_district_instance (dest); - if ((inst != NULL) && - (inst->district_id == CANAL_DISTRICT_ID) && - district_is_complete (dest, inst->district_id)) - should_override = true; - } - - if (should_override) { - coast_override_active = true; - is->coast_walk_unit = this; - is->coast_walk_transport_override = false; - is->coast_walk_prev_state = prev_state; - is->coast_walk_prev_container = prev_container; - is->coast_walk_restore_goto_path = restore_goto_path; - is->coast_walk_prev_path_len = prev_path_len; - is->coast_walk_prev_path_dest_x = prev_path_dest_x; - is->coast_walk_prev_path_dest_y = prev_path_dest_y; - } - } - } - - is->zoc_interceptor = is->zoc_defender = NULL; - int tr = Unit_move_to_adjacent_tile (this, __, neighbor_index, param_2, param_3, param_4); - if ((this == is->zoc_defender) && check_life_after_zoc (this, is->zoc_interceptor)) - tr = ! is_online_game (); // This is what the original method returns when the unit was destroyed in combat - - if (coast_override_active) { - is->coast_walk_unit = NULL; - is->coast_walk_transport_override = false; - - if (this->Body.Container_Unit == this->Body.ID) { - this->Body.Container_Unit = is->coast_walk_prev_container; - Unit_set_state (this, __, is->coast_walk_prev_state); - if (is->coast_walk_restore_goto_path) { - this->Body.path_len = is->coast_walk_prev_path_len; - this->Body.path_dest_x = is->coast_walk_prev_path_dest_x; - this->Body.path_dest_y = is->coast_walk_prev_path_dest_y; - } - } - } - - is->temporarily_disallow_lethal_zoc = false; - is->moving_unit_to_adjacent_tile = false; - is->move_spend_override_unit = NULL; - is->move_spend_override_value = 0; - return tr; -} - -void __fastcall -patch_Unit_load_into_army_after_move_to_adj_tile (Unit * this, int edx, Unit * loadee) -{ - // Take care not to load an army into itself b/c that will cause the game to crash. The game may attempt to do that at the end of - // move_to_adjacent_tile b/c we return the unit itself as a transport target when we want to allow it to move onto coast. - if (is->coast_walk_transport_override && this == loadee) - return; - - Unit_load_into_army (this, __, loadee); -} - -int __fastcall -patch_Unit_teleport (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad) -{ - is->zoc_interceptor = NULL; - int tr = Unit_teleport (this, __, tile_x, tile_y, unit_telepad); - check_life_after_zoc (this, is->zoc_interceptor); - return tr; -} - -bool -can_do_defensive_bombard (Unit * unit, UnitType * type) -{ - if ((type->Bombard_Strength > 0) && (! Unit_has_ability (unit, __, UTA_Cruise_Missile))) { - if (cannot_defend_inside_transport (unit)) - return false; - - if ((unit->Body.Status & USF_USED_DEFENSIVE_BOMBARD) == 0) // has not already done DB this turn - return true; - - // If the "blitz" special DB rule is activated and this unit has blitz, check if it still has an extra DB to use - else if ((is->current_config.special_defensive_bombard_rules & SDBR_BLITZ) && UnitType_has_ability (type, __, UTA_Blitz)) { - int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, unit->Body.ID, 0); - return type->Movement > extra_dbs + 1; - - } else - return false; - } else - return false; -} - -Unit * __fastcall -patch_Fighter_find_defensive_bombarder (Fighter * this, int edx, Unit * attacker, Unit * defender) -{ - int special_db_rules = is->current_config.special_defensive_bombard_rules; - if ((special_db_rules == 0) && - ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) == 0) && - ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) == 0)) - return Fighter_find_defensive_bombarder (this, __, attacker, defender); - else { - enum UnitTypeClasses attacker_class = p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class; - int attacker_has_one_hp = Unit_get_max_hp (attacker) - attacker->Body.Damage <= 1; - - Tile * defender_tile = tile_at (defender->Body.X, defender->Body.Y); - if ((Unit_get_defense_strength (attacker) < 1) || // if attacker cannot defend OR - (defender_tile == NULL) || (defender_tile == p_null_tile) || // defender tile is invalid OR - (((special_db_rules & SDBR_LETHAL) == 0) && attacker_has_one_hp) || // (DB is non-lethal AND attacker has one HP remaining) OR - ((special_db_rules & SDBR_NOT_INVISIBLE) && ! patch_Unit_is_visible_to_civ (attacker, __, defender->Body.CivID, 1))) // (invisible units are immune to DB AND attacker is invisible) - return NULL; - - Unit * tr = NULL; - int highest_strength = -1; - enum UnitTypeAbilities lethal_bombard_req = (attacker_class == UTC_Sea) ? UTA_Lethal_Sea_Bombardment : UTA_Lethal_Land_Bombardment; - FOR_UNITS_ON (uti, defender_tile) { - Unit * candidate = uti.unit; - UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; - if (can_do_defensive_bombard (candidate, candidate_type) && - (candidate_type->Bombard_Strength > highest_strength) && - (candidate != defender) && - (Unit_get_containing_army (candidate) != defender) && - ((attacker_class == candidate_type->Unit_Class) || - ((special_db_rules & SDBR_AERIAL) && - (candidate_type->Unit_Class == UTC_Air) && - (candidate_type->Air_Missions & UCV_Bombing)) || - ((special_db_rules & SDBR_DOCKED_VS_LAND) && - (candidate_type->Unit_Class == UTC_Sea) && - (get_city_ptr (defender_tile->CityID) != NULL))) && - ((! attacker_has_one_hp) || UnitType_has_ability (candidate_type, __, lethal_bombard_req))) { - tr = candidate; - highest_strength = candidate_type->Bombard_Strength; - } - } - return tr; - } -} - -void __fastcall -patch_Fighter_damage_by_db_in_main_loop (Fighter * this, int edx, Unit * bombarder, Unit * defender) -{ - if (p_bic_data->UnitTypes[bombarder->Body.UnitTypeID].Unit_Class == UTC_Air) { - if (Unit_try_flying_over_tile (bombarder, __, defender->Body.X, defender->Body.Y)) - return; // intercepted - else if (patch_Main_Screen_Form_is_unit_visible_to_player (p_main_screen_form, __, defender->Body.X, defender->Body.Y, bombarder)) - Unit_play_bombing_animation (bombarder, __, defender->Body.X, defender->Body.Y); - } - - // If the unit has already performed DB this turn, then record that it's consumed one of its extra DBs - if (bombarder->Body.Status & USF_USED_DEFENSIVE_BOMBARD) { - int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, bombarder->Body.ID, 0); - itable_insert (&is->extra_defensive_bombards, bombarder->Body.ID, extra_dbs + 1); - } - - int damage_before = defender->Body.Damage; - Fighter_damage_by_defensive_bombard (this, __, bombarder, defender); - int damage_after = defender->Body.Damage; - - is->dbe.bombarder = bombarder; - is->dbe.defender = defender; - if (damage_after > damage_before) { - is->dbe.damage_done = true; - int max_hp = Unit_get_max_hp (defender); - int dead_before = damage_before >= max_hp, dead_after = damage_after >= max_hp; - - // If the unit was killed by defensive bombard, play its death animation then toggle off animations for the rest of the combat so it - // doesn't look like anything else happens. Technically, the combat continues and the dead unit is guarantted to lose because the - // patch to get_combat_odds ensures the dead unit has no chance of winning a round. - if (dead_before ^ dead_after) { - is->dbe.defender_was_destroyed = true; - if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (this, __, bombarder, defender, true)) - Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, defender, AT_DEATH, false); - is->dbe.saved_animation_setting = this->play_animations; - this->play_animations = 0; - } - } -} - -int __fastcall -patch_Fighter_get_odds_for_main_combat_loop (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses) -{ - if (is->dbe.defender_was_destroyed) - return 1025; - - struct c3x_config * cfg = &is->current_config; - // Only OR in counter-rule terrain skipping when we actually ran apply_counter_rules for this - // call. Otherwise counter_combat_ctx.ignore_terrain can be stale from an earlier probe (e.g. - // find_civ4_best_defender_against) or an earlier combat round — especially risky after - // merges that add new odds call sites. - bool ignore_terrain_for_odds = ignore_defensive_bonuses; - if (cfg->enable_unit_counters && attacker != NULL && defender != NULL) { - Tile * def_tile = tile_at (this->defender_location_x, - this->defender_location_y); - int aa, dd; - bool ignore_terrain; - apply_counter_rules (cfg, attacker, defender, def_tile, - &aa, &dd, &ignore_terrain); - - is->counter_combat_ctx.active = true; - is->counter_combat_ctx.attacker = attacker; - is->counter_combat_ctx.defender = defender; - is->counter_combat_ctx.attacker_atk_pct = aa; - is->counter_combat_ctx.defender_def_pct = dd; - is->counter_combat_ctx.ignore_terrain = ignore_terrain; - ignore_terrain_for_odds = ignore_defensive_bonuses || ignore_terrain; - } - - int result = Fighter_get_combat_odds (this, __, attacker, defender, bombarding, - ignore_terrain_for_odds); - is->counter_combat_ctx.active = false; - return result; -} - -// Civ 4-style best defender: On the specified tile, pick the defender that is hardest for the -// attacker to beat (i.e. the one with the highest *defender* win rate against the attacker). -// Takes unit counter rules into account. Returns NULL if there is no suitable defender. -// -// IMPORTANT — odds semantics: vanilla Fighter_get_combat_odds returns the *defender*'s win -// chance (out of ~1024), not the attacker's. Confirmed by the existing patch at -// patch_Fighter_get_odds_for_main_combat_loop: when the attacker has been killed by defensive -// bombardment ("defender_was_destroyed"), the patch returns 1025 so the still-running combat -// loop sees ~100% defender win chance and finishes off the doomed attacker. Therefore "hardest -// to beat" = "highest defender win chance" = max odds. -// -// Notes: -// - Skips units with Container_Unit >= 0 (units inside armies/transports; only the top unit represents the group). -// - Skips units not visible to the attacker's civ, avoiding revealing invisible units. -// - Skips units of the same civ as the attacker (they cannot defend). -// - Skips units with defense strength <= 0 (incapable of combat). -// - Temporarily overwrites is->counter_combat_ctx internally and saves/restores the context before/after execution, -// to avoid disrupting the actual combat odds context. -Unit * -find_civ4_best_defender_against (Unit * attacker, Tile * tile, int tile_x, int tile_y) -{ - if ((attacker == NULL) || (tile == NULL) || (tile == p_null_tile)) - return NULL; - - // Defensive: validate attacker shape before we deref any of its fields downstream. If the - // pointer is stale or refers to a half-initialized unit, UnitTypeID will be out of range and - // we bail out instead of crashing inside Fighter_get_combat_odds / vtable calls. - int atk_tid = attacker->Body.UnitTypeID; - if ((atk_tid < 0) || (atk_tid >= p_bic_data->UnitTypeCount)) - return NULL; - - struct c3x_config * cfg = &is->current_config; - int attacker_civ = attacker->Body.CivID; - - // Backup the current counter ctx, as we'll be repeatedly overwriting it within the loop. - bool saved_active = is->counter_combat_ctx.active; - Unit * saved_attacker = is->counter_combat_ctx.attacker; - Unit * saved_defender = is->counter_combat_ctx.defender; - int saved_attacker_atk = is->counter_combat_ctx.attacker_atk_pct; - int saved_defender_def = is->counter_combat_ctx.defender_def_pct; - bool saved_ignore_terrain = is->counter_combat_ctx.ignore_terrain; - - // Backup the live Fighter struct fields. Vanilla Fighter_get_combat_odds may consult - // fighter.attacker / fighter.defender / fighter.defender_location_x/y to fetch terrain or - // state; if those still point at units from a previous combat (or are NULL during init), the - // vanilla code can dereference garbage and crash. We point them at the current candidate - // inside the loop and restore the originals at the end. - Unit * saved_fighter_attacker = p_bic_data->fighter.attacker; - Unit * saved_fighter_defender = p_bic_data->fighter.defender; - int saved_fighter_atk_x = p_bic_data->fighter.attacker_location_x; - int saved_fighter_atk_y = p_bic_data->fighter.attacker_location_y; - int saved_fighter_def_x = p_bic_data->fighter.defender_location_x; - int saved_fighter_def_y = p_bic_data->fighter.defender_location_y; - - Unit * best = NULL; - // We track the maximum defender win rate. Start below any possible result so the first - // eligible candidate always becomes the initial best. - int best_odds = -1; - - FOR_UNITS_ON (uti, tile) { - Unit * d = uti.unit; - if ((d == NULL) || (d == attacker)) - continue; - // Defensive: a unit on the tile_units linked list with an out-of-range type id is almost - // certainly stale or in some half-initialized state — skip it entirely so we never pass it - // to anything that dereferences UnitType. - int dtid = d->Body.UnitTypeID; - if ((dtid < 0) || (dtid >= p_bic_data->UnitTypeCount)) - continue; - if (d->Body.Container_Unit >= 0) - continue; - if (d->Body.CivID == attacker_civ) - continue; - // Must be a true enemy of the attacker (allies/peace treaties). - if (! d->vtable->is_enemy_of_civ (d, __, attacker_civ, 0)) - continue; - if (Unit_get_defense_strength (d) <= 0) - continue; - if (! patch_Unit_is_visible_to_civ (d, __, attacker_civ, 0)) - continue; - - // Apply unit counter multipliers (100 if unit counters are disabled, equivalent to vanilla win rate formula). - int aa = 100, dd = 100; - bool ignore_terrain = false; - if (cfg->enable_unit_counters) - apply_counter_rules (cfg, attacker, d, tile, &aa, &dd, &ignore_terrain); - - is->counter_combat_ctx.active = true; - is->counter_combat_ctx.attacker = attacker; - is->counter_combat_ctx.defender = d; - is->counter_combat_ctx.attacker_atk_pct = aa; - is->counter_combat_ctx.defender_def_pct = dd; - is->counter_combat_ctx.ignore_terrain = ignore_terrain; - - // Point the live Fighter struct at the (attacker, d) pair so the vanilla odds function - // reads valid pointers instead of stale ones. - p_bic_data->fighter.attacker = attacker; - p_bic_data->fighter.defender = d; - p_bic_data->fighter.attacker_location_x = attacker->Body.X; - p_bic_data->fighter.attacker_location_y = attacker->Body.Y; - p_bic_data->fighter.defender_location_x = tile_x; - p_bic_data->fighter.defender_location_y = tile_y; - - // IMPORTANT: vanilla Fighter_get_combat_odds reads attack/defense values directly from - // UnitType.Attack and UnitType.Defence — it does NOT route through Unit_get_attack/defense_strength - // in a way that this mod has hooked (Unit_get_defense_strength is not registered in - // civ_prog_objects.csv as an inlead, so patch_Unit_get_defense_strength never gets called from - // inside vanilla odds computation). To make our counter multipliers actually affect the odds we - // compute here, we monkey-patch the UnitType fields for the duration of the call and restore - // them immediately after. This is single-threaded mod code and the call window is microseconds, - // so no other reader can observe the temporary values. - UnitType * a_type = &p_bic_data->UnitTypes[atk_tid]; - UnitType * d_type = &p_bic_data->UnitTypes[dtid]; - int saved_a_attack = a_type->Attack; - int saved_d_defence = d_type->Defence; - if (aa != 100) - a_type->Attack = (saved_a_attack * aa) / 100; - if (dd != 100) - d_type->Defence = (saved_d_defence * dd) / 100; - - int odds = Fighter_get_combat_odds (&p_bic_data->fighter, __, attacker, d, false, ignore_terrain); - - a_type->Attack = saved_a_attack; - d_type->Defence = saved_d_defence; - - // odds = defender's win chance (see comment above the function). We want the candidate - // that is hardest for the attacker to beat, i.e. the one with the *highest* odds. - bool replace; - if (best == NULL) { - replace = true; - } else if (odds > best_odds) { - replace = true; - } else if (odds < best_odds) { - replace = false; - } else { - // Odds tie. Defer to vanilla's own defender comparator (cheaper-cost-defends-first - // etc.) — but we must give it the *effective* defense of each candidate against - // this attacker, otherwise it would compare base defenses (e.g. Swordsman base 2 vs - // Musketman base 4) and pick Musketman immediately, never reaching the cost - // tie-break that should decide between two units that are effectively equally hard - // to beat (Swordsman with a x2 counter has effective def 4, equal to Musketman's - // base 4 — vanilla's tie-break should then prefer the cheaper Swordsman). - // - // We can't rely on counter_combat_ctx flowing through Unit_get_defense_strength - // here (see the long comment above the odds call: the patch isn't actually hooked - // into vanilla code). So we apply the multiplier ourselves on top of whatever - // Unit_get_defense_strength returns for each candidate. - int best_aa = 100, best_dd = 100; - bool best_ignore = false; - if (cfg->enable_unit_counters) - apply_counter_rules (cfg, attacker, best, tile, &best_aa, &best_dd, &best_ignore); - - int d_def = (Unit_get_defense_strength (d) * dd ) / 100; - int best_def = (Unit_get_defense_strength (best) * best_dd) / 100; - - replace = Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, - d, d_def, best, best_def, true); - } - if (replace) { - best = d; - best_odds = odds; - } - } - - is->counter_combat_ctx.active = saved_active; - is->counter_combat_ctx.attacker = saved_attacker; - is->counter_combat_ctx.defender = saved_defender; - is->counter_combat_ctx.attacker_atk_pct = saved_attacker_atk; - is->counter_combat_ctx.defender_def_pct = saved_defender_def; - is->counter_combat_ctx.ignore_terrain = saved_ignore_terrain; - - // Restore the live Fighter struct so we don't leave it pointing at our probe values when a - // real combat (or other code path that reads it) starts. - p_bic_data->fighter.attacker = saved_fighter_attacker; - p_bic_data->fighter.defender = saved_fighter_defender; - p_bic_data->fighter.attacker_location_x = saved_fighter_atk_x; - p_bic_data->fighter.attacker_location_y = saved_fighter_atk_y; - p_bic_data->fighter.defender_location_x = saved_fighter_def_x; - p_bic_data->fighter.defender_location_y = saved_fighter_def_y; - - return best; -} - -byte __fastcall -patch_Fighter_fight (Fighter * this, int edx, Unit * attacker, - int attack_direction, Unit * defender_or_null) -{ - // Civ 4-style best defender: compute the defender from the target tile (neighbor of the - // attacker) using counter-aware odds, then use that unit for combat. - // - // Vanilla usually *pre-resolves* a defender and passes it non-NULL. That selection uses base - // UnitType stats (and cost tie-breaks), not our counter rules — so combat could hit Musketman - // while Main_Screen_Form_find_visible_unit (which always calls find_civ4_best_defender_against) - // showed Swordsman. We therefore apply our pick whenever the attack is a normal 8-neighbor - // strike and either no defender was passed, or the passed defender still sits on the target - // tile (vanilla's stack defender). If vanilla passes a defender on some other tile, leave it - // alone (unusual / non-adjacent paths). - if (is->current_config.use_civ4_style_best_defender && - is->current_config.enable_unit_counters && - (attacker != NULL) && - // Strict guard: attack_direction must be a valid 8-neighbor index. Some non-combat code - // paths call Fighter_fight with sentinel values (-1 etc.); forwarding those into - // neighbor_index_to_diff would produce a junk target tile and crash. - (attack_direction >= 0) && (attack_direction < 8)) { - int dx = 0, dy = 0; - neighbor_index_to_diff (attack_direction, &dx, &dy); - // Belt-and-braces: dx/dy must lie on the 8-neighbor lattice. - if ((dx >= -1) && (dx <= 1) && (dy >= -1) && (dy <= 1) && ((dx != 0) || (dy != 0))) { - int target_x = attacker->Body.X + dx; - int target_y = attacker->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); - Tile * target_tile = tile_at (target_x, target_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - bool vanilla_defender_on_target = - (defender_or_null != NULL) && - (defender_or_null->Body.X == target_x) && - (defender_or_null->Body.Y == target_y); - if ((defender_or_null == NULL) || vanilla_defender_on_target) { - Unit * picked = find_civ4_best_defender_against (attacker, target_tile, target_x, target_y); - if (picked != NULL) - defender_or_null = picked; - } - } - } - } - - byte tr = Fighter_fight (this, __, attacker, attack_direction, - defender_or_null); - is->dbe = (struct defensive_bombard_event) {0}; - is->counter_combat_ctx.active = false; - return tr; -} - -int __fastcall -patch_Unit_get_attack_strength (Unit * this) -{ - int base = Unit_get_attack_strength (this); - if (! is->counter_combat_ctx.active) - return base; - if (this == is->counter_combat_ctx.attacker) - return base * is->counter_combat_ctx.attacker_atk_pct / 100; - return base; -} - -int __fastcall -patch_Unit_get_defense_strength (Unit * this) -{ - int base = Unit_get_defense_strength (this); - if (! is->counter_combat_ctx.active) - return base; - if (this == is->counter_combat_ctx.defender) - return base * is->counter_combat_ctx.defender_def_pct / 100; - return base; -} - -void __fastcall -patch_Unit_score_kill_by_defender (Unit * this, int edx, Unit * victim, bool was_attacking) -{ - // This function is called when the defender wins in combat. If the attacker was actually killed by defensive bombardment, then award credit - // for that kill to the defensive bombarder not the defender in combat. - if (is->dbe.defender_was_destroyed) { - is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; - Unit_score_kill (is->dbe.bombarder, __, victim, was_attacking); - is->do_not_enslave_units = false; - p_bic_data->fighter.play_animations = is->dbe.saved_animation_setting; - - } else - Unit_score_kill (this, __, victim, was_attacking); -} - -void __fastcall -patch_Unit_play_attack_anim_for_def_bombard (Unit * this, int edx, int direction) -{ - // Don't play any animation for air units, the animations are instead handled in the patch for damage_by_defensive_bombard - if (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) { - - // Make sure the unit is displayed if it's in an army and we're configured for that - struct unit_display_override saved_udo = is->unit_display_override; - Unit * container; - if (is->current_config.show_armies_performing_defensive_bombard && - (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && - Unit_has_ability (container, __, UTA_Army)) - is->unit_display_override = (struct unit_display_override) { this->Body.ID, this->Body.X, this->Body.Y }; - - Unit_play_attack_animation (this, __, direction); - - is->unit_display_override = saved_udo; - } -} - -bool -can_precision_strike_tile_improv_at (Unit * unit, int x, int y) -{ - Tile * tile; - return is->current_config.allow_precision_strikes_against_tile_improvements && // we're configured to allow prec. strikes vs tiles AND - ((tile = tile_at (x, y)) != p_null_tile) && // get tile, make sure it's valid AND - is_explored (tile, unit->Body.CivID) && // tile has been explored by attacker AND - has_any_destructible_overlays (tile, true); // it has something that can be destroyed by prec. strike -} - -// Same as above function except this one applies to the V3 field instead of FOWStatus -Tile * __cdecl -patch_tile_at_for_v3_check (int x, int y) -{ - Tile * tile = tile_at (x, y); - int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; - if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { - is->dummy_tile->Body.V3 = ((tile->Body.V3 & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; - return is->dummy_tile; - } else - return tile; -} - -bool __fastcall -patch_Unit_check_contact_bit_6_on_right_click (Unit * this, int edx, int civ_id) -{ - bool tr = Unit_check_contact_bit_6 (this, __, civ_id); - if ((! tr) && - is->current_config.share_visibility_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << civ_id) & *p_human_player_bits)) { // is civ_id a human player - if ((1 << this->Body.CivID) & *p_human_player_bits) - tr = true; - - else { - // Check if any other human player has contact - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != civ_id) && - Unit_check_contact_bit_6 (this, __, n_player)) { - tr = true; - break; - } - player_bits >>= 1; - n_player++; - } - } - } - return tr; -} - -bool __fastcall -patch_Unit_check_precision_strike_target (Unit * this, int edx, int tile_x, int tile_y) -{ - return Unit_check_precision_strike_target (this, __, tile_x, tile_y) || can_precision_strike_tile_improv_at (this, tile_x, tile_y); -} - -void __fastcall -patch_Unit_play_attack_animation_vs_tile (Unit * this, int edx, int direction) -{ - if (is->current_config.polish_precision_striking && - UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile) && - (is->attacking_tile_x != this->Body.X) && (is->attacking_tile_y != this->Body.Y)) - Unit_animate_cruise_missile_strike (this, __, is->attacking_tile_x, is->attacking_tile_y); - else - Unit_play_attack_animation (this, __, direction); -} - -void __fastcall -patch_Unit_attack_tile (Unit * this, int edx, int x, int y, int bombarding) -{ - Tile * target_tile = NULL; - bool had_district_before = false; - int district_id_before = -1; - int tile_x = x; - int tile_y = y; - - if (is->current_config.enable_districts) { - - // Check if this is a completed wonder district that cannot be destroyed - if (is->current_config.enable_wonder_districts && - !is->current_config.completed_wonder_districts_can_be_destroyed) { - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - target_tile = tile_at (tile_x, tile_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - struct wonder_district_info * info = get_wonder_district_info (target_tile); - if (info != NULL && info->state == WDS_COMPLETED) { - // This tile has a completed wonder district and they can't be destroyed - if (((*p_human_player_bits & (1 << this->Body.CivID)) != 0) && - (this->Body.CivID == p_main_screen_form->Player_CivID)) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_PILLAGE", -1, 0, 0, 0); - patch_show_popup (popup, __, 0, 0); - } - return; - } - } - } - - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - target_tile = tile_at (tile_x, tile_y); - if ((target_tile != NULL) && (target_tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (target_tile); - if (inst != NULL) { - had_district_before = true; - district_id_before = inst->district_id; - } - } - } - - is->attacking_tile_x = x; - is->attacking_tile_y = y; - if (bombarding) - is->unit_bombard_attacking_tile = this; - - Unit_attack_tile (this, __, x, y, bombarding); - - // Check if the district was destroyed by the attack - if (had_district_before && (target_tile != NULL) && (target_tile != p_null_tile) && district_id_before != NATURAL_WONDER_DISTRICT_ID) { - struct district_instance * inst_after = get_district_instance (target_tile); - bool has_district_after = (inst_after != NULL); - int district_id_after = (inst_after != NULL) ? inst_after->district_id : -1; - - // If the district existed before but not after, or the tile no longer has a mine, the district was destroyed - if (!has_district_after || !(target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & TILE_FLAG_MINE)) { - bool is_water_tile = target_tile != NULL && target_tile->vtable->m35_Check_Is_Water (target_tile); - handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, ! is_water_tile); - } - } - - is->unit_bombard_attacking_tile = NULL; - is->attacking_tile_x = is->attacking_tile_y = -1; -} - -void __fastcall -patch_Unit_do_precision_strike (Unit * this, int edx, int x, int y) -{ - if ((city_at (x, y) == NULL) && can_precision_strike_tile_improv_at (this, x, y)) - patch_Unit_attack_tile (this, __, x, y, 1); - else - Unit_do_precision_strike (this, __, x, y); - - if (is->current_config.polish_precision_striking && - UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile)) - patch_Unit_despawn (this, __, 0, false, false, 0, 0, 0, 0); -} - -int __fastcall -patch_Unit_get_max_moves_after_barricade_attack (Unit * this) -{ - if (is->current_config.dont_end_units_turn_after_bombarding_barricade && (this == is->unit_bombard_attacking_tile)) - return this->Body.Moves + p_bic_data->General.RoadsMovementRate; - else - return patch_Unit_get_max_move_points (this); -} - -City * __cdecl -patch_city_at_in_find_bombard_defender (int x, int y) -{ - // The caller (Fighter::find_defender_against_bombardment) has a set of lists of bombard priority/eligibility in its stack memory. The list - // for land units bombarding land tiles normally restricts the targets to land units by containing [UTC_Land, -1, -1]. If we're configured to - // remove that restriction, modify the list so it contains instead [UTC_Land, UTC_Sea, UTC_Air]. Conveniently, the offset from this function's - // first parameter to the list is 0x40 bytes in all executables. - if (is->current_config.remove_land_artillery_target_restrictions) { - enum UnitTypeClasses * list = (void *)((byte *)&x + 0x40); - list[1] = UTC_Sea; - list[2] = UTC_Air; - } - - return city_at (x, y); -} - -bool __fastcall -patch_Unit_check_bombard_target (Unit * this, int edx, int tile_x, int tile_y) -{ - bool base = Unit_check_bombard_target (this, __, tile_x, tile_y); - Tile * tile = tile_at (tile_x, tile_y); - int overlays; - - if (base && - itable_look_up_or (&is->current_config.can_bombard_only_sea_tiles, this->Body.UnitTypeID, 0) && - ! tile->vtable->m35_Check_Is_Water (tile)) - return false; - - else if (base && - is->current_config.disallow_useless_bombard_vs_airfields && - ! Unit_has_ability (this, __, UTA_Nuclear_Weapon) && - ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // if tile has an airfield AND - (overlays == 0x20000000)) { // tile only has an airfield - UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - - // Check that a bombard attack vs this tile would not be wasted. It won't be if either (1) there are no units on the tile, (2) there - // is a unit that can be damaged by bombarding, or (3) there are no units that can be damaged and no air units. The rules for - // bombardment are that you can't damage aircraft in an airfield and you also can't destroy an airfield from underneath aircraft. - int any_units = 0, - any_vulnerable_units = 0, - any_air_units = 0; - FOR_UNITS_ON (uti, tile) { - enum UnitTypeClasses class = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; - any_units = 1; - any_air_units |= class == UTC_Air; - any_vulnerable_units |= (class != UTC_Air) && (Unit_get_defense_strength (uti.unit) > 0) && - can_damage_bombarding (this_type, uti.unit, tile); - } - return (! any_units) || // case (1) above - any_vulnerable_units || // case (2) - ((! any_air_units) && (! any_vulnerable_units)); // case (3) - - } else - return base; -} - -bool __fastcall -patch_Unit_can_disembark_anything (Unit * this, int edx, int tile_x, int tile_y) -{ - Tile * this_tile = tile_at (this->Body.X, this->Body.Y); - Tile * target_tile = tile_at (tile_x, tile_y); - bool base = Unit_can_disembark_anything (this, __, tile_x, tile_y); - - // Apply units per tile limit - if (base) { - bool stack_limited_for_all = true; - FOR_UNITS_ON (uti, this_tile) - if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_below_stack_limit (target_tile, this->Body.CivID, uti.unit->Body.UnitTypeID)) { - stack_limited_for_all = false; - break; - } - if (stack_limited_for_all) - return false; - } - - // Apply trespassing restriction. First check if this civ may move into (tile_x, tile_y) without trespassing. If it would be trespassing, then - // we can only disembark anything if this transport has a passenger that can ignore the restriction. Without this check, the game can enter an - // infinite loop under rare circumstances. - if (base && - is->current_config.disallow_trespassing && - check_trespassing (this->Body.CivID, this_tile, target_tile)) { - bool any_exempt_passengers = false; - FOR_UNITS_ON (uti, this_tile) - if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_allowed_to_trespass (uti.unit)) { - any_exempt_passengers = true; - break; - } - return any_exempt_passengers; - - } else - return base; -} - -int __fastcall -patch_Unit_get_defense_for_bombardable_unit_check (Unit * this) -{ - // Returning a defense value of zero indicates this unit is not a target for bombardment. If configured, exclude all air units from - // bombardment so the attacks target tile improvements instead. Do this only if the tile has another improvement in addition to an airfield, - // or we could destroy the airfield itself. - Tile * tile; - int overlays; - if (is->current_config.allow_bombard_of_other_improvs_on_occupied_airfield && // If configured AND - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && // "this" is an air unit AND - ((tile = tile_at (this->Body.X, this->Body.Y)) != p_null_tile) && // "this" is on a valid tile AND - ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // tile has an airfield AND - (overlays != 0x20000000)) // tile does not only have an airfield - return 0; - - else - return Unit_get_defense_strength (this); -} - -void __fastcall -patch_Demographics_Form_m22_draw (Demographics_Form * this) -{ - Demographics_Form_m22_draw (this); - - if (is->current_config.show_total_city_count) { - // There's proably a better way to get the city count, but better safe than sorry. I don't know if it's possible for the city list to - // contain holes so the surest thing is to check every possible ID. - int city_count = 0; { - if (p_cities->Cities != NULL) - for (int n = 0; n <= p_cities->LastIndex; n++) { - City_Body * body = p_cities->Cities[n].City; - city_count += (body != NULL) && ((int)body != offsetof (City, Body)); - } - } - - PCX_Image * canvas = &this->Base.Data.Canvas; - - // Draw backdrop - { - char temp_path[2*MAX_PATH]; - PCX_Image backdrop; - PCX_Image_construct (&backdrop); - get_mod_art_path ("CityCountBackdrop.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&backdrop, __, temp_path, NULL, 0, 0x100, 2); - if (backdrop.JGL.Image != NULL) { - int w = backdrop.JGL.Image->vtable->m54_Get_Width (backdrop.JGL.Image); - PCX_Image_draw_onto (&backdrop, __, canvas, (1024 - w) / 2, 720); - } - backdrop.vtable->destruct (&backdrop, __, 0); - } - - // Draw text on top of the backdrop - char s[100]; - snprintf (s, sizeof s, "%s %d / %d", is->c3x_labels[CL_TOTAL_CITIES], city_count, is->city_limit); - s[(sizeof s) - 1] = '\0'; - PCX_Image_set_text_effects (canvas, __, 0x80000000, -1, 2, 2); // Set text color to black - PCX_Image_draw_centered_text (canvas, __, get_font (14, FSF_NONE), s, 1024/2 - 100, 730, 200, strlen (s)); - } -} - -int __fastcall -patch_Leader_get_optimal_city_number (Leader * this) -{ - if (! is->current_config.strengthen_forbidden_palace_ocn_effect) - return Leader_get_optimal_city_number (this); - else { - int num_sans_fp = Leader_get_optimal_city_number (this), // OCN w/o contrib from num of FPs - fp_count = patch_Leader_count_wonders_with_small_flag (this, __, ITSW_Reduces_Corruption, NULL), - s_diff = p_bic_data->DifficultyLevels[this->player_difficulty].Optimal_Cities, // Difficulty scaling, called "percentage of optimal cities" in the editor - base_ocn = p_bic_data->WorldSizes[p_bic_data->Map.World.World_Size].OptimalCityCount; - return num_sans_fp + (s_diff * fp_count * base_ocn + 50) / 100; // Add 50 to round off - } -} - -int __fastcall -patch_Leader_count_forbidden_palaces_for_ocn (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) -{ - if (! is->current_config.strengthen_forbidden_palace_ocn_effect) - return patch_Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); - else - return 0; // We'll add in the FP effect later with a different weight -} - -void __fastcall -patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id) -{ - is->is_computing_city_connections = true; - long long ts_before; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); - - if (is->tnx_init_state == IS_OK) { - if (is->tnx_cache == NULL) { - is->tnx_cache = is->create_tnx_cache (&p_bic_data->Map); - is->set_up_before_building_network (is->tnx_cache); - } else if (! is->keep_tnx_cache) - is->set_up_before_building_network (is->tnx_cache); - } - - Trade_Net_recompute_city_connections (this, __, civ_id, redo_road_network, param_3, redo_roads_for_city_id); - - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; - - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - is->time_spent_computing_city_connections += ts_after - ts_before; - is->count_calls_to_recompute_city_connections++; - is->is_computing_city_connections = false; -} - -void __fastcall -patch_Map_build_trade_network (Map * this) -{ - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) - is->set_up_before_building_network (is->tnx_cache); - is->keep_tnx_cache = true; - Map_build_trade_network (this); - is->keep_tnx_cache = false; - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; -} - -void __fastcall -patch_Trade_Net_recompute_city_cons_and_res (Trade_Net * this, int edx, bool param_1) -{ - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) - is->set_up_before_building_network (is->tnx_cache); - - is->keep_tnx_cache = true; - Trade_Net_recompute_city_cons_and_res (this, __, param_1); - is->keep_tnx_cache = false; - - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) - is->distribution_hub_totals_dirty = true; -} - -int __fastcall -patch_Trade_Net_set_unit_path_to_fill_road_net (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) -{ - int tr; - long long ts_before; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); - - if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { - is->flood_fill_road_network (is->tnx_cache, from_x, from_y, civ_id); - tr = 0; // Return value is not used by caller anyway - } else - tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); - - long long ts_after; - QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); - is->time_spent_filling_roads += ts_after - ts_before; - return tr; -} - -bool -set_up_gdi_plus () -{ - if (is->gdi_plus.init_state == IS_UNINITED) { - is->gdi_plus.init_state = IS_INIT_FAILED; - is->gdi_plus.gp_graphics = NULL; - - struct startup_input { - UINT32 GdiplusVersion; - void * DebugEventCallback; - BOOL SuppressBackgroundThread; - BOOL SuppressExternalCodecs; - } startup_input = {1, NULL, FALSE, FALSE}; - - is->gdi_plus.module = LoadLibraryA ("gdiplus.dll"); - if (is->gdi_plus.module == NULL) { - MessageBoxA (NULL, "Failed to load gdiplus.dll!", "Error", MB_ICONERROR); - goto end_init; - } - - int (WINAPI * GdiplusStartup) (ULONG_PTR * out_token, struct startup_input *, void * startup_output) = - (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdiplusStartup"); - - is->gdi_plus.CreateFromHDC = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreateFromHDC"); - is->gdi_plus.DeleteGraphics = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeleteGraphics"); - is->gdi_plus.SetSmoothingMode = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetSmoothingMode"); - is->gdi_plus.SetPenDashStyle = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetPenDashStyle"); - is->gdi_plus.CreatePen1 = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreatePen1"); - is->gdi_plus.DeletePen = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeletePen"); - is->gdi_plus.DrawLineI = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDrawLineI"); - if ((is->gdi_plus.CreateFromHDC == NULL) || (is->gdi_plus.DeleteGraphics == NULL) || - (is->gdi_plus.SetSmoothingMode == NULL) || (is->gdi_plus.SetPenDashStyle == NULL) || - (is->gdi_plus.CreatePen1 == NULL) || (is->gdi_plus.DeletePen == NULL) || - (is->gdi_plus.DrawLineI == NULL)) { - MessageBoxA (NULL, "Failed to get GDI+ proc addresses!", "Error", MB_ICONERROR); - goto end_init; - } - - int status = GdiplusStartup (&is->gdi_plus.token, &startup_input, NULL); - if (status != 0) { - char s[200]; - snprintf (s, sizeof s, "Failed to initialize GDI+! Startup status: %d", status); - MessageBoxA (NULL, s, "Error", MB_ICONERROR); - goto end_init; - } - - is->gdi_plus.init_state = IS_OK; - end_init: - ; - } - - return is->gdi_plus.init_state == IS_OK; -} - -int __fastcall -patch_OpenGLRenderer_initialize (OpenGLRenderer * this, int edx, PCX_Image * texture) -{ - if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || - ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) - return OpenGLRenderer_initialize (this, __, texture); - - // Initialize GDI+ instead - else { - if (! set_up_gdi_plus ()) - return 2; - if (is->gdi_plus.gp_graphics != NULL) { - is->gdi_plus.DeleteGraphics (is->gdi_plus.gp_graphics); - is->gdi_plus.gp_graphics = NULL; - } - int status = is->gdi_plus.CreateFromHDC (texture->JGL.Image->DC, &is->gdi_plus.gp_graphics); - if (status == 0) { - is->gdi_plus.SetSmoothingMode (is->gdi_plus.gp_graphics, 4); // 4 = SmoothingModeAntiAlias from GdiPlusEnums.h - return 0; - } else - return 2; - } -} - -void __fastcall -patch_OpenGLRenderer_set_color (OpenGLRenderer * this, int edx, unsigned int rgb555) -{ - // Convert rgb555 to rgb888 - unsigned int rgb888 = 0; { - unsigned int mask = 31; - int shift = 3; - for (int n = 0; n < 3; n++) { - rgb888 |= (rgb555 & mask) << shift; - mask <<= 5; - shift += 3; - } - } - - is->ogl_color = (is->ogl_color & 0xFF000000) | rgb888; - OpenGLRenderer_set_color (this, __, rgb555); -} - -void __fastcall -patch_OpenGLRenderer_set_opacity (OpenGLRenderer * this, int edx, unsigned int alpha) -{ - is->ogl_color = (is->ogl_color & 0x00FFFFFF) | (alpha << 24); - OpenGLRenderer_set_opacity (this, __, alpha); -} - -void __fastcall -patch_OpenGLRenderer_set_line_width (OpenGLRenderer * this, int edx, int width) -{ - is->ogl_line_width = width; - OpenGLRenderer_set_line_width (this, __, width); -} - -void __fastcall -patch_OpenGLRenderer_enable_line_dashing (OpenGLRenderer * this) -{ - is->ogl_line_stipple_enabled = true; - OpenGLRenderer_enable_line_dashing (this); -} - -void __fastcall -patch_OpenGLRenderer_disable_line_dashing (OpenGLRenderer * this) -{ - is->ogl_line_stipple_enabled = false; - OpenGLRenderer_disable_line_dashing (this); -} - -void __fastcall -patch_OpenGLRenderer_draw_line (OpenGLRenderer * this, int edx, int x1, int y1, int x2, int y2) -{ - if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || - ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) - OpenGLRenderer_draw_line (this, __, x1, y1, x2, y2); - - else if ((is->gdi_plus.init_state == IS_OK) && (is->gdi_plus.gp_graphics != NULL)) { - void * gp_pen; - int unit_world = 0; // = UnitWorld from gdiplusenums.h - int status = is->gdi_plus.CreatePen1 (is->ogl_color, (float)is->ogl_line_width, unit_world, &gp_pen); - if (status == 0) { - if (is->ogl_line_stipple_enabled) - is->gdi_plus.SetPenDashStyle (gp_pen, 1); // 1 = DashStyleDash from GdiPlusEnums.h - is->gdi_plus.DrawLineI (is->gdi_plus.gp_graphics, gp_pen, x1, y1, x2, y2); - is->gdi_plus.DeletePen (gp_pen); - } - } -} - -int __fastcall -patch_Tile_check_water_for_retreat_on_defense (Tile * this) -{ - Unit * defender = p_bic_data->fighter.defender; - - // Under the standard game rules, defensively retreating onto a water tile is not allowed. Set retreat_blocked to true if "this" is a water - // tile and we're not configured to allow retreating onto water tiles. - bool retreat_blocked; { - if (this->vtable->m35_Check_Is_Water (this)) { - if ( is->current_config.allow_defensive_retreat_on_water - && defender != NULL - && p_bic_data->UnitTypes[defender->Body.UnitTypeID].Unit_Class == UTC_Sea - && ( is->current_config.limit_defensive_retreat_on_water_to_types.len == 0 - || (bool)itable_look_up_or (&is->current_config.limit_defensive_retreat_on_water_to_types, defender->Body.UnitTypeID, 0))) - retreat_blocked = false; - else - retreat_blocked = true; - } else - retreat_blocked = false; - } - - // Check stack limit - if ((! retreat_blocked) && - (defender != NULL) && - ! is_below_stack_limit (this, defender->Body.CivID, defender->Body.UnitTypeID)) - retreat_blocked = true; - - // The return from this call is only used to filter the given tile as a possible retreat destination based on whether it's water or not - return (int)retreat_blocked; -} - -int __fastcall -patch_City_count_airports_for_airdrop (City * this, int edx, enum ImprovementTypeFlags airport_flag) -{ - if (is->current_config.allow_airdrop_without_airport) - return 1; - else - return City_count_improvements_with_flag (this, __, airport_flag); -} - -int __fastcall -patch_Leader_get_cont_city_count_for_worker_req (Leader * this, int edx, int cont_id) -{ - int tr = Leader_get_city_count_on_continent (this, __, cont_id); - if (is->current_config.ai_worker_requirement_percent != 100) - tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; - return tr; -} - -int __fastcall -patch_Leader_get_city_count_for_worker_prod_cap (Leader * this) -{ - int tr = this->Cities_Count; - // Don't scale down the cap since it's pretty low to begin with - if (is->current_config.ai_worker_requirement_percent > 100) - tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; - return tr; -} - -// If "only_improv_id" is >= 0, will only return yields from mills attached to that improv, otherwise returns all yields from all improvs -void -gather_mill_yields (City * city, int only_improv_id, int * out_food, int * out_shields, int * out_commerce) -{ - int food = 0, shields = 0, commerce = 0; - for (int n = 0; n < is->current_config.count_mills; n++) { - struct mill * mill = &is->current_config.mills[n]; - if ((mill->flags & MF_YIELDS) && - ((only_improv_id < 0) || (mill->improv_id == only_improv_id)) && - can_generate_resource (city->Body.CivID, mill) && - has_active_building (city, mill->improv_id) && - has_resources_required_by_building (city, mill->improv_id)) { - Resource_Type * res = &p_bic_data->ResourceTypes[mill->resource_id]; - food += res->Food; - shields += res->Shield; - commerce += res->Commerce; - } - } - *out_food = food; - *out_shields = shields; - *out_commerce = commerce; -} - -int __fastcall -patch_City_calc_tile_yield_while_gathering (City * this, int edx, YieldKind kind, int tile_x, int tile_y) -{ - int tr = City_calc_tile_yield_at (this, __, kind, tile_x, tile_y); - - // Include yields from generated resources - if ((this->Body.X == tile_x) && (this->Body.Y == tile_y)) { - int mill_food, mill_shields, mill_commerce; - gather_mill_yields (this, -1, &mill_food, &mill_shields, &mill_commerce); - if (kind == YK_FOOD) tr += mill_food; - else if (kind == YK_SHIELDS) tr += mill_shields; - else if (kind == YK_COMMERCE) tr += mill_commerce; - - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - int bonus_food = 0, bonus_shields = 0, bonus_gold = 0; - calculate_city_center_district_bonus (this, &bonus_food, &bonus_shields, &bonus_gold); - if (kind == YK_FOOD) tr += bonus_food; - else if (kind == YK_SHIELDS) tr += bonus_shields; - else if (kind == YK_COMMERCE) tr += bonus_gold; - } - } - - return tr; -} - -bool __fastcall -patch_Leader_record_export (Leader * this, int edx, int importer_civ_id, int resource_id) -{ - bool exported = Leader_record_export (this, __, importer_civ_id, resource_id); - if (exported && - (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill - is->must_recompute_resources_for_mill_inputs = true; - return exported; -} - -bool __fastcall -patch_Leader_erase_export (Leader * this, int edx, int importer_civ_id, int resource_id) -{ - bool erased = Leader_erase_export (this, __, importer_civ_id, resource_id); - if (erased && - (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill - is->must_recompute_resources_for_mill_inputs = true; - return erased; -} - -int __fastcall -patch_Sprite_draw_improv_img_on_city_form (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int tr = Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); - - int generated_resources[16]; - int generated_resource_count = 0; - for (int n = 0; (n < is->current_config.count_mills) && (generated_resource_count < ARRAY_LEN (generated_resources)); n++) { - struct mill * mill = &is->current_config.mills[n]; - if ((mill->improv_id == is->drawing_icons_for_improv_id) && - ((mill->flags & MF_SHOW_BONUS) || (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus)) && - (! ((mill->flags & MF_HIDE_NON_BONUS) && (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus))) && - can_generate_resource (p_city_form->CurrentCity->Body.CivID, mill) && - has_active_building (p_city_form->CurrentCity, mill->improv_id) && - has_resources_required_by_building (p_city_form->CurrentCity, mill->improv_id)) - generated_resources[generated_resource_count++] = mill->resource_id; - } - - if ((generated_resource_count > 0) && (is->resources_sheet != NULL) && (is->resources_sheet->JGL.Image != NULL) && (TransparentBlt != NULL)) { - JGL_Image * jgl_canvas = canvas->JGL.Image, - * jgl_sheet = is->resources_sheet->JGL.Image; - - HDC canvas_dc = jgl_canvas->vtable->acquire_dc (jgl_canvas); - if (canvas_dc != NULL) { - HDC sheet_dc = jgl_sheet->vtable->acquire_dc (jgl_sheet); - if (sheet_dc != NULL) { - - for (int n = 0; n < generated_resource_count; n++) { - int icon_id = p_bic_data->ResourceTypes[generated_resources[n]].IconID, - sheet_row = icon_id / 6, - sheet_col = icon_id % 6; - - int dy = (n * 160 / not_below (1, generated_resource_count - 1) + 5) / 10; - TransparentBlt (canvas_dc, // dest DC - pixel_x + 15, pixel_y + dy, 24, 24, // dest x, y, width, height - sheet_dc, // src DC - 9 + 50*sheet_col, 9 + 50*sheet_row, 33, 33, // src x, y, width, height - 0xFF00FF); // transparent color (RGB) - } - - jgl_sheet->vtable->release_dc (jgl_sheet, __, 1); - } - jgl_canvas->vtable->release_dc (jgl_canvas, __, 1); - } - } - return tr; -} - -void __cdecl -patch_draw_improv_icons_on_city_screen (Base_List_Control * control, int improv_id, int item_index, int offset_x, int offset_y) -{ - is->drawing_icons_for_improv_id = improv_id; - draw_improv_icons_on_city_screen (control, improv_id, item_index, offset_x, offset_y); - is->drawing_icons_for_improv_id = -1; -} - -int __fastcall -patch_City_get_tourism_amount_to_draw (City * this, int edx, int improv_id) -{ - is->tourism_icon_counter = 0; - - int mill_food, mill_shields, mill_commerce; - gather_mill_yields (this, improv_id, &mill_food, &mill_shields, &mill_commerce); - int combined_commerce = mill_commerce + City_get_tourism_amount (this, __, improv_id); - - is->convert_displayed_tourism_to_food = mill_food; - is->convert_displayed_tourism_to_shields = mill_shields; - is->combined_tourism_and_mill_commerce = combined_commerce; - return int_abs (mill_food) + int_abs (mill_shields) + int_abs (combined_commerce); -} - -int __fastcall -patch_Sprite_draw_tourism_gold (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - // Replace the yield sprite we're drawing with food or a shield if needed. - Sprite * sprite = NULL; { - if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food)) { - if (is->convert_displayed_tourism_to_food >= 0) - sprite = &p_city_form->City_Icons_Images.Icon_15_Food; - else { - init_red_food_icon (); - if (is->red_food_icon_state == IS_OK) - sprite = &is->red_food_icon; - } - } else if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food) + int_abs (is->convert_displayed_tourism_to_shields)) - sprite = (is->convert_displayed_tourism_to_shields >= 0) ? &p_city_form->City_Icons_Images.Icon_13_Shield : &p_city_form->City_Icons_Images.Icon_05_Shield_Outcome; - else if (is->combined_tourism_and_mill_commerce < 0) - sprite = &p_city_form->City_Icons_Images.Icon_17_Gold_Outcome; - else - sprite = this; - } - - int tr = 0; // return value is not used by caller - if (sprite != NULL) - tr = Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, color_table); - is->tourism_icon_counter++; - return tr; -} - -Unit * __fastcall -patch_Leader_spawn_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) -{ - int spawn_x = tile_x, - spawn_y = tile_y; - - if (is->current_config.enable_districts) { - UnitType * type = &p_bic_data->UnitTypes[type_id]; - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities) { - City * spawn_city = city_at (tile_x, tile_y); - if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { - int district_x, district_y; - Tile * district_tile = get_completed_district_tile_for_city (spawn_city, AERODROME_DISTRICT_ID, &district_x, &district_y); - if ((district_tile != NULL) && (district_tile != p_null_tile) && - (district_tile->Territory_OwnerID == this->ID) && - is_below_stack_limit (district_tile, this->ID, type_id)) { - spawn_x = district_x; - spawn_y = district_y; - } - } - } - - if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities) { - City * spawn_city = city_at (tile_x, tile_y); - if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { - int district_x, district_y; - Tile * district_tile = get_completed_district_tile_for_city (spawn_city, PORT_DISTRICT_ID, &district_x, &district_y); - if ((district_tile != NULL) && (district_tile != p_null_tile) && - (district_tile->Territory_OwnerID == this->ID) && - is_below_stack_limit (district_tile, this->ID, type_id)) { - spawn_x = district_x; - spawn_y = district_y; - } - } - } - } - - Unit * tr = Leader_spawn_unit (this, __, type_id, spawn_x, spawn_y, barb_tribe_id, id, param_6, leader_kind, race_id); - if (tr != NULL) - change_unit_type_count (this, type_id, 1); - return tr; -} - -Unit * __fastcall -patch_Leader_spawn_captured_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) -{ - Unit * tr = patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); - if ((tr != NULL) && is->moving_unit_to_adjacent_tile) - is->temporarily_disallow_lethal_zoc = true; - return tr; -} - -void __fastcall -patch_Leader_enter_new_era (Leader * this, int edx, bool param_1, bool no_online_sync) -{ - Leader_enter_new_era (this, __, param_1, no_online_sync); - apply_era_specific_names (this); -} - -char * __fastcall -patch_Leader_get_player_title_for_intro_popup (Leader * this) -{ - // Normally the era-specific names are applied later, after game loading is finished, but in this case we apply the player's names ahead of - // time so they appear on the intro popup. "this" will always refer to the human player in this call. - apply_era_specific_names (this); - return Leader_get_title (this); -} - -void __fastcall -patch_City_spawn_unit_if_done (City * this) -{ - bool skip_spawn = false; - - // Apply unit limit. If this city's owner has reached the limit for the unit type it's building then force it to build something else. - int available; - if ((this->Body.Order_Type == COT_Unit) && - get_available_unit_count (&leaders[this->Body.CivID], this->Body.Order_ID, &available) && - (available <= 0)) { - int limited_unit_type_id = this->Body.Order_ID; - - if (*p_human_player_bits & 1<Body.CivID) { - // Find another type ID to build instead of the limited one - int replacement_type_id = -1; { - int limited_unit_strat = p_bic_data->UnitTypes[limited_unit_type_id].AI_Strategy, - shields_in_box = this->Body.StoredProduction; - UnitType * replacement_type; - for (int can_type_id = 0; can_type_id < p_bic_data->UnitTypeCount; can_type_id++) - if (patch_City_can_build_unit (this, __, can_type_id, 1, 0, 0)) { - UnitType * candidate_type = &p_bic_data->UnitTypes[can_type_id]; - - // If we haven't found a replacement yet, use this one - if (replacement_type_id < 0) { - replacement_type_id = can_type_id; - replacement_type = candidate_type; - - // Keep the prev replacement if it doesn't waste shields but this candidate would - } else if ((replacement_type->Cost >= shields_in_box) && (candidate_type->Cost < shields_in_box)) - continue; - - // Keep the prev if it shares an AI strategy with the limited unit but this candidate doesn't - else if (((replacement_type->AI_Strategy & limited_unit_strat) != 0) && - ((candidate_type ->AI_Strategy & limited_unit_strat) == 0)) - continue; - - // At this point we know switching to the candidate would not cause us to waste shields and would not - // give us a worse match role-wise to the original limited unit. So pick it if it's better somehow, - // either a better role match or more expensive. - else if ((candidate_type->Cost > replacement_type->Cost) || - (((replacement_type->AI_Strategy & limited_unit_strat) == 0) && - ((candidate_type ->AI_Strategy & limited_unit_strat) != 0))) { - replacement_type_id = can_type_id; - replacement_type = candidate_type; - } - } - } - - if (replacement_type_id >= 0) { - City_set_production (this, __, COT_Unit, replacement_type_id, false); - if (this->Body.CivID == p_main_screen_form->Player_CivID) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, this->Body.CityName, -1, -1); - set_popup_str_param (1, p_bic_data->UnitTypes[limited_unit_type_id].Name, -1, -1); - int limit = -1; - get_unit_limit (&leaders[this->Body.CivID], limited_unit_type_id, &limit); - set_popup_int_param (2, limit); - set_popup_str_param (3, p_bic_data->UnitTypes[replacement_type_id].Name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_LIMITED_UNIT_CHANGE", -1, 0, 0, 0); - int response = patch_show_popup (popup, __, 0, 0); - if (response == 0) - *p_zoom_to_city_after_update = true; - } - } - - } else { - City_Order order; - patch_City_ai_choose_production (this, __, &order); - City_set_production (this, __, order.OrderType, order.OrderID, false); - } - - // If the player changed production to something other than a unit, don't spawn anything - if (this->Body.Order_Type != COT_Unit) - skip_spawn = true; - - // Just as a final check, if we weren't able to switch production off the limited unit, prevent it from being spawned so the limit - // doesn't get violated. - if ((this->Body.Order_Type == COT_Unit) && (this->Body.Order_ID == limited_unit_type_id)) - skip_spawn = true; - } - - // Check district requirements for air and naval units - if ((! skip_spawn) && (this->Body.Order_Type == COT_Unit) && is->current_config.enable_districts) { - int unit_id = this->Body.Order_ID; - UnitType * type = &p_bic_data->UnitTypes[unit_id]; - bool needs_district = false; - int required_district_id = -1; - - // Air units require aerodrome - if ((type->Unit_Class == UTC_Air) && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (! city_has_required_district (this, AERODROME_DISTRICT_ID))) { - needs_district = true; - required_district_id = AERODROME_DISTRICT_ID; - } - // Naval units require port - else if ((type->Unit_Class == UTC_Sea) && - is->current_config.enable_port_districts && - is->current_config.naval_units_use_port_districts_not_cities && - (! city_has_required_district (this, PORT_DISTRICT_ID))) { - needs_district = true; - required_district_id = PORT_DISTRICT_ID; - } - - if (needs_district) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - - // For AI, redirect to a safe fallback and queue the missing district. - // For humans, this late hook should only veto the spawn and show a warning, - // otherwise the city gets switched off the intended build with no unit spawned. - if (! is_human) { - mark_city_needs_district (this, required_district_id); - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (this, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) - City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); - } - } - - // Show message to human player - if (is_human && (this->Body.CivID == p_main_screen_form->Player_CivID)) { - char msg[160]; - char const * unit_name = type->Name; - char const * district_name = is->district_configs[required_district_id].name; - snprintf (msg, sizeof msg, "%s %s %s", unit_name, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_name); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (this->Body.X, this->Body.Y, msg, true); - } - - skip_spawn = true; - } - } - - if (! skip_spawn) - City_spawn_unit_if_done (this); -} - -void __fastcall -patch_Leader_upgrade_all_units (Leader * this, int edx, int type_id) -{ - is->penciled_in_upgrade_count = 0; - Leader_upgrade_all_units (this, __, type_id); -} - -void __fastcall -patch_Main_Screen_Form_upgrade_all_units (Main_Screen_Form * this, int edx, int type_id) -{ - is->penciled_in_upgrade_count = 0; - Main_Screen_Form_upgrade_all_units (this, __, type_id); -} - -bool __fastcall -patch_Unit_can_perform_upgrade_all (Unit * this, int edx, int unit_command_value) -{ - bool base = patch_Unit_can_perform_command (this, __, unit_command_value); - - // Deal with unit limits. If the unit type we're upgrading to is limited, we need to pencil in the upgrade to make sure that we don't queue up - // so many upgrades that we exceed the limit. - City * city; - int upgrade_id, available; - if (base && - (is->current_config.unit_limits.len > 0) && - (NULL != (city = city_at (this->Body.X, this->Body.Y))) && - (0 <= (upgrade_id = City_get_upgraded_type_id (city, __, this->Body.UnitTypeID))) && - get_available_unit_count (&leaders[this->Body.CivID], upgrade_id, &available)) { - - // Find penciled in upgrade. Add a new one if we don't already have one. - struct penciled_in_upgrade * piu = NULL; { - for (int n = 0; n < is->penciled_in_upgrade_count; n++) - if (is->penciled_in_upgrades[n].unit_type_id == upgrade_id) { - piu = &is->penciled_in_upgrades[n]; - break; - } - if (piu == NULL) { - reserve (sizeof is->penciled_in_upgrades[0], (void **)&is->penciled_in_upgrades, &is->penciled_in_upgrade_capacity, is->penciled_in_upgrade_count); - piu = &is->penciled_in_upgrades[is->penciled_in_upgrade_count]; - is->penciled_in_upgrade_count += 1; - piu->unit_type_id = upgrade_id; - piu->count = 0; - } - } - - // If we can have more units of the type we're upgrading to, pencil in another upgrade and return true. Otherwise return false so this - // unit isn't considered one of the upgradable ones. - if (piu->count < available) { - piu->count += 1; - return true; - } else - return false; - - } else - return base; -} - -void __fastcall -patch_Fighter_animate_start_of_combat (Fighter * this, int edx, Unit * attacker, Unit * defender) -{ - // Temporarily clear the attacker retreat eligibility flag when needed so naval units are rotated and animated properly. Normally the game - // does not use ranged animations when the attacker can retreat and, worse, not using ranged anims means it also ignores the - // rotate-before-attack setting. - bool restore_attacker_retreat_eligibility = false; - if ((is->current_config.sea_retreat_rules != RR_STANDARD) && - (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Sea) && - Unit_has_ability (attacker, __, UTA_Ranged_Attack_Animation) && - Unit_has_ability (defender, __, UTA_Ranged_Attack_Animation) && - this->attacker_eligible_to_retreat) { - this->attacker_eligible_to_retreat = false; - restore_attacker_retreat_eligibility = true; - } - - Fighter_animate_start_of_combat (this, __, attacker, defender); - - if (restore_attacker_retreat_eligibility) - this->attacker_eligible_to_retreat = true; -} - -Unit * __fastcall -patch_Leader_spawn_unit_from_building (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) -{ - int available; - if (get_available_unit_count (this, type_id, &available) && (available <= 0)) - return NULL; - else - return patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); -} - -int __fastcall -patch_City_count_improvs_enabling_upgrade (City * this, int edx, enum ImprovementTypeFlags flag) -{ - return is->current_config.allow_upgrades_in_any_city ? 1 : City_count_improvements_with_flag (this, __, flag); -} - -City * __fastcall -patch_Leader_create_city_from_hut (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_POPPED_FROM_HUT); - return tr; -} - -City * __fastcall -patch_Leader_create_city_for_ai_respawn (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_PLACED_FOR_AI_RESPAWN); - return tr; -} - -City * __fastcall -patch_Leader_create_city_for_founding (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_FOUNDED); - return tr; -} - -City * __fastcall -patch_Leader_create_city_for_scenario (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) -{ - City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); - if (tr != NULL) - on_gain_city (this, tr, CGR_PLACED_FOR_SCENARIO); - return tr; -} - -City * -find_city_to_inherit_shared_small_wonder (Leader * leader, int wonder_improv_id) -{ - if ((leader == NULL) || - (! is->current_config.enable_districts) || - (! is->current_config.enable_wonder_districts) || - (! is->current_config.cities_with_mutual_district_receive_wonders)) - return NULL; - - FOR_CITIES_OF (coi, leader->ID) { - City * city = coi.city; - if ((city == NULL) || (! patch_City_has_improvement (city, __, wonder_improv_id, false))) - continue; - - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - Tile * tile = wai.tile; - - struct district_instance * inst = wai.district_inst; - if (inst->district_id != WONDER_DISTRICT_ID) - continue; - - struct wonder_district_info * info = &inst->wonder_info; - if ((info == NULL) || (info->state != WDS_COMPLETED)) - continue; - - int nearby_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); - if (nearby_improv_id == wonder_improv_id) - return city; - } - } - - return NULL; -} - -void -collect_small_wonders_present_in_city (City * city, int * lost_small_wonders, int * lost_small_wonder_count, int max_lost_small_wonders) -{ - if ((city == NULL) || - (lost_small_wonders == NULL) || - (lost_small_wonder_count == NULL) || - (max_lost_small_wonders <= 0)) - return; - - *lost_small_wonder_count = 0; - - if (! is->current_config.enable_districts || - ! is->current_config.enable_wonder_districts || - ! is->current_config.cities_with_mutual_district_receive_wonders) - return; - - for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { - Improvement * improv = &p_bic_data->Improvements[improv_id]; - if ((improv->Characteristics & ITC_Small_Wonder) == 0) - continue; - if (! patch_City_has_improvement (city, __, improv_id, false)) - continue; - if (*lost_small_wonder_count >= max_lost_small_wonders) - break; - lost_small_wonders[(*lost_small_wonder_count)++] = improv_id; - } -} - -void -reassign_shared_small_wonder_owners_after_city_loss (Leader * leader, int const * lost_small_wonders, int lost_small_wonder_count) -{ - if ((! is->current_config.enable_districts) || - (leader == NULL) || - (! is->current_config.enable_wonder_districts) || - (! is->current_config.cities_with_mutual_district_receive_wonders) || - (lost_small_wonders == NULL) || - (lost_small_wonder_count <= 0)) - return; - - for (int n = 0; n < lost_small_wonder_count; n++) { - int improv_id = lost_small_wonders[n]; - if ((improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) - continue; - - if (leader->Small_Wonders[improv_id] != -1) - continue; - - // Vanilla clears Leader.Small_Wonders when the recorded owner city loses the building during - // capture. Only repair the small wonders that were actually present in the lost city before - // capture, and if another city of the same civ still legitimately shares the wonder district, - // promote that city to be the new canonical owner so the small wonder's effects still work. - City * replacement = find_city_to_inherit_shared_small_wonder (leader, improv_id); - if (replacement != NULL) - leader->Small_Wonders[improv_id] = replacement->Body.ID; - } -} - -bool __fastcall -patch_Leader_do_capture_city (Leader * this, int edx, City * city, bool involuntary, bool converted) -{ - Leader * previous_owner = &leaders[city->Body.CivID]; - int lost_small_wonders[32]; - int lost_small_wonder_count; - - // Record which small wonders were physically present in the city before capture so any - // post-capture ownership repair only touches wonders actually affected. - collect_small_wonders_present_in_city (city, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); - - is->currently_capturing_city = city; - on_lose_city (previous_owner, city, converted ? CLR_CONVERTED : (involuntary ? CLR_CONQUERED : CLR_TRADED)); - bool tr = Leader_do_capture_city (this, __, city, involuntary, converted); - - // The game clears the losing civ's canonical Small_Wonders owner when the recorded city loses - // the building. Reassign that ownership here if another same-civ city still legitimately shares the wonder district. - if (is->current_config.enable_districts && - is->current_config.enable_wonder_districts && - is->current_config.cities_with_mutual_district_receive_wonders && - lost_small_wonder_count > 0) { - reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); - } - - on_gain_city (this, city, converted ? CGR_CONVERTED : (involuntary ? CGR_CONQUERED : CGR_TRADED)); - is->currently_capturing_city = NULL; - return tr; -} - -void __fastcall -patch_City_raze (City * this, int edx, int civ_id_responsible, bool checking_elimination) -{ - Leader * previous_owner = &leaders[this->Body.CivID]; - int lost_small_wonders[32]; - int lost_small_wonder_count; - - collect_small_wonders_present_in_city (this, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); - on_lose_city (previous_owner, this, CLR_DESTROYED); - City_raze (this, __, civ_id_responsible, checking_elimination); - - if (lost_small_wonder_count > 0) - reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); - - // Delete the extra improvement bits records for this city - City_Improvements * improv_lists[2] = {&this->Body.Improvements_1, &this->Body.Improvements_2}; - for (int n = 0; n < ARRAY_LEN (improv_lists); n++) { - City_Improvements * improv_list = improv_lists[n]; - byte * extra_bits; - if (itable_look_up (&is->extra_city_improvs, (int)improv_list, (int *)&extra_bits)) { - free (extra_bits); - itable_remove (&is->extra_city_improvs, (int)improv_list); - } - } -} - -void __fastcall -patch_City_draw_hud_icon (City * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y) -{ - Leader * owner = &leaders[this->Body.CivID]; - int restore_capital = owner->CapitalID; - - // Temporarily set this city as the capital if it has an extra palace so it gets the capital star icon - if ((is->current_config.ai_multi_city_start > 1) && - ((*p_human_player_bits & (1 << owner->ID)) == 0) && - has_extra_palace (this)) - owner->CapitalID = this->Body.ID; - - City_draw_hud_icon (this, __, canvas, pixel_x, pixel_y); - owner->CapitalID = restore_capital; -} - -bool __fastcall -patch_City_has_hud_icon (City * this) -{ - return City_has_hud_icon (this) - || ( (is->current_config.ai_multi_city_start > 1) - && ((*p_human_player_bits & (1 << this->Body.CivID)) == 0) - && has_extra_palace (this)); -} - -void __fastcall -patch_City_draw_on_map (City * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) -{ - Leader * owner = &leaders[this->Body.CivID]; - int restore_capital = owner->CapitalID; - - if (is->current_config.do_not_make_capital_cities_appear_larger) - owner->CapitalID = -1; - - // Temporarily set this city as the capital if it has an extra palace so it gets drawn with the next larger size - else if ((is->current_config.ai_multi_city_start > 1) && - ((*p_human_player_bits & (1 << owner->ID)) == 0) && - has_extra_palace (this)) - owner->CapitalID = this->Body.ID; - - City_draw_on_map (this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); - owner->CapitalID = restore_capital; -} - -// Writes a string to replace "Wake" or "Activate" on the right-click menu entry for the given unit. Some units might not have a replacement, in which -// case the function writes nothing and returns false. The string is written to out_str which must point to a buffer of at least str_capacity bytes. -bool -get_menu_verb_for_unit (Unit * unit, char * out_str, int str_capacity) -{ - struct state_desc { - enum c3x_label label; - bool is_doing_worker_job; - } state_descs[35] = { - {CL_IDLE , false}, // [No state] = 0x0 - {CL_FORTIFIED , false}, // Fortifying = 0x1 - {CL_MINING , true }, // Build_Mines = 0x2 - {CL_IRRIGATING , true }, // Irrigate = 0x3 - {CL_BUILDING_FORTRESS , true }, // Build_Fortress = 0x4 - {CL_BUILDING_ROAD , true }, // Build_Road = 0x5 - {CL_BUILDING_RAILROAD , true }, // Build_Railroad = 0x6 - {CL_PLANTING_FOREST , true }, // Plant_Forest = 0x7 - {CL_CLEARING_FOREST , true }, // Clear_Forest = 0x8 - {CL_CLEARING_WETLANDS , true }, // Clear_Wetlands = 0x9 - {CL_CLEARING_DAMAGE , true }, // Clear_Damage = 0xA - {CL_BUILDING_AIRFIELD , true }, // Build_Airfield = 0xB - {CL_BUILDING_RADAR_TOWER, true }, // Build_Radar_Tower = 0xC - {CL_BUILDING_OUTPOST , true }, // Build_Outpost = 0xD - {CL_BUILDING_BARRICADE , true }, // Build_Barricade = 0xE - {CL_INTERCEPTING , false}, // Intercept = 0xF - {CL_MOVING , false}, // Go_To = 0x10 - {CL_BUILDING_ROAD , true }, // Road_To_Tile = 0x11 - {CL_BUILDING_RAILROAD , true }, // Railroad_To_Tile = 0x12 - {CL_BUILDING_COLONY , true }, // Build_Colony = 0x13 - {CL_AUTOMATED , true }, // Auto_Irrigate = 0x14 - {CL_AUTOMATED , true }, // Build_Trade_Routes = 0x15 - {CL_AUTOMATED , true }, // Auto_Clear_Forest = 0x16 - {CL_AUTOMATED , true }, // Auto_Clear_Swamp = 0x17 - {CL_AUTOMATED , true }, // Auto_Clear_Pollution = 0x18 - {CL_AUTOMATED , true }, // Auto_Save_City_Tiles = 0x19 - {CL_EXPLORING , false}, // Explore = 0x1A - {CL_IN_STATE_27 , false}, // ? = 0x1B - {CL_IN_STATE_28 , false}, // Fleeing = 0x1C - {CL_IN_STATE_29 , false}, // ? = 0x1D - {CL_IN_STATE_30 , false}, // ? = 0x1E - {CL_BOMBARDING , false}, // Auto_Bombard = 0x1F - {CL_BOMBARDING , false}, // Auto_Air_Bombard = 0x20 - {CL_BOMBARDING , false}, // Auto_Precision_Strike = 0x21 - {CL_IDLE , false}, // Exhausted = 0x22 - }; - enum UnitStateType state = unit->Body.UnitState; - struct state_desc const * desc; - if ((state >= 0) && (state < ARRAY_LEN (state_descs)) && (desc = &state_descs[state]) && (desc->label >= 0) && (desc->label < COUNT_C3X_LABELS)) { - enum c3x_label label = desc->label; - Unit * container; - if (((label == CL_IDLE) || (label == CL_MOVING) || (label == CL_IN_STATE_29) || desc->is_doing_worker_job) && unit->Body.automated) - label = CL_AUTOMATED; - else if ((label == CL_FORTIFIED) && (NULL != (container = get_unit_ptr (unit->Body.Container_Unit))) && ! Unit_has_ability (container, __, UTA_Army)) - label = CL_TRANSPORTED; - else if ((label == CL_FORTIFIED) && (unit->Body.Status & (USF_SENTRY | USF_SENTRY_ENEMY_ONLY))) - label = CL_SENTRY; - else if ((label == CL_MINING) && is->current_config.enable_districts) { - - // Check if this unit is actually building a district instead of a mine - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - struct district_instance * inst = get_district_instance (tile); - if ((tile != NULL) && (tile != p_null_tile) && inst != NULL) { - char const * district_name = is->district_configs[inst->district_id].name; - snprintf (out_str, str_capacity, "%s %s", is->c3x_labels[CL_BUILDING], district_name); - out_str[str_capacity - 1] = '\0'; - return true; - } - } - - strncpy (out_str, is->c3x_labels[label], str_capacity); - out_str[str_capacity - 1] = '\0'; - return true; - } else - return false; -} - -void __fastcall -patch_MenuUnitItem_write_text_to_temp_str (MenuUnitItem * this) -{ - MenuUnitItem_write_text_to_temp_str (this); - - Unit * unit = this->unit; - char repl_verb[32]; - if (is->current_config.describe_states_of_units_on_menu && - (unit->Body.CivID == p_main_screen_form->Player_CivID) && - (Unit_get_containing_army (unit) == NULL) && - get_menu_verb_for_unit (unit, repl_verb, sizeof repl_verb)) { - char * verb = (unit->Body.UnitState == UnitState_Fortifying) ? (*p_labels)[LBL_WAKE] : (*p_labels)[LBL_ACTIVATE]; - char * verb_str_start = strstr (temp_str, verb); - if (verb_str_start != NULL) { - char s[500]; - char * verb_str_end = verb_str_start + strlen (verb); - snprintf (s, sizeof s, "%.*s%s%s", verb_str_start - temp_str, temp_str, repl_verb, verb_str_end); - s[(sizeof s) - 1] = '\0'; - strncpy (temp_str, s, sizeof s); - } - } -} - -void __fastcall -patch_Tile_m74_Set_Square_Type_for_hill_gen (Tile * this, int edx, enum SquareTypes sq, int tile_x, int tile_y) -{ - if ((sq == SQ_Volcano) && is->current_config.do_not_generate_volcanos) - sq = SQ_Mountains; - this->vtable->m74_Set_Square_Type (this, __, sq, tile_x, tile_y); -} - -void __fastcall -patch_Map_place_scenario_things (Map * this) -{ - is->is_placing_scenario_things = true; - - Map_place_scenario_things (this); - - // If there are any mills in the config then recompute yields & happiness in all cities. This must be done because we avoid doing this as - // mills are added to cities while placing scenario things. - if (is->current_config.count_mills > 0) - for (int n = 0; n <= p_cities->LastIndex; n++) { - City * city = get_city_ptr (n); - if (city != NULL) - patch_City_recompute_yields_and_happiness (city); - } - - if (is->current_config.enable_districts || - is->current_config.enable_natural_wonders || - is->current_config.enable_named_tiles) - load_scenario_districts_from_file (); - - if (is->current_config.enable_natural_wonders && - is->current_config.add_natural_wonders_to_scenarios_if_none) { - bool any_natural_wonders = false; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst != NULL) && - (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) { - any_natural_wonders = true; - break; - } - } - if (! any_natural_wonders) - place_natural_wonders_on_map (); - } - is->is_placing_scenario_things = false; -} - -void -on_open_advisor (AdvisorKind kind) -{ - recompute_resources_if_necessary (); -} - -bool __fastcall patch_Advisor_Base_Form_domestic_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_DOMESTIC); return Advisor_Base_Form_domestic_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_trade_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_TRADE) ; return Advisor_Base_Form_trade_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_military_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_MILITARY); return Advisor_Base_Form_military_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_foreign_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_FOREIGN) ; return Advisor_Base_Form_foreign_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_cultural_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_CULTURAL); return Advisor_Base_Form_cultural_m95 (this); } -bool __fastcall patch_Advisor_Base_Form_science_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_SCIENCE) ; return Advisor_Base_Form_science_m95 (this); } - -void __fastcall -patch_Main_Screen_Form_open_quick_build_chooser (Main_Screen_Form * this, int edx, City * city, int mouse_x, int mouse_y) -{ - recompute_resources_if_necessary (); - Main_Screen_Form_open_quick_build_chooser (this, __, city, mouse_x, mouse_y); -} - -int __fastcall -patch_Context_Menu_get_selected_item_on_unit_rcm (Context_Menu * this) -{ - // In the base game, this method returns -1 for any disabled item which prevents the player from clicking those. We want players to be able to - // click unit items which have been disabled by the mod so they can interrupt the queued actions of units that have no moves left. - int index = this->Selected_Item; - if (index >= 0) { - if (is->current_config.enable_named_tiles && is->named_tile_menu_active) { - Context_Menu_Item * item = &this->Items[index]; - if (item->Menu_Item_ID == NAMED_TILE_MENU_ID) { - handle_named_tile_menu_selection (); - return -1; - } - } - bool is_enabled = (this->Items[index].Status & 2) == 0; - bool is_unit_item = (this->Items[index].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount)) >= 0; - return (is_enabled || is_unit_item) ? index : -1; - } - return -1; -} - -int __fastcall -patch_Tile_check_water_to_block_pollution (Tile * this) -{ - if (this->vtable->m35_Check_Is_Water (this)) - return 1; - else if (is->current_config.do_not_pollute_impassable_tiles) { - enum SquareTypes terrain_type = this->vtable->m50_Get_Square_BaseType (this); - return p_bic_data->TileTypes[terrain_type].Flags.Impassable; - } else - return 0; -} - -void __fastcall -patch_Tile_set_flag_for_eruption_damage (Tile * this, int edx, int param_1, int param_2, int x, int y) -{ - if (is->current_config.enable_districts) { - struct district_instance * inst = get_district_instance (this); - if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { - // District found - handle removal - int district_id = inst->district_id; - - // Notify human player if this tile is in their territory - int territory_owner = this->vtable->m38_Get_Territory_OwnerID (this); - if (territory_owner == p_main_screen_form->Player_CivID) { - char msg[160]; - char const * district_name = is->district_configs[district_id].name; - snprintf (msg, sizeof msg, "%s %s", district_name, is->c3x_labels[CL_DISTRICT_DESTROYED_BY_VOLCANO]); - msg[(sizeof msg) - 1] = '\0'; - show_map_specific_text (x, y, msg, true); - } - - // Remove the district - handle_district_removed (this, district_id, x, y, false); - - // Clear the mine flags - this->vtable->m62_Set_Tile_BuildingID (this, __, -1); - this->vtable->m51_Unset_Tile_Flags (this, __, 0, TILE_FLAG_MINE, x, y); - } - } - - // Apply the normal eruption damage (lava flag) if allowed - if (! (is->current_config.do_not_pollute_impassable_tiles && - p_bic_data->TileTypes[this->vtable->m50_Get_Square_BaseType (this)].Flags.Impassable)) - this->vtable->m56_Set_Tile_Flags (this, __, param_1, param_2, x, y); -} - -bool __fastcall -patch_City_confirm_production_switch (City * this, int edx, int order_type, int order_id) -{ - bool tr = City_confirm_production_switch (this, __, order_type, order_id); - if (tr && - (order_type == COT_Improvement) && (order_id >= 0) && (order_id < p_bic_data->ImprovementsCount) && - (this->Body.CivID == p_main_screen_form->Player_CivID) && - is->current_config.warn_when_chosen_building_would_replace_another) { - Improvement * improv = &p_bic_data->Improvements[order_id]; - if (improv->ImprovementFlags & ITF_Replaces_Other_Buildings) { - Improvement * replaced = NULL; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { - Improvement * other = &p_bic_data->Improvements[n]; - if ((other->ImprovementFlags & ITF_Replaces_Other_Buildings) && - patch_City_has_improvement (this, __, n, false)) { - replaced = other; - break; - } - } - if (replaced != NULL) { - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, improv->Name.S, -1, -1); - set_popup_str_param (1, replaced->Name.S, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARN_ABOUT_BUILDING_REPLACEMENT", -1, 0, 0, 0); - if (patch_show_popup (popup, __, 0, 0) == 1) - return false; - } - } - } - return tr; -} - -byte const c3x_save_segment_bookend[4] = {0x22, 'C', '3', 'X'}; - -// Writes a string to the buffer and pads the end so it's four-byte aligned (assuming the existing contents is already so aligned). -void -serialize_aligned_text (char const * text, struct buffer * b) -{ - int len = strlen (text); - if (len > 0) { - int padded_len = (len + 4) & ~3; // +1 for null terminator then +3 & ~3 for alignment - byte * p = buffer_allocate (b, padded_len); - strcpy (p, text); - for (int n = 0; n < padded_len - len; n++) - p[len + n] = (byte)0; - } -} - -void * __fastcall -patch_MappedFile_open_to_load_game (MappedFile * this, int edx, char * file_name, int sequential_access) -{ - void * tr = MappedFile_open (this, __, file_name, sequential_access); - if (tr != NULL) - is->accessing_save_file = this; - return tr; -} - -void * __fastcall -patch_MappedFile_create_file_to_save_game (MappedFile * this, int edx, LPCSTR file_path, unsigned file_size, int is_shared) -{ - // Determine if we're currently applying settler perfume to any AI player - bool any_current_settler_perfume = false; - if (is->current_config.ai_settler_perfume_on_founding != 0) { - int duration = is->current_config.ai_settler_perfume_on_founding_duration; - for (int n = 0; n < 32; n++) { - int last_founding_turn = is->turn_no_of_last_founding_for_settler_perfume[n]; - if ((last_founding_turn != -1) && ((*p_current_turn_no - last_founding_turn) < duration)) - any_current_settler_perfume = true; - } - } - - // Assemble mod save data - struct buffer mod_data = {0}; { - if (is->extra_defensive_bombards.len > 0) { - serialize_aligned_text ("extra_defensive_bombards", &mod_data); - itable_serialize (&is->extra_defensive_bombards, &mod_data); - } - if (is->airdrops_this_turn.len > 0) { - serialize_aligned_text ("airdrops_this_turn", &mod_data); - itable_serialize (&is->airdrops_this_turn, &mod_data); - } - if (is->unit_transport_ties.len > 0) { - serialize_aligned_text ("unit_transport_ties", &mod_data); - itable_serialize (&is->unit_transport_ties, &mod_data); - } - if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && is->waiting_units.len > 0) { - serialize_aligned_text ("waiting_units", &mod_data); - itable_serialize (&is->waiting_units, &mod_data); - } - if ((p_bic_data->ImprovementsCount > 256) && (p_cities->Cities != NULL) && (is->extra_city_improvs.len > 0)) { - serialize_aligned_text ("extra_city_improvs", &mod_data); - int extra_improv_count = p_bic_data->ImprovementsCount - 256; - *(int *)buffer_allocate (&mod_data, sizeof(int)) = extra_improv_count; - - int count_entries = 0; { - for (int n = 0; n <= p_cities->LastIndex; n++) { - City_Body * body = p_cities->Cities[n].City; - if ((body != NULL) && ((int)body != offsetof (City, Body))) { - int unused; - if (itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_1, &unused) || - itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_2, &unused)) - count_entries++; - } - } - } - *(int *)buffer_allocate (&mod_data, sizeof(int)) = count_entries; - - int ints_per_list = (extra_improv_count + 31) / 32; - int bytes_per_list = (extra_improv_count + 7) / 8; - for (int n = 0; n <= p_cities->LastIndex; n++) { - City_Body * body = p_cities->Cities[n].City; - if ((body != NULL) && ((int)body != offsetof (City, Body))) { - byte * extra_bit_lists[2]; - extra_bit_lists[0] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_1, 0); - extra_bit_lists[1] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_2, 0); - if ((extra_bit_lists[0] != NULL) || (extra_bit_lists[1] != NULL)) { - *(int *)buffer_allocate (&mod_data, sizeof(int)) = body->ID; - for (int k = 0; k < 2; k++) { - int list_size = sizeof(int) * ints_per_list; - int * list = (int *)buffer_allocate (&mod_data, list_size); - memset (list, 0, list_size); - if (extra_bit_lists[k] != NULL) - memcpy (list, extra_bit_lists[k], bytes_per_list); - } - } - } - } - } - if (any_current_settler_perfume) { - serialize_aligned_text ("turn_no_of_last_founding_for_settler_perfume", &mod_data); - void * area = buffer_allocate (&mod_data, sizeof is->turn_no_of_last_founding_for_settler_perfume); - memcpy (area, is->turn_no_of_last_founding_for_settler_perfume, sizeof is->turn_no_of_last_founding_for_settler_perfume); - } - if (is->current_config.day_night_cycle_mode != DNCM_OFF) { - serialize_aligned_text ("current_day_night_cycle", &mod_data); - int_to_bytes (buffer_allocate (&mod_data, sizeof is->current_day_night_cycle), is->current_day_night_cycle); - } - if (is->current_config.enable_districts && (is->district_count > 0)) { - serialize_aligned_text ("district_config_names", &mod_data); - int * entry_count = (int *)buffer_allocate (&mod_data, sizeof(int)); - *entry_count = is->district_count; - for (int district_id = 0; district_id < is->district_count; district_id++) { - *(int *)buffer_allocate (&mod_data, sizeof(int)) = district_id; - char const * name = is->district_configs[district_id].name; - if (name == NULL) - name = ""; - serialize_aligned_text (name, &mod_data); - } - } - - if (is->current_config.enable_districts) { - int entry_count = 0; - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req != NULL) && (req->city_id >= 0)) - entry_count++; - } - } - if (entry_count > 0) { - serialize_aligned_text ("district_pending_requests", &mod_data); - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 5 * entry_count)); - int * out = chunk + 1; - chunk[0] = entry_count; - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if ((req == NULL) || (req->city_id < 0)) - continue; - out[0] = req->city_id; - out[1] = req->district_id; - out[2] = req->assigned_worker_id; - out[3] = req->target_x; - out[4] = req->target_y; - out += 5; - } - } - } - } - - if (is->current_config.enable_districts && - (is->city_pending_building_orders.len > 0)) { - int entry_count = 0; - FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { - City * city = (City *)tei.key; - int improv_id = tei.value; - if ((city != NULL) && (improv_id >= 0)) - entry_count++; - } - if (entry_count > 0) { - serialize_aligned_text ("building_pending_orders", &mod_data); - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 2 * entry_count)); - int * out = chunk + 1; - chunk[0] = entry_count; - FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { - City * city = (City *)tei.key; - int improv_id = tei.value; - if ((city == NULL) || (improv_id < 0)) - continue; - out[0] = city->Body.ID; - out[1] = improv_id; - out += 2; - } - } - } - - if (is->current_config.enable_districts && (is->district_tile_map.len > 0)) { - serialize_aligned_text ("district_tile_map", &mod_data); - int entry_capacity = is->district_tile_map.len; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 9 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * tile = (Tile *)tei.key; - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst == NULL) - continue; - int x, y; - if (! district_instance_get_coords (inst, tile, &x, &y)) - continue; - int wonder_city_id = inst->wonder_info.city_id; - if (wonder_city_id >= 0) { - City * info_city = get_city_ptr (wonder_city_id); - inst->wonder_info.city = info_city; - if (info_city == NULL) - wonder_city_id = -1; - } else - inst->wonder_info.city = NULL; - out[0] = x; - out[1] = y; - out[2] = inst->district_id; - out[3] = (int)inst->state; - out[4] = inst->built_by_civ_id; - out[5] = inst->completed_turn; - out[6] = (int)inst->wonder_info.state; - out[7] = wonder_city_id; - out[8] = inst->wonder_info.wonder_index; - out += 9; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 9 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - - if (is->current_config.enable_natural_wonders && (is->district_tile_map.len > 0)) { - int entry_capacity = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) - continue; - if (inst->natural_wonder_info.natural_wonder_id < 0) - continue; - entry_capacity++; - } - if (entry_capacity > 0) { - serialize_aligned_text ("natural_wonder_districts", &mod_data); - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - Tile * tile = (Tile *)tei.key; - struct district_instance * inst = (struct district_instance *)tei.value; - if ((inst == NULL) || - (inst->district_id != NATURAL_WONDER_DISTRICT_ID) || - (inst->natural_wonder_info.natural_wonder_id < 0)) - continue; - int x, y; - if (! district_instance_get_coords (inst, tile, &x, &y)) - continue; - out[0] = x; - out[1] = y; - out[2] = inst->natural_wonder_info.natural_wonder_id; - out += 3; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - } - - if (is->current_config.enable_districts && - is->current_config.enable_distribution_hub_districts && - (is->distribution_hub_records.len > 0)) { - serialize_aligned_text ("distribution_hub_records", &mod_data); - int entry_capacity = is->distribution_hub_records.len; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { - struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; - if (rec == NULL) - continue; - out[0] = rec->tile_x; - out[1] = rec->tile_y; - out[2] = rec->civ_id; - out += 3; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - - if (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities && - (is->aerodrome_airlift_usage.len > 0)) { - serialize_aligned_text ("aerodrome_airlift_usage", &mod_data); - int entry_capacity = is->aerodrome_airlift_usage.len; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); - int * out = chunk + 1; - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { - Tile * tile = (Tile *)tei.key; - int mask = tei.value; - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - int tile_x, tile_y; - if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) - continue; - - out[0] = tile_x; - out[1] = tile_y; - out[2] = mask; - out += 3; - written++; - } - chunk[0] = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); - mod_data.length -= trimmed_bytes; - } - } - - if (is->current_config.enable_named_tiles && (is->named_tile_map.len > 0)) { - serialize_aligned_text ("named_tiles", &mod_data); - int entry_capacity = is->named_tile_map.len; - int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); - byte * chunk = (byte *)buffer_allocate (&mod_data, (int)sizeof(int) + bytes_per_entry * entry_capacity); - int * count = (int *)chunk; - byte * out = (byte *)(count + 1); - int written = 0; - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if ((entry == NULL) || (entry->name[0] == '\0')) - continue; - Tile * tile = (Tile *)tei.key; - int tile_x = entry->tile_x; - int tile_y = entry->tile_y; - if ((tile != NULL) && (tile != p_null_tile)) - tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); - ((int *)out)[0] = tile_x; - ((int *)out)[1] = tile_y; - out += sizeof(int) * 2; - memcpy (out, entry->name, sizeof entry->name); - out += sizeof entry->name; - written++; - } - *count = written; - int unused_entries = entry_capacity - written; - if (unused_entries > 0) { - int trimmed_bytes = unused_entries * bytes_per_entry; - mod_data.length -= trimmed_bytes; - } - } - - if (is->great_wall_auto_build != GWABS_NOT_STARTED) { - serialize_aligned_text ("great_wall_auto_build_state", &mod_data); - *(int *)buffer_allocate (&mod_data, sizeof(int)) = (int)is->great_wall_auto_build; - } - - if (is->ai_candidate_bridge_or_canals_initialized || (is->ai_candidate_bridge_or_canals_count > 0)) { - serialize_aligned_text ("ai_candidate_bridge_or_canals", &mod_data); - int * header = (int *)buffer_allocate (&mod_data, sizeof(int) * 3); - header[0] = is->ai_candidate_bridge_or_canals_initialized ? 1 : 0; - header[1] = is->ai_candidate_bridge_or_canals_count; - header[2] = is->ai_candidate_bridge_or_canals_capacity; - for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { - struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; - int tile_count = (int)entry->tile_count; - if ((tile_count <= 0) || (entry->tile_x == NULL) || (entry->tile_y == NULL)) - tile_count = 0; - - int field_count = 14; - int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (field_count + tile_count * 2)); - int pending_city_id = entry->pending_req.city_id; - if ((pending_city_id < 0) && (entry->pending_req.city != NULL)) - pending_city_id = entry->pending_req.city->Body.ID; - - chunk[0] = entry->district_id; - chunk[1] = (int)entry->owner_civ_id; - chunk[2] = tile_count; - chunk[3] = (entry->tile_capacity > 0) ? entry->tile_capacity : tile_count; - chunk[4] = entry->assigned_tile_index; - chunk[5] = entry->assigned_worker_id; - chunk[6] = entry->completed ? 1 : 0; - chunk[7] = pending_city_id; - chunk[8] = entry->pending_req.civ_id; - chunk[9] = entry->pending_req.district_id; - chunk[10] = entry->pending_req.assigned_worker_id; - chunk[11] = entry->pending_req.target_x; - chunk[12] = entry->pending_req.target_y; - chunk[13] = entry->pending_req.worker_assigned_turn; - - int * out = chunk + field_count; - for (int ti = 0; ti < tile_count; ti++) { - out[0] = entry->tile_x[ti]; - out[1] = entry->tile_y[ti]; - out += 2; - } - } - } - } - - int metadata_size = (mod_data.length > 0) ? 12 : 0; // Two four-byte bookends plus one four-byte size, only written if there's any mod data - - void * tr = MappedFile_create_file (this, __, file_path, file_size + mod_data.length + metadata_size, is_shared); - if (tr != NULL) { - is->accessing_save_file = this; - if ((mod_data.length > 0) && (mod_data.length + metadata_size <= this->size)) { - // Write first bookend to mod's segment in the save data - byte * seg_start = (byte *)tr + file_size; - for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) - seg_start[n] = c3x_save_segment_bookend[n]; - - // Write actual mod game data - memcpy ((byte *)tr + file_size + 4, mod_data.contents, mod_data.length); - - // Write size of mod data - byte * seg_end = (byte *)tr + file_size + 4 + mod_data.length; - int_to_bytes (seg_end, mod_data.length); - - // Finish off with another bookend - for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) - seg_end[4+n] = c3x_save_segment_bookend[n]; - } - } - buffer_deinit (&mod_data); - return tr; -} - -bool -match_save_chunk_name (byte ** cursor, char const * name) -{ - if (strcmp (name, *cursor) == 0) { - // Move cursor past the string if it matched. Also move past any padding that was added to ensure alignment (see serialize_aligned_text). - *cursor = (byte *)((int)*cursor + strlen (name) + 4 & ~3); - return true; - } else - return false; -} - -bool -match_save_segment_bookend (byte * b) -{ - return memcmp (c3x_save_segment_bookend, b, ARRAY_LEN (c3x_save_segment_bookend)) == 0; -} - -int __cdecl -patch_move_game_data (byte * buffer, bool save_else_load) -{ - int tr = move_game_data (buffer, save_else_load); - - if (! save_else_load) { - // Free all district_instance structs first - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst != NULL) - free (inst); - } - table_deinit (&is->district_tile_map); - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if (entry != NULL) - free (entry); - } - table_deinit (&is->named_tile_map); - clear_all_tracked_workers (); - reset_ai_candidate_bridge_or_canals (); - } - - // Check for a mod save data section and load it if present - MappedFile * save; - int seg_size; - byte * seg; - if ((! save_else_load) && - ((save = is->accessing_save_file) != NULL) && - (save->size >= 8) && - match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - 4)) && - ((seg_size = int_from_bytes ((byte *)((int)save->base_addr + save->size - 8))) > 0) && - (save->size >= seg_size + 12) && - match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - seg_size - 12)) && - ((seg = malloc (seg_size)) != NULL)) { - memcpy (seg, (void *)((int)save->base_addr + save->size - seg_size - 8), seg_size); - - byte * cursor = seg; - char * error_chunk_name = NULL; - while (cursor < seg + seg_size) { - if (match_save_chunk_name (&cursor, "special save message")) { - char * msg = (char *)cursor; - cursor = (byte *)((int)cursor + strlen (msg) + 4 & ~3); - - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); - PopupForm_add_text (popup, __, "This save contains a special message:", 0); - PopupForm_add_text (popup, __, msg, 0); - patch_show_popup (popup, __, 0, 0); - - } else if (match_save_chunk_name (&cursor, "extra_defensive_bombards")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->extra_defensive_bombards); - if (bytes_read > 0) - cursor += bytes_read; - else { - error_chunk_name = "extra_defensive_bombards"; - break; - } - - } else if (match_save_chunk_name (&cursor, "airdrops_this_turn")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->airdrops_this_turn); - if (bytes_read > 0) - cursor += bytes_read; - else { - error_chunk_name = "airdrops_this_turn"; - break; - } - - } else if (match_save_chunk_name (&cursor, "unit_transport_ties")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->unit_transport_ties); - if (bytes_read > 0) - cursor += bytes_read; - else { - error_chunk_name = "unit_transport_ties"; - break; - } - - } else if (match_save_chunk_name (&cursor, "waiting_units")) { - int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->waiting_units); - if (bytes_read > 0) { - cursor += bytes_read; - is->have_loaded_waiting_units = true; - } else { - error_chunk_name = "waiting_units"; - break; - } - - } else if (match_save_chunk_name (&cursor, "extra_city_improvs")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - - // Read two int vars from this save chunk - int file_extra_improv_count, count_entries; - if (remaining_bytes >= 8) { - file_extra_improv_count = *((int *)cursor)++; - count_entries = *((int *)cursor)++; - remaining_bytes -= 8; - } else - goto done_with_extra_city_improvs; - - // Check that the extra improv counts are valid. They must be greater than zero and what was stored in the save must - // match what we got from the current scenario data. - int extra_improv_count = not_below (0, p_bic_data->ImprovementsCount - 256); - if ((file_extra_improv_count <= 0) || (extra_improv_count != file_extra_improv_count)) - goto done_with_extra_city_improvs; - - // The extra bits data in the save is stored in 32-bit chunks, "ints", to maintain alignment. Compute how many ints we - // need for each list of bits and check that reading all entries won't overrun the buffer. - int ints_per_list = (extra_improv_count + 31) / 32, - ints_per_entry = 1 + 2 * ints_per_list; - if (count_entries * ints_per_entry * sizeof(int) > remaining_bytes) - goto done_with_extra_city_improvs; - - // Main loop reading the extra bits data - for (int n = 0; n < count_entries; n++) { - City * city = get_city_ptr (*((int *)cursor)++); - if (city == NULL) - goto done_with_extra_city_improvs; - - byte * extra_bits_1 = calloc (sizeof (int), ints_per_list); - for (int k = 0; k < ints_per_list; k++) - ((int *)extra_bits_1)[k] = *((int *)cursor)++; - itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_1, (int)extra_bits_1); - - byte * extra_bits_2 = calloc (sizeof (int), ints_per_list); - for (int k = 0; k < ints_per_list; k++) - ((int *)extra_bits_2)[k] = *((int *)cursor)++; - itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_2, (int)extra_bits_2); - } - - // Rebuild the trade network since it may have changed as a result of the additional buildings. This method also - // refreshes the free improvement tables and recomputes city happiness. - patch_Map_build_trade_network (&p_bic_data->Map); - - success = true; - - done_with_extra_city_improvs: - if (! success) { - error_chunk_name = "extra_city_improvs";; - break; - } - - } else if (match_save_chunk_name (&cursor, "turn_no_of_last_founding_for_settler_perfume")) { - for (int n = 0; n < 32; n++) - is->turn_no_of_last_founding_for_settler_perfume[n] = *((int *)cursor)++; - - } else if (match_save_chunk_name (&cursor, "current_day_night_cycle")) { - is->current_day_night_cycle = *((int *)cursor)++; - is->day_night_cycle_unstarted = false; - - // The day/night cycle sprite proxies will have been cleared in patch_load_scenario. They will not necessarily be set - // up again in the usual way because Map_Renderer::load_images is not necessarily called when loading a save. The game - // skips reloading all graphics when loading a save while in-game with another that uses the same graphics (possibly - // only the standard graphics; I didn't test). If day/night cycle mode is active, restore the proxies now if they - // haven't already been. - if ((is->day_night_cycle_img_state == IS_OK) && ! is->day_night_cycle_img_proxies_indexed) - build_sprite_proxies_24 (&p_bic_data->Map.Renderer); - - // Because we've restored current_day_night_cycle from the save, set that is is not the first turn so the cycle - // doesn't get restarted. - is->day_night_cycle_unstarted = false; - - } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_state")) { - int state = *((int *)cursor)++; - if ((state >= GWABS_NOT_STARTED) && (state <= GWABS_DONE)) - is->great_wall_auto_build = (enum great_wall_auto_build_state)state; - else - is->great_wall_auto_build = GWABS_NOT_STARTED; - - } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_is_done")) { - bool was_done = (*((int *)cursor)++ != 0); - is->great_wall_auto_build = was_done ? GWABS_DONE : GWABS_NOT_STARTED; - - } else if (match_save_chunk_name (&cursor, "district_pending_requests")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && - (remaining_bytes >= entry_count * 5 * (int)sizeof(int))) { - for (int civ_id = 0; civ_id < 32; civ_id++) { - FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { - struct pending_district_request * req = (struct pending_district_request *)tei.value; - if (req != NULL) - free (req); - } - table_deinit (&is->city_pending_district_requests[civ_id]); - } - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 5 * (int)sizeof(int)) { - success = false; - break; - } - int city_id = *ints++; - int district_id = *ints++; - int assigned_worker_id = *ints++; - int target_x = *ints++; - int target_y = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 5 * (int)sizeof(int); - City * city = get_city_ptr (city_id); - if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) - continue; - struct pending_district_request * req = create_pending_district_request (city, district_id); - if (req == NULL) - continue; - if ((assigned_worker_id >= 0) && (get_unit_ptr (assigned_worker_id) == NULL)) - assigned_worker_id = -1; - req->assigned_worker_id = assigned_worker_id; - req->target_x = target_x; - req->target_y = target_y; - } - if (! success) { - for (int civ_id = 0; civ_id < 32; civ_id++) - table_deinit (&is->city_pending_district_requests[civ_id]); - } - } - } - if (! success) { - error_chunk_name = "district_pending_requests"; - break; - } - } else if (match_save_chunk_name (&cursor, "building_pending_orders")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && - (remaining_bytes >= entry_count * 2 * (int)sizeof(int))) { - table_deinit (&is->city_pending_building_orders); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 2 * (int)sizeof(int)) { - success = false; - break; - } - int city_id = *ints++; - int improv_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 2 * (int)sizeof(int); - if (improv_id < 0) - continue; - City * city = get_city_ptr (city_id); - if (city == NULL) - continue; - itable_insert (&is->city_pending_building_orders, (int)city, improv_id); - } - if (! success) - table_deinit (&is->city_pending_building_orders); - } - } - if (! success) { - error_chunk_name = "building_pending_orders"; - break; - } - } else if (match_save_chunk_name (&cursor, "district_tile_map")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if (entry_count >= 0) { - int ints_per_entry = 9; - success = true; - int required_bytes = entry_count * ints_per_entry * (int)sizeof(int); - if (success && remaining_bytes >= required_bytes) { - FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { - struct district_instance * inst = (struct district_instance *)tei.value; - if (inst != NULL) - free (inst); - } - table_deinit (&is->district_tile_map); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < ints_per_entry * (int)sizeof(int)) { - success = false; - break; - } - int x = *ints++; - int y = *ints++; - int district_id = *ints++; - int state_val = *ints++; - int built_by_civ_id = *ints++; - int completed_turn = *ints++; - int wonder_state = *ints++; - int wonder_city_id = *ints++; - int wonder_index = *ints++; - cursor = (byte *)ints; - remaining_bytes -= ints_per_entry * (int)sizeof(int); - if ((district_id < 0) || (district_id >= is->district_count)) - continue; - Tile * tile = tile_at (x, y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = ensure_district_instance (tile, district_id, x, y); - if (inst != NULL) { - enum district_state new_state; - switch (state_val) { - case DS_COMPLETED: - new_state = DS_COMPLETED; - break; - case DS_UNDER_CONSTRUCTION: - new_state = DS_UNDER_CONSTRUCTION; - break; - default: - new_state = DS_UNDER_CONSTRUCTION; - break; - } - inst->state = new_state; - inst->built_by_civ_id = built_by_civ_id; - inst->completed_turn = completed_turn; - - inst->wonder_info.state = (enum wonder_district_state)wonder_state; - inst->wonder_info.city_id = (wonder_city_id >= 0) ? wonder_city_id : -1; - City * info_city = (wonder_city_id >= 0) ? get_city_ptr (wonder_city_id) : NULL; - inst->wonder_info.city = info_city; - if (info_city == NULL) - inst->wonder_info.city_id = -1; - inst->wonder_info.wonder_index = wonder_index; - set_tile_unworkable_for_all_cities (tile, x, y); - } - } - } - } - else - success = false; - } - } - if (! success) { - error_chunk_name = "district_tile_map"; - break; - } - } else if (match_save_chunk_name (&cursor, "natural_wonder_districts")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 3 * (int)sizeof(int)) { - success = false; - break; - } - int x = *ints++; - int y = *ints++; - int natural_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 3 * (int)sizeof(int); - if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) - continue; - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, x, y); - if (inst == NULL) - continue; - inst->district_id = NATURAL_WONDER_DISTRICT_ID; - inst->state = DS_COMPLETED; - inst->natural_wonder_info.natural_wonder_id = natural_id; - set_tile_unworkable_for_all_cities (tile, x, y); - } - } - } - if (! success) { - error_chunk_name = "natural_wonder_districts"; - break; - } - } else if (match_save_chunk_name (&cursor, "distribution_hub_records")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { - clear_distribution_hub_tables (); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 3 * (int)sizeof(int)) { - success = false; - break; - } - int x = *ints++; - int y = *ints++; - int civ_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 3 * (int)sizeof(int); - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - on_distribution_hub_completed (tile, x, y); - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec != NULL) - rec->civ_id = civ_id; - } - } - } - if (! success) { - error_chunk_name = "distribution_hub_records"; - break; - } - } else if (match_save_chunk_name (&cursor, "aerodrome_airlift_usage")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if ((entry_count >= 0) && - (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { - table_deinit (&is->aerodrome_airlift_usage); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < 3 * (int)sizeof(int)) { - success = false; - break; - } - int tile_x = *ints++; - int tile_y = *ints++; - int mask = *ints++; - cursor = (byte *)ints; - remaining_bytes -= 3 * (int)sizeof(int); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - itable_insert (&is->aerodrome_airlift_usage, (int)tile, mask); - } - if (! success) - table_deinit (&is->aerodrome_airlift_usage); - } - } - if (! success) { - error_chunk_name = "aerodrome_airlift_usage"; - break; - } - - } else if (match_save_chunk_name (&cursor, "named_tiles")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int entry_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); - if ((entry_count >= 0) && (remaining_bytes >= entry_count * bytes_per_entry)) { - table_deinit (&is->named_tile_map); - success = true; - for (int n = 0; n < entry_count; n++) { - if (remaining_bytes < bytes_per_entry) { - success = false; - break; - } - int tile_x = *ints++; - int tile_y = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int) * 2; - - char name_buf[101]; - memcpy (name_buf, cursor, sizeof name_buf); - name_buf[(sizeof name_buf) - 1] = '\0'; - cursor += sizeof name_buf; - remaining_bytes -= sizeof name_buf; - ints = (int *)cursor; - - if (name_buf[0] == '\0') - continue; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - struct named_tile_entry * entry = calloc (1, sizeof *entry); - if (entry == NULL) { - success = false; - break; - } - entry->tile_x = tile_x; - entry->tile_y = tile_y; - strncpy (entry->name, name_buf, sizeof entry->name); - entry->name[(sizeof entry->name) - 1] = '\0'; - itable_insert (&is->named_tile_map, (int)tile, (int)entry); - } - if (! success) { - FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { - struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; - if (entry != NULL) - free (entry); - } - table_deinit (&is->named_tile_map); - } - } - } - if (! success) { - error_chunk_name = "named_tiles"; - break; - } - - } else if (match_save_chunk_name (&cursor, "ai_candidate_bridge_or_canals")) { - bool success = false; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int) * 3) { - int * ints = (int *)cursor; - int saved_initialized = *ints++; - int saved_count = *ints++; - int saved_capacity = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int) * 3; - - if ((saved_count >= 0) && (saved_capacity >= 0)) { - reset_ai_candidate_bridge_or_canals (); - success = true; - - int alloc_capacity = saved_capacity; - if (alloc_capacity < saved_count) - alloc_capacity = saved_count; - if (alloc_capacity > 0) { - is->ai_candidate_bridge_or_canals = (struct ai_candidate_bridge_or_canal_entry *)calloc (alloc_capacity, sizeof *is->ai_candidate_bridge_or_canals); - if (is->ai_candidate_bridge_or_canals == NULL) { - success = false; - alloc_capacity = 0; - } else - is->ai_candidate_bridge_or_canals_capacity = alloc_capacity; - } - - is->ai_candidate_bridge_or_canals_initialized = (saved_initialized != 0); - int loaded_count = 0; - for (int ei = 0; ei < saved_count; ei++) { - if (remaining_bytes < (int)sizeof(int) * 14) { - success = false; - break; - } - int district_id = *ints++; - int owner_civ_id = *ints++; - int tile_count = *ints++; - int tile_capacity = *ints++; - int assigned_tile_index = *ints++; - int assigned_worker_id = *ints++; - int completed = *ints++; - int pending_city_id = *ints++; - int pending_civ_id = *ints++; - int pending_district_id = *ints++; - int pending_assigned_worker_id = *ints++; - int pending_target_x = *ints++; - int pending_target_y = *ints++; - int pending_worker_assigned_turn = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int) * 14; - - if (tile_count < 0) { - success = false; - break; - } - if (remaining_bytes < tile_count * 2 * (int)sizeof(int)) { - success = false; - break; - } - - int stored_tile_count = tile_count; - if (tile_count > AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES) - tile_count = AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES; - if (tile_capacity < tile_count) - tile_capacity = tile_count; - - struct ai_candidate_bridge_or_canal_entry * entry = NULL; - if ((alloc_capacity > 0) && (loaded_count < alloc_capacity)) - entry = &is->ai_candidate_bridge_or_canals[loaded_count]; - - if (entry != NULL) { - entry->district_id = district_id; - entry->owner_civ_id = (short)owner_civ_id; - entry->tile_count = (short)tile_count; - entry->tile_capacity = tile_capacity; - entry->assigned_tile_index = assigned_tile_index; - entry->assigned_worker_id = assigned_worker_id; - entry->completed = (completed != 0); - - entry->tile_x = (short *)calloc (sizeof *entry->tile_x, tile_count); - entry->tile_y = (short *)calloc (sizeof *entry->tile_y, tile_count); - if ((tile_count > 0) && ((entry->tile_x == NULL) || (entry->tile_y == NULL))) { - if (entry->tile_x != NULL) - free (entry->tile_x); - if (entry->tile_y != NULL) - free (entry->tile_y); - entry->tile_x = NULL; - entry->tile_y = NULL; - entry->tile_count = 0; - entry->tile_capacity = 0; - } - - for (int ti = 0; ti < stored_tile_count; ti++) { - int tx = *ints++; - int ty = *ints++; - if ((entry->tile_x != NULL) && (ti < tile_count)) { - entry->tile_x[ti] = (short)tx; - entry->tile_y[ti] = (short)ty; - } - } - - entry->pending_req.city = (pending_city_id >= 0) ? get_city_ptr (pending_city_id) : NULL; - entry->pending_req.city_id = (entry->pending_req.city != NULL) ? pending_city_id : -1; - entry->pending_req.civ_id = pending_civ_id; - entry->pending_req.district_id = pending_district_id; - entry->pending_req.assigned_worker_id = pending_assigned_worker_id; - entry->pending_req.target_x = pending_target_x; - entry->pending_req.target_y = pending_target_y; - entry->pending_req.worker_assigned_turn = pending_worker_assigned_turn; - - if ((entry->assigned_worker_id >= 0) && (get_unit_ptr (entry->assigned_worker_id) == NULL)) - entry->assigned_worker_id = -1; - if ((entry->pending_req.assigned_worker_id >= 0) && (get_unit_ptr (entry->pending_req.assigned_worker_id) == NULL)) - entry->pending_req.assigned_worker_id = -1; - if ((entry->assigned_tile_index < 0) || (entry->assigned_tile_index >= entry->tile_count)) - entry->assigned_tile_index = -1; - - loaded_count++; - } else { - for (int ti = 0; ti < stored_tile_count; ti++) { - ints += 2; - } - } - - cursor = (byte *)ints; - remaining_bytes -= stored_tile_count * 2 * (int)sizeof(int); - } - if (success) - is->ai_candidate_bridge_or_canals_count = loaded_count; - } - } - if (! success) { - error_chunk_name = "ai_candidate_bridge_or_canals"; - break; - } - - } else if (match_save_chunk_name (&cursor, "district_config_names")) { - bool success = false; - bool mismatch_found = false; - bool count_mismatch = false; - char first_mismatch[200]; - first_mismatch[0] = '\0'; - int remaining_bytes = (seg + seg_size) - cursor; - if (remaining_bytes >= (int)sizeof(int)) { - int * ints = (int *)cursor; - int saved_count = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - if (saved_count >= 0) { - success = true; - count_mismatch = (saved_count != is->district_count); - char * saved_names[saved_count]; - for (int n = 0; n < saved_count; n++) { - if (remaining_bytes < (int)sizeof(int)) { - success = false; - break; - } - ints = (int *)cursor; - int saved_id = *ints++; - cursor = (byte *)ints; - remaining_bytes -= (int)sizeof(int); - - int name_len = -1; - for (int k = 0; k < remaining_bytes; k++) { - if (cursor[k] == '\0') { - name_len = k; - break; - } - } - if (name_len < 0) { - success = false; - break; - } - int padded_len = (name_len + 4) & ~3; - if (padded_len > remaining_bytes) { - success = false; - break; - } - - char * saved_name = (char *)cursor; - saved_names[n] = saved_name; - if (! mismatch_found) { - if ((saved_id < 0) || (saved_id >= is->district_count)) { - snprintf (first_mismatch, sizeof first_mismatch, "%s %d (\"%s\") %s", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW]); - first_mismatch[(sizeof first_mismatch) - 1] = '\0'; - mismatch_found = true; - } else { - char const * current_name = is->district_configs[saved_id].name; - if (current_name == NULL) - current_name = ""; - if (strcmp (current_name, saved_name) != 0) { - snprintf (first_mismatch, sizeof first_mismatch, "%s %d \"%s\" %s \"%s\"", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_NAME_MISMATCH], current_name); - first_mismatch[(sizeof first_mismatch) - 1] = '\0'; - mismatch_found = true; - } - } - } - - cursor += padded_len; - remaining_bytes -= padded_len; - } - if (success && count_mismatch && (first_mismatch[0] == '\0')) { - snprintf (first_mismatch, sizeof first_mismatch, "%s %d %s %d", is->c3x_labels[CL_SAVE_FILE_HAD], saved_count, is->c3x_labels[CL_CURRENT_CONFIG_HAS_ONLY], is->district_count); - first_mismatch[(sizeof first_mismatch) - 1] = '\0'; - mismatch_found = true; - } - if (success && mismatch_found) { - PopupForm * popup = get_popup_form (); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); - - char s[1000]; - snprintf (s, sizeof s, "%s %s", is->c3x_labels[CL_WARNING_DISTRICTS_CONFIG_MISMATCH], first_mismatch); - snprintf (s, sizeof s, "%s. %s", s, is->c3x_labels[CL_MAY_BE_OTHER_ERRORS_AS_WELL]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^"); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_DISTRICTS_IN_SAVE_FILE]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - for (int n = 0; n < saved_count; n++) { - snprintf (s, sizeof s, "^ (%d) %s", n, saved_names[n]); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - - snprintf (s, sizeof s, "^"); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - - snprintf (s, sizeof s, "^%s \"%s\":", is->c3x_labels[CL_CURRENTLY_CONFIGURED_DISTRICTS], is->current_districts_config_path); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - for (int n = 0; n < is->district_count; n++) { - snprintf (s, sizeof s, "^ (%d) %s", n, is->district_configs[n].name); - s[(sizeof s) - 1] = '\0'; - PopupForm_add_text (popup, __, s, 0); - } - - patch_show_popup (popup, __, 0, 0); - } - } - } - if (! success) { - error_chunk_name = "district_config_names"; - break; - } - - } else { - error_chunk_name = "N/A"; - break; - } - } - - if (error_chunk_name != NULL) { - char s[200]; - snprintf (s, sizeof s, "Failed to read mod save data. Error occured in chunk: %s", error_chunk_name); - s[(sizeof s) - 1] = '\0'; - pop_up_in_game_error (s); - } - - free (seg); - } - - return tr; -} - -void __fastcall -patch_MappedFile_deinit_after_saving_or_loading (MappedFile * this) -{ - is->accessing_save_file = NULL; - MappedFile_deinit (this); -} - -bool __fastcall -patch_Tile_m7_Check_Barbarian_Camp (Tile * this, int edx, int visible_to_civ) -{ - int * p_stack = (int *)&visible_to_civ; - int ret_addr = p_stack[-1]; - - // If the barb unit AI is calling this method to check if there's a camp to defend, return true if we're allowing barb city capture and the - // tile has a city. This causes barb units to defend cities they've captured, otherwise they'll ignore them. - if ((ret_addr == ADDR_CHECK_BARB_CAMP_TO_DEFEND_RETURN) && - is->current_config.enable_city_capture_by_barbarians && - Tile_has_city (this)) - return true; - else - return Tile_m7_Check_Barbarian_Camp (this, __, visible_to_civ); -} - -bool __fastcall -patch_Unit_can_heal_at (Unit * this, int edx, int tile_x, int tile_y) -{ - if (is->current_config.enable_districts && - is->current_config.enable_port_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { - Tile * tile = tile_at (tile_x, tile_y); - if (tile_has_friendly_port_district (tile, this->Body.CivID)) { - int occupier_id = get_tile_occupier_id (tile_x, tile_y, -1, true); - return (occupier_id == -1) || (occupier_id == this->Body.CivID); - } - } - - return Unit_can_heal_at (this, __, tile_x, tile_y); -} - -bool __fastcall -patch_Unit_can_airdrop (Unit * this) -{ - UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - - bool allowed = Unit_can_airdrop (this); - - bool require_aerodrome = (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities); - - if (require_aerodrome) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - bool has_aerodrome = false; - - if ((tile != NULL) && (tile != p_null_tile)) - has_aerodrome = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); - - if (! has_aerodrome) - allowed = false; - else if (! allowed) { - if ((this_type->Unit_Class != UTC_Air) && - (this_type->Air_Missions & UCV_Airdrop) && - (this->Body.Moves == 0)) - allowed = true; - } - } - - // Possibly rule in this airdrop as allowed if it's by a paratrooper in a helicopter on a carrier and we're configured to allow airdrops under - // those circumstances. - if ((! allowed) && (is->current_config.special_helicopter_rules & SHR_PASSENGER_AIRDROP)) { - Unit * container = get_unit_ptr (this->Body.Container_Unit); - if (container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) { // if in helicopter - Unit * metacontainer = get_unit_ptr (container->Body.Container_Unit); - if (metacontainer != NULL && p_bic_data->UnitTypes[metacontainer->Body.UnitTypeID].Unit_Class == UTC_Sea && - Unit_has_ability (metacontainer, __, UTA_Transports_Only_Aircraft)) { // if that helicopter is on a carrier - // Allow the airdrop under the same restrictions as from an airfield - allowed = this_type->Unit_Class != UTC_Air && this->Body.Moves == 0; - } - } - } - - if (! allowed) - return false; - - return itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0) == 0; -} - -bool __fastcall -patch_City_Improvements_contains (City_Improvements * this, int edx, int id) -{ - byte * extra_bits; - if ((id < 256) || ! is->current_config.remove_city_improvement_limit) - return City_Improvements_contains (this, __, id); - else if (itable_look_up (&is->extra_city_improvs, (int)this, (int *)&extra_bits)) { - int extra_id = id - 256; - return (extra_bits[extra_id>>3] >> (extra_id & 7)) & 1; - } else - return false; -} - -void __fastcall -patch_City_Improvements_set (City_Improvements * this, int edx, int id, bool add_else_remove) -{ - if ((id < 256) || ! is->current_config.remove_city_improvement_limit) - return City_Improvements_set (this, __, id, add_else_remove); - else { - byte * extra_bits = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)this, 0); - int extra_id = id - 256; - byte mask = 1 << (extra_id & 7); - if (add_else_remove) { - if (! extra_bits) { - int extra_bits_size = (not_below (0, p_bic_data->ImprovementsCount - 256) >> 3) + 1; - extra_bits = calloc (1, extra_bits_size); - itable_insert (&is->extra_city_improvs, (int)this, (int)extra_bits); - } - extra_bits[extra_id>>3] |= mask; - } else if ((! add_else_remove) && (extra_bits != NULL)) - extra_bits[extra_id>>3] &= ~mask; - } -} - -bool __fastcall -patch_Leader_has_tech_to_stop_disease (Leader * this, int edx, int id) -{ - if (! is->current_config.patch_disease_stopping_tech_flag_bug) - return Leader_has_tech (this, __, id); - else - return Leader_has_tech_with_flag (this, __, ATF_Disabled_Deseases_From_Flood_Plains); -} - -void __fastcall -patch_set_worker_animation (void * this, int edx, Unit * unit, int job_id) -{ - AnimationType anim_type; - - // If districts disabled or unit is null or job is not building mines, use base logic - if ((! is->current_config.enable_districts) || - (unit == NULL) || - (job_id != WJ_Build_Mines)) { - set_worker_animation(this, __, unit, job_id); - return; - } - - // If tile has a district under construction - Tile * tile = tile_at (unit->Body.X, unit->Body.Y); - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && - ! district_is_complete (tile, inst->district_id) && job_id == WJ_Build_Mines) { - - // Override and ensure build animation is used - job_id = AT_BUILD; - } - - set_worker_animation(this, __, unit, job_id); -} - -void __fastcall -patch_Unit_work_simple_job (Unit * this, int edx, int job_id) -{ - is->lmify_tile_after_working_simple_job = NULL; - - // Check if districts are enabled - if (is->current_config.enable_districts) { - int tile_x = this->Body.X; - int tile_y = this->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - - if (tile != NULL && tile != p_null_tile) { - // Check if there's a completed district on this tile - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete(tile, inst->district_id)) { - int district_id = inst->district_id; - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - - // AI players only (human removal is handled via issue_district_worker_command) - if (!is_human) { - bool allow_removal = false; - if (district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = &inst->wonder_info; - allow_removal = (info->state == WDS_UNUSED); - } - - if (allow_removal) { - remove_district_instance (tile); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); - handle_district_removed (tile, district_id, tile_x, tile_y, false); - } - } - } - } - } - - Unit_work_simple_job (this, __, job_id); - - if (is->lmify_tile_after_working_simple_job != NULL) - is->lmify_tile_after_working_simple_job->vtable->m31_set_landmark (is->lmify_tile_after_working_simple_job, __, true); -} - -void __fastcall -patch_Map_change_tile_terrain_by_worker (Map * this, int edx, enum SquareTypes new_terrain_type, int x, int y) -{ - Map_change_tile_terrain (this, __, new_terrain_type, x, y); - - if (is->current_config.convert_to_landmark_after_planting_forest && (new_terrain_type == SQ_Forest)) - is->lmify_tile_after_working_simple_job = tile_at (x, y); -} - -int __fastcall -patch_Leader_ai_eval_technology (Leader * this, int edx, int id, bool param_2, bool param_3) -{ - int base = Leader_ai_eval_technology (this, __, id, param_2, param_3); - return apply_perfume (PK_TECHNOLOGY, p_bic_data->Advances[id].Name, base); -} - -int __fastcall -patch_Leader_ai_eval_government (Leader * this, int edx, int id) -{ - int base = Leader_ai_eval_government (this, __, id); - return apply_perfume (PK_GOVERNMENT, p_bic_data->Governments[id].Name.S, base); -} - -bool -roll_to_spare_unit_from_nuke (Unit * unit) -{ - int one_hp_destroy_chance = is->current_config.chance_for_nukes_to_destroy_max_one_hp_units; - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - if ((one_hp_destroy_chance < 100) && - (Unit_get_max_hp (unit) <= 1) && - (type->Defence > 0) && - ((type->Unit_Class == UTC_Land) || (type->Unit_Class == UTC_Sea))) - return ! (rand_int (p_rand_object, __, 100) < one_hp_destroy_chance); - else - return false; -} - -void __fastcall -patch_Unit_despawn_after_killed_by_nuke (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) -{ - if (roll_to_spare_unit_from_nuke (this)) - this->Body.Damage = Unit_get_max_hp (this) - 1; - else { - bool prev_always_despawn_passengers = is->always_despawn_passengers; - if ((is->current_config.land_transport_rules & LTR_NO_ESCAPE) && is_land_transport (this)) - is->always_despawn_passengers = true; - else if ((is->current_config.special_helicopter_rules & SHR_NO_ESCAPE) && p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air && - p_bic_data->UnitTypes[this->Body.UnitTypeID].Transport_Capacity > 0) - is->always_despawn_passengers = true; - patch_Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); - is->always_despawn_passengers = prev_always_despawn_passengers; - } -} - -void __fastcall -patch_mp_despawn_after_killed_by_nuke (void * this, int edx, int unit_id, int civ_id_responsible, byte param_3, byte param_4, byte param_5, byte param_6) -{ - Unit * unit = get_unit_ptr (unit_id); - if ((unit != NULL) && roll_to_spare_unit_from_nuke (unit)) - unit->Body.Damage = Unit_get_max_hp (unit) - 1; - else - mp_despawn (this, __, unit_id, civ_id_responsible, param_3, param_4, param_5, param_6); -} - -bool __fastcall -patch_City_has_unprotected_improv_to_sell (City * this, int edx, int id) -{ - // Fall back to original logic only if the config doesn't alter the behavior. - if (! is->current_config.allow_sale_of_aqueducts_and_hospitals && !is->current_config.allow_sale_of_small_wonders) - return City_has_unprotected_improv (this, __, id); - - else if (patch_City_has_improvement (this, __, id, false)) { - Improvement * improv = &p_bic_data->Improvements[id]; - int max_pop_to_sell = INT_MAX; // By default, population-based sell isn't restricted - if (improv->ImprovementFlags & (ITF_Allows_City_Level_2 | ITF_Allows_City_Level_3)) { // Aqueduct/Hospital? - if (is->current_config.allow_sale_of_aqueducts_and_hospitals) { - if (improv->ImprovementFlags & ITF_Allows_City_Level_2) - max_pop_to_sell = p_bic_data->General.MaximumSize_Town; - else if (improv->ImprovementFlags & ITF_Allows_City_Level_3) - max_pop_to_sell = p_bic_data->General.MaximumSize_City; - } else { - // Do not allow selling these. - max_pop_to_sell = 0; - } - } - - // Can't sell: - // - Great Wonders - // - Small Wonders, unless the config allows it - // - Capital - // - Aqueduct/Hospital if the city is too big for that population - return ((improv->Characteristics & ITC_Wonder) == 0) && - (is->current_config.allow_sale_of_small_wonders || ((improv->Characteristics & ITC_Small_Wonder) == 0)) && - ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && - (this->Body.Population.Size <= max_pop_to_sell); - - } else - return false; -} - -bool __fastcall -patch_UnitType_has_detector_ability_for_vis_check (UnitType * this, int edx, enum UnitTypeAbilities a) -{ - bool tr = UnitType_has_ability (this, __, a); - - // Restrict detection by sea units to other sea units and non-sea units to other non-sea units - if (tr && - is->current_config.no_cross_shore_detection && - (is->checking_visibility_for_unit != NULL) && - ((this->Unit_Class == UTC_Sea) ^ (p_bic_data->UnitTypes[is->checking_visibility_for_unit->Body.UnitTypeID].Unit_Class == UTC_Sea))) - tr = false; - - return tr; -} - -bool -is_airdrop_trespassing (Unit * unit, int target_x, int target_y) -{ - if (is->current_config.disallow_trespassing && - check_trespassing (unit->Body.CivID, tile_at (unit->Body.X, unit->Body.Y), tile_at (target_x, target_y))) { - bool allowed = is_allowed_to_trespass (unit); - - // If "unit" is an air unit that can carry others, like helicopters, then this airdrop is only allowed if all of its passengers are - // allowed to trespass. - UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; - if (allowed && (type->Unit_Class == UTC_Air) && (type->Transport_Capacity > 0)) - FOR_UNITS_ON (uti, tile_at (unit->Body.X, unit->Body.Y)) - if ((uti.unit->Body.Container_Unit == unit->Body.ID) && - (! is_allowed_to_trespass (uti.unit))) { - allowed = false; - break; - } - - return ! allowed; - } else - return false; -} - -bool __fastcall -patch_Unit_check_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) -{ - return Unit_check_airdrop_target (this, __, tile_x, tile_y) && - is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID) && - ! is_airdrop_trespassing (this, tile_x, tile_y); -} - -bool __fastcall -patch_Unit_can_airlift (Unit * this) -{ - bool base = Unit_can_airlift (this); - - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) - return base; - - Tile * tile = tile_at (this->Body.X, this->Body.Y); - if ((tile == NULL) || (tile == p_null_tile)) - return base; - - bool allow_from_non_city = false; - if (base) { - City * city = city_at (this->Body.X, this->Body.Y); - if ((city == NULL) || (city->Body.CivID != this->Body.CivID)) - allow_from_non_city = true; - } - - if (allow_from_non_city) - return true; - - return tile_has_friendly_aerodrome_district (tile, this->Body.CivID, true); -} - -bool __fastcall -patch_Unit_check_airlift_target (Unit * this, int edx, int tile_x, int tile_y) -{ - bool base = Unit_check_airlift_target (this, __, tile_x, tile_y); - bool allowed = base; - - Tile * tile = tile_at (tile_x, tile_y); - - if (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities) { - if ((tile == NULL) || (tile == p_null_tile)) { - allowed = false; - } else { - City * target_city = city_at (tile_x, tile_y); - if (allowed && - (target_city != NULL) && - (target_city->Body.CivID == this->Body.CivID)) - allowed = false; - - if (! allowed) - allowed = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); - } - } - - if (! allowed) - return false; - - return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); -} - -void __fastcall -patch_Unit_airlift (Unit * this, int edx, int tile_x, int tile_y) -{ - Tile * source_tile = NULL; - bool mark_usage = false; - - if (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities) { - source_tile = tile_at (this->Body.X, this->Body.Y); - if (tile_has_friendly_aerodrome_district (source_tile, this->Body.CivID, true)) - mark_usage = true; - } - - Unit_airlift (this, __, tile_x, tile_y); - - if (mark_usage && (source_tile != NULL) && (source_tile != p_null_tile)) { - int mask = itable_look_up_or (&is->aerodrome_airlift_usage, (int)source_tile, 0); - mask |= (1 << this->Body.CivID); - itable_insert (&is->aerodrome_airlift_usage, (int)source_tile, mask); - } -} - -int __fastcall -patch_City_count_airports_for_ai_airlift_target (City * this, int edx, enum ImprovementTypeFlags airport_flag) -{ - // When this function is called, the AI unit being moved is stored in register ESI. - Unit * unit; - __asm__ __volatile__("mov %%esi, %0" : "=r" (unit)); - - int tr = City_count_improvements_with_flag (this, __, airport_flag); - - // Check the stack limit here. If the city's tile is at the limit, return that it has no airport so the AI can't airlift there. - if ((tr > 0) && ! is_below_stack_limit (tile_at (this->Body.X, this->Body.Y), this->Body.CivID, unit->Body.UnitTypeID)) - return 0; - - else - return tr; -} - -int __fastcall -patch_Unit_ai_eval_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) -{ - int tr = Unit_ai_eval_airdrop_target (this, __, tile_x, tile_y); - - // Prevent the AI from airdropping onto tiles in violation of the stack limit or trespassing restriction - if ((tr > 0) && - ((! is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID)) || - is_airdrop_trespassing (this, tile_x, tile_y))) - tr = 0; - - return tr; -} - -bool __fastcall -patch_Unit_find_telepad_on_tile (Unit * this, int edx, int x, int y, bool show_selection_popup, Unit ** out_unit_telepad) -{ - if (! is_below_stack_limit (tile_at (x, y), this->Body.CivID, this->Body.UnitTypeID)) { - *out_unit_telepad = NULL; - return false; - } else - return Unit_find_telepad_on_tile (this, __, x, y, show_selection_popup, out_unit_telepad); -} - -bool __fastcall -patch_Unit_ai_go_to_capital (Unit * this) -{ - City * capital = get_city_ptr (leaders[this->Body.CivID].CapitalID); - - // Block going to capital if the capital's tile is at the stack limit. This stops the AI from airlifting there (would violate the limit) and - // saves it from trying to pathfind there. - if ((capital != NULL) && - ! is_below_stack_limit (tile_at (capital->Body.X, capital->Body.Y), this->Body.CivID, this->Body.UnitTypeID)) - return false; - - return Unit_ai_go_to_capital (this); -} - -bool __fastcall -patch_Unit_is_in_rebase_range (Unit * this, int edx, int tile_x, int tile_y) -{ - bool in_range; - - // 6 is the game's standard value, so fall back on the base game logic in that case - if (is->current_config.rebase_range_multiplier == 6) - in_range = Unit_is_in_rebase_range (this, __, tile_x, tile_y); - - else { - int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - if (op_range < 1) - op_range = 500; - - int x_dist = Map_get_x_dist (&p_bic_data->Map, __, tile_x, this->Body.X), - y_dist = Map_get_y_dist (&p_bic_data->Map, __, tile_y, this->Body.Y); - - in_range = ((x_dist + y_dist) >> 1) <= (op_range * is->current_config.rebase_range_multiplier); - } - - return in_range && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); -} - -bool __fastcall -patch_Unit_check_rebase_target (Unit * this, int edx, int tile_x, int tile_y) -{ - // Check if this is an air unit - bool is_air_unit = (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air); - - // If districts are enabled and this is an air unit, check for aerodrome districts - if (is_air_unit && is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts) { - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile != NULL) && (tile != p_null_tile)) { - // Check if tile has a district - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - int district_id = inst->district_id; - // Check if this is an aerodrome district owned by this unit's civ - if ((district_id == AERODROME_DISTRICT_ID) && (tile->Territory_OwnerID == this->Body.CivID)) { - // Check if aerodrome is complete - if (district_is_complete (tile, district_id)) { - // Perform range check - bool in_range = patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y); - if (in_range) { - return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); - } - } - } - } - - // If air_units_use_aerodrome_districts_not_cities is enabled, check if there's a city and disallow it - if (is->current_config.air_units_use_aerodrome_districts_not_cities) { - City * target_city = city_at (tile_x, tile_y); - if (target_city != NULL && target_city->Body.CivID == this->Body.CivID) { - // There's a friendly city here - disallow landing since configured to use aerodromes/airfields/carriers only - return false; - } - } - } - } - - // 6 is the game's standard value, so fall back on the base game logic in that case - if (is->current_config.rebase_range_multiplier == 6) { - return Unit_check_rebase_target (this, __, tile_x, tile_y) && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); - - // Otherwise, we have to redo the range check. Unlike Unit::is_in_rebase_range, the base method here does more than just check the range so we - // want to make sure to call it even if we determine that the target is in range. In that case, set the range to unlimited temporarily so the - // base game's range check passes. - } else { - if (patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y)) { - int * p_op_range = &p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - int original_op_range = *p_op_range; - *p_op_range = 0; - bool tr = Unit_check_rebase_target (this, __, tile_x, tile_y); - *p_op_range = original_op_range; - return tr; - } else - return false; - } -} - -int __fastcall -patch_Sprite_draw_already_worked_tile_img (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - Sprite * to_draw = this; - - if (is->do_not_draw_already_worked_tile_img) - return 0; - - if (is->current_config.toggle_zoom_with_z_on_city_screen && p_bic_data->is_zoomed_out) { - - // Load sprite if necessary - if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_UNINITED) { - is->tile_already_worked_zoomed_out_sprite_init_state = IS_INIT_FAILED; - PCX_Image * pcx = malloc (sizeof *pcx); - if (pcx != NULL) { - memset (pcx, 0, sizeof *pcx); - PCX_Image_construct (pcx); - char path[2*MAX_PATH]; - get_mod_art_path ("TileAlreadyWorkedZoomedOut.pcx", path, sizeof path); - PCX_Image_read_file (pcx, __, path, NULL, 0, 0x100, 2); - if (pcx->JGL.Image != NULL) { - Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; - memset (sprite, 0, sizeof *sprite); - Sprite_construct (sprite); - Sprite_slice_pcx (sprite, __, pcx, 0, 0, 64, 32, 1, 1); - is->tile_already_worked_zoomed_out_sprite_init_state = IS_OK; - } - pcx->vtable->destruct (pcx, __, 0); - free (pcx); - } - } - - if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_OK) - to_draw = &is->tile_already_worked_zoomed_out_sprite; - } - - return Sprite_draw (to_draw, __, canvas, pixel_x, pixel_y, color_table); -} - -int __fastcall -patch_Tile_m43_Get_field_30_for_city_loc_eval (Tile * this) -{ - int tr = this->vtable->m43_Get_field_30 (this); - - // This patch function replaces two places where ai_eval_city_location calls Tile::m43_Get_field_30 to check the 18th bit, which indicates - // whether the tile is in the workable area of any city. If it is but the work area has been expanded, check that it's actually within the - // normal 20-tile area. This prevents work area expansion from causing AIs to space their cities further apart. - // The field_30_get_counter is a crazy workaround for the fact that the game doesn't have any way to determine a tile's coordinates given a - // pointer to its object. So we track the initial (x, y) for the tile we're evaluating and then count calls to this func to know what - // neighboring coords "this" corresponds to. - int get_counter = is->ai_evaling_city_field_30_get_counter; - if (((tr >> 17) & 1) && (is->current_config.city_work_radius >= 3)) { - bool found_city = false; - int this_x, this_y; { - int dx, dy; - patch_ni_to_diff_for_work_area (get_counter, &dx, &dy); - this_x = is->ai_evaling_city_loc_x + dx; - this_y = is->ai_evaling_city_loc_y + dy; - wrap_tile_coords (&p_bic_data->Map, &this_x, &this_y); - } - FOR_TILES_AROUND (tai, 21, this_x, this_y) - if (Tile_has_city (tai.tile)) { - found_city = true; - break; - } - if (! found_city) - tr &= ~(1 << 17); - } - get_counter++; - if (get_counter >= 21) - get_counter = 0; - is->ai_evaling_city_field_30_get_counter = get_counter; - - return tr; - -} - -// Intercept the call where the game gets a random index at which to start searching for a suitable tile to become polluted. Normally, it passes 20 as -// the limit here. We must replace that to cover a potentially modded work area. -int __fastcall -patch_rand_int_to_place_pollution (void * this, int edx, int lim) -{ - return rand_int (this, __, is->workable_tile_count - 1); -} - -void __fastcall -patch_Main_Screen_Form_t2s_coords_to_draw_yields (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int * out_x, int * out_y) -{ - Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, out_x, out_y); - - // If we've zoomed out the map on the city screen, we may end up drawing the tile yields off screen depending on the map size. If this is the - // case, detected by negative screen coords, then shift the coords over by one map-screen back onto the actual screen. The shift amounts are - // 64*map_width/2 and 32*map_height/2 for x and y because (64, 32) is the size of a zoomed out tile and /2 is for overlap (I think). - if (p_bic_data->is_zoomed_out && (*out_x < 0)) - *out_x += p_bic_data->Map.Width << 5; - if (p_bic_data->is_zoomed_out && (*out_y < 0)) - *out_y += p_bic_data->Map.Height << 4; -} - -void -set_clip_area_to_map_view (City_Form * city_form) -{ - int left_margin = (p_bic_data->ScreenWidth - city_form->Background_Image.Width) / 2, - top_margin = (p_bic_data->ScreenHeight - city_form->Background_Image.Height) / 2; - RECT map_view_on_screen = { .left = left_margin, .top = top_margin + 92, .right = left_margin + 1024, .bottom = top_margin + 508 }; - JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; - jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &map_view_on_screen); -} - -void -clear_clip_area (City_Form * city_form) -{ - JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; - jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &jgl_canvas->Image_Rect); -} - -void -init_distribution_hub_icons () -{ - if (is->distribution_hub_icons_img_state != IS_UNINITED) - return; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - char ss[200]; - snprintf (ss, sizeof ss, "[C3X] init_distribution_hub_icons: state=%d\n", is->distribution_hub_icons_img_state); - (*p_OutputDebugStringA) (ss); - - char temp_path[2*MAX_PATH]; - get_mod_art_path ("Districts/DistributionHubIncomeIcons.pcx", temp_path, sizeof temp_path); - - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - if ((pcx.JGL.Image == NULL) || - (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || - (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { - (*p_OutputDebugStringA) ("[C3X] PCX file for distribution hub icons failed to load or is too small.\n"); - is->distribution_hub_icons_img_state = IS_INIT_FAILED; - goto cleanup; - } - - // Extract shield icon (index 4: x = 1 + 4*31 = 125, width 30) - Sprite_construct (&is->distribution_hub_shield_icon); - Sprite_slice_pcx (&is->distribution_hub_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); - - // Extract shield corruption icon (index 5: x = 1 + 5*31 = 156, width 30) - Sprite_construct (&is->distribution_hub_corruption_icon); - Sprite_slice_pcx (&is->distribution_hub_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); - - // Extract small shield icon (index 13) - Sprite_construct (&is->distribution_hub_shield_icon_small); - Sprite_slice_pcx (&is->distribution_hub_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); - - // Extract surplus food icon (index 6: x = 1 + 6*31 = 187, width 30) - Sprite_construct (&is->distribution_hub_food_icon); - Sprite_slice_pcx (&is->distribution_hub_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); - - // Extract small surplus food icon (index 15) - Sprite_construct (&is->distribution_hub_food_icon_small); - Sprite_slice_pcx (&is->distribution_hub_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); - - // Extract eaten food icon (index 7: x = 1 + 7*31 = 218, width 30) - Sprite_construct (&is->distribution_hub_eaten_food_icon); - Sprite_slice_pcx (&is->distribution_hub_eaten_food_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); - - is->distribution_hub_icons_img_state = IS_OK; -cleanup: - pcx.vtable->destruct (&pcx, __, 0); -} - -void -draw_district_yields (City_Form * city_form, Tile * tile, int district_id, int screen_x, int screen_y) -{ - // Lazy load district icons - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - if (is->dc_icons_img_state != IS_OK) - return; - - if (district_id < 0 || district_id >= is->district_count) - return; - - // Get district configuration - struct district_config * config = &is->district_configs[district_id]; - struct district_instance * inst = get_district_instance (tile); - - // Count total yields from bonuses - int food_bonus = 0, shield_bonus = 0, gold_bonus = 0, science_bonus = 0, culture_bonus = 0, happiness_bonus = 0; - get_effective_district_yields (inst, config, &food_bonus, &shield_bonus, &gold_bonus, &science_bonus, &culture_bonus, &happiness_bonus); - if ((config->generated_resource_id >= 0) && - (config->generated_resource_flags & MF_YIELDS) && - (city_form->CurrentCity != NULL) && - district_generates_resource_for_civ (tile, inst, config, city_form->CurrentCity->Body.CivID)) { - Resource_Type * res = &p_bic_data->ResourceTypes[config->generated_resource_id]; - food_bonus += res->Food; - shield_bonus += res->Shield; - gold_bonus += res->Commerce; - } - - int food_pos = food_bonus > 0 ? food_bonus : 0; - int food_neg = food_bonus < 0 ? -food_bonus : 0; - int shield_pos = shield_bonus > 0 ? shield_bonus : 0; - int shield_neg = shield_bonus < 0 ? -shield_bonus : 0; - int gold_pos = gold_bonus > 0 ? gold_bonus : 0; - int gold_neg = gold_bonus < 0 ? -gold_bonus : 0; - int science_pos = science_bonus > 0 ? science_bonus : 0; - int science_neg = science_bonus < 0 ? -science_bonus : 0; - int culture_pos = culture_bonus > 0 ? culture_bonus : 0; - int culture_neg = culture_bonus < 0 ? -culture_bonus : 0; - int happiness_pos = happiness_bonus > 0 ? happiness_bonus : 0; - int happiness_neg = happiness_bonus < 0 ? -happiness_bonus : 0; - - int total_yield = 0; - total_yield += food_pos + food_neg; - total_yield += shield_pos + shield_neg; - total_yield += gold_pos + gold_neg; - total_yield += science_pos + science_neg; - total_yield += culture_pos + culture_neg; - total_yield += happiness_pos + happiness_neg; - - if (total_yield <= 0) - return; - - // Get sprites - Sprite * food_sprite = &is->district_food_icon_small; - Sprite * shield_sprite = &is->district_shield_icon_small; - Sprite * commerce_sprite = &is->district_commerce_icon_small; - Sprite * science_sprite = &is->district_science_icon_small; - Sprite * culture_sprite = &is->district_culture_icon_small; - Sprite * happiness_sprite = &is->district_happiness_icon_small; - Sprite * food_negative_sprite = &is->district_negative_food_icon_small; - Sprite * shield_negative_sprite = &is->district_negative_shield_icon_small; - Sprite * commerce_negative_sprite = &is->district_negative_commerce_icon_small; - Sprite * science_negative_sprite = &is->district_negative_science_icon_small; - Sprite * culture_negative_sprite = &is->district_negative_culture_icon_small; - Sprite * happiness_negative_sprite = &is->district_unhappiness_icon_small; - - // Determine sprite dimensions - int sprite_width = food_sprite->Width3; - int sprite_height = food_sprite->Height; - - // Calculate total width of all icons - int total_width = total_yield * sprite_width; - - // Center the icons horizontally - int half_width = total_width >> 1; - int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; - int max_offset = (tile_width >> 1) - 5; - if (half_width > max_offset) - half_width = max_offset; - - int pixel_x = screen_x - half_width; - int pixel_y = screen_y - (sprite_height >> 1); - - // Adjust spacing if icons would exceed tile width - int spacing = sprite_width; - if (total_width > tile_width - 10) { - if (total_yield > 1) { - spacing = (tile_width - 10 - sprite_width) / (total_yield - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > sprite_width) - spacing = sprite_width; - } - } - - // Draw icons in order: shields, food, science, commerce, culture - for (int i = 0; i < shield_pos; i++) { - Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < shield_neg; i++) { - Sprite_draw (shield_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < food_pos; i++) { - Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < food_neg; i++) { - Sprite_draw (food_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < science_pos; i++) { - Sprite_draw (science_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < science_neg; i++) { - Sprite_draw (science_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < gold_pos; i++) { - Sprite_draw (commerce_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < gold_neg; i++) { - Sprite_draw (commerce_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < culture_pos; i++) { - Sprite_draw (culture_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < culture_neg; i++) { - Sprite_draw (culture_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - - for (int i = 0; i < happiness_pos; i++) { - Sprite_draw (happiness_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } - for (int i = 0; i < happiness_neg; i++) { - Sprite_draw (happiness_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing; - } -} - -void -draw_distribution_hub_yields (City_Form * city_form, Tile * tile, int tile_x, int tile_y, int screen_x, int screen_y) -{ - // Get the distribution hub record for this tile - struct distribution_hub_record * rec = get_distribution_hub_record (tile); - if (rec == NULL) - return; - - City * anchor_city = get_connected_city_for_distribution_hub (rec); - if (! distribution_hub_accessible_to_city (rec, city_form->CurrentCity)) - return; - - int food_yield = rec->food_yield; - int shield_yield = rec->shield_yield; - int total_yield = food_yield + shield_yield; - - if (total_yield <= 0) - return; - - // Lazy load distribution hub icons - if (is->distribution_hub_icons_img_state == IS_UNINITED) - init_distribution_hub_icons (); - if (is->distribution_hub_icons_img_state != IS_OK) - return; - - Sprite * food_sprite = &is->distribution_hub_food_icon_small; - Sprite * shield_sprite = &is->distribution_hub_shield_icon_small; - - if (food_sprite->Width3 == 0) food_sprite = &is->distribution_hub_food_icon; - if (shield_sprite->Width3 == 0) shield_sprite = &is->distribution_hub_shield_icon; - - int sprite_height = food_sprite->Height; - if (sprite_height == 0) sprite_height = shield_sprite->Height; - - int food_width = food_sprite->Width3; - int shield_width = shield_sprite->Width3; - if ((food_width <= 0) && (shield_width > 0)) food_width = shield_width; - if ((shield_width <= 0) && (food_width > 0)) shield_width = food_width; - - // Calculate total width of all icons - int total_width = 0; - if (food_yield > 0) total_width += food_width * food_yield; - if (shield_yield > 0) total_width += shield_width * shield_yield; - - // Center the icons horizontally - int half_width = total_width >> 1; - int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; - int max_offset = (tile_width >> 1) - 5; - if (half_width > max_offset) half_width = max_offset; - - int pixel_x = screen_x - half_width; - int pixel_y = screen_y - (sprite_height >> 1); - - // Adjust spacing if icons would exceed tile width - int spacing_food = food_width; - int spacing_shield = shield_width; - - if (total_width > tile_width - 10) { - if (total_yield > 1) { - int spacing = (tile_width - 10 - food_width) / (total_yield - 1); - if (spacing < 1) - spacing = 1; - else if (spacing > food_width) - spacing = food_width; - spacing_food = spacing; - spacing_shield = spacing; - } - } - - // Draw food icons first - for (int i = 0; i < food_yield; i++) { - Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing_food; - } - - // Draw shield icons - for (int i = 0; i < shield_yield; i++) { - Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); - pixel_x += spacing_shield; - } -} - -void __fastcall -patch_City_Form_draw_yields_on_worked_tiles (City_Form * this) -{ - // If we're zoomed in and the city work radius is at least 4 then it's likely we'll end up drawing things outside of the city screen's usual - // map area. Set the clip area to the map area so none of those draws are visible. - bool changed_clip_area = false; - if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { - set_clip_area_to_map_view (this); - changed_clip_area = true; - } - - if (is->current_config.enable_districts && this->CurrentCity != NULL) { - recompute_city_yields_with_districts (this->CurrentCity); - } - - is->do_not_draw_already_worked_tile_img = false; - City_Form_draw_yields_on_worked_tiles (this); - - // If we're zoomed out then draw the yields again but this time skip drawing of the tile-already-worked sprites. This is because the - // transparent regions of those sprites get drawn overtop of the yield sprites when zoomed out, and that overdrawing deletes parts of the - // yields, i.e., it overwrites their colored pixels with transparent ones. The simplest solution is to draw the yields again after the - // already-worked sprites to ensure the former get drawn overtop of the latter. - if (p_bic_data->is_zoomed_out) { - is->do_not_draw_already_worked_tile_img = true; - City_Form_draw_yields_on_worked_tiles (this); - } - - // Draw district bonuses on district tiles - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - City * city = this->CurrentCity; - if (city == NULL) - goto skip_district_yields; - - int city_x = city->Body.X; - int city_y = city->Body.Y; - int civ_id = city->Body.CivID; - - // Calculate screen coordinates for city center - int center_screen_x, center_screen_y; - Main_Screen_Form_tile_to_screen_coords (p_main_screen_form, __, city_x, city_y, ¢er_screen_x, ¢er_screen_y); - - int tile_half_width = p_bic_data->is_zoomed_out ? 32 : 64; - int tile_half_height = p_bic_data->is_zoomed_out ? 16 : 32; - center_screen_x += tile_half_width; - if (center_screen_x < 0) - center_screen_x += p_bic_data->Map.Width * tile_half_width; - center_screen_y += tile_half_height; - if (center_screen_y < 0) - center_screen_y += p_bic_data->Map.Height * tile_half_height; - - int remaining_utilized_neighborhoods = 0; - if (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts) - remaining_utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); - - FOR_DISTRICTS_AROUND (wai, city_x, city_y, true) { - struct district_instance * inst = wai.district_inst; - int district_id = inst->district_id; - - bool is_distribution_hub = district_id == DISTRIBUTION_HUB_DISTRICT_ID; - bool is_natural_wonder = district_id == NATURAL_WONDER_DISTRICT_ID; - - if (is_natural_wonder && (!is->current_config.enable_natural_wonders)) - continue; - - // Distribution hubs are drawn in the dedicated wider-radius pass below. - if (is_distribution_hub) - continue; - - if (!is_natural_wonder && (!is->current_config.enable_districts)) - continue; - - // For neighborhood districts, check if population is high enough to utilize them - if (is->current_config.enable_districts && - is->current_config.enable_neighborhood_districts && - district_id == NEIGHBORHOOD_DISTRICT_ID) { - // Only draw yields if this neighborhood is utilized - if (remaining_utilized_neighborhoods <= 0) - continue; - remaining_utilized_neighborhoods--; - } - - // Calculate screen coordinates for this tile - int screen_x = center_screen_x + (wai.dx * tile_half_width); - int screen_y = center_screen_y + (wai.dy * tile_half_height); - - // Call the appropriate drawing function - draw_district_yields (this, wai.tile, district_id, screen_x, screen_y); - } - - // Draw distribution hub yields around a larger radius so connected hubs outside the work area are shown - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { - int const max_tiles = workable_tile_counts[7]; - - for (int ni = 0; ni < max_tiles; ni++) { - int dx, dy; - patch_ni_to_diff_for_work_area (ni, &dx, &dy); - - int tile_x = city_x + dx; - int tile_y = city_y + dy; - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID)) - continue; - - int screen_x = center_screen_x + (dx * tile_half_width); - int screen_y = center_screen_y + (dy * tile_half_height); - draw_distribution_hub_yields (this, tile, tile_x, tile_y, screen_x, screen_y); - } - } - } - -skip_district_yields: - if (changed_clip_area) - clear_clip_area (this); -} - -bool __fastcall -patch_City_Form_draw_highlighted_yields (City_Form * this, int edx, int tile_x, int tile_y, int neighbor_index) -{ - // Make sure we don't draw outside the map area - bool changed_clip_area = false; - if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { - set_clip_area_to_map_view (this); - changed_clip_area = true; - } - - bool tr = City_Form_draw_highlighted_yields (this, __, tile_x, tile_y, neighbor_index); - - if (changed_clip_area) - clear_clip_area (this); - return tr; -} - -void __fastcall -patch_City_Form_draw_border_around_workable_tiles (City_Form * this) -{ - // Make sure we don't draw outside the map area - bool changed_clip_area = false; - if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { - set_clip_area_to_map_view (this); - changed_clip_area = true; - } - - City_Form_draw_border_around_workable_tiles (this); - - if (changed_clip_area) - clear_clip_area (this); -} - -bool __fastcall -patch_City_stop_working_polluted_tile (City * this, int edx, int neighbor_index) -{ - if (is->current_config.do_not_unassign_workers_from_polluted_tiles && - (*p_human_player_bits & (1 << this->Body.CivID))) - return false; // do nothing; return value is not used - else - return City_stop_working_tile (this, __, neighbor_index); -} - -void __fastcall -patch_City_manage_by_governor (City * this, int edx, bool manage_professions) -{ - int * p_stack = (int *)&manage_professions; - int ret_addr = p_stack[-1]; - - // Do nothing if called after spawning pollution but didn't unassign worker - if ((ret_addr == ADDR_MANAGE_CITY_AFTER_POLLUTION_RETURN) && - is->current_config.do_not_unassign_workers_from_polluted_tiles && - (*p_human_player_bits & (1 << this->Body.CivID))) - return; - - City_manage_by_governor (this, __, manage_professions); -} - -City * __cdecl -patch_find_nearest_city_for_ai_alliance_eval (int tile_x, int tile_y, int owner_id, int continent_id, int ignore_owner_id, int perspective_id, City * ignore_city) -{ - City * tr = find_nearest_city (tile_x, tile_y, owner_id, continent_id, ignore_owner_id, perspective_id, ignore_city); - if (is->current_config.patch_division_by_zero_in_ai_alliance_eval && (*p_nearest_city_distance == 0)) - *p_nearest_city_distance = 1; - return tr; -} - -int __fastcall -patch_Unit_get_max_move_points (Unit * this) -{ - if (Unit_has_ability (this, __, UTA_Army) && is->current_config.patch_empty_army_movement) { - int slowest_member_mp = INT_MAX; - bool any_units_in_army = false; - FOR_UNITS_ON (uti, tile_at (this->Body.X, this->Body.Y)) { - if (uti.unit->Body.Container_Unit == this->Body.ID) { - any_units_in_army = true; - slowest_member_mp = not_above (Unit_get_max_move_points (uti.unit), slowest_member_mp); - } - } - if (any_units_in_army) - return slowest_member_mp + p_bic_data->General.RoadsMovementRate; - else - return get_max_move_points (&p_bic_data->UnitTypes[this->Body.UnitTypeID], this->Body.CivID); - } else - return Unit_get_max_move_points (this); -} - -char __fastcall -patch_Unit_is_visible_to_civ_for_bouncing (Unit * this, int edx, int civ_id, int param_2) -{ - // If we're set not to kick out invisible units and this one is invis. then report that it's not seen so it's left alone - if (is->do_not_bounce_invisible_units && Unit_has_ability (this, __, UTA_Invisible)) - return 0; - else - return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); -} - -void __fastcall -patch_Leader_make_peace (Leader * this, int edx, int civ_id) -{ - Leader_make_peace (this, __, civ_id); - - if (is->current_config.disallow_trespassing && - (! this->At_War[civ_id]) && // Make sure the war actually ended - ((this->Relation_Treaties[civ_id] & 2) == 0)) { // Check right of passage (just in case) - is->do_not_bounce_invisible_units = true; - Leader_bounce_trespassing_units (&leaders[civ_id], __, this->ID); - is->do_not_bounce_invisible_units = false; - } -} - -// This patch function replaces calls to Leader::count_wonders_with_flag but is only valid in cases where it only matters whether the return value is -// zero or non-zero. This function will not return the actual count, just zero if no wonders are present and some >0 value if there is at least one. -int __fastcall -patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) -{ - int tr = Leader_count_wonders_with_flag (this, __, flag, only_in_city); - - if ((tr == 0) && - (only_in_city == NULL) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player - - // Sum up wonders owned by other human players - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->ID)) - if (Leader_count_wonders_with_flag (&leaders[n_player], __, flag, only_in_city) > 0) { - tr = 1; - break; - } - player_bits >>= 1; - n_player++; - } - } - - return tr; -} - -int __fastcall -patch_Leader_count_wonders_with_flag_ignore_great_wall (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) -{ - if (is->current_config.enable_districts && - is->current_config.enable_great_wall_districts && - is->current_config.disable_great_wall_city_defense_bonus && - flag == ITW_Doubles_City_Defenses) - return 0; - - return patch_Leader_count_any_shared_wonders_with_flag (this, __, flag, only_in_city); -} - -int const shared_small_wonder_flags = - ITSW_Increases_Chance_of_Leader_Appearance | - ITSW_Build_Larger_Armies | - ITSW_Treasury_Earns_5_Percent | - ITSW_Decreases_Success_Of_Missile_Attacks | - ITSW_Allows_Spy_Missions | - ITSW_Allows_Healing_In_Enemy_Territory | - ITSW_Requires_Victorous_Army | - ITSE_Requires_Elite_Naval_Units; - - -int __fastcall -patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) -{ - int tr = Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); - - // If "this" is a human player who's sharing wonders in hotseat and the flag is one of the ones that gets shared, include the wonders owned by - // all other humans in the game - if ((city_or_null == NULL) && - (flag & shared_small_wonder_flags) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player - - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->ID)) - tr += Leader_count_wonders_with_small_flag (&leaders[n_player], __, flag, city_or_null); - player_bits >>= 1; - n_player++; - } - } - - return tr; -} - -int -find_human_player_with_small_wonder (int improv_id) -{ - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if (player_bits & 1) - if (leaders[n_player].Small_Wonders[improv_id] != -1) - return n_player; - player_bits >>= 1; - n_player++; - } - return -1; -} - -bool __fastcall -patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2) -{ - Improvement * improv = &p_bic_data->Improvements[i_improv]; - bool restore = false; - bool already_shared = false; - int saved_status, saved_required_building_count, saved_armies_count; - if ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) && // if the improv in question is a great or small wonder - is->current_config.share_wonders_in_hotseat && // if we're configured to share wonder effects - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // if in a hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // if "this" is a human player - - // If another human player has already built this small wonder and it has no non-shared effects, then make it unbuildable - if ((improv->Characteristics & ITC_Small_Wonder) && - (find_human_player_with_small_wonder (i_improv) != -1) && - ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) - already_shared = true; - - else { - restore = true; - saved_status = this->Status; - if (improv->RequiredBuildingID != -1) - saved_required_building_count = this->Improvement_Counts[improv->RequiredBuildingID]; - saved_armies_count = this->Armies_Count; - - // Loop over all other human players in the game - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != this->ID)) { - - // Combine status bits - this->Status |= leaders[n_player].Status & (LSF_HAS_VICTORIOUS_ARMY | LSF_HAS_ELITE_NAVAL_UNIT); - - // Combine building counts for the required building if there is one - if (improv->RequiredBuildingID != -1) - this->Improvement_Counts[improv->RequiredBuildingID] += leaders[n_player].Improvement_Counts[improv->RequiredBuildingID]; - - // Combine army counts - this->Armies_Count += leaders[n_player].Armies_Count; - - } - player_bits >>= 1; - n_player++; - } - } - } - - bool tr = (! already_shared) && Leader_can_build_city_improvement (this, __, i_improv, param_2); - - if (restore) { - this->Status = saved_status; - if (improv->RequiredBuildingID != -1) - this->Improvement_Counts[improv->RequiredBuildingID] = saved_required_building_count; - - this->Armies_Count = saved_armies_count; - } - return tr; - -} - -void __fastcall -patch_City_add_happiness_from_buildings (City * this, int edx, int * inout_happiness, int * inout_unhappiness) -{ - // If we're in a hotseat game with shared wonder effects, merge all human player's improvement counts together so the base function checks for - // happiness from improvements owned by other human players. - Leader * owner = &leaders[this->Body.CivID]; - bool restore_improv_counts = false; - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->Body.CivID) & *p_human_player_bits)) { // "this" is owned by a human player - - // Ensure the space we've set aside for saving the real improv counts is large enough - if ((is->saved_improv_counts == NULL) || (is->saved_improv_counts_capacity < p_bic_data->ImprovementsCount)) { - free (is->saved_improv_counts); - is->saved_improv_counts = calloc (p_bic_data->ImprovementsCount, sizeof is->saved_improv_counts[0]); - is->saved_improv_counts_capacity = (is->saved_improv_counts != NULL) ? p_bic_data->ImprovementsCount : 0; - } - - - if (is->saved_improv_counts != NULL) { - // Save the owner's real improv counts and remember to restore them before returning - restore_improv_counts = true; - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - is->saved_improv_counts[n] = owner->Improvement_Counts[n]; - - // Add in improv counts for wonders from all other human players in the game - unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_player = 1; - while (player_bits != 0) { - if ((player_bits & 1) && (n_player != owner->ID)) - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (p_bic_data->Improvements[n].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) - owner->Improvement_Counts[n] += leaders[n_player].Improvement_Counts[n]; - player_bits >>= 1; - n_player++; - } - } - - } - - City_add_happiness_from_buildings (this, __, inout_happiness, inout_unhappiness); - - if (is->current_config.enable_districts) { - int district_happy = 0; - calculate_district_happiness_bonus (this, &district_happy); - - if (district_happy != 0) - *inout_happiness += district_happy; - } - - if (restore_improv_counts) { - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - owner->Improvement_Counts[n] = is->saved_improv_counts[n]; - } -} - -int __fastcall -patch_City_count_other_cont_happiness_buildings (City * this, int edx, int improv_id) -{ - int tr = City_count_other_buildings_on_continent (this, __, improv_id); - - // If it's a hotseat game where we're sharing wonders, "improv_id" refers to a wonder, and "this" is owned by a human player - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((p_bic_data->Improvements[improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && - ((1 << this->Body.CivID) & *p_human_player_bits)) { - - // Add in instances of this improvment on this continent owned by other human players - Tile * this_city_tile = tile_at (this->Body.X, this->Body.Y); - int this_cont_id = this_city_tile->vtable->m46_Get_ContinentID (this_city_tile); - for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { - City * city = get_city_ptr (city_index); - if ((city != NULL) && (city != this) && - (city->Body.CivID != this->Body.CivID) && // if city is owned by a different player AND - ((1 << city->Body.CivID) & *p_human_player_bits)) { // that player is a human - Tile * that_city_tile = tile_at (city->Body.X, city->Body.Y); - int that_cont_id = that_city_tile->vtable->m46_Get_ContinentID (that_city_tile); - if ((this_cont_id == that_cont_id) && patch_City_has_improvement (city, __, improv_id, true)) - tr++; - } - } - - } - - return tr; -} - -void __fastcall -patch_Leader_update_great_library_unlocks (Leader * this) -{ - // If it's a hotseat game with shared wonder effects and "this" is a human player, share contacts among all human players so that "this" gets - // techs from civs known to any human player in the game. Save the real contact info and restore it afterward. NOTE: Contact info has to go - // two ways here; we must mark that "this" has contacted the AIs and vice-versa otherwise the techs won't be granted. That's why we must save - // & restore all contact bits for all players. - bool restore_contacts = false; - struct contact_set { - int contacts[32]; - } saved_contact_sets[32]; - if (is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player - - restore_contacts = true; - for (int n = 0; n < 32; n++) - for (int k = 0; k < 32; k++) - saved_contact_sets[n].contacts[k] = leaders[n].Contacts[k]; - - unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_human = 1; - while (human_player_bits != 0) { - if ((human_player_bits & 1) && (n_human != this->ID)) // n_human is ID of a human player other than "this" - for (int n_ai = 0; n_ai < 32; n_ai++) - if ((*p_player_bits & (1 << n_ai)) && ((*p_human_player_bits & (1 << n_ai)) == 0)) { - // If the human and AI players have contact, mark "this" as having contact with the AI and vice-versa - if (leaders[n_human].Contacts[n_ai] & 1) { - this->Contacts[n_ai] |= 1; - leaders[n_ai].Contacts[this->ID] |= 1; - } - } - human_player_bits >>= 1; - n_human++; - } - } - - Leader_update_great_library_unlocks (this); - - if (restore_contacts) - for (int n = 0; n < 32; n++) - for (int k = 0; k < 32; k++) - leaders[n].Contacts[k] = saved_contact_sets[n].contacts[k]; -} - -bool __fastcall -patch_Leader_has_wonder_doubling_happiness_from (Leader * this, int edx, int improv_id) -{ - bool tr = Leader_has_wonder_doubling_happiness_from (this, __, improv_id); - - // If we're sharing wonder effects in a hotseat game and "this" is a human player, return true when another human player in the game has a - // wonder doubling happiness - if ((! tr) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player - unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; - int n_human = 1; - while (human_player_bits != 0) { - if ((human_player_bits & 1) && - (n_human != this->ID) && - Leader_has_wonder_doubling_happiness_from (&leaders[n_human], __, improv_id)) { - tr = true; - break; - } - human_player_bits >>= 1; - n_human++; - } - } - - return tr; -} - -int __fastcall -patch_Sprite_draw_citizen_head (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - // Reset variable - is->specialist_icon_drawing_running_x = INT_MIN; - - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -int -adjust_specialist_yield_icon_x (int pixel_x, int width) -{ - if (is->current_config.fix_overlapping_specialist_yield_icons) { - if (is->specialist_icon_drawing_running_x == INT_MIN) // first icon drawn - is->specialist_icon_drawing_running_x = pixel_x; - int tr = is->specialist_icon_drawing_running_x; - is->specialist_icon_drawing_running_x += width; - return tr; - } else - return pixel_x; -} - -int __fastcall -patch_Sprite_draw_entertainer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_12_Happy_Faces.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_scientist_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_16_Science.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_tax_collector_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_14_Gold.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_civil_engineer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_13_Shield.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} -int __fastcall -patch_Sprite_draw_police_officer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - int width = p_city_form->City_Icons_Images.Icon_17_Gold_Outcome.Width / 2; - return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); -} - -void __fastcall -patch_City_add_building_if_done (City * this) -{ - // If sharing small wonders in hotseat, check whether the city is building a small wonder that's no longer available to the player b/c its - // effects are provided from another. - int improv_id = this->Body.Order_ID; - Improvement * improv = &p_bic_data->Improvements[improv_id]; - int already_built_by_id; - if ((improv->Characteristics & ITC_Small_Wonder) && - is->current_config.share_wonders_in_hotseat && - (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game - ((1 << this->Body.CivID) & *p_human_player_bits) && // city owned by a human player - ((already_built_by_id = find_human_player_with_small_wonder (improv_id)) != -1) && // SW already built by another human player - ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) { // SW has no non-shared effects - - // Switch city production to something else and notify the player - this->vtable->set_production_to_most_expensive_option (this); - if ((this->Body.CivID == p_main_screen_form->Player_CivID) && (already_built_by_id != p_main_screen_form->Player_CivID)) { - char * new_build_name = (this->Body.Order_Type == COT_Improvement) ? - p_bic_data->Improvements[this->Body.Order_ID].Name.S : - p_bic_data->UnitTypes[this->Body.Order_ID].Name; - PopupForm * popup = get_popup_form (); - set_popup_str_param (0, this->Body.CityName, -1, -1); - set_popup_str_param (1, improv->Name.S, -1, -1); - set_popup_str_param (2, Leader_get_civ_noun (&leaders[already_built_by_id]), -1, -1); - set_popup_str_param (3, new_build_name, -1, -1); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_SHARED_WONDER_CHANGE", -1, 0, 0, 0); - int response = patch_show_popup (popup, __, 0, 0); - if (response == 0) - *p_zoom_to_city_after_update = true; - } - - // As in the base logic, if production gets switched, the game doesn't check if it might still complete on the same turn. - return; - } - - // If production ended up on a wonder, make sure the city can actually build it; otherwise fall back to a defensive unit. - int order_type = this->Body.Order_Type; - int order_id = this->Body.Order_ID; - if (is->current_config.enable_districts && order_type == COT_Improvement) { - Improvement * new_improv = &p_bic_data->Improvements[order_id]; // Improvement might have changed - if (new_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { - if (! (City_can_build_improvement (this, __, order_id, false) && city_meets_district_prereqs_to_build_improvement (this, order_id, true))) { - char ss[256]; - snprintf (ss, sizeof ss, "patch_City_add_building_if_done: City '%s' cannot complete building of wonder '%s'; switching to defensive unit.\n", - this->Body.CityName, - new_improv->Name.S); - (*p_OutputDebugStringA) (ss); - City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; - if (choose_defensive_unit_order (this, &defensive_order)) { - UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; - if (def_type->Unit_Class == UTC_Land) { - City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); - return; - } - } - } - } - } - - City_add_building_if_done (this); -} - -bool __fastcall -patch_City_can_build_upgrade_type (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) -{ - UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; - if (is->current_config.prevent_old_units_from_upgrading_past_ability_block && - ((type->Special_Actions & UCV_Upgrade_Unit) == 0) && - (type->Available_To & (1 << leaders[this->Body.CivID].RaceID))) - exclude_upgradable = false; - - return patch_City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); -} - -void __fastcall -patch_Main_GUI_position_elements (Main_GUI * this) -{ - Main_GUI_position_elements (this); - - // Double size of minimap if configured - bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || - ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); - if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) { - this->Mini_Map_Click_Rect.top -= 105; - this->Mini_Map_Click_Rect.right += 229; - } -} - -#define PEDIA_DESC_LINES_PER_PAGE 38 - -// Returns whether or not the line should be drawn -bool -do_next_line_for_pedia_desc (PCX_Image * canvas, int * inout_y) -{ - if (is->cmpd.drawing_lines && is->current_config.allow_multipage_civilopedia_descriptions) { - int first_line_on_shown_page = is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE; - int page = is->cmpd.line_count / PEDIA_DESC_LINES_PER_PAGE; - is->cmpd.line_count += 1; - is->cmpd.last_page = (page > is->cmpd.last_page) ? page : is->cmpd.last_page; - - if (page == is->cmpd.shown_page) { - *inout_y -= is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE * PCX_Image_get_text_line_height (canvas); - return true; - } else - return false; - } - return true; -} - -int __fastcall -patch_PCX_Image_do_draw_centered_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) -{ - if (do_next_line_for_pedia_desc (this, &y)) - return PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); - else - return 0; // Caller does not use return value -} - -int __fastcall -patch_PCX_Image_draw_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int str_len) -{ - if (do_next_line_for_pedia_desc (this, &y)) - return PCX_Image_draw_text (this, __, str, x, y, str_len); - else - return PCX_Image_draw_text (this, __, " ", x, y, 1); // Caller uses the return value here so draw an empty string isntead of doing nothing -} - -// Steam code is slightly different; this no-len version of draw_text gets called sometimes. It's the same as draw_text instead it computes the string -// length itself instead of taking it in as a parameter. -int __fastcall -patch_PCX_Image_draw_text_no_len_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y) -{ - return patch_PCX_Image_draw_text_in_wrap_func (this, __, str, x, y, strlen (str)); -} - -void -draw_civilopedia_article (void (__fastcall * base) (Civilopedia_Article *), Civilopedia_Article * article) -{ - // If the article changed then clear things from the old one - if (is->cmpd.article != article) { - is->cmpd.last_page = 0; - is->cmpd.shown_page = 0; - is->cmpd.article = article; - } - - is->cmpd.line_count = 0; - is->cmpd.drawing_lines = article->show_description; - - base (article); - - is->cmpd.drawing_lines = false; -} - -void __fastcall -patch_Civilopedia_Article_m01_Draw_GCON_or_RACE (Civilopedia_Article * this) -{ - draw_civilopedia_article (Civilopedia_Article_m01_Draw_GCON_or_RACE, this); -} - -void -print_pedia_unit_stats (PCX_Image * canvas, int x, char ** entries, int entry_count) -{ - // Same forumula as the base game. Shifts entries upward if 4 or more. - int y = (entry_count > 3) ? 4 * (3 * entry_count - 9) : 0; - y = 449 - y; - - for (int n = 0; n < entry_count; n++) - y = PCX_Image_draw_and_wrap_text (canvas, __, entries[n], x, y, 150); -} - -void __fastcall -patch_Civilopedia_Article_m01_Draw_UNIT (Civilopedia_Article * this) -{ - // Make sure list of second column stat strings is clear before drawing - char ** entries = is->pedia_unit_stats_second_column_strs; - int capacity = ARRAY_LEN (is->pedia_unit_stats_second_column_strs); - if (is->current_config.expand_civilopedia_unit_stats) - for (int n = 0; n < capacity; n++) { - free (entries[n]); - entries[n] = NULL; - } - - draw_civilopedia_article (Civilopedia_Article_m01_Draw_UNIT, this); - - bool drew_stats = this->show_description == false || this->more_text_line_count == 0; - if (is->current_config.expand_civilopedia_unit_stats && drew_stats) { - // By this point entries have been filled in for the second column of unit stats (see ...draw_pedia_unit_stats_2nd_column), which has - // not actually been drawn. - int entry_count = 0; - for (int n = 0; n < capacity; n++) - if (entries[n] != NULL) - entry_count++; - - char s[100] = {0}; - - // Add entry for op range if aircraft. The original game shows movement instead of op range in the first column but we patch that to - // show movement always. - if (entry_count < capacity && this->unit_type->Unit_Class == UTC_Air) { - // Reserve spot at entries[0] to prepend new item - for (int n = capacity - 1; n > 0; n--) - entries[n] = entries[n-1]; - entry_count++; - - snprintf (s, (sizeof s) - 1, "%s: %d", (*p_labels)[LBL_OPERATIONAL_RANGE], this->unit_type->OperationalRange); - entries[0] = strdup (s); - } - - // Add bombard range if tactical nuke with bombard strength == 0 because the base game won't display it - if (entry_count < capacity && - this->unit_type->Unit_Class == UTC_Land && - this->unit_type->Bombard_Strength == 0 && - UnitType_has_ability (this->unit_type, __, UTA_Nuclear_Weapon) && - UnitType_has_ability (this->unit_type, __, UTA_Tacticle_Missile)) { - snprintf (s, (sizeof s) - 1, "%s: %d", (*p_labels)[LBL_BOMBARD_RANGE], this->unit_type->Bombard_Range); - entries[entry_count++] = strdup (s); - } - - // Add HP Bonus - if (entry_count < capacity && this->unit_type->Hit_Point_Bonus != 0) { - snprintf (s, (sizeof s) - 1, "%s: %d", is->c3x_labels[CL_HP_BONUS], this->unit_type->Hit_Point_Bonus); - entries[entry_count++] = strdup (s); - } - - // Add worker strength - int rounded_worker_strength = ((int)(this->unit_type->WorkerStrength * 10000.0f) + 50) / 100; - if (entry_count < capacity && rounded_worker_strength != 0) { - snprintf (s, (sizeof s) - 1, "%s: %d%%", is->c3x_labels[CL_WORKER_STRENGTH], rounded_worker_strength); - entries[entry_count++] = strdup (s); - } - - if (entry_count <= 6) - print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 213, entries, entry_count); - else { // If more than 6 entries, split some off into a third column - int third_count = entry_count / 2, - second_count = entry_count - third_count; - print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 198, entries, second_count); - print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 355, &entries[second_count], third_count); - } - } -} - -int __fastcall -patch_PCX_Image_draw_pedia_unit_stats_2nd_column (PCX_Image * this, int edx, char * str, int x, int y, int width) -{ - if (is->current_config.expand_civilopedia_unit_stats) - for (int n = 0; n < ARRAY_LEN (is->pedia_unit_stats_second_column_strs); n++) - if (is->pedia_unit_stats_second_column_strs[n] == NULL) { - is->pedia_unit_stats_second_column_strs[n] = strdup (str); // Record what would have been drawn here - str = " "; // Draw empty string. Can't skip draw call entirely b/c we need the return value - break; - } - - return PCX_Image_draw_and_wrap_text (this, __, str, x, y, width); -} - -void __fastcall -patch_Civilopedia_Form_m53_On_Control_Click (Civilopedia_Form * this, int edx, CivilopediaControlID control_id) -{ - Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; - - // "Effects" button leaves description mode, returns to showing effects - if ((control_id == PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID) && (current_article != NULL)) { - current_article->show_description = false; - is->cmpd.shown_page = 0; - play_sound_effect (26); // 26 = SE_SELECT - p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); - - // "Previous" button shows the previous page of a multi-page description or switches to effects mode if on the first page - } else if (control_id == PEDIA_MULTIPAGE_PREV_BUTTON_ID) { - if (is->cmpd.shown_page > 0) - is->cmpd.shown_page -= 1; - else - current_article->show_description = false; - play_sound_effect (26); - p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); - - } else if ((control_id == CCID_DESCRIPTION_BTN) && // if description/more/prev button was clicked AND - (current_article != NULL) && current_article->show_description && // currently showing a description of an article AND - (is->cmpd.last_page > 0)) { // this is a multi-page description - - // Show the next page of the multi-page description unless it's a two-page description and we're on the second page, in which case go - // back to the first. - if ((is->cmpd.last_page == 1) && (is->cmpd.shown_page == 1)) - is->cmpd.shown_page = 0; - else - is->cmpd.shown_page = not_above (is->cmpd.last_page, is->cmpd.shown_page + 1); - play_sound_effect (26); - p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); - - } else - Civilopedia_Form_m53_On_Control_Click (this, __, control_id); -} - -void __fastcall -patch_Civilopedia_Form_m22_Draw (Civilopedia_Form * this) -{ - // Make sure the new buttons are not visible and the multipage variables are cleared when we exit description mode - if ((this->Current_Article_ID < 0) || ! this->Articles[this->Current_Article_ID]->show_description) { - is->cmpd.shown_page = is->cmpd.last_page = 0; - if (is->cmpd.effects_btn != NULL) - is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); - if (is->cmpd.previous_btn != NULL) - is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); - } - - Civilopedia_Form_m22_Draw (this); -} - -int __fastcall -patch_Button_initialize_civilopedia_description (Button * this, int edx, char * text, int control_id, int x, int y, int width, int height, Base_Form * parent, int param_8) -{ - Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; - if (current_article == NULL) - return Button_initialize (this, __, text, control_id, x, y, width, height, parent, param_8); - - // Set button visibility for multi-page descriptions if we're showing such a thing right now - bool show_desc_btn = true, show_effects_btn = false, show_previous_btn = false; - char * desc_btn_text = text; - if (current_article->show_description && (is->cmpd.last_page > 0)) { - - // Tribe articles act like one long descripton. - if ((current_article->article_kind == CAK_TRIBE) || (current_article->article_kind == CAK_GAME_CONCEPT)) { - - // Show the more button as long as we're not on the last page. Show the previous always since we're in description mode. - show_previous_btn = true; - desc_btn_text = (*p_labels)[LBL_MORE]; - if (is->cmpd.shown_page >= is->cmpd.last_page) - show_desc_btn = false; - - // Unit articles have separate description/effects modes. - } else if (current_article->article_kind == CAK_UNIT) { - - // For a two-page description, show the effects button and the description button which will act as a next/previous button - if (is->cmpd.last_page == 1) { - show_effects_btn = true; - desc_btn_text = is->cmpd.shown_page == 0 ? (*p_labels)[LBL_MORE] : (*p_labels)[LBL_PREVIOUS]; - - // For a three or more page description, show the effects button, and show the description button only if we're not on the - // last page (b/c it's the next button), and show the previous button only if we're not on the first page. If the desc button - // is visible, make it say "More". - } else { - show_effects_btn = true; - if (is->cmpd.shown_page >= is->cmpd.last_page) - show_desc_btn = false; - else - desc_btn_text = (*p_labels)[LBL_MORE]; - show_previous_btn = is->cmpd.shown_page > 0; - } - } - } - - int tr = Button_initialize (this, __, desc_btn_text, control_id, x, y, width, height, parent, param_8); - - if (! show_desc_btn) - this->vtable->m02_Show_Disabled ((Base_Form *)this); - - if (is->cmpd.effects_btn != NULL) { - if (show_effects_btn) - is->cmpd.effects_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.effects_btn, __, 0); - else - is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); - } - - if (is->cmpd.previous_btn != NULL) { - if (show_previous_btn) - is->cmpd.previous_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.previous_btn, __, 0); - else - is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); - } - - return tr; -} - -int __fastcall -patch_Civilopedia_Form_m68_Show_Dialog (Civilopedia_Form * this, int edx, int param_1, void * param_2, void * param_3) -{ - memset (&is->cmpd, 0, sizeof is->cmpd); - - Button * bs[] = {malloc (sizeof Button), malloc (sizeof Button)}; - for (int n = 0; n < ARRAY_LEN (bs); n++) { - if (bs[n] == NULL) - continue; - Button_construct (bs[n]); - - int desc_btn_x = 535, desc_btn_y = 222, desc_btn_height = 17; - - Button_initialize (bs[n], __, - n == 0 ? (*p_labels)[LBL_EFFECTS] : (*p_labels)[LBL_PREVIOUS], - n == 0 ? PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID : PEDIA_MULTIPAGE_PREV_BUTTON_ID, // control ID - desc_btn_x, // location x - desc_btn_y + (n == 0 ? -2 : 2) * desc_btn_height, // location y - MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height - (Base_Form *)this, // parent - 0); // ? - - for (int k = 0; k < 3; k++) - bs[n]->Images[k] = &this->Description_Btn_Images[k]; - - // Do now draw the button until needed - bs[n]->vtable->m02_Show_Disabled ((Base_Form *)bs[n]); - } - is->cmpd.effects_btn = bs[0]; - is->cmpd.previous_btn = bs[1]; - - int tr = Civilopedia_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); - - for (int n = 0; n < ARRAY_LEN (bs); n++) - if (bs[n] != NULL) { - bs[n]->vtable->destruct ((Base_Form *)bs[n], __, 0); - free (bs[n]); - } - is->cmpd.effects_btn = is->cmpd.previous_btn = NULL; - - return tr; -} - -void -init_district_images () -{ - if (is_online_game () || is->dc_img_state != IS_UNINITED) - return; - - char art_dir[200]; - char temp_path[2*MAX_PATH]; - - is->dc_img_state = IS_INIT_FAILED; - - PCX_Image pcx; - PCX_Image_construct (&pcx); - - // For each district type - for (int dc = 0; dc < is->district_count; dc++) { - struct district_config const * cfg = &is->district_configs[dc]; - int variant_count = cfg->img_path_count; - if (variant_count <= 0) - continue; - - int era_count = cfg->vary_img_by_era ? 4 : 1; - int column_count = cfg->img_column_count; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - - // For each cultural variant - for (int variant_i = 0; variant_i < variant_count; variant_i++) { - if (cfg->img_paths[variant_i] == NULL) - continue; - - // Read PCX file - snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", cfg->img_paths[variant_i]); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - - if (pcx.JGL.Image == NULL) { - - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load district images from %s", temp_path); - pop_up_in_game_error (ss); - - (*p_OutputDebugStringA) ("[C3X] Failed to load districts sprite sheet.\n"); - for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) - for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) - for (int era_i = 0; era_i < 4; era_i++) { - for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { - Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - } - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - // For each era - for (int era_i = 0; era_i < era_count; era_i++) { - - // For each column in the image (variations on the district image for that era) - for (int col_i = 0; col_i < column_count; col_i++) { - Sprite_construct (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i]); - - int x = sprite_width * col_i, - y = sprite_height * era_i; - Sprite_slice_pcx (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i], __, &pcx, x, y, sprite_width, sprite_height, 1, 1); - } - } - - pcx.vtable->clear_JGL (&pcx); - } - } - // Load abandoned district images (land + maritime) - get_mod_art_path ("Districts/1200/Abandoned.pcx", temp_path, sizeof temp_path); - PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); - - if (pcx.JGL.Image == NULL) { - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load abandoned district images from %s", temp_path); - pop_up_in_game_error (ss); - for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) - for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) - for (int era_i = 0; era_i < 4; era_i++) { - for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { - Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; - if (sprite->vtable != NULL) - sprite->vtable->destruct (sprite, __, 0); - } - } - pcx.vtable->destruct (&pcx, __, 0); - return; - } - - Sprite_construct (&is->abandoned_district_img); - Sprite_slice_pcx (&is->abandoned_district_img, __, &pcx, 0, 0, 128, 64, 1, 1); - - Sprite_construct (&is->abandoned_maritime_district_img); - Sprite_slice_pcx (&is->abandoned_maritime_district_img, __, &pcx, 128, 0, 128, 64, 1, 1); - pcx.vtable->clear_JGL (&pcx); - - // Load wonder district images (dynamically per wonder) - if (is->current_config.enable_wonder_districts) { - char const * last_img_path = NULL; - PCX_Image wpcx; - PCX_Image_construct (&wpcx); - bool pcx_loaded = false; - - for (int wi = 0; wi < is->wonder_district_count; wi++) { - struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; - char const * img_path = cfg->img_path; - if (img_path == NULL) - img_path = "Wonders.pcx"; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - - // Load new image file if different from previous - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - - snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - PCX_Image_read_file (&wpcx, __, temp_path, NULL, 0, 0x100, 2); - - if (wpcx.JGL.Image == NULL) { - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load wonder district images from %s", temp_path); - pop_up_in_game_error (ss); - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; - - Sprite_construct (&set->img); - int x = sprite_width * cfg->img_column; - int y = sprite_height * cfg->img_row; - Sprite_slice_pcx (&set->img, __, &wpcx, x, y, sprite_width, sprite_height, 1, 1); - - Sprite_construct (&set->construct_img); - int cx = sprite_width * cfg->img_construct_column; - int cy = sprite_height * cfg->img_construct_row; - Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, sprite_width, sprite_height, 1, 1); - - if (cfg->enable_img_alt_dir) { - Sprite_construct (&set->alt_dir_img); - int ax = sprite_width * cfg->img_alt_dir_column; - int ay = sprite_height * cfg->img_alt_dir_row; - Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, sprite_width, sprite_height, 1, 1); - - Sprite_construct (&set->alt_dir_construct_img); - int acx = sprite_width * cfg->img_alt_dir_construct_column; - int acy = sprite_height * cfg->img_alt_dir_construct_row; - Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, sprite_width, sprite_height, 1, 1); - } - } - - if (pcx_loaded) - wpcx.vtable->clear_JGL (&wpcx); - wpcx.vtable->destruct (&wpcx, __, 0); - } - - if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { - char const * last_img_path = NULL; - PCX_Image nwpcx; - PCX_Image_construct (&nwpcx); - bool pcx_loaded = false; - - for (int ni = 0; ni < is->natural_wonder_count; ni++) { - struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[ni]; - if (cfg->name == NULL) - continue; - - char const * img_path = cfg->img_path; - if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - - snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); - get_mod_art_path (art_dir, temp_path, sizeof temp_path); - PCX_Image_read_file (&nwpcx, __, temp_path, NULL, 0, 0x100, 2); - - if (nwpcx.JGL.Image == NULL) { - char ss[200]; - snprintf (ss, sizeof ss, "init_district_images: failed to load natural wonder images from %s", temp_path); - pop_up_in_game_error (ss); - pcx_loaded = false; - continue; - } - - pcx_loaded = true; - last_img_path = img_path; - } - - if (! pcx_loaded) - continue; - - Sprite_construct (&is->natural_wonder_img_sets[ni].img); - int x = 128 * cfg->img_column; - int y = 88 * cfg->img_row; - Sprite_slice_pcx (&is->natural_wonder_img_sets[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); - } - - if (pcx_loaded) - nwpcx.vtable->clear_JGL (&nwpcx); - nwpcx.vtable->destruct (&nwpcx, __, 0); - } - - is->dc_img_state = IS_OK; - pcx.vtable->destruct (&pcx, __, 0); -} - -bool -tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv) -{ - Tile * center = tile_at (tile_x, tile_y); - - if ((center == NULL) || (center == p_null_tile)) return false; - int owner_id = center->Territory_OwnerID; - if (owner_id <= 0) return false; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - if (has_active_building (wai.city, i_improv)) - return true; - } - - return false; -} - -bool -wonder_requires_river (struct wonder_district_config const * cfg) -{ - unsigned int build_mask = wonder_buildable_square_type_mask (cfg); - if (build_mask == 0) - build_mask = district_default_buildable_mask (); - if ((build_mask & square_type_mask_bit (SQ_RIVER)) != 0) - return true; - if (cfg->buildable_on_rivers) - return true; - return false; -} - -Tile * -get_tile_sprite_indices (int tile_x, int tile_y, int * out_sheet_index, int * out_sprite_index) -{ - wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); - Tile * tile = tile_at (tile_x, tile_y); - - if (tile != NULL && tile != p_null_tile) { - *out_sheet_index = (tile->SquareParts >> 8) & 0xFF; - *out_sprite_index = tile->SquareParts & 0xFF; - } else { - *out_sheet_index = -1; - *out_sprite_index = -1; - } - - return tile; -} - -void -align_district_with_river (Tile * tile, int * out_pixel_x, int * out_pixel_y, enum direction * out_dir) -{ - if ((tile == NULL) || (tile == p_null_tile)) - return; - - enum direction dir = DIR_ZERO; - if (! get_primary_river_direction (tile, &dir)) - return; - - int dx, dy; - int offset = 36; - direction_to_offset (dir, &dx, &dy); - - dy = 0; - switch (dir) { - case DIR_N: dy = -offset; break; - case DIR_NE: dy = -offset/2; break; - case DIR_E: dy = 0; break; - case DIR_SE: dy = offset/2; break; - case DIR_S: dy = offset; break; - case DIR_SW: dy = offset/2; break; - case DIR_W: dy = 0; break; - case DIR_NW: dy = -offset/2; break; - default: break; - } - - if (out_pixel_x != NULL) - *out_pixel_x += dx; - if (out_pixel_y != NULL) - *out_pixel_y += dy; - if (out_dir != NULL) - *out_dir = dir; -} - -void -align_variant_and_pixel_offsets_with_coastline (Tile * tile, int * out_variant, int * out_pixel_x, int * out_pixel_y) -{ - if ((tile == NULL) || (tile == p_null_tile) || (out_variant == NULL)) - return; - - int owner_id = tile->Territory_OwnerID; - if (owner_id <= 0) - return; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return; - - int tile_x = inst->tile_x; - int tile_y = inst->tile_y; - Map * map = &p_bic_data->Map; - - City * closest_city = NULL; - int closest_dx = 0, closest_dy = 0; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - City * city = wai.city; - int ndx = city->Body.X - tile_x; - int ndy = city->Body.Y - tile_y; - - if (map->Flags & 1) { - int half_width = map->Width / 2; - if (ndx > half_width) - ndx -= map->Width; - else if (ndx < -half_width) - ndx += map->Width; - } - if (map->Flags & 2) { - int half_height = map->Height / 2; - if (ndy > half_height) - ndy -= map->Height; - else if (ndy < -half_height) - ndy += map->Height; - } - - closest_city = city; - closest_dx = ndx; - closest_dy = ndy; - break; - } - - if (closest_city == NULL) - return; - - bool city_is_directly_above_port = (closest_dx == 0) && (closest_dy == -2); - bool city_is_directly_below_port = (closest_dx == 0) && (closest_dy == 2); - bool city_is_directly_west_of_port = (closest_dx < 0) && (closest_dy == 0); - bool city_is_directly_east_of_port = (closest_dx > 0) && (closest_dy == 0); - bool city_is_directly_northeast_of_port = (closest_dx == 1) && (closest_dy == -1); - bool city_is_directly_southeast_of_port = (closest_dx == 1) && (closest_dy == 1); - bool city_is_directly_southwest_of_port = (closest_dx == -1) && (closest_dy == 1); - bool city_is_directly_northwest_of_port = (closest_dx == -1) && (closest_dy == -1); - - // Variant indices; can't use direction enum as values are slightly different - int NONE = -1; - int NW = 0; - int NE = 1; - int SE = 2; - int SW = 3; - *out_variant = NONE; - - enum direction anchor = NONE; - bool direct_diagonal = false; - - // Direct diagonals - if (city_is_directly_northeast_of_port) { *out_variant = SW; anchor = DIR_NE; direct_diagonal = true; } - else if (city_is_directly_southeast_of_port) { *out_variant = NW; anchor = DIR_SE; direct_diagonal = true; } - else if (city_is_directly_southwest_of_port) { *out_variant = NE; anchor = DIR_SW; direct_diagonal = true; } - else if (city_is_directly_northwest_of_port) { *out_variant = SE; anchor = DIR_NW; direct_diagonal = true; } - - // City either in a direct cardinal direction or not adjacent, check relative directions - else { - bool city_is_west_of_port = (closest_dx < 0); - bool city_is_east_of_port = (closest_dx > 0); - bool city_is_north_of_port = (closest_dy < 0); - bool city_is_south_of_port = (closest_dy > 0); - bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, true); - bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, true); - bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); - bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); - bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); - bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, true); - bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, true); - bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, true); - - if (city_is_directly_above_port) { - if (northwest_tile_is_land && ! tile_is_land (owner_id, tile_x + 1, tile_y + 1, true)) { - *out_variant = SE; anchor = DIR_NW; - } else if (northeast_tile_is_land && ! tile_is_land (owner_id, tile_x - 1, tile_y + 1, true)) { - *out_variant = SW; anchor = DIR_NE; - } else { - *out_variant = SW; anchor = DIR_NE; - *out_pixel_x -= 4; *out_pixel_y -= 4; - } - } else if (city_is_directly_below_port) { - if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else { - *out_variant = NE; anchor = DIR_SW; - *out_pixel_x += 4; *out_pixel_y += 4; - } - } else if (city_is_directly_west_of_port) { - if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else { - *out_variant = SE; anchor = DIR_NW; - *out_pixel_x -= 30; *out_pixel_y += 24; - } - } else if (city_is_directly_east_of_port) { - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else { - *out_variant = SW; anchor = DIR_NE; - *out_pixel_x += 30; *out_pixel_y -= 24; - } - } else if (city_is_north_of_port && city_is_west_of_port) { - if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - } else if (city_is_north_of_port && city_is_east_of_port) { - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - } else if (city_is_south_of_port && city_is_east_of_port) { - if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - } else if (city_is_south_of_port && city_is_west_of_port) { - if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - } - - // No ideal direction, pick based on any owner land tiles around port - if (*out_variant == NONE) { - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } - else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } - else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } - else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } - } - - // Same civ doesn't own any adjacent land tiles, pick based on *any* land tiles - if (*out_variant == NONE) { - bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); - bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); - bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); - bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); - bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); - bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); - bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); - bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); - if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } - else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } - else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } - else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } - else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } - else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } - else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } - else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } - else { *out_variant = SW; anchor = DIR_NE; } // Somehow no land tiles at all? Default to NE - } - } - - Tile * anchor_tile; - int anchor_sheet_index, anchor_sprite_index; - switch (anchor) { - case DIR_N: anchor_tile = get_tile_sprite_indices (tile_x, tile_y - 2, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_NE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_E: anchor_tile = get_tile_sprite_indices (tile_x + 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_SE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_S: anchor_tile = get_tile_sprite_indices (tile_x, tile_y + 2, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_SW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_W: anchor_tile = get_tile_sprite_indices (tile_x - 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; - case DIR_NW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; - default: anchor_sheet_index = -1; anchor_sprite_index = -1; break; - } - - bool anchor_is_hill = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Hills; - bool anchor_is_mountain = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Mountains; - - // Determine general pixel offsets based on direction & anchor - if (*out_variant == SW && anchor == DIR_NE) { *out_pixel_x -= 0; *out_pixel_y += 6; } - else if (*out_variant == SE && anchor == DIR_NW) { *out_pixel_x -= 2; *out_pixel_y += 6; } - else if (*out_variant == NW && anchor == DIR_SE) { *out_pixel_x -= 0; *out_pixel_y -= 2; } - else if (*out_variant == SW && anchor == DIR_N) { *out_pixel_x -= 56; *out_pixel_y -= 26; } - else if (*out_variant == SW && anchor == DIR_E) { *out_pixel_x += 36; *out_pixel_y += 18; } - else if (*out_variant == NE && anchor == DIR_S) { *out_pixel_x += 70; *out_pixel_y += 30; } - else if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 14; } - - // Handle edge cases. Tedious, but looks quite a bit better so worth it - if (! (anchor_is_hill || anchor_is_mountain) && ! direct_diagonal) { - if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 20; } - - // Sheet 0 - if (anchor_sheet_index == 0) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 32; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 32; } - - if ((*out_variant == NE || *out_variant == NW) && anchor == DIR_S && anchor_sprite_index == 26) { *out_pixel_x -= 4; *out_pixel_y += 30; } - else if (*out_variant == NE && anchor == DIR_SW && anchor_sprite_index == 20) { *out_pixel_x -= 2; *out_pixel_y += 4; } - - if (*out_variant == SW && (anchor_sprite_index == 0 || anchor_sprite_index == 4 || anchor_sprite_index == 10 || anchor_sprite_index == 1)) { *out_pixel_x +=2; *out_pixel_y -= 8; } - else if (*out_variant == SW && anchor == DIR_N && (anchor_sprite_index == 6)) { *out_pixel_x -= 6; *out_pixel_y -= 8; } - else if (*out_variant == SE && anchor == DIR_W && (anchor_sprite_index == 18)) { *out_pixel_x += 6; *out_pixel_y += 4; } - else if (*out_variant == NE && anchor == DIR_SW && (anchor_sprite_index == 51)) { *out_pixel_x += 20; *out_pixel_y -= 20; } - else if (*out_variant == SW && anchor == DIR_NE && (anchor_sprite_index == 0)) { *out_pixel_x -= 4; *out_pixel_y += 4; } - else if (*out_variant == NW && anchor == DIR_SE && (anchor_sprite_index == 44)) { *out_pixel_x -= 8; *out_pixel_y -= 12; } - } - // Sheet 1 - else if (anchor_sheet_index == 1) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 10; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 10; } - - if (*out_variant == SW && (anchor_sprite_index == 7 || anchor_sprite_index == 17 || anchor_sprite_index == 16)) { *out_pixel_x +=10; *out_pixel_y -= 8; } - } - // Sheet 3 - else if (anchor_sheet_index == 2) { - if (*out_variant == SW && (anchor_sprite_index == 6)) { *out_pixel_x +=2; *out_pixel_y -= 8; } - } - // Sheet 3 - else if (anchor_sheet_index == 3) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 16; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 16; } - - if (*out_variant == SW && (anchor_sprite_index == 43 || anchor_sprite_index == 40)) { *out_pixel_x +=6; *out_pixel_y -= 12; } - else if (*out_variant == SW && (anchor_sprite_index == 35 || anchor_sprite_index == 39)) { *out_pixel_x +=6; *out_pixel_y -= 12; } - else if (*out_variant == SE && (anchor_sprite_index == 50)) { *out_pixel_x -=6; *out_pixel_y -= 12; } - else if (*out_variant == SE && (anchor_sprite_index == 26)) { *out_pixel_x += 50; *out_pixel_y -= 2; } - } - // Sheet 4 - else if (anchor_sheet_index == 4) { - if (*out_variant == SW && (anchor_sprite_index == 71)) { *out_pixel_x +=2; *out_pixel_y -= 8; } - } - // Sheet 5 - else if (anchor_sheet_index == 5) { - if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 18; } - else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 18; } - - if ((*out_variant == SW || *out_variant == SE) && anchor_sprite_index == 18) { *out_pixel_y -= 10; } - else if (*out_variant == SW && anchor_sprite_index == 73) { *out_pixel_x -=4; *out_pixel_y -= 10; } - else if (*out_variant == NW && anchor == DIR_SE && anchor_sprite_index == 42) { *out_pixel_y -= 8; } - else if ((*out_variant == NW || *out_variant == SW) && anchor_sprite_index == 6) { *out_pixel_x += 12; *out_pixel_y -= 6; } - else if ((*out_variant == SW) && anchor_sprite_index == 16) { *out_pixel_x -=8; *out_pixel_y -= 10; } - } - } - else if (direct_diagonal && *out_variant == SW && anchor == DIR_NE) { *out_pixel_x -=8; *out_pixel_y -= 8; } - else if (direct_diagonal && *out_variant == SE && anchor == DIR_NW) { *out_pixel_x -=8; *out_pixel_y -= 8; } - else if (direct_diagonal && *out_variant == NW && anchor == DIR_SE) { *out_pixel_x +=6; *out_pixel_y += 6; } - else if (direct_diagonal && *out_variant == NE && anchor == DIR_SW) { *out_pixel_x +=6; *out_pixel_y += 6; } -} - -bool -wonder_should_use_alternative_direction_image (int tile_x, int tile_y, int owner_id, struct wonder_district_config const * cfg) -{ - if (owner_id <= 0) - return false; - - // We only care about the nearest same-civ city in the work area around the tile. - // Assumes the base wonder art (img_row/column) faces west and the alt art faces east. - // To "face away" from the nearest city, we pick the alt art when that city lies to the east. - Tile * center = is->current_render_tile; - if ((center == NULL) || (center == p_null_tile)) - return false; - - // If on a river and the wonder allows river alignment, make sure we face the river instead - bool allow_river = wonder_requires_river (cfg); - if (allow_river) { - enum direction river_dir = DIR_ZERO; - if (get_primary_river_direction (center, &river_dir)) { - int dx, dy; - - if (direction_to_offset (river_dir, &dx, &dy)) { - // I'm not completely sure of the logic here, but this seems to match the vanilla behavior - // in terms of having the wonder face the general direction of the river flow - if (dx == 2) - return false; - - return dx > 0; - } - } - } - - // Else face away from the nearest same-civ city - Map * map = &p_bic_data->Map; - int best_dist = INT_MAX; - int best_dx = 0; - int city_dx = 0; - int city_dy = 0; - - FOR_CITIES_AROUND (wai, tile_x, tile_y) { - City * city = wai.city; - if ((city == NULL) || (city->Body.CivID != owner_id)) - continue; - - int dx = city->Body.X - tile_x; - int dy = city->Body.Y - tile_y; - - if (map->Flags & 1) { - int half_width = map->Width >> 1; - if (dx > half_width) - dx -= map->Width; - else if (dx < -half_width) - dx += map->Width; - } - if (map->Flags & 2) { - int half_height = map->Height >> 1; - if (dy > half_height) - dy -= map->Height; - else if (dy < -half_height) - dy += map->Height; - } - - int dist = int_abs (dx) + int_abs (dy); - // Pick the closest city; if tied, favor the one with a clearer east/west offset so we know which way to face. - if ((dist < best_dist) || - ((dist == best_dist) && ((int_abs (dx) < int_abs (best_dx)) || (best_dx == 0)))) { - best_dist = dist; - best_dx = dx; - city_dx = city->Body.X; - city_dy = city->Body.Y; - } - } - - bool city_is_directly_above_port = city_dx == tile_x && city_dy == tile_y - 2; - bool city_is_directly_below_port = city_dx == tile_x && city_dy == tile_y + 2; - - if (city_is_directly_above_port || city_is_directly_below_port) { - bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); - bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); - bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); - - if (northeast_tile_is_land || east_tile_is_land || southeast_tile_is_land) - return true; - } - - if ((best_dist == INT_MAX) || (best_dx == 0)) - return false; - - return best_dx > 0; -} - -void -draw_district_on_map_or_canvas(Sprite * sprite, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (is->tile_info_open) { - PCX_Image * canvas = (PCX_Image *)map_renderer; - patch_Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, NULL); - return; - } - - patch_Sprite_draw_on_map (sprite, __, map_renderer, pixel_x, pixel_y, 1, 1, (p_bic_data->is_zoomed_out != false) + 1, 0); -} - -int -get_energy_grid_image_index (int tile_x, int tile_y) -{ - struct district_infos * info = &is->district_infos[ENERGY_GRID_DISTRICT_ID]; - for (int i = 0; i < info->dependent_building_count; i++) { - // Zero is "no building"; Buildings start from index one - int column_index = i + 1; - int building_id = info->dependent_building_ids[i]; - if (tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) - return column_index; - } - - return 0; -} - -int -get_bridge_image_index (Tile * tile, int tile_x, int tile_y) -{ - int SW_NE = 0; - int NW_SE = 1; - int N_S = 2; - int W_E = 3; - - if ((tile->vtable->m42_Get_Overlays (tile, __, 0) & TILE_FLAG_RAILROAD) != 0) { - SW_NE += 4; - NW_SE += 4; - N_S += 4; - W_E += 4; - } - - bool bridge_n = tile_has_district_at (tile_x, tile_y - 2, BRIDGE_DISTRICT_ID); - bool bridge_s = tile_has_district_at (tile_x, tile_y + 2, BRIDGE_DISTRICT_ID); - bool bridge_w = tile_has_district_at (tile_x - 2, tile_y, BRIDGE_DISTRICT_ID); - bool bridge_e = tile_has_district_at (tile_x + 2, tile_y, BRIDGE_DISTRICT_ID); - bool bridge_ne = tile_has_district_at (tile_x + 1, tile_y - 1, BRIDGE_DISTRICT_ID); - bool bridge_nw = tile_has_district_at (tile_x - 1, tile_y - 1, BRIDGE_DISTRICT_ID); - bool bridge_se = tile_has_district_at (tile_x + 1, tile_y + 1, BRIDGE_DISTRICT_ID); - bool bridge_sw = tile_has_district_at (tile_x - 1, tile_y + 1, BRIDGE_DISTRICT_ID); - - if (bridge_n || bridge_s || bridge_w || bridge_e || bridge_ne || bridge_nw || bridge_se || bridge_sw) { - int ns_count = (bridge_n ? 1 : 0) + (bridge_s ? 1 : 0); - int we_count = (bridge_w ? 1 : 0) + (bridge_e ? 1 : 0); - int swne_count = (bridge_sw ? 1 : 0) + (bridge_ne ? 1 : 0); - int nwse_count = (bridge_nw ? 1 : 0) + (bridge_se ? 1 : 0); - - if (swne_count == 2) return SW_NE; - if (nwse_count == 2) return NW_SE; - if (ns_count == 2) return N_S; - if (we_count == 2) return W_E; - - if (bridge_ne || bridge_sw) return SW_NE; - if (bridge_nw || bridge_se) return NW_SE; - if (bridge_n || bridge_s) return N_S; - if (bridge_w || bridge_e) return W_E; - } - - int owner_id = tile->Territory_OwnerID; - bool north_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); - bool south_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); - bool west_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); - bool east_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); - bool ne_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); - bool nw_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); - bool se_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); - bool sw_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); - - bool north_link = north_land || bridge_n; - bool south_link = south_land || bridge_s; - bool west_link = west_land || bridge_w; - bool east_link = east_land || bridge_e; - bool ne_link = ne_land || bridge_ne; - bool nw_link = nw_land || bridge_nw; - bool se_link = se_land || bridge_se; - bool sw_link = sw_land || bridge_sw; - - if (sw_link && ne_link) return SW_NE; - if (nw_link && se_link) return NW_SE; - if (north_link && south_link) return N_S; - if (west_link && east_link) return W_E; - - if (ne_link || sw_link) return SW_NE; - if (nw_link || se_link) return NW_SE; - if (north_link || south_link) return N_S; - if (west_link || east_link) return W_E; - - return SW_NE; -} - -void -get_bridge_directions (Tile * tile, int tile_x, int tile_y, int * out_dir1, int * out_dir2) -{ - int dir1 = -1; - int dir2 = -1; - int index = get_bridge_image_index (tile, tile_x, tile_y); - - switch (index) { - case 0: dir1 = DIR_SW; dir2 = DIR_NE; break; - case 1: dir1 = DIR_NW; dir2 = DIR_SE; break; - case 2: dir1 = DIR_N; dir2 = DIR_S; break; - case 3: dir1 = DIR_W; dir2 = DIR_E; break; - default: break; - } - - *out_dir1 = dir1; - *out_dir2 = dir2; -} - -void -get_canal_directions (Tile * tile, int tile_x, int tile_y, bool out_water_dirs[9], int * out_dir1, int * out_dir2) -{ - bool canal_at_n = tile_has_district_at (tile_x, tile_y - 2, CANAL_DISTRICT_ID); - bool canal_at_s = tile_has_district_at (tile_x, tile_y + 2, CANAL_DISTRICT_ID); - bool canal_at_w = tile_has_district_at (tile_x - 2, tile_y, CANAL_DISTRICT_ID); - bool canal_at_e = tile_has_district_at (tile_x + 2, tile_y, CANAL_DISTRICT_ID); - bool canal_at_ne = tile_has_district_at (tile_x + 1, tile_y - 1, CANAL_DISTRICT_ID); - bool canal_at_nw = tile_has_district_at (tile_x - 1, tile_y - 1, CANAL_DISTRICT_ID); - bool canal_at_se = tile_has_district_at (tile_x + 1, tile_y + 1, CANAL_DISTRICT_ID); - bool canal_at_sw = tile_has_district_at (tile_x - 1, tile_y + 1, CANAL_DISTRICT_ID); - bool water_n = tile_is_water (tile_x, tile_y - 2); - bool water_s = tile_is_water (tile_x, tile_y + 2); - bool water_w = tile_is_water (tile_x - 2, tile_y); - bool water_e = tile_is_water (tile_x + 2, tile_y); - bool water_ne = tile_is_water (tile_x + 1, tile_y - 1); - bool water_nw = tile_is_water (tile_x - 1, tile_y - 1); - bool water_se = tile_is_water (tile_x + 1, tile_y + 1); - bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); - bool canal_or_water_n = canal_at_n || water_n; - bool canal_or_water_s = canal_at_s || water_s; - bool canal_or_water_w = canal_at_w || water_w; - bool canal_or_water_e = canal_at_e || water_e; - bool canal_or_water_ne = canal_at_ne || water_ne; - bool canal_or_water_nw = canal_at_nw || water_nw; - bool canal_or_water_se = canal_at_se || water_se; - bool canal_or_water_sw = canal_at_sw || water_sw; - - bool canal_dirs[9] = { - false, canal_at_ne, canal_at_e, canal_at_se, - canal_at_s, canal_at_sw, canal_at_w, canal_at_nw, canal_at_n - }; - bool water_dirs[9] = { - false, water_ne, water_e, water_se, - water_s, water_sw, water_w, water_nw, water_n - }; - bool available_dirs[9] = { - false, canal_or_water_ne, canal_or_water_e, canal_or_water_se, - canal_or_water_s, canal_or_water_sw, canal_or_water_w, canal_or_water_nw, canal_or_water_n - }; - - // Avoid acute angles (adjacent directions) that look cramped. - int disallowed_pairs[][2] = { - { DIR_N, DIR_NE }, { DIR_NE, DIR_E }, { DIR_E, DIR_SE }, { DIR_SE, DIR_S }, - { DIR_S, DIR_SW }, { DIR_SW, DIR_W }, { DIR_W, DIR_NW }, { DIR_NW, DIR_N } - }; - int disallowed_pair_count = sizeof(disallowed_pairs) / sizeof(disallowed_pairs[0]); - int pref_dirs[8] = { DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_N, DIR_E, DIR_S, DIR_W }; - - int dir1 = -1; - int dir2 = -1; - - bool has_canal_dir = canal_dirs[DIR_N] || canal_dirs[DIR_NE] || canal_dirs[DIR_E] || canal_dirs[DIR_SE] || - canal_dirs[DIR_S] || canal_dirs[DIR_SW] || canal_dirs[DIR_W] || canal_dirs[DIR_NW]; - - if (has_canal_dir) { - for (int i = 0; i < 8 && dir1 == -1; i++) { - int d = pref_dirs[i]; - if (canal_dirs[d]) - dir1 = d; - } - } else { - for (int i = 0; i < 8 && dir1 == -1; i++) { - int d = pref_dirs[i]; - if (available_dirs[d]) - dir1 = d; - } - } - - if (dir1 >= 0) { - for (int pass = 0; pass < 2 && dir2 == -1; pass++) { - bool * dirs = (pass == 0) ? canal_dirs : available_dirs; - for (int i = 0; i < 8; i++) { - int d = pref_dirs[i]; - if (d == dir1 || ! dirs[d]) - continue; - bool pair_is_too_close = false; - for (int k = 0; k < disallowed_pair_count; k++) { - if ((dir1 == disallowed_pairs[k][0] && d == disallowed_pairs[k][1]) || - (dir1 == disallowed_pairs[k][1] && d == disallowed_pairs[k][0])) { - pair_is_too_close = true; - break; - } - } - if (pair_is_too_close) - continue; - dir2 = d; - break; - } - } - } - - int draw_dir1 = dir1; - int draw_dir2 = dir2; - if ((draw_dir1 >= 0) && (draw_dir2 >= 0)) { - int weight1 = 0; - int weight2 = 0; - - if (draw_dir1 == DIR_S) weight1 = 2; - else if ((draw_dir1 == DIR_SE) || (draw_dir1 == DIR_SW)) weight1 = 1; - else if ((draw_dir1 == DIR_NE) || (draw_dir1 == DIR_NW) || (draw_dir1 == DIR_N)) weight1 = -1; - - if (draw_dir2 == DIR_S) weight2 = 2; - else if ((draw_dir2 == DIR_SE) || (draw_dir2 == DIR_SW)) weight2 = 1; - else if ((draw_dir2 == DIR_NE) || (draw_dir2 == DIR_NW) || (draw_dir2 == DIR_N)) weight2 = -1; - - if (weight1 > weight2) { - int tmp = draw_dir1; - draw_dir1 = draw_dir2; - draw_dir2 = tmp; - } - } - - // Manual overrides - overall algorithm works pretty well, but handle corner cases - if (!has_canal_dir && water_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir1 = DIR_NE; draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && water_dirs[DIR_N] && water_dirs[DIR_NE]) { draw_dir1 = DIR_N; draw_dir2 = DIR_S; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_SE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_NE] && water_dirs[DIR_N]) { draw_dir1 = DIR_N; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && water_dirs[DIR_S]) { draw_dir2 = DIR_S; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && canal_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && canal_dirs[DIR_NE] && water_dirs[DIR_S]) { draw_dir2 = DIR_SW; } - if (draw_dir1 == DIR_NW && draw_dir2 == DIR_NE && canal_dirs[DIR_NW] && water_dirs[DIR_SE]) { draw_dir2 = DIR_SE; } - if (draw_dir1 == DIR_NW && draw_dir2 == DIR_S && canal_dirs[DIR_NW] && water_dirs[DIR_S]) { draw_dir2 = DIR_SE; } - - *out_dir1 = draw_dir1; - *out_dir2 = draw_dir2; - for (int i = 0; i < 9; i++) - out_water_dirs[i] = water_dirs[i]; -} - -void -draw_canal_on_map_or_canvas(Sprite * sprite, int tile_x, int tile_y, int dir, bool water_dirs[9], Map_Renderer * map_renderer, int draw_x, int draw_y) -{ - int y_offset = 9; - int x_offset = y_offset * 2; - - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y); - - // In certain cases, add an additional draw if adjacent to water so that the canal appears to extend far enough - if (dir == DIR_N && water_dirs[DIR_N]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y - y_offset); - else if (dir == DIR_NE && water_dirs[DIR_NE]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y - y_offset); - else if (dir == DIR_E && water_dirs[DIR_E]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y); - else if (dir == DIR_SE && water_dirs[DIR_SE]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y + y_offset); - else if (dir == DIR_S && water_dirs[DIR_S]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y + y_offset); - else if (dir == DIR_SW && water_dirs[DIR_SW]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y + y_offset); - else if (dir == DIR_W && water_dirs[DIR_W]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y); - else if (dir == DIR_NW && water_dirs[DIR_NW]) - draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y - y_offset); -} - -void -draw_canal_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int era) -{ - struct district_config const * cfg = &is->district_configs[CANAL_DISTRICT_ID]; - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - int offset_x = pixel_x + cfg->x_offset; - int offset_y = pixel_y + cfg->y_offset; - int dir1_draw_x = offset_x - ((sprite_width - 128) / 2); - int dir1_draw_y = offset_y - (sprite_height - 64); - int dir2_draw_x = dir1_draw_x; - int dir2_draw_y = dir1_draw_y; - - int draw_dir1 = -1; - int draw_dir2 = -1; - bool water_dirs[9] = { false, false, false, false, false, false, false, false, false }; - get_canal_directions (tile, tile_x, tile_y, water_dirs, &draw_dir1, &draw_dir2); - - // Set offsets based on directions for (literal) edge cases - if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S) { dir1_draw_x += 7; dir1_draw_y -= 2; } - else if (draw_dir1 == DIR_N && draw_dir2 == DIR_W) { dir2_draw_x -= 12; } - else if (draw_dir1 == DIR_N && draw_dir2 == DIR_SE) { dir2_draw_x += 4; } - - if (draw_dir1 >= 0) { - Sprite * sprite1 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir1]; - draw_canal_on_map_or_canvas(sprite1, tile_x, tile_y, draw_dir1, water_dirs, map_renderer, dir1_draw_x, dir1_draw_y); - } - - if (draw_dir2 >= 0) { - Sprite * sprite2 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir2]; - draw_canal_on_map_or_canvas(sprite2, tile_x, tile_y, draw_dir2, water_dirs, map_renderer, dir2_draw_x, dir2_draw_y); - } -} - -void -draw_great_wall_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - bool wall_nw = tile_has_district_at (tile_x - 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); - bool wall_ne = tile_has_district_at (tile_x + 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); - bool wall_se = tile_has_district_at (tile_x + 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); - bool wall_sw = tile_has_district_at (tile_x - 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); - bool wall_s = tile_has_district_at (tile_x, tile_y + 2, GREAT_WALL_DISTRICT_ID); - bool wall_n = tile_has_district_at (tile_x, tile_y - 2, GREAT_WALL_DISTRICT_ID); - - bool water_ne = tile_is_water (tile_x - 1, tile_y - 1); - bool water_nw = tile_is_water (tile_x + 1, tile_y - 1); - bool water_w = tile_is_water (tile_x - 2, tile_y); - bool water_n = tile_is_water (tile_x, tile_y + 2); - bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); - bool water_se = tile_is_water (tile_x + 1, tile_y + 1); - - Sprite * sprites = is->district_img_sets[GREAT_WALL_DISTRICT_ID].imgs[0][0]; - Sprite * base = &sprites[0]; - - // Rotate around clockwise NW -> SW to get the perspective right - if (wall_nw) draw_district_on_map_or_canvas(&sprites[DIR_NW], map_renderer, pixel_x, pixel_y); - if (wall_ne) draw_district_on_map_or_canvas(&sprites[DIR_NE], map_renderer, pixel_x, pixel_y); - - // Base pillar - draw_district_on_map_or_canvas(base, map_renderer, pixel_x, pixel_y); - - if (wall_sw) draw_district_on_map_or_canvas(&sprites[DIR_SW], map_renderer, pixel_x, pixel_y); - if (wall_se) draw_district_on_map_or_canvas(&sprites[DIR_SE], map_renderer, pixel_x, pixel_y); -} - -void -draw_district_generated_resource_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, - int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) -{ - int base_resource = Tile_get_resource_visible_to (tile, __, visible_to_civ_id); - int district_resource = -1; - - if (inst->state == DS_COMPLETED) { - int district_id = inst->district_id; - if ((district_id >= 0) && (district_id < is->district_count)) { - struct district_config * cfg = &is->district_configs[district_id]; - if (cfg->generated_resource_id >= 0) { - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_id >= 0) && ((visible_to_civ_id < 0) || (owner_id == visible_to_civ_id))) { - int res_id = cfg->generated_resource_id; - if (district_generates_resource_for_civ (tile, inst, cfg, owner_id)) - district_resource = res_id; - } - } - } - } - - if (district_resource < 0) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; - int offset = tile_width >> 2; - int left_x = pixel_x - (offset >> 1); - int right_x = pixel_x + (offset >> 1); - - int icon_id = p_bic_data->ResourceTypes[district_resource].IconID; - Sprite * sprite = NULL; - Map_Renderer * resource_renderer = is->tile_info_open ? &p_bic_data->Map.Renderer : map_renderer; - int resource_sprite_count = 0; - if ((resource_renderer != NULL) && (resource_renderer->Resources != NULL)) - // The renderer allocates Resources as a counted heap array: the int stored just before the - // first Sprite is the number of entries loaded from resources.pcx. - resource_sprite_count = ((int *)resource_renderer->Resources)[-1]; - if ((icon_id < 0) || (icon_id >= resource_sprite_count)) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - sprite = &resource_renderer->Resources[icon_id]; - if (sprite == NULL) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - if (base_resource >= 0) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, left_x, pixel_y); - } - - int tile_height = tile_width >> 1; - int sprite_width = sprite->Width; - int sprite_height = sprite->Height; - if (sprite_width <= 0) sprite_width = sprite->Width3; - if (sprite_height <= 0) sprite_height = sprite->Height3; - int center_x = (tile_width - sprite_width) >> 1; - int center_y = (tile_height - sprite_height) >> 1; - int draw_x = (base_resource >= 0) ? right_x : pixel_x; - draw_x += center_x; - int draw_y = pixel_y + center_y; - if (is->tile_info_open) { - PCX_Image * canvas = (PCX_Image *)map_renderer; - patch_Sprite_draw (sprite, __, canvas, draw_x, draw_y, NULL); - } else { - int draw_scale = (p_bic_data->is_zoomed_out != false) + 1; - patch_Sprite_draw_on_map (sprite, __, map_renderer, draw_x, draw_y, 1, 1, draw_scale, 0); - } -} - -int -count_completed_buildings_in_district_radius (int tile_x, int tile_y, int district_id) -{ - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos * district_info = &is->district_infos[district_id]; - int completed_count = 0; - for (int i = 0; i < district_info->dependent_building_count; i++) { - int building_id = district_info->dependent_building_ids[i]; - if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) - completed_count++; - } - return completed_count; -} - -void -draw_district_on_map_or_canvas_by_buildings (Sprite * base_sprite, Map_Renderer * map_renderer, int district_id, int variant, int era, int tile_x, int tile_y, int draw_x, int draw_y) -{ - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos * district_info = &is->district_infos[district_id]; - - draw_district_on_map_or_canvas(base_sprite, map_renderer, draw_x, draw_y); - - for (int i = 0; i < district_info->dependent_building_count; i++) { - // Zero is "base texture"; Actual building column art starts from index one - int column_index = i + 1; - int building_id = district_info->dependent_building_ids[i]; - if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) { - Sprite * district_sprite = &is->district_img_sets[district_id].imgs[variant][era][column_index]; - draw_district_on_map_or_canvas(district_sprite, map_renderer, draw_x, draw_y); - } - } -} - -void -draw_district_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) -{ - int district_id = inst->district_id; - if (is->dc_img_state == IS_UNINITED) - init_district_images (); - - if (is->dc_img_state != IS_OK) - return; - - // Natural Wonder - if (district_id == NATURAL_WONDER_DISTRICT_ID) { - if (! is->current_config.enable_natural_wonders) - return; - - int natural_id = inst->natural_wonder_info.natural_wonder_id; - if ((natural_id >= 0) && (natural_id < is->natural_wonder_count)) { - Sprite * nsprite = &is->natural_wonder_img_sets[natural_id].img; - int y_offset = 88 - 64; // Height of wonder img minus height of tile - int draw_y = pixel_y - y_offset; - - draw_district_on_map_or_canvas(nsprite, map_renderer, pixel_x, draw_y); - } - return; - } - - // Districts - if (is->current_config.enable_districts) { - if (district_id < 0 || district_id >= is->district_count) return; - bool completed = district_is_complete (tile, district_id); - - if (! completed) - return; - - struct district_config const * cfg = &is->district_configs[district_id]; - struct district_infos * district_info = &is->district_infos[district_id]; - int territory_owner_id = tile->Territory_OwnerID; - int variant = 0; - int era = 0; - int culture = 0; - int buildings = 0; - int draw_pixel_x = pixel_x; - int draw_pixel_y = pixel_y; - enum direction river_dir = DIR_ZERO; - - // If in a territory, use owner's culture/era - if (territory_owner_id > 0) { - Leader * leader = &leaders[territory_owner_id]; - culture = p_bic_data->Races[leader->RaceID].CultureGroupID; - if (cfg->vary_img_by_culture) - variant = culture; - if (cfg->vary_img_by_era) - era = leader->Era; - if (cfg->align_to_coast) - align_variant_and_pixel_offsets_with_coastline (tile, &variant, &draw_pixel_x, &draw_pixel_y); - - // Else render abandoned if not a Wonder, Natural Wonder, Bridge, or Canal - } else if (district_id != WONDER_DISTRICT_ID && district_id != NATURAL_WONDER_DISTRICT_ID && district_id != BRIDGE_DISTRICT_ID && district_id != CANAL_DISTRICT_ID) { - Sprite * abandoned_sprite = &is->abandoned_district_img; - if (tile->vtable->m35_Check_Is_Water (tile) && is->abandoned_maritime_district_img.vtable != NULL) - abandoned_sprite = &is->abandoned_maritime_district_img; - if (abandoned_sprite->vtable != NULL) { - draw_district_on_map_or_canvas(abandoned_sprite, map_renderer, draw_pixel_x + cfg->x_offset, draw_pixel_y + cfg->y_offset); - } - return; - } - - // If out of a territory (and not abandoned) but builder is known, use builder's era & culture - if (territory_owner_id < 0 && inst->built_by_civ_id >= 0) { - Leader * builder = &leaders[inst->built_by_civ_id]; - culture = p_bic_data->Races[builder->RaceID].CultureGroupID; - if (cfg->vary_img_by_culture) - variant = culture; - if (cfg->vary_img_by_era) - era = builder->Era; - } - - int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; - int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; - int offset_x = draw_pixel_x + cfg->x_offset; - int offset_y = draw_pixel_y + cfg->y_offset; - int draw_x = offset_x - ((sprite_width - 128) / 2); - int draw_y = offset_y - (sprite_height - 64); - Sprite (*sprites)[MAX_DISTRICT_ERA_COUNT][MAX_DISTRICT_COLUMN_COUNT] = is->district_img_sets[district_id].imgs; - - // Render - switch (district_id) { - case WONDER_DISTRICT_ID: - { - if (! is->current_config.enable_wonder_districts) - return; - - struct wonder_district_info * info = get_wonder_district_info (tile); - if (info == NULL) - return; - - int construct_windex = -1; - Sprite * wsprite = NULL; - - struct wonder_district_config * wcfg = NULL; - struct wonder_district_image_set * set = NULL; - - // Completed - if (info->state == WDS_COMPLETED) { - int windex = info->wonder_index; - if ((windex < 0) || (windex >= is->wonder_district_count)) - return; - wcfg = &is->wonder_district_configs[windex]; - set = &is->wonder_district_img_sets[windex]; - // Under construction - } else if (wonder_district_tile_under_construction (tile, tile_x, tile_y, &construct_windex) && (construct_windex >= 0)) { - if (construct_windex >= is->wonder_district_count) - return; - wcfg = &is->wonder_district_configs[construct_windex]; - set = &is->wonder_district_img_sets[construct_windex]; - // Unused - } else { - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - - if (wonder_requires_river(wcfg)) - align_district_with_river (tile, &draw_pixel_x, &draw_pixel_y, &river_dir); - - int wonder_width = (wcfg->custom_width > 0) ? wcfg->custom_width : 128; - int wonder_height = (wcfg->custom_height > 0) ? wcfg->custom_height : 64; - int wonder_offset_x = draw_pixel_x + cfg->x_offset; - int wonder_offset_y = draw_pixel_y + cfg->y_offset; - int wonder_draw_x = wonder_offset_x - ((wonder_width - 128) / 2); - int wonder_draw_y = wonder_offset_y - (wonder_height - 64); - - bool use_alt_dir = wcfg->enable_img_alt_dir && wonder_should_use_alternative_direction_image (tile_x, tile_y, territory_owner_id, wcfg); - if (info->state == WDS_COMPLETED) - wsprite = (use_alt_dir && (set->alt_dir_img.vtable != NULL)) ? &set->alt_dir_img : &set->img; - else - wsprite = (use_alt_dir && (set->alt_dir_construct_img.vtable != NULL)) ? &set->alt_dir_construct_img : &set->construct_img; - - draw_district_on_map_or_canvas(wsprite, map_renderer, wonder_draw_x, wonder_draw_y); - return; - } - case NEIGHBORHOOD_DISTRICT_ID: - { - if (! is->current_config.enable_neighborhood_districts) - return; - - unsigned v = (unsigned)tile_x * 0x9E3779B1u + (unsigned)tile_y * 0x85EBCA6Bu; - v ^= v >> 16; - v *= 0x7FEB352Du; - v ^= v >> 15; - v *= 0x846CA68Bu; - v ^= v >> 16; - buildings = clamp(0, 3, (int)(v & 3u)); /* final 0..3 */ - variant = culture; - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - case DISTRIBUTION_HUB_DISTRICT_ID: - if (! is->current_config.enable_distribution_hub_districts) - return; - - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - case ENERGY_GRID_DISTRICT_ID: - { - if (! is->current_config.enable_energy_grid_districts) - return; - - buildings = get_energy_grid_image_index (tile_x, tile_y); - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - case BRIDGE_DISTRICT_ID: - { - if (! is->current_config.enable_bridge_districts) - return; - - buildings = get_bridge_image_index (tile, tile_x, tile_y); - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - case CANAL_DISTRICT_ID: - { - if (! is->current_config.enable_canal_districts) - return; - - draw_canal_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y, era); - return; - } - case GREAT_WALL_DISTRICT_ID: - { - if (! is->current_config.enable_great_wall_districts) - return; - - draw_great_wall_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - default: - { - // Draw by counting number of completed buildings in radius - if (cfg->render_strategy == DRS_BY_COUNT) { - buildings = count_completed_buildings_in_district_radius (tile_x, tile_y, district_id); - draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); - return; - } - // Draw by checking each building individually and layering images - else if (cfg->render_strategy == DRS_BY_BUILDING) { - Sprite * base_sprite = &is->district_img_sets[district_id].imgs[variant][era][0]; - draw_district_on_map_or_canvas_by_buildings(base_sprite, map_renderer, district_id, variant, era, tile_x, tile_y, draw_x, draw_y); - return; - } - } - } - } - - Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); -} - -void __fastcall -patch_Map_Renderer_m12_Draw_Tile_Buildings(Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { - Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - Tile * tile = is->current_render_tile; - if (is->tile_info_open) - tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if ((tile == NULL) || (tile == p_null_tile)) - return; - - struct district_instance * inst = is->current_render_tile_district; - if (is->tile_info_open) - inst = get_district_instance (tile); - if (inst == NULL) { - Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - // Draw resources first if needed - if (is->district_configs[inst->district_id].draw_over_resources) - draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); - - draw_district_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); -} - -void __fastcall -patch_Map_Renderer_m09_Draw_Tile_Resources (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) -{ - if (! is->current_config.enable_districts) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - Tile * tile = is->current_render_tile; - if (is->tile_info_open) - tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); - if ((tile == NULL) || (tile == p_null_tile)) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - struct district_instance * inst = is->current_render_tile_district; - if (is->tile_info_open) - inst = get_district_instance (tile); - if (inst == NULL) { - Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); - return; - } - - // Resources that should be drawn below district are already drawn, skip in that case - if (is->district_configs[inst->district_id].draw_over_resources) - return; - - draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); -} - -void __fastcall -patch_Map_Renderer_m11_Draw_Tile_Irrigation (Map_Renderer *this, int edx, int visible_to_civ, int tile_x, int tile_y, int param_4, int param_5, int param_6) -{ - if (! is->current_config.enable_districts) { - Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); - return; - } - - struct district_instance * inst = is->current_render_tile_district; - if (inst == NULL) { - Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); - return; - } - - // If it has a completed district that serves as pseudo-irrigation source, suppress drawing irrigation - if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (is->current_render_tile, inst->district_id)) - return; - - Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); -} - -bool __fastcall -patch_Tile_has_city_or_district (Tile * this) -{ - bool has_city = Tile_has_city (this); - if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { - return has_city || (get_district_instance (this) != NULL); - } - return has_city; -} - -int __fastcall -patch_Tile_check_water_for_navigator_cell_coloring (Tile * this) -{ - if (! is->current_config.show_territory_colors_on_water_tiles_in_minimap) - return this->vtable->m35_Check_Is_Water (this); - else - return 0; -} - -bool -is_skippable_popup (char * text_key) -{ - char * skippable_keys[] = {"SUMMARY_END_GOLDEN_AGE", "SUMMARY_END_SCIENCE_AGE", "SUMMARY_NEW_SMALL_WONDER", // unimportant domestic things - "WONDERPRODUCE", // another civ completed a wonder - "MAKEPEACE", "MUTUALPROTECTIONPACT", "MILITARYALLIANCE", "SUMMARY_DECLARE_WAR", // diplo events not involving the player - "TRADEEMBARGOENDS", // embargo vs player ends - "SUMMARY_CIV_DESTROYED_BY_CIV", "SUMMARY_CIV_DESTROYED", // foreign civs destroyed not by player - "LOSTGOOD", // 'We lost our supply of ...!' - "TRADEEMBARGO", "MILITARYALLIANCEWARONUS", "MILITARYALLIANCEAGAINSTUS", // trade embargo or alliance vs player - "SUMMARY_TRAVELERS_REPORT"}; // another civs starts a wonder - - for (int n = 0; n < ARRAY_LEN (skippable_keys); n++) - if (strcmp (text_key, skippable_keys[n]) == 0) - return true; - return false; -} - -int __fastcall -patch_PopupForm_impl_begin_showing_popup (PopupForm * this) -{ - if (is_online_game () || - (! is->current_config.convert_some_popups_into_online_mp_messages) || - (! is_skippable_popup (this->text_key))) - return PopupForm_impl_begin_showing_popup (this); - - else { - unsigned saved_prefs = *p_preferences; - int saved_flags = this->field_1BF0[0xE4]; - - *p_preferences |= P_SHOW_FEWER_MP_POPUPS; - this->field_1BF0[0xE4] |= 0x4000; - int tr = PopupForm_impl_begin_showing_popup (this); - - *(bool *)(p_main_screen_form->animator.field_18E4 + 10) = true; // Set what must be a dirty flag - Animator_update (&p_main_screen_form->animator); // Make sure message appears - - this->field_1BF0[0xE4] = saved_flags; - *p_preferences = saved_prefs; - - return tr; - } -} - -bool __stdcall -patch_is_online_game_for_show_popup () -{ - return is->current_config.convert_some_popups_into_online_mp_messages ? true : is_online_game (); -} - -bool -ai_move_district_worker (Unit * worker, struct district_worker_record * rec) -{ - if ((worker == NULL) || (rec == NULL)) - return false; - - char ss[200]; - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d assigned to build district\n", worker->Body.ID); - (*p_OutputDebugStringA) (ss); - - // Check the original request city made for district - struct pending_district_request * req = rec->pending_req; - if ((req == NULL) || - (req->assigned_worker_id != worker->Body.ID) || - (req->target_x < 0) || (req->target_y < 0)) - return false; - - int district_id = req->district_id; - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d moving to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); - (*p_OutputDebugStringA) (ss); - - City * request_city = get_city_ptr (req->city_id); - if (request_city == NULL) { - clear_tracked_worker_assignment (rec); - remove_pending_district_request (req); - return false; - } - req->city = request_city; - struct district_config * cfg = &is->district_configs[district_id]; - Tile * target_tile = tile_at (req->target_x, req->target_y); - if ((target_tile == NULL) || (target_tile == p_null_tile) || - (target_tile->vtable->m38_Get_Territory_OwnerID (target_tile) != worker->Body.CivID) || - (! city_radius_contains_tile (request_city, req->target_x, req->target_y))) { - clear_city_district_request (request_city, req->district_id); - return false; - } - - // If the worker has arrived - if ((worker->Body.X == req->target_x) && (worker->Body.Y == req->target_y)) { - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d arrived at (%d,%d) to build district\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - Tile * tile = tile_at (worker->Body.X, worker->Body.Y); - struct district_instance * inst = get_district_instance (tile); - bool do_replacement = false; - - // If there is a completed district here already - if ((inst != NULL) && district_is_complete (tile, inst->district_id)) { - int existing_district_id = inst->district_id; - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d found existing district ID %d at (%d,%d)\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - if (existing_district_id == req->district_id) { - clear_city_district_request (request_city, req->district_id); - clear_tracked_worker_assignment (rec); - return false; - } - - // Allow replacement of unused wonder districts - if (existing_district_id == WONDER_DISTRICT_ID) { - struct wonder_district_info * info = &inst->wonder_info; - if (info->state == WDS_UNUSED) - do_replacement = true; - } else if (district_is_obsolete_for_civ (existing_district_id, request_city->Body.CivID)) { - do_replacement = true; - } else { - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d cannot replace existing district ID %d at (%d,%d), cancelling request\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - clear_city_district_request (request_city, req->district_id); - return false; - } - - if (!do_replacement) { - return false; // Nothing left to do here - } - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for duplicate districts near city at (%d,%d)\n", request_city->Body.X, request_city->Body.Y); - (*p_OutputDebugStringA) (ss); - - // One final check: do we still need the district? Check for any dupes nearby - if (req->district_id != DISTRIBUTION_HUB_DISTRICT_ID && req->district_id != NEIGHBORHOOD_DISTRICT_ID) { - FOR_DISTRICTS_AROUND (wai, request_city->Body.X, request_city->Body.Y, false) { - if (wai.tile == tile) - continue; - - if (wai.district_inst->district_id == req->district_id) { - snprintf (ss, sizeof ss, "ai_move_district_worker: Found duplicate district ID %d near city at (%d,%d), cancelling request\n", req->district_id, request_city->Body.X, request_city->Body.Y); - (*p_OutputDebugStringA) (ss); - clear_city_district_request (request_city, req->district_id); - return false; - } - } - } - - // Need to make sure distro hubs get roads. If this will be one, build the road first to be sure - if (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID) { - bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); - if (! has_road && ! cfg->auto_add_road) { - Unit_set_state(worker, __, UnitState_Build_Road); - worker->Body.Job_ID = WJ_Build_Road; - return true; - } - } - - enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); - bool district_buildable_here = district_is_buildable_on_tile (&is->district_configs[req->district_id], tile); - - // Remove any existing improvements - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); - if (do_replacement) { - remove_district_instance (tile); - handle_district_removed (tile, req->district_id, worker->Body.X, worker->Body.Y, false); - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for craters or pollution at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - if (tile->vtable->m21_Check_Crates (tile, __, 0) || tile->vtable->m20_Check_Pollution (tile, __, 0)) { - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d clearing craters or pollution at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - Unit_set_state(worker, __, UnitState_Clear_Damage); - worker->Body.Job_ID = WJ_Clean_Pollution; - return true; - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for forest or wetlands at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - // Clear any forest/wetlands - if (! district_buildable_here && base_type == SQ_Forest) { - Unit_set_state(worker, __, UnitState_Clear_Forest); - worker->Body.Job_ID = WJ_Clean_Forest; - return true; - } else if (! district_buildable_here && ((base_type == SQ_Jungle) || (base_type == SQ_Swamp))) { - Unit_set_state(worker, __, UnitState_Clear_Wetlands); - worker->Body.Job_ID = WJ_Clear_Swamp; - return true; - } - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d starting construction of district at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); - (*p_OutputDebugStringA) (ss); - - // Clear any existing improvements (irrigation and mines) - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); - - // Start construction of district - inst = ensure_district_instance (tile, req->district_id, req->target_x, req->target_y); - inst->built_by_civ_id = worker->Body.CivID; - Unit_set_state(worker, __, UnitState_Build_Mines); - worker->Body.Job_ID = WJ_Build_Mines; // Build district - return true; - - // Else if the worker needs to be sent - } else { - if ((worker->Body.UnitState != UnitState_Go_To) || - (worker->Body.path_dest_x != req->target_x) || - (worker->Body.path_dest_y != req->target_y)) { - int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, - worker->Body.X, worker->Body.Y, req->target_x, req->target_y, - worker, worker->Body.CivID, 0x41, NULL); - if (path_result > 0) { - - snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d path set to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); - (*p_OutputDebugStringA) (ss); - - Unit_set_escortee (worker, __, -1); - Unit_set_state (worker, __, UnitState_Go_To); - worker->Body.path_dest_x = req->target_x; - worker->Body.path_dest_y = req->target_y; - } else { - clear_tracked_worker_assignment (rec); - return false; - } - } - } - return false; -} - -bool -ai_worker_try_tile_improvement_district (Unit * worker) -{ - if (! is->current_config.enable_districts || worker == NULL) return false; - if (! is_worker (worker)) return false; - if (worker->Body.Auto_CityID < 0) return false; - - City * city = get_city_ptr (worker->Body.Auto_CityID); - if (city == NULL) return false; - if (city->Body.CivID != worker->Body.CivID) return false; - - int civ_id = worker->Body.CivID; - int tile_x = worker->Body.X; - int tile_y = worker->Body.Y; - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (tile->CityID >= 0) return false; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; - if (! city_radius_contains_tile (city, tile_x, tile_y)) return false; - if (get_district_instance (tile) != NULL) return false; - - // Evaluate whether the best improvement here is irrigation, mines, or a district, using heuristics based on city needs - int food_weight = (city->Body.FoodIncome < city->Body.FoodRequired) ? 3 : 1; - int shield_weight = (city->Body.ProductionIncome < city->Body.Population.Size) ? 2 : 1; - int unhappy_percent = - city->Body.UnhappyNoReasonPercent + - city->Body.UnhappyCrowdedPercent + - city->Body.UnhappyWarWearinessPercent + - city->Body.UnhappyAgresssionPercent + - city->Body.UnhappyPropagandaPercent + - city->Body.UnhappyDraftPercent + - city->Body.UnhappyOppressionPercent + - city->Body.UnhappyThisCityImprovementsPercent + - city->Body.UnhappyOtherCityImprovementsPercent; - int happiness_weight = (unhappy_percent > 0) ? 2 : 1; - int gold_weight = 1; - int resource_boost = 5 * (food_weight + shield_weight + gold_weight + happiness_weight); - - int irrigation_score = INT_MIN; - if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Irrigate, tile_x, tile_y, 0) && - ! tile->vtable->m17_Check_Irrigation (tile, __, 0)) { - int base_type = tile->vtable->m50_Get_Square_BaseType (tile); - int bonus = p_bic_data->TileTypes[base_type].IrrigationBonus; - if (bonus < 0) - bonus = 0; - irrigation_score = bonus * food_weight; - } - - int mine_score = INT_MIN; - if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Build_Mines, tile_x, tile_y, 0) && - ! tile->vtable->m18_Check_Mines (tile, __, 0)) { - int base_type = tile->vtable->m50_Get_Square_BaseType (tile); - int bonus = p_bic_data->TileTypes[base_type].MiningBonus; - if (bonus < 0) - bonus = 0; - mine_score = bonus * shield_weight; - } - - int best_score = INT_MIN; - int best_district_id = -1; - for (int i = 0; i < is->district_count; i++) { - struct district_config const * cfg = &is->district_configs[i]; - if (cfg->ai_build_strategy != DABS_TILE_IMPROVEMENT) - continue; - if (! can_build_district_on_tile (tile, i, civ_id)) - continue; - - struct district_instance temp = {0}; - temp.district_id = i; - temp.tile_x = (short)tile_x; - temp.tile_y = (short)tile_y; - - int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; - get_effective_district_yields (&temp, cfg, &food, &shields, &gold, &science, &culture, &happiness); - - int score = food * food_weight + shields * shield_weight + gold * gold_weight; - score += (science + culture) / 2; - score += happiness * happiness_weight; - if ((cfg->generated_resource_id >= 0) && - ! patch_City_has_resource (city, __, cfg->generated_resource_id)) - score += resource_boost; - - if (score > best_score) { - best_score = score; - best_district_id = i; - } - } - - if ((best_district_id >= 0) && - (best_score >= irrigation_score) && - (best_score >= mine_score)) { - unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); - unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); - tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); - if (removable_flags != 0) - tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); - ensure_district_instance (tile, best_district_id, tile_x, tile_y); - Unit_set_state (worker, __, UnitState_Build_Mines); - worker->Body.Job_ID = WJ_Build_Mines; - return true; - } - - return false; -} - -void __fastcall -patch_Unit_ai_move_terraformer (Unit * this) -{ - Map * map = &p_bic_data->Map; - int type_id = this->Body.UnitTypeID; - int civ_id = this->Body.CivID; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - int territory_owner = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m38_Get_Territory_OwnerID (tile) : -1; - - - if (is->current_config.enable_districts && ! is_human && is_worker (this)) { - update_tracked_worker_for_unit (this); - struct district_instance * inst = get_district_instance (tile); - - if ((territory_owner == civ_id) && - inst != NULL && inst->district_id != NATURAL_WONDER_DISTRICT_ID && - tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Coast) { - // Roads should be made after district builds. The district is complete but - // worker is still likely on the tile, so check here and build road if needed - struct district_config * cfg = &is->district_configs[inst->district_id]; - bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); - if (! has_road && ! cfg->auto_add_road) { - Unit_set_state(this, __, UnitState_Build_Road); - this->Body.Job_ID = WJ_Build_Road; - return; - } - - // Same check for railroads - bool can_build_railroad = Leader_can_do_worker_job (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y, 0); - bool has_railroad = (*tile->vtable->m23_Check_Railroads)(tile, __, 0); - if (can_build_railroad && !has_railroad && ! cfg->auto_add_railroad) { - Unit_set_state(this, __, UnitState_Build_Railroad); - this->Body.Job_ID = WJ_Build_Railroad; - return; - } - } - - struct district_worker_record * rec = get_tracked_worker_record (this); - if (rec != NULL && rec->pending_req != NULL) { - if (ai_move_district_worker (this, rec)) - return; - } - - if ((this->Body.Auto_CityID >= 0) && ai_worker_try_tile_improvement_district (this)) - return; - } - - bool pop_else_caravan; - if ((tile != NULL) && (tile != p_null_tile) && - (type_id >= 0) && (type_id < p_bic_data->UnitTypeCount) && - is_material_unit (&p_bic_data->UnitTypes[type_id], &pop_else_caravan) && - ((pop_else_caravan && is->current_config.enable_pop_unit_ai) || - ((! pop_else_caravan) && is->current_config.enable_caravan_unit_ai))) { - ai_move_material_unit (this); - return; - } - - Unit_ai_move_terraformer (this); -} - -bool __fastcall -patch_Unit_ai_can_sacrifice (Unit * this, int edx, bool requires_city) -{ - int sacrifice_action = UCV_Sacrifice & 0x0FFFFFFF; // Mask out top four category bits - UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; - if (is->current_config.patch_ai_can_sacrifice_without_special_ability && ((type->Special_Actions & sacrifice_action) == 0)) - return false; - else - return Unit_ai_can_sacrifice (this, __, requires_city); -} - -int __cdecl -patch_get_building_defense_bonus_at (int x, int y, int param_3) -{ - // Get base building defense bonus first - int base = get_building_defense_bonus_at (x, y, param_3); - - // If districts are disabled, return base - if (!is->current_config.enable_districts) - return base; - - Tile * tile = tile_at (x, y); - if ((tile == NULL) || (tile == p_null_tile)) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL) { - struct district_config const * cfg = &is->district_configs[inst->district_id]; - int bonus = cfg->defense_bonus_percent; - bonus += apply_district_bonus_entries (inst, &cfg->defense_bonus_extras, inst->district_id); - return bonus; - } - - return base; -} - -void __fastcall -patch_Unit_select (Unit * this) -{ - if (is->current_config.enable_districts) { - Tile * tile = tile_at (this->Body.X, this->Body.Y); - - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && is_worker(this) && inst->district_id >= 0 && inst->district_id <= is->district_count && - ! district_is_complete (tile, inst->district_id)) { - int district_id = inst->district_id; - PopupForm * popup = get_popup_form (); - int remaining_turns = get_worker_remaining_turns_to_complete (this, __, 0); - set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); - set_popup_int_param (1, remaining_turns); - popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_CANCEL_BUILD_DISTRICT", -1, 0, 0, 0); - - int sel = patch_show_popup (popup, __, 0, 0); - if (sel == 0) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, 0); - - bool other_workers_present = false; - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit != NULL) && (unit != this) && - (unit->Body.UnitState == UnitState_Build_Mines) && - (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { - other_workers_present = true; - break; - } - } - if (! other_workers_present) { - remove_district_instance (tile); - } - } else { - return; - } - } - } - - // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here - if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { - is->highlight_city_radii = false; - clear_highlighted_worker_tiles_and_redraw (); - } - - Unit_select (this); -} - -void __fastcall -patch_City_Form_draw_food_income_icons (City_Form * this) -{ - // Call original function first - City_Form_draw_food_income_icons (this); - - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) - return; - - // Get current city - City * city = this->CurrentCity; - if (city == NULL) - return; - - // Calculate standard district food bonus - int standard_district_food = 0; - FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { - int district_id = wai.district_inst->district_id; - int food_bonus = 0; - get_effective_district_yields (wai.district_inst, &is->district_configs[district_id], &food_bonus, NULL, NULL, NULL, NULL, NULL); - standard_district_food += food_bonus; - } - - // Get distribution hub food bonus - int distribution_hub_food = 0; - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) - get_distribution_hub_yields_for_city (city, &distribution_hub_food, NULL); - - // Total district food - int total_district_food = standard_district_food + distribution_hub_food; - if (total_district_food <= 0) - return; - - // Lazy load icons - if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { - if (is->distribution_hub_icons_img_state == IS_UNINITED) - init_distribution_hub_icons (); - if (is->distribution_hub_icons_img_state != IS_OK) - return; - } - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - if (is->dc_icons_img_state != IS_OK) - return; - - int food_income = city->Body.FoodIncome; - int food_required = city->Body.FoodRequired; - - // Calculate how standard district food icons are distributed - int standard_food_eaten = 0; - int standard_food_surplus = 0; - if (standard_district_food > 0) { - if (standard_district_food >= food_income) { - standard_food_surplus = food_income; - standard_food_eaten = standard_district_food - food_income; - } else { - standard_food_surplus = standard_district_food; - standard_food_eaten = 0; - } - } - - // Calculate how distribution hub food icons are distributed - int hub_food_eaten = 0; - int hub_food_surplus = 0; - int remaining_income = food_income - standard_food_surplus; - if (distribution_hub_food > 0) { - if (distribution_hub_food >= remaining_income) { - hub_food_surplus = remaining_income; - hub_food_eaten = distribution_hub_food - remaining_income; - } else { - hub_food_surplus = distribution_hub_food; - hub_food_eaten = 0; - } - } - - // Draw eaten district food icons (left side, from right to left) - int total_eaten = standard_food_eaten + hub_food_eaten; - if (total_eaten > 0) { - Sprite * base_eaten_sprite = &(this->City_Icons_Images).Icon_07; - int eaten_sprite_width = base_eaten_sprite->Width; - int eaten_sprite_height = base_eaten_sprite->Height; - struct tagRECT * eaten_rect = &this->Food_Consumption_Rect; - int eaten_rect_width = eaten_rect->right - eaten_rect->left; - - int eaten_spacing = eaten_sprite_width; - if ((food_required > 1) && (food_required * eaten_sprite_width - eaten_rect_width != 0) && - (eaten_rect_width <= food_required * eaten_sprite_width)) { - eaten_spacing = (eaten_rect_width - eaten_sprite_width) / (food_required - 1); - if (eaten_spacing < 1) - eaten_spacing = 1; - else if (eaten_spacing > eaten_sprite_width) - eaten_spacing = eaten_sprite_width; - } - - int eaten_x_offset = eaten_spacing * (food_required - 1); - // Draw standard district eaten first - for (int i = 0; i < standard_food_eaten && i < food_required; i++) { - int x = eaten_rect->left + eaten_x_offset; - int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - - (eaten_sprite_height >> 1)); - Sprite_draw (&is->district_food_eaten_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - eaten_x_offset -= eaten_spacing; - } - // Draw distribution hub eaten - for (int i = 0; i < hub_food_eaten && eaten_x_offset >= 0; i++) { - int x = eaten_rect->left + eaten_x_offset; - int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - - (eaten_sprite_height >> 1)); - Sprite_draw (&is->distribution_hub_eaten_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - eaten_x_offset -= eaten_spacing; - } - } - - // Draw surplus district food icons (right side, from right to left) - int total_surplus = standard_food_surplus + hub_food_surplus; - if (total_surplus > 0) { - Sprite * base_surplus_sprite = &(this->City_Icons_Images).Icon_06; - int surplus_sprite_width = base_surplus_sprite->Width; - int surplus_sprite_height = base_surplus_sprite->Height; - struct tagRECT * surplus_rect = &this->Food_Storage_Rect; - int surplus_rect_width = surplus_rect->right - surplus_rect->left; - - int surplus_spacing = surplus_sprite_width; - if ((food_income > 1) && (food_income * surplus_sprite_width - surplus_rect_width != 0) && - (surplus_rect_width <= food_income * surplus_sprite_width)) { - surplus_spacing = (surplus_rect_width - surplus_sprite_width) / (food_income - 1); - if (surplus_spacing < 1) - surplus_spacing = 1; - else if (surplus_spacing > surplus_sprite_width) - surplus_spacing = surplus_sprite_width; - } - - int surplus_x_offset = 0; - // Draw standard district surplus first - for (int i = 0; i < standard_food_surplus && i < food_income; i++) { - int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; - int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - - (surplus_sprite_height >> 1)) - 1; - Sprite_draw (&is->district_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - surplus_x_offset += surplus_spacing; - } - // Draw distribution hub surplus - for (int i = 0; i < hub_food_surplus && surplus_x_offset < surplus_rect_width; i++) { - int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; - int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - - (surplus_sprite_height >> 1)) - 1; - Sprite_draw (&is->distribution_hub_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); - surplus_x_offset += surplus_spacing; - } - } -} - -void -recompute_district_and_distribution_hub_shields_for_city_view (City * city) -{ - if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) - return; - - int city_id = city->Body.ID; - int city_x = city->Body.X; - int city_y = city->Body.Y; - - // District yields are injected through the city center tile in patch_City_calc_tile_yield_while_gathering. - // Grab the base yield (no districts) directly from the original function, then compute the - // district bonus that calculate_city_center_district_bonus will layer on afterward. - int city_center_base_shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, city_x, city_y); - int total_district_shield_bonus = 0; - calculate_city_center_district_bonus (city, NULL, &total_district_shield_bonus, NULL); - - // Distribution hub contribution is tracked separately for icon rendering. - int distribution_hub_shields = 0; - if (is->current_config.enable_distribution_hub_districts) - get_distribution_hub_yields_for_city (city, NULL, &distribution_hub_shields); - if (distribution_hub_shields < 0) - distribution_hub_shields = 0; - if (distribution_hub_shields > total_district_shield_bonus) - distribution_hub_shields = total_district_shield_bonus; - - int standard_district_shields = total_district_shield_bonus - distribution_hub_shields; - if (standard_district_shields < 0) - standard_district_shields = 0; - - // Recompute yields with districts active so ProductionIncome/Loss reflect the city view. - recompute_city_yields_with_districts (city); - int total_production_income = city->Body.ProductionIncome; - int total_production_loss = city->Body.ProductionLoss; - int total_net_shields = total_production_income + total_production_loss; // ProductionLoss stored as negative - - // Remove the district bonus from the gross tile production and recompute corruption on that base value. - int city_center_with_districts = city_center_base_shields + total_district_shield_bonus; - int gross_without_specials = city->Body.Tiles_Production - (city_center_with_districts - city_center_base_shields); - if (gross_without_specials < 0) - gross_without_specials = 0; - - int base_corruption_abs = patch_City_compute_corrupted_yield (city, __, gross_without_specials, true); - if (base_corruption_abs < 0) - base_corruption_abs = 0; - int base_production_loss = -base_corruption_abs; - - // Corruption becomes more negative as it increases. - int additional_corruption = total_production_loss - base_production_loss; - - int district_shields_remaining = standard_district_shields; - int hub_shields_remaining = distribution_hub_shields; - - if (additional_corruption < 0) { - int extra_loss = -additional_corruption; - - if (district_shields_remaining > 0) { - int from_districts = (extra_loss < district_shields_remaining) ? extra_loss : district_shields_remaining; - district_shields_remaining -= from_districts; - extra_loss -= from_districts; - } - - if ((extra_loss > 0) && (hub_shields_remaining > 0)) { - int from_hub = (extra_loss < hub_shields_remaining) ? extra_loss : hub_shields_remaining; - hub_shields_remaining -= from_hub; - extra_loss -= from_hub; - } - } - - int non_district_shields_remaining = total_net_shields - district_shields_remaining - hub_shields_remaining; - if (non_district_shields_remaining < 0) - non_district_shields_remaining = 0; - - int total_corruption = -total_production_loss; - if (total_corruption < 0) - total_corruption = 0; - int district_corruption = standard_district_shields - district_shields_remaining; - int hub_corruption = distribution_hub_shields - hub_shields_remaining; - int base_corruption = total_corruption - district_corruption - hub_corruption; - if (base_corruption < 0) - base_corruption = 0; - - is->non_district_shield_icons_remaining = non_district_shields_remaining; - is->district_shield_icons_remaining = district_shields_remaining; - is->distribution_hub_shield_icons_remaining = hub_shields_remaining; - - is->corruption_shield_icons_remaining = base_corruption; - is->district_corruption_icons_remaining = district_corruption; - is->distribution_hub_corruption_icons_remaining = hub_corruption; -} - -void __fastcall -patch_City_draw_production_income_icons (City * this, int edx, int canvas, int * rect_ptr) -{ - if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { - City_draw_production_income_icons (this, __, canvas, rect_ptr); - return; - } - - recompute_district_and_distribution_hub_shields_for_city_view (this); - City_draw_production_income_icons (this, __, canvas, rect_ptr); - - is->corruption_shield_icons_remaining = 0; - is->district_corruption_icons_remaining = 0; - is->distribution_hub_corruption_icons_remaining = 0; - - is->non_district_shield_icons_remaining = 0; - is->district_shield_icons_remaining = 0; - is->distribution_hub_shield_icons_remaining = 0; -} - -int __fastcall -patch_Sprite_draw_production_income_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - if (is->distribution_hub_icons_img_state == IS_UNINITED) - init_distribution_hub_icons (); - if (is->dc_icons_img_state == IS_UNINITED) - init_district_icons (); - - if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && is->dc_icons_img_state == IS_OK) { - Sprite to_draw = *this; - if (is->corruption_shield_icons_remaining > 0 || - is->district_corruption_icons_remaining > 0 || - is->distribution_hub_corruption_icons_remaining > 0) { - - if (is->corruption_shield_icons_remaining > 0) { - is->corruption_shield_icons_remaining--; - } else if (is->district_corruption_icons_remaining > 0) { - to_draw = is->district_corruption_icon; - is->district_corruption_icons_remaining--; - } else if (is->distribution_hub_icons_img_state == IS_OK) { - to_draw = is->distribution_hub_corruption_icon; - is->distribution_hub_corruption_icons_remaining--; - } - } - else if (is->non_district_shield_icons_remaining > 0 || - is->district_shield_icons_remaining > 0 || - is->distribution_hub_shield_icons_remaining > 0) { - - if (is->non_district_shield_icons_remaining > 0) { - is->non_district_shield_icons_remaining--; - } else if (is->district_shield_icons_remaining > 0) { - to_draw = is->district_shield_icon; - is->district_shield_icons_remaining--; - } else if (is->distribution_hub_icons_img_state == IS_OK) { - to_draw = is->distribution_hub_shield_icon; - is->distribution_hub_shield_icons_remaining--; - } - - } - return Sprite_draw (&to_draw, __, canvas, pixel_x, pixel_y, color_table); - } - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -bool -district_tile_needs_defense (Tile * tile, int tile_x, int tile_y, struct district_instance * inst, int civ_id, int work_radius) -{ - if ((tile == NULL) || (tile == p_null_tile)) return false; - if (inst == NULL) return false; - - int district_id = inst->district_id; - struct district_config const * cfg = &is->district_configs[district_id]; - if (! district_is_complete (tile, district_id)) return false; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; - - // Check if already has enough defenders (2 for aerodromes, distribution hubs, destroyable completed wonders) - int defender_count = count_units_at (tile_x, tile_y, UF_DEFENDER_VIS_TO_A_OF_CLASS_B, civ_id, 0, -1); - int max_defenders = - (district_id == AERODROME_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID || - (cfg->defense_bonus_percent > 0 && district_id != NEIGHBORHOOD_DISTRICT_ID) || - (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed)) - ? 2 : 1; - if (defender_count >= max_defenders) - return false; - - // Distribution hubs always need defense - if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) - return true; - - // Wonder districts need defense if under construction or completed (not unused) - if (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed) { - enum wonder_district_state state = inst->wonder_info.state; - if (state == WDS_UNDER_CONSTRUCTION || state == WDS_COMPLETED) - return true; - // Unused wonder districts don't need defense - return false; - } - - return any_enemies_near (&leaders[civ_id], tile_x, tile_y, -1, work_radius); -} - -int -compute_turns_required_for_path (Unit * unit, int path_length) -{ - if (path_length < 1) - return 0; - - int max_mp = patch_Unit_get_max_move_points (unit); - if (max_mp <= 0) - return 9999; - - int moves_used_this_turn = max_mp - unit->Body.Moves; - moves_used_this_turn = not_below (0, moves_used_this_turn); - moves_used_this_turn = not_above (moves_used_this_turn, 9999); - - int remaining_mp = path_length - moves_used_this_turn; - if (remaining_mp < 0) - remaining_mp = 0; - - return (max_mp - 1 + remaining_mp) / max_mp + 1; -} - -void -maybe_update_best_district_target (Unit * unit, - int civ_id, - int max_distance, - int unit_x, - int unit_y, - int tile_x, - int tile_y, - int base_score, - int * best_score, - int * best_x, - int * best_y, - int * best_path_length, - int * evaluated_paths, - int max_path_checks) -{ - if (*evaluated_paths >= max_path_checks) - return; - - int path_length; - int path_result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, tile_x, tile_y, - unit, civ_id, 0x81, &path_length); - *evaluated_paths += 1; - if (path_result <= 0) - return; - - if (max_distance > 0) { - int turns = compute_turns_required_for_path (unit, path_length); - if (turns > max_distance) - return; - } - - int score = base_score - path_length; - if ((score > *best_score) || ((score == *best_score) && (path_length < *best_path_length))) { - *best_score = score; - *best_x = tile_x; - *best_y = tile_y; - *best_path_length = path_length; - } -} - -// Patch seek_colony to actively search for undefended districts -int __fastcall -patch_Unit_seek_colony (Unit * this, int edx, bool for_own_defense, int max_distance) -{ - // Only intercept if defending own assets and districts are enabled - if (!for_own_defense || - !is->current_config.enable_districts || - !is->current_config.ai_defends_districts) - return Unit_seek_colony (this, __, for_own_defense, max_distance); - - int civ_id = this->Body.CivID; - int unit_x = this->Body.X; - int unit_y = this->Body.Y; - - Tile * current_tile = tile_at (unit_x, unit_y); - if ((current_tile == NULL) || (current_tile == p_null_tile)) - return Unit_seek_colony (this, __, for_own_defense, max_distance); - - int continent_id = current_tile->vtable->m46_Get_ContinentID (current_tile); - - const int search_radius = 20; - const int max_path_checks = 64; - const int wonder_base_score = 1000; - const int regular_base_score = 500; - - int best_x = -1; - int best_y = -1; - int best_score = INT_MIN; - int best_path_length = INT_MAX; - int evaluated_paths = 0; - - bool abort_search = false; - - if ((is->current_config.enable_wonder_districts && is->current_config.completed_wonder_districts_can_be_destroyed) || - is->current_config.enable_distribution_hub_districts) { - for (int dx = -search_radius; (dx <= search_radius) && !abort_search; dx++) { - for (int dy = -search_radius; dy <= search_radius; dy++) { - if (evaluated_paths >= max_path_checks) { - abort_search = true; - break; - } - - int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); - int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); - Tile * district_tile = tile_at (target_x, target_y); - if ((district_tile == NULL) || (district_tile == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (district_tile); - if (inst == NULL) - continue; - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) - continue; - if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) - continue; - if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) - continue; - - maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, - tile_x, tile_y, wonder_base_score, - &best_score, &best_x, &best_y, - &best_path_length, &evaluated_paths, - max_path_checks); - } - } - } - - if ((best_x < 0) && (evaluated_paths < max_path_checks)) { - for (int dx = -search_radius; (dx <= search_radius) && (evaluated_paths < max_path_checks); dx++) { - for (int dy = -search_radius; dy <= search_radius; dy++) { - if (evaluated_paths >= max_path_checks) - break; - - int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); - int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); - Tile * district_tile = tile_at (target_x, target_y); - if ((district_tile == NULL) || (district_tile == p_null_tile)) - continue; - - struct district_instance * inst = get_district_instance (district_tile); - if ((inst == NULL) || (inst->district_id == WONDER_DISTRICT_ID)) - continue; - - int tile_x, tile_y; - if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) - continue; - if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) - continue; - if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) - continue; - - maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, - tile_x, tile_y, regular_base_score, - &best_score, &best_x, &best_y, - &best_path_length, &evaluated_paths, - max_path_checks); - } - } - } - - if ((best_x >= 0) && (best_y >= 0)) { - int result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, best_x, best_y, - this, civ_id, 0x181, NULL); - return result; - } - - return Unit_seek_colony (this, __, for_own_defense, max_distance); -} - -// Patch has_colony to make units stay on districts, only patches within Unit::ai_move_defensive_unit -bool __fastcall -patch_Tile_has_district_or_colony (Tile * this) -{ - if (is->current_config.enable_districts && - is->current_config.ai_defends_districts) { - - struct district_instance * inst = get_district_instance (this); - return (inst != NULL) && district_is_complete (this, inst->district_id); - } - - // Fallback to original has_colony logic - return Tile_has_colony (this); -} - -int __fastcall -patch_Buildings_Info_get_age_in_years_for_tourism (Buildings_Info * this, int edx, int building_index) -{ - int base = Buildings_Info_get_age_in_years (this, __, building_index); - if (is->current_config.tourism_time_scale_percent == 100) - return base; - else if (is->current_config.tourism_time_scale_percent <= 0) - return INT_MAX; - else - return (base * 100 + 50) / is->current_config.tourism_time_scale_percent; -} - -int __fastcall -patch_Sprite_draw_minimap_frame (Sprite * this, int edx, Sprite * alpha, int param_2, PCX_Image * canvas, int x, int y, int param_6) -{ - bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || - ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); - if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) - return Sprite_draw_for_hud (&is->double_size_box_left_color_pcx, __, &is->double_size_box_left_alpha_pcx, param_2, canvas, x, y, param_6); - else - return Sprite_draw_for_hud (this, __, alpha, param_2, canvas, x, y, param_6); -} - -int __fastcall -patch_City_get_turns_to_build_2_for_ai_move_leader (City * this, int edx, City_Order * order, bool param_2) -{ - // Initialize order variable to city's current build. This is not done in the base logic and can cause crashes. - City_Order current_order = { .OrderID = this->Body.Order_ID, .OrderType = this->Body.Order_Type }; - if (is->current_config.patch_crash_in_leader_unit_ai) - order = ¤t_order; - - return City_get_turns_to_build_2 (this, __, order, param_2); -} - -void __fastcall -patch_City_set_production (City * this, int edx, int order_type, int order_id, bool ask_to_confirm) -{ - City_set_production (this, __, order_type, order_id, ask_to_confirm); - - if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) - return; - - // If the human player, we need to set/unset a wonder district for this city, depending - // on what is being built. The human player wouldn't be able to choose a wonder if a wonder - // district wasn't available, so we don't need to worry about feasibility here. - // The AI uses a different mechanism to reserve wonder districts via patch_Leader_do_production_phase. - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - if (! is_human) - return; - - char ss[256]; - bool release_reservation = true; - if (this->Body.Order_Type == COT_Improvement) { - Improvement * improv = &p_bic_data->Improvements[this->Body.Order_ID]; - if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { - if (reserve_wonder_district_for_city (this, this->Body.Order_ID)) { - release_reservation = false; - } - } - } - - if (release_reservation) { - release_wonder_district_reservation (this); - } -} - -int __fastcall -patch_Tile_m71_Check_Worker_Job (Tile * this) -{ - if (is->current_config.enable_natural_wonders) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && - (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && - (inst->natural_wonder_info.natural_wonder_id >= 0)) { - return -1; // No worker job allowed on natural wonders - } - } - return Tile_m71_Check_Worker_Job (this); -} - -int __fastcall -patch_Tile_get_road_bonus (Tile * this) -{ - if (is->current_config.enable_natural_wonders) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { - return 0; - } - } - if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { - return 1; - } - } - return Tile_get_road_bonus (this); -} - -bool __fastcall -patch_Unit_has_army_ability_to_perform_unload (Unit * this, int edx, enum UnitTypeAbilities a) -{ - return is->current_config.allow_unload_from_army ? false : Unit_has_ability (this, __, a); -} - -void __fastcall -patch_Unit_disembark (Unit * this, int edx, int tile_x, int tile_y) -{ - Unit * container = get_unit_ptr (this->Body.Container_Unit); - bool unloading_from_army = is->current_config.allow_unload_from_army && container != NULL && Unit_has_ability (container, __, UTA_Army); - - // If removing a unit from an army, transfer a proportional amount of damage to the unit removed - int damage_transferred = 0; - if (unloading_from_army) { - int army_damage_percent = container->Body.Damage * 100 / Unit_get_max_hp (container), - max_damage = Unit_get_max_hp (this) - 1 - this->Body.Damage; - damage_transferred = clamp (0, max_damage, (army_damage_percent * Unit_get_max_hp (this) + 50) / 100); - } - - Unit_disembark (this, __, tile_x, tile_y); - - if (unloading_from_army) { - this->Body.Damage = not_above (Unit_get_max_hp (this) - 1, this->Body.Damage + damage_transferred); - container->Body.Damage = not_below (0, container->Body.Damage - damage_transferred); - - if (this->Body.ID == container->Body.army_top_defender_id) { - Unit * new_top_defender = NULL; - FOR_UNITS_ON (uti, tile_at (container->Body.X, container->Body.Y)) - if (uti.unit->Body.Container_Unit == container->Body.ID) { - if (new_top_defender == NULL) - new_top_defender = uti.unit; - else if (Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, uti.unit, Unit_get_defense_strength (uti.unit), new_top_defender, Unit_get_defense_strength (new_top_defender), true)) - new_top_defender = uti.unit; - } - container->Body.army_top_defender_id = (new_top_defender != NULL) ? new_top_defender->Body.ID : -1; - } - } -} - -bool __fastcall -patch_Unit_has_ability_no_load_non_army_passengers (Unit * this, int edx, enum UnitTypeAbilities army_ability) -{ - UnitType * transport_type = &p_bic_data->UnitTypes[is->can_load_transport->Body.UnitTypeID], - * passenger_type = &p_bic_data->UnitTypes[this ->Body.UnitTypeID]; - - // This call comes from Unit::can_load at the point where it's determined that the passenger (this) has transport capacity > 0 and is checking - // whether it's an army. If not, it can't be loaded. Add two exceptions here for land transports, if configured, one to allow LTs to load into - // naval units and another to allow empty LTs to load into armies. - if (is->current_config.land_transport_rules != 0) - if ((passenger_type->Unit_Class == UTC_Land) && ! Unit_has_ability (this, __, army_ability)) { // if it's a land transport - if ((is->current_config.land_transport_rules & LTR_LOAD_ONTO_BOAT) && (transport_type->Unit_Class == UTC_Sea)) - return true; - if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && - Unit_has_ability (is->can_load_transport, __, army_ability) && (Unit_count_contained_units (this) == 0)) - return true; - } - - // Similarly, allow helicopters to be loaded onto carriers if so configured - if ((is->current_config.special_helicopter_rules & SHR_ALLOW_ON_CARRIERS) && - passenger_type->Unit_Class == UTC_Air && - transport_type->Unit_Class == UTC_Sea && - Unit_has_ability (is->can_load_transport, __, UTA_Transports_Only_Aircraft)) - return true; - - return Unit_has_ability (this, __, army_ability); -} - -bool __fastcall -patch_Unit_has_ability_no_load_transport_into_army (Unit * this, int edx, enum UnitTypeAbilities army_ability) -{ - // Similar to above, here it checks if the target unit is an army and rejects the load if it is (again, already determined that the passenger - // has transport capacity). Modify this rule to return false for land transports trying to join armies if configured. We don't have to check - // that the LT is empty since that is already disallowed by the modified check above. - bool is_army = Unit_has_ability (this, __, army_ability); - if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && is_army && - (p_bic_data->UnitTypes[is->can_load_passenger->Body.UnitTypeID].Unit_Class == UTC_Land)) - return false; - - else - return is_army; -} - -bool __fastcall -patch_Fighter_unit_can_defend (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) -{ - if (cannot_defend_inside_transport (unit)) - return false; - else - return Fighter_unit_can_defend (this, __, unit, tile_x, tile_y); -} - -bool __fastcall -patch_Leader_is_enemy_unit_for_ground_aa (Leader * this, int edx, Unit * bomber) -{ - // When this function is called, the potential interceptor unit is stored in register ESI. - Unit * interceptor; - __asm__ __volatile__("mov %%esi, %0" : "=r" (interceptor)); - - Unit * container = get_unit_ptr (interceptor->Body.Container_Unit); - bool in_transport = (container != NULL) && ! Unit_has_ability (container, __, UTA_Army); - if (in_transport && - (is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Land) - return false; - else if (in_transport && - (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && - p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) - return false; - else if (in_transport && - is->current_config.no_land_anti_air_from_inside_naval_transport && - (p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea)) - return false; - else - return Leader_is_enemy_unit (this, __, bomber); -} - -bool __fastcall -patch_Unit_has_army_ability_for_passenger_despawn (Unit * this, int edx, enum UnitTypeAbilities army_ability) -{ - // If the unit has the army ability, the game will always despawn the passengers. Otherwise there are exceptions like land unit passengers - // won't be despawned if the transport is on a land tile. - return is->always_despawn_passengers || Unit_has_ability (this, __, army_ability); -} - -int __cdecl -patch_count_units_at_in_try_capturing (int x, int y, enum unit_filter filter, int arg_a, int arg_b, int arg_c) -{ - Tile * tile = tile_at (x, y); - - // If one of the no-defense-from-inside rules is in force, count units like the function normally would except skip units that are inside - // transports from which they can't defend. Otherwise, if those transports have 0 defense, the passengers will prevent them from being - // captured but not fight themselves, making movement onto their tile impossible. - if (tile->vtable->m35_Check_Is_Water (tile) == 0 && - ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) || (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE))) { - int tr = 0; - FOR_UNITS_ON (tai, tile) { - if ((arg_b == -1 || p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].Unit_Class == arg_b) && - (arg_a == -1 || patch_Unit_is_visible_to_civ (tai.unit, __, arg_a, 1)) && - (Unit_get_defense_strength (tai.unit) > 0) && - ! cannot_defend_inside_transport (tai.unit)) - tr++; - } - return tr; - - } else - return count_units_at (x, y, filter, arg_a, arg_b, arg_c); -} - -void __fastcall -patch_Map_generate_resources (Map * this, int edx, int secondary_seed) -{ - int const bic_tag_good = 0x444f4f47; // = 'GOOD' - int resource_type_count = this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, -1, NULL); - bool * ratios_to_clear = NULL; - int lux_percent = is->current_config.luxury_randomized_appearance_rate_percent; - int seed = (this->Seed + 0x180E3) * secondary_seed; - - // To change the randomized appearance rate for luxuries, fill in an appearance rate for any that would be randomized (rate set == 0) using - // the same process the game would to randomize the rate but with different limits. That process involves taking two random numbers from 0 to - // 25 then adding them together and to 50 to produce a random rate from 50 to 100 biased toward the middle of that range. - if (lux_percent != 100 && - (ratios_to_clear = calloc (1, resource_type_count)) != NULL) { - for (int n = 0; n < resource_type_count; n++) { - Resource_Type * res; - this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); - if (res->Class == RC_Luxury && res->AppearanceRatio == 0) { - ratios_to_clear[n] = true; - int half_lux_percent = (lux_percent * 50 + 50) / 100, - quarter_lux_percent = (lux_percent * 25 + 50) / 100; - res->AppearanceRatio = not_below (1, half_lux_percent + rand_int (&seed, __, quarter_lux_percent) + rand_int (&seed, __, quarter_lux_percent)); - } - } - } - - Map_generate_resources (this, __, secondary_seed); - - if (ratios_to_clear != NULL) { - for (int n = 0; n < resource_type_count; n++) - if (ratios_to_clear[n]) { - Resource_Type * res; - this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); - res->AppearanceRatio = 0; - } - free (ratios_to_clear); - } -} - -PassBetweenValidity __fastcall -patch_Unit_can_pass_between (Unit * this, int edx, int from_x, int from_y, int to_x, int to_y, int param_5) -{ - PassBetweenValidity base = Unit_can_pass_between (this, __, from_x, from_y, to_x, to_y, param_5); - - if (is->current_config.enable_districts) { - Tile * to = tile_at (to_x, to_y); - bool to_valid = (to != NULL) && (to != p_null_tile); - struct district_instance * to_inst = NULL; - bool to_inst_complete = false; - if (to_valid) { - to_inst = get_district_instance (to); - if (to_inst != NULL) - to_inst_complete = district_is_complete (to, to_inst->district_id); - } - if (great_wall_blocks_civ (to, this->Body.CivID)) - return PBV_GENERIC_INVALID_MOVE; - if (to_valid) { - bool impassible = false; - bool impassible_to_wheeled = false; - if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { - if (impassible) - return PBV_GENERIC_INVALID_MOVE; - if (impassible_to_wheeled && Unit_has_ability (this, __, UTA_Wheeled)) { - Tile * from = tile_at (from_x, from_y); - bool connected_by_road = (from != NULL) && (to != NULL) && - (from->vtable->m25_Check_Roads (from, __, 0) != 0) && - (to->vtable->m25_Check_Roads (to, __, 0) != 0); - if (! connected_by_road) - return PBV_REQUIRES_ROAD; - } - } - } - - if (is->current_config.workers_can_enter_coast && - base != PBV_OK && is_worker(this)) { - Tile * source = tile_at (from_x, from_y); - if (source != NULL && - source->vtable->m35_Check_Is_Water (source) && - (source->vtable->m50_Get_Square_BaseType (source) == SQ_Coast)) - return PBV_OK; - - if (to_valid && - to->vtable->m35_Check_Is_Water (to) && - (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) { - bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; - - // If human, okay to enter coast tile - if (is_human) - return PBV_OK; - - struct district_worker_record * rec = get_tracked_worker_record (this); - struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; - if (req != NULL) - return PBV_OK; - } - } - - if (is->current_config.enable_bridge_districts && - base != PBV_OK && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == BRIDGE_DISTRICT_ID)) - return PBV_OK; - - if (is->current_config.enable_canal_districts && - base != PBV_OK && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && - (to_inst != NULL) && to_inst_complete && - (to_inst->district_id == CANAL_DISTRICT_ID)) - return PBV_OK; - } - - return base; -} - -Unit * __fastcall -patch_Unit_select_transport (Unit * this, int edx, int tile_x, int tile_y, bool do_show_popup) -{ - Unit * transport = Unit_select_transport (this, __, tile_x, tile_y, do_show_popup); - - if (is->current_config.enable_districts && - (transport == NULL) && (this == is->coast_walk_unit)) { - Tile * dest = tile_at (tile_x, tile_y); - if (dest != NULL) { - bool allow_move = false; - if (is->current_config.workers_can_enter_coast && is_worker (this) && - dest->vtable->m35_Check_Is_Water (dest) && - (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) - allow_move = true; - - if (! allow_move && is->current_config.enable_bridge_districts && - (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land)) { - struct district_instance * inst = get_district_instance (dest); - if (inst != NULL && inst->district_id == BRIDGE_DISTRICT_ID && - district_is_complete (dest, inst->district_id)) { - allow_move = true; - } - } - - if (allow_move) { - is->coast_walk_transport_override = true; - return this; // Fake a transport so the move logic proceeds - } - } - } - - return transport; -} - -// Returns true if the given tile is a water district owned by an enemy of the unit -bool -is_enemy_maritime_district_tile (Unit * unit, Tile * tile) -{ - if ((unit == NULL) || (tile == NULL) || (tile == p_null_tile)) - return false; - - if (! is->current_config.enable_districts) - return false; - - if (! tile->vtable->m35_Check_Is_Water (tile)) - return false; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return false; - - int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner <= 0) || (owner == unit->Body.CivID)) - return false; - - Leader * leader = &leaders[unit->Body.CivID]; - return leader->At_War[owner]; -} - -// Boost pillage desirability for maritime districts -int __fastcall -patch_Unit_ai_eval_pillage_target (Unit * this, int edx, int tile_x, int tile_y) -{ - int base = Unit_ai_eval_pillage_target (this, __, tile_x, tile_y); - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if (is_enemy_maritime_district_tile (this, tile)) { - // Double the base score so districts outrank generic coast targets - base += base + 0x300; - } - - return base; -} - -// Light-weight hunt for nearby friendly ports; returns true if a path/command was issued -bool -try_path_to_friendly_port_district (Unit * unit, bool require_damaged, bool require_undefended) -{ - if ((unit == NULL) || - ! is->current_config.enable_districts || - ! is->current_config.enable_port_districts) - return false; - - if (unit->Body.Container_Unit >= 0) // Don't redirect cargo - return false; - - if (unit->Body.Moves <= 0) - return false; - - if (require_damaged && (unit->Body.Damage <= 0)) - return false; - - if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Sea) - return false; - - int sea_id = unit->vtable->get_sea_id (unit); - if (sea_id < 0) - return false; - - int best_x = -1, best_y = -1, best_path_len = INT_MAX; - const int search_radius = 10; - for (int dy = -search_radius; dy <= search_radius; dy++) { - for (int dx = -search_radius; dx <= search_radius; dx++) { - int tx = unit->Body.X + dx, ty = unit->Body.Y + dy; - wrap_tile_coords (&p_bic_data->Map, &tx, &ty); - - Tile * tile = tile_at (tx, ty); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - - if ((short)tile->vtable->m46_Get_ContinentID (tile) != sea_id) - continue; - - if (! tile_has_friendly_port_district (tile, unit->Body.CivID)) - continue; - - int occupier_id = get_tile_occupier_id (tx, ty, -1, true); - if ((occupier_id != -1) && (occupier_id != unit->Body.CivID)) - continue; - - if (require_undefended) { - bool has_friendly_sea_unit = false; - FOR_UNITS_ON (uti, tile) { - Unit * on_tile = uti.unit; - if ((on_tile == NULL) || (on_tile->Body.Container_Unit >= 0)) - continue; - if (on_tile->Body.CivID != unit->Body.CivID) - continue; - if (p_bic_data->UnitTypes[on_tile->Body.UnitTypeID].Unit_Class != UTC_Sea) - continue; - if (on_tile->Body.ID == unit->Body.ID) - continue; - has_friendly_sea_unit = true; - break; - } - if (has_friendly_sea_unit) - continue; - } - - if (! is_below_stack_limit (tile, unit->Body.CivID, UTC_Sea)) - continue; - - int path_len = 0; - int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, - tx, ty, unit, unit->Body.CivID, 0x81, &path_len); - if (path_result <= 0) - continue; - - if (path_len < best_path_len) { - best_path_len = path_len; - best_x = tx; - best_y = ty; - } - } - } - - if (unit->Body.X == best_x && unit->Body.Y == best_y) { - Unit_set_escortee (unit, __, -1); - Unit_set_state (unit, __, UnitState_Fortifying); - return true; - } - else if (best_x >= 0) { - patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, best_x, best_y, - unit, unit->Body.CivID, 0x81, NULL); - Unit_set_escortee (unit, __, -1); - Unit_set_state (unit, __, UnitState_Go_To); - unit->Body.path_dest_x = best_x; - unit->Body.path_dest_y = best_y; - return true; - } - - return false; -} - -void __fastcall -patch_Unit_ai_move_naval_power_unit (Unit * this) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - ! is->current_config.naval_units_use_port_districts_not_cities) { - Unit_ai_move_naval_power_unit (this); - return; - } - - Tile * here = tile_at (this->Body.X, this->Body.Y); - if (here == NULL) { - Unit_ai_move_naval_power_unit (this); - return; - } - - // If we're on a port and the sole unit, fortify - if (is->current_config.ai_defends_districts && - tile_has_friendly_port_district (here, this->Body.CivID) && - count_units_at (this->Body.X, this->Body.Y, UF_0, this->Body.CivID, 0, -1) == 1) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If we're already sitting on an enemy maritime district, pillage it immediately - if (this->Body.Container_Unit < 0) { - if (is_enemy_maritime_district_tile (this, here) && - patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y) && - (patch_Unit_ai_eval_pillage_target (this, __, this->Body.X, this->Body.Y) > 0)) { - patch_Unit_attack_tile (this, __, this->Body.X, this->Body.Y, false); - return; - } - } - - // If damaged and CAN heal at current location (e.g. port district), fortify to heal - if (this->Body.Damage > 0 && patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If damaged and cannot heal here, try to path to a friendly port district - if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) - return; - - Unit_ai_move_naval_power_unit (this); - return; -} - -void __fastcall -patch_Unit_ai_move_naval_transport (Unit * this) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - ! is->current_config.naval_units_use_port_districts_not_cities) { - Unit_ai_move_naval_transport (this); - return; - } - - // If damaged and CAN heal at current location (e.g. port district), fortify to heal - if ((this->Body.Damage > 0) && - patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If damaged and cannot heal here, try to path to a friendly port district - if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) - return; - - Unit_ai_move_naval_transport (this); -} - -void __fastcall -patch_Unit_ai_move_naval_missile_transport (Unit * this) -{ - if (! is->current_config.enable_districts || - ! is->current_config.enable_port_districts || - ! is->current_config.naval_units_use_port_districts_not_cities) { - patch_Unit_ai_move_naval_missile_transport (this); - return; - } - - // If damaged and CAN heal at current location (e.g. port district), fortify to heal - if ((this->Body.Damage > 0) && - patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - // If damaged and cannot heal here, try to path to a friendly port district - if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) - return; - - Unit_ai_move_naval_missile_transport (this); -} - -void __fastcall -patch_Unit_ai_move_air_bombard_unit (Unit * this) -{ - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) { - Unit_ai_move_air_bombard_unit (this); - return; - } - - if (this->Body.Damage > 0) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - int best_target = 0; - int target_x = -1, target_y = -1; - int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - int grid = op_range * 2 + 1; - if (1 < grid * grid) { - for (int n = 1; n < grid * grid; n++) { - int dx, dy; - neighbor_index_to_diff (n, &dx, &dy); - int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); - int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); - if (Map_in_range (&p_bic_data->Map, __, x, y)) { - int score = Unit_ai_eval_bombard_target (this, __, x, y, 1); - if (score > best_target) { - best_target = score; - target_x = x; - target_y = y; - } - } - } - } - - int best_base_score = 0x7fffffff; - int base_x = -1, base_y = -1; - FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, - p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) - continue; - - int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 6, -1, -1); - int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); - int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); - int score = (count * 10) + ((x_dist + y_dist) >> 1); - if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) - score -= 20; - - if (score < best_base_score) { - best_base_score = score; - base_x = aerodrome_x; - base_y = aerodrome_y; - } - } - - if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { - Unit_set_escortee (this, __, -1); - Unit_rebase (this, __, base_x, base_y); - return; - } - - if ((target_x >= 0) && (target_y >= 0)) { - Unit_set_escortee (this, __, -1); - patch_Unit_bombard_tile (this, __, target_x, target_y); - return; - } - - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -void __fastcall -patch_Unit_ai_move_air_defense_unit (Unit * this) -{ - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) { - Unit_ai_move_air_defense_unit (this); - return; - } - - Unit_ai_move_air_defense_unit (this); - - Unit_set_state (this, __, 0); - if (this->Body.Damage > 0) { - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); - return; - } - - int best_base_score = 0x7fffffff; - int base_x = -1, base_y = -1; - FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, - p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) - continue; - - int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 7, -1, -1); - int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); - int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); - int score = (count * 10) + ((x_dist + y_dist) >> 1); - if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) - score -= 20; - - if (score < best_base_score) { - best_base_score = score; - base_x = aerodrome_x; - base_y = aerodrome_y; - } - } - - if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { - Unit_set_escortee (this, __, -1); - Unit_rebase (this, __, base_x, base_y); - return; - } - - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Intercept); -} - -void __fastcall -patch_Unit_ai_move_air_transport (Unit * this) -{ - if (! (is->current_config.enable_districts && - is->current_config.enable_aerodrome_districts && - is->current_config.air_units_use_aerodrome_districts_not_cities)) { - Unit_ai_move_air_transport (this); - return; - } - - Unit_ai_move_air_transport (this); - - if (this->Body.Damage < 1) { - if (Unit_can_airdrop (this)) { - int best_score = 0; - int best_x = -1, best_y = -1; - int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; - int grid = op_range * 2 + 1; - if (1 < grid * grid) { - for (int n = 1; n < grid * grid; n++) { - int dx, dy; - neighbor_index_to_diff (n, &dx, &dy); - int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); - int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); - if (Map_in_range (&p_bic_data->Map, __, x, y)) { - int score = Unit_ai_eval_airdrop_target (this, __, x, y); - if (score > best_score) { - best_score = score; - best_x = x; - best_y = y; - } - } - } - if ((best_x >= 0) && (best_y >= 0)) { - Unit_set_escortee (this, __, -1); - Unit_airdrop (this, __, best_x, best_y); - return; - } - } - } - - int best_score = -1; - int base_x = -1, base_y = -1; - FOR_AERODROMES_AROUND (this) { - if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, - p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) - continue; - - int score = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 0, -1, -1) + - count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 1, -1, -1) + 1; - if (count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 9, -1, -1) == 0) - score *= 2; - int cont_id = aerodrome_tile->vtable->m46_Get_ContinentID (aerodrome_tile); - if ((cont_id >= 0) && (cont_id < p_bic_data->Map.Continent_Count) && - (p_bic_data->Map.Continents[cont_id].Body.TileCount > 0x15)) - score *= 2; - - if (score > best_score) { - best_score = score; - base_x = aerodrome_x; - base_y = aerodrome_y; - } - } - - if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { - Unit_set_escortee (this, __, -1); - Unit_rebase (this, __, base_x, base_y); - if (Unit_count_contained_units (this) > 0) { - patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); - } - return; - } - } - - if (Unit_count_contained_units (this) > 0) - patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); - - Unit_set_escortee (this, __, -1); - Unit_set_state (this, __, UnitState_Fortifying); -} - -bool __fastcall -patch_Tile_has_colony_ignore_extraterritorial (Tile * tile) -{ - if (!Tile_has_colony (tile)) - return false; - - if (!is->current_config.allow_extraterritorial_colonies) - return true; - - if ((tile == NULL) || (tile == p_null_tile)) - return true; - - int tile_building_id = tile->vtable->m47_Get_Tile_BuildingID (tile); - if ((tile_building_id < 0) || (p_colonies == NULL) || (p_colonies->Items == NULL) || - (tile_building_id > p_colonies->LastIndex)) - return true; - - Tile_Building_Body * colony_body = p_colonies->Items[tile_building_id].Object; - if ((colony_body == NULL) || ((int)colony_body == offsetof (Tile_Building, Body))) - return true; - - return colony_body->OwnerID == tile->vtable->m38_Get_Territory_OwnerID (tile); -} - -int __fastcall -patch_Leader_get_attitude_toward (Leader * this, int edx, int civ_id, int param_2) -{ - int score = Leader_get_attitude_toward (this, __, civ_id, param_2); - if (!is->current_config.allow_extraterritorial_colonies) - return score; - - int penalty = is->current_config.per_extraterritorial_colony_relation_penalty; - if (penalty != 0) { - int this_civ_id = this->ID; - if ((p_colonies != NULL) && (p_colonies->Items != NULL)) { - for (int n = 0; n <= p_colonies->LastIndex; n++) { - Tile_Building_Body * colony_body = p_colonies->Items[n].Object; - if ((colony_body == NULL) || - ((int)colony_body == offsetof (Tile_Building, Body))) - continue; - - Tile * tile = tile_at (colony_body->X, colony_body->Y); - if ((tile == NULL) || (tile == p_null_tile)) - continue; - if (tile->vtable->m38_Get_Territory_OwnerID (tile) != this_civ_id) - continue; - if (colony_body->OwnerID != civ_id) - continue; - score -= penalty; - } - } - } - return score; -} - -void __fastcall -patch_UnitIDList_insert_after_init (UnitIDList * this, int edx, int id, UnitIDItem * item) -{ - // If using non-standard unit cycling, avoid calling this method b/c it sometimes causes a crash - if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) - UnitIDList_insert_after (this, __, id, item); -} - -bool __fastcall -patch_Tile_m17_Check_Irrigation (Tile * this, int edx, int visible_to_civ_id) -{ - bool base = Tile_m17_Check_Irrigation (this, __, visible_to_civ_id); - if (base) - return true; - - if (! is->current_config.enable_districts) - return base; - - struct district_instance * inst = get_district_instance (this); - if (inst == NULL) - return base; - - if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (this, inst->district_id)) - return true; - - return base; -} - -int __fastcall -patch_Unit_ai_eval_bombard_target (Unit * this, int edx, int tile_x, int tile_y, int param_3) -{ - int score = Unit_ai_eval_bombard_target (this, __, tile_x, tile_y, param_3); - - if (! (is->current_config.enable_districts && - is->current_config.enable_great_wall_districts)) - return score; - - Tile * tile = tile_at (tile_x, tile_y); - if ((tile == NULL) || (tile == p_null_tile)) - return score; - - struct district_instance * inst = get_district_instance (tile); - if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID) || (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID))) - return score; - - int obsolete_id = is->district_infos[GREAT_WALL_DISTRICT_ID].obsoleted_by_id; - if ((obsolete_id >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, obsolete_id)) - return score; - - int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); - if ((owner_id <= 0) || (owner_id == this->Body.CivID)) - return score; - if (! this->vtable->is_enemy_of_civ (this, __, owner_id, false)) - return score; - - bool has_unit_on_tile = false; - bool has_enemy_on_tile = false; - Leader * me = &leaders[this->Body.CivID]; - FOR_UNITS_ON (uti, tile) { - UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; - if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0)) { - has_unit_on_tile = true; - if (me->At_War[uti.unit->Body.CivID]) { - if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { - has_enemy_on_tile = true; - break; - } - } else - break; - } - } - - if (has_unit_on_tile && ! has_enemy_on_tile) - return score; - - // Boost score to prioritize Great Wall targets - if (score < 0x6000) - score = 0x6000; - - // Additional boost if there is no unit on it, more likely to destroy it - if (! has_enemy_on_tile) - score += 0x200; - - return score; -} - -void __fastcall -patch_Unit_heal_at_start_of_turn (Unit * this) -{ - if (is->current_config.enable_districts) { - Tile * tile = tile_at ((this->Body).X, (this->Body).Y); - if ((tile != NULL) && (tile != p_null_tile)) { - struct district_instance * inst = get_district_instance (tile); - if (inst != NULL && district_is_complete (tile, inst->district_id) && - is->district_configs[inst->district_id].heal_units_in_one_turn) { - int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); - if (territory_owner == this->Body.CivID) { - (this->Body).Damage = 0; - return; - } - } - } - } - - Unit_heal_at_start_of_turn (this); -} - -// Makes naval AI treat enemy port districts as valid targets to path toward. -int __cdecl -patch_get_tile_occupier_id_in_Unit_ai_move_naval_power_unit (int x, int y, int pov_civ_id, bool respect_unit_invisibility) -{ - int base = get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); - if (base != -1) - return base; - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return -1; - - Tile * tile = tile_at (x, y); - if (tile == NULL || tile == p_null_tile) - return -1; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return -1; - - return (*tile->vtable->m38_Get_Territory_OwnerID) (tile); -} - -// Returns a non-zero score for enemy port district tiles so they pass the threshold check and are bombard targets -int __fastcall -patch_Fighter_eval_tile_vulnerability_in_Unit_ai_move_naval_power_unit (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) -{ - int base = Fighter_eval_tile_vulnerability (this, __, unit, tile_x, tile_y); - if (base > 0) - return base; - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if (tile == NULL || tile == p_null_tile) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return base; - - int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); - if (owner <= 0 || owner == unit->Body.CivID) - return base; - - if (! leaders[unit->Body.CivID].At_War[owner]) - return base; - - // Return a score high enough to pass threshold (iVar13 * 8 + 0x100) - // 0x300 should be sufficient for most cases - return 0x300; -} - -// Returns the territory owner for enemy port districts so the score isn't reduced and naval units move to enemy ports -// (to subsequently pillage them) -int __cdecl -patch_get_combat_occupier_in_Unit_ai_move_naval_power_unit (int tile_x, int tile_y, int civ_id, byte ignore_visibility) -{ - int base = get_combat_occupier (tile_x, tile_y, civ_id, ignore_visibility); - if (base != -1) - return base; - - if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) - return base; - - Tile * tile = tile_at (tile_x, tile_y); - if (tile == NULL || tile == p_null_tile) - return base; - - struct district_instance * inst = get_district_instance (tile); - if (inst == NULL) - return base; - - int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); - if (owner <= 0 || owner == civ_id) - return base; - - if (! leaders[civ_id].At_War[owner]) - return base; - - return owner; -} - -int __fastcall -patch_rand_int_to_enslave (void * this, int edx, int lim) -{ - // lim is 100, enslaving happens if the return value is < 33 - int r = rand_int (this, __, lim); - return is->do_not_enslave_units ? 100 : r; -} - -int __fastcall -patch_Sprite_draw_espionage_screen_target_civ_bkg (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) -{ - // Figure out which of the potential target civs we're drawing by working backwards from the Y location - int top = (p_bic_data->ScreenHeight - p_espionage_form->Image.Height) / 2; - is->espionage_form_drawing_target_index = (pixel_y - top - 0x5C) / 0x3a + p_espionage_form->field_1584; - - return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); -} - -char * __fastcall -patch_Civilopedia_Article_get_name_for_esp_screen (Civilopedia_Article * this) -{ - // Ensure that we have captured a valid civ ID being drawn then, if that civ has an era-specific formal name, return that so that the - // era-specific names apply on the espionage screen. - int target_civ_id; - if (is->espionage_form_drawing_target_index >= 0 && - is->espionage_form_drawing_target_index < p_espionage_form->target_civ_id_count && - (target_civ_id = p_espionage_form->target_civ_ids[is->espionage_form_drawing_target_index]) >= 0 && - target_civ_id < 32 && - is->aliased_civ_formal_name_bits & 1<Name.S; -} - -void __fastcall -patch_Animator_play_one_shot_victory_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) -{ - if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Air && is->current_config.aircraft_victory_animation != NULL) { - struct string_slice slice = {.str = is->current_config.aircraft_victory_animation, .len = strlen (is->current_config.aircraft_victory_animation)}; - find_animation_type_by_name (&slice, true, &anim_type); - } - - Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); -} - -void -clear_selectable_units_list (Main_Screen_Form * main_screen_form, bool include_unit_objects) -{ - // This is what the base game does to clear things at the start of assemble_selectable_units - if (include_unit_objects && p_units->Units != NULL) - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if (unit != NULL) - unit->Body.in_selectable_units_list = false; - } - UnitIDItem * item = main_screen_form->selectable_units.first; - while (item != NULL) { - UnitIDItem * next = item->next; - item->vtable->destruct (item, __, 1); - item = next; - } - main_screen_form->selectable_units.first = main_screen_form->selectable_units.last = NULL; - main_screen_form->selectable_units.length = 0; -} - -void __fastcall -patch_Main_Screen_Form_assemble_selectable_units (Main_Screen_Form * this) -{ - if (is->have_loaded_waiting_units) - is->have_loaded_waiting_units = false; - else - table_deinit (&is->waiting_units); - - if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) - Main_Screen_Form_assemble_selectable_units (this); - else { - clear_selectable_units_list (this, true); - this->unit_cycle_cursor = NULL; - this->completed_unit_cycle = false; - } -} - -void __fastcall -patch_Main_Screen_Form_set_selected_unit (Main_Screen_Form * this, int edx, Unit * unit, bool param_2) -{ - // To set a unit to wait, Main_Screen_Form::issue_command calls this method with unit == NULL and param_2 == false. Detect when that's - // happened and record that the unit's been set to wait so we can reimplement the wait command when replacing the base unit cycling logic. - int * p_stack = (int *)&unit; - int ret_addr = p_stack[-1]; - if (ret_addr == SET_SELECTED_UNIT_TO_ISSUE_WAIT_COMMAND_RET && unit == NULL && this->Current_Unit != NULL) { - // Give the unit a waiting level higher than the minimum among all units already set to wait. This ensures that this unit does not get - // immediately picked up again by the cycling logic unless it's the only selectable unit left. This also means that the first unit set - // to wait will be the first cycled to once all the non-waiting units have been moved (it's the only one at level 1). I consider that - // an advantage. - int min_others_waiting_level = INT_MAX; - bool any_others_waiting = false; - FOR_TABLE_ENTRIES (tei, &is->waiting_units) - if (tei.key != this->Current_Unit->Body.ID) { - any_others_waiting = true; - if (tei.value < min_others_waiting_level) - min_others_waiting_level = tei.value; - } - itable_insert (&is->waiting_units, this->Current_Unit->Body.ID, any_others_waiting ? min_others_waiting_level + 1 : 1); - } - - if (unit != NULL) { - is->last_selected_unit.initial_x = is->last_selected_unit.last_x = unit->Body.X; - is->last_selected_unit.initial_y = is->last_selected_unit.last_y = unit->Body.Y; - is->last_selected_unit.type_id = unit->Body.UnitTypeID; - is->last_selected_unit.ptr = unit; - itable_remove (&is->waiting_units, unit->Body.ID); // Clear waiting record when waiting unit is selected - } - - if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD) - clear_selectable_units_list (this, false); - - bool redraw = false; - if (is->current_config.show_ai_city_location_desirability_if_settler) { - int new_perspective = -1; - if (unit != NULL) { - int unit_type_id = unit->Body.UnitTypeID; - int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; - new_perspective = (worker_actions >= 1 && (worker_actions & (UCV_Build_City)) && !is_worker(unit)) ? p_main_screen_form->Player_CivID : -1; - } - - if (new_perspective != is->city_loc_display_perspective) { - is->city_loc_display_perspective = new_perspective; - redraw = true; - } - } - - Main_Screen_Form_set_selected_unit (this, __, unit, param_2); - - // If selecting a new unit, must insert it into the list to ensure it's actually selected. - if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && unit != NULL) { - UnitIDList_insert_before (&this->selectable_units, __, unit->Body.ID, NULL); - this->unit_cycle_cursor = this->selectable_units.first; - } - - if (redraw && ! this->is_now_loading_game) - p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); -} - -Unit * __fastcall -patch_Main_Screen_Form_find_next_unit_for_cycling (Main_Screen_Form * this) -{ - if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) - return Main_Screen_Form_find_next_unit_for_cycling (this); - - else { - int least_difference = INT_MAX; - Unit * least_different_unit = NULL; - int sx = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_x : is->last_selected_unit.last_x, - sy = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_y : is->last_selected_unit.last_y; - for (int n = 0; n <= p_units->LastIndex; n++) { - Unit * unit = get_unit_ptr (n); - if (unit != NULL && unit->Body.CivID == this->Player_CivID && Unit_can_cycle_to (unit)) { - int distance = not_above (1<<15, int_abs (unit->Body.X - sx) + int_abs (unit->Body.Y - sy)); - - bool other_type, not_duplicate; { - if (is->last_selected_unit.type_id == unit->Body.UnitTypeID) { - other_type = false; - if (is->last_selected_unit.ptr != NULL) - not_duplicate = ! are_units_duplicate (&is->last_selected_unit.ptr->Body, &unit->Body, false); - else - not_duplicate = true; - } else - other_type = not_duplicate = true; - } - - int wait_level = itable_look_up_or (&is->waiting_units, unit->Body.ID, 0); - - int difference = ((int)wait_level << 20) + (distance << 2) + ((int)other_type << 1) + (int)not_duplicate; - if (difference < least_difference) { - least_difference = difference; - least_different_unit = unit; - } - } - } - this->completed_unit_cycle = least_different_unit == NULL; - return least_different_unit; - } -} - -void __fastcall -patch_City_m22 (City * this, int edx, bool param_1) -{ - int * p_stack = (int *)¶m_1; - int ret_addr = p_stack[-1]; - - City_m22 (this, __, param_1); - - // If the base game method failed to find a new thing for city to build, we've been called by the methods that complete a previous build, and - // the city is owned by the UI controller, the game will crash because there will be no default option for the build selector popup. If we're - // configured to fix that, suggest Wealth for the new build or, failing that, any buildable unit or improvement. - if ( this->Body.Order_Type == 0 - && is->current_config.patch_failure_to_find_new_city_build - && this->Body.CivID == p_main_screen_form->Player_CivID - && ( ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_1 - || ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_2 - || ret_addr == CITY_M22_TO_SPAWN_UNIT_IF_DONE_RETURN)) { - - // Search for an improvement-type order we can build. Choose Wealth if possible, otherwise just pick the first thing that can be built - for (int n = 0; n < p_bic_data->ImprovementsCount; n++) - if (patch_City_can_build_improvement (this, __, n, true)) { - if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { - this->Body.Order_Type = COT_Improvement; - this->Body.Order_ID = n; - break; - } else if (this->Body.Order_Type == 0) { - this->Body.Order_Type = COT_Improvement; - this->Body.Order_ID = n; - } - } - - // If we still don't have a build, pick the first buildable unit - if (this->Body.Order_Type == 0) - for (int n = 0; n < p_bic_data->UnitTypeCount; n++) - if (patch_City_can_build_unit (this, __, n, true, 0, false)) { - this->Body.Order_Type = COT_Unit; - this->Body.Order_ID = n; - break; - } - } -} - -int __fastcall -patch_PCX_Image_process_dom_adv_turn_count_text (PCX_Image * this, int edx, char * str) -{ - if (is->current_config.reformat_turns_remaining_on_domestic_advisor_screen) { - char * start = strstr (str, p_advisor_internal_form->Labels[16].S); // Search for "turns" - if (start == NULL) - start = strstr (str, p_advisor_internal_form->Labels[17].S); // Search for "turn" - - if (start != NULL) { - *start = toupper (*start); // Upcase first letter of "turn/s" - - char s[64]; // Must be same size as "str" param, which is a 64-byte stack-allocated string - snprintf (s, sizeof s, "%.*s %s", start - str, str, start); // Reprint string with space before "Turn/s" - s[(sizeof s) - 1] = '\0'; - memcpy (str, s, sizeof s); - } - } - - return PCX_Image_process_text (this, __, str); -} - -int -compare_menu_unit_items (void const * a, void const * b) -{ - return MenuUnitItem_should_appear_after ((MenuUnitItem *)a, __, (MenuUnitItem *)b) ? 1 : -1; -} - -int __fastcall -patch_MenuUnitList_get_length_before_sorting (MenuUnitList * this) -{ - int length = MenuUnitList_get_length (this); - - if (is->current_config.patch_passengers_out_of_order_on_menu && length > 0) { - qsort (this->items, length, sizeof this->items[0], compare_menu_unit_items); - - // Fix any units not being listed immediately after the unit they're contained in - // First, loop over all units in the list, stopping at each that might contain others - for (int n = 0; n < length - 1; n++) { - Unit * container = this->items[n].unit; - if ((int)container > 1 && // original code checks if unit ptrs are NULL or equal to 1 - p_bic_data->UnitTypes[container->Body.UnitTypeID].Transport_Capacity > 0) { - - // Advance iterator "j" past the container and past any empty slots or correctly positioned units right after it - int j = n + 1; - while (j < length && ((int)this->items[j].unit <= 1 || this->items[j].unit->Body.Container_Unit == container->Body.ID)) - j++; - - // Check the rest of the list for out-of-place passengers - for (int k = j + 1; k < length; k++) { - if ((int)this->items[k].unit > 1 && this->items[k].unit->Body.Container_Unit == container->Body.ID) { - - // Move item from index "k" to index "j" and advance "j" past it - MenuUnitItem moved = this->items[k]; - memmove (&this->items[j + 1], &this->items[j], (k - j) * sizeof this->items[0]); - this->items[j] = moved; - j++; - } - } - } - } - - // The caller is checking if the length is > 0 before sorting the list. Since we've already sorted it, return 0. - return 0; - } else - return length; -} - -void __fastcall -patch_Map_finalize_params_for_scenario_map (Map * this) -{ - Map_finalize_params (this); - - enum barbarian_activity_override barb_override = is->current_config.override_barbarian_activity_level_for_scenario_maps; - if (barb_override != BAO_NONE) { - if (barb_override == BAO_RANDOM) { - LARGE_INTEGER time; - QueryPerformanceCounter (&time); - int r = this->Seed ^ time.u.LowPart; // The map seed will be the same every time so incorporate some entropy - this->World.Final_Barbarians_Activity = rand_int (&r, __, 5) - 1; - } else - this->World.Final_Barbarians_Activity = clamp (-1, 3, barb_override); - } -} - -Unit * __fastcall -patch_Unit_select_army_member_for_combat (Unit * this, int edx, int param_1, char param_2) -{ - if (is->current_config.patch_empty_army_combat_crash) { - int unit_count = 0; - Tile * tile = tile_at (this->Body.X, this->Body.Y); - if (tile != NULL && tile != p_null_tile) { - FOR_UNITS_ON (uti, tile) { - Unit * unit = uti.unit; - if ((unit != NULL) && (unit->Body.Container_Unit == this->Body.ID)) - unit_count += Unit_count_contained_units (unit) + 1; - } - } - if (unit_count == 0) - return this; - } - - return Unit_select_army_member_for_combat (this, __, param_1, param_2); -} - -int __fastcall -patch_Tile_check_water_for_canal_move_to_adjacent_tile_dest (Tile * this) -{ - if ((this != NULL) && (this != p_null_tile) && - is->current_config.enable_districts && - is->current_config.enable_canal_districts && - (is->coast_walk_unit != NULL) && - (p_bic_data->UnitTypes[is->coast_walk_unit->Body.UnitTypeID].Unit_Class == UTC_Sea)) { - struct district_instance * inst = get_district_instance (this); - if ((inst != NULL) && - (inst->district_id == CANAL_DISTRICT_ID) && - district_is_complete (this, inst->district_id)) - return 1; - } - - return this->vtable->m35_Check_Is_Water (this); -} - -// TCC requires a main function be defined even though it's never used. -int main () { return 0; } +#include "stdlib.h" +#include "stdio.h" + +#include "C3X.h" + +void (WINAPI ** p_OutputDebugStringA) (char * lpOutputString) = ADDR_ADDR_OUTPUTDEBUGSTRINGA; +short (WINAPI ** p_GetAsyncKeyState) (int vKey) = ADDR_ADDR_GETASYNCKEYSTATE; +FARPROC (WINAPI ** p_GetProcAddress) (HMODULE hModule, char const * lpProcName) = ADDR_ADDR_GETPROCADDRESS; +HMODULE (WINAPI ** p_GetModuleHandleA) (char const * lpModuleName) = ADDR_ADDR_GETMODULEHANDLEA; +int (WINAPI ** p_MessageBoxA) (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) = ADDR_ADDR_MESSAGEBOXA; + +struct injected_state * is = ADDR_INJECTED_STATE; + +// To be used as placeholder second argument so that we can imitate thiscall convention with fastcall +#define __ 0 + +// Many Windows and C standard library functions have to be loaded dynamically with GetProcAddress and the addresses are stored in the injected +// state. This is covered up with macros, which is not something I would normally do, but in this case it's very useful because it means the code in +// common.c can be shared by the patcher and the injected code. +#define VirtualProtect is->VirtualProtect +#define CloseHandle is->CloseHandle +#define CreateFileA is->CreateFileA +#define GetFileSize is->GetFileSize +#define ReadFile is->ReadFile +#define LoadLibraryA is->LoadLibraryA +#define FreeLibrary is->FreeLibrary +#define MessageBoxA is->MessageBoxA +#define MultiByteToWideChar is->MultiByteToWideChar +#define WideCharToMultiByte is->WideCharToMultiByte +#define GetLastError is->GetLastError +#define QueryPerformanceCounter is->QueryPerformanceCounter +#define QueryPerformanceFrequency is->QueryPerformanceFrequency +#define GetLocalTime is->GetLocalTime +#define TransparentBlt is->TransparentBlt +#define snprintf is->snprintf +#define malloc is->malloc +#define calloc is->calloc +#define realloc is->realloc +#define free is->free +#define strtol is->strtol +#define strtof is->strtof +#define strncmp is->strncmp +#define strcmp is->strcmp +#define _stricmp is->_stricmp +#define strlen is->strlen +#define strncpy is->strncpy +#define strcpy is->strcpy +#define strdup is->strdup +#define strstr is->strstr +#define qsort is->qsort +#define memcmp is->memcmp +#define memcpy is->memcpy +#define tolower is->tolower +#define toupper is->toupper + +#include "common.c" + +#define TRADE_SCROLL_BUTTON_ID_LEFT 0x222001 +#define TRADE_SCROLL_BUTTON_ID_RIGHT 0x222002 + +// Must match size of button images in descbox.pcx +#define MOD_INFO_BUTTON_WIDTH 102 +#define MOD_INFO_BUTTON_HEIGHT 17 + +#define MOD_INFO_BUTTON_ID 0x222003 + +#define PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID 0x222004 +#define PEDIA_MULTIPAGE_PREV_BUTTON_ID 0x222005 + +#define TILE_FLAG_ROAD 0x1 +#define TILE_FLAG_RAILROAD 0x2 +#define TILE_FLAG_MINE 0x4 +#define TILE_FLAG_IRRIGATION 0x8 + +#define NEIGHBORHOOD_DISTRICT_ID 0 +#define WONDER_DISTRICT_ID 1 +#define DISTRIBUTION_HUB_DISTRICT_ID 2 +#define AERODROME_DISTRICT_ID 3 +#define NATURAL_WONDER_DISTRICT_ID 4 +#define PORT_DISTRICT_ID 5 +#define CENTRAL_RAIL_HUB_DISTRICT_ID 6 +#define ENERGY_GRID_DISTRICT_ID 7 +#define BRIDGE_DISTRICT_ID 8 +#define CANAL_DISTRICT_ID 9 +#define GREAT_WALL_DISTRICT_ID 10 + +#define MAX_DISTRICT_VARIANT_COUNT 5 +#define MAX_DISTRICT_ERA_COUNT 4 +#define MAX_DISTRICT_COLUMN_COUNT 10 + +// Max grid of tiles that an AI will evaluate a candidate bridge or canal for, +// used to limit computational complexity +#define AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES 10 + +enum { NAMED_TILE_MENU_ID = 0x90 }; + +char const * const hotseat_replay_save_path = "Saves\\Auto\\ai-move-replay-before-interturn.SAV"; +char const * const hotseat_resume_save_path = "Saves\\Auto\\ai-move-replay-resume.SAV"; + +// Need to define memmove for use by TCC when generated code for functions that return a struct +void * +memmove (void * dest, void const * src, size_t size) +{ + return is->memmove (dest, src, size); +} + +// Also need to define memset for some reason +void * +memset (void * dest, int ch, size_t count) +{ + for (size_t n = 0; n < count; n++) + ((char *)dest)[n] = ch; + return dest; +} + +// Computes num/denom randomly rounded off so that E[rand_div (x,y)] = (float)x/y +// As an example: E[rand_div (6, 5)] = 1.2, it will return 1 with 80% probability and 2 with 20% prob. +int +rand_div (int num, int denom) +{ + int q = num / denom, + r = num % denom; + return q + (rand_int (p_rand_object, __, denom) < r); +} + +bool +are_tiles_adjacent (int ax, int ay, int bx, int by) +{ + int x_dist = int_abs (ax - bx), + y_dist = int_abs (ay - by); + + // Handle edge wrapping by counting from the opposite direction if it would be shorter + if (p_bic_data->Map.Flags & 1) { // if map wraps horizontally + int width = p_bic_data->Map.Width; + if (x_dist > (width>>1)) + x_dist = width - x_dist; + } + if (p_bic_data->Map.Flags & 2) { // if map wraps vertically + int height = p_bic_data->Map.Height; + if (y_dist > (height>>1)) + y_dist = height - y_dist; + } + + return (x_dist + y_dist) == 2; +} + +int +compute_wrapped_component (int diff, int size, bool wraps) +{ + if (! wraps || (size <= 0)) + return diff; + + int half = size >> 1; + if (diff > half) + diff = size - diff; + return diff; +} + +void +compute_wrapped_deltas (int ax, int ay, int bx, int by, int * out_dx, int * out_dy) +{ + int dx = int_abs (ax - bx); + int dy = int_abs (ay - by); + bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; + bool wraps_vert = (p_bic_data->Map.Flags & 2) != 0; + dx = compute_wrapped_component (dx, p_bic_data->Map.Width, wraps_horiz); + dy = compute_wrapped_component (dy, p_bic_data->Map.Height, wraps_vert); + if (out_dx != NULL) + *out_dx = dx; + if (out_dy != NULL) + *out_dy = dy; +} + +int +compute_wrapped_manhattan_distance (int ax, int ay, int bx, int by) +{ + int dx, dy; + compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); + return dx + dy; +} + +int +compute_wrapped_chebyshev_distance (int ax, int ay, int bx, int by) +{ + int dx, dy; + compute_wrapped_deltas (ax, ay, bx, by, &dx, &dy); + return (dx > dy) ? dx : dy; +} + +bool +tile_has_resource (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + int resource_type = tile->vtable->m39_Get_Resource_Type (tile); + return (resource_type >= 0) && (resource_type < p_bic_data->ResourceTypeCount); +} + +City * +get_city_ptr (int id) +{ + if ((p_cities->Cities != NULL) && + (id >= 0) && (id <= p_cities->LastIndex)) { + City_Body * body = p_cities->Cities[id].City; + if (body != NULL) { + City * city = (City *)((char *)body - offsetof (City, Body)); + if (city != NULL) + return city; + } + } + return NULL; +} + +// Forward declarations for unit counter system (defined after their dependencies) +enum recognizable_parse_result parse_unit_counter_group (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_group); +enum recognizable_parse_result parse_counter_rule (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_rule); + +// Declare various functions needed for districts and hard to untangle and reorder here +void __fastcall patch_City_recompute_yields_and_happiness (City * this); +void __fastcall patch_Map_build_trade_network (Map * this); +bool __fastcall patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value); +bool __fastcall patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y); +bool __fastcall patch_City_has_resource (City * this, int edx, int resource_id); +bool __fastcall patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2); +char __fastcall patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing); +void __fastcall patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7); +bool can_build_district_on_tile (Tile * tile, int district_id, int civ_id); +bool city_can_build_district (City * city, int district_id); +bool leader_can_build_district (Leader * leader, int district_id); +bool wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id); +bool find_civ_trait_id_by_name (struct string_slice const * name, int * out_id); +bool find_civ_culture_id_by_name (struct string_slice const * name, int * out_id); +Tile * find_tile_for_district (City * city, int district_id, int * out_x, int * out_y); +struct district_instance * get_district_instance (Tile * tile); +struct named_tile_entry * get_named_tile_entry (Tile * tile); +bool city_has_required_district (City * city, int district_id); +bool district_is_complete (Tile * tile, int district_id); +bool city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id); +void clear_city_district_request (City * city, int district_id); +void set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y); +bool city_radius_contains_tile (City * city, int tile_x, int tile_y); +void on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y); +bool ai_move_district_worker (Unit * worker, struct district_worker_record * rec); +bool has_active_building (City * city, int improv_id); +bool tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv); +void recompute_distribution_hub_totals (); +void get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y); +void wrap_tile_coords (Map * map, int * x, int * y); +int count_neighborhoods_in_city_radius (City * city); +int count_utilized_neighborhoods_in_city_radius (City * city); +char * copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes); +bool city_has_resource_r (City * city, int resource_id, int max_generated_resource_id); + +struct pause_for_popup { + bool done; // Set to true to exit for loop + bool redundant; // If true, this pause would overlap a previous one and so should not be counted + long long ts_before; +}; + +struct pause_for_popup +pfp_init () +{ + struct pause_for_popup tr; + tr.done = false; + tr.redundant = is->paused_for_popup; + if (! tr.redundant) { + is->paused_for_popup = true; + QueryPerformanceCounter ((LARGE_INTEGER *)&tr.ts_before); + } + return tr; +} + +void +pfp_finish (struct pause_for_popup * pfp) +{ + if ((! pfp->redundant) && (! pfp->done)) { + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + is->time_spent_paused_during_popup += ts_after - pfp->ts_before; + is->paused_for_popup = false; + } + pfp->done = true; +} + +#define WITH_PAUSE_FOR_POPUP for (struct pause_for_popup pfp = pfp_init (); ! pfp.done; pfp_finish (&pfp)) + +int __fastcall +patch_show_popup (void * this, int edx, int param_1, int param_2) +{ + int tr; + WITH_PAUSE_FOR_POPUP { + is->show_popup_was_called = 1; + tr = show_popup (this, __, param_1, param_2); + } + return tr; +} + +void +pop_up_in_game_error (char const * msg) +{ + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); + PopupForm_add_text (popup, __, (char *)msg, false); + patch_show_popup (popup, __, 0, 0); +} + +void +memoize (int val) +{ + if (is->memo_len < is->memo_capacity) + is->memo[is->memo_len++] = val; + else { + int new_capacity = not_below (100, 2 * is->memo_capacity); + int * new_memo = malloc (new_capacity * sizeof is->memo[0]); + if (new_memo != NULL) { + for (int n = 0; n < is->memo_len; n++) + new_memo[n] = is->memo[n]; + free (is->memo); + is->memo = new_memo; + is->memo_capacity = new_capacity; + is->memo[is->memo_len++] = val; + } + } + +} + +void +clear_memo () +{ + is->memo_len = 0; +} + +// The maximum possible cultural neighbor index. We don't bother dealing with indices beyond this b/c it's the last tile in the seventh ring. Also +// equals one less than the tile count up to & inc. the seventh ring b/c of the zeroth tile. +#define MAX_CULTURAL_NI 192 + +// Number of workable tiles including the city center for each workable radius +unsigned char const workable_tile_counts[8] = {1, 9, 21, 37, 61, 89, 137, 193}; + +char const cultural_ni_to_diffs[(MAX_CULTURAL_NI + 1) * 2] = +{ + 0, 0, + +// first ring + 1, -1, 2, 0, 1, 1, 0, 2, -1, 1, -2, 0, -1, -1, + 0, -2, + +// second ring + 1, -3, 2, -2, 3, -1, 3, 1, 2, 2, 1, 3, -1, 3, -2, 2, + -3, 1, -3, -1, -2, -2, -1, -3, + +// third ring + 0, -4, 4, 0, 0, 4, -4, 0, 2, -4, 3, -3, 4, -2, 4, 2, + 3, 3, 2, 4, -2, 4, -3, 3, -4, 2, -4, -2, -3, -3, -2, -4, + +// fourth ring + 1, -5, 5, -1, 5, 1, 1, 5, -1, 5, -5, 1, -5, -1, -1, -5, + 0, -6, 6, 0, 0, 6, -6, 0, 3, -5, 4, -4, 5, -3, 5, 3, + 4, 4, 3, 5, -3, 5, -4, 4, -5, 3, -5, -3, -4, -4, -3, -5, + +// fifth ring + 1, -7, 2, -6, 6, -2, 7, -1, 7, 1, 6, 2, 2, 6, 1, 7, + -1, 7, -2, 6, -6, 2, -7, 1, -7, -1, -6, -2, -2, -6, -1, -7, + 4, -6, 5, -5, 6, -4, 6, 4, 5, 5, 4, 6, -4, 6, -5, 5, + -6, 4, -6, -4, -5, -5, -4, -6, + +// sixth ring + 0, -8, 8, 0, 0, 8, -8, 0, 1, -9, 2, -8, 3, -7, 7, -3, + 8, -2, 9, -1, 9, 1, 8, 2, 7, 3, 3, 7, 2, 8, 1, 9, + -1, 9, -2, 8, -3, 7, -7, 3, -8, 2, -9, 1, -9, -1, -8, -2, + -7, -3, -3, -7, -2, -8, -1, -9, 4, -8, 5, -7, 6, -6, 7, -5, + 8, -4, 8, 4, 7, 5, 6, 6, 5, 7, 4, 8, -4, 8, -5, 7, + -6, 6, -7, 5, -8, 4, -8, -4, -7, -5, -6, -6, -5, -7, -4, -8, + +// seventh ring + 0, -10, 10, 0, 0, 10, -10, 0, 1, -11, 2, -10, 3, -9, 9, -3, + 10, -2, 11, -1, 11, 1, 10, 2, 9, 3, 3, 9, 2, 10, 1, 11, + -1, 11, -2, 10, -3, 9, -9, 3, -10, 2, -11, 1, -11, -1, -10, -2, + -9, -3, -3, -9, -2, -10, -1, -11, 4, -10, 5, -9, 6, -8, 7, -7, + 8, -6, 9, -5, 10, -4, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, + 5, 9, 4, 10, -4, 10, -5, 9, -6, 8, -7, 7, -8, 6, -9, 5, + -10, 4, -10, -4, -9, -5, -8, -6, -7, -7, -6, -8, -5, -9, -4, -10 +}; + +// Like neighbor_index_to_diff, but enumerates tiles in an order that matches cultural border expansion. Only valid for 0 <= neighbor_index <= MAX_CULTURAL_NI. +void __cdecl +patch_ni_to_diff_for_work_area (int neighbor_index, int * x_disp, int * y_disp) +{ + if (neighbor_index <= 0) { + *x_disp = *y_disp = 0; + return; + } else if (neighbor_index > MAX_CULTURAL_NI) + neighbor_index = neighbor_index % (MAX_CULTURAL_NI + 1); + + int i = neighbor_index << 1; + char const * p = &cultural_ni_to_diffs[neighbor_index << 1]; + *x_disp = p[0]; + *y_disp = p[1]; +} + +int __fastcall +patch_City_find_min_value_tile (City * this) +{ + int tr = City_find_min_value_tile (this); + + // The original function has been edited to enumerate tiles in our custom order matching cultural borders instead of the game's original + // order. It returns a neighbor index from that enumeration. We must convert it to standard order if it's beyond the range where the two + // enumerations overlap. + if (tr >= 21) + tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; + + return tr; +} + +int __fastcall +patch_City_find_best_tile_to_work (City * this, int edx, Unit * worker, bool param_2) +{ + int tr = City_find_best_tile_to_work (this, __, worker, param_2); + if (tr >= 21) + tr = (tr <= MAX_CULTURAL_NI) ? is->cultural_ni_to_standard[tr] : 0; + return tr; +} + +bool __fastcall +City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 21) && (neighbor_index <= MAX_CULTURAL_NI)) + neighbor_index = is->cultural_ni_to_standard[neighbor_index]; + return City_stop_working_tile (this, __, neighbor_index); +} + +int __fastcall +patch_Map_compute_ni_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + // Within the first two rings, there's no difference b/w the standard and custom "work area" neighbor indices so fall back to the base game's + // function in that case. + if (is->workable_tile_count <= 21) + return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); + + // If the work area has been expanded, compute the neighbor index then check that it's within the area. Ignore the limit we were passed and + // instead use the number of tiles in the workable area, doubled to cover the difference between cultural vs standard enumeration. + else { + int ni = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, 2 * is->workable_tile_count); + if ((ni >= 0) && (ni <= ARRAY_LEN (is->ni_to_work_radius)) && + (is->ni_to_work_radius[ni] >= 0) && + (is->ni_to_work_radius[ni] <= is->current_config.city_work_radius)) + return ni; + else + return -1; + } +} + +int __fastcall +patch_Map_m28_find_cnter_neigh_point_for_work_area (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + int ret_addr = ((int *)&x_home)[-1]; + if (ret_addr != ADDR_FIND_CENTER_NP_SPOTLIGHT_RET) + return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); + else + return patch_Map_compute_ni_for_work_area (this, __, x_home, y_home, x_neigh, y_neigh, 500); +} + +int +get_work_ring_limit_by_culture (City * city) +{ + if (is->current_config.work_area_limit == WAL_NONE) + return INT_MAX; + else { + int lower_lim = (is->current_config.work_area_limit == WAL_CULTURAL_MIN_2) ? 2 : 1; + return not_below (lower_lim, city->Body.cultural_level); + } +} + +int +get_work_ring_limit_by_improvements (City * city) +{ + if (is->current_config.count_work_area_improvements == 0) + return INT_MAX; + else { + int maxRadius = 0; + int bonusRadius = 0; + for (int n = 0; n < is->current_config.count_work_area_improvements; n++) { + struct work_area_improvement * work_area_improvement = &is->current_config.work_area_improvements[n]; + if (work_area_improvement->work_area_radius_limit > maxRadius && + (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { + maxRadius = work_area_improvement->work_area_radius_limit; + } + if (work_area_improvement->work_area_radius_bonus > 0 && + (work_area_improvement->improv_id == -1 || has_active_building (city, work_area_improvement->improv_id))) { + bonusRadius += work_area_improvement->work_area_radius_bonus; + } + } + return maxRadius + bonusRadius; + } +} + +int +get_work_ring_limit_total (City * city) +{ + int cultureLimit = get_work_ring_limit_by_culture(city); + int improvementLimit = get_work_ring_limit_by_improvements(city); + if (cultureLimit < improvementLimit) + return cultureLimit; + return improvementLimit; +} + +bool __fastcall +patch_City_controls_tile (City * this, int edx, int neighbor_index, bool consider_enemy_units) +{ + // Check that this tile is not outside the city's work area. We've deleted a check from the base game code that verifies the n.i. is within 21 + // tiles so we can replicate it here in a way that also works for an expanded work area. + int work_radius = ((neighbor_index >= 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) ? is->ni_to_work_radius[neighbor_index] : -1; + if ((work_radius > is->current_config.city_work_radius) || (work_radius < 0)) + return false; + + int work_ring_limit = get_work_ring_limit_total (this); + if (work_radius > work_ring_limit) { + + // May consider this tile within the limit if any adjacent tiles are within the limit & within borders + bool exempt_from_limit; + if (is->current_config.work_area_limit != WAL_CULTURAL_OR_ADJACENT) + exempt_from_limit = false; + else if (neighbor_index >= 9) { + exempt_from_limit = false; + int center_x, center_y; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, ¢er_x, ¢er_y); + int neighbors_checked = 0; + for (int ni = 1; ni < ARRAY_LEN (is->ni_to_work_radius); ni++) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, ni, &nx, &ny); + if (are_tiles_adjacent (center_x, center_y, nx, ny)) { + neighbors_checked++; + int wr = is->ni_to_work_radius[ni]; + Tile * neighbor; + if (((wr >= 0) && (wr <= work_ring_limit)) && + (neighbor = tile_at (nx, ny)) && + (neighbor->vtable->m38_Get_Territory_OwnerID (neighbor) == this->Body.CivID)) { + exempt_from_limit = true; + break; + } + } + if (neighbors_checked == 8) + break; + } + } else + exempt_from_limit = true; + + if (! exempt_from_limit) + return false; + } + + if (neighbor_index >= 0) { + int tile_x, tile_y; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + // Check if the tile itself is a completed district (includes natural wonders) + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id)) + return false; + + // Check if the tile is covered by a distribution hub + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + return false; + } + } + } + } + + return City_controls_tile (this, __, neighbor_index, consider_enemy_units); +} + +bool __fastcall +patch_City_controls_tile_conv_ni (City * this, int edx, int neighbor_index, bool consider_enemy_units) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return patch_City_controls_tile (this, __, is->cultural_ni_to_standard[neighbor_index], consider_enemy_units); + else + return false; +} + +bool __fastcall +patch_City_stop_working_tile_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return City_stop_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); + else + return false; +} + +bool __fastcall +patch_City_start_working_tile_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return City_start_working_tile (this, __, is->cultural_ni_to_standard[neighbor_index]); + else + return false; +} + +void __fastcall +patch_City_add_or_remove_tile_yield_conv_ni (City * this, int edx, int neighbor_index, bool add_else_remove) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + City_add_or_remove_tile_yield (this, __, is->cultural_ni_to_standard[neighbor_index], add_else_remove); +} + +bool __fastcall +patch_City_is_neighboring_tile_in_area_conv_ni (City * this, int edx, int neighbor_index) +{ + if ((neighbor_index >= 0) && (neighbor_index <= MAX_CULTURAL_NI)) + return City_is_neighboring_tile_in_area (this, __, is->cultural_ni_to_standard[neighbor_index]); + else + return false; +} + +int +get_city_screen_center_y (City * city) +{ + int y = city->Body.Y; + if (p_bic_data->is_zoomed_out) + return y + 7; // when zoomed out, shift map up to center city + else if (is->current_config.city_work_radius >= 3) + return y + 4; // when work radius is 3, shift map up one extra tile so as not to overlap citizen heads + else + return y + 2; // base game behavior +} + +void __fastcall +patch_Main_Screen_Form_bring_cnter_view_city_focus (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) +{ + // If the city we're viewing can work tiles in the 4+ ring then zoom out the map display to show them + int effective_radius = not_above (get_work_ring_limit_total (p_city_form->CurrentCity), is->current_config.city_work_radius); + if (is->current_config.work_area_limit == WAL_CULTURAL_OR_ADJACENT) + effective_radius = not_above (is->current_config.city_work_radius, effective_radius + 1); + if (effective_radius >= 4 && is->current_config.auto_zoom_city_screen_for_large_work_areas) + p_bic_data->is_zoomed_out = true; + + Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); +} + +void __fastcall +patch_Main_Screen_Form_bring_cnter_view_city_arrow (Main_Screen_Form * this, int edx, int x, int y, int param_3, bool always_update_tile_bounds, bool param_5) +{ + Main_Screen_Form_bring_tile_into_view (this, __, x, get_city_screen_center_y (p_city_form->CurrentCity), param_3, always_update_tile_bounds, param_5); +} + +void tile_index_to_coords (Map * map, int index, int * out_x, int * out_y); + +Tile * __fastcall +patch_Map_get_tile_for_work_area_drawing (Map * this, int edx, int index) +{ + Tile * tr = Map_get_tile (this, __, index); + + if (tr != p_null_tile) { + int x, y; + tile_index_to_coords (this, index, &x, &y); + City * viewing_city = p_city_form->CurrentCity; + int ni = Map_compute_neighbor_index (this, __, viewing_city->Body.X, viewing_city->Body.Y, x, y, 1000); + if ((ni > 0) && ! patch_City_controls_tile (viewing_city, __, ni, false)) + tr = p_null_tile; + } + + return tr; +} + +// Resets is->current_config to the base config and updates the list of config names. Does NOT re-apply machine code edits. +void +reset_to_base_config () +{ + struct c3x_config * cc = &is->current_config; + + for (int n = 0; n < ARRAY_LEN (cc->limit_units_per_tile); n++) + cc->limit_units_per_tile[n] = 0; + + table_deinit (&cc->exclude_types_from_units_per_tile_limit); + + for (int n = 0; n < COUNT_PERFUME_KINDS; n++) + stable_deinit (&cc->perfume_specs[n]); + + // Free building-unit prereqs table + FOR_TABLE_ENTRIES (tei, &cc->building_unit_prereqs) { + if ((tei.value & 1) == 0) + free ((void *)tei.value); + } + table_deinit (&cc->building_unit_prereqs); + + // Free list of mills + if (cc->mills != NULL) { + free (cc->mills); + cc->mills = NULL; + cc->count_mills = 0; + } + + // Free list of AI multi-city start extra palaces + if (cc->ai_multi_start_extra_palaces != NULL) { + free (cc->ai_multi_start_extra_palaces); + cc->ai_multi_start_extra_palaces = NULL; + cc->count_ai_multi_start_extra_palaces = 0; + cc->ai_multi_start_extra_palaces_capacity = 0; + } + + table_deinit (&cc->limit_defensive_retreat_on_water_to_types); + table_deinit (&cc->can_bombard_only_sea_tiles); + + // Free set of PTW artillery types and list of converted types + table_deinit (&cc->ptw_arty_types); + if (is->charmed_types_converted_to_ptw_arty != NULL) { + free (is->charmed_types_converted_to_ptw_arty); + is->charmed_types_converted_to_ptw_arty = NULL; + is->count_charmed_types_converted_to_ptw_arty = 0; + is->charmed_types_converted_to_ptw_arty_capacity = 0; + } + + // Free era alias lists + if (cc->civ_era_alias_lists != NULL) { + for (int n = 0; n < cc->count_civ_era_alias_lists; n++) { + struct civ_era_alias_list * list = &cc->civ_era_alias_lists[n]; + free (list->key); + for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) + free (list->aliases[k]); + } + free (cc->civ_era_alias_lists); + cc->civ_era_alias_lists = NULL; + cc->count_civ_era_alias_lists = 0; + } + if (cc->leader_era_alias_lists != NULL) { + for (int n = 0; n < cc->count_leader_era_alias_lists; n++) { + struct leader_era_alias_list * list = &cc->leader_era_alias_lists[n]; + free (list->key); + for (int k = 0; k < ERA_ALIAS_LIST_CAPACITY; k++) { + free (list->aliases[k]); + free (list->titles[k]); + } + } + free (cc->leader_era_alias_lists); + cc->leader_era_alias_lists = NULL; + cc->count_leader_era_alias_lists = 0; + } + + // Free list of work_area_improvements + if (cc->work_area_improvements != NULL) { + free (cc->work_area_improvements); + cc->work_area_improvements = NULL; + cc->count_work_area_improvements = 0; + } + + // Free aircraft victory animation string + if (cc->aircraft_victory_animation != NULL) { + free (cc->aircraft_victory_animation); + cc->aircraft_victory_animation = NULL; + } + + if (cc->great_wall_auto_build_wonder_name != NULL) { + free (cc->great_wall_auto_build_wonder_name); + cc->great_wall_auto_build_wonder_name = NULL; + } + + if (cc->unit_counter_groups != NULL) { + for (int n = 0; n < cc->count_unit_counter_groups; n++) { + free (cc->unit_counter_groups[n].name); + free (cc->unit_counter_groups[n].type_ids); + } + free (cc->unit_counter_groups); + cc->unit_counter_groups = NULL; + cc->count_unit_counter_groups = 0; + } + + if (cc->counter_rules != NULL) { + for (int n = 0; n < cc->count_counter_rules; n++) { + free (cc->counter_rules[n].attacker_group); + free (cc->counter_rules[n].defender_group); + free (cc->counter_rules[n].district_name); + } + free (cc->counter_rules); + cc->counter_rules = NULL; + cc->count_counter_rules = 0; + } + + // Free unit limits table + FOR_TABLE_ENTRIES (tei, &cc->unit_limits) + free ((void *)tei.value); + stable_deinit (&cc->unit_limits); + + // Free the linked list of loaded config names and the string name contained in each one + if (is->loaded_config_names != NULL) { + struct loaded_config_name * next = is->loaded_config_names; + while (next != NULL) { + struct loaded_config_name * to_free = next; + next = next->next; + free (to_free->name); + free (to_free); + } + } + + // Overwrite the current config with the base config + memcpy (&is->current_config, &is->base_config, sizeof is->current_config); + + // These fields are heap-allocated and must not be inherited from base_config + // (base_config never owns valid pointers for them) + is->current_config.unit_counter_groups = NULL; + is->current_config.count_unit_counter_groups = 0; + is->current_config.counter_rules = NULL; + is->current_config.count_counter_rules = 0; + + // Recreate loaded config names list with just the base config + is->loaded_config_names = malloc (sizeof *is->loaded_config_names); + is->loaded_config_names->name = strdup ("(base)"); + is->loaded_config_names->next = NULL; + + // Update IS variable that's tied to a config value + is->workable_tile_count = workable_tile_counts[is->current_config.city_work_radius]; +} + +struct id_list { + int length; + int capacity; + int ids[0]; +}; + +struct id_list * +alloc_id_list (int capacity, struct id_list const * copy) +{ + struct id_list * tr = malloc ((sizeof *tr) + capacity * sizeof(tr->ids[0])); + tr->length = 0; + tr->capacity = capacity; + if (copy != NULL) { + int new_len = not_above (capacity, copy->length); + for (int n = 0; n < new_len; n++) + tr->ids[n] = copy->ids[n]; + tr->length = new_len; + } + return tr; +} + +// This is the largest ID that will be stored inline inside sidtables. The amount here must be smaller than any pointer we'd get from malloc since the +// sidtable code compares values against this amount to determine which are inlined values versus pointers. +#define SID_TABLE_MAX_INLINE_ID 10000 + +void +sidtable_deinit (struct table * t) +{ + FOR_TABLE_ENTRIES (tei, t) { + free ((void *)tei.key); + if (tei.value > SID_TABLE_MAX_INLINE_ID) + free ((void *)tei.value); + } + table_deinit (t); +} + +void +sidtable_append (struct table * t, struct string_slice const * key, int id) +{ + // Expand or allocate table as needed + if (t->len >= table_capacity (t) / 2) + table__expand (t, hash_str, compare_str_keys); + + size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); + int * entry = &((int *)TABLE__BASE (t))[2*index]; + if (table__is_occupied (t, index)) { // If key is already in the table + int prev_val = entry[1]; + if (prev_val <= SID_TABLE_MAX_INLINE_ID) { // If prev value is an id, convert it to a list + struct id_list * new_list = alloc_id_list (2, NULL); + new_list->ids[0] = prev_val; + new_list->ids[1] = id; + new_list->length = 2; + entry[1] = (int)new_list; + } else { // Else, prev value is a list so append the new ID to it + struct id_list * list = (void *)prev_val; + if (list->length >= list->capacity) { // Expand list if necessary + struct id_list * new_list = alloc_id_list (2 * list->capacity, list); + entry[1] = (int)new_list; + free (list); + list = new_list; + } + list->ids[list->length] = id; + list->length++; + } + } else { // Key is not in the table, add it for the first time + entry[0] = (int)extract_slice (key); + if (id <= SID_TABLE_MAX_INLINE_ID) // Write ID inline if possible + entry[1] = id; + else { // Otherwise create a list for this one ID + struct id_list * new_list = alloc_id_list (2, NULL); + new_list->ids[0] = id; + new_list->length = 1; + entry[1] = (int)new_list; + } + table__set_occupation (t, index, 1); + t->len++; + } +} + +bool +sidtable_get_by_index (struct table const * t, size_t index, int ** out_ids, int * out_count) +{ + size_t capacity = table_capacity (t); + if ((capacity > 0) && (index < capacity) && table__is_occupied (t, index)) { + int * entry = &((int *)TABLE__BASE (t))[2*index]; + int val = entry[1]; + if (val <= SID_TABLE_MAX_INLINE_ID) { // Value is an ID + *out_ids = &entry[1]; + *out_count = 1; + } else { + struct id_list * list = (void *)val; + *out_ids = &list->ids[0]; + *out_count = list->length; + } + return true; + } else + return false; +} + +bool +sidtable_look_up (struct table const * t, char const * key, int ** out_ids, int * out_count) +{ + if (t->len > 0) { + size_t index = table__place (t, compare_str_keys, (int)key, hash_str ((int)key)); + return sidtable_get_by_index (t, index, out_ids, out_count); + } else + return false; +} + +bool +sidtable_look_up_slice (struct table const * t, struct string_slice const * key, int ** out_ids, int * out_count) +{ + if (t->len > 0) { + size_t index = table__place (t, compare_slice_and_str_keys, (int)key, hash_slice ((int)key)); + return sidtable_get_by_index (t, index, out_ids, out_count); + } else + return false; +} + +struct error_line { + char text[200]; + struct error_line * next; +}; + +struct error_line * +add_error_line (struct error_line ** p_lines) +{ + struct error_line * tr = calloc (1, sizeof *tr); + + struct error_line ** p_prev = p_lines; + while (*p_prev != NULL) + p_prev = &(*p_prev)->next; + *p_prev = tr; + + return tr; +} + +void +add_unrecognized_line (struct error_line ** p_lines, struct string_slice const * name) +{ + struct error_line * line = add_error_line (p_lines); + char s[100]; + snprintf (line->text, sizeof line->text, "^ %.*s", name->len, name->str); + line->text[(sizeof line->text) - 1] = '\0'; +} + +void +free_error_lines (struct error_line * lines) +{ + while (lines != NULL) { + struct error_line * next = lines->next; + free (lines); + lines = next; + } +} + +bool +find_improv_id_by_name (struct string_slice const * name, int * out) +{ + Improvement * improv; + if (name->len <= sizeof improv->Name) + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { + *out = n; + return true; + } + return false; +} + +// start_id specifies where the search will start. It's useful for finding multiple type IDs with the same name, which commonly happens due to the +// game duplicating unit types. +bool +find_unit_type_id_by_name (struct string_slice const * name, int start_id, int * out) +{ + UnitType * unit_type; + if (name->len <= sizeof unit_type->Name) + for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) + if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { + *out = n; + return true; + } + return false; +} + +bool +find_resource_id_by_name (struct string_slice const * name, int * out) +{ + Resource_Type * res_type; + if (name->len <= sizeof res_type->Name) + for (int n = 0; n < p_bic_data->ResourceTypeCount; n++) + if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { + *out = n; + return true; + } + return false; +} + +bool +find_animation_type_by_name (struct string_slice const * name, bool lower_case, AnimationType * out) +{ + for (int n_anim = 0; n_anim < COUNT_ANIMATION_TYPES; n_anim++) + if (strlen (animation_names[n_anim]) == name->len) { + bool all_chars_match = true; + for (int k = 0; k < name->len; k++) { + int c = animation_names[n_anim][k]; + if (lower_case) + c = tolower (c); + if (c != name->str[k]) { + all_chars_match = false; + break; + } + } + if (all_chars_match) { + *out = n_anim; + return true; + } + } + return false; +} + +enum game_object_kind { + GOK_UNIT_TYPE = 0, + GOK_BUILDING, + GOK_RESOURCE, + GOK_TECHNOLOGY, + GOK_GOVERNMENT, + + COUNT_GAME_OBJECT_KINDS +}; + +bool +find_game_object_id_by_name (enum game_object_kind kind, struct string_slice const * name, int start_id, int * out) +{ + switch (kind) { + case GOK_UNIT_TYPE: { + UnitType * unit_type; + if (name->len <= sizeof unit_type->Name) + for (int n = start_id; n < p_bic_data->UnitTypeCount; n++) + if (slice_matches_str (name, p_bic_data->UnitTypes[n].Name)) { + *out = n; + return true; + } + return false; + } + case GOK_BUILDING: { + Improvement * improv; + if (name->len <= sizeof improv->Name) + for (int n = start_id; n < p_bic_data->ImprovementsCount; n++) + if (slice_matches_str (name, p_bic_data->Improvements[n].Name.S)) { + *out = n; + return true; + } + return false; + } + case GOK_RESOURCE: { + Resource_Type * res_type; + if (name->len <= sizeof res_type->Name) + for (int n = start_id; n < p_bic_data->ResourceTypeCount; n++) + if (slice_matches_str (name, p_bic_data->ResourceTypes[n].Name)) { + *out = n; + return true; + } + return false; + } + case GOK_TECHNOLOGY: { + Advance * adv; + if (name->len <= sizeof adv->Name) + for (int n = start_id; n < p_bic_data->AdvanceCount; n++) + if (slice_matches_str (name, p_bic_data->Advances[n].Name)) { + *out = n; + return true; + } + return false; + } + case GOK_GOVERNMENT: { + Government * govt; + if (name->len <= sizeof govt->Name) + for (int n = start_id; n < p_bic_data->GovernmentsCount; n++) + if (slice_matches_str (name, p_bic_data->Governments[n].Name.S)) { + *out = n; + return true; + } + return false; + } + default: + return false; + } +} + +// Converts a build name (like "Spearman" or "Granary") into a City_Order struct. Returns whether or not any improvement or unit type was found under +// the given name. +bool +find_city_order_by_name (struct string_slice const * name, City_Order * out) +{ + int id; + if (find_improv_id_by_name (name, &id)) { + out->OrderID = id; + out->OrderType = COT_Improvement; + return true; + } else if (find_unit_type_id_by_name (name, 0, &id)) { + out->OrderID = id; + out->OrderType = COT_Unit; + return true; + } else + return false; +} + +// Returns a list of AI strat duplicates of the unit type with the given id. This means a list of all other unit types that are identical to the given +// one except were separated out so each can have only one AI strategy. Returns the total number of duplicates, which may be greater than dup_ids_len. +int +list_unit_type_duplicates (int type_id, int * out_dup_ids, int dup_ids_len) +{ + // type_id may be a duplicate itself. Find the base type so we can start assembling the array from there. Otherwise we may miss some. + int alt_for_id = p_bic_data->UnitTypes[type_id].alternate_strategy_for_id; + int base_type_id = (alt_for_id >= 0) ? alt_for_id : type_id; + + int tr = 0, current = base_type_id; + while (1) { + if (current != type_id) { + if (tr < dup_ids_len) + out_dup_ids[tr] = current; + tr++; + } + int next; + if (itable_look_up (&is->unit_type_duplicates, current, &next)) + current = next; + else + break; + } + + return tr; +} + +// A "recognizable" is something that contains the name of a unit, building, etc. When parsing one, it's possible for it to be grammatically valid but +// contain a name that doesn't match anything in the scenario data. That's a special kind of error. In that case, we record the error to report in a +// popup and continue parsing. +enum recognizable_parse_result { + RPR_OK = 0, + RPR_UNRECOGNIZED, + RPR_PARSE_ERROR +}; + +struct perfume_spec { + char name[36]; // Must be large enough to fit the name of a unit type or improvement + i31b value; // Int component stores amount, bool stores whether it's a percentage or not +}; + +enum recognizable_parse_result +parse_perfume_spec (char ** p_cursor, enum perfume_kind kind, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + char * cur = *p_cursor; + struct string_slice name; + City_Order unused_city_order; + int unused_id; + i31b value; + if (parse_string (&cur, &name) && + skip_punctuation (&cur, ':') && + parse_i31b (&cur, &value)) { + *p_cursor = cur; + + if (((kind == PK_PRODUCTION) && find_city_order_by_name (&name, &unused_city_order)) || + ((kind == PK_TECHNOLOGY) && find_game_object_id_by_name (GOK_TECHNOLOGY, &name, 0, &unused_id)) || + ((kind == PK_GOVERNMENT) && find_game_object_id_by_name (GOK_GOVERNMENT, &name, 0, &unused_id))) { + struct perfume_spec * out = out_perfume_spec; + snprintf (out->name, sizeof out->name, "%.*s", name.len, name.str); + out->name[(sizeof out->name) - 1] = '\0'; + out->value = value; + return RPR_OK; + } else { + add_unrecognized_line (p_unrecognized_lines, &name); + return RPR_UNRECOGNIZED; + } + } else + return RPR_PARSE_ERROR; +} + +enum recognizable_parse_result +parse_production_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + return parse_perfume_spec (p_cursor, PK_PRODUCTION, p_unrecognized_lines, out_perfume_spec); +} + +enum recognizable_parse_result +parse_technology_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + return parse_perfume_spec (p_cursor, PK_TECHNOLOGY, p_unrecognized_lines, out_perfume_spec); +} + +enum recognizable_parse_result +parse_government_perfume_spec (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_perfume_spec) +{ + return parse_perfume_spec (p_cursor, PK_GOVERNMENT, p_unrecognized_lines, out_perfume_spec); +} + +enum recognizable_parse_result +parse_mill (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_mill) +{ + char * cur = *p_cursor; + struct string_slice improv_name; + if (parse_string (&cur, &improv_name) && + skip_punctuation (&cur, ':')) { + + short flags = 0; + struct string_slice resource_name; + while (1) { + if (! parse_string (&cur, &resource_name)) + return RPR_PARSE_ERROR; + else if (slice_matches_str (&resource_name, "local")) flags |= MF_LOCAL; + else if (slice_matches_str (&resource_name, "no-tech-req")) flags |= MF_NO_TECH_REQ; + else if (slice_matches_str (&resource_name, "yields")) flags |= MF_YIELDS; + else if (slice_matches_str (&resource_name, "show-bonus")) flags |= MF_SHOW_BONUS; + else if (slice_matches_str (&resource_name, "hide-non-bonus")) flags |= MF_HIDE_NON_BONUS; + else + break; + } + + *p_cursor = cur; + int improv_id, resource_id; + int any_unrecognized = 0; + if (! find_improv_id_by_name (&improv_name, &improv_id)) { + add_unrecognized_line (p_unrecognized_lines, &improv_name); + any_unrecognized = 1; + } + if (! find_resource_id_by_name (&resource_name, &resource_id)) { + add_unrecognized_line (p_unrecognized_lines, &resource_name); + any_unrecognized = 1; + } + if (any_unrecognized) + return RPR_UNRECOGNIZED; + else { + struct mill * out = out_mill; + out->improv_id = improv_id; + out->resource_id = resource_id; + out->flags = flags; + return RPR_OK; + } + } else + return RPR_PARSE_ERROR; +} + +enum recognizable_parse_result +parse_era_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_or_civ_alias_list, bool leader_else_civ_name) +{ + char * cur = *p_cursor; + struct string_slice key; + if (parse_string (&cur, &key) && + skip_punctuation (&cur, ':')) { + + char * aliases[ERA_ALIAS_LIST_CAPACITY] = {0}; + char * titles[ERA_ALIAS_LIST_CAPACITY] = {0}; + int alias_count = 0, + female_bits = 0, + gender_specified_bits = 0; // For each alias, set to 1 if a gender was specified + struct string_slice alias; + while (1) { + if (parse_string (&cur, &alias)) { + if (alias_count < ERA_ALIAS_LIST_CAPACITY) + aliases[alias_count] = extract_slice (&alias); + + // If we're parsing a list of leader names, read in the gender & title if present + if (leader_else_civ_name) { + char * inner_cur = cur; + struct string_slice gender; + struct string_slice title = {0}; + if ( skip_punctuation (&inner_cur, '(') + && parse_string (&inner_cur, &gender) + && ( skip_punctuation (&inner_cur, ')') + || ( skip_punctuation (&inner_cur, ',') + && parse_string (&inner_cur, &title) + && skip_punctuation (&inner_cur, ')'))) + && ( slice_matches_str (&gender, "M") + || slice_matches_str (&gender, "m") + || slice_matches_str (&gender, "F") + || slice_matches_str (&gender, "f"))) { + if (alias_count < 32) { + if (slice_matches_str (&gender, "F") || slice_matches_str (&gender, "f")) + female_bits |= 1 << alias_count; + gender_specified_bits |= 1 << alias_count; + } + if (title.len > 0) + titles[alias_count] = extract_slice (&title); + cur = inner_cur; + } + } + + alias_count++; + } else + break; + } + if (alias_count == 0) + return RPR_PARSE_ERROR; + + *p_cursor = cur; + + // Check that "key" matches a noun, adjective, or formal name of any civ ("race") in the scenario data. Store that civ. + Race * race_matching_key = NULL; { + for (int n = 0; n < p_bic_data->RacesCount; n++) { + Race * race = &p_bic_data->Races[n]; + if ( ( leader_else_civ_name + && slice_matches_str (&key, race->LeaderName)) + || ( (! leader_else_civ_name) + && ( slice_matches_str (&key, race->AdjectiveName) + || slice_matches_str (&key, race->CountryName) + || slice_matches_str (&key, race->SingularName)))) { + race_matching_key = race; + break; + } + } + } + if (race_matching_key == NULL) { + add_unrecognized_line (p_unrecognized_lines, &key); + return RPR_UNRECOGNIZED; + } + + if (leader_else_civ_name) { + struct leader_era_alias_list * out = out_leader_or_civ_alias_list; + memset (out, 0, sizeof *out); // Make sure unspecified aliases & titles are NULL + out->key = extract_slice (&key); + for (int n = 0; n < alias_count; n++) { + out->aliases[n] = aliases[n]; + out->titles[n] = titles[n]; + } + + // Set gender bits + int unreplaced_bits = (race_matching_key->LeaderGender == 0) ? 0 : ~0; + out->gender_bits = (unreplaced_bits & ~gender_specified_bits) | female_bits; + + + } else { + struct civ_era_alias_list * out = out_leader_or_civ_alias_list; + memset (out, 0, sizeof *out); + out->key = extract_slice (&key); + for (int n = 0; n < alias_count; n++) + out->aliases[n] = aliases[n]; + } + + return RPR_OK; + } else + return RPR_PARSE_ERROR; +} + + +enum recognizable_parse_result +parse_civ_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_civ_era_alias_list) +{ + return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_civ_era_alias_list, false); +} + +enum recognizable_parse_result +parse_leader_name_alias_list (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_leader_era_alias_list) +{ + return parse_era_alias_list (p_cursor, p_unrecognized_lines, out_leader_era_alias_list, true); +} + +struct parsed_unit_type_limit { + char name[32]; // Same length as Name in Unit_Type + struct unit_type_limit limit; +}; + +enum recognizable_parse_result +parse_unit_type_limit (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_unit_type_limit) +{ + char * cur = *p_cursor; + struct parsed_unit_type_limit * out = out_parsed_unit_type_limit; + + struct string_slice name; + struct unit_type_limit limit = {0}; + if (skip_white_space (&cur) && + parse_string (&cur, &name) && + (name.len < (sizeof out->name)) && + skip_punctuation (&cur, ':')) { + + do { + int num; + if (! parse_int (&cur, &num)) + return RPR_PARSE_ERROR; + + struct string_slice ss; + if (parse_string (&cur, &ss)) { + if (slice_matches_str (&ss, "per-city")) + limit.per_city += num; + else if (slice_matches_str (&ss, "cities-per")) + limit.cities_per += num; + else + return RPR_PARSE_ERROR; + } else + limit.per_civ += num; + + } 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 { + add_unrecognized_line (p_unrecognized_lines, &name); + *p_cursor = cur; + return RPR_UNRECOGNIZED; + } + + } else + return RPR_PARSE_ERROR; +} + +enum recognizable_parse_result +parse_work_area_improvement (char ** p_cursor, struct error_line ** p_unrecognized_lines, void * out_parsed_work_area_improvement) +{ + char * cur = *p_cursor; + struct work_area_improvement * out = out_parsed_work_area_improvement; + out->improv_id = -1; + out->work_area_radius_limit = 0; + out->work_area_radius_bonus = 0; + + struct string_slice improv_name; + if (skip_white_space (&cur) && + parse_string (&cur, &improv_name) && + skip_punctuation (&cur, ':')) { + + int num; + if (! parse_int (&cur, &num)) + return RPR_PARSE_ERROR; + + struct string_slice ss; + if (parse_string (&cur, &ss)) { + if (slice_matches_str (&ss, "extra")) + out->work_area_radius_bonus = num; + else + return RPR_PARSE_ERROR; + } else + out->work_area_radius_limit = num; + + int improv_id; + if (slice_matches_str (&improv_name, "default")) { + out->improv_id = -1; + *p_cursor = cur; + return RPR_OK; + } else if (find_improv_id_by_name (&improv_name, &improv_id)) { + out->improv_id = improv_id; + *p_cursor = cur; + return RPR_OK; + } else { + add_unrecognized_line (p_unrecognized_lines, &improv_name); + *p_cursor = cur; + return RPR_UNRECOGNIZED; + } + + } else + return RPR_PARSE_ERROR; +} + +// Recognizable items are appended to out_list/count, which must have been previously initialized (NULL/0 is valid for an empty list). +// If an error occurs while reading, returns the location of the error inside the slice, specifically the number of characters before the unreadable +// item. If no error occurs, returns -1. +int +read_recognizables (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + int item_size, + enum recognizable_parse_result (* parse_item) (char **, struct error_line **, void *), + void ** inout_list, + int * inout_count) +{ + if (s->len <= 0) + return -1; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + + bool success = false; + void * new_items = NULL; + int count_new_items = 0; + int new_items_capacity = 0; + void * temp_item = malloc (item_size); + + while (1) { + enum recognizable_parse_result result = parse_item (&cursor, p_unrecognized_lines, temp_item); + if (result != RPR_PARSE_ERROR) { + if (result == RPR_OK) { + reserve (item_size, &new_items, &new_items_capacity, count_new_items); + memcpy ((byte *)new_items + count_new_items * item_size, temp_item, item_size); + count_new_items++; + } + + if (skip_punctuation (&cursor, ',') && skip_white_space (&cursor)) + continue; + else if (skip_horiz_space (&cursor) && (*cursor == '\0')) { + success = true; + break; + } else + break; + } else + break; + } + + if (success && (count_new_items > 0)) { + *inout_list = realloc (*inout_list, (*inout_count + count_new_items) * item_size); + memcpy ((byte *)*inout_list + *inout_count * item_size, new_items, count_new_items * item_size); + *inout_count += count_new_items; + } + free (temp_item); + free (new_items); + free (extracted_slice); + return success ? -1 : cursor - extracted_slice; +} + +// Reads a "sidtable" from text. A sidtable maps strings to IDs of scenario objects. The string keys are also expected to be a type of scenario +// object. This method reads text such as: +// Factory: Battleship, Stable: Horseman Knight Cavalry, "Siege Workshop": Catapult Trebuchet +// and converts it to a table mapping "Factory", "Stable", and "Siege Workshop" to the corresponding unit type IDs. All new entries are appended to +// the given table; existing entries are not removed. +// Like read_recognizables, this method returns -1 for success or the location of an error if there is one. +int +read_sidtable (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + enum game_object_kind key_kind, + enum game_object_kind list_elem_kind, + struct table * sidtable) +{ + if (s->len <= 0) + return -1; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + while (1) { + struct string_slice key; + if (skip_white_space (&cursor) && parse_string (&cursor, &key)) { + int unused; + bool recognized_key = find_game_object_id_by_name (key_kind, &key, 0, &unused); + if (! recognized_key) + add_unrecognized_line (p_unrecognized_lines, &key); + if (! skip_punctuation (&cursor, ':')) + break; + struct string_slice elem_name; + while (skip_white_space (&cursor) && parse_string (&cursor, &elem_name)) { + bool recognized_elem = false; + int elem_id = -1; + while (find_game_object_id_by_name (list_elem_kind, &elem_name, elem_id + 1, &elem_id)) { + recognized_elem = true; + if (recognized_key) + sidtable_append (sidtable, &key, elem_id); + } + if (! recognized_elem) + add_unrecognized_line (p_unrecognized_lines, &elem_name); + } + skip_punctuation (&cursor, ','); + } else { + success = (*cursor == '\0'); + break; + } + } + + free (extracted_slice); + return success ? -1 : cursor - extracted_slice; +} + +// Like read_recognizables, returns -1 for success or the location of an error if there is one +int +read_building_unit_prereqs (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + struct table * building_unit_prereqs) +{ + if (s->len <= 0) + return -1; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + struct prereq { + int building_id; + struct string_slice unit_type_name; + } * new_prereqs = NULL; + int new_prereqs_capacity = 0; + int count_new_prereqs = 0; + + while (1) { + struct string_slice building_name; + if (skip_white_space (&cursor) && parse_string (&cursor, &building_name)) { + int building_id; + bool have_building_id = find_improv_id_by_name (&building_name, &building_id); + if (! have_building_id) + add_unrecognized_line (p_unrecognized_lines, &building_name); + if (! skip_punctuation (&cursor, ':')) + break; + struct string_slice unit_type_name; + while (skip_white_space (&cursor) && parse_string (&cursor, &unit_type_name)) { + int unused; + if (find_unit_type_id_by_name (&unit_type_name, 0, &unused)) { // if there is any by this name, later we'll deal with the possibility of multiple + if (have_building_id) { + reserve (sizeof new_prereqs[0], (void **)&new_prereqs, &new_prereqs_capacity, count_new_prereqs); + new_prereqs[count_new_prereqs++] = (struct prereq) { .building_id = building_id, .unit_type_name = unit_type_name }; + } + } else + add_unrecognized_line (p_unrecognized_lines, &unit_type_name); + } + skip_punctuation (&cursor, ','); + } else { + success = (*cursor == '\0'); + break; + } + } + + // If parsing succeeded, add the new prereq rules to the table + if (success) + for (int n = 0; n < count_new_prereqs; n++) { + struct prereq * prereq = &new_prereqs[n]; + + int unit_type_id = -1; + while (find_unit_type_id_by_name (&prereq->unit_type_name, unit_type_id + 1, &unit_type_id)) { + + // If this unit type ID is not already in the table, insert it paired with the encoded building ID + int prev_val; + if (! itable_look_up (building_unit_prereqs, unit_type_id, &prev_val)) + itable_insert (building_unit_prereqs, unit_type_id, (prereq->building_id << 1) | 1); + + // If the unit type ID is already associated with a building ID, create a list for both the old and new building IDs + else if (prev_val & 1) { + int * list = malloc (MAX_BUILDING_PREREQS_FOR_UNIT * sizeof *list); + for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) + list[n] = -1; + list[0] = prev_val >> 1; // Decode + list[1] = prereq->building_id; + itable_insert (building_unit_prereqs, unit_type_id, (int)list); + + // Otherwise, it's already associated with a list. Search the list for a free spot and fill it with the new building ID + } else { + int * list = (int *)prev_val; + for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) + if (list[n] < 0) { + list[n] = prereq->building_id; + break; + } + } + } + } + + + free (new_prereqs); + free (extracted_slice); + return success ? -1 : cursor - extracted_slice; +} + +// Reads a space-separated list of unit types like: +// Worker Galley "Gallic Swordsman" +// Looks up the type ID(s) for each name and inserts them into the unit_types table associated with a value of 1. +bool +read_unit_type_list (struct string_slice const * s, struct error_line ** p_unrecognized_lines, struct table * unit_types) +{ + if (s->len <= 0) + return true; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + while (1) { + struct string_slice name; + if (parse_string (&cursor, &name)) { + + int id = -1; + bool matched_any = false; + while (find_unit_type_id_by_name (&name, id + 1, &id)) { + itable_insert (unit_types, id, 1); + matched_any = true; + } + + if (! matched_any) + add_unrecognized_line (p_unrecognized_lines, &name); + + } else { + skip_white_space (&cursor); + success = *cursor == '\0'; + break; + } + } + + free (extracted_slice); + return success; +} + +bool +read_ai_multi_start_extra_palaces (struct string_slice const * s, + struct error_line ** p_unrecognized_lines, + int ** p_ai_multi_start_extra_palaces, + int * p_count_ai_multi_start_extra_palaces, + int * p_ai_multi_start_extra_palaces_capacity) +{ + if (s->len <= 0) + return true; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + bool success = false; + + while (1) { + struct string_slice name; + if (parse_string (&cursor, &name)) { + int id; + if (find_improv_id_by_name (&name, &id)) { + int count = *p_count_ai_multi_start_extra_palaces; + reserve (sizeof **p_ai_multi_start_extra_palaces, (void **)p_ai_multi_start_extra_palaces, p_ai_multi_start_extra_palaces_capacity, count); + (*p_ai_multi_start_extra_palaces)[count] = id; + *p_count_ai_multi_start_extra_palaces = count + 1; + } else + add_unrecognized_line (p_unrecognized_lines, &name); + + } else { + skip_white_space (&cursor); + success = *cursor == '\0'; + break; + } + } + + free (extracted_slice); + return success; +} + +bool +read_retreat_rules (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "standard" )) { *out_val = RR_STANDARD; return true; } + else if (slice_matches_str (&trimmed, "none" )) { *out_val = RR_NONE; return true; } + else if (slice_matches_str (&trimmed, "all-units" )) { *out_val = RR_ALL_UNITS; return true; } + else if (slice_matches_str (&trimmed, "if-faster" )) { *out_val = RR_IF_FASTER; return true; } + else if (slice_matches_str (&trimmed, "if-not-slower" )) { *out_val = RR_IF_NOT_SLOWER; return true; } + else if (slice_matches_str (&trimmed, "if-fast-and-not-slower")) { *out_val = RR_IF_FAST_AND_NOT_SLOWER; return true; } + else + return false; +} + +bool +read_line_drawing_override (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "never" )) { *out_val = LDO_NEVER; return true; } + else if (slice_matches_str (&trimmed, "wine" )) { *out_val = LDO_WINE; return true; } + else if (slice_matches_str (&trimmed, "always")) { *out_val = LDO_ALWAYS; return true; } + else + return false; +} + +bool +read_minimap_doubling_mode (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "never" )) { *out_val = MDM_NEVER; return true; } + else if (slice_matches_str (&trimmed, "high-def")) { *out_val = MDM_HIGH_DEF; return true; } + else if (slice_matches_str (&trimmed, "always" )) { *out_val = MDM_ALWAYS; return true; } + else + return false; +} + +bool +read_unit_cycle_search_criteria (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "standard" )) { *out_val = UCSC_STANDARD; return true; } + else if (slice_matches_str (&trimmed, "similar-near-start" )) { *out_val = UCSC_SIMILAR_NEAR_START; return true; } + else if (slice_matches_str (&trimmed, "similar-near-destination")) { *out_val = UCSC_SIMILAR_NEAR_DESTINATION; return true; } + else + return false; +} + +bool +read_no_ai_patrol_override (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "zero")) { *out_val = NAPO_ZERO; return true; } + else if (slice_matches_str (&trimmed, "one" )) { *out_val = NAPO_ONE; return true; } + else if (slice_matches_str (&trimmed, "none")) { *out_val = NAPO_NONE; return true; } + else + return false; +} + +bool +read_work_area_limit (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "none" )) { *out_val = WAL_NONE; return true; } + else if (slice_matches_str (&trimmed, "cultural" )) { *out_val = WAL_CULTURAL; return true; } + else if (slice_matches_str (&trimmed, "cultural-min-2" )) { *out_val = WAL_CULTURAL_MIN_2; return true; } + else if (slice_matches_str (&trimmed, "cultural-or-adjacent")) { *out_val = WAL_CULTURAL_OR_ADJACENT; return true; } + else + return false; +} + +bool +read_day_night_cycle_mode (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "off" )) { *out_val = DNCM_OFF; return true; } + else if (slice_matches_str (&trimmed, "timer" )) { *out_val = DNCM_TIMER; return true; } + else if (slice_matches_str (&trimmed, "user-time" )) { *out_val = DNCM_USER_TIME; return true; } + else if (slice_matches_str (&trimmed, "every-turn")) { *out_val = DNCM_EVERY_TURN; return true; } + else if (slice_matches_str (&trimmed, "specified" )) { *out_val = DNCM_SPECIFIED; return true; } + else + return false; +} + +bool +read_distribution_hub_yield_division_mode (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "flat" )) { *out_val = DHYDM_FLAT; return true; } + else if (slice_matches_str (&trimmed, "scale-by-city-count" )) { *out_val = DHYDM_SCALE_BY_CITY_COUNT; return true; } + else + return false; +} + +bool +read_ai_distribution_hub_build_strategy (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "auto" )) { *out_val = ADHBS_AUTO; return true; } + else if (slice_matches_str (&trimmed, "by-city-count" )) { *out_val = ADHBS_BY_CITY_COUNT; return true; } + else + return false; +} + +bool +read_ai_auto_build_great_wall_strategy (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "all-borders" )) { *out_val = AAGWS_ALL_BORDERS; return true; } + else if (slice_matches_str (&trimmed, "other-civ-bordered-only")) { *out_val = AAGWS_OTHER_CIV_BORDERED_ONLY; return true; } + else + return false; +} + +bool +read_tile_terrain_type_value (struct string_slice const * s, enum SquareTypes * out_type) +{ + if (s == NULL || out_type == NULL) + return false; + + struct string_slice trimmed = trim_string_slice (s, 1); + if (trimmed.len <= 0) + return false; + + struct { + char const * name; + int value; + } const entries[] = { + {"desert", SQ_Desert}, + {"deserts", SQ_Desert}, + {"plain", SQ_Plains}, + {"plains", SQ_Plains}, + {"grassland", SQ_Grassland}, + {"grasslands", SQ_Grassland}, + {"tundra", SQ_Tundra}, + {"tundras", SQ_Tundra}, + {"floodplain", SQ_FloodPlain}, + {"floodplains", SQ_FloodPlain}, + {"hill", SQ_Hills}, + {"hills", SQ_Hills}, + {"mountain", SQ_Mountains}, + {"mountains", SQ_Mountains}, + {"forest", SQ_Forest}, + {"forests", SQ_Forest}, + {"jungle", SQ_Jungle}, + {"jungles", SQ_Jungle}, + {"marsh", SQ_Swamp}, + {"marshes", SQ_Swamp}, + {"swamp", SQ_Swamp}, + {"swamps", SQ_Swamp}, + {"volcano", SQ_Volcano}, + {"volcanos", SQ_Volcano}, + {"coast", SQ_Coast}, + {"coasts", SQ_Coast}, + {"sea", SQ_Sea}, + {"seas", SQ_Sea}, + {"ocean", SQ_Ocean}, + {"oceans", SQ_Ocean}, + {"river", SQ_RIVER}, + {"rivers", SQ_RIVER}, + {"snow-volcano", SQ_SNOW_VOLCANO}, + {"snow-volcanos", SQ_SNOW_VOLCANO}, + {"snow-forest", SQ_SNOW_FOREST}, + {"snow-forests", SQ_SNOW_FOREST}, + {"snow-mountain", SQ_SNOW_MOUNTAIN}, + {"snow-mountains", SQ_SNOW_MOUNTAIN}, + {"any", SQ_INVALID} + }; + + for (int i = 0; i < (int)ARRAY_LEN (entries); i++) { + if (slice_matches_str (&trimmed, entries[i].name)) { + *out_type = (enum SquareTypes)entries[i].value; + return true; + } + } + + return false; +} + +unsigned int +square_type_mask_bit (enum SquareTypes type) +{ + if ((int)type < 0 || type > SQ_SNOW_MOUNTAIN) + return 0; + return (unsigned int)(1u << type); +} + +unsigned int +district_buildable_mine_mask_bit (void) +{ + return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 1)); +} + +unsigned int +district_buildable_irrigation_mask_bit (void) +{ + return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 2)); +} + +unsigned int +district_buildable_lake_mask_bit (void) +{ + return (unsigned int)(1u << (SQ_SNOW_MOUNTAIN + 3)); +} + +unsigned int +all_square_types_mask (void) +{ + return (unsigned int)((1u << (SQ_SNOW_MOUNTAIN + 1)) - 1); +} + +unsigned int +district_default_buildable_mask (void) +{ + return (unsigned int)DEFAULT_DISTRICT_BUILDABLE_MASK; +} + +bool +tile_has_snow_mountain (Tile * tile) +{ + return (tile != NULL) && (tile != p_null_tile) && tile->vtable->m29_Check_Mountain_Snowcap (tile); +} + +bool +tile_is_lake (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (! tile->vtable->m35_Check_Is_Water (tile)) + return false; + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + return false; + + int lake_size_threshold = 21; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + return continent->Body.TileCount <= lake_size_threshold; +} + +bool +tile_has_snow_volcano (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Volcano) + return false; + + int overlays = tile->vtable->m43_Get_field_30 (tile); + return (overlays & 0x100000) != 0; +} + +bool +tile_has_snow_forest (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Forest) + return false; + + int overlays = tile->vtable->m43_Get_field_30 (tile); + return (overlays & 0x100000) != 0; +} + +bool +tile_matches_square_type (Tile * tile, enum SquareTypes type) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + switch (type) { + case SQ_SNOW_MOUNTAIN: + return tile_has_snow_mountain (tile); + case SQ_SNOW_VOLCANO: + return tile_has_snow_volcano (tile); + case SQ_SNOW_FOREST: + return tile_has_snow_forest (tile); + case SQ_RIVER: + return tile->vtable->m37_Get_River_Code (tile) != 0; + default: + return tile->vtable->m50_Get_Square_BaseType (tile) == type; + } +} + +bool +tile_matches_square_type_mask (Tile * tile, unsigned int mask) +{ + if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) + return false; + + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + unsigned int base_bit = square_type_mask_bit (base_type); + if ((base_bit != 0) && ((mask & base_bit) != 0)) + return true; + + enum SquareTypes const special_types[] = {SQ_RIVER, SQ_SNOW_MOUNTAIN, SQ_SNOW_VOLCANO, SQ_SNOW_FOREST}; + for (int i = 0; i < (int)ARRAY_LEN (special_types); i++) { + enum SquareTypes stype = special_types[i]; + unsigned int bit = square_type_mask_bit (stype); + if ((mask & bit) && tile_matches_square_type (tile, stype)) + return true; + } + + unsigned int mine_bit = district_buildable_mine_mask_bit (); + if ((mask & mine_bit) && tile->vtable->m18_Check_Mines (tile, __, 0)) + return true; + + unsigned int irrigation_bit = district_buildable_irrigation_mask_bit (); + if ((mask & irrigation_bit) && tile->vtable->m17_Check_Irrigation (tile, __, 0)) + return true; + + unsigned int lake_bit = district_buildable_lake_mask_bit (); + if ((mask & lake_bit) && tile_is_lake (tile)) + return true; + + return false; +} + +bool +tile_matches_overlay_mask (Tile * tile, unsigned int mask) +{ + if ((tile == NULL) || (tile == p_null_tile) || (mask == 0)) + return false; + + unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); + if ((mask & DOM_MINE) && ((overlays & TILE_FLAG_MINE) != 0)) + return true; + if ((mask & DOM_IRRIGATION) && ((overlays & 0x00000008) != 0)) + return true; + if ((mask & DOM_FORTRESS) && ((overlays & 0x00000010) != 0)) + return true; + if ((mask & DOM_BARRICADE) && ((overlays & 0x10000000) != 0)) + return true; + if ((mask & DOM_OUTPOST) && ((overlays & 0x80000000) != 0)) + return true; + if ((mask & DOM_RADAR_TOWER) && ((overlays & 0x40000000) != 0)) + return true; + if ((mask & DOM_AIRFIELD) && ((overlays & 0x20000000) != 0)) + return true; + if ((mask & DOM_JUNGLE) && tile_matches_square_type (tile, SQ_Jungle)) + return true; + if ((mask & DOM_FOREST) && tile_matches_square_type (tile, SQ_Forest)) + return true; + if ((mask & DOM_SWAMP) && tile_matches_square_type (tile, SQ_Swamp)) + return true; + if ((mask & DOM_RIVER) && tile_matches_square_type (tile, SQ_RIVER)) + return true; + + return false; +} + +bool +read_natural_wonder_terrain_type (struct string_slice const * s, enum SquareTypes * out_type) +{ + enum SquareTypes parsed; + if (! read_tile_terrain_type_value (s, &parsed)) + return false; + + switch (parsed) { + case SQ_Desert: + case SQ_Plains: + case SQ_Grassland: + case SQ_Jungle: + case SQ_Tundra: + case SQ_FloodPlain: + case SQ_Swamp: + case SQ_Hills: + case SQ_Mountains: + case SQ_Forest: + case SQ_Volcano: + case SQ_SNOW_MOUNTAIN: + case SQ_SNOW_FOREST: + case SQ_SNOW_VOLCANO: + case SQ_Coast: + case SQ_Sea: + case SQ_Ocean: + *out_type = parsed; + return true; + + default: + return false; + } +} + +bool +read_direction_value (struct string_slice const * s, enum direction * out_dir) +{ + if (s == NULL || out_dir == NULL) + return false; + + struct string_slice trimmed = trim_string_slice (s, 1); + if (trimmed.len <= 0) + return false; + + if (slice_matches_str (&trimmed, "northeast")) { *out_dir = DIR_NE; return true; } + else if (slice_matches_str (&trimmed, "east" )) { *out_dir = DIR_E; return true; } + else if (slice_matches_str (&trimmed, "southeast")) { *out_dir = DIR_SE; return true; } + else if (slice_matches_str (&trimmed, "south" )) { *out_dir = DIR_S; return true; } + else if (slice_matches_str (&trimmed, "southwest")) { *out_dir = DIR_SW; return true; } + else if (slice_matches_str (&trimmed, "west" )) { *out_dir = DIR_W; return true; } + else if (slice_matches_str (&trimmed, "northwest")) { *out_dir = DIR_NW; return true; } + else if (slice_matches_str (&trimmed, "north" )) { *out_dir = DIR_N; return true; } + else + return false; +} + +bool +read_barbarian_activity_override (struct string_slice const * s, enum barbarian_activity_override * out) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (trimmed.len <= 0) + return false; + + bool found = false; + char * extracted = extract_slice (s); + + struct { + char * str; + enum barbarian_activity_override value; + } possibilities[] = {{ .str = "none" , .value = BAO_NONE }, + { .str = (*p_labels)[LBL_NO_BARBARIANS ], .value = BAO_NO_BARBARIANS }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 1], .value = BAO_SEDENTARY }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 2], .value = BAO_ROAMING }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 3], .value = BAO_RESTLESS }, + { .str = (*p_labels)[LBL_NO_BARBARIANS + 4], .value = BAO_RAGING }, + { .str = (*p_labels)[LBL_RANDOM_BARBS] , .value = BAO_RANDOM }, + { .str = "No Barbarians" , .value = BAO_NO_BARBARIANS }, + { .str = "Sedentary" , .value = BAO_SEDENTARY }, + { .str = "Roaming" , .value = BAO_ROAMING }, + { .str = "Restless" , .value = BAO_RESTLESS }, + { .str = "Raging" , .value = BAO_RAGING }, + { .str = "Random" , .value = BAO_RANDOM }}; + + // Check for exact match + for (int n = 0; n < ARRAY_LEN (possibilities); n++) + if (0 == strcmp (extracted, possibilities[n].str)) { + *out = possibilities[n].value; + found = true; + break; + } + + // If not found, check again ignoring case + if (! found) + for (int n = 0; n < ARRAY_LEN (possibilities); n++) + if (0 == _stricmp (extracted, possibilities[n].str)) { + *out = possibilities[n].value; + found = true; + break; + } + + free (extracted); + return found; +} + +struct parsable_field_bit { + char * name; + int bit_value; +}; + +bool +read_bit_field (struct string_slice const * s, struct parsable_field_bit const * bits, int count_bits, int * out_field) +{ + struct string_slice trimmed = trim_string_slice (s, 0); + s = &trimmed; + + int tr; + if (s->len <= 0) + tr = 0; + else if (slice_matches_str (s, "all")) + tr = ~0; + else { + tr = 0; + char * cursor = &s->str[0]; + char * s_end = &s->str[s->len]; + while (1) { + struct string_slice name; + + if (cursor >= s_end) + break; + else if (! parse_string (&cursor, &name)) { + skip_white_space (&cursor); + if (cursor >= s_end) + break; + else + return false; // Invalid character in value + } + + bool matched_any = false; + for (int n = 0; n < count_bits; n++) + if (slice_matches_str (&name, bits[n].name)) { + tr |= bits[n].bit_value; + matched_any = true; + break; + } + if (! matched_any) + return false; + } + } + *out_field = tr; + return true; +} + +int +read_units_per_tile_limit (struct string_slice const * s, int * out_limits) +{ + int single_val; + if (read_int (s, &single_val)) { + out_limits[0] = out_limits[1] = out_limits[2] = single_val; + return true; + + } else { + bool success = false; + char * extracted_slice = extract_slice (s); + char * cursor = extracted_slice; + int vals[3]; + if (parse_int (&cursor, &vals[0]) && parse_int (&cursor, &vals[1]) && parse_int (&cursor, &vals[2]) && + skip_horiz_space (&cursor) && (*cursor == '\0')) { + for (int n = 0; n < ARRAY_LEN (vals); n++) + out_limits[n] = vals[n]; + success = true; + } + free (extracted_slice); + return success; + } +} + +struct config_parsing { + char * file_path; + char * text; + char * cursor; + struct string_slice key; + int displayed_error_message; +}; + +enum config_parse_error { + CPE_GENERIC, + CPE_BAD_VALUE, + CPE_BAD_BOOL_VALUE, + CPE_BAD_INT_VALUE, + CPE_BAD_STACK_LIMIT_VALUE, + CPE_BAD_KEY +}; + +void +handle_config_error_at (struct config_parsing * p, char * error_loc, enum config_parse_error err) +{ + char err_msg[1000]; + if (! p->displayed_error_message) { + int line_no = 1; + for (char * c = p->text; c < error_loc; c++) + line_no += *c == '\n'; + + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); + snprintf (err_msg, sizeof err_msg, "Error reading \"%s\" on line %d.", p->file_path, line_no); + err_msg[(sizeof err_msg) - 1] = '\0'; + PopupForm_add_text (popup, __, err_msg, false); + + if (err == CPE_GENERIC) { + if (p->key.str != NULL) + snprintf (err_msg, sizeof err_msg, "^The last key successfully read was \"%.*s\".", p->key.len, p->key.str); + else + snprintf (err_msg, sizeof err_msg, "^Error occurred before any keys could be read."); + } else if (err == CPE_BAD_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid.", p->key.len, p->key.str); + else if (err == CPE_BAD_BOOL_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"true\" or \"false\".", p->key.len, p->key.str); + else if (err == CPE_BAD_INT_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected an integer.", p->key.len, p->key.str); + else if (err == CPE_BAD_STACK_LIMIT_VALUE) + snprintf (err_msg, sizeof err_msg, "^The value for \"%.*s\" is invalid. Expected \"false\", an integer, or a list of exactly three of those.", p->key.len, p->key.str); + else if (err == CPE_BAD_KEY) + snprintf (err_msg, sizeof err_msg, "^The key name \"%.*s\" is not recognized.", p->key.len, p->key.str); + err_msg[(sizeof err_msg) - 1] = '\0'; + PopupForm_add_text (popup, __, err_msg, false); + + patch_show_popup (popup, __, 0, 0); + p->displayed_error_message = 1; + } +} + +void +handle_config_error (struct config_parsing * p, enum config_parse_error err) +{ + handle_config_error_at (p, p->cursor, err); +} + +// Loads a config from the given file, layering it on top of is->current_config and appending its name to the list of loaded configs. Does NOT +// re-apply machine code edits. +void +load_config (char const * file_path, int path_is_relative_to_mod_dir) +{ + char err_msg[1000]; + struct c3x_config * cfg = &is->current_config; + + int full_path_size = 2 * MAX_PATH; + char * full_path = malloc (full_path_size); + if (path_is_relative_to_mod_dir) + snprintf (full_path, full_path_size, "%s\\%s", is->mod_rel_dir, file_path); + else + strncpy (full_path, file_path, full_path_size); + full_path[full_path_size - 1] = '\0'; + + char * text; { + char * utf8_text = file_to_string (full_path); + if (utf8_text == NULL) { + free (full_path); + return; + } + text = convert_from_utf8 (utf8_text, *p_code_page); + free (utf8_text); + if (text == NULL) { + snprintf (err_msg, sizeof err_msg, "Failed to re-encode contents of \"%s\". This file must contain UTF-8 text and only characters usable by Civ 3.", full_path); + err_msg[(sizeof err_msg) - 1] = '\0'; + pop_up_in_game_error (err_msg); + free (full_path); + return; + } + } + + struct perfume_spec_list { + struct perfume_spec * items; + int count; + } perfume_spec_lists[COUNT_PERFUME_KINDS] = {0}; + + struct parsed_unit_type_limit * parsed_unit_type_limits = NULL; + int parsed_unit_type_limit_count = 0; + + struct config_parsing p = { .file_path = full_path, .text = text, .cursor = text, .key = {0}, .displayed_error_message = 0 }; + struct error_line * unrecognized_lines = NULL; + while (1) { + skip_horiz_space (&p.cursor); + if (*p.cursor == '\0') + break; + else if (*p.cursor == '\n') + p.cursor++; // Continue to next line + else if (*p.cursor == ';') + skip_to_line_end (&p.cursor); // Skip comment line + else if (*p.cursor == '[') + skip_to_line_end (&p.cursor); // Skip section line + else if (parse_string (&p.cursor, &p.key) && skip_punctuation (&p.cursor, '=')) { // Parse key and equals sign + + struct string_slice value; + if (parse_string (&p.cursor, &value) || parse_bracketed_block (&p.cursor, &value)) { // Parse value + int ival, offset, recog_err_offset; + + // if key is for a boolean option + if (stable_look_up_slice (&is->boolean_config_offsets, &p.key, &offset)) { + if (read_int (&value, &ival)) + *((char *)cfg + offset) = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + + // if key is for an integer option + } else if (stable_look_up_slice (&is->integer_config_offsets, &p.key, &offset)) { + if (read_int (&value, &ival)) + *(int *)((byte *)cfg + offset) = ival; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + + // Handle city_work_radius separately from the other int options so we can clamp it and update the count var + } else if (slice_matches_str (&p.key, "city_work_radius")) { + if (read_int (&value, &ival)) { + cfg->city_work_radius = clamp (1, 7, ival); + is->workable_tile_count = workable_tile_counts[cfg->city_work_radius]; + } else + handle_config_error (&p, CPE_BAD_INT_VALUE); + + // if key is for something special + } else if (slice_matches_str (&p.key, "limit_units_per_tile")) { + if (! read_units_per_tile_limit (&value, &cfg->limit_units_per_tile[0])) + handle_config_error (&p, CPE_BAD_STACK_LIMIT_VALUE); + } else if (slice_matches_str (&p.key, "production_perfume") || slice_matches_str (&p.key, "perfume_specs")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct perfume_spec), + parse_production_perfume_spec, + (void **)&perfume_spec_lists[PK_PRODUCTION].items, + &perfume_spec_lists[PK_PRODUCTION].count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "technology_perfume")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct perfume_spec), + parse_technology_perfume_spec, + (void **)&perfume_spec_lists[PK_TECHNOLOGY].items, + &perfume_spec_lists[PK_TECHNOLOGY].count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "government_perfume")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct perfume_spec), + parse_government_perfume_spec, + (void **)&perfume_spec_lists[PK_GOVERNMENT].items, + &perfume_spec_lists[PK_GOVERNMENT].count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "building_prereqs_for_units")) { + if (0 <= (recog_err_offset = read_building_unit_prereqs (&value, &unrecognized_lines, &cfg->building_unit_prereqs))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "buildings_generating_resources")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct mill), + parse_mill, + (void **)&cfg->mills, + &cfg->count_mills))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_multi_start_extra_palaces")) { + if (! read_ai_multi_start_extra_palaces (&value, + &unrecognized_lines, + &cfg->ai_multi_start_extra_palaces, + &cfg->count_ai_multi_start_extra_palaces, + &cfg->ai_multi_start_extra_palaces_capacity)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_settler_perfume_on_founding")) { + if (! read_i31b (&value, &cfg->ai_settler_perfume_on_founding)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "land_retreat_rules")) { + if (! read_retreat_rules (&value, (int *)&cfg->land_retreat_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "sea_retreat_rules")) { + if (! read_retreat_rules (&value, (int *)&cfg->sea_retreat_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "draw_lines_using_gdi_plus")) { + if (! read_line_drawing_override (&value, (int *)&cfg->draw_lines_using_gdi_plus)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "double_minimap_size")) { + if (! read_minimap_doubling_mode (&value, (int *)&cfg->double_minimap_size)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "unit_cycle_search_criteria")) { + if (! read_unit_cycle_search_criteria (&value, (int *)&cfg->unit_cycle_search_criteria)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "override_no_ai_patrol")) { + if (! read_no_ai_patrol_override (&value, (int *)&cfg->override_no_ai_patrol)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "override_barbarian_activity_level_for_scenario_maps")) { + if (! read_barbarian_activity_override (&value, &cfg->override_barbarian_activity_level_for_scenario_maps)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "special_defensive_bombard_rules")) { + struct parsable_field_bit bits[] = { + {"lethal" , SDBR_LETHAL}, + {"not-invisible" , SDBR_NOT_INVISIBLE}, + {"aerial" , SDBR_AERIAL}, + {"blitz" , SDBR_BLITZ}, + {"docked-vs-land", SDBR_DOCKED_VS_LAND}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_defensive_bombard_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "special_zone_of_control_rules")) { + struct parsable_field_bit bits[] = { + {"lethal" , SZOCR_LETHAL}, + {"aerial" , SZOCR_AERIAL}, + {"amphibious" , SZOCR_AMPHIBIOUS}, + {"not-from-inside", SZOCR_NOT_FROM_INSIDE}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_zone_of_control_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "land_transport_rules")) { + struct parsable_field_bit bits[] = { + {"load-onto-boat" , LTR_LOAD_ONTO_BOAT}, + {"join-army" , LTR_JOIN_ARMY}, + {"no-defense-from-inside", LTR_NO_DEFENSE_FROM_INSIDE}, + {"no-escape" , LTR_NO_ESCAPE}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->land_transport_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "special_helicopter_rules")) { + struct parsable_field_bit bits[] = { + {"allow-on-carriers" , SHR_ALLOW_ON_CARRIERS}, + {"passenger-airdrop" , SHR_PASSENGER_AIRDROP}, + {"no-defense-from-inside", SHR_NO_DEFENSE_FROM_INSIDE}, + {"no-escape" , SHR_NO_ESCAPE}, + }; + if (! read_bit_field (&value, bits, ARRAY_LEN (bits), (int *)&cfg->special_helicopter_rules)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "work_area_limit")) { + if (! read_work_area_limit (&value, (int *)&cfg->work_area_limit)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "work_area_improvements")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct work_area_improvement), + parse_work_area_improvement, + (void **)&cfg->work_area_improvements, + &cfg->count_work_area_improvements))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "day_night_cycle_mode")) { + if (! read_day_night_cycle_mode (&value, (int *)&cfg->day_night_cycle_mode)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "distribution_hub_yield_division_mode")) { + if (! read_distribution_hub_yield_division_mode (&value, (int *)&cfg->distribution_hub_yield_division_mode)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_distribution_hub_build_strategy")) { + if (! read_ai_distribution_hub_build_strategy (&value, (int *)&cfg->ai_distribution_hub_build_strategy)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ai_auto_build_great_wall_strategy")) { + if (! read_ai_auto_build_great_wall_strategy (&value, (int *)&cfg->ai_auto_build_great_wall_strategy)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "great_wall_auto_build_wonder_name")) { + if (cfg->great_wall_auto_build_wonder_name != NULL) { + free (cfg->great_wall_auto_build_wonder_name); + cfg->great_wall_auto_build_wonder_name = NULL; + } + cfg->great_wall_auto_build_wonder_name = copy_trimmed_string_or_null (&value, 1); + cfg->great_wall_auto_build_wonder_improv_id = -1; + } else if (slice_matches_str (&p.key, "exclude_types_from_units_per_tile_limit")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->exclude_types_from_units_per_tile_limit)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "limit_defensive_retreat_on_water_to_types")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->limit_defensive_retreat_on_water_to_types)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "ptw_like_artillery_targeting")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->ptw_arty_types)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "can_bombard_only_sea_tiles")) { + if (! read_unit_type_list (&value, &unrecognized_lines, &cfg->can_bombard_only_sea_tiles)) + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "civ_aliases_by_era")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct civ_era_alias_list), + parse_civ_name_alias_list, + (void **)&cfg->civ_era_alias_lists, + &cfg->count_civ_era_alias_lists))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "leader_aliases_by_era")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct leader_era_alias_list), + parse_leader_name_alias_list, + (void **)&cfg->leader_era_alias_lists, + &cfg->count_leader_era_alias_lists))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "unit_limits")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct parsed_unit_type_limit), + parse_unit_type_limit, + (void **)&parsed_unit_type_limits, + &parsed_unit_type_limit_count))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "aircraft_victory_animation")) { + struct string_slice trimmed = trim_string_slice (&value, 1); + bool value_ok = false; + if (slice_matches_str (&trimmed, "none")) { + if (cfg->aircraft_victory_animation != NULL) { + free (cfg->aircraft_victory_animation); + cfg->aircraft_victory_animation = NULL; + } + value_ok = true; + } else if (trimmed.len > 0) { + AnimationType unused; + if (find_animation_type_by_name (&trimmed, true, &unused)) { + if (cfg->aircraft_victory_animation != NULL) + free (cfg->aircraft_victory_animation); + cfg->aircraft_victory_animation = extract_slice (&trimmed); + value_ok = true; + } + } + if (! value_ok) + handle_config_error (&p, CPE_BAD_VALUE); + + // if key is for an obsolete option + } else if (slice_matches_str (&p.key, "patch_disembark_immobile_bug")) { + if (read_int (&value, &ival)) + cfg->patch_blocked_disembark_freeze = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "anarchy_length_reduction_percent")) { + if (read_int (&value, &ival)) + cfg->anarchy_length_percent = 100 - ival; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + } else if (slice_matches_str (&p.key, "adjust_minimum_city_separation")) { + if (read_int (&value, &ival)) + cfg->minimum_city_separation = ival + 1; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + } else if (slice_matches_str (&p.key, "reduce_max_escorts_per_ai_transport")) { + if (read_int (&value, &ival)) + cfg->max_ai_naval_escorts = 3 - ival; + else + handle_config_error (&p, CPE_BAD_INT_VALUE); + } else if (slice_matches_str (&p.key, "retreat_rules")) { + int rules; + if (read_retreat_rules (&value, &rules)) { + cfg->land_retreat_rules = rules; + cfg->sea_retreat_rules = rules; + } else + handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "halve_ai_research_rate")) { + if (read_int (&value, &ival)) { + if (ival) // halving = true => set multiplier to 50, otherwise do nothing + cfg->ai_research_multiplier = 50; + } else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "enable_ai_two_city_start")) { + if (read_int (&value, &ival)) + cfg->ai_multi_city_start = (ival != 0) ? 2 : 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "polish_non_air_precision_striking")) { + if (read_int (&value, &ival)) + cfg->polish_precision_striking = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "promote_forbidden_palace_decorruption")) { + if (read_int (&value, &ival)) + cfg->promote_wonder_decorruption_effect = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "move_trade_net_object")) { + ; // No nothing. This setting no longer serves any purpose. + + // if key was previously misspelled + } else if (slice_matches_str (&p.key, "share_visibility_in_hoseat")) { + if (read_int (&value, &ival)) + cfg->share_visibility_in_hotseat = ival != 0; + else + handle_config_error (&p, CPE_BAD_BOOL_VALUE); + } else if (slice_matches_str (&p.key, "unit_group")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct unit_counter_group), + parse_unit_counter_group, + (void **)&cfg->unit_counter_groups, + &cfg->count_unit_counter_groups))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "counter_rule")) { + if (0 <= (recog_err_offset = read_recognizables (&value, + &unrecognized_lines, + sizeof (struct counter_rule), + parse_counter_rule, + (void **)&cfg->counter_rules, + &cfg->count_counter_rules))) + handle_config_error_at (&p, value.str + recog_err_offset, CPE_BAD_VALUE); + + } else { + handle_config_error (&p, CPE_BAD_KEY); + } + + + } else { // Failed to parse value + handle_config_error (&p, CPE_BAD_VALUE); + skip_to_line_end (&p.cursor); + } + + } else { // Failed to categorize line + handle_config_error (&p, CPE_GENERIC); + skip_to_line_end (&p.cursor); + } + } + + if (cfg->warn_about_unrecognized_names && (unrecognized_lines != NULL)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "Unrecognized names in %s:", full_path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + for (struct error_line * line = unrecognized_lines; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + patch_show_popup (popup, __, 0, 0); + } + + // Copy perfume specs from lists to tables + for (int n = 0; n < COUNT_PERFUME_KINDS; n++) { + struct table * table = &cfg->perfume_specs[n]; + struct perfume_spec_list * list = &perfume_spec_lists[n]; + if (list->items != NULL) { + for (int k = 0; k < list->count; k++) { + struct perfume_spec * ps = &list->items[k]; + stable_insert (table, ps->name, ps->value); + } + free (list->items); + } + } + + // Copy unit type limits from list to table + if (parsed_unit_type_limits != NULL) { + for (int n = 0; n < parsed_unit_type_limit_count; n++) { + struct parsed_unit_type_limit * parsed_lim = &parsed_unit_type_limits[n]; + struct unit_type_limit * lim_values = malloc (sizeof *lim_values); + *lim_values = parsed_lim->limit; + stable_insert (&cfg->unit_limits, parsed_lim->name, (int)lim_values); + } + free (parsed_unit_type_limits); + } + + free (text); + free_error_lines (unrecognized_lines); + + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = full_path; + new_lcn->next = NULL; + + top_lcn->next = new_lcn; +} + +bool +tile_coords_from_ptr (Map * map, Tile * tile, int * out_x, int * out_y) +{ + if ((tile == NULL) || (tile == p_null_tile) || (map == NULL)) + return false; + + int tile_count = map->TileCount; + for (int index = 0; index < tile_count; index++) { + Tile * candidate = Map_get_tile (map, __, index); + if (candidate == tile) { + tile_index_to_coords (map, index, out_x, out_y); + return true; + } + } + + return false; +} + +int +get_pending_district_request_key (int city_id, int district_id) +{ + if ((city_id < 0) || (district_id < 0)) + return -1; + unsigned int key = ((unsigned int)city_id << 16) | (unsigned int)(district_id & 0xffff); + return (int)key; +} + +struct pending_district_request * +find_pending_district_request (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0)) + return NULL; + + int civ_id = city->Body.CivID; + int city_id = city->Body.ID; + int key = get_pending_district_request_key (city_id, district_id); + if (key < 0) + return NULL; + + int stored; + if (itable_look_up (&is->city_pending_district_requests[civ_id], key, &stored)) { + struct pending_district_request * req = (struct pending_district_request *)stored; + if ((req != NULL) && (req->civ_id == civ_id) && (req->city_id == city_id) && (req->district_id == district_id)) { + if (req->city != city) + req->city = city; + return req; + } + } + return NULL; +} + +struct pending_district_request * +create_pending_district_request (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return NULL; + + struct pending_district_request * existing = find_pending_district_request (city, district_id); + if (existing != NULL) + return existing; + + int civ_id = city->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) + return NULL; + + struct pending_district_request * req = (struct pending_district_request *)calloc (1, sizeof *req); + if (req == NULL) + return NULL; + + req->city = city; + req->city_id = city->Body.ID; + req->civ_id = civ_id; + req->district_id = district_id; + req->assigned_worker_id = -1; + req->target_x = -1; + req->target_y = -1; + req->worker_assigned_turn = 0; + + int key = get_pending_district_request_key (req->city_id, district_id); + if (key < 0) { + free (req); + return NULL; + } + + char ss[200]; + snprintf (ss, sizeof ss, "create_pending_district_request: Creating pending district request for city %s (ID %d) district ID %d with key %d\n", + city->Body.CityName, city->Body.ID, district_id, key); + (*p_OutputDebugStringA) (ss); + + itable_insert (&is->city_pending_district_requests[civ_id], key, (int)req); + return req; +} + +struct pending_district_request * +find_pending_district_request_by_coords (City * city_or_null, int tile_x, int tile_y, int district_id) +{ + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + + int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((civ_id < 0) || (civ_id >= 32)) + return NULL; + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req == NULL) continue; + if (req->district_id != district_id) continue; + if (city_or_null != NULL) { + int city_id = city_or_null->Body.ID; + if (req->city_id != city_id) + continue; + req->city = city_or_null; + req->civ_id = city_or_null->Body.CivID; + } + if ((req->target_x == tile_x) && (req->target_y == tile_y)) + return req; + } + return NULL; +} + +bool +is_tile_earmarked_for_district (int tile_x, int tile_y) +{ + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req == NULL) continue; + if ((req->target_x == tile_x) && (req->target_y == tile_y)) + return true; + } + return false; +} + +struct district_instance * +get_district_instance (Tile * tile) +{ + if (tile == NULL || tile == p_null_tile) + return NULL; + + int stored_ptr; + if (! itable_look_up (&is->district_tile_map, (int)tile, &stored_ptr)) + return NULL; + + struct district_instance * inst = (struct district_instance *)stored_ptr; + + if ((inst == NULL) || (inst->district_id < 0) || (inst->district_id >= is->district_count)) + return NULL; + + return inst; +} + +struct wonder_district_info * +get_wonder_district_info (Tile * tile) +{ + if (tile == NULL || tile == p_null_tile) + return NULL; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return NULL; + + return &inst->wonder_info; +} + +void +remove_district_instance (Tile * tile) +{ + if (tile == NULL || tile == p_null_tile) + return; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + free (inst); + itable_remove (&is->district_tile_map, (int)tile); + } +} + +void +district_instance_set_coords (struct district_instance * inst, int tile_x, int tile_y) +{ + if (inst == NULL) + return; + + // Normalize coordinates to map bounds for consistency + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + inst->tile_x = tile_x; + inst->tile_y = tile_y; +} + +struct district_instance * +ensure_district_instance (Tile * tile, int district_id, int tile_x, int tile_y) +{ + if (tile == NULL || tile == p_null_tile) + return NULL; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + return inst; + } + + inst = (struct district_instance *)calloc (1, sizeof(struct district_instance)); + if (inst == NULL) + return NULL; + + inst->state = DS_UNDER_CONSTRUCTION; + inst->district_id = district_id; + inst->built_by_civ_id = -1; + inst->completed_turn = -1; + + // Initialize wonder_info (only relevant for wonder districts) + inst->wonder_info.state = WDS_UNUSED; + inst->wonder_info.city = NULL; + inst->wonder_info.city_id = -1; + inst->wonder_info.wonder_index = -1; + inst->natural_wonder_info.natural_wonder_id = -1; + + district_instance_set_coords (inst, tile_x, tile_y); + itable_insert (&is->district_tile_map, (int)tile, (int)inst); + return inst; +} + +bool +district_instance_get_coords (struct district_instance * inst, Tile * tile, int * out_x, int * out_y) +{ + if ((inst == NULL) || (out_x == NULL) || (out_y == NULL)) + return false; + + int x = inst->tile_x; + int y = inst->tile_y; + if ((x >= 0) && (y >= 0)) { + *out_x = x; + *out_y = y; + return true; + } + + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile_coords_from_ptr (&p_bic_data->Map, tile, &x, &y)) { + district_instance_set_coords (inst, x, y); + *out_x = x; + *out_y = y; + return true; + } + + return false; +} + +struct natural_wonder_district_config const * +get_natural_wonder_config_by_id (int natural_wonder_id) +{ + if (! is->current_config.enable_natural_wonders) + return NULL; + if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) + return NULL; + return &is->natural_wonder_configs[natural_wonder_id]; +} + +void +assign_natural_wonder_to_tile (Tile * tile, int tile_x, int tile_y, int natural_wonder_id) +{ + if (! is->current_config.enable_natural_wonders) + return; + if ((tile == NULL) || (tile == p_null_tile)) + return; + if ((natural_wonder_id < 0) || (natural_wonder_id >= is->natural_wonder_count)) + return; + + if (get_natural_wonder_config_by_id (natural_wonder_id) == NULL) + return; + + struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, tile_x, tile_y); + if (inst == NULL) + return; + + inst->district_id = NATURAL_WONDER_DISTRICT_ID; + inst->state = DS_COMPLETED; + inst->natural_wonder_info.natural_wonder_id = natural_wonder_id; + set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); +} + +int +apply_district_bonus_entries (struct district_instance * inst, + struct district_bonus_list const * extras, + int district_id) +{ + if ((inst == NULL) || (extras == NULL) || (extras->count <= 0)) + return 0; + + int tile_x = inst->tile_x; + int tile_y = inst->tile_y; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return 0; + + int bonus = 0; + for (int i = 0; i < extras->count; i++) { + struct district_bonus_entry const * entry = &extras->entries[i]; + if (entry->type == DBET_TILE) { + if (tile_matches_square_type (tile, entry->tile_type)) + bonus += entry->bonus; + } else if (entry->type == DBET_BUILDING) { + if (entry->building_id >= 0 && + tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, entry->building_id)) + bonus += entry->bonus; + } + } + + return bonus; +} + +void +get_effective_district_yields (struct district_instance * inst, + struct district_config const * cfg, + int * out_food, + int * out_shields, + int * out_gold, + int * out_science, + int * out_culture, + int * out_happiness) +{ + int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; + + if (cfg != NULL && is->current_config.enable_districts) { + food = cfg->food_bonus; + shields = cfg->shield_bonus; + gold = cfg->gold_bonus; + science = cfg->science_bonus; + culture = cfg->culture_bonus; + happiness = cfg->happiness_bonus; + + int district_id = (inst != NULL) ? inst->district_id : -1; + food += apply_district_bonus_entries (inst, &cfg->food_bonus_extras, district_id); + shields += apply_district_bonus_entries (inst, &cfg->shield_bonus_extras, district_id); + gold += apply_district_bonus_entries (inst, &cfg->gold_bonus_extras, district_id); + science += apply_district_bonus_entries (inst, &cfg->science_bonus_extras, district_id); + culture += apply_district_bonus_entries (inst, &cfg->culture_bonus_extras, district_id); + happiness += apply_district_bonus_entries (inst, &cfg->happiness_bonus_extras, district_id); + } + + if (inst != NULL && is->current_config.enable_natural_wonders && inst->district_id == NATURAL_WONDER_DISTRICT_ID) { + struct natural_wonder_district_config const * nwcfg = get_natural_wonder_config_by_id (inst->natural_wonder_info.natural_wonder_id); + if (nwcfg != NULL) { + food += nwcfg->food_bonus; + shields += nwcfg->shield_bonus; + gold += nwcfg->gold_bonus; + science += nwcfg->science_bonus; + culture += nwcfg->culture_bonus; + happiness += nwcfg->happiness_bonus; + } + } + + if (out_food != NULL) + *out_food = food; + if (out_shields != NULL) + *out_shields = shields; + if (out_gold != NULL) + *out_gold = gold; + if (out_science != NULL) + *out_science = science; + if (out_culture != NULL) + *out_culture = culture; + if (out_happiness != NULL) + *out_happiness = happiness; +} + +int +natural_wonder_min_distance_sq (int x, + int y, + struct wonder_location const * placements, + int placement_count) +{ + if ((placements == NULL) || (placement_count <= 0)) + return INT_MAX; + + int best = INT_MAX; + for (int i = 0; i < placement_count; i++) { + int dx, dy; + compute_wrapped_deltas (x, y, placements[i].x, placements[i].y, &dx, &dy); + int dist_sq = dx * dx + dy * dy; + if (dist_sq < best) + best = dist_sq; + } + return best; +} + +bool +continent_has_natural_wonder (int continent_id, + struct wonder_location const * placements, + int placement_count) +{ + if (continent_id < 0) + return false; + if ((placements == NULL) || (placement_count <= 0)) + return false; + + for (int i = 0; i < placement_count; i++) { + Tile * placed_tile = tile_at (placements[i].x, placements[i].y); + if ((placed_tile == NULL) || (placed_tile == p_null_tile)) + continue; + int placed_continent_id = placed_tile->vtable->m46_Get_ContinentID (placed_tile); + if (placed_continent_id == continent_id) + return true; + } + + return false; +} + +bool +natural_wonder_candidate_list_push (struct natural_wonder_candidate_list * list, Tile * tile, int tile_x, int tile_y) +{ + if (list == NULL) + return false; + + if (list->count >= list->capacity) { + int new_capacity = (list->capacity > 0) ? (list->capacity * 2) : 8; + struct natural_wonder_candidate * grown = + (struct natural_wonder_candidate *)realloc (list->entries, new_capacity * sizeof *grown); + if (grown == NULL) + return false; + list->entries = grown; + list->capacity = new_capacity; + } + + struct natural_wonder_candidate * entry = &list->entries[list->count++]; + entry->tile = tile; + entry->x = (short)tile_x; + entry->y = (short)tile_y; + return true; +} + +bool +natural_wonder_tile_is_clear (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (tile->CityID >= 0) return false; + if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return false; + if (tile->vtable->m15_Check_Goody_Hut (tile, __, 0)) return false; + if (tile->vtable->m39_Get_Resource_Type (tile) >= 0) return false; + if (tile->vtable->m18_Check_Mines (tile, __, 0)) return false; + if (get_district_instance (tile) != NULL) return false; + + // Check if this tile is a starting location for any civ + int tile_index = (p_bic_data->Map.Width >> 1) * tile_y + ((tile_x >> 1) & 0x7FFF); + for (int civ = 0; civ < p_bic_data->Map.Civ_Count; civ++) { + if (p_bic_data->Map.Starting_Locations[civ] == tile_index) { + return false; + } + } + + return true; +} + +bool +district_exists_within_distance (int tile_x, int tile_y, int district_id, int civ_id, int min_distance) +{ + if ((district_id < 0) || (district_id >= is->district_count) || (min_distance < 0)) + return false; + + for (int dist = 0; dist <= min_distance; dist++) { + struct vertex { + int x, y; + } vertices[4] = { + {tile_x , tile_y - 2*dist}, + {tile_x + 2*dist, tile_y }, + {tile_x , tile_y + 2*dist}, + {tile_x - 2*dist, tile_y } + }; + + int edge_dirs[4] = {3, 5, 7, 1}; + int edge_len = (dist == 0) ? 1 : 2 * dist; + + for (int vert = 0; vert < 4; vert++) { + wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); + int dx, dy; + neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); + for (int j = 0; j < edge_len; j++) { + int cx = vertices[vert].x + j * dx; + int cy = vertices[vert].y + j * dy; + wrap_tile_coords (&p_bic_data->Map, &cx, &cy); + + Tile * tile = tile_at (cx, cy); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if ((civ_id >= 0) && (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id)) + continue; + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == district_id)) + return true; + } + } + } + + return false; +} + +void +detach_workers_from_request (struct pending_district_request * req) +{ + if (req == NULL) + return; + + int civ_id = req->civ_id; + if ((civ_id < 0) || (civ_id >= 32)) { + for (int civ = 0; civ < 32; civ++) { + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + if ((rec != NULL) && (rec->pending_req == req)) + rec->pending_req = NULL; + } + } + return; + } + + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + if ((rec != NULL) && (rec->pending_req == req)) + rec->pending_req = NULL; + } +} + +void +remove_pending_district_request (struct pending_district_request * req) +{ + if (req == NULL) + return; + + int civ_id = req->civ_id; + if ((civ_id < 0) || (civ_id >= 32)) + return; + + int key = get_pending_district_request_key (req->city_id, req->district_id); + + detach_workers_from_request (req); + + if ((req->target_x >= 0) && (req->target_y >= 0)) { + Tile * tile = tile_at (req->target_x, req->target_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && + (inst->district_id == req->district_id) && + (inst->state != DS_COMPLETED)) + remove_district_instance (tile); + } + } + + if (key >= 0) + itable_remove (&is->city_pending_district_requests[civ_id], key); + req->city = NULL; + req->city_id = -1; + req->civ_id = -1; + free (req); +} + +bool __fastcall +patch_Leader_impl_would_raze_city (Leader * this, int edx, City * city) +{ + return is->current_config.prevent_razing_by_players ? false : Leader_impl_would_raze_city (this, __, city); +} + +int __fastcall patch_Unit_get_max_move_points (Unit * this); + +// This function is used to fix a bug where the game would freeze when using disembark all on a transport that contained an immobile unit. The bug +// comes from the fact that the function to disembark all units loops continuously over units in the transport until there are none left that +// can be disembarked. The problem is the logic to check disembarkability erroneously reports immobile units as disembarkable when they're not, +// so the program gets stuck in an infinite loop. The fix affects the function that checks disembarkability, replacing a call to +// Unit_get_max_move_points with a call to the function below. This function returns zero for immobile units, causing the caller to report +// (correctly) that the unit cannot be disembarked. +int __fastcall +patch_Unit_get_max_move_points_for_disembarking (Unit * this) +{ + if (is->current_config.patch_blocked_disembark_freeze && + UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Immobile)) + return 0; + else + return patch_Unit_get_max_move_points (this); +} + +// Unit::move_to_adjacent_tile uses a separate "spend all remaining movement when disembarking" branch for land units moving from water to land. +// Bridge districts still look like water tiles to that stock logic, so stepping off a bridge can incorrectly consume the whole turn. When the +// wrapper around move_to_adjacent_tile detects bridge->land movement, it precomputes the correct spent-moves total and exposes it here. +int __fastcall +patch_Unit_get_max_move_points_for_bridge_exit (Unit * this) +{ + if ((this != NULL) && (this == is->move_spend_override_unit)) + return is->move_spend_override_value; + else + return patch_Unit_get_max_move_points (this); +} + +// This func implements GA remaining turns indicator. It intercepts a call to some kind of text processing function when it's called to process the +// text in the lower right (containing current research, GA status, & mobilization) and splices in the number of remaining GA turns if in a GA. +int __fastcall +patch_PCX_Image_process_tech_ga_status (PCX_Image * this, int edx, char * str) +{ + Leader * player = &leaders[p_main_screen_form->Player_CivID]; + if (is->current_config.show_golden_age_turns_remaining && + (*p_current_turn_no < player->Golden_Age_End)) { + int turns_left = player->Golden_Age_End - *p_current_turn_no; + char const * ga_label = (*p_labels)[LBL_GOLDEN_AGE]; + char const * ga_str_start = strstr (str, ga_label); + if (ga_str_start != NULL) { + char s[250]; + char const * ga_str_end = ga_str_start + strlen (ga_label); + snprintf (s, sizeof s, "%.*s (%d)%s", ga_str_end - str, str, turns_left, ga_str_end); + s[(sizeof s) - 1] = '\0'; + strncpy (str, s, sizeof s); + } + } + return PCX_Image_process_text (this, __, str); +} + +bool __fastcall +patch_Leader_is_tile_visible (Leader * this, int edx, int x, int y) +{ + Tile_Body * tile = &tile_at (x, y)->Body; + unsigned vis_bits = tile->FOWStatus | tile->V3 | tile->Visibility | tile->field_D0_Visibility; + if (vis_bits & (1 << this->ID)) + return true; + else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND + ((1 << this->ID) & *p_human_player_bits) && // "this" is a human player AND + (vis_bits & *p_human_player_bits)) // any human player has visibility on the tile + return true; + else + return false; +} + +bool __fastcall +patch_Main_Screen_Form_is_unit_visible_to_player (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * unit) +{ + return (unit->Body.CivID == this->Player_CivID) || patch_Leader_is_tile_visible (&leaders[this->Player_CivID], __, tile_x, tile_y); +} + +enum direction +reverse_dir (enum direction dir) +{ + enum direction const reversed[] = { + DIR_ZERO, // DIR_ZERO + DIR_SW , // DIR_NE + DIR_W , // DIR_E + DIR_NW , // DIR_SE + DIR_N , // DIR_S + DIR_NE , // DIR_SW + DIR_E , // DIR_W + DIR_SE , // DIR_NW + DIR_S , // DIR_N + }; + int n = (int)dir; + if ((n >= 0) && (n < ARRAY_LEN (reversed))) + return reversed[n]; + else + return DIR_ZERO; +} + +bool +direction_to_offset (enum direction dir, int * out_dx, int * out_dy) +{ + int dx = 0, dy = 0; + + switch (dir) { + case DIR_NE: dx = 1; dy = -1; break; + case DIR_E: dx = 2; dy = 0; break; + case DIR_SE: dx = 1; dy = 1; break; + case DIR_S: dx = 0; dy = 2; break; + case DIR_SW: dx = -1; dy = 1; break; + case DIR_W: dx = -2; dy = 0; break; + case DIR_NW: dx = -1; dy = -1; break; + case DIR_N: dx = 0; dy = -2; break; + case DIR_ZERO: + default: + return false; + } + + if (out_dx != NULL) + *out_dx = dx; + if (out_dy != NULL) + *out_dy = dy; + return true; +} + +int +direction_to_neighbor_bit (enum direction dir) +{ + switch (dir) { + case DIR_NE: return 1; + case DIR_E: return 2; + case DIR_SE: return 3; + case DIR_S: return 4; + case DIR_SW: return 5; + case DIR_W: return 6; + case DIR_NW: return 7; + case DIR_N: return 0; // Matches engine behaviour where neighbor index 8 maps to 0 + default: + return -1; + } +} + +bool +get_primary_river_direction (Tile * tile, enum direction * out_dir) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + char river_bits = tile->vtable->m37_Get_River_Code (tile); + if (river_bits == 0) + return false; + + enum direction dirs[] = {DIR_E, DIR_W, DIR_SE, DIR_NE, DIR_SW, DIR_NW, DIR_S, DIR_N}; + for (int i = 0; i < (int)ARRAY_LEN (dirs); i++) { + int bit = direction_to_neighbor_bit (dirs[i]); + if ((bit >= 0) && ((river_bits & (1 << bit)) != 0)) { + if (out_dir != NULL) + *out_dir = dirs[i]; + return true; + } + } + + return false; +} + +void +wrap_tile_coords (Map * map, int * x, int * y) +{ + if (map->Flags & 1) { + if (*x < 0) *x += map->Width; + else if (*x >= map->Width) *x -= map->Width; + } + if (map->Flags & 2) { + if (*y < 0) *y += map->Height; + else if (*y >= map->Height) *y -= map->Height; + } +} + +void +tile_index_to_coords (Map * map, int index, int * out_x, int * out_y) +{ + if ((index >= 0) && (index < map->TileCount)) { + int width = map->Width; + int double_row = index / width, double_row_rem = index % width; + if (double_row_rem < width/2) { + *out_x = 2 * double_row_rem; + *out_y = 2 * double_row; + } else { + *out_x = 1 + 2 * (double_row_rem - width/2); + *out_y = 2 * double_row + 1; + } + } else + *out_x = *out_y = -1; +} + +int +tile_coords_to_index (Map * map, int x, int y) +{ + if ((map == NULL) || (x < 0) || (y < 0) || (x >= map->Width) || (y >= map->Height)) + return -1; + + int width = map->Width; + int row = y / 2; + if ((y & 1) == 0) { + return row * width + (x / 2); + } else { + return row * width + (width / 2) + (x / 2); + } +} + +Tile * +tile_at_index (Map * map, int i) +{ + int x, y; + tile_index_to_coords (map, i, &x, &y); + return tile_at (x, y); +} + +void +get_neighbor_coords (Map * map, int x, int y, int neighbor_index, int * out_x, int * out_y) +{ + int dx, dy; + neighbor_index_to_diff (neighbor_index, &dx, &dy); + *out_x = x + dx; + *out_y = y + dy; + wrap_tile_coords (map, out_x, out_y); +} + +Tile * __stdcall +tile_at_city_or_null (City * city_or_null) +{ + if (city_or_null) + return tile_at (city_or_null->Body.X, city_or_null->Body.Y); + else + return p_null_tile; +} + +Unit * +get_unit_ptr (int id) +{ + if ((p_units->Units != NULL) && + (id >= 0) && (id <= p_units->LastIndex)) { + Unit_Body * body = p_units->Units[id].Unit; + if (body != NULL) { + Unit * unit = (Unit *)((char *)body - offsetof (Unit, Body)); + if (unit != NULL) + return unit; + } + } + return NULL; +} + +bool +is_land_transport (Unit * unit) +{ + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + return type->Unit_Class == UTC_Land && type->Transport_Capacity > 0 && ! Unit_has_ability (unit, __, UTA_Army); +} + +bool +is_in_land_transport (Unit * unit) +{ + Unit * container = get_unit_ptr (unit->Body.Container_Unit); + return container != NULL && is_land_transport (container); +} + +// Checks if the unit is inside a transport (either helicopter or land transport) from which it is not allowed to defend according to the mod config. +bool +cannot_defend_inside_transport (Unit * unit) +{ + Unit * container = get_unit_ptr (unit->Body.Container_Unit); + if (container != NULL) { + if ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && is_land_transport (container)) + return true; + + if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return true; + } + return false; +} + +struct unit_tile_iter { + int id; + int item_index; + Unit * unit; +}; + +void +uti_next (struct unit_tile_iter * uti) +{ + if (((p_tile_units->Base.Items == NULL) || (uti->item_index < 0)) || + (uti->item_index > p_tile_units->Base.LastIndex)) { + uti->item_index = -1; + uti->id = p_tile_units->DefaultValue; + } else { + Base_List_Item * item = &p_tile_units->Base.Items[uti->item_index]; + uti->item_index = item->V; + uti->id = (int)item->Object; + } + uti->unit = get_unit_ptr (uti->id); +} + +struct unit_tile_iter +uti_init (Tile * tile) +{ + struct unit_tile_iter tr; + int tile_unit_id = tile->vtable->m40_get_TileUnit_ID (tile); + tr.id = TileUnits_TileUnitID_to_UnitID (p_tile_units, __, tile_unit_id, &tr.item_index); + tr.unit = get_unit_ptr (tr.id); + return tr; +} + +#define FOR_UNITS_ON(uti_name, tile) for (struct unit_tile_iter uti_name = uti_init (tile); uti_name.id != -1; uti_next (&uti_name)) + +bool +tile_has_enemy_unit (Tile * tile, int civ_id) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + if ((civ_id < 0) || (civ_id >= 32)) + return false; + + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit == NULL) || (unit->Body.Container_Unit >= 0)) + continue; + if (unit->Body.CivID == civ_id) + continue; + if (unit->vtable->is_enemy_of_civ (unit, __, civ_id, 0)) + return true; + } + + return false; +} + +struct citizen_iter { + int index; + Citizens * list; + Citizen_Base * ctzn; +}; + +void +ci_next (struct citizen_iter * ci) +{ + while (1) { + ci->index++; + if (ci->index > ci->list->LastIndex) { + ci->ctzn = NULL; + break; + } else { + Citizen_Body * body = ci->list->Items[ci->index].Body; + if ((body != NULL) && ((int)body != offsetof (Citizen_Base, Body))) { + ci->ctzn = (Citizen_Base *)((int)body - offsetof (Citizen_Base, Body)); + break; + } + } + } +} + +struct citizen_iter +ci_init (City * city) +{ + struct citizen_iter tr; + tr.index = -1; + tr.list = &city->Body.Citizens; + tr.ctzn = NULL; + if (city->Body.Citizens.Items != NULL) + ci_next (&tr); + return tr; +} + +#define FOR_CITIZENS_IN(ci_name, city) for (struct citizen_iter ci_name = ci_init (city); (ci_name.list->Items != NULL) && (ci_name.index <= ci.list->LastIndex); ci_next (&ci_name)) + +struct city_of_iter { + int city_id; + int civ_id; + City * city; +}; + +void +coi_next (struct city_of_iter * coi) +{ + coi->city_id++; + while (coi->city_id <= p_cities->LastIndex) { + City_Body * body = p_cities->Cities[coi->city_id].City; + if ((body != NULL) && ((int)body != offsetof (City, Body)) && (body->CivID == coi->civ_id)) { + coi->city = (City *)((char *)body - offsetof (City, Body)); + break; + } + coi->city_id++; + } +} + +struct city_of_iter +coi_init (int civ_id) +{ + struct city_of_iter tr = { .city_id = -1, .civ_id = civ_id, .city = NULL }; + if (p_cities->Cities != NULL) + coi_next (&tr); + else + tr.city_id = p_cities->LastIndex + 1; + return tr; +} + +#define FOR_CITIES_OF(coi_name, civ_id) for (struct city_of_iter coi_name = coi_init (civ_id); coi_name.city_id <= p_cities->LastIndex; coi_next (&coi_name)) + +struct tiles_around_iter { + int center_x, center_y; + int n, num_tiles; + Tile * tile; + int tile_x, tile_y; +}; + +void +tai_next (struct tiles_around_iter * tai) +{ + tai->tile = p_null_tile; + while ((tai->n < tai->num_tiles) && (tai->tile == p_null_tile)) { + tai->n += 1; + int tx, ty; + get_neighbor_coords (&p_bic_data->Map, tai->center_x, tai->center_y, tai->n, &tx, &ty); + if ((tx >= 0) && (tx < p_bic_data->Map.Width) && (ty >= 0) && (ty < p_bic_data->Map.Height)) { + tai->tile = tile_at (tx, ty); + tai->tile_x = tx; + tai->tile_y = ty; + } + } +} + +struct tiles_around_iter +tai_init (int num_tiles, int x, int y) +{ + struct tiles_around_iter tr; + tr.center_x = x; + tr.center_y = y; + tr.n = 0; + tr.num_tiles = num_tiles; + tr.tile = tile_at (x, y); + tr.tile_x = x; + tr.tile_y = y; + return tr; +} + +#define FOR_TILES_AROUND(tai_name, _num_tiles, _x, _y) for (struct tiles_around_iter tai_name = tai_init (_num_tiles, _x, _y); (tai_name.n < tai_name.num_tiles); tai_next (&tai_name)) + +enum work_area_iter_output_type { + WAIO_ANY, + WAIO_DISTRICTS, + WAIO_CITIES, +}; + +struct work_area_iter { + int center_x, center_y; + int n, num_tiles; + int civ_id; + int dx, dy; + int tile_x, tile_y; + Tile * tile; + City * city; + struct district_instance * district_inst; + enum work_area_iter_output_type output_type; + bool completed_districts_only; +}; + +void +wai_next (struct work_area_iter * wai) +{ + wai->tile = p_null_tile; + wai->district_inst = NULL; + while ((wai->n + 1) < wai->num_tiles) { + wai->n += 1; + patch_ni_to_diff_for_work_area (wai->n, &wai->dx, &wai->dy); + wai->tile_x = wai->center_x + wai->dx; + wai->tile_y = wai->center_y + wai->dy; + wrap_tile_coords (&p_bic_data->Map, &wai->tile_x, &wai->tile_y); + Tile * candidate = tile_at (wai->tile_x, wai->tile_y); + if ((candidate == NULL) || (candidate == p_null_tile)) + continue; + if ((wai->civ_id < 0) || (candidate->vtable->m38_Get_Territory_OwnerID (candidate) != wai->civ_id)) + continue; + if (tile_has_enemy_unit (candidate, wai->civ_id)) + continue; + if (candidate->vtable->m20_Check_Pollution (candidate, __, 0)) + continue; + City * city; + if (wai->output_type == WAIO_CITIES) { + if (candidate->CityID < 0) + continue; + city = get_city_ptr (candidate->vtable->m45_Get_City_ID (candidate)); + if (city == NULL || city->Body.CivID != wai->civ_id) + continue; + } + struct district_instance * inst = get_district_instance (candidate); + if (wai->output_type == WAIO_DISTRICTS) { + if (inst == NULL) + continue; + int district_id = inst->district_id; + if (wai->completed_districts_only && (! district_is_complete (candidate, district_id))) + continue; + } + wai->city = city; + wai->district_inst = inst; + wai->tile = candidate; + break; + } + if (wai->tile == p_null_tile) + wai->n = wai->num_tiles; +} + +struct work_area_iter +wai_init_common (int x, int y, enum work_area_iter_output_type output, bool completed_districts_only) +{ + struct work_area_iter tr; + tr.center_x = x; + tr.center_y = y; + tr.n = -1; + tr.num_tiles = is->workable_tile_count; + Tile * center_tile = tile_at (x, y); + if ((center_tile == NULL) || (center_tile == p_null_tile)) + tr.civ_id = -1; + else + tr.civ_id = center_tile->vtable->m38_Get_Territory_OwnerID (center_tile); + tr.tile = p_null_tile; + tr.district_inst = NULL; + tr.dx = 0; + tr.dy = 0; + tr.tile_x = 0; + tr.tile_y = 0; + tr.output_type = output; + tr.completed_districts_only = completed_districts_only; + wai_next (&tr); + return tr; +} + +struct work_area_iter +wai_init (int x, int y) +{ + return wai_init_common (x, y, false, false); +} + +struct work_area_iter +wai_init_districts (int x, int y, bool completed_only) +{ + return wai_init_common (x, y, WAIO_DISTRICTS, completed_only); +} + +struct work_area_iter +wai_init_cities (int x, int y) +{ + struct work_area_iter tr = wai_init_common (x, y, WAIO_CITIES, false); + return tr; +} + +#define FOR_WORK_AREA_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) +#define FOR_DISTRICTS_AROUND(wai_name, _x, _y, _completed_only) for (struct work_area_iter wai_name = wai_init_districts (_x, _y, _completed_only); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) +#define FOR_CITIES_AROUND(wai_name, _x, _y) for (struct work_area_iter wai_name = wai_init_cities (_x, _y); (wai_name.n < wai_name.num_tiles); wai_next (&wai_name)) +#define FOR_AERODROMES_AROUND(unit_ptr) \ + for (struct table_entry_iter _tei = tei_init (&is->district_tile_map); \ + _tei.index < _tei.capacity; \ + tei_next (&_tei)) \ + for (Tile * aerodrome_tile = (Tile *)_tei.key; \ + (aerodrome_tile != NULL) && (aerodrome_tile != p_null_tile); \ + aerodrome_tile = NULL) \ + for (struct district_instance * aerodrome_inst = (struct district_instance *)_tei.value; \ + (aerodrome_inst != NULL) && \ + (aerodrome_inst->district_id == AERODROME_DISTRICT_ID) && \ + district_is_complete (aerodrome_tile, AERODROME_DISTRICT_ID); \ + aerodrome_inst = NULL) \ + for (int aerodrome_x = 0, aerodrome_y = 0; \ + district_instance_get_coords (aerodrome_inst, aerodrome_tile, &aerodrome_x, &aerodrome_y) && \ + (aerodrome_tile->vtable->m38_Get_Territory_OwnerID (aerodrome_tile) == (unit_ptr)->Body.CivID) && \ + patch_Unit_is_in_rebase_range ((unit_ptr), __, aerodrome_x, aerodrome_y); \ + aerodrome_x = 0, aerodrome_y = 0) + +struct tile_rings_iter { + int center_x, center_y; + int const * rings; + int ring_count; + int r_idx; + int ni; + int tile_x, tile_y; + int current_ring; + Tile * tile; +}; + +void +tri_next (struct tile_rings_iter * tri) +{ + tri->tile = p_null_tile; + while (tri->r_idx < tri->ring_count) { + int ring_no = tri->rings[tri->r_idx]; + if ((ring_no <= 0) || (ring_no >= 8)) { + tri->r_idx += 1; + tri->ni = -1; + continue; + } + int start_ni = workable_tile_counts[ring_no - 1]; + int end_ni = workable_tile_counts[ring_no]; + if (tri->ni < start_ni) + tri->ni = start_ni; + else if ((tri->ni + 1) < end_ni) + tri->ni += 1; + else { + tri->r_idx += 1; + tri->ni = -1; + continue; + } + tri->current_ring = ring_no; + int dx, dy; + patch_ni_to_diff_for_work_area (tri->ni, &dx, &dy); + int tx = tri->center_x + dx; + int ty = tri->center_y + dy; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + tri->tile_x = tx; + tri->tile_y = ty; + Tile * candidate = tile_at (tx, ty); + if ((candidate == NULL) || (candidate == p_null_tile)) + continue; + tri->tile = candidate; + break; + } + if (tri->tile == p_null_tile) { + tri->r_idx = tri->ring_count; + tri->ni = -1; + } +} + +struct tile_rings_iter +tri_init (int x, int y, int const * rings, int ring_count) +{ + struct tile_rings_iter tr; + tr.center_x = x; + tr.center_y = y; + tr.rings = rings; + tr.ring_count = ring_count; + tr.r_idx = 0; + tr.ni = -1; + tr.tile_x = 0; + tr.tile_y = 0; + tr.current_ring = 0; + tr.tile = p_null_tile; + tri_next (&tr); + return tr; +} + +#define FOR_TILE_RINGS_AROUND(tri_name, _x, _y, _rings, _ring_count) for (struct tile_rings_iter tri_name = tri_init (_x, _y, _rings, _ring_count); (tri_name.r_idx < tri_name.ring_count); tri_next (&tri_name)) + +bool +tile_square_type_is (Tile * tile, enum SquareTypes type) +{ + return tile_matches_square_type (tile, type); +} + +bool +district_is_buildable_on_tile (struct district_config const * cfg, Tile * tile) +{ + if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + unsigned int mask = cfg->buildable_square_types_mask; + if (mask == 0) + mask = district_default_buildable_mask (); + + bool square_matches = tile_matches_square_type_mask (tile, mask); + bool overlay_allowed = false; + bool overlay_required = false; + + if (cfg->has_buildable_without_removal) + overlay_allowed = tile_matches_overlay_mask (tile, cfg->buildable_without_removal_mask); + + if (cfg->has_buildable_on_overlays) { + overlay_required = tile_matches_overlay_mask (tile, cfg->buildable_on_overlays_mask); + if (! overlay_required) + return false; + } + if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) + return false; + + if (! square_matches && ! overlay_allowed && ! overlay_required) + return false; + + if (cfg->has_buildable_on_districts) { + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + + int existing_district_id = inst->district_id; + if (! district_is_complete (tile, existing_district_id)) + return false; + + bool matches = false; + for (int i = 0; i < cfg->buildable_on_district_id_count; i++) { + if (cfg->buildable_on_district_ids[i] == existing_district_id) { + matches = true; + break; + } + } + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to || cfg->has_buildable_adjacent_to_districts || cfg->has_buildable_adjacent_to_overlays) { + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + return false; + + if (cfg->has_buildable_adjacent_to) { + bool matches = false; + bool city_adjacent = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (Tile_has_city (tai.tile)) { + city_adjacent = true; + if (cfg->buildable_adjacent_to_allows_city) + matches = true; + } + if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) + matches = true; + if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) + break; + } + if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) + return false; + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to_overlays) { + bool matches = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { + matches = true; + break; + } + } + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to_districts) { + bool matches = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + struct district_instance * adj_inst = get_district_instance (tai.tile); + if (adj_inst == NULL) + continue; + int adj_district_id = adj_inst->district_id; + if (! district_is_complete (tai.tile, adj_district_id)) + continue; + for (int i = 0; i < cfg->buildable_adjacent_to_district_id_count; i++) { + if (cfg->buildable_adjacent_to_district_ids[i] == adj_district_id) { + matches = true; + break; + } + } + if (matches) + break; + } + if (! matches) + return false; + } + } + + return true; +} + +bool +is_coastal_island (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + if (tile->vtable->m35_Check_Is_Water (tile)) + return false; + + bool has_neighbor = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + return false; + + has_neighbor = true; + if (! adj->vtable->m35_Check_Is_Water (adj)) + return false; + + if (adj->vtable->m50_Get_Square_BaseType (adj) != SQ_Coast) + return false; + } + + return has_neighbor; +} + +bool +natural_wonder_adjacent_requirement_met (struct natural_wonder_district_config const * cfg, + Tile * tile, + int tile_x, + int tile_y) +{ + enum SquareTypes required = cfg->adjacent_to; + if (required == (enum SquareTypes)SQ_INVALID) + return true; + + if (required == SQ_RIVER) { + char river_bits = tile->vtable->m37_Get_River_Code (tile); + if (cfg->adjacency_dir != DIR_ZERO) { + int bit = direction_to_neighbor_bit (cfg->adjacency_dir); + if (bit < 0) + return false; + return (river_bits & (1 << bit)) != 0; + } else + return river_bits != 0; + } + + if (cfg->adjacency_dir != DIR_ZERO) { + int dx, dy; + if (! direction_to_offset (cfg->adjacency_dir, &dx, &dy)) + return false; + int nx = tile_x + dx; + int ny = tile_y + dy; + wrap_tile_coords (&p_bic_data->Map, &nx, &ny); + Tile * neighbor = tile_at (nx, ny); + return tile_square_type_is (neighbor, required); + } + + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_square_type_is (tai.tile, required)) + return true; + } + + return false; +} + +int +count_diagonal_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) +{ + if (type == (enum SquareTypes)SQ_INVALID) + return 0; + + enum direction dirs[4] = {DIR_NE, DIR_NW, DIR_SE, DIR_SW}; + int count = 0; + for (int i = 0; i < 4; i++) { + int dx, dy; + if (! direction_to_offset (dirs[i], &dx, &dy)) + continue; + int nx = tile_x + dx; + int ny = tile_y + dy; + wrap_tile_coords (&p_bic_data->Map, &nx, &ny); + Tile * neighbor = tile_at (nx, ny); + if (tile_square_type_is (neighbor, type)) + count += 1; + } + return count; +} + +int +count_adjacent_tiles_of_type (int tile_x, int tile_y, enum SquareTypes type) +{ + if (type == (enum SquareTypes)SQ_INVALID) + return 0; + + int count = 0; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_square_type_is (tai.tile, type)) + count += 1; + } + return count; +} + +bool +natural_wonder_terrain_matches (struct natural_wonder_district_config const * cfg, Tile * tile, int tile_x, int tile_y) +{ + if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + if (! tile_matches_square_type (tile, cfg->terrain_type)) + return false; + + if (cfg->terrain_type == SQ_Coast) { + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + return false; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + if ((continent == NULL) || (continent->Body.TileCount <= 5)) + return false; + } + + if (is_coastal_island (tile, tile_x, tile_y)) + return false; + + if ((cfg->adjacent_to != SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 0)) + return false; + + if ((cfg->adjacent_to == SQ_Coast) && (count_adjacent_tiles_of_type (tile_x, tile_y, SQ_Coast) > 4)) + return false; + + if (! natural_wonder_adjacent_requirement_met (cfg, tile, tile_x, tile_y)) + return false; + + return true; +} + +struct district_worker_record * +get_tracked_worker_record (Unit * worker) +{ + if (worker == NULL) return NULL; + int civ_id = worker->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) return NULL; + + int value; + if (itable_look_up (&is->district_worker_tables[civ_id], worker->Body.ID, &value)) + return (struct district_worker_record *)value; + return NULL; +} + +struct district_worker_record * +ensure_tracked_worker_record (Unit * worker) +{ + if (worker == NULL) return NULL; + int civ_id = worker->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) return NULL; + + struct district_worker_record * rec = get_tracked_worker_record (worker); + if (rec != NULL) return rec; + + rec = (struct district_worker_record *)calloc (1, sizeof *rec); + if (rec == NULL) return NULL; + + rec->worker = worker; + rec->unit_id = worker->Body.ID; + Tile * tile = tile_at (worker->Body.X, worker->Body.Y); + rec->continent_id = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m46_Get_ContinentID (tile) : -1; + rec->pending_req = NULL; + + itable_insert (&is->district_worker_tables[civ_id], worker->Body.ID, (int)rec); + return rec; +} + +void +remove_tracked_worker_record (int civ_id, int unit_id) +{ + if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) + return; + + int value; + if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) + return; + + struct district_worker_record * rec = (struct district_worker_record *)value; + if (rec->pending_req != NULL) { + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + } + + itable_remove (&is->district_worker_tables[civ_id], unit_id); + free (rec); +} + +void +clear_tracked_worker_assignment (struct district_worker_record * rec) +{ + if (rec == NULL) + return; + + if (rec->pending_req != NULL) { + if (rec->pending_req->assigned_worker_id == rec->unit_id) + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + } +} + +void +clear_tracked_worker_assignment_by_id (int civ_id, int unit_id) +{ + if ((civ_id < 0) || (civ_id >= 32) || (unit_id < 0)) + return; + + int value; + if (! itable_look_up (&is->district_worker_tables[civ_id], unit_id, &value)) + return; + + struct district_worker_record * rec = (struct district_worker_record *)value; + if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == unit_id)) + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + if ((rec->worker == NULL) || (get_unit_ptr (unit_id) == NULL)) + remove_tracked_worker_record (civ_id, unit_id); +} + +void +clear_all_tracked_workers (void) +{ + for (int civ = 0; civ < 32; civ++) { + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + if (rec == NULL) + continue; + if ((rec->pending_req != NULL) && (rec->pending_req->assigned_worker_id == rec->unit_id)) + rec->pending_req->assigned_worker_id = -1; + rec->pending_req = NULL; + free (rec); + } + is->district_worker_tables[civ].len = 0; + if (is->district_worker_tables[civ].block != NULL) { + free (is->district_worker_tables[civ].block); + is->district_worker_tables[civ].block = NULL; + } + is->district_worker_tables[civ].capacity_exponent = 0; + } +} + +bool is_worker (Unit * unit) +{ + if (unit == NULL) + return false; + + int unit_type_id = unit->Body.UnitTypeID; + int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; + + if (worker_actions == 0 || !(worker_actions & (UCV_Build_Road | UCV_Build_Mine | UCV_Irrigate))) { + return false; + } + + return true; +} + +void +update_tracked_worker_for_unit (Unit * worker) +{ + if (worker == NULL || ! is->current_config.enable_districts) return; + + int civ_id = worker->Body.CivID; + int type_id = worker->Body.UnitTypeID; + if ((civ_id < 0) || (civ_id >= 32)) return; + if ((*p_human_player_bits & (1 << civ_id)) != 0) return; + + char ss[200]; + snprintf (ss, sizeof ss, "Updating tracked worker for unit %d of type %d\n", worker->Body.ID, type_id); + (*p_OutputDebugStringA) (ss); + + if (! is_worker (worker)) { + remove_tracked_worker_record(worker->Body.CivID, worker->Body.ID); + return; + } + + ensure_tracked_worker_record (worker); +} + +bool +assign_worker_to_district (struct pending_district_request * req, Unit * worker, City * city, int district_id, int tile_x, int tile_y) +{ + if (worker == NULL || city == NULL) + return false; + if (req == NULL) + return false; + + req->city = city; + req->city_id = city->Body.ID; + req->civ_id = city->Body.CivID; + req->assigned_worker_id = worker->Body.ID; + req->worker_assigned_turn = *p_current_turn_no; + req->target_x = tile_x; + req->target_y = tile_y; + worker->Body.Auto_CityID = city->Body.ID; + + char ss[200]; + snprintf (ss, sizeof ss, "assign_worker_to_district: Assigned worker unit %d to build district %d in city %s at (%d,%d)\n", + worker->Body.ID, district_id, city->Body.CityName, tile_x, tile_y); + (*p_OutputDebugStringA) (ss); + + struct district_worker_record * record = ensure_tracked_worker_record (worker); + if (record != NULL) { + record->pending_req = req; + } + + return ai_move_district_worker (worker, record); +} + +bool +worker_is_available_for_district (Unit * worker) +{ + if (worker == NULL) + return false; + + int civ_id = worker->Body.CivID; + if ((civ_id < 0) || (civ_id >= 32)) return false; + if ((*p_human_player_bits & (1 << civ_id)) != 0) return false; + + int type_id = worker->Body.UnitTypeID; + if ((type_id < 0) || (type_id >= p_bic_data->UnitTypeCount)) return false; + + struct district_worker_record * record = get_tracked_worker_record (worker); + if (record == NULL) + return false; + + return record->pending_req == NULL; +} + +Unit * +find_best_worker_for_district (Leader * leader, City * city, int district_id, int target_x, int target_y) +{ + char ss[200]; + + if ((leader == NULL) || (city == NULL)) { + snprintf (ss, sizeof ss, "Invalid leader or city when finding best worker for district %d\n", district_id); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + int civ_id = leader->ID; + if ((civ_id < 0) || (civ_id >= 32)) { + snprintf (ss, sizeof ss, "Invalid civ_id %d when finding best worker for district %d\n", civ_id, district_id); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + if (is->district_worker_tables[civ_id].len == 0) { + snprintf (ss, sizeof ss, "No tracked workers for civ %d when finding best worker for district %d\n", civ_id, district_id); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + Tile * target_tile = tile_at (target_x, target_y); + if ((target_tile == NULL) || (target_tile == p_null_tile)) { + snprintf (ss, sizeof ss, "Invalid target tile (%d,%d) when finding best worker for district %d in city %s\n", + target_x, target_y, district_id, city->Body.CityName); + (*p_OutputDebugStringA) (ss); + return NULL; + } + + int target_continent_id = target_tile->vtable->m46_Get_ContinentID (target_tile); + Unit * best_worker = NULL; + int best_dist = INT_MAX; + + snprintf (ss, sizeof ss, "Finding best worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); + (*p_OutputDebugStringA) (ss); + + FOR_TABLE_ENTRIES (tei, &is->district_worker_tables[civ_id]) { + struct district_worker_record * rec = (struct district_worker_record *)tei.value; + + if (rec == NULL) { + continue; + } + + Unit * candidate_worker = get_unit_ptr (rec->unit_id); + if ((candidate_worker == NULL) || (candidate_worker->Body.CivID != civ_id)) { + remove_tracked_worker_record (civ_id, rec->unit_id); + continue; + } + rec->worker = candidate_worker; + + if (! worker_is_available_for_district (candidate_worker)) { + continue; + } + + Tile * worker_tile = tile_at (candidate_worker->Body.X, candidate_worker->Body.Y); + if ((worker_tile == NULL) || (worker_tile == p_null_tile)) { + continue; + } + + int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); + if ((target_continent_id >= 0) && (worker_continent_id != target_continent_id)) { + continue; + } + + int dist = compute_wrapped_chebyshev_distance (candidate_worker->Body.X, candidate_worker->Body.Y, target_x, target_y); + + if (dist < best_dist) { + best_worker = candidate_worker; + best_dist = dist; + if (dist == 0) + return best_worker; + } + } + + return best_worker; +} + +void +process_pending_district_request (Leader * leader, struct pending_district_request * req) +{ + if ((leader == NULL) || (req == NULL)) + return; + + City * city = get_city_ptr (req->city_id); + if (city == NULL) { + remove_pending_district_request (req); + return; + } + req->city = city; + + int district_id = req->district_id; + int civ_id = req->civ_id; + + if (city->Body.CivID != civ_id) { + clear_city_district_request (city, district_id); + return; + } + + if (district_id < 0 || district_id >= is->district_count) return; + + // Check if city already has the district if not a neighborhood or distribution hub + if (district_id != NEIGHBORHOOD_DISTRICT_ID && + district_id != DISTRIBUTION_HUB_DISTRICT_ID && + is->district_configs[district_id].allow_multiple == false && + city_has_required_district (city, district_id)) { + + // Clear the request + clear_city_district_request (city, district_id); + return; + } + + // Assigned worker is no longer valid; clear assignment + if (req->assigned_worker_id >= 0) { + Unit * assigned = get_unit_ptr (req->assigned_worker_id); + if (assigned != NULL) { + // Check if more than allowed turns have elapsed since assignment and worker is not at target tile + bool worker_at_target = (assigned->Body.X == req->target_x) && (assigned->Body.Y == req->target_y); + if ((*p_current_turn_no - req->worker_assigned_turn) > is->current_config.ai_city_district_max_build_wait_turns && !worker_at_target) { + clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); + req->assigned_worker_id = -1; + req->worker_assigned_turn = *p_current_turn_no; + } else { + return; + } + } else { + // Assigned worker is null, make sure we get a new one + clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); + req->assigned_worker_id = -1; + } + } + + struct district_instance * inst = NULL; + int target_x = 0; + int target_y = 0; + Tile * tile = find_tile_for_district (city, district_id, &target_x, &target_y); + if ((tile == NULL) || (tile == p_null_tile)) { + clear_city_district_request (city, district_id); + return; + } + wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); + + char ss[200]; + snprintf (ss, sizeof ss, "Assigning worker for district %d in city %s at (%d,%d)\n", district_id, city->Body.CityName, target_x, target_y); + (*p_OutputDebugStringA) (ss); + + Unit * worker = find_best_worker_for_district (leader, city, district_id, target_x, target_y); + if (worker == NULL) + return; + + snprintf (ss, sizeof ss, "Found worker %d for district %d in city %s at (%d,%d)\n", + worker->Body.ID, district_id, city->Body.CityName, target_x, target_y); + (*p_OutputDebugStringA) (ss); + + assign_worker_to_district (req, worker, city, district_id, target_x, target_y); +} + +void +assign_workers_for_pending_districts (Leader * leader) +{ + if ((leader == NULL) || ! is->current_config.enable_districts) + return; + + int civ_id = leader->ID; + if ((civ_id < 0) || (civ_id >= 32)) + return; + + if ((*p_human_player_bits & (1 << civ_id)) != 0) + return; + + int pending_count = is->city_pending_district_requests[civ_id].len; + if (pending_count <= 0) + return; + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req == NULL) + continue; + + City * city = get_city_ptr (req->city_id); + if (city == NULL) { + remove_pending_district_request (req); + continue; + } + + req->city = city; + if (city->Body.CivID != req->civ_id) { + remove_pending_district_request (req); + continue; + } + + process_pending_district_request (leader, req); + } +} + +City * +find_closest_owned_city_for_tile (int civ_id, int tile_x, int tile_y) +{ + City * best_city = NULL; + int best_dist = INT_MAX; + + FOR_CITIES_OF (coi, civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + + int dist = compute_wrapped_chebyshev_distance (city->Body.X, city->Body.Y, tile_x, tile_y); + if (dist < best_dist) { + best_dist = dist; + best_city = city; + } + } + + return best_city; +} + +bool +ai_candidate_bridge_or_canal_is_buildable_for_civ (struct ai_candidate_bridge_or_canal_entry * entry, int civ_id, int * out_tile_index) +{ + if ((entry == NULL) || (entry->tile_count <= 0)) + return false; + + int pending_index = -1; + for (int ti = 0; ti < entry->tile_count; ti++) { + int tx = entry->tile_x[ti]; + int ty = entry->tile_y[ti]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (owner != civ_id) + return false; + if (tile->CityID >= 0) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + if (inst->district_id == entry->district_id) + continue; + if (inst->district_id == WONDER_DISTRICT_ID) + return false; + if (! is->current_config.ai_can_replace_existing_districts_with_canals) { + return false; + } + } + + if (pending_index < 0) + pending_index = ti; + } + + if (pending_index < 0) { + entry->completed = true; + return false; + } + + if (out_tile_index != NULL) + *out_tile_index = pending_index; + + return true; +} + +void +release_ai_candidate_bridge_or_canal_worker (struct ai_candidate_bridge_or_canal_entry * entry) +{ + if ((entry == NULL) || (entry->assigned_worker_id < 0)) + return; + + int civ_id = entry->pending_req.civ_id; + if ((civ_id >= 0) && (civ_id < 32)) + clear_tracked_worker_assignment_by_id (civ_id, entry->assigned_worker_id); + + entry->assigned_worker_id = -1; + entry->assigned_tile_index = -1; + entry->pending_req.city = NULL; + entry->pending_req.city_id = -1; + entry->pending_req.civ_id = -1; + entry->pending_req.district_id = -1; + entry->pending_req.assigned_worker_id = -1; + entry->pending_req.target_x = -1; + entry->pending_req.target_y = -1; + entry->pending_req.worker_assigned_turn = 0; +} + +void +reset_ai_candidate_bridge_or_canals (void) +{ + if (is->ai_candidate_bridge_or_canals != NULL) { + for (int i = 0; i < is->ai_candidate_bridge_or_canals_capacity; i++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[i]; + if (entry->tile_x != NULL) + free (entry->tile_x); + if (entry->tile_y != NULL) + free (entry->tile_y); + } + free (is->ai_candidate_bridge_or_canals); + is->ai_candidate_bridge_or_canals = NULL; + } + is->ai_candidate_bridge_or_canals_capacity = 0; + is->ai_candidate_bridge_or_canals_count = 0; + is->ai_candidate_bridge_or_canals_initialized = false; +} + +bool +tile_has_district_at (int tile_x, int tile_y, int district_id) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + return (inst != NULL) && (inst->district_id == district_id) && (district_is_complete (tile, district_id)); +} + +bool +tile_is_land (int civ_id, int tile_x, int tile_y, bool must_be_same_owner) +{ + if (must_be_same_owner && (civ_id <= 0)) + return false; + + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + return (tile != NULL) && (tile != p_null_tile) && (! tile->vtable->m35_Check_Is_Water (tile)) && + ((! must_be_same_owner) || (tile->Territory_OwnerID == civ_id)); +} + +bool +tile_is_water (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + return (tile != NULL) && (tile != p_null_tile) && (tile->vtable->m35_Check_Is_Water (tile)); +} + +bool +ensure_ai_candidate_bridge_or_canals_capacity (int required) +{ + if (required <= 0) + return true; + if (required <= is->ai_candidate_bridge_or_canals_capacity) + return true; + int new_capacity = (is->ai_candidate_bridge_or_canals_capacity > 0) ? is->ai_candidate_bridge_or_canals_capacity * 2 : 4; + if (new_capacity < required) + new_capacity = required; + struct ai_candidate_bridge_or_canal_entry * larger = (struct ai_candidate_bridge_or_canal_entry *)realloc ( + is->ai_candidate_bridge_or_canals, new_capacity * sizeof *larger); + if (larger == NULL) + return false; + for (int i = is->ai_candidate_bridge_or_canals_capacity; i < new_capacity; i++) { + struct ai_candidate_bridge_or_canal_entry * entry = &larger[i]; + entry->tile_x = NULL; + entry->tile_y = NULL; + entry->tile_capacity = 0; + entry->district_id = -1; + entry->owner_civ_id = -1; + entry->tile_count = 0; + entry->assigned_tile_index = -1; + entry->assigned_worker_id = -1; + entry->completed = false; + struct pending_district_request * req = &entry->pending_req; + req->city = NULL; + req->city_id = -1; + req->civ_id = -1; + req->district_id = -1; + req->assigned_worker_id = -1; + req->target_x = -1; + req->target_y = -1; + req->worker_assigned_turn = 0; + } + is->ai_candidate_bridge_or_canals = larger; + is->ai_candidate_bridge_or_canals_capacity = new_capacity; + return true; +} + +bool +canal_has_different_adjacent_seas (int tile_x, int tile_y, int civ_id) +{ + struct water_pair { + int dx1, dy1; + int dx2, dy2; + }; + + const struct water_pair pairs[] = { + { 1, -1, -1, 1 }, // NE + SW + { 1, 1, -1, -1 }, // SE + NW + }; + + Map * map = &p_bic_data->Map; + bool require_owner = (civ_id >= 0); + + for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { + int ax = tile_x + pairs[i].dx1; + int ay = tile_y + pairs[i].dy1; + wrap_tile_coords (map, &ax, &ay); + Tile * first = tile_at (ax, ay); + if ((first == NULL) || (first == p_null_tile)) + continue; + if (! first->vtable->m35_Check_Is_Water (first)) + continue; + if (require_owner && (first->vtable->m38_Get_Territory_OwnerID (first) != civ_id)) + continue; + + int bx = tile_x + pairs[i].dx2; + int by = tile_y + pairs[i].dy2; + wrap_tile_coords (map, &bx, &by); + Tile * second = tile_at (bx, by); + if ((second == NULL) || (second == p_null_tile)) + continue; + if (! second->vtable->m35_Check_Is_Water (second)) + continue; + if (require_owner && (second->vtable->m38_Get_Territory_OwnerID (second) != civ_id)) + continue; + + int sea_a = first->vtable->m46_Get_ContinentID (first); + int sea_b = second->vtable->m46_Get_ContinentID (second); + if ((sea_a >= 0) && (sea_b >= 0) && (sea_a != sea_b)) + return true; + } + + return false; +} + +// Check if two water tiles can reach each other via water within a radius, excluding a blocked tile +bool +water_tiles_connected_within_radius (int start_x, int start_y, int target_x, int target_y, int block_x, int block_y, int radius) +{ + // Simple BFS using a fixed-size visited array for tiles within radius + // workable_tile_counts[6] = 137 tiles for radius 6 + int max_tiles = 137; + int visited_x[137]; + int visited_y[137]; + int visited_count = 0; + int queue_x[137]; + int queue_y[137]; + int queue_head = 0; + int queue_tail = 0; + + queue_x[queue_tail] = start_x; + queue_y[queue_tail] = start_y; + queue_tail++; + visited_x[visited_count] = start_x; + visited_y[visited_count] = start_y; + visited_count++; + + while (queue_head < queue_tail) { + int cx = queue_x[queue_head]; + int cy = queue_y[queue_head]; + queue_head++; + + // Check 8 adjacent tiles + FOR_TILES_AROUND (tai, 9, cx, cy) { + if (tai.n == 0) + continue; + int nx = tai.tile_x; + int ny = tai.tile_y; + + // Found target + if (nx == target_x && ny == target_y) + return true; + + // Skip blocked tile (the isthmus) + if (nx == block_x && ny == block_y) + continue; + + // Check if within radius of original start + int dx = nx - start_x; + int dy = ny - start_y; + if (dx < 0) dx = -dx; + if (dy < 0) dy = -dy; + // Use Chebyshev distance approximation for hex grid + int dist = (dx + dy + ((dx > dy) ? dx : dy)) / 2; + if (dist > radius) + continue; + + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (! adj->vtable->m35_Check_Is_Water (adj)) + continue; + + // Check if already visited + bool already_visited = false; + for (int i = 0; i < visited_count; i++) { + if (visited_x[i] == nx && visited_y[i] == ny) { + already_visited = true; + break; + } + } + if (already_visited) + continue; + + // Add to queue and visited + if (visited_count < max_tiles && queue_tail < max_tiles) { + visited_x[visited_count] = nx; + visited_y[visited_count] = ny; + visited_count++; + queue_x[queue_tail] = nx; + queue_y[queue_tail] = ny; + queue_tail++; + } + } + } + return false; +} + +// Check if tile separates adjacent water tiles that are not connected within a small radius +bool +canal_has_same_sea_isthmus (int tile_x, int tile_y, int civ_id, int check_radius) +{ + // If another canal exists nearby, this isn't a unique isthmus target. + FOR_TILES_AROUND (tai, workable_tile_counts[2], tile_x, tile_y) { + if (tai.n == 0) + continue; + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + continue; + struct district_instance * adj_inst = get_district_instance (adj); + if ((adj_inst != NULL) && (adj_inst->district_id == CANAL_DISTRICT_ID)) + return false; + } + + // Check opposite diagonal water tiles that are not connected within radius 2 + struct water_pair { + int dx1, dy1; + int dx2, dy2; + }; + + const struct water_pair pairs[] = { + { 1, -1, -1, 1 }, // NE + SW + { 1, 1, -1, -1 }, // SE + NW + }; + + for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { + int ax = tile_x + pairs[i].dx1; + int ay = tile_y + pairs[i].dy1; + wrap_tile_coords (&p_bic_data->Map, &ax, &ay); + Tile * first = tile_at (ax, ay); + if ((first == NULL) || (first == p_null_tile)) + continue; + if (! first->vtable->m35_Check_Is_Water (first)) + continue; + + int bx = tile_x + pairs[i].dx2; + int by = tile_y + pairs[i].dy2; + wrap_tile_coords (&p_bic_data->Map, &bx, &by); + Tile * second = tile_at (bx, by); + if ((second == NULL) || (second == p_null_tile)) + continue; + if (! second->vtable->m35_Check_Is_Water (second)) + continue; + + if (! water_tiles_connected_within_radius ( + ax, ay, + bx, by, + tile_x, tile_y, 2)) { + return true; + } + } + return false; +} + +bool +bridge_tile_connects_two_continents (int tile_x, int tile_y, int civ_id) +{ + struct bridge_pair { + int dx1, dy1; + int dx2, dy2; + }; + + Map * map = &p_bic_data->Map; + const struct bridge_pair pairs[] = { + {0, -2, 0, 2}, + {-2, 0, 2, 0}, + {-1, -1, 1, 1}, + {-1, 1, 1, -1}, + }; + + bool require_owner = (civ_id >= 0); + + for (int i = 0; i < (int)(sizeof (pairs) / sizeof (pairs[0])); i++) { + int ax = tile_x + pairs[i].dx1; + int ay = tile_y + pairs[i].dy1; + wrap_tile_coords (map, &ax, &ay); + if (! tile_is_land (civ_id, ax, ay, require_owner)) + continue; + Tile * first = tile_at (ax, ay); + if ((first == NULL) || (first == p_null_tile)) + continue; + + int bx = tile_x + pairs[i].dx2; + int by = tile_y + pairs[i].dy2; + wrap_tile_coords (map, &bx, &by); + if (! tile_is_land (civ_id, bx, by, require_owner)) + continue; + Tile * second = tile_at (bx, by); + if ((second == NULL) || (second == p_null_tile)) + continue; + + int cont_a = first->vtable->m46_Get_ContinentID (first); + int cont_b = second->vtable->m46_Get_ContinentID (second); + if ((cont_a >= 0) && (cont_b >= 0) && (cont_a != cont_b)) + return true; + } + + return false; +} + +bool +tile_point_in_block (int tile_x, int tile_y, int block_x0, int block_y0, int block_x1, int block_y1) +{ + return (tile_x >= block_x0) && (tile_x < block_x1) && (tile_y >= block_y0) && (tile_y < block_y1); +} + +bool +tile_is_coastal_water (int tile_x, int tile_y) +{ + Map * map = &p_bic_data->Map; + wrap_tile_coords (map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + if (! tile->vtable->m35_Check_Is_Water (tile)) + return false; + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + return base_type == SQ_Coast; +} + +bool +tile_exists_at (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + return (tile != NULL) && (tile != p_null_tile); +} + +bool +tile_is_reserved_in_district_tile_map (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return false; + int existing = 0; + return itable_look_up (&is->district_tile_map, (int)tile, &existing); +} + +bool +tile_has_diagonal_water (int tile_x, int tile_y) +{ + Map * map = &p_bic_data->Map; + int const adj_dx[4] = { 1, 1, -1, -1 }; + int const adj_dy[4] = { -1, 1, -1, 1 }; + + for (int i = 0; i < 4; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * tile = tile_at (nx, ny); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m35_Check_Is_Water (tile)) + return true; + } + return false; +} + +bool +tile_part_of_existing_candidate (int tile_x, int tile_y) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if (entry->tile_count <= 0) + continue; + for (int ti = 0; ti < entry->tile_count; ti++) { + if ((entry->tile_x[ti] == tile_x) && (entry->tile_y[ti] == tile_y)) + return true; + } + } + return false; +} + +bool +tile_has_bridge_or_canal_nearby (int tile_x, int tile_y) +{ + FOR_TILES_AROUND (tai, workable_tile_counts[1], tile_x, tile_y) { + Tile * adj = tai.tile; + if ((adj == NULL) || (adj == p_null_tile)) + continue; + struct district_instance * inst = get_district_instance (adj); + if ((inst != NULL) && + ((inst->district_id == BRIDGE_DISTRICT_ID) || (inst->district_id == CANAL_DISTRICT_ID))) + return true; + if (tile_part_of_existing_candidate (tai.tile_x, tai.tile_y)) + return true; + } + return false; +} + +bool +add_ai_candidate_entry (int district_id, short owner_civ_id, short * xs, short * ys, int count) +{ + if (count <= 0) + return false; + if (! ensure_ai_candidate_bridge_or_canals_capacity (is->ai_candidate_bridge_or_canals_count + 1)) + return false; + + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[is->ai_candidate_bridge_or_canals_count]; + entry->tile_x = (short *)malloc (sizeof *entry->tile_x * count); + entry->tile_y = (short *)malloc (sizeof *entry->tile_y * count); + if ((entry->tile_x == NULL) || (entry->tile_y == NULL)) { + if (entry->tile_x != NULL) + free (entry->tile_x); + if (entry->tile_y != NULL) + free (entry->tile_y); + return false; + } + + entry->district_id = district_id; + entry->owner_civ_id = owner_civ_id; + entry->tile_count = (short)count; + entry->tile_capacity = count; + entry->assigned_tile_index = -1; + entry->assigned_worker_id = -1; + entry->completed = false; + for (int ti = 0; ti < count; ti++) { + entry->tile_x[ti] = xs[ti]; + entry->tile_y[ti] = ys[ti]; + } + + struct pending_district_request * req = &entry->pending_req; + req->city = NULL; + req->city_id = -1; + req->civ_id = owner_civ_id; + req->district_id = district_id; + req->assigned_worker_id = -1; + req->target_x = -1; + req->target_y = -1; + req->worker_assigned_turn = 0; + + is->ai_candidate_bridge_or_canals_count++; + return true; +} + +int +find_bridge_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, + int contiguous_limit, int candidate_capacity, + short * out_x, short * out_y, short * out_owner) +{ + const int dirs[4][2] = { + { 0, -2 }, { -2, 0 }, { -1, -1 }, { -1, 1 } + }; + + int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + if (candidate_capacity > 0 && max_len > candidate_capacity) + max_len = candidate_capacity; + + for (int length = 1; length <= max_len; length++) { + for (int ti = 0; ti < map->TileCount; ti++) { + int tx = -1; + int ty = -1; + tile_index_to_coords (map, ti, &tx, &ty); + if (! tile_point_in_block (tx, ty, block_x0, block_y0, block_x1, block_y1)) + continue; + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile_has_resource (tile)) + continue; + if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], tile)) + continue; + if (tile_is_reserved_in_district_tile_map (tx, ty)) + continue; + short owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + for (int di = 0; di < (int)(sizeof (dirs) / sizeof (dirs[0])); di++) { + int dx = dirs[di][0]; + int dy = dirs[di][1]; + int end_x = tx + dx * (length - 1); + int end_y = ty + dy * (length - 1); + wrap_tile_coords (map, &end_x, &end_y); + if (! tile_point_in_block (end_x, end_y, block_x0, block_y0, block_x1, block_y1)) + continue; + + bool ok = true; + for (int step = 0; step < length; step++) { + int cx = tx + dx * step; + int cy = ty + dy * step; + wrap_tile_coords (map, &cx, &cy); + if (! tile_point_in_block (cx, cy, block_x0, block_y0, block_x1, block_y1)) { + ok = false; + break; + } + if (! tile_exists_at (cx, cy)) { + ok = false; + break; + } + if (! tile_is_coastal_water (cx, cy)) { + ok = false; + break; + } + Tile * bridge_tile = tile_at (cx, cy); + if ((bridge_tile == NULL) || (bridge_tile == p_null_tile)) { + ok = false; + break; + } + if (tile_has_resource (bridge_tile)) { + ok = false; + break; + } + if (! district_is_buildable_on_tile (&is->district_configs[BRIDGE_DISTRICT_ID], bridge_tile)) { + ok = false; + break; + } + if (tile_has_bridge_or_canal_nearby (cx, cy)) { + ok = false; + break; + } + if (tile_is_reserved_in_district_tile_map (cx, cy)) { + ok = false; + break; + } + if (tile_part_of_existing_candidate (cx, cy)) { + ok = false; + break; + } + } + if (! ok) + continue; + + int land_ax = tx - dx; + int land_ay = ty - dy; + wrap_tile_coords (map, &land_ax, &land_ay); + if (! tile_point_in_block (land_ax, land_ay, block_x0, block_y0, block_x1, block_y1)) + continue; + if (! tile_exists_at (land_ax, land_ay)) + continue; + if (! tile_is_land (-1, land_ax, land_ay, false)) + continue; + Tile * land_a = tile_at (land_ax, land_ay); + if ((land_a == NULL) || (land_a == p_null_tile)) + continue; + + int land_bx = tx + dx * length; + int land_by = ty + dy * length; + wrap_tile_coords (map, &land_bx, &land_by); + if (! tile_point_in_block (land_bx, land_by, block_x0, block_y0, block_x1, block_y1)) + continue; + if (! tile_exists_at (land_bx, land_by)) + continue; + if (! tile_is_land (-1, land_bx, land_by, false)) + continue; + Tile * land_b = tile_at (land_bx, land_by); + if ((land_b == NULL) || (land_b == p_null_tile)) + continue; + + int cont_a = land_a->vtable->m46_Get_ContinentID (land_a); + int cont_b = land_b->vtable->m46_Get_ContinentID (land_b); + if ((cont_a < 0) || (cont_b < 0) || (cont_a == cont_b)) + continue; + + for (int step = 0; step < length; step++) { + int cx = tx + dx * step; + int cy = ty + dy * step; + wrap_tile_coords (map, &cx, &cy); + out_x[step] = (short)cx; + out_y[step] = (short)cy; + } + *out_owner = owner; + return length; + } + } + } + return 0; +} + +int +gather_canal_line (int start_x, int start_y, int dx, int dy, int limit, + int block_x0, int block_y0, int block_x1, int block_y1, + short * out_x, short * out_y) +{ + int effective_limit = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, limit); + + if (! tile_is_land (-1, start_x, start_y, false)) + return 0; + if (tile_part_of_existing_candidate (start_x, start_y)) + return 0; + + short back_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + short back_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + short forward_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + short forward_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + int back_count = 0; + int forward_count = 0; + int remaining = effective_limit - 1; + Map * map = &p_bic_data->Map; + + int cx = start_x; + int cy = start_y; + while ((remaining > 0) && (back_count < effective_limit)) { + int nx = cx - dx; + int ny = cy - dy; + wrap_tile_coords (map, &nx, &ny); + if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) + break; + if (! tile_is_land (-1, nx, ny, false)) + break; + if (tile_part_of_existing_candidate (nx, ny)) + break; + back_x[back_count] = (short)nx; + back_y[back_count] = (short)ny; + back_count++; + remaining--; + cx = nx; + cy = ny; + } + + cx = start_x; + cy = start_y; + while ((remaining > 0) && (forward_count < effective_limit)) { + int nx = cx + dx; + int ny = cy + dy; + wrap_tile_coords (map, &nx, &ny); + if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) + break; + if (! tile_is_land (-1, nx, ny, false)) + break; + if (tile_part_of_existing_candidate (nx, ny)) + break; + forward_x[forward_count] = (short)nx; + forward_y[forward_count] = (short)ny; + forward_count++; + remaining--; + cx = nx; + cy = ny; + } + + int write = 0; + for (int bi = back_count - 1; bi >= 0; bi--) { + out_x[write] = back_x[bi]; + out_y[write] = back_y[bi]; + write++; + } + out_x[write] = (short)start_x; + out_y[write] = (short)start_y; + write++; + for (int fi = 0; fi < forward_count; fi++) { + out_x[write] = forward_x[fi]; + out_y[write] = forward_y[fi]; + write++; + } + + return write; +} + +bool +cluster_connects_two_seas_or_isthmus (short * xs, short * ys, int count) +{ + for (int i = 0; i < count; i++) { + if (canal_has_different_adjacent_seas (xs[i], ys[i], -1)) + return true; + if (canal_has_same_sea_isthmus (xs[i], ys[i], -1, 2)) + return true; + } + return false; +} + +int +find_canal_candidate_in_block (Map * map, int block_x0, int block_y0, int block_x1, int block_y1, + int contiguous_limit, int candidate_capacity, + short * out_x, short * out_y, short * out_owner) +{ + const int dir_dx[8] = { 0, 1, 2, 1, 0, -1, -2, -1 }; + const int dir_dy[8] = { -2, -1, 0, 1, 2, 1, 0, -1 }; + + int max_len = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + if (candidate_capacity > 0 && max_len > candidate_capacity) + max_len = candidate_capacity; + + int tile_count = map->TileCount; + int * visit = (int *)malloc (sizeof (*visit) * tile_count); + int * queue_x = (int *)malloc (sizeof (*queue_x) * tile_count); + int * queue_y = (int *)malloc (sizeof (*queue_y) * tile_count); + if ((visit == NULL) || (queue_x == NULL) || (queue_y == NULL)) { + if (visit != NULL) + free (visit); + if (queue_x != NULL) + free (queue_x); + if (queue_y != NULL) + free (queue_y); + return 0; + } + for (int i = 0; i < tile_count; i++) + visit[i] = 0; + + int visit_mark = 1; + + for (int length = 1; length <= max_len; length++) { + for (int ti = 0; ti < map->TileCount; ti++) { + int start_x = -1; + int start_y = -1; + tile_index_to_coords (map, ti, &start_x, &start_y); + if (! tile_point_in_block (start_x, start_y, block_x0, block_y0, block_x1, block_y1)) + continue; + if (! tile_is_land (-1, start_x, start_y, false)) + continue; + if (tile_part_of_existing_candidate (start_x, start_y)) + continue; + if (tile_has_bridge_or_canal_nearby (start_x, start_y)) + continue; + if (tile_is_reserved_in_district_tile_map (start_x, start_y)) + continue; + Tile * start_tile = tile_at (start_x, start_y); + if ((start_tile == NULL) || (start_tile == p_null_tile)) + continue; + if (tile_has_resource (start_tile)) + continue; + if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], start_tile)) + continue; + int continent_id = start_tile->vtable->m46_Get_ContinentID (start_tile); + if (continent_id < 0) + continue; + short owner = start_tile->vtable->m38_Get_Territory_OwnerID (start_tile); + + int stack_len = 1; + int dir_stack[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + int path_dir[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES]; + out_x[0] = (short)start_x; + out_y[0] = (short)start_y; + dir_stack[0] = -1; + path_dir[0] = -1; + + while (stack_len > 0) { + int depth = stack_len - 1; + int cx = out_x[depth]; + int cy = out_y[depth]; + + if (depth + 1 == length) { + bool endpoints_ok = false; + if (length == 1) { + int ex = out_x[0]; + int ey = out_y[0]; + bool pair_ok = false; + if (tile_is_water (ex, ey - 2) && tile_is_water (ex, ey + 2)) pair_ok = true; + if (tile_is_water (ex - 2, ey) && tile_is_water (ex + 2, ey)) pair_ok = true; + if (tile_is_water (ex - 1, ey - 1) && tile_is_water (ex + 1, ey + 1)) pair_ok = true; + if (tile_is_water (ex - 1, ey + 1) && tile_is_water (ex + 1, ey - 1)) pair_ok = true; + if (pair_ok && tile_has_diagonal_water (ex, ey)) + endpoints_ok = true; + } else { + int first_dir = path_dir[1]; + int last_dir = path_dir[length - 1]; + int sx = out_x[0]; + int sy = out_y[0]; + int ex = out_x[length - 1]; + int ey = out_y[length - 1]; + bool start_water = tile_is_water (sx - dir_dx[first_dir], sy - dir_dy[first_dir]); + bool end_water = tile_is_water (ex + dir_dx[last_dir], ey + dir_dy[last_dir]); + if (start_water && end_water && + tile_has_diagonal_water (sx, sy) && + tile_has_diagonal_water (ex, ey)) + endpoints_ok = true; + } + + bool buildable = true; + if (endpoints_ok) { + for (int pi = 0; pi < length; pi++) { + Tile * path_tile = tile_at (out_x[pi], out_y[pi]); + if ((path_tile == NULL) || (path_tile == p_null_tile) || + tile_has_resource (path_tile) || + (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], path_tile)) || + tile_is_reserved_in_district_tile_map (out_x[pi], out_y[pi])) { + buildable = false; + break; + } + if (tile_has_bridge_or_canal_nearby (out_x[pi], out_y[pi])) { + buildable = false; + break; + } + } + } else { + buildable = false; + } + + if (buildable) { + // Collect adjacent land tiles for component checks + int adj_x[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; + int adj_y[AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES * 8]; + int adj_count = 0; + for (int pi = 0; pi < length; pi++) { + int px = out_x[pi]; + int py = out_y[pi]; + for (int di = 0; di < 8; di++) { + int nx = px + dir_dx[di]; + int ny = py + dir_dy[di]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_is_land (-1, nx, ny, false)) + continue; + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) + continue; + bool in_path = false; + for (int pj = 0; pj < length; pj++) { + if ((out_x[pj] == nx) && (out_y[pj] == ny)) { + in_path = true; + break; + } + } + if (in_path) + continue; + bool seen = false; + for (int aj = 0; aj < adj_count; aj++) { + if ((adj_x[aj] == nx) && (adj_y[aj] == ny)) { + seen = true; + break; + } + } + if (! seen && (adj_count < (int)(sizeof (adj_x) / sizeof (adj_x[0])))) { + adj_x[adj_count] = nx; + adj_y[adj_count] = ny; + adj_count++; + } + } + } + + if (adj_count >= 2) { + int best1 = 0; + int best2 = 0; + int min_land = is->current_config.ai_canal_eval_min_bisected_land_tiles; + if (min_land < 1) + min_land = 1; + visit_mark++; + if (visit_mark == 0) { + visit_mark = 1; + for (int i = 0; i < tile_count; i++) + visit[i] = 0; + } + + for (int ai = 0; ai < adj_count; ai++) { + int aidx = tile_coords_to_index (map, adj_x[ai], adj_y[ai]); + if ((aidx < 0) || (visit[aidx] == visit_mark)) + continue; + + int comp_size = 0; + int head = 0; + int tail = 0; + visit[aidx] = visit_mark; + queue_x[tail] = adj_x[ai]; + queue_y[tail] = adj_y[ai]; + tail++; + + while (head < tail) { + int qx = queue_x[head]; + int qy = queue_y[head]; + head++; + comp_size++; + for (int di = 0; di < 8; di++) { + int nx = qx + dir_dx[di]; + int ny = qy + dir_dy[di]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_is_land (-1, nx, ny, false)) + continue; + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (adj->vtable->m46_Get_ContinentID (adj) != continent_id) + continue; + bool blocked = false; + for (int pj = 0; pj < length; pj++) { + if ((out_x[pj] == nx) && (out_y[pj] == ny)) { + blocked = true; + break; + } + } + if (blocked) + continue; + int nidx = tile_coords_to_index (map, nx, ny); + if ((nidx < 0) || (visit[nidx] == visit_mark)) + continue; + visit[nidx] = visit_mark; + queue_x[tail] = nx; + queue_y[tail] = ny; + tail++; + } + } + + if (comp_size > best1) { + best2 = best1; + best1 = comp_size; + } else if (comp_size > best2) { + best2 = comp_size; + } + } + + if ((best1 >= min_land) && (best2 >= min_land)) { + *out_owner = owner; + free (visit); + free (queue_x); + free (queue_y); + return length; + } + } + } + dir_stack[depth] = -1; + stack_len--; + continue; + } + + int next_dir = dir_stack[depth] + 1; + bool advanced = false; + while (next_dir < 8) { + int ndx = dir_dx[next_dir]; + int ndy = dir_dy[next_dir]; + int nx = cx + ndx; + int ny = cy + ndy; + wrap_tile_coords (map, &nx, &ny); + dir_stack[depth] = next_dir; + + if (! tile_point_in_block (nx, ny, block_x0, block_y0, block_x1, block_y1)) { + next_dir++; + continue; + } + if (! tile_is_land (-1, nx, ny, false)) { + next_dir++; + continue; + } + if (tile_part_of_existing_candidate (nx, ny)) { + next_dir++; + continue; + } + if (tile_is_reserved_in_district_tile_map (nx, ny)) { + next_dir++; + continue; + } + Tile * next_tile = tile_at (nx, ny); + if ((next_tile == NULL) || (next_tile == p_null_tile)) { + next_dir++; + continue; + } + if (tile_has_resource (next_tile)) { + next_dir++; + continue; + } + if (! district_is_buildable_on_tile (&is->district_configs[CANAL_DISTRICT_ID], next_tile)) { + next_dir++; + continue; + } + if (tile_has_bridge_or_canal_nearby (nx, ny)) { + next_dir++; + continue; + } + if (next_tile->vtable->m46_Get_ContinentID (next_tile) != continent_id) { + next_dir++; + continue; + } + bool dup = false; + for (int pi = 0; pi < depth + 1; pi++) { + if ((out_x[pi] == nx) && (out_y[pi] == ny)) { + dup = true; + break; + } + } + if (dup) { + next_dir++; + continue; + } + + if (depth >= 1) { + int prev_dir = dir_stack[depth - 1]; + int diff = next_dir - prev_dir; + if (diff < 0) + diff += 8; + if (diff > 4) + diff = 8 - diff; + if (diff > 1) { + next_dir++; + continue; + } + } + + out_x[depth + 1] = (short)nx; + out_y[depth + 1] = (short)ny; + dir_stack[depth + 1] = -1; + path_dir[depth + 1] = next_dir; + stack_len++; + advanced = true; + break; + } + + if (! advanced) { + dir_stack[depth] = -1; + stack_len--; + } + } + } + } + + free (visit); + free (queue_x); + free (queue_y); + return 0; +} + +void +generate_ai_bridge_candidates_by_block (Map * map, int block_size, int contiguous_limit) +{ + if ((map == NULL) || (block_size <= 0)) + return; + + int width = map->Width; + int height = map->Height; + if ((width <= 0) || (height <= 0)) + return; + + if (block_size < 1) + block_size = 1; + + int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + + short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); + short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); + if ((candidate_x == NULL) || (candidate_y == NULL)) { + if (candidate_x != NULL) + free (candidate_x); + if (candidate_y != NULL) + free (candidate_y); + return; + } + + for (int base_y = 0; base_y < height; base_y += block_size) { + int block_y1 = base_y + block_size; + if (block_y1 > height) + block_y1 = height; + for (int base_x = 0; base_x < width; base_x += block_size) { + int block_x1 = base_x + block_size; + if (block_x1 > width) + block_x1 = width; + short owner = -1; + int count = find_bridge_candidate_in_block ( + map, base_x, base_y, block_x1, block_y1, + contiguous_limit, candidate_capacity, + candidate_x, candidate_y, &owner); + if (count <= 0) + continue; + if (! add_ai_candidate_entry (BRIDGE_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { + free (candidate_x); + free (candidate_y); + return; + } + } + } + + free (candidate_x); + free (candidate_y); +} + +void +generate_ai_canal_candidates_by_block (Map * map, int block_size, int contiguous_limit) +{ + if ((map == NULL) || (block_size <= 0)) + return; + + int width = map->Width; + int height = map->Height; + if ((width <= 0) || (height <= 0)) + return; + + if (block_size < 1) + block_size = 1; + + int candidate_capacity = clamp (1, AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES, contiguous_limit); + + short * candidate_x = (short *)malloc (sizeof *candidate_x * candidate_capacity); + short * candidate_y = (short *)malloc (sizeof *candidate_y * candidate_capacity); + if ((candidate_x == NULL) || (candidate_y == NULL)) { + if (candidate_x != NULL) + free (candidate_x); + if (candidate_y != NULL) + free (candidate_y); + return; + } + + for (int base_y = 0; base_y < height; base_y += block_size) { + int block_y1 = base_y + block_size; + if (block_y1 > height) + block_y1 = height; + for (int base_x = 0; base_x < width; base_x += block_size) { + int block_x1 = base_x + block_size; + if (block_x1 > width) + block_x1 = width; + short owner = -1; + int count = find_canal_candidate_in_block ( + map, base_x, base_y, block_x1, block_y1, + contiguous_limit, candidate_capacity, + candidate_x, candidate_y, &owner); + if (count <= 0) + continue; + if (! add_ai_candidate_entry (CANAL_DISTRICT_ID, owner, candidate_x, candidate_y, count)) { + free (candidate_x); + free (candidate_y); + return; + } + } + } + + free (candidate_x); + free (candidate_y); +} + +void +generate_ai_canal_and_bridge_targets () +{ + if (is->ai_candidate_bridge_or_canals_initialized) + return; + if ((! is->current_config.enable_canal_districts) && (! is->current_config.enable_bridge_districts)) + return; + + Map * map = &p_bic_data->Map; + int width = map->Width; + int height = map->Height; + if ((width <= 0) || (height <= 0)) + return; + + int block_size = is->current_config.ai_bridge_canal_eval_block_size; + if (block_size <= 0) + block_size = 10; + + if (is->current_config.enable_bridge_districts && is->current_config.ai_builds_bridges) { + generate_ai_bridge_candidates_by_block ( + map, + block_size, + is->current_config.max_contiguous_bridge_districts); + } + + if (is->current_config.enable_canal_districts && is->current_config.ai_builds_canals) { + generate_ai_canal_candidates_by_block ( + map, + block_size, + is->current_config.max_contiguous_canal_districts); + } + + is->ai_candidate_bridge_or_canals_initialized = true; +} + +void +assign_workers_for_ai_candidate_bridge_or_canals (Leader * leader) +{ + if ((leader == NULL) || (is->ai_candidate_bridge_or_canals_count <= 0)) + return; + + int civ_id = leader->ID; + if ((*p_human_player_bits & (1 << civ_id)) != 0) + return; + + if (! leader_can_build_district (leader, CANAL_DISTRICT_ID) && ! leader_can_build_district (leader, BRIDGE_DISTRICT_ID)) + return; + + if (! is->ai_candidate_bridge_or_canals_initialized) { + reset_ai_candidate_bridge_or_canals (); + generate_ai_canal_and_bridge_targets (); + } + + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if (entry->completed) + continue; + + int district_id = entry->district_id; + if ((district_id == CANAL_DISTRICT_ID) && (! is->current_config.enable_canal_districts)) continue; + if ((district_id == BRIDGE_DISTRICT_ID) && (! is->current_config.enable_bridge_districts)) continue; + if (! leader_can_build_district (leader, district_id)) continue; + + if (entry->assigned_worker_id >= 0) { + Unit * worker = get_unit_ptr (entry->assigned_worker_id); + if (worker == NULL) { + release_ai_candidate_bridge_or_canal_worker (entry); + } else if ((entry->assigned_tile_index >= 0) && (entry->assigned_tile_index < entry->tile_count)) { + int tx = entry->tile_x[entry->assigned_tile_index]; + int ty = entry->tile_y[entry->assigned_tile_index]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + Tile * tile = tile_at (tx, ty); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && inst->district_id == district_id && district_is_complete (tile, district_id)) { + release_ai_candidate_bridge_or_canal_worker (entry); + } + } + } + if (entry->assigned_worker_id >= 0) + continue; + } + + int target_idx = -1; + if (! ai_candidate_bridge_or_canal_is_buildable_for_civ (entry, civ_id, &target_idx)) { + release_ai_candidate_bridge_or_canal_worker (entry); + continue; + } + + if (target_idx < 0) + continue; + + City * city = find_closest_owned_city_for_tile (civ_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); + if (city == NULL) + continue; + + Unit * worker = find_best_worker_for_district (leader, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx]); + if (worker == NULL) + continue; + + memset (&entry->pending_req, 0, sizeof entry->pending_req); + entry->pending_req.district_id = district_id; + entry->pending_req.civ_id = civ_id; + if (! assign_worker_to_district (&entry->pending_req, worker, city, district_id, entry->tile_x[target_idx], entry->tile_y[target_idx])) + continue; + + entry->assigned_worker_id = worker->Body.ID; + entry->assigned_tile_index = target_idx; + } +} + +void +recompute_city_yields_with_districts (City * city) +{ + if (city == NULL) + return; + + bool prev_flag = is->distribution_hub_refresh_in_progress; + is->distribution_hub_refresh_in_progress = true; + patch_City_recompute_yields_and_happiness (city); + is->distribution_hub_refresh_in_progress = prev_flag; +} + +enum UnitStateType __fastcall +patch_City_instruct_worker (City * this, int edx, int tile_x, int tile_y, bool param_3, Unit * worker) +{ + return City_instruct_worker (this, __, tile_x, tile_y, param_3, worker); +} + +int +find_wonder_config_index_by_improvement_id (int improv_id) +{ + if (improv_id < 0) + return -1; + + char ss[200]; + + for (int wi = 0; wi < is->wonder_district_count; wi++) { + int bid = -1; + if (stable_look_up (&is->building_name_to_id, is->wonder_district_configs[wi].wonder_name, &bid) && + (bid == improv_id)) { + return wi; + } + } + + return -1; +} + +void set_wonder_built_flag (int improv_id, bool is_built); + +unsigned int +wonder_buildable_square_type_mask (struct wonder_district_config const * cfg) +{ + if (cfg == NULL) + return district_default_buildable_mask (); + + unsigned int mask = cfg->buildable_square_types_mask; + if (mask == 0) + mask = district_default_buildable_mask (); + return mask; +} + +unsigned int +wonder_buildable_mask_for_improvement (int improv_id) +{ + int windex = find_wonder_config_index_by_improvement_id (improv_id); + if (windex < 0) + return district_default_buildable_mask (); + return wonder_buildable_square_type_mask (&is->wonder_district_configs[windex]); +} + +bool +wonder_is_buildable_on_square_type (struct wonder_district_config const * cfg, Tile * tile) +{ + if ((cfg == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + if (! tile_matches_square_type_mask (tile, wonder_buildable_square_type_mask (cfg))) + return false; + + if (cfg->buildable_on_rivers && (tile->vtable->m37_Get_River_Code (tile) == 0)) + return false; + + if (cfg->has_buildable_adjacent_to) { + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + return false; + + bool matches = false; + bool city_adjacent = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (Tile_has_city (tai.tile)) { + city_adjacent = true; + if (cfg->buildable_adjacent_to_allows_city) + matches = true; + } + if (tile_matches_square_type_mask (tai.tile, cfg->buildable_adjacent_to_square_types_mask)) + matches = true; + if (matches && (cfg->buildable_adjacent_to_allows_city || ! city_adjacent)) + break; + } + if (city_adjacent && ! cfg->buildable_adjacent_to_allows_city) + return false; + if (! matches) + return false; + } + + if (cfg->has_buildable_adjacent_to_overlays) { + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + return false; + + bool matches = false; + FOR_TILES_AROUND (tai, 9, tile_x, tile_y) { + if (tai.n == 0) + continue; + if (tile_matches_overlay_mask (tai.tile, cfg->buildable_adjacent_to_overlays_mask)) { + matches = true; + break; + } + } + if (! matches) + return false; + } + + return true; +} + +bool +wonder_is_buildable_on_tile (Tile * tile, int wonder_improv_id) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); + if (windex < 0) + return tile_matches_square_type_mask (tile, district_default_buildable_mask ()); + + return wonder_is_buildable_on_square_type (&is->wonder_district_configs[windex], tile); +} + +bool +wonder_is_buildable_by_civ (int wonder_improv_id, int civ_id) +{ + if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) + return false; + if ((civ_id < 0) || (civ_id >= 32)) + return false; + + int windex = find_wonder_config_index_by_improvement_id (wonder_improv_id); + if (windex < 0) + return true; + + struct wonder_district_config const * cfg = &is->wonder_district_configs[windex]; + Leader * leader = &leaders[civ_id]; + + if (cfg->has_buildable_by_civs) { + bool civ_match = false; + if (cfg->buildable_by_civ_count > 0) { + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + for (int i = 0; i < cfg->buildable_by_civ_count; i++) { + char const * civ_name = cfg->buildable_by_civs[i]; + if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; + if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; + if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; + if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; + if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; + } + } + if (! civ_match) + return false; + } + + if (cfg->has_buildable_by_civ_traits) { + if (cfg->buildable_by_civ_traits_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL || race->vtable == NULL) + return false; + bool trait_match = false; + for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { + int trait_id = cfg->buildable_by_civ_traits_ids[i]; + if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { + trait_match = true; + break; + } + } + if (! trait_match) + return false; + } + + if (cfg->has_buildable_by_civ_govs) { + if (cfg->buildable_by_civ_govs_id_count <= 0) + return false; + int gov_id = leader->GovernmentType; + bool gov_match = false; + for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { + if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { + gov_match = true; + break; + } + } + if (! gov_match) + return false; + } + + if (cfg->has_buildable_by_civ_cultures) { + if (cfg->buildable_by_civ_cultures_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + int culture_id = race->CultureGroupID; + bool culture_match = false; + for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { + if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { + culture_match = true; + break; + } + } + if (! culture_match) + return false; + } + + return true; +} + +int +get_wonder_improvement_id_from_index (int windex) +{ + if ((windex < 0) || (windex >= is->wonder_district_count)) + return -1; + + char const * wonder_name = is->wonder_district_configs[windex].wonder_name; + if ((wonder_name == NULL) || (wonder_name[0] == '\0')) + return -1; + + int improv_id; + if (stable_look_up (&is->building_name_to_id, (char *)wonder_name, &improv_id)) + return improv_id; + else + return -1; +} + +void +remember_pending_building_order (City * city, int improvement_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (improvement_id < 0)) + return; + + if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) + return; + + itable_insert (&is->city_pending_building_orders, (int)city, improvement_id); +} + +bool +look_up_pending_building_order (City * city, int * out_improv_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (out_improv_id == NULL)) + return false; + + return itable_look_up (&is->city_pending_building_orders, (int)city, out_improv_id); +} + +void +forget_pending_building_order (City * city) +{ + if (! is->current_config.enable_districts || + (city == NULL)) + return; + + itable_remove (&is->city_pending_building_orders, (int)city); +} + +bool +is_wonder_or_small_wonder_already_being_built (City * city, int improv_id) +{ + if ((city == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) + return false; + + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) + return false; + + int civ_id = city->Body.CivID; + FOR_CITIES_OF (coi, civ_id) { + City * other_city = coi.city; + if ((other_city == NULL) || (other_city == city)) + continue; + + if ((other_city->Body.Order_Type == COT_Improvement) && + (other_city->Body.Order_ID == improv_id)) + return true; + } + + return false; +} + +struct district_building_prereq_list * +get_district_building_prereq_list (int improv_id) +{ + if (improv_id < 0) + return NULL; + + int stored = 0; + if (! itable_look_up (&is->district_building_prereqs, improv_id, &stored)) + return NULL; + return (struct district_building_prereq_list *)stored; +} + +bool +district_building_prereq_list_contains (struct district_building_prereq_list * list, int district_id) +{ + if ((list == NULL) || (district_id < 0)) + return false; + for (int i = 0; i < list->count; i++) { + if (list->district_ids[i] == district_id) + return true; + } + return false; +} + +void +add_district_building_prereq (int improv_id, int district_id) +{ + if ((improv_id < 0) || (district_id < 0)) + return; + + struct district_building_prereq_list * list = get_district_building_prereq_list (improv_id); + if (list == NULL) { + list = calloc (1, sizeof *list); + if (list == NULL) + return; + list->count = 0; + itable_insert (&is->district_building_prereqs, improv_id, (int)list); + } + + if (district_building_prereq_list_contains (list, district_id)) + return; + + if (list->count >= ARRAY_LEN (list->district_ids)) + return; + + list->district_ids[list->count++] = district_id; +} + +bool +city_has_river_district (City * city, int district_id) +{ + if (city == NULL) + return false; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if (wai.district_inst->district_id != district_id) + continue; + if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) + return true; + } + return false; +} + +bool +city_has_any_prereq_district_for_improvement (City * city, + struct district_building_prereq_list * list, + bool requires_river, + bool allow_wonder_district) +{ + if ((city == NULL) || (list == NULL)) + return false; + + for (int i = 0; i < list->count; i++) { + int district_id = list->district_ids[i]; + if (district_id < 0) + continue; + if (! allow_wonder_district && district_id == WONDER_DISTRICT_ID) + continue; + if (requires_river) { + if (city_has_river_district (city, district_id)) + return true; + } else if (city_has_required_district (city, district_id)) { + return true; + } + } + return false; +} + +int +pick_missing_district_for_improvement (City * city, struct district_building_prereq_list * list) +{ + if ((list == NULL) || (list->count <= 0)) + return -1; + + int fallback = -1; + for (int i = 0; i < list->count; i++) { + int district_id = list->district_ids[i]; + if (district_id < 0) + continue; + if (fallback < 0) + fallback = district_id; + if ((city != NULL) && leader_can_build_district (&leaders[city->Body.CivID], district_id)) + return district_id; + } + return fallback; +} + + +bool +district_is_complete(Tile * tile, int district_id) +{ + if ((tile == NULL) || (tile == p_null_tile) || + (district_id < 0) || (district_id >= is->district_count)) + return false; + + bool is_natural_wonder = (district_id == NATURAL_WONDER_DISTRICT_ID); + bool districts_disabled = ! is->current_config.enable_districts; + bool natural_wonders_disabled = ! is->current_config.enable_natural_wonders; + struct district_config const * cfg = &is->district_configs[district_id]; + + if (districts_disabled && (!is_natural_wonder || natural_wonders_disabled)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != district_id) + return false; + + // If already marked COMPLETED, just return true + if (inst->state == DS_COMPLETED) + return true; + + // State is UNDER_CONSTRUCTION - check if tile has mines now + bool has_mines = tile->vtable->m18_Check_Mines (tile, __, 0) != 0; + + if (! has_mines) { + // Still under construction - check if we should clean it up + bool worker_present = false; + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit != NULL) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { + worker_present = true; + break; + } + } + if (! worker_present) { + remove_district_instance (tile); + } + return false; + } + + // Mark as completed and run one-time side effects + inst->state = DS_COMPLETED; + inst->completed_turn = *p_current_turn_no; + + int tile_x, tile_y; + if (district_instance_get_coords (inst, tile, &tile_x, &tile_y)) { + set_tile_unworkable_for_all_cities (tile, tile_x, tile_y); + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + if (cfg->auto_add_road) { + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + if (! has_road) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_ROAD, tile_x, tile_y); + } + + if (cfg->auto_add_railroad) { + bool has_railroad = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; + if (! has_railroad) { + if ((territory_owner >= 0) && patch_Leader_can_do_worker_job (&leaders[territory_owner], __, WJ_Build_Railroad, tile_x, tile_y, 0)) { + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_RAILROAD, tile_x, tile_y); + } + } + } + + // Activate distribution hub if applicable + if (is->current_config.enable_distribution_hub_districts && + (district_id == DISTRIBUTION_HUB_DISTRICT_ID)) { + on_distribution_hub_completed (tile, tile_x, tile_y); + } + + // Remove forest/swamp if applicable + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + if ((base_type == SQ_Forest) || (base_type == SQ_Swamp)) { + int new_terrain_type = tile->vtable->m71_Check_Worker_Job (tile); + if (new_terrain_type >= 0) + Map_change_tile_terrain (&p_bic_data->Map, __, (enum SquareTypes)new_terrain_type, tile_x, tile_y); + } + + char ss[200]; + snprintf (ss, sizeof ss, "District %d completed at tile (%d,%d)\n", district_id, tile_x, tile_y); + (*p_OutputDebugStringA) (ss); + + // Check if this was an AI-requested district + struct pending_district_request * req = find_pending_district_request_by_coords (NULL, tile_x, tile_y, district_id); + if (req != NULL) { + City * requesting_city = get_city_ptr (req->city_id); + if (requesting_city != NULL) { + req->city = requesting_city; + snprintf (ss, sizeof ss, "District %d at tile (%d,%d) was ordered by city %s\n", + district_id, tile_x, tile_y, requesting_city->Body.CityName); + (*p_OutputDebugStringA) (ss); + + // Check if city has pending building order that depends on this district + int pending_improv_id; + if (look_up_pending_building_order (requesting_city, &pending_improv_id)) { + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (pending_improv_id); + if (district_building_prereq_list_contains (prereq_list, district_id)) { + snprintf (ss, sizeof ss, "City %s setting production to improvement %d\n", + requesting_city->Body.CityName, pending_improv_id); + (*p_OutputDebugStringA) (ss); + + // Check if another city is already building this wonder/small wonder + bool can_set_production = true; + if (is_wonder_or_small_wonder_already_being_built (requesting_city, pending_improv_id)) { + snprintf (ss, sizeof ss, "City %s cannot build improvement %d - already being built elsewhere\n", + requesting_city->Body.CityName, pending_improv_id); + (*p_OutputDebugStringA) (ss); + can_set_production = false; + } + + // Set city production to the pending improvement + if (can_set_production && City_can_build_improvement (requesting_city, __, pending_improv_id, false)) { + snprintf (ss, sizeof ss, "City %s can now build improvement %d\n", + requesting_city->Body.CityName, pending_improv_id); + (*p_OutputDebugStringA) (ss); + City_set_production (requesting_city, __, COT_Improvement, pending_improv_id, false); + } + + // Clear the pending building order + forget_pending_building_order (requesting_city); + } + } + + // Clear worker assignment so worker is freed up for other tasks + if (req->assigned_worker_id >= 0) { + snprintf (ss, sizeof ss, "Clearing worker assignment for unit %d\n", req->assigned_worker_id); + (*p_OutputDebugStringA) (ss); + int civ_id = req->civ_id; + clear_tracked_worker_assignment_by_id (civ_id, req->assigned_worker_id); + } + } + + // Remove the pending district request + remove_pending_district_request (req); + } + } + + return true; +} + +void +mark_city_needs_district (City * city, int district_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (district_id < 0) || (district_id >= is->district_count)) + return; + + create_pending_district_request (city, district_id); +} + +void +set_tile_unworkable_for_all_cities (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return; + + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + + City * assigned_city = NULL; + int assigned_city_id = tile->Body.CityAreaID; + if (assigned_city_id >= 0) + assigned_city = get_city_ptr (assigned_city_id); + + if (assigned_city != NULL) { + int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, + assigned_city->Body.X, assigned_city->Body.Y, tile_x, tile_y, 1000); + bool removed_assignment = false; + if ((neighbor_index > 0) && (neighbor_index < ARRAY_LEN (is->ni_to_work_radius))) + removed_assignment = City_stop_working_tile (assigned_city, __, neighbor_index); + if (! removed_assignment) + tile->Body.CityAreaID = -1; + if (! removed_assignment) + recompute_city_yields_with_districts (assigned_city); + } else + tile->Body.CityAreaID = -1; + + if (p_cities->Cities != NULL) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city == NULL) || (city == assigned_city)) + continue; + int neighbor_index = Map_compute_neighbor_index (&p_bic_data->Map, __, + city->Body.X, city->Body.Y, tile_x, tile_y, 1000); + if ((neighbor_index <= 0) || (neighbor_index >= ARRAY_LEN (is->ni_to_work_radius))) + continue; + int work_radius = is->ni_to_work_radius[neighbor_index]; + if ((work_radius < 0) || (work_radius > is->current_config.city_work_radius)) + continue; + recompute_city_yields_with_districts (city); + } + } +} + +struct distribution_hub_record * +get_distribution_hub_record (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + + int stored; + if (itable_look_up (&is->distribution_hub_records, (int)tile, &stored)) + return (struct distribution_hub_record *)stored; + else + return NULL; +} + +City * +get_connected_city_for_distribution_hub (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return NULL; + + Tile * tile = rec->tile; + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + + City * best_city = NULL; + int best_distance = INT_MAX; + int best_y = INT_MAX; + int best_x = INT_MAX; + int best_id = INT_MAX; + + FOR_CITIES_OF (coi, rec->civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, city, rec->tile_x, rec->tile_y)) + continue; + + int distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, city->Body.X, city->Body.Y); + if ((best_city == NULL) || + (distance < best_distance) || + ((distance == best_distance) && (city->Body.Y < best_y)) || + ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X < best_x)) || + ((distance == best_distance) && (city->Body.Y == best_y) && (city->Body.X == best_x) && (city->Body.ID < best_id))) { + best_city = city; + best_distance = distance; + best_y = city->Body.Y; + best_x = city->Body.X; + best_id = city->Body.ID; + } + } + + return best_city; +} + +bool +distribution_hub_accessible_to_city (struct distribution_hub_record * rec, City * city) +{ + if ((rec == NULL) || (city == NULL)) + return false; + + if (city->Body.CivID != rec->civ_id) + return false; + + City * anchor_city = get_connected_city_for_distribution_hub (rec); + if (anchor_city == NULL) + return false; + + if (anchor_city == city) + return true; + + return Trade_Net_have_trade_connection (is->trade_net, __, anchor_city, city, rec->civ_id); +} + +void +get_distribution_hub_yields_for_city (City * city, int * out_food, int * out_shields) +{ + int food = 0; + int shields = 0; + + if ((city != NULL) && + is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts) { + if (is->distribution_hub_totals_dirty && + ! is->distribution_hub_refresh_in_progress) + recompute_distribution_hub_totals (); + + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (distribution_hub_accessible_to_city (rec, city)) { + food += rec->food_yield; + shields += rec->shield_yield; + } + } + } + + if (city_has_required_district (city, CENTRAL_RAIL_HUB_DISTRICT_ID)) { + food += (food * is->current_config.central_rail_hub_distribution_food_bonus_percent) / 100; + shields += (shields * is->current_config.central_rail_hub_distribution_shield_bonus_percent) / 100; + } + + if (out_food != NULL) + *out_food = food; + if (out_shields != NULL) + *out_shields = shields; +} + +void +adjust_distribution_hub_coverage (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return; + + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if ((area_tile == NULL) || (area_tile == p_null_tile)) + continue; + int tx = tai.tile_x; + int ty = tai.tile_y; + + if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) + continue; + if (Tile_has_city (area_tile)) + continue; + if (get_district_instance (area_tile) != NULL) + continue; + + struct wonder_district_info * area_info = get_wonder_district_info (area_tile); + if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) + continue; + + int key = (int)area_tile; + int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); + itable_insert (&is->distribution_hub_coverage_counts, key, prev + 1); + + if (area_tile->Body.CityAreaID >= 0) { + set_tile_unworkable_for_all_cities (area_tile, tx, ty); + area_tile->Body.CityAreaID = -1; + } + } +} + +void +release_distribution_hub_coverage (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return; + + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if ((area_tile == NULL) || (area_tile == p_null_tile)) + continue; + + int key = (int)area_tile; + int prev = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); + if (prev <= 0) + continue; + + if (prev == 1) + itable_remove (&is->distribution_hub_coverage_counts, key); + else + itable_insert (&is->distribution_hub_coverage_counts, key, prev - 1); + } +} + +void +clear_distribution_hub_tables (void) +{ + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + free (rec); + } + table_deinit (&is->distribution_hub_records); + table_deinit (&is->distribution_hub_coverage_counts); + is->distribution_hub_totals_dirty = true; +} + +bool +city_radius_contains_tile (City * city, int tile_x, int tile_y) +{ + if (city == NULL) + return false; + + int ni = patch_Map_compute_ni_for_work_area (&p_bic_data->Map, __, city->Body.X, city->Body.Y, tile_x, tile_y, is->workable_tile_count); + return ni >= 0; +} + +void +recompute_distribution_hub_yields (struct distribution_hub_record * rec) +{ + if (rec == NULL) + return; + + Tile * tile = tile_at (rec->tile_x, rec->tile_y); + rec->tile = tile; + + if ((tile == NULL) || + (tile == p_null_tile) || + ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID) || + tile->vtable->m20_Check_Pollution (tile, __, 0) || + tile_has_enemy_unit (tile, rec->civ_id)) { + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + return; + } + + int food_sum = 0; + int shield_sum = 0; + City * anchor_city = get_connected_city_for_distribution_hub (rec); + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if (area_tile == p_null_tile) + continue; + int tx = tai.tile_x; + int ty = tai.tile_y; + + // Only include tiles that belong to the distribution hub owner + if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) + continue; + + // Skip city tiles + if (Tile_has_city (area_tile)) + continue; + + // Skip tiles with enemy units + if (tile_has_enemy_unit (area_tile, rec->civ_id)) + continue; + + // Skip tiles with pollution + if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) + continue; + + // Skip tiles that are other districts (but not this hub itself) + struct district_instance * area_district = get_district_instance (area_tile); + if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) + continue; + + // Skip tiles with completed wonders + struct wonder_district_info * area_info = get_wonder_district_info (area_tile); + if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) + continue; + + // Check if another hub of the same civ is closer to this tile + int my_distance = compute_wrapped_manhattan_distance (rec->tile_x, rec->tile_y, tx, ty); + bool tile_belongs_to_me = true; + + FOR_TABLE_ENTRIES (other_tei, &is->distribution_hub_records) { + struct distribution_hub_record * other_rec = (struct distribution_hub_record *)other_tei.value; + if ((other_rec == NULL) || (other_rec == rec)) + continue; + if (other_rec->civ_id != rec->civ_id) + continue; + + int other_distance = compute_wrapped_manhattan_distance (other_rec->tile_x, other_rec->tile_y, tx, ty); + if (other_distance < my_distance) { + tile_belongs_to_me = false; + break; + } + if (other_distance == my_distance) { + // Tie-breaking: prefer hub with lower Y, then lower X + if (other_rec->tile_y < rec->tile_y) { + tile_belongs_to_me = false; + break; + } + if ((other_rec->tile_y == rec->tile_y) && (other_rec->tile_x < rec->tile_x)) { + tile_belongs_to_me = false; + break; + } + } + } + + if (! tile_belongs_to_me) + continue; + + food_sum += City_calc_tile_yield_at (anchor_city, __, 0, tx, ty); + shield_sum += City_calc_tile_yield_at (anchor_city, __, 1, tx, ty); + } + + rec->raw_food_yield = food_sum; + rec->raw_shield_yield = shield_sum; + + int food_div = is->current_config.distribution_hub_food_yield_divisor; + int shield_div = is->current_config.distribution_hub_shield_yield_divisor; + if (food_div <= 0) + food_div = 1; + if (shield_div <= 0) + shield_div = 1; + + int connected_city_count = 0; + if (anchor_city != NULL) { + FOR_CITIES_OF (coi, rec->civ_id) { + City * other_city = coi.city; + if ((other_city != NULL) && distribution_hub_accessible_to_city (rec, other_city)) + connected_city_count++; + } + } + if (connected_city_count <= 0) + connected_city_count = 1; + + if (is->current_config.distribution_hub_yield_division_mode == DHYDM_SCALE_BY_CITY_COUNT) { + int city_root = 1; + while ((city_root + 1) * (city_root + 1) <= connected_city_count) + city_root++; + int city_food_divisor = city_root * food_div; + int city_shield_divisor = city_root * shield_div; + if (city_food_divisor < 1) city_food_divisor = 1; + if (city_shield_divisor < 1) city_shield_divisor = 1; + rec->food_yield = food_sum / city_food_divisor; + rec->shield_yield = shield_sum / city_shield_divisor; + } else { + rec->food_yield = food_sum / food_div; + rec->shield_yield = shield_sum / shield_div; + } +} + +void +remove_distribution_hub_record (Tile * tile) +{ + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec == NULL) + return; + + int affected_civ_id = rec->civ_id; + release_distribution_hub_coverage (rec); + itable_remove (&is->distribution_hub_records, (int)tile); + free (rec); + is->distribution_hub_totals_dirty = true; + recompute_distribution_hub_totals (); + + // Recalculate yields for all cities of this civ + if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * target_city = get_city_ptr (city_index); + if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) + recompute_city_yields_with_districts (target_city); + } + } +} + +void +recompute_distribution_hub_totals () +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_distribution_hub_districts) { + is->distribution_hub_totals_dirty = false; + return; + } + + struct table new_coverage_counts = {0}; + struct table newly_covered_tiles = {0}; + + clear_memo (); + int civs_needing_recalc[32] = {0}; + + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + Tile * tile = (Tile *)tei.key; + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (rec == NULL) + continue; + + Tile * current_tile = tile_at (rec->tile_x, rec->tile_y); + if ((current_tile == NULL) || + (current_tile == p_null_tile) || + ! district_is_complete (current_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { + memoize (tei.key); + continue; + } + + rec->tile = current_tile; + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + + int old_civ_id = rec->civ_id; + rec->civ_id = current_tile->vtable->m38_Get_Territory_OwnerID (current_tile); + + if (old_civ_id != rec->civ_id) + civs_needing_recalc[old_civ_id] = 1; + civs_needing_recalc[rec->civ_id] = 1; + + City * anchor = get_connected_city_for_distribution_hub (rec); + + if ((anchor == NULL) || + current_tile->vtable->m20_Check_Pollution (current_tile, __, 0) || + tile_has_enemy_unit (current_tile, rec->civ_id)) + continue; + + FOR_TILES_AROUND (tai, workable_tile_counts[1], rec->tile_x, rec->tile_y) { + Tile * area_tile = tai.tile; + if (area_tile == p_null_tile) + continue; + int tx = tai.tile_x; + int ty = tai.tile_y; + + if (area_tile->vtable->m38_Get_Territory_OwnerID (area_tile) != rec->civ_id) + continue; + if (Tile_has_city (area_tile)) + continue; + if (tile_has_enemy_unit (area_tile, rec->civ_id)) + continue; + if (area_tile->vtable->m20_Check_Pollution (area_tile, __, 0)) + continue; + + struct district_instance * area_district = get_district_instance (area_tile); + if ((area_district != NULL) && ((tx != rec->tile_x) || (ty != rec->tile_y))) + continue; + + struct wonder_district_info * area_info = get_wonder_district_info (area_tile); + if ((area_info != NULL) && (area_info->state == WDS_COMPLETED)) + continue; + + int key = (int)area_tile; + int prev_cover_pass = itable_look_up_or (&new_coverage_counts, key, 0); + int prev_cover_old = itable_look_up_or (&is->distribution_hub_coverage_counts, key, 0); + itable_insert (&new_coverage_counts, key, prev_cover_pass + 1); + if ((prev_cover_pass == 0) && (prev_cover_old <= 0)) + itable_insert (&newly_covered_tiles, key, 1); + } + } + + for (int i = 0; i < is->memo_len; i++) + remove_distribution_hub_record ((Tile *)is->memo[i]); + clear_memo (); + + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (rec == NULL) + continue; + + City * anchor = get_connected_city_for_distribution_hub (rec); + if (anchor == NULL) { + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + continue; + } + + recompute_distribution_hub_yields (rec); + } + + table_deinit (&is->distribution_hub_coverage_counts); + is->distribution_hub_coverage_counts = new_coverage_counts; + memset (&new_coverage_counts, 0, sizeof new_coverage_counts); + + FOR_TABLE_ENTRIES (tei, &newly_covered_tiles) { + Tile * covered_tile = (Tile *)tei.key; + if ((covered_tile == NULL) || (covered_tile == p_null_tile)) + continue; + int tx, ty; + if (! tile_coords_from_ptr (&p_bic_data->Map, covered_tile, &tx, &ty)) + continue; + set_tile_unworkable_for_all_cities (covered_tile, tx, ty); + covered_tile->Body.CityAreaID = -1; + } + table_deinit (&newly_covered_tiles); + + // Recalculate yields for cities of civs whose distribution hub ownership changed + for (int civ_id = 0; civ_id < 32; civ_id++) { + if (civs_needing_recalc[civ_id] && (p_cities->Cities != NULL)) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city != NULL) && (city->Body.CivID == civ_id)) + recompute_city_yields_with_districts (city); + } + } + } + + is->distribution_hub_totals_dirty = false; +} + +void +on_distribution_hub_completed (Tile * tile, int tile_x, int tile_y) +{ + if (! is->current_config.enable_districts || ! is->current_config.enable_distribution_hub_districts) + return; + + int tile_owner = -1; + if ((tile != NULL) && (tile != p_null_tile)) + tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec != NULL) { + int old_civ_id = rec->civ_id; + rec->tile = tile; + rec->tile_x = tile_x; + rec->tile_y = tile_y; + + release_distribution_hub_coverage (rec); + rec->civ_id = tile_owner; + is->distribution_hub_totals_dirty = true; + recompute_distribution_hub_totals (); + + if (old_civ_id != tile_owner) { + // Recompute for old civ + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * target_city = get_city_ptr (city_index); + if ((target_city != NULL) && (target_city->Body.CivID == old_civ_id)) + recompute_city_yields_with_districts (target_city); + } + } + } + + rec = malloc (sizeof *rec); + if (rec == NULL) + return; + rec->tile = tile; + rec->tile_x = tile_x; + rec->tile_y = tile_y; + rec->civ_id = tile_owner; + rec->food_yield = 0; + rec->shield_yield = 0; + rec->raw_food_yield = 0; + rec->raw_shield_yield = 0; + itable_insert (&is->distribution_hub_records, (int)tile, (int)rec); + adjust_distribution_hub_coverage (rec); + + is->distribution_hub_totals_dirty = true; + recompute_distribution_hub_totals (); + + // Recalculate yields for all cities of this civ + int affected_civ_id = rec->civ_id; + if ((affected_civ_id >= 0) && (p_cities->Cities != NULL)) { + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * target_city = get_city_ptr (city_index); + if ((target_city != NULL) && (target_city->Body.CivID == affected_civ_id)) + recompute_city_yields_with_districts (target_city); + } + } +} + +void +refresh_distribution_hubs_for_city (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_distribution_hub_districts || + (city == NULL)) + return; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int tx = wai.tile_x, ty = wai.tile_y; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID) + continue; + on_distribution_hub_completed (tile, tx, ty); + } +} + +bool +is_space_char (char c) +{ + switch (c) { + case ' ': + case '\t': + case '\n': + case '\r': + case '\f': + case '\v': + return true; + default: + return false; + } +} + +enum key_value_parse_status { + KVP_SUCCESS, + KVP_NO_EQUALS, + KVP_EMPTY_KEY +}; + +enum key_value_parse_status +parse_trimmed_key_value (struct string_slice const * trimmed, + struct string_slice * out_key, + struct string_slice * out_value) +{ + if ((trimmed == NULL) || (trimmed->len <= 0)) + return KVP_NO_EQUALS; + + char * equals = NULL; + for (int i = 0; i < trimmed->len; i++) { + if (trimmed->str[i] == '=') { + equals = trimmed->str + i; + break; + } + } + if (equals == NULL) + return KVP_NO_EQUALS; + + struct string_slice key = { .str = trimmed->str, .len = (int)(equals - trimmed->str) }; + key = trim_string_slice (&key, 0); + if (key.len == 0) + return KVP_EMPTY_KEY; + + struct string_slice value = { .str = equals + 1, .len = (int)((trimmed->str + trimmed->len) - (equals + 1)) }; + *out_key = key; + *out_value = trim_string_slice (&value, 0); + return KVP_SUCCESS; +} + +void +add_key_parse_error (struct error_line ** parse_errors, + int line_number, + struct string_slice const * key, + struct string_slice const * value, + char const * message_suffix) +{ + struct error_line * err = add_error_line (parse_errors); + char * key_str = extract_slice (key); + char * value_str = (value != NULL) ? extract_slice (value) : NULL; + if (value_str != NULL) + snprintf (err->text, sizeof err->text, "^ Line %d: %s \"%s\" %s", line_number, key_str, value_str, message_suffix); + else + snprintf (err->text, sizeof err->text, "^ Line %d: %s %s", line_number, key_str, message_suffix); + err->text[(sizeof err->text) - 1] = '\0'; + if (value_str != NULL) + free (value_str); + free (key_str); +} + +void +add_unrecognized_key_error (struct error_line ** unrecognized_keys, + int line_number, + struct string_slice const * key) +{ + struct error_line * err_line = add_error_line (unrecognized_keys); + char * key_str = extract_slice (key); + snprintf (err_line->text, sizeof err_line->text, "^ Line %d: %s", line_number, key_str); + err_line->text[(sizeof err_line->text) - 1] = '\0'; + free (key_str); +} + +char * +copy_trimmed_string_or_null (struct string_slice const * slice, int remove_quotes) +{ + struct string_slice trimmed = trim_string_slice (slice, remove_quotes); + if (trimmed.len == 0) + return NULL; + return extract_slice (&trimmed); +} + +void +free_bonus_entry_list (struct district_bonus_list * list) +{ + if (list == NULL) + return; + + for (int i = 0; i < list->count; i++) { + if (list->entries[i].type == DBET_BUILDING && + list->entries[i].building_name != NULL) { + free ((void *)list->entries[i].building_name); + list->entries[i].building_name = NULL; + } + } + list->count = 0; +} + +void +free_bonus_entry_list_override (struct district_bonus_list * list, + struct district_bonus_list const * defaults) +{ + if (list == NULL) + return; + + for (int i = 0; i < list->count; i++) { + if (list->entries[i].type == DBET_BUILDING && + list->entries[i].building_name != NULL) { + char const * default_name = NULL; + if ((defaults != NULL) && (i < defaults->count)) + default_name = defaults->entries[i].building_name; + if (list->entries[i].building_name != default_name) + free ((void *)list->entries[i].building_name); + list->entries[i].building_name = NULL; + } + } + list->count = (defaults != NULL) ? defaults->count : 0; +} + +void +move_bonus_entry_list (struct district_bonus_list * dest, + struct district_bonus_list * src) +{ + if ((dest == NULL) || (src == NULL)) + return; + + dest->count = src->count; + for (int i = 0; i < src->count; i++) { + dest->entries[i] = src->entries[i]; + src->entries[i].building_name = NULL; + } + src->count = 0; +} + +void +free_dynamic_district_config (struct district_config * cfg) +{ + if (cfg == NULL) + return; + + if (! cfg->is_dynamic) + return; + + char const * name_ptr = cfg->name; + if (cfg->name != NULL) { + free ((void *)cfg->name); + cfg->name = NULL; + } + if ((cfg->display_name != NULL) && + (cfg->display_name != name_ptr)) { + free ((void *)cfg->display_name); + cfg->display_name = NULL; + } + if (cfg->tooltip != NULL) { + free ((void *)cfg->tooltip); + cfg->tooltip = NULL; + } + for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { + if (cfg->advance_prereqs[i] != NULL) { + free ((void *)cfg->advance_prereqs[i]); + cfg->advance_prereqs[i] = NULL; + } + } + cfg->advance_prereq_count = 0; + if (cfg->obsoleted_by != NULL) { + free ((void *)cfg->obsoleted_by); + cfg->obsoleted_by = NULL; + } + + for (int i = 0; i < 5; i++) { + if (cfg->resource_prereqs[i] != NULL) { + free ((void *)cfg->resource_prereqs[i]); + cfg->resource_prereqs[i] = NULL; + } + } + + if (cfg->resource_prereq_on_tile != NULL) { + free ((void *)cfg->resource_prereq_on_tile); + cfg->resource_prereq_on_tile = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { + if (cfg->wonder_prereqs[i] != NULL) { + free ((void *)cfg->wonder_prereqs[i]); + cfg->wonder_prereqs[i] = NULL; + } + } + cfg->wonder_prereq_count = 0; + + for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { + if (cfg->natural_wonder_prereqs[i] != NULL) { + free ((void *)cfg->natural_wonder_prereqs[i]); + cfg->natural_wonder_prereqs[i] = NULL; + } + } + cfg->natural_wonder_prereq_count = 0; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { + if (cfg->buildable_on_districts[i] != NULL) { + free ((void *)cfg->buildable_on_districts[i]); + cfg->buildable_on_districts[i] = NULL; + } + } + cfg->buildable_on_district_count = 0; + cfg->buildable_on_district_id_count = 0; + cfg->has_buildable_on_districts = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { + if (cfg->buildable_adjacent_to_districts[i] != NULL) { + free ((void *)cfg->buildable_adjacent_to_districts[i]); + cfg->buildable_adjacent_to_districts[i] = NULL; + } + } + cfg->buildable_adjacent_to_district_count = 0; + cfg->buildable_adjacent_to_district_id_count = 0; + cfg->has_buildable_adjacent_to = false; + cfg->has_buildable_adjacent_to_districts = false; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + if (cfg->buildable_by_civs[i] != NULL) { + free ((void *)cfg->buildable_by_civs[i]); + cfg->buildable_by_civs[i] = NULL; + } + } + cfg->buildable_by_civ_count = 0; + cfg->has_buildable_by_civs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) + cfg->buildable_by_civ_traits_ids[i] = -1; + cfg->buildable_by_civ_traits_id_count = 0; + cfg->has_buildable_by_civ_traits = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) + cfg->buildable_by_civ_govs_ids[i] = -1; + cfg->buildable_by_civ_govs_id_count = 0; + cfg->has_buildable_by_civ_govs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) + cfg->buildable_by_civ_cultures_ids[i] = -1; + cfg->buildable_by_civ_cultures_id_count = 0; + cfg->has_buildable_by_civ_cultures = false; + + for (int i = 0; i < 5; i++) { + if (cfg->dependent_improvements[i] != NULL) { + free ((void *)cfg->dependent_improvements[i]); + cfg->dependent_improvements[i] = NULL; + } + } + + for (int i = 0; i < 10; i++) { + if (cfg->img_paths[i] != NULL) { + free ((void *)cfg->img_paths[i]); + cfg->img_paths[i] = NULL; + } + } + + free_bonus_entry_list (&cfg->culture_bonus_extras); + free_bonus_entry_list (&cfg->science_bonus_extras); + free_bonus_entry_list (&cfg->food_bonus_extras); + free_bonus_entry_list (&cfg->gold_bonus_extras); + free_bonus_entry_list (&cfg->shield_bonus_extras); + free_bonus_entry_list (&cfg->happiness_bonus_extras); + free_bonus_entry_list (&cfg->defense_bonus_extras); + + memset (cfg, 0, sizeof *cfg); +} + +void +free_dynamic_wonder_config (struct wonder_district_config * cfg) +{ + if (cfg == NULL) + return; + + if (! cfg->is_dynamic) + return; + + if (cfg->wonder_name != NULL) { + free ((void *)cfg->wonder_name); + cfg->wonder_name = NULL; + } + + if (cfg->img_path != NULL) { + free ((void *)cfg->img_path); + cfg->img_path = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + if (cfg->buildable_by_civs[i] != NULL) { + free ((void *)cfg->buildable_by_civs[i]); + cfg->buildable_by_civs[i] = NULL; + } + } + cfg->buildable_by_civ_count = 0; + cfg->has_buildable_by_civs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) + cfg->buildable_by_civ_traits_ids[i] = -1; + cfg->buildable_by_civ_traits_id_count = 0; + cfg->has_buildable_by_civ_traits = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) + cfg->buildable_by_civ_govs_ids[i] = -1; + cfg->buildable_by_civ_govs_id_count = 0; + cfg->has_buildable_by_civ_govs = false; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) + cfg->buildable_by_civ_cultures_ids[i] = -1; + cfg->buildable_by_civ_cultures_id_count = 0; + cfg->has_buildable_by_civ_cultures = false; + + memset (cfg, 0, sizeof *cfg); +} + +void +free_dynamic_natural_wonder_config (struct natural_wonder_district_config * cfg) +{ + if (cfg == NULL) + return; + + if (! cfg->is_dynamic) + return; + + if (cfg->name != NULL) { + free ((void *)cfg->name); + cfg->name = NULL; + } + + if (cfg->img_path != NULL) { + free ((void *)cfg->img_path); + cfg->img_path = NULL; + } + + memset (cfg, 0, sizeof *cfg); + cfg->adjacent_to = (enum SquareTypes)SQ_INVALID; + cfg->adjacency_dir = DIR_ZERO; +} + +enum Unit_Command_Values +allocate_dynamic_district_command (char const * name) +{ + int offset = is->next_custom_dynamic_command_index; + is->next_custom_dynamic_command_index += 1; + int value = C3X_DISTRICT_COMMAND_BASE - (offset + 1); + return (enum Unit_Command_Values)value; +} + +void +free_special_district_override_strings (struct district_config * cfg, struct district_config const * defaults) +{ + if (cfg == NULL || defaults == NULL) + return; + + if ((cfg->display_name != NULL) && + (cfg->display_name != cfg->name) && + (cfg->display_name != defaults->display_name)) { + free ((void *)cfg->display_name); + cfg->display_name = NULL; + } + if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) { + free ((void *)cfg->tooltip); + cfg->tooltip = NULL; + } + for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { + char const * default_value = (defaults != NULL && i < defaults->advance_prereq_count) + ? defaults->advance_prereqs[i] + : NULL; + if ((cfg->advance_prereqs[i] != NULL) && + (cfg->advance_prereqs[i] != default_value)) { + free ((void *)cfg->advance_prereqs[i]); + } + cfg->advance_prereqs[i] = NULL; + } + cfg->advance_prereq_count = 0; + if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) { + free ((void *)cfg->obsoleted_by); + cfg->obsoleted_by = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { + char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; + if ((cfg->resource_prereqs[i] != NULL) && + (cfg->resource_prereqs[i] != default_value)) + free ((void *)cfg->resource_prereqs[i]); + cfg->resource_prereqs[i] = NULL; + } + cfg->resource_prereq_count = defaults->resource_prereq_count; + + if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) { + free ((void *)cfg->resource_prereq_on_tile); + cfg->resource_prereq_on_tile = NULL; + } + + for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { + char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; + if ((cfg->wonder_prereqs[i] != NULL) && + (cfg->wonder_prereqs[i] != default_value)) + free ((void *)cfg->wonder_prereqs[i]); + cfg->wonder_prereqs[i] = NULL; + } + cfg->wonder_prereq_count = defaults->wonder_prereq_count; + + for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { + char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; + if ((cfg->natural_wonder_prereqs[i] != NULL) && + (cfg->natural_wonder_prereqs[i] != default_value)) + free ((void *)cfg->natural_wonder_prereqs[i]); + cfg->natural_wonder_prereqs[i] = NULL; + } + cfg->natural_wonder_prereq_count = defaults->natural_wonder_prereq_count; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { + char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; + if ((cfg->buildable_on_districts[i] != NULL) && + (cfg->buildable_on_districts[i] != default_value)) { + free ((void *)cfg->buildable_on_districts[i]); + } + cfg->buildable_on_districts[i] = NULL; + } + cfg->buildable_on_district_count = defaults->buildable_on_district_count; + cfg->buildable_on_district_id_count = defaults->buildable_on_district_id_count; + cfg->has_buildable_on_districts = defaults->has_buildable_on_districts; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { + char const * default_value = (i < defaults->buildable_adjacent_to_district_count) + ? defaults->buildable_adjacent_to_districts[i] + : NULL; + if ((cfg->buildable_adjacent_to_districts[i] != NULL) && + (cfg->buildable_adjacent_to_districts[i] != default_value)) { + free ((void *)cfg->buildable_adjacent_to_districts[i]); + } + cfg->buildable_adjacent_to_districts[i] = NULL; + } + cfg->buildable_adjacent_to_district_count = defaults->buildable_adjacent_to_district_count; + cfg->buildable_adjacent_to_district_id_count = defaults->buildable_adjacent_to_district_id_count; + cfg->has_buildable_adjacent_to = defaults->has_buildable_adjacent_to; + cfg->has_buildable_adjacent_to_districts = defaults->has_buildable_adjacent_to_districts; + + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; + if ((cfg->buildable_by_civs[i] != NULL) && + (cfg->buildable_by_civs[i] != default_value)) { + free ((void *)cfg->buildable_by_civs[i]); + } + cfg->buildable_by_civs[i] = NULL; + } + cfg->buildable_by_civ_count = defaults->buildable_by_civ_count; + cfg->has_buildable_by_civs = defaults->has_buildable_by_civs; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_traits_ids); i++) + cfg->buildable_by_civ_traits_ids[i] = -1; + cfg->buildable_by_civ_traits_id_count = defaults->buildable_by_civ_traits_id_count; + cfg->has_buildable_by_civ_traits = defaults->has_buildable_by_civ_traits; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_govs_ids); i++) + cfg->buildable_by_civ_govs_ids[i] = -1; + cfg->buildable_by_civ_govs_id_count = defaults->buildable_by_civ_govs_id_count; + cfg->has_buildable_by_civ_govs = defaults->has_buildable_by_civ_govs; + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); i++) + cfg->buildable_by_civ_cultures_ids[i] = -1; + cfg->buildable_by_civ_cultures_id_count = defaults->buildable_by_civ_cultures_id_count; + cfg->has_buildable_by_civ_cultures = defaults->has_buildable_by_civ_cultures; + cfg->buildable_by_war_allies = defaults->buildable_by_war_allies; + cfg->buildable_by_pact_allies = defaults->buildable_by_pact_allies; + + for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { + char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; + if ((cfg->dependent_improvements[i] != NULL) && + (cfg->dependent_improvements[i] != default_value)) { + free ((void *)cfg->dependent_improvements[i]); + } + cfg->dependent_improvements[i] = NULL; + } + cfg->dependent_improvement_max_index = defaults->dependent_improvement_max_index; + + for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { + char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; + if ((cfg->img_paths[i] != NULL) && + (cfg->img_paths[i] != default_value)) { + free ((void *)cfg->img_paths[i]); + } + cfg->img_paths[i] = NULL; + } + cfg->img_path_count = defaults->img_path_count; + + free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); + free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); + free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); + free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); + free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); + free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); + free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); +} + +void +reset_regular_district_configs (void) +{ + for (int i = USED_SPECIAL_DISTRICT_TYPES; i < COUNT_DISTRICT_TYPES; i++) { + if (is->district_configs[i].is_dynamic) + free_dynamic_district_config (&is->district_configs[i]); + } + + for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) + free_special_district_override_strings (&is->district_configs[i], &special_district_defaults[i]); + + memset (is->district_configs, 0, sizeof is->district_configs); + for (int i = 0; i < USED_SPECIAL_DISTRICT_TYPES; i++) + is->district_configs[i] = special_district_defaults[i]; + + is->special_district_count = USED_SPECIAL_DISTRICT_TYPES; + is->dynamic_district_count = 0; + is->district_count = is->special_district_count; + is->next_custom_dynamic_command_index = 0; +} + +void +reset_wonder_district_configs (void) +{ + for (int i = 0; i < MAX_WONDER_DISTRICT_TYPES; i++) { + if (is->wonder_district_configs[i].is_dynamic) + free_dynamic_wonder_config (&is->wonder_district_configs[i]); + } + + memset (is->wonder_district_configs, 0, sizeof is->wonder_district_configs); + is->wonder_district_count = 0; +} + +void +reset_natural_wonder_configs (void) +{ + for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { + if (is->natural_wonder_configs[i].is_dynamic) + free_dynamic_natural_wonder_config (&is->natural_wonder_configs[i]); + } + + memset (is->natural_wonder_configs, 0, sizeof is->natural_wonder_configs); + for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) { + is->natural_wonder_configs[i].adjacent_to = (enum SquareTypes)SQ_INVALID; + is->natural_wonder_configs[i].adjacency_dir = DIR_ZERO; + } + for (int i = 0; i < MAX_NATURAL_WONDER_DISTRICT_TYPES; i++) + is->natural_wonder_img_sets[i].img.vtable = NULL; + stable_deinit (&is->natural_wonder_name_to_id); + is->natural_wonder_count = 0; +} + +void +clear_dynamic_district_definitions (void) +{ + reset_regular_district_configs (); + reset_wonder_district_configs (); + reset_natural_wonder_configs (); + reset_ai_candidate_bridge_or_canals (); +} + +void +init_parsed_district_definition (struct parsed_district_definition * def) +{ + memset (def, 0, sizeof *def); + def->img_path_count = -1; + def->defense_bonus_percent = 0; + def->render_strategy = DRS_BY_COUNT; + def->ai_build_strategy = DABS_DISTRICT; + def->buildable_square_types_mask = district_default_buildable_mask (); + def->buildable_adjacent_to_square_types_mask = 0; + def->buildable_without_removal_mask = 0; + def->buildable_on_overlays_mask = 0; + def->buildable_adjacent_to_overlays_mask = 0; + def->buildable_on_rivers = false; + def->buildable_adjacent_to_allows_city = false; +} + +void +free_parsed_district_definition (struct parsed_district_definition * def) +{ + if (def == NULL) + return; + + if (def->display_name != NULL) { + free (def->display_name); + def->display_name = NULL; + } + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + if (def->tooltip != NULL) { + free (def->tooltip); + def->tooltip = NULL; + } + for (int i = 0; i < def->advance_prereq_count; i++) { + if (def->advance_prereqs[i] != NULL) { + free (def->advance_prereqs[i]); + def->advance_prereqs[i] = NULL; + } + } + def->advance_prereq_count = 0; + for (int i = 0; i < ARRAY_LEN (def->buildable_on_districts); i++) { + if (def->buildable_on_districts[i] != NULL) { + free (def->buildable_on_districts[i]); + def->buildable_on_districts[i] = NULL; + } + } + for (int i = 0; i < ARRAY_LEN (def->buildable_adjacent_to_districts); i++) { + if (def->buildable_adjacent_to_districts[i] != NULL) { + free (def->buildable_adjacent_to_districts[i]); + def->buildable_adjacent_to_districts[i] = NULL; + } + } + if (def->obsoleted_by != NULL) { + free (def->obsoleted_by); + def->obsoleted_by = NULL; + } + + for (int i = 0; i < def->resource_prereq_count; i++) { + if (def->resource_prereqs[i] != NULL) { + free (def->resource_prereqs[i]); + def->resource_prereqs[i] = NULL; + } + } + def->resource_prereq_count = 0; + + if (def->resource_prereq_on_tile != NULL) { + free (def->resource_prereq_on_tile); + def->resource_prereq_on_tile = NULL; + } + + for (int i = 0; i < def->wonder_prereq_count; i++) { + if (def->wonder_prereqs[i] != NULL) { + free (def->wonder_prereqs[i]); + def->wonder_prereqs[i] = NULL; + } + } + def->wonder_prereq_count = 0; + + for (int i = 0; i < def->natural_wonder_prereq_count; i++) { + if (def->natural_wonder_prereqs[i] != NULL) { + free (def->natural_wonder_prereqs[i]); + def->natural_wonder_prereqs[i] = NULL; + } + } + def->natural_wonder_prereq_count = 0; + def->buildable_adjacent_to_district_count = 0; + + for (int i = 0; i < def->buildable_by_civ_count; i++) { + if (def->buildable_by_civs[i] != NULL) { + free (def->buildable_by_civs[i]); + def->buildable_by_civs[i] = NULL; + } + } + def->buildable_by_civ_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + + for (int i = 0; i < def->dependent_improvement_max_index; i++) { + if (def->dependent_improvements[i] != NULL) { + free (def->dependent_improvements[i]); + def->dependent_improvements[i] = NULL; + } + } + def->dependent_improvement_max_index = 0; + + for (int i = 0; i < def->img_path_count; i++) { + if (def->img_paths[i] != NULL) { + free (def->img_paths[i]); + def->img_paths[i] = NULL; + } + } + def->img_path_count = 0; + + if (def->generated_resource != NULL) { + free (def->generated_resource); + def->generated_resource = NULL; + } + + free_bonus_entry_list (&def->culture_bonus_extras); + free_bonus_entry_list (&def->science_bonus_extras); + free_bonus_entry_list (&def->food_bonus_extras); + free_bonus_entry_list (&def->gold_bonus_extras); + free_bonus_entry_list (&def->shield_bonus_extras); + free_bonus_entry_list (&def->happiness_bonus_extras); + free_bonus_entry_list (&def->defense_bonus_extras); + + init_parsed_district_definition (def); +} + +int +find_special_district_index_by_name (char const * name) +{ + if (name == NULL) + return -1; + + for (int i = 0; i < is->special_district_count; i++) { + if ((is->district_configs[i].name != NULL) && + (strcmp (is->district_configs[i].name, name) == 0)) + return i; + } + return -1; +} + + +// --------------------------------------------------------------- +// Unit counter system +// --------------------------------------------------------------- + +bool +read_counter_rule_terrain_mask (struct string_slice const * terrain_name, unsigned int * out_mask) +{ + if ((terrain_name == NULL) || (out_mask == NULL)) + return false; + + struct string_slice trimmed = trim_string_slice (terrain_name, 1); + if (trimmed.len <= 0) + return false; + + if (slice_matches_str (&trimmed, "lake") || slice_matches_str (&trimmed, "lakes")) { + *out_mask = district_buildable_lake_mask_bit (); + return true; + } + + enum SquareTypes parsed; + if (! read_tile_terrain_type_value (&trimmed, &parsed)) + return false; + + if (parsed == (enum SquareTypes)SQ_INVALID) + *out_mask = all_square_types_mask () | district_buildable_lake_mask_bit (); + else + *out_mask = square_type_mask_bit (parsed); + + return *out_mask != 0; +} + +struct unit_counter_group * +find_unit_counter_group_by_name (struct c3x_config * cfg, char const * name) +{ + for (int i = 0; i < cfg->count_unit_counter_groups; i++) { + struct unit_counter_group * g = &cfg->unit_counter_groups[i]; + if (g->name && strcmp (g->name, name) == 0) + return g; + } + return NULL; +} + +bool +unit_type_in_group (struct unit_counter_group * g, int type_id) +{ + char const * name = p_bic_data->UnitTypes[type_id].Name; + for (int i = 0; i < g->count_type_ids; i++) + if (strcmp (p_bic_data->UnitTypes[g->type_ids[i]].Name, name) == 0) + return true; + return false; +} + +bool +unit_matches_counter_side (struct c3x_config * cfg, int type_id, + int match, char * group_name) +{ + if (match == UCM_ANY) + return true; + if (match == UCM_GROUP) { + struct unit_counter_group * g = + find_unit_counter_group_by_name (cfg, group_name); + return g && unit_type_in_group (g, type_id); + } + // Direct unit type match: compare by name rather than exact ID so that + // AI strategy duplicates (same name, different ID) are also matched. + return strcmp (p_bic_data->UnitTypes[match].Name, + p_bic_data->UnitTypes[type_id].Name) == 0; +} + +enum recognizable_parse_result +parse_unit_counter_group (char ** p_cursor, + struct error_line ** p_unrecognized_lines, + void * out_group) +{ + char * cur = *p_cursor; + struct string_slice group_name; + if (! (parse_string (&cur, &group_name) && skip_punctuation (&cur, ':'))) + return RPR_PARSE_ERROR; + + struct unit_counter_group * g = out_group; + g->name = extract_slice (&group_name); + g->type_ids = NULL; + g->count_type_ids = 0; + + int any_unrecognized = 0; + struct string_slice type_name; + while (parse_string (&cur, &type_name)) { + // Loop through all unit types with this name, including AI strategy + // duplicates (same name, different ID), which the game creates internally. + int type_id = 0; + bool found_any = false; + while (find_unit_type_id_by_name (&type_name, type_id, &type_id)) { + g->type_ids = realloc (g->type_ids, + (g->count_type_ids + 1) * sizeof (int)); + g->type_ids[g->count_type_ids++] = type_id; + found_any = true; + type_id++; // continue search from next index + } + if (! found_any) { + add_unrecognized_line (p_unrecognized_lines, &type_name); + any_unrecognized = 1; + } + if (! skip_punctuation (&cur, ',')) + break; + } + *p_cursor = cur; + return any_unrecognized ? RPR_UNRECOGNIZED : RPR_OK; +} + +enum recognizable_parse_result +parse_counter_rule (char ** p_cursor, + struct error_line ** p_unrecognized_lines, + void * out_rule) +{ + char * cur = *p_cursor; + struct string_slice attacker_name, vs_token, defender_name; + + if (! parse_string (&cur, &attacker_name)) + return RPR_PARSE_ERROR; + if (! (parse_string (&cur, &vs_token) && + slice_matches_str (&vs_token, "vs"))) + return RPR_PARSE_ERROR; + if (! parse_string (&cur, &defender_name)) + return RPR_PARSE_ERROR; + + struct counter_rule * r = out_rule; + *r = (struct counter_rule) { + .attacker_match = UCM_ANY, + .defender_match = UCM_ANY, + .terrain_mask = 0, + .district_id = -1, + .district_name = NULL, + .self_atk_pct = 100, + .self_def_pct = 100, + .enemy_atk_pct = 100, + .enemy_def_pct = 100, + }; + + if (! slice_matches_str (&attacker_name, "*")) { + int type_id; + if (find_unit_type_id_by_name (&attacker_name, 0, &type_id)) + r->attacker_match = type_id; + else { + r->attacker_match = UCM_GROUP; + r->attacker_group = extract_slice (&attacker_name); + } + } + + if (! slice_matches_str (&defender_name, "*")) { + int type_id; + if (find_unit_type_id_by_name (&defender_name, 0, &type_id)) + r->defender_match = type_id; + else { + r->defender_match = UCM_GROUP; + r->defender_group = extract_slice (&defender_name); + } + } + + struct string_slice token; + while (parse_string (&cur, &token)) { + if (slice_matches_str (&token, "in-city")) { + r->only_in_city = true; + } else if (slice_matches_str (&token, "ignore-terrain")) { + r->ignore_terrain = true; + } else if (slice_matches_str (&token, "self-atk")) { + if (! parse_int (&cur, &r->self_atk_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "self-def")) { + if (! parse_int (&cur, &r->self_def_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "enemy-atk")) { + if (! parse_int (&cur, &r->enemy_atk_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "enemy-def")) { + if (! parse_int (&cur, &r->enemy_def_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "terrain")) { + struct string_slice terrain_name; + if (! parse_string (&cur, &terrain_name)) + return RPR_PARSE_ERROR; + if (! read_counter_rule_terrain_mask (&terrain_name, &r->terrain_mask)) { + add_unrecognized_line (p_unrecognized_lines, &terrain_name); + return RPR_UNRECOGNIZED; + } + } else if (slice_matches_str (&token, "district")) { + struct string_slice district_name; + if (! parse_string (&cur, &district_name)) + return RPR_PARSE_ERROR; + free (r->district_name); + r->district_name = extract_slice (&district_name); + r->district_id = -1; + } else { + break; + } + } + + *p_cursor = cur; + return RPR_OK; +} + +void +apply_counter_rules (struct c3x_config * cfg, + Unit * attacker, Unit * defender, Tile * def_tile, + int * out_attacker_atk, int * out_defender_def, + bool * out_ignore_terrain) +{ + int a_type = attacker->Body.UnitTypeID; + int d_type = defender->Body.UnitTypeID; + bool in_city = Tile_has_city (def_tile); + + int aa = 100, dd = 100; + bool ignore = false; + + for (int i = 0; i < cfg->count_counter_rules; i++) { + struct counter_rule * r = &cfg->counter_rules[i]; + + // Check forward match (attacker=rule attacker side, defender=rule defender side) + // Applied fields: self-atk (attacker attack), enemy-def (defender defense) + bool forward = unit_matches_counter_side (cfg, a_type, + r->attacker_match, r->attacker_group) && + unit_matches_counter_side (cfg, d_type, + r->defender_match, r->defender_group); + + // Check reverse match (attacker=rule defender side, defender=rule attacker side) + // Applied fields: self-def (rule attacker side is now defending), enemy-atk (rule defender side is now attacking) + bool reverse = unit_matches_counter_side (cfg, a_type, + r->defender_match, r->defender_group) && + unit_matches_counter_side (cfg, d_type, + r->attacker_match, r->attacker_group); + + if (! forward && ! reverse) + continue; + + // Environment checks are based on the defender's tile + if (r->only_in_city && ! in_city) + continue; + if (r->terrain_mask != 0 && + ! tile_matches_square_type_mask (def_tile, r->terrain_mask)) + continue; + if (r->district_name != NULL && + ! ((r->district_id != -1) && + cfg->enable_districts && + district_is_complete (def_tile, r->district_id))) + continue; + + if (forward) { + aa = aa * r->self_atk_pct / 100; // self-atk: attacker attack + dd = dd * r->enemy_def_pct / 100; // enemy-def: defender defense + } + if (reverse) { + aa = aa * r->enemy_atk_pct / 100; // enemy-atk: rule defender side now acts as attacker + dd = dd * r->self_def_pct / 100; // self-def: rule attacker side now acts as defender + } + if (forward || reverse) + ignore = ignore || r->ignore_terrain; + } + + *out_attacker_atk = aa; + *out_defender_def = dd; + *out_ignore_terrain = ignore; +} + +bool +district_is_included_by_final_config (int district_id) +{ + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + if (! is->current_config.enable_districts) + return false; + + switch (district_id) { + case NEIGHBORHOOD_DISTRICT_ID: return is->current_config.enable_neighborhood_districts; + case WONDER_DISTRICT_ID: return is->current_config.enable_wonder_districts; + case DISTRIBUTION_HUB_DISTRICT_ID: return is->current_config.enable_distribution_hub_districts; + case AERODROME_DISTRICT_ID: return is->current_config.enable_aerodrome_districts; + case PORT_DISTRICT_ID: return is->current_config.enable_port_districts; + case CENTRAL_RAIL_HUB_DISTRICT_ID: return is->current_config.enable_central_rail_hub_districts; + case ENERGY_GRID_DISTRICT_ID: return is->current_config.enable_energy_grid_districts; + case BRIDGE_DISTRICT_ID: return is->current_config.enable_bridge_districts; + case CANAL_DISTRICT_ID: return is->current_config.enable_canal_districts; + case GREAT_WALL_DISTRICT_ID: return is->current_config.enable_great_wall_districts; + default: return true; + } +} + +bool +ensure_culture_variant_art (struct district_config * cfg, int section_start_line) +{ + if ((cfg == NULL) || (! cfg->vary_img_by_culture)) + return true; + + const int required_variants = 5; + const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); + if (cfg->img_path_count <= 0) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] load_dynamic_district_configs: district \"%s\" requires culture-specific art but none provided (line %d)\n", cfg->name, section_start_line); + (*p_OutputDebugStringA) (ss); + return false; + } + + while ((cfg->img_path_count < required_variants) && + (cfg->img_path_count < max_img_paths)) { + cfg->img_paths[cfg->img_path_count] = strdup (cfg->img_paths[0]); + cfg->img_path_count += 1; + } + + return true; +} + +bool +parse_config_string_list (char * value_text, + char ** dest, + int capacity, + int * out_count, + struct error_line ** parse_errors, + int line_number, + char const * key) +{ + for (int i = 0; i < capacity; i++) { + if (dest[i] != NULL) { + free (dest[i]); + dest[i] = NULL; + } + } + *out_count = 0; + + if (value_text == NULL || *value_text == '\0') + return true; + + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + if (*cursor == '\0') + break; + + char * item_start; + char * item_end; + if (*cursor == '"') { + cursor++; + item_start = cursor; + while ((*cursor != '\0') && (*cursor != '"')) + cursor++; + if (*cursor != '"') { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (missing closing quote)", line_number, key); + err->text[(sizeof err->text) - 1] = '\0'; + for (int j = 0; j < capacity; j++) { + if (dest[j] != NULL) { + free (dest[j]); + dest[j] = NULL; + } + } + *out_count = 0; + return false; + } + item_end = cursor; + cursor++; + } else { + item_start = cursor; + while ((*cursor != '\0') && (*cursor != ',')) + cursor++; + item_end = cursor; + } + + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + + int item_len = item_end - item_start; + if (item_len > 0) { + if (*out_count < capacity) { + char * copy = malloc (item_len + 1); + if (copy == NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (out of memory)", line_number, key); + err->text[(sizeof err->text) - 1] = '\0'; + for (int j = 0; j < capacity; j++) { + if (dest[j] != NULL) { + free (dest[j]); + dest[j] = NULL; + } + } + *out_count = 0; + return false; + } + memcpy (copy, item_start, item_len); + copy[item_len] = '\0'; + dest[*out_count] = copy; + *out_count += 1; + } + } + + while (is_space_char (*cursor)) + cursor++; + + if (*cursor == ',') { + cursor++; + continue; + } + if (*cursor == '\0') + break; + } + + return true; +} + +bool +parse_buildable_square_type_mask (struct string_slice const * value, + unsigned int * out_mask, + struct error_line ** parse_errors, + int line_number, + char const * key_name, + bool * out_allow_city) +{ + char * value_text = trim_and_extract_slice (value, 0); + unsigned int mask = 0; + int entry_count = 0; + bool allow_city = false; + bool allow_city_token = (key_name != NULL) && (strcmp (key_name, "buildable_adjacent_to") == 0); + if (key_name == NULL) + key_name = "buildable_on"; + + if (value_text != NULL) { + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + char * item_start = cursor; + while ((*cursor != '\0') && (*cursor != ',')) + cursor++; + + char * item_end = cursor; + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + + struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; + if (item_slice.len > 0) { + if (slice_matches_str (&item_slice, "city")) { + if (! allow_city_token) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + allow_city = true; + entry_count += 1; + } else if (slice_matches_str (&item_slice, "lake")) { + mask |= district_buildable_lake_mask_bit (); + entry_count += 1; + } else { + enum SquareTypes parsed; + if (read_tile_terrain_type_value (&item_slice, &parsed)) { + if ((parsed == SQ_RIVER) || + (parsed == SQ_Forest) || + (parsed == SQ_Jungle) || + (parsed == SQ_Swamp)) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + if (parsed == (enum SquareTypes)SQ_INVALID) { + mask = all_square_types_mask (); + mask &= ~(square_type_mask_bit (SQ_Forest) | + square_type_mask_bit (SQ_Jungle) | + square_type_mask_bit (SQ_Swamp)); + } else + mask |= square_type_mask_bit (parsed); + entry_count += 1; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + } + } + + if (*cursor == ',') { + cursor++; + continue; + } + break; + } + } + + if (value_text != NULL) + free (value_text); + + if ((entry_count == 0) || ((mask == 0) && ! allow_city)) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one tile terrain type)", line_number, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + return false; + } + + *out_mask = mask; + if (out_allow_city != NULL) + *out_allow_city = allow_city; + return true; +} + +bool +parse_buildable_overlay_mask (struct string_slice const * value, + unsigned int * out_mask, + struct error_line ** parse_errors, + int line_number, + char const * key_name) +{ + char * value_text = trim_and_extract_slice (value, 0); + unsigned int mask = 0; + unsigned int allowed_mask = (DOM_MINE | DOM_IRRIGATION | DOM_FORTRESS | DOM_BARRICADE | + DOM_OUTPOST | DOM_RADAR_TOWER | DOM_JUNGLE | DOM_FOREST | + DOM_SWAMP | DOM_RIVER | DOM_AIRFIELD); + int entry_count = 0; + + if (key_name == NULL) + key_name = "buildable_without_removal"; + if (strcmp (key_name, "buildable_without_removal") == 0) + allowed_mask = (DOM_JUNGLE | DOM_FOREST | DOM_SWAMP); + else if (strcmp (key_name, "buildable_on_overlays") == 0) + allowed_mask &= ~DOM_RIVER; + + if (value_text != NULL) { + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + char * item_start = cursor; + while ((*cursor != '\0') && (*cursor != ',')) + cursor++; + + char * item_end = cursor; + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + + struct string_slice item_slice = { .str = item_start, .len = (int)(item_end - item_start) }; + if (item_slice.len > 0) { + unsigned int bit = 0; + if (slice_matches_str (&item_slice, "mine")) { + bit = DOM_MINE; + } else if (slice_matches_str (&item_slice, "irrigation")) { + bit = DOM_IRRIGATION; + } else if (slice_matches_str (&item_slice, "fortress")) { + bit = DOM_FORTRESS; + } else if (slice_matches_str (&item_slice, "barricade")) { + bit = DOM_BARRICADE; + } else if (slice_matches_str (&item_slice, "outpost")) { + bit = DOM_OUTPOST; + } else if (slice_matches_str (&item_slice, "radar-tower")) { + bit = DOM_RADAR_TOWER; + } else if (slice_matches_str (&item_slice, "airfield")) { + bit = DOM_AIRFIELD; + } else if (slice_matches_str (&item_slice, "jungle")) { + bit = DOM_JUNGLE; + } else if (slice_matches_str (&item_slice, "jungles")) { + bit = DOM_JUNGLE; + } else if (slice_matches_str (&item_slice, "forest")) { + bit = DOM_FOREST; + } else if (slice_matches_str (&item_slice, "forests")) { + bit = DOM_FOREST; + } else if (slice_matches_str (&item_slice, "marsh")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "marshes")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "swamp")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "swamps")) { + bit = DOM_SWAMP; + } else if (slice_matches_str (&item_slice, "river")) { + bit = DOM_RIVER; + } else if (slice_matches_str (&item_slice, "rivers")) { + bit = DOM_RIVER; + } + + if (bit != 0) { + if ((allowed_mask & bit) == 0) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + mask |= bit; + entry_count += 1; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %.*s (invalid %s entry)", line_number, item_slice.len, item_slice.str, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + free (value_text); + return false; + } + } + + if (*cursor == ',') { + cursor++; + continue; + } + break; + } + } + + if (value_text != NULL) + free (value_text); + + if ((entry_count == 0) || (mask == 0)) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected at least one overlay)", line_number, key_name); + err->text[(sizeof err->text) - 1] = '\0'; + return false; + } + + *out_mask = mask; + return true; +} + +bool +parse_district_bonus_entries (struct string_slice const * value, + int * out_base_bonus, + struct district_bonus_list * out_extras, + struct error_line ** parse_errors, + int line_number, + struct string_slice const * key) +{ + if ((out_base_bonus == NULL) || (out_extras == NULL)) { + add_key_parse_error (parse_errors, line_number, key, value, "(invalid bonus target)"); + return false; + } + + char * value_text = trim_and_extract_slice (value, 0); + free_bonus_entry_list (out_extras); + *out_base_bonus = 0; + + if ((value_text == NULL) || (*value_text == '\0')) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); + free (value_text); + return false; + } + + bool got_base = false; + int base_bonus = 0; + + char * cursor = value_text; + while (1) { + while (is_space_char (*cursor)) + cursor++; + + if (*cursor == '\0') + break; + + char * item_start = cursor; + bool in_quotes = false; + while (*cursor != '\0') { + if (*cursor == '"') + in_quotes = ! in_quotes; + if ((! in_quotes) && (*cursor == ',')) + break; + cursor++; + } + + char * item_end = cursor; + while ((item_end > item_start) && is_space_char (item_end[-1])) + item_end--; + while ((item_start < item_end) && is_space_char (*item_start)) + item_start++; + + if (item_end > item_start) { + struct string_slice item = { .str = item_start, .len = (int)(item_end - item_start) }; + + if (! got_base) { + struct string_slice base_slice = trim_string_slice (&item, 0); + if (! read_int (&base_slice, &base_bonus)) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + got_base = true; + } else { + char * colon = NULL; + in_quotes = false; + for (char * p = item_start; p < item_end; p++) { + if (*p == '"') + in_quotes = ! in_quotes; + if ((! in_quotes) && (*p == ':')) { + colon = p; + break; + } + } + + if (colon == NULL) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected \"name: bonus\" entry)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + struct string_slice name_slice = { .str = item_start, .len = (int)(colon - item_start) }; + struct string_slice bonus_slice = { .str = colon + 1, .len = (int)(item_end - (colon + 1)) }; + struct string_slice trimmed_name = trim_string_slice (&name_slice, 1); + struct string_slice trimmed_bonus = trim_string_slice (&bonus_slice, 0); + + if (trimmed_name.len <= 0) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus name)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + int bonus_value = 0; + if (! read_int (&trimmed_bonus, &bonus_value)) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected bonus value)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + if (out_extras->count >= MAX_DISTRICT_BONUS_ENTRIES) { + add_key_parse_error (parse_errors, line_number, key, value, "(too many bonus entries)"); + free_bonus_entry_list (out_extras); + free (value_text); + return false; + } + + struct district_bonus_entry * entry = &out_extras->entries[out_extras->count++]; + entry->bonus = bonus_value; + entry->building_id = -1; + entry->building_name = NULL; + + enum SquareTypes parsed_type; + if (read_tile_terrain_type_value (&trimmed_name, &parsed_type)) { + entry->type = DBET_TILE; + entry->tile_type = parsed_type; + } else { + entry->type = DBET_BUILDING; + entry->tile_type = (enum SquareTypes)SQ_INVALID; + entry->building_name = extract_slice (&trimmed_name); + } + } + } + + if (*cursor == ',') { + cursor++; + continue; + } + if (*cursor == '\0') + break; + } + + free (value_text); + + if (! got_base) { + add_key_parse_error (parse_errors, line_number, key, value, "(expected base bonus)"); + free_bonus_entry_list (out_extras); + return false; + } + + *out_base_bonus = base_bonus; + return true; +} + +bool +override_special_district_from_definition (struct parsed_district_definition * def, int section_start_line) +{ + if ((! def->has_name) || (def->name == NULL)) + return false; + + int index = find_special_district_index_by_name (def->name); + if (index < 0) + return false; + + struct district_config * cfg = &is->district_configs[index]; + struct district_config const * defaults = &special_district_defaults[index]; + + free (def->name); + def->name = NULL; + def->has_name = false; + + if (def->has_display_name) { + if ((cfg->display_name != NULL) && + (cfg->display_name != cfg->name) && + (cfg->display_name != defaults->display_name)) + free ((void *)cfg->display_name); + cfg->display_name = def->display_name; + def->display_name = NULL; + } + + if (def->has_tooltip) { + if ((cfg->tooltip != NULL) && (cfg->tooltip != defaults->tooltip)) + free ((void *)cfg->tooltip); + cfg->tooltip = def->tooltip; + def->tooltip = NULL; + } + + if (def->has_advance_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->advance_prereqs); i++) { + char const * default_value = (i < defaults->advance_prereq_count) ? defaults->advance_prereqs[i] : NULL; + if ((cfg->advance_prereqs[i] != NULL) && + (cfg->advance_prereqs[i] != default_value)) + free ((void *)cfg->advance_prereqs[i]); + cfg->advance_prereqs[i] = NULL; + } + + cfg->advance_prereq_count = def->advance_prereq_count; + const int max_entries = ARRAY_LEN (cfg->advance_prereqs); + if (cfg->advance_prereq_count > max_entries) + cfg->advance_prereq_count = max_entries; + for (int i = 0; i < cfg->advance_prereq_count; i++) { + cfg->advance_prereqs[i] = def->advance_prereqs[i]; + def->advance_prereqs[i] = NULL; + } + def->advance_prereq_count = 0; + } + + if (def->has_obsoleted_by) { + if ((cfg->obsoleted_by != NULL) && (cfg->obsoleted_by != defaults->obsoleted_by)) + free ((void *)cfg->obsoleted_by); + cfg->obsoleted_by = def->obsoleted_by; + def->obsoleted_by = NULL; + } + + if (def->has_resource_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->resource_prereqs); i++) { + char const * default_value = (i < defaults->resource_prereq_count) ? defaults->resource_prereqs[i] : NULL; + if ((cfg->resource_prereqs[i] != NULL) && + (cfg->resource_prereqs[i] != default_value)) + free ((void *)cfg->resource_prereqs[i]); + cfg->resource_prereqs[i] = NULL; + } + + cfg->resource_prereq_count = def->resource_prereq_count; + const int max_entries = ARRAY_LEN (cfg->resource_prereqs); + if (cfg->resource_prereq_count > max_entries) + cfg->resource_prereq_count = max_entries; + for (int i = 0; i < cfg->resource_prereq_count; i++) { + cfg->resource_prereqs[i] = def->resource_prereqs[i]; + def->resource_prereqs[i] = NULL; + } + } + + if (def->has_resource_prereq_on_tile) { + if ((cfg->resource_prereq_on_tile != NULL) && (cfg->resource_prereq_on_tile != defaults->resource_prereq_on_tile)) + free ((void *)cfg->resource_prereq_on_tile); + cfg->resource_prereq_on_tile = def->resource_prereq_on_tile; + def->resource_prereq_on_tile = NULL; + } + + if (def->has_wonder_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->wonder_prereqs); i++) { + char const * default_value = (i < defaults->wonder_prereq_count) ? defaults->wonder_prereqs[i] : NULL; + if ((cfg->wonder_prereqs[i] != NULL) && + (cfg->wonder_prereqs[i] != default_value)) + free ((void *)cfg->wonder_prereqs[i]); + cfg->wonder_prereqs[i] = NULL; + } + + cfg->wonder_prereq_count = def->wonder_prereq_count; + const int max_entries = ARRAY_LEN (cfg->wonder_prereqs); + if (cfg->wonder_prereq_count > max_entries) + cfg->wonder_prereq_count = max_entries; + for (int i = 0; i < cfg->wonder_prereq_count; i++) { + cfg->wonder_prereqs[i] = def->wonder_prereqs[i]; + def->wonder_prereqs[i] = NULL; + } + } + + if (def->has_natural_wonder_prereqs) { + for (int i = 0; i < ARRAY_LEN (cfg->natural_wonder_prereqs); i++) { + char const * default_value = (i < defaults->natural_wonder_prereq_count) ? defaults->natural_wonder_prereqs[i] : NULL; + if ((cfg->natural_wonder_prereqs[i] != NULL) && + (cfg->natural_wonder_prereqs[i] != default_value)) + free ((void *)cfg->natural_wonder_prereqs[i]); + cfg->natural_wonder_prereqs[i] = NULL; + } + + cfg->natural_wonder_prereq_count = def->natural_wonder_prereq_count; + const int max_entries = ARRAY_LEN (cfg->natural_wonder_prereqs); + if (cfg->natural_wonder_prereq_count > max_entries) + cfg->natural_wonder_prereq_count = max_entries; + for (int i = 0; i < cfg->natural_wonder_prereq_count; i++) { + cfg->natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; + def->natural_wonder_prereqs[i] = NULL; + } + } + + if (def->has_buildable_on_districts) { + for (int i = 0; i < ARRAY_LEN (cfg->buildable_on_districts); i++) { + char const * default_value = (i < defaults->buildable_on_district_count) ? defaults->buildable_on_districts[i] : NULL; + if ((cfg->buildable_on_districts[i] != NULL) && + (cfg->buildable_on_districts[i] != default_value)) + free ((void *)cfg->buildable_on_districts[i]); + cfg->buildable_on_districts[i] = NULL; + } + + cfg->buildable_on_district_count = def->buildable_on_district_count; + const int max_entries = ARRAY_LEN (cfg->buildable_on_districts); + if (cfg->buildable_on_district_count > max_entries) + cfg->buildable_on_district_count = max_entries; + for (int i = 0; i < cfg->buildable_on_district_count; i++) { + cfg->buildable_on_districts[i] = def->buildable_on_districts[i]; + def->buildable_on_districts[i] = NULL; + } + cfg->buildable_on_district_id_count = 0; + cfg->has_buildable_on_districts = true; + } + + if (def->has_buildable_adjacent_to_districts) { + for (int i = 0; i < ARRAY_LEN (cfg->buildable_adjacent_to_districts); i++) { + char const * default_value = (i < defaults->buildable_adjacent_to_district_count) + ? defaults->buildable_adjacent_to_districts[i] + : NULL; + if ((cfg->buildable_adjacent_to_districts[i] != NULL) && + (cfg->buildable_adjacent_to_districts[i] != default_value)) + free ((void *)cfg->buildable_adjacent_to_districts[i]); + cfg->buildable_adjacent_to_districts[i] = NULL; + } + + cfg->buildable_adjacent_to_district_count = def->buildable_adjacent_to_district_count; + const int max_entries = ARRAY_LEN (cfg->buildable_adjacent_to_districts); + if (cfg->buildable_adjacent_to_district_count > max_entries) + cfg->buildable_adjacent_to_district_count = max_entries; + for (int i = 0; i < cfg->buildable_adjacent_to_district_count; i++) { + cfg->buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; + def->buildable_adjacent_to_districts[i] = NULL; + } + cfg->buildable_adjacent_to_district_id_count = 0; + cfg->has_buildable_adjacent_to_districts = true; + } + + if (def->has_buildable_by_civs) { + for (int i = 0; i < ARRAY_LEN (cfg->buildable_by_civs); i++) { + char const * default_value = (i < defaults->buildable_by_civ_count) ? defaults->buildable_by_civs[i] : NULL; + if ((cfg->buildable_by_civs[i] != NULL) && + (cfg->buildable_by_civs[i] != default_value)) + free ((void *)cfg->buildable_by_civs[i]); + cfg->buildable_by_civs[i] = NULL; + } + cfg->buildable_by_civ_count = def->buildable_by_civ_count; + const int max_civ_names = ARRAY_LEN (cfg->buildable_by_civs); + if (cfg->buildable_by_civ_count > max_civ_names) + cfg->buildable_by_civ_count = max_civ_names; + for (int i = 0; i < cfg->buildable_by_civ_count; i++) { + cfg->buildable_by_civs[i] = def->buildable_by_civs[i]; + def->buildable_by_civs[i] = NULL; + } + cfg->has_buildable_by_civs = true; + } + + if (def->has_buildable_by_civ_traits) { + cfg->buildable_by_civ_traits_id_count = def->buildable_by_civ_traits_id_count; + const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_traits_ids); + if (cfg->buildable_by_civ_traits_id_count > max_entries) + cfg->buildable_by_civ_traits_id_count = max_entries; + for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) + cfg->buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; + cfg->has_buildable_by_civ_traits = true; + } + + if (def->has_buildable_by_civ_govs) { + cfg->buildable_by_civ_govs_id_count = def->buildable_by_civ_govs_id_count; + const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_govs_ids); + if (cfg->buildable_by_civ_govs_id_count > max_entries) + cfg->buildable_by_civ_govs_id_count = max_entries; + for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) + cfg->buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; + cfg->has_buildable_by_civ_govs = true; + } + + if (def->has_buildable_by_civ_cultures) { + cfg->buildable_by_civ_cultures_id_count = def->buildable_by_civ_cultures_id_count; + const int max_entries = ARRAY_LEN (cfg->buildable_by_civ_cultures_ids); + if (cfg->buildable_by_civ_cultures_id_count > max_entries) + cfg->buildable_by_civ_cultures_id_count = max_entries; + for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) + cfg->buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; + cfg->has_buildable_by_civ_cultures = true; + } + + if (def->has_buildable_by_war_allies) + cfg->buildable_by_war_allies = def->buildable_by_war_allies; + if (def->has_buildable_by_pact_allies) + cfg->buildable_by_pact_allies = def->buildable_by_pact_allies; + + if (def->has_allow_multiple) + cfg->allow_multiple = def->allow_multiple; + if (def->has_vary_img_by_era) + cfg->vary_img_by_era = def->vary_img_by_era; + if (def->has_vary_img_by_culture) + cfg->vary_img_by_culture = def->vary_img_by_culture; + if (def->has_render_strategy) + cfg->render_strategy = def->render_strategy; + if (def->has_ai_build_strategy) + cfg->ai_build_strategy = def->ai_build_strategy; + if (def->has_align_to_coast) + cfg->align_to_coast = def->align_to_coast; + if (def->has_draw_over_resources) + cfg->draw_over_resources = def->draw_over_resources; + if (def->has_allow_irrigation_from) + cfg->allow_irrigation_from = def->allow_irrigation_from; + if (def->has_auto_add_road) + cfg->auto_add_road = def->auto_add_road; + if (def->has_auto_add_railroad) + cfg->auto_add_railroad = def->auto_add_railroad; + if (def->has_custom_width) + cfg->custom_width = def->custom_width; + if (def->has_custom_height) + cfg->custom_height = def->custom_height; + if (def->has_x_offset) + cfg->x_offset = def->x_offset; + if (def->has_y_offset) + cfg->y_offset = def->y_offset; + if (def->has_btn_tile_sheet_column) + cfg->btn_tile_sheet_column = def->btn_tile_sheet_column; + if (def->has_btn_tile_sheet_row) + cfg->btn_tile_sheet_row = def->btn_tile_sheet_row; + if (def->has_defense_bonus_percent) { + cfg->defense_bonus_percent = def->defense_bonus_percent; + free_bonus_entry_list_override (&cfg->defense_bonus_extras, &defaults->defense_bonus_extras); + move_bonus_entry_list (&cfg->defense_bonus_extras, &def->defense_bonus_extras); + } + if (def->has_heal_units_in_one_turn) + cfg->heal_units_in_one_turn = def->heal_units_in_one_turn; + if (def->has_impassible) + cfg->impassible = def->impassible; + if (def->has_impassible_to_wheeled) + cfg->impassible_to_wheeled = def->impassible_to_wheeled; + if (def->has_culture_bonus) { + cfg->culture_bonus = def->culture_bonus; + free_bonus_entry_list_override (&cfg->culture_bonus_extras, &defaults->culture_bonus_extras); + move_bonus_entry_list (&cfg->culture_bonus_extras, &def->culture_bonus_extras); + } + if (def->has_science_bonus) { + cfg->science_bonus = def->science_bonus; + free_bonus_entry_list_override (&cfg->science_bonus_extras, &defaults->science_bonus_extras); + move_bonus_entry_list (&cfg->science_bonus_extras, &def->science_bonus_extras); + } + if (def->has_food_bonus) { + cfg->food_bonus = def->food_bonus; + free_bonus_entry_list_override (&cfg->food_bonus_extras, &defaults->food_bonus_extras); + move_bonus_entry_list (&cfg->food_bonus_extras, &def->food_bonus_extras); + } + if (def->has_gold_bonus) { + cfg->gold_bonus = def->gold_bonus; + free_bonus_entry_list_override (&cfg->gold_bonus_extras, &defaults->gold_bonus_extras); + move_bonus_entry_list (&cfg->gold_bonus_extras, &def->gold_bonus_extras); + } + if (def->has_shield_bonus) { + cfg->shield_bonus = def->shield_bonus; + free_bonus_entry_list_override (&cfg->shield_bonus_extras, &defaults->shield_bonus_extras); + move_bonus_entry_list (&cfg->shield_bonus_extras, &def->shield_bonus_extras); + } + if (def->has_happiness_bonus) { + cfg->happiness_bonus = def->happiness_bonus; + free_bonus_entry_list_override (&cfg->happiness_bonus_extras, &defaults->happiness_bonus_extras); + move_bonus_entry_list (&cfg->happiness_bonus_extras, &def->happiness_bonus_extras); + } + if (def->has_buildable_on) + cfg->buildable_square_types_mask = def->buildable_square_types_mask; + if (def->has_buildable_adjacent_to) { + cfg->buildable_adjacent_to_square_types_mask = def->buildable_adjacent_to_square_types_mask; + cfg->has_buildable_adjacent_to = true; + cfg->buildable_adjacent_to_allows_city = def->buildable_adjacent_to_allows_city; + } + if (def->has_buildable_without_removal) { + cfg->buildable_without_removal_mask = def->buildable_without_removal_mask; + cfg->has_buildable_without_removal = true; + } + if (def->has_buildable_on_overlays) { + cfg->buildable_on_overlays_mask = def->buildable_on_overlays_mask; + cfg->has_buildable_on_overlays = true; + } + if (def->has_buildable_on_rivers) + cfg->buildable_on_rivers = def->buildable_on_rivers; + if (def->has_buildable_adjacent_to_overlays) { + cfg->buildable_adjacent_to_overlays_mask = def->buildable_adjacent_to_overlays_mask; + cfg->has_buildable_adjacent_to_overlays = true; + } + + if (def->has_generated_resource) { + if ((cfg->generated_resource != NULL) && (cfg->generated_resource != defaults->generated_resource)) + free ((void *)cfg->generated_resource); + cfg->generated_resource = def->generated_resource; + def->generated_resource = NULL; + cfg->generated_resource_flags = def->generated_resource_flags; + cfg->generated_resource_id = -1; + } + + if (def->has_dependent_improvements) { + for (int i = 0; i < ARRAY_LEN (cfg->dependent_improvements); i++) { + char const * default_value = (i < defaults->dependent_improvement_max_index) ? defaults->dependent_improvements[i] : NULL; + if ((cfg->dependent_improvements[i] != NULL) && + (cfg->dependent_improvements[i] != default_value)) + free ((void *)cfg->dependent_improvements[i]); + cfg->dependent_improvements[i] = NULL; + } + + cfg->dependent_improvement_max_index = def->dependent_improvement_max_index; + const int max_entries = ARRAY_LEN (cfg->dependent_improvements); + if (cfg->dependent_improvement_max_index > max_entries) + cfg->dependent_improvement_max_index = max_entries; + for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { + cfg->dependent_improvements[i] = def->dependent_improvements[i]; + def->dependent_improvements[i] = NULL; + } + if (! def->has_img_column_count) { + cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->dependent_improvement_max_index + 1); + cfg->has_img_column_count_override = false; + } + } + + if (def->has_img_paths) { + for (int i = 0; i < ARRAY_LEN (cfg->img_paths); i++) { + char const * default_value = (i < defaults->img_path_count) ? defaults->img_paths[i] : NULL; + if ((cfg->img_paths[i] != NULL) && + (cfg->img_paths[i] != default_value)) + free ((void *)cfg->img_paths[i]); + cfg->img_paths[i] = NULL; + } + + cfg->img_path_count = def->img_path_count; + const int max_img_paths = ARRAY_LEN (cfg->img_paths); + if (cfg->img_path_count > max_img_paths) + cfg->img_path_count = max_img_paths; + for (int i = 0; i < cfg->img_path_count; i++) { + cfg->img_paths[i] = def->img_paths[i]; + def->img_paths[i] = NULL; + } + } + + if (def->has_img_column_count) { + cfg->img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, cfg->img_column_count); + cfg->has_img_column_count_override = true; + } + + if (! ensure_culture_variant_art (cfg, section_start_line)) { + free_special_district_override_strings (cfg, defaults); + *cfg = *defaults; + return false; + } + + return true; +} + +bool +add_dynamic_district_from_definition (struct parsed_district_definition * def, int section_start_line) +{ + if ((! def->has_name) || (def->name == NULL)) + return false; + + if ((! def->has_img_paths) || (def->img_path_count <= 0)) + return false; + + int existing_index = -1; + for (int i = is->special_district_count; i < is->district_count; i++) { + if ((is->district_configs[i].name != NULL) && + (strcmp (is->district_configs[i].name, def->name) == 0)) { + existing_index = i; + break; + } + } + + bool reusing_existing = existing_index >= 0; + int dest_index = reusing_existing ? existing_index : (is->special_district_count + is->dynamic_district_count); + + if ((! reusing_existing) && (dest_index >= COUNT_DISTRICT_TYPES)) + return false; + + enum Unit_Command_Values preserved_command = 0; + if (reusing_existing) + preserved_command = is->district_configs[dest_index].command; + + struct district_config new_cfg; + memset (&new_cfg, 0, sizeof new_cfg); + new_cfg.is_dynamic = true; + + new_cfg.name = def->name; + def->name = NULL; + if (def->has_display_name) { + new_cfg.display_name = def->display_name; + if (new_cfg.display_name == NULL) + new_cfg.display_name = new_cfg.name; + def->display_name = NULL; + } else { + new_cfg.display_name = new_cfg.name; + } + + if (def->has_tooltip) { + new_cfg.tooltip = def->tooltip; + def->tooltip = NULL; + } else if (new_cfg.name != NULL) { + char buffer[128]; + snprintf (buffer, sizeof buffer, "Build %s", new_cfg.name); + new_cfg.tooltip = strdup (buffer); + } + + if (def->has_advance_prereqs) { + new_cfg.advance_prereq_count = def->advance_prereq_count; + const int max_entries = ARRAY_LEN (new_cfg.advance_prereqs); + if (new_cfg.advance_prereq_count > max_entries) + new_cfg.advance_prereq_count = max_entries; + for (int i = 0; i < new_cfg.advance_prereq_count; i++) { + new_cfg.advance_prereqs[i] = def->advance_prereqs[i]; + def->advance_prereqs[i] = NULL; + } + def->advance_prereq_count = 0; + } + + if (def->has_obsoleted_by) { + new_cfg.obsoleted_by = def->obsoleted_by; + def->obsoleted_by = NULL; + } + + new_cfg.resource_prereq_count = def->has_resource_prereqs ? def->resource_prereq_count : 0; + const int max_resource_entries = ARRAY_LEN (new_cfg.resource_prereqs); + if (new_cfg.resource_prereq_count > max_resource_entries) + new_cfg.resource_prereq_count = max_resource_entries; + for (int i = 0; i < new_cfg.resource_prereq_count; i++) { + new_cfg.resource_prereqs[i] = def->resource_prereqs[i]; + def->resource_prereqs[i] = NULL; + } + + if (def->has_resource_prereq_on_tile) { + new_cfg.resource_prereq_on_tile = def->resource_prereq_on_tile; + def->resource_prereq_on_tile = NULL; + } + + new_cfg.wonder_prereq_count = def->has_wonder_prereqs ? def->wonder_prereq_count : 0; + const int max_required_wonders = ARRAY_LEN (new_cfg.wonder_prereqs); + if (new_cfg.wonder_prereq_count > max_required_wonders) + new_cfg.wonder_prereq_count = max_required_wonders; + for (int i = 0; i < new_cfg.wonder_prereq_count; i++) { + new_cfg.wonder_prereqs[i] = def->wonder_prereqs[i]; + def->wonder_prereqs[i] = NULL; + } + + new_cfg.natural_wonder_prereq_count = def->has_natural_wonder_prereqs ? def->natural_wonder_prereq_count : 0; + const int max_required_natural_wonders = ARRAY_LEN (new_cfg.natural_wonder_prereqs); + if (new_cfg.natural_wonder_prereq_count > max_required_natural_wonders) + new_cfg.natural_wonder_prereq_count = max_required_natural_wonders; + for (int i = 0; i < new_cfg.natural_wonder_prereq_count; i++) { + new_cfg.natural_wonder_prereqs[i] = def->natural_wonder_prereqs[i]; + def->natural_wonder_prereqs[i] = NULL; + } + + new_cfg.buildable_on_district_count = def->has_buildable_on_districts ? def->buildable_on_district_count : 0; + const int max_buildable_on_districts = ARRAY_LEN (new_cfg.buildable_on_districts); + if (new_cfg.buildable_on_district_count > max_buildable_on_districts) + new_cfg.buildable_on_district_count = max_buildable_on_districts; + for (int i = 0; i < new_cfg.buildable_on_district_count; i++) { + new_cfg.buildable_on_districts[i] = def->buildable_on_districts[i]; + def->buildable_on_districts[i] = NULL; + } + new_cfg.buildable_on_district_id_count = 0; + new_cfg.has_buildable_on_districts = def->has_buildable_on_districts; + + new_cfg.buildable_adjacent_to_district_count = def->has_buildable_adjacent_to_districts ? def->buildable_adjacent_to_district_count : 0; + const int max_adjacent_to_districts = ARRAY_LEN (new_cfg.buildable_adjacent_to_districts); + if (new_cfg.buildable_adjacent_to_district_count > max_adjacent_to_districts) + new_cfg.buildable_adjacent_to_district_count = max_adjacent_to_districts; + for (int i = 0; i < new_cfg.buildable_adjacent_to_district_count; i++) { + new_cfg.buildable_adjacent_to_districts[i] = def->buildable_adjacent_to_districts[i]; + def->buildable_adjacent_to_districts[i] = NULL; + } + new_cfg.buildable_adjacent_to_district_id_count = 0; + new_cfg.has_buildable_adjacent_to_districts = def->has_buildable_adjacent_to_districts; + + new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; + const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); + if (new_cfg.buildable_by_civ_count > max_civ_names) + new_cfg.buildable_by_civ_count = max_civ_names; + for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { + new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; + def->buildable_by_civs[i] = NULL; + } + + new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; + + new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; + const int max_buildable_traits = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); + if (new_cfg.buildable_by_civ_traits_id_count > max_buildable_traits) + new_cfg.buildable_by_civ_traits_id_count = max_buildable_traits; + for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) + new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; + new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; + + new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; + const int max_buildable_govs = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); + if (new_cfg.buildable_by_civ_govs_id_count > max_buildable_govs) + new_cfg.buildable_by_civ_govs_id_count = max_buildable_govs; + for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) + new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; + new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; + + new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; + const int max_buildable_cultures = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); + if (new_cfg.buildable_by_civ_cultures_id_count > max_buildable_cultures) + new_cfg.buildable_by_civ_cultures_id_count = max_buildable_cultures; + for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) + new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; + new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; + + new_cfg.buildable_by_war_allies = def->has_buildable_by_war_allies ? def->buildable_by_war_allies : false; + new_cfg.buildable_by_pact_allies = def->has_buildable_by_pact_allies ? def->buildable_by_pact_allies : false; + + new_cfg.allow_multiple = def->has_allow_multiple ? def->allow_multiple : false; + new_cfg.vary_img_by_era = def->has_vary_img_by_era ? def->vary_img_by_era : false; + new_cfg.vary_img_by_culture = def->has_vary_img_by_culture ? def->vary_img_by_culture : false; + new_cfg.render_strategy = def->has_render_strategy ? def->render_strategy : DRS_BY_COUNT; + new_cfg.ai_build_strategy = def->has_ai_build_strategy ? def->ai_build_strategy : DABS_DISTRICT; + new_cfg.align_to_coast = def->has_align_to_coast ? def->align_to_coast : false; + new_cfg.draw_over_resources = def->has_draw_over_resources ? def->draw_over_resources : false; + new_cfg.allow_irrigation_from = def->has_allow_irrigation_from ? def->allow_irrigation_from : false; + new_cfg.auto_add_road = def->has_auto_add_road ? def->auto_add_road : false; + new_cfg.auto_add_railroad = def->has_auto_add_railroad ? def->auto_add_railroad : false; + new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; + new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; + new_cfg.x_offset = def->has_x_offset ? def->x_offset : 0; + new_cfg.y_offset = def->has_y_offset ? def->y_offset : 0; + new_cfg.btn_tile_sheet_column = def->has_btn_tile_sheet_column ? def->btn_tile_sheet_column : 0; + new_cfg.btn_tile_sheet_row = def->has_btn_tile_sheet_row ? def->btn_tile_sheet_row : 0; + new_cfg.defense_bonus_percent = def->has_defense_bonus_percent ? def->defense_bonus_percent : 0; + new_cfg.heal_units_in_one_turn = def->has_heal_units_in_one_turn ? def->heal_units_in_one_turn : false; + new_cfg.impassible = def->has_impassible ? def->impassible : false; + new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; + new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; + new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; + new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; + new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; + new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; + new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; + new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); + new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; + new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; + new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; + new_cfg.buildable_without_removal_mask = def->has_buildable_without_removal ? def->buildable_without_removal_mask : 0; + new_cfg.has_buildable_without_removal = def->has_buildable_without_removal; + new_cfg.buildable_on_overlays_mask = def->has_buildable_on_overlays ? def->buildable_on_overlays_mask : 0; + new_cfg.has_buildable_on_overlays = def->has_buildable_on_overlays; + new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; + new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; + new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; + + if (def->has_culture_bonus) + move_bonus_entry_list (&new_cfg.culture_bonus_extras, &def->culture_bonus_extras); + if (def->has_science_bonus) + move_bonus_entry_list (&new_cfg.science_bonus_extras, &def->science_bonus_extras); + if (def->has_food_bonus) + move_bonus_entry_list (&new_cfg.food_bonus_extras, &def->food_bonus_extras); + if (def->has_gold_bonus) + move_bonus_entry_list (&new_cfg.gold_bonus_extras, &def->gold_bonus_extras); + if (def->has_shield_bonus) + move_bonus_entry_list (&new_cfg.shield_bonus_extras, &def->shield_bonus_extras); + if (def->has_happiness_bonus) + move_bonus_entry_list (&new_cfg.happiness_bonus_extras, &def->happiness_bonus_extras); + if (def->has_defense_bonus_percent) + move_bonus_entry_list (&new_cfg.defense_bonus_extras, &def->defense_bonus_extras); + + if (def->has_generated_resource) { + new_cfg.generated_resource = def->generated_resource; + def->generated_resource = NULL; + new_cfg.generated_resource_flags = def->generated_resource_flags; + new_cfg.generated_resource_id = -1; + } else { + new_cfg.generated_resource = NULL; + new_cfg.generated_resource_id = -1; + new_cfg.generated_resource_flags = 0; + } + + new_cfg.dependent_improvement_max_index = def->has_dependent_improvements ? def->dependent_improvement_max_index : 0; + const int max_dependent_entries = ARRAY_LEN (is->district_configs[0].dependent_improvements); + if (new_cfg.dependent_improvement_max_index > max_dependent_entries) + new_cfg.dependent_improvement_max_index = max_dependent_entries; + for (int i = 0; i < new_cfg.dependent_improvement_max_index; i++) { + new_cfg.dependent_improvements[i] = def->dependent_improvements[i]; + def->dependent_improvements[i] = NULL; + } + + new_cfg.img_path_count = def->img_path_count; + const int max_img_paths = ARRAY_LEN (is->district_configs[0].img_paths); + if (new_cfg.img_path_count > max_img_paths) + new_cfg.img_path_count = max_img_paths; + for (int i = 0; i < new_cfg.img_path_count; i++) { + new_cfg.img_paths[i] = def->img_paths[i]; + def->img_paths[i] = NULL; + } + + if (! ensure_culture_variant_art (&new_cfg, section_start_line)) { + free_dynamic_district_config (&new_cfg); + return false; + } + + new_cfg.img_column_count = clamp (1, MAX_DISTRICT_COLUMN_COUNT, def->has_img_column_count ? def->img_column_count : new_cfg.dependent_improvement_max_index + 1); + new_cfg.has_img_column_count_override = def->has_img_column_count; + + if (reusing_existing) + new_cfg.command = preserved_command; + else + new_cfg.command = allocate_dynamic_district_command (new_cfg.name); + + struct district_config * dest_cfg = &is->district_configs[dest_index]; + if (reusing_existing) { + enum Unit_Command_Values saved_command = preserved_command; + free_dynamic_district_config (dest_cfg); + *dest_cfg = new_cfg; + dest_cfg->command = saved_command; + } else { + free_dynamic_district_config (dest_cfg); + *dest_cfg = new_cfg; + is->dynamic_district_count += 1; + is->district_count = is->special_district_count + is->dynamic_district_count; + } + + return true; +} + +void +finalize_parsed_district_definition (struct parsed_district_definition * def, int section_start_line) +{ + if ((! def->has_name) || (def->name == NULL)) + return; + + if (! override_special_district_from_definition (def, section_start_line)) + add_dynamic_district_from_definition (def, section_start_line); + + free_parsed_district_definition (def); +} + +void +handle_district_definition_key (struct parsed_district_definition * def, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if (slice_matches_str (key, "name")) { + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + char * name_copy = copy_trimmed_string_or_null (value, 1); + if (name_copy == NULL) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else { + def->name = name_copy; + def->has_name = true; + } + + } else if (slice_matches_str (key, "display_name")) { + if (def->display_name != NULL) { + free (def->display_name); + def->display_name = NULL; + } + def->display_name = copy_trimmed_string_or_null (value, 1); + def->has_display_name = true; + + } else if (slice_matches_str (key, "tooltip")) { + if (def->tooltip != NULL) { + free (def->tooltip); + def->tooltip = NULL; + } + def->tooltip = copy_trimmed_string_or_null (value, 1); + def->has_tooltip = true; + + } else if (slice_matches_str (key, "advance_prereqs") || slice_matches_str (key, "advance_prereq")) { + for (int i = 0; i < def->advance_prereq_count; i++) { + if (def->advance_prereqs[i] != NULL) { + free (def->advance_prereqs[i]); + def->advance_prereqs[i] = NULL; + } + } + def->advance_prereq_count = 0; + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->advance_prereqs, + ARRAY_LEN (def->advance_prereqs), + &list_count, + parse_errors, + line_number, + "advance_prereqs")) { + def->advance_prereq_count = list_count; + def->has_advance_prereqs = true; + } else { + def->advance_prereq_count = 0; + def->has_advance_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "obsoleted_by")) { + if (def->obsoleted_by != NULL) { + free (def->obsoleted_by); + def->obsoleted_by = NULL; + } + def->obsoleted_by = copy_trimmed_string_or_null (value, 1); + def->has_obsoleted_by = true; + + } else if (slice_matches_str (key, "resource_prereqs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->resource_prereqs, + ARRAY_LEN (def->resource_prereqs), + &list_count, + parse_errors, + line_number, + "resource_prereqs")) { + def->resource_prereq_count = list_count; + def->has_resource_prereqs = true; + } else { + def->resource_prereq_count = 0; + def->has_resource_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "resource_prereq_on_tile")) { + if (def->resource_prereq_on_tile != NULL) { + free (def->resource_prereq_on_tile); + def->resource_prereq_on_tile = NULL; + } + def->resource_prereq_on_tile = copy_trimmed_string_or_null (value, 1); + def->has_resource_prereq_on_tile = true; + + } else if (slice_matches_str (key, "wonder_prereqs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->wonder_prereqs, + ARRAY_LEN (def->wonder_prereqs), + &list_count, + parse_errors, + line_number, + "wonder_prereqs")) { + def->wonder_prereq_count = list_count; + def->has_wonder_prereqs = true; + } else { + def->wonder_prereq_count = 0; + def->has_wonder_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "natural_wonder_prereqs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->natural_wonder_prereqs, + ARRAY_LEN (def->natural_wonder_prereqs), + &list_count, + parse_errors, + line_number, + "natural_wonder_prereqs")) { + def->natural_wonder_prereq_count = list_count; + def->has_natural_wonder_prereqs = true; + } else { + def->natural_wonder_prereq_count = 0; + def->has_natural_wonder_prereqs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_on_districts")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_on_districts, + ARRAY_LEN (def->buildable_on_districts), + &list_count, + parse_errors, + line_number, + "buildable_on_districts")) { + def->buildable_on_district_count = list_count; + def->has_buildable_on_districts = true; + } else { + def->buildable_on_district_count = 0; + def->has_buildable_on_districts = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_adjacent_to_districts")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_adjacent_to_districts, + ARRAY_LEN (def->buildable_adjacent_to_districts), + &list_count, + parse_errors, + line_number, + "buildable_adjacent_to_districts")) { + def->buildable_adjacent_to_district_count = list_count; + def->has_buildable_adjacent_to_districts = true; + } else { + def->buildable_adjacent_to_district_count = 0; + def->has_buildable_adjacent_to_districts = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civs, + ARRAY_LEN (def->buildable_by_civs), + &list_count, + parse_errors, + line_number, + "buildable_by_civs")) { + def->buildable_by_civ_count = list_count; + def->has_buildable_by_civs = true; + } else { + def->buildable_by_civ_count = 0; + def->has_buildable_by_civs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_traits")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_traits, + ARRAY_LEN (def->buildable_by_civ_traits), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_traits")) { + def->buildable_by_civ_traits_count = list_count; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + char const * trait_name = def->buildable_by_civ_traits[i]; + if ((trait_name == NULL) || (trait_name[0] == '\0')) + continue; + int trait_id = -1; + struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; + if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { + if (def->buildable_by_civ_traits_ids[k] == trait_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) + def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->has_buildable_by_civ_traits = true; + } else { + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + def->has_buildable_by_civ_traits = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_govs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_govs, + ARRAY_LEN (def->buildable_by_civ_govs), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_govs")) { + def->buildable_by_civ_govs_count = list_count; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + char const * gov_name = def->buildable_by_civ_govs[i]; + if ((gov_name == NULL) || (gov_name[0] == '\0')) + continue; + int gov_id = -1; + struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; + if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { + if (def->buildable_by_civ_govs_ids[k] == gov_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) + def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->has_buildable_by_civ_govs = true; + } else { + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + def->has_buildable_by_civ_govs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_cultures, + ARRAY_LEN (def->buildable_by_civ_cultures), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_cultures")) { + def->buildable_by_civ_cultures_count = list_count; + def->buildable_by_civ_cultures_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + char const * culture_name = def->buildable_by_civ_cultures[i]; + if ((culture_name == NULL) || (culture_name[0] == '\0')) + continue; + int culture_id = -1; + struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; + if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { + if (def->buildable_by_civ_cultures_ids[k] == culture_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) + def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->has_buildable_by_civ_cultures = true; + } else { + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + def->has_buildable_by_civ_cultures = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_war_allies")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_by_war_allies = (ival != 0); + def->has_buildable_by_war_allies = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "buildable_by_pact_allies")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_by_pact_allies = (ival != 0); + def->has_buildable_by_pact_allies = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "img_paths")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->img_paths, + ARRAY_LEN (def->img_paths), + &list_count, + parse_errors, + line_number, + "img_paths")) { + def->img_path_count = list_count; + def->has_img_paths = true; + } else { + def->img_path_count = 0; + def->has_img_paths = false; + } + free (value_text); + + } else if (slice_matches_str (key, "img_column_count")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_column_count = ival; + def->has_img_column_count = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "dependent_improvs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->dependent_improvements, + ARRAY_LEN (def->dependent_improvements), + &list_count, + parse_errors, + line_number, + "dependent_improvs")) { + def->dependent_improvement_max_index = list_count; + def->has_dependent_improvements = true; + } else { + def->dependent_improvement_max_index = 0; + def->has_dependent_improvements = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_on")) { + unsigned int mask; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { + def->buildable_square_types_mask = mask; + def->has_buildable_on = true; + } + + } else if (slice_matches_str (key, "buildable_without_removal")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_without_removal")) { + def->buildable_without_removal_mask = mask; + def->has_buildable_without_removal = true; + } else { + def->has_buildable_without_removal = false; + } + + } else if (slice_matches_str (key, "buildable_on_overlays")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_on_overlays")) { + def->buildable_on_overlays_mask = mask; + def->has_buildable_on_overlays = true; + } else { + def->has_buildable_on_overlays = false; + } + + } else if (slice_matches_str (key, "buildable_on_rivers")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_on_rivers = (ival != 0); + def->has_buildable_on_rivers = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "buildable_adjacent_to")) { + unsigned int mask; + def->buildable_adjacent_to_allows_city = false; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { + def->buildable_adjacent_to_square_types_mask = mask; + def->has_buildable_adjacent_to = true; + } + + } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { + def->buildable_adjacent_to_overlays_mask = mask; + def->has_buildable_adjacent_to_overlays = true; + } else { + def->has_buildable_adjacent_to_overlays = false; + } + + } else if (slice_matches_str (key, "allow_multiple")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->allow_multiple = (ival != 0); + def->has_allow_multiple = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "vary_img_by_era")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->vary_img_by_era = (ival != 0); + def->has_vary_img_by_era = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "vary_img_by_culture")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->vary_img_by_culture = (ival != 0); + def->has_vary_img_by_culture = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "render_strategy")) { + char * strategy = copy_trimmed_string_or_null (value, 1); + if (strategy == NULL) { + def->has_render_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else if (strcmp (strategy, "by-count") == 0) { + def->render_strategy = DRS_BY_COUNT; + def->has_render_strategy = true; + } else if (strcmp (strategy, "by-building") == 0) { + def->render_strategy = DRS_BY_BUILDING; + def->has_render_strategy = true; + } else { + def->has_render_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected \"by-count\" or \"by-building\")"); + } + if (strategy != NULL) + free (strategy); + + } else if (slice_matches_str (key, "ai_build_strategy")) { + char * strategy = copy_trimmed_string_or_null (value, 1); + if (strategy == NULL) { + def->has_ai_build_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else if (strcmp (strategy, "district") == 0) { + def->ai_build_strategy = DABS_DISTRICT; + def->has_ai_build_strategy = true; + } else if (strcmp (strategy, "tile-improvement") == 0) { + def->ai_build_strategy = DABS_TILE_IMPROVEMENT; + def->has_ai_build_strategy = true; + } else { + def->has_ai_build_strategy = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected \"district\" or \"tile-improvement\")"); + } + if (strategy != NULL) + free (strategy); + + } else if (slice_matches_str (key, "align_to_coast")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->align_to_coast = (ival != 0); + def->has_align_to_coast = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "draw_over_resources")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->draw_over_resources = (ival != 0); + def->has_draw_over_resources = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "allow_irrigation_from")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->allow_irrigation_from = (ival != 0); + def->has_allow_irrigation_from = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "auto_add_road")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->auto_add_road = (ival != 0); + def->has_auto_add_road = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "auto_add_railroad")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->auto_add_railroad = (ival != 0); + def->has_auto_add_railroad = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "impassible")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible = (ival != 0); + def->has_impassible = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "impassible_to_wheeled")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible_to_wheeled = (ival != 0); + def->has_impassible_to_wheeled = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "custom_width")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_width = ival; + def->has_custom_width = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "custom_height")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_height = ival; + def->has_custom_height = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "x_offset")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->x_offset = ival; + def->has_x_offset = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "y_offset")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->y_offset = ival; + def->has_y_offset = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "btn_tile_sheet_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->btn_tile_sheet_column = ival; + def->has_btn_tile_sheet_column = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "btn_tile_sheet_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->btn_tile_sheet_row = ival; + def->has_btn_tile_sheet_row = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "defense_bonus_percent")) { + if (parse_district_bonus_entries (value, &def->defense_bonus_percent, &def->defense_bonus_extras, parse_errors, line_number, key)) { + def->has_defense_bonus_percent = true; + } else { + def->has_defense_bonus_percent = false; + } + + } else if (slice_matches_str (key, "heal_units_in_one_turn")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->heal_units_in_one_turn = (ival != 0); + def->has_heal_units_in_one_turn = true; + } else + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + + } else if (slice_matches_str (key, "culture_bonus")) { + if (parse_district_bonus_entries (value, &def->culture_bonus, &def->culture_bonus_extras, parse_errors, line_number, key)) { + def->has_culture_bonus = true; + } else { + def->has_culture_bonus = false; + } + + } else if (slice_matches_str (key, "science_bonus")) { + if (parse_district_bonus_entries (value, &def->science_bonus, &def->science_bonus_extras, parse_errors, line_number, key)) { + def->has_science_bonus = true; + } else { + def->has_science_bonus = false; + } + + } else if (slice_matches_str (key, "food_bonus")) { + if (parse_district_bonus_entries (value, &def->food_bonus, &def->food_bonus_extras, parse_errors, line_number, key)) { + def->has_food_bonus = true; + } else { + def->has_food_bonus = false; + } + + } else if (slice_matches_str (key, "gold_bonus")) { + if (parse_district_bonus_entries (value, &def->gold_bonus, &def->gold_bonus_extras, parse_errors, line_number, key)) { + def->has_gold_bonus = true; + } else { + def->has_gold_bonus = false; + } + + } else if (slice_matches_str (key, "shield_bonus")) { + if (parse_district_bonus_entries (value, &def->shield_bonus, &def->shield_bonus_extras, parse_errors, line_number, key)) { + def->has_shield_bonus = true; + } else { + def->has_shield_bonus = false; + } + + } else if (slice_matches_str (key, "happiness_bonus")) { + if (parse_district_bonus_entries (value, &def->happiness_bonus, &def->happiness_bonus_extras, parse_errors, line_number, key)) { + def->has_happiness_bonus = true; + } else { + def->has_happiness_bonus = false; + } + + } else if (slice_matches_str (key, "generated_resource")) { + if (def->generated_resource != NULL) { + free (def->generated_resource); + def->generated_resource = NULL; + } + def->generated_resource_flags = 0; + + char * value_text = trim_and_extract_slice (value, 0); + if ((value_text == NULL) || (*value_text == '\0')) { + def->generated_resource = NULL; + def->has_generated_resource = true; + } else { + char * cursor = value_text; + struct string_slice resource_name = {0}; + struct string_slice token; + bool ok = true; + while (skip_white_space (&cursor) && parse_string (&cursor, &token)) { + if (slice_matches_str (&token, "local")) + def->generated_resource_flags |= MF_LOCAL; + else if (slice_matches_str (&token, "no-tech-req")) + def->generated_resource_flags |= MF_NO_TECH_REQ; + else if (slice_matches_str (&token, "yields")) + def->generated_resource_flags |= MF_YIELDS; + else if (resource_name.str == NULL) + resource_name = token; + else { + ok = false; + break; + } + } + + if (! ok || (resource_name.str == NULL)) { + def->generated_resource = NULL; + def->has_generated_resource = false; + def->generated_resource_flags = 0; + add_key_parse_error (parse_errors, line_number, key, value, + "(expected resource name plus optional flags: local, yields, no-tech-req)"); + } else { + def->generated_resource = extract_slice (&resource_name); + def->has_generated_resource = true; + } + } + free (value_text); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +bool +line_is_empty_or_comment (struct string_slice const * trimmed) +{ + return ((trimmed == NULL) || (trimmed->len == 0) || (trimmed->str[0] == ';') || (trimmed->str[0] == '[')); +} + +bool +file_exists_at_path (char const * path) +{ + if ((path == NULL) || (path[0] == '\0')) + return false; + + HANDLE file = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + return false; + + CloseHandle (file); + return true; +} + +void +load_dynamic_district_config_file (char const * file_path, + int path_is_relative_to_mod_dir, + int log_missing, + int drop_existing_configs) +{ + char path[MAX_PATH]; + if (path_is_relative_to_mod_dir) { + if (is->mod_rel_dir == NULL) + return; + snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); + } else { + strncpy (path, file_path, sizeof path); + } + path[(sizeof path) - 1] = '\0'; + + char * text = file_to_string (path); + if (text == NULL) { + if (log_missing) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] Districts config file not found: %s", path); + (*p_OutputDebugStringA) (ss); + } + return; + } + + if (drop_existing_configs) + reset_regular_district_configs (); + + struct parsed_district_definition def; + init_parsed_district_definition (&def); + bool in_section = false; + int section_start_line = 0; + int line_number = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + bool has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if ((directive.len > 0) && slice_matches_str (&directive, "District")) { + if (in_section) + finalize_parsed_district_definition (&def, section_start_line); + in_section = true; + section_start_line = line_number; + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); + if (status == KVP_NO_EQUALS) { + char * line_text = extract_slice (&trimmed); + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); + err->text[(sizeof err->text) - 1] = '\0'; + free (line_text); + cursor = has_newline ? line_end + 1 : line_end; + continue; + } else if (status == KVP_EMPTY_KEY) { + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); + err->text[(sizeof err->text) - 1] = '\0'; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + handle_district_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) + finalize_parsed_district_definition (&def, section_start_line); + + free_parsed_district_definition (&def); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + snprintf (is->current_districts_config_path, sizeof is->current_districts_config_path, path); + + if (parse_errors != NULL || unrecognized_keys != NULL) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "District Config errors in %s:", path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + if (parse_errors != NULL) { + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", false); + PopupForm_add_text (popup, __, "Unrecognized keys:", false); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + patch_show_popup (popup, __, 0, 0); + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); + } +} + +void +load_dynamic_district_configs () +{ + char * scenario_filename = "scenario.districts_config.txt"; + char * scenario_district_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + if ((scenario_district_config_path != NULL) && + (0 != strcmp (scenario_filename, scenario_district_config_path)) && + file_exists_at_path (scenario_district_config_path)) { + load_dynamic_district_config_file (scenario_district_config_path, 0, 0, 1); + return; + } + + if (is->mod_rel_dir != NULL) { + char user_path[MAX_PATH]; + snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_config.txt"); + user_path[(sizeof user_path) - 1] = '\0'; + if (file_exists_at_path (user_path)) { + load_dynamic_district_config_file ("user.districts_config.txt", 1, 0, 1); + return; + } + } + + load_dynamic_district_config_file ("default.districts_config.txt", 1, 1, 1); +} + +void +init_parsed_wonder_definition (struct parsed_wonder_definition * def) +{ + memset (def, 0, sizeof *def); + def->buildable_square_types_mask = district_default_buildable_mask (); + def->buildable_adjacent_to_square_types_mask = 0; + def->buildable_adjacent_to_overlays_mask = 0; + def->buildable_on_rivers = false; + def->buildable_adjacent_to_allows_city = false; + for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_traits_ids); i++) + def->buildable_by_civ_traits_ids[i] = -1; + for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_govs_ids); i++) + def->buildable_by_civ_govs_ids[i] = -1; + for (int i = 0; i < ARRAY_LEN (def->buildable_by_civ_cultures_ids); i++) + def->buildable_by_civ_cultures_ids[i] = -1; +} + +void +free_parsed_wonder_definition (struct parsed_wonder_definition * def) +{ + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + + for (int i = 0; i < def->buildable_by_civ_count; i++) { + if (def->buildable_by_civs[i] != NULL) { + free (def->buildable_by_civs[i]); + def->buildable_by_civs[i] = NULL; + } + } + def->buildable_by_civ_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + + init_parsed_wonder_definition (def); +} + +bool +add_dynamic_wonder_from_definition (struct parsed_wonder_definition * def, int section_start_line) +{ + int existing_index = -1; + for (int i = 0; i < is->wonder_district_count; i++) { + if ((is->wonder_district_configs[i].wonder_name != NULL) && + (strcmp (is->wonder_district_configs[i].wonder_name, def->name) == 0)) { + existing_index = i; + break; + } + } + + int dest = (existing_index >= 0) ? existing_index : is->wonder_district_count; + if ((dest < 0) || (dest >= MAX_WONDER_DISTRICT_TYPES)) + return false; + + struct wonder_district_config new_cfg; + memset (&new_cfg, 0, sizeof new_cfg); + new_cfg.index = dest; + new_cfg.is_dynamic = true; + new_cfg.wonder_name = strdup (def->name); + new_cfg.img_path = (def->img_path != NULL) ? strdup (def->img_path) : strdup ("Wonders.pcx"); + new_cfg.img_row = def->img_row; + new_cfg.img_column = def->img_column; + new_cfg.img_construct_row = def->img_construct_row; + new_cfg.img_construct_column = def->img_construct_column; + new_cfg.img_alt_dir_construct_row = def->img_alt_dir_construct_row; + new_cfg.img_alt_dir_construct_column = def->img_alt_dir_construct_column; + new_cfg.img_alt_dir_row = def->img_alt_dir_row; + new_cfg.img_alt_dir_column = def->img_alt_dir_column; + new_cfg.custom_width = def->has_custom_width ? def->custom_width : 0; + new_cfg.custom_height = def->has_custom_height ? def->custom_height : 0; + new_cfg.enable_img_alt_dir = def->enable_img_alt_dir; + new_cfg.buildable_square_types_mask = def->has_buildable_on ? def->buildable_square_types_mask : district_default_buildable_mask (); + new_cfg.buildable_on_rivers = def->has_buildable_on_rivers ? def->buildable_on_rivers : false; + new_cfg.buildable_adjacent_to_overlays_mask = def->has_buildable_adjacent_to_overlays ? def->buildable_adjacent_to_overlays_mask : 0; + new_cfg.buildable_adjacent_to_square_types_mask = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_square_types_mask : 0; + new_cfg.buildable_adjacent_to_allows_city = def->has_buildable_adjacent_to ? def->buildable_adjacent_to_allows_city : false; + new_cfg.buildable_by_civ_count = def->has_buildable_by_civs ? def->buildable_by_civ_count : 0; + const int max_civ_names = ARRAY_LEN (new_cfg.buildable_by_civs); + if (new_cfg.buildable_by_civ_count > max_civ_names) + new_cfg.buildable_by_civ_count = max_civ_names; + for (int i = 0; i < new_cfg.buildable_by_civ_count; i++) { + new_cfg.buildable_by_civs[i] = def->buildable_by_civs[i]; + def->buildable_by_civs[i] = NULL; + } + new_cfg.has_buildable_by_civs = def->has_buildable_by_civs; + new_cfg.buildable_by_civ_traits_id_count = def->has_buildable_by_civ_traits ? def->buildable_by_civ_traits_id_count : 0; + const int max_trait_entries = ARRAY_LEN (new_cfg.buildable_by_civ_traits_ids); + if (new_cfg.buildable_by_civ_traits_id_count > max_trait_entries) + new_cfg.buildable_by_civ_traits_id_count = max_trait_entries; + for (int i = 0; i < new_cfg.buildable_by_civ_traits_id_count; i++) + new_cfg.buildable_by_civ_traits_ids[i] = def->buildable_by_civ_traits_ids[i]; + new_cfg.has_buildable_by_civ_traits = def->has_buildable_by_civ_traits; + new_cfg.buildable_by_civ_govs_id_count = def->has_buildable_by_civ_govs ? def->buildable_by_civ_govs_id_count : 0; + const int max_gov_entries = ARRAY_LEN (new_cfg.buildable_by_civ_govs_ids); + if (new_cfg.buildable_by_civ_govs_id_count > max_gov_entries) + new_cfg.buildable_by_civ_govs_id_count = max_gov_entries; + for (int i = 0; i < new_cfg.buildable_by_civ_govs_id_count; i++) + new_cfg.buildable_by_civ_govs_ids[i] = def->buildable_by_civ_govs_ids[i]; + new_cfg.has_buildable_by_civ_govs = def->has_buildable_by_civ_govs; + new_cfg.buildable_by_civ_cultures_id_count = def->has_buildable_by_civ_cultures ? def->buildable_by_civ_cultures_id_count : 0; + const int max_culture_entries = ARRAY_LEN (new_cfg.buildable_by_civ_cultures_ids); + if (new_cfg.buildable_by_civ_cultures_id_count > max_culture_entries) + new_cfg.buildable_by_civ_cultures_id_count = max_culture_entries; + for (int i = 0; i < new_cfg.buildable_by_civ_cultures_id_count; i++) + new_cfg.buildable_by_civ_cultures_ids[i] = def->buildable_by_civ_cultures_ids[i]; + new_cfg.has_buildable_by_civ_cultures = def->has_buildable_by_civ_cultures; + new_cfg.has_buildable_adjacent_to = def->has_buildable_adjacent_to; + new_cfg.has_buildable_adjacent_to_overlays = def->has_buildable_adjacent_to_overlays; + + if (existing_index >= 0) { + struct wonder_district_config * cfg = &is->wonder_district_configs[existing_index]; + free_dynamic_wonder_config (cfg); + *cfg = new_cfg; + cfg->index = existing_index; + } else { + struct wonder_district_config * cfg = &is->wonder_district_configs[dest]; + free_dynamic_wonder_config (cfg); + *cfg = new_cfg; + is->wonder_district_count += 1; + } + + return true; +} + +void +finalize_parsed_wonder_definition (struct parsed_wonder_definition * def, + int section_start_line, + struct error_line ** parse_errors) +{ + bool ok = true; + + if ((! def->has_name) || (def->name == NULL)) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_construct_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_row (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_construct_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_construct_column (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (def->enable_img_alt_dir) { + if (! def->has_img_alt_dir_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_row (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_alt_dir_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_column (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_alt_dir_construct_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_row (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_alt_dir_construct_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_alt_dir_construct_column (value is required when enable_img_alt_dir is set)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + } + + if (ok) + add_dynamic_wonder_from_definition (def, section_start_line); + + free_parsed_wonder_definition (def); +} + +void +handle_wonder_definition_key (struct parsed_wonder_definition * def, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if (slice_matches_str (key, "name")) { + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else { + char * name_copy = extract_slice (&unquoted); + if (name_copy == NULL) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); + } else { + def->name = name_copy; + def->has_name = true; + } + } + + } else if (slice_matches_str (key, "img_path")) { + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_img_path = false; + } else { + char * path_copy = extract_slice (&unquoted); + if (path_copy == NULL) { + def->has_img_path = false; + } else { + def->img_path = path_copy; + def->has_img_path = true; + } + } + + } else if (slice_matches_str (key, "img_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_row = ival; + def->has_img_row = true; + } else { + def->has_img_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_column = ival; + def->has_img_column = true; + } else { + def->has_img_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_construct_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_construct_row = ival; + def->has_img_construct_row = true; + } else { + def->has_img_construct_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_construct_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_construct_column = ival; + def->has_img_construct_column = true; + } else { + def->has_img_construct_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_construct_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_construct_row = ival; + def->has_img_alt_dir_construct_row = true; + } else { + def->has_img_alt_dir_construct_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_construct_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_construct_column = ival; + def->has_img_alt_dir_construct_column = true; + } else { + def->has_img_alt_dir_construct_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_row = ival; + def->has_img_alt_dir_row = true; + } else { + def->has_img_alt_dir_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_alt_dir_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_alt_dir_column = ival; + def->has_img_alt_dir_column = true; + } else { + def->has_img_alt_dir_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "custom_width")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_width = ival; + def->has_custom_width = true; + } else { + def->has_custom_width = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "custom_height")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->custom_height = ival; + def->has_custom_height = true; + } else { + def->has_custom_height = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "enable_img_alt_dir")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->enable_img_alt_dir = (ival != 0); + def->has_enable_img_alt_dir = true; + } else { + def->has_enable_img_alt_dir = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "buildable_on")) { + unsigned int mask; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_on", NULL)) { + def->buildable_square_types_mask = mask; + def->has_buildable_on = true; + } else { + def->has_buildable_on = false; + } + + } else if (slice_matches_str (key, "buildable_on_rivers")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->buildable_on_rivers = (ival != 0); + def->has_buildable_on_rivers = true; + } else { + def->has_buildable_on_rivers = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "buildable_adjacent_to")) { + unsigned int mask; + def->buildable_adjacent_to_allows_city = false; + if (parse_buildable_square_type_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to", &def->buildable_adjacent_to_allows_city)) { + def->buildable_adjacent_to_square_types_mask = mask; + def->has_buildable_adjacent_to = true; + } else { + def->has_buildable_adjacent_to = false; + } + + } else if (slice_matches_str (key, "buildable_adjacent_to_overlays")) { + unsigned int mask; + if (parse_buildable_overlay_mask (value, &mask, parse_errors, line_number, "buildable_adjacent_to_overlays")) { + def->buildable_adjacent_to_overlays_mask = mask; + def->has_buildable_adjacent_to_overlays = true; + } else { + def->has_buildable_adjacent_to_overlays = false; + } + + } else if (slice_matches_str (key, "buildable_by_civs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civs, + ARRAY_LEN (def->buildable_by_civs), + &list_count, + parse_errors, + line_number, + "buildable_by_civs")) { + def->buildable_by_civ_count = list_count; + def->has_buildable_by_civs = true; + } else { + def->buildable_by_civ_count = 0; + def->has_buildable_by_civs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_traits")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_traits, + ARRAY_LEN (def->buildable_by_civ_traits), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_traits")) { + def->buildable_by_civ_traits_count = list_count; + def->buildable_by_civ_traits_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + char const * trait_name = def->buildable_by_civ_traits[i]; + if ((trait_name == NULL) || (trait_name[0] == '\0')) + continue; + int trait_id = -1; + struct string_slice trait_slice = { .str = (char *)trait_name, .len = (int)strlen (trait_name) }; + if (find_civ_trait_id_by_name (&trait_slice, &trait_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_traits_id_count; k++) { + if (def->buildable_by_civ_traits_ids[k] == trait_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_traits_id_count < ARRAY_LEN (def->buildable_by_civ_traits_ids))) + def->buildable_by_civ_traits_ids[def->buildable_by_civ_traits_id_count++] = trait_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_traits entry \"%.*s\" not found", line_number, trait_slice.len, trait_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_traits_count; i++) { + if (def->buildable_by_civ_traits[i] != NULL) { + free (def->buildable_by_civ_traits[i]); + def->buildable_by_civ_traits[i] = NULL; + } + } + def->buildable_by_civ_traits_count = 0; + def->has_buildable_by_civ_traits = true; + } else { + def->buildable_by_civ_traits_count = 0; + def->buildable_by_civ_traits_id_count = 0; + def->has_buildable_by_civ_traits = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_govs")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_govs, + ARRAY_LEN (def->buildable_by_civ_govs), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_govs")) { + def->buildable_by_civ_govs_count = list_count; + def->buildable_by_civ_govs_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + char const * gov_name = def->buildable_by_civ_govs[i]; + if ((gov_name == NULL) || (gov_name[0] == '\0')) + continue; + int gov_id = -1; + struct string_slice gov_slice = { .str = (char *)gov_name, .len = (int)strlen (gov_name) }; + if (find_game_object_id_by_name (GOK_GOVERNMENT, &gov_slice, 0, &gov_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_govs_id_count; k++) { + if (def->buildable_by_civ_govs_ids[k] == gov_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_govs_id_count < ARRAY_LEN (def->buildable_by_civ_govs_ids))) + def->buildable_by_civ_govs_ids[def->buildable_by_civ_govs_id_count++] = gov_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_govs entry \"%.*s\" not found", line_number, gov_slice.len, gov_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_govs_count; i++) { + if (def->buildable_by_civ_govs[i] != NULL) { + free (def->buildable_by_civ_govs[i]); + def->buildable_by_civ_govs[i] = NULL; + } + } + def->buildable_by_civ_govs_count = 0; + def->has_buildable_by_civ_govs = true; + } else { + def->buildable_by_civ_govs_count = 0; + def->buildable_by_civ_govs_id_count = 0; + def->has_buildable_by_civ_govs = false; + } + free (value_text); + + } else if (slice_matches_str (key, "buildable_by_civ_cultures")) { + char * value_text = trim_and_extract_slice (value, 0); + int list_count = 0; + if (parse_config_string_list (value_text, + def->buildable_by_civ_cultures, + ARRAY_LEN (def->buildable_by_civ_cultures), + &list_count, + parse_errors, + line_number, + "buildable_by_civ_cultures")) { + def->buildable_by_civ_cultures_count = list_count; + def->buildable_by_civ_cultures_id_count = 0; + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + char const * culture_name = def->buildable_by_civ_cultures[i]; + if ((culture_name == NULL) || (culture_name[0] == '\0')) + continue; + int culture_id = -1; + struct string_slice culture_slice = { .str = (char *)culture_name, .len = (int)strlen (culture_name) }; + if (find_civ_culture_id_by_name (&culture_slice, &culture_id)) { + bool already_listed = false; + for (int k = 0; k < def->buildable_by_civ_cultures_id_count; k++) { + if (def->buildable_by_civ_cultures_ids[k] == culture_id) { + already_listed = true; + break; + } + } + if ((! already_listed) && (def->buildable_by_civ_cultures_id_count < ARRAY_LEN (def->buildable_by_civ_cultures_ids))) + def->buildable_by_civ_cultures_ids[def->buildable_by_civ_cultures_id_count++] = culture_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: buildable_by_civ_cultures entry \"%.*s\" not found", line_number, culture_slice.len, culture_slice.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + for (int i = 0; i < def->buildable_by_civ_cultures_count; i++) { + if (def->buildable_by_civ_cultures[i] != NULL) { + free (def->buildable_by_civ_cultures[i]); + def->buildable_by_civ_cultures[i] = NULL; + } + } + def->buildable_by_civ_cultures_count = 0; + def->has_buildable_by_civ_cultures = true; + } else { + def->buildable_by_civ_cultures_count = 0; + def->buildable_by_civ_cultures_id_count = 0; + def->has_buildable_by_civ_cultures = false; + } + free (value_text); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +void +load_dynamic_wonder_config_file (char const * file_path, + int path_is_relative_to_mod_dir, + int log_missing, + int drop_existing_configs) +{ + char path[MAX_PATH]; + if (path_is_relative_to_mod_dir) { + if (is->mod_rel_dir == NULL) + return; + snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); + } else { + strncpy (path, file_path, sizeof path); + } + path[(sizeof path) - 1] = '\0'; + + char * text = file_to_string (path); + if (text == NULL) { + if (log_missing) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] Wonders config file not found: %s", path); + (*p_OutputDebugStringA) (ss); + } + return; + } + + if (drop_existing_configs) + reset_wonder_district_configs (); + + struct parsed_wonder_definition def; + init_parsed_wonder_definition (&def); + bool in_section = false; + int section_start_line = 0; + int line_number = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + bool has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { + if (in_section) + finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); + in_section = true; + section_start_line = line_number; + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); + if (status == KVP_NO_EQUALS) { + char * line_text = extract_slice (&trimmed); + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); + err->text[(sizeof err->text) - 1] = '\0'; + free (line_text); + cursor = has_newline ? line_end + 1 : line_end; + continue; + } else if (status == KVP_EMPTY_KEY) { + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); + err->text[(sizeof err->text) - 1] = '\0'; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + handle_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) + finalize_parsed_wonder_definition (&def, section_start_line, &parse_errors); + + free_parsed_wonder_definition (&def); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + + if (parse_errors != NULL || unrecognized_keys != NULL) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "Wonder District Config errors in %s:", path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + if (parse_errors != NULL) { + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", false); + PopupForm_add_text (popup, __, "Unrecognized keys:", false); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + patch_show_popup (popup, __, 0, 0); + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); + } +} + +void +load_dynamic_wonder_configs () +{ + char * scenario_filename = "scenario.districts_wonders_config.txt"; + char * scenario_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + if ((scenario_wonder_config_path != NULL) && + (0 != strcmp (scenario_filename, scenario_wonder_config_path)) && + file_exists_at_path (scenario_wonder_config_path)) { + load_dynamic_wonder_config_file (scenario_wonder_config_path, 0, 0, 1); + return; + } + + if (is->mod_rel_dir != NULL) { + char user_path[MAX_PATH]; + snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_wonders_config.txt"); + user_path[(sizeof user_path) - 1] = '\0'; + if (file_exists_at_path (user_path)) { + load_dynamic_wonder_config_file ("user.districts_wonders_config.txt", 1, 0, 1); + return; + } + } + + load_dynamic_wonder_config_file ("default.districts_wonders_config.txt", 1, 1, 1); +} + +void +init_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) +{ + memset (def, 0, sizeof *def); + def->terrain_type = SQ_Grassland; + def->adjacent_to = (enum SquareTypes)SQ_INVALID; + def->adjacency_dir = DIR_ZERO; +} + +void +free_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def) +{ + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + init_parsed_natural_wonder_definition (def); +} + +bool +add_natural_wonder_from_definition (struct parsed_natural_wonder_definition * def, int section_start_line) +{ + if ((def == NULL) || (def->name == NULL)) + return false; + + int existing_index; + bool has_existing = stable_look_up (&is->natural_wonder_name_to_id, def->name, &existing_index); + + int dest = has_existing ? existing_index : is->natural_wonder_count; + if ((dest < 0) || (dest >= MAX_NATURAL_WONDER_DISTRICT_TYPES)) + return false; + + struct natural_wonder_district_config new_cfg; + memset (&new_cfg, 0, sizeof new_cfg); + new_cfg.index = dest; + new_cfg.is_dynamic = true; + new_cfg.adjacent_to = (enum SquareTypes)SQ_INVALID; + new_cfg.adjacency_dir = DIR_ZERO; + + char * name_copy = strdup (def->name); + if (name_copy == NULL) + return false; + new_cfg.name = name_copy; + + char const * img_path_src = def->img_path; + char * img_copy = strdup (img_path_src); + if (img_copy == NULL) { + free (name_copy); + return false; + } + new_cfg.img_path = img_copy; + new_cfg.img_row = def->img_row; + new_cfg.img_column = def->img_column; + new_cfg.terrain_type = def->terrain_type; + new_cfg.adjacent_to = def->adjacent_to; + new_cfg.adjacency_dir = def->adjacency_dir; + new_cfg.culture_bonus = def->has_culture_bonus ? def->culture_bonus : 0; + new_cfg.science_bonus = def->has_science_bonus ? def->science_bonus : 0; + new_cfg.food_bonus = def->has_food_bonus ? def->food_bonus : 0; + new_cfg.gold_bonus = def->has_gold_bonus ? def->gold_bonus : 0; + new_cfg.shield_bonus = def->has_shield_bonus ? def->shield_bonus : 0; + new_cfg.happiness_bonus = def->has_happiness_bonus ? def->happiness_bonus : 0; + new_cfg.impassible = def->has_impassible ? def->impassible : false; + new_cfg.impassible_to_wheeled = def->has_impassible_to_wheeled ? def->impassible_to_wheeled : false; + + if (has_existing) { + struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[existing_index]; + free_dynamic_natural_wonder_config (cfg); + *cfg = new_cfg; + } else { + struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[dest]; + free_dynamic_natural_wonder_config (cfg); + *cfg = new_cfg; + is->natural_wonder_count = dest + 1; + stable_insert (&is->natural_wonder_name_to_id, new_cfg.name, dest); + } + + return true; +} + +void +finalize_parsed_natural_wonder_definition (struct parsed_natural_wonder_definition * def, + int section_start_line, + struct error_line ** parse_errors) +{ + bool ok = true; + + if ((! def->has_name) || (def->name == NULL)) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: name (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_row) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_row (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_img_column) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: img_column (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + if (! def->has_terrain_type) { + ok = false; + if (parse_errors != NULL) { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: terrain_type (value is required)", section_start_line); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + if (ok) + add_natural_wonder_from_definition (def, section_start_line); + + free_parsed_natural_wonder_definition (def); +} + +void +handle_natural_wonder_definition_key (struct parsed_natural_wonder_definition * def, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if (slice_matches_str (key, "name")) { + if (def->name != NULL) { + free (def->name); + def->name = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(value is required)"); + } else { + char * name_copy = extract_slice (&unquoted); + if (name_copy == NULL) { + def->has_name = false; + add_key_parse_error (parse_errors, line_number, key, value, "(out of memory)"); + } else { + def->name = name_copy; + def->has_name = true; + } + } + + } else if (slice_matches_str (key, "terrain_type")) { + enum SquareTypes terrain; + if (read_natural_wonder_terrain_type (value, &terrain)) { + def->terrain_type = terrain; + def->has_terrain_type = true; + } else { + def->has_terrain_type = false; + add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized terrain type)"); + } + + } else if (slice_matches_str (key, "adjacent_to")) { + enum SquareTypes adj; + if (read_tile_terrain_type_value (value, &adj)) { + def->adjacent_to = adj; + def->has_adjacent_to = true; + } else { + def->adjacent_to = (enum SquareTypes)SQ_INVALID; + def->has_adjacent_to = false; + add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized tile terrain type)"); + } + + } else if (slice_matches_str (key, "adjacency_dir")) { + enum direction dir; + if (read_direction_value (value, &dir)) { + def->adjacency_dir = dir; + def->has_adjacency_dir = true; + } else { + def->adjacency_dir = DIR_ZERO; + def->has_adjacency_dir = false; + add_key_parse_error (parse_errors, line_number, key, value, "(unrecognized direction)"); + } + + } else if (slice_matches_str (key, "img_path")) { + if (def->img_path != NULL) { + free (def->img_path); + def->img_path = NULL; + } + + struct string_slice unquoted = trim_string_slice (value, 1); + if (unquoted.len == 0) { + def->has_img_path = false; + } else { + char * path_copy = extract_slice (&unquoted); + if (path_copy == NULL) { + def->has_img_path = false; + } else { + def->img_path = path_copy; + def->has_img_path = true; + } + } + + } else if (slice_matches_str (key, "img_row")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_row = ival; + def->has_img_row = true; + } else { + def->has_img_row = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "img_column")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->img_column = ival; + def->has_img_column = true; + } else { + def->has_img_column = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "culture_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->culture_bonus = ival; + def->has_culture_bonus = true; + } else { + def->has_culture_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "science_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->science_bonus = ival; + def->has_science_bonus = true; + } else { + def->has_science_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "food_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->food_bonus = ival; + def->has_food_bonus = true; + } else { + def->has_food_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "gold_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->gold_bonus = ival; + def->has_gold_bonus = true; + } else { + def->has_gold_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "shield_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->shield_bonus = ival; + def->has_shield_bonus = true; + } else { + def->has_shield_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "happiness_bonus")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->happiness_bonus = ival; + def->has_happiness_bonus = true; + } else { + def->has_happiness_bonus = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "impassible")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible = (ival != 0); + def->has_impassible = true; + } else { + def->has_impassible = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else if (slice_matches_str (key, "impassible_to_wheeled")) { + struct string_slice val_slice = *value; + int ival; + if (read_int (&val_slice, &ival)) { + def->impassible_to_wheeled = (ival != 0); + def->has_impassible_to_wheeled = true; + } else { + def->has_impassible_to_wheeled = false; + add_key_parse_error (parse_errors, line_number, key, value, "(expected integer)"); + } + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +void +load_natural_wonder_config_file (char const * file_path, + int path_is_relative_to_mod_dir, + int log_missing, + int drop_existing_configs) +{ + char path[MAX_PATH]; + if (path_is_relative_to_mod_dir) { + if (is->mod_rel_dir == NULL) + return; + snprintf (path, sizeof path, "%s\\%s", is->mod_rel_dir, file_path); + } else { + strncpy (path, file_path, sizeof path); + } + path[(sizeof path) - 1] = '\0'; + + char * text = file_to_string (path); + if (text == NULL) { + if (log_missing) { + char ss[256]; + snprintf (ss, sizeof ss, "[C3X] Natural wonders config file not found: %s", path); + (*p_OutputDebugStringA) (ss); + } + return; + } + + if (drop_existing_configs) + reset_natural_wonder_configs (); + + struct parsed_natural_wonder_definition def; + init_parsed_natural_wonder_definition (&def); + bool in_section = false; + int section_start_line = 0; + int line_number = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + bool has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if ((directive.len > 0) && slice_matches_str (&directive, "Wonder")) { + if (in_section) + finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); + in_section = true; + section_start_line = line_number; + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + enum key_value_parse_status status = parse_trimmed_key_value (&trimmed, &key_slice, &value_slice); + if (status == KVP_NO_EQUALS) { + char * line_text = extract_slice (&trimmed); + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s (expected '=')", line_number, line_text); + err->text[(sizeof err->text) - 1] = '\0'; + free (line_text); + cursor = has_newline ? line_end + 1 : line_end; + continue; + } else if (status == KVP_EMPTY_KEY) { + struct error_line * err = add_error_line (&parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: (missing key)", line_number); + err->text[(sizeof err->text) - 1] = '\0'; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + handle_natural_wonder_definition_key (&def, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) + finalize_parsed_natural_wonder_definition (&def, section_start_line, &parse_errors); + + free_parsed_natural_wonder_definition (&def); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + + if (parse_errors != NULL || unrecognized_keys != NULL) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[200]; + snprintf (s, sizeof s, "Natural Wonder Config errors in %s:", path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, false); + if (parse_errors != NULL) { + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", false); + PopupForm_add_text (popup, __, "Unrecognized keys:", false); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + patch_show_popup (popup, __, 0, 0); + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); + } +} + +void +load_natural_wonder_configs () +{ + char * scenario_filename = "scenario.districts_natural_wonders_config.txt"; + char * scenario_natural_wonder_config_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + if ((scenario_natural_wonder_config_path != NULL) && + (0 != strcmp (scenario_filename, scenario_natural_wonder_config_path)) && + file_exists_at_path (scenario_natural_wonder_config_path)) { + load_natural_wonder_config_file (scenario_natural_wonder_config_path, 0, 0, 1); + return; + } + + if (is->mod_rel_dir != NULL) { + char user_path[MAX_PATH]; + snprintf (user_path, sizeof user_path, "%s\\%s", is->mod_rel_dir, "user.districts_natural_wonders_config.txt"); + user_path[(sizeof user_path) - 1] = '\0'; + if (file_exists_at_path (user_path)) { + load_natural_wonder_config_file ("user.districts_natural_wonders_config.txt", 1, 0, 1); + return; + } + } + + load_natural_wonder_config_file ("default.districts_natural_wonders_config.txt", 1, 1, 1); +} + +bool +district_config_has_dependent_improvement (struct district_config * cfg, char const * name) +{ + if ((cfg == NULL) || (name == NULL) || (name[0] == '\0')) + return false; + + for (int i = 0; i < cfg->dependent_improvement_max_index; i++) { + char const * existing = cfg->dependent_improvements[i]; + if ((existing != NULL) && (strcmp (existing, name) == 0)) + return true; + } + return false; +} + +bool +find_civ_trait_id_by_name (struct string_slice const * name, int * out_id) +{ + if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) + return false; + + struct trait_entry { enum c3x_label label; char const * fallback_name; int id; } traits[] = { + {CL_AGRICULTURAL, "Agricultural", 6}, + {CL_COMMERCIAL, "Commercial", 1}, + {CL_EXPANSIONIST, "Expansionist", 2}, + {CL_INDUSTRIOUS, "Industrious", 5}, + {CL_MILITARISTIC, "Militaristic", 0}, + {CL_RELIGIOUS, "Religious", 4}, + {CL_SCIENTIFIC, "Scientific", 3}, + {CL_SEAFARING, "Seafaring", 7} + }; + + for (int i = 0; i < ARRAY_LEN (traits); i++) { + char const * localized_name = is->c3x_labels[traits[i].label]; + if (((localized_name != NULL) && (localized_name[0] != '\0') && slice_matches_str (name, localized_name)) + || slice_matches_str (name, traits[i].fallback_name)) { + *out_id = traits[i].id; + return true; + } + } + + return false; +} + +bool +find_civ_culture_id_by_name (struct string_slice const * name, int * out_id) +{ + if ((name == NULL) || (name->len <= 0) || (out_id == NULL)) + return false; + + struct culture_entry { char const * name; int id; } cultures[] = { + {"American", 0}, + {"AMERICAN", 0}, + {"AMER", 0}, + {"European", 1}, + {"EUROPEAN", 1}, + {"EURO", 1}, + {"Roman", 2}, + {"ROMAN", 2}, + {"Mid East", 3}, + {"Mideast", 3}, + {"MIDEAST", 3}, + {"Asian", 4}, + {"ASIAN", 4} + }; + + for (int i = 0; i < ARRAY_LEN (cultures); i++) { + if (slice_matches_str (name, cultures[i].name)) { + *out_id = cultures[i].id; + return true; + } + } + + return false; +} + +int +find_district_index_by_name (char const * name) +{ + if ((name == NULL) || (name[0] == '\0')) + return -1; + + for (int i = 0; i < is->district_count; i++) { + char const * existing = is->district_configs[i].name; + if ((existing != NULL) && (strcmp (existing, name) == 0)) + return i; + } + + return -1; +} + +void +resolve_counter_rule_districts (struct error_line ** parse_errors) +{ + struct c3x_config * cfg = &is->current_config; + + for (int i = 0; i < cfg->count_counter_rules; i++) { + struct counter_rule * rule = &cfg->counter_rules[i]; + rule->district_id = -1; + + if ((rule->district_name == NULL) || (rule->district_name[0] == '\0')) + continue; + + int district_id = find_district_index_by_name (rule->district_name); + if (district_id >= 0) { + rule->district_id = district_id; + } else { + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ counter_rule district \"%s\" not found", rule->district_name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } +} + +int +find_wonder_district_index_by_name (char const * name) +{ + if ((name == NULL) || (name[0] == '\0')) + return -1; + + int improv_id; + if (! stable_look_up (&is->building_name_to_id, (char *)name, &improv_id)) + return -1; + + return find_wonder_config_index_by_improvement_id (improv_id); +} + +int +find_natural_wonder_index_by_name (char const * name) +{ + if ((name == NULL) || (name[0] == '\0') || (is == NULL)) + return -1; + + for (int i = 0; i < is->natural_wonder_count; i++) { + char const * existing = is->natural_wonder_configs[i].name; + if ((existing != NULL) && (strcmp (existing, name) == 0)) + return i; + } + return -1; +} + +void +set_wonders_dependent_on_wonder_district (void) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_wonder_districts) + return; + + struct district_config * cfg = &is->district_configs[WONDER_DISTRICT_ID]; + for (int wi = 0; wi < is->wonder_district_count; wi++) { + char const * wonder_name = is->wonder_district_configs[wi].wonder_name; + if ((wonder_name == NULL) || (wonder_name[0] == '\0')) + continue; + if (district_config_has_dependent_improvement (cfg, wonder_name)) + continue; + + int dest = cfg->dependent_improvement_max_index; + if (dest >= ARRAY_LEN (cfg->dependent_improvements)) { + continue; + } + + char * copy = strdup (wonder_name); + if (copy == NULL) { + continue; + } + + cfg->dependent_improvements[dest] = copy; + cfg->dependent_improvement_max_index = dest + 1; + } + + if (! cfg->has_img_column_count_override && + (cfg->img_column_count < cfg->dependent_improvement_max_index + 1)) + cfg->img_column_count = cfg->dependent_improvement_max_index + 1; +} + +void +resolve_district_bonus_building_entries (struct district_bonus_list * list, + char const * district_name, + char const * bonus_name, + struct error_line ** parse_errors) +{ + if (list == NULL) + return; + + for (int i = 0; i < list->count; i++) { + struct district_bonus_entry * entry = &list->entries[i]; + if (entry->type != DBET_BUILDING) + continue; + if ((entry->building_name == NULL) || (entry->building_name[0] == '\0')) { + entry->building_id = -1; + continue; + } + + int improv_id; + struct string_slice improv_name = { .str = (char *)entry->building_name, .len = (int)strlen (entry->building_name) }; + if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { + entry->building_id = improv_id; + stable_insert (&is->building_name_to_id, improv_name.str, improv_id); + } else { + entry->building_id = -1; + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": %s entry \"%.*s\" not found", + district_name, bonus_name, improv_name.len, improv_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } +} + +void parse_building_and_tech_ids () +{ + struct c3x_config * cfg = &is->current_config; + char ss[200]; + struct error_line * district_parse_errors = NULL; + struct error_line * wonder_parse_errors = NULL; + + cfg->great_wall_auto_build_wonder_improv_id = -1; + if (cfg->enable_districts && + cfg->enable_great_wall_districts && + cfg->auto_build_great_wall_around_territory && + cfg->great_wall_auto_build_wonder_name != NULL && + cfg->great_wall_auto_build_wonder_name[0] != '\0') { + struct string_slice wonder_name = { + .str = cfg->great_wall_auto_build_wonder_name, + .len = strlen (cfg->great_wall_auto_build_wonder_name) + }; + if (! find_improv_id_by_name (&wonder_name, &cfg->great_wall_auto_build_wonder_improv_id)) { + snprintf (ss, sizeof ss, + "Error reading config: The value for \"great_wall_auto_build_wonder_name\" is invalid: \"%s\"", + cfg->great_wall_auto_build_wonder_name); + ss[(sizeof ss) - 1] = '\0'; + pop_up_in_game_error (ss); + } + } + + for (int i = 0; i < is->district_count; i++) { + char const * district_name = (is->district_configs[i].name != NULL) ? is->district_configs[i].name : "District"; + if (! district_is_included_by_final_config (i)) { + is->district_infos[i].advance_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) + is->district_infos[i].advance_prereq_ids[j] = -1; + is->district_infos[i].obsoleted_by_id = -1; + is->district_infos[i].resource_prereq_count = 0; + for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) + is->district_infos[i].resource_prereq_ids[j] = -1; + is->district_infos[i].resource_prereq_on_tile_id = -1; + is->district_infos[i].wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) + is->district_infos[i].wonder_prereq_ids[j] = -1; + is->district_infos[i].natural_wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) + is->district_infos[i].natural_wonder_prereq_ids[j] = -1; + is->district_infos[i].dependent_building_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) + is->district_infos[i].dependent_building_ids[j] = -1; + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) + is->district_configs[i].buildable_on_district_ids[j] = -1; + is->district_configs[i].buildable_on_district_id_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) + is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; + is->district_configs[i].buildable_adjacent_to_district_id_count = 0; + is->district_configs[i].generated_resource_id = -1; + continue; + } + if ((is->district_configs[i].name != NULL) && + (is->district_configs[i].command != 0) && + (is->district_configs[i].command != -1)) + itable_insert (&is->command_id_to_district_id, is->district_configs[i].command, i); + is->district_infos[i].advance_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) + is->district_infos[i].advance_prereq_ids[j] = -1; + is->district_infos[i].obsoleted_by_id = -1; + is->district_infos[i].resource_prereq_count = 0; + for (int j = 0; j < MAX_DISTRICT_DEPENDENTS; j++) + is->district_infos[i].resource_prereq_ids[j] = -1; + is->district_infos[i].resource_prereq_on_tile_id = -1; + is->district_infos[i].wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) + is->district_infos[i].wonder_prereq_ids[j] = -1; + is->district_infos[i].natural_wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) + is->district_infos[i].natural_wonder_prereq_ids[j] = -1; + + // Map advance prereqs to districts + int stored_tech_count = 0; + for (int j = 0; j < is->district_configs[i].advance_prereq_count; j++) { + char const * prereq = is->district_configs[i].advance_prereqs[j]; + if (prereq == NULL || prereq[0] == '\0') + continue; + int tech_id; + struct string_slice tech_name = { .str = (char *)prereq, .len = (int)strlen (prereq) }; + if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { + snprintf (ss, sizeof ss, "Found tech prereq \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); + (*p_OutputDebugStringA) (ss); + if (stored_tech_count < ARRAY_LEN (is->district_infos[i].advance_prereq_ids)) { + is->district_infos[i].advance_prereq_ids[stored_tech_count] = tech_id; + stored_tech_count++; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": advance_prereqs entry \"%.*s\" not found", district_name, tech_name.len, tech_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].advance_prereq_count = stored_tech_count; + + // Map obsoleted_by to tech ID + if (is->district_configs[i].obsoleted_by != NULL && is->district_configs[i].obsoleted_by != "") { + int tech_id; + struct string_slice tech_name = { .str = (char *)is->district_configs[i].obsoleted_by, .len = (int)strlen (is->district_configs[i].obsoleted_by) }; + if (find_game_object_id_by_name (GOK_TECHNOLOGY, &tech_name, 0, &tech_id)) { + snprintf (ss, sizeof ss, "Found tech obsoleted_by \"%.*s\" for district \"%s\", ID %d\n", tech_name.len, tech_name.str, district_name, tech_id); + (*p_OutputDebugStringA) (ss); + is->district_infos[i].obsoleted_by_id = tech_id; + } else { + is->district_infos[i].obsoleted_by_id = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": obsoleted_by \"%.*s\" not found", district_name, tech_name.len, tech_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + // Map resource prereqs to districts (multiple resources now supported) + int stored_res_count = 0; + for (int j = 0; j < is->district_configs[i].resource_prereq_count; j++) { + if (is->district_configs[i].resource_prereqs[j] == "" || is->district_configs[i].resource_prereqs[j] == NULL) + continue; + int res_id; + struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereqs[j], .len = (int)strlen (is->district_configs[i].resource_prereqs[j]) }; + if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { + snprintf (ss, sizeof ss, "Found resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); + (*p_OutputDebugStringA) (ss); + if (stored_res_count < ARRAY_LEN (is->district_infos[i].resource_prereq_ids)) { + is->district_infos[i].resource_prereq_ids[stored_res_count] = res_id; + stored_res_count++; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq \"%.*s\" not found", district_name, res_name.len, res_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].resource_prereq_count = stored_res_count; + if (is->district_configs[i].resource_prereq_on_tile != NULL && is->district_configs[i].resource_prereq_on_tile != "") { + int res_id; + struct string_slice res_name = { .str = (char *)is->district_configs[i].resource_prereq_on_tile, .len = (int)strlen (is->district_configs[i].resource_prereq_on_tile) }; + if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { + snprintf (ss, sizeof ss, "Found on-tile resource prereq \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); + (*p_OutputDebugStringA) (ss); + is->district_infos[i].resource_prereq_on_tile_id = res_id; + } else { + is->district_infos[i].resource_prereq_on_tile_id = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": resource_prereq_on_tile \"%.*s\" not found", district_name, res_name.len, res_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + int stored_wonder_count = 0; + for (int j = 0; j < is->district_configs[i].wonder_prereq_count; j++) { + if (is->district_configs[i].wonder_prereqs[j] == "" || is->district_configs[i].wonder_prereqs[j] == NULL) + continue; + int improv_id; + struct string_slice wonder_name = { .str = (char *)is->district_configs[i].wonder_prereqs[j], .len = (int)strlen (is->district_configs[i].wonder_prereqs[j]) }; + if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { + if (stored_wonder_count < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids)) { + is->district_infos[i].wonder_prereq_ids[stored_wonder_count] = improv_id; + stored_wonder_count += 1; + } + stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": wonder_prereqs entry \"%.*s\" not found", district_name, wonder_name.len, wonder_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].wonder_prereq_count = stored_wonder_count; + + int stored_natural_wonder_count = 0; + for (int j = 0; j < is->district_configs[i].natural_wonder_prereq_count; j++) { + if (is->district_configs[i].natural_wonder_prereqs[j] == "" || is->district_configs[i].natural_wonder_prereqs[j] == NULL) + continue; + int natural_wonder_id = -1; + char const * name = is->district_configs[i].natural_wonder_prereqs[j]; + if (stable_look_up (&is->natural_wonder_name_to_id, (char *)name, &natural_wonder_id)) { + if (stored_natural_wonder_count < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids)) { + is->district_infos[i].natural_wonder_prereq_ids[stored_natural_wonder_count] = natural_wonder_id; + stored_natural_wonder_count += 1; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": natural_wonder_prereqs entry \"%s\" not found", district_name, name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_infos[i].natural_wonder_prereq_count = stored_natural_wonder_count; + + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids); j++) + is->district_configs[i].buildable_on_district_ids[j] = -1; + is->district_configs[i].buildable_on_district_id_count = 0; + + if (is->district_configs[i].has_buildable_on_districts) { + int stored_buildable_on_count = 0; + for (int j = 0; j < is->district_configs[i].buildable_on_district_count; j++) { + char const * name = is->district_configs[i].buildable_on_districts[j]; + if (name == NULL || name[0] == '\0') + continue; + int other_district_id = find_district_index_by_name (name); + if (other_district_id >= 0) { + if (stored_buildable_on_count < ARRAY_LEN (is->district_configs[i].buildable_on_district_ids)) { + is->district_configs[i].buildable_on_district_ids[stored_buildable_on_count] = other_district_id; + stored_buildable_on_count += 1; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_on_districts entry \"%s\" not found", district_name, name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_configs[i].buildable_on_district_id_count = stored_buildable_on_count; + } + + for (int j = 0; j < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids); j++) + is->district_configs[i].buildable_adjacent_to_district_ids[j] = -1; + is->district_configs[i].buildable_adjacent_to_district_id_count = 0; + + if (is->district_configs[i].has_buildable_adjacent_to_districts) { + int stored_adjacent_count = 0; + for (int j = 0; j < is->district_configs[i].buildable_adjacent_to_district_count; j++) { + char const * name = is->district_configs[i].buildable_adjacent_to_districts[j]; + if (name == NULL || name[0] == '\0') + continue; + int other_district_id = find_district_index_by_name (name); + if (other_district_id >= 0) { + if (stored_adjacent_count < ARRAY_LEN (is->district_configs[i].buildable_adjacent_to_district_ids)) { + is->district_configs[i].buildable_adjacent_to_district_ids[stored_adjacent_count] = other_district_id; + stored_adjacent_count += 1; + } + } else { + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": buildable_adjacent_to_districts entry \"%s\" not found", district_name, name); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + is->district_configs[i].buildable_adjacent_to_district_id_count = stored_adjacent_count; + } + + // Resolve generated resource name to ID + if (is->district_configs[i].generated_resource != NULL && is->district_configs[i].generated_resource != "") { + int res_id; + struct string_slice res_name = { .str = (char *)is->district_configs[i].generated_resource, .len = (int)strlen (is->district_configs[i].generated_resource) }; + if (find_game_object_id_by_name (GOK_RESOURCE, &res_name, 0, &res_id)) { + snprintf (ss, sizeof ss, "Found generated resource \"%.*s\" for district \"%s\", ID %d\n", res_name.len, res_name.str, district_name, res_id); + (*p_OutputDebugStringA) (ss); + is->district_configs[i].generated_resource_id = res_id; + } else { + is->district_configs[i].generated_resource_id = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": generated_resource \"%.*s\" not found", district_name, res_name.len, res_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + // Map improvement prereqs to districts + int stored_count = 0; + for (int j = 0; j < is->district_configs[i].dependent_improvement_max_index; j++) { + int improv_id; + if (is->district_configs[i].dependent_improvements[j] == "" || is->district_configs[i].dependent_improvements[j] == NULL) + continue; + + // Gate wonder district prereqs behind enable_wonder_districts + if ((is->district_configs[i].command == UCV_Build_WonderDistrict) && (! cfg->enable_wonder_districts)) + continue; + + struct string_slice improv_name = { .str = (char *)is->district_configs[i].dependent_improvements[j], .len = (int)strlen (is->district_configs[i].dependent_improvements[j]) }; + if (find_game_object_id_by_name (GOK_BUILDING, &improv_name, 0, &improv_id)) { + snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for district \"%s\", ID %d\n", improv_name.len, improv_name.str, district_name, improv_id); + (*p_OutputDebugStringA) (ss); + if (stored_count < ARRAY_LEN (is->district_infos[i].dependent_building_ids)) { + is->district_infos[i].dependent_building_ids[stored_count] = improv_id; + stored_count += 1; + } + add_district_building_prereq (improv_id, i); + stable_insert (&is->building_name_to_id, improv_name.str, improv_id); + } else { + is->district_infos[i].dependent_building_ids[j] = -1; + struct error_line * err = add_error_line (&district_parse_errors); + snprintf (err->text, sizeof err->text, "^ District \"%s\": dependent_improvs entry \"%.*s\" not found", district_name, improv_name.len, improv_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + is->district_infos[i].dependent_building_count = stored_count; + } + + resolve_district_bonus_building_entries (&is->district_configs[i].culture_bonus_extras, district_name, "culture_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].science_bonus_extras, district_name, "science_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].food_bonus_extras, district_name, "food_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].gold_bonus_extras, district_name, "gold_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].shield_bonus_extras, district_name, "shield_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].happiness_bonus_extras, district_name, "happiness_bonus", &district_parse_errors); + resolve_district_bonus_building_entries (&is->district_configs[i].defense_bonus_extras, district_name, "defense_bonus_percent", &district_parse_errors); + } + + resolve_counter_rule_districts (&district_parse_errors); + + // Map wonder names to their improvement IDs for rendering under-construction wonders + for (int wi = 0; wi < is->wonder_district_count; wi++) { + if (is->wonder_district_configs[wi].wonder_name == NULL || is->wonder_district_configs[wi].wonder_name[0] == '\0') + continue; + + int improv_id; + struct string_slice wonder_name = { .str = (char *)is->wonder_district_configs[wi].wonder_name, .len = (int)strlen (is->wonder_district_configs[wi].wonder_name) }; + if (find_game_object_id_by_name (GOK_BUILDING, &wonder_name, 0, &improv_id)) { + snprintf (ss, sizeof ss, "Found improvement prereq \"%.*s\" for wonder district \"%s\", ID %d\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name, improv_id); + (*p_OutputDebugStringA) (ss); + stable_insert (&is->building_name_to_id, wonder_name.str, improv_id); + } else { + snprintf (ss, sizeof ss, "Could not find improvement prereq \"%.*s\" for wonder district \"%s\"\n", wonder_name.len, wonder_name.str, is->wonder_district_configs[wi].wonder_name); + (*p_OutputDebugStringA) (ss); + struct error_line * err = add_error_line (&wonder_parse_errors); + snprintf (err->text, sizeof err->text, "^ Wonder district \"%s\": improvement \"%.*s\" not found", (is->wonder_district_configs[wi].wonder_name != NULL) ? is->wonder_district_configs[wi].wonder_name : "Wonder District", wonder_name.len, wonder_name.str); + err->text[(sizeof err->text) - 1] = '\0'; + } + } + + if ((district_parse_errors != NULL) || (wonder_parse_errors != NULL)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + + if (district_parse_errors != NULL) { + char header[256]; + if (is->current_districts_config_path[0] != '\0') + snprintf (header, sizeof header, "District Config errors in %s:", is->current_districts_config_path); + else + snprintf (header, sizeof header, "District Config lookup errors:"); + header[(sizeof header) - 1] = '\0'; + PopupForm_add_text (popup, __, header, false); + for (struct error_line * line = district_parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + + if ((district_parse_errors != NULL) && (wonder_parse_errors != NULL)) + PopupForm_add_text (popup, __, "", false); + + if (wonder_parse_errors != NULL) { + char header[256]; + snprintf (header, sizeof header, "Wonder District Config lookup errors:"); + header[(sizeof header) - 1] = '\0'; + PopupForm_add_text (popup, __, header, false); + for (struct error_line * line = wonder_parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, false); + } + + patch_show_popup (popup, __, 0, 0); + free_error_lines (district_parse_errors); + free_error_lines (wonder_parse_errors); + } +} + +void +load_districts_config () +{ + clear_dynamic_district_definitions (); + load_dynamic_district_configs (); + load_dynamic_wonder_configs (); + load_natural_wonder_configs (); + is->district_count = is->special_district_count + is->dynamic_district_count; + + set_wonders_dependent_on_wonder_district (); + parse_building_and_tech_ids (); +} + +void +place_natural_wonders_on_map (void) +{ + if (! is->current_config.enable_natural_wonders) + return; + + int wonder_count = is->natural_wonder_count; + if (wonder_count <= 0) + return; + + struct natural_wonder_candidate_list * candidate_lists = (struct natural_wonder_candidate_list *)calloc (wonder_count, sizeof *candidate_lists); + bool * already_placed = (bool *)calloc (wonder_count, sizeof *already_placed); + + if ((candidate_lists == NULL) || (already_placed == NULL)) { + if (candidate_lists != NULL) free (candidate_lists); + if (already_placed != NULL) free (already_placed); + return; + } + + struct wonder_location * placements = NULL; + int placement_count = 0; + int placement_capacity = 0; + int existing_count = 0; + + // Record existing natural wonders + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + + int wonder_id = inst->natural_wonder_info.natural_wonder_id; + if ((wonder_id < 0) || (wonder_id >= wonder_count)) + continue; + + already_placed[wonder_id] = true; + + Tile * tile = (Tile *)tei.key; + int tile_x, tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + continue; + + if (placement_count >= placement_capacity) { + int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; + struct wonder_location * grown = + (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); + if (grown == NULL) + continue; + placements = grown; + placement_capacity = new_capacity; + } + + if (placements != NULL) { + placements[placement_count++] = (struct wonder_location){ + .x = (short)tile_x, + .y = (short)tile_y + }; + existing_count += 1; + } + } + + // Build candidate lists + int map_width = p_bic_data->Map.Width; + int map_height = p_bic_data->Map.Height; + int minimum_separation = is->current_config.minimum_natural_wonder_separation; + + for (int y = 0; y < map_height; y++) { + for (int x = 0; x < map_width; x++) { + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + if (! natural_wonder_tile_is_clear (tile, x, y)) continue; + if (district_exists_within_distance (x, y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; + + for (int ni = 0; ni < wonder_count; ni++) { + if (already_placed[ni]) + continue; + + struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; + if (cfg->name == NULL) + continue; + + if (! natural_wonder_terrain_matches (cfg, tile, x, y)) + continue; + + natural_wonder_candidate_list_push (&candidate_lists[ni], tile, x, y); + } + } + } + + bool wraps_horiz = (p_bic_data->Map.Flags & 1) != 0; + int newly_placed = 0; + int * wonder_order = (int *)malloc (wonder_count * sizeof *wonder_order); + if (wonder_order != NULL) { + for (int i = 0; i < wonder_count; i++) + wonder_order[i] = i; + for (int i = wonder_count - 1; i > 0; i--) { + int swap_index = rand_int (p_rand_object, __, i + 1); + int temp = wonder_order[i]; + wonder_order[i] = wonder_order[swap_index]; + wonder_order[swap_index] = temp; + } + } + + for (int order_index = 0; order_index < wonder_count; order_index++) { + int ni = (wonder_order != NULL) ? wonder_order[order_index] : order_index; + if (already_placed[ni]) + continue; + + struct natural_wonder_candidate_list * list = &candidate_lists[ni]; + if (list->count == 0) { + char msg[256]; + snprintf (msg, sizeof msg, "[C3X] No valid tiles to place natural wonder \"%s\".\n", + (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); + (*p_OutputDebugStringA) (msg); + continue; + } + + int best_index = -1; + int best_dist = -1; + int best_adjacent_count = -1; + int best_target_diff = INT_MAX; + int best_rand = INT_MAX; + int best_same_type_count = -1; + int best_continent_priority = INT_MAX; + int target_x = (wonder_count > 0) + ? (int)(((long long)(2 * ni + 1) * map_width) / (2 * wonder_count)) + : (map_width >> 1); + + for (int ci = 0; ci < list->count; ci++) { + struct natural_wonder_candidate * cand = &list->entries[ci]; + Tile * tile = cand->tile; + if ((tile == NULL) || (tile == p_null_tile)) continue; + if (get_district_instance (tile) != NULL) continue; + if (! natural_wonder_tile_is_clear (tile, cand->x, cand->y)) continue; + if (! natural_wonder_terrain_matches (&is->natural_wonder_configs[ni], tile, cand->x, cand->y)) continue; + if (district_exists_within_distance (cand->x, cand->y, NATURAL_WONDER_DISTRICT_ID, -1, minimum_separation)) continue; + + int min_dist_sq = natural_wonder_min_distance_sq (cand->x, cand->y, placements, placement_count); + if (min_dist_sq == INT_MAX) { + int span = (map_width * map_width) + (map_height * map_height); + if (span <= 0) + span = INT_MAX; + min_dist_sq = span; + } + + int dx_raw = int_abs (cand->x - target_x); + int dx_adjusted = compute_wrapped_component (dx_raw, map_width, wraps_horiz); + int rand_val = rand_int (p_rand_object, __, 0x7FFF); + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + int continent_priority = 1; + if ((continent_id >= 0) && ! continent_has_natural_wonder (continent_id, placements, placement_count)) + continent_priority = 0; + + bool adjacency_bonus_active = + (is->natural_wonder_configs[ni].adjacent_to != (enum SquareTypes)SQ_INVALID) && + (is->natural_wonder_configs[ni].adjacency_dir == DIR_ZERO); + int adjacency_count = -1; + if (adjacency_bonus_active) + adjacency_count = count_adjacent_tiles_of_type (cand->x, cand->y, + is->natural_wonder_configs[ni].adjacent_to); + + int same_type_count = count_adjacent_tiles_of_type (cand->x, cand->y, + is->natural_wonder_configs[ni].terrain_type); + + bool better = false; + if (continent_priority < best_continent_priority) + better = true; + else if (continent_priority > best_continent_priority) + continue; + + if (! better && adjacency_bonus_active) { + if (adjacency_count > best_adjacent_count) + better = true; + else if (adjacency_count < best_adjacent_count) + continue; + } + + if (! better) { + if (same_type_count > best_same_type_count) + better = true; + else if (same_type_count < best_same_type_count) + continue; + } + + if (! better) { + if ((min_dist_sq > best_dist) || + ((min_dist_sq == best_dist) && (dx_adjusted < best_target_diff)) || + ((min_dist_sq == best_dist) && (dx_adjusted == best_target_diff) && (rand_val < best_rand))) + better = true; + else + continue; + } + + best_dist = min_dist_sq; + best_target_diff = dx_adjusted; + best_rand = rand_val; + best_index = ci; + best_continent_priority = continent_priority; + if (adjacency_bonus_active) + best_adjacent_count = adjacency_count; + best_same_type_count = same_type_count; + } + + if (best_index < 0) { + char msg[256]; + snprintf (msg, sizeof msg, "[C3X] Could not find a suitable tile for natural wonder \"%s\" after filtering.\n", + (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder"); + (*p_OutputDebugStringA) (msg); + continue; + } + + struct natural_wonder_candidate * chosen = &list->entries[best_index]; + assign_natural_wonder_to_tile (chosen->tile, chosen->x, chosen->y, ni); + + if (placement_count >= placement_capacity) { + int new_capacity = (placement_capacity > 0) ? placement_capacity * 2 : 8; + struct wonder_location * grown = + (struct wonder_location *)realloc (placements, new_capacity * sizeof *grown); + if (grown != NULL) { + placements = grown; + placement_capacity = new_capacity; + } + } + + if ((placements != NULL) && (placement_count < placement_capacity)) { + placements[placement_count++] = (struct wonder_location){ + .x = chosen->x, + .y = chosen->y + }; + } + + newly_placed += 1; + + char msg[256]; + snprintf (msg, sizeof msg, "[C3X] Placed natural wonder \"%s\" at (%d,%d).\n", + (is->natural_wonder_configs[ni].name != NULL) ? is->natural_wonder_configs[ni].name : "Natural Wonder", + chosen->x, chosen->y); + (*p_OutputDebugStringA) (msg); + } + + char summary[256]; + snprintf (summary, sizeof summary, "[C3X] Natural wonder placement complete. Newly placed: %d, already present: %d.\n", + newly_placed, existing_count); + (*p_OutputDebugStringA) (summary); + + for (int ni = 0; ni < wonder_count; ni++) + free (candidate_lists[ni].entries); + free (wonder_order); + free (candidate_lists); + free (already_placed); + free (placements); +} + +void +init_scenario_district_entry (struct scenario_district_entry * entry) +{ + if (entry == NULL) + return; + + memset (entry, 0, sizeof *entry); +} + +void +init_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) +{ + if (entry == NULL) + return; + + memset (entry, 0, sizeof *entry); +} + +void +free_scenario_district_entry (struct scenario_district_entry * entry) +{ + if (entry == NULL) + return; + + if (entry->district_name != NULL) { + free (entry->district_name); + entry->district_name = NULL; + } + if (entry->wonder_city_name != NULL) { + free (entry->wonder_city_name); + entry->wonder_city_name = NULL; + } + if (entry->wonder_name != NULL) { + free (entry->wonder_name); + entry->wonder_name = NULL; + } + entry->has_coordinates = 0; + entry->has_district_name = 0; + entry->has_wonder_city = 0; + entry->has_wonder_name = 0; +} + +void +free_scenario_named_tile_entry (struct scenario_named_tile_entry * entry) +{ + if (entry == NULL) + return; + + if (entry->name != NULL) { + free (entry->name); + entry->name = NULL; + } + entry->has_coordinates = 0; + entry->has_name = 0; +} + +void +add_scenario_district_error (struct error_line ** parse_errors, + int line_number, + char const * message) +{ + if (message == NULL) + return; + + struct error_line * err = add_error_line (parse_errors); + snprintf (err->text, sizeof err->text, "^ Line %d: %s", line_number, message); + err->text[(sizeof err->text) - 1] = '\0'; +} + +int +parse_scenario_district_coordinates (struct string_slice const * value, int * out_x, int * out_y) +{ + if ((value == NULL) || (out_x == NULL) || (out_y == NULL)) + return 0; + + char * text = trim_and_extract_slice (value, 0); + if (text == NULL) + return 0; + + char * cursor = text; + int success = 0; + int x, y; + if (parse_int (&cursor, &x) && + skip_punctuation (&cursor, ',') && + parse_int (&cursor, &y)) { + skip_horiz_space (&cursor); + success = (*cursor == '\0'); + if (success) { + *out_x = x; + *out_y = y; + } + } + + free (text); + return success; +} + +int +finalize_scenario_district_entry (struct scenario_district_entry * entry, + int section_start_line, + struct error_line ** parse_errors) +{ + int success = 1; + if ((entry == NULL) || (parse_errors == NULL)) + return 0; + + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return 1; + } + + if (! entry->has_coordinates) + add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); + if ((! entry->has_district_name) || (entry->district_name == NULL) || (entry->district_name[0] == '\0')) + add_scenario_district_error (parse_errors, section_start_line, "district (value is required)"); + + if ((! entry->has_coordinates) || (! entry->has_district_name) || + (entry->district_name == NULL) || (entry->district_name[0] == '\0')) + success = 0; + + int map_x = entry->tile_x; + int map_y = entry->tile_y; + if (success) { + wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); + Tile * tile = tile_at (map_x, map_y); + if ((tile == NULL) || (tile == p_null_tile)) { + add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); + success = 0; + } else { + int district_id = find_district_index_by_name (entry->district_name); + if ((district_id < 0) || (district_id >= is->district_count)) { + char msg[200]; + snprintf (msg, sizeof msg, "district (unrecognized name: \"%s\")", entry->district_name); + add_scenario_district_error (parse_errors, section_start_line, msg); + success = 0; + } else { + if ((district_id == NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_natural_wonders) { + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return 1; + } + if ((district_id != NATURAL_WONDER_DISTRICT_ID) && ! is->current_config.enable_districts) { + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return 1; + } + struct district_instance * inst = ensure_district_instance (tile, district_id, map_x, map_y); + if (inst == NULL) { + add_scenario_district_error (parse_errors, section_start_line, "Failed to create district instance"); + success = 0; + } else { + inst->district_id = district_id; + district_instance_set_coords (inst, map_x, map_y); + inst->state = DS_COMPLETED; + inst->wonder_info.state = WDS_UNUSED; + inst->wonder_info.city = NULL; + inst->wonder_info.city_id = -1; + inst->wonder_info.wonder_index = -1; + inst->natural_wonder_info.natural_wonder_id = -1; + + if (district_id == WONDER_DISTRICT_ID) { + int has_city = entry->has_wonder_city && + (entry->wonder_city_name != NULL) && (entry->wonder_city_name[0] != '\0'); + int has_wonder = entry->has_wonder_name && + (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); + if (! has_city || ! has_wonder) { + add_scenario_district_error (parse_errors, section_start_line, "Wonder district requires both wonder_city and wonder_name"); + success = 0; + } else { + int wonder_index = find_wonder_district_index_by_name (entry->wonder_name); + if (wonder_index < 0) { + char msg[200]; + snprintf (msg, sizeof msg, "wonder_name (unrecognized wonder: \"%s\")", entry->wonder_name); + add_scenario_district_error (parse_errors, section_start_line, msg); + success = 0; + } else { + inst->wonder_info.city = NULL; + inst->wonder_info.city_id = -1; + inst->wonder_info.state = WDS_COMPLETED; + inst->wonder_info.wonder_index = wonder_index; + } + } + } else if (district_id == NATURAL_WONDER_DISTRICT_ID) { + int has_name = entry->has_wonder_name && + (entry->wonder_name != NULL) && (entry->wonder_name[0] != '\0'); + if (! has_name) { + add_scenario_district_error (parse_errors, section_start_line, "Natural Wonder district requires wonder_name"); + success = 0; + } else { + int natural_index = find_natural_wonder_index_by_name (entry->wonder_name); + if (natural_index < 0) { + char msg[200]; + snprintf (msg, sizeof msg, "wonder_name (unrecognized natural wonder: \"%s\")", entry->wonder_name); + add_scenario_district_error (parse_errors, section_start_line, msg); + success = 0; + } else + inst->natural_wonder_info.natural_wonder_id = natural_index; + } + if (entry->has_wonder_city) + add_scenario_district_error (parse_errors, section_start_line, "wonder_city ignored for Natural Wonder district entries"); + } else if (entry->has_wonder_city || entry->has_wonder_name) { + add_scenario_district_error (parse_errors, section_start_line, "wonder_* fields only valid for Wonder or Natural Wonder district entries"); + } + + if (success) { + if (district_id != NATURAL_WONDER_DISTRICT_ID && !tile->vtable->m18_Check_Mines (tile, __, 0)) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, map_x, map_y); + set_tile_unworkable_for_all_cities (tile, map_x, map_y); + } + } + } + } + } + + free_scenario_district_entry (entry); + init_scenario_district_entry (entry); + return success; +} + +bool +tile_can_be_named (Tile * tile, int tile_x, int tile_y) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) + return false; + return true; +} + +void +remove_named_tile_entry (Tile * tile) +{ + struct named_tile_entry * entry = get_named_tile_entry (tile); + if (entry == NULL) + return; + itable_remove (&is->named_tile_map, (int)tile); + free (entry); +} + +void +set_named_tile_entry (Tile * tile, int tile_x, int tile_y, char const * name) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return; + if ((name == NULL) || (name[0] == '\0')) { + remove_named_tile_entry (tile); + return; + } + + struct named_tile_entry * entry = get_named_tile_entry (tile); + if (entry == NULL) { + entry = calloc (1, sizeof *entry); + if (entry == NULL) + return; + itable_insert (&is->named_tile_map, (int)tile, (int)entry); + } + entry->tile_x = tile_x; + entry->tile_y = tile_y; + strncpy (entry->name, name, sizeof entry->name); + entry->name[(sizeof entry->name) - 1] = '\0'; +} + +int +finalize_scenario_named_tile_entry (struct scenario_named_tile_entry * entry, + int section_start_line, + struct error_line ** parse_errors) +{ + int success = 1; + if ((entry == NULL) || (parse_errors == NULL)) + return 0; + + if (! is->current_config.enable_named_tiles) { + free_scenario_named_tile_entry (entry); + init_scenario_named_tile_entry (entry); + return 1; + } + + if (! entry->has_coordinates) + add_scenario_district_error (parse_errors, section_start_line, "coordinates (value is required)"); + if ((! entry->has_name) || (entry->name == NULL) || (entry->name[0] == '\0')) + add_scenario_district_error (parse_errors, section_start_line, "name (value is required)"); + + if ((! entry->has_coordinates) || (! entry->has_name) || + (entry->name == NULL) || (entry->name[0] == '\0')) + success = 0; + + int map_x = entry->tile_x; + int map_y = entry->tile_y; + if (success) { + wrap_tile_coords (&p_bic_data->Map, &map_x, &map_y); + Tile * tile = tile_at (map_x, map_y); + if ((tile == NULL) || (tile == p_null_tile)) { + add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile not found)"); + success = 0; + } else if (! tile_can_be_named (tile, map_x, map_y)) { + add_scenario_district_error (parse_errors, section_start_line, "Invalid coordinates (tile cannot be named)"); + success = 0; + } else { + set_named_tile_entry (tile, map_x, map_y, entry->name); + } + } + + free_scenario_named_tile_entry (entry); + init_scenario_named_tile_entry (entry); + return success; +} + +void +handle_scenario_district_key (struct scenario_district_entry * entry, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if ((entry == NULL) || (key == NULL) || (value == NULL)) + return; + + if (slice_matches_str (key, "coordinates")) { + int x, y; + if (parse_scenario_district_coordinates (value, &x, &y)) { + entry->tile_x = x; + entry->tile_y = y; + entry->has_coordinates = 1; + } else + add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); + + } else if (slice_matches_str (key, "district")) { + if (entry->district_name != NULL) { + free (entry->district_name); + entry->district_name = NULL; + } + entry->district_name = copy_trimmed_string_or_null (value, 1); + entry->has_district_name = (entry->district_name != NULL); + if (! entry->has_district_name) + add_scenario_district_error (parse_errors, line_number, "district (value is required)"); + + } else if (slice_matches_str (key, "wonder_city")) { + if (entry->wonder_city_name != NULL) { + free (entry->wonder_city_name); + entry->wonder_city_name = NULL; + } + entry->wonder_city_name = copy_trimmed_string_or_null (value, 1); + entry->has_wonder_city = (entry->wonder_city_name != NULL); + + } else if (slice_matches_str (key, "wonder_name")) { + if (entry->wonder_name != NULL) { + free (entry->wonder_name); + entry->wonder_name = NULL; + } + entry->wonder_name = copy_trimmed_string_or_null (value, 1); + entry->has_wonder_name = (entry->wonder_name != NULL); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +void +handle_scenario_named_tile_key (struct scenario_named_tile_entry * entry, + struct string_slice const * key, + struct string_slice const * value, + int line_number, + struct error_line ** parse_errors, + struct error_line ** unrecognized_keys) +{ + if ((entry == NULL) || (key == NULL) || (value == NULL)) + return; + + if (slice_matches_str (key, "coordinates")) { + int x, y; + if (parse_scenario_district_coordinates (value, &x, &y)) { + entry->tile_x = x; + entry->tile_y = y; + entry->has_coordinates = 1; + } else + add_scenario_district_error (parse_errors, line_number, "coordinates (expected format: x,y)"); + + } else if (slice_matches_str (key, "name")) { + if (entry->name != NULL) { + free (entry->name); + entry->name = NULL; + } + entry->name = copy_trimmed_string_or_null (value, 1); + entry->has_name = (entry->name != NULL); + if (! entry->has_name) + add_scenario_district_error (parse_errors, line_number, "name (value is required)"); + + } else + add_unrecognized_key_error (unrecognized_keys, line_number, key); +} + +// Parses a .c3x.txt file corresponding to the given scenario file path, loading district instances as specified. +// +// The expected file format itself is very simple. Example: +// +// ``` +// DISTRICTS +// +// #District +// coordinates = 12,28 +// district = Entertainment Complex +// +// #District +// coordinates = 9,23 +// district = Wonder District +// wonder_city = Rome +// wonder_name = The Pyramids +// +// #District +// coordinates = 10,30 +// district = Natural Wonder +// wonder_name = Mount Everest +// +// #NamedTile +// coordinates = 41,23 +// name = Tiber River +// ``` +// +// Details at https://github.com/instafluff0/Civ3_Editor_Fork_for_C3X_Districts +void +load_scenario_districts_from_file () +{ + char * scenario_filename = "scenario.districts.txt"; + char * scenario_districts_path = BIC_get_asset_path (p_bic_data, __, scenario_filename, false); + + // BIC_get_asset_path returns the file name when it can't find the file + if ((scenario_districts_path == NULL) || (0 == strcmp (scenario_filename, scenario_districts_path))) + return; + + char * text = file_to_string (scenario_districts_path); + if (text == NULL) + return; + + struct scenario_district_entry entry; + struct scenario_named_tile_entry named_entry; + init_scenario_district_entry (&entry); + init_scenario_named_tile_entry (&named_entry); + int in_section = 0; + int section_start_line = 0; + int section_type = 0; + int line_number = 0; + int header_seen = 0; + struct error_line * unrecognized_keys = NULL; + struct error_line * parse_errors = NULL; + + char * cursor = text; + while (*cursor != '\0') { + line_number += 1; + + char * line_start = cursor; + char * line_end = cursor; + while ((*line_end != '\0') && (*line_end != '\n')) + line_end++; + + int line_len = line_end - line_start; + int has_newline = (*line_end == '\n'); + if (has_newline) + *line_end = '\0'; + + struct string_slice line_slice = { .str = line_start, .len = line_len }; + struct string_slice trimmed = trim_string_slice (&line_slice, 0); + if (line_is_empty_or_comment (&trimmed)) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + // Keep support for legacy header, technically not needed + if (! header_seen) { + if (slice_matches_str (&trimmed, "DISTRICTS")) { + header_seen = 1; + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + } + + if (trimmed.str[0] == '#') { + struct string_slice directive = trimmed; + directive.str += 1; + directive.len -= 1; + directive = trim_string_slice (&directive, 0); + if (slice_matches_str (&directive, "District")) { + if (in_section) { + if (section_type == 1) + finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); + else if (section_type == 2) + finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); + } + in_section = 1; + section_type = 1; + section_start_line = line_number; + free_scenario_district_entry (&entry); + init_scenario_district_entry (&entry); + } else if (slice_matches_str (&directive, "NamedTile")) { + if (in_section) { + if (section_type == 1) + finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); + else if (section_type == 2) + finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); + } + in_section = 1; + section_type = 2; + section_start_line = line_number; + free_scenario_named_tile_entry (&named_entry); + init_scenario_named_tile_entry (&named_entry); + } + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + if (! in_section) { + cursor = has_newline ? line_end + 1 : line_end; + continue; + } + + struct string_slice key_slice = {0}; + struct string_slice value_slice = {0}; + switch (parse_trimmed_key_value (&trimmed, &key_slice, &value_slice)) { + case KVP_NO_EQUALS: + add_scenario_district_error (&parse_errors, line_number, "(expected '=')"); + break; + case KVP_EMPTY_KEY: + add_scenario_district_error (&parse_errors, line_number, "(missing key)"); + break; + case KVP_SUCCESS: + if (section_type == 1) + handle_scenario_district_key (&entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + else if (section_type == 2) + handle_scenario_named_tile_key (&named_entry, &key_slice, &value_slice, line_number, &parse_errors, &unrecognized_keys); + break; + } + + cursor = has_newline ? line_end + 1 : line_end; + } + + if (in_section) { + if (section_type == 1) + finalize_scenario_district_entry (&entry, section_start_line, &parse_errors); + else if (section_type == 2) + finalize_scenario_named_tile_entry (&named_entry, section_start_line, &parse_errors); + } + + free_scenario_district_entry (&entry); + free_scenario_named_tile_entry (&named_entry); + free (text); + + // Append to loaded config names list + struct loaded_config_name * top_lcn = is->loaded_config_names; + while (top_lcn->next != NULL) + top_lcn = top_lcn->next; + + struct loaded_config_name * new_lcn = malloc (sizeof *new_lcn); + new_lcn->name = strdup (scenario_districts_path); + new_lcn->next = NULL; + + top_lcn->next = new_lcn; + + if ((parse_errors != NULL) || (unrecognized_keys != NULL)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char header[256]; + snprintf (header, sizeof header, "District scenario file issues in %s:", scenario_districts_path); + header[(sizeof header) - 1] = '\0'; + PopupForm_add_text (popup, __, header, 0); + if (parse_errors != NULL) + for (struct error_line * line = parse_errors; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, 0); + if (unrecognized_keys != NULL) { + PopupForm_add_text (popup, __, "", 0); + PopupForm_add_text (popup, __, "Unrecognized keys:", 0); + for (struct error_line * line = unrecognized_keys; line != NULL; line = line->next) + PopupForm_add_text (popup, __, line->text, 0); + } + patch_show_popup (popup, __, 0, 0); + } + + free_error_lines (parse_errors); + free_error_lines (unrecognized_keys); +} + +void +deinit_district_images (void) +{ + if (is->dc_img_state == IS_OK) { + for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) { + for (int variant = 0; variant < ARRAY_LEN (is->district_img_sets[dc].imgs); variant++) + for (int era = 0; era < 4; era++) + for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc].imgs[variant][era]); col++) { + Sprite * sprite = &is->district_img_sets[dc].imgs[variant][era][col]; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + } + + for (int wi = 0; wi < MAX_WONDER_DISTRICT_TYPES; wi++) { + struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; + if (set->img.vtable != NULL) + set->img.vtable->destruct (&set->img, __, 0); + if (set->construct_img.vtable != NULL) + set->construct_img.vtable->destruct (&set->construct_img, __, 0); + if (set->alt_dir_img.vtable != NULL) + set->alt_dir_img.vtable->destruct (&set->alt_dir_img, __, 0); + if (set->alt_dir_construct_img.vtable != NULL) + set->alt_dir_construct_img.vtable->destruct (&set->alt_dir_construct_img, __, 0); + } + + for (int ni = 0; ni < MAX_NATURAL_WONDER_DISTRICT_TYPES; ni++) { + Sprite * sprite = &is->natural_wonder_img_sets[ni].img; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + + if (is->abandoned_district_img.vtable != NULL) + is->abandoned_district_img.vtable->destruct (&is->abandoned_district_img, __, 0); + if (is->abandoned_maritime_district_img.vtable != NULL) + is->abandoned_maritime_district_img.vtable->destruct (&is->abandoned_maritime_district_img, __, 0); + } + + is->dc_img_state = IS_UNINITED; +} + +void +clear_highlighted_worker_tiles_for_districts () +{ + FOR_TABLE_ENTRIES (tei, &is->highlighted_city_radius_tile_pointers) { + struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)tei.value; + if (info != NULL) + free (info); + } + table_deinit (&is->highlighted_city_radius_tile_pointers); +} + + +void +reset_district_state (bool reset_tile_map) +{ + clear_all_tracked_workers (); + deinit_district_images (); + deinit_district_command_buttons (); + clear_highlighted_worker_tiles_for_districts (); + + FOR_TABLE_ENTRIES (tei, &is->district_building_prereqs) { + struct district_building_prereq_list * list = (struct district_building_prereq_list *)tei.value; + if (list != NULL) + free (list); + } + table_deinit (&is->district_building_prereqs); + table_deinit (&is->command_id_to_district_id); + stable_deinit (&is->building_name_to_id); + if (reset_tile_map) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst != NULL) + free (inst); + } + table_deinit (&is->district_tile_map); + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if (entry != NULL) + free (entry); + } + table_deinit (&is->named_tile_map); + } + + clear_distribution_hub_tables (); + + is->distribution_hub_totals_dirty = true; + + clear_dynamic_district_definitions (); + is->district_count = is->special_district_count; + + for (int i = 0; i < COUNT_DISTRICT_TYPES; i++) { + is->district_infos[i].advance_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].advance_prereq_ids); j++) + is->district_infos[i].advance_prereq_ids[j] = -1; + is->district_infos[i].obsoleted_by_id = -1; + is->district_infos[i].resource_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].resource_prereq_ids); j++) + is->district_infos[i].resource_prereq_ids[j] = -1; + is->district_infos[i].resource_prereq_on_tile_id = -1; + is->district_infos[i].wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].wonder_prereq_ids); j++) + is->district_infos[i].wonder_prereq_ids[j] = -1; + is->district_infos[i].natural_wonder_prereq_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].natural_wonder_prereq_ids); j++) + is->district_infos[i].natural_wonder_prereq_ids[j] = -1; + is->district_infos[i].dependent_building_count = 0; + for (int j = 0; j < ARRAY_LEN (is->district_infos[i].dependent_building_ids); j++) + is->district_infos[i].dependent_building_ids[j] = -1; + } + + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req != NULL) + free (req); + } + table_deinit (&is->city_pending_district_requests[civ_id]); + } + table_deinit (&is->city_pending_building_orders); + + is->great_wall_auto_build = GWABS_NOT_STARTED; +} + +void +clear_city_district_request (City * city, int district_id) +{ + if (! is->current_config.enable_districts || + (city == NULL) || + (district_id < 0) || (district_id >= is->district_count)) + return; + + struct pending_district_request * req = find_pending_district_request (city, district_id); + if (req == NULL) + return; + + remove_pending_district_request (req); + + int pending_improv_id; + if (look_up_pending_building_order (city, &pending_improv_id)) { + int required_district_id; + if (city_requires_district_for_improvement (city, pending_improv_id, &required_district_id)) { + if (required_district_id == district_id) + forget_pending_building_order (city); + } + } +} + +bool +district_resource_prereqs_met_r (Tile * tile, int tile_x, int tile_y, int district_id, int max_req_resource_id) +{ + if ((tile == NULL) || (tile == p_null_tile) || + (district_id < 0) || (district_id >= is->district_count)) + return false; + + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + struct district_infos * info = &is->district_infos[district_id]; + int on_tile_req = info->resource_prereq_on_tile_id; + if (on_tile_req >= 0) { + int res_here = (owner >= 0) ? Tile_get_resource_visible_to (tile, __, owner) : -1; + if (res_here != on_tile_req) + return false; + } + + // If no resource prereqs, then the check passes + if (info->resource_prereq_count <= 0) + return true; + + if (owner < 0) + return false; + + // Check resource prereqs - ALL must be present + for (int i = 0; i < info->resource_prereq_count; i++) { + int resource_req = info->resource_prereq_ids[i]; + if (resource_req < 0) + continue; + if (resource_req > max_req_resource_id) + return false; + + bool has_resource = false; + bool is_bonus_resource = p_bic_data->ResourceTypes[resource_req].Class == RC_Bonus; + + FOR_CITIES_OF (coi, owner) { + City * req_city = coi.city; + if (! Trade_Net_is_tile_connected_to_city (is->trade_net, __, req_city, tile_x, tile_y)) + continue; + if (! city_has_resource_r (req_city, resource_req, max_req_resource_id)) + if (! is_bonus_resource) + continue; + else { + int civ_id = req_city->Body.CivID; + FOR_TILES_AROUND (tai, is->workable_tile_count, req_city->Body.X, req_city->Body.Y) { + Tile * radius_tile = tai.tile; + if ((radius_tile == NULL) || (radius_tile == p_null_tile)) + continue; + if (radius_tile->vtable->m38_Get_Territory_OwnerID (radius_tile) != civ_id) + continue; + if (Tile_get_resource_visible_to (radius_tile, __, civ_id) == resource_req) { + has_resource = true; + break; + } + } + if (has_resource) + break; + continue; + } + + has_resource = true; + break; + } + + // If this required resource is not available, the check fails + if (!has_resource) + return false; + } + + return true; +} + +bool +district_resource_prereqs_met (Tile * tile, int tile_x, int tile_y, int district_id) +{ + return district_resource_prereqs_met_r (tile, tile_x, tile_y, district_id, INT_MAX); +} + +int +count_contiguous_bridge_districts (int tile_x, int tile_y, int dx, int dy) +{ + Map * map = &p_bic_data->Map; + int nx = tile_x + dx; + int ny = tile_y + dy; + int count = 0; + int max_steps = map->Width + map->Height; + + for (int step = 0; step < max_steps; step++) { + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) + break; + count++; + nx += dx; + ny += dy; + } + + return count; +} + +int +count_contiguous_canal_districts (int tile_x, int tile_y, int max_count) +{ + if (max_count <= 0) + return 0; + + Map * map = &p_bic_data->Map; + int limit = max_count + 1; + int capacity = limit; + if (capacity < 1) + capacity = 1; + + int * xs = malloc (sizeof (*xs) * capacity); + int * ys = malloc (sizeof (*ys) * capacity); + if ((xs == NULL) || (ys == NULL)) { + if (xs != NULL) + free (xs); + if (ys != NULL) + free (ys); + return limit; + } + + int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; + int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; + int head = 0; + int tail = 0; + int count = 0; + + xs[tail] = tile_x; + ys[tail] = tile_y; + tail++; + + while (head < tail) { + int cx = xs[head]; + int cy = ys[head]; + head++; + count++; + if (count >= limit) + break; + + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) + continue; + + bool seen = false; + for (int j = 0; j < tail; j++) { + if ((xs[j] == nx) && (ys[j] == ny)) { + seen = true; + break; + } + } + if (seen) + continue; + + if (tail < capacity) { + xs[tail] = nx; + ys[tail] = ny; + tail++; + } else { + count = limit; + head = tail; + break; + } + } + } + + free (xs); + free (ys); + + return count; +} + +bool +district_line_is_straight (int tile_x, int tile_y, int district_id) +{ + Map * map = &p_bic_data->Map; + int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; + int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; + + for (int i = 0; i < 8; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, district_id)) + continue; + + int cand_dx = -adj_dx[i]; + int cand_dy = -adj_dy[i]; + + for (int j = 0; j < 8; j++) { + int ox = nx + adj_dx[j]; + int oy = ny + adj_dy[j]; + wrap_tile_coords (map, &ox, &oy); + if ((ox == tile_x) && (oy == tile_y)) + continue; + if (! tile_has_district_at (ox, oy, district_id)) + continue; + + if (! ((adj_dx[j] == cand_dx) && (adj_dy[j] == cand_dy)) && + ! ((adj_dx[j] == -cand_dx) && (adj_dy[j] == -cand_dy))) + return false; + } + } + + return true; +} + +bool +bridge_district_tile_is_valid (int tile_x, int tile_y) +{ + if (! tile_is_coastal_water (tile_x, tile_y)) + return false; + + bool has_adjacent_land_or_bridge = false; + Map * map = &p_bic_data->Map; + int const adj_dx[8] = { 0, 0, -2, 2, -1, 1, -1, 1 }; + int const adj_dy[8] = { -2, 2, 0, 0, 1, -1, -1, 1 }; + + for (int i = 0; i < 8; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (tile_is_land (-1, nx, ny, false) || tile_has_district_at (nx, ny, BRIDGE_DISTRICT_ID)) { + has_adjacent_land_or_bridge = true; + break; + } + } + if (! has_adjacent_land_or_bridge) + return false; + + if (is->current_config.max_contiguous_bridge_districts > 0) { + int max_bridges = is->current_config.max_contiguous_bridge_districts; + + int ns_count = count_contiguous_bridge_districts (tile_x, tile_y, 0, -2) + + count_contiguous_bridge_districts (tile_x, tile_y, 0, 2); + if (ns_count >= max_bridges) + return false; + + int we_count = count_contiguous_bridge_districts (tile_x, tile_y, -2, 0) + + count_contiguous_bridge_districts (tile_x, tile_y, 2, 0); + if (we_count >= max_bridges) + return false; + + int swne_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, 1) + + count_contiguous_bridge_districts (tile_x, tile_y, 1, -1); + if (swne_count >= max_bridges) + return false; + + int nwse_count = count_contiguous_bridge_districts (tile_x, tile_y, -1, -1) + + count_contiguous_bridge_districts (tile_x, tile_y, 1, 1); + if (nwse_count >= max_bridges) + return false; + } + + return district_line_is_straight (tile_x, tile_y, BRIDGE_DISTRICT_ID); +} + +bool +canal_district_tile_is_valid (int tile_x, int tile_y) +{ + if (tile_is_water (tile_x, tile_y)) + return false; + + if (is->current_config.max_contiguous_canal_districts > 0) { + int count = count_contiguous_canal_districts (tile_x, tile_y, is->current_config.max_contiguous_canal_districts); + if (count > is->current_config.max_contiguous_canal_districts) + return false; + } + + Map * map = &p_bic_data->Map; + int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; + int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; + + for (int i = 0; i < 8; i++) { + int nx = tile_x + adj_dx[i]; + int ny = tile_y + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * tile = tile_at (nx, ny); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m35_Check_Is_Water (tile)) + return true; + + if (tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && + district_is_complete (tile, CANAL_DISTRICT_ID)) + return true; + } + } + + return false; +} + +bool +can_build_district_on_tile (Tile * tile, int district_id, int civ_id) +{ + if ((! is->current_config.enable_districts) || + (tile == NULL) || (tile == p_null_tile) || + (tile->CityID >= 0) || + tile->vtable->m21_Check_Crates (tile, __, 0) || + tile->vtable->m20_Check_Pollution (tile, __, 0) || + (district_id < 0) || (district_id >= is->district_count)) + return false; + + struct district_config const * cfg = &is->district_configs[district_id]; + if (cfg->command == -1) + return false; + + if ((cfg->command == UCV_Build_Neighborhood) && !is->current_config.enable_neighborhood_districts) return false; + if ((cfg->command == UCV_Build_WonderDistrict) && !is->current_config.enable_wonder_districts) return false; + if ((cfg->command == UCV_Build_DistributionHub) && !is->current_config.enable_distribution_hub_districts) return false; + if ((cfg->command == UCV_Build_Aerodrome) && !is->current_config.enable_aerodrome_districts) return false; + if ((cfg->command == UCV_Build_Port) && !is->current_config.enable_port_districts) return false; + if ((cfg->command == UCV_Build_Bridge) && !is->current_config.enable_bridge_districts) return false; + if ((cfg->command == UCV_Build_CentralRailHub) && !is->current_config.enable_central_rail_hub_districts) return false; + if ((cfg->command == UCV_Build_EnergyGrid) && !is->current_config.enable_energy_grid_districts) return false; + if ((cfg->command == UCV_Build_GreatWall) && !is->current_config.enable_great_wall_districts) return false; + + if (! district_is_buildable_on_tile (cfg, tile)) + return false; + + int tile_x = 0, tile_y = 0; + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + + if (! leader_can_build_district (&leaders[civ_id], district_id)) + return false; + + if (! district_resource_prereqs_met (tile, tile_x, tile_y, district_id)) + return false; + + if ((district_id == CANAL_DISTRICT_ID) && (! canal_district_tile_is_valid (tile_x, tile_y))) + return false; + + if ((district_id == BRIDGE_DISTRICT_ID) && (! bridge_district_tile_is_valid (tile_x, tile_y))) + return false; + + struct district_instance * existing_inst = get_district_instance (tile); + struct district_infos const * info = &is->district_infos[district_id]; + int existing_district_id = (existing_inst != NULL) ? existing_inst->district_id : -1; + bool district_completed = district_is_complete (tile, existing_district_id); + + if ((existing_district_id == district_id) && district_completed) + return false; + if ((existing_district_id >= 0) && (existing_district_id != district_id) && (! district_completed)) + return false; + + if (! cfg->allow_multiple) { + if (district_exists_within_distance (tile_x, tile_y, district_id, civ_id, is->current_config.city_work_radius)) + return false; + } + + return true; +} + +bool +district_is_obsolete_for_civ (int district_id, int civ_id) +{ + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + int obsolete_id = is->district_infos[district_id].obsoleted_by_id; + if (obsolete_id < 0) + return false; + + return Leader_has_tech (&leaders[civ_id], __, obsolete_id); +} + +bool +tile_has_obsolete_district_for_civ (Tile * tile, int civ_id) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + + int district_id = inst->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + if (! district_is_complete (tile, district_id)) + return false; + + return district_is_obsolete_for_civ (district_id, civ_id); +} + +bool +tile_suitable_for_district (Tile * tile, int district_id, City * city, bool * out_has_resource) +{ + bool has_resource = false; + if ((tile != NULL) && (tile != p_null_tile)) + has_resource = tile_has_resource (tile); + if (out_has_resource != NULL) + *out_has_resource = has_resource; + + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (tile->CityID >= 0) return false; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) return false; + if (! can_build_district_on_tile (tile, district_id, city->Body.CivID)) return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + if (tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + return true; + + // Unused wonder districts can be repurposed, completed cannot + if (district_id == WONDER_DISTRICT_ID && inst->state == DS_COMPLETED) { + struct wonder_district_info * winfo = &inst->wonder_info; + if (winfo->state == WDS_COMPLETED) + return false; + } + + return false; + } + + return true; +} + +bool +can_generate_resource (int for_civ_id, struct mill * mill) +{ + int req_tech_id = (mill->flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[mill->resource_id].RequireID; + return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); +} + +bool +district_can_generate_resource (int for_civ_id, struct district_config * dc) +{ + if (dc->generated_resource_id < 0) + return false; + int req_tech_id = (dc->generated_resource_flags & MF_NO_TECH_REQ) ? -1 : p_bic_data->ResourceTypes[dc->generated_resource_id].RequireID; + return (req_tech_id < 0) || Leader_has_tech (&leaders[for_civ_id], __, req_tech_id); +} + +bool +district_generates_resource_for_civ (Tile * tile, struct district_instance * inst, struct district_config * dc, int civ_id) +{ + if ((tile == NULL) || (tile == p_null_tile) || (inst == NULL) || (dc == NULL)) + return false; + if (inst->state != DS_COMPLETED) + return false; + if (dc->generated_resource_id < 0) + return false; + if (! district_can_generate_resource (civ_id, dc)) + return false; + + int tile_x = 0, tile_y = 0; + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + return district_resource_prereqs_met_r (tile, tile_x, tile_y, inst->district_id, dc->generated_resource_id - 1); +} + +void +calculate_city_center_district_bonus (City * city, int * out_food, int * out_shields, int * out_gold) +{ + if (out_food != NULL) + *out_food = 0; + if (out_shields != NULL) + *out_shields = 0; + if (out_gold != NULL) + *out_gold = 0; + + if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) + return; + + int bonus_food = 0; + int bonus_shields = 0; + int bonus_gold = 0; + + int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + int neighborhoods_counted = 0; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) + continue; + Tile * tile = wai.tile; + + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + if (is->current_config.enable_neighborhood_districts && + (district_id == NEIGHBORHOOD_DISTRICT_ID)) { + if (neighborhoods_counted >= utilized_neighborhoods) + continue; + neighborhoods_counted++; + } + + struct district_config * cfg = &is->district_configs[district_id]; + int food_bonus = 0, shield_bonus = 0, gold_bonus = 0; + get_effective_district_yields (inst, cfg, &food_bonus, &shield_bonus, &gold_bonus, NULL, NULL, NULL); + bonus_food += food_bonus; + bonus_shields += shield_bonus; + bonus_gold += gold_bonus; + + if ((cfg->generated_resource_id >= 0) && (cfg->generated_resource_flags & MF_YIELDS)) { + int res_id = cfg->generated_resource_id; + if (district_generates_resource_for_civ (tile, inst, cfg, city->Body.CivID)) { + Resource_Type * res = &p_bic_data->ResourceTypes[res_id]; + bonus_food += res->Food; + bonus_shields += res->Shield; + bonus_gold += res->Commerce; + } + } + } + + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { + int hub_food = 0; + int hub_shields = 0; + get_distribution_hub_yields_for_city (city, &hub_food, &hub_shields); + bonus_food += hub_food; + bonus_shields += hub_shields; + } + + if (out_food != NULL) + *out_food = bonus_food; + if (out_shields != NULL) + *out_shields = bonus_shields; + if (out_gold != NULL) + *out_gold = bonus_gold; +} + +int __fastcall +patch_Map_calc_food_yield_at (Map * this, int edx, int tile_x, int tile_y, int tile_base_type, int civ_id, int imagine_fully_improved, City * city) +{ + if (! is->current_config.enable_districts) + return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id)) { + return 0; + } + } + + return Map_calc_food_yield_at (this, __, tile_x, tile_y, tile_base_type, civ_id, imagine_fully_improved, city); +} + +int __fastcall +patch_Map_calc_shield_yield_at (Map * this, int edx, int tile_x, int tile_y, int civ_id, City * city, int param_5, int param_6) +{ + if (! is->current_config.enable_districts) + return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id)) { + return 0; + } + } + + return Map_calc_shield_yield_at (this, __, tile_x, tile_y, civ_id, city, param_5, param_6); +} + +int +compute_city_tile_yield_sum (City * city, int tile_x, int tile_y) +{ + if (city == NULL) + return 0; + int food = City_calc_tile_yield_at (city, __, YK_FOOD, tile_x, tile_y); + int shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, tile_x, tile_y); + int commerce = City_calc_tile_yield_at (city, __, YK_COMMERCE, tile_x, tile_y); + return food + shields + commerce; +} + +int * +get_water_continent_ids_connected_via_canal (Tile * tile, int * out_count) +{ + if (out_count != NULL) + *out_count = 0; + if (! is->current_config.enable_canal_districts) + return NULL; + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + if (! tile->vtable->m35_Check_Is_Water (tile)) + return NULL; + + int origin_continent_id = tile->vtable->m46_Get_ContinentID (tile); + int continent_count = p_bic_data->Map.Continent_Count; + if ((origin_continent_id < 0) || (origin_continent_id >= continent_count)) + return NULL; + + Map * map = &p_bic_data->Map; + int tile_count = map->TileCount; + if (tile_count <= 0) + return NULL; + + // Use a BFS over completed canal tiles, starting from those touching the origin water body. + int * queue_xs = malloc (sizeof (*queue_xs) * tile_count); + int * queue_ys = malloc (sizeof (*queue_ys) * tile_count); + int * ids = malloc (sizeof (*ids) * continent_count); + bool * seen = calloc (continent_count, sizeof (*seen)); + if ((queue_xs == NULL) || (queue_ys == NULL) || (ids == NULL) || (seen == NULL)) { + if (queue_xs != NULL) + free (queue_xs); + if (queue_ys != NULL) + free (queue_ys); + if (ids != NULL) + free (ids); + if (seen != NULL) + free (seen); + return NULL; + } + + seen[origin_continent_id] = true; + + int const adj_dx[8] = { 0, 0, -2, 2, 1, 1, -1, -1 }; + int const adj_dy[8] = { -2, 2, 0, 0, -1, 1, -1, 1 }; + int head = 0; + int tail = 0; + + // Seed queue with completed canal districts adjacent to the origin water body. + for (int index = 0; index < tile_count; index++) { + Tile * cand = Map_get_tile (map, __, index); + if ((cand == NULL) || (cand == p_null_tile)) + continue; + + int cx = 0, cy = 0; + tile_index_to_coords (map, index, &cx, &cy); + if (! tile_has_district_at (cx, cy, CANAL_DISTRICT_ID)) + continue; + + struct district_instance * inst = get_district_instance (cand); + if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || + (! district_is_complete (cand, CANAL_DISTRICT_ID))) + continue; + + bool adjacent_to_origin = false; + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (! adj->vtable->m35_Check_Is_Water (adj)) + continue; + int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); + if (adj_continent_id == origin_continent_id) { + adjacent_to_origin = true; + break; + } + } + if (! adjacent_to_origin) + continue; + + bool seen_canal = false; + for (int j = 0; j < tail; j++) { + if ((queue_xs[j] == cx) && (queue_ys[j] == cy)) { + seen_canal = true; + break; + } + } + if (! seen_canal && (tail < tile_count)) { + queue_xs[tail] = cx; + queue_ys[tail] = cy; + tail++; + } + } + + int id_count = 0; + + while (head < tail) { + int cx = queue_xs[head]; + int cy = queue_ys[head]; + head++; + + // Record all water bodies adjacent to this canal tile. + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + if (! adj->vtable->m35_Check_Is_Water (adj)) + continue; + + int adj_continent_id = adj->vtable->m46_Get_ContinentID (adj); + if ((adj_continent_id < 0) || (adj_continent_id >= continent_count)) + continue; + if (! seen[adj_continent_id]) { + seen[adj_continent_id] = true; + ids[id_count] = adj_continent_id; + id_count++; + } + } + + // Traverse to neighboring completed canal districts. + for (int i = 0; i < 8; i++) { + int nx = cx + adj_dx[i]; + int ny = cy + adj_dy[i]; + wrap_tile_coords (map, &nx, &ny); + if (! tile_has_district_at (nx, ny, CANAL_DISTRICT_ID)) + continue; + + Tile * adj = tile_at (nx, ny); + if ((adj == NULL) || (adj == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (adj); + if ((inst == NULL) || (inst->district_id != CANAL_DISTRICT_ID) || (! district_is_complete (adj, CANAL_DISTRICT_ID))) + continue; + + bool seen_canal = false; + for (int j = 0; j < tail; j++) { + if ((queue_xs[j] == nx) && (queue_ys[j] == ny)) { + seen_canal = true; + break; + } + } + if (! seen_canal && (tail < tile_count)) { + queue_xs[tail] = nx; + queue_ys[tail] = ny; + tail++; + } + } + } + + free (queue_xs); + free (queue_ys); + free (seen); + + if (out_count != NULL) + *out_count = id_count; + if (id_count <= 0) { + free (ids); + return NULL; + } + + return ids; +} + +Tile * +find_tile_for_neighborhood_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + + // Search in order: ring 1, then rings 2..N + // Ring order array: 1, 2, 3, ..., city_work_radius + int ring_order[8]; + int ring_count = 0; + for (int r = 1; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + + Tile * best_tile = NULL; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + bool has_resource = false; + if (is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + continue; + } + + if (! tile_suitable_for_district (tile, NEIGHBORHOOD_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + if (get_district_instance (tile) != NULL && + ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +find_tile_for_port_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + int threshold_for_body_of_water = 21; // Mimic vanilla behavior so AI doesn't build ports in small lakes + + // Search in order: ring 1, then rings 2..N + int ring_order[8]; + int ring_count = 0; + for (int r = 1; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + + Tile * best_tile = NULL; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + bool has_resource = false; + if (is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + continue; + } + + if (! tile_suitable_for_district (tile, PORT_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + if (get_district_instance (tile) != NULL && + ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + continue; + if (! tile->vtable->m35_Check_Is_Water (tile)) + continue; + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + bool large_enough_body = (continent->Body.TileCount >= threshold_for_body_of_water); + if (! large_enough_body) { + int connected_count = 0; + int * connected_ids = get_water_continent_ids_connected_via_canal (tile, &connected_count); + for (int i = 0; i < connected_count; i++) { + int connected_id = connected_ids[i]; + if ((connected_id < 0) || (connected_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * connected_continent = &p_bic_data->Map.Continents[connected_id]; + if (connected_continent->Body.TileCount >= threshold_for_body_of_water) { + large_enough_body = true; + break; + } + } + if (connected_ids != NULL) + free (connected_ids); + } + if (! large_enough_body) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +find_tile_for_wonder_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + int target_improv_id = -1; + if (look_up_pending_building_order (city, &target_improv_id)) { + if ((target_improv_id < 0) || + (target_improv_id >= p_bic_data->ImprovementsCount) || + ((p_bic_data->Improvements[target_improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0)) + target_improv_id = -1; + } + if (target_improv_id < 0) { + int order_id = city->Body.Order_ID; + if ((city->Body.Order_Type == COT_Improvement) && + (order_id >= 0) && + (order_id < p_bic_data->ImprovementsCount)) { + Improvement * order = &p_bic_data->Improvements[order_id]; + if (order->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + target_improv_id = order_id; + } + } + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + + // Search in order: ring 2, then rings 3..N, then ring 1 as last resort + int ring_order[8]; + int ring_count = 0; + ring_order[ring_count++] = 2; + for (int r = 3; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + ring_order[ring_count++] = 1; + + Tile * best_tile = NULL; + bool has_resource = false; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + if (! tile_suitable_for_district (tile, WONDER_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + if (! wonder_is_buildable_on_tile (tile, target_improv_id)) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +find_tile_for_distribution_hub_district (City * city, int * out_x, int * out_y) +{ + if (city == NULL) + return NULL; + + const int resource_penalty = 100; + const int yield_weight = 40; + const int city_distance_weight = 8; + const int capital_distance_weight = 45; + const int desired_min_capital_distance = 8; + const int proximity_penalty_scale = 300; + const int different_continent_bonus = 500; + + Tile * best_tile = NULL; + int best_score = INT_MIN; + int best_adjusted_yield = INT_MIN; + int best_distance = -1; + int best_distance_to_capital = -1; + bool best_has_resource = true; + + int civ_id = city->Body.CivID; + bool has_capital = false; + int capital_x = 0; + int capital_y = 0; + int capital_continent_id = -1; + + City * capital = get_city_ptr (leaders[civ_id].CapitalID); + if (capital != NULL) { + has_capital = true; + capital_x = capital->Body.X; + capital_y = capital->Body.Y; + Tile * capital_tile = tile_at (capital_x, capital_y); + if ((capital_tile != NULL) && (capital_tile != p_null_tile)) + capital_continent_id = capital_tile->vtable->m46_Get_ContinentID (capital_tile); + } + + FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { + int tx = wai.tile_x, ty = wai.tile_y; + Tile * tile = wai.tile; + bool has_resource; + if (! tile_suitable_for_district (tile, DISTRIBUTION_HUB_DISTRICT_ID, city, &has_resource)) + continue; + if (has_resource) + continue; + + int chebyshev = compute_wrapped_chebyshev_distance (tx, ty, city->Body.X, city->Body.Y); + if (chebyshev <= 1) + continue; + + bool too_close_to_existing_hub_or_city = false; + for (int m = 0; m < workable_tile_counts[2]; m++) { + int ndx, ndy; + patch_ni_to_diff_for_work_area (m, &ndx, &ndy); + int nx = tx + ndx, ny = ty + ndy; + wrap_tile_coords (&p_bic_data->Map, &nx, &ny); + Tile * nearby_tile = tile_at (nx, ny); + if ((nearby_tile != NULL) && (nearby_tile != p_null_tile)) { + struct district_instance * nearby_inst = get_district_instance (nearby_tile); + if ((nearby_inst != NULL) && + (nearby_inst->district_id == DISTRIBUTION_HUB_DISTRICT_ID) && + district_is_complete (nearby_tile, DISTRIBUTION_HUB_DISTRICT_ID)) { + too_close_to_existing_hub_or_city = true; + break; + } + else if (nearby_tile->CityID >= 0) { + too_close_to_existing_hub_or_city = true; + break; + } + } + } + if (too_close_to_existing_hub_or_city) + continue; + + int raw_yield = compute_city_tile_yield_sum (city, tx, ty); + int adjusted_yield = raw_yield - (has_resource ? resource_penalty : 0); + int distance = compute_wrapped_manhattan_distance (tx, ty, city->Body.X, city->Body.Y); + int distance_to_capital = has_capital + ? compute_wrapped_manhattan_distance (tx, ty, capital_x, capital_y) + : 0; + + int proximity_penalty = 0; + if (has_capital && (distance_to_capital < desired_min_capital_distance)) + proximity_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; + + int continent_bonus = 0; + if ((capital_continent_id >= 0) && (tile != NULL) && (tile != p_null_tile)) { + int tile_continent_id = tile->vtable->m46_Get_ContinentID (tile); + if ((tile_continent_id >= 0) && (tile_continent_id != capital_continent_id)) + continent_bonus = different_continent_bonus; + } + + int score = + adjusted_yield * yield_weight + + distance * city_distance_weight + + distance_to_capital * capital_distance_weight - + proximity_penalty + + continent_bonus; + + if ((score > best_score) || + ((score == best_score) && (distance_to_capital > best_distance_to_capital)) || + ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield > best_adjusted_yield)) || + ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance > best_distance)) || + ((score == best_score) && (distance_to_capital == best_distance_to_capital) && (adjusted_yield == best_adjusted_yield) && (distance == best_distance) && (! has_resource && best_has_resource))) { + best_tile = tile; + best_score = score; + best_adjusted_yield = adjusted_yield; + best_distance = distance; + best_distance_to_capital = distance_to_capital; + best_has_resource = has_resource; + *out_x = tx; + *out_y = ty; + } + } + + return best_tile; +} + +bool +city_can_build_district (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos const * info = &is->district_infos[district_id]; + + if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) + return false; + + if ((info->resource_prereq_count > 0) || (info->resource_prereq_on_tile_id >= 0)) { + bool resource_prereqs_met = false; + + FOR_TILES_AROUND (tai, is->workable_tile_count, city->Body.X, city->Body.Y) { + Tile * tile = tai.tile; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) + continue; + if (! district_resource_prereqs_met_r (tile, tai.tile_x, tai.tile_y, district_id, INT_MAX)) + continue; + + resource_prereqs_met = true; + break; + } + + if (! resource_prereqs_met) + return false; + } + + // Check if district does not allow multiple and city already has one + if (! cfg->allow_multiple && city_has_required_district (city, district_id)) + return false; + + return true; +} + +bool +leader_has_wonder_prereq (Leader * leader, struct district_infos const * info) +{ + if (info == NULL) + return false; + if (info->wonder_prereq_count <= 0) + return true; + if ((leader == NULL) || (leader->Improvement_Counts == NULL)) + return false; + + for (int i = 0; i < info->wonder_prereq_count; i++) { + int improv_id = info->wonder_prereq_ids[i]; + if (improv_id >= 0 && leader->Improvement_Counts[improv_id] > 0) + return true; + } + + return false; +} + +bool +leader_has_natural_wonder_prereq_in_territory (int civ_id, struct district_infos const * info) +{ + if (info == NULL) + return false; + if (info->natural_wonder_prereq_count <= 0) + return true; + if (! is->current_config.enable_natural_wonders) + return false; + + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + + int wonder_id = inst->natural_wonder_info.natural_wonder_id; + if (wonder_id < 0) + continue; + + bool matches = false; + for (int i = 0; i < info->natural_wonder_prereq_count; i++) { + if (info->natural_wonder_prereq_ids[i] == wonder_id) { + matches = true; + break; + } + } + if (! matches) + continue; + + Tile * tile = (Tile *)tei.key; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; + } + + return false; +} + +int +count_distribution_hubs_for_civ (int civ_id) +{ + int current = 0; + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if ((rec != NULL) && (rec->civ_id == civ_id)) + current++; + } + return current; +} + +bool +leader_can_natively_build_district (Leader * leader, int district_id) +{ + if ((leader == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos const * info = &is->district_infos[district_id]; + + for (int i = 0; i < info->advance_prereq_count; i++) { + int prereq_id = info->advance_prereq_ids[i]; + if ((prereq_id >= 0) && ! Leader_has_tech (leader, __, prereq_id)) + return false; + } + int obsolete_id = info->obsoleted_by_id; + if ((obsolete_id >= 0) && Leader_has_tech (leader, __, obsolete_id)) + return false; + + if (! leader_has_wonder_prereq (leader, info)) + return false; + + if (! leader_has_natural_wonder_prereq_in_territory (leader->ID, info)) + return false; + + if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) { + int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; + if (max_per_100 > 0) { + int city_count = leader->Cities_Count; + int max_allowed = (city_count * max_per_100 + 99) / 100; + if (max_allowed <= 0) + return false; + + int current = count_distribution_hubs_for_civ (leader->ID); + if (current >= max_allowed) + return false; + } + } + + if (cfg->has_buildable_by_civs) { + bool civ_match = false; + if (cfg->buildable_by_civ_count > 0) { + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + for (int i = 0; i < cfg->buildable_by_civ_count; i++) { + char const * civ_name = cfg->buildable_by_civs[i]; + if ((civ_name == NULL) || (civ_name[0] == '\0')) continue; + if ((race->CountryName != NULL) && (strcmp (civ_name, race->CountryName) == 0)) civ_match = true; break; + if ((race->SingularName != NULL) && (strcmp (civ_name, race->SingularName) == 0)) civ_match = true; break; + if ((race->AdjectiveName != NULL) && (strcmp (civ_name, race->AdjectiveName) == 0)) civ_match = true; break; + if ((race->LeaderName != NULL) && (strcmp (civ_name, race->LeaderName) == 0)) civ_match = true; break; + } + } + if (! civ_match) + return false; + } + + if (cfg->has_buildable_by_civ_traits) { + if (cfg->buildable_by_civ_traits_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL || race->vtable == NULL) + return false; + bool trait_match = false; + for (int i = 0; i < cfg->buildable_by_civ_traits_id_count; i++) { + int trait_id = cfg->buildable_by_civ_traits_ids[i]; + if (trait_id >= 0 && race->vtable->CheckBonus (race, __, trait_id)) { + trait_match = true; + break; + } + } + if (! trait_match) + return false; + } + + if (cfg->has_buildable_by_civ_govs) { + if (cfg->buildable_by_civ_govs_id_count <= 0) + return false; + int gov_id = leader->GovernmentType; + bool gov_match = false; + for (int i = 0; i < cfg->buildable_by_civ_govs_id_count; i++) { + if (cfg->buildable_by_civ_govs_ids[i] == gov_id) { + gov_match = true; + break; + } + } + if (! gov_match) + return false; + } + + if (cfg->has_buildable_by_civ_cultures) { + if (cfg->buildable_by_civ_cultures_id_count <= 0) + return false; + Race * race = (leader->RaceID >= 0 && leader->RaceID < p_bic_data->RacesCount) + ? &p_bic_data->Races[leader->RaceID] + : NULL; + if (race == NULL) + return false; + int culture_id = race->CultureGroupID; + bool culture_match = false; + for (int i = 0; i < cfg->buildable_by_civ_cultures_id_count; i++) { + if (cfg->buildable_by_civ_cultures_ids[i] == culture_id) { + culture_match = true; + break; + } + } + if (! culture_match) + return false; + } + + return true; +} + +bool +leader_has_war_ally_district_access (Leader * leader, int district_id) +{ + if (leader == NULL) + return false; + + int self_id = leader->ID; + for (int civ_id = 0; civ_id < 32; civ_id++) { + if (civ_id == self_id) + continue; + Leader * other = &leaders[civ_id]; + if (other->Military_Allies[self_id] != 0 && leader_can_natively_build_district (other, district_id)) + return true; + } + + return false; +} + +bool +leader_has_pact_ally_district_access (Leader * leader, int district_id) +{ + if (leader == NULL) + return false; + + int self_id = leader->ID; + for (int civ_id = 0; civ_id < 32; civ_id++) { + if (civ_id == self_id) + continue; + Leader * other = &leaders[civ_id]; + if (((leader->Relation_Treaties[civ_id] & 1) != 0 && // 1 = peace treaty + (leader->Relation_Treaties[civ_id] & 4) != 0) && // 4 = mutual protection pact + leader_can_natively_build_district (other, district_id)) { + return true; + } + } + + return false; +} + +bool +leader_can_build_district (Leader * leader, int district_id) +{ + bool can_natively_build = leader_can_natively_build_district (leader, district_id); + + if (can_natively_build) + return true; + + struct district_config const * cfg = &is->district_configs[district_id]; + if (cfg->buildable_by_war_allies && leader_has_war_ally_district_access (leader, district_id)) + return true; + if (cfg->buildable_by_pact_allies && leader_has_pact_ally_district_access (leader, district_id)) + return true; + + return can_natively_build; +} + +Tile * +find_tile_for_district (City * city, int district_id, int * out_x, int * out_y) +{ + if ((city == NULL) || (out_x == NULL) || (out_y == NULL)) + return NULL; + if ((district_id < 0) || (district_id >= is->district_count)) + return NULL; + + // Check if city can build this district at all + if (! city_can_build_district (city, district_id)) + return NULL; + + if (district_id == NEIGHBORHOOD_DISTRICT_ID) + return find_tile_for_neighborhood_district (city, out_x, out_y); + if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) + return find_tile_for_distribution_hub_district (city, out_x, out_y); + if (district_id == PORT_DISTRICT_ID) + return find_tile_for_port_district (city, out_x, out_y); + if (district_id == WONDER_DISTRICT_ID) + return find_tile_for_wonder_district (city, out_x, out_y); + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int city_work_radius = is->current_config.city_work_radius; + + // Search in order: ring 2, then rings 3..N, then ring 1 as last resort + // Ring order array: 2, 3, 4, ..., city_work_radius, 1 + int ring_order[8]; + int ring_count = 0; + ring_order[ring_count++] = 2; + for (int r = 3; r <= city_work_radius; r++) + ring_order[ring_count++] = r; + ring_order[ring_count++] = 1; + + Tile * best_tile = NULL; + struct district_config * cfg = &is->district_configs[district_id]; + int best_yield = INT_MAX; + int best_x = -1, best_y = -1; + int current_ring = -1; + + FOR_TILE_RINGS_AROUND (tri, city_x, city_y, ring_order, ring_count) { + if (tri.current_ring != current_ring) { + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + current_ring = tri.current_ring; + best_tile = NULL; + best_yield = INT_MAX; + } + + Tile * tile = tri.tile; + bool has_resource = false; + if (is->current_config.enable_distribution_hub_districts) { + int covered = itable_look_up_or (&is->distribution_hub_coverage_counts, (int)tile, 0); + if (covered > 0) + continue; + } + + if (! tile_suitable_for_district (tile, district_id, city, &has_resource)) + continue; + if (cfg->resource_prereq_on_tile < 0 && has_resource) + continue; + if (get_district_instance (tile) != NULL && ! tile_has_obsolete_district_for_civ (tile, city->Body.CivID)) + continue; + + int yield = compute_city_tile_yield_sum (city, tri.tile_x, tri.tile_y); + if (yield < best_yield && (! is_tile_earmarked_for_district (tri.tile_x, tri.tile_y))) { + best_yield = yield; + best_tile = tile; + best_x = tri.tile_x; + best_y = tri.tile_y; + } + } + + if (best_tile != NULL) { + *out_x = best_x; + *out_y = best_y; + return best_tile; + } + + return NULL; +} + +Tile * +get_completed_district_tile_for_city (City * city, int district_id, int * out_x, int * out_y) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return NULL; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + struct district_instance * inst = wai.district_inst; + + if (inst->district_id != district_id) + continue; + + // For wonder districts, filter based on wonder_district_state + if (district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = &inst->wonder_info; + // Must be either unused or under construction by this city + if (info->state == WDS_COMPLETED) + continue; + if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) + continue; + if (info->state == WDS_UNDER_CONSTRUCTION) { + info->city = city; + info->city_id = city->Body.ID; + } + } + + if (out_x != NULL) + *out_x = x; + if (out_y != NULL) + *out_y = y; + return candidate; + } + + return NULL; +} + +bool +tile_has_friendly_aerodrome_district (Tile * tile, int civ_id, bool require_available) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_aerodrome_districts || + (tile == NULL) || + (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != AERODROME_DISTRICT_ID) + return false; + + if (! district_is_complete (tile, AERODROME_DISTRICT_ID)) + return false; + + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (territory_owner != civ_id) + return false; + + if (require_available) { + int usage_mask; + if (itable_look_up (&is->aerodrome_airlift_usage, (int)tile, &usage_mask) && + (usage_mask & (1 << civ_id))) + return false; + } + + return true; +} + +bool +tile_has_friendly_port_district (Tile * tile, int civ_id) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + (tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != PORT_DISTRICT_ID)) + return false; + + if (! district_is_complete (tile, PORT_DISTRICT_ID)) + return false; + + return tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id; +} + +bool +city_has_required_district (City * city, int district_id) +{ + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + if (get_completed_district_tile_for_city (city, district_id, NULL, NULL) != NULL) { + clear_city_district_request (city, district_id); + return true; + } + return false; +} + +bool +city_has_wonder_district_with_no_completed_wonder (City * city, int wonder_improv_id) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + Tile * candidate = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + + struct wonder_district_info * info = get_wonder_district_info (candidate); + bool buildable = wonder_is_buildable_on_tile (candidate, wonder_improv_id); + if (info == NULL) return true; + if (info->state == WDS_COMPLETED) continue; + if (info->state == WDS_UNUSED && buildable) return true; + if (info->state == WDS_UNDER_CONSTRUCTION && buildable && info->city_id == city->Body.ID) { + info->city = city; + return true; // Reserved by this city + } + } + + return false; +} + +int __fastcall patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city); +int __fastcall patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null); +void __fastcall patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3); + + +void __fastcall +patch_Main_Screen_Form_show_map_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) +{ + WITH_PAUSE_FOR_POPUP { + Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, pause); + } +} + +int __cdecl +patch_process_text_for_map_message (char * in, char * out) +{ + if (is->map_message_text_override != NULL) { + strcpy (out, is->map_message_text_override); + is->map_message_text_override = NULL; + return 0; + } else + return process_text_snippet (in, out); +} + +// Works like show_map_message but takes a bit of text to display instead of a key for script.txt +void +show_map_specific_text (int tile_x, int tile_y, char const * text, bool pause) +{ + is->map_message_text_override = text; + patch_Main_Screen_Form_show_map_message (p_main_screen_form, __, tile_x, tile_y, "LANDCONQUER", pause); // Use any key here. It will be overridden. +} + +bool __fastcall +patch_City_has_improvement (City * this, int edx, int improv_id, bool include_auto_improvements) +{ + bool tr = City_has_improvement (this, __, improv_id, include_auto_improvements); + + // Check if the improvement is provided for free by another human player's wonder if we're in a hotseat game and the config option is on + if ((! tr) && + include_auto_improvements && + is->current_config.share_wonders_in_hotseat && + ((1 << this->Body.CivID) & *p_human_player_bits) && + (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // if we're in a hotseat game + + // Loop over every other human player in the game and check if the city would have the improv if they were its owner + int actual_owner_id = this->Body.CivID; + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != actual_owner_id)) { + this->Body.CivID = n_player; + if (City_has_improvement (this, __, improv_id, include_auto_improvements)) { + tr = true; + break; + } + } + player_bits >>= 1; + n_player++; + } + this->Body.CivID = actual_owner_id; + + } + + return tr; +} + +int +count_neighborhoods_in_city_radius (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return 0; + + int count = 0; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + struct district_instance * inst = wai.district_inst; + if (inst != NULL && + inst->district_id >= 0 && inst->district_id < is->district_count && + inst->district_id == NEIGHBORHOOD_DISTRICT_ID) + count++; + } + return count; +} + +int +count_utilized_neighborhoods_in_city_radius (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return 0; + + int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; + if (base_cap <= 0) + return 0; + + int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; + if (per_neighborhood <= 0) + return 0; + + int pop = city->Body.Population.Size; + if (pop <= base_cap) + return 0; + + int excess_pop = pop - base_cap; + int utilized = (excess_pop + per_neighborhood - 1) / per_neighborhood; + int total_neighborhoods = count_neighborhoods_in_city_radius (city); + + if (utilized > total_neighborhoods) + utilized = total_neighborhoods; + + return utilized; +} + +int +get_neighborhood_pop_cap (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return -1; + + int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; + if (base_cap <= 0) + return -1; + + int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; + if (per_neighborhood < 0) + per_neighborhood = 0; + + int neighborhoods = count_neighborhoods_in_city_radius (city); + long long cap = (long long)base_cap + (long long)per_neighborhood * neighborhoods; + if (cap < base_cap) + cap = base_cap; + + return (int)cap; +} + +bool +city_is_at_neighborhood_cap (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return false; + + int cap = get_neighborhood_pop_cap (city); + if (cap <= 0) + return false; + + return city->Body.Population.Size >= cap; +} + +void +ensure_neighborhood_request_for_city (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_neighborhood_districts || + (city == NULL)) + return; + + if (! leader_can_build_district (&leaders[city->Body.CivID], NEIGHBORHOOD_DISTRICT_ID)) + return; + + mark_city_needs_district (city, NEIGHBORHOOD_DISTRICT_ID); +} + +void +calculate_district_culture_science_bonuses (City * city, int * culture_bonus, int * science_bonus) +{ + if (culture_bonus != NULL) + *culture_bonus = 0; + if (science_bonus != NULL) + *science_bonus = 0; + + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders) || (city == NULL)) + return; + + int total_culture = 0; + int total_science = 0; + int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) + continue; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + struct district_config const * cfg = &is->district_configs[district_id]; + int district_culture_bonus = 0; + int district_science_bonus = 0; + get_effective_district_yields (inst, cfg, NULL, NULL, NULL, &district_science_bonus, &district_culture_bonus, NULL); + + bool is_neighborhood = (cfg->command == UCV_Build_Neighborhood); + if (is_neighborhood) { + if (utilized_neighborhoods > 0) { + total_culture += district_culture_bonus; + total_science += district_science_bonus; + utilized_neighborhoods--; + } + } else { + total_culture += district_culture_bonus; + total_science += district_science_bonus; + } + } + + if (culture_bonus != NULL) + *culture_bonus = total_culture; + if (science_bonus != NULL) + *science_bonus = total_science; +} + +void +calculate_district_happiness_bonus (City * city, int * happiness_bonus) +{ + if (happiness_bonus != NULL) + *happiness_bonus = 0; + + if (! is->current_config.enable_districts || (city == NULL)) + return; + + int total_happy = 0; + int utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) + continue; + + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + struct district_config const * cfg = &is->district_configs[district_id]; + + bool is_neighborhood = district_id == NEIGHBORHOOD_DISTRICT_ID; + if (is_neighborhood && (utilized_neighborhoods <= 0)) + continue; + + if (is_neighborhood) + utilized_neighborhoods--; + + int district_happy = 0; + get_effective_district_yields (inst, cfg, NULL, NULL, NULL, NULL, NULL, &district_happy); + if (district_happy != 0) + total_happy += district_happy; + } + + if (happiness_bonus != NULL) + *happiness_bonus = total_happy; +} + +int __fastcall +patch_City_requires_improvement_to_grow (City * this) +{ + int required_improv = City_requires_improvement_to_grow (this); + if ((required_improv == -1) && + (this != NULL) && + is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + city_is_at_neighborhood_cap (this)) { + return 0; // Neighborhood sentinel + } + + return required_improv; +} + +// Replacement check specifically for stalled growth check function, +// where we can't pass through the neighborhood sentinel. That function itself +// doesn't block growth, it just triggers the dialog, so safe to skip it if +// neighborhoods are needed. +int __fastcall +patch_City_requires_improvement_to_grow_besides_neighborhood (City * this) +{ + return City_requires_improvement_to_grow (this); +} + +void __fastcall +patch_maybe_show_improvement_needed_for_growth_dialog (void * this, int edx, City * city, int * param_2) +{ + int required_improv_id = (int)param_2; + if (is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + (required_improv_id == 0)) // Neighborhood sentinel + return; + + maybe_show_improvement_needed_for_growth_dialog (this, __, city, param_2); +} + +void +maybe_show_neighborhood_growth_warning (City * city) +{ + if ((city == NULL) || ! (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts)) return; + int requirement = patch_City_requires_improvement_to_grow (city); + if (requirement != 0) return; // Neighborhood sentinel not present + if (city->Body.FoodIncome <= 0) return; // Not growing + if (is_online_game ()) return; + int civ_id = city->Body.CivID; + if (civ_id != p_main_screen_form->Player_CivID) return; + if ((*p_human_player_bits & (1u << civ_id)) == 0) return; + + unsigned int turn_no = (unsigned int)*p_current_turn_no; + unsigned int throttle = ((unsigned int)city->Body.X << 5) ^ (unsigned int)city->Body.Y; + int frequency = is->current_config.neighborhood_needed_message_frequency; + if ((frequency <= 0) || (((turn_no + throttle) % frequency) != 0)) + return; + + char msg[160]; + char const * city_name = city->Body.CityName; + snprintf (msg, sizeof msg, "%s %s %s %s", + city_name, + is->c3x_labels[CL_REQUIRES], + is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name, + is->c3x_labels[CL_TO_GROW] + ); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); +} + +bool __stdcall +patch_is_not_pop_capped_or_starving (City * city) +{ + bool tr = is_not_pop_capped_or_starving (city); + if (! tr) return false; + + if (is->current_config.enable_districts) { + if (city_is_at_neighborhood_cap (city)) + return false; + } + + return true; +} + +bool +remove_building_if_no_district (City * city, int district_id, int building_id) +{ + if ((city == NULL) || (building_id < 0)) return false; + if (! patch_City_has_improvement (city, __, building_id, false)) return false; + if (city_has_required_district (city, district_id)) return false; + + patch_City_add_or_remove_improvement (city, __, building_id, 0, false); + return true; +} + +bool +city_has_other_completed_wonder_district_for_improvement (City * city, int wonder_improv_id, int removed_x, int removed_y) +{ + if (! (is->current_config.enable_districts && is->current_config.enable_wonder_districts) || + (city == NULL) || (wonder_improv_id < 0)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + if ((x == removed_x) && (y == removed_y)) + continue; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if (info->state != WDS_COMPLETED) + continue; + + int candidate_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); + if (candidate_improv_id != wonder_improv_id) + continue; + + return true; + } + + return false; +} + +void +remove_shared_wonder_if_no_other_district (City * city, int wonder_improv_id, int removed_x, int removed_y) +{ + if ((city == NULL) || (wonder_improv_id < 0)) + return; + + if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) + return; + + if (leaders[city->Body.CivID].Small_Wonders[wonder_improv_id] == city->Body.ID) + return; + + if (city_has_other_completed_wonder_district_for_improvement (city, wonder_improv_id, removed_x, removed_y)) + return; + + patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); +} + +void +reduce_city_population_due_to_lost_neighborhood (City * city) +{ + if (city == NULL) + return; + + if (! (is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + is->current_config.destroying_neighborhood_reduces_pop)) + return; + + int base_cap = is->current_config.maximum_pop_before_neighborhood_needed; + int per_neighborhood = is->current_config.per_neighborhood_pop_growth_enabled; + if ((base_cap <= 0) || (per_neighborhood <= 0)) + return; + + int neighborhoods = count_neighborhoods_in_city_radius (city); + int cap = base_cap + (per_neighborhood * neighborhoods); + if (cap < base_cap) + cap = base_cap; + + int pop = city->Body.Population.Size; + if (pop <= cap) + return; + + int to_remove = pop - cap; + int removed = 0; + while (to_remove-- > 0) { + City_remove_population (city, __, 1, -1, '\0'); + removed++; + } + + if ((removed > 0) && + ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && + (city->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[160]; + snprintf (msg, sizeof msg, "%s %s %s", + city->Body.CityName, + is->c3x_labels[CL_LOST_POPULATION_DUE_TO_DESTROYED_NEIGHBORHOOD], + is->district_configs[NEIGHBORHOOD_DISTRICT_ID].display_name + ); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } +} + +bool +city_has_other_completed_district (City * city, int district_id, int removed_x, int removed_y) +{ + if (! is->current_config.enable_districts || + (city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + if ((x == removed_x) && (y == removed_y)) + continue; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != district_id) + continue; + + return true; + } + + return false; +} + +bool +district_instance_is_redundant (struct district_instance * inst, Tile * tile) +{ + if (! is->current_config.enable_districts || + (inst == NULL) || + (tile == NULL) || (tile == p_null_tile)) + return false; + + int district_id = inst->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + return false; + + if (! district_is_complete (tile, district_id)) + return false; + + if (district_id == NEIGHBORHOOD_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID) + return false; + + int tile_x = inst->tile_x; + int tile_y = inst->tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + return false; + + int civ_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + + if (district_id == WONDER_DISTRICT_ID) + return inst->wonder_info.state == WDS_UNUSED; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + if (! city_has_other_completed_district (wai.city, district_id, tile_x, tile_y)) + return false; + } + + return true; +} + +bool +any_nearby_city_would_lose_district_benefits (int district_id, int civ_id, int removed_x, int removed_y) +{ + if (! is->current_config.enable_districts) + return false; + + if (district_id < 0 || district_id >= is->district_count) + return false; + + struct district_infos * info = &is->district_infos[district_id]; + + // If there are no dependent buildings, no city can lose benefits + if (info->dependent_building_count == 0) + return false; + + // Check all cities within work radius of the removed district + FOR_CITIES_AROUND (wai, removed_x, removed_y) { + City * city = wai.city; + + // Check if this city has another completed district of the same type nearby (excluding the one being removed) + if (city_has_other_completed_district (city, district_id, removed_x, removed_y)) + continue; + + // This city doesn't have another district, check if it has any dependent buildings + for (int i = 0; i < info->dependent_building_count; i++) { + int building_id = info->dependent_building_ids[i]; + if (building_id >= 0 && patch_City_has_improvement (city, __, building_id, false)) + return true; + } + } + + return false; +} + +void +remove_dependent_buildings_for_district (int district_id, int center_x, int center_y) +{ + if (! is->current_config.enable_districts || (district_id < 0) || (district_id >= is->district_count)) + return; + + struct district_infos * info = &is->district_infos[district_id]; + + if ((center_x < 0) || (center_y < 0) || + (center_x >= p_bic_data->Map.Width) || (center_y >= p_bic_data->Map.Height)) + return; + + FOR_CITIES_AROUND (wai, center_x, center_y) { + City * city = wai.city; + + if (city_has_other_completed_district (city, district_id, center_x, center_y)) + continue; + + int removed_count = 0; + int first_building_id = -1; + + for (int i = 0; i < info->dependent_building_count; i++) { + int building_id = info->dependent_building_ids[i]; + if (building_id >= 0) { + // This also loops through tiles around the city but is not redundant, as the city + // may have multiple districts of the same type in its radius (eg outside radius of this particular district) + if (remove_building_if_no_district (city, district_id, building_id)) { + if (removed_count == 0) + first_building_id = building_id; + removed_count++; + } + } + } + + if ((removed_count > 0) && + is->current_config.show_message_when_building_lost_to_destroyed_district && + ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) && + (city->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[200]; + char const * district_name = is->district_configs[district_id].name; + char const * building_name = (first_building_id >= 0) ? p_bic_data->Improvements[first_building_id].Name.S : ""; + + if (removed_count == 1) + snprintf (msg, sizeof msg, "%s%s %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_APOSTROPHE_S], + building_name, + is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], + district_name); + else + snprintf (msg, sizeof msg, "%s%s %s %s %d %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_APOSTROPHE_S], + building_name, + is->c3x_labels[CL_AND], + removed_count - 1, + is->c3x_labels[CL_OTHER_BUILDINGS_HAVE_BEEN], + is->c3x_labels[CL_LOST_DUE_TO_DESTROYED], + district_name); + + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + } +} + +void +remove_wonder_improvement_for_destroyed_district (int wonder_improv_id) +{ + if ((wonder_improv_id < 0) || (wonder_improv_id >= p_bic_data->ImprovementsCount)) + return; + + if ((p_cities == NULL) || (p_cities->Cities == NULL)) + return; + + for (int idx = 0; idx <= p_cities->LastIndex; idx++) { + City * city = get_city_ptr (idx); + if (city == NULL) + continue; + if (! patch_City_has_improvement (city, __, wonder_improv_id, false)) + continue; + + patch_City_add_or_remove_improvement (city, __, wonder_improv_id, 0, false); + } +} + +void +handle_district_removed (Tile * tile, int district_id, int center_x, int center_y, bool leave_ruins) +{ + if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.enable_districts) + return; + + int wonder_windex = -1; + int wonder_improv_id = -1; + + // Get wonder district info before removing + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info != NULL && info->state == WDS_COMPLETED) + wonder_windex = info->wonder_index; + + int actual_district_id = district_id; + if (actual_district_id < 0) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) + actual_district_id = inst->district_id; + } + + remove_district_instance (tile); + + bool removed_neighborhood = actual_district_id == NEIGHBORHOOD_DISTRICT_ID; + + if (is->current_config.enable_wonder_districts && + (actual_district_id == WONDER_DISTRICT_ID) && + (wonder_windex >= 0)) + wonder_improv_id = get_wonder_improvement_id_from_index (wonder_windex); + + if (wonder_improv_id >= 0 && is->current_config.completed_wonder_districts_can_be_destroyed) + remove_wonder_improvement_for_destroyed_district (wonder_improv_id); + + if (is->current_config.enable_distribution_hub_districts && + (actual_district_id == DISTRIBUTION_HUB_DISTRICT_ID)) + remove_distribution_hub_record (tile); + + if (district_id >= 0) + remove_dependent_buildings_for_district (district_id, center_x, center_y); + + // Make the tile workable again by resetting CityAreaID and recomputing yields for nearby cities + tile->Body.CityAreaID = -1; + + int tile_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + + FOR_CITIES_AROUND (wai, center_x, center_y) { + if (removed_neighborhood) + reduce_city_population_due_to_lost_neighborhood (wai.city); + recompute_city_yields_with_districts (wai.city); + } + + if (leave_ruins && (tile->vtable->m60_Set_Ruins != NULL)) { + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, center_x, center_y); + tile->vtable->m60_Set_Ruins (tile, __, 1); + } + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +bool +city_has_active_wonder_for_district (City * city) +{ + struct district_infos * info = &is->district_infos[WONDER_DISTRICT_ID]; + for (int n = 0; n < ARRAY_LEN (info->dependent_building_ids); n++) { + int building_id = info->dependent_building_ids[n]; + if ((building_id >= 0) && has_active_building (city, building_id)) + return true; + } + return false; +} + +bool +city_requires_district_for_improvement (City * city, int improv_id, int * out_district_id) +{ + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); + if ((prereq_list == NULL) || (prereq_list->count <= 0)) + return false; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder = false; + + // Special logic for handling rivers + bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; + bool has_prereq = false; + + if (is->current_config.enable_wonder_districts && + district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) { + is_wonder = true; + if (! wonder_is_buildable_by_civ (improv_id, city->Body.CivID)) { + if (out_district_id != NULL) + *out_district_id = -1; + return false; + } + if (requires_river) { + bool has_river_wonder_district = false; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if (wai.district_inst->district_id != WONDER_DISTRICT_ID) + continue; + if (wai.tile->vtable->m37_Get_River_Code (wai.tile) == 0) + continue; + if (! wonder_is_buildable_on_tile (wai.tile, improv_id)) + continue; + struct wonder_district_info * info = get_wonder_district_info (wai.tile); + if (info == NULL) { + has_river_wonder_district = true; + break; + } + if (info->state == WDS_COMPLETED) + continue; + if (info->state == WDS_UNDER_CONSTRUCTION && info->city_id != city->Body.ID) + continue; + has_river_wonder_district = true; + break; + } + if (has_river_wonder_district) + has_prereq = true; + } else if (city_has_wonder_district_with_no_completed_wonder (city, improv_id)) { + has_prereq = true; + } + } + + if (! has_prereq && city_has_any_prereq_district_for_improvement (city, prereq_list, requires_river, !is_wonder)) + has_prereq = true; + + if (has_prereq) + return false; + + if (out_district_id != NULL) + *out_district_id = pick_missing_district_for_improvement (city, prereq_list); + return true; +} + +void +clear_best_feasible_order (City * city) +{ + int key = (int)city; + int stored_int; + if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) { + struct ai_best_feasible_order * stored = (struct ai_best_feasible_order *)stored_int; + free (stored); + itable_remove (&is->ai_best_feasible_orders, key); + } +} + +void +record_best_feasible_order (City * city, City_Order const * order, int value) +{ + int key = (int)city; + int stored_int; + struct ai_best_feasible_order * stored; + if (itable_look_up (&is->ai_best_feasible_orders, key, &stored_int)) + stored = (struct ai_best_feasible_order *)stored_int; + else { + stored = malloc (sizeof *stored); + if (stored == NULL) + return; + stored->order = *order; + stored->value = value; + itable_insert (&is->ai_best_feasible_orders, key, (int)stored); + return; + } + + if (value > stored->value) { + stored->order = *order; + stored->value = value; + } +} + +struct ai_best_feasible_order * +get_best_feasible_order (City * city) +{ + int stored_int; + if (itable_look_up (&is->ai_best_feasible_orders, (int)city, &stored_int)) + return (struct ai_best_feasible_order *)stored_int; + else + return NULL; +} + +bool +city_is_currently_building_wonder (City * city) +{ + if ((city == NULL) || (city->Body.Order_Type != COT_Improvement)) + return false; + int order_id = city->Body.Order_ID; + if ((order_id < 0) || (order_id >= p_bic_data->ImprovementsCount)) + return false; + return (p_bic_data->Improvements[order_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; +} + +bool +wonder_district_tile_under_construction (Tile * tile, int tile_x, int tile_y, int * out_windex) +{ + if (! is->current_config.enable_wonder_districts || + (tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != WONDER_DISTRICT_ID) + return false; + + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info == NULL || info->state != WDS_UNDER_CONSTRUCTION) + return false; + + City * reserved_city = get_city_ptr (info->city_id); + if (reserved_city == NULL) + return false; + info->city = reserved_city; + info->city_id = reserved_city->Body.ID; + + // Verify the reserved city is still building a wonder + if (! city_is_currently_building_wonder (reserved_city)) + return false; + + // Verify this tile is within the reserved city's radius + if (! city_radius_contains_tile (reserved_city, tile_x, tile_y)) + return false; + + // Get the wonder index for the wonder being built + if (out_windex != NULL) { + int order_id = reserved_city->Body.Order_ID; + int windex = find_wonder_config_index_by_improvement_id (order_id); + *out_windex = windex; + } + + return true; +} + +bool +city_needs_wonder_district (City * city) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + + int pending_improv_id; + if (look_up_pending_building_order (city, &pending_improv_id)) { + // Check if it's actually a wonder + if ((pending_improv_id >= 0) && (pending_improv_id < p_bic_data->ImprovementsCount)) { + Improvement * improv = &p_bic_data->Improvements[pending_improv_id]; + if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + return true; + } + } + if (city_is_currently_building_wonder (city)) + return true; + if (city_has_active_wonder_for_district (city)) + return true; + return false; +} + +bool +city_has_assigned_wonder_district (City * city, Tile * ignore_tile, int wonder_improv_id) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + if (candidate == ignore_tile) + continue; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = inst ? &inst->wonder_info : NULL; + if ((info != NULL) && + (info->state == WDS_UNDER_CONSTRUCTION) && + (info->city_id == city->Body.ID)) { + info->city = city; + if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) { + info->state = WDS_UNUSED; + info->city = NULL; + info->city_id = -1; + info->wonder_index = -1; + continue; + } + return true; + } + } + + return false; +} + +bool +free_wonder_district_for_city (City * city) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((*p_human_player_bits & (1 << city->Body.CivID)) != 0) + return false; + if (city_needs_wonder_district (city)) + return false; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { + int x = wai.tile_x, y = wai.tile_y; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info != NULL && info->state == WDS_COMPLETED) + continue; // Don't remove completed wonder districts + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + continue; + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + + handle_district_removed (tile, WONDER_DISTRICT_ID, city->Body.X, city->Body.Y, false); + return true; + } + + return false; +} + +bool +reserve_wonder_district_for_city (City * city, int wonder_improv_id) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return false; + if ((wonder_improv_id >= 0) && ! wonder_is_buildable_by_civ (wonder_improv_id, city->Body.CivID)) + return false; + + if (city_has_assigned_wonder_district (city, NULL, wonder_improv_id)) + return true; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * candidate = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + if ((wonder_improv_id >= 0) && (! wonder_is_buildable_on_tile (candidate, wonder_improv_id))) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if (info->state == WDS_COMPLETED) continue; + if (info->state == WDS_UNDER_CONSTRUCTION) { + if (info->city_id == city->Body.ID) { + info->city = city; + return true; + } + continue; + } + if (city_has_assigned_wonder_district (city, candidate, wonder_improv_id)) + return true; + + // Reserve this Wonder district for this city + info->state = WDS_UNDER_CONSTRUCTION; + info->city = city; + info->city_id = city->Body.ID; + info->wonder_index = -1; + return true; + } + + return false; +} + +void +release_wonder_district_reservation (City * city) +{ + if (! is->current_config.enable_wonder_districts || (city == NULL)) + return; + + // Find and remove any reservations for this city + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, false) { + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if ((info != NULL) && + (info->state == WDS_UNDER_CONSTRUCTION) && + (info->city_id == city->Body.ID)) { + info->city = city; + info->state = WDS_UNUSED; + info->city = NULL; + info->city_id = -1; + info->wonder_index = -1; + } + } +} + +void +handle_district_destroyed_by_attack (Tile * tile, int tile_x, int tile_y, bool leave_ruins) +{ + if (! is->current_config.enable_districts || tile == NULL || tile == p_null_tile) + return; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + int district_id = inst->district_id; + + // If this is a Wonder District with a completed wonder and wonders can't be destroyed, restore overlay and keep district + if (is->current_config.enable_wonder_districts) { + struct wonder_district_info * info = get_wonder_district_info (tile); + if ((district_id == WONDER_DISTRICT_ID) && + (info != NULL && info->state == WDS_COMPLETED) && + (! is->current_config.completed_wonder_districts_can_be_destroyed)) { + unsigned int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); + if ((overlays & TILE_FLAG_MINE) == 0) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + return; + } + } + if (district_id == BRIDGE_DISTRICT_ID || district_id == CANAL_DISTRICT_ID) { + enum UnitTypeClasses target_class = (district_id == BRIDGE_DISTRICT_ID) ? UTC_Land : UTC_Sea; + clear_memo (); + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if (unit == NULL) + continue; + int unit_type_id = unit->Body.UnitTypeID; + if ((unit_type_id < 0) || (unit_type_id >= p_bic_data->UnitTypeCount)) + continue; + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + bool matches = (type->Unit_Class == target_class); + if (! matches && unit->Body.Container_Unit >= 0) { + Unit * container = get_unit_ptr (unit->Body.Container_Unit); + if (container != NULL) { + int container_type_id = container->Body.UnitTypeID; + if ((container_type_id >= 0) && (container_type_id < p_bic_data->UnitTypeCount)) { + UnitType * container_type = &p_bic_data->UnitTypes[container_type_id]; + matches = (container_type->Unit_Class == target_class); + } + } + } + if (matches) { + bool already = false; + for (int n = 0; n < is->memo_len; n++) + if (is->memo[n] == unit->Body.ID) { + already = true; + break; + } + if (! already) + memoize (unit->Body.ID); + } + } + for (int n = 0; n < is->memo_len; n++) { + Unit * to_despawn = get_unit_ptr (is->memo[n]); + if (to_despawn != NULL) + patch_Unit_despawn (to_despawn, __, 0, 1, 0, 0, 0, 0, 0); + } + clear_memo (); + } + handle_district_removed (tile, district_id, tile_x, tile_y, leave_ruins); + } +} + +bool +has_active_building (City * city, int improv_id) +{ + Leader * owner = &leaders[city->Body.CivID]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + return patch_City_has_improvement (city, __, improv_id, 1) && // building is physically present in city AND + ((improv->ObsoleteID < 0) || (! Leader_has_tech (owner, __, improv->ObsoleteID))) && // building is not obsolete AND + ((improv->GovernmentID < 0) || (improv->GovernmentID == owner->GovernmentType)); // building is not restricted to a different govt +} + +void +init_unit_type_count (Leader * leader) +{ + int id = leader->ID; + struct table * counts = &is->unit_type_counts[id]; + + if (counts->len > 0) + table_deinit (counts); + + if (p_units->Units != NULL) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit_Body * body = p_units->Units[n].Unit; + if ((body != NULL) && ((int)body != offsetof (Unit, Body)) && (body->CivID == id)) { + int prev_count = itable_look_up_or (counts, body->UnitTypeID, 0); + itable_insert (counts, body->UnitTypeID, prev_count + 1); + } + } + + is->unit_type_count_init_bits |= 1 << id; +} + +int +get_unit_type_count (Leader * leader, int unit_type_id) +{ + int id = leader->ID; + struct table * counts = &is->unit_type_counts[id]; + + if ((is->unit_type_count_init_bits & 1<ID; + struct table * counts = &is->unit_type_counts[id]; + if ((is->unit_type_count_init_bits & (1 << id)) == 0) + init_unit_type_count (leader); + + int prev_amount = itable_look_up_or (counts, unit_type_id, 0); + itable_insert (counts, unit_type_id, prev_amount + amount); +} + +// If this unit type is limited, returns true and writes how many units of the type the given player is allowed to "out_limit". If the type is not +// limited, returns false. +bool +get_unit_limit (Leader * leader, int unit_type_id, int * out_limit) +{ + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + struct unit_type_limit * lim; + 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; + if (lim->cities_per != 0) + tr += city_count / lim->cities_per; + *out_limit = tr; + return true; + } else + return false; +} + +// This this unit type is limited, returns true and writes to "out_available" how many units the given player can add before reaching the limit. If +// the type is not limited, returns false. +bool +get_available_unit_count (Leader * leader, int unit_type_id, int * out_available) +{ + int limit; + if (get_unit_limit (leader, unit_type_id, &limit)) { + int count = get_unit_type_count (leader, unit_type_id); + int dups[30]; + int dups_count = list_unit_type_duplicates (unit_type_id, dups, ARRAY_LEN (dups)); + for (int n = 0; n < dups_count; n++) + count += get_unit_type_count (leader, dups[n]); + + *out_available = limit - count; + return true; + } else + return false; +} + +int +add_i31b_to_int (int base, i31b addition) +{ + int amount; + bool percent; + i31b_unpack (addition, &amount, &percent); + if (! percent) + return base + amount; + else { + int fraction = (base * int_abs (amount) + 50) / 100; + return (amount >= 0) ? base + fraction : base - fraction; + } +} + +int +apply_perfume (enum perfume_kind kind, char const * name, int base_amount) +{ + i31b perfume_value; + if (stable_look_up (&is->current_config.perfume_specs[kind], name, &perfume_value)) + return add_i31b_to_int (base_amount, perfume_value); + else + return base_amount; +} + +int __stdcall +intercept_consideration (int valuation) +{ + City * city = is->ai_considering_production_for_city; + City_Order * order = &is->ai_considering_order; + + // Apply perfume + char * order_name; { + if (order->OrderType == COT_Improvement) + order_name = p_bic_data->Improvements[order->OrderID].Name.S; + else + order_name = p_bic_data->UnitTypes[order->OrderID].Name; + } + valuation = apply_perfume (PK_PRODUCTION, order_name, valuation); + + // Apply temp AI settler perfume + if ((order->OrderType == COT_Unit) && + (p_bic_data->UnitTypes[order->OrderID].AI_Strategy & UTAI_Settle) && + (is->current_config.ai_settler_perfume_on_founding != 0) && + (is->current_config.ai_settler_perfume_on_founding_duration != 0) && + (is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID] >= 0)) { + int turns_since_founding = *p_current_turn_no - is->turn_no_of_last_founding_for_settler_perfume[city->Body.CivID]; + int duration = is->current_config.ai_settler_perfume_on_founding_duration; + if (turns_since_founding < duration) { + i31b perfume = is->current_config.ai_settler_perfume_on_founding; + + // Scale amount by turns remaining + { + int amount; + bool percent; + i31b_unpack (perfume, &amount, &percent); + + int percent_remaining = (100 * (duration - turns_since_founding)) / duration; + amount = (amount * percent_remaining + 50) / 100; + + perfume = i31b_pack (amount, percent); + } + + valuation = add_i31b_to_int (valuation, perfume); + } + } + + if (is->current_config.enable_districts && + (city != NULL) && + ((*p_human_player_bits & (1 << city->Body.CivID)) == 0)) { + bool feasible = false; + switch (order->OrderType) { + case COT_Improvement: + if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->ImprovementsCount) && + (! city_requires_district_for_improvement (city, order->OrderID, NULL))) + feasible = true; + break; + case COT_Unit: + if ((order->OrderID >= 0) && (order->OrderID < p_bic_data->UnitTypeCount)) + feasible = true; + break; + default: + break; + } + if (feasible) + record_best_feasible_order (city, order, valuation); + } + + // Expand the list of valuations if necessary + reserve (sizeof is->ai_prod_valuations[0], (void **)&is->ai_prod_valuations, &is->ai_prod_valuations_capacity, is->count_ai_prod_valuations); + + // Record this valuation + int n = is->count_ai_prod_valuations++; + is->ai_prod_valuations[n] = (struct ai_prod_valuation) { + .order_type = order->OrderType, + .order_id = order->OrderID, + .point_value = valuation + }; + + return valuation; +} + +// Returns a pointer to a bitfield that can be used to record resource access for resource IDs >= 32. This procedure can work with any city ID since +// it allocates and zero-initializes these bit fields as necessary. The given resource ID must be at least 32. The index of the bit for that resource +// within the field is resource_id%32. +unsigned * +get_extra_resource_bits (int city_id, int resource_id) +{ + int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); + int ints_per_city = 1 + extra_resource_count/32; + if (city_id >= is->extra_available_resources_capacity) { + int new_capacity = city_id + 100; + unsigned * new_array = calloc (new_capacity * ints_per_city, sizeof new_array[0]); + if (is->extra_available_resources != NULL) { + memcpy (new_array, is->extra_available_resources, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); + free (is->extra_available_resources); + } + is->extra_available_resources = new_array; + is->extra_available_resources_capacity = new_capacity; + } + return &is->extra_available_resources[city_id * ints_per_city + (resource_id-32)/32]; +} + +void __stdcall +intercept_set_resource_bit (City * city, int resource_id) +{ + if (resource_id < 32) + city->Body.Available_Resources |= 1 << resource_id; + else + *get_extra_resource_bits (city->Body.ID, resource_id) |= 1 << (resource_id&31); +} + +// Must forward declare this function since there's a circular dependency between it and patch_City_has_resource +bool has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id); + +bool __fastcall +patch_City_has_resource (City * this, int edx, int resource_id) +{ + return city_has_resource_r (this, resource_id, INT_MAX); +} + +bool +city_has_resource_r (City * this, int resource_id, int max_generated_resource_id) +{ + bool tr; + if ((this == NULL) || (resource_id < 0) || (resource_id >= p_bic_data->ResourceTypeCount)) + return false; + if (resource_id > max_generated_resource_id) + return false; + + if (is->current_config.patch_phantom_resource_bug && + (resource_id >= 32) && (resource_id < p_bic_data->ResourceTypeCount) && + (! City_has_trade_connection_to_capital (this))) { + unsigned bits = (this->Body.ID < is->extra_available_resources_capacity) ? *get_extra_resource_bits (this->Body.ID, resource_id) : 0; + tr = (bits >> (resource_id&31)) & 1; + } else + tr = City_has_resource (this, __, resource_id); + + // Check if access to this resource is provided by a building in the city + if (! tr) + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if ((mill->resource_id == resource_id) && + (mill->flags & MF_LOCAL) && + can_generate_resource (this->Body.CivID, mill) && + has_active_building (this, mill->improv_id) && + has_resources_required_by_building_r (this, mill->improv_id, mill->resource_id - 1)) { + tr = true; + break; + } + } + + // Check if access to this resource is provided by a district in the city's work radius + if ((! tr) && is->current_config.enable_districts) { + FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { + struct district_instance * di = wai.district_inst; + int district_id = di->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + continue; + + struct district_config * dc = &is->district_configs[district_id]; + if ((dc->generated_resource_id == resource_id) && + (dc->generated_resource_flags & MF_LOCAL) && + district_generates_resource_for_civ (wai.tile, di, dc, this->Body.CivID)) { + tr = true; + break; + } + } + } + + return tr; +} + +// Checks if the resource requirements for an improvement are satisfied in a given city. The "max_req_resource_id" parameter is to guard against +// infinite loops in case of circular resource dependencies due to mills. The way it works is that resource requirements can only be satisfied if +// their ID is not greater than that limit. This function is called recursively by patch_City_has_resource and in the recursive calls, the limit is +// set to be below the resource ID provided by the mill being considered. So, when considering resource production chains, the limit approaches zero +// with each recursive call, hence infinite loops are not possible. +bool +has_resources_required_by_building_r (City * city, int improv_id, int max_req_resource_id) +{ + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if (! (improv->ImprovementFlags & ITF_Required_Goods_Must_Be_In_City_Radius)) { + for (int n = 0; n < 2; n++) { + int res_id = (&improv->Resource1ID)[n]; + if ((res_id >= 0) && + ((res_id > max_req_resource_id) || (! city_has_resource_r (city, res_id, max_req_resource_id)))) + return false; + } + return true; + } else { + int * targets = &improv->Resource1ID; + if ((targets[0] < 0) && (targets[1] < 0)) + return true; + int finds[2] = {0, 0}; + + int civ_id = city->Body.CivID; + for (int n = 0; n < is->workable_tile_count; n++) { + int dx, dy; + patch_ni_to_diff_for_work_area (n, &dx, &dy); + int x = city->Body.X + dx, y = city->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &x, &y); + Tile * tile = tile_at (x, y); + if (tile->vtable->m38_Get_Territory_OwnerID (tile) == civ_id) { + int res_here = Tile_get_resource_visible_to (tile, __, civ_id); + if (res_here >= 0) { + finds[0] |= targets[0] == res_here; + finds[1] |= targets[1] == res_here; + } + } + } + + return ((targets[0] < 0) || finds[0]) && ((targets[1] < 0) || finds[1]); + } +} + +bool +has_resources_required_by_building (City * city, int improv_id) +{ + return has_resources_required_by_building_r (city, improv_id, INT_MAX); +} + +void __fastcall +patch_City_recompute_commerce (City * this) +{ + City_recompute_commerce (this); + + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + int science_bonus = 0; + calculate_district_culture_science_bonuses (this, NULL, &science_bonus); + + if (science_bonus != 0) { + this->Body.Science += science_bonus; + if (this->Body.Science < 0) + this->Body.Science = 0; + } +} + +void __fastcall +patch_City_recompute_yields_and_happiness (City * this) +{ + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts && + ! is->distribution_hub_refresh_in_progress && + is->distribution_hub_totals_dirty) + recompute_distribution_hub_totals (); + + City_recompute_yields_and_happiness (this); +} + +void __fastcall +patch_City_update_culture (City * this) +{ + City_update_culture (this); + + if ((this == NULL) || ! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + int culture_bonus = 0; + calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); + + if (culture_bonus == 0) + return; + + int culture_income = this->Body.CultureIncome + culture_bonus; + if (culture_income < 0) + culture_income = 0; + this->Body.CultureIncome = culture_income; + + int civ_id = this->Body.CivID; + int total_culture = this->Body.Total_Cultures[civ_id] + culture_bonus; + if (total_culture < 0) + total_culture = 0; + this->Body.Total_Cultures[civ_id] = total_culture; + + City_recompute_cultural_level (this, __, '\0', '\0', '\0'); +} + +void __fastcall +patch_City_recompute_culture_income (City * this) +{ + City_recompute_culture_income (this); + + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + int culture_bonus = 0; + calculate_district_culture_science_bonuses (this, &culture_bonus, NULL); + + if (culture_bonus != 0) { + this->Body.CultureIncome += culture_bonus; + if (this->Body.CultureIncome < 0) + this->Body.CultureIncome = 0; + } +} + +// Recomputes yields in cities with active mills that depend on input resources. Intended to be called when an input resource has been potentially +// gained or lost. Recomputes only for the cities of a given leader or, if NULL, for all cities on the map. +void +recompute_mill_yields_after_resource_change (Leader * leader_or_null) +{ + if (p_cities->Cities != NULL) + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city != NULL) && + ((leader_or_null == NULL) || (city->Body.CivID == leader_or_null->ID))) { + bool any_relevant_mills = false; + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + Improvement * mill_improv = &p_bic_data->Improvements[mill->improv_id]; + if ((mill->flags & MF_YIELDS) && + ((mill_improv->Resource1ID >= 0) || (mill_improv->Resource2ID >= 0)) && + has_active_building (city, mill->improv_id)) { + any_relevant_mills = true; + break; + } + } + if (any_relevant_mills) + patch_City_recompute_yields_and_happiness (city); + } + } +} + + +int +resource_tile_resource_id (struct extra_resource_tile const * rt) +{ + if (rt == NULL) + return -1; + if (rt->type == ERT_MILL_RESOURCE) { + return (rt->mill_info.mill != NULL) ? rt->mill_info.mill->resource_id : -1; + } else if (rt->district_info.cfg != NULL) { + return rt->district_info.cfg->generated_resource_id; + } + return -1; +} + +int +compare_resource_tiles (void const * vp_a, void const * vp_b) +{ + struct extra_resource_tile const * a = vp_a, * b = vp_b; + return resource_tile_resource_id (a) - resource_tile_resource_id (b); +} + +void __fastcall +patch_Trade_Net_recompute_resources (Trade_Net * this, int edx, bool skip_popups) +{ + int extra_resource_count = not_below (0, p_bic_data->ResourceTypeCount - 32); + int ints_per_city = 1 + extra_resource_count/32; + memset (is->extra_available_resources, 0, is->extra_available_resources_capacity * ints_per_city * sizeof (unsigned)); + + // Assemble list of mill tiles + is->count_resource_tiles = 0; + if (p_cities->Cities != NULL) + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if (city != NULL) + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if (((mill->flags & MF_LOCAL) == 0) && + has_active_building (city, mill->improv_id) && + can_generate_resource (city->Body.CivID, mill)) { + Tile * resource_tile = tile_at (city->Body.X, city->Body.Y); + if ((resource_tile == NULL) || (resource_tile == p_null_tile)) + continue; + reserve (sizeof is->resource_tiles[0], + (void **)&is->resource_tiles, + &is->resource_tiles_capacity, + is->count_resource_tiles); + is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { + .tile = resource_tile, + .type = ERT_MILL_RESOURCE, + .mill_info = { + .city = city, + .mill = mill + } + }; + } + } + } + if (is->current_config.enable_districts) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * district_tile = (Tile *)tei.key; + struct district_instance * inst = (struct district_instance *)tei.value; + if ((district_tile == NULL) || (district_tile == p_null_tile) || (inst == NULL) || (inst->state != DS_COMPLETED)) + continue; + + int district_id = inst->district_id; + if ((district_id < 0) || (district_id >= is->district_count)) + continue; + + struct district_config * cfg = &is->district_configs[district_id]; + if ((cfg == NULL) || (cfg->generated_resource_id < 0)) + continue; + + int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); + if (owner_id < 0) + continue; + if ((cfg->generated_resource_flags & MF_LOCAL) != 0) + continue; + if (! district_can_generate_resource (owner_id, cfg)) + continue; + + reserve (sizeof is->resource_tiles[0], + (void **)&is->resource_tiles, + &is->resource_tiles_capacity, + is->count_resource_tiles); + is->resource_tiles[is->count_resource_tiles++] = (struct extra_resource_tile) { + .tile = district_tile, + .type = ERT_DISTRICT_RESOURCE, + .district_info = { + .inst = inst, + .cfg = cfg + } + }; + } + } + qsort (is->resource_tiles, is->count_resource_tiles, sizeof is->resource_tiles[0], compare_resource_tiles); + + is->got_resource_tile = NULL; + is->saved_tile_count = p_bic_data->Map.TileCount; + p_bic_data->Map.TileCount += is->count_resource_tiles; + Trade_Net_recompute_resources (this, __, skip_popups); + + // Restore the tile count if necessary. It may have already been restored by patch_Map_Renderer_m71_Draw_Tiles. This happens when the call to + // recompute_resources above opens a popup message about connecting a resource for the first time, which triggers redraw of the map. + if (is->saved_tile_count >= 0) { + p_bic_data->Map.TileCount = is->saved_tile_count; + is->saved_tile_count = -1; + } + + recompute_mill_yields_after_resource_change (NULL); + + is->must_recompute_resources_for_mill_inputs = false; +} + +Tile * +get_resource_tile (int index) +{ + struct extra_resource_tile * rt = &is->resource_tiles[index]; + is->got_resource_tile = rt; + return rt->tile; +} + +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_1 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_2 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_3 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_4 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } +Tile * __fastcall patch_Map_get_tile_when_recomputing_resources_5 (Map * map, int edx, int index) { return (index < is->saved_tile_count) ? Map_get_tile (map, __, index) : get_resource_tile (index - is->saved_tile_count); } + +int __fastcall +patch_Tile_get_visible_resource_when_recomputing (Tile * tile, int edx, int civ_id) +{ + if (is->got_resource_tile != NULL) { + struct extra_resource_tile * rt = is->got_resource_tile; + is->got_resource_tile = NULL; + if (rt->type == ERT_MILL_RESOURCE) { + if ((rt->mill_info.city != NULL) && (rt->mill_info.mill != NULL) && + has_resources_required_by_building (rt->mill_info.city, rt->mill_info.mill->improv_id)) + return rt->mill_info.mill->resource_id; + else + return -1; + } else { + Tile * district_tile = rt->tile; + struct district_instance * inst = rt->district_info.inst; + struct district_config * cfg = rt->district_info.cfg; + if ((district_tile != NULL) && (district_tile != p_null_tile) && (inst != NULL) && + (cfg != NULL) && (inst->state == DS_COMPLETED)) { + int owner_id = district_tile->vtable->m38_Get_Territory_OwnerID (district_tile); + if ((owner_id == civ_id) && district_generates_resource_for_civ (district_tile, inst, cfg, owner_id)) + return cfg->generated_resource_id; + } + return -1; + } + } + + int base_resource = Tile_get_resource_visible_to (tile, __, civ_id); + return base_resource; +} + +int WINAPI +patch_MessageBoxA (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) +{ + if (is->current_config.suppress_hypertext_links_exceeded_popup && + (strcmp (lpText, "Maximum hypertext links exceeded!") == 0)) + return IDOK; + else + return MessageBoxA (hWnd, lpText, lpCaption, uType); +} + +char * __fastcall +do_capture_modified_gold_trade (TradeOffer * trade_offer, int edx, int val, char * str, unsigned base) +{ + is->modifying_gold_trade = trade_offer; + return print_int (val, str, base); +} + +// Here the order of the registers matches the order that they're pushed by the pusha instruction +struct register_set { + int edi, esi, ebp, esp, ebx, edx, ecx, eax; +}; + +// Return 1 to allow the candidate unit to exert ZoC, 0 to exclude it. A pointer to the candidate is in esi. +int __stdcall +filter_zoc_candidate (struct register_set * reg) +{ + Unit * candidate = (Unit *)reg->esi, + * defender = is->zoc_defender; + + UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID], + * defender_type = &p_bic_data->UnitTypes[defender ->Body.UnitTypeID]; + + enum UnitTypeClasses candidate_class = candidate_type->Unit_Class, + defender_class = defender_type ->Unit_Class; + + bool lethal = ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) != 0) && (! is->temporarily_disallow_lethal_zoc); + bool aerial = (is->current_config.special_zone_of_control_rules & SZOCR_AERIAL ) != 0, + amphibious = (is->current_config.special_zone_of_control_rules & SZOCR_AMPHIBIOUS) != 0; + + // Exclude air units if aerial ZoC is not enabled and exclude land-to-sea & sea-to-land ZoC if amphibious is not enabled + if ((! aerial) && (candidate_class == UTC_Air)) + return 0; + if ((! amphibious) && + (((candidate_class == UTC_Land) && (defender_class == UTC_Sea )) || + ((candidate_class == UTC_Sea ) && (defender_class == UTC_Land)))) + return 0; + + // In case of cross-domain ZoC, filter out units with zero bombard strength or range. They can't use their attack strength in this case, so + // without bombard they can be ruled out. Don't forget units may have non-zero bombard strength and zero range for defensive bombard. + int range = (candidate_class != UTC_Air) ? candidate_type->Bombard_Range : candidate_type->OperationalRange; + if ((candidate_class != defender_class) && ((candidate_type->Bombard_Strength <= 0) || (range <= 0))) + return 0; + + // Require lethal config option & lethal bombard against one HP defender + if ((Unit_get_max_hp (defender) - defender->Body.Damage <= 1) && + ((! lethal) || + ((defender_class == UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Sea_Bombardment)) || + ((defender_class != UTC_Sea) && ! UnitType_has_ability (candidate_type, __, UTA_Lethal_Land_Bombardment)))) + return 0; + + // Air units require the bombing action to perform ZoC + if ((candidate_class == UTC_Air) && ! (candidate_type->Air_Missions & UCV_Bombing)) + return 0; + + // Exclude land units in transports if configured + if ((is->current_config.special_zone_of_control_rules & SZOCR_NOT_FROM_INSIDE) && candidate_class == UTC_Land) { + Unit * container = get_unit_ptr (candidate->Body.Container_Unit); + if ((container != NULL) && ! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)) + return 0; + } + + return 1; +} + +#define TRADE_NET_REF_COUNT 315 +#define TRADE_NET_INSTR_COUNT_GOG 22 +#define TRADE_NET_INSTR_COUNT_STEAM 23 +#define TRADE_NET_INSTR_COUNT_PCG 22 +#define TRADE_NET_ADDR_TOTAL_COUNT ((TRADE_NET_REF_COUNT * 3) + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM + TRADE_NET_INSTR_COUNT_PCG) + +int * +load_trade_net_addrs () +{ + if (is->trade_net_addrs_load_state == IS_OK) + return is->trade_net_addrs; + else if (is->trade_net_addrs_load_state == IS_INIT_FAILED) + return NULL; + + bool success = false; + char err_msg[300] = {0}; + + is->trade_net_addrs = calloc (3 * TRADE_NET_ADDR_TOTAL_COUNT, sizeof is->trade_net_addrs[0]); + if (! is->trade_net_addrs) { + snprintf (err_msg, (sizeof err_msg) - 1, "Bad alloc"); + goto done; + } + + char file_path[MAX_PATH] = {0}; + snprintf (file_path, (sizeof file_path) - 1, "%s\\trade_net_addresses.txt", is->mod_rel_dir); + char * refs_file = file_to_string (file_path); + if (! refs_file) { + snprintf (err_msg, (sizeof err_msg) - 1, "Couldn't load %s", file_path); + goto done; + } + + char * cursor = refs_file; + int loaded_count = 0; + while (true) { + if (*cursor == '#') { // comment line + skip_line (&cursor); + continue; + } + + skip_horiz_space (&cursor); + if (*cursor == '\n') { // empty line + cursor++; + continue; + } else if (*cursor == '\0') // end of file + break; + + // otherwise we must be on a line with some addresses + int ref; + bool got_any_addresses = false; + while (parse_int (&cursor, &ref)) { + if (loaded_count >= TRADE_NET_ADDR_TOTAL_COUNT) { + snprintf (err_msg, (sizeof err_msg) - 1, "Too many values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); + goto done; + } + is->trade_net_addrs[loaded_count] = ref; + loaded_count++; + got_any_addresses = true; + } + + if (! got_any_addresses) { + snprintf (err_msg, (sizeof err_msg) - 1, "Parse error"); + goto done; + } + } + + if (loaded_count < TRADE_NET_ADDR_TOTAL_COUNT) { + snprintf (err_msg, (sizeof err_msg) - 1, "Too few values in file (expected %d exactly)", TRADE_NET_ADDR_TOTAL_COUNT); + goto done; + } + + success = true; + +done: + free (refs_file); + if (! success) { + char full_err_msg[300] = {0}; + snprintf (full_err_msg, (sizeof full_err_msg) - 1, "Failed to load trade net refs: %s", err_msg); + MessageBox (NULL, full_err_msg, NULL, MB_ICONERROR); + is->trade_net_addrs_load_state = IS_INIT_FAILED; + return NULL; + } else { + is->trade_net_addrs_load_state = IS_OK; + return is->trade_net_addrs; + } +} + +unsigned short * __fastcall +patch_get_pixel_to_draw_city_dot (JGL_Image * this, int edx, int x, int y) +{ + unsigned short * tr = this->vtable->m07_m05_Get_Pixel (this, __, x, y); + + if ((x + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Width2) && (y + 1 < p_main_screen_form->GUI.Navigator_Data.Mini_Map_Height2)) { + unsigned short * below = this->vtable->m07_m05_Get_Pixel (this, __, x + 1, y + 1); + if (below != NULL) + *below = 0; + } + + return tr; +} + +enum branch_kind { BK_CALL, BK_JUMP }; + +byte * +emit_branch (enum branch_kind kind, byte * cursor, void const * target) +{ + int offset = (int)target - ((int)cursor + 5); + *cursor++ = (kind == BK_CALL) ? 0xE8 : 0xE9; + return int_to_bytes (cursor, offset); +} + +// Just calls VirtualProtect and displays an error message if it fails. Made for use by the WITH_MEM_PROTECTION macro. +bool +check_virtual_protect (LPVOID addr, SIZE_T size, DWORD flags, PDWORD old_protect) +{ + if (VirtualProtect (addr, size, flags, old_protect)) + return true; + else { + char err_msg[1000]; + snprintf (err_msg, sizeof err_msg, "VirtualProtect failed! Args:\n Address: 0x%p\n Size: %d\n Flags: 0x%x", addr, size, flags); + err_msg[(sizeof err_msg) - 1] = '\0'; + MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); + return false; + } +} + +#define WITH_MEM_PROTECTION(addr, size, flags) \ + for (DWORD old_protect, unused, iter_count = 0; \ + (iter_count == 0) && check_virtual_protect (addr, size, flags, &old_protect); \ + VirtualProtect (addr, size, old_protect, &unused), iter_count++) + +void __fastcall adjust_sliders_preproduction (Leader * this); + +struct saved_code_area { + int size; + byte original_contents[]; +}; + +// Saves an area of base game code and optionally replaces it with no-ops. The area can be restored with restore_code_area. This method assumes that +// the necessary memory protection has already been set on the area, specifically that it can be written to. The method will do nothing if the area +// has already been saved with the same size. It's an error to re-save an address with a different size or overlap two saved areas. +void +save_code_area (byte * addr, int size, bool nopify) +{ + struct saved_code_area * sca; + if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { + if (sca->size != 0) { + if (sca->size != size) { + char s[200]; + snprintf (s, sizeof s, "Save code area conflict: address %p was already saved with size %d, conflicting with new size %d.", addr, sca->size, size); + s[(sizeof s) - 1] = '\0'; + pop_up_in_game_error (s); + } + return; + } + } else { + sca = malloc (size + sizeof *sca); + itable_insert (&is->saved_code_areas, (int)addr, (int)sca); + } + sca->size = size; + memcpy (&sca->original_contents, addr, size); + if (nopify) + memset (addr, 0x90, size); +} + +// Restores a saved chunk of code to its original contents. Does nothing if the area hasn't been saved. Assumes the appropriate memory protection has +// already been set. +void +restore_code_area (byte * addr) +{ + struct saved_code_area * sca; + if (itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca)) { + memcpy (addr, &sca->original_contents, sca->size); + sca->size = 0; + } +} + +bool +is_code_area_saved (byte * addr) +{ + struct saved_code_area * sca; + return itable_look_up (&is->saved_code_areas, (int)addr, (int *)&sca) && (sca->size > 0); +} + +// Nopifies or restores an area depending on if yes_or_no is 1 or 0. Sets the necessary memory protections. +void +set_nopification (int yes_or_no, byte * addr, int size) +{ + WITH_MEM_PROTECTION (addr, size, PAGE_EXECUTE_READWRITE) { + if (yes_or_no) + save_code_area (addr, size, true); + else + restore_code_area (addr); + } +} + +void +apply_machine_code_edits (struct c3x_config const * cfg, bool at_program_start) +{ + DWORD old_protect, unused; + + // Allow stealth attack against single unit + WITH_MEM_PROTECTION (ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_STEALTH_ATTACK_TARGET_COUNT_CHECK = cfg->allow_stealth_attack_against_single_unit ? 0 : 1; + + // Enable small wonders providing free buildings + WITH_MEM_PROTECTION (ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER, 10, PAGE_EXECUTE_READWRITE) { + byte normal[8] = {0x83, 0xE1, 0x04, 0x80, 0xF9, 0x04, 0x0F, 0x85}; // and ecx, 4; cmp ecx, 4; jnz [offset] + byte modded[8] = {0x83, 0xE1, 0x0C, 0x80, 0xF9, 0x00, 0x0F, 0x84}; // and ecx, 12; cmp ecx, 0; jz [offset] + for (int n = 0; n < 8; n++) + ((byte *)ADDR_RECOMPUTE_AUTO_IMPROVS_FILTER)[n] = cfg->enable_free_buildings_from_small_wonders ? modded[n] : normal[n]; + } + + // Bypass artillery in city check + // replacing 0x74 (= jump if [city ptr is] zero) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_CHECK_ARTILLERY_IN_CITY, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_CHECK_ARTILLERY_IN_CITY = cfg->use_offensive_artillery_ai ? 0xEB : 0x74; + + // Remove unit limit + if (! at_program_start) { + // Replace 0x7C (= jump if less than [unit limit]) with 0xEB (= uncond. jump) in Leader::spawn_unit + WITH_MEM_PROTECTION (ADDR_UNIT_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_UNIT_COUNT_CHECK = cfg->remove_unit_limit ? 0xEB : 0x7C; + + // Increase max ID to search for tradable units by 10x if limit removed + WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_UNIT_ID, 4, PAGE_EXECUTE_READWRITE) + int_to_bytes (ADDR_MAX_TRADABLE_UNIT_ID, cfg->remove_unit_limit ? 81920 : 8192); + + // Reallocate diplo_form->tradable_units array so it's 10x long if limit removed + civ_prog_free (p_diplo_form->tradable_units); + int tradable_units_len = cfg->remove_unit_limit ? 81920 : 8192, + tradable_units_size = tradable_units_len * sizeof (TradableItem); + p_diplo_form->tradable_units = new (tradable_units_size); + for (int n = 0; n < tradable_units_len; n++) + p_diplo_form->tradable_units[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 + + // Patch the size limit on some code that clears the tradable units array when starting a new game + WITH_MEM_PROTECTION (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) + int_to_bytes (ADDR_TRADABLE_UNITS_SIZE_TO_CLEAR, tradable_units_size); + } + + // Remove the standard rule that blocks battle-created units while the player already has one + set_nopification (cfg->allow_multiple_battle_created_units_per_player, ADDR_EXISTING_BATTLE_CREATED_UNIT_CHECK, 6); + + // Bypass air unit check when drawing pedia stats. If it passes, the check will draw the op. range instead of movement in the first column. + // replacing 0x75 (= jnz) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS, 1, PAGE_EXECUTE_READWRITE) + *ADDR_AIR_UNIT_CHECK_TO_DRAW_PEDIA_STATS = is->current_config.expand_civilopedia_unit_stats ? 0xEB : 0x75; + + // Remove era limit + // replacing 0x74 (= jump if zero [after cmp'ing era count with 4]) with 0xEB + WITH_MEM_PROTECTION (ADDR_ERA_COUNT_CHECK, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_ERA_COUNT_CHECK = cfg->remove_era_limit ? 0xEB : 0x74; + + // Fix science age bug + // Similar in nature to the sub bug, the function that measures a city's research output accepts a flag that determines whether or not it + // takes science ages into account. It's mistakenly not set by the code that gathers all research points to increment tech progress (but it + // is set elsewhere in code for the interface). The patch simply sets this flag. + WITH_MEM_PROTECTION (ADDR_SCIENCE_AGE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_SCIENCE_AGE_BUG_PATCH = cfg->patch_science_age_bug ? 1 : 0; + + // Pedia pink line bug fix + // The size of the pedia background texture is hard-coded into the EXE and in the base game it's one pixel too small. This shows up in game as + // a one pixel wide pink line along the right edge of the civilopedia. This patch simply increases the texture width by one. + WITH_MEM_PROTECTION (ADDR_PEDIA_TEXTURE_BUG_PATCH, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_PEDIA_TEXTURE_BUG_PATCH = cfg->patch_pedia_texture_bug ? 0xA6 : 0xA5; + + // Fix for houseboat bug + // See my posts on CFC for an explanation of the bug and its fix: + // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16084386 + // https://forums.civfanatics.com/threads/sub-bug-fix-and-other-adventures-in-exe-modding.666881/page-10#post-16085242 + WITH_MEM_PROTECTION (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, PAGE_EXECUTE_READWRITE) { + if (cfg->patch_houseboat_bug) { + save_code_area (ADDR_HOUSEBOAT_BUG_PATCH, ADDR_HOUSEBOAT_BUG_PATCH_END - ADDR_HOUSEBOAT_BUG_PATCH, true); + byte * cursor = ADDR_HOUSEBOAT_BUG_PATCH; + *cursor++ = 0x50; // push eax + int call_offset = (int)&tile_at_city_or_null - ((int)cursor + 5); + *cursor++ = 0xE8; // call + cursor = int_to_bytes (cursor, call_offset); + } else + restore_code_area (ADDR_HOUSEBOAT_BUG_PATCH); + } + + // NoRaze + WITH_MEM_PROTECTION (ADDR_AUTORAZE_BYPASS, 2, PAGE_EXECUTE_READWRITE) { + byte normal[2] = {0x0F, 0x85}; // jnz + byte bypass[2] = {0x90, 0xE9}; // nop, jmp + for (int n = 0; n < 2; n++) + ((byte *)ADDR_AUTORAZE_BYPASS)[n] = cfg->prevent_autorazing ? bypass[n] : normal[n]; + } + + // Overwrite the instruction(s) where the AI's production choosing code compares the value of what it's currently considering to the best + // option so far. This is done twice since improvements and units are handled in separate loops. The instr(s) are overwritten with a jump to + // an "airlock", which is a bit of code that wraps the call to intercept_consideration. The contents of the airlocks are prepared by the + // patcher in init_consideration_airlocks. + // TODO: This instruction replacement could be done in the patcher too and that might be a better place for it. Think about this. + for (int n = 0; n < 2; n++) { + void * addr_intercept = (n == 0) ? ADDR_INTERCEPT_AI_IMPROV_VALUE : ADDR_INTERCEPT_AI_UNIT_VALUE; + void * addr_airlock = (n == 0) ? ADDR_IMPROV_CONSIDERATION_AIRLOCK : ADDR_UNIT_CONSIDERATION_AIRLOCK; + + WITH_MEM_PROTECTION (addr_intercept, AI_CONSIDERATION_INTERCEPT_LEN, PAGE_EXECUTE_READWRITE) { + byte * cursor = addr_intercept; + + // write jump to airlock + *cursor++ = 0xE9; + int offset = (int)addr_airlock - ((int)addr_intercept + 5); + cursor = int_to_bytes (cursor, offset); + + // fill the rest of the space with NOPs + while (cursor < (byte *)addr_intercept + AI_CONSIDERATION_INTERCEPT_LEN) + *cursor++ = 0x90; // nop + } + } + + // Overwrite instruction that sets bits in City.Body.Available_Resources with a jump to the airlock + WITH_MEM_PROTECTION (ADDR_INTERCEPT_SET_RESOURCE_BIT, 6, PAGE_EXECUTE_READWRITE) { + byte * cursor = ADDR_INTERCEPT_SET_RESOURCE_BIT; + if (cfg->patch_phantom_resource_bug) { + *cursor++ = 0xE9; + int offset = (int)ADDR_SET_RESOURCE_BIT_AIRLOCK - ((int)ADDR_INTERCEPT_SET_RESOURCE_BIT + 5); + cursor = int_to_bytes (cursor, offset); + *cursor++ = 0x90; // nop + } else { + byte original[6] = {0x09, 0xB0, 0x9C, 0x00, 0x00, 0x00}; // or dword ptr [eax+0x9C], esi + for (int n = 0; n < 6; n++) + cursor[n] = original[n]; + } + } + + // Enlarge the mask that's applied to p_bic_data->Map.TileCount in the loop over lines in Trade_Net::recompute_resources. This lets us loop + // over more than 0xFFFF tiles. + WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_MASK, 1, PAGE_EXECUTE_READWRITE) { + *(byte *)ADDR_RESOURCE_TILE_COUNT_MASK = (cfg->count_mills > 0) ? 0xFF : 0x00; + } + // Similarly, enlarge the cmp instruction that jumps over the entire loop when the tile count is zero. Do this by simply removing the operand + // override prefix byte (0x66), overwriting it with a nop (0x90). This converts the instruction "cmp word ptr [bic_data.Map.TileCount], di" + // into "nop; cmp dword ptr [bic_data.Map.TileCount], edi" + WITH_MEM_PROTECTION (ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE, 1, PAGE_EXECUTE_READWRITE) { + *(byte *)ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE = 0x90; + } + + byte * addr_turn_metalimits[] = {ADDR_TURN_METALIMIT_1, ADDR_TURN_METALIMIT_2, ADDR_TURN_METALIMIT_3, ADDR_TURN_METALIMIT_4, + ADDR_TURN_METALIMIT_5, ADDR_TURN_METALIMIT_6, ADDR_TURN_METALIMIT_7}; + for (int n = 0; n < ARRAY_LEN (addr_turn_metalimits); n++) { + byte * addr = addr_turn_metalimits[n]; + WITH_MEM_PROTECTION (addr, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (addr, cfg->remove_cap_on_turn_limit ? 1000000 : 1000); + } + } + + // Overwrite the human-ness test and call to Leader::ai_adjust_sliders that happens during the preproduction player update method. The new + // code calls adjust_sliders_preproduction for all players. + WITH_MEM_PROTECTION (ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT, 9, PAGE_EXECUTE_READWRITE) { + byte * cursor = ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT; + *cursor++ = 0x8B; *cursor++ = 0xCE; // mov ecx, esi + cursor = emit_branch (BK_CALL, cursor, adjust_sliders_preproduction); + for (; cursor < ADDR_AI_PREPRODUCTION_SLIDER_ADJUSTMENT + 9; cursor++) + *cursor = 0x90; // nop + } + + // Set up a special intercept of the base game's calls to print_int in order to grab a pointer to a gold TradeOffer object being modified. The + // calls to print_int happen in the context of creating the default text to be placed in the set-gold-amount popup. Conveniently, a pointer to + // the TradeOffer object is always stored in register ecx when this call happens. It's not easily accessible since print_int uses the cdecl + // convention so we must use an airlock-like thing to effectively convert the calling convention to fastcall. The first part of this code + // simply replaces the call to print_int with a call to the airlock-like thing, and the second part initializes its contents. + byte * addr_print_gold_amounts[] = {ADDR_PRINT_GOLD_AMOUNT_1, ADDR_PRINT_GOLD_AMOUNT_2}; + for (int n = 0; n < ARRAY_LEN (addr_print_gold_amounts); n++) { + byte * addr = addr_print_gold_amounts[n]; + WITH_MEM_PROTECTION (addr, 5, PAGE_EXECUTE_READWRITE) + emit_branch (BK_CALL, addr, ADDR_CAPTURE_MODIFIED_GOLD_TRADE); + } + WITH_MEM_PROTECTION (ADDR_CAPTURE_MODIFIED_GOLD_TRADE, 32, PAGE_EXECUTE_READWRITE) { + byte * cursor = ADDR_CAPTURE_MODIFIED_GOLD_TRADE; + + // Repush all of the arguments to print_int onto the stack, they will be consumed by do_capture_modified_gold_trade since it's + // fastcall. The original args don't need to be removed b/c we're replacing a cdecl function so that's the caller's + // responsibility. The TradeOffer pointer is already in ECX, so that's fine as long as we don't touch that register. + byte repush[] = {0xFF, 0x74, 0x24, 0x0C}; // push [esp+0xC] + for (int n = 0; n < 3; n++) + for (int k = 0; k < ARRAY_LEN (repush); k++) + *cursor++ = repush[k]; + + cursor = emit_branch (BK_CALL, cursor, do_capture_modified_gold_trade); // call do_capture_modified_gold_trade + *cursor++ = 0xC3; // ret + } + + // Edit branch in capture_city to never run code for barbs, this allows barbs to capture cities + WITH_MEM_PROTECTION (ADDR_CAPTURE_CITY_BARB_BRANCH, 2, PAGE_EXECUTE_READWRITE) { + byte normal[2] = {0x0F, 0x85}; // jnz + byte bypass[2] = {0x90, 0xE9}; // nop, jmp + for (int n = 0; n < 2; n++) + ((byte *)ADDR_CAPTURE_CITY_BARB_BRANCH)[n] = cfg->enable_city_capture_by_barbarians ? bypass[n] : normal[n]; + } + + // After the production phase is done for the barb player, there are two jump instructions skipping the production code for civs. Replacing + // those jumps lets us run the civ production code for the barbs as well. + WITH_MEM_PROTECTION (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, PAGE_EXECUTE_READWRITE) { + if (cfg->enable_city_capture_by_barbarians) { + save_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP, 6, true); + byte jump_to_civ[6] = {0x0F, 0x8D, 0x0C, 0x00, 0x00, 0x00}; // jge +0x12 + for (int n = 0; n < 6; n++) + ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP[n] = jump_to_civ[n]; + } else + restore_code_area (ADDR_PROD_PHASE_BARB_DONE_NO_SPAWN_JUMP); + } + set_nopification (cfg->enable_city_capture_by_barbarians, ADDR_PROD_PHASE_BARB_DONE_JUMP, 5); + + for (int domain = 0; domain < 2; domain++) { + byte * addr_skip = (domain == 0) ? ADDR_SKIP_LAND_UNITS_FOR_SEA_ZOC : ADDR_SKIP_SEA_UNITS_FOR_LAND_ZOC, + * addr_airlock = (domain == 0) ? ADDR_SEA_ZOC_FILTER_AIRLOCK : ADDR_LAND_ZOC_FILTER_AIRLOCK; + + WITH_MEM_PROTECTION (addr_skip, 6, PAGE_EXECUTE_READWRITE) { + if ((cfg->special_zone_of_control_rules != 0) && ! is_code_area_saved (addr_skip)) { + byte * original_target = addr_skip + 6 + int_from_bytes (addr_skip + 2); // target addr of jump instr we're replacing + save_code_area (addr_skip, 6, true); + + // Initialize airlock. The airlock preserves all registers and calls filter_zoc_candidate then either follows or skips the + // original jump depending on what it returns. If zero is returned, follows the jump, skipping a bunch of code and filtering + // out the unit as a candidate for ZoC. + WITH_MEM_PROTECTION (addr_airlock, INLEAD_SIZE, PAGE_READWRITE) { + byte * cursor = addr_airlock; + *cursor++ = 0x60; // pusha + *cursor++ = 0x54; // push esp + cursor = emit_branch (BK_CALL, cursor, filter_zoc_candidate); + *cursor++ = 0x83; *cursor++ = 0xF8; *cursor++ = 0x01; // cmp eax, 1 + *cursor++ = 0x75; *cursor++ = 0x06; // jne 6 + *cursor++ = 0x61; // popa + cursor = emit_branch (BK_JUMP, cursor, addr_skip + 6); + *cursor++ = 0x61; // popa + cursor = emit_branch (BK_JUMP, cursor, original_target); + } + + // Write jump to airlock + emit_branch (BK_JUMP, addr_skip, addr_airlock); + } else if (cfg->special_zone_of_control_rules == 0) + restore_code_area (addr_skip); + } + } + + set_nopification ( cfg->special_zone_of_control_rules != 0, ADDR_ZOC_CHECK_ATTACKER_ANIM_FIELD_111, 6); + set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_LAND_UNIT , 6); + set_nopification ((cfg->special_zone_of_control_rules & SZOCR_LETHAL) != 0, ADDR_SKIP_ZOC_FOR_ONE_HP_SEA_UNIT , 6); + + WITH_MEM_PROTECTION (ADDR_LUXURY_BOX_ROW_HEIGHT, 4, PAGE_EXECUTE_READWRITE) { + byte normal [4] = {0x8B, 0x44, 0x24, LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET}; // mov eax, dword ptr [esp + LUXURY_BOX_ROW_HEIGHT_STACK_OFFSET] + byte compact[4] = {0x31, 0xC0, 0xB0, 0x10}; // xor eax, eax; mov al, 0x10 + for (int n = 0; n < 4; n++) + ADDR_LUXURY_BOX_ROW_HEIGHT[n] = cfg->compact_luxury_display_on_city_screen ? compact[n] : normal[n]; + } + + WITH_MEM_PROTECTION (ADDR_MOST_STRAT_RES_ON_CITY_SCREEN, 1, PAGE_EXECUTE_READWRITE) { + *(byte *)ADDR_MOST_STRAT_RES_ON_CITY_SCREEN = cfg->compact_strategic_resource_display_on_city_screen ? 13 : 8; + } + + // Remove a check that a returned neighbor index is within the 21 tile work area in code related to hoving the mouse over the work area on the + // city screen. This check is redundant and could be removed always, but only do so if work area is expanded. + set_nopification (cfg->city_work_radius > 2, ADDR_REDUNDANT_CHECK_ON_WORK_AREA_HOVER, 6); + + // Skip redundant check of clicked tile's neighbor index in City_Form::handle_left_click. + WITH_MEM_PROTECTION (ADDR_CITY_FORM_LEFT_CLICK_JUMP, 1, PAGE_EXECUTE_READWRITE) { + *ADDR_CITY_FORM_LEFT_CLICK_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) + } + + // Skip check that neighbor index passed to City::controls_tile is within work radius. This check is now implemented in the patch func. + WITH_MEM_PROTECTION (ADDR_CONTROLS_TILE_JUMP, 1, PAGE_EXECUTE_READWRITE) { + *ADDR_CONTROLS_TILE_JUMP = 0xEB; // 0x7C (jl) -> 0xEB (jmp) + } + + // When searching for a tile on which to spawn pollution, the game wraps its search around by using remainder after division. Here, we replace + // the dividend to match a potentially expanded city work area. + WITH_MEM_PROTECTION (ADDR_SPAWN_POLLUTION_MOD, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_SPAWN_POLLUTION_MOD, is->workable_tile_count - 1); + } + + WITH_MEM_PROTECTION (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_PATHFINDER_RECONSTRUCTION_MAX_LEN, cfg->patch_premature_truncation_of_found_paths ? 2560 : 256); + } + + int * trade_net_addrs; + bool already_moved_trade_net = is->trade_net != p_original_trade_net, + want_moved_trade_net = cfg->city_limit > 512; + int lifted_city_limit_exp = 11; + int lifted_city_limit = 1 << lifted_city_limit_exp; + if ((! at_program_start) && + ((trade_net_addrs = load_trade_net_addrs ()) != NULL) && + ((already_moved_trade_net && ! want_moved_trade_net) || (want_moved_trade_net && ! already_moved_trade_net))) { + // Allocate a new trade net object if necessary. To construct it, all we have to do is zero a few fields and set the vptr. Otherwise, + // set the allocated object aside for deletion later. Also set new & old addresses to the locations we're moving to & from. + Trade_Net * to_free = NULL; + int p_old, p_new; + if (want_moved_trade_net) { + is->trade_net = calloc (1, (sizeof (Trade_Net)) - (4 * 512 * 512) + (4 * lifted_city_limit * lifted_city_limit)); + is->city_limit = lifted_city_limit; + is->trade_net->vtable = p_original_trade_net->vtable; + p_old = (int)p_original_trade_net; + p_new = (int)is->trade_net; + } else { + to_free = is->trade_net; + is->city_limit = 512; + p_old = (int)is->trade_net; + p_new = (int)p_original_trade_net; + is->trade_net = p_original_trade_net; + } + already_moved_trade_net = is->trade_net != p_original_trade_net; // Keep this variable up to date + + // Patch all references from the "old" object to the "new" one + int offset; + bool popped_up_error = false; + char err_msg[200] = {0}; + int * refs; { + if (exe_version_index == 0) + refs = trade_net_addrs; + else if (exe_version_index == 1) // Steam version, skip refs and instructions for GOG + refs = &trade_net_addrs[TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; + else // PCGames.de version, skip two sets of refs and instrs for GOG & Steam + refs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; + } + for (int n_ref = 0; n_ref < TRADE_NET_REF_COUNT; n_ref++) { + int addr = refs[n_ref]; + WITH_MEM_PROTECTION ((void *)(addr - 10), 20, PAGE_EXECUTE_READWRITE) { + byte * instr = (byte *)addr; + if ((instr[0] == 0xB9) && (int_from_bytes (&instr[1]) == p_old)) // move trade net ptr to ecx + int_to_bytes (&instr[1], p_new); + else if ((instr[0] == 0xC7) && (instr[1] == 0x05) && (int_from_bytes (&instr[2]) == p_old)) // write trade net vtable ptr + int_to_bytes (&instr[2], p_new); + else if ((instr[0] == 0x81) && (instr[1] == 0xFE) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp esi, trade net location + ; // Do not patch this location because it's the upper limit for a memcpy + else if ((instr[0] == 0x81) && (instr[1] == 0xFF) && (int_from_bytes (&instr[2]) == (int)p_original_trade_net)) // cmp edi, trade net location + ; // Same + else if ((instr[0] == 0x81) && (instr[1] == 0xFA) && (int_from_bytes (&instr[2]) == (int)&p_original_trade_net->Data2)) // cmp edx, trade net data2 location + ; // Same + else if (((instr[0] == 0xA3) || (instr[0] == 0xA1)) && // move eax to field or vice-versa + (offset = int_from_bytes (&instr[1]) - p_old, (offset >= 0) && (offset < 100))) + int_to_bytes (&instr[1], p_new + offset); + else if ((instr[0] == 0x89) && ((instr[1] >= 0x0D) && (instr[1] <= 0x3D)) && // move other regs to field + (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) + int_to_bytes (&instr[2], p_new + offset); + else if ((instr[0] == 0x8B) && ((instr[1] == 0x35) || (instr[1] == 0x3D) || (instr[1] == 0x0D)) && // mov field to esi, edi or ecx + (offset = int_from_bytes (&instr[2]) - p_old, (offset >= 0) && (offset < 100))) + int_to_bytes (&instr[2], p_new + offset); + else if (! popped_up_error) { + snprintf (err_msg, (sizeof err_msg) - 1, "Can't move trade net object from address 0x%x. Pattern doesn't match.", addr); + MessageBox (NULL, err_msg, NULL, MB_ICONERROR); + popped_up_error = true; + } + } + } + + // Patch all instructions that involve the stride of Trade_Net.Matrix + int * addrs, addr_count; { + if (exe_version_index == 0) { + addrs = &trade_net_addrs[TRADE_NET_REF_COUNT]; + addr_count = TRADE_NET_INSTR_COUNT_GOG; + } else if (exe_version_index == 1) { + addrs = &trade_net_addrs[2 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG]; + addr_count = TRADE_NET_INSTR_COUNT_STEAM; + } else { + addrs = &trade_net_addrs[3 * TRADE_NET_REF_COUNT + TRADE_NET_INSTR_COUNT_GOG + TRADE_NET_INSTR_COUNT_STEAM]; + addr_count = TRADE_NET_INSTR_COUNT_GOG; + } + for (int n = 0; n < addr_count; n++) { + byte * instr = (byte *)addrs[n]; + WITH_MEM_PROTECTION (instr, 10, PAGE_EXECUTE_READWRITE) { + if (! want_moved_trade_net) + restore_code_area (instr); + + else { + if ((instr[0] == 0xC1) && (instr[1] >= 0xE0) && (instr[1] <= 0xE7)) { // shl + save_code_area (instr, 3, false); + // shift amount is either 9 (1<<9 == 512) or 11 (1<<11 == 4*512, stride in bytes) + // in the second case, replace with lifted_exp + 2 to convert to bytes + instr[2] = lifted_city_limit_exp + ((instr[2] == 11) ? 2 : 0); + + } else if ((instr[0] == 0x81) && (instr[1] >= 0xC0) && (instr[1] <= 0xC7)) { // add + save_code_area (instr, 6, false); + int amount = int_from_bytes (&instr[2]); + // amount is either 512 or 4*512, replace with lifted_lim or 4*lifted_lim + int_to_bytes (&instr[2], (amount == 512) ? lifted_city_limit : 4*lifted_city_limit); + + } else if ((instr[0] == 0x8D) && (instr[1] == 0x9C) && (instr[2] == 0x90)) { // lea + save_code_area (instr, 7, false); + int offset = 4 * lifted_city_limit + 0x38; // stride in bytes plus 0x38 offset to Matrix in Trade_Net object + int_to_bytes (&instr[3], offset); + + } else if (instr[0] == 0xB9) { // mov + save_code_area (instr, 5, false); + int_to_bytes (&instr[1], lifted_city_limit * lifted_city_limit); + + } else if (! popped_up_error) { + snprintf (err_msg, (sizeof err_msg) - 1, "Can't patch matrix stride at address 0x%x. Pattern doesn't match.", (int)instr); + MessageBox (NULL, err_msg, NULL, MB_ICONERROR); + popped_up_error = true; + } + } + } + } + } + + // Reallocate diplo_form->tradable_cities array so it matches the city limit + civ_prog_free (p_diplo_form->tradable_cities); + int tradable_cities_len = want_moved_trade_net ? lifted_city_limit : 512, + tradable_cities_size = tradable_cities_len * sizeof (TradableItem); + p_diplo_form->tradable_cities = new (tradable_cities_size); + for (int n = 0; n < tradable_cities_len; n++) + p_diplo_form->tradable_cities[n] = (TradableItem) {.label = (char *)-1, 0}; // clear label to -1 and other fields to 0 + + // Patch the size limit on some code that clears the tradable cities array when starting a new game + WITH_MEM_PROTECTION (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_TRADABLE_CITIES_SIZE_TO_CLEAR, tradable_cities_size); + } + + if (to_free) { + to_free->vtable->destruct (to_free, __, 0); + free (to_free); + } + } + + // Set is->city_limit and patch two instructions that contain the limit + is->city_limit = clamp (0, already_moved_trade_net ? lifted_city_limit : 512, cfg->city_limit); + WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN, 6, PAGE_EXECUTE_READWRITE) { + int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CONT_BEGIN_TURN[2], is->city_limit); + } + WITH_MEM_PROTECTION (ADDR_CITY_LIM_CMP_IN_CREATE_CITY, 5, PAGE_EXECUTE_READWRITE) { + int_to_bytes (&ADDR_CITY_LIM_CMP_IN_CREATE_CITY[1], is->city_limit); + } + WITH_MEM_PROTECTION (ADDR_MAX_TRADABLE_CITY_ID, 4, PAGE_EXECUTE_READWRITE) { + int_to_bytes (ADDR_MAX_TRADABLE_CITY_ID, already_moved_trade_net ? lifted_city_limit : 512); + } + + WITH_MEM_PROTECTION (ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR, 6, PAGE_EXECUTE_READWRITE) { + byte * instr = ADDR_CULTURE_DOUBLING_TIME_CMP_INSTR; + if (cfg->years_to_double_building_culture == 1000) + restore_code_area (instr); + else { + if (instr[0] == 0x3D) { // in GOG and PCG EXEs, instr is cmp eax, 0x3E8 + save_code_area (instr, 5, false); + int_to_bytes (&instr[1], cfg->years_to_double_building_culture); + } else if (instr[0] == 0x3B) { // in Steam EXE, instr is cmp eax, dword ptr 0x688C9C + save_code_area (instr, 6, true); + instr[0] = 0x3D; + int_to_bytes (&instr[1], cfg->years_to_double_building_culture); + } + } + } + + WITH_MEM_PROTECTION (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, PAGE_EXECUTE_READWRITE) { + if (cfg->accentuate_cities_on_minimap) { + save_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, 5, false); + emit_branch (BK_JUMP, ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT, ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL); + } else + restore_code_area (ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT); + } + WITH_MEM_PROTECTION (ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { + byte * code = ADDR_INLEAD_FOR_CITY_DOT_DRAW_PIXEL_REPL; + code[0] = 0x55; code[1] = 0x53; // write push ebp and push ebx, two overwritten instrs before the call + emit_branch (BK_CALL, &code[2], &patch_get_pixel_to_draw_city_dot); // call patch func + emit_branch (BK_JUMP, &code[7], ADDR_GET_PIXEL_FOR_DRAW_CITY_DOT + 5); // jump back to original code + } + + // Bypass adjacent resource of different type check + // replacing 0x7D (= jge) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9, 1, PAGE_EXECUTE_READWRITE) + *(byte *)ADDR_RES_CHECK_JUMP_TILE_INDEX_AT_LEAST_9 = cfg->allow_adjacent_resources_of_different_types ? 0xEB : 0x7D; + + WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, PAGE_EXECUTE_READWRITE) { + if (cfg->tiles_per_non_luxury_resource == 32) + restore_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV); + else { + save_code_area (ADDR_RESOURCE_GEN_TILE_COUNT_DIV, 7, true); + + // Jump to replacement division logic, kept in an inlead because it doesn't fit in 7 bytes + emit_branch (BK_JUMP, ADDR_RESOURCE_GEN_TILE_COUNT_DIV, ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL); + + // Fill in the replacement division logic. Instead of computing tile_count>>5, compute tile_count/cfg->tiles_per_non_luxury_resource. + WITH_MEM_PROTECTION (ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL, INLEAD_SIZE, PAGE_EXECUTE_READWRITE) { + int d = not_below (1, cfg->tiles_per_non_luxury_resource); + byte d0 = d & 0xFF, + d1 = (d >> 8) & 0xFF, + d2 = (d >> 16) & 0xFF, + d3 = d >> 24; + + byte * cursor = ADDR_RESOURCE_GEN_TILE_COUNT_DIV_REPL; + + // In the Steam EXE, the limit (tile_count/32 by default) must be left in ecx. For the other EXEs, edx. + if (exe_version_index == 1) { + byte new_div[] = { + 0x50, // push eax + 0x52, // push edx + 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count + 0x0F, 0xB7, 0xD2, // movzx edx, dx + 0x89, 0xD0, // mov eax, edx + 0x31, 0xD2, // xor edx, edx + 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} + 0xF7, 0xF1, // div ecx + 0x89, 0xC1, // mov ecx, eax + 0x5A, // pop edx + 0x58 // pop eax + }; + for (int n = 0; n < ARRAY_LEN (new_div); n++) + *cursor++ = new_div[n]; + + } else { + byte new_div[] = { + 0x50, // push eax + 0x51, // push ecx + 0x66, 0x8B, 0x56, 0x40, // mov dx, word ptr [esi+0x40] # Loads tile count + 0x0F, 0xB7, 0xD2, // movzx edx, dx + 0x89, 0xD0, // mov eax, edx + 0x31, 0xD2, // xor edx, edx + 0xB9, d0, d1, d2, d3, // mov ecx, {{divisor}} + 0xF7, 0xF1, // div ecx + 0x89, 0xC2, // mov edx, eax + 0x59, // pop ecx + 0x58 // pop eax + }; + for (int n = 0; n < ARRAY_LEN (new_div); n++) + *cursor++ = new_div[n]; + } + + cursor = emit_branch (BK_JUMP, cursor, ADDR_RESOURCE_GEN_TILE_COUNT_DIV + 7); + } + } + } + + // Disable a jump that skips playing victory animations for air units if they've been configured to have a victory anim + set_nopification (cfg->aircraft_victory_animation != NULL, ADDR_SKIP_VICTORY_ANIM_IF_AIR, 6); + + // Bypass capital check to return zero corruption + // replacing 0x75 (= jnz) with 0xEB (= uncond. jump) + WITH_MEM_PROTECTION (ADDR_CORRUPTION_CAPITAL_CHECK, 1, PAGE_EXECUTE_READWRITE) + *ADDR_CORRUPTION_CAPITAL_CHECK = cfg->allow_corruption_in_capital ? 0xEB : 0x75; + + // Insert amount added to building decorruption effect just for the capital + WITH_MEM_PROTECTION (ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT, 3, PAGE_EXECUTE_READWRITE) + *(ADDR_ADD_CAPITAL_CORRUPTION_BUILDING_EFFECT + 2) = clamp (0, 100, cfg->special_capital_decorruption_effect); +} + +void +get_mod_art_path (char const * file_name, char * out_path, int path_buf_size) +{ + char s[1000]; + snprintf (s, sizeof s, "Art\\%s", file_name); + s[(sizeof s) - 1] = '\0'; + + char * scenario_path = BIC_get_asset_path (p_bic_data, __, s, false); + if (0 != strcmp (scenario_path, s)) // get_asset_path returns its input when the file is not found + snprintf (out_path, path_buf_size, "%s", scenario_path); + else + snprintf (out_path, path_buf_size, "%s\\Art\\%s", is->mod_rel_dir, file_name); + out_path[path_buf_size - 1] = '\0'; +} + + +Sprite* +SpriteList_at(SpriteList *list, int i) { + return &list->field_0[i]; +} + +void +set_path(String260 *dst, const char *p) { + snprintf(dst->S, sizeof(dst->S), "%s", p); +} + +void +slice_grid(Sprite *out, PCX_Image *img, + int tile_w, int tile_h, int full_w, int full_h) +{ + for (int y = 0; y < full_h; y += tile_h) + for (int x = 0; x < full_w; x += tile_w) + Sprite_slice_pcx(out++, __, img, x, y, tile_w, tile_h, 1, 1); +} + +void +slice_grid_into_list(SpriteList *bucket, PCX_Image *img, + int tile_w, int tile_h, int full_w, int full_h) +{ + int k = 0; + for (int y = 0; y < full_h; y += tile_h) + for (int x = 0; x < full_w; x += tile_w) + Sprite_slice_pcx(SpriteList_at(bucket, k++), __, img, x, y, tile_w, tile_h, 1, 1); +} + +void +join_path(char *out, size_t out_sz, const char *dir, const char *file) +{ + size_t n = strlen(dir); + int need_sep = (n > 0 && dir[n-1] != '/' && dir[n-1] != '\\'); + snprintf(out, out_sz, "%s%s%s", dir, need_sep ? "\\" : "", file); +} + +void +read_in_dir(PCX_Image *img, + const char *art_dir, + const char *filename, + String260 *store) { + char pbuf[512]; + join_path(pbuf, sizeof pbuf, art_dir, filename); + if (store) { + // assumes: typedef struct { char S[260]; } String260; + snprintf(store->S, sizeof store->S, "%s", pbuf); + } + + char temp_path[2*MAX_PATH]; + + snprintf(temp_path, sizeof temp_path, "%s\\%s", art_dir, filename); + PCX_Image_read_file(img, __, temp_path, NULL, 0, 0x100, 2); +} + +bool load_day_night_hour_images(struct day_night_cycle_img_set *this, const char *art_dir, const char *hour) +{ + char ss[200]; + PCX_Image img; + PCX_Image_construct(&img); + + // Std terrain (9 sheets): 6x9 of 128x64 over 0x480x0x240 + const char *STD_SHEETS[9] = { + "xtgc.pcx", "xpgc.pcx", "xdgc.pcx", "xdpc.pcx", "xdgp.pcx", "xggc.pcx", + "wCSO.pcx", "wSSS.pcx", "wOOO.pcx" + }; + for (int i = 0; i < 9; ++i) { + read_in_dir(&img, art_dir, STD_SHEETS[i], NULL); + if (img.JGL.Image == NULL) return false; + slice_grid_into_list(&this->Std_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); + } + + // LM terrain (9): same slicing + const char *LMT_SHEETS[9] = { + "lxtgc.pcx", "lxpgc.pcx", "lxdgc.pcx", "lxdpc.pcx", "lxdgp.pcx", "lxggc.pcx", + "lwCSO.pcx", "lwSSS.pcx", "lwOOO.pcx" + }; + for (int i = 0; i < 9; ++i) { + read_in_dir(&img, art_dir, LMT_SHEETS[i], NULL); + if (img.JGL.Image == NULL) return false; + slice_grid_into_list(&this->LM_Terrain_Images[i], &img, 0x80, 0x40, 0x480, 0x240); + } + + // Polar icecaps: 8x4 of 128x64 + read_in_dir(&img, art_dir, "polarICEcaps-final.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Polar_Icecaps_Images, &img, 0x80, 0x40, 0x400, 0x100); + + // Hills / LM Hills: 4x3 of 128x72 + read_in_dir(&img, art_dir, "xhills.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); + read_in_dir(&img, art_dir, "hill forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Hills_Forests_Images, &img, 0x80, 0x48, 0x200, 0x120); + read_in_dir(&img, art_dir, "hill jungle.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Hills_Jungle_Images, &img, 0x80, 0x48, 0x200, 0x120); + read_in_dir(&img, art_dir, "LMHills.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->LM_Hills_Images, &img, 0x80, 0x48, 0x200, 0x120); + + // Flood plains: 4x4 of 128x64 + read_in_dir(&img, art_dir, "floodplains.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Flood_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); + + // Delta + Mountain rivers: 4x4 each, interleaved across one contiguous block + { + const char *RIV_SHEETS[2] = { "deltaRivers.pcx", "mtnRivers.pcx" }; + Sprite *contig = this->Delta_Rivers_Images; // Mountain_Rivers_Images follows + for (int s = 0; s < 2; ++s) { + read_in_dir(&img, art_dir, RIV_SHEETS[s], NULL); + if (img.JGL.Image == NULL) return false; + Sprite *p = contig + s; // even=delta, odd=mountain + for (int y = 0; y < 0x100; y += 0x40) + for (int x = 0; x < 0x200; x += 0x80) { + Sprite_slice_pcx(p, __, &img, x, y, 0x80, 0x40, 1, 1); + p += 2; + } + } + } + + // Waterfalls: 4x1 of 128x64 + read_in_dir(&img, art_dir, "waterfalls.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Waterfalls_Images, &img, 0x80, 0x40, 0x200, 0x40); + + // Irrigation (desert/plains/normal/tundra): each 4x4 of 128x64 + read_in_dir(&img, art_dir, "irrigation DESETT.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Desert_Images, &img, 0x80, 0x40, 0x200, 0x100); + read_in_dir(&img, art_dir, "irrigation PLAINS.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Plains_Images, &img, 0x80, 0x40, 0x200, 0x100); + read_in_dir(&img, art_dir, "irrigation.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Images, &img, 0x80, 0x40, 0x200, 0x100); + read_in_dir(&img, art_dir, "irrigation TUNDRA.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Irrigation_Tundra_Images, &img, 0x80, 0x40, 0x200, 0x100); + + // Volcanos (plain/forests/jungles/snow): 4x4 of 128x88 + read_in_dir(&img, art_dir, "Volcanos.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Volcanos forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Volcanos jungles.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Volcanos-snow.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Volcanos_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); + + // Marsh: Large band then Small band (tiles 128x88) + read_in_dir(&img, art_dir, "marsh.pcx", NULL); + if (img.JGL.Image == NULL) return false; + // Large (2 rows, 4 cols) + { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Marsh_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + // Small (2 rows, 5 cols) + { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Marsh_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + // LM mountains + standard mountains (plain/forests/jungles/snow): 4x4 of 128x88 + read_in_dir(&img, art_dir, "LMMountains.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->LM_Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Mountains.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "mountain forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Forests_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "mountain jungles.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Jungles_Images, &img, 0x80, 0x58, 0x200, 0x160); + read_in_dir(&img, art_dir, "Mountains-snow.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Mountains_Snow_Images, &img, 0x80, 0x58, 0x200, 0x160); + + // Roads (16x16) and Railroads (16x17), tiles 128x64 + read_in_dir(&img, art_dir, "roads.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Roads_Images, &img, 0x80, 0x40, 0x800, 0x400); + read_in_dir(&img, art_dir, "railroads.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Railroads_Images, &img, 0x80, 0x40, 0x800, 0x440); + + // LM Forests (Large 2x4, Small 2x6, Pines 2x6), tiles 128x88 + read_in_dir(&img, art_dir, "LMForests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->LM_Forests_Large_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->LM_Forests_Small_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->LM_Forests_Pines_Images[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + // Grassland/Plains/Tundra forests & jungles (bands; tiles 128x88) — order is important + read_in_dir(&img, art_dir, "grassland forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + // Jungles Large, Small + { int k=0; for (int y=0; y<0xb0; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Jungles_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0xb0; y<0x160; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Jungles_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + // Forests Large, Small, Pines + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Grassland_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + read_in_dir(&img, art_dir, "plains forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Plains_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Plains_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Plains_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + read_in_dir(&img, art_dir, "tundra forests.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { int k=0; for (int y=0x160; y<0x210; y+=0x58) for (int x=0; x<0x200; x+=0x80) + Sprite_slice_pcx(&this->Tundra_Forests_Large[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x210; y<0x2c0; y+=0x58) for (int x=0; x<0x280; x+=0x80) + Sprite_slice_pcx(&this->Tundra_Forests_Small[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + { int k=0; for (int y=0x2c0; y<0x370; y+=0x58) for (int x=0; x<0x300; x+=0x80) + Sprite_slice_pcx(&this->Tundra_Forests_Pines[k++], __, &img, x, y, 0x80, 0x58, 1, 1); } + + // LM Terrain (7 single 128x64, vertical strip) + read_in_dir(&img, art_dir, "landmark_terrain.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i = 0, y = 0; i < 7; ++i, y += 0x40) + Sprite_slice_pcx(&this->LM_Terrain[i], __, &img, 0, y, 0x80, 0x40, 1, 1); + + // TNT (same odd ordering as original) + read_in_dir(&img, art_dir, "tnt.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[6+i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[9+i], __, &img, x, 0x40, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[12+i], __, &img, x, 0x80, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[0+i], __, &img, x, 0xC0, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[15+i], __, &img, x, 0x100, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Tnt_Images[3+i], __, &img, x, 0x140, 0x80, 0x40, 1, 1); + + // Goody huts: 8 tiles, x=(i%3)*0x80, y=(i/3)*0x40 + read_in_dir(&img, art_dir, "goodyhuts.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i = 0; i < 8; ++i) { + int x = (i % 3) << 7; + int y = (i / 3) << 6; + Sprite_slice_pcx(&this->Goody_Huts_Images[i], __, &img, x, y, 0x80, 0x40, 1, 1); + } + + // Terrain buildings (fortress/camp/barbarian camp/mines/barricade) + read_in_dir(&img, art_dir, "TerrainBuildings.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Fortress[i], __, &img, 0x00, y, 0x80, 0x40, 1, 1); + for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Camp[i], __, &img, 0x80, y, 0x80, 0x40, 1, 1); + Sprite_slice_pcx(&this->Terrain_Buldings_Barbarian_Camp, __, &img, 0x100, 0x00, 0x80, 0x40, 1, 1); + Sprite_slice_pcx(&this->Terrain_Buldings_Mines, __, &img, 0x100, 0x40, 0x80, 0x40, 1, 1); + for (int i=0, y=0; i<4; ++i, y+=0x40) Sprite_slice_pcx(&this->Terrain_Buldings_Barricade[i], __, &img, 0x180, y, 0x80, 0x40, 1, 1); + + // Pollution & Craters (5x5 of 128x64) + read_in_dir(&img, art_dir, "pollution.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Pollution, &img, 0x80, 0x40, 0x280, 0x140); + read_in_dir(&img, art_dir, "craters.pcx", NULL); + if (img.JGL.Image == NULL) return false; + slice_grid(this->Craters, &img, 0x80, 0x40, 0x280, 0x140); + + // Airfields / Outposts / Radar + read_in_dir(&img, art_dir, "x_airfields and detect.pcx", NULL); + if (img.JGL.Image == NULL) return false; + for (int i=0, x=0; i<2; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Airfields[i], __, &img, x, 0x00, 0x80, 0x40, 1, 1); + for (int i=0, x=0; i<3; ++i, x+=0x80) Sprite_slice_pcx(&this->Terrain_Buldings_Outposts[i], __, &img, x, 0x40, 0x80, 0x80, 1, 1); + Sprite_slice_pcx(&this->Terrain_Buldings_Radar, __, &img, 0x00, 0xC0, 0x80, 0x80, 1, 1); + + // Victory (single 128x64) + read_in_dir(&img, art_dir, "x_victory.pcx", NULL); + if (img.JGL.Image == NULL) return false; + Sprite_slice_pcx(&this->Victory_Image, __, &img, 0, 0, 0x80, 0x40, 1, 1); + + // Resources + read_in_dir(&img, art_dir, "resources.pcx", NULL); + if (img.JGL.Image == NULL) return false; + size_t k = 0; + for (int r = 0, y = 1; r < 6; ++r, y += 50) { + for (int c = 0, x = 1; c < 6; ++c, x += 50) { + Sprite_slice_pcx(&this->Resources[k++], __, &img, x, y, 49, 49, 1, 1); + } + } + + // Base cities + static const char *CITY_BASE[5] = { + "rAMER.pcx", "rEURO.pcx", "rROMAN.pcx", "rMIDEAST.pcx", "rASIAN.pcx" + }; + for (int culture = 0; culture < 5; culture++) { + read_in_dir(&img, art_dir, CITY_BASE[culture], NULL); + if (img.JGL.Image == NULL) return false; + int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; + int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; + int y = 0; + for (int era = 0; era < 4; ++era, y += sprite_h) { + int x = 0; + for (int size = 0; size < 3; ++size, x += sprite_w) { + const int idx = culture + 5*era + 20*size; + Sprite_slice_pcx(&this->City_Images[idx], __, &img, x, y, sprite_w, sprite_h, 1, 1); + } + } + } + + // Walled cities + static const char *CITY_WALL[5] = { + "AMERWALL.pcx", "EUROWALL.pcx", "ROMANWALL.pcx", "MIDEASTWALL.pcx", "ASIANWALL.pcx" + }; + for (int culture = 0; culture < 5; ++culture) { + read_in_dir(&img, art_dir, CITY_WALL[culture], NULL); + if (img.JGL.Image == NULL) return false; + int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image); + int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image) / 4; + int y = 0; + for (int era = 0; era < 4; ++era, y += sprite_h) { + const int size = 3; // walled towns are a special category + const int idx = culture + 5*era + 20*size; + Sprite_slice_pcx(&this->City_Images[idx], __, &img, 0, y, sprite_w, sprite_h, 1, 1); + } + } + + // Destroyed cities + read_in_dir(&img, art_dir, "DESTROY.pcx", NULL); + if (img.JGL.Image == NULL) return false; + { + int sprite_w = img.JGL.Image->vtable->m54_Get_Width(img.JGL.Image) / 3; + int sprite_h = img.JGL.Image->vtable->m55_Get_Height(img.JGL.Image); + int x = 0; + for (int i = 0; i < 3; ++i, x += sprite_w) + Sprite_slice_pcx(&this->Destroyed_City_Images[i], __, &img, x, 0, sprite_w, sprite_h, 1, 1); + } + + // Districts (if enabled) + if (is->current_config.enable_districts) { + char art_dir[200]; + char temp_path[2*MAX_PATH]; + snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + for (int dc = 0; dc < is->district_count; dc++) { + struct district_config const * cfg = &is->district_configs[dc]; + int variant_capacity = ARRAY_LEN (this->District_Images[dc]); + int variant_count = cfg->img_path_count; + if (variant_count <= 0) + continue; + if (variant_count > variant_capacity) + variant_count = variant_capacity; + + int era_count = cfg->vary_img_by_era ? 4 : 1; + int column_count = cfg->img_column_count; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + + for (int variant_i = 0; variant_i < variant_count; variant_i++) { + const char * img_path = cfg->img_paths[variant_i]; + if ((img_path == NULL) || (img_path[0] == '\0')) + continue; + + read_in_dir (&img, temp_path, img_path, NULL); + if (img.JGL.Image == NULL) + return false; + + for (int era = 0; era < era_count; era++) { + for (int col = 0; col < column_count; col++) { + int tile_x = sprite_width * col; + int tile_y = sprite_height * era; + Sprite_slice_pcx (&this->District_Images[dc][variant_i][era][col], __, &img, tile_x, tile_y, sprite_width, sprite_height, 1, 1); + } + } + } + } + + // Abandoned district art (land + maritime) for this hour + read_in_dir (&img, temp_path, "Abandoned.pcx", NULL); + if (img.JGL.Image == NULL) + return false; + Sprite_slice_pcx (&this->Abandoned_District_Image, __, &img, 0, 0, 128, 64, 1, 1); + Sprite_slice_pcx (&this->Abandoned_Maritime_District_Image, __, &img, 128, 0, 128, 64, 1, 1); + + // Load wonder district images (dynamically per wonder) for this hour + if (is->current_config.enable_wonder_districts) { + char const * last_img_path = NULL; + PCX_Image wpcx; + PCX_Image_construct (&wpcx); + bool pcx_loaded = false; + + for (int wi = 0; wi < is->wonder_district_count; wi++) { + struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; + char const * img_path = cfg->img_path; + if (img_path == NULL) + img_path = "Wonders.pcx"; + + // Load new image file if different from previous + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + + read_in_dir (&wpcx, temp_path, img_path, NULL); + + if (wpcx.JGL.Image == NULL) { + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + struct wonder_district_image_set * set = &this->Wonder_District_Images[wi]; + + Sprite_construct (&set->img); + int x = 128 * cfg->img_column; + int y = 64 * cfg->img_row; + Sprite_slice_pcx (&set->img, __, &wpcx, x, y, 128, 64, 1, 1); + + Sprite_construct (&set->construct_img); + int cx = 128 * cfg->img_construct_column; + int cy = 64 * cfg->img_construct_row; + Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, 128, 64, 1, 1); + + if (cfg->enable_img_alt_dir) { + Sprite_construct (&set->alt_dir_img); + int ax = 128 * cfg->img_alt_dir_column; + int ay = 64 * cfg->img_alt_dir_row; + Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, 128, 64, 1, 1); + + Sprite_construct (&set->alt_dir_construct_img); + int acx = 128 * cfg->img_alt_dir_construct_column; + int acy = 64 * cfg->img_alt_dir_construct_row; + Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, 128, 64, 1, 1); + } + } + + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + wpcx.vtable->destruct (&wpcx, __, 0); + } + + } + + if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { + char art_dir[200]; + char temp_path[2*MAX_PATH]; + snprintf (art_dir, sizeof art_dir, "Districts/%s", hour); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + + char const * last_img_path = NULL; + PCX_Image nwpcx; + PCX_Image_construct (&nwpcx); + bool pcx_loaded = false; + + for (int ni = 0; ni < is->natural_wonder_count; ni++) { + struct natural_wonder_district_config const * cfg = &is->natural_wonder_configs[ni]; + if ((cfg->img_path == NULL) || (cfg->img_path[0] == '\0')) + continue; + + char const * img_path = cfg->img_path; + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + + read_in_dir (&nwpcx, temp_path, img_path, NULL); + + if (nwpcx.JGL.Image == NULL) { + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + Sprite_construct (&this->Natural_Wonder_Images[ni].img); + int x = 128 * cfg->img_column; + int y = 88 * cfg->img_row; + Sprite_slice_pcx (&this->Natural_Wonder_Images[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); + } + + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + nwpcx.vtable->destruct (&nwpcx, __, 0); + } + + img.vtable->destruct (&img, __, 0); + + return true; +} + +Sprite * +get_sprite_proxy_for_current_hour(Sprite *s) { + int v; + int hour = is->current_day_night_cycle; // 0..23 + if (itable_look_up(&is->day_night_sprite_proxy_by_hour[hour], (int)s, &v)) + return (Sprite *)v; + return NULL; // not proxied, fall back to s +} + +void +insert_spritelist_proxies(SpriteList *ss, SpriteList *ps, int hour, int len1, int len2) { + for (int i = 0; i < len1; i++) { + for (int j = 0; j < len2; j++) { + Sprite *s = &ss[i].field_0[j]; + Sprite *p = &ps[i].field_0[j]; + if (s && p) { + itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); + } + } + } +} + +void +insert_sprite_proxies(Sprite *ss, Sprite *ps, int hour, int len) { + for (int i = 0; i < len; i++) { + Sprite *s = &ss[i]; + Sprite *p = &ps[i]; + if (s && p) { + itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); + } + } +} + +void +insert_sprite_proxy(Sprite *s, Sprite *p, int hour) { + if (s && p) { + itable_insert(&is->day_night_sprite_proxy_by_hour[hour], (int)s, (int)p); + } +} + +void +build_sprite_proxies_24(Map_Renderer *mr) { + for (int h = 0; h < 24; ++h) { + insert_sprite_proxies(city_sprites, is->day_night_cycle_imgs[h].City_Images, h, 80); + insert_sprite_proxies(destroyed_city_sprites, is->day_night_cycle_imgs[h].Destroyed_City_Images, h, 3); + insert_sprite_proxies(mr->Resources, is->day_night_cycle_imgs[h].Resources, h, 36); + insert_spritelist_proxies(mr->Std_Terrain_Images, is->day_night_cycle_imgs[h].Std_Terrain_Images, h, 9, 81); + insert_spritelist_proxies(mr->LM_Terrain_Images, is->day_night_cycle_imgs[h].LM_Terrain_Images, h, 9, 81); + insert_sprite_proxy(&mr->Terrain_Buldings_Barbarian_Camp, &is->day_night_cycle_imgs[h].Terrain_Buldings_Barbarian_Camp, h); + insert_sprite_proxy(&mr->Terrain_Buldings_Mines, &is->day_night_cycle_imgs[h].Terrain_Buldings_Mines, h); + insert_sprite_proxy(&mr->Victory_Image, &is->day_night_cycle_imgs[h].Victory_Image, h); + insert_sprite_proxy(&mr->Terrain_Buldings_Radar, &is->day_night_cycle_imgs[h].Terrain_Buldings_Radar, h); + insert_sprite_proxies(mr->Flood_Plains_Images, is->day_night_cycle_imgs[h].Flood_Plains_Images, h, 16); + insert_sprite_proxies(mr->Polar_Icecaps_Images, is->day_night_cycle_imgs[h].Polar_Icecaps_Images, h, 32); + insert_sprite_proxies(mr->Roads_Images, is->day_night_cycle_imgs[h].Roads_Images, h, 256); + insert_sprite_proxies(mr->Railroads_Images, is->day_night_cycle_imgs[h].Railroads_Images, h, 272); + insert_sprite_proxies(mr->Terrain_Buldings_Airfields, is->day_night_cycle_imgs[h].Terrain_Buldings_Airfields, h, 2); + insert_sprite_proxies(mr->Terrain_Buldings_Camp, is->day_night_cycle_imgs[h].Terrain_Buldings_Camp, h, 4); + insert_sprite_proxies(mr->Terrain_Buldings_Fortress, is->day_night_cycle_imgs[h].Terrain_Buldings_Fortress, h, 4); + insert_sprite_proxies(mr->Terrain_Buldings_Barricade, is->day_night_cycle_imgs[h].Terrain_Buldings_Barricade, h, 4); + insert_sprite_proxies(mr->Goody_Huts_Images, is->day_night_cycle_imgs[h].Goody_Huts_Images, h, 8); + insert_sprite_proxies(mr->Terrain_Buldings_Outposts, is->day_night_cycle_imgs[h].Terrain_Buldings_Outposts, h, 3); + insert_sprite_proxies(mr->Pollution, is->day_night_cycle_imgs[h].Pollution, h, 25); + insert_sprite_proxies(mr->Craters, is->day_night_cycle_imgs[h].Craters, h, 25); + insert_sprite_proxies(mr->Tnt_Images, is->day_night_cycle_imgs[h].Tnt_Images, h, 18); + insert_sprite_proxies(mr->Waterfalls_Images, is->day_night_cycle_imgs[h].Waterfalls_Images, h, 4); + insert_sprite_proxies(mr->LM_Terrain, is->day_night_cycle_imgs[h].LM_Terrain, h, 7); + insert_sprite_proxies(mr->Marsh_Large, is->day_night_cycle_imgs[h].Marsh_Large, h, 8); + insert_sprite_proxies(mr->Marsh_Small, is->day_night_cycle_imgs[h].Marsh_Small, h, 10); + insert_sprite_proxies(mr->Volcanos_Images, is->day_night_cycle_imgs[h].Volcanos_Images, h, 16); + insert_sprite_proxies(mr->Volcanos_Forests_Images, is->day_night_cycle_imgs[h].Volcanos_Forests_Images, h, 16); + insert_sprite_proxies(mr->Volcanos_Jungles_Images, is->day_night_cycle_imgs[h].Volcanos_Jungles_Images, h, 16); + insert_sprite_proxies(mr->Volcanos_Snow_Images, is->day_night_cycle_imgs[h].Volcanos_Snow_Images, h, 16); + insert_sprite_proxies(mr->Grassland_Forests_Large, is->day_night_cycle_imgs[h].Grassland_Forests_Large, h, 8); + insert_sprite_proxies(mr->Plains_Forests_Large, is->day_night_cycle_imgs[h].Plains_Forests_Large, h, 8); + insert_sprite_proxies(mr->Tundra_Forests_Large, is->day_night_cycle_imgs[h].Tundra_Forests_Large, h, 8); + insert_sprite_proxies(mr->Grassland_Forests_Small, is->day_night_cycle_imgs[h].Grassland_Forests_Small, h, 10); + insert_sprite_proxies(mr->Plains_Forests_Small, is->day_night_cycle_imgs[h].Plains_Forests_Small, h, 10); + insert_sprite_proxies(mr->Tundra_Forests_Small, is->day_night_cycle_imgs[h].Tundra_Forests_Small, h, 10); + insert_sprite_proxies(mr->Grassland_Forests_Pines, is->day_night_cycle_imgs[h].Grassland_Forests_Pines, h, 12); + insert_sprite_proxies(mr->Plains_Forests_Pines, is->day_night_cycle_imgs[h].Plains_Forests_Pines, h, 12); + insert_sprite_proxies(mr->Tundra_Forests_Pines, is->day_night_cycle_imgs[h].Tundra_Forests_Pines, h, 12); + insert_sprite_proxies(mr->Irrigation_Desert_Images, is->day_night_cycle_imgs[h].Irrigation_Desert_Images, h, 16); + insert_sprite_proxies(mr->Irrigation_Plains_Images, is->day_night_cycle_imgs[h].Irrigation_Plains_Images, h, 16); + insert_sprite_proxies(mr->Irrigation_Images, is->day_night_cycle_imgs[h].Irrigation_Images, h, 16); + insert_sprite_proxies(mr->Irrigation_Tundra_Images, is->day_night_cycle_imgs[h].Irrigation_Tundra_Images, h, 16); + insert_sprite_proxies(mr->Grassland_Jungles_Large, is->day_night_cycle_imgs[h].Grassland_Jungles_Large, h, 8); + insert_sprite_proxies(mr->Grassland_Jungles_Small, is->day_night_cycle_imgs[h].Grassland_Jungles_Small, h, 12); + insert_sprite_proxies(mr->Mountains_Images, is->day_night_cycle_imgs[h].Mountains_Images, h, 16); + insert_sprite_proxies(mr->Mountains_Forests_Images, is->day_night_cycle_imgs[h].Mountains_Forests_Images, h, 16); + insert_sprite_proxies(mr->Mountains_Jungles_Images, is->day_night_cycle_imgs[h].Mountains_Jungles_Images, h, 16); + insert_sprite_proxies(mr->Mountains_Snow_Images, is->day_night_cycle_imgs[h].Mountains_Snow_Images, h, 16); + insert_sprite_proxies(mr->Hills_Images, is->day_night_cycle_imgs[h].Hills_Images, h, 16); + insert_sprite_proxies(mr->Hills_Forests_Images, is->day_night_cycle_imgs[h].Hills_Forests_Images, h, 16); + insert_sprite_proxies(mr->Hills_Jungle_Images, is->day_night_cycle_imgs[h].Hills_Jungle_Images, h, 16); + insert_sprite_proxies(mr->Delta_Rivers_Images, is->day_night_cycle_imgs[h].Delta_Rivers_Images, h, 16); + insert_sprite_proxies(mr->Mountain_Rivers_Images, is->day_night_cycle_imgs[h].Mountain_Rivers_Images, h, 16); + insert_sprite_proxies(mr->LM_Mountains_Images, is->day_night_cycle_imgs[h].LM_Mountains_Images, h, 16); + insert_sprite_proxies(mr->LM_Forests_Large_Images, is->day_night_cycle_imgs[h].LM_Forests_Large_Images, h, 8); + insert_sprite_proxies(mr->LM_Forests_Small_Images, is->day_night_cycle_imgs[h].LM_Forests_Small_Images, h, 10); + insert_sprite_proxies(mr->LM_Forests_Pines_Images, is->day_night_cycle_imgs[h].LM_Forests_Pines_Images, h, 12); + insert_sprite_proxies(mr->LM_Hills_Images, is->day_night_cycle_imgs[h].LM_Hills_Images, h, 16); + + if (is->current_config.enable_districts) { + for (int dc = 0; dc < is->district_count; dc++) { + struct district_config const * cfg = &is->district_configs[dc]; + int variant_capacity = ARRAY_LEN (is->district_img_sets[dc].imgs); + int variant_count = cfg->img_path_count; + if (variant_count <= 0) + continue; + if (variant_count > variant_capacity) + variant_count = variant_capacity; + + int era_count = cfg->vary_img_by_era ? 4 : 1; + int column_count = cfg->img_column_count; + + for (int variant_i = 0; variant_i < variant_count; variant_i++) { + if ((cfg->img_paths[variant_i] == NULL) || (cfg->img_paths[variant_i][0] == '\0')) + continue; + for (int era = 0; era < era_count; era++) { + for (int col = 0; col < column_count; col++) { + Sprite * base = &is->district_img_sets[dc].imgs[variant_i][era][col]; + Sprite * proxy = &is->day_night_cycle_imgs[h].District_Images[dc][variant_i][era][col]; + insert_sprite_proxy (base, proxy, h); + } + } + } + } + + insert_sprite_proxy (&is->abandoned_district_img, &is->day_night_cycle_imgs[h].Abandoned_District_Image, h); + insert_sprite_proxy (&is->abandoned_maritime_district_img, &is->day_night_cycle_imgs[h].Abandoned_Maritime_District_Image, h); + + // Wonder districts + if (is->current_config.enable_wonder_districts) { + for (int wi = 0; wi < is->wonder_district_count; wi++) { + Sprite * base_img = &is->wonder_district_img_sets[wi].img; + Sprite * proxy_img = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].img; + insert_sprite_proxy (base_img, proxy_img, h); + + Sprite * base_construct = &is->wonder_district_img_sets[wi].construct_img; + Sprite * proxy_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].construct_img; + insert_sprite_proxy (base_construct, proxy_construct, h); + + if (is->wonder_district_img_sets[wi].alt_dir_img.vtable != NULL) { + Sprite * base_alt = &is->wonder_district_img_sets[wi].alt_dir_img; + Sprite * proxy_alt = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_img; + insert_sprite_proxy (base_alt, proxy_alt, h); + } + + if (is->wonder_district_img_sets[wi].alt_dir_construct_img.vtable != NULL) { + Sprite * base_alt_construct = &is->wonder_district_img_sets[wi].alt_dir_construct_img; + Sprite * proxy_alt_construct = &is->day_night_cycle_imgs[h].Wonder_District_Images[wi].alt_dir_construct_img; + insert_sprite_proxy (base_alt_construct, proxy_alt_construct, h); + } + } + } + } + + // Natural wonders + if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { + for (int ni = 0; ni < is->natural_wonder_count; ni++) { + Sprite * base_nw = &is->natural_wonder_img_sets[ni].img; + Sprite * proxy_nw = &is->day_night_cycle_imgs[h].Natural_Wonder_Images[ni].img; + insert_sprite_proxy (base_nw, proxy_nw, h); + } + } + } + is->day_night_cycle_img_proxies_indexed = true; +} + +void +init_day_night_images() +{ + if (is->day_night_cycle_img_state != IS_UNINITED) + return; + + const char *hour_strs[24] = { + "2400", "0100", "0200", "0300", "0400", "0500", "0600", "0700", + "0800", "0900", "1000", "1100", "1200", "1300", "1400", "1500", + "1600", "1700", "1800", "1900", "2000", "2100", "2200", "2300" + }; + + for (int i = 0; i < 24; i++) { + + char art_dir[200]; + char temp_path[2*MAX_PATH]; + snprintf (art_dir, sizeof art_dir, "DayNight/%s", hour_strs[i]); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + bool success = load_day_night_hour_images (&is->day_night_cycle_imgs[i], temp_path, hour_strs[i]); + + if (!success) { + char ss[200]; + snprintf(ss, sizeof ss, "Failed to load day/night cycle images for hour %s, reverting to base game art.", hour_strs[i]); + pop_up_in_game_error (ss); + + is->day_night_cycle_img_state = IS_INIT_FAILED; + return; + } + } + + Map_Renderer * mr = &p_bic_data->Map.Renderer; + build_sprite_proxies_24(mr); + + is->day_night_cycle_img_state = IS_OK; +} + +void +deindex_day_night_image_proxies() +{ + if (!is->day_night_cycle_img_proxies_indexed) + return; + + for (int i = 0; i < 24; i++) { + table_deinit (&is->day_night_sprite_proxy_by_hour[i]); + } + is->day_night_cycle_img_proxies_indexed = false; +} + +int +calculate_current_day_night_cycle_hour () +{ + int output = 12; // Default to noon + int increment = is->current_config.fixed_hours_per_turn_for_day_night_cycle; + + switch (is->current_config.day_night_cycle_mode) { + + // Disabled. This shouldn't be possible, but default to noon to be safe + case DNCM_OFF: + return output; + + // Time elapsed since last update + case DNCM_TIMER: { + LARGE_INTEGER perf_freq; + QueryPerformanceFrequency(&perf_freq); + + if (is->day_night_cycle_unstarted) { + is->current_day_night_cycle = output; + QueryPerformanceCounter(&is->last_day_night_cycle_update_time); + } + + LARGE_INTEGER time_now; + QueryPerformanceCounter(&time_now); + + double elapsed_seconds = + (double)(time_now.QuadPart - is->last_day_night_cycle_update_time.QuadPart) / + (double)perf_freq.QuadPart; + + if (elapsed_seconds > (double)is->current_config.elapsed_minutes_per_day_night_hour_transition * 60.0) { + output = is->current_day_night_cycle + increment; + is->last_day_night_cycle_update_time = time_now; + } else { + output = is->current_day_night_cycle; + } + break; + } + + // Match user's current time + case DNCM_USER_TIME: { + LPSYSTEMTIME lpSystemTime = (LPSYSTEMTIME)malloc(sizeof(SYSTEMTIME)); + GetLocalTime (lpSystemTime); + output = lpSystemTime->wHour; + free (lpSystemTime); + break; + } + + // Increment fixed amount each interturn + case DNCM_EVERY_TURN: { + if (is->day_night_cycle_unstarted) { + increment = 0; + is->current_day_night_cycle = output; + } + output = is->current_day_night_cycle + increment; + break; + } + + // Pin the hour to a specific value + case DNCM_SPECIFIED: { + output = is->current_config.pinned_hour_for_day_night_cycle; + break; + } + } + + // If midnight or over, restart at 0 or later + if (output > 23) output = output - 24; + + // Clamp to valid range of 0-23 in case of weird config values + output = clamp (0, 23, output); + is->day_night_cycle_unstarted = false; + + return output; +} + +void __fastcall +patch_Map_Renderer_load_images (Map_Renderer *this, int edx) +{ + Map_Renderer_load_images(this, __); + + // Initialize day/night cycle and re-calculate hour, if applicable + if (is->current_config.day_night_cycle_mode != DNCM_OFF) { + is->current_day_night_cycle = calculate_current_day_night_cycle_hour (); + + if (is->day_night_cycle_img_state == IS_UNINITED) { + init_day_night_images (); + } + + if (is->day_night_cycle_img_state == IS_OK) { + + // Sprite proxies are deindexed during each load event as sprite instances (really only Resources, which are reloaded) may change. + if (!is->day_night_cycle_img_proxies_indexed) { + build_sprite_proxies_24(this); + } + } + } +} + +void +patch_init_floating_point () +{ + init_floating_point (); + + // NOTE: At this point the program is done with the CRT initialization stuff and will start calling constructors for global + // objects as soon as this function returns. This is a good place to inject code that will run at program start. + + // Specify metadata about all boolean options on the mod config. We'll use this info to set up the table of offsets (for easy parsing) and to + // fill out the base config. + struct boolean_config_option { + char * name; + bool base_val; + int offset; + } boolean_config_options[] = { + {"enable_stack_bombard" , true , offsetof (struct c3x_config, enable_stack_bombard)}, + {"enable_disorder_warning" , true , offsetof (struct c3x_config, enable_disorder_warning)}, + {"allow_stealth_attack_against_single_unit" , false, offsetof (struct c3x_config, allow_stealth_attack_against_single_unit)}, + {"show_detailed_city_production_info" , true , offsetof (struct c3x_config, show_detailed_city_production_info)}, + {"limited_railroads_work_like_fast_roads" , false, offsetof (struct c3x_config, limited_railroads_work_like_fast_roads)}, + {"exclude_cities_from_units_per_tile_limit" , false, offsetof (struct c3x_config, exclude_cities_from_units_per_tile_limit)}, + {"enable_free_buildings_from_small_wonders" , true , offsetof (struct c3x_config, enable_free_buildings_from_small_wonders)}, + {"enable_stack_unit_commands" , true , offsetof (struct c3x_config, enable_stack_unit_commands)}, + {"skip_repeated_tile_improv_replacement_asks" , true , offsetof (struct c3x_config, skip_repeated_tile_improv_replacement_asks)}, + {"autofill_best_gold_amount_when_trading" , true , offsetof (struct c3x_config, autofill_best_gold_amount_when_trading)}, + {"disallow_founding_next_to_foreign_city" , true , offsetof (struct c3x_config, disallow_founding_next_to_foreign_city)}, + {"enable_trade_screen_scroll" , true , offsetof (struct c3x_config, enable_trade_screen_scroll)}, + {"group_units_on_right_click_menu" , true , offsetof (struct c3x_config, group_units_on_right_click_menu)}, + {"gray_out_units_on_menu_with_no_remaining_moves" , true , offsetof (struct c3x_config, gray_out_units_on_menu_with_no_remaining_moves)}, + {"put_movement_icons_on_units_on_menu" , true , offsetof (struct c3x_config, put_movement_icons_on_units_on_menu)}, + {"describe_states_of_units_on_menu" , true , offsetof (struct c3x_config, describe_states_of_units_on_menu)}, + {"show_golden_age_turns_remaining" , true , offsetof (struct c3x_config, show_golden_age_turns_remaining)}, + {"show_zoc_attacks_from_mid_stack" , true , offsetof (struct c3x_config, show_zoc_attacks_from_mid_stack)}, + {"show_armies_performing_defensive_bombard" , true , offsetof (struct c3x_config, show_armies_performing_defensive_bombard)}, + {"cut_research_spending_to_avoid_bankruptcy" , true , offsetof (struct c3x_config, cut_research_spending_to_avoid_bankruptcy)}, + {"dont_pause_for_love_the_king_messages" , true , offsetof (struct c3x_config, dont_pause_for_love_the_king_messages)}, + {"reverse_specialist_order_with_shift" , true , offsetof (struct c3x_config, reverse_specialist_order_with_shift)}, + {"toggle_zoom_with_z_on_city_screen" , true , offsetof (struct c3x_config, toggle_zoom_with_z_on_city_screen)}, + {"dont_give_king_names_in_non_regicide_games" , true , offsetof (struct c3x_config, dont_give_king_names_in_non_regicide_games)}, + {"no_elvis_easter_egg" , false, offsetof (struct c3x_config, no_elvis_easter_egg)}, + {"disable_worker_automation" , false, offsetof (struct c3x_config, disable_worker_automation)}, + {"enable_land_sea_intersections" , false, offsetof (struct c3x_config, enable_land_sea_intersections)}, + {"disallow_trespassing" , false, offsetof (struct c3x_config, disallow_trespassing)}, + {"show_detailed_tile_info" , true , offsetof (struct c3x_config, show_detailed_tile_info)}, + {"warn_about_unrecognized_names" , true , offsetof (struct c3x_config, warn_about_unrecognized_names)}, + {"enable_ai_production_ranking" , true , offsetof (struct c3x_config, enable_ai_production_ranking)}, + {"enable_ai_city_location_desirability_display" , true, offsetof (struct c3x_config, enable_ai_city_location_desirability_display)}, + {"show_ai_city_location_desirability_if_settler" , false, offsetof (struct c3x_config, show_ai_city_location_desirability_if_settler)}, + {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, + {"zero_corruption_when_off" , true , offsetof (struct c3x_config, zero_corruption_when_off)}, + {"disallow_land_units_from_affecting_water_tiles" , true , offsetof (struct c3x_config, disallow_land_units_from_affecting_water_tiles)}, + {"dont_end_units_turn_after_airdrop" , false, offsetof (struct c3x_config, dont_end_units_turn_after_airdrop)}, + {"allow_airdrop_without_airport" , false, offsetof (struct c3x_config, allow_airdrop_without_airport)}, + {"enable_negative_pop_pollution" , true , offsetof (struct c3x_config, enable_negative_pop_pollution)}, + {"allow_defensive_retreat_on_water" , false, offsetof (struct c3x_config, allow_defensive_retreat_on_water)}, + {"promote_wonder_decorruption_effect" , false, offsetof (struct c3x_config, promote_wonder_decorruption_effect)}, + {"allow_military_leaders_to_hurry_wonders" , false, offsetof (struct c3x_config, allow_military_leaders_to_hurry_wonders)}, + {"allow_multiple_battle_created_units_per_player" , false, offsetof (struct c3x_config, allow_multiple_battle_created_units_per_player)}, + {"aggressively_penalize_bankruptcy" , false, offsetof (struct c3x_config, aggressively_penalize_bankruptcy)}, + {"no_penalty_exception_for_agri_fresh_water_city_tiles" , false, offsetof (struct c3x_config, no_penalty_exception_for_agri_fresh_water_city_tiles)}, + {"use_offensive_artillery_ai" , true , offsetof (struct c3x_config, use_offensive_artillery_ai)}, + {"dont_escort_unflagged_units" , false, offsetof (struct c3x_config, dont_escort_unflagged_units)}, + {"replace_leader_unit_ai" , true , offsetof (struct c3x_config, replace_leader_unit_ai)}, + {"fix_ai_army_composition" , true , offsetof (struct c3x_config, fix_ai_army_composition)}, + {"enable_pop_unit_ai" , true , offsetof (struct c3x_config, enable_pop_unit_ai)}, + {"enable_caravan_unit_ai" , true , offsetof (struct c3x_config, enable_caravan_unit_ai)}, + {"remove_unit_limit" , true , offsetof (struct c3x_config, remove_unit_limit)}, + {"remove_city_improvement_limit" , true , offsetof (struct c3x_config, remove_city_improvement_limit)}, + {"remove_cap_on_turn_limit" , true , offsetof (struct c3x_config, remove_cap_on_turn_limit)}, + {"remove_era_limit" , false, offsetof (struct c3x_config, remove_era_limit)}, + {"patch_submarine_bug" , true , offsetof (struct c3x_config, patch_submarine_bug)}, + {"patch_science_age_bug" , true , offsetof (struct c3x_config, patch_science_age_bug)}, + {"patch_pedia_texture_bug" , true , offsetof (struct c3x_config, patch_pedia_texture_bug)}, + {"patch_blocked_disembark_freeze" , true , offsetof (struct c3x_config, patch_blocked_disembark_freeze)}, + {"patch_houseboat_bug" , true , offsetof (struct c3x_config, patch_houseboat_bug)}, + {"patch_intercept_lost_turn_bug" , true , offsetof (struct c3x_config, patch_intercept_lost_turn_bug)}, + {"patch_phantom_resource_bug" , true , offsetof (struct c3x_config, patch_phantom_resource_bug)}, + {"patch_maintenance_persisting_for_obsolete_buildings" , true , offsetof (struct c3x_config, patch_maintenance_persisting_for_obsolete_buildings)}, + {"patch_barbarian_diagonal_bug" , true , offsetof (struct c3x_config, patch_barbarian_diagonal_bug)}, + {"patch_disease_stopping_tech_flag_bug" , false, offsetof (struct c3x_config, patch_disease_stopping_tech_flag_bug)}, + {"patch_division_by_zero_in_ai_alliance_eval" , true , offsetof (struct c3x_config, patch_division_by_zero_in_ai_alliance_eval)}, + {"patch_empty_army_movement" , true , offsetof (struct c3x_config, patch_empty_army_movement)}, + {"patch_empty_army_combat_crash" , true , offsetof (struct c3x_config, patch_empty_army_combat_crash)}, + {"patch_premature_truncation_of_found_paths" , true , offsetof (struct c3x_config, patch_premature_truncation_of_found_paths)}, + {"patch_zero_production_crash" , true , offsetof (struct c3x_config, patch_zero_production_crash)}, + {"patch_ai_can_form_army_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_form_army_without_special_ability)}, + {"patch_ai_can_sacrifice_without_special_ability" , true , offsetof (struct c3x_config, patch_ai_can_sacrifice_without_special_ability)}, + {"patch_crash_in_leader_unit_ai" , true , offsetof (struct c3x_config, patch_crash_in_leader_unit_ai)}, + {"patch_failure_to_find_new_city_build" , true , offsetof (struct c3x_config, patch_failure_to_find_new_city_build)}, + {"patch_passengers_out_of_order_on_menu" , true , offsetof (struct c3x_config, patch_passengers_out_of_order_on_menu)}, + {"delete_off_map_ai_units" , true , offsetof (struct c3x_config, delete_off_map_ai_units)}, + {"fix_overlapping_specialist_yield_icons" , true , offsetof (struct c3x_config, fix_overlapping_specialist_yield_icons)}, + {"prevent_autorazing" , false, offsetof (struct c3x_config, prevent_autorazing)}, + {"prevent_razing_by_players" , false, offsetof (struct c3x_config, prevent_razing_by_players)}, + {"suppress_hypertext_links_exceeded_popup" , true , offsetof (struct c3x_config, suppress_hypertext_links_exceeded_popup)}, + {"indicate_non_upgradability_in_pedia" , true , offsetof (struct c3x_config, indicate_non_upgradability_in_pedia)}, + {"show_message_after_dodging_sam" , true , offsetof (struct c3x_config, show_message_after_dodging_sam)}, + {"include_stealth_attack_cancel_option" , false, offsetof (struct c3x_config, include_stealth_attack_cancel_option)}, + {"intercept_recon_missions" , false, offsetof (struct c3x_config, intercept_recon_missions)}, + {"charge_one_move_for_recon_and_interception" , false, offsetof (struct c3x_config, charge_one_move_for_recon_and_interception)}, + {"polish_precision_striking" , true , offsetof (struct c3x_config, polish_precision_striking)}, + {"enable_stealth_attack_via_bombardment" , false, offsetof (struct c3x_config, enable_stealth_attack_via_bombardment)}, + {"immunize_aircraft_against_bombardment" , false, offsetof (struct c3x_config, immunize_aircraft_against_bombardment)}, + {"replay_ai_moves_in_hotseat_games" , false, offsetof (struct c3x_config, replay_ai_moves_in_hotseat_games)}, + {"restore_unit_directions_on_game_load" , true , offsetof (struct c3x_config, restore_unit_directions_on_game_load)}, + {"apply_grid_ini_setting_on_game_load" , true , offsetof (struct c3x_config, apply_grid_ini_setting_on_game_load)}, + {"charm_flag_triggers_ptw_like_targeting" , false, offsetof (struct c3x_config, charm_flag_triggers_ptw_like_targeting)}, + {"city_icons_show_unit_effects_not_trade" , true , offsetof (struct c3x_config, city_icons_show_unit_effects_not_trade)}, + {"ignore_king_ability_for_defense_priority" , false, offsetof (struct c3x_config, ignore_king_ability_for_defense_priority)}, + {"show_untradable_techs_on_trade_screen" , false, offsetof (struct c3x_config, show_untradable_techs_on_trade_screen)}, + {"disallow_useless_bombard_vs_airfields" , true , offsetof (struct c3x_config, disallow_useless_bombard_vs_airfields)}, + {"compact_luxury_display_on_city_screen" , false, offsetof (struct c3x_config, compact_luxury_display_on_city_screen)}, + {"compact_strategic_resource_display_on_city_screen" , false, offsetof (struct c3x_config, compact_strategic_resource_display_on_city_screen)}, + {"warn_when_chosen_building_would_replace_another" , false, offsetof (struct c3x_config, warn_when_chosen_building_would_replace_another)}, + {"do_not_unassign_workers_from_polluted_tiles" , false, offsetof (struct c3x_config, do_not_unassign_workers_from_polluted_tiles)}, + {"do_not_make_capital_cities_appear_larger" , false, offsetof (struct c3x_config, do_not_make_capital_cities_appear_larger)}, + {"show_territory_colors_on_water_tiles_in_minimap" , false, offsetof (struct c3x_config, show_territory_colors_on_water_tiles_in_minimap)}, + {"convert_some_popups_into_online_mp_messages" , false, offsetof (struct c3x_config, convert_some_popups_into_online_mp_messages)}, + {"enable_debug_mode_switch" , false, offsetof (struct c3x_config, enable_debug_mode_switch)}, + {"accentuate_cities_on_minimap" , false, offsetof (struct c3x_config, accentuate_cities_on_minimap)}, + {"allow_multipage_civilopedia_descriptions" , true , offsetof (struct c3x_config, allow_multipage_civilopedia_descriptions)}, + {"reformat_turns_remaining_on_domestic_advisor_screen" , true , offsetof (struct c3x_config, reformat_turns_remaining_on_domestic_advisor_screen)}, + {"expand_civilopedia_unit_stats" , true , offsetof (struct c3x_config, expand_civilopedia_unit_stats)}, + {"enable_trade_net_x" , true , offsetof (struct c3x_config, enable_trade_net_x)}, + {"optimize_improvement_loops" , true , offsetof (struct c3x_config, optimize_improvement_loops)}, + {"measure_turn_times" , false, offsetof (struct c3x_config, measure_turn_times)}, + {"enable_city_capture_by_barbarians" , false, offsetof (struct c3x_config, enable_city_capture_by_barbarians)}, + {"share_visibility_in_hotseat" , false, offsetof (struct c3x_config, share_visibility_in_hotseat)}, + {"share_wonders_in_hotseat" , false, offsetof (struct c3x_config, share_wonders_in_hotseat)}, + {"allow_precision_strikes_against_tile_improvements" , false, offsetof (struct c3x_config, allow_precision_strikes_against_tile_improvements)}, + {"dont_end_units_turn_after_bombarding_barricade" , false, offsetof (struct c3x_config, dont_end_units_turn_after_bombarding_barricade)}, + {"remove_land_artillery_target_restrictions" , false, offsetof (struct c3x_config, remove_land_artillery_target_restrictions)}, + {"allow_bombard_of_other_improvs_on_occupied_airfield" , false, offsetof (struct c3x_config, allow_bombard_of_other_improvs_on_occupied_airfield)}, + {"show_total_city_count" , false, offsetof (struct c3x_config, show_total_city_count)}, + {"strengthen_forbidden_palace_ocn_effect" , false, offsetof (struct c3x_config, strengthen_forbidden_palace_ocn_effect)}, + {"allow_upgrades_in_any_city" , false, offsetof (struct c3x_config, allow_upgrades_in_any_city)}, + {"do_not_generate_volcanos" , false, offsetof (struct c3x_config, do_not_generate_volcanos)}, + {"do_not_pollute_impassable_tiles" , false, offsetof (struct c3x_config, do_not_pollute_impassable_tiles)}, + {"show_hp_of_stealth_attack_options" , false, offsetof (struct c3x_config, show_hp_of_stealth_attack_options)}, + {"exclude_invisible_units_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_invisible_units_from_stealth_attack)}, + {"exclude_passengers_from_stealth_attack" , false, offsetof (struct c3x_config, exclude_passengers_from_stealth_attack)}, + {"convert_to_landmark_after_planting_forest" , false, offsetof (struct c3x_config, convert_to_landmark_after_planting_forest)}, + {"allow_sale_of_aqueducts_and_hospitals" , false, offsetof (struct c3x_config, allow_sale_of_aqueducts_and_hospitals)}, + {"no_cross_shore_detection" , false, offsetof (struct c3x_config, no_cross_shore_detection)}, + {"auto_zoom_city_screen_for_large_work_areas" , true, offsetof (struct c3x_config, auto_zoom_city_screen_for_large_work_areas)}, + {"limit_unit_loading_to_one_transport_per_turn" , false, offsetof (struct c3x_config, limit_unit_loading_to_one_transport_per_turn)}, + {"prevent_old_units_from_upgrading_past_ability_block" , false, offsetof (struct c3x_config, prevent_old_units_from_upgrading_past_ability_block)}, + {"allow_extraterritorial_colonies" , false, offsetof (struct c3x_config, allow_extraterritorial_colonies)}, + {"draw_forests_over_roads_and_railroads" , false, offsetof (struct c3x_config, draw_forests_over_roads_and_railroads)}, + {"enable_districts" , false, offsetof (struct c3x_config, enable_districts)}, + {"enable_neighborhood_districts" , false, offsetof (struct c3x_config, enable_neighborhood_districts)}, + {"enable_wonder_districts" , false, offsetof (struct c3x_config, enable_wonder_districts)}, + {"enable_natural_wonders" , false, offsetof (struct c3x_config, enable_natural_wonders)}, + {"add_natural_wonders_to_scenarios_if_none" , false, offsetof (struct c3x_config, add_natural_wonders_to_scenarios_if_none)}, + {"enable_named_tiles" , false, offsetof (struct c3x_config, enable_named_tiles)}, + {"enable_distribution_hub_districts" , false, offsetof (struct c3x_config, enable_distribution_hub_districts)}, + {"enable_aerodrome_districts" , false, offsetof (struct c3x_config, enable_aerodrome_districts)}, + {"enable_port_districts" , false, offsetof (struct c3x_config, enable_port_districts)}, + {"enable_bridge_districts" , false, offsetof (struct c3x_config, enable_bridge_districts)}, + {"enable_canal_districts" , false, offsetof (struct c3x_config, enable_canal_districts)}, + {"enable_central_rail_hub_districts" , false, offsetof (struct c3x_config, enable_central_rail_hub_districts)}, + {"enable_energy_grid_districts" , false, offsetof (struct c3x_config, enable_energy_grid_districts)}, + {"enable_great_wall_districts" , false, offsetof (struct c3x_config, enable_great_wall_districts)}, + {"completed_wonder_districts_can_be_destroyed" , false, offsetof (struct c3x_config, completed_wonder_districts_can_be_destroyed)}, + {"destroyed_wonders_can_be_built_again" , false, offsetof (struct c3x_config, destroyed_wonders_can_be_built_again)}, + {"cities_with_mutual_district_receive_buildings" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_buildings)}, + {"cities_with_mutual_district_receive_wonders" , false, offsetof (struct c3x_config, cities_with_mutual_district_receive_wonders)}, + {"show_message_when_building_received_by_mutual_district", false, offsetof (struct c3x_config, show_message_when_building_received_by_mutual_district)}, + {"show_message_when_building_lost_to_destroyed_district" , false, offsetof (struct c3x_config, show_message_when_building_lost_to_destroyed_district)}, + {"destroying_neighborhood_reduces_pop" , false, offsetof (struct c3x_config, destroying_neighborhood_reduces_pop)}, + {"air_units_use_aerodrome_districts_not_cities" , false, offsetof (struct c3x_config, air_units_use_aerodrome_districts_not_cities)}, + {"naval_units_use_port_districts_not_cities" , false, offsetof (struct c3x_config, naval_units_use_port_districts_not_cities)}, + {"show_natural_wonder_name_on_map" , false, offsetof (struct c3x_config, show_natural_wonder_name_on_map)}, + {"ai_defends_districts" , false, offsetof (struct c3x_config, ai_defends_districts)}, + {"great_wall_districts_impassible_by_others" , false, offsetof (struct c3x_config, great_wall_districts_impassible_by_others)}, + {"auto_build_great_wall_around_territory" , false, offsetof (struct c3x_config, auto_build_great_wall_around_territory)}, + {"disable_great_wall_city_defense_bonus" , false, offsetof (struct c3x_config, disable_great_wall_city_defense_bonus)}, + {"expand_water_tile_checks_to_city_work_area" , false, offsetof (struct c3x_config, expand_water_tile_checks_to_city_work_area)}, + {"ai_can_replace_existing_districts_with_canals" , false, offsetof (struct c3x_config, ai_can_replace_existing_districts_with_canals)}, + {"ai_builds_bridges" , false, offsetof (struct c3x_config, ai_builds_bridges)}, + {"ai_builds_canals" , false, offsetof (struct c3x_config, ai_builds_canals)}, + {"workers_can_enter_coast" , false, offsetof (struct c3x_config, workers_can_enter_coast)}, + {"enable_city_work_radii_highlights" , false, offsetof (struct c3x_config, enable_city_work_radii_highlights)}, + {"introduce_all_human_players_at_start_of_hotseat_game" , false, offsetof (struct c3x_config, introduce_all_human_players_at_start_of_hotseat_game)}, + {"allow_unload_from_army" , false, offsetof (struct c3x_config, allow_unload_from_army)}, + {"no_land_anti_air_from_inside_naval_transport" , false, offsetof (struct c3x_config, no_land_anti_air_from_inside_naval_transport)}, + {"prevent_enslaving_by_bombardment" , false, offsetof (struct c3x_config, prevent_enslaving_by_bombardment)}, + {"allow_adjacent_resources_of_different_types" , false, offsetof (struct c3x_config, allow_adjacent_resources_of_different_types)}, + {"allow_corruption_in_capital" , false, offsetof (struct c3x_config, allow_corruption_in_capital)}, + {"allow_sale_of_small_wonders" , false, offsetof (struct c3x_config, allow_sale_of_small_wonders)}, + {"initialize_preplaced_scenario_leaders_as_mgls" , false, offsetof (struct c3x_config, initialize_preplaced_scenario_leaders_as_mgls)}, + {"enable_unit_counters" , false, offsetof (struct c3x_config, enable_unit_counters)}, + {"use_civ4_style_best_defender" , false, offsetof (struct c3x_config, use_civ4_style_best_defender)}, + }; + + struct integer_config_option { + char * name; + int base_val; + int offset; + } integer_config_options[] = { + {"limit_railroad_movement" , 0, offsetof (struct c3x_config, limit_railroad_movement)}, + {"minimum_city_separation" , 1, offsetof (struct c3x_config, minimum_city_separation)}, + {"anarchy_length_percent" , 100, offsetof (struct c3x_config, anarchy_length_percent)}, + {"ai_multi_city_start" , 0, offsetof (struct c3x_config, ai_multi_city_start)}, + {"max_tries_to_place_fp_city" , 10000, offsetof (struct c3x_config, max_tries_to_place_fp_city)}, + {"ai_research_multiplier" , 100, offsetof (struct c3x_config, ai_research_multiplier)}, + {"ai_settler_perfume_on_founding_duration" , 0, offsetof (struct c3x_config, ai_settler_perfume_on_founding_duration)}, + {"extra_unit_maintenance_per_shields" , 0, offsetof (struct c3x_config, extra_unit_maintenance_per_shields)}, + {"ai_build_artillery_ratio" , 16, offsetof (struct c3x_config, ai_build_artillery_ratio)}, + {"ai_artillery_value_damage_percent" , 50, offsetof (struct c3x_config, ai_artillery_value_damage_percent)}, + {"ai_build_bomber_ratio" , 70, offsetof (struct c3x_config, ai_build_bomber_ratio)}, + {"max_ai_naval_escorts" , 3, offsetof (struct c3x_config, max_ai_naval_escorts)}, + {"ai_worker_requirement_percent" , 150, offsetof (struct c3x_config, ai_worker_requirement_percent)}, + {"chance_for_nukes_to_destroy_max_one_hp_units" , 100, offsetof (struct c3x_config, chance_for_nukes_to_destroy_max_one_hp_units)}, + {"rebase_range_multiplier" , 6, offsetof (struct c3x_config, rebase_range_multiplier)}, + {"elapsed_minutes_per_day_night_hour_transition" , 3, offsetof (struct c3x_config, elapsed_minutes_per_day_night_hour_transition)}, + {"fixed_hours_per_turn_for_day_night_cycle" , 1, offsetof (struct c3x_config, fixed_hours_per_turn_for_day_night_cycle)}, + {"pinned_hour_for_day_night_cycle" , 0, offsetof (struct c3x_config, pinned_hour_for_day_night_cycle)}, + {"years_to_double_building_culture" , 1000, offsetof (struct c3x_config, years_to_double_building_culture)}, + {"tourism_time_scale_percent" , 100, offsetof (struct c3x_config, tourism_time_scale_percent)}, + {"luxury_randomized_appearance_rate_percent" , 100, offsetof (struct c3x_config, luxury_randomized_appearance_rate_percent)}, + {"tiles_per_non_luxury_resource" , 32, offsetof (struct c3x_config, tiles_per_non_luxury_resource)}, + {"special_capital_decorruption_effect" , 10, offsetof (struct c3x_config, special_capital_decorruption_effect)}, + {"city_limit" , 2048, offsetof (struct c3x_config, city_limit)}, + {"maximum_pop_before_neighborhood_needed" , 8, offsetof (struct c3x_config, maximum_pop_before_neighborhood_needed)}, + {"per_neighborhood_pop_growth_enabled" , 2, offsetof (struct c3x_config, per_neighborhood_pop_growth_enabled)}, + {"minimum_natural_wonder_separation" , 10, offsetof (struct c3x_config, minimum_natural_wonder_separation)}, + {"distribution_hub_food_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_food_yield_divisor)}, + {"distribution_hub_shield_yield_divisor" , 1, offsetof (struct c3x_config, distribution_hub_shield_yield_divisor)}, + {"ai_ideal_distribution_hub_count_per_100_cities" , 1, offsetof (struct c3x_config, ai_ideal_distribution_hub_count_per_100_cities)}, + {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, + {"max_distribution_hub_count_per_100_cities" , 50, offsetof (struct c3x_config, max_distribution_hub_count_per_100_cities)}, + {"central_rail_hub_distribution_food_bonus_percent" , 25, offsetof (struct c3x_config, central_rail_hub_distribution_food_bonus_percent)}, + {"central_rail_hub_distribution_shield_bonus_percent", 25, offsetof (struct c3x_config, central_rail_hub_distribution_shield_bonus_percent)}, + {"neighborhood_needed_message_frequency" , 4, offsetof (struct c3x_config, neighborhood_needed_message_frequency)}, + {"max_contiguous_bridge_districts" , 3, offsetof (struct c3x_config, max_contiguous_bridge_districts)}, + {"max_contiguous_canal_districts" , 5, offsetof (struct c3x_config, max_contiguous_canal_districts)}, + {"ai_canal_eval_min_bisected_land_tiles" , 10, offsetof (struct c3x_config, ai_canal_eval_min_bisected_land_tiles)}, + {"ai_bridge_canal_eval_block_size" , 20, offsetof (struct c3x_config, ai_bridge_canal_eval_block_size)}, + {"ai_bridge_eval_lake_tile_threshold" , 6, offsetof (struct c3x_config, ai_bridge_eval_lake_tile_threshold)}, + {"ai_city_district_max_build_wait_turns" , 20, offsetof (struct c3x_config, ai_city_district_max_build_wait_turns)}, + {"per_extraterritorial_colony_relation_penalty" , 0, offsetof (struct c3x_config, per_extraterritorial_colony_relation_penalty)}, + }; + + is->kernel32 = (*p_GetModuleHandleA) ("kernel32.dll"); + is->user32 = (*p_GetModuleHandleA) ("user32.dll"); + is->msvcrt = (*p_GetModuleHandleA) ("msvcrt.dll"); + + // Remember the function names here are macros that expand to is->... + VirtualProtect = (void *)(*p_GetProcAddress) (is->kernel32, "VirtualProtect"); + CloseHandle = (void *)(*p_GetProcAddress) (is->kernel32, "CloseHandle"); + CreateFileA = (void *)(*p_GetProcAddress) (is->kernel32, "CreateFileA"); + GetFileSize = (void *)(*p_GetProcAddress) (is->kernel32, "GetFileSize"); + ReadFile = (void *)(*p_GetProcAddress) (is->kernel32, "ReadFile"); + LoadLibraryA = (void *)(*p_GetProcAddress) (is->kernel32, "LoadLibraryA"); + FreeLibrary = (void *)(*p_GetProcAddress) (is->kernel32, "FreeLibrary"); + MultiByteToWideChar = (void *)(*p_GetProcAddress) (is->kernel32, "MultiByteToWideChar"); + WideCharToMultiByte = (void *)(*p_GetProcAddress) (is->kernel32, "WideCharToMultiByte"); + GetLastError = (void *)(*p_GetProcAddress) (is->kernel32, "GetLastError"); + QueryPerformanceCounter = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceCounter"); + QueryPerformanceFrequency = (void *)(*p_GetProcAddress) (is->kernel32, "QueryPerformanceFrequency"); + GetLocalTime = (void *)(*p_GetProcAddress) (is->kernel32, "GetLocalTime"); + MessageBoxA = (void *)(*p_GetProcAddress) (is->user32, "MessageBoxA"); + is->msimg32 = LoadLibraryA ("Msimg32.dll"); + TransparentBlt = (void *)(*p_GetProcAddress) (is->msimg32, "TransparentBlt"); + snprintf = (void *)(*p_GetProcAddress) (is->msvcrt, "_snprintf"); + malloc = (void *)(*p_GetProcAddress) (is->msvcrt, "malloc"); + calloc = (void *)(*p_GetProcAddress) (is->msvcrt, "calloc"); + realloc = (void *)(*p_GetProcAddress) (is->msvcrt, "realloc"); + free = (void *)(*p_GetProcAddress) (is->msvcrt, "free"); + strtol = (void *)(*p_GetProcAddress) (is->msvcrt, "strtol"); + strcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strcmp"); + strncmp = (void *)(*p_GetProcAddress) (is->msvcrt, "strncmp"); + _stricmp = (void *)(*p_GetProcAddress) (is->msvcrt, "_stricmp"); + strlen = (void *)(*p_GetProcAddress) (is->msvcrt, "strlen"); + strncpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strncpy"); + strcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "strcpy"); + strdup = (void *)(*p_GetProcAddress) (is->msvcrt, "_strdup"); + strstr = (void *)(*p_GetProcAddress) (is->msvcrt, "strstr"); + qsort = (void *)(*p_GetProcAddress) (is->msvcrt, "qsort"); + memcmp = (void *)(*p_GetProcAddress) (is->msvcrt, "memcmp"); + memcpy = (void *)(*p_GetProcAddress) (is->msvcrt, "memcpy"); + tolower = (void *)(*p_GetProcAddress) (is->msvcrt, "tolower"); + toupper = (void *)(*p_GetProcAddress) (is->msvcrt, "toupper"); + is->memmove = (void *)(*p_GetProcAddress) (is->msvcrt, "memmove"); // No #define for this one, instead it has a wrapper func + + // Intercept the game's calls to MessageBoxA. We can't do this through the patcher since that would interfere with the runtime loader. + WITH_MEM_PROTECTION (p_MessageBoxA, 4, PAGE_READWRITE) + *p_MessageBoxA = patch_MessageBoxA; + + // Set file path to mod's script.txt + snprintf (is->mod_script_path, sizeof is->mod_script_path, "%s\\Text\\c3x-script.txt", is->mod_rel_dir); + is->mod_script_path[(sizeof is->mod_script_path) - 1] = '\0'; + + // Fill in base config + struct c3x_config base_config = {0}; + base_config.land_retreat_rules = RR_STANDARD; + base_config.sea_retreat_rules = RR_STANDARD; + base_config.ai_settler_perfume_on_founding = 0; + base_config.work_area_limit = WAL_NONE; + base_config.draw_lines_using_gdi_plus = LDO_WINE; + base_config.double_minimap_size = MDM_HIGH_DEF; + base_config.override_no_ai_patrol = NAPO_NONE; + base_config.override_barbarian_activity_level_for_scenario_maps = BAO_NONE; + base_config.unit_cycle_search_criteria = UCSC_STANDARD; + base_config.city_work_radius = 2; + base_config.day_night_cycle_mode = DNCM_OFF; + base_config.distribution_hub_yield_division_mode = DHYDM_FLAT; + base_config.ai_distribution_hub_build_strategy = ADHBS_BY_CITY_COUNT; + base_config.ai_auto_build_great_wall_strategy = AAGWS_ALL_BORDERS; + base_config.great_wall_auto_build_wonder_improv_id = -1; + for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) + *((char *)&base_config + boolean_config_options[n].offset) = boolean_config_options[n].base_val; + for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) + *(int *)((byte *)&base_config + integer_config_options[n].offset) = integer_config_options[n].base_val; + memcpy (&is->base_config, &base_config, sizeof base_config); + + // Load labels + { + for (int n = 0; n < COUNT_C3X_LABELS; n++) + is->c3x_labels[n] = ""; + + char labels_path[MAX_PATH]; + snprintf (labels_path, sizeof labels_path, "%s\\Text\\c3x-labels.txt", is->mod_rel_dir); + labels_path[(sizeof labels_path) - 1] = '\0'; + char * labels_file_contents = file_to_string (labels_path); + + if (labels_file_contents != NULL) { + char * cursor = labels_file_contents; + int n = 0; + while ((n < COUNT_C3X_LABELS) && (*cursor != '\0')) { + if (*cursor == '\n') + cursor++; + else if ((cursor[0] == '\r') && (cursor[1] == '\n')) + cursor += 2; + else if (*cursor == ';') { + while ((*cursor != '\0') && (*cursor != '\n')) + cursor++; + } else { + char * line_start = cursor; + while ((*cursor != '\0') && (*cursor != '\r') && (*cursor != '\n')) + cursor++; + int line_len = cursor - line_start; + if (NULL != (is->c3x_labels[n] = malloc (line_len + 1))) { + strncpy (is->c3x_labels[n], line_start, line_len); + is->c3x_labels[n][line_len] = '\0'; + } + n++; + } + } + free (labels_file_contents); + + } else { + char err_msg[500]; + snprintf (err_msg, sizeof err_msg, "Couldn't read labels from %s\nPlease make sure the file exists. If you moved the modded EXE you must move the mod folder after it.", labels_path); + err_msg[(sizeof err_msg) - 1] = '\0'; + MessageBoxA (NULL, err_msg, NULL, MB_ICONWARNING); + } + } + + is->sb_next_up = NULL; + is->trade_net = p_original_trade_net; + is->city_limit = 512; + is->trade_net_addrs_load_state = IS_UNINITED; + is->trade_net_addrs = NULL; + is->tnx_cache = NULL; + is->is_computing_city_connections = false; + is->keep_tnx_cache = false; + is->must_recompute_resources_for_mill_inputs = false; + is->is_placing_scenario_things = false; + is->paused_for_popup = false; + is->time_spent_paused_during_popup = 0; + is->time_spent_computing_city_connections = 0; + is->count_calls_to_recompute_city_connections = 0; + + is->have_job_and_loc_to_skip = 0; + + // Initialize trade screen scroll vars + is->open_diplo_form_straight_to_trade = 0; + is->trade_screen_scroll_to_id = -1; + is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; + is->trade_scroll_button_images = NULL; + is->trade_scroll_button_state = IS_UNINITED; + is->eligible_for_trade_scroll = 0; + + memset (&is->saved_code_areas, 0, sizeof is->saved_code_areas); + + is->unit_menu_duplicates = NULL; + + is->memo = NULL; + is->memo_len = 0; + is->memo_capacity = 0; + + // Fill in array mapping cultural NIs to standard ones. + is->cultural_ni_to_standard = malloc (MAX_CULTURAL_NI + 1); + for (int n = 0; n <= MAX_CULTURAL_NI; n++) { + char const * p = &cultural_ni_to_diffs[n << 1]; + is->cultural_ni_to_standard[n] = diff_to_neighbor_index (p[0], p[1], 1000); + } + + // Fill in array mapping standard NIs to work radii AKA work ring numbers + for (int n = 0; n < ARRAY_LEN (is->ni_to_work_radius); n++) { + int work_radius = -1; + int dx, dy; + neighbor_index_to_diff (n, &dx, &dy); + for (int ring_no = 0; ring_no <= 7; ring_no++) { + for (int k = workable_tile_counts[ring_no-1]; k < workable_tile_counts[ring_no]; k++) { + char const * p = &cultural_ni_to_diffs[k<<1]; + if ((p[0] == dx) && (p[1] == dy)) { + work_radius = ring_no; + break; + } + } + if (work_radius != -1) + break; + } + is->ni_to_work_radius[n] = work_radius; + } + + is->city_loc_display_perspective = -1; + + is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; + + is->extra_available_resources = NULL; + is->extra_available_resources_capacity = 0; + + memset (is->interceptor_reset_lists, 0, sizeof is->interceptor_reset_lists); + + is->ai_prod_valuations = NULL; + is->count_ai_prod_valuations = 0; + is->ai_prod_valuations_capacity = 0; + + is->resource_tiles = NULL; + is->count_resource_tiles = 0; + is->resource_tiles_capacity = 0; + is->got_resource_tile = NULL; + is->saved_tile_count = -1; + is->mill_input_resource_bits = NULL; + + is->drawing_icons_for_improv_id = -1; + + is->resources_sheet = NULL; + + is->modifying_gold_trade = NULL; + + is->bombard_stealth_target = NULL; + is->selecting_stealth_target_for_bombard = 0; + + is->map_message_text_override = NULL; + + is->load_file_path_override = NULL; + + is->replay_for_players = 0; + + is->suppress_intro_after_load_popup = 0; + + is->force_barb_activity_for_cities = 0; + + is->dummy_tile = calloc (1, sizeof *is->dummy_tile); + + is->bombarding_unit = NULL; + + is->unit_bombard_attacking_tile = NULL; + is->attacking_tile_x = is->attacking_tile_y = -1; + + is->temporarily_disallow_lethal_zoc = false; + is->moving_unit_to_adjacent_tile = false; + is->showing_hotseat_replay = false; + is->getting_tile_occupier_for_ai_pathfinding = false; + + is->running_on_wine = false; { + HMODULE ntdll = (*p_GetModuleHandleA) ("ntdll.dll"); + is->running_on_wine = (ntdll != NULL) && ((*p_GetProcAddress) (ntdll, "wine_get_version") != NULL); + } + + is->gdi_plus.init_state = IS_UNINITED; + + is->water_trade_improvs = (struct improv_id_list) {0}; + is->air_trade_improvs = (struct improv_id_list) {0}; + is->combat_defense_improvs = (struct improv_id_list) {0}; + + is->unit_display_override = (struct unit_display_override) {-1, -1, -1}; + + is->dbe = (struct defensive_bombard_event) {0}; + + memset (&is->boolean_config_offsets, 0, sizeof is->boolean_config_offsets); + for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) + stable_insert (&is->boolean_config_offsets, boolean_config_options[n].name, boolean_config_options[n].offset); + memset (&is->integer_config_offsets, 0, sizeof is->integer_config_offsets); + for (int n = 0; n < ARRAY_LEN (integer_config_options); n++) + stable_insert (&is->integer_config_offsets, integer_config_options[n].name, integer_config_options[n].offset); + + memset (&is->unit_type_alt_strategies, 0, sizeof is->unit_type_alt_strategies); + memset (&is->unit_type_duplicates , 0, sizeof is->unit_type_duplicates); + memset (&is->extra_defensive_bombards, 0, sizeof is->extra_defensive_bombards); + memset (&is->airdrops_this_turn , 0, sizeof is->airdrops_this_turn); + memset (&is->unit_transport_ties , 0, sizeof is->unit_transport_ties); + memset (&is->extra_city_improvs , 0, sizeof is->extra_city_improvs); + + is->unit_type_count_init_bits = 0; + for (int n = 0; n < 32; n++) + memset (&is->unit_type_counts[n], 0, sizeof is->unit_type_counts[n]); + + is->penciled_in_upgrades = NULL; + is->penciled_in_upgrade_count = is->penciled_in_upgrade_capacity = 0; + + is->currently_capturing_city = NULL; + is->accessing_save_file = NULL; + + is->drawn_strat_resource_count = 0; + + is->charmed_types_converted_to_ptw_arty = NULL; + is->count_charmed_types_converted_to_ptw_arty = 0; + is->charmed_types_converted_to_ptw_arty_capacity = 0; + + is->checking_visibility_for_unit = NULL; + + is->do_not_bounce_invisible_units = false; + is->always_despawn_passengers = false; + is->do_not_enslave_units = false; + + is->saved_improv_counts = NULL; + is->saved_improv_counts_capacity = 0; + + memset (is->last_main_screen_key_up_events, 0, sizeof is->last_main_screen_key_up_events); + + reset_district_state (true); + + is->natural_wonder_count = 0; + + is->sharing_buildings_by_districts_in_progress = false; + is->can_load_transport = is->can_load_passenger = NULL; + + is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; + is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; + is->last_selected_unit.ptr = NULL; + + is->waiting_units = (struct table) {0}; + is->have_loaded_waiting_units = false; + + is->extra_capture_despawns = NULL; + is->count_extra_capture_despawns = 0; + is->extra_capture_despawns_capacity = 0; + + is->loaded_config_names = NULL; + reset_to_base_config (); + apply_machine_code_edits (&is->current_config, true); +} + +void +init_stackable_command_buttons () +{ + if (is->sc_img_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + for (int n = 0; n < 4; n++) + Sprite_construct (&is->sc_button_image_sets[sc].imgs[n]); + + char temp_path[2*MAX_PATH]; + + is->sb_activated_by_button = 0; + is->sc_img_state = IS_INIT_FAILED; + + char const * filenames[4] = {"StackedNormButtons.pcx", "StackedRolloverButtons.pcx", "StackedHighlightedButtons.pcx", "StackedButtonsAlpha.pcx"}; + for (int n = 0; n < 4; n++) { + get_mod_art_path (filenames[n], temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + for (int k = 0; k < 4; k++) { + Sprite * sprite = &is->sc_button_image_sets[sc].imgs[k]; + sprite->vtable->destruct (sprite, __, 0); + } + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) { + int x = 32 * sc_button_infos[sc].tile_sheet_column, + y = 32 * sc_button_infos[sc].tile_sheet_row; + Sprite_slice_pcx (&is->sc_button_image_sets[sc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); + } + + pcx.vtable->clear_JGL (&pcx); + } + + is->sc_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +void +init_disabled_command_buttons () +{ + if (is->disabled_command_img_state != IS_UNINITED) + return; + + is->disabled_command_img_state = IS_INIT_FAILED; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("DisabledButtons.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load disabled command buttons sprite sheet.\n"); + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + Sprite_construct (&is->disabled_build_city_button_img); + Sprite_slice_pcx (&is->disabled_build_city_button_img, __, &pcx, 32*5, 32*2, 32, 32, 1, 0); + + is->disabled_command_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_stackable_command_buttons () +{ + if (is->sc_img_state == IS_OK) + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + for (int n = 0; n < 4; n++) { + Sprite * sprite = &is->sc_button_image_sets[sc].imgs[n]; + sprite->vtable->destruct (sprite, __, 0); + } + is->sc_img_state = IS_UNINITED; +} + +void +deinit_disabled_command_buttons () +{ + Sprite * sprite = &is->disabled_build_city_button_img; + if (is->disabled_command_img_state == IS_OK) + sprite->vtable->destruct (sprite, __, 0); + memset (sprite, 0, sizeof *sprite); + is->disabled_command_img_state = IS_UNINITED; +} + +void +init_tile_highlights () +{ + if (is->tile_highlight_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + + is->tile_highlight_state = IS_INIT_FAILED; + + snprintf (temp_path, sizeof temp_path, "%s\\Art\\TileHighlights.pcx", is->mod_rel_dir); + temp_path[(sizeof temp_path) - 1] = '\0'; + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load stacked command buttons sprite sheet.\n"); + goto cleanup; + } + + for (int n = 0; n < COUNT_TILE_HIGHLIGHTS; n++) + Sprite_slice_pcx (&is->tile_highlights[n], __, &pcx, 128*n, 0, 128, 64, 1, 0); + + is->tile_highlight_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +init_unit_rcm_icons () +{ + if (is->unit_rcm_icon_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("UnitRCMIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image == NULL) || + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 57) || + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 64)) { + (*p_OutputDebugStringA) ("[C3X] PCX file for unit RCM icons failed to load or is too small.\n"); + goto cleanup; + } + + for (int set = 0; set < COUNT_UNIT_RCM_ICON_SETS; set++) { + Sprite * icons = &is->unit_rcm_icons[set * COUNT_UNIT_RCM_ICONS]; + for (int n = 0; n < COUNT_UNIT_RCM_ICONS; n++) { + Sprite_construct (&icons[n]); + Sprite_slice_pcx (&icons[n], __, &pcx, 1 + 14*set, 1 + 16*n, 14, 15, 1, 0); + } + } + + is->unit_rcm_icon_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_unit_rcm_icons () +{ + if (is->unit_rcm_icon_state == IS_OK) { + int total_icon_count = COUNT_UNIT_RCM_ICONS * COUNT_UNIT_RCM_ICON_SETS; + for (int n = 0; n < total_icon_count; n++) { + Sprite * sprite = &is->unit_rcm_icons[n]; + sprite->vtable->destruct (sprite, __, 0); + } + is->unit_rcm_icon_state = IS_UNINITED; + } +} + +void +init_red_food_icon () +{ + if (is->red_food_icon_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("MoreCityIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image != NULL) && + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) >= 32) && + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) == 32)) { + Sprite_construct (&is->red_food_icon); + Sprite_slice_pcx (&is->red_food_icon, __, &pcx, 1, 1, 30, 30, 1, 1); + is->red_food_icon_state = IS_OK; + } else { + (*p_OutputDebugStringA) ("[C3X] PCX file for red food icon failed to load or is not the correct size.\n"); + is->red_food_icon_state = IS_INIT_FAILED; + } + + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_red_food_icon () +{ + if (is->red_food_icon_state == IS_OK) + is->red_food_icon.vtable->destruct (&is->red_food_icon, __, 0); + is->red_food_icon_state = IS_UNINITED; +} + +enum init_state +init_large_minimap_frame () +{ + if (is->large_minimap_frame_img_state != IS_UNINITED) + return is->large_minimap_frame_img_state; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + + get_mod_art_path ("interface\\DoubleSizeBoxLeftColor.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image != NULL) { + Sprite_construct (&is->double_size_box_left_color_pcx); + int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), + height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); + Sprite_slice_pcx (&is->double_size_box_left_color_pcx, __, &pcx, 0, 0, width, height, 1, 1); + } else { + pcx.vtable->destruct (&pcx, __, 0); + return is->large_minimap_frame_img_state = IS_INIT_FAILED; + } + + get_mod_art_path ("interface\\DoubleSizeBoxLeftAlpha.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image != NULL) { + Sprite_construct (&is->double_size_box_left_alpha_pcx); + int width = pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image), + height = pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image); + Sprite_slice_pcx (&is->double_size_box_left_alpha_pcx, __, &pcx, 0, 0, width, height, 1, 1); + } else { + is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); + pcx.vtable->destruct (&pcx, __, 0); + return is->large_minimap_frame_img_state = IS_INIT_FAILED;; + } + + pcx.vtable->destruct (&pcx, __, 0); + return is->large_minimap_frame_img_state = IS_OK; +} + +void +deinit_large_minimap_frame () +{ + if (is->large_minimap_frame_img_state == IS_OK) { + is->double_size_box_left_color_pcx.vtable->destruct (&is->double_size_box_left_color_pcx, __, 0); + is->double_size_box_left_alpha_pcx.vtable->destruct (&is->double_size_box_left_alpha_pcx, __, 0); + } + is->large_minimap_frame_img_state = IS_UNINITED; +} + +int __cdecl +patch_get_tile_occupier_for_ai_path (int x, int y, int pov_civ_id, bool respect_unit_invisibility) +{ + is->getting_tile_occupier_for_ai_pathfinding = true; + return get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); + is->getting_tile_occupier_for_ai_pathfinding = false; +} + +char __fastcall patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2); + +char __fastcall +patch_Unit_is_tile_occupier_visible (Unit * this, int edx, int civ_id, int param_2) +{ + // Here's the fix for the submarine bug: If we're constructing a path for an AI unit, ignore unit invisibility so the pathfinder will path + // around instead of over other civ's units. We must carve out an exception if the AI is at war with the unit in question. In that case if it + // "accidentally" paths over the unit, it should get stuck in combat like the human player would. + if (is->current_config.patch_submarine_bug && + is->getting_tile_occupier_for_ai_pathfinding && + ! this->vtable->is_enemy_of_civ (this, __, civ_id, 0)) + return 1; + else + return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); +} + +void do_trade_scroll (DiploForm * diplo, int forward); + +void __cdecl +activate_trade_scroll_button (int control_id) +{ + do_trade_scroll (p_diplo_form, control_id == TRADE_SCROLL_BUTTON_ID_RIGHT); +} + +void +init_trade_scroll_buttons (DiploForm * diplo_form) +{ + if (is->trade_scroll_button_state != IS_UNINITED) + return; + + char temp_path[2*MAX_PATH]; + PCX_Image pcx; + PCX_Image_construct (&pcx); + get_mod_art_path ("TradeScrollButtons.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + is->trade_scroll_button_state = IS_INIT_FAILED; + (*p_OutputDebugStringA) ("[C3X] Failed to load TradeScrollButtons.pcx\n"); + goto cleanup; + } + + // Stores normal, rollover, and highlight images, in that order, first for the left button then for the right + is->trade_scroll_button_images = calloc (6, sizeof is->trade_scroll_button_images[0]); + for (int n = 0; n < 6; n++) + Sprite_construct (&is->trade_scroll_button_images[n]); + Sprite * imgs = is->trade_scroll_button_images; + + for (int right = 0; right < 2; right++) + for (int n = 0; n < 3; n++) + Sprite_slice_pcx (&imgs[n + 3*right], __, &pcx, right ? 44 : 0, 1 + 48*n, 43, 47, 1, 1); + + for (int right = 0; right < 2; right++) { + Button * b = new (sizeof *b); + + Button_construct (b); + int id = right ? TRADE_SCROLL_BUTTON_ID_RIGHT : TRADE_SCROLL_BUTTON_ID_LEFT; + Button_initialize (b, __, NULL, id, right ? 622 : 358, 50, 43, 47, (Base_Form *)diplo_form, 0); + for (int n = 0; n < 3; n++) + b->Images[n] = &imgs[n + 3*right]; + + b->activation_handler = &activate_trade_scroll_button; + b->field_630[0] = 0; // TODO: Is this necessary? It's done by the base game code when creating the city screen scroll buttons + + if (! right) + is->trade_scroll_button_left = b; + else + is->trade_scroll_button_right = b; + } + + is->trade_scroll_button_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +deinit_trade_scroll_buttons () +{ + if (is->trade_scroll_button_state == IS_OK) { + is->trade_scroll_button_left ->vtable->destruct ((Base_Form *)is->trade_scroll_button_left , __, 0); + is->trade_scroll_button_right->vtable->destruct ((Base_Form *)is->trade_scroll_button_right, __, 0); + is->trade_scroll_button_left = is->trade_scroll_button_right = NULL; + for (int n = 0; n < 6; n++) { + Sprite * sprite = &is->trade_scroll_button_images[n]; + sprite->vtable->destruct (sprite, __, 0); + } + free (is->trade_scroll_button_images); + is->trade_scroll_button_images = NULL; + } + is->trade_scroll_button_state = IS_UNINITED; +} + +void +init_mod_info_button_images () +{ + if (is->mod_info_button_images_state != IS_UNINITED) + return; + + is->mod_info_button_images_state = IS_INIT_FAILED; + + PCX_Image * descbox_pcx = new (sizeof *descbox_pcx); + PCX_Image_construct (descbox_pcx); + char * descbox_path = BIC_get_asset_path (p_bic_data, __, "art\\civilopedia\\descbox.pcx", true); + PCX_Image_read_file (descbox_pcx, __, descbox_path, NULL, 0, 0x100, 1); + if (descbox_pcx->JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load descbox.pcx\n"); + return; + } + + for (int n = 0; n < 3; n++) { + Sprite_construct (&is->mod_info_button_images[n]); + Sprite_slice_pcx_with_color_table (&is->mod_info_button_images[n], __, descbox_pcx, 1 + n * 103, 1, MOD_INFO_BUTTON_WIDTH, + MOD_INFO_BUTTON_HEIGHT, 1, 1); + } + + is->mod_info_button_images_state = IS_OK; +} + +int +count_escorters (Unit * unit) +{ + IDLS * idls = &unit->Body.IDLS; + if (idls->escorters.contents != NULL) { + int tr = 0; + for (int * p_escorter_id = idls->escorters.contents; p_escorter_id < idls->escorters.contents_end; p_escorter_id++) + tr += NULL != get_unit_ptr (*p_escorter_id); + return tr; + } else + return 0; +} + +// If "unit" belongs to the AI, records that all players that have visibility on (x, y) have seen an AI unit +void +record_ai_unit_seen (Unit * unit, int x, int y) +{ + if (0 == (*p_human_player_bits & 1<Body.CivID)) { + Tile * tile = tile_at (x, y); + if ((tile != NULL) && (tile != p_null_tile)) { + Tile_Body * body = &tile->Body; + is->players_saw_ai_unit |= body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility; + } + } +} + +void +recompute_resources_if_necessary () +{ + if (is->must_recompute_resources_for_mill_inputs) + patch_Trade_Net_recompute_resources (is->trade_net, __, false); +} + +void __fastcall +patch_Unit_bombard_tile (Unit * this, int edx, int x, int y) +{ + Tile * target_tile = NULL; + bool had_district_before = false; + int tile_x = x; + int tile_y = y; + struct district_instance * inst; + + if (is->current_config.enable_districts) { + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + target_tile = tile_at (tile_x, tile_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + inst = get_district_instance (target_tile); + had_district_before = (inst != NULL); + } + } + + is->bombarding_unit = this; + record_ai_unit_seen (this, x, y); + Unit_bombard_tile (this, __, x, y); + is->bombard_stealth_target = NULL; + is->bombarding_unit = NULL; + + if (had_district_before && target_tile != NULL && target_tile != p_null_tile && inst->district_id != NATURAL_WONDER_DISTRICT_ID) { + unsigned int overlays = target_tile->vtable->m42_Get_Overlays (target_tile, __, 0); + if ((overlays & TILE_FLAG_MINE) == 0) + handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, false); + } +} + +void __fastcall +patch_Unit_move (Unit * this, int edx, int tile_x, int tile_y) +{ + record_ai_unit_seen (this, tile_x, tile_y); + + Unit_move (this, __, tile_x, tile_y); + + if (this == is->last_selected_unit.ptr) { + is->last_selected_unit.last_x = this->Body.X; + is->last_selected_unit.last_y = this->Body.Y; + } +} + +// Returns true if the unit has attacked & does not have blitz or if it's run out of movement points for the turn +bool +has_exhausted_attack (Unit * unit) +{ + return (unit->Body.Moves >= patch_Unit_get_max_move_points (unit)) || + ((unit->Body.Status & USF_USED_ATTACK) && ! UnitType_has_ability (&p_bic_data->UnitTypes[unit->Body.UnitTypeID], __, UTA_Blitz)); +} + +// Returns whether or not the unit type is a combat type and can do damage on offense (as opposed to only being able to defend). This includes units +// that can only do damage by bombarding and nuclear weapons. +bool +is_offensive_combat_type (UnitType * unit_type) +{ + return (unit_type->Attack > 0) || + ((((unit_type->Special_Actions & UCV_Bombard) | (unit_type->Air_Missions & UCV_Bombing)) & 0x0FFFFFFF) && // (type can perform bombard or bombing AND + ((unit_type->Bombard_Strength > 0) || UnitType_has_ability (unit_type, __, UTA_Nuclear_Weapon))); // (unit has bombard strength OR is a nuclear weapon)) +} + +bool +can_damage_bombarding (UnitType * attacker_type, Unit * defender, Tile * defender_tile) +{ + Unit * container; + if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + (container = get_unit_ptr (defender->Body.Container_Unit)) != NULL && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return false; + + UnitType * defender_type = &p_bic_data->UnitTypes[defender->Body.UnitTypeID]; + if (defender_type->Unit_Class == UTC_Land) { + int has_lethal_land_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Land_Bombardment); + return defender->Body.Damage + (! has_lethal_land_bombard) < Unit_get_max_hp (defender); + } else if (defender_type->Unit_Class == UTC_Sea) { + // Land artillery can't normally damage ships in port + if ((attacker_type->Unit_Class == UTC_Land) && (! is->current_config.remove_land_artillery_target_restrictions) && Tile_has_city (defender_tile)) + return false; + int has_lethal_sea_bombard = UnitType_has_ability (attacker_type, __, UTA_Lethal_Sea_Bombardment); + return defender->Body.Damage + (! has_lethal_sea_bombard) < Unit_get_max_hp (defender); + } else if (defender_type->Unit_Class == UTC_Air) { + if (is->current_config.immunize_aircraft_against_bombardment) + return false; + // Can't damage aircraft in an airfield by bombarding, the attack doesn't even go off + if ((defender_tile->vtable->m42_Get_Overlays (defender_tile, __, 0) & 0x20000000) != 0) + return false; + // Land artillery can't normally damage aircraft but naval artillery and other aircraft can. Lethal bombard doesn't apply; anything + // that can damage can kill. + return (attacker_type->Unit_Class != UTC_Land) || is->current_config.remove_land_artillery_target_restrictions; + } else // UTC_Space? UTC_Alternate_Dimension??? + return false; +} + +char __fastcall +patch_Unit_is_visible_to_civ (Unit * this, int edx, int civ_id, int param_2) +{ + // Save the previous value here b/c this function gets called recursively + Unit * prev_checking = is->checking_visibility_for_unit; + is->checking_visibility_for_unit = this; + + char base_vis = Unit_is_visible_to_civ (this, __, civ_id, param_2); + if ((! base_vis) && // if unit is not visible to civ_id AND + is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND + ((1 << civ_id) & *p_human_player_bits) && // civ_id is a human player AND + (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game + + // Check if the unit is visible to any other human player in the game + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && + (n_player != civ_id) && + Unit_is_visible_to_civ (this, __, n_player, param_2)) + return 1; + player_bits >>= 1; + n_player++; + } + } + + is->checking_visibility_for_unit = prev_checking; + return base_vis; +} + +bool +has_any_destructible_improvements (City * city) +{ + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * improv = &p_bic_data->Improvements[n]; + if (((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) == 0) && // if improv is not a wonder AND + ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && // it's not the palace AND + (improv->SpaceshipPart < 0) && // it's not a spaceship part AND + patch_City_has_improvement (city, __, n, 0)) // it's present in the city ignoring free improvements + return true; + } + return false; +} + +int const destructible_overlays = + 0x00000003 | // road, railroad + 0x00000004 | // mine + 0x00000008 | // irrigation + 0x00000010 | // fortress + 0x10000000 | // barricade + 0x20000000 | // airfield + 0x40000000 | // radar + 0x80000000; // outpost + +bool +has_any_destructible_overlays (Tile * tile, bool precision_strike) +{ + int overlays = tile->vtable->m42_Get_Overlays (tile, __, 0); + if ((overlays & destructible_overlays) == 0) + return false; + else { + if (! precision_strike) + return true; + else { + if (overlays == 0x20000000) { // if tile ONLY has an airfield + int any_aircraft_on_tile = 0; { + FOR_UNITS_ON (uti, tile) + if (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class == UTC_Air) { + any_aircraft_on_tile = 1; + break; + } + } + return ! any_aircraft_on_tile; + } else + return true; + } + } +} + +void __fastcall +patch_Main_Screen_Form_perform_action_on_tile (Main_Screen_Form * this, int edx, enum Unit_Mode_Actions action, int x, int y) +{ + if ((! is->current_config.enable_stack_bombard) || // if stack bombard is disabled OR + (! ((action == UMA_Bombard) || (action == UMA_Air_Bombard))) || // action is not bombard OR + ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) && // (control key is not down AND + ((is->sc_img_state != IS_UNINITED) && (is->sb_activated_by_button == 0))) || // (button flag is valid AND not set)) OR + is_online_game ()) { // is online game + Main_Screen_Form_perform_action_on_tile (this, __, action, x, y); + return; + } + + // Save preferences so we can restore them at the end of the stack bombard operation. We might change them to turn off combat animations. + unsigned init_prefs = *p_preferences; + + clear_memo (); + + wrap_tile_coords (&p_bic_data->Map, &x, &y); + Tile * base_tile = tile_at (this->Current_Unit->Body.X, this->Current_Unit->Body.Y); + Tile * target_tile = tile_at (x, y); + int attacker_type_id = this->Current_Unit->Body.UnitTypeID; + UnitType * attacker_type = &p_bic_data->UnitTypes[attacker_type_id]; + int civ_id = this->Current_Unit->Body.CivID; + + // Count & memoize attackers + int selected_unit_id = this->Current_Unit->Body.ID; + FOR_UNITS_ON (uti, base_tile) + if ((uti.id != selected_unit_id) && + (uti.unit->Body.CivID == civ_id) && + (uti.unit->Body.UnitTypeID == attacker_type_id) && + ((uti.unit->Body.Container_Unit < 0) || (attacker_type->Unit_Class == UTC_Air)) && + (uti.unit->Body.UnitState == 0) && + ! has_exhausted_attack (uti.unit)) + memoize (uti.id); + int count_attackers = is->memo_len; + + // Count & memoize targets (also count air units while we're at it) + int num_air_units_on_target_tile = 0; + FOR_UNITS_ON (uti, target_tile) { + num_air_units_on_target_tile += UTC_Air == p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; + if ((uti.unit->Body.CivID != civ_id) && + (Unit_get_defense_strength (uti.unit) > 0) && + (uti.unit->Body.Container_Unit < 0) && + patch_Unit_is_visible_to_civ (uti.unit, __, civ_id, 0) && + can_damage_bombarding (attacker_type, uti.unit, target_tile)) + memoize (uti.id); + } + int count_targets = is->memo_len - count_attackers; + + // Now our attackers and targets arrays will just be pointers into the memo + int * attackers = &is->memo[0], * targets = &is->memo[count_attackers]; + + int attacking_units = 0, attacking_tile = 0; + City * target_city = NULL; + if (count_targets > 0) + attacking_units = 1; + else if (Tile_has_city (target_tile)) + target_city = get_city_ptr (target_tile->vtable->m45_Get_City_ID (target_tile)); + else { + // Make sure not to set attacking_tile when the tile has an airfield and air units (but no land units) on + // it. In that case we can't damage the airfield and if we try to anyway, the units will waste their moves + // without attacking. + int has_airfield = (target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & 0x20000000) != 0; + attacking_tile = (! has_airfield) || (num_air_units_on_target_tile == 0); + } + + is->sb_next_up = this->Current_Unit; + int i_next_attacker = 0; + int anything_left_to_attack; + int last_attack_didnt_happen; + do { + // If combat animations were enabled when the stack bombard operation started, reset the preference according to the state of the + // shift key (down => skip animations, up => show them). + if (init_prefs & P_ANIMATE_BATTLES) { + if ((*p_GetAsyncKeyState) (VK_SHIFT) >> 8) + *p_preferences &= ~P_ANIMATE_BATTLES; + else + *p_preferences |= P_ANIMATE_BATTLES; + } + + int moves_before_bombard = is->sb_next_up->Body.Moves; + + patch_Unit_bombard_tile (is->sb_next_up, __, x, y); + // At this point sb_next_up may have become NULL if the unit was a bomber that got shot down. + + // Check if the last unit sent into battle actually did anything. If it didn't we should at least skip over + // it to avoid an infinite loop, but actually the only time this should happen is if the player is not at + // war with the targeted civ and chose not to declare when prompted. In this case it's better to just stop + // trying to attack so as to not spam the player with prompts. + last_attack_didnt_happen = (is->sb_next_up == NULL) || (is->sb_next_up->Body.Moves == moves_before_bombard); + + if ((is->sb_next_up == NULL) || has_exhausted_attack (is->sb_next_up)) { + is->sb_next_up = NULL; + while ((i_next_attacker < count_attackers) && (is->sb_next_up == NULL)) + is->sb_next_up = get_unit_ptr (attackers[i_next_attacker++]); + } + + if (attacking_units) { + anything_left_to_attack = 0; + for (int n = 0; n < count_targets; n++) { + Unit * unit = get_unit_ptr (targets[n]); + + // Make sure this unit is still a valid target. Keep in mind it's possible for new units to be created during the + // stack bombard operation if the attackers have lethal bombard and the enslave ability. + if ((unit != NULL) && (unit->Body.X == x) && (unit->Body.Y == y) && (unit->Body.CivID != civ_id)) { + + if (can_damage_bombarding (attacker_type, unit, target_tile)) { + anything_left_to_attack = 1; + break; + } + } + } + } else if (target_city != NULL) + anything_left_to_attack = (target_city->Body.Population.Size > 1) || has_any_destructible_improvements (target_city); + else if (attacking_tile) + anything_left_to_attack = has_any_destructible_overlays (target_tile, false); + else + anything_left_to_attack = 0; + } while ((is->sb_next_up != NULL) && anything_left_to_attack && (! last_attack_didnt_happen)); + + is->sb_activated_by_button = 0; + is->sb_next_up = NULL; + *p_preferences = init_prefs; + this->GUI.Base.vtable->m73_call_m22_Draw ((Base_Form *)&this->GUI); +} + +void +set_up_stack_bombard_buttons (Main_GUI * this) +{ + if (is_online_game () || (! is->current_config.enable_stack_bombard)) + return; + + init_stackable_command_buttons (); + if (is->sc_img_state != IS_OK) + return; + + // Find button that the original method set to (air) bombard, then find the next unused button after that. + Command_Button * bombard_button = NULL, * free_button = NULL; { + int i_bombard_button; + for (int n = 0; n < 42; n++) + if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && + (this->Unit_Command_Buttons[n].Command == UCV_Bombard || this->Unit_Command_Buttons[n].Command == UCV_Bombing)) { + bombard_button = &this->Unit_Command_Buttons[n]; + i_bombard_button = n; + break; + } + if (bombard_button != NULL) + for (int n = i_bombard_button + 1; n < 42; n++) + if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { + free_button = &this->Unit_Command_Buttons[n]; + break; + } + } + + if ((bombard_button == NULL) || (free_button == NULL)) + return; + + // Set up free button for stack bombard + free_button->Command = bombard_button->Command; + free_button->field_6D8 = bombard_button->field_6D8; + struct sc_button_image_set * img_set = + (bombard_button->Command == UCV_Bombing) ? &is->sc_button_image_sets[SC_BOMB] : &is->sc_button_image_sets[SC_BOMBARD]; + for (int n = 0; n < 4; n++) + free_button->Button.Images[n] = &img_set->imgs[n]; + free_button->Button.field_664 = bombard_button->Button.field_664; + // FUN_005559E0 is also called in the original code. I don't know what it actually does but I'm pretty sure it doesn't + // matter for our purposes. + Button_set_tooltip (&free_button->Button, __, is->c3x_labels[CL_SB_TOOLTIP]); + free_button->Button.field_5FC[13] = bombard_button->Button.field_5FC[13]; + free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); +} + +void +init_district_command_buttons () +{ + if (is_online_game () || is->dc_btn_img_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) + for (int n = 0; n < 4; n++) + Sprite_construct (&is->district_btn_img_sets[dc].imgs[n]); + + char temp_path[2*MAX_PATH]; + + is->dc_btn_img_state = IS_INIT_FAILED; + + // For each button sprite type (normal, rollover, highlighted, alpha) + char const * filenames[4] = { + "Districts\\WorkerDistrictButtonsNorm.pcx", "Districts\\WorkerDistrictButtonsRollover.pcx", + "Districts\\WorkerDistrictButtonsHighlighted.pcx", "Districts\\WorkerDistrictButtonsAlpha.pcx" + }; + for (int n = 0; n < 4; n++) { + get_mod_art_path (filenames[n], temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if (pcx.JGL.Image == NULL) { + (*p_OutputDebugStringA) ("[C3X] Failed to load work district command buttons sprite sheet.\n"); + for (int dc = 0; dc < COUNT_DISTRICT_TYPES; dc++) + for (int k = 0; k < 4; k++) { + Sprite * sprite = &is->district_btn_img_sets[dc].imgs[k]; + sprite->vtable->destruct (sprite, __, 0); + } + pcx.vtable->destruct (&pcx, __, 0); + + char ss[200]; + snprintf (ss, sizeof ss, "[C3X] Failed to load district command button images from %s", temp_path); + pop_up_in_game_error (ss); + + return; + } + + // For each district type + int district_count = is->district_count; + if (district_count > COUNT_DISTRICT_TYPES) + district_count = COUNT_DISTRICT_TYPES; + for (int dc = 0; dc < district_count; dc++) { + int x = 32 * is->district_configs[dc].btn_tile_sheet_column, + y = 32 * is->district_configs[dc].btn_tile_sheet_row; + Sprite_slice_pcx (&is->district_btn_img_sets[dc].imgs[n], __, &pcx, x, y, 32, 32, 1, 0); + } + + pcx.vtable->clear_JGL (&pcx); + } + + is->dc_btn_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +int +parse_turns_from_tooltip (char const * tooltip) +{ + if ((tooltip == NULL) || (*tooltip == '\0')) + return -1; + + char const * last_paren = NULL; + for (char const * cursor = tooltip; *cursor != '\0'; cursor++) + if (*cursor == '(') + last_paren = cursor; + if (last_paren == NULL) + return -1; + + char const * digit_ptr = last_paren + 1; + while (*digit_ptr == ' ') + digit_ptr++; + + int turns = 0; + bool have_digit = false; + while ((*digit_ptr >= '0') && (*digit_ptr <= '9')) { + have_digit = true; + turns = (turns * 10) + (*digit_ptr - '0'); + digit_ptr++; + } + return have_digit ? turns : -1; +} + +void +compute_highlighted_worker_tiles_for_districts () +{ + if (is_online_game () + || ! is->current_config.enable_districts + || ! is->current_config.enable_city_work_radii_highlights) + return; + + Unit * selected_unit = p_main_screen_form->Current_Unit; + if (selected_unit == NULL) + return; + + int unit_type_id = selected_unit->Body.UnitTypeID; + if (p_bic_data->UnitTypes[unit_type_id].Worker_Actions == 0) + return; + + if (is->tile_highlight_state == IS_UNINITED) + init_tile_highlights (); + if (is->tile_highlight_state != IS_OK) + return; + + int worker_civ_id = selected_unit->Body.CivID; + if ((p_cities == NULL) || (p_cities->Cities == NULL)) + return; + + // Loop over all cities owned by this civ and tally their workable tiles + FOR_CITIES_OF (coi, worker_civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + + // Highlight city center so players can easily see which cities contribute + Tile * city_center_tile = tile_at (city->Body.X, city->Body.Y); + if ((city_center_tile != NULL) && (city_center_tile != p_null_tile)) { + int stored_ptr; + if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, &stored_ptr)) { + struct highlighted_city_radius_tile_info * info = malloc (sizeof (struct highlighted_city_radius_tile_info)); + info->highlight_level = 0; + itable_insert (&is->highlighted_city_radius_tile_pointers, (int)city_center_tile, (int)info); + } + } + + // Add all workable tiles around the city (excluding city center) + for (int n = 1; n < is->workable_tile_count; n++) { + int dx, dy; + patch_ni_to_diff_for_work_area (n, &dx, &dy); + int tile_x = city->Body.X + dx; + int tile_y = city->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + + Tile * workable_tile = tile_at (tile_x, tile_y); + if ((workable_tile == NULL) || (workable_tile == p_null_tile)) continue; + if (workable_tile->vtable->m38_Get_Territory_OwnerID (workable_tile) != worker_civ_id) continue; + + // Upsert into highlighted_city_radius_tile_pointers + int stored_ptr; + struct highlighted_city_radius_tile_info * info; + if (! itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, &stored_ptr)) { + info = malloc (sizeof (struct highlighted_city_radius_tile_info)); + info->highlight_level = 0; + itable_insert (&is->highlighted_city_radius_tile_pointers, (int)workable_tile, (int)info); + } else { + info = (struct highlighted_city_radius_tile_info *)stored_ptr; + info->highlight_level += 3; + } + } + } +} + +void +set_up_district_buttons (Main_GUI * this) +{ + if (is_online_game () || ! is->current_config.enable_districts) return; + if (is->dc_btn_img_state == IS_UNINITED) init_district_command_buttons (); + if (is->dc_btn_img_state != IS_OK) return; + + Unit * selected_unit = p_main_screen_form->Current_Unit; + if (selected_unit == NULL || ! is_worker(selected_unit)) return; + + Tile * tile = tile_at (selected_unit->Body.X, selected_unit->Body.Y); + if ((tile == NULL) || (tile == p_null_tile) || (tile->CityID >= 0)) return; + + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + if (tile->vtable->m21_Check_Crates (tile, __, 0)) return; + if (tile->vtable->m20_Check_Pollution (tile, __, 0)) return; + + Command_Button * fortify_button = NULL; + int i_starting_button; + int mine_turns = -1; + for (int n = 0; n < 42; n++) { + if (((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) != 0) && + (this->Unit_Command_Buttons[n].Command == UCV_Fortify)) { + fortify_button = &this->Unit_Command_Buttons[n]; + i_starting_button = n; + } + if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { + mine_turns = parse_turns_from_tooltip (this->Unit_Command_Buttons[n].Button.ToolTip); + } + if (fortify_button != NULL && mine_turns >= 0) + break; + } + + if (fortify_button == NULL) + return; + + i_starting_button = -1; + + // Check if there's already a district on this tile. If so, and the unit can build mines, + // ensure the mine button is enabled so the worker can continue construction. + int existing_district_id = -1; + struct district_instance * existing_inst = get_district_instance (tile); + if (existing_inst != NULL) { + existing_district_id = existing_inst->district_id; + if (is->current_config.enable_natural_wonders && existing_inst->district_id == NATURAL_WONDER_DISTRICT_ID) { + return; + } + if (patch_Unit_can_perform_command(selected_unit, __, UCV_Build_Mine)) { + for (int n = 0; n < 42; n++) { + if (this->Unit_Command_Buttons[n].Command == UCV_Build_Mine) { + Command_Button * mine_button = &this->Unit_Command_Buttons[n]; + if (base_type == SQ_Coast) { + mine_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&mine_button->Button); + break; + } + if ((mine_button->Button.Base_Data.Status2 & 1) == 0) { + mine_button->Button.field_5FC[13] = 0; + mine_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&mine_button->Button, __, 0); + } + break; + } + } + } + } + + bool district_completed = district_is_complete (tile, existing_district_id); + + // First pass: collect which district types should be shown + int active_districts[COUNT_DISTRICT_TYPES]; + int active_count = 0; + + for (int dc = 0; dc < is->district_count; dc++) { + + if (is->district_configs[dc].command == -1) + continue; + + bool already_building = false; + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if (unit != NULL && is_worker(unit) && existing_inst != NULL && existing_inst->district_id == dc) { + // If there's a worker on the tile and it's building this district, + // show the button so more workers can contribute. This works around an + // issue where a specific district requiring irrigation no longer + // is buildable by other workers because initial construction removes the + // required irrigation overlay upon construction start + already_building = true; + break; + } + } + + if (existing_district_id == dc && district_completed) continue; + if ((existing_district_id >= 0) && (existing_district_id != dc) && (! district_completed)) continue; + + if (! can_build_district_on_tile (tile, dc, selected_unit->Body.CivID) && ! already_building) + continue; + + // This district should be shown + active_districts[active_count++] = dc; + } + + + if (active_count == 0) + return; + + // Calculate centered starting position + // For odd counts, center perfectly; for even counts, favor left of center + int center_pos = 6; + i_starting_button = center_pos - (active_count / 2); + if (i_starting_button < 0) + i_starting_button = 0; + + // Second pass: render the buttons + for (int idx = 0; idx < active_count; idx++) { + int dc = active_districts[idx]; + + Command_Button * free_button = NULL; + for (int n = i_starting_button; n < 42; n++) { + if ((this->Unit_Command_Buttons[n].Button.Base_Data.Status2 & 1) == 0) { + free_button = &this->Unit_Command_Buttons[n]; + i_starting_button = n + 1; + break; + } + } + + if (free_button == NULL) + return; + + // Set up free button for creating district + free_button->Command = is->district_configs[dc].command; + + // Replace the button's image with the district image. Disabling & re-enabling and + // clearing field_5FC[13] are all necessary to trigger a redraw. + free_button->Button.vtable->m02_Show_Disabled ((Base_Form *)&free_button->Button); + free_button->field_6D8 = fortify_button->field_6D8; + for (int k = 0; k < 4; k++) + free_button->Button.Images[k] = &is->district_btn_img_sets[dc].imgs[k]; + free_button->Button.field_664 = fortify_button->Button.field_664; + if (mine_turns >= 0) { + char tooltip[256]; + char const * turn_word = (mine_turns == 1) ? "turn" : "turns"; + snprintf (tooltip, sizeof tooltip, "%s (%d %s)", is->district_configs[dc].tooltip, mine_turns, turn_word); + tooltip[(sizeof tooltip) - 1] = '\0'; + Button_set_tooltip (&free_button->Button, __, tooltip); + } else + Button_set_tooltip (&free_button->Button, __, (char *)is->district_configs[dc].tooltip); + free_button->Button.field_5FC[13] = 0; + free_button->Button.vtable->m01_Show_Enabled ((Base_Form *)&free_button->Button, __, 0); + } +} + +void +set_up_stack_worker_buttons (Main_GUI * this) +{ + if ((((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // (control key is not down OR + (! is->current_config.enable_stack_unit_commands) || // stack worker commands not enabled OR + is_online_game ()) // is online game + return; + + init_stackable_command_buttons (); + if (is->sc_img_state != IS_OK) + return; + + // For each unit command button + for (int n = 0; n < 42; n++) { + Command_Button * cb = &this->Unit_Command_Buttons[n]; + + // If it's enabled and not a bombard button (those are handled in the function above) + if (((cb->Button.Base_Data.Status2 & 1) != 0) && + (cb->Command != UCV_Bombard) && (cb->Command != UCV_Bombing)) { + + // Find the stackable worker command that this button controls, if there is one, and check that + // the button isn't already showing the stack image for that command. Note: this check is important + // b/c this function gets called repeatedly while the CTRL key is held down. + for (int sc = 0; sc < COUNT_STACKABLE_COMMANDS; sc++) + if ((cb->Command == sc_button_infos[sc].command) && + (cb->Button.Images[0] != &is->sc_button_image_sets[sc].imgs[0])) { + + // Replace the button's image with the stack image. Disabling & re-enabling and + // clearing field_5FC[13] are all necessary to trigger a redraw. + cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); + for (int k = 0; k < 4; k++) + cb->Button.Images[k] = &is->sc_button_image_sets[sc].imgs[k]; + cb->Button.field_5FC[13] = 0; + cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); + + break; + } + } + } +} + +CityLocValidity __fastcall patch_Map_check_city_location (Map * this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile); + +void __fastcall +patch_Main_GUI_set_up_unit_command_buttons (Main_GUI * this) +{ + // Recompute resources now if needed because of a trade deal involving mill inputs. In rare cases the change in deals might affect a mill that + // produces a resource that's used for a worker job. + recompute_resources_if_necessary (); + + Main_GUI_set_up_unit_command_buttons (this); + set_up_stack_bombard_buttons (this); + set_up_stack_worker_buttons (this); + + if (is->current_config.enable_districts) { + set_up_district_buttons (this); + } + + // If the minimum city separation is increased, then gray out the found city button if we're too close to another city. + if ((is->current_config.minimum_city_separation > 1) && (p_main_screen_form->Current_Unit != NULL) && (is->disabled_command_img_state == IS_OK)) { + Unit_Body * selected_unit = &p_main_screen_form->Current_Unit->Body; + + // For each unit command button + for (int n = 0; n < 42; n++) { + Command_Button * cb = &this->Unit_Command_Buttons[n]; + + // If it's enabled, set to city founding, and the current city location is too close to another city + if (((cb->Button.Base_Data.Status2 & 1) != 0) && + (cb->Command == UCV_Build_City) && + (patch_Map_check_city_location (&p_bic_data->Map, __, selected_unit->X, selected_unit->Y, selected_unit->CivID, false) == CLV_CITY_TOO_CLOSE)) { + + // Replace the button's image with the disabled image, as in set_up_stack_worker_buttons. + cb->Button.vtable->m02_Show_Disabled ((Base_Form *)&cb->Button); + for (int k = 0; k < 3; k++) + cb->Button.Images[k] = &is->disabled_build_city_button_img; + cb->Button.field_5FC[13] = 0; + + char tooltip[200]; { + memset (tooltip, 0, sizeof tooltip); + char * label = is->c3x_labels[CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP], + * to_replace = "$NUM0", + * replace_location = strstr (label, to_replace); + if (replace_location != NULL) + snprintf (tooltip, sizeof tooltip, "%.*s%d%s", replace_location - label, label, is->current_config.minimum_city_separation, replace_location + strlen (to_replace)); + else + snprintf (tooltip, sizeof tooltip, "%s", label); + tooltip[(sizeof tooltip) - 1] = '\0'; + } + Button_set_tooltip (&cb->Button, __, tooltip); + + cb->Button.vtable->m01_Show_Enabled ((Base_Form *)&cb->Button, __, 0); + + } + } + } +} + +void +clear_highlighted_worker_tiles_and_redraw () +{ + clear_highlighted_worker_tiles_for_districts (); + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +void +check_happiness_at_end_of_turn () +{ + int num_unhappy_cities = 0; + City * first_unhappy_city = NULL; + FOR_CITIES_OF (coi, p_main_screen_form->Player_CivID) { + City_recompute_happiness (coi.city); + int num_happy = 0, num_unhappy = 0; + FOR_CITIZENS_IN (ci, coi.city) { + num_happy += ci.ctzn->Body.Mood == CMT_Happy; + num_unhappy += ci.ctzn->Body.Mood == CMT_Unhappy; + } + if (num_unhappy > num_happy) { + num_unhappy_cities++; + if (first_unhappy_city == NULL) + first_unhappy_city = coi.city; + } + } + + if (first_unhappy_city != NULL) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, first_unhappy_city->Body.CityName, -1, -1); + if (num_unhappy_cities > 1) + set_popup_int_param (1, num_unhappy_cities - 1); + char * key = (num_unhappy_cities > 1) ? "C3X_DISORDER_WARNING_MULTIPLE" : "C3X_DISORDER_WARNING_ONE"; + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, key, -1, 0, 0, 0); + int response = patch_show_popup (popup, __, 0, 0); + + if (response == 2) { // zoom to city + p_main_screen_form->turn_end_flag = 1; + City_zoom_to (first_unhappy_city, __, 0); + } else if (response == 1) // just cancel turn end + p_main_screen_form->turn_end_flag = 1; + // else do nothing, let turn end + + } +} + +void +do_trade_scroll (DiploForm * diplo, int forward) +{ + int increment = forward ? 1 : -1; + int id = -1; + for (int n = (diplo->other_party_civ_id + increment) & 31; n != diplo->other_party_civ_id; n = (n + increment) & 31) + if ((n != 0) && // if N is not barbs AND + (n != p_main_screen_form->Player_CivID) && // N is not the player's AND + (*p_player_bits & (1U << n)) && // N belongs to an active player AND + (leaders[p_main_screen_form->Player_CivID].Contacts[n] & 1) && // N has contact with the player AND + Leader_ai_would_meet_with (&leaders[n], __, p_main_screen_form->Player_CivID)) { // AI is willing to meet + id = n; + break; + } + + if (id >= 0) { + is->trade_screen_scroll_to_id = id; + DiploForm_close (diplo); + // Note extra code needs to get run here if the other player is not an AI + } +} + +void __fastcall +patch_DiploForm_m82_handle_key_event (DiploForm * this, int edx, int virtual_key_code, int is_down) +{ + if (is->eligible_for_trade_scroll && + (this->mode == 2) && + ((virtual_key_code == VK_LEFT) || (virtual_key_code == VK_RIGHT)) && + (! is_down)) + do_trade_scroll (this, virtual_key_code == VK_RIGHT); + else + DiploForm_m82_handle_key_event (this, __, virtual_key_code, is_down); +} + +int __fastcall +patch_DiploForm_m68_Show_Dialog (DiploForm * this, int edx, int param_1, void * param_2, void * param_3) +{ + if (is->open_diplo_form_straight_to_trade) { + is->open_diplo_form_straight_to_trade = 0; + + // Done by the base game but not necessary as far as I can tell + // void (__cdecl * FUN_00537700) (int) = 0x537700; + // FUN_00537700 (0x15); + // this->field_E9C[0] = this->field_E9C[0] + 1; + + // Set diplo screen mode to two-way trade negotation + this->mode = 2; + + // Set AI's diplo message to something like "what did you have in mind" + int iVar35 = DiploForm_set_their_message (this, __, DM_AI_PROPOSAL_RESPONSE, 0, 0x1A8); + this->field_1390[0] = DM_AI_PROPOSAL_RESPONSE; + this->field_1390[1] = 0; + this->field_1390[2] = iVar35; + + // Reset player message options. This will replace the propose deal, declare war, and leave options with the usual "nevermind" option + // that appears for negotiations. + DiploForm_reset_our_message_choices (this); + + // Done by the base game but not necessary as far as I can tell + // void (__fastcall * FUN_004C89A0) (void *) = 0x4C89A0; + // FUN_004C89A0 (&this->field_1BF4[0]); + + } + + return DiploForm_m68_Show_Dialog (this, __, param_1, param_2, param_3); +} + +void __fastcall +patch_DiploForm_do_diplomacy (DiploForm * this, int edx, int diplo_message, int param_2, int civ_id, int do_not_request_audience, int war_negotiation, int disallow_proposal, TradeOfferList * our_offers, TradeOfferList * their_offers) +{ + is->open_diplo_form_straight_to_trade = 0; + is->trade_screen_scroll_to_id = -1; + + // Trade screen scroll is disabled in online games b/c there's extra synchronization we'd need to do to open or close the diplo screen with + // a human player. + is->eligible_for_trade_scroll = is->current_config.enable_trade_screen_scroll && (! is_online_game ()); + + if (is->eligible_for_trade_scroll && (is->trade_scroll_button_state == IS_UNINITED)) + init_trade_scroll_buttons (this); + + WITH_PAUSE_FOR_POPUP { + DiploForm_do_diplomacy (this, __, diplo_message, param_2, civ_id, do_not_request_audience, war_negotiation, disallow_proposal, our_offers, their_offers); + + while (is->trade_screen_scroll_to_id >= 0) { + int scroll_to_id = is->trade_screen_scroll_to_id; + is->trade_screen_scroll_to_id = -1; + is->open_diplo_form_straight_to_trade = 1; + DiploForm_do_diplomacy (this, __, DM_AI_COUNTER, 0, scroll_to_id, 1, 0, 0, NULL, NULL); + } + } + + is->open_diplo_form_straight_to_trade = 0; + is->eligible_for_trade_scroll = 0; +} + +void __fastcall +patch_DiploForm_m22_Draw (DiploForm * this) +{ + if (is->trade_scroll_button_state == IS_OK) { + Button * left = is->trade_scroll_button_left, + * right = is->trade_scroll_button_right; + if (is->eligible_for_trade_scroll && (this->mode == 2)) { + left ->vtable->m01_Show_Enabled ((Base_Form *)left , __, 0); + right->vtable->m01_Show_Enabled ((Base_Form *)right, __, 0); + left ->vtable->m73_call_m22_Draw ((Base_Form *)left); + right->vtable->m73_call_m22_Draw ((Base_Form *)right); + } else { + left ->vtable->m02_Show_Disabled ((Base_Form *)left); + right->vtable->m02_Show_Disabled ((Base_Form *)right); + } + } + + DiploForm_m22_Draw (this); +} + +void +intercept_end_of_turn () +{ + if (is->current_config.enable_disorder_warning) { + check_happiness_at_end_of_turn (); + if (p_main_screen_form->turn_end_flag == 1) // Check if player cancelled turn ending in the disorder warning popup + return; + } + + // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + + if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { + is->city_loc_display_perspective = -1; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw + } + + // Clear things that don't apply across turns + is->have_job_and_loc_to_skip = 0; +} + +bool +is_worker_or_settler_command (int unit_command_value) +{ + return (unit_command_value & 0x20000000) || + ((unit_command_value >= UCV_Build_Remote_Colony) && (unit_command_value <= UCV_Auto_Save_Tiles)); +} + +bool +command_would_replace_district (int unit_command_value) +{ + // Note: Roads & railroads, etc. can coexist with the district + return (unit_command_value == UCV_Build_Mine) || + (unit_command_value == UCV_Irrigate) || + (unit_command_value == UCV_Plant_Forest) || + (unit_command_value == UCV_Build_Outpost) || + (unit_command_value == UCV_Build_Fortress) || + (unit_command_value == UCV_Build_Barricade) || + (unit_command_value == UCV_Build_Airfield) || + (unit_command_value == UCV_Build_Radar_Tower) || + (unit_command_value == UCV_Build_Colony); +} + +bool +handle_worker_command_that_may_replace_district (Unit * unit, int unit_command_value, bool * removed_existing) +{ + if (removed_existing != NULL) + *removed_existing = false; + + if ((! is->current_config.enable_districts) || (unit == NULL)) return true; + if (! is_worker_or_settler_command (unit_command_value)) return true; + if (! command_would_replace_district (unit_command_value)) return true; + if (! patch_Unit_can_perform_command (unit, __, unit_command_value)) return true; + + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + if ((tile == NULL) || (tile == p_null_tile)) + return true; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (! district_is_complete (tile, inst->district_id))) + return true; + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, tile, &tile_x, &tile_y)) + return false; + + int district_id = inst->district_id; + int civ_id = unit->Body.CivID; + bool redundant_district = district_instance_is_redundant (inst, tile); + bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (district_id, civ_id, tile_x, tile_y); + if (redundant_district) + would_lose_buildings = false; + + bool remove_existing = redundant_district; + if (inst != NULL && district_id >= 0 && district_id < is->district_count) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char *)is->district_configs[district_id].display_name, -1, -1); + set_popup_str_param (1, (char *)is->district_configs[district_id].display_name, -1, -1); + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + would_lose_buildings + ? "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT" + : "C3X_CONFIRM_BUILD_IMPROVEMENT_OVER_DISTRICT_SAFE", + -1, 0, 0, 0); + int sel = patch_show_popup (popup, __, 0, 0); + if (sel != 0) + return false; + remove_existing = true; + } + + if (remove_existing) { + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + handle_district_removed (tile, district_id, tile_x, tile_y, false); + if (removed_existing != NULL) + *removed_existing = true; + } + + return true; +} + +bool __fastcall + patch_Unit_can_upgrade (Unit * this) +{ + bool base = Unit_can_upgrade (this); + int available; + City * city = city_at (this->Body.X, this->Body.Y); + if (base && + (city != NULL) && + get_available_unit_count (&leaders[this->Body.CivID], City_get_upgraded_type_id (city, __, this->Body.UnitTypeID), &available) && + (available <= 0)) + return false; + else + return base; +} + +bool +is_district_command (int unit_command_value) +{ + int district_id = -1; + if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) + return false; + + return district_id != NATURAL_WONDER_DISTRICT_ID; +} + +int __fastcall +patch_Map_check_colony_location (Map * this, int edx, int tile_x, int tile_y, int civ_id) +{ + int base = Map_check_colony_location (this, __, tile_x, tile_y, civ_id); + Tile * tile = tile_at (tile_x, tile_y); + + if ((tile == NULL) || (tile == p_null_tile) || ! is->current_config.allow_extraterritorial_colonies) + return base; + + if (tile->vtable->m35_Check_Is_Water (tile)) return base; + if (Tile_has_city (tile) || Tile_has_colony (tile)) return base; + + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_id < 0) || (owner_id == civ_id)) return base; + + int resource_type = Tile_get_resource_visible_to (tile, __, civ_id); + if ((resource_type < 0) || (resource_type >= p_bic_data->ResourceTypeCount)) return base; + + int req_tech = p_bic_data->ResourceTypes[resource_type].RequireID; + if ((req_tech >= 0) && (! Leader_has_tech (&leaders[civ_id], __, req_tech))) return base; + + int res_class = p_bic_data->ResourceTypes[resource_type].Class; + if ((res_class != RC_Strategic) && (res_class != RC_Luxury)) return base; + if (tile->vtable->m26_Check_Tile_Building (tile)) + return 6; + + return 0; +} + +bool __fastcall +patch_Unit_can_perform_command (Unit * this, int edx, int unit_command_value) +{ + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + // No worker or settler commands allowed on natural wonders + if ((tile != NULL) && (tile != p_null_tile) && is->current_config.enable_natural_wonders) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && + (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) { + if (is_worker_or_settler_command (unit_command_value) || is_district_command (unit_command_value)) + return false; + } + } + + if (is_district_command (unit_command_value)) { + int district_id; + if (! itable_look_up (&is->command_id_to_district_id, unit_command_value, &district_id)) + return false; + + return is_worker (this) && can_build_district_on_tile (tile, district_id, this->Body.CivID); + } + // Extra check for colony founding if extraterritorial colonies allowed + else if (unit_command_value == UCV_Build_Colony || unit_command_value == UCV_Build_Remote_Colony) { + if (is->current_config.allow_extraterritorial_colonies && is_worker (this)) { + return patch_Map_check_colony_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID) == 0; + } + } + // Extra check for road building if bridge districts allowed + else if (unit_command_value == UCV_Build_Road) { + struct district_instance * inst = get_district_instance (tile); + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + if (!has_road && (inst != NULL) && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) + return true; + } + // Extra check for railroad building if bridge districts allowed + else if (unit_command_value == UCV_Build_Railroad) { + struct district_instance * inst = get_district_instance (tile); + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; + if ((inst != NULL) && is_worker (this) && has_road && + ! has_rail && tile_has_district_at (this->Body.X, this->Body.Y, BRIDGE_DISTRICT_ID)) { + int req_tech = p_bic_data->WorkerJobs[WJ_Build_Railroad].RequireID; + if ((req_tech < 0) || + ((req_tech != p_bic_data->AdvanceCount) && + Leader_has_tech (&leaders[this->Body.CivID], __, req_tech))) { + if (Leader_has_resources_for_job_at (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y)) + return true; + } + } + } + else if (unit_command_value == UCV_Build_Mine) { + bool has_district = (tile != NULL) && (tile != p_null_tile) && (get_district_instance (tile) != NULL); + + if (has_district) { + return Tile_get_mining_bonus (tile) > 0; + } + } else if (unit_command_value == UCV_Pillage) { + return patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y); + } + } + if (is->current_config.disable_worker_automation && + (this->Body.CivID == p_main_screen_form->Player_CivID) && + (unit_command_value == UCV_Automate)) + return false; + else if (is->current_config.disallow_land_units_from_affecting_water_tiles && + is_worker_or_settler_command (unit_command_value)) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + enum UnitTypeClasses class = p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class; + return ((class != UTC_Land) || (! tile->vtable->m35_Check_Is_Water (tile))) && + Unit_can_perform_command (this, __, unit_command_value); + } + + return Unit_can_perform_command (this, __, unit_command_value); +} + +void __fastcall +patch_Unit_join_city (Unit * this, int edx, City * city) +{ + if (is->current_config.enable_districts && is_worker (this)) { + int civ_id = this->Body.CivID; + bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; + if (! is_human) { + struct district_worker_record * rec = get_tracked_worker_record (this); + if ((rec != NULL) && (rec->pending_req != NULL)) { + ai_move_district_worker (this, rec); + return; + } + + Tile * worker_tile = tile_at (this->Body.X, this->Body.Y); + if ((worker_tile != NULL) && (worker_tile != p_null_tile)) { + int worker_continent_id = worker_tile->vtable->m46_Get_ContinentID (worker_tile); + + if ((civ_id >= 0) && (civ_id < 32)) { + struct pending_district_request * same_city_req = NULL; + struct pending_district_request * same_continent_req = NULL; + + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req == NULL) || (req->assigned_worker_id >= 0)) + continue; + if ((req->civ_id != civ_id) || (req->city_id < 0)) + continue; + + City * req_city = get_city_ptr (req->city_id); + if (req_city == NULL) + continue; + + if (city != NULL && req_city->Body.ID == city->Body.ID) { + same_city_req = req; + break; + } + + Tile * req_city_tile = tile_at (req_city->Body.X, req_city->Body.Y); + if ((req_city_tile != NULL) && (req_city_tile != p_null_tile)) { + int req_continent_id = req_city_tile->vtable->m46_Get_ContinentID (req_city_tile); + if (req_continent_id == worker_continent_id) { + same_continent_req = req; + } + } + } + + struct pending_district_request * chosen_req = (same_city_req != NULL) ? same_city_req : same_continent_req; + if (chosen_req != NULL) { + City * req_city = get_city_ptr (chosen_req->city_id); + if (req_city != NULL) { + int target_x = 0; + int target_y = 0; + Tile * target_tile = find_tile_for_district (req_city, chosen_req->district_id, &target_x, &target_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); + assign_worker_to_district (chosen_req, this, req_city, chosen_req->district_id, target_x, target_y); + return; + } + } + } + } + } + } + } + + Unit_join_city (this, __, city); +} + +bool __fastcall +patch_Unit_can_pillage (Unit * this, int edx, int tile_x, int tile_y) +{ + bool base = Unit_can_pillage (this, __, tile_x, tile_y); + + if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return base; + + int district_id = inst->district_id; + if (is->current_config.enable_natural_wonders && + (district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) + return false; + + if (! district_is_complete (tile, district_id)) + return true; + + if (district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info == NULL || info->state != WDS_COMPLETED) + return true; + return is->current_config.completed_wonder_districts_can_be_destroyed; + } + + return true; +} + +bool __fastcall +patch_Unit_can_do_worker_command_for_button_setup (Unit * this, int edx, int unit_command_value) +{ + bool base = patch_Unit_can_perform_command (this, __, unit_command_value); + + // If the command is to build a city and it can't be done because another city is already too close, and the minimum separation was changed + // from its standard value, then return true here so that the build city button will be added anyway. We'll gray it out later. Check that the + // grayed out button image is initialized now so we don't activate the build city button then find out later we can't gray it out. + if ((! base) && + (unit_command_value == UCV_Build_City) && + (is->current_config.minimum_city_separation > 1) && + (patch_Map_check_city_location (&p_bic_data->Map, __, this->Body.X, this->Body.Y, this->Body.CivID, false) == CLV_CITY_TOO_CLOSE) && + (init_disabled_command_buttons (), is->disabled_command_img_state == IS_OK)) + return true; + + else + return base; +} + +int +compare_helpers (void const * vp_a, void const * vp_b) +{ + Unit * a = get_unit_ptr (*(int *)vp_a), + * b = get_unit_ptr (*(int *)vp_b); + if ((a != NULL) && (b != NULL)) { + // Compute how many movement points each has left (ML = moves left) + int ml_a = patch_Unit_get_max_move_points (a) - a->Body.Moves, + ml_b = patch_Unit_get_max_move_points (b) - b->Body.Moves; + + // Whichever one has more MP left comes first in the array + if (ml_a > ml_b) return 1; + else if (ml_b > ml_a) return -1; + else return 0; + } else + // If at least one of the unit ids is invalid, might as well sort it later in the array + return (a != NULL) ? -1 : ((b != NULL) ? 1 : 0); +} + +void +issue_stack_worker_command (Unit * unit, int command) +{ + int tile_x = unit->Body.X; + int tile_y = unit->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + int unit_type_id = unit->Body.UnitTypeID; + int unit_id = unit->Body.ID; + + // Put together a list of helpers and store it on the memo. Helpers are just other workers on the same tile that can be issued the same command. + clear_memo (); + FOR_UNITS_ON (uti, tile) + if ((uti.id != unit_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) { + // check if the clicked command is among worker actions that this unit type can perform + int actions = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Worker_Actions; + int command_without_category = command & 0x0FFFFFFF; + if ((actions & command_without_category) == command_without_category) + memoize (uti.id); + } + + // Sort the list of helpers so that the ones with the fewest remaining movement points are listed first. + qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_helpers); + + Unit * next_up = unit; + int i_next_helper = 0; + int last_action_didnt_happen; + do { + int state_before_action = next_up->Body.UnitState; + Main_Screen_Form_issue_command (p_main_screen_form, __, command, next_up); + last_action_didnt_happen = (next_up->Body.UnitState == state_before_action); + + // Call this update function to cause the worker to actually perform the action. Otherwise + // it only gets queued, the worker keeps is movement points, and the action doesn't get done + // until the interturn. + if (! last_action_didnt_happen) + next_up->vtable->update_while_active (next_up); + + next_up = NULL; + while ((i_next_helper < is->memo_len) && (next_up == NULL)) + next_up = get_unit_ptr (is->memo[i_next_helper++]); + } while ((next_up != NULL) && (! last_action_didnt_happen)); +} + +void +issue_district_worker_command (Unit * unit, int command) +{ + if (! is->current_config.enable_districts) + return; + + if (unit == NULL) + return; + + int tile_x = unit->Body.X; + int tile_y = unit->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return; + + if (! is_worker(unit)) + return; + + int district_id = -1; + if (! itable_look_up (&is->command_id_to_district_id, command, &district_id)) + return; + if ((district_id < 0) || (district_id >= is->district_count)) + return; + + if (! leader_can_build_district (&leaders[unit->Body.CivID], district_id)) + return; + + // Disallow placing districts on invalid terrain, pollution, or cratered tiles + if (tile->vtable->m21_Check_Crates (tile, __, 0)) + return; + if (tile->vtable->m20_Check_Pollution (tile, __, 0)) + return; + + if (! district_is_buildable_on_tile (&is->district_configs[district_id], tile)) + return; + + // If District will be replaced by another District + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete(tile, inst->district_id)) { + int existing_district_id = inst->district_id; + int inst_x, inst_y; + if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) + return; + + int civ_id = unit->Body.CivID; + bool redundant_district = district_instance_is_redundant (inst, tile); + bool would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, inst_x, inst_y); + if (redundant_district) + would_lose_buildings = false; + + bool remove_existing = false; + + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char*)is->district_configs[existing_district_id].display_name, -1, -1); + set_popup_str_param (1, (char*)is->district_configs[existing_district_id].display_name, -1, -1); + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + would_lose_buildings + ? "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT" + : "C3X_CONFIRM_REPLACE_DISTRICT_WITH_DIFFERENT_DISTRICT_SAFE", + -1, 0, 0, 0 + ); + + int sel = patch_show_popup (popup, __, 0, 0); + if (sel == 0) + remove_existing = true; + else + return; + + if (remove_existing) { + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); + handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); + } + } + + // If District will replace an improvement + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); + + if (removable_flags != 0) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_BUILD_DISTRICT_OVER_IMPROVEMENT", -1, 0, 0, 0); + int sel = patch_show_popup (popup, __, 0, 0); + if (sel != 0) + return; + } + + if (removable_flags != 0) + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + + inst = ensure_district_instance (tile, district_id, tile_x, tile_y); + inst->built_by_civ_id = unit->Body.CivID; + if (inst != NULL) + inst->state = DS_UNDER_CONSTRUCTION; + + Unit_set_state (unit, __, UnitState_Build_Mines); + unit->Body.Job_ID = WJ_Build_Mines; +} + +void +issue_stack_unit_mgmt_command (Unit * unit, int command) +{ + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + int unit_type_id = unit->Body.UnitTypeID; + int unit_id = unit->Body.ID; + + PopupForm * popup = get_popup_form (); + + clear_memo (); + + if (command == UCV_Fortify) { + // This probably won't work for online games since "fortify all" does additional work in that case. See Main_Screen_Form::fortify_all. + // I don't like how this method doesn't place units in the fortified pose. One workaround is so use + // Main_Screen_Form::issue_fortify_command, but that plays the entire fortify animation for each unit which is a major annoyance for + // large stacks. The base game's "fortify all" function also doesn't set the pose so I don't see any easy way to fix this. + FOR_UNITS_ON (uti, tile) + if ((uti.unit->Body.UnitTypeID == unit_type_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + (uti.unit->Body.CivID == unit->Body.CivID) && + (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) + Unit_set_state (uti.unit, __, UnitState_Fortifying); + + } else if (command == UCV_Upgrade_Unit) { + int our_treasury = leaders[unit->Body.CivID].Gold_Encoded + leaders[unit->Body.CivID].Gold_Decrement; + + // If the unit type we're upgrading to is limited, find out how many we can add. Keep that in "available". If the type is not limited, + // leave available set to INT_MAX. + int available = INT_MAX; { + City * city; + int upgrade_id; + if ((is->current_config.unit_limits.len > 0) && + patch_Unit_can_perform_command (unit, __, UCV_Upgrade_Unit) && + (NULL != (city = city_at (unit->Body.X, unit->Body.Y))) && + (0 < (upgrade_id = City_get_upgraded_type_id (city, __, unit_type_id)))) + get_available_unit_count (&leaders[unit->Body.CivID], upgrade_id, &available); + } + + int cost = 0; + FOR_UNITS_ON (uti, tile) + if ((available > 0) && + (uti.unit->Body.UnitTypeID == unit_type_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + patch_Unit_can_perform_command (uti.unit, __, UCV_Upgrade_Unit)) { + cost += Unit_get_upgrade_cost (uti.unit); + available--; + memoize (uti.id); + } + + if (cost <= our_treasury) { + set_popup_str_param (0, p_bic_data->UnitTypes[unit_type_id].Name, -1, -1); + set_popup_int_param (0, is->memo_len); + set_popup_int_param (1, cost); + popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "UPGRADE_ALL", -1, 0, 0, 0); + if (patch_show_popup (popup, __, 0, 0) == 0) + for (int n = 0; n < is->memo_len; n++) { + Unit * to_upgrade = get_unit_ptr (is->memo[n]); + if (to_upgrade != NULL) + Unit_upgrade (to_upgrade, __, false); + } + + } else { + set_popup_int_param (0, cost); + int param_5 = is_online_game () ? 0x4000 : 0; // As in base code + popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "NO_GOLD_TO_UPGRADE_ALL", -1, 0, param_5, 0); + patch_show_popup (popup, __, 0, 0); + } + + } else if (command == UCV_Disband) { + FOR_UNITS_ON (uti, tile) + if ((uti.unit->Body.UnitTypeID == unit_type_id) && + (uti.unit->Body.Container_Unit < 0) && + (uti.unit->Body.UnitState == 0) && + (uti.unit->Body.Moves < patch_Unit_get_max_move_points (uti.unit))) + memoize (uti.id); + + if (is->memo_len > 0) { + set_popup_int_param (0, is->memo_len); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_STACK_DISBAND", -1, 0, 0, 0); + if (patch_show_popup (popup, __, 0, 0) == 0) { + for (int n = 0; n < is->memo_len; n++) { + Unit * to_disband = get_unit_ptr (is->memo[n]); + if (to_disband) + Unit_disband (to_disband); + } + } + } + } +} + +void __fastcall +patch_Main_GUI_handle_button_press (Main_GUI * this, int edx, int button_id) +{ + // Set SB flag according to case (2) + if (button_id < 42) { + if ((is->sc_img_state == IS_OK) && + ((this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMBARD].imgs[0]) || + (this->Unit_Command_Buttons[button_id].Button.Images[0] == &is->sc_button_image_sets[SC_BOMB ].imgs[0]))) + is->sb_activated_by_button = 1; + else + is->sb_activated_by_button = 0; + } + + int command = this->Unit_Command_Buttons[button_id].Command; + + // Clear any highlighted tiles + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + + if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { + is->city_loc_display_perspective = -1; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw + } + + // If a district, run district build logic + if (is->current_config.enable_districts && is_district_command (command)) { + clear_something_1 (); + Timer_clear (&this->timer_1); + issue_district_worker_command (p_main_screen_form->Current_Unit, command); + return; + } + + // Check if command is a worker build command (not a district) and a district exists on the tile + if (is->current_config.enable_districts && p_main_screen_form->Current_Unit != NULL) { + + bool removed_existing = false; + if (! handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) + return; + if (removed_existing) { + clear_something_1 (); + Timer_clear (&this->timer_1); + Main_GUI_handle_button_press (this, __, button_id); + return; + } + } + + struct sc_button_info const * stack_button_info; { + stack_button_info = NULL; + if (button_id < 42) // If button pressed was a unit command button + for (int n = 0; n < COUNT_STACKABLE_COMMANDS; n++) + if (command == sc_button_infos[n].command) { + stack_button_info = &sc_button_infos[n]; + break; + } + } + + if ((stack_button_info == NULL) || // If there's no stack command for the pressed button OR + (! is->current_config.enable_stack_unit_commands) || // stack unit commands are not enabled OR + (((*p_GetAsyncKeyState) (VK_CONTROL)) >> 8 == 0) || // CTRL key is not down OR + (p_main_screen_form->Current_Unit == NULL) || // no unit is selected OR + is_online_game ()) { // is online game + Main_GUI_handle_button_press (this, __, button_id); + return; + } + + enum stackable_command_kind kind = stack_button_info->kind; + if ((kind == SCK_TERRAFORM) || (kind == SCK_UNIT_MGMT)) { + // Replicate behavior of function we're replacing + clear_something_1 (); + Timer_clear (&this->timer_1); + + if (kind == SCK_TERRAFORM) + issue_stack_worker_command (p_main_screen_form->Current_Unit, stack_button_info->command); + else if (kind == SCK_UNIT_MGMT) + issue_stack_unit_mgmt_command (p_main_screen_form->Current_Unit, stack_button_info->command); + } else + Main_GUI_handle_button_press (this, __, button_id); +} + +bool __fastcall +patch_Main_Screen_Form_issue_command (Main_Screen_Form * this, int edx, int command, Unit * unit) +{ + Unit * target_unit = unit; + if (target_unit == NULL) + target_unit = this->Current_Unit; + + if (is->current_config.enable_districts) { + bool removed_existing = false; + if (! handle_worker_command_that_may_replace_district (target_unit, command, &removed_existing)) + return false; + } + + return Main_Screen_Form_issue_command (this, __, command, unit); +} + +bool +is_command_button_active (Main_GUI * main_gui, enum Unit_Command_Values command) +{ + Command_Button * buttons = main_gui->Unit_Command_Buttons; + for (int n = 0; n < 42; n++) + if (((buttons[n].Button.Base_Data.Status2 & 1) != 0) && (buttons[n].Command == command)) + return true; + return false; +} + +int __fastcall +patch_Main_Screen_Form_handle_key_down (Main_Screen_Form * this, int edx, int char_code, int virtual_key_code) +{ + // Set SB flag according to case (4) + int precision_strike_is_available = is_command_button_active (&this->GUI, UCV_Precision_Bombing); + if ((virtual_key_code == VK_B) || (precision_strike_is_available && (virtual_key_code == VK_P))) + is->sb_activated_by_button = 0; + + if ((virtual_key_code & 0xFF) == VK_CONTROL) { + set_up_stack_worker_buttons (&this->GUI); + + if (is->current_config.enable_city_work_radii_highlights && + ! is->highlight_city_radii) { + Unit * unit = p_main_screen_form->Current_Unit; + if (unit != NULL) { + is->highlight_city_radii = true; + compute_highlighted_worker_tiles_for_districts (); + this->vtable->m73_call_m22_Draw ((Base_Form *)this); + } + } + } else { + if (is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + } + + char original_turn_end_flag = this->turn_end_flag; + int tr = Main_Screen_Form_handle_key_down (this, __, char_code, virtual_key_code); + if ((original_turn_end_flag == 1) && (this->turn_end_flag == 0)) + intercept_end_of_turn (); + + return tr; +} + +int +patch_handle_cursor_change_in_jgl () +{ + // Set SB flag according to case (3) and the annoying state + if ((is->sb_activated_by_button != 2) && + (p_main_screen_form->Mode_Action != UMA_Bombard) && + (p_main_screen_form->Mode_Action != UMA_Air_Bombard)) + is->sb_activated_by_button = 0; + + return handle_cursor_change_in_jgl (); +} + +void __fastcall +patch_Main_Screen_Form_handle_left_click_on_map_1 (Main_Screen_Form * this, int edx, int param_1, int param_2) +{ + if (is->sb_activated_by_button == 1) + is->sb_activated_by_button = 2; + Main_Screen_Form_handle_left_click_on_map_1 (this, __, param_1, param_2); + is->sb_activated_by_button = 0; +} + + +void __fastcall +patch_Main_GUI_handle_click_in_status_panel (Main_GUI * this, int edx, int mouse_x, int mouse_y) +{ + char original_turn_end_flag = p_main_screen_form->turn_end_flag; + Main_GUI_handle_click_in_status_panel (this, __, mouse_x, mouse_y); + if ((original_turn_end_flag == 1) && (p_main_screen_form->turn_end_flag == 0)) + intercept_end_of_turn (); +} + +// Gets effective shields generated per turn, including civil engineers, disorder, and anarchy. +int +get_city_production_rate (City * city, enum City_Order_Types order_type, int order_id) +{ + int in_disorder = city->Body.Status & CSF_Civil_Disorder, + in_anarchy = p_bic_data->Governments[leaders[city->Body.CivID].GovernmentType].b_Transition_Type, + getting_tile_shields = (! in_disorder) && (! in_anarchy); + + if (order_type == COT_Improvement) { + int building_wealth = (p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0; + int specialist_shields = 0; + FOR_CITIZENS_IN (ci, city) + if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) // I don't know what is check is for but it's done in the base code + specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; + return (getting_tile_shields ? city->Body.ProductionIncome : 0) + ((! building_wealth) ? specialist_shields : 0); + } else if ((order_type == COT_Unit) && getting_tile_shields) + return city->Body.ProductionIncome; + else + return 0; +} + +void __fastcall +patch_City_Form_open (City_Form * this, int edx, City * city, int param_2) +{ + recompute_resources_if_necessary (); + + WITH_PAUSE_FOR_POPUP { + City_Form_open (this, __, city, param_2); + } +} + +void +init_district_icons () +{ + if (is->dc_icons_img_state != IS_UNINITED) + return; + + char ss[200]; + snprintf (ss, sizeof ss, "[C3X] init_district_icons: state=%d\n", is->dc_icons_img_state); + (*p_OutputDebugStringA) (ss); + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("Districts/DistrictIncomeIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image == NULL) || + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { + (*p_OutputDebugStringA) ("[C3X] PCX file for district icons failed to load or is too small.\n"); + is->dc_icons_img_state = IS_INIT_FAILED; + goto cleanup; + } + + // Extract science icon (index 1) + Sprite_construct (&is->district_science_icon); + Sprite_slice_pcx (&is->district_science_icon, __, &pcx, 1 + 1*31, 1, 30, 30, 1, 1); + + // Extract commerce icon (index 2) + Sprite_construct (&is->district_commerce_icon); + Sprite_slice_pcx (&is->district_commerce_icon, __, &pcx, 1 + 2*31, 1, 30, 30, 1, 1); + + // Extract shield icon (index 4) + Sprite_construct (&is->district_shield_icon); + Sprite_slice_pcx (&is->district_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); + + // Extract corruption icon (index 5) + Sprite_construct (&is->district_corruption_icon); + Sprite_slice_pcx (&is->district_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); + + // Extract food icon (index 6) + Sprite_construct (&is->district_food_icon); + Sprite_slice_pcx (&is->district_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); + + // Extract food eaten icon (index 7) + Sprite_construct (&is->district_food_eaten_icon); + Sprite_slice_pcx (&is->district_food_eaten_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); + + // Extract small happiness icon (index 12) + Sprite_construct (&is->district_happiness_icon_small); + Sprite_slice_pcx (&is->district_happiness_icon_small, __, &pcx, 1 + 12*31, 1, 30, 30, 1, 1); + + // Extract small shield icon (index 13) + Sprite_construct (&is->district_shield_icon_small); + Sprite_slice_pcx (&is->district_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); + + // Extract small commerce icon (index 14) + Sprite_construct (&is->district_commerce_icon_small); + Sprite_slice_pcx (&is->district_commerce_icon_small, __, &pcx, 1 + 14*31, 1, 30, 30, 1, 1); + + // Extract small food icon (index 15: x = 1 + 15*31 = 466, width 30) + Sprite_construct (&is->district_food_icon_small); + Sprite_slice_pcx (&is->district_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); + + // Extract small science icon (index 16) + Sprite_construct (&is->district_science_icon_small); + Sprite_slice_pcx (&is->district_science_icon_small, __, &pcx, 1 + 16*31, 1, 30, 30, 1, 1); + + // Extract small culture icon (index 18) + Sprite_construct (&is->district_culture_icon_small); + Sprite_slice_pcx (&is->district_culture_icon_small, __, &pcx, 1 + 18*31, 1, 30, 30, 1, 1); + + // Load Negatives (mostly red) from here + + // Extract negative small commerce icon (index 17) + Sprite_construct (&is->district_negative_commerce_icon_small); + Sprite_slice_pcx (&is->district_negative_commerce_icon_small, __, &pcx, 1 + 17*31, 1, 30, 30, 1, 1); + + // Extract small unhappiness icon (index 19) + Sprite_construct (&is->district_unhappiness_icon_small); + Sprite_slice_pcx (&is->district_unhappiness_icon_small, __, &pcx, 1 + 19*31, 1, 30, 30, 1, 1); + + // Extract negative small shield icon (index 20) + Sprite_construct (&is->district_negative_shield_icon_small); + Sprite_slice_pcx (&is->district_negative_shield_icon_small, __, &pcx, 1 + 20*31, 1, 30, 30, 1, 1); + + // Extract negative small culture icon (index 21) + Sprite_construct (&is->district_negative_culture_icon_small); + Sprite_slice_pcx (&is->district_negative_culture_icon_small, __, &pcx, 1 + 21*31, 1, 30, 30, 1, 1); + + // Extract negative small culture icon (index 22) + Sprite_construct (&is->district_negative_food_icon_small); + Sprite_slice_pcx (&is->district_negative_food_icon_small, __, &pcx, 1 + 22*31, 1, 30, 30, 1, 1); + + // Extract negative small science icon (index 23) + Sprite_construct (&is->district_negative_science_icon_small); + Sprite_slice_pcx (&is->district_negative_science_icon_small, __, &pcx, 1 + 23*31, 1, 30, 30, 1, 1); + + is->dc_icons_img_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void __fastcall +patch_City_Form_draw (City_Form * this) +{ + // Recompute city form production rect location every time because the config might have changed. Doing it here is also easier than + // patching the constructor. + int form_top = (p_bic_data->ScreenHeight - this->Background_Image.Height) / 2; + this->Production_Storage_Indicator.top = form_top + 621 + (is->current_config.show_detailed_city_production_info ? 34 : 0); + + is->drawn_strat_resource_count = 0; + + // Make sure culture income (including from districts) is up to date before the draw event + if (is->current_config.enable_districts) + patch_City_recompute_culture_income(this->CurrentCity); + + City_Form_draw (this); + + if (is->current_config.show_detailed_city_production_info) { + City * city = this->CurrentCity; + int order_type = city->Body.Order_Type, + order_id = city->Body.Order_ID, + order_progress = City_get_order_progress (city), + order_cost = City_get_order_cost (city), + prod_rate = get_city_production_rate (city, order_type, order_id), + building_wealth = (order_type == COT_Improvement) && ((p_bic_data->Improvements[order_id].ImprovementFlags & ITF_Capitalization) != 0); + + int turns_left, surplus; { + if (prod_rate > 0) { + turns_left = (order_cost - order_progress) / prod_rate; + if ((order_cost - order_progress) % prod_rate != 0) + turns_left++; + if (turns_left < 1) + turns_left = 1; + surplus = (turns_left * prod_rate) - (order_cost - order_progress); + } else { + turns_left = 9999; + surplus = 0; + } + } + + char line1[100]; { + if (prod_rate > 0) { + if (! building_wealth) + snprintf (line1, sizeof line1, "%s %d %s", this->Labels.To_Build, turns_left, (turns_left == 1) ? this->Labels.Single_Turn : this->Labels.Multiple_Turns); + else + snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_NEVER_COMPLETES]); + } else + snprintf (line1, sizeof line1, "%s", is->c3x_labels[CL_HALTED]); + line1[(sizeof line1) - 1] = '\0'; + } + + char line2[100]; { + if (! building_wealth) { + int percent_complete = order_cost > 0 ? ((10000 * order_progress) / order_cost + 50) / 100 : 100; + snprintf (line2, sizeof line2, "%d / %d (%d%s)", order_progress, order_cost, percent_complete, this->Labels.Percent); + } else + snprintf (line2, sizeof line2, "---"); + line2[(sizeof line2) - 1] = '\0'; + } + + char line3[100]; { + if ((! building_wealth) && (prod_rate > 0)) { + int s_per, s_rem; { + if (turns_left > 1) { + s_per = surplus / turns_left; + s_rem = surplus % turns_left; + } else { + s_per = surplus; + s_rem = 0; + } + } + char * s_lab = is->c3x_labels[CL_SURPLUS]; + if ((s_per != 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d + %d %s", s_lab, s_rem, s_per, this->Labels.Per_Turn); + else if ((s_per == 0) && (s_rem != 0)) snprintf (line3, sizeof line3, "%s: %d", s_lab, s_rem); + else if ((s_per != 0) && (s_rem == 0)) snprintf (line3, sizeof line3, "%s: %d %s", s_lab, s_per, this->Labels.Per_Turn); + else snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NONE]); + } else + snprintf (line3, sizeof line3, "%s", is->c3x_labels[CL_SURPLUS_NA]); + line3[(sizeof line3) - 1] = '\0'; + } + + Object_66C3FC * font = get_font (10, FSF_NONE); + int left = this->Production_Storage_Indicator.left, + top = this->Production_Storage_Indicator.top, + width = this->Production_Storage_Indicator.right - left; + PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line1, left, top - 42, width, strlen (line1)); + PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line2, left, top - 28, width, strlen (line2)); + PCX_Image_draw_centered_text (&this->Base.Data.Canvas, __, font, line3, left, top - 14, width, strlen (line3)); + } + + // Draw district commerce bonuses (gold and science) + if (! (is->current_config.enable_districts || is->current_config.enable_natural_wonders)) + return; + + // Lazy load district icons + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + if (is->dc_icons_img_state != IS_OK) + return; + + City * city = this->CurrentCity; + if (city == NULL) + return; + + // Calculate district gold and science bonuses by iterating workable tiles + int district_gold = 0; + int city_civ_id = city->Body.CivID; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + if ((wai.dx == 0) && (wai.dy == 0)) continue; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + struct district_config const * cfg = &is->district_configs[district_id]; + int gold_bonus = 0; + get_effective_district_yields (inst, cfg, NULL, NULL, &gold_bonus, NULL, NULL, NULL); + district_gold += gold_bonus; + } + + Leader * leader = &leaders[city_civ_id]; + int gold_proportion = (district_gold * leader->gold_slider) / 10; + int science_proportion = (district_gold * leader->science_slider) / 10; + + // Draw district gold icons + if (gold_proportion > 0) { + Sprite * gold_sprite = &is->district_commerce_icon; + int sprite_width = gold_sprite->Width; + int sprite_height = gold_sprite->Height; + + struct tagRECT * gold_rect = &this->Gold_Income_Rect; + int total_gold = City_get_net_commerce (city, __, 2, true); + + // Calculate spacing + int spacing = sprite_width; + if ((total_gold > 1) && (total_gold * sprite_width != (gold_rect->right - gold_rect->left))) { + int rect_width = gold_rect->right - gold_rect->left; + if (rect_width <= total_gold * sprite_width) { + spacing = (rect_width - sprite_width) / (total_gold - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > sprite_width) + spacing = sprite_width; + } + } + + // Draw from right to left + int x_offset = 0; + int y_offset = 5; + for (int i = 0; i < gold_proportion && i < total_gold; i++) { + int x = gold_rect->right - x_offset - sprite_width; + int y = gold_rect->top + ((gold_rect->bottom - gold_rect->top >> 1) - + (sprite_height >> 1)) + y_offset; + + Sprite_draw (gold_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); + x_offset += spacing; + } + } + + // Draw district science icons + if (science_proportion > 0) { + Sprite * science_sprite = &is->district_commerce_icon; + int sprite_width = science_sprite->Width; + int sprite_height = science_sprite->Height; + + struct tagRECT * science_rect = &this->Science_Income_Rect; + int total_science = City_get_net_commerce (city, __, 1, true); + + // Calculate spacing + int spacing = sprite_width; + if ((total_science > 1) && (total_science * sprite_width != (science_rect->right - science_rect->left))) { + int rect_width = science_rect->right - science_rect->left; + if (rect_width <= total_science * sprite_width) { + spacing = (rect_width - sprite_width) / (total_science - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > sprite_width) + spacing = sprite_width; + } + } + + // Draw from right to left + int x_offset = 0; + int y_offset = 5; + for (int i = 0; i < science_proportion && i < total_science; i++) { + int x = science_rect->right - x_offset - sprite_width; + int y = science_rect->top + ((science_rect->bottom - science_rect->top >> 1) - + (sprite_height >> 1)) + y_offset; + + Sprite_draw (science_sprite, __, &(this->Base).Data.Canvas, x, y, NULL); + x_offset += spacing; + } + } +} + +void __fastcall +patch_City_Form_print_production_info (City_Form *this, int edx, String256 * out_strs, int str_capacity) +{ + City_Form_print_production_info (this, __, out_strs, str_capacity); + if (is->current_config.show_detailed_city_production_info) + out_strs[1].S[0] = '\0'; +} + +int __fastcall +patch_Sprite_draw_strat_res_on_city_screen (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + if (is->current_config.compact_strategic_resource_display_on_city_screen) + pixel_x -= 13 * is->drawn_strat_resource_count + 17; + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +int __fastcall +patch_PCX_Image_do_draw_cntd_text_for_strat_res (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) +{ + if (is->current_config.compact_strategic_resource_display_on_city_screen) + x -= 13 * is->drawn_strat_resource_count + 17; + int tr = PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); + is->drawn_strat_resource_count++; + return tr; +} + +int __fastcall +patch_City_get_turns_to_build (City * this, int edx, enum City_Order_Types order_type, int order_id, bool param_3) +{ + // To fix the zero production crash, return 9999 when the city's total production rate is zero, avoiding a division by zero. That's only + // possible when producing an improvement due to negative shields from specialists. The original logic attempts to return 9999 in case of zero + // production but checks for that before including shields from specialists. + if (is->current_config.patch_zero_production_crash && (order_type == COT_Improvement)) { + + int specialist_shields = 0; + FOR_CITIZENS_IN (ci, this) + if ((ci.ctzn->Body.field_20[0] & 0xFF) == 0) + specialist_shields += p_bic_data->CitizenTypes[ci.ctzn->Body.WorkerType].Construction; + + // Return 9999 if the denominator in the base function's calculation would be zero. Note the base calc is incorrect in that it + // considers specialist shields to count toward Wealth, however we're not going to address that issue here, just stop the crash. + if (this->Body.ProductionIncome + specialist_shields <= 0) + return 9999; + } + + return City_get_turns_to_build (this, __, order_type, order_id, param_3); +} + +bool +is_below_stack_limit (Tile * tile, int civ_id, int type_id) +{ + enum UnitTypeClasses class = p_bic_data->UnitTypes[type_id].Unit_Class; + + int stack_limit = is->current_config.limit_units_per_tile[class]; + if (stack_limit <= 0) + return true; + + if (is->current_config.exclude_cities_from_units_per_tile_limit && + get_city_ptr (tile->CityID) != NULL) + return true; + + if (itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, type_id, 0)) + return true; + + FOR_UNITS_ON (uti, tile) { + // If there is a foreign unit on the tile then consider it as being below the stack limit. This ensures that the stack limit doesn't + // block combat between players. + if (uti.unit->Body.CivID != civ_id) + return true; + + int uti_type_id = uti.unit->Body.UnitTypeID; + if ((uti.unit->Body.Container_Unit < 0) && + (class == p_bic_data->UnitTypes[uti_type_id].Unit_Class) && + ! itable_look_up_or (&is->current_config.exclude_types_from_units_per_tile_limit, uti_type_id, 0)) { + stack_limit -= 1; + if (stack_limit <= 0) + return false; + } + } + return true; +} + +// Returns the ID of the civ this move is trespassing against, or 0 if it's not trespassing. +int +check_trespassing (int civ_id, Tile * from, Tile * to) +{ + int from_territory_id = from->vtable->m38_Get_Territory_OwnerID (from), + to_territory_id = to ->vtable->m38_Get_Territory_OwnerID (to); + if ((civ_id > 0) && + (to_territory_id != civ_id) && + (to_territory_id > 0) && + (to_territory_id != from_territory_id) && + (! leaders[civ_id].At_War[to_territory_id]) && + ((leaders[civ_id].Relation_Treaties[to_territory_id] & 2) == 0)) // Check right of passage + return to_territory_id; + else + return 0; +} + +bool +is_allowed_to_trespass (Unit * unit) +{ + int type_id = unit->Body.UnitTypeID; + if ((type_id >= 0) && (type_id < p_bic_data->UnitTypeCount)) { + UnitType * type = &p_bic_data->UnitTypes[type_id]; + return UnitType_has_ability (type, __, UTA_Hidden_Nationality) || UnitType_has_ability (type, __, UTA_Invisible); + } else + return false; +} + +bool +get_tile_district_impassibility (Tile * tile, bool * out_impassible, bool * out_impassible_to_wheeled) +{ + if (out_impassible != NULL) + *out_impassible = false; + if (out_impassible_to_wheeled != NULL) + *out_impassible_to_wheeled = false; + + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + if (! district_is_complete (tile, inst->district_id)) + return false; + + if (inst->district_id == NATURAL_WONDER_DISTRICT_ID) { + if (! is->current_config.enable_natural_wonders) + return false; + int natural_id = inst->natural_wonder_info.natural_wonder_id; + if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) + return false; + if (out_impassible != NULL) + *out_impassible = is->natural_wonder_configs[natural_id].impassible; + if (out_impassible_to_wheeled != NULL) + *out_impassible_to_wheeled = is->natural_wonder_configs[natural_id].impassible_to_wheeled; + return true; + } + + if (! is->current_config.enable_districts) + return false; + if ((inst->district_id < 0) || (inst->district_id >= is->district_count)) + return false; + + if (out_impassible != NULL) + *out_impassible = is->district_configs[inst->district_id].impassible; + if (out_impassible_to_wheeled != NULL) + *out_impassible_to_wheeled = is->district_configs[inst->district_id].impassible_to_wheeled; + return true; +} + +AdjacentMoveValidity __fastcall +patch_Unit_can_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, int param_2) +{ + AdjacentMoveValidity base_validity = Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2); + + if (is->current_config.enable_districts) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + Tile * dest = tile_at (nx, ny); + + // Let workers step onto coast tiles when the config flag is enabled (base logic treats this as an invalid sea move) + if (is->current_config.workers_can_enter_coast && is_worker (this) && + ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { + if ((dest != NULL) && + dest->vtable->m35_Check_Is_Water (dest) && + (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) + base_validity = AMV_OK; + } + + // Allow land units to enter bridge tiles + if (is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && + ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { + if ((dest != NULL) && (dest != p_null_tile)) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { + base_validity = AMV_OK; + } + } + } + + // Allow naval units to enter completed canal tiles + if (is->current_config.enable_canal_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && + ((base_validity == AMV_INVALID_SEA_MOVE) || (base_validity == AMV_CANNOT_EMBARK))) { + if ((dest != NULL) && (dest != p_null_tile)) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && (inst->district_id == CANAL_DISTRICT_ID) && district_is_complete (dest, inst->district_id)) { + base_validity = AMV_OK; + } + } + } + + if ((base_validity == AMV_OK) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { + if ((dest != NULL) && (dest != p_null_tile) && Tile_has_city (dest)) + return AMV_INVALID_SEA_MOVE; + } + } + + // Apply unit count per tile limit + int type_id = this->Body.UnitTypeID; + if ((base_validity == AMV_OK) && (is->current_config.limit_units_per_tile[p_bic_data->UnitTypes[type_id].Unit_Class] > 0)) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + if (! is_below_stack_limit (tile_at (nx, ny), this->Body.CivID, type_id)) + return AMV_CANNOT_PASS_BETWEEN; + } + + // Apply trespassing restriction + if (is->current_config.disallow_trespassing && (base_validity == AMV_OK)) { + Tile * from = tile_at (this->Body.X, this->Body.Y); + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + int trespasses_against_civ_id = check_trespassing (this->Body.CivID, from, tile_at (nx, ny)); + if ((trespasses_against_civ_id > 0) && (! is_allowed_to_trespass (this))) + // The tile might be occupied by a unit belonging to a civ other than the one that owns the territory (against whom we'd be + // trespassing). In this case we must forbid the move entirely since TRIGGERS_WAR will not stop it if we're at war with the + // occupying civ. This fixes a bug where units could trespass by attacking an enemy unit across a border. They would then get + // stuck halfway between tiles if they won. + return (trespasses_against_civ_id == get_tile_occupier_id (nx, ny, this->Body.CivID, false)) ? AMV_TRIGGERS_WAR : AMV_CANNOT_PASS_BETWEEN; + } + + return base_validity; +} + +bool +great_wall_blocks_civ (Tile * tile, int civ_id) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_great_wall_districts || + ! is->current_config.great_wall_districts_impassible_by_others) + return false; + + if ((tile == NULL) || (tile == p_null_tile)) + return false; + + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (owner_id <= 0) + return false; + if (owner_id == civ_id) + return false; + if ((civ_id > 0) && ((leaders[civ_id].Relation_Treaties[owner_id] & 2) != 0)) // 2 = right of passage + return false; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID)) + return false; + + if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) + return false; + + if (district_is_obsolete_for_civ (GREAT_WALL_DISTRICT_ID, civ_id)) + return false; + + return true; +} + +int __fastcall +patch_Trade_Net_get_movement_cost (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned flags, int neighbor_index, Trade_Net_Distance_Info * dist_info) +{ + if (is->is_computing_city_connections && // if this call came while rebuilding the trade network AND + (is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL) && // Trade Net X is set up AND + (unit == NULL) && ((flags == 0x1009) || (flags == 0x9))) // this call can be accelerated by TNX + return is->get_move_cost_for_sea_trade (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags, neighbor_index, dist_info); + + int base_cost = Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, neighbor_index, dist_info); + + bool districts_enabled = is->current_config.enable_districts; + if (districts_enabled) { + Tile * to = tile_at (to_x, to_y); + bool to_valid = (to != NULL) && (to != p_null_tile); + struct district_instance * to_inst = NULL; + bool to_inst_complete = false; + if (to_valid) { + to_inst = get_district_instance (to); + if (to_inst != NULL) + to_inst_complete = district_is_complete (to, to_inst->district_id); + } + + if ((unit != NULL) && great_wall_blocks_civ (to, unit->Body.CivID)) + return -1; + if ((unit != NULL) && to_valid) { + bool impassible = false; + bool impassible_to_wheeled = false; + if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { + if (impassible) + return -1; + if (impassible_to_wheeled && Unit_has_ability (unit, __, UTA_Wheeled)) { + Tile * from = tile_at (from_x, from_y); + bool connected_by_road = (from != NULL) && (to != NULL) && + (from->vtable->m25_Check_Roads (from, __, 0) != 0) && + (to->vtable->m25_Check_Roads (to, __, 0) != 0); + if (! connected_by_road) + return -1; + } + } + } + + // Let the pathfinder consider coastal tiles reachable for workers when the config flag is on + if (is->current_config.workers_can_enter_coast && + (base_cost < 0) && (unit != NULL) && is_worker (unit) && + to_valid && + to->vtable->m35_Check_Is_Water (to) && + (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) + base_cost = Unit_get_max_move_points (unit); + + // Let the pathfinder consider bridge tiles reachable for land units + if (is->current_config.enable_bridge_districts && + (base_cost < 0) && (unit != NULL) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == BRIDGE_DISTRICT_ID)) + base_cost = Unit_get_max_move_points (unit); + + // Let the pathfinder consider canal tiles reachable for naval units + if (is->current_config.enable_canal_districts && + (base_cost < 0) && (unit != NULL) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == CANAL_DISTRICT_ID)) + base_cost = Unit_get_max_move_points (unit); + + // Treat roads/rails on bridge districts like land roads/rails for movement cost. + if ((unit != NULL) && + is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Land)) { + Tile * from = tile_at (from_x, from_y); + if ((from != NULL) && (from != p_null_tile) && to_valid) { + struct district_instance * from_inst = get_district_instance (from); + bool from_bridge = (from_inst != NULL) && + (from_inst->district_id == BRIDGE_DISTRICT_ID) && + district_is_complete (from, from_inst->district_id); + bool to_bridge = (to_inst != NULL) && + to_inst_complete && + (to_inst->district_id == BRIDGE_DISTRICT_ID); + if (from_bridge || to_bridge) { + bool from_rail = from->vtable->m23_Check_Railroads (from, __, 0) != 0; + bool to_rail = to->vtable->m23_Check_Railroads (to, __, 0) != 0; + bool from_road = from->vtable->m25_Check_Roads (from, __, 0) != 0; + bool to_road = to->vtable->m25_Check_Roads (to, __, 0) != 0; + if (from_rail && to_rail) + base_cost = 0; + else if (from_road && to_road) + base_cost = 1; + } + } + } + + if ((unit != NULL) && + (base_cost >= 0) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Sea) && + to_valid && Tile_has_city (to)) + return -1; + } + + // Apply unit count per tile limit + if ((unit != NULL) && ! is_below_stack_limit (tile_at (to_x, to_y), unit->Body.CivID, unit->Body.UnitTypeID)) + return -1; + + // Apply trespassing restriction + if (is->current_config.disallow_trespassing && + check_trespassing (civ_id, tile_at (from_x, from_y), tile_at (to_x, to_y)) && + ((unit == NULL) || (! is_allowed_to_trespass (unit)))) + return -1; + + // Adjust movement cost to enforce limited railroad movement + if ((is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0)) { + if ((unit != NULL) && (base_cost == 0)) { // Railroad move + if (! is->current_config.limited_railroads_work_like_fast_roads) { // If Civ 4 style RR, scale cost by type's moves + int type_moves_available = patch_Unit_get_max_move_points (unit) / p_bic_data->General.RoadsMovementRate; + return type_moves_available * is->railroad_mp_cost_per_move; + } else + return is->railroad_mp_cost_per_move; + } else if (base_cost == 1) // Road move + return is->road_mp_cost; + } + + return base_cost; +} + +int __fastcall +patch_Trade_Net_set_unit_path (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) +{ + int tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); + + bool may_require_length_fix = (is->current_config.limit_railroad_movement > 0) && // if railroad movement is limited AND + (tr > 0) && (out_path_length_in_mp != NULL) && // path was found AND caller wants to know its length AND + (unit != NULL); // the path is for an actual unit + + // We might have to correct the path length returned by the base game's pathfinder. This occurs when railroad movement is limited and the + // unit's total MP exceeds what can be stored in a one-byte integer. The cause of the incorrect length is that the pathfinder internally + // stores the remaining moves at each node of the search in a single byte. This correction fixes the bug (reported several times) that ETAs + // shown in the interface are wrong. + if (may_require_length_fix && (patch_Unit_get_max_move_points (unit) > 255)) { // Need to recompute path length if unit's total MP can overflow a uint8 + + // First memoize the cost of taking each step along the path. This must be done separately because the pathfinder's internal data only + // lets us traverse the path backwards. + { + // Must pass cached "distance info" to Trade_Net::get_movement_cost. Trade_Net stores two sets of cached data, which one was + // used depends on the flags. I believe one is intended to be used for city trade connections and the other for unit movement. + Trade_Net_Distance_Info * dist_info = (flags & 1) ? this->Data2 : this->Data4; + + clear_memo (); + int x = to_x, y = to_y; + do { + // "flags & 1" again determines whether Data2 or Data4 was used. + enum direction dir = Trade_Net_get_direction_from_internal_map (this, __, x, y, flags & 1); + if (dir == DIR_ZERO) + break; + + int prev_x, prev_y; { + int dx, dy; + neighbor_index_to_diff (dir, &dx, &dy); + prev_x = x + dx; prev_y = y + dy; + wrap_tile_coords (&p_bic_data->Map, &prev_x, &prev_y); + } + + memoize (patch_Trade_Net_get_movement_cost (this, __, prev_x, prev_y, x, y, unit, civ_id, flags, reverse_dir (dir), dist_info)); + x = prev_x; y = prev_y; + } while (! ((x == from_x) && (y == from_y))); + } + + // Now walk the path forwards tracking how much MP the unit would spend. We must be aware that the unit can't spend more MP than it + // has. For example, if a unit with 1 move walks onto an unimproved mountain, that effectively costs only 1 move, not 3. + int mp_remaining = patch_Unit_get_max_move_points (unit) - unit->Body.Moves, + mp_spent = 0; + for (int n = is->memo_len - 1; n >= 0; n--) { + int cost = is->memo[n]; + if (cost < mp_remaining) { + mp_spent += cost; + mp_remaining -= cost; + } else { + mp_spent += mp_remaining; + mp_remaining = patch_Unit_get_max_move_points (unit); + } + } + *out_path_length_in_mp = mp_spent; + + // Also, if this is a move between adjacent tiles, make sure the path length doesn't exceed the unit's remaining MP. Otherwise, the game may + // erroneously show an ETA of >1 turn. + } else if (may_require_length_fix && are_tiles_adjacent (from_x, from_y, to_x, to_y)) + *out_path_length_in_mp = not_above (patch_Unit_get_max_move_points (unit) - unit->Body.Moves, *out_path_length_in_mp); + + return tr; +} + +int __fastcall +patch_Trade_Net_set_unit_path_to_find_sea_route (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) +{ + // Accelerate this call with TNX if possible + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { + bool route_exists = is->try_drawing_sea_trade_route (this, is->tnx_cache, from_x, from_y, to_x, to_y, civ_id, flags); + return route_exists ? 1 : 0; + } else + return Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); +} + +// Renames this leader and their civ based on their era. Era-specific names come from the config file. If this leader has a custom name set by the +// human player, this method does nothing. +void +apply_era_specific_names (Leader * leader) +{ + int leader_bit = 1 << leader->ID; + Race * race = &p_bic_data->Races[leader->RaceID]; + + struct replaceable_name { + char * base_name; + int * tracking_bits; + char * buf; + int buf_size; + } replaceable_names[] = { + {race->vtable->GetAdjectiveName (race), &is->aliased_civ_adjective_bits , leader->tribe_customization.civ_adjective , sizeof leader->tribe_customization.civ_adjective}, + {race->vtable->GetSingularName (race) , &is->aliased_civ_noun_bits , leader->tribe_customization.civ_noun , sizeof leader->tribe_customization.civ_noun}, + {race->vtable->GetCountryName (race) , &is->aliased_civ_formal_name_bits, leader->tribe_customization.civ_formal_name, sizeof leader->tribe_customization.civ_formal_name} + }; + + // Apply replacements to civ noun, adjective, and formal name + for (int n = 0; n < ARRAY_LEN (replaceable_names); n++) { + struct replaceable_name * repl = &replaceable_names[n]; + if ((*repl->tracking_bits & leader_bit) || (repl->buf[0] == '\0')) { + char * replacement = NULL; + if (leader->Era < ERA_ALIAS_LIST_CAPACITY) + // Search through the list of aliases in reverse order so that, if the same key was listed multiple times, the last + // appearance overrides the earlier ones. This is important b/c when configs are loaded, their aliases get appended to + // the list. + for (int k = is->current_config.count_civ_era_alias_lists - 1; k >= 0; k--) { + struct civ_era_alias_list * list = &is->current_config.civ_era_alias_lists[k]; + if (strcmp (list->key, repl->base_name) == 0) { + replacement = list->aliases[leader->Era]; + break; + } + } + if (replacement != NULL) { + strncpy (repl->buf, replacement, repl->buf_size); + repl->buf[repl->buf_size - 1] = '\0'; + *repl->tracking_bits |= leader_bit; + } else { + repl->buf[0] = '\0'; + *repl->tracking_bits &= ~leader_bit; + } + } + } + + // Apply replacement to leader name, gender, and title + if ((is->aliased_leader_name_bits & leader_bit) || (leader->tribe_customization.leader_name[0] == '\0')) { + char * base_name = race->vtable->GetLeaderName (race); + char * replacement_name = NULL; + char * replacement_title = NULL; + int replacement_gender; // Only used if replacement_name is + if (leader->Era < ERA_ALIAS_LIST_CAPACITY) + for (int k = is->current_config.count_leader_era_alias_lists - 1; k >= 0; k--) { + struct leader_era_alias_list * list = &is->current_config.leader_era_alias_lists[k]; + if (strcmp (list->key, base_name) == 0) { + replacement_name = list->aliases[leader->Era]; + replacement_title = list->titles[leader->Era]; + replacement_gender = (list->gender_bits >> leader->Era) & 1; + break; + } + } + if (replacement_name != NULL) { + TribeCustomization * tc = &leader->tribe_customization; + strncpy (tc->leader_name, replacement_name, sizeof tc->leader_name); + tc->leader_name[(sizeof tc->leader_name) - 1] = '\0'; + tc->leader_gender = replacement_gender; + is->aliased_leader_name_bits |= leader_bit; + + // If this replacement name has a special title and this player does not have a custom title set, replace the title. + if ((replacement_title != NULL) && ((is->aliased_leader_title_bits & leader_bit) || (tc->leader_title[0] == '\0'))) { + strncpy (tc->leader_title, replacement_title, sizeof tc->leader_title); + tc->leader_title[(sizeof tc->leader_title) - 1] = '\0'; + is->aliased_leader_title_bits |= leader_bit; + + // If the current name has no title and the player's title was previously replaced, undo the replacement. + } else if ((replacement_title == NULL) && (is->aliased_leader_title_bits & leader_bit)) { + leader->tribe_customization.leader_title[0] = '\0'; + is->aliased_leader_title_bits &= ~leader_bit; + } + } else { + leader->tribe_customization.leader_name[0] = '\0'; + // Don't need to clear custom leader gender since it's not used unless a custom name was set + is->aliased_leader_name_bits &= ~leader_bit; + + // Remove title replacement if present + if (is->aliased_leader_title_bits & leader_bit) { + leader->tribe_customization.leader_title[0] = '\0'; + is->aliased_leader_title_bits &= ~leader_bit; + } + } + } +} + +int __cdecl +patch_do_save_game (char const * file_path, char param_2, GUID * guid) +{ + // Do not save the modified road movement rate, if it was modified to limit railroad movement + int restore_rmr = (is->current_config.limit_railroad_movement > 0) && (is->saved_road_movement_rate > 0); + int rmr; + if (restore_rmr) { + rmr = p_bic_data->General.RoadsMovementRate; + p_bic_data->General.RoadsMovementRate = is->saved_road_movement_rate; + } + + // Do not save the modified barb culture group ID + int restore_barb_culture_group = is->current_config.enable_city_capture_by_barbarians && (is->saved_barb_culture_group >= 0); + int barb_culture; + if (restore_barb_culture_group) { + barb_culture = p_bic_data->Races[leaders[0].RaceID].CultureGroupID; + p_bic_data->Races[leaders[0].RaceID].CultureGroupID = is->saved_barb_culture_group; + } + + // Do not save names that were replaced with era-specific versions + for (int n = 0; n < 32; n++) { + Leader * leader = &leaders[n]; + int leader_bit = 1 << leader->ID; + if (is->aliased_civ_noun_bits & leader_bit) leader->tribe_customization.civ_noun [0] = '\0'; + if (is->aliased_civ_adjective_bits & leader_bit) leader->tribe_customization.civ_adjective [0] = '\0'; + if (is->aliased_civ_formal_name_bits & leader_bit) leader->tribe_customization.civ_formal_name[0] = '\0'; + if (is->aliased_leader_name_bits & leader_bit) leader->tribe_customization.leader_name [0] = '\0'; + if (is->aliased_leader_title_bits & leader_bit) leader->tribe_customization.leader_title [0] = '\0'; + } + is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; + + // Do not save unit types with the charm bits cleared if they were cleared by convertion to PTW targeting. The special actions field must not + // include the top category bits that are part of the UCV_* enum + for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { + UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; + converted_type->Special_Actions |= (0x00FFFFFF & UCV_Charm_Bombard); + } + + int tr = do_save_game (file_path, param_2, guid); + + if (restore_rmr) + p_bic_data->General.RoadsMovementRate = rmr; + if (restore_barb_culture_group) + p_bic_data->Races[leaders[0].RaceID].CultureGroupID = barb_culture; + + // Reapply era aliases + for (int n = 0; n < 32; n++) + if (*p_player_bits & (1 << n)) + apply_era_specific_names (&leaders[n]); + + // Reclear charm bits on converted types + for (int n = 0; n < is->count_charmed_types_converted_to_ptw_arty; n++) { + UnitType * converted_type = &p_bic_data->UnitTypes[is->charmed_types_converted_to_ptw_arty[n]]; + converted_type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); + } + + return tr; +} + +void +record_unit_type_alt_strategy (int type_id) +{ + int ai_strat_index; { + int ai_strat_bits = p_bic_data->UnitTypes[type_id].AI_Strategy; + if ((ai_strat_bits & ai_strat_bits - 1) != 0) // Sanity check: must only have one strat (one bit) set + return; + ai_strat_index = 0; + while ((ai_strat_bits & 1) == 0) { + ai_strat_index++; + ai_strat_bits >>= 1; + } + } + + itable_insert (&is->unit_type_alt_strategies, type_id, ai_strat_index); +} + +void +append_improv_id_to_list (struct improv_id_list * list, int id) +{ + reserve (sizeof list->items[0], (void **)&list->items, &list->capacity, list->count); + list->items[list->count] = id; + list->count += 1; +} + +unsigned __fastcall +patch_load_scenario (BIC * this, int edx, char * param_1, unsigned * param_2) +{ + int ret_addr = ((int *)¶m_1)[-1]; + + // Destroy TNX cache from previous map. A new one will be created when needed. + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { + is->destroy_tnx_cache (is->tnx_cache); + is->tnx_cache = NULL; + } + + unsigned tr = load_scenario (this, __, param_1, param_2); + char * scenario_path = param_1; + + // There are two cases when load_scenario is called that we don't want to run our own code. These are (1) when the scenario is loaded to + // generate a preview (map, etc.) for the "Civ Content" or "Conquests" menu and (2) when the function is called recursively. The recursive + // call is done, I believe, only when loading saves using the default rules. The game first tries to load custom rules then falls back on + // loading the default rules. In any case, we want to ignore that call so we don't run the same code twice. + if ((ret_addr == ADDR_LOAD_SCENARIO_PREVIEW_RETURN) || (ret_addr == ADDR_LOAD_SCENARIO_RESUME_SAVE_2_RETURN)) + return tr; + + reset_to_base_config (); + load_config ("default.c3x_config.ini", 1); + char * scenario_config_file_name = "scenario.c3x_config.ini"; + char * scenario_config_path = BIC_get_asset_path (p_bic_data, __, scenario_config_file_name, false); + + // BIC_get_asset_path returns the file name when it can't find the file + if (0 != strcmp (scenario_config_file_name, scenario_config_path)) { + load_config (scenario_config_path, 0); + } + load_config ("custom.c3x_config.ini", 1); + apply_machine_code_edits (&is->current_config, false); + + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + reset_district_state (true); + load_districts_config (); + } + + // Initialize Trade Net X + if (is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_UNINITED)) { + char path[MAX_PATH]; + snprintf (path, sizeof path, "%s\\Trade Net X\\TradeNetX.dll", is->mod_rel_dir); + path[(sizeof path) - 1] = '\0'; + is->trade_net_x = LoadLibraryA (path); + if (is->trade_net_x != NULL) { + is->set_exe_version = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_exe_version"); + is->create_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "create_tnx_cache"); + is->destroy_tnx_cache = (void *)(*p_GetProcAddress) (is->trade_net_x, "destroy_tnx_cache"); + is->set_up_before_building_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "set_up_before_building_network"); + is->get_move_cost_for_sea_trade = (void *)(*p_GetProcAddress) (is->trade_net_x, "get_move_cost_for_sea_trade"); + is->flood_fill_road_network = (void *)(*p_GetProcAddress) (is->trade_net_x, "flood_fill_road_network"); + is->try_drawing_sea_trade_route = (void *)(*p_GetProcAddress) (is->trade_net_x, "try_drawing_sea_trade_route"); + + is->set_exe_version (exe_version_index); + + // Run tests + if (0) { + int (__stdcall * test) () = (void *)(*p_GetProcAddress) (is->trade_net_x, "test"); + int failed_test_count = test (); + if (failed_test_count > 0) + MessageBoxA (NULL, "Failed some tests in Trade Net X!", NULL, MB_ICONWARNING); + else + MessageBoxA (NULL, "All tests in Trade Net X passed.", "Success", MB_ICONINFORMATION); + } + + is->tnx_init_state = IS_OK; + } else { + MessageBoxA (NULL, "Failed to load Trade Net X!", NULL, MB_ICONERROR); + is->tnx_init_state = IS_INIT_FAILED; + } + + // Deinitialize Trade Net X + } else if ((! is->current_config.enable_trade_net_x) && (is->tnx_init_state == IS_OK)) { + FreeLibrary (is->trade_net_x); + is->trade_net_x = NULL; + is->tnx_init_state = IS_UNINITED; + } + + // This scenario might use different mod art assets than the old one + deinit_stackable_command_buttons (); + deinit_district_command_buttons (); + deinit_disabled_command_buttons (); + deinit_trade_scroll_buttons (); + deinit_unit_rcm_icons (); + deinit_red_food_icon (); + deinit_large_minimap_frame (); + if (is->tile_already_worked_zoomed_out_sprite_init_state != IS_UNINITED) { + enum init_state * state = &is->tile_already_worked_zoomed_out_sprite_init_state; + if (*state == IS_OK) { + Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; + sprite->vtable->destruct (sprite, __, 0); + } + *state = IS_UNINITED; + } + + // Need to clear this since the resource count might have changed + if (is->extra_available_resources != NULL) { + free (is->extra_available_resources); + is->extra_available_resources = NULL; + is->extra_available_resources_capacity = 0; + } + + // Similarly, these don't carry over between games + for (int n = 0; n < 32; n++) + is->interceptor_reset_lists[n].count = 0; + is->replay_for_players = 0; + table_deinit (&is->extra_defensive_bombards); + table_deinit (&is->airdrops_this_turn); + table_deinit (&is->unit_transport_ties); + is->last_selected_unit.initial_x = is->last_selected_unit.initial_y = -1; + is->last_selected_unit.last_x = is->last_selected_unit.last_y = is->last_selected_unit.type_id = -1; + is->last_selected_unit.ptr = NULL; + table_deinit (&is->waiting_units); + is->have_loaded_waiting_units = false; + + // Clear extra city improvement bits + FOR_TABLE_ENTRIES (tei, &is->extra_city_improvs) + free ((void *)tei.value); + table_deinit (&is->extra_city_improvs); + + // Clear unit type counts + for (int n = 0; n < 32; n++) + table_deinit (&is->unit_type_counts[n]); + is->unit_type_count_init_bits = 0; + + // Clear last city founding turn numbers + for (int n = 0; n < 32; n++) + is->turn_no_of_last_founding_for_settler_perfume[n] = -1; + + // Load resources.pcx + { + PCX_Image * rs = is->resources_sheet; + if (rs != NULL) + rs->vtable->destruct (rs, __, 0); + else + rs = malloc (sizeof *rs); + memset (rs, 0, sizeof *rs); + PCX_Image_construct (rs); + + char * resources_pcx_path = BIC_get_asset_path (p_bic_data, __, "Art\\resources.pcx", true); + PCX_Image_read_file (rs, __, resources_pcx_path, NULL, 0, 0x100, 2); + is->resources_sheet = rs; + } + + // Recreate table of alt strategies mapping duplicates to their strategies + table_deinit (&is->unit_type_alt_strategies); + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; + if (alt_for_id >= 0) { + record_unit_type_alt_strategy (n); + record_unit_type_alt_strategy (alt_for_id); // Record the original too so we know it has alternatives + } + } + + // Recreate table of duplicates mapping unit types to the next duplicate + table_deinit (&is->unit_type_duplicates); + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + int alt_for_id = p_bic_data->UnitTypes[n].alternate_strategy_for_id; + if (alt_for_id >= 0) { + + // Find the type ID of the last duplicate in the list. alt_for_id refers to the original unit that was duplicated possibly + // multiple times. Begin searching there and, each time we find another duplicate, use its ID to continue the search. When + // we're done last_dup_id will be set to whichever ID in the list of duplicates is not already associated with another. + int last_dup_id = alt_for_id; { + int next; + while (itable_look_up (&is->unit_type_duplicates, last_dup_id, &next)) + last_dup_id = next; + } + + // Add this unit type to the end of the list of duplicates + itable_insert (&is->unit_type_duplicates, last_dup_id, n); + } + } + + // Convert charm-flagged units to using PTW targeting if necessary + if (is->current_config.charm_flag_triggers_ptw_like_targeting) { + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if (type->Special_Actions & UCV_Charm_Bombard) { + // Also add it to the list of converted types + reserve (sizeof is->charmed_types_converted_to_ptw_arty[0], // item size + (void **)&is->charmed_types_converted_to_ptw_arty, // ptr to items + &is->charmed_types_converted_to_ptw_arty_capacity, // ptr to capacity + is->count_charmed_types_converted_to_ptw_arty); // count + is->charmed_types_converted_to_ptw_arty[is->count_charmed_types_converted_to_ptw_arty] = n; + is->count_charmed_types_converted_to_ptw_arty += 1; + + // Add this type ID to the table + itable_insert (&is->current_config.ptw_arty_types, n, 1); + + // Clear the charm flag, taking care not to clear the category bit. This is necessary for the PTW targeting to work + // since the logic to implement it only applies to the non-charm code path. It wouldn't make sense to have both charm + // attack and PTW targeting anyway, since charm attack already works that way vs cities. + type->Special_Actions &= ~(0x00FFFFFF & UCV_Charm_Bombard); + } + } + } + + // Pick out which resources are used as mill inputs + if (is->mill_input_resource_bits) + free (is->mill_input_resource_bits); + is->mill_input_resource_bits = calloc (1, 1 + p_bic_data->ResourceTypeCount / 8); + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + for (int k = 0; k < 2; k++) { + int resource_id = (&p_bic_data->Improvements[mill->improv_id].Resource1ID)[k]; + if ((resource_id >= 0) && (resource_id < p_bic_data->ResourceTypeCount)) { + byte bit = 1 << (resource_id & 7); + is->mill_input_resource_bits[resource_id>>3] |= bit; + } + } + } + + // Recreate lists of water & air trade improvements + is->water_trade_improvs .count = 0; + is->air_trade_improvs .count = 0; + is->combat_defense_improvs.count = 0; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + enum ImprovementTypeFlags flags = p_bic_data->Improvements[n].ImprovementFlags; + if (flags & ITF_Allows_Water_Trade) append_improv_id_to_list (&is->water_trade_improvs , n); + if (flags & ITF_Allows_Air_Trade) append_improv_id_to_list (&is->air_trade_improvs , n); + if (p_bic_data->Improvements[n].Combat_Defence != 0) append_improv_id_to_list (&is->combat_defense_improvs, n); + } + + // Set up for limiting railroad movement + if (is->current_config.limit_railroad_movement > 0) { + // Bit 0x200 of field_484 indicates whether or not the last call to load_scenario loaded the General section of the BIQ. The game will + // skip loading of that section and many others when loading a game with the same standard scenario as the then-current one, common + // when loading an autosave. + bool loaded_general = (this->field_848 & 0x200) != 0; + + // For the base RMR, use the saved rate if it's valid and we haven't loaded a new rate as part of the General section. Otherwise, use + // the rate from that section. + int base_rmr = (loaded_general || is->saved_road_movement_rate <= 0) ? p_bic_data->General.RoadsMovementRate : is->saved_road_movement_rate; + + int g = gcd (base_rmr, is->current_config.limit_railroad_movement); // Scale down all MP costs by this common divisor to help against + // overflow of 8-bit integers inside the pathfinder. + is->saved_road_movement_rate = base_rmr; + p_bic_data->General.RoadsMovementRate = base_rmr * is->current_config.limit_railroad_movement / g; // Full move in MP + is->road_mp_cost = is->current_config.limit_railroad_movement / g; + is->railroad_mp_cost_per_move = base_rmr / g; + } else { + is->saved_road_movement_rate = -1; + is->road_mp_cost = 1; + is->railroad_mp_cost_per_move = 0; + } + + // If barb city capturing is enabled and the barbs have the non-existent "none" culture group (index -1), switch them to the first real + // culture group. The "none" group produces corrupt graphics and crashes. + int * barb_culture_group = &p_bic_data->Races[leaders[0].RaceID].CultureGroupID; + if (is->current_config.enable_city_capture_by_barbarians && (*barb_culture_group < 0)) { + is->saved_barb_culture_group = *barb_culture_group; + *barb_culture_group = 0; + } else + is->saved_barb_culture_group = -1; + + // Clear old alias bits + is->aliased_civ_noun_bits = is->aliased_civ_adjective_bits = is->aliased_civ_formal_name_bits = is->aliased_leader_name_bits = is->aliased_leader_title_bits = 0; + + // Apply no AI patrol override + if (is->current_config.override_no_ai_patrol == NAPO_ZERO) + *p_allow_ai_patrol = true; + else if (is->current_config.override_no_ai_patrol == NAPO_ONE) + *p_allow_ai_patrol = false; + else if (is->current_config.override_no_ai_patrol == NAPO_NONE) + *p_allow_ai_patrol = 0 == get_int_from_conquests_ini ("NoAIPatrol", 1, 0); + + // Clear day/night cycle vars and deindex sprite proxies, if necessary. + if (is->current_config.day_night_cycle_mode != DNCM_OFF) { + is->day_night_cycle_unstarted = true; + is->current_day_night_cycle = 12; + if (is->day_night_cycle_img_proxies_indexed) { + deindex_day_night_image_proxies (); + } + } + + return tr; +} + +void __fastcall +patch_Leader_recompute_auto_improvements (Leader * this) +{ + is->leader_param_for_patch_get_wonder_city_id = this; + Leader_recompute_auto_improvements (this); +} + +int __fastcall +patch_Game_get_wonder_city_id (Game * this, int edx, int wonder_improvement_id) +{ + int ret_addr = ((int *)&wonder_improvement_id)[-1]; + if ((is->current_config.enable_free_buildings_from_small_wonders) && (ret_addr == ADDR_SMALL_WONDER_FREE_IMPROVS_RETURN)) { + Leader * leader = is->leader_param_for_patch_get_wonder_city_id; + Improvement * improv = &p_bic_data->Improvements[wonder_improvement_id]; + if ((improv->Characteristics & ITC_Small_Wonder) != 0) { + // Need to check if Small_Wonders array is NULL b/c recompute_auto_improvements gets called with leaders that are absent/dead. + return (leader->Small_Wonders != NULL) ? leader->Small_Wonders[wonder_improvement_id] : -1; + } + } + return Game_get_wonder_city_id (this, __, wonder_improvement_id); +} + +int __fastcall +patch_Main_Screen_Form_handle_key_up (Main_Screen_Form * this, int edx, int virtual_key_code) +{ + if ((virtual_key_code & 0xFF) == VK_CONTROL) { + patch_Main_GUI_set_up_unit_command_buttons (&this->GUI); + + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + } + + return Main_Screen_Form_handle_key_up (this, __, virtual_key_code); +} + +char __fastcall +patch_Leader_can_do_worker_job (Leader * this, int edx, enum Worker_Jobs job, int tile_x, int tile_y, int ask_if_replacing) +{ + char tr; + bool is_ai = ((*p_human_player_bits & (1 << this->ID)) == 0); + bool skip_replacement_logic = + (p_main_screen_form->Player_CivID == this->ID) && is->current_config.skip_repeated_tile_improv_replacement_asks; + + Tile * tile = tile_at (tile_x, tile_y); + + // If districts on, short-circuit any potential AI workers accidentally building in another civ's territory. + if (is->current_config.enable_districts && is_ai && (tile != NULL) && (tile != p_null_tile)) { + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (territory_owner > 0 && territory_owner != this->ID) + return 0; + } + + // Check if AI is trying to change a district tile (before calling vanilla logic) + if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && + is_ai) { + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { + int district_id = inst->district_id; + bool allow_ai_change = false; + + // Allow AI to modify obsolete districts + if (district_is_obsolete_for_civ (district_id, this->ID)) + allow_ai_change = true; + + // Allow if district could be used as a prerequisite for other buildable districts + if (! allow_ai_change) { + for (int other_id = 0; other_id < is->district_count; other_id++) { + if (other_id == district_id) + continue; + struct district_config const * other_cfg = &is->district_configs[other_id]; + if (! other_cfg->has_buildable_on_districts) + continue; + for (int i = 0; i < other_cfg->buildable_on_district_id_count; i++) { + if (other_cfg->buildable_on_district_ids[i] == district_id) { + if (leader_can_build_district (this, other_id)) + allow_ai_change = true; + break; + } + } + if (allow_ai_change) + break; + } + } + + // Allow AI to build roads/rails on bridge districts + if (! allow_ai_change && (district_id == BRIDGE_DISTRICT_ID) && + (job == WJ_Build_Road || job == WJ_Build_Railroad)) + allow_ai_change = true; + + // For Wonder Districts: check if unused (can be replaced) + if (! allow_ai_change && is->current_config.enable_wonder_districts && (district_id == WONDER_DISTRICT_ID)) { + struct wonder_district_info * info = get_wonder_district_info (tile); + + // If there's a reservation (wonder being built) or completed wonder, block replacement + if (info != NULL && info->state != WDS_UNUSED) + return 0; + + // Wonder district is unused - fall through to normal tech checks + } + else if (! allow_ai_change && is->current_config.enable_natural_wonders && (district_id == NATURAL_WONDER_DISTRICT_ID)) { + return 0; + } + else if (! allow_ai_change) { + // For all other district types: AI should not change them + return 0; + } + } + } + } + + if (! skip_replacement_logic) + tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); + else if (is->have_job_and_loc_to_skip && + (is->to_skip.job == job) && (is->to_skip.tile_x == tile_x) && (is->to_skip.tile_y == tile_y)) + tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, 0); + else { + is->show_popup_was_called = 0; + tr = Leader_can_do_worker_job (this, __, job, tile_x, tile_y, ask_if_replacing); + if (is->show_popup_was_called && tr) { // Check that the popup was shown and the player chose to replace + is->to_skip = (struct worker_job_and_location) { .job = job, .tile_x = tile_x, .tile_y = tile_y }; + is->have_job_and_loc_to_skip = 1; + } + } + + if (! tr && is->current_config.enable_districts && (job == WJ_Build_Mines)) { + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && + inst->district_id >= 0 && inst->district_id < is->district_count && + ! tile->vtable->m35_Check_Is_Water (tile) && + (tile->CityID < 0) && + ! tile->vtable->m18_Check_Mines (tile, __, 0)) { + int tile_x = 0, tile_y = 0; + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + int owner_civ = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_civ == this->ID) || (owner_civ == 0)) { + if (leader_can_build_district (this, inst->district_id) && + district_resource_prereqs_met (tile, tile_x, tile_y, inst->district_id)) + tr = 1; + } + } + } + } + + if (! tr && is->current_config.enable_districts && is->current_config.enable_bridge_districts && + (job == WJ_Build_Road || job == WJ_Build_Railroad)) { + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { + bool has_road = tile->vtable->m25_Check_Roads (tile, __, 0) != 0; + if (job == WJ_Build_Road) { + if (! has_road) + tr = 1; + } else { + bool has_rail = tile->vtable->m23_Check_Railroads (tile, __, 0) != 0; + if (has_road && ! has_rail) { + int req_tech = p_bic_data->WorkerJobs[job].RequireID; + if ((req_tech < 0) || + ((req_tech != p_bic_data->AdvanceCount) && + Leader_has_tech (&leaders[this->ID], __, req_tech))) { + if (Leader_has_resources_for_job_at (&leaders[this->ID], __, job, tile_x, tile_y)) + tr = 1; + } + } + } + } + } + } + + return tr; +} + +bool __fastcall +patch_Unit_can_hurry_production (Unit * this, int edx, City * city, bool exclude_cheap_improvements) +{ + if (is->current_config.allow_military_leaders_to_hurry_wonders && Unit_has_ability (this, __, UTA_Leader)) { + LeaderKind actual_kind = this->Body.leader_kind; + this->Body.leader_kind = LK_Scientific; + bool tr = Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); + this->Body.leader_kind = actual_kind; + return tr; + } else + return Unit_can_hurry_production (this, __, city, exclude_cheap_improvements); +} + +bool __fastcall +patch_Unit_can_load (Unit * this, int edx, Unit * passenger) +{ + is->can_load_transport = this; + is->can_load_passenger = passenger; + bool tr; + + // If this potential passenger is tied to a different transport, do not allow it to load into this one + int tied_transport_id = -1; + if (is->current_config.limit_unit_loading_to_one_transport_per_turn && + (! Unit_has_ability (this, __, UTA_Army)) && + itable_look_up (&is->unit_transport_ties, passenger->Body.ID, &tied_transport_id) && + (this->Body.ID != tied_transport_id)) + tr = false; + + else + tr = Unit_can_load (this, __, passenger); + + is->can_load_transport = is->can_load_passenger = NULL; + return tr; +} + +void __fastcall +patch_Unit_load (Unit * this, int edx, Unit * transport) +{ + Unit_load (this, __, transport); + + // Tie the unit to the transport if configured to do so + if (is->current_config.limit_unit_loading_to_one_transport_per_turn && ! Unit_has_ability (transport, __, UTA_Army)) + itable_insert (&is->unit_transport_ties, this->Body.ID, transport->Body.ID); +} + +bool +any_enemies_near (Leader const * me, int tile_x, int tile_y, enum UnitTypeClasses class, int num_tiles) +{ + bool tr = false; + FOR_TILES_AROUND (tai, num_tiles, tile_x, tile_y) { + int enemy_on_this_tile = 0; + FOR_UNITS_ON (uti, tai.tile) { + UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; + if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0) && + (((int)class < 0) || (unit_type->Unit_Class == class))) { + if (me->At_War[uti.unit->Body.CivID]) { + if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { + enemy_on_this_tile = 1; + break; + } + } else + break; + } + } + if (enemy_on_this_tile) { + tr = true; + break; + } + } + return tr; +} + +bool +any_enemies_near_unit (Unit * unit, int num_tiles) +{ + UnitType * unit_type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + return any_enemies_near (&leaders[unit->Body.CivID], unit->Body.X, unit->Body.Y, unit_type->Unit_Class, num_tiles); +} + +void __fastcall +patch_Unit_ai_move_artillery (Unit * this) +{ + if ((! is->current_config.use_offensive_artillery_ai) || + ((this->Body.UnitTypeID < 0) || (this->Body.UnitTypeID >= p_bic_data->UnitTypeCount))) // Check for invalid unit type id which appears sometimes, IDK why + goto base_impl; + + Tile * on_tile = tile_at (this->Body.X, this->Body.Y); + City * in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); + UnitType const * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + int num_escorters_req = this->vtable->eval_escort_requirement (this); + + if ((in_city == NULL) || (count_escorters (this) >= num_escorters_req)) + goto base_impl; + + // Don't assign escort if there are any enemies around because in that case it might be a serious mistake to take a defender out of the city + if (any_enemies_near_unit (this, 37)) + goto base_impl; + + // Find the strongest healthy defender the city has and assign that unit as an escort but make sure doing so doesn't leave the city + // defenseless. I think picking the strongest defender is the right choice here because the artillery pair is more likely to come under + // attack than a city and also leaving obsolete units in the city gives them a chance to upgrade. + int num_defenders = 0; + Unit * best_defender = NULL; + int best_defender_strength = -1; + FOR_UNITS_ON (uti, on_tile) { + Unit_Body * body = &uti.unit->Body; + UnitType * type = &p_bic_data->UnitTypes[body->UnitTypeID]; + if ((type->AI_Strategy & UTAI_Defence) && + (! UnitType_has_ability (type, __, UTA_Immobile)) && + (body->Damage == 0) && + ((body->UnitState == 0) || (body->UnitState == UnitState_Fortifying)) && + (body->escortee < 0)) { + num_defenders++; + int str = type->Defence * Unit_get_max_hp (uti.unit); + if (str > best_defender_strength) { + best_defender = uti.unit; + best_defender_strength = str; + } + } + } + if ((num_defenders >= 2) && (best_defender != NULL)) { + Unit_set_state (best_defender, __, 0); + Unit_set_escortee (best_defender, __, this->Body.ID); + } + +base_impl: + Unit_ai_move_artillery (this); + + // Recompute these since the unit might have moved + on_tile = tile_at (this->Body.X, this->Body.Y); + in_city = get_city_ptr (on_tile->vtable->m45_Get_City_ID (on_tile)); + + // Load the unit into a transport for a naval invasion if it's just sitting in a city with nothing else to do + if (is->current_config.use_offensive_artillery_ai && + (in_city != NULL) && + (this->Body.Moves == 0) && + (this->Body.UnitState == UnitState_Fortifying) && + (this->Body.Container_Unit < 0)) { + Unit * transport = Unit_find_transport (this, __, this->Body.X, this->Body.Y); + if (transport != NULL) { + + int transport_capacity = p_bic_data->UnitTypes[transport->Body.UnitTypeID].Transport_Capacity; + int units_in_transport, arty_in_transport; { + units_in_transport = arty_in_transport = 0; + FOR_UNITS_ON (uti, on_tile) + if (uti.unit->Body.Container_Unit == transport->Body.ID) { + units_in_transport++; + arty_in_transport += (p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].AI_Strategy & UTAI_Artillery) != 0; + } + } + + // Check that there's space for the arty unit and an escort, and that the transport does not have more than one arty per three + // spaces so we're less likely to assemble invasion forces composed of nothing but artillery. + if ((units_in_transport + 2 <= transport_capacity) && + (arty_in_transport < not_below (1, transport_capacity / 3))) { + Unit_set_escortee (this, __, -1); + patch_Unit_load (this, __, transport); + } + } + } +} + +// Estimates the number of turns necessary to move the given unit to the given tile and writes it to *out_num_turns. Returns 0 if there is no path +// from the unit's current position to the given tile, 1 otherwise. +int +estimate_travel_time (Unit * unit, int to_tile_x, int to_tile_y, int * out_num_turns) +{ + int dist_in_mp; + patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, to_tile_x, to_tile_y, unit, unit->Body.CivID, 1, &dist_in_mp); + dist_in_mp += unit->Body.Moves; // Add MP already spent this turn to the distance + int max_mp = patch_Unit_get_max_move_points (unit); + if ((dist_in_mp >= 0) && (max_mp > 0)) { + *out_num_turns = dist_in_mp / max_mp; + return 1; + } else + return 0; // No path or unit cannot move +} + +City * +find_nearest_established_city (Unit * unit, int continent_id) +{ + int lowest_unattractiveness = INT_MAX; + City * least_unattractive_city = NULL; + FOR_CITIES_OF (coi,unit->Body.CivID) { + Tile * city_tile = tile_at (coi.city->Body.X, coi.city->Body.Y); + if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { + int dist_in_turns; + if (! estimate_travel_time (unit, coi.city->Body.X, coi.city->Body.Y, &dist_in_turns)) + continue; + int unattractiveness = 10 * dist_in_turns; + unattractiveness = (10 + unattractiveness) / (10 + coi.city->Body.Population.Size); + if (coi.city->Body.CultureIncome > 0) + unattractiveness /= 5; + if (unattractiveness < lowest_unattractiveness) { + lowest_unattractiveness = unattractiveness; + least_unattractive_city = coi.city; + } + } + } + return least_unattractive_city; +} + +bool __fastcall +patch_Unit_ai_can_form_army (Unit * this) +{ + int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.patch_ai_can_form_army_without_special_ability && ((type->Special_Actions & build_army_action) == 0)) + return false; + else + return Unit_ai_can_form_army (this); +} + +void __fastcall +patch_Unit_ai_move_leader (Unit * this) +{ + if (! is->current_config.replace_leader_unit_ai) { + Unit_ai_move_leader (this); + return; + } + + Tile * tile = tile_at (this->Body.X, this->Body.Y); + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + + // Disband the unit if it's on a continent with no cities of its civ. This is what the original logic does. + if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { + Unit_disband (this); + return; + } + + // Flee if the unit is near an enemy without adequate escort + int has_adequate_escort; { + int escorter_count = 0; + int any_healthy_escorters = 0; + int index; + for (int escorter_id = Unit_next_escorter_id (this, __, &index, true); escorter_id >= 0; escorter_id = Unit_next_escorter_id (this, __, &index, false)) { + Unit * escorter = get_unit_ptr (escorter_id); + if ((escorter != NULL) && (escorter->Body.X == this->Body.X) && (escorter->Body.Y == this->Body.Y)) { + escorter_count++; + int remaining_health = Unit_get_max_hp (escorter) - escorter->Body.Damage; + any_healthy_escorters |= (remaining_health >= 3) || (escorter->Body.Damage == 0); + } + } + has_adequate_escort = (escorter_count > 0) && any_healthy_escorters; + } + if ((! has_adequate_escort) && any_enemies_near_unit (this, 49)) { + Unit_set_state (this, __, UnitState_Fleeing); + bool done = this->vtable->work (this); + if (done || (this->Body.UnitState != 0)) + return; + } + + // Move along path if the unit already has one set + byte next_move = Unit_pop_next_move_from_path (this); + if (next_move > 0) { + this->vtable->Move (this, __, next_move, 0); + return; + } + + // Start a science age if we can + // It would be nice to compute a value for this and compare it to the option of rushing production but it's hard to come up with a valuation + if (is->current_config.patch_science_age_bug && Unit_ai_can_start_science_age (this)) { + Unit_start_science_age (this); + return; + } + + // Estimate the value of creating an army. First test if that's even a possiblity and if not leave the value at -1 so rushing production is + // always preferable (note we can't use Unit_ai_can_form_army for this b/c it returns false for units not in a city). The value of forming + // an army is "infinite" if we don't already have one and otherwise it depends on the army unit's shield cost +/- 25% for each point of + // aggression divided by the number of armies already in the field. + int num_armies = leaders[this->Body.CivID].Armies_Count; + int form_army_value = -1; + int build_army_action = UCV_Build_Army & 0x0FFFFFFF; // Mask out top four category bits + if ((this->Body.leader_kind & LK_Military) && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & build_army_action) && + ((num_armies + 1) * p_bic_data->General.ArmySupportCities <= leaders[this->Body.CivID].Cities_Count) && + (p_bic_data->General.BuildArmyUnitID >= 0) && + (p_bic_data->General.BuildArmyUnitID < p_bic_data->UnitTypeCount)) { + if (num_armies < 1) + form_army_value = INT_MAX; + else { + form_army_value = p_bic_data->UnitTypes[p_bic_data->General.BuildArmyUnitID].Cost; + int aggression_level = p_bic_data->Races[leaders[this->Body.CivID].RaceID].AggressionLevel; // aggression level varies between -2 and +2 + form_army_value = (form_army_value * (4 + aggression_level)) / 4; + if (num_armies > 1) + form_army_value /= num_armies; + } + } + + // Estimate the value of rushing production in every city on this continent and remember the highest one + City * best_rush_loc = NULL; + int best_rush_value = -1; + FOR_CITIES_OF (coi, this->Body.CivID) { + City * city = coi.city; + Tile * city_tile = tile_at (city->Body.X, city->Body.Y); + if ((continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) && + patch_Unit_can_hurry_production (this, __, city, false)) { + // Base value is equal to the number of shields rushing would save + int value = City_get_order_cost (city) - City_get_order_progress (city) - city->Body.ProductionIncome; + if (value <= 0) + continue; + + // Consider distance: Reduce the value by the number of shields produced while the leader is en route to rush. + int dist_in_turns; + if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) + continue; // no path or unit cannot move + value -= dist_in_turns * city->Body.ProductionIncome; + if (value <= 0) + continue; + + // Consider corruption: Scale down the value of rushing an improvement by the corruption rate of the city. + // This is to reflect the fact that infrastructure is more valuable in less corrupt cities. But do not apply + // this to wonders since their benefit is in most cases not lessened by local corruption. + Improvement * improv = (city->Body.Order_Type == COT_Improvement) ? &p_bic_data->Improvements[city->Body.Order_ID] : NULL; + int is_wonder = (improv != NULL) && (0 != (improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder))); + if ((improv != NULL) && (! is_wonder)) { + int good_shields = city->Body.ProductionIncome; + int corrupt_shields = city->Body.ProductionLoss; + if (good_shields + corrupt_shields > 0) + value = (value * good_shields) / (good_shields + corrupt_shields); + else + continue; + } + + if ((value > 0) && (value > best_rush_value)) { + best_rush_loc = city; + best_rush_value = value; + } + } + } + + // Hurry production or form an army depending on the estimated values of doing so. We might have to move to a (different) city if that's where + // we want to rush production or if we want to form an army but aren't already in a city. + City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); + City * moving_to_city = NULL; + if ((best_rush_loc != NULL) && (best_rush_value > form_army_value)) { + if (best_rush_loc == in_city) { + Unit_hurry_production (this); + return; + } else + moving_to_city = best_rush_loc; + } else if ((form_army_value > -1) && patch_Unit_ai_can_form_army (this)) { + Unit_form_army (this); + return; + } else if (in_city == NULL) { + // Nothing to do. Try to find a close, established city to move to & wait in. + moving_to_city = find_nearest_established_city (this, continent_id); + } + if (moving_to_city) { + int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); + if (first_move > 0) { + Unit_set_escortee (this, __, -1); + this->vtable->Move (this, __, first_move, 0); + return; + } + } + + // Nothing to do, nowhere to go, just fortify in place. + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +int +measure_strength_in_army (UnitType * type) +{ + return ((type->Attack + type->Defence) * (4 + type->Hit_Point_Bonus)) / 4; +} + +bool __fastcall +patch_impl_ai_is_good_army_addition (Unit * this, int edx, Unit * candidate) +{ + if (! is->current_config.fix_ai_army_composition) + return impl_ai_is_good_army_addition (this, __, candidate); + + UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + if (((candidate_type->AI_Strategy & UTAI_Offence) == 0) || + UnitType_has_ability (candidate_type, __, UTA_Hidden_Nationality)) + return false; + + int num_units_in_army = 0, + army_min_speed = INT_MAX, + army_min_strength = INT_MAX; + FOR_UNITS_ON (uti, tile) { + if (uti.unit->Body.Container_Unit == this->Body.ID) { + num_units_in_army++; + int movement = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Movement; + if (movement < army_min_speed) + army_min_speed = movement; + int member_strength = measure_strength_in_army (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]); + if (member_strength < army_min_strength) + army_min_strength = member_strength; + } + } + + return (num_units_in_army == 0) || + ((candidate_type->Movement >= army_min_speed) && + (measure_strength_in_army (candidate_type) >= army_min_strength)); +} + +int +rate_artillery (UnitType * type) +{ + int tr = type->Attack + type->Defence + 2 * type->Bombard_Strength * type->FireRate; + + // include movement + int moves = type->Movement; + if (moves >= 2) + tr = tr * (moves + 1) / 2; + + // include range + int range = type->Bombard_Range; + if (range >= 2) + tr = tr * (range + 1) / 2; + + // include extra hp + if (type->Hit_Point_Bonus > 0) + tr = tr * (4 + type->Hit_Point_Bonus) / 4; + + return tr; +} + +int +rate_bomber (UnitType * type) +{ + int tr = type->Bombard_Strength * type->FireRate + type->Defence; + + // include range + tr = tr * (10 + type->OperationalRange) / 10; + + // include cost + tr = (tr * 100) / (100 + type->Cost); + + // include abilities + if (UnitType_has_ability (type, __, UTA_Blitz)) + tr = tr * (type->Movement + 1) / 2; + if (UnitType_has_ability (type, __, UTA_Lethal_Land_Bombardment)) + tr = tr * 3 / 2; + if (UnitType_has_ability (type, __, UTA_Lethal_Sea_Bombardment)) + tr = tr * 5 / 4; + if (UnitType_has_ability (type, __, UTA_Stealth)) + tr = tr * 3 / 2; + + // include extra hp + if (type->Hit_Point_Bonus > 0) + tr = tr * (4 + type->Hit_Point_Bonus) / 4; + + return tr; +} + +bool __fastcall +patch_City_can_build_unit (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) +{ + bool base = City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); + + if (base) { + // Apply building prereqs + int building_prereq; + if (itable_look_up (&is->current_config.building_unit_prereqs, unit_type_id, &building_prereq)) { + // If the prereq is an encoded building ID + if (building_prereq & 1) { + if (! has_active_building (this, building_prereq >> 1)) + return false; + + // Else it's a pointer to a list of building IDs + } else { + int * list = (int *)building_prereq; + for (int n = 0; n < MAX_BUILDING_PREREQS_FOR_UNIT; n++) + if ((list[n] >= 0) && ! has_active_building (this, list[n])) + return false; + } + } + + // Apply unit type limit + int available; + if (get_available_unit_count (&leaders[this->Body.CivID], unit_type_id, &available) && (available <= 0)) + return false; + } + + if (is->current_config.enable_districts) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + + // Bail if tech reqs are not met + int prereq_id = type->AdvReq; + if (prereq_id >= 0 && ! Leader_has_tech (&leaders[this->Body.CivID], __, prereq_id)) + return false; + + if (! Leader_can_build_unit (&leaders[this->Body.CivID], __, unit_type_id, 1, false)) + return false; + + // Superficially allow the AI to choose the unit for scoring and production. + // If a disallowed air/naval unit is chosen in ai_choose_production, we'll swap it out for a feasible fallback later + // after prioritizing the aerodrome/port to be built + if (! is_human && ( + (type->Unit_Class == UTC_Air || city_can_build_district (this, AERODROME_DISTRICT_ID)) || + (type->Unit_Class == UTC_Sea || city_can_build_district (this, PORT_DISTRICT_ID))) + ) + return base; + + // Air units + if (type->Unit_Class == UTC_Air) { + if (is->current_config.enable_aerodrome_districts && is->current_config.air_units_use_aerodrome_districts_not_cities) { + if (find_pending_district_request (this, AERODROME_DISTRICT_ID) != NULL) + return false; + if (! city_can_build_district (this, AERODROME_DISTRICT_ID)) + return false; + return city_has_required_district (this, AERODROME_DISTRICT_ID); + } + // Naval units + } else if (type->Unit_Class == UTC_Sea) { + if (is->current_config.enable_port_districts && is->current_config.naval_units_use_port_districts_not_cities) { + if (find_pending_district_request (this, PORT_DISTRICT_ID) != NULL) + return false; + if (! city_can_build_district (this, PORT_DISTRICT_ID)) + return false; + return city_has_required_district (this, PORT_DISTRICT_ID); + } + } + } + + return base; +} + +int __fastcall +patch_City_get_largest_adjacent_sea_within_work_area (City * this) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + int improv_id = is->current_evaluating_improve_id; + if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { + + // If Coastal Fortress, default to original logic (city must be next to coast) + if (p_bic_data->Improvements[improv_id].Naval_Bombard_Defence > 0) + return City_get_largest_adjacent_sea (this); + } + int lake_size_threshold = 21; + int largest_size = 0; + int largest_continent_id = -1; + FOR_WORK_AREA_AROUND (wai, this->Body.X, this->Body.Y) { + if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { + int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + if (continent->Body.TileCount <= lake_size_threshold && ! is->current_config.enable_canal_districts) + continue; + if (p_bic_data->Map.Continents[continent_id].Body.TileCount > largest_size) { + largest_size = p_bic_data->Map.Continents[continent_id].Body.TileCount; + largest_continent_id = continent_id; + } + } + } + return largest_continent_id; + } + return City_get_largest_adjacent_sea (this); +} + +bool __fastcall +patch_Map_impl_is_near_river_within_work_area (Map * this, int edx, int x, int y, int num_tiles) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + FOR_WORK_AREA_AROUND (wai, x, y) { + if (wai.tile->vtable->m37_Get_River_Code (wai.tile) != 0) { + return true; + } + } + return false; + } + + return this->vtable->is_near_river (this, __, x, y, num_tiles); +} + +bool __fastcall +patch_Map_impl_is_near_lake_within_work_area (Map * this, int edx, int x, int y, int num_tiles) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + int lake_size_threshold = 21; + FOR_WORK_AREA_AROUND (wai, x, y) { + if (wai.tile->vtable->m35_Check_Is_Water (wai.tile)) { + int continent_id = wai.tile->vtable->m46_Get_ContinentID (wai.tile); + if ((continent_id < 0) || (continent_id >= p_bic_data->Map.Continent_Count)) + continue; + Continent * continent = &p_bic_data->Map.Continents[continent_id]; + if (continent->Body.TileCount <= lake_size_threshold) + return true; + } + } + return false; + } + + return this->vtable->is_near_lake (this, __, x, y, num_tiles); +} + +bool __fastcall +patch_Map_impl_has_fresh_water_within_work_area (Map * this, int edx, int tile_x, int tile_y) +{ + if (is->current_config.enable_districts && is->current_config.expand_water_tile_checks_to_city_work_area) { + int improv_id = is->current_evaluating_improve_id; + if ((improv_id >= 0) && (improv_id < p_bic_data->ImprovementsCount)) { + + // If an Aqueduct, default to original logic (city must be next to coast) + if ((p_bic_data->Improvements[improv_id].ImprovementFlags & ITF_Allows_City_Level_2) != 0) + return this->vtable->has_fresh_water (this, __, tile_x, tile_y); + } + if (patch_Map_impl_is_near_river_within_work_area (this, __, tile_x, tile_y, 1)) + return true; + if (patch_Map_impl_is_near_lake_within_work_area (this, __, tile_x, tile_y, 1)) + return true; + return false; + } + + return this->vtable->has_fresh_water (this, __, tile_x, tile_y); +} + +bool +city_meets_district_prereqs_to_build_improvement (City * city, int i_improv, bool apply_strict_rules) +{ + // Different logic for human vs AI players + bool is_human = (*p_human_player_bits & (1 << city->Body.CivID)) != 0; + + Improvement * improv = &p_bic_data->Improvements[i_improv]; + bool is_wonder = is->current_config.enable_wonder_districts && (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)); + if (is_wonder && ! wonder_is_buildable_by_civ (i_improv, city->Body.CivID)) + return false; + + bool requires_river = (improv->ImprovementFlags & ITF_Must_Be_Near_River) != 0; + + // Check if the improvement requires a district + bool needs_district = city_requires_district_for_improvement (city, i_improv, NULL); + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); + + // District is either not needed or already built + if (! needs_district) + return true; + + if (prereq_list == NULL) + return false; + + bool has_buildable_candidate = false; + bool has_wonder_candidate = false; + bool has_non_wonder_candidate = false; + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) + continue; + has_buildable_candidate = true; + if (district_id == WONDER_DISTRICT_ID) + has_wonder_candidate = true; + else + has_non_wonder_candidate = true; + } + if (! has_buildable_candidate) + return false; + + // Check that we have the necessary terrain + bool has_terrain_for_district = false; + bool has_terrain_for_wonder = false; + bool has_river_terrain_for_district = false; + FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { + Tile * tile = wai.tile; + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + if (! leader_can_build_district (&leaders[city->Body.CivID], district_id)) + continue; + if (! tile_suitable_for_district (tile, district_id, city, NULL)) + continue; + + if (is_wonder && district_id == WONDER_DISTRICT_ID) { + if (! wonder_is_buildable_on_tile (tile, i_improv)) + continue; + } + + has_terrain_for_district = true; + if (requires_river && tile->vtable->m37_Get_River_Code (tile) != 0) + has_river_terrain_for_district = true; + + if (is_wonder && district_id == WONDER_DISTRICT_ID) { + if (! requires_river || tile->vtable->m37_Get_River_Code (tile) != 0) { + has_terrain_for_wonder = true; + } + } + } + } + + bool requires_wonder_terrain = is_wonder && has_wonder_candidate && ! has_non_wonder_candidate; + if (! has_terrain_for_district || + (requires_river && ! has_river_terrain_for_district) || + (requires_wonder_terrain && ! has_terrain_for_wonder)) { + return false; + } + + // If human has everything needed except a built district (which is buildable), allow relaxed checks so UI can gray entry out + if (is_human) { + return ! apply_strict_rules; + } + + // If AI already has a pending district request for this required district, return false + // to prevent wasting a turn trying to choose this improvement + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + if (find_pending_district_request (city, district_id) != NULL) + return false; + } + + // Superficially allow the AI to choose the improvement for scoring and production. + // If a disallowed improvement is chosen in ai_choose_production, we'll swap it out for a feasible fallback later + // after prioritizing the district to be built + return true; +} + +bool __fastcall +patch_City_can_build_improvement (City * this, int edx, int i_improv, bool apply_strict_rules) +{ + is->current_evaluating_improve_id = i_improv; + + char ss[200]; + snprintf (ss, sizeof ss, "patch_City_can_build_improvement:evaluating improvement %s (%d)\n", + p_bic_data->Improvements[i_improv].Name.S, i_improv); + (*p_OutputDebugStringA) (ss); + + // First defer to the base game's logic + bool base = City_can_build_improvement (this, __, i_improv, apply_strict_rules); + if (! base) return false; + if (! is->current_config.enable_districts) return base; + + bool can_build = city_meets_district_prereqs_to_build_improvement (this, i_improv, apply_strict_rules); + is->current_evaluating_improve_id = -1; + + return can_build; +} + +bool +ai_handle_district_production_requirements (City * city, City_Order * out) +{ + clear_best_feasible_order (city); + bool swapped_to_fallback = false; + City_Order fallback_order = {0}; + int required_district_id = -1; + bool should_mark_district = false; + + char ss[200]; + + if (is->current_config.enable_districts && + (out->OrderID >= 0)) { + bool needs_wonder_district = false; + bool requires_district = false; + bool needs_district = false; + + if ((out->OrderType == COT_Unit) && + (out->OrderID < p_bic_data->UnitTypeCount)) { + UnitType * type = &p_bic_data->UnitTypes[out->OrderID]; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { + required_district_id = AERODROME_DISTRICT_ID; + needs_district = true; + should_mark_district = true; + } else if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (city, PORT_DISTRICT_ID))) { + required_district_id = PORT_DISTRICT_ID; + needs_district = true; + should_mark_district = true; + } + } else if ((out->OrderType == COT_Improvement) && + (out->OrderID < p_bic_data->ImprovementsCount)) { + // Check if AI is trying to build a wonder without an incomplete wonder district + requires_district = city_requires_district_for_improvement (city, out->OrderID, &required_district_id); + if (is->current_config.enable_wonder_districts) { + Improvement * improv = &p_bic_data->Improvements[out->OrderID]; + if ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && + (! city_has_wonder_district_with_no_completed_wonder (city, out->OrderID))) { + snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: City %d (%s) needs wonder district to build wonder improvement %d\n", + city->Body.ID, city->Body.CityName, out->OrderID); + (*p_OutputDebugStringA) (ss); + needs_wonder_district = true; + if (required_district_id < 0) { + required_district_id = WONDER_DISTRICT_ID; + } + } + } + needs_district = needs_wonder_district || requires_district; + } + + if (needs_district) { + struct ai_best_feasible_order * stored = get_best_feasible_order (city); + if (stored != NULL) { + bool fallback_is_feasible = true; + if (stored->order.OrderType == COT_Improvement) { + if ((stored->order.OrderID < 0) || + (stored->order.OrderID >= p_bic_data->ImprovementsCount)) + fallback_is_feasible = false; + + // Check if fallback requires a district the city doesn't have + if (fallback_is_feasible && + city_requires_district_for_improvement (city, stored->order.OrderID, NULL)) + fallback_is_feasible = false; + + // If original order was a wonder, ensure fallback is not also a wonder + if (fallback_is_feasible && needs_wonder_district) { + Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; + if (fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + fallback_is_feasible = false; + } + + // If fallback is a wonder, check if it has an incomplete wonder district + if (fallback_is_feasible && is->current_config.enable_wonder_districts) { + Improvement * fallback_improv = &p_bic_data->Improvements[stored->order.OrderID]; + if ((fallback_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) && + (! city_has_wonder_district_with_no_completed_wonder (city, stored->order.OrderID))) + fallback_is_feasible = false; + } + } else if (stored->order.OrderType == COT_Unit) { + if ((stored->order.OrderID < 0) || + (stored->order.OrderID >= p_bic_data->UnitTypeCount)) + fallback_is_feasible = false; + if (fallback_is_feasible) { + UnitType * type = &p_bic_data->UnitTypes[stored->order.OrderID]; + if (type->Unit_Class != UTC_Land) + fallback_is_feasible = false; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (city, AERODROME_DISTRICT_ID))) + fallback_is_feasible = false; + if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (city, PORT_DISTRICT_ID))) + fallback_is_feasible = false; + } + } else + fallback_is_feasible = false; + + if (fallback_is_feasible) { + if (out->OrderType == COT_Improvement) { + // Remember pending building order for any improvement that requires a district + snprintf (ss, sizeof ss, "ai_handle_district_production_requirements: Remembering fallback pending building order for city %d (%s): order type %d id %d\n", + city->Body.ID, city->Body.CityName, out->OrderType, out->OrderID); + (*p_OutputDebugStringA) (ss); + remember_pending_building_order (city, out->OrderID); + } + + fallback_order = stored->order; + swapped_to_fallback = true; + } + } + } + } + + if (swapped_to_fallback) { + *out = fallback_order; + } + if ((swapped_to_fallback || should_mark_district) && (required_district_id >= 0)) + mark_city_needs_district (city, required_district_id); + + clear_best_feasible_order (city); + return swapped_to_fallback; +} + +void __fastcall +patch_City_ai_choose_production (City * this, int edx, City_Order * out) +{ + is->ai_considering_production_for_city = this; + City_ai_choose_production (this, __, out); + + char ss[200]; + snprintf (ss, sizeof ss, "patch_City_ai_choose_production: City %d (%s) chose order type %d id %d\n", + this->Body.ID, this->Body.CityName, out->OrderType, out->OrderID); + (*p_OutputDebugStringA) (ss); + + if (is->current_config.enable_districts) { + if (ai_handle_district_production_requirements (this, out)) { + return; + } + } + + Leader * me = &leaders[this->Body.CivID]; + int arty_ratio = is->current_config.ai_build_artillery_ratio; + int bomber_ratio = is->current_config.ai_build_bomber_ratio; + + // Check if AI-build-more-artillery mod option is activated and this city is building something that we might want to switch to artillery + if ((arty_ratio > 0) && + (out->OrderType == COT_Unit) && + (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && + (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & (UTAI_Offence | UTAI_Defence))) { + + // Check how many offense/defense/artillery units this AI has already built. We'll only force it to build arty if it has a minimum + // of one defender per city, one attacker per two cities, and of course if it's below the ratio limit. + int num_attackers = me->AI_Strategy_Unit_Counts[0], + num_defenders = me->AI_Strategy_Unit_Counts[1], + num_artillery = me->AI_Strategy_Unit_Counts[2]; + if ((num_attackers > me->Cities_Count / 2) && + (num_defenders > me->Cities_Count) && + (100*num_artillery < arty_ratio*(num_attackers + num_defenders))) { + + // Loop over all build options to determine the best artillery unit available. Record its attack power and also find & record + // the highest attack power available from any offensive unit so we can compare them. + int best_arty_type_id = -1, + best_arty_rating = -1, + best_arty_strength = -1, + best_attacker_strength = -1; + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if ((type->AI_Strategy & (UTAI_Artillery | UTAI_Offence)) && + patch_City_can_build_unit (this, __, n, 1, 0, 0)) { + if (type->AI_Strategy & UTAI_Artillery) { + int this_rating = rate_artillery (&p_bic_data->UnitTypes[n]); + if (this_rating > best_arty_rating) { + best_arty_type_id = n; + best_arty_rating = this_rating; + best_arty_strength = type->Bombard_Strength * type->FireRate; + } + } else { // attacker + int this_strength = (type->Attack * (4 + type->Hit_Point_Bonus)) / 4; + if (this_strength > best_attacker_strength) + best_attacker_strength = this_strength; + } + } + } + + // Randomly switch city production to the artillery unit if we found one + if (best_arty_type_id >= 0) { + int chance = 12 * arty_ratio / 10; + + // Scale the chance of switching by the ratio of the attack power the artillery would provide to the attack power + // of the strongest offensive unit. This way the AI will rapidly build artillery up to the ratio limit only when + // artillery are its best way of dealing damage. + // Some example numbers: + // | Best attacker (str) | Best arty (str) | Chance w/ ratio = 20, damage% = 50 + // | Swordsman (3) | Catapult (4) | 16 + // | Knight (4) | Trebuchet (6) | 18 + // | Cavalry (6) | Cannon (8) | 16 + // | Cavalry (6) | Artillery (24) | 48 + // | Tank (16) | Artillery (24) | 18 + if (best_attacker_strength > 0) + chance = (chance * best_arty_strength * is->current_config.ai_artillery_value_damage_percent) / (best_attacker_strength * 100); + + if (rand_int (p_rand_object, __, 100) < chance) + out->OrderID = best_arty_type_id; + } + } + + } else if ((bomber_ratio > 0) && + (out->OrderType == COT_Unit) && + (out->OrderID >= 0) && (out->OrderID < p_bic_data->UnitTypeCount) && + (p_bic_data->UnitTypes[out->OrderID].AI_Strategy & UTAI_Air_Defence)) { + int num_fighters = me->AI_Strategy_Unit_Counts[7], + num_bombers = me->AI_Strategy_Unit_Counts[6]; + if (100 * num_bombers < bomber_ratio * num_fighters) { + int best_bomber_type_id = -1, + best_bomber_rating = -1; + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if ((type->AI_Strategy & UTAI_Air_Bombard) && + patch_City_can_build_unit (this, __, n, 1, 0, 0)) { + int this_rating = rate_bomber (&p_bic_data->UnitTypes[n]); + if (this_rating > best_bomber_rating) { + best_bomber_type_id = n; + best_bomber_rating = this_rating; + } + } + } + + if (best_bomber_type_id >= 0) { + int chance = 12 * bomber_ratio / 10; + if (rand_int (p_rand_object, __, 100) < chance) + out->OrderID = best_bomber_type_id; + } + } + } + + is->ai_considering_production_for_city = NULL; +} + +int __fastcall +patch_Unit_disembark_passengers (Unit * this, int edx, int tile_x, int tile_y) +{ + // Break any escort relationships if the escorting unit can't move onto the target tile. This prevents a freeze where the game continues + // trying to disembark units because an escortee looks like it could be disembarked except it can't because it won't move if its escorter + // can't be moved first. + Tile * tile = tile_at (this->Body.X, this->Body.Y), + * target = tile_at (tile_x , tile_y); + if (is->current_config.patch_blocked_disembark_freeze && (tile != NULL) && (target != NULL)) { + enum SquareTypes target_terrain = target->vtable->m50_Get_Square_BaseType (target); + FOR_UNITS_ON (uti, tile) { + Unit * escortee = get_unit_ptr (uti.unit->Body.escortee); + if ( (escortee != NULL) + && (uti.unit->Body.Container_Unit == this->Body.ID) + && (escortee->Body.Container_Unit == this->Body.ID) + && ( UnitType_has_ability (&p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID], __, UTA_Immobile) + || ( is->current_config.disallow_trespassing + && check_trespassing (uti.unit->Body.CivID, tile, target) + && ! is_allowed_to_trespass (uti.unit)) + || Unit_is_terrain_impassable (uti.unit, __, target_terrain))) + Unit_set_escortee (uti.unit, __, -1); + } + } + + return Unit_disembark_passengers (this, __, tile_x, tile_y); +} + +// Returns whether or not the current deal being offered to the AI on the trade screen would be accepted. How advantageous the AI thinks the +// trade is for itself is stored in out_their_advantage if it's not NULL. This advantage is measured in gold, if it's positive it means the +// AI thinks it's gaining that much value from the trade and if it's negative it thinks it would be losing that much. I don't know what would +// happen if this function were called while the trade screen is not active. +bool +is_current_offer_acceptable (int * out_their_advantage) +{ + int their_id = p_diplo_form->other_party_civ_id; + + DiploMessage consideration = Leader_consider_trade ( + &leaders[their_id], + __, + &p_diplo_form->our_offer_lists[their_id], + &p_diplo_form->their_offer_lists[their_id], + p_main_screen_form->Player_CivID, + 0, true, 0, 0, + out_their_advantage, + NULL, NULL); + + return consideration == DM_AI_ACCEPT; +} + +// Adds an offer of gold to the list and returns it. If one already exists in the list, returns a pointer to it. +TradeOffer * +offer_gold (TradeOfferList * list, int is_lump_sum, int * is_new_offer) +{ + if (list->length > 0) + for (TradeOffer * offer = list->first; offer != NULL; offer = offer->next) + if ((offer->kind == 7) && (offer->param_1 == is_lump_sum)) { + *is_new_offer = 0; + return offer; + } + + TradeOffer * tr = new (sizeof *tr); + *tr = (struct TradeOffer) { + .vtable = p_trade_offer_vtable, + .kind = 7, // TODO: Replace with enum + .param_1 = is_lump_sum, + .param_2 = 0, + .next = NULL, + .prev = NULL + }; + + if (list->length > 0) { + tr->prev = list->last; + list->last->next = tr; + list->last = tr; + list->length += 1; + } else { + list->last = list->first = tr; + list->length = 1; + } + + *is_new_offer = 1; + return tr; +} + +// Removes offer from list of offers but does not free it. Assumes offer is in the list. +void +remove_offer (TradeOfferList * list, TradeOffer * offer) +{ + if (list->length == 1) { + list->first = list->last = NULL; + list->length = 0; + } else if (list->length > 1) { + TradeOffer * prev = offer->prev, * next = offer->next; + if (prev) + prev->next = next; + if (next) + next->prev = prev; + if (list->first == offer) + list->first = next; + if (list->last == offer) + list->last = prev; + list->length -= 1; + } + offer->prev = offer->next = NULL; +} + +void __fastcall +patch_PopupForm_set_text_key_and_flags (PopupForm * this, int edx, char * script_path, char * text_key, int param_3, int param_4, int param_5, int param_6) +{ + int * p_stack = (int *)&script_path; + int ret_addr = p_stack[-1]; + + int is_initial_gold_trade = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_INITIAL_GOLD_OFFER_RETURN), + is_modifying_gold_trade = (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN ) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_OFFER_RETURN); + + // This function gets called from all over the place, check that it's being called to setup the set gold amount popup in the trade screen + if (is->current_config.autofill_best_gold_amount_when_trading && (is_initial_gold_trade || is_modifying_gold_trade)) { + int asking = (ret_addr == ADDR_SETUP_INITIAL_GOLD_ASK_RETURN) || (ret_addr == ADDR_SETUP_MODIFY_GOLD_ASK_RETURN); + int is_lump_sum = is_initial_gold_trade ? + p_stack[TRADE_GOLD_SETTER_IS_LUMP_SUM_OFFSET] : // Read this variable from the caller's frame + is->modifying_gold_trade->param_1; + + int their_id = p_diplo_form->other_party_civ_id, + our_id = p_main_screen_form->Player_CivID; + + // This variable will store the result of the optimization process and it's what will be used as the final amount presented to the + // player in the popup and left in the TradeOffer object (if applicable). Default to zero for new offers and the previous amount when + // modifying an offer. When modifying, we also zero the amount on the table b/c the optimization process only works properly from that + // starting point. + int best_amount = 0; + if (is_modifying_gold_trade) { + best_amount = is->modifying_gold_trade->param_2; + is->modifying_gold_trade->param_2 = 0; + } + + int their_advantage; + bool is_original_acceptable = is_current_offer_acceptable (&their_advantage); + + // if (we're asking for money on an acceptable trade and are offering something) OR (we're offering money on an unacceptable trade and + // are asking for something) + if (( asking && is_original_acceptable && (p_diplo_form->our_offer_lists[their_id] .length > 0)) || + ((! asking) && (! is_original_acceptable) && (p_diplo_form->their_offer_lists[their_id].length > 0))) { + + TradeOfferList * offers = asking ? &p_diplo_form->their_offer_lists[their_id] : &p_diplo_form->our_offer_lists[their_id]; + int test_offer_is_new; + TradeOffer * test_offer = offer_gold (offers, is_lump_sum, &test_offer_is_new); + + // When asking for gold, start at zero and work upwards. When offering gold it's more complicated. For lump sum + // offers, start with our entire treasury and work downward. For GPT offers, start with an upper bound and work + // downward. The upper bound depends on how much the AI thinks it's losing on the trade (in gold) divided by 20 + // (b/c 20 turn deal) with a lot of extra headroom just to make sure. + int starting_amount; { + if (asking) + starting_amount = 0; + else { + if (is_lump_sum) + starting_amount = leaders[our_id].Gold_Encoded + leaders[our_id].Gold_Decrement; + else { + int guess = not_below (0, 0 - their_advantage) / 20; + starting_amount = 10 + guess * 2; + } + } + } + + // Check if optimization is still possible. It's not if we're offering gold and our maximum offer is unacceptable + test_offer->param_2 = starting_amount; + if (asking || is_current_offer_acceptable (NULL)) { + + best_amount = starting_amount; + for (int step_size = asking ? 1000 : -1000; step_size != 0; step_size /= 10) { + test_offer->param_2 = best_amount; + while (1) { + test_offer->param_2 += step_size; + if (test_offer->param_2 < 0) + break; + else if (is_current_offer_acceptable (NULL)) + best_amount = test_offer->param_2; + else + break; + } + } + } + + // Annoying little edge case: The limitation on AIs not to trade more than their entire treasury is handled in the + // interface not the trade evaluation logic so we have to limit our gold request here to their treasury (otherwise + // the amount will default to how much they would pay if they had infinite money). + int their_treasury = leaders[their_id].Gold_Encoded + leaders[their_id].Gold_Decrement; + if (asking && is_lump_sum && (best_amount > their_treasury)) + best_amount = their_treasury; + + // Restore the trade table to its original state. Remove & free test_offer if it was newly created, otherwise put back its + // original amount. + if (test_offer_is_new) { + remove_offer (offers, test_offer); + test_offer->vtable->destruct (test_offer, __, 1); + } + + // If we're offering gold on a trade that's already acceptable, the optimal amount is zero. We must handle this explicitly in case + // we're modifying an amount already on the table. If we didn't, the above condition wouldn't optimize the amount and we'd default to + // the original amount. + } else if ((! asking) && is_original_acceptable) + best_amount = 0; + + if (is_modifying_gold_trade) + is->modifying_gold_trade->param_2 = best_amount; + snprintf (is->ask_gold_default, sizeof is->ask_gold_default, "%d", best_amount); + is->ask_gold_default[(sizeof is->ask_gold_default) - 1] = '\0'; + PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, (int)is->ask_gold_default, param_5, param_6); + } else + PopupForm_set_text_key_and_flags (this, __, script_path, text_key, param_3, param_4, param_5, param_6); +} + +CityLocValidity __fastcall +patch_Map_check_city_location (Map *this, int edx, int tile_x, int tile_y, int civ_id, bool check_for_city_on_tile) +{ + if (is->current_config.enable_natural_wonders) { + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { + return CLV_BLOCKED; + } + } + } + + int min_sep = is->current_config.minimum_city_separation; + CityLocValidity base_result = Map_check_city_location (this, __, tile_x, tile_y, civ_id, check_for_city_on_tile); + + // If minimum separation is one, make no change + if (min_sep == 1) + return base_result; + + // If minimum separation is <= 0, ignore the CITY_TOO_CLOSE objection to city placement unless the location is next to a city belonging to + // another civ and the settings forbid founding there. + else if ((min_sep <= 0) && (base_result == CLV_CITY_TOO_CLOSE)) { + if (is->current_config.disallow_founding_next_to_foreign_city) + for (int n = 1; n <= 8; n++) { + int x, y; + get_neighbor_coords (&p_bic_data->Map, tile_x, tile_y, n, &x, &y); + City * city = city_at (x, y); + if ((city != NULL) && (city->Body.CivID != civ_id)) + return CLV_CITY_TOO_CLOSE; + } + return CLV_OK; + + // If we have an increased separation we might have to exclude some locations the base code allows. + } else if ((min_sep > 1) && (base_result == CLV_OK)) { + // Check tiles around (x, y) for a city. Because the base result is CLV_OK, we don't have to check neighboring tiles, just those at + // distance 2, 3, ... up to (an including) the minimum separation + for (int dist = 2; dist <= min_sep; dist++) { + + // vertices stores the unwrapped coords of the tiles at the vertices of the square of tiles at distance "dist" around + // (tile_x, tile_y). The order of the vertices is north, east, south, west. + struct vertex { + int x, y; + } vertices[4] = { + {tile_x , tile_y - 2*dist}, + {tile_x + 2*dist, tile_y }, + {tile_x , tile_y + 2*dist}, + {tile_x - 2*dist, tile_y } + }; + + // neighbor index for direction of tiles along edge starting from each vertex + // values correspond to directions: southeast, southwest, northwest, northeast + int edge_dirs[4] = {3, 5, 7, 1}; + + // Loop over verts and check tiles along their associated edges. The N vert is associated with the NE edge, the E vert with + // the SE edge, etc. + for (int vert = 0; vert < 4; vert++) { + wrap_tile_coords (&p_bic_data->Map, &vertices[vert].x, &vertices[vert].y); + int dx, dy; + neighbor_index_to_diff (edge_dirs[vert], &dx, &dy); + for (int j = 0; j < 2*dist; j++) { // loop over tiles along this edge + int cx = vertices[vert].x + j * dx, + cy = vertices[vert].y + j * dy; + wrap_tile_coords (&p_bic_data->Map, &cx, &cy); + if (city_at (cx, cy)) + return CLV_CITY_TOO_CLOSE; + } + } + + } + return base_result; + + } else + return base_result; +} + +bool +is_zero_strength (UnitType * ut) +{ + return (ut->Attack == 0) && (ut->Defence == 0); +} + +bool +is_captured (Unit_Body * u) +{ + return (u->RaceID >= 0) && (u->CivID >= 0) && (u->CivID < 32) && leaders[u->CivID].RaceID != u->RaceID; +} + +// Decides whether or not units "a" and "b" are duplicates, i.e., whether they are interchangeable. +// If surface_only is set, the function checks only surface-level characteristics, meaning those that are visible to other players. +bool +are_units_duplicate (Unit_Body * a, Unit_Body * b, bool surface_only) +{ + UnitType * a_type = &p_bic_data->UnitTypes[a->UnitTypeID], + * b_type = &p_bic_data->UnitTypes[b->UnitTypeID]; + + // If only doing a surface comparison, look through the alternate strategy types to the base types. The difference b/w the alt types is only + // their AI strategies, and that isn't considered a surface feature. + if (surface_only) { + while (a_type->alternate_strategy_for_id >= 0) + a_type = &p_bic_data->UnitTypes[a_type->alternate_strategy_for_id]; + while (b_type->alternate_strategy_for_id >= 0) + b_type = &p_bic_data->UnitTypes[b_type->alternate_strategy_for_id]; + } + + // a and b are duplicates "on the surface" if... + bool are_surface_duplicates = + // ... they belong to the same player ... + (a->CivID == b->CivID) && + + // ... they have the same type that is not [a leader OR army] AND not a transport AND ... + (a_type == b_type) && + (! (UnitType_has_ability (a_type, __, UTA_Leader) || UnitType_has_ability (a_type, __, UTA_Army))) && + (a_type->Transport_Capacity == 0) && + + // ... they've taken the same amount of damage AND have the same charm status AND ... + (a->Damage == b->Damage) && (a->charmed == b->charmed) && + + // ... they're either both fortified or both not AND ... + (! (a->UnitState == UnitState_Fortifying) ^ (b->UnitState == UnitState_Fortifying)) && + + // ... [they have the same experience level OR are zero strength units] AND ... + ((a->Combat_Experience == b->Combat_Experience) || is_zero_strength (a_type)) && + + // ... [they are both not contained in any unit OR they are both contained in the same unit] AND ... + (((a->Container_Unit < 0) && (b->Container_Unit < 0)) || (a->Container_Unit == b->Container_Unit)) && + + // ... neither one is carrying a princess AND ... + ((a->carrying_princess_of_race < 0) && (b->carrying_princess_of_race < 0)) && + + // ... [they are both captured units OR are both native units] AND ... + (! (is_captured (a) ^ is_captured (b))) && + + // ... their custom names are identical. + (0 == strncmp (a->Custom_Name.S, b->Custom_Name.S, sizeof (a->Custom_Name))); + + if ((! are_surface_duplicates) || surface_only) + return are_surface_duplicates; + + // a and b are additionally "deep", i.e. in all ways, duplicates if... + bool are_deep_duplicates = + // ... they've used up the same number of moves AND ... + (a->Moves == b->Moves) && + + // ... they have matching statuses (has attacked this turn, etc.) AND states (is fortified, is doing worker action, etc.) AND automation status AND ... + (a->Status == b->Status) && (a->UnitState == b->UnitState) && (a->automated == b->automated) && + + // ... they have both done the same number of airdrops this turn. + (itable_look_up_or (&is->airdrops_this_turn, a->ID, 0) == itable_look_up_or (&is->airdrops_this_turn, b->ID, 0)); + + return are_deep_duplicates; +} + +bool +is_busy (Unit * unit) +{ + int state = unit->Body.UnitState; + return ((state >= UnitState_Build_Mines) && (state <= UnitState_Explore)) || + (state == UnitState_Auto_Bombard) || (state == UnitState_Auto_Air_Bombard) || + unit->Body.automated; +} + +int __fastcall +patch_Context_Menu_add_item_and_set_color (Context_Menu * this, int edx, int item_id, char * text, int red) +{ + // Initialize the array of duplicate counts. The array is 0x100 items long because that's the maximum number of items a menu can have. + if (is->current_config.group_units_on_right_click_menu && + (is->unit_menu_duplicates == NULL)) { + unsigned dups_size = 0x100 * sizeof is->unit_menu_duplicates[0]; + is->unit_menu_duplicates = malloc (dups_size); + memset (is->unit_menu_duplicates, 0, dups_size); + } + + // Check if this menu item is a valid unit and grab pointers to its info + int unit_id; + Unit_Body * unit_body; + bool disable = false, put_icon = false; + int icon_index = 0; + if ((0 <= (unit_id = item_id - (0x13 + p_bic_data->UnitTypeCount))) && + (NULL != (unit_body = p_units->Units[unit_id].Unit)) && + (unit_body->UnitTypeID >= 0) && (unit_body->UnitTypeID < p_bic_data->UnitTypeCount)) { + + if (is->current_config.group_units_on_right_click_menu) { + // Loop over all existing menu items and check if any of them is a unit that's a duplicate of the one being added + for (int n = 0; n < this->Item_Count; n++) { + Context_Menu_Item * item = &this->Items[n]; + int dup_unit_id = this->Items[n].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount); + Unit_Body * dup_body; + if ((dup_unit_id >= 0) && + (NULL != (dup_body = p_units->Units[dup_unit_id].Unit)) && + are_units_duplicate (unit_body, dup_body, unit_body->CivID != p_main_screen_form->Player_CivID)) { + // The new item is a duplicate of the nth. Mark that in the duplicate counts array and return without actually + // adding the item. It doesn't matter what value we return because the caller doesn't use it. + is->unit_menu_duplicates[n] += 1; + return 0; + } + } + } + + if (unit_body->CivID == p_main_screen_form->Player_CivID) { + Unit * unit = (Unit *)((int)unit_body - offsetof (Unit, Body)); + UnitType * unit_type = &p_bic_data->UnitTypes[unit_body->UnitTypeID]; + bool no_moves_left = unit_body->Moves >= patch_Unit_get_max_move_points (unit); + if (no_moves_left && is->current_config.gray_out_units_on_menu_with_no_remaining_moves) + disable = true; + + // Put an icon next to this unit if we're configured to do so and it's not in an army + Unit * container; + if (is->current_config.put_movement_icons_on_units_on_menu && + ((NULL == (container = get_unit_ptr (unit_body->Container_Unit))) || + (! UnitType_has_ability (&p_bic_data->UnitTypes[container->Body.UnitTypeID], __, UTA_Army)))) { + put_icon = true; + + bool attacker = is_offensive_combat_type (unit_type) || (Unit_has_ability (unit, __, UTA_Army) && (Unit_count_contained_units (unit) >= 1)), + busy = is_busy (unit); + + int icon_set_index = ((int)busy << 1) + (int)(! attacker); + + int icon_row; { + if (no_moves_left) + icon_row = URCMI_CANT_MOVE; + else if (unit_body->Moves == 0) + icon_row = URCMI_UNMOVED; + else if (! attacker) + icon_row = URCMI_MOVED_NO_ATTACK; + else + icon_row = (! has_exhausted_attack (unit)) ? URCMI_MOVED_CAN_ATTACK : URCMI_MOVED_NO_ATTACK; + } + + icon_index = icon_set_index * COUNT_UNIT_RCM_ICONS + icon_row; + } + } + } + + int tr = Context_Menu_add_item_and_set_color (this, __, item_id, text, red); + + if (disable) + Context_Menu_disable_item (this, __, item_id); + + if (put_icon) { + init_unit_rcm_icons (); + if (is->unit_rcm_icon_state == IS_OK) + Context_Menu_put_image_on_item (this, __, item_id, &is->unit_rcm_icons[icon_index]); + } + + return tr; +} + +int __fastcall +patch_Context_Menu_open (Context_Menu * this, int edx, int x, int y, int param_3) +{ + int * p_stack = (int *)&x; + int ret_addr = p_stack[-1]; + + if (is->current_config.enable_named_tiles && + is->named_tile_menu_active) { + int tile_x = is->named_tile_menu_tile_x; + int tile_y = is->named_tile_menu_tile_y; + Tile * tile = tile_at (tile_x, tile_y); + if (tile_can_be_named (tile, tile_x, tile_y)) { + struct named_tile_entry * entry = get_named_tile_entry (tile); + char menu_text[64]; + if ((entry != NULL) && (entry->name[0] != '\0')) + snprintf (menu_text, sizeof menu_text, "%s %s", is->c3x_labels[CL_RENAME_TILE], entry->name); + else + strcpy (menu_text,is->c3x_labels[CL_NAME_TILE]); + if (this->Item_Count > 0) + Context_Menu_add_separator (this, __, 0); + Context_Menu_add_item (this, __, NAMED_TILE_MENU_ID, menu_text, false, (Sprite *)0x0); + } + } + + if (is->current_config.group_units_on_right_click_menu && + (ret_addr == ADDR_OPEN_UNIT_MENU_RETURN) && + (is->unit_menu_duplicates != NULL)) { + + // Change the menu text to include the duplicate counts. This is pretty straight forward except for a couple little issues: we must + // use the game's internal malloc & free for compatibility with the base code and must call a function that widens the menu form, + // as necessary, to accommodate the longer strings. + for (int n = 0; n < this->Item_Count; n++) + if (is->unit_menu_duplicates[n] > 0) { + Context_Menu_Item * item = &this->Items[n]; + unsigned new_text_len = strlen (item->Text) + 20; + char * new_text = civ_prog_malloc (new_text_len); + + // Print entry text including dup count to new_text. Biggest complication here is that we want to print the dup count + // after any leading spaces to preserve indentation. + { + int num_spaces = 0; + while (item->Text[num_spaces] == ' ') + num_spaces++; + snprintf (new_text, new_text_len, "%.*s%dx %s", num_spaces, item->Text, is->unit_menu_duplicates[n] + 1, &item->Text[num_spaces]); + new_text[new_text_len - 1] = '\0'; + } + + civ_prog_free (item->Text); + item->Text = new_text; + Context_Menu_widen_for_text (this, __, new_text); + } + + // Clear the duplicate counts + memset (is->unit_menu_duplicates, 0, 0x100 * sizeof is->unit_menu_duplicates[0]); + } + + return Context_Menu_open (this, __, x, y, param_3); +} + +bool +is_material_unit (UnitType const * type, bool * out_is_pop_else_caravan) +{ + int join_city_action = UCV_Join_City & 0x0FFFFFFF; // To get the join city action code, use the command value and mask out the top 4 category bits + int disband_action = UCV_Disband & 0x0FFFFFFF; + if ((type->Attack | type->Defence | type->Bombard_Strength) == 0) { // if non-combat unit + if ((type->PopulationCost > 0) && (type->Worker_Actions == join_city_action)) { + *out_is_pop_else_caravan = true; + return true; + } else if ((type->Standard_Actions & disband_action) && (type->Worker_Actions == 0)) { + *out_is_pop_else_caravan = false; + return true; + } else + return false; + } else + return false; +} + +void +ai_move_material_unit (Unit * this) +{ + int type_id = this->Body.UnitTypeID; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + UnitType * type = &p_bic_data->UnitTypes[type_id]; + + // Determine whether this is a pop unit (will search for a city to join) or a caravan (will search for a city to disband) + int join_city_action = UCV_Join_City & 0x0FFFFFFF; + bool pop_else_caravan = type->Worker_Actions == join_city_action; + + int continent_id = tile->vtable->m46_Get_ContinentID (tile); + + // This part of the code follows how the replacement leader AI works. Basically it disbands the unit if it's on a continent with no + // friendly cities, then flees if it's in danger, then moves it along a set path if it has one. + if (leaders[this->Body.CivID].city_count_per_cont[continent_id] == 0) { + Unit_disband (this); + return; + } + if (any_enemies_near_unit (this, 49)) { + Unit_set_state (this, __, UnitState_Fleeing); + bool done = this->vtable->work (this); + if (done || (this->Body.UnitState != 0)) + return; + } + byte next_move = Unit_pop_next_move_from_path (this); + if (next_move > 0) { + this->vtable->Move (this, __, next_move, 0); + return; + } + + // Find the best city to act on + City * best_city = NULL; + int best_city_value = pop_else_caravan ? -1 : 0; // min value to act is 0 for pop units, 1 for caravans + FOR_CITIES_OF (coi, this->Body.CivID) { + City * city = coi.city; + Tile * city_tile = tile_at (city->Body.X, city->Body.Y); + if (continent_id == city_tile->vtable->m46_Get_ContinentID (city_tile)) { + + if (pop_else_caravan) { + // Skip this city if it can't support another citizen + if ((city->Body.FoodIncome <= 0) || + (City_requires_improvement_to_grow (city) > -1)) + continue; + } else { + // Skip this city if its current build can't be rushed + if (! City_can_take_outside_shields (city, __, 0)) + continue; + } + + // Consider distance. + int dist_in_turns; + if (! estimate_travel_time (this, city->Body.X, city->Body.Y, &dist_in_turns)) + continue; // No path or unit cannot move + + int value; + if (pop_else_caravan) + value = 1000 / (10 + dist_in_turns); // Base value of 100 * 10 / (10 + dist_in_turn) + else { + // value is number of useful shields we'd get by moving to this city and disbanding there + int shields_per_turn = get_city_production_rate (city, city->Body.Order_Type, city->Body.Order_ID), + shields_to_complete_build = City_get_order_cost (city) - City_get_order_progress (city) - shields_per_turn, + disband_value = Leader_get_unit_cost (&leaders[city->Body.CivID], __, type_id, false) >> 2; + value = not_above (shields_to_complete_build, disband_value) - shields_per_turn * dist_in_turns; + } + + // Scale value by city corruption rate for pop units or caravan units targeting cities building improvs + if (pop_else_caravan || (city->Body.Order_Type == COT_Improvement)) { + int good_shields = city->Body.ProductionIncome, + corrupt_shields = city->Body.ProductionLoss; + if (good_shields + corrupt_shields > 0) + value = (value * good_shields) / (good_shields + corrupt_shields); + else + value = -1; + } + + if (value > best_city_value) { + best_city = city; + best_city_value = value; + } + } + } + + // Join city if we're already in the city we want to join, otherwise move to that city. If we couldn't find a city to join, go to the + // nearest established city and wait. + City * in_city = get_city_ptr (tile->vtable->m45_Get_City_ID (tile)); + City * moving_to_city = NULL; + if (best_city != NULL) { + if (best_city == in_city) { + if (pop_else_caravan && patch_Unit_can_perform_command (this, __, UCV_Join_City)) { + Unit_join_city (this, __, in_city); + return; + } else if ((! pop_else_caravan) && patch_Unit_can_perform_command (this, __, UCV_Disband)) { + Unit_disband (this); + return; + } + } else + moving_to_city = best_city; + } else if (in_city == NULL) + moving_to_city = find_nearest_established_city (this, continent_id); + + if (moving_to_city) { + int first_move = patch_Trade_Net_set_unit_path (is->trade_net, __, this->Body.X, this->Body.Y, moving_to_city->Body.X, moving_to_city->Body.Y, this, this->Body.CivID, 0x101, NULL); + if (first_move > 0) { + Unit_set_escortee (this, __, -1); + this->vtable->Move (this, __, first_move, 0); + return; + } + } + + // Nothing to do, nowhere to go, just fortify in place. + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +int __stdcall +patch_get_anarchy_length (int leader_id) +{ + int base = get_anarchy_length (leader_id); + int multiplier = is->current_config.anarchy_length_percent; + if (multiplier != 100) { + // Anarchy cannot be less than 2 turns or you'll get an instant government switch. Only let that happen when the percent multiplier is + // set below zero, indicating a desire for no anarchy. Otherwise we can't reduce anarchy below 2 turns. + if (multiplier < 0) + return 1; + else if (base <= 2) + return base; + else + return not_below (2, rand_div (base * multiplier, 100)); + } else + return base; +} + +bool __fastcall +patch_Unit_check_king_ability_while_spawning (Unit * this, int edx, enum UnitTypeAbilities a) +{ + if (is->current_config.dont_give_king_names_in_non_regicide_games && + ((*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) == 0)) + return false; + else + return Unit_has_ability (this, __, a); +} + +int __fastcall +patch_Map_compute_neighbor_index_for_pass_between (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + if (is->current_config.enable_land_sea_intersections) + return 0; + else + return Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); +} + +// This call replacement used to be part of improvement perfuming but now its only purpose is to set ai_considering_order when +// ai_choose_production is looping over improvements. +bool __fastcall +patch_Improvement_has_wonder_com_bonus_for_ai_prod (Improvement * this, int edx, enum ImprovementTypeWonderFeatures flag) +{ + is->ai_considering_order.OrderID = this - p_bic_data->Improvements; + is->ai_considering_order.OrderType = COT_Improvement; + return Improvement_has_wonder_flag (this, __, flag); +} + +// Similarly, this one sets the var when looping over unit types. +bool __fastcall +patch_UnitType_has_strat_0_for_ai_prod (UnitType * this, int edx, byte n) +{ + is->ai_considering_order.OrderID = this - p_bic_data->UnitTypes; + is->ai_considering_order.OrderType = COT_Unit; + return UnitType_has_ai_strategy (this, __, n); +} + +int +compare_ai_prod_valuations (void const * vp_a, void const * vp_b) +{ + struct ai_prod_valuation const * a = vp_a, + * b = vp_b; + if (a->point_value > b->point_value) return -1; + else if (b->point_value > a->point_value) return 1; + else return 0; +} + +void +rank_ai_production_options (City * city) +{ + is->count_ai_prod_valuations = 0; + City_Order unused; + patch_City_ai_choose_production (city, __, &unused); // records valuations in is->ai_prod_valuations + qsort (is->ai_prod_valuations, is->count_ai_prod_valuations, sizeof is->ai_prod_valuations[0], compare_ai_prod_valuations); +} + +void __fastcall +patch_City_Form_m82_handle_key_event (City_Form * this, int edx, int virtual_key_code, int is_down) +{ + if (is->current_config.enable_ai_production_ranking && + (~*p_human_player_bits & (1 << this->CurrentCity->Body.CivID)) && + (virtual_key_code == VK_P) && is_down) { + rank_ai_production_options (this->CurrentCity); + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_AI_PROD_RANKING", -1, 0, 0, 0); + char s[200]; + for (int n = 0; n < is->count_ai_prod_valuations; n++) { + struct ai_prod_valuation const * val = &is->ai_prod_valuations[n]; + char * name = (val->order_type == COT_Improvement) ? p_bic_data->Improvements[val->order_id].Name.S : p_bic_data->UnitTypes[val->order_id].Name; + + int show_strategy = -1; + if (val->order_type == COT_Unit) + itable_look_up (&is->unit_type_alt_strategies, val->order_id, &show_strategy); + + if ((show_strategy >= 0) && (show_strategy <= CL_LAST_UNIT_STRAT - CL_FIRST_UNIT_STRAT)) + snprintf (s, sizeof s, "^%d %s (%s)", val->point_value, name, is->c3x_labels[CL_FIRST_UNIT_STRAT + show_strategy]); + else + snprintf (s, sizeof s, "^%d %s", val->point_value, name); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + patch_show_popup (popup, __, 0, 0); + + } else if (is->current_config.toggle_zoom_with_z_on_city_screen && + (virtual_key_code == VK_Z) && is_down) { + p_bic_data->is_zoomed_out = ! p_bic_data->is_zoomed_out; + Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, this->CurrentCity->Body.X, get_city_screen_center_y (this->CurrentCity), 0, true, false); // also redraws map + this->Base.vtable->m73_call_m22_Draw ((Base_Form *)this); + } + + City_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); +} + +bool +can_harvest_shields_from_forest (Tile * tile) +{ + int flags = tile->vtable->m43_Get_field_30 (tile); + return (flags & 0x10000000) == 0; +} + +void __fastcall +patch_open_tile_info (void * this, int edx, int mouse_x, int mouse_y, int civ_id) +{ + int tx, ty; + if (is->current_config.show_detailed_tile_info && + (! Main_Screen_Form_get_tile_coords_under_mouse (p_main_screen_form, __, mouse_x, mouse_y, &tx, &ty))) { + is->viewing_tile_info_x = tx; + is->viewing_tile_info_y = ty; + is->tile_info_open = true; + } else + is->viewing_tile_info_x = is->viewing_tile_info_y = -1; + + open_tile_info (this, __, mouse_x, mouse_y, civ_id); + + is->tile_info_open = false; +} + +int __fastcall +patch_Match_ai_eval_city_location (void * this, int edx, int x, int y, int civ_id, bool param_4, int * out_breakdown) +{ + is->ai_evaling_city_loc_x = x; + is->ai_evaling_city_loc_y = y; + is->ai_evaling_city_field_30_get_counter = 0; + + return Match_ai_eval_city_location (this, __, x, y, civ_id, param_4, out_breakdown); +} + +bool +is_explored (Tile * tile, int civ_id) +{ + unsigned explored_bits = tile->Body.Fog_Of_War; + int in_debug_mode = (*p_debug_mode_bits & 8) != 0; // checking bit 3 here b/c that's how resource visibility is checked in open_tile_info + if (in_debug_mode || (explored_bits & (1 << civ_id))) + return true; + else if (is->current_config.share_visibility_in_hotseat && // if shared hotseat vis is enabled AND + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game AND + ((1 << civ_id) & *p_human_player_bits) && // "civ_id" is a human player AND + (explored_bits & *p_human_player_bits)) // any human player has visibility on the tile + return true; + else + return false; +} + +// On the GOG executable, this function intercepts the call to draw the "No information available" text on a unexplored (black) tile. In that case we +// replace that text with the coords. But on the Steam EXE this func also intercepts the call that draws the resource name on the visible tile info +// box b/c the call site is reused via a jump. So we must check that the tile is actually unexplored before replacing the text so that the resource +// name doesn't get overwritten. +int __fastcall +patch_PCX_Image_draw_no_tile_info (PCX_Image * this, int edx, char * str, int x, int y, int str_len) +{ + Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if ((tile != p_null_tile) && ! is_explored (tile, p_main_screen_form->Player_CivID)) { + char s[100]; + snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); + s[(sizeof s) - 1] = '\0'; + return PCX_Image_draw_text (this, __, s, x, y, strlen (s)); + } else + return PCX_Image_draw_text (this, __, str, x, y, str_len); +} + +int __fastcall +patch_PCX_Image_draw_tile_info_terrain (PCX_Image * this, int edx, char * str, int x, int y, int str_len) +{ + Tile * tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if (tile != p_null_tile) { + bool show_district_name = false; + + char s[200]; + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + // Draw district name to the right of terrain name if tile has one + struct district_instance * dist = get_district_instance (tile); + + if (dist != NULL) { + show_district_name = true; + char const * display_name = is->district_configs[dist->district_id].display_name; + if ((display_name == NULL) || (display_name[0] == '\0')) + display_name = is->district_configs[dist->district_id].name; + + // If it's a wonder district with a completed wonder, show the wonder name instead + if ((dist->district_id == WONDER_DISTRICT_ID) && + (dist->wonder_info.state == WDS_COMPLETED) && + (dist->wonder_info.wonder_index >= 0) && + (dist->wonder_info.wonder_index < is->wonder_district_count)) { + char const * wonder_name = is->wonder_district_configs[dist->wonder_info.wonder_index].wonder_name; + if ((wonder_name != NULL) && (wonder_name[0] != '\0')) { + display_name = wonder_name; + } + } else if ((dist->district_id == NATURAL_WONDER_DISTRICT_ID) && + (dist->natural_wonder_info.natural_wonder_id >= 0) && + (dist->natural_wonder_info.natural_wonder_id < is->natural_wonder_count)) { + int natural_id = dist->natural_wonder_info.natural_wonder_id; + char const * natural_name = is->natural_wonder_configs[natural_id].name; + if ((natural_name != NULL) && (natural_name[0] != '\0')) { + display_name = natural_name; + } + } + + snprintf (s, sizeof s, "%s", display_name); + PCX_Image_draw_text (this, __, s, x + 68, y, strlen (s)); + } + } + + // Show sprites & sheet indexes if in debug mode + int is_debug_mode = (*p_debug_mode_bits & 4) != 0; + if (is_debug_mode) { + int sheet_index = (tile->SquareParts >> 8) & 0xFF; + int sprite_index = tile->SquareParts & 0xFF; + snprintf (s, sizeof s, "%d, %d", sheet_index, sprite_index); + PCX_Image_draw_text (this, __, s, x, y - 18, strlen (s)); + } + + // Draw tile coords on line below terrain name + snprintf (s, sizeof s, "(%d, %d)", is->viewing_tile_info_x, is->viewing_tile_info_y); + PCX_Image_draw_text (this, __, s, x, y + 14, strlen (s)); + + if ((is->city_loc_display_perspective >= 0) && + ((1 << is->city_loc_display_perspective) & *p_player_bits)) { + int eval = patch_Match_ai_eval_city_location (p_match, __, is->viewing_tile_info_x, is->viewing_tile_info_y, is->city_loc_display_perspective, false, NULL); + if (eval > 0) { + snprintf (s, sizeof s, "%d", eval - 1000000); + PCX_Image_draw_text (this, __, s, x + 95, y, strlen (s)); + } + } + + // If tile has been chopped and district name not shown (uses same space), indicate that to the right of the terrain name + if (! can_harvest_shields_from_forest (tile) && !show_district_name) + PCX_Image_draw_text (this, __, is->c3x_labels[CL_CHOPPED], x + 145, y, strlen (is->c3x_labels[CL_CHOPPED])); + } + return PCX_Image_draw_text (this, __, str, x, y, str_len); +} + +int __fastcall +patch_City_compute_corrupted_yield (City * this, int edx, int gross_yield, bool is_production) +{ + Leader * leader = &leaders[this->Body.CivID]; + + if (is->current_config.zero_corruption_when_off && + (p_bic_data->Governments[leader->GovernmentType].CorruptionAndWaste == CWT_Off)) + return 0; + + int tr = City_compute_corrupted_yield (this, __, gross_yield, is_production); + + if (is->current_config.promote_wonder_decorruption_effect) { + int actual_capital_id = leader->CapitalID; + for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { + Improvement * improv = &p_bic_data->Improvements[improv_id]; + City * pseudo_capital = NULL; + if (improv->SmallWonderFlags & ITSW_Reduces_Corruption) { + if (improv->Characteristics & ITC_Small_Wonder) { + pseudo_capital = get_city_ptr (leader->Small_Wonders[improv_id]); + } else if (improv->Characteristics & ITC_Wonder) { + pseudo_capital = get_city_ptr (Game_get_wonder_city_id(p_game, __, improv_id)); + } + + if (pseudo_capital != NULL && pseudo_capital->Body.CivID == this->Body.CivID && pseudo_capital->Body.ID != actual_capital_id) { + leader->CapitalID = pseudo_capital->Body.ID; + int fp_corrupted_yield = City_compute_corrupted_yield (this, __, gross_yield, is_production); + if (fp_corrupted_yield < tr) + tr = fp_corrupted_yield; + } + } + } + leader->CapitalID = actual_capital_id; + } + + return tr; +} + +int __fastcall +patch_Sprite_draw (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + Sprite * to_draw = get_sprite_proxy_for_current_hour(this); + return Sprite_draw(to_draw ? to_draw : this, __, canvas, pixel_x, pixel_y, color_table); +} + +int __fastcall +patch_Sprite_draw_on_map (Sprite * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) +{ + Sprite * to_draw = get_sprite_proxy_for_current_hour(this); + return Sprite_draw_on_map(to_draw ? to_draw : this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); +} + +bool +is_or_could_become_grassland (Tile * tile) +{ + enum SquareTypes sq_type = tile->vtable->m50_Get_Square_BaseType (tile), + underlying_type = tile->vtable->m49_Get_Square_RealType (tile); + int worker_job_id = p_bic_data->TileTypes[sq_type].WorkerJobID; + return sq_type == SQ_Grassland || + (underlying_type == SQ_Grassland && (worker_job_id == WJ_Clean_Forest || worker_job_id == WJ_Clear_Swamp)) || + tile->vtable->m72_Get_Pollution_Effect (tile) == SQ_Grassland; +} + +void __fastcall +patch_Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (Map_Renderer * this, int edx, int param_1, int pixel_x, int pixel_y, Map_Renderer * map_renderer, int param_5, int tile_x, int tile_y, int param_8) +{ + Map * map = &p_bic_data->Map; + Tile * tile = tile_at (tile_x, tile_y); + + is->current_render_tile = tile; + is->current_render_tile_x = tile_x; + is->current_render_tile_y = tile_y; + is->current_render_tile_district = get_district_instance (tile); + + Map_Renderer_m19_Draw_Tile_by_XY_and_Flags (this, __, param_1, pixel_x, pixel_y, map_renderer, param_5, tile_x, tile_y, param_8); + + is->current_render_tile = NULL; + is->current_render_tile_x = -1; + is->current_render_tile_y = -1; + is->current_render_tile_district = NULL; + + if ((is->city_loc_display_perspective >= 0) && + (! map->vtable->m10_Get_Map_Zoom (map)) && // Turn off display when zoomed out. Need another set of highlight images for that. + ((1 << is->city_loc_display_perspective) & *p_player_bits) && + (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. + + init_tile_highlights (); + if (is->tile_highlight_state == IS_OK) { + int eval = patch_Match_ai_eval_city_location (p_match, __, tile_x, tile_y, is->city_loc_display_perspective, false, NULL); + if (eval > 0) { + int step_size = 10; + int midpoint = (COUNT_TILE_HIGHLIGHTS % 2 == 0) ? 1000000 : (1000000 - step_size/2); + int grade = (eval >= midpoint) ? (eval - midpoint) / step_size : (eval - midpoint) / step_size - 1; + int i_highlight = clamp (0, COUNT_TILE_HIGHLIGHTS - 1, COUNT_TILE_HIGHLIGHTS/2 + grade); + Sprite_draw_on_map (&is->tile_highlights[i_highlight], __, this, pixel_x, pixel_y, 1, 1, 1, 0); + } + } + } + + // Districts-related highlights + if (is->current_config.enable_districts && + (((tile_x + tile_y) % 2) == 0)) { // Replicate a check from the base game code. Without this we'd be drawing additional tiles half-way off the grid. + init_tile_highlights (); + if (is->tile_highlight_state == IS_OK) { + + // Draw city work radius highlights for selected worker + if (is->current_config.enable_city_work_radii_highlights && + is->highlight_city_radii) { + + if ((tile != NULL) && (tile != p_null_tile)) { + int stored_ptr; + if (itable_look_up (&is->highlighted_city_radius_tile_pointers, (int)tile, &stored_ptr)) { + struct highlighted_city_radius_tile_info * info = (struct highlighted_city_radius_tile_info *)stored_ptr; + Sprite_draw_on_map (&is->tile_highlights[clamp(0, COUNT_TILE_HIGHLIGHTS - 1, info->highlight_level)], __, this, pixel_x, pixel_y, 1, 1, 1, 0); + } + } + } + + // If focusing on a tile after Great Wall completed, highlight the tile while getting user confirmation + if (is->focused_tile != NULL && is->focused_tile == tile) { + Sprite_draw_on_map (&is->tile_highlights[10], __, this, pixel_x, pixel_y, 1, 1, 1, 0); + } + } + } +} + +// We determine at the start of the game where *any* AI player might want to build canals and bridges. +// This is done up front in a single pass, as re-assessing every single turn per AI is wasteful and the +// geography of the map doesn't change. This function adds all the candidates as districts, effectively +// drawing them directly on the map. We don't use it in a normal game, but this is extremely useful for +// debugging so good to keep it around. For debugging, just call it immediately after +// generate_ai_canal_and_bridge_targets () +void +insert_ai_candidate_bridge_or_canals_into_district_tile_map () +{ + if ((is->ai_candidate_bridge_or_canals_count <= 0) || (! is->ai_candidate_bridge_or_canals_initialized)) + return; + + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if (entry == NULL) + continue; + + char ss[256]; + snprintf (ss, sizeof ss, "Entry %d: district %d owner %d tiles %d completed %d\n", + ei, entry->district_id, entry->owner_civ_id, entry->tile_count, entry->completed ? 1 : 0); + (*p_OutputDebugStringA)(ss); + + for (int ti = 0; ti < entry->tile_count; ti++) { + int tx = entry->tile_x[ti]; + int ty = entry->tile_y[ti]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + snprintf (ss, sizeof ss, " (%d,%d)%s\n", tx, ty, (ti == entry->assigned_tile_index) ? " [assigned]" : ""); + (*p_OutputDebugStringA)(ss); + } + } + + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + if ((entry == NULL) || (entry->completed)) + continue; + + for (int ti = 0; ti < entry->tile_count; ti++) { + int tx = entry->tile_x[ti]; + int ty = entry->tile_y[ti]; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int key = (int)tile; + int existing; + if (itable_look_up (&is->district_tile_map, key, &existing)) + continue; + + struct district_instance * inst = (struct district_instance *)calloc (1, sizeof *inst); + if (inst == NULL) + continue; + inst->state = DS_COMPLETED; + inst->district_id = entry->district_id; + inst->tile_x = tx; + inst->tile_y = ty; + + itable_insert (&is->district_tile_map, key, (int)inst); + } + } +} + +void __fastcall +patch_Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (Map_Renderer * this, int edx, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (! is->current_config.draw_forests_over_roads_and_railroads) { + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + Tile * tile = is->current_render_tile; + if ((tile == NULL) || (tile == p_null_tile)) + return; + + if ((tile->vtable->m50_Get_Square_BaseType (tile) == SQ_Forest) && + (*tile->vtable->m25_Check_Roads)(tile, __, 0)) { + is->draw_forests_over_roads_on_tile = true; + return; + } + + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, tile_x, tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Map_Renderer_m52_Draw_Roads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + // Don't draw roads if a bridge is here + if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { + Tile * tile = is->current_render_tile; + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * dist = get_district_instance (tile); + if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { + return; + } + } + } + + Map_Renderer_m52_Draw_Roads (this, __, image_index, map_renderer, pixel_x, pixel_y); + + if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) + return; + + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Map_Renderer_m52_Draw_Railroads (Map_Renderer * this, int edx, int image_index, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + // Don't draw railroads if a bridge is here + if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { + Tile * tile = is->current_render_tile; + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * dist = get_district_instance (tile); + if ((dist != NULL) && (dist->district_id == BRIDGE_DISTRICT_ID)) { + return; + } + } + } + + Map_Renderer_m52_Draw_Railroads (this, __, image_index, map_renderer, pixel_x, pixel_y); + + if (! is->current_config.draw_forests_over_roads_and_railroads || ! is->draw_forests_over_roads_on_tile) + return; + + Map_Renderer_m08_Draw_Tile_Forests_Jungle_Swamp (this, __, is->current_render_tile_x, is->current_render_tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Main_Screen_Form_m82_handle_key_event (Main_Screen_Form * this, int edx, int virtual_key_code, int is_down) +{ + char s[200]; + int * last_events = is->last_main_screen_key_up_events; + bool in_game = *p_player_bits != 0; // Player bits all zero indicates we aren't currently in a game. Need to check for this because UI events + // on the main menu also pass through this function. + + if (! is_down) { + for (int n = ARRAY_LEN (is->last_main_screen_key_up_events) - 1; n > 0; n--) + last_events[n] = last_events[n - 1]; + last_events[0] = virtual_key_code; + } + + if (is->current_config.enable_ai_city_location_desirability_display && + (virtual_key_code == VK_L) && is_down && + (! (is_command_button_active (&this->GUI, UCV_Load) || is_command_button_active (&this->GUI, UCV_Unload))) && + in_game) { + int is_debug_mode = (*p_debug_mode_bits & 4) != 0; // This is how the check is done in open_tile_info. Actually there are two debug + // mode bits (4 and 8) and I don't know what the difference is. + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CITY_LOC_HIGHLIGHTS", -1, 0, 0x40, 0); + snprintf (s, sizeof s, " %s", is->c3x_labels[CL_OFF]); + s[(sizeof s) - 1] = '\0'; + PopupSelection_add_item (&popup->selection, __, s, 0); + for (int n = 1; n < 32; n++) + if ((*p_player_bits & (1 << n)) && + (is_debug_mode || (n == p_main_screen_form->Player_CivID))) { + Race * race = &p_bic_data->Races[leaders[n].RaceID]; + snprintf (s, sizeof s, " (%d) %s", n, race->vtable->GetLeaderName (race)); + s[(sizeof s) - 1] = '\0'; + PopupSelection_add_item (&popup->selection, __, s, n); + } + int sel = patch_show_popup (popup, __, 0, 0); + if (sel >= 0) { // -1 indicates popup was closed without making a selection + is->city_loc_display_perspective = (sel >= 1) ? sel : -1; + this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw + } + + } else if (is->current_config.enable_debug_mode_switch && + (in_game && ! is_down) && + (last_events[4] == VK_D) && (last_events[3] == VK_E) && (last_events[2] == VK_B) && (last_events[1] == VK_U) && (last_events[0] == VK_G)) { + PopupForm * popup = get_popup_form (); + if ((*p_debug_mode_bits & 0xC) != 0) { // Consider debug mode on if either bit is set + *p_debug_mode_bits &= ~0xC; + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + PopupForm_add_text (popup, __, "Debug mode deactivated.", 0); + patch_show_popup (popup, __, 0, 0); + } else { + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_DEBUG_ACTIVATION", -1, 0, 0, 0); + int sel = patch_show_popup (popup, __, 0, 0); + if (sel == 0) { + *p_debug_mode_bits |= 0xC; + *(bool *)((int)p_human_player_bits + 37) = true; // Set MegaTrainerXL flag indicating edited save + } + } + this->vtable->m73_call_m22_Draw ((Base_Form *)this); // Trigger map redraw + + // Worker keyboard shortcuts that would normally go to patch_Main_Screen_Form_issue_command + // unfortunately get short-circuited if a district is on a tile and the default popup to replace a "mine" is shown. + // The only way to catch these beforehand I've found it is to intercept the key event here. + } else if (is->current_config.enable_districts && + p_main_screen_form->Current_Unit != NULL && + is_down && + is_worker (p_main_screen_form->Current_Unit)) { + int command = -1; + bool removed_existing = false; + if (virtual_key_code == VK_M && is_command_button_active (&this->GUI, UCV_Build_Mine)) command = UCV_Build_Mine; + else if (virtual_key_code == VK_I && is_command_button_active (&this->GUI, UCV_Irrigate)) command = UCV_Irrigate; + else if (virtual_key_code == VK_N && is_command_button_active (&this->GUI, UCV_Plant_Forest)) command = UCV_Plant_Forest; + + if (handle_worker_command_that_may_replace_district (p_main_screen_form->Current_Unit, command, &removed_existing)) { + Main_Screen_Form_issue_command (this, __, command, p_main_screen_form->Current_Unit); + } + } + +after_district_key_handling: + Main_Screen_Form_m82_handle_key_event (this, __, virtual_key_code, is_down); +} + +int __fastcall +patch_Unit_get_move_points_after_airdrop (Unit * this) +{ + int prev_airdrop_count = itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0); + itable_insert (&is->airdrops_this_turn, this->Body.ID, prev_airdrop_count + 1); + + return is->current_config.dont_end_units_turn_after_airdrop ? this->Body.Moves : patch_Unit_get_max_move_points (this); +} + +int __fastcall +patch_Unit_get_move_points_after_set_to_intercept (Unit * this) +{ + return is->current_config.patch_intercept_lost_turn_bug ? this->Body.Moves : patch_Unit_get_max_move_points (this); +} + +void __cdecl +activate_mod_info_button (int control_id) +{ + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + char s[500]; + char version_letter = 'A' + MOD_VERSION%100; + + if (MOD_PREVIEW_VERSION == 0) + snprintf (s, sizeof s, "%s: %d%c", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' '); + else + snprintf (s, sizeof s, "%s: %d%c%s %d", is->c3x_labels[CL_VERSION], MOD_VERSION/100, MOD_VERSION%100 != 0 ? version_letter : ' ', is->c3x_labels[CL_PREVIEW], MOD_PREVIEW_VERSION); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_CONFIG_FILES_LOADED]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + int n = 1; + for (struct loaded_config_name * lcn = is->loaded_config_names; lcn != NULL; lcn = lcn->next) { + snprintf (s, sizeof s, "^ %d. %s", n, lcn->name); + s[(sizeof s) - 1] = '\0'; + n++; + PopupForm_add_text (popup, __, s, 0); + } + + patch_show_popup (popup, __, 0, 0); +} + +int __fastcall +patch_Parameters_Form_m68_Show_Dialog (Parameters_Form * this, int edx, int param_1, void * param_2, void * param_3) +{ + init_mod_info_button_images (); + + // "b" is the mod info button. It's created each time the preferences form (or "parameters" form as Antal called it) is opened and destroyed + // every time the form is closed. This is the easiest way since it matches how the base game works. At first I tried creating the button once + // but then it will only appear once since its attachment to the prefs form is lost when the form is destroyed on closure. I tried reattaching + // the button to each newly created form but wasn't able to make that work. + Button * b = NULL; + if (is->mod_info_button_images_state == IS_OK) { + b = malloc (sizeof *b); + Button_construct (b); + + Button_initialize (b, __, + is->c3x_labels[CL_MOD_INFO_BUTTON_TEXT], // text + MOD_INFO_BUTTON_ID, // control ID + (p_bic_data->ScreenWidth - 1024) / 2 + 891, // location x + (p_bic_data->ScreenHeight - 768) / 2 + 31, // location y + MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height + (Base_Form *)this, // parent + 0); // ? + + for (int n = 0; n < 3; n++) + b->Images[n] = &is->mod_info_button_images[n]; + PCX_Image_set_font (&b->Base_Data.Canvas, __, get_font (15, FSF_NONE), 0, 0, 0); + b->activation_handler = &activate_mod_info_button; + + // Need to draw once manually or the button won't look right + b->vtable->m73_call_m22_Draw ((Base_Form *)b); + } + + int tr = Parameters_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); + + if (b != NULL) { + b->vtable->destruct ((Base_Form *)b, __, 0); + free (b); + } + + return tr; +} + +bool __fastcall +patch_City_cycle_specialist_type (City * this, int edx, int mouse_x, int mouse_y, Citizen * citizen, City_Form * city_form) +{ + int specialist_count = 0; { + Leader * city_owner = &leaders[this->Body.CivID]; + for (int n = 0; n < p_bic_data->CitizenTypeCount; n++) + specialist_count += (n != p_bic_data->default_citizen_type) && + Leader_has_tech (city_owner, __, p_bic_data->CitizenTypes[n].RequireID); + } + int shift_down = (*p_GetAsyncKeyState) (VK_SHIFT) >> 8; + int original_worker_type = citizen->WorkerType; + + // The return value of this function is not actually used by either of the two original callers. + bool tr = City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); + + // Cycle all the way around back to the previous specialist type, if appropriate. + // If the worker type was not changed after the first call to cycle_specialist_type, that indicates that the player was asked to disable + // governor management and chose not to. Do not try to cycle backwards in that case or else we'll spam the player with more popups. + if (is->current_config.reverse_specialist_order_with_shift && + shift_down && (specialist_count > 2) && (citizen->WorkerType != original_worker_type)) { + for (int n = 0; n < specialist_count - 2; n++) + City_cycle_specialist_type (this, __, mouse_x, mouse_y, citizen, city_form); + } + + return tr; +} + +int __fastcall +patch_City_get_pollution_from_pop (City * this) +{ + if (! is->current_config.enable_negative_pop_pollution) + return City_get_pollution_from_pop (this); + + int base_pollution = this->Body.Population.Size - p_bic_data->General.MaximumSize_City; + if (base_pollution <= 0) + return 0; + + // Consider improvements + int net_pollution = base_pollution; + int any_cleaning_improvs = 0; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * improv = &p_bic_data->Improvements[n]; + if ((improv->ImprovementFlags & ITF_Removes_Population_Pollution) && has_active_building (this, n)) { + any_cleaning_improvs = 1; + if (improv->Pollution < 0) + net_pollution += improv->Pollution; + } + } + + if (net_pollution <= 0) + return 0; + else if (any_cleaning_improvs) + return 1; + else + return net_pollution; +} + +// The original version of this function in the base game contains a duplicate of the logic that computes the total pollution from buildings and +// pop. By re-implementing it to use the get_pollution_from_* functions, we ensure that our changes to get_pollution_from_pop will be accounted for. +// Note: This function is called from two places, one is the city screen and the other I'm not sure about. The pollution spawning logic works by +// calling the get_pollution_from_* funcs directly. +int __fastcall +patch_City_get_total_pollution (City * this) +{ + return City_get_pollution_from_buildings (this) + patch_City_get_pollution_from_pop (this); +} + +void remove_extra_palaces (City * city, City * excluded_destination); + +void +set_wonder_built_flag (int improv_id, bool is_built) +{ + if ((p_match == NULL) || (improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) + return; + + byte * built_flags = *(byte **)((byte *)p_match + 0x4fc); + if (built_flags == NULL) + return; + + built_flags[improv_id] = is_built; +} + +bool +choose_defensive_unit_order (City * city, City_Order * out_order) +{ + if ((city == NULL) || (out_order == NULL)) + return false; + + for (int pass = 0; pass < 3; pass++) { + int best_unit_id = -1; + int best_defence = -1; + + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) { + UnitType * type = &p_bic_data->UnitTypes[n]; + if (! patch_City_can_build_unit (city, __, n, 1, 0, 0)) + continue; + + int defence = type->Defence; + if ((pass < 2) && (defence <= 0)) + continue; + if ((pass <= 1) && (type->Unit_Class != UTC_Land)) + continue; + if ((pass == 0) && ((type->AI_Strategy & UTAI_Defence) == 0)) + continue; + + if (defence > best_defence) { + best_defence = defence; + best_unit_id = n; + } + } + + if (best_unit_id >= 0) { + out_order->OrderType = COT_Unit; + out_order->OrderID = best_unit_id; + return true; + } + } + + return false; +} + +// When a city adds a building that depends on a district, optionally mirror that +// building to all other same-civ cities that can also work the district tile. +void +copy_building_with_cities_in_radius (City * source, int improv_id, int required_district_id, int tile_x, int tile_y) +{ + if (! is->current_config.enable_districts) return; + if (source == NULL) return; + + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + + if (is_wonder) { + if (! is->current_config.cities_with_mutual_district_receive_wonders) + return; + } else if (! is->current_config.cities_with_mutual_district_receive_buildings) + return; + + // If a Wonder, we know the specific tile it is at, so determine which other cities have that in work radius. + if (is_wonder) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile == p_null_tile) return; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != source->Body.CivID) return; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL || inst->district_id != required_district_id) return; + if (! district_is_complete (tile, required_district_id)) return; + + FOR_CITIES_OF (coi, source->Body.CivID) { + City * city = coi.city; + if (city == NULL) continue; + if (city == source) continue; + + if (! city_radius_contains_tile (city, tile_x, tile_y)) + continue; + + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != city->Body.CivID) + continue; + + if (! patch_City_has_improvement (city, __, improv_id, false)) { + City_add_or_remove_improvement (city, __, improv_id, 1, false); + } + } + } + // Else there may be multiple district instances of this type, so check each tile around the city + else { + FOR_DISTRICTS_AROUND (wai, source->Body.X, source->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * tile = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != required_district_id) continue; + + FOR_CITIES_OF (coi, source->Body.CivID) { + City * city = coi.city; + if (city == NULL) continue; + if (city == source) continue; + + if (! city_radius_contains_tile (city, x, y)) + continue; + + if (! patch_City_has_improvement (city, __, improv_id, false)) { + City_add_or_remove_improvement (city, __, improv_id, 1, false); + + // If city already building it, switch to a defensive unit instead + int current_improv_id = city->Body.Order_ID; + if (current_improv_id == improv_id) { + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + // Show message to user + if (is->current_config.show_message_when_building_received_by_mutual_district && + city->Body.CivID == p_main_screen_form->Player_CivID) { + char msg[300]; + snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_RECEIVED], + p_bic_data->Improvements[improv_id].Name.S, + is->c3x_labels[CL_FROM_SHARED], + is->district_configs[required_district_id].name, + is->c3x_labels[CL_WITH], + source->Body.CityName); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + } + } + } + } +} + +void +grant_existing_district_buildings_to_city (City * city) +{ + if (! is->current_config.enable_districts || + (! is->current_config.cities_with_mutual_district_receive_buildings && + ! is->current_config.cities_with_mutual_district_receive_wonders) || + (city == NULL)) + return; + + int civ_id = city->Body.CivID; + int current_improv_id = city->Body.Order_ID; + bool prev_flag = is->sharing_buildings_by_districts_in_progress; + is->sharing_buildings_by_districts_in_progress = true; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + Tile * tile = wai.tile; + + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + struct district_infos * info = &is->district_infos[district_id]; + if (info->dependent_building_count <= 0) + continue; + + FOR_CITIES_OF (coi, civ_id) { + City * other = coi.city; + if ((other == NULL) || (other == city)) + continue; + + if (! city_radius_contains_tile (other, wai.tile_x, wai.tile_y)) + continue; + + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != other->Body.CivID) + continue; + + for (int i = 0; i < info->dependent_building_count; i++) { + int building_id = info->dependent_building_ids[i]; + if (building_id < 0) + continue; + + Improvement * building = &p_bic_data->Improvements[building_id]; + bool is_wonder = (building->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + + if (is_wonder) + continue; + + if (! patch_City_has_improvement (other, __, building_id, false)) + continue; + + if (patch_City_has_improvement (city, __, building_id, false)) + continue; + + City_add_or_remove_improvement (city, __, building_id, 1, false); + + // If city already building it, switch to a defensive unit instead + if (current_improv_id == building_id) { + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + if (is->current_config.show_message_when_building_received_by_mutual_district && + city->Body.CivID == p_main_screen_form->Player_CivID) { + char msg[300]; + snprintf (msg, sizeof msg, "%s %s %s %s %s %s %s", + city->Body.CityName, + is->c3x_labels[CL_RECEIVED], + p_bic_data->Improvements[building_id].Name.S, + is->c3x_labels[CL_FROM_SHARED], + is->district_configs[district_id].name, + is->c3x_labels[CL_WITH], + other->Body.CityName); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + } + } + } + + is->sharing_buildings_by_districts_in_progress = prev_flag; +} + +void +auto_build_great_wall_districts_for_civ (int civ_id) +{ + if ((! is->current_config.enable_districts) || + (! is->current_config.enable_great_wall_districts) || + (! is->current_config.auto_build_great_wall_around_territory) || + (is->great_wall_auto_build == GWABS_DONE) || + (civ_id < 0) || + is->is_placing_scenario_things) + return; + + bool is_human = (*p_human_player_bits & (1 << civ_id)) != 0; + + if ((GREAT_WALL_DISTRICT_ID < 0) || (GREAT_WALL_DISTRICT_ID >= is->district_count)) { + is->great_wall_auto_build = GWABS_DONE; + return; + } + + init_tile_highlights (); + + struct district_config const * cfg = &is->district_configs[GREAT_WALL_DISTRICT_ID]; + if ((cfg->command == -1) || (! leader_can_build_district (&leaders[civ_id], GREAT_WALL_DISTRICT_ID))) { + is->great_wall_auto_build = GWABS_DONE; + return; + } + + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_BEGIN_GREAT_WALL_AUTO_BUILD", -1, 0, 0, 0); + if (civ_id == p_main_screen_form->Player_CivID) + patch_show_popup (popup, __, 0, 0); + + is->great_wall_auto_build = GWABS_RUNNING; + + unsigned int const replaceable_flags = TILE_FLAG_MINE | TILE_FLAG_IRRIGATION; + bool require_other_civ_border = (! is_human) && is->current_config.ai_auto_build_great_wall_strategy == AAGWS_OTHER_CIV_BORDERED_ONLY; + + for (int index = 0; index < p_bic_data->Map.TileCount; index++) { + int x, y; + tile_index_to_coords (&p_bic_data->Map, index, &x, &y); + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->CityID >= 0) + continue; + if (tile->vtable->m35_Check_Is_Water (tile)) + continue; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) + continue; + + bool has_border = false; + bool has_other_civ_border = false; + FOR_TILES_AROUND (tai, 9, x, y) { + if (tai.n == 0) + continue; + Tile * neighbor = tai.tile; + if (neighbor->vtable->m35_Check_Is_Water (neighbor)) + continue; + int owner_id = neighbor->vtable->m38_Get_Territory_OwnerID (neighbor); + if (owner_id != civ_id) { + has_border = true; + if (owner_id > 0) { + has_other_civ_border = true; + break; + } + } + } + if (! has_border) + continue; + if (require_other_civ_border && (! has_other_civ_border)) + continue; + + if (! district_is_buildable_on_tile (cfg, tile)) + continue; + if (! district_resource_prereqs_met (tile, x, y, GREAT_WALL_DISTRICT_ID)) + continue; + + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == GREAT_WALL_DISTRICT_ID)) { + if (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID)) { + inst->state = DS_COMPLETED; + if (! tile->vtable->m18_Check_Mines (tile, __, 0)) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); + set_tile_unworkable_for_all_cities (tile, x, y); + } + continue; + } + + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int replace_flags = overlay_flags & replaceable_flags; + bool has_district = (inst != NULL); + int existing_district_id = -1; + if (has_district) + existing_district_id = inst->district_id; + + if (is_human && civ_id == p_main_screen_form->Player_CivID) { + is->focused_tile = tile; + Main_Screen_Form_bring_tile_into_view (p_main_screen_form, __, x, y, 0, true, false); + + char * popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL"; + set_popup_str_param (0, (char *)is->district_configs[GREAT_WALL_DISTRICT_ID].display_name, -1, -1); + + if (has_district) { + bool redundant_district = district_instance_is_redundant (inst, tile); + bool would_lose_buildings; + would_lose_buildings = any_nearby_city_would_lose_district_benefits (existing_district_id, civ_id, x, y); + if (redundant_district) + would_lose_buildings = false; + if ((existing_district_id >= 0) && (existing_district_id < is->district_count)) { + set_popup_str_param (1, (char *)is->district_configs[existing_district_id].display_name, -1, -1); + } + popup_key = would_lose_buildings + ? "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT" + : "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_DISTRICT_SAFE"; + } else if (replace_flags != 0) { + popup_key = "C3X_CONFIRM_BUILD_GREAT_WALL_OVER_IMPROVEMENT"; + } + + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + popup_key, + -1, 0, 0, 0); + + int sel = patch_show_popup (popup, __, 0, 0); + if (sel != 0) + continue; + } + + if (has_district || (replace_flags != 0)) { + if (has_district) { + int inst_x = x, inst_y = y; + if (! district_instance_get_coords (inst, tile, &inst_x, &inst_y)) + continue; + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, inst_x, inst_y); + handle_district_removed (tile, existing_district_id, inst_x, inst_y, false); + } + + if (replace_flags != 0) + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, replace_flags, x, y); + } + + if (get_district_instance (tile) != NULL) + continue; + + inst = ensure_district_instance (tile, GREAT_WALL_DISTRICT_ID, x, y); + if (inst == NULL) + continue; + + inst->district_id = GREAT_WALL_DISTRICT_ID; + district_instance_set_coords (inst, x, y); + inst->state = DS_COMPLETED; + if (! tile->vtable->m18_Check_Mines (tile, __, 0)) + tile->vtable->m56_Set_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, x, y); + set_tile_unworkable_for_all_cities (tile, x, y); + } + + is->great_wall_auto_build = GWABS_DONE; + is->focused_tile = NULL; +} + +//We need to forwards-declare this +void __fastcall +patch_City_manage_by_governor (City * this, int edx, bool manage_professions); + +void __fastcall +patch_City_add_or_remove_improvement (City * this, int edx, int improv_id, int add, bool param_3) +{ + int init_maintenance = this->Body.Improvements_Maintenance; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + bool is_wonder_removal = (! add) && + ((improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && + (! is->is_placing_scenario_things); + int init_work_area_radius = get_work_ring_limit_total(this); + + // The enable_negative_pop_pollution feature changes the rules so that improvements flagged as removing pop pollution and having a negative + // pollution amount contribute to the city's pop pollution instead of building pollution. Here we make sure that such improvements do not + // contribute to building pollution by temporarily zeroing out their pollution stat when they're added to or removed from a city. + if (is->current_config.enable_negative_pop_pollution && + (improv->ImprovementFlags & ITF_Removes_Population_Pollution) && + (improv->Pollution < 0)) { + int saved_pollution_amount = improv->Pollution; + improv->Pollution = 0; + City_add_or_remove_improvement (this, __, improv_id, add, param_3); + improv->Pollution = saved_pollution_amount; + } else + City_add_or_remove_improvement (this, __, improv_id, add, param_3); + + if (is->current_config.enable_districts && is_wonder_removal && ((improv->Characteristics & ITC_Wonder) != 0)) { + if (is->current_config.destroyed_wonders_can_be_built_again) + set_wonder_built_flag (improv_id, false); + + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, improv->Name.S, -1, -1); + popup->vtable->set_text_key_and_flags ( + popup, __, is->mod_script_path, + is->current_config.destroyed_wonders_can_be_built_again ? "C3X_DISTRICT_WONDER_DESTROYED_REBUILD" : "C3X_DISTRICT_WONDER_DESTROYED", + -1, 0, 0, 0 + ); + patch_show_popup (popup, __, 0, 0); + } + + // If the city just finished a wonder and was using a wonder district for that, set the wonder + // as completed (which switches the art over and prevents the tile from being used again) + int x, y; + if (add && is->current_config.enable_districts && is->current_config.enable_wonder_districts) { + if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { + int matched_windex = find_wonder_config_index_by_improvement_id (improv_id); + + if (matched_windex >= 0) { + FOR_DISTRICTS_AROUND (wai, this->Body.X, this->Body.Y, true) { + x = wai.tile_x; + y = wai.tile_y; + Tile * t = wai.tile; + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + if (! wonder_is_buildable_on_tile (t, improv_id)) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if (info->state != WDS_UNDER_CONSTRUCTION) continue; + if (info->city_id != this->Body.ID) continue; + + // Mark this wonder district as completed with the wonder + info->city = this; + info->city_id = this->Body.ID; + info->state = WDS_COMPLETED; + info->wonder_index = matched_windex; + break; + } + } + } + } + + int gw_auto_build_improv_id = is->current_config.great_wall_auto_build_wonder_improv_id; + if (add && is->current_config.enable_districts && + is->current_config.auto_build_great_wall_around_territory && + (gw_auto_build_improv_id >= 0) && (improv_id == gw_auto_build_improv_id)) + auto_build_great_wall_districts_for_civ (this->Body.CivID); + + //Calculate if work_area has shrunk, and if so, redistribute citizens. + int post_work_area_radius = get_work_ring_limit_total(this); + if (post_work_area_radius < init_work_area_radius) { + patch_City_manage_by_governor(this, __, false); + } + + // Update things in case we've added or removed a mill. This is only necessary while in-game. If the game is still loading the scenario, it + // will recompute resources after it's done and we'll recompute yields and happiness ourselves. + if (! is->is_placing_scenario_things) { + // Collect info about this mill, if in fact the added or removed improvement is a mill. If it's not, all these vars will be left + // false. "generates_input" tracks whether or not the mill generates a resource that's an input for another mill. + bool is_non_local_mill, is_yielding_mill, generates_input; { + is_non_local_mill = is_yielding_mill = generates_input = false; + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if (mill->improv_id == improv_id) { + is_non_local_mill |= (mill->flags & MF_LOCAL) == 0; + is_yielding_mill |= (mill->flags & MF_YIELDS) != 0; + generates_input |= (is->mill_input_resource_bits[mill->resource_id >> 3] & (1 << (mill->resource_id & 7))) != 0; + } + } + } + + // If the mill generates a resource that's added to the trade network or it's generating an input (potentially used locally to + // generate a traded resource) then rebuild the resource network. This is not necessary if the improvement also affects trade routes + // since the base method will have already done this recomputation. + if ((is_non_local_mill || generates_input) && + ((improv->ImprovementFlags & ITF_Allows_Water_Trade) == 0) && + ((improv->ImprovementFlags & ITF_Allows_Air_Trade) == 0) && + ((improv->WonderFlags & ITW_Safe_Sea_Travel) == 0)) + patch_Trade_Net_recompute_resources (is->trade_net, __, 0); + + // If the mill adds yields or might be a link in a resource production chain that does, recompute yields in the city. + if (is_yielding_mill || generates_input) + patch_City_recompute_yields_and_happiness (this); + } + + // Adding or removing an obsolete improvement should not change the total maintenance since obsolete improvs shouldn't cost maintenance. In + // the base game, they usually do since the game doesn't update maintenance costs when buildings are obsoleted, but with that bug patched we + // can enforce the correct behavior. + if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && + (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) + this->Body.Improvements_Maintenance = init_maintenance; + + // If AI MCS is enabled and we've added the Palace to a city, then remove any extra palaces from that city. If we're in the process of + // capturing a city, it's necessary to exclude that city as a possible destination for removed extra palaces. + if ((is->current_config.ai_multi_city_start > 1) && + (! is->is_placing_scenario_things) && + add && (improv->ImprovementFlags & ITF_Center_of_Empire) && + ((*p_human_player_bits & (1 << this->Body.CivID)) == 0)) + remove_extra_palaces (this, is->currently_capturing_city); + + // If sharing wonders in hotseat mode, we must recompute improvement maintenance for all human players when any one of them gains or loses a + // wonder that grants free improvements. + if ((! is->is_placing_scenario_things) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->Body.CivID) & *p_human_player_bits)) { // is this city owned by a human player + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->Body.CivID)) + Leader_recompute_buildings_maintenance (&leaders[n_player]); + player_bits >>= 1; + n_player++; + } + } + + // Optionally share district-dependent buildings or wonders to other cities in range of the same district + bool allow_wonder_sharing = is->current_config.cities_with_mutual_district_receive_wonders; + bool allow_building_sharing = is->current_config.cities_with_mutual_district_receive_buildings; + + if ((! is->is_placing_scenario_things) && add && + is->current_config.enable_districts && (allow_building_sharing || allow_wonder_sharing) && + (! is->sharing_buildings_by_districts_in_progress)) { + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (improv_id); + if (prereq_list != NULL) { + bool is_wonder = (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0; + if ((! is_wonder && allow_building_sharing) || (is_wonder && allow_wonder_sharing)) { + is->sharing_buildings_by_districts_in_progress = true; + for (int i = 0; i < prereq_list->count; i++) { + int district_id = prereq_list->district_ids[i]; + if (district_id < 0) + continue; + copy_building_with_cities_in_radius (this, improv_id, district_id, x, y); + } + is->sharing_buildings_by_districts_in_progress = false; + } + } + } +} + +void __fastcall +patch_Fighter_begin (Fighter * this, int edx, Unit * attacker, int attack_direction, Unit * defender) +{ + Fighter_begin (this, __, attacker, attack_direction, defender); + + // Apply override of retreat eligibility + // Must use this->defender instead of the defender argument since the argument is often NULL, in which case Fighter_begin finds a defender on + // the target tile and stores it in this->defender. Also must check that against NULL since Fighter_begin might fail to find a defender. + enum UnitTypeClasses class = p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID].Unit_Class; + if ((this->defender != NULL) && ((class == UTC_Land) || (class == UTC_Sea))) { + enum retreat_rules retreat_rules = (class == UTC_Land) ? is->current_config.land_retreat_rules : is->current_config.sea_retreat_rules; + if (retreat_rules != RR_STANDARD) { + int attacker_max_mp = patch_Unit_get_max_move_points (this->attacker), + defender_max_mp = patch_Unit_get_max_move_points (this->defender); + + if (retreat_rules == RR_NONE) + this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 0; + else if (retreat_rules == RR_ALL_UNITS) + this->attacker_eligible_to_retreat = this->defender_eligible_to_retreat = 1; + else if (retreat_rules == RR_IF_FASTER) { + this->attacker_eligible_to_retreat = attacker_max_mp > defender_max_mp; + this->defender_eligible_to_retreat = defender_max_mp > attacker_max_mp; + } else if (retreat_rules == RR_IF_NOT_SLOWER) { + this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp; + this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp; + } else if (retreat_rules == RR_IF_FAST_AND_NOT_SLOWER) { + this->attacker_eligible_to_retreat = attacker_max_mp >= defender_max_mp && attacker_max_mp > p_bic_data->General.RoadsMovementRate; + this->defender_eligible_to_retreat = defender_max_mp >= attacker_max_mp && defender_max_mp > p_bic_data->General.RoadsMovementRate; + } + + // Prevent immobile units from retreating + this->attacker_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->attacker->Body.UnitTypeID], __, UTA_Immobile); + this->defender_eligible_to_retreat &= ! UnitType_has_ability (&p_bic_data->UnitTypes[this->defender->Body.UnitTypeID], __, UTA_Immobile); + + // Prevent defender from retreating if in a city + this->defender_eligible_to_retreat &= city_at (this->defender_location_x, this->defender_location_y) == NULL; + } + } +} + +void __fastcall +patch_Unit_despawn (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) +{ + // Determine whether this despawn happened involuntarily, i.e. whether it's because of the actions of a player other than its owner. This + // includes cases where the unit was destroyed in combat, captured, kicked from territory with nowhere to go, etc. + int ret_addr = ((int *)&civ_id_responsible)[-1]; + bool involuntary = + ret_addr == DESPAWN_TO_FIGHT_1_RETURN || ret_addr == DESPAWN_TO_FIGHT_2_RETURN + || ret_addr == DESPAWN_TO_DO_BOMBARD_TILE_RETURN || ret_addr == DESPAWN_TO_CRUISE_MISSILE_DEFENDER_RETURN + || ret_addr == DESPAWN_TO_BOUNCE_TRESPASSING_UNITS_RETURN || ret_addr == DESPAWN_TO_NUKE_DAMAGE_RETURN + || ret_addr == DESPAWN_RECURSIVE_RETURN || ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN + || ret_addr == DESPAWN_TO_TRY_FLYING_OVER_TILE_RETURN; + + int owner_id = this->Body.CivID; + int type_id = this->Body.UnitTypeID; + UnitType * type = &p_bic_data->UnitTypes[type_id]; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + // Clear extra DBs, airdrops, wait records, and transport ties used by this unit + itable_remove (&is->extra_defensive_bombards, this->Body.ID); + itable_remove (&is->airdrops_this_turn, this->Body.ID); + itable_remove (&is->waiting_units, this->Body.ID); + itable_remove (&is->unit_transport_ties, this->Body.ID); + + // If we're despawning the stored ZoC defender, clear that variable so we don't despawn it again in check_life_after_zoc + if (this == is->zoc_defender) + is->zoc_defender = NULL; + + if (this == is->sb_next_up) + is->sb_next_up = NULL; + + if (this == is->last_selected_unit.ptr) + is->last_selected_unit.ptr = NULL; + + // Remove this unit from the list of extra units to despawn after capturing + int original_count = is->count_extra_capture_despawns; + for (int n_src = 0, n_dest = 0; n_src < original_count; n_src++) { + if (is->extra_capture_despawns[n_src] != this) { + is->extra_capture_despawns[n_dest] = is->extra_capture_despawns[n_src]; + n_dest++; + } else + is->count_extra_capture_despawns -= 1; + } + + // If the unit being despawned is a land transport or helicopter, we may have to make sure to despawn its passengers as well because the base + // game won't. In general, the passengers are lost if the transport was despawned involuntarily, i.e. because of another player's attack or + // something like that, or if the passengers couldn't survive outside the transport, specifically because it's a helicopter at sea. + bool must_despawn_passengers = false; { + if (is_land_transport (this)) + must_despawn_passengers = involuntary && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); + + else if (type->Unit_Class == UTC_Air && type->Transport_Capacity > 0) { // if "this" is a helicopter + Unit * container = get_unit_ptr (this->Body.Container_Unit); + bool on_carrier = container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea && + Unit_has_ability (container, __, UTA_Transports_Only_Aircraft); + bool passengers_could_survive = Tile_has_city (tile) || ! tile->vtable->m35_Check_Is_Water (tile); + + // If no-defense-from-inside is off, passengers in helicopters will fight to defend their tile, so they wouldn't be left + // inside the helicopter when their tile is taken. If it's on, an occupied heli can be destroyed or captured by a land unit, + // and we must make sure to despawn the passengers in that case because they can't remain on the tile. Hence, + // no-defense-from-inside implies no-escape in almost all circumstances (nukes are the exception). + enum special_helicopter_rules special_rules = is->current_config.special_helicopter_rules; + if (((special_rules & SHR_ALLOW_ON_CARRIERS) && on_carrier) || (special_rules & (SHR_NO_DEFENSE_FROM_INSIDE | SHR_NO_ESCAPE))) + must_despawn_passengers = involuntary || ! passengers_could_survive; + } + } + + bool prev_always_despawn_passengers = is->always_despawn_passengers; + + if (must_despawn_passengers) { + // If we've been called from do_capture_units, record the passengers in the list of units to be despawned after do_capture_units + // returns. We can't simply despawn the units now even by setting always_despawn_passengers because the despawning messes up an + // iterator over tile units inside do_capture_units. + if (ret_addr == DESPAWN_TO_DO_CAPTURE_UNITS_RETURN) { + FOR_UNITS_ON (uti, tile) + if (uti.unit->Body.Container_Unit == this->Body.ID) { + reserve (sizeof is->extra_capture_despawns[0], // item size + (void **)&is->extra_capture_despawns, // ptr to items + &is->extra_capture_despawns_capacity, // ptr to capacity + is->count_extra_capture_despawns); // count + is->extra_capture_despawns[is->count_extra_capture_despawns] = uti.unit; + is->count_extra_capture_despawns += 1; + } + + } else + is->always_despawn_passengers = true; + } + + Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); + + is->always_despawn_passengers = prev_always_despawn_passengers; + + change_unit_type_count (&leaders[owner_id], type_id, -1); +} + +bool __fastcall +patch_Unit_do_capture_units (Unit * this, int edx, int tile_x, int tile_y, int owner_civ_id) +{ + is->count_extra_capture_despawns = 0; + + bool tr = Unit_do_capture_units (this, __, tile_x, tile_y, owner_civ_id); + + // Here we rely on patch_Unit_despawn to remove despawned units from the list + while (is->count_extra_capture_despawns > 0) + patch_Unit_despawn (is->extra_capture_despawns[0], __, this->Body.ID, 0, 0, 0, 0, 0, 0); + + return tr; +} + +void __fastcall +patch_Map_Renderer_m71_Draw_Tiles (Map_Renderer * this, int edx, int param_1, int param_2, int param_3) +{ + // Restore the tile count if it was saved by recompute_resources. This is necessary because the Draw_Tiles method loops over all tiles. + if (is->saved_tile_count >= 0) { + p_bic_data->Map.TileCount = is->saved_tile_count; + is->saved_tile_count = -1; + } + + Map_Renderer_m71_Draw_Tiles (this, __, param_1, param_2, param_3); +} + +struct named_tile_entry * +get_named_tile_entry (Tile * tile) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return NULL; + int stored_ptr = 0; + if (! itable_look_up (&is->named_tile_map, (int)tile, &stored_ptr)) + return NULL; + return (struct named_tile_entry *)stored_ptr; +} + +bool +prompt_for_named_tile (char const * seed_name, char * out_name, int out_len) +{ + if ((out_name == NULL) || (out_len <= 0)) + return false; + out_name[0] = '\0'; + + PopupForm * popup = get_popup_form (); + if (popup == NULL) + return false; + + char seed_buf[101]; + if (seed_name == NULL) + seed_name = ""; + strncpy (seed_buf, seed_name, sizeof seed_buf); + seed_buf[(sizeof seed_buf) - 1] = '\0'; + if (seed_buf[0] == '\0') + strncpy (seed_buf, "Tile", sizeof seed_buf); + + set_popup_str_param (0, seed_buf, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, script_dot_txt_file_path, "RENAME_CITY", 0x64, (int)seed_buf, 0x44, 0); + int sel = patch_show_popup (popup, __, 0, 0); + is->focused_tile = NULL; + if (sel != 0) + return false; + + if (temp_ui_strs[0][0] == '\0') + return true; + + strncpy (out_name, temp_ui_strs[0], out_len); + out_name[out_len - 1] = '\0'; + return true; +} + +void +handle_named_tile_menu_selection (void) +{ + int tile_x = is->named_tile_menu_tile_x; + int tile_y = is->named_tile_menu_tile_y; + Tile * tile = tile_at (tile_x, tile_y); + if (! tile_can_be_named (tile, tile_x, tile_y)) + return; + + init_tile_highlights (); + + struct named_tile_entry * entry = get_named_tile_entry (tile); + char const * current_name = (entry != NULL) ? entry->name : ""; + char new_name[100]; + is->focused_tile = tile; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + bool got_name = prompt_for_named_tile (current_name, new_name, sizeof new_name); + is->focused_tile = NULL; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + if (! got_name) + return; + + set_named_tile_entry (tile, tile_x, tile_y, new_name); + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +void __fastcall +patch_Main_Screen_Form_handle_right_click_on_tile (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) +{ + if (is->current_config.enable_named_tiles) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile_can_be_named (tile, tile_x, tile_y) && ! Tile_has_city (tile)) { + is->named_tile_menu_active = true; + is->named_tile_menu_tile_x = tile_x; + is->named_tile_menu_tile_y = tile_y; + Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); + is->named_tile_menu_active = false; + return; + } + } + + Main_Screen_Form_handle_right_click_on_tile (this, __, tile_x, tile_y, mouse_x, mouse_y); +} + +void __fastcall +patch_Main_Screen_Form_open_right_click_menu (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int mouse_x, int mouse_y) +{ + bool set_active = false; + if (!is->named_tile_menu_active && is->current_config.enable_named_tiles) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile_can_be_named (tile, tile_x, tile_y)) { + is->named_tile_menu_active = true; + is->named_tile_menu_tile_x = tile_x; + is->named_tile_menu_tile_y = tile_y; + set_active = true; + } + } + Main_Screen_Form_open_right_click_menu (this, __, tile_x, tile_y, mouse_x, mouse_y); + if (set_active) + is->named_tile_menu_active = false; +} + +void +draw_map_tile_text (Main_Screen_Form * this, PCX_Image * canvas, char * text, int screen_x, int screen_y, int base_screen_height, int y_offset) +{ + int is_zoomed_out = (p_bic_data->is_zoomed_out != false); + int scale = is_zoomed_out ? 2 : 1; + int screen_width = 128 / scale; + int screen_height = base_screen_height / scale; + int text_width = screen_width - (is_zoomed_out ? 4 : 8); + if (text_width < 12) + text_width = screen_width; + + int text_left = screen_x + (screen_width - text_width) / 2; + int draw_y = screen_y - y_offset; + int text_top = draw_y + screen_height + (is_zoomed_out ? 2 : 4); + + Object_66C3FC * font = get_font (10, FSF_NONE); + if (font != NULL) { + PCX_Image_set_text_effects (canvas, __, 0x80FFFFFF, 0x80000000, 1, 1); + PCX_Image_draw_centered_text (canvas, __, font, text, text_left, text_top - 10, text_width, strlen (text)); + } +} + +void __fastcall +patch_Main_Screen_Form_draw_city_hud (Main_Screen_Form * this, int edx, PCX_Image * canvas) +{ + Main_Screen_Form_draw_city_hud (this, __, canvas); + + bool draw_natural_wonders = is->current_config.enable_natural_wonders && + is->current_config.show_natural_wonder_name_on_map; + bool draw_named_tiles = is->current_config.enable_named_tiles; + if (!draw_natural_wonders && !draw_named_tiles) + return; + + if (canvas == NULL) + canvas = &this->Base_Data.Canvas; + + if ((canvas == NULL) || (canvas->JGL.Image == NULL)) + return; + + if (draw_natural_wonders) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + + int natural_id = inst->natural_wonder_info.natural_wonder_id; + if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) + continue; + + struct natural_wonder_district_config const * nw_cfg = &is->natural_wonder_configs[natural_id]; + if ((nw_cfg == NULL) || (nw_cfg->name == NULL) || (nw_cfg->name[0] == '\0')) + continue; + + Tile * tile = (Tile *)tei.key; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int tile_x, tile_y; + if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + continue; + + int screen_x, screen_y; + Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); + + draw_map_tile_text (this, canvas, (char *)nw_cfg->name, screen_x, screen_y, 88, 88 - 64); + } + } + + if (draw_named_tiles) { + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if ((entry == NULL) || (entry->name[0] == '\0')) + continue; + + Tile * tile = (Tile *)tei.key; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int tile_x, tile_y; + if (!tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) { + tile_x = entry->tile_x; + tile_y = entry->tile_y; + tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + } + + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) + continue; + + int screen_x, screen_y; + Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, &screen_x, &screen_y); + + draw_map_tile_text (this, canvas, entry->name, screen_x, screen_y, 64, 3); + } + } +} + +// Returns whether or not city has an "extra palace", a concept used by the AI multi-city start. Extra palaces are small wonders that reduce +// corruption (e.g. forbidden palace) that are listed under the ai_multi_start_extra_palaces config option. +bool +has_extra_palace (City * city) +{ + for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { + int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) && + (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && + (leaders[city->Body.CivID].Small_Wonders[improv_id] == city->Body.ID)) { + return true; + } + } + return false; +} + +// Removes any extra palaces from this city to other cities owned by the same player (if possible). Does not check that the city belongs to an AI or +// that AI MCS is enabled. +void +remove_extra_palaces (City * city, City * excluded_destination) +{ + Leader * leader = &leaders[city->Body.CivID]; + int extra_palace_lost; + do { + // Search for an extra palace in the city and delete it. Remember its ID so we can put it elsewhere. + extra_palace_lost = -1; + for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { + int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) && + (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && + (leader->Small_Wonders[improv_id] == city->Body.ID)) { + patch_City_add_or_remove_improvement (city, __, improv_id, 0, false); + extra_palace_lost = improv_id; + break; + } + } + + // Replace the lost extra palace like what happens to the real palace + if (extra_palace_lost >= 0) { + int best_rating = -1; + City * best_location = NULL; + FOR_CITIES_OF (coi, leader->ID) { + City * candidate = coi.city; + if ((candidate != city) && + (candidate->Body.ID != leader->CapitalID) && + (candidate != excluded_destination) && + ! has_extra_palace (candidate)) { + + // Rate this candidate as a possible (extra) palace location. The criteria we use to rate it are identical to + // what the base game uses to find a new location for the palace. + int rating = 0; + rating += candidate->Body.Population.Size; + rating += count_units_at (candidate->Body.X, candidate->Body.Y, UF_4, -1, 0, -1); + rating += 2 * City_count_citizens_of_race (candidate, __, leader->RaceID); + FOR_TILES_AROUND (tai, 0x121, candidate->Body.X, candidate->Body.Y) { + if (tai.n == 0) + continue; + City * neighbor = get_city_ptr (tai.tile->CityID); + if ((neighbor != NULL) && (neighbor != city) && (neighbor->Body.CivID == leader->ID)) { + int size = neighbor->Body.Population.Size; + if (size > p_bic_data->General.MaximumSize_City) rating += 3; + else if (size > p_bic_data->General.MaximumSize_Town) rating += 2; + else rating += 1; + } + } + + if (rating > best_rating) { + best_rating = rating; + best_location = candidate; + } + } + } + + if (best_location != NULL) + City_add_or_remove_improvement (best_location, __, extra_palace_lost, 1, false); + } + } while (extra_palace_lost >= 0); +} + +// Give a city any completed wonder districts in work radius, if cities_with_mutual_district_receive_wonders is true. +// This is essentially for cases where the original Wonder-constructing city is lost and a new city is built +// that can work the same wonder district tile. +void +grant_nearby_wonders_to_city (City * city) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_wonder_districts || + ! is->current_config.cities_with_mutual_district_receive_wonders || + (city == NULL)) + return; + + bool prev_flag = is->sharing_buildings_by_districts_in_progress; + is->sharing_buildings_by_districts_in_progress = true; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int x = wai.tile_x, y = wai.tile_y; + Tile * tile = wai.tile; + + // Make sure Wonder is completed + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) continue; + struct wonder_district_info * info = &inst->wonder_info; + if ((info == NULL) || (info->state != WDS_COMPLETED)) continue; + + // Check that city doesn't already have the Wonder + int improv_id = get_wonder_improvement_id_from_index (info->wonder_index); + if (improv_id < 0) continue; + + if (patch_City_has_improvement (city, __, improv_id, false)) continue; + + // Small wonders use Leader.Small_Wonders as their canonical owner record. If the city + // just changed hands and the new owner already has that small wonder elsewhere, do not + // re-grant it from the nearby district or the capture can recreate a duplicate. + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) != 0) { + City * owning_city = get_city_ptr (leaders[city->Body.CivID].Small_Wonders[improv_id]); + if ((owning_city != NULL) && + (owning_city->Body.CivID == city->Body.CivID) && + ! city_radius_contains_tile (owning_city, x, y)) + continue; + } + + // Add the Wonder to the city + patch_City_add_or_remove_improvement (city, __, improv_id, 1, false); + } + + is->sharing_buildings_by_districts_in_progress = prev_flag; +} + +void +on_gain_city (Leader * leader, City * city, enum city_gain_reason reason) +{ + if (reason == CGR_FOUNDED) + is->turn_no_of_last_founding_for_settler_perfume[leader->ID] = *p_current_turn_no; + + // Handle extra palaces for AI multi-city start + if (((*p_human_player_bits & (1<ID)) == 0) && // If leader is an AI AND + (is->current_config.ai_multi_city_start > 1) && // AI multi-city start is enabled AND + (leader->Cities_Count > 1) && // city is not the only one the AI has (i.e. it's not the capital) AND + (reason != CGR_PLACED_FOR_SCENARIO) && (reason != CGR_PLACED_FOR_AI_MULTI_CITY_START)) { // city was not placed before the game started + + // Find an extra palace that this player does not already have + int free_extra_palace = -1; + for (int n = 0; n < is->current_config.count_ai_multi_start_extra_palaces; n++) { + int improv_id = is->current_config.ai_multi_start_extra_palaces[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) && + (improv->SmallWonderFlags & ITSW_Reduces_Corruption) && + (NULL == get_city_ptr (leader->Small_Wonders[improv_id]))) { + free_extra_palace = improv_id; + break; + } + } + + // Place that extra palace here + if (free_extra_palace >= 0) + City_add_or_remove_improvement (city, __, free_extra_palace, 1, false); + } + + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + patch_City_recompute_yields_and_happiness (city); + patch_City_recompute_culture_income (city); + } + + if (is->current_config.enable_districts) { + + // Remove any district previously on the tile, if city just founded + if (reason == CGR_FOUNDED) { + Tile * city_tile = tile_at (city->Body.X, city->Body.Y); + if ((city_tile != NULL) && (city_tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (city_tile); + if (inst != NULL) + handle_district_removed (city_tile, inst->district_id, city->Body.X, city->Body.Y, false); + } + } + + bool receive_buildings = is->current_config.cities_with_mutual_district_receive_buildings; + bool receive_wonders = is->current_config.cities_with_mutual_district_receive_wonders; + + // Grant buildings and wonders from nearby completed districts owned by other cities of same civ, if enabled + if (receive_buildings) { + grant_existing_district_buildings_to_city (city); + } + + // Grant wonders nearby in same territory, regardless of city (i.e., orphaned wonders from destroyed cities), if enabled + if (receive_wonders) { + grant_nearby_wonders_to_city (city); + } + + if (is->current_config.enable_distribution_hub_districts) { + refresh_distribution_hubs_for_city (city); + } + } +} + +void +on_lose_city (Leader * leader, City * city, enum city_loss_reason reason) +{ + // If leader is an AI and AI MCS is enabled, remove any extra palaces the city has + if (((*p_human_player_bits & (1<ID)) == 0) && + (is->current_config.ai_multi_city_start > 1)) + remove_extra_palaces (city, NULL); + + if (is->current_config.enable_districts) { + if (is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; + + forget_pending_building_order (city); + for (int district_id = 0; district_id < is->district_count; district_id++) + clear_city_district_request (city, district_id); + + if (is->current_config.enable_wonder_districts) + release_wonder_district_reservation (city); + } else if (is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; +} + +// Returns -1 if the location is unusable, 0-9 if it's usable but doesn't satisfy all criteria, and 10 if it couldn't be better +int +eval_starting_location (Map * map, int const * alt_starting_locs, int alt_starting_loc_count, int tile_x, int tile_y, int civ_id) +{ + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != p_null_tile) && + (patch_Map_check_city_location (map, __, tile_x, tile_y, civ_id, true) == CLV_OK) && + (tile->vtable->m15_Check_Goody_Hut (tile, __, 0) == 0) && + (tile->vtable->m40_get_TileUnit_ID (tile) == -1)) { + int tr = 0; + + // Avoid this location if it's too close to another starting location. If it's much too close, it's ruled out entirely. + int closest_dist = INT_MAX; + for (int n = 1; n <= map->Civ_Count; n++) + if (map->Starting_Locations[n] >= 0) { + int other_x, other_y; + tile_index_to_coords (map, map->Starting_Locations[n], &other_x, &other_y); + int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); + if (dist < closest_dist) + closest_dist = dist; + } + for (int n = 0; n < alt_starting_loc_count; n++) + if (alt_starting_locs[n] >= 0) { + int other_x, other_y; + tile_index_to_coords (map, alt_starting_locs[n], &other_x, &other_y); + int dist = Map_get_x_dist (map, __, tile_x, other_x) + Map_get_y_dist (map, __, tile_y, other_y); + if (dist < closest_dist) + closest_dist = dist; + } + if (closest_dist < map->Civ_Distance/3) + return -1; + else if (closest_dist >= 2*map->Civ_Distance/3) + tr += 1; + + // Avoid tiny islands + // tr += map->vtable->m33_Get_Continent (map, __, tile->ContinentID)->Body.TileCount >= 20; + + // Avoid garbage terrain, e.g. all desert or tundra + int break_even_food_tiles = 0; + FOR_TILES_AROUND (tai, 21, tile_x, tile_y) { + if (tai.n == 0) + continue; // Skip tile that would be covered by the city + int tile_food = patch_Map_calc_food_yield_at (map, __, tai.tile_x, tai.tile_y, tai.tile->vtable->m50_Get_Square_BaseType (tai.tile), civ_id, 0, NULL); + int food_required = p_bic_data->General.FoodPerCitizen + (tai.tile->vtable->m35_Check_Is_Water (tai.tile) ? 1 : 0); + break_even_food_tiles += tile_food >= food_required; + } + tr += break_even_food_tiles >= 2; + + // Avoid wasting a food bonus + tr += (tile->ResourceType < 0) || (tile->ResourceType >= p_bic_data->ResourceTypeCount) || + (p_bic_data->ResourceTypes[tile->ResourceType].Food == 0); + + int max_score = 3; + return (10*tr)/max_score; + } else + return -1; +} + +City * +create_starter_city (Map * map, int civ_id, int tile_index) +{ + int x, y; + tile_index_to_coords (map, tile_index, &x, &y); + City * tr = Leader_create_city (&leaders[civ_id], __, x, y, leaders[civ_id].RaceID, -1, NULL, true); + if (tr != NULL) + on_gain_city (&leaders[civ_id], tr, CGR_PLACED_FOR_AI_MULTI_CITY_START); + return tr; +} + +void +set_up_ai_multi_city_start (Map * map, int city_count) +{ + // Set of bits determining which players are eligible for the two-city start + int eligibility_bits = 0, + count_eligible_civs = 0; + for (int n = 1; n < 32; n++) + if ((*p_player_bits & 1<Starting_Locations[n]) != p_null_tile)) { // has a valid starting location + eligibility_bits |= 1 << n; + count_eligible_civs++; + } + + if ((city_count < 1) || (count_eligible_civs == 0)) // if we have nothing to do + return; + + char load_text[50]; + snprintf (load_text, sizeof load_text, "%s...", is->c3x_labels[CL_CREATING_CITIES]); + load_text[(sizeof load_text) - 1] = '\0'; + Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); + + // Generate alternate sets of starting locations. We need one set for each extra city we're going to create per player. Each set only needs to + // include starting locations for eligible players, all others will be left as -1. + int alt_starting_loc_count = 32 * (city_count - 1); + int * alt_starting_locs = malloc (alt_starting_loc_count * sizeof *alt_starting_locs); { + for (int n = 0; n < alt_starting_loc_count; n++) + alt_starting_locs[n] = -1; + + for (int i_loc = 0; i_loc < alt_starting_loc_count; i_loc++) { + int civ_id = i_loc % 32; + if ((civ_id != 0) && (eligibility_bits & 1<current_config.max_tries_to_place_fp_city; try++) { + int i_loc = rand_int (p_rand_object, __, map->TileCount); + int x_loc, y_loc; + tile_index_to_coords (map, i_loc, &x_loc, &y_loc); + if ((x_loc >= 0) && (y_loc >= 0)) { + int val = eval_starting_location (map, alt_starting_locs, alt_starting_loc_count, x_loc, y_loc, civ_id); + if (val >= 10) { + best_loc_index = i_loc; + break; + } else if (val > best_loc_val) { + best_loc_val = val; + best_loc_index = i_loc; + } + } + } + + if (best_loc_index >= 0) + alt_starting_locs[i_loc] = best_loc_index; + } + } + } + + int count_cities_created = 0; + int count_eligible_civs_handled = 0; + for (int civ_id = 1; civ_id < 32; civ_id++) + if (eligibility_bits & 1<Starting_Locations[civ_id]; + + // Create the first starting city for the AI. This one is its capital and is located at its actual starting + // location. Afterward, delete its starting settler so it's as if the settler founded the city. + { + Unit * starting_settler = NULL; + FOR_UNITS_ON (tai, tile_at_index (map, sloc)) { + if (p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].AI_Strategy & UTAI_Settle) { + starting_settler = tai.unit; + break; + } + } + + create_starter_city (map, civ_id, sloc); + count_cities_created++; + + if (starting_settler != NULL) + patch_Unit_despawn (starting_settler, __, 0, 1, 0, 0, 0, 0, 0); + + } + + // Memoize all of the AI's starting units + clear_memo (); + FOR_UNITS_ON (tai, tile_at_index (map, sloc)) + memoize ((int)tai.unit); + + int extra_city_count = 0; + for (int i_city = 1; i_city < city_count; i_city++) { + int loc = alt_starting_locs[(i_city-1)*32 + civ_id]; + City * city; + if ((loc >= 0) && + (NULL != (city = create_starter_city (map, civ_id, loc)))) { + count_cities_created++; + extra_city_count++; + + // Spawn palace substitute in new city + if (extra_city_count-1 < is->current_config.count_ai_multi_start_extra_palaces) + patch_City_add_or_remove_improvement (city, __, is->current_config.ai_multi_start_extra_palaces[extra_city_count - 1], 1, true); + + // Move starting units over to the new city. Do this by moving every Nth unit where N is the number of extra + // cities we've founded so far plus one. ("Extra" cities are the ones created after the capital.) E.g., if + // this is the 1st city after the capital, move every 2nd unit to it. If it's the 2nd, move every 3rd, etc. + for (int n = 0; n < is->memo_len; n++) + if (n % (extra_city_count+1) == extra_city_count) + patch_Unit_move ((Unit *)is->memo[n], __, city->Body.X, city->Body.Y); + + } + } + + // Update progress report + count_eligible_civs_handled++; + int progress = 100 * count_eligible_civs_handled / count_eligible_civs; + snprintf (load_text, sizeof load_text, "%s %d%%", is->c3x_labels[CL_CREATING_CITIES], progress); + load_text[(sizeof load_text) - 1] = '\0'; + Main_GUI_label_loading_bar (&p_main_screen_form->GUI, __, 1, load_text); + + } + + free (alt_starting_locs); + + // Sanity check + int any_adjacent_cities = 0; { + if (p_cities->Cities != NULL) + for (int city_index = 0; (city_index <= p_cities->LastIndex) && ! any_adjacent_cities; city_index++) { + City * city = get_city_ptr (city_index); + if (city != NULL) + FOR_TILES_AROUND (tai, 9, city->Body.X, city->Body.Y) + if ((tai.n > 0) && (NULL != get_city_ptr (tai.tile->vtable->m45_Get_City_ID (tai.tile)))) { + any_adjacent_cities = 1; + break; + } + } + } + int any_missing_fp_cities = (count_cities_created < city_count * count_eligible_civs); + if (any_adjacent_cities || any_missing_fp_cities) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARNING", -1, 0, 0, 0); + char s[100]; + snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_FAILED_SANITY_CHECK]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + if (any_adjacent_cities) { + snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_ADJACENT_CITIES]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + if (any_missing_fp_cities) { + snprintf (s, sizeof s, "^%s", is->c3x_labels[CL_MCS_MISSING_CITIES]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + patch_show_popup (popup, __, 0, 0); + } +} + +void __fastcall +patch_Map_process_after_placing (Map * this, int edx, bool param_1) +{ + if ((is->current_config.ai_multi_city_start > 0) && (*p_current_turn_no == 0)) + set_up_ai_multi_city_start (this, is->current_config.ai_multi_city_start); + + Map_process_after_placing (this, __, param_1); +} + +void __fastcall +patch_Map_impl_generate (Map * this, int edx, int seed, bool is_multiplayer_game, int num_seafaring_civs) +{ + Map_impl_generate (this, __, seed, is_multiplayer_game, num_seafaring_civs); + + if (is->current_config.enable_natural_wonders) + place_natural_wonders_on_map (); +} + +int __fastcall +patch_City_get_net_commerce (City * this, int edx, int kind, bool include_science_age) +{ + int base = City_get_net_commerce (this, __, kind, include_science_age); + + if ((kind == 1) && // beakers, as opposed to 2 which is gold + (is->current_config.ai_research_multiplier != 100) && + ((*p_human_player_bits & 1<Body.CivID) == 0)) + return (base * is->current_config.ai_research_multiplier + 50) / 100; + else + return base; +} + +// Cuts research spending while total expenditures > treasury. Returns whether spending has been cut. +bool +cut_unaffordable_research_spending (Leader * leader, bool skip_popup) +{ + // The rate cap limits AI players' spending on the gold slider (in Leader::ai_adjust_sliders) however it does not apply to human players when + // adjusting sliders manually on the domestic advisor screen. + int gold_rate_cap = ((*p_human_player_bits & 1<ID) != 0) ? 10 : p_bic_data->Governments[leader->GovernmentType].RateCap; + + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + bool reduced_spending = false; + while (leader->science_slider > 0 && + leader->gold_slider < gold_rate_cap && + treasury + Leader_compute_income (leader) < 0) { + leader->science_slider -= 1; + leader->gold_slider += 1; + Leader_recompute_economy (leader); + reduced_spending = true; + } + if (reduced_spending && ! skip_popup && leader->ID == p_main_screen_form->Player_CivID) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_CUT_RESEARCH_SPENDING", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + return reduced_spending; +} + +void __fastcall +adjust_sliders_preproduction (Leader * this) +{ + if ((*p_human_player_bits & 1<ID) == 0) { + // Replicate the behavior of the original code for AI players. (apply_machine_code_edits overwrites an equivalent branch & call in the + // original code with a call to this method.) + this->vtable->ai_adjust_sliders (this); + + // If aggressively penalize bankruptcy is on, cut the AI's research spending if it can't afford it. This may be redundant as + // ai_adjust_sliders will already cut AI spending but maybe not all the way to zero. Do this only every third turn so the AI is not + // completely prevented from researching. + if (is->current_config.aggressively_penalize_bankruptcy && (*p_current_turn_no + this->ID) % 3 == 0) + cut_unaffordable_research_spending (this, true); + + // If human player would go bankrupt, try reducing their research spending to avoid that + } else if (is->current_config.cut_research_spending_to_avoid_bankruptcy) + cut_unaffordable_research_spending (this, false); +} + +int __fastcall +patch_City_get_improvement_maintenance (City * this, int edx, int improv_id) +{ + // Check if this improvment is provided for free by another player via shared wonder effects + int civ_id = this->Body.CivID; + bool free_from_sharing = false; + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << civ_id) & *p_human_player_bits)) { // is this city owned by a human player + + // Check if any other human player in the game has this improv in their auto improvs table, including for this city's continent + bool has_free_improv = false; + Tile * city_tile = tile_at (this->Body.X, this->Body.Y); + int continent_id = city_tile->vtable->m46_Get_ContinentID (city_tile); + int cont_coded_key = (continent_id + 1) * p_bic_data->ImprovementsCount + improv_id;; + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != civ_id)) + if (Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, improv_id , NULL) || + Hash_Table_look_up (&leaders[n_player].Auto_Improvements, __, cont_coded_key, NULL)) { + free_from_sharing = true; + break; + } + player_bits >>= 1; + n_player++; + } + } + + if (! free_from_sharing) + return City_get_improvement_maintenance (this, __, improv_id); + else + return 0; +} + +int __fastcall +patch_Leader_count_maintenance_free_units (Leader * this) +{ + if ((is->current_config.extra_unit_maintenance_per_shields <= 0) && (this->ID != 0)) + return Leader_count_maintenance_free_units (this); + else { + int tr = 0; + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if ((unit != NULL) && (unit->Body.CivID == this->ID)) { + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + + // If this is a free unit + if ((unit->Body.RaceID != this->RaceID) || (type->requires_support == 0)) + tr++; + + // If this unit belongs to the barbs and has a tribe ID set (indicating it was spawned in a barb camp) then count it + // as a free unit in order not to bankrupt the barb player if the barb player controls any cities. A tribe ID of 75 is + // the generic ID that's assigned to barb units when they're spawned with no specific tribe ID. + else if ((unit->Body.CivID == 0) && (unit->Body.barb_tribe_id >= 0) && (unit->Body.barb_tribe_id < 75)) + tr++; + + // Otherwise, if we're configured to apply extra maintenance based on shield cost, reduce the free unit count by + // however many times this unit's cost is above the threshold for extra maintenace. It's alright if the resulting free + // unit count is negative since all callers of this function subtract its return value from the total unit count to + // obtain the count of units that must be paid for. + else if (is->current_config.extra_unit_maintenance_per_shields > 0) + tr -= type->Cost / is->current_config.extra_unit_maintenance_per_shields; + } + } + return tr; + } +} + +int __fastcall +patch_Leader_sum_unit_maintenance (Leader * this, int edx, int government_id) +{ + if (is->current_config.extra_unit_maintenance_per_shields <= 0) + return Leader_sum_unit_maintenance (this, __, government_id); + else if (this->Cities_Count > 0) { + int maint_free_count = patch_Leader_count_maintenance_free_units (this); + int cost_per_unit, base_free_count; + get_unit_support_info (this->ID, government_id, &cost_per_unit, &base_free_count); + int ai_free_count; { + if (*p_human_player_bits & 1<ID) + ai_free_count = 0; + else { + Difficulty_Level * difficulty = &p_bic_data->DifficultyLevels[*p_game_difficulty]; + ai_free_count = difficulty->Bonus_For_Each_City * this->Cities_Count + difficulty->Additional_Free_Support; + } + } + return not_below (0, (this->Unit_Count - base_free_count - ai_free_count - maint_free_count) * cost_per_unit); + } else + return 0; +} + +int +sum_improvements_maintenance_to_pay (Leader * leader, int govt_id) +{ + if (is->current_config.aggressively_penalize_bankruptcy) + // We're going to replace the logic that charges maintenance, and the replacement will charge both unit & building maintenance b/c + // they're intertwined under the new rules. Return zero here so the base game code doesn't charge any building maintenance on its own. + return 0; + else + return Leader_sum_improvements_maintenance (leader, __, govt_id); +} + +// The sum_improvements_maintenance function is called in two places as part of the randomization of whether improv or unit maintenance gets paid +// first. Redirect both of these calls to one function of our own. +int __fastcall patch_Leader_sum_improv_maintenance_to_pay_1 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } +int __fastcall patch_Leader_sum_improv_maintenance_to_pay_2 (Leader * this, int edx, int govt_id) { return sum_improvements_maintenance_to_pay (this, govt_id); } + +int +compare_buildings_to_sell (void const * a, void const * b) +{ + int maint_a = (*(int const *)a >> 26) & 31, + maint_b = (*(int const *)b >> 26) & 31; + return maint_b - maint_a; +} + +// Returns the final improv cost after buildings were sold +int +sell_unaffordable_buildings (Leader * leader, int improv_cost, int unit_cost) +{ + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + + clear_memo (); + + // Memoize all buildings this player owns that we might potentially sell. B/c the memo can only contain ints, we must pack the maintenance + // cost, improv ID, and city ID all into one int. The city ID is stored in the lowest 13 bits, then the improv ID in the next 13, and finally + // the maintenance amount in the 5 above those. + FOR_CITIES_OF (coi, leader->ID) + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * improv = &p_bic_data->Improvements[n]; + + int unsellable_flags = + ITF_Center_of_Empire | + ITF_50_Luxury_Output | + ITF_50_Tax_Output | + ITF_Reduces_Corruption | + ITF_Increases_Luxury_Trade | + ITF_Allows_City_Level_2 | + ITF_Allows_City_Level_3 | + ITF_Capitalization | + ITF_Allows_Water_Trade | + ITF_Allows_Air_Trade | + ITF_Increases_Shields_In_Water | + ITF_Increases_Food_In_Water | + ITF_Increases_Trade_In_Water; + + // Only sell improvements that aren't contributing gold, even indirectly through e.g. happiness or boosting shield production + // for Wealth + bool sellable = + ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) == 0) && + ((improv->ImprovementFlags & unsellable_flags) == 0) && + (improv->Happy_Faces_All <= 0) && (improv->Happy_Faces <= 0) && + (improv->Production <= 0); + + if (sellable && patch_City_has_improvement (coi.city, __, n, 0)) { + int maint = patch_City_get_improvement_maintenance (coi.city, __, n); + if (maint > 0) + memoize ((not_above (31, maint) << 26) | (n << 13) | coi.city_id); + } + } + + // Sort the list of buildings so the highest maintenance ones come first + qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_buildings_to_sell); + + // Sell buildings until we can cover maintenance costs or until we run out of ones to sell + int count_sold = 0; + while ((improv_cost + unit_cost > treasury) && (count_sold < is->memo_len)) { + int improv_id = ((1<<13) - 1) & (is->memo[count_sold] >> 13), + city_id = ((1<<13) - 1) & is->memo[count_sold]; + City * city = get_city_ptr (city_id); + improv_cost -= patch_City_get_improvement_maintenance (city, __, improv_id); + City_sell_improvement (city, __, improv_id, false); + treasury = leader->Gold_Encoded + leader->Gold_Decrement; + count_sold++; + } + + // Show popup informing the player that their buildings were force sold + if ((leader->ID == p_main_screen_form->Player_CivID) && ! is_online_game ()) { + PopupForm * popup = get_popup_form (); + if (count_sold == 1) { + int improv_id = ((1<<13) - 1) & (is->memo[0] >> 13), + city_id = ((1<<13) - 1) & is->memo[0]; + set_popup_str_param (0, get_city_ptr (city_id)->Body.CityName , -1, -1); + set_popup_str_param (1, p_bic_data->Improvements[improv_id].Name.S, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_SINGLE_IMPROV", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } else if (count_sold > 1) { + set_popup_int_param (0, count_sold); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_SOLD_MULTIPLE_IMPROVS", -1, 0, 0, 0); + + // Add list of sold improvements to popup + for (int n = 0; n < count_sold; n++) { + int improv_id = ((1<<13) - 1) & (is->memo[n] >> 13), + city_id = ((1<<13) - 1) & is->memo[n]; + char s[200]; + snprintf (s, sizeof s, "^ %s in %s", + p_bic_data->Improvements[improv_id].Name.S, + get_city_ptr (city_id)->Body.CityName); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + + patch_show_popup (popup, __, 0, 0); + } + } + + return improv_cost; +} + +// Returns the final unit cost after disbanding +int +disband_unaffordable_units (Leader * leader, int improv_cost, int unit_cost, int cost_per_unit) +{ + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + int count_disbanded = 0; + Unit * to_disband; + char first_disbanded_name[32]; + while ((improv_cost + unit_cost > treasury) && + (unit_cost > 0) && + (NULL != (to_disband = leader->vtable->find_unsupported_unit (leader)))) { + if (count_disbanded == 0) { + char const * name_src = (to_disband->Body.Custom_Name.S[0] == '\0') + ? p_bic_data->UnitTypes[to_disband->Body.UnitTypeID].Name + : to_disband->Body.Custom_Name.S; + strncpy (first_disbanded_name, name_src, sizeof first_disbanded_name); + first_disbanded_name[(sizeof first_disbanded_name) - 1] = '\0'; + } + Unit_disband (to_disband); + count_disbanded++; + unit_cost -= cost_per_unit; + } + + // Show popup informing the player that their units were disbanded + if (leader->ID == p_main_screen_form->Player_CivID) { + PopupForm * popup = get_popup_form (); + if (count_disbanded == 1) { + set_popup_str_param (0, first_disbanded_name, -1, -1); + int online_flag = is_online_game () ? 0x4000 : 0; + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_SINGLE_UNIT", -1, 0, online_flag, 0); + patch_show_popup (popup, __, 0, 0); + } else if ((count_disbanded > 1) && ! is_online_game ()) { + set_popup_int_param (0, count_disbanded); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_DISBANDED_MULTIPLE_UNITS", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + } + + return unit_cost; +} + +int +compare_cities_by_production (void const * vp_id_a, void const * vp_id_b) +{ + City * a = get_city_ptr (*(int const *)vp_id_a), + * b = get_city_ptr (*(int const *)vp_id_b); + return a->Body.ProductionIncome - b->Body.ProductionIncome; +} + +void +charge_maintenance_with_aggressive_penalties (Leader * leader) +{ + int cost_per_unit; + get_unit_support_info (leader->ID, leader->GovernmentType, &cost_per_unit, NULL); + + int improv_cost = Leader_sum_improvements_maintenance (leader, __, leader->GovernmentType); + + int unit_cost = 0; { + if (leader->Cities_Count > 0) // Players with no cities don't pay unit maintenance, per the original game rules + if (cost_per_unit > 0) { + int count_free_units = Leader_get_free_unit_count (leader, __, leader->GovernmentType) + patch_Leader_count_maintenance_free_units (leader); + unit_cost += not_below (0, (leader->Unit_Count - count_free_units) * cost_per_unit); + } + } + + int treasury = leader->Gold_Encoded + leader->Gold_Decrement; + if (improv_cost + unit_cost > treasury) { + + // For AIs, alternate between selling buildings and disbanding units when maintenance can't be paid + if (((1<ID & *p_human_player_bits) != 0) || ((leader->ID + *p_current_turn_no) % 2 == 0)) { + improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); + unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); + } else { + unit_cost = disband_unaffordable_units (leader, improv_cost, unit_cost, cost_per_unit); + improv_cost = sell_unaffordable_buildings (leader, improv_cost, unit_cost); + } + + treasury = leader->Gold_Encoded + leader->Gold_Decrement; // Update b/c selling buildings recovers some gold + + // If the player still can't afford maintenance, even after all that, start switching their cities to Wealth + int wealth_income = 0; + if (improv_cost + unit_cost > treasury + wealth_income) { + // Memoize all cities not already building wealth and sort by production (lowest first) + clear_memo (); + FOR_CITIES_OF (coi, leader->ID) + if ((coi.city->Body.Status & CSF_Capitalization) == 0) + memoize (coi.city_id); + qsort (is->memo, is->memo_len, sizeof is->memo[0], compare_cities_by_production); + + int wealth_improv_id = -1; { + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { + wealth_improv_id = n; + break; + } + } + + if (wealth_improv_id >= 0) { + int n = 0, + switched_any = 0; + + while ((n < is->memo_len) && (improv_cost + unit_cost > treasury + wealth_income)) { + City * city = get_city_ptr (is->memo[n]); + City_set_production (city, __, COT_Improvement, wealth_improv_id, false); + switched_any = 1; + wealth_income += City_get_income_from_wealth_build (city); + n++; + } + + if (switched_any && (leader->ID == p_main_screen_form->Player_CivID)) { + PopupForm * popup = get_popup_form (); + Improvement * wealth = &p_bic_data->Improvements[wealth_improv_id]; + set_popup_str_param (0, wealth->Name.S, -1, -1); + set_popup_str_param (1, wealth->CivilopediaEntry.S, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_FORCE_BUILD_WEALTH", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + } + } + } + + Leader_set_treasury (leader, __, treasury - improv_cost - unit_cost); +} + +bool __fastcall +patch_Unit_has_king_ability_for_find_unsupported (Unit * this, int edx, enum UnitTypeAbilities king_ability) +{ + // If we're set to aggressively penalize bankruptcy and this unit doesn't require support, return that it is a king so it doesn't get + // disbanded. + if (is->current_config.aggressively_penalize_bankruptcy && ! p_bic_data->UnitTypes[this->Body.UnitTypeID].requires_support) + return true; + + else + return Unit_has_ability (this, __, king_ability); +} + +void __fastcall +patch_Leader_pay_unit_maintenance (Leader * this) +{ + if (! is->current_config.aggressively_penalize_bankruptcy) + Leader_pay_unit_maintenance (this); + else + charge_maintenance_with_aggressive_penalties (this); +} + +void __fastcall +patch_Main_Screen_Form_show_wltk_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) +{ + patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); +} + +void __fastcall +patch_Main_Screen_Form_show_wltk_ended_message (Main_Screen_Form * this, int edx, int tile_x, int tile_y, char * text_key, bool pause) +{ + patch_Main_Screen_Form_show_map_message (this, __, tile_x, tile_y, text_key, is->current_config.dont_pause_for_love_the_king_messages ? false : pause); +} + +char __fastcall +patch_Tile_has_city_for_agri_penalty_exception (Tile * this) +{ + return is->current_config.no_penalty_exception_for_agri_fresh_water_city_tiles ? 0 : Tile_has_city (this); +} + +int +show_razing_popup (void * popup_object, int popup_param_1, int popup_param_2, int razing_option) +{ + int response = patch_show_popup (popup_object, __, popup_param_1, popup_param_2); + if (is->current_config.prevent_razing_by_players && (response == razing_option)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_RAZE", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + return 0; + } + return response; +} + +int __fastcall patch_show_popup_option_1_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 1); } +int __fastcall patch_show_popup_option_2_razes (void *this, int edx, int param_1, int param_2) { return show_razing_popup (this, param_1, param_2, 2); } + +int __fastcall +patch_Context_Menu_add_abandon_city (Context_Menu * this, int edx, int item_id, char * text, bool checkbox, Sprite * image) +{ + if (is->current_config.prevent_razing_by_players) + return 0; // Return value is ignored by the caller + else + return Context_Menu_add_item (this, __, item_id, text, checkbox, image); +} + +char * +check_pedia_upgrades_to_ptr (TextBuffer * this, char * str) +{ + Civilopedia_Form * pedia = p_civilopedia_form; + UnitType * unit_type = NULL; + if (is->current_config.indicate_non_upgradability_in_pedia && + (pedia->Current_Article_ID >= 0) && (pedia->Current_Article_ID <= pedia->Max_Article_ID) && + (NULL != (unit_type = pedia->Articles[pedia->Current_Article_ID]->unit_type)) && + ((unit_type->Special_Actions & UCV_Upgrade_Unit) == 0)) + return is->c3x_labels[CL_OBSOLETED_BY]; + else + return TextBuffer_check_ptr (this, __, str); +} + +char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_1 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } +char * __fastcall patch_TextBuffer_check_pedia_upgrades_to_ptr_2 (TextBuffer * this, int edx, char * str) { return check_pedia_upgrades_to_ptr (this, str); } + +bool __fastcall +patch_Unit_select_stealth_attack_target (Unit * this, int edx, int target_civ_id, int x, int y, bool allow_popup, Unit ** out_selected_target) +{ + is->added_any_stealth_target = 0; + return Unit_select_stealth_attack_target (this, __, target_civ_id, x, y, allow_popup, out_selected_target); +} + +bool __fastcall +patch_Unit_can_stealth_attack (Unit * this, int edx, Unit * target) +{ + bool tr = Unit_can_stealth_attack (this, __, target); + + // If we're selecting a target for stealth attack via bombardment, we must filter out candidates we can't damage that way + if (tr && is->selecting_stealth_target_for_bombard && + ! can_damage_bombarding (&p_bic_data->UnitTypes[this->Body.UnitTypeID], target, tile_at (target->Body.X, target->Body.Y))) + return false; + + else if (tr && is->current_config.exclude_invisible_units_from_stealth_attack && ! patch_Unit_is_visible_to_civ (target, __, this->Body.CivID, 1)) + return false; + + else if (tr && is->current_config.exclude_passengers_from_stealth_attack && get_unit_ptr (target->Body.Container_Unit) != NULL) + return false; + + else + return tr; +} + +int __fastcall +patch_Tile_check_water_for_stealth_attack (Tile * this) +{ + // When stealth attack bombard is enabled, remove a special rule inside can_stealth_attack that prevents land units from stealth attacking + // onto sea tiles. This allows land artillery to stealth attack naval units. + return is->current_config.enable_stealth_attack_via_bombardment ? 0 : this->vtable->m35_Check_Is_Water (this); +} + +int __fastcall +patch_PopupSelection_add_stealth_attack_target (PopupSelection * this, int edx, char * text, int value) +{ + if (is->current_config.include_stealth_attack_cancel_option && (! is->added_any_stealth_target)) { + PopupSelection_add_item (this, __, is->c3x_labels[CL_NO_STEALTH_ATTACK], -1); + is->added_any_stealth_target = 1; + } + + Unit * unit; + if (is->current_config.show_hp_of_stealth_attack_options && + ((unit = get_unit_ptr (value)) != NULL)) { + char s[500]; + int max_hp = Unit_get_max_hp (unit); + snprintf (s, sizeof s, "(%d/%d) %s", max_hp - unit->Body.Damage, max_hp, text); + s[(sizeof s) - 1] = '\0'; + return PopupSelection_add_item (this, __, s, value); + } else + return PopupSelection_add_item (this, __, text, value); +} + +void __fastcall +patch_Unit_perform_air_recon (Unit * this, int edx, int x, int y) +{ + int moves_plus_one = this->Body.Moves + p_bic_data->General.RoadsMovementRate; + + bool was_intercepted = false; + if (is->current_config.intercept_recon_missions) { + // Temporarily add vision on the target tile so the game plays the animation if the unit is show down by ground AA + Tile_Body * tile = &tile_at (x, y)->Body; + int saved_vis = tile->Visibility; + tile->Visibility |= 1 << this->Body.CivID; + was_intercepted = Unit_try_flying_over_tile (this, __, x, y); + tile->Visibility = saved_vis; + } + + if (! was_intercepted) { + Unit_perform_air_recon (this, __, x, y); + if (is->current_config.charge_one_move_for_recon_and_interception) + this->Body.Moves = moves_plus_one; + } +} + +int __fastcall +patch_Unit_get_interceptor_max_moves (Unit * this) +{ + // Stop fighters from intercepting multiple times per turn without blitz + if (is->current_config.charge_one_move_for_recon_and_interception && + (this->Body.Status & USF_USED_ATTACK != 0) && ! UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Blitz)) + return 0; + + else + return patch_Unit_get_max_move_points (this); +} + +int __fastcall +patch_Unit_get_moves_after_interception (Unit * this) +{ + if (is->current_config.charge_one_move_for_recon_and_interception) { + this->Body.Status |= USF_USED_ATTACK; // Set status bit indicating that the interceptor has attacked this turn + return this->Body.Moves + p_bic_data->General.RoadsMovementRate; + } else + return patch_Unit_get_max_move_points (this); +} + +void __fastcall +patch_Unit_set_state_after_interception (Unit * this, int edx, int new_state) +{ + if (! is->current_config.charge_one_move_for_recon_and_interception) + Unit_set_state (this, __, new_state); + + // If fighters are supposed to be able to intercept multiple times per turn, then we can't knock them out of the interception state as soon as + // they intercept something like in the base game. Instead, record this interception event so that we can clear their state at the start of + // their next turn. + else { + struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->Body.CivID]; + reserve (sizeof irl->items[0], (void **)&irl->items, &irl->capacity, irl->count); + irl->items[irl->count++] = (struct interception) { + .unit_id = this->Body.ID, + .x = this->Body.X, + .y = this->Body.Y + }; + } +} + +// Goes through every entry in a table with unit IDs as keys and filters out any that belong to the given owner (or are invalid). +void +remove_unit_id_entries_owned_by (struct table * t, int owner_id) +{ + if (t->len > 0) { + clear_memo (); + FOR_TABLE_ENTRIES (tei, t) { + Unit * unit = get_unit_ptr (tei.key); + if ((unit == NULL) || (unit->Body.CivID == owner_id)) + memoize (tei.key); + } + for (int n = 0; n < is->memo_len; n++) + itable_remove (t, is->memo[n]); + } +} + +void __fastcall +patch_Leader_begin_turn (Leader * this) +{ + if (is->aerodrome_airlift_usage.len > 0) { + int civ_bit = 1 << this->ID; + clear_memo (); + FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { + int mask = tei.value; + if (mask & civ_bit) { + int new_mask = mask & ~civ_bit; + memoize (tei.key); + memoize (new_mask); + } + } + for (int n = 0; n < is->memo_len; n += 2) { + int key = is->memo[n]; + int new_mask = is->memo[n + 1]; + if (new_mask == 0) + itable_remove (&is->aerodrome_airlift_usage, key); + else + itable_insert (&is->aerodrome_airlift_usage, key, new_mask); + } + clear_memo (); + } + + // Eject trespassers + is->do_not_bounce_invisible_units = true; + if (is->current_config.disallow_trespassing && (*p_current_turn_no > 0)) + for (int n = 1; n < 32; n++) + if ((*p_player_bits & (1 << n)) && + (n != this->ID) && + (! this->At_War[n]) && + ((this->Relation_Treaties[n] & 2) == 0)) // Check right of passage + Leader_bounce_trespassing_units (&leaders[n], __, this->ID); + is->do_not_bounce_invisible_units = false; + + if (is->current_config.introduce_all_human_players_at_start_of_hotseat_game && + (*p_current_turn_no == 0) && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((*p_human_player_bits & (1 << this->ID)) != 0)) + for (int n = 0; n < 32; n++) + if (*p_human_player_bits & (1 << n)) + Leader_make_contact (this, __, n, false); + + Leader_begin_turn (this); +} + +void __fastcall +patch_Leader_begin_unit_turns (Leader * this) +{ + // Reset the states of all fighters that performed an interception on the previous turn. + struct interceptor_reset_list * irl = &is->interceptor_reset_lists[this->ID]; + for (int n = 0; n < irl->count; n++) { + struct interception * record = &irl->items[n]; + Unit * interceptor = get_unit_ptr (record->unit_id); + if ((interceptor != NULL) && + (interceptor->Body.CivID == this->ID) && + (interceptor->Body.X == record->x) && + (interceptor->Body.Y == record->y) && + (interceptor->Body.UnitState == UnitState_Intercept)) + Unit_set_state (interceptor, __, 0); + } + irl->count = 0; + + // Reset extra defensive bombard and airdrop counters + remove_unit_id_entries_owned_by (&is->extra_defensive_bombards, this->ID); + remove_unit_id_entries_owned_by (&is->airdrops_this_turn , this->ID); + remove_unit_id_entries_owned_by (&is->unit_transport_ties , this->ID); + + clear_memo (); + if (is->current_config.delete_off_map_ai_units && + ((*p_human_player_bits & (1 << this->ID)) == 0) && + (p_units->Units != NULL)) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit_Body * body = p_units->Units[n].Unit; + if ((body != NULL) && + ((int)body != offsetof (Unit, Body)) && + (body->CivID == this->ID) && + ! Map_in_range (&p_bic_data->Map, __, body->X, body->Y)) + memoize (body->ID); + } + for (int n = 0; n < is->memo_len; n++) + patch_Unit_despawn (get_unit_ptr (is->memo[n]), __, 0, 1, 0, 0, 0, 0, 0); + + Leader_begin_unit_turns (this); +} + +Unit * __fastcall +patch_Fighter_find_actual_bombard_defender (Fighter * this, int edx, Unit * bombarder, int tile_x, int tile_y, int bombarder_civ_id, bool land_lethal, bool sea_lethal) +{ + if (is->bombard_stealth_target == NULL) + return Fighter_find_defender_against_bombardment (this, __, bombarder, tile_x, tile_y, bombarder_civ_id, land_lethal, sea_lethal); + else + return is->bombard_stealth_target; +} + +Unit * +select_stealth_attack_bombard_target (Unit * unit, int tile_x, int tile_y) +{ + bool land_lethal = Unit_has_ability (unit, __, UTA_Lethal_Land_Bombardment), + sea_lethal = Unit_has_ability (unit, __, UTA_Lethal_Sea_Bombardment); + Unit * defender = Fighter_find_defender_against_bombardment (&p_bic_data->fighter, __, unit, tile_x, tile_y, unit->Body.CivID, land_lethal, sea_lethal); + if (defender != NULL) { + Unit * target; + is->selecting_stealth_target_for_bombard = 1; + bool got_one = patch_Unit_select_stealth_attack_target (unit, __, defender->Body.CivID, tile_x, tile_y, true, &target); + is->selecting_stealth_target_for_bombard = 0; + return got_one ? target : NULL; + } else + return NULL; +} + +bool __fastcall +patch_Unit_try_flying_for_precision_strike (Unit * this, int edx, int x, int y) +{ + bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); + if (is->current_config.polish_precision_striking && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) && + ! is_cruise_missile) + // This method returns -1 when some kind of error occurs. In that case, return true implying the unit was shot down so the caller + // doesn't do anything more. Otherwise, return false so it goes ahead and applies damage. + return Unit_play_bombard_fire_animation (this, __, x, y) == -1; + + else if (is->current_config.polish_precision_striking && is_cruise_missile) { + Unit_animate_cruise_missile_strike (this, __, x, y); + return false; + + } else + return Unit_try_flying_over_tile (this, __, x, y); +} + +void __fastcall +patch_Unit_play_bombing_anim_for_precision_strike (Unit * this, int edx, int x, int y) +{ + // Only play the bombing animation here if we haven't already played an animation in the above method. We don't want to play all animations + // here since the bombard fire animation can fail for whatever reason but this method can't handle failure. + bool is_cruise_missile = UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile); + if ((! is->current_config.polish_precision_striking) || + ((p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && ! is_cruise_missile)) + Unit_play_bombing_animation (this, __, x, y); +} + +int __fastcall +patch_Unit_play_anim_for_bombard_tile (Unit * this, int edx, int x, int y) +{ + Unit * stealth_attack_target = NULL; + if (((p_bic_data->UnitTypes[this->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && + is->current_config.enable_stealth_attack_via_bombardment && + (! is_online_game ()) && + patch_Leader_is_tile_visible (&leaders[this->Body.CivID], __, x, y)) + is->bombard_stealth_target = select_stealth_attack_bombard_target (this, x, y); + + return Unit_play_bombard_fire_animation (this, __, x, y); +} + +void __fastcall +patch_Main_Screen_Form_issue_precision_strike_cmd (Main_Screen_Form * this, int edx, Unit * unit) +{ + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + if ((! is->current_config.polish_precision_striking) || (type->Unit_Class == UTC_Air)) + Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); + else { + // issue_precision_strike_cmd will use the unit type's operational range. To make it use bombard range instead, place that value in + // the operational range field temporarily. Conveniently, it's only necessary to do this temporary switch once, here, because the main + // screen form stores a copy of the range for its own use and the method to actually perform the strike doesn't check the range. + int saved_op_range = type->OperationalRange; + type->OperationalRange = type->Bombard_Range; + Main_Screen_Form_issue_precision_strike_cmd (this, __, unit); + type->OperationalRange = saved_op_range; + } +} + +int __fastcall +patch_Map_compute_neighbor_index_for_cm_strike (Map * this, int edx, int x_home, int y_home, int x_neigh, int y_neigh, int lim) +{ + int tr = Map_compute_neighbor_index (this, __, x_home, y_home, x_neigh, y_neigh, lim); + + if ((tr >= 0) && + (is->bombarding_unit != NULL) && + ((p_bic_data->UnitTypes[is->bombarding_unit->Body.UnitTypeID].Special_Actions & UCV_Stealth_Attack) != 0) && + is->current_config.enable_stealth_attack_via_bombardment && + (! is_online_game ()) && + patch_Leader_is_tile_visible (&leaders[is->bombarding_unit->Body.CivID], __, x_neigh, y_neigh)) + is->bombard_stealth_target = select_stealth_attack_bombard_target (is->bombarding_unit, x_neigh, y_neigh); + + return tr; +} + +int __fastcall +patch_rand_bombard_target (void * this, int edx, int lim) +{ + // If we have a bombard stealth attack target set then return 2 so that the bombard damage will be applied to units not pop or buildings. + return (is->bombard_stealth_target == NULL) ? rand_int (this, __, lim) : 2; +} + +int __fastcall +patch_rand_int_to_dodge_city_aa (void * this, int edx, int lim) +{ + int tr = rand_int (this, __, lim); + is->result_of_roll_to_dodge_city_aa = tr; + return tr; +} + +int __fastcall +patch_Unit_get_defense_to_dodge_city_aa (Unit * this) +{ + int defense = Unit_get_defense_strength (this); + if (is->current_config.show_message_after_dodging_sam && + (defense > is->result_of_roll_to_dodge_city_aa) && + (this->Body.CivID == p_main_screen_form->Player_CivID)) + show_map_specific_text (this->Body.X, this->Body.Y, is->c3x_labels[CL_DODGED_SAM], 0); + return defense; +} + +int __fastcall +patch_Unit_get_defense_to_find_bombard_defender (Unit * this) +{ + // The caller is filtering out candidates with zero defense strength as possible targets to receive damage from bombardment. We can return 0 + // here to make sure "this" unit is not targeted. + + Unit * container; + + if (is->current_config.immunize_aircraft_against_bombardment && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air)) + return 0; + + else if ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return 0; + + else + return Unit_get_defense_strength (this); +} + +int __cdecl +patch_get_WindowsFileBox_from_ini (LPCSTR key, int param_2, int param_3) +{ + // If the file path has already been determined, then avoid using the Windows file picker. This makes the later code to insert the path easier + // since we only have to intercept the opening of the civ-style file picker instead of both that and the Windows one. + if (is->load_file_path_override == NULL) + return get_int_from_conquests_ini (key, param_2, param_3); + else + return 0; +} + +char const * __fastcall +patch_do_open_load_game_file_picker (void * this) +{ + if (is->load_file_path_override != NULL) { + char const * tr = is->load_file_path_override; + is->load_file_path_override = NULL; + return tr; + } else + return open_load_game_file_picker (this); +} + +int __fastcall +patch_show_intro_after_load_popup (void * this, int edx, int param_1, int param_2) +{ + if (! is->suppress_intro_after_load_popup) + return patch_show_popup (this, __, param_1, param_2); + else { + is->suppress_intro_after_load_popup = 0; + return 0; + } +} + +void __fastcall patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id); + +void * __cdecl +patch_do_load_game (char * param_1) +{ + void * tr = do_load_game (param_1); + + if (is->current_config.restore_unit_directions_on_game_load && (p_units->Units != NULL)) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if ((unit != NULL) && (unit->Body.UnitState != UnitState_Fortifying)) { + if (Map_in_range (&p_bic_data->Map, __, unit->Body.X, unit->Body.Y) && + Map_in_range (&p_bic_data->Map, __, unit->Body.PrevMoveX, unit->Body.PrevMoveY)) { + int dx = unit->Body.X - unit->Body.PrevMoveX, dy = unit->Body.Y - unit->Body.PrevMoveY; + int dir = -1; + if ((dx == 1) && (dy == -1)) dir = DIR_NE; + else if ((dx == 2) && (dy == 0)) dir = DIR_E; + else if ((dx == 1) && (dy == 1)) dir = DIR_SE; + else if ((dx == 0) && (dy == 2)) dir = DIR_S; + else if ((dx == -1) && (dy == 1)) dir = DIR_SW; + else if ((dx == -2) && (dy == 0)) dir = DIR_W; + else if ((dx == -1) && (dy == -1)) dir = DIR_NW; + else if ((dx == 0) && (dy == -2)) dir = DIR_N; + if (dir >= 0) + unit->Body.Animation.summary.direction = dir; + } + } + } + + // Apply era aliases + for (int n = 0; n < 32; n++) + if (*p_player_bits & (1 << n)) + apply_era_specific_names (&leaders[n]); + + if (is->current_config.apply_grid_ini_setting_on_game_load) { + int grid_on = get_int_from_conquests_ini ("GridOn", 0, 0); + Map_Renderer * mr = &p_bic_data->Map.Renderer; + if (grid_on && ! mr->MapGrid_Flag) + mr->vtable->m68_Toggle_Grid (mr); + } + + return tr; +} + +void * +load_game_ex (char const * file_path, int suppress_intro_popup) +{ + is->suppress_intro_after_load_popup = suppress_intro_popup; + is->load_file_path_override = file_path; + return patch_do_load_game (NULL); +} + +int __fastcall +patch_show_movement_phase_popup (void * this, int edx, int param_1, int param_2) +{ + int tr = patch_show_popup (this, __, param_1, param_2); + + int player_civ_id = p_main_screen_form->Player_CivID; + int replay_for_players = is->replay_for_players; // Store this b/c it gets reset on game load + if (replay_for_players & 1<showing_hotseat_replay = true; + + patch_do_save_game (hotseat_resume_save_path, 1, 0); + load_game_ex (hotseat_replay_save_path, 1); + p_main_screen_form->Player_CivID = player_civ_id; + + // Re-enable the GUI so the minimap is visible during the replay. We must also reset the minimap & redraw it so that it reflects the + // player we just seated (above) instead of leftover data from the last player. + Main_GUI * main_gui = &p_main_screen_form->GUI; + main_gui->is_enabled = 1; + Navigator_Data_reset (&main_gui->Navigator_Data); + main_gui->Base.vtable->m73_call_m22_Draw ((Base_Form *)main_gui); + + perform_interturn (); + load_game_ex (hotseat_resume_save_path, 1); + p_main_screen_form->is_now_loading_game = 0; + + // Restore the replay_for_players variable b/c it gets cleared when loading a game. Also mask out the bit for the player we just + // showed the replay to. + is->replay_for_players = replay_for_players & ~(1<showing_hotseat_replay = false; + } + + return tr; +} + +// Returns a set of player bits containing only those players that are human and can see at least one AI unit. For speed and simplicity, does not +// account for units' invisibility ability, units are considered visible as long as they're on a visible tile. +int +find_human_players_seeing_ai_units () +{ + int tr = 0; + Map * map = &p_bic_data->Map; + if (map->Tiles != NULL) + for (int n_tile = 0; n_tile < map->TileCount; n_tile++) { + Tile * tile = map->Tiles[n_tile]; + Tile_Body * body = &tile->Body; + int human_vis_bits = (body->FOWStatus | body->V3 | body->Visibility | body->field_D0_Visibility) & *p_human_player_bits; + if (human_vis_bits != 0) // If any human players can see this tile + for (int n_player = 0; n_player < 32; n_player++) + if (human_vis_bits & 1<TileUnitID, &unused); + Unit * unit = get_unit_ptr (unit_id); + if ((unit != NULL) && + ((*p_human_player_bits & 1<Body.CivID) == 0)) { + tr |= 1<current_config.replay_ai_moves_in_hotseat_games && + (*p_is_offline_mp_game && ! *p_is_pbem_game); // offline MP but not PBEM => we're in a hotseat game + int ai_unit_vis_before; + if (save_replay) { + ai_unit_vis_before = find_human_players_seeing_ai_units (); + int toggleable_rules = *p_toggleable_rules; + *p_toggleable_rules |= TR_PRESERVE_RANDOM_SEED; // Make sure preserve random seed is on for the replay save + patch_do_save_game (hotseat_replay_save_path, 1, 0); + *p_toggleable_rules = toggleable_rules; + } + + is->players_saw_ai_unit = 0; // Clear bits. After perform_interturn, each set bit will indicate a player that has seen an AI unit move + long long ts_before; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); + is->time_spent_paused_during_popup = 0; + is->time_spent_computing_city_connections = 0; + is->count_calls_to_recompute_city_connections = 0; + unsigned saved_prefs = *p_preferences; + if (is->current_config.measure_turn_times) + *p_preferences &= ~(P_ANIMATE_BATTLES | P_SHOW_FRIEND_MOVES | P_SHOW_ENEMY_MOVES); + + perform_interturn (); + + if (is->current_config.day_night_cycle_mode) { + if (is->day_night_cycle_img_state == IS_OK) { + int new_hour = calculate_current_day_night_cycle_hour (); + if (new_hour != is->current_day_night_cycle) { + is->current_day_night_cycle = new_hour; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + } + } + } + + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_for_districts (); + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); + } + + if (is->current_config.show_ai_city_location_desirability_if_settler && is->city_loc_display_perspective >= 0) { + is->city_loc_display_perspective = -1; + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); // Trigger map redraw + } + + if (is->current_config.measure_turn_times) { + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + long long perf_freq; + QueryPerformanceFrequency ((LARGE_INTEGER *)&perf_freq); + int turn_time_in_ms = 1000 * (ts_after - ts_before - is->time_spent_paused_during_popup) / perf_freq; + int city_con_time_in_ms = 1000 * is->time_spent_computing_city_connections / perf_freq; + int road_time_in_ms = 1000 * is->time_spent_filling_roads / perf_freq; + + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + char msg[1000]; + + struct c3x_opt { + bool is_active; + char * name; + } opts[] = {{is->current_config.optimize_improvement_loops, "improv. loops"}, + {is->current_config.enable_trade_net_x && (is->tnx_init_state == IS_OK), "trade net x"}}; + char opt_list[1000]; + memset (opt_list, 0, sizeof opt_list); + strncpy (opt_list, "^C3X optimizations: ", sizeof opt_list); + bool any_active_opts = false; + for (int n = 0; n < ARRAY_LEN (opts); n++) + if (opts[n].is_active) { + char * cursor = &opt_list[strlen (opt_list)]; + snprintf (cursor, opt_list + (sizeof opt_list) - cursor, "%s%s", any_active_opts ? ", " : "", opts[n].name); + any_active_opts = true; + } + if (! any_active_opts) { + char * cursor = &opt_list[strlen (opt_list)]; + strncpy (cursor, "None", opt_list + (sizeof opt_list) - cursor); + } + PopupForm_add_text (popup, __, (char *)opt_list, false); + + snprintf (msg, sizeof msg, "^Turn time: %d.%03d sec", turn_time_in_ms/1000, turn_time_in_ms%1000); + PopupForm_add_text (popup, __, (char *)msg, false); + snprintf (msg, sizeof msg, "^ Recomputing city connections: %d.%03d sec (%d calls)", + city_con_time_in_ms/1000, city_con_time_in_ms%1000, + is->count_calls_to_recompute_city_connections); + PopupForm_add_text (popup, __, (char *)msg, false); + snprintf (msg, sizeof msg, "^ Flood filling road network: %d.%03d sec", + road_time_in_ms/1000, road_time_in_ms%1000); + PopupForm_add_text (popup, __, (char *)msg, false); + patch_show_popup (popup, __, 0, 0); + + *p_preferences = saved_prefs; + } + + if (save_replay) { + int last_human_player_bit = 0; { + for (int n = 0; n < 32; n++) + if (*p_human_player_bits & 1<replay_for_players = (ai_unit_vis_before | (is->players_saw_ai_unit & *p_human_player_bits)) & ~last_human_player_bit; + } +} + +void __cdecl +patch_initialize_map_music (int civ_id, int era_id, bool param_3) +{ + if (! is->showing_hotseat_replay) + initialize_map_music (civ_id, era_id, param_3); +} + +void __stdcall +patch_deinitialize_map_music () +{ + if (! is->showing_hotseat_replay) + deinitialize_map_music (); +} + +void __fastcall +patch_Fighter_do_bombard_tile (Fighter * this, int edx, Unit * unit, int neighbor_index, int mp_tile_x, int mp_tile_y) +{ + // Unit::score_kill will be called if the bombarder destroys its target, and that is the only way score_kill can be called while this method + // is running. So if we're configured to stop enslaving from bombard, turn off enslaving while it's running. + is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; + + // Check if we're going to do PTW-like targeting, if not fall back on the base game's do_bombard_tile method. We'll also fall back on that + // method in the case where we're in an online game and the bombard can't happen b/c the tile is occupied by another battle. In that case, no + // bombard is possible but we'll call the base method anyway since it will show a little message saying as much. + if (itable_look_up_or (&is->current_config.ptw_arty_types, unit->Body.UnitTypeID, 0) && + (is->bombard_stealth_target == NULL) && + ! (is_online_game () && mp_check_current_combat (p_mp_object, __, mp_tile_x, mp_tile_y))) { + + City * city; { + int dx, dy; + neighbor_index_to_diff (neighbor_index, &dx, &dy); + int tile_x = unit->Body.X + dx, tile_y = unit->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + city = city_at (tile_x, tile_y); + } + + int rv; + if ((city != NULL) && ((rv = rand_int (p_rand_object, __, 3)) < 2)) + Fighter_damage_city_by_bombardment (this, __, unit, city, rv, 0); + else + Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); + + } else + Fighter_do_bombard_tile (this, __, unit, neighbor_index, mp_tile_x, mp_tile_y); + + is->do_not_enslave_units = false; +} + +bool __fastcall +patch_Unit_check_king_for_defense_priority (Unit * this, int edx, enum UnitTypeAbilities king_ability) +{ + return (! is->current_config.ignore_king_ability_for_defense_priority) || (*p_toggleable_rules & (TR_REGICIDE | TR_MASS_REGICIDE)) ? + Unit_has_ability (this, __, king_ability) : + false; +} + +void WINAPI +patch_get_local_time_for_unit_ini (LPSYSTEMTIME lpSystemTime) +{ + GetLocalTime (lpSystemTime); + if (is->current_config.no_elvis_easter_egg && (lpSystemTime->wMonth == 1) && (lpSystemTime->wDay == 8)) + lpSystemTime->wDay = 9; +} + +bool __fastcall +patch_Leader_could_buy_tech_for_trade_screen (Leader * this, int edx, int tech_id, int from_civ_id) +{ + // Temporarily remove the untradable flag so this tech is listed on the screen instead of skipped over. After all the items have been + // assembled, we'll go back and disable the untradable techs. + if (is->current_config.show_untradable_techs_on_trade_screen) { + int saved_flags = p_bic_data->Advances[tech_id].Flags; + p_bic_data->Advances[tech_id].Flags &= ~ATF_Cannot_Be_Traded; + bool tr = this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); + p_bic_data->Advances[tech_id].Flags = saved_flags; + return tr; + + } else + return this->vtable->could_buy_tech (this, __, tech_id, from_civ_id); +} + +void __fastcall +patch_DiploForm_assemble_tradable_items (DiploForm * this) +{ + DiploForm_assemble_tradable_items (this); + + // Disable (gray out) all untradable techs + if (is->current_config.show_untradable_techs_on_trade_screen) + for (int n = 0; n < p_bic_data->AdvanceCount; n++) + if (p_bic_data->Advances[n].Flags & ATF_Cannot_Be_Traded) { + this->tradable_technologies[n].can_be_bought = 0; + this->tradable_technologies[n].can_be_sold = 0; + } +} + +bool __fastcall +patch_City_can_trade_via_water (City * this) +{ + if (is->current_config.optimize_improvement_loops) { + for (int n = 0; n < is->water_trade_improvs.count; n++) + if (has_active_building (this, is->water_trade_improvs.items[n])) + return true; + return false; + } else + return City_can_trade_via_water (this); +} + +bool __fastcall +patch_City_can_trade_via_air (City * this) +{ + if (is->current_config.optimize_improvement_loops) { + for (int n = 0; n < is->air_trade_improvs.count; n++) + if (has_active_building (this, is->air_trade_improvs.items[n])) + return true; + return false; + } else + return City_can_trade_via_air (this); +} + +int __fastcall +patch_City_get_building_defense_bonus (City * this) +{ + bool cancel_great_wall_boost = is->current_config.enable_districts && + is->current_config.enable_great_wall_districts && + is->current_config.disable_great_wall_city_defense_bonus; + + if (is->current_config.optimize_improvement_loops || cancel_great_wall_boost) { + int tr = 0; + int is_size_level_1 = (this->Body.Population.Size <= p_bic_data->General.MaximumSize_City) && + (this->Body.Population.Size <= p_bic_data->General.MaximumSize_Town); + for (int n = 0; n < is->combat_defense_improvs.count; n++) { + int improv_id = is->combat_defense_improvs.items[n]; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((is_size_level_1 || (improv->Combat_Bombard == 0)) && has_active_building (this, improv_id)) { + int multiplier; + if ((improv->Combat_Bombard > 0) && + (! cancel_great_wall_boost) && + (patch_Leader_count_any_shared_wonders_with_flag (&leaders[(this->Body).CivID], __, ITW_Doubles_City_Defenses, NULL) > 0)) + multiplier = 2; + else + multiplier = 1; + + int building_defense = multiplier * improv->Combat_Defence; + if (building_defense > tr) + tr = building_defense; + } + } + return tr; + } else + return City_get_building_defense_bonus (this); +} + +bool __fastcall +patch_City_shows_harbor_icon (City * this) +{ + return is->current_config.city_icons_show_unit_effects_not_trade ? + City_count_improvements_with_flag (this, __, ITF_Veteran_Sea_Units) > 0 : + patch_City_can_trade_via_water (this); +} + +bool __fastcall +patch_City_shows_airport_icon (City * this) +{ + return is->current_config.city_icons_show_unit_effects_not_trade ? + City_count_improvements_with_flag (this, __, ITF_Veteran_Air_Units) > 0 : + patch_City_can_trade_via_air (this); +} + +int __fastcall +patch_Unit_eval_escort_requirement (Unit * this) +{ + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + int ai_strat = type->AI_Strategy; + bool owned_by_ai = (*p_human_player_bits & 1<Body.CivID) == 0; // We must not reduce the escort requirement for human-owned units + // because that will interfere with group movement of units. + + // Apply special escort rules + if (owned_by_ai && is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) + return 0; + else if (owned_by_ai && is->current_config.use_offensive_artillery_ai && (ai_strat & UTAI_Artillery)) + return 1; + + else { + int base = Unit_eval_escort_requirement (this); + if (owned_by_ai && (ai_strat & (UTAI_Naval_Transport | UTAI_Naval_Carrier | UTAI_Naval_Missile_Transport))) + return not_above (is->current_config.max_ai_naval_escorts, base); + else + return base; + } +} + +bool __fastcall +patch_Unit_has_enough_escorters_present (Unit * this) +{ + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) + return true; + else + return Unit_has_enough_escorters_present (this); +} + +void __fastcall +patch_Unit_check_escorter_health (Unit * this, int edx, bool * has_any_escort_present, bool * any_escorter_cant_heal) +{ + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.dont_escort_unflagged_units && ! UnitType_has_ability (type, __, UTA_Requires_Escort)) { + *has_any_escort_present = true; + *any_escorter_cant_heal = true; // Returning true here indicates the unit should not stop to wait for its escorter(s) to heal. + } else + Unit_check_escorter_health (this, __, has_any_escort_present, any_escorter_cant_heal); +} + +void __fastcall +patch_Leader_unlock_technology (Leader * this, int edx, int tech_id, bool param_2, bool param_3, bool param_4) +{ + int * p_stack = (int *)&tech_id; + int ret_addr = p_stack[-1]; + + Leader_unlock_technology (this, __, tech_id, param_2, param_3, param_4); + + // If this method was not called during game initialization + if ((ret_addr != ADDR_UNLOCK_TECH_AT_INIT_1) && + (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_2) && + (ret_addr != ADDR_UNLOCK_TECH_AT_INIT_3)) { + + // If this tech obsoletes some building and we're configured to fix the maintenance bug then recompute city maintenance. + if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings) { + bool obsoletes_anything = false; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (p_bic_data->Improvements[n].ObsoleteID == tech_id) { + obsoletes_anything = true; + break; + } + if (obsoletes_anything) + Leader_recompute_buildings_maintenance (this); + } + } +} + +int __fastcall +patch_City_get_improv_maintenance_for_ui (City * this, int edx, int improv_id) +{ + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if (is->current_config.patch_maintenance_persisting_for_obsolete_buildings && + (improv->ObsoleteID >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, improv->ObsoleteID)) + return 0; + else + return patch_City_get_improvement_maintenance (this, __, improv_id); +} + +// Patch for barbarian diagonal bug. This bug is a small mistake in the original code, maybe a copy+paste error. The original code tries to loop over +// tiles around the barb unit by incrementing a neighbor index and coverting it to tile coords (like normal). The problem is that after it converts +// the neighbor index to dx and dy, it adds dx to both coords of the unit's position instead of using dy. The fix is simply to subtract off dx and add +// in dy when the Y coord is passed to Map::wrap_vert. +void __cdecl +patch_neighbor_index_to_diff_for_barb_ai (int neighbor_index, int * out_x, int * out_y) +{ + neighbor_index_to_diff (neighbor_index, out_x, out_y); + is->barb_diag_patch_dy_fix = *out_y - *out_x; +} +int __fastcall +patch_Map_wrap_vert_for_barb_ai (Map * this, int edx, int y) +{ + return Map_wrap_vert (this, __, is->current_config.patch_barbarian_diagonal_bug ? (y + is->barb_diag_patch_dy_fix) : y); +} + +int +count_workable_tiles_for_city (City * city) +{ + if (city == NULL) + return 0; + + int workable = 0; + FOR_WORK_AREA_AROUND (wai, city->Body.X, city->Body.Y) { + Tile * tile = wai.tile; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + if (tile->Body.CityAreaID != city->Body.ID) + continue; + + struct district_instance * inst = get_district_instance (tile); + if ((inst != NULL) && district_is_complete (tile, inst->district_id)) + continue; + + workable++; + } + return workable; +} + +int +compute_auto_distribution_hub_goal (Leader * leader, int city_count) +{ + int total_unused_tiles = 0; + int stagnating_cities = 0; + int slow_growth_cities = 0; + int very_low_production_cities = 0; + int low_production_cities = 0; + + FOR_CITIES_OF (coi, leader->ID) { + City * city = coi.city; + if (city == NULL) + continue; + + int pop_size = city->Body.Population.Size; + int workable_tiles = count_workable_tiles_for_city (city); + if ((workable_tiles > 0) && (pop_size < workable_tiles)) + total_unused_tiles += workable_tiles - pop_size; + + int net_food = city->Body.FoodIncome; + if (net_food <= 0) + stagnating_cities++; + else if (net_food <= 2) + slow_growth_cities++; + + int net_shields = city->Body.ProductionIncome + city->Body.ProductionLoss; + if (net_shields < 0) + net_shields = 0; + if (net_shields <= 3) + very_low_production_cities++; + else if (net_shields <= 6) + low_production_cities++; + } + + int base_desired = (city_count + 3) / 4; + + int tiles_per_chunk = is->workable_tile_count; + if (tiles_per_chunk <= 0) + tiles_per_chunk = 1; + int unused_bonus = (total_unused_tiles + tiles_per_chunk * 3 - 1) / (tiles_per_chunk * 3); + + int food_pressure = stagnating_cities * 2 + slow_growth_cities; + int food_bonus = (food_pressure + 2) / 3; + + int production_pressure = very_low_production_cities * 2 + low_production_cities; + int production_bonus = (production_pressure + 2) / 3; + + int desired = base_desired + unused_bonus + food_bonus + production_bonus; + int max_reasonable = (city_count + 1) / 2; + int max_per_100 = is->current_config.max_distribution_hub_count_per_100_cities; + if (max_per_100 > 0) { + int capped = (city_count * max_per_100 + 99) / 100; + if (capped >= 0) + max_reasonable = capped; + } + if (desired > max_reasonable) + desired = max_reasonable; + if (desired < 1) + desired = 1; + + return desired; +} + +void +ai_update_distribution_hub_goal_for_leader (Leader * leader) +{ + if (leader == NULL) + return; + if (! is->current_config.enable_districts || + ! is->current_config.enable_distribution_hub_districts) + return; + + int civ_id = leader->ID; + if ((1 << civ_id) & *p_human_player_bits) + return; + + int city_count = leader->Cities_Count; + if (city_count <= 0) + return; + + int desired = 0; + if (is->current_config.ai_distribution_hub_build_strategy == ADHBS_AUTO) + desired = compute_auto_distribution_hub_goal (leader, city_count); + else { + int ideal_per_100 = is->current_config.ai_ideal_distribution_hub_count_per_100_cities; + if (ideal_per_100 <= 0) + return; + desired = (city_count * ideal_per_100) / 100; + } + if (desired <= 0) + return; + + int current = 0; + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if ((rec != NULL) && (rec->civ_id == civ_id)) + current++; + } + + int in_progress = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * tile = (Tile *)tei.key; + int mapped_district_id = tei.value; + if ((tile != NULL) && + (mapped_district_id == DISTRIBUTION_HUB_DISTRICT_ID) && + ! district_is_complete (tile, DISTRIBUTION_HUB_DISTRICT_ID)) { + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (owner == civ_id) + in_progress++; + } + } + + int pending = 0; + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req != NULL) && (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID)) + pending++; + } + + int planned = current + in_progress + pending; + if (planned >= desired) + return; + + City * capital = get_city_ptr (leader->CapitalID); + bool has_capital = (capital != NULL); + int capital_x = has_capital ? capital->Body.X : 0; + int capital_y = has_capital ? capital->Body.Y : 0; + + const int yield_weight = 40; + const int capital_distance_weight = 45; + const int desired_min_capital_distance = 8; + const int proximity_penalty_scale = 300; + + while (planned < desired) { + City * best_city = NULL; + int best_tile_x = 0; + int best_tile_y = 0; + int best_score = INT_MIN; + + FOR_CITIES_OF (coi, civ_id) { + City * city = coi.city; + if (city == NULL) + continue; + if (city_has_required_district (city, DISTRIBUTION_HUB_DISTRICT_ID)) + continue; + + if (find_pending_district_request (city, DISTRIBUTION_HUB_DISTRICT_ID) != NULL) + continue; + + int tile_x, tile_y; + Tile * candidate = find_tile_for_district (city, DISTRIBUTION_HUB_DISTRICT_ID, &tile_x, &tile_y); + if (candidate == NULL) + continue; + + int yield_sum = compute_city_tile_yield_sum (city, tile_x, tile_y); + int distance_to_capital = 0; + if (has_capital) + distance_to_capital = compute_wrapped_manhattan_distance (city->Body.X, city->Body.Y, capital_x, capital_y); + + int closeness_penalty = 0; + if (has_capital && (distance_to_capital < desired_min_capital_distance)) + closeness_penalty = (desired_min_capital_distance - distance_to_capital) * proximity_penalty_scale; + + int score = yield_sum * yield_weight + distance_to_capital * capital_distance_weight - closeness_penalty; + if (tile_has_resource (candidate)) + score -= 500; + + if (score > best_score) { + best_score = score; + best_city = city; + best_tile_x = tile_x; + best_tile_y = tile_y; + } + } + + if (best_city == NULL) + break; + + mark_city_needs_district (best_city, DISTRIBUTION_HUB_DISTRICT_ID); + planned++; + } +} + +bool +assign_ai_fallback_production (City * city, int disallowed_improvement_id) +{ + if (city == NULL) + return false; + + City_Order new_order = { .OrderID = -1, .OrderType = 0 }; + patch_City_ai_choose_production (city, __, &new_order); + + bool order_ok = false; + if (new_order.OrderType == COT_Improvement) { + if ((new_order.OrderID >= 0) && + (new_order.OrderID < p_bic_data->ImprovementsCount) && + (new_order.OrderID != disallowed_improvement_id) && + ! city_requires_district_for_improvement (city, new_order.OrderID, NULL) && + ! is_wonder_or_small_wonder_already_being_built (city, new_order.OrderID)) + order_ok = true; + } else if (new_order.OrderType == COT_Unit) { + if ((new_order.OrderID >= 0) && + (new_order.OrderID < p_bic_data->UnitTypeCount) && + (p_bic_data->UnitTypes[new_order.OrderID].Unit_Class == UTC_Land) && + patch_City_can_build_unit (city, __, new_order.OrderID, 1, 0, 0)) + order_ok = true; + } + + char ss[200]; + snprintf (ss, sizeof ss, "assign_ai_fallback_production: Remembering fallback pending building order for city %d (%s): id %d\n", + city->Body.ID, city->Body.CityName, disallowed_improvement_id); + (*p_OutputDebugStringA) (ss); + remember_pending_building_order (city, disallowed_improvement_id); + + if (order_ok) { + City_set_production (city, __, new_order.OrderType, new_order.OrderID, false); + return true; + } + + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) { + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + return true; + } + } + + return false; +} + +void __fastcall +patch_Leader_do_production_phase (Leader * this) +{ + recompute_resources_if_necessary (); + + if (is->current_config.enable_districts) { + assign_workers_for_pending_districts (this); + + if ((is->current_config.enable_canal_districts || is->current_config.enable_bridge_districts) && + (is->current_config.ai_builds_bridges || is->current_config.ai_builds_canals)) + assign_workers_for_ai_candidate_bridge_or_canals (this); + + bool ai_player = ((*p_human_player_bits & (1 << this->ID)) == 0); + int auto_dynamic_district_ids[COUNT_DISTRICT_TYPES]; + int auto_dynamic_district_count = 0; + + // For dynamic districts, the AI will never be triggered to build them if they have no dependent buildings. + // Determine which dynamic districts the AI could build. In the city loop after, mark which cities need them + if (ai_player) { + for (int district_id = is->special_district_count; district_id < is->district_count; district_id++) { + struct district_config * cfg = &is->district_configs[district_id]; + struct district_infos * info = &is->district_infos[district_id]; + + if (info->dependent_building_count > 0) continue; + if (cfg->command == -1) continue; + + if (! leader_can_build_district (this, district_id)) + continue; + + if (auto_dynamic_district_count < ARRAY_LEN (auto_dynamic_district_ids)) + auto_dynamic_district_ids[auto_dynamic_district_count++] = district_id; + } + } + + // Special exception for AI to build Central Rail Hub, which is available in Industrial era but Mass Transit, + // the only building dependent on it, is in the Modern era. Without this the AI wouldn't build in Industrial era. + if (is->current_config.enable_central_rail_hub_districts) { + if (leader_can_build_district (this, CENTRAL_RAIL_HUB_DISTRICT_ID)) + auto_dynamic_district_ids[auto_dynamic_district_count++] = CENTRAL_RAIL_HUB_DISTRICT_ID; + } + + if (is->current_config.enable_distribution_hub_districts) { + if (leader_can_build_district (this, DISTRIBUTION_HUB_DISTRICT_ID)) + ai_update_distribution_hub_goal_for_leader (this); + } + + FOR_CITIES_OF (coi, this->ID) { + City * city = coi.city; + if (city == NULL) continue; + + bool at_neighborhood_cap = is->current_config.enable_neighborhood_districts && city_is_at_neighborhood_cap (city); + + // Mark any needed dynamic districts for AI players. This isn't the most intelligent approach (we're not weighing district benefits), + // but it's simple and works reasonably well + if (ai_player && (auto_dynamic_district_count > 0)) { + for (int i = 0; i < auto_dynamic_district_count; i++) { + int district_id = auto_dynamic_district_ids[i]; + + if (city_has_required_district (city, district_id)) continue; + if (! city_can_build_district (city, district_id)) continue; + if (find_pending_district_request (city, district_id) != NULL) continue; + + int target_x = 0, target_y = 0; + if (find_tile_for_district (city, district_id, &target_x, &target_y) == NULL) + continue; + + mark_city_needs_district (city, district_id); + } + } + + if (at_neighborhood_cap) { + if (! ai_player) + maybe_show_neighborhood_growth_warning (city); + else + ensure_neighborhood_request_for_city (city); + } + + if (city->Body.Order_Type == COT_Unit) { + int unit_id = city->Body.Order_ID; + int req_district_id = -1; + bool needs_halt = false; + + if ((unit_id >= 0) && (unit_id < p_bic_data->UnitTypeCount)) { + UnitType * type = &p_bic_data->UnitTypes[unit_id]; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (city, AERODROME_DISTRICT_ID))) { + req_district_id = AERODROME_DISTRICT_ID; + needs_halt = true; + } else if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (city, PORT_DISTRICT_ID))) { + req_district_id = PORT_DISTRICT_ID; + needs_halt = true; + } + } + + if (needs_halt) { + char ss[200]; + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting unit %d due to missing district %d\n", + city->Body.ID, city->Body.CityName, unit_id, req_district_id); + (*p_OutputDebugStringA) (ss); + + if (ai_player) + mark_city_needs_district (city, req_district_id); + + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + + continue; + } + } + + if (city->Body.Order_Type != COT_Improvement) continue; + int i_improv = city->Body.Order_ID; + + // Check if production needs to be halted due to missing district + int req_district_id = -1; + char const * district_description = NULL; + bool needs_halt = false; + + // Check buildings & wonders dependent on districts + if (city_requires_district_for_improvement (city, i_improv, &req_district_id)) { + if (req_district_id >= 0) { + needs_halt = true; + district_description = is->district_configs[req_district_id].name; + } + } + + // Wonders + char ss[200]; + if (is->current_config.enable_wonder_districts) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: Checking wonder improv %d for city %d (%s)\n", + i_improv, city->Body.ID, city->Body.CityName); + (*p_OutputDebugStringA) (ss); + if (city_is_currently_building_wonder (city)) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) is building wonder improv %d\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + bool wonder_requires_district = false; + if (i_improv >= 0) { + struct district_building_prereq_list * prereq_list = get_district_building_prereq_list (i_improv); + if (district_building_prereq_list_contains (prereq_list, WONDER_DISTRICT_ID)) + wonder_requires_district = true; + } + + if (wonder_requires_district) { + bool has_wonder_district = reserve_wonder_district_for_city (city, i_improv); + if (! has_wonder_district) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) lacks Wonder District for wonder improv %d\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + needs_halt = true; + req_district_id = WONDER_DISTRICT_ID; + district_description = "Wonder District"; + } + } else { + release_wonder_district_reservation (city); + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) wonder improv %d does not require Wonder District\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + } + } else { + release_wonder_district_reservation (city); + } + } + + // If production needs to be halted, handle the reassignment and messaging + if (needs_halt) { + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) halting improv %d due to missing district %d\n", + city->Body.ID, city->Body.CityName, i_improv, req_district_id); + (*p_OutputDebugStringA) (ss); + // Switch production to another option + if (ai_player) { + mark_city_needs_district (city, req_district_id); + assign_ai_fallback_production (city, i_improv); + } else { + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (city, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (city, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + // Show message to human player + if (! ai_player && (city->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[160]; + char const * bname = p_bic_data->Improvements[i_improv].Name.S; + snprintf (msg, sizeof msg, "%s %s %s", bname, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_description); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (city->Body.X, city->Body.Y, msg, true); + } + continue; + } + snprintf (ss, sizeof ss, "patch_Leader_do_production_phase: City %d (%s) improv %d passed missing district check\n", + city->Body.ID, city->Body.CityName, i_improv); + (*p_OutputDebugStringA) (ss); + } + } + + // Force-activate the barbs if there are any barb cities on the map and barb city capturing is enabled. This is necessary for barb city + // production to work given how it's currently implemented. + if (is->current_config.enable_city_capture_by_barbarians && (this->ID == 0)) { + int any_barb_cities = 0; + FOR_CITIES_OF (coi, this->ID) { + any_barb_cities = 1; + break; + } + if (any_barb_cities) + is->force_barb_activity_for_cities = 1; + } + + // If barbs are force-activated, make sure their activity level is at least 1 (sedentary). + int * p_barb_activity = &p_bic_data->Map.World.Final_Barbarians_Activity; + int saved_barb_activity = *p_barb_activity; + if (is->force_barb_activity_for_cities && (*p_barb_activity <= 0)) + *p_barb_activity = 1; + + Leader_do_production_phase (this); + + if (is->force_barb_activity_for_cities) { + *p_barb_activity = saved_barb_activity; + is->force_barb_activity_for_cities = 0; + } +} + +// This function counts the number of players in the game. The return value will be compared to the number of cities on the map to determine if there +// are enough cities (per player) to unlock barb production. If barb activity is forced on, return zero so that the check always passes. +int __cdecl +patch_count_player_bits_for_barb_prod (unsigned int bit_field) +{ + return is->force_barb_activity_for_cities ? 0 : count_set_bits (bit_field); +} + +Tile * __fastcall +patch_Map_get_tile_to_check_visibility (Map * this, int edx, int index) +{ + Tile * tr = Map_get_tile (this, __, index); + int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; + if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { + int human_bits = *p_human_player_bits; + is->dummy_tile->Body.Fog_Of_War = tr->Body.Fog_Of_War | ((tr->Body.Fog_Of_War & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.FOWStatus = tr->Body.FOWStatus | ((tr->Body.FOWStatus & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.V3 = tr->Body.V3 | ((tr->Body.V3 & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.Visibility = tr->Body.Visibility | ((tr->Body.Visibility & human_bits) != 0 ? human_bits : 0); + is->dummy_tile->Body.field_D0_Visibility = tr->Body.field_D0_Visibility | ((tr->Body.field_D0_Visibility & human_bits) != 0 ? human_bits : 0); + tr = is->dummy_tile; + } + is->tile_returned_for_visibility_check = tr; + return tr; +} + +Tile * __fastcall +patch_Map_get_tile_to_check_visibility_again (Map * this, int edx, int index) +{ + return is->tile_returned_for_visibility_check; +} + +// Same as above except this method uses the FOWStatus field instead of Fog_Of_War +Tile * __fastcall +patch_Map_get_tile_for_fow_status_check (Map * this, int edx, int index) +{ + Tile * tile = Map_get_tile (this, __, index); + int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; + if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { + is->dummy_tile->Body.FOWStatus = ((tile->Body.FOWStatus & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; + return is->dummy_tile; + } else + return tile; +} + +Tile * __cdecl +patch_tile_at_to_check_visibility (int x, int y) +{ + return patch_Map_get_tile_to_check_visibility (&p_bic_data->Map, __, (p_bic_data->Map.Width >> 1) * y + (x >> 1)); +} + +Tile * __cdecl +patch_tile_at_to_check_visibility_again (int x, int y) +{ + return is->tile_returned_for_visibility_check; +} + +unsigned __fastcall +patch_Tile_m42_Get_Overlays (Tile * this, int edx, byte visible_to_civ) +{ + unsigned base_vis_overlays = Tile_m42_Get_Overlays (this, __, visible_to_civ); + if ((visible_to_civ != 0) && // if we're seeing from a player's persp. instead of seeing the actual overlays AND + is->current_config.share_visibility_in_hotseat && // shared hotseat vis is enabled AND + ((1 << visible_to_civ) & *p_human_player_bits) && // the perspective is of a human player AND + (base_vis_overlays != this->Overlays) && // that player can't already see all the actual overlays AND + (*p_is_offline_mp_game && ! *p_is_pbem_game)) { // we're in a hotseat game + + // Check if there's another human player that can see the actual overlays. If so, give that info to this player and return it. + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != visible_to_civ) && + (Tile_m42_Get_Overlays (this, __, n_player) == this->Overlays)) { + this->Body.Visibile_Overlays[visible_to_civ] = this->Overlays; + return this->Overlays; + } + player_bits >>= 1; + n_player++; + } + + return base_vis_overlays; + } else + return base_vis_overlays; +} + +int __fastcall +patch_Tile_check_water_for_sea_zoc (Tile * this) +{ + if ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) + return this->vtable->m35_Check_Is_Water (this); + else + return 1; // The caller will skip ZoC logic if this is a land tile without a city because the targeted unit is a sea unit. Instead + // return 1, so all tiles are considered sea tiles, so we can run the ZoC logic for land units or air units on land. +} + +int __fastcall +patch_Tile_check_water_for_land_zoc (Tile * this) +{ + // Same as above except this time we want to consider all tiles to be land + return ((is->current_config.special_zone_of_control_rules & (SZOCR_AMPHIBIOUS | SZOCR_AERIAL)) == 0) ? + this->vtable->m35_Check_Is_Water (this) : + 0; +} + + +int __fastcall +patch_Unit_get_attack_strength_for_sea_zoc (Unit * this) +{ + return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) ? Unit_get_attack_strength (this) : 0; +} + +int __fastcall +patch_Unit_get_attack_strength_for_land_zoc (Unit * this) +{ + return (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) ? Unit_get_attack_strength (this) : 0; +} + +// Forward declaration; defined further below near patch_Fighter_get_odds_for_main_combat_loop +// where its dependencies (apply_counter_rules, Fighter_get_combat_odds, counter_combat_ctx) live. +Unit * find_civ4_best_defender_against (Unit * attacker, Tile * tile, int tile_x, int tile_y); + +Unit * __fastcall +patch_Main_Screen_Form_find_visible_unit (Main_Screen_Form * this, int edx, int tile_x, int tile_y, Unit * excluded) +{ + struct unit_display_override * override = &is->unit_display_override; + if ((override->unit_id >= 0) && (override->tile_x == tile_x) && (override->tile_y == tile_y)) { + Unit * unit = get_unit_ptr (override->unit_id); + if (unit != NULL) { + if ((unit->Body.X == tile_x) && (unit->Body.Y == tile_y)) + return unit; + } + } + + // Civ 4-style 'best defender' display: when a player selects an attacker, the unit at the top of the enemy stack + // should be the one with the lowest win rate against that attacker. + // Only takes effect when both `use_civ4_style_best_defender` and `enable_unit_counters` are enabled, + // and provided the currently selected unit belongs to the local player and there is an enemy unit on the target square. + // + if (is->current_config.use_civ4_style_best_defender && + is->current_config.enable_unit_counters && + (this->Current_Unit != NULL) && + (this->Current_Unit->Body.CivID == this->Player_CivID) && + ((this->Current_Unit->Body.X != tile_x) || (this->Current_Unit->Body.Y != tile_y))) { + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile) && + tile_has_enemy_unit (tile, this->Current_Unit->Body.CivID)) { + Unit * best = find_civ4_best_defender_against (this->Current_Unit, tile, tile_x, tile_y); + if ((best != NULL) && (best != excluded)) + return best; + } + } + + return Main_Screen_Form_find_visible_unit (this, __, tile_x, tile_y, excluded); +} + +void __fastcall +patch_Animator_play_zoc_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) +{ + if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Air) + Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); +} + +bool __fastcall +patch_Fighter_check_zoc_anim_visibility (Fighter * this, int edx, Unit * attacker, Unit * defender, bool param_3) +{ + // If we've reached this point in the code (in the calling method) then a unit has been selected to exert zone of control and it has passed + // its dice roll to cause damage. Stash its pointer for possible use later. + is->zoc_interceptor = attacker; + + // If an air unit was selected, pre-emptively undo the damage from ZoC since we'll want to run our own bit of logic to do that (the air unit + // may still get shot down). Return false from this function to skip over all of the animation logic in the caller since it wouldn't work for + // aircraft. + if (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Air) { + defender->Body.Damage -= 1; + return false; + + // Repeat a check done by the caller. We've deleted this check to ensure that this function always gets called so we can grab the interceptor. + } else if (attacker->Body.Animation.field_111 == 0) + return false; + + else { + bool tr = Fighter_check_combat_anim_visibility (this, __, attacker, defender, param_3); + + // If necessary, set up to ensure the unit's attack animation is visible. This means forcing it to the top of its stack and + // temporarily unfortifying it if it's fortified. (If it's fortified, the animation is occasionally not visible. Don't know why.) + if (tr && is->current_config.show_zoc_attacks_from_mid_stack) { + is->unit_display_override = (struct unit_display_override) { attacker->Body.ID, attacker->Body.X, attacker->Body.Y }; + if (attacker->Body.UnitState == UnitState_Fortifying) { + Unit_set_state (attacker, __, 0); + is->refortify_interceptor_after_zoc = true; + } + } + + return tr; + } +} + +int __fastcall +patch_City_sum_buildings_naval_power_for_zoc (City * this) +{ + // Cancel out city's naval power if the unit has only one HP left. This prevents coastal fortresses from knocking that last hit point off + // passing units when lethal ZoC is enabled, because to make that work we delete an earlier check excusing 1-HP units from ZoC. + if ((is->zoc_defender != NULL) && + ((Unit_get_max_hp (is->zoc_defender) - is->zoc_defender->Body.Damage) <= 1)) + return 0; + + else + return City_sum_buildings_naval_power (this); +} + +void __fastcall +patch_Fighter_apply_zone_of_control (Fighter * this, int edx, Unit * unit, int from_x, int from_y, int to_x, int to_y) +{ + is->zoc_interceptor = NULL; + is->zoc_defender = unit; + is->refortify_interceptor_after_zoc = false; + struct unit_display_override saved_udo = is->unit_display_override; + Fighter_apply_zone_of_control (this, __, unit, from_x, from_y, to_x, to_y); + + // Actually exert ZoC if an air unit managed to do so. + if ((is->zoc_interceptor != NULL) && (p_bic_data->UnitTypes[is->zoc_interceptor->Body.UnitTypeID].Unit_Class == UTC_Air)) { + bool intercepted = Unit_try_flying_over_tile (is->zoc_interceptor, __, from_x, from_y); + if (! intercepted) { + Unit_play_bombing_animation (is->zoc_interceptor, __, from_x, from_y); + unit->Body.Damage = not_below (0, unit->Body.Damage + 1); + } + } + + if (is->refortify_interceptor_after_zoc) + Unit_set_state (is->zoc_interceptor, __, UnitState_Fortifying); + is->unit_display_override = saved_udo; +} + +// These two patches replace two function calls in Unit::move_to_adjacent_tile that come immediately after the unit has been subjected to zone of +// control. These calls recheck that the move is valid, not sure why. Here they're patched to indicate that the move in invalid when the unit was +// previously killed by ZoC. This causes move_to_adjacent_tile to return early without running the code that would place the unit on the destination +// tile and, for example, capturing an enemy city there. +int __fastcall +patch_Trade_Net_get_move_cost_after_zoc (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, unsigned param_7, int neighbor_index, Trade_Net_Distance_Info * dist_info) +{ + return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (unit) - unit->Body.Damage) > 0) ? + patch_Trade_Net_get_movement_cost (this, __, from_x, from_y, to_x, to_y, unit, civ_id, param_7, neighbor_index, dist_info) : + -1; +} + +AdjacentMoveValidity __fastcall +patch_Unit_can_move_after_zoc (Unit * this, int edx, int neighbor_index, int param_2) +{ + return ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) == 0) || ((Unit_get_max_hp (this) - this->Body.Damage) > 0) ? + patch_Unit_can_move_to_adjacent_tile (this, __, neighbor_index, param_2) : + AMV_1; +} + +// Checks unit's HP after it was possibly hit by ZoC and deals with the consequences if it's dead. Does nothing if config option to make ZoC lethal +// isn't set or if interceptor is NULL. Returns true if the unit was killed, false otherwise. +bool +check_life_after_zoc (Unit * unit, Unit * interceptor) +{ + if ((is->current_config.special_zone_of_control_rules & SZOCR_LETHAL) && (interceptor != NULL) && + ((Unit_get_max_hp (unit) - unit->Body.Damage) <= 0)) { + + // Call Unit::score_kill but turn off enslaving if we're configured to stop enslaving after bombardment and the ZoC was performed by + // bombardment, which is always the case for cross-domain ZoC or when bombard str > attack. + UnitType * interceptor_type = &p_bic_data->UnitTypes[interceptor->Body.UnitTypeID]; + if (is->current_config.prevent_enslaving_by_bombardment && + ((p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != interceptor_type->Unit_Class) || + (interceptor_type->Bombard_Strength >= Unit_get_attack_strength (interceptor)))) + is->do_not_enslave_units = true; + Unit_score_kill (interceptor, __, unit, false); + is->do_not_enslave_units = false; + + if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (&p_bic_data->fighter, __, interceptor, unit, true)) + Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, unit, AT_DEATH, false); + + bool prev_always_despawn_passengers = is->always_despawn_passengers; + is->always_despawn_passengers = is_land_transport (unit) && (is->current_config.land_transport_rules & LTR_NO_ESCAPE); + patch_Unit_despawn (unit, __, interceptor->Body.CivID, 0, 0, 0, 0, 0, 0); + is->always_despawn_passengers = prev_always_despawn_passengers; + + return true; + } else + return false; +} + +int __fastcall +patch_Unit_move_to_adjacent_tile (Unit * this, int edx, int neighbor_index, bool param_2, int param_3, byte param_4) +{ + is->moving_unit_to_adjacent_tile = true; + is->move_spend_override_unit = NULL; + is->move_spend_override_value = 0; + + bool const allow_worker_coast = is->current_config.enable_districts && is->current_config.workers_can_enter_coast && is_worker (this); + bool const allow_bridge_walk = is->current_config.enable_districts && + is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land); + bool const allow_canal_sail = is->current_config.enable_districts && + is->current_config.enable_canal_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea); + bool coast_override_active = false; + enum UnitStateType prev_state = this->Body.UnitState; + int prev_container = this->Body.Container_Unit; + bool restore_goto_path = prev_state == UnitState_Go_To; + int prev_path_len = this->Body.path_len; + int prev_path_dest_x = this->Body.path_dest_x; + int prev_path_dest_y = this->Body.path_dest_y; + + if (allow_worker_coast || allow_bridge_walk || allow_canal_sail) { + int nx, ny; + get_neighbor_coords (&p_bic_data->Map, this->Body.X, this->Body.Y, neighbor_index, &nx, &ny); + Tile * dest = tile_at (nx, ny); + if (dest != NULL) { + if (allow_bridge_walk && ! dest->vtable->m35_Check_Is_Water (dest)) { + Tile * src = tile_at (this->Body.X, this->Body.Y); + if ((src != NULL) && (src != p_null_tile)) { + struct district_instance * src_inst = get_district_instance (src); + bool from_bridge = (src_inst != NULL) && + (src_inst->district_id == BRIDGE_DISTRICT_ID) && + district_is_complete (src, src_inst->district_id); + if (from_bridge) { + int move_cost = patch_Trade_Net_get_movement_cost ( + is->trade_net, __, + this->Body.X, this->Body.Y, nx, ny, + this, this->Body.CivID, 0, neighbor_index, NULL); + if (move_cost >= 0) { + int spent_moves = this->Body.Moves + move_cost; + is->move_spend_override_unit = this; + is->move_spend_override_value = not_above (spent_moves, patch_Unit_get_max_move_points (this)); + } + } + } + } + + bool should_override = false; + if (allow_worker_coast && + dest->vtable->m35_Check_Is_Water (dest) && + (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + if (is_human) { + should_override = true; + } else { + struct district_worker_record * rec = get_tracked_worker_record (this); + struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; + if (req != NULL) { + City * req_city = (req->city != NULL) ? req->city : get_city_ptr (req->city_id); + if ((req->district_id >= 0) && + (req->district_id < is->district_count) && + (req_city != NULL) && + city_radius_contains_tile (req_city, nx, ny) && + (req->target_x == nx) && (req->target_y == ny)) { + struct district_config const * cfg = &is->district_configs[req->district_id]; + if ((cfg->buildable_square_types_mask & (1 << SQ_Coast)) != 0) + should_override = true; + } + } + } + } + + if (! should_override && allow_bridge_walk) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && + (inst->district_id == BRIDGE_DISTRICT_ID) && + district_is_complete (dest, inst->district_id)) + should_override = true; + } + + if (! should_override && allow_canal_sail) { + struct district_instance * inst = get_district_instance (dest); + if ((inst != NULL) && + (inst->district_id == CANAL_DISTRICT_ID) && + district_is_complete (dest, inst->district_id)) + should_override = true; + } + + if (should_override) { + coast_override_active = true; + is->coast_walk_unit = this; + is->coast_walk_transport_override = false; + is->coast_walk_prev_state = prev_state; + is->coast_walk_prev_container = prev_container; + is->coast_walk_restore_goto_path = restore_goto_path; + is->coast_walk_prev_path_len = prev_path_len; + is->coast_walk_prev_path_dest_x = prev_path_dest_x; + is->coast_walk_prev_path_dest_y = prev_path_dest_y; + } + } + } + + is->zoc_interceptor = is->zoc_defender = NULL; + int tr = Unit_move_to_adjacent_tile (this, __, neighbor_index, param_2, param_3, param_4); + if ((this == is->zoc_defender) && check_life_after_zoc (this, is->zoc_interceptor)) + tr = ! is_online_game (); // This is what the original method returns when the unit was destroyed in combat + + if (coast_override_active) { + is->coast_walk_unit = NULL; + is->coast_walk_transport_override = false; + + if (this->Body.Container_Unit == this->Body.ID) { + this->Body.Container_Unit = is->coast_walk_prev_container; + Unit_set_state (this, __, is->coast_walk_prev_state); + if (is->coast_walk_restore_goto_path) { + this->Body.path_len = is->coast_walk_prev_path_len; + this->Body.path_dest_x = is->coast_walk_prev_path_dest_x; + this->Body.path_dest_y = is->coast_walk_prev_path_dest_y; + } + } + } + + is->temporarily_disallow_lethal_zoc = false; + is->moving_unit_to_adjacent_tile = false; + is->move_spend_override_unit = NULL; + is->move_spend_override_value = 0; + return tr; +} + +void __fastcall +patch_Unit_load_into_army_after_move_to_adj_tile (Unit * this, int edx, Unit * loadee) +{ + // Take care not to load an army into itself b/c that will cause the game to crash. The game may attempt to do that at the end of + // move_to_adjacent_tile b/c we return the unit itself as a transport target when we want to allow it to move onto coast. + if (is->coast_walk_transport_override && this == loadee) + return; + + Unit_load_into_army (this, __, loadee); +} + +int __fastcall +patch_Unit_teleport (Unit * this, int edx, int tile_x, int tile_y, Unit * unit_telepad) +{ + is->zoc_interceptor = NULL; + int tr = Unit_teleport (this, __, tile_x, tile_y, unit_telepad); + check_life_after_zoc (this, is->zoc_interceptor); + return tr; +} + +bool +can_do_defensive_bombard (Unit * unit, UnitType * type) +{ + if ((type->Bombard_Strength > 0) && (! Unit_has_ability (unit, __, UTA_Cruise_Missile))) { + if (cannot_defend_inside_transport (unit)) + return false; + + if ((unit->Body.Status & USF_USED_DEFENSIVE_BOMBARD) == 0) // has not already done DB this turn + return true; + + // If the "blitz" special DB rule is activated and this unit has blitz, check if it still has an extra DB to use + else if ((is->current_config.special_defensive_bombard_rules & SDBR_BLITZ) && UnitType_has_ability (type, __, UTA_Blitz)) { + int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, unit->Body.ID, 0); + return type->Movement > extra_dbs + 1; + + } else + return false; + } else + return false; +} + +Unit * __fastcall +patch_Fighter_find_defensive_bombarder (Fighter * this, int edx, Unit * attacker, Unit * defender) +{ + int special_db_rules = is->current_config.special_defensive_bombard_rules; + if ((special_db_rules == 0) && + ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) == 0) && + ((is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) == 0)) + return Fighter_find_defensive_bombarder (this, __, attacker, defender); + else { + enum UnitTypeClasses attacker_class = p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class; + int attacker_has_one_hp = Unit_get_max_hp (attacker) - attacker->Body.Damage <= 1; + + Tile * defender_tile = tile_at (defender->Body.X, defender->Body.Y); + if ((Unit_get_defense_strength (attacker) < 1) || // if attacker cannot defend OR + (defender_tile == NULL) || (defender_tile == p_null_tile) || // defender tile is invalid OR + (((special_db_rules & SDBR_LETHAL) == 0) && attacker_has_one_hp) || // (DB is non-lethal AND attacker has one HP remaining) OR + ((special_db_rules & SDBR_NOT_INVISIBLE) && ! patch_Unit_is_visible_to_civ (attacker, __, defender->Body.CivID, 1))) // (invisible units are immune to DB AND attacker is invisible) + return NULL; + + Unit * tr = NULL; + int highest_strength = -1; + enum UnitTypeAbilities lethal_bombard_req = (attacker_class == UTC_Sea) ? UTA_Lethal_Sea_Bombardment : UTA_Lethal_Land_Bombardment; + FOR_UNITS_ON (uti, defender_tile) { + Unit * candidate = uti.unit; + UnitType * candidate_type = &p_bic_data->UnitTypes[candidate->Body.UnitTypeID]; + if (can_do_defensive_bombard (candidate, candidate_type) && + (candidate_type->Bombard_Strength > highest_strength) && + (candidate != defender) && + (Unit_get_containing_army (candidate) != defender) && + ((attacker_class == candidate_type->Unit_Class) || + ((special_db_rules & SDBR_AERIAL) && + (candidate_type->Unit_Class == UTC_Air) && + (candidate_type->Air_Missions & UCV_Bombing)) || + ((special_db_rules & SDBR_DOCKED_VS_LAND) && + (candidate_type->Unit_Class == UTC_Sea) && + (get_city_ptr (defender_tile->CityID) != NULL))) && + ((! attacker_has_one_hp) || UnitType_has_ability (candidate_type, __, lethal_bombard_req))) { + tr = candidate; + highest_strength = candidate_type->Bombard_Strength; + } + } + return tr; + } +} + +void __fastcall +patch_Fighter_damage_by_db_in_main_loop (Fighter * this, int edx, Unit * bombarder, Unit * defender) +{ + if (p_bic_data->UnitTypes[bombarder->Body.UnitTypeID].Unit_Class == UTC_Air) { + if (Unit_try_flying_over_tile (bombarder, __, defender->Body.X, defender->Body.Y)) + return; // intercepted + else if (patch_Main_Screen_Form_is_unit_visible_to_player (p_main_screen_form, __, defender->Body.X, defender->Body.Y, bombarder)) + Unit_play_bombing_animation (bombarder, __, defender->Body.X, defender->Body.Y); + } + + // If the unit has already performed DB this turn, then record that it's consumed one of its extra DBs + if (bombarder->Body.Status & USF_USED_DEFENSIVE_BOMBARD) { + int extra_dbs = itable_look_up_or (&is->extra_defensive_bombards, bombarder->Body.ID, 0); + itable_insert (&is->extra_defensive_bombards, bombarder->Body.ID, extra_dbs + 1); + } + + int damage_before = defender->Body.Damage; + Fighter_damage_by_defensive_bombard (this, __, bombarder, defender); + int damage_after = defender->Body.Damage; + + is->dbe.bombarder = bombarder; + is->dbe.defender = defender; + if (damage_after > damage_before) { + is->dbe.damage_done = true; + int max_hp = Unit_get_max_hp (defender); + int dead_before = damage_before >= max_hp, dead_after = damage_after >= max_hp; + + // If the unit was killed by defensive bombard, play its death animation then toggle off animations for the rest of the combat so it + // doesn't look like anything else happens. Technically, the combat continues and the dead unit is guarantted to lose because the + // patch to get_combat_odds ensures the dead unit has no chance of winning a round. + if (dead_before ^ dead_after) { + is->dbe.defender_was_destroyed = true; + if ((! is_online_game ()) && Fighter_check_combat_anim_visibility (this, __, bombarder, defender, true)) + Animator_play_one_shot_unit_animation (&p_main_screen_form->animator, __, defender, AT_DEATH, false); + is->dbe.saved_animation_setting = this->play_animations; + this->play_animations = 0; + } + } +} + +int __fastcall +patch_Fighter_get_odds_for_main_combat_loop (Fighter * this, int edx, Unit * attacker, Unit * defender, bool bombarding, bool ignore_defensive_bonuses) +{ + if (is->dbe.defender_was_destroyed) + return 1025; + + struct c3x_config * cfg = &is->current_config; + // Only OR in counter-rule terrain skipping when we actually ran apply_counter_rules for this + // call. Otherwise counter_combat_ctx.ignore_terrain can be stale from an earlier probe (e.g. + // find_civ4_best_defender_against) or an earlier combat round — especially risky after + // merges that add new odds call sites. + bool ignore_terrain_for_odds = ignore_defensive_bonuses; + if (cfg->enable_unit_counters && attacker != NULL && defender != NULL) { + Tile * def_tile = tile_at (this->defender_location_x, + this->defender_location_y); + int aa, dd; + bool ignore_terrain; + apply_counter_rules (cfg, attacker, defender, def_tile, + &aa, &dd, &ignore_terrain); + + is->counter_combat_ctx.active = true; + is->counter_combat_ctx.attacker = attacker; + is->counter_combat_ctx.defender = defender; + is->counter_combat_ctx.attacker_atk_pct = aa; + is->counter_combat_ctx.defender_def_pct = dd; + is->counter_combat_ctx.ignore_terrain = ignore_terrain; + ignore_terrain_for_odds = ignore_defensive_bonuses || ignore_terrain; + } + + int result = Fighter_get_combat_odds (this, __, attacker, defender, bombarding, + ignore_terrain_for_odds); + is->counter_combat_ctx.active = false; + return result; +} + +// Civ 4-style best defender: On the specified tile, pick the defender that is hardest for the +// attacker to beat (i.e. the one with the highest *defender* win rate against the attacker). +// Takes unit counter rules into account. Returns NULL if there is no suitable defender. +// +// IMPORTANT — odds semantics: vanilla Fighter_get_combat_odds returns the *defender*'s win +// chance (out of ~1024), not the attacker's. Confirmed by the existing patch at +// patch_Fighter_get_odds_for_main_combat_loop: when the attacker has been killed by defensive +// bombardment ("defender_was_destroyed"), the patch returns 1025 so the still-running combat +// loop sees ~100% defender win chance and finishes off the doomed attacker. Therefore "hardest +// to beat" = "highest defender win chance" = max odds. +// +// Notes: +// - Skips units with Container_Unit >= 0 (units inside armies/transports; only the top unit represents the group). +// - Skips units not visible to the attacker's civ, avoiding revealing invisible units. +// - Skips units of the same civ as the attacker (they cannot defend). +// - Skips units with defense strength <= 0 (incapable of combat). +// - Temporarily overwrites is->counter_combat_ctx internally and saves/restores the context before/after execution, +// to avoid disrupting the actual combat odds context. +Unit * +find_civ4_best_defender_against (Unit * attacker, Tile * tile, int tile_x, int tile_y) +{ + if ((attacker == NULL) || (tile == NULL) || (tile == p_null_tile)) + return NULL; + + // Defensive: validate attacker shape before we deref any of its fields downstream. If the + // pointer is stale or refers to a half-initialized unit, UnitTypeID will be out of range and + // we bail out instead of crashing inside Fighter_get_combat_odds / vtable calls. + int atk_tid = attacker->Body.UnitTypeID; + if ((atk_tid < 0) || (atk_tid >= p_bic_data->UnitTypeCount)) + return NULL; + + struct c3x_config * cfg = &is->current_config; + int attacker_civ = attacker->Body.CivID; + + // Backup the current counter ctx, as we'll be repeatedly overwriting it within the loop. + bool saved_active = is->counter_combat_ctx.active; + Unit * saved_attacker = is->counter_combat_ctx.attacker; + Unit * saved_defender = is->counter_combat_ctx.defender; + int saved_attacker_atk = is->counter_combat_ctx.attacker_atk_pct; + int saved_defender_def = is->counter_combat_ctx.defender_def_pct; + bool saved_ignore_terrain = is->counter_combat_ctx.ignore_terrain; + + // Backup the live Fighter struct fields. Vanilla Fighter_get_combat_odds may consult + // fighter.attacker / fighter.defender / fighter.defender_location_x/y to fetch terrain or + // state; if those still point at units from a previous combat (or are NULL during init), the + // vanilla code can dereference garbage and crash. We point them at the current candidate + // inside the loop and restore the originals at the end. + Unit * saved_fighter_attacker = p_bic_data->fighter.attacker; + Unit * saved_fighter_defender = p_bic_data->fighter.defender; + int saved_fighter_atk_x = p_bic_data->fighter.attacker_location_x; + int saved_fighter_atk_y = p_bic_data->fighter.attacker_location_y; + int saved_fighter_def_x = p_bic_data->fighter.defender_location_x; + int saved_fighter_def_y = p_bic_data->fighter.defender_location_y; + + Unit * best = NULL; + // We track the maximum defender win rate. Start below any possible result so the first + // eligible candidate always becomes the initial best. + int best_odds = -1; + + FOR_UNITS_ON (uti, tile) { + Unit * d = uti.unit; + if ((d == NULL) || (d == attacker)) + continue; + // Defensive: a unit on the tile_units linked list with an out-of-range type id is almost + // certainly stale or in some half-initialized state — skip it entirely so we never pass it + // to anything that dereferences UnitType. + int dtid = d->Body.UnitTypeID; + if ((dtid < 0) || (dtid >= p_bic_data->UnitTypeCount)) + continue; + if (d->Body.Container_Unit >= 0) + continue; + if (d->Body.CivID == attacker_civ) + continue; + // Must be a true enemy of the attacker (allies/peace treaties). + if (! d->vtable->is_enemy_of_civ (d, __, attacker_civ, 0)) + continue; + if (Unit_get_defense_strength (d) <= 0) + continue; + if (! patch_Unit_is_visible_to_civ (d, __, attacker_civ, 0)) + continue; + + // Apply unit counter multipliers (100 if unit counters are disabled, equivalent to vanilla win rate formula). + int aa = 100, dd = 100; + bool ignore_terrain = false; + if (cfg->enable_unit_counters) + apply_counter_rules (cfg, attacker, d, tile, &aa, &dd, &ignore_terrain); + + is->counter_combat_ctx.active = true; + is->counter_combat_ctx.attacker = attacker; + is->counter_combat_ctx.defender = d; + is->counter_combat_ctx.attacker_atk_pct = aa; + is->counter_combat_ctx.defender_def_pct = dd; + is->counter_combat_ctx.ignore_terrain = ignore_terrain; + + // Point the live Fighter struct at the (attacker, d) pair so the vanilla odds function + // reads valid pointers instead of stale ones. + p_bic_data->fighter.attacker = attacker; + p_bic_data->fighter.defender = d; + p_bic_data->fighter.attacker_location_x = attacker->Body.X; + p_bic_data->fighter.attacker_location_y = attacker->Body.Y; + p_bic_data->fighter.defender_location_x = tile_x; + p_bic_data->fighter.defender_location_y = tile_y; + + // IMPORTANT: vanilla Fighter_get_combat_odds reads attack/defense values directly from + // UnitType.Attack and UnitType.Defence — it does NOT route through Unit_get_attack/defense_strength + // in a way that this mod has hooked (Unit_get_defense_strength is not registered in + // civ_prog_objects.csv as an inlead, so patch_Unit_get_defense_strength never gets called from + // inside vanilla odds computation). To make our counter multipliers actually affect the odds we + // compute here, we monkey-patch the UnitType fields for the duration of the call and restore + // them immediately after. This is single-threaded mod code and the call window is microseconds, + // so no other reader can observe the temporary values. + UnitType * a_type = &p_bic_data->UnitTypes[atk_tid]; + UnitType * d_type = &p_bic_data->UnitTypes[dtid]; + int saved_a_attack = a_type->Attack; + int saved_d_defence = d_type->Defence; + if (aa != 100) + a_type->Attack = (saved_a_attack * aa) / 100; + if (dd != 100) + d_type->Defence = (saved_d_defence * dd) / 100; + + int odds = Fighter_get_combat_odds (&p_bic_data->fighter, __, attacker, d, false, ignore_terrain); + + a_type->Attack = saved_a_attack; + d_type->Defence = saved_d_defence; + + // odds = defender's win chance (see comment above the function). We want the candidate + // that is hardest for the attacker to beat, i.e. the one with the *highest* odds. + bool replace; + if (best == NULL) { + replace = true; + } else if (odds > best_odds) { + replace = true; + } else if (odds < best_odds) { + replace = false; + } else { + // Odds tie. Defer to vanilla's own defender comparator (cheaper-cost-defends-first + // etc.) — but we must give it the *effective* defense of each candidate against + // this attacker, otherwise it would compare base defenses (e.g. Swordsman base 2 vs + // Musketman base 4) and pick Musketman immediately, never reaching the cost + // tie-break that should decide between two units that are effectively equally hard + // to beat (Swordsman with a x2 counter has effective def 4, equal to Musketman's + // base 4 — vanilla's tie-break should then prefer the cheaper Swordsman). + // + // We can't rely on counter_combat_ctx flowing through Unit_get_defense_strength + // here (see the long comment above the odds call: the patch isn't actually hooked + // into vanilla code). So we apply the multiplier ourselves on top of whatever + // Unit_get_defense_strength returns for each candidate. + int best_aa = 100, best_dd = 100; + bool best_ignore = false; + if (cfg->enable_unit_counters) + apply_counter_rules (cfg, attacker, best, tile, &best_aa, &best_dd, &best_ignore); + + int d_def = (Unit_get_defense_strength (d) * dd ) / 100; + int best_def = (Unit_get_defense_strength (best) * best_dd) / 100; + + replace = Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, + d, d_def, best, best_def, true); + } + if (replace) { + best = d; + best_odds = odds; + } + } + + is->counter_combat_ctx.active = saved_active; + is->counter_combat_ctx.attacker = saved_attacker; + is->counter_combat_ctx.defender = saved_defender; + is->counter_combat_ctx.attacker_atk_pct = saved_attacker_atk; + is->counter_combat_ctx.defender_def_pct = saved_defender_def; + is->counter_combat_ctx.ignore_terrain = saved_ignore_terrain; + + // Restore the live Fighter struct so we don't leave it pointing at our probe values when a + // real combat (or other code path that reads it) starts. + p_bic_data->fighter.attacker = saved_fighter_attacker; + p_bic_data->fighter.defender = saved_fighter_defender; + p_bic_data->fighter.attacker_location_x = saved_fighter_atk_x; + p_bic_data->fighter.attacker_location_y = saved_fighter_atk_y; + p_bic_data->fighter.defender_location_x = saved_fighter_def_x; + p_bic_data->fighter.defender_location_y = saved_fighter_def_y; + + return best; +} + +byte __fastcall +patch_Fighter_fight (Fighter * this, int edx, Unit * attacker, + int attack_direction, Unit * defender_or_null) +{ + // Civ 4-style best defender: compute the defender from the target tile (neighbor of the + // attacker) using counter-aware odds, then use that unit for combat. + // + // Vanilla usually *pre-resolves* a defender and passes it non-NULL. That selection uses base + // UnitType stats (and cost tie-breaks), not our counter rules — so combat could hit Musketman + // while Main_Screen_Form_find_visible_unit (which always calls find_civ4_best_defender_against) + // showed Swordsman. We therefore apply our pick whenever the attack is a normal 8-neighbor + // strike and either no defender was passed, or the passed defender still sits on the target + // tile (vanilla's stack defender). If vanilla passes a defender on some other tile, leave it + // alone (unusual / non-adjacent paths). + if (is->current_config.use_civ4_style_best_defender && + is->current_config.enable_unit_counters && + (attacker != NULL) && + // Strict guard: attack_direction must be a valid 8-neighbor index. Some non-combat code + // paths call Fighter_fight with sentinel values (-1 etc.); forwarding those into + // neighbor_index_to_diff would produce a junk target tile and crash. + (attack_direction >= 0) && (attack_direction < 8)) { + int dx = 0, dy = 0; + neighbor_index_to_diff (attack_direction, &dx, &dy); + // Belt-and-braces: dx/dy must lie on the 8-neighbor lattice. + if ((dx >= -1) && (dx <= 1) && (dy >= -1) && (dy <= 1) && ((dx != 0) || (dy != 0))) { + int target_x = attacker->Body.X + dx; + int target_y = attacker->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &target_x, &target_y); + Tile * target_tile = tile_at (target_x, target_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + bool vanilla_defender_on_target = + (defender_or_null != NULL) && + (defender_or_null->Body.X == target_x) && + (defender_or_null->Body.Y == target_y); + if ((defender_or_null == NULL) || vanilla_defender_on_target) { + Unit * picked = find_civ4_best_defender_against (attacker, target_tile, target_x, target_y); + if (picked != NULL) + defender_or_null = picked; + } + } + } + } + + byte tr = Fighter_fight (this, __, attacker, attack_direction, + defender_or_null); + is->dbe = (struct defensive_bombard_event) {0}; + is->counter_combat_ctx.active = false; + return tr; +} + +int __fastcall +patch_Unit_get_attack_strength (Unit * this) +{ + int base = Unit_get_attack_strength (this); + if (! is->counter_combat_ctx.active) + return base; + if (this == is->counter_combat_ctx.attacker) + return base * is->counter_combat_ctx.attacker_atk_pct / 100; + return base; +} + +int __fastcall +patch_Unit_get_defense_strength (Unit * this) +{ + int base = Unit_get_defense_strength (this); + if (! is->counter_combat_ctx.active) + return base; + if (this == is->counter_combat_ctx.defender) + return base * is->counter_combat_ctx.defender_def_pct / 100; + return base; +} + +void __fastcall +patch_Unit_score_kill_by_defender (Unit * this, int edx, Unit * victim, bool was_attacking) +{ + // This function is called when the defender wins in combat. If the attacker was actually killed by defensive bombardment, then award credit + // for that kill to the defensive bombarder not the defender in combat. + if (is->dbe.defender_was_destroyed) { + is->do_not_enslave_units = is->current_config.prevent_enslaving_by_bombardment; + Unit_score_kill (is->dbe.bombarder, __, victim, was_attacking); + is->do_not_enslave_units = false; + p_bic_data->fighter.play_animations = is->dbe.saved_animation_setting; + + } else + Unit_score_kill (this, __, victim, was_attacking); +} + +void __fastcall +patch_Unit_play_attack_anim_for_def_bombard (Unit * this, int edx, int direction) +{ + // Don't play any animation for air units, the animations are instead handled in the patch for damage_by_defensive_bombard + if (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class != UTC_Air) { + + // Make sure the unit is displayed if it's in an army and we're configured for that + struct unit_display_override saved_udo = is->unit_display_override; + Unit * container; + if (is->current_config.show_armies_performing_defensive_bombard && + (container = get_unit_ptr (this->Body.Container_Unit)) != NULL && + Unit_has_ability (container, __, UTA_Army)) + is->unit_display_override = (struct unit_display_override) { this->Body.ID, this->Body.X, this->Body.Y }; + + Unit_play_attack_animation (this, __, direction); + + is->unit_display_override = saved_udo; + } +} + +bool +can_precision_strike_tile_improv_at (Unit * unit, int x, int y) +{ + Tile * tile; + return is->current_config.allow_precision_strikes_against_tile_improvements && // we're configured to allow prec. strikes vs tiles AND + ((tile = tile_at (x, y)) != p_null_tile) && // get tile, make sure it's valid AND + is_explored (tile, unit->Body.CivID) && // tile has been explored by attacker AND + has_any_destructible_overlays (tile, true); // it has something that can be destroyed by prec. strike +} + +// Same as above function except this one applies to the V3 field instead of FOWStatus +Tile * __cdecl +patch_tile_at_for_v3_check (int x, int y) +{ + Tile * tile = tile_at (x, y); + int is_hotseat_game = *p_is_offline_mp_game && ! *p_is_pbem_game; + if (is_hotseat_game && is->current_config.share_visibility_in_hotseat) { + is->dummy_tile->Body.V3 = ((tile->Body.V3 & *p_human_player_bits) != 0) << p_main_screen_form->Player_CivID; + return is->dummy_tile; + } else + return tile; +} + +bool __fastcall +patch_Unit_check_contact_bit_6_on_right_click (Unit * this, int edx, int civ_id) +{ + bool tr = Unit_check_contact_bit_6 (this, __, civ_id); + if ((! tr) && + is->current_config.share_visibility_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << civ_id) & *p_human_player_bits)) { // is civ_id a human player + if ((1 << this->Body.CivID) & *p_human_player_bits) + tr = true; + + else { + // Check if any other human player has contact + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != civ_id) && + Unit_check_contact_bit_6 (this, __, n_player)) { + tr = true; + break; + } + player_bits >>= 1; + n_player++; + } + } + } + return tr; +} + +bool __fastcall +patch_Unit_check_precision_strike_target (Unit * this, int edx, int tile_x, int tile_y) +{ + return Unit_check_precision_strike_target (this, __, tile_x, tile_y) || can_precision_strike_tile_improv_at (this, tile_x, tile_y); +} + +void __fastcall +patch_Unit_play_attack_animation_vs_tile (Unit * this, int edx, int direction) +{ + if (is->current_config.polish_precision_striking && + UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile) && + (is->attacking_tile_x != this->Body.X) && (is->attacking_tile_y != this->Body.Y)) + Unit_animate_cruise_missile_strike (this, __, is->attacking_tile_x, is->attacking_tile_y); + else + Unit_play_attack_animation (this, __, direction); +} + +void __fastcall +patch_Unit_attack_tile (Unit * this, int edx, int x, int y, int bombarding) +{ + Tile * target_tile = NULL; + bool had_district_before = false; + int district_id_before = -1; + int tile_x = x; + int tile_y = y; + + if (is->current_config.enable_districts) { + + // Check if this is a completed wonder district that cannot be destroyed + if (is->current_config.enable_wonder_districts && + !is->current_config.completed_wonder_districts_can_be_destroyed) { + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + target_tile = tile_at (tile_x, tile_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + struct wonder_district_info * info = get_wonder_district_info (target_tile); + if (info != NULL && info->state == WDS_COMPLETED) { + // This tile has a completed wonder district and they can't be destroyed + if (((*p_human_player_bits & (1 << this->Body.CivID)) != 0) && + (this->Body.CivID == p_main_screen_form->Player_CivID)) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CANT_PILLAGE", -1, 0, 0, 0); + patch_show_popup (popup, __, 0, 0); + } + return; + } + } + } + + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + target_tile = tile_at (tile_x, tile_y); + if ((target_tile != NULL) && (target_tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (target_tile); + if (inst != NULL) { + had_district_before = true; + district_id_before = inst->district_id; + } + } + } + + is->attacking_tile_x = x; + is->attacking_tile_y = y; + if (bombarding) + is->unit_bombard_attacking_tile = this; + + Unit_attack_tile (this, __, x, y, bombarding); + + // Check if the district was destroyed by the attack + if (had_district_before && (target_tile != NULL) && (target_tile != p_null_tile) && district_id_before != NATURAL_WONDER_DISTRICT_ID) { + struct district_instance * inst_after = get_district_instance (target_tile); + bool has_district_after = (inst_after != NULL); + int district_id_after = (inst_after != NULL) ? inst_after->district_id : -1; + + // If the district existed before but not after, or the tile no longer has a mine, the district was destroyed + if (!has_district_after || !(target_tile->vtable->m42_Get_Overlays (target_tile, __, 0) & TILE_FLAG_MINE)) { + bool is_water_tile = target_tile != NULL && target_tile->vtable->m35_Check_Is_Water (target_tile); + handle_district_destroyed_by_attack (target_tile, tile_x, tile_y, ! is_water_tile); + } + } + + is->unit_bombard_attacking_tile = NULL; + is->attacking_tile_x = is->attacking_tile_y = -1; +} + +void __fastcall +patch_Unit_do_precision_strike (Unit * this, int edx, int x, int y) +{ + if ((city_at (x, y) == NULL) && can_precision_strike_tile_improv_at (this, x, y)) + patch_Unit_attack_tile (this, __, x, y, 1); + else + Unit_do_precision_strike (this, __, x, y); + + if (is->current_config.polish_precision_striking && + UnitType_has_ability (&p_bic_data->UnitTypes[this->Body.UnitTypeID], __, UTA_Cruise_Missile)) + patch_Unit_despawn (this, __, 0, false, false, 0, 0, 0, 0); +} + +int __fastcall +patch_Unit_get_max_moves_after_barricade_attack (Unit * this) +{ + if (is->current_config.dont_end_units_turn_after_bombarding_barricade && (this == is->unit_bombard_attacking_tile)) + return this->Body.Moves + p_bic_data->General.RoadsMovementRate; + else + return patch_Unit_get_max_move_points (this); +} + +City * __cdecl +patch_city_at_in_find_bombard_defender (int x, int y) +{ + // The caller (Fighter::find_defender_against_bombardment) has a set of lists of bombard priority/eligibility in its stack memory. The list + // for land units bombarding land tiles normally restricts the targets to land units by containing [UTC_Land, -1, -1]. If we're configured to + // remove that restriction, modify the list so it contains instead [UTC_Land, UTC_Sea, UTC_Air]. Conveniently, the offset from this function's + // first parameter to the list is 0x40 bytes in all executables. + if (is->current_config.remove_land_artillery_target_restrictions) { + enum UnitTypeClasses * list = (void *)((byte *)&x + 0x40); + list[1] = UTC_Sea; + list[2] = UTC_Air; + } + + return city_at (x, y); +} + +bool __fastcall +patch_Unit_check_bombard_target (Unit * this, int edx, int tile_x, int tile_y) +{ + bool base = Unit_check_bombard_target (this, __, tile_x, tile_y); + Tile * tile = tile_at (tile_x, tile_y); + int overlays; + + if (base && + itable_look_up_or (&is->current_config.can_bombard_only_sea_tiles, this->Body.UnitTypeID, 0) && + ! tile->vtable->m35_Check_Is_Water (tile)) + return false; + + else if (base && + is->current_config.disallow_useless_bombard_vs_airfields && + ! Unit_has_ability (this, __, UTA_Nuclear_Weapon) && + ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // if tile has an airfield AND + (overlays == 0x20000000)) { // tile only has an airfield + UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + + // Check that a bombard attack vs this tile would not be wasted. It won't be if either (1) there are no units on the tile, (2) there + // is a unit that can be damaged by bombarding, or (3) there are no units that can be damaged and no air units. The rules for + // bombardment are that you can't damage aircraft in an airfield and you also can't destroy an airfield from underneath aircraft. + int any_units = 0, + any_vulnerable_units = 0, + any_air_units = 0; + FOR_UNITS_ON (uti, tile) { + enum UnitTypeClasses class = p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID].Unit_Class; + any_units = 1; + any_air_units |= class == UTC_Air; + any_vulnerable_units |= (class != UTC_Air) && (Unit_get_defense_strength (uti.unit) > 0) && + can_damage_bombarding (this_type, uti.unit, tile); + } + return (! any_units) || // case (1) above + any_vulnerable_units || // case (2) + ((! any_air_units) && (! any_vulnerable_units)); // case (3) + + } else + return base; +} + +bool __fastcall +patch_Unit_can_disembark_anything (Unit * this, int edx, int tile_x, int tile_y) +{ + Tile * this_tile = tile_at (this->Body.X, this->Body.Y); + Tile * target_tile = tile_at (tile_x, tile_y); + bool base = Unit_can_disembark_anything (this, __, tile_x, tile_y); + + // Apply units per tile limit + if (base) { + bool stack_limited_for_all = true; + FOR_UNITS_ON (uti, this_tile) + if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_below_stack_limit (target_tile, this->Body.CivID, uti.unit->Body.UnitTypeID)) { + stack_limited_for_all = false; + break; + } + if (stack_limited_for_all) + return false; + } + + // Apply trespassing restriction. First check if this civ may move into (tile_x, tile_y) without trespassing. If it would be trespassing, then + // we can only disembark anything if this transport has a passenger that can ignore the restriction. Without this check, the game can enter an + // infinite loop under rare circumstances. + if (base && + is->current_config.disallow_trespassing && + check_trespassing (this->Body.CivID, this_tile, target_tile)) { + bool any_exempt_passengers = false; + FOR_UNITS_ON (uti, this_tile) + if ((uti.unit->Body.Container_Unit == this->Body.ID) && is_allowed_to_trespass (uti.unit)) { + any_exempt_passengers = true; + break; + } + return any_exempt_passengers; + + } else + return base; +} + +int __fastcall +patch_Unit_get_defense_for_bombardable_unit_check (Unit * this) +{ + // Returning a defense value of zero indicates this unit is not a target for bombardment. If configured, exclude all air units from + // bombardment so the attacks target tile improvements instead. Do this only if the tile has another improvement in addition to an airfield, + // or we could destroy the airfield itself. + Tile * tile; + int overlays; + if (is->current_config.allow_bombard_of_other_improvs_on_occupied_airfield && // If configured AND + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air) && // "this" is an air unit AND + ((tile = tile_at (this->Body.X, this->Body.Y)) != p_null_tile) && // "this" is on a valid tile AND + ((overlays = tile->vtable->m42_Get_Overlays (tile, __, 0)) & 0x20000000) && // tile has an airfield AND + (overlays != 0x20000000)) // tile does not only have an airfield + return 0; + + else + return Unit_get_defense_strength (this); +} + +void __fastcall +patch_Demographics_Form_m22_draw (Demographics_Form * this) +{ + Demographics_Form_m22_draw (this); + + if (is->current_config.show_total_city_count) { + // There's proably a better way to get the city count, but better safe than sorry. I don't know if it's possible for the city list to + // contain holes so the surest thing is to check every possible ID. + int city_count = 0; { + if (p_cities->Cities != NULL) + for (int n = 0; n <= p_cities->LastIndex; n++) { + City_Body * body = p_cities->Cities[n].City; + city_count += (body != NULL) && ((int)body != offsetof (City, Body)); + } + } + + PCX_Image * canvas = &this->Base.Data.Canvas; + + // Draw backdrop + { + char temp_path[2*MAX_PATH]; + PCX_Image backdrop; + PCX_Image_construct (&backdrop); + get_mod_art_path ("CityCountBackdrop.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&backdrop, __, temp_path, NULL, 0, 0x100, 2); + if (backdrop.JGL.Image != NULL) { + int w = backdrop.JGL.Image->vtable->m54_Get_Width (backdrop.JGL.Image); + PCX_Image_draw_onto (&backdrop, __, canvas, (1024 - w) / 2, 720); + } + backdrop.vtable->destruct (&backdrop, __, 0); + } + + // Draw text on top of the backdrop + char s[100]; + snprintf (s, sizeof s, "%s %d / %d", is->c3x_labels[CL_TOTAL_CITIES], city_count, is->city_limit); + s[(sizeof s) - 1] = '\0'; + PCX_Image_set_text_effects (canvas, __, 0x80000000, -1, 2, 2); // Set text color to black + PCX_Image_draw_centered_text (canvas, __, get_font (14, FSF_NONE), s, 1024/2 - 100, 730, 200, strlen (s)); + } +} + +int __fastcall +patch_Leader_get_optimal_city_number (Leader * this) +{ + if (! is->current_config.strengthen_forbidden_palace_ocn_effect) + return Leader_get_optimal_city_number (this); + else { + int num_sans_fp = Leader_get_optimal_city_number (this), // OCN w/o contrib from num of FPs + fp_count = patch_Leader_count_wonders_with_small_flag (this, __, ITSW_Reduces_Corruption, NULL), + s_diff = p_bic_data->DifficultyLevels[this->player_difficulty].Optimal_Cities, // Difficulty scaling, called "percentage of optimal cities" in the editor + base_ocn = p_bic_data->WorldSizes[p_bic_data->Map.World.World_Size].OptimalCityCount; + return num_sans_fp + (s_diff * fp_count * base_ocn + 50) / 100; // Add 50 to round off + } +} + +int __fastcall +patch_Leader_count_forbidden_palaces_for_ocn (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) +{ + if (! is->current_config.strengthen_forbidden_palace_ocn_effect) + return patch_Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); + else + return 0; // We'll add in the FP effect later with a different weight +} + +void __fastcall +patch_Trade_Net_recompute_city_connections (Trade_Net * this, int edx, int civ_id, bool redo_road_network, byte param_3, int redo_roads_for_city_id) +{ + is->is_computing_city_connections = true; + long long ts_before; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); + + if (is->tnx_init_state == IS_OK) { + if (is->tnx_cache == NULL) { + is->tnx_cache = is->create_tnx_cache (&p_bic_data->Map); + is->set_up_before_building_network (is->tnx_cache); + } else if (! is->keep_tnx_cache) + is->set_up_before_building_network (is->tnx_cache); + } + + Trade_Net_recompute_city_connections (this, __, civ_id, redo_road_network, param_3, redo_roads_for_city_id); + + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; + + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + is->time_spent_computing_city_connections += ts_after - ts_before; + is->count_calls_to_recompute_city_connections++; + is->is_computing_city_connections = false; +} + +void __fastcall +patch_Map_build_trade_network (Map * this) +{ + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) + is->set_up_before_building_network (is->tnx_cache); + is->keep_tnx_cache = true; + Map_build_trade_network (this); + is->keep_tnx_cache = false; + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; +} + +void __fastcall +patch_Trade_Net_recompute_city_cons_and_res (Trade_Net * this, int edx, bool param_1) +{ + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) + is->set_up_before_building_network (is->tnx_cache); + + is->keep_tnx_cache = true; + Trade_Net_recompute_city_cons_and_res (this, __, param_1); + is->keep_tnx_cache = false; + + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) + is->distribution_hub_totals_dirty = true; +} + +int __fastcall +patch_Trade_Net_set_unit_path_to_fill_road_net (Trade_Net * this, int edx, int from_x, int from_y, int to_x, int to_y, Unit * unit, int civ_id, int flags, int * out_path_length_in_mp) +{ + int tr; + long long ts_before; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_before); + + if ((is->tnx_init_state == IS_OK) && (is->tnx_cache != NULL)) { + is->flood_fill_road_network (is->tnx_cache, from_x, from_y, civ_id); + tr = 0; // Return value is not used by caller anyway + } else + tr = Trade_Net_set_unit_path (this, __, from_x, from_y, to_x, to_y, unit, civ_id, flags, out_path_length_in_mp); + + long long ts_after; + QueryPerformanceCounter ((LARGE_INTEGER *)&ts_after); + is->time_spent_filling_roads += ts_after - ts_before; + return tr; +} + +bool +set_up_gdi_plus () +{ + if (is->gdi_plus.init_state == IS_UNINITED) { + is->gdi_plus.init_state = IS_INIT_FAILED; + is->gdi_plus.gp_graphics = NULL; + + struct startup_input { + UINT32 GdiplusVersion; + void * DebugEventCallback; + BOOL SuppressBackgroundThread; + BOOL SuppressExternalCodecs; + } startup_input = {1, NULL, FALSE, FALSE}; + + is->gdi_plus.module = LoadLibraryA ("gdiplus.dll"); + if (is->gdi_plus.module == NULL) { + MessageBoxA (NULL, "Failed to load gdiplus.dll!", "Error", MB_ICONERROR); + goto end_init; + } + + int (WINAPI * GdiplusStartup) (ULONG_PTR * out_token, struct startup_input *, void * startup_output) = + (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdiplusStartup"); + + is->gdi_plus.CreateFromHDC = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreateFromHDC"); + is->gdi_plus.DeleteGraphics = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeleteGraphics"); + is->gdi_plus.SetSmoothingMode = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetSmoothingMode"); + is->gdi_plus.SetPenDashStyle = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipSetPenDashStyle"); + is->gdi_plus.CreatePen1 = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipCreatePen1"); + is->gdi_plus.DeletePen = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDeletePen"); + is->gdi_plus.DrawLineI = (void *)(*p_GetProcAddress) (is->gdi_plus.module, "GdipDrawLineI"); + if ((is->gdi_plus.CreateFromHDC == NULL) || (is->gdi_plus.DeleteGraphics == NULL) || + (is->gdi_plus.SetSmoothingMode == NULL) || (is->gdi_plus.SetPenDashStyle == NULL) || + (is->gdi_plus.CreatePen1 == NULL) || (is->gdi_plus.DeletePen == NULL) || + (is->gdi_plus.DrawLineI == NULL)) { + MessageBoxA (NULL, "Failed to get GDI+ proc addresses!", "Error", MB_ICONERROR); + goto end_init; + } + + int status = GdiplusStartup (&is->gdi_plus.token, &startup_input, NULL); + if (status != 0) { + char s[200]; + snprintf (s, sizeof s, "Failed to initialize GDI+! Startup status: %d", status); + MessageBoxA (NULL, s, "Error", MB_ICONERROR); + goto end_init; + } + + is->gdi_plus.init_state = IS_OK; + end_init: + ; + } + + return is->gdi_plus.init_state == IS_OK; +} + +int __fastcall +patch_OpenGLRenderer_initialize (OpenGLRenderer * this, int edx, PCX_Image * texture) +{ + if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || + ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) + return OpenGLRenderer_initialize (this, __, texture); + + // Initialize GDI+ instead + else { + if (! set_up_gdi_plus ()) + return 2; + if (is->gdi_plus.gp_graphics != NULL) { + is->gdi_plus.DeleteGraphics (is->gdi_plus.gp_graphics); + is->gdi_plus.gp_graphics = NULL; + } + int status = is->gdi_plus.CreateFromHDC (texture->JGL.Image->DC, &is->gdi_plus.gp_graphics); + if (status == 0) { + is->gdi_plus.SetSmoothingMode (is->gdi_plus.gp_graphics, 4); // 4 = SmoothingModeAntiAlias from GdiPlusEnums.h + return 0; + } else + return 2; + } +} + +void __fastcall +patch_OpenGLRenderer_set_color (OpenGLRenderer * this, int edx, unsigned int rgb555) +{ + // Convert rgb555 to rgb888 + unsigned int rgb888 = 0; { + unsigned int mask = 31; + int shift = 3; + for (int n = 0; n < 3; n++) { + rgb888 |= (rgb555 & mask) << shift; + mask <<= 5; + shift += 3; + } + } + + is->ogl_color = (is->ogl_color & 0xFF000000) | rgb888; + OpenGLRenderer_set_color (this, __, rgb555); +} + +void __fastcall +patch_OpenGLRenderer_set_opacity (OpenGLRenderer * this, int edx, unsigned int alpha) +{ + is->ogl_color = (is->ogl_color & 0x00FFFFFF) | (alpha << 24); + OpenGLRenderer_set_opacity (this, __, alpha); +} + +void __fastcall +patch_OpenGLRenderer_set_line_width (OpenGLRenderer * this, int edx, int width) +{ + is->ogl_line_width = width; + OpenGLRenderer_set_line_width (this, __, width); +} + +void __fastcall +patch_OpenGLRenderer_enable_line_dashing (OpenGLRenderer * this) +{ + is->ogl_line_stipple_enabled = true; + OpenGLRenderer_enable_line_dashing (this); +} + +void __fastcall +patch_OpenGLRenderer_disable_line_dashing (OpenGLRenderer * this) +{ + is->ogl_line_stipple_enabled = false; + OpenGLRenderer_disable_line_dashing (this); +} + +void __fastcall +patch_OpenGLRenderer_draw_line (OpenGLRenderer * this, int edx, int x1, int y1, int x2, int y2) +{ + if ((is->current_config.draw_lines_using_gdi_plus == LDO_NEVER) || + ((is->current_config.draw_lines_using_gdi_plus == LDO_WINE) && ! is->running_on_wine)) + OpenGLRenderer_draw_line (this, __, x1, y1, x2, y2); + + else if ((is->gdi_plus.init_state == IS_OK) && (is->gdi_plus.gp_graphics != NULL)) { + void * gp_pen; + int unit_world = 0; // = UnitWorld from gdiplusenums.h + int status = is->gdi_plus.CreatePen1 (is->ogl_color, (float)is->ogl_line_width, unit_world, &gp_pen); + if (status == 0) { + if (is->ogl_line_stipple_enabled) + is->gdi_plus.SetPenDashStyle (gp_pen, 1); // 1 = DashStyleDash from GdiPlusEnums.h + is->gdi_plus.DrawLineI (is->gdi_plus.gp_graphics, gp_pen, x1, y1, x2, y2); + is->gdi_plus.DeletePen (gp_pen); + } + } +} + +int __fastcall +patch_Tile_check_water_for_retreat_on_defense (Tile * this) +{ + Unit * defender = p_bic_data->fighter.defender; + + // Under the standard game rules, defensively retreating onto a water tile is not allowed. Set retreat_blocked to true if "this" is a water + // tile and we're not configured to allow retreating onto water tiles. + bool retreat_blocked; { + if (this->vtable->m35_Check_Is_Water (this)) { + if ( is->current_config.allow_defensive_retreat_on_water + && defender != NULL + && p_bic_data->UnitTypes[defender->Body.UnitTypeID].Unit_Class == UTC_Sea + && ( is->current_config.limit_defensive_retreat_on_water_to_types.len == 0 + || (bool)itable_look_up_or (&is->current_config.limit_defensive_retreat_on_water_to_types, defender->Body.UnitTypeID, 0))) + retreat_blocked = false; + else + retreat_blocked = true; + } else + retreat_blocked = false; + } + + // Check stack limit + if ((! retreat_blocked) && + (defender != NULL) && + ! is_below_stack_limit (this, defender->Body.CivID, defender->Body.UnitTypeID)) + retreat_blocked = true; + + // The return from this call is only used to filter the given tile as a possible retreat destination based on whether it's water or not + return (int)retreat_blocked; +} + +int __fastcall +patch_City_count_airports_for_airdrop (City * this, int edx, enum ImprovementTypeFlags airport_flag) +{ + if (is->current_config.allow_airdrop_without_airport) + return 1; + else + return City_count_improvements_with_flag (this, __, airport_flag); +} + +int __fastcall +patch_Leader_get_cont_city_count_for_worker_req (Leader * this, int edx, int cont_id) +{ + int tr = Leader_get_city_count_on_continent (this, __, cont_id); + if (is->current_config.ai_worker_requirement_percent != 100) + tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; + return tr; +} + +int __fastcall +patch_Leader_get_city_count_for_worker_prod_cap (Leader * this) +{ + int tr = this->Cities_Count; + // Don't scale down the cap since it's pretty low to begin with + if (is->current_config.ai_worker_requirement_percent > 100) + tr = (tr * is->current_config.ai_worker_requirement_percent + 50) / 100; + return tr; +} + +// If "only_improv_id" is >= 0, will only return yields from mills attached to that improv, otherwise returns all yields from all improvs +void +gather_mill_yields (City * city, int only_improv_id, int * out_food, int * out_shields, int * out_commerce) +{ + int food = 0, shields = 0, commerce = 0; + for (int n = 0; n < is->current_config.count_mills; n++) { + struct mill * mill = &is->current_config.mills[n]; + if ((mill->flags & MF_YIELDS) && + ((only_improv_id < 0) || (mill->improv_id == only_improv_id)) && + can_generate_resource (city->Body.CivID, mill) && + has_active_building (city, mill->improv_id) && + has_resources_required_by_building (city, mill->improv_id)) { + Resource_Type * res = &p_bic_data->ResourceTypes[mill->resource_id]; + food += res->Food; + shields += res->Shield; + commerce += res->Commerce; + } + } + *out_food = food; + *out_shields = shields; + *out_commerce = commerce; +} + +int __fastcall +patch_City_calc_tile_yield_while_gathering (City * this, int edx, YieldKind kind, int tile_x, int tile_y) +{ + int tr = City_calc_tile_yield_at (this, __, kind, tile_x, tile_y); + + // Include yields from generated resources + if ((this->Body.X == tile_x) && (this->Body.Y == tile_y)) { + int mill_food, mill_shields, mill_commerce; + gather_mill_yields (this, -1, &mill_food, &mill_shields, &mill_commerce); + if (kind == YK_FOOD) tr += mill_food; + else if (kind == YK_SHIELDS) tr += mill_shields; + else if (kind == YK_COMMERCE) tr += mill_commerce; + + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + int bonus_food = 0, bonus_shields = 0, bonus_gold = 0; + calculate_city_center_district_bonus (this, &bonus_food, &bonus_shields, &bonus_gold); + if (kind == YK_FOOD) tr += bonus_food; + else if (kind == YK_SHIELDS) tr += bonus_shields; + else if (kind == YK_COMMERCE) tr += bonus_gold; + } + } + + return tr; +} + +bool __fastcall +patch_Leader_record_export (Leader * this, int edx, int importer_civ_id, int resource_id) +{ + bool exported = Leader_record_export (this, __, importer_civ_id, resource_id); + if (exported && + (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill + is->must_recompute_resources_for_mill_inputs = true; + return exported; +} + +bool __fastcall +patch_Leader_erase_export (Leader * this, int edx, int importer_civ_id, int resource_id) +{ + bool erased = Leader_erase_export (this, __, importer_civ_id, resource_id); + if (erased && + (is->mill_input_resource_bits[resource_id>>3] & (1 << (resource_id & 7)))) // if the traded resource is an input to any mill + is->must_recompute_resources_for_mill_inputs = true; + return erased; +} + +int __fastcall +patch_Sprite_draw_improv_img_on_city_form (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int tr = Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); + + int generated_resources[16]; + int generated_resource_count = 0; + for (int n = 0; (n < is->current_config.count_mills) && (generated_resource_count < ARRAY_LEN (generated_resources)); n++) { + struct mill * mill = &is->current_config.mills[n]; + if ((mill->improv_id == is->drawing_icons_for_improv_id) && + ((mill->flags & MF_SHOW_BONUS) || (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus)) && + (! ((mill->flags & MF_HIDE_NON_BONUS) && (p_bic_data->ResourceTypes[mill->resource_id].Class != RC_Bonus))) && + can_generate_resource (p_city_form->CurrentCity->Body.CivID, mill) && + has_active_building (p_city_form->CurrentCity, mill->improv_id) && + has_resources_required_by_building (p_city_form->CurrentCity, mill->improv_id)) + generated_resources[generated_resource_count++] = mill->resource_id; + } + + if ((generated_resource_count > 0) && (is->resources_sheet != NULL) && (is->resources_sheet->JGL.Image != NULL) && (TransparentBlt != NULL)) { + JGL_Image * jgl_canvas = canvas->JGL.Image, + * jgl_sheet = is->resources_sheet->JGL.Image; + + HDC canvas_dc = jgl_canvas->vtable->acquire_dc (jgl_canvas); + if (canvas_dc != NULL) { + HDC sheet_dc = jgl_sheet->vtable->acquire_dc (jgl_sheet); + if (sheet_dc != NULL) { + + for (int n = 0; n < generated_resource_count; n++) { + int icon_id = p_bic_data->ResourceTypes[generated_resources[n]].IconID, + sheet_row = icon_id / 6, + sheet_col = icon_id % 6; + + int dy = (n * 160 / not_below (1, generated_resource_count - 1) + 5) / 10; + TransparentBlt (canvas_dc, // dest DC + pixel_x + 15, pixel_y + dy, 24, 24, // dest x, y, width, height + sheet_dc, // src DC + 9 + 50*sheet_col, 9 + 50*sheet_row, 33, 33, // src x, y, width, height + 0xFF00FF); // transparent color (RGB) + } + + jgl_sheet->vtable->release_dc (jgl_sheet, __, 1); + } + jgl_canvas->vtable->release_dc (jgl_canvas, __, 1); + } + } + return tr; +} + +void __cdecl +patch_draw_improv_icons_on_city_screen (Base_List_Control * control, int improv_id, int item_index, int offset_x, int offset_y) +{ + is->drawing_icons_for_improv_id = improv_id; + draw_improv_icons_on_city_screen (control, improv_id, item_index, offset_x, offset_y); + is->drawing_icons_for_improv_id = -1; +} + +int __fastcall +patch_City_get_tourism_amount_to_draw (City * this, int edx, int improv_id) +{ + is->tourism_icon_counter = 0; + + int mill_food, mill_shields, mill_commerce; + gather_mill_yields (this, improv_id, &mill_food, &mill_shields, &mill_commerce); + int combined_commerce = mill_commerce + City_get_tourism_amount (this, __, improv_id); + + is->convert_displayed_tourism_to_food = mill_food; + is->convert_displayed_tourism_to_shields = mill_shields; + is->combined_tourism_and_mill_commerce = combined_commerce; + return int_abs (mill_food) + int_abs (mill_shields) + int_abs (combined_commerce); +} + +int __fastcall +patch_Sprite_draw_tourism_gold (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + // Replace the yield sprite we're drawing with food or a shield if needed. + Sprite * sprite = NULL; { + if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food)) { + if (is->convert_displayed_tourism_to_food >= 0) + sprite = &p_city_form->City_Icons_Images.Icon_15_Food; + else { + init_red_food_icon (); + if (is->red_food_icon_state == IS_OK) + sprite = &is->red_food_icon; + } + } else if (is->tourism_icon_counter < int_abs (is->convert_displayed_tourism_to_food) + int_abs (is->convert_displayed_tourism_to_shields)) + sprite = (is->convert_displayed_tourism_to_shields >= 0) ? &p_city_form->City_Icons_Images.Icon_13_Shield : &p_city_form->City_Icons_Images.Icon_05_Shield_Outcome; + else if (is->combined_tourism_and_mill_commerce < 0) + sprite = &p_city_form->City_Icons_Images.Icon_17_Gold_Outcome; + else + sprite = this; + } + + int tr = 0; // return value is not used by caller + if (sprite != NULL) + tr = Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, color_table); + is->tourism_icon_counter++; + return tr; +} + +Unit * __fastcall +patch_Leader_spawn_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) +{ + int spawn_x = tile_x, + spawn_y = tile_y; + + if (is->current_config.enable_districts) { + UnitType * type = &p_bic_data->UnitTypes[type_id]; + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities) { + City * spawn_city = city_at (tile_x, tile_y); + if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { + int district_x, district_y; + Tile * district_tile = get_completed_district_tile_for_city (spawn_city, AERODROME_DISTRICT_ID, &district_x, &district_y); + if ((district_tile != NULL) && (district_tile != p_null_tile) && + (district_tile->Territory_OwnerID == this->ID) && + is_below_stack_limit (district_tile, this->ID, type_id)) { + spawn_x = district_x; + spawn_y = district_y; + } + } + } + + if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities) { + City * spawn_city = city_at (tile_x, tile_y); + if ((spawn_city != NULL) && (spawn_city->Body.CivID == this->ID)) { + int district_x, district_y; + Tile * district_tile = get_completed_district_tile_for_city (spawn_city, PORT_DISTRICT_ID, &district_x, &district_y); + if ((district_tile != NULL) && (district_tile != p_null_tile) && + (district_tile->Territory_OwnerID == this->ID) && + is_below_stack_limit (district_tile, this->ID, type_id)) { + spawn_x = district_x; + spawn_y = district_y; + } + } + } + } + + Unit * tr = Leader_spawn_unit (this, __, type_id, spawn_x, spawn_y, barb_tribe_id, id, param_6, leader_kind, race_id); + if (tr != NULL) + change_unit_type_count (this, type_id, 1); + return tr; +} + +Unit * __fastcall +patch_Leader_spawn_captured_unit (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) +{ + Unit * tr = patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); + if ((tr != NULL) && is->moving_unit_to_adjacent_tile) + is->temporarily_disallow_lethal_zoc = true; + return tr; +} + +void __fastcall +patch_Leader_enter_new_era (Leader * this, int edx, bool param_1, bool no_online_sync) +{ + Leader_enter_new_era (this, __, param_1, no_online_sync); + apply_era_specific_names (this); +} + +char * __fastcall +patch_Leader_get_player_title_for_intro_popup (Leader * this) +{ + // Normally the era-specific names are applied later, after game loading is finished, but in this case we apply the player's names ahead of + // time so they appear on the intro popup. "this" will always refer to the human player in this call. + apply_era_specific_names (this); + return Leader_get_title (this); +} + +void __fastcall +patch_City_spawn_unit_if_done (City * this) +{ + bool skip_spawn = false; + + // Apply unit limit. If this city's owner has reached the limit for the unit type it's building then force it to build something else. + int available; + if ((this->Body.Order_Type == COT_Unit) && + get_available_unit_count (&leaders[this->Body.CivID], this->Body.Order_ID, &available) && + (available <= 0)) { + int limited_unit_type_id = this->Body.Order_ID; + + if (*p_human_player_bits & 1<Body.CivID) { + // Find another type ID to build instead of the limited one + int replacement_type_id = -1; { + int limited_unit_strat = p_bic_data->UnitTypes[limited_unit_type_id].AI_Strategy, + shields_in_box = this->Body.StoredProduction; + UnitType * replacement_type; + for (int can_type_id = 0; can_type_id < p_bic_data->UnitTypeCount; can_type_id++) + if (patch_City_can_build_unit (this, __, can_type_id, 1, 0, 0)) { + UnitType * candidate_type = &p_bic_data->UnitTypes[can_type_id]; + + // If we haven't found a replacement yet, use this one + if (replacement_type_id < 0) { + replacement_type_id = can_type_id; + replacement_type = candidate_type; + + // Keep the prev replacement if it doesn't waste shields but this candidate would + } else if ((replacement_type->Cost >= shields_in_box) && (candidate_type->Cost < shields_in_box)) + continue; + + // Keep the prev if it shares an AI strategy with the limited unit but this candidate doesn't + else if (((replacement_type->AI_Strategy & limited_unit_strat) != 0) && + ((candidate_type ->AI_Strategy & limited_unit_strat) == 0)) + continue; + + // At this point we know switching to the candidate would not cause us to waste shields and would not + // give us a worse match role-wise to the original limited unit. So pick it if it's better somehow, + // either a better role match or more expensive. + else if ((candidate_type->Cost > replacement_type->Cost) || + (((replacement_type->AI_Strategy & limited_unit_strat) == 0) && + ((candidate_type ->AI_Strategy & limited_unit_strat) != 0))) { + replacement_type_id = can_type_id; + replacement_type = candidate_type; + } + } + } + + if (replacement_type_id >= 0) { + City_set_production (this, __, COT_Unit, replacement_type_id, false); + if (this->Body.CivID == p_main_screen_form->Player_CivID) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, this->Body.CityName, -1, -1); + set_popup_str_param (1, p_bic_data->UnitTypes[limited_unit_type_id].Name, -1, -1); + int limit = -1; + get_unit_limit (&leaders[this->Body.CivID], limited_unit_type_id, &limit); + set_popup_int_param (2, limit); + set_popup_str_param (3, p_bic_data->UnitTypes[replacement_type_id].Name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_LIMITED_UNIT_CHANGE", -1, 0, 0, 0); + int response = patch_show_popup (popup, __, 0, 0); + if (response == 0) + *p_zoom_to_city_after_update = true; + } + } + + } else { + City_Order order; + patch_City_ai_choose_production (this, __, &order); + City_set_production (this, __, order.OrderType, order.OrderID, false); + } + + // If the player changed production to something other than a unit, don't spawn anything + if (this->Body.Order_Type != COT_Unit) + skip_spawn = true; + + // Just as a final check, if we weren't able to switch production off the limited unit, prevent it from being spawned so the limit + // doesn't get violated. + if ((this->Body.Order_Type == COT_Unit) && (this->Body.Order_ID == limited_unit_type_id)) + skip_spawn = true; + } + + // Check district requirements for air and naval units + if ((! skip_spawn) && (this->Body.Order_Type == COT_Unit) && is->current_config.enable_districts) { + int unit_id = this->Body.Order_ID; + UnitType * type = &p_bic_data->UnitTypes[unit_id]; + bool needs_district = false; + int required_district_id = -1; + + // Air units require aerodrome + if ((type->Unit_Class == UTC_Air) && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (! city_has_required_district (this, AERODROME_DISTRICT_ID))) { + needs_district = true; + required_district_id = AERODROME_DISTRICT_ID; + } + // Naval units require port + else if ((type->Unit_Class == UTC_Sea) && + is->current_config.enable_port_districts && + is->current_config.naval_units_use_port_districts_not_cities && + (! city_has_required_district (this, PORT_DISTRICT_ID))) { + needs_district = true; + required_district_id = PORT_DISTRICT_ID; + } + + if (needs_district) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + + // For AI, redirect to a safe fallback and queue the missing district. + // For humans, this late hook should only veto the spawn and show a warning, + // otherwise the city gets switched off the intended build with no unit spawned. + if (! is_human) { + mark_city_needs_district (this, required_district_id); + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (this, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) + City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); + } + } + + // Show message to human player + if (is_human && (this->Body.CivID == p_main_screen_form->Player_CivID)) { + char msg[160]; + char const * unit_name = type->Name; + char const * district_name = is->district_configs[required_district_id].name; + snprintf (msg, sizeof msg, "%s %s %s", unit_name, is->c3x_labels[CL_CONSTRUCTION_HALTED_DUE_TO_MISSING_DISTRICT], district_name); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (this->Body.X, this->Body.Y, msg, true); + } + + skip_spawn = true; + } + } + + if (! skip_spawn) + City_spawn_unit_if_done (this); +} + +void __fastcall +patch_Leader_upgrade_all_units (Leader * this, int edx, int type_id) +{ + is->penciled_in_upgrade_count = 0; + Leader_upgrade_all_units (this, __, type_id); +} + +void __fastcall +patch_Main_Screen_Form_upgrade_all_units (Main_Screen_Form * this, int edx, int type_id) +{ + is->penciled_in_upgrade_count = 0; + Main_Screen_Form_upgrade_all_units (this, __, type_id); +} + +bool __fastcall +patch_Unit_can_perform_upgrade_all (Unit * this, int edx, int unit_command_value) +{ + bool base = patch_Unit_can_perform_command (this, __, unit_command_value); + + // Deal with unit limits. If the unit type we're upgrading to is limited, we need to pencil in the upgrade to make sure that we don't queue up + // so many upgrades that we exceed the limit. + City * city; + int upgrade_id, available; + if (base && + (is->current_config.unit_limits.len > 0) && + (NULL != (city = city_at (this->Body.X, this->Body.Y))) && + (0 <= (upgrade_id = City_get_upgraded_type_id (city, __, this->Body.UnitTypeID))) && + get_available_unit_count (&leaders[this->Body.CivID], upgrade_id, &available)) { + + // Find penciled in upgrade. Add a new one if we don't already have one. + struct penciled_in_upgrade * piu = NULL; { + for (int n = 0; n < is->penciled_in_upgrade_count; n++) + if (is->penciled_in_upgrades[n].unit_type_id == upgrade_id) { + piu = &is->penciled_in_upgrades[n]; + break; + } + if (piu == NULL) { + reserve (sizeof is->penciled_in_upgrades[0], (void **)&is->penciled_in_upgrades, &is->penciled_in_upgrade_capacity, is->penciled_in_upgrade_count); + piu = &is->penciled_in_upgrades[is->penciled_in_upgrade_count]; + is->penciled_in_upgrade_count += 1; + piu->unit_type_id = upgrade_id; + piu->count = 0; + } + } + + // If we can have more units of the type we're upgrading to, pencil in another upgrade and return true. Otherwise return false so this + // unit isn't considered one of the upgradable ones. + if (piu->count < available) { + piu->count += 1; + return true; + } else + return false; + + } else + return base; +} + +void __fastcall +patch_Fighter_animate_start_of_combat (Fighter * this, int edx, Unit * attacker, Unit * defender) +{ + // Temporarily clear the attacker retreat eligibility flag when needed so naval units are rotated and animated properly. Normally the game + // does not use ranged animations when the attacker can retreat and, worse, not using ranged anims means it also ignores the + // rotate-before-attack setting. + bool restore_attacker_retreat_eligibility = false; + if ((is->current_config.sea_retreat_rules != RR_STANDARD) && + (p_bic_data->UnitTypes[attacker->Body.UnitTypeID].Unit_Class == UTC_Sea) && + Unit_has_ability (attacker, __, UTA_Ranged_Attack_Animation) && + Unit_has_ability (defender, __, UTA_Ranged_Attack_Animation) && + this->attacker_eligible_to_retreat) { + this->attacker_eligible_to_retreat = false; + restore_attacker_retreat_eligibility = true; + } + + Fighter_animate_start_of_combat (this, __, attacker, defender); + + if (restore_attacker_retreat_eligibility) + this->attacker_eligible_to_retreat = true; +} + +Unit * __fastcall +patch_Leader_spawn_unit_from_building (Leader * this, int edx, int type_id, int tile_x, int tile_y, int barb_tribe_id, int id, bool param_6, LeaderKind leader_kind, int race_id) +{ + int available; + if (get_available_unit_count (this, type_id, &available) && (available <= 0)) + return NULL; + else + return patch_Leader_spawn_unit (this, __, type_id, tile_x, tile_y, barb_tribe_id, id, param_6, leader_kind, race_id); +} + +int __fastcall +patch_City_count_improvs_enabling_upgrade (City * this, int edx, enum ImprovementTypeFlags flag) +{ + return is->current_config.allow_upgrades_in_any_city ? 1 : City_count_improvements_with_flag (this, __, flag); +} + +City * __fastcall +patch_Leader_create_city_from_hut (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_POPPED_FROM_HUT); + return tr; +} + +City * __fastcall +patch_Leader_create_city_for_ai_respawn (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_PLACED_FOR_AI_RESPAWN); + return tr; +} + +City * __fastcall +patch_Leader_create_city_for_founding (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_FOUNDED); + return tr; +} + +City * __fastcall +patch_Leader_create_city_for_scenario (Leader * this, int edx, int x, int y, int race_id, int param_4, char const * name, bool param_6) +{ + City * tr = Leader_create_city (this, __, x, y, race_id, param_4, name, param_6); + if (tr != NULL) + on_gain_city (this, tr, CGR_PLACED_FOR_SCENARIO); + return tr; +} + +City * +find_city_to_inherit_shared_small_wonder (Leader * leader, int wonder_improv_id) +{ + if ((leader == NULL) || + (! is->current_config.enable_districts) || + (! is->current_config.enable_wonder_districts) || + (! is->current_config.cities_with_mutual_district_receive_wonders)) + return NULL; + + FOR_CITIES_OF (coi, leader->ID) { + City * city = coi.city; + if ((city == NULL) || (! patch_City_has_improvement (city, __, wonder_improv_id, false))) + continue; + + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + Tile * tile = wai.tile; + + struct district_instance * inst = wai.district_inst; + if (inst->district_id != WONDER_DISTRICT_ID) + continue; + + struct wonder_district_info * info = &inst->wonder_info; + if ((info == NULL) || (info->state != WDS_COMPLETED)) + continue; + + int nearby_improv_id = get_wonder_improvement_id_from_index (info->wonder_index); + if (nearby_improv_id == wonder_improv_id) + return city; + } + } + + return NULL; +} + +void +collect_small_wonders_present_in_city (City * city, int * lost_small_wonders, int * lost_small_wonder_count, int max_lost_small_wonders) +{ + if ((city == NULL) || + (lost_small_wonders == NULL) || + (lost_small_wonder_count == NULL) || + (max_lost_small_wonders <= 0)) + return; + + *lost_small_wonder_count = 0; + + if (! is->current_config.enable_districts || + ! is->current_config.enable_wonder_districts || + ! is->current_config.cities_with_mutual_district_receive_wonders) + return; + + for (int improv_id = 0; improv_id < p_bic_data->ImprovementsCount; improv_id++) { + Improvement * improv = &p_bic_data->Improvements[improv_id]; + if ((improv->Characteristics & ITC_Small_Wonder) == 0) + continue; + if (! patch_City_has_improvement (city, __, improv_id, false)) + continue; + if (*lost_small_wonder_count >= max_lost_small_wonders) + break; + lost_small_wonders[(*lost_small_wonder_count)++] = improv_id; + } +} + +void +reassign_shared_small_wonder_owners_after_city_loss (Leader * leader, int const * lost_small_wonders, int lost_small_wonder_count) +{ + if ((! is->current_config.enable_districts) || + (leader == NULL) || + (! is->current_config.enable_wonder_districts) || + (! is->current_config.cities_with_mutual_district_receive_wonders) || + (lost_small_wonders == NULL) || + (lost_small_wonder_count <= 0)) + return; + + for (int n = 0; n < lost_small_wonder_count; n++) { + int improv_id = lost_small_wonders[n]; + if ((improv_id < 0) || (improv_id >= p_bic_data->ImprovementsCount)) + continue; + + if (leader->Small_Wonders[improv_id] != -1) + continue; + + // Vanilla clears Leader.Small_Wonders when the recorded owner city loses the building during + // capture. Only repair the small wonders that were actually present in the lost city before + // capture, and if another city of the same civ still legitimately shares the wonder district, + // promote that city to be the new canonical owner so the small wonder's effects still work. + City * replacement = find_city_to_inherit_shared_small_wonder (leader, improv_id); + if (replacement != NULL) + leader->Small_Wonders[improv_id] = replacement->Body.ID; + } +} + +bool __fastcall +patch_Leader_do_capture_city (Leader * this, int edx, City * city, bool involuntary, bool converted) +{ + Leader * previous_owner = &leaders[city->Body.CivID]; + int lost_small_wonders[32]; + int lost_small_wonder_count; + + // Record which small wonders were physically present in the city before capture so any + // post-capture ownership repair only touches wonders actually affected. + collect_small_wonders_present_in_city (city, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); + + is->currently_capturing_city = city; + on_lose_city (previous_owner, city, converted ? CLR_CONVERTED : (involuntary ? CLR_CONQUERED : CLR_TRADED)); + bool tr = Leader_do_capture_city (this, __, city, involuntary, converted); + + // The game clears the losing civ's canonical Small_Wonders owner when the recorded city loses + // the building. Reassign that ownership here if another same-civ city still legitimately shares the wonder district. + if (is->current_config.enable_districts && + is->current_config.enable_wonder_districts && + is->current_config.cities_with_mutual_district_receive_wonders && + lost_small_wonder_count > 0) { + reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); + } + + on_gain_city (this, city, converted ? CGR_CONVERTED : (involuntary ? CGR_CONQUERED : CGR_TRADED)); + is->currently_capturing_city = NULL; + return tr; +} + +void __fastcall +patch_City_raze (City * this, int edx, int civ_id_responsible, bool checking_elimination) +{ + Leader * previous_owner = &leaders[this->Body.CivID]; + int lost_small_wonders[32]; + int lost_small_wonder_count; + + collect_small_wonders_present_in_city (this, lost_small_wonders, &lost_small_wonder_count, ARRAY_LEN (lost_small_wonders)); + on_lose_city (previous_owner, this, CLR_DESTROYED); + City_raze (this, __, civ_id_responsible, checking_elimination); + + if (lost_small_wonder_count > 0) + reassign_shared_small_wonder_owners_after_city_loss (previous_owner, lost_small_wonders, lost_small_wonder_count); + + // Delete the extra improvement bits records for this city + City_Improvements * improv_lists[2] = {&this->Body.Improvements_1, &this->Body.Improvements_2}; + for (int n = 0; n < ARRAY_LEN (improv_lists); n++) { + City_Improvements * improv_list = improv_lists[n]; + byte * extra_bits; + if (itable_look_up (&is->extra_city_improvs, (int)improv_list, (int *)&extra_bits)) { + free (extra_bits); + itable_remove (&is->extra_city_improvs, (int)improv_list); + } + } +} + +void __fastcall +patch_City_draw_hud_icon (City * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y) +{ + Leader * owner = &leaders[this->Body.CivID]; + int restore_capital = owner->CapitalID; + + // Temporarily set this city as the capital if it has an extra palace so it gets the capital star icon + if ((is->current_config.ai_multi_city_start > 1) && + ((*p_human_player_bits & (1 << owner->ID)) == 0) && + has_extra_palace (this)) + owner->CapitalID = this->Body.ID; + + City_draw_hud_icon (this, __, canvas, pixel_x, pixel_y); + owner->CapitalID = restore_capital; +} + +bool __fastcall +patch_City_has_hud_icon (City * this) +{ + return City_has_hud_icon (this) + || ( (is->current_config.ai_multi_city_start > 1) + && ((*p_human_player_bits & (1 << this->Body.CivID)) == 0) + && has_extra_palace (this)); +} + +void __fastcall +patch_City_draw_on_map (City * this, int edx, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int param_4, int param_5, int param_6, int param_7) +{ + Leader * owner = &leaders[this->Body.CivID]; + int restore_capital = owner->CapitalID; + + if (is->current_config.do_not_make_capital_cities_appear_larger) + owner->CapitalID = -1; + + // Temporarily set this city as the capital if it has an extra palace so it gets drawn with the next larger size + else if ((is->current_config.ai_multi_city_start > 1) && + ((*p_human_player_bits & (1 << owner->ID)) == 0) && + has_extra_palace (this)) + owner->CapitalID = this->Body.ID; + + City_draw_on_map (this, __, map_renderer, pixel_x, pixel_y, param_4, param_5, param_6, param_7); + owner->CapitalID = restore_capital; +} + +// Writes a string to replace "Wake" or "Activate" on the right-click menu entry for the given unit. Some units might not have a replacement, in which +// case the function writes nothing and returns false. The string is written to out_str which must point to a buffer of at least str_capacity bytes. +bool +get_menu_verb_for_unit (Unit * unit, char * out_str, int str_capacity) +{ + struct state_desc { + enum c3x_label label; + bool is_doing_worker_job; + } state_descs[35] = { + {CL_IDLE , false}, // [No state] = 0x0 + {CL_FORTIFIED , false}, // Fortifying = 0x1 + {CL_MINING , true }, // Build_Mines = 0x2 + {CL_IRRIGATING , true }, // Irrigate = 0x3 + {CL_BUILDING_FORTRESS , true }, // Build_Fortress = 0x4 + {CL_BUILDING_ROAD , true }, // Build_Road = 0x5 + {CL_BUILDING_RAILROAD , true }, // Build_Railroad = 0x6 + {CL_PLANTING_FOREST , true }, // Plant_Forest = 0x7 + {CL_CLEARING_FOREST , true }, // Clear_Forest = 0x8 + {CL_CLEARING_WETLANDS , true }, // Clear_Wetlands = 0x9 + {CL_CLEARING_DAMAGE , true }, // Clear_Damage = 0xA + {CL_BUILDING_AIRFIELD , true }, // Build_Airfield = 0xB + {CL_BUILDING_RADAR_TOWER, true }, // Build_Radar_Tower = 0xC + {CL_BUILDING_OUTPOST , true }, // Build_Outpost = 0xD + {CL_BUILDING_BARRICADE , true }, // Build_Barricade = 0xE + {CL_INTERCEPTING , false}, // Intercept = 0xF + {CL_MOVING , false}, // Go_To = 0x10 + {CL_BUILDING_ROAD , true }, // Road_To_Tile = 0x11 + {CL_BUILDING_RAILROAD , true }, // Railroad_To_Tile = 0x12 + {CL_BUILDING_COLONY , true }, // Build_Colony = 0x13 + {CL_AUTOMATED , true }, // Auto_Irrigate = 0x14 + {CL_AUTOMATED , true }, // Build_Trade_Routes = 0x15 + {CL_AUTOMATED , true }, // Auto_Clear_Forest = 0x16 + {CL_AUTOMATED , true }, // Auto_Clear_Swamp = 0x17 + {CL_AUTOMATED , true }, // Auto_Clear_Pollution = 0x18 + {CL_AUTOMATED , true }, // Auto_Save_City_Tiles = 0x19 + {CL_EXPLORING , false}, // Explore = 0x1A + {CL_IN_STATE_27 , false}, // ? = 0x1B + {CL_IN_STATE_28 , false}, // Fleeing = 0x1C + {CL_IN_STATE_29 , false}, // ? = 0x1D + {CL_IN_STATE_30 , false}, // ? = 0x1E + {CL_BOMBARDING , false}, // Auto_Bombard = 0x1F + {CL_BOMBARDING , false}, // Auto_Air_Bombard = 0x20 + {CL_BOMBARDING , false}, // Auto_Precision_Strike = 0x21 + {CL_IDLE , false}, // Exhausted = 0x22 + }; + enum UnitStateType state = unit->Body.UnitState; + struct state_desc const * desc; + if ((state >= 0) && (state < ARRAY_LEN (state_descs)) && (desc = &state_descs[state]) && (desc->label >= 0) && (desc->label < COUNT_C3X_LABELS)) { + enum c3x_label label = desc->label; + Unit * container; + if (((label == CL_IDLE) || (label == CL_MOVING) || (label == CL_IN_STATE_29) || desc->is_doing_worker_job) && unit->Body.automated) + label = CL_AUTOMATED; + else if ((label == CL_FORTIFIED) && (NULL != (container = get_unit_ptr (unit->Body.Container_Unit))) && ! Unit_has_ability (container, __, UTA_Army)) + label = CL_TRANSPORTED; + else if ((label == CL_FORTIFIED) && (unit->Body.Status & (USF_SENTRY | USF_SENTRY_ENEMY_ONLY))) + label = CL_SENTRY; + else if ((label == CL_MINING) && is->current_config.enable_districts) { + + // Check if this unit is actually building a district instead of a mine + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + struct district_instance * inst = get_district_instance (tile); + if ((tile != NULL) && (tile != p_null_tile) && inst != NULL) { + char const * district_name = is->district_configs[inst->district_id].name; + snprintf (out_str, str_capacity, "%s %s", is->c3x_labels[CL_BUILDING], district_name); + out_str[str_capacity - 1] = '\0'; + return true; + } + } + + strncpy (out_str, is->c3x_labels[label], str_capacity); + out_str[str_capacity - 1] = '\0'; + return true; + } else + return false; +} + +void __fastcall +patch_MenuUnitItem_write_text_to_temp_str (MenuUnitItem * this) +{ + MenuUnitItem_write_text_to_temp_str (this); + + Unit * unit = this->unit; + char repl_verb[32]; + if (is->current_config.describe_states_of_units_on_menu && + (unit->Body.CivID == p_main_screen_form->Player_CivID) && + (Unit_get_containing_army (unit) == NULL) && + get_menu_verb_for_unit (unit, repl_verb, sizeof repl_verb)) { + char * verb = (unit->Body.UnitState == UnitState_Fortifying) ? (*p_labels)[LBL_WAKE] : (*p_labels)[LBL_ACTIVATE]; + char * verb_str_start = strstr (temp_str, verb); + if (verb_str_start != NULL) { + char s[500]; + char * verb_str_end = verb_str_start + strlen (verb); + snprintf (s, sizeof s, "%.*s%s%s", verb_str_start - temp_str, temp_str, repl_verb, verb_str_end); + s[(sizeof s) - 1] = '\0'; + strncpy (temp_str, s, sizeof s); + } + } +} + +void __fastcall +patch_Tile_m74_Set_Square_Type_for_hill_gen (Tile * this, int edx, enum SquareTypes sq, int tile_x, int tile_y) +{ + if ((sq == SQ_Volcano) && is->current_config.do_not_generate_volcanos) + sq = SQ_Mountains; + this->vtable->m74_Set_Square_Type (this, __, sq, tile_x, tile_y); +} + +void __fastcall +patch_Map_place_scenario_things (Map * this) +{ + is->is_placing_scenario_things = true; + + Map_place_scenario_things (this); + + // If there are any mills in the config then recompute yields & happiness in all cities. This must be done because we avoid doing this as + // mills are added to cities while placing scenario things. + if (is->current_config.count_mills > 0) + for (int n = 0; n <= p_cities->LastIndex; n++) { + City * city = get_city_ptr (n); + if (city != NULL) + patch_City_recompute_yields_and_happiness (city); + } + + if (is->current_config.enable_districts || + is->current_config.enable_natural_wonders || + is->current_config.enable_named_tiles) + load_scenario_districts_from_file (); + + if (is->current_config.enable_natural_wonders && + is->current_config.add_natural_wonders_to_scenarios_if_none) { + bool any_natural_wonders = false; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst != NULL) && + (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) { + any_natural_wonders = true; + break; + } + } + if (! any_natural_wonders) + place_natural_wonders_on_map (); + } + is->is_placing_scenario_things = false; +} + +void +on_open_advisor (AdvisorKind kind) +{ + recompute_resources_if_necessary (); +} + +bool __fastcall patch_Advisor_Base_Form_domestic_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_DOMESTIC); return Advisor_Base_Form_domestic_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_trade_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_TRADE) ; return Advisor_Base_Form_trade_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_military_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_MILITARY); return Advisor_Base_Form_military_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_foreign_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_FOREIGN) ; return Advisor_Base_Form_foreign_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_cultural_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_CULTURAL); return Advisor_Base_Form_cultural_m95 (this); } +bool __fastcall patch_Advisor_Base_Form_science_m95 (Advisor_Base_Form * this) { on_open_advisor (AK_SCIENCE) ; return Advisor_Base_Form_science_m95 (this); } + +void __fastcall +patch_Main_Screen_Form_open_quick_build_chooser (Main_Screen_Form * this, int edx, City * city, int mouse_x, int mouse_y) +{ + recompute_resources_if_necessary (); + Main_Screen_Form_open_quick_build_chooser (this, __, city, mouse_x, mouse_y); +} + +int __fastcall +patch_Context_Menu_get_selected_item_on_unit_rcm (Context_Menu * this) +{ + // In the base game, this method returns -1 for any disabled item which prevents the player from clicking those. We want players to be able to + // click unit items which have been disabled by the mod so they can interrupt the queued actions of units that have no moves left. + int index = this->Selected_Item; + if (index >= 0) { + if (is->current_config.enable_named_tiles && is->named_tile_menu_active) { + Context_Menu_Item * item = &this->Items[index]; + if (item->Menu_Item_ID == NAMED_TILE_MENU_ID) { + handle_named_tile_menu_selection (); + return -1; + } + } + bool is_enabled = (this->Items[index].Status & 2) == 0; + bool is_unit_item = (this->Items[index].Menu_Item_ID - (0x13 + p_bic_data->UnitTypeCount)) >= 0; + return (is_enabled || is_unit_item) ? index : -1; + } + return -1; +} + +int __fastcall +patch_Tile_check_water_to_block_pollution (Tile * this) +{ + if (this->vtable->m35_Check_Is_Water (this)) + return 1; + else if (is->current_config.do_not_pollute_impassable_tiles) { + enum SquareTypes terrain_type = this->vtable->m50_Get_Square_BaseType (this); + return p_bic_data->TileTypes[terrain_type].Flags.Impassable; + } else + return 0; +} + +void __fastcall +patch_Tile_set_flag_for_eruption_damage (Tile * this, int edx, int param_1, int param_2, int x, int y) +{ + if (is->current_config.enable_districts) { + struct district_instance * inst = get_district_instance (this); + if (inst != NULL && inst->district_id >= 0 && inst->district_id < is->district_count) { + // District found - handle removal + int district_id = inst->district_id; + + // Notify human player if this tile is in their territory + int territory_owner = this->vtable->m38_Get_Territory_OwnerID (this); + if (territory_owner == p_main_screen_form->Player_CivID) { + char msg[160]; + char const * district_name = is->district_configs[district_id].name; + snprintf (msg, sizeof msg, "%s %s", district_name, is->c3x_labels[CL_DISTRICT_DESTROYED_BY_VOLCANO]); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (x, y, msg, true); + } + + // Remove the district + handle_district_removed (this, district_id, x, y, false); + + // Clear the mine flags + this->vtable->m62_Set_Tile_BuildingID (this, __, -1); + this->vtable->m51_Unset_Tile_Flags (this, __, 0, TILE_FLAG_MINE, x, y); + } + } + + // Apply the normal eruption damage (lava flag) if allowed + if (! (is->current_config.do_not_pollute_impassable_tiles && + p_bic_data->TileTypes[this->vtable->m50_Get_Square_BaseType (this)].Flags.Impassable)) + this->vtable->m56_Set_Tile_Flags (this, __, param_1, param_2, x, y); +} + +bool __fastcall +patch_City_confirm_production_switch (City * this, int edx, int order_type, int order_id) +{ + bool tr = City_confirm_production_switch (this, __, order_type, order_id); + if (tr && + (order_type == COT_Improvement) && (order_id >= 0) && (order_id < p_bic_data->ImprovementsCount) && + (this->Body.CivID == p_main_screen_form->Player_CivID) && + is->current_config.warn_when_chosen_building_would_replace_another) { + Improvement * improv = &p_bic_data->Improvements[order_id]; + if (improv->ImprovementFlags & ITF_Replaces_Other_Buildings) { + Improvement * replaced = NULL; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) { + Improvement * other = &p_bic_data->Improvements[n]; + if ((other->ImprovementFlags & ITF_Replaces_Other_Buildings) && + patch_City_has_improvement (this, __, n, false)) { + replaced = other; + break; + } + } + if (replaced != NULL) { + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, improv->Name.S, -1, -1); + set_popup_str_param (1, replaced->Name.S, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_WARN_ABOUT_BUILDING_REPLACEMENT", -1, 0, 0, 0); + if (patch_show_popup (popup, __, 0, 0) == 1) + return false; + } + } + } + return tr; +} + +byte const c3x_save_segment_bookend[4] = {0x22, 'C', '3', 'X'}; + +// Writes a string to the buffer and pads the end so it's four-byte aligned (assuming the existing contents is already so aligned). +void +serialize_aligned_text (char const * text, struct buffer * b) +{ + int len = strlen (text); + if (len > 0) { + int padded_len = (len + 4) & ~3; // +1 for null terminator then +3 & ~3 for alignment + byte * p = buffer_allocate (b, padded_len); + strcpy (p, text); + for (int n = 0; n < padded_len - len; n++) + p[len + n] = (byte)0; + } +} + +void * __fastcall +patch_MappedFile_open_to_load_game (MappedFile * this, int edx, char * file_name, int sequential_access) +{ + void * tr = MappedFile_open (this, __, file_name, sequential_access); + if (tr != NULL) + is->accessing_save_file = this; + return tr; +} + +void * __fastcall +patch_MappedFile_create_file_to_save_game (MappedFile * this, int edx, LPCSTR file_path, unsigned file_size, int is_shared) +{ + // Determine if we're currently applying settler perfume to any AI player + bool any_current_settler_perfume = false; + if (is->current_config.ai_settler_perfume_on_founding != 0) { + int duration = is->current_config.ai_settler_perfume_on_founding_duration; + for (int n = 0; n < 32; n++) { + int last_founding_turn = is->turn_no_of_last_founding_for_settler_perfume[n]; + if ((last_founding_turn != -1) && ((*p_current_turn_no - last_founding_turn) < duration)) + any_current_settler_perfume = true; + } + } + + // Assemble mod save data + struct buffer mod_data = {0}; { + if (is->extra_defensive_bombards.len > 0) { + serialize_aligned_text ("extra_defensive_bombards", &mod_data); + itable_serialize (&is->extra_defensive_bombards, &mod_data); + } + if (is->airdrops_this_turn.len > 0) { + serialize_aligned_text ("airdrops_this_turn", &mod_data); + itable_serialize (&is->airdrops_this_turn, &mod_data); + } + if (is->unit_transport_ties.len > 0) { + serialize_aligned_text ("unit_transport_ties", &mod_data); + itable_serialize (&is->unit_transport_ties, &mod_data); + } + if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && is->waiting_units.len > 0) { + serialize_aligned_text ("waiting_units", &mod_data); + itable_serialize (&is->waiting_units, &mod_data); + } + if ((p_bic_data->ImprovementsCount > 256) && (p_cities->Cities != NULL) && (is->extra_city_improvs.len > 0)) { + serialize_aligned_text ("extra_city_improvs", &mod_data); + int extra_improv_count = p_bic_data->ImprovementsCount - 256; + *(int *)buffer_allocate (&mod_data, sizeof(int)) = extra_improv_count; + + int count_entries = 0; { + for (int n = 0; n <= p_cities->LastIndex; n++) { + City_Body * body = p_cities->Cities[n].City; + if ((body != NULL) && ((int)body != offsetof (City, Body))) { + int unused; + if (itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_1, &unused) || + itable_look_up (&is->extra_city_improvs, (int)&body->Improvements_2, &unused)) + count_entries++; + } + } + } + *(int *)buffer_allocate (&mod_data, sizeof(int)) = count_entries; + + int ints_per_list = (extra_improv_count + 31) / 32; + int bytes_per_list = (extra_improv_count + 7) / 8; + for (int n = 0; n <= p_cities->LastIndex; n++) { + City_Body * body = p_cities->Cities[n].City; + if ((body != NULL) && ((int)body != offsetof (City, Body))) { + byte * extra_bit_lists[2]; + extra_bit_lists[0] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_1, 0); + extra_bit_lists[1] = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)&body->Improvements_2, 0); + if ((extra_bit_lists[0] != NULL) || (extra_bit_lists[1] != NULL)) { + *(int *)buffer_allocate (&mod_data, sizeof(int)) = body->ID; + for (int k = 0; k < 2; k++) { + int list_size = sizeof(int) * ints_per_list; + int * list = (int *)buffer_allocate (&mod_data, list_size); + memset (list, 0, list_size); + if (extra_bit_lists[k] != NULL) + memcpy (list, extra_bit_lists[k], bytes_per_list); + } + } + } + } + } + if (any_current_settler_perfume) { + serialize_aligned_text ("turn_no_of_last_founding_for_settler_perfume", &mod_data); + void * area = buffer_allocate (&mod_data, sizeof is->turn_no_of_last_founding_for_settler_perfume); + memcpy (area, is->turn_no_of_last_founding_for_settler_perfume, sizeof is->turn_no_of_last_founding_for_settler_perfume); + } + if (is->current_config.day_night_cycle_mode != DNCM_OFF) { + serialize_aligned_text ("current_day_night_cycle", &mod_data); + int_to_bytes (buffer_allocate (&mod_data, sizeof is->current_day_night_cycle), is->current_day_night_cycle); + } + if (is->current_config.enable_districts && (is->district_count > 0)) { + serialize_aligned_text ("district_config_names", &mod_data); + int * entry_count = (int *)buffer_allocate (&mod_data, sizeof(int)); + *entry_count = is->district_count; + for (int district_id = 0; district_id < is->district_count; district_id++) { + *(int *)buffer_allocate (&mod_data, sizeof(int)) = district_id; + char const * name = is->district_configs[district_id].name; + if (name == NULL) + name = ""; + serialize_aligned_text (name, &mod_data); + } + } + + if (is->current_config.enable_districts) { + int entry_count = 0; + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req != NULL) && (req->city_id >= 0)) + entry_count++; + } + } + if (entry_count > 0) { + serialize_aligned_text ("district_pending_requests", &mod_data); + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 5 * entry_count)); + int * out = chunk + 1; + chunk[0] = entry_count; + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if ((req == NULL) || (req->city_id < 0)) + continue; + out[0] = req->city_id; + out[1] = req->district_id; + out[2] = req->assigned_worker_id; + out[3] = req->target_x; + out[4] = req->target_y; + out += 5; + } + } + } + } + + if (is->current_config.enable_districts && + (is->city_pending_building_orders.len > 0)) { + int entry_count = 0; + FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { + City * city = (City *)tei.key; + int improv_id = tei.value; + if ((city != NULL) && (improv_id >= 0)) + entry_count++; + } + if (entry_count > 0) { + serialize_aligned_text ("building_pending_orders", &mod_data); + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 2 * entry_count)); + int * out = chunk + 1; + chunk[0] = entry_count; + FOR_TABLE_ENTRIES (tei, &is->city_pending_building_orders) { + City * city = (City *)tei.key; + int improv_id = tei.value; + if ((city == NULL) || (improv_id < 0)) + continue; + out[0] = city->Body.ID; + out[1] = improv_id; + out += 2; + } + } + } + + if (is->current_config.enable_districts && (is->district_tile_map.len > 0)) { + serialize_aligned_text ("district_tile_map", &mod_data); + int entry_capacity = is->district_tile_map.len; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 9 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * tile = (Tile *)tei.key; + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst == NULL) + continue; + int x, y; + if (! district_instance_get_coords (inst, tile, &x, &y)) + continue; + int wonder_city_id = inst->wonder_info.city_id; + if (wonder_city_id >= 0) { + City * info_city = get_city_ptr (wonder_city_id); + inst->wonder_info.city = info_city; + if (info_city == NULL) + wonder_city_id = -1; + } else + inst->wonder_info.city = NULL; + out[0] = x; + out[1] = y; + out[2] = inst->district_id; + out[3] = (int)inst->state; + out[4] = inst->built_by_civ_id; + out[5] = inst->completed_turn; + out[6] = (int)inst->wonder_info.state; + out[7] = wonder_city_id; + out[8] = inst->wonder_info.wonder_index; + out += 9; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 9 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + + if (is->current_config.enable_natural_wonders && (is->district_tile_map.len > 0)) { + int entry_capacity = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || (inst->district_id != NATURAL_WONDER_DISTRICT_ID)) + continue; + if (inst->natural_wonder_info.natural_wonder_id < 0) + continue; + entry_capacity++; + } + if (entry_capacity > 0) { + serialize_aligned_text ("natural_wonder_districts", &mod_data); + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + Tile * tile = (Tile *)tei.key; + struct district_instance * inst = (struct district_instance *)tei.value; + if ((inst == NULL) || + (inst->district_id != NATURAL_WONDER_DISTRICT_ID) || + (inst->natural_wonder_info.natural_wonder_id < 0)) + continue; + int x, y; + if (! district_instance_get_coords (inst, tile, &x, &y)) + continue; + out[0] = x; + out[1] = y; + out[2] = inst->natural_wonder_info.natural_wonder_id; + out += 3; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + } + + if (is->current_config.enable_districts && + is->current_config.enable_distribution_hub_districts && + (is->distribution_hub_records.len > 0)) { + serialize_aligned_text ("distribution_hub_records", &mod_data); + int entry_capacity = is->distribution_hub_records.len; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->distribution_hub_records) { + struct distribution_hub_record * rec = (struct distribution_hub_record *)tei.value; + if (rec == NULL) + continue; + out[0] = rec->tile_x; + out[1] = rec->tile_y; + out[2] = rec->civ_id; + out += 3; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + + if (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities && + (is->aerodrome_airlift_usage.len > 0)) { + serialize_aligned_text ("aerodrome_airlift_usage", &mod_data); + int entry_capacity = is->aerodrome_airlift_usage.len; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (1 + 3 * entry_capacity)); + int * out = chunk + 1; + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->aerodrome_airlift_usage) { + Tile * tile = (Tile *)tei.key; + int mask = tei.value; + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + int tile_x, tile_y; + if (! tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y)) + continue; + + out[0] = tile_x; + out[1] = tile_y; + out[2] = mask; + out += 3; + written++; + } + chunk[0] = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * 3 * (int)sizeof(int); + mod_data.length -= trimmed_bytes; + } + } + + if (is->current_config.enable_named_tiles && (is->named_tile_map.len > 0)) { + serialize_aligned_text ("named_tiles", &mod_data); + int entry_capacity = is->named_tile_map.len; + int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); + byte * chunk = (byte *)buffer_allocate (&mod_data, (int)sizeof(int) + bytes_per_entry * entry_capacity); + int * count = (int *)chunk; + byte * out = (byte *)(count + 1); + int written = 0; + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if ((entry == NULL) || (entry->name[0] == '\0')) + continue; + Tile * tile = (Tile *)tei.key; + int tile_x = entry->tile_x; + int tile_y = entry->tile_y; + if ((tile != NULL) && (tile != p_null_tile)) + tile_coords_from_ptr (&p_bic_data->Map, tile, &tile_x, &tile_y); + ((int *)out)[0] = tile_x; + ((int *)out)[1] = tile_y; + out += sizeof(int) * 2; + memcpy (out, entry->name, sizeof entry->name); + out += sizeof entry->name; + written++; + } + *count = written; + int unused_entries = entry_capacity - written; + if (unused_entries > 0) { + int trimmed_bytes = unused_entries * bytes_per_entry; + mod_data.length -= trimmed_bytes; + } + } + + if (is->great_wall_auto_build != GWABS_NOT_STARTED) { + serialize_aligned_text ("great_wall_auto_build_state", &mod_data); + *(int *)buffer_allocate (&mod_data, sizeof(int)) = (int)is->great_wall_auto_build; + } + + if (is->ai_candidate_bridge_or_canals_initialized || (is->ai_candidate_bridge_or_canals_count > 0)) { + serialize_aligned_text ("ai_candidate_bridge_or_canals", &mod_data); + int * header = (int *)buffer_allocate (&mod_data, sizeof(int) * 3); + header[0] = is->ai_candidate_bridge_or_canals_initialized ? 1 : 0; + header[1] = is->ai_candidate_bridge_or_canals_count; + header[2] = is->ai_candidate_bridge_or_canals_capacity; + for (int ei = 0; ei < is->ai_candidate_bridge_or_canals_count; ei++) { + struct ai_candidate_bridge_or_canal_entry * entry = &is->ai_candidate_bridge_or_canals[ei]; + int tile_count = (int)entry->tile_count; + if ((tile_count <= 0) || (entry->tile_x == NULL) || (entry->tile_y == NULL)) + tile_count = 0; + + int field_count = 14; + int * chunk = (int *)buffer_allocate (&mod_data, sizeof(int) * (field_count + tile_count * 2)); + int pending_city_id = entry->pending_req.city_id; + if ((pending_city_id < 0) && (entry->pending_req.city != NULL)) + pending_city_id = entry->pending_req.city->Body.ID; + + chunk[0] = entry->district_id; + chunk[1] = (int)entry->owner_civ_id; + chunk[2] = tile_count; + chunk[3] = (entry->tile_capacity > 0) ? entry->tile_capacity : tile_count; + chunk[4] = entry->assigned_tile_index; + chunk[5] = entry->assigned_worker_id; + chunk[6] = entry->completed ? 1 : 0; + chunk[7] = pending_city_id; + chunk[8] = entry->pending_req.civ_id; + chunk[9] = entry->pending_req.district_id; + chunk[10] = entry->pending_req.assigned_worker_id; + chunk[11] = entry->pending_req.target_x; + chunk[12] = entry->pending_req.target_y; + chunk[13] = entry->pending_req.worker_assigned_turn; + + int * out = chunk + field_count; + for (int ti = 0; ti < tile_count; ti++) { + out[0] = entry->tile_x[ti]; + out[1] = entry->tile_y[ti]; + out += 2; + } + } + } + } + + int metadata_size = (mod_data.length > 0) ? 12 : 0; // Two four-byte bookends plus one four-byte size, only written if there's any mod data + + void * tr = MappedFile_create_file (this, __, file_path, file_size + mod_data.length + metadata_size, is_shared); + if (tr != NULL) { + is->accessing_save_file = this; + if ((mod_data.length > 0) && (mod_data.length + metadata_size <= this->size)) { + // Write first bookend to mod's segment in the save data + byte * seg_start = (byte *)tr + file_size; + for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) + seg_start[n] = c3x_save_segment_bookend[n]; + + // Write actual mod game data + memcpy ((byte *)tr + file_size + 4, mod_data.contents, mod_data.length); + + // Write size of mod data + byte * seg_end = (byte *)tr + file_size + 4 + mod_data.length; + int_to_bytes (seg_end, mod_data.length); + + // Finish off with another bookend + for (int n = 0; n < ARRAY_LEN (c3x_save_segment_bookend); n++) + seg_end[4+n] = c3x_save_segment_bookend[n]; + } + } + buffer_deinit (&mod_data); + return tr; +} + +bool +match_save_chunk_name (byte ** cursor, char const * name) +{ + if (strcmp (name, *cursor) == 0) { + // Move cursor past the string if it matched. Also move past any padding that was added to ensure alignment (see serialize_aligned_text). + *cursor = (byte *)((int)*cursor + strlen (name) + 4 & ~3); + return true; + } else + return false; +} + +bool +match_save_segment_bookend (byte * b) +{ + return memcmp (c3x_save_segment_bookend, b, ARRAY_LEN (c3x_save_segment_bookend)) == 0; +} + +int __cdecl +patch_move_game_data (byte * buffer, bool save_else_load) +{ + int tr = move_game_data (buffer, save_else_load); + + if (! save_else_load) { + // Free all district_instance structs first + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst != NULL) + free (inst); + } + table_deinit (&is->district_tile_map); + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if (entry != NULL) + free (entry); + } + table_deinit (&is->named_tile_map); + clear_all_tracked_workers (); + reset_ai_candidate_bridge_or_canals (); + } + + // Check for a mod save data section and load it if present + MappedFile * save; + int seg_size; + byte * seg; + if ((! save_else_load) && + ((save = is->accessing_save_file) != NULL) && + (save->size >= 8) && + match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - 4)) && + ((seg_size = int_from_bytes ((byte *)((int)save->base_addr + save->size - 8))) > 0) && + (save->size >= seg_size + 12) && + match_save_segment_bookend ((byte *)((int)save->base_addr + save->size - seg_size - 12)) && + ((seg = malloc (seg_size)) != NULL)) { + memcpy (seg, (void *)((int)save->base_addr + save->size - seg_size - 8), seg_size); + + byte * cursor = seg; + char * error_chunk_name = NULL; + while (cursor < seg + seg_size) { + if (match_save_chunk_name (&cursor, "special save message")) { + char * msg = (char *)cursor; + cursor = (byte *)((int)cursor + strlen (msg) + 4 & ~3); + + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_INFO", -1, 0, 0, 0); + PopupForm_add_text (popup, __, "This save contains a special message:", 0); + PopupForm_add_text (popup, __, msg, 0); + patch_show_popup (popup, __, 0, 0); + + } else if (match_save_chunk_name (&cursor, "extra_defensive_bombards")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->extra_defensive_bombards); + if (bytes_read > 0) + cursor += bytes_read; + else { + error_chunk_name = "extra_defensive_bombards"; + break; + } + + } else if (match_save_chunk_name (&cursor, "airdrops_this_turn")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->airdrops_this_turn); + if (bytes_read > 0) + cursor += bytes_read; + else { + error_chunk_name = "airdrops_this_turn"; + break; + } + + } else if (match_save_chunk_name (&cursor, "unit_transport_ties")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->unit_transport_ties); + if (bytes_read > 0) + cursor += bytes_read; + else { + error_chunk_name = "unit_transport_ties"; + break; + } + + } else if (match_save_chunk_name (&cursor, "waiting_units")) { + int bytes_read = itable_deserialize (cursor, seg + seg_size, &is->waiting_units); + if (bytes_read > 0) { + cursor += bytes_read; + is->have_loaded_waiting_units = true; + } else { + error_chunk_name = "waiting_units"; + break; + } + + } else if (match_save_chunk_name (&cursor, "extra_city_improvs")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + + // Read two int vars from this save chunk + int file_extra_improv_count, count_entries; + if (remaining_bytes >= 8) { + file_extra_improv_count = *((int *)cursor)++; + count_entries = *((int *)cursor)++; + remaining_bytes -= 8; + } else + goto done_with_extra_city_improvs; + + // Check that the extra improv counts are valid. They must be greater than zero and what was stored in the save must + // match what we got from the current scenario data. + int extra_improv_count = not_below (0, p_bic_data->ImprovementsCount - 256); + if ((file_extra_improv_count <= 0) || (extra_improv_count != file_extra_improv_count)) + goto done_with_extra_city_improvs; + + // The extra bits data in the save is stored in 32-bit chunks, "ints", to maintain alignment. Compute how many ints we + // need for each list of bits and check that reading all entries won't overrun the buffer. + int ints_per_list = (extra_improv_count + 31) / 32, + ints_per_entry = 1 + 2 * ints_per_list; + if (count_entries * ints_per_entry * sizeof(int) > remaining_bytes) + goto done_with_extra_city_improvs; + + // Main loop reading the extra bits data + for (int n = 0; n < count_entries; n++) { + City * city = get_city_ptr (*((int *)cursor)++); + if (city == NULL) + goto done_with_extra_city_improvs; + + byte * extra_bits_1 = calloc (sizeof (int), ints_per_list); + for (int k = 0; k < ints_per_list; k++) + ((int *)extra_bits_1)[k] = *((int *)cursor)++; + itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_1, (int)extra_bits_1); + + byte * extra_bits_2 = calloc (sizeof (int), ints_per_list); + for (int k = 0; k < ints_per_list; k++) + ((int *)extra_bits_2)[k] = *((int *)cursor)++; + itable_insert (&is->extra_city_improvs, (int)&city->Body.Improvements_2, (int)extra_bits_2); + } + + // Rebuild the trade network since it may have changed as a result of the additional buildings. This method also + // refreshes the free improvement tables and recomputes city happiness. + patch_Map_build_trade_network (&p_bic_data->Map); + + success = true; + + done_with_extra_city_improvs: + if (! success) { + error_chunk_name = "extra_city_improvs";; + break; + } + + } else if (match_save_chunk_name (&cursor, "turn_no_of_last_founding_for_settler_perfume")) { + for (int n = 0; n < 32; n++) + is->turn_no_of_last_founding_for_settler_perfume[n] = *((int *)cursor)++; + + } else if (match_save_chunk_name (&cursor, "current_day_night_cycle")) { + is->current_day_night_cycle = *((int *)cursor)++; + is->day_night_cycle_unstarted = false; + + // The day/night cycle sprite proxies will have been cleared in patch_load_scenario. They will not necessarily be set + // up again in the usual way because Map_Renderer::load_images is not necessarily called when loading a save. The game + // skips reloading all graphics when loading a save while in-game with another that uses the same graphics (possibly + // only the standard graphics; I didn't test). If day/night cycle mode is active, restore the proxies now if they + // haven't already been. + if ((is->day_night_cycle_img_state == IS_OK) && ! is->day_night_cycle_img_proxies_indexed) + build_sprite_proxies_24 (&p_bic_data->Map.Renderer); + + // Because we've restored current_day_night_cycle from the save, set that is is not the first turn so the cycle + // doesn't get restarted. + is->day_night_cycle_unstarted = false; + + } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_state")) { + int state = *((int *)cursor)++; + if ((state >= GWABS_NOT_STARTED) && (state <= GWABS_DONE)) + is->great_wall_auto_build = (enum great_wall_auto_build_state)state; + else + is->great_wall_auto_build = GWABS_NOT_STARTED; + + } else if (match_save_chunk_name (&cursor, "great_wall_auto_build_is_done")) { + bool was_done = (*((int *)cursor)++ != 0); + is->great_wall_auto_build = was_done ? GWABS_DONE : GWABS_NOT_STARTED; + + } else if (match_save_chunk_name (&cursor, "district_pending_requests")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && + (remaining_bytes >= entry_count * 5 * (int)sizeof(int))) { + for (int civ_id = 0; civ_id < 32; civ_id++) { + FOR_TABLE_ENTRIES (tei, &is->city_pending_district_requests[civ_id]) { + struct pending_district_request * req = (struct pending_district_request *)tei.value; + if (req != NULL) + free (req); + } + table_deinit (&is->city_pending_district_requests[civ_id]); + } + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 5 * (int)sizeof(int)) { + success = false; + break; + } + int city_id = *ints++; + int district_id = *ints++; + int assigned_worker_id = *ints++; + int target_x = *ints++; + int target_y = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 5 * (int)sizeof(int); + City * city = get_city_ptr (city_id); + if ((city == NULL) || (district_id < 0) || (district_id >= is->district_count)) + continue; + struct pending_district_request * req = create_pending_district_request (city, district_id); + if (req == NULL) + continue; + if ((assigned_worker_id >= 0) && (get_unit_ptr (assigned_worker_id) == NULL)) + assigned_worker_id = -1; + req->assigned_worker_id = assigned_worker_id; + req->target_x = target_x; + req->target_y = target_y; + } + if (! success) { + for (int civ_id = 0; civ_id < 32; civ_id++) + table_deinit (&is->city_pending_district_requests[civ_id]); + } + } + } + if (! success) { + error_chunk_name = "district_pending_requests"; + break; + } + } else if (match_save_chunk_name (&cursor, "building_pending_orders")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && + (remaining_bytes >= entry_count * 2 * (int)sizeof(int))) { + table_deinit (&is->city_pending_building_orders); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 2 * (int)sizeof(int)) { + success = false; + break; + } + int city_id = *ints++; + int improv_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 2 * (int)sizeof(int); + if (improv_id < 0) + continue; + City * city = get_city_ptr (city_id); + if (city == NULL) + continue; + itable_insert (&is->city_pending_building_orders, (int)city, improv_id); + } + if (! success) + table_deinit (&is->city_pending_building_orders); + } + } + if (! success) { + error_chunk_name = "building_pending_orders"; + break; + } + } else if (match_save_chunk_name (&cursor, "district_tile_map")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if (entry_count >= 0) { + int ints_per_entry = 9; + success = true; + int required_bytes = entry_count * ints_per_entry * (int)sizeof(int); + if (success && remaining_bytes >= required_bytes) { + FOR_TABLE_ENTRIES (tei, &is->district_tile_map) { + struct district_instance * inst = (struct district_instance *)tei.value; + if (inst != NULL) + free (inst); + } + table_deinit (&is->district_tile_map); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < ints_per_entry * (int)sizeof(int)) { + success = false; + break; + } + int x = *ints++; + int y = *ints++; + int district_id = *ints++; + int state_val = *ints++; + int built_by_civ_id = *ints++; + int completed_turn = *ints++; + int wonder_state = *ints++; + int wonder_city_id = *ints++; + int wonder_index = *ints++; + cursor = (byte *)ints; + remaining_bytes -= ints_per_entry * (int)sizeof(int); + if ((district_id < 0) || (district_id >= is->district_count)) + continue; + Tile * tile = tile_at (x, y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = ensure_district_instance (tile, district_id, x, y); + if (inst != NULL) { + enum district_state new_state; + switch (state_val) { + case DS_COMPLETED: + new_state = DS_COMPLETED; + break; + case DS_UNDER_CONSTRUCTION: + new_state = DS_UNDER_CONSTRUCTION; + break; + default: + new_state = DS_UNDER_CONSTRUCTION; + break; + } + inst->state = new_state; + inst->built_by_civ_id = built_by_civ_id; + inst->completed_turn = completed_turn; + + inst->wonder_info.state = (enum wonder_district_state)wonder_state; + inst->wonder_info.city_id = (wonder_city_id >= 0) ? wonder_city_id : -1; + City * info_city = (wonder_city_id >= 0) ? get_city_ptr (wonder_city_id) : NULL; + inst->wonder_info.city = info_city; + if (info_city == NULL) + inst->wonder_info.city_id = -1; + inst->wonder_info.wonder_index = wonder_index; + set_tile_unworkable_for_all_cities (tile, x, y); + } + } + } + } + else + success = false; + } + } + if (! success) { + error_chunk_name = "district_tile_map"; + break; + } + } else if (match_save_chunk_name (&cursor, "natural_wonder_districts")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 3 * (int)sizeof(int)) { + success = false; + break; + } + int x = *ints++; + int y = *ints++; + int natural_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 3 * (int)sizeof(int); + if ((natural_id < 0) || (natural_id >= is->natural_wonder_count)) + continue; + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + struct district_instance * inst = ensure_district_instance (tile, NATURAL_WONDER_DISTRICT_ID, x, y); + if (inst == NULL) + continue; + inst->district_id = NATURAL_WONDER_DISTRICT_ID; + inst->state = DS_COMPLETED; + inst->natural_wonder_info.natural_wonder_id = natural_id; + set_tile_unworkable_for_all_cities (tile, x, y); + } + } + } + if (! success) { + error_chunk_name = "natural_wonder_districts"; + break; + } + } else if (match_save_chunk_name (&cursor, "distribution_hub_records")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { + clear_distribution_hub_tables (); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 3 * (int)sizeof(int)) { + success = false; + break; + } + int x = *ints++; + int y = *ints++; + int civ_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 3 * (int)sizeof(int); + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + on_distribution_hub_completed (tile, x, y); + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec != NULL) + rec->civ_id = civ_id; + } + } + } + if (! success) { + error_chunk_name = "distribution_hub_records"; + break; + } + } else if (match_save_chunk_name (&cursor, "aerodrome_airlift_usage")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if ((entry_count >= 0) && + (remaining_bytes >= entry_count * 3 * (int)sizeof(int))) { + table_deinit (&is->aerodrome_airlift_usage); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < 3 * (int)sizeof(int)) { + success = false; + break; + } + int tile_x = *ints++; + int tile_y = *ints++; + int mask = *ints++; + cursor = (byte *)ints; + remaining_bytes -= 3 * (int)sizeof(int); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + itable_insert (&is->aerodrome_airlift_usage, (int)tile, mask); + } + if (! success) + table_deinit (&is->aerodrome_airlift_usage); + } + } + if (! success) { + error_chunk_name = "aerodrome_airlift_usage"; + break; + } + + } else if (match_save_chunk_name (&cursor, "named_tiles")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int entry_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + int bytes_per_entry = (int)sizeof(int) * 2 + (int)sizeof(((struct named_tile_entry *)0)->name); + if ((entry_count >= 0) && (remaining_bytes >= entry_count * bytes_per_entry)) { + table_deinit (&is->named_tile_map); + success = true; + for (int n = 0; n < entry_count; n++) { + if (remaining_bytes < bytes_per_entry) { + success = false; + break; + } + int tile_x = *ints++; + int tile_y = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int) * 2; + + char name_buf[101]; + memcpy (name_buf, cursor, sizeof name_buf); + name_buf[(sizeof name_buf) - 1] = '\0'; + cursor += sizeof name_buf; + remaining_bytes -= sizeof name_buf; + ints = (int *)cursor; + + if (name_buf[0] == '\0') + continue; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + struct named_tile_entry * entry = calloc (1, sizeof *entry); + if (entry == NULL) { + success = false; + break; + } + entry->tile_x = tile_x; + entry->tile_y = tile_y; + strncpy (entry->name, name_buf, sizeof entry->name); + entry->name[(sizeof entry->name) - 1] = '\0'; + itable_insert (&is->named_tile_map, (int)tile, (int)entry); + } + if (! success) { + FOR_TABLE_ENTRIES (tei, &is->named_tile_map) { + struct named_tile_entry * entry = (struct named_tile_entry *)tei.value; + if (entry != NULL) + free (entry); + } + table_deinit (&is->named_tile_map); + } + } + } + if (! success) { + error_chunk_name = "named_tiles"; + break; + } + + } else if (match_save_chunk_name (&cursor, "ai_candidate_bridge_or_canals")) { + bool success = false; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int) * 3) { + int * ints = (int *)cursor; + int saved_initialized = *ints++; + int saved_count = *ints++; + int saved_capacity = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int) * 3; + + if ((saved_count >= 0) && (saved_capacity >= 0)) { + reset_ai_candidate_bridge_or_canals (); + success = true; + + int alloc_capacity = saved_capacity; + if (alloc_capacity < saved_count) + alloc_capacity = saved_count; + if (alloc_capacity > 0) { + is->ai_candidate_bridge_or_canals = (struct ai_candidate_bridge_or_canal_entry *)calloc (alloc_capacity, sizeof *is->ai_candidate_bridge_or_canals); + if (is->ai_candidate_bridge_or_canals == NULL) { + success = false; + alloc_capacity = 0; + } else + is->ai_candidate_bridge_or_canals_capacity = alloc_capacity; + } + + is->ai_candidate_bridge_or_canals_initialized = (saved_initialized != 0); + int loaded_count = 0; + for (int ei = 0; ei < saved_count; ei++) { + if (remaining_bytes < (int)sizeof(int) * 14) { + success = false; + break; + } + int district_id = *ints++; + int owner_civ_id = *ints++; + int tile_count = *ints++; + int tile_capacity = *ints++; + int assigned_tile_index = *ints++; + int assigned_worker_id = *ints++; + int completed = *ints++; + int pending_city_id = *ints++; + int pending_civ_id = *ints++; + int pending_district_id = *ints++; + int pending_assigned_worker_id = *ints++; + int pending_target_x = *ints++; + int pending_target_y = *ints++; + int pending_worker_assigned_turn = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int) * 14; + + if (tile_count < 0) { + success = false; + break; + } + if (remaining_bytes < tile_count * 2 * (int)sizeof(int)) { + success = false; + break; + } + + int stored_tile_count = tile_count; + if (tile_count > AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES) + tile_count = AI_BRIDGE_CANAL_CANDIDATE_MAX_EVAL_TILES; + if (tile_capacity < tile_count) + tile_capacity = tile_count; + + struct ai_candidate_bridge_or_canal_entry * entry = NULL; + if ((alloc_capacity > 0) && (loaded_count < alloc_capacity)) + entry = &is->ai_candidate_bridge_or_canals[loaded_count]; + + if (entry != NULL) { + entry->district_id = district_id; + entry->owner_civ_id = (short)owner_civ_id; + entry->tile_count = (short)tile_count; + entry->tile_capacity = tile_capacity; + entry->assigned_tile_index = assigned_tile_index; + entry->assigned_worker_id = assigned_worker_id; + entry->completed = (completed != 0); + + entry->tile_x = (short *)calloc (sizeof *entry->tile_x, tile_count); + entry->tile_y = (short *)calloc (sizeof *entry->tile_y, tile_count); + if ((tile_count > 0) && ((entry->tile_x == NULL) || (entry->tile_y == NULL))) { + if (entry->tile_x != NULL) + free (entry->tile_x); + if (entry->tile_y != NULL) + free (entry->tile_y); + entry->tile_x = NULL; + entry->tile_y = NULL; + entry->tile_count = 0; + entry->tile_capacity = 0; + } + + for (int ti = 0; ti < stored_tile_count; ti++) { + int tx = *ints++; + int ty = *ints++; + if ((entry->tile_x != NULL) && (ti < tile_count)) { + entry->tile_x[ti] = (short)tx; + entry->tile_y[ti] = (short)ty; + } + } + + entry->pending_req.city = (pending_city_id >= 0) ? get_city_ptr (pending_city_id) : NULL; + entry->pending_req.city_id = (entry->pending_req.city != NULL) ? pending_city_id : -1; + entry->pending_req.civ_id = pending_civ_id; + entry->pending_req.district_id = pending_district_id; + entry->pending_req.assigned_worker_id = pending_assigned_worker_id; + entry->pending_req.target_x = pending_target_x; + entry->pending_req.target_y = pending_target_y; + entry->pending_req.worker_assigned_turn = pending_worker_assigned_turn; + + if ((entry->assigned_worker_id >= 0) && (get_unit_ptr (entry->assigned_worker_id) == NULL)) + entry->assigned_worker_id = -1; + if ((entry->pending_req.assigned_worker_id >= 0) && (get_unit_ptr (entry->pending_req.assigned_worker_id) == NULL)) + entry->pending_req.assigned_worker_id = -1; + if ((entry->assigned_tile_index < 0) || (entry->assigned_tile_index >= entry->tile_count)) + entry->assigned_tile_index = -1; + + loaded_count++; + } else { + for (int ti = 0; ti < stored_tile_count; ti++) { + ints += 2; + } + } + + cursor = (byte *)ints; + remaining_bytes -= stored_tile_count * 2 * (int)sizeof(int); + } + if (success) + is->ai_candidate_bridge_or_canals_count = loaded_count; + } + } + if (! success) { + error_chunk_name = "ai_candidate_bridge_or_canals"; + break; + } + + } else if (match_save_chunk_name (&cursor, "district_config_names")) { + bool success = false; + bool mismatch_found = false; + bool count_mismatch = false; + char first_mismatch[200]; + first_mismatch[0] = '\0'; + int remaining_bytes = (seg + seg_size) - cursor; + if (remaining_bytes >= (int)sizeof(int)) { + int * ints = (int *)cursor; + int saved_count = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + if (saved_count >= 0) { + success = true; + count_mismatch = (saved_count != is->district_count); + char * saved_names[saved_count]; + for (int n = 0; n < saved_count; n++) { + if (remaining_bytes < (int)sizeof(int)) { + success = false; + break; + } + ints = (int *)cursor; + int saved_id = *ints++; + cursor = (byte *)ints; + remaining_bytes -= (int)sizeof(int); + + int name_len = -1; + for (int k = 0; k < remaining_bytes; k++) { + if (cursor[k] == '\0') { + name_len = k; + break; + } + } + if (name_len < 0) { + success = false; + break; + } + int padded_len = (name_len + 4) & ~3; + if (padded_len > remaining_bytes) { + success = false; + break; + } + + char * saved_name = (char *)cursor; + saved_names[n] = saved_name; + if (! mismatch_found) { + if ((saved_id < 0) || (saved_id >= is->district_count)) { + snprintf (first_mismatch, sizeof first_mismatch, "%s %d (\"%s\") %s", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_IN_SAVE_BUT_MISSING_NOW]); + first_mismatch[(sizeof first_mismatch) - 1] = '\0'; + mismatch_found = true; + } else { + char const * current_name = is->district_configs[saved_id].name; + if (current_name == NULL) + current_name = ""; + if (strcmp (current_name, saved_name) != 0) { + snprintf (first_mismatch, sizeof first_mismatch, "%s %d \"%s\" %s \"%s\"", is->c3x_labels[CL_DISTRICT_ID], saved_id, saved_name, is->c3x_labels[CL_DISTRICT_NAME_MISMATCH], current_name); + first_mismatch[(sizeof first_mismatch) - 1] = '\0'; + mismatch_found = true; + } + } + } + + cursor += padded_len; + remaining_bytes -= padded_len; + } + if (success && count_mismatch && (first_mismatch[0] == '\0')) { + snprintf (first_mismatch, sizeof first_mismatch, "%s %d %s %d", is->c3x_labels[CL_SAVE_FILE_HAD], saved_count, is->c3x_labels[CL_CURRENT_CONFIG_HAS_ONLY], is->district_count); + first_mismatch[(sizeof first_mismatch) - 1] = '\0'; + mismatch_found = true; + } + if (success && mismatch_found) { + PopupForm * popup = get_popup_form (); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_ERROR", -1, 0, 0, 0); + + char s[1000]; + snprintf (s, sizeof s, "%s %s", is->c3x_labels[CL_WARNING_DISTRICTS_CONFIG_MISMATCH], first_mismatch); + snprintf (s, sizeof s, "%s. %s", s, is->c3x_labels[CL_MAY_BE_OTHER_ERRORS_AS_WELL]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^"); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^%s:", is->c3x_labels[CL_DISTRICTS_IN_SAVE_FILE]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + for (int n = 0; n < saved_count; n++) { + snprintf (s, sizeof s, "^ (%d) %s", n, saved_names[n]); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + + snprintf (s, sizeof s, "^"); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + + snprintf (s, sizeof s, "^%s \"%s\":", is->c3x_labels[CL_CURRENTLY_CONFIGURED_DISTRICTS], is->current_districts_config_path); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + for (int n = 0; n < is->district_count; n++) { + snprintf (s, sizeof s, "^ (%d) %s", n, is->district_configs[n].name); + s[(sizeof s) - 1] = '\0'; + PopupForm_add_text (popup, __, s, 0); + } + + patch_show_popup (popup, __, 0, 0); + } + } + } + if (! success) { + error_chunk_name = "district_config_names"; + break; + } + + } else { + error_chunk_name = "N/A"; + break; + } + } + + if (error_chunk_name != NULL) { + char s[200]; + snprintf (s, sizeof s, "Failed to read mod save data. Error occured in chunk: %s", error_chunk_name); + s[(sizeof s) - 1] = '\0'; + pop_up_in_game_error (s); + } + + free (seg); + } + + return tr; +} + +void __fastcall +patch_MappedFile_deinit_after_saving_or_loading (MappedFile * this) +{ + is->accessing_save_file = NULL; + MappedFile_deinit (this); +} + +bool __fastcall +patch_Tile_m7_Check_Barbarian_Camp (Tile * this, int edx, int visible_to_civ) +{ + int * p_stack = (int *)&visible_to_civ; + int ret_addr = p_stack[-1]; + + // If the barb unit AI is calling this method to check if there's a camp to defend, return true if we're allowing barb city capture and the + // tile has a city. This causes barb units to defend cities they've captured, otherwise they'll ignore them. + if ((ret_addr == ADDR_CHECK_BARB_CAMP_TO_DEFEND_RETURN) && + is->current_config.enable_city_capture_by_barbarians && + Tile_has_city (this)) + return true; + else + return Tile_m7_Check_Barbarian_Camp (this, __, visible_to_civ); +} + +bool __fastcall +patch_Unit_can_heal_at (Unit * this, int edx, int tile_x, int tile_y) +{ + if (is->current_config.enable_districts && + is->current_config.enable_port_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea)) { + Tile * tile = tile_at (tile_x, tile_y); + if (tile_has_friendly_port_district (tile, this->Body.CivID)) { + int occupier_id = get_tile_occupier_id (tile_x, tile_y, -1, true); + return (occupier_id == -1) || (occupier_id == this->Body.CivID); + } + } + + return Unit_can_heal_at (this, __, tile_x, tile_y); +} + +bool __fastcall +patch_Unit_can_airdrop (Unit * this) +{ + UnitType * this_type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + + bool allowed = Unit_can_airdrop (this); + + bool require_aerodrome = (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities); + + if (require_aerodrome) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + bool has_aerodrome = false; + + if ((tile != NULL) && (tile != p_null_tile)) + has_aerodrome = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); + + if (! has_aerodrome) + allowed = false; + else if (! allowed) { + if ((this_type->Unit_Class != UTC_Air) && + (this_type->Air_Missions & UCV_Airdrop) && + (this->Body.Moves == 0)) + allowed = true; + } + } + + // Possibly rule in this airdrop as allowed if it's by a paratrooper in a helicopter on a carrier and we're configured to allow airdrops under + // those circumstances. + if ((! allowed) && (is->current_config.special_helicopter_rules & SHR_PASSENGER_AIRDROP)) { + Unit * container = get_unit_ptr (this->Body.Container_Unit); + if (container != NULL && p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) { // if in helicopter + Unit * metacontainer = get_unit_ptr (container->Body.Container_Unit); + if (metacontainer != NULL && p_bic_data->UnitTypes[metacontainer->Body.UnitTypeID].Unit_Class == UTC_Sea && + Unit_has_ability (metacontainer, __, UTA_Transports_Only_Aircraft)) { // if that helicopter is on a carrier + // Allow the airdrop under the same restrictions as from an airfield + allowed = this_type->Unit_Class != UTC_Air && this->Body.Moves == 0; + } + } + } + + if (! allowed) + return false; + + return itable_look_up_or (&is->airdrops_this_turn, this->Body.ID, 0) == 0; +} + +bool __fastcall +patch_City_Improvements_contains (City_Improvements * this, int edx, int id) +{ + byte * extra_bits; + if ((id < 256) || ! is->current_config.remove_city_improvement_limit) + return City_Improvements_contains (this, __, id); + else if (itable_look_up (&is->extra_city_improvs, (int)this, (int *)&extra_bits)) { + int extra_id = id - 256; + return (extra_bits[extra_id>>3] >> (extra_id & 7)) & 1; + } else + return false; +} + +void __fastcall +patch_City_Improvements_set (City_Improvements * this, int edx, int id, bool add_else_remove) +{ + if ((id < 256) || ! is->current_config.remove_city_improvement_limit) + return City_Improvements_set (this, __, id, add_else_remove); + else { + byte * extra_bits = (byte *)itable_look_up_or (&is->extra_city_improvs, (int)this, 0); + int extra_id = id - 256; + byte mask = 1 << (extra_id & 7); + if (add_else_remove) { + if (! extra_bits) { + int extra_bits_size = (not_below (0, p_bic_data->ImprovementsCount - 256) >> 3) + 1; + extra_bits = calloc (1, extra_bits_size); + itable_insert (&is->extra_city_improvs, (int)this, (int)extra_bits); + } + extra_bits[extra_id>>3] |= mask; + } else if ((! add_else_remove) && (extra_bits != NULL)) + extra_bits[extra_id>>3] &= ~mask; + } +} + +bool __fastcall +patch_Leader_has_tech_to_stop_disease (Leader * this, int edx, int id) +{ + if (! is->current_config.patch_disease_stopping_tech_flag_bug) + return Leader_has_tech (this, __, id); + else + return Leader_has_tech_with_flag (this, __, ATF_Disabled_Deseases_From_Flood_Plains); +} + +void __fastcall +patch_set_worker_animation (void * this, int edx, Unit * unit, int job_id) +{ + AnimationType anim_type; + + // If districts disabled or unit is null or job is not building mines, use base logic + if ((! is->current_config.enable_districts) || + (unit == NULL) || + (job_id != WJ_Build_Mines)) { + set_worker_animation(this, __, unit, job_id); + return; + } + + // If tile has a district under construction + Tile * tile = tile_at (unit->Body.X, unit->Body.Y); + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && + ! district_is_complete (tile, inst->district_id) && job_id == WJ_Build_Mines) { + + // Override and ensure build animation is used + job_id = AT_BUILD; + } + + set_worker_animation(this, __, unit, job_id); +} + +void __fastcall +patch_Unit_work_simple_job (Unit * this, int edx, int job_id) +{ + is->lmify_tile_after_working_simple_job = NULL; + + // Check if districts are enabled + if (is->current_config.enable_districts) { + int tile_x = this->Body.X; + int tile_y = this->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + + if (tile != NULL && tile != p_null_tile) { + // Check if there's a completed district on this tile + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete(tile, inst->district_id)) { + int district_id = inst->district_id; + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + + // AI players only (human removal is handled via issue_district_worker_command) + if (!is_human) { + bool allow_removal = false; + if (district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = &inst->wonder_info; + allow_removal = (info->state == WDS_UNUSED); + } + + if (allow_removal) { + remove_district_instance (tile); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, TILE_FLAG_MINE, tile_x, tile_y); + handle_district_removed (tile, district_id, tile_x, tile_y, false); + } + } + } + } + } + + Unit_work_simple_job (this, __, job_id); + + if (is->lmify_tile_after_working_simple_job != NULL) + is->lmify_tile_after_working_simple_job->vtable->m31_set_landmark (is->lmify_tile_after_working_simple_job, __, true); +} + +void __fastcall +patch_Map_change_tile_terrain_by_worker (Map * this, int edx, enum SquareTypes new_terrain_type, int x, int y) +{ + Map_change_tile_terrain (this, __, new_terrain_type, x, y); + + if (is->current_config.convert_to_landmark_after_planting_forest && (new_terrain_type == SQ_Forest)) + is->lmify_tile_after_working_simple_job = tile_at (x, y); +} + +int __fastcall +patch_Leader_ai_eval_technology (Leader * this, int edx, int id, bool param_2, bool param_3) +{ + int base = Leader_ai_eval_technology (this, __, id, param_2, param_3); + return apply_perfume (PK_TECHNOLOGY, p_bic_data->Advances[id].Name, base); +} + +int __fastcall +patch_Leader_ai_eval_government (Leader * this, int edx, int id) +{ + int base = Leader_ai_eval_government (this, __, id); + return apply_perfume (PK_GOVERNMENT, p_bic_data->Governments[id].Name.S, base); +} + +bool +roll_to_spare_unit_from_nuke (Unit * unit) +{ + int one_hp_destroy_chance = is->current_config.chance_for_nukes_to_destroy_max_one_hp_units; + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + if ((one_hp_destroy_chance < 100) && + (Unit_get_max_hp (unit) <= 1) && + (type->Defence > 0) && + ((type->Unit_Class == UTC_Land) || (type->Unit_Class == UTC_Sea))) + return ! (rand_int (p_rand_object, __, 100) < one_hp_destroy_chance); + else + return false; +} + +void __fastcall +patch_Unit_despawn_after_killed_by_nuke (Unit * this, int edx, int civ_id_responsible, byte param_2, byte param_3, byte param_4, byte param_5, byte param_6, byte param_7) +{ + if (roll_to_spare_unit_from_nuke (this)) + this->Body.Damage = Unit_get_max_hp (this) - 1; + else { + bool prev_always_despawn_passengers = is->always_despawn_passengers; + if ((is->current_config.land_transport_rules & LTR_NO_ESCAPE) && is_land_transport (this)) + is->always_despawn_passengers = true; + else if ((is->current_config.special_helicopter_rules & SHR_NO_ESCAPE) && p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air && + p_bic_data->UnitTypes[this->Body.UnitTypeID].Transport_Capacity > 0) + is->always_despawn_passengers = true; + patch_Unit_despawn (this, __, civ_id_responsible, param_2, param_3, param_4, param_5, param_6, param_7); + is->always_despawn_passengers = prev_always_despawn_passengers; + } +} + +void __fastcall +patch_mp_despawn_after_killed_by_nuke (void * this, int edx, int unit_id, int civ_id_responsible, byte param_3, byte param_4, byte param_5, byte param_6) +{ + Unit * unit = get_unit_ptr (unit_id); + if ((unit != NULL) && roll_to_spare_unit_from_nuke (unit)) + unit->Body.Damage = Unit_get_max_hp (unit) - 1; + else + mp_despawn (this, __, unit_id, civ_id_responsible, param_3, param_4, param_5, param_6); +} + +bool __fastcall +patch_City_has_unprotected_improv_to_sell (City * this, int edx, int id) +{ + // Fall back to original logic only if the config doesn't alter the behavior. + if (! is->current_config.allow_sale_of_aqueducts_and_hospitals && !is->current_config.allow_sale_of_small_wonders) + return City_has_unprotected_improv (this, __, id); + + else if (patch_City_has_improvement (this, __, id, false)) { + Improvement * improv = &p_bic_data->Improvements[id]; + int max_pop_to_sell = INT_MAX; // By default, population-based sell isn't restricted + if (improv->ImprovementFlags & (ITF_Allows_City_Level_2 | ITF_Allows_City_Level_3)) { // Aqueduct/Hospital? + if (is->current_config.allow_sale_of_aqueducts_and_hospitals) { + if (improv->ImprovementFlags & ITF_Allows_City_Level_2) + max_pop_to_sell = p_bic_data->General.MaximumSize_Town; + else if (improv->ImprovementFlags & ITF_Allows_City_Level_3) + max_pop_to_sell = p_bic_data->General.MaximumSize_City; + } else { + // Do not allow selling these. + max_pop_to_sell = 0; + } + } + + // Can't sell: + // - Great Wonders + // - Small Wonders, unless the config allows it + // - Capital + // - Aqueduct/Hospital if the city is too big for that population + return ((improv->Characteristics & ITC_Wonder) == 0) && + (is->current_config.allow_sale_of_small_wonders || ((improv->Characteristics & ITC_Small_Wonder) == 0)) && + ((improv->ImprovementFlags & ITF_Center_of_Empire) == 0) && + (this->Body.Population.Size <= max_pop_to_sell); + + } else + return false; +} + +bool __fastcall +patch_UnitType_has_detector_ability_for_vis_check (UnitType * this, int edx, enum UnitTypeAbilities a) +{ + bool tr = UnitType_has_ability (this, __, a); + + // Restrict detection by sea units to other sea units and non-sea units to other non-sea units + if (tr && + is->current_config.no_cross_shore_detection && + (is->checking_visibility_for_unit != NULL) && + ((this->Unit_Class == UTC_Sea) ^ (p_bic_data->UnitTypes[is->checking_visibility_for_unit->Body.UnitTypeID].Unit_Class == UTC_Sea))) + tr = false; + + return tr; +} + +bool +is_airdrop_trespassing (Unit * unit, int target_x, int target_y) +{ + if (is->current_config.disallow_trespassing && + check_trespassing (unit->Body.CivID, tile_at (unit->Body.X, unit->Body.Y), tile_at (target_x, target_y))) { + bool allowed = is_allowed_to_trespass (unit); + + // If "unit" is an air unit that can carry others, like helicopters, then this airdrop is only allowed if all of its passengers are + // allowed to trespass. + UnitType * type = &p_bic_data->UnitTypes[unit->Body.UnitTypeID]; + if (allowed && (type->Unit_Class == UTC_Air) && (type->Transport_Capacity > 0)) + FOR_UNITS_ON (uti, tile_at (unit->Body.X, unit->Body.Y)) + if ((uti.unit->Body.Container_Unit == unit->Body.ID) && + (! is_allowed_to_trespass (uti.unit))) { + allowed = false; + break; + } + + return ! allowed; + } else + return false; +} + +bool __fastcall +patch_Unit_check_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) +{ + return Unit_check_airdrop_target (this, __, tile_x, tile_y) && + is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID) && + ! is_airdrop_trespassing (this, tile_x, tile_y); +} + +bool __fastcall +patch_Unit_can_airlift (Unit * this) +{ + bool base = Unit_can_airlift (this); + + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) + return base; + + Tile * tile = tile_at (this->Body.X, this->Body.Y); + if ((tile == NULL) || (tile == p_null_tile)) + return base; + + bool allow_from_non_city = false; + if (base) { + City * city = city_at (this->Body.X, this->Body.Y); + if ((city == NULL) || (city->Body.CivID != this->Body.CivID)) + allow_from_non_city = true; + } + + if (allow_from_non_city) + return true; + + return tile_has_friendly_aerodrome_district (tile, this->Body.CivID, true); +} + +bool __fastcall +patch_Unit_check_airlift_target (Unit * this, int edx, int tile_x, int tile_y) +{ + bool base = Unit_check_airlift_target (this, __, tile_x, tile_y); + bool allowed = base; + + Tile * tile = tile_at (tile_x, tile_y); + + if (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities) { + if ((tile == NULL) || (tile == p_null_tile)) { + allowed = false; + } else { + City * target_city = city_at (tile_x, tile_y); + if (allowed && + (target_city != NULL) && + (target_city->Body.CivID == this->Body.CivID)) + allowed = false; + + if (! allowed) + allowed = tile_has_friendly_aerodrome_district (tile, this->Body.CivID, false); + } + } + + if (! allowed) + return false; + + return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); +} + +void __fastcall +patch_Unit_airlift (Unit * this, int edx, int tile_x, int tile_y) +{ + Tile * source_tile = NULL; + bool mark_usage = false; + + if (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities) { + source_tile = tile_at (this->Body.X, this->Body.Y); + if (tile_has_friendly_aerodrome_district (source_tile, this->Body.CivID, true)) + mark_usage = true; + } + + Unit_airlift (this, __, tile_x, tile_y); + + if (mark_usage && (source_tile != NULL) && (source_tile != p_null_tile)) { + int mask = itable_look_up_or (&is->aerodrome_airlift_usage, (int)source_tile, 0); + mask |= (1 << this->Body.CivID); + itable_insert (&is->aerodrome_airlift_usage, (int)source_tile, mask); + } +} + +int __fastcall +patch_City_count_airports_for_ai_airlift_target (City * this, int edx, enum ImprovementTypeFlags airport_flag) +{ + // When this function is called, the AI unit being moved is stored in register ESI. + Unit * unit; + __asm__ __volatile__("mov %%esi, %0" : "=r" (unit)); + + int tr = City_count_improvements_with_flag (this, __, airport_flag); + + // Check the stack limit here. If the city's tile is at the limit, return that it has no airport so the AI can't airlift there. + if ((tr > 0) && ! is_below_stack_limit (tile_at (this->Body.X, this->Body.Y), this->Body.CivID, unit->Body.UnitTypeID)) + return 0; + + else + return tr; +} + +int __fastcall +patch_Unit_ai_eval_airdrop_target (Unit * this, int edx, int tile_x, int tile_y) +{ + int tr = Unit_ai_eval_airdrop_target (this, __, tile_x, tile_y); + + // Prevent the AI from airdropping onto tiles in violation of the stack limit or trespassing restriction + if ((tr > 0) && + ((! is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID)) || + is_airdrop_trespassing (this, tile_x, tile_y))) + tr = 0; + + return tr; +} + +bool __fastcall +patch_Unit_find_telepad_on_tile (Unit * this, int edx, int x, int y, bool show_selection_popup, Unit ** out_unit_telepad) +{ + if (! is_below_stack_limit (tile_at (x, y), this->Body.CivID, this->Body.UnitTypeID)) { + *out_unit_telepad = NULL; + return false; + } else + return Unit_find_telepad_on_tile (this, __, x, y, show_selection_popup, out_unit_telepad); +} + +bool __fastcall +patch_Unit_ai_go_to_capital (Unit * this) +{ + City * capital = get_city_ptr (leaders[this->Body.CivID].CapitalID); + + // Block going to capital if the capital's tile is at the stack limit. This stops the AI from airlifting there (would violate the limit) and + // saves it from trying to pathfind there. + if ((capital != NULL) && + ! is_below_stack_limit (tile_at (capital->Body.X, capital->Body.Y), this->Body.CivID, this->Body.UnitTypeID)) + return false; + + return Unit_ai_go_to_capital (this); +} + +bool __fastcall +patch_Unit_is_in_rebase_range (Unit * this, int edx, int tile_x, int tile_y) +{ + bool in_range; + + // 6 is the game's standard value, so fall back on the base game logic in that case + if (is->current_config.rebase_range_multiplier == 6) + in_range = Unit_is_in_rebase_range (this, __, tile_x, tile_y); + + else { + int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + if (op_range < 1) + op_range = 500; + + int x_dist = Map_get_x_dist (&p_bic_data->Map, __, tile_x, this->Body.X), + y_dist = Map_get_y_dist (&p_bic_data->Map, __, tile_y, this->Body.Y); + + in_range = ((x_dist + y_dist) >> 1) <= (op_range * is->current_config.rebase_range_multiplier); + } + + return in_range && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); +} + +bool __fastcall +patch_Unit_check_rebase_target (Unit * this, int edx, int tile_x, int tile_y) +{ + // Check if this is an air unit + bool is_air_unit = (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Air); + + // If districts are enabled and this is an air unit, check for aerodrome districts + if (is_air_unit && is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts) { + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile != NULL) && (tile != p_null_tile)) { + // Check if tile has a district + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + int district_id = inst->district_id; + // Check if this is an aerodrome district owned by this unit's civ + if ((district_id == AERODROME_DISTRICT_ID) && (tile->Territory_OwnerID == this->Body.CivID)) { + // Check if aerodrome is complete + if (district_is_complete (tile, district_id)) { + // Perform range check + bool in_range = patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y); + if (in_range) { + return is_below_stack_limit (tile, this->Body.CivID, this->Body.UnitTypeID); + } + } + } + } + + // If air_units_use_aerodrome_districts_not_cities is enabled, check if there's a city and disallow it + if (is->current_config.air_units_use_aerodrome_districts_not_cities) { + City * target_city = city_at (tile_x, tile_y); + if (target_city != NULL && target_city->Body.CivID == this->Body.CivID) { + // There's a friendly city here - disallow landing since configured to use aerodromes/airfields/carriers only + return false; + } + } + } + } + + // 6 is the game's standard value, so fall back on the base game logic in that case + if (is->current_config.rebase_range_multiplier == 6) { + return Unit_check_rebase_target (this, __, tile_x, tile_y) && is_below_stack_limit (tile_at (tile_x, tile_y), this->Body.CivID, this->Body.UnitTypeID); + + // Otherwise, we have to redo the range check. Unlike Unit::is_in_rebase_range, the base method here does more than just check the range so we + // want to make sure to call it even if we determine that the target is in range. In that case, set the range to unlimited temporarily so the + // base game's range check passes. + } else { + if (patch_Unit_is_in_rebase_range (this, __, tile_x, tile_y)) { + int * p_op_range = &p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + int original_op_range = *p_op_range; + *p_op_range = 0; + bool tr = Unit_check_rebase_target (this, __, tile_x, tile_y); + *p_op_range = original_op_range; + return tr; + } else + return false; + } +} + +int __fastcall +patch_Sprite_draw_already_worked_tile_img (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + Sprite * to_draw = this; + + if (is->do_not_draw_already_worked_tile_img) + return 0; + + if (is->current_config.toggle_zoom_with_z_on_city_screen && p_bic_data->is_zoomed_out) { + + // Load sprite if necessary + if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_UNINITED) { + is->tile_already_worked_zoomed_out_sprite_init_state = IS_INIT_FAILED; + PCX_Image * pcx = malloc (sizeof *pcx); + if (pcx != NULL) { + memset (pcx, 0, sizeof *pcx); + PCX_Image_construct (pcx); + char path[2*MAX_PATH]; + get_mod_art_path ("TileAlreadyWorkedZoomedOut.pcx", path, sizeof path); + PCX_Image_read_file (pcx, __, path, NULL, 0, 0x100, 2); + if (pcx->JGL.Image != NULL) { + Sprite * sprite = &is->tile_already_worked_zoomed_out_sprite; + memset (sprite, 0, sizeof *sprite); + Sprite_construct (sprite); + Sprite_slice_pcx (sprite, __, pcx, 0, 0, 64, 32, 1, 1); + is->tile_already_worked_zoomed_out_sprite_init_state = IS_OK; + } + pcx->vtable->destruct (pcx, __, 0); + free (pcx); + } + } + + if (is->tile_already_worked_zoomed_out_sprite_init_state == IS_OK) + to_draw = &is->tile_already_worked_zoomed_out_sprite; + } + + return Sprite_draw (to_draw, __, canvas, pixel_x, pixel_y, color_table); +} + +int __fastcall +patch_Tile_m43_Get_field_30_for_city_loc_eval (Tile * this) +{ + int tr = this->vtable->m43_Get_field_30 (this); + + // This patch function replaces two places where ai_eval_city_location calls Tile::m43_Get_field_30 to check the 18th bit, which indicates + // whether the tile is in the workable area of any city. If it is but the work area has been expanded, check that it's actually within the + // normal 20-tile area. This prevents work area expansion from causing AIs to space their cities further apart. + // The field_30_get_counter is a crazy workaround for the fact that the game doesn't have any way to determine a tile's coordinates given a + // pointer to its object. So we track the initial (x, y) for the tile we're evaluating and then count calls to this func to know what + // neighboring coords "this" corresponds to. + int get_counter = is->ai_evaling_city_field_30_get_counter; + if (((tr >> 17) & 1) && (is->current_config.city_work_radius >= 3)) { + bool found_city = false; + int this_x, this_y; { + int dx, dy; + patch_ni_to_diff_for_work_area (get_counter, &dx, &dy); + this_x = is->ai_evaling_city_loc_x + dx; + this_y = is->ai_evaling_city_loc_y + dy; + wrap_tile_coords (&p_bic_data->Map, &this_x, &this_y); + } + FOR_TILES_AROUND (tai, 21, this_x, this_y) + if (Tile_has_city (tai.tile)) { + found_city = true; + break; + } + if (! found_city) + tr &= ~(1 << 17); + } + get_counter++; + if (get_counter >= 21) + get_counter = 0; + is->ai_evaling_city_field_30_get_counter = get_counter; + + return tr; + +} + +// Intercept the call where the game gets a random index at which to start searching for a suitable tile to become polluted. Normally, it passes 20 as +// the limit here. We must replace that to cover a potentially modded work area. +int __fastcall +patch_rand_int_to_place_pollution (void * this, int edx, int lim) +{ + return rand_int (this, __, is->workable_tile_count - 1); +} + +void __fastcall +patch_Main_Screen_Form_t2s_coords_to_draw_yields (Main_Screen_Form * this, int edx, int tile_x, int tile_y, int * out_x, int * out_y) +{ + Main_Screen_Form_tile_to_screen_coords (this, __, tile_x, tile_y, out_x, out_y); + + // If we've zoomed out the map on the city screen, we may end up drawing the tile yields off screen depending on the map size. If this is the + // case, detected by negative screen coords, then shift the coords over by one map-screen back onto the actual screen. The shift amounts are + // 64*map_width/2 and 32*map_height/2 for x and y because (64, 32) is the size of a zoomed out tile and /2 is for overlap (I think). + if (p_bic_data->is_zoomed_out && (*out_x < 0)) + *out_x += p_bic_data->Map.Width << 5; + if (p_bic_data->is_zoomed_out && (*out_y < 0)) + *out_y += p_bic_data->Map.Height << 4; +} + +void +set_clip_area_to_map_view (City_Form * city_form) +{ + int left_margin = (p_bic_data->ScreenWidth - city_form->Background_Image.Width) / 2, + top_margin = (p_bic_data->ScreenHeight - city_form->Background_Image.Height) / 2; + RECT map_view_on_screen = { .left = left_margin, .top = top_margin + 92, .right = left_margin + 1024, .bottom = top_margin + 508 }; + JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; + jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &map_view_on_screen); +} + +void +clear_clip_area (City_Form * city_form) +{ + JGL_Image * jgl_canvas = city_form->Base.Data.Canvas.JGL.Image; + jgl_canvas->vtable->m13_Set_Clip_Region (jgl_canvas, __, &jgl_canvas->Image_Rect); +} + +void +init_distribution_hub_icons () +{ + if (is->distribution_hub_icons_img_state != IS_UNINITED) + return; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + char ss[200]; + snprintf (ss, sizeof ss, "[C3X] init_distribution_hub_icons: state=%d\n", is->distribution_hub_icons_img_state); + (*p_OutputDebugStringA) (ss); + + char temp_path[2*MAX_PATH]; + get_mod_art_path ("Districts/DistributionHubIncomeIcons.pcx", temp_path, sizeof temp_path); + + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + if ((pcx.JGL.Image == NULL) || + (pcx.JGL.Image->vtable->m54_Get_Width (pcx.JGL.Image) < 776) || + (pcx.JGL.Image->vtable->m55_Get_Height (pcx.JGL.Image) < 32)) { + (*p_OutputDebugStringA) ("[C3X] PCX file for distribution hub icons failed to load or is too small.\n"); + is->distribution_hub_icons_img_state = IS_INIT_FAILED; + goto cleanup; + } + + // Extract shield icon (index 4: x = 1 + 4*31 = 125, width 30) + Sprite_construct (&is->distribution_hub_shield_icon); + Sprite_slice_pcx (&is->distribution_hub_shield_icon, __, &pcx, 1 + 4*31, 1, 30, 30, 1, 1); + + // Extract shield corruption icon (index 5: x = 1 + 5*31 = 156, width 30) + Sprite_construct (&is->distribution_hub_corruption_icon); + Sprite_slice_pcx (&is->distribution_hub_corruption_icon, __, &pcx, 1 + 5*31, 1, 30, 30, 1, 1); + + // Extract small shield icon (index 13) + Sprite_construct (&is->distribution_hub_shield_icon_small); + Sprite_slice_pcx (&is->distribution_hub_shield_icon_small, __, &pcx, 1 + 13*31, 1, 30, 30, 1, 1); + + // Extract surplus food icon (index 6: x = 1 + 6*31 = 187, width 30) + Sprite_construct (&is->distribution_hub_food_icon); + Sprite_slice_pcx (&is->distribution_hub_food_icon, __, &pcx, 1 + 6*31, 1, 30, 30, 1, 1); + + // Extract small surplus food icon (index 15) + Sprite_construct (&is->distribution_hub_food_icon_small); + Sprite_slice_pcx (&is->distribution_hub_food_icon_small, __, &pcx, 1 + 15*31, 1, 30, 30, 1, 1); + + // Extract eaten food icon (index 7: x = 1 + 7*31 = 218, width 30) + Sprite_construct (&is->distribution_hub_eaten_food_icon); + Sprite_slice_pcx (&is->distribution_hub_eaten_food_icon, __, &pcx, 1 + 7*31, 1, 30, 30, 1, 1); + + is->distribution_hub_icons_img_state = IS_OK; +cleanup: + pcx.vtable->destruct (&pcx, __, 0); +} + +void +draw_district_yields (City_Form * city_form, Tile * tile, int district_id, int screen_x, int screen_y) +{ + // Lazy load district icons + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + if (is->dc_icons_img_state != IS_OK) + return; + + if (district_id < 0 || district_id >= is->district_count) + return; + + // Get district configuration + struct district_config * config = &is->district_configs[district_id]; + struct district_instance * inst = get_district_instance (tile); + + // Count total yields from bonuses + int food_bonus = 0, shield_bonus = 0, gold_bonus = 0, science_bonus = 0, culture_bonus = 0, happiness_bonus = 0; + get_effective_district_yields (inst, config, &food_bonus, &shield_bonus, &gold_bonus, &science_bonus, &culture_bonus, &happiness_bonus); + if ((config->generated_resource_id >= 0) && + (config->generated_resource_flags & MF_YIELDS) && + (city_form->CurrentCity != NULL) && + district_generates_resource_for_civ (tile, inst, config, city_form->CurrentCity->Body.CivID)) { + Resource_Type * res = &p_bic_data->ResourceTypes[config->generated_resource_id]; + food_bonus += res->Food; + shield_bonus += res->Shield; + gold_bonus += res->Commerce; + } + + int food_pos = food_bonus > 0 ? food_bonus : 0; + int food_neg = food_bonus < 0 ? -food_bonus : 0; + int shield_pos = shield_bonus > 0 ? shield_bonus : 0; + int shield_neg = shield_bonus < 0 ? -shield_bonus : 0; + int gold_pos = gold_bonus > 0 ? gold_bonus : 0; + int gold_neg = gold_bonus < 0 ? -gold_bonus : 0; + int science_pos = science_bonus > 0 ? science_bonus : 0; + int science_neg = science_bonus < 0 ? -science_bonus : 0; + int culture_pos = culture_bonus > 0 ? culture_bonus : 0; + int culture_neg = culture_bonus < 0 ? -culture_bonus : 0; + int happiness_pos = happiness_bonus > 0 ? happiness_bonus : 0; + int happiness_neg = happiness_bonus < 0 ? -happiness_bonus : 0; + + int total_yield = 0; + total_yield += food_pos + food_neg; + total_yield += shield_pos + shield_neg; + total_yield += gold_pos + gold_neg; + total_yield += science_pos + science_neg; + total_yield += culture_pos + culture_neg; + total_yield += happiness_pos + happiness_neg; + + if (total_yield <= 0) + return; + + // Get sprites + Sprite * food_sprite = &is->district_food_icon_small; + Sprite * shield_sprite = &is->district_shield_icon_small; + Sprite * commerce_sprite = &is->district_commerce_icon_small; + Sprite * science_sprite = &is->district_science_icon_small; + Sprite * culture_sprite = &is->district_culture_icon_small; + Sprite * happiness_sprite = &is->district_happiness_icon_small; + Sprite * food_negative_sprite = &is->district_negative_food_icon_small; + Sprite * shield_negative_sprite = &is->district_negative_shield_icon_small; + Sprite * commerce_negative_sprite = &is->district_negative_commerce_icon_small; + Sprite * science_negative_sprite = &is->district_negative_science_icon_small; + Sprite * culture_negative_sprite = &is->district_negative_culture_icon_small; + Sprite * happiness_negative_sprite = &is->district_unhappiness_icon_small; + + // Determine sprite dimensions + int sprite_width = food_sprite->Width3; + int sprite_height = food_sprite->Height; + + // Calculate total width of all icons + int total_width = total_yield * sprite_width; + + // Center the icons horizontally + int half_width = total_width >> 1; + int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; + int max_offset = (tile_width >> 1) - 5; + if (half_width > max_offset) + half_width = max_offset; + + int pixel_x = screen_x - half_width; + int pixel_y = screen_y - (sprite_height >> 1); + + // Adjust spacing if icons would exceed tile width + int spacing = sprite_width; + if (total_width > tile_width - 10) { + if (total_yield > 1) { + spacing = (tile_width - 10 - sprite_width) / (total_yield - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > sprite_width) + spacing = sprite_width; + } + } + + // Draw icons in order: shields, food, science, commerce, culture + for (int i = 0; i < shield_pos; i++) { + Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < shield_neg; i++) { + Sprite_draw (shield_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < food_pos; i++) { + Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < food_neg; i++) { + Sprite_draw (food_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < science_pos; i++) { + Sprite_draw (science_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < science_neg; i++) { + Sprite_draw (science_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < gold_pos; i++) { + Sprite_draw (commerce_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < gold_neg; i++) { + Sprite_draw (commerce_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < culture_pos; i++) { + Sprite_draw (culture_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < culture_neg; i++) { + Sprite_draw (culture_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + + for (int i = 0; i < happiness_pos; i++) { + Sprite_draw (happiness_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } + for (int i = 0; i < happiness_neg; i++) { + Sprite_draw (happiness_negative_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing; + } +} + +void +draw_distribution_hub_yields (City_Form * city_form, Tile * tile, int tile_x, int tile_y, int screen_x, int screen_y) +{ + // Get the distribution hub record for this tile + struct distribution_hub_record * rec = get_distribution_hub_record (tile); + if (rec == NULL) + return; + + City * anchor_city = get_connected_city_for_distribution_hub (rec); + if (! distribution_hub_accessible_to_city (rec, city_form->CurrentCity)) + return; + + int food_yield = rec->food_yield; + int shield_yield = rec->shield_yield; + int total_yield = food_yield + shield_yield; + + if (total_yield <= 0) + return; + + // Lazy load distribution hub icons + if (is->distribution_hub_icons_img_state == IS_UNINITED) + init_distribution_hub_icons (); + if (is->distribution_hub_icons_img_state != IS_OK) + return; + + Sprite * food_sprite = &is->distribution_hub_food_icon_small; + Sprite * shield_sprite = &is->distribution_hub_shield_icon_small; + + if (food_sprite->Width3 == 0) food_sprite = &is->distribution_hub_food_icon; + if (shield_sprite->Width3 == 0) shield_sprite = &is->distribution_hub_shield_icon; + + int sprite_height = food_sprite->Height; + if (sprite_height == 0) sprite_height = shield_sprite->Height; + + int food_width = food_sprite->Width3; + int shield_width = shield_sprite->Width3; + if ((food_width <= 0) && (shield_width > 0)) food_width = shield_width; + if ((shield_width <= 0) && (food_width > 0)) shield_width = food_width; + + // Calculate total width of all icons + int total_width = 0; + if (food_yield > 0) total_width += food_width * food_yield; + if (shield_yield > 0) total_width += shield_width * shield_yield; + + // Center the icons horizontally + int half_width = total_width >> 1; + int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; + int max_offset = (tile_width >> 1) - 5; + if (half_width > max_offset) half_width = max_offset; + + int pixel_x = screen_x - half_width; + int pixel_y = screen_y - (sprite_height >> 1); + + // Adjust spacing if icons would exceed tile width + int spacing_food = food_width; + int spacing_shield = shield_width; + + if (total_width > tile_width - 10) { + if (total_yield > 1) { + int spacing = (tile_width - 10 - food_width) / (total_yield - 1); + if (spacing < 1) + spacing = 1; + else if (spacing > food_width) + spacing = food_width; + spacing_food = spacing; + spacing_shield = spacing; + } + } + + // Draw food icons first + for (int i = 0; i < food_yield; i++) { + Sprite_draw (food_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing_food; + } + + // Draw shield icons + for (int i = 0; i < shield_yield; i++) { + Sprite_draw (shield_sprite, __, &city_form->Base.Data.Canvas, pixel_x, pixel_y, NULL); + pixel_x += spacing_shield; + } +} + +void __fastcall +patch_City_Form_draw_yields_on_worked_tiles (City_Form * this) +{ + // If we're zoomed in and the city work radius is at least 4 then it's likely we'll end up drawing things outside of the city screen's usual + // map area. Set the clip area to the map area so none of those draws are visible. + bool changed_clip_area = false; + if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { + set_clip_area_to_map_view (this); + changed_clip_area = true; + } + + if (is->current_config.enable_districts && this->CurrentCity != NULL) { + recompute_city_yields_with_districts (this->CurrentCity); + } + + is->do_not_draw_already_worked_tile_img = false; + City_Form_draw_yields_on_worked_tiles (this); + + // If we're zoomed out then draw the yields again but this time skip drawing of the tile-already-worked sprites. This is because the + // transparent regions of those sprites get drawn overtop of the yield sprites when zoomed out, and that overdrawing deletes parts of the + // yields, i.e., it overwrites their colored pixels with transparent ones. The simplest solution is to draw the yields again after the + // already-worked sprites to ensure the former get drawn overtop of the latter. + if (p_bic_data->is_zoomed_out) { + is->do_not_draw_already_worked_tile_img = true; + City_Form_draw_yields_on_worked_tiles (this); + } + + // Draw district bonuses on district tiles + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + City * city = this->CurrentCity; + if (city == NULL) + goto skip_district_yields; + + int city_x = city->Body.X; + int city_y = city->Body.Y; + int civ_id = city->Body.CivID; + + // Calculate screen coordinates for city center + int center_screen_x, center_screen_y; + Main_Screen_Form_tile_to_screen_coords (p_main_screen_form, __, city_x, city_y, ¢er_screen_x, ¢er_screen_y); + + int tile_half_width = p_bic_data->is_zoomed_out ? 32 : 64; + int tile_half_height = p_bic_data->is_zoomed_out ? 16 : 32; + center_screen_x += tile_half_width; + if (center_screen_x < 0) + center_screen_x += p_bic_data->Map.Width * tile_half_width; + center_screen_y += tile_half_height; + if (center_screen_y < 0) + center_screen_y += p_bic_data->Map.Height * tile_half_height; + + int remaining_utilized_neighborhoods = 0; + if (is->current_config.enable_districts && is->current_config.enable_neighborhood_districts) + remaining_utilized_neighborhoods = count_utilized_neighborhoods_in_city_radius (city); + + FOR_DISTRICTS_AROUND (wai, city_x, city_y, true) { + struct district_instance * inst = wai.district_inst; + int district_id = inst->district_id; + + bool is_distribution_hub = district_id == DISTRIBUTION_HUB_DISTRICT_ID; + bool is_natural_wonder = district_id == NATURAL_WONDER_DISTRICT_ID; + + if (is_natural_wonder && (!is->current_config.enable_natural_wonders)) + continue; + + // Distribution hubs are drawn in the dedicated wider-radius pass below. + if (is_distribution_hub) + continue; + + if (!is_natural_wonder && (!is->current_config.enable_districts)) + continue; + + // For neighborhood districts, check if population is high enough to utilize them + if (is->current_config.enable_districts && + is->current_config.enable_neighborhood_districts && + district_id == NEIGHBORHOOD_DISTRICT_ID) { + // Only draw yields if this neighborhood is utilized + if (remaining_utilized_neighborhoods <= 0) + continue; + remaining_utilized_neighborhoods--; + } + + // Calculate screen coordinates for this tile + int screen_x = center_screen_x + (wai.dx * tile_half_width); + int screen_y = center_screen_y + (wai.dy * tile_half_height); + + // Call the appropriate drawing function + draw_district_yields (this, wai.tile, district_id, screen_x, screen_y); + } + + // Draw distribution hub yields around a larger radius so connected hubs outside the work area are shown + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { + int const max_tiles = workable_tile_counts[7]; + + for (int ni = 0; ni < max_tiles; ni++) { + int dx, dy; + patch_ni_to_diff_for_work_area (ni, &dx, &dy); + + int tile_x = city_x + dx; + int tile_y = city_y + dy; + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != DISTRIBUTION_HUB_DISTRICT_ID)) + continue; + + int screen_x = center_screen_x + (dx * tile_half_width); + int screen_y = center_screen_y + (dy * tile_half_height); + draw_distribution_hub_yields (this, tile, tile_x, tile_y, screen_x, screen_y); + } + } + } + +skip_district_yields: + if (changed_clip_area) + clear_clip_area (this); +} + +bool __fastcall +patch_City_Form_draw_highlighted_yields (City_Form * this, int edx, int tile_x, int tile_y, int neighbor_index) +{ + // Make sure we don't draw outside the map area + bool changed_clip_area = false; + if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { + set_clip_area_to_map_view (this); + changed_clip_area = true; + } + + bool tr = City_Form_draw_highlighted_yields (this, __, tile_x, tile_y, neighbor_index); + + if (changed_clip_area) + clear_clip_area (this); + return tr; +} + +void __fastcall +patch_City_Form_draw_border_around_workable_tiles (City_Form * this) +{ + // Make sure we don't draw outside the map area + bool changed_clip_area = false; + if ((is->current_config.city_work_radius >= 4) && ! p_bic_data->is_zoomed_out) { + set_clip_area_to_map_view (this); + changed_clip_area = true; + } + + City_Form_draw_border_around_workable_tiles (this); + + if (changed_clip_area) + clear_clip_area (this); +} + +bool __fastcall +patch_City_stop_working_polluted_tile (City * this, int edx, int neighbor_index) +{ + if (is->current_config.do_not_unassign_workers_from_polluted_tiles && + (*p_human_player_bits & (1 << this->Body.CivID))) + return false; // do nothing; return value is not used + else + return City_stop_working_tile (this, __, neighbor_index); +} + +void __fastcall +patch_City_manage_by_governor (City * this, int edx, bool manage_professions) +{ + int * p_stack = (int *)&manage_professions; + int ret_addr = p_stack[-1]; + + // Do nothing if called after spawning pollution but didn't unassign worker + if ((ret_addr == ADDR_MANAGE_CITY_AFTER_POLLUTION_RETURN) && + is->current_config.do_not_unassign_workers_from_polluted_tiles && + (*p_human_player_bits & (1 << this->Body.CivID))) + return; + + City_manage_by_governor (this, __, manage_professions); +} + +City * __cdecl +patch_find_nearest_city_for_ai_alliance_eval (int tile_x, int tile_y, int owner_id, int continent_id, int ignore_owner_id, int perspective_id, City * ignore_city) +{ + City * tr = find_nearest_city (tile_x, tile_y, owner_id, continent_id, ignore_owner_id, perspective_id, ignore_city); + if (is->current_config.patch_division_by_zero_in_ai_alliance_eval && (*p_nearest_city_distance == 0)) + *p_nearest_city_distance = 1; + return tr; +} + +int __fastcall +patch_Unit_get_max_move_points (Unit * this) +{ + if (Unit_has_ability (this, __, UTA_Army) && is->current_config.patch_empty_army_movement) { + int slowest_member_mp = INT_MAX; + bool any_units_in_army = false; + FOR_UNITS_ON (uti, tile_at (this->Body.X, this->Body.Y)) { + if (uti.unit->Body.Container_Unit == this->Body.ID) { + any_units_in_army = true; + slowest_member_mp = not_above (Unit_get_max_move_points (uti.unit), slowest_member_mp); + } + } + if (any_units_in_army) + return slowest_member_mp + p_bic_data->General.RoadsMovementRate; + else + return get_max_move_points (&p_bic_data->UnitTypes[this->Body.UnitTypeID], this->Body.CivID); + } else + return Unit_get_max_move_points (this); +} + +char __fastcall +patch_Unit_is_visible_to_civ_for_bouncing (Unit * this, int edx, int civ_id, int param_2) +{ + // If we're set not to kick out invisible units and this one is invis. then report that it's not seen so it's left alone + if (is->do_not_bounce_invisible_units && Unit_has_ability (this, __, UTA_Invisible)) + return 0; + else + return patch_Unit_is_visible_to_civ (this, __, civ_id, param_2); +} + +void __fastcall +patch_Leader_make_peace (Leader * this, int edx, int civ_id) +{ + Leader_make_peace (this, __, civ_id); + + if (is->current_config.disallow_trespassing && + (! this->At_War[civ_id]) && // Make sure the war actually ended + ((this->Relation_Treaties[civ_id] & 2) == 0)) { // Check right of passage (just in case) + is->do_not_bounce_invisible_units = true; + Leader_bounce_trespassing_units (&leaders[civ_id], __, this->ID); + is->do_not_bounce_invisible_units = false; + } +} + +// This patch function replaces calls to Leader::count_wonders_with_flag but is only valid in cases where it only matters whether the return value is +// zero or non-zero. This function will not return the actual count, just zero if no wonders are present and some >0 value if there is at least one. +int __fastcall +patch_Leader_count_any_shared_wonders_with_flag (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) +{ + int tr = Leader_count_wonders_with_flag (this, __, flag, only_in_city); + + if ((tr == 0) && + (only_in_city == NULL) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player + + // Sum up wonders owned by other human players + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->ID)) + if (Leader_count_wonders_with_flag (&leaders[n_player], __, flag, only_in_city) > 0) { + tr = 1; + break; + } + player_bits >>= 1; + n_player++; + } + } + + return tr; +} + +int __fastcall +patch_Leader_count_wonders_with_flag_ignore_great_wall (Leader * this, int edx, enum ImprovementTypeWonderFeatures flag, City * only_in_city) +{ + if (is->current_config.enable_districts && + is->current_config.enable_great_wall_districts && + is->current_config.disable_great_wall_city_defense_bonus && + flag == ITW_Doubles_City_Defenses) + return 0; + + return patch_Leader_count_any_shared_wonders_with_flag (this, __, flag, only_in_city); +} + +int const shared_small_wonder_flags = + ITSW_Increases_Chance_of_Leader_Appearance | + ITSW_Build_Larger_Armies | + ITSW_Treasury_Earns_5_Percent | + ITSW_Decreases_Success_Of_Missile_Attacks | + ITSW_Allows_Spy_Missions | + ITSW_Allows_Healing_In_Enemy_Territory | + ITSW_Requires_Victorous_Army | + ITSE_Requires_Elite_Naval_Units; + + +int __fastcall +patch_Leader_count_wonders_with_small_flag (Leader * this, int edx, enum ImprovementTypeSmallWonderFeatures flag, City * city_or_null) +{ + int tr = Leader_count_wonders_with_small_flag (this, __, flag, city_or_null); + + // If "this" is a human player who's sharing wonders in hotseat and the flag is one of the ones that gets shared, include the wonders owned by + // all other humans in the game + if ((city_or_null == NULL) && + (flag & shared_small_wonder_flags) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // is "this" a human player + + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->ID)) + tr += Leader_count_wonders_with_small_flag (&leaders[n_player], __, flag, city_or_null); + player_bits >>= 1; + n_player++; + } + } + + return tr; +} + +int +find_human_player_with_small_wonder (int improv_id) +{ + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if (player_bits & 1) + if (leaders[n_player].Small_Wonders[improv_id] != -1) + return n_player; + player_bits >>= 1; + n_player++; + } + return -1; +} + +bool __fastcall +patch_Leader_can_build_city_improvement (Leader * this, int edx, int i_improv, bool param_2) +{ + Improvement * improv = &p_bic_data->Improvements[i_improv]; + bool restore = false; + bool already_shared = false; + int saved_status, saved_required_building_count, saved_armies_count; + if ((improv->Characteristics & (ITC_Small_Wonder | ITC_Wonder)) && // if the improv in question is a great or small wonder + is->current_config.share_wonders_in_hotseat && // if we're configured to share wonder effects + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // if in a hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // if "this" is a human player + + // If another human player has already built this small wonder and it has no non-shared effects, then make it unbuildable + if ((improv->Characteristics & ITC_Small_Wonder) && + (find_human_player_with_small_wonder (i_improv) != -1) && + ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) + already_shared = true; + + else { + restore = true; + saved_status = this->Status; + if (improv->RequiredBuildingID != -1) + saved_required_building_count = this->Improvement_Counts[improv->RequiredBuildingID]; + saved_armies_count = this->Armies_Count; + + // Loop over all other human players in the game + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != this->ID)) { + + // Combine status bits + this->Status |= leaders[n_player].Status & (LSF_HAS_VICTORIOUS_ARMY | LSF_HAS_ELITE_NAVAL_UNIT); + + // Combine building counts for the required building if there is one + if (improv->RequiredBuildingID != -1) + this->Improvement_Counts[improv->RequiredBuildingID] += leaders[n_player].Improvement_Counts[improv->RequiredBuildingID]; + + // Combine army counts + this->Armies_Count += leaders[n_player].Armies_Count; + + } + player_bits >>= 1; + n_player++; + } + } + } + + bool tr = (! already_shared) && Leader_can_build_city_improvement (this, __, i_improv, param_2); + + if (restore) { + this->Status = saved_status; + if (improv->RequiredBuildingID != -1) + this->Improvement_Counts[improv->RequiredBuildingID] = saved_required_building_count; + + this->Armies_Count = saved_armies_count; + } + return tr; + +} + +void __fastcall +patch_City_add_happiness_from_buildings (City * this, int edx, int * inout_happiness, int * inout_unhappiness) +{ + // If we're in a hotseat game with shared wonder effects, merge all human player's improvement counts together so the base function checks for + // happiness from improvements owned by other human players. + Leader * owner = &leaders[this->Body.CivID]; + bool restore_improv_counts = false; + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->Body.CivID) & *p_human_player_bits)) { // "this" is owned by a human player + + // Ensure the space we've set aside for saving the real improv counts is large enough + if ((is->saved_improv_counts == NULL) || (is->saved_improv_counts_capacity < p_bic_data->ImprovementsCount)) { + free (is->saved_improv_counts); + is->saved_improv_counts = calloc (p_bic_data->ImprovementsCount, sizeof is->saved_improv_counts[0]); + is->saved_improv_counts_capacity = (is->saved_improv_counts != NULL) ? p_bic_data->ImprovementsCount : 0; + } + + + if (is->saved_improv_counts != NULL) { + // Save the owner's real improv counts and remember to restore them before returning + restore_improv_counts = true; + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + is->saved_improv_counts[n] = owner->Improvement_Counts[n]; + + // Add in improv counts for wonders from all other human players in the game + unsigned player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_player = 1; + while (player_bits != 0) { + if ((player_bits & 1) && (n_player != owner->ID)) + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (p_bic_data->Improvements[n].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) + owner->Improvement_Counts[n] += leaders[n_player].Improvement_Counts[n]; + player_bits >>= 1; + n_player++; + } + } + + } + + City_add_happiness_from_buildings (this, __, inout_happiness, inout_unhappiness); + + if (is->current_config.enable_districts) { + int district_happy = 0; + calculate_district_happiness_bonus (this, &district_happy); + + if (district_happy != 0) + *inout_happiness += district_happy; + } + + if (restore_improv_counts) { + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + owner->Improvement_Counts[n] = is->saved_improv_counts[n]; + } +} + +int __fastcall +patch_City_count_other_cont_happiness_buildings (City * this, int edx, int improv_id) +{ + int tr = City_count_other_buildings_on_continent (this, __, improv_id); + + // If it's a hotseat game where we're sharing wonders, "improv_id" refers to a wonder, and "this" is owned by a human player + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((p_bic_data->Improvements[improv_id].Characteristics & (ITC_Wonder | ITC_Small_Wonder)) != 0) && + ((1 << this->Body.CivID) & *p_human_player_bits)) { + + // Add in instances of this improvment on this continent owned by other human players + Tile * this_city_tile = tile_at (this->Body.X, this->Body.Y); + int this_cont_id = this_city_tile->vtable->m46_Get_ContinentID (this_city_tile); + for (int city_index = 0; city_index <= p_cities->LastIndex; city_index++) { + City * city = get_city_ptr (city_index); + if ((city != NULL) && (city != this) && + (city->Body.CivID != this->Body.CivID) && // if city is owned by a different player AND + ((1 << city->Body.CivID) & *p_human_player_bits)) { // that player is a human + Tile * that_city_tile = tile_at (city->Body.X, city->Body.Y); + int that_cont_id = that_city_tile->vtable->m46_Get_ContinentID (that_city_tile); + if ((this_cont_id == that_cont_id) && patch_City_has_improvement (city, __, improv_id, true)) + tr++; + } + } + + } + + return tr; +} + +void __fastcall +patch_Leader_update_great_library_unlocks (Leader * this) +{ + // If it's a hotseat game with shared wonder effects and "this" is a human player, share contacts among all human players so that "this" gets + // techs from civs known to any human player in the game. Save the real contact info and restore it afterward. NOTE: Contact info has to go + // two ways here; we must mark that "this" has contacted the AIs and vice-versa otherwise the techs won't be granted. That's why we must save + // & restore all contact bits for all players. + bool restore_contacts = false; + struct contact_set { + int contacts[32]; + } saved_contact_sets[32]; + if (is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player + + restore_contacts = true; + for (int n = 0; n < 32; n++) + for (int k = 0; k < 32; k++) + saved_contact_sets[n].contacts[k] = leaders[n].Contacts[k]; + + unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_human = 1; + while (human_player_bits != 0) { + if ((human_player_bits & 1) && (n_human != this->ID)) // n_human is ID of a human player other than "this" + for (int n_ai = 0; n_ai < 32; n_ai++) + if ((*p_player_bits & (1 << n_ai)) && ((*p_human_player_bits & (1 << n_ai)) == 0)) { + // If the human and AI players have contact, mark "this" as having contact with the AI and vice-versa + if (leaders[n_human].Contacts[n_ai] & 1) { + this->Contacts[n_ai] |= 1; + leaders[n_ai].Contacts[this->ID] |= 1; + } + } + human_player_bits >>= 1; + n_human++; + } + } + + Leader_update_great_library_unlocks (this); + + if (restore_contacts) + for (int n = 0; n < 32; n++) + for (int k = 0; k < 32; k++) + leaders[n].Contacts[k] = saved_contact_sets[n].contacts[k]; +} + +bool __fastcall +patch_Leader_has_wonder_doubling_happiness_from (Leader * this, int edx, int improv_id) +{ + bool tr = Leader_has_wonder_doubling_happiness_from (this, __, improv_id); + + // If we're sharing wonder effects in a hotseat game and "this" is a human player, return true when another human player in the game has a + // wonder doubling happiness + if ((! tr) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->ID) & *p_human_player_bits)) { // "this" is a human player + unsigned human_player_bits = *(unsigned *)p_human_player_bits >> 1; + int n_human = 1; + while (human_player_bits != 0) { + if ((human_player_bits & 1) && + (n_human != this->ID) && + Leader_has_wonder_doubling_happiness_from (&leaders[n_human], __, improv_id)) { + tr = true; + break; + } + human_player_bits >>= 1; + n_human++; + } + } + + return tr; +} + +int __fastcall +patch_Sprite_draw_citizen_head (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + // Reset variable + is->specialist_icon_drawing_running_x = INT_MIN; + + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +int +adjust_specialist_yield_icon_x (int pixel_x, int width) +{ + if (is->current_config.fix_overlapping_specialist_yield_icons) { + if (is->specialist_icon_drawing_running_x == INT_MIN) // first icon drawn + is->specialist_icon_drawing_running_x = pixel_x; + int tr = is->specialist_icon_drawing_running_x; + is->specialist_icon_drawing_running_x += width; + return tr; + } else + return pixel_x; +} + +int __fastcall +patch_Sprite_draw_entertainer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_12_Happy_Faces.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_scientist_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_16_Science.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_tax_collector_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_14_Gold.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_civil_engineer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_13_Shield.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} +int __fastcall +patch_Sprite_draw_police_officer_yield_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + int width = p_city_form->City_Icons_Images.Icon_17_Gold_Outcome.Width / 2; + return Sprite_draw (this, __, canvas, adjust_specialist_yield_icon_x (pixel_x, width), pixel_y, color_table); +} + +void __fastcall +patch_City_add_building_if_done (City * this) +{ + // If sharing small wonders in hotseat, check whether the city is building a small wonder that's no longer available to the player b/c its + // effects are provided from another. + int improv_id = this->Body.Order_ID; + Improvement * improv = &p_bic_data->Improvements[improv_id]; + int already_built_by_id; + if ((improv->Characteristics & ITC_Small_Wonder) && + is->current_config.share_wonders_in_hotseat && + (*p_is_offline_mp_game && ! *p_is_pbem_game) && // is hotseat game + ((1 << this->Body.CivID) & *p_human_player_bits) && // city owned by a human player + ((already_built_by_id = find_human_player_with_small_wonder (improv_id)) != -1) && // SW already built by another human player + ((improv->SmallWonderFlags & ~shared_small_wonder_flags) == 0)) { // SW has no non-shared effects + + // Switch city production to something else and notify the player + this->vtable->set_production_to_most_expensive_option (this); + if ((this->Body.CivID == p_main_screen_form->Player_CivID) && (already_built_by_id != p_main_screen_form->Player_CivID)) { + char * new_build_name = (this->Body.Order_Type == COT_Improvement) ? + p_bic_data->Improvements[this->Body.Order_ID].Name.S : + p_bic_data->UnitTypes[this->Body.Order_ID].Name; + PopupForm * popup = get_popup_form (); + set_popup_str_param (0, this->Body.CityName, -1, -1); + set_popup_str_param (1, improv->Name.S, -1, -1); + set_popup_str_param (2, Leader_get_civ_noun (&leaders[already_built_by_id]), -1, -1); + set_popup_str_param (3, new_build_name, -1, -1); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_SHARED_WONDER_CHANGE", -1, 0, 0, 0); + int response = patch_show_popup (popup, __, 0, 0); + if (response == 0) + *p_zoom_to_city_after_update = true; + } + + // As in the base logic, if production gets switched, the game doesn't check if it might still complete on the same turn. + return; + } + + // If production ended up on a wonder, make sure the city can actually build it; otherwise fall back to a defensive unit. + int order_type = this->Body.Order_Type; + int order_id = this->Body.Order_ID; + if (is->current_config.enable_districts && order_type == COT_Improvement) { + Improvement * new_improv = &p_bic_data->Improvements[order_id]; // Improvement might have changed + if (new_improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { + if (! (City_can_build_improvement (this, __, order_id, false) && city_meets_district_prereqs_to_build_improvement (this, order_id, true))) { + char ss[256]; + snprintf (ss, sizeof ss, "patch_City_add_building_if_done: City '%s' cannot complete building of wonder '%s'; switching to defensive unit.\n", + this->Body.CityName, + new_improv->Name.S); + (*p_OutputDebugStringA) (ss); + City_Order defensive_order = { .OrderID = -1, .OrderType = 0 }; + if (choose_defensive_unit_order (this, &defensive_order)) { + UnitType * def_type = &p_bic_data->UnitTypes[defensive_order.OrderID]; + if (def_type->Unit_Class == UTC_Land) { + City_set_production (this, __, defensive_order.OrderType, defensive_order.OrderID, false); + return; + } + } + } + } + } + + City_add_building_if_done (this); +} + +bool __fastcall +patch_City_can_build_upgrade_type (City * this, int edx, int unit_type_id, bool exclude_upgradable, int param_3, bool allow_kings) +{ + UnitType * type = &p_bic_data->UnitTypes[unit_type_id]; + if (is->current_config.prevent_old_units_from_upgrading_past_ability_block && + ((type->Special_Actions & UCV_Upgrade_Unit) == 0) && + (type->Available_To & (1 << leaders[this->Body.CivID].RaceID))) + exclude_upgradable = false; + + return patch_City_can_build_unit (this, __, unit_type_id, exclude_upgradable, param_3, allow_kings); +} + +void __fastcall +patch_Main_GUI_position_elements (Main_GUI * this) +{ + Main_GUI_position_elements (this); + + // Double size of minimap if configured + bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || + ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); + if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) { + this->Mini_Map_Click_Rect.top -= 105; + this->Mini_Map_Click_Rect.right += 229; + } +} + +#define PEDIA_DESC_LINES_PER_PAGE 38 + +// Returns whether or not the line should be drawn +bool +do_next_line_for_pedia_desc (PCX_Image * canvas, int * inout_y) +{ + if (is->cmpd.drawing_lines && is->current_config.allow_multipage_civilopedia_descriptions) { + int first_line_on_shown_page = is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE; + int page = is->cmpd.line_count / PEDIA_DESC_LINES_PER_PAGE; + is->cmpd.line_count += 1; + is->cmpd.last_page = (page > is->cmpd.last_page) ? page : is->cmpd.last_page; + + if (page == is->cmpd.shown_page) { + *inout_y -= is->cmpd.shown_page * PEDIA_DESC_LINES_PER_PAGE * PCX_Image_get_text_line_height (canvas); + return true; + } else + return false; + } + return true; +} + +int __fastcall +patch_PCX_Image_do_draw_centered_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int width, unsigned str_len) +{ + if (do_next_line_for_pedia_desc (this, &y)) + return PCX_Image_do_draw_centered_text (this, __, str, x, y, width, str_len); + else + return 0; // Caller does not use return value +} + +int __fastcall +patch_PCX_Image_draw_text_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y, int str_len) +{ + if (do_next_line_for_pedia_desc (this, &y)) + return PCX_Image_draw_text (this, __, str, x, y, str_len); + else + return PCX_Image_draw_text (this, __, " ", x, y, 1); // Caller uses the return value here so draw an empty string isntead of doing nothing +} + +// Steam code is slightly different; this no-len version of draw_text gets called sometimes. It's the same as draw_text instead it computes the string +// length itself instead of taking it in as a parameter. +int __fastcall +patch_PCX_Image_draw_text_no_len_in_wrap_func (PCX_Image * this, int edx, char * str, int x, int y) +{ + return patch_PCX_Image_draw_text_in_wrap_func (this, __, str, x, y, strlen (str)); +} + +void +draw_civilopedia_article (void (__fastcall * base) (Civilopedia_Article *), Civilopedia_Article * article) +{ + // If the article changed then clear things from the old one + if (is->cmpd.article != article) { + is->cmpd.last_page = 0; + is->cmpd.shown_page = 0; + is->cmpd.article = article; + } + + is->cmpd.line_count = 0; + is->cmpd.drawing_lines = article->show_description; + + base (article); + + is->cmpd.drawing_lines = false; +} + +void __fastcall +patch_Civilopedia_Article_m01_Draw_GCON_or_RACE (Civilopedia_Article * this) +{ + draw_civilopedia_article (Civilopedia_Article_m01_Draw_GCON_or_RACE, this); +} + +void +print_pedia_unit_stats (PCX_Image * canvas, int x, char ** entries, int entry_count) +{ + // Same forumula as the base game. Shifts entries upward if 4 or more. + int y = (entry_count > 3) ? 4 * (3 * entry_count - 9) : 0; + y = 449 - y; + + for (int n = 0; n < entry_count; n++) + y = PCX_Image_draw_and_wrap_text (canvas, __, entries[n], x, y, 150); +} + +void __fastcall +patch_Civilopedia_Article_m01_Draw_UNIT (Civilopedia_Article * this) +{ + // Make sure list of second column stat strings is clear before drawing + char ** entries = is->pedia_unit_stats_second_column_strs; + int capacity = ARRAY_LEN (is->pedia_unit_stats_second_column_strs); + if (is->current_config.expand_civilopedia_unit_stats) + for (int n = 0; n < capacity; n++) { + free (entries[n]); + entries[n] = NULL; + } + + draw_civilopedia_article (Civilopedia_Article_m01_Draw_UNIT, this); + + bool drew_stats = this->show_description == false || this->more_text_line_count == 0; + if (is->current_config.expand_civilopedia_unit_stats && drew_stats) { + // By this point entries have been filled in for the second column of unit stats (see ...draw_pedia_unit_stats_2nd_column), which has + // not actually been drawn. + int entry_count = 0; + for (int n = 0; n < capacity; n++) + if (entries[n] != NULL) + entry_count++; + + char s[100] = {0}; + + // Add entry for op range if aircraft. The original game shows movement instead of op range in the first column but we patch that to + // show movement always. + if (entry_count < capacity && this->unit_type->Unit_Class == UTC_Air) { + // Reserve spot at entries[0] to prepend new item + for (int n = capacity - 1; n > 0; n--) + entries[n] = entries[n-1]; + entry_count++; + + snprintf (s, (sizeof s) - 1, "%s: %d", (*p_labels)[LBL_OPERATIONAL_RANGE], this->unit_type->OperationalRange); + entries[0] = strdup (s); + } + + // Add bombard range if tactical nuke with bombard strength == 0 because the base game won't display it + if (entry_count < capacity && + this->unit_type->Unit_Class == UTC_Land && + this->unit_type->Bombard_Strength == 0 && + UnitType_has_ability (this->unit_type, __, UTA_Nuclear_Weapon) && + UnitType_has_ability (this->unit_type, __, UTA_Tacticle_Missile)) { + snprintf (s, (sizeof s) - 1, "%s: %d", (*p_labels)[LBL_BOMBARD_RANGE], this->unit_type->Bombard_Range); + entries[entry_count++] = strdup (s); + } + + // Add HP Bonus + if (entry_count < capacity && this->unit_type->Hit_Point_Bonus != 0) { + snprintf (s, (sizeof s) - 1, "%s: %d", is->c3x_labels[CL_HP_BONUS], this->unit_type->Hit_Point_Bonus); + entries[entry_count++] = strdup (s); + } + + // Add worker strength + int rounded_worker_strength = ((int)(this->unit_type->WorkerStrength * 10000.0f) + 50) / 100; + if (entry_count < capacity && rounded_worker_strength != 0) { + snprintf (s, (sizeof s) - 1, "%s: %d%%", is->c3x_labels[CL_WORKER_STRENGTH], rounded_worker_strength); + entries[entry_count++] = strdup (s); + } + + if (entry_count <= 6) + print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 213, entries, entry_count); + else { // If more than 6 entries, split some off into a third column + int third_count = entry_count / 2, + second_count = entry_count - third_count; + print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 198, entries, second_count); + print_pedia_unit_stats (&p_civilopedia_form->Base.Data.Canvas, 355, &entries[second_count], third_count); + } + } +} + +int __fastcall +patch_PCX_Image_draw_pedia_unit_stats_2nd_column (PCX_Image * this, int edx, char * str, int x, int y, int width) +{ + if (is->current_config.expand_civilopedia_unit_stats) + for (int n = 0; n < ARRAY_LEN (is->pedia_unit_stats_second_column_strs); n++) + if (is->pedia_unit_stats_second_column_strs[n] == NULL) { + is->pedia_unit_stats_second_column_strs[n] = strdup (str); // Record what would have been drawn here + str = " "; // Draw empty string. Can't skip draw call entirely b/c we need the return value + break; + } + + return PCX_Image_draw_and_wrap_text (this, __, str, x, y, width); +} + +void __fastcall +patch_Civilopedia_Form_m53_On_Control_Click (Civilopedia_Form * this, int edx, CivilopediaControlID control_id) +{ + Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; + + // "Effects" button leaves description mode, returns to showing effects + if ((control_id == PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID) && (current_article != NULL)) { + current_article->show_description = false; + is->cmpd.shown_page = 0; + play_sound_effect (26); // 26 = SE_SELECT + p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); + + // "Previous" button shows the previous page of a multi-page description or switches to effects mode if on the first page + } else if (control_id == PEDIA_MULTIPAGE_PREV_BUTTON_ID) { + if (is->cmpd.shown_page > 0) + is->cmpd.shown_page -= 1; + else + current_article->show_description = false; + play_sound_effect (26); + p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); + + } else if ((control_id == CCID_DESCRIPTION_BTN) && // if description/more/prev button was clicked AND + (current_article != NULL) && current_article->show_description && // currently showing a description of an article AND + (is->cmpd.last_page > 0)) { // this is a multi-page description + + // Show the next page of the multi-page description unless it's a two-page description and we're on the second page, in which case go + // back to the first. + if ((is->cmpd.last_page == 1) && (is->cmpd.shown_page == 1)) + is->cmpd.shown_page = 0; + else + is->cmpd.shown_page = not_above (is->cmpd.last_page, is->cmpd.shown_page + 1); + play_sound_effect (26); + p_civilopedia_form->Base.vtable->m73_call_m22_Draw ((Base_Form *)p_civilopedia_form); + + } else + Civilopedia_Form_m53_On_Control_Click (this, __, control_id); +} + +void __fastcall +patch_Civilopedia_Form_m22_Draw (Civilopedia_Form * this) +{ + // Make sure the new buttons are not visible and the multipage variables are cleared when we exit description mode + if ((this->Current_Article_ID < 0) || ! this->Articles[this->Current_Article_ID]->show_description) { + is->cmpd.shown_page = is->cmpd.last_page = 0; + if (is->cmpd.effects_btn != NULL) + is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); + if (is->cmpd.previous_btn != NULL) + is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); + } + + Civilopedia_Form_m22_Draw (this); +} + +int __fastcall +patch_Button_initialize_civilopedia_description (Button * this, int edx, char * text, int control_id, int x, int y, int width, int height, Base_Form * parent, int param_8) +{ + Civilopedia_Article * current_article = (p_civilopedia_form->Current_Article_ID >= 0) ? p_civilopedia_form->Articles[p_civilopedia_form->Current_Article_ID] : NULL; + if (current_article == NULL) + return Button_initialize (this, __, text, control_id, x, y, width, height, parent, param_8); + + // Set button visibility for multi-page descriptions if we're showing such a thing right now + bool show_desc_btn = true, show_effects_btn = false, show_previous_btn = false; + char * desc_btn_text = text; + if (current_article->show_description && (is->cmpd.last_page > 0)) { + + // Tribe articles act like one long descripton. + if ((current_article->article_kind == CAK_TRIBE) || (current_article->article_kind == CAK_GAME_CONCEPT)) { + + // Show the more button as long as we're not on the last page. Show the previous always since we're in description mode. + show_previous_btn = true; + desc_btn_text = (*p_labels)[LBL_MORE]; + if (is->cmpd.shown_page >= is->cmpd.last_page) + show_desc_btn = false; + + // Unit articles have separate description/effects modes. + } else if (current_article->article_kind == CAK_UNIT) { + + // For a two-page description, show the effects button and the description button which will act as a next/previous button + if (is->cmpd.last_page == 1) { + show_effects_btn = true; + desc_btn_text = is->cmpd.shown_page == 0 ? (*p_labels)[LBL_MORE] : (*p_labels)[LBL_PREVIOUS]; + + // For a three or more page description, show the effects button, and show the description button only if we're not on the + // last page (b/c it's the next button), and show the previous button only if we're not on the first page. If the desc button + // is visible, make it say "More". + } else { + show_effects_btn = true; + if (is->cmpd.shown_page >= is->cmpd.last_page) + show_desc_btn = false; + else + desc_btn_text = (*p_labels)[LBL_MORE]; + show_previous_btn = is->cmpd.shown_page > 0; + } + } + } + + int tr = Button_initialize (this, __, desc_btn_text, control_id, x, y, width, height, parent, param_8); + + if (! show_desc_btn) + this->vtable->m02_Show_Disabled ((Base_Form *)this); + + if (is->cmpd.effects_btn != NULL) { + if (show_effects_btn) + is->cmpd.effects_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.effects_btn, __, 0); + else + is->cmpd.effects_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.effects_btn); + } + + if (is->cmpd.previous_btn != NULL) { + if (show_previous_btn) + is->cmpd.previous_btn->vtable->m01_Show_Enabled ((Base_Form *)is->cmpd.previous_btn, __, 0); + else + is->cmpd.previous_btn->vtable->m02_Show_Disabled ((Base_Form *)is->cmpd.previous_btn); + } + + return tr; +} + +int __fastcall +patch_Civilopedia_Form_m68_Show_Dialog (Civilopedia_Form * this, int edx, int param_1, void * param_2, void * param_3) +{ + memset (&is->cmpd, 0, sizeof is->cmpd); + + Button * bs[] = {malloc (sizeof Button), malloc (sizeof Button)}; + for (int n = 0; n < ARRAY_LEN (bs); n++) { + if (bs[n] == NULL) + continue; + Button_construct (bs[n]); + + int desc_btn_x = 535, desc_btn_y = 222, desc_btn_height = 17; + + Button_initialize (bs[n], __, + n == 0 ? (*p_labels)[LBL_EFFECTS] : (*p_labels)[LBL_PREVIOUS], + n == 0 ? PEDIA_MULTIPAGE_EFFECTS_BUTTON_ID : PEDIA_MULTIPAGE_PREV_BUTTON_ID, // control ID + desc_btn_x, // location x + desc_btn_y + (n == 0 ? -2 : 2) * desc_btn_height, // location y + MOD_INFO_BUTTON_WIDTH, MOD_INFO_BUTTON_HEIGHT, // width, height + (Base_Form *)this, // parent + 0); // ? + + for (int k = 0; k < 3; k++) + bs[n]->Images[k] = &this->Description_Btn_Images[k]; + + // Do now draw the button until needed + bs[n]->vtable->m02_Show_Disabled ((Base_Form *)bs[n]); + } + is->cmpd.effects_btn = bs[0]; + is->cmpd.previous_btn = bs[1]; + + int tr = Civilopedia_Form_m68_Show_Dialog (this, __, param_1, param_2, param_3); + + for (int n = 0; n < ARRAY_LEN (bs); n++) + if (bs[n] != NULL) { + bs[n]->vtable->destruct ((Base_Form *)bs[n], __, 0); + free (bs[n]); + } + is->cmpd.effects_btn = is->cmpd.previous_btn = NULL; + + return tr; +} + +void +init_district_images () +{ + if (is_online_game () || is->dc_img_state != IS_UNINITED) + return; + + char art_dir[200]; + char temp_path[2*MAX_PATH]; + + is->dc_img_state = IS_INIT_FAILED; + + PCX_Image pcx; + PCX_Image_construct (&pcx); + + // For each district type + for (int dc = 0; dc < is->district_count; dc++) { + struct district_config const * cfg = &is->district_configs[dc]; + int variant_count = cfg->img_path_count; + if (variant_count <= 0) + continue; + + int era_count = cfg->vary_img_by_era ? 4 : 1; + int column_count = cfg->img_column_count; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + + // For each cultural variant + for (int variant_i = 0; variant_i < variant_count; variant_i++) { + if (cfg->img_paths[variant_i] == NULL) + continue; + + // Read PCX file + snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", cfg->img_paths[variant_i]); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + + if (pcx.JGL.Image == NULL) { + + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load district images from %s", temp_path); + pop_up_in_game_error (ss); + + (*p_OutputDebugStringA) ("[C3X] Failed to load districts sprite sheet.\n"); + for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) + for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) + for (int era_i = 0; era_i < 4; era_i++) { + for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { + Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + } + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + // For each era + for (int era_i = 0; era_i < era_count; era_i++) { + + // For each column in the image (variations on the district image for that era) + for (int col_i = 0; col_i < column_count; col_i++) { + Sprite_construct (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i]); + + int x = sprite_width * col_i, + y = sprite_height * era_i; + Sprite_slice_pcx (&is->district_img_sets[dc].imgs[variant_i][era_i][col_i], __, &pcx, x, y, sprite_width, sprite_height, 1, 1); + } + } + + pcx.vtable->clear_JGL (&pcx); + } + } + // Load abandoned district images (land + maritime) + get_mod_art_path ("Districts/1200/Abandoned.pcx", temp_path, sizeof temp_path); + PCX_Image_read_file (&pcx, __, temp_path, NULL, 0, 0x100, 2); + + if (pcx.JGL.Image == NULL) { + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load abandoned district images from %s", temp_path); + pop_up_in_game_error (ss); + for (int dc2 = 0; dc2 < COUNT_DISTRICT_TYPES; dc2++) + for (int variant_i2 = 0; variant_i2 < ARRAY_LEN (is->district_img_sets[dc2].imgs); variant_i2++) + for (int era_i = 0; era_i < 4; era_i++) { + for (int col = 0; col < ARRAY_LEN (is->district_img_sets[dc2].imgs[variant_i2][era_i]); col++) { + Sprite * sprite = &is->district_img_sets[dc2].imgs[variant_i2][era_i][col]; + if (sprite->vtable != NULL) + sprite->vtable->destruct (sprite, __, 0); + } + } + pcx.vtable->destruct (&pcx, __, 0); + return; + } + + Sprite_construct (&is->abandoned_district_img); + Sprite_slice_pcx (&is->abandoned_district_img, __, &pcx, 0, 0, 128, 64, 1, 1); + + Sprite_construct (&is->abandoned_maritime_district_img); + Sprite_slice_pcx (&is->abandoned_maritime_district_img, __, &pcx, 128, 0, 128, 64, 1, 1); + pcx.vtable->clear_JGL (&pcx); + + // Load wonder district images (dynamically per wonder) + if (is->current_config.enable_wonder_districts) { + char const * last_img_path = NULL; + PCX_Image wpcx; + PCX_Image_construct (&wpcx); + bool pcx_loaded = false; + + for (int wi = 0; wi < is->wonder_district_count; wi++) { + struct wonder_district_config * cfg = &is->wonder_district_configs[wi]; + char const * img_path = cfg->img_path; + if (img_path == NULL) + img_path = "Wonders.pcx"; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + + // Load new image file if different from previous + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + + snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + PCX_Image_read_file (&wpcx, __, temp_path, NULL, 0, 0x100, 2); + + if (wpcx.JGL.Image == NULL) { + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load wonder district images from %s", temp_path); + pop_up_in_game_error (ss); + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + struct wonder_district_image_set * set = &is->wonder_district_img_sets[wi]; + + Sprite_construct (&set->img); + int x = sprite_width * cfg->img_column; + int y = sprite_height * cfg->img_row; + Sprite_slice_pcx (&set->img, __, &wpcx, x, y, sprite_width, sprite_height, 1, 1); + + Sprite_construct (&set->construct_img); + int cx = sprite_width * cfg->img_construct_column; + int cy = sprite_height * cfg->img_construct_row; + Sprite_slice_pcx (&set->construct_img, __, &wpcx, cx, cy, sprite_width, sprite_height, 1, 1); + + if (cfg->enable_img_alt_dir) { + Sprite_construct (&set->alt_dir_img); + int ax = sprite_width * cfg->img_alt_dir_column; + int ay = sprite_height * cfg->img_alt_dir_row; + Sprite_slice_pcx (&set->alt_dir_img, __, &wpcx, ax, ay, sprite_width, sprite_height, 1, 1); + + Sprite_construct (&set->alt_dir_construct_img); + int acx = sprite_width * cfg->img_alt_dir_construct_column; + int acy = sprite_height * cfg->img_alt_dir_construct_row; + Sprite_slice_pcx (&set->alt_dir_construct_img, __, &wpcx, acx, acy, sprite_width, sprite_height, 1, 1); + } + } + + if (pcx_loaded) + wpcx.vtable->clear_JGL (&wpcx); + wpcx.vtable->destruct (&wpcx, __, 0); + } + + if (is->current_config.enable_natural_wonders && (is->natural_wonder_count > 0)) { + char const * last_img_path = NULL; + PCX_Image nwpcx; + PCX_Image_construct (&nwpcx); + bool pcx_loaded = false; + + for (int ni = 0; ni < is->natural_wonder_count; ni++) { + struct natural_wonder_district_config * cfg = &is->natural_wonder_configs[ni]; + if (cfg->name == NULL) + continue; + + char const * img_path = cfg->img_path; + if ((last_img_path == NULL) || (strcmp (img_path, last_img_path) != 0)) { + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + + snprintf (art_dir, sizeof art_dir, "Districts/1200/%s", img_path); + get_mod_art_path (art_dir, temp_path, sizeof temp_path); + PCX_Image_read_file (&nwpcx, __, temp_path, NULL, 0, 0x100, 2); + + if (nwpcx.JGL.Image == NULL) { + char ss[200]; + snprintf (ss, sizeof ss, "init_district_images: failed to load natural wonder images from %s", temp_path); + pop_up_in_game_error (ss); + pcx_loaded = false; + continue; + } + + pcx_loaded = true; + last_img_path = img_path; + } + + if (! pcx_loaded) + continue; + + Sprite_construct (&is->natural_wonder_img_sets[ni].img); + int x = 128 * cfg->img_column; + int y = 88 * cfg->img_row; + Sprite_slice_pcx (&is->natural_wonder_img_sets[ni].img, __, &nwpcx, x, y, 128, 88, 1, 1); + } + + if (pcx_loaded) + nwpcx.vtable->clear_JGL (&nwpcx); + nwpcx.vtable->destruct (&nwpcx, __, 0); + } + + is->dc_img_state = IS_OK; + pcx.vtable->destruct (&pcx, __, 0); +} + +bool +tile_coords_has_city_with_building_in_district_radius (int tile_x, int tile_y, int i_improv) +{ + Tile * center = tile_at (tile_x, tile_y); + + if ((center == NULL) || (center == p_null_tile)) return false; + int owner_id = center->Territory_OwnerID; + if (owner_id <= 0) return false; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + if (has_active_building (wai.city, i_improv)) + return true; + } + + return false; +} + +bool +wonder_requires_river (struct wonder_district_config const * cfg) +{ + unsigned int build_mask = wonder_buildable_square_type_mask (cfg); + if (build_mask == 0) + build_mask = district_default_buildable_mask (); + if ((build_mask & square_type_mask_bit (SQ_RIVER)) != 0) + return true; + if (cfg->buildable_on_rivers) + return true; + return false; +} + +Tile * +get_tile_sprite_indices (int tile_x, int tile_y, int * out_sheet_index, int * out_sprite_index) +{ + wrap_tile_coords (&p_bic_data->Map, &tile_x, &tile_y); + Tile * tile = tile_at (tile_x, tile_y); + + if (tile != NULL && tile != p_null_tile) { + *out_sheet_index = (tile->SquareParts >> 8) & 0xFF; + *out_sprite_index = tile->SquareParts & 0xFF; + } else { + *out_sheet_index = -1; + *out_sprite_index = -1; + } + + return tile; +} + +void +align_district_with_river (Tile * tile, int * out_pixel_x, int * out_pixel_y, enum direction * out_dir) +{ + if ((tile == NULL) || (tile == p_null_tile)) + return; + + enum direction dir = DIR_ZERO; + if (! get_primary_river_direction (tile, &dir)) + return; + + int dx, dy; + int offset = 36; + direction_to_offset (dir, &dx, &dy); + + dy = 0; + switch (dir) { + case DIR_N: dy = -offset; break; + case DIR_NE: dy = -offset/2; break; + case DIR_E: dy = 0; break; + case DIR_SE: dy = offset/2; break; + case DIR_S: dy = offset; break; + case DIR_SW: dy = offset/2; break; + case DIR_W: dy = 0; break; + case DIR_NW: dy = -offset/2; break; + default: break; + } + + if (out_pixel_x != NULL) + *out_pixel_x += dx; + if (out_pixel_y != NULL) + *out_pixel_y += dy; + if (out_dir != NULL) + *out_dir = dir; +} + +void +align_variant_and_pixel_offsets_with_coastline (Tile * tile, int * out_variant, int * out_pixel_x, int * out_pixel_y) +{ + if ((tile == NULL) || (tile == p_null_tile) || (out_variant == NULL)) + return; + + int owner_id = tile->Territory_OwnerID; + if (owner_id <= 0) + return; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return; + + int tile_x = inst->tile_x; + int tile_y = inst->tile_y; + Map * map = &p_bic_data->Map; + + City * closest_city = NULL; + int closest_dx = 0, closest_dy = 0; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + City * city = wai.city; + int ndx = city->Body.X - tile_x; + int ndy = city->Body.Y - tile_y; + + if (map->Flags & 1) { + int half_width = map->Width / 2; + if (ndx > half_width) + ndx -= map->Width; + else if (ndx < -half_width) + ndx += map->Width; + } + if (map->Flags & 2) { + int half_height = map->Height / 2; + if (ndy > half_height) + ndy -= map->Height; + else if (ndy < -half_height) + ndy += map->Height; + } + + closest_city = city; + closest_dx = ndx; + closest_dy = ndy; + break; + } + + if (closest_city == NULL) + return; + + bool city_is_directly_above_port = (closest_dx == 0) && (closest_dy == -2); + bool city_is_directly_below_port = (closest_dx == 0) && (closest_dy == 2); + bool city_is_directly_west_of_port = (closest_dx < 0) && (closest_dy == 0); + bool city_is_directly_east_of_port = (closest_dx > 0) && (closest_dy == 0); + bool city_is_directly_northeast_of_port = (closest_dx == 1) && (closest_dy == -1); + bool city_is_directly_southeast_of_port = (closest_dx == 1) && (closest_dy == 1); + bool city_is_directly_southwest_of_port = (closest_dx == -1) && (closest_dy == 1); + bool city_is_directly_northwest_of_port = (closest_dx == -1) && (closest_dy == -1); + + // Variant indices; can't use direction enum as values are slightly different + int NONE = -1; + int NW = 0; + int NE = 1; + int SE = 2; + int SW = 3; + *out_variant = NONE; + + enum direction anchor = NONE; + bool direct_diagonal = false; + + // Direct diagonals + if (city_is_directly_northeast_of_port) { *out_variant = SW; anchor = DIR_NE; direct_diagonal = true; } + else if (city_is_directly_southeast_of_port) { *out_variant = NW; anchor = DIR_SE; direct_diagonal = true; } + else if (city_is_directly_southwest_of_port) { *out_variant = NE; anchor = DIR_SW; direct_diagonal = true; } + else if (city_is_directly_northwest_of_port) { *out_variant = SE; anchor = DIR_NW; direct_diagonal = true; } + + // City either in a direct cardinal direction or not adjacent, check relative directions + else { + bool city_is_west_of_port = (closest_dx < 0); + bool city_is_east_of_port = (closest_dx > 0); + bool city_is_north_of_port = (closest_dy < 0); + bool city_is_south_of_port = (closest_dy > 0); + bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, true); + bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, true); + bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); + bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); + bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); + bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, true); + bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, true); + bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, true); + + if (city_is_directly_above_port) { + if (northwest_tile_is_land && ! tile_is_land (owner_id, tile_x + 1, tile_y + 1, true)) { + *out_variant = SE; anchor = DIR_NW; + } else if (northeast_tile_is_land && ! tile_is_land (owner_id, tile_x - 1, tile_y + 1, true)) { + *out_variant = SW; anchor = DIR_NE; + } else { + *out_variant = SW; anchor = DIR_NE; + *out_pixel_x -= 4; *out_pixel_y -= 4; + } + } else if (city_is_directly_below_port) { + if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else { + *out_variant = NE; anchor = DIR_SW; + *out_pixel_x += 4; *out_pixel_y += 4; + } + } else if (city_is_directly_west_of_port) { + if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else { + *out_variant = SE; anchor = DIR_NW; + *out_pixel_x -= 30; *out_pixel_y += 24; + } + } else if (city_is_directly_east_of_port) { + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else { + *out_variant = SW; anchor = DIR_NE; + *out_pixel_x += 30; *out_pixel_y -= 24; + } + } else if (city_is_north_of_port && city_is_west_of_port) { + if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + } else if (city_is_north_of_port && city_is_east_of_port) { + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + } else if (city_is_south_of_port && city_is_east_of_port) { + if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + } else if (city_is_south_of_port && city_is_west_of_port) { + if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + } + + // No ideal direction, pick based on any owner land tiles around port + if (*out_variant == NONE) { + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } + else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } + else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } + else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } + } + + // Same civ doesn't own any adjacent land tiles, pick based on *any* land tiles + if (*out_variant == NONE) { + bool northwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); + bool north_tile_is_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); + bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); + bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); + bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); + bool south_tile_is_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); + bool southwest_tile_is_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); + bool west_tile_is_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); + if (northeast_tile_is_land) { *out_variant = SW; anchor = DIR_NE; } + else if (southeast_tile_is_land) { *out_variant = NW; anchor = DIR_SE; } + else if (southwest_tile_is_land) { *out_variant = NE; anchor = DIR_SW; } + else if (northwest_tile_is_land) { *out_variant = SE; anchor = DIR_NW; } + else if (north_tile_is_land) { *out_variant = SW; anchor = DIR_N; } + else if (east_tile_is_land) { *out_variant = SW; anchor = DIR_E; } + else if (south_tile_is_land) { *out_variant = NE; anchor = DIR_S; } + else if (west_tile_is_land) { *out_variant = SE; anchor = DIR_W; } + else { *out_variant = SW; anchor = DIR_NE; } // Somehow no land tiles at all? Default to NE + } + } + + Tile * anchor_tile; + int anchor_sheet_index, anchor_sprite_index; + switch (anchor) { + case DIR_N: anchor_tile = get_tile_sprite_indices (tile_x, tile_y - 2, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_NE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_E: anchor_tile = get_tile_sprite_indices (tile_x + 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_SE: anchor_tile = get_tile_sprite_indices (tile_x + 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_S: anchor_tile = get_tile_sprite_indices (tile_x, tile_y + 2, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_SW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y + 1, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_W: anchor_tile = get_tile_sprite_indices (tile_x - 2, tile_y, &anchor_sheet_index, &anchor_sprite_index); break; + case DIR_NW: anchor_tile = get_tile_sprite_indices (tile_x - 1, tile_y - 1, &anchor_sheet_index, &anchor_sprite_index); break; + default: anchor_sheet_index = -1; anchor_sprite_index = -1; break; + } + + bool anchor_is_hill = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Hills; + bool anchor_is_mountain = anchor_tile != NULL && anchor_tile->vtable->m50_Get_Square_BaseType (anchor_tile) == SQ_Mountains; + + // Determine general pixel offsets based on direction & anchor + if (*out_variant == SW && anchor == DIR_NE) { *out_pixel_x -= 0; *out_pixel_y += 6; } + else if (*out_variant == SE && anchor == DIR_NW) { *out_pixel_x -= 2; *out_pixel_y += 6; } + else if (*out_variant == NW && anchor == DIR_SE) { *out_pixel_x -= 0; *out_pixel_y -= 2; } + else if (*out_variant == SW && anchor == DIR_N) { *out_pixel_x -= 56; *out_pixel_y -= 26; } + else if (*out_variant == SW && anchor == DIR_E) { *out_pixel_x += 36; *out_pixel_y += 18; } + else if (*out_variant == NE && anchor == DIR_S) { *out_pixel_x += 70; *out_pixel_y += 30; } + else if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 14; } + + // Handle edge cases. Tedious, but looks quite a bit better so worth it + if (! (anchor_is_hill || anchor_is_mountain) && ! direct_diagonal) { + if (*out_variant == SE && anchor == DIR_W) { *out_pixel_x -= 20; *out_pixel_y += 20; } + + // Sheet 0 + if (anchor_sheet_index == 0) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 32; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 32; } + + if ((*out_variant == NE || *out_variant == NW) && anchor == DIR_S && anchor_sprite_index == 26) { *out_pixel_x -= 4; *out_pixel_y += 30; } + else if (*out_variant == NE && anchor == DIR_SW && anchor_sprite_index == 20) { *out_pixel_x -= 2; *out_pixel_y += 4; } + + if (*out_variant == SW && (anchor_sprite_index == 0 || anchor_sprite_index == 4 || anchor_sprite_index == 10 || anchor_sprite_index == 1)) { *out_pixel_x +=2; *out_pixel_y -= 8; } + else if (*out_variant == SW && anchor == DIR_N && (anchor_sprite_index == 6)) { *out_pixel_x -= 6; *out_pixel_y -= 8; } + else if (*out_variant == SE && anchor == DIR_W && (anchor_sprite_index == 18)) { *out_pixel_x += 6; *out_pixel_y += 4; } + else if (*out_variant == NE && anchor == DIR_SW && (anchor_sprite_index == 51)) { *out_pixel_x += 20; *out_pixel_y -= 20; } + else if (*out_variant == SW && anchor == DIR_NE && (anchor_sprite_index == 0)) { *out_pixel_x -= 4; *out_pixel_y += 4; } + else if (*out_variant == NW && anchor == DIR_SE && (anchor_sprite_index == 44)) { *out_pixel_x -= 8; *out_pixel_y -= 12; } + } + // Sheet 1 + else if (anchor_sheet_index == 1) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 10; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 10; } + + if (*out_variant == SW && (anchor_sprite_index == 7 || anchor_sprite_index == 17 || anchor_sprite_index == 16)) { *out_pixel_x +=10; *out_pixel_y -= 8; } + } + // Sheet 3 + else if (anchor_sheet_index == 2) { + if (*out_variant == SW && (anchor_sprite_index == 6)) { *out_pixel_x +=2; *out_pixel_y -= 8; } + } + // Sheet 3 + else if (anchor_sheet_index == 3) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 16; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 16; } + + if (*out_variant == SW && (anchor_sprite_index == 43 || anchor_sprite_index == 40)) { *out_pixel_x +=6; *out_pixel_y -= 12; } + else if (*out_variant == SW && (anchor_sprite_index == 35 || anchor_sprite_index == 39)) { *out_pixel_x +=6; *out_pixel_y -= 12; } + else if (*out_variant == SE && (anchor_sprite_index == 50)) { *out_pixel_x -=6; *out_pixel_y -= 12; } + else if (*out_variant == SE && (anchor_sprite_index == 26)) { *out_pixel_x += 50; *out_pixel_y -= 2; } + } + // Sheet 4 + else if (anchor_sheet_index == 4) { + if (*out_variant == SW && (anchor_sprite_index == 71)) { *out_pixel_x +=2; *out_pixel_y -= 8; } + } + // Sheet 5 + else if (anchor_sheet_index == 5) { + if (*out_variant == SW || *out_variant == NW) { *out_pixel_x += 18; } + else if (*out_variant == SE || *out_variant == NE) { *out_pixel_x -= 18; } + + if ((*out_variant == SW || *out_variant == SE) && anchor_sprite_index == 18) { *out_pixel_y -= 10; } + else if (*out_variant == SW && anchor_sprite_index == 73) { *out_pixel_x -=4; *out_pixel_y -= 10; } + else if (*out_variant == NW && anchor == DIR_SE && anchor_sprite_index == 42) { *out_pixel_y -= 8; } + else if ((*out_variant == NW || *out_variant == SW) && anchor_sprite_index == 6) { *out_pixel_x += 12; *out_pixel_y -= 6; } + else if ((*out_variant == SW) && anchor_sprite_index == 16) { *out_pixel_x -=8; *out_pixel_y -= 10; } + } + } + else if (direct_diagonal && *out_variant == SW && anchor == DIR_NE) { *out_pixel_x -=8; *out_pixel_y -= 8; } + else if (direct_diagonal && *out_variant == SE && anchor == DIR_NW) { *out_pixel_x -=8; *out_pixel_y -= 8; } + else if (direct_diagonal && *out_variant == NW && anchor == DIR_SE) { *out_pixel_x +=6; *out_pixel_y += 6; } + else if (direct_diagonal && *out_variant == NE && anchor == DIR_SW) { *out_pixel_x +=6; *out_pixel_y += 6; } +} + +bool +wonder_should_use_alternative_direction_image (int tile_x, int tile_y, int owner_id, struct wonder_district_config const * cfg) +{ + if (owner_id <= 0) + return false; + + // We only care about the nearest same-civ city in the work area around the tile. + // Assumes the base wonder art (img_row/column) faces west and the alt art faces east. + // To "face away" from the nearest city, we pick the alt art when that city lies to the east. + Tile * center = is->current_render_tile; + if ((center == NULL) || (center == p_null_tile)) + return false; + + // If on a river and the wonder allows river alignment, make sure we face the river instead + bool allow_river = wonder_requires_river (cfg); + if (allow_river) { + enum direction river_dir = DIR_ZERO; + if (get_primary_river_direction (center, &river_dir)) { + int dx, dy; + + if (direction_to_offset (river_dir, &dx, &dy)) { + // I'm not completely sure of the logic here, but this seems to match the vanilla behavior + // in terms of having the wonder face the general direction of the river flow + if (dx == 2) + return false; + + return dx > 0; + } + } + } + + // Else face away from the nearest same-civ city + Map * map = &p_bic_data->Map; + int best_dist = INT_MAX; + int best_dx = 0; + int city_dx = 0; + int city_dy = 0; + + FOR_CITIES_AROUND (wai, tile_x, tile_y) { + City * city = wai.city; + if ((city == NULL) || (city->Body.CivID != owner_id)) + continue; + + int dx = city->Body.X - tile_x; + int dy = city->Body.Y - tile_y; + + if (map->Flags & 1) { + int half_width = map->Width >> 1; + if (dx > half_width) + dx -= map->Width; + else if (dx < -half_width) + dx += map->Width; + } + if (map->Flags & 2) { + int half_height = map->Height >> 1; + if (dy > half_height) + dy -= map->Height; + else if (dy < -half_height) + dy += map->Height; + } + + int dist = int_abs (dx) + int_abs (dy); + // Pick the closest city; if tied, favor the one with a clearer east/west offset so we know which way to face. + if ((dist < best_dist) || + ((dist == best_dist) && ((int_abs (dx) < int_abs (best_dx)) || (best_dx == 0)))) { + best_dist = dist; + best_dx = dx; + city_dx = city->Body.X; + city_dy = city->Body.Y; + } + } + + bool city_is_directly_above_port = city_dx == tile_x && city_dy == tile_y - 2; + bool city_is_directly_below_port = city_dx == tile_x && city_dy == tile_y + 2; + + if (city_is_directly_above_port || city_is_directly_below_port) { + bool northeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, true); + bool east_tile_is_land = tile_is_land (owner_id, tile_x + 2, tile_y, true); + bool southeast_tile_is_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, true); + + if (northeast_tile_is_land || east_tile_is_land || southeast_tile_is_land) + return true; + } + + if ((best_dist == INT_MAX) || (best_dx == 0)) + return false; + + return best_dx > 0; +} + +void +draw_district_on_map_or_canvas(Sprite * sprite, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (is->tile_info_open) { + PCX_Image * canvas = (PCX_Image *)map_renderer; + patch_Sprite_draw (sprite, __, canvas, pixel_x, pixel_y, NULL); + return; + } + + patch_Sprite_draw_on_map (sprite, __, map_renderer, pixel_x, pixel_y, 1, 1, (p_bic_data->is_zoomed_out != false) + 1, 0); +} + +int +get_energy_grid_image_index (int tile_x, int tile_y) +{ + struct district_infos * info = &is->district_infos[ENERGY_GRID_DISTRICT_ID]; + for (int i = 0; i < info->dependent_building_count; i++) { + // Zero is "no building"; Buildings start from index one + int column_index = i + 1; + int building_id = info->dependent_building_ids[i]; + if (tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) + return column_index; + } + + return 0; +} + +int +get_bridge_image_index (Tile * tile, int tile_x, int tile_y) +{ + int SW_NE = 0; + int NW_SE = 1; + int N_S = 2; + int W_E = 3; + + if ((tile->vtable->m42_Get_Overlays (tile, __, 0) & TILE_FLAG_RAILROAD) != 0) { + SW_NE += 4; + NW_SE += 4; + N_S += 4; + W_E += 4; + } + + bool bridge_n = tile_has_district_at (tile_x, tile_y - 2, BRIDGE_DISTRICT_ID); + bool bridge_s = tile_has_district_at (tile_x, tile_y + 2, BRIDGE_DISTRICT_ID); + bool bridge_w = tile_has_district_at (tile_x - 2, tile_y, BRIDGE_DISTRICT_ID); + bool bridge_e = tile_has_district_at (tile_x + 2, tile_y, BRIDGE_DISTRICT_ID); + bool bridge_ne = tile_has_district_at (tile_x + 1, tile_y - 1, BRIDGE_DISTRICT_ID); + bool bridge_nw = tile_has_district_at (tile_x - 1, tile_y - 1, BRIDGE_DISTRICT_ID); + bool bridge_se = tile_has_district_at (tile_x + 1, tile_y + 1, BRIDGE_DISTRICT_ID); + bool bridge_sw = tile_has_district_at (tile_x - 1, tile_y + 1, BRIDGE_DISTRICT_ID); + + if (bridge_n || bridge_s || bridge_w || bridge_e || bridge_ne || bridge_nw || bridge_se || bridge_sw) { + int ns_count = (bridge_n ? 1 : 0) + (bridge_s ? 1 : 0); + int we_count = (bridge_w ? 1 : 0) + (bridge_e ? 1 : 0); + int swne_count = (bridge_sw ? 1 : 0) + (bridge_ne ? 1 : 0); + int nwse_count = (bridge_nw ? 1 : 0) + (bridge_se ? 1 : 0); + + if (swne_count == 2) return SW_NE; + if (nwse_count == 2) return NW_SE; + if (ns_count == 2) return N_S; + if (we_count == 2) return W_E; + + if (bridge_ne || bridge_sw) return SW_NE; + if (bridge_nw || bridge_se) return NW_SE; + if (bridge_n || bridge_s) return N_S; + if (bridge_w || bridge_e) return W_E; + } + + int owner_id = tile->Territory_OwnerID; + bool north_land = tile_is_land (owner_id, tile_x, tile_y - 2, false); + bool south_land = tile_is_land (owner_id, tile_x, tile_y + 2, false); + bool west_land = tile_is_land (owner_id, tile_x - 2, tile_y, false); + bool east_land = tile_is_land (owner_id, tile_x + 2, tile_y, false); + bool ne_land = tile_is_land (owner_id, tile_x + 1, tile_y - 1, false); + bool nw_land = tile_is_land (owner_id, tile_x - 1, tile_y - 1, false); + bool se_land = tile_is_land (owner_id, tile_x + 1, tile_y + 1, false); + bool sw_land = tile_is_land (owner_id, tile_x - 1, tile_y + 1, false); + + bool north_link = north_land || bridge_n; + bool south_link = south_land || bridge_s; + bool west_link = west_land || bridge_w; + bool east_link = east_land || bridge_e; + bool ne_link = ne_land || bridge_ne; + bool nw_link = nw_land || bridge_nw; + bool se_link = se_land || bridge_se; + bool sw_link = sw_land || bridge_sw; + + if (sw_link && ne_link) return SW_NE; + if (nw_link && se_link) return NW_SE; + if (north_link && south_link) return N_S; + if (west_link && east_link) return W_E; + + if (ne_link || sw_link) return SW_NE; + if (nw_link || se_link) return NW_SE; + if (north_link || south_link) return N_S; + if (west_link || east_link) return W_E; + + return SW_NE; +} + +void +get_bridge_directions (Tile * tile, int tile_x, int tile_y, int * out_dir1, int * out_dir2) +{ + int dir1 = -1; + int dir2 = -1; + int index = get_bridge_image_index (tile, tile_x, tile_y); + + switch (index) { + case 0: dir1 = DIR_SW; dir2 = DIR_NE; break; + case 1: dir1 = DIR_NW; dir2 = DIR_SE; break; + case 2: dir1 = DIR_N; dir2 = DIR_S; break; + case 3: dir1 = DIR_W; dir2 = DIR_E; break; + default: break; + } + + *out_dir1 = dir1; + *out_dir2 = dir2; +} + +void +get_canal_directions (Tile * tile, int tile_x, int tile_y, bool out_water_dirs[9], int * out_dir1, int * out_dir2) +{ + bool canal_at_n = tile_has_district_at (tile_x, tile_y - 2, CANAL_DISTRICT_ID); + bool canal_at_s = tile_has_district_at (tile_x, tile_y + 2, CANAL_DISTRICT_ID); + bool canal_at_w = tile_has_district_at (tile_x - 2, tile_y, CANAL_DISTRICT_ID); + bool canal_at_e = tile_has_district_at (tile_x + 2, tile_y, CANAL_DISTRICT_ID); + bool canal_at_ne = tile_has_district_at (tile_x + 1, tile_y - 1, CANAL_DISTRICT_ID); + bool canal_at_nw = tile_has_district_at (tile_x - 1, tile_y - 1, CANAL_DISTRICT_ID); + bool canal_at_se = tile_has_district_at (tile_x + 1, tile_y + 1, CANAL_DISTRICT_ID); + bool canal_at_sw = tile_has_district_at (tile_x - 1, tile_y + 1, CANAL_DISTRICT_ID); + bool water_n = tile_is_water (tile_x, tile_y - 2); + bool water_s = tile_is_water (tile_x, tile_y + 2); + bool water_w = tile_is_water (tile_x - 2, tile_y); + bool water_e = tile_is_water (tile_x + 2, tile_y); + bool water_ne = tile_is_water (tile_x + 1, tile_y - 1); + bool water_nw = tile_is_water (tile_x - 1, tile_y - 1); + bool water_se = tile_is_water (tile_x + 1, tile_y + 1); + bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); + bool canal_or_water_n = canal_at_n || water_n; + bool canal_or_water_s = canal_at_s || water_s; + bool canal_or_water_w = canal_at_w || water_w; + bool canal_or_water_e = canal_at_e || water_e; + bool canal_or_water_ne = canal_at_ne || water_ne; + bool canal_or_water_nw = canal_at_nw || water_nw; + bool canal_or_water_se = canal_at_se || water_se; + bool canal_or_water_sw = canal_at_sw || water_sw; + + bool canal_dirs[9] = { + false, canal_at_ne, canal_at_e, canal_at_se, + canal_at_s, canal_at_sw, canal_at_w, canal_at_nw, canal_at_n + }; + bool water_dirs[9] = { + false, water_ne, water_e, water_se, + water_s, water_sw, water_w, water_nw, water_n + }; + bool available_dirs[9] = { + false, canal_or_water_ne, canal_or_water_e, canal_or_water_se, + canal_or_water_s, canal_or_water_sw, canal_or_water_w, canal_or_water_nw, canal_or_water_n + }; + + // Avoid acute angles (adjacent directions) that look cramped. + int disallowed_pairs[][2] = { + { DIR_N, DIR_NE }, { DIR_NE, DIR_E }, { DIR_E, DIR_SE }, { DIR_SE, DIR_S }, + { DIR_S, DIR_SW }, { DIR_SW, DIR_W }, { DIR_W, DIR_NW }, { DIR_NW, DIR_N } + }; + int disallowed_pair_count = sizeof(disallowed_pairs) / sizeof(disallowed_pairs[0]); + int pref_dirs[8] = { DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_N, DIR_E, DIR_S, DIR_W }; + + int dir1 = -1; + int dir2 = -1; + + bool has_canal_dir = canal_dirs[DIR_N] || canal_dirs[DIR_NE] || canal_dirs[DIR_E] || canal_dirs[DIR_SE] || + canal_dirs[DIR_S] || canal_dirs[DIR_SW] || canal_dirs[DIR_W] || canal_dirs[DIR_NW]; + + if (has_canal_dir) { + for (int i = 0; i < 8 && dir1 == -1; i++) { + int d = pref_dirs[i]; + if (canal_dirs[d]) + dir1 = d; + } + } else { + for (int i = 0; i < 8 && dir1 == -1; i++) { + int d = pref_dirs[i]; + if (available_dirs[d]) + dir1 = d; + } + } + + if (dir1 >= 0) { + for (int pass = 0; pass < 2 && dir2 == -1; pass++) { + bool * dirs = (pass == 0) ? canal_dirs : available_dirs; + for (int i = 0; i < 8; i++) { + int d = pref_dirs[i]; + if (d == dir1 || ! dirs[d]) + continue; + bool pair_is_too_close = false; + for (int k = 0; k < disallowed_pair_count; k++) { + if ((dir1 == disallowed_pairs[k][0] && d == disallowed_pairs[k][1]) || + (dir1 == disallowed_pairs[k][1] && d == disallowed_pairs[k][0])) { + pair_is_too_close = true; + break; + } + } + if (pair_is_too_close) + continue; + dir2 = d; + break; + } + } + } + + int draw_dir1 = dir1; + int draw_dir2 = dir2; + if ((draw_dir1 >= 0) && (draw_dir2 >= 0)) { + int weight1 = 0; + int weight2 = 0; + + if (draw_dir1 == DIR_S) weight1 = 2; + else if ((draw_dir1 == DIR_SE) || (draw_dir1 == DIR_SW)) weight1 = 1; + else if ((draw_dir1 == DIR_NE) || (draw_dir1 == DIR_NW) || (draw_dir1 == DIR_N)) weight1 = -1; + + if (draw_dir2 == DIR_S) weight2 = 2; + else if ((draw_dir2 == DIR_SE) || (draw_dir2 == DIR_SW)) weight2 = 1; + else if ((draw_dir2 == DIR_NE) || (draw_dir2 == DIR_NW) || (draw_dir2 == DIR_N)) weight2 = -1; + + if (weight1 > weight2) { + int tmp = draw_dir1; + draw_dir1 = draw_dir2; + draw_dir2 = tmp; + } + } + + // Manual overrides - overall algorithm works pretty well, but handle corner cases + if (!has_canal_dir && water_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir1 = DIR_NE; draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && water_dirs[DIR_N] && water_dirs[DIR_NE]) { draw_dir1 = DIR_N; draw_dir2 = DIR_S; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_SE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_SE && water_dirs[DIR_NE] && water_dirs[DIR_N]) { draw_dir1 = DIR_N; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && water_dirs[DIR_S]) { draw_dir2 = DIR_S; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_NW && canal_dirs[DIR_NE] && water_dirs[DIR_SW]) { draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S && canal_dirs[DIR_NE] && water_dirs[DIR_S]) { draw_dir2 = DIR_SW; } + if (draw_dir1 == DIR_NW && draw_dir2 == DIR_NE && canal_dirs[DIR_NW] && water_dirs[DIR_SE]) { draw_dir2 = DIR_SE; } + if (draw_dir1 == DIR_NW && draw_dir2 == DIR_S && canal_dirs[DIR_NW] && water_dirs[DIR_S]) { draw_dir2 = DIR_SE; } + + *out_dir1 = draw_dir1; + *out_dir2 = draw_dir2; + for (int i = 0; i < 9; i++) + out_water_dirs[i] = water_dirs[i]; +} + +void +draw_canal_on_map_or_canvas(Sprite * sprite, int tile_x, int tile_y, int dir, bool water_dirs[9], Map_Renderer * map_renderer, int draw_x, int draw_y) +{ + int y_offset = 9; + int x_offset = y_offset * 2; + + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y); + + // In certain cases, add an additional draw if adjacent to water so that the canal appears to extend far enough + if (dir == DIR_N && water_dirs[DIR_N]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y - y_offset); + else if (dir == DIR_NE && water_dirs[DIR_NE]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y - y_offset); + else if (dir == DIR_E && water_dirs[DIR_E]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y); + else if (dir == DIR_SE && water_dirs[DIR_SE]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x + x_offset, draw_y + y_offset); + else if (dir == DIR_S && water_dirs[DIR_S]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x, draw_y + y_offset); + else if (dir == DIR_SW && water_dirs[DIR_SW]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y + y_offset); + else if (dir == DIR_W && water_dirs[DIR_W]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y); + else if (dir == DIR_NW && water_dirs[DIR_NW]) + draw_district_on_map_or_canvas(sprite, map_renderer, draw_x - x_offset, draw_y - y_offset); +} + +void +draw_canal_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int era) +{ + struct district_config const * cfg = &is->district_configs[CANAL_DISTRICT_ID]; + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + int offset_x = pixel_x + cfg->x_offset; + int offset_y = pixel_y + cfg->y_offset; + int dir1_draw_x = offset_x - ((sprite_width - 128) / 2); + int dir1_draw_y = offset_y - (sprite_height - 64); + int dir2_draw_x = dir1_draw_x; + int dir2_draw_y = dir1_draw_y; + + int draw_dir1 = -1; + int draw_dir2 = -1; + bool water_dirs[9] = { false, false, false, false, false, false, false, false, false }; + get_canal_directions (tile, tile_x, tile_y, water_dirs, &draw_dir1, &draw_dir2); + + // Set offsets based on directions for (literal) edge cases + if (draw_dir1 == DIR_NE && draw_dir2 == DIR_S) { dir1_draw_x += 7; dir1_draw_y -= 2; } + else if (draw_dir1 == DIR_N && draw_dir2 == DIR_W) { dir2_draw_x -= 12; } + else if (draw_dir1 == DIR_N && draw_dir2 == DIR_SE) { dir2_draw_x += 4; } + + if (draw_dir1 >= 0) { + Sprite * sprite1 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir1]; + draw_canal_on_map_or_canvas(sprite1, tile_x, tile_y, draw_dir1, water_dirs, map_renderer, dir1_draw_x, dir1_draw_y); + } + + if (draw_dir2 >= 0) { + Sprite * sprite2 = &is->district_img_sets[CANAL_DISTRICT_ID].imgs[0][era][draw_dir2]; + draw_canal_on_map_or_canvas(sprite2, tile_x, tile_y, draw_dir2, water_dirs, map_renderer, dir2_draw_x, dir2_draw_y); + } +} + +void +draw_great_wall_district (Tile * tile, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + bool wall_nw = tile_has_district_at (tile_x - 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); + bool wall_ne = tile_has_district_at (tile_x + 1, tile_y - 1, GREAT_WALL_DISTRICT_ID); + bool wall_se = tile_has_district_at (tile_x + 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); + bool wall_sw = tile_has_district_at (tile_x - 1, tile_y + 1, GREAT_WALL_DISTRICT_ID); + bool wall_s = tile_has_district_at (tile_x, tile_y + 2, GREAT_WALL_DISTRICT_ID); + bool wall_n = tile_has_district_at (tile_x, tile_y - 2, GREAT_WALL_DISTRICT_ID); + + bool water_ne = tile_is_water (tile_x - 1, tile_y - 1); + bool water_nw = tile_is_water (tile_x + 1, tile_y - 1); + bool water_w = tile_is_water (tile_x - 2, tile_y); + bool water_n = tile_is_water (tile_x, tile_y + 2); + bool water_sw = tile_is_water (tile_x - 1, tile_y + 1); + bool water_se = tile_is_water (tile_x + 1, tile_y + 1); + + Sprite * sprites = is->district_img_sets[GREAT_WALL_DISTRICT_ID].imgs[0][0]; + Sprite * base = &sprites[0]; + + // Rotate around clockwise NW -> SW to get the perspective right + if (wall_nw) draw_district_on_map_or_canvas(&sprites[DIR_NW], map_renderer, pixel_x, pixel_y); + if (wall_ne) draw_district_on_map_or_canvas(&sprites[DIR_NE], map_renderer, pixel_x, pixel_y); + + // Base pillar + draw_district_on_map_or_canvas(base, map_renderer, pixel_x, pixel_y); + + if (wall_sw) draw_district_on_map_or_canvas(&sprites[DIR_SW], map_renderer, pixel_x, pixel_y); + if (wall_se) draw_district_on_map_or_canvas(&sprites[DIR_SE], map_renderer, pixel_x, pixel_y); +} + +void +draw_district_generated_resource_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, + int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) +{ + int base_resource = Tile_get_resource_visible_to (tile, __, visible_to_civ_id); + int district_resource = -1; + + if (inst->state == DS_COMPLETED) { + int district_id = inst->district_id; + if ((district_id >= 0) && (district_id < is->district_count)) { + struct district_config * cfg = &is->district_configs[district_id]; + if (cfg->generated_resource_id >= 0) { + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_id >= 0) && ((visible_to_civ_id < 0) || (owner_id == visible_to_civ_id))) { + int res_id = cfg->generated_resource_id; + if (district_generates_resource_for_civ (tile, inst, cfg, owner_id)) + district_resource = res_id; + } + } + } + } + + if (district_resource < 0) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + int tile_width = p_bic_data->is_zoomed_out ? 64 : 128; + int offset = tile_width >> 2; + int left_x = pixel_x - (offset >> 1); + int right_x = pixel_x + (offset >> 1); + + int icon_id = p_bic_data->ResourceTypes[district_resource].IconID; + Sprite * sprite = NULL; + Map_Renderer * resource_renderer = is->tile_info_open ? &p_bic_data->Map.Renderer : map_renderer; + int resource_sprite_count = 0; + if ((resource_renderer != NULL) && (resource_renderer->Resources != NULL)) + // The renderer allocates Resources as a counted heap array: the int stored just before the + // first Sprite is the number of entries loaded from resources.pcx. + resource_sprite_count = ((int *)resource_renderer->Resources)[-1]; + if ((icon_id < 0) || (icon_id >= resource_sprite_count)) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + sprite = &resource_renderer->Resources[icon_id]; + if (sprite == NULL) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + if (base_resource >= 0) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, left_x, pixel_y); + } + + int tile_height = tile_width >> 1; + int sprite_width = sprite->Width; + int sprite_height = sprite->Height; + if (sprite_width <= 0) sprite_width = sprite->Width3; + if (sprite_height <= 0) sprite_height = sprite->Height3; + int center_x = (tile_width - sprite_width) >> 1; + int center_y = (tile_height - sprite_height) >> 1; + int draw_x = (base_resource >= 0) ? right_x : pixel_x; + draw_x += center_x; + int draw_y = pixel_y + center_y; + if (is->tile_info_open) { + PCX_Image * canvas = (PCX_Image *)map_renderer; + patch_Sprite_draw (sprite, __, canvas, draw_x, draw_y, NULL); + } else { + int draw_scale = (p_bic_data->is_zoomed_out != false) + 1; + patch_Sprite_draw_on_map (sprite, __, map_renderer, draw_x, draw_y, 1, 1, draw_scale, 0); + } +} + +int +count_completed_buildings_in_district_radius (int tile_x, int tile_y, int district_id) +{ + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos * district_info = &is->district_infos[district_id]; + int completed_count = 0; + for (int i = 0; i < district_info->dependent_building_count; i++) { + int building_id = district_info->dependent_building_ids[i]; + if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) + completed_count++; + } + return completed_count; +} + +void +draw_district_on_map_or_canvas_by_buildings (Sprite * base_sprite, Map_Renderer * map_renderer, int district_id, int variant, int era, int tile_x, int tile_y, int draw_x, int draw_y) +{ + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos * district_info = &is->district_infos[district_id]; + + draw_district_on_map_or_canvas(base_sprite, map_renderer, draw_x, draw_y); + + for (int i = 0; i < district_info->dependent_building_count; i++) { + // Zero is "base texture"; Actual building column art starts from index one + int column_index = i + 1; + int building_id = district_info->dependent_building_ids[i]; + if ((building_id >= 0) && tile_coords_has_city_with_building_in_district_radius (tile_x, tile_y, building_id)) { + Sprite * district_sprite = &is->district_img_sets[district_id].imgs[variant][era][column_index]; + draw_district_on_map_or_canvas(district_sprite, map_renderer, draw_x, draw_y); + } + } +} + +void +draw_district_on_tile (Map_Renderer * this, Tile * tile, struct district_instance * inst, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y, int visible_to_civ_id) +{ + int district_id = inst->district_id; + if (is->dc_img_state == IS_UNINITED) + init_district_images (); + + if (is->dc_img_state != IS_OK) + return; + + // Natural Wonder + if (district_id == NATURAL_WONDER_DISTRICT_ID) { + if (! is->current_config.enable_natural_wonders) + return; + + int natural_id = inst->natural_wonder_info.natural_wonder_id; + if ((natural_id >= 0) && (natural_id < is->natural_wonder_count)) { + Sprite * nsprite = &is->natural_wonder_img_sets[natural_id].img; + int y_offset = 88 - 64; // Height of wonder img minus height of tile + int draw_y = pixel_y - y_offset; + + draw_district_on_map_or_canvas(nsprite, map_renderer, pixel_x, draw_y); + } + return; + } + + // Districts + if (is->current_config.enable_districts) { + if (district_id < 0 || district_id >= is->district_count) return; + bool completed = district_is_complete (tile, district_id); + + if (! completed) + return; + + struct district_config const * cfg = &is->district_configs[district_id]; + struct district_infos * district_info = &is->district_infos[district_id]; + int territory_owner_id = tile->Territory_OwnerID; + int variant = 0; + int era = 0; + int culture = 0; + int buildings = 0; + int draw_pixel_x = pixel_x; + int draw_pixel_y = pixel_y; + enum direction river_dir = DIR_ZERO; + + // If in a territory, use owner's culture/era + if (territory_owner_id > 0) { + Leader * leader = &leaders[territory_owner_id]; + culture = p_bic_data->Races[leader->RaceID].CultureGroupID; + if (cfg->vary_img_by_culture) + variant = culture; + if (cfg->vary_img_by_era) + era = leader->Era; + if (cfg->align_to_coast) + align_variant_and_pixel_offsets_with_coastline (tile, &variant, &draw_pixel_x, &draw_pixel_y); + + // Else render abandoned if not a Wonder, Natural Wonder, Bridge, or Canal + } else if (district_id != WONDER_DISTRICT_ID && district_id != NATURAL_WONDER_DISTRICT_ID && district_id != BRIDGE_DISTRICT_ID && district_id != CANAL_DISTRICT_ID) { + Sprite * abandoned_sprite = &is->abandoned_district_img; + if (tile->vtable->m35_Check_Is_Water (tile) && is->abandoned_maritime_district_img.vtable != NULL) + abandoned_sprite = &is->abandoned_maritime_district_img; + if (abandoned_sprite->vtable != NULL) { + draw_district_on_map_or_canvas(abandoned_sprite, map_renderer, draw_pixel_x + cfg->x_offset, draw_pixel_y + cfg->y_offset); + } + return; + } + + // If out of a territory (and not abandoned) but builder is known, use builder's era & culture + if (territory_owner_id < 0 && inst->built_by_civ_id >= 0) { + Leader * builder = &leaders[inst->built_by_civ_id]; + culture = p_bic_data->Races[builder->RaceID].CultureGroupID; + if (cfg->vary_img_by_culture) + variant = culture; + if (cfg->vary_img_by_era) + era = builder->Era; + } + + int sprite_width = (cfg->custom_width > 0) ? cfg->custom_width : 128; + int sprite_height = (cfg->custom_height > 0) ? cfg->custom_height : 64; + int offset_x = draw_pixel_x + cfg->x_offset; + int offset_y = draw_pixel_y + cfg->y_offset; + int draw_x = offset_x - ((sprite_width - 128) / 2); + int draw_y = offset_y - (sprite_height - 64); + Sprite (*sprites)[MAX_DISTRICT_ERA_COUNT][MAX_DISTRICT_COLUMN_COUNT] = is->district_img_sets[district_id].imgs; + + // Render + switch (district_id) { + case WONDER_DISTRICT_ID: + { + if (! is->current_config.enable_wonder_districts) + return; + + struct wonder_district_info * info = get_wonder_district_info (tile); + if (info == NULL) + return; + + int construct_windex = -1; + Sprite * wsprite = NULL; + + struct wonder_district_config * wcfg = NULL; + struct wonder_district_image_set * set = NULL; + + // Completed + if (info->state == WDS_COMPLETED) { + int windex = info->wonder_index; + if ((windex < 0) || (windex >= is->wonder_district_count)) + return; + wcfg = &is->wonder_district_configs[windex]; + set = &is->wonder_district_img_sets[windex]; + // Under construction + } else if (wonder_district_tile_under_construction (tile, tile_x, tile_y, &construct_windex) && (construct_windex >= 0)) { + if (construct_windex >= is->wonder_district_count) + return; + wcfg = &is->wonder_district_configs[construct_windex]; + set = &is->wonder_district_img_sets[construct_windex]; + // Unused + } else { + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + + if (wonder_requires_river(wcfg)) + align_district_with_river (tile, &draw_pixel_x, &draw_pixel_y, &river_dir); + + int wonder_width = (wcfg->custom_width > 0) ? wcfg->custom_width : 128; + int wonder_height = (wcfg->custom_height > 0) ? wcfg->custom_height : 64; + int wonder_offset_x = draw_pixel_x + cfg->x_offset; + int wonder_offset_y = draw_pixel_y + cfg->y_offset; + int wonder_draw_x = wonder_offset_x - ((wonder_width - 128) / 2); + int wonder_draw_y = wonder_offset_y - (wonder_height - 64); + + bool use_alt_dir = wcfg->enable_img_alt_dir && wonder_should_use_alternative_direction_image (tile_x, tile_y, territory_owner_id, wcfg); + if (info->state == WDS_COMPLETED) + wsprite = (use_alt_dir && (set->alt_dir_img.vtable != NULL)) ? &set->alt_dir_img : &set->img; + else + wsprite = (use_alt_dir && (set->alt_dir_construct_img.vtable != NULL)) ? &set->alt_dir_construct_img : &set->construct_img; + + draw_district_on_map_or_canvas(wsprite, map_renderer, wonder_draw_x, wonder_draw_y); + return; + } + case NEIGHBORHOOD_DISTRICT_ID: + { + if (! is->current_config.enable_neighborhood_districts) + return; + + unsigned v = (unsigned)tile_x * 0x9E3779B1u + (unsigned)tile_y * 0x85EBCA6Bu; + v ^= v >> 16; + v *= 0x7FEB352Du; + v ^= v >> 15; + v *= 0x846CA68Bu; + v ^= v >> 16; + buildings = clamp(0, 3, (int)(v & 3u)); /* final 0..3 */ + variant = culture; + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + case DISTRIBUTION_HUB_DISTRICT_ID: + if (! is->current_config.enable_distribution_hub_districts) + return; + + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + case ENERGY_GRID_DISTRICT_ID: + { + if (! is->current_config.enable_energy_grid_districts) + return; + + buildings = get_energy_grid_image_index (tile_x, tile_y); + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + case BRIDGE_DISTRICT_ID: + { + if (! is->current_config.enable_bridge_districts) + return; + + buildings = get_bridge_image_index (tile, tile_x, tile_y); + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + case CANAL_DISTRICT_ID: + { + if (! is->current_config.enable_canal_districts) + return; + + draw_canal_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y, era); + return; + } + case GREAT_WALL_DISTRICT_ID: + { + if (! is->current_config.enable_great_wall_districts) + return; + + draw_great_wall_district (tile, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + default: + { + // Draw by counting number of completed buildings in radius + if (cfg->render_strategy == DRS_BY_COUNT) { + buildings = count_completed_buildings_in_district_radius (tile_x, tile_y, district_id); + draw_district_on_map_or_canvas(&sprites[variant][era][buildings], map_renderer, draw_x, draw_y); + return; + } + // Draw by checking each building individually and layering images + else if (cfg->render_strategy == DRS_BY_BUILDING) { + Sprite * base_sprite = &is->district_img_sets[district_id].imgs[variant][era][0]; + draw_district_on_map_or_canvas_by_buildings(base_sprite, map_renderer, district_id, variant, era, tile_x, tile_y, draw_x, draw_y); + return; + } + } + } + } + + Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); +} + +void __fastcall +patch_Map_Renderer_m12_Draw_Tile_Buildings(Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { + Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + Tile * tile = is->current_render_tile; + if (is->tile_info_open) + tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if ((tile == NULL) || (tile == p_null_tile)) + return; + + struct district_instance * inst = is->current_render_tile_district; + if (is->tile_info_open) + inst = get_district_instance (tile); + if (inst == NULL) { + Map_Renderer_m12_Draw_Tile_Buildings(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + // Draw resources first if needed + if (is->district_configs[inst->district_id].draw_over_resources) + draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); + + draw_district_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); +} + +void __fastcall +patch_Map_Renderer_m09_Draw_Tile_Resources (Map_Renderer * this, int edx, int visible_to_civ_id, int tile_x, int tile_y, Map_Renderer * map_renderer, int pixel_x, int pixel_y) +{ + if (! is->current_config.enable_districts) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + Tile * tile = is->current_render_tile; + if (is->tile_info_open) + tile = tile_at (is->viewing_tile_info_x, is->viewing_tile_info_y); + if ((tile == NULL) || (tile == p_null_tile)) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + struct district_instance * inst = is->current_render_tile_district; + if (is->tile_info_open) + inst = get_district_instance (tile); + if (inst == NULL) { + Map_Renderer_m09_Draw_Tile_Resources(this, __, visible_to_civ_id, tile_x, tile_y, map_renderer, pixel_x, pixel_y); + return; + } + + // Resources that should be drawn below district are already drawn, skip in that case + if (is->district_configs[inst->district_id].draw_over_resources) + return; + + draw_district_generated_resource_on_tile (this, tile, inst, tile_x, tile_y, map_renderer, pixel_x, pixel_y, visible_to_civ_id); +} + +void __fastcall +patch_Map_Renderer_m11_Draw_Tile_Irrigation (Map_Renderer *this, int edx, int visible_to_civ, int tile_x, int tile_y, int param_4, int param_5, int param_6) +{ + if (! is->current_config.enable_districts) { + Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); + return; + } + + struct district_instance * inst = is->current_render_tile_district; + if (inst == NULL) { + Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); + return; + } + + // If it has a completed district that serves as pseudo-irrigation source, suppress drawing irrigation + if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (is->current_render_tile, inst->district_id)) + return; + + Map_Renderer_m11_Draw_Tile_Irrigation (this, __, visible_to_civ, tile_x, tile_y, param_4, param_5, param_6); +} + +bool __fastcall +patch_Tile_has_city_or_district (Tile * this) +{ + bool has_city = Tile_has_city (this); + if (is->current_config.enable_districts || is->current_config.enable_natural_wonders) { + return has_city || (get_district_instance (this) != NULL); + } + return has_city; +} + +int __fastcall +patch_Tile_check_water_for_navigator_cell_coloring (Tile * this) +{ + if (! is->current_config.show_territory_colors_on_water_tiles_in_minimap) + return this->vtable->m35_Check_Is_Water (this); + else + return 0; +} + +bool +is_skippable_popup (char * text_key) +{ + char * skippable_keys[] = {"SUMMARY_END_GOLDEN_AGE", "SUMMARY_END_SCIENCE_AGE", "SUMMARY_NEW_SMALL_WONDER", // unimportant domestic things + "WONDERPRODUCE", // another civ completed a wonder + "MAKEPEACE", "MUTUALPROTECTIONPACT", "MILITARYALLIANCE", "SUMMARY_DECLARE_WAR", // diplo events not involving the player + "TRADEEMBARGOENDS", // embargo vs player ends + "SUMMARY_CIV_DESTROYED_BY_CIV", "SUMMARY_CIV_DESTROYED", // foreign civs destroyed not by player + "LOSTGOOD", // 'We lost our supply of ...!' + "TRADEEMBARGO", "MILITARYALLIANCEWARONUS", "MILITARYALLIANCEAGAINSTUS", // trade embargo or alliance vs player + "SUMMARY_TRAVELERS_REPORT"}; // another civs starts a wonder + + for (int n = 0; n < ARRAY_LEN (skippable_keys); n++) + if (strcmp (text_key, skippable_keys[n]) == 0) + return true; + return false; +} + +int __fastcall +patch_PopupForm_impl_begin_showing_popup (PopupForm * this) +{ + if (is_online_game () || + (! is->current_config.convert_some_popups_into_online_mp_messages) || + (! is_skippable_popup (this->text_key))) + return PopupForm_impl_begin_showing_popup (this); + + else { + unsigned saved_prefs = *p_preferences; + int saved_flags = this->field_1BF0[0xE4]; + + *p_preferences |= P_SHOW_FEWER_MP_POPUPS; + this->field_1BF0[0xE4] |= 0x4000; + int tr = PopupForm_impl_begin_showing_popup (this); + + *(bool *)(p_main_screen_form->animator.field_18E4 + 10) = true; // Set what must be a dirty flag + Animator_update (&p_main_screen_form->animator); // Make sure message appears + + this->field_1BF0[0xE4] = saved_flags; + *p_preferences = saved_prefs; + + return tr; + } +} + +bool __stdcall +patch_is_online_game_for_show_popup () +{ + return is->current_config.convert_some_popups_into_online_mp_messages ? true : is_online_game (); +} + +bool +ai_move_district_worker (Unit * worker, struct district_worker_record * rec) +{ + if ((worker == NULL) || (rec == NULL)) + return false; + + char ss[200]; + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d assigned to build district\n", worker->Body.ID); + (*p_OutputDebugStringA) (ss); + + // Check the original request city made for district + struct pending_district_request * req = rec->pending_req; + if ((req == NULL) || + (req->assigned_worker_id != worker->Body.ID) || + (req->target_x < 0) || (req->target_y < 0)) + return false; + + int district_id = req->district_id; + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d moving to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); + (*p_OutputDebugStringA) (ss); + + City * request_city = get_city_ptr (req->city_id); + if (request_city == NULL) { + clear_tracked_worker_assignment (rec); + remove_pending_district_request (req); + return false; + } + req->city = request_city; + struct district_config * cfg = &is->district_configs[district_id]; + Tile * target_tile = tile_at (req->target_x, req->target_y); + if ((target_tile == NULL) || (target_tile == p_null_tile) || + (target_tile->vtable->m38_Get_Territory_OwnerID (target_tile) != worker->Body.CivID) || + (! city_radius_contains_tile (request_city, req->target_x, req->target_y))) { + clear_city_district_request (request_city, req->district_id); + return false; + } + + // If the worker has arrived + if ((worker->Body.X == req->target_x) && (worker->Body.Y == req->target_y)) { + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d arrived at (%d,%d) to build district\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + Tile * tile = tile_at (worker->Body.X, worker->Body.Y); + struct district_instance * inst = get_district_instance (tile); + bool do_replacement = false; + + // If there is a completed district here already + if ((inst != NULL) && district_is_complete (tile, inst->district_id)) { + int existing_district_id = inst->district_id; + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d found existing district ID %d at (%d,%d)\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + if (existing_district_id == req->district_id) { + clear_city_district_request (request_city, req->district_id); + clear_tracked_worker_assignment (rec); + return false; + } + + // Allow replacement of unused wonder districts + if (existing_district_id == WONDER_DISTRICT_ID) { + struct wonder_district_info * info = &inst->wonder_info; + if (info->state == WDS_UNUSED) + do_replacement = true; + } else if (district_is_obsolete_for_civ (existing_district_id, request_city->Body.CivID)) { + do_replacement = true; + } else { + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d cannot replace existing district ID %d at (%d,%d), cancelling request\n", worker->Body.ID, existing_district_id, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + clear_city_district_request (request_city, req->district_id); + return false; + } + + if (!do_replacement) { + return false; // Nothing left to do here + } + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for duplicate districts near city at (%d,%d)\n", request_city->Body.X, request_city->Body.Y); + (*p_OutputDebugStringA) (ss); + + // One final check: do we still need the district? Check for any dupes nearby + if (req->district_id != DISTRIBUTION_HUB_DISTRICT_ID && req->district_id != NEIGHBORHOOD_DISTRICT_ID) { + FOR_DISTRICTS_AROUND (wai, request_city->Body.X, request_city->Body.Y, false) { + if (wai.tile == tile) + continue; + + if (wai.district_inst->district_id == req->district_id) { + snprintf (ss, sizeof ss, "ai_move_district_worker: Found duplicate district ID %d near city at (%d,%d), cancelling request\n", req->district_id, request_city->Body.X, request_city->Body.Y); + (*p_OutputDebugStringA) (ss); + clear_city_district_request (request_city, req->district_id); + return false; + } + } + } + + // Need to make sure distro hubs get roads. If this will be one, build the road first to be sure + if (req->district_id == DISTRIBUTION_HUB_DISTRICT_ID) { + bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); + if (! has_road && ! cfg->auto_add_road) { + Unit_set_state(worker, __, UnitState_Build_Road); + worker->Body.Job_ID = WJ_Build_Road; + return true; + } + } + + enum SquareTypes base_type = tile->vtable->m50_Get_Square_BaseType (tile); + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); + bool district_buildable_here = district_is_buildable_on_tile (&is->district_configs[req->district_id], tile); + + // Remove any existing improvements + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); + if (do_replacement) { + remove_district_instance (tile); + handle_district_removed (tile, req->district_id, worker->Body.X, worker->Body.Y, false); + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for craters or pollution at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + if (tile->vtable->m21_Check_Crates (tile, __, 0) || tile->vtable->m20_Check_Pollution (tile, __, 0)) { + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d clearing craters or pollution at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + Unit_set_state(worker, __, UnitState_Clear_Damage); + worker->Body.Job_ID = WJ_Clean_Pollution; + return true; + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Checking for forest or wetlands at worker ID %d location (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + // Clear any forest/wetlands + if (! district_buildable_here && base_type == SQ_Forest) { + Unit_set_state(worker, __, UnitState_Clear_Forest); + worker->Body.Job_ID = WJ_Clean_Forest; + return true; + } else if (! district_buildable_here && ((base_type == SQ_Jungle) || (base_type == SQ_Swamp))) { + Unit_set_state(worker, __, UnitState_Clear_Wetlands); + worker->Body.Job_ID = WJ_Clear_Swamp; + return true; + } + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d starting construction of district at (%d,%d)\n", worker->Body.ID, worker->Body.X, worker->Body.Y); + (*p_OutputDebugStringA) (ss); + + // Clear any existing improvements (irrigation and mines) + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, worker->Body.X, worker->Body.Y); + + // Start construction of district + inst = ensure_district_instance (tile, req->district_id, req->target_x, req->target_y); + inst->built_by_civ_id = worker->Body.CivID; + Unit_set_state(worker, __, UnitState_Build_Mines); + worker->Body.Job_ID = WJ_Build_Mines; // Build district + return true; + + // Else if the worker needs to be sent + } else { + if ((worker->Body.UnitState != UnitState_Go_To) || + (worker->Body.path_dest_x != req->target_x) || + (worker->Body.path_dest_y != req->target_y)) { + int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, + worker->Body.X, worker->Body.Y, req->target_x, req->target_y, + worker, worker->Body.CivID, 0x41, NULL); + if (path_result > 0) { + + snprintf (ss, sizeof ss, "ai_move_district_worker: Worker ID %d path set to (%d,%d) to build district\n", worker->Body.ID, req->target_x, req->target_y); + (*p_OutputDebugStringA) (ss); + + Unit_set_escortee (worker, __, -1); + Unit_set_state (worker, __, UnitState_Go_To); + worker->Body.path_dest_x = req->target_x; + worker->Body.path_dest_y = req->target_y; + } else { + clear_tracked_worker_assignment (rec); + return false; + } + } + } + return false; +} + +bool +ai_worker_try_tile_improvement_district (Unit * worker) +{ + if (! is->current_config.enable_districts || worker == NULL) return false; + if (! is_worker (worker)) return false; + if (worker->Body.Auto_CityID < 0) return false; + + City * city = get_city_ptr (worker->Body.Auto_CityID); + if (city == NULL) return false; + if (city->Body.CivID != worker->Body.CivID) return false; + + int civ_id = worker->Body.CivID; + int tile_x = worker->Body.X; + int tile_y = worker->Body.Y; + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (tile->CityID >= 0) return false; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; + if (! city_radius_contains_tile (city, tile_x, tile_y)) return false; + if (get_district_instance (tile) != NULL) return false; + + // Evaluate whether the best improvement here is irrigation, mines, or a district, using heuristics based on city needs + int food_weight = (city->Body.FoodIncome < city->Body.FoodRequired) ? 3 : 1; + int shield_weight = (city->Body.ProductionIncome < city->Body.Population.Size) ? 2 : 1; + int unhappy_percent = + city->Body.UnhappyNoReasonPercent + + city->Body.UnhappyCrowdedPercent + + city->Body.UnhappyWarWearinessPercent + + city->Body.UnhappyAgresssionPercent + + city->Body.UnhappyPropagandaPercent + + city->Body.UnhappyDraftPercent + + city->Body.UnhappyOppressionPercent + + city->Body.UnhappyThisCityImprovementsPercent + + city->Body.UnhappyOtherCityImprovementsPercent; + int happiness_weight = (unhappy_percent > 0) ? 2 : 1; + int gold_weight = 1; + int resource_boost = 5 * (food_weight + shield_weight + gold_weight + happiness_weight); + + int irrigation_score = INT_MIN; + if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Irrigate, tile_x, tile_y, 0) && + ! tile->vtable->m17_Check_Irrigation (tile, __, 0)) { + int base_type = tile->vtable->m50_Get_Square_BaseType (tile); + int bonus = p_bic_data->TileTypes[base_type].IrrigationBonus; + if (bonus < 0) + bonus = 0; + irrigation_score = bonus * food_weight; + } + + int mine_score = INT_MIN; + if (Leader_can_do_worker_job (&leaders[civ_id], __, WJ_Build_Mines, tile_x, tile_y, 0) && + ! tile->vtable->m18_Check_Mines (tile, __, 0)) { + int base_type = tile->vtable->m50_Get_Square_BaseType (tile); + int bonus = p_bic_data->TileTypes[base_type].MiningBonus; + if (bonus < 0) + bonus = 0; + mine_score = bonus * shield_weight; + } + + int best_score = INT_MIN; + int best_district_id = -1; + for (int i = 0; i < is->district_count; i++) { + struct district_config const * cfg = &is->district_configs[i]; + if (cfg->ai_build_strategy != DABS_TILE_IMPROVEMENT) + continue; + if (! can_build_district_on_tile (tile, i, civ_id)) + continue; + + struct district_instance temp = {0}; + temp.district_id = i; + temp.tile_x = (short)tile_x; + temp.tile_y = (short)tile_y; + + int food = 0, shields = 0, gold = 0, science = 0, culture = 0, happiness = 0; + get_effective_district_yields (&temp, cfg, &food, &shields, &gold, &science, &culture, &happiness); + + int score = food * food_weight + shields * shield_weight + gold * gold_weight; + score += (science + culture) / 2; + score += happiness * happiness_weight; + if ((cfg->generated_resource_id >= 0) && + ! patch_City_has_resource (city, __, cfg->generated_resource_id)) + score += resource_boost; + + if (score > best_score) { + best_score = score; + best_district_id = i; + } + } + + if ((best_district_id >= 0) && + (best_score >= irrigation_score) && + (best_score >= mine_score)) { + unsigned int overlay_flags = tile->vtable->m42_Get_Overlays (tile, __, 0); + unsigned int removable_flags = overlay_flags & (destructible_overlays & ~(TILE_FLAG_ROAD | TILE_FLAG_RAILROAD)); + tile->vtable->m62_Set_Tile_BuildingID (tile, __, -1); + if (removable_flags != 0) + tile->vtable->m51_Unset_Tile_Flags (tile, __, 0, removable_flags, tile_x, tile_y); + ensure_district_instance (tile, best_district_id, tile_x, tile_y); + Unit_set_state (worker, __, UnitState_Build_Mines); + worker->Body.Job_ID = WJ_Build_Mines; + return true; + } + + return false; +} + +void __fastcall +patch_Unit_ai_move_terraformer (Unit * this) +{ + Map * map = &p_bic_data->Map; + int type_id = this->Body.UnitTypeID; + int civ_id = this->Body.CivID; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + int territory_owner = ((tile != NULL) && (tile != p_null_tile)) ? tile->vtable->m38_Get_Territory_OwnerID (tile) : -1; + + + if (is->current_config.enable_districts && ! is_human && is_worker (this)) { + update_tracked_worker_for_unit (this); + struct district_instance * inst = get_district_instance (tile); + + if ((territory_owner == civ_id) && + inst != NULL && inst->district_id != NATURAL_WONDER_DISTRICT_ID && + tile->vtable->m50_Get_Square_BaseType (tile) != SQ_Coast) { + // Roads should be made after district builds. The district is complete but + // worker is still likely on the tile, so check here and build road if needed + struct district_config * cfg = &is->district_configs[inst->district_id]; + bool has_road = (*tile->vtable->m25_Check_Roads)(tile, __, 0); + if (! has_road && ! cfg->auto_add_road) { + Unit_set_state(this, __, UnitState_Build_Road); + this->Body.Job_ID = WJ_Build_Road; + return; + } + + // Same check for railroads + bool can_build_railroad = Leader_can_do_worker_job (&leaders[this->Body.CivID], __, WJ_Build_Railroad, this->Body.X, this->Body.Y, 0); + bool has_railroad = (*tile->vtable->m23_Check_Railroads)(tile, __, 0); + if (can_build_railroad && !has_railroad && ! cfg->auto_add_railroad) { + Unit_set_state(this, __, UnitState_Build_Railroad); + this->Body.Job_ID = WJ_Build_Railroad; + return; + } + } + + struct district_worker_record * rec = get_tracked_worker_record (this); + if (rec != NULL && rec->pending_req != NULL) { + if (ai_move_district_worker (this, rec)) + return; + } + + if ((this->Body.Auto_CityID >= 0) && ai_worker_try_tile_improvement_district (this)) + return; + } + + bool pop_else_caravan; + if ((tile != NULL) && (tile != p_null_tile) && + (type_id >= 0) && (type_id < p_bic_data->UnitTypeCount) && + is_material_unit (&p_bic_data->UnitTypes[type_id], &pop_else_caravan) && + ((pop_else_caravan && is->current_config.enable_pop_unit_ai) || + ((! pop_else_caravan) && is->current_config.enable_caravan_unit_ai))) { + ai_move_material_unit (this); + return; + } + + Unit_ai_move_terraformer (this); +} + +bool __fastcall +patch_Unit_ai_can_sacrifice (Unit * this, int edx, bool requires_city) +{ + int sacrifice_action = UCV_Sacrifice & 0x0FFFFFFF; // Mask out top four category bits + UnitType * type = &p_bic_data->UnitTypes[this->Body.UnitTypeID]; + if (is->current_config.patch_ai_can_sacrifice_without_special_ability && ((type->Special_Actions & sacrifice_action) == 0)) + return false; + else + return Unit_ai_can_sacrifice (this, __, requires_city); +} + +int __cdecl +patch_get_building_defense_bonus_at (int x, int y, int param_3) +{ + // Get base building defense bonus first + int base = get_building_defense_bonus_at (x, y, param_3); + + // If districts are disabled, return base + if (!is->current_config.enable_districts) + return base; + + Tile * tile = tile_at (x, y); + if ((tile == NULL) || (tile == p_null_tile)) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL) { + struct district_config const * cfg = &is->district_configs[inst->district_id]; + int bonus = cfg->defense_bonus_percent; + bonus += apply_district_bonus_entries (inst, &cfg->defense_bonus_extras, inst->district_id); + return bonus; + } + + return base; +} + +void __fastcall +patch_Unit_select (Unit * this) +{ + if (is->current_config.enable_districts) { + Tile * tile = tile_at (this->Body.X, this->Body.Y); + + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && is_worker(this) && inst->district_id >= 0 && inst->district_id <= is->district_count && + ! district_is_complete (tile, inst->district_id)) { + int district_id = inst->district_id; + PopupForm * popup = get_popup_form (); + int remaining_turns = get_worker_remaining_turns_to_complete (this, __, 0); + set_popup_str_param (0, (char*)is->district_configs[district_id].display_name, -1, -1); + set_popup_int_param (1, remaining_turns); + popup->vtable->set_text_key_and_flags (popup, __, is->mod_script_path, "C3X_CONFIRM_CANCEL_BUILD_DISTRICT", -1, 0, 0, 0); + + int sel = patch_show_popup (popup, __, 0, 0); + if (sel == 0) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, 0); + + bool other_workers_present = false; + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit != NULL) && (unit != this) && + (unit->Body.UnitState == UnitState_Build_Mines) && + (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Worker_Actions != 0)) { + other_workers_present = true; + break; + } + } + if (! other_workers_present) { + remove_district_instance (tile); + } + } else { + return; + } + } + } + + // Sometimes clearing of highlighted tiles doesn't trigger when CTRL lifted, so double-check here + if (is->current_config.enable_city_work_radii_highlights && is->highlight_city_radii) { + is->highlight_city_radii = false; + clear_highlighted_worker_tiles_and_redraw (); + } + + Unit_select (this); +} + +void __fastcall +patch_City_Form_draw_food_income_icons (City_Form * this) +{ + // Call original function first + City_Form_draw_food_income_icons (this); + + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) + return; + + // Get current city + City * city = this->CurrentCity; + if (city == NULL) + return; + + // Calculate standard district food bonus + int standard_district_food = 0; + FOR_DISTRICTS_AROUND (wai, city->Body.X, city->Body.Y, true) { + int district_id = wai.district_inst->district_id; + int food_bonus = 0; + get_effective_district_yields (wai.district_inst, &is->district_configs[district_id], &food_bonus, NULL, NULL, NULL, NULL, NULL); + standard_district_food += food_bonus; + } + + // Get distribution hub food bonus + int distribution_hub_food = 0; + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) + get_distribution_hub_yields_for_city (city, &distribution_hub_food, NULL); + + // Total district food + int total_district_food = standard_district_food + distribution_hub_food; + if (total_district_food <= 0) + return; + + // Lazy load icons + if (is->current_config.enable_districts && is->current_config.enable_distribution_hub_districts) { + if (is->distribution_hub_icons_img_state == IS_UNINITED) + init_distribution_hub_icons (); + if (is->distribution_hub_icons_img_state != IS_OK) + return; + } + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + if (is->dc_icons_img_state != IS_OK) + return; + + int food_income = city->Body.FoodIncome; + int food_required = city->Body.FoodRequired; + + // Calculate how standard district food icons are distributed + int standard_food_eaten = 0; + int standard_food_surplus = 0; + if (standard_district_food > 0) { + if (standard_district_food >= food_income) { + standard_food_surplus = food_income; + standard_food_eaten = standard_district_food - food_income; + } else { + standard_food_surplus = standard_district_food; + standard_food_eaten = 0; + } + } + + // Calculate how distribution hub food icons are distributed + int hub_food_eaten = 0; + int hub_food_surplus = 0; + int remaining_income = food_income - standard_food_surplus; + if (distribution_hub_food > 0) { + if (distribution_hub_food >= remaining_income) { + hub_food_surplus = remaining_income; + hub_food_eaten = distribution_hub_food - remaining_income; + } else { + hub_food_surplus = distribution_hub_food; + hub_food_eaten = 0; + } + } + + // Draw eaten district food icons (left side, from right to left) + int total_eaten = standard_food_eaten + hub_food_eaten; + if (total_eaten > 0) { + Sprite * base_eaten_sprite = &(this->City_Icons_Images).Icon_07; + int eaten_sprite_width = base_eaten_sprite->Width; + int eaten_sprite_height = base_eaten_sprite->Height; + struct tagRECT * eaten_rect = &this->Food_Consumption_Rect; + int eaten_rect_width = eaten_rect->right - eaten_rect->left; + + int eaten_spacing = eaten_sprite_width; + if ((food_required > 1) && (food_required * eaten_sprite_width - eaten_rect_width != 0) && + (eaten_rect_width <= food_required * eaten_sprite_width)) { + eaten_spacing = (eaten_rect_width - eaten_sprite_width) / (food_required - 1); + if (eaten_spacing < 1) + eaten_spacing = 1; + else if (eaten_spacing > eaten_sprite_width) + eaten_spacing = eaten_sprite_width; + } + + int eaten_x_offset = eaten_spacing * (food_required - 1); + // Draw standard district eaten first + for (int i = 0; i < standard_food_eaten && i < food_required; i++) { + int x = eaten_rect->left + eaten_x_offset; + int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - + (eaten_sprite_height >> 1)); + Sprite_draw (&is->district_food_eaten_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + eaten_x_offset -= eaten_spacing; + } + // Draw distribution hub eaten + for (int i = 0; i < hub_food_eaten && eaten_x_offset >= 0; i++) { + int x = eaten_rect->left + eaten_x_offset; + int y = eaten_rect->top + ((eaten_rect->bottom - eaten_rect->top >> 1) - + (eaten_sprite_height >> 1)); + Sprite_draw (&is->distribution_hub_eaten_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + eaten_x_offset -= eaten_spacing; + } + } + + // Draw surplus district food icons (right side, from right to left) + int total_surplus = standard_food_surplus + hub_food_surplus; + if (total_surplus > 0) { + Sprite * base_surplus_sprite = &(this->City_Icons_Images).Icon_06; + int surplus_sprite_width = base_surplus_sprite->Width; + int surplus_sprite_height = base_surplus_sprite->Height; + struct tagRECT * surplus_rect = &this->Food_Storage_Rect; + int surplus_rect_width = surplus_rect->right - surplus_rect->left; + + int surplus_spacing = surplus_sprite_width; + if ((food_income > 1) && (food_income * surplus_sprite_width - surplus_rect_width != 0) && + (surplus_rect_width <= food_income * surplus_sprite_width)) { + surplus_spacing = (surplus_rect_width - surplus_sprite_width) / (food_income - 1); + if (surplus_spacing < 1) + surplus_spacing = 1; + else if (surplus_spacing > surplus_sprite_width) + surplus_spacing = surplus_sprite_width; + } + + int surplus_x_offset = 0; + // Draw standard district surplus first + for (int i = 0; i < standard_food_surplus && i < food_income; i++) { + int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; + int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - + (surplus_sprite_height >> 1)) - 1; + Sprite_draw (&is->district_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + surplus_x_offset += surplus_spacing; + } + // Draw distribution hub surplus + for (int i = 0; i < hub_food_surplus && surplus_x_offset < surplus_rect_width; i++) { + int x = surplus_rect->right - surplus_x_offset - surplus_sprite_width; + int y = surplus_rect->top + ((surplus_rect->bottom - surplus_rect->top >> 1) - + (surplus_sprite_height >> 1)) - 1; + Sprite_draw (&is->distribution_hub_food_icon, __, &(this->Base).Data.Canvas, x, y, NULL); + surplus_x_offset += surplus_spacing; + } + } +} + +void +recompute_district_and_distribution_hub_shields_for_city_view (City * city) +{ + if ((! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) || (city == NULL)) + return; + + int city_id = city->Body.ID; + int city_x = city->Body.X; + int city_y = city->Body.Y; + + // District yields are injected through the city center tile in patch_City_calc_tile_yield_while_gathering. + // Grab the base yield (no districts) directly from the original function, then compute the + // district bonus that calculate_city_center_district_bonus will layer on afterward. + int city_center_base_shields = City_calc_tile_yield_at (city, __, YK_SHIELDS, city_x, city_y); + int total_district_shield_bonus = 0; + calculate_city_center_district_bonus (city, NULL, &total_district_shield_bonus, NULL); + + // Distribution hub contribution is tracked separately for icon rendering. + int distribution_hub_shields = 0; + if (is->current_config.enable_distribution_hub_districts) + get_distribution_hub_yields_for_city (city, NULL, &distribution_hub_shields); + if (distribution_hub_shields < 0) + distribution_hub_shields = 0; + if (distribution_hub_shields > total_district_shield_bonus) + distribution_hub_shields = total_district_shield_bonus; + + int standard_district_shields = total_district_shield_bonus - distribution_hub_shields; + if (standard_district_shields < 0) + standard_district_shields = 0; + + // Recompute yields with districts active so ProductionIncome/Loss reflect the city view. + recompute_city_yields_with_districts (city); + int total_production_income = city->Body.ProductionIncome; + int total_production_loss = city->Body.ProductionLoss; + int total_net_shields = total_production_income + total_production_loss; // ProductionLoss stored as negative + + // Remove the district bonus from the gross tile production and recompute corruption on that base value. + int city_center_with_districts = city_center_base_shields + total_district_shield_bonus; + int gross_without_specials = city->Body.Tiles_Production - (city_center_with_districts - city_center_base_shields); + if (gross_without_specials < 0) + gross_without_specials = 0; + + int base_corruption_abs = patch_City_compute_corrupted_yield (city, __, gross_without_specials, true); + if (base_corruption_abs < 0) + base_corruption_abs = 0; + int base_production_loss = -base_corruption_abs; + + // Corruption becomes more negative as it increases. + int additional_corruption = total_production_loss - base_production_loss; + + int district_shields_remaining = standard_district_shields; + int hub_shields_remaining = distribution_hub_shields; + + if (additional_corruption < 0) { + int extra_loss = -additional_corruption; + + if (district_shields_remaining > 0) { + int from_districts = (extra_loss < district_shields_remaining) ? extra_loss : district_shields_remaining; + district_shields_remaining -= from_districts; + extra_loss -= from_districts; + } + + if ((extra_loss > 0) && (hub_shields_remaining > 0)) { + int from_hub = (extra_loss < hub_shields_remaining) ? extra_loss : hub_shields_remaining; + hub_shields_remaining -= from_hub; + extra_loss -= from_hub; + } + } + + int non_district_shields_remaining = total_net_shields - district_shields_remaining - hub_shields_remaining; + if (non_district_shields_remaining < 0) + non_district_shields_remaining = 0; + + int total_corruption = -total_production_loss; + if (total_corruption < 0) + total_corruption = 0; + int district_corruption = standard_district_shields - district_shields_remaining; + int hub_corruption = distribution_hub_shields - hub_shields_remaining; + int base_corruption = total_corruption - district_corruption - hub_corruption; + if (base_corruption < 0) + base_corruption = 0; + + is->non_district_shield_icons_remaining = non_district_shields_remaining; + is->district_shield_icons_remaining = district_shields_remaining; + is->distribution_hub_shield_icons_remaining = hub_shields_remaining; + + is->corruption_shield_icons_remaining = base_corruption; + is->district_corruption_icons_remaining = district_corruption; + is->distribution_hub_corruption_icons_remaining = hub_corruption; +} + +void __fastcall +patch_City_draw_production_income_icons (City * this, int edx, int canvas, int * rect_ptr) +{ + if (! is->current_config.enable_districts && ! is->current_config.enable_natural_wonders) { + City_draw_production_income_icons (this, __, canvas, rect_ptr); + return; + } + + recompute_district_and_distribution_hub_shields_for_city_view (this); + City_draw_production_income_icons (this, __, canvas, rect_ptr); + + is->corruption_shield_icons_remaining = 0; + is->district_corruption_icons_remaining = 0; + is->distribution_hub_corruption_icons_remaining = 0; + + is->non_district_shield_icons_remaining = 0; + is->district_shield_icons_remaining = 0; + is->distribution_hub_shield_icons_remaining = 0; +} + +int __fastcall +patch_Sprite_draw_production_income_icon (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + if (is->distribution_hub_icons_img_state == IS_UNINITED) + init_distribution_hub_icons (); + if (is->dc_icons_img_state == IS_UNINITED) + init_district_icons (); + + if ((is->current_config.enable_districts || is->current_config.enable_natural_wonders) && is->dc_icons_img_state == IS_OK) { + Sprite to_draw = *this; + if (is->corruption_shield_icons_remaining > 0 || + is->district_corruption_icons_remaining > 0 || + is->distribution_hub_corruption_icons_remaining > 0) { + + if (is->corruption_shield_icons_remaining > 0) { + is->corruption_shield_icons_remaining--; + } else if (is->district_corruption_icons_remaining > 0) { + to_draw = is->district_corruption_icon; + is->district_corruption_icons_remaining--; + } else if (is->distribution_hub_icons_img_state == IS_OK) { + to_draw = is->distribution_hub_corruption_icon; + is->distribution_hub_corruption_icons_remaining--; + } + } + else if (is->non_district_shield_icons_remaining > 0 || + is->district_shield_icons_remaining > 0 || + is->distribution_hub_shield_icons_remaining > 0) { + + if (is->non_district_shield_icons_remaining > 0) { + is->non_district_shield_icons_remaining--; + } else if (is->district_shield_icons_remaining > 0) { + to_draw = is->district_shield_icon; + is->district_shield_icons_remaining--; + } else if (is->distribution_hub_icons_img_state == IS_OK) { + to_draw = is->distribution_hub_shield_icon; + is->distribution_hub_shield_icons_remaining--; + } + + } + return Sprite_draw (&to_draw, __, canvas, pixel_x, pixel_y, color_table); + } + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +bool +district_tile_needs_defense (Tile * tile, int tile_x, int tile_y, struct district_instance * inst, int civ_id, int work_radius) +{ + if ((tile == NULL) || (tile == p_null_tile)) return false; + if (inst == NULL) return false; + + int district_id = inst->district_id; + struct district_config const * cfg = &is->district_configs[district_id]; + if (! district_is_complete (tile, district_id)) return false; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != civ_id) return false; + + // Check if already has enough defenders (2 for aerodromes, distribution hubs, destroyable completed wonders) + int defender_count = count_units_at (tile_x, tile_y, UF_DEFENDER_VIS_TO_A_OF_CLASS_B, civ_id, 0, -1); + int max_defenders = + (district_id == AERODROME_DISTRICT_ID || district_id == DISTRIBUTION_HUB_DISTRICT_ID || + (cfg->defense_bonus_percent > 0 && district_id != NEIGHBORHOOD_DISTRICT_ID) || + (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed)) + ? 2 : 1; + if (defender_count >= max_defenders) + return false; + + // Distribution hubs always need defense + if (district_id == DISTRIBUTION_HUB_DISTRICT_ID) + return true; + + // Wonder districts need defense if under construction or completed (not unused) + if (district_id == WONDER_DISTRICT_ID && is->current_config.completed_wonder_districts_can_be_destroyed) { + enum wonder_district_state state = inst->wonder_info.state; + if (state == WDS_UNDER_CONSTRUCTION || state == WDS_COMPLETED) + return true; + // Unused wonder districts don't need defense + return false; + } + + return any_enemies_near (&leaders[civ_id], tile_x, tile_y, -1, work_radius); +} + +int +compute_turns_required_for_path (Unit * unit, int path_length) +{ + if (path_length < 1) + return 0; + + int max_mp = patch_Unit_get_max_move_points (unit); + if (max_mp <= 0) + return 9999; + + int moves_used_this_turn = max_mp - unit->Body.Moves; + moves_used_this_turn = not_below (0, moves_used_this_turn); + moves_used_this_turn = not_above (moves_used_this_turn, 9999); + + int remaining_mp = path_length - moves_used_this_turn; + if (remaining_mp < 0) + remaining_mp = 0; + + return (max_mp - 1 + remaining_mp) / max_mp + 1; +} + +void +maybe_update_best_district_target (Unit * unit, + int civ_id, + int max_distance, + int unit_x, + int unit_y, + int tile_x, + int tile_y, + int base_score, + int * best_score, + int * best_x, + int * best_y, + int * best_path_length, + int * evaluated_paths, + int max_path_checks) +{ + if (*evaluated_paths >= max_path_checks) + return; + + int path_length; + int path_result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, tile_x, tile_y, + unit, civ_id, 0x81, &path_length); + *evaluated_paths += 1; + if (path_result <= 0) + return; + + if (max_distance > 0) { + int turns = compute_turns_required_for_path (unit, path_length); + if (turns > max_distance) + return; + } + + int score = base_score - path_length; + if ((score > *best_score) || ((score == *best_score) && (path_length < *best_path_length))) { + *best_score = score; + *best_x = tile_x; + *best_y = tile_y; + *best_path_length = path_length; + } +} + +// Patch seek_colony to actively search for undefended districts +int __fastcall +patch_Unit_seek_colony (Unit * this, int edx, bool for_own_defense, int max_distance) +{ + // Only intercept if defending own assets and districts are enabled + if (!for_own_defense || + !is->current_config.enable_districts || + !is->current_config.ai_defends_districts) + return Unit_seek_colony (this, __, for_own_defense, max_distance); + + int civ_id = this->Body.CivID; + int unit_x = this->Body.X; + int unit_y = this->Body.Y; + + Tile * current_tile = tile_at (unit_x, unit_y); + if ((current_tile == NULL) || (current_tile == p_null_tile)) + return Unit_seek_colony (this, __, for_own_defense, max_distance); + + int continent_id = current_tile->vtable->m46_Get_ContinentID (current_tile); + + const int search_radius = 20; + const int max_path_checks = 64; + const int wonder_base_score = 1000; + const int regular_base_score = 500; + + int best_x = -1; + int best_y = -1; + int best_score = INT_MIN; + int best_path_length = INT_MAX; + int evaluated_paths = 0; + + bool abort_search = false; + + if ((is->current_config.enable_wonder_districts && is->current_config.completed_wonder_districts_can_be_destroyed) || + is->current_config.enable_distribution_hub_districts) { + for (int dx = -search_radius; (dx <= search_radius) && !abort_search; dx++) { + for (int dy = -search_radius; dy <= search_radius; dy++) { + if (evaluated_paths >= max_path_checks) { + abort_search = true; + break; + } + + int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); + int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); + Tile * district_tile = tile_at (target_x, target_y); + if ((district_tile == NULL) || (district_tile == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (district_tile); + if (inst == NULL) + continue; + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) + continue; + if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) + continue; + if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) + continue; + + maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, + tile_x, tile_y, wonder_base_score, + &best_score, &best_x, &best_y, + &best_path_length, &evaluated_paths, + max_path_checks); + } + } + } + + if ((best_x < 0) && (evaluated_paths < max_path_checks)) { + for (int dx = -search_radius; (dx <= search_radius) && (evaluated_paths < max_path_checks); dx++) { + for (int dy = -search_radius; dy <= search_radius; dy++) { + if (evaluated_paths >= max_path_checks) + break; + + int target_x = Map_wrap_horiz (&p_bic_data->Map, __, unit_x + dx); + int target_y = Map_wrap_vert (&p_bic_data->Map, __, unit_y + dy); + Tile * district_tile = tile_at (target_x, target_y); + if ((district_tile == NULL) || (district_tile == p_null_tile)) + continue; + + struct district_instance * inst = get_district_instance (district_tile); + if ((inst == NULL) || (inst->district_id == WONDER_DISTRICT_ID)) + continue; + + int tile_x, tile_y; + if (! district_instance_get_coords (inst, district_tile, &tile_x, &tile_y)) + continue; + if (district_tile->vtable->m46_Get_ContinentID (district_tile) != continent_id) + continue; + if (! district_tile_needs_defense (district_tile, tile_x, tile_y, inst, civ_id, 5)) + continue; + + maybe_update_best_district_target (this, civ_id, max_distance, unit_x, unit_y, + tile_x, tile_y, regular_base_score, + &best_score, &best_x, &best_y, + &best_path_length, &evaluated_paths, + max_path_checks); + } + } + } + + if ((best_x >= 0) && (best_y >= 0)) { + int result = Trade_Net_set_unit_path (is->trade_net, __, unit_x, unit_y, best_x, best_y, + this, civ_id, 0x181, NULL); + return result; + } + + return Unit_seek_colony (this, __, for_own_defense, max_distance); +} + +// Patch has_colony to make units stay on districts, only patches within Unit::ai_move_defensive_unit +bool __fastcall +patch_Tile_has_district_or_colony (Tile * this) +{ + if (is->current_config.enable_districts && + is->current_config.ai_defends_districts) { + + struct district_instance * inst = get_district_instance (this); + return (inst != NULL) && district_is_complete (this, inst->district_id); + } + + // Fallback to original has_colony logic + return Tile_has_colony (this); +} + +int __fastcall +patch_Buildings_Info_get_age_in_years_for_tourism (Buildings_Info * this, int edx, int building_index) +{ + int base = Buildings_Info_get_age_in_years (this, __, building_index); + if (is->current_config.tourism_time_scale_percent == 100) + return base; + else if (is->current_config.tourism_time_scale_percent <= 0) + return INT_MAX; + else + return (base * 100 + 50) / is->current_config.tourism_time_scale_percent; +} + +int __fastcall +patch_Sprite_draw_minimap_frame (Sprite * this, int edx, Sprite * alpha, int param_2, PCX_Image * canvas, int x, int y, int param_6) +{ + bool want_larger_minimap = (is->current_config.double_minimap_size == MDM_ALWAYS) || + ((is->current_config.double_minimap_size == MDM_HIGH_DEF) && (p_bic_data->ScreenWidth >= 1920)); + if (want_larger_minimap && (init_large_minimap_frame () == IS_OK)) + return Sprite_draw_for_hud (&is->double_size_box_left_color_pcx, __, &is->double_size_box_left_alpha_pcx, param_2, canvas, x, y, param_6); + else + return Sprite_draw_for_hud (this, __, alpha, param_2, canvas, x, y, param_6); +} + +int __fastcall +patch_City_get_turns_to_build_2_for_ai_move_leader (City * this, int edx, City_Order * order, bool param_2) +{ + // Initialize order variable to city's current build. This is not done in the base logic and can cause crashes. + City_Order current_order = { .OrderID = this->Body.Order_ID, .OrderType = this->Body.Order_Type }; + if (is->current_config.patch_crash_in_leader_unit_ai) + order = ¤t_order; + + return City_get_turns_to_build_2 (this, __, order, param_2); +} + +void __fastcall +patch_City_set_production (City * this, int edx, int order_type, int order_id, bool ask_to_confirm) +{ + City_set_production (this, __, order_type, order_id, ask_to_confirm); + + if (! is->current_config.enable_districts || ! is->current_config.enable_wonder_districts) + return; + + // If the human player, we need to set/unset a wonder district for this city, depending + // on what is being built. The human player wouldn't be able to choose a wonder if a wonder + // district wasn't available, so we don't need to worry about feasibility here. + // The AI uses a different mechanism to reserve wonder districts via patch_Leader_do_production_phase. + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + if (! is_human) + return; + + char ss[256]; + bool release_reservation = true; + if (this->Body.Order_Type == COT_Improvement) { + Improvement * improv = &p_bic_data->Improvements[this->Body.Order_ID]; + if (improv->Characteristics & (ITC_Wonder | ITC_Small_Wonder)) { + if (reserve_wonder_district_for_city (this, this->Body.Order_ID)) { + release_reservation = false; + } + } + } + + if (release_reservation) { + release_wonder_district_reservation (this); + } +} + +int __fastcall +patch_Tile_m71_Check_Worker_Job (Tile * this) +{ + if (is->current_config.enable_natural_wonders) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && + (inst->district_id == NATURAL_WONDER_DISTRICT_ID) && + (inst->natural_wonder_info.natural_wonder_id >= 0)) { + return -1; // No worker job allowed on natural wonders + } + } + return Tile_m71_Check_Worker_Job (this); +} + +int __fastcall +patch_Tile_get_road_bonus (Tile * this) +{ + if (is->current_config.enable_natural_wonders) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && (inst->district_id == NATURAL_WONDER_DISTRICT_ID)) { + return 0; + } + } + if (is->current_config.enable_districts && is->current_config.enable_bridge_districts) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && (inst->district_id == BRIDGE_DISTRICT_ID)) { + return 1; + } + } + return Tile_get_road_bonus (this); +} + +bool __fastcall +patch_Unit_has_army_ability_to_perform_unload (Unit * this, int edx, enum UnitTypeAbilities a) +{ + return is->current_config.allow_unload_from_army ? false : Unit_has_ability (this, __, a); +} + +void __fastcall +patch_Unit_disembark (Unit * this, int edx, int tile_x, int tile_y) +{ + Unit * container = get_unit_ptr (this->Body.Container_Unit); + bool unloading_from_army = is->current_config.allow_unload_from_army && container != NULL && Unit_has_ability (container, __, UTA_Army); + + // If removing a unit from an army, transfer a proportional amount of damage to the unit removed + int damage_transferred = 0; + if (unloading_from_army) { + int army_damage_percent = container->Body.Damage * 100 / Unit_get_max_hp (container), + max_damage = Unit_get_max_hp (this) - 1 - this->Body.Damage; + damage_transferred = clamp (0, max_damage, (army_damage_percent * Unit_get_max_hp (this) + 50) / 100); + } + + Unit_disembark (this, __, tile_x, tile_y); + + if (unloading_from_army) { + this->Body.Damage = not_above (Unit_get_max_hp (this) - 1, this->Body.Damage + damage_transferred); + container->Body.Damage = not_below (0, container->Body.Damage - damage_transferred); + + if (this->Body.ID == container->Body.army_top_defender_id) { + Unit * new_top_defender = NULL; + FOR_UNITS_ON (uti, tile_at (container->Body.X, container->Body.Y)) + if (uti.unit->Body.Container_Unit == container->Body.ID) { + if (new_top_defender == NULL) + new_top_defender = uti.unit; + else if (Fighter_prefer_first_defender_1 (&p_bic_data->fighter, __, uti.unit, Unit_get_defense_strength (uti.unit), new_top_defender, Unit_get_defense_strength (new_top_defender), true)) + new_top_defender = uti.unit; + } + container->Body.army_top_defender_id = (new_top_defender != NULL) ? new_top_defender->Body.ID : -1; + } + } +} + +bool __fastcall +patch_Unit_has_ability_no_load_non_army_passengers (Unit * this, int edx, enum UnitTypeAbilities army_ability) +{ + UnitType * transport_type = &p_bic_data->UnitTypes[is->can_load_transport->Body.UnitTypeID], + * passenger_type = &p_bic_data->UnitTypes[this ->Body.UnitTypeID]; + + // This call comes from Unit::can_load at the point where it's determined that the passenger (this) has transport capacity > 0 and is checking + // whether it's an army. If not, it can't be loaded. Add two exceptions here for land transports, if configured, one to allow LTs to load into + // naval units and another to allow empty LTs to load into armies. + if (is->current_config.land_transport_rules != 0) + if ((passenger_type->Unit_Class == UTC_Land) && ! Unit_has_ability (this, __, army_ability)) { // if it's a land transport + if ((is->current_config.land_transport_rules & LTR_LOAD_ONTO_BOAT) && (transport_type->Unit_Class == UTC_Sea)) + return true; + if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && + Unit_has_ability (is->can_load_transport, __, army_ability) && (Unit_count_contained_units (this) == 0)) + return true; + } + + // Similarly, allow helicopters to be loaded onto carriers if so configured + if ((is->current_config.special_helicopter_rules & SHR_ALLOW_ON_CARRIERS) && + passenger_type->Unit_Class == UTC_Air && + transport_type->Unit_Class == UTC_Sea && + Unit_has_ability (is->can_load_transport, __, UTA_Transports_Only_Aircraft)) + return true; + + return Unit_has_ability (this, __, army_ability); +} + +bool __fastcall +patch_Unit_has_ability_no_load_transport_into_army (Unit * this, int edx, enum UnitTypeAbilities army_ability) +{ + // Similar to above, here it checks if the target unit is an army and rejects the load if it is (again, already determined that the passenger + // has transport capacity). Modify this rule to return false for land transports trying to join armies if configured. We don't have to check + // that the LT is empty since that is already disallowed by the modified check above. + bool is_army = Unit_has_ability (this, __, army_ability); + if ((is->current_config.land_transport_rules & LTR_JOIN_ARMY) && is_army && + (p_bic_data->UnitTypes[is->can_load_passenger->Body.UnitTypeID].Unit_Class == UTC_Land)) + return false; + + else + return is_army; +} + +bool __fastcall +patch_Fighter_unit_can_defend (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) +{ + if (cannot_defend_inside_transport (unit)) + return false; + else + return Fighter_unit_can_defend (this, __, unit, tile_x, tile_y); +} + +bool __fastcall +patch_Leader_is_enemy_unit_for_ground_aa (Leader * this, int edx, Unit * bomber) +{ + // When this function is called, the potential interceptor unit is stored in register ESI. + Unit * interceptor; + __asm__ __volatile__("mov %%esi, %0" : "=r" (interceptor)); + + Unit * container = get_unit_ptr (interceptor->Body.Container_Unit); + bool in_transport = (container != NULL) && ! Unit_has_ability (container, __, UTA_Army); + if (in_transport && + (is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Land) + return false; + else if (in_transport && + (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE) && + p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Air) + return false; + else if (in_transport && + is->current_config.no_land_anti_air_from_inside_naval_transport && + (p_bic_data->UnitTypes[container->Body.UnitTypeID].Unit_Class == UTC_Sea)) + return false; + else + return Leader_is_enemy_unit (this, __, bomber); +} + +bool __fastcall +patch_Unit_has_army_ability_for_passenger_despawn (Unit * this, int edx, enum UnitTypeAbilities army_ability) +{ + // If the unit has the army ability, the game will always despawn the passengers. Otherwise there are exceptions like land unit passengers + // won't be despawned if the transport is on a land tile. + return is->always_despawn_passengers || Unit_has_ability (this, __, army_ability); +} + +int __cdecl +patch_count_units_at_in_try_capturing (int x, int y, enum unit_filter filter, int arg_a, int arg_b, int arg_c) +{ + Tile * tile = tile_at (x, y); + + // If one of the no-defense-from-inside rules is in force, count units like the function normally would except skip units that are inside + // transports from which they can't defend. Otherwise, if those transports have 0 defense, the passengers will prevent them from being + // captured but not fight themselves, making movement onto their tile impossible. + if (tile->vtable->m35_Check_Is_Water (tile) == 0 && + ((is->current_config.land_transport_rules & LTR_NO_DEFENSE_FROM_INSIDE) || (is->current_config.special_helicopter_rules & SHR_NO_DEFENSE_FROM_INSIDE))) { + int tr = 0; + FOR_UNITS_ON (tai, tile) { + if ((arg_b == -1 || p_bic_data->UnitTypes[tai.unit->Body.UnitTypeID].Unit_Class == arg_b) && + (arg_a == -1 || patch_Unit_is_visible_to_civ (tai.unit, __, arg_a, 1)) && + (Unit_get_defense_strength (tai.unit) > 0) && + ! cannot_defend_inside_transport (tai.unit)) + tr++; + } + return tr; + + } else + return count_units_at (x, y, filter, arg_a, arg_b, arg_c); +} + +void __fastcall +patch_Map_generate_resources (Map * this, int edx, int secondary_seed) +{ + int const bic_tag_good = 0x444f4f47; // = 'GOOD' + int resource_type_count = this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, -1, NULL); + bool * ratios_to_clear = NULL; + int lux_percent = is->current_config.luxury_randomized_appearance_rate_percent; + int seed = (this->Seed + 0x180E3) * secondary_seed; + + // To change the randomized appearance rate for luxuries, fill in an appearance rate for any that would be randomized (rate set == 0) using + // the same process the game would to randomize the rate but with different limits. That process involves taking two random numbers from 0 to + // 25 then adding them together and to 50 to produce a random rate from 50 to 100 biased toward the middle of that range. + if (lux_percent != 100 && + (ratios_to_clear = calloc (1, resource_type_count)) != NULL) { + for (int n = 0; n < resource_type_count; n++) { + Resource_Type * res; + this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); + if (res->Class == RC_Luxury && res->AppearanceRatio == 0) { + ratios_to_clear[n] = true; + int half_lux_percent = (lux_percent * 50 + 50) / 100, + quarter_lux_percent = (lux_percent * 25 + 50) / 100; + res->AppearanceRatio = not_below (1, half_lux_percent + rand_int (&seed, __, quarter_lux_percent) + rand_int (&seed, __, quarter_lux_percent)); + } + } + } + + Map_generate_resources (this, __, secondary_seed); + + if (ratios_to_clear != NULL) { + for (int n = 0; n < resource_type_count; n++) + if (ratios_to_clear[n]) { + Resource_Type * res; + this->vtable->m35_Get_BIC_Sub_Data (this, __, bic_tag_good, n, (void **)&res); + res->AppearanceRatio = 0; + } + free (ratios_to_clear); + } +} + +PassBetweenValidity __fastcall +patch_Unit_can_pass_between (Unit * this, int edx, int from_x, int from_y, int to_x, int to_y, int param_5) +{ + PassBetweenValidity base = Unit_can_pass_between (this, __, from_x, from_y, to_x, to_y, param_5); + + if (is->current_config.enable_districts) { + Tile * to = tile_at (to_x, to_y); + bool to_valid = (to != NULL) && (to != p_null_tile); + struct district_instance * to_inst = NULL; + bool to_inst_complete = false; + if (to_valid) { + to_inst = get_district_instance (to); + if (to_inst != NULL) + to_inst_complete = district_is_complete (to, to_inst->district_id); + } + if (great_wall_blocks_civ (to, this->Body.CivID)) + return PBV_GENERIC_INVALID_MOVE; + if (to_valid) { + bool impassible = false; + bool impassible_to_wheeled = false; + if (get_tile_district_impassibility (to, &impassible, &impassible_to_wheeled)) { + if (impassible) + return PBV_GENERIC_INVALID_MOVE; + if (impassible_to_wheeled && Unit_has_ability (this, __, UTA_Wheeled)) { + Tile * from = tile_at (from_x, from_y); + bool connected_by_road = (from != NULL) && (to != NULL) && + (from->vtable->m25_Check_Roads (from, __, 0) != 0) && + (to->vtable->m25_Check_Roads (to, __, 0) != 0); + if (! connected_by_road) + return PBV_REQUIRES_ROAD; + } + } + } + + if (is->current_config.workers_can_enter_coast && + base != PBV_OK && is_worker(this)) { + Tile * source = tile_at (from_x, from_y); + if (source != NULL && + source->vtable->m35_Check_Is_Water (source) && + (source->vtable->m50_Get_Square_BaseType (source) == SQ_Coast)) + return PBV_OK; + + if (to_valid && + to->vtable->m35_Check_Is_Water (to) && + (to->vtable->m50_Get_Square_BaseType (to) == SQ_Coast)) { + bool is_human = (*p_human_player_bits & (1 << this->Body.CivID)) != 0; + + // If human, okay to enter coast tile + if (is_human) + return PBV_OK; + + struct district_worker_record * rec = get_tracked_worker_record (this); + struct pending_district_request * req = (rec != NULL) ? rec->pending_req : NULL; + if (req != NULL) + return PBV_OK; + } + } + + if (is->current_config.enable_bridge_districts && + base != PBV_OK && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == BRIDGE_DISTRICT_ID)) + return PBV_OK; + + if (is->current_config.enable_canal_districts && + base != PBV_OK && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Sea) && + (to_inst != NULL) && to_inst_complete && + (to_inst->district_id == CANAL_DISTRICT_ID)) + return PBV_OK; + } + + return base; +} + +Unit * __fastcall +patch_Unit_select_transport (Unit * this, int edx, int tile_x, int tile_y, bool do_show_popup) +{ + Unit * transport = Unit_select_transport (this, __, tile_x, tile_y, do_show_popup); + + if (is->current_config.enable_districts && + (transport == NULL) && (this == is->coast_walk_unit)) { + Tile * dest = tile_at (tile_x, tile_y); + if (dest != NULL) { + bool allow_move = false; + if (is->current_config.workers_can_enter_coast && is_worker (this) && + dest->vtable->m35_Check_Is_Water (dest) && + (dest->vtable->m50_Get_Square_BaseType (dest) == SQ_Coast)) + allow_move = true; + + if (! allow_move && is->current_config.enable_bridge_districts && + (p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class == UTC_Land)) { + struct district_instance * inst = get_district_instance (dest); + if (inst != NULL && inst->district_id == BRIDGE_DISTRICT_ID && + district_is_complete (dest, inst->district_id)) { + allow_move = true; + } + } + + if (allow_move) { + is->coast_walk_transport_override = true; + return this; // Fake a transport so the move logic proceeds + } + } + } + + return transport; +} + +// Returns true if the given tile is a water district owned by an enemy of the unit +bool +is_enemy_maritime_district_tile (Unit * unit, Tile * tile) +{ + if ((unit == NULL) || (tile == NULL) || (tile == p_null_tile)) + return false; + + if (! is->current_config.enable_districts) + return false; + + if (! tile->vtable->m35_Check_Is_Water (tile)) + return false; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return false; + + int owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner <= 0) || (owner == unit->Body.CivID)) + return false; + + Leader * leader = &leaders[unit->Body.CivID]; + return leader->At_War[owner]; +} + +// Boost pillage desirability for maritime districts +int __fastcall +patch_Unit_ai_eval_pillage_target (Unit * this, int edx, int tile_x, int tile_y) +{ + int base = Unit_ai_eval_pillage_target (this, __, tile_x, tile_y); + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if (is_enemy_maritime_district_tile (this, tile)) { + // Double the base score so districts outrank generic coast targets + base += base + 0x300; + } + + return base; +} + +// Light-weight hunt for nearby friendly ports; returns true if a path/command was issued +bool +try_path_to_friendly_port_district (Unit * unit, bool require_damaged, bool require_undefended) +{ + if ((unit == NULL) || + ! is->current_config.enable_districts || + ! is->current_config.enable_port_districts) + return false; + + if (unit->Body.Container_Unit >= 0) // Don't redirect cargo + return false; + + if (unit->Body.Moves <= 0) + return false; + + if (require_damaged && (unit->Body.Damage <= 0)) + return false; + + if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class != UTC_Sea) + return false; + + int sea_id = unit->vtable->get_sea_id (unit); + if (sea_id < 0) + return false; + + int best_x = -1, best_y = -1, best_path_len = INT_MAX; + const int search_radius = 10; + for (int dy = -search_radius; dy <= search_radius; dy++) { + for (int dx = -search_radius; dx <= search_radius; dx++) { + int tx = unit->Body.X + dx, ty = unit->Body.Y + dy; + wrap_tile_coords (&p_bic_data->Map, &tx, &ty); + + Tile * tile = tile_at (tx, ty); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + + if ((short)tile->vtable->m46_Get_ContinentID (tile) != sea_id) + continue; + + if (! tile_has_friendly_port_district (tile, unit->Body.CivID)) + continue; + + int occupier_id = get_tile_occupier_id (tx, ty, -1, true); + if ((occupier_id != -1) && (occupier_id != unit->Body.CivID)) + continue; + + if (require_undefended) { + bool has_friendly_sea_unit = false; + FOR_UNITS_ON (uti, tile) { + Unit * on_tile = uti.unit; + if ((on_tile == NULL) || (on_tile->Body.Container_Unit >= 0)) + continue; + if (on_tile->Body.CivID != unit->Body.CivID) + continue; + if (p_bic_data->UnitTypes[on_tile->Body.UnitTypeID].Unit_Class != UTC_Sea) + continue; + if (on_tile->Body.ID == unit->Body.ID) + continue; + has_friendly_sea_unit = true; + break; + } + if (has_friendly_sea_unit) + continue; + } + + if (! is_below_stack_limit (tile, unit->Body.CivID, UTC_Sea)) + continue; + + int path_len = 0; + int path_result = patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, + tx, ty, unit, unit->Body.CivID, 0x81, &path_len); + if (path_result <= 0) + continue; + + if (path_len < best_path_len) { + best_path_len = path_len; + best_x = tx; + best_y = ty; + } + } + } + + if (unit->Body.X == best_x && unit->Body.Y == best_y) { + Unit_set_escortee (unit, __, -1); + Unit_set_state (unit, __, UnitState_Fortifying); + return true; + } + else if (best_x >= 0) { + patch_Trade_Net_set_unit_path (is->trade_net, __, unit->Body.X, unit->Body.Y, best_x, best_y, + unit, unit->Body.CivID, 0x81, NULL); + Unit_set_escortee (unit, __, -1); + Unit_set_state (unit, __, UnitState_Go_To); + unit->Body.path_dest_x = best_x; + unit->Body.path_dest_y = best_y; + return true; + } + + return false; +} + +void __fastcall +patch_Unit_ai_move_naval_power_unit (Unit * this) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + ! is->current_config.naval_units_use_port_districts_not_cities) { + Unit_ai_move_naval_power_unit (this); + return; + } + + Tile * here = tile_at (this->Body.X, this->Body.Y); + if (here == NULL) { + Unit_ai_move_naval_power_unit (this); + return; + } + + // If we're on a port and the sole unit, fortify + if (is->current_config.ai_defends_districts && + tile_has_friendly_port_district (here, this->Body.CivID) && + count_units_at (this->Body.X, this->Body.Y, UF_0, this->Body.CivID, 0, -1) == 1) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If we're already sitting on an enemy maritime district, pillage it immediately + if (this->Body.Container_Unit < 0) { + if (is_enemy_maritime_district_tile (this, here) && + patch_Unit_can_pillage (this, __, this->Body.X, this->Body.Y) && + (patch_Unit_ai_eval_pillage_target (this, __, this->Body.X, this->Body.Y) > 0)) { + patch_Unit_attack_tile (this, __, this->Body.X, this->Body.Y, false); + return; + } + } + + // If damaged and CAN heal at current location (e.g. port district), fortify to heal + if (this->Body.Damage > 0 && patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If damaged and cannot heal here, try to path to a friendly port district + if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) + return; + + Unit_ai_move_naval_power_unit (this); + return; +} + +void __fastcall +patch_Unit_ai_move_naval_transport (Unit * this) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + ! is->current_config.naval_units_use_port_districts_not_cities) { + Unit_ai_move_naval_transport (this); + return; + } + + // If damaged and CAN heal at current location (e.g. port district), fortify to heal + if ((this->Body.Damage > 0) && + patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If damaged and cannot heal here, try to path to a friendly port district + if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) + return; + + Unit_ai_move_naval_transport (this); +} + +void __fastcall +patch_Unit_ai_move_naval_missile_transport (Unit * this) +{ + if (! is->current_config.enable_districts || + ! is->current_config.enable_port_districts || + ! is->current_config.naval_units_use_port_districts_not_cities) { + patch_Unit_ai_move_naval_missile_transport (this); + return; + } + + // If damaged and CAN heal at current location (e.g. port district), fortify to heal + if ((this->Body.Damage > 0) && + patch_Unit_can_heal_at (this, __, this->Body.X, this->Body.Y)) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + // If damaged and cannot heal here, try to path to a friendly port district + if ((this->Body.Damage > 0) && try_path_to_friendly_port_district (this, true, false)) + return; + + Unit_ai_move_naval_missile_transport (this); +} + +void __fastcall +patch_Unit_ai_move_air_bombard_unit (Unit * this) +{ + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) { + Unit_ai_move_air_bombard_unit (this); + return; + } + + if (this->Body.Damage > 0) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + int best_target = 0; + int target_x = -1, target_y = -1; + int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + int grid = op_range * 2 + 1; + if (1 < grid * grid) { + for (int n = 1; n < grid * grid; n++) { + int dx, dy; + neighbor_index_to_diff (n, &dx, &dy); + int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); + int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); + if (Map_in_range (&p_bic_data->Map, __, x, y)) { + int score = Unit_ai_eval_bombard_target (this, __, x, y, 1); + if (score > best_target) { + best_target = score; + target_x = x; + target_y = y; + } + } + } + } + + int best_base_score = 0x7fffffff; + int base_x = -1, base_y = -1; + FOR_AERODROMES_AROUND (this) { + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) + continue; + + int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 6, -1, -1); + int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); + int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); + int score = (count * 10) + ((x_dist + y_dist) >> 1); + if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) + score -= 20; + + if (score < best_base_score) { + best_base_score = score; + base_x = aerodrome_x; + base_y = aerodrome_y; + } + } + + if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { + Unit_set_escortee (this, __, -1); + Unit_rebase (this, __, base_x, base_y); + return; + } + + if ((target_x >= 0) && (target_y >= 0)) { + Unit_set_escortee (this, __, -1); + patch_Unit_bombard_tile (this, __, target_x, target_y); + return; + } + + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +void __fastcall +patch_Unit_ai_move_air_defense_unit (Unit * this) +{ + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) { + Unit_ai_move_air_defense_unit (this); + return; + } + + Unit_ai_move_air_defense_unit (this); + + Unit_set_state (this, __, 0); + if (this->Body.Damage > 0) { + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); + return; + } + + int best_base_score = 0x7fffffff; + int base_x = -1, base_y = -1; + FOR_AERODROMES_AROUND (this) { + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) + continue; + + int count = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 7, -1, -1); + int x_dist = Map_get_x_dist (&p_bic_data->Map, __, aerodrome_x, this->Body.X); + int y_dist = Map_get_y_dist (&p_bic_data->Map, __, aerodrome_y, this->Body.Y); + int score = (count * 10) + ((x_dist + y_dist) >> 1); + if ((this->Body.X == aerodrome_x) && (this->Body.Y == aerodrome_y)) + score -= 20; + + if (score < best_base_score) { + best_base_score = score; + base_x = aerodrome_x; + base_y = aerodrome_y; + } + } + + if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { + Unit_set_escortee (this, __, -1); + Unit_rebase (this, __, base_x, base_y); + return; + } + + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Intercept); +} + +void __fastcall +patch_Unit_ai_move_air_transport (Unit * this) +{ + if (! (is->current_config.enable_districts && + is->current_config.enable_aerodrome_districts && + is->current_config.air_units_use_aerodrome_districts_not_cities)) { + Unit_ai_move_air_transport (this); + return; + } + + Unit_ai_move_air_transport (this); + + if (this->Body.Damage < 1) { + if (Unit_can_airdrop (this)) { + int best_score = 0; + int best_x = -1, best_y = -1; + int op_range = p_bic_data->UnitTypes[this->Body.UnitTypeID].OperationalRange; + int grid = op_range * 2 + 1; + if (1 < grid * grid) { + for (int n = 1; n < grid * grid; n++) { + int dx, dy; + neighbor_index_to_diff (n, &dx, &dy); + int x = Map_wrap_horiz (&p_bic_data->Map, __, this->Body.X + dx); + int y = Map_wrap_vert (&p_bic_data->Map, __, this->Body.Y + dy); + if (Map_in_range (&p_bic_data->Map, __, x, y)) { + int score = Unit_ai_eval_airdrop_target (this, __, x, y); + if (score > best_score) { + best_score = score; + best_x = x; + best_y = y; + } + } + } + if ((best_x >= 0) && (best_y >= 0)) { + Unit_set_escortee (this, __, -1); + Unit_airdrop (this, __, best_x, best_y); + return; + } + } + } + + int best_score = -1; + int base_x = -1, base_y = -1; + FOR_AERODROMES_AROUND (this) { + if (! is_below_stack_limit (aerodrome_tile, this->Body.CivID, + p_bic_data->UnitTypes[this->Body.UnitTypeID].Unit_Class)) + continue; + + int score = count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 0, -1, -1) + + count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 1, -1, -1) + 1; + if (count_units_at (aerodrome_x, aerodrome_y, UF_AI_STRAT_A_VIS_TO_B, 9, -1, -1) == 0) + score *= 2; + int cont_id = aerodrome_tile->vtable->m46_Get_ContinentID (aerodrome_tile); + if ((cont_id >= 0) && (cont_id < p_bic_data->Map.Continent_Count) && + (p_bic_data->Map.Continents[cont_id].Body.TileCount > 0x15)) + score *= 2; + + if (score > best_score) { + best_score = score; + base_x = aerodrome_x; + base_y = aerodrome_y; + } + } + + if ((base_x >= 0) && (base_y >= 0) && ((this->Body.X != base_x) || (this->Body.Y != base_y))) { + Unit_set_escortee (this, __, -1); + Unit_rebase (this, __, base_x, base_y); + if (Unit_count_contained_units (this) > 0) { + patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); + } + return; + } + } + + if (Unit_count_contained_units (this) > 0) + patch_Unit_disembark_passengers (this, __, this->Body.X, this->Body.Y); + + Unit_set_escortee (this, __, -1); + Unit_set_state (this, __, UnitState_Fortifying); +} + +bool __fastcall +patch_Tile_has_colony_ignore_extraterritorial (Tile * tile) +{ + if (!Tile_has_colony (tile)) + return false; + + if (!is->current_config.allow_extraterritorial_colonies) + return true; + + if ((tile == NULL) || (tile == p_null_tile)) + return true; + + int tile_building_id = tile->vtable->m47_Get_Tile_BuildingID (tile); + if ((tile_building_id < 0) || (p_colonies == NULL) || (p_colonies->Items == NULL) || + (tile_building_id > p_colonies->LastIndex)) + return true; + + Tile_Building_Body * colony_body = p_colonies->Items[tile_building_id].Object; + if ((colony_body == NULL) || ((int)colony_body == offsetof (Tile_Building, Body))) + return true; + + return colony_body->OwnerID == tile->vtable->m38_Get_Territory_OwnerID (tile); +} + +int __fastcall +patch_Leader_get_attitude_toward (Leader * this, int edx, int civ_id, int param_2) +{ + int score = Leader_get_attitude_toward (this, __, civ_id, param_2); + if (!is->current_config.allow_extraterritorial_colonies) + return score; + + int penalty = is->current_config.per_extraterritorial_colony_relation_penalty; + if (penalty != 0) { + int this_civ_id = this->ID; + if ((p_colonies != NULL) && (p_colonies->Items != NULL)) { + for (int n = 0; n <= p_colonies->LastIndex; n++) { + Tile_Building_Body * colony_body = p_colonies->Items[n].Object; + if ((colony_body == NULL) || + ((int)colony_body == offsetof (Tile_Building, Body))) + continue; + + Tile * tile = tile_at (colony_body->X, colony_body->Y); + if ((tile == NULL) || (tile == p_null_tile)) + continue; + if (tile->vtable->m38_Get_Territory_OwnerID (tile) != this_civ_id) + continue; + if (colony_body->OwnerID != civ_id) + continue; + score -= penalty; + } + } + } + return score; +} + +void __fastcall +patch_UnitIDList_insert_after_init (UnitIDList * this, int edx, int id, UnitIDItem * item) +{ + // If using non-standard unit cycling, avoid calling this method b/c it sometimes causes a crash + if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) + UnitIDList_insert_after (this, __, id, item); +} + +bool __fastcall +patch_Tile_m17_Check_Irrigation (Tile * this, int edx, int visible_to_civ_id) +{ + bool base = Tile_m17_Check_Irrigation (this, __, visible_to_civ_id); + if (base) + return true; + + if (! is->current_config.enable_districts) + return base; + + struct district_instance * inst = get_district_instance (this); + if (inst == NULL) + return base; + + if (is->district_configs[inst->district_id].allow_irrigation_from && district_is_complete (this, inst->district_id)) + return true; + + return base; +} + +int __fastcall +patch_Unit_ai_eval_bombard_target (Unit * this, int edx, int tile_x, int tile_y, int param_3) +{ + int score = Unit_ai_eval_bombard_target (this, __, tile_x, tile_y, param_3); + + if (! (is->current_config.enable_districts && + is->current_config.enable_great_wall_districts)) + return score; + + Tile * tile = tile_at (tile_x, tile_y); + if ((tile == NULL) || (tile == p_null_tile)) + return score; + + struct district_instance * inst = get_district_instance (tile); + if ((inst == NULL) || (inst->district_id != GREAT_WALL_DISTRICT_ID) || (! district_is_complete (tile, GREAT_WALL_DISTRICT_ID))) + return score; + + int obsolete_id = is->district_infos[GREAT_WALL_DISTRICT_ID].obsoleted_by_id; + if ((obsolete_id >= 0) && Leader_has_tech (&leaders[this->Body.CivID], __, obsolete_id)) + return score; + + int owner_id = tile->vtable->m38_Get_Territory_OwnerID (tile); + if ((owner_id <= 0) || (owner_id == this->Body.CivID)) + return score; + if (! this->vtable->is_enemy_of_civ (this, __, owner_id, false)) + return score; + + bool has_unit_on_tile = false; + bool has_enemy_on_tile = false; + Leader * me = &leaders[this->Body.CivID]; + FOR_UNITS_ON (uti, tile) { + UnitType const * unit_type = &p_bic_data->UnitTypes[uti.unit->Body.UnitTypeID]; + if (patch_Unit_is_visible_to_civ (uti.unit, __, me->ID, 0)) { + has_unit_on_tile = true; + if (me->At_War[uti.unit->Body.CivID]) { + if ((unit_type->Defence > 0) || (unit_type->Attack > 0)) { + has_enemy_on_tile = true; + break; + } + } else + break; + } + } + + if (has_unit_on_tile && ! has_enemy_on_tile) + return score; + + // Boost score to prioritize Great Wall targets + if (score < 0x6000) + score = 0x6000; + + // Additional boost if there is no unit on it, more likely to destroy it + if (! has_enemy_on_tile) + score += 0x200; + + return score; +} + +void __fastcall +patch_Unit_heal_at_start_of_turn (Unit * this) +{ + if (is->current_config.enable_districts) { + Tile * tile = tile_at ((this->Body).X, (this->Body).Y); + if ((tile != NULL) && (tile != p_null_tile)) { + struct district_instance * inst = get_district_instance (tile); + if (inst != NULL && district_is_complete (tile, inst->district_id) && + is->district_configs[inst->district_id].heal_units_in_one_turn) { + int territory_owner = tile->vtable->m38_Get_Territory_OwnerID (tile); + if (territory_owner == this->Body.CivID) { + (this->Body).Damage = 0; + return; + } + } + } + } + + Unit_heal_at_start_of_turn (this); +} + +// Makes naval AI treat enemy port districts as valid targets to path toward. +int __cdecl +patch_get_tile_occupier_id_in_Unit_ai_move_naval_power_unit (int x, int y, int pov_civ_id, bool respect_unit_invisibility) +{ + int base = get_tile_occupier_id (x, y, pov_civ_id, respect_unit_invisibility); + if (base != -1) + return base; + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return -1; + + Tile * tile = tile_at (x, y); + if (tile == NULL || tile == p_null_tile) + return -1; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return -1; + + return (*tile->vtable->m38_Get_Territory_OwnerID) (tile); +} + +// Returns a non-zero score for enemy port district tiles so they pass the threshold check and are bombard targets +int __fastcall +patch_Fighter_eval_tile_vulnerability_in_Unit_ai_move_naval_power_unit (Fighter * this, int edx, Unit * unit, int tile_x, int tile_y) +{ + int base = Fighter_eval_tile_vulnerability (this, __, unit, tile_x, tile_y); + if (base > 0) + return base; + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if (tile == NULL || tile == p_null_tile) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return base; + + int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); + if (owner <= 0 || owner == unit->Body.CivID) + return base; + + if (! leaders[unit->Body.CivID].At_War[owner]) + return base; + + // Return a score high enough to pass threshold (iVar13 * 8 + 0x100) + // 0x300 should be sufficient for most cases + return 0x300; +} + +// Returns the territory owner for enemy port districts so the score isn't reduced and naval units move to enemy ports +// (to subsequently pillage them) +int __cdecl +patch_get_combat_occupier_in_Unit_ai_move_naval_power_unit (int tile_x, int tile_y, int civ_id, byte ignore_visibility) +{ + int base = get_combat_occupier (tile_x, tile_y, civ_id, ignore_visibility); + if (base != -1) + return base; + + if (! is->current_config.enable_districts || ! is->current_config.enable_port_districts) + return base; + + Tile * tile = tile_at (tile_x, tile_y); + if (tile == NULL || tile == p_null_tile) + return base; + + struct district_instance * inst = get_district_instance (tile); + if (inst == NULL) + return base; + + int owner = (*tile->vtable->m38_Get_Territory_OwnerID) (tile); + if (owner <= 0 || owner == civ_id) + return base; + + if (! leaders[civ_id].At_War[owner]) + return base; + + return owner; +} + +int __fastcall +patch_rand_int_to_enslave (void * this, int edx, int lim) +{ + // lim is 100, enslaving happens if the return value is < 33 + int r = rand_int (this, __, lim); + return is->do_not_enslave_units ? 100 : r; +} + +int __fastcall +patch_Sprite_draw_espionage_screen_target_civ_bkg (Sprite * this, int edx, PCX_Image * canvas, int pixel_x, int pixel_y, PCX_Color_Table * color_table) +{ + // Figure out which of the potential target civs we're drawing by working backwards from the Y location + int top = (p_bic_data->ScreenHeight - p_espionage_form->Image.Height) / 2; + is->espionage_form_drawing_target_index = (pixel_y - top - 0x5C) / 0x3a + p_espionage_form->field_1584; + + return Sprite_draw (this, __, canvas, pixel_x, pixel_y, color_table); +} + +char * __fastcall +patch_Civilopedia_Article_get_name_for_esp_screen (Civilopedia_Article * this) +{ + // Ensure that we have captured a valid civ ID being drawn then, if that civ has an era-specific formal name, return that so that the + // era-specific names apply on the espionage screen. + int target_civ_id; + if (is->espionage_form_drawing_target_index >= 0 && + is->espionage_form_drawing_target_index < p_espionage_form->target_civ_id_count && + (target_civ_id = p_espionage_form->target_civ_ids[is->espionage_form_drawing_target_index]) >= 0 && + target_civ_id < 32 && + is->aliased_civ_formal_name_bits & 1<Name.S; +} + +void __fastcall +patch_Animator_play_one_shot_victory_animation (Animator * this, int edx, Unit * unit, AnimationType anim_type, bool param_3) +{ + if (p_bic_data->UnitTypes[unit->Body.UnitTypeID].Unit_Class == UTC_Air && is->current_config.aircraft_victory_animation != NULL) { + struct string_slice slice = {.str = is->current_config.aircraft_victory_animation, .len = strlen (is->current_config.aircraft_victory_animation)}; + find_animation_type_by_name (&slice, true, &anim_type); + } + + Animator_play_one_shot_unit_animation (this, __, unit, anim_type, param_3); +} + +void +clear_selectable_units_list (Main_Screen_Form * main_screen_form, bool include_unit_objects) +{ + // This is what the base game does to clear things at the start of assemble_selectable_units + if (include_unit_objects && p_units->Units != NULL) + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if (unit != NULL) + unit->Body.in_selectable_units_list = false; + } + UnitIDItem * item = main_screen_form->selectable_units.first; + while (item != NULL) { + UnitIDItem * next = item->next; + item->vtable->destruct (item, __, 1); + item = next; + } + main_screen_form->selectable_units.first = main_screen_form->selectable_units.last = NULL; + main_screen_form->selectable_units.length = 0; +} + +void __fastcall +patch_Main_Screen_Form_assemble_selectable_units (Main_Screen_Form * this) +{ + if (is->have_loaded_waiting_units) + is->have_loaded_waiting_units = false; + else + table_deinit (&is->waiting_units); + + if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) + Main_Screen_Form_assemble_selectable_units (this); + else { + clear_selectable_units_list (this, true); + this->unit_cycle_cursor = NULL; + this->completed_unit_cycle = false; + } +} + +void __fastcall +patch_Main_Screen_Form_set_selected_unit (Main_Screen_Form * this, int edx, Unit * unit, bool param_2) +{ + // To set a unit to wait, Main_Screen_Form::issue_command calls this method with unit == NULL and param_2 == false. Detect when that's + // happened and record that the unit's been set to wait so we can reimplement the wait command when replacing the base unit cycling logic. + int * p_stack = (int *)&unit; + int ret_addr = p_stack[-1]; + if (ret_addr == SET_SELECTED_UNIT_TO_ISSUE_WAIT_COMMAND_RET && unit == NULL && this->Current_Unit != NULL) { + // Give the unit a waiting level higher than the minimum among all units already set to wait. This ensures that this unit does not get + // immediately picked up again by the cycling logic unless it's the only selectable unit left. This also means that the first unit set + // to wait will be the first cycled to once all the non-waiting units have been moved (it's the only one at level 1). I consider that + // an advantage. + int min_others_waiting_level = INT_MAX; + bool any_others_waiting = false; + FOR_TABLE_ENTRIES (tei, &is->waiting_units) + if (tei.key != this->Current_Unit->Body.ID) { + any_others_waiting = true; + if (tei.value < min_others_waiting_level) + min_others_waiting_level = tei.value; + } + itable_insert (&is->waiting_units, this->Current_Unit->Body.ID, any_others_waiting ? min_others_waiting_level + 1 : 1); + } + + if (unit != NULL) { + is->last_selected_unit.initial_x = is->last_selected_unit.last_x = unit->Body.X; + is->last_selected_unit.initial_y = is->last_selected_unit.last_y = unit->Body.Y; + is->last_selected_unit.type_id = unit->Body.UnitTypeID; + is->last_selected_unit.ptr = unit; + itable_remove (&is->waiting_units, unit->Body.ID); // Clear waiting record when waiting unit is selected + } + + if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD) + clear_selectable_units_list (this, false); + + bool redraw = false; + if (is->current_config.show_ai_city_location_desirability_if_settler) { + int new_perspective = -1; + if (unit != NULL) { + int unit_type_id = unit->Body.UnitTypeID; + int worker_actions = p_bic_data->UnitTypes[unit_type_id].Worker_Actions; + new_perspective = (worker_actions >= 1 && (worker_actions & (UCV_Build_City)) && !is_worker(unit)) ? p_main_screen_form->Player_CivID : -1; + } + + if (new_perspective != is->city_loc_display_perspective) { + is->city_loc_display_perspective = new_perspective; + redraw = true; + } + } + + Main_Screen_Form_set_selected_unit (this, __, unit, param_2); + + // If selecting a new unit, must insert it into the list to ensure it's actually selected. + if (is->current_config.unit_cycle_search_criteria != UCSC_STANDARD && unit != NULL) { + UnitIDList_insert_before (&this->selectable_units, __, unit->Body.ID, NULL); + this->unit_cycle_cursor = this->selectable_units.first; + } + + if (redraw && ! this->is_now_loading_game) + p_main_screen_form->vtable->m73_call_m22_Draw ((Base_Form *)p_main_screen_form); +} + +Unit * __fastcall +patch_Main_Screen_Form_find_next_unit_for_cycling (Main_Screen_Form * this) +{ + if (is->current_config.unit_cycle_search_criteria == UCSC_STANDARD) + return Main_Screen_Form_find_next_unit_for_cycling (this); + + else { + int least_difference = INT_MAX; + Unit * least_different_unit = NULL; + int sx = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_x : is->last_selected_unit.last_x, + sy = is->current_config.unit_cycle_search_criteria == UCSC_SIMILAR_NEAR_START ? is->last_selected_unit.initial_y : is->last_selected_unit.last_y; + for (int n = 0; n <= p_units->LastIndex; n++) { + Unit * unit = get_unit_ptr (n); + if (unit != NULL && unit->Body.CivID == this->Player_CivID && Unit_can_cycle_to (unit)) { + int distance = not_above (1<<15, int_abs (unit->Body.X - sx) + int_abs (unit->Body.Y - sy)); + + bool other_type, not_duplicate; { + if (is->last_selected_unit.type_id == unit->Body.UnitTypeID) { + other_type = false; + if (is->last_selected_unit.ptr != NULL) + not_duplicate = ! are_units_duplicate (&is->last_selected_unit.ptr->Body, &unit->Body, false); + else + not_duplicate = true; + } else + other_type = not_duplicate = true; + } + + int wait_level = itable_look_up_or (&is->waiting_units, unit->Body.ID, 0); + + int difference = ((int)wait_level << 20) + (distance << 2) + ((int)other_type << 1) + (int)not_duplicate; + if (difference < least_difference) { + least_difference = difference; + least_different_unit = unit; + } + } + } + this->completed_unit_cycle = least_different_unit == NULL; + return least_different_unit; + } +} + +void __fastcall +patch_City_m22 (City * this, int edx, bool param_1) +{ + int * p_stack = (int *)¶m_1; + int ret_addr = p_stack[-1]; + + City_m22 (this, __, param_1); + + // If the base game method failed to find a new thing for city to build, we've been called by the methods that complete a previous build, and + // the city is owned by the UI controller, the game will crash because there will be no default option for the build selector popup. If we're + // configured to fix that, suggest Wealth for the new build or, failing that, any buildable unit or improvement. + if ( this->Body.Order_Type == 0 + && is->current_config.patch_failure_to_find_new_city_build + && this->Body.CivID == p_main_screen_form->Player_CivID + && ( ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_1 + || ret_addr == CITY_M22_TO_ADD_BUILDING_IF_DONE_RETURN_2 + || ret_addr == CITY_M22_TO_SPAWN_UNIT_IF_DONE_RETURN)) { + + // Search for an improvement-type order we can build. Choose Wealth if possible, otherwise just pick the first thing that can be built + for (int n = 0; n < p_bic_data->ImprovementsCount; n++) + if (patch_City_can_build_improvement (this, __, n, true)) { + if (p_bic_data->Improvements[n].ImprovementFlags & ITF_Capitalization) { + this->Body.Order_Type = COT_Improvement; + this->Body.Order_ID = n; + break; + } else if (this->Body.Order_Type == 0) { + this->Body.Order_Type = COT_Improvement; + this->Body.Order_ID = n; + } + } + + // If we still don't have a build, pick the first buildable unit + if (this->Body.Order_Type == 0) + for (int n = 0; n < p_bic_data->UnitTypeCount; n++) + if (patch_City_can_build_unit (this, __, n, true, 0, false)) { + this->Body.Order_Type = COT_Unit; + this->Body.Order_ID = n; + break; + } + } +} + +int __fastcall +patch_PCX_Image_process_dom_adv_turn_count_text (PCX_Image * this, int edx, char * str) +{ + if (is->current_config.reformat_turns_remaining_on_domestic_advisor_screen) { + char * start = strstr (str, p_advisor_internal_form->Labels[16].S); // Search for "turns" + if (start == NULL) + start = strstr (str, p_advisor_internal_form->Labels[17].S); // Search for "turn" + + if (start != NULL) { + *start = toupper (*start); // Upcase first letter of "turn/s" + + char s[64]; // Must be same size as "str" param, which is a 64-byte stack-allocated string + snprintf (s, sizeof s, "%.*s %s", start - str, str, start); // Reprint string with space before "Turn/s" + s[(sizeof s) - 1] = '\0'; + memcpy (str, s, sizeof s); + } + } + + return PCX_Image_process_text (this, __, str); +} + +int +compare_menu_unit_items (void const * a, void const * b) +{ + return MenuUnitItem_should_appear_after ((MenuUnitItem *)a, __, (MenuUnitItem *)b) ? 1 : -1; +} + +int __fastcall +patch_MenuUnitList_get_length_before_sorting (MenuUnitList * this) +{ + int length = MenuUnitList_get_length (this); + + if (is->current_config.patch_passengers_out_of_order_on_menu && length > 0) { + qsort (this->items, length, sizeof this->items[0], compare_menu_unit_items); + + // Fix any units not being listed immediately after the unit they're contained in + // First, loop over all units in the list, stopping at each that might contain others + for (int n = 0; n < length - 1; n++) { + Unit * container = this->items[n].unit; + if ((int)container > 1 && // original code checks if unit ptrs are NULL or equal to 1 + p_bic_data->UnitTypes[container->Body.UnitTypeID].Transport_Capacity > 0) { + + // Advance iterator "j" past the container and past any empty slots or correctly positioned units right after it + int j = n + 1; + while (j < length && ((int)this->items[j].unit <= 1 || this->items[j].unit->Body.Container_Unit == container->Body.ID)) + j++; + + // Check the rest of the list for out-of-place passengers + for (int k = j + 1; k < length; k++) { + if ((int)this->items[k].unit > 1 && this->items[k].unit->Body.Container_Unit == container->Body.ID) { + + // Move item from index "k" to index "j" and advance "j" past it + MenuUnitItem moved = this->items[k]; + memmove (&this->items[j + 1], &this->items[j], (k - j) * sizeof this->items[0]); + this->items[j] = moved; + j++; + } + } + } + } + + // The caller is checking if the length is > 0 before sorting the list. Since we've already sorted it, return 0. + return 0; + } else + return length; +} + +void __fastcall +patch_Map_finalize_params_for_scenario_map (Map * this) +{ + Map_finalize_params (this); + + enum barbarian_activity_override barb_override = is->current_config.override_barbarian_activity_level_for_scenario_maps; + if (barb_override != BAO_NONE) { + if (barb_override == BAO_RANDOM) { + LARGE_INTEGER time; + QueryPerformanceCounter (&time); + int r = this->Seed ^ time.u.LowPart; // The map seed will be the same every time so incorporate some entropy + this->World.Final_Barbarians_Activity = rand_int (&r, __, 5) - 1; + } else + this->World.Final_Barbarians_Activity = clamp (-1, 3, barb_override); + } +} + +Unit * __fastcall +patch_Unit_select_army_member_for_combat (Unit * this, int edx, int param_1, char param_2) +{ + if (is->current_config.patch_empty_army_combat_crash) { + int unit_count = 0; + Tile * tile = tile_at (this->Body.X, this->Body.Y); + if (tile != NULL && tile != p_null_tile) { + FOR_UNITS_ON (uti, tile) { + Unit * unit = uti.unit; + if ((unit != NULL) && (unit->Body.Container_Unit == this->Body.ID)) + unit_count += Unit_count_contained_units (unit) + 1; + } + } + if (unit_count == 0) + return this; + } + + return Unit_select_army_member_for_combat (this, __, param_1, param_2); +} + +int __fastcall +patch_Tile_check_water_for_canal_move_to_adjacent_tile_dest (Tile * this) +{ + if ((this != NULL) && (this != p_null_tile) && + is->current_config.enable_districts && + is->current_config.enable_canal_districts && + (is->coast_walk_unit != NULL) && + (p_bic_data->UnitTypes[is->coast_walk_unit->Body.UnitTypeID].Unit_Class == UTC_Sea)) { + struct district_instance * inst = get_district_instance (this); + if ((inst != NULL) && + (inst->district_id == CANAL_DISTRICT_ID) && + district_is_complete (this, inst->district_id)) + return 1; + } + + return this->vtable->m35_Check_Is_Water (this); +} + +// TCC requires a main function be defined even though it's never used. +int main () { return 0; } diff --git a/lend/README.md b/lend/README.md index bf970936..6b7e24b5 100644 --- a/lend/README.md +++ b/lend/README.md @@ -1,31 +1,31 @@ -lend -==== - -Tiny x86 Length Disassembler - -The inspiration for the design of this x86 length disassembler came from -Zdisasm by Z0MBiE (I can't actually find this on his page but it's around, -just google code search for zdisasm.h) and three ideas presented nicely in a -single forum thread: - -http://www.devmaster.net/forums/showthread.php?t=2311 - -The three ideas came from the following posts: - -1. The original post by Nick (a purely logical length disassembler) -2. The post by earlnsk (a Russian switch case length disassembler) - The Russian length disassembler can be found here: - http://hack-expo.void.ru/groups/blt/text/disasm.txt (Russian) - http://z0mbie.daemonlab.org/disasme.txt (English) -3. The post by WolfgangSt (bitmap lookup tables) - -With these ideas I decided to make a tiny length disassemler in c. - -My length disassembler can use logical statements or lookup tables (32 byte -bitmap tables) to perform the checks required to determine instruction length. -Currently the smallest footprint I have managed is 589 bytes (LengthDisasm -function length + 4x32 byte lookup tables). I'm sure there are further -optimizations possible (even without using assembly). - -I haven't looked into it too much but I don't think it would to too difficult -to adapt this approach for x86_64. +lend +==== + +Tiny x86 Length Disassembler + +The inspiration for the design of this x86 length disassembler came from +Zdisasm by Z0MBiE (I can't actually find this on his page but it's around, +just google code search for zdisasm.h) and three ideas presented nicely in a +single forum thread: + +http://www.devmaster.net/forums/showthread.php?t=2311 + +The three ideas came from the following posts: + +1. The original post by Nick (a purely logical length disassembler) +2. The post by earlnsk (a Russian switch case length disassembler) + The Russian length disassembler can be found here: + http://hack-expo.void.ru/groups/blt/text/disasm.txt (Russian) + http://z0mbie.daemonlab.org/disasme.txt (English) +3. The post by WolfgangSt (bitmap lookup tables) + +With these ideas I decided to make a tiny length disassemler in c. + +My length disassembler can use logical statements or lookup tables (32 byte +bitmap tables) to perform the checks required to determine instruction length. +Currently the smallest footprint I have managed is 589 bytes (LengthDisasm +function length + 4x32 byte lookup tables). I'm sure there are further +optimizations possible (even without using assembly). + +I haven't looked into it too much but I don't think it would to too difficult +to adapt this approach for x86_64. diff --git a/lend/ld32.c b/lend/ld32.c index 50885525..bd21689e 100644 --- a/lend/ld32.c +++ b/lend/ld32.c @@ -1,80 +1,80 @@ -/* -x86 Length Disassembler. -Copyright (C) 2013 Byron Platt - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "ld32.h" - -/* length_disasm */ -unsigned int length_disasm(void * opcode0) { - - unsigned char* opcode = opcode0; - - unsigned int flag = 0; - unsigned int ddef = 4, mdef = 4; - unsigned int msize = 0, dsize = 0; - - unsigned char op, modrm, mod, rm; - -prefix: - op = *opcode++; - - /* prefix */ - if (CHECK_PREFIX(op)) { - if (CHECK_PREFIX_66(op)) ddef = 2; - else if (CHECK_PREFIX_67(op)) mdef = 2; - goto prefix; - } - - /* two byte opcode */ - if (CHECK_0F(op)) { - op = *opcode++; - if (CHECK_MODRM2(op)) flag++; - if (CHECK_DATA12(op)) dsize++; - if (CHECK_DATA662(op)) dsize += ddef; - } - - /* one byte opcode */ - else { - if (CHECK_MODRM(op)) flag++; - if (CHECK_TEST(op) && !(*opcode & 0x38)) dsize += (op & 1) ? ddef : 1; - if (CHECK_DATA1(op)) dsize++; - if (CHECK_DATA2(op)) dsize += 2; - if (CHECK_DATA66(op)) dsize += ddef; - if (CHECK_MEM67(op)) msize += mdef; - } - - /* modrm */ - if (flag) { - modrm = *opcode++; - mod = modrm & 0xc0; - rm = modrm & 0x07; - if (mod != 0xc0) { - if (mod == 0x40) msize++; - if (mod == 0x80) msize += mdef; - if (mdef == 2) { - if ((mod == 0x00) && (rm == 0x06)) msize += 2; - } else { - if (rm == 0x04) rm = *opcode++ & 0x07; - if (rm == 0x05 && mod == 0x00) msize += 4; - } - } - } - - opcode += msize + dsize; - - return opcode - (unsigned char *)opcode0; -} +/* +x86 Length Disassembler. +Copyright (C) 2013 Byron Platt + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "ld32.h" + +/* length_disasm */ +unsigned int length_disasm(void * opcode0) { + + unsigned char* opcode = opcode0; + + unsigned int flag = 0; + unsigned int ddef = 4, mdef = 4; + unsigned int msize = 0, dsize = 0; + + unsigned char op, modrm, mod, rm; + +prefix: + op = *opcode++; + + /* prefix */ + if (CHECK_PREFIX(op)) { + if (CHECK_PREFIX_66(op)) ddef = 2; + else if (CHECK_PREFIX_67(op)) mdef = 2; + goto prefix; + } + + /* two byte opcode */ + if (CHECK_0F(op)) { + op = *opcode++; + if (CHECK_MODRM2(op)) flag++; + if (CHECK_DATA12(op)) dsize++; + if (CHECK_DATA662(op)) dsize += ddef; + } + + /* one byte opcode */ + else { + if (CHECK_MODRM(op)) flag++; + if (CHECK_TEST(op) && !(*opcode & 0x38)) dsize += (op & 1) ? ddef : 1; + if (CHECK_DATA1(op)) dsize++; + if (CHECK_DATA2(op)) dsize += 2; + if (CHECK_DATA66(op)) dsize += ddef; + if (CHECK_MEM67(op)) msize += mdef; + } + + /* modrm */ + if (flag) { + modrm = *opcode++; + mod = modrm & 0xc0; + rm = modrm & 0x07; + if (mod != 0xc0) { + if (mod == 0x40) msize++; + if (mod == 0x80) msize += mdef; + if (mdef == 2) { + if ((mod == 0x00) && (rm == 0x06)) msize += 2; + } else { + if (rm == 0x04) rm = *opcode++ & 0x07; + if (rm == 0x05 && mod == 0x00) msize += 4; + } + } + } + + opcode += msize + dsize; + + return opcode - (unsigned char *)opcode0; +} diff --git a/lend/ld32.h b/lend/ld32.h index c29434e3..ac19a8bd 100644 --- a/lend/ld32.h +++ b/lend/ld32.h @@ -1,254 +1,254 @@ -/* -x86 Length Disassembler. -Copyright (C) 2013 Byron Platt - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#ifndef __LD32_H__ -#define __LD32_H__ - -/* implemented tables */ -#define PREFIX_T 1 -#define MODRM2_T 2 -#define MODRM_T 4 -#define DATA1_T 8 -#define DATA2_T 16 -#define DATA66_T 32 - -/* configure tables */ -#ifndef USE_T -#define USE_T (MODRM2_T|MODRM_T|DATA1_T|DATA66_T) -#endif - -/* length_disasm */ -unsigned int length_disasm(void* opcode0); - -/* table macros */ -#ifdef USE_T -#define BITMASK32( \ - b00,b01,b02,b03,b04,b05,b06,b07, \ - b08,b09,b0a,b0b,b0c,b0d,b0e,b0f, \ - b10,b11,b12,b13,b14,b15,b16,b17, \ - b18,b19,b1a,b1b,b1c,b1d,b1e,b1f \ -) ( \ - (b00<<0x00)|(b01<<0x01)|(b02<<0x02)|(b03<<0x03)| \ - (b04<<0x04)|(b05<<0x05)|(b06<<0x06)|(b07<<0x07)| \ - (b08<<0x08)|(b09<<0x09)|(b0a<<0x0a)|(b0b<<0x0b)| \ - (b0c<<0x0c)|(b0d<<0x0d)|(b0e<<0x0e)|(b0f<<0x0f)| \ - (b10<<0x10)|(b11<<0x11)|(b12<<0x12)|(b13<<0x13)| \ - (b14<<0x14)|(b15<<0x15)|(b16<<0x16)|(b17<<0x17)| \ - (b18<<0x18)|(b19<<0x19)|(b1a<<0x1a)|(b1b<<0x1b)| \ - (b1c<<0x1c)|(b1d<<0x1d)|(b1e<<0x1e)|(b1f<<0x1f) \ -) -#define CHECK_TABLE(t, v) ((t[(v)>>5]>>((v)&0x1f))&1) -#endif - -/* CHECK_PREFIX */ -#if defined(USE_T) && (USE_T & PREFIX_T) -const static unsigned int prefix_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ - BITMASK32(0,0,0,0,0,0,1,0, 0,0,0,0,0,0,1,0, /* 2 */ - 0,0,0,0,0,0,1,0, 0,0,0,0,0,0,1,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,0,0,1,1,1,1, 0,0,0,0,0,0,0,0, /* 6 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* c */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ - 1,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ -}; -#define CHECK_PREFIX(v) CHECK_TABLE(prefix_t, v) -#else -#define CHECK_PREFIX(v) \ - (((v)&0xe7)==0x26||((v)&0xfc)==0x64||(v)==0xf0||(v)==0xf2||(v)==0xf3) -#endif - -/* CHECK_PREFIX_66 */ -#define CHECK_PREFIX_66(v) ((v)==0x66) - -/* CHECK_PREFIX_67 */ -#define CHECK_PREFIX_67(v) ((v)==0x67) - -/* CHECK_0F */ -#define CHECK_0F(v) ((v)==0x0f) - -/* CHECK_MODRM2 */ -#if defined(USE_T) && (USE_T & MODRM2_T) -const static unsigned int modrm2_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(1,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 2 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 6 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1), /* 9 */ - BITMASK32(0,0,0,1,1,1,0,0, 0,0,0,1,1,1,0,1, /* a */ - 1,1,1,1,1,1,1,1, 0,0,1,1,1,1,1,1), /* b */ - BITMASK32(1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* c */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ -}; -#define CHECK_MODRM2(v) CHECK_TABLE(modrm2_t, v) -#else -#define CHECK_MODRM2(v) (__extension__ ({ \ - register BYTE __a=(v)&0xfc, __b=(v)&0xfe; \ - ((v)&0xf0)==0x90||((v)&0xf8)==0xb0||((v)&0xf6)==0xa4|| \ - __a==0x00||__a==0xbc||__b==0xba||__b==0xc0|| \ - (v)==0xa3||(v)==0xab||(v)==0xaf; \ -})) -#endif - -/* CHECK_DATA12 */ -#define CHECK_DATA12(v) ((v)==0xa4||(v)==0xac||(v)==0xba) - -/* CHECK_DATA662 */ -#define CHECK_DATA662(v) (((v)&0xf0)==0x80) - -/* CHECK_MODRM */ -#if defined(USE_T) && (USE_T & MODRM_T) -const static unsigned int modrm_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0, /* 0 */ - 1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0), /* 1 */ - BITMASK32(1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0, /* 2 */ - 1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,1,1,0,0,0,0, 0,1,0,1,0,0,0,0, /* 6 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ - BITMASK32(1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, /* 8 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ - BITMASK32(1,1,0,0,1,1,1,1, 0,0,0,0,0,0,0,0, /* c */ - 1,1,1,1,0,0,0,0, 1,1,1,1,1,1,1,1), /* d */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ - 0,0,0,0,0,0,1,1, 0,0,0,0,0,0,1,1) /* f */ -}; -#define CHECK_MODRM(v) CHECK_TABLE(modrm_t, v) -#else -#define CHECK_MODRM(v) (__extension__ ({ \ - register BYTE __a=(v)&0xfc, __b=(v)&0xfe; \ - ((v)&0xc4)==0x00||((v)&0xf0)==0x80||((v)&0xf8)==0xd8||((v)&0xf6)==0xf6|| \ - __a==0xc4||__a==0xd0||__b==0x62||__b==0xc0|| \ - (v)==0x69||(v)==0x6b; \ -})) -#endif - -/* CHECK_TEST */ -#define CHECK_TEST(v) ((v)==0xf6||(v)==0xf7) - -/* CHECK_DATA1 */ -#if defined(USE_T) && (USE_T & DATA1_T) -const static unsigned int data1_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0, /* 0 */ - 0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0), /* 1 */ - BITMASK32(0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0, /* 2 */ - 0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,1,1,0,0,0,0, /* 6 */ - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1), /* 7 */ - BITMASK32(1,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ - BITMASK32(0,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0, /* a */ - 1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0), /* b */ - BITMASK32(1,1,0,0,0,0,1,0, 1,0,0,0,0,1,0,0, /* c */ - 0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0), /* d */ - BITMASK32(1,1,1,1,1,1,1,1, 0,0,0,1,0,0,0,0, /* e */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ -}; -#define CHECK_DATA1(v) CHECK_TABLE(data1_t, v) -#else -#define CHECK_DATA1(v) (__extension__ ({ \ - register BYTE __a=(v)&0xf8, __b=(v)&0xfe; \ - ((v)&0xf0)==0x70||((v)&0xc7)==0x04|| \ - __a==0xb0||__a==0xe0||__b==0x6a||__b==0x82||__b==0xc0||__b==0xd4|| \ - (v)==0x80||(v)==0xa8||(v)==0xc6||(v)==0xc8||(v)==0xcd||(v)==0xeb; \ -})) -#endif - -/* CHECK_DATA2 */ -#if defined(USE_T) && (USE_T & DATA2_T) -const static unsigned int data2_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 2 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 6 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ - 0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0), /* 9 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ - BITMASK32(0,0,1,0,0,0,0,0, 1,0,1,0,0,0,0,0, /* c */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0, /* e */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ -}; -#define CHECK_DATA2(v) CHECK_TABLE(data2_t, v) -#else -#define CHECK_DATA2(v) \ - ((v)==0x9a||(v)==0xc2||(v)==0xc8||(v)==0xca||(v)==0xea) -#endif - -/* CHECK_DATA66 */ -#if defined(USE_T) && (USE_T & DATA66_T) -const static unsigned int data66_t[] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - BITMASK32(0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0, /* 0 */ - 0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0), /* 1 */ - BITMASK32(0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0, /* 2 */ - 0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0), /* 3 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ - BITMASK32(0,0,0,0,0,0,0,0, 1,1,0,0,0,0,0,0, /* 6 */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ - BITMASK32(0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ - 0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0), /* 9 */ - BITMASK32(0,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0, /* a */ - 0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1), /* b */ - BITMASK32(0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,0, /* c */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ - BITMASK32(0,0,0,0,0,0,0,0, 1,1,1,0,0,0,0,0, /* e */ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ -}; -#define CHECK_DATA66(v) CHECK_TABLE(data66_t, v) -#else -#define CHECK_DATA66(v) \ - (((v)&0xc7)==0x05||((v)&0xf8)==0xb8||((v)&0x7e)==0x68|| \ - (v)==0x81||(v)==0x9a||(v)==0xa9||(v)==0xc7||(v)==0xea) -#endif - -/* CHECK_MEM67 */ -#define CHECK_MEM67(v) (((v)&0xfc)==0xa0) - -#endif +/* +x86 Length Disassembler. +Copyright (C) 2013 Byron Platt + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef __LD32_H__ +#define __LD32_H__ + +/* implemented tables */ +#define PREFIX_T 1 +#define MODRM2_T 2 +#define MODRM_T 4 +#define DATA1_T 8 +#define DATA2_T 16 +#define DATA66_T 32 + +/* configure tables */ +#ifndef USE_T +#define USE_T (MODRM2_T|MODRM_T|DATA1_T|DATA66_T) +#endif + +/* length_disasm */ +unsigned int length_disasm(void* opcode0); + +/* table macros */ +#ifdef USE_T +#define BITMASK32( \ + b00,b01,b02,b03,b04,b05,b06,b07, \ + b08,b09,b0a,b0b,b0c,b0d,b0e,b0f, \ + b10,b11,b12,b13,b14,b15,b16,b17, \ + b18,b19,b1a,b1b,b1c,b1d,b1e,b1f \ +) ( \ + (b00<<0x00)|(b01<<0x01)|(b02<<0x02)|(b03<<0x03)| \ + (b04<<0x04)|(b05<<0x05)|(b06<<0x06)|(b07<<0x07)| \ + (b08<<0x08)|(b09<<0x09)|(b0a<<0x0a)|(b0b<<0x0b)| \ + (b0c<<0x0c)|(b0d<<0x0d)|(b0e<<0x0e)|(b0f<<0x0f)| \ + (b10<<0x10)|(b11<<0x11)|(b12<<0x12)|(b13<<0x13)| \ + (b14<<0x14)|(b15<<0x15)|(b16<<0x16)|(b17<<0x17)| \ + (b18<<0x18)|(b19<<0x19)|(b1a<<0x1a)|(b1b<<0x1b)| \ + (b1c<<0x1c)|(b1d<<0x1d)|(b1e<<0x1e)|(b1f<<0x1f) \ +) +#define CHECK_TABLE(t, v) ((t[(v)>>5]>>((v)&0x1f))&1) +#endif + +/* CHECK_PREFIX */ +#if defined(USE_T) && (USE_T & PREFIX_T) +const static unsigned int prefix_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ + BITMASK32(0,0,0,0,0,0,1,0, 0,0,0,0,0,0,1,0, /* 2 */ + 0,0,0,0,0,0,1,0, 0,0,0,0,0,0,1,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,0,0,1,1,1,1, 0,0,0,0,0,0,0,0, /* 6 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* c */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ + 1,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ +}; +#define CHECK_PREFIX(v) CHECK_TABLE(prefix_t, v) +#else +#define CHECK_PREFIX(v) \ + (((v)&0xe7)==0x26||((v)&0xfc)==0x64||(v)==0xf0||(v)==0xf2||(v)==0xf3) +#endif + +/* CHECK_PREFIX_66 */ +#define CHECK_PREFIX_66(v) ((v)==0x66) + +/* CHECK_PREFIX_67 */ +#define CHECK_PREFIX_67(v) ((v)==0x67) + +/* CHECK_0F */ +#define CHECK_0F(v) ((v)==0x0f) + +/* CHECK_MODRM2 */ +#if defined(USE_T) && (USE_T & MODRM2_T) +const static unsigned int modrm2_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(1,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 2 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 6 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1), /* 9 */ + BITMASK32(0,0,0,1,1,1,0,0, 0,0,0,1,1,1,0,1, /* a */ + 1,1,1,1,1,1,1,1, 0,0,1,1,1,1,1,1), /* b */ + BITMASK32(1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* c */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ +}; +#define CHECK_MODRM2(v) CHECK_TABLE(modrm2_t, v) +#else +#define CHECK_MODRM2(v) (__extension__ ({ \ + register BYTE __a=(v)&0xfc, __b=(v)&0xfe; \ + ((v)&0xf0)==0x90||((v)&0xf8)==0xb0||((v)&0xf6)==0xa4|| \ + __a==0x00||__a==0xbc||__b==0xba||__b==0xc0|| \ + (v)==0xa3||(v)==0xab||(v)==0xaf; \ +})) +#endif + +/* CHECK_DATA12 */ +#define CHECK_DATA12(v) ((v)==0xa4||(v)==0xac||(v)==0xba) + +/* CHECK_DATA662 */ +#define CHECK_DATA662(v) (((v)&0xf0)==0x80) + +/* CHECK_MODRM */ +#if defined(USE_T) && (USE_T & MODRM_T) +const static unsigned int modrm_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0, /* 0 */ + 1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0), /* 1 */ + BITMASK32(1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0, /* 2 */ + 1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,1,1,0,0,0,0, 0,1,0,1,0,0,0,0, /* 6 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ + BITMASK32(1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, /* 8 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ + BITMASK32(1,1,0,0,1,1,1,1, 0,0,0,0,0,0,0,0, /* c */ + 1,1,1,1,0,0,0,0, 1,1,1,1,1,1,1,1), /* d */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* e */ + 0,0,0,0,0,0,1,1, 0,0,0,0,0,0,1,1) /* f */ +}; +#define CHECK_MODRM(v) CHECK_TABLE(modrm_t, v) +#else +#define CHECK_MODRM(v) (__extension__ ({ \ + register BYTE __a=(v)&0xfc, __b=(v)&0xfe; \ + ((v)&0xc4)==0x00||((v)&0xf0)==0x80||((v)&0xf8)==0xd8||((v)&0xf6)==0xf6|| \ + __a==0xc4||__a==0xd0||__b==0x62||__b==0xc0|| \ + (v)==0x69||(v)==0x6b; \ +})) +#endif + +/* CHECK_TEST */ +#define CHECK_TEST(v) ((v)==0xf6||(v)==0xf7) + +/* CHECK_DATA1 */ +#if defined(USE_T) && (USE_T & DATA1_T) +const static unsigned int data1_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0, /* 0 */ + 0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0), /* 1 */ + BITMASK32(0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0, /* 2 */ + 0,0,0,0,1,0,0,0, 0,0,0,0,1,0,0,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,1,1,0,0,0,0, /* 6 */ + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1), /* 7 */ + BITMASK32(1,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 9 */ + BITMASK32(0,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0, /* a */ + 1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0), /* b */ + BITMASK32(1,1,0,0,0,0,1,0, 1,0,0,0,0,1,0,0, /* c */ + 0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0), /* d */ + BITMASK32(1,1,1,1,1,1,1,1, 0,0,0,1,0,0,0,0, /* e */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ +}; +#define CHECK_DATA1(v) CHECK_TABLE(data1_t, v) +#else +#define CHECK_DATA1(v) (__extension__ ({ \ + register BYTE __a=(v)&0xf8, __b=(v)&0xfe; \ + ((v)&0xf0)==0x70||((v)&0xc7)==0x04|| \ + __a==0xb0||__a==0xe0||__b==0x6a||__b==0x82||__b==0xc0||__b==0xd4|| \ + (v)==0x80||(v)==0xa8||(v)==0xc6||(v)==0xc8||(v)==0xcd||(v)==0xeb; \ +})) +#endif + +/* CHECK_DATA2 */ +#if defined(USE_T) && (USE_T & DATA2_T) +const static unsigned int data2_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 0 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 1 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 2 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 6 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ + 0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0), /* 9 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* a */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* b */ + BITMASK32(0,0,1,0,0,0,0,0, 1,0,1,0,0,0,0,0, /* c */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0, /* e */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ +}; +#define CHECK_DATA2(v) CHECK_TABLE(data2_t, v) +#else +#define CHECK_DATA2(v) \ + ((v)==0x9a||(v)==0xc2||(v)==0xc8||(v)==0xca||(v)==0xea) +#endif + +/* CHECK_DATA66 */ +#if defined(USE_T) && (USE_T & DATA66_T) +const static unsigned int data66_t[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + BITMASK32(0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0, /* 0 */ + 0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0), /* 1 */ + BITMASK32(0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0, /* 2 */ + 0,0,0,0,0,1,0,0, 0,0,0,0,0,1,0,0), /* 3 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 4 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 5 */ + BITMASK32(0,0,0,0,0,0,0,0, 1,1,0,0,0,0,0,0, /* 6 */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* 7 */ + BITMASK32(0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, /* 8 */ + 0,0,0,0,0,0,0,0, 0,0,1,0,0,0,0,0), /* 9 */ + BITMASK32(0,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0, /* a */ + 0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1), /* b */ + BITMASK32(0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,0, /* c */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0), /* d */ + BITMASK32(0,0,0,0,0,0,0,0, 1,1,1,0,0,0,0,0, /* e */ + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0) /* f */ +}; +#define CHECK_DATA66(v) CHECK_TABLE(data66_t, v) +#else +#define CHECK_DATA66(v) \ + (((v)&0xc7)==0x05||((v)&0xf8)==0xb8||((v)&0x7e)==0x68|| \ + (v)==0x81||(v)==0x9a||(v)==0xa9||(v)==0xc7||(v)==0xea) +#endif + +/* CHECK_MEM67 */ +#define CHECK_MEM67(v) (((v)&0xfc)==0xa0) + +#endif diff --git a/tcc/include/_mingw.h b/tcc/include/_mingw.h index 35de395f..3f227f22 100644 --- a/tcc/include/_mingw.h +++ b/tcc/include/_mingw.h @@ -1,164 +1,164 @@ -/* - * _mingw.h - * - * This file is for TinyCC and not part of the Mingw32 package. - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef __MINGW_H -#define __MINGW_H - -/* some winapi files define these before including _mingw.h --> */ -#undef __cdecl -#undef _X86_ -#undef WIN32 -/* <-- */ - -#include -#include - -#define __int8 char -#define __int16 short -#define __int32 int -#define __int64 long long -#define _HAVE_INT64 - -#define __cdecl -#define __declspec(x) __attribute__((x)) -#define __unaligned __attribute__((packed)) -#define __fastcall __attribute__((fastcall)) - -#define __MSVCRT__ 1 -#undef _MSVCRT_ -#define __MINGW_IMPORT extern __declspec(dllimport) -#define __MINGW_ATTRIB_NORETURN __declspec(noreturn) -#define __MINGW_ATTRIB_CONST -#define __MINGW_ATTRIB_DEPRECATED -#define __MINGW_ATTRIB_MALLOC -#define __MINGW_ATTRIB_PURE -#define __MINGW_ATTRIB_NONNULL(arg) -#define __MINGW_NOTHROW -#define __GNUC_VA_LIST - -#define _CRTIMP extern -#define __CRT_INLINE static __inline__ - -#define _CRT_ALIGN(x) __attribute__((aligned(x))) -#define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) -#define _CRT_PACKING 8 -#define __CRT_UNALIGNED -#define _CONST_RETURN - -#ifndef _TRUNCATE -#define _TRUNCATE ((size_t)-1) -#endif - -#define __CRT_STRINGIZE(_Value) #_Value -#define _CRT_STRINGIZE(_Value) __CRT_STRINGIZE(_Value) -#define __CRT_WIDE(_String) L ## _String -#define _CRT_WIDE(_String) __CRT_WIDE(_String) - -#ifdef _WIN64 -#define __stdcall -#define _AMD64_ 1 -#define __x86_64 1 -#define _M_X64 100 /* Visual Studio */ -#define _M_AMD64 100 /* Visual Studio */ -#define USE_MINGW_SETJMP_TWO_ARGS -#define mingw_getsp tinyc_getbp -#else -#define __stdcall __attribute__((__stdcall__)) -#define _X86_ 1 -#define _M_IX86 300 /* Visual Studio */ -#define _USE_32BIT_TIME_T -#endif - -/* in stddef.h */ -#define _SIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#define _PTRDIFF_T_DEFINED -#define _WCHAR_T_DEFINED -#define _UINTPTR_T_DEFINED -#define _INTPTR_T_DEFINED -#define _INTEGRAL_MAX_BITS 64 - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED -typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -typedef long long __time64_t; -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T -typedef __time32_t time_t; -#else -typedef __time64_t time_t; -#endif -#endif - -#ifndef _WCTYPE_T_DEFINED -#define _WCTYPE_T_DEFINED -typedef wchar_t wctype_t; -#endif - -#ifndef _WINT_T -#define _WINT_T -typedef __WINT_TYPE__ wint_t; -#endif - -typedef int errno_t; -#define _ERRCODE_DEFINED - -typedef struct threadlocaleinfostruct *pthreadlocinfo; -typedef struct threadmbcinfostruct *pthreadmbcinfo; -typedef struct localeinfo_struct _locale_tstruct,*_locale_t; - -/* for winapi */ -#define _ANONYMOUS_UNION -#define _ANONYMOUS_STRUCT -#define DECLSPEC_NORETURN __declspec(noreturn) -#define DECLARE_STDCALL_P(type) __stdcall type -#define NOSERVICE 1 -#define NOMCX 1 -#define NOIME 1 -#define __INTRIN_H_ -#ifndef DUMMYUNIONNAME -# define DUMMYUNIONNAME -# define DUMMYUNIONNAME1 -# define DUMMYUNIONNAME2 -# define DUMMYUNIONNAME3 -# define DUMMYUNIONNAME4 -# define DUMMYUNIONNAME5 -#endif -#ifndef DUMMYSTRUCTNAME -# define DUMMYSTRUCTNAME -#endif -#ifndef WINVER -# define WINVER 0x0502 -#endif -#ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x502 -#endif - -#define __C89_NAMELESS -#define __MINGW_EXTENSION -#define WINAPI_FAMILY_PARTITION(X) 1 -#define MINGW_HAS_SECURE_API -#define WIN32 1 - -#endif /* __MINGW_H */ +/* + * _mingw.h + * + * This file is for TinyCC and not part of the Mingw32 package. + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __MINGW_H +#define __MINGW_H + +/* some winapi files define these before including _mingw.h --> */ +#undef __cdecl +#undef _X86_ +#undef WIN32 +/* <-- */ + +#include +#include + +#define __int8 char +#define __int16 short +#define __int32 int +#define __int64 long long +#define _HAVE_INT64 + +#define __cdecl +#define __declspec(x) __attribute__((x)) +#define __unaligned __attribute__((packed)) +#define __fastcall __attribute__((fastcall)) + +#define __MSVCRT__ 1 +#undef _MSVCRT_ +#define __MINGW_IMPORT extern __declspec(dllimport) +#define __MINGW_ATTRIB_NORETURN __declspec(noreturn) +#define __MINGW_ATTRIB_CONST +#define __MINGW_ATTRIB_DEPRECATED +#define __MINGW_ATTRIB_MALLOC +#define __MINGW_ATTRIB_PURE +#define __MINGW_ATTRIB_NONNULL(arg) +#define __MINGW_NOTHROW +#define __GNUC_VA_LIST + +#define _CRTIMP extern +#define __CRT_INLINE static __inline__ + +#define _CRT_ALIGN(x) __attribute__((aligned(x))) +#define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) +#define _CRT_PACKING 8 +#define __CRT_UNALIGNED +#define _CONST_RETURN + +#ifndef _TRUNCATE +#define _TRUNCATE ((size_t)-1) +#endif + +#define __CRT_STRINGIZE(_Value) #_Value +#define _CRT_STRINGIZE(_Value) __CRT_STRINGIZE(_Value) +#define __CRT_WIDE(_String) L ## _String +#define _CRT_WIDE(_String) __CRT_WIDE(_String) + +#ifdef _WIN64 +#define __stdcall +#define _AMD64_ 1 +#define __x86_64 1 +#define _M_X64 100 /* Visual Studio */ +#define _M_AMD64 100 /* Visual Studio */ +#define USE_MINGW_SETJMP_TWO_ARGS +#define mingw_getsp tinyc_getbp +#else +#define __stdcall __attribute__((__stdcall__)) +#define _X86_ 1 +#define _M_IX86 300 /* Visual Studio */ +#define _USE_32BIT_TIME_T +#endif + +/* in stddef.h */ +#define _SIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#define _PTRDIFF_T_DEFINED +#define _WCHAR_T_DEFINED +#define _UINTPTR_T_DEFINED +#define _INTPTR_T_DEFINED +#define _INTEGRAL_MAX_BITS 64 + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED +typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +typedef long long __time64_t; +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T +typedef __time32_t time_t; +#else +typedef __time64_t time_t; +#endif +#endif + +#ifndef _WCTYPE_T_DEFINED +#define _WCTYPE_T_DEFINED +typedef wchar_t wctype_t; +#endif + +#ifndef _WINT_T +#define _WINT_T +typedef __WINT_TYPE__ wint_t; +#endif + +typedef int errno_t; +#define _ERRCODE_DEFINED + +typedef struct threadlocaleinfostruct *pthreadlocinfo; +typedef struct threadmbcinfostruct *pthreadmbcinfo; +typedef struct localeinfo_struct _locale_tstruct,*_locale_t; + +/* for winapi */ +#define _ANONYMOUS_UNION +#define _ANONYMOUS_STRUCT +#define DECLSPEC_NORETURN __declspec(noreturn) +#define DECLARE_STDCALL_P(type) __stdcall type +#define NOSERVICE 1 +#define NOMCX 1 +#define NOIME 1 +#define __INTRIN_H_ +#ifndef DUMMYUNIONNAME +# define DUMMYUNIONNAME +# define DUMMYUNIONNAME1 +# define DUMMYUNIONNAME2 +# define DUMMYUNIONNAME3 +# define DUMMYUNIONNAME4 +# define DUMMYUNIONNAME5 +#endif +#ifndef DUMMYSTRUCTNAME +# define DUMMYSTRUCTNAME +#endif +#ifndef WINVER +# define WINVER 0x0502 +#endif +#ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x502 +#endif + +#define __C89_NAMELESS +#define __MINGW_EXTENSION +#define WINAPI_FAMILY_PARTITION(X) 1 +#define MINGW_HAS_SECURE_API +#define WIN32 1 + +#endif /* __MINGW_H */ diff --git a/tcc/include/assert.h b/tcc/include/assert.h index 4fce450e..b15bb638 100644 --- a/tcc/include/assert.h +++ b/tcc/include/assert.h @@ -1,62 +1,62 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef __ASSERT_H_ -#define __ASSERT_H_ - -#include <_mingw.h> -#ifdef __cplusplus -#include -#endif - -#ifdef NDEBUG -#ifndef assert -#define assert(_Expression) ((void)0) -#endif -#else - -#ifndef _CRT_TERMINATE_DEFINED -#define _CRT_TERMINATE_DEFINED - void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; - _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; -#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ -/* C99 function name */ -void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; -__CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) -{ _exit(status); } -#endif - -#pragma push_macro("abort") -#undef abort - void __cdecl __declspec(noreturn) abort(void); -#pragma pop_macro("abort") - -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -extern void __cdecl _wassert(const wchar_t *_Message,const wchar_t *_File,unsigned _Line); -extern void __cdecl _assert(const char *, const char *, unsigned); - -#ifdef __cplusplus -} -#endif - -#ifndef assert -//#define assert(_Expression) (void)((!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression),_CRT_WIDE(__FILE__),__LINE__),0)) -#define assert(e) ((e) ? (void)0 : _assert(#e, __FILE__, __LINE__)) -#endif - -#endif - -#if (__STDC_VERSION__ >= 201112L) && !defined(static_assert) -/* C11, section 7.2: The macro static_assert expands to _Static_assert. */ -#define static_assert(exp, str) _Static_assert(exp, str) -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef __ASSERT_H_ +#define __ASSERT_H_ + +#include <_mingw.h> +#ifdef __cplusplus +#include +#endif + +#ifdef NDEBUG +#ifndef assert +#define assert(_Expression) ((void)0) +#endif +#else + +#ifndef _CRT_TERMINATE_DEFINED +#define _CRT_TERMINATE_DEFINED + void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; + _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; +#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ +/* C99 function name */ +void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; +__CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) +{ _exit(status); } +#endif + +#pragma push_macro("abort") +#undef abort + void __cdecl __declspec(noreturn) abort(void); +#pragma pop_macro("abort") + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +extern void __cdecl _wassert(const wchar_t *_Message,const wchar_t *_File,unsigned _Line); +extern void __cdecl _assert(const char *, const char *, unsigned); + +#ifdef __cplusplus +} +#endif + +#ifndef assert +//#define assert(_Expression) (void)((!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression),_CRT_WIDE(__FILE__),__LINE__),0)) +#define assert(e) ((e) ? (void)0 : _assert(#e, __FILE__, __LINE__)) +#endif + +#endif + +#if (__STDC_VERSION__ >= 201112L) && !defined(static_assert) +/* C11, section 7.2: The macro static_assert expands to _Static_assert. */ +#define static_assert(exp, str) _Static_assert(exp, str) +#endif + +#endif diff --git a/tcc/include/conio.h b/tcc/include/conio.h index 7a4c1f19..39f779eb 100644 --- a/tcc/include/conio.h +++ b/tcc/include/conio.h @@ -1,409 +1,409 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_CONIO -#define _INC_CONIO - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP char *_cgets(char *_Buffer); - _CRTIMP int __cdecl _cprintf(const char *_Format,...); - _CRTIMP int __cdecl _cputs(const char *_Str); - _CRTIMP int __cdecl _cscanf(const char *_Format,...); - _CRTIMP int __cdecl _cscanf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _getch(void); - _CRTIMP int __cdecl _getche(void); - _CRTIMP int __cdecl _vcprintf(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_p(const char *_Format,...); - _CRTIMP int __cdecl _vcprintf_p(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_p_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _kbhit(void); - -#if defined(_X86_) && !defined(__x86_64) - int __cdecl _inp(unsigned short); - unsigned short __cdecl _inpw(unsigned short); - unsigned long __cdecl _inpd(unsigned short); - int __cdecl _outp(unsigned short,int); - unsigned short __cdecl _outpw(unsigned short,unsigned short); - unsigned long __cdecl _outpd(unsigned short,unsigned long); -#endif - - _CRTIMP int __cdecl _putch(int _Ch); - _CRTIMP int __cdecl _ungetch(int _Ch); - _CRTIMP int __cdecl _getch_nolock(void); - _CRTIMP int __cdecl _getche_nolock(void); - _CRTIMP int __cdecl _putch_nolock(int _Ch); - _CRTIMP int __cdecl _ungetch_nolock(int _Ch); - -#ifndef _WCONIO_DEFINED -#define _WCONIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - - _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _getwch(void); - _CRTIMP wint_t __cdecl _getwche(void); - _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); - _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); - _CRTIMP int __cdecl _cputws(const wchar_t *_String); - _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP wint_t __cdecl _putwch_nolock(wchar_t _WCh); - _CRTIMP wint_t __cdecl _getwch_nolock(void); - _CRTIMP wint_t __cdecl _getwche_nolock(void); - _CRTIMP wint_t __cdecl _ungetwch_nolock(wint_t _WCh); -#endif - -#ifndef NO_OLDNAMES - char *__cdecl cgets(char *_Buffer); - int __cdecl cprintf(const char *_Format,...); - int __cdecl cputs(const char *_Str); - int __cdecl cscanf(const char *_Format,...); - int __cdecl getch(void); - int __cdecl getche(void); - int __cdecl kbhit(void); - int __cdecl putch(int _Ch); - int __cdecl ungetch(int _Ch); - -#if (defined(_X86_) && !defined(__x86_64)) - int __cdecl inp(unsigned short); - unsigned short __cdecl inpw(unsigned short); - int __cdecl outp(unsigned short,int); - unsigned short __cdecl outpw(unsigned short,unsigned short); -#endif - - /* I/O intrin functions. */ - __CRT_INLINE unsigned char __inbyte(unsigned short Port) - { - unsigned char value; - __asm__ __volatile__ ("inb %w1,%b0" - : "=a" (value) - : "Nd" (Port)); - return value; - } - __CRT_INLINE unsigned short __inword(unsigned short Port) - { - unsigned short value; - __asm__ __volatile__ ("inw %w1,%w0" - : "=a" (value) - : "Nd" (Port)); - return value; - } - __CRT_INLINE unsigned long __indword(unsigned short Port) - { - unsigned long value; - __asm__ __volatile__ ("inl %w1,%0" - : "=a" (value) - : "Nd" (Port)); - return value; - } - __CRT_INLINE void __outbyte(unsigned short Port,unsigned char Data) - { - __asm__ __volatile__ ("outb %b0,%w1" - : - : "a" (Data), "Nd" (Port)); - } - __CRT_INLINE void __outword(unsigned short Port,unsigned short Data) - { - __asm__ __volatile__ ("outw %w0,%w1" - : - : "a" (Data), "Nd" (Port)); - } - __CRT_INLINE void __outdword(unsigned short Port,unsigned long Data) - { - __asm__ __volatile__ ("outl %0,%w1" - : - : "a" (Data), "Nd" (Port)); - } - __CRT_INLINE void __inbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; insb " - : "=D" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __inwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; insw " - : "=D" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __indwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; insl " - : "=D" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - - __CRT_INLINE void __outbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; outsb " - : "=S" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __outwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; outsw " - : "=S" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - __CRT_INLINE void __outdwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) - { - __asm__ __volatile__ ( - "cld ; rep ; outsl " - : "=S" (Buffer), "=c" (Count) - : "d"(Port), "0"(Buffer), "1" (Count) - ); - } - - __CRT_INLINE unsigned __int64 __readcr0(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr0, %[value]" - : [value] "=q" (value)); - return value; - } - - /* Register sizes are different between 32/64 bit mode. So we have to do this for _WIN64 and _WIN32 - separately. */ - -#ifdef _WIN64 - __CRT_INLINE void __writecr0(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr0" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr2(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr2, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr2(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr2" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr3(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr3, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr3(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr3" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr4(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr4, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr4(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr4" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned __int64 __readcr8(void) - { - unsigned __int64 value; - __asm__ __volatile__ ( - "mov %%cr8, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr8(unsigned __int64 Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr8" - : - : [Data] "q" (Data) - : "memory"); - } - -#elif defined(_WIN32) - - __CRT_INLINE void __writecr0(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr0" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr2(void) - { - unsigned long value; - __asm__ __volatile__ ( - "mov %%cr2, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr2(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr2" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr3(void) - { - unsigned long value; - __asm__ __volatile__ ( - "mov %%cr3, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr3(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr3" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr4(void) - { - unsigned long value; - __asm__ __volatile__ ( - "mov %%cr4, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr4(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr4" - : - : [Data] "q" (Data) - : "memory"); - } - - __CRT_INLINE unsigned long __readcr8(void) - { - unsigned long value; __asm__ __volatile__ ( - "mov %%cr8, %[value]" - : [value] "=q" (value)); - return value; - } - - __CRT_INLINE void __writecr8(unsigned Data) - { - __asm__ __volatile__ ( - "mov %[Data], %%cr8" - : - : [Data] "q" (Data) - : "memory"); - } - -#endif - - __CRT_INLINE unsigned __int64 __readmsr(unsigned long msr) - { - unsigned __int64 val1, val2; - __asm__ __volatile__( - "rdmsr" - : "=a" (val1), "=d" (val2) - : "c" (msr)); - return val1 | (val2 << 32); - } - - __CRT_INLINE void __writemsr (unsigned long msr, unsigned __int64 Value) - { - unsigned long val1 = Value, val2 = Value >> 32; - __asm__ __volatile__ ( - "wrmsr" - : - : "c" (msr), "a" (val1), "d" (val2)); - } - - __CRT_INLINE unsigned __int64 __rdtsc(void) - { - unsigned __int64 val1, val2; - __asm__ __volatile__ ( - "rdtsc" - : "=a" (val1), "=d" (val2)); - return val1 | (val2 << 32); - } - - __CRT_INLINE void __cpuid(int CPUInfo[4], int InfoType) - { - __asm__ __volatile__ ( - "cpuid" - : "=a" (CPUInfo [0]), "=b" (CPUInfo [1]), "=c" (CPUInfo [2]), "=d" (CPUInfo [3]) - : "a" (InfoType)); - } - -#endif - -#ifdef __cplusplus -} -#endif - -#include - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_CONIO +#define _INC_CONIO + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP char *_cgets(char *_Buffer); + _CRTIMP int __cdecl _cprintf(const char *_Format,...); + _CRTIMP int __cdecl _cputs(const char *_Str); + _CRTIMP int __cdecl _cscanf(const char *_Format,...); + _CRTIMP int __cdecl _cscanf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _getch(void); + _CRTIMP int __cdecl _getche(void); + _CRTIMP int __cdecl _vcprintf(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_p(const char *_Format,...); + _CRTIMP int __cdecl _vcprintf_p(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_p_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _kbhit(void); + +#if defined(_X86_) && !defined(__x86_64) + int __cdecl _inp(unsigned short); + unsigned short __cdecl _inpw(unsigned short); + unsigned long __cdecl _inpd(unsigned short); + int __cdecl _outp(unsigned short,int); + unsigned short __cdecl _outpw(unsigned short,unsigned short); + unsigned long __cdecl _outpd(unsigned short,unsigned long); +#endif + + _CRTIMP int __cdecl _putch(int _Ch); + _CRTIMP int __cdecl _ungetch(int _Ch); + _CRTIMP int __cdecl _getch_nolock(void); + _CRTIMP int __cdecl _getche_nolock(void); + _CRTIMP int __cdecl _putch_nolock(int _Ch); + _CRTIMP int __cdecl _ungetch_nolock(int _Ch); + +#ifndef _WCONIO_DEFINED +#define _WCONIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + + _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _getwch(void); + _CRTIMP wint_t __cdecl _getwche(void); + _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); + _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); + _CRTIMP int __cdecl _cputws(const wchar_t *_String); + _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP wint_t __cdecl _putwch_nolock(wchar_t _WCh); + _CRTIMP wint_t __cdecl _getwch_nolock(void); + _CRTIMP wint_t __cdecl _getwche_nolock(void); + _CRTIMP wint_t __cdecl _ungetwch_nolock(wint_t _WCh); +#endif + +#ifndef NO_OLDNAMES + char *__cdecl cgets(char *_Buffer); + int __cdecl cprintf(const char *_Format,...); + int __cdecl cputs(const char *_Str); + int __cdecl cscanf(const char *_Format,...); + int __cdecl getch(void); + int __cdecl getche(void); + int __cdecl kbhit(void); + int __cdecl putch(int _Ch); + int __cdecl ungetch(int _Ch); + +#if (defined(_X86_) && !defined(__x86_64)) + int __cdecl inp(unsigned short); + unsigned short __cdecl inpw(unsigned short); + int __cdecl outp(unsigned short,int); + unsigned short __cdecl outpw(unsigned short,unsigned short); +#endif + + /* I/O intrin functions. */ + __CRT_INLINE unsigned char __inbyte(unsigned short Port) + { + unsigned char value; + __asm__ __volatile__ ("inb %w1,%b0" + : "=a" (value) + : "Nd" (Port)); + return value; + } + __CRT_INLINE unsigned short __inword(unsigned short Port) + { + unsigned short value; + __asm__ __volatile__ ("inw %w1,%w0" + : "=a" (value) + : "Nd" (Port)); + return value; + } + __CRT_INLINE unsigned long __indword(unsigned short Port) + { + unsigned long value; + __asm__ __volatile__ ("inl %w1,%0" + : "=a" (value) + : "Nd" (Port)); + return value; + } + __CRT_INLINE void __outbyte(unsigned short Port,unsigned char Data) + { + __asm__ __volatile__ ("outb %b0,%w1" + : + : "a" (Data), "Nd" (Port)); + } + __CRT_INLINE void __outword(unsigned short Port,unsigned short Data) + { + __asm__ __volatile__ ("outw %w0,%w1" + : + : "a" (Data), "Nd" (Port)); + } + __CRT_INLINE void __outdword(unsigned short Port,unsigned long Data) + { + __asm__ __volatile__ ("outl %0,%w1" + : + : "a" (Data), "Nd" (Port)); + } + __CRT_INLINE void __inbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; insb " + : "=D" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __inwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; insw " + : "=D" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __indwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; insl " + : "=D" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + + __CRT_INLINE void __outbytestring(unsigned short Port,unsigned char *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; outsb " + : "=S" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __outwordstring(unsigned short Port,unsigned short *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; outsw " + : "=S" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + __CRT_INLINE void __outdwordstring(unsigned short Port,unsigned long *Buffer,unsigned long Count) + { + __asm__ __volatile__ ( + "cld ; rep ; outsl " + : "=S" (Buffer), "=c" (Count) + : "d"(Port), "0"(Buffer), "1" (Count) + ); + } + + __CRT_INLINE unsigned __int64 __readcr0(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr0, %[value]" + : [value] "=q" (value)); + return value; + } + + /* Register sizes are different between 32/64 bit mode. So we have to do this for _WIN64 and _WIN32 + separately. */ + +#ifdef _WIN64 + __CRT_INLINE void __writecr0(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr0" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr2(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr2, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr2(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr2" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr3(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr3, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr3(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr3" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr4(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr4, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr4(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr4" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned __int64 __readcr8(void) + { + unsigned __int64 value; + __asm__ __volatile__ ( + "mov %%cr8, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr8(unsigned __int64 Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr8" + : + : [Data] "q" (Data) + : "memory"); + } + +#elif defined(_WIN32) + + __CRT_INLINE void __writecr0(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr0" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr2(void) + { + unsigned long value; + __asm__ __volatile__ ( + "mov %%cr2, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr2(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr2" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr3(void) + { + unsigned long value; + __asm__ __volatile__ ( + "mov %%cr3, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr3(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr3" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr4(void) + { + unsigned long value; + __asm__ __volatile__ ( + "mov %%cr4, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr4(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr4" + : + : [Data] "q" (Data) + : "memory"); + } + + __CRT_INLINE unsigned long __readcr8(void) + { + unsigned long value; __asm__ __volatile__ ( + "mov %%cr8, %[value]" + : [value] "=q" (value)); + return value; + } + + __CRT_INLINE void __writecr8(unsigned Data) + { + __asm__ __volatile__ ( + "mov %[Data], %%cr8" + : + : [Data] "q" (Data) + : "memory"); + } + +#endif + + __CRT_INLINE unsigned __int64 __readmsr(unsigned long msr) + { + unsigned __int64 val1, val2; + __asm__ __volatile__( + "rdmsr" + : "=a" (val1), "=d" (val2) + : "c" (msr)); + return val1 | (val2 << 32); + } + + __CRT_INLINE void __writemsr (unsigned long msr, unsigned __int64 Value) + { + unsigned long val1 = Value, val2 = Value >> 32; + __asm__ __volatile__ ( + "wrmsr" + : + : "c" (msr), "a" (val1), "d" (val2)); + } + + __CRT_INLINE unsigned __int64 __rdtsc(void) + { + unsigned __int64 val1, val2; + __asm__ __volatile__ ( + "rdtsc" + : "=a" (val1), "=d" (val2)); + return val1 | (val2 << 32); + } + + __CRT_INLINE void __cpuid(int CPUInfo[4], int InfoType) + { + __asm__ __volatile__ ( + "cpuid" + : "=a" (CPUInfo [0]), "=b" (CPUInfo [1]), "=c" (CPUInfo [2]), "=d" (CPUInfo [3]) + : "a" (InfoType)); + } + +#endif + +#ifdef __cplusplus +} +#endif + +#include + +#endif diff --git a/tcc/include/ctype.h b/tcc/include/ctype.h index 346926cc..7e901002 100644 --- a/tcc/include/ctype.h +++ b/tcc/include/ctype.h @@ -1,281 +1,281 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_CTYPE -#define _INC_CTYPE - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifndef _CRT_CTYPEDATA_DEFINED -#define _CRT_CTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef __PCTYPE_FUNC -#define __PCTYPE_FUNC __pctype_func() -#ifdef _MSVCRT_ -#define __pctype_func() (_pctype) -#else -#define __pctype_func() (*_imp___pctype) -#endif -#endif - -#ifndef _pctype -#ifdef _MSVCRT_ - extern unsigned short *_pctype; -#else - extern unsigned short **_imp___pctype; -#define _pctype (*_imp___pctype) -#endif -#endif - -#endif -#endif - -#ifndef _CRT_WCTYPEDATA_DEFINED -#define _CRT_WCTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS -#ifndef _wctype -#ifdef _MSVCRT_ - extern unsigned short *_wctype; -#else - extern unsigned short **_imp___wctype; -#define _wctype (*_imp___wctype) -#endif -#endif -#ifdef _MSVCRT_ -#define __pwctype_func() (_pwctype) -#ifndef _pwctype - extern unsigned short *_pwctype; -#endif -#else -#define __pwctype_func() (*_imp___pwctype) -#ifndef _pwctype - extern unsigned short **_imp___pwctype; -#define _pwctype (*_imp___pwctype) -#endif -#endif -#endif -#endif - - /* CRT stuff */ -#if 1 - extern const unsigned char __newclmap[]; - extern const unsigned char __newcumap[]; - extern pthreadlocinfo __ptlocinfo; - extern pthreadmbcinfo __ptmbcinfo; - extern int __globallocalestatus; - extern int __locale_changed; - extern struct threadlocaleinfostruct __initiallocinfo; - extern _locale_tstruct __initiallocalestructinfo; - pthreadlocinfo __cdecl __updatetlocinfo(void); - pthreadmbcinfo __cdecl __updatetmbcinfo(void); -#endif - -#define _UPPER 0x1 -#define _LOWER 0x2 -#define _DIGIT 0x4 -#define _SPACE 0x8 - -#define _PUNCT 0x10 -#define _CONTROL 0x20 -#define _BLANK 0x40 -#define _HEX 0x80 - -#define _LEADBYTE 0x8000 -#define _ALPHA (0x0100|_UPPER|_LOWER) - -#ifndef _CTYPE_DEFINED -#define _CTYPE_DEFINED - - _CRTIMP int __cdecl _isctype(int _C,int _Type); - _CRTIMP int __cdecl _isctype_l(int _C,int _Type,_locale_t _Locale); - _CRTIMP int __cdecl isalpha(int _C); - _CRTIMP int __cdecl _isalpha_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isupper(int _C); - _CRTIMP int __cdecl _isupper_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl islower(int _C); - _CRTIMP int __cdecl _islower_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isdigit(int _C); - _CRTIMP int __cdecl _isdigit_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isxdigit(int _C); - _CRTIMP int __cdecl _isxdigit_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isspace(int _C); - _CRTIMP int __cdecl _isspace_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl ispunct(int _C); - _CRTIMP int __cdecl _ispunct_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isalnum(int _C); - _CRTIMP int __cdecl _isalnum_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isprint(int _C); - _CRTIMP int __cdecl _isprint_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl isgraph(int _C); - _CRTIMP int __cdecl _isgraph_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl iscntrl(int _C); - _CRTIMP int __cdecl _iscntrl_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl toupper(int _C); - _CRTIMP int __cdecl tolower(int _C); - _CRTIMP int __cdecl _tolower(int _C); - _CRTIMP int __cdecl _tolower_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl _toupper(int _C); - _CRTIMP int __cdecl _toupper_l(int _C,_locale_t _Locale); - _CRTIMP int __cdecl __isascii(int _C); - _CRTIMP int __cdecl __toascii(int _C); - _CRTIMP int __cdecl __iscsymf(int _C); - _CRTIMP int __cdecl __iscsym(int _C); - -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) -int __cdecl isblank(int _C); -#endif -#endif - -#ifndef _WCTYPE_DEFINED -#define _WCTYPE_DEFINED - - int __cdecl iswalpha(wint_t _C); - _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); - int __cdecl iswupper(wint_t _C); - _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); - int __cdecl iswlower(wint_t _C); - _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswdigit(wint_t _C); - _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswxdigit(wint_t _C); - _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswspace(wint_t _C); - _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); - int __cdecl iswpunct(wint_t _C); - _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); - int __cdecl iswalnum(wint_t _C); - _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); - int __cdecl iswprint(wint_t _C); - _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); - int __cdecl iswgraph(wint_t _C); - _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); - int __cdecl iswcntrl(wint_t _C); - _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); - int __cdecl iswascii(wint_t _C); - int __cdecl isleadbyte(int _C); - _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); - wint_t __cdecl towupper(wint_t _C); - _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); - wint_t __cdecl towlower(wint_t _C); - _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswctype(wint_t _C,wctype_t _Type); - _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsymf(wint_t _C); - _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsym(wint_t _C); - _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); - int __cdecl is_wctype(wint_t _C,wctype_t _Type); - -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) -int __cdecl iswblank(wint_t _C); -#endif -#endif - -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef MB_CUR_MAX -#define MB_CUR_MAX ___mb_cur_max_func() -#ifndef __mb_cur_max -#ifdef _MSVCRT_ - extern int __mb_cur_max; -#else -#define __mb_cur_max (*_imp____mb_cur_max) - extern int *_imp____mb_cur_max; -#endif -#endif -#ifdef _MSVCRT_ -#define ___mb_cur_max_func() (__mb_cur_max) -#else -#define ___mb_cur_max_func() (*_imp____mb_cur_max) -#endif -#endif - -#define __chvalidchk(a,b) (__PCTYPE_FUNC[(a)] & (b)) -#define _chvalidchk_l(_Char,_Flag,_Locale) (!_Locale ? __chvalidchk(_Char,_Flag) : ((_locale_t)_Locale)->locinfo->pctype[_Char] & (_Flag)) -#define _ischartype_l(_Char,_Flag,_Locale) (((_Locale)!=NULL && (((_locale_t)(_Locale))->locinfo->mb_cur_max) > 1) ? _isctype_l(_Char,(_Flag),_Locale) : _chvalidchk_l(_Char,_Flag,_Locale)) -#define _isalpha_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA,_Locale) -#define _isupper_l(_Char,_Locale) _ischartype_l(_Char,_UPPER,_Locale) -#define _islower_l(_Char,_Locale) _ischartype_l(_Char,_LOWER,_Locale) -#define _isdigit_l(_Char,_Locale) _ischartype_l(_Char,_DIGIT,_Locale) -#define _isxdigit_l(_Char,_Locale) _ischartype_l(_Char,_HEX,_Locale) -#define _isspace_l(_Char,_Locale) _ischartype_l(_Char,_SPACE,_Locale) -#define _ispunct_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT,_Locale) -#define _isalnum_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA|_DIGIT,_Locale) -#define _isprint_l(_Char,_Locale) _ischartype_l(_Char,_BLANK|_PUNCT|_ALPHA|_DIGIT,_Locale) -#define _isgraph_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT|_ALPHA|_DIGIT,_Locale) -#define _iscntrl_l(_Char,_Locale) _ischartype_l(_Char,_CONTROL,_Locale) -#define _tolower(_Char) ((_Char)-'A'+'a') -#define _toupper(_Char) ((_Char)-'a'+'A') -#define __isascii(_Char) ((unsigned)(_Char) < 0x80) -#define __toascii(_Char) ((_Char) & 0x7f) - -#ifndef _WCTYPE_INLINE_DEFINED -#define _WCTYPE_INLINE_DEFINED - -#undef _CRT_WCTYPE_NOINLINE -#ifndef __cplusplus -#define iswalpha(_c) (iswctype(_c,_ALPHA)) -#define iswupper(_c) (iswctype(_c,_UPPER)) -#define iswlower(_c) (iswctype(_c,_LOWER)) -#define iswdigit(_c) (iswctype(_c,_DIGIT)) -#define iswxdigit(_c) (iswctype(_c,_HEX)) -#define iswspace(_c) (iswctype(_c,_SPACE)) -#define iswpunct(_c) (iswctype(_c,_PUNCT)) -#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) -#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) -#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) -#define iswcntrl(_c) (iswctype(_c,_CONTROL)) -#define iswascii(_c) ((unsigned)(_c) < 0x80) -#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) -#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) -#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) -#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) -#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) -#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) -#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) -#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) -#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) -#endif -#endif - -#define __iscsymf(_c) (isalpha(_c) || ((_c)=='_')) -#define __iscsym(_c) (isalnum(_c) || ((_c)=='_')) -#define __iswcsymf(_c) (iswalpha(_c) || ((_c)=='_')) -#define __iswcsym(_c) (iswalnum(_c) || ((_c)=='_')) -#define _iscsymf_l(_c,_p) (_isalpha_l(_c,_p) || ((_c)=='_')) -#define _iscsym_l(_c,_p) (_isalnum_l(_c,_p) || ((_c)=='_')) -#define _iswcsymf_l(_c,_p) (_iswalpha_l(_c,_p) || ((_c)=='_')) -#define _iswcsym_l(_c,_p) (_iswalnum_l(_c,_p) || ((_c)=='_')) -#endif - -#ifndef NO_OLDNAMES -#ifndef _CTYPE_DEFINED - int __cdecl isascii(int _C); - int __cdecl toascii(int _C); - int __cdecl iscsymf(int _C); - int __cdecl iscsym(int _C); -#else -#define isascii __isascii -#define toascii __toascii -#define iscsymf __iscsymf -#define iscsym __iscsym -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_CTYPE +#define _INC_CTYPE + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifndef _CRT_CTYPEDATA_DEFINED +#define _CRT_CTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef __PCTYPE_FUNC +#define __PCTYPE_FUNC __pctype_func() +#ifdef _MSVCRT_ +#define __pctype_func() (_pctype) +#else +#define __pctype_func() (*_imp___pctype) +#endif +#endif + +#ifndef _pctype +#ifdef _MSVCRT_ + extern unsigned short *_pctype; +#else + extern unsigned short **_imp___pctype; +#define _pctype (*_imp___pctype) +#endif +#endif + +#endif +#endif + +#ifndef _CRT_WCTYPEDATA_DEFINED +#define _CRT_WCTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS +#ifndef _wctype +#ifdef _MSVCRT_ + extern unsigned short *_wctype; +#else + extern unsigned short **_imp___wctype; +#define _wctype (*_imp___wctype) +#endif +#endif +#ifdef _MSVCRT_ +#define __pwctype_func() (_pwctype) +#ifndef _pwctype + extern unsigned short *_pwctype; +#endif +#else +#define __pwctype_func() (*_imp___pwctype) +#ifndef _pwctype + extern unsigned short **_imp___pwctype; +#define _pwctype (*_imp___pwctype) +#endif +#endif +#endif +#endif + + /* CRT stuff */ +#if 1 + extern const unsigned char __newclmap[]; + extern const unsigned char __newcumap[]; + extern pthreadlocinfo __ptlocinfo; + extern pthreadmbcinfo __ptmbcinfo; + extern int __globallocalestatus; + extern int __locale_changed; + extern struct threadlocaleinfostruct __initiallocinfo; + extern _locale_tstruct __initiallocalestructinfo; + pthreadlocinfo __cdecl __updatetlocinfo(void); + pthreadmbcinfo __cdecl __updatetmbcinfo(void); +#endif + +#define _UPPER 0x1 +#define _LOWER 0x2 +#define _DIGIT 0x4 +#define _SPACE 0x8 + +#define _PUNCT 0x10 +#define _CONTROL 0x20 +#define _BLANK 0x40 +#define _HEX 0x80 + +#define _LEADBYTE 0x8000 +#define _ALPHA (0x0100|_UPPER|_LOWER) + +#ifndef _CTYPE_DEFINED +#define _CTYPE_DEFINED + + _CRTIMP int __cdecl _isctype(int _C,int _Type); + _CRTIMP int __cdecl _isctype_l(int _C,int _Type,_locale_t _Locale); + _CRTIMP int __cdecl isalpha(int _C); + _CRTIMP int __cdecl _isalpha_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isupper(int _C); + _CRTIMP int __cdecl _isupper_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl islower(int _C); + _CRTIMP int __cdecl _islower_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isdigit(int _C); + _CRTIMP int __cdecl _isdigit_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isxdigit(int _C); + _CRTIMP int __cdecl _isxdigit_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isspace(int _C); + _CRTIMP int __cdecl _isspace_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl ispunct(int _C); + _CRTIMP int __cdecl _ispunct_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isalnum(int _C); + _CRTIMP int __cdecl _isalnum_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isprint(int _C); + _CRTIMP int __cdecl _isprint_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl isgraph(int _C); + _CRTIMP int __cdecl _isgraph_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl iscntrl(int _C); + _CRTIMP int __cdecl _iscntrl_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl toupper(int _C); + _CRTIMP int __cdecl tolower(int _C); + _CRTIMP int __cdecl _tolower(int _C); + _CRTIMP int __cdecl _tolower_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl _toupper(int _C); + _CRTIMP int __cdecl _toupper_l(int _C,_locale_t _Locale); + _CRTIMP int __cdecl __isascii(int _C); + _CRTIMP int __cdecl __toascii(int _C); + _CRTIMP int __cdecl __iscsymf(int _C); + _CRTIMP int __cdecl __iscsym(int _C); + +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) +int __cdecl isblank(int _C); +#endif +#endif + +#ifndef _WCTYPE_DEFINED +#define _WCTYPE_DEFINED + + int __cdecl iswalpha(wint_t _C); + _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); + int __cdecl iswupper(wint_t _C); + _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); + int __cdecl iswlower(wint_t _C); + _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswdigit(wint_t _C); + _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswxdigit(wint_t _C); + _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswspace(wint_t _C); + _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); + int __cdecl iswpunct(wint_t _C); + _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); + int __cdecl iswalnum(wint_t _C); + _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); + int __cdecl iswprint(wint_t _C); + _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); + int __cdecl iswgraph(wint_t _C); + _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); + int __cdecl iswcntrl(wint_t _C); + _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); + int __cdecl iswascii(wint_t _C); + int __cdecl isleadbyte(int _C); + _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); + wint_t __cdecl towupper(wint_t _C); + _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); + wint_t __cdecl towlower(wint_t _C); + _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswctype(wint_t _C,wctype_t _Type); + _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsymf(wint_t _C); + _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsym(wint_t _C); + _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); + int __cdecl is_wctype(wint_t _C,wctype_t _Type); + +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) +int __cdecl iswblank(wint_t _C); +#endif +#endif + +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef MB_CUR_MAX +#define MB_CUR_MAX ___mb_cur_max_func() +#ifndef __mb_cur_max +#ifdef _MSVCRT_ + extern int __mb_cur_max; +#else +#define __mb_cur_max (*_imp____mb_cur_max) + extern int *_imp____mb_cur_max; +#endif +#endif +#ifdef _MSVCRT_ +#define ___mb_cur_max_func() (__mb_cur_max) +#else +#define ___mb_cur_max_func() (*_imp____mb_cur_max) +#endif +#endif + +#define __chvalidchk(a,b) (__PCTYPE_FUNC[(a)] & (b)) +#define _chvalidchk_l(_Char,_Flag,_Locale) (!_Locale ? __chvalidchk(_Char,_Flag) : ((_locale_t)_Locale)->locinfo->pctype[_Char] & (_Flag)) +#define _ischartype_l(_Char,_Flag,_Locale) (((_Locale)!=NULL && (((_locale_t)(_Locale))->locinfo->mb_cur_max) > 1) ? _isctype_l(_Char,(_Flag),_Locale) : _chvalidchk_l(_Char,_Flag,_Locale)) +#define _isalpha_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA,_Locale) +#define _isupper_l(_Char,_Locale) _ischartype_l(_Char,_UPPER,_Locale) +#define _islower_l(_Char,_Locale) _ischartype_l(_Char,_LOWER,_Locale) +#define _isdigit_l(_Char,_Locale) _ischartype_l(_Char,_DIGIT,_Locale) +#define _isxdigit_l(_Char,_Locale) _ischartype_l(_Char,_HEX,_Locale) +#define _isspace_l(_Char,_Locale) _ischartype_l(_Char,_SPACE,_Locale) +#define _ispunct_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT,_Locale) +#define _isalnum_l(_Char,_Locale) _ischartype_l(_Char,_ALPHA|_DIGIT,_Locale) +#define _isprint_l(_Char,_Locale) _ischartype_l(_Char,_BLANK|_PUNCT|_ALPHA|_DIGIT,_Locale) +#define _isgraph_l(_Char,_Locale) _ischartype_l(_Char,_PUNCT|_ALPHA|_DIGIT,_Locale) +#define _iscntrl_l(_Char,_Locale) _ischartype_l(_Char,_CONTROL,_Locale) +#define _tolower(_Char) ((_Char)-'A'+'a') +#define _toupper(_Char) ((_Char)-'a'+'A') +#define __isascii(_Char) ((unsigned)(_Char) < 0x80) +#define __toascii(_Char) ((_Char) & 0x7f) + +#ifndef _WCTYPE_INLINE_DEFINED +#define _WCTYPE_INLINE_DEFINED + +#undef _CRT_WCTYPE_NOINLINE +#ifndef __cplusplus +#define iswalpha(_c) (iswctype(_c,_ALPHA)) +#define iswupper(_c) (iswctype(_c,_UPPER)) +#define iswlower(_c) (iswctype(_c,_LOWER)) +#define iswdigit(_c) (iswctype(_c,_DIGIT)) +#define iswxdigit(_c) (iswctype(_c,_HEX)) +#define iswspace(_c) (iswctype(_c,_SPACE)) +#define iswpunct(_c) (iswctype(_c,_PUNCT)) +#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) +#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) +#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) +#define iswcntrl(_c) (iswctype(_c,_CONTROL)) +#define iswascii(_c) ((unsigned)(_c) < 0x80) +#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) +#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) +#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) +#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) +#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) +#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) +#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) +#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) +#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) +#endif +#endif + +#define __iscsymf(_c) (isalpha(_c) || ((_c)=='_')) +#define __iscsym(_c) (isalnum(_c) || ((_c)=='_')) +#define __iswcsymf(_c) (iswalpha(_c) || ((_c)=='_')) +#define __iswcsym(_c) (iswalnum(_c) || ((_c)=='_')) +#define _iscsymf_l(_c,_p) (_isalpha_l(_c,_p) || ((_c)=='_')) +#define _iscsym_l(_c,_p) (_isalnum_l(_c,_p) || ((_c)=='_')) +#define _iswcsymf_l(_c,_p) (_iswalpha_l(_c,_p) || ((_c)=='_')) +#define _iswcsym_l(_c,_p) (_iswalnum_l(_c,_p) || ((_c)=='_')) +#endif + +#ifndef NO_OLDNAMES +#ifndef _CTYPE_DEFINED + int __cdecl isascii(int _C); + int __cdecl toascii(int _C); + int __cdecl iscsymf(int _C); + int __cdecl iscsym(int _C); +#else +#define isascii __isascii +#define toascii __toascii +#define iscsymf __iscsymf +#define iscsym __iscsym +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/dir.h b/tcc/include/dir.h index 71d8b4f6..f38f750d 100644 --- a/tcc/include/dir.h +++ b/tcc/include/dir.h @@ -1,31 +1,31 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * dir.h - * - * This file OBSOLESCENT and only provided for backward compatibility. - * Please use io.h instead. - * - * This file is part of the Mingw32 package. - * - * Contributors: - * Created by Colin Peters - * Mumit Khan - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#include - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * dir.h + * + * This file OBSOLESCENT and only provided for backward compatibility. + * Please use io.h instead. + * + * This file is part of the Mingw32 package. + * + * Contributors: + * Created by Colin Peters + * Mumit Khan + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include + diff --git a/tcc/include/direct.h b/tcc/include/direct.h index 3e9a4e48..99ce69db 100644 --- a/tcc/include/direct.h +++ b/tcc/include/direct.h @@ -1,68 +1,68 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_DIRECT -#define _INC_DIRECT - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _DISKFREE_T_DEFINED -#define _DISKFREE_T_DEFINED - struct _diskfree_t { - unsigned total_clusters; - unsigned avail_clusters; - unsigned sectors_per_cluster; - unsigned bytes_per_sector; - }; -#endif - - _CRTIMP char *__cdecl _getcwd(char *_DstBuf,int _SizeInBytes); - _CRTIMP char *__cdecl _getdcwd(int _Drive,char *_DstBuf,int _SizeInBytes); - char *__cdecl _getdcwd_nolock(int _Drive,char *_DstBuf,int _SizeInBytes); - _CRTIMP int __cdecl _chdir(const char *_Path); - _CRTIMP int __cdecl _mkdir(const char *_Path); - _CRTIMP int __cdecl _rmdir(const char *_Path); - _CRTIMP int __cdecl _chdrive(int _Drive); - _CRTIMP int __cdecl _getdrive(void); - _CRTIMP unsigned long __cdecl _getdrives(void); - -#ifndef _GETDISKFREE_DEFINED -#define _GETDISKFREE_DEFINED - _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); -#endif - -#ifndef _WDIRECT_DEFINED -#define _WDIRECT_DEFINED - _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); -#endif - -#ifndef NO_OLDNAMES - -#define diskfree_t _diskfree_t - - char *__cdecl getcwd(char *_DstBuf,int _SizeInBytes); - int __cdecl chdir(const char *_Path); - int __cdecl mkdir(const char *_Path); - int __cdecl rmdir(const char *_Path); -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_DIRECT +#define _INC_DIRECT + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _DISKFREE_T_DEFINED +#define _DISKFREE_T_DEFINED + struct _diskfree_t { + unsigned total_clusters; + unsigned avail_clusters; + unsigned sectors_per_cluster; + unsigned bytes_per_sector; + }; +#endif + + _CRTIMP char *__cdecl _getcwd(char *_DstBuf,int _SizeInBytes); + _CRTIMP char *__cdecl _getdcwd(int _Drive,char *_DstBuf,int _SizeInBytes); + char *__cdecl _getdcwd_nolock(int _Drive,char *_DstBuf,int _SizeInBytes); + _CRTIMP int __cdecl _chdir(const char *_Path); + _CRTIMP int __cdecl _mkdir(const char *_Path); + _CRTIMP int __cdecl _rmdir(const char *_Path); + _CRTIMP int __cdecl _chdrive(int _Drive); + _CRTIMP int __cdecl _getdrive(void); + _CRTIMP unsigned long __cdecl _getdrives(void); + +#ifndef _GETDISKFREE_DEFINED +#define _GETDISKFREE_DEFINED + _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); +#endif + +#ifndef _WDIRECT_DEFINED +#define _WDIRECT_DEFINED + _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); +#endif + +#ifndef NO_OLDNAMES + +#define diskfree_t _diskfree_t + + char *__cdecl getcwd(char *_DstBuf,int _SizeInBytes); + int __cdecl chdir(const char *_Path); + int __cdecl mkdir(const char *_Path); + int __cdecl rmdir(const char *_Path); +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/dirent.h b/tcc/include/dirent.h index 99881ba7..cd31f59e 100644 --- a/tcc/include/dirent.h +++ b/tcc/include/dirent.h @@ -1,135 +1,135 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* All the headers include this file. */ -#include <_mingw.h> - -#ifndef __STRICT_ANSI__ - -#ifndef _DIRENT_H_ -#define _DIRENT_H_ - - -#pragma pack(push,_CRT_PACKING) - -#include - -#ifndef RC_INVOKED - -#ifdef __cplusplus -extern "C" { -#endif - - struct dirent - { - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - char* d_name; /* File name. */ - /* NOTE: The name in the dirent structure points to the name in the - * finddata_t structure in the DIR. */ - }; - - /* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - * dd_stat field is now int (was short in older versions). - */ - typedef struct - { - /* disk transfer area for this dir */ - struct _finddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct dirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - char dd_name[1]; - } DIR; - - DIR* __cdecl opendir (const char*); - struct dirent* __cdecl readdir (DIR*); - int __cdecl closedir (DIR*); - void __cdecl rewinddir (DIR*); - long __cdecl telldir (DIR*); - void __cdecl seekdir (DIR*, long); - - - /* wide char versions */ - - struct _wdirent - { - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - wchar_t* d_name; /* File name. */ - /* NOTE: The name in the dirent structure points to the name in the * wfinddata_t structure in the _WDIR. */ - }; - - /* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - */ - typedef struct - { - /* disk transfer area for this dir */ - struct _wfinddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct _wdirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - wchar_t dd_name[1]; - } _WDIR; - - - - _WDIR* __cdecl _wopendir (const wchar_t*); - struct _wdirent* __cdecl _wreaddir (_WDIR*); - int __cdecl _wclosedir (_WDIR*); - void __cdecl _wrewinddir (_WDIR*); - long __cdecl _wtelldir (_WDIR*); - void __cdecl _wseekdir (_WDIR*, long); - - -#ifdef __cplusplus -} -#endif - -#endif /* Not RC_INVOKED */ - -#pragma pack(pop) - -#endif /* Not _DIRENT_H_ */ - - -#endif /* Not __STRICT_ANSI__ */ - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* All the headers include this file. */ +#include <_mingw.h> + +#ifndef __STRICT_ANSI__ + +#ifndef _DIRENT_H_ +#define _DIRENT_H_ + + +#pragma pack(push,_CRT_PACKING) + +#include + +#ifndef RC_INVOKED + +#ifdef __cplusplus +extern "C" { +#endif + + struct dirent + { + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + char* d_name; /* File name. */ + /* NOTE: The name in the dirent structure points to the name in the + * finddata_t structure in the DIR. */ + }; + + /* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + * dd_stat field is now int (was short in older versions). + */ + typedef struct + { + /* disk transfer area for this dir */ + struct _finddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct dirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + char dd_name[1]; + } DIR; + + DIR* __cdecl opendir (const char*); + struct dirent* __cdecl readdir (DIR*); + int __cdecl closedir (DIR*); + void __cdecl rewinddir (DIR*); + long __cdecl telldir (DIR*); + void __cdecl seekdir (DIR*, long); + + + /* wide char versions */ + + struct _wdirent + { + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + wchar_t* d_name; /* File name. */ + /* NOTE: The name in the dirent structure points to the name in the * wfinddata_t structure in the _WDIR. */ + }; + + /* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + */ + typedef struct + { + /* disk transfer area for this dir */ + struct _wfinddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct _wdirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + wchar_t dd_name[1]; + } _WDIR; + + + + _WDIR* __cdecl _wopendir (const wchar_t*); + struct _wdirent* __cdecl _wreaddir (_WDIR*); + int __cdecl _wclosedir (_WDIR*); + void __cdecl _wrewinddir (_WDIR*); + long __cdecl _wtelldir (_WDIR*); + void __cdecl _wseekdir (_WDIR*, long); + + +#ifdef __cplusplus +} +#endif + +#endif /* Not RC_INVOKED */ + +#pragma pack(pop) + +#endif /* Not _DIRENT_H_ */ + + +#endif /* Not __STRICT_ANSI__ */ + diff --git a/tcc/include/dos.h b/tcc/include/dos.h index 7f907d6e..294e8fe1 100644 --- a/tcc/include/dos.h +++ b/tcc/include/dos.h @@ -1,55 +1,55 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_DOS -#define _INC_DOS - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _DISKFREE_T_DEFINED -#define _DISKFREE_T_DEFINED - - struct _diskfree_t { - unsigned total_clusters; - unsigned avail_clusters; - unsigned sectors_per_cluster; - unsigned bytes_per_sector; - }; -#endif - -#define _A_NORMAL 0x00 -#define _A_RDONLY 0x01 -#define _A_HIDDEN 0x02 -#define _A_SYSTEM 0x04 -#define _A_SUBDIR 0x10 -#define _A_ARCH 0x20 - -#ifndef _GETDISKFREE_DEFINED -#define _GETDISKFREE_DEFINED - _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); -#endif - -#if (defined(_X86_) && !defined(__x86_64)) - void __cdecl _disable(void); - void __cdecl _enable(void); -#endif - -#ifndef NO_OLDNAMES -#define diskfree_t _diskfree_t -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_DOS +#define _INC_DOS + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _DISKFREE_T_DEFINED +#define _DISKFREE_T_DEFINED + + struct _diskfree_t { + unsigned total_clusters; + unsigned avail_clusters; + unsigned sectors_per_cluster; + unsigned bytes_per_sector; + }; +#endif + +#define _A_NORMAL 0x00 +#define _A_RDONLY 0x01 +#define _A_HIDDEN 0x02 +#define _A_SYSTEM 0x04 +#define _A_SUBDIR 0x10 +#define _A_ARCH 0x20 + +#ifndef _GETDISKFREE_DEFINED +#define _GETDISKFREE_DEFINED + _CRTIMP unsigned __cdecl _getdiskfree(unsigned _Drive,struct _diskfree_t *_DiskFree); +#endif + +#if (defined(_X86_) && !defined(__x86_64)) + void __cdecl _disable(void); + void __cdecl _enable(void); +#endif + +#ifndef NO_OLDNAMES +#define diskfree_t _diskfree_t +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/errno.h b/tcc/include/errno.h index 38b0b9a5..574ffa9b 100644 --- a/tcc/include/errno.h +++ b/tcc/include/errno.h @@ -1,75 +1,75 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_ERRNO -#define _INC_ERRNO - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRT_ERRNO_DEFINED -#define _CRT_ERRNO_DEFINED - _CRTIMP int *__cdecl _errno(void); -#define errno (*_errno()) - - errno_t __cdecl _set_errno(int _Value); - errno_t __cdecl _get_errno(int *_Value); -#endif - -#define EPERM 1 -#define ENOENT 2 -#define ESRCH 3 -#define EINTR 4 -#define EIO 5 -#define ENXIO 6 -#define E2BIG 7 -#define ENOEXEC 8 -#define EBADF 9 -#define ECHILD 10 -#define EAGAIN 11 -#define ENOMEM 12 -#define EACCES 13 -#define EFAULT 14 -#define EBUSY 16 -#define EEXIST 17 -#define EXDEV 18 -#define ENODEV 19 -#define ENOTDIR 20 -#define EISDIR 21 -#define ENFILE 23 -#define EMFILE 24 -#define ENOTTY 25 -#define EFBIG 27 -#define ENOSPC 28 -#define ESPIPE 29 -#define EROFS 30 -#define EMLINK 31 -#define EPIPE 32 -#define EDOM 33 -#define EDEADLK 36 -#define ENAMETOOLONG 38 -#define ENOLCK 39 -#define ENOSYS 40 -#define ENOTEMPTY 41 - -#ifndef RC_INVOKED -#if !defined(_SECURECRT_ERRCODE_VALUES_DEFINED) -#define _SECURECRT_ERRCODE_VALUES_DEFINED -#define EINVAL 22 -#define ERANGE 34 -#define EILSEQ 42 -#define STRUNCATE 80 -#endif -#endif - -#define EDEADLOCK EDEADLK - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_ERRNO +#define _INC_ERRNO + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRT_ERRNO_DEFINED +#define _CRT_ERRNO_DEFINED + _CRTIMP int *__cdecl _errno(void); +#define errno (*_errno()) + + errno_t __cdecl _set_errno(int _Value); + errno_t __cdecl _get_errno(int *_Value); +#endif + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define EDEADLK 36 +#define ENAMETOOLONG 38 +#define ENOLCK 39 +#define ENOSYS 40 +#define ENOTEMPTY 41 + +#ifndef RC_INVOKED +#if !defined(_SECURECRT_ERRCODE_VALUES_DEFINED) +#define _SECURECRT_ERRCODE_VALUES_DEFINED +#define EINVAL 22 +#define ERANGE 34 +#define EILSEQ 42 +#define STRUNCATE 80 +#endif +#endif + +#define EDEADLOCK EDEADLK + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/excpt.h b/tcc/include/excpt.h index c12a3489..26cc9437 100644 --- a/tcc/include/excpt.h +++ b/tcc/include/excpt.h @@ -1,123 +1,123 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_EXCPT -#define _INC_EXCPT - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - - struct _EXCEPTION_POINTERS; - -#ifndef EXCEPTION_DISPOSITION -#define EXCEPTION_DISPOSITION int -#endif -#define ExceptionContinueExecution 0 -#define ExceptionContinueSearch 1 -#define ExceptionNestedException 2 -#define ExceptionCollidedUnwind 3 - -#if (defined(_X86_) && !defined(__x86_64)) - struct _EXCEPTION_RECORD; - struct _CONTEXT; - - EXCEPTION_DISPOSITION __cdecl _except_handler(struct _EXCEPTION_RECORD *_ExceptionRecord,void *_EstablisherFrame,struct _CONTEXT *_ContextRecord,void *_DispatcherContext); -#elif defined(__ia64__) - - typedef struct _EXCEPTION_POINTERS *Exception_info_ptr; - struct _EXCEPTION_RECORD; - struct _CONTEXT; - struct _DISPATCHER_CONTEXT; - - _CRTIMP EXCEPTION_DISPOSITION __cdecl __C_specific_handler (struct _EXCEPTION_RECORD *_ExceptionRecord,unsigned __int64 _MemoryStackFp,unsigned __int64 _BackingStoreFp,struct _CONTEXT *_ContextRecord,struct _DISPATCHER_CONTEXT *_DispatcherContext,unsigned __int64 _GlobalPointer); -#elif defined(__x86_64) - - struct _EXCEPTION_RECORD; - struct _CONTEXT; -#endif - -#define GetExceptionCode _exception_code -#define exception_code _exception_code -#define GetExceptionInformation (struct _EXCEPTION_POINTERS *)_exception_info -#define exception_info (struct _EXCEPTION_POINTERS *)_exception_info -#define AbnormalTermination _abnormal_termination -#define abnormal_termination _abnormal_termination - - unsigned long __cdecl _exception_code(void); - void *__cdecl _exception_info(void); - int __cdecl _abnormal_termination(void); - -#define EXCEPTION_EXECUTE_HANDLER 1 -#define EXCEPTION_CONTINUE_SEARCH 0 -#define EXCEPTION_CONTINUE_EXECUTION -1 - - /* CRT stuff */ - typedef void (__cdecl * _PHNDLR)(int); - - struct _XCPT_ACTION { - unsigned long XcptNum; - int SigNum; - _PHNDLR XcptAction; - }; - - extern struct _XCPT_ACTION _XcptActTab[]; - extern int _XcptActTabCount; - extern int _XcptActTabSize; - extern int _First_FPE_Indx; - extern int _Num_FPE; - - int __cdecl __CppXcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); - int __cdecl _XcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); - - /* - * The type of function that is expected as an exception handler to be - * installed with _try1. - */ - typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); - -#ifndef HAVE_NO_SEH - /* - * This is not entirely necessary, but it is the structure installed by - * the _try1 primitive below. - */ - typedef struct _EXCEPTION_REGISTRATION { - struct _EXCEPTION_REGISTRATION *prev; - EXCEPTION_DISPOSITION (*handler)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); - } EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION; - - typedef EXCEPTION_REGISTRATION EXCEPTION_REGISTRATION_RECORD; - typedef PEXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION_RECORD; -#endif - -#if (defined(_X86_) && !defined(__x86_64)) -#define __try1(pHandler) \ - __asm__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : "g" (pHandler)); - -#define __except1 \ - __asm__ ("movl (%%esp),%%eax;movl %%eax,%%fs:0;addl $8,%%esp;" \ - : : : "%eax"); -#elif defined(__x86_64) -#define __try1(pHandler) \ - __asm__ ("pushq %0;pushq %%gs:0;movq %%rsp,%%gs:0;" : : "g" (pHandler)); - -#define __except1 \ - __asm__ ("movq (%%rsp),%%rax;movq %%rax,%%gs:0;addq $16,%%rsp;" \ - : : : "%rax"); -#else -#define __try1(pHandler) -#define __except1 -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_EXCPT +#define _INC_EXCPT + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + + struct _EXCEPTION_POINTERS; + +#ifndef EXCEPTION_DISPOSITION +#define EXCEPTION_DISPOSITION int +#endif +#define ExceptionContinueExecution 0 +#define ExceptionContinueSearch 1 +#define ExceptionNestedException 2 +#define ExceptionCollidedUnwind 3 + +#if (defined(_X86_) && !defined(__x86_64)) + struct _EXCEPTION_RECORD; + struct _CONTEXT; + + EXCEPTION_DISPOSITION __cdecl _except_handler(struct _EXCEPTION_RECORD *_ExceptionRecord,void *_EstablisherFrame,struct _CONTEXT *_ContextRecord,void *_DispatcherContext); +#elif defined(__ia64__) + + typedef struct _EXCEPTION_POINTERS *Exception_info_ptr; + struct _EXCEPTION_RECORD; + struct _CONTEXT; + struct _DISPATCHER_CONTEXT; + + _CRTIMP EXCEPTION_DISPOSITION __cdecl __C_specific_handler (struct _EXCEPTION_RECORD *_ExceptionRecord,unsigned __int64 _MemoryStackFp,unsigned __int64 _BackingStoreFp,struct _CONTEXT *_ContextRecord,struct _DISPATCHER_CONTEXT *_DispatcherContext,unsigned __int64 _GlobalPointer); +#elif defined(__x86_64) + + struct _EXCEPTION_RECORD; + struct _CONTEXT; +#endif + +#define GetExceptionCode _exception_code +#define exception_code _exception_code +#define GetExceptionInformation (struct _EXCEPTION_POINTERS *)_exception_info +#define exception_info (struct _EXCEPTION_POINTERS *)_exception_info +#define AbnormalTermination _abnormal_termination +#define abnormal_termination _abnormal_termination + + unsigned long __cdecl _exception_code(void); + void *__cdecl _exception_info(void); + int __cdecl _abnormal_termination(void); + +#define EXCEPTION_EXECUTE_HANDLER 1 +#define EXCEPTION_CONTINUE_SEARCH 0 +#define EXCEPTION_CONTINUE_EXECUTION -1 + + /* CRT stuff */ + typedef void (__cdecl * _PHNDLR)(int); + + struct _XCPT_ACTION { + unsigned long XcptNum; + int SigNum; + _PHNDLR XcptAction; + }; + + extern struct _XCPT_ACTION _XcptActTab[]; + extern int _XcptActTabCount; + extern int _XcptActTabSize; + extern int _First_FPE_Indx; + extern int _Num_FPE; + + int __cdecl __CppXcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); + int __cdecl _XcptFilter(unsigned long _ExceptionNum,struct _EXCEPTION_POINTERS * _ExceptionPtr); + + /* + * The type of function that is expected as an exception handler to be + * installed with _try1. + */ + typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); + +#ifndef HAVE_NO_SEH + /* + * This is not entirely necessary, but it is the structure installed by + * the _try1 primitive below. + */ + typedef struct _EXCEPTION_REGISTRATION { + struct _EXCEPTION_REGISTRATION *prev; + EXCEPTION_DISPOSITION (*handler)(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); + } EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION; + + typedef EXCEPTION_REGISTRATION EXCEPTION_REGISTRATION_RECORD; + typedef PEXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION_RECORD; +#endif + +#if (defined(_X86_) && !defined(__x86_64)) +#define __try1(pHandler) \ + __asm__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : "g" (pHandler)); + +#define __except1 \ + __asm__ ("movl (%%esp),%%eax;movl %%eax,%%fs:0;addl $8,%%esp;" \ + : : : "%eax"); +#elif defined(__x86_64) +#define __try1(pHandler) \ + __asm__ ("pushq %0;pushq %%gs:0;movq %%rsp,%%gs:0;" : : "g" (pHandler)); + +#define __except1 \ + __asm__ ("movq (%%rsp),%%rax;movq %%rax,%%gs:0;addq $16,%%rsp;" \ + : : : "%rax"); +#else +#define __try1(pHandler) +#define __except1 +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/fcntl.h b/tcc/include/fcntl.h index 40543e39..9202b08c 100644 --- a/tcc/include/fcntl.h +++ b/tcc/include/fcntl.h @@ -1,52 +1,52 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#include <_mingw.h> - -#include - -#ifndef _INC_FCNTL -#define _INC_FCNTL - -#define _O_RDONLY 0x0000 -#define _O_WRONLY 0x0001 -#define _O_RDWR 0x0002 -#define _O_APPEND 0x0008 -#define _O_CREAT 0x0100 -#define _O_TRUNC 0x0200 -#define _O_EXCL 0x0400 -#define _O_TEXT 0x4000 -#define _O_BINARY 0x8000 -#define _O_WTEXT 0x10000 -#define _O_U16TEXT 0x20000 -#define _O_U8TEXT 0x40000 -#define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR) - -#define _O_RAW _O_BINARY -#define _O_NOINHERIT 0x0080 -#define _O_TEMPORARY 0x0040 -#define _O_SHORT_LIVED 0x1000 - -#define _O_SEQUENTIAL 0x0020 -#define _O_RANDOM 0x0010 - -#if !defined(NO_OLDNAMES) || defined(_POSIX) -#define O_RDONLY _O_RDONLY -#define O_WRONLY _O_WRONLY -#define O_RDWR _O_RDWR -#define O_APPEND _O_APPEND -#define O_CREAT _O_CREAT -#define O_TRUNC _O_TRUNC -#define O_EXCL _O_EXCL -#define O_TEXT _O_TEXT -#define O_BINARY _O_BINARY -#define O_RAW _O_BINARY -#define O_TEMPORARY _O_TEMPORARY -#define O_NOINHERIT _O_NOINHERIT -#define O_SEQUENTIAL _O_SEQUENTIAL -#define O_RANDOM _O_RANDOM -#define O_ACCMODE _O_ACCMODE -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#include <_mingw.h> + +#include + +#ifndef _INC_FCNTL +#define _INC_FCNTL + +#define _O_RDONLY 0x0000 +#define _O_WRONLY 0x0001 +#define _O_RDWR 0x0002 +#define _O_APPEND 0x0008 +#define _O_CREAT 0x0100 +#define _O_TRUNC 0x0200 +#define _O_EXCL 0x0400 +#define _O_TEXT 0x4000 +#define _O_BINARY 0x8000 +#define _O_WTEXT 0x10000 +#define _O_U16TEXT 0x20000 +#define _O_U8TEXT 0x40000 +#define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR) + +#define _O_RAW _O_BINARY +#define _O_NOINHERIT 0x0080 +#define _O_TEMPORARY 0x0040 +#define _O_SHORT_LIVED 0x1000 + +#define _O_SEQUENTIAL 0x0020 +#define _O_RANDOM 0x0010 + +#if !defined(NO_OLDNAMES) || defined(_POSIX) +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_RDWR _O_RDWR +#define O_APPEND _O_APPEND +#define O_CREAT _O_CREAT +#define O_TRUNC _O_TRUNC +#define O_EXCL _O_EXCL +#define O_TEXT _O_TEXT +#define O_BINARY _O_BINARY +#define O_RAW _O_BINARY +#define O_TEMPORARY _O_TEMPORARY +#define O_NOINHERIT _O_NOINHERIT +#define O_SEQUENTIAL _O_SEQUENTIAL +#define O_RANDOM _O_RANDOM +#define O_ACCMODE _O_ACCMODE +#endif +#endif diff --git a/tcc/include/fenv.h b/tcc/include/fenv.h index 8efca4a0..258f3a5d 100644 --- a/tcc/include/fenv.h +++ b/tcc/include/fenv.h @@ -1,108 +1,108 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _FENV_H_ -#define _FENV_H_ - -#include <_mingw.h> - -/* FPU status word exception flags */ -#define FE_INVALID 0x01 -#define FE_DENORMAL 0x02 -#define FE_DIVBYZERO 0x04 -#define FE_OVERFLOW 0x08 -#define FE_UNDERFLOW 0x10 -#define FE_INEXACT 0x20 -#define FE_ALL_EXCEPT (FE_INVALID | FE_DENORMAL | FE_DIVBYZERO \ - | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) - -/* FPU control word rounding flags */ -#define FE_TONEAREST 0x0000 -#define FE_DOWNWARD 0x0400 -#define FE_UPWARD 0x0800 -#define FE_TOWARDZERO 0x0c00 - -/* The MXCSR exception flags are the same as the - FE flags. */ -#define __MXCSR_EXCEPT_FLAG_SHIFT 0 - -/* How much to shift FE status word exception flags - to get MXCSR rounding flags, */ -#define __MXCSR_ROUND_FLAG_SHIFT 3 - -#ifndef RC_INVOKED -/* - For now, support only for the basic abstraction of flags that are - either set or clear. fexcept_t could be structure that holds more - info about the fp environment. -*/ -typedef unsigned short fexcept_t; - -/* This 32-byte struct represents the entire floating point - environment as stored by fnstenv or fstenv, augmented by - the contents of the MXCSR register, as stored by stmxcsr - (if CPU supports it). */ -typedef struct -{ - unsigned short __control_word; - unsigned short __unused0; - unsigned short __status_word; - unsigned short __unused1; - unsigned short __tag_word; - unsigned short __unused2; - unsigned int __ip_offset; /* instruction pointer offset */ - unsigned short __ip_selector; - unsigned short __opcode; - unsigned int __data_offset; - unsigned short __data_selector; - unsigned short __unused3; - unsigned int __mxcsr; /* contents of the MXCSR register */ -} fenv_t; - - -/*The C99 standard (7.6.9) allows us to define implementation-specific macros for - different fp environments */ - -/* The default Intel x87 floating point environment (64-bit mantissa) */ -#define FE_PC64_ENV ((const fenv_t *)-1) - -/* The floating point environment set by MSVCRT _fpreset (53-bit mantissa) */ -#define FE_PC53_ENV ((const fenv_t *)-2) - -/* The FE_DFL_ENV macro is required by standard. - fesetenv will use the environment set at app startup.*/ -#define FE_DFL_ENV ((const fenv_t *) 0) - -#ifdef __cplusplus -extern "C" { -#endif - -/*TODO: Some of these could be inlined */ -/* 7.6.2 Exception */ - -extern int __cdecl feclearexcept (int); -extern int __cdecl fegetexceptflag (fexcept_t * flagp, int excepts); -extern int __cdecl feraiseexcept (int excepts ); -extern int __cdecl fesetexceptflag (const fexcept_t *, int); -extern int __cdecl fetestexcept (int excepts); - -/* 7.6.3 Rounding */ - -extern int __cdecl fegetround (void); -extern int __cdecl fesetround (int mode); - -/* 7.6.4 Environment */ - -extern int __cdecl fegetenv(fenv_t * envp); -extern int __cdecl fesetenv(const fenv_t * ); -extern int __cdecl feupdateenv(const fenv_t *); -extern int __cdecl feholdexcept(fenv_t *); - -#ifdef __cplusplus -} -#endif -#endif /* Not RC_INVOKED */ - -#endif /* ndef _FENV_H */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _FENV_H_ +#define _FENV_H_ + +#include <_mingw.h> + +/* FPU status word exception flags */ +#define FE_INVALID 0x01 +#define FE_DENORMAL 0x02 +#define FE_DIVBYZERO 0x04 +#define FE_OVERFLOW 0x08 +#define FE_UNDERFLOW 0x10 +#define FE_INEXACT 0x20 +#define FE_ALL_EXCEPT (FE_INVALID | FE_DENORMAL | FE_DIVBYZERO \ + | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) + +/* FPU control word rounding flags */ +#define FE_TONEAREST 0x0000 +#define FE_DOWNWARD 0x0400 +#define FE_UPWARD 0x0800 +#define FE_TOWARDZERO 0x0c00 + +/* The MXCSR exception flags are the same as the + FE flags. */ +#define __MXCSR_EXCEPT_FLAG_SHIFT 0 + +/* How much to shift FE status word exception flags + to get MXCSR rounding flags, */ +#define __MXCSR_ROUND_FLAG_SHIFT 3 + +#ifndef RC_INVOKED +/* + For now, support only for the basic abstraction of flags that are + either set or clear. fexcept_t could be structure that holds more + info about the fp environment. +*/ +typedef unsigned short fexcept_t; + +/* This 32-byte struct represents the entire floating point + environment as stored by fnstenv or fstenv, augmented by + the contents of the MXCSR register, as stored by stmxcsr + (if CPU supports it). */ +typedef struct +{ + unsigned short __control_word; + unsigned short __unused0; + unsigned short __status_word; + unsigned short __unused1; + unsigned short __tag_word; + unsigned short __unused2; + unsigned int __ip_offset; /* instruction pointer offset */ + unsigned short __ip_selector; + unsigned short __opcode; + unsigned int __data_offset; + unsigned short __data_selector; + unsigned short __unused3; + unsigned int __mxcsr; /* contents of the MXCSR register */ +} fenv_t; + + +/*The C99 standard (7.6.9) allows us to define implementation-specific macros for + different fp environments */ + +/* The default Intel x87 floating point environment (64-bit mantissa) */ +#define FE_PC64_ENV ((const fenv_t *)-1) + +/* The floating point environment set by MSVCRT _fpreset (53-bit mantissa) */ +#define FE_PC53_ENV ((const fenv_t *)-2) + +/* The FE_DFL_ENV macro is required by standard. + fesetenv will use the environment set at app startup.*/ +#define FE_DFL_ENV ((const fenv_t *) 0) + +#ifdef __cplusplus +extern "C" { +#endif + +/*TODO: Some of these could be inlined */ +/* 7.6.2 Exception */ + +extern int __cdecl feclearexcept (int); +extern int __cdecl fegetexceptflag (fexcept_t * flagp, int excepts); +extern int __cdecl feraiseexcept (int excepts ); +extern int __cdecl fesetexceptflag (const fexcept_t *, int); +extern int __cdecl fetestexcept (int excepts); + +/* 7.6.3 Rounding */ + +extern int __cdecl fegetround (void); +extern int __cdecl fesetround (int mode); + +/* 7.6.4 Environment */ + +extern int __cdecl fegetenv(fenv_t * envp); +extern int __cdecl fesetenv(const fenv_t * ); +extern int __cdecl feupdateenv(const fenv_t *); +extern int __cdecl feholdexcept(fenv_t *); + +#ifdef __cplusplus +} +#endif +#endif /* Not RC_INVOKED */ + +#endif /* ndef _FENV_H */ diff --git a/tcc/include/float.h b/tcc/include/float.h index b11a0ff2..35b28f2c 100644 --- a/tcc/include/float.h +++ b/tcc/include/float.h @@ -1,72 +1,72 @@ -#ifndef _FLOAT_H_ -#define _FLOAT_H_ - -#define FLT_RADIX 2 - -/* IEEE float */ -#define FLT_MANT_DIG 24 -#define FLT_DIG 6 -#define FLT_ROUNDS 1 -#define FLT_EPSILON 1.19209290e-07F -#define FLT_MIN_EXP (-125) -#define FLT_MIN 1.17549435e-38F -#define FLT_MIN_10_EXP (-37) -#define FLT_MAX_EXP 128 -#define FLT_MAX 3.40282347e+38F -#define FLT_MAX_10_EXP 38 - -/* IEEE double */ -#define DBL_MANT_DIG 53 -#define DBL_DIG 15 -#define DBL_EPSILON 2.2204460492503131e-16 -#define DBL_MIN_EXP (-1021) -#define DBL_MIN 2.2250738585072014e-308 -#define DBL_MIN_10_EXP (-307) -#define DBL_MAX_EXP 1024 -#define DBL_MAX 1.7976931348623157e+308 -#define DBL_MAX_10_EXP 308 - -/* horrible intel long double */ -#if defined __i386__ || defined __x86_64__ - -#define LDBL_MANT_DIG 64 -#define LDBL_DIG 18 -#define LDBL_EPSILON 1.08420217248550443401e-19L -#define LDBL_MIN_EXP (-16381) -#define LDBL_MIN 3.36210314311209350626e-4932L -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_EXP 16384 -#define LDBL_MAX 1.18973149535723176502e+4932L -#define LDBL_MAX_10_EXP 4932 - -#elif defined __aarch64__ || defined __riscv -/* - * Use values from: - * gcc -dM -E -xc /dev/null | grep LDBL | sed -e "s/__//g" - */ -#define LDBL_MANT_DIG 113 -#define LDBL_DIG 33 -#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L -#define LDBL_MIN_EXP (-16381) -#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_EXP 16384 -#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L -#define LDBL_MAX_EXP 16384 - -#else - -/* same as IEEE double */ -#define LDBL_MANT_DIG 53 -#define LDBL_DIG 15 -#define LDBL_EPSILON 2.2204460492503131e-16L -#define LDBL_MIN_EXP (-1021) -#define LDBL_MIN 2.2250738585072014e-308L -#define LDBL_MIN_10_EXP (-307) -#define LDBL_MAX_EXP 1024 -#define LDBL_MAX 1.7976931348623157e+308L -#define LDBL_MAX_10_EXP 308 - -#endif - -#endif /* _FLOAT_H_ */ +#ifndef _FLOAT_H_ +#define _FLOAT_H_ + +#define FLT_RADIX 2 + +/* IEEE float */ +#define FLT_MANT_DIG 24 +#define FLT_DIG 6 +#define FLT_ROUNDS 1 +#define FLT_EPSILON 1.19209290e-07F +#define FLT_MIN_EXP (-125) +#define FLT_MIN 1.17549435e-38F +#define FLT_MIN_10_EXP (-37) +#define FLT_MAX_EXP 128 +#define FLT_MAX 3.40282347e+38F +#define FLT_MAX_10_EXP 38 + +/* IEEE double */ +#define DBL_MANT_DIG 53 +#define DBL_DIG 15 +#define DBL_EPSILON 2.2204460492503131e-16 +#define DBL_MIN_EXP (-1021) +#define DBL_MIN 2.2250738585072014e-308 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_EXP 1024 +#define DBL_MAX 1.7976931348623157e+308 +#define DBL_MAX_10_EXP 308 + +/* horrible intel long double */ +#if defined __i386__ || defined __x86_64__ + +#define LDBL_MANT_DIG 64 +#define LDBL_DIG 18 +#define LDBL_EPSILON 1.08420217248550443401e-19L +#define LDBL_MIN_EXP (-16381) +#define LDBL_MIN 3.36210314311209350626e-4932L +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_EXP 16384 +#define LDBL_MAX 1.18973149535723176502e+4932L +#define LDBL_MAX_10_EXP 4932 + +#elif defined __aarch64__ || defined __riscv +/* + * Use values from: + * gcc -dM -E -xc /dev/null | grep LDBL | sed -e "s/__//g" + */ +#define LDBL_MANT_DIG 113 +#define LDBL_DIG 33 +#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L +#define LDBL_MIN_EXP (-16381) +#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_EXP 16384 +#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L +#define LDBL_MAX_EXP 16384 + +#else + +/* same as IEEE double */ +#define LDBL_MANT_DIG 53 +#define LDBL_DIG 15 +#define LDBL_EPSILON 2.2204460492503131e-16L +#define LDBL_MIN_EXP (-1021) +#define LDBL_MIN 2.2250738585072014e-308L +#define LDBL_MIN_10_EXP (-307) +#define LDBL_MAX_EXP 1024 +#define LDBL_MAX 1.7976931348623157e+308L +#define LDBL_MAX_10_EXP 308 + +#endif + +#endif /* _FLOAT_H_ */ diff --git a/tcc/include/inttypes.h b/tcc/include/inttypes.h index 08a906e1..73600919 100644 --- a/tcc/include/inttypes.h +++ b/tcc/include/inttypes.h @@ -1,297 +1,297 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* 7.8 Format conversion of integer types */ - -#ifndef _INTTYPES_H_ -#define _INTTYPES_H_ - -#include <_mingw.h> -#include -#define __need_wchar_t -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - intmax_t quot; - intmax_t rem; - } imaxdiv_t; - -#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) - -/* 7.8.1 Macros for format specifiers - * - * MS runtime does not yet understand C9x standard "ll" - * length specifier. It appears to treat "ll" as "l". - * The non-standard I64 length specifier causes warning in GCC, - * but understood by MS runtime functions. - */ - -/* fprintf macros for signed types */ -#define PRId8 "d" -#define PRId16 "d" -#define PRId32 "d" -#define PRId64 "I64d" - -#define PRIdLEAST8 "d" -#define PRIdLEAST16 "d" -#define PRIdLEAST32 "d" -#define PRIdLEAST64 "I64d" - -#define PRIdFAST8 "d" -#define PRIdFAST16 "d" -#define PRIdFAST32 "d" -#define PRIdFAST64 "I64d" - -#define PRIdMAX "I64d" - -#define PRIi8 "i" -#define PRIi16 "i" -#define PRIi32 "i" -#define PRIi64 "I64i" - -#define PRIiLEAST8 "i" -#define PRIiLEAST16 "i" -#define PRIiLEAST32 "i" -#define PRIiLEAST64 "I64i" - -#define PRIiFAST8 "i" -#define PRIiFAST16 "i" -#define PRIiFAST32 "i" -#define PRIiFAST64 "I64i" - -#define PRIiMAX "I64i" - -#define PRIo8 "o" -#define PRIo16 "o" -#define PRIo32 "o" -#define PRIo64 "I64o" - -#define PRIoLEAST8 "o" -#define PRIoLEAST16 "o" -#define PRIoLEAST32 "o" -#define PRIoLEAST64 "I64o" - -#define PRIoFAST8 "o" -#define PRIoFAST16 "o" -#define PRIoFAST32 "o" -#define PRIoFAST64 "I64o" - -#define PRIoMAX "I64o" - -/* fprintf macros for unsigned types */ -#define PRIu8 "u" -#define PRIu16 "u" -#define PRIu32 "u" -#define PRIu64 "I64u" - - -#define PRIuLEAST8 "u" -#define PRIuLEAST16 "u" -#define PRIuLEAST32 "u" -#define PRIuLEAST64 "I64u" - -#define PRIuFAST8 "u" -#define PRIuFAST16 "u" -#define PRIuFAST32 "u" -#define PRIuFAST64 "I64u" - -#define PRIuMAX "I64u" - -#define PRIx8 "x" -#define PRIx16 "x" -#define PRIx32 "x" -#define PRIx64 "I64x" - -#define PRIxLEAST8 "x" -#define PRIxLEAST16 "x" -#define PRIxLEAST32 "x" -#define PRIxLEAST64 "I64x" - -#define PRIxFAST8 "x" -#define PRIxFAST16 "x" -#define PRIxFAST32 "x" -#define PRIxFAST64 "I64x" - -#define PRIxMAX "I64x" - -#define PRIX8 "X" -#define PRIX16 "X" -#define PRIX32 "X" -#define PRIX64 "I64X" - -#define PRIXLEAST8 "X" -#define PRIXLEAST16 "X" -#define PRIXLEAST32 "X" -#define PRIXLEAST64 "I64X" - -#define PRIXFAST8 "X" -#define PRIXFAST16 "X" -#define PRIXFAST32 "X" -#define PRIXFAST64 "I64X" - -#define PRIXMAX "I64X" - -/* - * fscanf macros for signed int types - * NOTE: if 32-bit int is used for int_fast8_t and int_fast16_t - * (see stdint.h, 7.18.1.3), FAST8 and FAST16 should have - * no length identifiers - */ - -#define SCNd16 "hd" -#define SCNd32 "d" -#define SCNd64 "I64d" - -#define SCNdLEAST16 "hd" -#define SCNdLEAST32 "d" -#define SCNdLEAST64 "I64d" - -#define SCNdFAST16 "hd" -#define SCNdFAST32 "d" -#define SCNdFAST64 "I64d" - -#define SCNdMAX "I64d" - -#define SCNi16 "hi" -#define SCNi32 "i" -#define SCNi64 "I64i" - -#define SCNiLEAST16 "hi" -#define SCNiLEAST32 "i" -#define SCNiLEAST64 "I64i" - -#define SCNiFAST16 "hi" -#define SCNiFAST32 "i" -#define SCNiFAST64 "I64i" - -#define SCNiMAX "I64i" - -#define SCNo16 "ho" -#define SCNo32 "o" -#define SCNo64 "I64o" - -#define SCNoLEAST16 "ho" -#define SCNoLEAST32 "o" -#define SCNoLEAST64 "I64o" - -#define SCNoFAST16 "ho" -#define SCNoFAST32 "o" -#define SCNoFAST64 "I64o" - -#define SCNoMAX "I64o" - -#define SCNx16 "hx" -#define SCNx32 "x" -#define SCNx64 "I64x" - -#define SCNxLEAST16 "hx" -#define SCNxLEAST32 "x" -#define SCNxLEAST64 "I64x" - -#define SCNxFAST16 "hx" -#define SCNxFAST32 "x" -#define SCNxFAST64 "I64x" - -#define SCNxMAX "I64x" - -/* fscanf macros for unsigned int types */ - -#define SCNu16 "hu" -#define SCNu32 "u" -#define SCNu64 "I64u" - -#define SCNuLEAST16 "hu" -#define SCNuLEAST32 "u" -#define SCNuLEAST64 "I64u" - -#define SCNuFAST16 "hu" -#define SCNuFAST32 "u" -#define SCNuFAST64 "I64u" - -#define SCNuMAX "I64u" - -#ifdef _WIN64 -#define PRIdPTR "I64d" -#define PRIiPTR "I64i" -#define PRIoPTR "I64o" -#define PRIuPTR "I64u" -#define PRIxPTR "I64x" -#define PRIXPTR "I64X" -#define SCNdPTR "I64d" -#define SCNiPTR "I64i" -#define SCNoPTR "I64o" -#define SCNxPTR "I64x" -#define SCNuPTR "I64u" -#else -#define PRIdPTR "d" -#define PRIiPTR "i" -#define PRIoPTR "o" -#define PRIuPTR "u" -#define PRIxPTR "x" -#define PRIXPTR "X" -#define SCNdPTR "d" -#define SCNiPTR "i" -#define SCNoPTR "o" -#define SCNxPTR "x" -#define SCNuPTR "u" -#endif - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -/* - * no length modifier for char types prior to C9x - * MS runtime scanf appears to treat "hh" as "h" - */ - -/* signed char */ -#define SCNd8 "hhd" -#define SCNdLEAST8 "hhd" -#define SCNdFAST8 "hhd" - -#define SCNi8 "hhi" -#define SCNiLEAST8 "hhi" -#define SCNiFAST8 "hhi" - -#define SCNo8 "hho" -#define SCNoLEAST8 "hho" -#define SCNoFAST8 "hho" - -#define SCNx8 "hhx" -#define SCNxLEAST8 "hhx" -#define SCNxFAST8 "hhx" - -/* unsigned char */ -#define SCNu8 "hhu" -#define SCNuLEAST8 "hhu" -#define SCNuFAST8 "hhu" -#endif /* __STDC_VERSION__ >= 199901 */ - -#endif /* !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) */ - -intmax_t __cdecl imaxabs (intmax_t j); -__CRT_INLINE intmax_t __cdecl imaxabs (intmax_t j) - {return (j >= 0 ? j : -j);} -imaxdiv_t __cdecl imaxdiv (intmax_t numer, intmax_t denom); - -/* 7.8.2 Conversion functions for greatest-width integer types */ - -intmax_t __cdecl strtoimax (const char* __restrict__ nptr, - char** __restrict__ endptr, int base); -uintmax_t __cdecl strtoumax (const char* __restrict__ nptr, - char** __restrict__ endptr, int base); - -intmax_t __cdecl wcstoimax (const wchar_t* __restrict__ nptr, - wchar_t** __restrict__ endptr, int base); -uintmax_t __cdecl wcstoumax (const wchar_t* __restrict__ nptr, - wchar_t** __restrict__ endptr, int base); - -#ifdef __cplusplus -} -#endif - -#endif /* ndef _INTTYPES_H */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* 7.8 Format conversion of integer types */ + +#ifndef _INTTYPES_H_ +#define _INTTYPES_H_ + +#include <_mingw.h> +#include +#define __need_wchar_t +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + intmax_t quot; + intmax_t rem; + } imaxdiv_t; + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) + +/* 7.8.1 Macros for format specifiers + * + * MS runtime does not yet understand C9x standard "ll" + * length specifier. It appears to treat "ll" as "l". + * The non-standard I64 length specifier causes warning in GCC, + * but understood by MS runtime functions. + */ + +/* fprintf macros for signed types */ +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "d" +#define PRId64 "I64d" + +#define PRIdLEAST8 "d" +#define PRIdLEAST16 "d" +#define PRIdLEAST32 "d" +#define PRIdLEAST64 "I64d" + +#define PRIdFAST8 "d" +#define PRIdFAST16 "d" +#define PRIdFAST32 "d" +#define PRIdFAST64 "I64d" + +#define PRIdMAX "I64d" + +#define PRIi8 "i" +#define PRIi16 "i" +#define PRIi32 "i" +#define PRIi64 "I64i" + +#define PRIiLEAST8 "i" +#define PRIiLEAST16 "i" +#define PRIiLEAST32 "i" +#define PRIiLEAST64 "I64i" + +#define PRIiFAST8 "i" +#define PRIiFAST16 "i" +#define PRIiFAST32 "i" +#define PRIiFAST64 "I64i" + +#define PRIiMAX "I64i" + +#define PRIo8 "o" +#define PRIo16 "o" +#define PRIo32 "o" +#define PRIo64 "I64o" + +#define PRIoLEAST8 "o" +#define PRIoLEAST16 "o" +#define PRIoLEAST32 "o" +#define PRIoLEAST64 "I64o" + +#define PRIoFAST8 "o" +#define PRIoFAST16 "o" +#define PRIoFAST32 "o" +#define PRIoFAST64 "I64o" + +#define PRIoMAX "I64o" + +/* fprintf macros for unsigned types */ +#define PRIu8 "u" +#define PRIu16 "u" +#define PRIu32 "u" +#define PRIu64 "I64u" + + +#define PRIuLEAST8 "u" +#define PRIuLEAST16 "u" +#define PRIuLEAST32 "u" +#define PRIuLEAST64 "I64u" + +#define PRIuFAST8 "u" +#define PRIuFAST16 "u" +#define PRIuFAST32 "u" +#define PRIuFAST64 "I64u" + +#define PRIuMAX "I64u" + +#define PRIx8 "x" +#define PRIx16 "x" +#define PRIx32 "x" +#define PRIx64 "I64x" + +#define PRIxLEAST8 "x" +#define PRIxLEAST16 "x" +#define PRIxLEAST32 "x" +#define PRIxLEAST64 "I64x" + +#define PRIxFAST8 "x" +#define PRIxFAST16 "x" +#define PRIxFAST32 "x" +#define PRIxFAST64 "I64x" + +#define PRIxMAX "I64x" + +#define PRIX8 "X" +#define PRIX16 "X" +#define PRIX32 "X" +#define PRIX64 "I64X" + +#define PRIXLEAST8 "X" +#define PRIXLEAST16 "X" +#define PRIXLEAST32 "X" +#define PRIXLEAST64 "I64X" + +#define PRIXFAST8 "X" +#define PRIXFAST16 "X" +#define PRIXFAST32 "X" +#define PRIXFAST64 "I64X" + +#define PRIXMAX "I64X" + +/* + * fscanf macros for signed int types + * NOTE: if 32-bit int is used for int_fast8_t and int_fast16_t + * (see stdint.h, 7.18.1.3), FAST8 and FAST16 should have + * no length identifiers + */ + +#define SCNd16 "hd" +#define SCNd32 "d" +#define SCNd64 "I64d" + +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "d" +#define SCNdLEAST64 "I64d" + +#define SCNdFAST16 "hd" +#define SCNdFAST32 "d" +#define SCNdFAST64 "I64d" + +#define SCNdMAX "I64d" + +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 "I64i" + +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "i" +#define SCNiLEAST64 "I64i" + +#define SCNiFAST16 "hi" +#define SCNiFAST32 "i" +#define SCNiFAST64 "I64i" + +#define SCNiMAX "I64i" + +#define SCNo16 "ho" +#define SCNo32 "o" +#define SCNo64 "I64o" + +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "o" +#define SCNoLEAST64 "I64o" + +#define SCNoFAST16 "ho" +#define SCNoFAST32 "o" +#define SCNoFAST64 "I64o" + +#define SCNoMAX "I64o" + +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 "I64x" + +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "x" +#define SCNxLEAST64 "I64x" + +#define SCNxFAST16 "hx" +#define SCNxFAST32 "x" +#define SCNxFAST64 "I64x" + +#define SCNxMAX "I64x" + +/* fscanf macros for unsigned int types */ + +#define SCNu16 "hu" +#define SCNu32 "u" +#define SCNu64 "I64u" + +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "u" +#define SCNuLEAST64 "I64u" + +#define SCNuFAST16 "hu" +#define SCNuFAST32 "u" +#define SCNuFAST64 "I64u" + +#define SCNuMAX "I64u" + +#ifdef _WIN64 +#define PRIdPTR "I64d" +#define PRIiPTR "I64i" +#define PRIoPTR "I64o" +#define PRIuPTR "I64u" +#define PRIxPTR "I64x" +#define PRIXPTR "I64X" +#define SCNdPTR "I64d" +#define SCNiPTR "I64i" +#define SCNoPTR "I64o" +#define SCNxPTR "I64x" +#define SCNuPTR "I64u" +#else +#define PRIdPTR "d" +#define PRIiPTR "i" +#define PRIoPTR "o" +#define PRIuPTR "u" +#define PRIxPTR "x" +#define PRIXPTR "X" +#define SCNdPTR "d" +#define SCNiPTR "i" +#define SCNoPTR "o" +#define SCNxPTR "x" +#define SCNuPTR "u" +#endif + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +/* + * no length modifier for char types prior to C9x + * MS runtime scanf appears to treat "hh" as "h" + */ + +/* signed char */ +#define SCNd8 "hhd" +#define SCNdLEAST8 "hhd" +#define SCNdFAST8 "hhd" + +#define SCNi8 "hhi" +#define SCNiLEAST8 "hhi" +#define SCNiFAST8 "hhi" + +#define SCNo8 "hho" +#define SCNoLEAST8 "hho" +#define SCNoFAST8 "hho" + +#define SCNx8 "hhx" +#define SCNxLEAST8 "hhx" +#define SCNxFAST8 "hhx" + +/* unsigned char */ +#define SCNu8 "hhu" +#define SCNuLEAST8 "hhu" +#define SCNuFAST8 "hhu" +#endif /* __STDC_VERSION__ >= 199901 */ + +#endif /* !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) */ + +intmax_t __cdecl imaxabs (intmax_t j); +__CRT_INLINE intmax_t __cdecl imaxabs (intmax_t j) + {return (j >= 0 ? j : -j);} +imaxdiv_t __cdecl imaxdiv (intmax_t numer, intmax_t denom); + +/* 7.8.2 Conversion functions for greatest-width integer types */ + +intmax_t __cdecl strtoimax (const char* __restrict__ nptr, + char** __restrict__ endptr, int base); +uintmax_t __cdecl strtoumax (const char* __restrict__ nptr, + char** __restrict__ endptr, int base); + +intmax_t __cdecl wcstoimax (const wchar_t* __restrict__ nptr, + wchar_t** __restrict__ endptr, int base); +uintmax_t __cdecl wcstoumax (const wchar_t* __restrict__ nptr, + wchar_t** __restrict__ endptr, int base); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef _INTTYPES_H */ diff --git a/tcc/include/io.h b/tcc/include/io.h index 2cd96045..e2aeec3d 100644 --- a/tcc/include/io.h +++ b/tcc/include/io.h @@ -1,418 +1,418 @@ - -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _IO_H_ -#define _IO_H_ - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifndef _POSIX_ - -#ifdef __cplusplus -extern "C" { -#endif - -_CRTIMP char* __cdecl _getcwd (char*, int); -#ifndef _FSIZE_T_DEFINED - typedef unsigned long _fsize_t; -#define _FSIZE_T_DEFINED -#endif - -#ifndef _FINDDATA_T_DEFINED - - struct _finddata32_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - _fsize_t size; - char name[260]; - }; - -/*#if _INTEGRAL_MAX_BITS >= 64*/ - - struct _finddata32i64_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - __int64 size; - char name[260]; - }; - - struct _finddata64i32_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - _fsize_t size; - char name[260]; - }; - - struct __finddata64_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - __int64 size; - char name[260]; - }; -/* #endif */ - -#ifdef _USE_32BIT_TIME_T -#define _finddata_t _finddata32_t -#define _finddatai64_t _finddata32i64_t - -#ifdef _WIN64 -#define _findfirst _findfirst32 -#define _findnext _findnext32 -#else -#define _findfirst32 _findfirst -#define _findnext32 _findnext -#endif -#define _findfirsti64 _findfirst32i64 -#define _findnexti64 _findnext32i64 -#else -#define _finddata_t _finddata64i32_t -#define _finddatai64_t __finddata64_t - -#define _findfirst _findfirst64i32 -#define _findnext _findnext64i32 -#define _findfirsti64 _findfirst64 -#define _findnexti64 _findnext64 -#endif - -#define _FINDDATA_T_DEFINED -#endif - -#ifndef _WFINDDATA_T_DEFINED - - struct _wfinddata32_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - -/* #if _INTEGRAL_MAX_BITS >= 64 */ - - struct _wfinddata32i64_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - __int64 size; - wchar_t name[260]; - }; - - struct _wfinddata64i32_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - - struct _wfinddata64_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - __int64 size; - wchar_t name[260]; - }; -/* #endif */ - -#ifdef _USE_32BIT_TIME_T -#define _wfinddata_t _wfinddata32_t -#define _wfinddatai64_t _wfinddata32i64_t - -#define _wfindfirst _wfindfirst32 -#define _wfindnext _wfindnext32 -#define _wfindfirsti64 _wfindfirst32i64 -#define _wfindnexti64 _wfindnext32i64 -#else -#define _wfinddata_t _wfinddata64i32_t -#define _wfinddatai64_t _wfinddata64_t - -#define _wfindfirst _wfindfirst64i32 -#define _wfindnext _wfindnext64i32 -#define _wfindfirsti64 _wfindfirst64 -#define _wfindnexti64 _wfindnext64 -#endif - -#define _WFINDDATA_T_DEFINED -#endif - -#define _A_NORMAL 0x00 -#define _A_RDONLY 0x01 -#define _A_HIDDEN 0x02 -#define _A_SYSTEM 0x04 -#define _A_SUBDIR 0x10 -#define _A_ARCH 0x20 - -#ifndef _SIZE_T_DEFINED -#define _SIZE_T_DEFINED -#undef size_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef unsigned int size_t __attribute__ ((mode (DI))); -#else - typedef unsigned __int64 size_t; -#endif -#else - typedef unsigned int size_t; -#endif -#endif - -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#undef ssize_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int ssize_t __attribute__ ((mode (DI))); -#else - typedef __int64 ssize_t; -#endif -#else - typedef int ssize_t; -#endif -#endif - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int _off64_t __attribute__ ((mode (DI))); -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef int off64_t __attribute__ ((mode (DI))); -#endif -#else - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif -#endif - - /* Some defines for _access nAccessMode (MS doesn't define them, but - * it doesn't seem to hurt to add them). */ -#define F_OK 0 /* Check for file existence */ -#define X_OK 1 /* Check for execute permission. */ -#define W_OK 2 /* Check for write permission */ -#define R_OK 4 /* Check for read permission */ - - _CRTIMP int __cdecl _access(const char *_Filename,int _AccessMode); - _CRTIMP int __cdecl _chmod(const char *_Filename,int _Mode); - _CRTIMP int __cdecl _chsize(int _FileHandle,long _Size); - _CRTIMP int __cdecl _close(int _FileHandle); - _CRTIMP int __cdecl _commit(int _FileHandle); - _CRTIMP int __cdecl _creat(const char *_Filename,int _PermissionMode); - _CRTIMP int __cdecl _dup(int _FileHandle); - _CRTIMP int __cdecl _dup2(int _FileHandleSrc,int _FileHandleDst); - _CRTIMP int __cdecl _eof(int _FileHandle); - _CRTIMP long __cdecl _filelength(int _FileHandle); - _CRTIMP intptr_t __cdecl _findfirst32(const char *_Filename,struct _finddata32_t *_FindData); - _CRTIMP int __cdecl _findnext32(intptr_t _FindHandle,struct _finddata32_t *_FindData); - _CRTIMP int __cdecl _findclose(intptr_t _FindHandle); - _CRTIMP int __cdecl _isatty(int _FileHandle); - _CRTIMP int __cdecl _locking(int _FileHandle,int _LockMode,long _NumOfBytes); - _CRTIMP long __cdecl _lseek(int _FileHandle,long _Offset,int _Origin); - _off64_t lseek64(int fd,_off64_t offset, int whence); - _CRTIMP char *__cdecl _mktemp(char *_TemplateName); - _CRTIMP int __cdecl _pipe(int *_PtHandles,unsigned int _PipeSize,int _TextMode); - _CRTIMP int __cdecl _read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); - -#ifndef _CRT_DIRECTORY_DEFINED -#define _CRT_DIRECTORY_DEFINED - int __cdecl remove(const char *_Filename); - int __cdecl rename(const char *_OldFilename,const char *_NewFilename); - _CRTIMP int __cdecl _unlink(const char *_Filename); -#ifndef NO_OLDNAMES - int __cdecl unlink(const char *_Filename); -#endif -#endif - - _CRTIMP int __cdecl _setmode(int _FileHandle,int _Mode); - _CRTIMP long __cdecl _tell(int _FileHandle); - _CRTIMP int __cdecl _umask(int _Mode); - _CRTIMP int __cdecl _write(int _FileHandle,const void *_Buf,unsigned int _MaxCharCount); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP __int64 __cdecl _filelengthi64(int _FileHandle); - _CRTIMP intptr_t __cdecl _findfirst32i64(const char *_Filename,struct _finddata32i64_t *_FindData); - _CRTIMP intptr_t __cdecl _findfirst64(const char *_Filename,struct __finddata64_t *_FindData); -#ifdef __cplusplus -#include -#endif - intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData); - __CRT_INLINE intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData) - { - struct __finddata64_t fd; - intptr_t ret = _findfirst64(_Filename,&fd); - _FindData->attrib=fd.attrib; - _FindData->time_create=fd.time_create; - _FindData->time_access=fd.time_access; - _FindData->time_write=fd.time_write; - _FindData->size=(_fsize_t) fd.size; - strncpy(_FindData->name,fd.name,260); - return ret; - } - _CRTIMP int __cdecl _findnext32i64(intptr_t _FindHandle,struct _finddata32i64_t *_FindData); - _CRTIMP int __cdecl _findnext64(intptr_t _FindHandle,struct __finddata64_t *_FindData); - int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData); - __CRT_INLINE int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData) - { - struct __finddata64_t fd; - int ret = _findnext64(_FindHandle,&fd); - _FindData->attrib=fd.attrib; - _FindData->time_create=fd.time_create; - _FindData->time_access=fd.time_access; - _FindData->time_write=fd.time_write; - _FindData->size=(_fsize_t) fd.size; - strncpy(_FindData->name,fd.name,260); - return ret; - } - __int64 __cdecl _lseeki64(int _FileHandle,__int64 _Offset,int _Origin); - __int64 __cdecl _telli64(int _FileHandle); -#endif -#ifndef NO_OLDNAMES - -#ifndef _UWIN - int __cdecl chdir (const char *); - char *__cdecl getcwd (char *, int); - int __cdecl mkdir (const char *); - char *__cdecl mktemp(char *); - int __cdecl rmdir (const char*); - int __cdecl chmod (const char *, int); -#endif /* _UWIN */ - -#endif /* Not NO_OLDNAMES */ - - _CRTIMP errno_t __cdecl _sopen_s(int *_FileHandle,const char *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode); - -#ifndef __cplusplus - _CRTIMP int __cdecl _open(const char *_Filename,int _OpenFlag,...); - _CRTIMP int __cdecl _sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); -#else - extern "C++" _CRTIMP int __cdecl _open(const char *_Filename,int _Openflag,int _PermissionMode = 0); - extern "C++" _CRTIMP int __cdecl _sopen(const char *_Filename,int _Openflag,int _ShareFlag,int _PermissionMode = 0); -#endif - -#ifndef _WIO_DEFINED -#define _WIO_DEFINED - _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); - _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); - _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); - _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); - _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); - _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); - intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); - _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); - _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); - int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); - _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); -#endif - - _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); - -#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) - _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); - _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); -#else - extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); - extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); -#endif - -#endif - - int __cdecl __lock_fhandle(int _Filehandle); - void __cdecl _unlock_fhandle(int _Filehandle); - _CRTIMP intptr_t __cdecl _get_osfhandle(int _FileHandle); - _CRTIMP int __cdecl _open_osfhandle(intptr_t _OSFileHandle,int _Flags); - -#ifndef NO_OLDNAMES - int __cdecl access(const char *_Filename,int _AccessMode); - int __cdecl chmod(const char *_Filename,int _AccessMode); - int __cdecl chsize(int _FileHandle,long _Size); - int __cdecl close(int _FileHandle); - int __cdecl creat(const char *_Filename,int _PermissionMode); - int __cdecl dup(int _FileHandle); - int __cdecl dup2(int _FileHandleSrc,int _FileHandleDst); - int __cdecl eof(int _FileHandle); - long __cdecl filelength(int _FileHandle); - int __cdecl isatty(int _FileHandle); - int __cdecl locking(int _FileHandle,int _LockMode,long _NumOfBytes); - long __cdecl lseek(int _FileHandle,long _Offset,int _Origin); - char *__cdecl mktemp(char *_TemplateName); - int __cdecl open(const char *_Filename,int _OpenFlag,...); - int __cdecl read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); - int __cdecl setmode(int _FileHandle,int _Mode); - int __cdecl sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); - long __cdecl tell(int _FileHandle); - int __cdecl umask(int _Mode); - int __cdecl write(int _Filehandle,const void *_Buf,unsigned int _MaxCharCount); -#endif - -#ifdef __cplusplus -} -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Misc stuff */ -char *getlogin(void); -#ifdef __USE_MINGW_ALARM -unsigned int alarm(unsigned int seconds); -#endif - -#ifdef __USE_MINGW_ACCESS -/* Old versions of MSVCRT access() just ignored X_OK, while the version - shipped with Vista, returns an error code. This will restore the - old behaviour */ -static inline int __mingw_access (const char *__fname, int __mode) { - return _access (__fname, __mode & ~X_OK); -} - -#define access(__f,__m) __mingw_access (__f, __m) -#endif - - -#ifdef __cplusplus -} -#endif - - -#pragma pack(pop) - -#include - -#endif /* End _IO_H_ */ - + +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _IO_H_ +#define _IO_H_ + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifndef _POSIX_ + +#ifdef __cplusplus +extern "C" { +#endif + +_CRTIMP char* __cdecl _getcwd (char*, int); +#ifndef _FSIZE_T_DEFINED + typedef unsigned long _fsize_t; +#define _FSIZE_T_DEFINED +#endif + +#ifndef _FINDDATA_T_DEFINED + + struct _finddata32_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + _fsize_t size; + char name[260]; + }; + +/*#if _INTEGRAL_MAX_BITS >= 64*/ + + struct _finddata32i64_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + __int64 size; + char name[260]; + }; + + struct _finddata64i32_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + _fsize_t size; + char name[260]; + }; + + struct __finddata64_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + __int64 size; + char name[260]; + }; +/* #endif */ + +#ifdef _USE_32BIT_TIME_T +#define _finddata_t _finddata32_t +#define _finddatai64_t _finddata32i64_t + +#ifdef _WIN64 +#define _findfirst _findfirst32 +#define _findnext _findnext32 +#else +#define _findfirst32 _findfirst +#define _findnext32 _findnext +#endif +#define _findfirsti64 _findfirst32i64 +#define _findnexti64 _findnext32i64 +#else +#define _finddata_t _finddata64i32_t +#define _finddatai64_t __finddata64_t + +#define _findfirst _findfirst64i32 +#define _findnext _findnext64i32 +#define _findfirsti64 _findfirst64 +#define _findnexti64 _findnext64 +#endif + +#define _FINDDATA_T_DEFINED +#endif + +#ifndef _WFINDDATA_T_DEFINED + + struct _wfinddata32_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + +/* #if _INTEGRAL_MAX_BITS >= 64 */ + + struct _wfinddata32i64_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + __int64 size; + wchar_t name[260]; + }; + + struct _wfinddata64i32_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + + struct _wfinddata64_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + __int64 size; + wchar_t name[260]; + }; +/* #endif */ + +#ifdef _USE_32BIT_TIME_T +#define _wfinddata_t _wfinddata32_t +#define _wfinddatai64_t _wfinddata32i64_t + +#define _wfindfirst _wfindfirst32 +#define _wfindnext _wfindnext32 +#define _wfindfirsti64 _wfindfirst32i64 +#define _wfindnexti64 _wfindnext32i64 +#else +#define _wfinddata_t _wfinddata64i32_t +#define _wfinddatai64_t _wfinddata64_t + +#define _wfindfirst _wfindfirst64i32 +#define _wfindnext _wfindnext64i32 +#define _wfindfirsti64 _wfindfirst64 +#define _wfindnexti64 _wfindnext64 +#endif + +#define _WFINDDATA_T_DEFINED +#endif + +#define _A_NORMAL 0x00 +#define _A_RDONLY 0x01 +#define _A_HIDDEN 0x02 +#define _A_SYSTEM 0x04 +#define _A_SUBDIR 0x10 +#define _A_ARCH 0x20 + +#ifndef _SIZE_T_DEFINED +#define _SIZE_T_DEFINED +#undef size_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef unsigned int size_t __attribute__ ((mode (DI))); +#else + typedef unsigned __int64 size_t; +#endif +#else + typedef unsigned int size_t; +#endif +#endif + +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#undef ssize_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int ssize_t __attribute__ ((mode (DI))); +#else + typedef __int64 ssize_t; +#endif +#else + typedef int ssize_t; +#endif +#endif + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int _off64_t __attribute__ ((mode (DI))); +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef int off64_t __attribute__ ((mode (DI))); +#endif +#else + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif +#endif + + /* Some defines for _access nAccessMode (MS doesn't define them, but + * it doesn't seem to hurt to add them). */ +#define F_OK 0 /* Check for file existence */ +#define X_OK 1 /* Check for execute permission. */ +#define W_OK 2 /* Check for write permission */ +#define R_OK 4 /* Check for read permission */ + + _CRTIMP int __cdecl _access(const char *_Filename,int _AccessMode); + _CRTIMP int __cdecl _chmod(const char *_Filename,int _Mode); + _CRTIMP int __cdecl _chsize(int _FileHandle,long _Size); + _CRTIMP int __cdecl _close(int _FileHandle); + _CRTIMP int __cdecl _commit(int _FileHandle); + _CRTIMP int __cdecl _creat(const char *_Filename,int _PermissionMode); + _CRTIMP int __cdecl _dup(int _FileHandle); + _CRTIMP int __cdecl _dup2(int _FileHandleSrc,int _FileHandleDst); + _CRTIMP int __cdecl _eof(int _FileHandle); + _CRTIMP long __cdecl _filelength(int _FileHandle); + _CRTIMP intptr_t __cdecl _findfirst32(const char *_Filename,struct _finddata32_t *_FindData); + _CRTIMP int __cdecl _findnext32(intptr_t _FindHandle,struct _finddata32_t *_FindData); + _CRTIMP int __cdecl _findclose(intptr_t _FindHandle); + _CRTIMP int __cdecl _isatty(int _FileHandle); + _CRTIMP int __cdecl _locking(int _FileHandle,int _LockMode,long _NumOfBytes); + _CRTIMP long __cdecl _lseek(int _FileHandle,long _Offset,int _Origin); + _off64_t lseek64(int fd,_off64_t offset, int whence); + _CRTIMP char *__cdecl _mktemp(char *_TemplateName); + _CRTIMP int __cdecl _pipe(int *_PtHandles,unsigned int _PipeSize,int _TextMode); + _CRTIMP int __cdecl _read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); + +#ifndef _CRT_DIRECTORY_DEFINED +#define _CRT_DIRECTORY_DEFINED + int __cdecl remove(const char *_Filename); + int __cdecl rename(const char *_OldFilename,const char *_NewFilename); + _CRTIMP int __cdecl _unlink(const char *_Filename); +#ifndef NO_OLDNAMES + int __cdecl unlink(const char *_Filename); +#endif +#endif + + _CRTIMP int __cdecl _setmode(int _FileHandle,int _Mode); + _CRTIMP long __cdecl _tell(int _FileHandle); + _CRTIMP int __cdecl _umask(int _Mode); + _CRTIMP int __cdecl _write(int _FileHandle,const void *_Buf,unsigned int _MaxCharCount); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP __int64 __cdecl _filelengthi64(int _FileHandle); + _CRTIMP intptr_t __cdecl _findfirst32i64(const char *_Filename,struct _finddata32i64_t *_FindData); + _CRTIMP intptr_t __cdecl _findfirst64(const char *_Filename,struct __finddata64_t *_FindData); +#ifdef __cplusplus +#include +#endif + intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData); + __CRT_INLINE intptr_t __cdecl _findfirst64i32(const char *_Filename,struct _finddata64i32_t *_FindData) + { + struct __finddata64_t fd; + intptr_t ret = _findfirst64(_Filename,&fd); + _FindData->attrib=fd.attrib; + _FindData->time_create=fd.time_create; + _FindData->time_access=fd.time_access; + _FindData->time_write=fd.time_write; + _FindData->size=(_fsize_t) fd.size; + strncpy(_FindData->name,fd.name,260); + return ret; + } + _CRTIMP int __cdecl _findnext32i64(intptr_t _FindHandle,struct _finddata32i64_t *_FindData); + _CRTIMP int __cdecl _findnext64(intptr_t _FindHandle,struct __finddata64_t *_FindData); + int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData); + __CRT_INLINE int __cdecl _findnext64i32(intptr_t _FindHandle,struct _finddata64i32_t *_FindData) + { + struct __finddata64_t fd; + int ret = _findnext64(_FindHandle,&fd); + _FindData->attrib=fd.attrib; + _FindData->time_create=fd.time_create; + _FindData->time_access=fd.time_access; + _FindData->time_write=fd.time_write; + _FindData->size=(_fsize_t) fd.size; + strncpy(_FindData->name,fd.name,260); + return ret; + } + __int64 __cdecl _lseeki64(int _FileHandle,__int64 _Offset,int _Origin); + __int64 __cdecl _telli64(int _FileHandle); +#endif +#ifndef NO_OLDNAMES + +#ifndef _UWIN + int __cdecl chdir (const char *); + char *__cdecl getcwd (char *, int); + int __cdecl mkdir (const char *); + char *__cdecl mktemp(char *); + int __cdecl rmdir (const char*); + int __cdecl chmod (const char *, int); +#endif /* _UWIN */ + +#endif /* Not NO_OLDNAMES */ + + _CRTIMP errno_t __cdecl _sopen_s(int *_FileHandle,const char *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode); + +#ifndef __cplusplus + _CRTIMP int __cdecl _open(const char *_Filename,int _OpenFlag,...); + _CRTIMP int __cdecl _sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); +#else + extern "C++" _CRTIMP int __cdecl _open(const char *_Filename,int _Openflag,int _PermissionMode = 0); + extern "C++" _CRTIMP int __cdecl _sopen(const char *_Filename,int _Openflag,int _ShareFlag,int _PermissionMode = 0); +#endif + +#ifndef _WIO_DEFINED +#define _WIO_DEFINED + _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); + _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); + _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); + _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); + _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); + _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); + intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); + _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); + _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); + int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); + _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); +#endif + + _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); + +#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) + _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); + _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); +#else + extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); + extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); +#endif + +#endif + + int __cdecl __lock_fhandle(int _Filehandle); + void __cdecl _unlock_fhandle(int _Filehandle); + _CRTIMP intptr_t __cdecl _get_osfhandle(int _FileHandle); + _CRTIMP int __cdecl _open_osfhandle(intptr_t _OSFileHandle,int _Flags); + +#ifndef NO_OLDNAMES + int __cdecl access(const char *_Filename,int _AccessMode); + int __cdecl chmod(const char *_Filename,int _AccessMode); + int __cdecl chsize(int _FileHandle,long _Size); + int __cdecl close(int _FileHandle); + int __cdecl creat(const char *_Filename,int _PermissionMode); + int __cdecl dup(int _FileHandle); + int __cdecl dup2(int _FileHandleSrc,int _FileHandleDst); + int __cdecl eof(int _FileHandle); + long __cdecl filelength(int _FileHandle); + int __cdecl isatty(int _FileHandle); + int __cdecl locking(int _FileHandle,int _LockMode,long _NumOfBytes); + long __cdecl lseek(int _FileHandle,long _Offset,int _Origin); + char *__cdecl mktemp(char *_TemplateName); + int __cdecl open(const char *_Filename,int _OpenFlag,...); + int __cdecl read(int _FileHandle,void *_DstBuf,unsigned int _MaxCharCount); + int __cdecl setmode(int _FileHandle,int _Mode); + int __cdecl sopen(const char *_Filename,int _OpenFlag,int _ShareFlag,...); + long __cdecl tell(int _FileHandle); + int __cdecl umask(int _Mode); + int __cdecl write(int _Filehandle,const void *_Buf,unsigned int _MaxCharCount); +#endif + +#ifdef __cplusplus +} +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Misc stuff */ +char *getlogin(void); +#ifdef __USE_MINGW_ALARM +unsigned int alarm(unsigned int seconds); +#endif + +#ifdef __USE_MINGW_ACCESS +/* Old versions of MSVCRT access() just ignored X_OK, while the version + shipped with Vista, returns an error code. This will restore the + old behaviour */ +static inline int __mingw_access (const char *__fname, int __mode) { + return _access (__fname, __mode & ~X_OK); +} + +#define access(__f,__m) __mingw_access (__f, __m) +#endif + + +#ifdef __cplusplus +} +#endif + + +#pragma pack(pop) + +#include + +#endif /* End _IO_H_ */ + diff --git a/tcc/include/iso646.h b/tcc/include/iso646.h index 2cea9a65..02770f6b 100644 --- a/tcc/include/iso646.h +++ b/tcc/include/iso646.h @@ -1,36 +1,36 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the TinyCC package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -/* - * ISO C Standard: 7.9 Alternative spellings - */ - -#ifndef _ISO646_H_ -#define _ISO646_H_ - -#define and && -#define and_eq &= -#define bitand & -#define bitor | -#define compl ~ -#define not ! -#define not_eq != -#define or || -#define or_eq |= -#define xor ^ -#define xor_eq ^= - -#endif /* _ISO646_H_ */ - - - - - - - - - - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the TinyCC package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +/* + * ISO C Standard: 7.9 Alternative spellings + */ + +#ifndef _ISO646_H_ +#define _ISO646_H_ + +#define and && +#define and_eq &= +#define bitand & +#define bitor | +#define compl ~ +#define not ! +#define not_eq != +#define or || +#define or_eq |= +#define xor ^ +#define xor_eq ^= + +#endif /* _ISO646_H_ */ + + + + + + + + + + diff --git a/tcc/include/limits.h b/tcc/include/limits.h index 816a5e97..498e02e4 100644 --- a/tcc/include/limits.h +++ b/tcc/include/limits.h @@ -1,116 +1,116 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#include <_mingw.h> - -#ifndef _INC_LIMITS -#define _INC_LIMITS - -/* -* File system limits -* -* TODO: NAME_MAX and OPEN_MAX are file system limits or not? Are they the -* same as FILENAME_MAX and FOPEN_MAX from stdio.h? -* NOTE: Apparently the actual size of PATH_MAX is 260, but a space is -* required for the NUL. TODO: Test? -*/ -#define PATH_MAX (259) - -#define CHAR_BIT 8 -#define SCHAR_MIN (-128) -#define SCHAR_MAX 127 -#define UCHAR_MAX 0xff - -#ifndef __CHAR_UNSIGNED__ -#define CHAR_MIN SCHAR_MIN -#define CHAR_MAX SCHAR_MAX -#else -#define CHAR_MIN 0 -#define CHAR_MAX UCHAR_MAX -#endif - -#define MB_LEN_MAX 5 -#define SHRT_MIN (-32768) -#define SHRT_MAX 32767 -#define USHRT_MAX 0xffff -#define INT_MIN (-2147483647 - 1) -#define INT_MAX 2147483647 -#define UINT_MAX 0xffffffff -#define LONG_MIN (-2147483647L - 1) -#define LONG_MAX 2147483647L -#define ULONG_MAX 0xffffffffUL -#define LLONG_MAX 9223372036854775807ll -#define LLONG_MIN (-9223372036854775807ll - 1) -#define ULLONG_MAX 0xffffffffffffffffull - -#if _INTEGRAL_MAX_BITS >= 8 -#define _I8_MIN (-127 - 1) -#define _I8_MAX 127i8 -#define _UI8_MAX 0xffu -#endif - -#if _INTEGRAL_MAX_BITS >= 16 -#define _I16_MIN (-32767 - 1) -#define _I16_MAX 32767i16 -#define _UI16_MAX 0xffffu -#endif - -#if _INTEGRAL_MAX_BITS >= 32 -#define _I32_MIN (-2147483647 - 1) -#define _I32_MAX 2147483647 -#define _UI32_MAX 0xffffffffu -#endif - -#if defined(__GNUC__) -#undef LONG_LONG_MAX -#define LONG_LONG_MAX 9223372036854775807ll -#undef LONG_LONG_MIN -#define LONG_LONG_MIN (-LONG_LONG_MAX-1) -#undef ULONG_LONG_MAX -#define ULONG_LONG_MAX (2ull * LONG_LONG_MAX + 1ull) -#endif - -#if _INTEGRAL_MAX_BITS >= 64 -#define _I64_MIN (-9223372036854775807ll - 1) -#define _I64_MAX 9223372036854775807ll -#define _UI64_MAX 0xffffffffffffffffull -#endif - -#ifndef SIZE_MAX -#ifdef _WIN64 -#define SIZE_MAX _UI64_MAX -#else -#define SIZE_MAX UINT_MAX -#endif -#endif - -#ifdef _POSIX_ -#define _POSIX_ARG_MAX 4096 -#define _POSIX_CHILD_MAX 6 -#define _POSIX_LINK_MAX 8 -#define _POSIX_MAX_CANON 255 -#define _POSIX_MAX_INPUT 255 -#define _POSIX_NAME_MAX 14 -#define _POSIX_NGROUPS_MAX 0 -#define _POSIX_OPEN_MAX 16 -#define _POSIX_PATH_MAX 255 -#define _POSIX_PIPE_BUF 512 -#define _POSIX_SSIZE_MAX 32767 -#define _POSIX_STREAM_MAX 8 -#define _POSIX_TZNAME_MAX 3 -#define ARG_MAX 14500 -#define LINK_MAX 1024 -#define MAX_CANON _POSIX_MAX_CANON -#define MAX_INPUT _POSIX_MAX_INPUT -#define NAME_MAX 255 -#define NGROUPS_MAX 16 -#define OPEN_MAX 32 -#define PATH_MAX 512 -#define PIPE_BUF _POSIX_PIPE_BUF -#define SSIZE_MAX _POSIX_SSIZE_MAX -#define STREAM_MAX 20 -#define TZNAME_MAX 10 -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#include <_mingw.h> + +#ifndef _INC_LIMITS +#define _INC_LIMITS + +/* +* File system limits +* +* TODO: NAME_MAX and OPEN_MAX are file system limits or not? Are they the +* same as FILENAME_MAX and FOPEN_MAX from stdio.h? +* NOTE: Apparently the actual size of PATH_MAX is 260, but a space is +* required for the NUL. TODO: Test? +*/ +#define PATH_MAX (259) + +#define CHAR_BIT 8 +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 +#define UCHAR_MAX 0xff + +#ifndef __CHAR_UNSIGNED__ +#define CHAR_MIN SCHAR_MIN +#define CHAR_MAX SCHAR_MAX +#else +#define CHAR_MIN 0 +#define CHAR_MAX UCHAR_MAX +#endif + +#define MB_LEN_MAX 5 +#define SHRT_MIN (-32768) +#define SHRT_MAX 32767 +#define USHRT_MAX 0xffff +#define INT_MIN (-2147483647 - 1) +#define INT_MAX 2147483647 +#define UINT_MAX 0xffffffff +#define LONG_MIN (-2147483647L - 1) +#define LONG_MAX 2147483647L +#define ULONG_MAX 0xffffffffUL +#define LLONG_MAX 9223372036854775807ll +#define LLONG_MIN (-9223372036854775807ll - 1) +#define ULLONG_MAX 0xffffffffffffffffull + +#if _INTEGRAL_MAX_BITS >= 8 +#define _I8_MIN (-127 - 1) +#define _I8_MAX 127i8 +#define _UI8_MAX 0xffu +#endif + +#if _INTEGRAL_MAX_BITS >= 16 +#define _I16_MIN (-32767 - 1) +#define _I16_MAX 32767i16 +#define _UI16_MAX 0xffffu +#endif + +#if _INTEGRAL_MAX_BITS >= 32 +#define _I32_MIN (-2147483647 - 1) +#define _I32_MAX 2147483647 +#define _UI32_MAX 0xffffffffu +#endif + +#if defined(__GNUC__) +#undef LONG_LONG_MAX +#define LONG_LONG_MAX 9223372036854775807ll +#undef LONG_LONG_MIN +#define LONG_LONG_MIN (-LONG_LONG_MAX-1) +#undef ULONG_LONG_MAX +#define ULONG_LONG_MAX (2ull * LONG_LONG_MAX + 1ull) +#endif + +#if _INTEGRAL_MAX_BITS >= 64 +#define _I64_MIN (-9223372036854775807ll - 1) +#define _I64_MAX 9223372036854775807ll +#define _UI64_MAX 0xffffffffffffffffull +#endif + +#ifndef SIZE_MAX +#ifdef _WIN64 +#define SIZE_MAX _UI64_MAX +#else +#define SIZE_MAX UINT_MAX +#endif +#endif + +#ifdef _POSIX_ +#define _POSIX_ARG_MAX 4096 +#define _POSIX_CHILD_MAX 6 +#define _POSIX_LINK_MAX 8 +#define _POSIX_MAX_CANON 255 +#define _POSIX_MAX_INPUT 255 +#define _POSIX_NAME_MAX 14 +#define _POSIX_NGROUPS_MAX 0 +#define _POSIX_OPEN_MAX 16 +#define _POSIX_PATH_MAX 255 +#define _POSIX_PIPE_BUF 512 +#define _POSIX_SSIZE_MAX 32767 +#define _POSIX_STREAM_MAX 8 +#define _POSIX_TZNAME_MAX 3 +#define ARG_MAX 14500 +#define LINK_MAX 1024 +#define MAX_CANON _POSIX_MAX_CANON +#define MAX_INPUT _POSIX_MAX_INPUT +#define NAME_MAX 255 +#define NGROUPS_MAX 16 +#define OPEN_MAX 32 +#define PATH_MAX 512 +#define PIPE_BUF _POSIX_PIPE_BUF +#define SSIZE_MAX _POSIX_SSIZE_MAX +#define STREAM_MAX 20 +#define TZNAME_MAX 10 +#endif +#endif diff --git a/tcc/include/locale.h b/tcc/include/locale.h index 64bfc6d4..686aa9ba 100644 --- a/tcc/include/locale.h +++ b/tcc/include/locale.h @@ -1,91 +1,91 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_LOCALE -#define _INC_LOCALE - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define LC_ALL 0 -#define LC_COLLATE 1 -#define LC_CTYPE 2 -#define LC_MONETARY 3 -#define LC_NUMERIC 4 -#define LC_TIME 5 - -#define LC_MIN LC_ALL -#define LC_MAX LC_TIME - -#ifndef _LCONV_DEFINED -#define _LCONV_DEFINED - struct lconv { - char *decimal_point; - char *thousands_sep; - char *grouping; - char *int_curr_symbol; - char *currency_symbol; - char *mon_decimal_point; - char *mon_thousands_sep; - char *mon_grouping; - char *positive_sign; - char *negative_sign; - char int_frac_digits; - char frac_digits; - char p_cs_precedes; - char p_sep_by_space; - char n_cs_precedes; - char n_sep_by_space; - char p_sign_posn; - char n_sign_posn; - }; -#endif - -#ifndef _CONFIG_LOCALE_SWT -#define _CONFIG_LOCALE_SWT - -#define _ENABLE_PER_THREAD_LOCALE 0x1 -#define _DISABLE_PER_THREAD_LOCALE 0x2 -#define _ENABLE_PER_THREAD_LOCALE_GLOBAL 0x10 -#define _DISABLE_PER_THREAD_LOCALE_GLOBAL 0x20 -#define _ENABLE_PER_THREAD_LOCALE_NEW 0x100 -#define _DISABLE_PER_THREAD_LOCALE_NEW 0x200 - -#endif - - int __cdecl _configthreadlocale(int _Flag); - char *__cdecl setlocale(int _Category,const char *_Locale); - _CRTIMP struct lconv *__cdecl localeconv(void); - _locale_t __cdecl _get_current_locale(void); - _locale_t __cdecl _create_locale(int _Category,const char *_Locale); - void __cdecl _free_locale(_locale_t _Locale); - _locale_t __cdecl __get_current_locale(void); - _locale_t __cdecl __create_locale(int _Category,const char *_Locale); - void __cdecl __free_locale(_locale_t _Locale); - -#ifndef _WLOCALE_DEFINED -#define _WLOCALE_DEFINED - _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_LOCALE +#define _INC_LOCALE + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define LC_ALL 0 +#define LC_COLLATE 1 +#define LC_CTYPE 2 +#define LC_MONETARY 3 +#define LC_NUMERIC 4 +#define LC_TIME 5 + +#define LC_MIN LC_ALL +#define LC_MAX LC_TIME + +#ifndef _LCONV_DEFINED +#define _LCONV_DEFINED + struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + }; +#endif + +#ifndef _CONFIG_LOCALE_SWT +#define _CONFIG_LOCALE_SWT + +#define _ENABLE_PER_THREAD_LOCALE 0x1 +#define _DISABLE_PER_THREAD_LOCALE 0x2 +#define _ENABLE_PER_THREAD_LOCALE_GLOBAL 0x10 +#define _DISABLE_PER_THREAD_LOCALE_GLOBAL 0x20 +#define _ENABLE_PER_THREAD_LOCALE_NEW 0x100 +#define _DISABLE_PER_THREAD_LOCALE_NEW 0x200 + +#endif + + int __cdecl _configthreadlocale(int _Flag); + char *__cdecl setlocale(int _Category,const char *_Locale); + _CRTIMP struct lconv *__cdecl localeconv(void); + _locale_t __cdecl _get_current_locale(void); + _locale_t __cdecl _create_locale(int _Category,const char *_Locale); + void __cdecl _free_locale(_locale_t _Locale); + _locale_t __cdecl __get_current_locale(void); + _locale_t __cdecl __create_locale(int _Category,const char *_Locale); + void __cdecl __free_locale(_locale_t _Locale); + +#ifndef _WLOCALE_DEFINED +#define _WLOCALE_DEFINED + _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/malloc.h b/tcc/include/malloc.h index 6e42432e..fc783a8e 100644 --- a/tcc/include/malloc.h +++ b/tcc/include/malloc.h @@ -1,181 +1,181 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _MALLOC_H_ -#define _MALLOC_H_ - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifndef _MM_MALLOC_H_INCLUDED -#define _MM_MALLOC_H_INCLUDED -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _WIN64 -#define _HEAP_MAXREQ 0xFFFFFFFFFFFFFFE0 -#else -#define _HEAP_MAXREQ 0xFFFFFFE0 -#endif - -#ifndef _STATIC_ASSERT -#define _STATIC_ASSERT(expr) extern void __static_assert_t(int [(expr)?1:-1]) -#endif - -/* Return codes for _heapwalk() */ -#define _HEAPEMPTY (-1) -#define _HEAPOK (-2) -#define _HEAPBADBEGIN (-3) -#define _HEAPBADNODE (-4) -#define _HEAPEND (-5) -#define _HEAPBADPTR (-6) - -/* Values for _heapinfo.useflag */ -#define _FREEENTRY 0 -#define _USEDENTRY 1 - -#ifndef _HEAPINFO_DEFINED -#define _HEAPINFO_DEFINED - /* The structure used to walk through the heap with _heapwalk. */ - typedef struct _heapinfo { - int *_pentry; - size_t _size; - int _useflag; - } _HEAPINFO; -#endif - - extern unsigned int _amblksiz; - -#define _mm_free(a) _aligned_free(a) -#define _mm_malloc(a,b) _aligned_malloc(a,b) - -#ifndef _CRT_ALLOCATION_DEFINED -#define _CRT_ALLOCATION_DEFINED - void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); - void __cdecl free(void *_Memory); - void *__cdecl malloc(size_t _Size); - void *__cdecl realloc(void *_Memory,size_t _NewSize); - _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); - /* _CRTIMP void __cdecl _aligned_free(void *_Memory); - _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); */ - _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); -#endif - -#define _MAX_WAIT_MALLOC_CRT 60000 - - _CRTIMP int __cdecl _resetstkoflw (void); - _CRTIMP unsigned long __cdecl _set_malloc_crt_max_wait(unsigned long _NewValue); - - _CRTIMP void *__cdecl _expand(void *_Memory,size_t _NewSize); - _CRTIMP size_t __cdecl _msize(void *_Memory); -#ifdef __GNUC__ -#undef _alloca -#define _alloca(x) __builtin_alloca((x)) -#else - /* tcc implements alloca internally and exposes it (since commit d778bde7). - /* alloca is declared at include/stddef.h (which is distributed with tcc). - */ -#ifdef _alloca -#undef _alloca -#endif -#define _alloca(x) alloca((x)) -#endif - _CRTIMP size_t __cdecl _get_sbh_threshold(void); - _CRTIMP int __cdecl _set_sbh_threshold(size_t _NewValue); - _CRTIMP errno_t __cdecl _set_amblksiz(size_t _Value); - _CRTIMP errno_t __cdecl _get_amblksiz(size_t *_Value); - _CRTIMP int __cdecl _heapadd(void *_Memory,size_t _Size); - _CRTIMP int __cdecl _heapchk(void); - _CRTIMP int __cdecl _heapmin(void); - _CRTIMP int __cdecl _heapset(unsigned int _Fill); - _CRTIMP int __cdecl _heapwalk(_HEAPINFO *_EntryInfo); - _CRTIMP size_t __cdecl _heapused(size_t *_Used,size_t *_Commit); - _CRTIMP intptr_t __cdecl _get_heap_handle(void); - -#define _ALLOCA_S_THRESHOLD 1024 -#define _ALLOCA_S_STACK_MARKER 0xCCCC -#define _ALLOCA_S_HEAP_MARKER 0xDDDD - -#if(defined(_X86_) && !defined(__x86_64)) -#define _ALLOCA_S_MARKER_SIZE 8 -#elif defined(__ia64__) || defined(__x86_64) -#define _ALLOCA_S_MARKER_SIZE 16 -#endif - -#if !defined(RC_INVOKED) - static __inline void *_MarkAllocaS(void *_Ptr,unsigned int _Marker) { - if(_Ptr) { - *((unsigned int*)_Ptr) = _Marker; - _Ptr = (char*)_Ptr + _ALLOCA_S_MARKER_SIZE; - } - return _Ptr; - } -#endif - -#undef _malloca -#define _malloca(size) \ - ((((size) + _ALLOCA_S_MARKER_SIZE) <= _ALLOCA_S_THRESHOLD) ? \ - _MarkAllocaS(_alloca((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_STACK_MARKER) : \ - _MarkAllocaS(malloc((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_HEAP_MARKER)) -#undef _FREEA_INLINE -#define _FREEA_INLINE - -#ifndef RC_INVOKED -#undef _freea - static __inline void __cdecl _freea(void *_Memory) { - unsigned int _Marker; - if(_Memory) { - _Memory = (char*)_Memory - _ALLOCA_S_MARKER_SIZE; - _Marker = *(unsigned int *)_Memory; - if(_Marker==_ALLOCA_S_HEAP_MARKER) { - free(_Memory); - } -#ifdef _ASSERTE - else if(_Marker!=_ALLOCA_S_STACK_MARKER) { - _ASSERTE(("Corrupted pointer passed to _freea",0)); - } -#endif - } - } -#endif /* RC_INVOKED */ - -#ifndef NO_OLDNAMES -#ifdef __GNUC__ -#undef alloca -#define alloca(x) __builtin_alloca((x)) -#endif -#endif - -#ifdef HEAPHOOK -#ifndef _HEAPHOOK_DEFINED -#define _HEAPHOOK_DEFINED - typedef int (__cdecl *_HEAPHOOK)(int,size_t,void *,void **); -#endif - - _CRTIMP _HEAPHOOK __cdecl _setheaphook(_HEAPHOOK _NewHook); - -#define _HEAP_MALLOC 1 -#define _HEAP_CALLOC 2 -#define _HEAP_FREE 3 -#define _HEAP_REALLOC 4 -#define _HEAP_MSIZE 5 -#define _HEAP_EXPAND 6 -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#endif /* _MALLOC_H_ */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _MALLOC_H_ +#define _MALLOC_H_ + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifndef _MM_MALLOC_H_INCLUDED +#define _MM_MALLOC_H_INCLUDED +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN64 +#define _HEAP_MAXREQ 0xFFFFFFFFFFFFFFE0 +#else +#define _HEAP_MAXREQ 0xFFFFFFE0 +#endif + +#ifndef _STATIC_ASSERT +#define _STATIC_ASSERT(expr) extern void __static_assert_t(int [(expr)?1:-1]) +#endif + +/* Return codes for _heapwalk() */ +#define _HEAPEMPTY (-1) +#define _HEAPOK (-2) +#define _HEAPBADBEGIN (-3) +#define _HEAPBADNODE (-4) +#define _HEAPEND (-5) +#define _HEAPBADPTR (-6) + +/* Values for _heapinfo.useflag */ +#define _FREEENTRY 0 +#define _USEDENTRY 1 + +#ifndef _HEAPINFO_DEFINED +#define _HEAPINFO_DEFINED + /* The structure used to walk through the heap with _heapwalk. */ + typedef struct _heapinfo { + int *_pentry; + size_t _size; + int _useflag; + } _HEAPINFO; +#endif + + extern unsigned int _amblksiz; + +#define _mm_free(a) _aligned_free(a) +#define _mm_malloc(a,b) _aligned_malloc(a,b) + +#ifndef _CRT_ALLOCATION_DEFINED +#define _CRT_ALLOCATION_DEFINED + void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); + void __cdecl free(void *_Memory); + void *__cdecl malloc(size_t _Size); + void *__cdecl realloc(void *_Memory,size_t _NewSize); + _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); + /* _CRTIMP void __cdecl _aligned_free(void *_Memory); + _CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); */ + _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); +#endif + +#define _MAX_WAIT_MALLOC_CRT 60000 + + _CRTIMP int __cdecl _resetstkoflw (void); + _CRTIMP unsigned long __cdecl _set_malloc_crt_max_wait(unsigned long _NewValue); + + _CRTIMP void *__cdecl _expand(void *_Memory,size_t _NewSize); + _CRTIMP size_t __cdecl _msize(void *_Memory); +#ifdef __GNUC__ +#undef _alloca +#define _alloca(x) __builtin_alloca((x)) +#else + /* tcc implements alloca internally and exposes it (since commit d778bde7). + /* alloca is declared at include/stddef.h (which is distributed with tcc). + */ +#ifdef _alloca +#undef _alloca +#endif +#define _alloca(x) alloca((x)) +#endif + _CRTIMP size_t __cdecl _get_sbh_threshold(void); + _CRTIMP int __cdecl _set_sbh_threshold(size_t _NewValue); + _CRTIMP errno_t __cdecl _set_amblksiz(size_t _Value); + _CRTIMP errno_t __cdecl _get_amblksiz(size_t *_Value); + _CRTIMP int __cdecl _heapadd(void *_Memory,size_t _Size); + _CRTIMP int __cdecl _heapchk(void); + _CRTIMP int __cdecl _heapmin(void); + _CRTIMP int __cdecl _heapset(unsigned int _Fill); + _CRTIMP int __cdecl _heapwalk(_HEAPINFO *_EntryInfo); + _CRTIMP size_t __cdecl _heapused(size_t *_Used,size_t *_Commit); + _CRTIMP intptr_t __cdecl _get_heap_handle(void); + +#define _ALLOCA_S_THRESHOLD 1024 +#define _ALLOCA_S_STACK_MARKER 0xCCCC +#define _ALLOCA_S_HEAP_MARKER 0xDDDD + +#if(defined(_X86_) && !defined(__x86_64)) +#define _ALLOCA_S_MARKER_SIZE 8 +#elif defined(__ia64__) || defined(__x86_64) +#define _ALLOCA_S_MARKER_SIZE 16 +#endif + +#if !defined(RC_INVOKED) + static __inline void *_MarkAllocaS(void *_Ptr,unsigned int _Marker) { + if(_Ptr) { + *((unsigned int*)_Ptr) = _Marker; + _Ptr = (char*)_Ptr + _ALLOCA_S_MARKER_SIZE; + } + return _Ptr; + } +#endif + +#undef _malloca +#define _malloca(size) \ + ((((size) + _ALLOCA_S_MARKER_SIZE) <= _ALLOCA_S_THRESHOLD) ? \ + _MarkAllocaS(_alloca((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_STACK_MARKER) : \ + _MarkAllocaS(malloc((size) + _ALLOCA_S_MARKER_SIZE),_ALLOCA_S_HEAP_MARKER)) +#undef _FREEA_INLINE +#define _FREEA_INLINE + +#ifndef RC_INVOKED +#undef _freea + static __inline void __cdecl _freea(void *_Memory) { + unsigned int _Marker; + if(_Memory) { + _Memory = (char*)_Memory - _ALLOCA_S_MARKER_SIZE; + _Marker = *(unsigned int *)_Memory; + if(_Marker==_ALLOCA_S_HEAP_MARKER) { + free(_Memory); + } +#ifdef _ASSERTE + else if(_Marker!=_ALLOCA_S_STACK_MARKER) { + _ASSERTE(("Corrupted pointer passed to _freea",0)); + } +#endif + } + } +#endif /* RC_INVOKED */ + +#ifndef NO_OLDNAMES +#ifdef __GNUC__ +#undef alloca +#define alloca(x) __builtin_alloca((x)) +#endif +#endif + +#ifdef HEAPHOOK +#ifndef _HEAPHOOK_DEFINED +#define _HEAPHOOK_DEFINED + typedef int (__cdecl *_HEAPHOOK)(int,size_t,void *,void **); +#endif + + _CRTIMP _HEAPHOOK __cdecl _setheaphook(_HEAPHOOK _NewHook); + +#define _HEAP_MALLOC 1 +#define _HEAP_CALLOC 2 +#define _HEAP_FREE 3 +#define _HEAP_REALLOC 4 +#define _HEAP_MSIZE 5 +#define _HEAP_EXPAND 6 +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#endif /* _MALLOC_H_ */ diff --git a/tcc/include/math.h b/tcc/include/math.h index 1b2c2b23..8e66407e 100644 --- a/tcc/include/math.h +++ b/tcc/include/math.h @@ -1,497 +1,497 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _MATH_H_ -#define _MATH_H_ - -#if __GNUC__ >= 3 -#pragma GCC system_header -#endif - -#include <_mingw.h> - -struct exception; - -#pragma pack(push,_CRT_PACKING) - -#define _DOMAIN 1 -#define _SING 2 -#define _OVERFLOW 3 -#define _UNDERFLOW 4 -#define _TLOSS 5 -#define _PLOSS 6 - -#ifndef __STRICT_ANSI__ -#ifndef NO_OLDNAMES -#define DOMAIN _DOMAIN -#define SING _SING -#define OVERFLOW _OVERFLOW -#define UNDERFLOW _UNDERFLOW -#define TLOSS _TLOSS -#define PLOSS _PLOSS -#endif -#endif - -#ifndef __STRICT_ANSI__ -#define M_E 2.71828182845904523536 -#define M_LOG2E 1.44269504088896340736 -#define M_LOG10E 0.434294481903251827651 -#define M_LN2 0.693147180559945309417 -#define M_LN10 2.30258509299404568402 -#define M_PI 3.14159265358979323846 -#define M_PI_2 1.57079632679489661923 -#define M_PI_4 0.785398163397448309616 -#define M_1_PI 0.318309886183790671538 -#define M_2_PI 0.636619772367581343076 -#define M_2_SQRTPI 1.12837916709551257390 -#define M_SQRT2 1.41421356237309504880 -#define M_SQRT1_2 0.707106781186547524401 -#endif - -#ifndef __STRICT_ANSI__ -/* See also float.h */ -#ifndef __MINGW_FPCLASS_DEFINED -#define __MINGW_FPCLASS_DEFINED 1 -#define _FPCLASS_SNAN 0x0001 /* Signaling "Not a Number" */ -#define _FPCLASS_QNAN 0x0002 /* Quiet "Not a Number" */ -#define _FPCLASS_NINF 0x0004 /* Negative Infinity */ -#define _FPCLASS_NN 0x0008 /* Negative Normal */ -#define _FPCLASS_ND 0x0010 /* Negative Denormal */ -#define _FPCLASS_NZ 0x0020 /* Negative Zero */ -#define _FPCLASS_PZ 0x0040 /* Positive Zero */ -#define _FPCLASS_PD 0x0080 /* Positive Denormal */ -#define _FPCLASS_PN 0x0100 /* Positive Normal */ -#define _FPCLASS_PINF 0x0200 /* Positive Infinity */ -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _EXCEPTION_DEFINED -#define _EXCEPTION_DEFINED - struct _exception { - int type; - char *name; - double arg1; - double arg2; - double retval; - }; -#endif - -#ifndef _COMPLEX_DEFINED -#define _COMPLEX_DEFINED - struct _complex { - double x,y; - }; -#endif - -#define EDOM 33 -#define ERANGE 34 - -#ifndef _HUGE -#ifdef _MSVCRT_ - extern double *_HUGE; -#else - extern double *_imp___HUGE; -#define _HUGE (*_imp___HUGE) -#endif -#endif - -#define HUGE_VAL _HUGE - -#ifndef _CRT_ABS_DEFINED -#define _CRT_ABS_DEFINED - int __cdecl abs(int _X); - long __cdecl labs(long _X); -#endif - double __cdecl acos(double _X); - double __cdecl asin(double _X); - double __cdecl atan(double _X); - double __cdecl atan2(double _Y,double _X); -#ifndef _SIGN_DEFINED -#define _SIGN_DEFINED - _CRTIMP double __cdecl _copysign (double _Number,double _Sign); - _CRTIMP double __cdecl _chgsign (double _X); -#endif - double __cdecl cos(double _X); - double __cdecl cosh(double _X); - double __cdecl exp(double _X); - double __cdecl expm1(double _X); - double __cdecl fabs(double _X); - double __cdecl fmod(double _X,double _Y); - double __cdecl log(double _X); - double __cdecl log10(double _X); - double __cdecl pow(double _X,double _Y); - double __cdecl sin(double _X); - double __cdecl sinh(double _X); - double __cdecl tan(double _X); - double __cdecl tanh(double _X); - double __cdecl sqrt(double _X); -#ifndef _CRT_ATOF_DEFINED -#define _CRT_ATOF_DEFINED - double __cdecl atof(const char *_String); - double __cdecl _atof_l(const char *_String,_locale_t _Locale); -#endif - - _CRTIMP double __cdecl _cabs(struct _complex _ComplexA); - double __cdecl ceil(double _X); - double __cdecl floor(double _X); - double __cdecl frexp(double _X,int *_Y); - double __cdecl _hypot(double _X,double _Y); - _CRTIMP double __cdecl _j0(double _X); - _CRTIMP double __cdecl _j1(double _X); - _CRTIMP double __cdecl _jn(int _X,double _Y); - double __cdecl ldexp(double _X,int _Y); -#ifndef _CRT_MATHERR_DEFINED -#define _CRT_MATHERR_DEFINED - int __cdecl _matherr(struct _exception *_Except); -#endif - double __cdecl modf(double _X,double *_Y); - _CRTIMP double __cdecl _y0(double _X); - _CRTIMP double __cdecl _y1(double _X); - _CRTIMP double __cdecl _yn(int _X,double _Y); - -#if(defined(_X86_) && !defined(__x86_64)) - _CRTIMP int __cdecl _set_SSE2_enable(int _Flag); - /* from libmingwex */ - float __cdecl _hypotf(float _X,float _Y); -#endif - - float frexpf(float _X,int *_Y); - float __cdecl ldexpf(float _X,int _Y); - long double __cdecl ldexpl(long double _X,int _Y); - float __cdecl acosf(float _X); - float __cdecl asinf(float _X); - float __cdecl atanf(float _X); - float __cdecl atan2f(float _X,float _Y); - float __cdecl cosf(float _X); - float __cdecl sinf(float _X); - float __cdecl tanf(float _X); - float __cdecl coshf(float _X); - float __cdecl sinhf(float _X); - float __cdecl tanhf(float _X); - float __cdecl expf(float _X); - float __cdecl expm1f(float _X); - float __cdecl logf(float _X); - float __cdecl log10f(float _X); - float __cdecl modff(float _X,float *_Y); - float __cdecl powf(float _X,float _Y); - float __cdecl sqrtf(float _X); - float __cdecl ceilf(float _X); - float __cdecl floorf(float _X); - float __cdecl fmodf(float _X,float _Y); - float __cdecl _hypotf(float _X,float _Y); - float __cdecl fabsf(float _X); -#if !defined(__ia64__) - /* from libmingwex */ - float __cdecl _copysignf (float _Number,float _Sign); - float __cdecl _chgsignf (float _X); - float __cdecl _logbf(float _X); - float __cdecl _nextafterf(float _X,float _Y); - int __cdecl _finitef(float _X); - int __cdecl _isnanf(float _X); - int __cdecl _fpclassf(float _X); -#endif - -#ifndef NO_OLDNAMES -#define matherr _matherr - -#define HUGE _HUGE - /* double __cdecl cabs(struct _complex _X); */ - double __cdecl hypot(double _X,double _Y); - _CRTIMP double __cdecl j0(double _X); - _CRTIMP double __cdecl j1(double _X); - _CRTIMP double __cdecl jn(int _X,double _Y); - _CRTIMP double __cdecl y0(double _X); - _CRTIMP double __cdecl y1(double _X); - _CRTIMP double __cdecl yn(int _X,double _Y); -#endif - -#ifndef __NO_ISOCEXT -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \ - || !defined __STRICT_ANSI__ || defined __GLIBCPP__ - -#define NAN (0.0F/0.0F) -#define HUGE_VALF (1.0F/0.0F) -#define HUGE_VALL (1.0L/0.0L) -#define INFINITY (1.0F/0.0F) - - -#define FP_NAN 0x0100 -#define FP_NORMAL 0x0400 -#define FP_INFINITE (FP_NAN | FP_NORMAL) -#define FP_ZERO 0x4000 -#define FP_SUBNORMAL (FP_NORMAL | FP_ZERO) - /* 0x0200 is signbit mask */ - - - /* - We can't __CRT_INLINE float or double, because we want to ensure truncation - to semantic type before classification. - (A normal long double value might become subnormal when - converted to double, and zero when converted to float.) - */ - - extern int __cdecl __fpclassifyf (float); - extern int __cdecl __fpclassify (double); - extern int __cdecl __fpclassifyl (long double); - -/* Implemented at tcc/tcc_libm.h -#define fpclassify(x) (sizeof (x) == sizeof (float) ? __fpclassifyf (x) \ - : sizeof (x) == sizeof (double) ? __fpclassify (x) \ - : __fpclassifyl (x)) -*/ -#define fpclassify(x) \ - _Generic(x, float: __fpclassifyf, double: __fpclassify, long double: __fpclassifyl)(x) - - /* 7.12.3.2 */ -#define isfinite(x) ((fpclassify(x) & FP_NAN) == 0) - - /* 7.12.3.3 */ -#define isinf(x) (fpclassify(x) == FP_INFINITE) - - /* 7.12.3.4 */ - /* We don't need to worry about truncation here: - A NaN stays a NaN. */ -#define isnan(x) (fpclassify(x) == FP_NAN) - - /* 7.12.3.5 */ -#define isnormal(x) (fpclassify(x) == FP_NORMAL) - - /* 7.12.3.6 The signbit macro */ - - extern int __cdecl __signbitf (float); - extern int __cdecl __signbit (double); - extern int __cdecl __signbitl (long double); - -/* Implemented at tcc/tcc_libm.h -#define signbit(x) (sizeof (x) == sizeof (float) ? __signbitf (x) \ - : sizeof (x) == sizeof (double) ? __signbit (x) \ - : __signbitl (x)) -*/ -#define signbit(x) \ - _Generic(x, float: __signbitf, double: __signbit, long double: __signbitl)(x) - - extern double __cdecl exp2(double); - extern float __cdecl exp2f(float); - extern long double __cdecl exp2l(long double); - -#define FP_ILOGB0 ((int)0x80000000) -#define FP_ILOGBNAN ((int)0x80000000) - extern int __cdecl ilogb (double); - extern int __cdecl ilogbf (float); - extern int __cdecl ilogbl (long double); - - extern double __cdecl log1p(double); - extern float __cdecl log1pf(float); - extern long double __cdecl log1pl(long double); - - extern double __cdecl log2 (double); - extern float __cdecl log2f (float); - extern long double __cdecl log2l (long double); - - extern double __cdecl logb (double); - extern float __cdecl logbf (float); - extern long double __cdecl logbl (long double); - - extern long double __cdecl modfl (long double, long double*); - - /* 7.12.6.13 */ - extern double __cdecl scalbn (double, int); - extern float __cdecl scalbnf (float, int); - extern long double __cdecl scalbnl (long double, int); - - extern double __cdecl scalbln (double, long); - extern float __cdecl scalblnf (float, long); - extern long double __cdecl scalblnl (long double, long); - - /* 7.12.7.1 */ - /* Implementations adapted from Cephes versions */ - extern double __cdecl cbrt (double); - extern float __cdecl cbrtf (float); - extern long double __cdecl cbrtl (long double); - - extern double __cdecl hypot (double, double); - extern float __cdecl hypotf (float, float); - extern long double __cdecl hypotl (long double, long double); - - extern long double __cdecl powl (long double, long double); - extern long double __cdecl expl(long double); - extern long double __cdecl expm1l(long double); - extern long double __cdecl coshl(long double); - extern long double __cdecl fabsl (long double); - extern long double __cdecl acosl(long double); - extern long double __cdecl asinl(long double); - extern long double __cdecl atanl(long double); - extern long double __cdecl atan2l(long double,long double); - extern long double __cdecl sinhl(long double); - extern long double __cdecl tanhl(long double); - - /* 7.12.8.1 The erf functions */ - extern double __cdecl erf (double); - extern float __cdecl erff (float); - /* TODO - extern long double __cdecl erfl (long double); - */ - - /* 7.12.8.2 The erfc functions */ - extern double __cdecl erfc (double); - extern float __cdecl erfcf (float); - /* TODO - extern long double __cdecl erfcl (long double); - */ - - /* 7.12.8.3 The lgamma functions */ - extern double __cdecl lgamma (double); - extern float __cdecl lgammaf (float); - extern long double __cdecl lgammal (long double); - - /* 7.12.8.4 The tgamma functions */ - extern double __cdecl tgamma (double); - extern float __cdecl tgammaf (float); - extern long double __cdecl tgammal (long double); - - extern long double __cdecl ceill (long double); - extern long double __cdecl floorl (long double); - extern long double __cdecl frexpl(long double,int *); - extern long double __cdecl log10l(long double); - extern long double __cdecl logl(long double); - extern long double __cdecl cosl(long double); - extern long double __cdecl sinl(long double); - extern long double __cdecl tanl(long double); - extern long double sqrtl(long double); - - /* 7.12.9.3 */ - extern double __cdecl nearbyint ( double); - extern float __cdecl nearbyintf (float); - extern long double __cdecl nearbyintl (long double); - - /* 7.12.9.4 */ - /* round, using fpu control word settings */ - extern double __cdecl rint (double); - extern float __cdecl rintf (float); - extern long double __cdecl rintl (long double); - - extern long __cdecl lrint (double); - extern long __cdecl lrintf (float); - extern long __cdecl lrintl (long double); - - extern long long __cdecl llrint (double); - extern long long __cdecl llrintf (float); - extern long long __cdecl llrintl (long double); - - #define FE_TONEAREST 0x0000 - #define FE_DOWNWARD 0x0400 - #define FE_UPWARD 0x0800 - #define FE_TOWARDZERO 0x0c00 - - /* 7.12.9.6 */ - /* round away from zero, regardless of fpu control word settings */ - extern double __cdecl round (double); - extern float __cdecl roundf (float); - extern long double __cdecl roundl (long double); - - /* 7.12.9.7 */ - extern long __cdecl lround (double); - extern long __cdecl lroundf (float); - extern long __cdecl lroundl (long double); - - extern long long __cdecl llround (double); - extern long long __cdecl llroundf (float); - extern long long __cdecl llroundl (long double); - - /* 7.12.9.8 */ - /* round towards zero, regardless of fpu control word settings */ - extern double __cdecl trunc (double); - extern float __cdecl truncf (float); - extern long double __cdecl truncl (long double); - - extern long double __cdecl fmodl (long double, long double); - - /* 7.12.10.2 */ - extern double __cdecl remainder (double, double); - extern float __cdecl remainderf (float, float); - extern long double __cdecl remainderl (long double, long double); - - /* 7.12.10.3 */ - extern double __cdecl remquo(double, double, int *); - extern float __cdecl remquof(float, float, int *); - extern long double __cdecl remquol(long double, long double, int *); - - /* 7.12.11.1 */ - extern double __cdecl copysign (double, double); /* in libmoldname.a */ - extern float __cdecl copysignf (float, float); - extern long double __cdecl copysignl (long double, long double); - - /* 7.12.11.2 Return a NaN */ - extern double __cdecl nan(const char *tagp); - extern float __cdecl nanf(const char *tagp); - extern long double __cdecl nanl(const char *tagp); - -#ifndef __STRICT_ANSI__ -#define _nan() nan("") -#define _nanf() nanf("") -#define _nanl() nanl("") -#endif - - /* 7.12.11.3 */ - extern double __cdecl nextafter (double, double); /* in libmoldname.a */ - extern float __cdecl nextafterf (float, float); - extern long double __cdecl nextafterl (long double, long double); - - /* 7.12.11.4 The nexttoward functions: TODO */ - - /* 7.12.12.1 */ - /* x > y ? (x - y) : 0.0 */ - extern double __cdecl fdim (double x, double y); - extern float __cdecl fdimf (float x, float y); - extern long double __cdecl fdiml (long double x, long double y); - - /* fmax and fmin. - NaN arguments are treated as missing data: if one argument is a NaN - and the other numeric, then these functions choose the numeric - value. */ - - /* 7.12.12.2 */ - extern double __cdecl fmax (double, double); - extern float __cdecl fmaxf (float, float); - extern long double __cdecl fmaxl (long double, long double); - - /* 7.12.12.3 */ - extern double __cdecl fmin (double, double); - extern float __cdecl fminf (float, float); - extern long double __cdecl fminl (long double, long double); - - /* 7.12.13.1 */ - /* return x * y + z as a ternary op */ - extern double __cdecl fma (double, double, double); - extern float __cdecl fmaf (float, float, float); - extern long double __cdecl fmal (long double, long double, long double); - - -#endif /* __STDC_VERSION__ >= 199901L */ -#endif /* __NO_ISOCEXT */ - -#ifdef __cplusplus -} -#endif -#pragma pack(pop) - -/* 7.12.14 */ -/* - * With these functions, comparisons involving quiet NaNs set the FP - * condition code to "unordered". The IEEE floating-point spec - * dictates that the result of floating-point comparisons should be - * false whenever a NaN is involved, with the exception of the != op, - * which always returns true: yes, (NaN != NaN) is true). - */ - -/* Mini libm (inline __fpclassify*, __signbit* and variants) */ -#include "tcc/tcc_libm.h" - -#endif /* End _MATH_H_ */ - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _MATH_H_ +#define _MATH_H_ + +#if __GNUC__ >= 3 +#pragma GCC system_header +#endif + +#include <_mingw.h> + +struct exception; + +#pragma pack(push,_CRT_PACKING) + +#define _DOMAIN 1 +#define _SING 2 +#define _OVERFLOW 3 +#define _UNDERFLOW 4 +#define _TLOSS 5 +#define _PLOSS 6 + +#ifndef __STRICT_ANSI__ +#ifndef NO_OLDNAMES +#define DOMAIN _DOMAIN +#define SING _SING +#define OVERFLOW _OVERFLOW +#define UNDERFLOW _UNDERFLOW +#define TLOSS _TLOSS +#define PLOSS _PLOSS +#endif +#endif + +#ifndef __STRICT_ANSI__ +#define M_E 2.71828182845904523536 +#define M_LOG2E 1.44269504088896340736 +#define M_LOG10E 0.434294481903251827651 +#define M_LN2 0.693147180559945309417 +#define M_LN10 2.30258509299404568402 +#define M_PI 3.14159265358979323846 +#define M_PI_2 1.57079632679489661923 +#define M_PI_4 0.785398163397448309616 +#define M_1_PI 0.318309886183790671538 +#define M_2_PI 0.636619772367581343076 +#define M_2_SQRTPI 1.12837916709551257390 +#define M_SQRT2 1.41421356237309504880 +#define M_SQRT1_2 0.707106781186547524401 +#endif + +#ifndef __STRICT_ANSI__ +/* See also float.h */ +#ifndef __MINGW_FPCLASS_DEFINED +#define __MINGW_FPCLASS_DEFINED 1 +#define _FPCLASS_SNAN 0x0001 /* Signaling "Not a Number" */ +#define _FPCLASS_QNAN 0x0002 /* Quiet "Not a Number" */ +#define _FPCLASS_NINF 0x0004 /* Negative Infinity */ +#define _FPCLASS_NN 0x0008 /* Negative Normal */ +#define _FPCLASS_ND 0x0010 /* Negative Denormal */ +#define _FPCLASS_NZ 0x0020 /* Negative Zero */ +#define _FPCLASS_PZ 0x0040 /* Positive Zero */ +#define _FPCLASS_PD 0x0080 /* Positive Denormal */ +#define _FPCLASS_PN 0x0100 /* Positive Normal */ +#define _FPCLASS_PINF 0x0200 /* Positive Infinity */ +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _EXCEPTION_DEFINED +#define _EXCEPTION_DEFINED + struct _exception { + int type; + char *name; + double arg1; + double arg2; + double retval; + }; +#endif + +#ifndef _COMPLEX_DEFINED +#define _COMPLEX_DEFINED + struct _complex { + double x,y; + }; +#endif + +#define EDOM 33 +#define ERANGE 34 + +#ifndef _HUGE +#ifdef _MSVCRT_ + extern double *_HUGE; +#else + extern double *_imp___HUGE; +#define _HUGE (*_imp___HUGE) +#endif +#endif + +#define HUGE_VAL _HUGE + +#ifndef _CRT_ABS_DEFINED +#define _CRT_ABS_DEFINED + int __cdecl abs(int _X); + long __cdecl labs(long _X); +#endif + double __cdecl acos(double _X); + double __cdecl asin(double _X); + double __cdecl atan(double _X); + double __cdecl atan2(double _Y,double _X); +#ifndef _SIGN_DEFINED +#define _SIGN_DEFINED + _CRTIMP double __cdecl _copysign (double _Number,double _Sign); + _CRTIMP double __cdecl _chgsign (double _X); +#endif + double __cdecl cos(double _X); + double __cdecl cosh(double _X); + double __cdecl exp(double _X); + double __cdecl expm1(double _X); + double __cdecl fabs(double _X); + double __cdecl fmod(double _X,double _Y); + double __cdecl log(double _X); + double __cdecl log10(double _X); + double __cdecl pow(double _X,double _Y); + double __cdecl sin(double _X); + double __cdecl sinh(double _X); + double __cdecl tan(double _X); + double __cdecl tanh(double _X); + double __cdecl sqrt(double _X); +#ifndef _CRT_ATOF_DEFINED +#define _CRT_ATOF_DEFINED + double __cdecl atof(const char *_String); + double __cdecl _atof_l(const char *_String,_locale_t _Locale); +#endif + + _CRTIMP double __cdecl _cabs(struct _complex _ComplexA); + double __cdecl ceil(double _X); + double __cdecl floor(double _X); + double __cdecl frexp(double _X,int *_Y); + double __cdecl _hypot(double _X,double _Y); + _CRTIMP double __cdecl _j0(double _X); + _CRTIMP double __cdecl _j1(double _X); + _CRTIMP double __cdecl _jn(int _X,double _Y); + double __cdecl ldexp(double _X,int _Y); +#ifndef _CRT_MATHERR_DEFINED +#define _CRT_MATHERR_DEFINED + int __cdecl _matherr(struct _exception *_Except); +#endif + double __cdecl modf(double _X,double *_Y); + _CRTIMP double __cdecl _y0(double _X); + _CRTIMP double __cdecl _y1(double _X); + _CRTIMP double __cdecl _yn(int _X,double _Y); + +#if(defined(_X86_) && !defined(__x86_64)) + _CRTIMP int __cdecl _set_SSE2_enable(int _Flag); + /* from libmingwex */ + float __cdecl _hypotf(float _X,float _Y); +#endif + + float frexpf(float _X,int *_Y); + float __cdecl ldexpf(float _X,int _Y); + long double __cdecl ldexpl(long double _X,int _Y); + float __cdecl acosf(float _X); + float __cdecl asinf(float _X); + float __cdecl atanf(float _X); + float __cdecl atan2f(float _X,float _Y); + float __cdecl cosf(float _X); + float __cdecl sinf(float _X); + float __cdecl tanf(float _X); + float __cdecl coshf(float _X); + float __cdecl sinhf(float _X); + float __cdecl tanhf(float _X); + float __cdecl expf(float _X); + float __cdecl expm1f(float _X); + float __cdecl logf(float _X); + float __cdecl log10f(float _X); + float __cdecl modff(float _X,float *_Y); + float __cdecl powf(float _X,float _Y); + float __cdecl sqrtf(float _X); + float __cdecl ceilf(float _X); + float __cdecl floorf(float _X); + float __cdecl fmodf(float _X,float _Y); + float __cdecl _hypotf(float _X,float _Y); + float __cdecl fabsf(float _X); +#if !defined(__ia64__) + /* from libmingwex */ + float __cdecl _copysignf (float _Number,float _Sign); + float __cdecl _chgsignf (float _X); + float __cdecl _logbf(float _X); + float __cdecl _nextafterf(float _X,float _Y); + int __cdecl _finitef(float _X); + int __cdecl _isnanf(float _X); + int __cdecl _fpclassf(float _X); +#endif + +#ifndef NO_OLDNAMES +#define matherr _matherr + +#define HUGE _HUGE + /* double __cdecl cabs(struct _complex _X); */ + double __cdecl hypot(double _X,double _Y); + _CRTIMP double __cdecl j0(double _X); + _CRTIMP double __cdecl j1(double _X); + _CRTIMP double __cdecl jn(int _X,double _Y); + _CRTIMP double __cdecl y0(double _X); + _CRTIMP double __cdecl y1(double _X); + _CRTIMP double __cdecl yn(int _X,double _Y); +#endif + +#ifndef __NO_ISOCEXT +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \ + || !defined __STRICT_ANSI__ || defined __GLIBCPP__ + +#define NAN (0.0F/0.0F) +#define HUGE_VALF (1.0F/0.0F) +#define HUGE_VALL (1.0L/0.0L) +#define INFINITY (1.0F/0.0F) + + +#define FP_NAN 0x0100 +#define FP_NORMAL 0x0400 +#define FP_INFINITE (FP_NAN | FP_NORMAL) +#define FP_ZERO 0x4000 +#define FP_SUBNORMAL (FP_NORMAL | FP_ZERO) + /* 0x0200 is signbit mask */ + + + /* + We can't __CRT_INLINE float or double, because we want to ensure truncation + to semantic type before classification. + (A normal long double value might become subnormal when + converted to double, and zero when converted to float.) + */ + + extern int __cdecl __fpclassifyf (float); + extern int __cdecl __fpclassify (double); + extern int __cdecl __fpclassifyl (long double); + +/* Implemented at tcc/tcc_libm.h +#define fpclassify(x) (sizeof (x) == sizeof (float) ? __fpclassifyf (x) \ + : sizeof (x) == sizeof (double) ? __fpclassify (x) \ + : __fpclassifyl (x)) +*/ +#define fpclassify(x) \ + _Generic(x, float: __fpclassifyf, double: __fpclassify, long double: __fpclassifyl)(x) + + /* 7.12.3.2 */ +#define isfinite(x) ((fpclassify(x) & FP_NAN) == 0) + + /* 7.12.3.3 */ +#define isinf(x) (fpclassify(x) == FP_INFINITE) + + /* 7.12.3.4 */ + /* We don't need to worry about truncation here: + A NaN stays a NaN. */ +#define isnan(x) (fpclassify(x) == FP_NAN) + + /* 7.12.3.5 */ +#define isnormal(x) (fpclassify(x) == FP_NORMAL) + + /* 7.12.3.6 The signbit macro */ + + extern int __cdecl __signbitf (float); + extern int __cdecl __signbit (double); + extern int __cdecl __signbitl (long double); + +/* Implemented at tcc/tcc_libm.h +#define signbit(x) (sizeof (x) == sizeof (float) ? __signbitf (x) \ + : sizeof (x) == sizeof (double) ? __signbit (x) \ + : __signbitl (x)) +*/ +#define signbit(x) \ + _Generic(x, float: __signbitf, double: __signbit, long double: __signbitl)(x) + + extern double __cdecl exp2(double); + extern float __cdecl exp2f(float); + extern long double __cdecl exp2l(long double); + +#define FP_ILOGB0 ((int)0x80000000) +#define FP_ILOGBNAN ((int)0x80000000) + extern int __cdecl ilogb (double); + extern int __cdecl ilogbf (float); + extern int __cdecl ilogbl (long double); + + extern double __cdecl log1p(double); + extern float __cdecl log1pf(float); + extern long double __cdecl log1pl(long double); + + extern double __cdecl log2 (double); + extern float __cdecl log2f (float); + extern long double __cdecl log2l (long double); + + extern double __cdecl logb (double); + extern float __cdecl logbf (float); + extern long double __cdecl logbl (long double); + + extern long double __cdecl modfl (long double, long double*); + + /* 7.12.6.13 */ + extern double __cdecl scalbn (double, int); + extern float __cdecl scalbnf (float, int); + extern long double __cdecl scalbnl (long double, int); + + extern double __cdecl scalbln (double, long); + extern float __cdecl scalblnf (float, long); + extern long double __cdecl scalblnl (long double, long); + + /* 7.12.7.1 */ + /* Implementations adapted from Cephes versions */ + extern double __cdecl cbrt (double); + extern float __cdecl cbrtf (float); + extern long double __cdecl cbrtl (long double); + + extern double __cdecl hypot (double, double); + extern float __cdecl hypotf (float, float); + extern long double __cdecl hypotl (long double, long double); + + extern long double __cdecl powl (long double, long double); + extern long double __cdecl expl(long double); + extern long double __cdecl expm1l(long double); + extern long double __cdecl coshl(long double); + extern long double __cdecl fabsl (long double); + extern long double __cdecl acosl(long double); + extern long double __cdecl asinl(long double); + extern long double __cdecl atanl(long double); + extern long double __cdecl atan2l(long double,long double); + extern long double __cdecl sinhl(long double); + extern long double __cdecl tanhl(long double); + + /* 7.12.8.1 The erf functions */ + extern double __cdecl erf (double); + extern float __cdecl erff (float); + /* TODO + extern long double __cdecl erfl (long double); + */ + + /* 7.12.8.2 The erfc functions */ + extern double __cdecl erfc (double); + extern float __cdecl erfcf (float); + /* TODO + extern long double __cdecl erfcl (long double); + */ + + /* 7.12.8.3 The lgamma functions */ + extern double __cdecl lgamma (double); + extern float __cdecl lgammaf (float); + extern long double __cdecl lgammal (long double); + + /* 7.12.8.4 The tgamma functions */ + extern double __cdecl tgamma (double); + extern float __cdecl tgammaf (float); + extern long double __cdecl tgammal (long double); + + extern long double __cdecl ceill (long double); + extern long double __cdecl floorl (long double); + extern long double __cdecl frexpl(long double,int *); + extern long double __cdecl log10l(long double); + extern long double __cdecl logl(long double); + extern long double __cdecl cosl(long double); + extern long double __cdecl sinl(long double); + extern long double __cdecl tanl(long double); + extern long double sqrtl(long double); + + /* 7.12.9.3 */ + extern double __cdecl nearbyint ( double); + extern float __cdecl nearbyintf (float); + extern long double __cdecl nearbyintl (long double); + + /* 7.12.9.4 */ + /* round, using fpu control word settings */ + extern double __cdecl rint (double); + extern float __cdecl rintf (float); + extern long double __cdecl rintl (long double); + + extern long __cdecl lrint (double); + extern long __cdecl lrintf (float); + extern long __cdecl lrintl (long double); + + extern long long __cdecl llrint (double); + extern long long __cdecl llrintf (float); + extern long long __cdecl llrintl (long double); + + #define FE_TONEAREST 0x0000 + #define FE_DOWNWARD 0x0400 + #define FE_UPWARD 0x0800 + #define FE_TOWARDZERO 0x0c00 + + /* 7.12.9.6 */ + /* round away from zero, regardless of fpu control word settings */ + extern double __cdecl round (double); + extern float __cdecl roundf (float); + extern long double __cdecl roundl (long double); + + /* 7.12.9.7 */ + extern long __cdecl lround (double); + extern long __cdecl lroundf (float); + extern long __cdecl lroundl (long double); + + extern long long __cdecl llround (double); + extern long long __cdecl llroundf (float); + extern long long __cdecl llroundl (long double); + + /* 7.12.9.8 */ + /* round towards zero, regardless of fpu control word settings */ + extern double __cdecl trunc (double); + extern float __cdecl truncf (float); + extern long double __cdecl truncl (long double); + + extern long double __cdecl fmodl (long double, long double); + + /* 7.12.10.2 */ + extern double __cdecl remainder (double, double); + extern float __cdecl remainderf (float, float); + extern long double __cdecl remainderl (long double, long double); + + /* 7.12.10.3 */ + extern double __cdecl remquo(double, double, int *); + extern float __cdecl remquof(float, float, int *); + extern long double __cdecl remquol(long double, long double, int *); + + /* 7.12.11.1 */ + extern double __cdecl copysign (double, double); /* in libmoldname.a */ + extern float __cdecl copysignf (float, float); + extern long double __cdecl copysignl (long double, long double); + + /* 7.12.11.2 Return a NaN */ + extern double __cdecl nan(const char *tagp); + extern float __cdecl nanf(const char *tagp); + extern long double __cdecl nanl(const char *tagp); + +#ifndef __STRICT_ANSI__ +#define _nan() nan("") +#define _nanf() nanf("") +#define _nanl() nanl("") +#endif + + /* 7.12.11.3 */ + extern double __cdecl nextafter (double, double); /* in libmoldname.a */ + extern float __cdecl nextafterf (float, float); + extern long double __cdecl nextafterl (long double, long double); + + /* 7.12.11.4 The nexttoward functions: TODO */ + + /* 7.12.12.1 */ + /* x > y ? (x - y) : 0.0 */ + extern double __cdecl fdim (double x, double y); + extern float __cdecl fdimf (float x, float y); + extern long double __cdecl fdiml (long double x, long double y); + + /* fmax and fmin. + NaN arguments are treated as missing data: if one argument is a NaN + and the other numeric, then these functions choose the numeric + value. */ + + /* 7.12.12.2 */ + extern double __cdecl fmax (double, double); + extern float __cdecl fmaxf (float, float); + extern long double __cdecl fmaxl (long double, long double); + + /* 7.12.12.3 */ + extern double __cdecl fmin (double, double); + extern float __cdecl fminf (float, float); + extern long double __cdecl fminl (long double, long double); + + /* 7.12.13.1 */ + /* return x * y + z as a ternary op */ + extern double __cdecl fma (double, double, double); + extern float __cdecl fmaf (float, float, float); + extern long double __cdecl fmal (long double, long double, long double); + + +#endif /* __STDC_VERSION__ >= 199901L */ +#endif /* __NO_ISOCEXT */ + +#ifdef __cplusplus +} +#endif +#pragma pack(pop) + +/* 7.12.14 */ +/* + * With these functions, comparisons involving quiet NaNs set the FP + * condition code to "unordered". The IEEE floating-point spec + * dictates that the result of floating-point comparisons should be + * false whenever a NaN is involved, with the exception of the != op, + * which always returns true: yes, (NaN != NaN) is true). + */ + +/* Mini libm (inline __fpclassify*, __signbit* and variants) */ +#include "tcc/tcc_libm.h" + +#endif /* End _MATH_H_ */ + diff --git a/tcc/include/mem.h b/tcc/include/mem.h index 43e3bb2b..25520235 100644 --- a/tcc/include/mem.h +++ b/tcc/include/mem.h @@ -1,13 +1,13 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * mem.h maps to string.h - */ -#ifndef __STRICT_ANSI__ -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * mem.h maps to string.h + */ +#ifndef __STRICT_ANSI__ +#include +#endif diff --git a/tcc/include/memory.h b/tcc/include/memory.h index 8d15970e..90d88aed 100644 --- a/tcc/include/memory.h +++ b/tcc/include/memory.h @@ -1,40 +1,40 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_MEMORY -#define _INC_MEMORY - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CONST_RETURN -#define _CONST_RETURN -#endif - -#define _WConst_return _CONST_RETURN - -#ifndef _CRT_MEMORY_DEFINED -#define _CRT_MEMORY_DEFINED - _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); - _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); - _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); - _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); - int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); - void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); - void *__cdecl memset(void *_Dst,int _Val,size_t _Size); - -#ifndef NO_OLDNAMES - void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); - int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_MEMORY +#define _INC_MEMORY + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CONST_RETURN +#define _CONST_RETURN +#endif + +#define _WConst_return _CONST_RETURN + +#ifndef _CRT_MEMORY_DEFINED +#define _CRT_MEMORY_DEFINED + _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); + _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); + _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); + _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); + int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); + void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); + void *__cdecl memset(void *_Dst,int _Val,size_t _Size); + +#ifndef NO_OLDNAMES + void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); + int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/process.h b/tcc/include/process.h index 7b94c0d6..dadaf2b7 100644 --- a/tcc/include/process.h +++ b/tcc/include/process.h @@ -1,176 +1,176 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_PROCESS -#define _INC_PROCESS - -#include <_mingw.h> - -/* Includes a definition of _pid_t and pid_t */ -#include - -#ifndef _POSIX_ -#ifdef __cplusplus -extern "C" { -#endif - -#define _P_WAIT 0 -#define _P_NOWAIT 1 -#define _OLD_P_OVERLAY 2 -#define _P_NOWAITO 3 -#define _P_DETACH 4 -#define _P_OVERLAY 2 - -#define _WAIT_CHILD 0 -#define _WAIT_GRANDCHILD 1 - - _CRTIMP uintptr_t __cdecl _beginthread(void (__cdecl *_StartAddress) (void *),unsigned _StackSize,void *_ArgList); - _CRTIMP void __cdecl _endthread(void); - _CRTIMP uintptr_t __cdecl _beginthreadex(void *_Security,unsigned _StackSize,unsigned (__stdcall *_StartAddress) (void *),void *_ArgList,unsigned _InitFlag,unsigned *_ThrdAddr); - _CRTIMP void __cdecl _endthreadex(unsigned _Retval); - -#ifndef _CRT_TERMINATE_DEFINED -#define _CRT_TERMINATE_DEFINED - void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; - _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; - -#pragma push_macro("abort") -#undef abort - void __cdecl __declspec(noreturn) abort(void); -#pragma pop_macro("abort") - -#endif - - _CRTIMP void __cdecl __MINGW_NOTHROW _cexit(void); - _CRTIMP void __cdecl __MINGW_NOTHROW _c_exit(void); - _CRTIMP int __cdecl _getpid(void); - _CRTIMP intptr_t __cdecl _cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); - _CRTIMP intptr_t __cdecl _execl(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execle(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execlp(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execlpe(const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _execv(const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _execve(const char *_Filename,const char *const *_ArgList,const char *const *_Env); - _CRTIMP intptr_t __cdecl _execvp(const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _execvpe(const char *_Filename,const char *const *_ArgList,const char *const *_Env); - _CRTIMP intptr_t __cdecl _spawnl(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnle(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnlp(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnlpe(int _Mode,const char *_Filename,const char *_ArgList,...); - _CRTIMP intptr_t __cdecl _spawnv(int _Mode,const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _spawnve(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); - _CRTIMP intptr_t __cdecl _spawnvp(int _Mode,const char *_Filename,const char *const *_ArgList); - _CRTIMP intptr_t __cdecl _spawnvpe(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); - -#ifndef _CRT_SYSTEM_DEFINED -#define _CRT_SYSTEM_DEFINED - int __cdecl system(const char *_Command); -#endif - -#ifndef _WPROCESS_DEFINED -#define _WPROCESS_DEFINED - _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif -#endif - - void __cdecl __security_init_cookie(void); -#if (defined(_X86_) && !defined(__x86_64)) - void __fastcall __security_check_cookie(uintptr_t _StackCookie); - __declspec(noreturn) void __cdecl __report_gsfailure(void); -#else - void __cdecl __security_check_cookie(uintptr_t _StackCookie); - __declspec(noreturn) void __cdecl __report_gsfailure(uintptr_t _StackCookie); -#endif - extern uintptr_t __security_cookie; - - intptr_t __cdecl _loaddll(char *_Filename); - int __cdecl _unloaddll(intptr_t _Handle); - int (__cdecl *__cdecl _getdllprocaddr(intptr_t _Handle,char *_ProcedureName,intptr_t _Ordinal))(void); - -#ifdef _DECL_DLLMAIN -#ifdef _WINDOWS_ - WINBOOL WINAPI DllMain(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); - WINBOOL WINAPI _CRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); - WINBOOL WINAPI _wCRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); - extern WINBOOL (WINAPI *const _pRawDllMain)(HANDLE,DWORD,LPVOID); -#else - int __stdcall DllMain(void *_HDllHandle,unsigned _Reason,void *_Reserved); - int __stdcall _CRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); - int __stdcall _wCRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); - extern int (__stdcall *const _pRawDllMain)(void *,unsigned,void *); -#endif -#endif - -#ifndef NO_OLDNAMES -#define P_WAIT _P_WAIT -#define P_NOWAIT _P_NOWAIT -#define P_OVERLAY _P_OVERLAY -#define OLD_P_OVERLAY _OLD_P_OVERLAY -#define P_NOWAITO _P_NOWAITO -#define P_DETACH _P_DETACH -#define WAIT_CHILD _WAIT_CHILD -#define WAIT_GRANDCHILD _WAIT_GRANDCHILD - - intptr_t __cdecl cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); -#ifdef __GNUC__ - int __cdecl execl(const char *_Filename,const char *_ArgList,...); - int __cdecl execle(const char *_Filename,const char *_ArgList,...); - int __cdecl execlp(const char *_Filename,const char *_ArgList,...); - int __cdecl execlpe(const char *_Filename,const char *_ArgList,...); -#else - intptr_t __cdecl execl(const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl execle(const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl execlp(const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl execlpe(const char *_Filename,const char *_ArgList,...); -#endif - intptr_t __cdecl spawnl(int,const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl spawnle(int,const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl spawnlp(int,const char *_Filename,const char *_ArgList,...); - intptr_t __cdecl spawnlpe(int,const char *_Filename,const char *_ArgList,...); - int __cdecl getpid(void); -#ifdef __GNUC__ - /* Those methods are predefined by gcc builtins to return int. So to prevent - stupid warnings, define them in POSIX way. This is save, because those - methods do not return in success case, so that the return value is not - really dependent to its scalar width. */ - int __cdecl execv(const char *_Filename,const char *const _ArgList[]); - int __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); - int __cdecl execvp(const char *_Filename,const char *const _ArgList[]); - int __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); -#else - intptr_t __cdecl execv(const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); - intptr_t __cdecl execvp(const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); -#endif - intptr_t __cdecl spawnv(int,const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl spawnve(int,const char *_Filename,const char *const _ArgList[],const char *const _Env[]); - intptr_t __cdecl spawnvp(int,const char *_Filename,const char *const _ArgList[]); - intptr_t __cdecl spawnvpe(int,const char *_Filename,const char *const _ArgList[],char *const _Env[]); -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_PROCESS +#define _INC_PROCESS + +#include <_mingw.h> + +/* Includes a definition of _pid_t and pid_t */ +#include + +#ifndef _POSIX_ +#ifdef __cplusplus +extern "C" { +#endif + +#define _P_WAIT 0 +#define _P_NOWAIT 1 +#define _OLD_P_OVERLAY 2 +#define _P_NOWAITO 3 +#define _P_DETACH 4 +#define _P_OVERLAY 2 + +#define _WAIT_CHILD 0 +#define _WAIT_GRANDCHILD 1 + + _CRTIMP uintptr_t __cdecl _beginthread(void (__cdecl *_StartAddress) (void *),unsigned _StackSize,void *_ArgList); + _CRTIMP void __cdecl _endthread(void); + _CRTIMP uintptr_t __cdecl _beginthreadex(void *_Security,unsigned _StackSize,unsigned (__stdcall *_StartAddress) (void *),void *_ArgList,unsigned _InitFlag,unsigned *_ThrdAddr); + _CRTIMP void __cdecl _endthreadex(unsigned _Retval); + +#ifndef _CRT_TERMINATE_DEFINED +#define _CRT_TERMINATE_DEFINED + void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; + _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; + +#pragma push_macro("abort") +#undef abort + void __cdecl __declspec(noreturn) abort(void); +#pragma pop_macro("abort") + +#endif + + _CRTIMP void __cdecl __MINGW_NOTHROW _cexit(void); + _CRTIMP void __cdecl __MINGW_NOTHROW _c_exit(void); + _CRTIMP int __cdecl _getpid(void); + _CRTIMP intptr_t __cdecl _cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); + _CRTIMP intptr_t __cdecl _execl(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execle(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execlp(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execlpe(const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _execv(const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _execve(const char *_Filename,const char *const *_ArgList,const char *const *_Env); + _CRTIMP intptr_t __cdecl _execvp(const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _execvpe(const char *_Filename,const char *const *_ArgList,const char *const *_Env); + _CRTIMP intptr_t __cdecl _spawnl(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnle(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnlp(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnlpe(int _Mode,const char *_Filename,const char *_ArgList,...); + _CRTIMP intptr_t __cdecl _spawnv(int _Mode,const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _spawnve(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); + _CRTIMP intptr_t __cdecl _spawnvp(int _Mode,const char *_Filename,const char *const *_ArgList); + _CRTIMP intptr_t __cdecl _spawnvpe(int _Mode,const char *_Filename,const char *const *_ArgList,const char *const *_Env); + +#ifndef _CRT_SYSTEM_DEFINED +#define _CRT_SYSTEM_DEFINED + int __cdecl system(const char *_Command); +#endif + +#ifndef _WPROCESS_DEFINED +#define _WPROCESS_DEFINED + _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif +#endif + + void __cdecl __security_init_cookie(void); +#if (defined(_X86_) && !defined(__x86_64)) + void __fastcall __security_check_cookie(uintptr_t _StackCookie); + __declspec(noreturn) void __cdecl __report_gsfailure(void); +#else + void __cdecl __security_check_cookie(uintptr_t _StackCookie); + __declspec(noreturn) void __cdecl __report_gsfailure(uintptr_t _StackCookie); +#endif + extern uintptr_t __security_cookie; + + intptr_t __cdecl _loaddll(char *_Filename); + int __cdecl _unloaddll(intptr_t _Handle); + int (__cdecl *__cdecl _getdllprocaddr(intptr_t _Handle,char *_ProcedureName,intptr_t _Ordinal))(void); + +#ifdef _DECL_DLLMAIN +#ifdef _WINDOWS_ + WINBOOL WINAPI DllMain(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); + WINBOOL WINAPI _CRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); + WINBOOL WINAPI _wCRT_INIT(HANDLE _HDllHandle,DWORD _Reason,LPVOID _Reserved); + extern WINBOOL (WINAPI *const _pRawDllMain)(HANDLE,DWORD,LPVOID); +#else + int __stdcall DllMain(void *_HDllHandle,unsigned _Reason,void *_Reserved); + int __stdcall _CRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); + int __stdcall _wCRT_INIT(void *_HDllHandle,unsigned _Reason,void *_Reserved); + extern int (__stdcall *const _pRawDllMain)(void *,unsigned,void *); +#endif +#endif + +#ifndef NO_OLDNAMES +#define P_WAIT _P_WAIT +#define P_NOWAIT _P_NOWAIT +#define P_OVERLAY _P_OVERLAY +#define OLD_P_OVERLAY _OLD_P_OVERLAY +#define P_NOWAITO _P_NOWAITO +#define P_DETACH _P_DETACH +#define WAIT_CHILD _WAIT_CHILD +#define WAIT_GRANDCHILD _WAIT_GRANDCHILD + + intptr_t __cdecl cwait(int *_TermStat,intptr_t _ProcHandle,int _Action); +#ifdef __GNUC__ + int __cdecl execl(const char *_Filename,const char *_ArgList,...); + int __cdecl execle(const char *_Filename,const char *_ArgList,...); + int __cdecl execlp(const char *_Filename,const char *_ArgList,...); + int __cdecl execlpe(const char *_Filename,const char *_ArgList,...); +#else + intptr_t __cdecl execl(const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl execle(const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl execlp(const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl execlpe(const char *_Filename,const char *_ArgList,...); +#endif + intptr_t __cdecl spawnl(int,const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl spawnle(int,const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl spawnlp(int,const char *_Filename,const char *_ArgList,...); + intptr_t __cdecl spawnlpe(int,const char *_Filename,const char *_ArgList,...); + int __cdecl getpid(void); +#ifdef __GNUC__ + /* Those methods are predefined by gcc builtins to return int. So to prevent + stupid warnings, define them in POSIX way. This is save, because those + methods do not return in success case, so that the return value is not + really dependent to its scalar width. */ + int __cdecl execv(const char *_Filename,const char *const _ArgList[]); + int __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); + int __cdecl execvp(const char *_Filename,const char *const _ArgList[]); + int __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); +#else + intptr_t __cdecl execv(const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl execve(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); + intptr_t __cdecl execvp(const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl execvpe(const char *_Filename,const char *const _ArgList[],const char *const _Env[]); +#endif + intptr_t __cdecl spawnv(int,const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl spawnve(int,const char *_Filename,const char *const _ArgList[],const char *const _Env[]); + intptr_t __cdecl spawnvp(int,const char *_Filename,const char *const _ArgList[]); + intptr_t __cdecl spawnvpe(int,const char *_Filename,const char *const _ArgList[],char *const _Env[]); +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tcc/include/sec_api/conio_s.h b/tcc/include/sec_api/conio_s.h index 131ad61b..98d97ba2 100644 --- a/tcc/include/sec_api/conio_s.h +++ b/tcc/include/sec_api/conio_s.h @@ -1,42 +1,42 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _INC_CONIO_S -#define _INC_CONIO_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _cgets_s(char *_Buffer,size_t _Size,size_t *_SizeRead); - _CRTIMP int __cdecl _cprintf_s(const char *_Format,...); - _CRTIMP int __cdecl _cscanf_s(const char *_Format,...); - _CRTIMP int __cdecl _cscanf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_s(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cprintf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - -#ifndef _WCONIO_DEFINED_S -#define _WCONIO_DEFINED_S - _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); - _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _INC_CONIO_S +#define _INC_CONIO_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _cgets_s(char *_Buffer,size_t _Size,size_t *_SizeRead); + _CRTIMP int __cdecl _cprintf_s(const char *_Format,...); + _CRTIMP int __cdecl _cscanf_s(const char *_Format,...); + _CRTIMP int __cdecl _cscanf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_s(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cprintf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + +#ifndef _WCONIO_DEFINED_S +#define _WCONIO_DEFINED_S + _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); + _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/crtdbg_s.h b/tcc/include/sec_api/crtdbg_s.h index c68a93fa..4598b4f7 100644 --- a/tcc/include/sec_api/crtdbg_s.h +++ b/tcc/include/sec_api/crtdbg_s.h @@ -1,19 +1,19 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _INC_CRTDBG_S -#define _INC_CRTDBG_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#define _dupenv_s_dbg(ps1,size,s2,t,f,l) _dupenv_s(ps1,size,s2) -#define _wdupenv_s_dbg(ps1,size,s2,t,f,l) _wdupenv_s(ps1,size,s2) - -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _INC_CRTDBG_S +#define _INC_CRTDBG_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#define _dupenv_s_dbg(ps1,size,s2,t,f,l) _dupenv_s(ps1,size,s2) +#define _wdupenv_s_dbg(ps1,size,s2,t,f,l) _wdupenv_s(ps1,size,s2) + +#endif + +#endif diff --git a/tcc/include/sec_api/io_s.h b/tcc/include/sec_api/io_s.h index da0811a4..ec565a61 100644 --- a/tcc/include/sec_api/io_s.h +++ b/tcc/include/sec_api/io_s.h @@ -1,33 +1,33 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_IO_S -#define _INC_IO_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _access_s(const char *_Filename,int _AccessMode); - _CRTIMP errno_t __cdecl _chsize_s(int _FileHandle,__int64 _Size); - _CRTIMP errno_t __cdecl _mktemp_s(char *_TemplateName,size_t _Size); - _CRTIMP errno_t __cdecl _umask_s(int _NewMode,int *_OldMode); - -#ifndef _WIO_S_DEFINED -#define _WIO_S_DEFINED - _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); - _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_IO_S +#define _INC_IO_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _access_s(const char *_Filename,int _AccessMode); + _CRTIMP errno_t __cdecl _chsize_s(int _FileHandle,__int64 _Size); + _CRTIMP errno_t __cdecl _mktemp_s(char *_TemplateName,size_t _Size); + _CRTIMP errno_t __cdecl _umask_s(int _NewMode,int *_OldMode); + +#ifndef _WIO_S_DEFINED +#define _WIO_S_DEFINED + _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); + _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/mbstring_s.h b/tcc/include/sec_api/mbstring_s.h index d7c46bd5..6b2b188f 100644 --- a/tcc/include/sec_api/mbstring_s.h +++ b/tcc/include/sec_api/mbstring_s.h @@ -1,52 +1,52 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_MBSTRING_S -#define _INC_MBSTRING_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _MBSTRING_S_DEFINED -#define _MBSTRING_S_DEFINED - _CRTIMP errno_t __cdecl _mbscat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); - _CRTIMP errno_t __cdecl _mbscat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbscpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); - _CRTIMP errno_t __cdecl _mbscpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbslwr_s(unsigned char *_Str,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _mbslwr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnbcat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnbcpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnbset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnbset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsncat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsncat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsncpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsncpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsnset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbsnset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val); - _CRTIMP errno_t __cdecl _mbsset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,_locale_t _Locale); - _CRTIMP unsigned char *__cdecl _mbstok_s(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context); - _CRTIMP unsigned char *__cdecl _mbstok_s_l(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbsupr_s(unsigned char *_Str,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _mbsupr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); - _CRTIMP errno_t __cdecl _mbccpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src); - _CRTIMP errno_t __cdecl _mbccpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src,_locale_t _Locale); -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_MBSTRING_S +#define _INC_MBSTRING_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _MBSTRING_S_DEFINED +#define _MBSTRING_S_DEFINED + _CRTIMP errno_t __cdecl _mbscat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); + _CRTIMP errno_t __cdecl _mbscat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbscpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src); + _CRTIMP errno_t __cdecl _mbscpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbslwr_s(unsigned char *_Str,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _mbslwr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnbcat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnbcpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnbset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnbset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Ch,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsncat_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsncat_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsncpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsncpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,const unsigned char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsnset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbsnset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsset_s(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val); + _CRTIMP errno_t __cdecl _mbsset_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,unsigned int _Val,_locale_t _Locale); + _CRTIMP unsigned char *__cdecl _mbstok_s(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context); + _CRTIMP unsigned char *__cdecl _mbstok_s_l(unsigned char *_Str,const unsigned char *_Delim,unsigned char **_Context,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbsupr_s(unsigned char *_Str,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _mbsupr_s_l(unsigned char *_Str,size_t _SizeInBytes,_locale_t _Locale); + _CRTIMP errno_t __cdecl _mbccpy_s(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src); + _CRTIMP errno_t __cdecl _mbccpy_s_l(unsigned char *_Dst,size_t _DstSizeInBytes,int *_PCopied,const unsigned char *_Src,_locale_t _Locale); +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/search_s.h b/tcc/include/sec_api/search_s.h index 93e7f09e..cae89989 100644 --- a/tcc/include/sec_api/search_s.h +++ b/tcc/include/sec_api/search_s.h @@ -1,25 +1,25 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SEARCH_S -#define _INC_SEARCH_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP void *__cdecl _lfind_s(const void *_Key,const void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); - _CRTIMP void *__cdecl _lsearch_s(const void *_Key,void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SEARCH_S +#define _INC_SEARCH_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP void *__cdecl _lfind_s(const void *_Key,const void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); + _CRTIMP void *__cdecl _lsearch_s(const void *_Key,void *_Base,unsigned int *_NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(void *,const void *,const void *),void *_Context); + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/stdio_s.h b/tcc/include/sec_api/stdio_s.h index 8e9ce2ed..c9b803b1 100644 --- a/tcc/include/sec_api/stdio_s.h +++ b/tcc/include/sec_api/stdio_s.h @@ -1,145 +1,145 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDIO_S -#define _INC_STDIO_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _STDIO_S_DEFINED -#define _STDIO_S_DEFINED - _CRTIMP errno_t __cdecl clearerr_s(FILE *_File); - int __cdecl fprintf_s(FILE *_File,const char *_Format,...); - size_t __cdecl fread_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); - _CRTIMP int __cdecl _fscanf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - int __cdecl printf_s(const char *_Format,...); - _CRTIMP int __cdecl _scanf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scanf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _snprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _vsnprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); - int __cdecl sprintf_s(char *_DstBuf,size_t _DstSize,const char *_Format,...); - _CRTIMP int __cdecl _fscanf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _sscanf_l(const char *_Src,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _sscanf_s_l(const char *_Src,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snscanf_s(const char *_Src,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _snscanf_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snscanf_s_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - int __cdecl vfprintf_s(FILE *_File,const char *_Format,va_list _ArgList); - int __cdecl vprintf_s(const char *_Format,va_list _ArgList); - int __cdecl vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); - int __cdecl vsprintf_s(char *_DstBuf,size_t _Size,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _fprintf_p(FILE *_File,const char *_Format,...); - _CRTIMP int __cdecl _printf_p(const char *_Format,...); - _CRTIMP int __cdecl _sprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,...); - _CRTIMP int __cdecl _vfprintf_p(FILE *_File,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vprintf_p(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vsprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _scprintf_p(const char *_Format,...); - _CRTIMP int __cdecl _vscprintf_p(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _printf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _printf_p_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _fprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vfprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _sprintf_l(char *_DstBuf,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _sprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsprintf_l(char *_DstBuf,const char *_Format,_locale_t,va_list _ArgList); - _CRTIMP int __cdecl _vsprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _scprintf_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scprintf_p_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vscprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vscprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _printf_s_l(const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _sprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vsnprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *,_locale_t _Locale,va_list _ArgList); - -#ifndef _WSTDIO_S_DEFINED -#define _WSTDIO_S_DEFINED - _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); - int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf_s(const wchar_t *_Format,...); - int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); - int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); - int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); - _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); - _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); - _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); - _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); - _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); -#endif -#endif - - _CRTIMP size_t __cdecl _fread_nolock_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); - -#ifdef __cplusplus -} -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDIO_S +#define _INC_STDIO_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _STDIO_S_DEFINED +#define _STDIO_S_DEFINED + _CRTIMP errno_t __cdecl clearerr_s(FILE *_File); + int __cdecl fprintf_s(FILE *_File,const char *_Format,...); + size_t __cdecl fread_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); + _CRTIMP int __cdecl _fscanf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + int __cdecl printf_s(const char *_Format,...); + _CRTIMP int __cdecl _scanf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scanf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _snprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _vsnprintf_c(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); + int __cdecl sprintf_s(char *_DstBuf,size_t _DstSize,const char *_Format,...); + _CRTIMP int __cdecl _fscanf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _sscanf_l(const char *_Src,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _sscanf_s_l(const char *_Src,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snscanf_s(const char *_Src,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _snscanf_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snscanf_s_l(const char *_Src,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + int __cdecl vfprintf_s(FILE *_File,const char *_Format,va_list _ArgList); + int __cdecl vprintf_s(const char *_Format,va_list _ArgList); + int __cdecl vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vsnprintf_s(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,va_list _ArgList); + int __cdecl vsprintf_s(char *_DstBuf,size_t _Size,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _fprintf_p(FILE *_File,const char *_Format,...); + _CRTIMP int __cdecl _printf_p(const char *_Format,...); + _CRTIMP int __cdecl _sprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,...); + _CRTIMP int __cdecl _vfprintf_p(FILE *_File,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vprintf_p(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vsprintf_p(char *_Dst,size_t _MaxCount,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _scprintf_p(const char *_Format,...); + _CRTIMP int __cdecl _vscprintf_p(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _printf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _printf_p_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _fprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfprintf_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vfprintf_p_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _sprintf_l(char *_DstBuf,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _sprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsprintf_l(char *_DstBuf,const char *_Format,_locale_t,va_list _ArgList); + _CRTIMP int __cdecl _vsprintf_p_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _scprintf_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scprintf_p_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vscprintf_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vscprintf_p_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _printf_s_l(const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vprintf_s_l(const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfprintf_s_l(FILE *_File,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _sprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsprintf_s_l(char *_DstBuf,size_t _DstSize,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnprintf_s_l(char *_DstBuf,size_t _DstSize,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnprintf_l(char *_DstBuf,size_t _MaxCount,const char *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vsnprintf_c_l(char *_DstBuf,size_t _MaxCount,const char *,_locale_t _Locale,va_list _ArgList); + +#ifndef _WSTDIO_S_DEFINED +#define _WSTDIO_S_DEFINED + _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); + int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf_s(const wchar_t *_Format,...); + int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); + int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); + int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); + _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); + _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); + _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); + _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); + _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); +#endif +#endif + + _CRTIMP size_t __cdecl _fread_nolock_s(void *_DstBuf,size_t _DstSize,size_t _ElementSize,size_t _Count,FILE *_File); + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tcc/include/sec_api/stdlib_s.h b/tcc/include/sec_api/stdlib_s.h index 7b78053d..f98262cc 100644 --- a/tcc/include/sec_api/stdlib_s.h +++ b/tcc/include/sec_api/stdlib_s.h @@ -1,67 +1,67 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDLIB_S -#define _INC_STDLIB_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _dupenv_s(char **_PBuffer,size_t *_PBufferSizeInBytes,const char *_VarName); - _CRTIMP errno_t __cdecl _itoa_s(int _Value,char *_DstBuf,size_t _Size,int _Radix); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _i64toa_s(__int64 _Val,char *_DstBuf,size_t _Size,int _Radix); - _CRTIMP errno_t __cdecl _ui64toa_s(unsigned __int64 _Val,char *_DstBuf,size_t _Size,int _Radix); -#endif - _CRTIMP errno_t __cdecl _ltoa_s(long _Val,char *_DstBuf,size_t _Size,int _Radix); - _CRTIMP errno_t __cdecl mbstowcs_s(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount); - _CRTIMP errno_t __cdecl _mbstowcs_s_l(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount,_locale_t _Locale); - _CRTIMP errno_t __cdecl _ultoa_s(unsigned long _Val,char *_DstBuf,size_t _Size,int _Radix); - _CRTIMP errno_t __cdecl _wctomb_s_l(int *_SizeConverted,char *_MbCh,size_t _SizeInBytes,wchar_t _WCh,_locale_t _Locale); - _CRTIMP errno_t __cdecl wcstombs_s(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes); - _CRTIMP errno_t __cdecl _wcstombs_s_l(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes,_locale_t _Locale); - -#ifndef _WSTDLIB_S_DEFINED -#define _WSTDLIB_S_DEFINED - _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); - _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); -#endif -#endif - -#ifndef _POSIX_ - _CRTIMP errno_t __cdecl _ecvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDights,int *_PtDec,int *_PtSign); - _CRTIMP errno_t __cdecl _fcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); - _CRTIMP errno_t __cdecl _gcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDigits); - _CRTIMP errno_t __cdecl _makepath_s(char *_PathResult,size_t _Size,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); - _CRTIMP errno_t __cdecl _putenv_s(const char *_Name,const char *_Value); - _CRTIMP errno_t __cdecl _searchenv_s(const char *_Filename,const char *_EnvVar,char *_ResultPath,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _splitpath_s(const char *_FullPath,char *_Drive,size_t _DriveSize,char *_Dir,size_t _DirSize,char *_Filename,size_t _FilenameSize,char *_Ext,size_t _ExtSize); - -#ifndef _WSTDLIBP_S_DEFINED -#define _WSTDLIBP_S_DEFINED - _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); - _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); - _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDLIB_S +#define _INC_STDLIB_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _dupenv_s(char **_PBuffer,size_t *_PBufferSizeInBytes,const char *_VarName); + _CRTIMP errno_t __cdecl _itoa_s(int _Value,char *_DstBuf,size_t _Size,int _Radix); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _i64toa_s(__int64 _Val,char *_DstBuf,size_t _Size,int _Radix); + _CRTIMP errno_t __cdecl _ui64toa_s(unsigned __int64 _Val,char *_DstBuf,size_t _Size,int _Radix); +#endif + _CRTIMP errno_t __cdecl _ltoa_s(long _Val,char *_DstBuf,size_t _Size,int _Radix); + _CRTIMP errno_t __cdecl mbstowcs_s(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount); + _CRTIMP errno_t __cdecl _mbstowcs_s_l(size_t *_PtNumOfCharConverted,wchar_t *_DstBuf,size_t _SizeInWords,const char *_SrcBuf,size_t _MaxCount,_locale_t _Locale); + _CRTIMP errno_t __cdecl _ultoa_s(unsigned long _Val,char *_DstBuf,size_t _Size,int _Radix); + _CRTIMP errno_t __cdecl _wctomb_s_l(int *_SizeConverted,char *_MbCh,size_t _SizeInBytes,wchar_t _WCh,_locale_t _Locale); + _CRTIMP errno_t __cdecl wcstombs_s(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes); + _CRTIMP errno_t __cdecl _wcstombs_s_l(size_t *_PtNumOfCharConverted,char *_Dst,size_t _DstSizeInBytes,const wchar_t *_Src,size_t _MaxCountInBytes,_locale_t _Locale); + +#ifndef _WSTDLIB_S_DEFINED +#define _WSTDLIB_S_DEFINED + _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); + _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); +#endif +#endif + +#ifndef _POSIX_ + _CRTIMP errno_t __cdecl _ecvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDights,int *_PtDec,int *_PtSign); + _CRTIMP errno_t __cdecl _fcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); + _CRTIMP errno_t __cdecl _gcvt_s(char *_DstBuf,size_t _Size,double _Val,int _NumOfDigits); + _CRTIMP errno_t __cdecl _makepath_s(char *_PathResult,size_t _Size,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); + _CRTIMP errno_t __cdecl _putenv_s(const char *_Name,const char *_Value); + _CRTIMP errno_t __cdecl _searchenv_s(const char *_Filename,const char *_EnvVar,char *_ResultPath,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _splitpath_s(const char *_FullPath,char *_Drive,size_t _DriveSize,char *_Dir,size_t _DirSize,char *_Filename,size_t _FilenameSize,char *_Ext,size_t _ExtSize); + +#ifndef _WSTDLIBP_S_DEFINED +#define _WSTDLIBP_S_DEFINED + _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); + _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); + _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/stralign_s.h b/tcc/include/sec_api/stralign_s.h index 2a7e4a41..5b78f586 100644 --- a/tcc/include/sec_api/stralign_s.h +++ b/tcc/include/sec_api/stralign_s.h @@ -1,30 +1,30 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef __STRALIGN_H_S_ -#define __STRALIGN_H_S_ - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(I_X86_) && defined(_WSTRING_S_DEFINED) -#if defined(__cplusplus) && defined(_WConst_Return) - static __inline PUWSTR ua_wcscpy_s(PUWSTR Destination,size_t DestinationSize,PCUWSTR Source) { - if(WSTR_ALIGNED(Source) && WSTR_ALIGNED(Destination)) return (wcscpy_s((PWSTR)Destination,DestinationSize,(PCWSTR)Source)==0 ? Destination : NULL); - return uaw_wcscpy((PCUWSTR)String,Character); - } -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef __STRALIGN_H_S_ +#define __STRALIGN_H_S_ + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(I_X86_) && defined(_WSTRING_S_DEFINED) +#if defined(__cplusplus) && defined(_WConst_Return) + static __inline PUWSTR ua_wcscpy_s(PUWSTR Destination,size_t DestinationSize,PCUWSTR Source) { + if(WSTR_ALIGNED(Source) && WSTR_ALIGNED(Destination)) return (wcscpy_s((PWSTR)Destination,DestinationSize,(PCWSTR)Source)==0 ? Destination : NULL); + return uaw_wcscpy((PCUWSTR)String,Character); + } +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tcc/include/sec_api/string_s.h b/tcc/include/sec_api/string_s.h index 5a648e5a..9db70e77 100644 --- a/tcc/include/sec_api/string_s.h +++ b/tcc/include/sec_api/string_s.h @@ -1,41 +1,41 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STRING_S -#define _INC_STRING_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _strset_s(char *_Dst,size_t _DstSize,int _Value); - _CRTIMP errno_t __cdecl _strerror_s(char *_Buf,size_t _SizeInBytes,const char *_ErrMsg); - _CRTIMP errno_t __cdecl _strlwr_s(char *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _strlwr_s_l(char *_Str,size_t _Size,_locale_t _Locale); - _CRTIMP errno_t __cdecl _strnset_s(char *_Str,size_t _Size,int _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _strupr_s(char *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _strupr_s_l(char *_Str,size_t _Size,_locale_t _Locale); -#ifndef _WSTRING_S_DEFINED -#define _WSTRING_S_DEFINED - _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); - _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); - _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); - _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); - _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); - _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STRING_S +#define _INC_STRING_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _strset_s(char *_Dst,size_t _DstSize,int _Value); + _CRTIMP errno_t __cdecl _strerror_s(char *_Buf,size_t _SizeInBytes,const char *_ErrMsg); + _CRTIMP errno_t __cdecl _strlwr_s(char *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _strlwr_s_l(char *_Str,size_t _Size,_locale_t _Locale); + _CRTIMP errno_t __cdecl _strnset_s(char *_Str,size_t _Size,int _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _strupr_s(char *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _strupr_s_l(char *_Str,size_t _Size,_locale_t _Locale); +#ifndef _WSTRING_S_DEFINED +#define _WSTRING_S_DEFINED + _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); + _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); + _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); + _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); + _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); + _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tcc/include/sec_api/sys/timeb_s.h b/tcc/include/sec_api/sys/timeb_s.h index 35afa624..af5ef098 100644 --- a/tcc/include/sec_api/sys/timeb_s.h +++ b/tcc/include/sec_api/sys/timeb_s.h @@ -1,34 +1,34 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _TIMEB_H_S -#define _TIMEB_H_S - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef _USE_32BIT_TIME_T -#define _ftime_s _ftime32_s -#else -#define _ftime_s _ftime64_s -#endif - - _CRTIMP errno_t __cdecl _ftime32_s(struct __timeb32 *_Time); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _ftime64_s(struct __timeb64 *_Time); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _TIMEB_H_S +#define _TIMEB_H_S + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef _USE_32BIT_TIME_T +#define _ftime_s _ftime32_s +#else +#define _ftime_s _ftime64_s +#endif + + _CRTIMP errno_t __cdecl _ftime32_s(struct __timeb32 *_Time); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _ftime64_s(struct __timeb64 *_Time); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tcc/include/sec_api/tchar_s.h b/tcc/include/sec_api/tchar_s.h index b70d0574..343d348e 100644 --- a/tcc/include/sec_api/tchar_s.h +++ b/tcc/include/sec_api/tchar_s.h @@ -1,266 +1,266 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_TCHAR_S -#define _INC_TCHAR_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _UNICODE - -#define _tprintf_s wprintf_s -#define _tprintf_s_l _wprintf_s_l -#define _tcprintf_s _cwprintf_s -#define _tcprintf_s_l _cwprintf_s_l -#define _vtcprintf_s _vcwprintf_s -#define _vtcprintf_s_l _vcwprintf_s_l -#define _ftprintf_s fwprintf_s -#define _ftprintf_s_l _fwprintf_s_l -#define _stprintf_s swprintf_s -#define _stprintf_s_l _swprintf_s_l -#define _sntprintf_s _snwprintf_s -#define _sntprintf_s_l _snwprintf_s_l -#define _vtprintf_s vwprintf_s -#define _vtprintf_s_l _vwprintf_s_l -#define _vftprintf_s vfwprintf_s -#define _vftprintf_s_l _vfwprintf_s_l -#define _vstprintf_s vswprintf_s -#define _vstprintf_s_l _vswprintf_s_l -#define _vsntprintf_s _vsnwprintf_s -#define _vsntprintf_s_l _vsnwprintf_s_l - -#define _tscanf_s wscanf_s -#define _tscanf_s_l _wscanf_s_l -#define _tcscanf_s _cwscanf_s -#define _tcscanf_s_l _cwscanf_s_l -#define _ftscanf_s fwscanf_s -#define _ftscanf_s_l _fwscanf_s_l -#define _stscanf_s swscanf_s -#define _stscanf_s_l _swscanf_s_l -#define _sntscanf_s _snwscanf_s -#define _sntscanf_s_l _snwscanf_s_l - -#define _cgetts_s _cgetws_s -#define _getts_s _getws_s - -#define _itot_s _itow_s -#define _ltot_s _ltow_s -#define _ultot_s _ultow_s -#define _i64tot_s _i64tow_s -#define _ui64tot_s _ui64tow_s - -#define _tcscat_s wcscat_s -#define _tcscpy_s wcscpy_s -#define _tcsncat_s wcsncat_s -#define _tcsncat_s_l _wcsncat_s_l -#define _tcsncpy_s wcsncpy_s -#define _tcsncpy_s_l _wcsncpy_s_l -#define _tcstok_s wcstok_s -#define _tcstok_s_l _wcstok_s_l -#define _tcserror_s _wcserror_s -#define __tcserror_s __wcserror_s - -#define _tcsnset_s _wcsnset_s -#define _tcsnset_s_l _wcsnset_s_l -#define _tcsset_s _wcsset_s -#define _tcsset_s_l _wcsset_s_l - -#define _tasctime_s _wasctime_s -#define _tctime_s _wctime_s -#define _tctime32_s _wctime32_s -#define _tctime64_s _wctime64_s -#define _tstrdate_s _wstrdate_s -#define _tstrtime_s _wstrtime_s - -#define _tgetenv_s _wgetenv_s -#define _tdupenv_s _wdupenv_s -#define _tmakepath_s _wmakepath_s -#define _tputenv_s _wputenv_s -#define _tsearchenv_s _wsearchenv_s -#define _tsplitpath_s _wsplitpath_s - -#define _tfopen_s _wfopen_s -#define _tfreopen_s _wfreopen_s -#define _ttmpnam_s _wtmpnam_s -#define _taccess_s _waccess_s -#define _tmktemp_s _wmktemp_s - -#define _tcsnccat_s wcsncat_s -#define _tcsnccat_s_l _wcsncat_s_l -#define _tcsnccpy_s wcsncpy_s -#define _tcsnccpy_s_l _wcsncpy_s_l - -#define _tcslwr_s _wcslwr_s -#define _tcslwr_s_l _wcslwr_s_l -#define _tcsupr_s _wcsupr_s -#define _tcsupr_s_l _wcsupr_s_l - -#define _wcstok_s_l(_String,_Delimiters,_Current_position,_Locale) (wcstok_s(_String,_Delimiters,_Current_position)) -#define _wcsnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_wcsnset_s(_Destination,_Destination_size_chars,_Value,_Count)) -#define _wcsset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_wcsset_s(_Destination,_Destination_size_chars,_Value)) - -#else - -#define _tprintf_s printf_s -#define _tprintf_s_l _printf_s_l -#define _tcprintf_s _cprintf_s -#define _tcprintf_s_l _cprintf_s_l -#define _vtcprintf_s _vcprintf_s -#define _vtcprintf_s_l _vcprintf_s_l -#define _ftprintf_s fprintf_s -#define _ftprintf_s_l _fprintf_s_l -#define _stprintf_s sprintf_s -#define _stprintf_s_l _sprintf_s_l -#define _sntprintf_s _snprintf_s -#define _sntprintf_s_l _snprintf_s_l -#define _vtprintf_s vprintf_s -#define _vtprintf_s_l _vprintf_s_l -#define _vftprintf_s vfprintf_s -#define _vftprintf_s_l _vfprintf_s_l -#define _vstprintf_s vsprintf_s -#define _vstprintf_s_l _vsprintf_s_l -#define _vsntprintf_s _vsnprintf_s -#define _vsntprintf_s_l _vsnprintf_s_l -#define _tscanf_s scanf_s -#define _tscanf_s_l _scanf_s_l -#define _tcscanf_s _cscanf_s -#define _tcscanf_s_l _cscanf_s_l -#define _ftscanf_s fscanf_s -#define _ftscanf_s_l _fscanf_s_l -#define _stscanf_s sscanf_s -#define _stscanf_s_l _sscanf_s_l -#define _sntscanf_s _snscanf_s -#define _sntscanf_s_l _snscanf_s_l - -#define _getts_s gets_s -#define _cgetts_s _cgets_s -#define _itot_s _itoa_s -#define _ltot_s _ltoa_s -#define _ultot_s _ultoa_s -#define _i64tot_s _i64toa_s -#define _ui64tot_s _ui64toa_s - -#define _tcscat_s strcat_s -#define _tcscpy_s strcpy_s -#define _tcserror_s strerror_s -#define __tcserror_s _strerror_s - -#define _tasctime_s asctime_s -#define _tctime_s ctime_s -#define _tctime32_s _ctime32_s -#define _tctime64_s _ctime64_s -#define _tstrdate_s _strdate_s -#define _tstrtime_s _strtime_s - -#define _tgetenv_s getenv_s -#define _tdupenv_s _dupenv_s -#define _tmakepath_s _makepath_s -#define _tputenv_s _putenv_s -#define _tsearchenv_s _searchenv_s -#define _tsplitpath_s _splitpath_s - -#define _tfopen_s fopen_s -#define _tfreopen_s freopen_s -#define _ttmpnam_s tmpnam_s -#define _tmktemp_s _mktemp_s - -#ifndef _POSIX_ -#define _taccess_s _access_s -#endif - -#define _tsopen_s _sopen_s - -#ifdef _MBCS - -#ifdef _MB_MAP_DIRECT - -#define _tcsncat_s _mbsnbcat_s -#define _tcsncat_s_l _mbsnbcat_s_l -#define _tcsncpy_s _mbsnbcpy_s -#define _tcsncpy_s_l _mbsnbcpy_s_l -#define _tcstok_s _mbstok_s -#define _tcstok_s_l _mbstok_s_l - -#define _tcsnset_s _mbsnbset_s -#define _tcsnset_s_l _mbsnbset_s_l -#define _tcsset_s _mbsset_s -#define _tcsset_s_l _mbsset_s_l - -#define _tcsnccat_s _mbsncat_s -#define _tcsnccat_s_l _mbsncat_s_l -#define _tcsnccpy_s _mbsncpy_s -#define _tcsnccpy_s_l _mbsncpy_s_l -#define _tcsncset_s _mbsnset_s -#define _tcsncset_s_l _mbsnset_s_l - -#define _tcslwr_s _mbslwr_s -#define _tcslwr_s_l _mbslwr_s_l -#define _tcsupr_s _mbsupr_s -#define _tcsupr_s_l _mbsupr_s_l - -#define _tccpy_s _mbccpy_s -#define _tccpy_s_l _mbccpy_s_l -#else - - _CRTIMP char *__cdecl _tcsncat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsncpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcstok_s(char *_Str,const char *_Delim,char **_Context); - _CRTIMP char *__cdecl _tcstok_s_l(char *_Str,const char *_Delim,char **_Context,_locale_t _Locale); - _CRTIMP errno_t __cdecl _tcsset_s(char *_Str,size_t _SizeInChars,unsigned int _Val); - _CRTIMP errno_t __cdecl _tcsset_s_l(char *_Str,size_t _SizeInChars,unsigned int,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcslwr_s(char *_Str,size_t _SizeInChars); - _CRTIMP char *__cdecl _tcslwr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsupr_s(char *_Str,size_t _SizeInChars); - _CRTIMP char *__cdecl _tcsupr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); - -#endif - -#else - -#define _tcsncat_s strncat_s -#define _tcsncat_s_l _strncat_s_l -#define _tcsncpy_s strncpy_s -#define _tcsncpy_s_l _strncpy_s_l -#define _tcstok_s strtok_s -#define _tcstok_s_l _strtok_s_l - -#define _tcsnset_s _strnset_s -#define _tcsnset_s_l _strnset_s_l -#define _tcsset_s _strset_s -#define _tcsset_s _strset_s -#define _tcsset_s_l _strset_s_l - -#define _tcsnccat_s strncat_s -#define _tcsnccat_s_l _strncat_s_l -#define _tcsnccpy_s strncpy_s -#define _tcsnccpy_s_l _strncpy_s_l - -#define _tcslwr_s _strlwr_s -#define _tcslwr_s_l _strlwr_s_l -#define _tcsupr_s _strupr_s -#define _tcsupr_s_l _strupr_s_l - -#define _strnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_strnset_s(_Destination,_Destination_size_chars,_Value,_Count)) -#define _strset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_strset_s(_Destination,_Destination_size_chars,_Value)) -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_TCHAR_S +#define _INC_TCHAR_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _UNICODE + +#define _tprintf_s wprintf_s +#define _tprintf_s_l _wprintf_s_l +#define _tcprintf_s _cwprintf_s +#define _tcprintf_s_l _cwprintf_s_l +#define _vtcprintf_s _vcwprintf_s +#define _vtcprintf_s_l _vcwprintf_s_l +#define _ftprintf_s fwprintf_s +#define _ftprintf_s_l _fwprintf_s_l +#define _stprintf_s swprintf_s +#define _stprintf_s_l _swprintf_s_l +#define _sntprintf_s _snwprintf_s +#define _sntprintf_s_l _snwprintf_s_l +#define _vtprintf_s vwprintf_s +#define _vtprintf_s_l _vwprintf_s_l +#define _vftprintf_s vfwprintf_s +#define _vftprintf_s_l _vfwprintf_s_l +#define _vstprintf_s vswprintf_s +#define _vstprintf_s_l _vswprintf_s_l +#define _vsntprintf_s _vsnwprintf_s +#define _vsntprintf_s_l _vsnwprintf_s_l + +#define _tscanf_s wscanf_s +#define _tscanf_s_l _wscanf_s_l +#define _tcscanf_s _cwscanf_s +#define _tcscanf_s_l _cwscanf_s_l +#define _ftscanf_s fwscanf_s +#define _ftscanf_s_l _fwscanf_s_l +#define _stscanf_s swscanf_s +#define _stscanf_s_l _swscanf_s_l +#define _sntscanf_s _snwscanf_s +#define _sntscanf_s_l _snwscanf_s_l + +#define _cgetts_s _cgetws_s +#define _getts_s _getws_s + +#define _itot_s _itow_s +#define _ltot_s _ltow_s +#define _ultot_s _ultow_s +#define _i64tot_s _i64tow_s +#define _ui64tot_s _ui64tow_s + +#define _tcscat_s wcscat_s +#define _tcscpy_s wcscpy_s +#define _tcsncat_s wcsncat_s +#define _tcsncat_s_l _wcsncat_s_l +#define _tcsncpy_s wcsncpy_s +#define _tcsncpy_s_l _wcsncpy_s_l +#define _tcstok_s wcstok_s +#define _tcstok_s_l _wcstok_s_l +#define _tcserror_s _wcserror_s +#define __tcserror_s __wcserror_s + +#define _tcsnset_s _wcsnset_s +#define _tcsnset_s_l _wcsnset_s_l +#define _tcsset_s _wcsset_s +#define _tcsset_s_l _wcsset_s_l + +#define _tasctime_s _wasctime_s +#define _tctime_s _wctime_s +#define _tctime32_s _wctime32_s +#define _tctime64_s _wctime64_s +#define _tstrdate_s _wstrdate_s +#define _tstrtime_s _wstrtime_s + +#define _tgetenv_s _wgetenv_s +#define _tdupenv_s _wdupenv_s +#define _tmakepath_s _wmakepath_s +#define _tputenv_s _wputenv_s +#define _tsearchenv_s _wsearchenv_s +#define _tsplitpath_s _wsplitpath_s + +#define _tfopen_s _wfopen_s +#define _tfreopen_s _wfreopen_s +#define _ttmpnam_s _wtmpnam_s +#define _taccess_s _waccess_s +#define _tmktemp_s _wmktemp_s + +#define _tcsnccat_s wcsncat_s +#define _tcsnccat_s_l _wcsncat_s_l +#define _tcsnccpy_s wcsncpy_s +#define _tcsnccpy_s_l _wcsncpy_s_l + +#define _tcslwr_s _wcslwr_s +#define _tcslwr_s_l _wcslwr_s_l +#define _tcsupr_s _wcsupr_s +#define _tcsupr_s_l _wcsupr_s_l + +#define _wcstok_s_l(_String,_Delimiters,_Current_position,_Locale) (wcstok_s(_String,_Delimiters,_Current_position)) +#define _wcsnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_wcsnset_s(_Destination,_Destination_size_chars,_Value,_Count)) +#define _wcsset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_wcsset_s(_Destination,_Destination_size_chars,_Value)) + +#else + +#define _tprintf_s printf_s +#define _tprintf_s_l _printf_s_l +#define _tcprintf_s _cprintf_s +#define _tcprintf_s_l _cprintf_s_l +#define _vtcprintf_s _vcprintf_s +#define _vtcprintf_s_l _vcprintf_s_l +#define _ftprintf_s fprintf_s +#define _ftprintf_s_l _fprintf_s_l +#define _stprintf_s sprintf_s +#define _stprintf_s_l _sprintf_s_l +#define _sntprintf_s _snprintf_s +#define _sntprintf_s_l _snprintf_s_l +#define _vtprintf_s vprintf_s +#define _vtprintf_s_l _vprintf_s_l +#define _vftprintf_s vfprintf_s +#define _vftprintf_s_l _vfprintf_s_l +#define _vstprintf_s vsprintf_s +#define _vstprintf_s_l _vsprintf_s_l +#define _vsntprintf_s _vsnprintf_s +#define _vsntprintf_s_l _vsnprintf_s_l +#define _tscanf_s scanf_s +#define _tscanf_s_l _scanf_s_l +#define _tcscanf_s _cscanf_s +#define _tcscanf_s_l _cscanf_s_l +#define _ftscanf_s fscanf_s +#define _ftscanf_s_l _fscanf_s_l +#define _stscanf_s sscanf_s +#define _stscanf_s_l _sscanf_s_l +#define _sntscanf_s _snscanf_s +#define _sntscanf_s_l _snscanf_s_l + +#define _getts_s gets_s +#define _cgetts_s _cgets_s +#define _itot_s _itoa_s +#define _ltot_s _ltoa_s +#define _ultot_s _ultoa_s +#define _i64tot_s _i64toa_s +#define _ui64tot_s _ui64toa_s + +#define _tcscat_s strcat_s +#define _tcscpy_s strcpy_s +#define _tcserror_s strerror_s +#define __tcserror_s _strerror_s + +#define _tasctime_s asctime_s +#define _tctime_s ctime_s +#define _tctime32_s _ctime32_s +#define _tctime64_s _ctime64_s +#define _tstrdate_s _strdate_s +#define _tstrtime_s _strtime_s + +#define _tgetenv_s getenv_s +#define _tdupenv_s _dupenv_s +#define _tmakepath_s _makepath_s +#define _tputenv_s _putenv_s +#define _tsearchenv_s _searchenv_s +#define _tsplitpath_s _splitpath_s + +#define _tfopen_s fopen_s +#define _tfreopen_s freopen_s +#define _ttmpnam_s tmpnam_s +#define _tmktemp_s _mktemp_s + +#ifndef _POSIX_ +#define _taccess_s _access_s +#endif + +#define _tsopen_s _sopen_s + +#ifdef _MBCS + +#ifdef _MB_MAP_DIRECT + +#define _tcsncat_s _mbsnbcat_s +#define _tcsncat_s_l _mbsnbcat_s_l +#define _tcsncpy_s _mbsnbcpy_s +#define _tcsncpy_s_l _mbsnbcpy_s_l +#define _tcstok_s _mbstok_s +#define _tcstok_s_l _mbstok_s_l + +#define _tcsnset_s _mbsnbset_s +#define _tcsnset_s_l _mbsnbset_s_l +#define _tcsset_s _mbsset_s +#define _tcsset_s_l _mbsset_s_l + +#define _tcsnccat_s _mbsncat_s +#define _tcsnccat_s_l _mbsncat_s_l +#define _tcsnccpy_s _mbsncpy_s +#define _tcsnccpy_s_l _mbsncpy_s_l +#define _tcsncset_s _mbsnset_s +#define _tcsncset_s_l _mbsnset_s_l + +#define _tcslwr_s _mbslwr_s +#define _tcslwr_s_l _mbslwr_s_l +#define _tcsupr_s _mbsupr_s +#define _tcsupr_s_l _mbsupr_s_l + +#define _tccpy_s _mbccpy_s +#define _tccpy_s_l _mbccpy_s_l +#else + + _CRTIMP char *__cdecl _tcsncat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsncpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcstok_s(char *_Str,const char *_Delim,char **_Context); + _CRTIMP char *__cdecl _tcstok_s_l(char *_Str,const char *_Delim,char **_Context,_locale_t _Locale); + _CRTIMP errno_t __cdecl _tcsset_s(char *_Str,size_t _SizeInChars,unsigned int _Val); + _CRTIMP errno_t __cdecl _tcsset_s_l(char *_Str,size_t _SizeInChars,unsigned int,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccpy_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccpy_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcslwr_s(char *_Str,size_t _SizeInChars); + _CRTIMP char *__cdecl _tcslwr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsupr_s(char *_Str,size_t _SizeInChars); + _CRTIMP char *__cdecl _tcsupr_s_l(char *_Str,size_t _SizeInChars,_locale_t _Locale); + +#endif + +#else + +#define _tcsncat_s strncat_s +#define _tcsncat_s_l _strncat_s_l +#define _tcsncpy_s strncpy_s +#define _tcsncpy_s_l _strncpy_s_l +#define _tcstok_s strtok_s +#define _tcstok_s_l _strtok_s_l + +#define _tcsnset_s _strnset_s +#define _tcsnset_s_l _strnset_s_l +#define _tcsset_s _strset_s +#define _tcsset_s _strset_s +#define _tcsset_s_l _strset_s_l + +#define _tcsnccat_s strncat_s +#define _tcsnccat_s_l _strncat_s_l +#define _tcsnccpy_s strncpy_s +#define _tcsnccpy_s_l _strncpy_s_l + +#define _tcslwr_s _strlwr_s +#define _tcslwr_s_l _strlwr_s_l +#define _tcsupr_s _strupr_s +#define _tcsupr_s_l _strupr_s_l + +#define _strnset_s_l(_Destination,_Destination_size_chars,_Value,_Count,_Locale) (_strnset_s(_Destination,_Destination_size_chars,_Value,_Count)) +#define _strset_s_l(_Destination,_Destination_size_chars,_Value,_Locale) (_strset_s(_Destination,_Destination_size_chars,_Value)) +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/tcc/include/sec_api/time_s.h b/tcc/include/sec_api/time_s.h index b955304a..9603b94f 100644 --- a/tcc/include/sec_api/time_s.h +++ b/tcc/include/sec_api/time_s.h @@ -1,61 +1,61 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _TIME_H__S -#define _TIME_H__S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - - _CRTIMP errno_t __cdecl _ctime32_s(char *_Buf,size_t _SizeInBytes,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _gmtime32_s(struct tm *_Tm,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _localtime32_s(struct tm *_Tm,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _strdate_s(char *_Buf,size_t _SizeInBytes); - _CRTIMP errno_t __cdecl _strtime_s(char *_Buf ,size_t _SizeInBytes); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _ctime64_s(char *_Buf,size_t _SizeInBytes,const __time64_t *_Time); - _CRTIMP errno_t __cdecl _gmtime64_s(struct tm *_Tm,const __time64_t *_Time); - _CRTIMP errno_t __cdecl _localtime64_s(struct tm *_Tm,const __time64_t *_Time); -#endif - -#ifndef _WTIME_S_DEFINED -#define _WTIME_S_DEFINED - _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); - _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) -#define _INC_WTIME_S_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } -#else -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } -#endif -#endif -#endif - -#ifndef RC_INVOKED -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime32_s(_Tm,_Time); } -#else -__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime64_s(_Tm,_Time); } -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _TIME_H__S +#define _TIME_H__S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + + _CRTIMP errno_t __cdecl _ctime32_s(char *_Buf,size_t _SizeInBytes,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _gmtime32_s(struct tm *_Tm,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _localtime32_s(struct tm *_Tm,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _strdate_s(char *_Buf,size_t _SizeInBytes); + _CRTIMP errno_t __cdecl _strtime_s(char *_Buf ,size_t _SizeInBytes); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _ctime64_s(char *_Buf,size_t _SizeInBytes,const __time64_t *_Time); + _CRTIMP errno_t __cdecl _gmtime64_s(struct tm *_Tm,const __time64_t *_Time); + _CRTIMP errno_t __cdecl _localtime64_s(struct tm *_Tm,const __time64_t *_Time); +#endif + +#ifndef _WTIME_S_DEFINED +#define _WTIME_S_DEFINED + _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); + _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) +#define _INC_WTIME_S_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } +#else +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } +#endif +#endif +#endif + +#ifndef RC_INVOKED +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime32_s(_Tm,_Time); } +#else +__CRT_INLINE errno_t __cdecl localtime_s(struct tm *_Tm,const time_t *_Time) { return _localtime64_s(_Tm,_Time); } +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/sec_api/wchar_s.h b/tcc/include/sec_api/wchar_s.h index 76c4b81a..94251aa8 100644 --- a/tcc/include/sec_api/wchar_s.h +++ b/tcc/include/sec_api/wchar_s.h @@ -1,128 +1,128 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_WCHAR_S -#define _INC_WCHAR_S - -#include - -#if defined(MINGW_HAS_SECURE_API) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _WIO_S_DEFINED -#define _WIO_S_DEFINED - _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); - _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); -#endif - -#ifndef _WCONIO_S_DEFINED -#define _WCONIO_S_DEFINED - _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); - _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); -#endif - -#ifndef _WSTDIO_S_DEFINED -#define _WSTDIO_S_DEFINED - _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); - int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf_s(const wchar_t *_Format,...); - int __cdecl vfwprintf_s(FILE *_File,const wchar_t *_Format,va_list _ArgList); - int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); - int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); - int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); - _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); -#endif - -#ifndef _WSTDLIB_S_DEFINED -#define _WSTDLIB_S_DEFINED - _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); - _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); - _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); -#endif -#endif - -#ifndef _POSIX_ -#ifndef _WSTDLIBP_S_DEFINED -#define _WSTDLIBP_S_DEFINED - _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); - _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); - _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); -#endif -#endif - -#ifndef _WSTRING_S_DEFINED -#define _WSTRING_S_DEFINED - _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); - _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); - _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); - _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); - _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); - _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); - _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); - _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); -#endif - -#ifndef _WTIME_S_DEFINED -#define _WTIME_S_DEFINED - _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); - _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); - _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); - _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) -#define _INC_WTIME_S_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } -#else -__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } -#endif -#endif -#endif - - _CRTIMP errno_t __cdecl mbsrtowcs_s(size_t *_Retval,wchar_t *_Dst,size_t _SizeInWords,const char **_PSrc,size_t _N,mbstate_t *_State); - _CRTIMP errno_t __cdecl wcrtomb_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,wchar_t _Ch,mbstate_t *_State); - _CRTIMP errno_t __cdecl wcsrtombs_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,const wchar_t **_Src,size_t _Size,mbstate_t *_State); - -#ifdef __cplusplus -} -#endif - -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_WCHAR_S +#define _INC_WCHAR_S + +#include + +#if defined(MINGW_HAS_SECURE_API) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _WIO_S_DEFINED +#define _WIO_S_DEFINED + _CRTIMP errno_t __cdecl _waccess_s(const wchar_t *_Filename,int _AccessMode); + _CRTIMP errno_t __cdecl _wmktemp_s(wchar_t *_TemplateName,size_t _SizeInWords); +#endif + +#ifndef _WCONIO_S_DEFINED +#define _WCONIO_S_DEFINED + _CRTIMP errno_t __cdecl _cgetws_s(wchar_t *_Buffer,size_t _SizeInWords,size_t *_SizeRead); + _CRTIMP int __cdecl _cwprintf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); +#endif + +#ifndef _WSTDIO_S_DEFINED +#define _WSTDIO_S_DEFINED + _CRTIMP wchar_t *__cdecl _getws_s(wchar_t *_Str,size_t _SizeInWords); + int __cdecl fwprintf_s(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf_s(const wchar_t *_Format,...); + int __cdecl vfwprintf_s(FILE *_File,const wchar_t *_Format,va_list _ArgList); + int __cdecl vwprintf_s(const wchar_t *_Format,va_list _ArgList); + int __cdecl swprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,...); + int __cdecl vswprintf_s(wchar_t *_Dst,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf_s(wchar_t *_DstBuf,size_t _DstSizeInWords,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_s_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_s_l(wchar_t *_DstBuf,size_t _DstSize,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwscanf_s_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swscanf_s_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf_s(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf_s_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wscanf_s_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP errno_t __cdecl _wfopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP errno_t __cdecl _wfreopen_s(FILE **_File,const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); + _CRTIMP errno_t __cdecl _wtmpnam_s(wchar_t *_DstBuf,size_t _SizeInWords); +#endif + +#ifndef _WSTDLIB_S_DEFINED +#define _WSTDLIB_S_DEFINED + _CRTIMP errno_t __cdecl _itow_s (int _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ltow_s (long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ultow_s (unsigned long _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _wgetenv_s(size_t *_ReturnSize,wchar_t *_DstBuf,size_t _DstSizeInWords,const wchar_t *_VarName); + _CRTIMP errno_t __cdecl _wdupenv_s(wchar_t **_Buffer,size_t *_BufferSizeInWords,const wchar_t *_VarName); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _i64tow_s(__int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); + _CRTIMP errno_t __cdecl _ui64tow_s(unsigned __int64 _Val,wchar_t *_DstBuf,size_t _SizeInWords,int _Radix); +#endif +#endif + +#ifndef _POSIX_ +#ifndef _WSTDLIBP_S_DEFINED +#define _WSTDLIBP_S_DEFINED + _CRTIMP errno_t __cdecl _wmakepath_s(wchar_t *_PathResult,size_t _SizeInWords,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); + _CRTIMP errno_t __cdecl _wputenv_s(const wchar_t *_Name,const wchar_t *_Value); + _CRTIMP errno_t __cdecl _wsearchenv_s(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wsplitpath_s(const wchar_t *_FullPath,wchar_t *_Drive,size_t _DriveSizeInWords,wchar_t *_Dir,size_t _DirSizeInWords,wchar_t *_Filename,size_t _FilenameSizeInWords,wchar_t *_Ext,size_t _ExtSizeInWords); +#endif +#endif + +#ifndef _WSTRING_S_DEFINED +#define _WSTRING_S_DEFINED + _CRTIMP wchar_t *__cdecl wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context); + _CRTIMP errno_t __cdecl _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum); + _CRTIMP errno_t __cdecl __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg); + _CRTIMP errno_t __cdecl _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount); + _CRTIMP errno_t __cdecl _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val); + _CRTIMP errno_t __cdecl _wcslwr_s(wchar_t *_Str,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale); + _CRTIMP errno_t __cdecl _wcsupr_s(wchar_t *_Str,size_t _Size); + _CRTIMP errno_t __cdecl _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale); +#endif + +#ifndef _WTIME_S_DEFINED +#define _WTIME_S_DEFINED + _CRTIMP errno_t __cdecl _wasctime_s(wchar_t *_Buf,size_t _SizeInWords,const struct tm *_Tm); + _CRTIMP errno_t __cdecl _wctime32_s(wchar_t *_Buf,size_t _SizeInWords,const __time32_t *_Time); + _CRTIMP errno_t __cdecl _wstrdate_s(wchar_t *_Buf,size_t _SizeInWords); + _CRTIMP errno_t __cdecl _wstrtime_s(wchar_t *_Buf,size_t _SizeInWords); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP errno_t __cdecl _wctime64_s(wchar_t *_Buf,size_t _SizeInWords,const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_S_INL) +#define _INC_WTIME_S_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime32_s(_Buffer,_SizeInWords,_Time); } +#else +__CRT_INLINE errno_t __cdecl _wctime_s(wchar_t *_Buffer,size_t _SizeInWords,const time_t *_Time) { return _wctime64_s(_Buffer,_SizeInWords,_Time); } +#endif +#endif +#endif + + _CRTIMP errno_t __cdecl mbsrtowcs_s(size_t *_Retval,wchar_t *_Dst,size_t _SizeInWords,const char **_PSrc,size_t _N,mbstate_t *_State); + _CRTIMP errno_t __cdecl wcrtomb_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,wchar_t _Ch,mbstate_t *_State); + _CRTIMP errno_t __cdecl wcsrtombs_s(size_t *_Retval,char *_Dst,size_t _SizeInBytes,const wchar_t **_Src,size_t _Size,mbstate_t *_State); + +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/tcc/include/setjmp.h b/tcc/include/setjmp.h index 5545426b..e4f142a3 100644 --- a/tcc/include/setjmp.h +++ b/tcc/include/setjmp.h @@ -1,160 +1,160 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SETJMP -#define _INC_SETJMP - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#if (defined(_X86_) && !defined(__x86_64)) - -#define _JBLEN 16 -#define _JBTYPE int - - typedef struct __JUMP_BUFFER { - unsigned long Ebp; - unsigned long Ebx; - unsigned long Edi; - unsigned long Esi; - unsigned long Esp; - unsigned long Eip; - unsigned long Registration; - unsigned long TryLevel; - unsigned long Cookie; - unsigned long UnwindFunc; - unsigned long UnwindData[6]; - } _JUMP_BUFFER; -#elif defined(__ia64__) - typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { - __int64 LowPart; - __int64 HighPart; - } SETJMP_FLOAT128; - -#define _JBLEN 33 - typedef SETJMP_FLOAT128 _JBTYPE; - - typedef struct __JUMP_BUFFER { - - unsigned long iAReserved[6]; - - unsigned long Registration; - unsigned long TryLevel; - unsigned long Cookie; - unsigned long UnwindFunc; - - unsigned long UnwindData[6]; - - SETJMP_FLOAT128 FltS0; - SETJMP_FLOAT128 FltS1; - SETJMP_FLOAT128 FltS2; - SETJMP_FLOAT128 FltS3; - SETJMP_FLOAT128 FltS4; - SETJMP_FLOAT128 FltS5; - SETJMP_FLOAT128 FltS6; - SETJMP_FLOAT128 FltS7; - SETJMP_FLOAT128 FltS8; - SETJMP_FLOAT128 FltS9; - SETJMP_FLOAT128 FltS10; - SETJMP_FLOAT128 FltS11; - SETJMP_FLOAT128 FltS12; - SETJMP_FLOAT128 FltS13; - SETJMP_FLOAT128 FltS14; - SETJMP_FLOAT128 FltS15; - SETJMP_FLOAT128 FltS16; - SETJMP_FLOAT128 FltS17; - SETJMP_FLOAT128 FltS18; - SETJMP_FLOAT128 FltS19; - __int64 FPSR; - __int64 StIIP; - __int64 BrS0; - __int64 BrS1; - __int64 BrS2; - __int64 BrS3; - __int64 BrS4; - __int64 IntS0; - __int64 IntS1; - __int64 IntS2; - __int64 IntS3; - __int64 RsBSP; - __int64 RsPFS; - __int64 ApUNAT; - __int64 ApLC; - __int64 IntSp; - __int64 IntNats; - __int64 Preds; - - } _JUMP_BUFFER; -#elif defined(__x86_64) - typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { - unsigned __int64 Part[2]; - } SETJMP_FLOAT128; - -#define _JBLEN 16 - typedef SETJMP_FLOAT128 _JBTYPE; - - typedef struct _JUMP_BUFFER { - unsigned __int64 Frame; - unsigned __int64 Rbx; - unsigned __int64 Rsp; - unsigned __int64 Rbp; - unsigned __int64 Rsi; - unsigned __int64 Rdi; - unsigned __int64 R12; - unsigned __int64 R13; - unsigned __int64 R14; - unsigned __int64 R15; - unsigned __int64 Rip; - unsigned __int64 Spare; - SETJMP_FLOAT128 Xmm6; - SETJMP_FLOAT128 Xmm7; - SETJMP_FLOAT128 Xmm8; - SETJMP_FLOAT128 Xmm9; - SETJMP_FLOAT128 Xmm10; - SETJMP_FLOAT128 Xmm11; - SETJMP_FLOAT128 Xmm12; - SETJMP_FLOAT128 Xmm13; - SETJMP_FLOAT128 Xmm14; - SETJMP_FLOAT128 Xmm15; - } _JUMP_BUFFER; -#endif -#ifndef _JMP_BUF_DEFINED - typedef _JBTYPE jmp_buf[_JBLEN]; -#define _JMP_BUF_DEFINED -#endif - - void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void); - -#ifdef USE_MINGW_SETJMP_TWO_ARGS -#ifndef _INC_SETJMPEX -#define setjmp(BUF) _setjmp((BUF),mingw_getsp()) - int __cdecl __attribute__ ((__nothrow__)) _setjmp(jmp_buf _Buf,void *_Ctx); -#else -#undef setjmp -#define setjmp(BUF) _setjmpex((BUF),mingw_getsp()) -#define setjmpex(BUF) _setjmpex((BUF),mingw_getsp()) - int __cdecl __attribute__ ((__nothrow__)) _setjmpex(jmp_buf _Buf,void *_Ctx); -#endif -#else -#ifndef _INC_SETJMPEX -#define setjmp _setjmp -#endif - int __cdecl __attribute__ ((__nothrow__)) setjmp(jmp_buf _Buf); -#endif - - __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl ms_longjmp(jmp_buf _Buf,int _Value)/* throw(...)*/; - __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value); - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SETJMP +#define _INC_SETJMP + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#if (defined(_X86_) && !defined(__x86_64)) + +#define _JBLEN 16 +#define _JBTYPE int + + typedef struct __JUMP_BUFFER { + unsigned long Ebp; + unsigned long Ebx; + unsigned long Edi; + unsigned long Esi; + unsigned long Esp; + unsigned long Eip; + unsigned long Registration; + unsigned long TryLevel; + unsigned long Cookie; + unsigned long UnwindFunc; + unsigned long UnwindData[6]; + } _JUMP_BUFFER; +#elif defined(__ia64__) + typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { + __int64 LowPart; + __int64 HighPart; + } SETJMP_FLOAT128; + +#define _JBLEN 33 + typedef SETJMP_FLOAT128 _JBTYPE; + + typedef struct __JUMP_BUFFER { + + unsigned long iAReserved[6]; + + unsigned long Registration; + unsigned long TryLevel; + unsigned long Cookie; + unsigned long UnwindFunc; + + unsigned long UnwindData[6]; + + SETJMP_FLOAT128 FltS0; + SETJMP_FLOAT128 FltS1; + SETJMP_FLOAT128 FltS2; + SETJMP_FLOAT128 FltS3; + SETJMP_FLOAT128 FltS4; + SETJMP_FLOAT128 FltS5; + SETJMP_FLOAT128 FltS6; + SETJMP_FLOAT128 FltS7; + SETJMP_FLOAT128 FltS8; + SETJMP_FLOAT128 FltS9; + SETJMP_FLOAT128 FltS10; + SETJMP_FLOAT128 FltS11; + SETJMP_FLOAT128 FltS12; + SETJMP_FLOAT128 FltS13; + SETJMP_FLOAT128 FltS14; + SETJMP_FLOAT128 FltS15; + SETJMP_FLOAT128 FltS16; + SETJMP_FLOAT128 FltS17; + SETJMP_FLOAT128 FltS18; + SETJMP_FLOAT128 FltS19; + __int64 FPSR; + __int64 StIIP; + __int64 BrS0; + __int64 BrS1; + __int64 BrS2; + __int64 BrS3; + __int64 BrS4; + __int64 IntS0; + __int64 IntS1; + __int64 IntS2; + __int64 IntS3; + __int64 RsBSP; + __int64 RsPFS; + __int64 ApUNAT; + __int64 ApLC; + __int64 IntSp; + __int64 IntNats; + __int64 Preds; + + } _JUMP_BUFFER; +#elif defined(__x86_64) + typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { + unsigned __int64 Part[2]; + } SETJMP_FLOAT128; + +#define _JBLEN 16 + typedef SETJMP_FLOAT128 _JBTYPE; + + typedef struct _JUMP_BUFFER { + unsigned __int64 Frame; + unsigned __int64 Rbx; + unsigned __int64 Rsp; + unsigned __int64 Rbp; + unsigned __int64 Rsi; + unsigned __int64 Rdi; + unsigned __int64 R12; + unsigned __int64 R13; + unsigned __int64 R14; + unsigned __int64 R15; + unsigned __int64 Rip; + unsigned __int64 Spare; + SETJMP_FLOAT128 Xmm6; + SETJMP_FLOAT128 Xmm7; + SETJMP_FLOAT128 Xmm8; + SETJMP_FLOAT128 Xmm9; + SETJMP_FLOAT128 Xmm10; + SETJMP_FLOAT128 Xmm11; + SETJMP_FLOAT128 Xmm12; + SETJMP_FLOAT128 Xmm13; + SETJMP_FLOAT128 Xmm14; + SETJMP_FLOAT128 Xmm15; + } _JUMP_BUFFER; +#endif +#ifndef _JMP_BUF_DEFINED + typedef _JBTYPE jmp_buf[_JBLEN]; +#define _JMP_BUF_DEFINED +#endif + + void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void); + +#ifdef USE_MINGW_SETJMP_TWO_ARGS +#ifndef _INC_SETJMPEX +#define setjmp(BUF) _setjmp((BUF),mingw_getsp()) + int __cdecl __attribute__ ((__nothrow__)) _setjmp(jmp_buf _Buf,void *_Ctx); +#else +#undef setjmp +#define setjmp(BUF) _setjmpex((BUF),mingw_getsp()) +#define setjmpex(BUF) _setjmpex((BUF),mingw_getsp()) + int __cdecl __attribute__ ((__nothrow__)) _setjmpex(jmp_buf _Buf,void *_Ctx); +#endif +#else +#ifndef _INC_SETJMPEX +#define setjmp _setjmp +#endif + int __cdecl __attribute__ ((__nothrow__)) setjmp(jmp_buf _Buf); +#endif + + __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl ms_longjmp(jmp_buf _Buf,int _Value)/* throw(...)*/; + __declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value); + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/share.h b/tcc/include/share.h index 9b1b9650..358855fe 100644 --- a/tcc/include/share.h +++ b/tcc/include/share.h @@ -1,28 +1,28 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SHARE -#define _INC_SHARE - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#define _SH_COMPAT 0x00 -#define _SH_DENYRW 0x10 -#define _SH_DENYWR 0x20 -#define _SH_DENYRD 0x30 -#define _SH_DENYNO 0x40 -#define _SH_SECURE 0x80 - -#ifndef NO_OLDNAMES -#define SH_COMPAT _SH_COMPAT -#define SH_DENYRW _SH_DENYRW -#define SH_DENYWR _SH_DENYWR -#define SH_DENYRD _SH_DENYRD -#define SH_DENYNO _SH_DENYNO -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SHARE +#define _INC_SHARE + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#define _SH_COMPAT 0x00 +#define _SH_DENYRW 0x10 +#define _SH_DENYWR 0x20 +#define _SH_DENYRD 0x30 +#define _SH_DENYNO 0x40 +#define _SH_SECURE 0x80 + +#ifndef NO_OLDNAMES +#define SH_COMPAT _SH_COMPAT +#define SH_DENYRW _SH_DENYRW +#define SH_DENYWR _SH_DENYWR +#define SH_DENYRD _SH_DENYRD +#define SH_DENYNO _SH_DENYNO +#endif + +#endif diff --git a/tcc/include/signal.h b/tcc/include/signal.h index c2424d35..a518f6b3 100644 --- a/tcc/include/signal.h +++ b/tcc/include/signal.h @@ -1,63 +1,63 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_SIGNAL -#define _INC_SIGNAL - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _SIG_ATOMIC_T_DEFINED -#define _SIG_ATOMIC_T_DEFINED - typedef int sig_atomic_t; -#endif - -#define NSIG 23 - -#define SIGHUP 1 /* hangup */ -#define SIGINT 2 -#define SIGQUIT 3 /* quit */ -#define SIGILL 4 -#define SIGTRAP 5 /* trace trap (not reset when caught) */ -#define SIGIOT 6 /* IOT instruction */ -#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */ -#define SIGEMT 7 /* EMT instruction */ -#define SIGFPE 8 -#define SIGKILL 9 /* kill (cannot be caught or ignored) */ -#define SIGBUS 10 /* bus error */ -#define SIGSEGV 11 -#define SIGSYS 12 /* bad argument to system call */ -#define SIGPIPE 13 /* write on a pipe with no one to read it */ -#ifdef __USE_MINGW_ALARM -#define SIGALRM 14 /* alarm clock */ -#endif -#define SIGTERM 15 -#define SIGBREAK 21 -#define SIGABRT2 22 - -#define SIGABRT_COMPAT 6 - - typedef void (*__p_sig_fn_t)(int); - -#define SIG_DFL (__p_sig_fn_t)0 -#define SIG_IGN (__p_sig_fn_t)1 -#define SIG_GET (__p_sig_fn_t)2 -#define SIG_SGE (__p_sig_fn_t)3 -#define SIG_ACK (__p_sig_fn_t)4 -#define SIG_ERR (__p_sig_fn_t)-1 - - extern void **__cdecl __pxcptinfoptrs(void); -#define _pxcptinfoptrs (*__pxcptinfoptrs()) - - __p_sig_fn_t __cdecl signal(int _SigNum,__p_sig_fn_t _Func); - int __cdecl raise(int _SigNum); - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_SIGNAL +#define _INC_SIGNAL + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _SIG_ATOMIC_T_DEFINED +#define _SIG_ATOMIC_T_DEFINED + typedef int sig_atomic_t; +#endif + +#define NSIG 23 + +#define SIGHUP 1 /* hangup */ +#define SIGINT 2 +#define SIGQUIT 3 /* quit */ +#define SIGILL 4 +#define SIGTRAP 5 /* trace trap (not reset when caught) */ +#define SIGIOT 6 /* IOT instruction */ +#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */ +#define SIGEMT 7 /* EMT instruction */ +#define SIGFPE 8 +#define SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define SIGBUS 10 /* bus error */ +#define SIGSEGV 11 +#define SIGSYS 12 /* bad argument to system call */ +#define SIGPIPE 13 /* write on a pipe with no one to read it */ +#ifdef __USE_MINGW_ALARM +#define SIGALRM 14 /* alarm clock */ +#endif +#define SIGTERM 15 +#define SIGBREAK 21 +#define SIGABRT2 22 + +#define SIGABRT_COMPAT 6 + + typedef void (*__p_sig_fn_t)(int); + +#define SIG_DFL (__p_sig_fn_t)0 +#define SIG_IGN (__p_sig_fn_t)1 +#define SIG_GET (__p_sig_fn_t)2 +#define SIG_SGE (__p_sig_fn_t)3 +#define SIG_ACK (__p_sig_fn_t)4 +#define SIG_ERR (__p_sig_fn_t)-1 + + extern void **__cdecl __pxcptinfoptrs(void); +#define _pxcptinfoptrs (*__pxcptinfoptrs()) + + __p_sig_fn_t __cdecl signal(int _SigNum,__p_sig_fn_t _Func); + int __cdecl raise(int _SigNum); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/stdalign.h b/tcc/include/stdalign.h index 51b96270..ae46c349 100644 --- a/tcc/include/stdalign.h +++ b/tcc/include/stdalign.h @@ -1,16 +1,16 @@ -#ifndef _STDALIGN_H -#define _STDALIGN_H - -#if __STDC_VERSION__ < 201112L && (defined(__GNUC__) || defined(__TINYC__)) -# define _Alignas(t) __attribute__((__aligned__(t))) -# define _Alignof(t) __alignof__(t) -#endif - -#define alignas _Alignas -#define alignof _Alignof - -#define __alignas_is_defined 1 -#define __alignof_is_defined 1 - -#endif /* _STDALIGN_H */ - +#ifndef _STDALIGN_H +#define _STDALIGN_H + +#if __STDC_VERSION__ < 201112L && (defined(__GNUC__) || defined(__TINYC__)) +# define _Alignas(t) __attribute__((__aligned__(t))) +# define _Alignof(t) __alignof__(t) +#endif + +#define alignas _Alignas +#define alignof _Alignof + +#define __alignas_is_defined 1 +#define __alignof_is_defined 1 + +#endif /* _STDALIGN_H */ + diff --git a/tcc/include/stdarg.h b/tcc/include/stdarg.h index 4b3089f0..aa784da2 100644 --- a/tcc/include/stdarg.h +++ b/tcc/include/stdarg.h @@ -1,14 +1,14 @@ -#ifndef _STDARG_H -#define _STDARG_H - -typedef __builtin_va_list va_list; -#define va_start __builtin_va_start -#define va_arg __builtin_va_arg -#define va_copy __builtin_va_copy -#define va_end __builtin_va_end - -/* fix a buggy dependency on GCC in libio.h */ -typedef va_list __gnuc_va_list; -#define _VA_LIST_DEFINED - -#endif /* _STDARG_H */ +#ifndef _STDARG_H +#define _STDARG_H + +typedef __builtin_va_list va_list; +#define va_start __builtin_va_start +#define va_arg __builtin_va_arg +#define va_copy __builtin_va_copy +#define va_end __builtin_va_end + +/* fix a buggy dependency on GCC in libio.h */ +typedef va_list __gnuc_va_list; +#define _VA_LIST_DEFINED + +#endif /* _STDARG_H */ diff --git a/tcc/include/stdatomic.h b/tcc/include/stdatomic.h index 28778b57..ee3024c0 100644 --- a/tcc/include/stdatomic.h +++ b/tcc/include/stdatomic.h @@ -1,125 +1,125 @@ -/* This file is derived from clang's stdatomic.h */ - -/*===---- stdatomic.h - Standard header for atomic types and operations -----=== - * - * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. - * See https://llvm.org/LICENSE.txt for license information. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - * - *===-----------------------------------------------------------------------=== - */ - -#ifndef _STDATOMIC_H -#define _STDATOMIC_H - -#include -#include - -/* Memory ordering */ -typedef enum { - memory_order_relaxed = __ATOMIC_RELAXED, - memory_order_consume = __ATOMIC_CONSUME, - memory_order_acquire = __ATOMIC_ACQUIRE, - memory_order_release = __ATOMIC_RELEASE, - memory_order_acq_rel = __ATOMIC_ACQ_REL, - memory_order_seq_cst = __ATOMIC_SEQ_CST, -} memory_order; - -/* Atomic typedefs */ -typedef _Atomic(_Bool) atomic_bool; -typedef _Atomic(char) atomic_char; -typedef _Atomic(signed char) atomic_schar; -typedef _Atomic(unsigned char) atomic_uchar; -typedef _Atomic(short) atomic_short; -typedef _Atomic(unsigned short) atomic_ushort; -typedef _Atomic(int) atomic_int; -typedef _Atomic(unsigned int) atomic_uint; -typedef _Atomic(long) atomic_long; -typedef _Atomic(unsigned long) atomic_ulong; -typedef _Atomic(long long) atomic_llong; -typedef _Atomic(unsigned long long) atomic_ullong; -typedef _Atomic(uint_least16_t) atomic_char16_t; -typedef _Atomic(uint_least32_t) atomic_char32_t; -typedef _Atomic(wchar_t) atomic_wchar_t; -typedef _Atomic(int_least8_t) atomic_int_least8_t; -typedef _Atomic(uint_least8_t) atomic_uint_least8_t; -typedef _Atomic(int_least16_t) atomic_int_least16_t; -typedef _Atomic(uint_least16_t) atomic_uint_least16_t; -typedef _Atomic(int_least32_t) atomic_int_least32_t; -typedef _Atomic(uint_least32_t) atomic_uint_least32_t; -typedef _Atomic(int_least64_t) atomic_int_least64_t; -typedef _Atomic(uint_least64_t) atomic_uint_least64_t; -typedef _Atomic(int_fast8_t) atomic_int_fast8_t; -typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t; -typedef _Atomic(int_fast16_t) atomic_int_fast16_t; -typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t; -typedef _Atomic(int_fast32_t) atomic_int_fast32_t; -typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t; -typedef _Atomic(int_fast64_t) atomic_int_fast64_t; -typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t; -typedef _Atomic(intptr_t) atomic_intptr_t; -typedef _Atomic(uintptr_t) atomic_uintptr_t; -typedef _Atomic(size_t) atomic_size_t; -typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t; -typedef _Atomic(intmax_t) atomic_intmax_t; -typedef _Atomic(uintmax_t) atomic_uintmax_t; - -/* Atomic flag */ -typedef struct { - atomic_bool value; -} atomic_flag; - -#define ATOMIC_FLAG_INIT {0} - -#define atomic_flag_test_and_set(object) \ - __c11_atomic_exchange(&(object)->value, 1, __ATOMIC_SEQ_CST) -#define atomic_flag_test_and_set_explicit(object, order) \ - __c11_atomic_exchange(&(object)->value, 1, order) - -#define atomic_flag_clear(object) \ - __c11_atomic_store(&(object)->value, 0, __ATOMIC_SEQ_CST) -#define atomic_flag_clear_explicit(object, order) \ - __c11_atomic_store(&(object)->value, 0, order) - -/* Generic routines */ -#define atomic_store(object, desired) \ - __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) -#define atomic_store_explicit __c11_atomic_store - -#define atomic_load(object) \ - __c11_atomic_load(object, __ATOMIC_SEQ_CST) -#define atomic_load_explicit __c11_atomic_load - -#define atomic_exchange(object, desired) \ - __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) -#define atomic_exchange_explicit __c11_atomic_exchange - -#define atomic_compare_exchange_strong(object, expected, desired) \ - __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) -#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong - -#define atomic_compare_exchange_weak(object, expected, desired) \ - __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) -#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak - -#define atomic_fetch_add(object, operand) \ - __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_add_explicit __c11_atomic_fetch_add - -#define atomic_fetch_sub(object, operand) \ - __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub - -#define atomic_fetch_or(object, operand) \ - __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_or_explicit __c11_atomic_fetch_or - -#define atomic_fetch_xor(object, operand) \ - __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor - -#define atomic_fetch_and(object, operand) \ - __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) -#define atomic_fetch_and_explicit __c11_atomic_fetch_and - -#endif /* _STDATOMIC_H */ +/* This file is derived from clang's stdatomic.h */ + +/*===---- stdatomic.h - Standard header for atomic types and operations -----=== + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef _STDATOMIC_H +#define _STDATOMIC_H + +#include +#include + +/* Memory ordering */ +typedef enum { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST, +} memory_order; + +/* Atomic typedefs */ +typedef _Atomic(_Bool) atomic_bool; +typedef _Atomic(char) atomic_char; +typedef _Atomic(signed char) atomic_schar; +typedef _Atomic(unsigned char) atomic_uchar; +typedef _Atomic(short) atomic_short; +typedef _Atomic(unsigned short) atomic_ushort; +typedef _Atomic(int) atomic_int; +typedef _Atomic(unsigned int) atomic_uint; +typedef _Atomic(long) atomic_long; +typedef _Atomic(unsigned long) atomic_ulong; +typedef _Atomic(long long) atomic_llong; +typedef _Atomic(unsigned long long) atomic_ullong; +typedef _Atomic(uint_least16_t) atomic_char16_t; +typedef _Atomic(uint_least32_t) atomic_char32_t; +typedef _Atomic(wchar_t) atomic_wchar_t; +typedef _Atomic(int_least8_t) atomic_int_least8_t; +typedef _Atomic(uint_least8_t) atomic_uint_least8_t; +typedef _Atomic(int_least16_t) atomic_int_least16_t; +typedef _Atomic(uint_least16_t) atomic_uint_least16_t; +typedef _Atomic(int_least32_t) atomic_int_least32_t; +typedef _Atomic(uint_least32_t) atomic_uint_least32_t; +typedef _Atomic(int_least64_t) atomic_int_least64_t; +typedef _Atomic(uint_least64_t) atomic_uint_least64_t; +typedef _Atomic(int_fast8_t) atomic_int_fast8_t; +typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t; +typedef _Atomic(int_fast16_t) atomic_int_fast16_t; +typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t; +typedef _Atomic(int_fast32_t) atomic_int_fast32_t; +typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t; +typedef _Atomic(int_fast64_t) atomic_int_fast64_t; +typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t; +typedef _Atomic(intptr_t) atomic_intptr_t; +typedef _Atomic(uintptr_t) atomic_uintptr_t; +typedef _Atomic(size_t) atomic_size_t; +typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t; +typedef _Atomic(intmax_t) atomic_intmax_t; +typedef _Atomic(uintmax_t) atomic_uintmax_t; + +/* Atomic flag */ +typedef struct { + atomic_bool value; +} atomic_flag; + +#define ATOMIC_FLAG_INIT {0} + +#define atomic_flag_test_and_set(object) \ + __c11_atomic_exchange(&(object)->value, 1, __ATOMIC_SEQ_CST) +#define atomic_flag_test_and_set_explicit(object, order) \ + __c11_atomic_exchange(&(object)->value, 1, order) + +#define atomic_flag_clear(object) \ + __c11_atomic_store(&(object)->value, 0, __ATOMIC_SEQ_CST) +#define atomic_flag_clear_explicit(object, order) \ + __c11_atomic_store(&(object)->value, 0, order) + +/* Generic routines */ +#define atomic_store(object, desired) \ + __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) +#define atomic_store_explicit __c11_atomic_store + +#define atomic_load(object) \ + __c11_atomic_load(object, __ATOMIC_SEQ_CST) +#define atomic_load_explicit __c11_atomic_load + +#define atomic_exchange(object, desired) \ + __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) +#define atomic_exchange_explicit __c11_atomic_exchange + +#define atomic_compare_exchange_strong(object, expected, desired) \ + __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong + +#define atomic_compare_exchange_weak(object, expected, desired) \ + __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak + +#define atomic_fetch_add(object, operand) \ + __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_add_explicit __c11_atomic_fetch_add + +#define atomic_fetch_sub(object, operand) \ + __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub + +#define atomic_fetch_or(object, operand) \ + __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_or_explicit __c11_atomic_fetch_or + +#define atomic_fetch_xor(object, operand) \ + __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor + +#define atomic_fetch_and(object, operand) \ + __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_and_explicit __c11_atomic_fetch_and + +#endif /* _STDATOMIC_H */ diff --git a/tcc/include/stdbool.h b/tcc/include/stdbool.h index 71579490..d2ee446e 100644 --- a/tcc/include/stdbool.h +++ b/tcc/include/stdbool.h @@ -1,11 +1,11 @@ -#ifndef _STDBOOL_H -#define _STDBOOL_H - -/* ISOC99 boolean */ - -#define bool _Bool -#define true 1 -#define false 0 -#define __bool_true_false_are_defined 1 - -#endif /* _STDBOOL_H */ +#ifndef _STDBOOL_H +#define _STDBOOL_H + +/* ISOC99 boolean */ + +#define bool _Bool +#define true 1 +#define false 0 +#define __bool_true_false_are_defined 1 + +#endif /* _STDBOOL_H */ diff --git a/tcc/include/stddef.h b/tcc/include/stddef.h index 52232361..ea024f30 100644 --- a/tcc/include/stddef.h +++ b/tcc/include/stddef.h @@ -1,39 +1,39 @@ -#ifndef _STDDEF_H -#define _STDDEF_H - -typedef __SIZE_TYPE__ size_t; -typedef __PTRDIFF_TYPE__ ssize_t; -typedef __WCHAR_TYPE__ wchar_t; -typedef __PTRDIFF_TYPE__ ptrdiff_t; -typedef __PTRDIFF_TYPE__ intptr_t; -typedef __SIZE_TYPE__ uintptr_t; - -#if __STDC_VERSION__ >= 201112L -typedef union { long long __ll; long double __ld; } max_align_t; -#endif - -#ifndef NULL -#define NULL ((void*)0) -#endif - -#undef offsetof -#define offsetof(type, field) ((size_t)&((type *)0)->field) - -void *alloca(size_t size); - -#endif - -/* Older glibc require a wint_t from (when requested - by __need_wint_t, as otherwise stddef.h isn't allowed to - define this type). Note that this must be outside the normal - _STDDEF_H guard, so that it works even when we've included the file - already (without requiring wint_t). Some other libs define _WINT_T - if they've already provided that type, so we can use that as guard. - TCC defines __WINT_TYPE__ for us. */ -#if defined (__need_wint_t) -#ifndef _WINT_T -#define _WINT_T -typedef __WINT_TYPE__ wint_t; -#endif -#undef __need_wint_t -#endif +#ifndef _STDDEF_H +#define _STDDEF_H + +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ssize_t; +typedef __WCHAR_TYPE__ wchar_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __PTRDIFF_TYPE__ intptr_t; +typedef __SIZE_TYPE__ uintptr_t; + +#if __STDC_VERSION__ >= 201112L +typedef union { long long __ll; long double __ld; } max_align_t; +#endif + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#undef offsetof +#define offsetof(type, field) ((size_t)&((type *)0)->field) + +void *alloca(size_t size); + +#endif + +/* Older glibc require a wint_t from (when requested + by __need_wint_t, as otherwise stddef.h isn't allowed to + define this type). Note that this must be outside the normal + _STDDEF_H guard, so that it works even when we've included the file + already (without requiring wint_t). Some other libs define _WINT_T + if they've already provided that type, so we can use that as guard. + TCC defines __WINT_TYPE__ for us. */ +#if defined (__need_wint_t) +#ifndef _WINT_T +#define _WINT_T +typedef __WINT_TYPE__ wint_t; +#endif +#undef __need_wint_t +#endif diff --git a/tcc/include/stdint.h b/tcc/include/stdint.h index d6c0d33c..cde32b6e 100644 --- a/tcc/include/stdint.h +++ b/tcc/include/stdint.h @@ -1,212 +1,212 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* ISO C9x 7.18 Integer types - * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * Contributor: Danny Smith - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Date: 2000-12-02 - */ - - -#ifndef _STDINT_H -#define _STDINT_H - -#include <_mingw.h> - -#define __need_wint_t -#define __need_wchar_t -#include "stddef.h" - -#ifndef __int8_t_defined -#define __int8_t_defined -/* 7.18.1.1 Exact-width integer types */ -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef int int32_t; -typedef unsigned uint32_t; -typedef long long int64_t; -typedef unsigned long long uint64_t; -#endif - -/* 7.18.1.2 Minimum-width integer types */ -typedef signed char int_least8_t; -typedef unsigned char uint_least8_t; -typedef short int_least16_t; -typedef unsigned short uint_least16_t; -typedef int int_least32_t; -typedef unsigned uint_least32_t; -typedef long long int_least64_t; -typedef unsigned long long uint_least64_t; - -/* 7.18.1.3 Fastest minimum-width integer types - * Not actually guaranteed to be fastest for all purposes - * Here we use the exact-width types for 8 and 16-bit ints. - */ -typedef char int_fast8_t; -typedef unsigned char uint_fast8_t; -typedef short int_fast16_t; -typedef unsigned short uint_fast16_t; -typedef int int_fast32_t; -typedef unsigned int uint_fast32_t; -typedef long long int_fast64_t; -typedef unsigned long long uint_fast64_t; - -/* 7.18.1.5 Greatest-width integer types */ -typedef long long intmax_t; -typedef unsigned long long uintmax_t; - -/* 7.18.2 Limits of specified-width integer types */ -#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) - -/* 7.18.2.1 Limits of exact-width integer types */ -#define INT8_MIN (-128) -#define INT16_MIN (-32768) -#define INT32_MIN (-2147483647 - 1) -#define INT64_MIN (-9223372036854775807LL - 1) - -#define INT8_MAX 127 -#define INT16_MAX 32767 -#define INT32_MAX 2147483647 -#define INT64_MAX 9223372036854775807LL - -#define UINT8_MAX 0xff /* 255U */ -#define UINT16_MAX 0xffff /* 65535U */ -#define UINT32_MAX 0xffffffff /* 4294967295U */ -#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ - -/* 7.18.2.2 Limits of minimum-width integer types */ -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST64_MIN INT64_MIN - -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MAX INT64_MAX - -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -/* 7.18.2.3 Limits of fastest minimum-width integer types */ -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST64_MIN INT64_MIN - -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MAX INT64_MAX - -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -/* 7.18.2.4 Limits of integer types capable of holding - object pointers */ -#ifdef _WIN64 -#define INTPTR_MIN INT64_MIN -#define INTPTR_MAX INT64_MAX -#define UINTPTR_MAX UINT64_MAX -#else -#define INTPTR_MIN INT32_MIN -#define INTPTR_MAX INT32_MAX -#define UINTPTR_MAX UINT32_MAX -#endif - -/* 7.18.2.5 Limits of greatest-width integer types */ -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -/* 7.18.3 Limits of other integer types */ -#ifdef _WIN64 -#define PTRDIFF_MIN INT64_MIN -#define PTRDIFF_MAX INT64_MAX -#else -#define PTRDIFF_MIN INT32_MIN -#define PTRDIFF_MAX INT32_MAX -#endif - -#define SIG_ATOMIC_MIN INT32_MIN -#define SIG_ATOMIC_MAX INT32_MAX - -#ifndef SIZE_MAX -#ifdef _WIN64 -#define SIZE_MAX UINT64_MAX -#else -#define SIZE_MAX UINT32_MAX -#endif -#endif - -#ifndef WCHAR_MIN /* also in wchar.h */ -#define WCHAR_MIN 0 -#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */ -#endif - -/* - * wint_t is unsigned short for compatibility with MS runtime - */ -#define WINT_MIN 0 -#define WINT_MAX ((wint_t)-1) /* UINT16_MAX */ - -#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ - - -/* 7.18.4 Macros for integer constants */ -#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) - -/* 7.18.4.1 Macros for minimum-width integer constants - - According to Douglas Gwyn : - "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC - 9899:1999 as initially published, the expansion was required - to be an integer constant of precisely matching type, which - is impossible to accomplish for the shorter types on most - platforms, because C99 provides no standard way to designate - an integer constant with width less than that of type int. - TC1 changed this to require just an integer constant - *expression* with *promoted* type." - - The trick used here is from Clive D W Feather. -*/ - -#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val)) -#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val)) -#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val)) -/* The 'trick' doesn't work in C89 for long long because, without - suffix, (val) will be evaluated as int, not intmax_t */ -#define INT64_C(val) val##LL - -#define UINT8_C(val) (UINT_LEAST8_MAX-UINT_LEAST8_MAX+(val)) -#define UINT16_C(val) (UINT_LEAST16_MAX-UINT_LEAST16_MAX+(val)) -#define UINT32_C(val) (UINT_LEAST32_MAX-UINT_LEAST32_MAX+(val)) -#define UINT64_C(val) val##ULL - -/* 7.18.4.2 Macros for greatest-width integer constants */ -#define INTMAX_C(val) val##LL -#define UINTMAX_C(val) val##ULL - -#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* ISO C9x 7.18 Integer types + * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * Contributor: Danny Smith + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Date: 2000-12-02 + */ + + +#ifndef _STDINT_H +#define _STDINT_H + +#include <_mingw.h> + +#define __need_wint_t +#define __need_wchar_t +#include "stddef.h" + +#ifndef __int8_t_defined +#define __int8_t_defined +/* 7.18.1.1 Exact-width integer types */ +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + +/* 7.18.1.2 Minimum-width integer types */ +typedef signed char int_least8_t; +typedef unsigned char uint_least8_t; +typedef short int_least16_t; +typedef unsigned short uint_least16_t; +typedef int int_least32_t; +typedef unsigned uint_least32_t; +typedef long long int_least64_t; +typedef unsigned long long uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types + * Not actually guaranteed to be fastest for all purposes + * Here we use the exact-width types for 8 and 16-bit ints. + */ +typedef char int_fast8_t; +typedef unsigned char uint_fast8_t; +typedef short int_fast16_t; +typedef unsigned short uint_fast16_t; +typedef int int_fast32_t; +typedef unsigned int uint_fast32_t; +typedef long long int_fast64_t; +typedef unsigned long long uint_fast64_t; + +/* 7.18.1.5 Greatest-width integer types */ +typedef long long intmax_t; +typedef unsigned long long uintmax_t; + +/* 7.18.2 Limits of specified-width integer types */ +#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) + +/* 7.18.2.1 Limits of exact-width integer types */ +#define INT8_MIN (-128) +#define INT16_MIN (-32768) +#define INT32_MIN (-2147483647 - 1) +#define INT64_MIN (-9223372036854775807LL - 1) + +#define INT8_MAX 127 +#define INT16_MAX 32767 +#define INT32_MAX 2147483647 +#define INT64_MAX 9223372036854775807LL + +#define UINT8_MAX 0xff /* 255U */ +#define UINT16_MAX 0xffff /* 65535U */ +#define UINT32_MAX 0xffffffff /* 4294967295U */ +#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ + +/* 7.18.2.2 Limits of minimum-width integer types */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* 7.18.2.3 Limits of fastest minimum-width integer types */ +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN + +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +/* 7.18.2.4 Limits of integer types capable of holding + object pointers */ +#ifdef _WIN64 +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX +#else +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#endif + +/* 7.18.2.5 Limits of greatest-width integer types */ +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +/* 7.18.3 Limits of other integer types */ +#ifdef _WIN64 +#define PTRDIFF_MIN INT64_MIN +#define PTRDIFF_MAX INT64_MAX +#else +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX +#endif + +#define SIG_ATOMIC_MIN INT32_MIN +#define SIG_ATOMIC_MAX INT32_MAX + +#ifndef SIZE_MAX +#ifdef _WIN64 +#define SIZE_MAX UINT64_MAX +#else +#define SIZE_MAX UINT32_MAX +#endif +#endif + +#ifndef WCHAR_MIN /* also in wchar.h */ +#define WCHAR_MIN 0 +#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */ +#endif + +/* + * wint_t is unsigned short for compatibility with MS runtime + */ +#define WINT_MIN 0 +#define WINT_MAX ((wint_t)-1) /* UINT16_MAX */ + +#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ + + +/* 7.18.4 Macros for integer constants */ +#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) + +/* 7.18.4.1 Macros for minimum-width integer constants + + According to Douglas Gwyn : + "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC + 9899:1999 as initially published, the expansion was required + to be an integer constant of precisely matching type, which + is impossible to accomplish for the shorter types on most + platforms, because C99 provides no standard way to designate + an integer constant with width less than that of type int. + TC1 changed this to require just an integer constant + *expression* with *promoted* type." + + The trick used here is from Clive D W Feather. +*/ + +#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val)) +#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val)) +#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val)) +/* The 'trick' doesn't work in C89 for long long because, without + suffix, (val) will be evaluated as int, not intmax_t */ +#define INT64_C(val) val##LL + +#define UINT8_C(val) (UINT_LEAST8_MAX-UINT_LEAST8_MAX+(val)) +#define UINT16_C(val) (UINT_LEAST16_MAX-UINT_LEAST16_MAX+(val)) +#define UINT32_C(val) (UINT_LEAST32_MAX-UINT_LEAST32_MAX+(val)) +#define UINT64_C(val) val##ULL + +/* 7.18.4.2 Macros for greatest-width integer constants */ +#define INTMAX_C(val) val##LL +#define UINTMAX_C(val) val##ULL + +#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ + +#endif diff --git a/tcc/include/stdio.h b/tcc/include/stdio.h index 0ec55246..da887936 100644 --- a/tcc/include/stdio.h +++ b/tcc/include/stdio.h @@ -1,429 +1,429 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDIO -#define _INC_STDIO - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#define BUFSIZ 512 -#define _NFILE _NSTREAM_ -#define _NSTREAM_ 512 -#define _IOB_ENTRIES 20 -#define EOF (-1) - -#ifndef _FILE_DEFINED - struct _iobuf { - char *_ptr; - int _cnt; - char *_base; - int _flag; - int _file; - int _charbuf; - int _bufsiz; - char *_tmpfname; - }; - typedef struct _iobuf FILE; -#define _FILE_DEFINED -#endif - -#ifdef _POSIX_ -#define _P_tmpdir "/" -#define _wP_tmpdir L"/" -#else -#define _P_tmpdir "\\" -#define _wP_tmpdir L"\\" -#endif - -#define L_tmpnam (sizeof(_P_tmpdir) + 12) - -#ifdef _POSIX_ -#define L_ctermid 9 -#define L_cuserid 32 -#endif - -#define SEEK_CUR 1 -#define SEEK_END 2 -#define SEEK_SET 0 - -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 - -#define FILENAME_MAX 260 -#define FOPEN_MAX 20 -#define _SYS_OPEN 20 -#define TMP_MAX 32767 - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif - -#ifndef _STDIO_DEFINED -#ifdef _WIN64 - _CRTIMP FILE *__cdecl __iob_func(void); -#else -#ifdef _MSVCRT_ -extern FILE _iob[]; /* A pointer to an array of FILE */ -#define __iob_func() (_iob) -#else -extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ -#define __iob_func() (*_imp___iob) -#define _iob __iob_func() -#endif -#endif -#endif - -#ifndef _FPOS_T_DEFINED -#define _FPOS_T_DEFINED -#undef _FPOSOFF - -#if (!defined(NO_OLDNAMES) || defined(__GNUC__)) && _INTEGRAL_MAX_BITS >= 64 - typedef __int64 fpos_t; -#define _FPOSOFF(fp) ((long)(fp)) -#else - typedef long long fpos_t; -#define _FPOSOFF(fp) ((long)(fp)) -#endif - -#endif - -#ifndef _STDSTREAM_DEFINED -#define _STDSTREAM_DEFINED - -#define stdin (&__iob_func()[0]) -#define stdout (&__iob_func()[1]) -#define stderr (&__iob_func()[2]) -#endif - -#define _IOREAD 0x0001 -#define _IOWRT 0x0002 - -#define _IOFBF 0x0000 -#define _IOLBF 0x0040 -#define _IONBF 0x0004 - -#define _IOMYBUF 0x0008 -#define _IOEOF 0x0010 -#define _IOERR 0x0020 -#define _IOSTRG 0x0040 -#define _IORW 0x0080 -#ifdef _POSIX_ -#define _IOAPPEND 0x0200 -#endif - -#define _TWO_DIGIT_EXPONENT 0x1 - -#ifndef _STDIO_DEFINED - - _CRTIMP int __cdecl _filbuf(FILE *_File); - _CRTIMP int __cdecl _flsbuf(int _Ch,FILE *_File); -#ifdef _POSIX_ - _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode); -#else - _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode,int _ShFlag); -#endif - void __cdecl clearerr(FILE *_File); - int __cdecl fclose(FILE *_File); - _CRTIMP int __cdecl _fcloseall(void); -#ifdef _POSIX_ - FILE *__cdecl fdopen(int _FileHandle,const char *_Mode); -#else - _CRTIMP FILE *__cdecl _fdopen(int _FileHandle,const char *_Mode); -#endif - int __cdecl feof(FILE *_File); - int __cdecl ferror(FILE *_File); - int __cdecl fflush(FILE *_File); - int __cdecl fgetc(FILE *_File); - _CRTIMP int __cdecl _fgetchar(void); - int __cdecl fgetpos(FILE *_File ,fpos_t *_Pos); - char *__cdecl fgets(char *_Buf,int _MaxCount,FILE *_File); -#ifdef _POSIX_ - int __cdecl fileno(FILE *_File); -#else - _CRTIMP int __cdecl _fileno(FILE *_File); -#endif - _CRTIMP char *__cdecl _tempnam(const char *_DirName,const char *_FilePrefix); - _CRTIMP int __cdecl _flushall(void); - FILE *__cdecl fopen(const char *_Filename,const char *_Mode); - FILE *fopen64(const char *filename,const char *mode); - int __cdecl fprintf(FILE *_File,const char *_Format,...); - int __cdecl fputc(int _Ch,FILE *_File); - _CRTIMP int __cdecl _fputchar(int _Ch); - int __cdecl fputs(const char *_Str,FILE *_File); - size_t __cdecl fread(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); - FILE *__cdecl freopen(const char *_Filename,const char *_Mode,FILE *_File); - int __cdecl fscanf(FILE *_File,const char *_Format,...); - int __cdecl fsetpos(FILE *_File,const fpos_t *_Pos); - int __cdecl fseek(FILE *_File,long _Offset,int _Origin); - int fseeko64(FILE* stream, _off64_t offset, int whence); - long __cdecl ftell(FILE *_File); - _off64_t ftello64(FILE * stream); - int __cdecl _fseeki64(FILE *_File,__int64 _Offset,int _Origin); - __int64 __cdecl _ftelli64(FILE *_File); - size_t __cdecl fwrite(const void *_Str,size_t _Size,size_t _Count,FILE *_File); - int __cdecl getc(FILE *_File); - int __cdecl getchar(void); - _CRTIMP int __cdecl _getmaxstdio(void); - char *__cdecl gets(char *_Buffer); - int __cdecl _getw(FILE *_File); -#ifndef _CRT_PERROR_DEFINED -#define _CRT_PERROR_DEFINED - void __cdecl perror(const char *_ErrMsg); -#endif - _CRTIMP int __cdecl _pclose(FILE *_File); - _CRTIMP FILE *__cdecl _popen(const char *_Command,const char *_Mode); -#if !defined(NO_OLDNAMES) && !defined(popen) -#define popen _popen -#define pclose _pclose -#endif - int __cdecl printf(const char *_Format,...); - int __cdecl putc(int _Ch,FILE *_File); - int __cdecl putchar(int _Ch); - int __cdecl puts(const char *_Str); - _CRTIMP int __cdecl _putw(int _Word,FILE *_File); -#ifndef _CRT_DIRECTORY_DEFINED -#define _CRT_DIRECTORY_DEFINED - int __cdecl remove(const char *_Filename); - int __cdecl rename(const char *_OldFilename,const char *_NewFilename); - _CRTIMP int __cdecl _unlink(const char *_Filename); -#ifndef NO_OLDNAMES - int __cdecl unlink(const char *_Filename); -#endif -#endif - void __cdecl rewind(FILE *_File); - _CRTIMP int __cdecl _rmtmp(void); - int __cdecl scanf(const char *_Format,...); - void __cdecl setbuf(FILE *_File,char *_Buffer); - _CRTIMP int __cdecl _setmaxstdio(int _Max); - _CRTIMP unsigned int __cdecl _set_output_format(unsigned int _Format); - _CRTIMP unsigned int __cdecl _get_output_format(void); - int __cdecl setvbuf(FILE *_File,char *_Buf,int _Mode,size_t _Size); - _CRTIMP int __cdecl _scprintf(const char *_Format,...); - int __cdecl sscanf(const char *_Src,const char *_Format,...); - _CRTIMP int __cdecl _snscanf(const char *_Src,size_t _MaxCount,const char *_Format,...); - FILE *__cdecl tmpfile(void); - char *__cdecl tmpnam(char *_Buffer); - int __cdecl ungetc(int _Ch,FILE *_File); - int __cdecl vfprintf(FILE *_File,const char *_Format,va_list _ArgList); - int __cdecl vprintf(const char *_Format,va_list _ArgList); - /* Make sure macros are not defined. */ -#pragma push_macro("vsnprintf") -#pragma push_macro("snprintf") -# undef vsnprintf -# undef snprintf - extern - __attribute__((format(gnu_printf, 3, 0))) __attribute__((nonnull (3))) - int __mingw_vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); - extern - __attribute__((format(gnu_printf, 3, 4))) __attribute__((nonnull (3))) - int __mingw_snprintf(char* s, size_t n, const char* format, ...); - int __cdecl vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snprintf(char *_Dest,size_t _Count,const char *_Format,...); - _CRTIMP int __cdecl _vsnprintf(char *_Dest,size_t _Count,const char *_Format,va_list _Args); - int __cdecl sprintf(char *_Dest,const char *_Format,...); - int __cdecl vsprintf(char *_Dest,const char *_Format,va_list _Args); -#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ - int __cdecl snprintf(char* s, size_t n, const char* format, ...); - __CRT_INLINE int __cdecl vsnprintf (char* s, size_t n, const char* format,va_list arg) { - return _vsnprintf ( s, n, format, arg); - } - int __cdecl vscanf(const char * Format, va_list argp); - int __cdecl vfscanf (FILE * fp, const char * Format,va_list argp); - int __cdecl vsscanf (const char * _Str,const char * Format,va_list argp); -#endif -/* Restore may prior defined macros snprintf/vsnprintf. */ -#pragma pop_macro("snprintf") -#pragma pop_macro("vsnprintf") -/* Check if vsnprintf and snprintf are defaulting to gnu-style. */ -# if defined(USE_MINGW_GNU_SNPRINTF) && USE_MINGW_GNU_SNPRINTF -# ifndef vsnprint -# define vsnprintf __mingw_vsnprintf -# endif -# ifndef snprintf -# define snprintf __mingw_snprintf -# endif -# endif - _CRTIMP int __cdecl _vscprintf(const char *_Format,va_list _ArgList); - _CRTIMP int __cdecl _set_printf_count_output(int _Value); - _CRTIMP int __cdecl _get_printf_count_output(void); - -#ifndef _WSTDIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifdef _POSIX_ - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); -#else - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); -#endif - wint_t __cdecl fgetwc(FILE *_File); - _CRTIMP wint_t __cdecl _fgetwchar(void); - wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); - wint_t __cdecl getwc(FILE *_File); - wint_t __cdecl getwchar(void); - wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); - wint_t __cdecl putwchar(wchar_t _Ch); - wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); - wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); - int __cdecl fputws(const wchar_t *_Str,FILE *_File); - _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); - _CRTIMP int __cdecl _putws(const wchar_t *_Str); - int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); - int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); - int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); - _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); - _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); -#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ - int __cdecl snwprintf (wchar_t* s, size_t n, const wchar_t* format, ...); - __CRT_INLINE int __cdecl vsnwprintf (wchar_t* s, size_t n, const wchar_t* format, va_list arg) { return _vsnwprintf(s,n,format,arg); } - int __cdecl vwscanf (const wchar_t *, va_list); - int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); - int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); -#endif - _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); - -#ifndef RC_INVOKED -#include -#endif - -#ifdef _CRT_NON_CONFORMING_SWPRINTFS -#ifndef __cplusplus -#define swprintf _swprintf -#define vswprintf _vswprintf -#define _swprintf_l __swprintf_l -#define _vswprintf_l __vswprintf_l -#endif -#endif - - _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); - _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); - int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); - int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - int __cdecl wscanf(const wchar_t *_Format,...); - _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); -#if !defined(NO_OLDNAMES) && !defined(wpopen) -#define wpopen _wpopen -#endif - _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); - _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); - _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); - -#undef _CRT_GETPUTWCHAR_NOINLINE - -#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) -#define getwchar() fgetwc(stdin) -#define putwchar(_c) fputwc((_c),stdout) -#else - __CRT_INLINE wint_t __cdecl getwchar() { return (fgetwc(stdin)); } - __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) { return (fputwc(_C,stdout)); } -#endif - -#define getwc(_stm) fgetwc(_stm) -#define putwc(_c,_stm) fputwc(_c,_stm) -#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) -#define _getwc_nolock(_stm) _fgetwc_nolock(_stm) - -#define _WSTDIO_DEFINED -#endif - -#define _STDIO_DEFINED -#endif - -#define _fgetc_nolock(_stream) (--(_stream)->_cnt >= 0 ? 0xff & *(_stream)->_ptr++ : _filbuf(_stream)) -#define _fputc_nolock(_c,_stream) (--(_stream)->_cnt >= 0 ? 0xff & (*(_stream)->_ptr++ = (char)(_c)) : _flsbuf((_c),(_stream))) -#define _getc_nolock(_stream) _fgetc_nolock(_stream) -#define _putc_nolock(_c,_stream) _fputc_nolock(_c,_stream) -#define _getchar_nolock() _getc_nolock(stdin) -#define _putchar_nolock(_c) _putc_nolock((_c),stdout) -#define _getwchar_nolock() _getwc_nolock(stdin) -#define _putwchar_nolock(_c) _putwc_nolock((_c),stdout) - - _CRTIMP void __cdecl _lock_file(FILE *_File); - _CRTIMP void __cdecl _unlock_file(FILE *_File); - _CRTIMP int __cdecl _fclose_nolock(FILE *_File); - _CRTIMP int __cdecl _fflush_nolock(FILE *_File); - _CRTIMP size_t __cdecl _fread_nolock(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); - _CRTIMP int __cdecl _fseek_nolock(FILE *_File,long _Offset,int _Origin); - _CRTIMP long __cdecl _ftell_nolock(FILE *_File); - _CRTIMP int __cdecl _fseeki64_nolock(FILE *_File,__int64 _Offset,int _Origin); - _CRTIMP __int64 __cdecl _ftelli64_nolock(FILE *_File); - _CRTIMP size_t __cdecl _fwrite_nolock(const void *_DstBuf,size_t _Size,size_t _Count,FILE *_File); - _CRTIMP int __cdecl _ungetc_nolock(int _Ch,FILE *_File); - -#if !defined(NO_OLDNAMES) || !defined(_POSIX) -#define P_tmpdir _P_tmpdir -#define SYS_OPEN _SYS_OPEN - - char *__cdecl tempnam(const char *_Directory,const char *_FilePrefix); - int __cdecl fcloseall(void); - FILE *__cdecl fdopen(int _FileHandle,const char *_Format); - int __cdecl fgetchar(void); - int __cdecl fileno(FILE *_File); - int __cdecl flushall(void); - int __cdecl fputchar(int _Ch); - int __cdecl getw(FILE *_File); - int __cdecl putw(int _Ch,FILE *_File); - int __cdecl rmtmp(void); -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDIO +#define _INC_STDIO + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#define BUFSIZ 512 +#define _NFILE _NSTREAM_ +#define _NSTREAM_ 512 +#define _IOB_ENTRIES 20 +#define EOF (-1) + +#ifndef _FILE_DEFINED + struct _iobuf { + char *_ptr; + int _cnt; + char *_base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char *_tmpfname; + }; + typedef struct _iobuf FILE; +#define _FILE_DEFINED +#endif + +#ifdef _POSIX_ +#define _P_tmpdir "/" +#define _wP_tmpdir L"/" +#else +#define _P_tmpdir "\\" +#define _wP_tmpdir L"\\" +#endif + +#define L_tmpnam (sizeof(_P_tmpdir) + 12) + +#ifdef _POSIX_ +#define L_ctermid 9 +#define L_cuserid 32 +#endif + +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_SET 0 + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#define FILENAME_MAX 260 +#define FOPEN_MAX 20 +#define _SYS_OPEN 20 +#define TMP_MAX 32767 + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif + +#ifndef _STDIO_DEFINED +#ifdef _WIN64 + _CRTIMP FILE *__cdecl __iob_func(void); +#else +#ifdef _MSVCRT_ +extern FILE _iob[]; /* A pointer to an array of FILE */ +#define __iob_func() (_iob) +#else +extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ +#define __iob_func() (*_imp___iob) +#define _iob __iob_func() +#endif +#endif +#endif + +#ifndef _FPOS_T_DEFINED +#define _FPOS_T_DEFINED +#undef _FPOSOFF + +#if (!defined(NO_OLDNAMES) || defined(__GNUC__)) && _INTEGRAL_MAX_BITS >= 64 + typedef __int64 fpos_t; +#define _FPOSOFF(fp) ((long)(fp)) +#else + typedef long long fpos_t; +#define _FPOSOFF(fp) ((long)(fp)) +#endif + +#endif + +#ifndef _STDSTREAM_DEFINED +#define _STDSTREAM_DEFINED + +#define stdin (&__iob_func()[0]) +#define stdout (&__iob_func()[1]) +#define stderr (&__iob_func()[2]) +#endif + +#define _IOREAD 0x0001 +#define _IOWRT 0x0002 + +#define _IOFBF 0x0000 +#define _IOLBF 0x0040 +#define _IONBF 0x0004 + +#define _IOMYBUF 0x0008 +#define _IOEOF 0x0010 +#define _IOERR 0x0020 +#define _IOSTRG 0x0040 +#define _IORW 0x0080 +#ifdef _POSIX_ +#define _IOAPPEND 0x0200 +#endif + +#define _TWO_DIGIT_EXPONENT 0x1 + +#ifndef _STDIO_DEFINED + + _CRTIMP int __cdecl _filbuf(FILE *_File); + _CRTIMP int __cdecl _flsbuf(int _Ch,FILE *_File); +#ifdef _POSIX_ + _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode); +#else + _CRTIMP FILE *__cdecl _fsopen(const char *_Filename,const char *_Mode,int _ShFlag); +#endif + void __cdecl clearerr(FILE *_File); + int __cdecl fclose(FILE *_File); + _CRTIMP int __cdecl _fcloseall(void); +#ifdef _POSIX_ + FILE *__cdecl fdopen(int _FileHandle,const char *_Mode); +#else + _CRTIMP FILE *__cdecl _fdopen(int _FileHandle,const char *_Mode); +#endif + int __cdecl feof(FILE *_File); + int __cdecl ferror(FILE *_File); + int __cdecl fflush(FILE *_File); + int __cdecl fgetc(FILE *_File); + _CRTIMP int __cdecl _fgetchar(void); + int __cdecl fgetpos(FILE *_File ,fpos_t *_Pos); + char *__cdecl fgets(char *_Buf,int _MaxCount,FILE *_File); +#ifdef _POSIX_ + int __cdecl fileno(FILE *_File); +#else + _CRTIMP int __cdecl _fileno(FILE *_File); +#endif + _CRTIMP char *__cdecl _tempnam(const char *_DirName,const char *_FilePrefix); + _CRTIMP int __cdecl _flushall(void); + FILE *__cdecl fopen(const char *_Filename,const char *_Mode); + FILE *fopen64(const char *filename,const char *mode); + int __cdecl fprintf(FILE *_File,const char *_Format,...); + int __cdecl fputc(int _Ch,FILE *_File); + _CRTIMP int __cdecl _fputchar(int _Ch); + int __cdecl fputs(const char *_Str,FILE *_File); + size_t __cdecl fread(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); + FILE *__cdecl freopen(const char *_Filename,const char *_Mode,FILE *_File); + int __cdecl fscanf(FILE *_File,const char *_Format,...); + int __cdecl fsetpos(FILE *_File,const fpos_t *_Pos); + int __cdecl fseek(FILE *_File,long _Offset,int _Origin); + int fseeko64(FILE* stream, _off64_t offset, int whence); + long __cdecl ftell(FILE *_File); + _off64_t ftello64(FILE * stream); + int __cdecl _fseeki64(FILE *_File,__int64 _Offset,int _Origin); + __int64 __cdecl _ftelli64(FILE *_File); + size_t __cdecl fwrite(const void *_Str,size_t _Size,size_t _Count,FILE *_File); + int __cdecl getc(FILE *_File); + int __cdecl getchar(void); + _CRTIMP int __cdecl _getmaxstdio(void); + char *__cdecl gets(char *_Buffer); + int __cdecl _getw(FILE *_File); +#ifndef _CRT_PERROR_DEFINED +#define _CRT_PERROR_DEFINED + void __cdecl perror(const char *_ErrMsg); +#endif + _CRTIMP int __cdecl _pclose(FILE *_File); + _CRTIMP FILE *__cdecl _popen(const char *_Command,const char *_Mode); +#if !defined(NO_OLDNAMES) && !defined(popen) +#define popen _popen +#define pclose _pclose +#endif + int __cdecl printf(const char *_Format,...); + int __cdecl putc(int _Ch,FILE *_File); + int __cdecl putchar(int _Ch); + int __cdecl puts(const char *_Str); + _CRTIMP int __cdecl _putw(int _Word,FILE *_File); +#ifndef _CRT_DIRECTORY_DEFINED +#define _CRT_DIRECTORY_DEFINED + int __cdecl remove(const char *_Filename); + int __cdecl rename(const char *_OldFilename,const char *_NewFilename); + _CRTIMP int __cdecl _unlink(const char *_Filename); +#ifndef NO_OLDNAMES + int __cdecl unlink(const char *_Filename); +#endif +#endif + void __cdecl rewind(FILE *_File); + _CRTIMP int __cdecl _rmtmp(void); + int __cdecl scanf(const char *_Format,...); + void __cdecl setbuf(FILE *_File,char *_Buffer); + _CRTIMP int __cdecl _setmaxstdio(int _Max); + _CRTIMP unsigned int __cdecl _set_output_format(unsigned int _Format); + _CRTIMP unsigned int __cdecl _get_output_format(void); + int __cdecl setvbuf(FILE *_File,char *_Buf,int _Mode,size_t _Size); + _CRTIMP int __cdecl _scprintf(const char *_Format,...); + int __cdecl sscanf(const char *_Src,const char *_Format,...); + _CRTIMP int __cdecl _snscanf(const char *_Src,size_t _MaxCount,const char *_Format,...); + FILE *__cdecl tmpfile(void); + char *__cdecl tmpnam(char *_Buffer); + int __cdecl ungetc(int _Ch,FILE *_File); + int __cdecl vfprintf(FILE *_File,const char *_Format,va_list _ArgList); + int __cdecl vprintf(const char *_Format,va_list _ArgList); + /* Make sure macros are not defined. */ +#pragma push_macro("vsnprintf") +#pragma push_macro("snprintf") +# undef vsnprintf +# undef snprintf + extern + __attribute__((format(gnu_printf, 3, 0))) __attribute__((nonnull (3))) + int __mingw_vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); + extern + __attribute__((format(gnu_printf, 3, 4))) __attribute__((nonnull (3))) + int __mingw_snprintf(char* s, size_t n, const char* format, ...); + int __cdecl vsnprintf(char *_DstBuf,size_t _MaxCount,const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snprintf(char *_Dest,size_t _Count,const char *_Format,...); + _CRTIMP int __cdecl _vsnprintf(char *_Dest,size_t _Count,const char *_Format,va_list _Args); + int __cdecl sprintf(char *_Dest,const char *_Format,...); + int __cdecl vsprintf(char *_Dest,const char *_Format,va_list _Args); +#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ + int __cdecl snprintf(char* s, size_t n, const char* format, ...); + __CRT_INLINE int __cdecl vsnprintf (char* s, size_t n, const char* format,va_list arg) { + return _vsnprintf ( s, n, format, arg); + } + int __cdecl vscanf(const char * Format, va_list argp); + int __cdecl vfscanf (FILE * fp, const char * Format,va_list argp); + int __cdecl vsscanf (const char * _Str,const char * Format,va_list argp); +#endif +/* Restore may prior defined macros snprintf/vsnprintf. */ +#pragma pop_macro("snprintf") +#pragma pop_macro("vsnprintf") +/* Check if vsnprintf and snprintf are defaulting to gnu-style. */ +# if defined(USE_MINGW_GNU_SNPRINTF) && USE_MINGW_GNU_SNPRINTF +# ifndef vsnprint +# define vsnprintf __mingw_vsnprintf +# endif +# ifndef snprintf +# define snprintf __mingw_snprintf +# endif +# endif + _CRTIMP int __cdecl _vscprintf(const char *_Format,va_list _ArgList); + _CRTIMP int __cdecl _set_printf_count_output(int _Value); + _CRTIMP int __cdecl _get_printf_count_output(void); + +#ifndef _WSTDIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifdef _POSIX_ + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); +#else + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); +#endif + wint_t __cdecl fgetwc(FILE *_File); + _CRTIMP wint_t __cdecl _fgetwchar(void); + wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); + wint_t __cdecl getwc(FILE *_File); + wint_t __cdecl getwchar(void); + wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); + wint_t __cdecl putwchar(wchar_t _Ch); + wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); + wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); + int __cdecl fputws(const wchar_t *_Str,FILE *_File); + _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); + _CRTIMP int __cdecl _putws(const wchar_t *_Str); + int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); + int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); + int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); + _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); + _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); +#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ + int __cdecl snwprintf (wchar_t* s, size_t n, const wchar_t* format, ...); + __CRT_INLINE int __cdecl vsnwprintf (wchar_t* s, size_t n, const wchar_t* format, va_list arg) { return _vsnwprintf(s,n,format,arg); } + int __cdecl vwscanf (const wchar_t *, va_list); + int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); + int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); +#endif + _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); + +#ifndef RC_INVOKED +#include +#endif + +#ifdef _CRT_NON_CONFORMING_SWPRINTFS +#ifndef __cplusplus +#define swprintf _swprintf +#define vswprintf _vswprintf +#define _swprintf_l __swprintf_l +#define _vswprintf_l __vswprintf_l +#endif +#endif + + _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); + _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); + int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); + int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + int __cdecl wscanf(const wchar_t *_Format,...); + _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); +#if !defined(NO_OLDNAMES) && !defined(wpopen) +#define wpopen _wpopen +#endif + _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); + _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); + _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); + +#undef _CRT_GETPUTWCHAR_NOINLINE + +#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) +#define getwchar() fgetwc(stdin) +#define putwchar(_c) fputwc((_c),stdout) +#else + __CRT_INLINE wint_t __cdecl getwchar() { return (fgetwc(stdin)); } + __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) { return (fputwc(_C,stdout)); } +#endif + +#define getwc(_stm) fgetwc(_stm) +#define putwc(_c,_stm) fputwc(_c,_stm) +#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) +#define _getwc_nolock(_stm) _fgetwc_nolock(_stm) + +#define _WSTDIO_DEFINED +#endif + +#define _STDIO_DEFINED +#endif + +#define _fgetc_nolock(_stream) (--(_stream)->_cnt >= 0 ? 0xff & *(_stream)->_ptr++ : _filbuf(_stream)) +#define _fputc_nolock(_c,_stream) (--(_stream)->_cnt >= 0 ? 0xff & (*(_stream)->_ptr++ = (char)(_c)) : _flsbuf((_c),(_stream))) +#define _getc_nolock(_stream) _fgetc_nolock(_stream) +#define _putc_nolock(_c,_stream) _fputc_nolock(_c,_stream) +#define _getchar_nolock() _getc_nolock(stdin) +#define _putchar_nolock(_c) _putc_nolock((_c),stdout) +#define _getwchar_nolock() _getwc_nolock(stdin) +#define _putwchar_nolock(_c) _putwc_nolock((_c),stdout) + + _CRTIMP void __cdecl _lock_file(FILE *_File); + _CRTIMP void __cdecl _unlock_file(FILE *_File); + _CRTIMP int __cdecl _fclose_nolock(FILE *_File); + _CRTIMP int __cdecl _fflush_nolock(FILE *_File); + _CRTIMP size_t __cdecl _fread_nolock(void *_DstBuf,size_t _ElementSize,size_t _Count,FILE *_File); + _CRTIMP int __cdecl _fseek_nolock(FILE *_File,long _Offset,int _Origin); + _CRTIMP long __cdecl _ftell_nolock(FILE *_File); + _CRTIMP int __cdecl _fseeki64_nolock(FILE *_File,__int64 _Offset,int _Origin); + _CRTIMP __int64 __cdecl _ftelli64_nolock(FILE *_File); + _CRTIMP size_t __cdecl _fwrite_nolock(const void *_DstBuf,size_t _Size,size_t _Count,FILE *_File); + _CRTIMP int __cdecl _ungetc_nolock(int _Ch,FILE *_File); + +#if !defined(NO_OLDNAMES) || !defined(_POSIX) +#define P_tmpdir _P_tmpdir +#define SYS_OPEN _SYS_OPEN + + char *__cdecl tempnam(const char *_Directory,const char *_FilePrefix); + int __cdecl fcloseall(void); + FILE *__cdecl fdopen(int _FileHandle,const char *_Format); + int __cdecl fgetchar(void); + int __cdecl fileno(FILE *_File); + int __cdecl flushall(void); + int __cdecl fputchar(int _Ch); + int __cdecl getw(FILE *_File); + int __cdecl putw(int _Ch,FILE *_File); + int __cdecl rmtmp(void); +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include + +#endif diff --git a/tcc/include/stdlib.h b/tcc/include/stdlib.h index d5560c54..033c0fdf 100644 --- a/tcc/include/stdlib.h +++ b/tcc/include/stdlib.h @@ -1,580 +1,580 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STDLIB -#define _INC_STDLIB - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define EXIT_SUCCESS 0 -#define EXIT_FAILURE 1 - -#ifndef _ONEXIT_T_DEFINED -#define _ONEXIT_T_DEFINED - - typedef int (__cdecl *_onexit_t)(void); - -#ifndef NO_OLDNAMES -#define onexit_t _onexit_t -#endif -#endif - -#ifndef _DIV_T_DEFINED -#define _DIV_T_DEFINED - - typedef struct _div_t { - int quot; - int rem; - } div_t; - - typedef struct _ldiv_t { - long quot; - long rem; - } ldiv_t; -#endif - -#ifndef _CRT_DOUBLE_DEC -#define _CRT_DOUBLE_DEC - -#pragma pack(4) - typedef struct { - unsigned char ld[10]; - } _LDOUBLE; -#pragma pack() - -#define _PTR_LD(x) ((unsigned char *)(&(x)->ld)) - - typedef struct { - double x; - } _CRT_DOUBLE; - - typedef struct { - float f; - } _CRT_FLOAT; - -#pragma push_macro("long") -#undef long - - typedef struct { - long double x; - } _LONGDOUBLE; - -#pragma pop_macro("long") - -#pragma pack(4) - typedef struct { - unsigned char ld12[12]; - } _LDBL12; -#pragma pack() -#endif - -#define RAND_MAX 0x7fff - -#ifndef MB_CUR_MAX -#define MB_CUR_MAX ___mb_cur_max_func() -#ifndef __mb_cur_max -#ifdef _MSVCRT_ - extern int __mb_cur_max; -#else -#define __mb_cur_max (*_imp____mb_cur_max) - extern int *_imp____mb_cur_max; -#endif -#endif -#ifdef _MSVCRT_ - extern int __mbcur_max; -#define ___mb_cur_max_func() (__mb_cur_max) -#else - extern int* _imp____mbcur_max; -#define ___mb_cur_max_func() (*_imp____mb_cur_max) -#endif -#endif - -#define __max(a,b) (((a) > (b)) ? (a) : (b)) -#define __min(a,b) (((a) < (b)) ? (a) : (b)) - -#define _MAX_PATH 260 -#define _MAX_DRIVE 3 -#define _MAX_DIR 256 -#define _MAX_FNAME 256 -#define _MAX_EXT 256 - -#define _OUT_TO_DEFAULT 0 -#define _OUT_TO_STDERR 1 -#define _OUT_TO_MSGBOX 2 -#define _REPORT_ERRMODE 3 - -#define _WRITE_ABORT_MSG 0x1 -#define _CALL_REPORTFAULT 0x2 - -#define _MAX_ENV 32767 - - typedef void (__cdecl *_purecall_handler)(void); - - _CRTIMP _purecall_handler __cdecl _set_purecall_handler(_purecall_handler _Handler); - _CRTIMP _purecall_handler __cdecl _get_purecall_handler(void); - - typedef void (__cdecl *_invalid_parameter_handler)(const wchar_t *,const wchar_t *,const wchar_t *,unsigned int,uintptr_t); - _invalid_parameter_handler __cdecl _set_invalid_parameter_handler(_invalid_parameter_handler _Handler); - _invalid_parameter_handler __cdecl _get_invalid_parameter_handler(void); - -#ifndef _CRT_ERRNO_DEFINED -#define _CRT_ERRNO_DEFINED - _CRTIMP int *__cdecl _errno(void); -#define errno (*_errno()) - errno_t __cdecl _set_errno(int _Value); - errno_t __cdecl _get_errno(int *_Value); -#endif - _CRTIMP unsigned long *__cdecl __doserrno(void); -#define _doserrno (*__doserrno()) - errno_t __cdecl _set_doserrno(unsigned long _Value); - errno_t __cdecl _get_doserrno(unsigned long *_Value); -#ifdef _MSVCRT_ - extern char *_sys_errlist[]; - extern int _sys_nerr; -#else - _CRTIMP char *_sys_errlist[1]; - _CRTIMP int _sys_nerr; -#endif -#if (defined(_X86_) && !defined(__x86_64)) - _CRTIMP int *__cdecl __p___argc(void); - _CRTIMP char ***__cdecl __p___argv(void); - _CRTIMP wchar_t ***__cdecl __p___wargv(void); - _CRTIMP char ***__cdecl __p__environ(void); - _CRTIMP wchar_t ***__cdecl __p__wenviron(void); - _CRTIMP char **__cdecl __p__pgmptr(void); - _CRTIMP wchar_t **__cdecl __p__wpgmptr(void); -#endif -#ifndef __argc -#ifdef _MSVCRT_ - extern int __argc; -#else -#define __argc (*_imp____argc) - extern int *_imp____argc; -#endif -#endif -#ifndef __argv -#ifdef _MSVCRT_ - extern char **__argv; -#else -#define __argv (*_imp____argv) - extern char ***_imp____argv; -#endif -#endif -#ifndef __wargv -#ifdef _MSVCRT_ - extern wchar_t **__wargv; -#else -#define __wargv (*_imp____wargv) - extern wchar_t ***_imp____wargv; -#endif -#endif - -#ifdef _POSIX_ - extern char **environ; -#else -#ifndef _environ -#ifdef _MSVCRT_ - extern char **_environ; -#else -#define _environ (*_imp___environ) - extern char ***_imp___environ; -#endif -#endif - -#ifndef _wenviron -#ifdef _MSVCRT_ - extern wchar_t **_wenviron; -#else -#define _wenviron (*_imp___wenviron) - extern wchar_t ***_imp___wenviron; -#endif -#endif -#endif -#ifndef _pgmptr -#ifdef _MSVCRT_ - extern char *_pgmptr; -#else -#define _pgmptr (*_imp___pgmptr) - extern char **_imp___pgmptr; -#endif -#endif - -#ifndef _wpgmptr -#ifdef _MSVCRT_ - extern wchar_t *_wpgmptr; -#else -#define _wpgmptr (*_imp___wpgmptr) - extern wchar_t **_imp___wpgmptr; -#endif -#endif - errno_t __cdecl _get_pgmptr(char **_Value); - errno_t __cdecl _get_wpgmptr(wchar_t **_Value); -#ifndef _fmode -#ifdef _MSVCRT_ - extern int _fmode; -#else -#define _fmode (*_imp___fmode) - extern int *_imp___fmode; -#endif -#endif - _CRTIMP errno_t __cdecl _set_fmode(int _Mode); - _CRTIMP errno_t __cdecl _get_fmode(int *_PMode); - -#ifndef _osplatform -#ifdef _MSVCRT_ - extern unsigned int _osplatform; -#else -#define _osplatform (*_imp___osplatform) - extern unsigned int *_imp___osplatform; -#endif -#endif - -#ifndef _osver -#ifdef _MSVCRT_ - extern unsigned int _osver; -#else -#define _osver (*_imp___osver) - extern unsigned int *_imp___osver; -#endif -#endif - -#ifndef _winver -#ifdef _MSVCRT_ - extern unsigned int _winver; -#else -#define _winver (*_imp___winver) - extern unsigned int *_imp___winver; -#endif -#endif - -#ifndef _winmajor -#ifdef _MSVCRT_ - extern unsigned int _winmajor; -#else -#define _winmajor (*_imp___winmajor) - extern unsigned int *_imp___winmajor; -#endif -#endif - -#ifndef _winminor -#ifdef _MSVCRT_ - extern unsigned int _winminor; -#else -#define _winminor (*_imp___winminor) - extern unsigned int *_imp___winminor; -#endif -#endif - - errno_t __cdecl _get_osplatform(unsigned int *_Value); - errno_t __cdecl _get_osver(unsigned int *_Value); - errno_t __cdecl _get_winver(unsigned int *_Value); - errno_t __cdecl _get_winmajor(unsigned int *_Value); - errno_t __cdecl _get_winminor(unsigned int *_Value); -#ifndef _countof -#ifndef __cplusplus -#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) -#else - extern "C++" { - template char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray]; -#define _countof(_Array) sizeof(*__countof_helper(_Array)) - } -#endif -#endif - -#ifndef _CRT_TERMINATE_DEFINED -#define _CRT_TERMINATE_DEFINED - void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; - _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; -#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ - /* C99 function name */ - void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; - __CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) - { _exit(status); } -#endif - -#pragma push_macro("abort") -#undef abort - void __cdecl __declspec(noreturn) abort(void); -#pragma pop_macro("abort") - -#endif - - _CRTIMP unsigned int __cdecl _set_abort_behavior(unsigned int _Flags,unsigned int _Mask); - -#ifndef _CRT_ABS_DEFINED -#define _CRT_ABS_DEFINED - int __cdecl abs(int _X); - long __cdecl labs(long _X); -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - __int64 __cdecl _abs64(__int64); -#endif - int __cdecl atexit(void (__cdecl *)(void)); -#ifndef _CRT_ATOF_DEFINED -#define _CRT_ATOF_DEFINED - double __cdecl atof(const char *_String); - double __cdecl _atof_l(const char *_String,_locale_t _Locale); -#endif - int __cdecl atoi(const char *_Str); - _CRTIMP int __cdecl _atoi_l(const char *_Str,_locale_t _Locale); - long __cdecl atol(const char *_Str); - _CRTIMP long __cdecl _atol_l(const char *_Str,_locale_t _Locale); -#ifndef _CRT_ALGO_DEFINED -#define _CRT_ALGO_DEFINED - void *__cdecl bsearch(const void *_Key,const void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); - void __cdecl qsort(void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); -#endif - unsigned short __cdecl _byteswap_ushort(unsigned short _Short); - /*unsigned long __cdecl _byteswap_ulong (unsigned long _Long); */ -#if _INTEGRAL_MAX_BITS >= 64 - unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64 _Int64); -#endif - div_t __cdecl div(int _Numerator,int _Denominator); - char *__cdecl getenv(const char *_VarName); - _CRTIMP char *__cdecl _itoa(int _Value,char *_Dest,int _Radix); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP char *__cdecl _i64toa(__int64 _Val,char *_DstBuf,int _Radix); - _CRTIMP char *__cdecl _ui64toa(unsigned __int64 _Val,char *_DstBuf,int _Radix); - _CRTIMP __int64 __cdecl _atoi64(const char *_String); - _CRTIMP __int64 __cdecl _atoi64_l(const char *_String,_locale_t _Locale); - _CRTIMP __int64 __cdecl _strtoi64(const char *_String,char **_EndPtr,int _Radix); - _CRTIMP __int64 __cdecl _strtoi64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP unsigned __int64 __cdecl _strtoui64(const char *_String,char **_EndPtr,int _Radix); - _CRTIMP unsigned __int64 __cdecl _strtoui64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); -#endif - ldiv_t __cdecl ldiv(long _Numerator,long _Denominator); - _CRTIMP char *__cdecl _ltoa(long _Value,char *_Dest,int _Radix); - int __cdecl mblen(const char *_Ch,size_t _MaxCount); - _CRTIMP int __cdecl _mblen_l(const char *_Ch,size_t _MaxCount,_locale_t _Locale); - _CRTIMP size_t __cdecl _mbstrlen(const char *_Str); - _CRTIMP size_t __cdecl _mbstrlen_l(const char *_Str,_locale_t _Locale); - _CRTIMP size_t __cdecl _mbstrnlen(const char *_Str,size_t _MaxCount); - _CRTIMP size_t __cdecl _mbstrnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); - int __cdecl mbtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes); - _CRTIMP int __cdecl _mbtowc_l(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes,_locale_t _Locale); - size_t __cdecl mbstowcs(wchar_t *_Dest,const char *_Source,size_t _MaxCount); - _CRTIMP size_t __cdecl _mbstowcs_l(wchar_t *_Dest,const char *_Source,size_t _MaxCount,_locale_t _Locale); - int __cdecl rand(void); - _CRTIMP int __cdecl _set_error_mode(int _Mode); - void __cdecl srand(unsigned int _Seed); - double __cdecl strtod(const char *_Str,char **_EndPtr); - float __cdecl strtof(const char *nptr, char **endptr); -#if !defined __NO_ISOCEXT /* in libmingwex.a */ - float __cdecl strtof (const char * __restrict__, char ** __restrict__); - long double __cdecl strtold(const char * __restrict__, char ** __restrict__); -#endif /* __NO_ISOCEXT */ - _CRTIMP double __cdecl _strtod_l(const char *_Str,char **_EndPtr,_locale_t _Locale); - long __cdecl strtol(const char *_Str,char **_EndPtr,int _Radix); - _CRTIMP long __cdecl _strtol_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); - unsigned long __cdecl strtoul(const char *_Str,char **_EndPtr,int _Radix); - _CRTIMP unsigned long __cdecl _strtoul_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); -#ifndef _CRT_SYSTEM_DEFINED -#define _CRT_SYSTEM_DEFINED - int __cdecl system(const char *_Command); -#endif - _CRTIMP char *__cdecl _ultoa(unsigned long _Value,char *_Dest,int _Radix); - int __cdecl wctomb(char *_MbCh,wchar_t _WCh); - _CRTIMP int __cdecl _wctomb_l(char *_MbCh,wchar_t _WCh,_locale_t _Locale); - size_t __cdecl wcstombs(char *_Dest,const wchar_t *_Source,size_t _MaxCount); - _CRTIMP size_t __cdecl _wcstombs_l(char *_Dest,const wchar_t *_Source,size_t _MaxCount,_locale_t _Locale); - -#ifndef _CRT_ALLOCATION_DEFINED -#define _CRT_ALLOCATION_DEFINED - void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); - void __cdecl free(void *_Memory); - void *__cdecl malloc(size_t _Size); - void *__cdecl realloc(void *_Memory,size_t _NewSize); - _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); - //_CRTIMP void __cdecl _aligned_free(void *_Memory); - //_CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); - _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); - _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); -#endif - -#ifndef _WSTDLIB_DEFINED -#define _WSTDLIB_DEFINED - - _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); - double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); - float __cdecl wcstof(const wchar_t *nptr, wchar_t **endptr); -#if !defined __NO_ISOCEXT /* in libmingwex.a */ - float __cdecl wcstof( const wchar_t * __restrict__, wchar_t ** __restrict__); - long double __cdecl wcstold(const wchar_t * __restrict__, wchar_t ** __restrict__); -#endif /* __NO_ISOCEXT */ - _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); - long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif - _CRTIMP double __cdecl _wtof(const wchar_t *_Str); - _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); - _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP long __cdecl _wtol(const wchar_t *_Str); - _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); - _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str ,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); -#endif -#endif - -#ifndef _POSIX_ -#define _CVTBUFSIZE (309+40) - _CRTIMP char *__cdecl _fullpath(char *_FullPath,const char *_Path,size_t _SizeInBytes); - _CRTIMP char *__cdecl _ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); - _CRTIMP char *__cdecl _fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); - _CRTIMP char *__cdecl _gcvt(double _Val,int _NumOfDigits,char *_DstBuf); - _CRTIMP int __cdecl _atodbl(_CRT_DOUBLE *_Result,char *_Str); - _CRTIMP int __cdecl _atoldbl(_LDOUBLE *_Result,char *_Str); - _CRTIMP int __cdecl _atoflt(_CRT_FLOAT *_Result,char *_Str); - _CRTIMP int __cdecl _atodbl_l(_CRT_DOUBLE *_Result,char *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _atoldbl_l(_LDOUBLE *_Result,char *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _atoflt_l(_CRT_FLOAT *_Result,char *_Str,_locale_t _Locale); - unsigned long __cdecl _lrotl(unsigned long _Val,int _Shift); - unsigned long __cdecl _lrotr(unsigned long _Val,int _Shift); - _CRTIMP void __cdecl _makepath(char *_Path,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); - _onexit_t __cdecl _onexit(_onexit_t _Func); - -#ifndef _CRT_PERROR_DEFINED -#define _CRT_PERROR_DEFINED - void __cdecl perror(const char *_ErrMsg); -#endif - _CRTIMP int __cdecl _putenv(const char *_EnvString); - unsigned int __cdecl _rotl(unsigned int _Val,int _Shift); -#if _INTEGRAL_MAX_BITS >= 64 - unsigned __int64 __cdecl _rotl64(unsigned __int64 _Val,int _Shift); -#endif - unsigned int __cdecl _rotr(unsigned int _Val,int _Shift); -#if _INTEGRAL_MAX_BITS >= 64 - unsigned __int64 __cdecl _rotr64(unsigned __int64 _Val,int _Shift); -#endif - _CRTIMP void __cdecl _searchenv(const char *_Filename,const char *_EnvVar,char *_ResultPath); - _CRTIMP void __cdecl _splitpath(const char *_FullPath,char *_Drive,char *_Dir,char *_Filename,char *_Ext); - _CRTIMP void __cdecl _swab(char *_Buf1,char *_Buf2,int _SizeInBytes); - -#ifndef _WSTDLIBP_DEFINED -#define _WSTDLIBP_DEFINED - _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); - _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); - _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); - _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); -#endif - - _CRTIMP void __cdecl _beep(unsigned _Frequency,unsigned _Duration) __MINGW_ATTRIB_DEPRECATED; - /* Not to be confused with _set_error_mode (int). */ - _CRTIMP void __cdecl _seterrormode(int _Mode) __MINGW_ATTRIB_DEPRECATED; - _CRTIMP void __cdecl _sleep(unsigned long _Duration) __MINGW_ATTRIB_DEPRECATED; -#endif - -#ifndef NO_OLDNAMES -#ifndef _POSIX_ -#if 0 -#ifndef __cplusplus -#ifndef NOMINMAX -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#endif -#endif -#endif - -#define sys_errlist _sys_errlist -#define sys_nerr _sys_nerr -#define environ _environ - char *__cdecl ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); - char *__cdecl fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); - char *__cdecl gcvt(double _Val,int _NumOfDigits,char *_DstBuf); - char *__cdecl itoa(int _Val,char *_DstBuf,int _Radix); - char *__cdecl ltoa(long _Val,char *_DstBuf,int _Radix); - int __cdecl putenv(const char *_EnvString); - void __cdecl swab(char *_Buf1,char *_Buf2,int _SizeInBytes); - char *__cdecl ultoa(unsigned long _Val,char *_Dstbuf,int _Radix); - onexit_t __cdecl onexit(onexit_t _Func); -#endif -#endif - -#if !defined __NO_ISOCEXT /* externs in static libmingwex.a */ - - typedef struct { long long quot, rem; } lldiv_t; - - lldiv_t __cdecl lldiv(long long, long long); - - __CRT_INLINE long long __cdecl llabs(long long _j) { return (_j >= 0 ? _j : -_j); } - - long long __cdecl strtoll(const char* __restrict__, char** __restrict, int); - unsigned long long __cdecl strtoull(const char* __restrict__, char** __restrict__, int); - - /* these are stubs for MS _i64 versions */ - long long __cdecl atoll (const char *); - -#ifndef __STRICT_ANSI__ - long long __cdecl wtoll (const wchar_t *); - char *__cdecl lltoa (long long, char *, int); - char *__cdecl ulltoa (unsigned long long , char *, int); - wchar_t *__cdecl lltow (long long, wchar_t *, int); - wchar_t *__cdecl ulltow (unsigned long long, wchar_t *, int); - - /* __CRT_INLINE using non-ansi functions */ - __CRT_INLINE long long __cdecl atoll (const char * _c) { return _atoi64 (_c); } - __CRT_INLINE char *__cdecl lltoa (long long _n, char * _c, int _i) { return _i64toa (_n, _c, _i); } - __CRT_INLINE char *__cdecl ulltoa (unsigned long long _n, char * _c, int _i) { return _ui64toa (_n, _c, _i); } - __CRT_INLINE long long __cdecl wtoll (const wchar_t * _w) { return _wtoi64 (_w); } - __CRT_INLINE wchar_t *__cdecl lltow (long long _n, wchar_t * _w, int _i) { return _i64tow (_n, _w, _i); } - __CRT_INLINE wchar_t *__cdecl ulltow (unsigned long long _n, wchar_t * _w, int _i) { return _ui64tow (_n, _w, _i); } -#endif /* (__STRICT_ANSI__) */ - -#endif /* !__NO_ISOCEXT */ - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include -#include - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STDLIB +#define _INC_STDLIB + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#ifndef _ONEXIT_T_DEFINED +#define _ONEXIT_T_DEFINED + + typedef int (__cdecl *_onexit_t)(void); + +#ifndef NO_OLDNAMES +#define onexit_t _onexit_t +#endif +#endif + +#ifndef _DIV_T_DEFINED +#define _DIV_T_DEFINED + + typedef struct _div_t { + int quot; + int rem; + } div_t; + + typedef struct _ldiv_t { + long quot; + long rem; + } ldiv_t; +#endif + +#ifndef _CRT_DOUBLE_DEC +#define _CRT_DOUBLE_DEC + +#pragma pack(4) + typedef struct { + unsigned char ld[10]; + } _LDOUBLE; +#pragma pack() + +#define _PTR_LD(x) ((unsigned char *)(&(x)->ld)) + + typedef struct { + double x; + } _CRT_DOUBLE; + + typedef struct { + float f; + } _CRT_FLOAT; + +#pragma push_macro("long") +#undef long + + typedef struct { + long double x; + } _LONGDOUBLE; + +#pragma pop_macro("long") + +#pragma pack(4) + typedef struct { + unsigned char ld12[12]; + } _LDBL12; +#pragma pack() +#endif + +#define RAND_MAX 0x7fff + +#ifndef MB_CUR_MAX +#define MB_CUR_MAX ___mb_cur_max_func() +#ifndef __mb_cur_max +#ifdef _MSVCRT_ + extern int __mb_cur_max; +#else +#define __mb_cur_max (*_imp____mb_cur_max) + extern int *_imp____mb_cur_max; +#endif +#endif +#ifdef _MSVCRT_ + extern int __mbcur_max; +#define ___mb_cur_max_func() (__mb_cur_max) +#else + extern int* _imp____mbcur_max; +#define ___mb_cur_max_func() (*_imp____mb_cur_max) +#endif +#endif + +#define __max(a,b) (((a) > (b)) ? (a) : (b)) +#define __min(a,b) (((a) < (b)) ? (a) : (b)) + +#define _MAX_PATH 260 +#define _MAX_DRIVE 3 +#define _MAX_DIR 256 +#define _MAX_FNAME 256 +#define _MAX_EXT 256 + +#define _OUT_TO_DEFAULT 0 +#define _OUT_TO_STDERR 1 +#define _OUT_TO_MSGBOX 2 +#define _REPORT_ERRMODE 3 + +#define _WRITE_ABORT_MSG 0x1 +#define _CALL_REPORTFAULT 0x2 + +#define _MAX_ENV 32767 + + typedef void (__cdecl *_purecall_handler)(void); + + _CRTIMP _purecall_handler __cdecl _set_purecall_handler(_purecall_handler _Handler); + _CRTIMP _purecall_handler __cdecl _get_purecall_handler(void); + + typedef void (__cdecl *_invalid_parameter_handler)(const wchar_t *,const wchar_t *,const wchar_t *,unsigned int,uintptr_t); + _invalid_parameter_handler __cdecl _set_invalid_parameter_handler(_invalid_parameter_handler _Handler); + _invalid_parameter_handler __cdecl _get_invalid_parameter_handler(void); + +#ifndef _CRT_ERRNO_DEFINED +#define _CRT_ERRNO_DEFINED + _CRTIMP int *__cdecl _errno(void); +#define errno (*_errno()) + errno_t __cdecl _set_errno(int _Value); + errno_t __cdecl _get_errno(int *_Value); +#endif + _CRTIMP unsigned long *__cdecl __doserrno(void); +#define _doserrno (*__doserrno()) + errno_t __cdecl _set_doserrno(unsigned long _Value); + errno_t __cdecl _get_doserrno(unsigned long *_Value); +#ifdef _MSVCRT_ + extern char *_sys_errlist[]; + extern int _sys_nerr; +#else + _CRTIMP char *_sys_errlist[1]; + _CRTIMP int _sys_nerr; +#endif +#if (defined(_X86_) && !defined(__x86_64)) + _CRTIMP int *__cdecl __p___argc(void); + _CRTIMP char ***__cdecl __p___argv(void); + _CRTIMP wchar_t ***__cdecl __p___wargv(void); + _CRTIMP char ***__cdecl __p__environ(void); + _CRTIMP wchar_t ***__cdecl __p__wenviron(void); + _CRTIMP char **__cdecl __p__pgmptr(void); + _CRTIMP wchar_t **__cdecl __p__wpgmptr(void); +#endif +#ifndef __argc +#ifdef _MSVCRT_ + extern int __argc; +#else +#define __argc (*_imp____argc) + extern int *_imp____argc; +#endif +#endif +#ifndef __argv +#ifdef _MSVCRT_ + extern char **__argv; +#else +#define __argv (*_imp____argv) + extern char ***_imp____argv; +#endif +#endif +#ifndef __wargv +#ifdef _MSVCRT_ + extern wchar_t **__wargv; +#else +#define __wargv (*_imp____wargv) + extern wchar_t ***_imp____wargv; +#endif +#endif + +#ifdef _POSIX_ + extern char **environ; +#else +#ifndef _environ +#ifdef _MSVCRT_ + extern char **_environ; +#else +#define _environ (*_imp___environ) + extern char ***_imp___environ; +#endif +#endif + +#ifndef _wenviron +#ifdef _MSVCRT_ + extern wchar_t **_wenviron; +#else +#define _wenviron (*_imp___wenviron) + extern wchar_t ***_imp___wenviron; +#endif +#endif +#endif +#ifndef _pgmptr +#ifdef _MSVCRT_ + extern char *_pgmptr; +#else +#define _pgmptr (*_imp___pgmptr) + extern char **_imp___pgmptr; +#endif +#endif + +#ifndef _wpgmptr +#ifdef _MSVCRT_ + extern wchar_t *_wpgmptr; +#else +#define _wpgmptr (*_imp___wpgmptr) + extern wchar_t **_imp___wpgmptr; +#endif +#endif + errno_t __cdecl _get_pgmptr(char **_Value); + errno_t __cdecl _get_wpgmptr(wchar_t **_Value); +#ifndef _fmode +#ifdef _MSVCRT_ + extern int _fmode; +#else +#define _fmode (*_imp___fmode) + extern int *_imp___fmode; +#endif +#endif + _CRTIMP errno_t __cdecl _set_fmode(int _Mode); + _CRTIMP errno_t __cdecl _get_fmode(int *_PMode); + +#ifndef _osplatform +#ifdef _MSVCRT_ + extern unsigned int _osplatform; +#else +#define _osplatform (*_imp___osplatform) + extern unsigned int *_imp___osplatform; +#endif +#endif + +#ifndef _osver +#ifdef _MSVCRT_ + extern unsigned int _osver; +#else +#define _osver (*_imp___osver) + extern unsigned int *_imp___osver; +#endif +#endif + +#ifndef _winver +#ifdef _MSVCRT_ + extern unsigned int _winver; +#else +#define _winver (*_imp___winver) + extern unsigned int *_imp___winver; +#endif +#endif + +#ifndef _winmajor +#ifdef _MSVCRT_ + extern unsigned int _winmajor; +#else +#define _winmajor (*_imp___winmajor) + extern unsigned int *_imp___winmajor; +#endif +#endif + +#ifndef _winminor +#ifdef _MSVCRT_ + extern unsigned int _winminor; +#else +#define _winminor (*_imp___winminor) + extern unsigned int *_imp___winminor; +#endif +#endif + + errno_t __cdecl _get_osplatform(unsigned int *_Value); + errno_t __cdecl _get_osver(unsigned int *_Value); + errno_t __cdecl _get_winver(unsigned int *_Value); + errno_t __cdecl _get_winmajor(unsigned int *_Value); + errno_t __cdecl _get_winminor(unsigned int *_Value); +#ifndef _countof +#ifndef __cplusplus +#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) +#else + extern "C++" { + template char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray]; +#define _countof(_Array) sizeof(*__countof_helper(_Array)) + } +#endif +#endif + +#ifndef _CRT_TERMINATE_DEFINED +#define _CRT_TERMINATE_DEFINED + void __cdecl __MINGW_NOTHROW exit(int _Code) __MINGW_ATTRIB_NORETURN; + _CRTIMP void __cdecl __MINGW_NOTHROW _exit(int _Code) __MINGW_ATTRIB_NORETURN; +#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */ + /* C99 function name */ + void __cdecl _Exit(int) __MINGW_ATTRIB_NORETURN; + __CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status) + { _exit(status); } +#endif + +#pragma push_macro("abort") +#undef abort + void __cdecl __declspec(noreturn) abort(void); +#pragma pop_macro("abort") + +#endif + + _CRTIMP unsigned int __cdecl _set_abort_behavior(unsigned int _Flags,unsigned int _Mask); + +#ifndef _CRT_ABS_DEFINED +#define _CRT_ABS_DEFINED + int __cdecl abs(int _X); + long __cdecl labs(long _X); +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + __int64 __cdecl _abs64(__int64); +#endif + int __cdecl atexit(void (__cdecl *)(void)); +#ifndef _CRT_ATOF_DEFINED +#define _CRT_ATOF_DEFINED + double __cdecl atof(const char *_String); + double __cdecl _atof_l(const char *_String,_locale_t _Locale); +#endif + int __cdecl atoi(const char *_Str); + _CRTIMP int __cdecl _atoi_l(const char *_Str,_locale_t _Locale); + long __cdecl atol(const char *_Str); + _CRTIMP long __cdecl _atol_l(const char *_Str,_locale_t _Locale); +#ifndef _CRT_ALGO_DEFINED +#define _CRT_ALGO_DEFINED + void *__cdecl bsearch(const void *_Key,const void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); + void __cdecl qsort(void *_Base,size_t _NumOfElements,size_t _SizeOfElements,int (__cdecl *_PtFuncCompare)(const void *,const void *)); +#endif + unsigned short __cdecl _byteswap_ushort(unsigned short _Short); + /*unsigned long __cdecl _byteswap_ulong (unsigned long _Long); */ +#if _INTEGRAL_MAX_BITS >= 64 + unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64 _Int64); +#endif + div_t __cdecl div(int _Numerator,int _Denominator); + char *__cdecl getenv(const char *_VarName); + _CRTIMP char *__cdecl _itoa(int _Value,char *_Dest,int _Radix); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP char *__cdecl _i64toa(__int64 _Val,char *_DstBuf,int _Radix); + _CRTIMP char *__cdecl _ui64toa(unsigned __int64 _Val,char *_DstBuf,int _Radix); + _CRTIMP __int64 __cdecl _atoi64(const char *_String); + _CRTIMP __int64 __cdecl _atoi64_l(const char *_String,_locale_t _Locale); + _CRTIMP __int64 __cdecl _strtoi64(const char *_String,char **_EndPtr,int _Radix); + _CRTIMP __int64 __cdecl _strtoi64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP unsigned __int64 __cdecl _strtoui64(const char *_String,char **_EndPtr,int _Radix); + _CRTIMP unsigned __int64 __cdecl _strtoui64_l(const char *_String,char **_EndPtr,int _Radix,_locale_t _Locale); +#endif + ldiv_t __cdecl ldiv(long _Numerator,long _Denominator); + _CRTIMP char *__cdecl _ltoa(long _Value,char *_Dest,int _Radix); + int __cdecl mblen(const char *_Ch,size_t _MaxCount); + _CRTIMP int __cdecl _mblen_l(const char *_Ch,size_t _MaxCount,_locale_t _Locale); + _CRTIMP size_t __cdecl _mbstrlen(const char *_Str); + _CRTIMP size_t __cdecl _mbstrlen_l(const char *_Str,_locale_t _Locale); + _CRTIMP size_t __cdecl _mbstrnlen(const char *_Str,size_t _MaxCount); + _CRTIMP size_t __cdecl _mbstrnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); + int __cdecl mbtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes); + _CRTIMP int __cdecl _mbtowc_l(wchar_t *_DstCh,const char *_SrcCh,size_t _SrcSizeInBytes,_locale_t _Locale); + size_t __cdecl mbstowcs(wchar_t *_Dest,const char *_Source,size_t _MaxCount); + _CRTIMP size_t __cdecl _mbstowcs_l(wchar_t *_Dest,const char *_Source,size_t _MaxCount,_locale_t _Locale); + int __cdecl rand(void); + _CRTIMP int __cdecl _set_error_mode(int _Mode); + void __cdecl srand(unsigned int _Seed); + double __cdecl strtod(const char *_Str,char **_EndPtr); + float __cdecl strtof(const char *nptr, char **endptr); +#if !defined __NO_ISOCEXT /* in libmingwex.a */ + float __cdecl strtof (const char * __restrict__, char ** __restrict__); + long double __cdecl strtold(const char * __restrict__, char ** __restrict__); +#endif /* __NO_ISOCEXT */ + _CRTIMP double __cdecl _strtod_l(const char *_Str,char **_EndPtr,_locale_t _Locale); + long __cdecl strtol(const char *_Str,char **_EndPtr,int _Radix); + _CRTIMP long __cdecl _strtol_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); + unsigned long __cdecl strtoul(const char *_Str,char **_EndPtr,int _Radix); + _CRTIMP unsigned long __cdecl _strtoul_l(const char *_Str,char **_EndPtr,int _Radix,_locale_t _Locale); +#ifndef _CRT_SYSTEM_DEFINED +#define _CRT_SYSTEM_DEFINED + int __cdecl system(const char *_Command); +#endif + _CRTIMP char *__cdecl _ultoa(unsigned long _Value,char *_Dest,int _Radix); + int __cdecl wctomb(char *_MbCh,wchar_t _WCh); + _CRTIMP int __cdecl _wctomb_l(char *_MbCh,wchar_t _WCh,_locale_t _Locale); + size_t __cdecl wcstombs(char *_Dest,const wchar_t *_Source,size_t _MaxCount); + _CRTIMP size_t __cdecl _wcstombs_l(char *_Dest,const wchar_t *_Source,size_t _MaxCount,_locale_t _Locale); + +#ifndef _CRT_ALLOCATION_DEFINED +#define _CRT_ALLOCATION_DEFINED + void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements); + void __cdecl free(void *_Memory); + void *__cdecl malloc(size_t _Size); + void *__cdecl realloc(void *_Memory,size_t _NewSize); + _CRTIMP void *__cdecl _recalloc(void *_Memory,size_t _Count,size_t _Size); + //_CRTIMP void __cdecl _aligned_free(void *_Memory); + //_CRTIMP void *__cdecl _aligned_malloc(size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_offset_malloc(size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_realloc(void *_Memory,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment); + _CRTIMP void *__cdecl _aligned_offset_realloc(void *_Memory,size_t _Size,size_t _Alignment,size_t _Offset); + _CRTIMP void *__cdecl _aligned_offset_recalloc(void *_Memory,size_t _Count,size_t _Size,size_t _Alignment,size_t _Offset); +#endif + +#ifndef _WSTDLIB_DEFINED +#define _WSTDLIB_DEFINED + + _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); + double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); + float __cdecl wcstof(const wchar_t *nptr, wchar_t **endptr); +#if !defined __NO_ISOCEXT /* in libmingwex.a */ + float __cdecl wcstof( const wchar_t * __restrict__, wchar_t ** __restrict__); + long double __cdecl wcstold(const wchar_t * __restrict__, wchar_t ** __restrict__); +#endif /* __NO_ISOCEXT */ + _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); + long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif + _CRTIMP double __cdecl _wtof(const wchar_t *_Str); + _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); + _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP long __cdecl _wtol(const wchar_t *_Str); + _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); + _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str ,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); +#endif +#endif + +#ifndef _POSIX_ +#define _CVTBUFSIZE (309+40) + _CRTIMP char *__cdecl _fullpath(char *_FullPath,const char *_Path,size_t _SizeInBytes); + _CRTIMP char *__cdecl _ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); + _CRTIMP char *__cdecl _fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); + _CRTIMP char *__cdecl _gcvt(double _Val,int _NumOfDigits,char *_DstBuf); + _CRTIMP int __cdecl _atodbl(_CRT_DOUBLE *_Result,char *_Str); + _CRTIMP int __cdecl _atoldbl(_LDOUBLE *_Result,char *_Str); + _CRTIMP int __cdecl _atoflt(_CRT_FLOAT *_Result,char *_Str); + _CRTIMP int __cdecl _atodbl_l(_CRT_DOUBLE *_Result,char *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _atoldbl_l(_LDOUBLE *_Result,char *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _atoflt_l(_CRT_FLOAT *_Result,char *_Str,_locale_t _Locale); + unsigned long __cdecl _lrotl(unsigned long _Val,int _Shift); + unsigned long __cdecl _lrotr(unsigned long _Val,int _Shift); + _CRTIMP void __cdecl _makepath(char *_Path,const char *_Drive,const char *_Dir,const char *_Filename,const char *_Ext); + _onexit_t __cdecl _onexit(_onexit_t _Func); + +#ifndef _CRT_PERROR_DEFINED +#define _CRT_PERROR_DEFINED + void __cdecl perror(const char *_ErrMsg); +#endif + _CRTIMP int __cdecl _putenv(const char *_EnvString); + unsigned int __cdecl _rotl(unsigned int _Val,int _Shift); +#if _INTEGRAL_MAX_BITS >= 64 + unsigned __int64 __cdecl _rotl64(unsigned __int64 _Val,int _Shift); +#endif + unsigned int __cdecl _rotr(unsigned int _Val,int _Shift); +#if _INTEGRAL_MAX_BITS >= 64 + unsigned __int64 __cdecl _rotr64(unsigned __int64 _Val,int _Shift); +#endif + _CRTIMP void __cdecl _searchenv(const char *_Filename,const char *_EnvVar,char *_ResultPath); + _CRTIMP void __cdecl _splitpath(const char *_FullPath,char *_Drive,char *_Dir,char *_Filename,char *_Ext); + _CRTIMP void __cdecl _swab(char *_Buf1,char *_Buf2,int _SizeInBytes); + +#ifndef _WSTDLIBP_DEFINED +#define _WSTDLIBP_DEFINED + _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); + _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); + _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); + _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); +#endif + + _CRTIMP void __cdecl _beep(unsigned _Frequency,unsigned _Duration) __MINGW_ATTRIB_DEPRECATED; + /* Not to be confused with _set_error_mode (int). */ + _CRTIMP void __cdecl _seterrormode(int _Mode) __MINGW_ATTRIB_DEPRECATED; + _CRTIMP void __cdecl _sleep(unsigned long _Duration) __MINGW_ATTRIB_DEPRECATED; +#endif + +#ifndef NO_OLDNAMES +#ifndef _POSIX_ +#if 0 +#ifndef __cplusplus +#ifndef NOMINMAX +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#endif +#endif +#endif + +#define sys_errlist _sys_errlist +#define sys_nerr _sys_nerr +#define environ _environ + char *__cdecl ecvt(double _Val,int _NumOfDigits,int *_PtDec,int *_PtSign); + char *__cdecl fcvt(double _Val,int _NumOfDec,int *_PtDec,int *_PtSign); + char *__cdecl gcvt(double _Val,int _NumOfDigits,char *_DstBuf); + char *__cdecl itoa(int _Val,char *_DstBuf,int _Radix); + char *__cdecl ltoa(long _Val,char *_DstBuf,int _Radix); + int __cdecl putenv(const char *_EnvString); + void __cdecl swab(char *_Buf1,char *_Buf2,int _SizeInBytes); + char *__cdecl ultoa(unsigned long _Val,char *_Dstbuf,int _Radix); + onexit_t __cdecl onexit(onexit_t _Func); +#endif +#endif + +#if !defined __NO_ISOCEXT /* externs in static libmingwex.a */ + + typedef struct { long long quot, rem; } lldiv_t; + + lldiv_t __cdecl lldiv(long long, long long); + + __CRT_INLINE long long __cdecl llabs(long long _j) { return (_j >= 0 ? _j : -_j); } + + long long __cdecl strtoll(const char* __restrict__, char** __restrict, int); + unsigned long long __cdecl strtoull(const char* __restrict__, char** __restrict__, int); + + /* these are stubs for MS _i64 versions */ + long long __cdecl atoll (const char *); + +#ifndef __STRICT_ANSI__ + long long __cdecl wtoll (const wchar_t *); + char *__cdecl lltoa (long long, char *, int); + char *__cdecl ulltoa (unsigned long long , char *, int); + wchar_t *__cdecl lltow (long long, wchar_t *, int); + wchar_t *__cdecl ulltow (unsigned long long, wchar_t *, int); + + /* __CRT_INLINE using non-ansi functions */ + __CRT_INLINE long long __cdecl atoll (const char * _c) { return _atoi64 (_c); } + __CRT_INLINE char *__cdecl lltoa (long long _n, char * _c, int _i) { return _i64toa (_n, _c, _i); } + __CRT_INLINE char *__cdecl ulltoa (unsigned long long _n, char * _c, int _i) { return _ui64toa (_n, _c, _i); } + __CRT_INLINE long long __cdecl wtoll (const wchar_t * _w) { return _wtoi64 (_w); } + __CRT_INLINE wchar_t *__cdecl lltow (long long _n, wchar_t * _w, int _i) { return _i64tow (_n, _w, _i); } + __CRT_INLINE wchar_t *__cdecl ulltow (unsigned long long _n, wchar_t * _w, int _i) { return _ui64tow (_n, _w, _i); } +#endif /* (__STRICT_ANSI__) */ + +#endif /* !__NO_ISOCEXT */ + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include +#include + +#endif diff --git a/tcc/include/stdnoreturn.h b/tcc/include/stdnoreturn.h index e71c9e1b..4d580ea5 100644 --- a/tcc/include/stdnoreturn.h +++ b/tcc/include/stdnoreturn.h @@ -1,7 +1,7 @@ -#ifndef _STDNORETURN_H -#define _STDNORETURN_H - -/* ISOC11 noreturn */ -#define noreturn _Noreturn - -#endif /* _STDNORETURN_H */ +#ifndef _STDNORETURN_H +#define _STDNORETURN_H + +/* ISOC11 noreturn */ +#define noreturn _Noreturn + +#endif /* _STDNORETURN_H */ diff --git a/tcc/include/string.h b/tcc/include/string.h index 288e12ba..3249dc3b 100644 --- a/tcc/include/string.h +++ b/tcc/include/string.h @@ -1,164 +1,164 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STRING -#define _INC_STRING - -#include <_mingw.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _NLSCMP_DEFINED -#define _NLSCMP_DEFINED -#define _NLSCMPERROR 2147483647 -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define _WConst_return _CONST_RETURN - -#ifndef _CRT_MEMORY_DEFINED -#define _CRT_MEMORY_DEFINED - _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); - _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); - _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); - _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); - int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); - void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); - void *__cdecl memset(void *_Dst,int _Val,size_t _Size); -#ifndef NO_OLDNAMES - void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); - int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); -#endif -#endif - char *__cdecl _strset(char *_Str,int _Val); - char *__cdecl strcpy(char *_Dest,const char *_Source); - char *__cdecl strcat(char *_Dest,const char *_Source); - int __cdecl strcmp(const char *_Str1,const char *_Str2); - size_t __cdecl strlen(const char *_Str); -#if 0 - size_t __cdecl strnlen(const char *_Str,size_t _MaxCount); -#endif - void *__cdecl memmove(void *_Dst,const void *_Src,size_t _Size); - _CRTIMP char *__cdecl _strdup(const char *_Src); - _CONST_RETURN char *__cdecl strchr(const char *_Str,int _Val); - _CRTIMP int __cdecl _stricmp(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _strcmpi(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _stricmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - int __cdecl strcoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _strcoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _stricoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _stricoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _strncoll (const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _strnicoll (const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - size_t __cdecl strcspn(const char *_Str,const char *_Control); - _CRTIMP char *__cdecl _strerror(const char *_ErrMsg); - char *__cdecl strerror(int); - _CRTIMP char *__cdecl _strlwr(char *_String); - char *strlwr_l(char *_String,_locale_t _Locale); - char *__cdecl strncat(char *_Dest,const char *_Source,size_t _Count); - int __cdecl strncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _strnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - char *strncpy(char *_Dest,const char *_Source,size_t _Count); - _CRTIMP char *__cdecl _strnset(char *_Str,int _Val,size_t _MaxCount); - _CONST_RETURN char *__cdecl strpbrk(const char *_Str,const char *_Control); - _CONST_RETURN char *__cdecl strrchr(const char *_Str,int _Ch); - _CRTIMP char *__cdecl _strrev(char *_Str); - size_t __cdecl strspn(const char *_Str,const char *_Control); - _CONST_RETURN char *__cdecl strstr(const char *_Str,const char *_SubStr); - char *__cdecl strtok(char *_Str,const char *_Delim); - _CRTIMP char *__cdecl _strupr(char *_String); - _CRTIMP char *_strupr_l(char *_String,_locale_t _Locale); - size_t __cdecl strxfrm(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP size_t __cdecl _strxfrm_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - -#ifndef NO_OLDNAMES - char *__cdecl strdup(const char *_Src); - int __cdecl strcmpi(const char *_Str1,const char *_Str2); - int __cdecl stricmp(const char *_Str1,const char *_Str2); - char *__cdecl strlwr(char *_Str); - int __cdecl strnicmp(const char *_Str1,const char *_Str,size_t _MaxCount); - __CRT_INLINE int __cdecl strncasecmp (const char *__sz1, const char *__sz2, size_t __sizeMaxCompare) { return _strnicmp (__sz1, __sz2, __sizeMaxCompare); } - __CRT_INLINE int __cdecl strcasecmp (const char *__sz1, const char *__sz2) { return _stricmp (__sz1, __sz2); } - char *__cdecl strnset(char *_Str,int _Val,size_t _MaxCount); - char *__cdecl strrev(char *_Str); - char *__cdecl strset(char *_Str,int _Val); - char *__cdecl strupr(char *_Str); -#endif - -#ifndef _WSTRING_DEFINED -#define _WSTRING_DEFINED - - _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); - wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); - _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); - int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); - wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); - size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); - size_t __cdecl wcslen(const wchar_t *_Str); - size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); - wchar_t *wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); - size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); - wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); - _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); - _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); - _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); - _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); - _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); - _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); - _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); - size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); - _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); - int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - -#ifndef NO_OLDNAMES - wchar_t *__cdecl wcsdup(const wchar_t *_Str); -#define wcswcs wcsstr - int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - wchar_t *__cdecl wcsrev(wchar_t *_Str); - wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); - wchar_t *__cdecl wcslwr(wchar_t *_Str); - wchar_t *__cdecl wcsupr(wchar_t *_Str); - int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STRING +#define _INC_STRING + +#include <_mingw.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _NLSCMP_DEFINED +#define _NLSCMP_DEFINED +#define _NLSCMPERROR 2147483647 +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define _WConst_return _CONST_RETURN + +#ifndef _CRT_MEMORY_DEFINED +#define _CRT_MEMORY_DEFINED + _CRTIMP void *__cdecl _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount); + _CONST_RETURN void *__cdecl memchr(const void *_Buf ,int _Val,size_t _MaxCount); + _CRTIMP int __cdecl _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); + _CRTIMP int __cdecl _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale); + int __cdecl memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); + void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _Size); + void *__cdecl memset(void *_Dst,int _Val,size_t _Size); +#ifndef NO_OLDNAMES + void *__cdecl memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size); + int __cdecl memicmp(const void *_Buf1,const void *_Buf2,size_t _Size); +#endif +#endif + char *__cdecl _strset(char *_Str,int _Val); + char *__cdecl strcpy(char *_Dest,const char *_Source); + char *__cdecl strcat(char *_Dest,const char *_Source); + int __cdecl strcmp(const char *_Str1,const char *_Str2); + size_t __cdecl strlen(const char *_Str); +#if 0 + size_t __cdecl strnlen(const char *_Str,size_t _MaxCount); +#endif + void *__cdecl memmove(void *_Dst,const void *_Src,size_t _Size); + _CRTIMP char *__cdecl _strdup(const char *_Src); + _CONST_RETURN char *__cdecl strchr(const char *_Str,int _Val); + _CRTIMP int __cdecl _stricmp(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _strcmpi(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _stricmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + int __cdecl strcoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _strcoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _stricoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _stricoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _strncoll (const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _strnicoll (const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + size_t __cdecl strcspn(const char *_Str,const char *_Control); + _CRTIMP char *__cdecl _strerror(const char *_ErrMsg); + char *__cdecl strerror(int); + _CRTIMP char *__cdecl _strlwr(char *_String); + char *strlwr_l(char *_String,_locale_t _Locale); + char *__cdecl strncat(char *_Dest,const char *_Source,size_t _Count); + int __cdecl strncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _strnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + char *strncpy(char *_Dest,const char *_Source,size_t _Count); + _CRTIMP char *__cdecl _strnset(char *_Str,int _Val,size_t _MaxCount); + _CONST_RETURN char *__cdecl strpbrk(const char *_Str,const char *_Control); + _CONST_RETURN char *__cdecl strrchr(const char *_Str,int _Ch); + _CRTIMP char *__cdecl _strrev(char *_Str); + size_t __cdecl strspn(const char *_Str,const char *_Control); + _CONST_RETURN char *__cdecl strstr(const char *_Str,const char *_SubStr); + char *__cdecl strtok(char *_Str,const char *_Delim); + _CRTIMP char *__cdecl _strupr(char *_String); + _CRTIMP char *_strupr_l(char *_String,_locale_t _Locale); + size_t __cdecl strxfrm(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP size_t __cdecl _strxfrm_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + +#ifndef NO_OLDNAMES + char *__cdecl strdup(const char *_Src); + int __cdecl strcmpi(const char *_Str1,const char *_Str2); + int __cdecl stricmp(const char *_Str1,const char *_Str2); + char *__cdecl strlwr(char *_Str); + int __cdecl strnicmp(const char *_Str1,const char *_Str,size_t _MaxCount); + __CRT_INLINE int __cdecl strncasecmp (const char *__sz1, const char *__sz2, size_t __sizeMaxCompare) { return _strnicmp (__sz1, __sz2, __sizeMaxCompare); } + __CRT_INLINE int __cdecl strcasecmp (const char *__sz1, const char *__sz2) { return _stricmp (__sz1, __sz2); } + char *__cdecl strnset(char *_Str,int _Val,size_t _MaxCount); + char *__cdecl strrev(char *_Str); + char *__cdecl strset(char *_Str,int _Val); + char *__cdecl strupr(char *_Str); +#endif + +#ifndef _WSTRING_DEFINED +#define _WSTRING_DEFINED + + _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); + wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); + _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); + int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); + wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); + size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); + size_t __cdecl wcslen(const wchar_t *_Str); + size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); + wchar_t *wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); + size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); + wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); + _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); + _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); + _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); + _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); + _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); + _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); + _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); + size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); + _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); + int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + +#ifndef NO_OLDNAMES + wchar_t *__cdecl wcsdup(const wchar_t *_Str); +#define wcswcs wcsstr + int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + wchar_t *__cdecl wcsrev(wchar_t *_Str); + wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); + wchar_t *__cdecl wcslwr(wchar_t *_Str); + wchar_t *__cdecl wcsupr(wchar_t *_Str); + int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#include +#endif diff --git a/tcc/include/sys/fcntl.h b/tcc/include/sys/fcntl.h index 8456b824..29fd55a1 100644 --- a/tcc/include/sys/fcntl.h +++ b/tcc/include/sys/fcntl.h @@ -1,13 +1,13 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * This fcntl.h maps to the root fcntl.h - */ -#ifndef __STRICT_ANSI__ -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * This fcntl.h maps to the root fcntl.h + */ +#ifndef __STRICT_ANSI__ +#include +#endif diff --git a/tcc/include/sys/file.h b/tcc/include/sys/file.h index 70169f39..370f352d 100644 --- a/tcc/include/sys/file.h +++ b/tcc/include/sys/file.h @@ -1,14 +1,14 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * This file.h maps to the root fcntl.h - * TODO? - */ -#ifndef __STRICT_ANSI__ -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * This file.h maps to the root fcntl.h + * TODO? + */ +#ifndef __STRICT_ANSI__ +#include +#endif diff --git a/tcc/include/sys/locking.h b/tcc/include/sys/locking.h index 98d9acc4..e3fc85b3 100644 --- a/tcc/include/sys/locking.h +++ b/tcc/include/sys/locking.h @@ -1,30 +1,30 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_LOCKING -#define _INC_LOCKING - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -/* All the headers include this file. */ -#include <_mingw.h> - -#define _LK_UNLCK 0 -#define _LK_LOCK 1 -#define _LK_NBLCK 2 -#define _LK_RLCK 3 -#define _LK_NBRLCK 4 - -#ifndef NO_OLDNAMES -#define LK_UNLCK _LK_UNLCK -#define LK_LOCK _LK_LOCK -#define LK_NBLCK _LK_NBLCK -#define LK_RLCK _LK_RLCK -#define LK_NBRLCK _LK_NBRLCK -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_LOCKING +#define _INC_LOCKING + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +/* All the headers include this file. */ +#include <_mingw.h> + +#define _LK_UNLCK 0 +#define _LK_LOCK 1 +#define _LK_NBLCK 2 +#define _LK_RLCK 3 +#define _LK_NBRLCK 4 + +#ifndef NO_OLDNAMES +#define LK_UNLCK _LK_UNLCK +#define LK_LOCK _LK_LOCK +#define LK_NBLCK _LK_NBLCK +#define LK_RLCK _LK_RLCK +#define LK_NBRLCK _LK_NBRLCK +#endif + +#endif diff --git a/tcc/include/sys/stat.h b/tcc/include/sys/stat.h index 1d687dbd..4a95e659 100644 --- a/tcc/include/sys/stat.h +++ b/tcc/include/sys/stat.h @@ -1,290 +1,290 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_STAT -#define _INC_STAT - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> -#include - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#include - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED - typedef long __time32_t; -#define _TIME32_T_DEFINED -#endif - -#ifndef _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 - typedef __int64 __time64_t; -#endif -#define _TIME64_T_DEFINED -#endif - -#ifndef _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#define _TIME_T_DEFINED -#endif - -#ifndef _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif - -#ifndef _STAT_DEFINED - -#ifdef _USE_32BIT_TIME_T -#ifndef _WIN64 -#define _fstat32 _fstat -#define _stat32 _stat -#define _wstat32 _wstat -#else -#define _fstat _fstat32 -#define _stat _stat32 -#define _wstat _wstat32 -#endif -#define _fstati64 _fstat32i64 -#define _stati64 _stat32i64 -#define _wstati64 _wstat32i64 -#else -#define _fstat _fstat64i32 -#define _fstati64 _fstat64 -#define _stat _stat64 -#define _stati64 _stat64 -#define _wstat _wstat64 -#define _wstati64 _wstat64 -#endif - - struct _stat32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - -#ifndef NO_OLDNAMES - struct stat { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; - }; -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - struct _stat32i64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - - struct _stat64i32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; - - struct _stat64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; -#endif - -#define __stat64 _stat64 - -#define _STAT_DEFINED -#endif - -#define _S_IFMT 0xF000 -#define _S_IFDIR 0x4000 -#define _S_IFCHR 0x2000 -#define _S_IFIFO 0x1000 -#define _S_IFREG 0x8000 -#define _S_IREAD 0x0100 -#define _S_IWRITE 0x0080 -#define _S_IEXEC 0x0040 - - _CRTIMP int __cdecl _fstat32(int _FileDes,struct _stat32 *_Stat); - _CRTIMP int __cdecl _stat32(const char *_Name,struct _stat32 *_Stat); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _fstat64(int _FileDes,struct _stat64 *_Stat); - _CRTIMP int __cdecl _fstat32i64(int _FileDes,struct _stat32i64 *_Stat); - int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat); - __CRT_INLINE int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat) - { - struct _stat64 st; - int ret=_fstat64(_FileDes,&st); - _Stat->st_dev=st.st_dev; - _Stat->st_ino=st.st_ino; - _Stat->st_mode=st.st_mode; - _Stat->st_nlink=st.st_nlink; - _Stat->st_uid=st.st_uid; - _Stat->st_gid=st.st_gid; - _Stat->st_rdev=st.st_rdev; - _Stat->st_size=(_off_t) st.st_size; - _Stat->st_atime=st.st_atime; - _Stat->st_mtime=st.st_mtime; - _Stat->st_ctime=st.st_ctime; - return ret; - } - _CRTIMP int __cdecl _stat64(const char *_Name,struct _stat64 *_Stat); - _CRTIMP int __cdecl _stat32i64(const char *_Name,struct _stat32i64 *_Stat); - int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat); - __CRT_INLINE int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat) - { - struct _stat64 st; - int ret=_stat64(_Name,&st); - _Stat->st_dev=st.st_dev; - _Stat->st_ino=st.st_ino; - _Stat->st_mode=st.st_mode; - _Stat->st_nlink=st.st_nlink; - _Stat->st_uid=st.st_uid; - _Stat->st_gid=st.st_gid; - _Stat->st_rdev=st.st_rdev; - _Stat->st_size=(_off_t) st.st_size; - _Stat->st_atime=st.st_atime; - _Stat->st_mtime=st.st_mtime; - _Stat->st_ctime=st.st_ctime; - return ret; - } -#endif - -#ifndef _WSTAT_DEFINED -#define _WSTAT_DEFINED - _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); - int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); - _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); -#endif -#endif - -#ifndef NO_OLDNAMES -#define _S_IFBLK 0x3000 /* Block: Is this ever set under w32? */ - -#define S_IFMT _S_IFMT -#define S_IFDIR _S_IFDIR -#define S_IFCHR _S_IFCHR -#define S_IFREG _S_IFREG -#define S_IREAD _S_IREAD -#define S_IWRITE _S_IWRITE -#define S_IEXEC _S_IEXEC -#define S_IFIFO _S_IFIFO -#define S_IFBLK _S_IFBLK - -#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) -#define _S_IXUSR _S_IEXEC -#define _S_IWUSR _S_IWRITE - -#define S_IRWXU _S_IRWXU -#define S_IXUSR _S_IXUSR -#define S_IWUSR _S_IWUSR -#define S_IRUSR _S_IRUSR -#define _S_IRUSR _S_IREAD - -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) - -#endif - -#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) -int __cdecl stat(const char *_Filename,struct stat *_Stat); -int __cdecl fstat(int _Desc,struct stat *_Stat); -int __cdecl wstat(const wchar_t *_Filename,struct stat *_Stat); -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { - return _fstat32(_Desc,(struct _stat32 *)_Stat); -} -__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { - return _stat32(_Filename,(struct _stat32 *)_Stat); -} -#else -__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { - return _fstat64i32(_Desc,(struct _stat64i32 *)_Stat); -} -__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { - return _stat64i32(_Filename,(struct _stat64i32 *)_Stat); -} -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_STAT +#define _INC_STAT + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> +#include + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#include + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED + typedef long __time32_t; +#define _TIME32_T_DEFINED +#endif + +#ifndef _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 + typedef __int64 __time64_t; +#endif +#define _TIME64_T_DEFINED +#endif + +#ifndef _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#define _TIME_T_DEFINED +#endif + +#ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +#ifndef _STAT_DEFINED + +#ifdef _USE_32BIT_TIME_T +#ifndef _WIN64 +#define _fstat32 _fstat +#define _stat32 _stat +#define _wstat32 _wstat +#else +#define _fstat _fstat32 +#define _stat _stat32 +#define _wstat _wstat32 +#endif +#define _fstati64 _fstat32i64 +#define _stati64 _stat32i64 +#define _wstati64 _wstat32i64 +#else +#define _fstat _fstat64i32 +#define _fstati64 _fstat64 +#define _stat _stat64 +#define _stati64 _stat64 +#define _wstat _wstat64 +#define _wstati64 _wstat64 +#endif + + struct _stat32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + +#ifndef NO_OLDNAMES + struct stat { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + }; +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + struct _stat32i64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + + struct _stat64i32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; + + struct _stat64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; +#endif + +#define __stat64 _stat64 + +#define _STAT_DEFINED +#endif + +#define _S_IFMT 0xF000 +#define _S_IFDIR 0x4000 +#define _S_IFCHR 0x2000 +#define _S_IFIFO 0x1000 +#define _S_IFREG 0x8000 +#define _S_IREAD 0x0100 +#define _S_IWRITE 0x0080 +#define _S_IEXEC 0x0040 + + _CRTIMP int __cdecl _fstat32(int _FileDes,struct _stat32 *_Stat); + _CRTIMP int __cdecl _stat32(const char *_Name,struct _stat32 *_Stat); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _fstat64(int _FileDes,struct _stat64 *_Stat); + _CRTIMP int __cdecl _fstat32i64(int _FileDes,struct _stat32i64 *_Stat); + int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat); + __CRT_INLINE int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat) + { + struct _stat64 st; + int ret=_fstat64(_FileDes,&st); + _Stat->st_dev=st.st_dev; + _Stat->st_ino=st.st_ino; + _Stat->st_mode=st.st_mode; + _Stat->st_nlink=st.st_nlink; + _Stat->st_uid=st.st_uid; + _Stat->st_gid=st.st_gid; + _Stat->st_rdev=st.st_rdev; + _Stat->st_size=(_off_t) st.st_size; + _Stat->st_atime=st.st_atime; + _Stat->st_mtime=st.st_mtime; + _Stat->st_ctime=st.st_ctime; + return ret; + } + _CRTIMP int __cdecl _stat64(const char *_Name,struct _stat64 *_Stat); + _CRTIMP int __cdecl _stat32i64(const char *_Name,struct _stat32i64 *_Stat); + int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat); + __CRT_INLINE int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat) + { + struct _stat64 st; + int ret=_stat64(_Name,&st); + _Stat->st_dev=st.st_dev; + _Stat->st_ino=st.st_ino; + _Stat->st_mode=st.st_mode; + _Stat->st_nlink=st.st_nlink; + _Stat->st_uid=st.st_uid; + _Stat->st_gid=st.st_gid; + _Stat->st_rdev=st.st_rdev; + _Stat->st_size=(_off_t) st.st_size; + _Stat->st_atime=st.st_atime; + _Stat->st_mtime=st.st_mtime; + _Stat->st_ctime=st.st_ctime; + return ret; + } +#endif + +#ifndef _WSTAT_DEFINED +#define _WSTAT_DEFINED + _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); + int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); + _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); +#endif +#endif + +#ifndef NO_OLDNAMES +#define _S_IFBLK 0x3000 /* Block: Is this ever set under w32? */ + +#define S_IFMT _S_IFMT +#define S_IFDIR _S_IFDIR +#define S_IFCHR _S_IFCHR +#define S_IFREG _S_IFREG +#define S_IREAD _S_IREAD +#define S_IWRITE _S_IWRITE +#define S_IEXEC _S_IEXEC +#define S_IFIFO _S_IFIFO +#define S_IFBLK _S_IFBLK + +#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC) +#define _S_IXUSR _S_IEXEC +#define _S_IWUSR _S_IWRITE + +#define S_IRWXU _S_IRWXU +#define S_IXUSR _S_IXUSR +#define S_IWUSR _S_IWUSR +#define S_IRUSR _S_IRUSR +#define _S_IRUSR _S_IREAD + +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) + +#endif + +#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) +int __cdecl stat(const char *_Filename,struct stat *_Stat); +int __cdecl fstat(int _Desc,struct stat *_Stat); +int __cdecl wstat(const wchar_t *_Filename,struct stat *_Stat); +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { + return _fstat32(_Desc,(struct _stat32 *)_Stat); +} +__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { + return _stat32(_Filename,(struct _stat32 *)_Stat); +} +#else +__CRT_INLINE int __cdecl fstat(int _Desc,struct stat *_Stat) { + return _fstat64i32(_Desc,(struct _stat64i32 *)_Stat); +} +__CRT_INLINE int __cdecl stat(const char *_Filename,struct stat *_Stat) { + return _stat64i32(_Filename,(struct _stat64i32 *)_Stat); +} +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/sys/time.h b/tcc/include/sys/time.h index af9be8f7..8ccab831 100644 --- a/tcc/include/sys/time.h +++ b/tcc/include/sys/time.h @@ -1,69 +1,69 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _SYS_TIME_H_ -#define _SYS_TIME_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __STRICT_ANSI__ -#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ -#define _TIMEVAL_DEFINED -struct timeval { - long tv_sec; - long tv_usec; -}; -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define timercmp(tvp, uvp, cmp) \ - (((tvp)->tv_sec != (uvp)->tv_sec) ? \ - ((tvp)->tv_sec cmp (uvp)->tv_sec) : \ - ((tvp)->tv_usec cmp (uvp)->tv_usec)) -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif /* _TIMEVAL_DEFINED */ - -#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ -#define _TIMEZONE_DEFINED -/* Provided for compatibility with code that assumes that - the presence of gettimeofday function implies a definition - of struct timezone. */ -struct timezone -{ - int tz_minuteswest; /* of Greenwich */ - int tz_dsttime; /* type of dst correction to apply */ -}; - - extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); - -#endif - -/* - Implementation as per: - The Open Group Base Specifications, Issue 6 - IEEE Std 1003.1, 2004 Edition - - The timezone pointer arg is ignored. Errors are ignored. -*/ -#ifndef _GETTIMEOFDAY_DEFINED -#define _GETTIMEOFDAY_DEFINED -int __cdecl gettimeofday(struct timeval *__restrict__, - void *__restrict__ /* tzp (unused) */); -#endif - -#endif /* __STRICT_ANSI__ */ - -#ifdef __cplusplus -} -#endif - -/* Adding timespec definition. */ -#include - - -#endif /* _SYS_TIME_H_ */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _SYS_TIME_H_ +#define _SYS_TIME_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __STRICT_ANSI__ +#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ +#define _TIMEVAL_DEFINED +struct timeval { + long tv_sec; + long tv_usec; +}; +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec != (uvp)->tv_sec) ? \ + ((tvp)->tv_sec cmp (uvp)->tv_sec) : \ + ((tvp)->tv_usec cmp (uvp)->tv_usec)) +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif /* _TIMEVAL_DEFINED */ + +#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ +#define _TIMEZONE_DEFINED +/* Provided for compatibility with code that assumes that + the presence of gettimeofday function implies a definition + of struct timezone. */ +struct timezone +{ + int tz_minuteswest; /* of Greenwich */ + int tz_dsttime; /* type of dst correction to apply */ +}; + + extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); + +#endif + +/* + Implementation as per: + The Open Group Base Specifications, Issue 6 + IEEE Std 1003.1, 2004 Edition + + The timezone pointer arg is ignored. Errors are ignored. +*/ +#ifndef _GETTIMEOFDAY_DEFINED +#define _GETTIMEOFDAY_DEFINED +int __cdecl gettimeofday(struct timeval *__restrict__, + void *__restrict__ /* tzp (unused) */); +#endif + +#endif /* __STRICT_ANSI__ */ + +#ifdef __cplusplus +} +#endif + +/* Adding timespec definition. */ +#include + + +#endif /* _SYS_TIME_H_ */ diff --git a/tcc/include/sys/timeb.h b/tcc/include/sys/timeb.h index 9fdb6965..34837738 100644 --- a/tcc/include/sys/timeb.h +++ b/tcc/include/sys/timeb.h @@ -1,133 +1,133 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _TIMEB_H_ -#define _TIMEB_H_ - -#include <_mingw.h> - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED - typedef long __time32_t; -#define _TIME32_T_DEFINED -#endif - -#ifndef _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 - typedef __int64 __time64_t; -#endif -#define _TIME64_T_DEFINED -#endif - -#ifndef _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#define _TIME_T_DEFINED -#endif - -#ifndef _TIMEB_DEFINED -#define _TIMEB_DEFINED - - struct __timeb32 { - __time32_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; - -#ifndef NO_OLDNAMES - struct timeb { - time_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - struct __timeb64 { - __time64_t time; - unsigned short millitm; - short timezone; - short dstflag; - }; -#endif - -#ifdef _USE_32BIT_TIME_T -#define _timeb __timeb32 -//gr #define _ftime _ftime32 -#define _ftime32 _ftime -#else -#define _timeb __timeb64 -#define _ftime _ftime64 -#endif -#endif - - _CRTIMP void __cdecl _ftime32(struct __timeb32 *_Time); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP void __cdecl _ftime64(struct __timeb64 *_Time); -#endif - -#ifndef _TIMESPEC_DEFINED -#define _TIMESPEC_DEFINED -struct timespec { - time_t tv_sec; /* Seconds */ - long tv_nsec; /* Nanoseconds */ -}; - -struct itimerspec { - struct timespec it_interval; /* Timer period */ - struct timespec it_value; /* Timer expiration */ -}; -#endif - -#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { - _ftime32((struct __timeb32 *)_Tmb); -} -#else -__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { - _ftime64((struct __timeb64 *)_Tmb); -} -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _TIMEB_H_ +#define _TIMEB_H_ + +#include <_mingw.h> + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED + typedef long __time32_t; +#define _TIME32_T_DEFINED +#endif + +#ifndef _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 + typedef __int64 __time64_t; +#endif +#define _TIME64_T_DEFINED +#endif + +#ifndef _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#define _TIME_T_DEFINED +#endif + +#ifndef _TIMEB_DEFINED +#define _TIMEB_DEFINED + + struct __timeb32 { + __time32_t time; + unsigned short millitm; + short timezone; + short dstflag; + }; + +#ifndef NO_OLDNAMES + struct timeb { + time_t time; + unsigned short millitm; + short timezone; + short dstflag; + }; +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + struct __timeb64 { + __time64_t time; + unsigned short millitm; + short timezone; + short dstflag; + }; +#endif + +#ifdef _USE_32BIT_TIME_T +#define _timeb __timeb32 +//gr #define _ftime _ftime32 +#define _ftime32 _ftime +#else +#define _timeb __timeb64 +#define _ftime _ftime64 +#endif +#endif + + _CRTIMP void __cdecl _ftime32(struct __timeb32 *_Time); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP void __cdecl _ftime64(struct __timeb64 *_Time); +#endif + +#ifndef _TIMESPEC_DEFINED +#define _TIMESPEC_DEFINED +struct timespec { + time_t tv_sec; /* Seconds */ + long tv_nsec; /* Nanoseconds */ +}; + +struct itimerspec { + struct timespec it_interval; /* Timer period */ + struct timespec it_value; /* Timer expiration */ +}; +#endif + +#if !defined (RC_INVOKED) && !defined (NO_OLDNAMES) +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { + _ftime32((struct __timeb32 *)_Tmb); +} +#else +__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb) { + _ftime64((struct __timeb64 *)_Tmb); +} +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include +#endif diff --git a/tcc/include/sys/types.h b/tcc/include/sys/types.h index 80ba7a47..7379b0f1 100644 --- a/tcc/include/sys/types.h +++ b/tcc/include/sys/types.h @@ -1,118 +1,118 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_TYPES -#define _INC_TYPES - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED -typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 -typedef __int64 __time64_t; -#endif -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T -typedef __time32_t time_t; -#else -typedef __time64_t time_t; -#endif -#endif - -#ifndef _INO_T_DEFINED -#define _INO_T_DEFINED -typedef unsigned short _ino_t; -#ifndef NO_OLDNAMES -typedef unsigned short ino_t; -#endif -#endif - -#ifndef _DEV_T_DEFINED -#define _DEV_T_DEFINED -typedef unsigned int _dev_t; -#ifndef NO_OLDNAMES -typedef unsigned int dev_t; -#endif -#endif - -#ifndef _PID_T_ -#define _PID_T_ -#ifndef _WIN64 -typedef int _pid_t; -#else -typedef __int64 _pid_t; -#endif - -#ifndef NO_OLDNAMES -typedef _pid_t pid_t; -#endif -#endif /* Not _PID_T_ */ - -#ifndef _MODE_T_ -#define _MODE_T_ -typedef unsigned short _mode_t; - -#ifndef NO_OLDNAMES -typedef _mode_t mode_t; -#endif -#endif /* Not _MODE_T_ */ - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif - -#ifndef _TIMESPEC_DEFINED -#define _TIMESPEC_DEFINED -struct timespec { - time_t tv_sec; /* Seconds */ - long tv_nsec; /* Nanoseconds */ -}; - -struct itimerspec { - struct timespec it_interval; /* Timer period */ - struct timespec it_value; /* Timer expiration */ -}; -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_TYPES +#define _INC_TYPES + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED +typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 +typedef __int64 __time64_t; +#endif +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T +typedef __time32_t time_t; +#else +typedef __time64_t time_t; +#endif +#endif + +#ifndef _INO_T_DEFINED +#define _INO_T_DEFINED +typedef unsigned short _ino_t; +#ifndef NO_OLDNAMES +typedef unsigned short ino_t; +#endif +#endif + +#ifndef _DEV_T_DEFINED +#define _DEV_T_DEFINED +typedef unsigned int _dev_t; +#ifndef NO_OLDNAMES +typedef unsigned int dev_t; +#endif +#endif + +#ifndef _PID_T_ +#define _PID_T_ +#ifndef _WIN64 +typedef int _pid_t; +#else +typedef __int64 _pid_t; +#endif + +#ifndef NO_OLDNAMES +typedef _pid_t pid_t; +#endif +#endif /* Not _PID_T_ */ + +#ifndef _MODE_T_ +#define _MODE_T_ +typedef unsigned short _mode_t; + +#ifndef NO_OLDNAMES +typedef _mode_t mode_t; +#endif +#endif /* Not _MODE_T_ */ + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif + +#ifndef _TIMESPEC_DEFINED +#define _TIMESPEC_DEFINED +struct timespec { + time_t tv_sec; /* Seconds */ + long tv_nsec; /* Nanoseconds */ +}; + +struct itimerspec { + struct timespec it_interval; /* Timer period */ + struct timespec it_value; /* Timer expiration */ +}; +#endif + +#endif diff --git a/tcc/include/sys/unistd.h b/tcc/include/sys/unistd.h index a0c29cda..31006d32 100644 --- a/tcc/include/sys/unistd.h +++ b/tcc/include/sys/unistd.h @@ -1,14 +1,14 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -/* - * This file is part of the Mingw32 package. - * - * unistd.h maps (roughly) to io.h - */ -#ifndef __STRICT_ANSI__ -#include -#endif - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +/* + * This file is part of the Mingw32 package. + * + * unistd.h maps (roughly) to io.h + */ +#ifndef __STRICT_ANSI__ +#include +#endif + diff --git a/tcc/include/sys/utime.h b/tcc/include/sys/utime.h index 4d9daee2..fec8304f 100644 --- a/tcc/include/sys/utime.h +++ b/tcc/include/sys/utime.h @@ -1,146 +1,146 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_UTIME -#define _INC_UTIME - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif - -#ifndef __TINYC__ /* gr */ -#ifdef _USE_32BIT_TIME_T -#ifdef _WIN64 -#undef _USE_32BIT_TIME_T -#endif -#else -#if _INTEGRAL_MAX_BITS < 64 -#define _USE_32BIT_TIME_T -#endif -#endif -#endif - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED - typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 - typedef __int64 __time64_t; -#endif -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#endif - -#ifndef _UTIMBUF_DEFINED -#define _UTIMBUF_DEFINED - - struct _utimbuf { - time_t actime; - time_t modtime; - }; - - struct __utimbuf32 { - __time32_t actime; - __time32_t modtime; - }; - -#if _INTEGRAL_MAX_BITS >= 64 - struct __utimbuf64 { - __time64_t actime; - __time64_t modtime; - }; -#endif - -#ifndef NO_OLDNAMES - struct utimbuf { - time_t actime; - time_t modtime; - }; - - struct utimbuf32 { - __time32_t actime; - __time32_t modtime; - }; -#endif -#endif - - _CRTIMP int __cdecl _utime32(const char *_Filename,struct __utimbuf32 *_Time); - _CRTIMP int __cdecl _futime32(int _FileDes,struct __utimbuf32 *_Time); - _CRTIMP int __cdecl _wutime32(const wchar_t *_Filename,struct __utimbuf32 *_Time); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _utime64(const char *_Filename,struct __utimbuf64 *_Time); - _CRTIMP int __cdecl _futime64(int _FileDes,struct __utimbuf64 *_Time); - _CRTIMP int __cdecl _wutime64(const wchar_t *_Filename,struct __utimbuf64 *_Time); -#endif - -#ifndef RC_INVOKED -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { - return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { - return _futime32(_Desc,(struct __utimbuf32 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { - return _wutime32(_Filename,(struct __utimbuf32 *)_Utimbuf); -} -#else -__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { - return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { - return _futime64(_Desc,(struct __utimbuf64 *)_Utimbuf); -} -__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { - return _wutime64(_Filename,(struct __utimbuf64 *)_Utimbuf); -} -#endif - -#ifndef NO_OLDNAMES -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { - return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); -} -#else -__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { - return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); -} -#endif -#endif -#endif - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_UTIME +#define _INC_UTIME + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +#ifndef __TINYC__ /* gr */ +#ifdef _USE_32BIT_TIME_T +#ifdef _WIN64 +#undef _USE_32BIT_TIME_T +#endif +#else +#if _INTEGRAL_MAX_BITS < 64 +#define _USE_32BIT_TIME_T +#endif +#endif +#endif + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED + typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 + typedef __int64 __time64_t; +#endif +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#endif + +#ifndef _UTIMBUF_DEFINED +#define _UTIMBUF_DEFINED + + struct _utimbuf { + time_t actime; + time_t modtime; + }; + + struct __utimbuf32 { + __time32_t actime; + __time32_t modtime; + }; + +#if _INTEGRAL_MAX_BITS >= 64 + struct __utimbuf64 { + __time64_t actime; + __time64_t modtime; + }; +#endif + +#ifndef NO_OLDNAMES + struct utimbuf { + time_t actime; + time_t modtime; + }; + + struct utimbuf32 { + __time32_t actime; + __time32_t modtime; + }; +#endif +#endif + + _CRTIMP int __cdecl _utime32(const char *_Filename,struct __utimbuf32 *_Time); + _CRTIMP int __cdecl _futime32(int _FileDes,struct __utimbuf32 *_Time); + _CRTIMP int __cdecl _wutime32(const wchar_t *_Filename,struct __utimbuf32 *_Time); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _utime64(const char *_Filename,struct __utimbuf64 *_Time); + _CRTIMP int __cdecl _futime64(int _FileDes,struct __utimbuf64 *_Time); + _CRTIMP int __cdecl _wutime64(const wchar_t *_Filename,struct __utimbuf64 *_Time); +#endif + +#ifndef RC_INVOKED +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { + return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { + return _futime32(_Desc,(struct __utimbuf32 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { + return _wutime32(_Filename,(struct __utimbuf32 *)_Utimbuf); +} +#else +__CRT_INLINE int __cdecl _utime(const char *_Filename,struct _utimbuf *_Utimbuf) { + return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _futime(int _Desc,struct _utimbuf *_Utimbuf) { + return _futime64(_Desc,(struct __utimbuf64 *)_Utimbuf); +} +__CRT_INLINE int __cdecl _wutime(const wchar_t *_Filename,struct _utimbuf *_Utimbuf) { + return _wutime64(_Filename,(struct __utimbuf64 *)_Utimbuf); +} +#endif + +#ifndef NO_OLDNAMES +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { + return _utime32(_Filename,(struct __utimbuf32 *)_Utimbuf); +} +#else +__CRT_INLINE int __cdecl utime(const char *_Filename,struct utimbuf *_Utimbuf) { + return _utime64(_Filename,(struct __utimbuf64 *)_Utimbuf); +} +#endif +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/tcc/tcc_libm.h b/tcc/include/tcc/tcc_libm.h index 0a6f791b..ba26ee00 100644 --- a/tcc/include/tcc/tcc_libm.h +++ b/tcc/include/tcc/tcc_libm.h @@ -1,618 +1,618 @@ -#ifndef _TCC_LIBM_H_ -#define _TCC_LIBM_H_ - -#include "../math.h" -#include "../stdint.h" - -/* TCC uses 8 bytes for double and long double, so effectively the l variants - * are never used. For now, they just run the normal (double) variant. - */ - -/* - * most of the code in this file is taken from MUSL rs-1.0 (MIT license) - * - musl-libc: http://git.musl-libc.org/cgit/musl/tree/src/math?h=rs-1.0 - * - License: http://git.musl-libc.org/cgit/musl/tree/COPYRIGHT?h=rs-1.0 - */ - -/******************************************************************************* - Start of code based on MUSL -*******************************************************************************/ -/* -musl as a whole is licensed under the following standard MIT license: - ----------------------------------------------------------------------- -Copyright © 2005-2014 Rich Felker, et al. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- -*/ - -/* fpclassify */ - -__CRT_INLINE int __cdecl __fpclassify (double x) { - union {double f; uint64_t i;} u = {.f = x}; - int e = u.i>>52 & 0x7ff; - if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; - if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; - return FP_NORMAL; -} - -__CRT_INLINE int __cdecl __fpclassifyf (float x) { - union {float f; uint32_t i;} u = {.f = x}; - int e = u.i>>23 & 0xff; - if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; - if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; - return FP_NORMAL; -} - -__CRT_INLINE int __cdecl __fpclassifyl (long double x) { - return __fpclassify(x); -} - - -/* signbit */ - -__CRT_INLINE int __cdecl __signbit (double x) { - union {double f; uint64_t i;} u = {.f = x}; - return u.i>>63; -} - -__CRT_INLINE int __cdecl __signbitf (float x) { - union {float f; uint32_t i; } u = {.f = x}; - return u.i>>31; -} - -__CRT_INLINE int __cdecl __signbitl (long double x) { - return __signbit(x); -} - - -/* fmin*, fmax* */ - -#define TCCFP_FMIN_EVAL (isnan(x) ? y : \ - isnan(y) ? x : \ - (signbit(x) != signbit(y)) ? (signbit(x) ? x : y) : \ - x < y ? x : y) - -__CRT_INLINE double __cdecl fmin (double x, double y) { - return TCCFP_FMIN_EVAL; -} - -__CRT_INLINE float __cdecl fminf (float x, float y) { - return TCCFP_FMIN_EVAL; -} - -__CRT_INLINE long double __cdecl fminl (long double x, long double y) { - return TCCFP_FMIN_EVAL; -} - -#define TCCFP_FMAX_EVAL (isnan(x) ? y : \ - isnan(y) ? x : \ - (signbit(x) != signbit(y)) ? (signbit(x) ? y : x) : \ - x < y ? y : x) - -__CRT_INLINE double __cdecl fmax (double x, double y) { - return TCCFP_FMAX_EVAL; -} - -__CRT_INLINE float __cdecl fmaxf (float x, float y) { - return TCCFP_FMAX_EVAL; -} - -__CRT_INLINE long double __cdecl fmaxl (long double x, long double y) { - return TCCFP_FMAX_EVAL; -} - - -/* *round* */ - -#define TCCFP_FORCE_EVAL(x) do { \ - volatile typeof(x) __x; \ - __x = (x); \ -} while(0) - -__CRT_INLINE double __cdecl round (double x) { - union {double f; uint64_t i;} u = {.f = x}; - int e = u.i >> 52 & 0x7ff; - double y; - - if (e >= 0x3ff+52) - return x; - if (u.i >> 63) - x = -x; - if (e < 0x3ff-1) { - /* raise inexact if x!=0 */ - TCCFP_FORCE_EVAL(x + 0x1p52); - return 0*u.f; - } - y = (double)(x + 0x1p52) - 0x1p52 - x; - y = y + x - (y > 0.5) + (y <= -0.5); /* branchless */ - return (u.i >> 63) ? -y : y; -} - -__CRT_INLINE long __cdecl lround (double x) { - return round(x); -} - -__CRT_INLINE long long __cdecl llround (double x) { - return round(x); -} - -__CRT_INLINE float __cdecl roundf (float x) { - return round(x); -} - -__CRT_INLINE long __cdecl lroundf (float x) { - return round(x); -} - -__CRT_INLINE long long __cdecl llroundf (float x) { - return round(x); -} - -__CRT_INLINE long double __cdecl roundl (long double x) { - return round(x); -} - -__CRT_INLINE long __cdecl lroundl (long double x) { - return round(x); -} - -__CRT_INLINE long long __cdecl llroundl (long double x) { - return round(x); -} - - -/* MUSL asinh, acosh, atanh */ - -__CRT_INLINE double __cdecl asinh(double x) { - union {double f; uint64_t i;} u = {.f = x}; - unsigned e = u.i >> 52 & 0x7ff, s = u.i >> 63; - u.i &= -1ull / 2, x = u.f; - if (e >= 0x3ff + 26) x = log(x) + 0.693147180559945309; - else if (e >= 0x3ff + 1) x = log(2*x + 1 / (sqrt(x*x + 1) + x)); /* |x|>=2 */ - else if (e >= 0x3ff - 26) x = log1p(x + x*x / (sqrt(x*x + 1) + 1)); - else TCCFP_FORCE_EVAL(x + 0x1p120f); - return s ? -x : x; -} - -__CRT_INLINE double __cdecl acosh(double x) { - union {double f; uint64_t i;} u = {.f = x}; - unsigned e = u.i >> 52 & 0x7ff; - if (e < 0x3ff + 1) return --x, log1p(x + sqrt(x*x + 2*x)); /* |x|<2 */ - if (e < 0x3ff + 26) return log(2*x - 1 / (x + sqrt(x*x - 1))); - return log(x) + 0.693147180559945309; -} - -__CRT_INLINE double __cdecl atanh(double x) { - union {double f; uint64_t i;} u = {.f = x}; - unsigned e = u.i >> 52 & 0x7ff, s = u.i >> 63; - u.i &= -1ull / 2, x = u.f; - if (e < 0x3ff - 1) { - if (e < 0x3ff - 32) { if (e == 0) TCCFP_FORCE_EVAL((float)x); } - else x = 0.5 * log1p(2*x + 2*x*x / (1 - x)); /* |x| < 0.5 */ - } else x = 0.5 * log1p(2*(x / (1 - x))); /* avoid overflow */ - return s ? -x : x; -} - -/* MUSL scalbn */ - -__CRT_INLINE double __cdecl scalbn(double x, int n) { - union {double f; uint64_t i;} u; - if (n > 1023) { - x *= 0x1p1023, n -= 1023; - if (n > 1023) { - x *= 0x1p1023, n -= 1023; - if (n > 1023) n = 1023; - } - } else if (n < -1022) { - x *= 0x1p-1022 * 0x1p53, n += 1022 - 53; - if (n < -1022) { - x *= 0x1p-1022 * 0x1p53, n += 1022 - 53; - if (n < -1022) n = -1022; - } - } - u.i = (0x3ffull + n) << 52; - return x * u.f; -} - -/* MUSL: Override msvcrt frexp(): 4.5x speedup! */ - -__CRT_INLINE double __cdecl frexp(double x, int *e) { - union {double f; uint64_t i;} u = {.f = x}; - int ee = u.i>>52 & 0x7ff; - if (!ee) { - if (x) x = frexp(x*0x1p64, e), *e -= 64; - else *e = 0; - return x; - } else if (ee == 0x7ff) - return x; - *e = ee - 0x3fe; - u.i &= 0x800fffffffffffffull; - u.i |= 0x3fe0000000000000ull; - return u.f; -} - -/* MUSL nan */ - -__CRT_INLINE double __cdecl nan(const char* s) { - return NAN; -} -__CRT_INLINE float __cdecl nanf(const char* s) { - return NAN; -} -__CRT_INLINE long double __cdecl nanl(const char* s) { - return NAN; -} - - -/******************************************************************************* - End of code based on MUSL -*******************************************************************************/ - - -/* Following are math functions missing from msvcrt.dll, and not defined - * in math.h or above. Functions still remaining: - * remquo(), remainder(), fma(), erf(), erfc(), nearbyint(). - * In : lldiv(). - */ - -__CRT_INLINE float __cdecl scalbnf(float x, int n) { - return scalbn(x, n); -} -__CRT_INLINE long double __cdecl scalbnl(long double x, int n) { - return scalbn(x, n); -} - -__CRT_INLINE double __cdecl scalbln(double x, long n) { - return scalbn(x, n); -} -__CRT_INLINE float __cdecl scalblnf(float x, long n) { - return scalbn(x, n); -} -__CRT_INLINE long double __cdecl scalblnl(long double x, long n) { - return scalbn(x, n); -} - -/* Override msvcrt ldexp(): 7.3x speedup! */ - -__CRT_INLINE double __cdecl ldexp(double x, int expn) { - return scalbn(x, expn); -} -__CRT_INLINE float __cdecl ldexpf(float x, int expn) { - return scalbn(x, expn); -} -__CRT_INLINE long double __cdecl ldexpl(long double x, int expn) { - return scalbn(x, expn); -} - -__CRT_INLINE float __cdecl frexpf(float x, int *y) { - return frexp(x, y); -} -__CRT_INLINE long double __cdecl frexpl (long double x, int* y) { - return frexp(x, y); -} - - -__CRT_INLINE double __cdecl rint(double x) { -double retval; - __asm__ ( - "fldl %1\n" - "frndint \n" - "fstpl %0\n" : "=m" (retval) : "m" (x)); - return retval; -} - -__CRT_INLINE float __cdecl rintf(float x) { - float retval; - __asm__ ( - "flds %1\n" - "frndint \n" - "fstps %0\n" : "=m" (retval) : "m" (x)); - return retval; -} -__CRT_INLINE long double __cdecl rintl (long double x) { - return rint(x); -} - - -/* 7.12.9.5 */ -__CRT_INLINE long __cdecl lrint(double x) { - long retval; - __asm__ __volatile__ - ("fldl %1\n" - "fistpl %0" : "=m" (retval) : "m" (x)); - return retval; -} - -__CRT_INLINE long __cdecl lrintf(float x) { - long retval; - __asm__ __volatile__ - ("flds %1\n" - "fistpl %0" : "=m" (retval) : "m" (x)); - return retval; -} - -__CRT_INLINE long __cdecl lrintl (long double x) { - return lrint(x); -} - - -__CRT_INLINE long long __cdecl llrint(double x) { -long long retval; - __asm__ __volatile__ - ("fldl %1\n" - "fistpll %0" : "=m" (retval) : "m" (x)); - return retval; -} - -__CRT_INLINE long long __cdecl llrintf(float x) { - long long retval; - __asm__ __volatile__ - ("flds %1\n" - "fistpll %0" : "=m" (retval) : "m" (x)); - return retval; -} - -__CRT_INLINE long long __cdecl llrintl (long double x) { - return llrint(x); -} - - -__CRT_INLINE double __cdecl trunc(double _x) { - double retval; - unsigned short saved_cw; - unsigned short tmp_cw; - __asm__ ("fnstcw %0;" : "=m" (saved_cw)); /* save FPU control word */ - tmp_cw = (saved_cw & ~(FE_TONEAREST | FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO)) - | FE_TOWARDZERO; - __asm__ ("fldcw %0;" : : "m" (tmp_cw)); - __asm__ ("fldl %1;" - "frndint;" - "fstpl %0;" : "=m" (retval) : "m" (_x)); /* round towards zero */ - __asm__ ("fldcw %0;" : : "m" (saved_cw) ); /* restore saved control word */ - return retval; -} - -__CRT_INLINE float __cdecl truncf(float x) { - return (float) ((intptr_t) x); -} -__CRT_INLINE long double __cdecl truncl(long double x) { - return trunc(x); -} - - -__CRT_INLINE long double __cdecl nextafterl(long double x, long double to) { - return nextafter(x, to); -} - -__CRT_INLINE double __cdecl nexttoward(double x, long double to) { - return nextafter(x, to); -} -__CRT_INLINE float __cdecl nexttowardf(float x, long double to) { - return nextafterf(x, to); -} -__CRT_INLINE long double __cdecl nexttowardl(long double x, long double to) { - return nextafter(x, to); -} - -/* Override msvcrt fabs(): 6.3x speedup! */ - -__CRT_INLINE double __cdecl fabs(double x) { - return x < 0 ? -x : x; -} -__CRT_INLINE float __cdecl fabsf(float x) { - return x < 0 ? -x : x; -} -__CRT_INLINE long double __cdecl fabsl(long double x) { - return x < 0 ? -x : x; -} - - -#if defined(_WIN32) && !defined(_WIN64) && !defined(__ia64__) - __CRT_INLINE float acosf(float x) { return acos(x); } - __CRT_INLINE float asinf(float x) { return asin(x); } - __CRT_INLINE float atanf(float x) { return atan(x); } - __CRT_INLINE float atan2f(float x, float y) { return atan2(x, y); } - __CRT_INLINE float ceilf(float x) { return ceil(x); } - __CRT_INLINE float cosf(float x) { return cos(x); } - __CRT_INLINE float coshf(float x) { return cosh(x); } - __CRT_INLINE float expf(float x) { return exp(x); } - __CRT_INLINE float floorf(float x) { return floor(x); } - __CRT_INLINE float fmodf(float x, float y) { return fmod(x, y); } - __CRT_INLINE float logf(float x) { return log(x); } - __CRT_INLINE float logbf(float x) { return logb(x); } - __CRT_INLINE float log10f(float x) { return log10(x); } - __CRT_INLINE float modff(float x, float *y) { double di, df = modf(x, &di); *y = di; return df; } - __CRT_INLINE float powf(float x, float y) { return pow(x, y); } - __CRT_INLINE float sinf(float x) { return sin(x); } - __CRT_INLINE float sinhf(float x) { return sinh(x); } - __CRT_INLINE float sqrtf(float x) { return sqrt(x); } - __CRT_INLINE float tanf(float x) { return tan(x); } - __CRT_INLINE float tanhf(float x) { return tanh(x); } -#endif -__CRT_INLINE float __cdecl asinhf(float x) { return asinh(x); } -__CRT_INLINE float __cdecl acoshf(float x) { return acosh(x); } -__CRT_INLINE float __cdecl atanhf(float x) { return atanh(x); } - -__CRT_INLINE long double __cdecl asinhl(long double x) { return asinh(x); } -__CRT_INLINE long double __cdecl acoshl(long double x) { return acosh(x); } -__CRT_INLINE long double __cdecl atanhl(long double x) { return atanh(x); } -__CRT_INLINE long double __cdecl asinl(long double x) { return asin(x); } -__CRT_INLINE long double __cdecl acosl(long double x) { return acos(x); } -__CRT_INLINE long double __cdecl atanl(long double x) { return atan(x); } -__CRT_INLINE long double __cdecl ceill(long double x) { return ceil(x); } -__CRT_INLINE long double __cdecl coshl(long double x) { return cosh(x); } -__CRT_INLINE long double __cdecl cosl(long double x) { return cos(x); } -__CRT_INLINE long double __cdecl expl(long double x) { return exp(x); } -__CRT_INLINE long double __cdecl floorl(long double x) { return floor(x); } -__CRT_INLINE long double __cdecl fmodl(long double x, long double y) { return fmod(x, y); } -__CRT_INLINE long double __cdecl hypotl(long double x, long double y) { return hypot(x, y); } -__CRT_INLINE long double __cdecl logl(long double x) { return log(x); } -__CRT_INLINE long double __cdecl logbl(long double x) { return logb(x); } -__CRT_INLINE long double __cdecl log10l(long double x) { return log10(x); } -__CRT_INLINE long double __cdecl modfl(long double x, long double* y) { double y1 = *y; x = modf(x, &y1); *y = y1; return x; } -__CRT_INLINE long double __cdecl powl(long double x, long double y) { return pow(x, y); } -__CRT_INLINE long double __cdecl sinhl(long double x) { return sinh(x); } -__CRT_INLINE long double __cdecl sinl(long double x) { return sin(x); } -__CRT_INLINE long double __cdecl sqrtl(long double x) { return sqrt(x); } -__CRT_INLINE long double __cdecl tanhl(long double x) { return tanh(x); } -__CRT_INLINE long double __cdecl tanl(long double x) { return tan(x); } - -/* Following are accurate, but much shorter implementations than MUSL lib. */ - -__CRT_INLINE double __cdecl log1p(double x) { - double u = 1.0 + x; - return u == 1.0 ? x : log(u)*(x / (u - 1.0)); -} -__CRT_INLINE float __cdecl log1pf(float x) { - float u = 1.0f + x; - return u == 1.0f ? x : logf(u)*(x / (u - 1.0f)); -} -__CRT_INLINE long double __cdecl log1pl(long double x) { - return log1p(x); -} - - -__CRT_INLINE double __cdecl expm1(double x) { - if (x > 0.0024 || x < -0.0024) return exp(x) - 1.0; - return x*(1.0 + 0.5*x*(1.0 + (1/3.0)*x*(1.0 + 0.25*x*(1.0 + 0.2*x)))); -} -__CRT_INLINE float __cdecl expm1f(float x) { - if (x > 0.085f || x < -0.085f) return expf(x) - 1.0f; - return x*(1.0f + 0.5f*x*(1.0f + (1/3.0f)*x*(1.0f + 0.25f*x))); -} -__CRT_INLINE long double __cdecl expm1l(long double x) { - return expm1(x); -} - - -__CRT_INLINE double __cdecl cbrt(double x) { - return x < 0.0 ? -pow(-x, 1/3.0) : pow(x, 1/3.0); -} -__CRT_INLINE float __cdecl cbrtf(float x) { - return x < 0.0f ? -pow(-x, 1/3.0) : pow(x, 1/3.0); -} -__CRT_INLINE long double __cdecl cbrtl(long double x) { - return cbrt(x); -} - - -__CRT_INLINE double __cdecl log2(double x) { - return log(x) * 1.442695040888963407; -} -__CRT_INLINE float __cdecl log2f(float x) { - return log(x) * 1.442695040888963407; -} -__CRT_INLINE long double __cdecl log2l(long double x) { - return log(x) * 1.442695040888963407; -} - - -__CRT_INLINE double __cdecl exp2(double x) { - return exp(x * 0.693147180559945309); -} -__CRT_INLINE float __cdecl exp2f(float x) { - return exp(x * 0.693147180559945309); -} -__CRT_INLINE long double __cdecl exp2l(long double x) { - return exp(x * 0.693147180559945309); -} - - -__CRT_INLINE int __cdecl ilogb(double x) { - return (int) logb(x); -} -__CRT_INLINE int __cdecl ilogbf(float x) { - return (int) logbf(x); -} -__CRT_INLINE int __cdecl ilogbl(long double x) { - return (int) logb(x); -} - - -__CRT_INLINE double __cdecl fdim(double x, double y) { - if (isnan(x) || isnan(y)) return NAN; - return x > y ? x - y : 0; -} -__CRT_INLINE float __cdecl fdimf(float x, float y) { - if (isnan(x) || isnan(y)) return NAN; - return x > y ? x - y : 0; -} -__CRT_INLINE long double __cdecl fdiml(long double x, long double y) { - if (isnan(x) || isnan(y)) return NAN; - return x > y ? x - y : 0; -} - - -/* tgamma and lgamma: Lanczos approximation - * https://rosettacode.org/wiki/Gamma_function - * https://www.johndcook.com/blog/cpp_gamma - */ - -__CRT_INLINE double __cdecl tgamma(double x) { - double m = 1.0, t = 3.14159265358979323; - if (x == floor(x)) { - if (x == 0) return INFINITY; - if (x < 0) return NAN; - if (x < 26) { for (double k = 2; k < x; ++k) m *= k; return m; } - } - if (x < 0.5) - return t / (sin(t*x)*tgamma(1.0 - x)); - if (x > 12.0) - return exp(lgamma(x)); - - static const double c[8] = {676.5203681218851, -1259.1392167224028, - 771.32342877765313, -176.61502916214059, - 12.507343278686905, -0.13857109526572012, - 9.9843695780195716e-6, 1.5056327351493116e-7}; - m = 0.99999999999980993, t = x + 6.5; /* x-1+8-.5 */ - for (int k = 0; k < 8; ++k) m += c[k] / (x + k); - return 2.50662827463100050 * pow(t, x - 0.5)*exp(-t)*m; /* C=sqrt(2pi) */ -} - - -__CRT_INLINE double __cdecl lgamma(double x) { - if (x < 12.0) { - if (x <= 0.0 && x == floor(x)) return INFINITY; - x = tgamma(x); - return log(x < 0.0 ? -x : x); - } - static const double c[7] = {1.0/12.0, -1.0/360.0, 1.0/1260.0, -1.0/1680.0, - 1.0/1188.0, -691.0/360360.0, 1.0/156.0}; - double m = -3617.0/122400.0, t = 1.0 / (x*x); - for (int k = 6; k >= 0; --k) m = m*t + c[k]; - return (x - 0.5)*log(x) - x + 0.918938533204672742 + m / x; /* C=log(2pi)/2 */ -} - -__CRT_INLINE float __cdecl tgammaf(float x) { - return tgamma(x); -} -__CRT_INLINE float __cdecl lgammaf(float x) { - return lgamma(x); -} -__CRT_INLINE long double __cdecl tgammal(long double x) { - return tgamma(x); -} -__CRT_INLINE long double __cdecl lgammal(long double x) { - return lgamma(x); -} - -#endif /* _TCC_LIBM_H_ */ +#ifndef _TCC_LIBM_H_ +#define _TCC_LIBM_H_ + +#include "../math.h" +#include "../stdint.h" + +/* TCC uses 8 bytes for double and long double, so effectively the l variants + * are never used. For now, they just run the normal (double) variant. + */ + +/* + * most of the code in this file is taken from MUSL rs-1.0 (MIT license) + * - musl-libc: http://git.musl-libc.org/cgit/musl/tree/src/math?h=rs-1.0 + * - License: http://git.musl-libc.org/cgit/musl/tree/COPYRIGHT?h=rs-1.0 + */ + +/******************************************************************************* + Start of code based on MUSL +*******************************************************************************/ +/* +musl as a whole is licensed under the following standard MIT license: + +---------------------------------------------------------------------- +Copyright © 2005-2014 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------- +*/ + +/* fpclassify */ + +__CRT_INLINE int __cdecl __fpclassify (double x) { + union {double f; uint64_t i;} u = {.f = x}; + int e = u.i>>52 & 0x7ff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} + +__CRT_INLINE int __cdecl __fpclassifyf (float x) { + union {float f; uint32_t i;} u = {.f = x}; + int e = u.i>>23 & 0xff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} + +__CRT_INLINE int __cdecl __fpclassifyl (long double x) { + return __fpclassify(x); +} + + +/* signbit */ + +__CRT_INLINE int __cdecl __signbit (double x) { + union {double f; uint64_t i;} u = {.f = x}; + return u.i>>63; +} + +__CRT_INLINE int __cdecl __signbitf (float x) { + union {float f; uint32_t i; } u = {.f = x}; + return u.i>>31; +} + +__CRT_INLINE int __cdecl __signbitl (long double x) { + return __signbit(x); +} + + +/* fmin*, fmax* */ + +#define TCCFP_FMIN_EVAL (isnan(x) ? y : \ + isnan(y) ? x : \ + (signbit(x) != signbit(y)) ? (signbit(x) ? x : y) : \ + x < y ? x : y) + +__CRT_INLINE double __cdecl fmin (double x, double y) { + return TCCFP_FMIN_EVAL; +} + +__CRT_INLINE float __cdecl fminf (float x, float y) { + return TCCFP_FMIN_EVAL; +} + +__CRT_INLINE long double __cdecl fminl (long double x, long double y) { + return TCCFP_FMIN_EVAL; +} + +#define TCCFP_FMAX_EVAL (isnan(x) ? y : \ + isnan(y) ? x : \ + (signbit(x) != signbit(y)) ? (signbit(x) ? y : x) : \ + x < y ? y : x) + +__CRT_INLINE double __cdecl fmax (double x, double y) { + return TCCFP_FMAX_EVAL; +} + +__CRT_INLINE float __cdecl fmaxf (float x, float y) { + return TCCFP_FMAX_EVAL; +} + +__CRT_INLINE long double __cdecl fmaxl (long double x, long double y) { + return TCCFP_FMAX_EVAL; +} + + +/* *round* */ + +#define TCCFP_FORCE_EVAL(x) do { \ + volatile typeof(x) __x; \ + __x = (x); \ +} while(0) + +__CRT_INLINE double __cdecl round (double x) { + union {double f; uint64_t i;} u = {.f = x}; + int e = u.i >> 52 & 0x7ff; + double y; + + if (e >= 0x3ff+52) + return x; + if (u.i >> 63) + x = -x; + if (e < 0x3ff-1) { + /* raise inexact if x!=0 */ + TCCFP_FORCE_EVAL(x + 0x1p52); + return 0*u.f; + } + y = (double)(x + 0x1p52) - 0x1p52 - x; + y = y + x - (y > 0.5) + (y <= -0.5); /* branchless */ + return (u.i >> 63) ? -y : y; +} + +__CRT_INLINE long __cdecl lround (double x) { + return round(x); +} + +__CRT_INLINE long long __cdecl llround (double x) { + return round(x); +} + +__CRT_INLINE float __cdecl roundf (float x) { + return round(x); +} + +__CRT_INLINE long __cdecl lroundf (float x) { + return round(x); +} + +__CRT_INLINE long long __cdecl llroundf (float x) { + return round(x); +} + +__CRT_INLINE long double __cdecl roundl (long double x) { + return round(x); +} + +__CRT_INLINE long __cdecl lroundl (long double x) { + return round(x); +} + +__CRT_INLINE long long __cdecl llroundl (long double x) { + return round(x); +} + + +/* MUSL asinh, acosh, atanh */ + +__CRT_INLINE double __cdecl asinh(double x) { + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff, s = u.i >> 63; + u.i &= -1ull / 2, x = u.f; + if (e >= 0x3ff + 26) x = log(x) + 0.693147180559945309; + else if (e >= 0x3ff + 1) x = log(2*x + 1 / (sqrt(x*x + 1) + x)); /* |x|>=2 */ + else if (e >= 0x3ff - 26) x = log1p(x + x*x / (sqrt(x*x + 1) + 1)); + else TCCFP_FORCE_EVAL(x + 0x1p120f); + return s ? -x : x; +} + +__CRT_INLINE double __cdecl acosh(double x) { + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + if (e < 0x3ff + 1) return --x, log1p(x + sqrt(x*x + 2*x)); /* |x|<2 */ + if (e < 0x3ff + 26) return log(2*x - 1 / (x + sqrt(x*x - 1))); + return log(x) + 0.693147180559945309; +} + +__CRT_INLINE double __cdecl atanh(double x) { + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff, s = u.i >> 63; + u.i &= -1ull / 2, x = u.f; + if (e < 0x3ff - 1) { + if (e < 0x3ff - 32) { if (e == 0) TCCFP_FORCE_EVAL((float)x); } + else x = 0.5 * log1p(2*x + 2*x*x / (1 - x)); /* |x| < 0.5 */ + } else x = 0.5 * log1p(2*(x / (1 - x))); /* avoid overflow */ + return s ? -x : x; +} + +/* MUSL scalbn */ + +__CRT_INLINE double __cdecl scalbn(double x, int n) { + union {double f; uint64_t i;} u; + if (n > 1023) { + x *= 0x1p1023, n -= 1023; + if (n > 1023) { + x *= 0x1p1023, n -= 1023; + if (n > 1023) n = 1023; + } + } else if (n < -1022) { + x *= 0x1p-1022 * 0x1p53, n += 1022 - 53; + if (n < -1022) { + x *= 0x1p-1022 * 0x1p53, n += 1022 - 53; + if (n < -1022) n = -1022; + } + } + u.i = (0x3ffull + n) << 52; + return x * u.f; +} + +/* MUSL: Override msvcrt frexp(): 4.5x speedup! */ + +__CRT_INLINE double __cdecl frexp(double x, int *e) { + union {double f; uint64_t i;} u = {.f = x}; + int ee = u.i>>52 & 0x7ff; + if (!ee) { + if (x) x = frexp(x*0x1p64, e), *e -= 64; + else *e = 0; + return x; + } else if (ee == 0x7ff) + return x; + *e = ee - 0x3fe; + u.i &= 0x800fffffffffffffull; + u.i |= 0x3fe0000000000000ull; + return u.f; +} + +/* MUSL nan */ + +__CRT_INLINE double __cdecl nan(const char* s) { + return NAN; +} +__CRT_INLINE float __cdecl nanf(const char* s) { + return NAN; +} +__CRT_INLINE long double __cdecl nanl(const char* s) { + return NAN; +} + + +/******************************************************************************* + End of code based on MUSL +*******************************************************************************/ + + +/* Following are math functions missing from msvcrt.dll, and not defined + * in math.h or above. Functions still remaining: + * remquo(), remainder(), fma(), erf(), erfc(), nearbyint(). + * In : lldiv(). + */ + +__CRT_INLINE float __cdecl scalbnf(float x, int n) { + return scalbn(x, n); +} +__CRT_INLINE long double __cdecl scalbnl(long double x, int n) { + return scalbn(x, n); +} + +__CRT_INLINE double __cdecl scalbln(double x, long n) { + return scalbn(x, n); +} +__CRT_INLINE float __cdecl scalblnf(float x, long n) { + return scalbn(x, n); +} +__CRT_INLINE long double __cdecl scalblnl(long double x, long n) { + return scalbn(x, n); +} + +/* Override msvcrt ldexp(): 7.3x speedup! */ + +__CRT_INLINE double __cdecl ldexp(double x, int expn) { + return scalbn(x, expn); +} +__CRT_INLINE float __cdecl ldexpf(float x, int expn) { + return scalbn(x, expn); +} +__CRT_INLINE long double __cdecl ldexpl(long double x, int expn) { + return scalbn(x, expn); +} + +__CRT_INLINE float __cdecl frexpf(float x, int *y) { + return frexp(x, y); +} +__CRT_INLINE long double __cdecl frexpl (long double x, int* y) { + return frexp(x, y); +} + + +__CRT_INLINE double __cdecl rint(double x) { +double retval; + __asm__ ( + "fldl %1\n" + "frndint \n" + "fstpl %0\n" : "=m" (retval) : "m" (x)); + return retval; +} + +__CRT_INLINE float __cdecl rintf(float x) { + float retval; + __asm__ ( + "flds %1\n" + "frndint \n" + "fstps %0\n" : "=m" (retval) : "m" (x)); + return retval; +} +__CRT_INLINE long double __cdecl rintl (long double x) { + return rint(x); +} + + +/* 7.12.9.5 */ +__CRT_INLINE long __cdecl lrint(double x) { + long retval; + __asm__ __volatile__ + ("fldl %1\n" + "fistpl %0" : "=m" (retval) : "m" (x)); + return retval; +} + +__CRT_INLINE long __cdecl lrintf(float x) { + long retval; + __asm__ __volatile__ + ("flds %1\n" + "fistpl %0" : "=m" (retval) : "m" (x)); + return retval; +} + +__CRT_INLINE long __cdecl lrintl (long double x) { + return lrint(x); +} + + +__CRT_INLINE long long __cdecl llrint(double x) { +long long retval; + __asm__ __volatile__ + ("fldl %1\n" + "fistpll %0" : "=m" (retval) : "m" (x)); + return retval; +} + +__CRT_INLINE long long __cdecl llrintf(float x) { + long long retval; + __asm__ __volatile__ + ("flds %1\n" + "fistpll %0" : "=m" (retval) : "m" (x)); + return retval; +} + +__CRT_INLINE long long __cdecl llrintl (long double x) { + return llrint(x); +} + + +__CRT_INLINE double __cdecl trunc(double _x) { + double retval; + unsigned short saved_cw; + unsigned short tmp_cw; + __asm__ ("fnstcw %0;" : "=m" (saved_cw)); /* save FPU control word */ + tmp_cw = (saved_cw & ~(FE_TONEAREST | FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO)) + | FE_TOWARDZERO; + __asm__ ("fldcw %0;" : : "m" (tmp_cw)); + __asm__ ("fldl %1;" + "frndint;" + "fstpl %0;" : "=m" (retval) : "m" (_x)); /* round towards zero */ + __asm__ ("fldcw %0;" : : "m" (saved_cw) ); /* restore saved control word */ + return retval; +} + +__CRT_INLINE float __cdecl truncf(float x) { + return (float) ((intptr_t) x); +} +__CRT_INLINE long double __cdecl truncl(long double x) { + return trunc(x); +} + + +__CRT_INLINE long double __cdecl nextafterl(long double x, long double to) { + return nextafter(x, to); +} + +__CRT_INLINE double __cdecl nexttoward(double x, long double to) { + return nextafter(x, to); +} +__CRT_INLINE float __cdecl nexttowardf(float x, long double to) { + return nextafterf(x, to); +} +__CRT_INLINE long double __cdecl nexttowardl(long double x, long double to) { + return nextafter(x, to); +} + +/* Override msvcrt fabs(): 6.3x speedup! */ + +__CRT_INLINE double __cdecl fabs(double x) { + return x < 0 ? -x : x; +} +__CRT_INLINE float __cdecl fabsf(float x) { + return x < 0 ? -x : x; +} +__CRT_INLINE long double __cdecl fabsl(long double x) { + return x < 0 ? -x : x; +} + + +#if defined(_WIN32) && !defined(_WIN64) && !defined(__ia64__) + __CRT_INLINE float acosf(float x) { return acos(x); } + __CRT_INLINE float asinf(float x) { return asin(x); } + __CRT_INLINE float atanf(float x) { return atan(x); } + __CRT_INLINE float atan2f(float x, float y) { return atan2(x, y); } + __CRT_INLINE float ceilf(float x) { return ceil(x); } + __CRT_INLINE float cosf(float x) { return cos(x); } + __CRT_INLINE float coshf(float x) { return cosh(x); } + __CRT_INLINE float expf(float x) { return exp(x); } + __CRT_INLINE float floorf(float x) { return floor(x); } + __CRT_INLINE float fmodf(float x, float y) { return fmod(x, y); } + __CRT_INLINE float logf(float x) { return log(x); } + __CRT_INLINE float logbf(float x) { return logb(x); } + __CRT_INLINE float log10f(float x) { return log10(x); } + __CRT_INLINE float modff(float x, float *y) { double di, df = modf(x, &di); *y = di; return df; } + __CRT_INLINE float powf(float x, float y) { return pow(x, y); } + __CRT_INLINE float sinf(float x) { return sin(x); } + __CRT_INLINE float sinhf(float x) { return sinh(x); } + __CRT_INLINE float sqrtf(float x) { return sqrt(x); } + __CRT_INLINE float tanf(float x) { return tan(x); } + __CRT_INLINE float tanhf(float x) { return tanh(x); } +#endif +__CRT_INLINE float __cdecl asinhf(float x) { return asinh(x); } +__CRT_INLINE float __cdecl acoshf(float x) { return acosh(x); } +__CRT_INLINE float __cdecl atanhf(float x) { return atanh(x); } + +__CRT_INLINE long double __cdecl asinhl(long double x) { return asinh(x); } +__CRT_INLINE long double __cdecl acoshl(long double x) { return acosh(x); } +__CRT_INLINE long double __cdecl atanhl(long double x) { return atanh(x); } +__CRT_INLINE long double __cdecl asinl(long double x) { return asin(x); } +__CRT_INLINE long double __cdecl acosl(long double x) { return acos(x); } +__CRT_INLINE long double __cdecl atanl(long double x) { return atan(x); } +__CRT_INLINE long double __cdecl ceill(long double x) { return ceil(x); } +__CRT_INLINE long double __cdecl coshl(long double x) { return cosh(x); } +__CRT_INLINE long double __cdecl cosl(long double x) { return cos(x); } +__CRT_INLINE long double __cdecl expl(long double x) { return exp(x); } +__CRT_INLINE long double __cdecl floorl(long double x) { return floor(x); } +__CRT_INLINE long double __cdecl fmodl(long double x, long double y) { return fmod(x, y); } +__CRT_INLINE long double __cdecl hypotl(long double x, long double y) { return hypot(x, y); } +__CRT_INLINE long double __cdecl logl(long double x) { return log(x); } +__CRT_INLINE long double __cdecl logbl(long double x) { return logb(x); } +__CRT_INLINE long double __cdecl log10l(long double x) { return log10(x); } +__CRT_INLINE long double __cdecl modfl(long double x, long double* y) { double y1 = *y; x = modf(x, &y1); *y = y1; return x; } +__CRT_INLINE long double __cdecl powl(long double x, long double y) { return pow(x, y); } +__CRT_INLINE long double __cdecl sinhl(long double x) { return sinh(x); } +__CRT_INLINE long double __cdecl sinl(long double x) { return sin(x); } +__CRT_INLINE long double __cdecl sqrtl(long double x) { return sqrt(x); } +__CRT_INLINE long double __cdecl tanhl(long double x) { return tanh(x); } +__CRT_INLINE long double __cdecl tanl(long double x) { return tan(x); } + +/* Following are accurate, but much shorter implementations than MUSL lib. */ + +__CRT_INLINE double __cdecl log1p(double x) { + double u = 1.0 + x; + return u == 1.0 ? x : log(u)*(x / (u - 1.0)); +} +__CRT_INLINE float __cdecl log1pf(float x) { + float u = 1.0f + x; + return u == 1.0f ? x : logf(u)*(x / (u - 1.0f)); +} +__CRT_INLINE long double __cdecl log1pl(long double x) { + return log1p(x); +} + + +__CRT_INLINE double __cdecl expm1(double x) { + if (x > 0.0024 || x < -0.0024) return exp(x) - 1.0; + return x*(1.0 + 0.5*x*(1.0 + (1/3.0)*x*(1.0 + 0.25*x*(1.0 + 0.2*x)))); +} +__CRT_INLINE float __cdecl expm1f(float x) { + if (x > 0.085f || x < -0.085f) return expf(x) - 1.0f; + return x*(1.0f + 0.5f*x*(1.0f + (1/3.0f)*x*(1.0f + 0.25f*x))); +} +__CRT_INLINE long double __cdecl expm1l(long double x) { + return expm1(x); +} + + +__CRT_INLINE double __cdecl cbrt(double x) { + return x < 0.0 ? -pow(-x, 1/3.0) : pow(x, 1/3.0); +} +__CRT_INLINE float __cdecl cbrtf(float x) { + return x < 0.0f ? -pow(-x, 1/3.0) : pow(x, 1/3.0); +} +__CRT_INLINE long double __cdecl cbrtl(long double x) { + return cbrt(x); +} + + +__CRT_INLINE double __cdecl log2(double x) { + return log(x) * 1.442695040888963407; +} +__CRT_INLINE float __cdecl log2f(float x) { + return log(x) * 1.442695040888963407; +} +__CRT_INLINE long double __cdecl log2l(long double x) { + return log(x) * 1.442695040888963407; +} + + +__CRT_INLINE double __cdecl exp2(double x) { + return exp(x * 0.693147180559945309); +} +__CRT_INLINE float __cdecl exp2f(float x) { + return exp(x * 0.693147180559945309); +} +__CRT_INLINE long double __cdecl exp2l(long double x) { + return exp(x * 0.693147180559945309); +} + + +__CRT_INLINE int __cdecl ilogb(double x) { + return (int) logb(x); +} +__CRT_INLINE int __cdecl ilogbf(float x) { + return (int) logbf(x); +} +__CRT_INLINE int __cdecl ilogbl(long double x) { + return (int) logb(x); +} + + +__CRT_INLINE double __cdecl fdim(double x, double y) { + if (isnan(x) || isnan(y)) return NAN; + return x > y ? x - y : 0; +} +__CRT_INLINE float __cdecl fdimf(float x, float y) { + if (isnan(x) || isnan(y)) return NAN; + return x > y ? x - y : 0; +} +__CRT_INLINE long double __cdecl fdiml(long double x, long double y) { + if (isnan(x) || isnan(y)) return NAN; + return x > y ? x - y : 0; +} + + +/* tgamma and lgamma: Lanczos approximation + * https://rosettacode.org/wiki/Gamma_function + * https://www.johndcook.com/blog/cpp_gamma + */ + +__CRT_INLINE double __cdecl tgamma(double x) { + double m = 1.0, t = 3.14159265358979323; + if (x == floor(x)) { + if (x == 0) return INFINITY; + if (x < 0) return NAN; + if (x < 26) { for (double k = 2; k < x; ++k) m *= k; return m; } + } + if (x < 0.5) + return t / (sin(t*x)*tgamma(1.0 - x)); + if (x > 12.0) + return exp(lgamma(x)); + + static const double c[8] = {676.5203681218851, -1259.1392167224028, + 771.32342877765313, -176.61502916214059, + 12.507343278686905, -0.13857109526572012, + 9.9843695780195716e-6, 1.5056327351493116e-7}; + m = 0.99999999999980993, t = x + 6.5; /* x-1+8-.5 */ + for (int k = 0; k < 8; ++k) m += c[k] / (x + k); + return 2.50662827463100050 * pow(t, x - 0.5)*exp(-t)*m; /* C=sqrt(2pi) */ +} + + +__CRT_INLINE double __cdecl lgamma(double x) { + if (x < 12.0) { + if (x <= 0.0 && x == floor(x)) return INFINITY; + x = tgamma(x); + return log(x < 0.0 ? -x : x); + } + static const double c[7] = {1.0/12.0, -1.0/360.0, 1.0/1260.0, -1.0/1680.0, + 1.0/1188.0, -691.0/360360.0, 1.0/156.0}; + double m = -3617.0/122400.0, t = 1.0 / (x*x); + for (int k = 6; k >= 0; --k) m = m*t + c[k]; + return (x - 0.5)*log(x) - x + 0.918938533204672742 + m / x; /* C=log(2pi)/2 */ +} + +__CRT_INLINE float __cdecl tgammaf(float x) { + return tgamma(x); +} +__CRT_INLINE float __cdecl lgammaf(float x) { + return lgamma(x); +} +__CRT_INLINE long double __cdecl tgammal(long double x) { + return tgamma(x); +} +__CRT_INLINE long double __cdecl lgammal(long double x) { + return lgamma(x); +} + +#endif /* _TCC_LIBM_H_ */ diff --git a/tcc/include/tccdefs.h b/tcc/include/tccdefs.h index 79a71a23..ba2a679f 100644 --- a/tcc/include/tccdefs.h +++ b/tcc/include/tccdefs.h @@ -1,284 +1,284 @@ -/* tccdefs.h - - Nothing is defined before this file except target machine, target os - and the few things related to option settings in tccpp.c:tcc_predefs(). - - This file is either included at runtime as is, or converted and - included as C-strings at compile-time (depending on CONFIG_TCC_PREDEFS). - - Note that line indent matters: - - - in lines starting at column 1, platform macros are replaced by - corresponding TCC target compile-time macros. See conftest.c for - the list of platform macros supported in lines starting at column 1. - - - only lines indented >= 4 are actually included into the executable, - check tccdefs_.h. -*/ - -#if __SIZEOF_POINTER__ == 4 - /* 32bit systems. */ -#if defined TARGETOS_OpenBSD - #define __SIZE_TYPE__ unsigned long - #define __PTRDIFF_TYPE__ long -#else - #define __SIZE_TYPE__ unsigned int - #define __PTRDIFF_TYPE__ int -#endif - #define __ILP32__ 1 - #define __INT64_TYPE__ long long -#elif __SIZEOF_LONG__ == 4 - /* 64bit Windows. */ - #define __SIZE_TYPE__ unsigned long long - #define __PTRDIFF_TYPE__ long long - #define __LLP64__ 1 - #define __INT64_TYPE__ long long -#else - /* Other 64bit systems. */ - #define __SIZE_TYPE__ unsigned long - #define __PTRDIFF_TYPE__ long - #define __LP64__ 1 -# if defined __linux__ - #define __INT64_TYPE__ long -# else /* APPLE, BSD */ - #define __INT64_TYPE__ long long -# endif -#endif - #define __SIZEOF_INT__ 4 - #define __INT_MAX__ 0x7fffffff -#if __SIZEOF_LONG__ == 4 - #define __LONG_MAX__ 0x7fffffffL -#else - #define __LONG_MAX__ 0x7fffffffffffffffL -#endif - #define __SIZEOF_LONG_LONG__ 8 - #define __LONG_LONG_MAX__ 0x7fffffffffffffffLL - #define __CHAR_BIT__ 8 - #define __ORDER_LITTLE_ENDIAN__ 1234 - #define __ORDER_BIG_ENDIAN__ 4321 - #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ -#if defined _WIN32 - #define __WCHAR_TYPE__ unsigned short - #define __WINT_TYPE__ unsigned short -#elif defined __linux__ - #define __WCHAR_TYPE__ int - #define __WINT_TYPE__ unsigned int -#else - #define __WCHAR_TYPE__ int - #define __WINT_TYPE__ int -#endif - - #if __STDC_VERSION__ == 201112L - # define __STDC_NO_ATOMICS__ 1 - # define __STDC_NO_COMPLEX__ 1 - # define __STDC_NO_THREADS__ 1 -#if !defined _WIN32 - # define __STDC_UTF_16__ 1 - # define __STDC_UTF_32__ 1 -#endif - #endif - - #define __ATOMIC_RELAXED 0 - #define __ATOMIC_CONSUME 1 - #define __ATOMIC_ACQUIRE 2 - #define __ATOMIC_RELEASE 3 - #define __ATOMIC_ACQ_REL 4 - #define __ATOMIC_SEQ_CST 5 - -#if defined _WIN32 - #define __declspec(x) __attribute__((x)) - #define __cdecl - -#elif defined __FreeBSD__ - #define __GNUC__ 9 - #define __GNUC_MINOR__ 3 - #define __GNUC_PATCHLEVEL__ 0 - #define __GNUC_STDC_INLINE__ 1 - #define __NO_TLS 1 -# if __SIZEOF_POINTER__ == 8 - /* FIXME, __int128_t is used by setjump */ - #define __int128_t struct { unsigned char _dummy[16] __attribute((aligned(16))); } -# endif - -#elif defined __FreeBSD_kernel__ - -#elif defined __NetBSD__ - #define __GNUC__ 4 - #define __GNUC_MINOR__ 1 - #define __GNUC_PATCHLEVEL__ 0 - #define _Pragma(x) - #define __ELF__ 1 -#if defined __aarch64__ - #define _LOCORE /* avoids usage of __asm */ -#endif - -#elif defined __OpenBSD__ - #define __GNUC__ 4 - #define _ANSI_LIBRARY 1 - -#elif defined __APPLE__ - /* emulate APPLE-GCC to make libc's headerfiles compile: */ - #define __GNUC__ 4 /* darwin emits warning on GCC<4 */ - #define __APPLE_CC__ 1 /* for */ - #define _DONT_USE_CTYPE_INLINE_ 1 - /* avoids usage of GCC/clang specific builtins in libc-headerfiles: */ - #define __FINITE_MATH_ONLY__ 1 - #define _FORTIFY_SOURCE 0 - -#else - /* Linux */ - -#endif - -#if !defined _WIN32 - /* glibc defines */ - #define __REDIRECT(name, proto, alias) name proto __asm__ (#alias) - #define __REDIRECT_NTH(name, proto, alias) name proto __asm__ (#alias) __THROW -#endif - - /* skip __builtin... with -E */ - #ifndef __TCC_PP__ - - #define __builtin_offsetof(type, field) ((__SIZE_TYPE__)&((type*)0)->field) - #define __builtin_extract_return_addr(x) x -#if !defined __linux__ && !defined _WIN32 - /* used by math.h */ - #define __builtin_huge_val() 1e500 - #define __builtin_huge_valf() 1e50f - #define __builtin_huge_vall() 1e5000L -# if defined __APPLE__ - #define __builtin_nanf(ignored_string) __nan() - /* used by floats.h to implement FLT_ROUNDS C99 macro. 1 == to nearest */ - #define __builtin_flt_rounds() 1 - /* used by _fd_def.h */ - #define __builtin_bzero(p, ignored_size) bzero(p, sizeof(*(p))) -# else - #define __builtin_nanf(ignored_string) (0.0F/0.0F) -# endif -#endif - - /* __builtin_va_list */ -#if defined __x86_64__ -#if !defined _WIN32 - /* GCC compatible definition of va_list. */ - /* This should be in sync with the declaration in our lib/libtcc1.c */ - typedef struct { - unsigned gp_offset, fp_offset; - union { - unsigned overflow_offset; - char *overflow_arg_area; - }; - char *reg_save_area; - } __builtin_va_list[1]; - - void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align); - #define __builtin_va_start(ap, last) \ - (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) - #define __builtin_va_arg(ap, t) \ - (*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t)))) - #define __builtin_va_copy(dest, src) (*(dest) = *(src)) - -#else /* _WIN64 */ - typedef char *__builtin_va_list; - #define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \ - ? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8)) -#endif - -#elif defined __arm__ - typedef char *__builtin_va_list; - #define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x) - #define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \ - & ~(_tcc_alignof(type) - 1)) - #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) - #define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \ - &~3), *(type *)(ap - ((sizeof(type)+3)&~3))) - -#elif defined __aarch64__ - typedef struct { - void *__stack, *__gr_top, *__vr_top; - int __gr_offs, __vr_offs; - } __builtin_va_list; - -#elif defined __riscv - typedef char *__builtin_va_list; - #define __va_reg_size (__riscv_xlen >> 3) - #define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \ - & -(__alignof__(type))) - #define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size))))) - -#else /* __i386__ */ - typedef char *__builtin_va_list; - #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) - #define __builtin_va_arg(ap,t) (*(t*)((ap+=(sizeof(t)+3)&~3)-((sizeof(t)+3)&~3))) - -#endif - #define __builtin_va_end(ap) (void)(ap) - #ifndef __builtin_va_copy - # define __builtin_va_copy(dest, src) (dest) = (src) - #endif - - /* TCC BBUILTIN AND BOUNDS ALIASES */ - #ifdef __leading_underscore - # define __RENAME(X) __asm__("_"X) - #else - # define __RENAME(X) __asm__(X) - #endif - #ifdef __BOUNDS_CHECKING_ON - # define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME("__bound_"#name); - # define __BOUND(ret,name,params) ret name params __RENAME("__bound_"#name); - #else - # define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(#name); - # define __BOUND(ret,name,params) - #endif - #define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params) - #define __BUILTIN(ret,name,params) ret __builtin_##name params __RENAME(#name); - - __BOTH(void*, memcpy, (void *, const void*, __SIZE_TYPE__)) - __BOTH(void*, memmove, (void *, const void*, __SIZE_TYPE__)) - __BOTH(void*, memset, (void *, int, __SIZE_TYPE__)) - __BOTH(int, memcmp, (const void *, const void*, __SIZE_TYPE__)) - __BOTH(__SIZE_TYPE__, strlen, (const char *)) - __BOTH(char*, strcpy, (char *, const char *)) - __BOTH(char*, strncpy, (char *, const char*, __SIZE_TYPE__)) - __BOTH(int, strcmp, (const char*, const char*)) - __BOTH(int, strncmp, (const char*, const char*, __SIZE_TYPE__)) - __BOTH(char*, strcat, (char*, const char*)) - __BOTH(char*, strchr, (const char*, int)) - __BOTH(char*, strdup, (const char*)) -#if defined __ARM_EABI__ - __BOUND(void*,__aeabi_memcpy,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memmove,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memmove4,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memmove8,(void*,const void*,__SIZE_TYPE__)) - __BOUND(void*,__aeabi_memset,(void*,int,__SIZE_TYPE__)) -#endif - -#if defined __linux__ || defined __APPLE__ // HAVE MALLOC_REDIR - #define __MAYBE_REDIR __BUILTIN -#else - #define __MAYBE_REDIR __BOTH -#endif - __MAYBE_REDIR(void*, malloc, (__SIZE_TYPE__)) - __MAYBE_REDIR(void*, realloc, (void *, __SIZE_TYPE__)) - __MAYBE_REDIR(void*, calloc, (__SIZE_TYPE__, __SIZE_TYPE__)) - __MAYBE_REDIR(void*, memalign, (__SIZE_TYPE__, __SIZE_TYPE__)) - __MAYBE_REDIR(void, free, (void*)) -#if defined __i386__ || defined __x86_64__ - __BOTH(void*, alloca, (__SIZE_TYPE__)) -#else - __BUILTIN(void*, alloca, (__SIZE_TYPE__)) -#endif - __BUILTIN(void, abort, (void)) - __BOUND(void, longjmp, ()) -#if !defined _WIN32 - __BOUND(void*, mmap, ()) - __BOUND(int, munmap, ()) -#endif - #undef __BUILTINBC - #undef __BUILTIN - #undef __BOUND - #undef __BOTH - #undef __MAYBE_REDIR - #undef __RENAME - - #endif /* ndef __TCC_PP__ */ +/* tccdefs.h + + Nothing is defined before this file except target machine, target os + and the few things related to option settings in tccpp.c:tcc_predefs(). + + This file is either included at runtime as is, or converted and + included as C-strings at compile-time (depending on CONFIG_TCC_PREDEFS). + + Note that line indent matters: + + - in lines starting at column 1, platform macros are replaced by + corresponding TCC target compile-time macros. See conftest.c for + the list of platform macros supported in lines starting at column 1. + + - only lines indented >= 4 are actually included into the executable, + check tccdefs_.h. +*/ + +#if __SIZEOF_POINTER__ == 4 + /* 32bit systems. */ +#if defined TARGETOS_OpenBSD + #define __SIZE_TYPE__ unsigned long + #define __PTRDIFF_TYPE__ long +#else + #define __SIZE_TYPE__ unsigned int + #define __PTRDIFF_TYPE__ int +#endif + #define __ILP32__ 1 + #define __INT64_TYPE__ long long +#elif __SIZEOF_LONG__ == 4 + /* 64bit Windows. */ + #define __SIZE_TYPE__ unsigned long long + #define __PTRDIFF_TYPE__ long long + #define __LLP64__ 1 + #define __INT64_TYPE__ long long +#else + /* Other 64bit systems. */ + #define __SIZE_TYPE__ unsigned long + #define __PTRDIFF_TYPE__ long + #define __LP64__ 1 +# if defined __linux__ + #define __INT64_TYPE__ long +# else /* APPLE, BSD */ + #define __INT64_TYPE__ long long +# endif +#endif + #define __SIZEOF_INT__ 4 + #define __INT_MAX__ 0x7fffffff +#if __SIZEOF_LONG__ == 4 + #define __LONG_MAX__ 0x7fffffffL +#else + #define __LONG_MAX__ 0x7fffffffffffffffL +#endif + #define __SIZEOF_LONG_LONG__ 8 + #define __LONG_LONG_MAX__ 0x7fffffffffffffffLL + #define __CHAR_BIT__ 8 + #define __ORDER_LITTLE_ENDIAN__ 1234 + #define __ORDER_BIG_ENDIAN__ 4321 + #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#if defined _WIN32 + #define __WCHAR_TYPE__ unsigned short + #define __WINT_TYPE__ unsigned short +#elif defined __linux__ + #define __WCHAR_TYPE__ int + #define __WINT_TYPE__ unsigned int +#else + #define __WCHAR_TYPE__ int + #define __WINT_TYPE__ int +#endif + + #if __STDC_VERSION__ == 201112L + # define __STDC_NO_ATOMICS__ 1 + # define __STDC_NO_COMPLEX__ 1 + # define __STDC_NO_THREADS__ 1 +#if !defined _WIN32 + # define __STDC_UTF_16__ 1 + # define __STDC_UTF_32__ 1 +#endif + #endif + + #define __ATOMIC_RELAXED 0 + #define __ATOMIC_CONSUME 1 + #define __ATOMIC_ACQUIRE 2 + #define __ATOMIC_RELEASE 3 + #define __ATOMIC_ACQ_REL 4 + #define __ATOMIC_SEQ_CST 5 + +#if defined _WIN32 + #define __declspec(x) __attribute__((x)) + #define __cdecl + +#elif defined __FreeBSD__ + #define __GNUC__ 9 + #define __GNUC_MINOR__ 3 + #define __GNUC_PATCHLEVEL__ 0 + #define __GNUC_STDC_INLINE__ 1 + #define __NO_TLS 1 +# if __SIZEOF_POINTER__ == 8 + /* FIXME, __int128_t is used by setjump */ + #define __int128_t struct { unsigned char _dummy[16] __attribute((aligned(16))); } +# endif + +#elif defined __FreeBSD_kernel__ + +#elif defined __NetBSD__ + #define __GNUC__ 4 + #define __GNUC_MINOR__ 1 + #define __GNUC_PATCHLEVEL__ 0 + #define _Pragma(x) + #define __ELF__ 1 +#if defined __aarch64__ + #define _LOCORE /* avoids usage of __asm */ +#endif + +#elif defined __OpenBSD__ + #define __GNUC__ 4 + #define _ANSI_LIBRARY 1 + +#elif defined __APPLE__ + /* emulate APPLE-GCC to make libc's headerfiles compile: */ + #define __GNUC__ 4 /* darwin emits warning on GCC<4 */ + #define __APPLE_CC__ 1 /* for */ + #define _DONT_USE_CTYPE_INLINE_ 1 + /* avoids usage of GCC/clang specific builtins in libc-headerfiles: */ + #define __FINITE_MATH_ONLY__ 1 + #define _FORTIFY_SOURCE 0 + +#else + /* Linux */ + +#endif + +#if !defined _WIN32 + /* glibc defines */ + #define __REDIRECT(name, proto, alias) name proto __asm__ (#alias) + #define __REDIRECT_NTH(name, proto, alias) name proto __asm__ (#alias) __THROW +#endif + + /* skip __builtin... with -E */ + #ifndef __TCC_PP__ + + #define __builtin_offsetof(type, field) ((__SIZE_TYPE__)&((type*)0)->field) + #define __builtin_extract_return_addr(x) x +#if !defined __linux__ && !defined _WIN32 + /* used by math.h */ + #define __builtin_huge_val() 1e500 + #define __builtin_huge_valf() 1e50f + #define __builtin_huge_vall() 1e5000L +# if defined __APPLE__ + #define __builtin_nanf(ignored_string) __nan() + /* used by floats.h to implement FLT_ROUNDS C99 macro. 1 == to nearest */ + #define __builtin_flt_rounds() 1 + /* used by _fd_def.h */ + #define __builtin_bzero(p, ignored_size) bzero(p, sizeof(*(p))) +# else + #define __builtin_nanf(ignored_string) (0.0F/0.0F) +# endif +#endif + + /* __builtin_va_list */ +#if defined __x86_64__ +#if !defined _WIN32 + /* GCC compatible definition of va_list. */ + /* This should be in sync with the declaration in our lib/libtcc1.c */ + typedef struct { + unsigned gp_offset, fp_offset; + union { + unsigned overflow_offset; + char *overflow_arg_area; + }; + char *reg_save_area; + } __builtin_va_list[1]; + + void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align); + #define __builtin_va_start(ap, last) \ + (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24)) + #define __builtin_va_arg(ap, t) \ + (*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t)))) + #define __builtin_va_copy(dest, src) (*(dest) = *(src)) + +#else /* _WIN64 */ + typedef char *__builtin_va_list; + #define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \ + ? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8)) +#endif + +#elif defined __arm__ + typedef char *__builtin_va_list; + #define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x) + #define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \ + & ~(_tcc_alignof(type) - 1)) + #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) + #define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \ + &~3), *(type *)(ap - ((sizeof(type)+3)&~3))) + +#elif defined __aarch64__ + typedef struct { + void *__stack, *__gr_top, *__vr_top; + int __gr_offs, __vr_offs; + } __builtin_va_list; + +#elif defined __riscv + typedef char *__builtin_va_list; + #define __va_reg_size (__riscv_xlen >> 3) + #define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \ + & -(__alignof__(type))) + #define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size))))) + +#else /* __i386__ */ + typedef char *__builtin_va_list; + #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)) + #define __builtin_va_arg(ap,t) (*(t*)((ap+=(sizeof(t)+3)&~3)-((sizeof(t)+3)&~3))) + +#endif + #define __builtin_va_end(ap) (void)(ap) + #ifndef __builtin_va_copy + # define __builtin_va_copy(dest, src) (dest) = (src) + #endif + + /* TCC BBUILTIN AND BOUNDS ALIASES */ + #ifdef __leading_underscore + # define __RENAME(X) __asm__("_"X) + #else + # define __RENAME(X) __asm__(X) + #endif + #ifdef __BOUNDS_CHECKING_ON + # define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME("__bound_"#name); + # define __BOUND(ret,name,params) ret name params __RENAME("__bound_"#name); + #else + # define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(#name); + # define __BOUND(ret,name,params) + #endif + #define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params) + #define __BUILTIN(ret,name,params) ret __builtin_##name params __RENAME(#name); + + __BOTH(void*, memcpy, (void *, const void*, __SIZE_TYPE__)) + __BOTH(void*, memmove, (void *, const void*, __SIZE_TYPE__)) + __BOTH(void*, memset, (void *, int, __SIZE_TYPE__)) + __BOTH(int, memcmp, (const void *, const void*, __SIZE_TYPE__)) + __BOTH(__SIZE_TYPE__, strlen, (const char *)) + __BOTH(char*, strcpy, (char *, const char *)) + __BOTH(char*, strncpy, (char *, const char*, __SIZE_TYPE__)) + __BOTH(int, strcmp, (const char*, const char*)) + __BOTH(int, strncmp, (const char*, const char*, __SIZE_TYPE__)) + __BOTH(char*, strcat, (char*, const char*)) + __BOTH(char*, strchr, (const char*, int)) + __BOTH(char*, strdup, (const char*)) +#if defined __ARM_EABI__ + __BOUND(void*,__aeabi_memcpy,(void*,const void*,__SIZE_TYPE__)) + __BOUND(void*,__aeabi_memmove,(void*,const void*,__SIZE_TYPE__)) + __BOUND(void*,__aeabi_memmove4,(void*,const void*,__SIZE_TYPE__)) + __BOUND(void*,__aeabi_memmove8,(void*,const void*,__SIZE_TYPE__)) + __BOUND(void*,__aeabi_memset,(void*,int,__SIZE_TYPE__)) +#endif + +#if defined __linux__ || defined __APPLE__ // HAVE MALLOC_REDIR + #define __MAYBE_REDIR __BUILTIN +#else + #define __MAYBE_REDIR __BOTH +#endif + __MAYBE_REDIR(void*, malloc, (__SIZE_TYPE__)) + __MAYBE_REDIR(void*, realloc, (void *, __SIZE_TYPE__)) + __MAYBE_REDIR(void*, calloc, (__SIZE_TYPE__, __SIZE_TYPE__)) + __MAYBE_REDIR(void*, memalign, (__SIZE_TYPE__, __SIZE_TYPE__)) + __MAYBE_REDIR(void, free, (void*)) +#if defined __i386__ || defined __x86_64__ + __BOTH(void*, alloca, (__SIZE_TYPE__)) +#else + __BUILTIN(void*, alloca, (__SIZE_TYPE__)) +#endif + __BUILTIN(void, abort, (void)) + __BOUND(void, longjmp, ()) +#if !defined _WIN32 + __BOUND(void*, mmap, ()) + __BOUND(int, munmap, ()) +#endif + #undef __BUILTINBC + #undef __BUILTIN + #undef __BOUND + #undef __BOTH + #undef __MAYBE_REDIR + #undef __RENAME + + #endif /* ndef __TCC_PP__ */ diff --git a/tcc/include/tcclib.h b/tcc/include/tcclib.h index b1968a40..8d59e4c9 100644 --- a/tcc/include/tcclib.h +++ b/tcc/include/tcclib.h @@ -1,80 +1,80 @@ -/* Simple libc header for TCC - * - * Add any function you want from the libc there. This file is here - * only for your convenience so that you do not need to put the whole - * glibc include files on your floppy disk - */ -#ifndef _TCCLIB_H -#define _TCCLIB_H - -#include -#include - -/* stdlib.h */ -void *calloc(size_t nmemb, size_t size); -void *malloc(size_t size); -void free(void *ptr); -void *realloc(void *ptr, size_t size); -int atoi(const char *nptr); -long int strtol(const char *nptr, char **endptr, int base); -unsigned long int strtoul(const char *nptr, char **endptr, int base); -void exit(int); - -/* stdio.h */ -typedef struct __FILE FILE; -#define EOF (-1) -extern FILE *stdin; -extern FILE *stdout; -extern FILE *stderr; -FILE *fopen(const char *path, const char *mode); -FILE *fdopen(int fildes, const char *mode); -FILE *freopen(const char *path, const char *mode, FILE *stream); -int fclose(FILE *stream); -size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); -size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); -int fgetc(FILE *stream); -char *fgets(char *s, int size, FILE *stream); -int getc(FILE *stream); -int getchar(void); -char *gets(char *s); -int ungetc(int c, FILE *stream); -int fflush(FILE *stream); -int putchar (int c); - -int printf(const char *format, ...); -int fprintf(FILE *stream, const char *format, ...); -int sprintf(char *str, const char *format, ...); -int snprintf(char *str, size_t size, const char *format, ...); -int asprintf(char **strp, const char *format, ...); -int dprintf(int fd, const char *format, ...); -int vprintf(const char *format, va_list ap); -int vfprintf(FILE *stream, const char *format, va_list ap); -int vsprintf(char *str, const char *format, va_list ap); -int vsnprintf(char *str, size_t size, const char *format, va_list ap); -int vasprintf(char **strp, const char *format, va_list ap); -int vdprintf(int fd, const char *format, va_list ap); - -void perror(const char *s); - -/* string.h */ -char *strcat(char *dest, const char *src); -char *strchr(const char *s, int c); -char *strrchr(const char *s, int c); -char *strcpy(char *dest, const char *src); -void *memcpy(void *dest, const void *src, size_t n); -void *memmove(void *dest, const void *src, size_t n); -void *memset(void *s, int c, size_t n); -char *strdup(const char *s); -size_t strlen(const char *s); - -/* dlfcn.h */ -#define RTLD_LAZY 0x001 -#define RTLD_NOW 0x002 -#define RTLD_GLOBAL 0x100 - -void *dlopen(const char *filename, int flag); -const char *dlerror(void); -void *dlsym(void *handle, char *symbol); -int dlclose(void *handle); - -#endif /* _TCCLIB_H */ +/* Simple libc header for TCC + * + * Add any function you want from the libc there. This file is here + * only for your convenience so that you do not need to put the whole + * glibc include files on your floppy disk + */ +#ifndef _TCCLIB_H +#define _TCCLIB_H + +#include +#include + +/* stdlib.h */ +void *calloc(size_t nmemb, size_t size); +void *malloc(size_t size); +void free(void *ptr); +void *realloc(void *ptr, size_t size); +int atoi(const char *nptr); +long int strtol(const char *nptr, char **endptr, int base); +unsigned long int strtoul(const char *nptr, char **endptr, int base); +void exit(int); + +/* stdio.h */ +typedef struct __FILE FILE; +#define EOF (-1) +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; +FILE *fopen(const char *path, const char *mode); +FILE *fdopen(int fildes, const char *mode); +FILE *freopen(const char *path, const char *mode, FILE *stream); +int fclose(FILE *stream); +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); +int fgetc(FILE *stream); +char *fgets(char *s, int size, FILE *stream); +int getc(FILE *stream); +int getchar(void); +char *gets(char *s); +int ungetc(int c, FILE *stream); +int fflush(FILE *stream); +int putchar (int c); + +int printf(const char *format, ...); +int fprintf(FILE *stream, const char *format, ...); +int sprintf(char *str, const char *format, ...); +int snprintf(char *str, size_t size, const char *format, ...); +int asprintf(char **strp, const char *format, ...); +int dprintf(int fd, const char *format, ...); +int vprintf(const char *format, va_list ap); +int vfprintf(FILE *stream, const char *format, va_list ap); +int vsprintf(char *str, const char *format, va_list ap); +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +int vasprintf(char **strp, const char *format, va_list ap); +int vdprintf(int fd, const char *format, va_list ap); + +void perror(const char *s); + +/* string.h */ +char *strcat(char *dest, const char *src); +char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); +char *strcpy(char *dest, const char *src); +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); +char *strdup(const char *s); +size_t strlen(const char *s); + +/* dlfcn.h */ +#define RTLD_LAZY 0x001 +#define RTLD_NOW 0x002 +#define RTLD_GLOBAL 0x100 + +void *dlopen(const char *filename, int flag); +const char *dlerror(void); +void *dlsym(void *handle, char *symbol); +int dlclose(void *handle); + +#endif /* _TCCLIB_H */ diff --git a/tcc/include/tchar.h b/tcc/include/tchar.h index e48c59ce..cd44beca 100644 --- a/tcc/include/tchar.h +++ b/tcc/include/tchar.h @@ -1,1102 +1,1102 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#include <_mingw.h> - -#ifndef _INC_TCHAR -#define _INC_TCHAR - -#ifdef _STRSAFE_H_INCLUDED_ -#error Need to include strsafe.h after tchar.h -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define _ftcscat _tcscat -#define _ftcschr _tcschr -#define _ftcscpy _tcscpy -#define _ftcscspn _tcscspn -#define _ftcslen _tcslen -#define _ftcsncat _tcsncat -#define _ftcsncpy _tcsncpy -#define _ftcspbrk _tcspbrk -#define _ftcsrchr _tcsrchr -#define _ftcsspn _tcsspn -#define _ftcsstr _tcsstr -#define _ftcstok _tcstok - -#define _ftcsdup _tcsdup -#define _ftcsnset _tcsnset -#define _ftcsrev _tcsrev -#define _ftcsset _tcsset - -#define _ftcscmp _tcscmp -#define _ftcsicmp _tcsicmp -#define _ftcsnccmp _tcsnccmp -#define _ftcsncmp _tcsncmp -#define _ftcsncicmp _tcsncicmp -#define _ftcsnicmp _tcsnicmp - -#define _ftcscoll _tcscoll -#define _ftcsicoll _tcsicoll -#define _ftcsnccoll _tcsnccoll -#define _ftcsncoll _tcsncoll -#define _ftcsncicoll _tcsncicoll -#define _ftcsnicoll _tcsnicoll - -#define _ftcsclen _tcsclen -#define _ftcsnccat _tcsnccat -#define _ftcsnccpy _tcsnccpy -#define _ftcsncset _tcsncset - -#define _ftcsdec _tcsdec -#define _ftcsinc _tcsinc -#define _ftcsnbcnt _tcsnbcnt -#define _ftcsnccnt _tcsnccnt -#define _ftcsnextc _tcsnextc -#define _ftcsninc _tcsninc -#define _ftcsspnp _tcsspnp - -#define _ftcslwr _tcslwr -#define _ftcsupr _tcsupr - -#define _ftclen _tclen -#define _ftccpy _tccpy -#define _ftccmp _tccmp - -#ifndef _CONST_RETURN -#ifdef __cplusplus -#define _CONST_RETURN const -#define _CRT_CONST_CORRECT_OVERLOADS -#else -#define _CONST_RETURN -#endif -#endif - -#define _WConst_return _CONST_RETURN - -#ifdef _UNICODE - -#ifdef __cplusplus -} -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _WCTYPE_T_DEFINED -#define _WCTYPE_T_DEFINED - typedef unsigned short wint_t; - typedef unsigned short wctype_t; -#endif - -#ifndef __TCHAR_DEFINED -#define __TCHAR_DEFINED - typedef wchar_t _TCHAR; - typedef wchar_t _TSCHAR; - typedef wchar_t _TUCHAR; - typedef wchar_t _TXCHAR; - typedef wint_t _TINT; -#endif - -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED -#ifndef NO_OLDNAMES - typedef wchar_t TCHAR; -#endif -#endif - -#define _TEOF WEOF - -#define __T(x) L##x - -#define _tmain wmain -#define _tWinMain wWinMain -#define _tenviron _wenviron -#define __targv __wargv - -#define _tprintf wprintf -#define _tprintf_l _wprintf_l -#define _tprintf_p _wprintf_p -#define _tprintf_p_l _wprintf_p_l -#define _tcprintf _cwprintf -#define _tcprintf_l _cwprintf_l -#define _tcprintf_p _cwprintf_p -#define _tcprintf_p_l _cwprintf_p_l -#define _vtcprintf _vcwprintf -#define _vtcprintf_l _vcwprintf_l -#define _vtcprintf_p _vcwprintf_p -#define _vtcprintf_p_l _vcwprintf_p_l -#define _ftprintf fwprintf -#define _ftprintf_l _fwprintf_l -#define _ftprintf_p _fwprintf_p -#define _ftprintf_p_l _fwprintf_p_l -#define _stprintf swprintf -#define _stprintf_l __swprintf_l -#define _stprintf_p _swprintf_p -#define _stprintf_p_l _swprintf_p_l -#define _sctprintf _scwprintf -#define _sctprintf_l _scwprintf_l -#define _sctprintf_p _scwprintf_p -#define _sctprintf_p_l _scwprintf_p_l -#define _sntprintf _snwprintf -#define _sntprintf_l _snwprintf_l -#define _vtprintf vwprintf -#define _vtprintf_l _vwprintf_l -#define _vtprintf_p _vwprintf_p -#define _vtprintf_p_l _vwprintf_p_l -#define _vftprintf vfwprintf -#define _vftprintf_l _vfwprintf_l -#define _vftprintf_p _vfwprintf_p -#define _vftprintf_p_l _vfwprintf_p_l -#define _vstprintf vswprintf -#define _vstprintf_l _vswprintf_l -#define _vstprintf_p _vswprintf_p -#define _vstprintf_p_l _vswprintf_p_l -#define _vsctprintf _vscwprintf -#define _vsctprintf_l _vscwprintf_l -#define _vsctprintf_p _vscwprintf_p -#define _vsctprintf_p_l _vscwprintf_p_l -#define _vsntprintf _vsnwprintf -#define _vsntprintf_l _vsnwprintf_l - -#define _tscanf wscanf -#define _tscanf_l _wscanf_l -#define _tcscanf _cwscanf -#define _tcscanf_l _cwscanf_l -#define _ftscanf fwscanf -#define _ftscanf_l _fwscanf_l -#define _stscanf swscanf -#define _stscanf_l _swscanf_l -#define _sntscanf _snwscanf -#define _sntscanf_l _snwscanf_l - -#define _fgettc fgetwc -#define _fgettc_nolock _fgetwc_nolock -#define _fgettchar _fgetwchar -#define _fgetts fgetws -#define _fputtc fputwc -#define _fputtc_nolock _fputwc_nolock -#define _fputtchar _fputwchar -#define _fputts fputws -#define _cputts _cputws -#define _cgetts _cgetws -#define _gettc getwc -#define _gettc_nolock _getwc_nolock -#define _gettch _getwch -#define _gettch_nolock _getwch_nolock -#define _gettche _getwche -#define _gettche_nolock _getwche_nolock -#define _gettchar getwchar -#define _gettchar_nolock _getwchar_nolock -#define _getts _getws -#define _puttc putwc -#define _puttc_nolock _putwc_nolock -#define _puttchar putwchar -#define _puttchar_nolock _putwchar_nolock -#define _puttch _putwch -#define _puttch_nolock _putwch_nolock -#define _putts _putws -#define _ungettc ungetwc -#define _ungettc_nolock _ungetwc_nolock -#define _ungettch _ungetwch -#define _ungettch_nolock _ungetwch_nolock - -#define _tcstod wcstod -#define _tcstol wcstol -#define _tcstoul wcstoul -#define _tcstoi64 _wcstoi64 -#define _tcstoui64 _wcstoui64 -#define _tstof _wtof -#define _tstol _wtol -#define _tstoi _wtoi -#define _tstoi64 _wtoi64 -#define _tcstod_l _wcstod_l -#define _tcstol_l _wcstol_l -#define _tcstoul_l _wcstoul_l -#define _tcstoi64_l _wcstoi64_l -#define _tcstoui64_l _wcstoui64_l -#define _tstof_l _wtof_l -#define _tstol_l _wtol_l -#define _tstoi_l _wtoi_l -#define _tstoi64_l _wtoi64_l - -#define _itot _itow -#define _ltot _ltow -#define _ultot _ultow -#define _ttoi _wtoi -#define _ttol _wtol - -#define _ttoi64 _wtoi64 -#define _i64tot _i64tow -#define _ui64tot _ui64tow - -#define _tcscat wcscat -#define _tcschr wcschr -#define _tcscpy wcscpy -#define _tcscspn wcscspn -#define _tcslen wcslen -#define _tcsnlen wcsnlen -#define _tcsncat wcsncat -#define _tcsncat_l _wcsncat_l -#define _tcsncpy wcsncpy -#define _tcsncpy_l _wcsncpy_l -#define _tcspbrk wcspbrk -#define _tcsrchr wcsrchr -#define _tcsspn wcsspn -#define _tcsstr wcsstr -#define _tcstok wcstok -#define _tcstok_l _wcstok_l -#define _tcserror _wcserror -#define __tcserror __wcserror - -#define _tcsdup _wcsdup -#define _tcsnset _wcsnset -#define _tcsnset_l _wcsnset_l -#define _tcsrev _wcsrev -#define _tcsset _wcsset -#define _tcsset_l _wcsset_l - -#define _tcscmp wcscmp -#define _tcsicmp _wcsicmp -#define _tcsicmp_l _wcsicmp_l -#define _tcsnccmp wcsncmp -#define _tcsncmp wcsncmp -#define _tcsncicmp _wcsnicmp -#define _tcsncicmp_l _wcsnicmp_l -#define _tcsnicmp _wcsnicmp -#define _tcsnicmp_l _wcsnicmp_l - -#define _tcscoll wcscoll -#define _tcscoll_l _wcscoll_l -#define _tcsicoll _wcsicoll -#define _tcsicoll_l _wcsicoll_l -#define _tcsnccoll _wcsncoll -#define _tcsnccoll_l _wcsncoll_l -#define _tcsncoll _wcsncoll -#define _tcsncoll_l _wcsncoll_l -#define _tcsncicoll _wcsnicoll -#define _tcsncicoll_l _wcsnicoll_l -#define _tcsnicoll _wcsnicoll -#define _tcsnicoll_l _wcsnicoll_l - -#define _texecl _wexecl -#define _texecle _wexecle -#define _texeclp _wexeclp -#define _texeclpe _wexeclpe -#define _texecv _wexecv -#define _texecve _wexecve -#define _texecvp _wexecvp -#define _texecvpe _wexecvpe - -#define _tspawnl _wspawnl -#define _tspawnle _wspawnle -#define _tspawnlp _wspawnlp -#define _tspawnlpe _wspawnlpe -#define _tspawnv _wspawnv -#define _tspawnve _wspawnve -#define _tspawnvp _wspawnvp -#define _tspawnvp _wspawnvp -#define _tspawnvpe _wspawnvpe - -#define _tsystem _wsystem - -#define _tasctime _wasctime -#define _tctime _wctime -#define _tctime32 _wctime32 -#define _tctime64 _wctime64 -#define _tstrdate _wstrdate -#define _tstrtime _wstrtime -#define _tutime _wutime -#define _tutime32 _wutime32 -#define _tutime64 _wutime64 -#define _tcsftime wcsftime -#define _tcsftime_l _wcsftime_l - -#define _tchdir _wchdir -#define _tgetcwd _wgetcwd -#define _tgetdcwd _wgetdcwd -#define _tgetdcwd_nolock _wgetdcwd_nolock -#define _tmkdir _wmkdir -#define _trmdir _wrmdir - -#define _tfullpath _wfullpath -#define _tgetenv _wgetenv -#define _tmakepath _wmakepath -#define _tpgmptr _wpgmptr -#define _get_tpgmptr _get_wpgmptr -#define _tputenv _wputenv -#define _tsearchenv _wsearchenv -#define _tsplitpath _wsplitpath - -#define _tfdopen _wfdopen -#define _tfsopen _wfsopen -#define _tfopen _wfopen -#define _tfreopen _wfreopen -#define _tperror _wperror -#define _tpopen _wpopen -#define _ttempnam _wtempnam -#define _ttmpnam _wtmpnam - -#define _taccess _waccess -#define _tchmod _wchmod -#define _tcreat _wcreat -#define _tfindfirst _wfindfirst -#define _tfindfirst32 _wfindfirst32 -#define _tfindfirst64 _wfindfirst64 -#define _tfindfirsti64 _wfindfirsti64 -#define _tfindfirst32i64 _wfindfirst32i64 -#define _tfindfirst64i32 _wfindfirst64i32 -#define _tfindnext _wfindnext -#define _tfindnext32 _wfindnext32 -#define _tfindnext64 _wfindnext64 -#define _tfindnexti64 _wfindnexti64 -#define _tfindnext32i64 _wfindnext32i64 -#define _tfindnext64i32 _wfindnext64i32 -#define _tmktemp _wmktemp -#define _topen _wopen -#define _tremove _wremove -#define _trename _wrename -#define _tsopen _wsopen -#define _tunlink _wunlink - -#define _tfinddata_t _wfinddata_t -#define _tfinddata32_t _wfinddata32_t -#define _tfinddata64_t _wfinddata64_t -#define _tfinddatai64_t _wfinddatai64_t -#define _tfinddata32i64_t _wfinddata32i64_t -#define _tfinddata64i32_t _wfinddata64i32_t - -#define _tstat _wstat -#define _tstat32 _wstat32 -#define _tstat32i64 _wstat32i64 -#define _tstat64 _wstat64 -#define _tstat64i32 _wstat64i32 -#define _tstati64 _wstati64 - -#define _tsetlocale _wsetlocale - -#define _tcsclen wcslen -#define _tcscnlen wcsnlen -#define _tcsclen_l(_String,_Locale) wcslen(_String) -#define _tcscnlen_l(_String,_Max_count,_Locale) wcsnlen_l((_String),(_Max_count)) -#define _tcsnccat wcsncat -#define _tcsnccat_l _wcsncat_l -#define _tcsnccpy wcsncpy -#define _tcsnccpy_l _wcsncpy_l -#define _tcsncset _wcsnset - -#define _tcsdec _wcsdec -#define _tcsinc _wcsinc -#define _tcsnbcnt _wcsncnt -#define _tcsnccnt _wcsncnt -#define _tcsnextc _wcsnextc -#define _tcsninc _wcsninc -#define _tcsspnp _wcsspnp - -#define _tcslwr _wcslwr -#define _tcslwr_l _wcslwr_l -#define _tcsupr _wcsupr -#define _tcsupr_l _wcsupr_l -#define _tcsxfrm wcsxfrm -#define _tcsxfrm_l _wcsxfrm_l - -#define _tclen(_pc) (1) -#define _tccpy(_pc1,_cpc2) ((*(_pc1) = *(_cpc2))) -#define _tccmp(_cpc1,_cpc2) ((*(_cpc1))-(*(_cpc2))) - -#define _istalnum iswalnum -#define _istalnum_l _iswalnum_l -#define _istalpha iswalpha -#define _istalpha_l _iswalpha_l -#define _istascii iswascii -#define _istcntrl iswcntrl -#define _istcntrl_l _iswcntrl_l -#define _istdigit iswdigit -#define _istdigit_l _iswdigit_l -#define _istgraph iswgraph -#define _istgraph_l _iswgraph_l -#define _istlower iswlower -#define _istlower_l _iswlower_l -#define _istprint iswprint -#define _istprint_l _iswprint_l -#define _istpunct iswpunct -#define _istpunct_l _iswpunct_l -#define _istspace iswspace -#define _istspace_l _iswspace_l -#define _istupper iswupper -#define _istupper_l _iswupper_l -#define _istxdigit iswxdigit -#define _istxdigit_l _iswxdigit_l - -#define _totupper towupper -#define _totupper_l _towupper_l -#define _totlower towlower -#define _totlower_l _towlower_l - -#define _istlegal(_Char) (1) -#define _istlead(_Char) (0) -#define _istleadbyte(_Char) (0) -#define _istleadbyte_l(_Char,_Locale) (0) - -#define _wcsdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) -#define _wcsinc(_pc) ((_pc)+1) -#define _wcsnextc(_cpc) ((unsigned int) *(_cpc)) -#define _wcsninc(_pc,_sz) (((_pc)+(_sz))) - _CRTIMP size_t __cdecl __wcsncnt(const wchar_t *_Str,size_t _MaxCount); -#define _wcsncnt(_cpc,_sz) (__wcsncnt(_cpc,_sz)) -#define _wcsspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+wcsspn(_cpc1,_cpc2))) ? ((_cpc1)+wcsspn(_cpc1,_cpc2)) : NULL)) -#define _wcsncpy_l(_Destination,_Source,_Count,_Locale) (wcsncpy(_Destination,_Source,_Count)) -#define _wcsncat_l(_Destination,_Source,_Count,_Locale) (wcsncat(_Destination,_Source,_Count)) -#define _wcstok_l(_String,_Delimiters,_Locale) (wcstok(_String,_Delimiters)) -#define _wcsnset_l(_Destination,_Value,_Count,_Locale) (_wcsnset(_Destination,_Value,_Count)) -#define _wcsset_l(_Destination,_Value,_Locale) (_wcsset(_Destination,_Value)) - - /* dirent structures and functions */ -#define _tdirent _wdirent -#define _TDIR _WDIR -#define _topendir _wopendir -#define _tclosedir _wclosedir -#define _treaddir _wreaddir -#define _trewinddir _wrewinddir -#define _ttelldir _wtelldir -#define _tseekdir _wseekdir - -#else - -#ifdef __cplusplus -} -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define _TEOF EOF - -#define __T(x) x - -#define _tmain main -#define _tWinMain WinMain -#ifdef _POSIX_ -#define _tenviron environ -#else -#define _tenviron _environ -#endif -#define __targv __argv - -#define _tprintf printf -#define _tprintf_l _printf_l -#define _tprintf_p _printf_p -#define _tprintf_p_l _printf_p_l -#define _tcprintf _cprintf -#define _tcprintf_l _cprintf_l -#define _tcprintf_p _cprintf_p -#define _tcprintf_p_l _cprintf_p_l -#define _vtcprintf _vcprintf -#define _vtcprintf_l _vcprintf_l -#define _vtcprintf_p _vcprintf_p -#define _vtcprintf_p_l _vcprintf_p_l -#define _ftprintf fprintf -#define _ftprintf_l _fprintf_l -#define _ftprintf_p _fprintf_p -#define _ftprintf_p_l _fprintf_p_l -#define _stprintf sprintf -#define _stprintf_l _sprintf_l -#define _stprintf_p _sprintf_p -#define _stprintf_p_l _sprintf_p_l -#define _sctprintf _scprintf -#define _sctprintf_l _scprintf_l -#define _sctprintf_p _scprintf_p -#define _sctprintf_p_l _scprintf_p_l -#define _sntprintf _snprintf -#define _sntprintf_l _snprintf_l -#define _vtprintf vprintf -#define _vtprintf_l _vprintf_l -#define _vtprintf_p _vprintf_p -#define _vtprintf_p_l _vprintf_p_l -#define _vftprintf vfprintf -#define _vftprintf_l _vfprintf_l -#define _vftprintf_p _vfprintf_p -#define _vftprintf_p_l _vfprintf_p_l -#define _vstprintf vsprintf -#define _vstprintf_l _vsprintf_l -#define _vstprintf_p _vsprintf_p -#define _vstprintf_p_l _vsprintf_p_l -#define _vsctprintf _vscprintf -#define _vsctprintf_l _vscprintf_l -#define _vsctprintf_p _vscprintf_p -#define _vsctprintf_p_l _vscprintf_p_l -#define _vsntprintf _vsnprintf -#define _vsntprintf_l _vsnprintf_l - -#define _tscanf scanf -#define _tscanf_l _scanf_l -#define _tcscanf _cscanf -#define _tcscanf_l _cscanf_l -#define _ftscanf fscanf -#define _ftscanf_l _fscanf_l -#define _stscanf sscanf -#define _stscanf_l _sscanf_l -#define _sntscanf _snscanf -#define _sntscanf_l _snscanf_l - -#define _fgettc fgetc -#define _fgettc_nolock _fgetc_nolock -#define _fgettchar _fgetchar -#define _fgetts fgets -#define _fputtc fputc -#define _fputtc_nolock _fputc_nolock -#define _fputtchar _fputchar -#define _fputts fputs -#define _cputts _cputs -#define _gettc getc -#define _gettc_nolock _getc_nolock -#define _gettch _getch -#define _gettch_nolock _getch_nolock -#define _gettche _getche -#define _gettche_nolock _getche_nolock -#define _gettchar getchar -#define _gettchar_nolock _getchar_nolock -#define _getts gets -#define _cgetts _cgets -#define _puttc putc -#define _puttc_nolock _putc_nolock -#define _puttchar putchar -#define _puttchar_nolock _putchar_nolock -#define _puttch _putch -#define _puttch_nolock _putch_nolock -#define _putts puts -#define _ungettc ungetc -#define _ungettc_nolock _ungetc_nolock -#define _ungettch _ungetch -#define _ungettch_nolock _ungetch_nolock - -#define _tcstod strtod -#define _tcstol strtol -#define _tcstoul strtoul -#define _tstof atof -#define _tstol atol -#define _tstoi atoi -#define _tstoi64 _atoi64 -#define _tcstod_l _strtod_l -#define _tcstol_l _strtol_l -#define _tcstoul_l _strtoul_l -#define _tstof_l _atof_l -#define _tstol_l _atol_l -#define _tstoi_l _atoi_l -#define _tstoi64_l _atoi64_l - -#define _itot _itoa -#define _ltot _ltoa -#define _ultot _ultoa -#define _ttoi atoi -#define _ttol atol - -#define _ttoi64 _atoi64 -#define _tcstoi64 _strtoi64 -#define _tcstoi64_l _strtoi64_l -#define _tcstoui64 _strtoui64 -#define _tcstoui64_l _strtoui64_l -#define _i64tot _i64toa -#define _ui64tot _ui64toa - -#define _tcscat strcat -#define _tcscpy strcpy -#define _tcsdup _strdup -#define _tcslen strlen -#if 0 -#define _tcsnlen strnlen -#endif -#define _tcsxfrm strxfrm -#define _tcsxfrm_l _strxfrm_l -#define _tcserror strerror -#define __tcserror _strerror - -#define _texecl _execl -#define _texecle _execle -#define _texeclp _execlp -#define _texeclpe _execlpe -#define _texecv _execv -#define _texecve _execve -#define _texecvp _execvp -#define _texecvpe _execvpe - -#define _tspawnl _spawnl -#define _tspawnle _spawnle -#define _tspawnlp _spawnlp -#define _tspawnlpe _spawnlpe -#define _tspawnv _spawnv -#define _tspawnve _spawnve -#define _tspawnvp _spawnvp -#define _tspawnvpe _spawnvpe - -#define _tsystem system - -#define _tasctime asctime -#define _tctime ctime -#define _tctime32 _ctime32 -#define _tctime64 _ctime64 -#define _tstrdate _strdate -#define _tstrtime _strtime -#define _tutime _utime -#define _tutime32 _utime32 -#define _tutime64 _utime64 -#define _tcsftime strftime -#define _tcsftime_l _strftime_l - -#define _tchdir _chdir -#define _tgetcwd _getcwd -#define _tgetdcwd _getdcwd -#define _tgetdcwd_nolock _getdcwd_nolock -#define _tmkdir _mkdir -#define _trmdir _rmdir - -#define _tfullpath _fullpath -#define _tgetenv getenv -#define _tmakepath _makepath -#define _tpgmptr _pgmptr -#define _get_tpgmptr _get_pgmptr -#define _tputenv _putenv -#define _tsearchenv _searchenv -#define _tsplitpath _splitpath - -#ifdef _POSIX_ -#define _tfdopen fdopen -#else -#define _tfdopen _fdopen -#endif -#define _tfsopen _fsopen -#define _tfopen fopen -#define _tfreopen freopen -#define _tperror perror -#define _tpopen _popen -#define _ttempnam _tempnam -#define _ttmpnam tmpnam - -#define _tchmod _chmod -#define _tcreat _creat -#define _tfindfirst _findfirst -#define _tfindfirst32 _findfirst32 -#define _tfindfirst64 _findfirst64 -#define _tfindfirsti64 _findfirsti64 -#define _tfindfirst32i64 _findfirst32i64 -#define _tfindfirst64i32 _findfirst64i32 -#define _tfindnext _findnext -#define _tfindnext32 _findnext32 -#define _tfindnext64 _findnext64 -#define _tfindnexti64 _findnexti64 -#define _tfindnext32i64 _findnext32i64 -#define _tfindnext64i32 _findnext64i32 -#define _tmktemp _mktemp - -#ifdef _POSIX_ -#define _topen open -#define _taccess access -#else -#define _topen _open -#define _taccess _access -#endif - -#define _tremove remove -#define _trename rename -#define _tsopen _sopen -#define _tunlink _unlink - -#define _tfinddata_t _finddata_t -#define _tfinddata32_t _finddata32_t -#define _tfinddata64_t __finddata64_t -#define _tfinddatai64_t _finddatai64_t -#define _tfinddata32i64_t _finddata32i64_t -#define _tfinddata64i32_t _finddata64i32_t - -#define _istascii __isascii -#define _istcntrl iscntrl -#define _istcntrl_l _iscntrl_l -#define _istxdigit isxdigit -#define _istxdigit_l _isxdigit_l - -#define _tstat _stat -#define _tstat32 _stat32 -#define _tstat32i64 _stat32i64 -#define _tstat64 _stat64 -#define _tstat64i32 _stat64i32 -#define _tstati64 _stati64 - -#define _tsetlocale setlocale - -#ifdef _MBCS - -#ifdef __cplusplus -} -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __TCHAR_DEFINED - typedef char _TCHAR; - typedef signed char _TSCHAR; - typedef unsigned char _TUCHAR; - typedef unsigned char _TXCHAR; - typedef unsigned int _TINT; -#define __TCHAR_DEFINED -#endif - -#ifndef _TCHAR_DEFINED -#ifndef NO_OLDNAMES - typedef char TCHAR; -#endif -#define _TCHAR_DEFINED -#endif - -#ifdef _MB_MAP_DIRECT - -#define _tcschr _mbschr -#define _tcscspn _mbscspn -#define _tcsncat _mbsnbcat -#define _tcsncat_l _mbsnbcat_l -#define _tcsncpy _mbsnbcpy -#define _tcsncpy_l _mbsnbcpy_l -#define _tcspbrk _mbspbrk -#define _tcsrchr _mbsrchr -#define _tcsspn _mbsspn -#define _tcsstr _mbsstr -#define _tcstok _mbstok -#define _tcstok_l _mbstok_l - -#define _tcsnset _mbsnbset -#define _tcsnset_l _mbsnbset_l -#define _tcsrev _mbsrev -#define _tcsset _mbsset -#define _tcsset_l _mbsset_l - -#define _tcscmp _mbscmp -#define _tcsicmp _mbsicmp -#define _tcsicmp_l _mbsicmp_l -#define _tcsnccmp _mbsncmp -#define _tcsncmp _mbsnbcmp -#define _tcsncicmp _mbsnicmp -#define _tcsncicmp_l _mbsnicmp_l -#define _tcsnicmp _mbsnbicmp -#define _tcsnicmp_l _mbsnbicmp_l - -#define _tcscoll _mbscoll -#define _tcscoll_l _mbscoll_l -#define _tcsicoll _mbsicoll -#define _tcsicoll_l _mbsicoll_l -#define _tcsnccoll _mbsncoll -#define _tcsnccoll_l _mbsncoll_l -#define _tcsncoll _mbsnbcoll -#define _tcsncoll_l _mbsnbcoll_l -#define _tcsncicoll _mbsnicoll -#define _tcsncicoll_l _mbsnicoll_l -#define _tcsnicoll _mbsnbicoll -#define _tcsnicoll_l _mbsnbicoll_l - -#define _tcsclen _mbslen -#define _tcscnlen _mbsnlen -#define _tcsclen_l _mbslen_l -#define _tcscnlen_l _mbsnlen_l -#define _tcsnccat _mbsncat -#define _tcsnccat_l _mbsncat_l -#define _tcsnccpy _mbsncpy -#define _tcsnccpy_l _mbsncpy_l -#define _tcsncset _mbsnset -#define _tcsncset_l _mbsnset_l - -#define _tcsdec _mbsdec -#define _tcsinc _mbsinc -#define _tcsnbcnt _mbsnbcnt -#define _tcsnccnt _mbsnccnt -#define _tcsnextc _mbsnextc -#define _tcsninc _mbsninc -#define _tcsspnp _mbsspnp - -#define _tcslwr _mbslwr -#define _tcslwr_l _mbslwr_l -#define _tcsupr _mbsupr -#define _tcsupr_l _mbsupr_l - -#define _tclen _mbclen -#define _tccpy _mbccpy -#define _tccpy_l _mbccpy_l -#else - - _CRTIMP _CONST_RETURN char *__cdecl _tcschr(const char *_Str,unsigned int _Val); - _CRTIMP size_t __cdecl _tcscspn(const char *_Str,const char *_Control); - _CRTIMP char *__cdecl _tcsncat(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsncpy(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsncpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP _CONST_RETURN char *__cdecl _tcspbrk(const char *_Str,const char *_Control); - _CRTIMP _CONST_RETURN char *__cdecl _tcsrchr(const char *_Str,unsigned int _Ch); - _CRTIMP size_t __cdecl _tcsspn(const char *_Str,const char *_Control); - _CRTIMP _CONST_RETURN char *__cdecl _tcsstr(const char *_Str,const char *_Substr); - _CRTIMP char *__cdecl _tcstok(char *_Str,const char *_Delim); - _CRTIMP char *__cdecl _tcstok_l(char *_Str,const char *_Delim,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnset(char *_Str,unsigned int _Val,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsrev(char *_Str); - _CRTIMP char *__cdecl _tcsset(char *_Str,unsigned int _Val); - _CRTIMP char *__cdecl _tcsset_l(char *_Str,unsigned int _Val,_locale_t _Locale); - _CRTIMP int __cdecl _tcscmp(const char *_Str1,const char *_Str); - _CRTIMP int __cdecl _tcsicmp(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _tcsicmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnccmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcscoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _tcscoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _tcsicoll(const char *_Str1,const char *_Str2); - _CRTIMP int __cdecl _tcsicoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnccoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsnccoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsncoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsncicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsncicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _tcsnicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _tcsnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP size_t __cdecl _tcsclen(const char *_Str); - _CRTIMP size_t __cdecl _tcscnlen(const char *_Str,size_t _MaxCount); - _CRTIMP size_t __cdecl _tcsclen_l(const char *_Str,_locale_t _Locale); - _CRTIMP size_t __cdecl _tcscnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccat(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsnccpy(char *_Dst,const char *_Src,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsnccpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsncset(char *_Str,unsigned int _Val,size_t _MaxCount); - _CRTIMP char *__cdecl _tcsdec(const char *_Start,const char *_Pos); - _CRTIMP char *__cdecl _tcsinc(const char *_Ptr); - _CRTIMP size_t __cdecl _tcsnbcnt(const char *_Str,size_t _MaxCount); - _CRTIMP size_t __cdecl _tcsnccnt(const char *_Str,size_t _MaxCount); - _CRTIMP unsigned int __cdecl _tcsnextc (const char *_Str); - _CRTIMP char *__cdecl _tcsninc(const char *_Ptr,size_t _Count); - _CRTIMP char *__cdecl _tcsspnp(const char *_Str1,const char *_Str2); - _CRTIMP char *__cdecl _tcslwr(char *_Str); - _CRTIMP char *__cdecl _tcslwr_l(char *_Str,_locale_t _Locale); - _CRTIMP char *__cdecl _tcsupr(char *_Str); - _CRTIMP char *__cdecl _tcsupr_l(char *_Str,_locale_t _Locale); - _CRTIMP size_t __cdecl _tclen(const char *_Str); - _CRTIMP void __cdecl _tccpy(char *_DstCh,const char *_SrcCh); - -#ifdef __cplusplus -#ifndef _CPP_TCHAR_INLINES_DEFINED -#define _CPP_TCHAR_INLINES_DEFINED - extern "C++" { - extern inline char *__cdecl _tcschr(char *_S,unsigned int _C) { return ((char *)_tcschr((const char *)_S,_C)); } - extern inline char *__cdecl _tcspbrk(char *_S,const char *_P) { return ((char *)_tcspbrk((const char *)_S,_P)); } - extern inline char *__cdecl _tcsrchr(char *_S,unsigned int _C) { return ((char *)_tcsrchr((const char *)_S,_C)); } - extern inline char *__cdecl _tcsstr(char *_S,const char *_P) { return ((char *)_tcsstr((const char *)_S,_P)); } - } -#endif -#endif -#endif - -#define _tccmp(_cp1,_cp2) _tcsnccmp(_cp1,_cp2,1) - -#define _istalnum _ismbcalnum -#define _istalnum_l _ismbcalnum_l -#define _istalpha _ismbcalpha -#define _istalpha_l _ismbcalpha_l -#define _istdigit _ismbcdigit -#define _istdigit_l _ismbcdigit_l -#define _istgraph _ismbcgraph -#define _istgraph_l _ismbcgraph_l -#define _istlegal _ismbclegal -#define _istlegal_l _ismbclegal_l -#define _istlower _ismbclower -#define _istlower_l _ismbclower_l -#define _istprint _ismbcprint -#define _istprint_l _ismbcprint_l -#define _istpunct _ismbcpunct -#define _istpunct_l _ismbcpunct_l -#define _istspace _ismbcspace -#define _istspace_l _ismbcspace_l -#define _istupper _ismbcupper -#define _istupper_l _ismbcupper_l - -#define _totupper _mbctoupper -#define _totupper_l _mbctoupper_l -#define _totlower _mbctolower -#define _totlower_l _mbctolower_l - -#define _istlead _ismbblead -#define _istleadbyte isleadbyte -#define _istleadbyte_l _isleadbyte_l -#else - -#ifndef __TCHAR_DEFINED -#define __TCHAR_DEFINED - typedef char _TCHAR; - typedef signed char _TSCHAR; - typedef unsigned char _TUCHAR; - typedef char _TXCHAR; - typedef int _TINT; -#endif - -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED -#ifndef NO_OLDNAMES - typedef char TCHAR; -#endif -#endif - -#define _tcschr strchr -#define _tcscspn strcspn -#define _tcsncat strncat -#define _tcsncat_l _strncat_l -#define _tcsncpy strncpy -#define _tcsncpy_l _strncpy_l -#define _tcspbrk strpbrk -#define _tcsrchr strrchr -#define _tcsspn strspn -#define _tcsstr strstr -#define _tcstok strtok -#define _tcstok_l _strtok_l - -#define _tcsnset _strnset -#define _tcsnset_l _strnset_l -#define _tcsrev _strrev -#define _tcsset _strset - -#define _tcscmp strcmp -#define _tcsicmp _stricmp -#define _tcsicmp_l _stricmp_l -#define _tcsnccmp strncmp -#define _tcsncmp strncmp -#define _tcsncicmp _strnicmp -#define _tcsncicmp_l _strnicmp_l -#define _tcsnicmp _strnicmp -#define _tcsnicmp_l _strnicmp_l - -#define _tcscoll strcoll -#define _tcscoll_l _strcoll_l -#define _tcsicoll _stricoll -#define _tcsicoll_l _stricoll_l -#define _tcsnccoll _strncoll -#define _tcsnccoll_l _strncoll_l -#define _tcsncoll _strncoll -#define _tcsncoll_l _strncoll_l -#define _tcsncicoll _strnicoll -#define _tcsncicoll_l _strnicoll_l -#define _tcsnicoll _strnicoll -#define _tcsnicoll_l _strnicoll_l - -#define _tcsclen strlen -#define _tcscnlen strnlen -#define _tcsclen_l(_String,_Locale) strlen(_String) -#define _tcscnlen_l(_String,_Max_count,_Locale) strnlen_l((_String),(_Max_count)) -#define _tcsnccat strncat -#define _tcsnccat_l _strncat_l -#define _tcsnccpy strncpy -#define _tcsnccpy_l _strncpy_l -#define _tcsncset _strnset - -#define _tcsdec _strdec -#define _tcsinc _strinc -#define _tcsnbcnt _strncnt -#define _tcsnccnt _strncnt -#define _tcsnextc _strnextc -#define _tcsninc _strninc -#define _tcsspnp _strspnp - -#define _tcslwr _strlwr -#define _tcslwr_l _strlwr_l -#define _tcsupr _strupr -#define _tcsupr_l _strupr_l -#define _tcsxfrm strxfrm -#define _tcsxfrm_l _strxfrm_l - -#define _istlead(_Char) (0) -#define _istleadbyte(_Char) (0) -#define _istleadbyte_l(_Char,_Locale) (0) - -#define _tclen(_pc) (1) -#define _tccpy(_pc1,_cpc2) (*(_pc1) = *(_cpc2)) -#define _tccmp(_cpc1,_cpc2) (((unsigned char)*(_cpc1))-((unsigned char)*(_cpc2))) - - /* dirent structures and functions */ -#define _tdirent dirent -#define _TDIR DIR -#define _topendir opendir -#define _tclosedir closedir -#define _treaddir readdir -#define _trewinddir rewinddir -#define _ttelldir telldir -#define _tseekdir seekdir - -#define _istalnum isalnum -#define _istalnum_l _isalnum_l -#define _istalpha isalpha -#define _istalpha_l _isalpha_l -#define _istdigit isdigit -#define _istdigit_l _isdigit_l -#define _istgraph isgraph -#define _istgraph_l _isgraph_l -#define _istlower islower -#define _istlower_l _islower_l -#define _istprint isprint -#define _istprint_l _isprint_l -#define _istpunct ispunct -#define _istpunct_l _ispunct_l -#define _istspace isspace -#define _istspace_l _isspace_l -#define _istupper isupper -#define _istupper_l _isupper_l - -#define _totupper toupper -#define _totupper_l _toupper_l -#define _totlower tolower -#define _totlower_l _tolower_l - -#define _istlegal(_c) (1) - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#define _strdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) -#define _strinc(_pc) ((_pc)+1) -#define _strnextc(_cpc) ((unsigned int) *(const unsigned char *)(_cpc)) -#define _strninc(_pc,_sz) (((_pc)+(_sz))) - _CRTIMP size_t __cdecl __strncnt(const char *_Str,size_t _Cnt); -#define _strncnt(_cpc,_sz) (__strncnt(_cpc,_sz)) -#define _strspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+strspn(_cpc1,_cpc2))) ? ((_cpc1)+strspn(_cpc1,_cpc2)) : NULL)) - -#define _strncpy_l(_Destination,_Source,_Count,_Locale) (strncpy(_Destination,_Source,_Count)) -#define _strncat_l(_Destination,_Source,_Count,_Locale) (strncat(_Destination,_Source,_Count)) -#define _strtok_l(_String,_Delimiters,_Locale) (strtok(_String,_Delimiters)) -#define _strnset_l(_Destination,_Value,_Count,_Locale) (_strnset(_Destination,_Value,_Count)) -#define _strset_l(_Destination,_Value,_Locale) (_strset(_Destination,_Value)) -#endif -#endif - -#define _T(x) __T(x) -#define _TEXT(x) __T(x) - -#ifdef __cplusplus -} -#endif - -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#include <_mingw.h> + +#ifndef _INC_TCHAR +#define _INC_TCHAR + +#ifdef _STRSAFE_H_INCLUDED_ +#error Need to include strsafe.h after tchar.h +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define _ftcscat _tcscat +#define _ftcschr _tcschr +#define _ftcscpy _tcscpy +#define _ftcscspn _tcscspn +#define _ftcslen _tcslen +#define _ftcsncat _tcsncat +#define _ftcsncpy _tcsncpy +#define _ftcspbrk _tcspbrk +#define _ftcsrchr _tcsrchr +#define _ftcsspn _tcsspn +#define _ftcsstr _tcsstr +#define _ftcstok _tcstok + +#define _ftcsdup _tcsdup +#define _ftcsnset _tcsnset +#define _ftcsrev _tcsrev +#define _ftcsset _tcsset + +#define _ftcscmp _tcscmp +#define _ftcsicmp _tcsicmp +#define _ftcsnccmp _tcsnccmp +#define _ftcsncmp _tcsncmp +#define _ftcsncicmp _tcsncicmp +#define _ftcsnicmp _tcsnicmp + +#define _ftcscoll _tcscoll +#define _ftcsicoll _tcsicoll +#define _ftcsnccoll _tcsnccoll +#define _ftcsncoll _tcsncoll +#define _ftcsncicoll _tcsncicoll +#define _ftcsnicoll _tcsnicoll + +#define _ftcsclen _tcsclen +#define _ftcsnccat _tcsnccat +#define _ftcsnccpy _tcsnccpy +#define _ftcsncset _tcsncset + +#define _ftcsdec _tcsdec +#define _ftcsinc _tcsinc +#define _ftcsnbcnt _tcsnbcnt +#define _ftcsnccnt _tcsnccnt +#define _ftcsnextc _tcsnextc +#define _ftcsninc _tcsninc +#define _ftcsspnp _tcsspnp + +#define _ftcslwr _tcslwr +#define _ftcsupr _tcsupr + +#define _ftclen _tclen +#define _ftccpy _tccpy +#define _ftccmp _tccmp + +#ifndef _CONST_RETURN +#ifdef __cplusplus +#define _CONST_RETURN const +#define _CRT_CONST_CORRECT_OVERLOADS +#else +#define _CONST_RETURN +#endif +#endif + +#define _WConst_return _CONST_RETURN + +#ifdef _UNICODE + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _WCTYPE_T_DEFINED +#define _WCTYPE_T_DEFINED + typedef unsigned short wint_t; + typedef unsigned short wctype_t; +#endif + +#ifndef __TCHAR_DEFINED +#define __TCHAR_DEFINED + typedef wchar_t _TCHAR; + typedef wchar_t _TSCHAR; + typedef wchar_t _TUCHAR; + typedef wchar_t _TXCHAR; + typedef wint_t _TINT; +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +#ifndef NO_OLDNAMES + typedef wchar_t TCHAR; +#endif +#endif + +#define _TEOF WEOF + +#define __T(x) L##x + +#define _tmain wmain +#define _tWinMain wWinMain +#define _tenviron _wenviron +#define __targv __wargv + +#define _tprintf wprintf +#define _tprintf_l _wprintf_l +#define _tprintf_p _wprintf_p +#define _tprintf_p_l _wprintf_p_l +#define _tcprintf _cwprintf +#define _tcprintf_l _cwprintf_l +#define _tcprintf_p _cwprintf_p +#define _tcprintf_p_l _cwprintf_p_l +#define _vtcprintf _vcwprintf +#define _vtcprintf_l _vcwprintf_l +#define _vtcprintf_p _vcwprintf_p +#define _vtcprintf_p_l _vcwprintf_p_l +#define _ftprintf fwprintf +#define _ftprintf_l _fwprintf_l +#define _ftprintf_p _fwprintf_p +#define _ftprintf_p_l _fwprintf_p_l +#define _stprintf swprintf +#define _stprintf_l __swprintf_l +#define _stprintf_p _swprintf_p +#define _stprintf_p_l _swprintf_p_l +#define _sctprintf _scwprintf +#define _sctprintf_l _scwprintf_l +#define _sctprintf_p _scwprintf_p +#define _sctprintf_p_l _scwprintf_p_l +#define _sntprintf _snwprintf +#define _sntprintf_l _snwprintf_l +#define _vtprintf vwprintf +#define _vtprintf_l _vwprintf_l +#define _vtprintf_p _vwprintf_p +#define _vtprintf_p_l _vwprintf_p_l +#define _vftprintf vfwprintf +#define _vftprintf_l _vfwprintf_l +#define _vftprintf_p _vfwprintf_p +#define _vftprintf_p_l _vfwprintf_p_l +#define _vstprintf vswprintf +#define _vstprintf_l _vswprintf_l +#define _vstprintf_p _vswprintf_p +#define _vstprintf_p_l _vswprintf_p_l +#define _vsctprintf _vscwprintf +#define _vsctprintf_l _vscwprintf_l +#define _vsctprintf_p _vscwprintf_p +#define _vsctprintf_p_l _vscwprintf_p_l +#define _vsntprintf _vsnwprintf +#define _vsntprintf_l _vsnwprintf_l + +#define _tscanf wscanf +#define _tscanf_l _wscanf_l +#define _tcscanf _cwscanf +#define _tcscanf_l _cwscanf_l +#define _ftscanf fwscanf +#define _ftscanf_l _fwscanf_l +#define _stscanf swscanf +#define _stscanf_l _swscanf_l +#define _sntscanf _snwscanf +#define _sntscanf_l _snwscanf_l + +#define _fgettc fgetwc +#define _fgettc_nolock _fgetwc_nolock +#define _fgettchar _fgetwchar +#define _fgetts fgetws +#define _fputtc fputwc +#define _fputtc_nolock _fputwc_nolock +#define _fputtchar _fputwchar +#define _fputts fputws +#define _cputts _cputws +#define _cgetts _cgetws +#define _gettc getwc +#define _gettc_nolock _getwc_nolock +#define _gettch _getwch +#define _gettch_nolock _getwch_nolock +#define _gettche _getwche +#define _gettche_nolock _getwche_nolock +#define _gettchar getwchar +#define _gettchar_nolock _getwchar_nolock +#define _getts _getws +#define _puttc putwc +#define _puttc_nolock _putwc_nolock +#define _puttchar putwchar +#define _puttchar_nolock _putwchar_nolock +#define _puttch _putwch +#define _puttch_nolock _putwch_nolock +#define _putts _putws +#define _ungettc ungetwc +#define _ungettc_nolock _ungetwc_nolock +#define _ungettch _ungetwch +#define _ungettch_nolock _ungetwch_nolock + +#define _tcstod wcstod +#define _tcstol wcstol +#define _tcstoul wcstoul +#define _tcstoi64 _wcstoi64 +#define _tcstoui64 _wcstoui64 +#define _tstof _wtof +#define _tstol _wtol +#define _tstoi _wtoi +#define _tstoi64 _wtoi64 +#define _tcstod_l _wcstod_l +#define _tcstol_l _wcstol_l +#define _tcstoul_l _wcstoul_l +#define _tcstoi64_l _wcstoi64_l +#define _tcstoui64_l _wcstoui64_l +#define _tstof_l _wtof_l +#define _tstol_l _wtol_l +#define _tstoi_l _wtoi_l +#define _tstoi64_l _wtoi64_l + +#define _itot _itow +#define _ltot _ltow +#define _ultot _ultow +#define _ttoi _wtoi +#define _ttol _wtol + +#define _ttoi64 _wtoi64 +#define _i64tot _i64tow +#define _ui64tot _ui64tow + +#define _tcscat wcscat +#define _tcschr wcschr +#define _tcscpy wcscpy +#define _tcscspn wcscspn +#define _tcslen wcslen +#define _tcsnlen wcsnlen +#define _tcsncat wcsncat +#define _tcsncat_l _wcsncat_l +#define _tcsncpy wcsncpy +#define _tcsncpy_l _wcsncpy_l +#define _tcspbrk wcspbrk +#define _tcsrchr wcsrchr +#define _tcsspn wcsspn +#define _tcsstr wcsstr +#define _tcstok wcstok +#define _tcstok_l _wcstok_l +#define _tcserror _wcserror +#define __tcserror __wcserror + +#define _tcsdup _wcsdup +#define _tcsnset _wcsnset +#define _tcsnset_l _wcsnset_l +#define _tcsrev _wcsrev +#define _tcsset _wcsset +#define _tcsset_l _wcsset_l + +#define _tcscmp wcscmp +#define _tcsicmp _wcsicmp +#define _tcsicmp_l _wcsicmp_l +#define _tcsnccmp wcsncmp +#define _tcsncmp wcsncmp +#define _tcsncicmp _wcsnicmp +#define _tcsncicmp_l _wcsnicmp_l +#define _tcsnicmp _wcsnicmp +#define _tcsnicmp_l _wcsnicmp_l + +#define _tcscoll wcscoll +#define _tcscoll_l _wcscoll_l +#define _tcsicoll _wcsicoll +#define _tcsicoll_l _wcsicoll_l +#define _tcsnccoll _wcsncoll +#define _tcsnccoll_l _wcsncoll_l +#define _tcsncoll _wcsncoll +#define _tcsncoll_l _wcsncoll_l +#define _tcsncicoll _wcsnicoll +#define _tcsncicoll_l _wcsnicoll_l +#define _tcsnicoll _wcsnicoll +#define _tcsnicoll_l _wcsnicoll_l + +#define _texecl _wexecl +#define _texecle _wexecle +#define _texeclp _wexeclp +#define _texeclpe _wexeclpe +#define _texecv _wexecv +#define _texecve _wexecve +#define _texecvp _wexecvp +#define _texecvpe _wexecvpe + +#define _tspawnl _wspawnl +#define _tspawnle _wspawnle +#define _tspawnlp _wspawnlp +#define _tspawnlpe _wspawnlpe +#define _tspawnv _wspawnv +#define _tspawnve _wspawnve +#define _tspawnvp _wspawnvp +#define _tspawnvp _wspawnvp +#define _tspawnvpe _wspawnvpe + +#define _tsystem _wsystem + +#define _tasctime _wasctime +#define _tctime _wctime +#define _tctime32 _wctime32 +#define _tctime64 _wctime64 +#define _tstrdate _wstrdate +#define _tstrtime _wstrtime +#define _tutime _wutime +#define _tutime32 _wutime32 +#define _tutime64 _wutime64 +#define _tcsftime wcsftime +#define _tcsftime_l _wcsftime_l + +#define _tchdir _wchdir +#define _tgetcwd _wgetcwd +#define _tgetdcwd _wgetdcwd +#define _tgetdcwd_nolock _wgetdcwd_nolock +#define _tmkdir _wmkdir +#define _trmdir _wrmdir + +#define _tfullpath _wfullpath +#define _tgetenv _wgetenv +#define _tmakepath _wmakepath +#define _tpgmptr _wpgmptr +#define _get_tpgmptr _get_wpgmptr +#define _tputenv _wputenv +#define _tsearchenv _wsearchenv +#define _tsplitpath _wsplitpath + +#define _tfdopen _wfdopen +#define _tfsopen _wfsopen +#define _tfopen _wfopen +#define _tfreopen _wfreopen +#define _tperror _wperror +#define _tpopen _wpopen +#define _ttempnam _wtempnam +#define _ttmpnam _wtmpnam + +#define _taccess _waccess +#define _tchmod _wchmod +#define _tcreat _wcreat +#define _tfindfirst _wfindfirst +#define _tfindfirst32 _wfindfirst32 +#define _tfindfirst64 _wfindfirst64 +#define _tfindfirsti64 _wfindfirsti64 +#define _tfindfirst32i64 _wfindfirst32i64 +#define _tfindfirst64i32 _wfindfirst64i32 +#define _tfindnext _wfindnext +#define _tfindnext32 _wfindnext32 +#define _tfindnext64 _wfindnext64 +#define _tfindnexti64 _wfindnexti64 +#define _tfindnext32i64 _wfindnext32i64 +#define _tfindnext64i32 _wfindnext64i32 +#define _tmktemp _wmktemp +#define _topen _wopen +#define _tremove _wremove +#define _trename _wrename +#define _tsopen _wsopen +#define _tunlink _wunlink + +#define _tfinddata_t _wfinddata_t +#define _tfinddata32_t _wfinddata32_t +#define _tfinddata64_t _wfinddata64_t +#define _tfinddatai64_t _wfinddatai64_t +#define _tfinddata32i64_t _wfinddata32i64_t +#define _tfinddata64i32_t _wfinddata64i32_t + +#define _tstat _wstat +#define _tstat32 _wstat32 +#define _tstat32i64 _wstat32i64 +#define _tstat64 _wstat64 +#define _tstat64i32 _wstat64i32 +#define _tstati64 _wstati64 + +#define _tsetlocale _wsetlocale + +#define _tcsclen wcslen +#define _tcscnlen wcsnlen +#define _tcsclen_l(_String,_Locale) wcslen(_String) +#define _tcscnlen_l(_String,_Max_count,_Locale) wcsnlen_l((_String),(_Max_count)) +#define _tcsnccat wcsncat +#define _tcsnccat_l _wcsncat_l +#define _tcsnccpy wcsncpy +#define _tcsnccpy_l _wcsncpy_l +#define _tcsncset _wcsnset + +#define _tcsdec _wcsdec +#define _tcsinc _wcsinc +#define _tcsnbcnt _wcsncnt +#define _tcsnccnt _wcsncnt +#define _tcsnextc _wcsnextc +#define _tcsninc _wcsninc +#define _tcsspnp _wcsspnp + +#define _tcslwr _wcslwr +#define _tcslwr_l _wcslwr_l +#define _tcsupr _wcsupr +#define _tcsupr_l _wcsupr_l +#define _tcsxfrm wcsxfrm +#define _tcsxfrm_l _wcsxfrm_l + +#define _tclen(_pc) (1) +#define _tccpy(_pc1,_cpc2) ((*(_pc1) = *(_cpc2))) +#define _tccmp(_cpc1,_cpc2) ((*(_cpc1))-(*(_cpc2))) + +#define _istalnum iswalnum +#define _istalnum_l _iswalnum_l +#define _istalpha iswalpha +#define _istalpha_l _iswalpha_l +#define _istascii iswascii +#define _istcntrl iswcntrl +#define _istcntrl_l _iswcntrl_l +#define _istdigit iswdigit +#define _istdigit_l _iswdigit_l +#define _istgraph iswgraph +#define _istgraph_l _iswgraph_l +#define _istlower iswlower +#define _istlower_l _iswlower_l +#define _istprint iswprint +#define _istprint_l _iswprint_l +#define _istpunct iswpunct +#define _istpunct_l _iswpunct_l +#define _istspace iswspace +#define _istspace_l _iswspace_l +#define _istupper iswupper +#define _istupper_l _iswupper_l +#define _istxdigit iswxdigit +#define _istxdigit_l _iswxdigit_l + +#define _totupper towupper +#define _totupper_l _towupper_l +#define _totlower towlower +#define _totlower_l _towlower_l + +#define _istlegal(_Char) (1) +#define _istlead(_Char) (0) +#define _istleadbyte(_Char) (0) +#define _istleadbyte_l(_Char,_Locale) (0) + +#define _wcsdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) +#define _wcsinc(_pc) ((_pc)+1) +#define _wcsnextc(_cpc) ((unsigned int) *(_cpc)) +#define _wcsninc(_pc,_sz) (((_pc)+(_sz))) + _CRTIMP size_t __cdecl __wcsncnt(const wchar_t *_Str,size_t _MaxCount); +#define _wcsncnt(_cpc,_sz) (__wcsncnt(_cpc,_sz)) +#define _wcsspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+wcsspn(_cpc1,_cpc2))) ? ((_cpc1)+wcsspn(_cpc1,_cpc2)) : NULL)) +#define _wcsncpy_l(_Destination,_Source,_Count,_Locale) (wcsncpy(_Destination,_Source,_Count)) +#define _wcsncat_l(_Destination,_Source,_Count,_Locale) (wcsncat(_Destination,_Source,_Count)) +#define _wcstok_l(_String,_Delimiters,_Locale) (wcstok(_String,_Delimiters)) +#define _wcsnset_l(_Destination,_Value,_Count,_Locale) (_wcsnset(_Destination,_Value,_Count)) +#define _wcsset_l(_Destination,_Value,_Locale) (_wcsset(_Destination,_Value)) + + /* dirent structures and functions */ +#define _tdirent _wdirent +#define _TDIR _WDIR +#define _topendir _wopendir +#define _tclosedir _wclosedir +#define _treaddir _wreaddir +#define _trewinddir _wrewinddir +#define _ttelldir _wtelldir +#define _tseekdir _wseekdir + +#else + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define _TEOF EOF + +#define __T(x) x + +#define _tmain main +#define _tWinMain WinMain +#ifdef _POSIX_ +#define _tenviron environ +#else +#define _tenviron _environ +#endif +#define __targv __argv + +#define _tprintf printf +#define _tprintf_l _printf_l +#define _tprintf_p _printf_p +#define _tprintf_p_l _printf_p_l +#define _tcprintf _cprintf +#define _tcprintf_l _cprintf_l +#define _tcprintf_p _cprintf_p +#define _tcprintf_p_l _cprintf_p_l +#define _vtcprintf _vcprintf +#define _vtcprintf_l _vcprintf_l +#define _vtcprintf_p _vcprintf_p +#define _vtcprintf_p_l _vcprintf_p_l +#define _ftprintf fprintf +#define _ftprintf_l _fprintf_l +#define _ftprintf_p _fprintf_p +#define _ftprintf_p_l _fprintf_p_l +#define _stprintf sprintf +#define _stprintf_l _sprintf_l +#define _stprintf_p _sprintf_p +#define _stprintf_p_l _sprintf_p_l +#define _sctprintf _scprintf +#define _sctprintf_l _scprintf_l +#define _sctprintf_p _scprintf_p +#define _sctprintf_p_l _scprintf_p_l +#define _sntprintf _snprintf +#define _sntprintf_l _snprintf_l +#define _vtprintf vprintf +#define _vtprintf_l _vprintf_l +#define _vtprintf_p _vprintf_p +#define _vtprintf_p_l _vprintf_p_l +#define _vftprintf vfprintf +#define _vftprintf_l _vfprintf_l +#define _vftprintf_p _vfprintf_p +#define _vftprintf_p_l _vfprintf_p_l +#define _vstprintf vsprintf +#define _vstprintf_l _vsprintf_l +#define _vstprintf_p _vsprintf_p +#define _vstprintf_p_l _vsprintf_p_l +#define _vsctprintf _vscprintf +#define _vsctprintf_l _vscprintf_l +#define _vsctprintf_p _vscprintf_p +#define _vsctprintf_p_l _vscprintf_p_l +#define _vsntprintf _vsnprintf +#define _vsntprintf_l _vsnprintf_l + +#define _tscanf scanf +#define _tscanf_l _scanf_l +#define _tcscanf _cscanf +#define _tcscanf_l _cscanf_l +#define _ftscanf fscanf +#define _ftscanf_l _fscanf_l +#define _stscanf sscanf +#define _stscanf_l _sscanf_l +#define _sntscanf _snscanf +#define _sntscanf_l _snscanf_l + +#define _fgettc fgetc +#define _fgettc_nolock _fgetc_nolock +#define _fgettchar _fgetchar +#define _fgetts fgets +#define _fputtc fputc +#define _fputtc_nolock _fputc_nolock +#define _fputtchar _fputchar +#define _fputts fputs +#define _cputts _cputs +#define _gettc getc +#define _gettc_nolock _getc_nolock +#define _gettch _getch +#define _gettch_nolock _getch_nolock +#define _gettche _getche +#define _gettche_nolock _getche_nolock +#define _gettchar getchar +#define _gettchar_nolock _getchar_nolock +#define _getts gets +#define _cgetts _cgets +#define _puttc putc +#define _puttc_nolock _putc_nolock +#define _puttchar putchar +#define _puttchar_nolock _putchar_nolock +#define _puttch _putch +#define _puttch_nolock _putch_nolock +#define _putts puts +#define _ungettc ungetc +#define _ungettc_nolock _ungetc_nolock +#define _ungettch _ungetch +#define _ungettch_nolock _ungetch_nolock + +#define _tcstod strtod +#define _tcstol strtol +#define _tcstoul strtoul +#define _tstof atof +#define _tstol atol +#define _tstoi atoi +#define _tstoi64 _atoi64 +#define _tcstod_l _strtod_l +#define _tcstol_l _strtol_l +#define _tcstoul_l _strtoul_l +#define _tstof_l _atof_l +#define _tstol_l _atol_l +#define _tstoi_l _atoi_l +#define _tstoi64_l _atoi64_l + +#define _itot _itoa +#define _ltot _ltoa +#define _ultot _ultoa +#define _ttoi atoi +#define _ttol atol + +#define _ttoi64 _atoi64 +#define _tcstoi64 _strtoi64 +#define _tcstoi64_l _strtoi64_l +#define _tcstoui64 _strtoui64 +#define _tcstoui64_l _strtoui64_l +#define _i64tot _i64toa +#define _ui64tot _ui64toa + +#define _tcscat strcat +#define _tcscpy strcpy +#define _tcsdup _strdup +#define _tcslen strlen +#if 0 +#define _tcsnlen strnlen +#endif +#define _tcsxfrm strxfrm +#define _tcsxfrm_l _strxfrm_l +#define _tcserror strerror +#define __tcserror _strerror + +#define _texecl _execl +#define _texecle _execle +#define _texeclp _execlp +#define _texeclpe _execlpe +#define _texecv _execv +#define _texecve _execve +#define _texecvp _execvp +#define _texecvpe _execvpe + +#define _tspawnl _spawnl +#define _tspawnle _spawnle +#define _tspawnlp _spawnlp +#define _tspawnlpe _spawnlpe +#define _tspawnv _spawnv +#define _tspawnve _spawnve +#define _tspawnvp _spawnvp +#define _tspawnvpe _spawnvpe + +#define _tsystem system + +#define _tasctime asctime +#define _tctime ctime +#define _tctime32 _ctime32 +#define _tctime64 _ctime64 +#define _tstrdate _strdate +#define _tstrtime _strtime +#define _tutime _utime +#define _tutime32 _utime32 +#define _tutime64 _utime64 +#define _tcsftime strftime +#define _tcsftime_l _strftime_l + +#define _tchdir _chdir +#define _tgetcwd _getcwd +#define _tgetdcwd _getdcwd +#define _tgetdcwd_nolock _getdcwd_nolock +#define _tmkdir _mkdir +#define _trmdir _rmdir + +#define _tfullpath _fullpath +#define _tgetenv getenv +#define _tmakepath _makepath +#define _tpgmptr _pgmptr +#define _get_tpgmptr _get_pgmptr +#define _tputenv _putenv +#define _tsearchenv _searchenv +#define _tsplitpath _splitpath + +#ifdef _POSIX_ +#define _tfdopen fdopen +#else +#define _tfdopen _fdopen +#endif +#define _tfsopen _fsopen +#define _tfopen fopen +#define _tfreopen freopen +#define _tperror perror +#define _tpopen _popen +#define _ttempnam _tempnam +#define _ttmpnam tmpnam + +#define _tchmod _chmod +#define _tcreat _creat +#define _tfindfirst _findfirst +#define _tfindfirst32 _findfirst32 +#define _tfindfirst64 _findfirst64 +#define _tfindfirsti64 _findfirsti64 +#define _tfindfirst32i64 _findfirst32i64 +#define _tfindfirst64i32 _findfirst64i32 +#define _tfindnext _findnext +#define _tfindnext32 _findnext32 +#define _tfindnext64 _findnext64 +#define _tfindnexti64 _findnexti64 +#define _tfindnext32i64 _findnext32i64 +#define _tfindnext64i32 _findnext64i32 +#define _tmktemp _mktemp + +#ifdef _POSIX_ +#define _topen open +#define _taccess access +#else +#define _topen _open +#define _taccess _access +#endif + +#define _tremove remove +#define _trename rename +#define _tsopen _sopen +#define _tunlink _unlink + +#define _tfinddata_t _finddata_t +#define _tfinddata32_t _finddata32_t +#define _tfinddata64_t __finddata64_t +#define _tfinddatai64_t _finddatai64_t +#define _tfinddata32i64_t _finddata32i64_t +#define _tfinddata64i32_t _finddata64i32_t + +#define _istascii __isascii +#define _istcntrl iscntrl +#define _istcntrl_l _iscntrl_l +#define _istxdigit isxdigit +#define _istxdigit_l _isxdigit_l + +#define _tstat _stat +#define _tstat32 _stat32 +#define _tstat32i64 _stat32i64 +#define _tstat64 _stat64 +#define _tstat64i32 _stat64i32 +#define _tstati64 _stati64 + +#define _tsetlocale setlocale + +#ifdef _MBCS + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __TCHAR_DEFINED + typedef char _TCHAR; + typedef signed char _TSCHAR; + typedef unsigned char _TUCHAR; + typedef unsigned char _TXCHAR; + typedef unsigned int _TINT; +#define __TCHAR_DEFINED +#endif + +#ifndef _TCHAR_DEFINED +#ifndef NO_OLDNAMES + typedef char TCHAR; +#endif +#define _TCHAR_DEFINED +#endif + +#ifdef _MB_MAP_DIRECT + +#define _tcschr _mbschr +#define _tcscspn _mbscspn +#define _tcsncat _mbsnbcat +#define _tcsncat_l _mbsnbcat_l +#define _tcsncpy _mbsnbcpy +#define _tcsncpy_l _mbsnbcpy_l +#define _tcspbrk _mbspbrk +#define _tcsrchr _mbsrchr +#define _tcsspn _mbsspn +#define _tcsstr _mbsstr +#define _tcstok _mbstok +#define _tcstok_l _mbstok_l + +#define _tcsnset _mbsnbset +#define _tcsnset_l _mbsnbset_l +#define _tcsrev _mbsrev +#define _tcsset _mbsset +#define _tcsset_l _mbsset_l + +#define _tcscmp _mbscmp +#define _tcsicmp _mbsicmp +#define _tcsicmp_l _mbsicmp_l +#define _tcsnccmp _mbsncmp +#define _tcsncmp _mbsnbcmp +#define _tcsncicmp _mbsnicmp +#define _tcsncicmp_l _mbsnicmp_l +#define _tcsnicmp _mbsnbicmp +#define _tcsnicmp_l _mbsnbicmp_l + +#define _tcscoll _mbscoll +#define _tcscoll_l _mbscoll_l +#define _tcsicoll _mbsicoll +#define _tcsicoll_l _mbsicoll_l +#define _tcsnccoll _mbsncoll +#define _tcsnccoll_l _mbsncoll_l +#define _tcsncoll _mbsnbcoll +#define _tcsncoll_l _mbsnbcoll_l +#define _tcsncicoll _mbsnicoll +#define _tcsncicoll_l _mbsnicoll_l +#define _tcsnicoll _mbsnbicoll +#define _tcsnicoll_l _mbsnbicoll_l + +#define _tcsclen _mbslen +#define _tcscnlen _mbsnlen +#define _tcsclen_l _mbslen_l +#define _tcscnlen_l _mbsnlen_l +#define _tcsnccat _mbsncat +#define _tcsnccat_l _mbsncat_l +#define _tcsnccpy _mbsncpy +#define _tcsnccpy_l _mbsncpy_l +#define _tcsncset _mbsnset +#define _tcsncset_l _mbsnset_l + +#define _tcsdec _mbsdec +#define _tcsinc _mbsinc +#define _tcsnbcnt _mbsnbcnt +#define _tcsnccnt _mbsnccnt +#define _tcsnextc _mbsnextc +#define _tcsninc _mbsninc +#define _tcsspnp _mbsspnp + +#define _tcslwr _mbslwr +#define _tcslwr_l _mbslwr_l +#define _tcsupr _mbsupr +#define _tcsupr_l _mbsupr_l + +#define _tclen _mbclen +#define _tccpy _mbccpy +#define _tccpy_l _mbccpy_l +#else + + _CRTIMP _CONST_RETURN char *__cdecl _tcschr(const char *_Str,unsigned int _Val); + _CRTIMP size_t __cdecl _tcscspn(const char *_Str,const char *_Control); + _CRTIMP char *__cdecl _tcsncat(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsncpy(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsncpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP _CONST_RETURN char *__cdecl _tcspbrk(const char *_Str,const char *_Control); + _CRTIMP _CONST_RETURN char *__cdecl _tcsrchr(const char *_Str,unsigned int _Ch); + _CRTIMP size_t __cdecl _tcsspn(const char *_Str,const char *_Control); + _CRTIMP _CONST_RETURN char *__cdecl _tcsstr(const char *_Str,const char *_Substr); + _CRTIMP char *__cdecl _tcstok(char *_Str,const char *_Delim); + _CRTIMP char *__cdecl _tcstok_l(char *_Str,const char *_Delim,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnset(char *_Str,unsigned int _Val,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsrev(char *_Str); + _CRTIMP char *__cdecl _tcsset(char *_Str,unsigned int _Val); + _CRTIMP char *__cdecl _tcsset_l(char *_Str,unsigned int _Val,_locale_t _Locale); + _CRTIMP int __cdecl _tcscmp(const char *_Str1,const char *_Str); + _CRTIMP int __cdecl _tcsicmp(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _tcsicmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnccmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcscoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _tcscoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _tcsicoll(const char *_Str1,const char *_Str2); + _CRTIMP int __cdecl _tcsicoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnccoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsnccoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsncoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsncicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsncicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _tcsnicoll(const char *_Str1,const char *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _tcsnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP size_t __cdecl _tcsclen(const char *_Str); + _CRTIMP size_t __cdecl _tcscnlen(const char *_Str,size_t _MaxCount); + _CRTIMP size_t __cdecl _tcsclen_l(const char *_Str,_locale_t _Locale); + _CRTIMP size_t __cdecl _tcscnlen_l(const char *_Str,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccat(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccat_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsnccpy(char *_Dst,const char *_Src,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsnccpy_l(char *_Dst,const char *_Src,size_t _MaxCount,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsncset(char *_Str,unsigned int _Val,size_t _MaxCount); + _CRTIMP char *__cdecl _tcsdec(const char *_Start,const char *_Pos); + _CRTIMP char *__cdecl _tcsinc(const char *_Ptr); + _CRTIMP size_t __cdecl _tcsnbcnt(const char *_Str,size_t _MaxCount); + _CRTIMP size_t __cdecl _tcsnccnt(const char *_Str,size_t _MaxCount); + _CRTIMP unsigned int __cdecl _tcsnextc (const char *_Str); + _CRTIMP char *__cdecl _tcsninc(const char *_Ptr,size_t _Count); + _CRTIMP char *__cdecl _tcsspnp(const char *_Str1,const char *_Str2); + _CRTIMP char *__cdecl _tcslwr(char *_Str); + _CRTIMP char *__cdecl _tcslwr_l(char *_Str,_locale_t _Locale); + _CRTIMP char *__cdecl _tcsupr(char *_Str); + _CRTIMP char *__cdecl _tcsupr_l(char *_Str,_locale_t _Locale); + _CRTIMP size_t __cdecl _tclen(const char *_Str); + _CRTIMP void __cdecl _tccpy(char *_DstCh,const char *_SrcCh); + +#ifdef __cplusplus +#ifndef _CPP_TCHAR_INLINES_DEFINED +#define _CPP_TCHAR_INLINES_DEFINED + extern "C++" { + extern inline char *__cdecl _tcschr(char *_S,unsigned int _C) { return ((char *)_tcschr((const char *)_S,_C)); } + extern inline char *__cdecl _tcspbrk(char *_S,const char *_P) { return ((char *)_tcspbrk((const char *)_S,_P)); } + extern inline char *__cdecl _tcsrchr(char *_S,unsigned int _C) { return ((char *)_tcsrchr((const char *)_S,_C)); } + extern inline char *__cdecl _tcsstr(char *_S,const char *_P) { return ((char *)_tcsstr((const char *)_S,_P)); } + } +#endif +#endif +#endif + +#define _tccmp(_cp1,_cp2) _tcsnccmp(_cp1,_cp2,1) + +#define _istalnum _ismbcalnum +#define _istalnum_l _ismbcalnum_l +#define _istalpha _ismbcalpha +#define _istalpha_l _ismbcalpha_l +#define _istdigit _ismbcdigit +#define _istdigit_l _ismbcdigit_l +#define _istgraph _ismbcgraph +#define _istgraph_l _ismbcgraph_l +#define _istlegal _ismbclegal +#define _istlegal_l _ismbclegal_l +#define _istlower _ismbclower +#define _istlower_l _ismbclower_l +#define _istprint _ismbcprint +#define _istprint_l _ismbcprint_l +#define _istpunct _ismbcpunct +#define _istpunct_l _ismbcpunct_l +#define _istspace _ismbcspace +#define _istspace_l _ismbcspace_l +#define _istupper _ismbcupper +#define _istupper_l _ismbcupper_l + +#define _totupper _mbctoupper +#define _totupper_l _mbctoupper_l +#define _totlower _mbctolower +#define _totlower_l _mbctolower_l + +#define _istlead _ismbblead +#define _istleadbyte isleadbyte +#define _istleadbyte_l _isleadbyte_l +#else + +#ifndef __TCHAR_DEFINED +#define __TCHAR_DEFINED + typedef char _TCHAR; + typedef signed char _TSCHAR; + typedef unsigned char _TUCHAR; + typedef char _TXCHAR; + typedef int _TINT; +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +#ifndef NO_OLDNAMES + typedef char TCHAR; +#endif +#endif + +#define _tcschr strchr +#define _tcscspn strcspn +#define _tcsncat strncat +#define _tcsncat_l _strncat_l +#define _tcsncpy strncpy +#define _tcsncpy_l _strncpy_l +#define _tcspbrk strpbrk +#define _tcsrchr strrchr +#define _tcsspn strspn +#define _tcsstr strstr +#define _tcstok strtok +#define _tcstok_l _strtok_l + +#define _tcsnset _strnset +#define _tcsnset_l _strnset_l +#define _tcsrev _strrev +#define _tcsset _strset + +#define _tcscmp strcmp +#define _tcsicmp _stricmp +#define _tcsicmp_l _stricmp_l +#define _tcsnccmp strncmp +#define _tcsncmp strncmp +#define _tcsncicmp _strnicmp +#define _tcsncicmp_l _strnicmp_l +#define _tcsnicmp _strnicmp +#define _tcsnicmp_l _strnicmp_l + +#define _tcscoll strcoll +#define _tcscoll_l _strcoll_l +#define _tcsicoll _stricoll +#define _tcsicoll_l _stricoll_l +#define _tcsnccoll _strncoll +#define _tcsnccoll_l _strncoll_l +#define _tcsncoll _strncoll +#define _tcsncoll_l _strncoll_l +#define _tcsncicoll _strnicoll +#define _tcsncicoll_l _strnicoll_l +#define _tcsnicoll _strnicoll +#define _tcsnicoll_l _strnicoll_l + +#define _tcsclen strlen +#define _tcscnlen strnlen +#define _tcsclen_l(_String,_Locale) strlen(_String) +#define _tcscnlen_l(_String,_Max_count,_Locale) strnlen_l((_String),(_Max_count)) +#define _tcsnccat strncat +#define _tcsnccat_l _strncat_l +#define _tcsnccpy strncpy +#define _tcsnccpy_l _strncpy_l +#define _tcsncset _strnset + +#define _tcsdec _strdec +#define _tcsinc _strinc +#define _tcsnbcnt _strncnt +#define _tcsnccnt _strncnt +#define _tcsnextc _strnextc +#define _tcsninc _strninc +#define _tcsspnp _strspnp + +#define _tcslwr _strlwr +#define _tcslwr_l _strlwr_l +#define _tcsupr _strupr +#define _tcsupr_l _strupr_l +#define _tcsxfrm strxfrm +#define _tcsxfrm_l _strxfrm_l + +#define _istlead(_Char) (0) +#define _istleadbyte(_Char) (0) +#define _istleadbyte_l(_Char,_Locale) (0) + +#define _tclen(_pc) (1) +#define _tccpy(_pc1,_cpc2) (*(_pc1) = *(_cpc2)) +#define _tccmp(_cpc1,_cpc2) (((unsigned char)*(_cpc1))-((unsigned char)*(_cpc2))) + + /* dirent structures and functions */ +#define _tdirent dirent +#define _TDIR DIR +#define _topendir opendir +#define _tclosedir closedir +#define _treaddir readdir +#define _trewinddir rewinddir +#define _ttelldir telldir +#define _tseekdir seekdir + +#define _istalnum isalnum +#define _istalnum_l _isalnum_l +#define _istalpha isalpha +#define _istalpha_l _isalpha_l +#define _istdigit isdigit +#define _istdigit_l _isdigit_l +#define _istgraph isgraph +#define _istgraph_l _isgraph_l +#define _istlower islower +#define _istlower_l _islower_l +#define _istprint isprint +#define _istprint_l _isprint_l +#define _istpunct ispunct +#define _istpunct_l _ispunct_l +#define _istspace isspace +#define _istspace_l _isspace_l +#define _istupper isupper +#define _istupper_l _isupper_l + +#define _totupper toupper +#define _totupper_l _toupper_l +#define _totlower tolower +#define _totlower_l _tolower_l + +#define _istlegal(_c) (1) + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#define _strdec(_cpc1,_cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1) +#define _strinc(_pc) ((_pc)+1) +#define _strnextc(_cpc) ((unsigned int) *(const unsigned char *)(_cpc)) +#define _strninc(_pc,_sz) (((_pc)+(_sz))) + _CRTIMP size_t __cdecl __strncnt(const char *_Str,size_t _Cnt); +#define _strncnt(_cpc,_sz) (__strncnt(_cpc,_sz)) +#define _strspnp(_cpc1,_cpc2) (!_cpc1 ? NULL : ((*((_cpc1)+strspn(_cpc1,_cpc2))) ? ((_cpc1)+strspn(_cpc1,_cpc2)) : NULL)) + +#define _strncpy_l(_Destination,_Source,_Count,_Locale) (strncpy(_Destination,_Source,_Count)) +#define _strncat_l(_Destination,_Source,_Count,_Locale) (strncat(_Destination,_Source,_Count)) +#define _strtok_l(_String,_Delimiters,_Locale) (strtok(_String,_Delimiters)) +#define _strnset_l(_Destination,_Value,_Count,_Locale) (_strnset(_Destination,_Value,_Count)) +#define _strset_l(_Destination,_Value,_Locale) (_strset(_Destination,_Value)) +#endif +#endif + +#define _T(x) __T(x) +#define _TEXT(x) __T(x) + +#ifdef __cplusplus +} +#endif + +#include +#endif diff --git a/tcc/include/tgmath.h b/tcc/include/tgmath.h index 46ff48b2..5d3e3578 100644 --- a/tcc/include/tgmath.h +++ b/tcc/include/tgmath.h @@ -1,89 +1,89 @@ -/* - * ISO C Standard: 7.22 Type-generic math - */ - -#ifndef _TGMATH_H -#define _TGMATH_H - -#include - -#ifndef __cplusplus -#define __tgmath_real(x, F) \ - _Generic ((x), float: F##f, long double: F##l, default: F)(x) -#define __tgmath_real_2_1(x, y, F) \ - _Generic ((x), float: F##f, long double: F##l, default: F)(x, y) -#define __tgmath_real_2(x, y, F) \ - _Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y) -#define __tgmath_real_3_2(x, y, z, F) \ - _Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y, z) -#define __tgmath_real_3(x, y, z, F) \ - _Generic ((x)+(y)+(z), float: F##f, long double: F##l, default: F)(x, y, z) - -/* Functions defined in both and (7.22p4) */ -#define acos(z) __tgmath_real(z, acos) -#define asin(z) __tgmath_real(z, asin) -#define atan(z) __tgmath_real(z, atan) -#define acosh(z) __tgmath_real(z, acosh) -#define asinh(z) __tgmath_real(z, asinh) -#define atanh(z) __tgmath_real(z, atanh) -#define cos(z) __tgmath_real(z, cos) -#define sin(z) __tgmath_real(z, sin) -#define tan(z) __tgmath_real(z, tan) -#define cosh(z) __tgmath_real(z, cosh) -#define sinh(z) __tgmath_real(z, sinh) -#define tanh(z) __tgmath_real(z, tanh) -#define exp(z) __tgmath_real(z, exp) -#define log(z) __tgmath_real(z, log) -#define pow(z1,z2) __tgmath_real_2(z1, z2, pow) -#define sqrt(z) __tgmath_real(z, sqrt) -#define fabs(z) __tgmath_real(z, fabs) - -/* Functions defined in only (7.22p5) */ -#define atan2(x,y) __tgmath_real_2(x, y, atan2) -#define cbrt(x) __tgmath_real(x, cbrt) -#define ceil(x) __tgmath_real(x, ceil) -#define copysign(x,y) __tgmath_real_2(x, y, copysign) -#define erf(x) __tgmath_real(x, erf) -#define erfc(x) __tgmath_real(x, erfc) -#define exp2(x) __tgmath_real(x, exp2) -#define expm1(x) __tgmath_real(x, expm1) -#define fdim(x,y) __tgmath_real_2(x, y, fdim) -#define floor(x) __tgmath_real(x, floor) -#define fma(x,y,z) __tgmath_real_3(x, y, z, fma) -#define fmax(x,y) __tgmath_real_2(x, y, fmax) -#define fmin(x,y) __tgmath_real_2(x, y, fmin) -#define fmod(x,y) __tgmath_real_2(x, y, fmod) -#define frexp(x,y) __tgmath_real_2_1(x, y, frexp) -#define hypot(x,y) __tgmath_real_2(x, y, hypot) -#define ilogb(x) __tgmath_real(x, ilogb) -#define ldexp(x,y) __tgmath_real_2_1(x, y, ldexp) -#define lgamma(x) __tgmath_real(x, lgamma) -#define llrint(x) __tgmath_real(x, llrint) -#define llround(x) __tgmath_real(x, llround) -#define log10(x) __tgmath_real(x, log10) -#define log1p(x) __tgmath_real(x, log1p) -#define log2(x) __tgmath_real(x, log2) -#define logb(x) __tgmath_real(x, logb) -#define lrint(x) __tgmath_real(x, lrint) -#define lround(x) __tgmath_real(x, lround) -#define nearbyint(x) __tgmath_real(x, nearbyint) -#define nextafter(x,y) __tgmath_real_2(x, y, nextafter) -#define nexttoward(x,y) __tgmath_real_2(x, y, nexttoward) -#define remainder(x,y) __tgmath_real_2(x, y, remainder) -#define remquo(x,y,z) __tgmath_real_3_2(x, y, z, remquo) -#define rint(x) __tgmath_real(x, rint) -#define round(x) __tgmath_real(x, round) -#define scalbln(x,y) __tgmath_real_2_1(x, y, scalbln) -#define scalbn(x,y) __tgmath_real_2_1(x, y, scalbn) -#define tgamma(x) __tgmath_real(x, tgamma) -#define trunc(x) __tgmath_real(x, trunc) - -/* Functions defined in only (7.22p6) -#define carg(z) __tgmath_cplx_only(z, carg) -#define cimag(z) __tgmath_cplx_only(z, cimag) -#define conj(z) __tgmath_cplx_only(z, conj) -#define cproj(z) __tgmath_cplx_only(z, cproj) -#define creal(z) __tgmath_cplx_only(z, creal) -*/ -#endif /* __cplusplus */ -#endif /* _TGMATH_H */ +/* + * ISO C Standard: 7.22 Type-generic math + */ + +#ifndef _TGMATH_H +#define _TGMATH_H + +#include + +#ifndef __cplusplus +#define __tgmath_real(x, F) \ + _Generic ((x), float: F##f, long double: F##l, default: F)(x) +#define __tgmath_real_2_1(x, y, F) \ + _Generic ((x), float: F##f, long double: F##l, default: F)(x, y) +#define __tgmath_real_2(x, y, F) \ + _Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y) +#define __tgmath_real_3_2(x, y, z, F) \ + _Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y, z) +#define __tgmath_real_3(x, y, z, F) \ + _Generic ((x)+(y)+(z), float: F##f, long double: F##l, default: F)(x, y, z) + +/* Functions defined in both and (7.22p4) */ +#define acos(z) __tgmath_real(z, acos) +#define asin(z) __tgmath_real(z, asin) +#define atan(z) __tgmath_real(z, atan) +#define acosh(z) __tgmath_real(z, acosh) +#define asinh(z) __tgmath_real(z, asinh) +#define atanh(z) __tgmath_real(z, atanh) +#define cos(z) __tgmath_real(z, cos) +#define sin(z) __tgmath_real(z, sin) +#define tan(z) __tgmath_real(z, tan) +#define cosh(z) __tgmath_real(z, cosh) +#define sinh(z) __tgmath_real(z, sinh) +#define tanh(z) __tgmath_real(z, tanh) +#define exp(z) __tgmath_real(z, exp) +#define log(z) __tgmath_real(z, log) +#define pow(z1,z2) __tgmath_real_2(z1, z2, pow) +#define sqrt(z) __tgmath_real(z, sqrt) +#define fabs(z) __tgmath_real(z, fabs) + +/* Functions defined in only (7.22p5) */ +#define atan2(x,y) __tgmath_real_2(x, y, atan2) +#define cbrt(x) __tgmath_real(x, cbrt) +#define ceil(x) __tgmath_real(x, ceil) +#define copysign(x,y) __tgmath_real_2(x, y, copysign) +#define erf(x) __tgmath_real(x, erf) +#define erfc(x) __tgmath_real(x, erfc) +#define exp2(x) __tgmath_real(x, exp2) +#define expm1(x) __tgmath_real(x, expm1) +#define fdim(x,y) __tgmath_real_2(x, y, fdim) +#define floor(x) __tgmath_real(x, floor) +#define fma(x,y,z) __tgmath_real_3(x, y, z, fma) +#define fmax(x,y) __tgmath_real_2(x, y, fmax) +#define fmin(x,y) __tgmath_real_2(x, y, fmin) +#define fmod(x,y) __tgmath_real_2(x, y, fmod) +#define frexp(x,y) __tgmath_real_2_1(x, y, frexp) +#define hypot(x,y) __tgmath_real_2(x, y, hypot) +#define ilogb(x) __tgmath_real(x, ilogb) +#define ldexp(x,y) __tgmath_real_2_1(x, y, ldexp) +#define lgamma(x) __tgmath_real(x, lgamma) +#define llrint(x) __tgmath_real(x, llrint) +#define llround(x) __tgmath_real(x, llround) +#define log10(x) __tgmath_real(x, log10) +#define log1p(x) __tgmath_real(x, log1p) +#define log2(x) __tgmath_real(x, log2) +#define logb(x) __tgmath_real(x, logb) +#define lrint(x) __tgmath_real(x, lrint) +#define lround(x) __tgmath_real(x, lround) +#define nearbyint(x) __tgmath_real(x, nearbyint) +#define nextafter(x,y) __tgmath_real_2(x, y, nextafter) +#define nexttoward(x,y) __tgmath_real_2(x, y, nexttoward) +#define remainder(x,y) __tgmath_real_2(x, y, remainder) +#define remquo(x,y,z) __tgmath_real_3_2(x, y, z, remquo) +#define rint(x) __tgmath_real(x, rint) +#define round(x) __tgmath_real(x, round) +#define scalbln(x,y) __tgmath_real_2_1(x, y, scalbln) +#define scalbn(x,y) __tgmath_real_2_1(x, y, scalbn) +#define tgamma(x) __tgmath_real(x, tgamma) +#define trunc(x) __tgmath_real(x, trunc) + +/* Functions defined in only (7.22p6) +#define carg(z) __tgmath_cplx_only(z, carg) +#define cimag(z) __tgmath_cplx_only(z, cimag) +#define conj(z) __tgmath_cplx_only(z, conj) +#define cproj(z) __tgmath_cplx_only(z, cproj) +#define creal(z) __tgmath_cplx_only(z, creal) +*/ +#endif /* __cplusplus */ +#endif /* _TGMATH_H */ diff --git a/tcc/include/time.h b/tcc/include/time.h index 7846d2f2..6c72e266 100644 --- a/tcc/include/time.h +++ b/tcc/include/time.h @@ -1,287 +1,287 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _TIME_H_ -#define _TIME_H_ - -#include <_mingw.h> - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef _WCHAR_T_DEFINED -#define _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#endif - -#ifndef _TIME32_T_DEFINED -#define _TIME32_T_DEFINED - typedef long __time32_t; -#endif - -#ifndef _TIME64_T_DEFINED -#define _TIME64_T_DEFINED -#if _INTEGRAL_MAX_BITS >= 64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int _time64_t __attribute__ ((mode (DI))); -#else - typedef __int64 __time64_t; -#endif -#endif -#endif - -#ifndef _TIME_T_DEFINED -#define _TIME_T_DEFINED -#ifdef _USE_32BIT_TIME_T - typedef __time32_t time_t; -#else - typedef __time64_t time_t; -#endif -#endif - -#ifndef _CLOCK_T_DEFINED -#define _CLOCK_T_DEFINED - typedef long clock_t; -#endif - -#ifndef _SIZE_T_DEFINED -#define _SIZE_T_DEFINED -#undef size_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef unsigned int size_t __attribute__ ((mode (DI))); -#else - typedef unsigned __int64 size_t; -#endif -#else - typedef unsigned int size_t; -#endif -#endif - -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#undef ssize_t -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int ssize_t __attribute__ ((mode (DI))); -#else - typedef __int64 ssize_t; -#endif -#else - typedef int ssize_t; -#endif -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifdef _USE_32BIT_TIME_T -#define _localtime32 localtime -#define _difftime32 difftime -#define _ctime32 ctime -#define _gmtime32 gmtime -#define _mktime32 mktime -#define _time32 time -#endif - -#ifndef _TM_DEFINED -#define _TM_DEFINED - struct tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - }; -#endif - -#define CLOCKS_PER_SEC 1000 - - __MINGW_IMPORT int _daylight; - __MINGW_IMPORT long _dstbias; - __MINGW_IMPORT long _timezone; - __MINGW_IMPORT char * _tzname[2]; - _CRTIMP errno_t __cdecl _get_daylight(int *_Daylight); - _CRTIMP errno_t __cdecl _get_dstbias(long *_Daylight_savings_bias); - _CRTIMP errno_t __cdecl _get_timezone(long *_Timezone); - _CRTIMP errno_t __cdecl _get_tzname(size_t *_ReturnValue,char *_Buffer,size_t _SizeInBytes,int _Index); - char *__cdecl asctime(const struct tm *_Tm); - _CRTIMP char *__cdecl _ctime32(const __time32_t *_Time); - clock_t __cdecl clock(void); - _CRTIMP double __cdecl _difftime32(__time32_t _Time1,__time32_t _Time2); - _CRTIMP struct tm *__cdecl _gmtime32(const __time32_t *_Time); - _CRTIMP struct tm *__cdecl _localtime32(const __time32_t *_Time); - size_t __cdecl strftime(char *_Buf,size_t _SizeInBytes,const char *_Format,const struct tm *_Tm); - _CRTIMP size_t __cdecl _strftime_l(char *_Buf,size_t _Max_size,const char *_Format,const struct tm *_Tm,_locale_t _Locale); - _CRTIMP char *__cdecl _strdate(char *_Buffer); - _CRTIMP char *__cdecl _strtime(char *_Buffer); - _CRTIMP __time32_t __cdecl _time32(__time32_t *_Time); - _CRTIMP __time32_t __cdecl _mktime32(struct tm *_Tm); - _CRTIMP __time32_t __cdecl _mkgmtime32(struct tm *_Tm); -#if defined (_POSIX_) || defined(__GNUC__) - void __cdecl tzset(void); -#else - _CRTIMP void __cdecl _tzset(void); -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - double __cdecl _difftime64(__time64_t _Time1,__time64_t _Time2); - _CRTIMP char *__cdecl _ctime64(const __time64_t *_Time); - _CRTIMP struct tm *__cdecl _gmtime64(const __time64_t *_Time); - _CRTIMP struct tm *__cdecl _localtime64(const __time64_t *_Time); - _CRTIMP __time64_t __cdecl _mktime64(struct tm *_Tm); - _CRTIMP __time64_t __cdecl _mkgmtime64(struct tm *_Tm); - _CRTIMP __time64_t __cdecl _time64(__time64_t *_Time); -#endif - unsigned __cdecl _getsystime(struct tm *_Tm); - unsigned __cdecl _setsystime(struct tm *_Tm,unsigned _MilliSec); - -#ifndef _SIZE_T_DEFINED -#define _SIZE_T_DEFINED -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef unsigned int size_t __attribute__ ((mode (DI))); -#else - typedef unsigned __int64 size_t; -#endif -#else - typedef unsigned long size_t; -#endif -#endif - -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#ifdef _WIN64 -#if defined(__GNUC__) && defined(__STRICT_ANSI__) - typedef int ssize_t __attribute__ ((mode (DI))); -#else - typedef __int64 ssize_t; -#endif -#else - typedef long ssize_t; -#endif -#endif - -#ifndef _WTIME_DEFINED - _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); - _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); - size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); - _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); - _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) -#define _INC_WTIME_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } -#else -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } -#endif -#endif - -#define _WTIME_DEFINED -#endif - -#ifndef RC_INVOKED -double __cdecl difftime(time_t _Time1,time_t _Time2); -char *__cdecl ctime(const time_t *_Time); -struct tm *__cdecl gmtime(const time_t *_Time); -struct tm *__cdecl localtime(const time_t *_Time); -struct tm *__cdecl localtime_r(const time_t *_Time,struct tm *); - -time_t __cdecl mktime(struct tm *_Tm); -time_t __cdecl _mkgmtime(struct tm *_Tm); -time_t __cdecl time(time_t *_Time); - -#ifdef _USE_32BIT_TIME_T -#if 0 -__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime32(_Time1,_Time2); } -__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime32(_Time); } -__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime32(_Time); } -__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime32(_Time); } -__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime32(_Tm); } -__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime32(_Tm); } -__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time32(_Time); } -#endif -#else -__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime64(_Time1,_Time2); } -__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime64(_Time); } -__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime64(_Time); } -__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime64(_Time); } -__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime64(_Tm); } -__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime64(_Tm); } -__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time64(_Time); } -#endif -#endif - -#if !defined(NO_OLDNAMES) || defined(_POSIX) -#define CLK_TCK CLOCKS_PER_SEC - - __MINGW_IMPORT int daylight; - __MINGW_IMPORT long dstbias; - __MINGW_IMPORT long timezone; - __MINGW_IMPORT char *tzname[2]; - void __cdecl tzset(void); -#endif - -#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ -#define _TIMEVAL_DEFINED -struct timeval { - long tv_sec; - long tv_usec; -}; -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif /* _TIMEVAL_DEFINED */ - -#ifndef __STRICT_ANSI__ -#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ -#define _TIMEZONE_DEFINED -struct timezone { - int tz_minuteswest; - int tz_dsttime; -}; - - extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); -#endif -#endif /* __STRICT_ANSI__ */ - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include - -/* Adding timespec definition. */ -#include - -#endif /* End _TIME_H_ */ - +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _TIME_H_ +#define _TIME_H_ + +#include <_mingw.h> + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef _WCHAR_T_DEFINED +#define _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#endif + +#ifndef _TIME32_T_DEFINED +#define _TIME32_T_DEFINED + typedef long __time32_t; +#endif + +#ifndef _TIME64_T_DEFINED +#define _TIME64_T_DEFINED +#if _INTEGRAL_MAX_BITS >= 64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int _time64_t __attribute__ ((mode (DI))); +#else + typedef __int64 __time64_t; +#endif +#endif +#endif + +#ifndef _TIME_T_DEFINED +#define _TIME_T_DEFINED +#ifdef _USE_32BIT_TIME_T + typedef __time32_t time_t; +#else + typedef __time64_t time_t; +#endif +#endif + +#ifndef _CLOCK_T_DEFINED +#define _CLOCK_T_DEFINED + typedef long clock_t; +#endif + +#ifndef _SIZE_T_DEFINED +#define _SIZE_T_DEFINED +#undef size_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef unsigned int size_t __attribute__ ((mode (DI))); +#else + typedef unsigned __int64 size_t; +#endif +#else + typedef unsigned int size_t; +#endif +#endif + +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#undef ssize_t +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int ssize_t __attribute__ ((mode (DI))); +#else + typedef __int64 ssize_t; +#endif +#else + typedef int ssize_t; +#endif +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifdef _USE_32BIT_TIME_T +#define _localtime32 localtime +#define _difftime32 difftime +#define _ctime32 ctime +#define _gmtime32 gmtime +#define _mktime32 mktime +#define _time32 time +#endif + +#ifndef _TM_DEFINED +#define _TM_DEFINED + struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + }; +#endif + +#define CLOCKS_PER_SEC 1000 + + __MINGW_IMPORT int _daylight; + __MINGW_IMPORT long _dstbias; + __MINGW_IMPORT long _timezone; + __MINGW_IMPORT char * _tzname[2]; + _CRTIMP errno_t __cdecl _get_daylight(int *_Daylight); + _CRTIMP errno_t __cdecl _get_dstbias(long *_Daylight_savings_bias); + _CRTIMP errno_t __cdecl _get_timezone(long *_Timezone); + _CRTIMP errno_t __cdecl _get_tzname(size_t *_ReturnValue,char *_Buffer,size_t _SizeInBytes,int _Index); + char *__cdecl asctime(const struct tm *_Tm); + _CRTIMP char *__cdecl _ctime32(const __time32_t *_Time); + clock_t __cdecl clock(void); + _CRTIMP double __cdecl _difftime32(__time32_t _Time1,__time32_t _Time2); + _CRTIMP struct tm *__cdecl _gmtime32(const __time32_t *_Time); + _CRTIMP struct tm *__cdecl _localtime32(const __time32_t *_Time); + size_t __cdecl strftime(char *_Buf,size_t _SizeInBytes,const char *_Format,const struct tm *_Tm); + _CRTIMP size_t __cdecl _strftime_l(char *_Buf,size_t _Max_size,const char *_Format,const struct tm *_Tm,_locale_t _Locale); + _CRTIMP char *__cdecl _strdate(char *_Buffer); + _CRTIMP char *__cdecl _strtime(char *_Buffer); + _CRTIMP __time32_t __cdecl _time32(__time32_t *_Time); + _CRTIMP __time32_t __cdecl _mktime32(struct tm *_Tm); + _CRTIMP __time32_t __cdecl _mkgmtime32(struct tm *_Tm); +#if defined (_POSIX_) || defined(__GNUC__) + void __cdecl tzset(void); +#else + _CRTIMP void __cdecl _tzset(void); +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + double __cdecl _difftime64(__time64_t _Time1,__time64_t _Time2); + _CRTIMP char *__cdecl _ctime64(const __time64_t *_Time); + _CRTIMP struct tm *__cdecl _gmtime64(const __time64_t *_Time); + _CRTIMP struct tm *__cdecl _localtime64(const __time64_t *_Time); + _CRTIMP __time64_t __cdecl _mktime64(struct tm *_Tm); + _CRTIMP __time64_t __cdecl _mkgmtime64(struct tm *_Tm); + _CRTIMP __time64_t __cdecl _time64(__time64_t *_Time); +#endif + unsigned __cdecl _getsystime(struct tm *_Tm); + unsigned __cdecl _setsystime(struct tm *_Tm,unsigned _MilliSec); + +#ifndef _SIZE_T_DEFINED +#define _SIZE_T_DEFINED +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef unsigned int size_t __attribute__ ((mode (DI))); +#else + typedef unsigned __int64 size_t; +#endif +#else + typedef unsigned long size_t; +#endif +#endif + +#ifndef _SSIZE_T_DEFINED +#define _SSIZE_T_DEFINED +#ifdef _WIN64 +#if defined(__GNUC__) && defined(__STRICT_ANSI__) + typedef int ssize_t __attribute__ ((mode (DI))); +#else + typedef __int64 ssize_t; +#endif +#else + typedef long ssize_t; +#endif +#endif + +#ifndef _WTIME_DEFINED + _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); + _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); + size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); + _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); + _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) +#define _INC_WTIME_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } +#else +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } +#endif +#endif + +#define _WTIME_DEFINED +#endif + +#ifndef RC_INVOKED +double __cdecl difftime(time_t _Time1,time_t _Time2); +char *__cdecl ctime(const time_t *_Time); +struct tm *__cdecl gmtime(const time_t *_Time); +struct tm *__cdecl localtime(const time_t *_Time); +struct tm *__cdecl localtime_r(const time_t *_Time,struct tm *); + +time_t __cdecl mktime(struct tm *_Tm); +time_t __cdecl _mkgmtime(struct tm *_Tm); +time_t __cdecl time(time_t *_Time); + +#ifdef _USE_32BIT_TIME_T +#if 0 +__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime32(_Time1,_Time2); } +__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime32(_Time); } +__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime32(_Time); } +__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime32(_Time); } +__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime32(_Tm); } +__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime32(_Tm); } +__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time32(_Time); } +#endif +#else +__CRT_INLINE double __cdecl difftime(time_t _Time1,time_t _Time2) { return _difftime64(_Time1,_Time2); } +__CRT_INLINE char *__cdecl ctime(const time_t *_Time) { return _ctime64(_Time); } +__CRT_INLINE struct tm *__cdecl gmtime(const time_t *_Time) { return _gmtime64(_Time); } +__CRT_INLINE struct tm *__cdecl localtime(const time_t *_Time) { return _localtime64(_Time); } +__CRT_INLINE time_t __cdecl mktime(struct tm *_Tm) { return _mktime64(_Tm); } +__CRT_INLINE time_t __cdecl _mkgmtime(struct tm *_Tm) { return _mkgmtime64(_Tm); } +__CRT_INLINE time_t __cdecl time(time_t *_Time) { return _time64(_Time); } +#endif +#endif + +#if !defined(NO_OLDNAMES) || defined(_POSIX) +#define CLK_TCK CLOCKS_PER_SEC + + __MINGW_IMPORT int daylight; + __MINGW_IMPORT long dstbias; + __MINGW_IMPORT long timezone; + __MINGW_IMPORT char *tzname[2]; + void __cdecl tzset(void); +#endif + +#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ +#define _TIMEVAL_DEFINED +struct timeval { + long tv_sec; + long tv_usec; +}; +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif /* _TIMEVAL_DEFINED */ + +#ifndef __STRICT_ANSI__ +#ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ +#define _TIMEZONE_DEFINED +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + + extern int __cdecl mingw_gettimeofday (struct timeval *p, struct timezone *z); +#endif +#endif /* __STRICT_ANSI__ */ + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include + +/* Adding timespec definition. */ +#include + +#endif /* End _TIME_H_ */ + diff --git a/tcc/include/uchar.h b/tcc/include/uchar.h index 4e9b13ce..1a2c0294 100644 --- a/tcc/include/uchar.h +++ b/tcc/include/uchar.h @@ -1,33 +1,33 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the TinyCC package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _INC_UCHAR -#define _INC_UCHAR - -/* - * The following defines are only valid when C11 (-std=c11) is used. - * - * ... a wide character constant prefixed by the letter u or U has type char16_t - * or char32_t, respectively, unsigned integer types defined in the - * header. - */ - -#if __STDC_VERSION__ >= 201112L -/** - * __STDC_UTF_16__ The integer constant 1, intended to indicate that - * values of type char16_t are UTF-16 encoded. - */ -#define __STDC_UTF_16__ 1 -/** - * __STDC_UTF_32__ The integer constant 1, intended to indicate that - * values of type char32_t are UTF-32 encoded. - */ -#define __STDC_UTF_32__ 1 - -typedef unsigned short char16_t; -typedef unsigned int char32_t; -#endif /* __STDC_VERSION__ >= 201112L */ -#endif /* _INC_UCHAR */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the TinyCC package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _INC_UCHAR +#define _INC_UCHAR + +/* + * The following defines are only valid when C11 (-std=c11) is used. + * + * ... a wide character constant prefixed by the letter u or U has type char16_t + * or char32_t, respectively, unsigned integer types defined in the + * header. + */ + +#if __STDC_VERSION__ >= 201112L +/** + * __STDC_UTF_16__ The integer constant 1, intended to indicate that + * values of type char16_t are UTF-16 encoded. + */ +#define __STDC_UTF_16__ 1 +/** + * __STDC_UTF_32__ The integer constant 1, intended to indicate that + * values of type char32_t are UTF-32 encoded. + */ +#define __STDC_UTF_32__ 1 + +typedef unsigned short char16_t; +typedef unsigned int char32_t; +#endif /* __STDC_VERSION__ >= 201112L */ +#endif /* _INC_UCHAR */ diff --git a/tcc/include/vadefs.h b/tcc/include/vadefs.h index bb6eacea..749b0bdd 100644 --- a/tcc/include/vadefs.h +++ b/tcc/include/vadefs.h @@ -1,11 +1,11 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_VADEFS -#define _INC_VADEFS - -//!__TINYC__: GNUC specific stuff removed - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_VADEFS +#define _INC_VADEFS + +//!__TINYC__: GNUC specific stuff removed + +#endif diff --git a/tcc/include/values.h b/tcc/include/values.h index 8b821727..1cd643ce 100644 --- a/tcc/include/values.h +++ b/tcc/include/values.h @@ -1,4 +1,4 @@ -/* - * TODO: Nothing here yet. Should provide UNIX compatibility constants - * comparable to those in limits.h and float.h. - */ +/* + * TODO: Nothing here yet. Should provide UNIX compatibility constants + * comparable to those in limits.h and float.h. + */ diff --git a/tcc/include/varargs.h b/tcc/include/varargs.h index 4e3d5a55..d614366e 100644 --- a/tcc/include/varargs.h +++ b/tcc/include/varargs.h @@ -1,12 +1,12 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _VARARGS_H -#define _VARARGS_H - -#error "TinyCC no longer implements ." -#error "Revise your code to use ." - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _VARARGS_H +#define _VARARGS_H + +#error "TinyCC no longer implements ." +#error "Revise your code to use ." + +#endif diff --git a/tcc/include/wchar.h b/tcc/include/wchar.h index 0069f1fa..389196fa 100644 --- a/tcc/include/wchar.h +++ b/tcc/include/wchar.h @@ -1,873 +1,873 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_WCHAR -#define _INC_WCHAR - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WCHAR_MIN /* also at stdint.h */ -#define WCHAR_MIN 0 -#define WCHAR_MAX ((wchar_t) -1) /* UINT16_MAX */ -#endif - -#ifndef __GNUC_VA_LIST -#define __GNUC_VA_LIST - typedef __builtin_va_list __gnuc_va_list; -#endif - -#ifndef _VA_LIST_DEFINED -#define _VA_LIST_DEFINED - typedef __gnuc_va_list va_list; -#endif - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifndef _FILE_DEFINED - struct _iobuf { - char *_ptr; - int _cnt; - char *_base; - int _flag; - int _file; - int _charbuf; - int _bufsiz; - char *_tmpfname; - }; - typedef struct _iobuf FILE; -#define _FILE_DEFINED -#endif - -#ifndef _STDIO_DEFINED -#ifdef _WIN64 - _CRTIMP FILE *__cdecl __iob_func(void); -#else -#ifdef _MSVCRT_ -extern FILE _iob[]; /* A pointer to an array of FILE */ -#define __iob_func() (_iob) -#else -extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ -#define __iob_func() (*_imp___iob) -#define _iob __iob_func() -#endif -#endif - -#define _iob __iob_func() -#endif - -#ifndef _STDSTREAM_DEFINED -#define stdin (&__iob_func()[0]) -#define stdout (&__iob_func()[1]) -#define stderr (&__iob_func()[2]) -#define _STDSTREAM_DEFINED -#endif - -#ifndef _FSIZE_T_DEFINED - typedef unsigned long _fsize_t; -#define _FSIZE_T_DEFINED -#endif - -#ifndef _WFINDDATA_T_DEFINED - struct _wfinddata32_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - -/* #if _INTEGRAL_MAX_BITS >= 64 */ - - struct _wfinddata32i64_t { - unsigned attrib; - __time32_t time_create; - __time32_t time_access; - __time32_t time_write; - __int64 size; - wchar_t name[260]; - }; - - struct _wfinddata64i32_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - _fsize_t size; - wchar_t name[260]; - }; - - struct _wfinddata64_t { - unsigned attrib; - __time64_t time_create; - __time64_t time_access; - __time64_t time_write; - __int64 size; - wchar_t name[260]; - }; -/* #endif */ - -#ifdef _USE_32BIT_TIME_T -#define _wfinddata_t _wfinddata32_t -#define _wfinddatai64_t _wfinddata32i64_t - -#define _wfindfirst _wfindfirst32 -#define _wfindnext _wfindnext32 -#define _wfindfirsti64 _wfindfirst32i64 -#define _wfindnexti64 _wfindnext32i64 -#else -#define _wfinddata_t _wfinddata64i32_t -#define _wfinddatai64_t _wfinddata64_t - -#define _wfindfirst _wfindfirst64i32 -#define _wfindnext _wfindnext64i32 -#define _wfindfirsti64 _wfindfirst64 -#define _wfindnexti64 _wfindnext64 -#endif - -#define _WFINDDATA_T_DEFINED -#endif - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifndef _CONST_RETURN -#define _CONST_RETURN -#endif - -#define _WConst_return _CONST_RETURN - -#ifndef _CRT_CTYPEDATA_DEFINED -#define _CRT_CTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef __PCTYPE_FUNC -#define __PCTYPE_FUNC __pctype_func() -#ifdef _MSVCRT_ -#define __pctype_func() (_pctype) -#else -#define __pctype_func() (*_imp___pctype) -#endif -#endif - -#ifndef _pctype -#ifdef _MSVCRT_ - extern unsigned short *_pctype; -#else - extern unsigned short **_imp___pctype; -#define _pctype (*_imp___pctype) -#endif -#endif -#endif -#endif - -#ifndef _CRT_WCTYPEDATA_DEFINED -#define _CRT_WCTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS -#ifndef _wctype -#ifdef _MSVCRT_ - extern unsigned short *_wctype; -#else - extern unsigned short **_imp___wctype; -#define _wctype (*_imp___wctype) -#endif -#endif - -#ifdef _MSVCRT_ -#define __pwctype_func() (_pwctype) -#else -#define __pwctype_func() (*_imp___pwctype) -#endif - -#ifndef _pwctype -#ifdef _MSVCRT_ - extern unsigned short *_pwctype; -#else - extern unsigned short **_imp___pwctype; -#define _pwctype (*_imp___pwctype) -#endif -#endif - -#endif -#endif - -#define _UPPER 0x1 -#define _LOWER 0x2 -#define _DIGIT 0x4 -#define _SPACE 0x8 - -#define _PUNCT 0x10 -#define _CONTROL 0x20 -#define _BLANK 0x40 -#define _HEX 0x80 - -#define _LEADBYTE 0x8000 -#define _ALPHA (0x0100|_UPPER|_LOWER) - -#ifndef _WCTYPE_DEFINED -#define _WCTYPE_DEFINED - - int __cdecl iswalpha(wint_t _C); - _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); - int __cdecl iswupper(wint_t _C); - _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); - int __cdecl iswlower(wint_t _C); - _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswdigit(wint_t _C); - _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswxdigit(wint_t _C); - _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); - int __cdecl iswspace(wint_t _C); - _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); - int __cdecl iswpunct(wint_t _C); - _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); - int __cdecl iswalnum(wint_t _C); - _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); - int __cdecl iswprint(wint_t _C); - _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); - int __cdecl iswgraph(wint_t _C); - _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); - int __cdecl iswcntrl(wint_t _C); - _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); - int __cdecl iswascii(wint_t _C); - int __cdecl isleadbyte(int _C); - _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); - wint_t __cdecl towupper(wint_t _C); - _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); - wint_t __cdecl towlower(wint_t _C); - _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); - int __cdecl iswctype(wint_t _C,wctype_t _Type); - _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsymf(wint_t _C); - _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); - _CRTIMP int __cdecl __iswcsym(wint_t _C); - _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); - int __cdecl is_wctype(wint_t _C,wctype_t _Type); -#endif - -#ifndef _WDIRECT_DEFINED -#define _WDIRECT_DEFINED - - _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); - _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); - _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); -#endif - -#ifndef _WIO_DEFINED -#define _WIO_DEFINED - - _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); - _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); - _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); - _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); - _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); - _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); - _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); - intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); - _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); - _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); - int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); - _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); -#endif - _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); -#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) - _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); - _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); -#else - extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); - extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); -#endif -#endif - -#ifndef _WLOCALE_DEFINED -#define _WLOCALE_DEFINED - _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); -#endif - -#ifndef _WPROCESS_DEFINED -#define _WPROCESS_DEFINED - - _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); - _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); - _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); - _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif -#endif - -#ifndef _WCTYPE_INLINE_DEFINED -#undef _CRT_WCTYPE_NOINLINE -#if !defined(__cplusplus) || defined(_CRT_WCTYPE_NOINLINE) -#define iswalpha(_c) (iswctype(_c,_ALPHA)) -#define iswupper(_c) (iswctype(_c,_UPPER)) -#define iswlower(_c) (iswctype(_c,_LOWER)) -#define iswdigit(_c) (iswctype(_c,_DIGIT)) -#define iswxdigit(_c) (iswctype(_c,_HEX)) -#define iswspace(_c) (iswctype(_c,_SPACE)) -#define iswpunct(_c) (iswctype(_c,_PUNCT)) -#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) -#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) -#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) -#define iswcntrl(_c) (iswctype(_c,_CONTROL)) -#define iswascii(_c) ((unsigned)(_c) < 0x80) - -#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) -#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) -#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) -#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) -#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) -#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) -#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) -#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) -#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) -#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) -#ifndef _CTYPE_DISABLE_MACROS -#define isleadbyte(_c) (__PCTYPE_FUNC[(unsigned char)(_c)] & _LEADBYTE) -#endif -#endif -#define _WCTYPE_INLINE_DEFINED -#endif - -#if !defined(_POSIX_) || defined(__GNUC__) -#ifndef _INO_T_DEFINED -#define _INO_T_DEFINED - typedef unsigned short _ino_t; -#ifndef NO_OLDNAMES - typedef unsigned short ino_t; -#endif -#endif - -#ifndef _DEV_T_DEFINED -#define _DEV_T_DEFINED - typedef unsigned int _dev_t; -#ifndef NO_OLDNAMES - typedef unsigned int dev_t; -#endif -#endif - -#ifndef _OFF_T_DEFINED -#define _OFF_T_DEFINED -#ifndef _OFF_T_ -#define _OFF_T_ - typedef long _off_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long off_t; -#endif -#endif -#endif - -#ifndef _OFF64_T_DEFINED -#define _OFF64_T_DEFINED - typedef long long _off64_t; -#if !defined(NO_OLDNAMES) || defined(_POSIX) - typedef long long off64_t; -#endif -#endif - -#ifndef _STAT_DEFINED -#define _STAT_DEFINED - -#ifdef _USE_32BIT_TIME_T -#ifdef WIN64 -#define _fstat _fstat32 -#define _stat _stat32 -#define _wstat _wstat32 -#else -#define _fstat32 _fstat -#define _stat32 _stat -#define _wstat32 _wstat -#endif -#define _fstati64 _fstat32i64 -#define _stati64 _stat32i64 -#define _wstati64 _wstat32i64 -#else -#define _fstat _fstat64i32 -#define _fstati64 _fstat64 -#define _stat _stat64i32 -#define _stati64 _stat64 -#define _wstat _wstat64i32 -#define _wstati64 _wstat64 -#endif - - struct _stat32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - -#ifndef NO_OLDNAMES - struct stat { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; - }; -#endif - -#if _INTEGRAL_MAX_BITS >= 64 - - struct _stat32i64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time32_t st_atime; - __time32_t st_mtime; - __time32_t st_ctime; - }; - - struct _stat64i32 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; - - struct _stat64 { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - __int64 st_size; - __time64_t st_atime; - __time64_t st_mtime; - __time64_t st_ctime; - }; -#endif - -#define __stat64 _stat64 - -#endif - -#ifndef _WSTAT_DEFINED -#define _WSTAT_DEFINED - - _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); - int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); - _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); -#endif -#endif -#endif - -#ifndef _WCONIO_DEFINED -#define _WCONIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - - _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _getwch(void); - _CRTIMP wint_t __cdecl _getwche(void); - _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); - _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); - _CRTIMP int __cdecl _cputws(const wchar_t *_String); - _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); - - _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - wint_t __cdecl _putwch_nolock(wchar_t _WCh); - wint_t __cdecl _getwch_nolock(void); - wint_t __cdecl _getwche_nolock(void); - wint_t __cdecl _ungetwch_nolock(wint_t _WCh); -#endif - -#ifndef _WSTDIO_DEFINED -#define _WSTDIO_DEFINED - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifdef _POSIX_ - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); -#else - _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); -#endif - - wint_t __cdecl fgetwc(FILE *_File); - _CRTIMP wint_t __cdecl _fgetwchar(void); - wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); - wint_t __cdecl getwc(FILE *_File); - wint_t __cdecl getwchar(void); - wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); - wint_t __cdecl putwchar(wchar_t _Ch); - wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); - wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); - int __cdecl fputws(const wchar_t *_Str,FILE *_File); - _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); - _CRTIMP int __cdecl _putws(const wchar_t *_Str); - int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); - int __cdecl wprintf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); - int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); - int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); - _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); - _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); -#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ - int __cdecl snwprintf (wchar_t *s, size_t n, const wchar_t * format, ...); - __CRT_INLINE int __cdecl vsnwprintf (wchar_t *s, size_t n, const wchar_t *format, va_list arg) { return _vsnwprintf(s,n,format,arg); } - int __cdecl vwscanf (const wchar_t *, va_list); - int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); - int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); -#endif - _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); - _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); - _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); - _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); - _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); - _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); -#ifndef RC_INVOKED -#include -#endif - -#ifdef _CRT_NON_CONFORMING_SWPRINTFS -#ifndef __cplusplus -#define swprintf _swprintf -#define vswprintf _vswprintf -#define _swprintf_l __swprintf_l -#define _vswprintf_l __vswprintf_l -#endif -#endif - - _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); - _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); - _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); - int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); - _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); - int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); - _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); - _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); - int __cdecl wscanf(const wchar_t *_Format,...); - _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); - _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); - _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); - -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); -#if !defined(NO_OLDNAMES) && !defined(wpopen) -#define wpopen _wpopen -#endif - _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); - _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); - _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); - _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); - _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); - -#undef _CRT_GETPUTWCHAR_NOINLINE - -#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) -#define getwchar() fgetwc(stdin) -#define putwchar(_c) fputwc((_c),stdout) -#else - __CRT_INLINE wint_t __cdecl getwchar() {return (fgetwc(stdin)); } - __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) {return (fputwc(_C,stdout)); } -#endif - -#define getwc(_stm) fgetwc(_stm) -#define putwc(_c,_stm) fputwc(_c,_stm) -#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) -#define _getwc_nolock(_c) _fgetwc_nolock(_c) -#endif - -#ifndef _WSTDLIB_DEFINED -#define _WSTDLIB_DEFINED - - _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); - _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); - double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); - _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); - float __cdecl wcstof( const wchar_t *nptr, wchar_t **endptr); -#if !defined __NO_ISOCEXT /* in libmingwex.a */ - float __cdecl wcstof (const wchar_t * __restrict__, wchar_t ** __restrict__); - long double __cdecl wcstold (const wchar_t * __restrict__, wchar_t ** __restrict__); -#endif /* __NO_ISOCEXT */ - long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); -#ifndef _CRT_WSYSTEM_DEFINED -#define _CRT_WSYSTEM_DEFINED - _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); -#endif - _CRTIMP double __cdecl _wtof(const wchar_t *_Str); - _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); - _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP long __cdecl _wtol(const wchar_t *_Str); - _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); - -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); - _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); - _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); - _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); - _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); - _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); -#endif -#endif - -#ifndef _POSIX_ -#ifndef _WSTDLIBP_DEFINED -#define _WSTDLIBP_DEFINED - _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); - _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); -#ifndef _CRT_WPERROR_DEFINED -#define _CRT_WPERROR_DEFINED - _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); -#endif - _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); - _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); - _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); -#endif -#endif - -#ifndef _WSTRING_DEFINED -#define _WSTRING_DEFINED - _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); - wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); - _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); - int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); - wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); - size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); - size_t __cdecl wcslen(const wchar_t *_Str); - size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); - wchar_t *__cdecl wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *__cdecl wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); - _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); - size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); - _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); - wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); - _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); - _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); - _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); - _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); - _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); - _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); - _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); - size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); - _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); - int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); - _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); - _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); - -#ifndef NO_OLDNAMES - wchar_t *__cdecl wcsdup(const wchar_t *_Str); -#define wcswcs wcsstr - int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); - int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); - wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); - wchar_t *__cdecl wcsrev(wchar_t *_Str); - wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); - wchar_t *__cdecl wcslwr(wchar_t *_Str); - wchar_t *__cdecl wcsupr(wchar_t *_Str); - int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); -#endif -#endif - -#ifndef _TM_DEFINED -#define _TM_DEFINED - struct tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - }; -#endif - -#ifndef _WTIME_DEFINED -#define _WTIME_DEFINED - - _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); - _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); - size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); - _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); - _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); - _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); -#if _INTEGRAL_MAX_BITS >= 64 - _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); -#endif - -#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) -#define _INC_WTIME_INL -#ifdef _USE_32BIT_TIME_T -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } -#else -__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } -#endif -#endif -#endif - - typedef int mbstate_t; - typedef wchar_t _Wint_t; - - wint_t __cdecl btowc(int); - size_t __cdecl mbrlen(const char *_Ch,size_t _SizeInBytes,mbstate_t *_State); - size_t __cdecl mbrtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SizeInBytes,mbstate_t *_State); - size_t __cdecl mbsrtowcs(wchar_t *_Dest,const char **_PSrc,size_t _Count,mbstate_t *_State); - size_t __cdecl wcrtomb(char *_Dest,wchar_t _Source,mbstate_t *_State); - size_t __cdecl wcsrtombs(char *_Dest,const wchar_t **_PSource,size_t _Count,mbstate_t *_State); - int __cdecl wctob(wint_t _WCh); - -#ifndef __NO_ISOCEXT /* these need static lib libmingwex.a */ - wchar_t *__cdecl wmemset(wchar_t *s, wchar_t c, size_t n); - _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *s, wchar_t c, size_t n); - int wmemcmp(const wchar_t *s1, const wchar_t *s2,size_t n); - wchar_t *__cdecl wmemcpy(wchar_t *s1,const wchar_t *s2,size_t n); - wchar_t *__cdecl wmemmove(wchar_t *s1, const wchar_t *s2, size_t n); - long long __cdecl wcstoll(const wchar_t *nptr,wchar_t **endptr, int base); - unsigned long long __cdecl wcstoull(const wchar_t *nptr,wchar_t **endptr, int base); -#endif /* __NO_ISOCEXT */ - - void *__cdecl memmove(void *_Dst,const void *_Src,size_t _MaxCount); - void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _MaxCount); - __CRT_INLINE int __cdecl fwide(FILE *_F,int _M) { (void)_F; return (_M); } - __CRT_INLINE int __cdecl mbsinit(const mbstate_t *_P) { return (!_P || *_P==0); } - __CRT_INLINE _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *_S,wchar_t _C,size_t _N) { for (;0<_N;++_S,--_N) if (*_S==_C) return (_CONST_RETURN wchar_t *)(_S); return (0); } - __CRT_INLINE int __cdecl wmemcmp(const wchar_t *_S1,const wchar_t *_S2,size_t _N) { for (; 0 < _N; ++_S1,++_S2,--_N) if (*_S1!=*_S2) return (*_S1 < *_S2 ? -1 : +1); return (0); } - __CRT_INLINE wchar_t *__cdecl wmemcpy(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memcpy(_S1,_S2,_N*sizeof(wchar_t)); } - __CRT_INLINE wchar_t *__cdecl wmemmove(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memmove(_S1,_S2,_N*sizeof(wchar_t)); } - __CRT_INLINE wchar_t *__cdecl wmemset(wchar_t *_S,wchar_t _C,size_t _N) { - wchar_t *_Su = _S; - for (;0<_N;++_Su,--_N) { - *_Su = _C; - } - return (_S); - } -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) - -#include -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_WCHAR +#define _INC_WCHAR + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WCHAR_MIN /* also at stdint.h */ +#define WCHAR_MIN 0 +#define WCHAR_MAX ((wchar_t) -1) /* UINT16_MAX */ +#endif + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST + typedef __builtin_va_list __gnuc_va_list; +#endif + +#ifndef _VA_LIST_DEFINED +#define _VA_LIST_DEFINED + typedef __gnuc_va_list va_list; +#endif + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifndef _FILE_DEFINED + struct _iobuf { + char *_ptr; + int _cnt; + char *_base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char *_tmpfname; + }; + typedef struct _iobuf FILE; +#define _FILE_DEFINED +#endif + +#ifndef _STDIO_DEFINED +#ifdef _WIN64 + _CRTIMP FILE *__cdecl __iob_func(void); +#else +#ifdef _MSVCRT_ +extern FILE _iob[]; /* A pointer to an array of FILE */ +#define __iob_func() (_iob) +#else +extern FILE (*_imp___iob)[]; /* A pointer to an array of FILE */ +#define __iob_func() (*_imp___iob) +#define _iob __iob_func() +#endif +#endif + +#define _iob __iob_func() +#endif + +#ifndef _STDSTREAM_DEFINED +#define stdin (&__iob_func()[0]) +#define stdout (&__iob_func()[1]) +#define stderr (&__iob_func()[2]) +#define _STDSTREAM_DEFINED +#endif + +#ifndef _FSIZE_T_DEFINED + typedef unsigned long _fsize_t; +#define _FSIZE_T_DEFINED +#endif + +#ifndef _WFINDDATA_T_DEFINED + struct _wfinddata32_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + +/* #if _INTEGRAL_MAX_BITS >= 64 */ + + struct _wfinddata32i64_t { + unsigned attrib; + __time32_t time_create; + __time32_t time_access; + __time32_t time_write; + __int64 size; + wchar_t name[260]; + }; + + struct _wfinddata64i32_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + _fsize_t size; + wchar_t name[260]; + }; + + struct _wfinddata64_t { + unsigned attrib; + __time64_t time_create; + __time64_t time_access; + __time64_t time_write; + __int64 size; + wchar_t name[260]; + }; +/* #endif */ + +#ifdef _USE_32BIT_TIME_T +#define _wfinddata_t _wfinddata32_t +#define _wfinddatai64_t _wfinddata32i64_t + +#define _wfindfirst _wfindfirst32 +#define _wfindnext _wfindnext32 +#define _wfindfirsti64 _wfindfirst32i64 +#define _wfindnexti64 _wfindnext32i64 +#else +#define _wfinddata_t _wfinddata64i32_t +#define _wfinddatai64_t _wfinddata64_t + +#define _wfindfirst _wfindfirst64i32 +#define _wfindnext _wfindnext64i32 +#define _wfindfirsti64 _wfindfirst64 +#define _wfindnexti64 _wfindnext64 +#endif + +#define _WFINDDATA_T_DEFINED +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef _CONST_RETURN +#define _CONST_RETURN +#endif + +#define _WConst_return _CONST_RETURN + +#ifndef _CRT_CTYPEDATA_DEFINED +#define _CRT_CTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef __PCTYPE_FUNC +#define __PCTYPE_FUNC __pctype_func() +#ifdef _MSVCRT_ +#define __pctype_func() (_pctype) +#else +#define __pctype_func() (*_imp___pctype) +#endif +#endif + +#ifndef _pctype +#ifdef _MSVCRT_ + extern unsigned short *_pctype; +#else + extern unsigned short **_imp___pctype; +#define _pctype (*_imp___pctype) +#endif +#endif +#endif +#endif + +#ifndef _CRT_WCTYPEDATA_DEFINED +#define _CRT_WCTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS +#ifndef _wctype +#ifdef _MSVCRT_ + extern unsigned short *_wctype; +#else + extern unsigned short **_imp___wctype; +#define _wctype (*_imp___wctype) +#endif +#endif + +#ifdef _MSVCRT_ +#define __pwctype_func() (_pwctype) +#else +#define __pwctype_func() (*_imp___pwctype) +#endif + +#ifndef _pwctype +#ifdef _MSVCRT_ + extern unsigned short *_pwctype; +#else + extern unsigned short **_imp___pwctype; +#define _pwctype (*_imp___pwctype) +#endif +#endif + +#endif +#endif + +#define _UPPER 0x1 +#define _LOWER 0x2 +#define _DIGIT 0x4 +#define _SPACE 0x8 + +#define _PUNCT 0x10 +#define _CONTROL 0x20 +#define _BLANK 0x40 +#define _HEX 0x80 + +#define _LEADBYTE 0x8000 +#define _ALPHA (0x0100|_UPPER|_LOWER) + +#ifndef _WCTYPE_DEFINED +#define _WCTYPE_DEFINED + + int __cdecl iswalpha(wint_t _C); + _CRTIMP int __cdecl _iswalpha_l(wint_t _C,_locale_t _Locale); + int __cdecl iswupper(wint_t _C); + _CRTIMP int __cdecl _iswupper_l(wint_t _C,_locale_t _Locale); + int __cdecl iswlower(wint_t _C); + _CRTIMP int __cdecl _iswlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswdigit(wint_t _C); + _CRTIMP int __cdecl _iswdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswxdigit(wint_t _C); + _CRTIMP int __cdecl _iswxdigit_l(wint_t _C,_locale_t _Locale); + int __cdecl iswspace(wint_t _C); + _CRTIMP int __cdecl _iswspace_l(wint_t _C,_locale_t _Locale); + int __cdecl iswpunct(wint_t _C); + _CRTIMP int __cdecl _iswpunct_l(wint_t _C,_locale_t _Locale); + int __cdecl iswalnum(wint_t _C); + _CRTIMP int __cdecl _iswalnum_l(wint_t _C,_locale_t _Locale); + int __cdecl iswprint(wint_t _C); + _CRTIMP int __cdecl _iswprint_l(wint_t _C,_locale_t _Locale); + int __cdecl iswgraph(wint_t _C); + _CRTIMP int __cdecl _iswgraph_l(wint_t _C,_locale_t _Locale); + int __cdecl iswcntrl(wint_t _C); + _CRTIMP int __cdecl _iswcntrl_l(wint_t _C,_locale_t _Locale); + int __cdecl iswascii(wint_t _C); + int __cdecl isleadbyte(int _C); + _CRTIMP int __cdecl _isleadbyte_l(int _C,_locale_t _Locale); + wint_t __cdecl towupper(wint_t _C); + _CRTIMP wint_t __cdecl _towupper_l(wint_t _C,_locale_t _Locale); + wint_t __cdecl towlower(wint_t _C); + _CRTIMP wint_t __cdecl _towlower_l(wint_t _C,_locale_t _Locale); + int __cdecl iswctype(wint_t _C,wctype_t _Type); + _CRTIMP int __cdecl _iswctype_l(wint_t _C,wctype_t _Type,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsymf(wint_t _C); + _CRTIMP int __cdecl _iswcsymf_l(wint_t _C,_locale_t _Locale); + _CRTIMP int __cdecl __iswcsym(wint_t _C); + _CRTIMP int __cdecl _iswcsym_l(wint_t _C,_locale_t _Locale); + int __cdecl is_wctype(wint_t _C,wctype_t _Type); +#endif + +#ifndef _WDIRECT_DEFINED +#define _WDIRECT_DEFINED + + _CRTIMP wchar_t *__cdecl _wgetcwd(wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP wchar_t *__cdecl _wgetdcwd(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + wchar_t *__cdecl _wgetdcwd_nolock(int _Drive,wchar_t *_DstBuf,int _SizeInWords); + _CRTIMP int __cdecl _wchdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wmkdir(const wchar_t *_Path); + _CRTIMP int __cdecl _wrmdir(const wchar_t *_Path); +#endif + +#ifndef _WIO_DEFINED +#define _WIO_DEFINED + + _CRTIMP int __cdecl _waccess(const wchar_t *_Filename,int _AccessMode); + _CRTIMP int __cdecl _wchmod(const wchar_t *_Filename,int _Mode); + _CRTIMP int __cdecl _wcreat(const wchar_t *_Filename,int _PermissionMode); + _CRTIMP intptr_t __cdecl _wfindfirst32(const wchar_t *_Filename,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wfindnext32(intptr_t _FindHandle,struct _wfinddata32_t *_FindData); + _CRTIMP int __cdecl _wunlink(const wchar_t *_Filename); + _CRTIMP int __cdecl _wrename(const wchar_t *_NewFilename,const wchar_t *_OldFilename); + _CRTIMP wchar_t *__cdecl _wmktemp(wchar_t *_TemplateName); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP intptr_t __cdecl _wfindfirst32i64(const wchar_t *_Filename,struct _wfinddata32i64_t *_FindData); + intptr_t __cdecl _wfindfirst64i32(const wchar_t *_Filename,struct _wfinddata64i32_t *_FindData); + _CRTIMP intptr_t __cdecl _wfindfirst64(const wchar_t *_Filename,struct _wfinddata64_t *_FindData); + _CRTIMP int __cdecl _wfindnext32i64(intptr_t _FindHandle,struct _wfinddata32i64_t *_FindData); + int __cdecl _wfindnext64i32(intptr_t _FindHandle,struct _wfinddata64i32_t *_FindData); + _CRTIMP int __cdecl _wfindnext64(intptr_t _FindHandle,struct _wfinddata64_t *_FindData); +#endif + _CRTIMP errno_t __cdecl _wsopen_s(int *_FileHandle,const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionFlag); +#if !defined(__cplusplus) || !(defined(_X86_) && !defined(__x86_64)) + _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,...); + _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,...); +#else + extern "C++" _CRTIMP int __cdecl _wopen(const wchar_t *_Filename,int _OpenFlag,int _PermissionMode = 0); + extern "C++" _CRTIMP int __cdecl _wsopen(const wchar_t *_Filename,int _OpenFlag,int _ShareFlag,int _PermissionMode = 0); +#endif +#endif + +#ifndef _WLOCALE_DEFINED +#define _WLOCALE_DEFINED + _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); +#endif + +#ifndef _WPROCESS_DEFINED +#define _WPROCESS_DEFINED + + _CRTIMP intptr_t __cdecl _wexecl(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecle(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclp(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexeclpe(const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wexecv(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecve(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wexecvp(const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wexecvpe(const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnl(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnle(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlp(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnlpe(int _Mode,const wchar_t *_Filename,const wchar_t *_ArgList,...); + _CRTIMP intptr_t __cdecl _wspawnv(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnve(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); + _CRTIMP intptr_t __cdecl _wspawnvp(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList); + _CRTIMP intptr_t __cdecl _wspawnvpe(int _Mode,const wchar_t *_Filename,const wchar_t *const *_ArgList,const wchar_t *const *_Env); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif +#endif + +#ifndef _WCTYPE_INLINE_DEFINED +#undef _CRT_WCTYPE_NOINLINE +#if !defined(__cplusplus) || defined(_CRT_WCTYPE_NOINLINE) +#define iswalpha(_c) (iswctype(_c,_ALPHA)) +#define iswupper(_c) (iswctype(_c,_UPPER)) +#define iswlower(_c) (iswctype(_c,_LOWER)) +#define iswdigit(_c) (iswctype(_c,_DIGIT)) +#define iswxdigit(_c) (iswctype(_c,_HEX)) +#define iswspace(_c) (iswctype(_c,_SPACE)) +#define iswpunct(_c) (iswctype(_c,_PUNCT)) +#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) +#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) +#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) +#define iswcntrl(_c) (iswctype(_c,_CONTROL)) +#define iswascii(_c) ((unsigned)(_c) < 0x80) + +#define _iswalpha_l(_c,_p) (_iswctype_l(_c,_ALPHA,_p)) +#define _iswupper_l(_c,_p) (_iswctype_l(_c,_UPPER,_p)) +#define _iswlower_l(_c,_p) (_iswctype_l(_c,_LOWER,_p)) +#define _iswdigit_l(_c,_p) (_iswctype_l(_c,_DIGIT,_p)) +#define _iswxdigit_l(_c,_p) (_iswctype_l(_c,_HEX,_p)) +#define _iswspace_l(_c,_p) (_iswctype_l(_c,_SPACE,_p)) +#define _iswpunct_l(_c,_p) (_iswctype_l(_c,_PUNCT,_p)) +#define _iswalnum_l(_c,_p) (_iswctype_l(_c,_ALPHA|_DIGIT,_p)) +#define _iswprint_l(_c,_p) (_iswctype_l(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswgraph_l(_c,_p) (_iswctype_l(_c,_PUNCT|_ALPHA|_DIGIT,_p)) +#define _iswcntrl_l(_c,_p) (_iswctype_l(_c,_CONTROL,_p)) +#ifndef _CTYPE_DISABLE_MACROS +#define isleadbyte(_c) (__PCTYPE_FUNC[(unsigned char)(_c)] & _LEADBYTE) +#endif +#endif +#define _WCTYPE_INLINE_DEFINED +#endif + +#if !defined(_POSIX_) || defined(__GNUC__) +#ifndef _INO_T_DEFINED +#define _INO_T_DEFINED + typedef unsigned short _ino_t; +#ifndef NO_OLDNAMES + typedef unsigned short ino_t; +#endif +#endif + +#ifndef _DEV_T_DEFINED +#define _DEV_T_DEFINED + typedef unsigned int _dev_t; +#ifndef NO_OLDNAMES + typedef unsigned int dev_t; +#endif +#endif + +#ifndef _OFF_T_DEFINED +#define _OFF_T_DEFINED +#ifndef _OFF_T_ +#define _OFF_T_ + typedef long _off_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long off_t; +#endif +#endif +#endif + +#ifndef _OFF64_T_DEFINED +#define _OFF64_T_DEFINED + typedef long long _off64_t; +#if !defined(NO_OLDNAMES) || defined(_POSIX) + typedef long long off64_t; +#endif +#endif + +#ifndef _STAT_DEFINED +#define _STAT_DEFINED + +#ifdef _USE_32BIT_TIME_T +#ifdef WIN64 +#define _fstat _fstat32 +#define _stat _stat32 +#define _wstat _wstat32 +#else +#define _fstat32 _fstat +#define _stat32 _stat +#define _wstat32 _wstat +#endif +#define _fstati64 _fstat32i64 +#define _stati64 _stat32i64 +#define _wstati64 _wstat32i64 +#else +#define _fstat _fstat64i32 +#define _fstati64 _fstat64 +#define _stat _stat64i32 +#define _stati64 _stat64 +#define _wstat _wstat64i32 +#define _wstati64 _wstat64 +#endif + + struct _stat32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + +#ifndef NO_OLDNAMES + struct stat { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + }; +#endif + +#if _INTEGRAL_MAX_BITS >= 64 + + struct _stat32i64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time32_t st_atime; + __time32_t st_mtime; + __time32_t st_ctime; + }; + + struct _stat64i32 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; + + struct _stat64 { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; +#endif + +#define __stat64 _stat64 + +#endif + +#ifndef _WSTAT_DEFINED +#define _WSTAT_DEFINED + + _CRTIMP int __cdecl _wstat32(const wchar_t *_Name,struct _stat32 *_Stat); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat); + int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat); + _CRTIMP int __cdecl _wstat64(const wchar_t *_Name,struct _stat64 *_Stat); +#endif +#endif +#endif + +#ifndef _WCONIO_DEFINED +#define _WCONIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + + _CRTIMP wchar_t *_cgetws(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _getwch(void); + _CRTIMP wint_t __cdecl _getwche(void); + _CRTIMP wint_t __cdecl _putwch(wchar_t _WCh); + _CRTIMP wint_t __cdecl _ungetwch(wint_t _WCh); + _CRTIMP int __cdecl _cputws(const wchar_t *_String); + _CRTIMP int __cdecl _cwprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _cwscanf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vcwprintf_p(const wchar_t *_Format,va_list _ArgList); + + _CRTIMP int __cdecl _cwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _cwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vcwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + wint_t __cdecl _putwch_nolock(wchar_t _WCh); + wint_t __cdecl _getwch_nolock(void); + wint_t __cdecl _getwche_nolock(void); + wint_t __cdecl _ungetwch_nolock(wint_t _WCh); +#endif + +#ifndef _WSTDIO_DEFINED +#define _WSTDIO_DEFINED + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifdef _POSIX_ + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode); +#else + _CRTIMP FILE *__cdecl _wfsopen(const wchar_t *_Filename,const wchar_t *_Mode,int _ShFlag); +#endif + + wint_t __cdecl fgetwc(FILE *_File); + _CRTIMP wint_t __cdecl _fgetwchar(void); + wint_t __cdecl fputwc(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _fputwchar(wchar_t _Ch); + wint_t __cdecl getwc(FILE *_File); + wint_t __cdecl getwchar(void); + wint_t __cdecl putwc(wchar_t _Ch,FILE *_File); + wint_t __cdecl putwchar(wchar_t _Ch); + wint_t __cdecl ungetwc(wint_t _Ch,FILE *_File); + wchar_t *__cdecl fgetws(wchar_t *_Dst,int _SizeInWords,FILE *_File); + int __cdecl fputws(const wchar_t *_Str,FILE *_File); + _CRTIMP wchar_t *__cdecl _getws(wchar_t *_String); + _CRTIMP int __cdecl _putws(const wchar_t *_Str); + int __cdecl fwprintf(FILE *_File,const wchar_t *_Format,...); + int __cdecl wprintf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _scwprintf(const wchar_t *_Format,...); + int __cdecl vfwprintf(FILE *_File,const wchar_t *_Format,va_list _ArgList); + int __cdecl vwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl swprintf(wchar_t*, const wchar_t*, ...); + _CRTIMP int __cdecl vswprintf(wchar_t*, const wchar_t*,va_list); + _CRTIMP int __cdecl _swprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_c(wchar_t *_DstBuf,size_t _SizeInWords,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vsnwprintf(wchar_t *_Dest,size_t _Count,const wchar_t *_Format,va_list _Args); +#ifndef __NO_ISOCEXT /* externs in libmingwex.a */ + int __cdecl snwprintf (wchar_t *s, size_t n, const wchar_t * format, ...); + __CRT_INLINE int __cdecl vsnwprintf (wchar_t *s, size_t n, const wchar_t *format, va_list arg) { return _vsnwprintf(s,n,format,arg); } + int __cdecl vwscanf (const wchar_t *, va_list); + int __cdecl vfwscanf (FILE *,const wchar_t *,va_list); + int __cdecl vswscanf (const wchar_t *,const wchar_t *,va_list); +#endif + _CRTIMP int __cdecl _fwprintf_p(FILE *_File,const wchar_t *_Format,...); + _CRTIMP int __cdecl _wprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vfwprintf_p(FILE *_File,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf_p(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_p(const wchar_t *_Format,...); + _CRTIMP int __cdecl _vscwprintf_p(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _wprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _wprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _fwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _fwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vfwprintf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vfwprintf_p_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _swprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vswprintf_c_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _vswprintf_p_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _scwprintf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _scwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vscwprintf_p_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _snwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _vsnwprintf_l(wchar_t *_DstBuf,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + _CRTIMP int __cdecl _swprintf(wchar_t *_Dest,const wchar_t *_Format,...); + _CRTIMP int __cdecl _vswprintf(wchar_t *_Dest,const wchar_t *_Format,va_list _Args); + _CRTIMP int __cdecl __swprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,...); + _CRTIMP int __cdecl __vswprintf_l(wchar_t *_Dest,const wchar_t *_Format,_locale_t _Plocinfo,va_list _Args); +#ifndef RC_INVOKED +#include +#endif + +#ifdef _CRT_NON_CONFORMING_SWPRINTFS +#ifndef __cplusplus +#define swprintf _swprintf +#define vswprintf _vswprintf +#define _swprintf_l __swprintf_l +#define _vswprintf_l __vswprintf_l +#endif +#endif + + _CRTIMP wchar_t *__cdecl _wtempnam(const wchar_t *_Directory,const wchar_t *_FilePrefix); + _CRTIMP int __cdecl _vscwprintf(const wchar_t *_Format,va_list _ArgList); + _CRTIMP int __cdecl _vscwprintf_l(const wchar_t *_Format,_locale_t _Locale,va_list _ArgList); + int __cdecl fwscanf(FILE *_File,const wchar_t *_Format,...); + _CRTIMP int __cdecl _fwscanf_l(FILE *_File,const wchar_t *_Format,_locale_t _Locale,...); + int __cdecl swscanf(const wchar_t *_Src,const wchar_t *_Format,...); + _CRTIMP int __cdecl _swscanf_l(const wchar_t *_Src,const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP int __cdecl _snwscanf(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,...); + _CRTIMP int __cdecl _snwscanf_l(const wchar_t *_Src,size_t _MaxCount,const wchar_t *_Format,_locale_t _Locale,...); + int __cdecl wscanf(const wchar_t *_Format,...); + _CRTIMP int __cdecl _wscanf_l(const wchar_t *_Format,_locale_t _Locale,...); + _CRTIMP FILE *__cdecl _wfdopen(int _FileHandle ,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfopen(const wchar_t *_Filename,const wchar_t *_Mode); + _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *_Filename,const wchar_t *_Mode,FILE *_OldFile); + +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP FILE *__cdecl _wpopen(const wchar_t *_Command,const wchar_t *_Mode); +#if !defined(NO_OLDNAMES) && !defined(wpopen) +#define wpopen _wpopen +#endif + _CRTIMP int __cdecl _wremove(const wchar_t *_Filename); + _CRTIMP wchar_t *__cdecl _wtmpnam(wchar_t *_Buffer); + _CRTIMP wint_t __cdecl _fgetwc_nolock(FILE *_File); + _CRTIMP wint_t __cdecl _fputwc_nolock(wchar_t _Ch,FILE *_File); + _CRTIMP wint_t __cdecl _ungetwc_nolock(wint_t _Ch,FILE *_File); + +#undef _CRT_GETPUTWCHAR_NOINLINE + +#if !defined(__cplusplus) || defined(_CRT_GETPUTWCHAR_NOINLINE) +#define getwchar() fgetwc(stdin) +#define putwchar(_c) fputwc((_c),stdout) +#else + __CRT_INLINE wint_t __cdecl getwchar() {return (fgetwc(stdin)); } + __CRT_INLINE wint_t __cdecl putwchar(wchar_t _C) {return (fputwc(_C,stdout)); } +#endif + +#define getwc(_stm) fgetwc(_stm) +#define putwc(_c,_stm) fputwc(_c,_stm) +#define _putwc_nolock(_c,_stm) _fputwc_nolock(_c,_stm) +#define _getwc_nolock(_c) _fgetwc_nolock(_c) +#endif + +#ifndef _WSTDLIB_DEFINED +#define _WSTDLIB_DEFINED + + _CRTIMP wchar_t *__cdecl _itow(int _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ltow(long _Value,wchar_t *_Dest,int _Radix); + _CRTIMP wchar_t *__cdecl _ultow(unsigned long _Value,wchar_t *_Dest,int _Radix); + double __cdecl wcstod(const wchar_t *_Str,wchar_t **_EndPtr); + _CRTIMP double __cdecl _wcstod_l(const wchar_t *_Str,wchar_t **_EndPtr,_locale_t _Locale); + float __cdecl wcstof( const wchar_t *nptr, wchar_t **endptr); +#if !defined __NO_ISOCEXT /* in libmingwex.a */ + float __cdecl wcstof (const wchar_t * __restrict__, wchar_t ** __restrict__); + long double __cdecl wcstold (const wchar_t * __restrict__, wchar_t ** __restrict__); +#endif /* __NO_ISOCEXT */ + long __cdecl wcstol(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP long __cdecl _wcstol_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + unsigned long __cdecl wcstoul(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned long __cdecl _wcstoul_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wgetenv(const wchar_t *_VarName); +#ifndef _CRT_WSYSTEM_DEFINED +#define _CRT_WSYSTEM_DEFINED + _CRTIMP int __cdecl _wsystem(const wchar_t *_Command); +#endif + _CRTIMP double __cdecl _wtof(const wchar_t *_Str); + _CRTIMP double __cdecl _wtof_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP int __cdecl _wtoi(const wchar_t *_Str); + _CRTIMP int __cdecl _wtoi_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP long __cdecl _wtol(const wchar_t *_Str); + _CRTIMP long __cdecl _wtol_l(const wchar_t *_Str,_locale_t _Locale); + +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _i64tow(__int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP wchar_t *__cdecl _ui64tow(unsigned __int64 _Val,wchar_t *_DstBuf,int _Radix); + _CRTIMP __int64 __cdecl _wtoi64(const wchar_t *_Str); + _CRTIMP __int64 __cdecl _wtoi64_l(const wchar_t *_Str,_locale_t _Locale); + _CRTIMP __int64 __cdecl _wcstoi64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP __int64 __cdecl _wcstoi64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); + _CRTIMP unsigned __int64 __cdecl _wcstoui64(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix); + _CRTIMP unsigned __int64 __cdecl _wcstoui64_l(const wchar_t *_Str,wchar_t **_EndPtr,int _Radix,_locale_t _Locale); +#endif +#endif + +#ifndef _POSIX_ +#ifndef _WSTDLIBP_DEFINED +#define _WSTDLIBP_DEFINED + _CRTIMP wchar_t *__cdecl _wfullpath(wchar_t *_FullPath,const wchar_t *_Path,size_t _SizeInWords); + _CRTIMP void __cdecl _wmakepath(wchar_t *_ResultPath,const wchar_t *_Drive,const wchar_t *_Dir,const wchar_t *_Filename,const wchar_t *_Ext); +#ifndef _CRT_WPERROR_DEFINED +#define _CRT_WPERROR_DEFINED + _CRTIMP void __cdecl _wperror(const wchar_t *_ErrMsg); +#endif + _CRTIMP int __cdecl _wputenv(const wchar_t *_EnvString); + _CRTIMP void __cdecl _wsearchenv(const wchar_t *_Filename,const wchar_t *_EnvVar,wchar_t *_ResultPath); + _CRTIMP void __cdecl _wsplitpath(const wchar_t *_FullPath,wchar_t *_Drive,wchar_t *_Dir,wchar_t *_Filename,wchar_t *_Ext); +#endif +#endif + +#ifndef _WSTRING_DEFINED +#define _WSTRING_DEFINED + _CRTIMP wchar_t *__cdecl _wcsdup(const wchar_t *_Str); + wchar_t *__cdecl wcscat(wchar_t *_Dest,const wchar_t *_Source); + _CONST_RETURN wchar_t *__cdecl wcschr(const wchar_t *_Str,wchar_t _Ch); + int __cdecl wcscmp(const wchar_t *_Str1,const wchar_t *_Str2); + wchar_t *__cdecl wcscpy(wchar_t *_Dest,const wchar_t *_Source); + size_t __cdecl wcscspn(const wchar_t *_Str,const wchar_t *_Control); + size_t __cdecl wcslen(const wchar_t *_Str); + size_t __cdecl wcsnlen(const wchar_t *_Src,size_t _MaxCount); + wchar_t *__cdecl wcsncat(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + int __cdecl wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *__cdecl wcsncpy(wchar_t *_Dest,const wchar_t *_Source,size_t _Count); + _CONST_RETURN wchar_t *__cdecl wcspbrk(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsrchr(const wchar_t *_Str,wchar_t _Ch); + size_t __cdecl wcsspn(const wchar_t *_Str,const wchar_t *_Control); + _CONST_RETURN wchar_t *__cdecl wcsstr(const wchar_t *_Str,const wchar_t *_SubStr); + wchar_t *__cdecl wcstok(wchar_t *_Str,const wchar_t *_Delim); + _CRTIMP wchar_t *__cdecl _wcserror(int _ErrNum); + _CRTIMP wchar_t *__cdecl __wcserror(const wchar_t *_Str); + _CRTIMP int __cdecl _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + _CRTIMP wchar_t *__cdecl _wcsrev(wchar_t *_Str); + _CRTIMP wchar_t *__cdecl _wcsset(wchar_t *_Str,wchar_t _Val); + _CRTIMP wchar_t *__cdecl _wcslwr(wchar_t *_String); + _CRTIMP wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wcsupr(wchar_t *_String); + _CRTIMP wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale); + size_t __cdecl wcsxfrm(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount); + _CRTIMP size_t __cdecl _wcsxfrm_l(wchar_t *_Dst,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale); + int __cdecl wcscoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); + _CRTIMP int __cdecl _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale); + _CRTIMP int __cdecl _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + _CRTIMP int __cdecl _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + _CRTIMP int __cdecl _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale); + +#ifndef NO_OLDNAMES + wchar_t *__cdecl wcsdup(const wchar_t *_Str); +#define wcswcs wcsstr + int __cdecl wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2); + int __cdecl wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount); + wchar_t *__cdecl wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount); + wchar_t *__cdecl wcsrev(wchar_t *_Str); + wchar_t *__cdecl wcsset(wchar_t *_Str,wchar_t _Val); + wchar_t *__cdecl wcslwr(wchar_t *_Str); + wchar_t *__cdecl wcsupr(wchar_t *_Str); + int __cdecl wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2); +#endif +#endif + +#ifndef _TM_DEFINED +#define _TM_DEFINED + struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + }; +#endif + +#ifndef _WTIME_DEFINED +#define _WTIME_DEFINED + + _CRTIMP wchar_t *__cdecl _wasctime(const struct tm *_Tm); + _CRTIMP wchar_t *__cdecl _wctime32(const __time32_t *_Time); + size_t __cdecl wcsftime(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm); + _CRTIMP size_t __cdecl _wcsftime_l(wchar_t *_Buf,size_t _SizeInWords,const wchar_t *_Format,const struct tm *_Tm,_locale_t _Locale); + _CRTIMP wchar_t *__cdecl _wstrdate(wchar_t *_Buffer); + _CRTIMP wchar_t *__cdecl _wstrtime(wchar_t *_Buffer); +#if _INTEGRAL_MAX_BITS >= 64 + _CRTIMP wchar_t *__cdecl _wctime64(const __time64_t *_Time); +#endif + +#if !defined (RC_INVOKED) && !defined (_INC_WTIME_INL) +#define _INC_WTIME_INL +#ifdef _USE_32BIT_TIME_T +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime32(_Time); } +#else +__CRT_INLINE wchar_t *__cdecl _wctime(const time_t *_Time) { return _wctime64(_Time); } +#endif +#endif +#endif + + typedef int mbstate_t; + typedef wchar_t _Wint_t; + + wint_t __cdecl btowc(int); + size_t __cdecl mbrlen(const char *_Ch,size_t _SizeInBytes,mbstate_t *_State); + size_t __cdecl mbrtowc(wchar_t *_DstCh,const char *_SrcCh,size_t _SizeInBytes,mbstate_t *_State); + size_t __cdecl mbsrtowcs(wchar_t *_Dest,const char **_PSrc,size_t _Count,mbstate_t *_State); + size_t __cdecl wcrtomb(char *_Dest,wchar_t _Source,mbstate_t *_State); + size_t __cdecl wcsrtombs(char *_Dest,const wchar_t **_PSource,size_t _Count,mbstate_t *_State); + int __cdecl wctob(wint_t _WCh); + +#ifndef __NO_ISOCEXT /* these need static lib libmingwex.a */ + wchar_t *__cdecl wmemset(wchar_t *s, wchar_t c, size_t n); + _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *s, wchar_t c, size_t n); + int wmemcmp(const wchar_t *s1, const wchar_t *s2,size_t n); + wchar_t *__cdecl wmemcpy(wchar_t *s1,const wchar_t *s2,size_t n); + wchar_t *__cdecl wmemmove(wchar_t *s1, const wchar_t *s2, size_t n); + long long __cdecl wcstoll(const wchar_t *nptr,wchar_t **endptr, int base); + unsigned long long __cdecl wcstoull(const wchar_t *nptr,wchar_t **endptr, int base); +#endif /* __NO_ISOCEXT */ + + void *__cdecl memmove(void *_Dst,const void *_Src,size_t _MaxCount); + void *__cdecl memcpy(void *_Dst,const void *_Src,size_t _MaxCount); + __CRT_INLINE int __cdecl fwide(FILE *_F,int _M) { (void)_F; return (_M); } + __CRT_INLINE int __cdecl mbsinit(const mbstate_t *_P) { return (!_P || *_P==0); } + __CRT_INLINE _CONST_RETURN wchar_t *__cdecl wmemchr(const wchar_t *_S,wchar_t _C,size_t _N) { for (;0<_N;++_S,--_N) if (*_S==_C) return (_CONST_RETURN wchar_t *)(_S); return (0); } + __CRT_INLINE int __cdecl wmemcmp(const wchar_t *_S1,const wchar_t *_S2,size_t _N) { for (; 0 < _N; ++_S1,++_S2,--_N) if (*_S1!=*_S2) return (*_S1 < *_S2 ? -1 : +1); return (0); } + __CRT_INLINE wchar_t *__cdecl wmemcpy(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memcpy(_S1,_S2,_N*sizeof(wchar_t)); } + __CRT_INLINE wchar_t *__cdecl wmemmove(wchar_t *_S1,const wchar_t *_S2,size_t _N) { return (wchar_t *)memmove(_S1,_S2,_N*sizeof(wchar_t)); } + __CRT_INLINE wchar_t *__cdecl wmemset(wchar_t *_S,wchar_t _C,size_t _N) { + wchar_t *_Su = _S; + for (;0<_N;++_Su,--_N) { + *_Su = _C; + } + return (_S); + } +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) + +#include +#endif diff --git a/tcc/include/wctype.h b/tcc/include/wctype.h index 5739f10c..a44cb384 100644 --- a/tcc/include/wctype.h +++ b/tcc/include/wctype.h @@ -1,172 +1,172 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _INC_WCTYPE -#define _INC_WCTYPE - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#include <_mingw.h> - -#pragma pack(push,_CRT_PACKING) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _CRTIMP -#define _CRTIMP __declspec(dllimport) -#endif - -#ifndef _WCHAR_T_DEFINED - typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif - -#ifndef _WCTYPE_T_DEFINED - typedef unsigned short wint_t; - typedef unsigned short wctype_t; -#define _WCTYPE_T_DEFINED -#endif - -#ifndef WEOF -#define WEOF (wint_t)(0xFFFF) -#endif - -#ifndef _CRT_CTYPEDATA_DEFINED -#define _CRT_CTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS - -#ifndef __PCTYPE_FUNC -#define __PCTYPE_FUNC __pctype_func() -#ifdef _MSVCRT_ -#define __pctype_func() (_pctype) -#else -#define __pctype_func() (*_imp___pctype) -#endif -#endif - -#ifndef _pctype -#ifdef _MSVCRT_ - extern unsigned short *_pctype; -#else - extern unsigned short **_imp___pctype; -#define _pctype (*_imp___pctype) -#endif -#endif - -#endif -#endif - -#ifndef _CRT_WCTYPEDATA_DEFINED -#define _CRT_WCTYPEDATA_DEFINED -#ifndef _CTYPE_DISABLE_MACROS -#ifndef _wctype -#ifdef _MSVCRT_ - extern unsigned short *_wctype; -#else - extern unsigned short **_imp___wctype; -#define _wctype (*_imp___wctype) -#endif -#endif - -#ifndef _pwctype -#ifdef _MSVCRT_ - extern unsigned short *_pwctype; -#else - extern unsigned short **_imp___pwctype; -#define _pwctype (*_imp___pwctype) -#define __pwctype_func() (*_imp___pwctype) -#endif -#endif -#endif -#endif - -#define _UPPER 0x1 -#define _LOWER 0x2 -#define _DIGIT 0x4 -#define _SPACE 0x8 - -#define _PUNCT 0x10 -#define _CONTROL 0x20 -#define _BLANK 0x40 -#define _HEX 0x80 - -#define _LEADBYTE 0x8000 -#define _ALPHA (0x0100|_UPPER|_LOWER) - -#ifndef _WCTYPE_DEFINED -#define _WCTYPE_DEFINED - - int __cdecl iswalpha(wint_t); - int __cdecl iswupper(wint_t); - int __cdecl iswlower(wint_t); - int __cdecl iswdigit(wint_t); - int __cdecl iswxdigit(wint_t); - int __cdecl iswspace(wint_t); - int __cdecl iswpunct(wint_t); - int __cdecl iswalnum(wint_t); - int __cdecl iswprint(wint_t); - int __cdecl iswgraph(wint_t); - int __cdecl iswcntrl(wint_t); - int __cdecl iswascii(wint_t); - int __cdecl isleadbyte(int); - wint_t __cdecl towupper(wint_t); - wint_t __cdecl towlower(wint_t); - int __cdecl iswctype(wint_t,wctype_t); - _CRTIMP int __cdecl __iswcsymf(wint_t); - _CRTIMP int __cdecl __iswcsym(wint_t); - int __cdecl is_wctype(wint_t,wctype_t); -#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) -int __cdecl isblank(int _C); -#endif -#endif - -#ifndef _WCTYPE_INLINE_DEFINED -#define _WCTYPE_INLINE_DEFINED -#ifndef __cplusplus -#define iswalpha(_c) (iswctype(_c,_ALPHA)) -#define iswupper(_c) (iswctype(_c,_UPPER)) -#define iswlower(_c) (iswctype(_c,_LOWER)) -#define iswdigit(_c) (iswctype(_c,_DIGIT)) -#define iswxdigit(_c) (iswctype(_c,_HEX)) -#define iswspace(_c) (iswctype(_c,_SPACE)) -#define iswpunct(_c) (iswctype(_c,_PUNCT)) -#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) -#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) -#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) -#define iswcntrl(_c) (iswctype(_c,_CONTROL)) -#define iswascii(_c) ((unsigned)(_c) < 0x80) -#define isleadbyte(c) (__pctype_func()[(unsigned char)(c)] & _LEADBYTE) -#else - __CRT_INLINE int __cdecl iswalpha(wint_t _C) {return (iswctype(_C,_ALPHA)); } - __CRT_INLINE int __cdecl iswupper(wint_t _C) {return (iswctype(_C,_UPPER)); } - __CRT_INLINE int __cdecl iswlower(wint_t _C) {return (iswctype(_C,_LOWER)); } - __CRT_INLINE int __cdecl iswdigit(wint_t _C) {return (iswctype(_C,_DIGIT)); } - __CRT_INLINE int __cdecl iswxdigit(wint_t _C) {return (iswctype(_C,_HEX)); } - __CRT_INLINE int __cdecl iswspace(wint_t _C) {return (iswctype(_C,_SPACE)); } - __CRT_INLINE int __cdecl iswpunct(wint_t _C) {return (iswctype(_C,_PUNCT)); } - __CRT_INLINE int __cdecl iswalnum(wint_t _C) {return (iswctype(_C,_ALPHA|_DIGIT)); } - __CRT_INLINE int __cdecl iswprint(wint_t _C) {return (iswctype(_C,_BLANK|_PUNCT|_ALPHA|_DIGIT)); } - __CRT_INLINE int __cdecl iswgraph(wint_t _C) {return (iswctype(_C,_PUNCT|_ALPHA|_DIGIT)); } - __CRT_INLINE int __cdecl iswcntrl(wint_t _C) {return (iswctype(_C,_CONTROL)); } - __CRT_INLINE int __cdecl iswascii(wint_t _C) {return ((unsigned)(_C) < 0x80); } - __CRT_INLINE int __cdecl isleadbyte(int _C) {return (__pctype_func()[(unsigned char)(_C)] & _LEADBYTE); } -#endif -#endif - - typedef wchar_t wctrans_t; - wint_t __cdecl towctrans(wint_t,wctrans_t); - wctrans_t __cdecl wctrans(const char *); - wctype_t __cdecl wctype(const char *); - -#ifdef __cplusplus -} -#endif - -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _INC_WCTYPE +#define _INC_WCTYPE + +#ifndef _WIN32 +#error Only Win32 target is supported! +#endif + +#include <_mingw.h> + +#pragma pack(push,_CRT_PACKING) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _CRTIMP +#define _CRTIMP __declspec(dllimport) +#endif + +#ifndef _WCHAR_T_DEFINED + typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +#ifndef _WCTYPE_T_DEFINED + typedef unsigned short wint_t; + typedef unsigned short wctype_t; +#define _WCTYPE_T_DEFINED +#endif + +#ifndef WEOF +#define WEOF (wint_t)(0xFFFF) +#endif + +#ifndef _CRT_CTYPEDATA_DEFINED +#define _CRT_CTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS + +#ifndef __PCTYPE_FUNC +#define __PCTYPE_FUNC __pctype_func() +#ifdef _MSVCRT_ +#define __pctype_func() (_pctype) +#else +#define __pctype_func() (*_imp___pctype) +#endif +#endif + +#ifndef _pctype +#ifdef _MSVCRT_ + extern unsigned short *_pctype; +#else + extern unsigned short **_imp___pctype; +#define _pctype (*_imp___pctype) +#endif +#endif + +#endif +#endif + +#ifndef _CRT_WCTYPEDATA_DEFINED +#define _CRT_WCTYPEDATA_DEFINED +#ifndef _CTYPE_DISABLE_MACROS +#ifndef _wctype +#ifdef _MSVCRT_ + extern unsigned short *_wctype; +#else + extern unsigned short **_imp___wctype; +#define _wctype (*_imp___wctype) +#endif +#endif + +#ifndef _pwctype +#ifdef _MSVCRT_ + extern unsigned short *_pwctype; +#else + extern unsigned short **_imp___pwctype; +#define _pwctype (*_imp___pwctype) +#define __pwctype_func() (*_imp___pwctype) +#endif +#endif +#endif +#endif + +#define _UPPER 0x1 +#define _LOWER 0x2 +#define _DIGIT 0x4 +#define _SPACE 0x8 + +#define _PUNCT 0x10 +#define _CONTROL 0x20 +#define _BLANK 0x40 +#define _HEX 0x80 + +#define _LEADBYTE 0x8000 +#define _ALPHA (0x0100|_UPPER|_LOWER) + +#ifndef _WCTYPE_DEFINED +#define _WCTYPE_DEFINED + + int __cdecl iswalpha(wint_t); + int __cdecl iswupper(wint_t); + int __cdecl iswlower(wint_t); + int __cdecl iswdigit(wint_t); + int __cdecl iswxdigit(wint_t); + int __cdecl iswspace(wint_t); + int __cdecl iswpunct(wint_t); + int __cdecl iswalnum(wint_t); + int __cdecl iswprint(wint_t); + int __cdecl iswgraph(wint_t); + int __cdecl iswcntrl(wint_t); + int __cdecl iswascii(wint_t); + int __cdecl isleadbyte(int); + wint_t __cdecl towupper(wint_t); + wint_t __cdecl towlower(wint_t); + int __cdecl iswctype(wint_t,wctype_t); + _CRTIMP int __cdecl __iswcsymf(wint_t); + _CRTIMP int __cdecl __iswcsym(wint_t); + int __cdecl is_wctype(wint_t,wctype_t); +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || !defined (NO_OLDNAMES) +int __cdecl isblank(int _C); +#endif +#endif + +#ifndef _WCTYPE_INLINE_DEFINED +#define _WCTYPE_INLINE_DEFINED +#ifndef __cplusplus +#define iswalpha(_c) (iswctype(_c,_ALPHA)) +#define iswupper(_c) (iswctype(_c,_UPPER)) +#define iswlower(_c) (iswctype(_c,_LOWER)) +#define iswdigit(_c) (iswctype(_c,_DIGIT)) +#define iswxdigit(_c) (iswctype(_c,_HEX)) +#define iswspace(_c) (iswctype(_c,_SPACE)) +#define iswpunct(_c) (iswctype(_c,_PUNCT)) +#define iswalnum(_c) (iswctype(_c,_ALPHA|_DIGIT)) +#define iswprint(_c) (iswctype(_c,_BLANK|_PUNCT|_ALPHA|_DIGIT)) +#define iswgraph(_c) (iswctype(_c,_PUNCT|_ALPHA|_DIGIT)) +#define iswcntrl(_c) (iswctype(_c,_CONTROL)) +#define iswascii(_c) ((unsigned)(_c) < 0x80) +#define isleadbyte(c) (__pctype_func()[(unsigned char)(c)] & _LEADBYTE) +#else + __CRT_INLINE int __cdecl iswalpha(wint_t _C) {return (iswctype(_C,_ALPHA)); } + __CRT_INLINE int __cdecl iswupper(wint_t _C) {return (iswctype(_C,_UPPER)); } + __CRT_INLINE int __cdecl iswlower(wint_t _C) {return (iswctype(_C,_LOWER)); } + __CRT_INLINE int __cdecl iswdigit(wint_t _C) {return (iswctype(_C,_DIGIT)); } + __CRT_INLINE int __cdecl iswxdigit(wint_t _C) {return (iswctype(_C,_HEX)); } + __CRT_INLINE int __cdecl iswspace(wint_t _C) {return (iswctype(_C,_SPACE)); } + __CRT_INLINE int __cdecl iswpunct(wint_t _C) {return (iswctype(_C,_PUNCT)); } + __CRT_INLINE int __cdecl iswalnum(wint_t _C) {return (iswctype(_C,_ALPHA|_DIGIT)); } + __CRT_INLINE int __cdecl iswprint(wint_t _C) {return (iswctype(_C,_BLANK|_PUNCT|_ALPHA|_DIGIT)); } + __CRT_INLINE int __cdecl iswgraph(wint_t _C) {return (iswctype(_C,_PUNCT|_ALPHA|_DIGIT)); } + __CRT_INLINE int __cdecl iswcntrl(wint_t _C) {return (iswctype(_C,_CONTROL)); } + __CRT_INLINE int __cdecl iswascii(wint_t _C) {return ((unsigned)(_C) < 0x80); } + __CRT_INLINE int __cdecl isleadbyte(int _C) {return (__pctype_func()[(unsigned char)(_C)] & _LEADBYTE); } +#endif +#endif + + typedef wchar_t wctrans_t; + wint_t __cdecl towctrans(wint_t,wctrans_t); + wctrans_t __cdecl wctrans(const char *); + wctype_t __cdecl wctype(const char *); + +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif diff --git a/tcc/include/winapi/basetsd.h b/tcc/include/winapi/basetsd.h index adc29da9..47d78c4c 100644 --- a/tcc/include/winapi/basetsd.h +++ b/tcc/include/winapi/basetsd.h @@ -1,149 +1,149 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _BASETSD_H_ -#define _BASETSD_H_ - -#if (defined(__x86_64) || defined(__ia64__)) && !defined(RC_INVOKED) -typedef unsigned __int64 POINTER_64_INT; -#else -typedef unsigned long POINTER_64_INT; -#endif - -#define POINTER_32 -#define POINTER_64 -#define FIRMWARE_PTR - -#ifdef __cplusplus -extern "C" { -#endif - - typedef signed char INT8,*PINT8; - typedef signed short INT16,*PINT16; - typedef signed int INT32,*PINT32; - typedef signed __int64 INT64,*PINT64; - typedef unsigned char UINT8,*PUINT8; - typedef unsigned short UINT16,*PUINT16; - typedef unsigned int UINT32,*PUINT32; - typedef unsigned __int64 UINT64,*PUINT64; - typedef signed int LONG32,*PLONG32; - typedef unsigned int ULONG32,*PULONG32; - typedef unsigned int DWORD32,*PDWORD32; - -#ifndef _W64 -#define _W64 -#endif - -#ifdef _WIN64 - typedef __int64 INT_PTR,*PINT_PTR; - typedef unsigned __int64 UINT_PTR,*PUINT_PTR; - typedef __int64 LONG_PTR,*PLONG_PTR; - typedef unsigned __int64 ULONG_PTR,*PULONG_PTR; -#define __int3264 __int64 -#else - typedef int INT_PTR,*PINT_PTR; - typedef unsigned int UINT_PTR,*PUINT_PTR; - typedef long LONG_PTR,*PLONG_PTR; - typedef unsigned long ULONG_PTR,*PULONG_PTR; -#define __int3264 __int32 -#endif - -#ifdef _WIN64 -#define ADDRESS_TAG_BIT 0x40000000000ULL - typedef __int64 SHANDLE_PTR; - typedef unsigned __int64 HANDLE_PTR; - typedef unsigned int UHALF_PTR,*PUHALF_PTR; - typedef int HALF_PTR,*PHALF_PTR; - - static __inline unsigned long HandleToULong(const void *h) { return((unsigned long) (ULONG_PTR) h); } - static __inline long HandleToLong(const void *h) { return((long) (LONG_PTR) h); } - static __inline void *ULongToHandle(const unsigned long h) { return((void *) (UINT_PTR) h); } - static __inline void *LongToHandle(const long h) { return((void *) (INT_PTR) h); } - static __inline unsigned long PtrToUlong(const void *p) { return((unsigned long) (ULONG_PTR) p); } - static __inline unsigned int PtrToUint(const void *p) { return((unsigned int) (UINT_PTR) p); } - static __inline unsigned short PtrToUshort(const void *p) { return((unsigned short) (unsigned long) (ULONG_PTR) p); } - static __inline long PtrToLong(const void *p) { return((long) (LONG_PTR) p); } - static __inline int PtrToInt(const void *p) { return((int) (INT_PTR) p); } - static __inline short PtrToShort(const void *p) { return((short) (long) (LONG_PTR) p); } - static __inline void *IntToPtr(const int i) { return((void *)(INT_PTR)i); } - static __inline void *UIntToPtr(const unsigned int ui) { return((void *)(UINT_PTR)ui); } - static __inline void *LongToPtr(const long l) { return((void *)(LONG_PTR)l); } - static __inline void *ULongToPtr(const unsigned long ul) { return((void *)(ULONG_PTR)ul); } - -#define PtrToPtr64(p) ((void *) p) -#define Ptr64ToPtr(p) ((void *) p) -#define HandleToHandle64(h) (PtrToPtr64(h)) -#define Handle64ToHandle(h) (Ptr64ToPtr(h)) - - static __inline void *Ptr32ToPtr(const void *p) { return (void *)p; } - static __inline void *Handle32ToHandle(const void *h) { return((void *) h); } - static __inline void *PtrToPtr32(const void *p) { return((void *) (ULONG_PTR) p); } - -#define HandleToHandle32(h) (PtrToPtr32(h)) -#else - -#define ADDRESS_TAG_BIT 0x80000000UL - - typedef unsigned short UHALF_PTR,*PUHALF_PTR; - typedef short HALF_PTR,*PHALF_PTR; - typedef long SHANDLE_PTR; - typedef unsigned long HANDLE_PTR; - -#define HandleToULong(h) ((ULONG)(ULONG_PTR)(h)) -#define HandleToLong(h) ((LONG)(LONG_PTR) (h)) -#define ULongToHandle(ul) ((HANDLE)(ULONG_PTR) (ul)) -#define LongToHandle(h) ((HANDLE)(LONG_PTR) (h)) -#define PtrToUlong(p) ((ULONG)(ULONG_PTR) (p)) -#define PtrToLong(p) ((LONG)(LONG_PTR) (p)) -#define PtrToUint(p) ((UINT)(UINT_PTR) (p)) -#define PtrToInt(p) ((INT)(INT_PTR) (p)) -#define PtrToUshort(p) ((unsigned short)(ULONG_PTR)(p)) -#define PtrToShort(p) ((short)(LONG_PTR)(p)) -#define IntToPtr(i) ((VOID *)(INT_PTR)((int)i)) -#define UIntToPtr(ui) ((VOID *)(UINT_PTR)((unsigned int)ui)) -#define LongToPtr(l) ((VOID *)(LONG_PTR)((long)l)) -#define ULongToPtr(ul) ((VOID *)(ULONG_PTR)((unsigned long)ul)) - - static __inline void *PtrToPtr64(const void *p) { return((void *) (ULONG_PTR)p); } - static __inline void *Ptr64ToPtr(const void *p) { return((void *) (ULONG_PTR) p); } - static __inline void *HandleToHandle64(const void *h) { return((void *) h); } - static __inline void *Handle64ToHandle(const void *h) { return((void *) (ULONG_PTR) h); } - -#define Ptr32ToPtr(p) ((void *) p) -#define Handle32ToHandle(h) (Ptr32ToPtr(h)) -#define PtrToPtr32(p) ((void *) p) -#define HandleToHandle32(h) (PtrToPtr32(h)) -#endif - -#define HandleToUlong(h) HandleToULong(h) -#define UlongToHandle(ul) ULongToHandle(ul) -#define UlongToPtr(ul) ULongToPtr(ul) -#define UintToPtr(ui) UIntToPtr(ui) - -#define MAXUINT_PTR (~((UINT_PTR)0)) -#define MAXINT_PTR ((INT_PTR)(MAXUINT_PTR >> 1)) -#define MININT_PTR (~MAXINT_PTR) - -#define MAXULONG_PTR (~((ULONG_PTR)0)) -#define MAXLONG_PTR ((LONG_PTR)(MAXULONG_PTR >> 1)) -#define MINLONG_PTR (~MAXLONG_PTR) - -#define MAXUHALF_PTR ((UHALF_PTR)~0) -#define MAXHALF_PTR ((HALF_PTR)(MAXUHALF_PTR >> 1)) -#define MINHALF_PTR (~MAXHALF_PTR) - - typedef ULONG_PTR SIZE_T,*PSIZE_T; - typedef LONG_PTR SSIZE_T,*PSSIZE_T; - typedef ULONG_PTR DWORD_PTR,*PDWORD_PTR; - typedef __int64 LONG64,*PLONG64; - typedef unsigned __int64 ULONG64,*PULONG64; - typedef unsigned __int64 DWORD64,*PDWORD64; - typedef ULONG_PTR KAFFINITY; - typedef KAFFINITY *PKAFFINITY; - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _BASETSD_H_ +#define _BASETSD_H_ + +#if (defined(__x86_64) || defined(__ia64__)) && !defined(RC_INVOKED) +typedef unsigned __int64 POINTER_64_INT; +#else +typedef unsigned long POINTER_64_INT; +#endif + +#define POINTER_32 +#define POINTER_64 +#define FIRMWARE_PTR + +#ifdef __cplusplus +extern "C" { +#endif + + typedef signed char INT8,*PINT8; + typedef signed short INT16,*PINT16; + typedef signed int INT32,*PINT32; + typedef signed __int64 INT64,*PINT64; + typedef unsigned char UINT8,*PUINT8; + typedef unsigned short UINT16,*PUINT16; + typedef unsigned int UINT32,*PUINT32; + typedef unsigned __int64 UINT64,*PUINT64; + typedef signed int LONG32,*PLONG32; + typedef unsigned int ULONG32,*PULONG32; + typedef unsigned int DWORD32,*PDWORD32; + +#ifndef _W64 +#define _W64 +#endif + +#ifdef _WIN64 + typedef __int64 INT_PTR,*PINT_PTR; + typedef unsigned __int64 UINT_PTR,*PUINT_PTR; + typedef __int64 LONG_PTR,*PLONG_PTR; + typedef unsigned __int64 ULONG_PTR,*PULONG_PTR; +#define __int3264 __int64 +#else + typedef int INT_PTR,*PINT_PTR; + typedef unsigned int UINT_PTR,*PUINT_PTR; + typedef long LONG_PTR,*PLONG_PTR; + typedef unsigned long ULONG_PTR,*PULONG_PTR; +#define __int3264 __int32 +#endif + +#ifdef _WIN64 +#define ADDRESS_TAG_BIT 0x40000000000ULL + typedef __int64 SHANDLE_PTR; + typedef unsigned __int64 HANDLE_PTR; + typedef unsigned int UHALF_PTR,*PUHALF_PTR; + typedef int HALF_PTR,*PHALF_PTR; + + static __inline unsigned long HandleToULong(const void *h) { return((unsigned long) (ULONG_PTR) h); } + static __inline long HandleToLong(const void *h) { return((long) (LONG_PTR) h); } + static __inline void *ULongToHandle(const unsigned long h) { return((void *) (UINT_PTR) h); } + static __inline void *LongToHandle(const long h) { return((void *) (INT_PTR) h); } + static __inline unsigned long PtrToUlong(const void *p) { return((unsigned long) (ULONG_PTR) p); } + static __inline unsigned int PtrToUint(const void *p) { return((unsigned int) (UINT_PTR) p); } + static __inline unsigned short PtrToUshort(const void *p) { return((unsigned short) (unsigned long) (ULONG_PTR) p); } + static __inline long PtrToLong(const void *p) { return((long) (LONG_PTR) p); } + static __inline int PtrToInt(const void *p) { return((int) (INT_PTR) p); } + static __inline short PtrToShort(const void *p) { return((short) (long) (LONG_PTR) p); } + static __inline void *IntToPtr(const int i) { return((void *)(INT_PTR)i); } + static __inline void *UIntToPtr(const unsigned int ui) { return((void *)(UINT_PTR)ui); } + static __inline void *LongToPtr(const long l) { return((void *)(LONG_PTR)l); } + static __inline void *ULongToPtr(const unsigned long ul) { return((void *)(ULONG_PTR)ul); } + +#define PtrToPtr64(p) ((void *) p) +#define Ptr64ToPtr(p) ((void *) p) +#define HandleToHandle64(h) (PtrToPtr64(h)) +#define Handle64ToHandle(h) (Ptr64ToPtr(h)) + + static __inline void *Ptr32ToPtr(const void *p) { return (void *)p; } + static __inline void *Handle32ToHandle(const void *h) { return((void *) h); } + static __inline void *PtrToPtr32(const void *p) { return((void *) (ULONG_PTR) p); } + +#define HandleToHandle32(h) (PtrToPtr32(h)) +#else + +#define ADDRESS_TAG_BIT 0x80000000UL + + typedef unsigned short UHALF_PTR,*PUHALF_PTR; + typedef short HALF_PTR,*PHALF_PTR; + typedef long SHANDLE_PTR; + typedef unsigned long HANDLE_PTR; + +#define HandleToULong(h) ((ULONG)(ULONG_PTR)(h)) +#define HandleToLong(h) ((LONG)(LONG_PTR) (h)) +#define ULongToHandle(ul) ((HANDLE)(ULONG_PTR) (ul)) +#define LongToHandle(h) ((HANDLE)(LONG_PTR) (h)) +#define PtrToUlong(p) ((ULONG)(ULONG_PTR) (p)) +#define PtrToLong(p) ((LONG)(LONG_PTR) (p)) +#define PtrToUint(p) ((UINT)(UINT_PTR) (p)) +#define PtrToInt(p) ((INT)(INT_PTR) (p)) +#define PtrToUshort(p) ((unsigned short)(ULONG_PTR)(p)) +#define PtrToShort(p) ((short)(LONG_PTR)(p)) +#define IntToPtr(i) ((VOID *)(INT_PTR)((int)i)) +#define UIntToPtr(ui) ((VOID *)(UINT_PTR)((unsigned int)ui)) +#define LongToPtr(l) ((VOID *)(LONG_PTR)((long)l)) +#define ULongToPtr(ul) ((VOID *)(ULONG_PTR)((unsigned long)ul)) + + static __inline void *PtrToPtr64(const void *p) { return((void *) (ULONG_PTR)p); } + static __inline void *Ptr64ToPtr(const void *p) { return((void *) (ULONG_PTR) p); } + static __inline void *HandleToHandle64(const void *h) { return((void *) h); } + static __inline void *Handle64ToHandle(const void *h) { return((void *) (ULONG_PTR) h); } + +#define Ptr32ToPtr(p) ((void *) p) +#define Handle32ToHandle(h) (Ptr32ToPtr(h)) +#define PtrToPtr32(p) ((void *) p) +#define HandleToHandle32(h) (PtrToPtr32(h)) +#endif + +#define HandleToUlong(h) HandleToULong(h) +#define UlongToHandle(ul) ULongToHandle(ul) +#define UlongToPtr(ul) ULongToPtr(ul) +#define UintToPtr(ui) UIntToPtr(ui) + +#define MAXUINT_PTR (~((UINT_PTR)0)) +#define MAXINT_PTR ((INT_PTR)(MAXUINT_PTR >> 1)) +#define MININT_PTR (~MAXINT_PTR) + +#define MAXULONG_PTR (~((ULONG_PTR)0)) +#define MAXLONG_PTR ((LONG_PTR)(MAXULONG_PTR >> 1)) +#define MINLONG_PTR (~MAXLONG_PTR) + +#define MAXUHALF_PTR ((UHALF_PTR)~0) +#define MAXHALF_PTR ((HALF_PTR)(MAXUHALF_PTR >> 1)) +#define MINHALF_PTR (~MAXHALF_PTR) + + typedef ULONG_PTR SIZE_T,*PSIZE_T; + typedef LONG_PTR SSIZE_T,*PSSIZE_T; + typedef ULONG_PTR DWORD_PTR,*PDWORD_PTR; + typedef __int64 LONG64,*PLONG64; + typedef unsigned __int64 ULONG64,*PULONG64; + typedef unsigned __int64 DWORD64,*PDWORD64; + typedef ULONG_PTR KAFFINITY; + typedef KAFFINITY *PKAFFINITY; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/basetyps.h b/tcc/include/winapi/basetyps.h index 698ec7ee..376665e7 100644 --- a/tcc/include/winapi/basetyps.h +++ b/tcc/include/winapi/basetyps.h @@ -1,85 +1,85 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !defined(_BASETYPS_H_) -#define _BASETYPS_H_ - -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C extern -#endif - -#define STDMETHODCALLTYPE WINAPI -#define STDMETHODVCALLTYPE __cdecl - -#define STDAPICALLTYPE WINAPI -#define STDAPIVCALLTYPE __cdecl - -#define STDAPI EXTERN_C HRESULT WINAPI -#define STDAPI_(type) EXTERN_C type WINAPI - -#define STDMETHODIMP HRESULT WINAPI -#define STDMETHODIMP_(type) type WINAPI - -#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE -#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE - -#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE -#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE - -#if defined(__cplusplus) && !defined(CINTERFACE) - -#define __STRUCT__ struct -#define STDMETHOD(method) virtual HRESULT WINAPI method -#define STDMETHOD_(type,method) virtual type WINAPI method -#define STDMETHODV(method) virtual HRESULT STDMETHODVCALLTYPE method -#define STDMETHODV_(type,method) virtual type STDMETHODVCALLTYPE method -#define PURE = 0 -#define THIS_ -#define THIS void -#define DECLARE_INTERFACE(iface) __STRUCT__ iface -#define DECLARE_INTERFACE_(iface,baseiface) __STRUCT__ iface : public baseiface -#else - -#ifndef __OBJC__ -#define interface struct -#endif - -#define STDMETHOD(method) HRESULT (WINAPI *method) -#define STDMETHOD_(type,method) type (WINAPI *method) -#define STDMETHODV(method) HRESULT (STDMETHODVCALLTYPE *method) -#define STDMETHODV_(type,method) type (STDMETHODVCALLTYPE *method) - -#define PURE -#define THIS_ INTERFACE *This, -#define THIS INTERFACE *This -#ifdef CONST_VTABLE -#define DECLARE_INTERFACE(iface) typedef struct iface { \ - const struct iface##Vtbl *lpVtbl; } iface; \ - typedef const struct iface##Vtbl iface##Vtbl; \ - const struct iface##Vtbl -#else -#define DECLARE_INTERFACE(iface) typedef struct iface { \ - struct iface##Vtbl *lpVtbl; \ - } iface; \ - typedef struct iface##Vtbl iface##Vtbl; \ - struct iface##Vtbl -#endif -#define DECLARE_INTERFACE_(iface,baseiface) DECLARE_INTERFACE(iface) -#endif - -#include - -#ifndef _ERROR_STATUS_T_DEFINED -#define _ERROR_STATUS_T_DEFINED -typedef unsigned long error_status_t; -#endif - -#ifndef _WCHAR_T_DEFINED -typedef unsigned short wchar_t; -#define _WCHAR_T_DEFINED -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !defined(_BASETYPS_H_) +#define _BASETYPS_H_ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C extern +#endif + +#define STDMETHODCALLTYPE WINAPI +#define STDMETHODVCALLTYPE __cdecl + +#define STDAPICALLTYPE WINAPI +#define STDAPIVCALLTYPE __cdecl + +#define STDAPI EXTERN_C HRESULT WINAPI +#define STDAPI_(type) EXTERN_C type WINAPI + +#define STDMETHODIMP HRESULT WINAPI +#define STDMETHODIMP_(type) type WINAPI + +#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE +#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE + +#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE +#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE + +#if defined(__cplusplus) && !defined(CINTERFACE) + +#define __STRUCT__ struct +#define STDMETHOD(method) virtual HRESULT WINAPI method +#define STDMETHOD_(type,method) virtual type WINAPI method +#define STDMETHODV(method) virtual HRESULT STDMETHODVCALLTYPE method +#define STDMETHODV_(type,method) virtual type STDMETHODVCALLTYPE method +#define PURE = 0 +#define THIS_ +#define THIS void +#define DECLARE_INTERFACE(iface) __STRUCT__ iface +#define DECLARE_INTERFACE_(iface,baseiface) __STRUCT__ iface : public baseiface +#else + +#ifndef __OBJC__ +#define interface struct +#endif + +#define STDMETHOD(method) HRESULT (WINAPI *method) +#define STDMETHOD_(type,method) type (WINAPI *method) +#define STDMETHODV(method) HRESULT (STDMETHODVCALLTYPE *method) +#define STDMETHODV_(type,method) type (STDMETHODVCALLTYPE *method) + +#define PURE +#define THIS_ INTERFACE *This, +#define THIS INTERFACE *This +#ifdef CONST_VTABLE +#define DECLARE_INTERFACE(iface) typedef struct iface { \ + const struct iface##Vtbl *lpVtbl; } iface; \ + typedef const struct iface##Vtbl iface##Vtbl; \ + const struct iface##Vtbl +#else +#define DECLARE_INTERFACE(iface) typedef struct iface { \ + struct iface##Vtbl *lpVtbl; \ + } iface; \ + typedef struct iface##Vtbl iface##Vtbl; \ + struct iface##Vtbl +#endif +#define DECLARE_INTERFACE_(iface,baseiface) DECLARE_INTERFACE(iface) +#endif + +#include + +#ifndef _ERROR_STATUS_T_DEFINED +#define _ERROR_STATUS_T_DEFINED +typedef unsigned long error_status_t; +#endif + +#ifndef _WCHAR_T_DEFINED +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif +#endif diff --git a/tcc/include/winapi/guiddef.h b/tcc/include/winapi/guiddef.h index aab49b3b..4e7909a9 100644 --- a/tcc/include/winapi/guiddef.h +++ b/tcc/include/winapi/guiddef.h @@ -1,156 +1,156 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef GUID_DEFINED -#define GUID_DEFINED -typedef struct _GUID { - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[8 ]; -} GUID; -#endif - -#ifndef UUID_DEFINED -#define UUID_DEFINED -typedef GUID UUID; -#endif - -#ifndef FAR -#define FAR -#endif - -#ifndef DECLSPEC_SELECTANY -#define DECLSPEC_SELECTANY __declspec(selectany) -#endif - -#ifndef EXTERN_C -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C extern -#endif -#endif - -#ifdef DEFINE_GUID -#undef DEFINE_GUID -#endif - -#ifdef INITGUID -#ifdef __cplusplus -#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } -#else -#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } -#endif -#else -#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID name -#endif - -#define DEFINE_OLEGUID(name,l,w1,w2) DEFINE_GUID(name,l,w1,w2,0xC0,0,0,0,0,0,0,0x46) - -#ifndef _GUIDDEF_H_ -#define _GUIDDEF_H_ - -#ifndef __LPGUID_DEFINED__ -#define __LPGUID_DEFINED__ -typedef GUID *LPGUID; -#endif - -#ifndef __LPCGUID_DEFINED__ -#define __LPCGUID_DEFINED__ -typedef const GUID *LPCGUID; -#endif - -#ifndef __IID_DEFINED__ -#define __IID_DEFINED__ - -typedef GUID IID; -typedef IID *LPIID; -#define IID_NULL GUID_NULL -#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) -typedef GUID CLSID; -typedef CLSID *LPCLSID; -#define CLSID_NULL GUID_NULL -#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) -typedef GUID FMTID; -typedef FMTID *LPFMTID; -#define FMTID_NULL GUID_NULL -#define IsEqualFMTID(rfmtid1,rfmtid2) IsEqualGUID(rfmtid1,rfmtid2) - -#ifdef __midl_proxy -#define __MIDL_CONST -#else -#define __MIDL_CONST const -#endif - -#ifndef _REFGUID_DEFINED -#define _REFGUID_DEFINED -#ifdef __cplusplus -#define REFGUID const GUID & -#else -#define REFGUID const GUID *__MIDL_CONST -#endif -#endif - -#ifndef _REFIID_DEFINED -#define _REFIID_DEFINED -#ifdef __cplusplus -#define REFIID const IID & -#else -#define REFIID const IID *__MIDL_CONST -#endif -#endif - -#ifndef _REFCLSID_DEFINED -#define _REFCLSID_DEFINED -#ifdef __cplusplus -#define REFCLSID const IID & -#else -#define REFCLSID const IID *__MIDL_CONST -#endif -#endif - -#ifndef _REFFMTID_DEFINED -#define _REFFMTID_DEFINED -#ifdef __cplusplus -#define REFFMTID const IID & -#else -#define REFFMTID const IID *__MIDL_CONST -#endif -#endif -#endif - -#ifndef _SYS_GUID_OPERATORS_ -#define _SYS_GUID_OPERATORS_ -#include - -#ifdef __cplusplus -__inline int InlineIsEqualGUID(REFGUID rguid1,REFGUID rguid2) { - return (((unsigned long *) &rguid1)[0]==((unsigned long *) &rguid2)[0] && ((unsigned long *) &rguid1)[1]==((unsigned long *) &rguid2)[1] && - ((unsigned long *) &rguid1)[2]==((unsigned long *) &rguid2)[2] && ((unsigned long *) &rguid1)[3]==((unsigned long *) &rguid2)[3]); -} -__inline int IsEqualGUID(REFGUID rguid1,REFGUID rguid2) { return !memcmp(&rguid1,&rguid2,sizeof(GUID)); } -#else -#define InlineIsEqualGUID(rguid1,rguid2) (((unsigned long *) rguid1)[0]==((unsigned long *) rguid2)[0] && ((unsigned long *) rguid1)[1]==((unsigned long *) rguid2)[1] && ((unsigned long *) rguid1)[2]==((unsigned long *) rguid2)[2] && ((unsigned long *) rguid1)[3]==((unsigned long *) rguid2)[3]) -#define IsEqualGUID(rguid1,rguid2) (!memcmp(rguid1,rguid2,sizeof(GUID))) -#endif - -#ifdef __INLINE_ISEQUAL_GUID -#undef IsEqualGUID -#define IsEqualGUID(rguid1,rguid2) InlineIsEqualGUID(rguid1,rguid2) -#endif - -#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) -#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) - -#if !defined _SYS_GUID_OPERATOR_EQ_ && !defined _NO_SYS_GUID_OPERATOR_EQ_ -#define _SYS_GUID_OPERATOR_EQ_ -#ifdef __cplusplus -__inline int operator==(REFGUID guidOne,REFGUID guidOther) { return IsEqualGUID(guidOne,guidOther); } -__inline int operator!=(REFGUID guidOne,REFGUID guidOther) { return !(guidOne==guidOther); } -#endif -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID { + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8 ]; +} GUID; +#endif + +#ifndef UUID_DEFINED +#define UUID_DEFINED +typedef GUID UUID; +#endif + +#ifndef FAR +#define FAR +#endif + +#ifndef DECLSPEC_SELECTANY +#define DECLSPEC_SELECTANY __declspec(selectany) +#endif + +#ifndef EXTERN_C +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C extern +#endif +#endif + +#ifdef DEFINE_GUID +#undef DEFINE_GUID +#endif + +#ifdef INITGUID +#ifdef __cplusplus +#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } +#else +#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) const GUID DECLSPEC_SELECTANY name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } +#endif +#else +#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) EXTERN_C const GUID name +#endif + +#define DEFINE_OLEGUID(name,l,w1,w2) DEFINE_GUID(name,l,w1,w2,0xC0,0,0,0,0,0,0,0x46) + +#ifndef _GUIDDEF_H_ +#define _GUIDDEF_H_ + +#ifndef __LPGUID_DEFINED__ +#define __LPGUID_DEFINED__ +typedef GUID *LPGUID; +#endif + +#ifndef __LPCGUID_DEFINED__ +#define __LPCGUID_DEFINED__ +typedef const GUID *LPCGUID; +#endif + +#ifndef __IID_DEFINED__ +#define __IID_DEFINED__ + +typedef GUID IID; +typedef IID *LPIID; +#define IID_NULL GUID_NULL +#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) +typedef GUID CLSID; +typedef CLSID *LPCLSID; +#define CLSID_NULL GUID_NULL +#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) +typedef GUID FMTID; +typedef FMTID *LPFMTID; +#define FMTID_NULL GUID_NULL +#define IsEqualFMTID(rfmtid1,rfmtid2) IsEqualGUID(rfmtid1,rfmtid2) + +#ifdef __midl_proxy +#define __MIDL_CONST +#else +#define __MIDL_CONST const +#endif + +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#ifdef __cplusplus +#define REFGUID const GUID & +#else +#define REFGUID const GUID *__MIDL_CONST +#endif +#endif + +#ifndef _REFIID_DEFINED +#define _REFIID_DEFINED +#ifdef __cplusplus +#define REFIID const IID & +#else +#define REFIID const IID *__MIDL_CONST +#endif +#endif + +#ifndef _REFCLSID_DEFINED +#define _REFCLSID_DEFINED +#ifdef __cplusplus +#define REFCLSID const IID & +#else +#define REFCLSID const IID *__MIDL_CONST +#endif +#endif + +#ifndef _REFFMTID_DEFINED +#define _REFFMTID_DEFINED +#ifdef __cplusplus +#define REFFMTID const IID & +#else +#define REFFMTID const IID *__MIDL_CONST +#endif +#endif +#endif + +#ifndef _SYS_GUID_OPERATORS_ +#define _SYS_GUID_OPERATORS_ +#include + +#ifdef __cplusplus +__inline int InlineIsEqualGUID(REFGUID rguid1,REFGUID rguid2) { + return (((unsigned long *) &rguid1)[0]==((unsigned long *) &rguid2)[0] && ((unsigned long *) &rguid1)[1]==((unsigned long *) &rguid2)[1] && + ((unsigned long *) &rguid1)[2]==((unsigned long *) &rguid2)[2] && ((unsigned long *) &rguid1)[3]==((unsigned long *) &rguid2)[3]); +} +__inline int IsEqualGUID(REFGUID rguid1,REFGUID rguid2) { return !memcmp(&rguid1,&rguid2,sizeof(GUID)); } +#else +#define InlineIsEqualGUID(rguid1,rguid2) (((unsigned long *) rguid1)[0]==((unsigned long *) rguid2)[0] && ((unsigned long *) rguid1)[1]==((unsigned long *) rguid2)[1] && ((unsigned long *) rguid1)[2]==((unsigned long *) rguid2)[2] && ((unsigned long *) rguid1)[3]==((unsigned long *) rguid2)[3]) +#define IsEqualGUID(rguid1,rguid2) (!memcmp(rguid1,rguid2,sizeof(GUID))) +#endif + +#ifdef __INLINE_ISEQUAL_GUID +#undef IsEqualGUID +#define IsEqualGUID(rguid1,rguid2) InlineIsEqualGUID(rguid1,rguid2) +#endif + +#define IsEqualIID(riid1,riid2) IsEqualGUID(riid1,riid2) +#define IsEqualCLSID(rclsid1,rclsid2) IsEqualGUID(rclsid1,rclsid2) + +#if !defined _SYS_GUID_OPERATOR_EQ_ && !defined _NO_SYS_GUID_OPERATOR_EQ_ +#define _SYS_GUID_OPERATOR_EQ_ +#ifdef __cplusplus +__inline int operator==(REFGUID guidOne,REFGUID guidOther) { return IsEqualGUID(guidOne,guidOther); } +__inline int operator!=(REFGUID guidOne,REFGUID guidOther) { return !(guidOne==guidOther); } +#endif +#endif +#endif +#endif diff --git a/tcc/include/winapi/poppack.h b/tcc/include/winapi/poppack.h index 5a9094d3..b08cba22 100644 --- a/tcc/include/winapi/poppack.h +++ b/tcc/include/winapi/poppack.h @@ -1,8 +1,8 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(pop) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(pop) +#endif diff --git a/tcc/include/winapi/pshpack1.h b/tcc/include/winapi/pshpack1.h index 18cbd8e6..d18d9e85 100644 --- a/tcc/include/winapi/pshpack1.h +++ b/tcc/include/winapi/pshpack1.h @@ -1,8 +1,8 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,1) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,1) +#endif diff --git a/tcc/include/winapi/pshpack2.h b/tcc/include/winapi/pshpack2.h index 6afc106e..7de16fd3 100644 --- a/tcc/include/winapi/pshpack2.h +++ b/tcc/include/winapi/pshpack2.h @@ -1,8 +1,8 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,2) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,2) +#endif diff --git a/tcc/include/winapi/pshpack4.h b/tcc/include/winapi/pshpack4.h index 1e10441f..1c8e61d7 100644 --- a/tcc/include/winapi/pshpack4.h +++ b/tcc/include/winapi/pshpack4.h @@ -1,8 +1,8 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,4) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,4) +#endif diff --git a/tcc/include/winapi/pshpack8.h b/tcc/include/winapi/pshpack8.h index 0f4e2de1..70a3c7f7 100644 --- a/tcc/include/winapi/pshpack8.h +++ b/tcc/include/winapi/pshpack8.h @@ -1,8 +1,8 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#if !(defined(lint) || defined(RC_INVOKED)) -#pragma pack(push,8) -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#if !(defined(lint) || defined(RC_INVOKED)) +#pragma pack(push,8) +#endif diff --git a/tcc/include/winapi/qos.h b/tcc/include/winapi/qos.h index 23f89fae..7fa6ad19 100644 --- a/tcc/include/winapi/qos.h +++ b/tcc/include/winapi/qos.h @@ -1,72 +1,72 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef __QOS_H_ -#define __QOS_H_ - -typedef ULONG SERVICETYPE; - -#define SERVICETYPE_NOTRAFFIC 0x00000000 -#define SERVICETYPE_BESTEFFORT 0x00000001 -#define SERVICETYPE_CONTROLLEDLOAD 0x00000002 -#define SERVICETYPE_GUARANTEED 0x00000003 - -#define SERVICETYPE_NETWORK_UNAVAILABLE 0x00000004 -#define SERVICETYPE_GENERAL_INFORMATION 0x00000005 -#define SERVICETYPE_NOCHANGE 0x00000006 -#define SERVICETYPE_NONCONFORMING 0x00000009 -#define SERVICETYPE_NETWORK_CONTROL 0x0000000A -#define SERVICETYPE_QUALITATIVE 0x0000000D - -#define SERVICE_BESTEFFORT 0x80010000 -#define SERVICE_CONTROLLEDLOAD 0x80020000 -#define SERVICE_GUARANTEED 0x80040000 -#define SERVICE_QUALITATIVE 0x80200000 - -#define SERVICE_NO_TRAFFIC_CONTROL 0x81000000 - -#define SERVICE_NO_QOS_SIGNALING 0x40000000 - -typedef struct _flowspec { - ULONG TokenRate; - ULONG TokenBucketSize; - ULONG PeakBandwidth; - ULONG Latency; - ULONG DelayVariation; - SERVICETYPE ServiceType; - ULONG MaxSduSize; - ULONG MinimumPolicedSize; -} FLOWSPEC,*PFLOWSPEC,*LPFLOWSPEC; - -#define QOS_NOT_SPECIFIED 0xFFFFFFFF -#define POSITIVE_INFINITY_RATE 0xFFFFFFFE - -typedef struct { - ULONG ObjectType; - ULONG ObjectLength; -} QOS_OBJECT_HDR,*LPQOS_OBJECT_HDR; - -#define QOS_GENERAL_ID_BASE 2000 -#define QOS_OBJECT_END_OF_LIST (0x00000001 + QOS_GENERAL_ID_BASE) -#define QOS_OBJECT_SD_MODE (0x00000002 + QOS_GENERAL_ID_BASE) -#define QOS_OBJECT_SHAPING_RATE (0x00000003 + QOS_GENERAL_ID_BASE) -#define QOS_OBJECT_DESTADDR (0x00000004 + QOS_GENERAL_ID_BASE) - -typedef struct _QOS_SD_MODE { - QOS_OBJECT_HDR ObjectHdr; - ULONG ShapeDiscardMode; -} QOS_SD_MODE,*LPQOS_SD_MODE; - -#define TC_NONCONF_BORROW 0 -#define TC_NONCONF_SHAPE 1 -#define TC_NONCONF_DISCARD 2 -#define TC_NONCONF_BORROW_PLUS 3 - -typedef struct _QOS_SHAPING_RATE { - QOS_OBJECT_HDR ObjectHdr; - ULONG ShapingRate; -} QOS_SHAPING_RATE,*LPQOS_SHAPING_RATE; - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef __QOS_H_ +#define __QOS_H_ + +typedef ULONG SERVICETYPE; + +#define SERVICETYPE_NOTRAFFIC 0x00000000 +#define SERVICETYPE_BESTEFFORT 0x00000001 +#define SERVICETYPE_CONTROLLEDLOAD 0x00000002 +#define SERVICETYPE_GUARANTEED 0x00000003 + +#define SERVICETYPE_NETWORK_UNAVAILABLE 0x00000004 +#define SERVICETYPE_GENERAL_INFORMATION 0x00000005 +#define SERVICETYPE_NOCHANGE 0x00000006 +#define SERVICETYPE_NONCONFORMING 0x00000009 +#define SERVICETYPE_NETWORK_CONTROL 0x0000000A +#define SERVICETYPE_QUALITATIVE 0x0000000D + +#define SERVICE_BESTEFFORT 0x80010000 +#define SERVICE_CONTROLLEDLOAD 0x80020000 +#define SERVICE_GUARANTEED 0x80040000 +#define SERVICE_QUALITATIVE 0x80200000 + +#define SERVICE_NO_TRAFFIC_CONTROL 0x81000000 + +#define SERVICE_NO_QOS_SIGNALING 0x40000000 + +typedef struct _flowspec { + ULONG TokenRate; + ULONG TokenBucketSize; + ULONG PeakBandwidth; + ULONG Latency; + ULONG DelayVariation; + SERVICETYPE ServiceType; + ULONG MaxSduSize; + ULONG MinimumPolicedSize; +} FLOWSPEC,*PFLOWSPEC,*LPFLOWSPEC; + +#define QOS_NOT_SPECIFIED 0xFFFFFFFF +#define POSITIVE_INFINITY_RATE 0xFFFFFFFE + +typedef struct { + ULONG ObjectType; + ULONG ObjectLength; +} QOS_OBJECT_HDR,*LPQOS_OBJECT_HDR; + +#define QOS_GENERAL_ID_BASE 2000 +#define QOS_OBJECT_END_OF_LIST (0x00000001 + QOS_GENERAL_ID_BASE) +#define QOS_OBJECT_SD_MODE (0x00000002 + QOS_GENERAL_ID_BASE) +#define QOS_OBJECT_SHAPING_RATE (0x00000003 + QOS_GENERAL_ID_BASE) +#define QOS_OBJECT_DESTADDR (0x00000004 + QOS_GENERAL_ID_BASE) + +typedef struct _QOS_SD_MODE { + QOS_OBJECT_HDR ObjectHdr; + ULONG ShapeDiscardMode; +} QOS_SD_MODE,*LPQOS_SD_MODE; + +#define TC_NONCONF_BORROW 0 +#define TC_NONCONF_SHAPE 1 +#define TC_NONCONF_DISCARD 2 +#define TC_NONCONF_BORROW_PLUS 3 + +typedef struct _QOS_SHAPING_RATE { + QOS_OBJECT_HDR ObjectHdr; + ULONG ShapingRate; +} QOS_SHAPING_RATE,*LPQOS_SHAPING_RATE; + +#endif diff --git a/tcc/include/winapi/winbase.h b/tcc/include/winapi/winbase.h index 8752e1d1..4a38006e 100644 --- a/tcc/include/winapi/winbase.h +++ b/tcc/include/winapi/winbase.h @@ -1,2951 +1,2951 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINBASE_ -#define _WINBASE_ - -#define WINADVAPI DECLSPEC_IMPORT -#define WINBASEAPI DECLSPEC_IMPORT -#define ZAWPROXYAPI DECLSPEC_IMPORT - -#ifdef __cplusplus -extern "C" { -#endif - -#define DefineHandleTable(w) ((w),TRUE) -#define LimitEmsPages(dw) -#define SetSwapAreaSize(w) (w) -#define LockSegment(w) GlobalFix((HANDLE)(w)) -#define UnlockSegment(w) GlobalUnfix((HANDLE)(w)) -#define GetCurrentTime() GetTickCount() - -#define Yield() - -#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) -#define INVALID_FILE_SIZE ((DWORD)0xffffffff) -#define INVALID_SET_FILE_POINTER ((DWORD)-1) -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) - -#define FILE_BEGIN 0 -#define FILE_CURRENT 1 -#define FILE_END 2 - -#define TIME_ZONE_ID_INVALID ((DWORD)0xffffffff) - -#define WAIT_FAILED ((DWORD)0xffffffff) -#define WAIT_OBJECT_0 ((STATUS_WAIT_0) + 0) -#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0) + 0) -#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0) + 0) -#define WAIT_IO_COMPLETION STATUS_USER_APC -#define STILL_ACTIVE STATUS_PENDING -#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION -#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT -#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT -#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP -#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED -#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND -#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO -#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT -#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION -#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW -#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK -#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW -#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO -#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW -#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION -#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR -#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION -#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION -#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW -#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION -#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION -#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE -#define EXCEPTION_POSSIBLE_DEADLOCK STATUS_POSSIBLE_DEADLOCK -#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT -#define MoveMemory RtlMoveMemory -#define CopyMemory RtlCopyMemory -#define FillMemory RtlFillMemory -#define ZeroMemory RtlZeroMemory -#define SecureZeroMemory RtlSecureZeroMemory - -#define FILE_FLAG_WRITE_THROUGH 0x80000000 -#define FILE_FLAG_OVERLAPPED 0x40000000 -#define FILE_FLAG_NO_BUFFERING 0x20000000 -#define FILE_FLAG_RANDOM_ACCESS 0x10000000 -#define FILE_FLAG_SEQUENTIAL_SCAN 0x8000000 -#define FILE_FLAG_DELETE_ON_CLOSE 0x4000000 -#define FILE_FLAG_BACKUP_SEMANTICS 0x2000000 -#define FILE_FLAG_POSIX_SEMANTICS 0x1000000 -#define FILE_FLAG_OPEN_REPARSE_POINT 0x200000 -#define FILE_FLAG_OPEN_NO_RECALL 0x100000 -#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x80000 - -#define CREATE_NEW 1 -#define CREATE_ALWAYS 2 -#define OPEN_EXISTING 3 -#define OPEN_ALWAYS 4 -#define TRUNCATE_EXISTING 5 - -#define PROGRESS_CONTINUE 0 -#define PROGRESS_CANCEL 1 -#define PROGRESS_STOP 2 -#define PROGRESS_QUIET 3 - -#define CALLBACK_CHUNK_FINISHED 0x0 -#define CALLBACK_STREAM_SWITCH 0x1 - -#define COPY_FILE_FAIL_IF_EXISTS 0x1 -#define COPY_FILE_RESTARTABLE 0x2 -#define COPY_FILE_OPEN_SOURCE_FOR_WRITE 0x4 -#define COPY_FILE_ALLOW_DECRYPTED_DESTINATION 0x8 - -#define REPLACEFILE_WRITE_THROUGH 0x1 -#define REPLACEFILE_IGNORE_MERGE_ERRORS 0x2 - -#define PIPE_ACCESS_INBOUND 0x1 -#define PIPE_ACCESS_OUTBOUND 0x2 -#define PIPE_ACCESS_DUPLEX 0x3 - -#define PIPE_CLIENT_END 0x0 -#define PIPE_SERVER_END 0x1 - -#define PIPE_WAIT 0x0 -#define PIPE_NOWAIT 0x1 -#define PIPE_READMODE_BYTE 0x0 -#define PIPE_READMODE_MESSAGE 0x2 -#define PIPE_TYPE_BYTE 0x0 -#define PIPE_TYPE_MESSAGE 0x4 - -#define PIPE_UNLIMITED_INSTANCES 255 - -#define SECURITY_ANONYMOUS (SecurityAnonymous << 16) -#define SECURITY_IDENTIFICATION (SecurityIdentification << 16) -#define SECURITY_IMPERSONATION (SecurityImpersonation << 16) -#define SECURITY_DELEGATION (SecurityDelegation << 16) - -#define SECURITY_CONTEXT_TRACKING 0x40000 -#define SECURITY_EFFECTIVE_ONLY 0x80000 - -#define SECURITY_SQOS_PRESENT 0x100000 -#define SECURITY_VALID_SQOS_FLAGS 0x1f0000 - - typedef struct _OVERLAPPED { - ULONG_PTR Internal; - ULONG_PTR InternalHigh; - union { - struct { - DWORD Offset; - DWORD OffsetHigh; - }; - PVOID Pointer; - }; - HANDLE hEvent; - } OVERLAPPED,*LPOVERLAPPED; - - typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - LPVOID lpSecurityDescriptor; - WINBOOL bInheritHandle; - } SECURITY_ATTRIBUTES,*PSECURITY_ATTRIBUTES,*LPSECURITY_ATTRIBUTES; - - typedef struct _PROCESS_INFORMATION { - HANDLE hProcess; - HANDLE hThread; - DWORD dwProcessId; - DWORD dwThreadId; - } PROCESS_INFORMATION,*PPROCESS_INFORMATION,*LPPROCESS_INFORMATION; - -#ifndef _FILETIME_ -#define _FILETIME_ - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME,*PFILETIME,*LPFILETIME; -#endif - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME,*PSYSTEMTIME,*LPSYSTEMTIME; - - typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); - typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - typedef VOID (WINAPI *PFIBER_START_ROUTINE)(LPVOID lpFiberParameter); - typedef PFIBER_START_ROUTINE LPFIBER_START_ROUTINE; - - typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; - typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION; - typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION; - typedef RTL_CRITICAL_SECTION_DEBUG CRITICAL_SECTION_DEBUG; - typedef PRTL_CRITICAL_SECTION_DEBUG PCRITICAL_SECTION_DEBUG; - typedef PRTL_CRITICAL_SECTION_DEBUG LPCRITICAL_SECTION_DEBUG; - - WINBASEAPI PVOID WINAPI EncodePointer(PVOID Ptr); - WINBASEAPI PVOID WINAPI DecodePointer(PVOID Ptr); - WINBASEAPI PVOID WINAPI EncodeSystemPointer(PVOID Ptr); - WINBASEAPI PVOID WINAPI DecodeSystemPointer(PVOID Ptr); - -#ifdef I_X86_ - typedef PLDT_ENTRY LPLDT_ENTRY; -#else - typedef LPVOID LPLDT_ENTRY; -#endif - -#define MUTEX_MODIFY_STATE MUTANT_QUERY_STATE -#define MUTEX_ALL_ACCESS MUTANT_ALL_ACCESS - -#define SP_SERIALCOMM ((DWORD)0x1) - -#define PST_UNSPECIFIED ((DWORD)0x0) -#define PST_RS232 ((DWORD)0x1) -#define PST_PARALLELPORT ((DWORD)0x2) -#define PST_RS422 ((DWORD)0x3) -#define PST_RS423 ((DWORD)0x4) -#define PST_RS449 ((DWORD)0x5) -#define PST_MODEM ((DWORD)0x6) -#define PST_FAX ((DWORD)0x21) -#define PST_SCANNER ((DWORD)0x22) -#define PST_NETWORK_BRIDGE ((DWORD)0x100) -#define PST_LAT ((DWORD)0x101) -#define PST_TCPIP_TELNET ((DWORD)0x102) -#define PST_X25 ((DWORD)0x103) - -#define PCF_DTRDSR ((DWORD)0x1) -#define PCF_RTSCTS ((DWORD)0x2) -#define PCF_RLSD ((DWORD)0x4) -#define PCF_PARITY_CHECK ((DWORD)0x8) -#define PCF_XONXOFF ((DWORD)0x10) -#define PCF_SETXCHAR ((DWORD)0x20) -#define PCF_TOTALTIMEOUTS ((DWORD)0x40) -#define PCF_INTTIMEOUTS ((DWORD)0x80) -#define PCF_SPECIALCHARS ((DWORD)0x100) -#define PCF_16BITMODE ((DWORD)0x200) - -#define SP_PARITY ((DWORD)0x1) -#define SP_BAUD ((DWORD)0x2) -#define SP_DATABITS ((DWORD)0x4) -#define SP_STOPBITS ((DWORD)0x8) -#define SP_HANDSHAKING ((DWORD)0x10) -#define SP_PARITY_CHECK ((DWORD)0x20) -#define SP_RLSD ((DWORD)0x40) - -#define BAUD_075 ((DWORD)0x1) -#define BAUD_110 ((DWORD)0x2) -#define BAUD_134_5 ((DWORD)0x4) -#define BAUD_150 ((DWORD)0x8) -#define BAUD_300 ((DWORD)0x10) -#define BAUD_600 ((DWORD)0x20) -#define BAUD_1200 ((DWORD)0x40) -#define BAUD_1800 ((DWORD)0x80) -#define BAUD_2400 ((DWORD)0x100) -#define BAUD_4800 ((DWORD)0x200) -#define BAUD_7200 ((DWORD)0x400) -#define BAUD_9600 ((DWORD)0x800) -#define BAUD_14400 ((DWORD)0x1000) -#define BAUD_19200 ((DWORD)0x2000) -#define BAUD_38400 ((DWORD)0x4000) -#define BAUD_56K ((DWORD)0x8000) -#define BAUD_128K ((DWORD)0x10000) -#define BAUD_115200 ((DWORD)0x20000) -#define BAUD_57600 ((DWORD)0x40000) -#define BAUD_USER ((DWORD)0x10000000) - -#define DATABITS_5 ((WORD)0x1) -#define DATABITS_6 ((WORD)0x2) -#define DATABITS_7 ((WORD)0x4) -#define DATABITS_8 ((WORD)0x8) -#define DATABITS_16 ((WORD)0x10) -#define DATABITS_16X ((WORD)0x20) - -#define STOPBITS_10 ((WORD)0x1) -#define STOPBITS_15 ((WORD)0x2) -#define STOPBITS_20 ((WORD)0x4) -#define PARITY_NONE ((WORD)0x100) -#define PARITY_ODD ((WORD)0x200) -#define PARITY_EVEN ((WORD)0x400) -#define PARITY_MARK ((WORD)0x800) -#define PARITY_SPACE ((WORD)0x1000) - - typedef struct _COMMPROP { - WORD wPacketLength; - WORD wPacketVersion; - DWORD dwServiceMask; - DWORD dwReserved1; - DWORD dwMaxTxQueue; - DWORD dwMaxRxQueue; - DWORD dwMaxBaud; - DWORD dwProvSubType; - DWORD dwProvCapabilities; - DWORD dwSettableParams; - DWORD dwSettableBaud; - WORD wSettableData; - WORD wSettableStopParity; - DWORD dwCurrentTxQueue; - DWORD dwCurrentRxQueue; - DWORD dwProvSpec1; - DWORD dwProvSpec2; - WCHAR wcProvChar[1]; - } COMMPROP,*LPCOMMPROP; - -#define COMMPROP_INITIALIZED ((DWORD)0xE73CF52E) - - typedef struct _COMSTAT { - DWORD fCtsHold : 1; - DWORD fDsrHold : 1; - DWORD fRlsdHold : 1; - DWORD fXoffHold : 1; - DWORD fXoffSent : 1; - DWORD fEof : 1; - DWORD fTxim : 1; - DWORD fReserved : 25; - DWORD cbInQue; - DWORD cbOutQue; - } COMSTAT,*LPCOMSTAT; - -#define DTR_CONTROL_DISABLE 0x0 -#define DTR_CONTROL_ENABLE 0x1 -#define DTR_CONTROL_HANDSHAKE 0x2 - -#define RTS_CONTROL_DISABLE 0x0 -#define RTS_CONTROL_ENABLE 0x1 -#define RTS_CONTROL_HANDSHAKE 0x2 -#define RTS_CONTROL_TOGGLE 0x3 - - typedef struct _DCB { - DWORD DCBlength; - DWORD BaudRate; - DWORD fBinary: 1; - DWORD fParity: 1; - DWORD fOutxCtsFlow:1; - DWORD fOutxDsrFlow:1; - DWORD fDtrControl:2; - DWORD fDsrSensitivity:1; - DWORD fTXContinueOnXoff: 1; - DWORD fOutX: 1; - DWORD fInX: 1; - DWORD fErrorChar: 1; - DWORD fNull: 1; - DWORD fRtsControl:2; - DWORD fAbortOnError:1; - DWORD fDummy2:17; - WORD wReserved; - WORD XonLim; - WORD XoffLim; - BYTE ByteSize; - BYTE Parity; - BYTE StopBits; - char XonChar; - char XoffChar; - char ErrorChar; - char EofChar; - char EvtChar; - WORD wReserved1; - } DCB,*LPDCB; - - typedef struct _COMMTIMEOUTS { - DWORD ReadIntervalTimeout; - DWORD ReadTotalTimeoutMultiplier; - DWORD ReadTotalTimeoutConstant; - DWORD WriteTotalTimeoutMultiplier; - DWORD WriteTotalTimeoutConstant; - } COMMTIMEOUTS,*LPCOMMTIMEOUTS; - - typedef struct _COMMCONFIG { - DWORD dwSize; - WORD wVersion; - WORD wReserved; - DCB dcb; - DWORD dwProviderSubType; - DWORD dwProviderOffset; - DWORD dwProviderSize; - WCHAR wcProviderData[1]; - } COMMCONFIG,*LPCOMMCONFIG; - - typedef struct _SYSTEM_INFO { - union { - DWORD dwOemId; - struct { - WORD wProcessorArchitecture; - WORD wReserved; - }; - }; - DWORD dwPageSize; - LPVOID lpMinimumApplicationAddress; - LPVOID lpMaximumApplicationAddress; - DWORD_PTR dwActiveProcessorMask; - DWORD dwNumberOfProcessors; - DWORD dwProcessorType; - DWORD dwAllocationGranularity; - WORD wProcessorLevel; - WORD wProcessorRevision; - } SYSTEM_INFO,*LPSYSTEM_INFO; - -#define FreeModule(hLibModule) FreeLibrary((hLibModule)) -#define MakeProcInstance(lpProc,hInstance) (lpProc) -#define FreeProcInstance(lpProc) (lpProc) - -#define GMEM_FIXED 0x0 -#define GMEM_MOVEABLE 0x2 -#define GMEM_NOCOMPACT 0x10 -#define GMEM_NODISCARD 0x20 -#define GMEM_ZEROINIT 0x40 -#define GMEM_MODIFY 0x80 -#define GMEM_DISCARDABLE 0x100 -#define GMEM_NOT_BANKED 0x1000 -#define GMEM_SHARE 0x2000 -#define GMEM_DDESHARE 0x2000 -#define GMEM_NOTIFY 0x4000 -#define GMEM_LOWER GMEM_NOT_BANKED -#define GMEM_VALID_FLAGS 0x7F72 -#define GMEM_INVALID_HANDLE 0x8000 - -#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT) -#define GPTR (GMEM_FIXED | GMEM_ZEROINIT) - -#define GlobalLRUNewest(h) ((HANDLE)(h)) -#define GlobalLRUOldest(h) ((HANDLE)(h)) -#define GlobalDiscard(h) GlobalReAlloc((h),0,GMEM_MOVEABLE) - -#define GMEM_DISCARDED 0x4000 -#define GMEM_LOCKCOUNT 0xff - - typedef struct _MEMORYSTATUS { - DWORD dwLength; - DWORD dwMemoryLoad; - SIZE_T dwTotalPhys; - SIZE_T dwAvailPhys; - SIZE_T dwTotalPageFile; - SIZE_T dwAvailPageFile; - SIZE_T dwTotalVirtual; - SIZE_T dwAvailVirtual; - } MEMORYSTATUS,*LPMEMORYSTATUS; - -#define LMEM_FIXED 0x0 -#define LMEM_MOVEABLE 0x2 -#define LMEM_NOCOMPACT 0x10 -#define LMEM_NODISCARD 0x20 -#define LMEM_ZEROINIT 0x40 -#define LMEM_MODIFY 0x80 -#define LMEM_DISCARDABLE 0xf00 -#define LMEM_VALID_FLAGS 0xf72 -#define LMEM_INVALID_HANDLE 0x8000 - -#define LHND (LMEM_MOVEABLE | LMEM_ZEROINIT) -#define LPTR (LMEM_FIXED | LMEM_ZEROINIT) - -#define NONZEROLHND (LMEM_MOVEABLE) -#define NONZEROLPTR (LMEM_FIXED) - -#define LocalDiscard(h) LocalReAlloc((h),0,LMEM_MOVEABLE) - -#define LMEM_DISCARDED 0x4000 -#define LMEM_LOCKCOUNT 0xff - -#define DEBUG_PROCESS 0x1 -#define DEBUG_ONLY_THIS_PROCESS 0x2 -#define CREATE_SUSPENDED 0x4 -#define DETACHED_PROCESS 0x8 -#define CREATE_NEW_CONSOLE 0x10 -#define NORMAL_PRIORITY_CLASS 0x20 -#define IDLE_PRIORITY_CLASS 0x40 -#define HIGH_PRIORITY_CLASS 0x80 -#define REALTIME_PRIORITY_CLASS 0x100 -#define CREATE_NEW_PROCESS_GROUP 0x200 -#define CREATE_UNICODE_ENVIRONMENT 0x400 -#define CREATE_SEPARATE_WOW_VDM 0x800 -#define CREATE_SHARED_WOW_VDM 0x1000 -#define CREATE_FORCEDOS 0x2000 -#define BELOW_NORMAL_PRIORITY_CLASS 0x4000 -#define ABOVE_NORMAL_PRIORITY_CLASS 0x8000 -#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x10000 - -#define CREATE_BREAKAWAY_FROM_JOB 0x1000000 -#define CREATE_PRESERVE_CODE_AUTHZ_LEVEL 0x2000000 - -#define CREATE_DEFAULT_ERROR_MODE 0x4000000 -#define CREATE_NO_WINDOW 0x8000000 - -#define PROFILE_USER 0x10000000 -#define PROFILE_KERNEL 0x20000000 -#define PROFILE_SERVER 0x40000000 - -#define CREATE_IGNORE_SYSTEM_DEFAULT 0x80000000 - -#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN -#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1) -#define THREAD_PRIORITY_NORMAL 0 -#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX -#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1) -#define THREAD_PRIORITY_ERROR_RETURN (MAXLONG) - -#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT -#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE - -#define EXCEPTION_DEBUG_EVENT 1 -#define CREATE_THREAD_DEBUG_EVENT 2 -#define CREATE_PROCESS_DEBUG_EVENT 3 -#define EXIT_THREAD_DEBUG_EVENT 4 -#define EXIT_PROCESS_DEBUG_EVENT 5 -#define LOAD_DLL_DEBUG_EVENT 6 -#define UNLOAD_DLL_DEBUG_EVENT 7 -#define OUTPUT_DEBUG_STRING_EVENT 8 -#define RIP_EVENT 9 - - typedef struct _EXCEPTION_DEBUG_INFO { - EXCEPTION_RECORD ExceptionRecord; - DWORD dwFirstChance; - } EXCEPTION_DEBUG_INFO,*LPEXCEPTION_DEBUG_INFO; - - typedef struct _CREATE_THREAD_DEBUG_INFO { - HANDLE hThread; - LPVOID lpThreadLocalBase; - LPTHREAD_START_ROUTINE lpStartAddress; - } CREATE_THREAD_DEBUG_INFO,*LPCREATE_THREAD_DEBUG_INFO; - - typedef struct _CREATE_PROCESS_DEBUG_INFO { - HANDLE hFile; - HANDLE hProcess; - HANDLE hThread; - LPVOID lpBaseOfImage; - DWORD dwDebugInfoFileOffset; - DWORD nDebugInfoSize; - LPVOID lpThreadLocalBase; - LPTHREAD_START_ROUTINE lpStartAddress; - LPVOID lpImageName; - WORD fUnicode; - } CREATE_PROCESS_DEBUG_INFO,*LPCREATE_PROCESS_DEBUG_INFO; - - typedef struct _EXIT_THREAD_DEBUG_INFO { - DWORD dwExitCode; - } EXIT_THREAD_DEBUG_INFO,*LPEXIT_THREAD_DEBUG_INFO; - - typedef struct _EXIT_PROCESS_DEBUG_INFO { - DWORD dwExitCode; - } EXIT_PROCESS_DEBUG_INFO,*LPEXIT_PROCESS_DEBUG_INFO; - - typedef struct _LOAD_DLL_DEBUG_INFO { - HANDLE hFile; - LPVOID lpBaseOfDll; - DWORD dwDebugInfoFileOffset; - DWORD nDebugInfoSize; - LPVOID lpImageName; - WORD fUnicode; - } LOAD_DLL_DEBUG_INFO,*LPLOAD_DLL_DEBUG_INFO; - - typedef struct _UNLOAD_DLL_DEBUG_INFO { - LPVOID lpBaseOfDll; - } UNLOAD_DLL_DEBUG_INFO,*LPUNLOAD_DLL_DEBUG_INFO; - - typedef struct _OUTPUT_DEBUG_STRING_INFO { - LPSTR lpDebugStringData; - WORD fUnicode; - WORD nDebugStringLength; - } OUTPUT_DEBUG_STRING_INFO,*LPOUTPUT_DEBUG_STRING_INFO; - - typedef struct _RIP_INFO { - DWORD dwError; - DWORD dwType; - } RIP_INFO,*LPRIP_INFO; - - typedef struct _DEBUG_EVENT { - DWORD dwDebugEventCode; - DWORD dwProcessId; - DWORD dwThreadId; - union { - EXCEPTION_DEBUG_INFO Exception; - CREATE_THREAD_DEBUG_INFO CreateThread; - CREATE_PROCESS_DEBUG_INFO CreateProcessInfo; - EXIT_THREAD_DEBUG_INFO ExitThread; - EXIT_PROCESS_DEBUG_INFO ExitProcess; - LOAD_DLL_DEBUG_INFO LoadDll; - UNLOAD_DLL_DEBUG_INFO UnloadDll; - OUTPUT_DEBUG_STRING_INFO DebugString; - RIP_INFO RipInfo; - } u; - } DEBUG_EVENT,*LPDEBUG_EVENT; - - typedef PCONTEXT LPCONTEXT; - typedef PEXCEPTION_RECORD LPEXCEPTION_RECORD; - typedef PEXCEPTION_POINTERS LPEXCEPTION_POINTERS; - -#define DRIVE_UNKNOWN 0 -#define DRIVE_NO_ROOT_DIR 1 -#define DRIVE_REMOVABLE 2 -#define DRIVE_FIXED 3 -#define DRIVE_REMOTE 4 -#define DRIVE_CDROM 5 -#define DRIVE_RAMDISK 6 - -#define GetFreeSpace(w) (0x100000L) -#define FILE_TYPE_UNKNOWN 0x0 -#define FILE_TYPE_DISK 0x1 -#define FILE_TYPE_CHAR 0x2 -#define FILE_TYPE_PIPE 0x3 -#define FILE_TYPE_REMOTE 0x8000 - -#define STD_INPUT_HANDLE ((DWORD)-10) -#define STD_OUTPUT_HANDLE ((DWORD)-11) -#define STD_ERROR_HANDLE ((DWORD)-12) - -#define NOPARITY 0 -#define ODDPARITY 1 -#define EVENPARITY 2 -#define MARKPARITY 3 -#define SPACEPARITY 4 - -#define ONESTOPBIT 0 -#define ONE5STOPBITS 1 -#define TWOSTOPBITS 2 - -#define IGNORE 0 -#define INFINITE 0xffffffff - -#define CBR_110 110 -#define CBR_300 300 -#define CBR_600 600 -#define CBR_1200 1200 -#define CBR_2400 2400 -#define CBR_4800 4800 -#define CBR_9600 9600 -#define CBR_14400 14400 -#define CBR_19200 19200 -#define CBR_38400 38400 -#define CBR_56000 56000 -#define CBR_57600 57600 -#define CBR_115200 115200 -#define CBR_128000 128000 -#define CBR_256000 256000 - -#define CE_RXOVER 0x1 -#define CE_OVERRUN 0x2 -#define CE_RXPARITY 0x4 -#define CE_FRAME 0x8 -#define CE_BREAK 0x10 -#define CE_TXFULL 0x100 -#define CE_PTO 0x200 -#define CE_IOE 0x400 -#define CE_DNS 0x800 -#define CE_OOP 0x1000 -#define CE_MODE 0x8000 - -#define IE_BADID (-1) -#define IE_OPEN (-2) -#define IE_NOPEN (-3) -#define IE_MEMORY (-4) -#define IE_DEFAULT (-5) -#define IE_HARDWARE (-10) -#define IE_BYTESIZE (-11) -#define IE_BAUDRATE (-12) - -#define EV_RXCHAR 0x1 -#define EV_RXFLAG 0x2 -#define EV_TXEMPTY 0x4 -#define EV_CTS 0x8 -#define EV_DSR 0x10 -#define EV_RLSD 0x20 -#define EV_BREAK 0x40 -#define EV_ERR 0x80 -#define EV_RING 0x100 -#define EV_PERR 0x200 -#define EV_RX80FULL 0x400 -#define EV_EVENT1 0x800 -#define EV_EVENT2 0x1000 - -#define SETXOFF 1 -#define SETXON 2 -#define SETRTS 3 -#define CLRRTS 4 -#define SETDTR 5 -#define CLRDTR 6 -#define RESETDEV 7 -#define SETBREAK 8 -#define CLRBREAK 9 - -#define PURGE_TXABORT 0x1 -#define PURGE_RXABORT 0x2 -#define PURGE_TXCLEAR 0x4 -#define PURGE_RXCLEAR 0x8 - -#define LPTx 0x80 - -#define MS_CTS_ON ((DWORD)0x10) -#define MS_DSR_ON ((DWORD)0x20) -#define MS_RING_ON ((DWORD)0x40) -#define MS_RLSD_ON ((DWORD)0x80) - -#define S_QUEUEEMPTY 0 -#define S_THRESHOLD 1 -#define S_ALLTHRESHOLD 2 - -#define S_NORMAL 0 -#define S_LEGATO 1 -#define S_STACCATO 2 - -#define S_PERIOD512 0 -#define S_PERIOD1024 1 -#define S_PERIOD2048 2 -#define S_PERIODVOICE 3 -#define S_WHITE512 4 -#define S_WHITE1024 5 -#define S_WHITE2048 6 -#define S_WHITEVOICE 7 - -#define S_SERDVNA (-1) -#define S_SEROFM (-2) -#define S_SERMACT (-3) -#define S_SERQFUL (-4) -#define S_SERBDNT (-5) -#define S_SERDLN (-6) -#define S_SERDCC (-7) -#define S_SERDTP (-8) -#define S_SERDVL (-9) -#define S_SERDMD (-10) -#define S_SERDSH (-11) -#define S_SERDPT (-12) -#define S_SERDFQ (-13) -#define S_SERDDR (-14) -#define S_SERDSR (-15) -#define S_SERDST (-16) - -#define NMPWAIT_WAIT_FOREVER 0xffffffff -#define NMPWAIT_NOWAIT 0x1 -#define NMPWAIT_USE_DEFAULT_WAIT 0x0 - -#define FS_CASE_IS_PRESERVED FILE_CASE_PRESERVED_NAMES -#define FS_CASE_SENSITIVE FILE_CASE_SENSITIVE_SEARCH -#define FS_UNICODE_STORED_ON_DISK FILE_UNICODE_ON_DISK -#define FS_PERSISTENT_ACLS FILE_PERSISTENT_ACLS -#define FS_VOL_IS_COMPRESSED FILE_VOLUME_IS_COMPRESSED -#define FS_FILE_COMPRESSION FILE_FILE_COMPRESSION -#define FS_FILE_ENCRYPTION FILE_SUPPORTS_ENCRYPTION - -#define FILE_MAP_COPY SECTION_QUERY -#define FILE_MAP_WRITE SECTION_MAP_WRITE -#define FILE_MAP_READ SECTION_MAP_READ -#define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS -#define FILE_MAP_EXECUTE SECTION_MAP_EXECUTE_EXPLICIT - -#define OF_READ 0x0 -#define OF_WRITE 0x1 -#define OF_READWRITE 0x2 -#define OF_SHARE_COMPAT 0x0 -#define OF_SHARE_EXCLUSIVE 0x10 -#define OF_SHARE_DENY_WRITE 0x20 -#define OF_SHARE_DENY_READ 0x30 -#define OF_SHARE_DENY_NONE 0x40 -#define OF_PARSE 0x100 -#define OF_DELETE 0x200 -#define OF_VERIFY 0x400 -#define OF_CANCEL 0x800 -#define OF_CREATE 0x1000 -#define OF_PROMPT 0x2000 -#define OF_EXIST 0x4000 -#define OF_REOPEN 0x8000 - -#define OFS_MAXPATHNAME 128 - typedef struct _OFSTRUCT { - BYTE cBytes; - BYTE fFixedDisk; - WORD nErrCode; - WORD Reserved1; - WORD Reserved2; - CHAR szPathName[OFS_MAXPATHNAME]; - } OFSTRUCT,*LPOFSTRUCT,*POFSTRUCT; - -#ifndef NOWINBASEINTERLOCK - -#ifndef _NTOS_ - -#if defined(__ia64__) && !defined(RC_INVOKED) - -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedIncrementAcquire _InterlockedIncrement_acq -#define InterlockedIncrementRelease _InterlockedIncrement_rel -#define InterlockedDecrement _InterlockedDecrement -#define InterlockedDecrementAcquire _InterlockedDecrement_acq -#define InterlockedDecrementRelease _InterlockedDecrement_rel -#define InterlockedExchange _InterlockedExchange -#define InterlockedExchangeAdd _InterlockedExchangeAdd -#define InterlockedCompareExchange _InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire _InterlockedCompareExchange_acq -#define InterlockedCompareExchangeRelease _InterlockedCompareExchange_rel -#define InterlockedExchangePointer _InterlockedExchangePointer -#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer_rel -#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer_acq - -#define InterlockedIncrement64 _InterlockedIncrement64 -#define InterlockedDecrement64 _InterlockedDecrement64 -#define InterlockedExchange64 _InterlockedExchange64 -#define InterlockedExchangeAcquire64 _InterlockedExchange64_acq -#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 -#define InterlockedCompareExchange64 _InterlockedCompareExchange64 -#define InterlockedCompareExchangeAcquire64 _InterlockedCompareExchange64_acq -#define InterlockedCompareExchangeRelease64 _InterlockedCompareExchange64_rel - - LONGLONG __cdecl InterlockedIncrement64(LONGLONG volatile *Addend); - LONGLONG __cdecl InterlockedDecrement64(LONGLONG volatile *Addend); - LONG __cdecl InterlockedIncrementAcquire(LONG volatile *Addend); - LONG __cdecl InterlockedDecrementAcquire(LONG volatile *Addend); - LONG __cdecl InterlockedIncrementRelease(LONG volatile *Addend); - LONG __cdecl InterlockedDecrementRelease(LONG volatile *Addend); - LONGLONG __cdecl InterlockedExchange64 (LONGLONG volatile *Target,LONGLONG Value); - LONGLONG __cdecl InterlockedExchangeAcquire64 (LONGLONG volatile *Target,LONGLONG Value); - LONGLONG __cdecl InterlockedExchangeAdd64 (LONGLONG volatile *Addend,LONGLONG Value); - LONGLONG __cdecl InterlockedCompareExchange64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); - LONGLONG __cdecl InterlockedCompareExchangeAcquire64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); - LONGLONG __cdecl InterlockedCompareExchangeRelease64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); - LONG __cdecl InterlockedIncrement(LONG volatile *lpAddend); - LONG __cdecl InterlockedDecrement(LONG volatile *lpAddend); - LONG __cdecl InterlockedExchange(LONG volatile *Target,LONG Value); - LONG __cdecl InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - LONG __cdecl InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); - LONG __cdecl InterlockedCompareExchangeRelease(LONG volatile *Destination,LONG ExChange,LONG Comperand); - LONG __cdecl InterlockedCompareExchangeAcquire(LONG volatile *Destination,LONG ExChange,LONG Comperand); - PVOID __cdecl InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); - PVOID __cdecl InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand); - PVOID __cdecl InterlockedCompareExchangePointerAcquire(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); - PVOID __cdecl InterlockedCompareExchangePointerRelease(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); - -#ifndef InterlockedAnd -#define InterlockedAnd InterlockedAnd_Inline - __CRT_INLINE LONG InterlockedAnd_Inline(LONG volatile *Target,LONG Set) { - LONG i; - LONG j; - j = *Target; - do { - i = j; - j = InterlockedCompareExchange(Target,i & Set,i); - } while(i!=j); - return j; - } -#endif - -#ifndef InterlockedOr -#define InterlockedOr InterlockedOr_Inline - - __CRT_INLINE LONG InterlockedOr_Inline(LONG volatile *Target,LONG Set) { - LONG i; - LONG j; - j = *Target; - do { - i = j; - j = InterlockedCompareExchange(Target,i | Set,i); - } while(i!=j); - return j; - } -#endif - -#ifndef InterlockedXor -#define InterlockedXor InterlockedXor_Inline - - __CRT_INLINE LONG InterlockedXor_Inline(LONG volatile *Target,LONG Set) { - LONG i; - LONG j; - j = *Target; - do { - i = j; - j = InterlockedCompareExchange(Target,i ^ Set,i); - } while(i!=j); - return j; - } -#endif - -#ifndef !defined (InterlockedAnd64) -#define InterlockedAnd64 InterlockedAnd64_Inline - - __CRT_INLINE LONGLONG InterlockedAnd64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); - return Old; - } -#endif - -#ifndef InterlockedOr64 -#define InterlockedOr64 InterlockedOr64_Inline - - __CRT_INLINE LONGLONG InterlockedOr64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); - return Old; - } -#endif - -#ifndef InterlockedXor64 -#define InterlockedXor64 InterlockedXor64_Inline - - __CRT_INLINE LONGLONG InterlockedXor64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); - return Old; - } -#endif - -#ifndef InterlockedBitTestAndSet -#define InterlockedBitTestAndSet InterlockedBitTestAndSet_Inline - - __CRT_INLINE BOOLEAN InterlockedBitTestAndSet_Inline(LONG *Base,LONG Bit) { - LONG tBit; - tBit = 1<<(Bit & (sizeof (*Base)*8-1)); - return (BOOLEAN)((InterlockedOr(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); - } -#endif - -#ifndef InterlockedBitTestAndReset -#define InterlockedBitTestAndReset InterlockedBitTestAndReset_Inline - - __CRT_INLINE BOOLEAN InterlockedBitTestAndReset_Inline(LONG *Base,LONG Bit) { - LONG tBit; - tBit = 1<<(Bit & (sizeof (*Base)*8-1)); - return (BOOLEAN)((InterlockedAnd(&Base[Bit/(sizeof(*Base)*8)],~tBit)&tBit)!=0); - } -#endif - -#ifndef InterlockedBitTestAndComplement -#define InterlockedBitTestAndComplement InterlockedBitTestAndComplement_Inline - - __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement_Inline(LONG *Base,LONG Bit) { - LONG tBit; - tBit = 1<<(Bit & (sizeof (*Base)*8-1)); - return (BOOLEAN)((InterlockedXor(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); - } -#endif -#elif defined(__x86_64) && !defined(RC_INVOKED) - -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedDecrement _InterlockedDecrement -#define InterlockedDecrementAcquire InterlockedDecrement -#define InterlockedDecrementRelease InterlockedDecrement -#define InterlockedExchange _InterlockedExchange -#define InterlockedExchangeAdd _InterlockedExchangeAdd -#define InterlockedCompareExchange _InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire InterlockedCompareExchange -#define InterlockedCompareExchangeRelease InterlockedCompareExchange -#define InterlockedExchangePointer _InterlockedExchangePointer -#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer -#define InterlockedAnd64 _InterlockedAnd64 -#define InterlockedOr64 _InterlockedOr64 -#define InterlockedXor64 _InterlockedXor64 -#define InterlockedIncrement64 _InterlockedIncrement64 -#define InterlockedDecrement64 _InterlockedDecrement64 -#define InterlockedExchange64 _InterlockedExchange64 -#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 -#define InterlockedCompareExchange64 _InterlockedCompareExchange64 -#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 -#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 - - LONG InterlockedIncrement(LONG volatile *Addend); - LONG InterlockedDecrement(LONG volatile *Addend); - LONG InterlockedExchange(LONG volatile *Target,LONG Value); - LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); - PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); - PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); - LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value); - LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value); - LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value); - LONG64 InterlockedIncrement64(LONG64 volatile *Addend); - LONG64 InterlockedDecrement64(LONG64 volatile *Addend); - LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value); - LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); - LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand); -#else - LONG WINAPI InterlockedIncrement(LONG volatile *lpAddend); - LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend); - LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value); - -#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value)) - - LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand); - LONGLONG WINAPI InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand); - - __CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); - return Old; - } - - __CRT_INLINE LONGLONG InterlockedOr64 (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); - return Old; - } - - __CRT_INLINE LONGLONG InterlockedXor64 (LONGLONG volatile *Destination,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Destination; - } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); - - return Old; - } - - __CRT_INLINE LONGLONG InterlockedIncrement64(LONGLONG volatile *Addend) { - LONGLONG Old; - do { - Old = *Addend; - } while(InterlockedCompareExchange64(Addend,Old + 1,Old)!=Old); - return Old + 1; - } - - __CRT_INLINE LONGLONG InterlockedDecrement64(LONGLONG volatile *Addend) { - LONGLONG Old; - do { - Old = *Addend; - } while(InterlockedCompareExchange64(Addend,Old - 1,Old)!=Old); - return Old - 1; - } - - __CRT_INLINE LONGLONG InterlockedExchange64(LONGLONG volatile *Target,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Target; - } while(InterlockedCompareExchange64(Target,Value,Old)!=Old); - return Old; - } - - __CRT_INLINE LONGLONG InterlockedExchangeAdd64(LONGLONG volatile *Addend,LONGLONG Value) { - LONGLONG Old; - do { - Old = *Addend; - } while(InterlockedCompareExchange64(Addend,Old + Value,Old)!=Old); - return Old; - } - -#ifdef __cplusplus - __CRT_INLINE PVOID __cdecl __InlineInterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { - return((PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)Destination,(LONG)(LONG_PTR)ExChange,(LONG)(LONG_PTR)Comperand)); - } -#define InterlockedCompareExchangePointer __InlineInterlockedCompareExchangePointer -#else -#define InterlockedCompareExchangePointer(Destination,ExChange,Comperand)(PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)(Destination),(LONG)(LONG_PTR)(ExChange),(LONG)(LONG_PTR)(Comperand)) -#endif - -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedDecrementAcquire InterlockedDecrement -#define InterlockedDecrementRelease InterlockedDecrement -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedCompareExchangeAcquire InterlockedCompareExchange -#define InterlockedCompareExchangeRelease InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 -#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 -#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer -#endif - -#if defined(_SLIST_HEADER_) && !defined(_NTOSP_) - WINBASEAPI VOID WINAPI InitializeSListHead(PSLIST_HEADER ListHead); - WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPopEntrySList(PSLIST_HEADER ListHead); - WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); - WINBASEAPI PSLIST_ENTRY WINAPI InterlockedFlushSList(PSLIST_HEADER ListHead); - WINBASEAPI USHORT WINAPI QueryDepthSList(PSLIST_HEADER ListHead); -#endif -#endif -#endif - - WINBASEAPI WINBOOL WINAPI FreeResource(HGLOBAL hResData); - WINBASEAPI LPVOID WINAPI LockResource(HGLOBAL hResData); - -#define UnlockResource(hResData) ((hResData),0) -#define MAXINTATOM 0xC000 -#define MAKEINTATOM(i) (LPTSTR)((ULONG_PTR)((WORD)(i))) -#define INVALID_ATOM ((ATOM)0) - - int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd); - WINBASEAPI WINBOOL WINAPI FreeLibrary(HMODULE hLibModule); - WINBASEAPI DECLSPEC_NORETURN VOID WINAPI FreeLibraryAndExitThread(HMODULE hLibModule,DWORD dwExitCode); - WINBASEAPI WINBOOL WINAPI DisableThreadLibraryCalls(HMODULE hLibModule); - WINBASEAPI FARPROC WINAPI GetProcAddress(HMODULE hModule,LPCSTR lpProcName); - WINBASEAPI DWORD WINAPI GetVersion(VOID); - WINBASEAPI HGLOBAL WINAPI GlobalAlloc(UINT uFlags,SIZE_T dwBytes); - WINBASEAPI HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem,SIZE_T dwBytes,UINT uFlags); - WINBASEAPI SIZE_T WINAPI GlobalSize(HGLOBAL hMem); - WINBASEAPI UINT WINAPI GlobalFlags(HGLOBAL hMem); - WINBASEAPI LPVOID WINAPI GlobalLock(HGLOBAL hMem); - WINBASEAPI HGLOBAL WINAPI GlobalHandle(LPCVOID pMem); - WINBASEAPI WINBOOL WINAPI GlobalUnlock(HGLOBAL hMem); - WINBASEAPI HGLOBAL WINAPI GlobalFree(HGLOBAL hMem); - WINBASEAPI SIZE_T WINAPI GlobalCompact(DWORD dwMinFree); - WINBASEAPI VOID WINAPI GlobalFix(HGLOBAL hMem); - WINBASEAPI VOID WINAPI GlobalUnfix(HGLOBAL hMem); - WINBASEAPI LPVOID WINAPI GlobalWire(HGLOBAL hMem); - WINBASEAPI WINBOOL WINAPI GlobalUnWire(HGLOBAL hMem); - WINBASEAPI VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer); - - typedef struct _MEMORYSTATUSEX { - DWORD dwLength; - DWORD dwMemoryLoad; - DWORDLONG ullTotalPhys; - DWORDLONG ullAvailPhys; - DWORDLONG ullTotalPageFile; - DWORDLONG ullAvailPageFile; - DWORDLONG ullTotalVirtual; - DWORDLONG ullAvailVirtual; - DWORDLONG ullAvailExtendedVirtual; - } MEMORYSTATUSEX,*LPMEMORYSTATUSEX; - - WINBASEAPI WINBOOL WINAPI GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer); - WINBASEAPI HLOCAL WINAPI LocalAlloc(UINT uFlags,SIZE_T uBytes); - WINBASEAPI HLOCAL WINAPI LocalReAlloc(HLOCAL hMem,SIZE_T uBytes,UINT uFlags); - WINBASEAPI LPVOID WINAPI LocalLock(HLOCAL hMem); - WINBASEAPI HLOCAL WINAPI LocalHandle(LPCVOID pMem); - WINBASEAPI WINBOOL WINAPI LocalUnlock(HLOCAL hMem); - WINBASEAPI SIZE_T WINAPI LocalSize(HLOCAL hMem); - WINBASEAPI UINT WINAPI LocalFlags(HLOCAL hMem); - WINBASEAPI HLOCAL WINAPI LocalFree(HLOCAL hMem); - WINBASEAPI SIZE_T WINAPI LocalShrink(HLOCAL hMem,UINT cbNewSize); - WINBASEAPI SIZE_T WINAPI LocalCompact(UINT uMinFree); - WINBASEAPI WINBOOL WINAPI FlushInstructionCache(HANDLE hProcess,LPCVOID lpBaseAddress,SIZE_T dwSize); - WINBASEAPI LPVOID WINAPI VirtualAlloc(LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); - WINBASEAPI WINBOOL WINAPI VirtualFree(LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); - WINBASEAPI WINBOOL WINAPI VirtualProtect(LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); - WINBASEAPI SIZE_T WINAPI VirtualQuery(LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); - WINBASEAPI LPVOID WINAPI VirtualAllocEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); - WINBASEAPI UINT WINAPI GetWriteWatch(DWORD dwFlags,PVOID lpBaseAddress,SIZE_T dwRegionSize,PVOID *lpAddresses,ULONG_PTR *lpdwCount,PULONG lpdwGranularity); - WINBASEAPI UINT WINAPI ResetWriteWatch(LPVOID lpBaseAddress,SIZE_T dwRegionSize); - WINBASEAPI SIZE_T WINAPI GetLargePageMinimum(VOID); - WINBASEAPI UINT WINAPI EnumSystemFirmwareTables(DWORD FirmwareTableProviderSignature,PVOID pFirmwareTableEnumBuffer,DWORD BufferSize); - WINBASEAPI UINT WINAPI GetSystemFirmwareTable(DWORD FirmwareTableProviderSignature,DWORD FirmwareTableID,PVOID pFirmwareTableBuffer,DWORD BufferSize); - WINBASEAPI WINBOOL WINAPI VirtualFreeEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); - WINBASEAPI WINBOOL WINAPI VirtualProtectEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); - WINBASEAPI SIZE_T WINAPI VirtualQueryEx(HANDLE hProcess,LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); - WINBASEAPI HANDLE WINAPI HeapCreate(DWORD flOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize); - WINBASEAPI WINBOOL WINAPI HeapDestroy(HANDLE hHeap); - WINBASEAPI LPVOID WINAPI HeapAlloc(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes); - WINBASEAPI LPVOID WINAPI HeapReAlloc(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem,SIZE_T dwBytes); - WINBASEAPI WINBOOL WINAPI HeapFree(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem); - WINBASEAPI SIZE_T WINAPI HeapSize(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); - WINBASEAPI WINBOOL WINAPI HeapValidate(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); - WINBASEAPI SIZE_T WINAPI HeapCompact(HANDLE hHeap,DWORD dwFlags); - WINBASEAPI HANDLE WINAPI GetProcessHeap(VOID); - WINBASEAPI DWORD WINAPI GetProcessHeaps(DWORD NumberOfHeaps,PHANDLE ProcessHeaps); - - typedef struct _PROCESS_HEAP_ENTRY { - PVOID lpData; - DWORD cbData; - BYTE cbOverhead; - BYTE iRegionIndex; - WORD wFlags; - union { - struct { - HANDLE hMem; - DWORD dwReserved[3]; - } Block; - struct { - DWORD dwCommittedSize; - DWORD dwUnCommittedSize; - LPVOID lpFirstBlock; - LPVOID lpLastBlock; - } Region; - }; - } PROCESS_HEAP_ENTRY,*LPPROCESS_HEAP_ENTRY,*PPROCESS_HEAP_ENTRY; - -#define PROCESS_HEAP_REGION 0x1 -#define PROCESS_HEAP_UNCOMMITTED_RANGE 0x2 -#define PROCESS_HEAP_ENTRY_BUSY 0x4 -#define PROCESS_HEAP_ENTRY_MOVEABLE 0x10 -#define PROCESS_HEAP_ENTRY_DDESHARE 0x20 - - WINBASEAPI WINBOOL WINAPI HeapLock(HANDLE hHeap); - WINBASEAPI WINBOOL WINAPI HeapUnlock(HANDLE hHeap); - WINBASEAPI WINBOOL WINAPI HeapWalk(HANDLE hHeap,LPPROCESS_HEAP_ENTRY lpEntry); - WINBASEAPI WINBOOL WINAPI HeapSetInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); - WINBASEAPI WINBOOL WINAPI HeapQueryInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); - -#define SCS_32BIT_BINARY 0 -#define SCS_DOS_BINARY 1 -#define SCS_WOW_BINARY 2 -#define SCS_PIF_BINARY 3 -#define SCS_POSIX_BINARY 4 -#define SCS_OS216_BINARY 5 -#define SCS_64BIT_BINARY 6 - -#ifdef UNICODE -#define GetBinaryType GetBinaryTypeW -#define GetShortPathName GetShortPathNameW -#define GetLongPathName GetLongPathNameW -#define GetEnvironmentStrings GetEnvironmentStringsW -#define SetEnvironmentStrings SetEnvironmentStringsW -#define FreeEnvironmentStrings FreeEnvironmentStringsW -#else -#define GetBinaryType GetBinaryTypeA -#define GetShortPathName GetShortPathNameA -#define GetLongPathName GetLongPathNameA -#define GetEnvironmentStringsA GetEnvironmentStrings -#define SetEnvironmentStrings SetEnvironmentStringsA -#define FreeEnvironmentStrings FreeEnvironmentStringsA -#endif - -#ifdef _WIN64 -#define SCS_THIS_PLATFORM_BINARY SCS_64BIT_BINARY -#else -#define SCS_THIS_PLATFORM_BINARY SCS_32BIT_BINARY -#endif - - WINBASEAPI WINBOOL WINAPI GetBinaryTypeA(LPCSTR lpApplicationName,LPDWORD lpBinaryType); - WINBASEAPI WINBOOL WINAPI GetBinaryTypeW(LPCWSTR lpApplicationName,LPDWORD lpBinaryType); - WINBASEAPI DWORD WINAPI GetShortPathNameA(LPCSTR lpszLongPath,LPSTR lpszShortPath,DWORD cchBuffer); - WINBASEAPI DWORD WINAPI GetShortPathNameW(LPCWSTR lpszLongPath,LPWSTR lpszShortPath,DWORD cchBuffer); - WINBASEAPI DWORD WINAPI GetLongPathNameA(LPCSTR lpszShortPath,LPSTR lpszLongPath,DWORD cchBuffer); - WINBASEAPI DWORD WINAPI GetLongPathNameW(LPCWSTR lpszShortPath,LPWSTR lpszLongPath,DWORD cchBuffer); - WINBASEAPI WINBOOL WINAPI GetProcessAffinityMask(HANDLE hProcess,PDWORD_PTR lpProcessAffinityMask,PDWORD_PTR lpSystemAffinityMask); - WINBASEAPI WINBOOL WINAPI SetProcessAffinityMask(HANDLE hProcess,DWORD_PTR dwProcessAffinityMask); - WINBASEAPI WINBOOL WINAPI GetProcessHandleCount(HANDLE hProcess,PDWORD pdwHandleCount); - WINBASEAPI WINBOOL WINAPI GetProcessTimes(HANDLE hProcess,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); - WINBASEAPI WINBOOL WINAPI GetProcessIoCounters(HANDLE hProcess,PIO_COUNTERS lpIoCounters); - WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize); - WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSizeEx(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize,PDWORD Flags); - WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize); - WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSizeEx(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize,DWORD Flags); - WINBASEAPI HANDLE WINAPI OpenProcess(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwProcessId); - WINBASEAPI HANDLE WINAPI GetCurrentProcess(VOID); - WINBASEAPI DWORD WINAPI GetCurrentProcessId(VOID); - WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitProcess(UINT uExitCode); - WINBASEAPI WINBOOL WINAPI TerminateProcess(HANDLE hProcess,UINT uExitCode); - WINBASEAPI WINBOOL WINAPI GetExitCodeProcess(HANDLE hProcess,LPDWORD lpExitCode); - WINBASEAPI VOID WINAPI FatalExit(int ExitCode); - /* WINBASEAPI LPCH WINAPI GetEnvironmentStrings(VOID); */ - WINBASEAPI LPWCH WINAPI GetEnvironmentStringsW(VOID); - WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsA(LPCH NewEnvironment); - WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsW(LPWCH NewEnvironment); - WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsA(LPCH); - WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsW(LPWCH); - WINBASEAPI VOID WINAPI RaiseException(DWORD dwExceptionCode,DWORD dwExceptionFlags,DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments); - WINBASEAPI LONG WINAPI UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo); - - typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(struct _EXCEPTION_POINTERS *ExceptionInfo); - typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER; - - WINBASEAPI LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); - -#define FIBER_FLAG_FLOAT_SWITCH 0x1 - - WINBASEAPI LPVOID WINAPI CreateFiber(SIZE_T dwStackSize,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); - WINBASEAPI LPVOID WINAPI CreateFiberEx(SIZE_T dwStackCommitSize,SIZE_T dwStackReserveSize,DWORD dwFlags,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); - WINBASEAPI VOID WINAPI DeleteFiber(LPVOID lpFiber); - WINBASEAPI LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter); - WINBASEAPI LPVOID WINAPI ConvertThreadToFiberEx(LPVOID lpParameter,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI ConvertFiberToThread(VOID); - WINBASEAPI VOID WINAPI SwitchToFiber(LPVOID lpFiber); - WINBASEAPI WINBOOL WINAPI SwitchToThread(VOID); - WINBASEAPI HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); - WINBASEAPI HANDLE WINAPI CreateRemoteThread(HANDLE hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); - WINBASEAPI HANDLE WINAPI GetCurrentThread(VOID); - WINBASEAPI DWORD WINAPI GetCurrentThreadId(VOID); - WINBASEAPI WINBOOL WINAPI SetThreadStackGuarantee (PULONG StackSizeInBytes); - WINBASEAPI DWORD WINAPI GetProcessIdOfThread(HANDLE Thread); - WINBASEAPI DWORD WINAPI GetThreadId(HANDLE Thread); - WINBASEAPI DWORD WINAPI GetProcessId(HANDLE Process); - WINBASEAPI DWORD WINAPI GetCurrentProcessorNumber(VOID); - WINBASEAPI DWORD_PTR WINAPI SetThreadAffinityMask(HANDLE hThread,DWORD_PTR dwThreadAffinityMask); - WINBASEAPI DWORD WINAPI SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor); - WINBASEAPI WINBOOL WINAPI SetProcessPriorityBoost(HANDLE hProcess,WINBOOL bDisablePriorityBoost); - WINBASEAPI WINBOOL WINAPI GetProcessPriorityBoost(HANDLE hProcess,PBOOL pDisablePriorityBoost); - WINBASEAPI WINBOOL WINAPI RequestWakeupLatency(LATENCY_TIME latency); - WINBASEAPI WINBOOL WINAPI IsSystemResumeAutomatic(VOID); - WINBASEAPI HANDLE WINAPI OpenThread(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwThreadId); - WINBASEAPI WINBOOL WINAPI SetThreadPriority(HANDLE hThread,int nPriority); - WINBASEAPI WINBOOL WINAPI SetThreadPriorityBoost(HANDLE hThread,WINBOOL bDisablePriorityBoost); - WINBASEAPI WINBOOL WINAPI GetThreadPriorityBoost(HANDLE hThread,PBOOL pDisablePriorityBoost); - WINBASEAPI int WINAPI GetThreadPriority(HANDLE hThread); - WINBASEAPI WINBOOL WINAPI GetThreadTimes(HANDLE hThread,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); - WINBASEAPI WINBOOL WINAPI GetThreadIOPendingFlag(HANDLE hThread,PBOOL lpIOIsPending); - WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitThread(DWORD dwExitCode); - WINBASEAPI WINBOOL WINAPI TerminateThread(HANDLE hThread,DWORD dwExitCode); - WINBASEAPI WINBOOL WINAPI GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode); - WINBASEAPI WINBOOL WINAPI GetThreadSelectorEntry(HANDLE hThread,DWORD dwSelector,LPLDT_ENTRY lpSelectorEntry); - WINBASEAPI EXECUTION_STATE WINAPI SetThreadExecutionState(EXECUTION_STATE esFlags); - WINBASEAPI DWORD WINAPI GetLastError(VOID); - WINBASEAPI VOID WINAPI SetLastError(DWORD dwErrCode); - -#ifndef RC_INVOKED -#ifdef WINBASE_DECLARE_RESTORE_LAST_ERROR - WINBASEAPI VOID WINAPI RestoreLastError(DWORD dwErrCode); - - typedef VOID (WINAPI *PRESTORE_LAST_ERROR)(DWORD); - -#define RESTORE_LAST_ERROR_NAME_A "RestoreLastError" -#define RESTORE_LAST_ERROR_NAME_W L"RestoreLastError" -#define RESTORE_LAST_ERROR_NAME TEXT("RestoreLastError") -#endif -#endif - -#define HasOverlappedIoCompleted(lpOverlapped) (((DWORD)(lpOverlapped)->Internal)!=STATUS_PENDING) - - WINBASEAPI WINBOOL WINAPI GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,LPDWORD lpNumberOfBytesTransferred,WINBOOL bWait); - WINBASEAPI HANDLE WINAPI CreateIoCompletionPort(HANDLE FileHandle,HANDLE ExistingCompletionPort,ULONG_PTR CompletionKey,DWORD NumberOfConcurrentThreads); - WINBASEAPI WINBOOL WINAPI GetQueuedCompletionStatus(HANDLE CompletionPort,LPDWORD lpNumberOfBytesTransferred,PULONG_PTR lpCompletionKey,LPOVERLAPPED *lpOverlapped,DWORD dwMilliseconds); - WINBASEAPI WINBOOL WINAPI PostQueuedCompletionStatus(HANDLE CompletionPort,DWORD dwNumberOfBytesTransferred,ULONG_PTR dwCompletionKey,LPOVERLAPPED lpOverlapped); - -#define SEM_FAILCRITICALERRORS 0x1 -#define SEM_NOGPFAULTERRORBOX 0x2 -#define SEM_NOALIGNMENTFAULTEXCEPT 0x4 -#define SEM_NOOPENFILEERRORBOX 0x8000 - - WINBASEAPI UINT WINAPI SetErrorMode(UINT uMode); - WINBASEAPI WINBOOL WINAPI ReadProcessMemory(HANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesRead); - WINBASEAPI WINBOOL WINAPI WriteProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesWritten); - WINBASEAPI WINBOOL WINAPI GetThreadContext(HANDLE hThread,LPCONTEXT lpContext); - WINBASEAPI WINBOOL WINAPI SetThreadContext(HANDLE hThread,CONST CONTEXT *lpContext); - WINBASEAPI DWORD WINAPI SuspendThread(HANDLE hThread); - WINBASEAPI DWORD WINAPI ResumeThread(HANDLE hThread); - - typedef VOID (WINAPI *PAPCFUNC)(ULONG_PTR dwParam); - - WINBASEAPI DWORD WINAPI QueueUserAPC(PAPCFUNC pfnAPC,HANDLE hThread,ULONG_PTR dwData); - WINBASEAPI WINBOOL WINAPI IsDebuggerPresent(VOID); - WINBASEAPI WINBOOL WINAPI CheckRemoteDebuggerPresent(HANDLE hProcess,PBOOL pbDebuggerPresent); - WINBASEAPI VOID WINAPI DebugBreak(VOID); - WINBASEAPI WINBOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT lpDebugEvent,DWORD dwMilliseconds); - WINBASEAPI WINBOOL WINAPI ContinueDebugEvent(DWORD dwProcessId,DWORD dwThreadId,DWORD dwContinueStatus); - WINBASEAPI WINBOOL WINAPI DebugActiveProcess(DWORD dwProcessId); - WINBASEAPI WINBOOL WINAPI DebugActiveProcessStop(DWORD dwProcessId); - WINBASEAPI WINBOOL WINAPI DebugSetProcessKillOnExit(WINBOOL KillOnExit); - WINBASEAPI WINBOOL WINAPI DebugBreakProcess(HANDLE Process); - WINBASEAPI VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI WINBOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); - WINBASEAPI DWORD WINAPI SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); - WINBASEAPI WINBOOL WINAPI TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); - WINBASEAPI WINBOOL WINAPI SetEvent(HANDLE hEvent); - WINBASEAPI WINBOOL WINAPI ResetEvent(HANDLE hEvent); - WINBASEAPI WINBOOL WINAPI PulseEvent(HANDLE hEvent); - WINBASEAPI WINBOOL WINAPI ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount,LPLONG lpPreviousCount); - WINBASEAPI WINBOOL WINAPI ReleaseMutex(HANDLE hMutex); - WINBASEAPI DWORD WINAPI WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds); - WINBASEAPI DWORD WINAPI WaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds); - WINBASEAPI VOID WINAPI Sleep(DWORD dwMilliseconds); - WINBASEAPI HGLOBAL WINAPI LoadResource(HMODULE hModule,HRSRC hResInfo); - WINBASEAPI DWORD WINAPI SizeofResource(HMODULE hModule,HRSRC hResInfo); - WINBASEAPI ATOM WINAPI GlobalDeleteAtom(ATOM nAtom); - WINBASEAPI WINBOOL WINAPI InitAtomTable(DWORD nSize); - WINBASEAPI ATOM WINAPI DeleteAtom(ATOM nAtom); - WINBASEAPI UINT WINAPI SetHandleCount(UINT uNumber); - WINBASEAPI DWORD WINAPI GetLogicalDrives(VOID); - WINBASEAPI WINBOOL WINAPI LockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh); - WINBASEAPI WINBOOL WINAPI UnlockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh); - WINBASEAPI WINBOOL WINAPI LockFileEx(HANDLE hFile,DWORD dwFlags,DWORD dwReserved,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh,LPOVERLAPPED lpOverlapped); - -#define LOCKFILE_FAIL_IMMEDIATELY 0x1 -#define LOCKFILE_EXCLUSIVE_LOCK 0x2 - - WINBASEAPI WINBOOL WINAPI UnlockFileEx(HANDLE hFile,DWORD dwReserved,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh,LPOVERLAPPED lpOverlapped); - - typedef struct _BY_HANDLE_FILE_INFORMATION { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD dwVolumeSerialNumber; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD nNumberOfLinks; - DWORD nFileIndexHigh; - DWORD nFileIndexLow; - } BY_HANDLE_FILE_INFORMATION,*PBY_HANDLE_FILE_INFORMATION,*LPBY_HANDLE_FILE_INFORMATION; - -#ifdef UNICODE -#define SetFileShortName SetFileShortNameW -#else -#define SetFileShortName SetFileShortNameA -#endif - - WINBASEAPI WINBOOL WINAPI GetFileInformationByHandle(HANDLE hFile,LPBY_HANDLE_FILE_INFORMATION lpFileInformation); - WINBASEAPI DWORD WINAPI GetFileType(HANDLE hFile); - WINBASEAPI DWORD WINAPI GetFileSize(HANDLE hFile,LPDWORD lpFileSizeHigh); - WINBASEAPI WINBOOL WINAPI GetFileSizeEx(HANDLE hFile,PLARGE_INTEGER lpFileSize); - WINBASEAPI HANDLE WINAPI GetStdHandle(DWORD nStdHandle); - WINBASEAPI WINBOOL WINAPI SetStdHandle(DWORD nStdHandle,HANDLE hHandle); - WINBASEAPI WINBOOL WINAPI WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI FlushFileBuffers(HANDLE hFile); - WINBASEAPI WINBOOL WINAPI DeviceIoControl(HANDLE hDevice,DWORD dwIoControlCode,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI RequestDeviceWakeup(HANDLE hDevice); - WINBASEAPI WINBOOL WINAPI CancelDeviceWakeupRequest(HANDLE hDevice); - WINBASEAPI WINBOOL WINAPI GetDevicePowerState(HANDLE hDevice,WINBOOL *pfOn); - WINBASEAPI WINBOOL WINAPI SetMessageWaitingIndicator(HANDLE hMsgIndicator,ULONG ulMsgCount); - WINBASEAPI WINBOOL WINAPI SetEndOfFile(HANDLE hFile); - WINBASEAPI DWORD WINAPI SetFilePointer(HANDLE hFile,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod); - WINBASEAPI WINBOOL WINAPI SetFilePointerEx(HANDLE hFile,LARGE_INTEGER liDistanceToMove,PLARGE_INTEGER lpNewFilePointer,DWORD dwMoveMethod); - WINBASEAPI WINBOOL WINAPI FindClose(HANDLE hFindFile); - WINBASEAPI WINBOOL WINAPI GetFileTime(HANDLE hFile,LPFILETIME lpCreationTime,LPFILETIME lpLastAccessTime,LPFILETIME lpLastWriteTime); - WINBASEAPI WINBOOL WINAPI SetFileTime(HANDLE hFile,CONST FILETIME *lpCreationTime,CONST FILETIME *lpLastAccessTime,CONST FILETIME *lpLastWriteTime); - WINBASEAPI WINBOOL WINAPI SetFileValidData(HANDLE hFile,LONGLONG ValidDataLength); - WINBASEAPI WINBOOL WINAPI SetFileShortNameA(HANDLE hFile,LPCSTR lpShortName); - WINBASEAPI WINBOOL WINAPI SetFileShortNameW(HANDLE hFile,LPCWSTR lpShortName); - WINBASEAPI WINBOOL WINAPI CloseHandle(HANDLE hObject); - WINBASEAPI WINBOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle,HANDLE hSourceHandle,HANDLE hTargetProcessHandle,LPHANDLE lpTargetHandle,DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwOptions); - WINBASEAPI WINBOOL WINAPI GetHandleInformation(HANDLE hObject,LPDWORD lpdwFlags); - WINBASEAPI WINBOOL WINAPI SetHandleInformation(HANDLE hObject,DWORD dwMask,DWORD dwFlags); - -#define HANDLE_FLAG_INHERIT 0x1 -#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x2 - -#define HINSTANCE_ERROR 32 - - WINBASEAPI DWORD WINAPI LoadModule(LPCSTR lpModuleName,LPVOID lpParameterBlock); - WINBASEAPI UINT WINAPI WinExec(LPCSTR lpCmdLine,UINT uCmdShow); - WINBASEAPI WINBOOL WINAPI ClearCommBreak(HANDLE hFile); - WINBASEAPI WINBOOL WINAPI ClearCommError(HANDLE hFile,LPDWORD lpErrors,LPCOMSTAT lpStat); - WINBASEAPI WINBOOL WINAPI SetupComm(HANDLE hFile,DWORD dwInQueue,DWORD dwOutQueue); - WINBASEAPI WINBOOL WINAPI EscapeCommFunction(HANDLE hFile,DWORD dwFunc); - WINBASEAPI WINBOOL WINAPI GetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); - WINBASEAPI WINBOOL WINAPI GetCommMask(HANDLE hFile,LPDWORD lpEvtMask); - WINBASEAPI WINBOOL WINAPI GetCommProperties(HANDLE hFile,LPCOMMPROP lpCommProp); - WINBASEAPI WINBOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat); - WINBASEAPI WINBOOL WINAPI GetCommState(HANDLE hFile,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI GetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI PurgeComm(HANDLE hFile,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI SetCommBreak(HANDLE hFile); - WINBASEAPI WINBOOL WINAPI SetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,DWORD dwSize); - WINBASEAPI WINBOOL WINAPI SetCommMask(HANDLE hFile,DWORD dwEvtMask); - WINBASEAPI WINBOOL WINAPI SetCommState(HANDLE hFile,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI SetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI TransmitCommChar(HANDLE hFile,char cChar); - WINBASEAPI WINBOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD lpEvtMask,LPOVERLAPPED lpOverlapped); - WINBASEAPI DWORD WINAPI SetTapePosition(HANDLE hDevice,DWORD dwPositionMethod,DWORD dwPartition,DWORD dwOffsetLow,DWORD dwOffsetHigh,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI GetTapePosition(HANDLE hDevice,DWORD dwPositionType,LPDWORD lpdwPartition,LPDWORD lpdwOffsetLow,LPDWORD lpdwOffsetHigh); - WINBASEAPI DWORD WINAPI PrepareTape(HANDLE hDevice,DWORD dwOperation,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI EraseTape(HANDLE hDevice,DWORD dwEraseType,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI CreateTapePartition(HANDLE hDevice,DWORD dwPartitionMethod,DWORD dwCount,DWORD dwSize); - WINBASEAPI DWORD WINAPI WriteTapemark(HANDLE hDevice,DWORD dwTapemarkType,DWORD dwTapemarkCount,WINBOOL bImmediate); - WINBASEAPI DWORD WINAPI GetTapeStatus(HANDLE hDevice); - WINBASEAPI DWORD WINAPI GetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPDWORD lpdwSize,LPVOID lpTapeInformation); - -#define GET_TAPE_MEDIA_INFORMATION 0 -#define GET_TAPE_DRIVE_INFORMATION 1 - - WINBASEAPI DWORD WINAPI SetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPVOID lpTapeInformation); - -#define SET_TAPE_MEDIA_INFORMATION 0 -#define SET_TAPE_DRIVE_INFORMATION 1 - - WINBASEAPI WINBOOL WINAPI Beep(DWORD dwFreq,DWORD dwDuration); - WINBASEAPI int WINAPI MulDiv(int nNumber,int nNumerator,int nDenominator); - WINBASEAPI VOID WINAPI GetSystemTime(LPSYSTEMTIME lpSystemTime); - WINBASEAPI VOID WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); - WINBASEAPI WINBOOL WINAPI SetSystemTime(CONST SYSTEMTIME *lpSystemTime); - WINBASEAPI VOID WINAPI GetLocalTime(LPSYSTEMTIME lpSystemTime); - WINBASEAPI WINBOOL WINAPI SetLocalTime(CONST SYSTEMTIME *lpSystemTime); - WINBASEAPI VOID WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo); - WINBASEAPI WINBOOL WINAPI SetSystemFileCacheSize(SIZE_T MinimumFileCacheSize,SIZE_T MaximumFileCacheSize,DWORD Flags); - WINBASEAPI WINBOOL WINAPI GetSystemFileCacheSize(PSIZE_T lpMinimumFileCacheSize,PSIZE_T lpMaximumFileCacheSize,PDWORD lpFlags); - WINBASEAPI WINBOOL WINAPI GetSystemRegistryQuota(PDWORD pdwQuotaAllowed,PDWORD pdwQuotaUsed); - WINBOOL WINAPI GetSystemTimes(LPFILETIME lpIdleTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); - WINBASEAPI VOID WINAPI GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo); - WINBASEAPI WINBOOL WINAPI IsProcessorFeaturePresent(DWORD ProcessorFeature); - - typedef struct _TIME_ZONE_INFORMATION { - LONG Bias; - WCHAR StandardName[32]; - SYSTEMTIME StandardDate; - LONG StandardBias; - WCHAR DaylightName[32]; - SYSTEMTIME DaylightDate; - LONG DaylightBias; - } TIME_ZONE_INFORMATION,*PTIME_ZONE_INFORMATION,*LPTIME_ZONE_INFORMATION; - -#ifdef UNICODE -#define FormatMessage FormatMessageW -#else -#define FormatMessage FormatMessageA -#endif - - WINBASEAPI WINBOOL WINAPI SystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpUniversalTime,LPSYSTEMTIME lpLocalTime); - WINBASEAPI WINBOOL WINAPI TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpLocalTime,LPSYSTEMTIME lpUniversalTime); - WINBASEAPI DWORD WINAPI GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation); - WINBASEAPI WINBOOL WINAPI SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation); - WINBASEAPI WINBOOL WINAPI SystemTimeToFileTime(CONST SYSTEMTIME *lpSystemTime,LPFILETIME lpFileTime); - WINBASEAPI WINBOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *lpFileTime,LPFILETIME lpLocalFileTime); - WINBASEAPI WINBOOL WINAPI LocalFileTimeToFileTime(CONST FILETIME *lpLocalFileTime,LPFILETIME lpFileTime); - WINBASEAPI WINBOOL WINAPI FileTimeToSystemTime(CONST FILETIME *lpFileTime,LPSYSTEMTIME lpSystemTime); - WINBASEAPI LONG WINAPI CompareFileTime(CONST FILETIME *lpFileTime1,CONST FILETIME *lpFileTime2); - WINBASEAPI WINBOOL WINAPI FileTimeToDosDateTime(CONST FILETIME *lpFileTime,LPWORD lpFatDate,LPWORD lpFatTime); - WINBASEAPI WINBOOL WINAPI DosDateTimeToFileTime(WORD wFatDate,WORD wFatTime,LPFILETIME lpFileTime); - WINBASEAPI DWORD WINAPI GetTickCount(VOID); - WINBASEAPI WINBOOL WINAPI SetSystemTimeAdjustment(DWORD dwTimeAdjustment,WINBOOL bTimeAdjustmentDisabled); - WINBASEAPI WINBOOL WINAPI GetSystemTimeAdjustment(PDWORD lpTimeAdjustment,PDWORD lpTimeIncrement,PBOOL lpTimeAdjustmentDisabled); - WINBASEAPI DWORD WINAPI FormatMessageA(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPSTR lpBuffer,DWORD nSize,va_list *Arguments); - WINBASEAPI DWORD WINAPI FormatMessageW(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPWSTR lpBuffer,DWORD nSize,va_list *Arguments); - -#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x100 -#define FORMAT_MESSAGE_IGNORE_INSERTS 0x200 -#define FORMAT_MESSAGE_FROM_STRING 0x400 -#define FORMAT_MESSAGE_FROM_HMODULE 0x800 -#define FORMAT_MESSAGE_FROM_SYSTEM 0x1000 -#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x2000 -#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0xff - -#ifdef UNICODE -#define CreateMailslot CreateMailslotW -#define EncryptFile EncryptFileW -#define DecryptFile DecryptFileW -#define FileEncryptionStatus FileEncryptionStatusW -#else -#define CreateMailslot CreateMailslotA -#define EncryptFile EncryptFileA -#define DecryptFile DecryptFileA -#define FileEncryptionStatus FileEncryptionStatusA -#endif - - WINBASEAPI WINBOOL WINAPI CreatePipe(PHANDLE hReadPipe,PHANDLE hWritePipe,LPSECURITY_ATTRIBUTES lpPipeAttributes,DWORD nSize); - WINBASEAPI WINBOOL WINAPI ConnectNamedPipe(HANDLE hNamedPipe,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI DisconnectNamedPipe(HANDLE hNamedPipe); - WINBASEAPI WINBOOL WINAPI SetNamedPipeHandleState(HANDLE hNamedPipe,LPDWORD lpMode,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout); - WINBASEAPI WINBOOL WINAPI GetNamedPipeInfo(HANDLE hNamedPipe,LPDWORD lpFlags,LPDWORD lpOutBufferSize,LPDWORD lpInBufferSize,LPDWORD lpMaxInstances); - WINBASEAPI WINBOOL WINAPI PeekNamedPipe(HANDLE hNamedPipe,LPVOID lpBuffer,DWORD nBufferSize,LPDWORD lpBytesRead,LPDWORD lpTotalBytesAvail,LPDWORD lpBytesLeftThisMessage); - WINBASEAPI WINBOOL WINAPI TransactNamedPipe(HANDLE hNamedPipe,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,LPOVERLAPPED lpOverlapped); - WINBASEAPI HANDLE WINAPI CreateMailslotA(LPCSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI HANDLE WINAPI CreateMailslotW(LPCWSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI GetMailslotInfo(HANDLE hMailslot,LPDWORD lpMaxMessageSize,LPDWORD lpNextSize,LPDWORD lpMessageCount,LPDWORD lpReadTimeout); - WINBASEAPI WINBOOL WINAPI SetMailslotInfo(HANDLE hMailslot,DWORD lReadTimeout); - WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap); - WINBASEAPI WINBOOL WINAPI FlushViewOfFile(LPCVOID lpBaseAddress,SIZE_T dwNumberOfBytesToFlush); - WINBASEAPI WINBOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress); - WINADVAPI WINBOOL WINAPI EncryptFileA(LPCSTR lpFileName); - WINADVAPI WINBOOL WINAPI EncryptFileW(LPCWSTR lpFileName); - WINADVAPI WINBOOL WINAPI DecryptFileA(LPCSTR lpFileName,DWORD dwReserved); - WINADVAPI WINBOOL WINAPI DecryptFileW(LPCWSTR lpFileName,DWORD dwReserved); - -#define FILE_ENCRYPTABLE 0 -#define FILE_IS_ENCRYPTED 1 -#define FILE_SYSTEM_ATTR 2 -#define FILE_ROOT_DIR 3 -#define FILE_SYSTEM_DIR 4 -#define FILE_UNKNOWN 5 -#define FILE_SYSTEM_NOT_SUPPORT 6 -#define FILE_USER_DISALLOWED 7 -#define FILE_READ_ONLY 8 -#define FILE_DIR_DISALLOWED 9 - - WINADVAPI WINBOOL WINAPI FileEncryptionStatusA(LPCSTR lpFileName,LPDWORD lpStatus); - WINADVAPI WINBOOL WINAPI FileEncryptionStatusW(LPCWSTR lpFileName,LPDWORD lpStatus); - -#define EFS_USE_RECOVERY_KEYS (0x1) - - typedef DWORD (WINAPI *PFE_EXPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,ULONG ulLength); - typedef DWORD (WINAPI *PFE_IMPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,PULONG ulLength); - -#define CREATE_FOR_IMPORT (1) -#define CREATE_FOR_DIR (2) -#define OVERWRITE_HIDDEN (4) - -#ifdef UNICODE -#define OpenEncryptedFileRaw OpenEncryptedFileRawW -#define lstrcmp lstrcmpW -#define lstrcmpi lstrcmpiW -#define lstrcpyn lstrcpynW -#define lstrcpy lstrcpyW -#define lstrcat lstrcatW -#define lstrlen lstrlenW -#else -#define OpenEncryptedFileRaw OpenEncryptedFileRawA -#define lstrcmp lstrcmpA -#define lstrcmpi lstrcmpiA -#define lstrcpyn lstrcpynA -#define lstrcpy lstrcpyA -#define lstrcat lstrcatA -#define lstrlen lstrlenA -#endif - - WINADVAPI DWORD WINAPI OpenEncryptedFileRawA(LPCSTR lpFileName,ULONG ulFlags,PVOID *pvContext); - WINADVAPI DWORD WINAPI OpenEncryptedFileRawW(LPCWSTR lpFileName,ULONG ulFlags,PVOID *pvContext); - WINADVAPI DWORD WINAPI ReadEncryptedFileRaw(PFE_EXPORT_FUNC pfExportCallback,PVOID pvCallbackContext,PVOID pvContext); - WINADVAPI DWORD WINAPI WriteEncryptedFileRaw(PFE_IMPORT_FUNC pfImportCallback,PVOID pvCallbackContext,PVOID pvContext); - WINADVAPI VOID WINAPI CloseEncryptedFileRaw(PVOID pvContext); - WINBASEAPI int WINAPI lstrcmpA(LPCSTR lpString1,LPCSTR lpString2); - WINBASEAPI int WINAPI lstrcmpW(LPCWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI int WINAPI lstrcmpiA(LPCSTR lpString1,LPCSTR lpString2); - WINBASEAPI int WINAPI lstrcmpiW(LPCWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI LPSTR WINAPI lstrcpynA(LPSTR lpString1,LPCSTR lpString2,int iMaxLength); - WINBASEAPI LPWSTR WINAPI lstrcpynW(LPWSTR lpString1,LPCWSTR lpString2,int iMaxLength); - WINBASEAPI LPSTR WINAPI lstrcpyA(LPSTR lpString1,LPCSTR lpString2); - WINBASEAPI LPWSTR WINAPI lstrcpyW(LPWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI LPSTR WINAPI lstrcatA(LPSTR lpString1,LPCSTR lpString2); - WINBASEAPI LPWSTR WINAPI lstrcatW(LPWSTR lpString1,LPCWSTR lpString2); - WINBASEAPI int WINAPI lstrlenA(LPCSTR lpString); - WINBASEAPI int WINAPI lstrlenW(LPCWSTR lpString); - WINBASEAPI HFILE WINAPI OpenFile(LPCSTR lpFileName,LPOFSTRUCT lpReOpenBuff,UINT uStyle); - WINBASEAPI HFILE WINAPI _lopen(LPCSTR lpPathName,int iReadWrite); - WINBASEAPI HFILE WINAPI _lcreat(LPCSTR lpPathName,int iAttribute); - WINBASEAPI UINT WINAPI _lread(HFILE hFile,LPVOID lpBuffer,UINT uBytes); - WINBASEAPI UINT WINAPI _lwrite(HFILE hFile,LPCCH lpBuffer,UINT uBytes); - WINBASEAPI long WINAPI _hread(HFILE hFile,LPVOID lpBuffer,long lBytes); - WINBASEAPI long WINAPI _hwrite(HFILE hFile,LPCCH lpBuffer,long lBytes); - WINBASEAPI HFILE WINAPI _lclose(HFILE hFile); - WINBASEAPI LONG WINAPI _llseek(HFILE hFile,LONG lOffset,int iOrigin); - WINADVAPI WINBOOL WINAPI IsTextUnicode(CONST VOID *lpv,int iSize,LPINT lpiResult); - -#define FLS_OUT_OF_INDEXES ((DWORD)0xffffffff) - - WINBASEAPI DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); - WINBASEAPI PVOID WINAPI FlsGetValue(DWORD dwFlsIndex); - WINBASEAPI WINBOOL WINAPI FlsSetValue(DWORD dwFlsIndex,PVOID lpFlsData); - WINBASEAPI WINBOOL WINAPI FlsFree(DWORD dwFlsIndex); - -#define TLS_OUT_OF_INDEXES ((DWORD)0xffffffff) - - WINBASEAPI DWORD WINAPI TlsAlloc(VOID); - WINBASEAPI LPVOID WINAPI TlsGetValue(DWORD dwTlsIndex); - WINBASEAPI WINBOOL WINAPI TlsSetValue(DWORD dwTlsIndex,LPVOID lpTlsValue); - WINBASEAPI WINBOOL WINAPI TlsFree(DWORD dwTlsIndex); - - typedef VOID (WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped); - - WINBASEAPI DWORD WINAPI SleepEx(DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI DWORD WINAPI WaitForSingleObjectEx(HANDLE hHandle,DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI DWORD WINAPI WaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI DWORD WINAPI SignalObjectAndWait(HANDLE hObjectToSignal,HANDLE hObjectToWaitOn,DWORD dwMilliseconds,WINBOOL bAlertable); - WINBASEAPI WINBOOL WINAPI ReadFileEx(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINBASEAPI WINBOOL WINAPI WriteFileEx(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINBASEAPI WINBOOL WINAPI BackupRead(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); - WINBASEAPI WINBOOL WINAPI BackupSeek(HANDLE hFile,DWORD dwLowBytesToSeek,DWORD dwHighBytesToSeek,LPDWORD lpdwLowByteSeeked,LPDWORD lpdwHighByteSeeked,LPVOID *lpContext); - WINBASEAPI WINBOOL WINAPI BackupWrite(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); - - typedef struct _WIN32_STREAM_ID { - DWORD dwStreamId; - DWORD dwStreamAttributes; - LARGE_INTEGER Size; - DWORD dwStreamNameSize; - WCHAR cStreamName[ANYSIZE_ARRAY]; - } WIN32_STREAM_ID,*LPWIN32_STREAM_ID; - -#define BACKUP_INVALID 0x0 -#define BACKUP_DATA 0x1 -#define BACKUP_EA_DATA 0x2 -#define BACKUP_SECURITY_DATA 0x3 -#define BACKUP_ALTERNATE_DATA 0x4 -#define BACKUP_LINK 0x5 -#define BACKUP_PROPERTY_DATA 0x6 -#define BACKUP_OBJECT_ID 0x7 -#define BACKUP_REPARSE_DATA 0x8 -#define BACKUP_SPARSE_BLOCK 0x9 - -#define STREAM_NORMAL_ATTRIBUTE 0x0 -#define STREAM_MODIFIED_WHEN_READ 0x1 -#define STREAM_CONTAINS_SECURITY 0x2 -#define STREAM_CONTAINS_PROPERTIES 0x4 -#define STREAM_SPARSE_ATTRIBUTE 0x8 - - WINBASEAPI WINBOOL WINAPI ReadFileScatter(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToRead,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); - WINBASEAPI WINBOOL WINAPI WriteFileGather(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToWrite,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); - -#define STARTF_USESHOWWINDOW 0x1 -#define STARTF_USESIZE 0x2 -#define STARTF_USEPOSITION 0x4 -#define STARTF_USECOUNTCHARS 0x8 -#define STARTF_USEFILLATTRIBUTE 0x10 -#define STARTF_RUNFULLSCREEN 0x20 -#define STARTF_FORCEONFEEDBACK 0x40 -#define STARTF_FORCEOFFFEEDBACK 0x80 -#define STARTF_USESTDHANDLES 0x100 - -#define STARTF_USEHOTKEY 0x200 - - typedef struct _STARTUPINFOA { - DWORD cb; - LPSTR lpReserved; - LPSTR lpDesktop; - LPSTR lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - LPBYTE lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOA,*LPSTARTUPINFOA; - - typedef struct _STARTUPINFOW { - DWORD cb; - LPWSTR lpReserved; - LPWSTR lpDesktop; - LPWSTR lpTitle; - DWORD dwX; - DWORD dwY; - DWORD dwXSize; - DWORD dwYSize; - DWORD dwXCountChars; - DWORD dwYCountChars; - DWORD dwFillAttribute; - DWORD dwFlags; - WORD wShowWindow; - WORD cbReserved2; - LPBYTE lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - } STARTUPINFOW,*LPSTARTUPINFOW; - -#ifdef UNICODE - typedef STARTUPINFOW STARTUPINFO; - typedef LPSTARTUPINFOW LPSTARTUPINFO; -#else - typedef STARTUPINFOA STARTUPINFO; - typedef LPSTARTUPINFOA LPSTARTUPINFO; -#endif - -#define SHUTDOWN_NORETRY 0x1 - - typedef struct _WIN32_FIND_DATAA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - CHAR cFileName[MAX_PATH]; - CHAR cAlternateFileName[14]; - } WIN32_FIND_DATAA,*PWIN32_FIND_DATAA,*LPWIN32_FIND_DATAA; - - typedef struct _WIN32_FIND_DATAW { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - WCHAR cFileName[MAX_PATH]; - WCHAR cAlternateFileName[14]; - } WIN32_FIND_DATAW,*PWIN32_FIND_DATAW,*LPWIN32_FIND_DATAW; - -#ifdef UNICODE - typedef WIN32_FIND_DATAW WIN32_FIND_DATA; - typedef PWIN32_FIND_DATAW PWIN32_FIND_DATA; - typedef LPWIN32_FIND_DATAW LPWIN32_FIND_DATA; -#else - typedef WIN32_FIND_DATAA WIN32_FIND_DATA; - typedef PWIN32_FIND_DATAA PWIN32_FIND_DATA; - typedef LPWIN32_FIND_DATAA LPWIN32_FIND_DATA; -#endif - - typedef struct _WIN32_FILE_ATTRIBUTE_DATA { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - } WIN32_FILE_ATTRIBUTE_DATA,*LPWIN32_FILE_ATTRIBUTE_DATA; - -#ifdef UNICODE -#define CreateMutex CreateMutexW -#define OpenMutex OpenMutexW -#define CreateEvent CreateEventW -#define OpenEvent OpenEventW -#define CreateSemaphore CreateSemaphoreW -#define OpenSemaphore OpenSemaphoreW -#else -#define CreateMutex CreateMutexA -#define OpenMutex OpenMutexA -#define CreateEvent CreateEventA -#define OpenEvent OpenEventA -#define CreateSemaphore CreateSemaphoreA -#define OpenSemaphore OpenSemaphoreA -#endif - - WINBASEAPI HANDLE WINAPI CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenMutexA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenMutexW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenEventA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenEventW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenSemaphoreA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenSemaphoreW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - - typedef VOID (WINAPI *PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue); - -#ifdef UNICODE -#define CreateWaitableTimer CreateWaitableTimerW -#define OpenWaitableTimer OpenWaitableTimerW -#define CreateFileMapping CreateFileMappingW -#define OpenFileMapping OpenFileMappingW -#define GetLogicalDriveStrings GetLogicalDriveStringsW -#define LoadLibrary LoadLibraryW -#define LoadLibraryEx LoadLibraryExW -#define GetModuleFileName GetModuleFileNameW -#define GetModuleHandle GetModuleHandleW -#else -#define CreateWaitableTimer CreateWaitableTimerA -#define OpenWaitableTimer OpenWaitableTimerA -#define CreateFileMapping CreateFileMappingA -#define OpenFileMapping OpenFileMappingA -#define GetLogicalDriveStrings GetLogicalDriveStringsA -#define LoadLibrary LoadLibraryA -#define LoadLibraryEx LoadLibraryExA -#define GetModuleFileName GetModuleFileNameA -#define GetModuleHandle GetModuleHandleA -#endif - - WINBASEAPI HANDLE WINAPI CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCSTR lpTimerName); - WINBASEAPI HANDLE WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCWSTR lpTimerName); - WINBASEAPI HANDLE WINAPI OpenWaitableTimerA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpTimerName); - WINBASEAPI HANDLE WINAPI OpenWaitableTimerW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpTimerName); - WINBASEAPI WINBOOL WINAPI SetWaitableTimer(HANDLE hTimer,const LARGE_INTEGER *lpDueTime,LONG lPeriod,PTIMERAPCROUTINE pfnCompletionRoutine,LPVOID lpArgToCompletionRoutine,WINBOOL fResume); - WINBASEAPI WINBOOL WINAPI CancelWaitableTimer(HANDLE hTimer); - WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenFileMappingA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenFileMappingW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI DWORD WINAPI GetLogicalDriveStringsA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetLogicalDriveStringsW(DWORD nBufferLength,LPWSTR lpBuffer); - - typedef enum _MEMORY_RESOURCE_NOTIFICATION_TYPE { - LowMemoryResourceNotification,HighMemoryResourceNotification - } MEMORY_RESOURCE_NOTIFICATION_TYPE; - - WINBASEAPI HANDLE WINAPI CreateMemoryResourceNotification(MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType); - WINBASEAPI WINBOOL WINAPI QueryMemoryResourceNotification(HANDLE ResourceNotificationHandle,PBOOL ResourceState); - WINBASEAPI HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName); - WINBASEAPI HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName); - WINBASEAPI HMODULE WINAPI LoadLibraryExA(LPCSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); - WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); - -#define DONT_RESOLVE_DLL_REFERENCES 0x1 -#define LOAD_LIBRARY_AS_DATAFILE 0x2 -#define LOAD_WITH_ALTERED_SEARCH_PATH 0x8 -#define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x10 -#define LOAD_LINRARY_AS_IMAGE_RESOURCE 0x20 -#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x40 - - WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule,LPCH lpFilename,DWORD nSize); - WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE hModule,LPWCH lpFilename,DWORD nSize); - WINBASEAPI HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName); - WINBASEAPI HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName); - -#ifndef RC_INVOKED -#define GET_MODULE_HANDLE_EX_FLAG_PIN (0x1) -#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT (0x2) -#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS (0x4) - - typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXA)(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); - typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXW)(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); - -#ifdef UNICODE -#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXW -#define GetModuleHandleEx GetModuleHandleExW -#else -#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXA -#define GetModuleHandleEx GetModuleHandleExA -#endif - - WINBASEAPI WINBOOL WINAPI GetModuleHandleExA(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); - WINBASEAPI WINBOOL WINAPI GetModuleHandleExW(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); -#endif - -#ifdef UNICODE -#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathW -#define CreateProcess CreateProcessW -#define FatalAppExit FatalAppExitW -#define GetStartupInfo GetStartupInfoW -#define GetCommandLine GetCommandLineW -#define GetEnvironmentVariable GetEnvironmentVariableW -#define SetEnvironmentVariable SetEnvironmentVariableW -#define ExpandEnvironmentStrings ExpandEnvironmentStringsW -#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableW -#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableW -#define OutputDebugString OutputDebugStringW -#define FindResource FindResourceW -#define FindResourceEx FindResourceExW -#else -#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathA -#define CreateProcess CreateProcessA -#define FatalAppExit FatalAppExitA -#define GetStartupInfo GetStartupInfoA -#define GetCommandLine GetCommandLineA -#define GetEnvironmentVariable GetEnvironmentVariableA -#define SetEnvironmentVariable SetEnvironmentVariableA -#define ExpandEnvironmentStrings ExpandEnvironmentStringsA -#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableA -#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableA -#define OutputDebugString OutputDebugStringA -#define FindResource FindResourceA -#define FindResourceEx FindResourceExA -#endif - - WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathA(LPCSTR ExeName); - WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathW(LPCWSTR ExeName); - WINBASEAPI WINBOOL WINAPI CreateProcessA(LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINBASEAPI WINBOOL WINAPI CreateProcessW(LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameA(LPCSTR lpDnsFQHostname,ULONG ulFlags); - WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameW(LPCWSTR lpDnsFQHostname,ULONG ulFlags); - WINBASEAPI WINBOOL WINAPI SetProcessShutdownParameters(DWORD dwLevel,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI GetProcessShutdownParameters(LPDWORD lpdwLevel,LPDWORD lpdwFlags); - WINBASEAPI DWORD WINAPI GetProcessVersion(DWORD ProcessId); - WINBASEAPI VOID WINAPI FatalAppExitA(UINT uAction,LPCSTR lpMessageText); - WINBASEAPI VOID WINAPI FatalAppExitW(UINT uAction,LPCWSTR lpMessageText); - WINBASEAPI VOID WINAPI GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo); - WINBASEAPI VOID WINAPI GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo); - WINBASEAPI LPSTR WINAPI GetCommandLineA(VOID); - WINBASEAPI LPWSTR WINAPI GetCommandLineW(VOID); - WINBASEAPI DWORD WINAPI GetEnvironmentVariableA(LPCSTR lpName,LPSTR lpBuffer,DWORD nSize); - WINBASEAPI DWORD WINAPI GetEnvironmentVariableW(LPCWSTR lpName,LPWSTR lpBuffer,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableA(LPCSTR lpName,LPCSTR lpValue); - WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpValue); - WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsA(LPCSTR lpSrc,LPSTR lpDst,DWORD nSize); - WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsW(LPCWSTR lpSrc,LPWSTR lpDst,DWORD nSize); - WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pBuffer,DWORD nSize); - WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pBuffer,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pValue,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pValue,DWORD nSize); - WINBASEAPI VOID WINAPI OutputDebugStringA(LPCSTR lpOutputString); - WINBASEAPI VOID WINAPI OutputDebugStringW(LPCWSTR lpOutputString); - WINBASEAPI HRSRC WINAPI FindResourceA(HMODULE hModule,LPCSTR lpName,LPCSTR lpType); - WINBASEAPI HRSRC WINAPI FindResourceW(HMODULE hModule,LPCWSTR lpName,LPCWSTR lpType); - WINBASEAPI HRSRC WINAPI FindResourceExA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage); - WINBASEAPI HRSRC WINAPI FindResourceExW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage); - -#ifdef UNICODE -#define ENUMRESTYPEPROC ENUMRESTYPEPROCW -#define ENUMRESNAMEPROC ENUMRESNAMEPROCW -#define ENUMRESLANGPROC ENUMRESLANGPROCW -#define EnumResourceTypes EnumResourceTypesW -#define EnumResourceNames EnumResourceNamesW -#define EnumResourceLanguages EnumResourceLanguagesW -#define BeginUpdateResource BeginUpdateResourceW -#define UpdateResource UpdateResourceW -#define EndUpdateResource EndUpdateResourceW -#define GlobalAddAtom GlobalAddAtomW -#define GlobalFindAtom GlobalFindAtomW -#define GlobalGetAtomName GlobalGetAtomNameW -#define AddAtom AddAtomW -#define FindAtom FindAtomW -#define GetAtomName GetAtomNameW -#define GetProfileInt GetProfileIntW -#define GetProfileString GetProfileStringW -#define WriteProfileString WriteProfileStringW -#define GetProfileSection GetProfileSectionW -#define WriteProfileSection WriteProfileSectionW -#define GetPrivateProfileInt GetPrivateProfileIntW -#define GetPrivateProfileString GetPrivateProfileStringW -#define WritePrivateProfileString WritePrivateProfileStringW -#define GetPrivateProfileSection GetPrivateProfileSectionW -#define WritePrivateProfileSection WritePrivateProfileSectionW -#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesW -#define GetPrivateProfileStruct GetPrivateProfileStructW -#define WritePrivateProfileStruct WritePrivateProfileStructW -#define GetDriveType GetDriveTypeW -#define GetSystemDirectory GetSystemDirectoryW -#define GetTempPath GetTempPathW -#define GetTempFileName GetTempFileNameW -#define GetWindowsDirectory GetWindowsDirectoryW -#define GetSystemWindowsDirectory GetSystemWindowsDirectoryW -#define AddLocalAlternateComputerName AddLocalAlternateComputerNameW -#else -#define ENUMRESTYPEPROC ENUMRESTYPEPROCA -#define ENUMRESNAMEPROC ENUMRESNAMEPROCA -#define ENUMRESLANGPROC ENUMRESLANGPROCA -#define EnumResourceTypes EnumResourceTypesA -#define EnumResourceNames EnumResourceNamesA -#define EnumResourceLanguages EnumResourceLanguagesA -#define BeginUpdateResource BeginUpdateResourceA -#define UpdateResource UpdateResourceA -#define EndUpdateResource EndUpdateResourceA -#define GlobalAddAtom GlobalAddAtomA -#define GlobalFindAtom GlobalFindAtomA -#define GlobalGetAtomName GlobalGetAtomNameA -#define AddAtom AddAtomA -#define FindAtom FindAtomA -#define GetAtomName GetAtomNameA -#define GetProfileInt GetProfileIntA -#define GetProfileString GetProfileStringA -#define WriteProfileString WriteProfileStringA -#define GetProfileSection GetProfileSectionA -#define WriteProfileSection WriteProfileSectionA -#define GetPrivateProfileInt GetPrivateProfileIntA -#define GetPrivateProfileString GetPrivateProfileStringA -#define WritePrivateProfileString WritePrivateProfileStringA -#define GetPrivateProfileSection GetPrivateProfileSectionA -#define WritePrivateProfileSection WritePrivateProfileSectionA -#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesA -#define GetPrivateProfileStruct GetPrivateProfileStructA -#define WritePrivateProfileStruct WritePrivateProfileStructA -#define GetDriveType GetDriveTypeA -#define GetSystemDirectory GetSystemDirectoryA -#define GetTempPath GetTempPathA -#define GetTempFileName GetTempFileNameA -#define GetWindowsDirectory GetWindowsDirectoryA -#define GetSystemWindowsDirectory GetSystemWindowsDirectoryA -#define AddLocalAlternateComputerName AddLocalAlternateComputerNameA -#endif - - typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCA)(HMODULE hModule,LPSTR lpType,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCW)(HMODULE hModule,LPWSTR lpType,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCA)(HMODULE hModule,LPCSTR lpType,LPSTR lpName,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCW)(HMODULE hModule,LPCWSTR lpType,LPWSTR lpName,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESLANGPROCA)(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LONG_PTR lParam); - typedef WINBOOL (CALLBACK *ENUMRESLANGPROCW)(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LONG_PTR lParam); - - WINBASEAPI WINBOOL WINAPI EnumResourceTypesA(HMODULE hModule,ENUMRESTYPEPROCA lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceTypesW(HMODULE hModule,ENUMRESTYPEPROCW lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceNamesA(HMODULE hModule,LPCSTR lpType,ENUMRESNAMEPROCA lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceNamesW(HMODULE hModule,LPCWSTR lpType,ENUMRESNAMEPROCW lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,ENUMRESLANGPROCA lpEnumFunc,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,ENUMRESLANGPROCW lpEnumFunc,LONG_PTR lParam); - WINBASEAPI HANDLE WINAPI BeginUpdateResourceA(LPCSTR pFileName,WINBOOL bDeleteExistingResources); - WINBASEAPI HANDLE WINAPI BeginUpdateResourceW(LPCWSTR pFileName,WINBOOL bDeleteExistingResources); - WINBASEAPI WINBOOL WINAPI UpdateResourceA(HANDLE hUpdate,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); - WINBASEAPI WINBOOL WINAPI UpdateResourceW(HANDLE hUpdate,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); - WINBASEAPI WINBOOL WINAPI EndUpdateResourceA(HANDLE hUpdate,WINBOOL fDiscard); - WINBASEAPI WINBOOL WINAPI EndUpdateResourceW(HANDLE hUpdate,WINBOOL fDiscard); - WINBASEAPI ATOM WINAPI GlobalAddAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI GlobalAddAtomW(LPCWSTR lpString); - WINBASEAPI ATOM WINAPI GlobalFindAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI GlobalFindAtomW(LPCWSTR lpString); - WINBASEAPI UINT WINAPI GlobalGetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); - WINBASEAPI UINT WINAPI GlobalGetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); - WINBASEAPI ATOM WINAPI AddAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI AddAtomW(LPCWSTR lpString); - WINBASEAPI ATOM WINAPI FindAtomA(LPCSTR lpString); - WINBASEAPI ATOM WINAPI FindAtomW(LPCWSTR lpString); - WINBASEAPI UINT WINAPI GetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); - WINBASEAPI UINT WINAPI GetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); - WINBASEAPI UINT WINAPI GetProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault); - WINBASEAPI UINT WINAPI GetProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault); - WINBASEAPI DWORD WINAPI GetProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize); - WINBASEAPI DWORD WINAPI GetProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize); - WINBASEAPI WINBOOL WINAPI WriteProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString); - WINBASEAPI WINBOOL WINAPI WriteProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString); - WINBASEAPI DWORD WINAPI GetProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize); - WINBASEAPI DWORD WINAPI GetProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize); - WINBASEAPI WINBOOL WINAPI WriteProfileSectionA(LPCSTR lpAppName,LPCSTR lpString); - WINBASEAPI WINBOOL WINAPI WriteProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString); - WINBASEAPI UINT WINAPI GetPrivateProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault,LPCSTR lpFileName); - WINBASEAPI UINT WINAPI GetPrivateProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault,LPCWSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString,LPCSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString,LPCWSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionA(LPCSTR lpAppName,LPCSTR lpString,LPCSTR lpFileName); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString,LPCWSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesA(LPSTR lpszReturnBuffer,DWORD nSize,LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesW(LPWSTR lpszReturnBuffer,DWORD nSize,LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); - WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); - WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); - WINBASEAPI UINT WINAPI GetDriveTypeA(LPCSTR lpRootPathName); - WINBASEAPI UINT WINAPI GetDriveTypeW(LPCWSTR lpRootPathName); - WINBASEAPI UINT WINAPI GetSystemDirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemDirectoryW(LPWSTR lpBuffer,UINT uSize); - WINBASEAPI DWORD WINAPI GetTempPathA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetTempPathW(DWORD nBufferLength,LPWSTR lpBuffer); - WINBASEAPI UINT WINAPI GetTempFileNameA(LPCSTR lpPathName,LPCSTR lpPrefixString,UINT uUnique,LPSTR lpTempFileName); - WINBASEAPI UINT WINAPI GetTempFileNameW(LPCWSTR lpPathName,LPCWSTR lpPrefixString,UINT uUnique,LPWSTR lpTempFileName); - WINBASEAPI UINT WINAPI GetWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); - -#ifndef RC_INVOKED -#ifdef UNICODE -#define GetSystemWow64Directory GetSystemWow64DirectoryW -#else -#define GetSystemWow64Directory GetSystemWow64DirectoryA -#endif - - WINBASEAPI UINT WINAPI GetSystemWow64DirectoryA(LPSTR lpBuffer,UINT uSize); - WINBASEAPI UINT WINAPI GetSystemWow64DirectoryW(LPWSTR lpBuffer,UINT uSize); - WINBASEAPI BOOLEAN WINAPI Wow64EnableWow64FsRedirection(BOOLEAN Wow64FsEnableRedirection); - WINBASEAPI WINBOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue); - WINBASEAPI WINBOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OlValue); - - typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_A)(LPSTR lpBuffer,UINT uSize); - typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_W)(LPWSTR lpBuffer,UINT uSize); - -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A "GetSystemWow64DirectoryA" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W L"GetSystemWow64DirectoryA" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T TEXT("GetSystemWow64DirectoryA") -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A "GetSystemWow64DirectoryW" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W L"GetSystemWow64DirectoryW" -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T TEXT("GetSystemWow64DirectoryW") - -#ifdef UNICODE -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T -#else -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W -#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T -#endif -#endif - -#ifdef UNICODE -#define SetCurrentDirectory SetCurrentDirectoryW -#define GetCurrentDirectory GetCurrentDirectoryW -#define SetDllDirectory SetDllDirectoryW -#define GetDllDirectory GetDllDirectoryW -#define GetDiskFreeSpace GetDiskFreeSpaceW -#define GetDiskFreeSpaceEx GetDiskFreeSpaceExW -#define CreateDirectory CreateDirectoryW -#define CreateDirectoryEx CreateDirectoryExW -#define RemoveDirectory RemoveDirectoryW -#define GetFullPathName GetFullPathNameW -#define DefineDosDevice DefineDosDeviceW -#define QueryDosDevice QueryDosDeviceW -#define CreateFile CreateFileW -#define SetFileAttributes SetFileAttributesW -#define GetFileAttributes GetFileAttributesW -#else -#define SetCurrentDirectory SetCurrentDirectoryA -#define GetCurrentDirectory GetCurrentDirectoryA -#define SetDllDirectory SetDllDirectoryA -#define GetDllDirectory GetDllDirectoryA -#define GetDiskFreeSpace GetDiskFreeSpaceA -#define GetDiskFreeSpaceEx GetDiskFreeSpaceExA -#define CreateDirectory CreateDirectoryA -#define CreateDirectoryEx CreateDirectoryExA -#define RemoveDirectory RemoveDirectoryA -#define GetFullPathName GetFullPathNameA -#define DefineDosDevice DefineDosDeviceA -#define QueryDosDevice QueryDosDeviceA -#define CreateFile CreateFileA -#define SetFileAttributes SetFileAttributesA -#define GetFileAttributes GetFileAttributesA -#endif - - WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryA(LPCSTR lpPathName); - WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryW(LPCWSTR lpPathName); - WINBASEAPI DWORD WINAPI GetCurrentDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetCurrentDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI SetDllDirectoryA(LPCSTR lpPathName); - WINBASEAPI WINBOOL WINAPI SetDllDirectoryW(LPCWSTR lpPathName); - WINBASEAPI DWORD WINAPI GetDllDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); - WINBASEAPI DWORD WINAPI GetDllDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceA(LPCSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceW(LPCWSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExA(LPCSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); - WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExW(LPCWSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryA(LPCSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryW(LPCWSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryExA(LPCSTR lpTemplateDirectory,LPCSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateDirectoryExW(LPCWSTR lpTemplateDirectory,LPCWSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI RemoveDirectoryA(LPCSTR lpPathName); - WINBASEAPI WINBOOL WINAPI RemoveDirectoryW(LPCWSTR lpPathName); - WINBASEAPI DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); - WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); - -#define DDD_RAW_TARGET_PATH 0x1 -#define DDD_REMOVE_DEFINITION 0x2 -#define DDD_EXACT_MATCH_ON_REMOVE 0x4 -#define DDD_NO_BROADCAST_SYSTEM 0x8 -#define DDD_LUID_BROADCAST_DRIVE 0x10 - - WINBASEAPI WINBOOL WINAPI DefineDosDeviceA(DWORD dwFlags,LPCSTR lpDeviceName,LPCSTR lpTargetPath); - WINBASEAPI WINBOOL WINAPI DefineDosDeviceW(DWORD dwFlags,LPCWSTR lpDeviceName,LPCWSTR lpTargetPath); - WINBASEAPI DWORD WINAPI QueryDosDeviceA(LPCSTR lpDeviceName,LPSTR lpTargetPath,DWORD ucchMax); - WINBASEAPI DWORD WINAPI QueryDosDeviceW(LPCWSTR lpDeviceName,LPWSTR lpTargetPath,DWORD ucchMax); - -#define EXPAND_LOCAL_DRIVES - - WINBASEAPI HANDLE WINAPI CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); - WINBASEAPI HANDLE WINAPI CreateFileW(LPCWSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); - WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE hOriginalFile,DWORD dwDesiredAccess,DWORD dwShareMode,DWORD dwFlagsAndAttributes); - WINBASEAPI WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName,DWORD dwFileAttributes); - WINBASEAPI WINBOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName,DWORD dwFileAttributes); - WINBASEAPI DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName); - WINBASEAPI DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName); - - typedef enum _GET_FILEEX_INFO_LEVELS { - GetFileExInfoStandard,GetFileExMaxInfoLevel - } GET_FILEEX_INFO_LEVELS; - -#ifdef UNICODE -#define GetFileAttributesEx GetFileAttributesExW -#define GetCompressedFileSize GetCompressedFileSizeW -#define DeleteFile DeleteFileW -#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3W -#else -#define GetFileAttributesEx GetFileAttributesExA -#define GetCompressedFileSize GetCompressedFileSizeA -#define DeleteFile DeleteFileA -#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3A -#endif - - WINBASEAPI WINBOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); - WINBASEAPI WINBOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); - WINBASEAPI DWORD WINAPI GetCompressedFileSizeA(LPCSTR lpFileName,LPDWORD lpFileSizeHigh); - WINBASEAPI DWORD WINAPI GetCompressedFileSizeW(LPCWSTR lpFileName,LPDWORD lpFileSizeHigh); - WINBASEAPI WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName); - WINBASEAPI WINBOOL WINAPI DeleteFileW(LPCWSTR lpFileName); - WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3A(LPCSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); - WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3W(LPCWSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); - - typedef enum _FINDEX_INFO_LEVELS { - FindExInfoStandard,FindExInfoMaxInfoLevel - } FINDEX_INFO_LEVELS; - - typedef enum _FINDEX_SEARCH_OPS { - FindExSearchNameMatch,FindExSearchLimitToDirectories,FindExSearchLimitToDevices,FindExSearchMaxSearchOp - } FINDEX_SEARCH_OPS; - -#define FIND_FIRST_EX_CASE_SENSITIVE 0x1 - -#ifdef UNICODE -#define FindFirstFileEx FindFirstFileExW -#define FindFirstFile FindFirstFileW -#define FindNextFile FindNextFileW -#define SearchPath SearchPathW -#define CopyFile CopyFileW -#define CopyFileEx CopyFileExW -#define MoveFile MoveFileW -#define MoveFileEx MoveFileExW -#define MoveFileWithProgress MoveFileWithProgressW -#define ReplaceFile ReplaceFileW -#define CreateHardLink CreateHardLinkW -#define CreateNamedPipe CreateNamedPipeW -#define GetNamedPipeHandleState GetNamedPipeHandleStateW -#define CallNamedPipe CallNamedPipeW -#define WaitNamedPipe WaitNamedPipeW -#define SetVolumeLabel SetVolumeLabelW -#define GetVolumeInformation GetVolumeInformationW -#define ClearEventLog ClearEventLogW -#define BackupEventLog BackupEventLogW -#define OpenEventLog OpenEventLogW -#define RegisterEventSource RegisterEventSourceW -#define OpenBackupEventLog OpenBackupEventLogW -#define ReadEventLog ReadEventLogW -#define ReportEvent ReportEventW -#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmW -#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmW -#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmW -#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleW -#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmW -#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmW -#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmW -#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmW -#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmW -#define SetFileSecurity SetFileSecurityW -#define GetFileSecurity GetFileSecurityW -#define FindFirstChangeNotification FindFirstChangeNotificationW -#define IsBadStringPtr IsBadStringPtrW -#define LookupAccountSid LookupAccountSidW -#define LookupAccountName LookupAccountNameW -#define LookupPrivilegeValue LookupPrivilegeValueW -#define LookupPrivilegeName LookupPrivilegeNameW -#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameW -#define BuildCommDCB BuildCommDCBW -#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW -#define CommConfigDialog CommConfigDialogW -#define GetDefaultCommConfig GetDefaultCommConfigW -#define SetDefaultCommConfig SetDefaultCommConfigW -#define GetComputerName GetComputerNameW -#define SetComputerName SetComputerNameW -#define GetComputerNameEx GetComputerNameExW -#define SetComputerNameEx SetComputerNameExW -#define DnsHostnameToComputerName DnsHostnameToComputerNameW -#define GetUserName GetUserNameW -#else -#define FindFirstFileEx FindFirstFileExA -#define FindFirstFile FindFirstFileA -#define FindNextFile FindNextFileA -#define SearchPath SearchPathA -#define CopyFile CopyFileA -#define CopyFileEx CopyFileExA -#define MoveFile MoveFileA -#define MoveFileEx MoveFileExA -#define MoveFileWithProgress MoveFileWithProgressA -#define ReplaceFile ReplaceFileA -#define CreateHardLink CreateHardLinkA -#define CreateNamedPipe CreateNamedPipeA -#define GetNamedPipeHandleState GetNamedPipeHandleStateA -#define CallNamedPipe CallNamedPipeA -#define WaitNamedPipe WaitNamedPipeA -#define SetVolumeLabel SetVolumeLabelA -#define GetVolumeInformation GetVolumeInformationA -#define ClearEventLog ClearEventLogA -#define BackupEventLog BackupEventLogA -#define OpenEventLog OpenEventLogA -#define RegisterEventSource RegisterEventSourceA -#define OpenBackupEventLog OpenBackupEventLogA -#define ReadEventLog ReadEventLogA -#define ReportEvent ReportEventA -#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmA -#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmA -#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmA -#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleA -#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmA -#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmA -#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmA -#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmA -#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmA -#define SetFileSecurity SetFileSecurityA -#define GetFileSecurity GetFileSecurityA -#define FindFirstChangeNotification FindFirstChangeNotificationA -#define IsBadStringPtr IsBadStringPtrA -#define LookupAccountSid LookupAccountSidA -#define LookupAccountName LookupAccountNameA -#define LookupPrivilegeValue LookupPrivilegeValueA -#define LookupPrivilegeName LookupPrivilegeNameA -#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameA -#define BuildCommDCB BuildCommDCBA -#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA -#define CommConfigDialog CommConfigDialogA -#define GetDefaultCommConfig GetDefaultCommConfigA -#define SetDefaultCommConfig SetDefaultCommConfigA -#define GetComputerName GetComputerNameA -#define SetComputerName SetComputerNameA -#define GetComputerNameEx GetComputerNameExA -#define SetComputerNameEx SetComputerNameExA -#define DnsHostnameToComputerName DnsHostnameToComputerNameA -#define GetUserName GetUserNameA -#endif - - WINBASEAPI HANDLE WINAPI FindFirstFileExA(LPCSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); - WINBASEAPI HANDLE WINAPI FindFirstFileExW(LPCWSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); - WINBASEAPI HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName,LPWIN32_FIND_DATAA lpFindFileData); - WINBASEAPI HANDLE WINAPI FindFirstFileW(LPCWSTR lpFileName,LPWIN32_FIND_DATAW lpFindFileData); - WINBASEAPI WINBOOL WINAPI FindNextFileA(HANDLE hFindFile,LPWIN32_FIND_DATAA lpFindFileData); - WINBASEAPI WINBOOL WINAPI FindNextFileW(HANDLE hFindFile,LPWIN32_FIND_DATAW lpFindFileData); - WINBASEAPI DWORD WINAPI SearchPathA(LPCSTR lpPath,LPCSTR lpFileName,LPCSTR lpExtension,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); - WINBASEAPI DWORD WINAPI SearchPathW(LPCWSTR lpPath,LPCWSTR lpFileName,LPCWSTR lpExtension,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); - WINBASEAPI WINBOOL WINAPI CopyFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,WINBOOL bFailIfExists); - WINBASEAPI WINBOOL WINAPI CopyFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,WINBOOL bFailIfExists); - - typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER TotalFileSize,LARGE_INTEGER TotalBytesTransferred,LARGE_INTEGER StreamSize,LARGE_INTEGER StreamBytesTransferred,DWORD dwStreamNumber,DWORD dwCallbackReason,HANDLE hSourceFile,HANDLE hDestinationFile,LPVOID lpData); - - WINBASEAPI WINBOOL WINAPI CopyFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); - WINBASEAPI WINBOOL WINAPI CopyFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); - WINBASEAPI WINBOOL WINAPI MoveFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName); - WINBASEAPI WINBOOL WINAPI MoveFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName); - WINBASEAPI WINBOOL WINAPI MoveFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI MoveFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI MoveFileWithProgressA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI MoveFileWithProgressW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); - -#define MOVEFILE_REPLACE_EXISTING 0x1 -#define MOVEFILE_COPY_ALLOWED 0x2 -#define MOVEFILE_DELAY_UNTIL_REBOOT 0x4 -#define MOVEFILE_WRITE_THROUGH 0x8 -#define MOVEFILE_CREATE_HARDLINK 0x10 -#define MOVEFILE_FAIL_IF_NOT_TRACKABLE 0x20 - - WINBASEAPI WINBOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,LPCSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,LPCWSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI CreateHardLinkA(LPCSTR lpFileName,LPCSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI CreateHardLinkW(LPCWSTR lpFileName,LPCWSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - - typedef enum _STREAM_INFO_LEVELS { - FindStreamInfoStandard,FindStreamInfoMaxInfoLevel - } STREAM_INFO_LEVELS; - - typedef struct _WIN32_FIND_STREAM_DATA { - LARGE_INTEGER StreamSize; - WCHAR cStreamName[MAX_PATH + 36]; - } WIN32_FIND_STREAM_DATA,*PWIN32_FIND_STREAM_DATA; - - HANDLE WINAPI FindFirstStreamW(LPCWSTR lpFileName,STREAM_INFO_LEVELS InfoLevel,LPVOID lpFindStreamData,DWORD dwFlags); - WINBOOL WINAPI FindNextStreamW(HANDLE hFindStream,LPVOID lpFindStreamData); - WINBASEAPI HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI HANDLE WINAPI CreateNamedPipeW(LPCWSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateA(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPSTR lpUserName,DWORD nMaxUserNameSize); - WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateW(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPWSTR lpUserName,DWORD nMaxUserNameSize); - WINBASEAPI WINBOOL WINAPI CallNamedPipeA(LPCSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI CallNamedPipeW(LPCWSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI WaitNamedPipeA(LPCSTR lpNamedPipeName,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI WaitNamedPipeW(LPCWSTR lpNamedPipeName,DWORD nTimeOut); - WINBASEAPI WINBOOL WINAPI SetVolumeLabelA(LPCSTR lpRootPathName,LPCSTR lpVolumeName); - WINBASEAPI WINBOOL WINAPI SetVolumeLabelW(LPCWSTR lpRootPathName,LPCWSTR lpVolumeName); - WINBASEAPI VOID WINAPI SetFileApisToOEM(VOID); - WINBASEAPI VOID WINAPI SetFileApisToANSI(VOID); - WINBASEAPI WINBOOL WINAPI AreFileApisANSI(VOID); - WINBASEAPI WINBOOL WINAPI GetVolumeInformationA(LPCSTR lpRootPathName,LPSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); - WINBASEAPI WINBOOL WINAPI GetVolumeInformationW(LPCWSTR lpRootPathName,LPWSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPWSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); - WINBASEAPI WINBOOL WINAPI CancelIo(HANDLE hFile); - WINADVAPI WINBOOL WINAPI ClearEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI ClearEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI BackupEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI BackupEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); - WINADVAPI WINBOOL WINAPI CloseEventLog(HANDLE hEventLog); - WINADVAPI WINBOOL WINAPI DeregisterEventSource(HANDLE hEventLog); - WINADVAPI WINBOOL WINAPI NotifyChangeEventLog(HANDLE hEventLog,HANDLE hEvent); - WINADVAPI WINBOOL WINAPI GetNumberOfEventLogRecords(HANDLE hEventLog,PDWORD NumberOfRecords); - WINADVAPI WINBOOL WINAPI GetOldestEventLogRecord(HANDLE hEventLog,PDWORD OldestRecord); - WINADVAPI HANDLE WINAPI OpenEventLogA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); - WINADVAPI HANDLE WINAPI OpenEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); - WINADVAPI HANDLE WINAPI RegisterEventSourceA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); - WINADVAPI HANDLE WINAPI RegisterEventSourceW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); - WINADVAPI HANDLE WINAPI OpenBackupEventLogA(LPCSTR lpUNCServerName,LPCSTR lpFileName); - WINADVAPI HANDLE WINAPI OpenBackupEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpFileName); - WINADVAPI WINBOOL WINAPI ReadEventLogA(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); - WINADVAPI WINBOOL WINAPI ReadEventLogW(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); - WINADVAPI WINBOOL WINAPI ReportEventA(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCSTR *lpStrings,LPVOID lpRawData); - WINADVAPI WINBOOL WINAPI ReportEventW(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCWSTR *lpStrings,LPVOID lpRawData); - -#define EVENTLOG_FULL_INFO 0 - - typedef struct _EVENTLOG_FULL_INFORMATION { - DWORD dwFull; - } EVENTLOG_FULL_INFORMATION,*LPEVENTLOG_FULL_INFORMATION; - - WINADVAPI WINBOOL WINAPI GetEventLogInformation(HANDLE hEventLog,DWORD dwInfoLevel,LPVOID lpBuffer,DWORD cbBufSize,LPDWORD pcbBytesNeeded); - WINADVAPI WINBOOL WINAPI DuplicateToken(HANDLE ExistingTokenHandle,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,PHANDLE DuplicateTokenHandle); - WINADVAPI WINBOOL WINAPI GetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); - WINADVAPI WINBOOL WINAPI ImpersonateNamedPipeClient(HANDLE hNamedPipe); - WINADVAPI WINBOOL WINAPI ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel); - WINADVAPI WINBOOL WINAPI RevertToSelf(VOID); - WINADVAPI WINBOOL WINAPI SetThreadToken (PHANDLE Thread,HANDLE Token); - WINADVAPI WINBOOL WINAPI AccessCheck(PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); - WINADVAPI WINBOOL WINAPI AccessCheckByType(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultList(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccessList,LPDWORD AccessStatusList); - WINADVAPI WINBOOL WINAPI OpenProcessToken(HANDLE ProcessHandle,DWORD DesiredAccess,PHANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI OpenThreadToken(HANDLE ThreadHandle,DWORD DesiredAccess,WINBOOL OpenAsSelf,PHANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI GetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI SetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength); - WINADVAPI WINBOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle,WINBOOL DisableAllPrivileges,PTOKEN_PRIVILEGES NewState,DWORD BufferLength,PTOKEN_PRIVILEGES PreviousState,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI AdjustTokenGroups(HANDLE TokenHandle,WINBOOL ResetToDefault,PTOKEN_GROUPS NewState,DWORD BufferLength,PTOKEN_GROUPS PreviousState,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI PrivilegeCheck(HANDLE ClientToken,PPRIVILEGE_SET RequiredPrivileges,LPBOOL pfResult); - WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); - WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmA(LPCSTR SubsystemName,LPCSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmW(LPCWSTR SubsystemName,LPCWSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); - WINADVAPI WINBOOL WINAPI IsWellKnownSid(PSID pSid,WELL_KNOWN_SID_TYPE WellKnownSidType); - WINADVAPI WINBOOL WINAPI CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType,PSID DomainSid,PSID pSid,DWORD *cbSid); - WINADVAPI WINBOOL WINAPI EqualDomainSid(PSID pSid1,PSID pSid2,WINBOOL *pfEqual); - WINADVAPI WINBOOL WINAPI GetWindowsAccountDomainSid(PSID pSid,PSID pDomainSid,DWORD *cbDomainSid); - WINADVAPI WINBOOL WINAPI IsValidSid(PSID pSid); - WINADVAPI WINBOOL WINAPI EqualSid(PSID pSid1,PSID pSid2); - WINADVAPI WINBOOL WINAPI EqualPrefixSid(PSID pSid1,PSID pSid2); - WINADVAPI DWORD WINAPI GetSidLengthRequired (UCHAR nSubAuthorityCount); - WINADVAPI WINBOOL WINAPI AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount,DWORD nSubAuthority0,DWORD nSubAuthority1,DWORD nSubAuthority2,DWORD nSubAuthority3,DWORD nSubAuthority4,DWORD nSubAuthority5,DWORD nSubAuthority6,DWORD nSubAuthority7,PSID *pSid); - WINADVAPI PVOID WINAPI FreeSid(PSID pSid); - WINADVAPI WINBOOL WINAPI InitializeSid(PSID Sid,PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount); - WINADVAPI PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid); - WINADVAPI PDWORD WINAPI GetSidSubAuthority(PSID pSid,DWORD nSubAuthority); - WINADVAPI PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid); - WINADVAPI DWORD WINAPI GetLengthSid(PSID pSid); - WINADVAPI WINBOOL WINAPI CopySid(DWORD nDestinationSidLength,PSID pDestinationSid,PSID pSourceSid); - WINADVAPI WINBOOL WINAPI AreAllAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); - WINADVAPI WINBOOL WINAPI AreAnyAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); - WINADVAPI VOID WINAPI MapGenericMask(PDWORD AccessMask,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI IsValidAcl(PACL pAcl); - WINADVAPI WINBOOL WINAPI InitializeAcl(PACL pAcl,DWORD nAclLength,DWORD dwAclRevision); - WINADVAPI WINBOOL WINAPI GetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); - WINADVAPI WINBOOL WINAPI SetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); - WINADVAPI WINBOOL WINAPI AddAce(PACL pAcl,DWORD dwAceRevision,DWORD dwStartingAceIndex,LPVOID pAceList,DWORD nAceListLength); - WINADVAPI WINBOOL WINAPI DeleteAce(PACL pAcl,DWORD dwAceIndex); - WINADVAPI WINBOOL WINAPI GetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce); - WINADVAPI WINBOOL WINAPI AddAccessAllowedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessAllowedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessDeniedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessDeniedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAuditAccessAce(PACL pAcl,DWORD dwAceRevision,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); - WINADVAPI WINBOOL WINAPI AddAuditAccessAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); - WINADVAPI WINBOOL WINAPI AddAccessAllowedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAccessDeniedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); - WINADVAPI WINBOOL WINAPI AddAuditAccessObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); - WINADVAPI WINBOOL WINAPI FindFirstFreeAce(PACL pAcl,LPVOID *pAce); - WINADVAPI WINBOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD dwRevision); - WINADVAPI WINBOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI DWORD WINAPI GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSECURITY_DESCRIPTOR_CONTROL pControl,LPDWORD lpdwRevision); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bDaclPresent,PACL pDacl,WINBOOL bDaclDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbDaclPresent,PACL *pDacl,LPBOOL lpbDaclDefaulted); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bSaclPresent,PACL pSacl,WINBOOL bSaclDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbSaclPresent,PACL *pSacl,LPBOOL lpbSaclDefaulted); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pOwner,WINBOOL bOwnerDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pOwner,LPBOOL lpbOwnerDefaulted); - WINADVAPI WINBOOL WINAPI SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pGroup,WINBOOL bGroupDefaulted); - WINADVAPI WINBOOL WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pGroup,LPBOOL lpbGroupDefaulted); - WINADVAPI DWORD WINAPI SetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); - WINADVAPI DWORD WINAPI GetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); - WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,WINBOOL IsDirectoryObject,HANDLE Token,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI ConvertToAutoInheritPrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CurrentSecurityDescriptor,PSECURITY_DESCRIPTOR *NewSecurityDescriptor,GUID *ObjectType,BOOLEAN IsDirectoryObject,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityEx(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID *ObjectType,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityWithMultipleInheritance(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID **ObjectTypes,ULONG GuidCount,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); - WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurity (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,PGENERIC_MAPPING GenericMapping,HANDLE Token); - WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurityEx (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,ULONG AutoInheritFlags,PGENERIC_MAPPING GenericMapping,HANDLE Token); - WINADVAPI WINBOOL WINAPI GetPrivateObjectSecurity(PSECURITY_DESCRIPTOR ObjectDescriptor,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ResultantDescriptor,DWORD DescriptorLength,PDWORD ReturnLength); - WINADVAPI WINBOOL WINAPI DestroyPrivateObjectSecurity(PSECURITY_DESCRIPTOR *ObjectDescriptor); - WINADVAPI WINBOOL WINAPI MakeSelfRelativeSD(PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferLength); - WINADVAPI WINBOOL WINAPI MakeAbsoluteSD(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,LPDWORD lpdwAbsoluteSecurityDescriptorSize,PACL pDacl,LPDWORD lpdwDaclSize,PACL pSacl,LPDWORD lpdwSaclSize,PSID pOwner,LPDWORD lpdwOwnerSize,PSID pPrimaryGroup,LPDWORD lpdwPrimaryGroupSize); - WINADVAPI WINBOOL WINAPI MakeAbsoluteSD2(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferSize); - WINADVAPI WINBOOL WINAPI SetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI WINBOOL WINAPI SetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI WINBOOL WINAPI GetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); - WINADVAPI WINBOOL WINAPI GetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); - WINADVAPI WINBOOL WINAPI SetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR SecurityDescriptor); - WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationA(LPCSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); - WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationW(LPCWSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); - WINBASEAPI WINBOOL WINAPI FindNextChangeNotification(HANDLE hChangeHandle); - WINBASEAPI WINBOOL WINAPI FindCloseChangeNotification(HANDLE hChangeHandle); - WINBASEAPI WINBOOL WINAPI ReadDirectoryChangesW(HANDLE hDirectory,LPVOID lpBuffer,DWORD nBufferLength,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINBASEAPI WINBOOL WINAPI VirtualLock(LPVOID lpAddress,SIZE_T dwSize); - WINBASEAPI WINBOOL WINAPI VirtualUnlock(LPVOID lpAddress,SIZE_T dwSize); - WINBASEAPI LPVOID WINAPI MapViewOfFileEx(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap,LPVOID lpBaseAddress); - WINBASEAPI WINBOOL WINAPI SetPriorityClass(HANDLE hProcess,DWORD dwPriorityClass); - WINBASEAPI DWORD WINAPI GetPriorityClass(HANDLE hProcess); - WINBASEAPI WINBOOL WINAPI IsBadReadPtr(CONST VOID *lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadWritePtr(LPVOID lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadHugeReadPtr(CONST VOID *lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadHugeWritePtr(LPVOID lp,UINT_PTR ucb); - WINBASEAPI WINBOOL WINAPI IsBadCodePtr(FARPROC lpfn); - WINBASEAPI WINBOOL WINAPI IsBadStringPtrA(LPCSTR lpsz,UINT_PTR ucchMax); - WINBASEAPI WINBOOL WINAPI IsBadStringPtrW(LPCWSTR lpsz,UINT_PTR ucchMax); - WINADVAPI WINBOOL WINAPI LookupAccountSidA(LPCSTR lpSystemName,PSID Sid,LPSTR Name,LPDWORD cchName,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName,PSID Sid,LPWSTR Name,LPDWORD cchName,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupAccountNameA(LPCSTR lpSystemName,LPCSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupAccountNameW(LPCWSTR lpSystemName,LPCWSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); - WINADVAPI WINBOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName,LPCSTR lpName,PLUID lpLuid); - WINADVAPI WINBOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName,LPCWSTR lpName,PLUID lpLuid); - WINADVAPI WINBOOL WINAPI LookupPrivilegeNameA(LPCSTR lpSystemName,PLUID lpLuid,LPSTR lpName,LPDWORD cchName); - WINADVAPI WINBOOL WINAPI LookupPrivilegeNameW(LPCWSTR lpSystemName,PLUID lpLuid,LPWSTR lpName,LPDWORD cchName); - WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameA(LPCSTR lpSystemName,LPCSTR lpName,LPSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); - WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameW(LPCWSTR lpSystemName,LPCWSTR lpName,LPWSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); - WINADVAPI WINBOOL WINAPI AllocateLocallyUniqueId(PLUID Luid); - WINBASEAPI WINBOOL WINAPI BuildCommDCBA(LPCSTR lpDef,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI BuildCommDCBW(LPCWSTR lpDef,LPDCB lpDCB); - WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsW(LPCWSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); - WINBASEAPI WINBOOL WINAPI CommConfigDialogA(LPCSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); - WINBASEAPI WINBOOL WINAPI CommConfigDialogW(LPCWSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); - WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); - WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); - WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); - WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); - -#define MAX_COMPUTERNAME_LENGTH 15 - - WINBASEAPI WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI GetComputerNameW(LPWSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI SetComputerNameA(LPCSTR lpComputerName); - WINBASEAPI WINBOOL WINAPI SetComputerNameW(LPCWSTR lpComputerName); - - typedef enum _COMPUTER_NAME_FORMAT { - ComputerNameNetBIOS,ComputerNameDnsHostname,ComputerNameDnsDomain,ComputerNameDnsFullyQualified,ComputerNamePhysicalNetBIOS,ComputerNamePhysicalDnsHostname,ComputerNamePhysicalDnsDomain,ComputerNamePhysicalDnsFullyQualified,ComputerNameMax - } COMPUTER_NAME_FORMAT; - - WINBASEAPI WINBOOL WINAPI GetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI GetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPWSTR lpBuffer,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI SetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPCSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI SetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPCWSTR lpBuffer); - WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameA(LPCSTR Hostname,LPSTR ComputerName,LPDWORD nSize); - WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameW(LPCWSTR Hostname,LPWSTR ComputerName,LPDWORD nSize); - WINADVAPI WINBOOL WINAPI GetUserNameA(LPSTR lpBuffer,LPDWORD pcbBuffer); - WINADVAPI WINBOOL WINAPI GetUserNameW(LPWSTR lpBuffer,LPDWORD pcbBuffer); - -#define LOGON32_LOGON_INTERACTIVE 2 -#define LOGON32_LOGON_NETWORK 3 -#define LOGON32_LOGON_BATCH 4 -#define LOGON32_LOGON_SERVICE 5 -#define LOGON32_LOGON_UNLOCK 7 -#define LOGON32_LOGON_NETWORK_CLEARTEXT 8 -#define LOGON32_LOGON_NEW_CREDENTIALS 9 - -#define LOGON32_PROVIDER_DEFAULT 0 -#define LOGON32_PROVIDER_WINNT35 1 -#define LOGON32_PROVIDER_WINNT40 2 -#define LOGON32_PROVIDER_WINNT50 3 - -#ifdef UNICODE -#define LogonUser LogonUserW -#define LogonUserEx LogonUserExW -#define CreateProcessAsUser CreateProcessAsUserW -#else -#define LogonUser LogonUserA -#define LogonUserEx LogonUserExA -#define CreateProcessAsUser CreateProcessAsUserA -#endif - - WINADVAPI WINBOOL WINAPI LogonUserA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); - WINADVAPI WINBOOL WINAPI LogonUserW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); - WINADVAPI WINBOOL WINAPI LogonUserExA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); - WINADVAPI WINBOOL WINAPI LogonUserExW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); - WINADVAPI WINBOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken); - WINADVAPI WINBOOL WINAPI CreateProcessAsUserA(HANDLE hToken,LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINADVAPI WINBOOL WINAPI CreateProcessAsUserW(HANDLE hToken,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - -#define LOGON_WITH_PROFILE 0x1 -#define LOGON_NETCREDENTIALS_ONLY 0x2 -#define LOGON_ZERO_PASSWORD_BUFFER 0x80000000 - - WINADVAPI WINBOOL WINAPI CreateProcessWithLogonW(LPCWSTR lpUsername,LPCWSTR lpDomain,LPCWSTR lpPassword,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINADVAPI WINBOOL WINAPI CreateProcessWithTokenW(HANDLE hToken,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); - WINADVAPI WINBOOL WINAPI ImpersonateAnonymousToken(HANDLE ThreadHandle); - WINADVAPI WINBOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken,DWORD dwDesiredAccess,LPSECURITY_ATTRIBUTES lpTokenAttributes,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,TOKEN_TYPE TokenType,PHANDLE phNewToken); - WINADVAPI WINBOOL WINAPI CreateRestrictedToken(HANDLE ExistingTokenHandle,DWORD Flags,DWORD DisableSidCount,PSID_AND_ATTRIBUTES SidsToDisable,DWORD DeletePrivilegeCount,PLUID_AND_ATTRIBUTES PrivilegesToDelete,DWORD RestrictedSidCount,PSID_AND_ATTRIBUTES SidsToRestrict,PHANDLE NewTokenHandle); - WINADVAPI WINBOOL WINAPI IsTokenRestricted(HANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI IsTokenUntrusted(HANDLE TokenHandle); - WINADVAPI WINBOOL WINAPI CheckTokenMembership(HANDLE TokenHandle,PSID SidToCheck,PBOOL IsMember); - - typedef WAITORTIMERCALLBACKFUNC WAITORTIMERCALLBACK; - - WINBASEAPI WINBOOL WINAPI RegisterWaitForSingleObject(PHANDLE phNewWaitObject,HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); - WINBASEAPI HANDLE WINAPI RegisterWaitForSingleObjectEx(HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); - WINBASEAPI WINBOOL WINAPI UnregisterWait(HANDLE WaitHandle); - WINBASEAPI WINBOOL WINAPI UnregisterWaitEx(HANDLE WaitHandle,HANDLE CompletionEvent); - WINBASEAPI WINBOOL WINAPI QueueUserWorkItem(LPTHREAD_START_ROUTINE Function,PVOID Context,ULONG Flags); - WINBASEAPI WINBOOL WINAPI BindIoCompletionCallback(HANDLE FileHandle,LPOVERLAPPED_COMPLETION_ROUTINE Function,ULONG Flags); - WINBASEAPI HANDLE WINAPI CreateTimerQueue(VOID); - WINBASEAPI WINBOOL WINAPI CreateTimerQueueTimer(PHANDLE phNewTimer,HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,ULONG Flags); - WINBASEAPI WINBOOL WINAPI ChangeTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,ULONG DueTime,ULONG Period); - WINBASEAPI WINBOOL WINAPI DeleteTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,HANDLE CompletionEvent); - WINBASEAPI WINBOOL WINAPI DeleteTimerQueueEx(HANDLE TimerQueue,HANDLE CompletionEvent); - WINBASEAPI HANDLE WINAPI SetTimerQueueTimer(HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,WINBOOL PreferIo); - WINBASEAPI WINBOOL WINAPI CancelTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer); - WINBASEAPI WINBOOL WINAPI DeleteTimerQueue(HANDLE TimerQueue); - -#define HW_PROFILE_GUIDLEN 39 -#define MAX_PROFILE_LEN 80 - -#define DOCKINFO_UNDOCKED (0x1) -#define DOCKINFO_DOCKED (0x2) -#define DOCKINFO_USER_SUPPLIED (0x4) -#define DOCKINFO_USER_UNDOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_UNDOCKED) -#define DOCKINFO_USER_DOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_DOCKED) - - typedef struct tagHW_PROFILE_INFOA { - DWORD dwDockInfo; - CHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; - CHAR szHwProfileName[MAX_PROFILE_LEN]; - } HW_PROFILE_INFOA,*LPHW_PROFILE_INFOA; - - typedef struct tagHW_PROFILE_INFOW { - DWORD dwDockInfo; - WCHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; - WCHAR szHwProfileName[MAX_PROFILE_LEN]; - } HW_PROFILE_INFOW,*LPHW_PROFILE_INFOW; - -#ifdef UNICODE - typedef HW_PROFILE_INFOW HW_PROFILE_INFO; - typedef LPHW_PROFILE_INFOW LPHW_PROFILE_INFO; -#else - typedef HW_PROFILE_INFOA HW_PROFILE_INFO; - typedef LPHW_PROFILE_INFOA LPHW_PROFILE_INFO; -#endif - -#ifdef UNICODE -#define GetCurrentHwProfile GetCurrentHwProfileW -#define GetVersionEx GetVersionExW -#define VerifyVersionInfo VerifyVersionInfoW -#else -#define GetCurrentHwProfile GetCurrentHwProfileA -#define GetVersionEx GetVersionExA -#define VerifyVersionInfo VerifyVersionInfoA -#endif - - WINADVAPI WINBOOL WINAPI GetCurrentHwProfileA (LPHW_PROFILE_INFOA lpHwProfileInfo); - WINADVAPI WINBOOL WINAPI GetCurrentHwProfileW (LPHW_PROFILE_INFOW lpHwProfileInfo); - WINBASEAPI WINBOOL WINAPI QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); - WINBASEAPI WINBOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); - WINBASEAPI WINBOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation); - WINBASEAPI WINBOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation); - WINBASEAPI WINBOOL WINAPI VerifyVersionInfoA(LPOSVERSIONINFOEXA lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); - WINBASEAPI WINBOOL WINAPI VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); - -#include - -#define TC_NORMAL 0 -#define TC_HARDERR 1 -#define TC_GP_TRAP 2 -#define TC_SIGNAL 3 - -#define AC_LINE_OFFLINE 0x0 -#define AC_LINE_ONLINE 0x1 -#define AC_LINE_BACKUP_POWER 0x2 -#define AC_LINE_UNKNOWN 0xff - -#define BATTERY_FLAG_HIGH 0x1 -#define BATTERY_FLAG_LOW 0x2 -#define BATTERY_FLAG_CRITICAL 0x4 -#define BATTERY_FLAG_CHARGING 0x8 -#define BATTERY_FLAG_NO_BATTERY 0x80 -#define BATTERY_FLAG_UNKNOWN 0xff - -#define BATTERY_PERCENTAGE_UNKNOWN 0xff - -#define BATTERY_LIFE_UNKNOWN 0xffffffff - - typedef struct _SYSTEM_POWER_STATUS { - BYTE ACLineStatus; - BYTE BatteryFlag; - BYTE BatteryLifePercent; - BYTE Reserved1; - DWORD BatteryLifeTime; - DWORD BatteryFullLifeTime; - } SYSTEM_POWER_STATUS,*LPSYSTEM_POWER_STATUS; - -#ifdef UNICODE -#define CreateJobObject CreateJobObjectW -#define OpenJobObject OpenJobObjectW -#define FindFirstVolume FindFirstVolumeW -#define FindNextVolume FindNextVolumeW -#define FindFirstVolumeMountPoint FindFirstVolumeMountPointW -#define FindNextVolumeMountPoint FindNextVolumeMountPointW -#define SetVolumeMountPoint SetVolumeMountPointW -#define DeleteVolumeMountPoint DeleteVolumeMountPointW -#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointW -#define GetVolumePathName GetVolumePathNameW -#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameW -#else -#define CreateJobObject CreateJobObjectA -#define OpenJobObject OpenJobObjectA -#define FindFirstVolume FindFirstVolumeA -#define FindNextVolume FindNextVolumeA -#define FindFirstVolumeMountPoint FindFirstVolumeMountPointA -#define FindNextVolumeMountPoint FindNextVolumeMountPointA -#define SetVolumeMountPoint SetVolumeMountPointA -#define DeleteVolumeMountPoint DeleteVolumeMountPointA -#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointA -#define GetVolumePathName GetVolumePathNameA -#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameA -#endif - - WINBOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS lpSystemPowerStatus); - WINBOOL WINAPI SetSystemPowerState(WINBOOL fSuspend,WINBOOL fForce); - WINBASEAPI WINBOOL WINAPI AllocateUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI WINBOOL WINAPI FreeUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI WINBOOL WINAPI MapUserPhysicalPages(PVOID VirtualAddress,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI WINBOOL WINAPI MapUserPhysicalPagesScatter(PVOID *VirtualAddresses,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); - WINBASEAPI HANDLE WINAPI CreateJobObjectA(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI CreateJobObjectW(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCWSTR lpName); - WINBASEAPI HANDLE WINAPI OpenJobObjectA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); - WINBASEAPI HANDLE WINAPI OpenJobObjectW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); - WINBASEAPI WINBOOL WINAPI AssignProcessToJobObject(HANDLE hJob,HANDLE hProcess); - WINBASEAPI WINBOOL WINAPI TerminateJobObject(HANDLE hJob,UINT uExitCode); - WINBASEAPI WINBOOL WINAPI QueryInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength,LPDWORD lpReturnLength); - WINBASEAPI WINBOOL WINAPI SetInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength); - WINBASEAPI WINBOOL WINAPI IsProcessInJob(HANDLE ProcessHandle,HANDLE JobHandle,PBOOL Result); - WINBASEAPI WINBOOL WINAPI CreateJobSet(ULONG NumJob,PJOB_SET_ARRAY UserJobSet,ULONG Flags); - WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); - WINBASEAPI ULONG WINAPI RemoveVectoredExceptionHandler(PVOID Handle); - WINBASEAPI PVOID WINAPI AddVectoredContinueHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); - WINBASEAPI ULONG WINAPI RemoveVectoredContinueHandler(PVOID Handle); - WINBASEAPI HANDLE WINAPI FindFirstVolumeA(LPSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI HANDLE WINAPI FindFirstVolumeW(LPWSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeA(HANDLE hFindVolume,LPSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeW(HANDLE hFindVolume,LPWSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindVolumeClose(HANDLE hFindVolume); - WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointA(LPCSTR lpszRootPathName,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointW(LPCWSTR lpszRootPathName,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointA(HANDLE hFindVolumeMountPoint,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointW(HANDLE hFindVolumeMountPoint,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI FindVolumeMountPointClose(HANDLE hFindVolumeMountPoint); - WINBASEAPI WINBOOL WINAPI SetVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPCSTR lpszVolumeName); - WINBASEAPI WINBOOL WINAPI SetVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPCWSTR lpszVolumeName); - WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointA(LPCSTR lpszVolumeMountPoint); - WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointW(LPCWSTR lpszVolumeMountPoint); - WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPWSTR lpszVolumeName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNameA(LPCSTR lpszFileName,LPSTR lpszVolumePathName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNameW(LPCWSTR lpszFileName,LPWSTR lpszVolumePathName,DWORD cchBufferLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameA(LPCSTR lpszVolumeName,LPCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); - WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameW(LPCWSTR lpszVolumeName,LPWCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); - -#define ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID 0x1 -#define ACTCTX_FLAG_LANGID_VALID 0x2 -#define ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID 0x4 -#define ACTCTX_FLAG_RESOURCE_NAME_VALID 0x8 -#define ACTCTX_FLAG_SET_PROCESS_DEFAULT 0x10 -#define ACTCTX_FLAG_APPLICATION_NAME_VALID 0x20 -#define ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF 0x40 -#define ACTCTX_FLAG_HMODULE_VALID 0x80 - - typedef struct tagACTCTXA { - ULONG cbSize; - DWORD dwFlags; - LPCSTR lpSource; - USHORT wProcessorArchitecture; - LANGID wLangId; - LPCSTR lpAssemblyDirectory; - LPCSTR lpResourceName; - LPCSTR lpApplicationName; - HMODULE hModule; - } ACTCTXA,*PACTCTXA; - - typedef struct tagACTCTXW { - ULONG cbSize; - DWORD dwFlags; - LPCWSTR lpSource; - USHORT wProcessorArchitecture; - LANGID wLangId; - LPCWSTR lpAssemblyDirectory; - LPCWSTR lpResourceName; - LPCWSTR lpApplicationName; - HMODULE hModule; - } ACTCTXW,*PACTCTXW; - - typedef const ACTCTXA *PCACTCTXA; - typedef const ACTCTXW *PCACTCTXW; - -#ifdef UNICODE - typedef ACTCTXW ACTCTX; - typedef PACTCTXW PACTCTX; - typedef PCACTCTXW PCACTCTX; -#else - typedef ACTCTXA ACTCTX; - typedef PACTCTXA PACTCTX; - typedef PCACTCTXA PCACTCTX; -#endif - -#ifdef UNICODE -#define CreateActCtx CreateActCtxW -#else -#define CreateActCtx CreateActCtxA -#endif - - WINBASEAPI HANDLE WINAPI CreateActCtxA(PCACTCTXA pActCtx); - WINBASEAPI HANDLE WINAPI CreateActCtxW(PCACTCTXW pActCtx); - WINBASEAPI VOID WINAPI AddRefActCtx(HANDLE hActCtx); - WINBASEAPI VOID WINAPI ReleaseActCtx(HANDLE hActCtx); - WINBASEAPI WINBOOL WINAPI ZombifyActCtx(HANDLE hActCtx); - WINBASEAPI WINBOOL WINAPI ActivateActCtx(HANDLE hActCtx,ULONG_PTR *lpCookie); - -#define DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION (0x1) - - WINBASEAPI WINBOOL WINAPI DeactivateActCtx(DWORD dwFlags,ULONG_PTR ulCookie); - WINBASEAPI WINBOOL WINAPI GetCurrentActCtx(HANDLE *lphActCtx); - - typedef struct tagACTCTX_SECTION_KEYED_DATA_2600 { - ULONG cbSize; - ULONG ulDataFormatVersion; - PVOID lpData; - ULONG ulLength; - PVOID lpSectionGlobalData; - ULONG ulSectionGlobalDataLength; - PVOID lpSectionBase; - ULONG ulSectionTotalLength; - HANDLE hActCtx; - ULONG ulAssemblyRosterIndex; - } ACTCTX_SECTION_KEYED_DATA_2600,*PACTCTX_SECTION_KEYED_DATA_2600; - - typedef const ACTCTX_SECTION_KEYED_DATA_2600 *PCACTCTX_SECTION_KEYED_DATA_2600; - - typedef struct tagACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA { - PVOID lpInformation; - PVOID lpSectionBase; - ULONG ulSectionLength; - PVOID lpSectionGlobalDataBase; - ULONG ulSectionGlobalDataLength; - } ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA,*PACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; - - typedef const ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA *PCACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; - - typedef struct tagACTCTX_SECTION_KEYED_DATA { - ULONG cbSize; - ULONG ulDataFormatVersion; - PVOID lpData; - ULONG ulLength; - PVOID lpSectionGlobalData; - ULONG ulSectionGlobalDataLength; - PVOID lpSectionBase; - ULONG ulSectionTotalLength; - HANDLE hActCtx; - ULONG ulAssemblyRosterIndex; - - ULONG ulFlags; - ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA AssemblyMetadata; - } ACTCTX_SECTION_KEYED_DATA,*PACTCTX_SECTION_KEYED_DATA; - - typedef const ACTCTX_SECTION_KEYED_DATA *PCACTCTX_SECTION_KEYED_DATA; - -#define FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX 0x1 -#define FIND_ACTCTX_SECTION_KEY_RETURN_FLAGS 0x2 -#define FIND_ACTCTX_SECTION_KEY_RETURN_ASSEMBLY_METADATA 0x4 - -#ifdef UNICODE -#define FindActCtxSectionString FindActCtxSectionStringW -#else -#define FindActCtxSectionString FindActCtxSectionStringA -#endif - - WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringA(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); - WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCWSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); - WINBASEAPI WINBOOL WINAPI FindActCtxSectionGuid(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,const GUID *lpGuidToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); - -#ifndef RC_INVOKED -#ifndef ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED - - typedef struct _ACTIVATION_CONTEXT_BASIC_INFORMATION { - HANDLE hActCtx; - DWORD dwFlags; - } ACTIVATION_CONTEXT_BASIC_INFORMATION,*PACTIVATION_CONTEXT_BASIC_INFORMATION; - - typedef const struct _ACTIVATION_CONTEXT_BASIC_INFORMATION *PCACTIVATION_CONTEXT_BASIC_INFORMATION; - -#define ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED 1 -#endif -#endif - -#define QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX 0x4 -#define QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE 0x8 -#define QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS 0x10 -#define QUERY_ACTCTX_FLAG_NO_ADDREF 0x80000000 - - WINBASEAPI WINBOOL WINAPI QueryActCtxW(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); - - typedef WINBOOL (WINAPI *PQUERYACTCTXW_FUNC)(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); - - WINBASEAPI WINBOOL WINAPI ProcessIdToSessionId(DWORD dwProcessId,DWORD *pSessionId); - WINBASEAPI DWORD WINAPI WTSGetActiveConsoleSessionId(); - WINBASEAPI WINBOOL WINAPI IsWow64Process(HANDLE hProcess,PBOOL Wow64Process); - WINBASEAPI WINBOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer,PDWORD ReturnedLength); - WINBASEAPI WINBOOL WINAPI GetNumaHighestNodeNumber(PULONG HighestNodeNumber); - WINBASEAPI WINBOOL WINAPI GetNumaProcessorNode(UCHAR Processor,PUCHAR NodeNumber); - WINBASEAPI WINBOOL WINAPI GetNumaNodeProcessorMask(UCHAR Node,PULONGLONG ProcessorMask); - WINBASEAPI WINBOOL WINAPI GetNumaAvailableMemoryNode(UCHAR Node,PULONGLONG AvailableBytes); - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINBASE_ +#define _WINBASE_ + +#define WINADVAPI DECLSPEC_IMPORT +#define WINBASEAPI DECLSPEC_IMPORT +#define ZAWPROXYAPI DECLSPEC_IMPORT + +#ifdef __cplusplus +extern "C" { +#endif + +#define DefineHandleTable(w) ((w),TRUE) +#define LimitEmsPages(dw) +#define SetSwapAreaSize(w) (w) +#define LockSegment(w) GlobalFix((HANDLE)(w)) +#define UnlockSegment(w) GlobalUnfix((HANDLE)(w)) +#define GetCurrentTime() GetTickCount() + +#define Yield() + +#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) +#define INVALID_FILE_SIZE ((DWORD)0xffffffff) +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) + +#define FILE_BEGIN 0 +#define FILE_CURRENT 1 +#define FILE_END 2 + +#define TIME_ZONE_ID_INVALID ((DWORD)0xffffffff) + +#define WAIT_FAILED ((DWORD)0xffffffff) +#define WAIT_OBJECT_0 ((STATUS_WAIT_0) + 0) +#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0) + 0) +#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0) + 0) +#define WAIT_IO_COMPLETION STATUS_USER_APC +#define STILL_ACTIVE STATUS_PENDING +#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION +#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT +#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT +#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP +#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED +#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND +#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO +#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT +#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION +#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW +#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK +#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW +#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO +#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW +#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION +#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR +#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION +#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION +#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW +#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION +#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION +#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE +#define EXCEPTION_POSSIBLE_DEADLOCK STATUS_POSSIBLE_DEADLOCK +#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT +#define MoveMemory RtlMoveMemory +#define CopyMemory RtlCopyMemory +#define FillMemory RtlFillMemory +#define ZeroMemory RtlZeroMemory +#define SecureZeroMemory RtlSecureZeroMemory + +#define FILE_FLAG_WRITE_THROUGH 0x80000000 +#define FILE_FLAG_OVERLAPPED 0x40000000 +#define FILE_FLAG_NO_BUFFERING 0x20000000 +#define FILE_FLAG_RANDOM_ACCESS 0x10000000 +#define FILE_FLAG_SEQUENTIAL_SCAN 0x8000000 +#define FILE_FLAG_DELETE_ON_CLOSE 0x4000000 +#define FILE_FLAG_BACKUP_SEMANTICS 0x2000000 +#define FILE_FLAG_POSIX_SEMANTICS 0x1000000 +#define FILE_FLAG_OPEN_REPARSE_POINT 0x200000 +#define FILE_FLAG_OPEN_NO_RECALL 0x100000 +#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x80000 + +#define CREATE_NEW 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define OPEN_ALWAYS 4 +#define TRUNCATE_EXISTING 5 + +#define PROGRESS_CONTINUE 0 +#define PROGRESS_CANCEL 1 +#define PROGRESS_STOP 2 +#define PROGRESS_QUIET 3 + +#define CALLBACK_CHUNK_FINISHED 0x0 +#define CALLBACK_STREAM_SWITCH 0x1 + +#define COPY_FILE_FAIL_IF_EXISTS 0x1 +#define COPY_FILE_RESTARTABLE 0x2 +#define COPY_FILE_OPEN_SOURCE_FOR_WRITE 0x4 +#define COPY_FILE_ALLOW_DECRYPTED_DESTINATION 0x8 + +#define REPLACEFILE_WRITE_THROUGH 0x1 +#define REPLACEFILE_IGNORE_MERGE_ERRORS 0x2 + +#define PIPE_ACCESS_INBOUND 0x1 +#define PIPE_ACCESS_OUTBOUND 0x2 +#define PIPE_ACCESS_DUPLEX 0x3 + +#define PIPE_CLIENT_END 0x0 +#define PIPE_SERVER_END 0x1 + +#define PIPE_WAIT 0x0 +#define PIPE_NOWAIT 0x1 +#define PIPE_READMODE_BYTE 0x0 +#define PIPE_READMODE_MESSAGE 0x2 +#define PIPE_TYPE_BYTE 0x0 +#define PIPE_TYPE_MESSAGE 0x4 + +#define PIPE_UNLIMITED_INSTANCES 255 + +#define SECURITY_ANONYMOUS (SecurityAnonymous << 16) +#define SECURITY_IDENTIFICATION (SecurityIdentification << 16) +#define SECURITY_IMPERSONATION (SecurityImpersonation << 16) +#define SECURITY_DELEGATION (SecurityDelegation << 16) + +#define SECURITY_CONTEXT_TRACKING 0x40000 +#define SECURITY_EFFECTIVE_ONLY 0x80000 + +#define SECURITY_SQOS_PRESENT 0x100000 +#define SECURITY_VALID_SQOS_FLAGS 0x1f0000 + + typedef struct _OVERLAPPED { + ULONG_PTR Internal; + ULONG_PTR InternalHigh; + union { + struct { + DWORD Offset; + DWORD OffsetHigh; + }; + PVOID Pointer; + }; + HANDLE hEvent; + } OVERLAPPED,*LPOVERLAPPED; + + typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + LPVOID lpSecurityDescriptor; + WINBOOL bInheritHandle; + } SECURITY_ATTRIBUTES,*PSECURITY_ATTRIBUTES,*LPSECURITY_ATTRIBUTES; + + typedef struct _PROCESS_INFORMATION { + HANDLE hProcess; + HANDLE hThread; + DWORD dwProcessId; + DWORD dwThreadId; + } PROCESS_INFORMATION,*PPROCESS_INFORMATION,*LPPROCESS_INFORMATION; + +#ifndef _FILETIME_ +#define _FILETIME_ + typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; + } FILETIME,*PFILETIME,*LPFILETIME; +#endif + + typedef struct _SYSTEMTIME { + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; + } SYSTEMTIME,*PSYSTEMTIME,*LPSYSTEMTIME; + + typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); + typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; + typedef VOID (WINAPI *PFIBER_START_ROUTINE)(LPVOID lpFiberParameter); + typedef PFIBER_START_ROUTINE LPFIBER_START_ROUTINE; + + typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; + typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION; + typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION; + typedef RTL_CRITICAL_SECTION_DEBUG CRITICAL_SECTION_DEBUG; + typedef PRTL_CRITICAL_SECTION_DEBUG PCRITICAL_SECTION_DEBUG; + typedef PRTL_CRITICAL_SECTION_DEBUG LPCRITICAL_SECTION_DEBUG; + + WINBASEAPI PVOID WINAPI EncodePointer(PVOID Ptr); + WINBASEAPI PVOID WINAPI DecodePointer(PVOID Ptr); + WINBASEAPI PVOID WINAPI EncodeSystemPointer(PVOID Ptr); + WINBASEAPI PVOID WINAPI DecodeSystemPointer(PVOID Ptr); + +#ifdef I_X86_ + typedef PLDT_ENTRY LPLDT_ENTRY; +#else + typedef LPVOID LPLDT_ENTRY; +#endif + +#define MUTEX_MODIFY_STATE MUTANT_QUERY_STATE +#define MUTEX_ALL_ACCESS MUTANT_ALL_ACCESS + +#define SP_SERIALCOMM ((DWORD)0x1) + +#define PST_UNSPECIFIED ((DWORD)0x0) +#define PST_RS232 ((DWORD)0x1) +#define PST_PARALLELPORT ((DWORD)0x2) +#define PST_RS422 ((DWORD)0x3) +#define PST_RS423 ((DWORD)0x4) +#define PST_RS449 ((DWORD)0x5) +#define PST_MODEM ((DWORD)0x6) +#define PST_FAX ((DWORD)0x21) +#define PST_SCANNER ((DWORD)0x22) +#define PST_NETWORK_BRIDGE ((DWORD)0x100) +#define PST_LAT ((DWORD)0x101) +#define PST_TCPIP_TELNET ((DWORD)0x102) +#define PST_X25 ((DWORD)0x103) + +#define PCF_DTRDSR ((DWORD)0x1) +#define PCF_RTSCTS ((DWORD)0x2) +#define PCF_RLSD ((DWORD)0x4) +#define PCF_PARITY_CHECK ((DWORD)0x8) +#define PCF_XONXOFF ((DWORD)0x10) +#define PCF_SETXCHAR ((DWORD)0x20) +#define PCF_TOTALTIMEOUTS ((DWORD)0x40) +#define PCF_INTTIMEOUTS ((DWORD)0x80) +#define PCF_SPECIALCHARS ((DWORD)0x100) +#define PCF_16BITMODE ((DWORD)0x200) + +#define SP_PARITY ((DWORD)0x1) +#define SP_BAUD ((DWORD)0x2) +#define SP_DATABITS ((DWORD)0x4) +#define SP_STOPBITS ((DWORD)0x8) +#define SP_HANDSHAKING ((DWORD)0x10) +#define SP_PARITY_CHECK ((DWORD)0x20) +#define SP_RLSD ((DWORD)0x40) + +#define BAUD_075 ((DWORD)0x1) +#define BAUD_110 ((DWORD)0x2) +#define BAUD_134_5 ((DWORD)0x4) +#define BAUD_150 ((DWORD)0x8) +#define BAUD_300 ((DWORD)0x10) +#define BAUD_600 ((DWORD)0x20) +#define BAUD_1200 ((DWORD)0x40) +#define BAUD_1800 ((DWORD)0x80) +#define BAUD_2400 ((DWORD)0x100) +#define BAUD_4800 ((DWORD)0x200) +#define BAUD_7200 ((DWORD)0x400) +#define BAUD_9600 ((DWORD)0x800) +#define BAUD_14400 ((DWORD)0x1000) +#define BAUD_19200 ((DWORD)0x2000) +#define BAUD_38400 ((DWORD)0x4000) +#define BAUD_56K ((DWORD)0x8000) +#define BAUD_128K ((DWORD)0x10000) +#define BAUD_115200 ((DWORD)0x20000) +#define BAUD_57600 ((DWORD)0x40000) +#define BAUD_USER ((DWORD)0x10000000) + +#define DATABITS_5 ((WORD)0x1) +#define DATABITS_6 ((WORD)0x2) +#define DATABITS_7 ((WORD)0x4) +#define DATABITS_8 ((WORD)0x8) +#define DATABITS_16 ((WORD)0x10) +#define DATABITS_16X ((WORD)0x20) + +#define STOPBITS_10 ((WORD)0x1) +#define STOPBITS_15 ((WORD)0x2) +#define STOPBITS_20 ((WORD)0x4) +#define PARITY_NONE ((WORD)0x100) +#define PARITY_ODD ((WORD)0x200) +#define PARITY_EVEN ((WORD)0x400) +#define PARITY_MARK ((WORD)0x800) +#define PARITY_SPACE ((WORD)0x1000) + + typedef struct _COMMPROP { + WORD wPacketLength; + WORD wPacketVersion; + DWORD dwServiceMask; + DWORD dwReserved1; + DWORD dwMaxTxQueue; + DWORD dwMaxRxQueue; + DWORD dwMaxBaud; + DWORD dwProvSubType; + DWORD dwProvCapabilities; + DWORD dwSettableParams; + DWORD dwSettableBaud; + WORD wSettableData; + WORD wSettableStopParity; + DWORD dwCurrentTxQueue; + DWORD dwCurrentRxQueue; + DWORD dwProvSpec1; + DWORD dwProvSpec2; + WCHAR wcProvChar[1]; + } COMMPROP,*LPCOMMPROP; + +#define COMMPROP_INITIALIZED ((DWORD)0xE73CF52E) + + typedef struct _COMSTAT { + DWORD fCtsHold : 1; + DWORD fDsrHold : 1; + DWORD fRlsdHold : 1; + DWORD fXoffHold : 1; + DWORD fXoffSent : 1; + DWORD fEof : 1; + DWORD fTxim : 1; + DWORD fReserved : 25; + DWORD cbInQue; + DWORD cbOutQue; + } COMSTAT,*LPCOMSTAT; + +#define DTR_CONTROL_DISABLE 0x0 +#define DTR_CONTROL_ENABLE 0x1 +#define DTR_CONTROL_HANDSHAKE 0x2 + +#define RTS_CONTROL_DISABLE 0x0 +#define RTS_CONTROL_ENABLE 0x1 +#define RTS_CONTROL_HANDSHAKE 0x2 +#define RTS_CONTROL_TOGGLE 0x3 + + typedef struct _DCB { + DWORD DCBlength; + DWORD BaudRate; + DWORD fBinary: 1; + DWORD fParity: 1; + DWORD fOutxCtsFlow:1; + DWORD fOutxDsrFlow:1; + DWORD fDtrControl:2; + DWORD fDsrSensitivity:1; + DWORD fTXContinueOnXoff: 1; + DWORD fOutX: 1; + DWORD fInX: 1; + DWORD fErrorChar: 1; + DWORD fNull: 1; + DWORD fRtsControl:2; + DWORD fAbortOnError:1; + DWORD fDummy2:17; + WORD wReserved; + WORD XonLim; + WORD XoffLim; + BYTE ByteSize; + BYTE Parity; + BYTE StopBits; + char XonChar; + char XoffChar; + char ErrorChar; + char EofChar; + char EvtChar; + WORD wReserved1; + } DCB,*LPDCB; + + typedef struct _COMMTIMEOUTS { + DWORD ReadIntervalTimeout; + DWORD ReadTotalTimeoutMultiplier; + DWORD ReadTotalTimeoutConstant; + DWORD WriteTotalTimeoutMultiplier; + DWORD WriteTotalTimeoutConstant; + } COMMTIMEOUTS,*LPCOMMTIMEOUTS; + + typedef struct _COMMCONFIG { + DWORD dwSize; + WORD wVersion; + WORD wReserved; + DCB dcb; + DWORD dwProviderSubType; + DWORD dwProviderOffset; + DWORD dwProviderSize; + WCHAR wcProviderData[1]; + } COMMCONFIG,*LPCOMMCONFIG; + + typedef struct _SYSTEM_INFO { + union { + DWORD dwOemId; + struct { + WORD wProcessorArchitecture; + WORD wReserved; + }; + }; + DWORD dwPageSize; + LPVOID lpMinimumApplicationAddress; + LPVOID lpMaximumApplicationAddress; + DWORD_PTR dwActiveProcessorMask; + DWORD dwNumberOfProcessors; + DWORD dwProcessorType; + DWORD dwAllocationGranularity; + WORD wProcessorLevel; + WORD wProcessorRevision; + } SYSTEM_INFO,*LPSYSTEM_INFO; + +#define FreeModule(hLibModule) FreeLibrary((hLibModule)) +#define MakeProcInstance(lpProc,hInstance) (lpProc) +#define FreeProcInstance(lpProc) (lpProc) + +#define GMEM_FIXED 0x0 +#define GMEM_MOVEABLE 0x2 +#define GMEM_NOCOMPACT 0x10 +#define GMEM_NODISCARD 0x20 +#define GMEM_ZEROINIT 0x40 +#define GMEM_MODIFY 0x80 +#define GMEM_DISCARDABLE 0x100 +#define GMEM_NOT_BANKED 0x1000 +#define GMEM_SHARE 0x2000 +#define GMEM_DDESHARE 0x2000 +#define GMEM_NOTIFY 0x4000 +#define GMEM_LOWER GMEM_NOT_BANKED +#define GMEM_VALID_FLAGS 0x7F72 +#define GMEM_INVALID_HANDLE 0x8000 + +#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT) +#define GPTR (GMEM_FIXED | GMEM_ZEROINIT) + +#define GlobalLRUNewest(h) ((HANDLE)(h)) +#define GlobalLRUOldest(h) ((HANDLE)(h)) +#define GlobalDiscard(h) GlobalReAlloc((h),0,GMEM_MOVEABLE) + +#define GMEM_DISCARDED 0x4000 +#define GMEM_LOCKCOUNT 0xff + + typedef struct _MEMORYSTATUS { + DWORD dwLength; + DWORD dwMemoryLoad; + SIZE_T dwTotalPhys; + SIZE_T dwAvailPhys; + SIZE_T dwTotalPageFile; + SIZE_T dwAvailPageFile; + SIZE_T dwTotalVirtual; + SIZE_T dwAvailVirtual; + } MEMORYSTATUS,*LPMEMORYSTATUS; + +#define LMEM_FIXED 0x0 +#define LMEM_MOVEABLE 0x2 +#define LMEM_NOCOMPACT 0x10 +#define LMEM_NODISCARD 0x20 +#define LMEM_ZEROINIT 0x40 +#define LMEM_MODIFY 0x80 +#define LMEM_DISCARDABLE 0xf00 +#define LMEM_VALID_FLAGS 0xf72 +#define LMEM_INVALID_HANDLE 0x8000 + +#define LHND (LMEM_MOVEABLE | LMEM_ZEROINIT) +#define LPTR (LMEM_FIXED | LMEM_ZEROINIT) + +#define NONZEROLHND (LMEM_MOVEABLE) +#define NONZEROLPTR (LMEM_FIXED) + +#define LocalDiscard(h) LocalReAlloc((h),0,LMEM_MOVEABLE) + +#define LMEM_DISCARDED 0x4000 +#define LMEM_LOCKCOUNT 0xff + +#define DEBUG_PROCESS 0x1 +#define DEBUG_ONLY_THIS_PROCESS 0x2 +#define CREATE_SUSPENDED 0x4 +#define DETACHED_PROCESS 0x8 +#define CREATE_NEW_CONSOLE 0x10 +#define NORMAL_PRIORITY_CLASS 0x20 +#define IDLE_PRIORITY_CLASS 0x40 +#define HIGH_PRIORITY_CLASS 0x80 +#define REALTIME_PRIORITY_CLASS 0x100 +#define CREATE_NEW_PROCESS_GROUP 0x200 +#define CREATE_UNICODE_ENVIRONMENT 0x400 +#define CREATE_SEPARATE_WOW_VDM 0x800 +#define CREATE_SHARED_WOW_VDM 0x1000 +#define CREATE_FORCEDOS 0x2000 +#define BELOW_NORMAL_PRIORITY_CLASS 0x4000 +#define ABOVE_NORMAL_PRIORITY_CLASS 0x8000 +#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x10000 + +#define CREATE_BREAKAWAY_FROM_JOB 0x1000000 +#define CREATE_PRESERVE_CODE_AUTHZ_LEVEL 0x2000000 + +#define CREATE_DEFAULT_ERROR_MODE 0x4000000 +#define CREATE_NO_WINDOW 0x8000000 + +#define PROFILE_USER 0x10000000 +#define PROFILE_KERNEL 0x20000000 +#define PROFILE_SERVER 0x40000000 + +#define CREATE_IGNORE_SYSTEM_DEFAULT 0x80000000 + +#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN +#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1) +#define THREAD_PRIORITY_NORMAL 0 +#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX +#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1) +#define THREAD_PRIORITY_ERROR_RETURN (MAXLONG) + +#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT +#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE + +#define EXCEPTION_DEBUG_EVENT 1 +#define CREATE_THREAD_DEBUG_EVENT 2 +#define CREATE_PROCESS_DEBUG_EVENT 3 +#define EXIT_THREAD_DEBUG_EVENT 4 +#define EXIT_PROCESS_DEBUG_EVENT 5 +#define LOAD_DLL_DEBUG_EVENT 6 +#define UNLOAD_DLL_DEBUG_EVENT 7 +#define OUTPUT_DEBUG_STRING_EVENT 8 +#define RIP_EVENT 9 + + typedef struct _EXCEPTION_DEBUG_INFO { + EXCEPTION_RECORD ExceptionRecord; + DWORD dwFirstChance; + } EXCEPTION_DEBUG_INFO,*LPEXCEPTION_DEBUG_INFO; + + typedef struct _CREATE_THREAD_DEBUG_INFO { + HANDLE hThread; + LPVOID lpThreadLocalBase; + LPTHREAD_START_ROUTINE lpStartAddress; + } CREATE_THREAD_DEBUG_INFO,*LPCREATE_THREAD_DEBUG_INFO; + + typedef struct _CREATE_PROCESS_DEBUG_INFO { + HANDLE hFile; + HANDLE hProcess; + HANDLE hThread; + LPVOID lpBaseOfImage; + DWORD dwDebugInfoFileOffset; + DWORD nDebugInfoSize; + LPVOID lpThreadLocalBase; + LPTHREAD_START_ROUTINE lpStartAddress; + LPVOID lpImageName; + WORD fUnicode; + } CREATE_PROCESS_DEBUG_INFO,*LPCREATE_PROCESS_DEBUG_INFO; + + typedef struct _EXIT_THREAD_DEBUG_INFO { + DWORD dwExitCode; + } EXIT_THREAD_DEBUG_INFO,*LPEXIT_THREAD_DEBUG_INFO; + + typedef struct _EXIT_PROCESS_DEBUG_INFO { + DWORD dwExitCode; + } EXIT_PROCESS_DEBUG_INFO,*LPEXIT_PROCESS_DEBUG_INFO; + + typedef struct _LOAD_DLL_DEBUG_INFO { + HANDLE hFile; + LPVOID lpBaseOfDll; + DWORD dwDebugInfoFileOffset; + DWORD nDebugInfoSize; + LPVOID lpImageName; + WORD fUnicode; + } LOAD_DLL_DEBUG_INFO,*LPLOAD_DLL_DEBUG_INFO; + + typedef struct _UNLOAD_DLL_DEBUG_INFO { + LPVOID lpBaseOfDll; + } UNLOAD_DLL_DEBUG_INFO,*LPUNLOAD_DLL_DEBUG_INFO; + + typedef struct _OUTPUT_DEBUG_STRING_INFO { + LPSTR lpDebugStringData; + WORD fUnicode; + WORD nDebugStringLength; + } OUTPUT_DEBUG_STRING_INFO,*LPOUTPUT_DEBUG_STRING_INFO; + + typedef struct _RIP_INFO { + DWORD dwError; + DWORD dwType; + } RIP_INFO,*LPRIP_INFO; + + typedef struct _DEBUG_EVENT { + DWORD dwDebugEventCode; + DWORD dwProcessId; + DWORD dwThreadId; + union { + EXCEPTION_DEBUG_INFO Exception; + CREATE_THREAD_DEBUG_INFO CreateThread; + CREATE_PROCESS_DEBUG_INFO CreateProcessInfo; + EXIT_THREAD_DEBUG_INFO ExitThread; + EXIT_PROCESS_DEBUG_INFO ExitProcess; + LOAD_DLL_DEBUG_INFO LoadDll; + UNLOAD_DLL_DEBUG_INFO UnloadDll; + OUTPUT_DEBUG_STRING_INFO DebugString; + RIP_INFO RipInfo; + } u; + } DEBUG_EVENT,*LPDEBUG_EVENT; + + typedef PCONTEXT LPCONTEXT; + typedef PEXCEPTION_RECORD LPEXCEPTION_RECORD; + typedef PEXCEPTION_POINTERS LPEXCEPTION_POINTERS; + +#define DRIVE_UNKNOWN 0 +#define DRIVE_NO_ROOT_DIR 1 +#define DRIVE_REMOVABLE 2 +#define DRIVE_FIXED 3 +#define DRIVE_REMOTE 4 +#define DRIVE_CDROM 5 +#define DRIVE_RAMDISK 6 + +#define GetFreeSpace(w) (0x100000L) +#define FILE_TYPE_UNKNOWN 0x0 +#define FILE_TYPE_DISK 0x1 +#define FILE_TYPE_CHAR 0x2 +#define FILE_TYPE_PIPE 0x3 +#define FILE_TYPE_REMOTE 0x8000 + +#define STD_INPUT_HANDLE ((DWORD)-10) +#define STD_OUTPUT_HANDLE ((DWORD)-11) +#define STD_ERROR_HANDLE ((DWORD)-12) + +#define NOPARITY 0 +#define ODDPARITY 1 +#define EVENPARITY 2 +#define MARKPARITY 3 +#define SPACEPARITY 4 + +#define ONESTOPBIT 0 +#define ONE5STOPBITS 1 +#define TWOSTOPBITS 2 + +#define IGNORE 0 +#define INFINITE 0xffffffff + +#define CBR_110 110 +#define CBR_300 300 +#define CBR_600 600 +#define CBR_1200 1200 +#define CBR_2400 2400 +#define CBR_4800 4800 +#define CBR_9600 9600 +#define CBR_14400 14400 +#define CBR_19200 19200 +#define CBR_38400 38400 +#define CBR_56000 56000 +#define CBR_57600 57600 +#define CBR_115200 115200 +#define CBR_128000 128000 +#define CBR_256000 256000 + +#define CE_RXOVER 0x1 +#define CE_OVERRUN 0x2 +#define CE_RXPARITY 0x4 +#define CE_FRAME 0x8 +#define CE_BREAK 0x10 +#define CE_TXFULL 0x100 +#define CE_PTO 0x200 +#define CE_IOE 0x400 +#define CE_DNS 0x800 +#define CE_OOP 0x1000 +#define CE_MODE 0x8000 + +#define IE_BADID (-1) +#define IE_OPEN (-2) +#define IE_NOPEN (-3) +#define IE_MEMORY (-4) +#define IE_DEFAULT (-5) +#define IE_HARDWARE (-10) +#define IE_BYTESIZE (-11) +#define IE_BAUDRATE (-12) + +#define EV_RXCHAR 0x1 +#define EV_RXFLAG 0x2 +#define EV_TXEMPTY 0x4 +#define EV_CTS 0x8 +#define EV_DSR 0x10 +#define EV_RLSD 0x20 +#define EV_BREAK 0x40 +#define EV_ERR 0x80 +#define EV_RING 0x100 +#define EV_PERR 0x200 +#define EV_RX80FULL 0x400 +#define EV_EVENT1 0x800 +#define EV_EVENT2 0x1000 + +#define SETXOFF 1 +#define SETXON 2 +#define SETRTS 3 +#define CLRRTS 4 +#define SETDTR 5 +#define CLRDTR 6 +#define RESETDEV 7 +#define SETBREAK 8 +#define CLRBREAK 9 + +#define PURGE_TXABORT 0x1 +#define PURGE_RXABORT 0x2 +#define PURGE_TXCLEAR 0x4 +#define PURGE_RXCLEAR 0x8 + +#define LPTx 0x80 + +#define MS_CTS_ON ((DWORD)0x10) +#define MS_DSR_ON ((DWORD)0x20) +#define MS_RING_ON ((DWORD)0x40) +#define MS_RLSD_ON ((DWORD)0x80) + +#define S_QUEUEEMPTY 0 +#define S_THRESHOLD 1 +#define S_ALLTHRESHOLD 2 + +#define S_NORMAL 0 +#define S_LEGATO 1 +#define S_STACCATO 2 + +#define S_PERIOD512 0 +#define S_PERIOD1024 1 +#define S_PERIOD2048 2 +#define S_PERIODVOICE 3 +#define S_WHITE512 4 +#define S_WHITE1024 5 +#define S_WHITE2048 6 +#define S_WHITEVOICE 7 + +#define S_SERDVNA (-1) +#define S_SEROFM (-2) +#define S_SERMACT (-3) +#define S_SERQFUL (-4) +#define S_SERBDNT (-5) +#define S_SERDLN (-6) +#define S_SERDCC (-7) +#define S_SERDTP (-8) +#define S_SERDVL (-9) +#define S_SERDMD (-10) +#define S_SERDSH (-11) +#define S_SERDPT (-12) +#define S_SERDFQ (-13) +#define S_SERDDR (-14) +#define S_SERDSR (-15) +#define S_SERDST (-16) + +#define NMPWAIT_WAIT_FOREVER 0xffffffff +#define NMPWAIT_NOWAIT 0x1 +#define NMPWAIT_USE_DEFAULT_WAIT 0x0 + +#define FS_CASE_IS_PRESERVED FILE_CASE_PRESERVED_NAMES +#define FS_CASE_SENSITIVE FILE_CASE_SENSITIVE_SEARCH +#define FS_UNICODE_STORED_ON_DISK FILE_UNICODE_ON_DISK +#define FS_PERSISTENT_ACLS FILE_PERSISTENT_ACLS +#define FS_VOL_IS_COMPRESSED FILE_VOLUME_IS_COMPRESSED +#define FS_FILE_COMPRESSION FILE_FILE_COMPRESSION +#define FS_FILE_ENCRYPTION FILE_SUPPORTS_ENCRYPTION + +#define FILE_MAP_COPY SECTION_QUERY +#define FILE_MAP_WRITE SECTION_MAP_WRITE +#define FILE_MAP_READ SECTION_MAP_READ +#define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS +#define FILE_MAP_EXECUTE SECTION_MAP_EXECUTE_EXPLICIT + +#define OF_READ 0x0 +#define OF_WRITE 0x1 +#define OF_READWRITE 0x2 +#define OF_SHARE_COMPAT 0x0 +#define OF_SHARE_EXCLUSIVE 0x10 +#define OF_SHARE_DENY_WRITE 0x20 +#define OF_SHARE_DENY_READ 0x30 +#define OF_SHARE_DENY_NONE 0x40 +#define OF_PARSE 0x100 +#define OF_DELETE 0x200 +#define OF_VERIFY 0x400 +#define OF_CANCEL 0x800 +#define OF_CREATE 0x1000 +#define OF_PROMPT 0x2000 +#define OF_EXIST 0x4000 +#define OF_REOPEN 0x8000 + +#define OFS_MAXPATHNAME 128 + typedef struct _OFSTRUCT { + BYTE cBytes; + BYTE fFixedDisk; + WORD nErrCode; + WORD Reserved1; + WORD Reserved2; + CHAR szPathName[OFS_MAXPATHNAME]; + } OFSTRUCT,*LPOFSTRUCT,*POFSTRUCT; + +#ifndef NOWINBASEINTERLOCK + +#ifndef _NTOS_ + +#if defined(__ia64__) && !defined(RC_INVOKED) + +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedIncrementAcquire _InterlockedIncrement_acq +#define InterlockedIncrementRelease _InterlockedIncrement_rel +#define InterlockedDecrement _InterlockedDecrement +#define InterlockedDecrementAcquire _InterlockedDecrement_acq +#define InterlockedDecrementRelease _InterlockedDecrement_rel +#define InterlockedExchange _InterlockedExchange +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire _InterlockedCompareExchange_acq +#define InterlockedCompareExchangeRelease _InterlockedCompareExchange_rel +#define InterlockedExchangePointer _InterlockedExchangePointer +#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer_rel +#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer_acq + +#define InterlockedIncrement64 _InterlockedIncrement64 +#define InterlockedDecrement64 _InterlockedDecrement64 +#define InterlockedExchange64 _InterlockedExchange64 +#define InterlockedExchangeAcquire64 _InterlockedExchange64_acq +#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 +#define InterlockedCompareExchangeAcquire64 _InterlockedCompareExchange64_acq +#define InterlockedCompareExchangeRelease64 _InterlockedCompareExchange64_rel + + LONGLONG __cdecl InterlockedIncrement64(LONGLONG volatile *Addend); + LONGLONG __cdecl InterlockedDecrement64(LONGLONG volatile *Addend); + LONG __cdecl InterlockedIncrementAcquire(LONG volatile *Addend); + LONG __cdecl InterlockedDecrementAcquire(LONG volatile *Addend); + LONG __cdecl InterlockedIncrementRelease(LONG volatile *Addend); + LONG __cdecl InterlockedDecrementRelease(LONG volatile *Addend); + LONGLONG __cdecl InterlockedExchange64 (LONGLONG volatile *Target,LONGLONG Value); + LONGLONG __cdecl InterlockedExchangeAcquire64 (LONGLONG volatile *Target,LONGLONG Value); + LONGLONG __cdecl InterlockedExchangeAdd64 (LONGLONG volatile *Addend,LONGLONG Value); + LONGLONG __cdecl InterlockedCompareExchange64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); + LONGLONG __cdecl InterlockedCompareExchangeAcquire64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); + LONGLONG __cdecl InterlockedCompareExchangeRelease64 (LONGLONG volatile *Destination,LONGLONG ExChange,LONGLONG Comperand); + LONG __cdecl InterlockedIncrement(LONG volatile *lpAddend); + LONG __cdecl InterlockedDecrement(LONG volatile *lpAddend); + LONG __cdecl InterlockedExchange(LONG volatile *Target,LONG Value); + LONG __cdecl InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + LONG __cdecl InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); + LONG __cdecl InterlockedCompareExchangeRelease(LONG volatile *Destination,LONG ExChange,LONG Comperand); + LONG __cdecl InterlockedCompareExchangeAcquire(LONG volatile *Destination,LONG ExChange,LONG Comperand); + PVOID __cdecl InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); + PVOID __cdecl InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand); + PVOID __cdecl InterlockedCompareExchangePointerAcquire(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); + PVOID __cdecl InterlockedCompareExchangePointerRelease(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); + +#ifndef InterlockedAnd +#define InterlockedAnd InterlockedAnd_Inline + __CRT_INLINE LONG InterlockedAnd_Inline(LONG volatile *Target,LONG Set) { + LONG i; + LONG j; + j = *Target; + do { + i = j; + j = InterlockedCompareExchange(Target,i & Set,i); + } while(i!=j); + return j; + } +#endif + +#ifndef InterlockedOr +#define InterlockedOr InterlockedOr_Inline + + __CRT_INLINE LONG InterlockedOr_Inline(LONG volatile *Target,LONG Set) { + LONG i; + LONG j; + j = *Target; + do { + i = j; + j = InterlockedCompareExchange(Target,i | Set,i); + } while(i!=j); + return j; + } +#endif + +#ifndef InterlockedXor +#define InterlockedXor InterlockedXor_Inline + + __CRT_INLINE LONG InterlockedXor_Inline(LONG volatile *Target,LONG Set) { + LONG i; + LONG j; + j = *Target; + do { + i = j; + j = InterlockedCompareExchange(Target,i ^ Set,i); + } while(i!=j); + return j; + } +#endif + +#ifndef !defined (InterlockedAnd64) +#define InterlockedAnd64 InterlockedAnd64_Inline + + __CRT_INLINE LONGLONG InterlockedAnd64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); + return Old; + } +#endif + +#ifndef InterlockedOr64 +#define InterlockedOr64 InterlockedOr64_Inline + + __CRT_INLINE LONGLONG InterlockedOr64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); + return Old; + } +#endif + +#ifndef InterlockedXor64 +#define InterlockedXor64 InterlockedXor64_Inline + + __CRT_INLINE LONGLONG InterlockedXor64_Inline (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); + return Old; + } +#endif + +#ifndef InterlockedBitTestAndSet +#define InterlockedBitTestAndSet InterlockedBitTestAndSet_Inline + + __CRT_INLINE BOOLEAN InterlockedBitTestAndSet_Inline(LONG *Base,LONG Bit) { + LONG tBit; + tBit = 1<<(Bit & (sizeof (*Base)*8-1)); + return (BOOLEAN)((InterlockedOr(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); + } +#endif + +#ifndef InterlockedBitTestAndReset +#define InterlockedBitTestAndReset InterlockedBitTestAndReset_Inline + + __CRT_INLINE BOOLEAN InterlockedBitTestAndReset_Inline(LONG *Base,LONG Bit) { + LONG tBit; + tBit = 1<<(Bit & (sizeof (*Base)*8-1)); + return (BOOLEAN)((InterlockedAnd(&Base[Bit/(sizeof(*Base)*8)],~tBit)&tBit)!=0); + } +#endif + +#ifndef InterlockedBitTestAndComplement +#define InterlockedBitTestAndComplement InterlockedBitTestAndComplement_Inline + + __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement_Inline(LONG *Base,LONG Bit) { + LONG tBit; + tBit = 1<<(Bit & (sizeof (*Base)*8-1)); + return (BOOLEAN)((InterlockedXor(&Base[Bit/(sizeof(*Base)*8)],tBit)&tBit)!=0); + } +#endif +#elif defined(__x86_64) && !defined(RC_INVOKED) + +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedDecrement _InterlockedDecrement +#define InterlockedDecrementAcquire InterlockedDecrement +#define InterlockedDecrementRelease InterlockedDecrement +#define InterlockedExchange _InterlockedExchange +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire InterlockedCompareExchange +#define InterlockedCompareExchangeRelease InterlockedCompareExchange +#define InterlockedExchangePointer _InterlockedExchangePointer +#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer +#define InterlockedAnd64 _InterlockedAnd64 +#define InterlockedOr64 _InterlockedOr64 +#define InterlockedXor64 _InterlockedXor64 +#define InterlockedIncrement64 _InterlockedIncrement64 +#define InterlockedDecrement64 _InterlockedDecrement64 +#define InterlockedExchange64 _InterlockedExchange64 +#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 +#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 +#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 + + LONG InterlockedIncrement(LONG volatile *Addend); + LONG InterlockedDecrement(LONG volatile *Addend); + LONG InterlockedExchange(LONG volatile *Target,LONG Value); + LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand); + PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID Exchange,PVOID Comperand); + PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value); + LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value); + LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value); + LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value); + LONG64 InterlockedIncrement64(LONG64 volatile *Addend); + LONG64 InterlockedDecrement64(LONG64 volatile *Addend); + LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value); + LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); + LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand); +#else + LONG WINAPI InterlockedIncrement(LONG volatile *lpAddend); + LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend); + LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value); + +#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value)) + + LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand); + LONGLONG WINAPI InterlockedCompareExchange64(LONGLONG volatile *Destination,LONGLONG Exchange,LONGLONG Comperand); + + __CRT_INLINE LONGLONG InterlockedAnd64 (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old & Value,Old)!=Old); + return Old; + } + + __CRT_INLINE LONGLONG InterlockedOr64 (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old | Value,Old)!=Old); + return Old; + } + + __CRT_INLINE LONGLONG InterlockedXor64 (LONGLONG volatile *Destination,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Destination; + } while(InterlockedCompareExchange64(Destination,Old ^ Value,Old)!=Old); + + return Old; + } + + __CRT_INLINE LONGLONG InterlockedIncrement64(LONGLONG volatile *Addend) { + LONGLONG Old; + do { + Old = *Addend; + } while(InterlockedCompareExchange64(Addend,Old + 1,Old)!=Old); + return Old + 1; + } + + __CRT_INLINE LONGLONG InterlockedDecrement64(LONGLONG volatile *Addend) { + LONGLONG Old; + do { + Old = *Addend; + } while(InterlockedCompareExchange64(Addend,Old - 1,Old)!=Old); + return Old - 1; + } + + __CRT_INLINE LONGLONG InterlockedExchange64(LONGLONG volatile *Target,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Target; + } while(InterlockedCompareExchange64(Target,Value,Old)!=Old); + return Old; + } + + __CRT_INLINE LONGLONG InterlockedExchangeAdd64(LONGLONG volatile *Addend,LONGLONG Value) { + LONGLONG Old; + do { + Old = *Addend; + } while(InterlockedCompareExchange64(Addend,Old + Value,Old)!=Old); + return Old; + } + +#ifdef __cplusplus + __CRT_INLINE PVOID __cdecl __InlineInterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { + return((PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)Destination,(LONG)(LONG_PTR)ExChange,(LONG)(LONG_PTR)Comperand)); + } +#define InterlockedCompareExchangePointer __InlineInterlockedCompareExchangePointer +#else +#define InterlockedCompareExchangePointer(Destination,ExChange,Comperand)(PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)(Destination),(LONG)(LONG_PTR)(ExChange),(LONG)(LONG_PTR)(Comperand)) +#endif + +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedDecrementAcquire InterlockedDecrement +#define InterlockedDecrementRelease InterlockedDecrement +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedCompareExchangeAcquire InterlockedCompareExchange +#define InterlockedCompareExchangeRelease InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 +#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 +#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer +#endif + +#if defined(_SLIST_HEADER_) && !defined(_NTOSP_) + WINBASEAPI VOID WINAPI InitializeSListHead(PSLIST_HEADER ListHead); + WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPopEntrySList(PSLIST_HEADER ListHead); + WINBASEAPI PSLIST_ENTRY WINAPI InterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); + WINBASEAPI PSLIST_ENTRY WINAPI InterlockedFlushSList(PSLIST_HEADER ListHead); + WINBASEAPI USHORT WINAPI QueryDepthSList(PSLIST_HEADER ListHead); +#endif +#endif +#endif + + WINBASEAPI WINBOOL WINAPI FreeResource(HGLOBAL hResData); + WINBASEAPI LPVOID WINAPI LockResource(HGLOBAL hResData); + +#define UnlockResource(hResData) ((hResData),0) +#define MAXINTATOM 0xC000 +#define MAKEINTATOM(i) (LPTSTR)((ULONG_PTR)((WORD)(i))) +#define INVALID_ATOM ((ATOM)0) + + int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd); + WINBASEAPI WINBOOL WINAPI FreeLibrary(HMODULE hLibModule); + WINBASEAPI DECLSPEC_NORETURN VOID WINAPI FreeLibraryAndExitThread(HMODULE hLibModule,DWORD dwExitCode); + WINBASEAPI WINBOOL WINAPI DisableThreadLibraryCalls(HMODULE hLibModule); + WINBASEAPI FARPROC WINAPI GetProcAddress(HMODULE hModule,LPCSTR lpProcName); + WINBASEAPI DWORD WINAPI GetVersion(VOID); + WINBASEAPI HGLOBAL WINAPI GlobalAlloc(UINT uFlags,SIZE_T dwBytes); + WINBASEAPI HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem,SIZE_T dwBytes,UINT uFlags); + WINBASEAPI SIZE_T WINAPI GlobalSize(HGLOBAL hMem); + WINBASEAPI UINT WINAPI GlobalFlags(HGLOBAL hMem); + WINBASEAPI LPVOID WINAPI GlobalLock(HGLOBAL hMem); + WINBASEAPI HGLOBAL WINAPI GlobalHandle(LPCVOID pMem); + WINBASEAPI WINBOOL WINAPI GlobalUnlock(HGLOBAL hMem); + WINBASEAPI HGLOBAL WINAPI GlobalFree(HGLOBAL hMem); + WINBASEAPI SIZE_T WINAPI GlobalCompact(DWORD dwMinFree); + WINBASEAPI VOID WINAPI GlobalFix(HGLOBAL hMem); + WINBASEAPI VOID WINAPI GlobalUnfix(HGLOBAL hMem); + WINBASEAPI LPVOID WINAPI GlobalWire(HGLOBAL hMem); + WINBASEAPI WINBOOL WINAPI GlobalUnWire(HGLOBAL hMem); + WINBASEAPI VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer); + + typedef struct _MEMORYSTATUSEX { + DWORD dwLength; + DWORD dwMemoryLoad; + DWORDLONG ullTotalPhys; + DWORDLONG ullAvailPhys; + DWORDLONG ullTotalPageFile; + DWORDLONG ullAvailPageFile; + DWORDLONG ullTotalVirtual; + DWORDLONG ullAvailVirtual; + DWORDLONG ullAvailExtendedVirtual; + } MEMORYSTATUSEX,*LPMEMORYSTATUSEX; + + WINBASEAPI WINBOOL WINAPI GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer); + WINBASEAPI HLOCAL WINAPI LocalAlloc(UINT uFlags,SIZE_T uBytes); + WINBASEAPI HLOCAL WINAPI LocalReAlloc(HLOCAL hMem,SIZE_T uBytes,UINT uFlags); + WINBASEAPI LPVOID WINAPI LocalLock(HLOCAL hMem); + WINBASEAPI HLOCAL WINAPI LocalHandle(LPCVOID pMem); + WINBASEAPI WINBOOL WINAPI LocalUnlock(HLOCAL hMem); + WINBASEAPI SIZE_T WINAPI LocalSize(HLOCAL hMem); + WINBASEAPI UINT WINAPI LocalFlags(HLOCAL hMem); + WINBASEAPI HLOCAL WINAPI LocalFree(HLOCAL hMem); + WINBASEAPI SIZE_T WINAPI LocalShrink(HLOCAL hMem,UINT cbNewSize); + WINBASEAPI SIZE_T WINAPI LocalCompact(UINT uMinFree); + WINBASEAPI WINBOOL WINAPI FlushInstructionCache(HANDLE hProcess,LPCVOID lpBaseAddress,SIZE_T dwSize); + WINBASEAPI LPVOID WINAPI VirtualAlloc(LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); + WINBASEAPI WINBOOL WINAPI VirtualFree(LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); + WINBASEAPI WINBOOL WINAPI VirtualProtect(LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); + WINBASEAPI SIZE_T WINAPI VirtualQuery(LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); + WINBASEAPI LPVOID WINAPI VirtualAllocEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect); + WINBASEAPI UINT WINAPI GetWriteWatch(DWORD dwFlags,PVOID lpBaseAddress,SIZE_T dwRegionSize,PVOID *lpAddresses,ULONG_PTR *lpdwCount,PULONG lpdwGranularity); + WINBASEAPI UINT WINAPI ResetWriteWatch(LPVOID lpBaseAddress,SIZE_T dwRegionSize); + WINBASEAPI SIZE_T WINAPI GetLargePageMinimum(VOID); + WINBASEAPI UINT WINAPI EnumSystemFirmwareTables(DWORD FirmwareTableProviderSignature,PVOID pFirmwareTableEnumBuffer,DWORD BufferSize); + WINBASEAPI UINT WINAPI GetSystemFirmwareTable(DWORD FirmwareTableProviderSignature,DWORD FirmwareTableID,PVOID pFirmwareTableBuffer,DWORD BufferSize); + WINBASEAPI WINBOOL WINAPI VirtualFreeEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD dwFreeType); + WINBASEAPI WINBOOL WINAPI VirtualProtectEx(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect); + WINBASEAPI SIZE_T WINAPI VirtualQueryEx(HANDLE hProcess,LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength); + WINBASEAPI HANDLE WINAPI HeapCreate(DWORD flOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize); + WINBASEAPI WINBOOL WINAPI HeapDestroy(HANDLE hHeap); + WINBASEAPI LPVOID WINAPI HeapAlloc(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes); + WINBASEAPI LPVOID WINAPI HeapReAlloc(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem,SIZE_T dwBytes); + WINBASEAPI WINBOOL WINAPI HeapFree(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem); + WINBASEAPI SIZE_T WINAPI HeapSize(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); + WINBASEAPI WINBOOL WINAPI HeapValidate(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem); + WINBASEAPI SIZE_T WINAPI HeapCompact(HANDLE hHeap,DWORD dwFlags); + WINBASEAPI HANDLE WINAPI GetProcessHeap(VOID); + WINBASEAPI DWORD WINAPI GetProcessHeaps(DWORD NumberOfHeaps,PHANDLE ProcessHeaps); + + typedef struct _PROCESS_HEAP_ENTRY { + PVOID lpData; + DWORD cbData; + BYTE cbOverhead; + BYTE iRegionIndex; + WORD wFlags; + union { + struct { + HANDLE hMem; + DWORD dwReserved[3]; + } Block; + struct { + DWORD dwCommittedSize; + DWORD dwUnCommittedSize; + LPVOID lpFirstBlock; + LPVOID lpLastBlock; + } Region; + }; + } PROCESS_HEAP_ENTRY,*LPPROCESS_HEAP_ENTRY,*PPROCESS_HEAP_ENTRY; + +#define PROCESS_HEAP_REGION 0x1 +#define PROCESS_HEAP_UNCOMMITTED_RANGE 0x2 +#define PROCESS_HEAP_ENTRY_BUSY 0x4 +#define PROCESS_HEAP_ENTRY_MOVEABLE 0x10 +#define PROCESS_HEAP_ENTRY_DDESHARE 0x20 + + WINBASEAPI WINBOOL WINAPI HeapLock(HANDLE hHeap); + WINBASEAPI WINBOOL WINAPI HeapUnlock(HANDLE hHeap); + WINBASEAPI WINBOOL WINAPI HeapWalk(HANDLE hHeap,LPPROCESS_HEAP_ENTRY lpEntry); + WINBASEAPI WINBOOL WINAPI HeapSetInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); + WINBASEAPI WINBOOL WINAPI HeapQueryInformation(HANDLE HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); + +#define SCS_32BIT_BINARY 0 +#define SCS_DOS_BINARY 1 +#define SCS_WOW_BINARY 2 +#define SCS_PIF_BINARY 3 +#define SCS_POSIX_BINARY 4 +#define SCS_OS216_BINARY 5 +#define SCS_64BIT_BINARY 6 + +#ifdef UNICODE +#define GetBinaryType GetBinaryTypeW +#define GetShortPathName GetShortPathNameW +#define GetLongPathName GetLongPathNameW +#define GetEnvironmentStrings GetEnvironmentStringsW +#define SetEnvironmentStrings SetEnvironmentStringsW +#define FreeEnvironmentStrings FreeEnvironmentStringsW +#else +#define GetBinaryType GetBinaryTypeA +#define GetShortPathName GetShortPathNameA +#define GetLongPathName GetLongPathNameA +#define GetEnvironmentStringsA GetEnvironmentStrings +#define SetEnvironmentStrings SetEnvironmentStringsA +#define FreeEnvironmentStrings FreeEnvironmentStringsA +#endif + +#ifdef _WIN64 +#define SCS_THIS_PLATFORM_BINARY SCS_64BIT_BINARY +#else +#define SCS_THIS_PLATFORM_BINARY SCS_32BIT_BINARY +#endif + + WINBASEAPI WINBOOL WINAPI GetBinaryTypeA(LPCSTR lpApplicationName,LPDWORD lpBinaryType); + WINBASEAPI WINBOOL WINAPI GetBinaryTypeW(LPCWSTR lpApplicationName,LPDWORD lpBinaryType); + WINBASEAPI DWORD WINAPI GetShortPathNameA(LPCSTR lpszLongPath,LPSTR lpszShortPath,DWORD cchBuffer); + WINBASEAPI DWORD WINAPI GetShortPathNameW(LPCWSTR lpszLongPath,LPWSTR lpszShortPath,DWORD cchBuffer); + WINBASEAPI DWORD WINAPI GetLongPathNameA(LPCSTR lpszShortPath,LPSTR lpszLongPath,DWORD cchBuffer); + WINBASEAPI DWORD WINAPI GetLongPathNameW(LPCWSTR lpszShortPath,LPWSTR lpszLongPath,DWORD cchBuffer); + WINBASEAPI WINBOOL WINAPI GetProcessAffinityMask(HANDLE hProcess,PDWORD_PTR lpProcessAffinityMask,PDWORD_PTR lpSystemAffinityMask); + WINBASEAPI WINBOOL WINAPI SetProcessAffinityMask(HANDLE hProcess,DWORD_PTR dwProcessAffinityMask); + WINBASEAPI WINBOOL WINAPI GetProcessHandleCount(HANDLE hProcess,PDWORD pdwHandleCount); + WINBASEAPI WINBOOL WINAPI GetProcessTimes(HANDLE hProcess,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); + WINBASEAPI WINBOOL WINAPI GetProcessIoCounters(HANDLE hProcess,PIO_COUNTERS lpIoCounters); + WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize); + WINBASEAPI WINBOOL WINAPI GetProcessWorkingSetSizeEx(HANDLE hProcess,PSIZE_T lpMinimumWorkingSetSize,PSIZE_T lpMaximumWorkingSetSize,PDWORD Flags); + WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize); + WINBASEAPI WINBOOL WINAPI SetProcessWorkingSetSizeEx(HANDLE hProcess,SIZE_T dwMinimumWorkingSetSize,SIZE_T dwMaximumWorkingSetSize,DWORD Flags); + WINBASEAPI HANDLE WINAPI OpenProcess(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwProcessId); + WINBASEAPI HANDLE WINAPI GetCurrentProcess(VOID); + WINBASEAPI DWORD WINAPI GetCurrentProcessId(VOID); + WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitProcess(UINT uExitCode); + WINBASEAPI WINBOOL WINAPI TerminateProcess(HANDLE hProcess,UINT uExitCode); + WINBASEAPI WINBOOL WINAPI GetExitCodeProcess(HANDLE hProcess,LPDWORD lpExitCode); + WINBASEAPI VOID WINAPI FatalExit(int ExitCode); + /* WINBASEAPI LPCH WINAPI GetEnvironmentStrings(VOID); */ + WINBASEAPI LPWCH WINAPI GetEnvironmentStringsW(VOID); + WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsA(LPCH NewEnvironment); + WINBASEAPI WINBOOL WINAPI SetEnvironmentStringsW(LPWCH NewEnvironment); + WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsA(LPCH); + WINBASEAPI WINBOOL WINAPI FreeEnvironmentStringsW(LPWCH); + WINBASEAPI VOID WINAPI RaiseException(DWORD dwExceptionCode,DWORD dwExceptionFlags,DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments); + WINBASEAPI LONG WINAPI UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo); + + typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(struct _EXCEPTION_POINTERS *ExceptionInfo); + typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER; + + WINBASEAPI LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); + +#define FIBER_FLAG_FLOAT_SWITCH 0x1 + + WINBASEAPI LPVOID WINAPI CreateFiber(SIZE_T dwStackSize,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); + WINBASEAPI LPVOID WINAPI CreateFiberEx(SIZE_T dwStackCommitSize,SIZE_T dwStackReserveSize,DWORD dwFlags,LPFIBER_START_ROUTINE lpStartAddress,LPVOID lpParameter); + WINBASEAPI VOID WINAPI DeleteFiber(LPVOID lpFiber); + WINBASEAPI LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter); + WINBASEAPI LPVOID WINAPI ConvertThreadToFiberEx(LPVOID lpParameter,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI ConvertFiberToThread(VOID); + WINBASEAPI VOID WINAPI SwitchToFiber(LPVOID lpFiber); + WINBASEAPI WINBOOL WINAPI SwitchToThread(VOID); + WINBASEAPI HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); + WINBASEAPI HANDLE WINAPI CreateRemoteThread(HANDLE hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId); + WINBASEAPI HANDLE WINAPI GetCurrentThread(VOID); + WINBASEAPI DWORD WINAPI GetCurrentThreadId(VOID); + WINBASEAPI WINBOOL WINAPI SetThreadStackGuarantee (PULONG StackSizeInBytes); + WINBASEAPI DWORD WINAPI GetProcessIdOfThread(HANDLE Thread); + WINBASEAPI DWORD WINAPI GetThreadId(HANDLE Thread); + WINBASEAPI DWORD WINAPI GetProcessId(HANDLE Process); + WINBASEAPI DWORD WINAPI GetCurrentProcessorNumber(VOID); + WINBASEAPI DWORD_PTR WINAPI SetThreadAffinityMask(HANDLE hThread,DWORD_PTR dwThreadAffinityMask); + WINBASEAPI DWORD WINAPI SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor); + WINBASEAPI WINBOOL WINAPI SetProcessPriorityBoost(HANDLE hProcess,WINBOOL bDisablePriorityBoost); + WINBASEAPI WINBOOL WINAPI GetProcessPriorityBoost(HANDLE hProcess,PBOOL pDisablePriorityBoost); + WINBASEAPI WINBOOL WINAPI RequestWakeupLatency(LATENCY_TIME latency); + WINBASEAPI WINBOOL WINAPI IsSystemResumeAutomatic(VOID); + WINBASEAPI HANDLE WINAPI OpenThread(DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwThreadId); + WINBASEAPI WINBOOL WINAPI SetThreadPriority(HANDLE hThread,int nPriority); + WINBASEAPI WINBOOL WINAPI SetThreadPriorityBoost(HANDLE hThread,WINBOOL bDisablePriorityBoost); + WINBASEAPI WINBOOL WINAPI GetThreadPriorityBoost(HANDLE hThread,PBOOL pDisablePriorityBoost); + WINBASEAPI int WINAPI GetThreadPriority(HANDLE hThread); + WINBASEAPI WINBOOL WINAPI GetThreadTimes(HANDLE hThread,LPFILETIME lpCreationTime,LPFILETIME lpExitTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); + WINBASEAPI WINBOOL WINAPI GetThreadIOPendingFlag(HANDLE hThread,PBOOL lpIOIsPending); + WINBASEAPI DECLSPEC_NORETURN VOID WINAPI ExitThread(DWORD dwExitCode); + WINBASEAPI WINBOOL WINAPI TerminateThread(HANDLE hThread,DWORD dwExitCode); + WINBASEAPI WINBOOL WINAPI GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode); + WINBASEAPI WINBOOL WINAPI GetThreadSelectorEntry(HANDLE hThread,DWORD dwSelector,LPLDT_ENTRY lpSelectorEntry); + WINBASEAPI EXECUTION_STATE WINAPI SetThreadExecutionState(EXECUTION_STATE esFlags); + WINBASEAPI DWORD WINAPI GetLastError(VOID); + WINBASEAPI VOID WINAPI SetLastError(DWORD dwErrCode); + +#ifndef RC_INVOKED +#ifdef WINBASE_DECLARE_RESTORE_LAST_ERROR + WINBASEAPI VOID WINAPI RestoreLastError(DWORD dwErrCode); + + typedef VOID (WINAPI *PRESTORE_LAST_ERROR)(DWORD); + +#define RESTORE_LAST_ERROR_NAME_A "RestoreLastError" +#define RESTORE_LAST_ERROR_NAME_W L"RestoreLastError" +#define RESTORE_LAST_ERROR_NAME TEXT("RestoreLastError") +#endif +#endif + +#define HasOverlappedIoCompleted(lpOverlapped) (((DWORD)(lpOverlapped)->Internal)!=STATUS_PENDING) + + WINBASEAPI WINBOOL WINAPI GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,LPDWORD lpNumberOfBytesTransferred,WINBOOL bWait); + WINBASEAPI HANDLE WINAPI CreateIoCompletionPort(HANDLE FileHandle,HANDLE ExistingCompletionPort,ULONG_PTR CompletionKey,DWORD NumberOfConcurrentThreads); + WINBASEAPI WINBOOL WINAPI GetQueuedCompletionStatus(HANDLE CompletionPort,LPDWORD lpNumberOfBytesTransferred,PULONG_PTR lpCompletionKey,LPOVERLAPPED *lpOverlapped,DWORD dwMilliseconds); + WINBASEAPI WINBOOL WINAPI PostQueuedCompletionStatus(HANDLE CompletionPort,DWORD dwNumberOfBytesTransferred,ULONG_PTR dwCompletionKey,LPOVERLAPPED lpOverlapped); + +#define SEM_FAILCRITICALERRORS 0x1 +#define SEM_NOGPFAULTERRORBOX 0x2 +#define SEM_NOALIGNMENTFAULTEXCEPT 0x4 +#define SEM_NOOPENFILEERRORBOX 0x8000 + + WINBASEAPI UINT WINAPI SetErrorMode(UINT uMode); + WINBASEAPI WINBOOL WINAPI ReadProcessMemory(HANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesRead); + WINBASEAPI WINBOOL WINAPI WriteProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize,SIZE_T *lpNumberOfBytesWritten); + WINBASEAPI WINBOOL WINAPI GetThreadContext(HANDLE hThread,LPCONTEXT lpContext); + WINBASEAPI WINBOOL WINAPI SetThreadContext(HANDLE hThread,CONST CONTEXT *lpContext); + WINBASEAPI DWORD WINAPI SuspendThread(HANDLE hThread); + WINBASEAPI DWORD WINAPI ResumeThread(HANDLE hThread); + + typedef VOID (WINAPI *PAPCFUNC)(ULONG_PTR dwParam); + + WINBASEAPI DWORD WINAPI QueueUserAPC(PAPCFUNC pfnAPC,HANDLE hThread,ULONG_PTR dwData); + WINBASEAPI WINBOOL WINAPI IsDebuggerPresent(VOID); + WINBASEAPI WINBOOL WINAPI CheckRemoteDebuggerPresent(HANDLE hProcess,PBOOL pbDebuggerPresent); + WINBASEAPI VOID WINAPI DebugBreak(VOID); + WINBASEAPI WINBOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT lpDebugEvent,DWORD dwMilliseconds); + WINBASEAPI WINBOOL WINAPI ContinueDebugEvent(DWORD dwProcessId,DWORD dwThreadId,DWORD dwContinueStatus); + WINBASEAPI WINBOOL WINAPI DebugActiveProcess(DWORD dwProcessId); + WINBASEAPI WINBOOL WINAPI DebugActiveProcessStop(DWORD dwProcessId); + WINBASEAPI WINBOOL WINAPI DebugSetProcessKillOnExit(WINBOOL KillOnExit); + WINBASEAPI WINBOOL WINAPI DebugBreakProcess(HANDLE Process); + WINBASEAPI VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI WINBOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); + WINBASEAPI DWORD WINAPI SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection,DWORD dwSpinCount); + WINBASEAPI WINBOOL WINAPI TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + WINBASEAPI WINBOOL WINAPI SetEvent(HANDLE hEvent); + WINBASEAPI WINBOOL WINAPI ResetEvent(HANDLE hEvent); + WINBASEAPI WINBOOL WINAPI PulseEvent(HANDLE hEvent); + WINBASEAPI WINBOOL WINAPI ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount,LPLONG lpPreviousCount); + WINBASEAPI WINBOOL WINAPI ReleaseMutex(HANDLE hMutex); + WINBASEAPI DWORD WINAPI WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds); + WINBASEAPI DWORD WINAPI WaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds); + WINBASEAPI VOID WINAPI Sleep(DWORD dwMilliseconds); + WINBASEAPI HGLOBAL WINAPI LoadResource(HMODULE hModule,HRSRC hResInfo); + WINBASEAPI DWORD WINAPI SizeofResource(HMODULE hModule,HRSRC hResInfo); + WINBASEAPI ATOM WINAPI GlobalDeleteAtom(ATOM nAtom); + WINBASEAPI WINBOOL WINAPI InitAtomTable(DWORD nSize); + WINBASEAPI ATOM WINAPI DeleteAtom(ATOM nAtom); + WINBASEAPI UINT WINAPI SetHandleCount(UINT uNumber); + WINBASEAPI DWORD WINAPI GetLogicalDrives(VOID); + WINBASEAPI WINBOOL WINAPI LockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh); + WINBASEAPI WINBOOL WINAPI UnlockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh); + WINBASEAPI WINBOOL WINAPI LockFileEx(HANDLE hFile,DWORD dwFlags,DWORD dwReserved,DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh,LPOVERLAPPED lpOverlapped); + +#define LOCKFILE_FAIL_IMMEDIATELY 0x1 +#define LOCKFILE_EXCLUSIVE_LOCK 0x2 + + WINBASEAPI WINBOOL WINAPI UnlockFileEx(HANDLE hFile,DWORD dwReserved,DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh,LPOVERLAPPED lpOverlapped); + + typedef struct _BY_HANDLE_FILE_INFORMATION { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD dwVolumeSerialNumber; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD nNumberOfLinks; + DWORD nFileIndexHigh; + DWORD nFileIndexLow; + } BY_HANDLE_FILE_INFORMATION,*PBY_HANDLE_FILE_INFORMATION,*LPBY_HANDLE_FILE_INFORMATION; + +#ifdef UNICODE +#define SetFileShortName SetFileShortNameW +#else +#define SetFileShortName SetFileShortNameA +#endif + + WINBASEAPI WINBOOL WINAPI GetFileInformationByHandle(HANDLE hFile,LPBY_HANDLE_FILE_INFORMATION lpFileInformation); + WINBASEAPI DWORD WINAPI GetFileType(HANDLE hFile); + WINBASEAPI DWORD WINAPI GetFileSize(HANDLE hFile,LPDWORD lpFileSizeHigh); + WINBASEAPI WINBOOL WINAPI GetFileSizeEx(HANDLE hFile,PLARGE_INTEGER lpFileSize); + WINBASEAPI HANDLE WINAPI GetStdHandle(DWORD nStdHandle); + WINBASEAPI WINBOOL WINAPI SetStdHandle(DWORD nStdHandle,HANDLE hHandle); + WINBASEAPI WINBOOL WINAPI WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI FlushFileBuffers(HANDLE hFile); + WINBASEAPI WINBOOL WINAPI DeviceIoControl(HANDLE hDevice,DWORD dwIoControlCode,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI RequestDeviceWakeup(HANDLE hDevice); + WINBASEAPI WINBOOL WINAPI CancelDeviceWakeupRequest(HANDLE hDevice); + WINBASEAPI WINBOOL WINAPI GetDevicePowerState(HANDLE hDevice,WINBOOL *pfOn); + WINBASEAPI WINBOOL WINAPI SetMessageWaitingIndicator(HANDLE hMsgIndicator,ULONG ulMsgCount); + WINBASEAPI WINBOOL WINAPI SetEndOfFile(HANDLE hFile); + WINBASEAPI DWORD WINAPI SetFilePointer(HANDLE hFile,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod); + WINBASEAPI WINBOOL WINAPI SetFilePointerEx(HANDLE hFile,LARGE_INTEGER liDistanceToMove,PLARGE_INTEGER lpNewFilePointer,DWORD dwMoveMethod); + WINBASEAPI WINBOOL WINAPI FindClose(HANDLE hFindFile); + WINBASEAPI WINBOOL WINAPI GetFileTime(HANDLE hFile,LPFILETIME lpCreationTime,LPFILETIME lpLastAccessTime,LPFILETIME lpLastWriteTime); + WINBASEAPI WINBOOL WINAPI SetFileTime(HANDLE hFile,CONST FILETIME *lpCreationTime,CONST FILETIME *lpLastAccessTime,CONST FILETIME *lpLastWriteTime); + WINBASEAPI WINBOOL WINAPI SetFileValidData(HANDLE hFile,LONGLONG ValidDataLength); + WINBASEAPI WINBOOL WINAPI SetFileShortNameA(HANDLE hFile,LPCSTR lpShortName); + WINBASEAPI WINBOOL WINAPI SetFileShortNameW(HANDLE hFile,LPCWSTR lpShortName); + WINBASEAPI WINBOOL WINAPI CloseHandle(HANDLE hObject); + WINBASEAPI WINBOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle,HANDLE hSourceHandle,HANDLE hTargetProcessHandle,LPHANDLE lpTargetHandle,DWORD dwDesiredAccess,WINBOOL bInheritHandle,DWORD dwOptions); + WINBASEAPI WINBOOL WINAPI GetHandleInformation(HANDLE hObject,LPDWORD lpdwFlags); + WINBASEAPI WINBOOL WINAPI SetHandleInformation(HANDLE hObject,DWORD dwMask,DWORD dwFlags); + +#define HANDLE_FLAG_INHERIT 0x1 +#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x2 + +#define HINSTANCE_ERROR 32 + + WINBASEAPI DWORD WINAPI LoadModule(LPCSTR lpModuleName,LPVOID lpParameterBlock); + WINBASEAPI UINT WINAPI WinExec(LPCSTR lpCmdLine,UINT uCmdShow); + WINBASEAPI WINBOOL WINAPI ClearCommBreak(HANDLE hFile); + WINBASEAPI WINBOOL WINAPI ClearCommError(HANDLE hFile,LPDWORD lpErrors,LPCOMSTAT lpStat); + WINBASEAPI WINBOOL WINAPI SetupComm(HANDLE hFile,DWORD dwInQueue,DWORD dwOutQueue); + WINBASEAPI WINBOOL WINAPI EscapeCommFunction(HANDLE hFile,DWORD dwFunc); + WINBASEAPI WINBOOL WINAPI GetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); + WINBASEAPI WINBOOL WINAPI GetCommMask(HANDLE hFile,LPDWORD lpEvtMask); + WINBASEAPI WINBOOL WINAPI GetCommProperties(HANDLE hFile,LPCOMMPROP lpCommProp); + WINBASEAPI WINBOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat); + WINBASEAPI WINBOOL WINAPI GetCommState(HANDLE hFile,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI GetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI PurgeComm(HANDLE hFile,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI SetCommBreak(HANDLE hFile); + WINBASEAPI WINBOOL WINAPI SetCommConfig(HANDLE hCommDev,LPCOMMCONFIG lpCC,DWORD dwSize); + WINBASEAPI WINBOOL WINAPI SetCommMask(HANDLE hFile,DWORD dwEvtMask); + WINBASEAPI WINBOOL WINAPI SetCommState(HANDLE hFile,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI SetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI TransmitCommChar(HANDLE hFile,char cChar); + WINBASEAPI WINBOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD lpEvtMask,LPOVERLAPPED lpOverlapped); + WINBASEAPI DWORD WINAPI SetTapePosition(HANDLE hDevice,DWORD dwPositionMethod,DWORD dwPartition,DWORD dwOffsetLow,DWORD dwOffsetHigh,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI GetTapePosition(HANDLE hDevice,DWORD dwPositionType,LPDWORD lpdwPartition,LPDWORD lpdwOffsetLow,LPDWORD lpdwOffsetHigh); + WINBASEAPI DWORD WINAPI PrepareTape(HANDLE hDevice,DWORD dwOperation,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI EraseTape(HANDLE hDevice,DWORD dwEraseType,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI CreateTapePartition(HANDLE hDevice,DWORD dwPartitionMethod,DWORD dwCount,DWORD dwSize); + WINBASEAPI DWORD WINAPI WriteTapemark(HANDLE hDevice,DWORD dwTapemarkType,DWORD dwTapemarkCount,WINBOOL bImmediate); + WINBASEAPI DWORD WINAPI GetTapeStatus(HANDLE hDevice); + WINBASEAPI DWORD WINAPI GetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPDWORD lpdwSize,LPVOID lpTapeInformation); + +#define GET_TAPE_MEDIA_INFORMATION 0 +#define GET_TAPE_DRIVE_INFORMATION 1 + + WINBASEAPI DWORD WINAPI SetTapeParameters(HANDLE hDevice,DWORD dwOperation,LPVOID lpTapeInformation); + +#define SET_TAPE_MEDIA_INFORMATION 0 +#define SET_TAPE_DRIVE_INFORMATION 1 + + WINBASEAPI WINBOOL WINAPI Beep(DWORD dwFreq,DWORD dwDuration); + WINBASEAPI int WINAPI MulDiv(int nNumber,int nNumerator,int nDenominator); + WINBASEAPI VOID WINAPI GetSystemTime(LPSYSTEMTIME lpSystemTime); + WINBASEAPI VOID WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); + WINBASEAPI WINBOOL WINAPI SetSystemTime(CONST SYSTEMTIME *lpSystemTime); + WINBASEAPI VOID WINAPI GetLocalTime(LPSYSTEMTIME lpSystemTime); + WINBASEAPI WINBOOL WINAPI SetLocalTime(CONST SYSTEMTIME *lpSystemTime); + WINBASEAPI VOID WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo); + WINBASEAPI WINBOOL WINAPI SetSystemFileCacheSize(SIZE_T MinimumFileCacheSize,SIZE_T MaximumFileCacheSize,DWORD Flags); + WINBASEAPI WINBOOL WINAPI GetSystemFileCacheSize(PSIZE_T lpMinimumFileCacheSize,PSIZE_T lpMaximumFileCacheSize,PDWORD lpFlags); + WINBASEAPI WINBOOL WINAPI GetSystemRegistryQuota(PDWORD pdwQuotaAllowed,PDWORD pdwQuotaUsed); + WINBOOL WINAPI GetSystemTimes(LPFILETIME lpIdleTime,LPFILETIME lpKernelTime,LPFILETIME lpUserTime); + WINBASEAPI VOID WINAPI GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo); + WINBASEAPI WINBOOL WINAPI IsProcessorFeaturePresent(DWORD ProcessorFeature); + + typedef struct _TIME_ZONE_INFORMATION { + LONG Bias; + WCHAR StandardName[32]; + SYSTEMTIME StandardDate; + LONG StandardBias; + WCHAR DaylightName[32]; + SYSTEMTIME DaylightDate; + LONG DaylightBias; + } TIME_ZONE_INFORMATION,*PTIME_ZONE_INFORMATION,*LPTIME_ZONE_INFORMATION; + +#ifdef UNICODE +#define FormatMessage FormatMessageW +#else +#define FormatMessage FormatMessageA +#endif + + WINBASEAPI WINBOOL WINAPI SystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpUniversalTime,LPSYSTEMTIME lpLocalTime); + WINBASEAPI WINBOOL WINAPI TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,LPSYSTEMTIME lpLocalTime,LPSYSTEMTIME lpUniversalTime); + WINBASEAPI DWORD WINAPI GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation); + WINBASEAPI WINBOOL WINAPI SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION *lpTimeZoneInformation); + WINBASEAPI WINBOOL WINAPI SystemTimeToFileTime(CONST SYSTEMTIME *lpSystemTime,LPFILETIME lpFileTime); + WINBASEAPI WINBOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *lpFileTime,LPFILETIME lpLocalFileTime); + WINBASEAPI WINBOOL WINAPI LocalFileTimeToFileTime(CONST FILETIME *lpLocalFileTime,LPFILETIME lpFileTime); + WINBASEAPI WINBOOL WINAPI FileTimeToSystemTime(CONST FILETIME *lpFileTime,LPSYSTEMTIME lpSystemTime); + WINBASEAPI LONG WINAPI CompareFileTime(CONST FILETIME *lpFileTime1,CONST FILETIME *lpFileTime2); + WINBASEAPI WINBOOL WINAPI FileTimeToDosDateTime(CONST FILETIME *lpFileTime,LPWORD lpFatDate,LPWORD lpFatTime); + WINBASEAPI WINBOOL WINAPI DosDateTimeToFileTime(WORD wFatDate,WORD wFatTime,LPFILETIME lpFileTime); + WINBASEAPI DWORD WINAPI GetTickCount(VOID); + WINBASEAPI WINBOOL WINAPI SetSystemTimeAdjustment(DWORD dwTimeAdjustment,WINBOOL bTimeAdjustmentDisabled); + WINBASEAPI WINBOOL WINAPI GetSystemTimeAdjustment(PDWORD lpTimeAdjustment,PDWORD lpTimeIncrement,PBOOL lpTimeAdjustmentDisabled); + WINBASEAPI DWORD WINAPI FormatMessageA(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPSTR lpBuffer,DWORD nSize,va_list *Arguments); + WINBASEAPI DWORD WINAPI FormatMessageW(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPWSTR lpBuffer,DWORD nSize,va_list *Arguments); + +#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x100 +#define FORMAT_MESSAGE_IGNORE_INSERTS 0x200 +#define FORMAT_MESSAGE_FROM_STRING 0x400 +#define FORMAT_MESSAGE_FROM_HMODULE 0x800 +#define FORMAT_MESSAGE_FROM_SYSTEM 0x1000 +#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x2000 +#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0xff + +#ifdef UNICODE +#define CreateMailslot CreateMailslotW +#define EncryptFile EncryptFileW +#define DecryptFile DecryptFileW +#define FileEncryptionStatus FileEncryptionStatusW +#else +#define CreateMailslot CreateMailslotA +#define EncryptFile EncryptFileA +#define DecryptFile DecryptFileA +#define FileEncryptionStatus FileEncryptionStatusA +#endif + + WINBASEAPI WINBOOL WINAPI CreatePipe(PHANDLE hReadPipe,PHANDLE hWritePipe,LPSECURITY_ATTRIBUTES lpPipeAttributes,DWORD nSize); + WINBASEAPI WINBOOL WINAPI ConnectNamedPipe(HANDLE hNamedPipe,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI DisconnectNamedPipe(HANDLE hNamedPipe); + WINBASEAPI WINBOOL WINAPI SetNamedPipeHandleState(HANDLE hNamedPipe,LPDWORD lpMode,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout); + WINBASEAPI WINBOOL WINAPI GetNamedPipeInfo(HANDLE hNamedPipe,LPDWORD lpFlags,LPDWORD lpOutBufferSize,LPDWORD lpInBufferSize,LPDWORD lpMaxInstances); + WINBASEAPI WINBOOL WINAPI PeekNamedPipe(HANDLE hNamedPipe,LPVOID lpBuffer,DWORD nBufferSize,LPDWORD lpBytesRead,LPDWORD lpTotalBytesAvail,LPDWORD lpBytesLeftThisMessage); + WINBASEAPI WINBOOL WINAPI TransactNamedPipe(HANDLE hNamedPipe,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,LPOVERLAPPED lpOverlapped); + WINBASEAPI HANDLE WINAPI CreateMailslotA(LPCSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI HANDLE WINAPI CreateMailslotW(LPCWSTR lpName,DWORD nMaxMessageSize,DWORD lReadTimeout,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI GetMailslotInfo(HANDLE hMailslot,LPDWORD lpMaxMessageSize,LPDWORD lpNextSize,LPDWORD lpMessageCount,LPDWORD lpReadTimeout); + WINBASEAPI WINBOOL WINAPI SetMailslotInfo(HANDLE hMailslot,DWORD lReadTimeout); + WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap); + WINBASEAPI WINBOOL WINAPI FlushViewOfFile(LPCVOID lpBaseAddress,SIZE_T dwNumberOfBytesToFlush); + WINBASEAPI WINBOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress); + WINADVAPI WINBOOL WINAPI EncryptFileA(LPCSTR lpFileName); + WINADVAPI WINBOOL WINAPI EncryptFileW(LPCWSTR lpFileName); + WINADVAPI WINBOOL WINAPI DecryptFileA(LPCSTR lpFileName,DWORD dwReserved); + WINADVAPI WINBOOL WINAPI DecryptFileW(LPCWSTR lpFileName,DWORD dwReserved); + +#define FILE_ENCRYPTABLE 0 +#define FILE_IS_ENCRYPTED 1 +#define FILE_SYSTEM_ATTR 2 +#define FILE_ROOT_DIR 3 +#define FILE_SYSTEM_DIR 4 +#define FILE_UNKNOWN 5 +#define FILE_SYSTEM_NOT_SUPPORT 6 +#define FILE_USER_DISALLOWED 7 +#define FILE_READ_ONLY 8 +#define FILE_DIR_DISALLOWED 9 + + WINADVAPI WINBOOL WINAPI FileEncryptionStatusA(LPCSTR lpFileName,LPDWORD lpStatus); + WINADVAPI WINBOOL WINAPI FileEncryptionStatusW(LPCWSTR lpFileName,LPDWORD lpStatus); + +#define EFS_USE_RECOVERY_KEYS (0x1) + + typedef DWORD (WINAPI *PFE_EXPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,ULONG ulLength); + typedef DWORD (WINAPI *PFE_IMPORT_FUNC)(PBYTE pbData,PVOID pvCallbackContext,PULONG ulLength); + +#define CREATE_FOR_IMPORT (1) +#define CREATE_FOR_DIR (2) +#define OVERWRITE_HIDDEN (4) + +#ifdef UNICODE +#define OpenEncryptedFileRaw OpenEncryptedFileRawW +#define lstrcmp lstrcmpW +#define lstrcmpi lstrcmpiW +#define lstrcpyn lstrcpynW +#define lstrcpy lstrcpyW +#define lstrcat lstrcatW +#define lstrlen lstrlenW +#else +#define OpenEncryptedFileRaw OpenEncryptedFileRawA +#define lstrcmp lstrcmpA +#define lstrcmpi lstrcmpiA +#define lstrcpyn lstrcpynA +#define lstrcpy lstrcpyA +#define lstrcat lstrcatA +#define lstrlen lstrlenA +#endif + + WINADVAPI DWORD WINAPI OpenEncryptedFileRawA(LPCSTR lpFileName,ULONG ulFlags,PVOID *pvContext); + WINADVAPI DWORD WINAPI OpenEncryptedFileRawW(LPCWSTR lpFileName,ULONG ulFlags,PVOID *pvContext); + WINADVAPI DWORD WINAPI ReadEncryptedFileRaw(PFE_EXPORT_FUNC pfExportCallback,PVOID pvCallbackContext,PVOID pvContext); + WINADVAPI DWORD WINAPI WriteEncryptedFileRaw(PFE_IMPORT_FUNC pfImportCallback,PVOID pvCallbackContext,PVOID pvContext); + WINADVAPI VOID WINAPI CloseEncryptedFileRaw(PVOID pvContext); + WINBASEAPI int WINAPI lstrcmpA(LPCSTR lpString1,LPCSTR lpString2); + WINBASEAPI int WINAPI lstrcmpW(LPCWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI int WINAPI lstrcmpiA(LPCSTR lpString1,LPCSTR lpString2); + WINBASEAPI int WINAPI lstrcmpiW(LPCWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI LPSTR WINAPI lstrcpynA(LPSTR lpString1,LPCSTR lpString2,int iMaxLength); + WINBASEAPI LPWSTR WINAPI lstrcpynW(LPWSTR lpString1,LPCWSTR lpString2,int iMaxLength); + WINBASEAPI LPSTR WINAPI lstrcpyA(LPSTR lpString1,LPCSTR lpString2); + WINBASEAPI LPWSTR WINAPI lstrcpyW(LPWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI LPSTR WINAPI lstrcatA(LPSTR lpString1,LPCSTR lpString2); + WINBASEAPI LPWSTR WINAPI lstrcatW(LPWSTR lpString1,LPCWSTR lpString2); + WINBASEAPI int WINAPI lstrlenA(LPCSTR lpString); + WINBASEAPI int WINAPI lstrlenW(LPCWSTR lpString); + WINBASEAPI HFILE WINAPI OpenFile(LPCSTR lpFileName,LPOFSTRUCT lpReOpenBuff,UINT uStyle); + WINBASEAPI HFILE WINAPI _lopen(LPCSTR lpPathName,int iReadWrite); + WINBASEAPI HFILE WINAPI _lcreat(LPCSTR lpPathName,int iAttribute); + WINBASEAPI UINT WINAPI _lread(HFILE hFile,LPVOID lpBuffer,UINT uBytes); + WINBASEAPI UINT WINAPI _lwrite(HFILE hFile,LPCCH lpBuffer,UINT uBytes); + WINBASEAPI long WINAPI _hread(HFILE hFile,LPVOID lpBuffer,long lBytes); + WINBASEAPI long WINAPI _hwrite(HFILE hFile,LPCCH lpBuffer,long lBytes); + WINBASEAPI HFILE WINAPI _lclose(HFILE hFile); + WINBASEAPI LONG WINAPI _llseek(HFILE hFile,LONG lOffset,int iOrigin); + WINADVAPI WINBOOL WINAPI IsTextUnicode(CONST VOID *lpv,int iSize,LPINT lpiResult); + +#define FLS_OUT_OF_INDEXES ((DWORD)0xffffffff) + + WINBASEAPI DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); + WINBASEAPI PVOID WINAPI FlsGetValue(DWORD dwFlsIndex); + WINBASEAPI WINBOOL WINAPI FlsSetValue(DWORD dwFlsIndex,PVOID lpFlsData); + WINBASEAPI WINBOOL WINAPI FlsFree(DWORD dwFlsIndex); + +#define TLS_OUT_OF_INDEXES ((DWORD)0xffffffff) + + WINBASEAPI DWORD WINAPI TlsAlloc(VOID); + WINBASEAPI LPVOID WINAPI TlsGetValue(DWORD dwTlsIndex); + WINBASEAPI WINBOOL WINAPI TlsSetValue(DWORD dwTlsIndex,LPVOID lpTlsValue); + WINBASEAPI WINBOOL WINAPI TlsFree(DWORD dwTlsIndex); + + typedef VOID (WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped); + + WINBASEAPI DWORD WINAPI SleepEx(DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI DWORD WINAPI WaitForSingleObjectEx(HANDLE hHandle,DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI DWORD WINAPI WaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *lpHandles,WINBOOL bWaitAll,DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI DWORD WINAPI SignalObjectAndWait(HANDLE hObjectToSignal,HANDLE hObjectToWaitOn,DWORD dwMilliseconds,WINBOOL bAlertable); + WINBASEAPI WINBOOL WINAPI ReadFileEx(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINBASEAPI WINBOOL WINAPI WriteFileEx(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINBASEAPI WINBOOL WINAPI BackupRead(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); + WINBASEAPI WINBOOL WINAPI BackupSeek(HANDLE hFile,DWORD dwLowBytesToSeek,DWORD dwHighBytesToSeek,LPDWORD lpdwLowByteSeeked,LPDWORD lpdwHighByteSeeked,LPVOID *lpContext); + WINBASEAPI WINBOOL WINAPI BackupWrite(HANDLE hFile,LPBYTE lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,WINBOOL bAbort,WINBOOL bProcessSecurity,LPVOID *lpContext); + + typedef struct _WIN32_STREAM_ID { + DWORD dwStreamId; + DWORD dwStreamAttributes; + LARGE_INTEGER Size; + DWORD dwStreamNameSize; + WCHAR cStreamName[ANYSIZE_ARRAY]; + } WIN32_STREAM_ID,*LPWIN32_STREAM_ID; + +#define BACKUP_INVALID 0x0 +#define BACKUP_DATA 0x1 +#define BACKUP_EA_DATA 0x2 +#define BACKUP_SECURITY_DATA 0x3 +#define BACKUP_ALTERNATE_DATA 0x4 +#define BACKUP_LINK 0x5 +#define BACKUP_PROPERTY_DATA 0x6 +#define BACKUP_OBJECT_ID 0x7 +#define BACKUP_REPARSE_DATA 0x8 +#define BACKUP_SPARSE_BLOCK 0x9 + +#define STREAM_NORMAL_ATTRIBUTE 0x0 +#define STREAM_MODIFIED_WHEN_READ 0x1 +#define STREAM_CONTAINS_SECURITY 0x2 +#define STREAM_CONTAINS_PROPERTIES 0x4 +#define STREAM_SPARSE_ATTRIBUTE 0x8 + + WINBASEAPI WINBOOL WINAPI ReadFileScatter(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToRead,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); + WINBASEAPI WINBOOL WINAPI WriteFileGather(HANDLE hFile,FILE_SEGMENT_ELEMENT aSegmentArray[],DWORD nNumberOfBytesToWrite,LPDWORD lpReserved,LPOVERLAPPED lpOverlapped); + +#define STARTF_USESHOWWINDOW 0x1 +#define STARTF_USESIZE 0x2 +#define STARTF_USEPOSITION 0x4 +#define STARTF_USECOUNTCHARS 0x8 +#define STARTF_USEFILLATTRIBUTE 0x10 +#define STARTF_RUNFULLSCREEN 0x20 +#define STARTF_FORCEONFEEDBACK 0x40 +#define STARTF_FORCEOFFFEEDBACK 0x80 +#define STARTF_USESTDHANDLES 0x100 + +#define STARTF_USEHOTKEY 0x200 + + typedef struct _STARTUPINFOA { + DWORD cb; + LPSTR lpReserved; + LPSTR lpDesktop; + LPSTR lpTitle; + DWORD dwX; + DWORD dwY; + DWORD dwXSize; + DWORD dwYSize; + DWORD dwXCountChars; + DWORD dwYCountChars; + DWORD dwFillAttribute; + DWORD dwFlags; + WORD wShowWindow; + WORD cbReserved2; + LPBYTE lpReserved2; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + } STARTUPINFOA,*LPSTARTUPINFOA; + + typedef struct _STARTUPINFOW { + DWORD cb; + LPWSTR lpReserved; + LPWSTR lpDesktop; + LPWSTR lpTitle; + DWORD dwX; + DWORD dwY; + DWORD dwXSize; + DWORD dwYSize; + DWORD dwXCountChars; + DWORD dwYCountChars; + DWORD dwFillAttribute; + DWORD dwFlags; + WORD wShowWindow; + WORD cbReserved2; + LPBYTE lpReserved2; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + } STARTUPINFOW,*LPSTARTUPINFOW; + +#ifdef UNICODE + typedef STARTUPINFOW STARTUPINFO; + typedef LPSTARTUPINFOW LPSTARTUPINFO; +#else + typedef STARTUPINFOA STARTUPINFO; + typedef LPSTARTUPINFOA LPSTARTUPINFO; +#endif + +#define SHUTDOWN_NORETRY 0x1 + + typedef struct _WIN32_FIND_DATAA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + CHAR cFileName[MAX_PATH]; + CHAR cAlternateFileName[14]; + } WIN32_FIND_DATAA,*PWIN32_FIND_DATAA,*LPWIN32_FIND_DATAA; + + typedef struct _WIN32_FIND_DATAW { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + WCHAR cFileName[MAX_PATH]; + WCHAR cAlternateFileName[14]; + } WIN32_FIND_DATAW,*PWIN32_FIND_DATAW,*LPWIN32_FIND_DATAW; + +#ifdef UNICODE + typedef WIN32_FIND_DATAW WIN32_FIND_DATA; + typedef PWIN32_FIND_DATAW PWIN32_FIND_DATA; + typedef LPWIN32_FIND_DATAW LPWIN32_FIND_DATA; +#else + typedef WIN32_FIND_DATAA WIN32_FIND_DATA; + typedef PWIN32_FIND_DATAA PWIN32_FIND_DATA; + typedef LPWIN32_FIND_DATAA LPWIN32_FIND_DATA; +#endif + + typedef struct _WIN32_FILE_ATTRIBUTE_DATA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + } WIN32_FILE_ATTRIBUTE_DATA,*LPWIN32_FILE_ATTRIBUTE_DATA; + +#ifdef UNICODE +#define CreateMutex CreateMutexW +#define OpenMutex OpenMutexW +#define CreateEvent CreateEventW +#define OpenEvent OpenEventW +#define CreateSemaphore CreateSemaphoreW +#define OpenSemaphore OpenSemaphoreW +#else +#define CreateMutex CreateMutexA +#define OpenMutex OpenMutexA +#define CreateEvent CreateEventA +#define OpenEvent OpenEventA +#define CreateSemaphore CreateSemaphoreA +#define OpenSemaphore OpenSemaphoreA +#endif + + WINBASEAPI HANDLE WINAPI CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes,WINBOOL bInitialOwner,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenMutexA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenMutexW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes,WINBOOL bManualReset,WINBOOL bInitialState,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenEventA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenEventW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenSemaphoreA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenSemaphoreW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + + typedef VOID (WINAPI *PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue); + +#ifdef UNICODE +#define CreateWaitableTimer CreateWaitableTimerW +#define OpenWaitableTimer OpenWaitableTimerW +#define CreateFileMapping CreateFileMappingW +#define OpenFileMapping OpenFileMappingW +#define GetLogicalDriveStrings GetLogicalDriveStringsW +#define LoadLibrary LoadLibraryW +#define LoadLibraryEx LoadLibraryExW +#define GetModuleFileName GetModuleFileNameW +#define GetModuleHandle GetModuleHandleW +#else +#define CreateWaitableTimer CreateWaitableTimerA +#define OpenWaitableTimer OpenWaitableTimerA +#define CreateFileMapping CreateFileMappingA +#define OpenFileMapping OpenFileMappingA +#define GetLogicalDriveStrings GetLogicalDriveStringsA +#define LoadLibrary LoadLibraryA +#define LoadLibraryEx LoadLibraryExA +#define GetModuleFileName GetModuleFileNameA +#define GetModuleHandle GetModuleHandleA +#endif + + WINBASEAPI HANDLE WINAPI CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCSTR lpTimerName); + WINBASEAPI HANDLE WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes,WINBOOL bManualReset,LPCWSTR lpTimerName); + WINBASEAPI HANDLE WINAPI OpenWaitableTimerA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpTimerName); + WINBASEAPI HANDLE WINAPI OpenWaitableTimerW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpTimerName); + WINBASEAPI WINBOOL WINAPI SetWaitableTimer(HANDLE hTimer,const LARGE_INTEGER *lpDueTime,LONG lPeriod,PTIMERAPCROUTINE pfnCompletionRoutine,LPVOID lpArgToCompletionRoutine,WINBOOL fResume); + WINBASEAPI WINBOOL WINAPI CancelWaitableTimer(HANDLE hTimer); + WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenFileMappingA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenFileMappingW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI DWORD WINAPI GetLogicalDriveStringsA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetLogicalDriveStringsW(DWORD nBufferLength,LPWSTR lpBuffer); + + typedef enum _MEMORY_RESOURCE_NOTIFICATION_TYPE { + LowMemoryResourceNotification,HighMemoryResourceNotification + } MEMORY_RESOURCE_NOTIFICATION_TYPE; + + WINBASEAPI HANDLE WINAPI CreateMemoryResourceNotification(MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType); + WINBASEAPI WINBOOL WINAPI QueryMemoryResourceNotification(HANDLE ResourceNotificationHandle,PBOOL ResourceState); + WINBASEAPI HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName); + WINBASEAPI HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName); + WINBASEAPI HMODULE WINAPI LoadLibraryExA(LPCSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); + WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags); + +#define DONT_RESOLVE_DLL_REFERENCES 0x1 +#define LOAD_LIBRARY_AS_DATAFILE 0x2 +#define LOAD_WITH_ALTERED_SEARCH_PATH 0x8 +#define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x10 +#define LOAD_LINRARY_AS_IMAGE_RESOURCE 0x20 +#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x40 + + WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule,LPCH lpFilename,DWORD nSize); + WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE hModule,LPWCH lpFilename,DWORD nSize); + WINBASEAPI HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName); + WINBASEAPI HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName); + +#ifndef RC_INVOKED +#define GET_MODULE_HANDLE_EX_FLAG_PIN (0x1) +#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT (0x2) +#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS (0x4) + + typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXA)(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); + typedef WINBOOL (WINAPI *PGET_MODULE_HANDLE_EXW)(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); + +#ifdef UNICODE +#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXW +#define GetModuleHandleEx GetModuleHandleExW +#else +#define PGET_MODULE_HANDLE_EX PGET_MODULE_HANDLE_EXA +#define GetModuleHandleEx GetModuleHandleExA +#endif + + WINBASEAPI WINBOOL WINAPI GetModuleHandleExA(DWORD dwFlags,LPCSTR lpModuleName,HMODULE *phModule); + WINBASEAPI WINBOOL WINAPI GetModuleHandleExW(DWORD dwFlags,LPCWSTR lpModuleName,HMODULE *phModule); +#endif + +#ifdef UNICODE +#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathW +#define CreateProcess CreateProcessW +#define FatalAppExit FatalAppExitW +#define GetStartupInfo GetStartupInfoW +#define GetCommandLine GetCommandLineW +#define GetEnvironmentVariable GetEnvironmentVariableW +#define SetEnvironmentVariable SetEnvironmentVariableW +#define ExpandEnvironmentStrings ExpandEnvironmentStringsW +#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableW +#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableW +#define OutputDebugString OutputDebugStringW +#define FindResource FindResourceW +#define FindResourceEx FindResourceExW +#else +#define NeedCurrentDirectoryForExePath NeedCurrentDirectoryForExePathA +#define CreateProcess CreateProcessA +#define FatalAppExit FatalAppExitA +#define GetStartupInfo GetStartupInfoA +#define GetCommandLine GetCommandLineA +#define GetEnvironmentVariable GetEnvironmentVariableA +#define SetEnvironmentVariable SetEnvironmentVariableA +#define ExpandEnvironmentStrings ExpandEnvironmentStringsA +#define GetFirmwareEnvironmentVariable GetFirmwareEnvironmentVariableA +#define SetFirmwareEnvironmentVariable SetFirmwareEnvironmentVariableA +#define OutputDebugString OutputDebugStringA +#define FindResource FindResourceA +#define FindResourceEx FindResourceExA +#endif + + WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathA(LPCSTR ExeName); + WINBASEAPI WINBOOL WINAPI NeedCurrentDirectoryForExePathW(LPCWSTR ExeName); + WINBASEAPI WINBOOL WINAPI CreateProcessA(LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINBASEAPI WINBOOL WINAPI CreateProcessW(LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameA(LPCSTR lpDnsFQHostname,ULONG ulFlags); + WINBASEAPI DWORD WINAPI AddLocalAlternateComputerNameW(LPCWSTR lpDnsFQHostname,ULONG ulFlags); + WINBASEAPI WINBOOL WINAPI SetProcessShutdownParameters(DWORD dwLevel,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI GetProcessShutdownParameters(LPDWORD lpdwLevel,LPDWORD lpdwFlags); + WINBASEAPI DWORD WINAPI GetProcessVersion(DWORD ProcessId); + WINBASEAPI VOID WINAPI FatalAppExitA(UINT uAction,LPCSTR lpMessageText); + WINBASEAPI VOID WINAPI FatalAppExitW(UINT uAction,LPCWSTR lpMessageText); + WINBASEAPI VOID WINAPI GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo); + WINBASEAPI VOID WINAPI GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo); + WINBASEAPI LPSTR WINAPI GetCommandLineA(VOID); + WINBASEAPI LPWSTR WINAPI GetCommandLineW(VOID); + WINBASEAPI DWORD WINAPI GetEnvironmentVariableA(LPCSTR lpName,LPSTR lpBuffer,DWORD nSize); + WINBASEAPI DWORD WINAPI GetEnvironmentVariableW(LPCWSTR lpName,LPWSTR lpBuffer,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableA(LPCSTR lpName,LPCSTR lpValue); + WINBASEAPI WINBOOL WINAPI SetEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpValue); + WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsA(LPCSTR lpSrc,LPSTR lpDst,DWORD nSize); + WINBASEAPI DWORD WINAPI ExpandEnvironmentStringsW(LPCWSTR lpSrc,LPWSTR lpDst,DWORD nSize); + WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pBuffer,DWORD nSize); + WINBASEAPI DWORD WINAPI GetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pBuffer,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableA(LPCSTR lpName,LPCSTR lpGuid,PVOID pValue,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetFirmwareEnvironmentVariableW(LPCWSTR lpName,LPCWSTR lpGuid,PVOID pValue,DWORD nSize); + WINBASEAPI VOID WINAPI OutputDebugStringA(LPCSTR lpOutputString); + WINBASEAPI VOID WINAPI OutputDebugStringW(LPCWSTR lpOutputString); + WINBASEAPI HRSRC WINAPI FindResourceA(HMODULE hModule,LPCSTR lpName,LPCSTR lpType); + WINBASEAPI HRSRC WINAPI FindResourceW(HMODULE hModule,LPCWSTR lpName,LPCWSTR lpType); + WINBASEAPI HRSRC WINAPI FindResourceExA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage); + WINBASEAPI HRSRC WINAPI FindResourceExW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage); + +#ifdef UNICODE +#define ENUMRESTYPEPROC ENUMRESTYPEPROCW +#define ENUMRESNAMEPROC ENUMRESNAMEPROCW +#define ENUMRESLANGPROC ENUMRESLANGPROCW +#define EnumResourceTypes EnumResourceTypesW +#define EnumResourceNames EnumResourceNamesW +#define EnumResourceLanguages EnumResourceLanguagesW +#define BeginUpdateResource BeginUpdateResourceW +#define UpdateResource UpdateResourceW +#define EndUpdateResource EndUpdateResourceW +#define GlobalAddAtom GlobalAddAtomW +#define GlobalFindAtom GlobalFindAtomW +#define GlobalGetAtomName GlobalGetAtomNameW +#define AddAtom AddAtomW +#define FindAtom FindAtomW +#define GetAtomName GetAtomNameW +#define GetProfileInt GetProfileIntW +#define GetProfileString GetProfileStringW +#define WriteProfileString WriteProfileStringW +#define GetProfileSection GetProfileSectionW +#define WriteProfileSection WriteProfileSectionW +#define GetPrivateProfileInt GetPrivateProfileIntW +#define GetPrivateProfileString GetPrivateProfileStringW +#define WritePrivateProfileString WritePrivateProfileStringW +#define GetPrivateProfileSection GetPrivateProfileSectionW +#define WritePrivateProfileSection WritePrivateProfileSectionW +#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesW +#define GetPrivateProfileStruct GetPrivateProfileStructW +#define WritePrivateProfileStruct WritePrivateProfileStructW +#define GetDriveType GetDriveTypeW +#define GetSystemDirectory GetSystemDirectoryW +#define GetTempPath GetTempPathW +#define GetTempFileName GetTempFileNameW +#define GetWindowsDirectory GetWindowsDirectoryW +#define GetSystemWindowsDirectory GetSystemWindowsDirectoryW +#define AddLocalAlternateComputerName AddLocalAlternateComputerNameW +#else +#define ENUMRESTYPEPROC ENUMRESTYPEPROCA +#define ENUMRESNAMEPROC ENUMRESNAMEPROCA +#define ENUMRESLANGPROC ENUMRESLANGPROCA +#define EnumResourceTypes EnumResourceTypesA +#define EnumResourceNames EnumResourceNamesA +#define EnumResourceLanguages EnumResourceLanguagesA +#define BeginUpdateResource BeginUpdateResourceA +#define UpdateResource UpdateResourceA +#define EndUpdateResource EndUpdateResourceA +#define GlobalAddAtom GlobalAddAtomA +#define GlobalFindAtom GlobalFindAtomA +#define GlobalGetAtomName GlobalGetAtomNameA +#define AddAtom AddAtomA +#define FindAtom FindAtomA +#define GetAtomName GetAtomNameA +#define GetProfileInt GetProfileIntA +#define GetProfileString GetProfileStringA +#define WriteProfileString WriteProfileStringA +#define GetProfileSection GetProfileSectionA +#define WriteProfileSection WriteProfileSectionA +#define GetPrivateProfileInt GetPrivateProfileIntA +#define GetPrivateProfileString GetPrivateProfileStringA +#define WritePrivateProfileString WritePrivateProfileStringA +#define GetPrivateProfileSection GetPrivateProfileSectionA +#define WritePrivateProfileSection WritePrivateProfileSectionA +#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesA +#define GetPrivateProfileStruct GetPrivateProfileStructA +#define WritePrivateProfileStruct WritePrivateProfileStructA +#define GetDriveType GetDriveTypeA +#define GetSystemDirectory GetSystemDirectoryA +#define GetTempPath GetTempPathA +#define GetTempFileName GetTempFileNameA +#define GetWindowsDirectory GetWindowsDirectoryA +#define GetSystemWindowsDirectory GetSystemWindowsDirectoryA +#define AddLocalAlternateComputerName AddLocalAlternateComputerNameA +#endif + + typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCA)(HMODULE hModule,LPSTR lpType,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESTYPEPROCW)(HMODULE hModule,LPWSTR lpType,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCA)(HMODULE hModule,LPCSTR lpType,LPSTR lpName,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESNAMEPROCW)(HMODULE hModule,LPCWSTR lpType,LPWSTR lpName,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESLANGPROCA)(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LONG_PTR lParam); + typedef WINBOOL (CALLBACK *ENUMRESLANGPROCW)(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LONG_PTR lParam); + + WINBASEAPI WINBOOL WINAPI EnumResourceTypesA(HMODULE hModule,ENUMRESTYPEPROCA lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceTypesW(HMODULE hModule,ENUMRESTYPEPROCW lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceNamesA(HMODULE hModule,LPCSTR lpType,ENUMRESNAMEPROCA lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceNamesW(HMODULE hModule,LPCWSTR lpType,ENUMRESNAMEPROCW lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,ENUMRESLANGPROCA lpEnumFunc,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumResourceLanguagesW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,ENUMRESLANGPROCW lpEnumFunc,LONG_PTR lParam); + WINBASEAPI HANDLE WINAPI BeginUpdateResourceA(LPCSTR pFileName,WINBOOL bDeleteExistingResources); + WINBASEAPI HANDLE WINAPI BeginUpdateResourceW(LPCWSTR pFileName,WINBOOL bDeleteExistingResources); + WINBASEAPI WINBOOL WINAPI UpdateResourceA(HANDLE hUpdate,LPCSTR lpType,LPCSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); + WINBASEAPI WINBOOL WINAPI UpdateResourceW(HANDLE hUpdate,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage,LPVOID lpData,DWORD cb); + WINBASEAPI WINBOOL WINAPI EndUpdateResourceA(HANDLE hUpdate,WINBOOL fDiscard); + WINBASEAPI WINBOOL WINAPI EndUpdateResourceW(HANDLE hUpdate,WINBOOL fDiscard); + WINBASEAPI ATOM WINAPI GlobalAddAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI GlobalAddAtomW(LPCWSTR lpString); + WINBASEAPI ATOM WINAPI GlobalFindAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI GlobalFindAtomW(LPCWSTR lpString); + WINBASEAPI UINT WINAPI GlobalGetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); + WINBASEAPI UINT WINAPI GlobalGetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); + WINBASEAPI ATOM WINAPI AddAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI AddAtomW(LPCWSTR lpString); + WINBASEAPI ATOM WINAPI FindAtomA(LPCSTR lpString); + WINBASEAPI ATOM WINAPI FindAtomW(LPCWSTR lpString); + WINBASEAPI UINT WINAPI GetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize); + WINBASEAPI UINT WINAPI GetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize); + WINBASEAPI UINT WINAPI GetProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault); + WINBASEAPI UINT WINAPI GetProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault); + WINBASEAPI DWORD WINAPI GetProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize); + WINBASEAPI DWORD WINAPI GetProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize); + WINBASEAPI WINBOOL WINAPI WriteProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString); + WINBASEAPI WINBOOL WINAPI WriteProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString); + WINBASEAPI DWORD WINAPI GetProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize); + WINBASEAPI DWORD WINAPI GetProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize); + WINBASEAPI WINBOOL WINAPI WriteProfileSectionA(LPCSTR lpAppName,LPCSTR lpString); + WINBASEAPI WINBOOL WINAPI WriteProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString); + WINBASEAPI UINT WINAPI GetPrivateProfileIntA(LPCSTR lpAppName,LPCSTR lpKeyName,INT nDefault,LPCSTR lpFileName); + WINBASEAPI UINT WINAPI GetPrivateProfileIntW(LPCWSTR lpAppName,LPCWSTR lpKeyName,INT nDefault,LPCWSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpDefault,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpDefault,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringA(LPCSTR lpAppName,LPCSTR lpKeyName,LPCSTR lpString,LPCSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStringW(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpString,LPCWSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionA(LPCSTR lpAppName,LPSTR lpReturnedString,DWORD nSize,LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionW(LPCWSTR lpAppName,LPWSTR lpReturnedString,DWORD nSize,LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionA(LPCSTR lpAppName,LPCSTR lpString,LPCSTR lpFileName); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileSectionW(LPCWSTR lpAppName,LPCWSTR lpString,LPCWSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesA(LPSTR lpszReturnBuffer,DWORD nSize,LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetPrivateProfileSectionNamesW(LPWSTR lpszReturnBuffer,DWORD nSize,LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); + WINBASEAPI WINBOOL WINAPI GetPrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructA(LPCSTR lpszSection,LPCSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCSTR szFile); + WINBASEAPI WINBOOL WINAPI WritePrivateProfileStructW(LPCWSTR lpszSection,LPCWSTR lpszKey,LPVOID lpStruct,UINT uSizeStruct,LPCWSTR szFile); + WINBASEAPI UINT WINAPI GetDriveTypeA(LPCSTR lpRootPathName); + WINBASEAPI UINT WINAPI GetDriveTypeW(LPCWSTR lpRootPathName); + WINBASEAPI UINT WINAPI GetSystemDirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemDirectoryW(LPWSTR lpBuffer,UINT uSize); + WINBASEAPI DWORD WINAPI GetTempPathA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetTempPathW(DWORD nBufferLength,LPWSTR lpBuffer); + WINBASEAPI UINT WINAPI GetTempFileNameA(LPCSTR lpPathName,LPCSTR lpPrefixString,UINT uUnique,LPSTR lpTempFileName); + WINBASEAPI UINT WINAPI GetTempFileNameW(LPCWSTR lpPathName,LPCWSTR lpPrefixString,UINT uUnique,LPWSTR lpTempFileName); + WINBASEAPI UINT WINAPI GetWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemWindowsDirectoryW(LPWSTR lpBuffer,UINT uSize); + +#ifndef RC_INVOKED +#ifdef UNICODE +#define GetSystemWow64Directory GetSystemWow64DirectoryW +#else +#define GetSystemWow64Directory GetSystemWow64DirectoryA +#endif + + WINBASEAPI UINT WINAPI GetSystemWow64DirectoryA(LPSTR lpBuffer,UINT uSize); + WINBASEAPI UINT WINAPI GetSystemWow64DirectoryW(LPWSTR lpBuffer,UINT uSize); + WINBASEAPI BOOLEAN WINAPI Wow64EnableWow64FsRedirection(BOOLEAN Wow64FsEnableRedirection); + WINBASEAPI WINBOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue); + WINBASEAPI WINBOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OlValue); + + typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_A)(LPSTR lpBuffer,UINT uSize); + typedef UINT (WINAPI *PGET_SYSTEM_WOW64_DIRECTORY_W)(LPWSTR lpBuffer,UINT uSize); + +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A "GetSystemWow64DirectoryA" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W L"GetSystemWow64DirectoryA" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T TEXT("GetSystemWow64DirectoryA") +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A "GetSystemWow64DirectoryW" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W L"GetSystemWow64DirectoryW" +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T TEXT("GetSystemWow64DirectoryW") + +#ifdef UNICODE +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_W_A +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_W_W +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_W_T +#else +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A GET_SYSTEM_WOW64_DIRECTORY_NAME_A_A +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_W GET_SYSTEM_WOW64_DIRECTORY_NAME_A_W +#define GET_SYSTEM_WOW64_DIRECTORY_NAME_T_T GET_SYSTEM_WOW64_DIRECTORY_NAME_A_T +#endif +#endif + +#ifdef UNICODE +#define SetCurrentDirectory SetCurrentDirectoryW +#define GetCurrentDirectory GetCurrentDirectoryW +#define SetDllDirectory SetDllDirectoryW +#define GetDllDirectory GetDllDirectoryW +#define GetDiskFreeSpace GetDiskFreeSpaceW +#define GetDiskFreeSpaceEx GetDiskFreeSpaceExW +#define CreateDirectory CreateDirectoryW +#define CreateDirectoryEx CreateDirectoryExW +#define RemoveDirectory RemoveDirectoryW +#define GetFullPathName GetFullPathNameW +#define DefineDosDevice DefineDosDeviceW +#define QueryDosDevice QueryDosDeviceW +#define CreateFile CreateFileW +#define SetFileAttributes SetFileAttributesW +#define GetFileAttributes GetFileAttributesW +#else +#define SetCurrentDirectory SetCurrentDirectoryA +#define GetCurrentDirectory GetCurrentDirectoryA +#define SetDllDirectory SetDllDirectoryA +#define GetDllDirectory GetDllDirectoryA +#define GetDiskFreeSpace GetDiskFreeSpaceA +#define GetDiskFreeSpaceEx GetDiskFreeSpaceExA +#define CreateDirectory CreateDirectoryA +#define CreateDirectoryEx CreateDirectoryExA +#define RemoveDirectory RemoveDirectoryA +#define GetFullPathName GetFullPathNameA +#define DefineDosDevice DefineDosDeviceA +#define QueryDosDevice QueryDosDeviceA +#define CreateFile CreateFileA +#define SetFileAttributes SetFileAttributesA +#define GetFileAttributes GetFileAttributesA +#endif + + WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryA(LPCSTR lpPathName); + WINBASEAPI WINBOOL WINAPI SetCurrentDirectoryW(LPCWSTR lpPathName); + WINBASEAPI DWORD WINAPI GetCurrentDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetCurrentDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI SetDllDirectoryA(LPCSTR lpPathName); + WINBASEAPI WINBOOL WINAPI SetDllDirectoryW(LPCWSTR lpPathName); + WINBASEAPI DWORD WINAPI GetDllDirectoryA(DWORD nBufferLength,LPSTR lpBuffer); + WINBASEAPI DWORD WINAPI GetDllDirectoryW(DWORD nBufferLength,LPWSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceA(LPCSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceW(LPCWSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExA(LPCSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); + WINBASEAPI WINBOOL WINAPI GetDiskFreeSpaceExW(LPCWSTR lpDirectoryName,PULARGE_INTEGER lpFreeBytesAvailableToCaller,PULARGE_INTEGER lpTotalNumberOfBytes,PULARGE_INTEGER lpTotalNumberOfFreeBytes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryA(LPCSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryW(LPCWSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryExA(LPCSTR lpTemplateDirectory,LPCSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateDirectoryExW(LPCWSTR lpTemplateDirectory,LPCWSTR lpNewDirectory,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI RemoveDirectoryA(LPCSTR lpPathName); + WINBASEAPI WINBOOL WINAPI RemoveDirectoryW(LPCWSTR lpPathName); + WINBASEAPI DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); + WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); + +#define DDD_RAW_TARGET_PATH 0x1 +#define DDD_REMOVE_DEFINITION 0x2 +#define DDD_EXACT_MATCH_ON_REMOVE 0x4 +#define DDD_NO_BROADCAST_SYSTEM 0x8 +#define DDD_LUID_BROADCAST_DRIVE 0x10 + + WINBASEAPI WINBOOL WINAPI DefineDosDeviceA(DWORD dwFlags,LPCSTR lpDeviceName,LPCSTR lpTargetPath); + WINBASEAPI WINBOOL WINAPI DefineDosDeviceW(DWORD dwFlags,LPCWSTR lpDeviceName,LPCWSTR lpTargetPath); + WINBASEAPI DWORD WINAPI QueryDosDeviceA(LPCSTR lpDeviceName,LPSTR lpTargetPath,DWORD ucchMax); + WINBASEAPI DWORD WINAPI QueryDosDeviceW(LPCWSTR lpDeviceName,LPWSTR lpTargetPath,DWORD ucchMax); + +#define EXPAND_LOCAL_DRIVES + + WINBASEAPI HANDLE WINAPI CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); + WINBASEAPI HANDLE WINAPI CreateFileW(LPCWSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile); + WINBASEAPI HANDLE WINAPI ReOpenFile(HANDLE hOriginalFile,DWORD dwDesiredAccess,DWORD dwShareMode,DWORD dwFlagsAndAttributes); + WINBASEAPI WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName,DWORD dwFileAttributes); + WINBASEAPI WINBOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName,DWORD dwFileAttributes); + WINBASEAPI DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName); + WINBASEAPI DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName); + + typedef enum _GET_FILEEX_INFO_LEVELS { + GetFileExInfoStandard,GetFileExMaxInfoLevel + } GET_FILEEX_INFO_LEVELS; + +#ifdef UNICODE +#define GetFileAttributesEx GetFileAttributesExW +#define GetCompressedFileSize GetCompressedFileSizeW +#define DeleteFile DeleteFileW +#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3W +#else +#define GetFileAttributesEx GetFileAttributesExA +#define GetCompressedFileSize GetCompressedFileSizeA +#define DeleteFile DeleteFileA +#define CheckNameLegalDOS8Dot3 CheckNameLegalDOS8Dot3A +#endif + + WINBASEAPI WINBOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); + WINBASEAPI WINBOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); + WINBASEAPI DWORD WINAPI GetCompressedFileSizeA(LPCSTR lpFileName,LPDWORD lpFileSizeHigh); + WINBASEAPI DWORD WINAPI GetCompressedFileSizeW(LPCWSTR lpFileName,LPDWORD lpFileSizeHigh); + WINBASEAPI WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName); + WINBASEAPI WINBOOL WINAPI DeleteFileW(LPCWSTR lpFileName); + WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3A(LPCSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); + WINBASEAPI WINBOOL WINAPI CheckNameLegalDOS8Dot3W(LPCWSTR lpName,LPSTR lpOemName,DWORD OemNameSize,PBOOL pbNameContainsSpaces,PBOOL pbNameLegal); + + typedef enum _FINDEX_INFO_LEVELS { + FindExInfoStandard,FindExInfoMaxInfoLevel + } FINDEX_INFO_LEVELS; + + typedef enum _FINDEX_SEARCH_OPS { + FindExSearchNameMatch,FindExSearchLimitToDirectories,FindExSearchLimitToDevices,FindExSearchMaxSearchOp + } FINDEX_SEARCH_OPS; + +#define FIND_FIRST_EX_CASE_SENSITIVE 0x1 + +#ifdef UNICODE +#define FindFirstFileEx FindFirstFileExW +#define FindFirstFile FindFirstFileW +#define FindNextFile FindNextFileW +#define SearchPath SearchPathW +#define CopyFile CopyFileW +#define CopyFileEx CopyFileExW +#define MoveFile MoveFileW +#define MoveFileEx MoveFileExW +#define MoveFileWithProgress MoveFileWithProgressW +#define ReplaceFile ReplaceFileW +#define CreateHardLink CreateHardLinkW +#define CreateNamedPipe CreateNamedPipeW +#define GetNamedPipeHandleState GetNamedPipeHandleStateW +#define CallNamedPipe CallNamedPipeW +#define WaitNamedPipe WaitNamedPipeW +#define SetVolumeLabel SetVolumeLabelW +#define GetVolumeInformation GetVolumeInformationW +#define ClearEventLog ClearEventLogW +#define BackupEventLog BackupEventLogW +#define OpenEventLog OpenEventLogW +#define RegisterEventSource RegisterEventSourceW +#define OpenBackupEventLog OpenBackupEventLogW +#define ReadEventLog ReadEventLogW +#define ReportEvent ReportEventW +#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmW +#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmW +#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmW +#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleW +#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmW +#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmW +#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmW +#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmW +#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmW +#define SetFileSecurity SetFileSecurityW +#define GetFileSecurity GetFileSecurityW +#define FindFirstChangeNotification FindFirstChangeNotificationW +#define IsBadStringPtr IsBadStringPtrW +#define LookupAccountSid LookupAccountSidW +#define LookupAccountName LookupAccountNameW +#define LookupPrivilegeValue LookupPrivilegeValueW +#define LookupPrivilegeName LookupPrivilegeNameW +#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameW +#define BuildCommDCB BuildCommDCBW +#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW +#define CommConfigDialog CommConfigDialogW +#define GetDefaultCommConfig GetDefaultCommConfigW +#define SetDefaultCommConfig SetDefaultCommConfigW +#define GetComputerName GetComputerNameW +#define SetComputerName SetComputerNameW +#define GetComputerNameEx GetComputerNameExW +#define SetComputerNameEx SetComputerNameExW +#define DnsHostnameToComputerName DnsHostnameToComputerNameW +#define GetUserName GetUserNameW +#else +#define FindFirstFileEx FindFirstFileExA +#define FindFirstFile FindFirstFileA +#define FindNextFile FindNextFileA +#define SearchPath SearchPathA +#define CopyFile CopyFileA +#define CopyFileEx CopyFileExA +#define MoveFile MoveFileA +#define MoveFileEx MoveFileExA +#define MoveFileWithProgress MoveFileWithProgressA +#define ReplaceFile ReplaceFileA +#define CreateHardLink CreateHardLinkA +#define CreateNamedPipe CreateNamedPipeA +#define GetNamedPipeHandleState GetNamedPipeHandleStateA +#define CallNamedPipe CallNamedPipeA +#define WaitNamedPipe WaitNamedPipeA +#define SetVolumeLabel SetVolumeLabelA +#define GetVolumeInformation GetVolumeInformationA +#define ClearEventLog ClearEventLogA +#define BackupEventLog BackupEventLogA +#define OpenEventLog OpenEventLogA +#define RegisterEventSource RegisterEventSourceA +#define OpenBackupEventLog OpenBackupEventLogA +#define ReadEventLog ReadEventLogA +#define ReportEvent ReportEventA +#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmA +#define AccessCheckByTypeAndAuditAlarm AccessCheckByTypeAndAuditAlarmA +#define AccessCheckByTypeResultListAndAuditAlarm AccessCheckByTypeResultListAndAuditAlarmA +#define AccessCheckByTypeResultListAndAuditAlarmByHandle AccessCheckByTypeResultListAndAuditAlarmByHandleA +#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmA +#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmA +#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmA +#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmA +#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmA +#define SetFileSecurity SetFileSecurityA +#define GetFileSecurity GetFileSecurityA +#define FindFirstChangeNotification FindFirstChangeNotificationA +#define IsBadStringPtr IsBadStringPtrA +#define LookupAccountSid LookupAccountSidA +#define LookupAccountName LookupAccountNameA +#define LookupPrivilegeValue LookupPrivilegeValueA +#define LookupPrivilegeName LookupPrivilegeNameA +#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameA +#define BuildCommDCB BuildCommDCBA +#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA +#define CommConfigDialog CommConfigDialogA +#define GetDefaultCommConfig GetDefaultCommConfigA +#define SetDefaultCommConfig SetDefaultCommConfigA +#define GetComputerName GetComputerNameA +#define SetComputerName SetComputerNameA +#define GetComputerNameEx GetComputerNameExA +#define SetComputerNameEx SetComputerNameExA +#define DnsHostnameToComputerName DnsHostnameToComputerNameA +#define GetUserName GetUserNameA +#endif + + WINBASEAPI HANDLE WINAPI FindFirstFileExA(LPCSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); + WINBASEAPI HANDLE WINAPI FindFirstFileExW(LPCWSTR lpFileName,FINDEX_INFO_LEVELS fInfoLevelId,LPVOID lpFindFileData,FINDEX_SEARCH_OPS fSearchOp,LPVOID lpSearchFilter,DWORD dwAdditionalFlags); + WINBASEAPI HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName,LPWIN32_FIND_DATAA lpFindFileData); + WINBASEAPI HANDLE WINAPI FindFirstFileW(LPCWSTR lpFileName,LPWIN32_FIND_DATAW lpFindFileData); + WINBASEAPI WINBOOL WINAPI FindNextFileA(HANDLE hFindFile,LPWIN32_FIND_DATAA lpFindFileData); + WINBASEAPI WINBOOL WINAPI FindNextFileW(HANDLE hFindFile,LPWIN32_FIND_DATAW lpFindFileData); + WINBASEAPI DWORD WINAPI SearchPathA(LPCSTR lpPath,LPCSTR lpFileName,LPCSTR lpExtension,DWORD nBufferLength,LPSTR lpBuffer,LPSTR *lpFilePart); + WINBASEAPI DWORD WINAPI SearchPathW(LPCWSTR lpPath,LPCWSTR lpFileName,LPCWSTR lpExtension,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR *lpFilePart); + WINBASEAPI WINBOOL WINAPI CopyFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,WINBOOL bFailIfExists); + WINBASEAPI WINBOOL WINAPI CopyFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,WINBOOL bFailIfExists); + + typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER TotalFileSize,LARGE_INTEGER TotalBytesTransferred,LARGE_INTEGER StreamSize,LARGE_INTEGER StreamBytesTransferred,DWORD dwStreamNumber,DWORD dwCallbackReason,HANDLE hSourceFile,HANDLE hDestinationFile,LPVOID lpData); + + WINBASEAPI WINBOOL WINAPI CopyFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); + WINBASEAPI WINBOOL WINAPI CopyFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,LPBOOL pbCancel,DWORD dwCopyFlags); + WINBASEAPI WINBOOL WINAPI MoveFileA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName); + WINBASEAPI WINBOOL WINAPI MoveFileW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName); + WINBASEAPI WINBOOL WINAPI MoveFileExA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI MoveFileExW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI MoveFileWithProgressA(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI MoveFileWithProgressW(LPCWSTR lpExistingFileName,LPCWSTR lpNewFileName,LPPROGRESS_ROUTINE lpProgressRoutine,LPVOID lpData,DWORD dwFlags); + +#define MOVEFILE_REPLACE_EXISTING 0x1 +#define MOVEFILE_COPY_ALLOWED 0x2 +#define MOVEFILE_DELAY_UNTIL_REBOOT 0x4 +#define MOVEFILE_WRITE_THROUGH 0x8 +#define MOVEFILE_CREATE_HARDLINK 0x10 +#define MOVEFILE_FAIL_IF_NOT_TRACKABLE 0x20 + + WINBASEAPI WINBOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,LPCSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,LPCWSTR lpBackupFileName,DWORD dwReplaceFlags,LPVOID lpExclude,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI CreateHardLinkA(LPCSTR lpFileName,LPCSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI CreateHardLinkW(LPCWSTR lpFileName,LPCWSTR lpExistingFileName,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + + typedef enum _STREAM_INFO_LEVELS { + FindStreamInfoStandard,FindStreamInfoMaxInfoLevel + } STREAM_INFO_LEVELS; + + typedef struct _WIN32_FIND_STREAM_DATA { + LARGE_INTEGER StreamSize; + WCHAR cStreamName[MAX_PATH + 36]; + } WIN32_FIND_STREAM_DATA,*PWIN32_FIND_STREAM_DATA; + + HANDLE WINAPI FindFirstStreamW(LPCWSTR lpFileName,STREAM_INFO_LEVELS InfoLevel,LPVOID lpFindStreamData,DWORD dwFlags); + WINBOOL WINAPI FindNextStreamW(HANDLE hFindStream,LPVOID lpFindStreamData); + WINBASEAPI HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI HANDLE WINAPI CreateNamedPipeW(LPCWSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateA(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPSTR lpUserName,DWORD nMaxUserNameSize); + WINBASEAPI WINBOOL WINAPI GetNamedPipeHandleStateW(HANDLE hNamedPipe,LPDWORD lpState,LPDWORD lpCurInstances,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout,LPWSTR lpUserName,DWORD nMaxUserNameSize); + WINBASEAPI WINBOOL WINAPI CallNamedPipeA(LPCSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI CallNamedPipeW(LPCWSTR lpNamedPipeName,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI WaitNamedPipeA(LPCSTR lpNamedPipeName,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI WaitNamedPipeW(LPCWSTR lpNamedPipeName,DWORD nTimeOut); + WINBASEAPI WINBOOL WINAPI SetVolumeLabelA(LPCSTR lpRootPathName,LPCSTR lpVolumeName); + WINBASEAPI WINBOOL WINAPI SetVolumeLabelW(LPCWSTR lpRootPathName,LPCWSTR lpVolumeName); + WINBASEAPI VOID WINAPI SetFileApisToOEM(VOID); + WINBASEAPI VOID WINAPI SetFileApisToANSI(VOID); + WINBASEAPI WINBOOL WINAPI AreFileApisANSI(VOID); + WINBASEAPI WINBOOL WINAPI GetVolumeInformationA(LPCSTR lpRootPathName,LPSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); + WINBASEAPI WINBOOL WINAPI GetVolumeInformationW(LPCWSTR lpRootPathName,LPWSTR lpVolumeNameBuffer,DWORD nVolumeNameSize,LPDWORD lpVolumeSerialNumber,LPDWORD lpMaximumComponentLength,LPDWORD lpFileSystemFlags,LPWSTR lpFileSystemNameBuffer,DWORD nFileSystemNameSize); + WINBASEAPI WINBOOL WINAPI CancelIo(HANDLE hFile); + WINADVAPI WINBOOL WINAPI ClearEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI ClearEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI BackupEventLogA(HANDLE hEventLog,LPCSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI BackupEventLogW(HANDLE hEventLog,LPCWSTR lpBackupFileName); + WINADVAPI WINBOOL WINAPI CloseEventLog(HANDLE hEventLog); + WINADVAPI WINBOOL WINAPI DeregisterEventSource(HANDLE hEventLog); + WINADVAPI WINBOOL WINAPI NotifyChangeEventLog(HANDLE hEventLog,HANDLE hEvent); + WINADVAPI WINBOOL WINAPI GetNumberOfEventLogRecords(HANDLE hEventLog,PDWORD NumberOfRecords); + WINADVAPI WINBOOL WINAPI GetOldestEventLogRecord(HANDLE hEventLog,PDWORD OldestRecord); + WINADVAPI HANDLE WINAPI OpenEventLogA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); + WINADVAPI HANDLE WINAPI OpenEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); + WINADVAPI HANDLE WINAPI RegisterEventSourceA(LPCSTR lpUNCServerName,LPCSTR lpSourceName); + WINADVAPI HANDLE WINAPI RegisterEventSourceW(LPCWSTR lpUNCServerName,LPCWSTR lpSourceName); + WINADVAPI HANDLE WINAPI OpenBackupEventLogA(LPCSTR lpUNCServerName,LPCSTR lpFileName); + WINADVAPI HANDLE WINAPI OpenBackupEventLogW(LPCWSTR lpUNCServerName,LPCWSTR lpFileName); + WINADVAPI WINBOOL WINAPI ReadEventLogA(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); + WINADVAPI WINBOOL WINAPI ReadEventLogW(HANDLE hEventLog,DWORD dwReadFlags,DWORD dwRecordOffset,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,DWORD *pnBytesRead,DWORD *pnMinNumberOfBytesNeeded); + WINADVAPI WINBOOL WINAPI ReportEventA(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCSTR *lpStrings,LPVOID lpRawData); + WINADVAPI WINBOOL WINAPI ReportEventW(HANDLE hEventLog,WORD wType,WORD wCategory,DWORD dwEventID,PSID lpUserSid,WORD wNumStrings,DWORD dwDataSize,LPCWSTR *lpStrings,LPVOID lpRawData); + +#define EVENTLOG_FULL_INFO 0 + + typedef struct _EVENTLOG_FULL_INFORMATION { + DWORD dwFull; + } EVENTLOG_FULL_INFORMATION,*LPEVENTLOG_FULL_INFORMATION; + + WINADVAPI WINBOOL WINAPI GetEventLogInformation(HANDLE hEventLog,DWORD dwInfoLevel,LPVOID lpBuffer,DWORD cbBufSize,LPDWORD pcbBytesNeeded); + WINADVAPI WINBOOL WINAPI DuplicateToken(HANDLE ExistingTokenHandle,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,PHANDLE DuplicateTokenHandle); + WINADVAPI WINBOOL WINAPI GetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); + WINADVAPI WINBOOL WINAPI ImpersonateNamedPipeClient(HANDLE hNamedPipe); + WINADVAPI WINBOOL WINAPI ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel); + WINADVAPI WINBOOL WINAPI RevertToSelf(VOID); + WINADVAPI WINBOOL WINAPI SetThreadToken (PHANDLE Thread,HANDLE Token); + WINADVAPI WINBOOL WINAPI AccessCheck(PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); + WINADVAPI WINBOOL WINAPI AccessCheckByType(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccess,LPBOOL AccessStatus); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultList(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID PrincipalSelfSid,HANDLE ClientToken,DWORD DesiredAccess,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,PPRIVILEGE_SET PrivilegeSet,LPDWORD PrivilegeSetLength,LPDWORD GrantedAccessList,LPDWORD AccessStatusList); + WINADVAPI WINBOOL WINAPI OpenProcessToken(HANDLE ProcessHandle,DWORD DesiredAccess,PHANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI OpenThreadToken(HANDLE ThreadHandle,DWORD DesiredAccess,WINBOOL OpenAsSelf,PHANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI GetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI SetTokenInformation(HANDLE TokenHandle,TOKEN_INFORMATION_CLASS TokenInformationClass,LPVOID TokenInformation,DWORD TokenInformationLength); + WINADVAPI WINBOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle,WINBOOL DisableAllPrivileges,PTOKEN_PRIVILEGES NewState,DWORD BufferLength,PTOKEN_PRIVILEGES PreviousState,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI AdjustTokenGroups(HANDLE TokenHandle,WINBOOL ResetToDefault,PTOKEN_GROUPS NewState,DWORD BufferLength,PTOKEN_GROUPS PreviousState,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI PrivilegeCheck(HANDLE ClientToken,PPRIVILEGE_SET RequiredPrivileges,LPBOOL pfResult); + WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,DWORD DesiredAccess,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPBOOL AccessStatus,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCSTR ObjectTypeName,LPCSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI AccessCheckByTypeResultListAndAuditAlarmByHandleW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,LPCWSTR ObjectTypeName,LPCWSTR ObjectName,PSECURITY_DESCRIPTOR SecurityDescriptor,PSID PrincipalSelfSid,DWORD DesiredAccess,AUDIT_EVENT_TYPE AuditType,DWORD Flags,POBJECT_TYPE_LIST ObjectTypeList,DWORD ObjectTypeListLength,PGENERIC_MAPPING GenericMapping,WINBOOL ObjectCreation,LPDWORD GrantedAccess,LPDWORD AccessStatusList,LPBOOL pfGenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,LPSTR ObjectTypeName,LPSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectOpenAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,LPWSTR ObjectTypeName,LPWSTR ObjectName,PSECURITY_DESCRIPTOR pSecurityDescriptor,HANDLE ClientToken,DWORD DesiredAccess,DWORD GrantedAccess,PPRIVILEGE_SET Privileges,WINBOOL ObjectCreation,WINBOOL AccessGranted,LPBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI ObjectPrivilegeAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,HANDLE ClientToken,DWORD DesiredAccess,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectCloseAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmA(LPCSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI ObjectDeleteAuditAlarmW(LPCWSTR SubsystemName,LPVOID HandleId,WINBOOL GenerateOnClose); + WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmA(LPCSTR SubsystemName,LPCSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI PrivilegedServiceAuditAlarmW(LPCWSTR SubsystemName,LPCWSTR ServiceName,HANDLE ClientToken,PPRIVILEGE_SET Privileges,WINBOOL AccessGranted); + WINADVAPI WINBOOL WINAPI IsWellKnownSid(PSID pSid,WELL_KNOWN_SID_TYPE WellKnownSidType); + WINADVAPI WINBOOL WINAPI CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType,PSID DomainSid,PSID pSid,DWORD *cbSid); + WINADVAPI WINBOOL WINAPI EqualDomainSid(PSID pSid1,PSID pSid2,WINBOOL *pfEqual); + WINADVAPI WINBOOL WINAPI GetWindowsAccountDomainSid(PSID pSid,PSID pDomainSid,DWORD *cbDomainSid); + WINADVAPI WINBOOL WINAPI IsValidSid(PSID pSid); + WINADVAPI WINBOOL WINAPI EqualSid(PSID pSid1,PSID pSid2); + WINADVAPI WINBOOL WINAPI EqualPrefixSid(PSID pSid1,PSID pSid2); + WINADVAPI DWORD WINAPI GetSidLengthRequired (UCHAR nSubAuthorityCount); + WINADVAPI WINBOOL WINAPI AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount,DWORD nSubAuthority0,DWORD nSubAuthority1,DWORD nSubAuthority2,DWORD nSubAuthority3,DWORD nSubAuthority4,DWORD nSubAuthority5,DWORD nSubAuthority6,DWORD nSubAuthority7,PSID *pSid); + WINADVAPI PVOID WINAPI FreeSid(PSID pSid); + WINADVAPI WINBOOL WINAPI InitializeSid(PSID Sid,PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount); + WINADVAPI PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid); + WINADVAPI PDWORD WINAPI GetSidSubAuthority(PSID pSid,DWORD nSubAuthority); + WINADVAPI PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid); + WINADVAPI DWORD WINAPI GetLengthSid(PSID pSid); + WINADVAPI WINBOOL WINAPI CopySid(DWORD nDestinationSidLength,PSID pDestinationSid,PSID pSourceSid); + WINADVAPI WINBOOL WINAPI AreAllAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); + WINADVAPI WINBOOL WINAPI AreAnyAccessesGranted(DWORD GrantedAccess,DWORD DesiredAccess); + WINADVAPI VOID WINAPI MapGenericMask(PDWORD AccessMask,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI IsValidAcl(PACL pAcl); + WINADVAPI WINBOOL WINAPI InitializeAcl(PACL pAcl,DWORD nAclLength,DWORD dwAclRevision); + WINADVAPI WINBOOL WINAPI GetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); + WINADVAPI WINBOOL WINAPI SetAclInformation(PACL pAcl,LPVOID pAclInformation,DWORD nAclInformationLength,ACL_INFORMATION_CLASS dwAclInformationClass); + WINADVAPI WINBOOL WINAPI AddAce(PACL pAcl,DWORD dwAceRevision,DWORD dwStartingAceIndex,LPVOID pAceList,DWORD nAceListLength); + WINADVAPI WINBOOL WINAPI DeleteAce(PACL pAcl,DWORD dwAceIndex); + WINADVAPI WINBOOL WINAPI GetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce); + WINADVAPI WINBOOL WINAPI AddAccessAllowedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessAllowedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessDeniedAce(PACL pAcl,DWORD dwAceRevision,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessDeniedAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAuditAccessAce(PACL pAcl,DWORD dwAceRevision,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); + WINADVAPI WINBOOL WINAPI AddAuditAccessAceEx(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD dwAccessMask,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); + WINADVAPI WINBOOL WINAPI AddAccessAllowedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAccessDeniedObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid); + WINADVAPI WINBOOL WINAPI AddAuditAccessObjectAce(PACL pAcl,DWORD dwAceRevision,DWORD AceFlags,DWORD AccessMask,GUID *ObjectTypeGuid,GUID *InheritedObjectTypeGuid,PSID pSid,WINBOOL bAuditSuccess,WINBOOL bAuditFailure); + WINADVAPI WINBOOL WINAPI FindFirstFreeAce(PACL pAcl,LPVOID *pAce); + WINADVAPI WINBOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD dwRevision); + WINADVAPI WINBOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI DWORD WINAPI GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSECURITY_DESCRIPTOR_CONTROL pControl,LPDWORD lpdwRevision); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR pSecurityDescriptor,SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bDaclPresent,PACL pDacl,WINBOOL bDaclDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbDaclPresent,PACL *pDacl,LPBOOL lpbDaclDefaulted); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,WINBOOL bSaclPresent,PACL pSacl,WINBOOL bSaclDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,LPBOOL lpbSaclPresent,PACL *pSacl,LPBOOL lpbSaclDefaulted); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pOwner,WINBOOL bOwnerDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pOwner,LPBOOL lpbOwnerDefaulted); + WINADVAPI WINBOOL WINAPI SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID pGroup,WINBOOL bGroupDefaulted); + WINADVAPI WINBOOL WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR pSecurityDescriptor,PSID *pGroup,LPBOOL lpbGroupDefaulted); + WINADVAPI DWORD WINAPI SetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); + WINADVAPI DWORD WINAPI GetSecurityDescriptorRMControl(PSECURITY_DESCRIPTOR SecurityDescriptor,PUCHAR RMControl); + WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,WINBOOL IsDirectoryObject,HANDLE Token,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI ConvertToAutoInheritPrivateObjectSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CurrentSecurityDescriptor,PSECURITY_DESCRIPTOR *NewSecurityDescriptor,GUID *ObjectType,BOOLEAN IsDirectoryObject,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityEx(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID *ObjectType,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI CreatePrivateObjectSecurityWithMultipleInheritance(PSECURITY_DESCRIPTOR ParentDescriptor,PSECURITY_DESCRIPTOR CreatorDescriptor,PSECURITY_DESCRIPTOR *NewDescriptor,GUID **ObjectTypes,ULONG GuidCount,WINBOOL IsContainerObject,ULONG AutoInheritFlags,HANDLE Token,PGENERIC_MAPPING GenericMapping); + WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurity (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,PGENERIC_MAPPING GenericMapping,HANDLE Token); + WINADVAPI WINBOOL WINAPI SetPrivateObjectSecurityEx (SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ModificationDescriptor,PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,ULONG AutoInheritFlags,PGENERIC_MAPPING GenericMapping,HANDLE Token); + WINADVAPI WINBOOL WINAPI GetPrivateObjectSecurity(PSECURITY_DESCRIPTOR ObjectDescriptor,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR ResultantDescriptor,DWORD DescriptorLength,PDWORD ReturnLength); + WINADVAPI WINBOOL WINAPI DestroyPrivateObjectSecurity(PSECURITY_DESCRIPTOR *ObjectDescriptor); + WINADVAPI WINBOOL WINAPI MakeSelfRelativeSD(PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferLength); + WINADVAPI WINBOOL WINAPI MakeAbsoluteSD(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,LPDWORD lpdwAbsoluteSecurityDescriptorSize,PACL pDacl,LPDWORD lpdwDaclSize,PACL pSacl,LPDWORD lpdwSaclSize,PSID pOwner,LPDWORD lpdwOwnerSize,PSID pPrimaryGroup,LPDWORD lpdwPrimaryGroupSize); + WINADVAPI WINBOOL WINAPI MakeAbsoluteSD2(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,LPDWORD lpdwBufferSize); + WINADVAPI WINBOOL WINAPI SetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI WINBOOL WINAPI SetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI WINBOOL WINAPI GetFileSecurityA(LPCSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); + WINADVAPI WINBOOL WINAPI GetFileSecurityW(LPCWSTR lpFileName,SECURITY_INFORMATION RequestedInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,DWORD nLength,LPDWORD lpnLengthNeeded); + WINADVAPI WINBOOL WINAPI SetKernelObjectSecurity(HANDLE Handle,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR SecurityDescriptor); + WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationA(LPCSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); + WINBASEAPI HANDLE WINAPI FindFirstChangeNotificationW(LPCWSTR lpPathName,WINBOOL bWatchSubtree,DWORD dwNotifyFilter); + WINBASEAPI WINBOOL WINAPI FindNextChangeNotification(HANDLE hChangeHandle); + WINBASEAPI WINBOOL WINAPI FindCloseChangeNotification(HANDLE hChangeHandle); + WINBASEAPI WINBOOL WINAPI ReadDirectoryChangesW(HANDLE hDirectory,LPVOID lpBuffer,DWORD nBufferLength,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINBASEAPI WINBOOL WINAPI VirtualLock(LPVOID lpAddress,SIZE_T dwSize); + WINBASEAPI WINBOOL WINAPI VirtualUnlock(LPVOID lpAddress,SIZE_T dwSize); + WINBASEAPI LPVOID WINAPI MapViewOfFileEx(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap,LPVOID lpBaseAddress); + WINBASEAPI WINBOOL WINAPI SetPriorityClass(HANDLE hProcess,DWORD dwPriorityClass); + WINBASEAPI DWORD WINAPI GetPriorityClass(HANDLE hProcess); + WINBASEAPI WINBOOL WINAPI IsBadReadPtr(CONST VOID *lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadWritePtr(LPVOID lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadHugeReadPtr(CONST VOID *lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadHugeWritePtr(LPVOID lp,UINT_PTR ucb); + WINBASEAPI WINBOOL WINAPI IsBadCodePtr(FARPROC lpfn); + WINBASEAPI WINBOOL WINAPI IsBadStringPtrA(LPCSTR lpsz,UINT_PTR ucchMax); + WINBASEAPI WINBOOL WINAPI IsBadStringPtrW(LPCWSTR lpsz,UINT_PTR ucchMax); + WINADVAPI WINBOOL WINAPI LookupAccountSidA(LPCSTR lpSystemName,PSID Sid,LPSTR Name,LPDWORD cchName,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName,PSID Sid,LPWSTR Name,LPDWORD cchName,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupAccountNameA(LPCSTR lpSystemName,LPCSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupAccountNameW(LPCWSTR lpSystemName,LPCWSTR lpAccountName,PSID Sid,LPDWORD cbSid,LPWSTR ReferencedDomainName,LPDWORD cchReferencedDomainName,PSID_NAME_USE peUse); + WINADVAPI WINBOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName,LPCSTR lpName,PLUID lpLuid); + WINADVAPI WINBOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName,LPCWSTR lpName,PLUID lpLuid); + WINADVAPI WINBOOL WINAPI LookupPrivilegeNameA(LPCSTR lpSystemName,PLUID lpLuid,LPSTR lpName,LPDWORD cchName); + WINADVAPI WINBOOL WINAPI LookupPrivilegeNameW(LPCWSTR lpSystemName,PLUID lpLuid,LPWSTR lpName,LPDWORD cchName); + WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameA(LPCSTR lpSystemName,LPCSTR lpName,LPSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); + WINADVAPI WINBOOL WINAPI LookupPrivilegeDisplayNameW(LPCWSTR lpSystemName,LPCWSTR lpName,LPWSTR lpDisplayName,LPDWORD cchDisplayName,LPDWORD lpLanguageId); + WINADVAPI WINBOOL WINAPI AllocateLocallyUniqueId(PLUID Luid); + WINBASEAPI WINBOOL WINAPI BuildCommDCBA(LPCSTR lpDef,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI BuildCommDCBW(LPCWSTR lpDef,LPDCB lpDCB); + WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI BuildCommDCBAndTimeoutsW(LPCWSTR lpDef,LPDCB lpDCB,LPCOMMTIMEOUTS lpCommTimeouts); + WINBASEAPI WINBOOL WINAPI CommConfigDialogA(LPCSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); + WINBASEAPI WINBOOL WINAPI CommConfigDialogW(LPCWSTR lpszName,HWND hWnd,LPCOMMCONFIG lpCC); + WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); + WINBASEAPI WINBOOL WINAPI GetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize); + WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); + WINBASEAPI WINBOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,DWORD dwSize); + +#define MAX_COMPUTERNAME_LENGTH 15 + + WINBASEAPI WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI GetComputerNameW(LPWSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI SetComputerNameA(LPCSTR lpComputerName); + WINBASEAPI WINBOOL WINAPI SetComputerNameW(LPCWSTR lpComputerName); + + typedef enum _COMPUTER_NAME_FORMAT { + ComputerNameNetBIOS,ComputerNameDnsHostname,ComputerNameDnsDomain,ComputerNameDnsFullyQualified,ComputerNamePhysicalNetBIOS,ComputerNamePhysicalDnsHostname,ComputerNamePhysicalDnsDomain,ComputerNamePhysicalDnsFullyQualified,ComputerNameMax + } COMPUTER_NAME_FORMAT; + + WINBASEAPI WINBOOL WINAPI GetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI GetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPWSTR lpBuffer,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI SetComputerNameExA(COMPUTER_NAME_FORMAT NameType,LPCSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI SetComputerNameExW(COMPUTER_NAME_FORMAT NameType,LPCWSTR lpBuffer); + WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameA(LPCSTR Hostname,LPSTR ComputerName,LPDWORD nSize); + WINBASEAPI WINBOOL WINAPI DnsHostnameToComputerNameW(LPCWSTR Hostname,LPWSTR ComputerName,LPDWORD nSize); + WINADVAPI WINBOOL WINAPI GetUserNameA(LPSTR lpBuffer,LPDWORD pcbBuffer); + WINADVAPI WINBOOL WINAPI GetUserNameW(LPWSTR lpBuffer,LPDWORD pcbBuffer); + +#define LOGON32_LOGON_INTERACTIVE 2 +#define LOGON32_LOGON_NETWORK 3 +#define LOGON32_LOGON_BATCH 4 +#define LOGON32_LOGON_SERVICE 5 +#define LOGON32_LOGON_UNLOCK 7 +#define LOGON32_LOGON_NETWORK_CLEARTEXT 8 +#define LOGON32_LOGON_NEW_CREDENTIALS 9 + +#define LOGON32_PROVIDER_DEFAULT 0 +#define LOGON32_PROVIDER_WINNT35 1 +#define LOGON32_PROVIDER_WINNT40 2 +#define LOGON32_PROVIDER_WINNT50 3 + +#ifdef UNICODE +#define LogonUser LogonUserW +#define LogonUserEx LogonUserExW +#define CreateProcessAsUser CreateProcessAsUserW +#else +#define LogonUser LogonUserA +#define LogonUserEx LogonUserExA +#define CreateProcessAsUser CreateProcessAsUserA +#endif + + WINADVAPI WINBOOL WINAPI LogonUserA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); + WINADVAPI WINBOOL WINAPI LogonUserW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken); + WINADVAPI WINBOOL WINAPI LogonUserExA(LPCSTR lpszUsername,LPCSTR lpszDomain,LPCSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); + WINADVAPI WINBOOL WINAPI LogonUserExW(LPCWSTR lpszUsername,LPCWSTR lpszDomain,LPCWSTR lpszPassword,DWORD dwLogonType,DWORD dwLogonProvider,PHANDLE phToken,PSID *ppLogonSid,PVOID *ppProfileBuffer,LPDWORD pdwProfileLength,PQUOTA_LIMITS pQuotaLimits); + WINADVAPI WINBOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken); + WINADVAPI WINBOOL WINAPI CreateProcessAsUserA(HANDLE hToken,LPCSTR lpApplicationName,LPSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFOA lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINADVAPI WINBOOL WINAPI CreateProcessAsUserW(HANDLE hToken,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,WINBOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + +#define LOGON_WITH_PROFILE 0x1 +#define LOGON_NETCREDENTIALS_ONLY 0x2 +#define LOGON_ZERO_PASSWORD_BUFFER 0x80000000 + + WINADVAPI WINBOOL WINAPI CreateProcessWithLogonW(LPCWSTR lpUsername,LPCWSTR lpDomain,LPCWSTR lpPassword,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINADVAPI WINBOOL WINAPI CreateProcessWithTokenW(HANDLE hToken,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation); + WINADVAPI WINBOOL WINAPI ImpersonateAnonymousToken(HANDLE ThreadHandle); + WINADVAPI WINBOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken,DWORD dwDesiredAccess,LPSECURITY_ATTRIBUTES lpTokenAttributes,SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,TOKEN_TYPE TokenType,PHANDLE phNewToken); + WINADVAPI WINBOOL WINAPI CreateRestrictedToken(HANDLE ExistingTokenHandle,DWORD Flags,DWORD DisableSidCount,PSID_AND_ATTRIBUTES SidsToDisable,DWORD DeletePrivilegeCount,PLUID_AND_ATTRIBUTES PrivilegesToDelete,DWORD RestrictedSidCount,PSID_AND_ATTRIBUTES SidsToRestrict,PHANDLE NewTokenHandle); + WINADVAPI WINBOOL WINAPI IsTokenRestricted(HANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI IsTokenUntrusted(HANDLE TokenHandle); + WINADVAPI WINBOOL WINAPI CheckTokenMembership(HANDLE TokenHandle,PSID SidToCheck,PBOOL IsMember); + + typedef WAITORTIMERCALLBACKFUNC WAITORTIMERCALLBACK; + + WINBASEAPI WINBOOL WINAPI RegisterWaitForSingleObject(PHANDLE phNewWaitObject,HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); + WINBASEAPI HANDLE WINAPI RegisterWaitForSingleObjectEx(HANDLE hObject,WAITORTIMERCALLBACK Callback,PVOID Context,ULONG dwMilliseconds,ULONG dwFlags); + WINBASEAPI WINBOOL WINAPI UnregisterWait(HANDLE WaitHandle); + WINBASEAPI WINBOOL WINAPI UnregisterWaitEx(HANDLE WaitHandle,HANDLE CompletionEvent); + WINBASEAPI WINBOOL WINAPI QueueUserWorkItem(LPTHREAD_START_ROUTINE Function,PVOID Context,ULONG Flags); + WINBASEAPI WINBOOL WINAPI BindIoCompletionCallback(HANDLE FileHandle,LPOVERLAPPED_COMPLETION_ROUTINE Function,ULONG Flags); + WINBASEAPI HANDLE WINAPI CreateTimerQueue(VOID); + WINBASEAPI WINBOOL WINAPI CreateTimerQueueTimer(PHANDLE phNewTimer,HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,ULONG Flags); + WINBASEAPI WINBOOL WINAPI ChangeTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,ULONG DueTime,ULONG Period); + WINBASEAPI WINBOOL WINAPI DeleteTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer,HANDLE CompletionEvent); + WINBASEAPI WINBOOL WINAPI DeleteTimerQueueEx(HANDLE TimerQueue,HANDLE CompletionEvent); + WINBASEAPI HANDLE WINAPI SetTimerQueueTimer(HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,WINBOOL PreferIo); + WINBASEAPI WINBOOL WINAPI CancelTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer); + WINBASEAPI WINBOOL WINAPI DeleteTimerQueue(HANDLE TimerQueue); + +#define HW_PROFILE_GUIDLEN 39 +#define MAX_PROFILE_LEN 80 + +#define DOCKINFO_UNDOCKED (0x1) +#define DOCKINFO_DOCKED (0x2) +#define DOCKINFO_USER_SUPPLIED (0x4) +#define DOCKINFO_USER_UNDOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_UNDOCKED) +#define DOCKINFO_USER_DOCKED (DOCKINFO_USER_SUPPLIED | DOCKINFO_DOCKED) + + typedef struct tagHW_PROFILE_INFOA { + DWORD dwDockInfo; + CHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; + CHAR szHwProfileName[MAX_PROFILE_LEN]; + } HW_PROFILE_INFOA,*LPHW_PROFILE_INFOA; + + typedef struct tagHW_PROFILE_INFOW { + DWORD dwDockInfo; + WCHAR szHwProfileGuid[HW_PROFILE_GUIDLEN]; + WCHAR szHwProfileName[MAX_PROFILE_LEN]; + } HW_PROFILE_INFOW,*LPHW_PROFILE_INFOW; + +#ifdef UNICODE + typedef HW_PROFILE_INFOW HW_PROFILE_INFO; + typedef LPHW_PROFILE_INFOW LPHW_PROFILE_INFO; +#else + typedef HW_PROFILE_INFOA HW_PROFILE_INFO; + typedef LPHW_PROFILE_INFOA LPHW_PROFILE_INFO; +#endif + +#ifdef UNICODE +#define GetCurrentHwProfile GetCurrentHwProfileW +#define GetVersionEx GetVersionExW +#define VerifyVersionInfo VerifyVersionInfoW +#else +#define GetCurrentHwProfile GetCurrentHwProfileA +#define GetVersionEx GetVersionExA +#define VerifyVersionInfo VerifyVersionInfoA +#endif + + WINADVAPI WINBOOL WINAPI GetCurrentHwProfileA (LPHW_PROFILE_INFOA lpHwProfileInfo); + WINADVAPI WINBOOL WINAPI GetCurrentHwProfileW (LPHW_PROFILE_INFOW lpHwProfileInfo); + WINBASEAPI WINBOOL WINAPI QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); + WINBASEAPI WINBOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); + WINBASEAPI WINBOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation); + WINBASEAPI WINBOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation); + WINBASEAPI WINBOOL WINAPI VerifyVersionInfoA(LPOSVERSIONINFOEXA lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); + WINBASEAPI WINBOOL WINAPI VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation,DWORD dwTypeMask,DWORDLONG dwlConditionMask); + +#include + +#define TC_NORMAL 0 +#define TC_HARDERR 1 +#define TC_GP_TRAP 2 +#define TC_SIGNAL 3 + +#define AC_LINE_OFFLINE 0x0 +#define AC_LINE_ONLINE 0x1 +#define AC_LINE_BACKUP_POWER 0x2 +#define AC_LINE_UNKNOWN 0xff + +#define BATTERY_FLAG_HIGH 0x1 +#define BATTERY_FLAG_LOW 0x2 +#define BATTERY_FLAG_CRITICAL 0x4 +#define BATTERY_FLAG_CHARGING 0x8 +#define BATTERY_FLAG_NO_BATTERY 0x80 +#define BATTERY_FLAG_UNKNOWN 0xff + +#define BATTERY_PERCENTAGE_UNKNOWN 0xff + +#define BATTERY_LIFE_UNKNOWN 0xffffffff + + typedef struct _SYSTEM_POWER_STATUS { + BYTE ACLineStatus; + BYTE BatteryFlag; + BYTE BatteryLifePercent; + BYTE Reserved1; + DWORD BatteryLifeTime; + DWORD BatteryFullLifeTime; + } SYSTEM_POWER_STATUS,*LPSYSTEM_POWER_STATUS; + +#ifdef UNICODE +#define CreateJobObject CreateJobObjectW +#define OpenJobObject OpenJobObjectW +#define FindFirstVolume FindFirstVolumeW +#define FindNextVolume FindNextVolumeW +#define FindFirstVolumeMountPoint FindFirstVolumeMountPointW +#define FindNextVolumeMountPoint FindNextVolumeMountPointW +#define SetVolumeMountPoint SetVolumeMountPointW +#define DeleteVolumeMountPoint DeleteVolumeMountPointW +#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointW +#define GetVolumePathName GetVolumePathNameW +#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameW +#else +#define CreateJobObject CreateJobObjectA +#define OpenJobObject OpenJobObjectA +#define FindFirstVolume FindFirstVolumeA +#define FindNextVolume FindNextVolumeA +#define FindFirstVolumeMountPoint FindFirstVolumeMountPointA +#define FindNextVolumeMountPoint FindNextVolumeMountPointA +#define SetVolumeMountPoint SetVolumeMountPointA +#define DeleteVolumeMountPoint DeleteVolumeMountPointA +#define GetVolumeNameForVolumeMountPoint GetVolumeNameForVolumeMountPointA +#define GetVolumePathName GetVolumePathNameA +#define GetVolumePathNamesForVolumeName GetVolumePathNamesForVolumeNameA +#endif + + WINBOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS lpSystemPowerStatus); + WINBOOL WINAPI SetSystemPowerState(WINBOOL fSuspend,WINBOOL fForce); + WINBASEAPI WINBOOL WINAPI AllocateUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI WINBOOL WINAPI FreeUserPhysicalPages(HANDLE hProcess,PULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI WINBOOL WINAPI MapUserPhysicalPages(PVOID VirtualAddress,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI WINBOOL WINAPI MapUserPhysicalPagesScatter(PVOID *VirtualAddresses,ULONG_PTR NumberOfPages,PULONG_PTR PageArray); + WINBASEAPI HANDLE WINAPI CreateJobObjectA(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI CreateJobObjectW(LPSECURITY_ATTRIBUTES lpJobAttributes,LPCWSTR lpName); + WINBASEAPI HANDLE WINAPI OpenJobObjectA(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCSTR lpName); + WINBASEAPI HANDLE WINAPI OpenJobObjectW(DWORD dwDesiredAccess,WINBOOL bInheritHandle,LPCWSTR lpName); + WINBASEAPI WINBOOL WINAPI AssignProcessToJobObject(HANDLE hJob,HANDLE hProcess); + WINBASEAPI WINBOOL WINAPI TerminateJobObject(HANDLE hJob,UINT uExitCode); + WINBASEAPI WINBOOL WINAPI QueryInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength,LPDWORD lpReturnLength); + WINBASEAPI WINBOOL WINAPI SetInformationJobObject(HANDLE hJob,JOBOBJECTINFOCLASS JobObjectInformationClass,LPVOID lpJobObjectInformation,DWORD cbJobObjectInformationLength); + WINBASEAPI WINBOOL WINAPI IsProcessInJob(HANDLE ProcessHandle,HANDLE JobHandle,PBOOL Result); + WINBASEAPI WINBOOL WINAPI CreateJobSet(ULONG NumJob,PJOB_SET_ARRAY UserJobSet,ULONG Flags); + WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); + WINBASEAPI ULONG WINAPI RemoveVectoredExceptionHandler(PVOID Handle); + WINBASEAPI PVOID WINAPI AddVectoredContinueHandler (ULONG First,PVECTORED_EXCEPTION_HANDLER Handler); + WINBASEAPI ULONG WINAPI RemoveVectoredContinueHandler(PVOID Handle); + WINBASEAPI HANDLE WINAPI FindFirstVolumeA(LPSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI HANDLE WINAPI FindFirstVolumeW(LPWSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeA(HANDLE hFindVolume,LPSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeW(HANDLE hFindVolume,LPWSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindVolumeClose(HANDLE hFindVolume); + WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointA(LPCSTR lpszRootPathName,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI HANDLE WINAPI FindFirstVolumeMountPointW(LPCWSTR lpszRootPathName,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointA(HANDLE hFindVolumeMountPoint,LPSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindNextVolumeMountPointW(HANDLE hFindVolumeMountPoint,LPWSTR lpszVolumeMountPoint,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI FindVolumeMountPointClose(HANDLE hFindVolumeMountPoint); + WINBASEAPI WINBOOL WINAPI SetVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPCSTR lpszVolumeName); + WINBASEAPI WINBOOL WINAPI SetVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPCWSTR lpszVolumeName); + WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointA(LPCSTR lpszVolumeMountPoint); + WINBASEAPI WINBOOL WINAPI DeleteVolumeMountPointW(LPCWSTR lpszVolumeMountPoint); + WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointA(LPCSTR lpszVolumeMountPoint,LPSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR lpszVolumeMountPoint,LPWSTR lpszVolumeName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNameA(LPCSTR lpszFileName,LPSTR lpszVolumePathName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNameW(LPCWSTR lpszFileName,LPWSTR lpszVolumePathName,DWORD cchBufferLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameA(LPCSTR lpszVolumeName,LPCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); + WINBASEAPI WINBOOL WINAPI GetVolumePathNamesForVolumeNameW(LPCWSTR lpszVolumeName,LPWCH lpszVolumePathNames,DWORD cchBufferLength,PDWORD lpcchReturnLength); + +#define ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID 0x1 +#define ACTCTX_FLAG_LANGID_VALID 0x2 +#define ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID 0x4 +#define ACTCTX_FLAG_RESOURCE_NAME_VALID 0x8 +#define ACTCTX_FLAG_SET_PROCESS_DEFAULT 0x10 +#define ACTCTX_FLAG_APPLICATION_NAME_VALID 0x20 +#define ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF 0x40 +#define ACTCTX_FLAG_HMODULE_VALID 0x80 + + typedef struct tagACTCTXA { + ULONG cbSize; + DWORD dwFlags; + LPCSTR lpSource; + USHORT wProcessorArchitecture; + LANGID wLangId; + LPCSTR lpAssemblyDirectory; + LPCSTR lpResourceName; + LPCSTR lpApplicationName; + HMODULE hModule; + } ACTCTXA,*PACTCTXA; + + typedef struct tagACTCTXW { + ULONG cbSize; + DWORD dwFlags; + LPCWSTR lpSource; + USHORT wProcessorArchitecture; + LANGID wLangId; + LPCWSTR lpAssemblyDirectory; + LPCWSTR lpResourceName; + LPCWSTR lpApplicationName; + HMODULE hModule; + } ACTCTXW,*PACTCTXW; + + typedef const ACTCTXA *PCACTCTXA; + typedef const ACTCTXW *PCACTCTXW; + +#ifdef UNICODE + typedef ACTCTXW ACTCTX; + typedef PACTCTXW PACTCTX; + typedef PCACTCTXW PCACTCTX; +#else + typedef ACTCTXA ACTCTX; + typedef PACTCTXA PACTCTX; + typedef PCACTCTXA PCACTCTX; +#endif + +#ifdef UNICODE +#define CreateActCtx CreateActCtxW +#else +#define CreateActCtx CreateActCtxA +#endif + + WINBASEAPI HANDLE WINAPI CreateActCtxA(PCACTCTXA pActCtx); + WINBASEAPI HANDLE WINAPI CreateActCtxW(PCACTCTXW pActCtx); + WINBASEAPI VOID WINAPI AddRefActCtx(HANDLE hActCtx); + WINBASEAPI VOID WINAPI ReleaseActCtx(HANDLE hActCtx); + WINBASEAPI WINBOOL WINAPI ZombifyActCtx(HANDLE hActCtx); + WINBASEAPI WINBOOL WINAPI ActivateActCtx(HANDLE hActCtx,ULONG_PTR *lpCookie); + +#define DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION (0x1) + + WINBASEAPI WINBOOL WINAPI DeactivateActCtx(DWORD dwFlags,ULONG_PTR ulCookie); + WINBASEAPI WINBOOL WINAPI GetCurrentActCtx(HANDLE *lphActCtx); + + typedef struct tagACTCTX_SECTION_KEYED_DATA_2600 { + ULONG cbSize; + ULONG ulDataFormatVersion; + PVOID lpData; + ULONG ulLength; + PVOID lpSectionGlobalData; + ULONG ulSectionGlobalDataLength; + PVOID lpSectionBase; + ULONG ulSectionTotalLength; + HANDLE hActCtx; + ULONG ulAssemblyRosterIndex; + } ACTCTX_SECTION_KEYED_DATA_2600,*PACTCTX_SECTION_KEYED_DATA_2600; + + typedef const ACTCTX_SECTION_KEYED_DATA_2600 *PCACTCTX_SECTION_KEYED_DATA_2600; + + typedef struct tagACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA { + PVOID lpInformation; + PVOID lpSectionBase; + ULONG ulSectionLength; + PVOID lpSectionGlobalDataBase; + ULONG ulSectionGlobalDataLength; + } ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA,*PACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; + + typedef const ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA *PCACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; + + typedef struct tagACTCTX_SECTION_KEYED_DATA { + ULONG cbSize; + ULONG ulDataFormatVersion; + PVOID lpData; + ULONG ulLength; + PVOID lpSectionGlobalData; + ULONG ulSectionGlobalDataLength; + PVOID lpSectionBase; + ULONG ulSectionTotalLength; + HANDLE hActCtx; + ULONG ulAssemblyRosterIndex; + + ULONG ulFlags; + ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA AssemblyMetadata; + } ACTCTX_SECTION_KEYED_DATA,*PACTCTX_SECTION_KEYED_DATA; + + typedef const ACTCTX_SECTION_KEYED_DATA *PCACTCTX_SECTION_KEYED_DATA; + +#define FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX 0x1 +#define FIND_ACTCTX_SECTION_KEY_RETURN_FLAGS 0x2 +#define FIND_ACTCTX_SECTION_KEY_RETURN_ASSEMBLY_METADATA 0x4 + +#ifdef UNICODE +#define FindActCtxSectionString FindActCtxSectionStringW +#else +#define FindActCtxSectionString FindActCtxSectionStringA +#endif + + WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringA(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); + WINBASEAPI WINBOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,LPCWSTR lpStringToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); + WINBASEAPI WINBOOL WINAPI FindActCtxSectionGuid(DWORD dwFlags,const GUID *lpExtensionGuid,ULONG ulSectionId,const GUID *lpGuidToFind,PACTCTX_SECTION_KEYED_DATA ReturnedData); + +#ifndef RC_INVOKED +#ifndef ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED + + typedef struct _ACTIVATION_CONTEXT_BASIC_INFORMATION { + HANDLE hActCtx; + DWORD dwFlags; + } ACTIVATION_CONTEXT_BASIC_INFORMATION,*PACTIVATION_CONTEXT_BASIC_INFORMATION; + + typedef const struct _ACTIVATION_CONTEXT_BASIC_INFORMATION *PCACTIVATION_CONTEXT_BASIC_INFORMATION; + +#define ACTIVATION_CONTEXT_BASIC_INFORMATION_DEFINED 1 +#endif +#endif + +#define QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX 0x4 +#define QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE 0x8 +#define QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS 0x10 +#define QUERY_ACTCTX_FLAG_NO_ADDREF 0x80000000 + + WINBASEAPI WINBOOL WINAPI QueryActCtxW(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); + + typedef WINBOOL (WINAPI *PQUERYACTCTXW_FUNC)(DWORD dwFlags,HANDLE hActCtx,PVOID pvSubInstance,ULONG ulInfoClass,PVOID pvBuffer,SIZE_T cbBuffer,SIZE_T *pcbWrittenOrRequired); + + WINBASEAPI WINBOOL WINAPI ProcessIdToSessionId(DWORD dwProcessId,DWORD *pSessionId); + WINBASEAPI DWORD WINAPI WTSGetActiveConsoleSessionId(); + WINBASEAPI WINBOOL WINAPI IsWow64Process(HANDLE hProcess,PBOOL Wow64Process); + WINBASEAPI WINBOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer,PDWORD ReturnedLength); + WINBASEAPI WINBOOL WINAPI GetNumaHighestNodeNumber(PULONG HighestNodeNumber); + WINBASEAPI WINBOOL WINAPI GetNumaProcessorNode(UCHAR Processor,PUCHAR NodeNumber); + WINBASEAPI WINBOOL WINAPI GetNumaNodeProcessorMask(UCHAR Node,PULONGLONG ProcessorMask); + WINBASEAPI WINBOOL WINAPI GetNumaAvailableMemoryNode(UCHAR Node,PULONGLONG AvailableBytes); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/wincon.h b/tcc/include/winapi/wincon.h index 3a9a94d7..a3501ee7 100644 --- a/tcc/include/winapi/wincon.h +++ b/tcc/include/winapi/wincon.h @@ -1,301 +1,301 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINCON_ -#define _WINCON_ - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct _COORD { - SHORT X; - SHORT Y; - } COORD,*PCOORD; - - typedef struct _SMALL_RECT { - SHORT Left; - SHORT Top; - SHORT Right; - SHORT Bottom; - } SMALL_RECT,*PSMALL_RECT; - - typedef struct _KEY_EVENT_RECORD { - WINBOOL bKeyDown; - WORD wRepeatCount; - WORD wVirtualKeyCode; - WORD wVirtualScanCode; - union { - WCHAR UnicodeChar; - CHAR AsciiChar; - } uChar; - DWORD dwControlKeyState; - } KEY_EVENT_RECORD,*PKEY_EVENT_RECORD; - -#define RIGHT_ALT_PRESSED 0x1 -#define LEFT_ALT_PRESSED 0x2 -#define RIGHT_CTRL_PRESSED 0x4 -#define LEFT_CTRL_PRESSED 0x8 -#define SHIFT_PRESSED 0x10 -#define NUMLOCK_ON 0x20 -#define SCROLLLOCK_ON 0x40 -#define CAPSLOCK_ON 0x80 -#define ENHANCED_KEY 0x100 -#define NLS_DBCSCHAR 0x10000 -#define NLS_ALPHANUMERIC 0x0 -#define NLS_KATAKANA 0x20000 -#define NLS_HIRAGANA 0x40000 -#define NLS_ROMAN 0x400000 -#define NLS_IME_CONVERSION 0x800000 -#define NLS_IME_DISABLE 0x20000000 - - typedef struct _MOUSE_EVENT_RECORD { - COORD dwMousePosition; - DWORD dwButtonState; - DWORD dwControlKeyState; - DWORD dwEventFlags; - } MOUSE_EVENT_RECORD,*PMOUSE_EVENT_RECORD; - -#define FROM_LEFT_1ST_BUTTON_PRESSED 0x1 -#define RIGHTMOST_BUTTON_PRESSED 0x2 -#define FROM_LEFT_2ND_BUTTON_PRESSED 0x4 -#define FROM_LEFT_3RD_BUTTON_PRESSED 0x8 -#define FROM_LEFT_4TH_BUTTON_PRESSED 0x10 - -#define MOUSE_MOVED 0x1 -#define DOUBLE_CLICK 0x2 -#define MOUSE_WHEELED 0x4 - - typedef struct _WINDOW_BUFFER_SIZE_RECORD { - COORD dwSize; - } WINDOW_BUFFER_SIZE_RECORD,*PWINDOW_BUFFER_SIZE_RECORD; - - typedef struct _MENU_EVENT_RECORD { - UINT dwCommandId; - } MENU_EVENT_RECORD,*PMENU_EVENT_RECORD; - - typedef struct _FOCUS_EVENT_RECORD { - WINBOOL bSetFocus; - } FOCUS_EVENT_RECORD,*PFOCUS_EVENT_RECORD; - - typedef struct _INPUT_RECORD { - WORD EventType; - union { - KEY_EVENT_RECORD KeyEvent; - MOUSE_EVENT_RECORD MouseEvent; - WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; - MENU_EVENT_RECORD MenuEvent; - FOCUS_EVENT_RECORD FocusEvent; - } Event; - } INPUT_RECORD,*PINPUT_RECORD; - -#define KEY_EVENT 0x1 -#define MOUSE_EVENT 0x2 -#define WINDOW_BUFFER_SIZE_EVENT 0x4 -#define MENU_EVENT 0x8 -#define FOCUS_EVENT 0x10 - - typedef struct _CHAR_INFO { - union { - WCHAR UnicodeChar; - CHAR AsciiChar; - } Char; - WORD Attributes; - } CHAR_INFO,*PCHAR_INFO; - -#define FOREGROUND_BLUE 0x1 -#define FOREGROUND_GREEN 0x2 -#define FOREGROUND_RED 0x4 -#define FOREGROUND_INTENSITY 0x8 -#define BACKGROUND_BLUE 0x10 -#define BACKGROUND_GREEN 0x20 -#define BACKGROUND_RED 0x40 -#define BACKGROUND_INTENSITY 0x80 -#define COMMON_LVB_LEADING_BYTE 0x100 -#define COMMON_LVB_TRAILING_BYTE 0x200 -#define COMMON_LVB_GRID_HORIZONTAL 0x400 -#define COMMON_LVB_GRID_LVERTICAL 0x800 -#define COMMON_LVB_GRID_RVERTICAL 0x1000 -#define COMMON_LVB_REVERSE_VIDEO 0x4000 -#define COMMON_LVB_UNDERSCORE 0x8000 - -#define COMMON_LVB_SBCSDBCS 0x300 - - typedef struct _CONSOLE_SCREEN_BUFFER_INFO { - COORD dwSize; - COORD dwCursorPosition; - WORD wAttributes; - SMALL_RECT srWindow; - COORD dwMaximumWindowSize; - } CONSOLE_SCREEN_BUFFER_INFO,*PCONSOLE_SCREEN_BUFFER_INFO; - - typedef struct _CONSOLE_CURSOR_INFO { - DWORD dwSize; - WINBOOL bVisible; - } CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO; - - typedef struct _CONSOLE_FONT_INFO { - DWORD nFont; - COORD dwFontSize; - } CONSOLE_FONT_INFO,*PCONSOLE_FONT_INFO; - - typedef struct _CONSOLE_SELECTION_INFO { - DWORD dwFlags; - COORD dwSelectionAnchor; - SMALL_RECT srSelection; - } CONSOLE_SELECTION_INFO,*PCONSOLE_SELECTION_INFO; - -#define CONSOLE_NO_SELECTION 0x0 -#define CONSOLE_SELECTION_IN_PROGRESS 0x1 -#define CONSOLE_SELECTION_NOT_EMPTY 0x2 -#define CONSOLE_MOUSE_SELECTION 0x4 -#define CONSOLE_MOUSE_DOWN 0x8 - - typedef WINBOOL (WINAPI *PHANDLER_ROUTINE)(DWORD CtrlType); - -#define CTRL_C_EVENT 0 -#define CTRL_BREAK_EVENT 1 -#define CTRL_CLOSE_EVENT 2 - -#define CTRL_LOGOFF_EVENT 5 -#define CTRL_SHUTDOWN_EVENT 6 - -#define ENABLE_PROCESSED_INPUT 0x1 -#define ENABLE_LINE_INPUT 0x2 -#define ENABLE_ECHO_INPUT 0x4 -#define ENABLE_WINDOW_INPUT 0x8 -#define ENABLE_MOUSE_INPUT 0x10 - -#define ENABLE_PROCESSED_OUTPUT 0x1 -#define ENABLE_WRAP_AT_EOL_OUTPUT 0x2 - -#ifdef UNICODE -#define PeekConsoleInput PeekConsoleInputW -#define ReadConsoleInput ReadConsoleInputW -#define WriteConsoleInput WriteConsoleInputW -#define ReadConsoleOutput ReadConsoleOutputW -#define WriteConsoleOutput WriteConsoleOutputW -#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterW -#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterW -#define FillConsoleOutputCharacter FillConsoleOutputCharacterW -#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferW -#define GetConsoleTitle GetConsoleTitleW -#define SetConsoleTitle SetConsoleTitleW -#define ReadConsole ReadConsoleW -#define WriteConsole WriteConsoleW -#define AddConsoleAlias AddConsoleAliasW -#define GetConsoleAlias GetConsoleAliasW -#define GetConsoleAliasesLength GetConsoleAliasesLengthW -#define GetConsoleAliasExesLength GetConsoleAliasExesLengthW -#define GetConsoleAliases GetConsoleAliasesW -#define GetConsoleAliasExes GetConsoleAliasExesW -#else -#define PeekConsoleInput PeekConsoleInputA -#define ReadConsoleInput ReadConsoleInputA -#define WriteConsoleInput WriteConsoleInputA -#define ReadConsoleOutput ReadConsoleOutputA -#define WriteConsoleOutput WriteConsoleOutputA -#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterA -#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterA -#define FillConsoleOutputCharacter FillConsoleOutputCharacterA -#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferA -#define GetConsoleTitle GetConsoleTitleA -#define SetConsoleTitle SetConsoleTitleA -#define ReadConsole ReadConsoleA -#define WriteConsole WriteConsoleA -#define AddConsoleAlias AddConsoleAliasA -#define GetConsoleAlias GetConsoleAliasA -#define GetConsoleAliasesLength GetConsoleAliasesLengthA -#define GetConsoleAliasExesLength GetConsoleAliasExesLengthA -#define GetConsoleAliases GetConsoleAliasesA -#define GetConsoleAliasExes GetConsoleAliasExesA -#endif - - WINBASEAPI WINBOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); - WINBASEAPI WINBOOL WINAPI WriteConsoleInputA(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); - WINBASEAPI WINBOOL WINAPI WriteConsoleInputW(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputA(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputW(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputA(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputW(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput,LPSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterW(HANDLE hConsoleOutput,LPWSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); - WINBASEAPI WINBOOL WINAPI ReadConsoleOutputAttribute(HANDLE hConsoleOutput,LPWORD lpAttribute,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfAttrsRead); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterA(HANDLE hConsoleOutput,LPCSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterW(HANDLE hConsoleOutput,LPCWSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI WriteConsoleOutputAttribute(HANDLE hConsoleOutput,CONST WORD *lpAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); - WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterA(HANDLE hConsoleOutput,CHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,WCHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); - WINBASEAPI WINBOOL WINAPI FillConsoleOutputAttribute(HANDLE hConsoleOutput,WORD wAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); - WINBASEAPI WINBOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle,LPDWORD lpMode); - WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hConsoleInput,LPDWORD lpNumberOfEvents); - WINBASEAPI WINBOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput,PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); - WINBASEAPI COORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput); - WINBASEAPI WINBOOL WINAPI GetConsoleCursorInfo(HANDLE hConsoleOutput,PCONSOLE_CURSOR_INFO lpConsoleCursorInfo); - WINBASEAPI WINBOOL WINAPI GetCurrentConsoleFont(HANDLE hConsoleOutput,WINBOOL bMaximumWindow,PCONSOLE_FONT_INFO lpConsoleCurrentFont); - WINBASEAPI COORD WINAPI GetConsoleFontSize(HANDLE hConsoleOutput,DWORD nFont); - WINBASEAPI WINBOOL WINAPI GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo); - WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD lpNumberOfMouseButtons); - WINBASEAPI WINBOOL WINAPI SetConsoleMode(HANDLE hConsoleHandle,DWORD dwMode); - WINBASEAPI WINBOOL WINAPI SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput); - WINBASEAPI WINBOOL WINAPI FlushConsoleInputBuffer(HANDLE hConsoleInput); - WINBASEAPI WINBOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput,COORD dwSize); - WINBASEAPI WINBOOL WINAPI SetConsoleCursorPosition(HANDLE hConsoleOutput,COORD dwCursorPosition); - WINBASEAPI WINBOOL WINAPI SetConsoleCursorInfo(HANDLE hConsoleOutput,CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo); - WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferA(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); - WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); - WINBASEAPI WINBOOL WINAPI SetConsoleWindowInfo(HANDLE hConsoleOutput,WINBOOL bAbsolute,CONST SMALL_RECT *lpConsoleWindow); - WINBASEAPI WINBOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttributes); - WINBASEAPI WINBOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,WINBOOL Add); - WINBASEAPI WINBOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,DWORD dwProcessGroupId); - WINBASEAPI WINBOOL WINAPI AllocConsole(VOID); - WINBASEAPI WINBOOL WINAPI FreeConsole(VOID); - WINBASEAPI WINBOOL WINAPI AttachConsole(DWORD dwProcessId); - -#define ATTACH_PARENT_PROCESS ((DWORD)-1) - - WINBASEAPI DWORD WINAPI GetConsoleTitleA(LPSTR lpConsoleTitle,DWORD nSize); - WINBASEAPI DWORD WINAPI GetConsoleTitleW(LPWSTR lpConsoleTitle,DWORD nSize); - WINBASEAPI WINBOOL WINAPI SetConsoleTitleA(LPCSTR lpConsoleTitle); - WINBASEAPI WINBOOL WINAPI SetConsoleTitleW(LPCWSTR lpConsoleTitle); - WINBASEAPI WINBOOL WINAPI ReadConsoleA(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI ReadConsoleW(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI WriteConsoleA(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); - WINBASEAPI WINBOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); - -#define CONSOLE_TEXTMODE_BUFFER 1 - - WINBASEAPI HANDLE WINAPI CreateConsoleScreenBuffer(DWORD dwDesiredAccess,DWORD dwShareMode,CONST SECURITY_ATTRIBUTES *lpSecurityAttributes,DWORD dwFlags,LPVOID lpScreenBufferData); - WINBASEAPI UINT WINAPI GetConsoleCP(VOID); - WINBASEAPI WINBOOL WINAPI SetConsoleCP(UINT wCodePageID); - WINBASEAPI UINT WINAPI GetConsoleOutputCP(VOID); - WINBASEAPI WINBOOL WINAPI SetConsoleOutputCP(UINT wCodePageID); - -#define CONSOLE_FULLSCREEN 1 -#define CONSOLE_FULLSCREEN_HARDWARE 2 - - WINBASEAPI WINBOOL WINAPI GetConsoleDisplayMode(LPDWORD lpModeFlags); - WINBASEAPI HWND WINAPI GetConsoleWindow(VOID); - WINBASEAPI DWORD WINAPI GetConsoleProcessList(LPDWORD lpdwProcessList,DWORD dwProcessCount); - WINBASEAPI WINBOOL WINAPI AddConsoleAliasA(LPSTR Source,LPSTR Target,LPSTR ExeName); - WINBASEAPI WINBOOL WINAPI AddConsoleAliasW(LPWSTR Source,LPWSTR Target,LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasA(LPSTR Source,LPSTR TargetBuffer,DWORD TargetBufferLength,LPSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasW(LPWSTR Source,LPWSTR TargetBuffer,DWORD TargetBufferLength,LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthA(LPSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthW(LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthA(VOID); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthW(VOID); - WINBASEAPI DWORD WINAPI GetConsoleAliasesA(LPSTR AliasBuffer,DWORD AliasBufferLength,LPSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasesW(LPWSTR AliasBuffer,DWORD AliasBufferLength,LPWSTR ExeName); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesA(LPSTR ExeNameBuffer,DWORD ExeNameBufferLength); - WINBASEAPI DWORD WINAPI GetConsoleAliasExesW(LPWSTR ExeNameBuffer,DWORD ExeNameBufferLength); - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINCON_ +#define _WINCON_ + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct _COORD { + SHORT X; + SHORT Y; + } COORD,*PCOORD; + + typedef struct _SMALL_RECT { + SHORT Left; + SHORT Top; + SHORT Right; + SHORT Bottom; + } SMALL_RECT,*PSMALL_RECT; + + typedef struct _KEY_EVENT_RECORD { + WINBOOL bKeyDown; + WORD wRepeatCount; + WORD wVirtualKeyCode; + WORD wVirtualScanCode; + union { + WCHAR UnicodeChar; + CHAR AsciiChar; + } uChar; + DWORD dwControlKeyState; + } KEY_EVENT_RECORD,*PKEY_EVENT_RECORD; + +#define RIGHT_ALT_PRESSED 0x1 +#define LEFT_ALT_PRESSED 0x2 +#define RIGHT_CTRL_PRESSED 0x4 +#define LEFT_CTRL_PRESSED 0x8 +#define SHIFT_PRESSED 0x10 +#define NUMLOCK_ON 0x20 +#define SCROLLLOCK_ON 0x40 +#define CAPSLOCK_ON 0x80 +#define ENHANCED_KEY 0x100 +#define NLS_DBCSCHAR 0x10000 +#define NLS_ALPHANUMERIC 0x0 +#define NLS_KATAKANA 0x20000 +#define NLS_HIRAGANA 0x40000 +#define NLS_ROMAN 0x400000 +#define NLS_IME_CONVERSION 0x800000 +#define NLS_IME_DISABLE 0x20000000 + + typedef struct _MOUSE_EVENT_RECORD { + COORD dwMousePosition; + DWORD dwButtonState; + DWORD dwControlKeyState; + DWORD dwEventFlags; + } MOUSE_EVENT_RECORD,*PMOUSE_EVENT_RECORD; + +#define FROM_LEFT_1ST_BUTTON_PRESSED 0x1 +#define RIGHTMOST_BUTTON_PRESSED 0x2 +#define FROM_LEFT_2ND_BUTTON_PRESSED 0x4 +#define FROM_LEFT_3RD_BUTTON_PRESSED 0x8 +#define FROM_LEFT_4TH_BUTTON_PRESSED 0x10 + +#define MOUSE_MOVED 0x1 +#define DOUBLE_CLICK 0x2 +#define MOUSE_WHEELED 0x4 + + typedef struct _WINDOW_BUFFER_SIZE_RECORD { + COORD dwSize; + } WINDOW_BUFFER_SIZE_RECORD,*PWINDOW_BUFFER_SIZE_RECORD; + + typedef struct _MENU_EVENT_RECORD { + UINT dwCommandId; + } MENU_EVENT_RECORD,*PMENU_EVENT_RECORD; + + typedef struct _FOCUS_EVENT_RECORD { + WINBOOL bSetFocus; + } FOCUS_EVENT_RECORD,*PFOCUS_EVENT_RECORD; + + typedef struct _INPUT_RECORD { + WORD EventType; + union { + KEY_EVENT_RECORD KeyEvent; + MOUSE_EVENT_RECORD MouseEvent; + WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; + MENU_EVENT_RECORD MenuEvent; + FOCUS_EVENT_RECORD FocusEvent; + } Event; + } INPUT_RECORD,*PINPUT_RECORD; + +#define KEY_EVENT 0x1 +#define MOUSE_EVENT 0x2 +#define WINDOW_BUFFER_SIZE_EVENT 0x4 +#define MENU_EVENT 0x8 +#define FOCUS_EVENT 0x10 + + typedef struct _CHAR_INFO { + union { + WCHAR UnicodeChar; + CHAR AsciiChar; + } Char; + WORD Attributes; + } CHAR_INFO,*PCHAR_INFO; + +#define FOREGROUND_BLUE 0x1 +#define FOREGROUND_GREEN 0x2 +#define FOREGROUND_RED 0x4 +#define FOREGROUND_INTENSITY 0x8 +#define BACKGROUND_BLUE 0x10 +#define BACKGROUND_GREEN 0x20 +#define BACKGROUND_RED 0x40 +#define BACKGROUND_INTENSITY 0x80 +#define COMMON_LVB_LEADING_BYTE 0x100 +#define COMMON_LVB_TRAILING_BYTE 0x200 +#define COMMON_LVB_GRID_HORIZONTAL 0x400 +#define COMMON_LVB_GRID_LVERTICAL 0x800 +#define COMMON_LVB_GRID_RVERTICAL 0x1000 +#define COMMON_LVB_REVERSE_VIDEO 0x4000 +#define COMMON_LVB_UNDERSCORE 0x8000 + +#define COMMON_LVB_SBCSDBCS 0x300 + + typedef struct _CONSOLE_SCREEN_BUFFER_INFO { + COORD dwSize; + COORD dwCursorPosition; + WORD wAttributes; + SMALL_RECT srWindow; + COORD dwMaximumWindowSize; + } CONSOLE_SCREEN_BUFFER_INFO,*PCONSOLE_SCREEN_BUFFER_INFO; + + typedef struct _CONSOLE_CURSOR_INFO { + DWORD dwSize; + WINBOOL bVisible; + } CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO; + + typedef struct _CONSOLE_FONT_INFO { + DWORD nFont; + COORD dwFontSize; + } CONSOLE_FONT_INFO,*PCONSOLE_FONT_INFO; + + typedef struct _CONSOLE_SELECTION_INFO { + DWORD dwFlags; + COORD dwSelectionAnchor; + SMALL_RECT srSelection; + } CONSOLE_SELECTION_INFO,*PCONSOLE_SELECTION_INFO; + +#define CONSOLE_NO_SELECTION 0x0 +#define CONSOLE_SELECTION_IN_PROGRESS 0x1 +#define CONSOLE_SELECTION_NOT_EMPTY 0x2 +#define CONSOLE_MOUSE_SELECTION 0x4 +#define CONSOLE_MOUSE_DOWN 0x8 + + typedef WINBOOL (WINAPI *PHANDLER_ROUTINE)(DWORD CtrlType); + +#define CTRL_C_EVENT 0 +#define CTRL_BREAK_EVENT 1 +#define CTRL_CLOSE_EVENT 2 + +#define CTRL_LOGOFF_EVENT 5 +#define CTRL_SHUTDOWN_EVENT 6 + +#define ENABLE_PROCESSED_INPUT 0x1 +#define ENABLE_LINE_INPUT 0x2 +#define ENABLE_ECHO_INPUT 0x4 +#define ENABLE_WINDOW_INPUT 0x8 +#define ENABLE_MOUSE_INPUT 0x10 + +#define ENABLE_PROCESSED_OUTPUT 0x1 +#define ENABLE_WRAP_AT_EOL_OUTPUT 0x2 + +#ifdef UNICODE +#define PeekConsoleInput PeekConsoleInputW +#define ReadConsoleInput ReadConsoleInputW +#define WriteConsoleInput WriteConsoleInputW +#define ReadConsoleOutput ReadConsoleOutputW +#define WriteConsoleOutput WriteConsoleOutputW +#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterW +#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterW +#define FillConsoleOutputCharacter FillConsoleOutputCharacterW +#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferW +#define GetConsoleTitle GetConsoleTitleW +#define SetConsoleTitle SetConsoleTitleW +#define ReadConsole ReadConsoleW +#define WriteConsole WriteConsoleW +#define AddConsoleAlias AddConsoleAliasW +#define GetConsoleAlias GetConsoleAliasW +#define GetConsoleAliasesLength GetConsoleAliasesLengthW +#define GetConsoleAliasExesLength GetConsoleAliasExesLengthW +#define GetConsoleAliases GetConsoleAliasesW +#define GetConsoleAliasExes GetConsoleAliasExesW +#else +#define PeekConsoleInput PeekConsoleInputA +#define ReadConsoleInput ReadConsoleInputA +#define WriteConsoleInput WriteConsoleInputA +#define ReadConsoleOutput ReadConsoleOutputA +#define WriteConsoleOutput WriteConsoleOutputA +#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterA +#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterA +#define FillConsoleOutputCharacter FillConsoleOutputCharacterA +#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferA +#define GetConsoleTitle GetConsoleTitleA +#define SetConsoleTitle SetConsoleTitleA +#define ReadConsole ReadConsoleA +#define WriteConsole WriteConsoleA +#define AddConsoleAlias AddConsoleAliasA +#define GetConsoleAlias GetConsoleAliasA +#define GetConsoleAliasesLength GetConsoleAliasesLengthA +#define GetConsoleAliasExesLength GetConsoleAliasExesLengthA +#define GetConsoleAliases GetConsoleAliasesA +#define GetConsoleAliasExes GetConsoleAliasExesA +#endif + + WINBASEAPI WINBOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput,PINPUT_RECORD lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsRead); + WINBASEAPI WINBOOL WINAPI WriteConsoleInputA(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); + WINBASEAPI WINBOOL WINAPI WriteConsoleInputW(HANDLE hConsoleInput,CONST INPUT_RECORD *lpBuffer,DWORD nLength,LPDWORD lpNumberOfEventsWritten); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputA(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputW(HANDLE hConsoleOutput,PCHAR_INFO lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpReadRegion); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputA(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputW(HANDLE hConsoleOutput,CONST CHAR_INFO *lpBuffer,COORD dwBufferSize,COORD dwBufferCoord,PSMALL_RECT lpWriteRegion); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput,LPSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputCharacterW(HANDLE hConsoleOutput,LPWSTR lpCharacter,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfCharsRead); + WINBASEAPI WINBOOL WINAPI ReadConsoleOutputAttribute(HANDLE hConsoleOutput,LPWORD lpAttribute,DWORD nLength,COORD dwReadCoord,LPDWORD lpNumberOfAttrsRead); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterA(HANDLE hConsoleOutput,LPCSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputCharacterW(HANDLE hConsoleOutput,LPCWSTR lpCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI WriteConsoleOutputAttribute(HANDLE hConsoleOutput,CONST WORD *lpAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); + WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterA(HANDLE hConsoleOutput,CHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,WCHAR cCharacter,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfCharsWritten); + WINBASEAPI WINBOOL WINAPI FillConsoleOutputAttribute(HANDLE hConsoleOutput,WORD wAttribute,DWORD nLength,COORD dwWriteCoord,LPDWORD lpNumberOfAttrsWritten); + WINBASEAPI WINBOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle,LPDWORD lpMode); + WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hConsoleInput,LPDWORD lpNumberOfEvents); + WINBASEAPI WINBOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput,PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); + WINBASEAPI COORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput); + WINBASEAPI WINBOOL WINAPI GetConsoleCursorInfo(HANDLE hConsoleOutput,PCONSOLE_CURSOR_INFO lpConsoleCursorInfo); + WINBASEAPI WINBOOL WINAPI GetCurrentConsoleFont(HANDLE hConsoleOutput,WINBOOL bMaximumWindow,PCONSOLE_FONT_INFO lpConsoleCurrentFont); + WINBASEAPI COORD WINAPI GetConsoleFontSize(HANDLE hConsoleOutput,DWORD nFont); + WINBASEAPI WINBOOL WINAPI GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo); + WINBASEAPI WINBOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD lpNumberOfMouseButtons); + WINBASEAPI WINBOOL WINAPI SetConsoleMode(HANDLE hConsoleHandle,DWORD dwMode); + WINBASEAPI WINBOOL WINAPI SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput); + WINBASEAPI WINBOOL WINAPI FlushConsoleInputBuffer(HANDLE hConsoleInput); + WINBASEAPI WINBOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput,COORD dwSize); + WINBASEAPI WINBOOL WINAPI SetConsoleCursorPosition(HANDLE hConsoleOutput,COORD dwCursorPosition); + WINBASEAPI WINBOOL WINAPI SetConsoleCursorInfo(HANDLE hConsoleOutput,CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo); + WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferA(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); + WINBASEAPI WINBOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput,CONST SMALL_RECT *lpScrollRectangle,CONST SMALL_RECT *lpClipRectangle,COORD dwDestinationOrigin,CONST CHAR_INFO *lpFill); + WINBASEAPI WINBOOL WINAPI SetConsoleWindowInfo(HANDLE hConsoleOutput,WINBOOL bAbsolute,CONST SMALL_RECT *lpConsoleWindow); + WINBASEAPI WINBOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttributes); + WINBASEAPI WINBOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,WINBOOL Add); + WINBASEAPI WINBOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,DWORD dwProcessGroupId); + WINBASEAPI WINBOOL WINAPI AllocConsole(VOID); + WINBASEAPI WINBOOL WINAPI FreeConsole(VOID); + WINBASEAPI WINBOOL WINAPI AttachConsole(DWORD dwProcessId); + +#define ATTACH_PARENT_PROCESS ((DWORD)-1) + + WINBASEAPI DWORD WINAPI GetConsoleTitleA(LPSTR lpConsoleTitle,DWORD nSize); + WINBASEAPI DWORD WINAPI GetConsoleTitleW(LPWSTR lpConsoleTitle,DWORD nSize); + WINBASEAPI WINBOOL WINAPI SetConsoleTitleA(LPCSTR lpConsoleTitle); + WINBASEAPI WINBOOL WINAPI SetConsoleTitleW(LPCWSTR lpConsoleTitle); + WINBASEAPI WINBOOL WINAPI ReadConsoleA(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI ReadConsoleW(HANDLE hConsoleInput,LPVOID lpBuffer,DWORD nNumberOfCharsToRead,LPDWORD lpNumberOfCharsRead,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI WriteConsoleA(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); + WINBASEAPI WINBOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput,CONST VOID *lpBuffer,DWORD nNumberOfCharsToWrite,LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved); + +#define CONSOLE_TEXTMODE_BUFFER 1 + + WINBASEAPI HANDLE WINAPI CreateConsoleScreenBuffer(DWORD dwDesiredAccess,DWORD dwShareMode,CONST SECURITY_ATTRIBUTES *lpSecurityAttributes,DWORD dwFlags,LPVOID lpScreenBufferData); + WINBASEAPI UINT WINAPI GetConsoleCP(VOID); + WINBASEAPI WINBOOL WINAPI SetConsoleCP(UINT wCodePageID); + WINBASEAPI UINT WINAPI GetConsoleOutputCP(VOID); + WINBASEAPI WINBOOL WINAPI SetConsoleOutputCP(UINT wCodePageID); + +#define CONSOLE_FULLSCREEN 1 +#define CONSOLE_FULLSCREEN_HARDWARE 2 + + WINBASEAPI WINBOOL WINAPI GetConsoleDisplayMode(LPDWORD lpModeFlags); + WINBASEAPI HWND WINAPI GetConsoleWindow(VOID); + WINBASEAPI DWORD WINAPI GetConsoleProcessList(LPDWORD lpdwProcessList,DWORD dwProcessCount); + WINBASEAPI WINBOOL WINAPI AddConsoleAliasA(LPSTR Source,LPSTR Target,LPSTR ExeName); + WINBASEAPI WINBOOL WINAPI AddConsoleAliasW(LPWSTR Source,LPWSTR Target,LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasA(LPSTR Source,LPSTR TargetBuffer,DWORD TargetBufferLength,LPSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasW(LPWSTR Source,LPWSTR TargetBuffer,DWORD TargetBufferLength,LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthA(LPSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasesLengthW(LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthA(VOID); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesLengthW(VOID); + WINBASEAPI DWORD WINAPI GetConsoleAliasesA(LPSTR AliasBuffer,DWORD AliasBufferLength,LPSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasesW(LPWSTR AliasBuffer,DWORD AliasBufferLength,LPWSTR ExeName); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesA(LPSTR ExeNameBuffer,DWORD ExeNameBufferLength); + WINBASEAPI DWORD WINAPI GetConsoleAliasExesW(LPWSTR ExeNameBuffer,DWORD ExeNameBufferLength); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/windef.h b/tcc/include/winapi/windef.h index e784a008..d63bdef1 100644 --- a/tcc/include/winapi/windef.h +++ b/tcc/include/winapi/windef.h @@ -1,293 +1,293 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINDEF_ -#define _WINDEF_ - -#ifndef STRICT -#define STRICT 1 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#ifndef BASETYPES -#define BASETYPES - typedef unsigned long ULONG; - typedef ULONG *PULONG; - typedef unsigned short USHORT; - typedef USHORT *PUSHORT; - typedef unsigned char UCHAR; - typedef UCHAR *PUCHAR; - typedef char *PSZ; -#endif - -#define MAX_PATH 260 - -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef IN -#define IN -#endif - -#ifndef OUT -#define OUT -#endif - -#ifndef OPTIONAL -#define OPTIONAL -#endif - -#undef far -#undef near -#undef pascal - -#define far -#define near -#define pascal __stdcall - -#define cdecl -#ifndef CDECL -#define CDECL -#endif -#ifndef CALLBACK -#define CALLBACK __stdcall -#endif -#ifndef WINAPI -#define WINAPI __stdcall -#endif -#define WINAPIV __cdecl -#define APIENTRY WINAPI -#define APIPRIVATE WINAPI -#define PASCAL WINAPI -#define WINAPI_INLINE WINAPI - -#undef FAR -#undef NEAR -#define FAR -#define NEAR -#ifndef CONST -#define CONST const -#endif - - typedef unsigned long DWORD; - typedef int WINBOOL; -#define BOOL WINBOOL - typedef unsigned char BYTE; - typedef unsigned short WORD; - typedef float FLOAT; - typedef FLOAT *PFLOAT; - typedef WINBOOL *PBOOL; - typedef WINBOOL *LPBOOL; - typedef BYTE *PBYTE; - typedef BYTE *LPBYTE; - typedef int *PINT; - typedef int *LPINT; - typedef WORD *PWORD; - typedef WORD *LPWORD; - typedef long *LPLONG; - typedef DWORD *PDWORD; - typedef DWORD *LPDWORD; - typedef void *LPVOID; -# ifndef _LPCVOID_DEFINED -#define _LPCVOID_DEFINED -typedef CONST void *LPCVOID; -#endif - typedef int INT; - typedef unsigned int UINT; - typedef unsigned int *PUINT; - -#ifndef NT_INCLUDED -#include -#endif - -//gr #include - - typedef UINT_PTR WPARAM; - typedef LONG_PTR LPARAM; - typedef LONG_PTR LRESULT; - -#ifndef __cplusplus -#ifndef NOMINMAX -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#endif -#endif - -#define MAKEWORD(a,b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8)) -#define MAKELONG(a,b) ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16)) -#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) -#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) -#define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff)) -#define HIBYTE(w) ((BYTE)((DWORD_PTR)(w) >> 8)) - -#ifndef WIN_INTERNAL - DECLARE_HANDLE (HWND); - DECLARE_HANDLE (HHOOK); -#ifdef WINABLE - DECLARE_HANDLE (HEVENT); -#endif -#endif - - typedef WORD ATOM; - - typedef HANDLE *SPHANDLE; - typedef HANDLE *LPHANDLE; - typedef HANDLE HGLOBAL; - typedef HANDLE HLOCAL; - typedef HANDLE GLOBALHANDLE; - typedef HANDLE LOCALHANDLE; -#ifdef _WIN64 - typedef INT_PTR (WINAPI *FARPROC)(); - typedef INT_PTR (WINAPI *NEARPROC)(); - typedef INT_PTR (WINAPI *PROC)(); -#else - typedef int (WINAPI *FARPROC)(); - typedef int (WINAPI *NEARPROC)(); - typedef int (WINAPI *PROC)(); -#endif - - typedef void *HGDIOBJ; - - DECLARE_HANDLE(HKEY); - typedef HKEY *PHKEY; - - DECLARE_HANDLE(HACCEL); - DECLARE_HANDLE(HBITMAP); - DECLARE_HANDLE(HBRUSH); - DECLARE_HANDLE(HCOLORSPACE); - DECLARE_HANDLE(HDC); - DECLARE_HANDLE(HGLRC); - DECLARE_HANDLE(HDESK); - DECLARE_HANDLE(HENHMETAFILE); - DECLARE_HANDLE(HFONT); - DECLARE_HANDLE(HICON); - DECLARE_HANDLE(HMENU); - DECLARE_HANDLE(HMETAFILE); - DECLARE_HANDLE(HINSTANCE); - typedef HINSTANCE HMODULE; - DECLARE_HANDLE(HPALETTE); - DECLARE_HANDLE(HPEN); - DECLARE_HANDLE(HRGN); - DECLARE_HANDLE(HRSRC); - DECLARE_HANDLE(HSTR); - DECLARE_HANDLE(HTASK); - DECLARE_HANDLE(HWINSTA); - DECLARE_HANDLE(HKL); - DECLARE_HANDLE(HMONITOR); - DECLARE_HANDLE(HWINEVENTHOOK); - DECLARE_HANDLE(HUMPD); - - typedef int HFILE; - typedef HICON HCURSOR; - typedef DWORD COLORREF; - typedef DWORD *LPCOLORREF; - -#define HFILE_ERROR ((HFILE)-1) - - typedef struct tagRECT { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECT,*PRECT,*NPRECT,*LPRECT; - - typedef const RECT *LPCRECT; - - typedef struct _RECTL { - LONG left; - LONG top; - LONG right; - LONG bottom; - } RECTL,*PRECTL,*LPRECTL; - - typedef const RECTL *LPCRECTL; - - typedef struct tagPOINT { - LONG x; - LONG y; - } POINT,*PPOINT,*NPPOINT,*LPPOINT; - - typedef struct _POINTL { - LONG x; - LONG y; - } POINTL,*PPOINTL; - - typedef struct tagSIZE { - LONG cx; - LONG cy; - } SIZE,*PSIZE,*LPSIZE; - - typedef SIZE SIZEL; - typedef SIZE *PSIZEL,*LPSIZEL; - - typedef struct tagPOINTS { - SHORT x; - SHORT y; - } POINTS,*PPOINTS,*LPPOINTS; - - typedef struct _FILETIME { - DWORD dwLowDateTime; - DWORD dwHighDateTime; - } FILETIME,*PFILETIME,*LPFILETIME; -#define _FILETIME_ - -#define DM_UPDATE 1 -#define DM_COPY 2 -#define DM_PROMPT 4 -#define DM_MODIFY 8 - -#define DM_IN_BUFFER DM_MODIFY -#define DM_IN_PROMPT DM_PROMPT -#define DM_OUT_BUFFER DM_COPY -#define DM_OUT_DEFAULT DM_UPDATE - -#define DC_FIELDS 1 -#define DC_PAPERS 2 -#define DC_PAPERSIZE 3 -#define DC_MINEXTENT 4 -#define DC_MAXEXTENT 5 -#define DC_BINS 6 -#define DC_DUPLEX 7 -#define DC_SIZE 8 -#define DC_EXTRA 9 -#define DC_VERSION 10 -#define DC_DRIVER 11 -#define DC_BINNAMES 12 -#define DC_ENUMRESOLUTIONS 13 -#define DC_FILEDEPENDENCIES 14 -#define DC_TRUETYPE 15 -#define DC_PAPERNAMES 16 -#define DC_ORIENTATION 17 -#define DC_COPIES 18 - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINDEF_ +#define _WINDEF_ + +#ifndef STRICT +#define STRICT 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#ifndef BASETYPES +#define BASETYPES + typedef unsigned long ULONG; + typedef ULONG *PULONG; + typedef unsigned short USHORT; + typedef USHORT *PUSHORT; + typedef unsigned char UCHAR; + typedef UCHAR *PUCHAR; + typedef char *PSZ; +#endif + +#define MAX_PATH 260 + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + +#ifndef OPTIONAL +#define OPTIONAL +#endif + +#undef far +#undef near +#undef pascal + +#define far +#define near +#define pascal __stdcall + +#define cdecl +#ifndef CDECL +#define CDECL +#endif +#ifndef CALLBACK +#define CALLBACK __stdcall +#endif +#ifndef WINAPI +#define WINAPI __stdcall +#endif +#define WINAPIV __cdecl +#define APIENTRY WINAPI +#define APIPRIVATE WINAPI +#define PASCAL WINAPI +#define WINAPI_INLINE WINAPI + +#undef FAR +#undef NEAR +#define FAR +#define NEAR +#ifndef CONST +#define CONST const +#endif + + typedef unsigned long DWORD; + typedef int WINBOOL; +#define BOOL WINBOOL + typedef unsigned char BYTE; + typedef unsigned short WORD; + typedef float FLOAT; + typedef FLOAT *PFLOAT; + typedef WINBOOL *PBOOL; + typedef WINBOOL *LPBOOL; + typedef BYTE *PBYTE; + typedef BYTE *LPBYTE; + typedef int *PINT; + typedef int *LPINT; + typedef WORD *PWORD; + typedef WORD *LPWORD; + typedef long *LPLONG; + typedef DWORD *PDWORD; + typedef DWORD *LPDWORD; + typedef void *LPVOID; +# ifndef _LPCVOID_DEFINED +#define _LPCVOID_DEFINED +typedef CONST void *LPCVOID; +#endif + typedef int INT; + typedef unsigned int UINT; + typedef unsigned int *PUINT; + +#ifndef NT_INCLUDED +#include +#endif + +//gr #include + + typedef UINT_PTR WPARAM; + typedef LONG_PTR LPARAM; + typedef LONG_PTR LRESULT; + +#ifndef __cplusplus +#ifndef NOMINMAX +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#endif +#endif + +#define MAKEWORD(a,b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8)) +#define MAKELONG(a,b) ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16)) +#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) +#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) +#define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff)) +#define HIBYTE(w) ((BYTE)((DWORD_PTR)(w) >> 8)) + +#ifndef WIN_INTERNAL + DECLARE_HANDLE (HWND); + DECLARE_HANDLE (HHOOK); +#ifdef WINABLE + DECLARE_HANDLE (HEVENT); +#endif +#endif + + typedef WORD ATOM; + + typedef HANDLE *SPHANDLE; + typedef HANDLE *LPHANDLE; + typedef HANDLE HGLOBAL; + typedef HANDLE HLOCAL; + typedef HANDLE GLOBALHANDLE; + typedef HANDLE LOCALHANDLE; +#ifdef _WIN64 + typedef INT_PTR (WINAPI *FARPROC)(); + typedef INT_PTR (WINAPI *NEARPROC)(); + typedef INT_PTR (WINAPI *PROC)(); +#else + typedef int (WINAPI *FARPROC)(); + typedef int (WINAPI *NEARPROC)(); + typedef int (WINAPI *PROC)(); +#endif + + typedef void *HGDIOBJ; + + DECLARE_HANDLE(HKEY); + typedef HKEY *PHKEY; + + DECLARE_HANDLE(HACCEL); + DECLARE_HANDLE(HBITMAP); + DECLARE_HANDLE(HBRUSH); + DECLARE_HANDLE(HCOLORSPACE); + DECLARE_HANDLE(HDC); + DECLARE_HANDLE(HGLRC); + DECLARE_HANDLE(HDESK); + DECLARE_HANDLE(HENHMETAFILE); + DECLARE_HANDLE(HFONT); + DECLARE_HANDLE(HICON); + DECLARE_HANDLE(HMENU); + DECLARE_HANDLE(HMETAFILE); + DECLARE_HANDLE(HINSTANCE); + typedef HINSTANCE HMODULE; + DECLARE_HANDLE(HPALETTE); + DECLARE_HANDLE(HPEN); + DECLARE_HANDLE(HRGN); + DECLARE_HANDLE(HRSRC); + DECLARE_HANDLE(HSTR); + DECLARE_HANDLE(HTASK); + DECLARE_HANDLE(HWINSTA); + DECLARE_HANDLE(HKL); + DECLARE_HANDLE(HMONITOR); + DECLARE_HANDLE(HWINEVENTHOOK); + DECLARE_HANDLE(HUMPD); + + typedef int HFILE; + typedef HICON HCURSOR; + typedef DWORD COLORREF; + typedef DWORD *LPCOLORREF; + +#define HFILE_ERROR ((HFILE)-1) + + typedef struct tagRECT { + LONG left; + LONG top; + LONG right; + LONG bottom; + } RECT,*PRECT,*NPRECT,*LPRECT; + + typedef const RECT *LPCRECT; + + typedef struct _RECTL { + LONG left; + LONG top; + LONG right; + LONG bottom; + } RECTL,*PRECTL,*LPRECTL; + + typedef const RECTL *LPCRECTL; + + typedef struct tagPOINT { + LONG x; + LONG y; + } POINT,*PPOINT,*NPPOINT,*LPPOINT; + + typedef struct _POINTL { + LONG x; + LONG y; + } POINTL,*PPOINTL; + + typedef struct tagSIZE { + LONG cx; + LONG cy; + } SIZE,*PSIZE,*LPSIZE; + + typedef SIZE SIZEL; + typedef SIZE *PSIZEL,*LPSIZEL; + + typedef struct tagPOINTS { + SHORT x; + SHORT y; + } POINTS,*PPOINTS,*LPPOINTS; + + typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; + } FILETIME,*PFILETIME,*LPFILETIME; +#define _FILETIME_ + +#define DM_UPDATE 1 +#define DM_COPY 2 +#define DM_PROMPT 4 +#define DM_MODIFY 8 + +#define DM_IN_BUFFER DM_MODIFY +#define DM_IN_PROMPT DM_PROMPT +#define DM_OUT_BUFFER DM_COPY +#define DM_OUT_DEFAULT DM_UPDATE + +#define DC_FIELDS 1 +#define DC_PAPERS 2 +#define DC_PAPERSIZE 3 +#define DC_MINEXTENT 4 +#define DC_MAXEXTENT 5 +#define DC_BINS 6 +#define DC_DUPLEX 7 +#define DC_SIZE 8 +#define DC_EXTRA 9 +#define DC_VERSION 10 +#define DC_DRIVER 11 +#define DC_BINNAMES 12 +#define DC_ENUMRESOLUTIONS 13 +#define DC_FILEDEPENDENCIES 14 +#define DC_TRUETYPE 15 +#define DC_PAPERNAMES 16 +#define DC_ORIENTATION 17 +#define DC_COPIES 18 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/windows.h b/tcc/include/winapi/windows.h index ebbeed59..ff6454a9 100644 --- a/tcc/include/winapi/windows.h +++ b/tcc/include/winapi/windows.h @@ -1,127 +1,127 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINDOWS_ -#define _WINDOWS_ - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#include <_mingw.h> - -#ifndef _INC_WINDOWS -#define _INC_WINDOWS - -#if defined(RC_INVOKED) && !defined(NOWINRES) - -#include -#else - -#ifdef RC_INVOKED -#define NOATOM -#define NOGDI -#define NOGDICAPMASKS -#define NOMETAFILE -#define NOMINMAX -#define NOMSG -#define NOOPENFILE -#define NORASTEROPS -#define NOSCROLL -#define NOSOUND -#define NOSYSMETRICS -#define NOTEXTMETRIC -#define NOWH -#define NOCOMM -#define NOKANJI -#define NOCRYPT -#define NOMCX -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) -#define I_X86_ -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) -#define _AMD64_ -#endif - -#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) -#if !defined(_IA64_) -#define _IA64_ -#endif -#endif - -#ifndef RC_INVOKED -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -//gr #include - -#ifndef WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef NOCRYPT -#include -#include -#include -#endif - -#ifndef NOUSER -#ifndef NOGDI -#include -#ifdef INC_OLE1 -#include -#else -#include -#endif -#include -#endif -#endif -#endif - -//gr #include - -#ifdef INC_OLE2 -#include -#endif - -#ifndef NOSERVICE -#include -#endif - -#ifndef NOMCX -#include -#endif - -#ifndef NOIME -#include -#endif - -#endif -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINDOWS_ +#define _WINDOWS_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#include <_mingw.h> + +#ifndef _INC_WINDOWS +#define _INC_WINDOWS + +#if defined(RC_INVOKED) && !defined(NOWINRES) + +#include +#else + +#ifdef RC_INVOKED +#define NOATOM +#define NOGDI +#define NOGDICAPMASKS +#define NOMETAFILE +#define NOMINMAX +#define NOMSG +#define NOOPENFILE +#define NORASTEROPS +#define NOSCROLL +#define NOSOUND +#define NOSYSMETRICS +#define NOTEXTMETRIC +#define NOWH +#define NOCOMM +#define NOKANJI +#define NOCRYPT +#define NOMCX +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) +#define I_X86_ +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) +#define _AMD64_ +#endif + +#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) +#if !defined(_IA64_) +#define _IA64_ +#endif +#endif + +#ifndef RC_INVOKED +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +//gr #include + +#ifndef WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef NOCRYPT +#include +#include +#include +#endif + +#ifndef NOUSER +#ifndef NOGDI +#include +#ifdef INC_OLE1 +#include +#else +#include +#endif +#include +#endif +#endif +#endif + +//gr #include + +#ifdef INC_OLE2 +#include +#endif + +#ifndef NOSERVICE +#include +#endif + +#ifndef NOMCX +#include +#endif + +#ifndef NOIME +#include +#endif + +#endif +#endif +#endif diff --git a/tcc/include/winapi/winerror.h b/tcc/include/winapi/winerror.h index 4524a3c1..77d85edc 100644 --- a/tcc/include/winapi/winerror.h +++ b/tcc/include/winapi/winerror.h @@ -1,3166 +1,3166 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINERROR_ -#define _WINERROR_ - -#define FACILITY_WINDOWSUPDATE 36 -#define FACILITY_WINDOWS_CE 24 -#define FACILITY_WINDOWS 8 -#define FACILITY_URT 19 -#define FACILITY_UMI 22 -#define FACILITY_SXS 23 -#define FACILITY_STORAGE 3 -#define FACILITY_STATE_MANAGEMENT 34 -#define FACILITY_SSPI 9 -#define FACILITY_SCARD 16 -#define FACILITY_SETUPAPI 15 -#define FACILITY_SECURITY 9 -#define FACILITY_RPC 1 -#define FACILITY_WIN32 7 -#define FACILITY_CONTROL 10 -#define FACILITY_NULL 0 -#define FACILITY_METADIRECTORY 35 -#define FACILITY_MSMQ 14 -#define FACILITY_MEDIASERVER 13 -#define FACILITY_INTERNET 12 -#define FACILITY_ITF 4 -#define FACILITY_HTTP 25 -#define FACILITY_DPLAY 21 -#define FACILITY_DISPATCH 2 -#define FACILITY_DIRECTORYSERVICE 37 -#define FACILITY_CONFIGURATION 33 -#define FACILITY_COMPLUS 17 -#define FACILITY_CERT 11 -#define FACILITY_BACKGROUNDCOPY 32 -#define FACILITY_ACS 20 -#define FACILITY_AAF 18 -#define ERROR_SUCCESS 0L -#define NO_ERROR 0L -#define SEC_E_OK ((HRESULT)0x00000000L) -#define ERROR_INVALID_FUNCTION 1L -#define ERROR_FILE_NOT_FOUND 2L -#define ERROR_PATH_NOT_FOUND 3L -#define ERROR_TOO_MANY_OPEN_FILES 4L -#define ERROR_ACCESS_DENIED 5L -#define ERROR_INVALID_HANDLE 6L -#define ERROR_ARENA_TRASHED 7L -#define ERROR_NOT_ENOUGH_MEMORY 8L -#define ERROR_INVALID_BLOCK 9L -#define ERROR_BAD_ENVIRONMENT 10L -#define ERROR_BAD_FORMAT 11L -#define ERROR_INVALID_ACCESS 12L -#define ERROR_INVALID_DATA 13L -#define ERROR_OUTOFMEMORY 14L -#define ERROR_INVALID_DRIVE 15L -#define ERROR_CURRENT_DIRECTORY 16L -#define ERROR_NOT_SAME_DEVICE 17L -#define ERROR_NO_MORE_FILES 18L -#define ERROR_WRITE_PROTECT 19L -#define ERROR_BAD_UNIT 20L -#define ERROR_NOT_READY 21L -#define ERROR_BAD_COMMAND 22L -#define ERROR_CRC 23L -#define ERROR_BAD_LENGTH 24L -#define ERROR_SEEK 25L -#define ERROR_NOT_DOS_DISK 26L -#define ERROR_SECTOR_NOT_FOUND 27L -#define ERROR_OUT_OF_PAPER 28L -#define ERROR_WRITE_FAULT 29L -#define ERROR_READ_FAULT 30L -#define ERROR_GEN_FAILURE 31L -#define ERROR_SHARING_VIOLATION 32L -#define ERROR_LOCK_VIOLATION 33L -#define ERROR_WRONG_DISK 34L -#define ERROR_SHARING_BUFFER_EXCEEDED 36L -#define ERROR_HANDLE_EOF 38L -#define ERROR_HANDLE_DISK_FULL 39L -#define ERROR_NOT_SUPPORTED 50L -#define ERROR_REM_NOT_LIST 51L -#define ERROR_DUP_NAME 52L -#define ERROR_BAD_NETPATH 53L -#define ERROR_NETWORK_BUSY 54L -#define ERROR_DEV_NOT_EXIST 55L -#define ERROR_TOO_MANY_CMDS 56L -#define ERROR_ADAP_HDW_ERR 57L -#define ERROR_BAD_NET_RESP 58L -#define ERROR_UNEXP_NET_ERR 59L -#define ERROR_BAD_REM_ADAP 60L -#define ERROR_PRINTQ_FULL 61L -#define ERROR_NO_SPOOL_SPACE 62L -#define ERROR_PRINT_CANCELLED 63L -#define ERROR_NETNAME_DELETED 64L -#define ERROR_NETWORK_ACCESS_DENIED 65L -#define ERROR_BAD_DEV_TYPE 66L -#define ERROR_BAD_NET_NAME 67L -#define ERROR_TOO_MANY_NAMES 68L -#define ERROR_TOO_MANY_SESS 69L -#define ERROR_SHARING_PAUSED 70L -#define ERROR_REQ_NOT_ACCEP 71L -#define ERROR_REDIR_PAUSED 72L -#define ERROR_FILE_EXISTS 80L -#define ERROR_CANNOT_MAKE 82L -#define ERROR_FAIL_I24 83L -#define ERROR_OUT_OF_STRUCTURES 84L -#define ERROR_ALREADY_ASSIGNED 85L -#define ERROR_INVALID_PASSWORD 86L -#define ERROR_INVALID_PARAMETER 87L -#define ERROR_NET_WRITE_FAULT 88L -#define ERROR_NO_PROC_SLOTS 89L -#define ERROR_TOO_MANY_SEMAPHORES 100L -#define ERROR_EXCL_SEM_ALREADY_OWNED 101L -#define ERROR_SEM_IS_SET 102L -#define ERROR_TOO_MANY_SEM_REQUESTS 103L -#define ERROR_INVALID_AT_INTERRUPT_TIME 104L -#define ERROR_SEM_OWNER_DIED 105L -#define ERROR_SEM_USER_LIMIT 106L -#define ERROR_DISK_CHANGE 107L -#define ERROR_DRIVE_LOCKED 108L -#define ERROR_BROKEN_PIPE 109L -#define ERROR_OPEN_FAILED 110L -#define ERROR_BUFFER_OVERFLOW 111L -#define ERROR_DISK_FULL 112L -#define ERROR_NO_MORE_SEARCH_HANDLES 113L -#define ERROR_INVALID_TARGET_HANDLE 114L -#define ERROR_INVALID_CATEGORY 117L -#define ERROR_INVALID_VERIFY_SWITCH 118L -#define ERROR_BAD_DRIVER_LEVEL 119L -#define ERROR_CALL_NOT_IMPLEMENTED 120L -#define ERROR_SEM_TIMEOUT 121L -#define ERROR_INSUFFICIENT_BUFFER 122L -#define ERROR_INVALID_NAME 123L -#define ERROR_INVALID_LEVEL 124L -#define ERROR_NO_VOLUME_LABEL 125L -#define ERROR_MOD_NOT_FOUND 126L -#define ERROR_PROC_NOT_FOUND 127L -#define ERROR_WAIT_NO_CHILDREN 128L -#define ERROR_CHILD_NOT_COMPLETE 129L -#define ERROR_DIRECT_ACCESS_HANDLE 130L -#define ERROR_NEGATIVE_SEEK 131L -#define ERROR_SEEK_ON_DEVICE 132L -#define ERROR_IS_JOIN_TARGET 133L -#define ERROR_IS_JOINED 134L -#define ERROR_IS_SUBSTED 135L -#define ERROR_NOT_JOINED 136L -#define ERROR_NOT_SUBSTED 137L -#define ERROR_JOIN_TO_JOIN 138L -#define ERROR_SUBST_TO_SUBST 139L -#define ERROR_JOIN_TO_SUBST 140L -#define ERROR_SUBST_TO_JOIN 141L -#define ERROR_BUSY_DRIVE 142L -#define ERROR_SAME_DRIVE 143L -#define ERROR_DIR_NOT_ROOT 144L -#define ERROR_DIR_NOT_EMPTY 145L -#define ERROR_IS_SUBST_PATH 146L -#define ERROR_IS_JOIN_PATH 147L -#define ERROR_PATH_BUSY 148L -#define ERROR_IS_SUBST_TARGET 149L -#define ERROR_SYSTEM_TRACE 150L -#define ERROR_INVALID_EVENT_COUNT 151L -#define ERROR_TOO_MANY_MUXWAITERS 152L -#define ERROR_INVALID_LIST_FORMAT 153L -#define ERROR_LABEL_TOO_LONG 154L -#define ERROR_TOO_MANY_TCBS 155L -#define ERROR_SIGNAL_REFUSED 156L -#define ERROR_DISCARDED 157L -#define ERROR_NOT_LOCKED 158L -#define ERROR_BAD_THREADID_ADDR 159L -#define ERROR_BAD_ARGUMENTS 160L -#define ERROR_BAD_PATHNAME 161L -#define ERROR_SIGNAL_PENDING 162L -#define ERROR_MAX_THRDS_REACHED 164L -#define ERROR_LOCK_FAILED 167L -#define ERROR_BUSY 170L -#define ERROR_CANCEL_VIOLATION 173L -#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174L -#define ERROR_INVALID_SEGMENT_NUMBER 180L -#define ERROR_INVALID_ORDINAL 182L -#define ERROR_ALREADY_EXISTS 183L -#define ERROR_INVALID_FLAG_NUMBER 186L -#define ERROR_SEM_NOT_FOUND 187L -#define ERROR_INVALID_STARTING_CODESEG 188L -#define ERROR_INVALID_STACKSEG 189L -#define ERROR_INVALID_MODULETYPE 190L -#define ERROR_INVALID_EXE_SIGNATURE 191L -#define ERROR_EXE_MARKED_INVALID 192L -#define ERROR_BAD_EXE_FORMAT 193L -#define ERROR_ITERATED_DATA_EXCEEDS_64k 194L -#define ERROR_INVALID_MINALLOCSIZE 195L -#define ERROR_DYNLINK_FROM_INVALID_RING 196L -#define ERROR_IOPL_NOT_ENABLED 197L -#define ERROR_INVALID_SEGDPL 198L -#define ERROR_AUTODATASEG_EXCEEDS_64k 199L -#define ERROR_RING2SEG_MUST_BE_MOVABLE 200L -#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201L -#define ERROR_INFLOOP_IN_RELOC_CHAIN 202L -#define ERROR_ENVVAR_NOT_FOUND 203L -#define ERROR_NO_SIGNAL_SENT 205L -#define ERROR_FILENAME_EXCED_RANGE 206L -#define ERROR_RING2_STACK_IN_USE 207L -#define ERROR_META_EXPANSION_TOO_LONG 208L -#define ERROR_INVALID_SIGNAL_NUMBER 209L -#define ERROR_THREAD_1_INACTIVE 210L -#define ERROR_LOCKED 212L -#define ERROR_TOO_MANY_MODULES 214L -#define ERROR_NESTING_NOT_ALLOWED 215L -#define ERROR_EXE_MACHINE_TYPE_MISMATCH 216L -#define ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY 217L -#define ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY 218L -#define ERROR_BAD_PIPE 230L -#define ERROR_PIPE_BUSY 231L -#define ERROR_NO_DATA 232L -#define ERROR_PIPE_NOT_CONNECTED 233L -#define ERROR_MORE_DATA 234L -#define ERROR_VC_DISCONNECTED 240L -#define ERROR_INVALID_EA_NAME 254L -#define ERROR_EA_LIST_INCONSISTENT 255L -#define WAIT_TIMEOUT 258L -#define ERROR_NO_MORE_ITEMS 259L -#define ERROR_CANNOT_COPY 266L -#define ERROR_DIRECTORY 267L -#define ERROR_EAS_DIDNT_FIT 275L -#define ERROR_EA_FILE_CORRUPT 276L -#define ERROR_EA_TABLE_FULL 277L -#define ERROR_INVALID_EA_HANDLE 278L -#define ERROR_EAS_NOT_SUPPORTED 282L -#define ERROR_NOT_OWNER 288L -#define ERROR_TOO_MANY_POSTS 298L -#define ERROR_PARTIAL_COPY 299L -#define ERROR_OPLOCK_NOT_GRANTED 300L -#define ERROR_INVALID_OPLOCK_PROTOCOL 301L -#define ERROR_DISK_TOO_FRAGMENTED 302L -#define ERROR_DELETE_PENDING 303L -#define ERROR_MR_MID_NOT_FOUND 317L -#define ERROR_SCOPE_NOT_FOUND 318L -#define ERROR_INVALID_ADDRESS 487L -#define ERROR_ARITHMETIC_OVERFLOW 534L -#define ERROR_PIPE_CONNECTED 535L -#define ERROR_PIPE_LISTENING 536L -#define ERROR_EA_ACCESS_DENIED 994L -#define ERROR_OPERATION_ABORTED 995L -#define ERROR_IO_INCOMPLETE 996L -#define ERROR_IO_PENDING 997L -#define ERROR_NOACCESS 998L -#define ERROR_SWAPERROR 999L -#define ERROR_STACK_OVERFLOW 1001L -#define ERROR_INVALID_MESSAGE 1002L -#define ERROR_CAN_NOT_COMPLETE 1003L -#define ERROR_INVALID_FLAGS 1004L -#define ERROR_UNRECOGNIZED_VOLUME 1005L -#define ERROR_FILE_INVALID 1006L -#define ERROR_FULLSCREEN_MODE 1007L -#define ERROR_NO_TOKEN 1008L -#define ERROR_BADDB 1009L -#define ERROR_BADKEY 1010L -#define ERROR_CANTOPEN 1011L -#define ERROR_CANTREAD 1012L -#define ERROR_CANTWRITE 1013L -#define ERROR_REGISTRY_RECOVERED 1014L -#define ERROR_REGISTRY_CORRUPT 1015L -#define ERROR_REGISTRY_IO_FAILED 1016L -#define ERROR_NOT_REGISTRY_FILE 1017L -#define ERROR_KEY_DELETED 1018L -#define ERROR_NO_LOG_SPACE 1019L -#define ERROR_KEY_HAS_CHILDREN 1020L -#define ERROR_CHILD_MUST_BE_VOLATILE 1021L -#define ERROR_NOTIFY_ENUM_DIR 1022L -#define ERROR_DEPENDENT_SERVICES_RUNNING 1051L -#define ERROR_INVALID_SERVICE_CONTROL 1052L -#define ERROR_SERVICE_REQUEST_TIMEOUT 1053L -#define ERROR_SERVICE_NO_THREAD 1054L -#define ERROR_SERVICE_DATABASE_LOCKED 1055L -#define ERROR_SERVICE_ALREADY_RUNNING 1056L -#define ERROR_INVALID_SERVICE_ACCOUNT 1057L -#define ERROR_SERVICE_DISABLED 1058L -#define ERROR_CIRCULAR_DEPENDENCY 1059L -#define ERROR_SERVICE_DOES_NOT_EXIST 1060L -#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061L -#define ERROR_SERVICE_NOT_ACTIVE 1062L -#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063L -#define ERROR_EXCEPTION_IN_SERVICE 1064L -#define ERROR_DATABASE_DOES_NOT_EXIST 1065L -#define ERROR_SERVICE_SPECIFIC_ERROR 1066L -#define ERROR_PROCESS_ABORTED 1067L -#define ERROR_SERVICE_DEPENDENCY_FAIL 1068L -#define ERROR_SERVICE_LOGON_FAILED 1069L -#define ERROR_SERVICE_START_HANG 1070L -#define ERROR_INVALID_SERVICE_LOCK 1071L -#define ERROR_SERVICE_MARKED_FOR_DELETE 1072L -#define ERROR_SERVICE_EXISTS 1073L -#define ERROR_ALREADY_RUNNING_LKG 1074L -#define ERROR_SERVICE_DEPENDENCY_DELETED 1075L -#define ERROR_BOOT_ALREADY_ACCEPTED 1076L -#define ERROR_SERVICE_NEVER_STARTED 1077L -#define ERROR_DUPLICATE_SERVICE_NAME 1078L -#define ERROR_DIFFERENT_SERVICE_ACCOUNT 1079L -#define ERROR_CANNOT_DETECT_DRIVER_FAILURE 1080L -#define ERROR_CANNOT_DETECT_PROCESS_ABORT 1081L -#define ERROR_NO_RECOVERY_PROGRAM 1082L -#define ERROR_SERVICE_NOT_IN_EXE 1083L -#define ERROR_NOT_SAFEBOOT_SERVICE 1084L -#define ERROR_END_OF_MEDIA 1100L -#define ERROR_FILEMARK_DETECTED 1101L -#define ERROR_BEGINNING_OF_MEDIA 1102L -#define ERROR_SETMARK_DETECTED 1103L -#define ERROR_NO_DATA_DETECTED 1104L -#define ERROR_PARTITION_FAILURE 1105L -#define ERROR_INVALID_BLOCK_LENGTH 1106L -#define ERROR_DEVICE_NOT_PARTITIONED 1107L -#define ERROR_UNABLE_TO_LOCK_MEDIA 1108L -#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109L -#define ERROR_MEDIA_CHANGED 1110L -#define ERROR_BUS_RESET 1111L -#define ERROR_NO_MEDIA_IN_DRIVE 1112L -#define ERROR_NO_UNICODE_TRANSLATION 1113L -#define ERROR_DLL_INIT_FAILED 1114L -#define ERROR_SHUTDOWN_IN_PROGRESS 1115L -#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116L -#define ERROR_IO_DEVICE 1117L -#define ERROR_SERIAL_NO_DEVICE 1118L -#define ERROR_IRQ_BUSY 1119L -#define ERROR_MORE_WRITES 1120L -#define ERROR_COUNTER_TIMEOUT 1121L -#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122L -#define ERROR_FLOPPY_WRONG_CYLINDER 1123L -#define ERROR_FLOPPY_UNKNOWN_ERROR 1124L -#define ERROR_FLOPPY_BAD_REGISTERS 1125L -#define ERROR_DISK_RECALIBRATE_FAILED 1126L -#define ERROR_DISK_OPERATION_FAILED 1127L -#define ERROR_DISK_RESET_FAILED 1128L -#define ERROR_EOM_OVERFLOW 1129L -#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130L -#define ERROR_POSSIBLE_DEADLOCK 1131L -#define ERROR_MAPPED_ALIGNMENT 1132L -#define ERROR_SET_POWER_STATE_VETOED 1140L -#define ERROR_SET_POWER_STATE_FAILED 1141L -#define ERROR_TOO_MANY_LINKS 1142L -#define ERROR_OLD_WIN_VERSION 1150L -#define ERROR_APP_WRONG_OS 1151L -#define ERROR_SINGLE_INSTANCE_APP 1152L -#define ERROR_RMODE_APP 1153L -#define ERROR_INVALID_DLL 1154L -#define ERROR_NO_ASSOCIATION 1155L -#define ERROR_DDE_FAIL 1156L -#define ERROR_DLL_NOT_FOUND 1157L -#define ERROR_NO_MORE_USER_HANDLES 1158L -#define ERROR_MESSAGE_SYNC_ONLY 1159L -#define ERROR_SOURCE_ELEMENT_EMPTY 1160L -#define ERROR_DESTINATION_ELEMENT_FULL 1161L -#define ERROR_ILLEGAL_ELEMENT_ADDRESS 1162L -#define ERROR_MAGAZINE_NOT_PRESENT 1163L -#define ERROR_DEVICE_REINITIALIZATION_NEEDED 1164L -#define ERROR_DEVICE_REQUIRES_CLEANING 1165L -#define ERROR_DEVICE_DOOR_OPEN 1166L -#define ERROR_DEVICE_NOT_CONNECTED 1167L -#define ERROR_NOT_FOUND 1168L -#define ERROR_NO_MATCH 1169L -#define ERROR_SET_NOT_FOUND 1170L -#define ERROR_POINT_NOT_FOUND 1171L -#define ERROR_NO_TRACKING_SERVICE 1172L -#define ERROR_NO_VOLUME_ID 1173L -#define ERROR_UNABLE_TO_REMOVE_REPLACED 1175L -#define ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176L -#define ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 1177L -#define ERROR_JOURNAL_DELETE_IN_PROGRESS 1178L -#define ERROR_JOURNAL_NOT_ACTIVE 1179L -#define ERROR_POTENTIAL_FILE_FOUND 1180L -#define ERROR_JOURNAL_ENTRY_DELETED 1181L -#define ERROR_BAD_DEVICE 1200L -#define ERROR_CONNECTION_UNAVAIL 1201L -#define ERROR_DEVICE_ALREADY_REMEMBERED 1202L -#define ERROR_NO_NET_OR_BAD_PATH 1203L -#define ERROR_BAD_PROVIDER 1204L -#define ERROR_CANNOT_OPEN_PROFILE 1205L -#define ERROR_BAD_PROFILE 1206L -#define ERROR_NOT_CONTAINER 1207L -#define ERROR_EXTENDED_ERROR 1208L -#define ERROR_INVALID_GROUPNAME 1209L -#define ERROR_INVALID_COMPUTERNAME 1210L -#define ERROR_INVALID_EVENTNAME 1211L -#define ERROR_INVALID_DOMAINNAME 1212L -#define ERROR_INVALID_SERVICENAME 1213L -#define ERROR_INVALID_NETNAME 1214L -#define ERROR_INVALID_SHARENAME 1215L -#define ERROR_INVALID_PASSWORDNAME 1216L -#define ERROR_INVALID_MESSAGENAME 1217L -#define ERROR_INVALID_MESSAGEDEST 1218L -#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219L -#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220L -#define ERROR_DUP_DOMAINNAME 1221L -#define ERROR_NO_NETWORK 1222L -#define ERROR_CANCELLED 1223L -#define ERROR_USER_MAPPED_FILE 1224L -#define ERROR_CONNECTION_REFUSED 1225L -#define ERROR_GRACEFUL_DISCONNECT 1226L -#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227L -#define ERROR_ADDRESS_NOT_ASSOCIATED 1228L -#define ERROR_CONNECTION_INVALID 1229L -#define ERROR_CONNECTION_ACTIVE 1230L -#define ERROR_NETWORK_UNREACHABLE 1231L -#define ERROR_HOST_UNREACHABLE 1232L -#define ERROR_PROTOCOL_UNREACHABLE 1233L -#define ERROR_PORT_UNREACHABLE 1234L -#define ERROR_REQUEST_ABORTED 1235L -#define ERROR_CONNECTION_ABORTED 1236L -#define ERROR_RETRY 1237L -#define ERROR_CONNECTION_COUNT_LIMIT 1238L -#define ERROR_LOGIN_TIME_RESTRICTION 1239L -#define ERROR_LOGIN_WKSTA_RESTRICTION 1240L -#define ERROR_INCORRECT_ADDRESS 1241L -#define ERROR_ALREADY_REGISTERED 1242L -#define ERROR_SERVICE_NOT_FOUND 1243L -#define ERROR_NOT_AUTHENTICATED 1244L -#define ERROR_NOT_LOGGED_ON 1245L -#define ERROR_CONTINUE 1246L -#define ERROR_ALREADY_INITIALIZED 1247L -#define ERROR_NO_MORE_DEVICES 1248L -#define ERROR_NO_SUCH_SITE 1249L -#define ERROR_DOMAIN_CONTROLLER_EXISTS 1250L -#define ERROR_ONLY_IF_CONNECTED 1251L -#define ERROR_OVERRIDE_NOCHANGES 1252L -#define ERROR_BAD_USER_PROFILE 1253L -#define ERROR_NOT_SUPPORTED_ON_SBS 1254L -#define ERROR_SERVER_SHUTDOWN_IN_PROGRESS 1255L -#define ERROR_HOST_DOWN 1256L -#define ERROR_NON_ACCOUNT_SID 1257L -#define ERROR_NON_DOMAIN_SID 1258L -#define ERROR_APPHELP_BLOCK 1259L -#define ERROR_ACCESS_DISABLED_BY_POLICY 1260L -#define ERROR_REG_NAT_CONSUMPTION 1261L -#define ERROR_CSCSHARE_OFFLINE 1262L -#define ERROR_PKINIT_FAILURE 1263L -#define ERROR_SMARTCARD_SUBSYSTEM_FAILURE 1264L -#define ERROR_DOWNGRADE_DETECTED 1265L -#define ERROR_MACHINE_LOCKED 1271L -#define ERROR_CALLBACK_SUPPLIED_INVALID_DATA 1273L -#define ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED 1274L -#define ERROR_DRIVER_BLOCKED 1275L -#define ERROR_INVALID_IMPORT_OF_NON_DLL 1276L -#define ERROR_ACCESS_DISABLED_WEBBLADE 1277L -#define ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER 1278L -#define ERROR_RECOVERY_FAILURE 1279L -#define ERROR_ALREADY_FIBER 1280L -#define ERROR_ALREADY_THREAD 1281L -#define ERROR_STACK_BUFFER_OVERRUN 1282L -#define ERROR_PARAMETER_QUOTA_EXCEEDED 1283L -#define ERROR_DEBUGGER_INACTIVE 1284L -#define ERROR_DELAY_LOAD_FAILED 1285L -#define ERROR_VDM_DISALLOWED 1286L -#define ERROR_UNIDENTIFIED_ERROR 1287L -#define ERROR_NOT_ALL_ASSIGNED 1300L -#define ERROR_SOME_NOT_MAPPED 1301L -#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302L -#define ERROR_LOCAL_USER_SESSION_KEY 1303L -#define ERROR_NULL_LM_PASSWORD 1304L -#define ERROR_UNKNOWN_REVISION 1305L -#define ERROR_REVISION_MISMATCH 1306L -#define ERROR_INVALID_OWNER 1307L -#define ERROR_INVALID_PRIMARY_GROUP 1308L -#define ERROR_NO_IMPERSONATION_TOKEN 1309L -#define ERROR_CANT_DISABLE_MANDATORY 1310L -#define ERROR_NO_LOGON_SERVERS 1311L -#define ERROR_NO_SUCH_LOGON_SESSION 1312L -#define ERROR_NO_SUCH_PRIVILEGE 1313L -#define ERROR_PRIVILEGE_NOT_HELD 1314L -#define ERROR_INVALID_ACCOUNT_NAME 1315L -#define ERROR_USER_EXISTS 1316L -#define ERROR_NO_SUCH_USER 1317L -#define ERROR_GROUP_EXISTS 1318L -#define ERROR_NO_SUCH_GROUP 1319L -#define ERROR_MEMBER_IN_GROUP 1320L -#define ERROR_MEMBER_NOT_IN_GROUP 1321L -#define ERROR_LAST_ADMIN 1322L -#define ERROR_WRONG_PASSWORD 1323L -#define ERROR_ILL_FORMED_PASSWORD 1324L -#define ERROR_PASSWORD_RESTRICTION 1325L -#define ERROR_LOGON_FAILURE 1326L -#define ERROR_ACCOUNT_RESTRICTION 1327L -#define ERROR_INVALID_LOGON_HOURS 1328L -#define ERROR_INVALID_WORKSTATION 1329L -#define ERROR_PASSWORD_EXPIRED 1330L -#define ERROR_ACCOUNT_DISABLED 1331L -#define ERROR_NONE_MAPPED 1332L -#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333L -#define ERROR_LUIDS_EXHAUSTED 1334L -#define ERROR_INVALID_SUB_AUTHORITY 1335L -#define ERROR_INVALID_ACL 1336L -#define ERROR_INVALID_SID 1337L -#define ERROR_INVALID_SECURITY_DESCR 1338L -#define ERROR_BAD_INHERITANCE_ACL 1340L -#define ERROR_SERVER_DISABLED 1341L -#define ERROR_SERVER_NOT_DISABLED 1342L -#define ERROR_INVALID_ID_AUTHORITY 1343L -#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344L -#define ERROR_INVALID_GROUP_ATTRIBUTES 1345L -#define ERROR_BAD_IMPERSONATION_LEVEL 1346L -#define ERROR_CANT_OPEN_ANONYMOUS 1347L -#define ERROR_BAD_VALIDATION_CLASS 1348L -#define ERROR_BAD_TOKEN_TYPE 1349L -#define ERROR_NO_SECURITY_ON_OBJECT 1350L -#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351L -#define ERROR_INVALID_SERVER_STATE 1352L -#define ERROR_INVALID_DOMAIN_STATE 1353L -#define ERROR_INVALID_DOMAIN_ROLE 1354L -#define ERROR_NO_SUCH_DOMAIN 1355L -#define ERROR_DOMAIN_EXISTS 1356L -#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357L -#define ERROR_INTERNAL_DB_CORRUPTION 1358L -#define ERROR_INTERNAL_ERROR 1359L -#define ERROR_GENERIC_NOT_MAPPED 1360L -#define ERROR_BAD_DESCRIPTOR_FORMAT 1361L -#define ERROR_NOT_LOGON_PROCESS 1362L -#define ERROR_LOGON_SESSION_EXISTS 1363L -#define ERROR_NO_SUCH_PACKAGE 1364L -#define ERROR_BAD_LOGON_SESSION_STATE 1365L -#define ERROR_LOGON_SESSION_COLLISION 1366L -#define ERROR_INVALID_LOGON_TYPE 1367L -#define ERROR_CANNOT_IMPERSONATE 1368L -#define ERROR_RXACT_INVALID_STATE 1369L -#define ERROR_RXACT_COMMIT_FAILURE 1370L -#define ERROR_SPECIAL_ACCOUNT 1371L -#define ERROR_SPECIAL_GROUP 1372L -#define ERROR_SPECIAL_USER 1373L -#define ERROR_MEMBERS_PRIMARY_GROUP 1374L -#define ERROR_TOKEN_ALREADY_IN_USE 1375L -#define ERROR_NO_SUCH_ALIAS 1376L -#define ERROR_MEMBER_NOT_IN_ALIAS 1377L -#define ERROR_MEMBER_IN_ALIAS 1378L -#define ERROR_ALIAS_EXISTS 1379L -#define ERROR_LOGON_NOT_GRANTED 1380L -#define ERROR_TOO_MANY_SECRETS 1381L -#define ERROR_SECRET_TOO_LONG 1382L -#define ERROR_INTERNAL_DB_ERROR 1383L -#define ERROR_TOO_MANY_CONTEXT_IDS 1384L -#define ERROR_LOGON_TYPE_NOT_GRANTED 1385L -#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386L -#define ERROR_NO_SUCH_MEMBER 1387L -#define ERROR_INVALID_MEMBER 1388L -#define ERROR_TOO_MANY_SIDS 1389L -#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390L -#define ERROR_NO_INHERITANCE 1391L -#define ERROR_FILE_CORRUPT 1392L -#define ERROR_DISK_CORRUPT 1393L -#define ERROR_NO_USER_SESSION_KEY 1394L -#define ERROR_LICENSE_QUOTA_EXCEEDED 1395L -#define ERROR_WRONG_TARGET_NAME 1396L -#define ERROR_MUTUAL_AUTH_FAILED 1397L -#define ERROR_TIME_SKEW 1398L -#define ERROR_CURRENT_DOMAIN_NOT_ALLOWED 1399L -#define ERROR_INVALID_WINDOW_HANDLE 1400L -#define ERROR_INVALID_MENU_HANDLE 1401L -#define ERROR_INVALID_CURSOR_HANDLE 1402L -#define ERROR_INVALID_ACCEL_HANDLE 1403L -#define ERROR_INVALID_HOOK_HANDLE 1404L -#define ERROR_INVALID_DWP_HANDLE 1405L -#define ERROR_TLW_WITH_WSCHILD 1406L -#define ERROR_CANNOT_FIND_WND_CLASS 1407L -#define ERROR_WINDOW_OF_OTHER_THREAD 1408L -#define ERROR_HOTKEY_ALREADY_REGISTERED 1409L -#define ERROR_CLASS_ALREADY_EXISTS 1410L -#define ERROR_CLASS_DOES_NOT_EXIST 1411L -#define ERROR_CLASS_HAS_WINDOWS 1412L -#define ERROR_INVALID_INDEX 1413L -#define ERROR_INVALID_ICON_HANDLE 1414L -#define ERROR_PRIVATE_DIALOG_INDEX 1415L -#define ERROR_LISTBOX_ID_NOT_FOUND 1416L -#define ERROR_NO_WILDCARD_CHARACTERS 1417L -#define ERROR_CLIPBOARD_NOT_OPEN 1418L -#define ERROR_HOTKEY_NOT_REGISTERED 1419L -#define ERROR_WINDOW_NOT_DIALOG 1420L -#define ERROR_CONTROL_ID_NOT_FOUND 1421L -#define ERROR_INVALID_COMBOBOX_MESSAGE 1422L -#define ERROR_WINDOW_NOT_COMBOBOX 1423L -#define ERROR_INVALID_EDIT_HEIGHT 1424L -#define ERROR_DC_NOT_FOUND 1425L -#define ERROR_INVALID_HOOK_FILTER 1426L -#define ERROR_INVALID_FILTER_PROC 1427L -#define ERROR_HOOK_NEEDS_HMOD 1428L -#define ERROR_GLOBAL_ONLY_HOOK 1429L -#define ERROR_JOURNAL_HOOK_SET 1430L -#define ERROR_HOOK_NOT_INSTALLED 1431L -#define ERROR_INVALID_LB_MESSAGE 1432L -#define ERROR_SETCOUNT_ON_BAD_LB 1433L -#define ERROR_LB_WITHOUT_TABSTOPS 1434L -#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435L -#define ERROR_CHILD_WINDOW_MENU 1436L -#define ERROR_NO_SYSTEM_MENU 1437L -#define ERROR_INVALID_MSGBOX_STYLE 1438L -#define ERROR_INVALID_SPI_VALUE 1439L -#define ERROR_SCREEN_ALREADY_LOCKED 1440L -#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441L -#define ERROR_NOT_CHILD_WINDOW 1442L -#define ERROR_INVALID_GW_COMMAND 1443L -#define ERROR_INVALID_THREAD_ID 1444L -#define ERROR_NON_MDICHILD_WINDOW 1445L -#define ERROR_POPUP_ALREADY_ACTIVE 1446L -#define ERROR_NO_SCROLLBARS 1447L -#define ERROR_INVALID_SCROLLBAR_RANGE 1448L -#define ERROR_INVALID_SHOWWIN_COMMAND 1449L -#define ERROR_NO_SYSTEM_RESOURCES 1450L -#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451L -#define ERROR_PAGED_SYSTEM_RESOURCES 1452L -#define ERROR_WORKING_SET_QUOTA 1453L -#define ERROR_PAGEFILE_QUOTA 1454L -#define ERROR_COMMITMENT_LIMIT 1455L -#define ERROR_MENU_ITEM_NOT_FOUND 1456L -#define ERROR_INVALID_KEYBOARD_HANDLE 1457L -#define ERROR_HOOK_TYPE_NOT_ALLOWED 1458L -#define ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION 1459L -#define ERROR_TIMEOUT 1460L -#define ERROR_INVALID_MONITOR_HANDLE 1461L -#define ERROR_INCORRECT_SIZE 1462L -#define ERROR_EVENTLOG_FILE_CORRUPT 1500L -#define ERROR_EVENTLOG_CANT_START 1501L -#define ERROR_LOG_FILE_FULL 1502L -#define ERROR_EVENTLOG_FILE_CHANGED 1503L -#define ERROR_INSTALL_SERVICE_FAILURE 1601L -#define ERROR_INSTALL_USEREXIT 1602L -#define ERROR_INSTALL_FAILURE 1603L -#define ERROR_INSTALL_SUSPEND 1604L -#define ERROR_UNKNOWN_PRODUCT 1605L -#define ERROR_UNKNOWN_FEATURE 1606L -#define ERROR_UNKNOWN_COMPONENT 1607L -#define ERROR_UNKNOWN_PROPERTY 1608L -#define ERROR_INVALID_HANDLE_STATE 1609L -#define ERROR_BAD_CONFIGURATION 1610L -#define ERROR_INDEX_ABSENT 1611L -#define ERROR_INSTALL_SOURCE_ABSENT 1612L -#define ERROR_INSTALL_PACKAGE_VERSION 1613L -#define ERROR_PRODUCT_UNINSTALLED 1614L -#define ERROR_BAD_QUERY_SYNTAX 1615L -#define ERROR_INVALID_FIELD 1616L -#define ERROR_DEVICE_REMOVED 1617L -#define ERROR_INSTALL_ALREADY_RUNNING 1618L -#define ERROR_INSTALL_PACKAGE_OPEN_FAILED 1619L -#define ERROR_INSTALL_PACKAGE_INVALID 1620L -#define ERROR_INSTALL_UI_FAILURE 1621L -#define ERROR_INSTALL_LOG_FAILURE 1622L -#define ERROR_INSTALL_LANGUAGE_UNSUPPORTED 1623L -#define ERROR_INSTALL_TRANSFORM_FAILURE 1624L -#define ERROR_INSTALL_PACKAGE_REJECTED 1625L -#define ERROR_FUNCTION_NOT_CALLED 1626L -#define ERROR_FUNCTION_FAILED 1627L -#define ERROR_INVALID_TABLE 1628L -#define ERROR_DATATYPE_MISMATCH 1629L -#define ERROR_UNSUPPORTED_TYPE 1630L -#define ERROR_CREATE_FAILED 1631L -#define ERROR_INSTALL_TEMP_UNWRITABLE 1632L -#define ERROR_INSTALL_PLATFORM_UNSUPPORTED 1633L -#define ERROR_INSTALL_NOTUSED 1634L -#define ERROR_PATCH_PACKAGE_OPEN_FAILED 1635L -#define ERROR_PATCH_PACKAGE_INVALID 1636L -#define ERROR_PATCH_PACKAGE_UNSUPPORTED 1637L -#define ERROR_PRODUCT_VERSION 1638L -#define ERROR_INVALID_COMMAND_LINE 1639L -#define ERROR_INSTALL_REMOTE_DISALLOWED 1640L -#define ERROR_SUCCESS_REBOOT_INITIATED 1641L -#define ERROR_PATCH_TARGET_NOT_FOUND 1642L -#define ERROR_PATCH_PACKAGE_REJECTED 1643L -#define ERROR_INSTALL_TRANSFORM_REJECTED 1644L -#define ERROR_INSTALL_REMOTE_PROHIBITED 1645L -#define RPC_S_INVALID_STRING_BINDING 1700L -#define RPC_S_WRONG_KIND_OF_BINDING 1701L -#define RPC_S_INVALID_BINDING 1702L -#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703L -#define RPC_S_INVALID_RPC_PROTSEQ 1704L -#define RPC_S_INVALID_STRING_UUID 1705L -#define RPC_S_INVALID_ENDPOINT_FORMAT 1706L -#define RPC_S_INVALID_NET_ADDR 1707L -#define RPC_S_NO_ENDPOINT_FOUND 1708L -#define RPC_S_INVALID_TIMEOUT 1709L -#define RPC_S_OBJECT_NOT_FOUND 1710L -#define RPC_S_ALREADY_REGISTERED 1711L -#define RPC_S_TYPE_ALREADY_REGISTERED 1712L -#define RPC_S_ALREADY_LISTENING 1713L -#define RPC_S_NO_PROTSEQS_REGISTERED 1714L -#define RPC_S_NOT_LISTENING 1715L -#define RPC_S_UNKNOWN_MGR_TYPE 1716L -#define RPC_S_UNKNOWN_IF 1717L -#define RPC_S_NO_BINDINGS 1718L -#define RPC_S_NO_PROTSEQS 1719L -#define RPC_S_CANT_CREATE_ENDPOINT 1720L -#define RPC_S_OUT_OF_RESOURCES 1721L -#define RPC_S_SERVER_UNAVAILABLE 1722L -#define RPC_S_SERVER_TOO_BUSY 1723L -#define RPC_S_INVALID_NETWORK_OPTIONS 1724L -#define RPC_S_NO_CALL_ACTIVE 1725L -#define RPC_S_CALL_FAILED 1726L -#define RPC_S_CALL_FAILED_DNE 1727L -#define RPC_S_PROTOCOL_ERROR 1728L -#define RPC_S_UNSUPPORTED_TRANS_SYN 1730L -#define RPC_S_UNSUPPORTED_TYPE 1732L -#define RPC_S_INVALID_TAG 1733L -#define RPC_S_INVALID_BOUND 1734L -#define RPC_S_NO_ENTRY_NAME 1735L -#define RPC_S_INVALID_NAME_SYNTAX 1736L -#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737L -#define RPC_S_UUID_NO_ADDRESS 1739L -#define RPC_S_DUPLICATE_ENDPOINT 1740L -#define RPC_S_UNKNOWN_AUTHN_TYPE 1741L -#define RPC_S_MAX_CALLS_TOO_SMALL 1742L -#define RPC_S_STRING_TOO_LONG 1743L -#define RPC_S_PROTSEQ_NOT_FOUND 1744L -#define RPC_S_PROCNUM_OUT_OF_RANGE 1745L -#define RPC_S_BINDING_HAS_NO_AUTH 1746L -#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747L -#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748L -#define RPC_S_INVALID_AUTH_IDENTITY 1749L -#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750L -#define EPT_S_INVALID_ENTRY 1751L -#define EPT_S_CANT_PERFORM_OP 1752L -#define EPT_S_NOT_REGISTERED 1753L -#define RPC_S_NOTHING_TO_EXPORT 1754L -#define RPC_S_INCOMPLETE_NAME 1755L -#define RPC_S_INVALID_VERS_OPTION 1756L -#define RPC_S_NO_MORE_MEMBERS 1757L -#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758L -#define RPC_S_INTERFACE_NOT_FOUND 1759L -#define RPC_S_ENTRY_ALREADY_EXISTS 1760L -#define RPC_S_ENTRY_NOT_FOUND 1761L -#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762L -#define RPC_S_INVALID_NAF_ID 1763L -#define RPC_S_CANNOT_SUPPORT 1764L -#define RPC_S_NO_CONTEXT_AVAILABLE 1765L -#define RPC_S_INTERNAL_ERROR 1766L -#define RPC_S_ZERO_DIVIDE 1767L -#define RPC_S_ADDRESS_ERROR 1768L -#define RPC_S_FP_DIV_ZERO 1769L -#define RPC_S_FP_UNDERFLOW 1770L -#define RPC_S_FP_OVERFLOW 1771L -#define RPC_X_NO_MORE_ENTRIES 1772L -#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773L -#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774L -#define RPC_X_SS_IN_NULL_CONTEXT 1775L -#define RPC_X_SS_CONTEXT_DAMAGED 1777L -#define RPC_X_SS_HANDLES_MISMATCH 1778L -#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779L -#define RPC_X_NULL_REF_POINTER 1780L -#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781L -#define RPC_X_BYTE_COUNT_TOO_SMALL 1782L -#define RPC_X_BAD_STUB_DATA 1783L -#define ERROR_INVALID_USER_BUFFER 1784L -#define ERROR_UNRECOGNIZED_MEDIA 1785L -#define ERROR_NO_TRUST_LSA_SECRET 1786L -#define ERROR_NO_TRUST_SAM_ACCOUNT 1787L -#define ERROR_TRUSTED_DOMAIN_FAILURE 1788L -#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789L -#define ERROR_TRUST_FAILURE 1790L -#define RPC_S_CALL_IN_PROGRESS 1791L -#define ERROR_NETLOGON_NOT_STARTED 1792L -#define ERROR_ACCOUNT_EXPIRED 1793L -#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794L -#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795L -#define ERROR_UNKNOWN_PORT 1796L -#define ERROR_UNKNOWN_PRINTER_DRIVER 1797L -#define ERROR_UNKNOWN_PRINTPROCESSOR 1798L -#define ERROR_INVALID_SEPARATOR_FILE 1799L -#define ERROR_INVALID_PRIORITY 1800L -#define ERROR_INVALID_PRINTER_NAME 1801L -#define ERROR_PRINTER_ALREADY_EXISTS 1802L -#define ERROR_INVALID_PRINTER_COMMAND 1803L -#define ERROR_INVALID_DATATYPE 1804L -#define ERROR_INVALID_ENVIRONMENT 1805L -#define RPC_S_NO_MORE_BINDINGS 1806L -#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807L -#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808L -#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809L -#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810L -#define ERROR_SERVER_HAS_OPEN_HANDLES 1811L -#define ERROR_RESOURCE_DATA_NOT_FOUND 1812L -#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813L -#define ERROR_RESOURCE_NAME_NOT_FOUND 1814L -#define ERROR_RESOURCE_LANG_NOT_FOUND 1815L -#define ERROR_NOT_ENOUGH_QUOTA 1816L -#define RPC_S_NO_INTERFACES 1817L -#define RPC_S_CALL_CANCELLED 1818L -#define RPC_S_BINDING_INCOMPLETE 1819L -#define RPC_S_COMM_FAILURE 1820L -#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821L -#define RPC_S_NO_PRINC_NAME 1822L -#define RPC_S_NOT_RPC_ERROR 1823L -#define RPC_S_UUID_LOCAL_ONLY 1824L -#define RPC_S_SEC_PKG_ERROR 1825L -#define RPC_S_NOT_CANCELLED 1826L -#define RPC_X_INVALID_ES_ACTION 1827L -#define RPC_X_WRONG_ES_VERSION 1828L -#define RPC_X_WRONG_STUB_VERSION 1829L -#define RPC_X_INVALID_PIPE_OBJECT 1830L -#define RPC_X_WRONG_PIPE_ORDER 1831L -#define RPC_X_WRONG_PIPE_VERSION 1832L -#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898L -#define EPT_S_CANT_CREATE 1899L -#define RPC_S_INVALID_OBJECT 1900L -#define ERROR_INVALID_TIME 1901L -#define ERROR_INVALID_FORM_NAME 1902L -#define ERROR_INVALID_FORM_SIZE 1903L -#define ERROR_ALREADY_WAITING 1904L -#define ERROR_PRINTER_DELETED 1905L -#define ERROR_INVALID_PRINTER_STATE 1906L -#define ERROR_PASSWORD_MUST_CHANGE 1907L -#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908L -#define ERROR_ACCOUNT_LOCKED_OUT 1909L -#define OR_INVALID_OXID 1910L -#define OR_INVALID_OID 1911L -#define OR_INVALID_SET 1912L -#define RPC_S_SEND_INCOMPLETE 1913L -#define RPC_S_INVALID_ASYNC_HANDLE 1914L -#define RPC_S_INVALID_ASYNC_CALL 1915L -#define RPC_X_PIPE_CLOSED 1916L -#define RPC_X_PIPE_DISCIPLINE_ERROR 1917L -#define RPC_X_PIPE_EMPTY 1918L -#define ERROR_NO_SITENAME 1919L -#define ERROR_CANT_ACCESS_FILE 1920L -#define ERROR_CANT_RESOLVE_FILENAME 1921L -#define RPC_S_ENTRY_TYPE_MISMATCH 1922L -#define RPC_S_NOT_ALL_OBJS_EXPORTED 1923L -#define RPC_S_INTERFACE_NOT_EXPORTED 1924L -#define RPC_S_PROFILE_NOT_ADDED 1925L -#define RPC_S_PRF_ELT_NOT_ADDED 1926L -#define RPC_S_PRF_ELT_NOT_REMOVED 1927L -#define RPC_S_GRP_ELT_NOT_ADDED 1928L -#define RPC_S_GRP_ELT_NOT_REMOVED 1929L -#define ERROR_KM_DRIVER_BLOCKED 1930L -#define ERROR_CONTEXT_EXPIRED 1931L -#define ERROR_PER_USER_TRUST_QUOTA_EXCEEDED 1932L -#define ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED 1933L -#define ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED 1934L -#define ERROR_AUTHENTICATION_FIREWALL_FAILED 1935L -#define ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED 1936L -#define ERROR_INVALID_PIXEL_FORMAT 2000L -#define ERROR_BAD_DRIVER 2001L -#define ERROR_INVALID_WINDOW_STYLE 2002L -#define ERROR_METAFILE_NOT_SUPPORTED 2003L -#define ERROR_TRANSFORM_NOT_SUPPORTED 2004L -#define ERROR_CLIPPING_NOT_SUPPORTED 2005L -#define ERROR_INVALID_CMM 2010L -#define ERROR_INVALID_PROFILE 2011L -#define ERROR_TAG_NOT_FOUND 2012L -#define ERROR_TAG_NOT_PRESENT 2013L -#define ERROR_DUPLICATE_TAG 2014L -#define ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE 2015L -#define ERROR_PROFILE_NOT_FOUND 2016L -#define ERROR_INVALID_COLORSPACE 2017L -#define ERROR_ICM_NOT_ENABLED 2018L -#define ERROR_DELETING_ICM_XFORM 2019L -#define ERROR_INVALID_TRANSFORM 2020L -#define ERROR_COLORSPACE_MISMATCH 2021L -#define ERROR_INVALID_COLORINDEX 2022L -#define ERROR_CONNECTED_OTHER_PASSWORD 2108L -#define ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT 2109L -#define ERROR_BAD_USERNAME 2202L -#define ERROR_NOT_CONNECTED 2250L -#define ERROR_OPEN_FILES 2401L -#define ERROR_ACTIVE_CONNECTIONS 2402L -#define ERROR_DEVICE_IN_USE 2404L -#define ERROR_UNKNOWN_PRINT_MONITOR 3000L -#define ERROR_PRINTER_DRIVER_IN_USE 3001L -#define ERROR_SPOOL_FILE_NOT_FOUND 3002L -#define ERROR_SPL_NO_STARTDOC 3003L -#define ERROR_SPL_NO_ADDJOB 3004L -#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005L -#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006L -#define ERROR_INVALID_PRINT_MONITOR 3007L -#define ERROR_PRINT_MONITOR_IN_USE 3008L -#define ERROR_PRINTER_HAS_JOBS_QUEUED 3009L -#define ERROR_SUCCESS_REBOOT_REQUIRED 3010L -#define ERROR_SUCCESS_RESTART_REQUIRED 3011L -#define ERROR_PRINTER_NOT_FOUND 3012L -#define ERROR_PRINTER_DRIVER_WARNED 3013L -#define ERROR_PRINTER_DRIVER_BLOCKED 3014L -#define ERROR_WINS_INTERNAL 4000L -#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001L -#define ERROR_STATIC_INIT 4002L -#define ERROR_INC_BACKUP 4003L -#define ERROR_FULL_BACKUP 4004L -#define ERROR_REC_NON_EXISTENT 4005L -#define ERROR_RPL_NOT_ALLOWED 4006L -#define ERROR_DHCP_ADDRESS_CONFLICT 4100L -#define ERROR_WMI_GUID_NOT_FOUND 4200L -#define ERROR_WMI_INSTANCE_NOT_FOUND 4201L -#define ERROR_WMI_ITEMID_NOT_FOUND 4202L -#define ERROR_WMI_TRY_AGAIN 4203L -#define ERROR_WMI_DP_NOT_FOUND 4204L -#define ERROR_WMI_UNRESOLVED_INSTANCE_REF 4205L -#define ERROR_WMI_ALREADY_ENABLED 4206L -#define ERROR_WMI_GUID_DISCONNECTED 4207L -#define ERROR_WMI_SERVER_UNAVAILABLE 4208L -#define ERROR_WMI_DP_FAILED 4209L -#define ERROR_WMI_INVALID_MOF 4210L -#define ERROR_WMI_INVALID_REGINFO 4211L -#define ERROR_WMI_ALREADY_DISABLED 4212L -#define ERROR_WMI_READ_ONLY 4213L -#define ERROR_WMI_SET_FAILURE 4214L -#define ERROR_INVALID_MEDIA 4300L -#define ERROR_INVALID_LIBRARY 4301L -#define ERROR_INVALID_MEDIA_POOL 4302L -#define ERROR_DRIVE_MEDIA_MISMATCH 4303L -#define ERROR_MEDIA_OFFLINE 4304L -#define ERROR_LIBRARY_OFFLINE 4305L -#define ERROR_EMPTY 4306L -#define ERROR_NOT_EMPTY 4307L -#define ERROR_MEDIA_UNAVAILABLE 4308L -#define ERROR_RESOURCE_DISABLED 4309L -#define ERROR_INVALID_CLEANER 4310L -#define ERROR_UNABLE_TO_CLEAN 4311L -#define ERROR_OBJECT_NOT_FOUND 4312L -#define ERROR_DATABASE_FAILURE 4313L -#define ERROR_DATABASE_FULL 4314L -#define ERROR_MEDIA_INCOMPATIBLE 4315L -#define ERROR_RESOURCE_NOT_PRESENT 4316L -#define ERROR_INVALID_OPERATION 4317L -#define ERROR_MEDIA_NOT_AVAILABLE 4318L -#define ERROR_DEVICE_NOT_AVAILABLE 4319L -#define ERROR_REQUEST_REFUSED 4320L -#define ERROR_INVALID_DRIVE_OBJECT 4321L -#define ERROR_LIBRARY_FULL 4322L -#define ERROR_MEDIUM_NOT_ACCESSIBLE 4323L -#define ERROR_UNABLE_TO_LOAD_MEDIUM 4324L -#define ERROR_UNABLE_TO_INVENTORY_DRIVE 4325L -#define ERROR_UNABLE_TO_INVENTORY_SLOT 4326L -#define ERROR_UNABLE_TO_INVENTORY_TRANSPORT 4327L -#define ERROR_TRANSPORT_FULL 4328L -#define ERROR_CONTROLLING_IEPORT 4329L -#define ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA 4330L -#define ERROR_CLEANER_SLOT_SET 4331L -#define ERROR_CLEANER_SLOT_NOT_SET 4332L -#define ERROR_CLEANER_CARTRIDGE_SPENT 4333L -#define ERROR_UNEXPECTED_OMID 4334L -#define ERROR_CANT_DELETE_LAST_ITEM 4335L -#define ERROR_MESSAGE_EXCEEDS_MAX_SIZE 4336L -#define ERROR_VOLUME_CONTAINS_SYS_FILES 4337L -#define ERROR_INDIGENOUS_TYPE 4338L -#define ERROR_NO_SUPPORTING_DRIVES 4339L -#define ERROR_CLEANER_CARTRIDGE_INSTALLED 4340L -#define ERROR_IEPORT_FULL 4341L -#define ERROR_FILE_OFFLINE 4350L -#define ERROR_REMOTE_STORAGE_NOT_ACTIVE 4351L -#define ERROR_REMOTE_STORAGE_MEDIA_ERROR 4352L -#define ERROR_NOT_A_REPARSE_POINT 4390L -#define ERROR_REPARSE_ATTRIBUTE_CONFLICT 4391L -#define ERROR_INVALID_REPARSE_DATA 4392L -#define ERROR_REPARSE_TAG_INVALID 4393L -#define ERROR_REPARSE_TAG_MISMATCH 4394L -#define ERROR_VOLUME_NOT_SIS_ENABLED 4500L -#define ERROR_DEPENDENT_RESOURCE_EXISTS 5001L -#define ERROR_DEPENDENCY_NOT_FOUND 5002L -#define ERROR_DEPENDENCY_ALREADY_EXISTS 5003L -#define ERROR_RESOURCE_NOT_ONLINE 5004L -#define ERROR_HOST_NODE_NOT_AVAILABLE 5005L -#define ERROR_RESOURCE_NOT_AVAILABLE 5006L -#define ERROR_RESOURCE_NOT_FOUND 5007L -#define ERROR_SHUTDOWN_CLUSTER 5008L -#define ERROR_CANT_EVICT_ACTIVE_NODE 5009L -#define ERROR_OBJECT_ALREADY_EXISTS 5010L -#define ERROR_OBJECT_IN_LIST 5011L -#define ERROR_GROUP_NOT_AVAILABLE 5012L -#define ERROR_GROUP_NOT_FOUND 5013L -#define ERROR_GROUP_NOT_ONLINE 5014L -#define ERROR_HOST_NODE_NOT_RESOURCE_OWNER 5015L -#define ERROR_HOST_NODE_NOT_GROUP_OWNER 5016L -#define ERROR_RESMON_CREATE_FAILED 5017L -#define ERROR_RESMON_ONLINE_FAILED 5018L -#define ERROR_RESOURCE_ONLINE 5019L -#define ERROR_QUORUM_RESOURCE 5020L -#define ERROR_NOT_QUORUM_CAPABLE 5021L -#define ERROR_CLUSTER_SHUTTING_DOWN 5022L -#define ERROR_INVALID_STATE 5023L -#define ERROR_RESOURCE_PROPERTIES_STORED 5024L -#define ERROR_NOT_QUORUM_CLASS 5025L -#define ERROR_CORE_RESOURCE 5026L -#define ERROR_QUORUM_RESOURCE_ONLINE_FAILED 5027L -#define ERROR_QUORUMLOG_OPEN_FAILED 5028L -#define ERROR_CLUSTERLOG_CORRUPT 5029L -#define ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE 5030L -#define ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE 5031L -#define ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND 5032L -#define ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE 5033L -#define ERROR_QUORUM_OWNER_ALIVE 5034L -#define ERROR_NETWORK_NOT_AVAILABLE 5035L -#define ERROR_NODE_NOT_AVAILABLE 5036L -#define ERROR_ALL_NODES_NOT_AVAILABLE 5037L -#define ERROR_RESOURCE_FAILED 5038L -#define ERROR_CLUSTER_INVALID_NODE 5039L -#define ERROR_CLUSTER_NODE_EXISTS 5040L -#define ERROR_CLUSTER_JOIN_IN_PROGRESS 5041L -#define ERROR_CLUSTER_NODE_NOT_FOUND 5042L -#define ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND 5043L -#define ERROR_CLUSTER_NETWORK_EXISTS 5044L -#define ERROR_CLUSTER_NETWORK_NOT_FOUND 5045L -#define ERROR_CLUSTER_NETINTERFACE_EXISTS 5046L -#define ERROR_CLUSTER_NETINTERFACE_NOT_FOUND 5047L -#define ERROR_CLUSTER_INVALID_REQUEST 5048L -#define ERROR_CLUSTER_INVALID_NETWORK_PROVIDER 5049L -#define ERROR_CLUSTER_NODE_DOWN 5050L -#define ERROR_CLUSTER_NODE_UNREACHABLE 5051L -#define ERROR_CLUSTER_NODE_NOT_MEMBER 5052L -#define ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS 5053L -#define ERROR_CLUSTER_INVALID_NETWORK 5054L -#define ERROR_CLUSTER_NODE_UP 5056L -#define ERROR_CLUSTER_IPADDR_IN_USE 5057L -#define ERROR_CLUSTER_NODE_NOT_PAUSED 5058L -#define ERROR_CLUSTER_NO_SECURITY_CONTEXT 5059L -#define ERROR_CLUSTER_NETWORK_NOT_INTERNAL 5060L -#define ERROR_CLUSTER_NODE_ALREADY_UP 5061L -#define ERROR_CLUSTER_NODE_ALREADY_DOWN 5062L -#define ERROR_CLUSTER_NETWORK_ALREADY_ONLINE 5063L -#define ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE 5064L -#define ERROR_CLUSTER_NODE_ALREADY_MEMBER 5065L -#define ERROR_CLUSTER_LAST_INTERNAL_NETWORK 5066L -#define ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS 5067L -#define ERROR_INVALID_OPERATION_ON_QUORUM 5068L -#define ERROR_DEPENDENCY_NOT_ALLOWED 5069L -#define ERROR_CLUSTER_NODE_PAUSED 5070L -#define ERROR_NODE_CANT_HOST_RESOURCE 5071L -#define ERROR_CLUSTER_NODE_NOT_READY 5072L -#define ERROR_CLUSTER_NODE_SHUTTING_DOWN 5073L -#define ERROR_CLUSTER_JOIN_ABORTED 5074L -#define ERROR_CLUSTER_INCOMPATIBLE_VERSIONS 5075L -#define ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED 5076L -#define ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED 5077L -#define ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND 5078L -#define ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED 5079L -#define ERROR_CLUSTER_RESNAME_NOT_FOUND 5080L -#define ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED 5081L -#define ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST 5082L -#define ERROR_CLUSTER_DATABASE_SEQMISMATCH 5083L -#define ERROR_RESMON_INVALID_STATE 5084L -#define ERROR_CLUSTER_GUM_NOT_LOCKER 5085L -#define ERROR_QUORUM_DISK_NOT_FOUND 5086L -#define ERROR_DATABASE_BACKUP_CORRUPT 5087L -#define ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT 5088L -#define ERROR_RESOURCE_PROPERTY_UNCHANGEABLE 5089L -#define ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE 5890L -#define ERROR_CLUSTER_QUORUMLOG_NOT_FOUND 5891L -#define ERROR_CLUSTER_MEMBERSHIP_HALT 5892L -#define ERROR_CLUSTER_INSTANCE_ID_MISMATCH 5893L -#define ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP 5894L -#define ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH 5895L -#define ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP 5896L -#define ERROR_CLUSTER_PARAMETER_MISMATCH 5897L -#define ERROR_NODE_CANNOT_BE_CLUSTERED 5898L -#define ERROR_CLUSTER_WRONG_OS_VERSION 5899L -#define ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME 5900L -#define ERROR_CLUSCFG_ALREADY_COMMITTED 5901L -#define ERROR_CLUSCFG_ROLLBACK_FAILED 5902L -#define ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT 5903L -#define ERROR_CLUSTER_OLD_VERSION 5904L -#define ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME 5905L -#define ERROR_ENCRYPTION_FAILED 6000L -#define ERROR_DECRYPTION_FAILED 6001L -#define ERROR_FILE_ENCRYPTED 6002L -#define ERROR_NO_RECOVERY_POLICY 6003L -#define ERROR_NO_EFS 6004L -#define ERROR_WRONG_EFS 6005L -#define ERROR_NO_USER_KEYS 6006L -#define ERROR_FILE_NOT_ENCRYPTED 6007L -#define ERROR_NOT_EXPORT_FORMAT 6008L -#define ERROR_FILE_READ_ONLY 6009L -#define ERROR_DIR_EFS_DISALLOWED 6010L -#define ERROR_EFS_SERVER_NOT_TRUSTED 6011L -#define ERROR_BAD_RECOVERY_POLICY 6012L -#define ERROR_EFS_ALG_BLOB_TOO_BIG 6013L -#define ERROR_VOLUME_NOT_SUPPORT_EFS 6014L -#define ERROR_EFS_DISABLED 6015L -#define ERROR_EFS_VERSION_NOT_SUPPORT 6016L -#define ERROR_NO_BROWSER_SERVERS_FOUND 6118L -#define SCHED_E_SERVICE_NOT_LOCALSYSTEM 6200L -#define ERROR_CTX_WINSTATION_NAME_INVALID 7001L -#define ERROR_CTX_INVALID_PD 7002L -#define ERROR_CTX_PD_NOT_FOUND 7003L -#define ERROR_CTX_WD_NOT_FOUND 7004L -#define ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY 7005L -#define ERROR_CTX_SERVICE_NAME_COLLISION 7006L -#define ERROR_CTX_CLOSE_PENDING 7007L -#define ERROR_CTX_NO_OUTBUF 7008L -#define ERROR_CTX_MODEM_INF_NOT_FOUND 7009L -#define ERROR_CTX_INVALID_MODEMNAME 7010L -#define ERROR_CTX_MODEM_RESPONSE_ERROR 7011L -#define ERROR_CTX_MODEM_RESPONSE_TIMEOUT 7012L -#define ERROR_CTX_MODEM_RESPONSE_NO_CARRIER 7013L -#define ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE 7014L -#define ERROR_CTX_MODEM_RESPONSE_BUSY 7015L -#define ERROR_CTX_MODEM_RESPONSE_VOICE 7016L -#define ERROR_CTX_TD_ERROR 7017L -#define ERROR_CTX_WINSTATION_NOT_FOUND 7022L -#define ERROR_CTX_WINSTATION_ALREADY_EXISTS 7023L -#define ERROR_CTX_WINSTATION_BUSY 7024L -#define ERROR_CTX_BAD_VIDEO_MODE 7025L -#define ERROR_CTX_GRAPHICS_INVALID 7035L -#define ERROR_CTX_LOGON_DISABLED 7037L -#define ERROR_CTX_NOT_CONSOLE 7038L -#define ERROR_CTX_CLIENT_QUERY_TIMEOUT 7040L -#define ERROR_CTX_CONSOLE_DISCONNECT 7041L -#define ERROR_CTX_CONSOLE_CONNECT 7042L -#define ERROR_CTX_SHADOW_DENIED 7044L -#define ERROR_CTX_WINSTATION_ACCESS_DENIED 7045L -#define ERROR_CTX_INVALID_WD 7049L -#define ERROR_CTX_SHADOW_INVALID 7050L -#define ERROR_CTX_SHADOW_DISABLED 7051L -#define ERROR_CTX_CLIENT_LICENSE_IN_USE 7052L -#define ERROR_CTX_CLIENT_LICENSE_NOT_SET 7053L -#define ERROR_CTX_LICENSE_NOT_AVAILABLE 7054L -#define ERROR_CTX_LICENSE_CLIENT_INVALID 7055L -#define ERROR_CTX_LICENSE_EXPIRED 7056L -#define ERROR_CTX_SHADOW_NOT_RUNNING 7057L -#define ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE 7058L -#define ERROR_ACTIVATION_COUNT_EXCEEDED 7059L -#define FRS_ERR_INVALID_API_SEQUENCE 8001L -#define FRS_ERR_STARTING_SERVICE 8002L -#define FRS_ERR_STOPPING_SERVICE 8003L -#define FRS_ERR_INTERNAL_API 8004L -#define FRS_ERR_INTERNAL 8005L -#define FRS_ERR_SERVICE_COMM 8006L -#define FRS_ERR_INSUFFICIENT_PRIV 8007L -#define FRS_ERR_AUTHENTICATION 8008L -#define FRS_ERR_PARENT_INSUFFICIENT_PRIV 8009L -#define FRS_ERR_PARENT_AUTHENTICATION 8010L -#define FRS_ERR_CHILD_TO_PARENT_COMM 8011L -#define FRS_ERR_PARENT_TO_CHILD_COMM 8012L -#define FRS_ERR_SYSVOL_POPULATE 8013L -#define FRS_ERR_SYSVOL_POPULATE_TIMEOUT 8014L -#define FRS_ERR_SYSVOL_IS_BUSY 8015L -#define FRS_ERR_SYSVOL_DEMOTE 8016L -#define FRS_ERR_INVALID_SERVICE_PARAMETER 8017L -#define DS_S_SUCCESS NO_ERROR -#define ERROR_DS_NOT_INSTALLED 8200L -#define ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY 8201L -#define ERROR_DS_NO_ATTRIBUTE_OR_VALUE 8202L -#define ERROR_DS_INVALID_ATTRIBUTE_SYNTAX 8203L -#define ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED 8204L -#define ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS 8205L -#define ERROR_DS_BUSY 8206L -#define ERROR_DS_UNAVAILABLE 8207L -#define ERROR_DS_NO_RIDS_ALLOCATED 8208L -#define ERROR_DS_NO_MORE_RIDS 8209L -#define ERROR_DS_INCORRECT_ROLE_OWNER 8210L -#define ERROR_DS_RIDMGR_INIT_ERROR 8211L -#define ERROR_DS_OBJ_CLASS_VIOLATION 8212L -#define ERROR_DS_CANT_ON_NON_LEAF 8213L -#define ERROR_DS_CANT_ON_RDN 8214L -#define ERROR_DS_CANT_MOD_OBJ_CLASS 8215L -#define ERROR_DS_CROSS_DOM_MOVE_ERROR 8216L -#define ERROR_DS_GC_NOT_AVAILABLE 8217L -#define ERROR_SHARED_POLICY 8218L -#define ERROR_POLICY_OBJECT_NOT_FOUND 8219L -#define ERROR_POLICY_ONLY_IN_DS 8220L -#define ERROR_PROMOTION_ACTIVE 8221L -#define ERROR_NO_PROMOTION_ACTIVE 8222L -#define ERROR_DS_OPERATIONS_ERROR 8224L -#define ERROR_DS_PROTOCOL_ERROR 8225L -#define ERROR_DS_TIMELIMIT_EXCEEDED 8226L -#define ERROR_DS_SIZELIMIT_EXCEEDED 8227L -#define ERROR_DS_ADMIN_LIMIT_EXCEEDED 8228L -#define ERROR_DS_COMPARE_FALSE 8229L -#define ERROR_DS_COMPARE_TRUE 8230L -#define ERROR_DS_AUTH_METHOD_NOT_SUPPORTED 8231L -#define ERROR_DS_STRONG_AUTH_REQUIRED 8232L -#define ERROR_DS_INAPPROPRIATE_AUTH 8233L -#define ERROR_DS_AUTH_UNKNOWN 8234L -#define ERROR_DS_REFERRAL 8235L -#define ERROR_DS_UNAVAILABLE_CRIT_EXTENSION 8236L -#define ERROR_DS_CONFIDENTIALITY_REQUIRED 8237L -#define ERROR_DS_INAPPROPRIATE_MATCHING 8238L -#define ERROR_DS_CONSTRAINT_VIOLATION 8239L -#define ERROR_DS_NO_SUCH_OBJECT 8240L -#define ERROR_DS_ALIAS_PROBLEM 8241L -#define ERROR_DS_INVALID_DN_SYNTAX 8242L -#define ERROR_DS_IS_LEAF 8243L -#define ERROR_DS_ALIAS_DEREF_PROBLEM 8244L -#define ERROR_DS_UNWILLING_TO_PERFORM 8245L -#define ERROR_DS_LOOP_DETECT 8246L -#define ERROR_DS_NAMING_VIOLATION 8247L -#define ERROR_DS_OBJECT_RESULTS_TOO_LARGE 8248L -#define ERROR_DS_AFFECTS_MULTIPLE_DSAS 8249L -#define ERROR_DS_SERVER_DOWN 8250L -#define ERROR_DS_LOCAL_ERROR 8251L -#define ERROR_DS_ENCODING_ERROR 8252L -#define ERROR_DS_DECODING_ERROR 8253L -#define ERROR_DS_FILTER_UNKNOWN 8254L -#define ERROR_DS_PARAM_ERROR 8255L -#define ERROR_DS_NOT_SUPPORTED 8256L -#define ERROR_DS_NO_RESULTS_RETURNED 8257L -#define ERROR_DS_CONTROL_NOT_FOUND 8258L -#define ERROR_DS_CLIENT_LOOP 8259L -#define ERROR_DS_REFERRAL_LIMIT_EXCEEDED 8260L -#define ERROR_DS_SORT_CONTROL_MISSING 8261L -#define ERROR_DS_OFFSET_RANGE_ERROR 8262L -#define ERROR_DS_ROOT_MUST_BE_NC 8301L -#define ERROR_DS_ADD_REPLICA_INHIBITED 8302L -#define ERROR_DS_ATT_NOT_DEF_IN_SCHEMA 8303L -#define ERROR_DS_MAX_OBJ_SIZE_EXCEEDED 8304L -#define ERROR_DS_OBJ_STRING_NAME_EXISTS 8305L -#define ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA 8306L -#define ERROR_DS_RDN_DOESNT_MATCH_SCHEMA 8307L -#define ERROR_DS_NO_REQUESTED_ATTS_FOUND 8308L -#define ERROR_DS_USER_BUFFER_TO_SMALL 8309L -#define ERROR_DS_ATT_IS_NOT_ON_OBJ 8310L -#define ERROR_DS_ILLEGAL_MOD_OPERATION 8311L -#define ERROR_DS_OBJ_TOO_LARGE 8312L -#define ERROR_DS_BAD_INSTANCE_TYPE 8313L -#define ERROR_DS_MASTERDSA_REQUIRED 8314L -#define ERROR_DS_OBJECT_CLASS_REQUIRED 8315L -#define ERROR_DS_MISSING_REQUIRED_ATT 8316L -#define ERROR_DS_ATT_NOT_DEF_FOR_CLASS 8317L -#define ERROR_DS_ATT_ALREADY_EXISTS 8318L -#define ERROR_DS_CANT_ADD_ATT_VALUES 8320L -#define ERROR_DS_SINGLE_VALUE_CONSTRAINT 8321L -#define ERROR_DS_RANGE_CONSTRAINT 8322L -#define ERROR_DS_ATT_VAL_ALREADY_EXISTS 8323L -#define ERROR_DS_CANT_REM_MISSING_ATT 8324L -#define ERROR_DS_CANT_REM_MISSING_ATT_VAL 8325L -#define ERROR_DS_ROOT_CANT_BE_SUBREF 8326L -#define ERROR_DS_NO_CHAINING 8327L -#define ERROR_DS_NO_CHAINED_EVAL 8328L -#define ERROR_DS_NO_PARENT_OBJECT 8329L -#define ERROR_DS_PARENT_IS_AN_ALIAS 8330L -#define ERROR_DS_CANT_MIX_MASTER_AND_REPS 8331L -#define ERROR_DS_CHILDREN_EXIST 8332L -#define ERROR_DS_OBJ_NOT_FOUND 8333L -#define ERROR_DS_ALIASED_OBJ_MISSING 8334L -#define ERROR_DS_BAD_NAME_SYNTAX 8335L -#define ERROR_DS_ALIAS_POINTS_TO_ALIAS 8336L -#define ERROR_DS_CANT_DEREF_ALIAS 8337L -#define ERROR_DS_OUT_OF_SCOPE 8338L -#define ERROR_DS_OBJECT_BEING_REMOVED 8339L -#define ERROR_DS_CANT_DELETE_DSA_OBJ 8340L -#define ERROR_DS_GENERIC_ERROR 8341L -#define ERROR_DS_DSA_MUST_BE_INT_MASTER 8342L -#define ERROR_DS_CLASS_NOT_DSA 8343L -#define ERROR_DS_INSUFF_ACCESS_RIGHTS 8344L -#define ERROR_DS_ILLEGAL_SUPERIOR 8345L -#define ERROR_DS_ATTRIBUTE_OWNED_BY_SAM 8346L -#define ERROR_DS_NAME_TOO_MANY_PARTS 8347L -#define ERROR_DS_NAME_TOO_LONG 8348L -#define ERROR_DS_NAME_VALUE_TOO_LONG 8349L -#define ERROR_DS_NAME_UNPARSEABLE 8350L -#define ERROR_DS_NAME_TYPE_UNKNOWN 8351L -#define ERROR_DS_NOT_AN_OBJECT 8352L -#define ERROR_DS_SEC_DESC_TOO_SHORT 8353L -#define ERROR_DS_SEC_DESC_INVALID 8354L -#define ERROR_DS_NO_DELETED_NAME 8355L -#define ERROR_DS_SUBREF_MUST_HAVE_PARENT 8356L -#define ERROR_DS_NCNAME_MUST_BE_NC 8357L -#define ERROR_DS_CANT_ADD_SYSTEM_ONLY 8358L -#define ERROR_DS_CLASS_MUST_BE_CONCRETE 8359L -#define ERROR_DS_INVALID_DMD 8360L -#define ERROR_DS_OBJ_GUID_EXISTS 8361L -#define ERROR_DS_NOT_ON_BACKLINK 8362L -#define ERROR_DS_NO_CROSSREF_FOR_NC 8363L -#define ERROR_DS_SHUTTING_DOWN 8364L -#define ERROR_DS_UNKNOWN_OPERATION 8365L -#define ERROR_DS_INVALID_ROLE_OWNER 8366L -#define ERROR_DS_COULDNT_CONTACT_FSMO 8367L -#define ERROR_DS_CROSS_NC_DN_RENAME 8368L -#define ERROR_DS_CANT_MOD_SYSTEM_ONLY 8369L -#define ERROR_DS_REPLICATOR_ONLY 8370L -#define ERROR_DS_OBJ_CLASS_NOT_DEFINED 8371L -#define ERROR_DS_OBJ_CLASS_NOT_SUBCLASS 8372L -#define ERROR_DS_NAME_REFERENCE_INVALID 8373L -#define ERROR_DS_CROSS_REF_EXISTS 8374L -#define ERROR_DS_CANT_DEL_MASTER_CROSSREF 8375L -#define ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD 8376L -#define ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX 8377L -#define ERROR_DS_DUP_RDN 8378L -#define ERROR_DS_DUP_OID 8379L -#define ERROR_DS_DUP_MAPI_ID 8380L -#define ERROR_DS_DUP_SCHEMA_ID_GUID 8381L -#define ERROR_DS_DUP_LDAP_DISPLAY_NAME 8382L -#define ERROR_DS_SEMANTIC_ATT_TEST 8383L -#define ERROR_DS_SYNTAX_MISMATCH 8384L -#define ERROR_DS_EXISTS_IN_MUST_HAVE 8385L -#define ERROR_DS_EXISTS_IN_MAY_HAVE 8386L -#define ERROR_DS_NONEXISTENT_MAY_HAVE 8387L -#define ERROR_DS_NONEXISTENT_MUST_HAVE 8388L -#define ERROR_DS_AUX_CLS_TEST_FAIL 8389L -#define ERROR_DS_NONEXISTENT_POSS_SUP 8390L -#define ERROR_DS_SUB_CLS_TEST_FAIL 8391L -#define ERROR_DS_BAD_RDN_ATT_ID_SYNTAX 8392L -#define ERROR_DS_EXISTS_IN_AUX_CLS 8393L -#define ERROR_DS_EXISTS_IN_SUB_CLS 8394L -#define ERROR_DS_EXISTS_IN_POSS_SUP 8395L -#define ERROR_DS_RECALCSCHEMA_FAILED 8396L -#define ERROR_DS_TREE_DELETE_NOT_FINISHED 8397L -#define ERROR_DS_CANT_DELETE 8398L -#define ERROR_DS_ATT_SCHEMA_REQ_ID 8399L -#define ERROR_DS_BAD_ATT_SCHEMA_SYNTAX 8400L -#define ERROR_DS_CANT_CACHE_ATT 8401L -#define ERROR_DS_CANT_CACHE_CLASS 8402L -#define ERROR_DS_CANT_REMOVE_ATT_CACHE 8403L -#define ERROR_DS_CANT_REMOVE_CLASS_CACHE 8404L -#define ERROR_DS_CANT_RETRIEVE_DN 8405L -#define ERROR_DS_MISSING_SUPREF 8406L -#define ERROR_DS_CANT_RETRIEVE_INSTANCE 8407L -#define ERROR_DS_CODE_INCONSISTENCY 8408L -#define ERROR_DS_DATABASE_ERROR 8409L -#define ERROR_DS_GOVERNSID_MISSING 8410L -#define ERROR_DS_MISSING_EXPECTED_ATT 8411L -#define ERROR_DS_NCNAME_MISSING_CR_REF 8412L -#define ERROR_DS_SECURITY_CHECKING_ERROR 8413L -#define ERROR_DS_SCHEMA_NOT_LOADED 8414L -#define ERROR_DS_SCHEMA_ALLOC_FAILED 8415L -#define ERROR_DS_ATT_SCHEMA_REQ_SYNTAX 8416L -#define ERROR_DS_GCVERIFY_ERROR 8417L -#define ERROR_DS_DRA_SCHEMA_MISMATCH 8418L -#define ERROR_DS_CANT_FIND_DSA_OBJ 8419L -#define ERROR_DS_CANT_FIND_EXPECTED_NC 8420L -#define ERROR_DS_CANT_FIND_NC_IN_CACHE 8421L -#define ERROR_DS_CANT_RETRIEVE_CHILD 8422L -#define ERROR_DS_SECURITY_ILLEGAL_MODIFY 8423L -#define ERROR_DS_CANT_REPLACE_HIDDEN_REC 8424L -#define ERROR_DS_BAD_HIERARCHY_FILE 8425L -#define ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED 8426L -#define ERROR_DS_CONFIG_PARAM_MISSING 8427L -#define ERROR_DS_COUNTING_AB_INDICES_FAILED 8428L -#define ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED 8429L -#define ERROR_DS_INTERNAL_FAILURE 8430L -#define ERROR_DS_UNKNOWN_ERROR 8431L -#define ERROR_DS_ROOT_REQUIRES_CLASS_TOP 8432L -#define ERROR_DS_REFUSING_FSMO_ROLES 8433L -#define ERROR_DS_MISSING_FSMO_SETTINGS 8434L -#define ERROR_DS_UNABLE_TO_SURRENDER_ROLES 8435L -#define ERROR_DS_DRA_GENERIC 8436L -#define ERROR_DS_DRA_INVALID_PARAMETER 8437L -#define ERROR_DS_DRA_BUSY 8438L -#define ERROR_DS_DRA_BAD_DN 8439L -#define ERROR_DS_DRA_BAD_NC 8440L -#define ERROR_DS_DRA_DN_EXISTS 8441L -#define ERROR_DS_DRA_INTERNAL_ERROR 8442L -#define ERROR_DS_DRA_INCONSISTENT_DIT 8443L -#define ERROR_DS_DRA_CONNECTION_FAILED 8444L -#define ERROR_DS_DRA_BAD_INSTANCE_TYPE 8445L -#define ERROR_DS_DRA_OUT_OF_MEM 8446L -#define ERROR_DS_DRA_MAIL_PROBLEM 8447L -#define ERROR_DS_DRA_REF_ALREADY_EXISTS 8448L -#define ERROR_DS_DRA_REF_NOT_FOUND 8449L -#define ERROR_DS_DRA_OBJ_IS_REP_SOURCE 8450L -#define ERROR_DS_DRA_DB_ERROR 8451L -#define ERROR_DS_DRA_NO_REPLICA 8452L -#define ERROR_DS_DRA_ACCESS_DENIED 8453L -#define ERROR_DS_DRA_NOT_SUPPORTED 8454L -#define ERROR_DS_DRA_RPC_CANCELLED 8455L -#define ERROR_DS_DRA_SOURCE_DISABLED 8456L -#define ERROR_DS_DRA_SINK_DISABLED 8457L -#define ERROR_DS_DRA_NAME_COLLISION 8458L -#define ERROR_DS_DRA_SOURCE_REINSTALLED 8459L -#define ERROR_DS_DRA_MISSING_PARENT 8460L -#define ERROR_DS_DRA_PREEMPTED 8461L -#define ERROR_DS_DRA_ABANDON_SYNC 8462L -#define ERROR_DS_DRA_SHUTDOWN 8463L -#define ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET 8464L -#define ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA 8465L -#define ERROR_DS_DRA_EXTN_CONNECTION_FAILED 8466L -#define ERROR_DS_INSTALL_SCHEMA_MISMATCH 8467L -#define ERROR_DS_DUP_LINK_ID 8468L -#define ERROR_DS_NAME_ERROR_RESOLVING 8469L -#define ERROR_DS_NAME_ERROR_NOT_FOUND 8470L -#define ERROR_DS_NAME_ERROR_NOT_UNIQUE 8471L -#define ERROR_DS_NAME_ERROR_NO_MAPPING 8472L -#define ERROR_DS_NAME_ERROR_DOMAIN_ONLY 8473L -#define ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING 8474L -#define ERROR_DS_CONSTRUCTED_ATT_MOD 8475L -#define ERROR_DS_WRONG_OM_OBJ_CLASS 8476L -#define ERROR_DS_DRA_REPL_PENDING 8477L -#define ERROR_DS_DS_REQUIRED 8478L -#define ERROR_DS_INVALID_LDAP_DISPLAY_NAME 8479L -#define ERROR_DS_NON_BASE_SEARCH 8480L -#define ERROR_DS_CANT_RETRIEVE_ATTS 8481L -#define ERROR_DS_BACKLINK_WITHOUT_LINK 8482L -#define ERROR_DS_EPOCH_MISMATCH 8483L -#define ERROR_DS_SRC_NAME_MISMATCH 8484L -#define ERROR_DS_SRC_AND_DST_NC_IDENTICAL 8485L -#define ERROR_DS_DST_NC_MISMATCH 8486L -#define ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC 8487L -#define ERROR_DS_SRC_GUID_MISMATCH 8488L -#define ERROR_DS_CANT_MOVE_DELETED_OBJECT 8489L -#define ERROR_DS_PDC_OPERATION_IN_PROGRESS 8490L -#define ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD 8491L -#define ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION 8492L -#define ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS 8493L -#define ERROR_DS_NC_MUST_HAVE_NC_PARENT 8494L -#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE 8495L -#define ERROR_DS_DST_DOMAIN_NOT_NATIVE 8496L -#define ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER 8497L -#define ERROR_DS_CANT_MOVE_ACCOUNT_GROUP 8498L -#define ERROR_DS_CANT_MOVE_RESOURCE_GROUP 8499L -#define ERROR_DS_INVALID_SEARCH_FLAG 8500L -#define ERROR_DS_NO_TREE_DELETE_ABOVE_NC 8501L -#define ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE 8502L -#define ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE 8503L -#define ERROR_DS_SAM_INIT_FAILURE 8504L -#define ERROR_DS_SENSITIVE_GROUP_VIOLATION 8505L -#define ERROR_DS_CANT_MOD_PRIMARYGROUPID 8506L -#define ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD 8507L -#define ERROR_DS_NONSAFE_SCHEMA_CHANGE 8508L -#define ERROR_DS_SCHEMA_UPDATE_DISALLOWED 8509L -#define ERROR_DS_CANT_CREATE_UNDER_SCHEMA 8510L -#define ERROR_DS_INSTALL_NO_SRC_SCH_VERSION 8511L -#define ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE 8512L -#define ERROR_DS_INVALID_GROUP_TYPE 8513L -#define ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN 8514L -#define ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN 8515L -#define ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER 8516L -#define ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER 8517L -#define ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER 8518L -#define ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER 8519L -#define ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER 8520L -#define ERROR_DS_HAVE_PRIMARY_MEMBERS 8521L -#define ERROR_DS_STRING_SD_CONVERSION_FAILED 8522L -#define ERROR_DS_NAMING_MASTER_GC 8523L -#define ERROR_DS_DNS_LOOKUP_FAILURE 8524L -#define ERROR_DS_COULDNT_UPDATE_SPNS 8525L -#define ERROR_DS_CANT_RETRIEVE_SD 8526L -#define ERROR_DS_KEY_NOT_UNIQUE 8527L -#define ERROR_DS_WRONG_LINKED_ATT_SYNTAX 8528L -#define ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD 8529L -#define ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY 8530L -#define ERROR_DS_CANT_START 8531L -#define ERROR_DS_INIT_FAILURE 8532L -#define ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION 8533L -#define ERROR_DS_SOURCE_DOMAIN_IN_FOREST 8534L -#define ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST 8535L -#define ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED 8536L -#define ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN 8537L -#define ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER 8538L -#define ERROR_DS_SRC_SID_EXISTS_IN_FOREST 8539L -#define ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH 8540L -#define ERROR_SAM_INIT_FAILURE 8541L -#define ERROR_DS_DRA_SCHEMA_INFO_SHIP 8542L -#define ERROR_DS_DRA_SCHEMA_CONFLICT 8543L -#define ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT 8544L -#define ERROR_DS_DRA_OBJ_NC_MISMATCH 8545L -#define ERROR_DS_NC_STILL_HAS_DSAS 8546L -#define ERROR_DS_GC_REQUIRED 8547L -#define ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY 8548L -#define ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS 8549L -#define ERROR_DS_CANT_ADD_TO_GC 8550L -#define ERROR_DS_NO_CHECKPOINT_WITH_PDC 8551L -#define ERROR_DS_SOURCE_AUDITING_NOT_ENABLED 8552L -#define ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC 8553L -#define ERROR_DS_INVALID_NAME_FOR_SPN 8554L -#define ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS 8555L -#define ERROR_DS_UNICODEPWD_NOT_IN_QUOTES 8556L -#define ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED 8557L -#define ERROR_DS_MUST_BE_RUN_ON_DST_DC 8558L -#define ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER 8559L -#define ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ 8560L -#define ERROR_DS_INIT_FAILURE_CONSOLE 8561L -#define ERROR_DS_SAM_INIT_FAILURE_CONSOLE 8562L -#define ERROR_DS_FOREST_VERSION_TOO_HIGH 8563L -#define ERROR_DS_DOMAIN_VERSION_TOO_HIGH 8564L -#define ERROR_DS_FOREST_VERSION_TOO_LOW 8565L -#define ERROR_DS_DOMAIN_VERSION_TOO_LOW 8566L -#define ERROR_DS_INCOMPATIBLE_VERSION 8567L -#define ERROR_DS_LOW_DSA_VERSION 8568L -#define ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN 8569L -#define ERROR_DS_NOT_SUPPORTED_SORT_ORDER 8570L -#define ERROR_DS_NAME_NOT_UNIQUE 8571L -#define ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4 8572L -#define ERROR_DS_OUT_OF_VERSION_STORE 8573L -#define ERROR_DS_INCOMPATIBLE_CONTROLS_USED 8574L -#define ERROR_DS_NO_REF_DOMAIN 8575L -#define ERROR_DS_RESERVED_LINK_ID 8576L -#define ERROR_DS_LINK_ID_NOT_AVAILABLE 8577L -#define ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER 8578L -#define ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE 8579L -#define ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC 8580L -#define ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG 8581L -#define ERROR_DS_MODIFYDN_WRONG_GRANDPARENT 8582L -#define ERROR_DS_NAME_ERROR_TRUST_REFERRAL 8583L -#define ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER 8584L -#define ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD 8585L -#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2 8586L -#define ERROR_DS_THREAD_LIMIT_EXCEEDED 8587L -#define ERROR_DS_NOT_CLOSEST 8588L -#define ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF 8589L -#define ERROR_DS_SINGLE_USER_MODE_FAILED 8590L -#define ERROR_DS_NTDSCRIPT_SYNTAX_ERROR 8591L -#define ERROR_DS_NTDSCRIPT_PROCESS_ERROR 8592L -#define ERROR_DS_DIFFERENT_REPL_EPOCHS 8593L -#define ERROR_DS_DRS_EXTENSIONS_CHANGED 8594L -#define ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR 8595L -#define ERROR_DS_NO_MSDS_INTID 8596L -#define ERROR_DS_DUP_MSDS_INTID 8597L -#define ERROR_DS_EXISTS_IN_RDNATTID 8598L -#define ERROR_DS_AUTHORIZATION_FAILED 8599L -#define ERROR_DS_INVALID_SCRIPT 8600L -#define ERROR_DS_REMOTE_CROSSREF_OP_FAILED 8601L -#define ERROR_DS_CROSS_REF_BUSY 8602L -#define ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN 8603L -#define ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC 8604L -#define ERROR_DS_DUPLICATE_ID_FOUND 8605L -#define ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT 8606L -#define ERROR_DS_GROUP_CONVERSION_ERROR 8607L -#define ERROR_DS_CANT_MOVE_APP_BASIC_GROUP 8608L -#define ERROR_DS_CANT_MOVE_APP_QUERY_GROUP 8609L -#define ERROR_DS_ROLE_NOT_VERIFIED 8610L -#define ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL 8611L -#define ERROR_DS_DOMAIN_RENAME_IN_PROGRESS 8612L -#define ERROR_DS_EXISTING_AD_CHILD_NC 8613L -#define ERROR_DS_REPL_LIFETIME_EXCEEDED 8614L -#define ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER 8615L -#define ERROR_DS_LDAP_SEND_QUEUE_FULL 8616L -#define ERROR_DS_DRA_OUT_SCHEDULE_WINDOW 8617L -#define DNS_ERROR_RESPONSE_CODES_BASE 9000 -#define DNS_ERROR_RCODE_NO_ERROR NO_ERROR -#define DNS_ERROR_MASK 0x00002328 -#define DNS_ERROR_RCODE_FORMAT_ERROR 9001L -#define DNS_ERROR_RCODE_SERVER_FAILURE 9002L -#define DNS_ERROR_RCODE_NAME_ERROR 9003L -#define DNS_ERROR_RCODE_NOT_IMPLEMENTED 9004L -#define DNS_ERROR_RCODE_REFUSED 9005L -#define DNS_ERROR_RCODE_YXDOMAIN 9006L -#define DNS_ERROR_RCODE_YXRRSET 9007L -#define DNS_ERROR_RCODE_NXRRSET 9008L -#define DNS_ERROR_RCODE_NOTAUTH 9009L -#define DNS_ERROR_RCODE_NOTZONE 9010L -#define DNS_ERROR_RCODE_BADSIG 9016L -#define DNS_ERROR_RCODE_BADKEY 9017L -#define DNS_ERROR_RCODE_BADTIME 9018L -#define DNS_ERROR_RCODE_LAST DNS_ERROR_RCODE_BADTIME -#define DNS_ERROR_PACKET_FMT_BASE 9500 -#define DNS_INFO_NO_RECORDS 9501L -#define DNS_ERROR_BAD_PACKET 9502L -#define DNS_ERROR_NO_PACKET 9503L -#define DNS_ERROR_RCODE 9504L -#define DNS_ERROR_UNSECURE_PACKET 9505L -#define DNS_STATUS_PACKET_UNSECURE DNS_ERROR_UNSECURE_PACKET -#define DNS_ERROR_NO_MEMORY ERROR_OUTOFMEMORY -#define DNS_ERROR_INVALID_NAME ERROR_INVALID_NAME -#define DNS_ERROR_INVALID_DATA ERROR_INVALID_DATA -#define DNS_ERROR_GENERAL_API_BASE 9550 -#define DNS_ERROR_INVALID_TYPE 9551L -#define DNS_ERROR_INVALID_IP_ADDRESS 9552L -#define DNS_ERROR_INVALID_PROPERTY 9553L -#define DNS_ERROR_TRY_AGAIN_LATER 9554L -#define DNS_ERROR_NOT_UNIQUE 9555L -#define DNS_ERROR_NON_RFC_NAME 9556L -#define DNS_STATUS_FQDN 9557L -#define DNS_STATUS_DOTTED_NAME 9558L -#define DNS_STATUS_SINGLE_PART_NAME 9559L -#define DNS_ERROR_INVALID_NAME_CHAR 9560L -#define DNS_ERROR_NUMERIC_NAME 9561L -#define DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER 9562L -#define DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION 9563L -#define DNS_ERROR_CANNOT_FIND_ROOT_HINTS 9564L -#define DNS_ERROR_INCONSISTENT_ROOT_HINTS 9565L -#define DNS_ERROR_ZONE_BASE 9600 -#define DNS_ERROR_ZONE_DOES_NOT_EXIST 9601L -#define DNS_ERROR_NO_ZONE_INFO 9602L -#define DNS_ERROR_INVALID_ZONE_OPERATION 9603L -#define DNS_ERROR_ZONE_CONFIGURATION_ERROR 9604L -#define DNS_ERROR_ZONE_HAS_NO_SOA_RECORD 9605L -#define DNS_ERROR_ZONE_HAS_NO_NS_RECORDS 9606L -#define DNS_ERROR_ZONE_LOCKED 9607L -#define DNS_ERROR_ZONE_CREATION_FAILED 9608L -#define DNS_ERROR_ZONE_ALREADY_EXISTS 9609L -#define DNS_ERROR_AUTOZONE_ALREADY_EXISTS 9610L -#define DNS_ERROR_INVALID_ZONE_TYPE 9611L -#define DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP 9612L -#define DNS_ERROR_ZONE_NOT_SECONDARY 9613L -#define DNS_ERROR_NEED_SECONDARY_ADDRESSES 9614L -#define DNS_ERROR_WINS_INIT_FAILED 9615L -#define DNS_ERROR_NEED_WINS_SERVERS 9616L -#define DNS_ERROR_NBSTAT_INIT_FAILED 9617L -#define DNS_ERROR_SOA_DELETE_INVALID 9618L -#define DNS_ERROR_FORWARDER_ALREADY_EXISTS 9619L -#define DNS_ERROR_ZONE_REQUIRES_MASTER_IP 9620L -#define DNS_ERROR_ZONE_IS_SHUTDOWN 9621L -#define DNS_ERROR_DATAFILE_BASE 9650 -#define DNS_ERROR_PRIMARY_REQUIRES_DATAFILE 9651L -#define DNS_ERROR_INVALID_DATAFILE_NAME 9652L -#define DNS_ERROR_DATAFILE_OPEN_FAILURE 9653L -#define DNS_ERROR_FILE_WRITEBACK_FAILED 9654L -#define DNS_ERROR_DATAFILE_PARSING 9655L -#define DNS_ERROR_DATABASE_BASE 9700 -#define DNS_ERROR_RECORD_DOES_NOT_EXIST 9701L -#define DNS_ERROR_RECORD_FORMAT 9702L -#define DNS_ERROR_NODE_CREATION_FAILED 9703L -#define DNS_ERROR_UNKNOWN_RECORD_TYPE 9704L -#define DNS_ERROR_RECORD_TIMED_OUT 9705L -#define DNS_ERROR_NAME_NOT_IN_ZONE 9706L -#define DNS_ERROR_CNAME_LOOP 9707L -#define DNS_ERROR_NODE_IS_CNAME 9708L -#define DNS_ERROR_CNAME_COLLISION 9709L -#define DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT 9710L -#define DNS_ERROR_RECORD_ALREADY_EXISTS 9711L -#define DNS_ERROR_SECONDARY_DATA 9712L -#define DNS_ERROR_NO_CREATE_CACHE_DATA 9713L -#define DNS_ERROR_NAME_DOES_NOT_EXIST 9714L -#define DNS_WARNING_PTR_CREATE_FAILED 9715L -#define DNS_WARNING_DOMAIN_UNDELETED 9716L -#define DNS_ERROR_DS_UNAVAILABLE 9717L -#define DNS_ERROR_DS_ZONE_ALREADY_EXISTS 9718L -#define DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE 9719L -#define DNS_ERROR_OPERATION_BASE 9750 -#define DNS_INFO_AXFR_COMPLETE 9751L -#define DNS_ERROR_AXFR 9752L -#define DNS_INFO_ADDED_LOCAL_WINS 9753L -#define DNS_ERROR_SECURE_BASE 9800 -#define DNS_STATUS_CONTINUE_NEEDED 9801L -#define DNS_ERROR_SETUP_BASE 9850 -#define DNS_ERROR_NO_TCPIP 9851L -#define DNS_ERROR_NO_DNS_SERVERS 9852L -#define DNS_ERROR_DP_BASE 9900 -#define DNS_ERROR_DP_DOES_NOT_EXIST 9901L -#define DNS_ERROR_DP_ALREADY_EXISTS 9902L -#define DNS_ERROR_DP_NOT_ENLISTED 9903L -#define DNS_ERROR_DP_ALREADY_ENLISTED 9904L -#define DNS_ERROR_DP_NOT_AVAILABLE 9905L -#define DNS_ERROR_DP_FSMO_ERROR 9906L - -#ifndef WSABASEERR -#define WSABASEERR 10000 -#define WSAEINTR 10004L -#define WSAEBADF 10009L -#define WSAEACCES 10013L -#define WSAEFAULT 10014L -#define WSAEINVAL 10022L -#define WSAEMFILE 10024L -#define WSAEWOULDBLOCK 10035L -#define WSAEINPROGRESS 10036L -#define WSAEALREADY 10037L -#define WSAENOTSOCK 10038L -#define WSAEDESTADDRREQ 10039L -#define WSAEMSGSIZE 10040L -#define WSAEPROTOTYPE 10041L -#define WSAENOPROTOOPT 10042L -#define WSAEPROTONOSUPPORT 10043L -#define WSAESOCKTNOSUPPORT 10044L -#define WSAEOPNOTSUPP 10045L -#define WSAEPFNOSUPPORT 10046L -#define WSAEAFNOSUPPORT 10047L -#define WSAEADDRINUSE 10048L -#define WSAEADDRNOTAVAIL 10049L -#define WSAENETDOWN 10050L -#define WSAENETUNREACH 10051L -#define WSAENETRESET 10052L -#define WSAECONNABORTED 10053L -#define WSAECONNRESET 10054L -#define WSAENOBUFS 10055L -#define WSAEISCONN 10056L -#define WSAENOTCONN 10057L -#define WSAESHUTDOWN 10058L -#define WSAETOOMANYREFS 10059L -#define WSAETIMEDOUT 10060L -#define WSAECONNREFUSED 10061L -#define WSAELOOP 10062L -#define WSAENAMETOOLONG 10063L -#define WSAEHOSTDOWN 10064L -#define WSAEHOSTUNREACH 10065L -#define WSAENOTEMPTY 10066L -#define WSAEPROCLIM 10067L -#define WSAEUSERS 10068L -#define WSAEDQUOT 10069L -#define WSAESTALE 10070L -#define WSAEREMOTE 10071L -#define WSASYSNOTREADY 10091L -#define WSAVERNOTSUPPORTED 10092L -#define WSANOTINITIALISED 10093L -#define WSAEDISCON 10101L -#define WSAENOMORE 10102L -#define WSAECANCELLED 10103L -#define WSAEINVALIDPROCTABLE 10104L -#define WSAEINVALIDPROVIDER 10105L -#define WSAEPROVIDERFAILEDINIT 10106L -#define WSASYSCALLFAILURE 10107L -#define WSASERVICE_NOT_FOUND 10108L -#define WSATYPE_NOT_FOUND 10109L -#define WSA_E_NO_MORE 10110L -#define WSA_E_CANCELLED 10111L -#define WSAEREFUSED 10112L -#ifndef WSAHOST_NOT_FOUND -#define WSAHOST_NOT_FOUND 11001L -#endif -#ifndef WSATRY_AGAIN -#define WSATRY_AGAIN 11002L -#endif -#ifndef WSANO_RECOVERY -#define WSANO_RECOVERY 11003L -#endif -#ifndef WSANO_DATA -#define WSANO_DATA 11004L -#endif -#ifndef WSA_QOS_RECEIVERS -#define WSA_QOS_RECEIVERS 11005L -#endif -#ifndef WSA_QOS_SENDERS -#define WSA_QOS_SENDERS 11006L -#endif -#ifndef WSA_QOS_NO_SENDERS -#define WSA_QOS_NO_SENDERS 11007L -#endif -#ifndef WSA_QOS_NO_RECEIVERS -#define WSA_QOS_NO_RECEIVERS 11008L -#endif -#ifndef WSA_QOS_REQUEST_CONFIRMED -#define WSA_QOS_REQUEST_CONFIRMED 11009L -#endif -#ifndef WSA_QOS_ADMISSION_FAILURE -#define WSA_QOS_ADMISSION_FAILURE 11010L -#endif -#ifndef WSA_QOS_POLICY_FAILURE -#define WSA_QOS_POLICY_FAILURE 11011L -#endif -#ifndef WSA_QOS_BAD_STYLE -#define WSA_QOS_BAD_STYLE 11012L -#endif -#ifndef WSA_QOS_BAD_OBJECT -#define WSA_QOS_BAD_OBJECT 11013L -#endif -#ifndef WSA_QOS_TRAFFIC_CTRL_ERROR -#define WSA_QOS_TRAFFIC_CTRL_ERROR 11014L -#endif -#ifndef WSA_QOS_GENERIC_ERROR -#define WSA_QOS_GENERIC_ERROR 11015L -#endif -#ifndef WSA_QOS_ESERVICETYPE -#define WSA_QOS_ESERVICETYPE 11016L -#endif -#ifndef WSA_QOS_EFLOWSPEC -#define WSA_QOS_EFLOWSPEC 11017L -#endif -#ifndef WSA_QOS_EPROVSPECBUF -#define WSA_QOS_EPROVSPECBUF 11018L -#endif -#ifndef WSA_QOS_EFILTERSTYLE -#define WSA_QOS_EFILTERSTYLE 11019L -#endif -#ifndef WSA_QOS_EFILTERTYPE -#define WSA_QOS_EFILTERTYPE 11020L -#endif -#ifndef WSA_QOS_EFILTERCOUNT -#define WSA_QOS_EFILTERCOUNT 11021L -#endif -#ifndef WSA_QOS_EOBJLENGTH -#define WSA_QOS_EOBJLENGTH 11022L -#endif -#ifndef WSA_QOS_EFLOWCOUNT -#define WSA_QOS_EFLOWCOUNT 11023L -#endif -#ifndef WSA_QOS_EUNKNOWNPSOBJ -#define WSA_QOS_EUNKNOWNPSOBJ 11024L -#endif -#ifndef WSA_QOS_EPOLICYOBJ -#define WSA_QOS_EPOLICYOBJ 11025L -#endif -#ifndef WSA_QOS_EFLOWDESC -#define WSA_QOS_EFLOWDESC 11026L -#endif -#ifndef WSA_QOS_EPSFLOWSPEC -#define WSA_QOS_EPSFLOWSPEC 11027L -#endif -#ifndef WSA_QOS_EPSFILTERSPEC -#define WSA_QOS_EPSFILTERSPEC 11028L -#endif -#ifndef WSA_QOS_ESDMODEOBJ -#define WSA_QOS_ESDMODEOBJ 11029L -#endif -#ifndef WSA_QOS_ESHAPERATEOBJ -#define WSA_QOS_ESHAPERATEOBJ 11030L -#endif -#ifndef WSA_QOS_RESERVED_PETYPE -#define WSA_QOS_RESERVED_PETYPE 11031L -#endif -#endif /* WSABASEERR */ - -#define ERROR_SXS_SECTION_NOT_FOUND 14000L -#define ERROR_SXS_CANT_GEN_ACTCTX 14001L -#define ERROR_SXS_INVALID_ACTCTXDATA_FORMAT 14002L -#define ERROR_SXS_ASSEMBLY_NOT_FOUND 14003L -#define ERROR_SXS_MANIFEST_FORMAT_ERROR 14004L -#define ERROR_SXS_MANIFEST_PARSE_ERROR 14005L -#define ERROR_SXS_ACTIVATION_CONTEXT_DISABLED 14006L -#define ERROR_SXS_KEY_NOT_FOUND 14007L -#define ERROR_SXS_VERSION_CONFLICT 14008L -#define ERROR_SXS_WRONG_SECTION_TYPE 14009L -#define ERROR_SXS_THREAD_QUERIES_DISABLED 14010L -#define ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET 14011L -#define ERROR_SXS_UNKNOWN_ENCODING_GROUP 14012L -#define ERROR_SXS_UNKNOWN_ENCODING 14013L -#define ERROR_SXS_INVALID_XML_NAMESPACE_URI 14014L -#define ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED 14015L -#define ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED 14016L -#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE 14017L -#define ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE 14018L -#define ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE 14019L -#define ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT 14020L -#define ERROR_SXS_DUPLICATE_DLL_NAME 14021L -#define ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME 14022L -#define ERROR_SXS_DUPLICATE_CLSID 14023L -#define ERROR_SXS_DUPLICATE_IID 14024L -#define ERROR_SXS_DUPLICATE_TLBID 14025L -#define ERROR_SXS_DUPLICATE_PROGID 14026L -#define ERROR_SXS_DUPLICATE_ASSEMBLY_NAME 14027L -#define ERROR_SXS_FILE_HASH_MISMATCH 14028L -#define ERROR_SXS_POLICY_PARSE_ERROR 14029L -#define ERROR_SXS_XML_E_MISSINGQUOTE 14030L -#define ERROR_SXS_XML_E_COMMENTSYNTAX 14031L -#define ERROR_SXS_XML_E_BADSTARTNAMECHAR 14032L -#define ERROR_SXS_XML_E_BADNAMECHAR 14033L -#define ERROR_SXS_XML_E_BADCHARINSTRING 14034L -#define ERROR_SXS_XML_E_XMLDECLSYNTAX 14035L -#define ERROR_SXS_XML_E_BADCHARDATA 14036L -#define ERROR_SXS_XML_E_MISSINGWHITESPACE 14037L -#define ERROR_SXS_XML_E_EXPECTINGTAGEND 14038L -#define ERROR_SXS_XML_E_MISSINGSEMICOLON 14039L -#define ERROR_SXS_XML_E_UNBALANCEDPAREN 14040L -#define ERROR_SXS_XML_E_INTERNALERROR 14041L -#define ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE 14042L -#define ERROR_SXS_XML_E_INCOMPLETE_ENCODING 14043L -#define ERROR_SXS_XML_E_MISSING_PAREN 14044L -#define ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE 14045L -#define ERROR_SXS_XML_E_MULTIPLE_COLONS 14046L -#define ERROR_SXS_XML_E_INVALID_DECIMAL 14047L -#define ERROR_SXS_XML_E_INVALID_HEXIDECIMAL 14048L -#define ERROR_SXS_XML_E_INVALID_UNICODE 14049L -#define ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK 14050L -#define ERROR_SXS_XML_E_UNEXPECTEDENDTAG 14051L -#define ERROR_SXS_XML_E_UNCLOSEDTAG 14052L -#define ERROR_SXS_XML_E_DUPLICATEATTRIBUTE 14053L -#define ERROR_SXS_XML_E_MULTIPLEROOTS 14054L -#define ERROR_SXS_XML_E_INVALIDATROOTLEVEL 14055L -#define ERROR_SXS_XML_E_BADXMLDECL 14056L -#define ERROR_SXS_XML_E_MISSINGROOT 14057L -#define ERROR_SXS_XML_E_UNEXPECTEDEOF 14058L -#define ERROR_SXS_XML_E_BADPEREFINSUBSET 14059L -#define ERROR_SXS_XML_E_UNCLOSEDSTARTTAG 14060L -#define ERROR_SXS_XML_E_UNCLOSEDENDTAG 14061L -#define ERROR_SXS_XML_E_UNCLOSEDSTRING 14062L -#define ERROR_SXS_XML_E_UNCLOSEDCOMMENT 14063L -#define ERROR_SXS_XML_E_UNCLOSEDDECL 14064L -#define ERROR_SXS_XML_E_UNCLOSEDCDATA 14065L -#define ERROR_SXS_XML_E_RESERVEDNAMESPACE 14066L -#define ERROR_SXS_XML_E_INVALIDENCODING 14067L -#define ERROR_SXS_XML_E_INVALIDSWITCH 14068L -#define ERROR_SXS_XML_E_BADXMLCASE 14069L -#define ERROR_SXS_XML_E_INVALID_STANDALONE 14070L -#define ERROR_SXS_XML_E_UNEXPECTED_STANDALONE 14071L -#define ERROR_SXS_XML_E_INVALID_VERSION 14072L -#define ERROR_SXS_XML_E_MISSINGEQUALS 14073L -#define ERROR_SXS_PROTECTION_RECOVERY_FAILED 14074L -#define ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT 14075L -#define ERROR_SXS_PROTECTION_CATALOG_NOT_VALID 14076L -#define ERROR_SXS_UNTRANSLATABLE_HRESULT 14077L -#define ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING 14078L -#define ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE 14079L -#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME 14080L -#define ERROR_IPSEC_QM_POLICY_EXISTS 13000L -#define ERROR_IPSEC_QM_POLICY_NOT_FOUND 13001L -#define ERROR_IPSEC_QM_POLICY_IN_USE 13002L -#define ERROR_IPSEC_MM_POLICY_EXISTS 13003L -#define ERROR_IPSEC_MM_POLICY_NOT_FOUND 13004L -#define ERROR_IPSEC_MM_POLICY_IN_USE 13005L -#define ERROR_IPSEC_MM_FILTER_EXISTS 13006L -#define ERROR_IPSEC_MM_FILTER_NOT_FOUND 13007L -#define ERROR_IPSEC_TRANSPORT_FILTER_EXISTS 13008L -#define ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND 13009L -#define ERROR_IPSEC_MM_AUTH_EXISTS 13010L -#define ERROR_IPSEC_MM_AUTH_NOT_FOUND 13011L -#define ERROR_IPSEC_MM_AUTH_IN_USE 13012L -#define ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND 13013L -#define ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND 13014L -#define ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND 13015L -#define ERROR_IPSEC_TUNNEL_FILTER_EXISTS 13016L -#define ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND 13017L -#define ERROR_IPSEC_MM_FILTER_PENDING_DELETION 13018L -#define ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION 13019L -#define ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION 13020L -#define ERROR_IPSEC_MM_POLICY_PENDING_DELETION 13021L -#define ERROR_IPSEC_MM_AUTH_PENDING_DELETION 13022L -#define ERROR_IPSEC_QM_POLICY_PENDING_DELETION 13023L -#define WARNING_IPSEC_MM_POLICY_PRUNED 13024L -#define WARNING_IPSEC_QM_POLICY_PRUNED 13025L -#define ERROR_IPSEC_IKE_NEG_STATUS_BEGIN 13800L -#define ERROR_IPSEC_IKE_AUTH_FAIL 13801L -#define ERROR_IPSEC_IKE_ATTRIB_FAIL 13802L -#define ERROR_IPSEC_IKE_NEGOTIATION_PENDING 13803L -#define ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR 13804L -#define ERROR_IPSEC_IKE_TIMED_OUT 13805L -#define ERROR_IPSEC_IKE_NO_CERT 13806L -#define ERROR_IPSEC_IKE_SA_DELETED 13807L -#define ERROR_IPSEC_IKE_SA_REAPED 13808L -#define ERROR_IPSEC_IKE_MM_ACQUIRE_DROP 13809L -#define ERROR_IPSEC_IKE_QM_ACQUIRE_DROP 13810L -#define ERROR_IPSEC_IKE_QUEUE_DROP_MM 13811L -#define ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM 13812L -#define ERROR_IPSEC_IKE_DROP_NO_RESPONSE 13813L -#define ERROR_IPSEC_IKE_MM_DELAY_DROP 13814L -#define ERROR_IPSEC_IKE_QM_DELAY_DROP 13815L -#define ERROR_IPSEC_IKE_ERROR 13816L -#define ERROR_IPSEC_IKE_CRL_FAILED 13817L -#define ERROR_IPSEC_IKE_INVALID_KEY_USAGE 13818L -#define ERROR_IPSEC_IKE_INVALID_CERT_TYPE 13819L -#define ERROR_IPSEC_IKE_NO_PRIVATE_KEY 13820L -#define ERROR_IPSEC_IKE_DH_FAIL 13822L -#define ERROR_IPSEC_IKE_INVALID_HEADER 13824L -#define ERROR_IPSEC_IKE_NO_POLICY 13825L -#define ERROR_IPSEC_IKE_INVALID_SIGNATURE 13826L -#define ERROR_IPSEC_IKE_KERBEROS_ERROR 13827L -#define ERROR_IPSEC_IKE_NO_PUBLIC_KEY 13828L -#define ERROR_IPSEC_IKE_PROCESS_ERR 13829L -#define ERROR_IPSEC_IKE_PROCESS_ERR_SA 13830L -#define ERROR_IPSEC_IKE_PROCESS_ERR_PROP 13831L -#define ERROR_IPSEC_IKE_PROCESS_ERR_TRANS 13832L -#define ERROR_IPSEC_IKE_PROCESS_ERR_KE 13833L -#define ERROR_IPSEC_IKE_PROCESS_ERR_ID 13834L -#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT 13835L -#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ 13836L -#define ERROR_IPSEC_IKE_PROCESS_ERR_HASH 13837L -#define ERROR_IPSEC_IKE_PROCESS_ERR_SIG 13838L -#define ERROR_IPSEC_IKE_PROCESS_ERR_NONCE 13839L -#define ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY 13840L -#define ERROR_IPSEC_IKE_PROCESS_ERR_DELETE 13841L -#define ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR 13842L -#define ERROR_IPSEC_IKE_INVALID_PAYLOAD 13843L -#define ERROR_IPSEC_IKE_LOAD_SOFT_SA 13844L -#define ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN 13845L -#define ERROR_IPSEC_IKE_INVALID_COOKIE 13846L -#define ERROR_IPSEC_IKE_NO_PEER_CERT 13847L -#define ERROR_IPSEC_IKE_PEER_CRL_FAILED 13848L -#define ERROR_IPSEC_IKE_POLICY_CHANGE 13849L -#define ERROR_IPSEC_IKE_NO_MM_POLICY 13850L -#define ERROR_IPSEC_IKE_NOTCBPRIV 13851L -#define ERROR_IPSEC_IKE_SECLOADFAIL 13852L -#define ERROR_IPSEC_IKE_FAILSSPINIT 13853L -#define ERROR_IPSEC_IKE_FAILQUERYSSP 13854L -#define ERROR_IPSEC_IKE_SRVACQFAIL 13855L -#define ERROR_IPSEC_IKE_SRVQUERYCRED 13856L -#define ERROR_IPSEC_IKE_GETSPIFAIL 13857L -#define ERROR_IPSEC_IKE_INVALID_FILTER 13858L -#define ERROR_IPSEC_IKE_OUT_OF_MEMORY 13859L -#define ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED 13860L -#define ERROR_IPSEC_IKE_INVALID_POLICY 13861L -#define ERROR_IPSEC_IKE_UNKNOWN_DOI 13862L -#define ERROR_IPSEC_IKE_INVALID_SITUATION 13863L -#define ERROR_IPSEC_IKE_DH_FAILURE 13864L -#define ERROR_IPSEC_IKE_INVALID_GROUP 13865L -#define ERROR_IPSEC_IKE_ENCRYPT 13866L -#define ERROR_IPSEC_IKE_DECRYPT 13867L -#define ERROR_IPSEC_IKE_POLICY_MATCH 13868L -#define ERROR_IPSEC_IKE_UNSUPPORTED_ID 13869L -#define ERROR_IPSEC_IKE_INVALID_HASH 13870L -#define ERROR_IPSEC_IKE_INVALID_HASH_ALG 13871L -#define ERROR_IPSEC_IKE_INVALID_HASH_SIZE 13872L -#define ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG 13873L -#define ERROR_IPSEC_IKE_INVALID_AUTH_ALG 13874L -#define ERROR_IPSEC_IKE_INVALID_SIG 13875L -#define ERROR_IPSEC_IKE_LOAD_FAILED 13876L -#define ERROR_IPSEC_IKE_RPC_DELETE 13877L -#define ERROR_IPSEC_IKE_BENIGN_REINIT 13878L -#define ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY 13879L -#define ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN 13881L -#define ERROR_IPSEC_IKE_MM_LIMIT 13882L -#define ERROR_IPSEC_IKE_NEGOTIATION_DISABLED 13883L -#define ERROR_IPSEC_IKE_NEG_STATUS_END 13884L -#define SEVERITY_SUCCESS 0 -#define SEVERITY_ERROR 1 -#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) -#define FAILED(hr) ((HRESULT)(hr) < 0) -#define IS_ERROR(Status) ((unsigned long)(Status) >> 31==SEVERITY_ERROR) -#define HRESULT_CODE(hr) ((hr) & 0xFFFF) -#define SCODE_CODE(sc) ((sc) & 0xFFFF) -#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) -#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1fff) -#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) -#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1) -#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) -#define MAKE_SCODE(sev,fac,code) ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) -#define FACILITY_NT_BIT 0x10000000 -#define __HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) -#ifdef INLINE_HRESULT_FROM_WIN32 -#ifndef _HRESULT_DEFINED -#define _HRESULT_DEFINED -typedef long HRESULT; -#endif -__CRT_INLINE HRESULT HRESULT_FROM_WIN32(long x) { return x <= 0 ? (HRESULT)x : (HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000);} -#else -#define HRESULT_FROM_WIN32(x) __HRESULT_FROM_WIN32(x) -#endif -#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT)) -#define GetScode(hr) ((SCODE) (hr)) -#define ResultFromScode(sc) ((HRESULT) (sc)) -#define PropagateResult(hrPrevious,scBase) ((HRESULT) scBase) -#ifdef RC_INVOKED -#define _HRESULT_TYPEDEF_(_sc) _sc -#else -#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc) -#endif -#define NOERROR 0 -#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL) -#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L) -#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL) -#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L) -#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L) -#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L) -#define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L) -#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L) -#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L) -#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L) -#define E_PENDING _HRESULT_TYPEDEF_(0x8000000AL) -#define CO_E_INIT_TLS _HRESULT_TYPEDEF_(0x80004006L) -#define CO_E_INIT_SHARED_ALLOCATOR _HRESULT_TYPEDEF_(0x80004007L) -#define CO_E_INIT_MEMORY_ALLOCATOR _HRESULT_TYPEDEF_(0x80004008L) -#define CO_E_INIT_CLASS_CACHE _HRESULT_TYPEDEF_(0x80004009L) -#define CO_E_INIT_RPC_CHANNEL _HRESULT_TYPEDEF_(0x8000400AL) -#define CO_E_INIT_TLS_SET_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400BL) -#define CO_E_INIT_TLS_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400CL) -#define CO_E_INIT_UNACCEPTED_USER_ALLOCATOR _HRESULT_TYPEDEF_(0x8000400DL) -#define CO_E_INIT_SCM_MUTEX_EXISTS _HRESULT_TYPEDEF_(0x8000400EL) -#define CO_E_INIT_SCM_FILE_MAPPING_EXISTS _HRESULT_TYPEDEF_(0x8000400FL) -#define CO_E_INIT_SCM_MAP_VIEW_OF_FILE _HRESULT_TYPEDEF_(0x80004010L) -#define CO_E_INIT_SCM_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80004011L) -#define CO_E_INIT_ONLY_SINGLE_THREADED _HRESULT_TYPEDEF_(0x80004012L) -#define CO_E_CANT_REMOTE _HRESULT_TYPEDEF_(0x80004013L) -#define CO_E_BAD_SERVER_NAME _HRESULT_TYPEDEF_(0x80004014L) -#define CO_E_WRONG_SERVER_IDENTITY _HRESULT_TYPEDEF_(0x80004015L) -#define CO_E_OLE1DDE_DISABLED _HRESULT_TYPEDEF_(0x80004016L) -#define CO_E_RUNAS_SYNTAX _HRESULT_TYPEDEF_(0x80004017L) -#define CO_E_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004018L) -#define CO_E_RUNAS_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004019L) -#define CO_E_RUNAS_LOGON_FAILURE _HRESULT_TYPEDEF_(0x8000401AL) -#define CO_E_LAUNCH_PERMSSION_DENIED _HRESULT_TYPEDEF_(0x8000401BL) -#define CO_E_START_SERVICE_FAILURE _HRESULT_TYPEDEF_(0x8000401CL) -#define CO_E_REMOTE_COMMUNICATION_FAILURE _HRESULT_TYPEDEF_(0x8000401DL) -#define CO_E_SERVER_START_TIMEOUT _HRESULT_TYPEDEF_(0x8000401EL) -#define CO_E_CLSREG_INCONSISTENT _HRESULT_TYPEDEF_(0x8000401FL) -#define CO_E_IIDREG_INCONSISTENT _HRESULT_TYPEDEF_(0x80004020L) -#define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L) -#define CO_E_RELOAD_DLL _HRESULT_TYPEDEF_(0x80004022L) -#define CO_E_MSI_ERROR _HRESULT_TYPEDEF_(0x80004023L) -#define CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT _HRESULT_TYPEDEF_(0x80004024L) -#define CO_E_SERVER_PAUSED _HRESULT_TYPEDEF_(0x80004025L) -#define CO_E_SERVER_NOT_PAUSED _HRESULT_TYPEDEF_(0x80004026L) -#define CO_E_CLASS_DISABLED _HRESULT_TYPEDEF_(0x80004027L) -#define CO_E_CLRNOTAVAILABLE _HRESULT_TYPEDEF_(0x80004028L) -#define CO_E_ASYNC_WORK_REJECTED _HRESULT_TYPEDEF_(0x80004029L) -#define CO_E_SERVER_INIT_TIMEOUT _HRESULT_TYPEDEF_(0x8000402AL) -#define CO_E_NO_SECCTX_IN_ACTIVATE _HRESULT_TYPEDEF_(0x8000402BL) -#define CO_E_TRACKER_CONFIG _HRESULT_TYPEDEF_(0x80004030L) -#define CO_E_THREADPOOL_CONFIG _HRESULT_TYPEDEF_(0x80004031L) -#define CO_E_SXS_CONFIG _HRESULT_TYPEDEF_(0x80004032L) -#define CO_E_MALFORMED_SPN _HRESULT_TYPEDEF_(0x80004033L) -#define S_OK ((HRESULT)0x00000000L) -#define S_FALSE ((HRESULT)0x00000001L) -#define OLE_E_FIRST ((HRESULT)0x80040000L) -#define OLE_E_LAST ((HRESULT)0x800400FFL) -#define OLE_S_FIRST ((HRESULT)0x00040000L) -#define OLE_S_LAST ((HRESULT)0x000400FFL) -#define OLE_E_OLEVERB _HRESULT_TYPEDEF_(0x80040000L) -#define OLE_E_ADVF _HRESULT_TYPEDEF_(0x80040001L) -#define OLE_E_ENUM_NOMORE _HRESULT_TYPEDEF_(0x80040002L) -#define OLE_E_ADVISENOTSUPPORTED _HRESULT_TYPEDEF_(0x80040003L) -#define OLE_E_NOCONNECTION _HRESULT_TYPEDEF_(0x80040004L) -#define OLE_E_NOTRUNNING _HRESULT_TYPEDEF_(0x80040005L) -#define OLE_E_NOCACHE _HRESULT_TYPEDEF_(0x80040006L) -#define OLE_E_BLANK _HRESULT_TYPEDEF_(0x80040007L) -#define OLE_E_CLASSDIFF _HRESULT_TYPEDEF_(0x80040008L) -#define OLE_E_CANT_GETMONIKER _HRESULT_TYPEDEF_(0x80040009L) -#define OLE_E_CANT_BINDTOSOURCE _HRESULT_TYPEDEF_(0x8004000AL) -#define OLE_E_STATIC _HRESULT_TYPEDEF_(0x8004000BL) -#define OLE_E_PROMPTSAVECANCELLED _HRESULT_TYPEDEF_(0x8004000CL) -#define OLE_E_INVALIDRECT _HRESULT_TYPEDEF_(0x8004000DL) -#define OLE_E_WRONGCOMPOBJ _HRESULT_TYPEDEF_(0x8004000EL) -#define OLE_E_INVALIDHWND _HRESULT_TYPEDEF_(0x8004000FL) -#define OLE_E_NOT_INPLACEACTIVE _HRESULT_TYPEDEF_(0x80040010L) -#define OLE_E_CANTCONVERT _HRESULT_TYPEDEF_(0x80040011L) -#define OLE_E_NOSTORAGE _HRESULT_TYPEDEF_(0x80040012L) -#define DV_E_FORMATETC _HRESULT_TYPEDEF_(0x80040064L) -#define DV_E_DVTARGETDEVICE _HRESULT_TYPEDEF_(0x80040065L) -#define DV_E_STGMEDIUM _HRESULT_TYPEDEF_(0x80040066L) -#define DV_E_STATDATA _HRESULT_TYPEDEF_(0x80040067L) -#define DV_E_LINDEX _HRESULT_TYPEDEF_(0x80040068L) -#define DV_E_TYMED _HRESULT_TYPEDEF_(0x80040069L) -#define DV_E_CLIPFORMAT _HRESULT_TYPEDEF_(0x8004006AL) -#define DV_E_DVASPECT _HRESULT_TYPEDEF_(0x8004006BL) -#define DV_E_DVTARGETDEVICE_SIZE _HRESULT_TYPEDEF_(0x8004006CL) -#define DV_E_NOIVIEWOBJECT _HRESULT_TYPEDEF_(0x8004006DL) -#define DRAGDROP_E_FIRST 0x80040100L -#define DRAGDROP_E_LAST 0x8004010FL -#define DRAGDROP_S_FIRST 0x00040100L -#define DRAGDROP_S_LAST 0x0004010FL -#define DRAGDROP_E_NOTREGISTERED _HRESULT_TYPEDEF_(0x80040100L) -#define DRAGDROP_E_ALREADYREGISTERED _HRESULT_TYPEDEF_(0x80040101L) -#define DRAGDROP_E_INVALIDHWND _HRESULT_TYPEDEF_(0x80040102L) -#define CLASSFACTORY_E_FIRST 0x80040110L -#define CLASSFACTORY_E_LAST 0x8004011FL -#define CLASSFACTORY_S_FIRST 0x00040110L -#define CLASSFACTORY_S_LAST 0x0004011FL -#define CLASS_E_NOAGGREGATION _HRESULT_TYPEDEF_(0x80040110L) -#define CLASS_E_CLASSNOTAVAILABLE _HRESULT_TYPEDEF_(0x80040111L) -#define CLASS_E_NOTLICENSED _HRESULT_TYPEDEF_(0x80040112L) -#define MARSHAL_E_FIRST 0x80040120L -#define MARSHAL_E_LAST 0x8004012FL -#define MARSHAL_S_FIRST 0x00040120L -#define MARSHAL_S_LAST 0x0004012FL -#define DATA_E_FIRST 0x80040130L -#define DATA_E_LAST 0x8004013FL -#define DATA_S_FIRST 0x00040130L -#define DATA_S_LAST 0x0004013FL -#define VIEW_E_FIRST 0x80040140L -#define VIEW_E_LAST 0x8004014FL -#define VIEW_S_FIRST 0x00040140L -#define VIEW_S_LAST 0x0004014FL -#define VIEW_E_DRAW _HRESULT_TYPEDEF_(0x80040140L) -#define REGDB_E_FIRST 0x80040150L -#define REGDB_E_LAST 0x8004015FL -#define REGDB_S_FIRST 0x00040150L -#define REGDB_S_LAST 0x0004015FL -#define REGDB_E_READREGDB _HRESULT_TYPEDEF_(0x80040150L) -#define REGDB_E_WRITEREGDB _HRESULT_TYPEDEF_(0x80040151L) -#define REGDB_E_KEYMISSING _HRESULT_TYPEDEF_(0x80040152L) -#define REGDB_E_INVALIDVALUE _HRESULT_TYPEDEF_(0x80040153L) -#define REGDB_E_CLASSNOTREG _HRESULT_TYPEDEF_(0x80040154L) -#define REGDB_E_IIDNOTREG _HRESULT_TYPEDEF_(0x80040155L) -#define REGDB_E_BADTHREADINGMODEL _HRESULT_TYPEDEF_(0x80040156L) -#define CAT_E_FIRST 0x80040160L -#define CAT_E_LAST 0x80040161L -#define CAT_E_CATIDNOEXIST _HRESULT_TYPEDEF_(0x80040160L) -#define CAT_E_NODESCRIPTION _HRESULT_TYPEDEF_(0x80040161L) -#define CS_E_FIRST 0x80040164L -#define CS_E_LAST 0x8004016FL -#define CS_E_PACKAGE_NOTFOUND _HRESULT_TYPEDEF_(0x80040164L) -#define CS_E_NOT_DELETABLE _HRESULT_TYPEDEF_(0x80040165L) -#define CS_E_CLASS_NOTFOUND _HRESULT_TYPEDEF_(0x80040166L) -#define CS_E_INVALID_VERSION _HRESULT_TYPEDEF_(0x80040167L) -#define CS_E_NO_CLASSSTORE _HRESULT_TYPEDEF_(0x80040168L) -#define CS_E_OBJECT_NOTFOUND _HRESULT_TYPEDEF_(0x80040169L) -#define CS_E_OBJECT_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x8004016AL) -#define CS_E_INVALID_PATH _HRESULT_TYPEDEF_(0x8004016BL) -#define CS_E_NETWORK_ERROR _HRESULT_TYPEDEF_(0x8004016CL) -#define CS_E_ADMIN_LIMIT_EXCEEDED _HRESULT_TYPEDEF_(0x8004016DL) -#define CS_E_SCHEMA_MISMATCH _HRESULT_TYPEDEF_(0x8004016EL) -#define CS_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x8004016FL) -#define CACHE_E_FIRST 0x80040170L -#define CACHE_E_LAST 0x8004017FL -#define CACHE_S_FIRST 0x00040170L -#define CACHE_S_LAST 0x0004017FL -#define CACHE_E_NOCACHE_UPDATED _HRESULT_TYPEDEF_(0x80040170L) -#define OLEOBJ_E_FIRST 0x80040180L -#define OLEOBJ_E_LAST 0x8004018FL -#define OLEOBJ_S_FIRST 0x00040180L -#define OLEOBJ_S_LAST 0x0004018FL -#define OLEOBJ_E_NOVERBS _HRESULT_TYPEDEF_(0x80040180L) -#define OLEOBJ_E_INVALIDVERB _HRESULT_TYPEDEF_(0x80040181L) -#define CLIENTSITE_E_FIRST 0x80040190L -#define CLIENTSITE_E_LAST 0x8004019FL -#define CLIENTSITE_S_FIRST 0x00040190L -#define CLIENTSITE_S_LAST 0x0004019FL -#define INPLACE_E_NOTUNDOABLE _HRESULT_TYPEDEF_(0x800401A0L) -#define INPLACE_E_NOTOOLSPACE _HRESULT_TYPEDEF_(0x800401A1L) -#define INPLACE_E_FIRST 0x800401A0L -#define INPLACE_E_LAST 0x800401AFL -#define INPLACE_S_FIRST 0x000401A0L -#define INPLACE_S_LAST 0x000401AFL -#define ENUM_E_FIRST 0x800401B0L -#define ENUM_E_LAST 0x800401BFL -#define ENUM_S_FIRST 0x000401B0L -#define ENUM_S_LAST 0x000401BFL -#define CONVERT10_E_FIRST 0x800401C0L -#define CONVERT10_E_LAST 0x800401CFL -#define CONVERT10_S_FIRST 0x000401C0L -#define CONVERT10_S_LAST 0x000401CFL -#define CONVERT10_E_OLESTREAM_GET _HRESULT_TYPEDEF_(0x800401C0L) -#define CONVERT10_E_OLESTREAM_PUT _HRESULT_TYPEDEF_(0x800401C1L) -#define CONVERT10_E_OLESTREAM_FMT _HRESULT_TYPEDEF_(0x800401C2L) -#define CONVERT10_E_OLESTREAM_BITMAP_TO_DIB _HRESULT_TYPEDEF_(0x800401C3L) -#define CONVERT10_E_STG_FMT _HRESULT_TYPEDEF_(0x800401C4L) -#define CONVERT10_E_STG_NO_STD_STREAM _HRESULT_TYPEDEF_(0x800401C5L) -#define CONVERT10_E_STG_DIB_TO_BITMAP _HRESULT_TYPEDEF_(0x800401C6L) -#define CLIPBRD_E_FIRST 0x800401D0L -#define CLIPBRD_E_LAST 0x800401DFL -#define CLIPBRD_S_FIRST 0x000401D0L -#define CLIPBRD_S_LAST 0x000401DFL -#define CLIPBRD_E_CANT_OPEN _HRESULT_TYPEDEF_(0x800401D0L) -#define CLIPBRD_E_CANT_EMPTY _HRESULT_TYPEDEF_(0x800401D1L) -#define CLIPBRD_E_CANT_SET _HRESULT_TYPEDEF_(0x800401D2L) -#define CLIPBRD_E_BAD_DATA _HRESULT_TYPEDEF_(0x800401D3L) -#define CLIPBRD_E_CANT_CLOSE _HRESULT_TYPEDEF_(0x800401D4L) -#define MK_E_FIRST 0x800401E0L -#define MK_E_LAST 0x800401EFL -#define MK_S_FIRST 0x000401E0L -#define MK_S_LAST 0x000401EFL -#define MK_E_CONNECTMANUALLY _HRESULT_TYPEDEF_(0x800401E0L) -#define MK_E_EXCEEDEDDEADLINE _HRESULT_TYPEDEF_(0x800401E1L) -#define MK_E_NEEDGENERIC _HRESULT_TYPEDEF_(0x800401E2L) -#define MK_E_UNAVAILABLE _HRESULT_TYPEDEF_(0x800401E3L) -#define MK_E_SYNTAX _HRESULT_TYPEDEF_(0x800401E4L) -#define MK_E_NOOBJECT _HRESULT_TYPEDEF_(0x800401E5L) -#define MK_E_INVALIDEXTENSION _HRESULT_TYPEDEF_(0x800401E6L) -#define MK_E_INTERMEDIATEINTERFACENOTSUPPORTED _HRESULT_TYPEDEF_(0x800401E7L) -#define MK_E_NOTBINDABLE _HRESULT_TYPEDEF_(0x800401E8L) -#define MK_E_NOTBOUND _HRESULT_TYPEDEF_(0x800401E9L) -#define MK_E_CANTOPENFILE _HRESULT_TYPEDEF_(0x800401EAL) -#define MK_E_MUSTBOTHERUSER _HRESULT_TYPEDEF_(0x800401EBL) -#define MK_E_NOINVERSE _HRESULT_TYPEDEF_(0x800401ECL) -#define MK_E_NOSTORAGE _HRESULT_TYPEDEF_(0x800401EDL) -#define MK_E_NOPREFIX _HRESULT_TYPEDEF_(0x800401EEL) -#define MK_E_ENUMERATION_FAILED _HRESULT_TYPEDEF_(0x800401EFL) -#define CO_E_FIRST 0x800401F0L -#define CO_E_LAST 0x800401FFL -#define CO_S_FIRST 0x000401F0L -#define CO_S_LAST 0x000401FFL -#define CO_E_NOTINITIALIZED _HRESULT_TYPEDEF_(0x800401F0L) -#define CO_E_ALREADYINITIALIZED _HRESULT_TYPEDEF_(0x800401F1L) -#define CO_E_CANTDETERMINECLASS _HRESULT_TYPEDEF_(0x800401F2L) -#define CO_E_CLASSSTRING _HRESULT_TYPEDEF_(0x800401F3L) -#define CO_E_IIDSTRING _HRESULT_TYPEDEF_(0x800401F4L) -#define CO_E_APPNOTFOUND _HRESULT_TYPEDEF_(0x800401F5L) -#define CO_E_APPSINGLEUSE _HRESULT_TYPEDEF_(0x800401F6L) -#define CO_E_ERRORINAPP _HRESULT_TYPEDEF_(0x800401F7L) -#define CO_E_DLLNOTFOUND _HRESULT_TYPEDEF_(0x800401F8L) -#define CO_E_ERRORINDLL _HRESULT_TYPEDEF_(0x800401F9L) -#define CO_E_WRONGOSFORAPP _HRESULT_TYPEDEF_(0x800401FAL) -#define CO_E_OBJNOTREG _HRESULT_TYPEDEF_(0x800401FBL) -#define CO_E_OBJISREG _HRESULT_TYPEDEF_(0x800401FCL) -#define CO_E_OBJNOTCONNECTED _HRESULT_TYPEDEF_(0x800401FDL) -#define CO_E_APPDIDNTREG _HRESULT_TYPEDEF_(0x800401FEL) -#define CO_E_RELEASED _HRESULT_TYPEDEF_(0x800401FFL) -#define EVENT_E_FIRST 0x80040200L -#define EVENT_E_LAST 0x8004021FL -#define EVENT_S_FIRST 0x00040200L -#define EVENT_S_LAST 0x0004021FL -#define EVENT_S_SOME_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x00040200L) -#define EVENT_E_ALL_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x80040201L) -#define EVENT_S_NOSUBSCRIBERS _HRESULT_TYPEDEF_(0x00040202L) -#define EVENT_E_QUERYSYNTAX _HRESULT_TYPEDEF_(0x80040203L) -#define EVENT_E_QUERYFIELD _HRESULT_TYPEDEF_(0x80040204L) -#define EVENT_E_INTERNALEXCEPTION _HRESULT_TYPEDEF_(0x80040205L) -#define EVENT_E_INTERNALERROR _HRESULT_TYPEDEF_(0x80040206L) -#define EVENT_E_INVALID_PER_USER_SID _HRESULT_TYPEDEF_(0x80040207L) -#define EVENT_E_USER_EXCEPTION _HRESULT_TYPEDEF_(0x80040208L) -#define EVENT_E_TOO_MANY_METHODS _HRESULT_TYPEDEF_(0x80040209L) -#define EVENT_E_MISSING_EVENTCLASS _HRESULT_TYPEDEF_(0x8004020AL) -#define EVENT_E_NOT_ALL_REMOVED _HRESULT_TYPEDEF_(0x8004020BL) -#define EVENT_E_COMPLUS_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004020CL) -#define EVENT_E_CANT_MODIFY_OR_DELETE_UNCONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020DL) -#define EVENT_E_CANT_MODIFY_OR_DELETE_CONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020EL) -#define EVENT_E_INVALID_EVENT_CLASS_PARTITION _HRESULT_TYPEDEF_(0x8004020FL) -#define EVENT_E_PER_USER_SID_NOT_LOGGED_ON _HRESULT_TYPEDEF_(0x80040210L) -#define XACT_E_FIRST 0x8004D000 -#define XACT_E_LAST 0x8004D029 -#define XACT_S_FIRST 0x0004D000 -#define XACT_S_LAST 0x0004D010 -#define XACT_E_ALREADYOTHERSINGLEPHASE _HRESULT_TYPEDEF_(0x8004D000L) -#define XACT_E_CANTRETAIN _HRESULT_TYPEDEF_(0x8004D001L) -#define XACT_E_COMMITFAILED _HRESULT_TYPEDEF_(0x8004D002L) -#define XACT_E_COMMITPREVENTED _HRESULT_TYPEDEF_(0x8004D003L) -#define XACT_E_HEURISTICABORT _HRESULT_TYPEDEF_(0x8004D004L) -#define XACT_E_HEURISTICCOMMIT _HRESULT_TYPEDEF_(0x8004D005L) -#define XACT_E_HEURISTICDAMAGE _HRESULT_TYPEDEF_(0x8004D006L) -#define XACT_E_HEURISTICDANGER _HRESULT_TYPEDEF_(0x8004D007L) -#define XACT_E_ISOLATIONLEVEL _HRESULT_TYPEDEF_(0x8004D008L) -#define XACT_E_NOASYNC _HRESULT_TYPEDEF_(0x8004D009L) -#define XACT_E_NOENLIST _HRESULT_TYPEDEF_(0x8004D00AL) -#define XACT_E_NOISORETAIN _HRESULT_TYPEDEF_(0x8004D00BL) -#define XACT_E_NORESOURCE _HRESULT_TYPEDEF_(0x8004D00CL) -#define XACT_E_NOTCURRENT _HRESULT_TYPEDEF_(0x8004D00DL) -#define XACT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004D00EL) -#define XACT_E_NOTSUPPORTED _HRESULT_TYPEDEF_(0x8004D00FL) -#define XACT_E_UNKNOWNRMGRID _HRESULT_TYPEDEF_(0x8004D010L) -#define XACT_E_WRONGSTATE _HRESULT_TYPEDEF_(0x8004D011L) -#define XACT_E_WRONGUOW _HRESULT_TYPEDEF_(0x8004D012L) -#define XACT_E_XTIONEXISTS _HRESULT_TYPEDEF_(0x8004D013L) -#define XACT_E_NOIMPORTOBJECT _HRESULT_TYPEDEF_(0x8004D014L) -#define XACT_E_INVALIDCOOKIE _HRESULT_TYPEDEF_(0x8004D015L) -#define XACT_E_INDOUBT _HRESULT_TYPEDEF_(0x8004D016L) -#define XACT_E_NOTIMEOUT _HRESULT_TYPEDEF_(0x8004D017L) -#define XACT_E_ALREADYINPROGRESS _HRESULT_TYPEDEF_(0x8004D018L) -#define XACT_E_ABORTED _HRESULT_TYPEDEF_(0x8004D019L) -#define XACT_E_LOGFULL _HRESULT_TYPEDEF_(0x8004D01AL) -#define XACT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D01BL) -#define XACT_E_CONNECTION_DOWN _HRESULT_TYPEDEF_(0x8004D01CL) -#define XACT_E_CONNECTION_DENIED _HRESULT_TYPEDEF_(0x8004D01DL) -#define XACT_E_REENLISTTIMEOUT _HRESULT_TYPEDEF_(0x8004D01EL) -#define XACT_E_TIP_CONNECT_FAILED _HRESULT_TYPEDEF_(0x8004D01FL) -#define XACT_E_TIP_PROTOCOL_ERROR _HRESULT_TYPEDEF_(0x8004D020L) -#define XACT_E_TIP_PULL_FAILED _HRESULT_TYPEDEF_(0x8004D021L) -#define XACT_E_DEST_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D022L) -#define XACT_E_TIP_DISABLED _HRESULT_TYPEDEF_(0x8004D023L) -#define XACT_E_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D024L) -#define XACT_E_PARTNER_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D025L) -#define XACT_E_XA_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D026L) -#define XACT_E_UNABLE_TO_READ_DTC_CONFIG _HRESULT_TYPEDEF_(0x8004D027L) -#define XACT_E_UNABLE_TO_LOAD_DTC_PROXY _HRESULT_TYPEDEF_(0x8004D028L) -#define XACT_E_ABORTING _HRESULT_TYPEDEF_(0x8004D029L) -#define XACT_E_CLERKNOTFOUND _HRESULT_TYPEDEF_(0x8004D080L) -#define XACT_E_CLERKEXISTS _HRESULT_TYPEDEF_(0x8004D081L) -#define XACT_E_RECOVERYINPROGRESS _HRESULT_TYPEDEF_(0x8004D082L) -#define XACT_E_TRANSACTIONCLOSED _HRESULT_TYPEDEF_(0x8004D083L) -#define XACT_E_INVALIDLSN _HRESULT_TYPEDEF_(0x8004D084L) -#define XACT_E_REPLAYREQUEST _HRESULT_TYPEDEF_(0x8004D085L) -#define XACT_S_ASYNC _HRESULT_TYPEDEF_(0x0004D000L) -#define XACT_S_DEFECT _HRESULT_TYPEDEF_(0x0004D001L) -#define XACT_S_READONLY _HRESULT_TYPEDEF_(0x0004D002L) -#define XACT_S_SOMENORETAIN _HRESULT_TYPEDEF_(0x0004D003L) -#define XACT_S_OKINFORM _HRESULT_TYPEDEF_(0x0004D004L) -#define XACT_S_MADECHANGESCONTENT _HRESULT_TYPEDEF_(0x0004D005L) -#define XACT_S_MADECHANGESINFORM _HRESULT_TYPEDEF_(0x0004D006L) -#define XACT_S_ALLNORETAIN _HRESULT_TYPEDEF_(0x0004D007L) -#define XACT_S_ABORTING _HRESULT_TYPEDEF_(0x0004D008L) -#define XACT_S_SINGLEPHASE _HRESULT_TYPEDEF_(0x0004D009L) -#define XACT_S_LOCALLY_OK _HRESULT_TYPEDEF_(0x0004D00AL) -#define XACT_S_LASTRESOURCEMANAGER _HRESULT_TYPEDEF_(0x0004D010L) -#define CONTEXT_E_FIRST 0x8004E000L -#define CONTEXT_E_LAST 0x8004E02FL -#define CONTEXT_S_FIRST 0x0004E000L -#define CONTEXT_S_LAST 0x0004E02FL -#define CONTEXT_E_ABORTED _HRESULT_TYPEDEF_(0x8004E002L) -#define CONTEXT_E_ABORTING _HRESULT_TYPEDEF_(0x8004E003L) -#define CONTEXT_E_NOCONTEXT _HRESULT_TYPEDEF_(0x8004E004L) -#define CONTEXT_E_WOULD_DEADLOCK _HRESULT_TYPEDEF_(0x8004E005L) -#define CONTEXT_E_SYNCH_TIMEOUT _HRESULT_TYPEDEF_(0x8004E006L) -#define CONTEXT_E_OLDREF _HRESULT_TYPEDEF_(0x8004E007L) -#define CONTEXT_E_ROLENOTFOUND _HRESULT_TYPEDEF_(0x8004E00CL) -#define CONTEXT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004E00FL) -#define CO_E_ACTIVATIONFAILED _HRESULT_TYPEDEF_(0x8004E021L) -#define CO_E_ACTIVATIONFAILED_EVENTLOGGED _HRESULT_TYPEDEF_(0x8004E022L) -#define CO_E_ACTIVATIONFAILED_CATALOGERROR _HRESULT_TYPEDEF_(0x8004E023L) -#define CO_E_ACTIVATIONFAILED_TIMEOUT _HRESULT_TYPEDEF_(0x8004E024L) -#define CO_E_INITIALIZATIONFAILED _HRESULT_TYPEDEF_(0x8004E025L) -#define CONTEXT_E_NOJIT _HRESULT_TYPEDEF_(0x8004E026L) -#define CONTEXT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004E027L) -#define CO_E_THREADINGMODEL_CHANGED _HRESULT_TYPEDEF_(0x8004E028L) -#define CO_E_NOIISINTRINSICS _HRESULT_TYPEDEF_(0x8004E029L) -#define CO_E_NOCOOKIES _HRESULT_TYPEDEF_(0x8004E02AL) -#define CO_E_DBERROR _HRESULT_TYPEDEF_(0x8004E02BL) -#define CO_E_NOTPOOLED _HRESULT_TYPEDEF_(0x8004E02CL) -#define CO_E_NOTCONSTRUCTED _HRESULT_TYPEDEF_(0x8004E02DL) -#define CO_E_NOSYNCHRONIZATION _HRESULT_TYPEDEF_(0x8004E02EL) -#define CO_E_ISOLEVELMISMATCH _HRESULT_TYPEDEF_(0x8004E02FL) -#define OLE_S_USEREG _HRESULT_TYPEDEF_(0x00040000L) -#define OLE_S_STATIC _HRESULT_TYPEDEF_(0x00040001L) -#define OLE_S_MAC_CLIPFORMAT _HRESULT_TYPEDEF_(0x00040002L) -#define DRAGDROP_S_DROP _HRESULT_TYPEDEF_(0x00040100L) -#define DRAGDROP_S_CANCEL _HRESULT_TYPEDEF_(0x00040101L) -#define DRAGDROP_S_USEDEFAULTCURSORS _HRESULT_TYPEDEF_(0x00040102L) -#define DATA_S_SAMEFORMATETC _HRESULT_TYPEDEF_(0x00040130L) -#define VIEW_S_ALREADY_FROZEN _HRESULT_TYPEDEF_(0x00040140L) -#define CACHE_S_FORMATETC_NOTSUPPORTED _HRESULT_TYPEDEF_(0x00040170L) -#define CACHE_S_SAMECACHE _HRESULT_TYPEDEF_(0x00040171L) -#define CACHE_S_SOMECACHES_NOTUPDATED _HRESULT_TYPEDEF_(0x00040172L) -#define OLEOBJ_S_INVALIDVERB _HRESULT_TYPEDEF_(0x00040180L) -#define OLEOBJ_S_CANNOT_DOVERB_NOW _HRESULT_TYPEDEF_(0x00040181L) -#define OLEOBJ_S_INVALIDHWND _HRESULT_TYPEDEF_(0x00040182L) -#define INPLACE_S_TRUNCATED _HRESULT_TYPEDEF_(0x000401A0L) -#define CONVERT10_S_NO_PRESENTATION _HRESULT_TYPEDEF_(0x000401C0L) -#define MK_S_REDUCED_TO_SELF _HRESULT_TYPEDEF_(0x000401E2L) -#define MK_S_ME _HRESULT_TYPEDEF_(0x000401E4L) -#define MK_S_HIM _HRESULT_TYPEDEF_(0x000401E5L) -#define MK_S_US _HRESULT_TYPEDEF_(0x000401E6L) -#define MK_S_MONIKERALREADYREGISTERED _HRESULT_TYPEDEF_(0x000401E7L) -#define SCHED_S_TASK_READY _HRESULT_TYPEDEF_(0x00041300L) -#define SCHED_S_TASK_RUNNING _HRESULT_TYPEDEF_(0x00041301L) -#define SCHED_S_TASK_DISABLED _HRESULT_TYPEDEF_(0x00041302L) -#define SCHED_S_TASK_HAS_NOT_RUN _HRESULT_TYPEDEF_(0x00041303L) -#define SCHED_S_TASK_NO_MORE_RUNS _HRESULT_TYPEDEF_(0x00041304L) -#define SCHED_S_TASK_NOT_SCHEDULED _HRESULT_TYPEDEF_(0x00041305L) -#define SCHED_S_TASK_TERMINATED _HRESULT_TYPEDEF_(0x00041306L) -#define SCHED_S_TASK_NO_VALID_TRIGGERS _HRESULT_TYPEDEF_(0x00041307L) -#define SCHED_S_EVENT_TRIGGER _HRESULT_TYPEDEF_(0x00041308L) -#define SCHED_E_TRIGGER_NOT_FOUND _HRESULT_TYPEDEF_(0x80041309L) -#define SCHED_E_TASK_NOT_READY _HRESULT_TYPEDEF_(0x8004130AL) -#define SCHED_E_TASK_NOT_RUNNING _HRESULT_TYPEDEF_(0x8004130BL) -#define SCHED_E_SERVICE_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004130CL) -#define SCHED_E_CANNOT_OPEN_TASK _HRESULT_TYPEDEF_(0x8004130DL) -#define SCHED_E_INVALID_TASK _HRESULT_TYPEDEF_(0x8004130EL) -#define SCHED_E_ACCOUNT_INFORMATION_NOT_SET _HRESULT_TYPEDEF_(0x8004130FL) -#define SCHED_E_ACCOUNT_NAME_NOT_FOUND _HRESULT_TYPEDEF_(0x80041310L) -#define SCHED_E_ACCOUNT_DBASE_CORRUPT _HRESULT_TYPEDEF_(0x80041311L) -#define SCHED_E_NO_SECURITY_SERVICES _HRESULT_TYPEDEF_(0x80041312L) -#define SCHED_E_UNKNOWN_OBJECT_VERSION _HRESULT_TYPEDEF_(0x80041313L) -#define SCHED_E_UNSUPPORTED_ACCOUNT_OPTION _HRESULT_TYPEDEF_(0x80041314L) -#define SCHED_E_SERVICE_NOT_RUNNING _HRESULT_TYPEDEF_(0x80041315L) -#define CO_E_CLASS_CREATE_FAILED _HRESULT_TYPEDEF_(0x80080001L) -#define CO_E_SCM_ERROR _HRESULT_TYPEDEF_(0x80080002L) -#define CO_E_SCM_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080003L) -#define CO_E_BAD_PATH _HRESULT_TYPEDEF_(0x80080004L) -#define CO_E_SERVER_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80080005L) -#define CO_E_OBJSRV_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080006L) -#define MK_E_NO_NORMALIZED _HRESULT_TYPEDEF_(0x80080007L) -#define CO_E_SERVER_STOPPING _HRESULT_TYPEDEF_(0x80080008L) -#define MEM_E_INVALID_ROOT _HRESULT_TYPEDEF_(0x80080009L) -#define MEM_E_INVALID_LINK _HRESULT_TYPEDEF_(0x80080010L) -#define MEM_E_INVALID_SIZE _HRESULT_TYPEDEF_(0x80080011L) -#define CO_S_NOTALLINTERFACES _HRESULT_TYPEDEF_(0x00080012L) -#define CO_S_MACHINENAMENOTFOUND _HRESULT_TYPEDEF_(0x00080013L) -#define DISP_E_UNKNOWNINTERFACE _HRESULT_TYPEDEF_(0x80020001L) -#define DISP_E_MEMBERNOTFOUND _HRESULT_TYPEDEF_(0x80020003L) -#define DISP_E_PARAMNOTFOUND _HRESULT_TYPEDEF_(0x80020004L) -#define DISP_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80020005L) -#define DISP_E_UNKNOWNNAME _HRESULT_TYPEDEF_(0x80020006L) -#define DISP_E_NONAMEDARGS _HRESULT_TYPEDEF_(0x80020007L) -#define DISP_E_BADVARTYPE _HRESULT_TYPEDEF_(0x80020008L) -#define DISP_E_EXCEPTION _HRESULT_TYPEDEF_(0x80020009L) -#define DISP_E_OVERFLOW _HRESULT_TYPEDEF_(0x8002000AL) -#define DISP_E_BADINDEX _HRESULT_TYPEDEF_(0x8002000BL) -#define DISP_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002000CL) -#define DISP_E_ARRAYISLOCKED _HRESULT_TYPEDEF_(0x8002000DL) -#define DISP_E_BADPARAMCOUNT _HRESULT_TYPEDEF_(0x8002000EL) -#define DISP_E_PARAMNOTOPTIONAL _HRESULT_TYPEDEF_(0x8002000FL) -#define DISP_E_BADCALLEE _HRESULT_TYPEDEF_(0x80020010L) -#define DISP_E_NOTACOLLECTION _HRESULT_TYPEDEF_(0x80020011L) -#define DISP_E_DIVBYZERO _HRESULT_TYPEDEF_(0x80020012L) -#define DISP_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80020013L) -#define TYPE_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80028016L) -#define TYPE_E_FIELDNOTFOUND _HRESULT_TYPEDEF_(0x80028017L) -#define TYPE_E_INVDATAREAD _HRESULT_TYPEDEF_(0x80028018L) -#define TYPE_E_UNSUPFORMAT _HRESULT_TYPEDEF_(0x80028019L) -#define TYPE_E_REGISTRYACCESS _HRESULT_TYPEDEF_(0x8002801CL) -#define TYPE_E_LIBNOTREGISTERED _HRESULT_TYPEDEF_(0x8002801DL) -#define TYPE_E_UNDEFINEDTYPE _HRESULT_TYPEDEF_(0x80028027L) -#define TYPE_E_QUALIFIEDNAMEDISALLOWED _HRESULT_TYPEDEF_(0x80028028L) -#define TYPE_E_INVALIDSTATE _HRESULT_TYPEDEF_(0x80028029L) -#define TYPE_E_WRONGTYPEKIND _HRESULT_TYPEDEF_(0x8002802AL) -#define TYPE_E_ELEMENTNOTFOUND _HRESULT_TYPEDEF_(0x8002802BL) -#define TYPE_E_AMBIGUOUSNAME _HRESULT_TYPEDEF_(0x8002802CL) -#define TYPE_E_NAMECONFLICT _HRESULT_TYPEDEF_(0x8002802DL) -#define TYPE_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002802EL) -#define TYPE_E_DLLFUNCTIONNOTFOUND _HRESULT_TYPEDEF_(0x8002802FL) -#define TYPE_E_BADMODULEKIND _HRESULT_TYPEDEF_(0x800288BDL) -#define TYPE_E_SIZETOOBIG _HRESULT_TYPEDEF_(0x800288C5L) -#define TYPE_E_DUPLICATEID _HRESULT_TYPEDEF_(0x800288C6L) -#define TYPE_E_INVALIDID _HRESULT_TYPEDEF_(0x800288CFL) -#define TYPE_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80028CA0L) -#define TYPE_E_OUTOFBOUNDS _HRESULT_TYPEDEF_(0x80028CA1L) -#define TYPE_E_IOERROR _HRESULT_TYPEDEF_(0x80028CA2L) -#define TYPE_E_CANTCREATETMPFILE _HRESULT_TYPEDEF_(0x80028CA3L) -#define TYPE_E_CANTLOADLIBRARY _HRESULT_TYPEDEF_(0x80029C4AL) -#define TYPE_E_INCONSISTENTPROPFUNCS _HRESULT_TYPEDEF_(0x80029C83L) -#define TYPE_E_CIRCULARTYPE _HRESULT_TYPEDEF_(0x80029C84L) -#define STG_E_INVALIDFUNCTION _HRESULT_TYPEDEF_(0x80030001L) -#define STG_E_FILENOTFOUND _HRESULT_TYPEDEF_(0x80030002L) -#define STG_E_PATHNOTFOUND _HRESULT_TYPEDEF_(0x80030003L) -#define STG_E_TOOMANYOPENFILES _HRESULT_TYPEDEF_(0x80030004L) -#define STG_E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80030005L) -#define STG_E_INVALIDHANDLE _HRESULT_TYPEDEF_(0x80030006L) -#define STG_E_INSUFFICIENTMEMORY _HRESULT_TYPEDEF_(0x80030008L) -#define STG_E_INVALIDPOINTER _HRESULT_TYPEDEF_(0x80030009L) -#define STG_E_NOMOREFILES _HRESULT_TYPEDEF_(0x80030012L) -#define STG_E_DISKISWRITEPROTECTED _HRESULT_TYPEDEF_(0x80030013L) -#define STG_E_SEEKERROR _HRESULT_TYPEDEF_(0x80030019L) -#define STG_E_WRITEFAULT _HRESULT_TYPEDEF_(0x8003001DL) -#define STG_E_READFAULT _HRESULT_TYPEDEF_(0x8003001EL) -#define STG_E_SHAREVIOLATION _HRESULT_TYPEDEF_(0x80030020L) -#define STG_E_LOCKVIOLATION _HRESULT_TYPEDEF_(0x80030021L) -#define STG_E_FILEALREADYEXISTS _HRESULT_TYPEDEF_(0x80030050L) -#define STG_E_INVALIDPARAMETER _HRESULT_TYPEDEF_(0x80030057L) -#define STG_E_MEDIUMFULL _HRESULT_TYPEDEF_(0x80030070L) -#define STG_E_PROPSETMISMATCHED _HRESULT_TYPEDEF_(0x800300F0L) -#define STG_E_ABNORMALAPIEXIT _HRESULT_TYPEDEF_(0x800300FAL) -#define STG_E_INVALIDHEADER _HRESULT_TYPEDEF_(0x800300FBL) -#define STG_E_INVALIDNAME _HRESULT_TYPEDEF_(0x800300FCL) -#define STG_E_UNKNOWN _HRESULT_TYPEDEF_(0x800300FDL) -#define STG_E_UNIMPLEMENTEDFUNCTION _HRESULT_TYPEDEF_(0x800300FEL) -#define STG_E_INVALIDFLAG _HRESULT_TYPEDEF_(0x800300FFL) -#define STG_E_INUSE _HRESULT_TYPEDEF_(0x80030100L) -#define STG_E_NOTCURRENT _HRESULT_TYPEDEF_(0x80030101L) -#define STG_E_REVERTED _HRESULT_TYPEDEF_(0x80030102L) -#define STG_E_CANTSAVE _HRESULT_TYPEDEF_(0x80030103L) -#define STG_E_OLDFORMAT _HRESULT_TYPEDEF_(0x80030104L) -#define STG_E_OLDDLL _HRESULT_TYPEDEF_(0x80030105L) -#define STG_E_SHAREREQUIRED _HRESULT_TYPEDEF_(0x80030106L) -#define STG_E_NOTFILEBASEDSTORAGE _HRESULT_TYPEDEF_(0x80030107L) -#define STG_E_EXTANTMARSHALLINGS _HRESULT_TYPEDEF_(0x80030108L) -#define STG_E_DOCFILECORRUPT _HRESULT_TYPEDEF_(0x80030109L) -#define STG_E_BADBASEADDRESS _HRESULT_TYPEDEF_(0x80030110L) -#define STG_E_DOCFILETOOLARGE _HRESULT_TYPEDEF_(0x80030111L) -#define STG_E_NOTSIMPLEFORMAT _HRESULT_TYPEDEF_(0x80030112L) -#define STG_E_INCOMPLETE _HRESULT_TYPEDEF_(0x80030201L) -#define STG_E_TERMINATED _HRESULT_TYPEDEF_(0x80030202L) -#define STG_S_CONVERTED _HRESULT_TYPEDEF_(0x00030200L) -#define STG_S_BLOCK _HRESULT_TYPEDEF_(0x00030201L) -#define STG_S_RETRYNOW _HRESULT_TYPEDEF_(0x00030202L) -#define STG_S_MONITORING _HRESULT_TYPEDEF_(0x00030203L) -#define STG_S_MULTIPLEOPENS _HRESULT_TYPEDEF_(0x00030204L) -#define STG_S_CONSOLIDATIONFAILED _HRESULT_TYPEDEF_(0x00030205L) -#define STG_S_CANNOTCONSOLIDATE _HRESULT_TYPEDEF_(0x00030206L) -#define STG_E_STATUS_COPY_PROTECTION_FAILURE _HRESULT_TYPEDEF_(0x80030305L) -#define STG_E_CSS_AUTHENTICATION_FAILURE _HRESULT_TYPEDEF_(0x80030306L) -#define STG_E_CSS_KEY_NOT_PRESENT _HRESULT_TYPEDEF_(0x80030307L) -#define STG_E_CSS_KEY_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x80030308L) -#define STG_E_CSS_SCRAMBLED_SECTOR _HRESULT_TYPEDEF_(0x80030309L) -#define STG_E_CSS_REGION_MISMATCH _HRESULT_TYPEDEF_(0x8003030AL) -#define STG_E_RESETS_EXHAUSTED _HRESULT_TYPEDEF_(0x8003030BL) -#define RPC_E_CALL_REJECTED _HRESULT_TYPEDEF_(0x80010001L) -#define RPC_E_CALL_CANCELED _HRESULT_TYPEDEF_(0x80010002L) -#define RPC_E_CANTPOST_INSENDCALL _HRESULT_TYPEDEF_(0x80010003L) -#define RPC_E_CANTCALLOUT_INASYNCCALL _HRESULT_TYPEDEF_(0x80010004L) -#define RPC_E_CANTCALLOUT_INEXTERNALCALL _HRESULT_TYPEDEF_(0x80010005L) -#define RPC_E_CONNECTION_TERMINATED _HRESULT_TYPEDEF_(0x80010006L) -#define RPC_E_SERVER_DIED _HRESULT_TYPEDEF_(0x80010007L) -#define RPC_E_CLIENT_DIED _HRESULT_TYPEDEF_(0x80010008L) -#define RPC_E_INVALID_DATAPACKET _HRESULT_TYPEDEF_(0x80010009L) -#define RPC_E_CANTTRANSMIT_CALL _HRESULT_TYPEDEF_(0x8001000AL) -#define RPC_E_CLIENT_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000BL) -#define RPC_E_CLIENT_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000CL) -#define RPC_E_SERVER_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000DL) -#define RPC_E_SERVER_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000EL) -#define RPC_E_INVALID_DATA _HRESULT_TYPEDEF_(0x8001000FL) -#define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L) -#define RPC_E_CANTCALLOUT_AGAIN _HRESULT_TYPEDEF_(0x80010011L) -#define RPC_E_SERVER_DIED_DNE _HRESULT_TYPEDEF_(0x80010012L) -#define RPC_E_SYS_CALL_FAILED _HRESULT_TYPEDEF_(0x80010100L) -#define RPC_E_OUT_OF_RESOURCES _HRESULT_TYPEDEF_(0x80010101L) -#define RPC_E_ATTEMPTED_MULTITHREAD _HRESULT_TYPEDEF_(0x80010102L) -#define RPC_E_NOT_REGISTERED _HRESULT_TYPEDEF_(0x80010103L) -#define RPC_E_FAULT _HRESULT_TYPEDEF_(0x80010104L) -#define RPC_E_SERVERFAULT _HRESULT_TYPEDEF_(0x80010105L) -#define RPC_E_CHANGED_MODE _HRESULT_TYPEDEF_(0x80010106L) -#define RPC_E_INVALIDMETHOD _HRESULT_TYPEDEF_(0x80010107L) -#define RPC_E_DISCONNECTED _HRESULT_TYPEDEF_(0x80010108L) -#define RPC_E_RETRY _HRESULT_TYPEDEF_(0x80010109L) -#define RPC_E_SERVERCALL_RETRYLATER _HRESULT_TYPEDEF_(0x8001010AL) -#define RPC_E_SERVERCALL_REJECTED _HRESULT_TYPEDEF_(0x8001010BL) -#define RPC_E_INVALID_CALLDATA _HRESULT_TYPEDEF_(0x8001010CL) -#define RPC_E_CANTCALLOUT_ININPUTSYNCCALL _HRESULT_TYPEDEF_(0x8001010DL) -#define RPC_E_WRONG_THREAD _HRESULT_TYPEDEF_(0x8001010EL) -#define RPC_E_THREAD_NOT_INIT _HRESULT_TYPEDEF_(0x8001010FL) -#define RPC_E_VERSION_MISMATCH _HRESULT_TYPEDEF_(0x80010110L) -#define RPC_E_INVALID_HEADER _HRESULT_TYPEDEF_(0x80010111L) -#define RPC_E_INVALID_EXTENSION _HRESULT_TYPEDEF_(0x80010112L) -#define RPC_E_INVALID_IPID _HRESULT_TYPEDEF_(0x80010113L) -#define RPC_E_INVALID_OBJECT _HRESULT_TYPEDEF_(0x80010114L) -#define RPC_S_CALLPENDING _HRESULT_TYPEDEF_(0x80010115L) -#define RPC_S_WAITONTIMER _HRESULT_TYPEDEF_(0x80010116L) -#define RPC_E_CALL_COMPLETE _HRESULT_TYPEDEF_(0x80010117L) -#define RPC_E_UNSECURE_CALL _HRESULT_TYPEDEF_(0x80010118L) -#define RPC_E_TOO_LATE _HRESULT_TYPEDEF_(0x80010119L) -#define RPC_E_NO_GOOD_SECURITY_PACKAGES _HRESULT_TYPEDEF_(0x8001011AL) -#define RPC_E_ACCESS_DENIED _HRESULT_TYPEDEF_(0x8001011BL) -#define RPC_E_REMOTE_DISABLED _HRESULT_TYPEDEF_(0x8001011CL) -#define RPC_E_INVALID_OBJREF _HRESULT_TYPEDEF_(0x8001011DL) -#define RPC_E_NO_CONTEXT _HRESULT_TYPEDEF_(0x8001011EL) -#define RPC_E_TIMEOUT _HRESULT_TYPEDEF_(0x8001011FL) -#define RPC_E_NO_SYNC _HRESULT_TYPEDEF_(0x80010120L) -#define RPC_E_FULLSIC_REQUIRED _HRESULT_TYPEDEF_(0x80010121L) -#define RPC_E_INVALID_STD_NAME _HRESULT_TYPEDEF_(0x80010122L) -#define CO_E_FAILEDTOIMPERSONATE _HRESULT_TYPEDEF_(0x80010123L) -#define CO_E_FAILEDTOGETSECCTX _HRESULT_TYPEDEF_(0x80010124L) -#define CO_E_FAILEDTOOPENTHREADTOKEN _HRESULT_TYPEDEF_(0x80010125L) -#define CO_E_FAILEDTOGETTOKENINFO _HRESULT_TYPEDEF_(0x80010126L) -#define CO_E_TRUSTEEDOESNTMATCHCLIENT _HRESULT_TYPEDEF_(0x80010127L) -#define CO_E_FAILEDTOQUERYCLIENTBLANKET _HRESULT_TYPEDEF_(0x80010128L) -#define CO_E_FAILEDTOSETDACL _HRESULT_TYPEDEF_(0x80010129L) -#define CO_E_ACCESSCHECKFAILED _HRESULT_TYPEDEF_(0x8001012AL) -#define CO_E_NETACCESSAPIFAILED _HRESULT_TYPEDEF_(0x8001012BL) -#define CO_E_WRONGTRUSTEENAMESYNTAX _HRESULT_TYPEDEF_(0x8001012CL) -#define CO_E_INVALIDSID _HRESULT_TYPEDEF_(0x8001012DL) -#define CO_E_CONVERSIONFAILED _HRESULT_TYPEDEF_(0x8001012EL) -#define CO_E_NOMATCHINGSIDFOUND _HRESULT_TYPEDEF_(0x8001012FL) -#define CO_E_LOOKUPACCSIDFAILED _HRESULT_TYPEDEF_(0x80010130L) -#define CO_E_NOMATCHINGNAMEFOUND _HRESULT_TYPEDEF_(0x80010131L) -#define CO_E_LOOKUPACCNAMEFAILED _HRESULT_TYPEDEF_(0x80010132L) -#define CO_E_SETSERLHNDLFAILED _HRESULT_TYPEDEF_(0x80010133L) -#define CO_E_FAILEDTOGETWINDIR _HRESULT_TYPEDEF_(0x80010134L) -#define CO_E_PATHTOOLONG _HRESULT_TYPEDEF_(0x80010135L) -#define CO_E_FAILEDTOGENUUID _HRESULT_TYPEDEF_(0x80010136L) -#define CO_E_FAILEDTOCREATEFILE _HRESULT_TYPEDEF_(0x80010137L) -#define CO_E_FAILEDTOCLOSEHANDLE _HRESULT_TYPEDEF_(0x80010138L) -#define CO_E_EXCEEDSYSACLLIMIT _HRESULT_TYPEDEF_(0x80010139L) -#define CO_E_ACESINWRONGORDER _HRESULT_TYPEDEF_(0x8001013AL) -#define CO_E_INCOMPATIBLESTREAMVERSION _HRESULT_TYPEDEF_(0x8001013BL) -#define CO_E_FAILEDTOOPENPROCESSTOKEN _HRESULT_TYPEDEF_(0x8001013CL) -#define CO_E_DECODEFAILED _HRESULT_TYPEDEF_(0x8001013DL) -#define CO_E_ACNOTINITIALIZED _HRESULT_TYPEDEF_(0x8001013FL) -#define CO_E_CANCEL_DISABLED _HRESULT_TYPEDEF_(0x80010140L) -#define RPC_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8001FFFFL) -#define ERROR_AUDITING_DISABLED _HRESULT_TYPEDEF_(0xC0090001L) -#define ERROR_ALL_SIDS_FILTERED _HRESULT_TYPEDEF_(0xC0090002L) -#define NTE_BAD_UID _HRESULT_TYPEDEF_(0x80090001L) -#define NTE_BAD_HASH _HRESULT_TYPEDEF_(0x80090002L) -#define NTE_BAD_KEY _HRESULT_TYPEDEF_(0x80090003L) -#define NTE_BAD_LEN _HRESULT_TYPEDEF_(0x80090004L) -#define NTE_BAD_DATA _HRESULT_TYPEDEF_(0x80090005L) -#define NTE_BAD_SIGNATURE _HRESULT_TYPEDEF_(0x80090006L) -#define NTE_BAD_VER _HRESULT_TYPEDEF_(0x80090007L) -#define NTE_BAD_ALGID _HRESULT_TYPEDEF_(0x80090008L) -#define NTE_BAD_FLAGS _HRESULT_TYPEDEF_(0x80090009L) -#define NTE_BAD_TYPE _HRESULT_TYPEDEF_(0x8009000AL) -#define NTE_BAD_KEY_STATE _HRESULT_TYPEDEF_(0x8009000BL) -#define NTE_BAD_HASH_STATE _HRESULT_TYPEDEF_(0x8009000CL) -#define NTE_NO_KEY _HRESULT_TYPEDEF_(0x8009000DL) -#define NTE_NO_MEMORY _HRESULT_TYPEDEF_(0x8009000EL) -#define NTE_EXISTS _HRESULT_TYPEDEF_(0x8009000FL) -#define NTE_PERM _HRESULT_TYPEDEF_(0x80090010L) -#define NTE_NOT_FOUND _HRESULT_TYPEDEF_(0x80090011L) -#define NTE_DOUBLE_ENCRYPT _HRESULT_TYPEDEF_(0x80090012L) -#define NTE_BAD_PROVIDER _HRESULT_TYPEDEF_(0x80090013L) -#define NTE_BAD_PROV_TYPE _HRESULT_TYPEDEF_(0x80090014L) -#define NTE_BAD_PUBLIC_KEY _HRESULT_TYPEDEF_(0x80090015L) -#define NTE_BAD_KEYSET _HRESULT_TYPEDEF_(0x80090016L) -#define NTE_PROV_TYPE_NOT_DEF _HRESULT_TYPEDEF_(0x80090017L) -#define NTE_PROV_TYPE_ENTRY_BAD _HRESULT_TYPEDEF_(0x80090018L) -#define NTE_KEYSET_NOT_DEF _HRESULT_TYPEDEF_(0x80090019L) -#define NTE_KEYSET_ENTRY_BAD _HRESULT_TYPEDEF_(0x8009001AL) -#define NTE_PROV_TYPE_NO_MATCH _HRESULT_TYPEDEF_(0x8009001BL) -#define NTE_SIGNATURE_FILE_BAD _HRESULT_TYPEDEF_(0x8009001CL) -#define NTE_PROVIDER_DLL_FAIL _HRESULT_TYPEDEF_(0x8009001DL) -#define NTE_PROV_DLL_NOT_FOUND _HRESULT_TYPEDEF_(0x8009001EL) -#define NTE_BAD_KEYSET_PARAM _HRESULT_TYPEDEF_(0x8009001FL) -#define NTE_FAIL _HRESULT_TYPEDEF_(0x80090020L) -#define NTE_SYS_ERR _HRESULT_TYPEDEF_(0x80090021L) -#define NTE_SILENT_CONTEXT _HRESULT_TYPEDEF_(0x80090022L) -#define NTE_TOKEN_KEYSET_STORAGE_FULL _HRESULT_TYPEDEF_(0x80090023L) -#define NTE_TEMPORARY_PROFILE _HRESULT_TYPEDEF_(0x80090024L) -#define NTE_FIXEDPARAMETER _HRESULT_TYPEDEF_(0x80090025L) -#define SEC_E_INSUFFICIENT_MEMORY _HRESULT_TYPEDEF_(0x80090300L) -#define SEC_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80090301L) -#define SEC_E_UNSUPPORTED_FUNCTION _HRESULT_TYPEDEF_(0x80090302L) -#define SEC_E_TARGET_UNKNOWN _HRESULT_TYPEDEF_(0x80090303L) -#define SEC_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80090304L) -#define SEC_E_SECPKG_NOT_FOUND _HRESULT_TYPEDEF_(0x80090305L) -#define SEC_E_NOT_OWNER _HRESULT_TYPEDEF_(0x80090306L) -#define SEC_E_CANNOT_INSTALL _HRESULT_TYPEDEF_(0x80090307L) -#define SEC_E_INVALID_TOKEN _HRESULT_TYPEDEF_(0x80090308L) -#define SEC_E_CANNOT_PACK _HRESULT_TYPEDEF_(0x80090309L) -#define SEC_E_QOP_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009030AL) -#define SEC_E_NO_IMPERSONATION _HRESULT_TYPEDEF_(0x8009030BL) -#define SEC_E_LOGON_DENIED _HRESULT_TYPEDEF_(0x8009030CL) -#define SEC_E_UNKNOWN_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030DL) -#define SEC_E_NO_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030EL) -#define SEC_E_MESSAGE_ALTERED _HRESULT_TYPEDEF_(0x8009030FL) -#define SEC_E_OUT_OF_SEQUENCE _HRESULT_TYPEDEF_(0x80090310L) -#define SEC_E_NO_AUTHENTICATING_AUTHORITY _HRESULT_TYPEDEF_(0x80090311L) -#define SEC_I_CONTINUE_NEEDED _HRESULT_TYPEDEF_(0x00090312L) -#define SEC_I_COMPLETE_NEEDED _HRESULT_TYPEDEF_(0x00090313L) -#define SEC_I_COMPLETE_AND_CONTINUE _HRESULT_TYPEDEF_(0x00090314L) -#define SEC_I_LOCAL_LOGON _HRESULT_TYPEDEF_(0x00090315L) -#define SEC_E_BAD_PKGID _HRESULT_TYPEDEF_(0x80090316L) -#define SEC_E_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x80090317L) -#define SEC_I_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x00090317L) -#define SEC_E_INCOMPLETE_MESSAGE _HRESULT_TYPEDEF_(0x80090318L) -#define SEC_E_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x80090320L) -#define SEC_E_BUFFER_TOO_SMALL _HRESULT_TYPEDEF_(0x80090321L) -#define SEC_I_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x00090320L) -#define SEC_I_RENEGOTIATE _HRESULT_TYPEDEF_(0x00090321L) -#define SEC_E_WRONG_PRINCIPAL _HRESULT_TYPEDEF_(0x80090322L) -#define SEC_I_NO_LSA_CONTEXT _HRESULT_TYPEDEF_(0x00090323L) -#define SEC_E_TIME_SKEW _HRESULT_TYPEDEF_(0x80090324L) -#define SEC_E_UNTRUSTED_ROOT _HRESULT_TYPEDEF_(0x80090325L) -#define SEC_E_ILLEGAL_MESSAGE _HRESULT_TYPEDEF_(0x80090326L) -#define SEC_E_CERT_UNKNOWN _HRESULT_TYPEDEF_(0x80090327L) -#define SEC_E_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090328L) -#define SEC_E_ENCRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090329L) -#define SEC_E_DECRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090330L) -#define SEC_E_ALGORITHM_MISMATCH _HRESULT_TYPEDEF_(0x80090331L) -#define SEC_E_SECURITY_QOS_FAILED _HRESULT_TYPEDEF_(0x80090332L) -#define SEC_E_UNFINISHED_CONTEXT_DELETED _HRESULT_TYPEDEF_(0x80090333L) -#define SEC_E_NO_TGT_REPLY _HRESULT_TYPEDEF_(0x80090334L) -#define SEC_E_NO_IP_ADDRESSES _HRESULT_TYPEDEF_(0x80090335L) -#define SEC_E_WRONG_CREDENTIAL_HANDLE _HRESULT_TYPEDEF_(0x80090336L) -#define SEC_E_CRYPTO_SYSTEM_INVALID _HRESULT_TYPEDEF_(0x80090337L) -#define SEC_E_MAX_REFERRALS_EXCEEDED _HRESULT_TYPEDEF_(0x80090338L) -#define SEC_E_MUST_BE_KDC _HRESULT_TYPEDEF_(0x80090339L) -#define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009033AL) -#define SEC_E_TOO_MANY_PRINCIPALS _HRESULT_TYPEDEF_(0x8009033BL) -#define SEC_E_NO_PA_DATA _HRESULT_TYPEDEF_(0x8009033CL) -#define SEC_E_PKINIT_NAME_MISMATCH _HRESULT_TYPEDEF_(0x8009033DL) -#define SEC_E_SMARTCARD_LOGON_REQUIRED _HRESULT_TYPEDEF_(0x8009033EL) -#define SEC_E_SHUTDOWN_IN_PROGRESS _HRESULT_TYPEDEF_(0x8009033FL) -#define SEC_E_KDC_INVALID_REQUEST _HRESULT_TYPEDEF_(0x80090340L) -#define SEC_E_KDC_UNABLE_TO_REFER _HRESULT_TYPEDEF_(0x80090341L) -#define SEC_E_KDC_UNKNOWN_ETYPE _HRESULT_TYPEDEF_(0x80090342L) -#define SEC_E_UNSUPPORTED_PREAUTH _HRESULT_TYPEDEF_(0x80090343L) -#define SEC_E_DELEGATION_REQUIRED _HRESULT_TYPEDEF_(0x80090345L) -#define SEC_E_BAD_BINDINGS _HRESULT_TYPEDEF_(0x80090346L) -#define SEC_E_MULTIPLE_ACCOUNTS _HRESULT_TYPEDEF_(0x80090347L) -#define SEC_E_NO_KERB_KEY _HRESULT_TYPEDEF_(0x80090348L) -#define SEC_E_CERT_WRONG_USAGE _HRESULT_TYPEDEF_(0x80090349L) -#define SEC_E_DOWNGRADE_DETECTED _HRESULT_TYPEDEF_(0x80090350L) -#define SEC_E_SMARTCARD_CERT_REVOKED _HRESULT_TYPEDEF_(0x80090351L) -#define SEC_E_ISSUING_CA_UNTRUSTED _HRESULT_TYPEDEF_(0x80090352L) -#define SEC_E_REVOCATION_OFFLINE_C _HRESULT_TYPEDEF_(0x80090353L) -#define SEC_E_PKINIT_CLIENT_FAILURE _HRESULT_TYPEDEF_(0x80090354L) -#define SEC_E_SMARTCARD_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090355L) -#define SEC_E_NO_S4U_PROT_SUPPORT _HRESULT_TYPEDEF_(0x80090356L) -#define SEC_E_CROSSREALM_DELEGATION_FAILURE _HRESULT_TYPEDEF_(0x80090357L) -#define SEC_E_REVOCATION_OFFLINE_KDC _HRESULT_TYPEDEF_(0x80090358L) -#define SEC_E_ISSUING_CA_UNTRUSTED_KDC _HRESULT_TYPEDEF_(0x80090359L) -#define SEC_E_KDC_CERT_EXPIRED _HRESULT_TYPEDEF_(0x8009035AL) -#define SEC_E_KDC_CERT_REVOKED _HRESULT_TYPEDEF_(0x8009035BL) -#define SEC_E_NO_SPM SEC_E_INTERNAL_ERROR -#define SEC_E_NOT_SUPPORTED SEC_E_UNSUPPORTED_FUNCTION -#define CRYPT_E_MSG_ERROR _HRESULT_TYPEDEF_(0x80091001L) -#define CRYPT_E_UNKNOWN_ALGO _HRESULT_TYPEDEF_(0x80091002L) -#define CRYPT_E_OID_FORMAT _HRESULT_TYPEDEF_(0x80091003L) -#define CRYPT_E_INVALID_MSG_TYPE _HRESULT_TYPEDEF_(0x80091004L) -#define CRYPT_E_UNEXPECTED_ENCODING _HRESULT_TYPEDEF_(0x80091005L) -#define CRYPT_E_AUTH_ATTR_MISSING _HRESULT_TYPEDEF_(0x80091006L) -#define CRYPT_E_HASH_VALUE _HRESULT_TYPEDEF_(0x80091007L) -#define CRYPT_E_INVALID_INDEX _HRESULT_TYPEDEF_(0x80091008L) -#define CRYPT_E_ALREADY_DECRYPTED _HRESULT_TYPEDEF_(0x80091009L) -#define CRYPT_E_NOT_DECRYPTED _HRESULT_TYPEDEF_(0x8009100AL) -#define CRYPT_E_RECIPIENT_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100BL) -#define CRYPT_E_CONTROL_TYPE _HRESULT_TYPEDEF_(0x8009100CL) -#define CRYPT_E_ISSUER_SERIALNUMBER _HRESULT_TYPEDEF_(0x8009100DL) -#define CRYPT_E_SIGNER_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100EL) -#define CRYPT_E_ATTRIBUTES_MISSING _HRESULT_TYPEDEF_(0x8009100FL) -#define CRYPT_E_STREAM_MSG_NOT_READY _HRESULT_TYPEDEF_(0x80091010L) -#define CRYPT_E_STREAM_INSUFFICIENT_DATA _HRESULT_TYPEDEF_(0x80091011L) -#define CRYPT_I_NEW_PROTECTION_REQUIRED _HRESULT_TYPEDEF_(0x00091012L) -#define CRYPT_E_BAD_LEN _HRESULT_TYPEDEF_(0x80092001L) -#define CRYPT_E_BAD_ENCODE _HRESULT_TYPEDEF_(0x80092002L) -#define CRYPT_E_FILE_ERROR _HRESULT_TYPEDEF_(0x80092003L) -#define CRYPT_E_NOT_FOUND _HRESULT_TYPEDEF_(0x80092004L) -#define CRYPT_E_EXISTS _HRESULT_TYPEDEF_(0x80092005L) -#define CRYPT_E_NO_PROVIDER _HRESULT_TYPEDEF_(0x80092006L) -#define CRYPT_E_SELF_SIGNED _HRESULT_TYPEDEF_(0x80092007L) -#define CRYPT_E_DELETED_PREV _HRESULT_TYPEDEF_(0x80092008L) -#define CRYPT_E_NO_MATCH _HRESULT_TYPEDEF_(0x80092009L) -#define CRYPT_E_UNEXPECTED_MSG_TYPE _HRESULT_TYPEDEF_(0x8009200AL) -#define CRYPT_E_NO_KEY_PROPERTY _HRESULT_TYPEDEF_(0x8009200BL) -#define CRYPT_E_NO_DECRYPT_CERT _HRESULT_TYPEDEF_(0x8009200CL) -#define CRYPT_E_BAD_MSG _HRESULT_TYPEDEF_(0x8009200DL) -#define CRYPT_E_NO_SIGNER _HRESULT_TYPEDEF_(0x8009200EL) -#define CRYPT_E_PENDING_CLOSE _HRESULT_TYPEDEF_(0x8009200FL) -#define CRYPT_E_REVOKED _HRESULT_TYPEDEF_(0x80092010L) -#define CRYPT_E_NO_REVOCATION_DLL _HRESULT_TYPEDEF_(0x80092011L) -#define CRYPT_E_NO_REVOCATION_CHECK _HRESULT_TYPEDEF_(0x80092012L) -#define CRYPT_E_REVOCATION_OFFLINE _HRESULT_TYPEDEF_(0x80092013L) -#define CRYPT_E_NOT_IN_REVOCATION_DATABASE _HRESULT_TYPEDEF_(0x80092014L) -#define CRYPT_E_INVALID_NUMERIC_STRING _HRESULT_TYPEDEF_(0x80092020L) -#define CRYPT_E_INVALID_PRINTABLE_STRING _HRESULT_TYPEDEF_(0x80092021L) -#define CRYPT_E_INVALID_IA5_STRING _HRESULT_TYPEDEF_(0x80092022L) -#define CRYPT_E_INVALID_X500_STRING _HRESULT_TYPEDEF_(0x80092023L) -#define CRYPT_E_NOT_CHAR_STRING _HRESULT_TYPEDEF_(0x80092024L) -#define CRYPT_E_FILERESIZED _HRESULT_TYPEDEF_(0x80092025L) -#define CRYPT_E_SECURITY_SETTINGS _HRESULT_TYPEDEF_(0x80092026L) -#define CRYPT_E_NO_VERIFY_USAGE_DLL _HRESULT_TYPEDEF_(0x80092027L) -#define CRYPT_E_NO_VERIFY_USAGE_CHECK _HRESULT_TYPEDEF_(0x80092028L) -#define CRYPT_E_VERIFY_USAGE_OFFLINE _HRESULT_TYPEDEF_(0x80092029L) -#define CRYPT_E_NOT_IN_CTL _HRESULT_TYPEDEF_(0x8009202AL) -#define CRYPT_E_NO_TRUSTED_SIGNER _HRESULT_TYPEDEF_(0x8009202BL) -#define CRYPT_E_MISSING_PUBKEY_PARA _HRESULT_TYPEDEF_(0x8009202CL) -#define CRYPT_E_OSS_ERROR _HRESULT_TYPEDEF_(0x80093000L) -#define OSS_MORE_BUF _HRESULT_TYPEDEF_(0x80093001L) -#define OSS_NEGATIVE_UINTEGER _HRESULT_TYPEDEF_(0x80093002L) -#define OSS_PDU_RANGE _HRESULT_TYPEDEF_(0x80093003L) -#define OSS_MORE_INPUT _HRESULT_TYPEDEF_(0x80093004L) -#define OSS_DATA_ERROR _HRESULT_TYPEDEF_(0x80093005L) -#define OSS_BAD_ARG _HRESULT_TYPEDEF_(0x80093006L) -#define OSS_BAD_VERSION _HRESULT_TYPEDEF_(0x80093007L) -#define OSS_OUT_MEMORY _HRESULT_TYPEDEF_(0x80093008L) -#define OSS_PDU_MISMATCH _HRESULT_TYPEDEF_(0x80093009L) -#define OSS_LIMITED _HRESULT_TYPEDEF_(0x8009300AL) -#define OSS_BAD_PTR _HRESULT_TYPEDEF_(0x8009300BL) -#define OSS_BAD_TIME _HRESULT_TYPEDEF_(0x8009300CL) -#define OSS_INDEFINITE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009300DL) -#define OSS_MEM_ERROR _HRESULT_TYPEDEF_(0x8009300EL) -#define OSS_BAD_TABLE _HRESULT_TYPEDEF_(0x8009300FL) -#define OSS_TOO_LONG _HRESULT_TYPEDEF_(0x80093010L) -#define OSS_CONSTRAINT_VIOLATED _HRESULT_TYPEDEF_(0x80093011L) -#define OSS_FATAL_ERROR _HRESULT_TYPEDEF_(0x80093012L) -#define OSS_ACCESS_SERIALIZATION_ERROR _HRESULT_TYPEDEF_(0x80093013L) -#define OSS_NULL_TBL _HRESULT_TYPEDEF_(0x80093014L) -#define OSS_NULL_FCN _HRESULT_TYPEDEF_(0x80093015L) -#define OSS_BAD_ENCRULES _HRESULT_TYPEDEF_(0x80093016L) -#define OSS_UNAVAIL_ENCRULES _HRESULT_TYPEDEF_(0x80093017L) -#define OSS_CANT_OPEN_TRACE_WINDOW _HRESULT_TYPEDEF_(0x80093018L) -#define OSS_UNIMPLEMENTED _HRESULT_TYPEDEF_(0x80093019L) -#define OSS_OID_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301AL) -#define OSS_CANT_OPEN_TRACE_FILE _HRESULT_TYPEDEF_(0x8009301BL) -#define OSS_TRACE_FILE_ALREADY_OPEN _HRESULT_TYPEDEF_(0x8009301CL) -#define OSS_TABLE_MISMATCH _HRESULT_TYPEDEF_(0x8009301DL) -#define OSS_TYPE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009301EL) -#define OSS_REAL_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301FL) -#define OSS_REAL_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093020L) -#define OSS_OUT_OF_RANGE _HRESULT_TYPEDEF_(0x80093021L) -#define OSS_COPIER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093022L) -#define OSS_CONSTRAINT_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093023L) -#define OSS_COMPARATOR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093024L) -#define OSS_COMPARATOR_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093025L) -#define OSS_MEM_MGR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093026L) -#define OSS_PDV_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093027L) -#define OSS_PDV_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093028L) -#define OSS_API_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093029L) -#define OSS_BERDER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302AL) -#define OSS_PER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302BL) -#define OSS_OPEN_TYPE_ERROR _HRESULT_TYPEDEF_(0x8009302CL) -#define OSS_MUTEX_NOT_CREATED _HRESULT_TYPEDEF_(0x8009302DL) -#define OSS_CANT_CLOSE_TRACE_FILE _HRESULT_TYPEDEF_(0x8009302EL) -#define CRYPT_E_ASN1_ERROR _HRESULT_TYPEDEF_(0x80093100L) -#define CRYPT_E_ASN1_INTERNAL _HRESULT_TYPEDEF_(0x80093101L) -#define CRYPT_E_ASN1_EOD _HRESULT_TYPEDEF_(0x80093102L) -#define CRYPT_E_ASN1_CORRUPT _HRESULT_TYPEDEF_(0x80093103L) -#define CRYPT_E_ASN1_LARGE _HRESULT_TYPEDEF_(0x80093104L) -#define CRYPT_E_ASN1_CONSTRAINT _HRESULT_TYPEDEF_(0x80093105L) -#define CRYPT_E_ASN1_MEMORY _HRESULT_TYPEDEF_(0x80093106L) -#define CRYPT_E_ASN1_OVERFLOW _HRESULT_TYPEDEF_(0x80093107L) -#define CRYPT_E_ASN1_BADPDU _HRESULT_TYPEDEF_(0x80093108L) -#define CRYPT_E_ASN1_BADARGS _HRESULT_TYPEDEF_(0x80093109L) -#define CRYPT_E_ASN1_BADREAL _HRESULT_TYPEDEF_(0x8009310AL) -#define CRYPT_E_ASN1_BADTAG _HRESULT_TYPEDEF_(0x8009310BL) -#define CRYPT_E_ASN1_CHOICE _HRESULT_TYPEDEF_(0x8009310CL) -#define CRYPT_E_ASN1_RULE _HRESULT_TYPEDEF_(0x8009310DL) -#define CRYPT_E_ASN1_UTF8 _HRESULT_TYPEDEF_(0x8009310EL) -#define CRYPT_E_ASN1_PDU_TYPE _HRESULT_TYPEDEF_(0x80093133L) -#define CRYPT_E_ASN1_NYI _HRESULT_TYPEDEF_(0x80093134L) -#define CRYPT_E_ASN1_EXTENDED _HRESULT_TYPEDEF_(0x80093201L) -#define CRYPT_E_ASN1_NOEOD _HRESULT_TYPEDEF_(0x80093202L) -#define CERTSRV_E_BAD_REQUESTSUBJECT _HRESULT_TYPEDEF_(0x80094001L) -#define CERTSRV_E_NO_REQUEST _HRESULT_TYPEDEF_(0x80094002L) -#define CERTSRV_E_BAD_REQUESTSTATUS _HRESULT_TYPEDEF_(0x80094003L) -#define CERTSRV_E_PROPERTY_EMPTY _HRESULT_TYPEDEF_(0x80094004L) -#define CERTSRV_E_INVALID_CA_CERTIFICATE _HRESULT_TYPEDEF_(0x80094005L) -#define CERTSRV_E_SERVER_SUSPENDED _HRESULT_TYPEDEF_(0x80094006L) -#define CERTSRV_E_ENCODING_LENGTH _HRESULT_TYPEDEF_(0x80094007L) -#define CERTSRV_E_ROLECONFLICT _HRESULT_TYPEDEF_(0x80094008L) -#define CERTSRV_E_RESTRICTEDOFFICER _HRESULT_TYPEDEF_(0x80094009L) -#define CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED _HRESULT_TYPEDEF_(0x8009400AL) -#define CERTSRV_E_NO_VALID_KRA _HRESULT_TYPEDEF_(0x8009400BL) -#define CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL _HRESULT_TYPEDEF_(0x8009400CL) -#define CERTSRV_E_NO_CAADMIN_DEFINED _HRESULT_TYPEDEF_(0x8009400DL) -#define CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE _HRESULT_TYPEDEF_(0x8009400EL) -#define CERTSRV_E_NO_DB_SESSIONS _HRESULT_TYPEDEF_(0x8009400FL) -#define CERTSRV_E_ALIGNMENT_FAULT _HRESULT_TYPEDEF_(0x80094010L) -#define CERTSRV_E_ENROLL_DENIED _HRESULT_TYPEDEF_(0x80094011L) -#define CERTSRV_E_TEMPLATE_DENIED _HRESULT_TYPEDEF_(0x80094012L) -#define CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE _HRESULT_TYPEDEF_(0x80094013L) -#define CERTSRV_E_UNSUPPORTED_CERT_TYPE _HRESULT_TYPEDEF_(0x80094800L) -#define CERTSRV_E_NO_CERT_TYPE _HRESULT_TYPEDEF_(0x80094801L) -#define CERTSRV_E_TEMPLATE_CONFLICT _HRESULT_TYPEDEF_(0x80094802L) -#define CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED _HRESULT_TYPEDEF_(0x80094803L) -#define CERTSRV_E_ARCHIVED_KEY_REQUIRED _HRESULT_TYPEDEF_(0x80094804L) -#define CERTSRV_E_SMIME_REQUIRED _HRESULT_TYPEDEF_(0x80094805L) -#define CERTSRV_E_BAD_RENEWAL_SUBJECT _HRESULT_TYPEDEF_(0x80094806L) -#define CERTSRV_E_BAD_TEMPLATE_VERSION _HRESULT_TYPEDEF_(0x80094807L) -#define CERTSRV_E_TEMPLATE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094808L) -#define CERTSRV_E_SIGNATURE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094809L) -#define CERTSRV_E_SIGNATURE_COUNT _HRESULT_TYPEDEF_(0x8009480AL) -#define CERTSRV_E_SIGNATURE_REJECTED _HRESULT_TYPEDEF_(0x8009480BL) -#define CERTSRV_E_ISSUANCE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x8009480CL) -#define CERTSRV_E_SUBJECT_UPN_REQUIRED _HRESULT_TYPEDEF_(0x8009480DL) -#define CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED _HRESULT_TYPEDEF_(0x8009480EL) -#define CERTSRV_E_SUBJECT_DNS_REQUIRED _HRESULT_TYPEDEF_(0x8009480FL) -#define CERTSRV_E_ARCHIVED_KEY_UNEXPECTED _HRESULT_TYPEDEF_(0x80094810L) -#define CERTSRV_E_KEY_LENGTH _HRESULT_TYPEDEF_(0x80094811L) -#define CERTSRV_E_SUBJECT_EMAIL_REQUIRED _HRESULT_TYPEDEF_(0x80094812L) -#define CERTSRV_E_UNKNOWN_CERT_TYPE _HRESULT_TYPEDEF_(0x80094813L) -#define CERTSRV_E_CERT_TYPE_OVERLAP _HRESULT_TYPEDEF_(0x80094814L) -#define XENROLL_E_KEY_NOT_EXPORTABLE _HRESULT_TYPEDEF_(0x80095000L) -#define XENROLL_E_CANNOT_ADD_ROOT_CERT _HRESULT_TYPEDEF_(0x80095001L) -#define XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND _HRESULT_TYPEDEF_(0x80095002L) -#define XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH _HRESULT_TYPEDEF_(0x80095003L) -#define XENROLL_E_RESPONSE_KA_HASH_MISMATCH _HRESULT_TYPEDEF_(0x80095004L) -#define XENROLL_E_KEYSPEC_SMIME_MISMATCH _HRESULT_TYPEDEF_(0x80095005L) -#define TRUST_E_SYSTEM_ERROR _HRESULT_TYPEDEF_(0x80096001L) -#define TRUST_E_NO_SIGNER_CERT _HRESULT_TYPEDEF_(0x80096002L) -#define TRUST_E_COUNTER_SIGNER _HRESULT_TYPEDEF_(0x80096003L) -#define TRUST_E_CERT_SIGNATURE _HRESULT_TYPEDEF_(0x80096004L) -#define TRUST_E_TIME_STAMP _HRESULT_TYPEDEF_(0x80096005L) -#define TRUST_E_BAD_DIGEST _HRESULT_TYPEDEF_(0x80096010L) -#define TRUST_E_BASIC_CONSTRAINTS _HRESULT_TYPEDEF_(0x80096019L) -#define TRUST_E_FINANCIAL_CRITERIA _HRESULT_TYPEDEF_(0x8009601EL) -#define MSSIPOTF_E_OUTOFMEMRANGE _HRESULT_TYPEDEF_(0x80097001L) -#define MSSIPOTF_E_CANTGETOBJECT _HRESULT_TYPEDEF_(0x80097002L) -#define MSSIPOTF_E_NOHEADTABLE _HRESULT_TYPEDEF_(0x80097003L) -#define MSSIPOTF_E_BAD_MAGICNUMBER _HRESULT_TYPEDEF_(0x80097004L) -#define MSSIPOTF_E_BAD_OFFSET_TABLE _HRESULT_TYPEDEF_(0x80097005L) -#define MSSIPOTF_E_TABLE_TAGORDER _HRESULT_TYPEDEF_(0x80097006L) -#define MSSIPOTF_E_TABLE_LONGWORD _HRESULT_TYPEDEF_(0x80097007L) -#define MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT _HRESULT_TYPEDEF_(0x80097008L) -#define MSSIPOTF_E_TABLES_OVERLAP _HRESULT_TYPEDEF_(0x80097009L) -#define MSSIPOTF_E_TABLE_PADBYTES _HRESULT_TYPEDEF_(0x8009700AL) -#define MSSIPOTF_E_FILETOOSMALL _HRESULT_TYPEDEF_(0x8009700BL) -#define MSSIPOTF_E_TABLE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700CL) -#define MSSIPOTF_E_FILE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700DL) -#define MSSIPOTF_E_FAILED_POLICY _HRESULT_TYPEDEF_(0x80097010L) -#define MSSIPOTF_E_FAILED_HINTS_CHECK _HRESULT_TYPEDEF_(0x80097011L) -#define MSSIPOTF_E_NOT_OPENTYPE _HRESULT_TYPEDEF_(0x80097012L) -#define MSSIPOTF_E_FILE _HRESULT_TYPEDEF_(0x80097013L) -#define MSSIPOTF_E_CRYPT _HRESULT_TYPEDEF_(0x80097014L) -#define MSSIPOTF_E_BADVERSION _HRESULT_TYPEDEF_(0x80097015L) -#define MSSIPOTF_E_DSIG_STRUCTURE _HRESULT_TYPEDEF_(0x80097016L) -#define MSSIPOTF_E_PCONST_CHECK _HRESULT_TYPEDEF_(0x80097017L) -#define MSSIPOTF_E_STRUCTURE _HRESULT_TYPEDEF_(0x80097018L) -#define NTE_OP_OK 0 -#define TRUST_E_PROVIDER_UNKNOWN _HRESULT_TYPEDEF_(0x800B0001L) -#define TRUST_E_ACTION_UNKNOWN _HRESULT_TYPEDEF_(0x800B0002L) -#define TRUST_E_SUBJECT_FORM_UNKNOWN _HRESULT_TYPEDEF_(0x800B0003L) -#define TRUST_E_SUBJECT_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800B0004L) -#define DIGSIG_E_ENCODE _HRESULT_TYPEDEF_(0x800B0005L) -#define DIGSIG_E_DECODE _HRESULT_TYPEDEF_(0x800B0006L) -#define DIGSIG_E_EXTENSIBILITY _HRESULT_TYPEDEF_(0x800B0007L) -#define DIGSIG_E_CRYPTO _HRESULT_TYPEDEF_(0x800B0008L) -#define PERSIST_E_SIZEDEFINITE _HRESULT_TYPEDEF_(0x800B0009L) -#define PERSIST_E_SIZEINDEFINITE _HRESULT_TYPEDEF_(0x800B000AL) -#define PERSIST_E_NOTSELFSIZING _HRESULT_TYPEDEF_(0x800B000BL) -#define TRUST_E_NOSIGNATURE _HRESULT_TYPEDEF_(0x800B0100L) -#define CERT_E_EXPIRED _HRESULT_TYPEDEF_(0x800B0101L) -#define CERT_E_VALIDITYPERIODNESTING _HRESULT_TYPEDEF_(0x800B0102L) -#define CERT_E_ROLE _HRESULT_TYPEDEF_(0x800B0103L) -#define CERT_E_PATHLENCONST _HRESULT_TYPEDEF_(0x800B0104L) -#define CERT_E_CRITICAL _HRESULT_TYPEDEF_(0x800B0105L) -#define CERT_E_PURPOSE _HRESULT_TYPEDEF_(0x800B0106L) -#define CERT_E_ISSUERCHAINING _HRESULT_TYPEDEF_(0x800B0107L) -#define CERT_E_MALFORMED _HRESULT_TYPEDEF_(0x800B0108L) -#define CERT_E_UNTRUSTEDROOT _HRESULT_TYPEDEF_(0x800B0109L) -#define CERT_E_CHAINING _HRESULT_TYPEDEF_(0x800B010AL) -#define TRUST_E_FAIL _HRESULT_TYPEDEF_(0x800B010BL) -#define CERT_E_REVOKED _HRESULT_TYPEDEF_(0x800B010CL) -#define CERT_E_UNTRUSTEDTESTROOT _HRESULT_TYPEDEF_(0x800B010DL) -#define CERT_E_REVOCATION_FAILURE _HRESULT_TYPEDEF_(0x800B010EL) -#define CERT_E_CN_NO_MATCH _HRESULT_TYPEDEF_(0x800B010FL) -#define CERT_E_WRONG_USAGE _HRESULT_TYPEDEF_(0x800B0110L) -#define TRUST_E_EXPLICIT_DISTRUST _HRESULT_TYPEDEF_(0x800B0111L) -#define CERT_E_UNTRUSTEDCA _HRESULT_TYPEDEF_(0x800B0112L) -#define CERT_E_INVALID_POLICY _HRESULT_TYPEDEF_(0x800B0113L) -#define CERT_E_INVALID_NAME _HRESULT_TYPEDEF_(0x800B0114L) -#define HRESULT_FROM_SETUPAPI(x) ((((x) & (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR))==(APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR)) ? ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_SETUPAPI << 16) | 0x80000000)) : HRESULT_FROM_WIN32(x)) -#define SPAPI_E_EXPECTED_SECTION_NAME _HRESULT_TYPEDEF_(0x800F0000L) -#define SPAPI_E_BAD_SECTION_NAME_LINE _HRESULT_TYPEDEF_(0x800F0001L) -#define SPAPI_E_SECTION_NAME_TOO_LONG _HRESULT_TYPEDEF_(0x800F0002L) -#define SPAPI_E_GENERAL_SYNTAX _HRESULT_TYPEDEF_(0x800F0003L) -#define SPAPI_E_WRONG_INF_STYLE _HRESULT_TYPEDEF_(0x800F0100L) -#define SPAPI_E_SECTION_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0101L) -#define SPAPI_E_LINE_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0102L) -#define SPAPI_E_NO_BACKUP _HRESULT_TYPEDEF_(0x800F0103L) -#define SPAPI_E_NO_ASSOCIATED_CLASS _HRESULT_TYPEDEF_(0x800F0200L) -#define SPAPI_E_CLASS_MISMATCH _HRESULT_TYPEDEF_(0x800F0201L) -#define SPAPI_E_DUPLICATE_FOUND _HRESULT_TYPEDEF_(0x800F0202L) -#define SPAPI_E_NO_DRIVER_SELECTED _HRESULT_TYPEDEF_(0x800F0203L) -#define SPAPI_E_KEY_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x800F0204L) -#define SPAPI_E_INVALID_DEVINST_NAME _HRESULT_TYPEDEF_(0x800F0205L) -#define SPAPI_E_INVALID_CLASS _HRESULT_TYPEDEF_(0x800F0206L) -#define SPAPI_E_DEVINST_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x800F0207L) -#define SPAPI_E_DEVINFO_NOT_REGISTERED _HRESULT_TYPEDEF_(0x800F0208L) -#define SPAPI_E_INVALID_REG_PROPERTY _HRESULT_TYPEDEF_(0x800F0209L) -#define SPAPI_E_NO_INF _HRESULT_TYPEDEF_(0x800F020AL) -#define SPAPI_E_NO_SUCH_DEVINST _HRESULT_TYPEDEF_(0x800F020BL) -#define SPAPI_E_CANT_LOAD_CLASS_ICON _HRESULT_TYPEDEF_(0x800F020CL) -#define SPAPI_E_INVALID_CLASS_INSTALLER _HRESULT_TYPEDEF_(0x800F020DL) -#define SPAPI_E_DI_DO_DEFAULT _HRESULT_TYPEDEF_(0x800F020EL) -#define SPAPI_E_DI_NOFILECOPY _HRESULT_TYPEDEF_(0x800F020FL) -#define SPAPI_E_INVALID_HWPROFILE _HRESULT_TYPEDEF_(0x800F0210L) -#define SPAPI_E_NO_DEVICE_SELECTED _HRESULT_TYPEDEF_(0x800F0211L) -#define SPAPI_E_DEVINFO_LIST_LOCKED _HRESULT_TYPEDEF_(0x800F0212L) -#define SPAPI_E_DEVINFO_DATA_LOCKED _HRESULT_TYPEDEF_(0x800F0213L) -#define SPAPI_E_DI_BAD_PATH _HRESULT_TYPEDEF_(0x800F0214L) -#define SPAPI_E_NO_CLASSINSTALL_PARAMS _HRESULT_TYPEDEF_(0x800F0215L) -#define SPAPI_E_FILEQUEUE_LOCKED _HRESULT_TYPEDEF_(0x800F0216L) -#define SPAPI_E_BAD_SERVICE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F0217L) -#define SPAPI_E_NO_CLASS_DRIVER_LIST _HRESULT_TYPEDEF_(0x800F0218L) -#define SPAPI_E_NO_ASSOCIATED_SERVICE _HRESULT_TYPEDEF_(0x800F0219L) -#define SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F021AL) -#define SPAPI_E_DEVICE_INTERFACE_ACTIVE _HRESULT_TYPEDEF_(0x800F021BL) -#define SPAPI_E_DEVICE_INTERFACE_REMOVED _HRESULT_TYPEDEF_(0x800F021CL) -#define SPAPI_E_BAD_INTERFACE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F021DL) -#define SPAPI_E_NO_SUCH_INTERFACE_CLASS _HRESULT_TYPEDEF_(0x800F021EL) -#define SPAPI_E_INVALID_REFERENCE_STRING _HRESULT_TYPEDEF_(0x800F021FL) -#define SPAPI_E_INVALID_MACHINENAME _HRESULT_TYPEDEF_(0x800F0220L) -#define SPAPI_E_REMOTE_COMM_FAILURE _HRESULT_TYPEDEF_(0x800F0221L) -#define SPAPI_E_MACHINE_UNAVAILABLE _HRESULT_TYPEDEF_(0x800F0222L) -#define SPAPI_E_NO_CONFIGMGR_SERVICES _HRESULT_TYPEDEF_(0x800F0223L) -#define SPAPI_E_INVALID_PROPPAGE_PROVIDER _HRESULT_TYPEDEF_(0x800F0224L) -#define SPAPI_E_NO_SUCH_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F0225L) -#define SPAPI_E_DI_POSTPROCESSING_REQUIRED _HRESULT_TYPEDEF_(0x800F0226L) -#define SPAPI_E_INVALID_COINSTALLER _HRESULT_TYPEDEF_(0x800F0227L) -#define SPAPI_E_NO_COMPAT_DRIVERS _HRESULT_TYPEDEF_(0x800F0228L) -#define SPAPI_E_NO_DEVICE_ICON _HRESULT_TYPEDEF_(0x800F0229L) -#define SPAPI_E_INVALID_INF_LOGCONFIG _HRESULT_TYPEDEF_(0x800F022AL) -#define SPAPI_E_DI_DONT_INSTALL _HRESULT_TYPEDEF_(0x800F022BL) -#define SPAPI_E_INVALID_FILTER_DRIVER _HRESULT_TYPEDEF_(0x800F022CL) -#define SPAPI_E_NON_WINDOWS_NT_DRIVER _HRESULT_TYPEDEF_(0x800F022DL) -#define SPAPI_E_NON_WINDOWS_DRIVER _HRESULT_TYPEDEF_(0x800F022EL) -#define SPAPI_E_NO_CATALOG_FOR_OEM_INF _HRESULT_TYPEDEF_(0x800F022FL) -#define SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE _HRESULT_TYPEDEF_(0x800F0230L) -#define SPAPI_E_NOT_DISABLEABLE _HRESULT_TYPEDEF_(0x800F0231L) -#define SPAPI_E_CANT_REMOVE_DEVINST _HRESULT_TYPEDEF_(0x800F0232L) -#define SPAPI_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x800F0233L) -#define SPAPI_E_DRIVER_NONNATIVE _HRESULT_TYPEDEF_(0x800F0234L) -#define SPAPI_E_IN_WOW64 _HRESULT_TYPEDEF_(0x800F0235L) -#define SPAPI_E_SET_SYSTEM_RESTORE_POINT _HRESULT_TYPEDEF_(0x800F0236L) -#define SPAPI_E_INCORRECTLY_COPIED_INF _HRESULT_TYPEDEF_(0x800F0237L) -#define SPAPI_E_SCE_DISABLED _HRESULT_TYPEDEF_(0x800F0238L) -#define SPAPI_E_UNKNOWN_EXCEPTION _HRESULT_TYPEDEF_(0x800F0239L) -#define SPAPI_E_PNP_REGISTRY_ERROR _HRESULT_TYPEDEF_(0x800F023AL) -#define SPAPI_E_REMOTE_REQUEST_UNSUPPORTED _HRESULT_TYPEDEF_(0x800F023BL) -#define SPAPI_E_NOT_AN_INSTALLED_OEM_INF _HRESULT_TYPEDEF_(0x800F023CL) -#define SPAPI_E_INF_IN_USE_BY_DEVICES _HRESULT_TYPEDEF_(0x800F023DL) -#define SPAPI_E_DI_FUNCTION_OBSOLETE _HRESULT_TYPEDEF_(0x800F023EL) -#define SPAPI_E_NO_AUTHENTICODE_CATALOG _HRESULT_TYPEDEF_(0x800F023FL) -#define SPAPI_E_AUTHENTICODE_DISALLOWED _HRESULT_TYPEDEF_(0x800F0240L) -#define SPAPI_E_AUTHENTICODE_TRUSTED_PUBLISHER _HRESULT_TYPEDEF_(0x800F0241L) -#define SPAPI_E_AUTHENTICODE_TRUST_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x800F0242L) -#define SPAPI_E_AUTHENTICODE_PUBLISHER_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800F0243L) -#define SPAPI_E_SIGNATURE_OSATTRIBUTE_MISMATCH _HRESULT_TYPEDEF_(0x800F0244L) -#define SPAPI_E_ONLY_VALIDATE_VIA_AUTHENTICODE _HRESULT_TYPEDEF_(0x800F0245L) -#define SPAPI_E_UNRECOVERABLE_STACK_OVERFLOW _HRESULT_TYPEDEF_(0x800F0300L) -#define SPAPI_E_ERROR_NOT_INSTALLED _HRESULT_TYPEDEF_(0x800F1000L) -#define SCARD_S_SUCCESS NO_ERROR -#define SCARD_F_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80100001L) -#define SCARD_E_CANCELLED _HRESULT_TYPEDEF_(0x80100002L) -#define SCARD_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80100003L) -#define SCARD_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80100004L) -#define SCARD_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x80100005L) -#define SCARD_E_NO_MEMORY _HRESULT_TYPEDEF_(0x80100006L) -#define SCARD_F_WAITED_TOO_LONG _HRESULT_TYPEDEF_(0x80100007L) -#define SCARD_E_INSUFFICIENT_BUFFER _HRESULT_TYPEDEF_(0x80100008L) -#define SCARD_E_UNKNOWN_READER _HRESULT_TYPEDEF_(0x80100009L) -#define SCARD_E_TIMEOUT _HRESULT_TYPEDEF_(0x8010000AL) -#define SCARD_E_SHARING_VIOLATION _HRESULT_TYPEDEF_(0x8010000BL) -#define SCARD_E_NO_SMARTCARD _HRESULT_TYPEDEF_(0x8010000CL) -#define SCARD_E_UNKNOWN_CARD _HRESULT_TYPEDEF_(0x8010000DL) -#define SCARD_E_CANT_DISPOSE _HRESULT_TYPEDEF_(0x8010000EL) -#define SCARD_E_PROTO_MISMATCH _HRESULT_TYPEDEF_(0x8010000FL) -#define SCARD_E_NOT_READY _HRESULT_TYPEDEF_(0x80100010L) -#define SCARD_E_INVALID_VALUE _HRESULT_TYPEDEF_(0x80100011L) -#define SCARD_E_SYSTEM_CANCELLED _HRESULT_TYPEDEF_(0x80100012L) -#define SCARD_F_COMM_ERROR _HRESULT_TYPEDEF_(0x80100013L) -#define SCARD_F_UNKNOWN_ERROR _HRESULT_TYPEDEF_(0x80100014L) -#define SCARD_E_INVALID_ATR _HRESULT_TYPEDEF_(0x80100015L) -#define SCARD_E_NOT_TRANSACTED _HRESULT_TYPEDEF_(0x80100016L) -#define SCARD_E_READER_UNAVAILABLE _HRESULT_TYPEDEF_(0x80100017L) -#define SCARD_P_SHUTDOWN _HRESULT_TYPEDEF_(0x80100018L) -#define SCARD_E_PCI_TOO_SMALL _HRESULT_TYPEDEF_(0x80100019L) -#define SCARD_E_READER_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001AL) -#define SCARD_E_DUPLICATE_READER _HRESULT_TYPEDEF_(0x8010001BL) -#define SCARD_E_CARD_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001CL) -#define SCARD_E_NO_SERVICE _HRESULT_TYPEDEF_(0x8010001DL) -#define SCARD_E_SERVICE_STOPPED _HRESULT_TYPEDEF_(0x8010001EL) -#define SCARD_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8010001FL) -#define SCARD_E_ICC_INSTALLATION _HRESULT_TYPEDEF_(0x80100020L) -#define SCARD_E_ICC_CREATEORDER _HRESULT_TYPEDEF_(0x80100021L) -#define SCARD_E_UNSUPPORTED_FEATURE _HRESULT_TYPEDEF_(0x80100022L) -#define SCARD_E_DIR_NOT_FOUND _HRESULT_TYPEDEF_(0x80100023L) -#define SCARD_E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80100024L) -#define SCARD_E_NO_DIR _HRESULT_TYPEDEF_(0x80100025L) -#define SCARD_E_NO_FILE _HRESULT_TYPEDEF_(0x80100026L) -#define SCARD_E_NO_ACCESS _HRESULT_TYPEDEF_(0x80100027L) -#define SCARD_E_WRITE_TOO_MANY _HRESULT_TYPEDEF_(0x80100028L) -#define SCARD_E_BAD_SEEK _HRESULT_TYPEDEF_(0x80100029L) -#define SCARD_E_INVALID_CHV _HRESULT_TYPEDEF_(0x8010002AL) -#define SCARD_E_UNKNOWN_RES_MNG _HRESULT_TYPEDEF_(0x8010002BL) -#define SCARD_E_NO_SUCH_CERTIFICATE _HRESULT_TYPEDEF_(0x8010002CL) -#define SCARD_E_CERTIFICATE_UNAVAILABLE _HRESULT_TYPEDEF_(0x8010002DL) -#define SCARD_E_NO_READERS_AVAILABLE _HRESULT_TYPEDEF_(0x8010002EL) -#define SCARD_E_COMM_DATA_LOST _HRESULT_TYPEDEF_(0x8010002FL) -#define SCARD_E_NO_KEY_CONTAINER _HRESULT_TYPEDEF_(0x80100030L) -#define SCARD_E_SERVER_TOO_BUSY _HRESULT_TYPEDEF_(0x80100031L) -#define SCARD_W_UNSUPPORTED_CARD _HRESULT_TYPEDEF_(0x80100065L) -#define SCARD_W_UNRESPONSIVE_CARD _HRESULT_TYPEDEF_(0x80100066L) -#define SCARD_W_UNPOWERED_CARD _HRESULT_TYPEDEF_(0x80100067L) -#define SCARD_W_RESET_CARD _HRESULT_TYPEDEF_(0x80100068L) -#define SCARD_W_REMOVED_CARD _HRESULT_TYPEDEF_(0x80100069L) -#define SCARD_W_SECURITY_VIOLATION _HRESULT_TYPEDEF_(0x8010006AL) -#define SCARD_W_WRONG_CHV _HRESULT_TYPEDEF_(0x8010006BL) -#define SCARD_W_CHV_BLOCKED _HRESULT_TYPEDEF_(0x8010006CL) -#define SCARD_W_EOF _HRESULT_TYPEDEF_(0x8010006DL) -#define SCARD_W_CANCELLED_BY_USER _HRESULT_TYPEDEF_(0x8010006EL) -#define SCARD_W_CARD_NOT_AUTHENTICATED _HRESULT_TYPEDEF_(0x8010006FL) -#define COMADMIN_E_OBJECTERRORS _HRESULT_TYPEDEF_(0x80110401L) -#define COMADMIN_E_OBJECTINVALID _HRESULT_TYPEDEF_(0x80110402L) -#define COMADMIN_E_KEYMISSING _HRESULT_TYPEDEF_(0x80110403L) -#define COMADMIN_E_ALREADYINSTALLED _HRESULT_TYPEDEF_(0x80110404L) -#define COMADMIN_E_APP_FILE_WRITEFAIL _HRESULT_TYPEDEF_(0x80110407L) -#define COMADMIN_E_APP_FILE_READFAIL _HRESULT_TYPEDEF_(0x80110408L) -#define COMADMIN_E_APP_FILE_VERSION _HRESULT_TYPEDEF_(0x80110409L) -#define COMADMIN_E_BADPATH _HRESULT_TYPEDEF_(0x8011040AL) -#define COMADMIN_E_APPLICATIONEXISTS _HRESULT_TYPEDEF_(0x8011040BL) -#define COMADMIN_E_ROLEEXISTS _HRESULT_TYPEDEF_(0x8011040CL) -#define COMADMIN_E_CANTCOPYFILE _HRESULT_TYPEDEF_(0x8011040DL) -#define COMADMIN_E_NOUSER _HRESULT_TYPEDEF_(0x8011040FL) -#define COMADMIN_E_INVALIDUSERIDS _HRESULT_TYPEDEF_(0x80110410L) -#define COMADMIN_E_NOREGISTRYCLSID _HRESULT_TYPEDEF_(0x80110411L) -#define COMADMIN_E_BADREGISTRYPROGID _HRESULT_TYPEDEF_(0x80110412L) -#define COMADMIN_E_AUTHENTICATIONLEVEL _HRESULT_TYPEDEF_(0x80110413L) -#define COMADMIN_E_USERPASSWDNOTVALID _HRESULT_TYPEDEF_(0x80110414L) -#define COMADMIN_E_CLSIDORIIDMISMATCH _HRESULT_TYPEDEF_(0x80110418L) -#define COMADMIN_E_REMOTEINTERFACE _HRESULT_TYPEDEF_(0x80110419L) -#define COMADMIN_E_DLLREGISTERSERVER _HRESULT_TYPEDEF_(0x8011041AL) -#define COMADMIN_E_NOSERVERSHARE _HRESULT_TYPEDEF_(0x8011041BL) -#define COMADMIN_E_DLLLOADFAILED _HRESULT_TYPEDEF_(0x8011041DL) -#define COMADMIN_E_BADREGISTRYLIBID _HRESULT_TYPEDEF_(0x8011041EL) -#define COMADMIN_E_APPDIRNOTFOUND _HRESULT_TYPEDEF_(0x8011041FL) -#define COMADMIN_E_REGISTRARFAILED _HRESULT_TYPEDEF_(0x80110423L) -#define COMADMIN_E_COMPFILE_DOESNOTEXIST _HRESULT_TYPEDEF_(0x80110424L) -#define COMADMIN_E_COMPFILE_LOADDLLFAIL _HRESULT_TYPEDEF_(0x80110425L) -#define COMADMIN_E_COMPFILE_GETCLASSOBJ _HRESULT_TYPEDEF_(0x80110426L) -#define COMADMIN_E_COMPFILE_CLASSNOTAVAIL _HRESULT_TYPEDEF_(0x80110427L) -#define COMADMIN_E_COMPFILE_BADTLB _HRESULT_TYPEDEF_(0x80110428L) -#define COMADMIN_E_COMPFILE_NOTINSTALLABLE _HRESULT_TYPEDEF_(0x80110429L) -#define COMADMIN_E_NOTCHANGEABLE _HRESULT_TYPEDEF_(0x8011042AL) -#define COMADMIN_E_NOTDELETEABLE _HRESULT_TYPEDEF_(0x8011042BL) -#define COMADMIN_E_SESSION _HRESULT_TYPEDEF_(0x8011042CL) -#define COMADMIN_E_COMP_MOVE_LOCKED _HRESULT_TYPEDEF_(0x8011042DL) -#define COMADMIN_E_COMP_MOVE_BAD_DEST _HRESULT_TYPEDEF_(0x8011042EL) -#define COMADMIN_E_REGISTERTLB _HRESULT_TYPEDEF_(0x80110430L) -#define COMADMIN_E_SYSTEMAPP _HRESULT_TYPEDEF_(0x80110433L) -#define COMADMIN_E_COMPFILE_NOREGISTRAR _HRESULT_TYPEDEF_(0x80110434L) -#define COMADMIN_E_COREQCOMPINSTALLED _HRESULT_TYPEDEF_(0x80110435L) -#define COMADMIN_E_SERVICENOTINSTALLED _HRESULT_TYPEDEF_(0x80110436L) -#define COMADMIN_E_PROPERTYSAVEFAILED _HRESULT_TYPEDEF_(0x80110437L) -#define COMADMIN_E_OBJECTEXISTS _HRESULT_TYPEDEF_(0x80110438L) -#define COMADMIN_E_COMPONENTEXISTS _HRESULT_TYPEDEF_(0x80110439L) -#define COMADMIN_E_REGFILE_CORRUPT _HRESULT_TYPEDEF_(0x8011043BL) -#define COMADMIN_E_PROPERTY_OVERFLOW _HRESULT_TYPEDEF_(0x8011043CL) -#define COMADMIN_E_NOTINREGISTRY _HRESULT_TYPEDEF_(0x8011043EL) -#define COMADMIN_E_OBJECTNOTPOOLABLE _HRESULT_TYPEDEF_(0x8011043FL) -#define COMADMIN_E_APPLID_MATCHES_CLSID _HRESULT_TYPEDEF_(0x80110446L) -#define COMADMIN_E_ROLE_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110447L) -#define COMADMIN_E_START_APP_NEEDS_COMPONENTS _HRESULT_TYPEDEF_(0x80110448L) -#define COMADMIN_E_REQUIRES_DIFFERENT_PLATFORM _HRESULT_TYPEDEF_(0x80110449L) -#define COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY _HRESULT_TYPEDEF_(0x8011044AL) -#define COMADMIN_E_CAN_NOT_START_APP _HRESULT_TYPEDEF_(0x8011044BL) -#define COMADMIN_E_CAN_NOT_EXPORT_SYS_APP _HRESULT_TYPEDEF_(0x8011044CL) -#define COMADMIN_E_CANT_SUBSCRIBE_TO_COMPONENT _HRESULT_TYPEDEF_(0x8011044DL) -#define COMADMIN_E_EVENTCLASS_CANT_BE_SUBSCRIBER _HRESULT_TYPEDEF_(0x8011044EL) -#define COMADMIN_E_LIB_APP_PROXY_INCOMPATIBLE _HRESULT_TYPEDEF_(0x8011044FL) -#define COMADMIN_E_BASE_PARTITION_ONLY _HRESULT_TYPEDEF_(0x80110450L) -#define COMADMIN_E_START_APP_DISABLED _HRESULT_TYPEDEF_(0x80110451L) -#define COMADMIN_E_CAT_DUPLICATE_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110457L) -#define COMADMIN_E_CAT_INVALID_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110458L) -#define COMADMIN_E_CAT_PARTITION_IN_USE _HRESULT_TYPEDEF_(0x80110459L) -#define COMADMIN_E_FILE_PARTITION_DUPLICATE_FILES _HRESULT_TYPEDEF_(0x8011045AL) -#define COMADMIN_E_CAT_IMPORTED_COMPONENTS_NOT_ALLOWED _HRESULT_TYPEDEF_(0x8011045BL) -#define COMADMIN_E_AMBIGUOUS_APPLICATION_NAME _HRESULT_TYPEDEF_(0x8011045CL) -#define COMADMIN_E_AMBIGUOUS_PARTITION_NAME _HRESULT_TYPEDEF_(0x8011045DL) -#define COMADMIN_E_REGDB_NOTINITIALIZED _HRESULT_TYPEDEF_(0x80110472L) -#define COMADMIN_E_REGDB_NOTOPEN _HRESULT_TYPEDEF_(0x80110473L) -#define COMADMIN_E_REGDB_SYSTEMERR _HRESULT_TYPEDEF_(0x80110474L) -#define COMADMIN_E_REGDB_ALREADYRUNNING _HRESULT_TYPEDEF_(0x80110475L) -#define COMADMIN_E_MIG_VERSIONNOTSUPPORTED _HRESULT_TYPEDEF_(0x80110480L) -#define COMADMIN_E_MIG_SCHEMANOTFOUND _HRESULT_TYPEDEF_(0x80110481L) -#define COMADMIN_E_CAT_BITNESSMISMATCH _HRESULT_TYPEDEF_(0x80110482L) -#define COMADMIN_E_CAT_UNACCEPTABLEBITNESS _HRESULT_TYPEDEF_(0x80110483L) -#define COMADMIN_E_CAT_WRONGAPPBITNESS _HRESULT_TYPEDEF_(0x80110484L) -#define COMADMIN_E_CAT_PAUSE_RESUME_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80110485L) -#define COMADMIN_E_CAT_SERVERFAULT _HRESULT_TYPEDEF_(0x80110486L) -#define COMQC_E_APPLICATION_NOT_QUEUED _HRESULT_TYPEDEF_(0x80110600L) -#define COMQC_E_NO_QUEUEABLE_INTERFACES _HRESULT_TYPEDEF_(0x80110601L) -#define COMQC_E_QUEUING_SERVICE_NOT_AVAILABLE _HRESULT_TYPEDEF_(0x80110602L) -#define COMQC_E_NO_IPERSISTSTREAM _HRESULT_TYPEDEF_(0x80110603L) -#define COMQC_E_BAD_MESSAGE _HRESULT_TYPEDEF_(0x80110604L) -#define COMQC_E_UNAUTHENTICATED _HRESULT_TYPEDEF_(0x80110605L) -#define COMQC_E_UNTRUSTED_ENQUEUER _HRESULT_TYPEDEF_(0x80110606L) -#define MSDTC_E_DUPLICATE_RESOURCE _HRESULT_TYPEDEF_(0x80110701L) -#define COMADMIN_E_OBJECT_PARENT_MISSING _HRESULT_TYPEDEF_(0x80110808L) -#define COMADMIN_E_OBJECT_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110809L) -#define COMADMIN_E_APP_NOT_RUNNING _HRESULT_TYPEDEF_(0x8011080AL) -#define COMADMIN_E_INVALID_PARTITION _HRESULT_TYPEDEF_(0x8011080BL) -#define COMADMIN_E_SVCAPP_NOT_POOLABLE_OR_RECYCLABLE _HRESULT_TYPEDEF_(0x8011080DL) -#define COMADMIN_E_USER_IN_SET _HRESULT_TYPEDEF_(0x8011080EL) -#define COMADMIN_E_CANTRECYCLELIBRARYAPPS _HRESULT_TYPEDEF_(0x8011080FL) -#define COMADMIN_E_CANTRECYCLESERVICEAPPS _HRESULT_TYPEDEF_(0x80110811L) -#define COMADMIN_E_PROCESSALREADYRECYCLED _HRESULT_TYPEDEF_(0x80110812L) -#define COMADMIN_E_PAUSEDPROCESSMAYNOTBERECYCLED _HRESULT_TYPEDEF_(0x80110813L) -#define COMADMIN_E_CANTMAKEINPROCSERVICE _HRESULT_TYPEDEF_(0x80110814L) -#define COMADMIN_E_PROGIDINUSEBYCLSID _HRESULT_TYPEDEF_(0x80110815L) -#define COMADMIN_E_DEFAULT_PARTITION_NOT_IN_SET _HRESULT_TYPEDEF_(0x80110816L) -#define COMADMIN_E_RECYCLEDPROCESSMAYNOTBEPAUSED _HRESULT_TYPEDEF_(0x80110817L) -#define COMADMIN_E_PARTITION_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110818L) -#define COMADMIN_E_PARTITION_MSI_ONLY _HRESULT_TYPEDEF_(0x80110819L) -#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_1_0_FORMAT _HRESULT_TYPEDEF_(0x8011081AL) -#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_NONBASE_PARTITIONS _HRESULT_TYPEDEF_(0x8011081BL) -#define COMADMIN_E_COMP_MOVE_SOURCE _HRESULT_TYPEDEF_(0x8011081CL) -#define COMADMIN_E_COMP_MOVE_DEST _HRESULT_TYPEDEF_(0x8011081DL) -#define COMADMIN_E_COMP_MOVE_PRIVATE _HRESULT_TYPEDEF_(0x8011081EL) -#define COMADMIN_E_BASEPARTITION_REQUIRED_IN_SET _HRESULT_TYPEDEF_(0x8011081FL) -#define COMADMIN_E_CANNOT_ALIAS_EVENTCLASS _HRESULT_TYPEDEF_(0x80110820L) -#define COMADMIN_E_PRIVATE_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110821L) -#define COMADMIN_E_SAFERINVALID _HRESULT_TYPEDEF_(0x80110822L) -#define COMADMIN_E_REGISTRY_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110823L) -#define COMADMIN_E_PARTITIONS_DISABLED _HRESULT_TYPEDEF_(0x80110824L) -#endif /* _WINERROR_ */ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINERROR_ +#define _WINERROR_ + +#define FACILITY_WINDOWSUPDATE 36 +#define FACILITY_WINDOWS_CE 24 +#define FACILITY_WINDOWS 8 +#define FACILITY_URT 19 +#define FACILITY_UMI 22 +#define FACILITY_SXS 23 +#define FACILITY_STORAGE 3 +#define FACILITY_STATE_MANAGEMENT 34 +#define FACILITY_SSPI 9 +#define FACILITY_SCARD 16 +#define FACILITY_SETUPAPI 15 +#define FACILITY_SECURITY 9 +#define FACILITY_RPC 1 +#define FACILITY_WIN32 7 +#define FACILITY_CONTROL 10 +#define FACILITY_NULL 0 +#define FACILITY_METADIRECTORY 35 +#define FACILITY_MSMQ 14 +#define FACILITY_MEDIASERVER 13 +#define FACILITY_INTERNET 12 +#define FACILITY_ITF 4 +#define FACILITY_HTTP 25 +#define FACILITY_DPLAY 21 +#define FACILITY_DISPATCH 2 +#define FACILITY_DIRECTORYSERVICE 37 +#define FACILITY_CONFIGURATION 33 +#define FACILITY_COMPLUS 17 +#define FACILITY_CERT 11 +#define FACILITY_BACKGROUNDCOPY 32 +#define FACILITY_ACS 20 +#define FACILITY_AAF 18 +#define ERROR_SUCCESS 0L +#define NO_ERROR 0L +#define SEC_E_OK ((HRESULT)0x00000000L) +#define ERROR_INVALID_FUNCTION 1L +#define ERROR_FILE_NOT_FOUND 2L +#define ERROR_PATH_NOT_FOUND 3L +#define ERROR_TOO_MANY_OPEN_FILES 4L +#define ERROR_ACCESS_DENIED 5L +#define ERROR_INVALID_HANDLE 6L +#define ERROR_ARENA_TRASHED 7L +#define ERROR_NOT_ENOUGH_MEMORY 8L +#define ERROR_INVALID_BLOCK 9L +#define ERROR_BAD_ENVIRONMENT 10L +#define ERROR_BAD_FORMAT 11L +#define ERROR_INVALID_ACCESS 12L +#define ERROR_INVALID_DATA 13L +#define ERROR_OUTOFMEMORY 14L +#define ERROR_INVALID_DRIVE 15L +#define ERROR_CURRENT_DIRECTORY 16L +#define ERROR_NOT_SAME_DEVICE 17L +#define ERROR_NO_MORE_FILES 18L +#define ERROR_WRITE_PROTECT 19L +#define ERROR_BAD_UNIT 20L +#define ERROR_NOT_READY 21L +#define ERROR_BAD_COMMAND 22L +#define ERROR_CRC 23L +#define ERROR_BAD_LENGTH 24L +#define ERROR_SEEK 25L +#define ERROR_NOT_DOS_DISK 26L +#define ERROR_SECTOR_NOT_FOUND 27L +#define ERROR_OUT_OF_PAPER 28L +#define ERROR_WRITE_FAULT 29L +#define ERROR_READ_FAULT 30L +#define ERROR_GEN_FAILURE 31L +#define ERROR_SHARING_VIOLATION 32L +#define ERROR_LOCK_VIOLATION 33L +#define ERROR_WRONG_DISK 34L +#define ERROR_SHARING_BUFFER_EXCEEDED 36L +#define ERROR_HANDLE_EOF 38L +#define ERROR_HANDLE_DISK_FULL 39L +#define ERROR_NOT_SUPPORTED 50L +#define ERROR_REM_NOT_LIST 51L +#define ERROR_DUP_NAME 52L +#define ERROR_BAD_NETPATH 53L +#define ERROR_NETWORK_BUSY 54L +#define ERROR_DEV_NOT_EXIST 55L +#define ERROR_TOO_MANY_CMDS 56L +#define ERROR_ADAP_HDW_ERR 57L +#define ERROR_BAD_NET_RESP 58L +#define ERROR_UNEXP_NET_ERR 59L +#define ERROR_BAD_REM_ADAP 60L +#define ERROR_PRINTQ_FULL 61L +#define ERROR_NO_SPOOL_SPACE 62L +#define ERROR_PRINT_CANCELLED 63L +#define ERROR_NETNAME_DELETED 64L +#define ERROR_NETWORK_ACCESS_DENIED 65L +#define ERROR_BAD_DEV_TYPE 66L +#define ERROR_BAD_NET_NAME 67L +#define ERROR_TOO_MANY_NAMES 68L +#define ERROR_TOO_MANY_SESS 69L +#define ERROR_SHARING_PAUSED 70L +#define ERROR_REQ_NOT_ACCEP 71L +#define ERROR_REDIR_PAUSED 72L +#define ERROR_FILE_EXISTS 80L +#define ERROR_CANNOT_MAKE 82L +#define ERROR_FAIL_I24 83L +#define ERROR_OUT_OF_STRUCTURES 84L +#define ERROR_ALREADY_ASSIGNED 85L +#define ERROR_INVALID_PASSWORD 86L +#define ERROR_INVALID_PARAMETER 87L +#define ERROR_NET_WRITE_FAULT 88L +#define ERROR_NO_PROC_SLOTS 89L +#define ERROR_TOO_MANY_SEMAPHORES 100L +#define ERROR_EXCL_SEM_ALREADY_OWNED 101L +#define ERROR_SEM_IS_SET 102L +#define ERROR_TOO_MANY_SEM_REQUESTS 103L +#define ERROR_INVALID_AT_INTERRUPT_TIME 104L +#define ERROR_SEM_OWNER_DIED 105L +#define ERROR_SEM_USER_LIMIT 106L +#define ERROR_DISK_CHANGE 107L +#define ERROR_DRIVE_LOCKED 108L +#define ERROR_BROKEN_PIPE 109L +#define ERROR_OPEN_FAILED 110L +#define ERROR_BUFFER_OVERFLOW 111L +#define ERROR_DISK_FULL 112L +#define ERROR_NO_MORE_SEARCH_HANDLES 113L +#define ERROR_INVALID_TARGET_HANDLE 114L +#define ERROR_INVALID_CATEGORY 117L +#define ERROR_INVALID_VERIFY_SWITCH 118L +#define ERROR_BAD_DRIVER_LEVEL 119L +#define ERROR_CALL_NOT_IMPLEMENTED 120L +#define ERROR_SEM_TIMEOUT 121L +#define ERROR_INSUFFICIENT_BUFFER 122L +#define ERROR_INVALID_NAME 123L +#define ERROR_INVALID_LEVEL 124L +#define ERROR_NO_VOLUME_LABEL 125L +#define ERROR_MOD_NOT_FOUND 126L +#define ERROR_PROC_NOT_FOUND 127L +#define ERROR_WAIT_NO_CHILDREN 128L +#define ERROR_CHILD_NOT_COMPLETE 129L +#define ERROR_DIRECT_ACCESS_HANDLE 130L +#define ERROR_NEGATIVE_SEEK 131L +#define ERROR_SEEK_ON_DEVICE 132L +#define ERROR_IS_JOIN_TARGET 133L +#define ERROR_IS_JOINED 134L +#define ERROR_IS_SUBSTED 135L +#define ERROR_NOT_JOINED 136L +#define ERROR_NOT_SUBSTED 137L +#define ERROR_JOIN_TO_JOIN 138L +#define ERROR_SUBST_TO_SUBST 139L +#define ERROR_JOIN_TO_SUBST 140L +#define ERROR_SUBST_TO_JOIN 141L +#define ERROR_BUSY_DRIVE 142L +#define ERROR_SAME_DRIVE 143L +#define ERROR_DIR_NOT_ROOT 144L +#define ERROR_DIR_NOT_EMPTY 145L +#define ERROR_IS_SUBST_PATH 146L +#define ERROR_IS_JOIN_PATH 147L +#define ERROR_PATH_BUSY 148L +#define ERROR_IS_SUBST_TARGET 149L +#define ERROR_SYSTEM_TRACE 150L +#define ERROR_INVALID_EVENT_COUNT 151L +#define ERROR_TOO_MANY_MUXWAITERS 152L +#define ERROR_INVALID_LIST_FORMAT 153L +#define ERROR_LABEL_TOO_LONG 154L +#define ERROR_TOO_MANY_TCBS 155L +#define ERROR_SIGNAL_REFUSED 156L +#define ERROR_DISCARDED 157L +#define ERROR_NOT_LOCKED 158L +#define ERROR_BAD_THREADID_ADDR 159L +#define ERROR_BAD_ARGUMENTS 160L +#define ERROR_BAD_PATHNAME 161L +#define ERROR_SIGNAL_PENDING 162L +#define ERROR_MAX_THRDS_REACHED 164L +#define ERROR_LOCK_FAILED 167L +#define ERROR_BUSY 170L +#define ERROR_CANCEL_VIOLATION 173L +#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174L +#define ERROR_INVALID_SEGMENT_NUMBER 180L +#define ERROR_INVALID_ORDINAL 182L +#define ERROR_ALREADY_EXISTS 183L +#define ERROR_INVALID_FLAG_NUMBER 186L +#define ERROR_SEM_NOT_FOUND 187L +#define ERROR_INVALID_STARTING_CODESEG 188L +#define ERROR_INVALID_STACKSEG 189L +#define ERROR_INVALID_MODULETYPE 190L +#define ERROR_INVALID_EXE_SIGNATURE 191L +#define ERROR_EXE_MARKED_INVALID 192L +#define ERROR_BAD_EXE_FORMAT 193L +#define ERROR_ITERATED_DATA_EXCEEDS_64k 194L +#define ERROR_INVALID_MINALLOCSIZE 195L +#define ERROR_DYNLINK_FROM_INVALID_RING 196L +#define ERROR_IOPL_NOT_ENABLED 197L +#define ERROR_INVALID_SEGDPL 198L +#define ERROR_AUTODATASEG_EXCEEDS_64k 199L +#define ERROR_RING2SEG_MUST_BE_MOVABLE 200L +#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201L +#define ERROR_INFLOOP_IN_RELOC_CHAIN 202L +#define ERROR_ENVVAR_NOT_FOUND 203L +#define ERROR_NO_SIGNAL_SENT 205L +#define ERROR_FILENAME_EXCED_RANGE 206L +#define ERROR_RING2_STACK_IN_USE 207L +#define ERROR_META_EXPANSION_TOO_LONG 208L +#define ERROR_INVALID_SIGNAL_NUMBER 209L +#define ERROR_THREAD_1_INACTIVE 210L +#define ERROR_LOCKED 212L +#define ERROR_TOO_MANY_MODULES 214L +#define ERROR_NESTING_NOT_ALLOWED 215L +#define ERROR_EXE_MACHINE_TYPE_MISMATCH 216L +#define ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY 217L +#define ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY 218L +#define ERROR_BAD_PIPE 230L +#define ERROR_PIPE_BUSY 231L +#define ERROR_NO_DATA 232L +#define ERROR_PIPE_NOT_CONNECTED 233L +#define ERROR_MORE_DATA 234L +#define ERROR_VC_DISCONNECTED 240L +#define ERROR_INVALID_EA_NAME 254L +#define ERROR_EA_LIST_INCONSISTENT 255L +#define WAIT_TIMEOUT 258L +#define ERROR_NO_MORE_ITEMS 259L +#define ERROR_CANNOT_COPY 266L +#define ERROR_DIRECTORY 267L +#define ERROR_EAS_DIDNT_FIT 275L +#define ERROR_EA_FILE_CORRUPT 276L +#define ERROR_EA_TABLE_FULL 277L +#define ERROR_INVALID_EA_HANDLE 278L +#define ERROR_EAS_NOT_SUPPORTED 282L +#define ERROR_NOT_OWNER 288L +#define ERROR_TOO_MANY_POSTS 298L +#define ERROR_PARTIAL_COPY 299L +#define ERROR_OPLOCK_NOT_GRANTED 300L +#define ERROR_INVALID_OPLOCK_PROTOCOL 301L +#define ERROR_DISK_TOO_FRAGMENTED 302L +#define ERROR_DELETE_PENDING 303L +#define ERROR_MR_MID_NOT_FOUND 317L +#define ERROR_SCOPE_NOT_FOUND 318L +#define ERROR_INVALID_ADDRESS 487L +#define ERROR_ARITHMETIC_OVERFLOW 534L +#define ERROR_PIPE_CONNECTED 535L +#define ERROR_PIPE_LISTENING 536L +#define ERROR_EA_ACCESS_DENIED 994L +#define ERROR_OPERATION_ABORTED 995L +#define ERROR_IO_INCOMPLETE 996L +#define ERROR_IO_PENDING 997L +#define ERROR_NOACCESS 998L +#define ERROR_SWAPERROR 999L +#define ERROR_STACK_OVERFLOW 1001L +#define ERROR_INVALID_MESSAGE 1002L +#define ERROR_CAN_NOT_COMPLETE 1003L +#define ERROR_INVALID_FLAGS 1004L +#define ERROR_UNRECOGNIZED_VOLUME 1005L +#define ERROR_FILE_INVALID 1006L +#define ERROR_FULLSCREEN_MODE 1007L +#define ERROR_NO_TOKEN 1008L +#define ERROR_BADDB 1009L +#define ERROR_BADKEY 1010L +#define ERROR_CANTOPEN 1011L +#define ERROR_CANTREAD 1012L +#define ERROR_CANTWRITE 1013L +#define ERROR_REGISTRY_RECOVERED 1014L +#define ERROR_REGISTRY_CORRUPT 1015L +#define ERROR_REGISTRY_IO_FAILED 1016L +#define ERROR_NOT_REGISTRY_FILE 1017L +#define ERROR_KEY_DELETED 1018L +#define ERROR_NO_LOG_SPACE 1019L +#define ERROR_KEY_HAS_CHILDREN 1020L +#define ERROR_CHILD_MUST_BE_VOLATILE 1021L +#define ERROR_NOTIFY_ENUM_DIR 1022L +#define ERROR_DEPENDENT_SERVICES_RUNNING 1051L +#define ERROR_INVALID_SERVICE_CONTROL 1052L +#define ERROR_SERVICE_REQUEST_TIMEOUT 1053L +#define ERROR_SERVICE_NO_THREAD 1054L +#define ERROR_SERVICE_DATABASE_LOCKED 1055L +#define ERROR_SERVICE_ALREADY_RUNNING 1056L +#define ERROR_INVALID_SERVICE_ACCOUNT 1057L +#define ERROR_SERVICE_DISABLED 1058L +#define ERROR_CIRCULAR_DEPENDENCY 1059L +#define ERROR_SERVICE_DOES_NOT_EXIST 1060L +#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061L +#define ERROR_SERVICE_NOT_ACTIVE 1062L +#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063L +#define ERROR_EXCEPTION_IN_SERVICE 1064L +#define ERROR_DATABASE_DOES_NOT_EXIST 1065L +#define ERROR_SERVICE_SPECIFIC_ERROR 1066L +#define ERROR_PROCESS_ABORTED 1067L +#define ERROR_SERVICE_DEPENDENCY_FAIL 1068L +#define ERROR_SERVICE_LOGON_FAILED 1069L +#define ERROR_SERVICE_START_HANG 1070L +#define ERROR_INVALID_SERVICE_LOCK 1071L +#define ERROR_SERVICE_MARKED_FOR_DELETE 1072L +#define ERROR_SERVICE_EXISTS 1073L +#define ERROR_ALREADY_RUNNING_LKG 1074L +#define ERROR_SERVICE_DEPENDENCY_DELETED 1075L +#define ERROR_BOOT_ALREADY_ACCEPTED 1076L +#define ERROR_SERVICE_NEVER_STARTED 1077L +#define ERROR_DUPLICATE_SERVICE_NAME 1078L +#define ERROR_DIFFERENT_SERVICE_ACCOUNT 1079L +#define ERROR_CANNOT_DETECT_DRIVER_FAILURE 1080L +#define ERROR_CANNOT_DETECT_PROCESS_ABORT 1081L +#define ERROR_NO_RECOVERY_PROGRAM 1082L +#define ERROR_SERVICE_NOT_IN_EXE 1083L +#define ERROR_NOT_SAFEBOOT_SERVICE 1084L +#define ERROR_END_OF_MEDIA 1100L +#define ERROR_FILEMARK_DETECTED 1101L +#define ERROR_BEGINNING_OF_MEDIA 1102L +#define ERROR_SETMARK_DETECTED 1103L +#define ERROR_NO_DATA_DETECTED 1104L +#define ERROR_PARTITION_FAILURE 1105L +#define ERROR_INVALID_BLOCK_LENGTH 1106L +#define ERROR_DEVICE_NOT_PARTITIONED 1107L +#define ERROR_UNABLE_TO_LOCK_MEDIA 1108L +#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109L +#define ERROR_MEDIA_CHANGED 1110L +#define ERROR_BUS_RESET 1111L +#define ERROR_NO_MEDIA_IN_DRIVE 1112L +#define ERROR_NO_UNICODE_TRANSLATION 1113L +#define ERROR_DLL_INIT_FAILED 1114L +#define ERROR_SHUTDOWN_IN_PROGRESS 1115L +#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116L +#define ERROR_IO_DEVICE 1117L +#define ERROR_SERIAL_NO_DEVICE 1118L +#define ERROR_IRQ_BUSY 1119L +#define ERROR_MORE_WRITES 1120L +#define ERROR_COUNTER_TIMEOUT 1121L +#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122L +#define ERROR_FLOPPY_WRONG_CYLINDER 1123L +#define ERROR_FLOPPY_UNKNOWN_ERROR 1124L +#define ERROR_FLOPPY_BAD_REGISTERS 1125L +#define ERROR_DISK_RECALIBRATE_FAILED 1126L +#define ERROR_DISK_OPERATION_FAILED 1127L +#define ERROR_DISK_RESET_FAILED 1128L +#define ERROR_EOM_OVERFLOW 1129L +#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130L +#define ERROR_POSSIBLE_DEADLOCK 1131L +#define ERROR_MAPPED_ALIGNMENT 1132L +#define ERROR_SET_POWER_STATE_VETOED 1140L +#define ERROR_SET_POWER_STATE_FAILED 1141L +#define ERROR_TOO_MANY_LINKS 1142L +#define ERROR_OLD_WIN_VERSION 1150L +#define ERROR_APP_WRONG_OS 1151L +#define ERROR_SINGLE_INSTANCE_APP 1152L +#define ERROR_RMODE_APP 1153L +#define ERROR_INVALID_DLL 1154L +#define ERROR_NO_ASSOCIATION 1155L +#define ERROR_DDE_FAIL 1156L +#define ERROR_DLL_NOT_FOUND 1157L +#define ERROR_NO_MORE_USER_HANDLES 1158L +#define ERROR_MESSAGE_SYNC_ONLY 1159L +#define ERROR_SOURCE_ELEMENT_EMPTY 1160L +#define ERROR_DESTINATION_ELEMENT_FULL 1161L +#define ERROR_ILLEGAL_ELEMENT_ADDRESS 1162L +#define ERROR_MAGAZINE_NOT_PRESENT 1163L +#define ERROR_DEVICE_REINITIALIZATION_NEEDED 1164L +#define ERROR_DEVICE_REQUIRES_CLEANING 1165L +#define ERROR_DEVICE_DOOR_OPEN 1166L +#define ERROR_DEVICE_NOT_CONNECTED 1167L +#define ERROR_NOT_FOUND 1168L +#define ERROR_NO_MATCH 1169L +#define ERROR_SET_NOT_FOUND 1170L +#define ERROR_POINT_NOT_FOUND 1171L +#define ERROR_NO_TRACKING_SERVICE 1172L +#define ERROR_NO_VOLUME_ID 1173L +#define ERROR_UNABLE_TO_REMOVE_REPLACED 1175L +#define ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176L +#define ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 1177L +#define ERROR_JOURNAL_DELETE_IN_PROGRESS 1178L +#define ERROR_JOURNAL_NOT_ACTIVE 1179L +#define ERROR_POTENTIAL_FILE_FOUND 1180L +#define ERROR_JOURNAL_ENTRY_DELETED 1181L +#define ERROR_BAD_DEVICE 1200L +#define ERROR_CONNECTION_UNAVAIL 1201L +#define ERROR_DEVICE_ALREADY_REMEMBERED 1202L +#define ERROR_NO_NET_OR_BAD_PATH 1203L +#define ERROR_BAD_PROVIDER 1204L +#define ERROR_CANNOT_OPEN_PROFILE 1205L +#define ERROR_BAD_PROFILE 1206L +#define ERROR_NOT_CONTAINER 1207L +#define ERROR_EXTENDED_ERROR 1208L +#define ERROR_INVALID_GROUPNAME 1209L +#define ERROR_INVALID_COMPUTERNAME 1210L +#define ERROR_INVALID_EVENTNAME 1211L +#define ERROR_INVALID_DOMAINNAME 1212L +#define ERROR_INVALID_SERVICENAME 1213L +#define ERROR_INVALID_NETNAME 1214L +#define ERROR_INVALID_SHARENAME 1215L +#define ERROR_INVALID_PASSWORDNAME 1216L +#define ERROR_INVALID_MESSAGENAME 1217L +#define ERROR_INVALID_MESSAGEDEST 1218L +#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219L +#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220L +#define ERROR_DUP_DOMAINNAME 1221L +#define ERROR_NO_NETWORK 1222L +#define ERROR_CANCELLED 1223L +#define ERROR_USER_MAPPED_FILE 1224L +#define ERROR_CONNECTION_REFUSED 1225L +#define ERROR_GRACEFUL_DISCONNECT 1226L +#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227L +#define ERROR_ADDRESS_NOT_ASSOCIATED 1228L +#define ERROR_CONNECTION_INVALID 1229L +#define ERROR_CONNECTION_ACTIVE 1230L +#define ERROR_NETWORK_UNREACHABLE 1231L +#define ERROR_HOST_UNREACHABLE 1232L +#define ERROR_PROTOCOL_UNREACHABLE 1233L +#define ERROR_PORT_UNREACHABLE 1234L +#define ERROR_REQUEST_ABORTED 1235L +#define ERROR_CONNECTION_ABORTED 1236L +#define ERROR_RETRY 1237L +#define ERROR_CONNECTION_COUNT_LIMIT 1238L +#define ERROR_LOGIN_TIME_RESTRICTION 1239L +#define ERROR_LOGIN_WKSTA_RESTRICTION 1240L +#define ERROR_INCORRECT_ADDRESS 1241L +#define ERROR_ALREADY_REGISTERED 1242L +#define ERROR_SERVICE_NOT_FOUND 1243L +#define ERROR_NOT_AUTHENTICATED 1244L +#define ERROR_NOT_LOGGED_ON 1245L +#define ERROR_CONTINUE 1246L +#define ERROR_ALREADY_INITIALIZED 1247L +#define ERROR_NO_MORE_DEVICES 1248L +#define ERROR_NO_SUCH_SITE 1249L +#define ERROR_DOMAIN_CONTROLLER_EXISTS 1250L +#define ERROR_ONLY_IF_CONNECTED 1251L +#define ERROR_OVERRIDE_NOCHANGES 1252L +#define ERROR_BAD_USER_PROFILE 1253L +#define ERROR_NOT_SUPPORTED_ON_SBS 1254L +#define ERROR_SERVER_SHUTDOWN_IN_PROGRESS 1255L +#define ERROR_HOST_DOWN 1256L +#define ERROR_NON_ACCOUNT_SID 1257L +#define ERROR_NON_DOMAIN_SID 1258L +#define ERROR_APPHELP_BLOCK 1259L +#define ERROR_ACCESS_DISABLED_BY_POLICY 1260L +#define ERROR_REG_NAT_CONSUMPTION 1261L +#define ERROR_CSCSHARE_OFFLINE 1262L +#define ERROR_PKINIT_FAILURE 1263L +#define ERROR_SMARTCARD_SUBSYSTEM_FAILURE 1264L +#define ERROR_DOWNGRADE_DETECTED 1265L +#define ERROR_MACHINE_LOCKED 1271L +#define ERROR_CALLBACK_SUPPLIED_INVALID_DATA 1273L +#define ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED 1274L +#define ERROR_DRIVER_BLOCKED 1275L +#define ERROR_INVALID_IMPORT_OF_NON_DLL 1276L +#define ERROR_ACCESS_DISABLED_WEBBLADE 1277L +#define ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER 1278L +#define ERROR_RECOVERY_FAILURE 1279L +#define ERROR_ALREADY_FIBER 1280L +#define ERROR_ALREADY_THREAD 1281L +#define ERROR_STACK_BUFFER_OVERRUN 1282L +#define ERROR_PARAMETER_QUOTA_EXCEEDED 1283L +#define ERROR_DEBUGGER_INACTIVE 1284L +#define ERROR_DELAY_LOAD_FAILED 1285L +#define ERROR_VDM_DISALLOWED 1286L +#define ERROR_UNIDENTIFIED_ERROR 1287L +#define ERROR_NOT_ALL_ASSIGNED 1300L +#define ERROR_SOME_NOT_MAPPED 1301L +#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302L +#define ERROR_LOCAL_USER_SESSION_KEY 1303L +#define ERROR_NULL_LM_PASSWORD 1304L +#define ERROR_UNKNOWN_REVISION 1305L +#define ERROR_REVISION_MISMATCH 1306L +#define ERROR_INVALID_OWNER 1307L +#define ERROR_INVALID_PRIMARY_GROUP 1308L +#define ERROR_NO_IMPERSONATION_TOKEN 1309L +#define ERROR_CANT_DISABLE_MANDATORY 1310L +#define ERROR_NO_LOGON_SERVERS 1311L +#define ERROR_NO_SUCH_LOGON_SESSION 1312L +#define ERROR_NO_SUCH_PRIVILEGE 1313L +#define ERROR_PRIVILEGE_NOT_HELD 1314L +#define ERROR_INVALID_ACCOUNT_NAME 1315L +#define ERROR_USER_EXISTS 1316L +#define ERROR_NO_SUCH_USER 1317L +#define ERROR_GROUP_EXISTS 1318L +#define ERROR_NO_SUCH_GROUP 1319L +#define ERROR_MEMBER_IN_GROUP 1320L +#define ERROR_MEMBER_NOT_IN_GROUP 1321L +#define ERROR_LAST_ADMIN 1322L +#define ERROR_WRONG_PASSWORD 1323L +#define ERROR_ILL_FORMED_PASSWORD 1324L +#define ERROR_PASSWORD_RESTRICTION 1325L +#define ERROR_LOGON_FAILURE 1326L +#define ERROR_ACCOUNT_RESTRICTION 1327L +#define ERROR_INVALID_LOGON_HOURS 1328L +#define ERROR_INVALID_WORKSTATION 1329L +#define ERROR_PASSWORD_EXPIRED 1330L +#define ERROR_ACCOUNT_DISABLED 1331L +#define ERROR_NONE_MAPPED 1332L +#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333L +#define ERROR_LUIDS_EXHAUSTED 1334L +#define ERROR_INVALID_SUB_AUTHORITY 1335L +#define ERROR_INVALID_ACL 1336L +#define ERROR_INVALID_SID 1337L +#define ERROR_INVALID_SECURITY_DESCR 1338L +#define ERROR_BAD_INHERITANCE_ACL 1340L +#define ERROR_SERVER_DISABLED 1341L +#define ERROR_SERVER_NOT_DISABLED 1342L +#define ERROR_INVALID_ID_AUTHORITY 1343L +#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344L +#define ERROR_INVALID_GROUP_ATTRIBUTES 1345L +#define ERROR_BAD_IMPERSONATION_LEVEL 1346L +#define ERROR_CANT_OPEN_ANONYMOUS 1347L +#define ERROR_BAD_VALIDATION_CLASS 1348L +#define ERROR_BAD_TOKEN_TYPE 1349L +#define ERROR_NO_SECURITY_ON_OBJECT 1350L +#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351L +#define ERROR_INVALID_SERVER_STATE 1352L +#define ERROR_INVALID_DOMAIN_STATE 1353L +#define ERROR_INVALID_DOMAIN_ROLE 1354L +#define ERROR_NO_SUCH_DOMAIN 1355L +#define ERROR_DOMAIN_EXISTS 1356L +#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357L +#define ERROR_INTERNAL_DB_CORRUPTION 1358L +#define ERROR_INTERNAL_ERROR 1359L +#define ERROR_GENERIC_NOT_MAPPED 1360L +#define ERROR_BAD_DESCRIPTOR_FORMAT 1361L +#define ERROR_NOT_LOGON_PROCESS 1362L +#define ERROR_LOGON_SESSION_EXISTS 1363L +#define ERROR_NO_SUCH_PACKAGE 1364L +#define ERROR_BAD_LOGON_SESSION_STATE 1365L +#define ERROR_LOGON_SESSION_COLLISION 1366L +#define ERROR_INVALID_LOGON_TYPE 1367L +#define ERROR_CANNOT_IMPERSONATE 1368L +#define ERROR_RXACT_INVALID_STATE 1369L +#define ERROR_RXACT_COMMIT_FAILURE 1370L +#define ERROR_SPECIAL_ACCOUNT 1371L +#define ERROR_SPECIAL_GROUP 1372L +#define ERROR_SPECIAL_USER 1373L +#define ERROR_MEMBERS_PRIMARY_GROUP 1374L +#define ERROR_TOKEN_ALREADY_IN_USE 1375L +#define ERROR_NO_SUCH_ALIAS 1376L +#define ERROR_MEMBER_NOT_IN_ALIAS 1377L +#define ERROR_MEMBER_IN_ALIAS 1378L +#define ERROR_ALIAS_EXISTS 1379L +#define ERROR_LOGON_NOT_GRANTED 1380L +#define ERROR_TOO_MANY_SECRETS 1381L +#define ERROR_SECRET_TOO_LONG 1382L +#define ERROR_INTERNAL_DB_ERROR 1383L +#define ERROR_TOO_MANY_CONTEXT_IDS 1384L +#define ERROR_LOGON_TYPE_NOT_GRANTED 1385L +#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386L +#define ERROR_NO_SUCH_MEMBER 1387L +#define ERROR_INVALID_MEMBER 1388L +#define ERROR_TOO_MANY_SIDS 1389L +#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390L +#define ERROR_NO_INHERITANCE 1391L +#define ERROR_FILE_CORRUPT 1392L +#define ERROR_DISK_CORRUPT 1393L +#define ERROR_NO_USER_SESSION_KEY 1394L +#define ERROR_LICENSE_QUOTA_EXCEEDED 1395L +#define ERROR_WRONG_TARGET_NAME 1396L +#define ERROR_MUTUAL_AUTH_FAILED 1397L +#define ERROR_TIME_SKEW 1398L +#define ERROR_CURRENT_DOMAIN_NOT_ALLOWED 1399L +#define ERROR_INVALID_WINDOW_HANDLE 1400L +#define ERROR_INVALID_MENU_HANDLE 1401L +#define ERROR_INVALID_CURSOR_HANDLE 1402L +#define ERROR_INVALID_ACCEL_HANDLE 1403L +#define ERROR_INVALID_HOOK_HANDLE 1404L +#define ERROR_INVALID_DWP_HANDLE 1405L +#define ERROR_TLW_WITH_WSCHILD 1406L +#define ERROR_CANNOT_FIND_WND_CLASS 1407L +#define ERROR_WINDOW_OF_OTHER_THREAD 1408L +#define ERROR_HOTKEY_ALREADY_REGISTERED 1409L +#define ERROR_CLASS_ALREADY_EXISTS 1410L +#define ERROR_CLASS_DOES_NOT_EXIST 1411L +#define ERROR_CLASS_HAS_WINDOWS 1412L +#define ERROR_INVALID_INDEX 1413L +#define ERROR_INVALID_ICON_HANDLE 1414L +#define ERROR_PRIVATE_DIALOG_INDEX 1415L +#define ERROR_LISTBOX_ID_NOT_FOUND 1416L +#define ERROR_NO_WILDCARD_CHARACTERS 1417L +#define ERROR_CLIPBOARD_NOT_OPEN 1418L +#define ERROR_HOTKEY_NOT_REGISTERED 1419L +#define ERROR_WINDOW_NOT_DIALOG 1420L +#define ERROR_CONTROL_ID_NOT_FOUND 1421L +#define ERROR_INVALID_COMBOBOX_MESSAGE 1422L +#define ERROR_WINDOW_NOT_COMBOBOX 1423L +#define ERROR_INVALID_EDIT_HEIGHT 1424L +#define ERROR_DC_NOT_FOUND 1425L +#define ERROR_INVALID_HOOK_FILTER 1426L +#define ERROR_INVALID_FILTER_PROC 1427L +#define ERROR_HOOK_NEEDS_HMOD 1428L +#define ERROR_GLOBAL_ONLY_HOOK 1429L +#define ERROR_JOURNAL_HOOK_SET 1430L +#define ERROR_HOOK_NOT_INSTALLED 1431L +#define ERROR_INVALID_LB_MESSAGE 1432L +#define ERROR_SETCOUNT_ON_BAD_LB 1433L +#define ERROR_LB_WITHOUT_TABSTOPS 1434L +#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435L +#define ERROR_CHILD_WINDOW_MENU 1436L +#define ERROR_NO_SYSTEM_MENU 1437L +#define ERROR_INVALID_MSGBOX_STYLE 1438L +#define ERROR_INVALID_SPI_VALUE 1439L +#define ERROR_SCREEN_ALREADY_LOCKED 1440L +#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441L +#define ERROR_NOT_CHILD_WINDOW 1442L +#define ERROR_INVALID_GW_COMMAND 1443L +#define ERROR_INVALID_THREAD_ID 1444L +#define ERROR_NON_MDICHILD_WINDOW 1445L +#define ERROR_POPUP_ALREADY_ACTIVE 1446L +#define ERROR_NO_SCROLLBARS 1447L +#define ERROR_INVALID_SCROLLBAR_RANGE 1448L +#define ERROR_INVALID_SHOWWIN_COMMAND 1449L +#define ERROR_NO_SYSTEM_RESOURCES 1450L +#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451L +#define ERROR_PAGED_SYSTEM_RESOURCES 1452L +#define ERROR_WORKING_SET_QUOTA 1453L +#define ERROR_PAGEFILE_QUOTA 1454L +#define ERROR_COMMITMENT_LIMIT 1455L +#define ERROR_MENU_ITEM_NOT_FOUND 1456L +#define ERROR_INVALID_KEYBOARD_HANDLE 1457L +#define ERROR_HOOK_TYPE_NOT_ALLOWED 1458L +#define ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION 1459L +#define ERROR_TIMEOUT 1460L +#define ERROR_INVALID_MONITOR_HANDLE 1461L +#define ERROR_INCORRECT_SIZE 1462L +#define ERROR_EVENTLOG_FILE_CORRUPT 1500L +#define ERROR_EVENTLOG_CANT_START 1501L +#define ERROR_LOG_FILE_FULL 1502L +#define ERROR_EVENTLOG_FILE_CHANGED 1503L +#define ERROR_INSTALL_SERVICE_FAILURE 1601L +#define ERROR_INSTALL_USEREXIT 1602L +#define ERROR_INSTALL_FAILURE 1603L +#define ERROR_INSTALL_SUSPEND 1604L +#define ERROR_UNKNOWN_PRODUCT 1605L +#define ERROR_UNKNOWN_FEATURE 1606L +#define ERROR_UNKNOWN_COMPONENT 1607L +#define ERROR_UNKNOWN_PROPERTY 1608L +#define ERROR_INVALID_HANDLE_STATE 1609L +#define ERROR_BAD_CONFIGURATION 1610L +#define ERROR_INDEX_ABSENT 1611L +#define ERROR_INSTALL_SOURCE_ABSENT 1612L +#define ERROR_INSTALL_PACKAGE_VERSION 1613L +#define ERROR_PRODUCT_UNINSTALLED 1614L +#define ERROR_BAD_QUERY_SYNTAX 1615L +#define ERROR_INVALID_FIELD 1616L +#define ERROR_DEVICE_REMOVED 1617L +#define ERROR_INSTALL_ALREADY_RUNNING 1618L +#define ERROR_INSTALL_PACKAGE_OPEN_FAILED 1619L +#define ERROR_INSTALL_PACKAGE_INVALID 1620L +#define ERROR_INSTALL_UI_FAILURE 1621L +#define ERROR_INSTALL_LOG_FAILURE 1622L +#define ERROR_INSTALL_LANGUAGE_UNSUPPORTED 1623L +#define ERROR_INSTALL_TRANSFORM_FAILURE 1624L +#define ERROR_INSTALL_PACKAGE_REJECTED 1625L +#define ERROR_FUNCTION_NOT_CALLED 1626L +#define ERROR_FUNCTION_FAILED 1627L +#define ERROR_INVALID_TABLE 1628L +#define ERROR_DATATYPE_MISMATCH 1629L +#define ERROR_UNSUPPORTED_TYPE 1630L +#define ERROR_CREATE_FAILED 1631L +#define ERROR_INSTALL_TEMP_UNWRITABLE 1632L +#define ERROR_INSTALL_PLATFORM_UNSUPPORTED 1633L +#define ERROR_INSTALL_NOTUSED 1634L +#define ERROR_PATCH_PACKAGE_OPEN_FAILED 1635L +#define ERROR_PATCH_PACKAGE_INVALID 1636L +#define ERROR_PATCH_PACKAGE_UNSUPPORTED 1637L +#define ERROR_PRODUCT_VERSION 1638L +#define ERROR_INVALID_COMMAND_LINE 1639L +#define ERROR_INSTALL_REMOTE_DISALLOWED 1640L +#define ERROR_SUCCESS_REBOOT_INITIATED 1641L +#define ERROR_PATCH_TARGET_NOT_FOUND 1642L +#define ERROR_PATCH_PACKAGE_REJECTED 1643L +#define ERROR_INSTALL_TRANSFORM_REJECTED 1644L +#define ERROR_INSTALL_REMOTE_PROHIBITED 1645L +#define RPC_S_INVALID_STRING_BINDING 1700L +#define RPC_S_WRONG_KIND_OF_BINDING 1701L +#define RPC_S_INVALID_BINDING 1702L +#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703L +#define RPC_S_INVALID_RPC_PROTSEQ 1704L +#define RPC_S_INVALID_STRING_UUID 1705L +#define RPC_S_INVALID_ENDPOINT_FORMAT 1706L +#define RPC_S_INVALID_NET_ADDR 1707L +#define RPC_S_NO_ENDPOINT_FOUND 1708L +#define RPC_S_INVALID_TIMEOUT 1709L +#define RPC_S_OBJECT_NOT_FOUND 1710L +#define RPC_S_ALREADY_REGISTERED 1711L +#define RPC_S_TYPE_ALREADY_REGISTERED 1712L +#define RPC_S_ALREADY_LISTENING 1713L +#define RPC_S_NO_PROTSEQS_REGISTERED 1714L +#define RPC_S_NOT_LISTENING 1715L +#define RPC_S_UNKNOWN_MGR_TYPE 1716L +#define RPC_S_UNKNOWN_IF 1717L +#define RPC_S_NO_BINDINGS 1718L +#define RPC_S_NO_PROTSEQS 1719L +#define RPC_S_CANT_CREATE_ENDPOINT 1720L +#define RPC_S_OUT_OF_RESOURCES 1721L +#define RPC_S_SERVER_UNAVAILABLE 1722L +#define RPC_S_SERVER_TOO_BUSY 1723L +#define RPC_S_INVALID_NETWORK_OPTIONS 1724L +#define RPC_S_NO_CALL_ACTIVE 1725L +#define RPC_S_CALL_FAILED 1726L +#define RPC_S_CALL_FAILED_DNE 1727L +#define RPC_S_PROTOCOL_ERROR 1728L +#define RPC_S_UNSUPPORTED_TRANS_SYN 1730L +#define RPC_S_UNSUPPORTED_TYPE 1732L +#define RPC_S_INVALID_TAG 1733L +#define RPC_S_INVALID_BOUND 1734L +#define RPC_S_NO_ENTRY_NAME 1735L +#define RPC_S_INVALID_NAME_SYNTAX 1736L +#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737L +#define RPC_S_UUID_NO_ADDRESS 1739L +#define RPC_S_DUPLICATE_ENDPOINT 1740L +#define RPC_S_UNKNOWN_AUTHN_TYPE 1741L +#define RPC_S_MAX_CALLS_TOO_SMALL 1742L +#define RPC_S_STRING_TOO_LONG 1743L +#define RPC_S_PROTSEQ_NOT_FOUND 1744L +#define RPC_S_PROCNUM_OUT_OF_RANGE 1745L +#define RPC_S_BINDING_HAS_NO_AUTH 1746L +#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747L +#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748L +#define RPC_S_INVALID_AUTH_IDENTITY 1749L +#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750L +#define EPT_S_INVALID_ENTRY 1751L +#define EPT_S_CANT_PERFORM_OP 1752L +#define EPT_S_NOT_REGISTERED 1753L +#define RPC_S_NOTHING_TO_EXPORT 1754L +#define RPC_S_INCOMPLETE_NAME 1755L +#define RPC_S_INVALID_VERS_OPTION 1756L +#define RPC_S_NO_MORE_MEMBERS 1757L +#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758L +#define RPC_S_INTERFACE_NOT_FOUND 1759L +#define RPC_S_ENTRY_ALREADY_EXISTS 1760L +#define RPC_S_ENTRY_NOT_FOUND 1761L +#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762L +#define RPC_S_INVALID_NAF_ID 1763L +#define RPC_S_CANNOT_SUPPORT 1764L +#define RPC_S_NO_CONTEXT_AVAILABLE 1765L +#define RPC_S_INTERNAL_ERROR 1766L +#define RPC_S_ZERO_DIVIDE 1767L +#define RPC_S_ADDRESS_ERROR 1768L +#define RPC_S_FP_DIV_ZERO 1769L +#define RPC_S_FP_UNDERFLOW 1770L +#define RPC_S_FP_OVERFLOW 1771L +#define RPC_X_NO_MORE_ENTRIES 1772L +#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773L +#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774L +#define RPC_X_SS_IN_NULL_CONTEXT 1775L +#define RPC_X_SS_CONTEXT_DAMAGED 1777L +#define RPC_X_SS_HANDLES_MISMATCH 1778L +#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779L +#define RPC_X_NULL_REF_POINTER 1780L +#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781L +#define RPC_X_BYTE_COUNT_TOO_SMALL 1782L +#define RPC_X_BAD_STUB_DATA 1783L +#define ERROR_INVALID_USER_BUFFER 1784L +#define ERROR_UNRECOGNIZED_MEDIA 1785L +#define ERROR_NO_TRUST_LSA_SECRET 1786L +#define ERROR_NO_TRUST_SAM_ACCOUNT 1787L +#define ERROR_TRUSTED_DOMAIN_FAILURE 1788L +#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789L +#define ERROR_TRUST_FAILURE 1790L +#define RPC_S_CALL_IN_PROGRESS 1791L +#define ERROR_NETLOGON_NOT_STARTED 1792L +#define ERROR_ACCOUNT_EXPIRED 1793L +#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794L +#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795L +#define ERROR_UNKNOWN_PORT 1796L +#define ERROR_UNKNOWN_PRINTER_DRIVER 1797L +#define ERROR_UNKNOWN_PRINTPROCESSOR 1798L +#define ERROR_INVALID_SEPARATOR_FILE 1799L +#define ERROR_INVALID_PRIORITY 1800L +#define ERROR_INVALID_PRINTER_NAME 1801L +#define ERROR_PRINTER_ALREADY_EXISTS 1802L +#define ERROR_INVALID_PRINTER_COMMAND 1803L +#define ERROR_INVALID_DATATYPE 1804L +#define ERROR_INVALID_ENVIRONMENT 1805L +#define RPC_S_NO_MORE_BINDINGS 1806L +#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807L +#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808L +#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809L +#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810L +#define ERROR_SERVER_HAS_OPEN_HANDLES 1811L +#define ERROR_RESOURCE_DATA_NOT_FOUND 1812L +#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813L +#define ERROR_RESOURCE_NAME_NOT_FOUND 1814L +#define ERROR_RESOURCE_LANG_NOT_FOUND 1815L +#define ERROR_NOT_ENOUGH_QUOTA 1816L +#define RPC_S_NO_INTERFACES 1817L +#define RPC_S_CALL_CANCELLED 1818L +#define RPC_S_BINDING_INCOMPLETE 1819L +#define RPC_S_COMM_FAILURE 1820L +#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821L +#define RPC_S_NO_PRINC_NAME 1822L +#define RPC_S_NOT_RPC_ERROR 1823L +#define RPC_S_UUID_LOCAL_ONLY 1824L +#define RPC_S_SEC_PKG_ERROR 1825L +#define RPC_S_NOT_CANCELLED 1826L +#define RPC_X_INVALID_ES_ACTION 1827L +#define RPC_X_WRONG_ES_VERSION 1828L +#define RPC_X_WRONG_STUB_VERSION 1829L +#define RPC_X_INVALID_PIPE_OBJECT 1830L +#define RPC_X_WRONG_PIPE_ORDER 1831L +#define RPC_X_WRONG_PIPE_VERSION 1832L +#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898L +#define EPT_S_CANT_CREATE 1899L +#define RPC_S_INVALID_OBJECT 1900L +#define ERROR_INVALID_TIME 1901L +#define ERROR_INVALID_FORM_NAME 1902L +#define ERROR_INVALID_FORM_SIZE 1903L +#define ERROR_ALREADY_WAITING 1904L +#define ERROR_PRINTER_DELETED 1905L +#define ERROR_INVALID_PRINTER_STATE 1906L +#define ERROR_PASSWORD_MUST_CHANGE 1907L +#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908L +#define ERROR_ACCOUNT_LOCKED_OUT 1909L +#define OR_INVALID_OXID 1910L +#define OR_INVALID_OID 1911L +#define OR_INVALID_SET 1912L +#define RPC_S_SEND_INCOMPLETE 1913L +#define RPC_S_INVALID_ASYNC_HANDLE 1914L +#define RPC_S_INVALID_ASYNC_CALL 1915L +#define RPC_X_PIPE_CLOSED 1916L +#define RPC_X_PIPE_DISCIPLINE_ERROR 1917L +#define RPC_X_PIPE_EMPTY 1918L +#define ERROR_NO_SITENAME 1919L +#define ERROR_CANT_ACCESS_FILE 1920L +#define ERROR_CANT_RESOLVE_FILENAME 1921L +#define RPC_S_ENTRY_TYPE_MISMATCH 1922L +#define RPC_S_NOT_ALL_OBJS_EXPORTED 1923L +#define RPC_S_INTERFACE_NOT_EXPORTED 1924L +#define RPC_S_PROFILE_NOT_ADDED 1925L +#define RPC_S_PRF_ELT_NOT_ADDED 1926L +#define RPC_S_PRF_ELT_NOT_REMOVED 1927L +#define RPC_S_GRP_ELT_NOT_ADDED 1928L +#define RPC_S_GRP_ELT_NOT_REMOVED 1929L +#define ERROR_KM_DRIVER_BLOCKED 1930L +#define ERROR_CONTEXT_EXPIRED 1931L +#define ERROR_PER_USER_TRUST_QUOTA_EXCEEDED 1932L +#define ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED 1933L +#define ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED 1934L +#define ERROR_AUTHENTICATION_FIREWALL_FAILED 1935L +#define ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED 1936L +#define ERROR_INVALID_PIXEL_FORMAT 2000L +#define ERROR_BAD_DRIVER 2001L +#define ERROR_INVALID_WINDOW_STYLE 2002L +#define ERROR_METAFILE_NOT_SUPPORTED 2003L +#define ERROR_TRANSFORM_NOT_SUPPORTED 2004L +#define ERROR_CLIPPING_NOT_SUPPORTED 2005L +#define ERROR_INVALID_CMM 2010L +#define ERROR_INVALID_PROFILE 2011L +#define ERROR_TAG_NOT_FOUND 2012L +#define ERROR_TAG_NOT_PRESENT 2013L +#define ERROR_DUPLICATE_TAG 2014L +#define ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE 2015L +#define ERROR_PROFILE_NOT_FOUND 2016L +#define ERROR_INVALID_COLORSPACE 2017L +#define ERROR_ICM_NOT_ENABLED 2018L +#define ERROR_DELETING_ICM_XFORM 2019L +#define ERROR_INVALID_TRANSFORM 2020L +#define ERROR_COLORSPACE_MISMATCH 2021L +#define ERROR_INVALID_COLORINDEX 2022L +#define ERROR_CONNECTED_OTHER_PASSWORD 2108L +#define ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT 2109L +#define ERROR_BAD_USERNAME 2202L +#define ERROR_NOT_CONNECTED 2250L +#define ERROR_OPEN_FILES 2401L +#define ERROR_ACTIVE_CONNECTIONS 2402L +#define ERROR_DEVICE_IN_USE 2404L +#define ERROR_UNKNOWN_PRINT_MONITOR 3000L +#define ERROR_PRINTER_DRIVER_IN_USE 3001L +#define ERROR_SPOOL_FILE_NOT_FOUND 3002L +#define ERROR_SPL_NO_STARTDOC 3003L +#define ERROR_SPL_NO_ADDJOB 3004L +#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005L +#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006L +#define ERROR_INVALID_PRINT_MONITOR 3007L +#define ERROR_PRINT_MONITOR_IN_USE 3008L +#define ERROR_PRINTER_HAS_JOBS_QUEUED 3009L +#define ERROR_SUCCESS_REBOOT_REQUIRED 3010L +#define ERROR_SUCCESS_RESTART_REQUIRED 3011L +#define ERROR_PRINTER_NOT_FOUND 3012L +#define ERROR_PRINTER_DRIVER_WARNED 3013L +#define ERROR_PRINTER_DRIVER_BLOCKED 3014L +#define ERROR_WINS_INTERNAL 4000L +#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001L +#define ERROR_STATIC_INIT 4002L +#define ERROR_INC_BACKUP 4003L +#define ERROR_FULL_BACKUP 4004L +#define ERROR_REC_NON_EXISTENT 4005L +#define ERROR_RPL_NOT_ALLOWED 4006L +#define ERROR_DHCP_ADDRESS_CONFLICT 4100L +#define ERROR_WMI_GUID_NOT_FOUND 4200L +#define ERROR_WMI_INSTANCE_NOT_FOUND 4201L +#define ERROR_WMI_ITEMID_NOT_FOUND 4202L +#define ERROR_WMI_TRY_AGAIN 4203L +#define ERROR_WMI_DP_NOT_FOUND 4204L +#define ERROR_WMI_UNRESOLVED_INSTANCE_REF 4205L +#define ERROR_WMI_ALREADY_ENABLED 4206L +#define ERROR_WMI_GUID_DISCONNECTED 4207L +#define ERROR_WMI_SERVER_UNAVAILABLE 4208L +#define ERROR_WMI_DP_FAILED 4209L +#define ERROR_WMI_INVALID_MOF 4210L +#define ERROR_WMI_INVALID_REGINFO 4211L +#define ERROR_WMI_ALREADY_DISABLED 4212L +#define ERROR_WMI_READ_ONLY 4213L +#define ERROR_WMI_SET_FAILURE 4214L +#define ERROR_INVALID_MEDIA 4300L +#define ERROR_INVALID_LIBRARY 4301L +#define ERROR_INVALID_MEDIA_POOL 4302L +#define ERROR_DRIVE_MEDIA_MISMATCH 4303L +#define ERROR_MEDIA_OFFLINE 4304L +#define ERROR_LIBRARY_OFFLINE 4305L +#define ERROR_EMPTY 4306L +#define ERROR_NOT_EMPTY 4307L +#define ERROR_MEDIA_UNAVAILABLE 4308L +#define ERROR_RESOURCE_DISABLED 4309L +#define ERROR_INVALID_CLEANER 4310L +#define ERROR_UNABLE_TO_CLEAN 4311L +#define ERROR_OBJECT_NOT_FOUND 4312L +#define ERROR_DATABASE_FAILURE 4313L +#define ERROR_DATABASE_FULL 4314L +#define ERROR_MEDIA_INCOMPATIBLE 4315L +#define ERROR_RESOURCE_NOT_PRESENT 4316L +#define ERROR_INVALID_OPERATION 4317L +#define ERROR_MEDIA_NOT_AVAILABLE 4318L +#define ERROR_DEVICE_NOT_AVAILABLE 4319L +#define ERROR_REQUEST_REFUSED 4320L +#define ERROR_INVALID_DRIVE_OBJECT 4321L +#define ERROR_LIBRARY_FULL 4322L +#define ERROR_MEDIUM_NOT_ACCESSIBLE 4323L +#define ERROR_UNABLE_TO_LOAD_MEDIUM 4324L +#define ERROR_UNABLE_TO_INVENTORY_DRIVE 4325L +#define ERROR_UNABLE_TO_INVENTORY_SLOT 4326L +#define ERROR_UNABLE_TO_INVENTORY_TRANSPORT 4327L +#define ERROR_TRANSPORT_FULL 4328L +#define ERROR_CONTROLLING_IEPORT 4329L +#define ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA 4330L +#define ERROR_CLEANER_SLOT_SET 4331L +#define ERROR_CLEANER_SLOT_NOT_SET 4332L +#define ERROR_CLEANER_CARTRIDGE_SPENT 4333L +#define ERROR_UNEXPECTED_OMID 4334L +#define ERROR_CANT_DELETE_LAST_ITEM 4335L +#define ERROR_MESSAGE_EXCEEDS_MAX_SIZE 4336L +#define ERROR_VOLUME_CONTAINS_SYS_FILES 4337L +#define ERROR_INDIGENOUS_TYPE 4338L +#define ERROR_NO_SUPPORTING_DRIVES 4339L +#define ERROR_CLEANER_CARTRIDGE_INSTALLED 4340L +#define ERROR_IEPORT_FULL 4341L +#define ERROR_FILE_OFFLINE 4350L +#define ERROR_REMOTE_STORAGE_NOT_ACTIVE 4351L +#define ERROR_REMOTE_STORAGE_MEDIA_ERROR 4352L +#define ERROR_NOT_A_REPARSE_POINT 4390L +#define ERROR_REPARSE_ATTRIBUTE_CONFLICT 4391L +#define ERROR_INVALID_REPARSE_DATA 4392L +#define ERROR_REPARSE_TAG_INVALID 4393L +#define ERROR_REPARSE_TAG_MISMATCH 4394L +#define ERROR_VOLUME_NOT_SIS_ENABLED 4500L +#define ERROR_DEPENDENT_RESOURCE_EXISTS 5001L +#define ERROR_DEPENDENCY_NOT_FOUND 5002L +#define ERROR_DEPENDENCY_ALREADY_EXISTS 5003L +#define ERROR_RESOURCE_NOT_ONLINE 5004L +#define ERROR_HOST_NODE_NOT_AVAILABLE 5005L +#define ERROR_RESOURCE_NOT_AVAILABLE 5006L +#define ERROR_RESOURCE_NOT_FOUND 5007L +#define ERROR_SHUTDOWN_CLUSTER 5008L +#define ERROR_CANT_EVICT_ACTIVE_NODE 5009L +#define ERROR_OBJECT_ALREADY_EXISTS 5010L +#define ERROR_OBJECT_IN_LIST 5011L +#define ERROR_GROUP_NOT_AVAILABLE 5012L +#define ERROR_GROUP_NOT_FOUND 5013L +#define ERROR_GROUP_NOT_ONLINE 5014L +#define ERROR_HOST_NODE_NOT_RESOURCE_OWNER 5015L +#define ERROR_HOST_NODE_NOT_GROUP_OWNER 5016L +#define ERROR_RESMON_CREATE_FAILED 5017L +#define ERROR_RESMON_ONLINE_FAILED 5018L +#define ERROR_RESOURCE_ONLINE 5019L +#define ERROR_QUORUM_RESOURCE 5020L +#define ERROR_NOT_QUORUM_CAPABLE 5021L +#define ERROR_CLUSTER_SHUTTING_DOWN 5022L +#define ERROR_INVALID_STATE 5023L +#define ERROR_RESOURCE_PROPERTIES_STORED 5024L +#define ERROR_NOT_QUORUM_CLASS 5025L +#define ERROR_CORE_RESOURCE 5026L +#define ERROR_QUORUM_RESOURCE_ONLINE_FAILED 5027L +#define ERROR_QUORUMLOG_OPEN_FAILED 5028L +#define ERROR_CLUSTERLOG_CORRUPT 5029L +#define ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE 5030L +#define ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE 5031L +#define ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND 5032L +#define ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE 5033L +#define ERROR_QUORUM_OWNER_ALIVE 5034L +#define ERROR_NETWORK_NOT_AVAILABLE 5035L +#define ERROR_NODE_NOT_AVAILABLE 5036L +#define ERROR_ALL_NODES_NOT_AVAILABLE 5037L +#define ERROR_RESOURCE_FAILED 5038L +#define ERROR_CLUSTER_INVALID_NODE 5039L +#define ERROR_CLUSTER_NODE_EXISTS 5040L +#define ERROR_CLUSTER_JOIN_IN_PROGRESS 5041L +#define ERROR_CLUSTER_NODE_NOT_FOUND 5042L +#define ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND 5043L +#define ERROR_CLUSTER_NETWORK_EXISTS 5044L +#define ERROR_CLUSTER_NETWORK_NOT_FOUND 5045L +#define ERROR_CLUSTER_NETINTERFACE_EXISTS 5046L +#define ERROR_CLUSTER_NETINTERFACE_NOT_FOUND 5047L +#define ERROR_CLUSTER_INVALID_REQUEST 5048L +#define ERROR_CLUSTER_INVALID_NETWORK_PROVIDER 5049L +#define ERROR_CLUSTER_NODE_DOWN 5050L +#define ERROR_CLUSTER_NODE_UNREACHABLE 5051L +#define ERROR_CLUSTER_NODE_NOT_MEMBER 5052L +#define ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS 5053L +#define ERROR_CLUSTER_INVALID_NETWORK 5054L +#define ERROR_CLUSTER_NODE_UP 5056L +#define ERROR_CLUSTER_IPADDR_IN_USE 5057L +#define ERROR_CLUSTER_NODE_NOT_PAUSED 5058L +#define ERROR_CLUSTER_NO_SECURITY_CONTEXT 5059L +#define ERROR_CLUSTER_NETWORK_NOT_INTERNAL 5060L +#define ERROR_CLUSTER_NODE_ALREADY_UP 5061L +#define ERROR_CLUSTER_NODE_ALREADY_DOWN 5062L +#define ERROR_CLUSTER_NETWORK_ALREADY_ONLINE 5063L +#define ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE 5064L +#define ERROR_CLUSTER_NODE_ALREADY_MEMBER 5065L +#define ERROR_CLUSTER_LAST_INTERNAL_NETWORK 5066L +#define ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS 5067L +#define ERROR_INVALID_OPERATION_ON_QUORUM 5068L +#define ERROR_DEPENDENCY_NOT_ALLOWED 5069L +#define ERROR_CLUSTER_NODE_PAUSED 5070L +#define ERROR_NODE_CANT_HOST_RESOURCE 5071L +#define ERROR_CLUSTER_NODE_NOT_READY 5072L +#define ERROR_CLUSTER_NODE_SHUTTING_DOWN 5073L +#define ERROR_CLUSTER_JOIN_ABORTED 5074L +#define ERROR_CLUSTER_INCOMPATIBLE_VERSIONS 5075L +#define ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED 5076L +#define ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED 5077L +#define ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND 5078L +#define ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED 5079L +#define ERROR_CLUSTER_RESNAME_NOT_FOUND 5080L +#define ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED 5081L +#define ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST 5082L +#define ERROR_CLUSTER_DATABASE_SEQMISMATCH 5083L +#define ERROR_RESMON_INVALID_STATE 5084L +#define ERROR_CLUSTER_GUM_NOT_LOCKER 5085L +#define ERROR_QUORUM_DISK_NOT_FOUND 5086L +#define ERROR_DATABASE_BACKUP_CORRUPT 5087L +#define ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT 5088L +#define ERROR_RESOURCE_PROPERTY_UNCHANGEABLE 5089L +#define ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE 5890L +#define ERROR_CLUSTER_QUORUMLOG_NOT_FOUND 5891L +#define ERROR_CLUSTER_MEMBERSHIP_HALT 5892L +#define ERROR_CLUSTER_INSTANCE_ID_MISMATCH 5893L +#define ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP 5894L +#define ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH 5895L +#define ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP 5896L +#define ERROR_CLUSTER_PARAMETER_MISMATCH 5897L +#define ERROR_NODE_CANNOT_BE_CLUSTERED 5898L +#define ERROR_CLUSTER_WRONG_OS_VERSION 5899L +#define ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME 5900L +#define ERROR_CLUSCFG_ALREADY_COMMITTED 5901L +#define ERROR_CLUSCFG_ROLLBACK_FAILED 5902L +#define ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT 5903L +#define ERROR_CLUSTER_OLD_VERSION 5904L +#define ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME 5905L +#define ERROR_ENCRYPTION_FAILED 6000L +#define ERROR_DECRYPTION_FAILED 6001L +#define ERROR_FILE_ENCRYPTED 6002L +#define ERROR_NO_RECOVERY_POLICY 6003L +#define ERROR_NO_EFS 6004L +#define ERROR_WRONG_EFS 6005L +#define ERROR_NO_USER_KEYS 6006L +#define ERROR_FILE_NOT_ENCRYPTED 6007L +#define ERROR_NOT_EXPORT_FORMAT 6008L +#define ERROR_FILE_READ_ONLY 6009L +#define ERROR_DIR_EFS_DISALLOWED 6010L +#define ERROR_EFS_SERVER_NOT_TRUSTED 6011L +#define ERROR_BAD_RECOVERY_POLICY 6012L +#define ERROR_EFS_ALG_BLOB_TOO_BIG 6013L +#define ERROR_VOLUME_NOT_SUPPORT_EFS 6014L +#define ERROR_EFS_DISABLED 6015L +#define ERROR_EFS_VERSION_NOT_SUPPORT 6016L +#define ERROR_NO_BROWSER_SERVERS_FOUND 6118L +#define SCHED_E_SERVICE_NOT_LOCALSYSTEM 6200L +#define ERROR_CTX_WINSTATION_NAME_INVALID 7001L +#define ERROR_CTX_INVALID_PD 7002L +#define ERROR_CTX_PD_NOT_FOUND 7003L +#define ERROR_CTX_WD_NOT_FOUND 7004L +#define ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY 7005L +#define ERROR_CTX_SERVICE_NAME_COLLISION 7006L +#define ERROR_CTX_CLOSE_PENDING 7007L +#define ERROR_CTX_NO_OUTBUF 7008L +#define ERROR_CTX_MODEM_INF_NOT_FOUND 7009L +#define ERROR_CTX_INVALID_MODEMNAME 7010L +#define ERROR_CTX_MODEM_RESPONSE_ERROR 7011L +#define ERROR_CTX_MODEM_RESPONSE_TIMEOUT 7012L +#define ERROR_CTX_MODEM_RESPONSE_NO_CARRIER 7013L +#define ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE 7014L +#define ERROR_CTX_MODEM_RESPONSE_BUSY 7015L +#define ERROR_CTX_MODEM_RESPONSE_VOICE 7016L +#define ERROR_CTX_TD_ERROR 7017L +#define ERROR_CTX_WINSTATION_NOT_FOUND 7022L +#define ERROR_CTX_WINSTATION_ALREADY_EXISTS 7023L +#define ERROR_CTX_WINSTATION_BUSY 7024L +#define ERROR_CTX_BAD_VIDEO_MODE 7025L +#define ERROR_CTX_GRAPHICS_INVALID 7035L +#define ERROR_CTX_LOGON_DISABLED 7037L +#define ERROR_CTX_NOT_CONSOLE 7038L +#define ERROR_CTX_CLIENT_QUERY_TIMEOUT 7040L +#define ERROR_CTX_CONSOLE_DISCONNECT 7041L +#define ERROR_CTX_CONSOLE_CONNECT 7042L +#define ERROR_CTX_SHADOW_DENIED 7044L +#define ERROR_CTX_WINSTATION_ACCESS_DENIED 7045L +#define ERROR_CTX_INVALID_WD 7049L +#define ERROR_CTX_SHADOW_INVALID 7050L +#define ERROR_CTX_SHADOW_DISABLED 7051L +#define ERROR_CTX_CLIENT_LICENSE_IN_USE 7052L +#define ERROR_CTX_CLIENT_LICENSE_NOT_SET 7053L +#define ERROR_CTX_LICENSE_NOT_AVAILABLE 7054L +#define ERROR_CTX_LICENSE_CLIENT_INVALID 7055L +#define ERROR_CTX_LICENSE_EXPIRED 7056L +#define ERROR_CTX_SHADOW_NOT_RUNNING 7057L +#define ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE 7058L +#define ERROR_ACTIVATION_COUNT_EXCEEDED 7059L +#define FRS_ERR_INVALID_API_SEQUENCE 8001L +#define FRS_ERR_STARTING_SERVICE 8002L +#define FRS_ERR_STOPPING_SERVICE 8003L +#define FRS_ERR_INTERNAL_API 8004L +#define FRS_ERR_INTERNAL 8005L +#define FRS_ERR_SERVICE_COMM 8006L +#define FRS_ERR_INSUFFICIENT_PRIV 8007L +#define FRS_ERR_AUTHENTICATION 8008L +#define FRS_ERR_PARENT_INSUFFICIENT_PRIV 8009L +#define FRS_ERR_PARENT_AUTHENTICATION 8010L +#define FRS_ERR_CHILD_TO_PARENT_COMM 8011L +#define FRS_ERR_PARENT_TO_CHILD_COMM 8012L +#define FRS_ERR_SYSVOL_POPULATE 8013L +#define FRS_ERR_SYSVOL_POPULATE_TIMEOUT 8014L +#define FRS_ERR_SYSVOL_IS_BUSY 8015L +#define FRS_ERR_SYSVOL_DEMOTE 8016L +#define FRS_ERR_INVALID_SERVICE_PARAMETER 8017L +#define DS_S_SUCCESS NO_ERROR +#define ERROR_DS_NOT_INSTALLED 8200L +#define ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY 8201L +#define ERROR_DS_NO_ATTRIBUTE_OR_VALUE 8202L +#define ERROR_DS_INVALID_ATTRIBUTE_SYNTAX 8203L +#define ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED 8204L +#define ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS 8205L +#define ERROR_DS_BUSY 8206L +#define ERROR_DS_UNAVAILABLE 8207L +#define ERROR_DS_NO_RIDS_ALLOCATED 8208L +#define ERROR_DS_NO_MORE_RIDS 8209L +#define ERROR_DS_INCORRECT_ROLE_OWNER 8210L +#define ERROR_DS_RIDMGR_INIT_ERROR 8211L +#define ERROR_DS_OBJ_CLASS_VIOLATION 8212L +#define ERROR_DS_CANT_ON_NON_LEAF 8213L +#define ERROR_DS_CANT_ON_RDN 8214L +#define ERROR_DS_CANT_MOD_OBJ_CLASS 8215L +#define ERROR_DS_CROSS_DOM_MOVE_ERROR 8216L +#define ERROR_DS_GC_NOT_AVAILABLE 8217L +#define ERROR_SHARED_POLICY 8218L +#define ERROR_POLICY_OBJECT_NOT_FOUND 8219L +#define ERROR_POLICY_ONLY_IN_DS 8220L +#define ERROR_PROMOTION_ACTIVE 8221L +#define ERROR_NO_PROMOTION_ACTIVE 8222L +#define ERROR_DS_OPERATIONS_ERROR 8224L +#define ERROR_DS_PROTOCOL_ERROR 8225L +#define ERROR_DS_TIMELIMIT_EXCEEDED 8226L +#define ERROR_DS_SIZELIMIT_EXCEEDED 8227L +#define ERROR_DS_ADMIN_LIMIT_EXCEEDED 8228L +#define ERROR_DS_COMPARE_FALSE 8229L +#define ERROR_DS_COMPARE_TRUE 8230L +#define ERROR_DS_AUTH_METHOD_NOT_SUPPORTED 8231L +#define ERROR_DS_STRONG_AUTH_REQUIRED 8232L +#define ERROR_DS_INAPPROPRIATE_AUTH 8233L +#define ERROR_DS_AUTH_UNKNOWN 8234L +#define ERROR_DS_REFERRAL 8235L +#define ERROR_DS_UNAVAILABLE_CRIT_EXTENSION 8236L +#define ERROR_DS_CONFIDENTIALITY_REQUIRED 8237L +#define ERROR_DS_INAPPROPRIATE_MATCHING 8238L +#define ERROR_DS_CONSTRAINT_VIOLATION 8239L +#define ERROR_DS_NO_SUCH_OBJECT 8240L +#define ERROR_DS_ALIAS_PROBLEM 8241L +#define ERROR_DS_INVALID_DN_SYNTAX 8242L +#define ERROR_DS_IS_LEAF 8243L +#define ERROR_DS_ALIAS_DEREF_PROBLEM 8244L +#define ERROR_DS_UNWILLING_TO_PERFORM 8245L +#define ERROR_DS_LOOP_DETECT 8246L +#define ERROR_DS_NAMING_VIOLATION 8247L +#define ERROR_DS_OBJECT_RESULTS_TOO_LARGE 8248L +#define ERROR_DS_AFFECTS_MULTIPLE_DSAS 8249L +#define ERROR_DS_SERVER_DOWN 8250L +#define ERROR_DS_LOCAL_ERROR 8251L +#define ERROR_DS_ENCODING_ERROR 8252L +#define ERROR_DS_DECODING_ERROR 8253L +#define ERROR_DS_FILTER_UNKNOWN 8254L +#define ERROR_DS_PARAM_ERROR 8255L +#define ERROR_DS_NOT_SUPPORTED 8256L +#define ERROR_DS_NO_RESULTS_RETURNED 8257L +#define ERROR_DS_CONTROL_NOT_FOUND 8258L +#define ERROR_DS_CLIENT_LOOP 8259L +#define ERROR_DS_REFERRAL_LIMIT_EXCEEDED 8260L +#define ERROR_DS_SORT_CONTROL_MISSING 8261L +#define ERROR_DS_OFFSET_RANGE_ERROR 8262L +#define ERROR_DS_ROOT_MUST_BE_NC 8301L +#define ERROR_DS_ADD_REPLICA_INHIBITED 8302L +#define ERROR_DS_ATT_NOT_DEF_IN_SCHEMA 8303L +#define ERROR_DS_MAX_OBJ_SIZE_EXCEEDED 8304L +#define ERROR_DS_OBJ_STRING_NAME_EXISTS 8305L +#define ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA 8306L +#define ERROR_DS_RDN_DOESNT_MATCH_SCHEMA 8307L +#define ERROR_DS_NO_REQUESTED_ATTS_FOUND 8308L +#define ERROR_DS_USER_BUFFER_TO_SMALL 8309L +#define ERROR_DS_ATT_IS_NOT_ON_OBJ 8310L +#define ERROR_DS_ILLEGAL_MOD_OPERATION 8311L +#define ERROR_DS_OBJ_TOO_LARGE 8312L +#define ERROR_DS_BAD_INSTANCE_TYPE 8313L +#define ERROR_DS_MASTERDSA_REQUIRED 8314L +#define ERROR_DS_OBJECT_CLASS_REQUIRED 8315L +#define ERROR_DS_MISSING_REQUIRED_ATT 8316L +#define ERROR_DS_ATT_NOT_DEF_FOR_CLASS 8317L +#define ERROR_DS_ATT_ALREADY_EXISTS 8318L +#define ERROR_DS_CANT_ADD_ATT_VALUES 8320L +#define ERROR_DS_SINGLE_VALUE_CONSTRAINT 8321L +#define ERROR_DS_RANGE_CONSTRAINT 8322L +#define ERROR_DS_ATT_VAL_ALREADY_EXISTS 8323L +#define ERROR_DS_CANT_REM_MISSING_ATT 8324L +#define ERROR_DS_CANT_REM_MISSING_ATT_VAL 8325L +#define ERROR_DS_ROOT_CANT_BE_SUBREF 8326L +#define ERROR_DS_NO_CHAINING 8327L +#define ERROR_DS_NO_CHAINED_EVAL 8328L +#define ERROR_DS_NO_PARENT_OBJECT 8329L +#define ERROR_DS_PARENT_IS_AN_ALIAS 8330L +#define ERROR_DS_CANT_MIX_MASTER_AND_REPS 8331L +#define ERROR_DS_CHILDREN_EXIST 8332L +#define ERROR_DS_OBJ_NOT_FOUND 8333L +#define ERROR_DS_ALIASED_OBJ_MISSING 8334L +#define ERROR_DS_BAD_NAME_SYNTAX 8335L +#define ERROR_DS_ALIAS_POINTS_TO_ALIAS 8336L +#define ERROR_DS_CANT_DEREF_ALIAS 8337L +#define ERROR_DS_OUT_OF_SCOPE 8338L +#define ERROR_DS_OBJECT_BEING_REMOVED 8339L +#define ERROR_DS_CANT_DELETE_DSA_OBJ 8340L +#define ERROR_DS_GENERIC_ERROR 8341L +#define ERROR_DS_DSA_MUST_BE_INT_MASTER 8342L +#define ERROR_DS_CLASS_NOT_DSA 8343L +#define ERROR_DS_INSUFF_ACCESS_RIGHTS 8344L +#define ERROR_DS_ILLEGAL_SUPERIOR 8345L +#define ERROR_DS_ATTRIBUTE_OWNED_BY_SAM 8346L +#define ERROR_DS_NAME_TOO_MANY_PARTS 8347L +#define ERROR_DS_NAME_TOO_LONG 8348L +#define ERROR_DS_NAME_VALUE_TOO_LONG 8349L +#define ERROR_DS_NAME_UNPARSEABLE 8350L +#define ERROR_DS_NAME_TYPE_UNKNOWN 8351L +#define ERROR_DS_NOT_AN_OBJECT 8352L +#define ERROR_DS_SEC_DESC_TOO_SHORT 8353L +#define ERROR_DS_SEC_DESC_INVALID 8354L +#define ERROR_DS_NO_DELETED_NAME 8355L +#define ERROR_DS_SUBREF_MUST_HAVE_PARENT 8356L +#define ERROR_DS_NCNAME_MUST_BE_NC 8357L +#define ERROR_DS_CANT_ADD_SYSTEM_ONLY 8358L +#define ERROR_DS_CLASS_MUST_BE_CONCRETE 8359L +#define ERROR_DS_INVALID_DMD 8360L +#define ERROR_DS_OBJ_GUID_EXISTS 8361L +#define ERROR_DS_NOT_ON_BACKLINK 8362L +#define ERROR_DS_NO_CROSSREF_FOR_NC 8363L +#define ERROR_DS_SHUTTING_DOWN 8364L +#define ERROR_DS_UNKNOWN_OPERATION 8365L +#define ERROR_DS_INVALID_ROLE_OWNER 8366L +#define ERROR_DS_COULDNT_CONTACT_FSMO 8367L +#define ERROR_DS_CROSS_NC_DN_RENAME 8368L +#define ERROR_DS_CANT_MOD_SYSTEM_ONLY 8369L +#define ERROR_DS_REPLICATOR_ONLY 8370L +#define ERROR_DS_OBJ_CLASS_NOT_DEFINED 8371L +#define ERROR_DS_OBJ_CLASS_NOT_SUBCLASS 8372L +#define ERROR_DS_NAME_REFERENCE_INVALID 8373L +#define ERROR_DS_CROSS_REF_EXISTS 8374L +#define ERROR_DS_CANT_DEL_MASTER_CROSSREF 8375L +#define ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD 8376L +#define ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX 8377L +#define ERROR_DS_DUP_RDN 8378L +#define ERROR_DS_DUP_OID 8379L +#define ERROR_DS_DUP_MAPI_ID 8380L +#define ERROR_DS_DUP_SCHEMA_ID_GUID 8381L +#define ERROR_DS_DUP_LDAP_DISPLAY_NAME 8382L +#define ERROR_DS_SEMANTIC_ATT_TEST 8383L +#define ERROR_DS_SYNTAX_MISMATCH 8384L +#define ERROR_DS_EXISTS_IN_MUST_HAVE 8385L +#define ERROR_DS_EXISTS_IN_MAY_HAVE 8386L +#define ERROR_DS_NONEXISTENT_MAY_HAVE 8387L +#define ERROR_DS_NONEXISTENT_MUST_HAVE 8388L +#define ERROR_DS_AUX_CLS_TEST_FAIL 8389L +#define ERROR_DS_NONEXISTENT_POSS_SUP 8390L +#define ERROR_DS_SUB_CLS_TEST_FAIL 8391L +#define ERROR_DS_BAD_RDN_ATT_ID_SYNTAX 8392L +#define ERROR_DS_EXISTS_IN_AUX_CLS 8393L +#define ERROR_DS_EXISTS_IN_SUB_CLS 8394L +#define ERROR_DS_EXISTS_IN_POSS_SUP 8395L +#define ERROR_DS_RECALCSCHEMA_FAILED 8396L +#define ERROR_DS_TREE_DELETE_NOT_FINISHED 8397L +#define ERROR_DS_CANT_DELETE 8398L +#define ERROR_DS_ATT_SCHEMA_REQ_ID 8399L +#define ERROR_DS_BAD_ATT_SCHEMA_SYNTAX 8400L +#define ERROR_DS_CANT_CACHE_ATT 8401L +#define ERROR_DS_CANT_CACHE_CLASS 8402L +#define ERROR_DS_CANT_REMOVE_ATT_CACHE 8403L +#define ERROR_DS_CANT_REMOVE_CLASS_CACHE 8404L +#define ERROR_DS_CANT_RETRIEVE_DN 8405L +#define ERROR_DS_MISSING_SUPREF 8406L +#define ERROR_DS_CANT_RETRIEVE_INSTANCE 8407L +#define ERROR_DS_CODE_INCONSISTENCY 8408L +#define ERROR_DS_DATABASE_ERROR 8409L +#define ERROR_DS_GOVERNSID_MISSING 8410L +#define ERROR_DS_MISSING_EXPECTED_ATT 8411L +#define ERROR_DS_NCNAME_MISSING_CR_REF 8412L +#define ERROR_DS_SECURITY_CHECKING_ERROR 8413L +#define ERROR_DS_SCHEMA_NOT_LOADED 8414L +#define ERROR_DS_SCHEMA_ALLOC_FAILED 8415L +#define ERROR_DS_ATT_SCHEMA_REQ_SYNTAX 8416L +#define ERROR_DS_GCVERIFY_ERROR 8417L +#define ERROR_DS_DRA_SCHEMA_MISMATCH 8418L +#define ERROR_DS_CANT_FIND_DSA_OBJ 8419L +#define ERROR_DS_CANT_FIND_EXPECTED_NC 8420L +#define ERROR_DS_CANT_FIND_NC_IN_CACHE 8421L +#define ERROR_DS_CANT_RETRIEVE_CHILD 8422L +#define ERROR_DS_SECURITY_ILLEGAL_MODIFY 8423L +#define ERROR_DS_CANT_REPLACE_HIDDEN_REC 8424L +#define ERROR_DS_BAD_HIERARCHY_FILE 8425L +#define ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED 8426L +#define ERROR_DS_CONFIG_PARAM_MISSING 8427L +#define ERROR_DS_COUNTING_AB_INDICES_FAILED 8428L +#define ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED 8429L +#define ERROR_DS_INTERNAL_FAILURE 8430L +#define ERROR_DS_UNKNOWN_ERROR 8431L +#define ERROR_DS_ROOT_REQUIRES_CLASS_TOP 8432L +#define ERROR_DS_REFUSING_FSMO_ROLES 8433L +#define ERROR_DS_MISSING_FSMO_SETTINGS 8434L +#define ERROR_DS_UNABLE_TO_SURRENDER_ROLES 8435L +#define ERROR_DS_DRA_GENERIC 8436L +#define ERROR_DS_DRA_INVALID_PARAMETER 8437L +#define ERROR_DS_DRA_BUSY 8438L +#define ERROR_DS_DRA_BAD_DN 8439L +#define ERROR_DS_DRA_BAD_NC 8440L +#define ERROR_DS_DRA_DN_EXISTS 8441L +#define ERROR_DS_DRA_INTERNAL_ERROR 8442L +#define ERROR_DS_DRA_INCONSISTENT_DIT 8443L +#define ERROR_DS_DRA_CONNECTION_FAILED 8444L +#define ERROR_DS_DRA_BAD_INSTANCE_TYPE 8445L +#define ERROR_DS_DRA_OUT_OF_MEM 8446L +#define ERROR_DS_DRA_MAIL_PROBLEM 8447L +#define ERROR_DS_DRA_REF_ALREADY_EXISTS 8448L +#define ERROR_DS_DRA_REF_NOT_FOUND 8449L +#define ERROR_DS_DRA_OBJ_IS_REP_SOURCE 8450L +#define ERROR_DS_DRA_DB_ERROR 8451L +#define ERROR_DS_DRA_NO_REPLICA 8452L +#define ERROR_DS_DRA_ACCESS_DENIED 8453L +#define ERROR_DS_DRA_NOT_SUPPORTED 8454L +#define ERROR_DS_DRA_RPC_CANCELLED 8455L +#define ERROR_DS_DRA_SOURCE_DISABLED 8456L +#define ERROR_DS_DRA_SINK_DISABLED 8457L +#define ERROR_DS_DRA_NAME_COLLISION 8458L +#define ERROR_DS_DRA_SOURCE_REINSTALLED 8459L +#define ERROR_DS_DRA_MISSING_PARENT 8460L +#define ERROR_DS_DRA_PREEMPTED 8461L +#define ERROR_DS_DRA_ABANDON_SYNC 8462L +#define ERROR_DS_DRA_SHUTDOWN 8463L +#define ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET 8464L +#define ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA 8465L +#define ERROR_DS_DRA_EXTN_CONNECTION_FAILED 8466L +#define ERROR_DS_INSTALL_SCHEMA_MISMATCH 8467L +#define ERROR_DS_DUP_LINK_ID 8468L +#define ERROR_DS_NAME_ERROR_RESOLVING 8469L +#define ERROR_DS_NAME_ERROR_NOT_FOUND 8470L +#define ERROR_DS_NAME_ERROR_NOT_UNIQUE 8471L +#define ERROR_DS_NAME_ERROR_NO_MAPPING 8472L +#define ERROR_DS_NAME_ERROR_DOMAIN_ONLY 8473L +#define ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING 8474L +#define ERROR_DS_CONSTRUCTED_ATT_MOD 8475L +#define ERROR_DS_WRONG_OM_OBJ_CLASS 8476L +#define ERROR_DS_DRA_REPL_PENDING 8477L +#define ERROR_DS_DS_REQUIRED 8478L +#define ERROR_DS_INVALID_LDAP_DISPLAY_NAME 8479L +#define ERROR_DS_NON_BASE_SEARCH 8480L +#define ERROR_DS_CANT_RETRIEVE_ATTS 8481L +#define ERROR_DS_BACKLINK_WITHOUT_LINK 8482L +#define ERROR_DS_EPOCH_MISMATCH 8483L +#define ERROR_DS_SRC_NAME_MISMATCH 8484L +#define ERROR_DS_SRC_AND_DST_NC_IDENTICAL 8485L +#define ERROR_DS_DST_NC_MISMATCH 8486L +#define ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC 8487L +#define ERROR_DS_SRC_GUID_MISMATCH 8488L +#define ERROR_DS_CANT_MOVE_DELETED_OBJECT 8489L +#define ERROR_DS_PDC_OPERATION_IN_PROGRESS 8490L +#define ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD 8491L +#define ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION 8492L +#define ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS 8493L +#define ERROR_DS_NC_MUST_HAVE_NC_PARENT 8494L +#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE 8495L +#define ERROR_DS_DST_DOMAIN_NOT_NATIVE 8496L +#define ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER 8497L +#define ERROR_DS_CANT_MOVE_ACCOUNT_GROUP 8498L +#define ERROR_DS_CANT_MOVE_RESOURCE_GROUP 8499L +#define ERROR_DS_INVALID_SEARCH_FLAG 8500L +#define ERROR_DS_NO_TREE_DELETE_ABOVE_NC 8501L +#define ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE 8502L +#define ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE 8503L +#define ERROR_DS_SAM_INIT_FAILURE 8504L +#define ERROR_DS_SENSITIVE_GROUP_VIOLATION 8505L +#define ERROR_DS_CANT_MOD_PRIMARYGROUPID 8506L +#define ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD 8507L +#define ERROR_DS_NONSAFE_SCHEMA_CHANGE 8508L +#define ERROR_DS_SCHEMA_UPDATE_DISALLOWED 8509L +#define ERROR_DS_CANT_CREATE_UNDER_SCHEMA 8510L +#define ERROR_DS_INSTALL_NO_SRC_SCH_VERSION 8511L +#define ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE 8512L +#define ERROR_DS_INVALID_GROUP_TYPE 8513L +#define ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN 8514L +#define ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN 8515L +#define ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER 8516L +#define ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER 8517L +#define ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER 8518L +#define ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER 8519L +#define ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER 8520L +#define ERROR_DS_HAVE_PRIMARY_MEMBERS 8521L +#define ERROR_DS_STRING_SD_CONVERSION_FAILED 8522L +#define ERROR_DS_NAMING_MASTER_GC 8523L +#define ERROR_DS_DNS_LOOKUP_FAILURE 8524L +#define ERROR_DS_COULDNT_UPDATE_SPNS 8525L +#define ERROR_DS_CANT_RETRIEVE_SD 8526L +#define ERROR_DS_KEY_NOT_UNIQUE 8527L +#define ERROR_DS_WRONG_LINKED_ATT_SYNTAX 8528L +#define ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD 8529L +#define ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY 8530L +#define ERROR_DS_CANT_START 8531L +#define ERROR_DS_INIT_FAILURE 8532L +#define ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION 8533L +#define ERROR_DS_SOURCE_DOMAIN_IN_FOREST 8534L +#define ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST 8535L +#define ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED 8536L +#define ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN 8537L +#define ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER 8538L +#define ERROR_DS_SRC_SID_EXISTS_IN_FOREST 8539L +#define ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH 8540L +#define ERROR_SAM_INIT_FAILURE 8541L +#define ERROR_DS_DRA_SCHEMA_INFO_SHIP 8542L +#define ERROR_DS_DRA_SCHEMA_CONFLICT 8543L +#define ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT 8544L +#define ERROR_DS_DRA_OBJ_NC_MISMATCH 8545L +#define ERROR_DS_NC_STILL_HAS_DSAS 8546L +#define ERROR_DS_GC_REQUIRED 8547L +#define ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY 8548L +#define ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS 8549L +#define ERROR_DS_CANT_ADD_TO_GC 8550L +#define ERROR_DS_NO_CHECKPOINT_WITH_PDC 8551L +#define ERROR_DS_SOURCE_AUDITING_NOT_ENABLED 8552L +#define ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC 8553L +#define ERROR_DS_INVALID_NAME_FOR_SPN 8554L +#define ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS 8555L +#define ERROR_DS_UNICODEPWD_NOT_IN_QUOTES 8556L +#define ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED 8557L +#define ERROR_DS_MUST_BE_RUN_ON_DST_DC 8558L +#define ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER 8559L +#define ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ 8560L +#define ERROR_DS_INIT_FAILURE_CONSOLE 8561L +#define ERROR_DS_SAM_INIT_FAILURE_CONSOLE 8562L +#define ERROR_DS_FOREST_VERSION_TOO_HIGH 8563L +#define ERROR_DS_DOMAIN_VERSION_TOO_HIGH 8564L +#define ERROR_DS_FOREST_VERSION_TOO_LOW 8565L +#define ERROR_DS_DOMAIN_VERSION_TOO_LOW 8566L +#define ERROR_DS_INCOMPATIBLE_VERSION 8567L +#define ERROR_DS_LOW_DSA_VERSION 8568L +#define ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN 8569L +#define ERROR_DS_NOT_SUPPORTED_SORT_ORDER 8570L +#define ERROR_DS_NAME_NOT_UNIQUE 8571L +#define ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4 8572L +#define ERROR_DS_OUT_OF_VERSION_STORE 8573L +#define ERROR_DS_INCOMPATIBLE_CONTROLS_USED 8574L +#define ERROR_DS_NO_REF_DOMAIN 8575L +#define ERROR_DS_RESERVED_LINK_ID 8576L +#define ERROR_DS_LINK_ID_NOT_AVAILABLE 8577L +#define ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER 8578L +#define ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE 8579L +#define ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC 8580L +#define ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG 8581L +#define ERROR_DS_MODIFYDN_WRONG_GRANDPARENT 8582L +#define ERROR_DS_NAME_ERROR_TRUST_REFERRAL 8583L +#define ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER 8584L +#define ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD 8585L +#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2 8586L +#define ERROR_DS_THREAD_LIMIT_EXCEEDED 8587L +#define ERROR_DS_NOT_CLOSEST 8588L +#define ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF 8589L +#define ERROR_DS_SINGLE_USER_MODE_FAILED 8590L +#define ERROR_DS_NTDSCRIPT_SYNTAX_ERROR 8591L +#define ERROR_DS_NTDSCRIPT_PROCESS_ERROR 8592L +#define ERROR_DS_DIFFERENT_REPL_EPOCHS 8593L +#define ERROR_DS_DRS_EXTENSIONS_CHANGED 8594L +#define ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR 8595L +#define ERROR_DS_NO_MSDS_INTID 8596L +#define ERROR_DS_DUP_MSDS_INTID 8597L +#define ERROR_DS_EXISTS_IN_RDNATTID 8598L +#define ERROR_DS_AUTHORIZATION_FAILED 8599L +#define ERROR_DS_INVALID_SCRIPT 8600L +#define ERROR_DS_REMOTE_CROSSREF_OP_FAILED 8601L +#define ERROR_DS_CROSS_REF_BUSY 8602L +#define ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN 8603L +#define ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC 8604L +#define ERROR_DS_DUPLICATE_ID_FOUND 8605L +#define ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT 8606L +#define ERROR_DS_GROUP_CONVERSION_ERROR 8607L +#define ERROR_DS_CANT_MOVE_APP_BASIC_GROUP 8608L +#define ERROR_DS_CANT_MOVE_APP_QUERY_GROUP 8609L +#define ERROR_DS_ROLE_NOT_VERIFIED 8610L +#define ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL 8611L +#define ERROR_DS_DOMAIN_RENAME_IN_PROGRESS 8612L +#define ERROR_DS_EXISTING_AD_CHILD_NC 8613L +#define ERROR_DS_REPL_LIFETIME_EXCEEDED 8614L +#define ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER 8615L +#define ERROR_DS_LDAP_SEND_QUEUE_FULL 8616L +#define ERROR_DS_DRA_OUT_SCHEDULE_WINDOW 8617L +#define DNS_ERROR_RESPONSE_CODES_BASE 9000 +#define DNS_ERROR_RCODE_NO_ERROR NO_ERROR +#define DNS_ERROR_MASK 0x00002328 +#define DNS_ERROR_RCODE_FORMAT_ERROR 9001L +#define DNS_ERROR_RCODE_SERVER_FAILURE 9002L +#define DNS_ERROR_RCODE_NAME_ERROR 9003L +#define DNS_ERROR_RCODE_NOT_IMPLEMENTED 9004L +#define DNS_ERROR_RCODE_REFUSED 9005L +#define DNS_ERROR_RCODE_YXDOMAIN 9006L +#define DNS_ERROR_RCODE_YXRRSET 9007L +#define DNS_ERROR_RCODE_NXRRSET 9008L +#define DNS_ERROR_RCODE_NOTAUTH 9009L +#define DNS_ERROR_RCODE_NOTZONE 9010L +#define DNS_ERROR_RCODE_BADSIG 9016L +#define DNS_ERROR_RCODE_BADKEY 9017L +#define DNS_ERROR_RCODE_BADTIME 9018L +#define DNS_ERROR_RCODE_LAST DNS_ERROR_RCODE_BADTIME +#define DNS_ERROR_PACKET_FMT_BASE 9500 +#define DNS_INFO_NO_RECORDS 9501L +#define DNS_ERROR_BAD_PACKET 9502L +#define DNS_ERROR_NO_PACKET 9503L +#define DNS_ERROR_RCODE 9504L +#define DNS_ERROR_UNSECURE_PACKET 9505L +#define DNS_STATUS_PACKET_UNSECURE DNS_ERROR_UNSECURE_PACKET +#define DNS_ERROR_NO_MEMORY ERROR_OUTOFMEMORY +#define DNS_ERROR_INVALID_NAME ERROR_INVALID_NAME +#define DNS_ERROR_INVALID_DATA ERROR_INVALID_DATA +#define DNS_ERROR_GENERAL_API_BASE 9550 +#define DNS_ERROR_INVALID_TYPE 9551L +#define DNS_ERROR_INVALID_IP_ADDRESS 9552L +#define DNS_ERROR_INVALID_PROPERTY 9553L +#define DNS_ERROR_TRY_AGAIN_LATER 9554L +#define DNS_ERROR_NOT_UNIQUE 9555L +#define DNS_ERROR_NON_RFC_NAME 9556L +#define DNS_STATUS_FQDN 9557L +#define DNS_STATUS_DOTTED_NAME 9558L +#define DNS_STATUS_SINGLE_PART_NAME 9559L +#define DNS_ERROR_INVALID_NAME_CHAR 9560L +#define DNS_ERROR_NUMERIC_NAME 9561L +#define DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER 9562L +#define DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION 9563L +#define DNS_ERROR_CANNOT_FIND_ROOT_HINTS 9564L +#define DNS_ERROR_INCONSISTENT_ROOT_HINTS 9565L +#define DNS_ERROR_ZONE_BASE 9600 +#define DNS_ERROR_ZONE_DOES_NOT_EXIST 9601L +#define DNS_ERROR_NO_ZONE_INFO 9602L +#define DNS_ERROR_INVALID_ZONE_OPERATION 9603L +#define DNS_ERROR_ZONE_CONFIGURATION_ERROR 9604L +#define DNS_ERROR_ZONE_HAS_NO_SOA_RECORD 9605L +#define DNS_ERROR_ZONE_HAS_NO_NS_RECORDS 9606L +#define DNS_ERROR_ZONE_LOCKED 9607L +#define DNS_ERROR_ZONE_CREATION_FAILED 9608L +#define DNS_ERROR_ZONE_ALREADY_EXISTS 9609L +#define DNS_ERROR_AUTOZONE_ALREADY_EXISTS 9610L +#define DNS_ERROR_INVALID_ZONE_TYPE 9611L +#define DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP 9612L +#define DNS_ERROR_ZONE_NOT_SECONDARY 9613L +#define DNS_ERROR_NEED_SECONDARY_ADDRESSES 9614L +#define DNS_ERROR_WINS_INIT_FAILED 9615L +#define DNS_ERROR_NEED_WINS_SERVERS 9616L +#define DNS_ERROR_NBSTAT_INIT_FAILED 9617L +#define DNS_ERROR_SOA_DELETE_INVALID 9618L +#define DNS_ERROR_FORWARDER_ALREADY_EXISTS 9619L +#define DNS_ERROR_ZONE_REQUIRES_MASTER_IP 9620L +#define DNS_ERROR_ZONE_IS_SHUTDOWN 9621L +#define DNS_ERROR_DATAFILE_BASE 9650 +#define DNS_ERROR_PRIMARY_REQUIRES_DATAFILE 9651L +#define DNS_ERROR_INVALID_DATAFILE_NAME 9652L +#define DNS_ERROR_DATAFILE_OPEN_FAILURE 9653L +#define DNS_ERROR_FILE_WRITEBACK_FAILED 9654L +#define DNS_ERROR_DATAFILE_PARSING 9655L +#define DNS_ERROR_DATABASE_BASE 9700 +#define DNS_ERROR_RECORD_DOES_NOT_EXIST 9701L +#define DNS_ERROR_RECORD_FORMAT 9702L +#define DNS_ERROR_NODE_CREATION_FAILED 9703L +#define DNS_ERROR_UNKNOWN_RECORD_TYPE 9704L +#define DNS_ERROR_RECORD_TIMED_OUT 9705L +#define DNS_ERROR_NAME_NOT_IN_ZONE 9706L +#define DNS_ERROR_CNAME_LOOP 9707L +#define DNS_ERROR_NODE_IS_CNAME 9708L +#define DNS_ERROR_CNAME_COLLISION 9709L +#define DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT 9710L +#define DNS_ERROR_RECORD_ALREADY_EXISTS 9711L +#define DNS_ERROR_SECONDARY_DATA 9712L +#define DNS_ERROR_NO_CREATE_CACHE_DATA 9713L +#define DNS_ERROR_NAME_DOES_NOT_EXIST 9714L +#define DNS_WARNING_PTR_CREATE_FAILED 9715L +#define DNS_WARNING_DOMAIN_UNDELETED 9716L +#define DNS_ERROR_DS_UNAVAILABLE 9717L +#define DNS_ERROR_DS_ZONE_ALREADY_EXISTS 9718L +#define DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE 9719L +#define DNS_ERROR_OPERATION_BASE 9750 +#define DNS_INFO_AXFR_COMPLETE 9751L +#define DNS_ERROR_AXFR 9752L +#define DNS_INFO_ADDED_LOCAL_WINS 9753L +#define DNS_ERROR_SECURE_BASE 9800 +#define DNS_STATUS_CONTINUE_NEEDED 9801L +#define DNS_ERROR_SETUP_BASE 9850 +#define DNS_ERROR_NO_TCPIP 9851L +#define DNS_ERROR_NO_DNS_SERVERS 9852L +#define DNS_ERROR_DP_BASE 9900 +#define DNS_ERROR_DP_DOES_NOT_EXIST 9901L +#define DNS_ERROR_DP_ALREADY_EXISTS 9902L +#define DNS_ERROR_DP_NOT_ENLISTED 9903L +#define DNS_ERROR_DP_ALREADY_ENLISTED 9904L +#define DNS_ERROR_DP_NOT_AVAILABLE 9905L +#define DNS_ERROR_DP_FSMO_ERROR 9906L + +#ifndef WSABASEERR +#define WSABASEERR 10000 +#define WSAEINTR 10004L +#define WSAEBADF 10009L +#define WSAEACCES 10013L +#define WSAEFAULT 10014L +#define WSAEINVAL 10022L +#define WSAEMFILE 10024L +#define WSAEWOULDBLOCK 10035L +#define WSAEINPROGRESS 10036L +#define WSAEALREADY 10037L +#define WSAENOTSOCK 10038L +#define WSAEDESTADDRREQ 10039L +#define WSAEMSGSIZE 10040L +#define WSAEPROTOTYPE 10041L +#define WSAENOPROTOOPT 10042L +#define WSAEPROTONOSUPPORT 10043L +#define WSAESOCKTNOSUPPORT 10044L +#define WSAEOPNOTSUPP 10045L +#define WSAEPFNOSUPPORT 10046L +#define WSAEAFNOSUPPORT 10047L +#define WSAEADDRINUSE 10048L +#define WSAEADDRNOTAVAIL 10049L +#define WSAENETDOWN 10050L +#define WSAENETUNREACH 10051L +#define WSAENETRESET 10052L +#define WSAECONNABORTED 10053L +#define WSAECONNRESET 10054L +#define WSAENOBUFS 10055L +#define WSAEISCONN 10056L +#define WSAENOTCONN 10057L +#define WSAESHUTDOWN 10058L +#define WSAETOOMANYREFS 10059L +#define WSAETIMEDOUT 10060L +#define WSAECONNREFUSED 10061L +#define WSAELOOP 10062L +#define WSAENAMETOOLONG 10063L +#define WSAEHOSTDOWN 10064L +#define WSAEHOSTUNREACH 10065L +#define WSAENOTEMPTY 10066L +#define WSAEPROCLIM 10067L +#define WSAEUSERS 10068L +#define WSAEDQUOT 10069L +#define WSAESTALE 10070L +#define WSAEREMOTE 10071L +#define WSASYSNOTREADY 10091L +#define WSAVERNOTSUPPORTED 10092L +#define WSANOTINITIALISED 10093L +#define WSAEDISCON 10101L +#define WSAENOMORE 10102L +#define WSAECANCELLED 10103L +#define WSAEINVALIDPROCTABLE 10104L +#define WSAEINVALIDPROVIDER 10105L +#define WSAEPROVIDERFAILEDINIT 10106L +#define WSASYSCALLFAILURE 10107L +#define WSASERVICE_NOT_FOUND 10108L +#define WSATYPE_NOT_FOUND 10109L +#define WSA_E_NO_MORE 10110L +#define WSA_E_CANCELLED 10111L +#define WSAEREFUSED 10112L +#ifndef WSAHOST_NOT_FOUND +#define WSAHOST_NOT_FOUND 11001L +#endif +#ifndef WSATRY_AGAIN +#define WSATRY_AGAIN 11002L +#endif +#ifndef WSANO_RECOVERY +#define WSANO_RECOVERY 11003L +#endif +#ifndef WSANO_DATA +#define WSANO_DATA 11004L +#endif +#ifndef WSA_QOS_RECEIVERS +#define WSA_QOS_RECEIVERS 11005L +#endif +#ifndef WSA_QOS_SENDERS +#define WSA_QOS_SENDERS 11006L +#endif +#ifndef WSA_QOS_NO_SENDERS +#define WSA_QOS_NO_SENDERS 11007L +#endif +#ifndef WSA_QOS_NO_RECEIVERS +#define WSA_QOS_NO_RECEIVERS 11008L +#endif +#ifndef WSA_QOS_REQUEST_CONFIRMED +#define WSA_QOS_REQUEST_CONFIRMED 11009L +#endif +#ifndef WSA_QOS_ADMISSION_FAILURE +#define WSA_QOS_ADMISSION_FAILURE 11010L +#endif +#ifndef WSA_QOS_POLICY_FAILURE +#define WSA_QOS_POLICY_FAILURE 11011L +#endif +#ifndef WSA_QOS_BAD_STYLE +#define WSA_QOS_BAD_STYLE 11012L +#endif +#ifndef WSA_QOS_BAD_OBJECT +#define WSA_QOS_BAD_OBJECT 11013L +#endif +#ifndef WSA_QOS_TRAFFIC_CTRL_ERROR +#define WSA_QOS_TRAFFIC_CTRL_ERROR 11014L +#endif +#ifndef WSA_QOS_GENERIC_ERROR +#define WSA_QOS_GENERIC_ERROR 11015L +#endif +#ifndef WSA_QOS_ESERVICETYPE +#define WSA_QOS_ESERVICETYPE 11016L +#endif +#ifndef WSA_QOS_EFLOWSPEC +#define WSA_QOS_EFLOWSPEC 11017L +#endif +#ifndef WSA_QOS_EPROVSPECBUF +#define WSA_QOS_EPROVSPECBUF 11018L +#endif +#ifndef WSA_QOS_EFILTERSTYLE +#define WSA_QOS_EFILTERSTYLE 11019L +#endif +#ifndef WSA_QOS_EFILTERTYPE +#define WSA_QOS_EFILTERTYPE 11020L +#endif +#ifndef WSA_QOS_EFILTERCOUNT +#define WSA_QOS_EFILTERCOUNT 11021L +#endif +#ifndef WSA_QOS_EOBJLENGTH +#define WSA_QOS_EOBJLENGTH 11022L +#endif +#ifndef WSA_QOS_EFLOWCOUNT +#define WSA_QOS_EFLOWCOUNT 11023L +#endif +#ifndef WSA_QOS_EUNKNOWNPSOBJ +#define WSA_QOS_EUNKNOWNPSOBJ 11024L +#endif +#ifndef WSA_QOS_EPOLICYOBJ +#define WSA_QOS_EPOLICYOBJ 11025L +#endif +#ifndef WSA_QOS_EFLOWDESC +#define WSA_QOS_EFLOWDESC 11026L +#endif +#ifndef WSA_QOS_EPSFLOWSPEC +#define WSA_QOS_EPSFLOWSPEC 11027L +#endif +#ifndef WSA_QOS_EPSFILTERSPEC +#define WSA_QOS_EPSFILTERSPEC 11028L +#endif +#ifndef WSA_QOS_ESDMODEOBJ +#define WSA_QOS_ESDMODEOBJ 11029L +#endif +#ifndef WSA_QOS_ESHAPERATEOBJ +#define WSA_QOS_ESHAPERATEOBJ 11030L +#endif +#ifndef WSA_QOS_RESERVED_PETYPE +#define WSA_QOS_RESERVED_PETYPE 11031L +#endif +#endif /* WSABASEERR */ + +#define ERROR_SXS_SECTION_NOT_FOUND 14000L +#define ERROR_SXS_CANT_GEN_ACTCTX 14001L +#define ERROR_SXS_INVALID_ACTCTXDATA_FORMAT 14002L +#define ERROR_SXS_ASSEMBLY_NOT_FOUND 14003L +#define ERROR_SXS_MANIFEST_FORMAT_ERROR 14004L +#define ERROR_SXS_MANIFEST_PARSE_ERROR 14005L +#define ERROR_SXS_ACTIVATION_CONTEXT_DISABLED 14006L +#define ERROR_SXS_KEY_NOT_FOUND 14007L +#define ERROR_SXS_VERSION_CONFLICT 14008L +#define ERROR_SXS_WRONG_SECTION_TYPE 14009L +#define ERROR_SXS_THREAD_QUERIES_DISABLED 14010L +#define ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET 14011L +#define ERROR_SXS_UNKNOWN_ENCODING_GROUP 14012L +#define ERROR_SXS_UNKNOWN_ENCODING 14013L +#define ERROR_SXS_INVALID_XML_NAMESPACE_URI 14014L +#define ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED 14015L +#define ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED 14016L +#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE 14017L +#define ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE 14018L +#define ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE 14019L +#define ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT 14020L +#define ERROR_SXS_DUPLICATE_DLL_NAME 14021L +#define ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME 14022L +#define ERROR_SXS_DUPLICATE_CLSID 14023L +#define ERROR_SXS_DUPLICATE_IID 14024L +#define ERROR_SXS_DUPLICATE_TLBID 14025L +#define ERROR_SXS_DUPLICATE_PROGID 14026L +#define ERROR_SXS_DUPLICATE_ASSEMBLY_NAME 14027L +#define ERROR_SXS_FILE_HASH_MISMATCH 14028L +#define ERROR_SXS_POLICY_PARSE_ERROR 14029L +#define ERROR_SXS_XML_E_MISSINGQUOTE 14030L +#define ERROR_SXS_XML_E_COMMENTSYNTAX 14031L +#define ERROR_SXS_XML_E_BADSTARTNAMECHAR 14032L +#define ERROR_SXS_XML_E_BADNAMECHAR 14033L +#define ERROR_SXS_XML_E_BADCHARINSTRING 14034L +#define ERROR_SXS_XML_E_XMLDECLSYNTAX 14035L +#define ERROR_SXS_XML_E_BADCHARDATA 14036L +#define ERROR_SXS_XML_E_MISSINGWHITESPACE 14037L +#define ERROR_SXS_XML_E_EXPECTINGTAGEND 14038L +#define ERROR_SXS_XML_E_MISSINGSEMICOLON 14039L +#define ERROR_SXS_XML_E_UNBALANCEDPAREN 14040L +#define ERROR_SXS_XML_E_INTERNALERROR 14041L +#define ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE 14042L +#define ERROR_SXS_XML_E_INCOMPLETE_ENCODING 14043L +#define ERROR_SXS_XML_E_MISSING_PAREN 14044L +#define ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE 14045L +#define ERROR_SXS_XML_E_MULTIPLE_COLONS 14046L +#define ERROR_SXS_XML_E_INVALID_DECIMAL 14047L +#define ERROR_SXS_XML_E_INVALID_HEXIDECIMAL 14048L +#define ERROR_SXS_XML_E_INVALID_UNICODE 14049L +#define ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK 14050L +#define ERROR_SXS_XML_E_UNEXPECTEDENDTAG 14051L +#define ERROR_SXS_XML_E_UNCLOSEDTAG 14052L +#define ERROR_SXS_XML_E_DUPLICATEATTRIBUTE 14053L +#define ERROR_SXS_XML_E_MULTIPLEROOTS 14054L +#define ERROR_SXS_XML_E_INVALIDATROOTLEVEL 14055L +#define ERROR_SXS_XML_E_BADXMLDECL 14056L +#define ERROR_SXS_XML_E_MISSINGROOT 14057L +#define ERROR_SXS_XML_E_UNEXPECTEDEOF 14058L +#define ERROR_SXS_XML_E_BADPEREFINSUBSET 14059L +#define ERROR_SXS_XML_E_UNCLOSEDSTARTTAG 14060L +#define ERROR_SXS_XML_E_UNCLOSEDENDTAG 14061L +#define ERROR_SXS_XML_E_UNCLOSEDSTRING 14062L +#define ERROR_SXS_XML_E_UNCLOSEDCOMMENT 14063L +#define ERROR_SXS_XML_E_UNCLOSEDDECL 14064L +#define ERROR_SXS_XML_E_UNCLOSEDCDATA 14065L +#define ERROR_SXS_XML_E_RESERVEDNAMESPACE 14066L +#define ERROR_SXS_XML_E_INVALIDENCODING 14067L +#define ERROR_SXS_XML_E_INVALIDSWITCH 14068L +#define ERROR_SXS_XML_E_BADXMLCASE 14069L +#define ERROR_SXS_XML_E_INVALID_STANDALONE 14070L +#define ERROR_SXS_XML_E_UNEXPECTED_STANDALONE 14071L +#define ERROR_SXS_XML_E_INVALID_VERSION 14072L +#define ERROR_SXS_XML_E_MISSINGEQUALS 14073L +#define ERROR_SXS_PROTECTION_RECOVERY_FAILED 14074L +#define ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT 14075L +#define ERROR_SXS_PROTECTION_CATALOG_NOT_VALID 14076L +#define ERROR_SXS_UNTRANSLATABLE_HRESULT 14077L +#define ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING 14078L +#define ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE 14079L +#define ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME 14080L +#define ERROR_IPSEC_QM_POLICY_EXISTS 13000L +#define ERROR_IPSEC_QM_POLICY_NOT_FOUND 13001L +#define ERROR_IPSEC_QM_POLICY_IN_USE 13002L +#define ERROR_IPSEC_MM_POLICY_EXISTS 13003L +#define ERROR_IPSEC_MM_POLICY_NOT_FOUND 13004L +#define ERROR_IPSEC_MM_POLICY_IN_USE 13005L +#define ERROR_IPSEC_MM_FILTER_EXISTS 13006L +#define ERROR_IPSEC_MM_FILTER_NOT_FOUND 13007L +#define ERROR_IPSEC_TRANSPORT_FILTER_EXISTS 13008L +#define ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND 13009L +#define ERROR_IPSEC_MM_AUTH_EXISTS 13010L +#define ERROR_IPSEC_MM_AUTH_NOT_FOUND 13011L +#define ERROR_IPSEC_MM_AUTH_IN_USE 13012L +#define ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND 13013L +#define ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND 13014L +#define ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND 13015L +#define ERROR_IPSEC_TUNNEL_FILTER_EXISTS 13016L +#define ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND 13017L +#define ERROR_IPSEC_MM_FILTER_PENDING_DELETION 13018L +#define ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION 13019L +#define ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION 13020L +#define ERROR_IPSEC_MM_POLICY_PENDING_DELETION 13021L +#define ERROR_IPSEC_MM_AUTH_PENDING_DELETION 13022L +#define ERROR_IPSEC_QM_POLICY_PENDING_DELETION 13023L +#define WARNING_IPSEC_MM_POLICY_PRUNED 13024L +#define WARNING_IPSEC_QM_POLICY_PRUNED 13025L +#define ERROR_IPSEC_IKE_NEG_STATUS_BEGIN 13800L +#define ERROR_IPSEC_IKE_AUTH_FAIL 13801L +#define ERROR_IPSEC_IKE_ATTRIB_FAIL 13802L +#define ERROR_IPSEC_IKE_NEGOTIATION_PENDING 13803L +#define ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR 13804L +#define ERROR_IPSEC_IKE_TIMED_OUT 13805L +#define ERROR_IPSEC_IKE_NO_CERT 13806L +#define ERROR_IPSEC_IKE_SA_DELETED 13807L +#define ERROR_IPSEC_IKE_SA_REAPED 13808L +#define ERROR_IPSEC_IKE_MM_ACQUIRE_DROP 13809L +#define ERROR_IPSEC_IKE_QM_ACQUIRE_DROP 13810L +#define ERROR_IPSEC_IKE_QUEUE_DROP_MM 13811L +#define ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM 13812L +#define ERROR_IPSEC_IKE_DROP_NO_RESPONSE 13813L +#define ERROR_IPSEC_IKE_MM_DELAY_DROP 13814L +#define ERROR_IPSEC_IKE_QM_DELAY_DROP 13815L +#define ERROR_IPSEC_IKE_ERROR 13816L +#define ERROR_IPSEC_IKE_CRL_FAILED 13817L +#define ERROR_IPSEC_IKE_INVALID_KEY_USAGE 13818L +#define ERROR_IPSEC_IKE_INVALID_CERT_TYPE 13819L +#define ERROR_IPSEC_IKE_NO_PRIVATE_KEY 13820L +#define ERROR_IPSEC_IKE_DH_FAIL 13822L +#define ERROR_IPSEC_IKE_INVALID_HEADER 13824L +#define ERROR_IPSEC_IKE_NO_POLICY 13825L +#define ERROR_IPSEC_IKE_INVALID_SIGNATURE 13826L +#define ERROR_IPSEC_IKE_KERBEROS_ERROR 13827L +#define ERROR_IPSEC_IKE_NO_PUBLIC_KEY 13828L +#define ERROR_IPSEC_IKE_PROCESS_ERR 13829L +#define ERROR_IPSEC_IKE_PROCESS_ERR_SA 13830L +#define ERROR_IPSEC_IKE_PROCESS_ERR_PROP 13831L +#define ERROR_IPSEC_IKE_PROCESS_ERR_TRANS 13832L +#define ERROR_IPSEC_IKE_PROCESS_ERR_KE 13833L +#define ERROR_IPSEC_IKE_PROCESS_ERR_ID 13834L +#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT 13835L +#define ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ 13836L +#define ERROR_IPSEC_IKE_PROCESS_ERR_HASH 13837L +#define ERROR_IPSEC_IKE_PROCESS_ERR_SIG 13838L +#define ERROR_IPSEC_IKE_PROCESS_ERR_NONCE 13839L +#define ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY 13840L +#define ERROR_IPSEC_IKE_PROCESS_ERR_DELETE 13841L +#define ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR 13842L +#define ERROR_IPSEC_IKE_INVALID_PAYLOAD 13843L +#define ERROR_IPSEC_IKE_LOAD_SOFT_SA 13844L +#define ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN 13845L +#define ERROR_IPSEC_IKE_INVALID_COOKIE 13846L +#define ERROR_IPSEC_IKE_NO_PEER_CERT 13847L +#define ERROR_IPSEC_IKE_PEER_CRL_FAILED 13848L +#define ERROR_IPSEC_IKE_POLICY_CHANGE 13849L +#define ERROR_IPSEC_IKE_NO_MM_POLICY 13850L +#define ERROR_IPSEC_IKE_NOTCBPRIV 13851L +#define ERROR_IPSEC_IKE_SECLOADFAIL 13852L +#define ERROR_IPSEC_IKE_FAILSSPINIT 13853L +#define ERROR_IPSEC_IKE_FAILQUERYSSP 13854L +#define ERROR_IPSEC_IKE_SRVACQFAIL 13855L +#define ERROR_IPSEC_IKE_SRVQUERYCRED 13856L +#define ERROR_IPSEC_IKE_GETSPIFAIL 13857L +#define ERROR_IPSEC_IKE_INVALID_FILTER 13858L +#define ERROR_IPSEC_IKE_OUT_OF_MEMORY 13859L +#define ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED 13860L +#define ERROR_IPSEC_IKE_INVALID_POLICY 13861L +#define ERROR_IPSEC_IKE_UNKNOWN_DOI 13862L +#define ERROR_IPSEC_IKE_INVALID_SITUATION 13863L +#define ERROR_IPSEC_IKE_DH_FAILURE 13864L +#define ERROR_IPSEC_IKE_INVALID_GROUP 13865L +#define ERROR_IPSEC_IKE_ENCRYPT 13866L +#define ERROR_IPSEC_IKE_DECRYPT 13867L +#define ERROR_IPSEC_IKE_POLICY_MATCH 13868L +#define ERROR_IPSEC_IKE_UNSUPPORTED_ID 13869L +#define ERROR_IPSEC_IKE_INVALID_HASH 13870L +#define ERROR_IPSEC_IKE_INVALID_HASH_ALG 13871L +#define ERROR_IPSEC_IKE_INVALID_HASH_SIZE 13872L +#define ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG 13873L +#define ERROR_IPSEC_IKE_INVALID_AUTH_ALG 13874L +#define ERROR_IPSEC_IKE_INVALID_SIG 13875L +#define ERROR_IPSEC_IKE_LOAD_FAILED 13876L +#define ERROR_IPSEC_IKE_RPC_DELETE 13877L +#define ERROR_IPSEC_IKE_BENIGN_REINIT 13878L +#define ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY 13879L +#define ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN 13881L +#define ERROR_IPSEC_IKE_MM_LIMIT 13882L +#define ERROR_IPSEC_IKE_NEGOTIATION_DISABLED 13883L +#define ERROR_IPSEC_IKE_NEG_STATUS_END 13884L +#define SEVERITY_SUCCESS 0 +#define SEVERITY_ERROR 1 +#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) +#define FAILED(hr) ((HRESULT)(hr) < 0) +#define IS_ERROR(Status) ((unsigned long)(Status) >> 31==SEVERITY_ERROR) +#define HRESULT_CODE(hr) ((hr) & 0xFFFF) +#define SCODE_CODE(sc) ((sc) & 0xFFFF) +#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) +#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1fff) +#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) +#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1) +#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) +#define MAKE_SCODE(sev,fac,code) ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code)))) +#define FACILITY_NT_BIT 0x10000000 +#define __HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) +#ifdef INLINE_HRESULT_FROM_WIN32 +#ifndef _HRESULT_DEFINED +#define _HRESULT_DEFINED +typedef long HRESULT; +#endif +__CRT_INLINE HRESULT HRESULT_FROM_WIN32(long x) { return x <= 0 ? (HRESULT)x : (HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000);} +#else +#define HRESULT_FROM_WIN32(x) __HRESULT_FROM_WIN32(x) +#endif +#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT)) +#define GetScode(hr) ((SCODE) (hr)) +#define ResultFromScode(sc) ((HRESULT) (sc)) +#define PropagateResult(hrPrevious,scBase) ((HRESULT) scBase) +#ifdef RC_INVOKED +#define _HRESULT_TYPEDEF_(_sc) _sc +#else +#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc) +#endif +#define NOERROR 0 +#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL) +#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L) +#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL) +#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L) +#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L) +#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L) +#define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L) +#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L) +#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L) +#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L) +#define E_PENDING _HRESULT_TYPEDEF_(0x8000000AL) +#define CO_E_INIT_TLS _HRESULT_TYPEDEF_(0x80004006L) +#define CO_E_INIT_SHARED_ALLOCATOR _HRESULT_TYPEDEF_(0x80004007L) +#define CO_E_INIT_MEMORY_ALLOCATOR _HRESULT_TYPEDEF_(0x80004008L) +#define CO_E_INIT_CLASS_CACHE _HRESULT_TYPEDEF_(0x80004009L) +#define CO_E_INIT_RPC_CHANNEL _HRESULT_TYPEDEF_(0x8000400AL) +#define CO_E_INIT_TLS_SET_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400BL) +#define CO_E_INIT_TLS_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400CL) +#define CO_E_INIT_UNACCEPTED_USER_ALLOCATOR _HRESULT_TYPEDEF_(0x8000400DL) +#define CO_E_INIT_SCM_MUTEX_EXISTS _HRESULT_TYPEDEF_(0x8000400EL) +#define CO_E_INIT_SCM_FILE_MAPPING_EXISTS _HRESULT_TYPEDEF_(0x8000400FL) +#define CO_E_INIT_SCM_MAP_VIEW_OF_FILE _HRESULT_TYPEDEF_(0x80004010L) +#define CO_E_INIT_SCM_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80004011L) +#define CO_E_INIT_ONLY_SINGLE_THREADED _HRESULT_TYPEDEF_(0x80004012L) +#define CO_E_CANT_REMOTE _HRESULT_TYPEDEF_(0x80004013L) +#define CO_E_BAD_SERVER_NAME _HRESULT_TYPEDEF_(0x80004014L) +#define CO_E_WRONG_SERVER_IDENTITY _HRESULT_TYPEDEF_(0x80004015L) +#define CO_E_OLE1DDE_DISABLED _HRESULT_TYPEDEF_(0x80004016L) +#define CO_E_RUNAS_SYNTAX _HRESULT_TYPEDEF_(0x80004017L) +#define CO_E_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004018L) +#define CO_E_RUNAS_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004019L) +#define CO_E_RUNAS_LOGON_FAILURE _HRESULT_TYPEDEF_(0x8000401AL) +#define CO_E_LAUNCH_PERMSSION_DENIED _HRESULT_TYPEDEF_(0x8000401BL) +#define CO_E_START_SERVICE_FAILURE _HRESULT_TYPEDEF_(0x8000401CL) +#define CO_E_REMOTE_COMMUNICATION_FAILURE _HRESULT_TYPEDEF_(0x8000401DL) +#define CO_E_SERVER_START_TIMEOUT _HRESULT_TYPEDEF_(0x8000401EL) +#define CO_E_CLSREG_INCONSISTENT _HRESULT_TYPEDEF_(0x8000401FL) +#define CO_E_IIDREG_INCONSISTENT _HRESULT_TYPEDEF_(0x80004020L) +#define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L) +#define CO_E_RELOAD_DLL _HRESULT_TYPEDEF_(0x80004022L) +#define CO_E_MSI_ERROR _HRESULT_TYPEDEF_(0x80004023L) +#define CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT _HRESULT_TYPEDEF_(0x80004024L) +#define CO_E_SERVER_PAUSED _HRESULT_TYPEDEF_(0x80004025L) +#define CO_E_SERVER_NOT_PAUSED _HRESULT_TYPEDEF_(0x80004026L) +#define CO_E_CLASS_DISABLED _HRESULT_TYPEDEF_(0x80004027L) +#define CO_E_CLRNOTAVAILABLE _HRESULT_TYPEDEF_(0x80004028L) +#define CO_E_ASYNC_WORK_REJECTED _HRESULT_TYPEDEF_(0x80004029L) +#define CO_E_SERVER_INIT_TIMEOUT _HRESULT_TYPEDEF_(0x8000402AL) +#define CO_E_NO_SECCTX_IN_ACTIVATE _HRESULT_TYPEDEF_(0x8000402BL) +#define CO_E_TRACKER_CONFIG _HRESULT_TYPEDEF_(0x80004030L) +#define CO_E_THREADPOOL_CONFIG _HRESULT_TYPEDEF_(0x80004031L) +#define CO_E_SXS_CONFIG _HRESULT_TYPEDEF_(0x80004032L) +#define CO_E_MALFORMED_SPN _HRESULT_TYPEDEF_(0x80004033L) +#define S_OK ((HRESULT)0x00000000L) +#define S_FALSE ((HRESULT)0x00000001L) +#define OLE_E_FIRST ((HRESULT)0x80040000L) +#define OLE_E_LAST ((HRESULT)0x800400FFL) +#define OLE_S_FIRST ((HRESULT)0x00040000L) +#define OLE_S_LAST ((HRESULT)0x000400FFL) +#define OLE_E_OLEVERB _HRESULT_TYPEDEF_(0x80040000L) +#define OLE_E_ADVF _HRESULT_TYPEDEF_(0x80040001L) +#define OLE_E_ENUM_NOMORE _HRESULT_TYPEDEF_(0x80040002L) +#define OLE_E_ADVISENOTSUPPORTED _HRESULT_TYPEDEF_(0x80040003L) +#define OLE_E_NOCONNECTION _HRESULT_TYPEDEF_(0x80040004L) +#define OLE_E_NOTRUNNING _HRESULT_TYPEDEF_(0x80040005L) +#define OLE_E_NOCACHE _HRESULT_TYPEDEF_(0x80040006L) +#define OLE_E_BLANK _HRESULT_TYPEDEF_(0x80040007L) +#define OLE_E_CLASSDIFF _HRESULT_TYPEDEF_(0x80040008L) +#define OLE_E_CANT_GETMONIKER _HRESULT_TYPEDEF_(0x80040009L) +#define OLE_E_CANT_BINDTOSOURCE _HRESULT_TYPEDEF_(0x8004000AL) +#define OLE_E_STATIC _HRESULT_TYPEDEF_(0x8004000BL) +#define OLE_E_PROMPTSAVECANCELLED _HRESULT_TYPEDEF_(0x8004000CL) +#define OLE_E_INVALIDRECT _HRESULT_TYPEDEF_(0x8004000DL) +#define OLE_E_WRONGCOMPOBJ _HRESULT_TYPEDEF_(0x8004000EL) +#define OLE_E_INVALIDHWND _HRESULT_TYPEDEF_(0x8004000FL) +#define OLE_E_NOT_INPLACEACTIVE _HRESULT_TYPEDEF_(0x80040010L) +#define OLE_E_CANTCONVERT _HRESULT_TYPEDEF_(0x80040011L) +#define OLE_E_NOSTORAGE _HRESULT_TYPEDEF_(0x80040012L) +#define DV_E_FORMATETC _HRESULT_TYPEDEF_(0x80040064L) +#define DV_E_DVTARGETDEVICE _HRESULT_TYPEDEF_(0x80040065L) +#define DV_E_STGMEDIUM _HRESULT_TYPEDEF_(0x80040066L) +#define DV_E_STATDATA _HRESULT_TYPEDEF_(0x80040067L) +#define DV_E_LINDEX _HRESULT_TYPEDEF_(0x80040068L) +#define DV_E_TYMED _HRESULT_TYPEDEF_(0x80040069L) +#define DV_E_CLIPFORMAT _HRESULT_TYPEDEF_(0x8004006AL) +#define DV_E_DVASPECT _HRESULT_TYPEDEF_(0x8004006BL) +#define DV_E_DVTARGETDEVICE_SIZE _HRESULT_TYPEDEF_(0x8004006CL) +#define DV_E_NOIVIEWOBJECT _HRESULT_TYPEDEF_(0x8004006DL) +#define DRAGDROP_E_FIRST 0x80040100L +#define DRAGDROP_E_LAST 0x8004010FL +#define DRAGDROP_S_FIRST 0x00040100L +#define DRAGDROP_S_LAST 0x0004010FL +#define DRAGDROP_E_NOTREGISTERED _HRESULT_TYPEDEF_(0x80040100L) +#define DRAGDROP_E_ALREADYREGISTERED _HRESULT_TYPEDEF_(0x80040101L) +#define DRAGDROP_E_INVALIDHWND _HRESULT_TYPEDEF_(0x80040102L) +#define CLASSFACTORY_E_FIRST 0x80040110L +#define CLASSFACTORY_E_LAST 0x8004011FL +#define CLASSFACTORY_S_FIRST 0x00040110L +#define CLASSFACTORY_S_LAST 0x0004011FL +#define CLASS_E_NOAGGREGATION _HRESULT_TYPEDEF_(0x80040110L) +#define CLASS_E_CLASSNOTAVAILABLE _HRESULT_TYPEDEF_(0x80040111L) +#define CLASS_E_NOTLICENSED _HRESULT_TYPEDEF_(0x80040112L) +#define MARSHAL_E_FIRST 0x80040120L +#define MARSHAL_E_LAST 0x8004012FL +#define MARSHAL_S_FIRST 0x00040120L +#define MARSHAL_S_LAST 0x0004012FL +#define DATA_E_FIRST 0x80040130L +#define DATA_E_LAST 0x8004013FL +#define DATA_S_FIRST 0x00040130L +#define DATA_S_LAST 0x0004013FL +#define VIEW_E_FIRST 0x80040140L +#define VIEW_E_LAST 0x8004014FL +#define VIEW_S_FIRST 0x00040140L +#define VIEW_S_LAST 0x0004014FL +#define VIEW_E_DRAW _HRESULT_TYPEDEF_(0x80040140L) +#define REGDB_E_FIRST 0x80040150L +#define REGDB_E_LAST 0x8004015FL +#define REGDB_S_FIRST 0x00040150L +#define REGDB_S_LAST 0x0004015FL +#define REGDB_E_READREGDB _HRESULT_TYPEDEF_(0x80040150L) +#define REGDB_E_WRITEREGDB _HRESULT_TYPEDEF_(0x80040151L) +#define REGDB_E_KEYMISSING _HRESULT_TYPEDEF_(0x80040152L) +#define REGDB_E_INVALIDVALUE _HRESULT_TYPEDEF_(0x80040153L) +#define REGDB_E_CLASSNOTREG _HRESULT_TYPEDEF_(0x80040154L) +#define REGDB_E_IIDNOTREG _HRESULT_TYPEDEF_(0x80040155L) +#define REGDB_E_BADTHREADINGMODEL _HRESULT_TYPEDEF_(0x80040156L) +#define CAT_E_FIRST 0x80040160L +#define CAT_E_LAST 0x80040161L +#define CAT_E_CATIDNOEXIST _HRESULT_TYPEDEF_(0x80040160L) +#define CAT_E_NODESCRIPTION _HRESULT_TYPEDEF_(0x80040161L) +#define CS_E_FIRST 0x80040164L +#define CS_E_LAST 0x8004016FL +#define CS_E_PACKAGE_NOTFOUND _HRESULT_TYPEDEF_(0x80040164L) +#define CS_E_NOT_DELETABLE _HRESULT_TYPEDEF_(0x80040165L) +#define CS_E_CLASS_NOTFOUND _HRESULT_TYPEDEF_(0x80040166L) +#define CS_E_INVALID_VERSION _HRESULT_TYPEDEF_(0x80040167L) +#define CS_E_NO_CLASSSTORE _HRESULT_TYPEDEF_(0x80040168L) +#define CS_E_OBJECT_NOTFOUND _HRESULT_TYPEDEF_(0x80040169L) +#define CS_E_OBJECT_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x8004016AL) +#define CS_E_INVALID_PATH _HRESULT_TYPEDEF_(0x8004016BL) +#define CS_E_NETWORK_ERROR _HRESULT_TYPEDEF_(0x8004016CL) +#define CS_E_ADMIN_LIMIT_EXCEEDED _HRESULT_TYPEDEF_(0x8004016DL) +#define CS_E_SCHEMA_MISMATCH _HRESULT_TYPEDEF_(0x8004016EL) +#define CS_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x8004016FL) +#define CACHE_E_FIRST 0x80040170L +#define CACHE_E_LAST 0x8004017FL +#define CACHE_S_FIRST 0x00040170L +#define CACHE_S_LAST 0x0004017FL +#define CACHE_E_NOCACHE_UPDATED _HRESULT_TYPEDEF_(0x80040170L) +#define OLEOBJ_E_FIRST 0x80040180L +#define OLEOBJ_E_LAST 0x8004018FL +#define OLEOBJ_S_FIRST 0x00040180L +#define OLEOBJ_S_LAST 0x0004018FL +#define OLEOBJ_E_NOVERBS _HRESULT_TYPEDEF_(0x80040180L) +#define OLEOBJ_E_INVALIDVERB _HRESULT_TYPEDEF_(0x80040181L) +#define CLIENTSITE_E_FIRST 0x80040190L +#define CLIENTSITE_E_LAST 0x8004019FL +#define CLIENTSITE_S_FIRST 0x00040190L +#define CLIENTSITE_S_LAST 0x0004019FL +#define INPLACE_E_NOTUNDOABLE _HRESULT_TYPEDEF_(0x800401A0L) +#define INPLACE_E_NOTOOLSPACE _HRESULT_TYPEDEF_(0x800401A1L) +#define INPLACE_E_FIRST 0x800401A0L +#define INPLACE_E_LAST 0x800401AFL +#define INPLACE_S_FIRST 0x000401A0L +#define INPLACE_S_LAST 0x000401AFL +#define ENUM_E_FIRST 0x800401B0L +#define ENUM_E_LAST 0x800401BFL +#define ENUM_S_FIRST 0x000401B0L +#define ENUM_S_LAST 0x000401BFL +#define CONVERT10_E_FIRST 0x800401C0L +#define CONVERT10_E_LAST 0x800401CFL +#define CONVERT10_S_FIRST 0x000401C0L +#define CONVERT10_S_LAST 0x000401CFL +#define CONVERT10_E_OLESTREAM_GET _HRESULT_TYPEDEF_(0x800401C0L) +#define CONVERT10_E_OLESTREAM_PUT _HRESULT_TYPEDEF_(0x800401C1L) +#define CONVERT10_E_OLESTREAM_FMT _HRESULT_TYPEDEF_(0x800401C2L) +#define CONVERT10_E_OLESTREAM_BITMAP_TO_DIB _HRESULT_TYPEDEF_(0x800401C3L) +#define CONVERT10_E_STG_FMT _HRESULT_TYPEDEF_(0x800401C4L) +#define CONVERT10_E_STG_NO_STD_STREAM _HRESULT_TYPEDEF_(0x800401C5L) +#define CONVERT10_E_STG_DIB_TO_BITMAP _HRESULT_TYPEDEF_(0x800401C6L) +#define CLIPBRD_E_FIRST 0x800401D0L +#define CLIPBRD_E_LAST 0x800401DFL +#define CLIPBRD_S_FIRST 0x000401D0L +#define CLIPBRD_S_LAST 0x000401DFL +#define CLIPBRD_E_CANT_OPEN _HRESULT_TYPEDEF_(0x800401D0L) +#define CLIPBRD_E_CANT_EMPTY _HRESULT_TYPEDEF_(0x800401D1L) +#define CLIPBRD_E_CANT_SET _HRESULT_TYPEDEF_(0x800401D2L) +#define CLIPBRD_E_BAD_DATA _HRESULT_TYPEDEF_(0x800401D3L) +#define CLIPBRD_E_CANT_CLOSE _HRESULT_TYPEDEF_(0x800401D4L) +#define MK_E_FIRST 0x800401E0L +#define MK_E_LAST 0x800401EFL +#define MK_S_FIRST 0x000401E0L +#define MK_S_LAST 0x000401EFL +#define MK_E_CONNECTMANUALLY _HRESULT_TYPEDEF_(0x800401E0L) +#define MK_E_EXCEEDEDDEADLINE _HRESULT_TYPEDEF_(0x800401E1L) +#define MK_E_NEEDGENERIC _HRESULT_TYPEDEF_(0x800401E2L) +#define MK_E_UNAVAILABLE _HRESULT_TYPEDEF_(0x800401E3L) +#define MK_E_SYNTAX _HRESULT_TYPEDEF_(0x800401E4L) +#define MK_E_NOOBJECT _HRESULT_TYPEDEF_(0x800401E5L) +#define MK_E_INVALIDEXTENSION _HRESULT_TYPEDEF_(0x800401E6L) +#define MK_E_INTERMEDIATEINTERFACENOTSUPPORTED _HRESULT_TYPEDEF_(0x800401E7L) +#define MK_E_NOTBINDABLE _HRESULT_TYPEDEF_(0x800401E8L) +#define MK_E_NOTBOUND _HRESULT_TYPEDEF_(0x800401E9L) +#define MK_E_CANTOPENFILE _HRESULT_TYPEDEF_(0x800401EAL) +#define MK_E_MUSTBOTHERUSER _HRESULT_TYPEDEF_(0x800401EBL) +#define MK_E_NOINVERSE _HRESULT_TYPEDEF_(0x800401ECL) +#define MK_E_NOSTORAGE _HRESULT_TYPEDEF_(0x800401EDL) +#define MK_E_NOPREFIX _HRESULT_TYPEDEF_(0x800401EEL) +#define MK_E_ENUMERATION_FAILED _HRESULT_TYPEDEF_(0x800401EFL) +#define CO_E_FIRST 0x800401F0L +#define CO_E_LAST 0x800401FFL +#define CO_S_FIRST 0x000401F0L +#define CO_S_LAST 0x000401FFL +#define CO_E_NOTINITIALIZED _HRESULT_TYPEDEF_(0x800401F0L) +#define CO_E_ALREADYINITIALIZED _HRESULT_TYPEDEF_(0x800401F1L) +#define CO_E_CANTDETERMINECLASS _HRESULT_TYPEDEF_(0x800401F2L) +#define CO_E_CLASSSTRING _HRESULT_TYPEDEF_(0x800401F3L) +#define CO_E_IIDSTRING _HRESULT_TYPEDEF_(0x800401F4L) +#define CO_E_APPNOTFOUND _HRESULT_TYPEDEF_(0x800401F5L) +#define CO_E_APPSINGLEUSE _HRESULT_TYPEDEF_(0x800401F6L) +#define CO_E_ERRORINAPP _HRESULT_TYPEDEF_(0x800401F7L) +#define CO_E_DLLNOTFOUND _HRESULT_TYPEDEF_(0x800401F8L) +#define CO_E_ERRORINDLL _HRESULT_TYPEDEF_(0x800401F9L) +#define CO_E_WRONGOSFORAPP _HRESULT_TYPEDEF_(0x800401FAL) +#define CO_E_OBJNOTREG _HRESULT_TYPEDEF_(0x800401FBL) +#define CO_E_OBJISREG _HRESULT_TYPEDEF_(0x800401FCL) +#define CO_E_OBJNOTCONNECTED _HRESULT_TYPEDEF_(0x800401FDL) +#define CO_E_APPDIDNTREG _HRESULT_TYPEDEF_(0x800401FEL) +#define CO_E_RELEASED _HRESULT_TYPEDEF_(0x800401FFL) +#define EVENT_E_FIRST 0x80040200L +#define EVENT_E_LAST 0x8004021FL +#define EVENT_S_FIRST 0x00040200L +#define EVENT_S_LAST 0x0004021FL +#define EVENT_S_SOME_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x00040200L) +#define EVENT_E_ALL_SUBSCRIBERS_FAILED _HRESULT_TYPEDEF_(0x80040201L) +#define EVENT_S_NOSUBSCRIBERS _HRESULT_TYPEDEF_(0x00040202L) +#define EVENT_E_QUERYSYNTAX _HRESULT_TYPEDEF_(0x80040203L) +#define EVENT_E_QUERYFIELD _HRESULT_TYPEDEF_(0x80040204L) +#define EVENT_E_INTERNALEXCEPTION _HRESULT_TYPEDEF_(0x80040205L) +#define EVENT_E_INTERNALERROR _HRESULT_TYPEDEF_(0x80040206L) +#define EVENT_E_INVALID_PER_USER_SID _HRESULT_TYPEDEF_(0x80040207L) +#define EVENT_E_USER_EXCEPTION _HRESULT_TYPEDEF_(0x80040208L) +#define EVENT_E_TOO_MANY_METHODS _HRESULT_TYPEDEF_(0x80040209L) +#define EVENT_E_MISSING_EVENTCLASS _HRESULT_TYPEDEF_(0x8004020AL) +#define EVENT_E_NOT_ALL_REMOVED _HRESULT_TYPEDEF_(0x8004020BL) +#define EVENT_E_COMPLUS_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004020CL) +#define EVENT_E_CANT_MODIFY_OR_DELETE_UNCONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020DL) +#define EVENT_E_CANT_MODIFY_OR_DELETE_CONFIGURED_OBJECT _HRESULT_TYPEDEF_(0x8004020EL) +#define EVENT_E_INVALID_EVENT_CLASS_PARTITION _HRESULT_TYPEDEF_(0x8004020FL) +#define EVENT_E_PER_USER_SID_NOT_LOGGED_ON _HRESULT_TYPEDEF_(0x80040210L) +#define XACT_E_FIRST 0x8004D000 +#define XACT_E_LAST 0x8004D029 +#define XACT_S_FIRST 0x0004D000 +#define XACT_S_LAST 0x0004D010 +#define XACT_E_ALREADYOTHERSINGLEPHASE _HRESULT_TYPEDEF_(0x8004D000L) +#define XACT_E_CANTRETAIN _HRESULT_TYPEDEF_(0x8004D001L) +#define XACT_E_COMMITFAILED _HRESULT_TYPEDEF_(0x8004D002L) +#define XACT_E_COMMITPREVENTED _HRESULT_TYPEDEF_(0x8004D003L) +#define XACT_E_HEURISTICABORT _HRESULT_TYPEDEF_(0x8004D004L) +#define XACT_E_HEURISTICCOMMIT _HRESULT_TYPEDEF_(0x8004D005L) +#define XACT_E_HEURISTICDAMAGE _HRESULT_TYPEDEF_(0x8004D006L) +#define XACT_E_HEURISTICDANGER _HRESULT_TYPEDEF_(0x8004D007L) +#define XACT_E_ISOLATIONLEVEL _HRESULT_TYPEDEF_(0x8004D008L) +#define XACT_E_NOASYNC _HRESULT_TYPEDEF_(0x8004D009L) +#define XACT_E_NOENLIST _HRESULT_TYPEDEF_(0x8004D00AL) +#define XACT_E_NOISORETAIN _HRESULT_TYPEDEF_(0x8004D00BL) +#define XACT_E_NORESOURCE _HRESULT_TYPEDEF_(0x8004D00CL) +#define XACT_E_NOTCURRENT _HRESULT_TYPEDEF_(0x8004D00DL) +#define XACT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004D00EL) +#define XACT_E_NOTSUPPORTED _HRESULT_TYPEDEF_(0x8004D00FL) +#define XACT_E_UNKNOWNRMGRID _HRESULT_TYPEDEF_(0x8004D010L) +#define XACT_E_WRONGSTATE _HRESULT_TYPEDEF_(0x8004D011L) +#define XACT_E_WRONGUOW _HRESULT_TYPEDEF_(0x8004D012L) +#define XACT_E_XTIONEXISTS _HRESULT_TYPEDEF_(0x8004D013L) +#define XACT_E_NOIMPORTOBJECT _HRESULT_TYPEDEF_(0x8004D014L) +#define XACT_E_INVALIDCOOKIE _HRESULT_TYPEDEF_(0x8004D015L) +#define XACT_E_INDOUBT _HRESULT_TYPEDEF_(0x8004D016L) +#define XACT_E_NOTIMEOUT _HRESULT_TYPEDEF_(0x8004D017L) +#define XACT_E_ALREADYINPROGRESS _HRESULT_TYPEDEF_(0x8004D018L) +#define XACT_E_ABORTED _HRESULT_TYPEDEF_(0x8004D019L) +#define XACT_E_LOGFULL _HRESULT_TYPEDEF_(0x8004D01AL) +#define XACT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D01BL) +#define XACT_E_CONNECTION_DOWN _HRESULT_TYPEDEF_(0x8004D01CL) +#define XACT_E_CONNECTION_DENIED _HRESULT_TYPEDEF_(0x8004D01DL) +#define XACT_E_REENLISTTIMEOUT _HRESULT_TYPEDEF_(0x8004D01EL) +#define XACT_E_TIP_CONNECT_FAILED _HRESULT_TYPEDEF_(0x8004D01FL) +#define XACT_E_TIP_PROTOCOL_ERROR _HRESULT_TYPEDEF_(0x8004D020L) +#define XACT_E_TIP_PULL_FAILED _HRESULT_TYPEDEF_(0x8004D021L) +#define XACT_E_DEST_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004D022L) +#define XACT_E_TIP_DISABLED _HRESULT_TYPEDEF_(0x8004D023L) +#define XACT_E_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D024L) +#define XACT_E_PARTNER_NETWORK_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D025L) +#define XACT_E_XA_TX_DISABLED _HRESULT_TYPEDEF_(0x8004D026L) +#define XACT_E_UNABLE_TO_READ_DTC_CONFIG _HRESULT_TYPEDEF_(0x8004D027L) +#define XACT_E_UNABLE_TO_LOAD_DTC_PROXY _HRESULT_TYPEDEF_(0x8004D028L) +#define XACT_E_ABORTING _HRESULT_TYPEDEF_(0x8004D029L) +#define XACT_E_CLERKNOTFOUND _HRESULT_TYPEDEF_(0x8004D080L) +#define XACT_E_CLERKEXISTS _HRESULT_TYPEDEF_(0x8004D081L) +#define XACT_E_RECOVERYINPROGRESS _HRESULT_TYPEDEF_(0x8004D082L) +#define XACT_E_TRANSACTIONCLOSED _HRESULT_TYPEDEF_(0x8004D083L) +#define XACT_E_INVALIDLSN _HRESULT_TYPEDEF_(0x8004D084L) +#define XACT_E_REPLAYREQUEST _HRESULT_TYPEDEF_(0x8004D085L) +#define XACT_S_ASYNC _HRESULT_TYPEDEF_(0x0004D000L) +#define XACT_S_DEFECT _HRESULT_TYPEDEF_(0x0004D001L) +#define XACT_S_READONLY _HRESULT_TYPEDEF_(0x0004D002L) +#define XACT_S_SOMENORETAIN _HRESULT_TYPEDEF_(0x0004D003L) +#define XACT_S_OKINFORM _HRESULT_TYPEDEF_(0x0004D004L) +#define XACT_S_MADECHANGESCONTENT _HRESULT_TYPEDEF_(0x0004D005L) +#define XACT_S_MADECHANGESINFORM _HRESULT_TYPEDEF_(0x0004D006L) +#define XACT_S_ALLNORETAIN _HRESULT_TYPEDEF_(0x0004D007L) +#define XACT_S_ABORTING _HRESULT_TYPEDEF_(0x0004D008L) +#define XACT_S_SINGLEPHASE _HRESULT_TYPEDEF_(0x0004D009L) +#define XACT_S_LOCALLY_OK _HRESULT_TYPEDEF_(0x0004D00AL) +#define XACT_S_LASTRESOURCEMANAGER _HRESULT_TYPEDEF_(0x0004D010L) +#define CONTEXT_E_FIRST 0x8004E000L +#define CONTEXT_E_LAST 0x8004E02FL +#define CONTEXT_S_FIRST 0x0004E000L +#define CONTEXT_S_LAST 0x0004E02FL +#define CONTEXT_E_ABORTED _HRESULT_TYPEDEF_(0x8004E002L) +#define CONTEXT_E_ABORTING _HRESULT_TYPEDEF_(0x8004E003L) +#define CONTEXT_E_NOCONTEXT _HRESULT_TYPEDEF_(0x8004E004L) +#define CONTEXT_E_WOULD_DEADLOCK _HRESULT_TYPEDEF_(0x8004E005L) +#define CONTEXT_E_SYNCH_TIMEOUT _HRESULT_TYPEDEF_(0x8004E006L) +#define CONTEXT_E_OLDREF _HRESULT_TYPEDEF_(0x8004E007L) +#define CONTEXT_E_ROLENOTFOUND _HRESULT_TYPEDEF_(0x8004E00CL) +#define CONTEXT_E_TMNOTAVAILABLE _HRESULT_TYPEDEF_(0x8004E00FL) +#define CO_E_ACTIVATIONFAILED _HRESULT_TYPEDEF_(0x8004E021L) +#define CO_E_ACTIVATIONFAILED_EVENTLOGGED _HRESULT_TYPEDEF_(0x8004E022L) +#define CO_E_ACTIVATIONFAILED_CATALOGERROR _HRESULT_TYPEDEF_(0x8004E023L) +#define CO_E_ACTIVATIONFAILED_TIMEOUT _HRESULT_TYPEDEF_(0x8004E024L) +#define CO_E_INITIALIZATIONFAILED _HRESULT_TYPEDEF_(0x8004E025L) +#define CONTEXT_E_NOJIT _HRESULT_TYPEDEF_(0x8004E026L) +#define CONTEXT_E_NOTRANSACTION _HRESULT_TYPEDEF_(0x8004E027L) +#define CO_E_THREADINGMODEL_CHANGED _HRESULT_TYPEDEF_(0x8004E028L) +#define CO_E_NOIISINTRINSICS _HRESULT_TYPEDEF_(0x8004E029L) +#define CO_E_NOCOOKIES _HRESULT_TYPEDEF_(0x8004E02AL) +#define CO_E_DBERROR _HRESULT_TYPEDEF_(0x8004E02BL) +#define CO_E_NOTPOOLED _HRESULT_TYPEDEF_(0x8004E02CL) +#define CO_E_NOTCONSTRUCTED _HRESULT_TYPEDEF_(0x8004E02DL) +#define CO_E_NOSYNCHRONIZATION _HRESULT_TYPEDEF_(0x8004E02EL) +#define CO_E_ISOLEVELMISMATCH _HRESULT_TYPEDEF_(0x8004E02FL) +#define OLE_S_USEREG _HRESULT_TYPEDEF_(0x00040000L) +#define OLE_S_STATIC _HRESULT_TYPEDEF_(0x00040001L) +#define OLE_S_MAC_CLIPFORMAT _HRESULT_TYPEDEF_(0x00040002L) +#define DRAGDROP_S_DROP _HRESULT_TYPEDEF_(0x00040100L) +#define DRAGDROP_S_CANCEL _HRESULT_TYPEDEF_(0x00040101L) +#define DRAGDROP_S_USEDEFAULTCURSORS _HRESULT_TYPEDEF_(0x00040102L) +#define DATA_S_SAMEFORMATETC _HRESULT_TYPEDEF_(0x00040130L) +#define VIEW_S_ALREADY_FROZEN _HRESULT_TYPEDEF_(0x00040140L) +#define CACHE_S_FORMATETC_NOTSUPPORTED _HRESULT_TYPEDEF_(0x00040170L) +#define CACHE_S_SAMECACHE _HRESULT_TYPEDEF_(0x00040171L) +#define CACHE_S_SOMECACHES_NOTUPDATED _HRESULT_TYPEDEF_(0x00040172L) +#define OLEOBJ_S_INVALIDVERB _HRESULT_TYPEDEF_(0x00040180L) +#define OLEOBJ_S_CANNOT_DOVERB_NOW _HRESULT_TYPEDEF_(0x00040181L) +#define OLEOBJ_S_INVALIDHWND _HRESULT_TYPEDEF_(0x00040182L) +#define INPLACE_S_TRUNCATED _HRESULT_TYPEDEF_(0x000401A0L) +#define CONVERT10_S_NO_PRESENTATION _HRESULT_TYPEDEF_(0x000401C0L) +#define MK_S_REDUCED_TO_SELF _HRESULT_TYPEDEF_(0x000401E2L) +#define MK_S_ME _HRESULT_TYPEDEF_(0x000401E4L) +#define MK_S_HIM _HRESULT_TYPEDEF_(0x000401E5L) +#define MK_S_US _HRESULT_TYPEDEF_(0x000401E6L) +#define MK_S_MONIKERALREADYREGISTERED _HRESULT_TYPEDEF_(0x000401E7L) +#define SCHED_S_TASK_READY _HRESULT_TYPEDEF_(0x00041300L) +#define SCHED_S_TASK_RUNNING _HRESULT_TYPEDEF_(0x00041301L) +#define SCHED_S_TASK_DISABLED _HRESULT_TYPEDEF_(0x00041302L) +#define SCHED_S_TASK_HAS_NOT_RUN _HRESULT_TYPEDEF_(0x00041303L) +#define SCHED_S_TASK_NO_MORE_RUNS _HRESULT_TYPEDEF_(0x00041304L) +#define SCHED_S_TASK_NOT_SCHEDULED _HRESULT_TYPEDEF_(0x00041305L) +#define SCHED_S_TASK_TERMINATED _HRESULT_TYPEDEF_(0x00041306L) +#define SCHED_S_TASK_NO_VALID_TRIGGERS _HRESULT_TYPEDEF_(0x00041307L) +#define SCHED_S_EVENT_TRIGGER _HRESULT_TYPEDEF_(0x00041308L) +#define SCHED_E_TRIGGER_NOT_FOUND _HRESULT_TYPEDEF_(0x80041309L) +#define SCHED_E_TASK_NOT_READY _HRESULT_TYPEDEF_(0x8004130AL) +#define SCHED_E_TASK_NOT_RUNNING _HRESULT_TYPEDEF_(0x8004130BL) +#define SCHED_E_SERVICE_NOT_INSTALLED _HRESULT_TYPEDEF_(0x8004130CL) +#define SCHED_E_CANNOT_OPEN_TASK _HRESULT_TYPEDEF_(0x8004130DL) +#define SCHED_E_INVALID_TASK _HRESULT_TYPEDEF_(0x8004130EL) +#define SCHED_E_ACCOUNT_INFORMATION_NOT_SET _HRESULT_TYPEDEF_(0x8004130FL) +#define SCHED_E_ACCOUNT_NAME_NOT_FOUND _HRESULT_TYPEDEF_(0x80041310L) +#define SCHED_E_ACCOUNT_DBASE_CORRUPT _HRESULT_TYPEDEF_(0x80041311L) +#define SCHED_E_NO_SECURITY_SERVICES _HRESULT_TYPEDEF_(0x80041312L) +#define SCHED_E_UNKNOWN_OBJECT_VERSION _HRESULT_TYPEDEF_(0x80041313L) +#define SCHED_E_UNSUPPORTED_ACCOUNT_OPTION _HRESULT_TYPEDEF_(0x80041314L) +#define SCHED_E_SERVICE_NOT_RUNNING _HRESULT_TYPEDEF_(0x80041315L) +#define CO_E_CLASS_CREATE_FAILED _HRESULT_TYPEDEF_(0x80080001L) +#define CO_E_SCM_ERROR _HRESULT_TYPEDEF_(0x80080002L) +#define CO_E_SCM_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080003L) +#define CO_E_BAD_PATH _HRESULT_TYPEDEF_(0x80080004L) +#define CO_E_SERVER_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80080005L) +#define CO_E_OBJSRV_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080006L) +#define MK_E_NO_NORMALIZED _HRESULT_TYPEDEF_(0x80080007L) +#define CO_E_SERVER_STOPPING _HRESULT_TYPEDEF_(0x80080008L) +#define MEM_E_INVALID_ROOT _HRESULT_TYPEDEF_(0x80080009L) +#define MEM_E_INVALID_LINK _HRESULT_TYPEDEF_(0x80080010L) +#define MEM_E_INVALID_SIZE _HRESULT_TYPEDEF_(0x80080011L) +#define CO_S_NOTALLINTERFACES _HRESULT_TYPEDEF_(0x00080012L) +#define CO_S_MACHINENAMENOTFOUND _HRESULT_TYPEDEF_(0x00080013L) +#define DISP_E_UNKNOWNINTERFACE _HRESULT_TYPEDEF_(0x80020001L) +#define DISP_E_MEMBERNOTFOUND _HRESULT_TYPEDEF_(0x80020003L) +#define DISP_E_PARAMNOTFOUND _HRESULT_TYPEDEF_(0x80020004L) +#define DISP_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80020005L) +#define DISP_E_UNKNOWNNAME _HRESULT_TYPEDEF_(0x80020006L) +#define DISP_E_NONAMEDARGS _HRESULT_TYPEDEF_(0x80020007L) +#define DISP_E_BADVARTYPE _HRESULT_TYPEDEF_(0x80020008L) +#define DISP_E_EXCEPTION _HRESULT_TYPEDEF_(0x80020009L) +#define DISP_E_OVERFLOW _HRESULT_TYPEDEF_(0x8002000AL) +#define DISP_E_BADINDEX _HRESULT_TYPEDEF_(0x8002000BL) +#define DISP_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002000CL) +#define DISP_E_ARRAYISLOCKED _HRESULT_TYPEDEF_(0x8002000DL) +#define DISP_E_BADPARAMCOUNT _HRESULT_TYPEDEF_(0x8002000EL) +#define DISP_E_PARAMNOTOPTIONAL _HRESULT_TYPEDEF_(0x8002000FL) +#define DISP_E_BADCALLEE _HRESULT_TYPEDEF_(0x80020010L) +#define DISP_E_NOTACOLLECTION _HRESULT_TYPEDEF_(0x80020011L) +#define DISP_E_DIVBYZERO _HRESULT_TYPEDEF_(0x80020012L) +#define DISP_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80020013L) +#define TYPE_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80028016L) +#define TYPE_E_FIELDNOTFOUND _HRESULT_TYPEDEF_(0x80028017L) +#define TYPE_E_INVDATAREAD _HRESULT_TYPEDEF_(0x80028018L) +#define TYPE_E_UNSUPFORMAT _HRESULT_TYPEDEF_(0x80028019L) +#define TYPE_E_REGISTRYACCESS _HRESULT_TYPEDEF_(0x8002801CL) +#define TYPE_E_LIBNOTREGISTERED _HRESULT_TYPEDEF_(0x8002801DL) +#define TYPE_E_UNDEFINEDTYPE _HRESULT_TYPEDEF_(0x80028027L) +#define TYPE_E_QUALIFIEDNAMEDISALLOWED _HRESULT_TYPEDEF_(0x80028028L) +#define TYPE_E_INVALIDSTATE _HRESULT_TYPEDEF_(0x80028029L) +#define TYPE_E_WRONGTYPEKIND _HRESULT_TYPEDEF_(0x8002802AL) +#define TYPE_E_ELEMENTNOTFOUND _HRESULT_TYPEDEF_(0x8002802BL) +#define TYPE_E_AMBIGUOUSNAME _HRESULT_TYPEDEF_(0x8002802CL) +#define TYPE_E_NAMECONFLICT _HRESULT_TYPEDEF_(0x8002802DL) +#define TYPE_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002802EL) +#define TYPE_E_DLLFUNCTIONNOTFOUND _HRESULT_TYPEDEF_(0x8002802FL) +#define TYPE_E_BADMODULEKIND _HRESULT_TYPEDEF_(0x800288BDL) +#define TYPE_E_SIZETOOBIG _HRESULT_TYPEDEF_(0x800288C5L) +#define TYPE_E_DUPLICATEID _HRESULT_TYPEDEF_(0x800288C6L) +#define TYPE_E_INVALIDID _HRESULT_TYPEDEF_(0x800288CFL) +#define TYPE_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80028CA0L) +#define TYPE_E_OUTOFBOUNDS _HRESULT_TYPEDEF_(0x80028CA1L) +#define TYPE_E_IOERROR _HRESULT_TYPEDEF_(0x80028CA2L) +#define TYPE_E_CANTCREATETMPFILE _HRESULT_TYPEDEF_(0x80028CA3L) +#define TYPE_E_CANTLOADLIBRARY _HRESULT_TYPEDEF_(0x80029C4AL) +#define TYPE_E_INCONSISTENTPROPFUNCS _HRESULT_TYPEDEF_(0x80029C83L) +#define TYPE_E_CIRCULARTYPE _HRESULT_TYPEDEF_(0x80029C84L) +#define STG_E_INVALIDFUNCTION _HRESULT_TYPEDEF_(0x80030001L) +#define STG_E_FILENOTFOUND _HRESULT_TYPEDEF_(0x80030002L) +#define STG_E_PATHNOTFOUND _HRESULT_TYPEDEF_(0x80030003L) +#define STG_E_TOOMANYOPENFILES _HRESULT_TYPEDEF_(0x80030004L) +#define STG_E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80030005L) +#define STG_E_INVALIDHANDLE _HRESULT_TYPEDEF_(0x80030006L) +#define STG_E_INSUFFICIENTMEMORY _HRESULT_TYPEDEF_(0x80030008L) +#define STG_E_INVALIDPOINTER _HRESULT_TYPEDEF_(0x80030009L) +#define STG_E_NOMOREFILES _HRESULT_TYPEDEF_(0x80030012L) +#define STG_E_DISKISWRITEPROTECTED _HRESULT_TYPEDEF_(0x80030013L) +#define STG_E_SEEKERROR _HRESULT_TYPEDEF_(0x80030019L) +#define STG_E_WRITEFAULT _HRESULT_TYPEDEF_(0x8003001DL) +#define STG_E_READFAULT _HRESULT_TYPEDEF_(0x8003001EL) +#define STG_E_SHAREVIOLATION _HRESULT_TYPEDEF_(0x80030020L) +#define STG_E_LOCKVIOLATION _HRESULT_TYPEDEF_(0x80030021L) +#define STG_E_FILEALREADYEXISTS _HRESULT_TYPEDEF_(0x80030050L) +#define STG_E_INVALIDPARAMETER _HRESULT_TYPEDEF_(0x80030057L) +#define STG_E_MEDIUMFULL _HRESULT_TYPEDEF_(0x80030070L) +#define STG_E_PROPSETMISMATCHED _HRESULT_TYPEDEF_(0x800300F0L) +#define STG_E_ABNORMALAPIEXIT _HRESULT_TYPEDEF_(0x800300FAL) +#define STG_E_INVALIDHEADER _HRESULT_TYPEDEF_(0x800300FBL) +#define STG_E_INVALIDNAME _HRESULT_TYPEDEF_(0x800300FCL) +#define STG_E_UNKNOWN _HRESULT_TYPEDEF_(0x800300FDL) +#define STG_E_UNIMPLEMENTEDFUNCTION _HRESULT_TYPEDEF_(0x800300FEL) +#define STG_E_INVALIDFLAG _HRESULT_TYPEDEF_(0x800300FFL) +#define STG_E_INUSE _HRESULT_TYPEDEF_(0x80030100L) +#define STG_E_NOTCURRENT _HRESULT_TYPEDEF_(0x80030101L) +#define STG_E_REVERTED _HRESULT_TYPEDEF_(0x80030102L) +#define STG_E_CANTSAVE _HRESULT_TYPEDEF_(0x80030103L) +#define STG_E_OLDFORMAT _HRESULT_TYPEDEF_(0x80030104L) +#define STG_E_OLDDLL _HRESULT_TYPEDEF_(0x80030105L) +#define STG_E_SHAREREQUIRED _HRESULT_TYPEDEF_(0x80030106L) +#define STG_E_NOTFILEBASEDSTORAGE _HRESULT_TYPEDEF_(0x80030107L) +#define STG_E_EXTANTMARSHALLINGS _HRESULT_TYPEDEF_(0x80030108L) +#define STG_E_DOCFILECORRUPT _HRESULT_TYPEDEF_(0x80030109L) +#define STG_E_BADBASEADDRESS _HRESULT_TYPEDEF_(0x80030110L) +#define STG_E_DOCFILETOOLARGE _HRESULT_TYPEDEF_(0x80030111L) +#define STG_E_NOTSIMPLEFORMAT _HRESULT_TYPEDEF_(0x80030112L) +#define STG_E_INCOMPLETE _HRESULT_TYPEDEF_(0x80030201L) +#define STG_E_TERMINATED _HRESULT_TYPEDEF_(0x80030202L) +#define STG_S_CONVERTED _HRESULT_TYPEDEF_(0x00030200L) +#define STG_S_BLOCK _HRESULT_TYPEDEF_(0x00030201L) +#define STG_S_RETRYNOW _HRESULT_TYPEDEF_(0x00030202L) +#define STG_S_MONITORING _HRESULT_TYPEDEF_(0x00030203L) +#define STG_S_MULTIPLEOPENS _HRESULT_TYPEDEF_(0x00030204L) +#define STG_S_CONSOLIDATIONFAILED _HRESULT_TYPEDEF_(0x00030205L) +#define STG_S_CANNOTCONSOLIDATE _HRESULT_TYPEDEF_(0x00030206L) +#define STG_E_STATUS_COPY_PROTECTION_FAILURE _HRESULT_TYPEDEF_(0x80030305L) +#define STG_E_CSS_AUTHENTICATION_FAILURE _HRESULT_TYPEDEF_(0x80030306L) +#define STG_E_CSS_KEY_NOT_PRESENT _HRESULT_TYPEDEF_(0x80030307L) +#define STG_E_CSS_KEY_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x80030308L) +#define STG_E_CSS_SCRAMBLED_SECTOR _HRESULT_TYPEDEF_(0x80030309L) +#define STG_E_CSS_REGION_MISMATCH _HRESULT_TYPEDEF_(0x8003030AL) +#define STG_E_RESETS_EXHAUSTED _HRESULT_TYPEDEF_(0x8003030BL) +#define RPC_E_CALL_REJECTED _HRESULT_TYPEDEF_(0x80010001L) +#define RPC_E_CALL_CANCELED _HRESULT_TYPEDEF_(0x80010002L) +#define RPC_E_CANTPOST_INSENDCALL _HRESULT_TYPEDEF_(0x80010003L) +#define RPC_E_CANTCALLOUT_INASYNCCALL _HRESULT_TYPEDEF_(0x80010004L) +#define RPC_E_CANTCALLOUT_INEXTERNALCALL _HRESULT_TYPEDEF_(0x80010005L) +#define RPC_E_CONNECTION_TERMINATED _HRESULT_TYPEDEF_(0x80010006L) +#define RPC_E_SERVER_DIED _HRESULT_TYPEDEF_(0x80010007L) +#define RPC_E_CLIENT_DIED _HRESULT_TYPEDEF_(0x80010008L) +#define RPC_E_INVALID_DATAPACKET _HRESULT_TYPEDEF_(0x80010009L) +#define RPC_E_CANTTRANSMIT_CALL _HRESULT_TYPEDEF_(0x8001000AL) +#define RPC_E_CLIENT_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000BL) +#define RPC_E_CLIENT_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000CL) +#define RPC_E_SERVER_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000DL) +#define RPC_E_SERVER_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000EL) +#define RPC_E_INVALID_DATA _HRESULT_TYPEDEF_(0x8001000FL) +#define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L) +#define RPC_E_CANTCALLOUT_AGAIN _HRESULT_TYPEDEF_(0x80010011L) +#define RPC_E_SERVER_DIED_DNE _HRESULT_TYPEDEF_(0x80010012L) +#define RPC_E_SYS_CALL_FAILED _HRESULT_TYPEDEF_(0x80010100L) +#define RPC_E_OUT_OF_RESOURCES _HRESULT_TYPEDEF_(0x80010101L) +#define RPC_E_ATTEMPTED_MULTITHREAD _HRESULT_TYPEDEF_(0x80010102L) +#define RPC_E_NOT_REGISTERED _HRESULT_TYPEDEF_(0x80010103L) +#define RPC_E_FAULT _HRESULT_TYPEDEF_(0x80010104L) +#define RPC_E_SERVERFAULT _HRESULT_TYPEDEF_(0x80010105L) +#define RPC_E_CHANGED_MODE _HRESULT_TYPEDEF_(0x80010106L) +#define RPC_E_INVALIDMETHOD _HRESULT_TYPEDEF_(0x80010107L) +#define RPC_E_DISCONNECTED _HRESULT_TYPEDEF_(0x80010108L) +#define RPC_E_RETRY _HRESULT_TYPEDEF_(0x80010109L) +#define RPC_E_SERVERCALL_RETRYLATER _HRESULT_TYPEDEF_(0x8001010AL) +#define RPC_E_SERVERCALL_REJECTED _HRESULT_TYPEDEF_(0x8001010BL) +#define RPC_E_INVALID_CALLDATA _HRESULT_TYPEDEF_(0x8001010CL) +#define RPC_E_CANTCALLOUT_ININPUTSYNCCALL _HRESULT_TYPEDEF_(0x8001010DL) +#define RPC_E_WRONG_THREAD _HRESULT_TYPEDEF_(0x8001010EL) +#define RPC_E_THREAD_NOT_INIT _HRESULT_TYPEDEF_(0x8001010FL) +#define RPC_E_VERSION_MISMATCH _HRESULT_TYPEDEF_(0x80010110L) +#define RPC_E_INVALID_HEADER _HRESULT_TYPEDEF_(0x80010111L) +#define RPC_E_INVALID_EXTENSION _HRESULT_TYPEDEF_(0x80010112L) +#define RPC_E_INVALID_IPID _HRESULT_TYPEDEF_(0x80010113L) +#define RPC_E_INVALID_OBJECT _HRESULT_TYPEDEF_(0x80010114L) +#define RPC_S_CALLPENDING _HRESULT_TYPEDEF_(0x80010115L) +#define RPC_S_WAITONTIMER _HRESULT_TYPEDEF_(0x80010116L) +#define RPC_E_CALL_COMPLETE _HRESULT_TYPEDEF_(0x80010117L) +#define RPC_E_UNSECURE_CALL _HRESULT_TYPEDEF_(0x80010118L) +#define RPC_E_TOO_LATE _HRESULT_TYPEDEF_(0x80010119L) +#define RPC_E_NO_GOOD_SECURITY_PACKAGES _HRESULT_TYPEDEF_(0x8001011AL) +#define RPC_E_ACCESS_DENIED _HRESULT_TYPEDEF_(0x8001011BL) +#define RPC_E_REMOTE_DISABLED _HRESULT_TYPEDEF_(0x8001011CL) +#define RPC_E_INVALID_OBJREF _HRESULT_TYPEDEF_(0x8001011DL) +#define RPC_E_NO_CONTEXT _HRESULT_TYPEDEF_(0x8001011EL) +#define RPC_E_TIMEOUT _HRESULT_TYPEDEF_(0x8001011FL) +#define RPC_E_NO_SYNC _HRESULT_TYPEDEF_(0x80010120L) +#define RPC_E_FULLSIC_REQUIRED _HRESULT_TYPEDEF_(0x80010121L) +#define RPC_E_INVALID_STD_NAME _HRESULT_TYPEDEF_(0x80010122L) +#define CO_E_FAILEDTOIMPERSONATE _HRESULT_TYPEDEF_(0x80010123L) +#define CO_E_FAILEDTOGETSECCTX _HRESULT_TYPEDEF_(0x80010124L) +#define CO_E_FAILEDTOOPENTHREADTOKEN _HRESULT_TYPEDEF_(0x80010125L) +#define CO_E_FAILEDTOGETTOKENINFO _HRESULT_TYPEDEF_(0x80010126L) +#define CO_E_TRUSTEEDOESNTMATCHCLIENT _HRESULT_TYPEDEF_(0x80010127L) +#define CO_E_FAILEDTOQUERYCLIENTBLANKET _HRESULT_TYPEDEF_(0x80010128L) +#define CO_E_FAILEDTOSETDACL _HRESULT_TYPEDEF_(0x80010129L) +#define CO_E_ACCESSCHECKFAILED _HRESULT_TYPEDEF_(0x8001012AL) +#define CO_E_NETACCESSAPIFAILED _HRESULT_TYPEDEF_(0x8001012BL) +#define CO_E_WRONGTRUSTEENAMESYNTAX _HRESULT_TYPEDEF_(0x8001012CL) +#define CO_E_INVALIDSID _HRESULT_TYPEDEF_(0x8001012DL) +#define CO_E_CONVERSIONFAILED _HRESULT_TYPEDEF_(0x8001012EL) +#define CO_E_NOMATCHINGSIDFOUND _HRESULT_TYPEDEF_(0x8001012FL) +#define CO_E_LOOKUPACCSIDFAILED _HRESULT_TYPEDEF_(0x80010130L) +#define CO_E_NOMATCHINGNAMEFOUND _HRESULT_TYPEDEF_(0x80010131L) +#define CO_E_LOOKUPACCNAMEFAILED _HRESULT_TYPEDEF_(0x80010132L) +#define CO_E_SETSERLHNDLFAILED _HRESULT_TYPEDEF_(0x80010133L) +#define CO_E_FAILEDTOGETWINDIR _HRESULT_TYPEDEF_(0x80010134L) +#define CO_E_PATHTOOLONG _HRESULT_TYPEDEF_(0x80010135L) +#define CO_E_FAILEDTOGENUUID _HRESULT_TYPEDEF_(0x80010136L) +#define CO_E_FAILEDTOCREATEFILE _HRESULT_TYPEDEF_(0x80010137L) +#define CO_E_FAILEDTOCLOSEHANDLE _HRESULT_TYPEDEF_(0x80010138L) +#define CO_E_EXCEEDSYSACLLIMIT _HRESULT_TYPEDEF_(0x80010139L) +#define CO_E_ACESINWRONGORDER _HRESULT_TYPEDEF_(0x8001013AL) +#define CO_E_INCOMPATIBLESTREAMVERSION _HRESULT_TYPEDEF_(0x8001013BL) +#define CO_E_FAILEDTOOPENPROCESSTOKEN _HRESULT_TYPEDEF_(0x8001013CL) +#define CO_E_DECODEFAILED _HRESULT_TYPEDEF_(0x8001013DL) +#define CO_E_ACNOTINITIALIZED _HRESULT_TYPEDEF_(0x8001013FL) +#define CO_E_CANCEL_DISABLED _HRESULT_TYPEDEF_(0x80010140L) +#define RPC_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8001FFFFL) +#define ERROR_AUDITING_DISABLED _HRESULT_TYPEDEF_(0xC0090001L) +#define ERROR_ALL_SIDS_FILTERED _HRESULT_TYPEDEF_(0xC0090002L) +#define NTE_BAD_UID _HRESULT_TYPEDEF_(0x80090001L) +#define NTE_BAD_HASH _HRESULT_TYPEDEF_(0x80090002L) +#define NTE_BAD_KEY _HRESULT_TYPEDEF_(0x80090003L) +#define NTE_BAD_LEN _HRESULT_TYPEDEF_(0x80090004L) +#define NTE_BAD_DATA _HRESULT_TYPEDEF_(0x80090005L) +#define NTE_BAD_SIGNATURE _HRESULT_TYPEDEF_(0x80090006L) +#define NTE_BAD_VER _HRESULT_TYPEDEF_(0x80090007L) +#define NTE_BAD_ALGID _HRESULT_TYPEDEF_(0x80090008L) +#define NTE_BAD_FLAGS _HRESULT_TYPEDEF_(0x80090009L) +#define NTE_BAD_TYPE _HRESULT_TYPEDEF_(0x8009000AL) +#define NTE_BAD_KEY_STATE _HRESULT_TYPEDEF_(0x8009000BL) +#define NTE_BAD_HASH_STATE _HRESULT_TYPEDEF_(0x8009000CL) +#define NTE_NO_KEY _HRESULT_TYPEDEF_(0x8009000DL) +#define NTE_NO_MEMORY _HRESULT_TYPEDEF_(0x8009000EL) +#define NTE_EXISTS _HRESULT_TYPEDEF_(0x8009000FL) +#define NTE_PERM _HRESULT_TYPEDEF_(0x80090010L) +#define NTE_NOT_FOUND _HRESULT_TYPEDEF_(0x80090011L) +#define NTE_DOUBLE_ENCRYPT _HRESULT_TYPEDEF_(0x80090012L) +#define NTE_BAD_PROVIDER _HRESULT_TYPEDEF_(0x80090013L) +#define NTE_BAD_PROV_TYPE _HRESULT_TYPEDEF_(0x80090014L) +#define NTE_BAD_PUBLIC_KEY _HRESULT_TYPEDEF_(0x80090015L) +#define NTE_BAD_KEYSET _HRESULT_TYPEDEF_(0x80090016L) +#define NTE_PROV_TYPE_NOT_DEF _HRESULT_TYPEDEF_(0x80090017L) +#define NTE_PROV_TYPE_ENTRY_BAD _HRESULT_TYPEDEF_(0x80090018L) +#define NTE_KEYSET_NOT_DEF _HRESULT_TYPEDEF_(0x80090019L) +#define NTE_KEYSET_ENTRY_BAD _HRESULT_TYPEDEF_(0x8009001AL) +#define NTE_PROV_TYPE_NO_MATCH _HRESULT_TYPEDEF_(0x8009001BL) +#define NTE_SIGNATURE_FILE_BAD _HRESULT_TYPEDEF_(0x8009001CL) +#define NTE_PROVIDER_DLL_FAIL _HRESULT_TYPEDEF_(0x8009001DL) +#define NTE_PROV_DLL_NOT_FOUND _HRESULT_TYPEDEF_(0x8009001EL) +#define NTE_BAD_KEYSET_PARAM _HRESULT_TYPEDEF_(0x8009001FL) +#define NTE_FAIL _HRESULT_TYPEDEF_(0x80090020L) +#define NTE_SYS_ERR _HRESULT_TYPEDEF_(0x80090021L) +#define NTE_SILENT_CONTEXT _HRESULT_TYPEDEF_(0x80090022L) +#define NTE_TOKEN_KEYSET_STORAGE_FULL _HRESULT_TYPEDEF_(0x80090023L) +#define NTE_TEMPORARY_PROFILE _HRESULT_TYPEDEF_(0x80090024L) +#define NTE_FIXEDPARAMETER _HRESULT_TYPEDEF_(0x80090025L) +#define SEC_E_INSUFFICIENT_MEMORY _HRESULT_TYPEDEF_(0x80090300L) +#define SEC_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80090301L) +#define SEC_E_UNSUPPORTED_FUNCTION _HRESULT_TYPEDEF_(0x80090302L) +#define SEC_E_TARGET_UNKNOWN _HRESULT_TYPEDEF_(0x80090303L) +#define SEC_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80090304L) +#define SEC_E_SECPKG_NOT_FOUND _HRESULT_TYPEDEF_(0x80090305L) +#define SEC_E_NOT_OWNER _HRESULT_TYPEDEF_(0x80090306L) +#define SEC_E_CANNOT_INSTALL _HRESULT_TYPEDEF_(0x80090307L) +#define SEC_E_INVALID_TOKEN _HRESULT_TYPEDEF_(0x80090308L) +#define SEC_E_CANNOT_PACK _HRESULT_TYPEDEF_(0x80090309L) +#define SEC_E_QOP_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009030AL) +#define SEC_E_NO_IMPERSONATION _HRESULT_TYPEDEF_(0x8009030BL) +#define SEC_E_LOGON_DENIED _HRESULT_TYPEDEF_(0x8009030CL) +#define SEC_E_UNKNOWN_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030DL) +#define SEC_E_NO_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030EL) +#define SEC_E_MESSAGE_ALTERED _HRESULT_TYPEDEF_(0x8009030FL) +#define SEC_E_OUT_OF_SEQUENCE _HRESULT_TYPEDEF_(0x80090310L) +#define SEC_E_NO_AUTHENTICATING_AUTHORITY _HRESULT_TYPEDEF_(0x80090311L) +#define SEC_I_CONTINUE_NEEDED _HRESULT_TYPEDEF_(0x00090312L) +#define SEC_I_COMPLETE_NEEDED _HRESULT_TYPEDEF_(0x00090313L) +#define SEC_I_COMPLETE_AND_CONTINUE _HRESULT_TYPEDEF_(0x00090314L) +#define SEC_I_LOCAL_LOGON _HRESULT_TYPEDEF_(0x00090315L) +#define SEC_E_BAD_PKGID _HRESULT_TYPEDEF_(0x80090316L) +#define SEC_E_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x80090317L) +#define SEC_I_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x00090317L) +#define SEC_E_INCOMPLETE_MESSAGE _HRESULT_TYPEDEF_(0x80090318L) +#define SEC_E_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x80090320L) +#define SEC_E_BUFFER_TOO_SMALL _HRESULT_TYPEDEF_(0x80090321L) +#define SEC_I_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x00090320L) +#define SEC_I_RENEGOTIATE _HRESULT_TYPEDEF_(0x00090321L) +#define SEC_E_WRONG_PRINCIPAL _HRESULT_TYPEDEF_(0x80090322L) +#define SEC_I_NO_LSA_CONTEXT _HRESULT_TYPEDEF_(0x00090323L) +#define SEC_E_TIME_SKEW _HRESULT_TYPEDEF_(0x80090324L) +#define SEC_E_UNTRUSTED_ROOT _HRESULT_TYPEDEF_(0x80090325L) +#define SEC_E_ILLEGAL_MESSAGE _HRESULT_TYPEDEF_(0x80090326L) +#define SEC_E_CERT_UNKNOWN _HRESULT_TYPEDEF_(0x80090327L) +#define SEC_E_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090328L) +#define SEC_E_ENCRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090329L) +#define SEC_E_DECRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090330L) +#define SEC_E_ALGORITHM_MISMATCH _HRESULT_TYPEDEF_(0x80090331L) +#define SEC_E_SECURITY_QOS_FAILED _HRESULT_TYPEDEF_(0x80090332L) +#define SEC_E_UNFINISHED_CONTEXT_DELETED _HRESULT_TYPEDEF_(0x80090333L) +#define SEC_E_NO_TGT_REPLY _HRESULT_TYPEDEF_(0x80090334L) +#define SEC_E_NO_IP_ADDRESSES _HRESULT_TYPEDEF_(0x80090335L) +#define SEC_E_WRONG_CREDENTIAL_HANDLE _HRESULT_TYPEDEF_(0x80090336L) +#define SEC_E_CRYPTO_SYSTEM_INVALID _HRESULT_TYPEDEF_(0x80090337L) +#define SEC_E_MAX_REFERRALS_EXCEEDED _HRESULT_TYPEDEF_(0x80090338L) +#define SEC_E_MUST_BE_KDC _HRESULT_TYPEDEF_(0x80090339L) +#define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009033AL) +#define SEC_E_TOO_MANY_PRINCIPALS _HRESULT_TYPEDEF_(0x8009033BL) +#define SEC_E_NO_PA_DATA _HRESULT_TYPEDEF_(0x8009033CL) +#define SEC_E_PKINIT_NAME_MISMATCH _HRESULT_TYPEDEF_(0x8009033DL) +#define SEC_E_SMARTCARD_LOGON_REQUIRED _HRESULT_TYPEDEF_(0x8009033EL) +#define SEC_E_SHUTDOWN_IN_PROGRESS _HRESULT_TYPEDEF_(0x8009033FL) +#define SEC_E_KDC_INVALID_REQUEST _HRESULT_TYPEDEF_(0x80090340L) +#define SEC_E_KDC_UNABLE_TO_REFER _HRESULT_TYPEDEF_(0x80090341L) +#define SEC_E_KDC_UNKNOWN_ETYPE _HRESULT_TYPEDEF_(0x80090342L) +#define SEC_E_UNSUPPORTED_PREAUTH _HRESULT_TYPEDEF_(0x80090343L) +#define SEC_E_DELEGATION_REQUIRED _HRESULT_TYPEDEF_(0x80090345L) +#define SEC_E_BAD_BINDINGS _HRESULT_TYPEDEF_(0x80090346L) +#define SEC_E_MULTIPLE_ACCOUNTS _HRESULT_TYPEDEF_(0x80090347L) +#define SEC_E_NO_KERB_KEY _HRESULT_TYPEDEF_(0x80090348L) +#define SEC_E_CERT_WRONG_USAGE _HRESULT_TYPEDEF_(0x80090349L) +#define SEC_E_DOWNGRADE_DETECTED _HRESULT_TYPEDEF_(0x80090350L) +#define SEC_E_SMARTCARD_CERT_REVOKED _HRESULT_TYPEDEF_(0x80090351L) +#define SEC_E_ISSUING_CA_UNTRUSTED _HRESULT_TYPEDEF_(0x80090352L) +#define SEC_E_REVOCATION_OFFLINE_C _HRESULT_TYPEDEF_(0x80090353L) +#define SEC_E_PKINIT_CLIENT_FAILURE _HRESULT_TYPEDEF_(0x80090354L) +#define SEC_E_SMARTCARD_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090355L) +#define SEC_E_NO_S4U_PROT_SUPPORT _HRESULT_TYPEDEF_(0x80090356L) +#define SEC_E_CROSSREALM_DELEGATION_FAILURE _HRESULT_TYPEDEF_(0x80090357L) +#define SEC_E_REVOCATION_OFFLINE_KDC _HRESULT_TYPEDEF_(0x80090358L) +#define SEC_E_ISSUING_CA_UNTRUSTED_KDC _HRESULT_TYPEDEF_(0x80090359L) +#define SEC_E_KDC_CERT_EXPIRED _HRESULT_TYPEDEF_(0x8009035AL) +#define SEC_E_KDC_CERT_REVOKED _HRESULT_TYPEDEF_(0x8009035BL) +#define SEC_E_NO_SPM SEC_E_INTERNAL_ERROR +#define SEC_E_NOT_SUPPORTED SEC_E_UNSUPPORTED_FUNCTION +#define CRYPT_E_MSG_ERROR _HRESULT_TYPEDEF_(0x80091001L) +#define CRYPT_E_UNKNOWN_ALGO _HRESULT_TYPEDEF_(0x80091002L) +#define CRYPT_E_OID_FORMAT _HRESULT_TYPEDEF_(0x80091003L) +#define CRYPT_E_INVALID_MSG_TYPE _HRESULT_TYPEDEF_(0x80091004L) +#define CRYPT_E_UNEXPECTED_ENCODING _HRESULT_TYPEDEF_(0x80091005L) +#define CRYPT_E_AUTH_ATTR_MISSING _HRESULT_TYPEDEF_(0x80091006L) +#define CRYPT_E_HASH_VALUE _HRESULT_TYPEDEF_(0x80091007L) +#define CRYPT_E_INVALID_INDEX _HRESULT_TYPEDEF_(0x80091008L) +#define CRYPT_E_ALREADY_DECRYPTED _HRESULT_TYPEDEF_(0x80091009L) +#define CRYPT_E_NOT_DECRYPTED _HRESULT_TYPEDEF_(0x8009100AL) +#define CRYPT_E_RECIPIENT_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100BL) +#define CRYPT_E_CONTROL_TYPE _HRESULT_TYPEDEF_(0x8009100CL) +#define CRYPT_E_ISSUER_SERIALNUMBER _HRESULT_TYPEDEF_(0x8009100DL) +#define CRYPT_E_SIGNER_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100EL) +#define CRYPT_E_ATTRIBUTES_MISSING _HRESULT_TYPEDEF_(0x8009100FL) +#define CRYPT_E_STREAM_MSG_NOT_READY _HRESULT_TYPEDEF_(0x80091010L) +#define CRYPT_E_STREAM_INSUFFICIENT_DATA _HRESULT_TYPEDEF_(0x80091011L) +#define CRYPT_I_NEW_PROTECTION_REQUIRED _HRESULT_TYPEDEF_(0x00091012L) +#define CRYPT_E_BAD_LEN _HRESULT_TYPEDEF_(0x80092001L) +#define CRYPT_E_BAD_ENCODE _HRESULT_TYPEDEF_(0x80092002L) +#define CRYPT_E_FILE_ERROR _HRESULT_TYPEDEF_(0x80092003L) +#define CRYPT_E_NOT_FOUND _HRESULT_TYPEDEF_(0x80092004L) +#define CRYPT_E_EXISTS _HRESULT_TYPEDEF_(0x80092005L) +#define CRYPT_E_NO_PROVIDER _HRESULT_TYPEDEF_(0x80092006L) +#define CRYPT_E_SELF_SIGNED _HRESULT_TYPEDEF_(0x80092007L) +#define CRYPT_E_DELETED_PREV _HRESULT_TYPEDEF_(0x80092008L) +#define CRYPT_E_NO_MATCH _HRESULT_TYPEDEF_(0x80092009L) +#define CRYPT_E_UNEXPECTED_MSG_TYPE _HRESULT_TYPEDEF_(0x8009200AL) +#define CRYPT_E_NO_KEY_PROPERTY _HRESULT_TYPEDEF_(0x8009200BL) +#define CRYPT_E_NO_DECRYPT_CERT _HRESULT_TYPEDEF_(0x8009200CL) +#define CRYPT_E_BAD_MSG _HRESULT_TYPEDEF_(0x8009200DL) +#define CRYPT_E_NO_SIGNER _HRESULT_TYPEDEF_(0x8009200EL) +#define CRYPT_E_PENDING_CLOSE _HRESULT_TYPEDEF_(0x8009200FL) +#define CRYPT_E_REVOKED _HRESULT_TYPEDEF_(0x80092010L) +#define CRYPT_E_NO_REVOCATION_DLL _HRESULT_TYPEDEF_(0x80092011L) +#define CRYPT_E_NO_REVOCATION_CHECK _HRESULT_TYPEDEF_(0x80092012L) +#define CRYPT_E_REVOCATION_OFFLINE _HRESULT_TYPEDEF_(0x80092013L) +#define CRYPT_E_NOT_IN_REVOCATION_DATABASE _HRESULT_TYPEDEF_(0x80092014L) +#define CRYPT_E_INVALID_NUMERIC_STRING _HRESULT_TYPEDEF_(0x80092020L) +#define CRYPT_E_INVALID_PRINTABLE_STRING _HRESULT_TYPEDEF_(0x80092021L) +#define CRYPT_E_INVALID_IA5_STRING _HRESULT_TYPEDEF_(0x80092022L) +#define CRYPT_E_INVALID_X500_STRING _HRESULT_TYPEDEF_(0x80092023L) +#define CRYPT_E_NOT_CHAR_STRING _HRESULT_TYPEDEF_(0x80092024L) +#define CRYPT_E_FILERESIZED _HRESULT_TYPEDEF_(0x80092025L) +#define CRYPT_E_SECURITY_SETTINGS _HRESULT_TYPEDEF_(0x80092026L) +#define CRYPT_E_NO_VERIFY_USAGE_DLL _HRESULT_TYPEDEF_(0x80092027L) +#define CRYPT_E_NO_VERIFY_USAGE_CHECK _HRESULT_TYPEDEF_(0x80092028L) +#define CRYPT_E_VERIFY_USAGE_OFFLINE _HRESULT_TYPEDEF_(0x80092029L) +#define CRYPT_E_NOT_IN_CTL _HRESULT_TYPEDEF_(0x8009202AL) +#define CRYPT_E_NO_TRUSTED_SIGNER _HRESULT_TYPEDEF_(0x8009202BL) +#define CRYPT_E_MISSING_PUBKEY_PARA _HRESULT_TYPEDEF_(0x8009202CL) +#define CRYPT_E_OSS_ERROR _HRESULT_TYPEDEF_(0x80093000L) +#define OSS_MORE_BUF _HRESULT_TYPEDEF_(0x80093001L) +#define OSS_NEGATIVE_UINTEGER _HRESULT_TYPEDEF_(0x80093002L) +#define OSS_PDU_RANGE _HRESULT_TYPEDEF_(0x80093003L) +#define OSS_MORE_INPUT _HRESULT_TYPEDEF_(0x80093004L) +#define OSS_DATA_ERROR _HRESULT_TYPEDEF_(0x80093005L) +#define OSS_BAD_ARG _HRESULT_TYPEDEF_(0x80093006L) +#define OSS_BAD_VERSION _HRESULT_TYPEDEF_(0x80093007L) +#define OSS_OUT_MEMORY _HRESULT_TYPEDEF_(0x80093008L) +#define OSS_PDU_MISMATCH _HRESULT_TYPEDEF_(0x80093009L) +#define OSS_LIMITED _HRESULT_TYPEDEF_(0x8009300AL) +#define OSS_BAD_PTR _HRESULT_TYPEDEF_(0x8009300BL) +#define OSS_BAD_TIME _HRESULT_TYPEDEF_(0x8009300CL) +#define OSS_INDEFINITE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009300DL) +#define OSS_MEM_ERROR _HRESULT_TYPEDEF_(0x8009300EL) +#define OSS_BAD_TABLE _HRESULT_TYPEDEF_(0x8009300FL) +#define OSS_TOO_LONG _HRESULT_TYPEDEF_(0x80093010L) +#define OSS_CONSTRAINT_VIOLATED _HRESULT_TYPEDEF_(0x80093011L) +#define OSS_FATAL_ERROR _HRESULT_TYPEDEF_(0x80093012L) +#define OSS_ACCESS_SERIALIZATION_ERROR _HRESULT_TYPEDEF_(0x80093013L) +#define OSS_NULL_TBL _HRESULT_TYPEDEF_(0x80093014L) +#define OSS_NULL_FCN _HRESULT_TYPEDEF_(0x80093015L) +#define OSS_BAD_ENCRULES _HRESULT_TYPEDEF_(0x80093016L) +#define OSS_UNAVAIL_ENCRULES _HRESULT_TYPEDEF_(0x80093017L) +#define OSS_CANT_OPEN_TRACE_WINDOW _HRESULT_TYPEDEF_(0x80093018L) +#define OSS_UNIMPLEMENTED _HRESULT_TYPEDEF_(0x80093019L) +#define OSS_OID_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301AL) +#define OSS_CANT_OPEN_TRACE_FILE _HRESULT_TYPEDEF_(0x8009301BL) +#define OSS_TRACE_FILE_ALREADY_OPEN _HRESULT_TYPEDEF_(0x8009301CL) +#define OSS_TABLE_MISMATCH _HRESULT_TYPEDEF_(0x8009301DL) +#define OSS_TYPE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009301EL) +#define OSS_REAL_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301FL) +#define OSS_REAL_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093020L) +#define OSS_OUT_OF_RANGE _HRESULT_TYPEDEF_(0x80093021L) +#define OSS_COPIER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093022L) +#define OSS_CONSTRAINT_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093023L) +#define OSS_COMPARATOR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093024L) +#define OSS_COMPARATOR_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093025L) +#define OSS_MEM_MGR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093026L) +#define OSS_PDV_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093027L) +#define OSS_PDV_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093028L) +#define OSS_API_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093029L) +#define OSS_BERDER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302AL) +#define OSS_PER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302BL) +#define OSS_OPEN_TYPE_ERROR _HRESULT_TYPEDEF_(0x8009302CL) +#define OSS_MUTEX_NOT_CREATED _HRESULT_TYPEDEF_(0x8009302DL) +#define OSS_CANT_CLOSE_TRACE_FILE _HRESULT_TYPEDEF_(0x8009302EL) +#define CRYPT_E_ASN1_ERROR _HRESULT_TYPEDEF_(0x80093100L) +#define CRYPT_E_ASN1_INTERNAL _HRESULT_TYPEDEF_(0x80093101L) +#define CRYPT_E_ASN1_EOD _HRESULT_TYPEDEF_(0x80093102L) +#define CRYPT_E_ASN1_CORRUPT _HRESULT_TYPEDEF_(0x80093103L) +#define CRYPT_E_ASN1_LARGE _HRESULT_TYPEDEF_(0x80093104L) +#define CRYPT_E_ASN1_CONSTRAINT _HRESULT_TYPEDEF_(0x80093105L) +#define CRYPT_E_ASN1_MEMORY _HRESULT_TYPEDEF_(0x80093106L) +#define CRYPT_E_ASN1_OVERFLOW _HRESULT_TYPEDEF_(0x80093107L) +#define CRYPT_E_ASN1_BADPDU _HRESULT_TYPEDEF_(0x80093108L) +#define CRYPT_E_ASN1_BADARGS _HRESULT_TYPEDEF_(0x80093109L) +#define CRYPT_E_ASN1_BADREAL _HRESULT_TYPEDEF_(0x8009310AL) +#define CRYPT_E_ASN1_BADTAG _HRESULT_TYPEDEF_(0x8009310BL) +#define CRYPT_E_ASN1_CHOICE _HRESULT_TYPEDEF_(0x8009310CL) +#define CRYPT_E_ASN1_RULE _HRESULT_TYPEDEF_(0x8009310DL) +#define CRYPT_E_ASN1_UTF8 _HRESULT_TYPEDEF_(0x8009310EL) +#define CRYPT_E_ASN1_PDU_TYPE _HRESULT_TYPEDEF_(0x80093133L) +#define CRYPT_E_ASN1_NYI _HRESULT_TYPEDEF_(0x80093134L) +#define CRYPT_E_ASN1_EXTENDED _HRESULT_TYPEDEF_(0x80093201L) +#define CRYPT_E_ASN1_NOEOD _HRESULT_TYPEDEF_(0x80093202L) +#define CERTSRV_E_BAD_REQUESTSUBJECT _HRESULT_TYPEDEF_(0x80094001L) +#define CERTSRV_E_NO_REQUEST _HRESULT_TYPEDEF_(0x80094002L) +#define CERTSRV_E_BAD_REQUESTSTATUS _HRESULT_TYPEDEF_(0x80094003L) +#define CERTSRV_E_PROPERTY_EMPTY _HRESULT_TYPEDEF_(0x80094004L) +#define CERTSRV_E_INVALID_CA_CERTIFICATE _HRESULT_TYPEDEF_(0x80094005L) +#define CERTSRV_E_SERVER_SUSPENDED _HRESULT_TYPEDEF_(0x80094006L) +#define CERTSRV_E_ENCODING_LENGTH _HRESULT_TYPEDEF_(0x80094007L) +#define CERTSRV_E_ROLECONFLICT _HRESULT_TYPEDEF_(0x80094008L) +#define CERTSRV_E_RESTRICTEDOFFICER _HRESULT_TYPEDEF_(0x80094009L) +#define CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED _HRESULT_TYPEDEF_(0x8009400AL) +#define CERTSRV_E_NO_VALID_KRA _HRESULT_TYPEDEF_(0x8009400BL) +#define CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL _HRESULT_TYPEDEF_(0x8009400CL) +#define CERTSRV_E_NO_CAADMIN_DEFINED _HRESULT_TYPEDEF_(0x8009400DL) +#define CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE _HRESULT_TYPEDEF_(0x8009400EL) +#define CERTSRV_E_NO_DB_SESSIONS _HRESULT_TYPEDEF_(0x8009400FL) +#define CERTSRV_E_ALIGNMENT_FAULT _HRESULT_TYPEDEF_(0x80094010L) +#define CERTSRV_E_ENROLL_DENIED _HRESULT_TYPEDEF_(0x80094011L) +#define CERTSRV_E_TEMPLATE_DENIED _HRESULT_TYPEDEF_(0x80094012L) +#define CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE _HRESULT_TYPEDEF_(0x80094013L) +#define CERTSRV_E_UNSUPPORTED_CERT_TYPE _HRESULT_TYPEDEF_(0x80094800L) +#define CERTSRV_E_NO_CERT_TYPE _HRESULT_TYPEDEF_(0x80094801L) +#define CERTSRV_E_TEMPLATE_CONFLICT _HRESULT_TYPEDEF_(0x80094802L) +#define CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED _HRESULT_TYPEDEF_(0x80094803L) +#define CERTSRV_E_ARCHIVED_KEY_REQUIRED _HRESULT_TYPEDEF_(0x80094804L) +#define CERTSRV_E_SMIME_REQUIRED _HRESULT_TYPEDEF_(0x80094805L) +#define CERTSRV_E_BAD_RENEWAL_SUBJECT _HRESULT_TYPEDEF_(0x80094806L) +#define CERTSRV_E_BAD_TEMPLATE_VERSION _HRESULT_TYPEDEF_(0x80094807L) +#define CERTSRV_E_TEMPLATE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094808L) +#define CERTSRV_E_SIGNATURE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x80094809L) +#define CERTSRV_E_SIGNATURE_COUNT _HRESULT_TYPEDEF_(0x8009480AL) +#define CERTSRV_E_SIGNATURE_REJECTED _HRESULT_TYPEDEF_(0x8009480BL) +#define CERTSRV_E_ISSUANCE_POLICY_REQUIRED _HRESULT_TYPEDEF_(0x8009480CL) +#define CERTSRV_E_SUBJECT_UPN_REQUIRED _HRESULT_TYPEDEF_(0x8009480DL) +#define CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED _HRESULT_TYPEDEF_(0x8009480EL) +#define CERTSRV_E_SUBJECT_DNS_REQUIRED _HRESULT_TYPEDEF_(0x8009480FL) +#define CERTSRV_E_ARCHIVED_KEY_UNEXPECTED _HRESULT_TYPEDEF_(0x80094810L) +#define CERTSRV_E_KEY_LENGTH _HRESULT_TYPEDEF_(0x80094811L) +#define CERTSRV_E_SUBJECT_EMAIL_REQUIRED _HRESULT_TYPEDEF_(0x80094812L) +#define CERTSRV_E_UNKNOWN_CERT_TYPE _HRESULT_TYPEDEF_(0x80094813L) +#define CERTSRV_E_CERT_TYPE_OVERLAP _HRESULT_TYPEDEF_(0x80094814L) +#define XENROLL_E_KEY_NOT_EXPORTABLE _HRESULT_TYPEDEF_(0x80095000L) +#define XENROLL_E_CANNOT_ADD_ROOT_CERT _HRESULT_TYPEDEF_(0x80095001L) +#define XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND _HRESULT_TYPEDEF_(0x80095002L) +#define XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH _HRESULT_TYPEDEF_(0x80095003L) +#define XENROLL_E_RESPONSE_KA_HASH_MISMATCH _HRESULT_TYPEDEF_(0x80095004L) +#define XENROLL_E_KEYSPEC_SMIME_MISMATCH _HRESULT_TYPEDEF_(0x80095005L) +#define TRUST_E_SYSTEM_ERROR _HRESULT_TYPEDEF_(0x80096001L) +#define TRUST_E_NO_SIGNER_CERT _HRESULT_TYPEDEF_(0x80096002L) +#define TRUST_E_COUNTER_SIGNER _HRESULT_TYPEDEF_(0x80096003L) +#define TRUST_E_CERT_SIGNATURE _HRESULT_TYPEDEF_(0x80096004L) +#define TRUST_E_TIME_STAMP _HRESULT_TYPEDEF_(0x80096005L) +#define TRUST_E_BAD_DIGEST _HRESULT_TYPEDEF_(0x80096010L) +#define TRUST_E_BASIC_CONSTRAINTS _HRESULT_TYPEDEF_(0x80096019L) +#define TRUST_E_FINANCIAL_CRITERIA _HRESULT_TYPEDEF_(0x8009601EL) +#define MSSIPOTF_E_OUTOFMEMRANGE _HRESULT_TYPEDEF_(0x80097001L) +#define MSSIPOTF_E_CANTGETOBJECT _HRESULT_TYPEDEF_(0x80097002L) +#define MSSIPOTF_E_NOHEADTABLE _HRESULT_TYPEDEF_(0x80097003L) +#define MSSIPOTF_E_BAD_MAGICNUMBER _HRESULT_TYPEDEF_(0x80097004L) +#define MSSIPOTF_E_BAD_OFFSET_TABLE _HRESULT_TYPEDEF_(0x80097005L) +#define MSSIPOTF_E_TABLE_TAGORDER _HRESULT_TYPEDEF_(0x80097006L) +#define MSSIPOTF_E_TABLE_LONGWORD _HRESULT_TYPEDEF_(0x80097007L) +#define MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT _HRESULT_TYPEDEF_(0x80097008L) +#define MSSIPOTF_E_TABLES_OVERLAP _HRESULT_TYPEDEF_(0x80097009L) +#define MSSIPOTF_E_TABLE_PADBYTES _HRESULT_TYPEDEF_(0x8009700AL) +#define MSSIPOTF_E_FILETOOSMALL _HRESULT_TYPEDEF_(0x8009700BL) +#define MSSIPOTF_E_TABLE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700CL) +#define MSSIPOTF_E_FILE_CHECKSUM _HRESULT_TYPEDEF_(0x8009700DL) +#define MSSIPOTF_E_FAILED_POLICY _HRESULT_TYPEDEF_(0x80097010L) +#define MSSIPOTF_E_FAILED_HINTS_CHECK _HRESULT_TYPEDEF_(0x80097011L) +#define MSSIPOTF_E_NOT_OPENTYPE _HRESULT_TYPEDEF_(0x80097012L) +#define MSSIPOTF_E_FILE _HRESULT_TYPEDEF_(0x80097013L) +#define MSSIPOTF_E_CRYPT _HRESULT_TYPEDEF_(0x80097014L) +#define MSSIPOTF_E_BADVERSION _HRESULT_TYPEDEF_(0x80097015L) +#define MSSIPOTF_E_DSIG_STRUCTURE _HRESULT_TYPEDEF_(0x80097016L) +#define MSSIPOTF_E_PCONST_CHECK _HRESULT_TYPEDEF_(0x80097017L) +#define MSSIPOTF_E_STRUCTURE _HRESULT_TYPEDEF_(0x80097018L) +#define NTE_OP_OK 0 +#define TRUST_E_PROVIDER_UNKNOWN _HRESULT_TYPEDEF_(0x800B0001L) +#define TRUST_E_ACTION_UNKNOWN _HRESULT_TYPEDEF_(0x800B0002L) +#define TRUST_E_SUBJECT_FORM_UNKNOWN _HRESULT_TYPEDEF_(0x800B0003L) +#define TRUST_E_SUBJECT_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800B0004L) +#define DIGSIG_E_ENCODE _HRESULT_TYPEDEF_(0x800B0005L) +#define DIGSIG_E_DECODE _HRESULT_TYPEDEF_(0x800B0006L) +#define DIGSIG_E_EXTENSIBILITY _HRESULT_TYPEDEF_(0x800B0007L) +#define DIGSIG_E_CRYPTO _HRESULT_TYPEDEF_(0x800B0008L) +#define PERSIST_E_SIZEDEFINITE _HRESULT_TYPEDEF_(0x800B0009L) +#define PERSIST_E_SIZEINDEFINITE _HRESULT_TYPEDEF_(0x800B000AL) +#define PERSIST_E_NOTSELFSIZING _HRESULT_TYPEDEF_(0x800B000BL) +#define TRUST_E_NOSIGNATURE _HRESULT_TYPEDEF_(0x800B0100L) +#define CERT_E_EXPIRED _HRESULT_TYPEDEF_(0x800B0101L) +#define CERT_E_VALIDITYPERIODNESTING _HRESULT_TYPEDEF_(0x800B0102L) +#define CERT_E_ROLE _HRESULT_TYPEDEF_(0x800B0103L) +#define CERT_E_PATHLENCONST _HRESULT_TYPEDEF_(0x800B0104L) +#define CERT_E_CRITICAL _HRESULT_TYPEDEF_(0x800B0105L) +#define CERT_E_PURPOSE _HRESULT_TYPEDEF_(0x800B0106L) +#define CERT_E_ISSUERCHAINING _HRESULT_TYPEDEF_(0x800B0107L) +#define CERT_E_MALFORMED _HRESULT_TYPEDEF_(0x800B0108L) +#define CERT_E_UNTRUSTEDROOT _HRESULT_TYPEDEF_(0x800B0109L) +#define CERT_E_CHAINING _HRESULT_TYPEDEF_(0x800B010AL) +#define TRUST_E_FAIL _HRESULT_TYPEDEF_(0x800B010BL) +#define CERT_E_REVOKED _HRESULT_TYPEDEF_(0x800B010CL) +#define CERT_E_UNTRUSTEDTESTROOT _HRESULT_TYPEDEF_(0x800B010DL) +#define CERT_E_REVOCATION_FAILURE _HRESULT_TYPEDEF_(0x800B010EL) +#define CERT_E_CN_NO_MATCH _HRESULT_TYPEDEF_(0x800B010FL) +#define CERT_E_WRONG_USAGE _HRESULT_TYPEDEF_(0x800B0110L) +#define TRUST_E_EXPLICIT_DISTRUST _HRESULT_TYPEDEF_(0x800B0111L) +#define CERT_E_UNTRUSTEDCA _HRESULT_TYPEDEF_(0x800B0112L) +#define CERT_E_INVALID_POLICY _HRESULT_TYPEDEF_(0x800B0113L) +#define CERT_E_INVALID_NAME _HRESULT_TYPEDEF_(0x800B0114L) +#define HRESULT_FROM_SETUPAPI(x) ((((x) & (APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR))==(APPLICATION_ERROR_MASK|ERROR_SEVERITY_ERROR)) ? ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_SETUPAPI << 16) | 0x80000000)) : HRESULT_FROM_WIN32(x)) +#define SPAPI_E_EXPECTED_SECTION_NAME _HRESULT_TYPEDEF_(0x800F0000L) +#define SPAPI_E_BAD_SECTION_NAME_LINE _HRESULT_TYPEDEF_(0x800F0001L) +#define SPAPI_E_SECTION_NAME_TOO_LONG _HRESULT_TYPEDEF_(0x800F0002L) +#define SPAPI_E_GENERAL_SYNTAX _HRESULT_TYPEDEF_(0x800F0003L) +#define SPAPI_E_WRONG_INF_STYLE _HRESULT_TYPEDEF_(0x800F0100L) +#define SPAPI_E_SECTION_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0101L) +#define SPAPI_E_LINE_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0102L) +#define SPAPI_E_NO_BACKUP _HRESULT_TYPEDEF_(0x800F0103L) +#define SPAPI_E_NO_ASSOCIATED_CLASS _HRESULT_TYPEDEF_(0x800F0200L) +#define SPAPI_E_CLASS_MISMATCH _HRESULT_TYPEDEF_(0x800F0201L) +#define SPAPI_E_DUPLICATE_FOUND _HRESULT_TYPEDEF_(0x800F0202L) +#define SPAPI_E_NO_DRIVER_SELECTED _HRESULT_TYPEDEF_(0x800F0203L) +#define SPAPI_E_KEY_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x800F0204L) +#define SPAPI_E_INVALID_DEVINST_NAME _HRESULT_TYPEDEF_(0x800F0205L) +#define SPAPI_E_INVALID_CLASS _HRESULT_TYPEDEF_(0x800F0206L) +#define SPAPI_E_DEVINST_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x800F0207L) +#define SPAPI_E_DEVINFO_NOT_REGISTERED _HRESULT_TYPEDEF_(0x800F0208L) +#define SPAPI_E_INVALID_REG_PROPERTY _HRESULT_TYPEDEF_(0x800F0209L) +#define SPAPI_E_NO_INF _HRESULT_TYPEDEF_(0x800F020AL) +#define SPAPI_E_NO_SUCH_DEVINST _HRESULT_TYPEDEF_(0x800F020BL) +#define SPAPI_E_CANT_LOAD_CLASS_ICON _HRESULT_TYPEDEF_(0x800F020CL) +#define SPAPI_E_INVALID_CLASS_INSTALLER _HRESULT_TYPEDEF_(0x800F020DL) +#define SPAPI_E_DI_DO_DEFAULT _HRESULT_TYPEDEF_(0x800F020EL) +#define SPAPI_E_DI_NOFILECOPY _HRESULT_TYPEDEF_(0x800F020FL) +#define SPAPI_E_INVALID_HWPROFILE _HRESULT_TYPEDEF_(0x800F0210L) +#define SPAPI_E_NO_DEVICE_SELECTED _HRESULT_TYPEDEF_(0x800F0211L) +#define SPAPI_E_DEVINFO_LIST_LOCKED _HRESULT_TYPEDEF_(0x800F0212L) +#define SPAPI_E_DEVINFO_DATA_LOCKED _HRESULT_TYPEDEF_(0x800F0213L) +#define SPAPI_E_DI_BAD_PATH _HRESULT_TYPEDEF_(0x800F0214L) +#define SPAPI_E_NO_CLASSINSTALL_PARAMS _HRESULT_TYPEDEF_(0x800F0215L) +#define SPAPI_E_FILEQUEUE_LOCKED _HRESULT_TYPEDEF_(0x800F0216L) +#define SPAPI_E_BAD_SERVICE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F0217L) +#define SPAPI_E_NO_CLASS_DRIVER_LIST _HRESULT_TYPEDEF_(0x800F0218L) +#define SPAPI_E_NO_ASSOCIATED_SERVICE _HRESULT_TYPEDEF_(0x800F0219L) +#define SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F021AL) +#define SPAPI_E_DEVICE_INTERFACE_ACTIVE _HRESULT_TYPEDEF_(0x800F021BL) +#define SPAPI_E_DEVICE_INTERFACE_REMOVED _HRESULT_TYPEDEF_(0x800F021CL) +#define SPAPI_E_BAD_INTERFACE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F021DL) +#define SPAPI_E_NO_SUCH_INTERFACE_CLASS _HRESULT_TYPEDEF_(0x800F021EL) +#define SPAPI_E_INVALID_REFERENCE_STRING _HRESULT_TYPEDEF_(0x800F021FL) +#define SPAPI_E_INVALID_MACHINENAME _HRESULT_TYPEDEF_(0x800F0220L) +#define SPAPI_E_REMOTE_COMM_FAILURE _HRESULT_TYPEDEF_(0x800F0221L) +#define SPAPI_E_MACHINE_UNAVAILABLE _HRESULT_TYPEDEF_(0x800F0222L) +#define SPAPI_E_NO_CONFIGMGR_SERVICES _HRESULT_TYPEDEF_(0x800F0223L) +#define SPAPI_E_INVALID_PROPPAGE_PROVIDER _HRESULT_TYPEDEF_(0x800F0224L) +#define SPAPI_E_NO_SUCH_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F0225L) +#define SPAPI_E_DI_POSTPROCESSING_REQUIRED _HRESULT_TYPEDEF_(0x800F0226L) +#define SPAPI_E_INVALID_COINSTALLER _HRESULT_TYPEDEF_(0x800F0227L) +#define SPAPI_E_NO_COMPAT_DRIVERS _HRESULT_TYPEDEF_(0x800F0228L) +#define SPAPI_E_NO_DEVICE_ICON _HRESULT_TYPEDEF_(0x800F0229L) +#define SPAPI_E_INVALID_INF_LOGCONFIG _HRESULT_TYPEDEF_(0x800F022AL) +#define SPAPI_E_DI_DONT_INSTALL _HRESULT_TYPEDEF_(0x800F022BL) +#define SPAPI_E_INVALID_FILTER_DRIVER _HRESULT_TYPEDEF_(0x800F022CL) +#define SPAPI_E_NON_WINDOWS_NT_DRIVER _HRESULT_TYPEDEF_(0x800F022DL) +#define SPAPI_E_NON_WINDOWS_DRIVER _HRESULT_TYPEDEF_(0x800F022EL) +#define SPAPI_E_NO_CATALOG_FOR_OEM_INF _HRESULT_TYPEDEF_(0x800F022FL) +#define SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE _HRESULT_TYPEDEF_(0x800F0230L) +#define SPAPI_E_NOT_DISABLEABLE _HRESULT_TYPEDEF_(0x800F0231L) +#define SPAPI_E_CANT_REMOVE_DEVINST _HRESULT_TYPEDEF_(0x800F0232L) +#define SPAPI_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x800F0233L) +#define SPAPI_E_DRIVER_NONNATIVE _HRESULT_TYPEDEF_(0x800F0234L) +#define SPAPI_E_IN_WOW64 _HRESULT_TYPEDEF_(0x800F0235L) +#define SPAPI_E_SET_SYSTEM_RESTORE_POINT _HRESULT_TYPEDEF_(0x800F0236L) +#define SPAPI_E_INCORRECTLY_COPIED_INF _HRESULT_TYPEDEF_(0x800F0237L) +#define SPAPI_E_SCE_DISABLED _HRESULT_TYPEDEF_(0x800F0238L) +#define SPAPI_E_UNKNOWN_EXCEPTION _HRESULT_TYPEDEF_(0x800F0239L) +#define SPAPI_E_PNP_REGISTRY_ERROR _HRESULT_TYPEDEF_(0x800F023AL) +#define SPAPI_E_REMOTE_REQUEST_UNSUPPORTED _HRESULT_TYPEDEF_(0x800F023BL) +#define SPAPI_E_NOT_AN_INSTALLED_OEM_INF _HRESULT_TYPEDEF_(0x800F023CL) +#define SPAPI_E_INF_IN_USE_BY_DEVICES _HRESULT_TYPEDEF_(0x800F023DL) +#define SPAPI_E_DI_FUNCTION_OBSOLETE _HRESULT_TYPEDEF_(0x800F023EL) +#define SPAPI_E_NO_AUTHENTICODE_CATALOG _HRESULT_TYPEDEF_(0x800F023FL) +#define SPAPI_E_AUTHENTICODE_DISALLOWED _HRESULT_TYPEDEF_(0x800F0240L) +#define SPAPI_E_AUTHENTICODE_TRUSTED_PUBLISHER _HRESULT_TYPEDEF_(0x800F0241L) +#define SPAPI_E_AUTHENTICODE_TRUST_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x800F0242L) +#define SPAPI_E_AUTHENTICODE_PUBLISHER_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800F0243L) +#define SPAPI_E_SIGNATURE_OSATTRIBUTE_MISMATCH _HRESULT_TYPEDEF_(0x800F0244L) +#define SPAPI_E_ONLY_VALIDATE_VIA_AUTHENTICODE _HRESULT_TYPEDEF_(0x800F0245L) +#define SPAPI_E_UNRECOVERABLE_STACK_OVERFLOW _HRESULT_TYPEDEF_(0x800F0300L) +#define SPAPI_E_ERROR_NOT_INSTALLED _HRESULT_TYPEDEF_(0x800F1000L) +#define SCARD_S_SUCCESS NO_ERROR +#define SCARD_F_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80100001L) +#define SCARD_E_CANCELLED _HRESULT_TYPEDEF_(0x80100002L) +#define SCARD_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80100003L) +#define SCARD_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80100004L) +#define SCARD_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x80100005L) +#define SCARD_E_NO_MEMORY _HRESULT_TYPEDEF_(0x80100006L) +#define SCARD_F_WAITED_TOO_LONG _HRESULT_TYPEDEF_(0x80100007L) +#define SCARD_E_INSUFFICIENT_BUFFER _HRESULT_TYPEDEF_(0x80100008L) +#define SCARD_E_UNKNOWN_READER _HRESULT_TYPEDEF_(0x80100009L) +#define SCARD_E_TIMEOUT _HRESULT_TYPEDEF_(0x8010000AL) +#define SCARD_E_SHARING_VIOLATION _HRESULT_TYPEDEF_(0x8010000BL) +#define SCARD_E_NO_SMARTCARD _HRESULT_TYPEDEF_(0x8010000CL) +#define SCARD_E_UNKNOWN_CARD _HRESULT_TYPEDEF_(0x8010000DL) +#define SCARD_E_CANT_DISPOSE _HRESULT_TYPEDEF_(0x8010000EL) +#define SCARD_E_PROTO_MISMATCH _HRESULT_TYPEDEF_(0x8010000FL) +#define SCARD_E_NOT_READY _HRESULT_TYPEDEF_(0x80100010L) +#define SCARD_E_INVALID_VALUE _HRESULT_TYPEDEF_(0x80100011L) +#define SCARD_E_SYSTEM_CANCELLED _HRESULT_TYPEDEF_(0x80100012L) +#define SCARD_F_COMM_ERROR _HRESULT_TYPEDEF_(0x80100013L) +#define SCARD_F_UNKNOWN_ERROR _HRESULT_TYPEDEF_(0x80100014L) +#define SCARD_E_INVALID_ATR _HRESULT_TYPEDEF_(0x80100015L) +#define SCARD_E_NOT_TRANSACTED _HRESULT_TYPEDEF_(0x80100016L) +#define SCARD_E_READER_UNAVAILABLE _HRESULT_TYPEDEF_(0x80100017L) +#define SCARD_P_SHUTDOWN _HRESULT_TYPEDEF_(0x80100018L) +#define SCARD_E_PCI_TOO_SMALL _HRESULT_TYPEDEF_(0x80100019L) +#define SCARD_E_READER_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001AL) +#define SCARD_E_DUPLICATE_READER _HRESULT_TYPEDEF_(0x8010001BL) +#define SCARD_E_CARD_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001CL) +#define SCARD_E_NO_SERVICE _HRESULT_TYPEDEF_(0x8010001DL) +#define SCARD_E_SERVICE_STOPPED _HRESULT_TYPEDEF_(0x8010001EL) +#define SCARD_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8010001FL) +#define SCARD_E_ICC_INSTALLATION _HRESULT_TYPEDEF_(0x80100020L) +#define SCARD_E_ICC_CREATEORDER _HRESULT_TYPEDEF_(0x80100021L) +#define SCARD_E_UNSUPPORTED_FEATURE _HRESULT_TYPEDEF_(0x80100022L) +#define SCARD_E_DIR_NOT_FOUND _HRESULT_TYPEDEF_(0x80100023L) +#define SCARD_E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80100024L) +#define SCARD_E_NO_DIR _HRESULT_TYPEDEF_(0x80100025L) +#define SCARD_E_NO_FILE _HRESULT_TYPEDEF_(0x80100026L) +#define SCARD_E_NO_ACCESS _HRESULT_TYPEDEF_(0x80100027L) +#define SCARD_E_WRITE_TOO_MANY _HRESULT_TYPEDEF_(0x80100028L) +#define SCARD_E_BAD_SEEK _HRESULT_TYPEDEF_(0x80100029L) +#define SCARD_E_INVALID_CHV _HRESULT_TYPEDEF_(0x8010002AL) +#define SCARD_E_UNKNOWN_RES_MNG _HRESULT_TYPEDEF_(0x8010002BL) +#define SCARD_E_NO_SUCH_CERTIFICATE _HRESULT_TYPEDEF_(0x8010002CL) +#define SCARD_E_CERTIFICATE_UNAVAILABLE _HRESULT_TYPEDEF_(0x8010002DL) +#define SCARD_E_NO_READERS_AVAILABLE _HRESULT_TYPEDEF_(0x8010002EL) +#define SCARD_E_COMM_DATA_LOST _HRESULT_TYPEDEF_(0x8010002FL) +#define SCARD_E_NO_KEY_CONTAINER _HRESULT_TYPEDEF_(0x80100030L) +#define SCARD_E_SERVER_TOO_BUSY _HRESULT_TYPEDEF_(0x80100031L) +#define SCARD_W_UNSUPPORTED_CARD _HRESULT_TYPEDEF_(0x80100065L) +#define SCARD_W_UNRESPONSIVE_CARD _HRESULT_TYPEDEF_(0x80100066L) +#define SCARD_W_UNPOWERED_CARD _HRESULT_TYPEDEF_(0x80100067L) +#define SCARD_W_RESET_CARD _HRESULT_TYPEDEF_(0x80100068L) +#define SCARD_W_REMOVED_CARD _HRESULT_TYPEDEF_(0x80100069L) +#define SCARD_W_SECURITY_VIOLATION _HRESULT_TYPEDEF_(0x8010006AL) +#define SCARD_W_WRONG_CHV _HRESULT_TYPEDEF_(0x8010006BL) +#define SCARD_W_CHV_BLOCKED _HRESULT_TYPEDEF_(0x8010006CL) +#define SCARD_W_EOF _HRESULT_TYPEDEF_(0x8010006DL) +#define SCARD_W_CANCELLED_BY_USER _HRESULT_TYPEDEF_(0x8010006EL) +#define SCARD_W_CARD_NOT_AUTHENTICATED _HRESULT_TYPEDEF_(0x8010006FL) +#define COMADMIN_E_OBJECTERRORS _HRESULT_TYPEDEF_(0x80110401L) +#define COMADMIN_E_OBJECTINVALID _HRESULT_TYPEDEF_(0x80110402L) +#define COMADMIN_E_KEYMISSING _HRESULT_TYPEDEF_(0x80110403L) +#define COMADMIN_E_ALREADYINSTALLED _HRESULT_TYPEDEF_(0x80110404L) +#define COMADMIN_E_APP_FILE_WRITEFAIL _HRESULT_TYPEDEF_(0x80110407L) +#define COMADMIN_E_APP_FILE_READFAIL _HRESULT_TYPEDEF_(0x80110408L) +#define COMADMIN_E_APP_FILE_VERSION _HRESULT_TYPEDEF_(0x80110409L) +#define COMADMIN_E_BADPATH _HRESULT_TYPEDEF_(0x8011040AL) +#define COMADMIN_E_APPLICATIONEXISTS _HRESULT_TYPEDEF_(0x8011040BL) +#define COMADMIN_E_ROLEEXISTS _HRESULT_TYPEDEF_(0x8011040CL) +#define COMADMIN_E_CANTCOPYFILE _HRESULT_TYPEDEF_(0x8011040DL) +#define COMADMIN_E_NOUSER _HRESULT_TYPEDEF_(0x8011040FL) +#define COMADMIN_E_INVALIDUSERIDS _HRESULT_TYPEDEF_(0x80110410L) +#define COMADMIN_E_NOREGISTRYCLSID _HRESULT_TYPEDEF_(0x80110411L) +#define COMADMIN_E_BADREGISTRYPROGID _HRESULT_TYPEDEF_(0x80110412L) +#define COMADMIN_E_AUTHENTICATIONLEVEL _HRESULT_TYPEDEF_(0x80110413L) +#define COMADMIN_E_USERPASSWDNOTVALID _HRESULT_TYPEDEF_(0x80110414L) +#define COMADMIN_E_CLSIDORIIDMISMATCH _HRESULT_TYPEDEF_(0x80110418L) +#define COMADMIN_E_REMOTEINTERFACE _HRESULT_TYPEDEF_(0x80110419L) +#define COMADMIN_E_DLLREGISTERSERVER _HRESULT_TYPEDEF_(0x8011041AL) +#define COMADMIN_E_NOSERVERSHARE _HRESULT_TYPEDEF_(0x8011041BL) +#define COMADMIN_E_DLLLOADFAILED _HRESULT_TYPEDEF_(0x8011041DL) +#define COMADMIN_E_BADREGISTRYLIBID _HRESULT_TYPEDEF_(0x8011041EL) +#define COMADMIN_E_APPDIRNOTFOUND _HRESULT_TYPEDEF_(0x8011041FL) +#define COMADMIN_E_REGISTRARFAILED _HRESULT_TYPEDEF_(0x80110423L) +#define COMADMIN_E_COMPFILE_DOESNOTEXIST _HRESULT_TYPEDEF_(0x80110424L) +#define COMADMIN_E_COMPFILE_LOADDLLFAIL _HRESULT_TYPEDEF_(0x80110425L) +#define COMADMIN_E_COMPFILE_GETCLASSOBJ _HRESULT_TYPEDEF_(0x80110426L) +#define COMADMIN_E_COMPFILE_CLASSNOTAVAIL _HRESULT_TYPEDEF_(0x80110427L) +#define COMADMIN_E_COMPFILE_BADTLB _HRESULT_TYPEDEF_(0x80110428L) +#define COMADMIN_E_COMPFILE_NOTINSTALLABLE _HRESULT_TYPEDEF_(0x80110429L) +#define COMADMIN_E_NOTCHANGEABLE _HRESULT_TYPEDEF_(0x8011042AL) +#define COMADMIN_E_NOTDELETEABLE _HRESULT_TYPEDEF_(0x8011042BL) +#define COMADMIN_E_SESSION _HRESULT_TYPEDEF_(0x8011042CL) +#define COMADMIN_E_COMP_MOVE_LOCKED _HRESULT_TYPEDEF_(0x8011042DL) +#define COMADMIN_E_COMP_MOVE_BAD_DEST _HRESULT_TYPEDEF_(0x8011042EL) +#define COMADMIN_E_REGISTERTLB _HRESULT_TYPEDEF_(0x80110430L) +#define COMADMIN_E_SYSTEMAPP _HRESULT_TYPEDEF_(0x80110433L) +#define COMADMIN_E_COMPFILE_NOREGISTRAR _HRESULT_TYPEDEF_(0x80110434L) +#define COMADMIN_E_COREQCOMPINSTALLED _HRESULT_TYPEDEF_(0x80110435L) +#define COMADMIN_E_SERVICENOTINSTALLED _HRESULT_TYPEDEF_(0x80110436L) +#define COMADMIN_E_PROPERTYSAVEFAILED _HRESULT_TYPEDEF_(0x80110437L) +#define COMADMIN_E_OBJECTEXISTS _HRESULT_TYPEDEF_(0x80110438L) +#define COMADMIN_E_COMPONENTEXISTS _HRESULT_TYPEDEF_(0x80110439L) +#define COMADMIN_E_REGFILE_CORRUPT _HRESULT_TYPEDEF_(0x8011043BL) +#define COMADMIN_E_PROPERTY_OVERFLOW _HRESULT_TYPEDEF_(0x8011043CL) +#define COMADMIN_E_NOTINREGISTRY _HRESULT_TYPEDEF_(0x8011043EL) +#define COMADMIN_E_OBJECTNOTPOOLABLE _HRESULT_TYPEDEF_(0x8011043FL) +#define COMADMIN_E_APPLID_MATCHES_CLSID _HRESULT_TYPEDEF_(0x80110446L) +#define COMADMIN_E_ROLE_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110447L) +#define COMADMIN_E_START_APP_NEEDS_COMPONENTS _HRESULT_TYPEDEF_(0x80110448L) +#define COMADMIN_E_REQUIRES_DIFFERENT_PLATFORM _HRESULT_TYPEDEF_(0x80110449L) +#define COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY _HRESULT_TYPEDEF_(0x8011044AL) +#define COMADMIN_E_CAN_NOT_START_APP _HRESULT_TYPEDEF_(0x8011044BL) +#define COMADMIN_E_CAN_NOT_EXPORT_SYS_APP _HRESULT_TYPEDEF_(0x8011044CL) +#define COMADMIN_E_CANT_SUBSCRIBE_TO_COMPONENT _HRESULT_TYPEDEF_(0x8011044DL) +#define COMADMIN_E_EVENTCLASS_CANT_BE_SUBSCRIBER _HRESULT_TYPEDEF_(0x8011044EL) +#define COMADMIN_E_LIB_APP_PROXY_INCOMPATIBLE _HRESULT_TYPEDEF_(0x8011044FL) +#define COMADMIN_E_BASE_PARTITION_ONLY _HRESULT_TYPEDEF_(0x80110450L) +#define COMADMIN_E_START_APP_DISABLED _HRESULT_TYPEDEF_(0x80110451L) +#define COMADMIN_E_CAT_DUPLICATE_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110457L) +#define COMADMIN_E_CAT_INVALID_PARTITION_NAME _HRESULT_TYPEDEF_(0x80110458L) +#define COMADMIN_E_CAT_PARTITION_IN_USE _HRESULT_TYPEDEF_(0x80110459L) +#define COMADMIN_E_FILE_PARTITION_DUPLICATE_FILES _HRESULT_TYPEDEF_(0x8011045AL) +#define COMADMIN_E_CAT_IMPORTED_COMPONENTS_NOT_ALLOWED _HRESULT_TYPEDEF_(0x8011045BL) +#define COMADMIN_E_AMBIGUOUS_APPLICATION_NAME _HRESULT_TYPEDEF_(0x8011045CL) +#define COMADMIN_E_AMBIGUOUS_PARTITION_NAME _HRESULT_TYPEDEF_(0x8011045DL) +#define COMADMIN_E_REGDB_NOTINITIALIZED _HRESULT_TYPEDEF_(0x80110472L) +#define COMADMIN_E_REGDB_NOTOPEN _HRESULT_TYPEDEF_(0x80110473L) +#define COMADMIN_E_REGDB_SYSTEMERR _HRESULT_TYPEDEF_(0x80110474L) +#define COMADMIN_E_REGDB_ALREADYRUNNING _HRESULT_TYPEDEF_(0x80110475L) +#define COMADMIN_E_MIG_VERSIONNOTSUPPORTED _HRESULT_TYPEDEF_(0x80110480L) +#define COMADMIN_E_MIG_SCHEMANOTFOUND _HRESULT_TYPEDEF_(0x80110481L) +#define COMADMIN_E_CAT_BITNESSMISMATCH _HRESULT_TYPEDEF_(0x80110482L) +#define COMADMIN_E_CAT_UNACCEPTABLEBITNESS _HRESULT_TYPEDEF_(0x80110483L) +#define COMADMIN_E_CAT_WRONGAPPBITNESS _HRESULT_TYPEDEF_(0x80110484L) +#define COMADMIN_E_CAT_PAUSE_RESUME_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80110485L) +#define COMADMIN_E_CAT_SERVERFAULT _HRESULT_TYPEDEF_(0x80110486L) +#define COMQC_E_APPLICATION_NOT_QUEUED _HRESULT_TYPEDEF_(0x80110600L) +#define COMQC_E_NO_QUEUEABLE_INTERFACES _HRESULT_TYPEDEF_(0x80110601L) +#define COMQC_E_QUEUING_SERVICE_NOT_AVAILABLE _HRESULT_TYPEDEF_(0x80110602L) +#define COMQC_E_NO_IPERSISTSTREAM _HRESULT_TYPEDEF_(0x80110603L) +#define COMQC_E_BAD_MESSAGE _HRESULT_TYPEDEF_(0x80110604L) +#define COMQC_E_UNAUTHENTICATED _HRESULT_TYPEDEF_(0x80110605L) +#define COMQC_E_UNTRUSTED_ENQUEUER _HRESULT_TYPEDEF_(0x80110606L) +#define MSDTC_E_DUPLICATE_RESOURCE _HRESULT_TYPEDEF_(0x80110701L) +#define COMADMIN_E_OBJECT_PARENT_MISSING _HRESULT_TYPEDEF_(0x80110808L) +#define COMADMIN_E_OBJECT_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x80110809L) +#define COMADMIN_E_APP_NOT_RUNNING _HRESULT_TYPEDEF_(0x8011080AL) +#define COMADMIN_E_INVALID_PARTITION _HRESULT_TYPEDEF_(0x8011080BL) +#define COMADMIN_E_SVCAPP_NOT_POOLABLE_OR_RECYCLABLE _HRESULT_TYPEDEF_(0x8011080DL) +#define COMADMIN_E_USER_IN_SET _HRESULT_TYPEDEF_(0x8011080EL) +#define COMADMIN_E_CANTRECYCLELIBRARYAPPS _HRESULT_TYPEDEF_(0x8011080FL) +#define COMADMIN_E_CANTRECYCLESERVICEAPPS _HRESULT_TYPEDEF_(0x80110811L) +#define COMADMIN_E_PROCESSALREADYRECYCLED _HRESULT_TYPEDEF_(0x80110812L) +#define COMADMIN_E_PAUSEDPROCESSMAYNOTBERECYCLED _HRESULT_TYPEDEF_(0x80110813L) +#define COMADMIN_E_CANTMAKEINPROCSERVICE _HRESULT_TYPEDEF_(0x80110814L) +#define COMADMIN_E_PROGIDINUSEBYCLSID _HRESULT_TYPEDEF_(0x80110815L) +#define COMADMIN_E_DEFAULT_PARTITION_NOT_IN_SET _HRESULT_TYPEDEF_(0x80110816L) +#define COMADMIN_E_RECYCLEDPROCESSMAYNOTBEPAUSED _HRESULT_TYPEDEF_(0x80110817L) +#define COMADMIN_E_PARTITION_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110818L) +#define COMADMIN_E_PARTITION_MSI_ONLY _HRESULT_TYPEDEF_(0x80110819L) +#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_1_0_FORMAT _HRESULT_TYPEDEF_(0x8011081AL) +#define COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_NONBASE_PARTITIONS _HRESULT_TYPEDEF_(0x8011081BL) +#define COMADMIN_E_COMP_MOVE_SOURCE _HRESULT_TYPEDEF_(0x8011081CL) +#define COMADMIN_E_COMP_MOVE_DEST _HRESULT_TYPEDEF_(0x8011081DL) +#define COMADMIN_E_COMP_MOVE_PRIVATE _HRESULT_TYPEDEF_(0x8011081EL) +#define COMADMIN_E_BASEPARTITION_REQUIRED_IN_SET _HRESULT_TYPEDEF_(0x8011081FL) +#define COMADMIN_E_CANNOT_ALIAS_EVENTCLASS _HRESULT_TYPEDEF_(0x80110820L) +#define COMADMIN_E_PRIVATE_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110821L) +#define COMADMIN_E_SAFERINVALID _HRESULT_TYPEDEF_(0x80110822L) +#define COMADMIN_E_REGISTRY_ACCESSDENIED _HRESULT_TYPEDEF_(0x80110823L) +#define COMADMIN_E_PARTITIONS_DISABLED _HRESULT_TYPEDEF_(0x80110824L) +#endif /* _WINERROR_ */ diff --git a/tcc/include/winapi/wingdi.h b/tcc/include/winapi/wingdi.h index af33bd2a..63d38917 100644 --- a/tcc/include/winapi/wingdi.h +++ b/tcc/include/winapi/wingdi.h @@ -1,4080 +1,4080 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINGDI_ -#define _WINGDI_ - -#define WINGDIAPI DECLSPEC_IMPORT -#define WINSPOOLAPI DECLSPEC_IMPORT - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#ifndef NOGDI -#ifndef NORASTEROPS -#define R2_BLACK 1 -#define R2_NOTMERGEPEN 2 -#define R2_MASKNOTPEN 3 -#define R2_NOTCOPYPEN 4 -#define R2_MASKPENNOT 5 -#define R2_NOT 6 -#define R2_XORPEN 7 -#define R2_NOTMASKPEN 8 -#define R2_MASKPEN 9 -#define R2_NOTXORPEN 10 -#define R2_NOP 11 -#define R2_MERGENOTPEN 12 -#define R2_COPYPEN 13 -#define R2_MERGEPENNOT 14 -#define R2_MERGEPEN 15 -#define R2_WHITE 16 -#define R2_LAST 16 - -#define SRCCOPY (DWORD)0x00CC0020 -#define SRCPAINT (DWORD)0x00EE0086 -#define SRCAND (DWORD)0x008800C6 -#define SRCINVERT (DWORD)0x00660046 -#define SRCERASE (DWORD)0x00440328 -#define NOTSRCCOPY (DWORD)0x00330008 -#define NOTSRCERASE (DWORD)0x001100A6 -#define MERGECOPY (DWORD)0x00C000CA -#define MERGEPAINT (DWORD)0x00BB0226 -#define PATCOPY (DWORD)0x00F00021 -#define PATPAINT (DWORD)0x00FB0A09 -#define PATINVERT (DWORD)0x005A0049 -#define DSTINVERT (DWORD)0x00550009 -#define BLACKNESS (DWORD)0x00000042 -#define WHITENESS (DWORD)0x00FF0062 -#define NOMIRRORBITMAP (DWORD)0x80000000 -#define CAPTUREBLT (DWORD)0x40000000 -#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) -#endif - -#define GDI_ERROR (0xFFFFFFFFL) -#define HGDI_ERROR (LongToHandle(0xFFFFFFFFL)) - -#define ERROR 0 -#define NULLREGION 1 -#define SIMPLEREGION 2 -#define COMPLEXREGION 3 -#define RGN_ERROR ERROR - -#define RGN_AND 1 -#define RGN_OR 2 -#define RGN_XOR 3 -#define RGN_DIFF 4 -#define RGN_COPY 5 -#define RGN_MIN RGN_AND -#define RGN_MAX RGN_COPY - -#define BLACKONWHITE 1 -#define WHITEONBLACK 2 -#define COLORONCOLOR 3 -#define HALFTONE 4 -#define MAXSTRETCHBLTMODE 4 - -#define STRETCH_ANDSCANS BLACKONWHITE -#define STRETCH_ORSCANS WHITEONBLACK -#define STRETCH_DELETESCANS COLORONCOLOR -#define STRETCH_HALFTONE HALFTONE - -#define ALTERNATE 1 -#define WINDING 2 -#define POLYFILL_LAST 2 - -#define LAYOUT_RTL 0x00000001 -#define LAYOUT_BTT 0x00000002 -#define LAYOUT_VBH 0x00000004 -#define LAYOUT_ORIENTATIONMASK (LAYOUT_RTL | LAYOUT_BTT | LAYOUT_VBH) -#define LAYOUT_BITMAPORIENTATIONPRESERVED 0x00000008 - -#define TA_NOUPDATECP 0 -#define TA_UPDATECP 1 - -#define TA_LEFT 0 -#define TA_RIGHT 2 -#define TA_CENTER 6 - -#define TA_TOP 0 -#define TA_BOTTOM 8 -#define TA_BASELINE 24 -#define TA_RTLREADING 256 -#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING) - -#define VTA_BASELINE TA_BASELINE -#define VTA_LEFT TA_BOTTOM -#define VTA_RIGHT TA_TOP -#define VTA_CENTER TA_CENTER -#define VTA_BOTTOM TA_RIGHT -#define VTA_TOP TA_LEFT - -#define ETO_OPAQUE 0x0002 -#define ETO_CLIPPED 0x0004 -#define ETO_GLYPH_INDEX 0x0010 -#define ETO_RTLREADING 0x0080 -#define ETO_NUMERICSLOCAL 0x0400 -#define ETO_NUMERICSLATIN 0x0800 -#define ETO_IGNORELANGUAGE 0x1000 -#define ETO_PDY 0x2000 - -#define ASPECT_FILTERING 0x0001 - -#define DCB_RESET 0x0001 -#define DCB_ACCUMULATE 0x0002 -#define DCB_DIRTY DCB_ACCUMULATE -#define DCB_SET (DCB_RESET | DCB_ACCUMULATE) -#define DCB_ENABLE 0x0004 -#define DCB_DISABLE 0x0008 - -#ifndef NOMETAFILE - -#define META_SETBKCOLOR 0x0201 -#define META_SETBKMODE 0x0102 -#define META_SETMAPMODE 0x0103 -#define META_SETROP2 0x0104 -#define META_SETRELABS 0x0105 -#define META_SETPOLYFILLMODE 0x0106 -#define META_SETSTRETCHBLTMODE 0x0107 -#define META_SETTEXTCHAREXTRA 0x0108 -#define META_SETTEXTCOLOR 0x0209 -#define META_SETTEXTJUSTIFICATION 0x020A -#define META_SETWINDOWORG 0x020B -#define META_SETWINDOWEXT 0x020C -#define META_SETVIEWPORTORG 0x020D -#define META_SETVIEWPORTEXT 0x020E -#define META_OFFSETWINDOWORG 0x020F -#define META_SCALEWINDOWEXT 0x0410 -#define META_OFFSETVIEWPORTORG 0x0211 -#define META_SCALEVIEWPORTEXT 0x0412 -#define META_LINETO 0x0213 -#define META_MOVETO 0x0214 -#define META_EXCLUDECLIPRECT 0x0415 -#define META_INTERSECTCLIPRECT 0x0416 -#define META_ARC 0x0817 -#define META_ELLIPSE 0x0418 -#define META_FLOODFILL 0x0419 -#define META_PIE 0x081A -#define META_RECTANGLE 0x041B -#define META_ROUNDRECT 0x061C -#define META_PATBLT 0x061D -#define META_SAVEDC 0x001E -#define META_SETPIXEL 0x041F -#define META_OFFSETCLIPRGN 0x0220 -#define META_TEXTOUT 0x0521 -#define META_BITBLT 0x0922 -#define META_STRETCHBLT 0x0B23 -#define META_POLYGON 0x0324 -#define META_POLYLINE 0x0325 -#define META_ESCAPE 0x0626 -#define META_RESTOREDC 0x0127 -#define META_FILLREGION 0x0228 -#define META_FRAMEREGION 0x0429 -#define META_INVERTREGION 0x012A -#define META_PAINTREGION 0x012B -#define META_SELECTCLIPREGION 0x012C -#define META_SELECTOBJECT 0x012D -#define META_SETTEXTALIGN 0x012E -#define META_CHORD 0x0830 -#define META_SETMAPPERFLAGS 0x0231 -#define META_EXTTEXTOUT 0x0a32 -#define META_SETDIBTODEV 0x0d33 -#define META_SELECTPALETTE 0x0234 -#define META_REALIZEPALETTE 0x0035 -#define META_ANIMATEPALETTE 0x0436 -#define META_SETPALENTRIES 0x0037 -#define META_POLYPOLYGON 0x0538 -#define META_RESIZEPALETTE 0x0139 -#define META_DIBBITBLT 0x0940 -#define META_DIBSTRETCHBLT 0x0b41 -#define META_DIBCREATEPATTERNBRUSH 0x0142 -#define META_STRETCHDIB 0x0f43 -#define META_EXTFLOODFILL 0x0548 -#define META_SETLAYOUT 0x0149 -#define META_DELETEOBJECT 0x01f0 -#define META_CREATEPALETTE 0x00f7 -#define META_CREATEPATTERNBRUSH 0x01F9 -#define META_CREATEPENINDIRECT 0x02FA -#define META_CREATEFONTINDIRECT 0x02FB -#define META_CREATEBRUSHINDIRECT 0x02FC -#define META_CREATEREGION 0x06FF - - typedef struct _DRAWPATRECT { - POINT ptPosition; - POINT ptSize; - WORD wStyle; - WORD wPattern; - } DRAWPATRECT,*PDRAWPATRECT; -#endif - -#define NEWFRAME 1 -#define ABORTDOC 2 -#define NEXTBAND 3 -#define SETCOLORTABLE 4 -#define GETCOLORTABLE 5 -#define FLUSHOUTPUT 6 -#define DRAFTMODE 7 -#define QUERYESCSUPPORT 8 -#define SETABORTPROC 9 -#define STARTDOC 10 -#define ENDDOC 11 -#define GETPHYSPAGESIZE 12 -#define GETPRINTINGOFFSET 13 -#define GETSCALINGFACTOR 14 -#define MFCOMMENT 15 -#define GETPENWIDTH 16 -#define SETCOPYCOUNT 17 -#define SELECTPAPERSOURCE 18 -#define DEVICEDATA 19 -#define PASSTHROUGH 19 -#define GETTECHNOLGY 20 -#define GETTECHNOLOGY 20 -#define SETLINECAP 21 -#define SETLINEJOIN 22 -#define SETMITERLIMIT 23 -#define BANDINFO 24 -#define DRAWPATTERNRECT 25 -#define GETVECTORPENSIZE 26 -#define GETVECTORBRUSHSIZE 27 -#define ENABLEDUPLEX 28 -#define GETSETPAPERBINS 29 -#define GETSETPRINTORIENT 30 -#define ENUMPAPERBINS 31 -#define SETDIBSCALING 32 -#define EPSPRINTING 33 -#define ENUMPAPERMETRICS 34 -#define GETSETPAPERMETRICS 35 -#define POSTSCRIPT_DATA 37 -#define POSTSCRIPT_IGNORE 38 -#define MOUSETRAILS 39 -#define GETDEVICEUNITS 42 - -#define GETEXTENDEDTEXTMETRICS 256 -#define GETEXTENTTABLE 257 -#define GETPAIRKERNTABLE 258 -#define GETTRACKKERNTABLE 259 -#define EXTTEXTOUT 512 -#define GETFACENAME 513 -#define DOWNLOADFACE 514 -#define ENABLERELATIVEWIDTHS 768 -#define ENABLEPAIRKERNING 769 -#define SETKERNTRACK 770 -#define SETALLJUSTVALUES 771 -#define SETCHARSET 772 - -#define STRETCHBLT 2048 -#define METAFILE_DRIVER 2049 -#define GETSETSCREENPARAMS 3072 -#define QUERYDIBSUPPORT 3073 -#define BEGIN_PATH 4096 -#define CLIP_TO_PATH 4097 -#define END_PATH 4098 -#define EXT_DEVICE_CAPS 4099 -#define RESTORE_CTM 4100 -#define SAVE_CTM 4101 -#define SET_ARC_DIRECTION 4102 -#define SET_BACKGROUND_COLOR 4103 -#define SET_POLY_MODE 4104 -#define SET_SCREEN_ANGLE 4105 -#define SET_SPREAD 4106 -#define TRANSFORM_CTM 4107 -#define SET_CLIP_BOX 4108 -#define SET_BOUNDS 4109 -#define SET_MIRROR_MODE 4110 -#define OPENCHANNEL 4110 -#define DOWNLOADHEADER 4111 -#define CLOSECHANNEL 4112 -#define POSTSCRIPT_PASSTHROUGH 4115 -#define ENCAPSULATED_POSTSCRIPT 4116 - -#define POSTSCRIPT_IDENTIFY 4117 -#define POSTSCRIPT_INJECTION 4118 - -#define CHECKJPEGFORMAT 4119 -#define CHECKPNGFORMAT 4120 - -#define GET_PS_FEATURESETTING 4121 - -#define SPCLPASSTHROUGH2 4568 - -#define PSIDENT_GDICENTRIC 0 -#define PSIDENT_PSCENTRIC 1 - - typedef struct _PSINJECTDATA { - DWORD DataBytes; - WORD InjectionPoint; - WORD PageNumber; - } PSINJECTDATA,*PPSINJECTDATA; - -#define PSINJECT_BEGINSTREAM 1 -#define PSINJECT_PSADOBE 2 -#define PSINJECT_PAGESATEND 3 -#define PSINJECT_PAGES 4 - -#define PSINJECT_DOCNEEDEDRES 5 -#define PSINJECT_DOCSUPPLIEDRES 6 -#define PSINJECT_PAGEORDER 7 -#define PSINJECT_ORIENTATION 8 -#define PSINJECT_BOUNDINGBOX 9 -#define PSINJECT_DOCUMENTPROCESSCOLORS 10 - -#define PSINJECT_COMMENTS 11 -#define PSINJECT_BEGINDEFAULTS 12 -#define PSINJECT_ENDDEFAULTS 13 -#define PSINJECT_BEGINPROLOG 14 -#define PSINJECT_ENDPROLOG 15 -#define PSINJECT_BEGINSETUP 16 -#define PSINJECT_ENDSETUP 17 -#define PSINJECT_TRAILER 18 -#define PSINJECT_EOF 19 -#define PSINJECT_ENDSTREAM 20 -#define PSINJECT_DOCUMENTPROCESSCOLORSATEND 21 - -#define PSINJECT_PAGENUMBER 100 -#define PSINJECT_BEGINPAGESETUP 101 -#define PSINJECT_ENDPAGESETUP 102 -#define PSINJECT_PAGETRAILER 103 -#define PSINJECT_PLATECOLOR 104 - -#define PSINJECT_SHOWPAGE 105 -#define PSINJECT_PAGEBBOX 106 -#define PSINJECT_ENDPAGECOMMENTS 107 - -#define PSINJECT_VMSAVE 200 -#define PSINJECT_VMRESTORE 201 - -#define FEATURESETTING_NUP 0 -#define FEATURESETTING_OUTPUT 1 -#define FEATURESETTING_PSLEVEL 2 -#define FEATURESETTING_CUSTPAPER 3 -#define FEATURESETTING_MIRROR 4 -#define FEATURESETTING_NEGATIVE 5 -#define FEATURESETTING_PROTOCOL 6 - -#define FEATURESETTING_PRIVATE_BEGIN 0x1000 -#define FEATURESETTING_PRIVATE_END 0x1FFF - - typedef struct _PSFEATURE_OUTPUT { - WINBOOL bPageIndependent; - WINBOOL bSetPageDevice; - } PSFEATURE_OUTPUT,*PPSFEATURE_OUTPUT; - - typedef struct _PSFEATURE_CUSTPAPER { - LONG lOrientation; - LONG lWidth; - LONG lHeight; - LONG lWidthOffset; - LONG lHeightOffset; - } PSFEATURE_CUSTPAPER,*PPSFEATURE_CUSTPAPER; - -#define PSPROTOCOL_ASCII 0 -#define PSPROTOCOL_BCP 1 -#define PSPROTOCOL_TBCP 2 -#define PSPROTOCOL_BINARY 3 - -#define QDI_SETDIBITS 1 -#define QDI_GETDIBITS 2 -#define QDI_DIBTOSCREEN 4 -#define QDI_STRETCHDIB 8 - -#define SP_NOTREPORTED 0x4000 -#define SP_ERROR (-1) -#define SP_APPABORT (-2) -#define SP_USERABORT (-3) -#define SP_OUTOFDISK (-4) -#define SP_OUTOFMEMORY (-5) - -#define PR_JOBSTATUS 0x0000 - -#define OBJ_PEN 1 -#define OBJ_BRUSH 2 -#define OBJ_DC 3 -#define OBJ_METADC 4 -#define OBJ_PAL 5 -#define OBJ_FONT 6 -#define OBJ_BITMAP 7 -#define OBJ_REGION 8 -#define OBJ_METAFILE 9 -#define OBJ_MEMDC 10 -#define OBJ_EXTPEN 11 -#define OBJ_ENHMETADC 12 -#define OBJ_ENHMETAFILE 13 -#define OBJ_COLORSPACE 14 - -#define MWT_IDENTITY 1 -#define MWT_LEFTMULTIPLY 2 -#define MWT_RIGHTMULTIPLY 3 - -#define MWT_MIN MWT_IDENTITY -#define MWT_MAX MWT_RIGHTMULTIPLY - -#define _XFORM_ - typedef struct tagXFORM { - FLOAT eM11; - FLOAT eM12; - FLOAT eM21; - FLOAT eM22; - FLOAT eDx; - FLOAT eDy; - } XFORM,*PXFORM,*LPXFORM; - - typedef struct tagBITMAP { - LONG bmType; - LONG bmWidth; - LONG bmHeight; - LONG bmWidthBytes; - WORD bmPlanes; - WORD bmBitsPixel; - LPVOID bmBits; - } BITMAP,*PBITMAP,*NPBITMAP,*LPBITMAP; - -#include - typedef struct tagRGBTRIPLE { - BYTE rgbtBlue; - BYTE rgbtGreen; - BYTE rgbtRed; - } RGBTRIPLE; -#include - - typedef struct tagRGBQUAD { - BYTE rgbBlue; - BYTE rgbGreen; - BYTE rgbRed; - BYTE rgbReserved; - } RGBQUAD; - typedef RGBQUAD *LPRGBQUAD; - -#define CS_ENABLE 0x00000001L -#define CS_DISABLE 0x00000002L -#define CS_DELETE_TRANSFORM 0x00000003L - -//!__TINYC__: #define LCS_SIGNATURE 'PSOC' -//!__TINYC__: #define LCS_sRGB 'sRGB' -//!__TINYC__: #define LCS_WINDOWS_COLOR_SPACE 'Win ' - - typedef LONG LCSCSTYPE; -#define LCS_CALIBRATED_RGB 0x00000000L - - typedef LONG LCSGAMUTMATCH; -#define LCS_GM_BUSINESS 0x00000001L -#define LCS_GM_GRAPHICS 0x00000002L -#define LCS_GM_IMAGES 0x00000004L -#define LCS_GM_ABS_COLORIMETRIC 0x00000008L - -#define CM_OUT_OF_GAMUT 255 -#define CM_IN_GAMUT 0 - -#define ICM_ADDPROFILE 1 -#define ICM_DELETEPROFILE 2 -#define ICM_QUERYPROFILE 3 -#define ICM_SETDEFAULTPROFILE 4 -#define ICM_REGISTERICMATCHER 5 -#define ICM_UNREGISTERICMATCHER 6 -#define ICM_QUERYMATCH 7 - -#define GetKValue(cmyk) ((BYTE)(cmyk)) -#define GetYValue(cmyk) ((BYTE)((cmyk)>> 8)) -#define GetMValue(cmyk) ((BYTE)((cmyk)>>16)) -#define GetCValue(cmyk) ((BYTE)((cmyk)>>24)) - -#define CMYK(c,m,y,k) ((COLORREF)((((BYTE)(k)|((WORD)((BYTE)(y))<<8))|(((DWORD)(BYTE)(m))<<16))|(((DWORD)(BYTE)(c))<<24))) - - typedef long FXPT16DOT16,*LPFXPT16DOT16; - typedef long FXPT2DOT30,*LPFXPT2DOT30; - - typedef struct tagCIEXYZ { - FXPT2DOT30 ciexyzX; - FXPT2DOT30 ciexyzY; - FXPT2DOT30 ciexyzZ; - } CIEXYZ; - typedef CIEXYZ *LPCIEXYZ; - - typedef struct tagICEXYZTRIPLE { - CIEXYZ ciexyzRed; - CIEXYZ ciexyzGreen; - CIEXYZ ciexyzBlue; - } CIEXYZTRIPLE; - - typedef CIEXYZTRIPLE *LPCIEXYZTRIPLE; - - typedef struct tagLOGCOLORSPACEA { - DWORD lcsSignature; - DWORD lcsVersion; - DWORD lcsSize; - LCSCSTYPE lcsCSType; - LCSGAMUTMATCH lcsIntent; - CIEXYZTRIPLE lcsEndpoints; - DWORD lcsGammaRed; - DWORD lcsGammaGreen; - DWORD lcsGammaBlue; - CHAR lcsFilename[MAX_PATH]; - } LOGCOLORSPACEA,*LPLOGCOLORSPACEA; - - typedef struct tagLOGCOLORSPACEW { - DWORD lcsSignature; - DWORD lcsVersion; - DWORD lcsSize; - LCSCSTYPE lcsCSType; - LCSGAMUTMATCH lcsIntent; - CIEXYZTRIPLE lcsEndpoints; - DWORD lcsGammaRed; - DWORD lcsGammaGreen; - DWORD lcsGammaBlue; - WCHAR lcsFilename[MAX_PATH]; - } LOGCOLORSPACEW,*LPLOGCOLORSPACEW; - -#ifdef UNICODE - typedef LOGCOLORSPACEW LOGCOLORSPACE; - typedef LPLOGCOLORSPACEW LPLOGCOLORSPACE; -#else - typedef LOGCOLORSPACEA LOGCOLORSPACE; - typedef LPLOGCOLORSPACEA LPLOGCOLORSPACE; -#endif - - typedef struct tagBITMAPCOREHEADER { - DWORD bcSize; - WORD bcWidth; - WORD bcHeight; - WORD bcPlanes; - WORD bcBitCount; - } BITMAPCOREHEADER,*LPBITMAPCOREHEADER,*PBITMAPCOREHEADER; - - typedef struct tagBITMAPINFOHEADER { - DWORD biSize; - LONG biWidth; - LONG biHeight; - WORD biPlanes; - WORD biBitCount; - DWORD biCompression; - DWORD biSizeImage; - LONG biXPelsPerMeter; - LONG biYPelsPerMeter; - DWORD biClrUsed; - DWORD biClrImportant; - } BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER; - - typedef struct { - DWORD bV4Size; - LONG bV4Width; - LONG bV4Height; - WORD bV4Planes; - WORD bV4BitCount; - DWORD bV4V4Compression; - DWORD bV4SizeImage; - LONG bV4XPelsPerMeter; - LONG bV4YPelsPerMeter; - DWORD bV4ClrUsed; - DWORD bV4ClrImportant; - DWORD bV4RedMask; - DWORD bV4GreenMask; - DWORD bV4BlueMask; - DWORD bV4AlphaMask; - DWORD bV4CSType; - CIEXYZTRIPLE bV4Endpoints; - DWORD bV4GammaRed; - DWORD bV4GammaGreen; - DWORD bV4GammaBlue; - } BITMAPV4HEADER,*LPBITMAPV4HEADER,*PBITMAPV4HEADER; - - typedef struct { - DWORD bV5Size; - LONG bV5Width; - LONG bV5Height; - WORD bV5Planes; - WORD bV5BitCount; - DWORD bV5Compression; - DWORD bV5SizeImage; - LONG bV5XPelsPerMeter; - LONG bV5YPelsPerMeter; - DWORD bV5ClrUsed; - DWORD bV5ClrImportant; - DWORD bV5RedMask; - DWORD bV5GreenMask; - DWORD bV5BlueMask; - DWORD bV5AlphaMask; - DWORD bV5CSType; - CIEXYZTRIPLE bV5Endpoints; - DWORD bV5GammaRed; - DWORD bV5GammaGreen; - DWORD bV5GammaBlue; - DWORD bV5Intent; - DWORD bV5ProfileData; - DWORD bV5ProfileSize; - DWORD bV5Reserved; - } BITMAPV5HEADER,*LPBITMAPV5HEADER,*PBITMAPV5HEADER; - -//!__TINYC__: #define PROFILE_LINKED 'LINK' -//!__TINYC__: #define PROFILE_EMBEDDED 'MBED' - -#define BI_RGB 0L -#define BI_RLE8 1L -#define BI_RLE4 2L -#define BI_BITFIELDS 3L -#define BI_JPEG 4L -#define BI_PNG 5L - - typedef struct tagBITMAPINFO { - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[1]; - } BITMAPINFO,*LPBITMAPINFO,*PBITMAPINFO; - - typedef struct tagBITMAPCOREINFO { - BITMAPCOREHEADER bmciHeader; - RGBTRIPLE bmciColors[1]; - } BITMAPCOREINFO,*LPBITMAPCOREINFO,*PBITMAPCOREINFO; - -#include - typedef struct tagBITMAPFILEHEADER { - WORD bfType; - DWORD bfSize; - WORD bfReserved1; - WORD bfReserved2; - DWORD bfOffBits; - } BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER; -#include - -#define MAKEPOINTS(l) (*((POINTS *)&(l))) - -#ifndef NOFONTSIG - typedef struct tagFONTSIGNATURE { - DWORD fsUsb[4]; - DWORD fsCsb[2]; - } FONTSIGNATURE,*PFONTSIGNATURE,*LPFONTSIGNATURE; - - typedef struct tagCHARSETINFO { - UINT ciCharset; - UINT ciACP; - FONTSIGNATURE fs; - } CHARSETINFO,*PCHARSETINFO,*NPCHARSETINFO,*LPCHARSETINFO; - -#define TCI_SRCCHARSET 1 -#define TCI_SRCCODEPAGE 2 -#define TCI_SRCFONTSIG 3 -#define TCI_SRCLOCALE 0x1000 - - typedef struct tagLOCALESIGNATURE { - DWORD lsUsb[4]; - DWORD lsCsbDefault[2]; - DWORD lsCsbSupported[2]; - } LOCALESIGNATURE,*PLOCALESIGNATURE,*LPLOCALESIGNATURE; -#endif - - -#ifndef NOMETAFILE - typedef struct tagHANDLETABLE { - HGDIOBJ objectHandle[1]; - } HANDLETABLE,*PHANDLETABLE,*LPHANDLETABLE; - - typedef struct tagMETARECORD { - DWORD rdSize; - WORD rdFunction; - WORD rdParm[1]; - } METARECORD; - typedef struct tagMETARECORD UNALIGNED *PMETARECORD; - typedef struct tagMETARECORD UNALIGNED *LPMETARECORD; - - typedef struct tagMETAFILEPICT { - LONG mm; - LONG xExt; - LONG yExt; - HMETAFILE hMF; - } METAFILEPICT,*LPMETAFILEPICT; - -#include - typedef struct tagMETAHEADER { - WORD mtType; - WORD mtHeaderSize; - WORD mtVersion; - DWORD mtSize; - WORD mtNoObjects; - DWORD mtMaxRecord; - WORD mtNoParameters; - } METAHEADER; - typedef struct tagMETAHEADER UNALIGNED *PMETAHEADER; - typedef struct tagMETAHEADER UNALIGNED *LPMETAHEADER; - -#include - - typedef struct tagENHMETARECORD { - DWORD iType; - DWORD nSize; - DWORD dParm[1]; - } ENHMETARECORD,*PENHMETARECORD,*LPENHMETARECORD; - - typedef struct tagENHMETAHEADER { - DWORD iType; - DWORD nSize; - RECTL rclBounds; - RECTL rclFrame; - DWORD dSignature; - DWORD nVersion; - DWORD nBytes; - DWORD nRecords; - WORD nHandles; - WORD sReserved; - DWORD nDescription; - DWORD offDescription; - DWORD nPalEntries; - SIZEL szlDevice; - SIZEL szlMillimeters; - DWORD cbPixelFormat; - DWORD offPixelFormat; - DWORD bOpenGL; - SIZEL szlMicrometers; - } ENHMETAHEADER,*PENHMETAHEADER,*LPENHMETAHEADER; -#endif - -#ifndef NOTEXTMETRIC -#define TMPF_FIXED_PITCH 0x01 -#define TMPF_VECTOR 0x02 -#define TMPF_DEVICE 0x08 -#define TMPF_TRUETYPE 0x04 - -#ifdef UNICODE - typedef WCHAR BCHAR; -#else - typedef BYTE BCHAR; -#endif - -#ifndef _TEXTMETRIC_DEFINED -#define _TEXTMETRIC_DEFINED - typedef struct tagTEXTMETRICA { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - BYTE tmFirstChar; - BYTE tmLastChar; - BYTE tmDefaultChar; - BYTE tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - } TEXTMETRICA,*PTEXTMETRICA,*NPTEXTMETRICA,*LPTEXTMETRICA; - - typedef struct tagTEXTMETRICW { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - WCHAR tmFirstChar; - WCHAR tmLastChar; - WCHAR tmDefaultChar; - WCHAR tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - } TEXTMETRICW,*PTEXTMETRICW,*NPTEXTMETRICW,*LPTEXTMETRICW; -#ifdef UNICODE - typedef TEXTMETRICW TEXTMETRIC; - typedef PTEXTMETRICW PTEXTMETRIC; - typedef NPTEXTMETRICW NPTEXTMETRIC; - typedef LPTEXTMETRICW LPTEXTMETRIC; -#else - typedef TEXTMETRICA TEXTMETRIC; - typedef PTEXTMETRICA PTEXTMETRIC; - typedef NPTEXTMETRICA NPTEXTMETRIC; - typedef LPTEXTMETRICA LPTEXTMETRIC; -#endif -#endif - -#define NTM_REGULAR 0x00000040L -#define NTM_BOLD 0x00000020L -#define NTM_ITALIC 0x00000001L - -#define NTM_NONNEGATIVE_AC 0x00010000 -#define NTM_PS_OPENTYPE 0x00020000 -#define NTM_TT_OPENTYPE 0x00040000 -#define NTM_MULTIPLEMASTER 0x00080000 -#define NTM_TYPE1 0x00100000 -#define NTM_DSIG 0x00200000 - -#include - typedef struct tagNEWTEXTMETRICA { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - BYTE tmFirstChar; - BYTE tmLastChar; - BYTE tmDefaultChar; - BYTE tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - DWORD ntmFlags; - UINT ntmSizeEM; - UINT ntmCellHeight; - UINT ntmAvgWidth; - } NEWTEXTMETRICA,*PNEWTEXTMETRICA,*NPNEWTEXTMETRICA,*LPNEWTEXTMETRICA; - - typedef struct tagNEWTEXTMETRICW { - LONG tmHeight; - LONG tmAscent; - LONG tmDescent; - LONG tmInternalLeading; - LONG tmExternalLeading; - LONG tmAveCharWidth; - LONG tmMaxCharWidth; - LONG tmWeight; - LONG tmOverhang; - LONG tmDigitizedAspectX; - LONG tmDigitizedAspectY; - WCHAR tmFirstChar; - WCHAR tmLastChar; - WCHAR tmDefaultChar; - WCHAR tmBreakChar; - BYTE tmItalic; - BYTE tmUnderlined; - BYTE tmStruckOut; - BYTE tmPitchAndFamily; - BYTE tmCharSet; - DWORD ntmFlags; - UINT ntmSizeEM; - UINT ntmCellHeight; - UINT ntmAvgWidth; - } NEWTEXTMETRICW,*PNEWTEXTMETRICW,*NPNEWTEXTMETRICW,*LPNEWTEXTMETRICW; -#ifdef UNICODE - typedef NEWTEXTMETRICW NEWTEXTMETRIC; - typedef PNEWTEXTMETRICW PNEWTEXTMETRIC; - typedef NPNEWTEXTMETRICW NPNEWTEXTMETRIC; - typedef LPNEWTEXTMETRICW LPNEWTEXTMETRIC; -#else - typedef NEWTEXTMETRICA NEWTEXTMETRIC; - typedef PNEWTEXTMETRICA PNEWTEXTMETRIC; - typedef NPNEWTEXTMETRICA NPNEWTEXTMETRIC; - typedef LPNEWTEXTMETRICA LPNEWTEXTMETRIC; -#endif -#include - - typedef struct tagNEWTEXTMETRICEXA { - NEWTEXTMETRICA ntmTm; - FONTSIGNATURE ntmFontSig; - } NEWTEXTMETRICEXA; - - typedef struct tagNEWTEXTMETRICEXW { - NEWTEXTMETRICW ntmTm; - FONTSIGNATURE ntmFontSig; - } NEWTEXTMETRICEXW; -#ifdef UNICODE - typedef NEWTEXTMETRICEXW NEWTEXTMETRICEX; -#else - typedef NEWTEXTMETRICEXA NEWTEXTMETRICEX; -#endif -#endif - - typedef struct tagPELARRAY { - LONG paXCount; - LONG paYCount; - LONG paXExt; - LONG paYExt; - BYTE paRGBs; - } PELARRAY,*PPELARRAY,*NPPELARRAY,*LPPELARRAY; - - typedef struct tagLOGBRUSH { - UINT lbStyle; - COLORREF lbColor; - ULONG_PTR lbHatch; - } LOGBRUSH,*PLOGBRUSH,*NPLOGBRUSH,*LPLOGBRUSH; - - typedef struct tagLOGBRUSH32 { - UINT lbStyle; - COLORREF lbColor; - ULONG lbHatch; - } LOGBRUSH32,*PLOGBRUSH32,*NPLOGBRUSH32,*LPLOGBRUSH32; - - typedef LOGBRUSH PATTERN; - typedef PATTERN *PPATTERN; - typedef PATTERN *NPPATTERN; - typedef PATTERN *LPPATTERN; - - typedef struct tagLOGPEN { - UINT lopnStyle; - POINT lopnWidth; - COLORREF lopnColor; - } LOGPEN,*PLOGPEN,*NPLOGPEN,*LPLOGPEN; - - typedef struct tagEXTLOGPEN { - DWORD elpPenStyle; - DWORD elpWidth; - UINT elpBrushStyle; - COLORREF elpColor; - ULONG_PTR elpHatch; - DWORD elpNumEntries; - DWORD elpStyleEntry[1]; - } EXTLOGPEN,*PEXTLOGPEN,*NPEXTLOGPEN,*LPEXTLOGPEN; - -#ifndef _PALETTEENTRY_DEFINED -#define _PALETTEENTRY_DEFINED - typedef struct tagPALETTEENTRY { - BYTE peRed; - BYTE peGreen; - BYTE peBlue; - BYTE peFlags; - } PALETTEENTRY,*PPALETTEENTRY,*LPPALETTEENTRY; -#endif - -#ifndef _LOGPALETTE_DEFINED -#define _LOGPALETTE_DEFINED - - typedef struct tagLOGPALETTE { - WORD palVersion; - WORD palNumEntries; - PALETTEENTRY palPalEntry[1]; - } LOGPALETTE,*PLOGPALETTE,*NPLOGPALETTE,*LPLOGPALETTE; -#endif - -#define LF_FACESIZE 32 - - typedef struct tagLOGFONTA { - LONG lfHeight; - LONG lfWidth; - LONG lfEscapement; - LONG lfOrientation; - LONG lfWeight; - BYTE lfItalic; - BYTE lfUnderline; - BYTE lfStrikeOut; - BYTE lfCharSet; - BYTE lfOutPrecision; - BYTE lfClipPrecision; - BYTE lfQuality; - BYTE lfPitchAndFamily; - CHAR lfFaceName[LF_FACESIZE]; - } LOGFONTA,*PLOGFONTA,*NPLOGFONTA,*LPLOGFONTA; - - typedef struct tagLOGFONTW { - LONG lfHeight; - LONG lfWidth; - LONG lfEscapement; - LONG lfOrientation; - LONG lfWeight; - BYTE lfItalic; - BYTE lfUnderline; - BYTE lfStrikeOut; - BYTE lfCharSet; - BYTE lfOutPrecision; - BYTE lfClipPrecision; - BYTE lfQuality; - BYTE lfPitchAndFamily; - WCHAR lfFaceName[LF_FACESIZE]; - } LOGFONTW,*PLOGFONTW,*NPLOGFONTW,*LPLOGFONTW; -#ifdef UNICODE - typedef LOGFONTW LOGFONT; - typedef PLOGFONTW PLOGFONT; - typedef NPLOGFONTW NPLOGFONT; - typedef LPLOGFONTW LPLOGFONT; -#else - typedef LOGFONTA LOGFONT; - typedef PLOGFONTA PLOGFONT; - typedef NPLOGFONTA NPLOGFONT; - typedef LPLOGFONTA LPLOGFONT; -#endif - -#define LF_FULLFACESIZE 64 - - typedef struct tagENUMLOGFONTA { - LOGFONTA elfLogFont; - BYTE elfFullName[LF_FULLFACESIZE]; - BYTE elfStyle[LF_FACESIZE]; - } ENUMLOGFONTA,*LPENUMLOGFONTA; - - typedef struct tagENUMLOGFONTW { - LOGFONTW elfLogFont; - WCHAR elfFullName[LF_FULLFACESIZE]; - WCHAR elfStyle[LF_FACESIZE]; - } ENUMLOGFONTW,*LPENUMLOGFONTW; -#ifdef UNICODE - typedef ENUMLOGFONTW ENUMLOGFONT; - typedef LPENUMLOGFONTW LPENUMLOGFONT; -#else - typedef ENUMLOGFONTA ENUMLOGFONT; - typedef LPENUMLOGFONTA LPENUMLOGFONT; -#endif - - typedef struct tagENUMLOGFONTEXA { - LOGFONTA elfLogFont; - BYTE elfFullName[LF_FULLFACESIZE]; - BYTE elfStyle[LF_FACESIZE]; - BYTE elfScript[LF_FACESIZE]; - } ENUMLOGFONTEXA,*LPENUMLOGFONTEXA; - - typedef struct tagENUMLOGFONTEXW { - LOGFONTW elfLogFont; - WCHAR elfFullName[LF_FULLFACESIZE]; - WCHAR elfStyle[LF_FACESIZE]; - WCHAR elfScript[LF_FACESIZE]; - } ENUMLOGFONTEXW,*LPENUMLOGFONTEXW; -#ifdef UNICODE - typedef ENUMLOGFONTEXW ENUMLOGFONTEX; - typedef LPENUMLOGFONTEXW LPENUMLOGFONTEX; -#else - typedef ENUMLOGFONTEXA ENUMLOGFONTEX; - typedef LPENUMLOGFONTEXA LPENUMLOGFONTEX; -#endif - -#define OUT_DEFAULT_PRECIS 0 -#define OUT_STRING_PRECIS 1 -#define OUT_CHARACTER_PRECIS 2 -#define OUT_STROKE_PRECIS 3 -#define OUT_TT_PRECIS 4 -#define OUT_DEVICE_PRECIS 5 -#define OUT_RASTER_PRECIS 6 -#define OUT_TT_ONLY_PRECIS 7 -#define OUT_OUTLINE_PRECIS 8 -#define OUT_SCREEN_OUTLINE_PRECIS 9 -#define OUT_PS_ONLY_PRECIS 10 - -#define CLIP_DEFAULT_PRECIS 0 -#define CLIP_CHARACTER_PRECIS 1 -#define CLIP_STROKE_PRECIS 2 -#define CLIP_MASK 0xf -#define CLIP_LH_ANGLES (1<<4) -#define CLIP_TT_ALWAYS (2<<4) -#define CLIP_DFA_DISABLE (4<<4) -#define CLIP_EMBEDDED (8<<4) - -#define DEFAULT_QUALITY 0 -#define DRAFT_QUALITY 1 -#define PROOF_QUALITY 2 -#define NONANTIALIASED_QUALITY 3 -#define ANTIALIASED_QUALITY 4 - -#define CLEARTYPE_QUALITY 5 -#define CLEARTYPE_NATURAL_QUALITY 6 - -#define DEFAULT_PITCH 0 -#define FIXED_PITCH 1 -#define VARIABLE_PITCH 2 -#define MONO_FONT 8 - -#define ANSI_CHARSET 0 -#define DEFAULT_CHARSET 1 -#define SYMBOL_CHARSET 2 -#define SHIFTJIS_CHARSET 128 -#define HANGEUL_CHARSET 129 -#define HANGUL_CHARSET 129 -#define GB2312_CHARSET 134 -#define CHINESEBIG5_CHARSET 136 -#define OEM_CHARSET 255 -#define JOHAB_CHARSET 130 -#define HEBREW_CHARSET 177 -#define ARABIC_CHARSET 178 -#define GREEK_CHARSET 161 -#define TURKISH_CHARSET 162 -#define VIETNAMESE_CHARSET 163 -#define THAI_CHARSET 222 -#define EASTEUROPE_CHARSET 238 -#define RUSSIAN_CHARSET 204 - -#define MAC_CHARSET 77 -#define BALTIC_CHARSET 186 - -#define FS_LATIN1 0x00000001L -#define FS_LATIN2 0x00000002L -#define FS_CYRILLIC 0x00000004L -#define FS_GREEK 0x00000008L -#define FS_TURKISH 0x00000010L -#define FS_HEBREW 0x00000020L -#define FS_ARABIC 0x00000040L -#define FS_BALTIC 0x00000080L -#define FS_VIETNAMESE 0x00000100L -#define FS_THAI 0x00010000L -#define FS_JISJAPAN 0x00020000L -#define FS_CHINESESIMP 0x00040000L -#define FS_WANSUNG 0x00080000L -#define FS_CHINESETRAD 0x00100000L -#define FS_JOHAB 0x00200000L -#define FS_SYMBOL 0x80000000L - -#define FF_DONTCARE (0<<4) -#define FF_ROMAN (1<<4) - -#define FF_SWISS (2<<4) - -#define FF_MODERN (3<<4) - -#define FF_SCRIPT (4<<4) -#define FF_DECORATIVE (5<<4) - -#define FW_DONTCARE 0 -#define FW_THIN 100 -#define FW_EXTRALIGHT 200 -#define FW_LIGHT 300 -#define FW_NORMAL 400 -#define FW_MEDIUM 500 -#define FW_SEMIBOLD 600 -#define FW_BOLD 700 -#define FW_EXTRABOLD 800 -#define FW_HEAVY 900 - -#define FW_ULTRALIGHT FW_EXTRALIGHT -#define FW_REGULAR FW_NORMAL -#define FW_DEMIBOLD FW_SEMIBOLD -#define FW_ULTRABOLD FW_EXTRABOLD -#define FW_BLACK FW_HEAVY - -#define PANOSE_COUNT 10 -#define PAN_FAMILYTYPE_INDEX 0 -#define PAN_SERIFSTYLE_INDEX 1 -#define PAN_WEIGHT_INDEX 2 -#define PAN_PROPORTION_INDEX 3 -#define PAN_CONTRAST_INDEX 4 -#define PAN_STROKEVARIATION_INDEX 5 -#define PAN_ARMSTYLE_INDEX 6 -#define PAN_LETTERFORM_INDEX 7 -#define PAN_MIDLINE_INDEX 8 -#define PAN_XHEIGHT_INDEX 9 - -#define PAN_CULTURE_LATIN 0 - - typedef struct tagPANOSE { - BYTE bFamilyType; - BYTE bSerifStyle; - BYTE bWeight; - BYTE bProportion; - BYTE bContrast; - BYTE bStrokeVariation; - BYTE bArmStyle; - BYTE bLetterform; - BYTE bMidline; - BYTE bXHeight; - } PANOSE,*LPPANOSE; - -#define PAN_ANY 0 -#define PAN_NO_FIT 1 - -#define PAN_FAMILY_TEXT_DISPLAY 2 -#define PAN_FAMILY_SCRIPT 3 -#define PAN_FAMILY_DECORATIVE 4 -#define PAN_FAMILY_PICTORIAL 5 - -#define PAN_SERIF_COVE 2 -#define PAN_SERIF_OBTUSE_COVE 3 -#define PAN_SERIF_SQUARE_COVE 4 -#define PAN_SERIF_OBTUSE_SQUARE_COVE 5 -#define PAN_SERIF_SQUARE 6 -#define PAN_SERIF_THIN 7 -#define PAN_SERIF_BONE 8 -#define PAN_SERIF_EXAGGERATED 9 -#define PAN_SERIF_TRIANGLE 10 -#define PAN_SERIF_NORMAL_SANS 11 -#define PAN_SERIF_OBTUSE_SANS 12 -#define PAN_SERIF_PERP_SANS 13 -#define PAN_SERIF_FLARED 14 -#define PAN_SERIF_ROUNDED 15 - -#define PAN_WEIGHT_VERY_LIGHT 2 -#define PAN_WEIGHT_LIGHT 3 -#define PAN_WEIGHT_THIN 4 -#define PAN_WEIGHT_BOOK 5 -#define PAN_WEIGHT_MEDIUM 6 -#define PAN_WEIGHT_DEMI 7 -#define PAN_WEIGHT_BOLD 8 -#define PAN_WEIGHT_HEAVY 9 -#define PAN_WEIGHT_BLACK 10 -#define PAN_WEIGHT_NORD 11 - -#define PAN_PROP_OLD_STYLE 2 -#define PAN_PROP_MODERN 3 -#define PAN_PROP_EVEN_WIDTH 4 -#define PAN_PROP_EXPANDED 5 -#define PAN_PROP_CONDENSED 6 -#define PAN_PROP_VERY_EXPANDED 7 -#define PAN_PROP_VERY_CONDENSED 8 -#define PAN_PROP_MONOSPACED 9 - -#define PAN_CONTRAST_NONE 2 -#define PAN_CONTRAST_VERY_LOW 3 -#define PAN_CONTRAST_LOW 4 -#define PAN_CONTRAST_MEDIUM_LOW 5 -#define PAN_CONTRAST_MEDIUM 6 -#define PAN_CONTRAST_MEDIUM_HIGH 7 -#define PAN_CONTRAST_HIGH 8 -#define PAN_CONTRAST_VERY_HIGH 9 - -#define PAN_STROKE_GRADUAL_DIAG 2 -#define PAN_STROKE_GRADUAL_TRAN 3 -#define PAN_STROKE_GRADUAL_VERT 4 -#define PAN_STROKE_GRADUAL_HORZ 5 -#define PAN_STROKE_RAPID_VERT 6 -#define PAN_STROKE_RAPID_HORZ 7 -#define PAN_STROKE_INSTANT_VERT 8 - -#define PAN_STRAIGHT_ARMS_HORZ 2 -#define PAN_STRAIGHT_ARMS_WEDGE 3 -#define PAN_STRAIGHT_ARMS_VERT 4 -#define PAN_STRAIGHT_ARMS_SINGLE_SERIF 5 -#define PAN_STRAIGHT_ARMS_DOUBLE_SERIF 6 -#define PAN_BENT_ARMS_HORZ 7 -#define PAN_BENT_ARMS_WEDGE 8 -#define PAN_BENT_ARMS_VERT 9 -#define PAN_BENT_ARMS_SINGLE_SERIF 10 -#define PAN_BENT_ARMS_DOUBLE_SERIF 11 - -#define PAN_LETT_NORMAL_CONTACT 2 -#define PAN_LETT_NORMAL_WEIGHTED 3 -#define PAN_LETT_NORMAL_BOXED 4 -#define PAN_LETT_NORMAL_FLATTENED 5 -#define PAN_LETT_NORMAL_ROUNDED 6 -#define PAN_LETT_NORMAL_OFF_CENTER 7 -#define PAN_LETT_NORMAL_SQUARE 8 -#define PAN_LETT_OBLIQUE_CONTACT 9 -#define PAN_LETT_OBLIQUE_WEIGHTED 10 -#define PAN_LETT_OBLIQUE_BOXED 11 -#define PAN_LETT_OBLIQUE_FLATTENED 12 -#define PAN_LETT_OBLIQUE_ROUNDED 13 -#define PAN_LETT_OBLIQUE_OFF_CENTER 14 -#define PAN_LETT_OBLIQUE_SQUARE 15 - -#define PAN_MIDLINE_STANDARD_TRIMMED 2 -#define PAN_MIDLINE_STANDARD_POINTED 3 -#define PAN_MIDLINE_STANDARD_SERIFED 4 -#define PAN_MIDLINE_HIGH_TRIMMED 5 -#define PAN_MIDLINE_HIGH_POINTED 6 -#define PAN_MIDLINE_HIGH_SERIFED 7 -#define PAN_MIDLINE_CONSTANT_TRIMMED 8 -#define PAN_MIDLINE_CONSTANT_POINTED 9 -#define PAN_MIDLINE_CONSTANT_SERIFED 10 -#define PAN_MIDLINE_LOW_TRIMMED 11 -#define PAN_MIDLINE_LOW_POINTED 12 -#define PAN_MIDLINE_LOW_SERIFED 13 - -#define PAN_XHEIGHT_CONSTANT_SMALL 2 -#define PAN_XHEIGHT_CONSTANT_STD 3 -#define PAN_XHEIGHT_CONSTANT_LARGE 4 -#define PAN_XHEIGHT_DUCKING_SMALL 5 -#define PAN_XHEIGHT_DUCKING_STD 6 -#define PAN_XHEIGHT_DUCKING_LARGE 7 - -#define ELF_VENDOR_SIZE 4 - - typedef struct tagEXTLOGFONTA { - LOGFONTA elfLogFont; - BYTE elfFullName[LF_FULLFACESIZE]; - BYTE elfStyle[LF_FACESIZE]; - DWORD elfVersion; - DWORD elfStyleSize; - DWORD elfMatch; - DWORD elfReserved; - BYTE elfVendorId[ELF_VENDOR_SIZE]; - DWORD elfCulture; - PANOSE elfPanose; - } EXTLOGFONTA,*PEXTLOGFONTA,*NPEXTLOGFONTA,*LPEXTLOGFONTA; - - typedef struct tagEXTLOGFONTW { - LOGFONTW elfLogFont; - WCHAR elfFullName[LF_FULLFACESIZE]; - WCHAR elfStyle[LF_FACESIZE]; - DWORD elfVersion; - DWORD elfStyleSize; - DWORD elfMatch; - DWORD elfReserved; - BYTE elfVendorId[ELF_VENDOR_SIZE]; - DWORD elfCulture; - PANOSE elfPanose; - } EXTLOGFONTW,*PEXTLOGFONTW,*NPEXTLOGFONTW,*LPEXTLOGFONTW; -#ifdef UNICODE - typedef EXTLOGFONTW EXTLOGFONT; - typedef PEXTLOGFONTW PEXTLOGFONT; - typedef NPEXTLOGFONTW NPEXTLOGFONT; - typedef LPEXTLOGFONTW LPEXTLOGFONT; -#else - typedef EXTLOGFONTA EXTLOGFONT; - typedef PEXTLOGFONTA PEXTLOGFONT; - typedef NPEXTLOGFONTA NPEXTLOGFONT; - typedef LPEXTLOGFONTA LPEXTLOGFONT; -#endif - -#define ELF_VERSION 0 -#define ELF_CULTURE_LATIN 0 - -#define RASTER_FONTTYPE 0x0001 -#define DEVICE_FONTTYPE 0x002 -#define TRUETYPE_FONTTYPE 0x004 - -#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) -#define PALETTERGB(r,g,b) (0x02000000 | RGB(r,g,b)) -#define PALETTEINDEX(i) ((COLORREF)(0x01000000 | (DWORD)(WORD)(i))) - -#define PC_RESERVED 0x01 -#define PC_EXPLICIT 0x02 -#define PC_NOCOLLAPSE 0x04 - -#define GetRValue(rgb) (LOBYTE(rgb)) -#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8)) -#define GetBValue(rgb) (LOBYTE((rgb)>>16)) - -#define TRANSPARENT 1 -#define OPAQUE 2 -#define BKMODE_LAST 2 - -#define GM_COMPATIBLE 1 -#define GM_ADVANCED 2 -#define GM_LAST 2 - -#define PT_CLOSEFIGURE 0x01 -#define PT_LINETO 0x02 -#define PT_BEZIERTO 0x04 -#define PT_MOVETO 0x06 - -#define MM_TEXT 1 -#define MM_LOMETRIC 2 -#define MM_HIMETRIC 3 -#define MM_LOENGLISH 4 -#define MM_HIENGLISH 5 -#define MM_TWIPS 6 -#define MM_ISOTROPIC 7 -#define MM_ANISOTROPIC 8 - -#define MM_MIN MM_TEXT -#define MM_MAX MM_ANISOTROPIC -#define MM_MAX_FIXEDSCALE MM_TWIPS - -#define ABSOLUTE 1 -#define RELATIVE 2 - -#define WHITE_BRUSH 0 -#define LTGRAY_BRUSH 1 -#define GRAY_BRUSH 2 -#define DKGRAY_BRUSH 3 -#define BLACK_BRUSH 4 -#define NULL_BRUSH 5 -#define HOLLOW_BRUSH NULL_BRUSH -#define WHITE_PEN 6 -#define BLACK_PEN 7 -#define NULL_PEN 8 -#define OEM_FIXED_FONT 10 -#define ANSI_FIXED_FONT 11 -#define ANSI_VAR_FONT 12 -#define SYSTEM_FONT 13 -#define DEVICE_DEFAULT_FONT 14 -#define DEFAULT_PALETTE 15 -#define SYSTEM_FIXED_FONT 16 - -#define DEFAULT_GUI_FONT 17 - -#define DC_BRUSH 18 -#define DC_PEN 19 - -#define STOCK_LAST 19 - -#define CLR_INVALID 0xFFFFFFFF - -#define BS_SOLID 0 -#define BS_NULL 1 -#define BS_HOLLOW BS_NULL -#define BS_HATCHED 2 -#define BS_PATTERN 3 -#define BS_INDEXED 4 -#define BS_DIBPATTERN 5 -#define BS_DIBPATTERNPT 6 -#define BS_PATTERN8X8 7 -#define BS_DIBPATTERN8X8 8 -#define BS_MONOPATTERN 9 - -#define HS_HORIZONTAL 0 -#define HS_VERTICAL 1 -#define HS_FDIAGONAL 2 -#define HS_BDIAGONAL 3 -#define HS_CROSS 4 -#define HS_DIAGCROSS 5 - -#define PS_SOLID 0 -#define PS_DASH 1 -#define PS_DOT 2 -#define PS_DASHDOT 3 -#define PS_DASHDOTDOT 4 -#define PS_NULL 5 -#define PS_INSIDEFRAME 6 -#define PS_USERSTYLE 7 -#define PS_ALTERNATE 8 -#define PS_STYLE_MASK 0x0000000F - -#define PS_ENDCAP_ROUND 0x00000000 -#define PS_ENDCAP_SQUARE 0x00000100 -#define PS_ENDCAP_FLAT 0x00000200 -#define PS_ENDCAP_MASK 0x00000F00 - -#define PS_JOIN_ROUND 0x00000000 -#define PS_JOIN_BEVEL 0x00001000 -#define PS_JOIN_MITER 0x00002000 -#define PS_JOIN_MASK 0x0000F000 - -#define PS_COSMETIC 0x00000000 -#define PS_GEOMETRIC 0x00010000 -#define PS_TYPE_MASK 0x000F0000 - -#define AD_COUNTERCLOCKWISE 1 -#define AD_CLOCKWISE 2 - -#define DRIVERVERSION 0 -#define TECHNOLOGY 2 -#define HORZSIZE 4 -#define VERTSIZE 6 -#define HORZRES 8 -#define VERTRES 10 -#define BITSPIXEL 12 -#define PLANES 14 -#define NUMBRUSHES 16 -#define NUMPENS 18 -#define NUMMARKERS 20 -#define NUMFONTS 22 -#define NUMCOLORS 24 -#define PDEVICESIZE 26 -#define CURVECAPS 28 -#define LINECAPS 30 -#define POLYGONALCAPS 32 -#define TEXTCAPS 34 -#define CLIPCAPS 36 -#define RASTERCAPS 38 -#define ASPECTX 40 -#define ASPECTY 42 -#define ASPECTXY 44 - -#define LOGPIXELSX 88 -#define LOGPIXELSY 90 - -#define SIZEPALETTE 104 -#define NUMRESERVED 106 -#define COLORRES 108 - -#define PHYSICALWIDTH 110 -#define PHYSICALHEIGHT 111 -#define PHYSICALOFFSETX 112 -#define PHYSICALOFFSETY 113 -#define SCALINGFACTORX 114 -#define SCALINGFACTORY 115 - -#define VREFRESH 116 - -#define DESKTOPVERTRES 117 - -#define DESKTOPHORZRES 118 - -#define BLTALIGNMENT 119 - -#define SHADEBLENDCAPS 120 -#define COLORMGMTCAPS 121 - -#ifndef NOGDICAPMASKS -#define DT_PLOTTER 0 -#define DT_RASDISPLAY 1 -#define DT_RASPRINTER 2 -#define DT_RASCAMERA 3 -#define DT_CHARSTREAM 4 -#define DT_METAFILE 5 -#define DT_DISPFILE 6 - -#define CC_NONE 0 -#define CC_CIRCLES 1 -#define CC_PIE 2 -#define CC_CHORD 4 -#define CC_ELLIPSES 8 -#define CC_WIDE 16 -#define CC_STYLED 32 -#define CC_WIDESTYLED 64 -#define CC_INTERIORS 128 -#define CC_ROUNDRECT 256 - -#define LC_NONE 0 -#define LC_POLYLINE 2 -#define LC_MARKER 4 -#define LC_POLYMARKER 8 -#define LC_WIDE 16 -#define LC_STYLED 32 -#define LC_WIDESTYLED 64 -#define LC_INTERIORS 128 - -#define PC_NONE 0 -#define PC_POLYGON 1 -#define PC_RECTANGLE 2 -#define PC_WINDPOLYGON 4 -#define PC_TRAPEZOID 4 -#define PC_SCANLINE 8 -#define PC_WIDE 16 -#define PC_STYLED 32 -#define PC_WIDESTYLED 64 -#define PC_INTERIORS 128 -#define PC_POLYPOLYGON 256 -#define PC_PATHS 512 - -#define CP_NONE 0 -#define CP_RECTANGLE 1 -#define CP_REGION 2 - -#define TC_OP_CHARACTER 0x00000001 -#define TC_OP_STROKE 0x00000002 -#define TC_CP_STROKE 0x00000004 -#define TC_CR_90 0x00000008 -#define TC_CR_ANY 0x00000010 -#define TC_SF_X_YINDEP 0x00000020 -#define TC_SA_DOUBLE 0x00000040 -#define TC_SA_INTEGER 0x00000080 -#define TC_SA_CONTIN 0x00000100 -#define TC_EA_DOUBLE 0x00000200 -#define TC_IA_ABLE 0x00000400 -#define TC_UA_ABLE 0x00000800 -#define TC_SO_ABLE 0x00001000 -#define TC_RA_ABLE 0x00002000 -#define TC_VA_ABLE 0x00004000 -#define TC_RESERVED 0x00008000 -#define TC_SCROLLBLT 0x00010000 -#endif - -#define RC_NONE -#define RC_BITBLT 1 -#define RC_BANDING 2 -#define RC_SCALING 4 -#define RC_BITMAP64 8 -#define RC_GDI20_OUTPUT 0x0010 -#define RC_GDI20_STATE 0x0020 -#define RC_SAVEBITMAP 0x0040 -#define RC_DI_BITMAP 0x0080 -#define RC_PALETTE 0x0100 -#define RC_DIBTODEV 0x0200 -#define RC_BIGFONT 0x0400 -#define RC_STRETCHBLT 0x0800 -#define RC_FLOODFILL 0x1000 -#define RC_STRETCHDIB 0x2000 -#define RC_OP_DX_OUTPUT 0x4000 -#define RC_DEVBITS 0x8000 - -#define SB_NONE 0x00000000 -#define SB_CONST_ALPHA 0x00000001 -#define SB_PIXEL_ALPHA 0x00000002 -#define SB_PREMULT_ALPHA 0x00000004 - -#define SB_GRAD_RECT 0x00000010 -#define SB_GRAD_TRI 0x00000020 - -#define CM_NONE 0x00000000 -#define CM_DEVICE_ICM 0x00000001 -#define CM_GAMMA_RAMP 0x00000002 -#define CM_CMYK_COLOR 0x00000004 - -#define DIB_RGB_COLORS 0 -#define DIB_PAL_COLORS 1 - -#define SYSPAL_ERROR 0 -#define SYSPAL_STATIC 1 -#define SYSPAL_NOSTATIC 2 -#define SYSPAL_NOSTATIC256 3 - -#define CBM_INIT 0x04L - -#define FLOODFILLBORDER 0 -#define FLOODFILLSURFACE 1 - -#define CCHDEVICENAME 32 - -#define CCHFORMNAME 32 - - typedef struct _devicemodeA { - BYTE dmDeviceName[CCHDEVICENAME]; - WORD dmSpecVersion; - WORD dmDriverVersion; - WORD dmSize; - WORD dmDriverExtra; - DWORD dmFields; - union { - struct { - short dmOrientation; - short dmPaperSize; - short dmPaperLength; - short dmPaperWidth; - short dmScale; - short dmCopies; - short dmDefaultSource; - short dmPrintQuality; - }; - struct { - POINTL dmPosition; - DWORD dmDisplayOrientation; - DWORD dmDisplayFixedOutput; - }; - }; - short dmColor; - short dmDuplex; - short dmYResolution; - short dmTTOption; - short dmCollate; - BYTE dmFormName[CCHFORMNAME]; - WORD dmLogPixels; - DWORD dmBitsPerPel; - DWORD dmPelsWidth; - DWORD dmPelsHeight; - union { - DWORD dmDisplayFlags; - DWORD dmNup; - }; - DWORD dmDisplayFrequency; - DWORD dmICMMethod; - DWORD dmICMIntent; - DWORD dmMediaType; - DWORD dmDitherType; - DWORD dmReserved1; - DWORD dmReserved2; - DWORD dmPanningWidth; - DWORD dmPanningHeight; - } DEVMODEA,*PDEVMODEA,*NPDEVMODEA,*LPDEVMODEA; - - typedef struct _devicemodeW { - WCHAR dmDeviceName[CCHDEVICENAME]; - WORD dmSpecVersion; - WORD dmDriverVersion; - WORD dmSize; - WORD dmDriverExtra; - DWORD dmFields; - union { - struct { - short dmOrientation; - short dmPaperSize; - short dmPaperLength; - short dmPaperWidth; - short dmScale; - short dmCopies; - short dmDefaultSource; - short dmPrintQuality; - }; - struct { - POINTL dmPosition; - DWORD dmDisplayOrientation; - DWORD dmDisplayFixedOutput; - }; - }; - short dmColor; - short dmDuplex; - short dmYResolution; - short dmTTOption; - short dmCollate; - WCHAR dmFormName[CCHFORMNAME]; - WORD dmLogPixels; - DWORD dmBitsPerPel; - DWORD dmPelsWidth; - DWORD dmPelsHeight; - union { - DWORD dmDisplayFlags; - DWORD dmNup; - }; - DWORD dmDisplayFrequency; - DWORD dmICMMethod; - DWORD dmICMIntent; - DWORD dmMediaType; - DWORD dmDitherType; - DWORD dmReserved1; - DWORD dmReserved2; - DWORD dmPanningWidth; - DWORD dmPanningHeight; - } DEVMODEW,*PDEVMODEW,*NPDEVMODEW,*LPDEVMODEW; -#ifdef UNICODE - typedef DEVMODEW DEVMODE; - typedef PDEVMODEW PDEVMODE; - typedef NPDEVMODEW NPDEVMODE; - typedef LPDEVMODEW LPDEVMODE; -#else - typedef DEVMODEA DEVMODE; - typedef PDEVMODEA PDEVMODE; - typedef NPDEVMODEA NPDEVMODE; - typedef LPDEVMODEA LPDEVMODE; -#endif - -#define DM_SPECVERSION 0x0401 - -#define DM_ORIENTATION 0x00000001L -#define DM_PAPERSIZE 0x00000002L -#define DM_PAPERLENGTH 0x00000004L -#define DM_PAPERWIDTH 0x00000008L -#define DM_SCALE 0x00000010L -#define DM_POSITION 0x00000020L -#define DM_NUP 0x00000040L -#define DM_DISPLAYORIENTATION 0x00000080L -#define DM_COPIES 0x00000100L -#define DM_DEFAULTSOURCE 0x00000200L -#define DM_PRINTQUALITY 0x00000400L -#define DM_COLOR 0x00000800L -#define DM_DUPLEX 0x00001000L -#define DM_YRESOLUTION 0x00002000L -#define DM_TTOPTION 0x00004000L -#define DM_COLLATE 0x00008000L -#define DM_FORMNAME 0x00010000L -#define DM_LOGPIXELS 0x00020000L -#define DM_BITSPERPEL 0x00040000L -#define DM_PELSWIDTH 0x00080000L -#define DM_PELSHEIGHT 0x00100000L -#define DM_DISPLAYFLAGS 0x00200000L -#define DM_DISPLAYFREQUENCY 0x00400000L -#define DM_ICMMETHOD 0x00800000L -#define DM_ICMINTENT 0x01000000L -#define DM_MEDIATYPE 0x02000000L -#define DM_DITHERTYPE 0x04000000L -#define DM_PANNINGWIDTH 0x08000000L -#define DM_PANNINGHEIGHT 0x10000000L -#define DM_DISPLAYFIXEDOUTPUT 0x20000000L - -#define DMORIENT_PORTRAIT 1 -#define DMORIENT_LANDSCAPE 2 - -#define DMPAPER_FIRST DMPAPER_LETTER -#define DMPAPER_LETTER 1 -#define DMPAPER_LETTERSMALL 2 -#define DMPAPER_TABLOID 3 -#define DMPAPER_LEDGER 4 -#define DMPAPER_LEGAL 5 -#define DMPAPER_STATEMENT 6 -#define DMPAPER_EXECUTIVE 7 -#define DMPAPER_A3 8 -#define DMPAPER_A4 9 -#define DMPAPER_A4SMALL 10 -#define DMPAPER_A5 11 -#define DMPAPER_B4 12 -#define DMPAPER_B5 13 -#define DMPAPER_FOLIO 14 -#define DMPAPER_QUARTO 15 -#define DMPAPER_10X14 16 -#define DMPAPER_11X17 17 -#define DMPAPER_NOTE 18 -#define DMPAPER_ENV_9 19 -#define DMPAPER_ENV_10 20 -#define DMPAPER_ENV_11 21 -#define DMPAPER_ENV_12 22 -#define DMPAPER_ENV_14 23 -#define DMPAPER_CSHEET 24 -#define DMPAPER_DSHEET 25 -#define DMPAPER_ESHEET 26 -#define DMPAPER_ENV_DL 27 -#define DMPAPER_ENV_C5 28 -#define DMPAPER_ENV_C3 29 -#define DMPAPER_ENV_C4 30 -#define DMPAPER_ENV_C6 31 -#define DMPAPER_ENV_C65 32 -#define DMPAPER_ENV_B4 33 -#define DMPAPER_ENV_B5 34 -#define DMPAPER_ENV_B6 35 -#define DMPAPER_ENV_ITALY 36 -#define DMPAPER_ENV_MONARCH 37 -#define DMPAPER_ENV_PERSONAL 38 -#define DMPAPER_FANFOLD_US 39 -#define DMPAPER_FANFOLD_STD_GERMAN 40 -#define DMPAPER_FANFOLD_LGL_GERMAN 41 -#define DMPAPER_ISO_B4 42 -#define DMPAPER_JAPANESE_POSTCARD 43 -#define DMPAPER_9X11 44 -#define DMPAPER_10X11 45 -#define DMPAPER_15X11 46 -#define DMPAPER_ENV_INVITE 47 -#define DMPAPER_RESERVED_48 48 -#define DMPAPER_RESERVED_49 49 -#define DMPAPER_LETTER_EXTRA 50 -#define DMPAPER_LEGAL_EXTRA 51 -#define DMPAPER_TABLOID_EXTRA 52 -#define DMPAPER_A4_EXTRA 53 -#define DMPAPER_LETTER_TRANSVERSE 54 -#define DMPAPER_A4_TRANSVERSE 55 -#define DMPAPER_LETTER_EXTRA_TRANSVERSE 56 -#define DMPAPER_A_PLUS 57 -#define DMPAPER_B_PLUS 58 -#define DMPAPER_LETTER_PLUS 59 -#define DMPAPER_A4_PLUS 60 -#define DMPAPER_A5_TRANSVERSE 61 -#define DMPAPER_B5_TRANSVERSE 62 -#define DMPAPER_A3_EXTRA 63 -#define DMPAPER_A5_EXTRA 64 -#define DMPAPER_B5_EXTRA 65 -#define DMPAPER_A2 66 -#define DMPAPER_A3_TRANSVERSE 67 -#define DMPAPER_A3_EXTRA_TRANSVERSE 68 -#define DMPAPER_DBL_JAPANESE_POSTCARD 69 -#define DMPAPER_A6 70 -#define DMPAPER_JENV_KAKU2 71 -#define DMPAPER_JENV_KAKU3 72 -#define DMPAPER_JENV_CHOU3 73 -#define DMPAPER_JENV_CHOU4 74 -#define DMPAPER_LETTER_ROTATED 75 -#define DMPAPER_A3_ROTATED 76 -#define DMPAPER_A4_ROTATED 77 -#define DMPAPER_A5_ROTATED 78 -#define DMPAPER_B4_JIS_ROTATED 79 -#define DMPAPER_B5_JIS_ROTATED 80 -#define DMPAPER_JAPANESE_POSTCARD_ROTATED 81 -#define DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED 82 -#define DMPAPER_A6_ROTATED 83 -#define DMPAPER_JENV_KAKU2_ROTATED 84 -#define DMPAPER_JENV_KAKU3_ROTATED 85 -#define DMPAPER_JENV_CHOU3_ROTATED 86 -#define DMPAPER_JENV_CHOU4_ROTATED 87 -#define DMPAPER_B6_JIS 88 -#define DMPAPER_B6_JIS_ROTATED 89 -#define DMPAPER_12X11 90 -#define DMPAPER_JENV_YOU4 91 -#define DMPAPER_JENV_YOU4_ROTATED 92 -#define DMPAPER_P16K 93 -#define DMPAPER_P32K 94 -#define DMPAPER_P32KBIG 95 -#define DMPAPER_PENV_1 96 -#define DMPAPER_PENV_2 97 -#define DMPAPER_PENV_3 98 -#define DMPAPER_PENV_4 99 -#define DMPAPER_PENV_5 100 -#define DMPAPER_PENV_6 101 -#define DMPAPER_PENV_7 102 -#define DMPAPER_PENV_8 103 -#define DMPAPER_PENV_9 104 -#define DMPAPER_PENV_10 105 -#define DMPAPER_P16K_ROTATED 106 -#define DMPAPER_P32K_ROTATED 107 -#define DMPAPER_P32KBIG_ROTATED 108 -#define DMPAPER_PENV_1_ROTATED 109 -#define DMPAPER_PENV_2_ROTATED 110 -#define DMPAPER_PENV_3_ROTATED 111 -#define DMPAPER_PENV_4_ROTATED 112 -#define DMPAPER_PENV_5_ROTATED 113 -#define DMPAPER_PENV_6_ROTATED 114 -#define DMPAPER_PENV_7_ROTATED 115 -#define DMPAPER_PENV_8_ROTATED 116 -#define DMPAPER_PENV_9_ROTATED 117 -#define DMPAPER_PENV_10_ROTATED 118 - -#define DMPAPER_LAST DMPAPER_PENV_10_ROTATED - -#define DMPAPER_USER 256 - -#define DMBIN_FIRST DMBIN_UPPER -#define DMBIN_UPPER 1 -#define DMBIN_ONLYONE 1 -#define DMBIN_LOWER 2 -#define DMBIN_MIDDLE 3 -#define DMBIN_MANUAL 4 -#define DMBIN_ENVELOPE 5 -#define DMBIN_ENVMANUAL 6 -#define DMBIN_AUTO 7 -#define DMBIN_TRACTOR 8 -#define DMBIN_SMALLFMT 9 -#define DMBIN_LARGEFMT 10 -#define DMBIN_LARGECAPACITY 11 -#define DMBIN_CASSETTE 14 -#define DMBIN_FORMSOURCE 15 -#define DMBIN_LAST DMBIN_FORMSOURCE - -#define DMBIN_USER 256 - -#define DMRES_DRAFT (-1) -#define DMRES_LOW (-2) -#define DMRES_MEDIUM (-3) -#define DMRES_HIGH (-4) - -#define DMCOLOR_MONOCHROME 1 -#define DMCOLOR_COLOR 2 - -#define DMDUP_SIMPLEX 1 -#define DMDUP_VERTICAL 2 -#define DMDUP_HORIZONTAL 3 - -#define DMTT_BITMAP 1 -#define DMTT_DOWNLOAD 2 -#define DMTT_SUBDEV 3 -#define DMTT_DOWNLOAD_OUTLINE 4 - -#define DMCOLLATE_FALSE 0 -#define DMCOLLATE_TRUE 1 - -#define DMDO_DEFAULT 0 -#define DMDO_90 1 -#define DMDO_180 2 -#define DMDO_270 3 - -#define DMDFO_DEFAULT 0 -#define DMDFO_STRETCH 1 -#define DMDFO_CENTER 2 - -#define DMDISPLAYFLAGS_TEXTMODE 0x00000004 - -#define DMNUP_SYSTEM 1 -#define DMNUP_ONEUP 2 - -#define DMICMMETHOD_NONE 1 -#define DMICMMETHOD_SYSTEM 2 -#define DMICMMETHOD_DRIVER 3 -#define DMICMMETHOD_DEVICE 4 - -#define DMICMMETHOD_USER 256 - -#define DMICM_SATURATE 1 -#define DMICM_CONTRAST 2 -#define DMICM_COLORIMETRIC 3 -#define DMICM_ABS_COLORIMETRIC 4 - -#define DMICM_USER 256 - -#define DMMEDIA_STANDARD 1 -#define DMMEDIA_TRANSPARENCY 2 -#define DMMEDIA_GLOSSY 3 - -#define DMMEDIA_USER 256 - -#define DMDITHER_NONE 1 -#define DMDITHER_COARSE 2 -#define DMDITHER_FINE 3 -#define DMDITHER_LINEART 4 -#define DMDITHER_ERRORDIFFUSION 5 -#define DMDITHER_RESERVED6 6 -#define DMDITHER_RESERVED7 7 -#define DMDITHER_RESERVED8 8 -#define DMDITHER_RESERVED9 9 -#define DMDITHER_GRAYSCALE 10 - -#define DMDITHER_USER 256 - - typedef struct _DISPLAY_DEVICEA { - DWORD cb; - CHAR DeviceName[32]; - CHAR DeviceString[128]; - DWORD StateFlags; - CHAR DeviceID[128]; - CHAR DeviceKey[128]; - } DISPLAY_DEVICEA,*PDISPLAY_DEVICEA,*LPDISPLAY_DEVICEA; - typedef struct _DISPLAY_DEVICEW { - DWORD cb; - WCHAR DeviceName[32]; - WCHAR DeviceString[128]; - DWORD StateFlags; - WCHAR DeviceID[128]; - WCHAR DeviceKey[128]; - } DISPLAY_DEVICEW,*PDISPLAY_DEVICEW,*LPDISPLAY_DEVICEW; -#ifdef UNICODE - typedef DISPLAY_DEVICEW DISPLAY_DEVICE; - typedef PDISPLAY_DEVICEW PDISPLAY_DEVICE; - typedef LPDISPLAY_DEVICEW LPDISPLAY_DEVICE; -#else - typedef DISPLAY_DEVICEA DISPLAY_DEVICE; - typedef PDISPLAY_DEVICEA PDISPLAY_DEVICE; - typedef LPDISPLAY_DEVICEA LPDISPLAY_DEVICE; -#endif - -#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 -#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002 -#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 -#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 -#define DISPLAY_DEVICE_VGA_COMPATIBLE 0x00000010 -#define DISPLAY_DEVICE_REMOVABLE 0x00000020 -#define DISPLAY_DEVICE_MODESPRUNED 0x08000000 -#define DISPLAY_DEVICE_REMOTE 0x04000000 -#define DISPLAY_DEVICE_DISCONNECT 0x02000000 - -#define DISPLAY_DEVICE_ACTIVE 0x00000001 -#define DISPLAY_DEVICE_ATTACHED 0x00000002 - -#define RDH_RECTANGLES 1 - - typedef struct _RGNDATAHEADER { - DWORD dwSize; - DWORD iType; - DWORD nCount; - DWORD nRgnSize; - RECT rcBound; - } RGNDATAHEADER,*PRGNDATAHEADER; - - typedef struct _RGNDATA { - RGNDATAHEADER rdh; - char Buffer[1]; - } RGNDATA,*PRGNDATA,*NPRGNDATA,*LPRGNDATA; - -#define SYSRGN 4 - - typedef struct _ABC { - int abcA; - UINT abcB; - int abcC; - } ABC,*PABC,*NPABC,*LPABC; - - typedef struct _ABCFLOAT { - FLOAT abcfA; - FLOAT abcfB; - FLOAT abcfC; - } ABCFLOAT,*PABCFLOAT,*NPABCFLOAT,*LPABCFLOAT; - -#ifndef NOTEXTMETRIC - - typedef struct _OUTLINETEXTMETRICA { - UINT otmSize; - TEXTMETRICA otmTextMetrics; - BYTE otmFiller; - PANOSE otmPanoseNumber; - UINT otmfsSelection; - UINT otmfsType; - int otmsCharSlopeRise; - int otmsCharSlopeRun; - int otmItalicAngle; - UINT otmEMSquare; - int otmAscent; - int otmDescent; - UINT otmLineGap; - UINT otmsCapEmHeight; - UINT otmsXHeight; - RECT otmrcFontBox; - int otmMacAscent; - int otmMacDescent; - UINT otmMacLineGap; - UINT otmusMinimumPPEM; - POINT otmptSubscriptSize; - POINT otmptSubscriptOffset; - POINT otmptSuperscriptSize; - POINT otmptSuperscriptOffset; - UINT otmsStrikeoutSize; - int otmsStrikeoutPosition; - int otmsUnderscoreSize; - int otmsUnderscorePosition; - PSTR otmpFamilyName; - PSTR otmpFaceName; - PSTR otmpStyleName; - PSTR otmpFullName; - } OUTLINETEXTMETRICA,*POUTLINETEXTMETRICA,*NPOUTLINETEXTMETRICA,*LPOUTLINETEXTMETRICA; - - typedef struct _OUTLINETEXTMETRICW { - UINT otmSize; - TEXTMETRICW otmTextMetrics; - BYTE otmFiller; - PANOSE otmPanoseNumber; - UINT otmfsSelection; - UINT otmfsType; - int otmsCharSlopeRise; - int otmsCharSlopeRun; - int otmItalicAngle; - UINT otmEMSquare; - int otmAscent; - int otmDescent; - UINT otmLineGap; - UINT otmsCapEmHeight; - UINT otmsXHeight; - RECT otmrcFontBox; - int otmMacAscent; - int otmMacDescent; - UINT otmMacLineGap; - UINT otmusMinimumPPEM; - POINT otmptSubscriptSize; - POINT otmptSubscriptOffset; - POINT otmptSuperscriptSize; - POINT otmptSuperscriptOffset; - UINT otmsStrikeoutSize; - int otmsStrikeoutPosition; - int otmsUnderscoreSize; - int otmsUnderscorePosition; - PSTR otmpFamilyName; - PSTR otmpFaceName; - PSTR otmpStyleName; - PSTR otmpFullName; - } OUTLINETEXTMETRICW,*POUTLINETEXTMETRICW,*NPOUTLINETEXTMETRICW,*LPOUTLINETEXTMETRICW; -#ifdef UNICODE - typedef OUTLINETEXTMETRICW OUTLINETEXTMETRIC; - typedef POUTLINETEXTMETRICW POUTLINETEXTMETRIC; - typedef NPOUTLINETEXTMETRICW NPOUTLINETEXTMETRIC; - typedef LPOUTLINETEXTMETRICW LPOUTLINETEXTMETRIC; -#else - typedef OUTLINETEXTMETRICA OUTLINETEXTMETRIC; - typedef POUTLINETEXTMETRICA POUTLINETEXTMETRIC; - typedef NPOUTLINETEXTMETRICA NPOUTLINETEXTMETRIC; - typedef LPOUTLINETEXTMETRICA LPOUTLINETEXTMETRIC; -#endif -#endif - - typedef struct tagPOLYTEXTA { - int x; - int y; - UINT n; - LPCSTR lpstr; - UINT uiFlags; - RECT rcl; - int *pdx; - } POLYTEXTA,*PPOLYTEXTA,*NPPOLYTEXTA,*LPPOLYTEXTA; - - typedef struct tagPOLYTEXTW { - int x; - int y; - UINT n; - LPCWSTR lpstr; - UINT uiFlags; - RECT rcl; - int *pdx; - } POLYTEXTW,*PPOLYTEXTW,*NPPOLYTEXTW,*LPPOLYTEXTW; -#ifdef UNICODE - typedef POLYTEXTW POLYTEXT; - typedef PPOLYTEXTW PPOLYTEXT; - typedef NPPOLYTEXTW NPPOLYTEXT; - typedef LPPOLYTEXTW LPPOLYTEXT; -#else - typedef POLYTEXTA POLYTEXT; - typedef PPOLYTEXTA PPOLYTEXT; - typedef NPPOLYTEXTA NPPOLYTEXT; - typedef LPPOLYTEXTA LPPOLYTEXT; -#endif - - typedef struct _FIXED { - WORD fract; - short value; - } FIXED; - - typedef struct _MAT2 { - FIXED eM11; - FIXED eM12; - FIXED eM21; - FIXED eM22; - } MAT2,*LPMAT2; - - typedef struct _GLYPHMETRICS { - UINT gmBlackBoxX; - UINT gmBlackBoxY; - POINT gmptGlyphOrigin; - short gmCellIncX; - short gmCellIncY; - } GLYPHMETRICS,*LPGLYPHMETRICS; - -#define GGO_METRICS 0 -#define GGO_BITMAP 1 -#define GGO_NATIVE 2 -#define GGO_BEZIER 3 - -#define GGO_GRAY2_BITMAP 4 -#define GGO_GRAY4_BITMAP 5 -#define GGO_GRAY8_BITMAP 6 -#define GGO_GLYPH_INDEX 0x0080 -#define GGO_UNHINTED 0x0100 - -#define TT_POLYGON_TYPE 24 - -#define TT_PRIM_LINE 1 -#define TT_PRIM_QSPLINE 2 -#define TT_PRIM_CSPLINE 3 - - typedef struct tagPOINTFX { - FIXED x; - FIXED y; - } POINTFX,*LPPOINTFX; - - typedef struct tagTTPOLYCURVE { - WORD wType; - WORD cpfx; - POINTFX apfx[1]; - } TTPOLYCURVE,*LPTTPOLYCURVE; - - typedef struct tagTTPOLYGONHEADER { - DWORD cb; - DWORD dwType; - POINTFX pfxStart; - } TTPOLYGONHEADER,*LPTTPOLYGONHEADER; - -#define GCP_DBCS 0x0001 -#define GCP_REORDER 0x0002 -#define GCP_USEKERNING 0x0008 -#define GCP_GLYPHSHAPE 0x0010 -#define GCP_LIGATE 0x0020 - -#define GCP_DIACRITIC 0x0100 -#define GCP_KASHIDA 0x0400 -#define GCP_ERROR 0x8000 -#define FLI_MASK 0x103B - -#define GCP_JUSTIFY 0x00010000L - -#define FLI_GLYPHS 0x00040000L -#define GCP_CLASSIN 0x00080000L -#define GCP_MAXEXTENT 0x00100000L -#define GCP_JUSTIFYIN 0x00200000L -#define GCP_DISPLAYZWG 0x00400000L -#define GCP_SYMSWAPOFF 0x00800000L -#define GCP_NUMERICOVERRIDE 0x01000000L -#define GCP_NEUTRALOVERRIDE 0x02000000L -#define GCP_NUMERICSLATIN 0x04000000L -#define GCP_NUMERICSLOCAL 0x08000000L - -#define GCPCLASS_LATIN 1 -#define GCPCLASS_HEBREW 2 -#define GCPCLASS_ARABIC 2 -#define GCPCLASS_NEUTRAL 3 -#define GCPCLASS_LOCALNUMBER 4 -#define GCPCLASS_LATINNUMBER 5 -#define GCPCLASS_LATINNUMERICTERMINATOR 6 -#define GCPCLASS_LATINNUMERICSEPARATOR 7 -#define GCPCLASS_NUMERICSEPARATOR 8 -#define GCPCLASS_PREBOUNDLTR 0x80 -#define GCPCLASS_PREBOUNDRTL 0x40 -#define GCPCLASS_POSTBOUNDLTR 0x20 -#define GCPCLASS_POSTBOUNDRTL 0x10 - -#define GCPGLYPH_LINKBEFORE 0x8000 -#define GCPGLYPH_LINKAFTER 0x4000 - - typedef struct tagGCP_RESULTSA { - DWORD lStructSize; - LPSTR lpOutString; - UINT *lpOrder; - int *lpDx; - int *lpCaretPos; - LPSTR lpClass; - LPWSTR lpGlyphs; - UINT nGlyphs; - int nMaxFit; - } GCP_RESULTSA,*LPGCP_RESULTSA; - typedef struct tagGCP_RESULTSW { - DWORD lStructSize; - LPWSTR lpOutString; - UINT *lpOrder; - int *lpDx; - int *lpCaretPos; - LPSTR lpClass; - LPWSTR lpGlyphs; - UINT nGlyphs; - int nMaxFit; - } GCP_RESULTSW,*LPGCP_RESULTSW; -#ifdef UNICODE - typedef GCP_RESULTSW GCP_RESULTS; - typedef LPGCP_RESULTSW LPGCP_RESULTS; -#else - typedef GCP_RESULTSA GCP_RESULTS; - typedef LPGCP_RESULTSA LPGCP_RESULTS; -#endif - - typedef struct _RASTERIZER_STATUS { - short nSize; - short wFlags; - short nLanguageID; - } RASTERIZER_STATUS,*LPRASTERIZER_STATUS; - -#define TT_AVAILABLE 0x0001 -#define TT_ENABLED 0x0002 - - typedef struct tagPIXELFORMATDESCRIPTOR { - WORD nSize; - WORD nVersion; - DWORD dwFlags; - BYTE iPixelType; - BYTE cColorBits; - BYTE cRedBits; - BYTE cRedShift; - BYTE cGreenBits; - BYTE cGreenShift; - BYTE cBlueBits; - BYTE cBlueShift; - BYTE cAlphaBits; - BYTE cAlphaShift; - BYTE cAccumBits; - BYTE cAccumRedBits; - BYTE cAccumGreenBits; - BYTE cAccumBlueBits; - BYTE cAccumAlphaBits; - BYTE cDepthBits; - BYTE cStencilBits; - BYTE cAuxBuffers; - BYTE iLayerType; - BYTE bReserved; - DWORD dwLayerMask; - DWORD dwVisibleMask; - DWORD dwDamageMask; - } PIXELFORMATDESCRIPTOR,*PPIXELFORMATDESCRIPTOR,*LPPIXELFORMATDESCRIPTOR; - -#define PFD_TYPE_RGBA 0 -#define PFD_TYPE_COLORINDEX 1 - -#define PFD_MAIN_PLANE 0 -#define PFD_OVERLAY_PLANE 1 -#define PFD_UNDERLAY_PLANE (-1) - -#define PFD_DOUBLEBUFFER 0x00000001 -#define PFD_STEREO 0x00000002 -#define PFD_DRAW_TO_WINDOW 0x00000004 -#define PFD_DRAW_TO_BITMAP 0x00000008 -#define PFD_SUPPORT_GDI 0x00000010 -#define PFD_SUPPORT_OPENGL 0x00000020 -#define PFD_GENERIC_FORMAT 0x00000040 -#define PFD_NEED_PALETTE 0x00000080 -#define PFD_NEED_SYSTEM_PALETTE 0x00000100 -#define PFD_SWAP_EXCHANGE 0x00000200 -#define PFD_SWAP_COPY 0x00000400 -#define PFD_SWAP_LAYER_BUFFERS 0x00000800 -#define PFD_GENERIC_ACCELERATED 0x00001000 -#define PFD_SUPPORT_DIRECTDRAW 0x00002000 - -#define PFD_DEPTH_DONTCARE 0x20000000 -#define PFD_DOUBLEBUFFER_DONTCARE 0x40000000 -#define PFD_STEREO_DONTCARE 0x80000000 - -#ifndef NOTEXTMETRIC - typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST TEXTMETRICA *,DWORD,LPARAM); - typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST TEXTMETRICW *,DWORD,LPARAM); -#ifdef UNICODE -#define OLDFONTENUMPROC OLDFONTENUMPROCW -#else -#define OLDFONTENUMPROC OLDFONTENUMPROCA -#endif -#else - typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST VOID *,DWORD,LPARAM); - typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST VOID *,DWORD,LPARAM); -#ifdef UNICODE -#define OLDFONTENUMPROC OLDFONTENUMPROCW -#else -#define OLDFONTENUMPROC OLDFONTENUMPROCA -#endif -#endif - - typedef OLDFONTENUMPROCA FONTENUMPROCA; - typedef OLDFONTENUMPROCW FONTENUMPROCW; -#ifdef UNICODE - typedef FONTENUMPROCW FONTENUMPROC; -#else - typedef FONTENUMPROCA FONTENUMPROC; -#endif - - typedef int (CALLBACK *GOBJENUMPROC)(LPVOID,LPARAM); - typedef VOID (CALLBACK *LINEDDAPROC)(int,int,LPARAM); - -#ifdef UNICODE -#define AddFontResource AddFontResourceW -#define CopyMetaFile CopyMetaFileW -#define CreateDC CreateDCW -#define CreateFontIndirect CreateFontIndirectW -#define CreateFont CreateFontW -#define CreateIC CreateICW -#define CreateMetaFile CreateMetaFileW -#define CreateScalableFontResource CreateScalableFontResourceW -#else -#define AddFontResource AddFontResourceA -#define CopyMetaFile CopyMetaFileA -#define CreateDC CreateDCA -#define CreateFontIndirect CreateFontIndirectA -#define CreateFont CreateFontA -#define CreateIC CreateICA -#define CreateMetaFile CreateMetaFileA -#define CreateScalableFontResource CreateScalableFontResourceA -#endif - - WINGDIAPI int WINAPI AddFontResourceA(LPCSTR); - WINGDIAPI int WINAPI AddFontResourceW(LPCWSTR); - WINGDIAPI WINBOOL WINAPI AnimatePalette(HPALETTE hPal,UINT iStartIndex,UINT cEntries,CONST PALETTEENTRY *ppe); - WINGDIAPI WINBOOL WINAPI Arc(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); - WINGDIAPI WINBOOL WINAPI BitBlt(HDC hdc,int x,int y,int cx,int cy,HDC hdcSrc,int x1,int y1,DWORD rop); - WINGDIAPI WINBOOL WINAPI CancelDC(HDC hdc); - WINGDIAPI WINBOOL WINAPI Chord(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); - WINGDIAPI int WINAPI ChoosePixelFormat(HDC hdc,CONST PIXELFORMATDESCRIPTOR *ppfd); - WINGDIAPI HMETAFILE WINAPI CloseMetaFile(HDC hdc); - WINGDIAPI int WINAPI CombineRgn(HRGN hrgnDst,HRGN hrgnSrc1,HRGN hrgnSrc2,int iMode); - WINGDIAPI HMETAFILE WINAPI CopyMetaFileA(HMETAFILE,LPCSTR); - WINGDIAPI HMETAFILE WINAPI CopyMetaFileW(HMETAFILE,LPCWSTR); - WINGDIAPI HBITMAP WINAPI CreateBitmap(int nWidth,int nHeight,UINT nPlanes,UINT nBitCount,CONST VOID *lpBits); - WINGDIAPI HBITMAP WINAPI CreateBitmapIndirect(CONST BITMAP *pbm); - WINGDIAPI HBRUSH WINAPI CreateBrushIndirect(CONST LOGBRUSH *plbrush); - WINGDIAPI HBITMAP WINAPI CreateCompatibleBitmap(HDC hdc,int cx,int cy); - WINGDIAPI HBITMAP WINAPI CreateDiscardableBitmap(HDC hdc,int cx,int cy); - WINGDIAPI HDC WINAPI CreateCompatibleDC(HDC hdc); - WINGDIAPI HDC WINAPI CreateDCA(LPCSTR pwszDriver,LPCSTR pwszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); - WINGDIAPI HDC WINAPI CreateDCW(LPCWSTR pwszDriver,LPCWSTR pwszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); - WINGDIAPI HBITMAP WINAPI CreateDIBitmap(HDC hdc,CONST BITMAPINFOHEADER *pbmih,DWORD flInit,CONST VOID *pjBits,CONST BITMAPINFO *pbmi,UINT iUsage); - WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrush(HGLOBAL h,UINT iUsage); - WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrushPt(CONST VOID *lpPackedDIB,UINT iUsage); - WINGDIAPI HRGN WINAPI CreateEllipticRgn(int x1,int y1,int x2,int y2); - WINGDIAPI HRGN WINAPI CreateEllipticRgnIndirect(CONST RECT *lprect); - WINGDIAPI HFONT WINAPI CreateFontIndirectA(CONST LOGFONTA *lplf); - WINGDIAPI HFONT WINAPI CreateFontIndirectW(CONST LOGFONTW *lplf); - WINGDIAPI HFONT WINAPI CreateFontA(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCSTR pszFaceName); - WINGDIAPI HFONT WINAPI CreateFontW(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCWSTR pszFaceName); - WINGDIAPI HBRUSH WINAPI CreateHatchBrush(int iHatch,COLORREF color); - WINGDIAPI HDC WINAPI CreateICA(LPCSTR pszDriver,LPCSTR pszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); - WINGDIAPI HDC WINAPI CreateICW(LPCWSTR pszDriver,LPCWSTR pszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); - WINGDIAPI HDC WINAPI CreateMetaFileA(LPCSTR pszFile); - WINGDIAPI HDC WINAPI CreateMetaFileW(LPCWSTR pszFile); - WINGDIAPI HPALETTE WINAPI CreatePalette(CONST LOGPALETTE *plpal); - WINGDIAPI HPEN WINAPI CreatePen(int iStyle,int cWidth,COLORREF color); - WINGDIAPI HPEN WINAPI CreatePenIndirect(CONST LOGPEN *plpen); - WINGDIAPI HRGN WINAPI CreatePolyPolygonRgn(CONST POINT *pptl,CONST INT *pc,int cPoly,int iMode); - WINGDIAPI HBRUSH WINAPI CreatePatternBrush(HBITMAP hbm); - WINGDIAPI HRGN WINAPI CreateRectRgn(int x1,int y1,int x2,int y2); - WINGDIAPI HRGN WINAPI CreateRectRgnIndirect(CONST RECT *lprect); - WINGDIAPI HRGN WINAPI CreateRoundRectRgn(int x1,int y1,int x2,int y2,int w,int h); - WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceA(DWORD fdwHidden,LPCSTR lpszFont,LPCSTR lpszFile,LPCSTR lpszPath); - WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceW(DWORD fdwHidden,LPCWSTR lpszFont,LPCWSTR lpszFile,LPCWSTR lpszPath); - WINGDIAPI HBRUSH WINAPI CreateSolidBrush(COLORREF color); - WINGDIAPI WINBOOL WINAPI DeleteDC(HDC hdc); - WINGDIAPI WINBOOL WINAPI DeleteMetaFile(HMETAFILE hmf); - WINGDIAPI WINBOOL WINAPI DeleteObject(HGDIOBJ ho); - WINGDIAPI int WINAPI DescribePixelFormat(HDC hdc,int iPixelFormat,UINT nBytes,LPPIXELFORMATDESCRIPTOR ppfd); - - typedef UINT (CALLBACK *LPFNDEVMODE)(HWND,HMODULE,LPDEVMODE,LPSTR,LPSTR,LPDEVMODE,LPSTR,UINT); - typedef DWORD (CALLBACK *LPFNDEVCAPS)(LPSTR,LPSTR,UINT,LPSTR,LPDEVMODE); - -#define DM_UPDATE 1 -#define DM_COPY 2 -#define DM_PROMPT 4 -#define DM_MODIFY 8 - -#define DM_IN_BUFFER DM_MODIFY -#define DM_IN_PROMPT DM_PROMPT -#define DM_OUT_BUFFER DM_COPY -#define DM_OUT_DEFAULT DM_UPDATE - -#define DC_FIELDS 1 -#define DC_PAPERS 2 -#define DC_PAPERSIZE 3 -#define DC_MINEXTENT 4 -#define DC_MAXEXTENT 5 -#define DC_BINS 6 -#define DC_DUPLEX 7 -#define DC_SIZE 8 -#define DC_EXTRA 9 -#define DC_VERSION 10 -#define DC_DRIVER 11 -#define DC_BINNAMES 12 -#define DC_ENUMRESOLUTIONS 13 -#define DC_FILEDEPENDENCIES 14 -#define DC_TRUETYPE 15 -#define DC_PAPERNAMES 16 -#define DC_ORIENTATION 17 -#define DC_COPIES 18 -#define DC_BINADJUST 19 -#define DC_EMF_COMPLIANT 20 -#define DC_DATATYPE_PRODUCED 21 -#define DC_COLLATE 22 -#define DC_MANUFACTURER 23 -#define DC_MODEL 24 -#define DC_PERSONALITY 25 -#define DC_PRINTRATE 26 -#define DC_PRINTRATEUNIT 27 -#define PRINTRATEUNIT_PPM 1 -#define PRINTRATEUNIT_CPS 2 -#define PRINTRATEUNIT_LPM 3 -#define PRINTRATEUNIT_IPM 4 -#define DC_PRINTERMEM 28 -#define DC_MEDIAREADY 29 -#define DC_STAPLE 30 -#define DC_PRINTRATEPPM 31 -#define DC_COLORDEVICE 32 -#define DC_NUP 33 -#define DC_MEDIATYPENAMES 34 -#define DC_MEDIATYPES 35 - -#define DCTT_BITMAP 0x0000001L -#define DCTT_DOWNLOAD 0x0000002L -#define DCTT_SUBDEV 0x0000004L -#define DCTT_DOWNLOAD_OUTLINE 0x0000008L - -#define DCBA_FACEUPNONE 0x0000 -#define DCBA_FACEUPCENTER 0x0001 -#define DCBA_FACEUPLEFT 0x0002 -#define DCBA_FACEUPRIGHT 0x0003 -#define DCBA_FACEDOWNNONE 0x0100 -#define DCBA_FACEDOWNCENTER 0x0101 -#define DCBA_FACEDOWNLEFT 0x0102 -#define DCBA_FACEDOWNRIGHT 0x0103 - -#ifdef UNICODE -#define DeviceCapabilities DeviceCapabilitiesW -#define EnumFontFamiliesEx EnumFontFamiliesExW -#define EnumFontFamilies EnumFontFamiliesW -#define EnumFonts EnumFontsW -#define GetCharWidth GetCharWidthW -#define GetCharWidth32 GetCharWidth32W -#define GetCharWidthFloat GetCharWidthFloatW -#define GetCharABCWidths GetCharABCWidthsW -#define GetCharABCWidthsFloat GetCharABCWidthsFloatW -#define GetGlyphOutline GetGlyphOutlineW -#define GetMetaFile GetMetaFileW -#else -#define DeviceCapabilities DeviceCapabilitiesA -#define EnumFontFamiliesEx EnumFontFamiliesExA -#define EnumFontFamilies EnumFontFamiliesA -#define EnumFonts EnumFontsA -#define GetCharWidth GetCharWidthA -#define GetCharWidth32 GetCharWidth32A -#define GetCharWidthFloat GetCharWidthFloatA -#define GetCharABCWidths GetCharABCWidthsA -#define GetCharABCWidthsFloat GetCharABCWidthsFloatA -#define GetGlyphOutline GetGlyphOutlineA -#define GetMetaFile GetMetaFileA -#endif - - WINSPOOLAPI int WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort,WORD fwCapability,LPSTR pOutput,CONST DEVMODEA *pDevMode); - WINSPOOLAPI int WINAPI DeviceCapabilitiesW(LPCWSTR pDevice,LPCWSTR pPort,WORD fwCapability,LPWSTR pOutput,CONST DEVMODEW *pDevMode); - WINGDIAPI int WINAPI DrawEscape(HDC hdc,int iEscape,int cjIn,LPCSTR lpIn); - WINGDIAPI WINBOOL WINAPI Ellipse(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI int WINAPI EnumFontFamiliesExA(HDC hdc,LPLOGFONTA lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam,DWORD dwFlags); - WINGDIAPI int WINAPI EnumFontFamiliesExW(HDC hdc,LPLOGFONTW lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam,DWORD dwFlags); - WINGDIAPI int WINAPI EnumFontFamiliesA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumFontFamiliesW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumFontsA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumFontsW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); - WINGDIAPI int WINAPI EnumObjects(HDC hdc,int nType,GOBJENUMPROC lpFunc,LPARAM lParam); - WINGDIAPI WINBOOL WINAPI EqualRgn(HRGN hrgn1,HRGN hrgn2); - WINGDIAPI int WINAPI Escape(HDC hdc,int iEscape,int cjIn,LPCSTR pvIn,LPVOID pvOut); - WINGDIAPI int WINAPI ExtEscape(HDC hdc,int iEscape,int cjInput,LPCSTR lpInData,int cjOutput,LPSTR lpOutData); - WINGDIAPI int WINAPI ExcludeClipRect(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI HRGN WINAPI ExtCreateRegion(CONST XFORM *lpx,DWORD nCount,CONST RGNDATA *lpData); - WINGDIAPI WINBOOL WINAPI ExtFloodFill(HDC hdc,int x,int y,COLORREF color,UINT type); - WINGDIAPI WINBOOL WINAPI FillRgn(HDC hdc,HRGN hrgn,HBRUSH hbr); - WINGDIAPI WINBOOL WINAPI FloodFill(HDC hdc,int x,int y,COLORREF color); - WINGDIAPI WINBOOL WINAPI FrameRgn(HDC hdc,HRGN hrgn,HBRUSH hbr,int w,int h); - WINGDIAPI int WINAPI GetROP2(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetAspectRatioFilterEx(HDC hdc,LPSIZE lpsize); - WINGDIAPI COLORREF WINAPI GetBkColor(HDC hdc); - WINGDIAPI COLORREF WINAPI GetDCBrushColor(HDC hdc); - WINGDIAPI COLORREF WINAPI GetDCPenColor(HDC hdc); - WINGDIAPI int WINAPI GetBkMode(HDC hdc); - WINGDIAPI LONG WINAPI GetBitmapBits(HBITMAP hbit,LONG cb,LPVOID lpvBits); - WINGDIAPI WINBOOL WINAPI GetBitmapDimensionEx(HBITMAP hbit,LPSIZE lpsize); - WINGDIAPI UINT WINAPI GetBoundsRect(HDC hdc,LPRECT lprect,UINT flags); - WINGDIAPI WINBOOL WINAPI GetBrushOrgEx(HDC hdc,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI GetCharWidthA(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidthW(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidth32A(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidth32W(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidthFloatA(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharWidthFloatW(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsA(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsW(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatA(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatW(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); - WINGDIAPI int WINAPI GetClipBox(HDC hdc,LPRECT lprect); - WINGDIAPI int WINAPI GetClipRgn(HDC hdc,HRGN hrgn); - WINGDIAPI int WINAPI GetMetaRgn(HDC hdc,HRGN hrgn); - WINGDIAPI HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type); - WINGDIAPI WINBOOL WINAPI GetCurrentPositionEx(HDC hdc,LPPOINT lppt); - WINGDIAPI int WINAPI GetDeviceCaps(HDC hdc,int index); - WINGDIAPI int WINAPI GetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,LPVOID lpvBits,LPBITMAPINFO lpbmi,UINT usage); - WINGDIAPI DWORD WINAPI GetFontData (HDC hdc,DWORD dwTable,DWORD dwOffset,PVOID pvBuffer,DWORD cjBuffer); - WINGDIAPI DWORD WINAPI GetGlyphOutlineA(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); - WINGDIAPI DWORD WINAPI GetGlyphOutlineW(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); - WINGDIAPI int WINAPI GetGraphicsMode(HDC hdc); - WINGDIAPI int WINAPI GetMapMode(HDC hdc); - WINGDIAPI UINT WINAPI GetMetaFileBitsEx(HMETAFILE hMF,UINT cbBuffer,LPVOID lpData); - WINGDIAPI HMETAFILE WINAPI GetMetaFileA(LPCSTR lpName); - WINGDIAPI HMETAFILE WINAPI GetMetaFileW(LPCWSTR lpName); - WINGDIAPI COLORREF WINAPI GetNearestColor(HDC hdc,COLORREF color); - WINGDIAPI UINT WINAPI GetNearestPaletteIndex(HPALETTE h,COLORREF color); - WINGDIAPI DWORD WINAPI GetObjectType(HGDIOBJ h); - -#ifndef NOTEXTMETRIC -#ifdef UNICODE -#define GetOutlineTextMetrics GetOutlineTextMetricsW -#else -#define GetOutlineTextMetrics GetOutlineTextMetricsA -#endif - - WINGDIAPI UINT WINAPI GetOutlineTextMetricsA(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICA potm); - WINGDIAPI UINT WINAPI GetOutlineTextMetricsW(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICW potm); -#endif - -#ifdef UNICODE -#define GetTextExtentPoint GetTextExtentPointW -#define GetTextExtentPoint32 GetTextExtentPoint32W -#define GetTextExtentExPoint GetTextExtentExPointW -#define GetCharacterPlacement GetCharacterPlacementW -#else -#define GetTextExtentPoint GetTextExtentPointA -#define GetTextExtentPoint32 GetTextExtentPoint32A -#define GetTextExtentExPoint GetTextExtentExPointA -#define GetCharacterPlacement GetCharacterPlacementA -#endif - - WINGDIAPI UINT WINAPI GetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); - WINGDIAPI COLORREF WINAPI GetPixel(HDC hdc,int x,int y); - WINGDIAPI int WINAPI GetPixelFormat(HDC hdc); - WINGDIAPI int WINAPI GetPolyFillMode(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetRasterizerCaps(LPRASTERIZER_STATUS lpraststat,UINT cjBytes); - WINGDIAPI int WINAPI GetRandomRgn (HDC hdc,HRGN hrgn,INT i); - WINGDIAPI DWORD WINAPI GetRegionData(HRGN hrgn,DWORD nCount,LPRGNDATA lpRgnData); - WINGDIAPI int WINAPI GetRgnBox(HRGN hrgn,LPRECT lprc); - WINGDIAPI HGDIOBJ WINAPI GetStockObject(int i); - WINGDIAPI int WINAPI GetStretchBltMode(HDC hdc); - WINGDIAPI UINT WINAPI GetSystemPaletteEntries(HDC hdc,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); - WINGDIAPI UINT WINAPI GetSystemPaletteUse(HDC hdc); - WINGDIAPI int WINAPI GetTextCharacterExtra(HDC hdc); - WINGDIAPI UINT WINAPI GetTextAlign(HDC hdc); - WINGDIAPI COLORREF WINAPI GetTextColor(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetTextExtentPointA(HDC hdc,LPCSTR lpString,int c,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI GetTextExtentPointW(HDC hdc,LPCWSTR lpString,int c,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32A(HDC hdc,LPCSTR lpString,int c,LPSIZE psizl); - WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32W(HDC hdc,LPCWSTR lpString,int c,LPSIZE psizl); - WINGDIAPI WINBOOL WINAPI GetTextExtentExPointA(HDC hdc,LPCSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); - WINGDIAPI WINBOOL WINAPI GetTextExtentExPointW(HDC hdc,LPCWSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); - WINGDIAPI int WINAPI GetTextCharset(HDC hdc); - WINGDIAPI int WINAPI GetTextCharsetInfo(HDC hdc,LPFONTSIGNATURE lpSig,DWORD dwFlags); - WINGDIAPI WINBOOL WINAPI TranslateCharsetInfo(DWORD *lpSrc,LPCHARSETINFO lpCs,DWORD dwFlags); - WINGDIAPI DWORD WINAPI GetFontLanguageInfo(HDC hdc); - WINGDIAPI DWORD WINAPI GetCharacterPlacementA(HDC hdc,LPCSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSA lpResults,DWORD dwFlags); - WINGDIAPI DWORD WINAPI GetCharacterPlacementW(HDC hdc,LPCWSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSW lpResults,DWORD dwFlags); - - typedef struct tagWCRANGE { - WCHAR wcLow; - USHORT cGlyphs; - } WCRANGE,*PWCRANGE,*LPWCRANGE; - - typedef struct tagGLYPHSET { - DWORD cbThis; - DWORD flAccel; - DWORD cGlyphsSupported; - DWORD cRanges; - WCRANGE ranges[1]; - } GLYPHSET,*PGLYPHSET,*LPGLYPHSET; - -#define GS_8BIT_INDICES 0x00000001 - -#define GGI_MARK_NONEXISTING_GLYPHS 0X0001 - -#ifdef UNICODE -#define GetGlyphIndices GetGlyphIndicesW -#else -#define GetGlyphIndices GetGlyphIndicesA -#endif - - WINGDIAPI DWORD WINAPI GetFontUnicodeRanges(HDC hdc,LPGLYPHSET lpgs); - WINGDIAPI DWORD WINAPI GetGlyphIndicesA(HDC hdc,LPCSTR lpstr,int c,LPWORD pgi,DWORD fl); - WINGDIAPI DWORD WINAPI GetGlyphIndicesW(HDC hdc,LPCWSTR lpstr,int c,LPWORD pgi,DWORD fl); - WINGDIAPI WINBOOL WINAPI GetTextExtentPointI(HDC hdc,LPWORD pgiIn,int cgi,LPSIZE psize); - WINGDIAPI WINBOOL WINAPI GetTextExtentExPointI (HDC hdc,LPWORD lpwszString,int cwchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); - WINGDIAPI WINBOOL WINAPI GetCharWidthI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPINT piWidths); - WINGDIAPI WINBOOL WINAPI GetCharABCWidthsI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPABC pabc); - -#define STAMP_DESIGNVECTOR (0x8000000 + 'd' + ('v' << 8)) -#define STAMP_AXESLIST (0x8000000 + 'a' + ('l' << 8)) -#define MM_MAX_NUMAXES 16 - - typedef struct tagDESIGNVECTOR { - DWORD dvReserved; - DWORD dvNumAxes; - LONG dvValues[MM_MAX_NUMAXES]; - } DESIGNVECTOR,*PDESIGNVECTOR,*LPDESIGNVECTOR; - -#ifdef UNICODE -#define AddFontResourceEx AddFontResourceExW -#define RemoveFontResourceEx RemoveFontResourceExW -#else -#define AddFontResourceEx AddFontResourceExA -#define RemoveFontResourceEx RemoveFontResourceExA -#endif - - WINGDIAPI int WINAPI AddFontResourceExA(LPCSTR name,DWORD fl,PVOID res); - WINGDIAPI int WINAPI AddFontResourceExW(LPCWSTR name,DWORD fl,PVOID res); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceExA(LPCSTR name,DWORD fl,PVOID pdv); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceExW(LPCWSTR name,DWORD fl,PVOID pdv); - WINGDIAPI HANDLE WINAPI AddFontMemResourceEx(PVOID pFileView,DWORD cjSize,PVOID pvResrved,DWORD *pNumFonts); - WINGDIAPI WINBOOL WINAPI RemoveFontMemResourceEx(HANDLE h); - -#define FR_PRIVATE 0x10 -#define FR_NOT_ENUM 0x20 - -#define MM_MAX_AXES_NAMELEN 16 - - typedef struct tagAXISINFOA { - LONG axMinValue; - LONG axMaxValue; - BYTE axAxisName[MM_MAX_AXES_NAMELEN]; - } AXISINFOA,*PAXISINFOA,*LPAXISINFOA; - - typedef struct tagAXISINFOW { - LONG axMinValue; - LONG axMaxValue; - WCHAR axAxisName[MM_MAX_AXES_NAMELEN]; - } AXISINFOW,*PAXISINFOW,*LPAXISINFOW; -#ifdef UNICODE - typedef AXISINFOW AXISINFO; - typedef PAXISINFOW PAXISINFO; - typedef LPAXISINFOW LPAXISINFO; -#else - typedef AXISINFOA AXISINFO; - typedef PAXISINFOA PAXISINFO; - typedef LPAXISINFOA LPAXISINFO; -#endif - - typedef struct tagAXESLISTA { - DWORD axlReserved; - DWORD axlNumAxes; - AXISINFOA axlAxisInfo[MM_MAX_NUMAXES]; - } AXESLISTA,*PAXESLISTA,*LPAXESLISTA; - - typedef struct tagAXESLISTW { - DWORD axlReserved; - DWORD axlNumAxes; - AXISINFOW axlAxisInfo[MM_MAX_NUMAXES]; - } AXESLISTW,*PAXESLISTW,*LPAXESLISTW; -#ifdef UNICODE - typedef AXESLISTW AXESLIST; - typedef PAXESLISTW PAXESLIST; - typedef LPAXESLISTW LPAXESLIST; -#else - typedef AXESLISTA AXESLIST; - typedef PAXESLISTA PAXESLIST; - typedef LPAXESLISTA LPAXESLIST; -#endif - - typedef struct tagENUMLOGFONTEXDVA { - ENUMLOGFONTEXA elfEnumLogfontEx; - DESIGNVECTOR elfDesignVector; - } ENUMLOGFONTEXDVA,*PENUMLOGFONTEXDVA,*LPENUMLOGFONTEXDVA; - - typedef struct tagENUMLOGFONTEXDVW { - ENUMLOGFONTEXW elfEnumLogfontEx; - DESIGNVECTOR elfDesignVector; - } ENUMLOGFONTEXDVW,*PENUMLOGFONTEXDVW,*LPENUMLOGFONTEXDVW; -#ifdef UNICODE - typedef ENUMLOGFONTEXDVW ENUMLOGFONTEXDV; - typedef PENUMLOGFONTEXDVW PENUMLOGFONTEXDV; - typedef LPENUMLOGFONTEXDVW LPENUMLOGFONTEXDV; -#else - typedef ENUMLOGFONTEXDVA ENUMLOGFONTEXDV; - typedef PENUMLOGFONTEXDVA PENUMLOGFONTEXDV; - typedef LPENUMLOGFONTEXDVA LPENUMLOGFONTEXDV; -#endif - -#ifdef UNICODE -#define CreateFontIndirectEx CreateFontIndirectExW -#else -#define CreateFontIndirectEx CreateFontIndirectExA -#endif - - WINGDIAPI HFONT WINAPI CreateFontIndirectExA(CONST ENUMLOGFONTEXDVA *); - WINGDIAPI HFONT WINAPI CreateFontIndirectExW(CONST ENUMLOGFONTEXDVW *); - -#ifndef NOTEXTMETRIC - typedef struct tagENUMTEXTMETRICA { - NEWTEXTMETRICEXA etmNewTextMetricEx; - AXESLISTA etmAxesList; - } ENUMTEXTMETRICA,*PENUMTEXTMETRICA,*LPENUMTEXTMETRICA; - typedef struct tagENUMTEXTMETRICW - { - NEWTEXTMETRICEXW etmNewTextMetricEx; - AXESLISTW etmAxesList; - } ENUMTEXTMETRICW,*PENUMTEXTMETRICW,*LPENUMTEXTMETRICW; -#ifdef UNICODE - typedef ENUMTEXTMETRICW ENUMTEXTMETRIC; - typedef PENUMTEXTMETRICW PENUMTEXTMETRIC; - typedef LPENUMTEXTMETRICW LPENUMTEXTMETRIC; -#else - typedef ENUMTEXTMETRICA ENUMTEXTMETRIC; - typedef PENUMTEXTMETRICA PENUMTEXTMETRIC; - typedef LPENUMTEXTMETRICA LPENUMTEXTMETRIC; -#endif -#endif - -#ifdef UNICODE -#define ResetDC ResetDCW -#define RemoveFontResource RemoveFontResourceW -#else -#define ResetDC ResetDCA -#define RemoveFontResource RemoveFontResourceA -#endif - - WINGDIAPI WINBOOL WINAPI GetViewportExtEx(HDC hdc,LPSIZE lpsize); - WINGDIAPI WINBOOL WINAPI GetViewportOrgEx(HDC hdc,LPPOINT lppoint); - WINGDIAPI WINBOOL WINAPI GetWindowExtEx(HDC hdc,LPSIZE lpsize); - WINGDIAPI WINBOOL WINAPI GetWindowOrgEx(HDC hdc,LPPOINT lppoint); - WINGDIAPI int WINAPI IntersectClipRect(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI WINBOOL WINAPI InvertRgn(HDC hdc,HRGN hrgn); - WINGDIAPI WINBOOL WINAPI LineDDA(int xStart,int yStart,int xEnd,int yEnd,LINEDDAPROC lpProc,LPARAM data); - WINGDIAPI WINBOOL WINAPI LineTo(HDC hdc,int x,int y); - WINGDIAPI WINBOOL WINAPI MaskBlt(HDC hdcDest,int xDest,int yDest,int width,int height,HDC hdcSrc,int xSrc,int ySrc,HBITMAP hbmMask,int xMask,int yMask,DWORD rop); - WINGDIAPI WINBOOL WINAPI PlgBlt(HDC hdcDest,CONST POINT *lpPoint,HDC hdcSrc,int xSrc,int ySrc,int width,int height,HBITMAP hbmMask,int xMask,int yMask); - WINGDIAPI int WINAPI OffsetClipRgn(HDC hdc,int x,int y); - WINGDIAPI int WINAPI OffsetRgn(HRGN hrgn,int x,int y); - WINGDIAPI WINBOOL WINAPI PatBlt(HDC hdc,int x,int y,int w,int h,DWORD rop); - WINGDIAPI WINBOOL WINAPI Pie(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); - WINGDIAPI WINBOOL WINAPI PlayMetaFile(HDC hdc,HMETAFILE hmf); - WINGDIAPI WINBOOL WINAPI PaintRgn(HDC hdc,HRGN hrgn); - WINGDIAPI WINBOOL WINAPI PolyPolygon(HDC hdc,CONST POINT *apt,CONST INT *asz,int csz); - WINGDIAPI WINBOOL WINAPI PtInRegion(HRGN hrgn,int x,int y); - WINGDIAPI WINBOOL WINAPI PtVisible(HDC hdc,int x,int y); - WINGDIAPI WINBOOL WINAPI RectInRegion(HRGN hrgn,CONST RECT *lprect); - WINGDIAPI WINBOOL WINAPI RectVisible(HDC hdc,CONST RECT *lprect); - WINGDIAPI WINBOOL WINAPI Rectangle(HDC hdc,int left,int top,int right,int bottom); - WINGDIAPI WINBOOL WINAPI RestoreDC(HDC hdc,int nSavedDC); - WINGDIAPI HDC WINAPI ResetDCA(HDC hdc,CONST DEVMODEA *lpdm); - WINGDIAPI HDC WINAPI ResetDCW(HDC hdc,CONST DEVMODEW *lpdm); - WINGDIAPI UINT WINAPI RealizePalette(HDC hdc); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceA(LPCSTR lpFileName); - WINGDIAPI WINBOOL WINAPI RemoveFontResourceW(LPCWSTR lpFileName); - WINGDIAPI WINBOOL WINAPI RoundRect(HDC hdc,int left,int top,int right,int bottom,int width,int height); - WINGDIAPI WINBOOL WINAPI ResizePalette(HPALETTE hpal,UINT n); - WINGDIAPI int WINAPI SaveDC(HDC hdc); - WINGDIAPI int WINAPI SelectClipRgn(HDC hdc,HRGN hrgn); - WINGDIAPI int WINAPI ExtSelectClipRgn(HDC hdc,HRGN hrgn,int mode); - WINGDIAPI int WINAPI SetMetaRgn(HDC hdc); - WINGDIAPI HGDIOBJ WINAPI SelectObject(HDC hdc,HGDIOBJ h); - WINGDIAPI HPALETTE WINAPI SelectPalette(HDC hdc,HPALETTE hPal,WINBOOL bForceBkgd); - WINGDIAPI COLORREF WINAPI SetBkColor(HDC hdc,COLORREF color); - WINGDIAPI COLORREF WINAPI SetDCBrushColor(HDC hdc,COLORREF color); - WINGDIAPI COLORREF WINAPI SetDCPenColor(HDC hdc,COLORREF color); - WINGDIAPI int WINAPI SetBkMode(HDC hdc,int mode); - WINGDIAPI LONG WINAPI SetBitmapBits(HBITMAP hbm,DWORD cb,CONST VOID *pvBits); - WINGDIAPI UINT WINAPI SetBoundsRect(HDC hdc,CONST RECT *lprect,UINT flags); - WINGDIAPI int WINAPI SetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); - WINGDIAPI int WINAPI SetDIBitsToDevice(HDC hdc,int xDest,int yDest,DWORD w,DWORD h,int xSrc,int ySrc,UINT StartScan,UINT cLines,CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); - WINGDIAPI DWORD WINAPI SetMapperFlags(HDC hdc,DWORD flags); - WINGDIAPI int WINAPI SetGraphicsMode(HDC hdc,int iMode); - WINGDIAPI int WINAPI SetMapMode(HDC hdc,int iMode); - WINGDIAPI DWORD WINAPI SetLayout(HDC hdc,DWORD l); - WINGDIAPI DWORD WINAPI GetLayout(HDC hdc); - WINGDIAPI HMETAFILE WINAPI SetMetaFileBitsEx(UINT cbBuffer,CONST BYTE *lpData); - WINGDIAPI UINT WINAPI SetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,CONST PALETTEENTRY *pPalEntries); - WINGDIAPI COLORREF WINAPI SetPixel(HDC hdc,int x,int y,COLORREF color); - WINGDIAPI WINBOOL WINAPI SetPixelV(HDC hdc,int x,int y,COLORREF color); - WINGDIAPI WINBOOL WINAPI SetPixelFormat(HDC hdc,int format,CONST PIXELFORMATDESCRIPTOR *ppfd); - WINGDIAPI int WINAPI SetPolyFillMode(HDC hdc,int mode); - WINGDIAPI WINBOOL WINAPI StretchBlt(HDC hdcDest,int xDest,int yDest,int wDest,int hDest,HDC hdcSrc,int xSrc,int ySrc,int wSrc,int hSrc,DWORD rop); - WINGDIAPI WINBOOL WINAPI SetRectRgn(HRGN hrgn,int left,int top,int right,int bottom); - WINGDIAPI int WINAPI StretchDIBits(HDC hdc,int xDest,int yDest,int DestWidth,int DestHeight,int xSrc,int ySrc,int SrcWidth,int SrcHeight,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT iUsage,DWORD rop); - WINGDIAPI int WINAPI SetROP2(HDC hdc,int rop2); - WINGDIAPI int WINAPI SetStretchBltMode(HDC hdc,int mode); - WINGDIAPI UINT WINAPI SetSystemPaletteUse(HDC hdc,UINT use); - WINGDIAPI int WINAPI SetTextCharacterExtra(HDC hdc,int extra); - WINGDIAPI COLORREF WINAPI SetTextColor(HDC hdc,COLORREF color); - WINGDIAPI UINT WINAPI SetTextAlign(HDC hdc,UINT align); - WINGDIAPI WINBOOL WINAPI SetTextJustification(HDC hdc,int extra,int count); - WINGDIAPI WINBOOL WINAPI UpdateColors(HDC hdc); - - typedef USHORT COLOR16; - - typedef struct _TRIVERTEX { - LONG x; - LONG y; - COLOR16 Red; - COLOR16 Green; - COLOR16 Blue; - COLOR16 Alpha; - } TRIVERTEX,*PTRIVERTEX,*LPTRIVERTEX; - - typedef struct _GRADIENT_TRIANGLE { - ULONG Vertex1; - ULONG Vertex2; - ULONG Vertex3; - } GRADIENT_TRIANGLE,*PGRADIENT_TRIANGLE,*LPGRADIENT_TRIANGLE; - - typedef struct _GRADIENT_RECT { - ULONG UpperLeft; - ULONG LowerRight; - } GRADIENT_RECT,*PGRADIENT_RECT,*LPGRADIENT_RECT; - - typedef struct _BLENDFUNCTION { - BYTE BlendOp; - BYTE BlendFlags; - BYTE SourceConstantAlpha; - BYTE AlphaFormat; - } BLENDFUNCTION,*PBLENDFUNCTION; - -#define AC_SRC_OVER 0x00 -#define AC_SRC_ALPHA 0x01 - - WINGDIAPI WINBOOL WINAPI AlphaBlend(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,BLENDFUNCTION ftn); - WINGDIAPI WINBOOL WINAPI TransparentBlt(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,UINT crTransparent); - -#define GRADIENT_FILL_RECT_H 0x00000000 -#define GRADIENT_FILL_RECT_V 0x00000001 -#define GRADIENT_FILL_TRIANGLE 0x00000002 -#define GRADIENT_FILL_OP_FLAG 0x000000ff - - WINGDIAPI WINBOOL WINAPI GradientFill(HDC hdc,PTRIVERTEX pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,ULONG ulMode); - -#ifndef NOMETAFILE - -#ifdef UNICODE -#define CopyEnhMetaFile CopyEnhMetaFileW -#define CreateEnhMetaFile CreateEnhMetaFileW -#define GetEnhMetaFile GetEnhMetaFileW -#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionW -#else -#define CopyEnhMetaFile CopyEnhMetaFileA -#define CreateEnhMetaFile CreateEnhMetaFileA -#define GetEnhMetaFile GetEnhMetaFileA -#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionA -#endif - - WINGDIAPI WINBOOL WINAPI PlayMetaFileRecord(HDC hdc,LPHANDLETABLE lpHandleTable,LPMETARECORD lpMR,UINT noObjs); - - typedef int (CALLBACK *MFENUMPROC)(HDC hdc,HANDLETABLE *lpht,METARECORD *lpMR,int nObj,LPARAM param); - - WINGDIAPI WINBOOL WINAPI EnumMetaFile(HDC hdc,HMETAFILE hmf,MFENUMPROC proc,LPARAM param); - - typedef int (CALLBACK *ENHMFENUMPROC)(HDC hdc,HANDLETABLE *lpht,CONST ENHMETARECORD *lpmr,int hHandles,LPARAM data); - - WINGDIAPI HENHMETAFILE WINAPI CloseEnhMetaFile(HDC hdc); - WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileA(HENHMETAFILE hEnh,LPCSTR lpFileName); - WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileW(HENHMETAFILE hEnh,LPCWSTR lpFileName); - WINGDIAPI HDC WINAPI CreateEnhMetaFileA(HDC hdc,LPCSTR lpFilename,CONST RECT *lprc,LPCSTR lpDesc); - WINGDIAPI HDC WINAPI CreateEnhMetaFileW(HDC hdc,LPCWSTR lpFilename,CONST RECT *lprc,LPCWSTR lpDesc); - WINGDIAPI WINBOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf); - WINGDIAPI WINBOOL WINAPI EnumEnhMetaFile(HDC hdc,HENHMETAFILE hmf,ENHMFENUMPROC proc,LPVOID param,CONST RECT *lpRect); - WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileA(LPCSTR lpName); - WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileW(LPCWSTR lpName); - WINGDIAPI UINT WINAPI GetEnhMetaFileBits(HENHMETAFILE hEMF,UINT nSize,LPBYTE lpData); - WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionA(HENHMETAFILE hemf,UINT cchBuffer,LPSTR lpDescription); - WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionW(HENHMETAFILE hemf,UINT cchBuffer,LPWSTR lpDescription); - WINGDIAPI UINT WINAPI GetEnhMetaFileHeader(HENHMETAFILE hemf,UINT nSize,LPENHMETAHEADER lpEnhMetaHeader); - WINGDIAPI UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf,UINT nNumEntries,LPPALETTEENTRY lpPaletteEntries); - WINGDIAPI UINT WINAPI GetEnhMetaFilePixelFormat(HENHMETAFILE hemf,UINT cbBuffer,PIXELFORMATDESCRIPTOR *ppfd); - WINGDIAPI UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,UINT cbData16,LPBYTE pData16,INT iMapMode,HDC hdcRef); - WINGDIAPI WINBOOL WINAPI PlayEnhMetaFile(HDC hdc,HENHMETAFILE hmf,CONST RECT *lprect); - WINGDIAPI WINBOOL WINAPI PlayEnhMetaFileRecord(HDC hdc,LPHANDLETABLE pht,CONST ENHMETARECORD *pmr,UINT cht); - WINGDIAPI HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT nSize,CONST BYTE *pb); - WINGDIAPI HENHMETAFILE WINAPI SetWinMetaFileBits(UINT nSize,CONST BYTE *lpMeta16Data,HDC hdcRef,CONST METAFILEPICT *lpMFP); - WINGDIAPI WINBOOL WINAPI GdiComment(HDC hdc,UINT nSize,CONST BYTE *lpData); -#endif - -#ifndef NOTEXTMETRIC -#ifdef UNICODE -#define GetTextMetrics GetTextMetricsW -#else -#define GetTextMetrics GetTextMetricsA -#endif - - WINGDIAPI WINBOOL WINAPI GetTextMetricsA(HDC hdc,LPTEXTMETRICA lptm); - WINGDIAPI WINBOOL WINAPI GetTextMetricsW(HDC hdc,LPTEXTMETRICW lptm); -#endif - - typedef struct tagDIBSECTION { - BITMAP dsBm; - BITMAPINFOHEADER dsBmih; - DWORD dsBitfields[3]; - HANDLE dshSection; - DWORD dsOffset; - } DIBSECTION,*LPDIBSECTION,*PDIBSECTION; - - WINGDIAPI WINBOOL WINAPI AngleArc(HDC hdc,int x,int y,DWORD r,FLOAT StartAngle,FLOAT SweepAngle); - WINGDIAPI WINBOOL WINAPI PolyPolyline(HDC hdc,CONST POINT *apt,CONST DWORD *asz,DWORD csz); - WINGDIAPI WINBOOL WINAPI GetWorldTransform(HDC hdc,LPXFORM lpxf); - WINGDIAPI WINBOOL WINAPI SetWorldTransform(HDC hdc,CONST XFORM *lpxf); - WINGDIAPI WINBOOL WINAPI ModifyWorldTransform(HDC hdc,CONST XFORM *lpxf,DWORD mode); - WINGDIAPI WINBOOL WINAPI CombineTransform(LPXFORM lpxfOut,CONST XFORM *lpxf1,CONST XFORM *lpxf2); - WINGDIAPI HBITMAP WINAPI CreateDIBSection(HDC hdc,CONST BITMAPINFO *lpbmi,UINT usage,VOID **ppvBits,HANDLE hSection,DWORD offset); - WINGDIAPI UINT WINAPI GetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,RGBQUAD *prgbq); - WINGDIAPI UINT WINAPI SetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,CONST RGBQUAD *prgbq); - -#define CA_NEGATIVE 0x0001 -#define CA_LOG_FILTER 0x0002 - -#define ILLUMINANT_DEVICE_DEFAULT 0 -#define ILLUMINANT_A 1 -#define ILLUMINANT_B 2 -#define ILLUMINANT_C 3 -#define ILLUMINANT_D50 4 -#define ILLUMINANT_D55 5 -#define ILLUMINANT_D65 6 -#define ILLUMINANT_D75 7 -#define ILLUMINANT_F2 8 -#define ILLUMINANT_MAX_INDEX ILLUMINANT_F2 - -#define ILLUMINANT_TUNGSTEN ILLUMINANT_A -#define ILLUMINANT_DAYLIGHT ILLUMINANT_C -#define ILLUMINANT_FLUORESCENT ILLUMINANT_F2 -#define ILLUMINANT_NTSC ILLUMINANT_C - -#define RGB_GAMMA_MIN (WORD)02500 -#define RGB_GAMMA_MAX (WORD)65000 - -#define REFERENCE_WHITE_MIN (WORD)6000 -#define REFERENCE_WHITE_MAX (WORD)10000 -#define REFERENCE_BLACK_MIN (WORD)0 -#define REFERENCE_BLACK_MAX (WORD)4000 - -#define COLOR_ADJ_MIN (SHORT)-100 -#define COLOR_ADJ_MAX (SHORT)100 - - typedef struct tagCOLORADJUSTMENT { - WORD caSize; - WORD caFlags; - WORD caIlluminantIndex; - WORD caRedGamma; - WORD caGreenGamma; - WORD caBlueGamma; - WORD caReferenceBlack; - WORD caReferenceWhite; - SHORT caContrast; - SHORT caBrightness; - SHORT caColorfulness; - SHORT caRedGreenTint; - } COLORADJUSTMENT,*PCOLORADJUSTMENT,*LPCOLORADJUSTMENT; - - WINGDIAPI WINBOOL WINAPI SetColorAdjustment(HDC hdc,CONST COLORADJUSTMENT *lpca); - WINGDIAPI WINBOOL WINAPI GetColorAdjustment(HDC hdc,LPCOLORADJUSTMENT lpca); - WINGDIAPI HPALETTE WINAPI CreateHalftonePalette(HDC hdc); - - typedef WINBOOL (CALLBACK *ABORTPROC)(HDC,int); - - typedef struct _DOCINFOA { - int cbSize; - LPCSTR lpszDocName; - LPCSTR lpszOutput; - LPCSTR lpszDatatype; - DWORD fwType; - } DOCINFOA,*LPDOCINFOA; - - typedef struct _DOCINFOW { - int cbSize; - LPCWSTR lpszDocName; - LPCWSTR lpszOutput; - LPCWSTR lpszDatatype; - DWORD fwType; - } DOCINFOW,*LPDOCINFOW; - -#ifdef UNICODE - typedef DOCINFOW DOCINFO; - typedef LPDOCINFOW LPDOCINFO; -#else - typedef DOCINFOA DOCINFO; - typedef LPDOCINFOA LPDOCINFO; -#endif - -#define DI_APPBANDING 0x00000001 -#define DI_ROPS_READ_DESTINATION 0x00000002 - -#ifdef UNICODE -#define StartDoc StartDocW -#define GetObject GetObjectW -#define TextOut TextOutW -#define ExtTextOut ExtTextOutW -#define PolyTextOut PolyTextOutW -#define GetTextFace GetTextFaceW -#else -#define StartDoc StartDocA -#define GetObject GetObjectA -#define TextOut TextOutA -#define ExtTextOut ExtTextOutA -#define PolyTextOut PolyTextOutA -#define GetTextFace GetTextFaceA -#endif - - WINGDIAPI int WINAPI StartDocA(HDC hdc,CONST DOCINFOA *lpdi); - WINGDIAPI int WINAPI StartDocW(HDC hdc,CONST DOCINFOW *lpdi); - WINGDIAPI int WINAPI EndDoc(HDC hdc); - WINGDIAPI int WINAPI StartPage(HDC hdc); - WINGDIAPI int WINAPI EndPage(HDC hdc); - WINGDIAPI int WINAPI AbortDoc(HDC hdc); - WINGDIAPI int WINAPI SetAbortProc(HDC hdc,ABORTPROC proc); - WINGDIAPI WINBOOL WINAPI AbortPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI ArcTo(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); - WINGDIAPI WINBOOL WINAPI BeginPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI CloseFigure(HDC hdc); - WINGDIAPI WINBOOL WINAPI EndPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI FillPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI FlattenPath(HDC hdc); - WINGDIAPI int WINAPI GetPath(HDC hdc,LPPOINT apt,LPBYTE aj,int cpt); - WINGDIAPI HRGN WINAPI PathToRegion(HDC hdc); - WINGDIAPI WINBOOL WINAPI PolyDraw(HDC hdc,CONST POINT *apt,CONST BYTE *aj,int cpt); - WINGDIAPI WINBOOL WINAPI SelectClipPath(HDC hdc,int mode); - WINGDIAPI int WINAPI SetArcDirection(HDC hdc,int dir); - WINGDIAPI WINBOOL WINAPI SetMiterLimit(HDC hdc,FLOAT limit,PFLOAT old); - WINGDIAPI WINBOOL WINAPI StrokeAndFillPath(HDC hdc); - WINGDIAPI WINBOOL WINAPI StrokePath(HDC hdc); - WINGDIAPI WINBOOL WINAPI WidenPath(HDC hdc); - WINGDIAPI HPEN WINAPI ExtCreatePen(DWORD iPenStyle,DWORD cWidth,CONST LOGBRUSH *plbrush,DWORD cStyle,CONST DWORD *pstyle); - WINGDIAPI WINBOOL WINAPI GetMiterLimit(HDC hdc,PFLOAT plimit); - WINGDIAPI int WINAPI GetArcDirection(HDC hdc); - WINGDIAPI int WINAPI GetObjectA(HANDLE h,int c,LPVOID pv); - WINGDIAPI int WINAPI GetObjectW(HANDLE h,int c,LPVOID pv); - WINGDIAPI WINBOOL WINAPI MoveToEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI TextOutA(HDC hdc,int x,int y,LPCSTR lpString,int c); - WINGDIAPI WINBOOL WINAPI TextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int c); - WINGDIAPI WINBOOL WINAPI ExtTextOutA(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCSTR lpString,UINT c,CONST INT *lpDx); - WINGDIAPI WINBOOL WINAPI ExtTextOutW(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCWSTR lpString,UINT c,CONST INT *lpDx); - WINGDIAPI WINBOOL WINAPI PolyTextOutA(HDC hdc,CONST POLYTEXTA *ppt,int nstrings); - WINGDIAPI WINBOOL WINAPI PolyTextOutW(HDC hdc,CONST POLYTEXTW *ppt,int nstrings); - WINGDIAPI HRGN WINAPI CreatePolygonRgn(CONST POINT *pptl,int cPoint,int iMode); - WINGDIAPI WINBOOL WINAPI DPtoLP(HDC hdc,LPPOINT lppt,int c); - WINGDIAPI WINBOOL WINAPI LPtoDP(HDC hdc,LPPOINT lppt,int c); - WINGDIAPI WINBOOL WINAPI Polygon(HDC hdc,CONST POINT *apt,int cpt); - WINGDIAPI WINBOOL WINAPI Polyline(HDC hdc,CONST POINT *apt,int cpt); - WINGDIAPI WINBOOL WINAPI PolyBezier(HDC hdc,CONST POINT *apt,DWORD cpt); - WINGDIAPI WINBOOL WINAPI PolyBezierTo(HDC hdc,CONST POINT *apt,DWORD cpt); - WINGDIAPI WINBOOL WINAPI PolylineTo(HDC hdc,CONST POINT *apt,DWORD cpt); - WINGDIAPI WINBOOL WINAPI SetViewportExtEx(HDC hdc,int x,int y,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI SetWindowExtEx(HDC hdc,int x,int y,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI OffsetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI OffsetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI ScaleViewportExtEx(HDC hdc,int xn,int dx,int yn,int yd,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI ScaleWindowExtEx(HDC hdc,int xn,int xd,int yn,int yd,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetBitmapDimensionEx(HBITMAP hbm,int w,int h,LPSIZE lpsz); - WINGDIAPI WINBOOL WINAPI SetBrushOrgEx(HDC hdc,int x,int y,LPPOINT lppt); - WINGDIAPI int WINAPI GetTextFaceA(HDC hdc,int c,LPSTR lpName); - WINGDIAPI int WINAPI GetTextFaceW(HDC hdc,int c,LPWSTR lpName); - -#define FONTMAPPER_MAX 10 - - typedef struct tagKERNINGPAIR { - WORD wFirst; - WORD wSecond; - int iKernAmount; - } KERNINGPAIR,*LPKERNINGPAIR; - -#ifdef UNICODE -#define GetKerningPairs GetKerningPairsW -#else -#define GetKerningPairs GetKerningPairsA -#endif - - WINGDIAPI DWORD WINAPI GetKerningPairsA(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); - WINGDIAPI DWORD WINAPI GetKerningPairsW(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); - WINGDIAPI WINBOOL WINAPI GetDCOrgEx(HDC hdc,LPPOINT lppt); - WINGDIAPI WINBOOL WINAPI FixBrushOrgEx(HDC hdc,int x,int y,LPPOINT ptl); - WINGDIAPI WINBOOL WINAPI UnrealizeObject(HGDIOBJ h); - WINGDIAPI WINBOOL WINAPI GdiFlush(); - WINGDIAPI DWORD WINAPI GdiSetBatchLimit(DWORD dw); - WINGDIAPI DWORD WINAPI GdiGetBatchLimit(); - -#define ICM_OFF 1 -#define ICM_ON 2 -#define ICM_QUERY 3 -#define ICM_DONE_OUTSIDEDC 4 - - typedef int (CALLBACK *ICMENUMPROCA)(LPSTR,LPARAM); - typedef int (CALLBACK *ICMENUMPROCW)(LPWSTR,LPARAM); - -#ifdef UNICODE -#define ICMENUMPROC ICMENUMPROCW -#define EnumICMProfiles EnumICMProfilesW -#define UpdateICMRegKey UpdateICMRegKeyW -#define GetLogColorSpace GetLogColorSpaceW -#define CreateColorSpace CreateColorSpaceW -#define GetICMProfile GetICMProfileW -#define SetICMProfile SetICMProfileW -#else -#define ICMENUMPROC ICMENUMPROCA -#define EnumICMProfiles EnumICMProfilesA -#define UpdateICMRegKey UpdateICMRegKeyA -#define GetLogColorSpace GetLogColorSpaceA -#define CreateColorSpace CreateColorSpaceA -#define GetICMProfile GetICMProfileA -#define SetICMProfile SetICMProfileA -#endif - - WINGDIAPI int WINAPI SetICMMode(HDC hdc,int mode); - WINGDIAPI WINBOOL WINAPI CheckColorsInGamut(HDC hdc,LPVOID lpRGBTriple,LPVOID dlpBuffer,DWORD nCount); - WINGDIAPI HCOLORSPACE WINAPI GetColorSpace(HDC hdc); - WINGDIAPI WINBOOL WINAPI GetLogColorSpaceA(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEA lpBuffer,DWORD nSize); - WINGDIAPI WINBOOL WINAPI GetLogColorSpaceW(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEW lpBuffer,DWORD nSize); - WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceA(LPLOGCOLORSPACEA lplcs); - WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceW(LPLOGCOLORSPACEW lplcs); - WINGDIAPI HCOLORSPACE WINAPI SetColorSpace(HDC hdc,HCOLORSPACE hcs); - WINGDIAPI WINBOOL WINAPI DeleteColorSpace(HCOLORSPACE hcs); - WINGDIAPI WINBOOL WINAPI GetICMProfileA(HDC hdc,LPDWORD pBufSize,LPSTR pszFilename); - WINGDIAPI WINBOOL WINAPI GetICMProfileW(HDC hdc,LPDWORD pBufSize,LPWSTR pszFilename); - WINGDIAPI WINBOOL WINAPI SetICMProfileA(HDC hdc,LPSTR lpFileName); - WINGDIAPI WINBOOL WINAPI SetICMProfileW(HDC hdc,LPWSTR lpFileName); - WINGDIAPI WINBOOL WINAPI GetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); - WINGDIAPI WINBOOL WINAPI SetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); - WINGDIAPI WINBOOL WINAPI ColorMatchToTarget(HDC hdc,HDC hdcTarget,DWORD action); - WINGDIAPI int WINAPI EnumICMProfilesA(HDC hdc,ICMENUMPROCA proc,LPARAM param); - WINGDIAPI int WINAPI EnumICMProfilesW(HDC hdc,ICMENUMPROCW proc,LPARAM param); - WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyA(DWORD reserved,LPSTR lpszCMID,LPSTR lpszFileName,UINT command); - WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyW(DWORD reserved,LPWSTR lpszCMID,LPWSTR lpszFileName,UINT command); - WINGDIAPI WINBOOL WINAPI ColorCorrectPalette(HDC hdc,HPALETTE hPal,DWORD deFirst,DWORD num); - -#ifndef NOMETAFILE - -#define ENHMETA_SIGNATURE 0x464D4520 -#define ENHMETA_STOCK_OBJECT 0x80000000 - -#define EMR_HEADER 1 -#define EMR_POLYBEZIER 2 -#define EMR_POLYGON 3 -#define EMR_POLYLINE 4 -#define EMR_POLYBEZIERTO 5 -#define EMR_POLYLINETO 6 -#define EMR_POLYPOLYLINE 7 -#define EMR_POLYPOLYGON 8 -#define EMR_SETWINDOWEXTEX 9 -#define EMR_SETWINDOWORGEX 10 -#define EMR_SETVIEWPORTEXTEX 11 -#define EMR_SETVIEWPORTORGEX 12 -#define EMR_SETBRUSHORGEX 13 -#define EMR_EOF 14 -#define EMR_SETPIXELV 15 -#define EMR_SETMAPPERFLAGS 16 -#define EMR_SETMAPMODE 17 -#define EMR_SETBKMODE 18 -#define EMR_SETPOLYFILLMODE 19 -#define EMR_SETROP2 20 -#define EMR_SETSTRETCHBLTMODE 21 -#define EMR_SETTEXTALIGN 22 -#define EMR_SETCOLORADJUSTMENT 23 -#define EMR_SETTEXTCOLOR 24 -#define EMR_SETBKCOLOR 25 -#define EMR_OFFSETCLIPRGN 26 -#define EMR_MOVETOEX 27 -#define EMR_SETMETARGN 28 -#define EMR_EXCLUDECLIPRECT 29 -#define EMR_INTERSECTCLIPRECT 30 -#define EMR_SCALEVIEWPORTEXTEX 31 -#define EMR_SCALEWINDOWEXTEX 32 -#define EMR_SAVEDC 33 -#define EMR_RESTOREDC 34 -#define EMR_SETWORLDTRANSFORM 35 -#define EMR_MODIFYWORLDTRANSFORM 36 -#define EMR_SELECTOBJECT 37 -#define EMR_CREATEPEN 38 -#define EMR_CREATEBRUSHINDIRECT 39 -#define EMR_DELETEOBJECT 40 -#define EMR_ANGLEARC 41 -#define EMR_ELLIPSE 42 -#define EMR_RECTANGLE 43 -#define EMR_ROUNDRECT 44 -#define EMR_ARC 45 -#define EMR_CHORD 46 -#define EMR_PIE 47 -#define EMR_SELECTPALETTE 48 -#define EMR_CREATEPALETTE 49 -#define EMR_SETPALETTEENTRIES 50 -#define EMR_RESIZEPALETTE 51 -#define EMR_REALIZEPALETTE 52 -#define EMR_EXTFLOODFILL 53 -#define EMR_LINETO 54 -#define EMR_ARCTO 55 -#define EMR_POLYDRAW 56 -#define EMR_SETARCDIRECTION 57 -#define EMR_SETMITERLIMIT 58 -#define EMR_BEGINPATH 59 -#define EMR_ENDPATH 60 -#define EMR_CLOSEFIGURE 61 -#define EMR_FILLPATH 62 -#define EMR_STROKEANDFILLPATH 63 -#define EMR_STROKEPATH 64 -#define EMR_FLATTENPATH 65 -#define EMR_WIDENPATH 66 -#define EMR_SELECTCLIPPATH 67 -#define EMR_ABORTPATH 68 - -#define EMR_GDICOMMENT 70 -#define EMR_FILLRGN 71 -#define EMR_FRAMERGN 72 -#define EMR_INVERTRGN 73 -#define EMR_PAINTRGN 74 -#define EMR_EXTSELECTCLIPRGN 75 -#define EMR_BITBLT 76 -#define EMR_STRETCHBLT 77 -#define EMR_MASKBLT 78 -#define EMR_PLGBLT 79 -#define EMR_SETDIBITSTODEVICE 80 -#define EMR_STRETCHDIBITS 81 -#define EMR_EXTCREATEFONTINDIRECTW 82 -#define EMR_EXTTEXTOUTA 83 -#define EMR_EXTTEXTOUTW 84 -#define EMR_POLYBEZIER16 85 -#define EMR_POLYGON16 86 -#define EMR_POLYLINE16 87 -#define EMR_POLYBEZIERTO16 88 -#define EMR_POLYLINETO16 89 -#define EMR_POLYPOLYLINE16 90 -#define EMR_POLYPOLYGON16 91 -#define EMR_POLYDRAW16 92 -#define EMR_CREATEMONOBRUSH 93 -#define EMR_CREATEDIBPATTERNBRUSHPT 94 -#define EMR_EXTCREATEPEN 95 -#define EMR_POLYTEXTOUTA 96 -#define EMR_POLYTEXTOUTW 97 - -#define EMR_SETICMMODE 98 -#define EMR_CREATECOLORSPACE 99 -#define EMR_SETCOLORSPACE 100 -#define EMR_DELETECOLORSPACE 101 -#define EMR_GLSRECORD 102 -#define EMR_GLSBOUNDEDRECORD 103 -#define EMR_PIXELFORMAT 104 -#define EMR_RESERVED_105 105 -#define EMR_RESERVED_106 106 -#define EMR_RESERVED_107 107 -#define EMR_RESERVED_108 108 -#define EMR_RESERVED_109 109 -#define EMR_RESERVED_110 110 -#define EMR_COLORCORRECTPALETTE 111 -#define EMR_SETICMPROFILEA 112 -#define EMR_SETICMPROFILEW 113 -#define EMR_ALPHABLEND 114 -#define EMR_SETLAYOUT 115 -#define EMR_TRANSPARENTBLT 116 -#define EMR_RESERVED_117 117 -#define EMR_GRADIENTFILL 118 -#define EMR_RESERVED_119 119 -#define EMR_RESERVED_120 120 -#define EMR_COLORMATCHTOTARGETW 121 -#define EMR_CREATECOLORSPACEW 122 - -#define EMR_MIN 1 - -#define EMR_MAX 122 - - typedef struct tagEMR { - DWORD iType; - DWORD nSize; - } EMR,*PEMR; - - typedef struct tagEMRTEXT { - POINTL ptlReference; - DWORD nChars; - DWORD offString; - DWORD fOptions; - RECTL rcl; - DWORD offDx; - } EMRTEXT,*PEMRTEXT; - - typedef struct tagABORTPATH { - EMR emr; - } EMRABORTPATH,*PEMRABORTPATH,EMRBEGINPATH,*PEMRBEGINPATH,EMRENDPATH,*PEMRENDPATH,EMRCLOSEFIGURE,*PEMRCLOSEFIGURE,EMRFLATTENPATH,*PEMRFLATTENPATH,EMRWIDENPATH,*PEMRWIDENPATH,EMRSETMETARGN,*PEMRSETMETARGN,EMRSAVEDC,*PEMRSAVEDC,EMRREALIZEPALETTE,*PEMRREALIZEPALETTE; - - typedef struct tagEMRSELECTCLIPPATH { - EMR emr; - DWORD iMode; - } EMRSELECTCLIPPATH,*PEMRSELECTCLIPPATH,EMRSETBKMODE,*PEMRSETBKMODE,EMRSETMAPMODE,*PEMRSETMAPMODE,EMRSETLAYOUT,*PEMRSETLAYOUT, - EMRSETPOLYFILLMODE,*PEMRSETPOLYFILLMODE,EMRSETROP2,*PEMRSETROP2,EMRSETSTRETCHBLTMODE,*PEMRSETSTRETCHBLTMODE,EMRSETICMMODE, - *PEMRSETICMMODE,EMRSETTEXTALIGN,*PEMRSETTEXTALIGN; - - typedef struct tagEMRSETMITERLIMIT { - EMR emr; - FLOAT eMiterLimit; - } EMRSETMITERLIMIT,*PEMRSETMITERLIMIT; - - typedef struct tagEMRRESTOREDC { - EMR emr; - LONG iRelative; - } EMRRESTOREDC,*PEMRRESTOREDC; - - typedef struct tagEMRSETARCDIRECTION { - EMR emr; - DWORD iArcDirection; - - } EMRSETARCDIRECTION,*PEMRSETARCDIRECTION; - - typedef struct tagEMRSETMAPPERFLAGS { - EMR emr; - DWORD dwFlags; - } EMRSETMAPPERFLAGS,*PEMRSETMAPPERFLAGS; - - typedef struct tagEMRSETTEXTCOLOR { - EMR emr; - COLORREF crColor; - } EMRSETBKCOLOR,*PEMRSETBKCOLOR,EMRSETTEXTCOLOR,*PEMRSETTEXTCOLOR; - - typedef struct tagEMRSELECTOBJECT { - EMR emr; - DWORD ihObject; - } EMRSELECTOBJECT,*PEMRSELECTOBJECT,EMRDELETEOBJECT,*PEMRDELETEOBJECT; - - typedef struct tagEMRSELECTPALETTE { - EMR emr; - DWORD ihPal; - } EMRSELECTPALETTE,*PEMRSELECTPALETTE; - - typedef struct tagEMRRESIZEPALETTE { - EMR emr; - DWORD ihPal; - DWORD cEntries; - } EMRRESIZEPALETTE,*PEMRRESIZEPALETTE; - - typedef struct tagEMRSETPALETTEENTRIES { - EMR emr; - DWORD ihPal; - DWORD iStart; - DWORD cEntries; - PALETTEENTRY aPalEntries[1]; - } EMRSETPALETTEENTRIES,*PEMRSETPALETTEENTRIES; - - typedef struct tagEMRSETCOLORADJUSTMENT { - EMR emr; - COLORADJUSTMENT ColorAdjustment; - } EMRSETCOLORADJUSTMENT,*PEMRSETCOLORADJUSTMENT; - - typedef struct tagEMRGDICOMMENT { - EMR emr; - DWORD cbData; - BYTE Data[1]; - } EMRGDICOMMENT,*PEMRGDICOMMENT; - - typedef struct tagEMREOF { - EMR emr; - DWORD nPalEntries; - DWORD offPalEntries; - DWORD nSizeLast; - } EMREOF,*PEMREOF; - - typedef struct tagEMRLINETO { - EMR emr; - POINTL ptl; - } EMRLINETO,*PEMRLINETO,EMRMOVETOEX,*PEMRMOVETOEX; - - typedef struct tagEMROFFSETCLIPRGN { - EMR emr; - POINTL ptlOffset; - } EMROFFSETCLIPRGN,*PEMROFFSETCLIPRGN; - - typedef struct tagEMRFILLPATH { - EMR emr; - RECTL rclBounds; - } EMRFILLPATH,*PEMRFILLPATH,EMRSTROKEANDFILLPATH,*PEMRSTROKEANDFILLPATH,EMRSTROKEPATH,*PEMRSTROKEPATH; - - typedef struct tagEMREXCLUDECLIPRECT { - EMR emr; - RECTL rclClip; - } EMREXCLUDECLIPRECT,*PEMREXCLUDECLIPRECT,EMRINTERSECTCLIPRECT,*PEMRINTERSECTCLIPRECT; - - typedef struct tagEMRSETVIEWPORTORGEX { - EMR emr; - POINTL ptlOrigin; - } EMRSETVIEWPORTORGEX,*PEMRSETVIEWPORTORGEX,EMRSETWINDOWORGEX,*PEMRSETWINDOWORGEX,EMRSETBRUSHORGEX,*PEMRSETBRUSHORGEX; - - typedef struct tagEMRSETVIEWPORTEXTEX { - EMR emr; - SIZEL szlExtent; - } EMRSETVIEWPORTEXTEX,*PEMRSETVIEWPORTEXTEX,EMRSETWINDOWEXTEX,*PEMRSETWINDOWEXTEX; - - typedef struct tagEMRSCALEVIEWPORTEXTEX { - EMR emr; - LONG xNum; - LONG xDenom; - LONG yNum; - LONG yDenom; - } EMRSCALEVIEWPORTEXTEX,*PEMRSCALEVIEWPORTEXTEX,EMRSCALEWINDOWEXTEX,*PEMRSCALEWINDOWEXTEX; - - typedef struct tagEMRSETWORLDTRANSFORM { - EMR emr; - XFORM xform; - } EMRSETWORLDTRANSFORM,*PEMRSETWORLDTRANSFORM; - - typedef struct tagEMRMODIFYWORLDTRANSFORM { - EMR emr; - XFORM xform; - DWORD iMode; - } EMRMODIFYWORLDTRANSFORM,*PEMRMODIFYWORLDTRANSFORM; - - typedef struct tagEMRSETPIXELV { - EMR emr; - POINTL ptlPixel; - COLORREF crColor; - } EMRSETPIXELV,*PEMRSETPIXELV; - - typedef struct tagEMREXTFLOODFILL { - EMR emr; - POINTL ptlStart; - COLORREF crColor; - DWORD iMode; - } EMREXTFLOODFILL,*PEMREXTFLOODFILL; - - typedef struct tagEMRELLIPSE { - EMR emr; - RECTL rclBox; - } EMRELLIPSE,*PEMRELLIPSE,EMRRECTANGLE,*PEMRRECTANGLE; - - typedef struct tagEMRROUNDRECT { - EMR emr; - RECTL rclBox; - SIZEL szlCorner; - } EMRROUNDRECT,*PEMRROUNDRECT; - - typedef struct tagEMRARC { - EMR emr; - RECTL rclBox; - POINTL ptlStart; - POINTL ptlEnd; - } EMRARC,*PEMRARC,EMRARCTO,*PEMRARCTO,EMRCHORD,*PEMRCHORD,EMRPIE,*PEMRPIE; - - typedef struct tagEMRANGLEARC { - EMR emr; - POINTL ptlCenter; - DWORD nRadius; - FLOAT eStartAngle; - FLOAT eSweepAngle; - } EMRANGLEARC,*PEMRANGLEARC; - - typedef struct tagEMRPOLYLINE { - EMR emr; - RECTL rclBounds; - DWORD cptl; - POINTL aptl[1]; - } EMRPOLYLINE,*PEMRPOLYLINE,EMRPOLYBEZIER,*PEMRPOLYBEZIER,EMRPOLYGON,*PEMRPOLYGON,EMRPOLYBEZIERTO,*PEMRPOLYBEZIERTO,EMRPOLYLINETO,*PEMRPOLYLINETO; - - typedef struct tagEMRPOLYLINE16 { - EMR emr; - RECTL rclBounds; - DWORD cpts; - POINTS apts[1]; - } EMRPOLYLINE16,*PEMRPOLYLINE16,EMRPOLYBEZIER16,*PEMRPOLYBEZIER16,EMRPOLYGON16,*PEMRPOLYGON16,EMRPOLYBEZIERTO16,*PEMRPOLYBEZIERTO16,EMRPOLYLINETO16,*PEMRPOLYLINETO16; - - typedef struct tagEMRPOLYDRAW { - EMR emr; - RECTL rclBounds; - DWORD cptl; - POINTL aptl[1]; - BYTE abTypes[1]; - } EMRPOLYDRAW,*PEMRPOLYDRAW; - - typedef struct tagEMRPOLYDRAW16 { - EMR emr; - RECTL rclBounds; - DWORD cpts; - POINTS apts[1]; - BYTE abTypes[1]; - } EMRPOLYDRAW16,*PEMRPOLYDRAW16; - - typedef struct tagEMRPOLYPOLYLINE { - EMR emr; - RECTL rclBounds; - DWORD nPolys; - DWORD cptl; - DWORD aPolyCounts[1]; - POINTL aptl[1]; - } EMRPOLYPOLYLINE,*PEMRPOLYPOLYLINE,EMRPOLYPOLYGON,*PEMRPOLYPOLYGON; - - typedef struct tagEMRPOLYPOLYLINE16 { - EMR emr; - RECTL rclBounds; - DWORD nPolys; - DWORD cpts; - DWORD aPolyCounts[1]; - POINTS apts[1]; - } EMRPOLYPOLYLINE16,*PEMRPOLYPOLYLINE16,EMRPOLYPOLYGON16,*PEMRPOLYPOLYGON16; - - typedef struct tagEMRINVERTRGN { - EMR emr; - RECTL rclBounds; - DWORD cbRgnData; - BYTE RgnData[1]; - } EMRINVERTRGN,*PEMRINVERTRGN,EMRPAINTRGN,*PEMRPAINTRGN; - - typedef struct tagEMRFILLRGN { - EMR emr; - RECTL rclBounds; - DWORD cbRgnData; - DWORD ihBrush; - BYTE RgnData[1]; - } EMRFILLRGN,*PEMRFILLRGN; - - typedef struct tagEMRFRAMERGN { - EMR emr; - RECTL rclBounds; - DWORD cbRgnData; - DWORD ihBrush; - SIZEL szlStroke; - BYTE RgnData[1]; - } EMRFRAMERGN,*PEMRFRAMERGN; - - typedef struct tagEMREXTSELECTCLIPRGN { - EMR emr; - DWORD cbRgnData; - DWORD iMode; - BYTE RgnData[1]; - } EMREXTSELECTCLIPRGN,*PEMREXTSELECTCLIPRGN; - - typedef struct tagEMREXTTEXTOUTA { - EMR emr; - RECTL rclBounds; - DWORD iGraphicsMode; - FLOAT exScale; - FLOAT eyScale; - EMRTEXT emrtext; - } EMREXTTEXTOUTA,*PEMREXTTEXTOUTA,EMREXTTEXTOUTW,*PEMREXTTEXTOUTW; - - typedef struct tagEMRPOLYTEXTOUTA { - EMR emr; - RECTL rclBounds; - DWORD iGraphicsMode; - FLOAT exScale; - FLOAT eyScale; - LONG cStrings; - EMRTEXT aemrtext[1]; - } EMRPOLYTEXTOUTA,*PEMRPOLYTEXTOUTA,EMRPOLYTEXTOUTW,*PEMRPOLYTEXTOUTW; - - typedef struct tagEMRBITBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - } EMRBITBLT,*PEMRBITBLT; - - typedef struct tagEMRSTRETCHBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG cxSrc; - LONG cySrc; - } EMRSTRETCHBLT,*PEMRSTRETCHBLT; - - typedef struct tagEMRMASKBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG xMask; - LONG yMask; - DWORD iUsageMask; - DWORD offBmiMask; - DWORD cbBmiMask; - DWORD offBitsMask; - DWORD cbBitsMask; - } EMRMASKBLT,*PEMRMASKBLT; - - typedef struct tagEMRPLGBLT { - EMR emr; - RECTL rclBounds; - POINTL aptlDest[3]; - LONG xSrc; - LONG ySrc; - LONG cxSrc; - LONG cySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG xMask; - LONG yMask; - DWORD iUsageMask; - DWORD offBmiMask; - DWORD cbBmiMask; - DWORD offBitsMask; - DWORD cbBitsMask; - } EMRPLGBLT,*PEMRPLGBLT; - - typedef struct tagEMRSETDIBITSTODEVICE { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG xSrc; - LONG ySrc; - LONG cxSrc; - LONG cySrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - DWORD iUsageSrc; - DWORD iStartScan; - DWORD cScans; - } EMRSETDIBITSTODEVICE,*PEMRSETDIBITSTODEVICE; - - typedef struct tagEMRSTRETCHDIBITS { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG xSrc; - LONG ySrc; - LONG cxSrc; - LONG cySrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - DWORD iUsageSrc; - DWORD dwRop; - LONG cxDest; - LONG cyDest; - } EMRSTRETCHDIBITS,*PEMRSTRETCHDIBITS; - - typedef struct tagEMREXTCREATEFONTINDIRECTW { - EMR emr; - DWORD ihFont; - EXTLOGFONTW elfw; - } EMREXTCREATEFONTINDIRECTW,*PEMREXTCREATEFONTINDIRECTW; - - typedef struct tagEMRCREATEPALETTE { - EMR emr; - DWORD ihPal; - LOGPALETTE lgpl; - } EMRCREATEPALETTE,*PEMRCREATEPALETTE; - - typedef struct tagEMRCREATEPEN { - EMR emr; - DWORD ihPen; - LOGPEN lopn; - } EMRCREATEPEN,*PEMRCREATEPEN; - - typedef struct tagEMREXTCREATEPEN { - EMR emr; - DWORD ihPen; - DWORD offBmi; - DWORD cbBmi; - DWORD offBits; - DWORD cbBits; - EXTLOGPEN elp; - } EMREXTCREATEPEN,*PEMREXTCREATEPEN; - - typedef struct tagEMRCREATEBRUSHINDIRECT { - EMR emr; - DWORD ihBrush; - LOGBRUSH32 lb; - } EMRCREATEBRUSHINDIRECT,*PEMRCREATEBRUSHINDIRECT; - - typedef struct tagEMRCREATEMONOBRUSH { - EMR emr; - DWORD ihBrush; - DWORD iUsage; - DWORD offBmi; - DWORD cbBmi; - DWORD offBits; - DWORD cbBits; - } EMRCREATEMONOBRUSH,*PEMRCREATEMONOBRUSH; - - typedef struct tagEMRCREATEDIBPATTERNBRUSHPT { - EMR emr; - DWORD ihBrush; - DWORD iUsage; - DWORD offBmi; - DWORD cbBmi; - DWORD offBits; - DWORD cbBits; - } EMRCREATEDIBPATTERNBRUSHPT,*PEMRCREATEDIBPATTERNBRUSHPT; - - typedef struct tagEMRFORMAT { - DWORD dSignature; - DWORD nVersion; - DWORD cbData; - DWORD offData; - } EMRFORMAT,*PEMRFORMAT; - - typedef struct tagEMRGLSRECORD { - EMR emr; - DWORD cbData; - BYTE Data[1]; - } EMRGLSRECORD,*PEMRGLSRECORD; - - typedef struct tagEMRGLSBOUNDEDRECORD { - EMR emr; - RECTL rclBounds; - DWORD cbData; - BYTE Data[1]; - } EMRGLSBOUNDEDRECORD,*PEMRGLSBOUNDEDRECORD; - - typedef struct tagEMRPIXELFORMAT { - EMR emr; - PIXELFORMATDESCRIPTOR pfd; - } EMRPIXELFORMAT,*PEMRPIXELFORMAT; - - typedef struct tagEMRCREATECOLORSPACE { - EMR emr; - DWORD ihCS; - LOGCOLORSPACEA lcs; - } EMRCREATECOLORSPACE,*PEMRCREATECOLORSPACE; - - typedef struct tagEMRSETCOLORSPACE { - EMR emr; - DWORD ihCS; - } EMRSETCOLORSPACE,*PEMRSETCOLORSPACE,EMRSELECTCOLORSPACE,*PEMRSELECTCOLORSPACE,EMRDELETECOLORSPACE,*PEMRDELETECOLORSPACE; - - typedef struct tagEMREXTESCAPE { - EMR emr; - INT iEscape; - INT cbEscData; - BYTE EscData[1]; - } EMREXTESCAPE,*PEMREXTESCAPE,EMRDRAWESCAPE,*PEMRDRAWESCAPE; - - typedef struct tagEMRNAMEDESCAPE { - EMR emr; - INT iEscape; - INT cbDriver; - INT cbEscData; - BYTE EscData[1]; - } EMRNAMEDESCAPE,*PEMRNAMEDESCAPE; - -#define SETICMPROFILE_EMBEDED 0x00000001 - - typedef struct tagEMRSETICMPROFILE { - EMR emr; - DWORD dwFlags; - DWORD cbName; - DWORD cbData; - BYTE Data[1]; - } EMRSETICMPROFILE,*PEMRSETICMPROFILE,EMRSETICMPROFILEA,*PEMRSETICMPROFILEA,EMRSETICMPROFILEW,*PEMRSETICMPROFILEW; - -#define CREATECOLORSPACE_EMBEDED 0x00000001 - - typedef struct tagEMRCREATECOLORSPACEW { - EMR emr; - DWORD ihCS; - LOGCOLORSPACEW lcs; - DWORD dwFlags; - DWORD cbData; - BYTE Data[1]; - } EMRCREATECOLORSPACEW,*PEMRCREATECOLORSPACEW; - -#define COLORMATCHTOTARGET_EMBEDED 0x00000001 - - typedef struct tagCOLORMATCHTOTARGET { - EMR emr; - DWORD dwAction; - DWORD dwFlags; - DWORD cbName; - DWORD cbData; - BYTE Data[1]; - } EMRCOLORMATCHTOTARGET,*PEMRCOLORMATCHTOTARGET; - - typedef struct tagCOLORCORRECTPALETTE { - EMR emr; - DWORD ihPalette; - DWORD nFirstEntry; - DWORD nPalEntries; - DWORD nReserved; - } EMRCOLORCORRECTPALETTE,*PEMRCOLORCORRECTPALETTE; - - typedef struct tagEMRALPHABLEND { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG cxSrc; - LONG cySrc; - } EMRALPHABLEND,*PEMRALPHABLEND; - - typedef struct tagEMRGRADIENTFILL { - EMR emr; - RECTL rclBounds; - DWORD nVer; - DWORD nTri; - ULONG ulMode; - TRIVERTEX Ver[1]; - } EMRGRADIENTFILL,*PEMRGRADIENTFILL; - - typedef struct tagEMRTRANSPARENTBLT { - EMR emr; - RECTL rclBounds; - LONG xDest; - LONG yDest; - LONG cxDest; - LONG cyDest; - DWORD dwRop; - LONG xSrc; - LONG ySrc; - XFORM xformSrc; - COLORREF crBkColorSrc; - DWORD iUsageSrc; - DWORD offBmiSrc; - DWORD cbBmiSrc; - DWORD offBitsSrc; - DWORD cbBitsSrc; - LONG cxSrc; - LONG cySrc; - } EMRTRANSPARENTBLT,*PEMRTRANSPARENTBLT; - -#define GDICOMMENT_IDENTIFIER 0x43494447 -#define GDICOMMENT_WINDOWS_METAFILE 0x80000001 -#define GDICOMMENT_BEGINGROUP 0x00000002 -#define GDICOMMENT_ENDGROUP 0x00000003 -#define GDICOMMENT_MULTIFORMATS 0x40000004 -#define EPS_SIGNATURE 0x46535045 -#define GDICOMMENT_UNICODE_STRING 0x00000040 -#define GDICOMMENT_UNICODE_END 0x00000080 -#endif - -#ifdef UNICODE -#define wglUseFontBitmaps wglUseFontBitmapsW -#else -#define wglUseFontBitmaps wglUseFontBitmapsA -#endif - - WINGDIAPI WINBOOL WINAPI wglCopyContext(HGLRC,HGLRC,UINT); - WINGDIAPI HGLRC WINAPI wglCreateContext(HDC); - WINGDIAPI HGLRC WINAPI wglCreateLayerContext(HDC,int); - WINGDIAPI WINBOOL WINAPI wglDeleteContext(HGLRC); - WINGDIAPI HGLRC WINAPI wglGetCurrentContext(VOID); - WINGDIAPI HDC WINAPI wglGetCurrentDC(VOID); - WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR); - WINGDIAPI WINBOOL WINAPI wglMakeCurrent(HDC,HGLRC); - WINGDIAPI WINBOOL WINAPI wglShareLists(HGLRC,HGLRC); - WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsA(HDC,DWORD,DWORD,DWORD); - WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsW(HDC,DWORD,DWORD,DWORD); - WINGDIAPI WINBOOL WINAPI SwapBuffers(HDC); - - typedef struct _POINTFLOAT { - FLOAT x; - FLOAT y; - } POINTFLOAT,*PPOINTFLOAT; - - typedef struct _GLYPHMETRICSFLOAT { - FLOAT gmfBlackBoxX; - FLOAT gmfBlackBoxY; - POINTFLOAT gmfptGlyphOrigin; - FLOAT gmfCellIncX; - FLOAT gmfCellIncY; - } GLYPHMETRICSFLOAT,*PGLYPHMETRICSFLOAT,*LPGLYPHMETRICSFLOAT; - -#define WGL_FONT_LINES 0 -#define WGL_FONT_POLYGONS 1 - -#ifdef UNICODE -#define wglUseFontOutlines wglUseFontOutlinesW -#else -#define wglUseFontOutlines wglUseFontOutlinesA -#endif - - WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesA(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); - WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesW(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); - - typedef struct tagLAYERPLANEDESCRIPTOR { - WORD nSize; - WORD nVersion; - DWORD dwFlags; - BYTE iPixelType; - BYTE cColorBits; - BYTE cRedBits; - BYTE cRedShift; - BYTE cGreenBits; - BYTE cGreenShift; - BYTE cBlueBits; - BYTE cBlueShift; - BYTE cAlphaBits; - BYTE cAlphaShift; - BYTE cAccumBits; - BYTE cAccumRedBits; - BYTE cAccumGreenBits; - BYTE cAccumBlueBits; - BYTE cAccumAlphaBits; - BYTE cDepthBits; - BYTE cStencilBits; - BYTE cAuxBuffers; - BYTE iLayerPlane; - BYTE bReserved; - COLORREF crTransparent; - } LAYERPLANEDESCRIPTOR,*PLAYERPLANEDESCRIPTOR,*LPLAYERPLANEDESCRIPTOR; - -#define LPD_DOUBLEBUFFER 0x00000001 -#define LPD_STEREO 0x00000002 -#define LPD_SUPPORT_GDI 0x00000010 -#define LPD_SUPPORT_OPENGL 0x00000020 -#define LPD_SHARE_DEPTH 0x00000040 -#define LPD_SHARE_STENCIL 0x00000080 -#define LPD_SHARE_ACCUM 0x00000100 -#define LPD_SWAP_EXCHANGE 0x00000200 -#define LPD_SWAP_COPY 0x00000400 -#define LPD_TRANSPARENT 0x00001000 - -#define LPD_TYPE_RGBA 0 -#define LPD_TYPE_COLORINDEX 1 - -#define WGL_SWAP_MAIN_PLANE 0x00000001 -#define WGL_SWAP_OVERLAY1 0x00000002 -#define WGL_SWAP_OVERLAY2 0x00000004 -#define WGL_SWAP_OVERLAY3 0x00000008 -#define WGL_SWAP_OVERLAY4 0x00000010 -#define WGL_SWAP_OVERLAY5 0x00000020 -#define WGL_SWAP_OVERLAY6 0x00000040 -#define WGL_SWAP_OVERLAY7 0x00000080 -#define WGL_SWAP_OVERLAY8 0x00000100 -#define WGL_SWAP_OVERLAY9 0x00000200 -#define WGL_SWAP_OVERLAY10 0x00000400 -#define WGL_SWAP_OVERLAY11 0x00000800 -#define WGL_SWAP_OVERLAY12 0x00001000 -#define WGL_SWAP_OVERLAY13 0x00002000 -#define WGL_SWAP_OVERLAY14 0x00004000 -#define WGL_SWAP_OVERLAY15 0x00008000 -#define WGL_SWAP_UNDERLAY1 0x00010000 -#define WGL_SWAP_UNDERLAY2 0x00020000 -#define WGL_SWAP_UNDERLAY3 0x00040000 -#define WGL_SWAP_UNDERLAY4 0x00080000 -#define WGL_SWAP_UNDERLAY5 0x00100000 -#define WGL_SWAP_UNDERLAY6 0x00200000 -#define WGL_SWAP_UNDERLAY7 0x00400000 -#define WGL_SWAP_UNDERLAY8 0x00800000 -#define WGL_SWAP_UNDERLAY9 0x01000000 -#define WGL_SWAP_UNDERLAY10 0x02000000 -#define WGL_SWAP_UNDERLAY11 0x04000000 -#define WGL_SWAP_UNDERLAY12 0x08000000 -#define WGL_SWAP_UNDERLAY13 0x10000000 -#define WGL_SWAP_UNDERLAY14 0x20000000 -#define WGL_SWAP_UNDERLAY15 0x40000000 - - WINGDIAPI WINBOOL WINAPI wglDescribeLayerPlane(HDC,int,int,UINT,LPLAYERPLANEDESCRIPTOR); - WINGDIAPI int WINAPI wglSetLayerPaletteEntries(HDC,int,int,int,CONST COLORREF *); - WINGDIAPI int WINAPI wglGetLayerPaletteEntries(HDC,int,int,int,COLORREF *); - WINGDIAPI WINBOOL WINAPI wglRealizeLayerPalette(HDC,int,WINBOOL); - WINGDIAPI WINBOOL WINAPI wglSwapLayerBuffers(HDC,UINT); - - typedef struct _WGLSWAP { - HDC hdc; - UINT uiFlags; - } WGLSWAP,*PWGLSWAP,*LPWGLSWAP; - -#define WGL_SWAPMULTIPLE_MAX 16 - - WINGDIAPI DWORD WINAPI wglSwapMultipleBuffers(UINT,CONST WGLSWAP *); -#endif - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINGDI_ +#define _WINGDI_ + +#define WINGDIAPI DECLSPEC_IMPORT +#define WINSPOOLAPI DECLSPEC_IMPORT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#ifndef NOGDI +#ifndef NORASTEROPS +#define R2_BLACK 1 +#define R2_NOTMERGEPEN 2 +#define R2_MASKNOTPEN 3 +#define R2_NOTCOPYPEN 4 +#define R2_MASKPENNOT 5 +#define R2_NOT 6 +#define R2_XORPEN 7 +#define R2_NOTMASKPEN 8 +#define R2_MASKPEN 9 +#define R2_NOTXORPEN 10 +#define R2_NOP 11 +#define R2_MERGENOTPEN 12 +#define R2_COPYPEN 13 +#define R2_MERGEPENNOT 14 +#define R2_MERGEPEN 15 +#define R2_WHITE 16 +#define R2_LAST 16 + +#define SRCCOPY (DWORD)0x00CC0020 +#define SRCPAINT (DWORD)0x00EE0086 +#define SRCAND (DWORD)0x008800C6 +#define SRCINVERT (DWORD)0x00660046 +#define SRCERASE (DWORD)0x00440328 +#define NOTSRCCOPY (DWORD)0x00330008 +#define NOTSRCERASE (DWORD)0x001100A6 +#define MERGECOPY (DWORD)0x00C000CA +#define MERGEPAINT (DWORD)0x00BB0226 +#define PATCOPY (DWORD)0x00F00021 +#define PATPAINT (DWORD)0x00FB0A09 +#define PATINVERT (DWORD)0x005A0049 +#define DSTINVERT (DWORD)0x00550009 +#define BLACKNESS (DWORD)0x00000042 +#define WHITENESS (DWORD)0x00FF0062 +#define NOMIRRORBITMAP (DWORD)0x80000000 +#define CAPTUREBLT (DWORD)0x40000000 +#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) +#endif + +#define GDI_ERROR (0xFFFFFFFFL) +#define HGDI_ERROR (LongToHandle(0xFFFFFFFFL)) + +#define ERROR 0 +#define NULLREGION 1 +#define SIMPLEREGION 2 +#define COMPLEXREGION 3 +#define RGN_ERROR ERROR + +#define RGN_AND 1 +#define RGN_OR 2 +#define RGN_XOR 3 +#define RGN_DIFF 4 +#define RGN_COPY 5 +#define RGN_MIN RGN_AND +#define RGN_MAX RGN_COPY + +#define BLACKONWHITE 1 +#define WHITEONBLACK 2 +#define COLORONCOLOR 3 +#define HALFTONE 4 +#define MAXSTRETCHBLTMODE 4 + +#define STRETCH_ANDSCANS BLACKONWHITE +#define STRETCH_ORSCANS WHITEONBLACK +#define STRETCH_DELETESCANS COLORONCOLOR +#define STRETCH_HALFTONE HALFTONE + +#define ALTERNATE 1 +#define WINDING 2 +#define POLYFILL_LAST 2 + +#define LAYOUT_RTL 0x00000001 +#define LAYOUT_BTT 0x00000002 +#define LAYOUT_VBH 0x00000004 +#define LAYOUT_ORIENTATIONMASK (LAYOUT_RTL | LAYOUT_BTT | LAYOUT_VBH) +#define LAYOUT_BITMAPORIENTATIONPRESERVED 0x00000008 + +#define TA_NOUPDATECP 0 +#define TA_UPDATECP 1 + +#define TA_LEFT 0 +#define TA_RIGHT 2 +#define TA_CENTER 6 + +#define TA_TOP 0 +#define TA_BOTTOM 8 +#define TA_BASELINE 24 +#define TA_RTLREADING 256 +#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING) + +#define VTA_BASELINE TA_BASELINE +#define VTA_LEFT TA_BOTTOM +#define VTA_RIGHT TA_TOP +#define VTA_CENTER TA_CENTER +#define VTA_BOTTOM TA_RIGHT +#define VTA_TOP TA_LEFT + +#define ETO_OPAQUE 0x0002 +#define ETO_CLIPPED 0x0004 +#define ETO_GLYPH_INDEX 0x0010 +#define ETO_RTLREADING 0x0080 +#define ETO_NUMERICSLOCAL 0x0400 +#define ETO_NUMERICSLATIN 0x0800 +#define ETO_IGNORELANGUAGE 0x1000 +#define ETO_PDY 0x2000 + +#define ASPECT_FILTERING 0x0001 + +#define DCB_RESET 0x0001 +#define DCB_ACCUMULATE 0x0002 +#define DCB_DIRTY DCB_ACCUMULATE +#define DCB_SET (DCB_RESET | DCB_ACCUMULATE) +#define DCB_ENABLE 0x0004 +#define DCB_DISABLE 0x0008 + +#ifndef NOMETAFILE + +#define META_SETBKCOLOR 0x0201 +#define META_SETBKMODE 0x0102 +#define META_SETMAPMODE 0x0103 +#define META_SETROP2 0x0104 +#define META_SETRELABS 0x0105 +#define META_SETPOLYFILLMODE 0x0106 +#define META_SETSTRETCHBLTMODE 0x0107 +#define META_SETTEXTCHAREXTRA 0x0108 +#define META_SETTEXTCOLOR 0x0209 +#define META_SETTEXTJUSTIFICATION 0x020A +#define META_SETWINDOWORG 0x020B +#define META_SETWINDOWEXT 0x020C +#define META_SETVIEWPORTORG 0x020D +#define META_SETVIEWPORTEXT 0x020E +#define META_OFFSETWINDOWORG 0x020F +#define META_SCALEWINDOWEXT 0x0410 +#define META_OFFSETVIEWPORTORG 0x0211 +#define META_SCALEVIEWPORTEXT 0x0412 +#define META_LINETO 0x0213 +#define META_MOVETO 0x0214 +#define META_EXCLUDECLIPRECT 0x0415 +#define META_INTERSECTCLIPRECT 0x0416 +#define META_ARC 0x0817 +#define META_ELLIPSE 0x0418 +#define META_FLOODFILL 0x0419 +#define META_PIE 0x081A +#define META_RECTANGLE 0x041B +#define META_ROUNDRECT 0x061C +#define META_PATBLT 0x061D +#define META_SAVEDC 0x001E +#define META_SETPIXEL 0x041F +#define META_OFFSETCLIPRGN 0x0220 +#define META_TEXTOUT 0x0521 +#define META_BITBLT 0x0922 +#define META_STRETCHBLT 0x0B23 +#define META_POLYGON 0x0324 +#define META_POLYLINE 0x0325 +#define META_ESCAPE 0x0626 +#define META_RESTOREDC 0x0127 +#define META_FILLREGION 0x0228 +#define META_FRAMEREGION 0x0429 +#define META_INVERTREGION 0x012A +#define META_PAINTREGION 0x012B +#define META_SELECTCLIPREGION 0x012C +#define META_SELECTOBJECT 0x012D +#define META_SETTEXTALIGN 0x012E +#define META_CHORD 0x0830 +#define META_SETMAPPERFLAGS 0x0231 +#define META_EXTTEXTOUT 0x0a32 +#define META_SETDIBTODEV 0x0d33 +#define META_SELECTPALETTE 0x0234 +#define META_REALIZEPALETTE 0x0035 +#define META_ANIMATEPALETTE 0x0436 +#define META_SETPALENTRIES 0x0037 +#define META_POLYPOLYGON 0x0538 +#define META_RESIZEPALETTE 0x0139 +#define META_DIBBITBLT 0x0940 +#define META_DIBSTRETCHBLT 0x0b41 +#define META_DIBCREATEPATTERNBRUSH 0x0142 +#define META_STRETCHDIB 0x0f43 +#define META_EXTFLOODFILL 0x0548 +#define META_SETLAYOUT 0x0149 +#define META_DELETEOBJECT 0x01f0 +#define META_CREATEPALETTE 0x00f7 +#define META_CREATEPATTERNBRUSH 0x01F9 +#define META_CREATEPENINDIRECT 0x02FA +#define META_CREATEFONTINDIRECT 0x02FB +#define META_CREATEBRUSHINDIRECT 0x02FC +#define META_CREATEREGION 0x06FF + + typedef struct _DRAWPATRECT { + POINT ptPosition; + POINT ptSize; + WORD wStyle; + WORD wPattern; + } DRAWPATRECT,*PDRAWPATRECT; +#endif + +#define NEWFRAME 1 +#define ABORTDOC 2 +#define NEXTBAND 3 +#define SETCOLORTABLE 4 +#define GETCOLORTABLE 5 +#define FLUSHOUTPUT 6 +#define DRAFTMODE 7 +#define QUERYESCSUPPORT 8 +#define SETABORTPROC 9 +#define STARTDOC 10 +#define ENDDOC 11 +#define GETPHYSPAGESIZE 12 +#define GETPRINTINGOFFSET 13 +#define GETSCALINGFACTOR 14 +#define MFCOMMENT 15 +#define GETPENWIDTH 16 +#define SETCOPYCOUNT 17 +#define SELECTPAPERSOURCE 18 +#define DEVICEDATA 19 +#define PASSTHROUGH 19 +#define GETTECHNOLGY 20 +#define GETTECHNOLOGY 20 +#define SETLINECAP 21 +#define SETLINEJOIN 22 +#define SETMITERLIMIT 23 +#define BANDINFO 24 +#define DRAWPATTERNRECT 25 +#define GETVECTORPENSIZE 26 +#define GETVECTORBRUSHSIZE 27 +#define ENABLEDUPLEX 28 +#define GETSETPAPERBINS 29 +#define GETSETPRINTORIENT 30 +#define ENUMPAPERBINS 31 +#define SETDIBSCALING 32 +#define EPSPRINTING 33 +#define ENUMPAPERMETRICS 34 +#define GETSETPAPERMETRICS 35 +#define POSTSCRIPT_DATA 37 +#define POSTSCRIPT_IGNORE 38 +#define MOUSETRAILS 39 +#define GETDEVICEUNITS 42 + +#define GETEXTENDEDTEXTMETRICS 256 +#define GETEXTENTTABLE 257 +#define GETPAIRKERNTABLE 258 +#define GETTRACKKERNTABLE 259 +#define EXTTEXTOUT 512 +#define GETFACENAME 513 +#define DOWNLOADFACE 514 +#define ENABLERELATIVEWIDTHS 768 +#define ENABLEPAIRKERNING 769 +#define SETKERNTRACK 770 +#define SETALLJUSTVALUES 771 +#define SETCHARSET 772 + +#define STRETCHBLT 2048 +#define METAFILE_DRIVER 2049 +#define GETSETSCREENPARAMS 3072 +#define QUERYDIBSUPPORT 3073 +#define BEGIN_PATH 4096 +#define CLIP_TO_PATH 4097 +#define END_PATH 4098 +#define EXT_DEVICE_CAPS 4099 +#define RESTORE_CTM 4100 +#define SAVE_CTM 4101 +#define SET_ARC_DIRECTION 4102 +#define SET_BACKGROUND_COLOR 4103 +#define SET_POLY_MODE 4104 +#define SET_SCREEN_ANGLE 4105 +#define SET_SPREAD 4106 +#define TRANSFORM_CTM 4107 +#define SET_CLIP_BOX 4108 +#define SET_BOUNDS 4109 +#define SET_MIRROR_MODE 4110 +#define OPENCHANNEL 4110 +#define DOWNLOADHEADER 4111 +#define CLOSECHANNEL 4112 +#define POSTSCRIPT_PASSTHROUGH 4115 +#define ENCAPSULATED_POSTSCRIPT 4116 + +#define POSTSCRIPT_IDENTIFY 4117 +#define POSTSCRIPT_INJECTION 4118 + +#define CHECKJPEGFORMAT 4119 +#define CHECKPNGFORMAT 4120 + +#define GET_PS_FEATURESETTING 4121 + +#define SPCLPASSTHROUGH2 4568 + +#define PSIDENT_GDICENTRIC 0 +#define PSIDENT_PSCENTRIC 1 + + typedef struct _PSINJECTDATA { + DWORD DataBytes; + WORD InjectionPoint; + WORD PageNumber; + } PSINJECTDATA,*PPSINJECTDATA; + +#define PSINJECT_BEGINSTREAM 1 +#define PSINJECT_PSADOBE 2 +#define PSINJECT_PAGESATEND 3 +#define PSINJECT_PAGES 4 + +#define PSINJECT_DOCNEEDEDRES 5 +#define PSINJECT_DOCSUPPLIEDRES 6 +#define PSINJECT_PAGEORDER 7 +#define PSINJECT_ORIENTATION 8 +#define PSINJECT_BOUNDINGBOX 9 +#define PSINJECT_DOCUMENTPROCESSCOLORS 10 + +#define PSINJECT_COMMENTS 11 +#define PSINJECT_BEGINDEFAULTS 12 +#define PSINJECT_ENDDEFAULTS 13 +#define PSINJECT_BEGINPROLOG 14 +#define PSINJECT_ENDPROLOG 15 +#define PSINJECT_BEGINSETUP 16 +#define PSINJECT_ENDSETUP 17 +#define PSINJECT_TRAILER 18 +#define PSINJECT_EOF 19 +#define PSINJECT_ENDSTREAM 20 +#define PSINJECT_DOCUMENTPROCESSCOLORSATEND 21 + +#define PSINJECT_PAGENUMBER 100 +#define PSINJECT_BEGINPAGESETUP 101 +#define PSINJECT_ENDPAGESETUP 102 +#define PSINJECT_PAGETRAILER 103 +#define PSINJECT_PLATECOLOR 104 + +#define PSINJECT_SHOWPAGE 105 +#define PSINJECT_PAGEBBOX 106 +#define PSINJECT_ENDPAGECOMMENTS 107 + +#define PSINJECT_VMSAVE 200 +#define PSINJECT_VMRESTORE 201 + +#define FEATURESETTING_NUP 0 +#define FEATURESETTING_OUTPUT 1 +#define FEATURESETTING_PSLEVEL 2 +#define FEATURESETTING_CUSTPAPER 3 +#define FEATURESETTING_MIRROR 4 +#define FEATURESETTING_NEGATIVE 5 +#define FEATURESETTING_PROTOCOL 6 + +#define FEATURESETTING_PRIVATE_BEGIN 0x1000 +#define FEATURESETTING_PRIVATE_END 0x1FFF + + typedef struct _PSFEATURE_OUTPUT { + WINBOOL bPageIndependent; + WINBOOL bSetPageDevice; + } PSFEATURE_OUTPUT,*PPSFEATURE_OUTPUT; + + typedef struct _PSFEATURE_CUSTPAPER { + LONG lOrientation; + LONG lWidth; + LONG lHeight; + LONG lWidthOffset; + LONG lHeightOffset; + } PSFEATURE_CUSTPAPER,*PPSFEATURE_CUSTPAPER; + +#define PSPROTOCOL_ASCII 0 +#define PSPROTOCOL_BCP 1 +#define PSPROTOCOL_TBCP 2 +#define PSPROTOCOL_BINARY 3 + +#define QDI_SETDIBITS 1 +#define QDI_GETDIBITS 2 +#define QDI_DIBTOSCREEN 4 +#define QDI_STRETCHDIB 8 + +#define SP_NOTREPORTED 0x4000 +#define SP_ERROR (-1) +#define SP_APPABORT (-2) +#define SP_USERABORT (-3) +#define SP_OUTOFDISK (-4) +#define SP_OUTOFMEMORY (-5) + +#define PR_JOBSTATUS 0x0000 + +#define OBJ_PEN 1 +#define OBJ_BRUSH 2 +#define OBJ_DC 3 +#define OBJ_METADC 4 +#define OBJ_PAL 5 +#define OBJ_FONT 6 +#define OBJ_BITMAP 7 +#define OBJ_REGION 8 +#define OBJ_METAFILE 9 +#define OBJ_MEMDC 10 +#define OBJ_EXTPEN 11 +#define OBJ_ENHMETADC 12 +#define OBJ_ENHMETAFILE 13 +#define OBJ_COLORSPACE 14 + +#define MWT_IDENTITY 1 +#define MWT_LEFTMULTIPLY 2 +#define MWT_RIGHTMULTIPLY 3 + +#define MWT_MIN MWT_IDENTITY +#define MWT_MAX MWT_RIGHTMULTIPLY + +#define _XFORM_ + typedef struct tagXFORM { + FLOAT eM11; + FLOAT eM12; + FLOAT eM21; + FLOAT eM22; + FLOAT eDx; + FLOAT eDy; + } XFORM,*PXFORM,*LPXFORM; + + typedef struct tagBITMAP { + LONG bmType; + LONG bmWidth; + LONG bmHeight; + LONG bmWidthBytes; + WORD bmPlanes; + WORD bmBitsPixel; + LPVOID bmBits; + } BITMAP,*PBITMAP,*NPBITMAP,*LPBITMAP; + +#include + typedef struct tagRGBTRIPLE { + BYTE rgbtBlue; + BYTE rgbtGreen; + BYTE rgbtRed; + } RGBTRIPLE; +#include + + typedef struct tagRGBQUAD { + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; + BYTE rgbReserved; + } RGBQUAD; + typedef RGBQUAD *LPRGBQUAD; + +#define CS_ENABLE 0x00000001L +#define CS_DISABLE 0x00000002L +#define CS_DELETE_TRANSFORM 0x00000003L + +//!__TINYC__: #define LCS_SIGNATURE 'PSOC' +//!__TINYC__: #define LCS_sRGB 'sRGB' +//!__TINYC__: #define LCS_WINDOWS_COLOR_SPACE 'Win ' + + typedef LONG LCSCSTYPE; +#define LCS_CALIBRATED_RGB 0x00000000L + + typedef LONG LCSGAMUTMATCH; +#define LCS_GM_BUSINESS 0x00000001L +#define LCS_GM_GRAPHICS 0x00000002L +#define LCS_GM_IMAGES 0x00000004L +#define LCS_GM_ABS_COLORIMETRIC 0x00000008L + +#define CM_OUT_OF_GAMUT 255 +#define CM_IN_GAMUT 0 + +#define ICM_ADDPROFILE 1 +#define ICM_DELETEPROFILE 2 +#define ICM_QUERYPROFILE 3 +#define ICM_SETDEFAULTPROFILE 4 +#define ICM_REGISTERICMATCHER 5 +#define ICM_UNREGISTERICMATCHER 6 +#define ICM_QUERYMATCH 7 + +#define GetKValue(cmyk) ((BYTE)(cmyk)) +#define GetYValue(cmyk) ((BYTE)((cmyk)>> 8)) +#define GetMValue(cmyk) ((BYTE)((cmyk)>>16)) +#define GetCValue(cmyk) ((BYTE)((cmyk)>>24)) + +#define CMYK(c,m,y,k) ((COLORREF)((((BYTE)(k)|((WORD)((BYTE)(y))<<8))|(((DWORD)(BYTE)(m))<<16))|(((DWORD)(BYTE)(c))<<24))) + + typedef long FXPT16DOT16,*LPFXPT16DOT16; + typedef long FXPT2DOT30,*LPFXPT2DOT30; + + typedef struct tagCIEXYZ { + FXPT2DOT30 ciexyzX; + FXPT2DOT30 ciexyzY; + FXPT2DOT30 ciexyzZ; + } CIEXYZ; + typedef CIEXYZ *LPCIEXYZ; + + typedef struct tagICEXYZTRIPLE { + CIEXYZ ciexyzRed; + CIEXYZ ciexyzGreen; + CIEXYZ ciexyzBlue; + } CIEXYZTRIPLE; + + typedef CIEXYZTRIPLE *LPCIEXYZTRIPLE; + + typedef struct tagLOGCOLORSPACEA { + DWORD lcsSignature; + DWORD lcsVersion; + DWORD lcsSize; + LCSCSTYPE lcsCSType; + LCSGAMUTMATCH lcsIntent; + CIEXYZTRIPLE lcsEndpoints; + DWORD lcsGammaRed; + DWORD lcsGammaGreen; + DWORD lcsGammaBlue; + CHAR lcsFilename[MAX_PATH]; + } LOGCOLORSPACEA,*LPLOGCOLORSPACEA; + + typedef struct tagLOGCOLORSPACEW { + DWORD lcsSignature; + DWORD lcsVersion; + DWORD lcsSize; + LCSCSTYPE lcsCSType; + LCSGAMUTMATCH lcsIntent; + CIEXYZTRIPLE lcsEndpoints; + DWORD lcsGammaRed; + DWORD lcsGammaGreen; + DWORD lcsGammaBlue; + WCHAR lcsFilename[MAX_PATH]; + } LOGCOLORSPACEW,*LPLOGCOLORSPACEW; + +#ifdef UNICODE + typedef LOGCOLORSPACEW LOGCOLORSPACE; + typedef LPLOGCOLORSPACEW LPLOGCOLORSPACE; +#else + typedef LOGCOLORSPACEA LOGCOLORSPACE; + typedef LPLOGCOLORSPACEA LPLOGCOLORSPACE; +#endif + + typedef struct tagBITMAPCOREHEADER { + DWORD bcSize; + WORD bcWidth; + WORD bcHeight; + WORD bcPlanes; + WORD bcBitCount; + } BITMAPCOREHEADER,*LPBITMAPCOREHEADER,*PBITMAPCOREHEADER; + + typedef struct tagBITMAPINFOHEADER { + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; + } BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER; + + typedef struct { + DWORD bV4Size; + LONG bV4Width; + LONG bV4Height; + WORD bV4Planes; + WORD bV4BitCount; + DWORD bV4V4Compression; + DWORD bV4SizeImage; + LONG bV4XPelsPerMeter; + LONG bV4YPelsPerMeter; + DWORD bV4ClrUsed; + DWORD bV4ClrImportant; + DWORD bV4RedMask; + DWORD bV4GreenMask; + DWORD bV4BlueMask; + DWORD bV4AlphaMask; + DWORD bV4CSType; + CIEXYZTRIPLE bV4Endpoints; + DWORD bV4GammaRed; + DWORD bV4GammaGreen; + DWORD bV4GammaBlue; + } BITMAPV4HEADER,*LPBITMAPV4HEADER,*PBITMAPV4HEADER; + + typedef struct { + DWORD bV5Size; + LONG bV5Width; + LONG bV5Height; + WORD bV5Planes; + WORD bV5BitCount; + DWORD bV5Compression; + DWORD bV5SizeImage; + LONG bV5XPelsPerMeter; + LONG bV5YPelsPerMeter; + DWORD bV5ClrUsed; + DWORD bV5ClrImportant; + DWORD bV5RedMask; + DWORD bV5GreenMask; + DWORD bV5BlueMask; + DWORD bV5AlphaMask; + DWORD bV5CSType; + CIEXYZTRIPLE bV5Endpoints; + DWORD bV5GammaRed; + DWORD bV5GammaGreen; + DWORD bV5GammaBlue; + DWORD bV5Intent; + DWORD bV5ProfileData; + DWORD bV5ProfileSize; + DWORD bV5Reserved; + } BITMAPV5HEADER,*LPBITMAPV5HEADER,*PBITMAPV5HEADER; + +//!__TINYC__: #define PROFILE_LINKED 'LINK' +//!__TINYC__: #define PROFILE_EMBEDDED 'MBED' + +#define BI_RGB 0L +#define BI_RLE8 1L +#define BI_RLE4 2L +#define BI_BITFIELDS 3L +#define BI_JPEG 4L +#define BI_PNG 5L + + typedef struct tagBITMAPINFO { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; + } BITMAPINFO,*LPBITMAPINFO,*PBITMAPINFO; + + typedef struct tagBITMAPCOREINFO { + BITMAPCOREHEADER bmciHeader; + RGBTRIPLE bmciColors[1]; + } BITMAPCOREINFO,*LPBITMAPCOREINFO,*PBITMAPCOREINFO; + +#include + typedef struct tagBITMAPFILEHEADER { + WORD bfType; + DWORD bfSize; + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; + } BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER; +#include + +#define MAKEPOINTS(l) (*((POINTS *)&(l))) + +#ifndef NOFONTSIG + typedef struct tagFONTSIGNATURE { + DWORD fsUsb[4]; + DWORD fsCsb[2]; + } FONTSIGNATURE,*PFONTSIGNATURE,*LPFONTSIGNATURE; + + typedef struct tagCHARSETINFO { + UINT ciCharset; + UINT ciACP; + FONTSIGNATURE fs; + } CHARSETINFO,*PCHARSETINFO,*NPCHARSETINFO,*LPCHARSETINFO; + +#define TCI_SRCCHARSET 1 +#define TCI_SRCCODEPAGE 2 +#define TCI_SRCFONTSIG 3 +#define TCI_SRCLOCALE 0x1000 + + typedef struct tagLOCALESIGNATURE { + DWORD lsUsb[4]; + DWORD lsCsbDefault[2]; + DWORD lsCsbSupported[2]; + } LOCALESIGNATURE,*PLOCALESIGNATURE,*LPLOCALESIGNATURE; +#endif + + +#ifndef NOMETAFILE + typedef struct tagHANDLETABLE { + HGDIOBJ objectHandle[1]; + } HANDLETABLE,*PHANDLETABLE,*LPHANDLETABLE; + + typedef struct tagMETARECORD { + DWORD rdSize; + WORD rdFunction; + WORD rdParm[1]; + } METARECORD; + typedef struct tagMETARECORD UNALIGNED *PMETARECORD; + typedef struct tagMETARECORD UNALIGNED *LPMETARECORD; + + typedef struct tagMETAFILEPICT { + LONG mm; + LONG xExt; + LONG yExt; + HMETAFILE hMF; + } METAFILEPICT,*LPMETAFILEPICT; + +#include + typedef struct tagMETAHEADER { + WORD mtType; + WORD mtHeaderSize; + WORD mtVersion; + DWORD mtSize; + WORD mtNoObjects; + DWORD mtMaxRecord; + WORD mtNoParameters; + } METAHEADER; + typedef struct tagMETAHEADER UNALIGNED *PMETAHEADER; + typedef struct tagMETAHEADER UNALIGNED *LPMETAHEADER; + +#include + + typedef struct tagENHMETARECORD { + DWORD iType; + DWORD nSize; + DWORD dParm[1]; + } ENHMETARECORD,*PENHMETARECORD,*LPENHMETARECORD; + + typedef struct tagENHMETAHEADER { + DWORD iType; + DWORD nSize; + RECTL rclBounds; + RECTL rclFrame; + DWORD dSignature; + DWORD nVersion; + DWORD nBytes; + DWORD nRecords; + WORD nHandles; + WORD sReserved; + DWORD nDescription; + DWORD offDescription; + DWORD nPalEntries; + SIZEL szlDevice; + SIZEL szlMillimeters; + DWORD cbPixelFormat; + DWORD offPixelFormat; + DWORD bOpenGL; + SIZEL szlMicrometers; + } ENHMETAHEADER,*PENHMETAHEADER,*LPENHMETAHEADER; +#endif + +#ifndef NOTEXTMETRIC +#define TMPF_FIXED_PITCH 0x01 +#define TMPF_VECTOR 0x02 +#define TMPF_DEVICE 0x08 +#define TMPF_TRUETYPE 0x04 + +#ifdef UNICODE + typedef WCHAR BCHAR; +#else + typedef BYTE BCHAR; +#endif + +#ifndef _TEXTMETRIC_DEFINED +#define _TEXTMETRIC_DEFINED + typedef struct tagTEXTMETRICA { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + BYTE tmFirstChar; + BYTE tmLastChar; + BYTE tmDefaultChar; + BYTE tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + } TEXTMETRICA,*PTEXTMETRICA,*NPTEXTMETRICA,*LPTEXTMETRICA; + + typedef struct tagTEXTMETRICW { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + WCHAR tmFirstChar; + WCHAR tmLastChar; + WCHAR tmDefaultChar; + WCHAR tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + } TEXTMETRICW,*PTEXTMETRICW,*NPTEXTMETRICW,*LPTEXTMETRICW; +#ifdef UNICODE + typedef TEXTMETRICW TEXTMETRIC; + typedef PTEXTMETRICW PTEXTMETRIC; + typedef NPTEXTMETRICW NPTEXTMETRIC; + typedef LPTEXTMETRICW LPTEXTMETRIC; +#else + typedef TEXTMETRICA TEXTMETRIC; + typedef PTEXTMETRICA PTEXTMETRIC; + typedef NPTEXTMETRICA NPTEXTMETRIC; + typedef LPTEXTMETRICA LPTEXTMETRIC; +#endif +#endif + +#define NTM_REGULAR 0x00000040L +#define NTM_BOLD 0x00000020L +#define NTM_ITALIC 0x00000001L + +#define NTM_NONNEGATIVE_AC 0x00010000 +#define NTM_PS_OPENTYPE 0x00020000 +#define NTM_TT_OPENTYPE 0x00040000 +#define NTM_MULTIPLEMASTER 0x00080000 +#define NTM_TYPE1 0x00100000 +#define NTM_DSIG 0x00200000 + +#include + typedef struct tagNEWTEXTMETRICA { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + BYTE tmFirstChar; + BYTE tmLastChar; + BYTE tmDefaultChar; + BYTE tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + DWORD ntmFlags; + UINT ntmSizeEM; + UINT ntmCellHeight; + UINT ntmAvgWidth; + } NEWTEXTMETRICA,*PNEWTEXTMETRICA,*NPNEWTEXTMETRICA,*LPNEWTEXTMETRICA; + + typedef struct tagNEWTEXTMETRICW { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + WCHAR tmFirstChar; + WCHAR tmLastChar; + WCHAR tmDefaultChar; + WCHAR tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; + DWORD ntmFlags; + UINT ntmSizeEM; + UINT ntmCellHeight; + UINT ntmAvgWidth; + } NEWTEXTMETRICW,*PNEWTEXTMETRICW,*NPNEWTEXTMETRICW,*LPNEWTEXTMETRICW; +#ifdef UNICODE + typedef NEWTEXTMETRICW NEWTEXTMETRIC; + typedef PNEWTEXTMETRICW PNEWTEXTMETRIC; + typedef NPNEWTEXTMETRICW NPNEWTEXTMETRIC; + typedef LPNEWTEXTMETRICW LPNEWTEXTMETRIC; +#else + typedef NEWTEXTMETRICA NEWTEXTMETRIC; + typedef PNEWTEXTMETRICA PNEWTEXTMETRIC; + typedef NPNEWTEXTMETRICA NPNEWTEXTMETRIC; + typedef LPNEWTEXTMETRICA LPNEWTEXTMETRIC; +#endif +#include + + typedef struct tagNEWTEXTMETRICEXA { + NEWTEXTMETRICA ntmTm; + FONTSIGNATURE ntmFontSig; + } NEWTEXTMETRICEXA; + + typedef struct tagNEWTEXTMETRICEXW { + NEWTEXTMETRICW ntmTm; + FONTSIGNATURE ntmFontSig; + } NEWTEXTMETRICEXW; +#ifdef UNICODE + typedef NEWTEXTMETRICEXW NEWTEXTMETRICEX; +#else + typedef NEWTEXTMETRICEXA NEWTEXTMETRICEX; +#endif +#endif + + typedef struct tagPELARRAY { + LONG paXCount; + LONG paYCount; + LONG paXExt; + LONG paYExt; + BYTE paRGBs; + } PELARRAY,*PPELARRAY,*NPPELARRAY,*LPPELARRAY; + + typedef struct tagLOGBRUSH { + UINT lbStyle; + COLORREF lbColor; + ULONG_PTR lbHatch; + } LOGBRUSH,*PLOGBRUSH,*NPLOGBRUSH,*LPLOGBRUSH; + + typedef struct tagLOGBRUSH32 { + UINT lbStyle; + COLORREF lbColor; + ULONG lbHatch; + } LOGBRUSH32,*PLOGBRUSH32,*NPLOGBRUSH32,*LPLOGBRUSH32; + + typedef LOGBRUSH PATTERN; + typedef PATTERN *PPATTERN; + typedef PATTERN *NPPATTERN; + typedef PATTERN *LPPATTERN; + + typedef struct tagLOGPEN { + UINT lopnStyle; + POINT lopnWidth; + COLORREF lopnColor; + } LOGPEN,*PLOGPEN,*NPLOGPEN,*LPLOGPEN; + + typedef struct tagEXTLOGPEN { + DWORD elpPenStyle; + DWORD elpWidth; + UINT elpBrushStyle; + COLORREF elpColor; + ULONG_PTR elpHatch; + DWORD elpNumEntries; + DWORD elpStyleEntry[1]; + } EXTLOGPEN,*PEXTLOGPEN,*NPEXTLOGPEN,*LPEXTLOGPEN; + +#ifndef _PALETTEENTRY_DEFINED +#define _PALETTEENTRY_DEFINED + typedef struct tagPALETTEENTRY { + BYTE peRed; + BYTE peGreen; + BYTE peBlue; + BYTE peFlags; + } PALETTEENTRY,*PPALETTEENTRY,*LPPALETTEENTRY; +#endif + +#ifndef _LOGPALETTE_DEFINED +#define _LOGPALETTE_DEFINED + + typedef struct tagLOGPALETTE { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[1]; + } LOGPALETTE,*PLOGPALETTE,*NPLOGPALETTE,*LPLOGPALETTE; +#endif + +#define LF_FACESIZE 32 + + typedef struct tagLOGFONTA { + LONG lfHeight; + LONG lfWidth; + LONG lfEscapement; + LONG lfOrientation; + LONG lfWeight; + BYTE lfItalic; + BYTE lfUnderline; + BYTE lfStrikeOut; + BYTE lfCharSet; + BYTE lfOutPrecision; + BYTE lfClipPrecision; + BYTE lfQuality; + BYTE lfPitchAndFamily; + CHAR lfFaceName[LF_FACESIZE]; + } LOGFONTA,*PLOGFONTA,*NPLOGFONTA,*LPLOGFONTA; + + typedef struct tagLOGFONTW { + LONG lfHeight; + LONG lfWidth; + LONG lfEscapement; + LONG lfOrientation; + LONG lfWeight; + BYTE lfItalic; + BYTE lfUnderline; + BYTE lfStrikeOut; + BYTE lfCharSet; + BYTE lfOutPrecision; + BYTE lfClipPrecision; + BYTE lfQuality; + BYTE lfPitchAndFamily; + WCHAR lfFaceName[LF_FACESIZE]; + } LOGFONTW,*PLOGFONTW,*NPLOGFONTW,*LPLOGFONTW; +#ifdef UNICODE + typedef LOGFONTW LOGFONT; + typedef PLOGFONTW PLOGFONT; + typedef NPLOGFONTW NPLOGFONT; + typedef LPLOGFONTW LPLOGFONT; +#else + typedef LOGFONTA LOGFONT; + typedef PLOGFONTA PLOGFONT; + typedef NPLOGFONTA NPLOGFONT; + typedef LPLOGFONTA LPLOGFONT; +#endif + +#define LF_FULLFACESIZE 64 + + typedef struct tagENUMLOGFONTA { + LOGFONTA elfLogFont; + BYTE elfFullName[LF_FULLFACESIZE]; + BYTE elfStyle[LF_FACESIZE]; + } ENUMLOGFONTA,*LPENUMLOGFONTA; + + typedef struct tagENUMLOGFONTW { + LOGFONTW elfLogFont; + WCHAR elfFullName[LF_FULLFACESIZE]; + WCHAR elfStyle[LF_FACESIZE]; + } ENUMLOGFONTW,*LPENUMLOGFONTW; +#ifdef UNICODE + typedef ENUMLOGFONTW ENUMLOGFONT; + typedef LPENUMLOGFONTW LPENUMLOGFONT; +#else + typedef ENUMLOGFONTA ENUMLOGFONT; + typedef LPENUMLOGFONTA LPENUMLOGFONT; +#endif + + typedef struct tagENUMLOGFONTEXA { + LOGFONTA elfLogFont; + BYTE elfFullName[LF_FULLFACESIZE]; + BYTE elfStyle[LF_FACESIZE]; + BYTE elfScript[LF_FACESIZE]; + } ENUMLOGFONTEXA,*LPENUMLOGFONTEXA; + + typedef struct tagENUMLOGFONTEXW { + LOGFONTW elfLogFont; + WCHAR elfFullName[LF_FULLFACESIZE]; + WCHAR elfStyle[LF_FACESIZE]; + WCHAR elfScript[LF_FACESIZE]; + } ENUMLOGFONTEXW,*LPENUMLOGFONTEXW; +#ifdef UNICODE + typedef ENUMLOGFONTEXW ENUMLOGFONTEX; + typedef LPENUMLOGFONTEXW LPENUMLOGFONTEX; +#else + typedef ENUMLOGFONTEXA ENUMLOGFONTEX; + typedef LPENUMLOGFONTEXA LPENUMLOGFONTEX; +#endif + +#define OUT_DEFAULT_PRECIS 0 +#define OUT_STRING_PRECIS 1 +#define OUT_CHARACTER_PRECIS 2 +#define OUT_STROKE_PRECIS 3 +#define OUT_TT_PRECIS 4 +#define OUT_DEVICE_PRECIS 5 +#define OUT_RASTER_PRECIS 6 +#define OUT_TT_ONLY_PRECIS 7 +#define OUT_OUTLINE_PRECIS 8 +#define OUT_SCREEN_OUTLINE_PRECIS 9 +#define OUT_PS_ONLY_PRECIS 10 + +#define CLIP_DEFAULT_PRECIS 0 +#define CLIP_CHARACTER_PRECIS 1 +#define CLIP_STROKE_PRECIS 2 +#define CLIP_MASK 0xf +#define CLIP_LH_ANGLES (1<<4) +#define CLIP_TT_ALWAYS (2<<4) +#define CLIP_DFA_DISABLE (4<<4) +#define CLIP_EMBEDDED (8<<4) + +#define DEFAULT_QUALITY 0 +#define DRAFT_QUALITY 1 +#define PROOF_QUALITY 2 +#define NONANTIALIASED_QUALITY 3 +#define ANTIALIASED_QUALITY 4 + +#define CLEARTYPE_QUALITY 5 +#define CLEARTYPE_NATURAL_QUALITY 6 + +#define DEFAULT_PITCH 0 +#define FIXED_PITCH 1 +#define VARIABLE_PITCH 2 +#define MONO_FONT 8 + +#define ANSI_CHARSET 0 +#define DEFAULT_CHARSET 1 +#define SYMBOL_CHARSET 2 +#define SHIFTJIS_CHARSET 128 +#define HANGEUL_CHARSET 129 +#define HANGUL_CHARSET 129 +#define GB2312_CHARSET 134 +#define CHINESEBIG5_CHARSET 136 +#define OEM_CHARSET 255 +#define JOHAB_CHARSET 130 +#define HEBREW_CHARSET 177 +#define ARABIC_CHARSET 178 +#define GREEK_CHARSET 161 +#define TURKISH_CHARSET 162 +#define VIETNAMESE_CHARSET 163 +#define THAI_CHARSET 222 +#define EASTEUROPE_CHARSET 238 +#define RUSSIAN_CHARSET 204 + +#define MAC_CHARSET 77 +#define BALTIC_CHARSET 186 + +#define FS_LATIN1 0x00000001L +#define FS_LATIN2 0x00000002L +#define FS_CYRILLIC 0x00000004L +#define FS_GREEK 0x00000008L +#define FS_TURKISH 0x00000010L +#define FS_HEBREW 0x00000020L +#define FS_ARABIC 0x00000040L +#define FS_BALTIC 0x00000080L +#define FS_VIETNAMESE 0x00000100L +#define FS_THAI 0x00010000L +#define FS_JISJAPAN 0x00020000L +#define FS_CHINESESIMP 0x00040000L +#define FS_WANSUNG 0x00080000L +#define FS_CHINESETRAD 0x00100000L +#define FS_JOHAB 0x00200000L +#define FS_SYMBOL 0x80000000L + +#define FF_DONTCARE (0<<4) +#define FF_ROMAN (1<<4) + +#define FF_SWISS (2<<4) + +#define FF_MODERN (3<<4) + +#define FF_SCRIPT (4<<4) +#define FF_DECORATIVE (5<<4) + +#define FW_DONTCARE 0 +#define FW_THIN 100 +#define FW_EXTRALIGHT 200 +#define FW_LIGHT 300 +#define FW_NORMAL 400 +#define FW_MEDIUM 500 +#define FW_SEMIBOLD 600 +#define FW_BOLD 700 +#define FW_EXTRABOLD 800 +#define FW_HEAVY 900 + +#define FW_ULTRALIGHT FW_EXTRALIGHT +#define FW_REGULAR FW_NORMAL +#define FW_DEMIBOLD FW_SEMIBOLD +#define FW_ULTRABOLD FW_EXTRABOLD +#define FW_BLACK FW_HEAVY + +#define PANOSE_COUNT 10 +#define PAN_FAMILYTYPE_INDEX 0 +#define PAN_SERIFSTYLE_INDEX 1 +#define PAN_WEIGHT_INDEX 2 +#define PAN_PROPORTION_INDEX 3 +#define PAN_CONTRAST_INDEX 4 +#define PAN_STROKEVARIATION_INDEX 5 +#define PAN_ARMSTYLE_INDEX 6 +#define PAN_LETTERFORM_INDEX 7 +#define PAN_MIDLINE_INDEX 8 +#define PAN_XHEIGHT_INDEX 9 + +#define PAN_CULTURE_LATIN 0 + + typedef struct tagPANOSE { + BYTE bFamilyType; + BYTE bSerifStyle; + BYTE bWeight; + BYTE bProportion; + BYTE bContrast; + BYTE bStrokeVariation; + BYTE bArmStyle; + BYTE bLetterform; + BYTE bMidline; + BYTE bXHeight; + } PANOSE,*LPPANOSE; + +#define PAN_ANY 0 +#define PAN_NO_FIT 1 + +#define PAN_FAMILY_TEXT_DISPLAY 2 +#define PAN_FAMILY_SCRIPT 3 +#define PAN_FAMILY_DECORATIVE 4 +#define PAN_FAMILY_PICTORIAL 5 + +#define PAN_SERIF_COVE 2 +#define PAN_SERIF_OBTUSE_COVE 3 +#define PAN_SERIF_SQUARE_COVE 4 +#define PAN_SERIF_OBTUSE_SQUARE_COVE 5 +#define PAN_SERIF_SQUARE 6 +#define PAN_SERIF_THIN 7 +#define PAN_SERIF_BONE 8 +#define PAN_SERIF_EXAGGERATED 9 +#define PAN_SERIF_TRIANGLE 10 +#define PAN_SERIF_NORMAL_SANS 11 +#define PAN_SERIF_OBTUSE_SANS 12 +#define PAN_SERIF_PERP_SANS 13 +#define PAN_SERIF_FLARED 14 +#define PAN_SERIF_ROUNDED 15 + +#define PAN_WEIGHT_VERY_LIGHT 2 +#define PAN_WEIGHT_LIGHT 3 +#define PAN_WEIGHT_THIN 4 +#define PAN_WEIGHT_BOOK 5 +#define PAN_WEIGHT_MEDIUM 6 +#define PAN_WEIGHT_DEMI 7 +#define PAN_WEIGHT_BOLD 8 +#define PAN_WEIGHT_HEAVY 9 +#define PAN_WEIGHT_BLACK 10 +#define PAN_WEIGHT_NORD 11 + +#define PAN_PROP_OLD_STYLE 2 +#define PAN_PROP_MODERN 3 +#define PAN_PROP_EVEN_WIDTH 4 +#define PAN_PROP_EXPANDED 5 +#define PAN_PROP_CONDENSED 6 +#define PAN_PROP_VERY_EXPANDED 7 +#define PAN_PROP_VERY_CONDENSED 8 +#define PAN_PROP_MONOSPACED 9 + +#define PAN_CONTRAST_NONE 2 +#define PAN_CONTRAST_VERY_LOW 3 +#define PAN_CONTRAST_LOW 4 +#define PAN_CONTRAST_MEDIUM_LOW 5 +#define PAN_CONTRAST_MEDIUM 6 +#define PAN_CONTRAST_MEDIUM_HIGH 7 +#define PAN_CONTRAST_HIGH 8 +#define PAN_CONTRAST_VERY_HIGH 9 + +#define PAN_STROKE_GRADUAL_DIAG 2 +#define PAN_STROKE_GRADUAL_TRAN 3 +#define PAN_STROKE_GRADUAL_VERT 4 +#define PAN_STROKE_GRADUAL_HORZ 5 +#define PAN_STROKE_RAPID_VERT 6 +#define PAN_STROKE_RAPID_HORZ 7 +#define PAN_STROKE_INSTANT_VERT 8 + +#define PAN_STRAIGHT_ARMS_HORZ 2 +#define PAN_STRAIGHT_ARMS_WEDGE 3 +#define PAN_STRAIGHT_ARMS_VERT 4 +#define PAN_STRAIGHT_ARMS_SINGLE_SERIF 5 +#define PAN_STRAIGHT_ARMS_DOUBLE_SERIF 6 +#define PAN_BENT_ARMS_HORZ 7 +#define PAN_BENT_ARMS_WEDGE 8 +#define PAN_BENT_ARMS_VERT 9 +#define PAN_BENT_ARMS_SINGLE_SERIF 10 +#define PAN_BENT_ARMS_DOUBLE_SERIF 11 + +#define PAN_LETT_NORMAL_CONTACT 2 +#define PAN_LETT_NORMAL_WEIGHTED 3 +#define PAN_LETT_NORMAL_BOXED 4 +#define PAN_LETT_NORMAL_FLATTENED 5 +#define PAN_LETT_NORMAL_ROUNDED 6 +#define PAN_LETT_NORMAL_OFF_CENTER 7 +#define PAN_LETT_NORMAL_SQUARE 8 +#define PAN_LETT_OBLIQUE_CONTACT 9 +#define PAN_LETT_OBLIQUE_WEIGHTED 10 +#define PAN_LETT_OBLIQUE_BOXED 11 +#define PAN_LETT_OBLIQUE_FLATTENED 12 +#define PAN_LETT_OBLIQUE_ROUNDED 13 +#define PAN_LETT_OBLIQUE_OFF_CENTER 14 +#define PAN_LETT_OBLIQUE_SQUARE 15 + +#define PAN_MIDLINE_STANDARD_TRIMMED 2 +#define PAN_MIDLINE_STANDARD_POINTED 3 +#define PAN_MIDLINE_STANDARD_SERIFED 4 +#define PAN_MIDLINE_HIGH_TRIMMED 5 +#define PAN_MIDLINE_HIGH_POINTED 6 +#define PAN_MIDLINE_HIGH_SERIFED 7 +#define PAN_MIDLINE_CONSTANT_TRIMMED 8 +#define PAN_MIDLINE_CONSTANT_POINTED 9 +#define PAN_MIDLINE_CONSTANT_SERIFED 10 +#define PAN_MIDLINE_LOW_TRIMMED 11 +#define PAN_MIDLINE_LOW_POINTED 12 +#define PAN_MIDLINE_LOW_SERIFED 13 + +#define PAN_XHEIGHT_CONSTANT_SMALL 2 +#define PAN_XHEIGHT_CONSTANT_STD 3 +#define PAN_XHEIGHT_CONSTANT_LARGE 4 +#define PAN_XHEIGHT_DUCKING_SMALL 5 +#define PAN_XHEIGHT_DUCKING_STD 6 +#define PAN_XHEIGHT_DUCKING_LARGE 7 + +#define ELF_VENDOR_SIZE 4 + + typedef struct tagEXTLOGFONTA { + LOGFONTA elfLogFont; + BYTE elfFullName[LF_FULLFACESIZE]; + BYTE elfStyle[LF_FACESIZE]; + DWORD elfVersion; + DWORD elfStyleSize; + DWORD elfMatch; + DWORD elfReserved; + BYTE elfVendorId[ELF_VENDOR_SIZE]; + DWORD elfCulture; + PANOSE elfPanose; + } EXTLOGFONTA,*PEXTLOGFONTA,*NPEXTLOGFONTA,*LPEXTLOGFONTA; + + typedef struct tagEXTLOGFONTW { + LOGFONTW elfLogFont; + WCHAR elfFullName[LF_FULLFACESIZE]; + WCHAR elfStyle[LF_FACESIZE]; + DWORD elfVersion; + DWORD elfStyleSize; + DWORD elfMatch; + DWORD elfReserved; + BYTE elfVendorId[ELF_VENDOR_SIZE]; + DWORD elfCulture; + PANOSE elfPanose; + } EXTLOGFONTW,*PEXTLOGFONTW,*NPEXTLOGFONTW,*LPEXTLOGFONTW; +#ifdef UNICODE + typedef EXTLOGFONTW EXTLOGFONT; + typedef PEXTLOGFONTW PEXTLOGFONT; + typedef NPEXTLOGFONTW NPEXTLOGFONT; + typedef LPEXTLOGFONTW LPEXTLOGFONT; +#else + typedef EXTLOGFONTA EXTLOGFONT; + typedef PEXTLOGFONTA PEXTLOGFONT; + typedef NPEXTLOGFONTA NPEXTLOGFONT; + typedef LPEXTLOGFONTA LPEXTLOGFONT; +#endif + +#define ELF_VERSION 0 +#define ELF_CULTURE_LATIN 0 + +#define RASTER_FONTTYPE 0x0001 +#define DEVICE_FONTTYPE 0x002 +#define TRUETYPE_FONTTYPE 0x004 + +#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) +#define PALETTERGB(r,g,b) (0x02000000 | RGB(r,g,b)) +#define PALETTEINDEX(i) ((COLORREF)(0x01000000 | (DWORD)(WORD)(i))) + +#define PC_RESERVED 0x01 +#define PC_EXPLICIT 0x02 +#define PC_NOCOLLAPSE 0x04 + +#define GetRValue(rgb) (LOBYTE(rgb)) +#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8)) +#define GetBValue(rgb) (LOBYTE((rgb)>>16)) + +#define TRANSPARENT 1 +#define OPAQUE 2 +#define BKMODE_LAST 2 + +#define GM_COMPATIBLE 1 +#define GM_ADVANCED 2 +#define GM_LAST 2 + +#define PT_CLOSEFIGURE 0x01 +#define PT_LINETO 0x02 +#define PT_BEZIERTO 0x04 +#define PT_MOVETO 0x06 + +#define MM_TEXT 1 +#define MM_LOMETRIC 2 +#define MM_HIMETRIC 3 +#define MM_LOENGLISH 4 +#define MM_HIENGLISH 5 +#define MM_TWIPS 6 +#define MM_ISOTROPIC 7 +#define MM_ANISOTROPIC 8 + +#define MM_MIN MM_TEXT +#define MM_MAX MM_ANISOTROPIC +#define MM_MAX_FIXEDSCALE MM_TWIPS + +#define ABSOLUTE 1 +#define RELATIVE 2 + +#define WHITE_BRUSH 0 +#define LTGRAY_BRUSH 1 +#define GRAY_BRUSH 2 +#define DKGRAY_BRUSH 3 +#define BLACK_BRUSH 4 +#define NULL_BRUSH 5 +#define HOLLOW_BRUSH NULL_BRUSH +#define WHITE_PEN 6 +#define BLACK_PEN 7 +#define NULL_PEN 8 +#define OEM_FIXED_FONT 10 +#define ANSI_FIXED_FONT 11 +#define ANSI_VAR_FONT 12 +#define SYSTEM_FONT 13 +#define DEVICE_DEFAULT_FONT 14 +#define DEFAULT_PALETTE 15 +#define SYSTEM_FIXED_FONT 16 + +#define DEFAULT_GUI_FONT 17 + +#define DC_BRUSH 18 +#define DC_PEN 19 + +#define STOCK_LAST 19 + +#define CLR_INVALID 0xFFFFFFFF + +#define BS_SOLID 0 +#define BS_NULL 1 +#define BS_HOLLOW BS_NULL +#define BS_HATCHED 2 +#define BS_PATTERN 3 +#define BS_INDEXED 4 +#define BS_DIBPATTERN 5 +#define BS_DIBPATTERNPT 6 +#define BS_PATTERN8X8 7 +#define BS_DIBPATTERN8X8 8 +#define BS_MONOPATTERN 9 + +#define HS_HORIZONTAL 0 +#define HS_VERTICAL 1 +#define HS_FDIAGONAL 2 +#define HS_BDIAGONAL 3 +#define HS_CROSS 4 +#define HS_DIAGCROSS 5 + +#define PS_SOLID 0 +#define PS_DASH 1 +#define PS_DOT 2 +#define PS_DASHDOT 3 +#define PS_DASHDOTDOT 4 +#define PS_NULL 5 +#define PS_INSIDEFRAME 6 +#define PS_USERSTYLE 7 +#define PS_ALTERNATE 8 +#define PS_STYLE_MASK 0x0000000F + +#define PS_ENDCAP_ROUND 0x00000000 +#define PS_ENDCAP_SQUARE 0x00000100 +#define PS_ENDCAP_FLAT 0x00000200 +#define PS_ENDCAP_MASK 0x00000F00 + +#define PS_JOIN_ROUND 0x00000000 +#define PS_JOIN_BEVEL 0x00001000 +#define PS_JOIN_MITER 0x00002000 +#define PS_JOIN_MASK 0x0000F000 + +#define PS_COSMETIC 0x00000000 +#define PS_GEOMETRIC 0x00010000 +#define PS_TYPE_MASK 0x000F0000 + +#define AD_COUNTERCLOCKWISE 1 +#define AD_CLOCKWISE 2 + +#define DRIVERVERSION 0 +#define TECHNOLOGY 2 +#define HORZSIZE 4 +#define VERTSIZE 6 +#define HORZRES 8 +#define VERTRES 10 +#define BITSPIXEL 12 +#define PLANES 14 +#define NUMBRUSHES 16 +#define NUMPENS 18 +#define NUMMARKERS 20 +#define NUMFONTS 22 +#define NUMCOLORS 24 +#define PDEVICESIZE 26 +#define CURVECAPS 28 +#define LINECAPS 30 +#define POLYGONALCAPS 32 +#define TEXTCAPS 34 +#define CLIPCAPS 36 +#define RASTERCAPS 38 +#define ASPECTX 40 +#define ASPECTY 42 +#define ASPECTXY 44 + +#define LOGPIXELSX 88 +#define LOGPIXELSY 90 + +#define SIZEPALETTE 104 +#define NUMRESERVED 106 +#define COLORRES 108 + +#define PHYSICALWIDTH 110 +#define PHYSICALHEIGHT 111 +#define PHYSICALOFFSETX 112 +#define PHYSICALOFFSETY 113 +#define SCALINGFACTORX 114 +#define SCALINGFACTORY 115 + +#define VREFRESH 116 + +#define DESKTOPVERTRES 117 + +#define DESKTOPHORZRES 118 + +#define BLTALIGNMENT 119 + +#define SHADEBLENDCAPS 120 +#define COLORMGMTCAPS 121 + +#ifndef NOGDICAPMASKS +#define DT_PLOTTER 0 +#define DT_RASDISPLAY 1 +#define DT_RASPRINTER 2 +#define DT_RASCAMERA 3 +#define DT_CHARSTREAM 4 +#define DT_METAFILE 5 +#define DT_DISPFILE 6 + +#define CC_NONE 0 +#define CC_CIRCLES 1 +#define CC_PIE 2 +#define CC_CHORD 4 +#define CC_ELLIPSES 8 +#define CC_WIDE 16 +#define CC_STYLED 32 +#define CC_WIDESTYLED 64 +#define CC_INTERIORS 128 +#define CC_ROUNDRECT 256 + +#define LC_NONE 0 +#define LC_POLYLINE 2 +#define LC_MARKER 4 +#define LC_POLYMARKER 8 +#define LC_WIDE 16 +#define LC_STYLED 32 +#define LC_WIDESTYLED 64 +#define LC_INTERIORS 128 + +#define PC_NONE 0 +#define PC_POLYGON 1 +#define PC_RECTANGLE 2 +#define PC_WINDPOLYGON 4 +#define PC_TRAPEZOID 4 +#define PC_SCANLINE 8 +#define PC_WIDE 16 +#define PC_STYLED 32 +#define PC_WIDESTYLED 64 +#define PC_INTERIORS 128 +#define PC_POLYPOLYGON 256 +#define PC_PATHS 512 + +#define CP_NONE 0 +#define CP_RECTANGLE 1 +#define CP_REGION 2 + +#define TC_OP_CHARACTER 0x00000001 +#define TC_OP_STROKE 0x00000002 +#define TC_CP_STROKE 0x00000004 +#define TC_CR_90 0x00000008 +#define TC_CR_ANY 0x00000010 +#define TC_SF_X_YINDEP 0x00000020 +#define TC_SA_DOUBLE 0x00000040 +#define TC_SA_INTEGER 0x00000080 +#define TC_SA_CONTIN 0x00000100 +#define TC_EA_DOUBLE 0x00000200 +#define TC_IA_ABLE 0x00000400 +#define TC_UA_ABLE 0x00000800 +#define TC_SO_ABLE 0x00001000 +#define TC_RA_ABLE 0x00002000 +#define TC_VA_ABLE 0x00004000 +#define TC_RESERVED 0x00008000 +#define TC_SCROLLBLT 0x00010000 +#endif + +#define RC_NONE +#define RC_BITBLT 1 +#define RC_BANDING 2 +#define RC_SCALING 4 +#define RC_BITMAP64 8 +#define RC_GDI20_OUTPUT 0x0010 +#define RC_GDI20_STATE 0x0020 +#define RC_SAVEBITMAP 0x0040 +#define RC_DI_BITMAP 0x0080 +#define RC_PALETTE 0x0100 +#define RC_DIBTODEV 0x0200 +#define RC_BIGFONT 0x0400 +#define RC_STRETCHBLT 0x0800 +#define RC_FLOODFILL 0x1000 +#define RC_STRETCHDIB 0x2000 +#define RC_OP_DX_OUTPUT 0x4000 +#define RC_DEVBITS 0x8000 + +#define SB_NONE 0x00000000 +#define SB_CONST_ALPHA 0x00000001 +#define SB_PIXEL_ALPHA 0x00000002 +#define SB_PREMULT_ALPHA 0x00000004 + +#define SB_GRAD_RECT 0x00000010 +#define SB_GRAD_TRI 0x00000020 + +#define CM_NONE 0x00000000 +#define CM_DEVICE_ICM 0x00000001 +#define CM_GAMMA_RAMP 0x00000002 +#define CM_CMYK_COLOR 0x00000004 + +#define DIB_RGB_COLORS 0 +#define DIB_PAL_COLORS 1 + +#define SYSPAL_ERROR 0 +#define SYSPAL_STATIC 1 +#define SYSPAL_NOSTATIC 2 +#define SYSPAL_NOSTATIC256 3 + +#define CBM_INIT 0x04L + +#define FLOODFILLBORDER 0 +#define FLOODFILLSURFACE 1 + +#define CCHDEVICENAME 32 + +#define CCHFORMNAME 32 + + typedef struct _devicemodeA { + BYTE dmDeviceName[CCHDEVICENAME]; + WORD dmSpecVersion; + WORD dmDriverVersion; + WORD dmSize; + WORD dmDriverExtra; + DWORD dmFields; + union { + struct { + short dmOrientation; + short dmPaperSize; + short dmPaperLength; + short dmPaperWidth; + short dmScale; + short dmCopies; + short dmDefaultSource; + short dmPrintQuality; + }; + struct { + POINTL dmPosition; + DWORD dmDisplayOrientation; + DWORD dmDisplayFixedOutput; + }; + }; + short dmColor; + short dmDuplex; + short dmYResolution; + short dmTTOption; + short dmCollate; + BYTE dmFormName[CCHFORMNAME]; + WORD dmLogPixels; + DWORD dmBitsPerPel; + DWORD dmPelsWidth; + DWORD dmPelsHeight; + union { + DWORD dmDisplayFlags; + DWORD dmNup; + }; + DWORD dmDisplayFrequency; + DWORD dmICMMethod; + DWORD dmICMIntent; + DWORD dmMediaType; + DWORD dmDitherType; + DWORD dmReserved1; + DWORD dmReserved2; + DWORD dmPanningWidth; + DWORD dmPanningHeight; + } DEVMODEA,*PDEVMODEA,*NPDEVMODEA,*LPDEVMODEA; + + typedef struct _devicemodeW { + WCHAR dmDeviceName[CCHDEVICENAME]; + WORD dmSpecVersion; + WORD dmDriverVersion; + WORD dmSize; + WORD dmDriverExtra; + DWORD dmFields; + union { + struct { + short dmOrientation; + short dmPaperSize; + short dmPaperLength; + short dmPaperWidth; + short dmScale; + short dmCopies; + short dmDefaultSource; + short dmPrintQuality; + }; + struct { + POINTL dmPosition; + DWORD dmDisplayOrientation; + DWORD dmDisplayFixedOutput; + }; + }; + short dmColor; + short dmDuplex; + short dmYResolution; + short dmTTOption; + short dmCollate; + WCHAR dmFormName[CCHFORMNAME]; + WORD dmLogPixels; + DWORD dmBitsPerPel; + DWORD dmPelsWidth; + DWORD dmPelsHeight; + union { + DWORD dmDisplayFlags; + DWORD dmNup; + }; + DWORD dmDisplayFrequency; + DWORD dmICMMethod; + DWORD dmICMIntent; + DWORD dmMediaType; + DWORD dmDitherType; + DWORD dmReserved1; + DWORD dmReserved2; + DWORD dmPanningWidth; + DWORD dmPanningHeight; + } DEVMODEW,*PDEVMODEW,*NPDEVMODEW,*LPDEVMODEW; +#ifdef UNICODE + typedef DEVMODEW DEVMODE; + typedef PDEVMODEW PDEVMODE; + typedef NPDEVMODEW NPDEVMODE; + typedef LPDEVMODEW LPDEVMODE; +#else + typedef DEVMODEA DEVMODE; + typedef PDEVMODEA PDEVMODE; + typedef NPDEVMODEA NPDEVMODE; + typedef LPDEVMODEA LPDEVMODE; +#endif + +#define DM_SPECVERSION 0x0401 + +#define DM_ORIENTATION 0x00000001L +#define DM_PAPERSIZE 0x00000002L +#define DM_PAPERLENGTH 0x00000004L +#define DM_PAPERWIDTH 0x00000008L +#define DM_SCALE 0x00000010L +#define DM_POSITION 0x00000020L +#define DM_NUP 0x00000040L +#define DM_DISPLAYORIENTATION 0x00000080L +#define DM_COPIES 0x00000100L +#define DM_DEFAULTSOURCE 0x00000200L +#define DM_PRINTQUALITY 0x00000400L +#define DM_COLOR 0x00000800L +#define DM_DUPLEX 0x00001000L +#define DM_YRESOLUTION 0x00002000L +#define DM_TTOPTION 0x00004000L +#define DM_COLLATE 0x00008000L +#define DM_FORMNAME 0x00010000L +#define DM_LOGPIXELS 0x00020000L +#define DM_BITSPERPEL 0x00040000L +#define DM_PELSWIDTH 0x00080000L +#define DM_PELSHEIGHT 0x00100000L +#define DM_DISPLAYFLAGS 0x00200000L +#define DM_DISPLAYFREQUENCY 0x00400000L +#define DM_ICMMETHOD 0x00800000L +#define DM_ICMINTENT 0x01000000L +#define DM_MEDIATYPE 0x02000000L +#define DM_DITHERTYPE 0x04000000L +#define DM_PANNINGWIDTH 0x08000000L +#define DM_PANNINGHEIGHT 0x10000000L +#define DM_DISPLAYFIXEDOUTPUT 0x20000000L + +#define DMORIENT_PORTRAIT 1 +#define DMORIENT_LANDSCAPE 2 + +#define DMPAPER_FIRST DMPAPER_LETTER +#define DMPAPER_LETTER 1 +#define DMPAPER_LETTERSMALL 2 +#define DMPAPER_TABLOID 3 +#define DMPAPER_LEDGER 4 +#define DMPAPER_LEGAL 5 +#define DMPAPER_STATEMENT 6 +#define DMPAPER_EXECUTIVE 7 +#define DMPAPER_A3 8 +#define DMPAPER_A4 9 +#define DMPAPER_A4SMALL 10 +#define DMPAPER_A5 11 +#define DMPAPER_B4 12 +#define DMPAPER_B5 13 +#define DMPAPER_FOLIO 14 +#define DMPAPER_QUARTO 15 +#define DMPAPER_10X14 16 +#define DMPAPER_11X17 17 +#define DMPAPER_NOTE 18 +#define DMPAPER_ENV_9 19 +#define DMPAPER_ENV_10 20 +#define DMPAPER_ENV_11 21 +#define DMPAPER_ENV_12 22 +#define DMPAPER_ENV_14 23 +#define DMPAPER_CSHEET 24 +#define DMPAPER_DSHEET 25 +#define DMPAPER_ESHEET 26 +#define DMPAPER_ENV_DL 27 +#define DMPAPER_ENV_C5 28 +#define DMPAPER_ENV_C3 29 +#define DMPAPER_ENV_C4 30 +#define DMPAPER_ENV_C6 31 +#define DMPAPER_ENV_C65 32 +#define DMPAPER_ENV_B4 33 +#define DMPAPER_ENV_B5 34 +#define DMPAPER_ENV_B6 35 +#define DMPAPER_ENV_ITALY 36 +#define DMPAPER_ENV_MONARCH 37 +#define DMPAPER_ENV_PERSONAL 38 +#define DMPAPER_FANFOLD_US 39 +#define DMPAPER_FANFOLD_STD_GERMAN 40 +#define DMPAPER_FANFOLD_LGL_GERMAN 41 +#define DMPAPER_ISO_B4 42 +#define DMPAPER_JAPANESE_POSTCARD 43 +#define DMPAPER_9X11 44 +#define DMPAPER_10X11 45 +#define DMPAPER_15X11 46 +#define DMPAPER_ENV_INVITE 47 +#define DMPAPER_RESERVED_48 48 +#define DMPAPER_RESERVED_49 49 +#define DMPAPER_LETTER_EXTRA 50 +#define DMPAPER_LEGAL_EXTRA 51 +#define DMPAPER_TABLOID_EXTRA 52 +#define DMPAPER_A4_EXTRA 53 +#define DMPAPER_LETTER_TRANSVERSE 54 +#define DMPAPER_A4_TRANSVERSE 55 +#define DMPAPER_LETTER_EXTRA_TRANSVERSE 56 +#define DMPAPER_A_PLUS 57 +#define DMPAPER_B_PLUS 58 +#define DMPAPER_LETTER_PLUS 59 +#define DMPAPER_A4_PLUS 60 +#define DMPAPER_A5_TRANSVERSE 61 +#define DMPAPER_B5_TRANSVERSE 62 +#define DMPAPER_A3_EXTRA 63 +#define DMPAPER_A5_EXTRA 64 +#define DMPAPER_B5_EXTRA 65 +#define DMPAPER_A2 66 +#define DMPAPER_A3_TRANSVERSE 67 +#define DMPAPER_A3_EXTRA_TRANSVERSE 68 +#define DMPAPER_DBL_JAPANESE_POSTCARD 69 +#define DMPAPER_A6 70 +#define DMPAPER_JENV_KAKU2 71 +#define DMPAPER_JENV_KAKU3 72 +#define DMPAPER_JENV_CHOU3 73 +#define DMPAPER_JENV_CHOU4 74 +#define DMPAPER_LETTER_ROTATED 75 +#define DMPAPER_A3_ROTATED 76 +#define DMPAPER_A4_ROTATED 77 +#define DMPAPER_A5_ROTATED 78 +#define DMPAPER_B4_JIS_ROTATED 79 +#define DMPAPER_B5_JIS_ROTATED 80 +#define DMPAPER_JAPANESE_POSTCARD_ROTATED 81 +#define DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED 82 +#define DMPAPER_A6_ROTATED 83 +#define DMPAPER_JENV_KAKU2_ROTATED 84 +#define DMPAPER_JENV_KAKU3_ROTATED 85 +#define DMPAPER_JENV_CHOU3_ROTATED 86 +#define DMPAPER_JENV_CHOU4_ROTATED 87 +#define DMPAPER_B6_JIS 88 +#define DMPAPER_B6_JIS_ROTATED 89 +#define DMPAPER_12X11 90 +#define DMPAPER_JENV_YOU4 91 +#define DMPAPER_JENV_YOU4_ROTATED 92 +#define DMPAPER_P16K 93 +#define DMPAPER_P32K 94 +#define DMPAPER_P32KBIG 95 +#define DMPAPER_PENV_1 96 +#define DMPAPER_PENV_2 97 +#define DMPAPER_PENV_3 98 +#define DMPAPER_PENV_4 99 +#define DMPAPER_PENV_5 100 +#define DMPAPER_PENV_6 101 +#define DMPAPER_PENV_7 102 +#define DMPAPER_PENV_8 103 +#define DMPAPER_PENV_9 104 +#define DMPAPER_PENV_10 105 +#define DMPAPER_P16K_ROTATED 106 +#define DMPAPER_P32K_ROTATED 107 +#define DMPAPER_P32KBIG_ROTATED 108 +#define DMPAPER_PENV_1_ROTATED 109 +#define DMPAPER_PENV_2_ROTATED 110 +#define DMPAPER_PENV_3_ROTATED 111 +#define DMPAPER_PENV_4_ROTATED 112 +#define DMPAPER_PENV_5_ROTATED 113 +#define DMPAPER_PENV_6_ROTATED 114 +#define DMPAPER_PENV_7_ROTATED 115 +#define DMPAPER_PENV_8_ROTATED 116 +#define DMPAPER_PENV_9_ROTATED 117 +#define DMPAPER_PENV_10_ROTATED 118 + +#define DMPAPER_LAST DMPAPER_PENV_10_ROTATED + +#define DMPAPER_USER 256 + +#define DMBIN_FIRST DMBIN_UPPER +#define DMBIN_UPPER 1 +#define DMBIN_ONLYONE 1 +#define DMBIN_LOWER 2 +#define DMBIN_MIDDLE 3 +#define DMBIN_MANUAL 4 +#define DMBIN_ENVELOPE 5 +#define DMBIN_ENVMANUAL 6 +#define DMBIN_AUTO 7 +#define DMBIN_TRACTOR 8 +#define DMBIN_SMALLFMT 9 +#define DMBIN_LARGEFMT 10 +#define DMBIN_LARGECAPACITY 11 +#define DMBIN_CASSETTE 14 +#define DMBIN_FORMSOURCE 15 +#define DMBIN_LAST DMBIN_FORMSOURCE + +#define DMBIN_USER 256 + +#define DMRES_DRAFT (-1) +#define DMRES_LOW (-2) +#define DMRES_MEDIUM (-3) +#define DMRES_HIGH (-4) + +#define DMCOLOR_MONOCHROME 1 +#define DMCOLOR_COLOR 2 + +#define DMDUP_SIMPLEX 1 +#define DMDUP_VERTICAL 2 +#define DMDUP_HORIZONTAL 3 + +#define DMTT_BITMAP 1 +#define DMTT_DOWNLOAD 2 +#define DMTT_SUBDEV 3 +#define DMTT_DOWNLOAD_OUTLINE 4 + +#define DMCOLLATE_FALSE 0 +#define DMCOLLATE_TRUE 1 + +#define DMDO_DEFAULT 0 +#define DMDO_90 1 +#define DMDO_180 2 +#define DMDO_270 3 + +#define DMDFO_DEFAULT 0 +#define DMDFO_STRETCH 1 +#define DMDFO_CENTER 2 + +#define DMDISPLAYFLAGS_TEXTMODE 0x00000004 + +#define DMNUP_SYSTEM 1 +#define DMNUP_ONEUP 2 + +#define DMICMMETHOD_NONE 1 +#define DMICMMETHOD_SYSTEM 2 +#define DMICMMETHOD_DRIVER 3 +#define DMICMMETHOD_DEVICE 4 + +#define DMICMMETHOD_USER 256 + +#define DMICM_SATURATE 1 +#define DMICM_CONTRAST 2 +#define DMICM_COLORIMETRIC 3 +#define DMICM_ABS_COLORIMETRIC 4 + +#define DMICM_USER 256 + +#define DMMEDIA_STANDARD 1 +#define DMMEDIA_TRANSPARENCY 2 +#define DMMEDIA_GLOSSY 3 + +#define DMMEDIA_USER 256 + +#define DMDITHER_NONE 1 +#define DMDITHER_COARSE 2 +#define DMDITHER_FINE 3 +#define DMDITHER_LINEART 4 +#define DMDITHER_ERRORDIFFUSION 5 +#define DMDITHER_RESERVED6 6 +#define DMDITHER_RESERVED7 7 +#define DMDITHER_RESERVED8 8 +#define DMDITHER_RESERVED9 9 +#define DMDITHER_GRAYSCALE 10 + +#define DMDITHER_USER 256 + + typedef struct _DISPLAY_DEVICEA { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD StateFlags; + CHAR DeviceID[128]; + CHAR DeviceKey[128]; + } DISPLAY_DEVICEA,*PDISPLAY_DEVICEA,*LPDISPLAY_DEVICEA; + typedef struct _DISPLAY_DEVICEW { + DWORD cb; + WCHAR DeviceName[32]; + WCHAR DeviceString[128]; + DWORD StateFlags; + WCHAR DeviceID[128]; + WCHAR DeviceKey[128]; + } DISPLAY_DEVICEW,*PDISPLAY_DEVICEW,*LPDISPLAY_DEVICEW; +#ifdef UNICODE + typedef DISPLAY_DEVICEW DISPLAY_DEVICE; + typedef PDISPLAY_DEVICEW PDISPLAY_DEVICE; + typedef LPDISPLAY_DEVICEW LPDISPLAY_DEVICE; +#else + typedef DISPLAY_DEVICEA DISPLAY_DEVICE; + typedef PDISPLAY_DEVICEA PDISPLAY_DEVICE; + typedef LPDISPLAY_DEVICEA LPDISPLAY_DEVICE; +#endif + +#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 +#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002 +#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 +#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 +#define DISPLAY_DEVICE_VGA_COMPATIBLE 0x00000010 +#define DISPLAY_DEVICE_REMOVABLE 0x00000020 +#define DISPLAY_DEVICE_MODESPRUNED 0x08000000 +#define DISPLAY_DEVICE_REMOTE 0x04000000 +#define DISPLAY_DEVICE_DISCONNECT 0x02000000 + +#define DISPLAY_DEVICE_ACTIVE 0x00000001 +#define DISPLAY_DEVICE_ATTACHED 0x00000002 + +#define RDH_RECTANGLES 1 + + typedef struct _RGNDATAHEADER { + DWORD dwSize; + DWORD iType; + DWORD nCount; + DWORD nRgnSize; + RECT rcBound; + } RGNDATAHEADER,*PRGNDATAHEADER; + + typedef struct _RGNDATA { + RGNDATAHEADER rdh; + char Buffer[1]; + } RGNDATA,*PRGNDATA,*NPRGNDATA,*LPRGNDATA; + +#define SYSRGN 4 + + typedef struct _ABC { + int abcA; + UINT abcB; + int abcC; + } ABC,*PABC,*NPABC,*LPABC; + + typedef struct _ABCFLOAT { + FLOAT abcfA; + FLOAT abcfB; + FLOAT abcfC; + } ABCFLOAT,*PABCFLOAT,*NPABCFLOAT,*LPABCFLOAT; + +#ifndef NOTEXTMETRIC + + typedef struct _OUTLINETEXTMETRICA { + UINT otmSize; + TEXTMETRICA otmTextMetrics; + BYTE otmFiller; + PANOSE otmPanoseNumber; + UINT otmfsSelection; + UINT otmfsType; + int otmsCharSlopeRise; + int otmsCharSlopeRun; + int otmItalicAngle; + UINT otmEMSquare; + int otmAscent; + int otmDescent; + UINT otmLineGap; + UINT otmsCapEmHeight; + UINT otmsXHeight; + RECT otmrcFontBox; + int otmMacAscent; + int otmMacDescent; + UINT otmMacLineGap; + UINT otmusMinimumPPEM; + POINT otmptSubscriptSize; + POINT otmptSubscriptOffset; + POINT otmptSuperscriptSize; + POINT otmptSuperscriptOffset; + UINT otmsStrikeoutSize; + int otmsStrikeoutPosition; + int otmsUnderscoreSize; + int otmsUnderscorePosition; + PSTR otmpFamilyName; + PSTR otmpFaceName; + PSTR otmpStyleName; + PSTR otmpFullName; + } OUTLINETEXTMETRICA,*POUTLINETEXTMETRICA,*NPOUTLINETEXTMETRICA,*LPOUTLINETEXTMETRICA; + + typedef struct _OUTLINETEXTMETRICW { + UINT otmSize; + TEXTMETRICW otmTextMetrics; + BYTE otmFiller; + PANOSE otmPanoseNumber; + UINT otmfsSelection; + UINT otmfsType; + int otmsCharSlopeRise; + int otmsCharSlopeRun; + int otmItalicAngle; + UINT otmEMSquare; + int otmAscent; + int otmDescent; + UINT otmLineGap; + UINT otmsCapEmHeight; + UINT otmsXHeight; + RECT otmrcFontBox; + int otmMacAscent; + int otmMacDescent; + UINT otmMacLineGap; + UINT otmusMinimumPPEM; + POINT otmptSubscriptSize; + POINT otmptSubscriptOffset; + POINT otmptSuperscriptSize; + POINT otmptSuperscriptOffset; + UINT otmsStrikeoutSize; + int otmsStrikeoutPosition; + int otmsUnderscoreSize; + int otmsUnderscorePosition; + PSTR otmpFamilyName; + PSTR otmpFaceName; + PSTR otmpStyleName; + PSTR otmpFullName; + } OUTLINETEXTMETRICW,*POUTLINETEXTMETRICW,*NPOUTLINETEXTMETRICW,*LPOUTLINETEXTMETRICW; +#ifdef UNICODE + typedef OUTLINETEXTMETRICW OUTLINETEXTMETRIC; + typedef POUTLINETEXTMETRICW POUTLINETEXTMETRIC; + typedef NPOUTLINETEXTMETRICW NPOUTLINETEXTMETRIC; + typedef LPOUTLINETEXTMETRICW LPOUTLINETEXTMETRIC; +#else + typedef OUTLINETEXTMETRICA OUTLINETEXTMETRIC; + typedef POUTLINETEXTMETRICA POUTLINETEXTMETRIC; + typedef NPOUTLINETEXTMETRICA NPOUTLINETEXTMETRIC; + typedef LPOUTLINETEXTMETRICA LPOUTLINETEXTMETRIC; +#endif +#endif + + typedef struct tagPOLYTEXTA { + int x; + int y; + UINT n; + LPCSTR lpstr; + UINT uiFlags; + RECT rcl; + int *pdx; + } POLYTEXTA,*PPOLYTEXTA,*NPPOLYTEXTA,*LPPOLYTEXTA; + + typedef struct tagPOLYTEXTW { + int x; + int y; + UINT n; + LPCWSTR lpstr; + UINT uiFlags; + RECT rcl; + int *pdx; + } POLYTEXTW,*PPOLYTEXTW,*NPPOLYTEXTW,*LPPOLYTEXTW; +#ifdef UNICODE + typedef POLYTEXTW POLYTEXT; + typedef PPOLYTEXTW PPOLYTEXT; + typedef NPPOLYTEXTW NPPOLYTEXT; + typedef LPPOLYTEXTW LPPOLYTEXT; +#else + typedef POLYTEXTA POLYTEXT; + typedef PPOLYTEXTA PPOLYTEXT; + typedef NPPOLYTEXTA NPPOLYTEXT; + typedef LPPOLYTEXTA LPPOLYTEXT; +#endif + + typedef struct _FIXED { + WORD fract; + short value; + } FIXED; + + typedef struct _MAT2 { + FIXED eM11; + FIXED eM12; + FIXED eM21; + FIXED eM22; + } MAT2,*LPMAT2; + + typedef struct _GLYPHMETRICS { + UINT gmBlackBoxX; + UINT gmBlackBoxY; + POINT gmptGlyphOrigin; + short gmCellIncX; + short gmCellIncY; + } GLYPHMETRICS,*LPGLYPHMETRICS; + +#define GGO_METRICS 0 +#define GGO_BITMAP 1 +#define GGO_NATIVE 2 +#define GGO_BEZIER 3 + +#define GGO_GRAY2_BITMAP 4 +#define GGO_GRAY4_BITMAP 5 +#define GGO_GRAY8_BITMAP 6 +#define GGO_GLYPH_INDEX 0x0080 +#define GGO_UNHINTED 0x0100 + +#define TT_POLYGON_TYPE 24 + +#define TT_PRIM_LINE 1 +#define TT_PRIM_QSPLINE 2 +#define TT_PRIM_CSPLINE 3 + + typedef struct tagPOINTFX { + FIXED x; + FIXED y; + } POINTFX,*LPPOINTFX; + + typedef struct tagTTPOLYCURVE { + WORD wType; + WORD cpfx; + POINTFX apfx[1]; + } TTPOLYCURVE,*LPTTPOLYCURVE; + + typedef struct tagTTPOLYGONHEADER { + DWORD cb; + DWORD dwType; + POINTFX pfxStart; + } TTPOLYGONHEADER,*LPTTPOLYGONHEADER; + +#define GCP_DBCS 0x0001 +#define GCP_REORDER 0x0002 +#define GCP_USEKERNING 0x0008 +#define GCP_GLYPHSHAPE 0x0010 +#define GCP_LIGATE 0x0020 + +#define GCP_DIACRITIC 0x0100 +#define GCP_KASHIDA 0x0400 +#define GCP_ERROR 0x8000 +#define FLI_MASK 0x103B + +#define GCP_JUSTIFY 0x00010000L + +#define FLI_GLYPHS 0x00040000L +#define GCP_CLASSIN 0x00080000L +#define GCP_MAXEXTENT 0x00100000L +#define GCP_JUSTIFYIN 0x00200000L +#define GCP_DISPLAYZWG 0x00400000L +#define GCP_SYMSWAPOFF 0x00800000L +#define GCP_NUMERICOVERRIDE 0x01000000L +#define GCP_NEUTRALOVERRIDE 0x02000000L +#define GCP_NUMERICSLATIN 0x04000000L +#define GCP_NUMERICSLOCAL 0x08000000L + +#define GCPCLASS_LATIN 1 +#define GCPCLASS_HEBREW 2 +#define GCPCLASS_ARABIC 2 +#define GCPCLASS_NEUTRAL 3 +#define GCPCLASS_LOCALNUMBER 4 +#define GCPCLASS_LATINNUMBER 5 +#define GCPCLASS_LATINNUMERICTERMINATOR 6 +#define GCPCLASS_LATINNUMERICSEPARATOR 7 +#define GCPCLASS_NUMERICSEPARATOR 8 +#define GCPCLASS_PREBOUNDLTR 0x80 +#define GCPCLASS_PREBOUNDRTL 0x40 +#define GCPCLASS_POSTBOUNDLTR 0x20 +#define GCPCLASS_POSTBOUNDRTL 0x10 + +#define GCPGLYPH_LINKBEFORE 0x8000 +#define GCPGLYPH_LINKAFTER 0x4000 + + typedef struct tagGCP_RESULTSA { + DWORD lStructSize; + LPSTR lpOutString; + UINT *lpOrder; + int *lpDx; + int *lpCaretPos; + LPSTR lpClass; + LPWSTR lpGlyphs; + UINT nGlyphs; + int nMaxFit; + } GCP_RESULTSA,*LPGCP_RESULTSA; + typedef struct tagGCP_RESULTSW { + DWORD lStructSize; + LPWSTR lpOutString; + UINT *lpOrder; + int *lpDx; + int *lpCaretPos; + LPSTR lpClass; + LPWSTR lpGlyphs; + UINT nGlyphs; + int nMaxFit; + } GCP_RESULTSW,*LPGCP_RESULTSW; +#ifdef UNICODE + typedef GCP_RESULTSW GCP_RESULTS; + typedef LPGCP_RESULTSW LPGCP_RESULTS; +#else + typedef GCP_RESULTSA GCP_RESULTS; + typedef LPGCP_RESULTSA LPGCP_RESULTS; +#endif + + typedef struct _RASTERIZER_STATUS { + short nSize; + short wFlags; + short nLanguageID; + } RASTERIZER_STATUS,*LPRASTERIZER_STATUS; + +#define TT_AVAILABLE 0x0001 +#define TT_ENABLED 0x0002 + + typedef struct tagPIXELFORMATDESCRIPTOR { + WORD nSize; + WORD nVersion; + DWORD dwFlags; + BYTE iPixelType; + BYTE cColorBits; + BYTE cRedBits; + BYTE cRedShift; + BYTE cGreenBits; + BYTE cGreenShift; + BYTE cBlueBits; + BYTE cBlueShift; + BYTE cAlphaBits; + BYTE cAlphaShift; + BYTE cAccumBits; + BYTE cAccumRedBits; + BYTE cAccumGreenBits; + BYTE cAccumBlueBits; + BYTE cAccumAlphaBits; + BYTE cDepthBits; + BYTE cStencilBits; + BYTE cAuxBuffers; + BYTE iLayerType; + BYTE bReserved; + DWORD dwLayerMask; + DWORD dwVisibleMask; + DWORD dwDamageMask; + } PIXELFORMATDESCRIPTOR,*PPIXELFORMATDESCRIPTOR,*LPPIXELFORMATDESCRIPTOR; + +#define PFD_TYPE_RGBA 0 +#define PFD_TYPE_COLORINDEX 1 + +#define PFD_MAIN_PLANE 0 +#define PFD_OVERLAY_PLANE 1 +#define PFD_UNDERLAY_PLANE (-1) + +#define PFD_DOUBLEBUFFER 0x00000001 +#define PFD_STEREO 0x00000002 +#define PFD_DRAW_TO_WINDOW 0x00000004 +#define PFD_DRAW_TO_BITMAP 0x00000008 +#define PFD_SUPPORT_GDI 0x00000010 +#define PFD_SUPPORT_OPENGL 0x00000020 +#define PFD_GENERIC_FORMAT 0x00000040 +#define PFD_NEED_PALETTE 0x00000080 +#define PFD_NEED_SYSTEM_PALETTE 0x00000100 +#define PFD_SWAP_EXCHANGE 0x00000200 +#define PFD_SWAP_COPY 0x00000400 +#define PFD_SWAP_LAYER_BUFFERS 0x00000800 +#define PFD_GENERIC_ACCELERATED 0x00001000 +#define PFD_SUPPORT_DIRECTDRAW 0x00002000 + +#define PFD_DEPTH_DONTCARE 0x20000000 +#define PFD_DOUBLEBUFFER_DONTCARE 0x40000000 +#define PFD_STEREO_DONTCARE 0x80000000 + +#ifndef NOTEXTMETRIC + typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST TEXTMETRICA *,DWORD,LPARAM); + typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST TEXTMETRICW *,DWORD,LPARAM); +#ifdef UNICODE +#define OLDFONTENUMPROC OLDFONTENUMPROCW +#else +#define OLDFONTENUMPROC OLDFONTENUMPROCA +#endif +#else + typedef int (CALLBACK *OLDFONTENUMPROCA)(CONST LOGFONTA *,CONST VOID *,DWORD,LPARAM); + typedef int (CALLBACK *OLDFONTENUMPROCW)(CONST LOGFONTW *,CONST VOID *,DWORD,LPARAM); +#ifdef UNICODE +#define OLDFONTENUMPROC OLDFONTENUMPROCW +#else +#define OLDFONTENUMPROC OLDFONTENUMPROCA +#endif +#endif + + typedef OLDFONTENUMPROCA FONTENUMPROCA; + typedef OLDFONTENUMPROCW FONTENUMPROCW; +#ifdef UNICODE + typedef FONTENUMPROCW FONTENUMPROC; +#else + typedef FONTENUMPROCA FONTENUMPROC; +#endif + + typedef int (CALLBACK *GOBJENUMPROC)(LPVOID,LPARAM); + typedef VOID (CALLBACK *LINEDDAPROC)(int,int,LPARAM); + +#ifdef UNICODE +#define AddFontResource AddFontResourceW +#define CopyMetaFile CopyMetaFileW +#define CreateDC CreateDCW +#define CreateFontIndirect CreateFontIndirectW +#define CreateFont CreateFontW +#define CreateIC CreateICW +#define CreateMetaFile CreateMetaFileW +#define CreateScalableFontResource CreateScalableFontResourceW +#else +#define AddFontResource AddFontResourceA +#define CopyMetaFile CopyMetaFileA +#define CreateDC CreateDCA +#define CreateFontIndirect CreateFontIndirectA +#define CreateFont CreateFontA +#define CreateIC CreateICA +#define CreateMetaFile CreateMetaFileA +#define CreateScalableFontResource CreateScalableFontResourceA +#endif + + WINGDIAPI int WINAPI AddFontResourceA(LPCSTR); + WINGDIAPI int WINAPI AddFontResourceW(LPCWSTR); + WINGDIAPI WINBOOL WINAPI AnimatePalette(HPALETTE hPal,UINT iStartIndex,UINT cEntries,CONST PALETTEENTRY *ppe); + WINGDIAPI WINBOOL WINAPI Arc(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); + WINGDIAPI WINBOOL WINAPI BitBlt(HDC hdc,int x,int y,int cx,int cy,HDC hdcSrc,int x1,int y1,DWORD rop); + WINGDIAPI WINBOOL WINAPI CancelDC(HDC hdc); + WINGDIAPI WINBOOL WINAPI Chord(HDC hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); + WINGDIAPI int WINAPI ChoosePixelFormat(HDC hdc,CONST PIXELFORMATDESCRIPTOR *ppfd); + WINGDIAPI HMETAFILE WINAPI CloseMetaFile(HDC hdc); + WINGDIAPI int WINAPI CombineRgn(HRGN hrgnDst,HRGN hrgnSrc1,HRGN hrgnSrc2,int iMode); + WINGDIAPI HMETAFILE WINAPI CopyMetaFileA(HMETAFILE,LPCSTR); + WINGDIAPI HMETAFILE WINAPI CopyMetaFileW(HMETAFILE,LPCWSTR); + WINGDIAPI HBITMAP WINAPI CreateBitmap(int nWidth,int nHeight,UINT nPlanes,UINT nBitCount,CONST VOID *lpBits); + WINGDIAPI HBITMAP WINAPI CreateBitmapIndirect(CONST BITMAP *pbm); + WINGDIAPI HBRUSH WINAPI CreateBrushIndirect(CONST LOGBRUSH *plbrush); + WINGDIAPI HBITMAP WINAPI CreateCompatibleBitmap(HDC hdc,int cx,int cy); + WINGDIAPI HBITMAP WINAPI CreateDiscardableBitmap(HDC hdc,int cx,int cy); + WINGDIAPI HDC WINAPI CreateCompatibleDC(HDC hdc); + WINGDIAPI HDC WINAPI CreateDCA(LPCSTR pwszDriver,LPCSTR pwszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); + WINGDIAPI HDC WINAPI CreateDCW(LPCWSTR pwszDriver,LPCWSTR pwszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); + WINGDIAPI HBITMAP WINAPI CreateDIBitmap(HDC hdc,CONST BITMAPINFOHEADER *pbmih,DWORD flInit,CONST VOID *pjBits,CONST BITMAPINFO *pbmi,UINT iUsage); + WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrush(HGLOBAL h,UINT iUsage); + WINGDIAPI HBRUSH WINAPI CreateDIBPatternBrushPt(CONST VOID *lpPackedDIB,UINT iUsage); + WINGDIAPI HRGN WINAPI CreateEllipticRgn(int x1,int y1,int x2,int y2); + WINGDIAPI HRGN WINAPI CreateEllipticRgnIndirect(CONST RECT *lprect); + WINGDIAPI HFONT WINAPI CreateFontIndirectA(CONST LOGFONTA *lplf); + WINGDIAPI HFONT WINAPI CreateFontIndirectW(CONST LOGFONTW *lplf); + WINGDIAPI HFONT WINAPI CreateFontA(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCSTR pszFaceName); + WINGDIAPI HFONT WINAPI CreateFontW(int cHeight,int cWidth,int cEscapement,int cOrientation,int cWeight,DWORD bItalic,DWORD bUnderline,DWORD bStrikeOut,DWORD iCharSet,DWORD iOutPrecision,DWORD iClipPrecision,DWORD iQuality,DWORD iPitchAndFamily,LPCWSTR pszFaceName); + WINGDIAPI HBRUSH WINAPI CreateHatchBrush(int iHatch,COLORREF color); + WINGDIAPI HDC WINAPI CreateICA(LPCSTR pszDriver,LPCSTR pszDevice,LPCSTR pszPort,CONST DEVMODEA *pdm); + WINGDIAPI HDC WINAPI CreateICW(LPCWSTR pszDriver,LPCWSTR pszDevice,LPCWSTR pszPort,CONST DEVMODEW *pdm); + WINGDIAPI HDC WINAPI CreateMetaFileA(LPCSTR pszFile); + WINGDIAPI HDC WINAPI CreateMetaFileW(LPCWSTR pszFile); + WINGDIAPI HPALETTE WINAPI CreatePalette(CONST LOGPALETTE *plpal); + WINGDIAPI HPEN WINAPI CreatePen(int iStyle,int cWidth,COLORREF color); + WINGDIAPI HPEN WINAPI CreatePenIndirect(CONST LOGPEN *plpen); + WINGDIAPI HRGN WINAPI CreatePolyPolygonRgn(CONST POINT *pptl,CONST INT *pc,int cPoly,int iMode); + WINGDIAPI HBRUSH WINAPI CreatePatternBrush(HBITMAP hbm); + WINGDIAPI HRGN WINAPI CreateRectRgn(int x1,int y1,int x2,int y2); + WINGDIAPI HRGN WINAPI CreateRectRgnIndirect(CONST RECT *lprect); + WINGDIAPI HRGN WINAPI CreateRoundRectRgn(int x1,int y1,int x2,int y2,int w,int h); + WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceA(DWORD fdwHidden,LPCSTR lpszFont,LPCSTR lpszFile,LPCSTR lpszPath); + WINGDIAPI WINBOOL WINAPI CreateScalableFontResourceW(DWORD fdwHidden,LPCWSTR lpszFont,LPCWSTR lpszFile,LPCWSTR lpszPath); + WINGDIAPI HBRUSH WINAPI CreateSolidBrush(COLORREF color); + WINGDIAPI WINBOOL WINAPI DeleteDC(HDC hdc); + WINGDIAPI WINBOOL WINAPI DeleteMetaFile(HMETAFILE hmf); + WINGDIAPI WINBOOL WINAPI DeleteObject(HGDIOBJ ho); + WINGDIAPI int WINAPI DescribePixelFormat(HDC hdc,int iPixelFormat,UINT nBytes,LPPIXELFORMATDESCRIPTOR ppfd); + + typedef UINT (CALLBACK *LPFNDEVMODE)(HWND,HMODULE,LPDEVMODE,LPSTR,LPSTR,LPDEVMODE,LPSTR,UINT); + typedef DWORD (CALLBACK *LPFNDEVCAPS)(LPSTR,LPSTR,UINT,LPSTR,LPDEVMODE); + +#define DM_UPDATE 1 +#define DM_COPY 2 +#define DM_PROMPT 4 +#define DM_MODIFY 8 + +#define DM_IN_BUFFER DM_MODIFY +#define DM_IN_PROMPT DM_PROMPT +#define DM_OUT_BUFFER DM_COPY +#define DM_OUT_DEFAULT DM_UPDATE + +#define DC_FIELDS 1 +#define DC_PAPERS 2 +#define DC_PAPERSIZE 3 +#define DC_MINEXTENT 4 +#define DC_MAXEXTENT 5 +#define DC_BINS 6 +#define DC_DUPLEX 7 +#define DC_SIZE 8 +#define DC_EXTRA 9 +#define DC_VERSION 10 +#define DC_DRIVER 11 +#define DC_BINNAMES 12 +#define DC_ENUMRESOLUTIONS 13 +#define DC_FILEDEPENDENCIES 14 +#define DC_TRUETYPE 15 +#define DC_PAPERNAMES 16 +#define DC_ORIENTATION 17 +#define DC_COPIES 18 +#define DC_BINADJUST 19 +#define DC_EMF_COMPLIANT 20 +#define DC_DATATYPE_PRODUCED 21 +#define DC_COLLATE 22 +#define DC_MANUFACTURER 23 +#define DC_MODEL 24 +#define DC_PERSONALITY 25 +#define DC_PRINTRATE 26 +#define DC_PRINTRATEUNIT 27 +#define PRINTRATEUNIT_PPM 1 +#define PRINTRATEUNIT_CPS 2 +#define PRINTRATEUNIT_LPM 3 +#define PRINTRATEUNIT_IPM 4 +#define DC_PRINTERMEM 28 +#define DC_MEDIAREADY 29 +#define DC_STAPLE 30 +#define DC_PRINTRATEPPM 31 +#define DC_COLORDEVICE 32 +#define DC_NUP 33 +#define DC_MEDIATYPENAMES 34 +#define DC_MEDIATYPES 35 + +#define DCTT_BITMAP 0x0000001L +#define DCTT_DOWNLOAD 0x0000002L +#define DCTT_SUBDEV 0x0000004L +#define DCTT_DOWNLOAD_OUTLINE 0x0000008L + +#define DCBA_FACEUPNONE 0x0000 +#define DCBA_FACEUPCENTER 0x0001 +#define DCBA_FACEUPLEFT 0x0002 +#define DCBA_FACEUPRIGHT 0x0003 +#define DCBA_FACEDOWNNONE 0x0100 +#define DCBA_FACEDOWNCENTER 0x0101 +#define DCBA_FACEDOWNLEFT 0x0102 +#define DCBA_FACEDOWNRIGHT 0x0103 + +#ifdef UNICODE +#define DeviceCapabilities DeviceCapabilitiesW +#define EnumFontFamiliesEx EnumFontFamiliesExW +#define EnumFontFamilies EnumFontFamiliesW +#define EnumFonts EnumFontsW +#define GetCharWidth GetCharWidthW +#define GetCharWidth32 GetCharWidth32W +#define GetCharWidthFloat GetCharWidthFloatW +#define GetCharABCWidths GetCharABCWidthsW +#define GetCharABCWidthsFloat GetCharABCWidthsFloatW +#define GetGlyphOutline GetGlyphOutlineW +#define GetMetaFile GetMetaFileW +#else +#define DeviceCapabilities DeviceCapabilitiesA +#define EnumFontFamiliesEx EnumFontFamiliesExA +#define EnumFontFamilies EnumFontFamiliesA +#define EnumFonts EnumFontsA +#define GetCharWidth GetCharWidthA +#define GetCharWidth32 GetCharWidth32A +#define GetCharWidthFloat GetCharWidthFloatA +#define GetCharABCWidths GetCharABCWidthsA +#define GetCharABCWidthsFloat GetCharABCWidthsFloatA +#define GetGlyphOutline GetGlyphOutlineA +#define GetMetaFile GetMetaFileA +#endif + + WINSPOOLAPI int WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort,WORD fwCapability,LPSTR pOutput,CONST DEVMODEA *pDevMode); + WINSPOOLAPI int WINAPI DeviceCapabilitiesW(LPCWSTR pDevice,LPCWSTR pPort,WORD fwCapability,LPWSTR pOutput,CONST DEVMODEW *pDevMode); + WINGDIAPI int WINAPI DrawEscape(HDC hdc,int iEscape,int cjIn,LPCSTR lpIn); + WINGDIAPI WINBOOL WINAPI Ellipse(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI int WINAPI EnumFontFamiliesExA(HDC hdc,LPLOGFONTA lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam,DWORD dwFlags); + WINGDIAPI int WINAPI EnumFontFamiliesExW(HDC hdc,LPLOGFONTW lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam,DWORD dwFlags); + WINGDIAPI int WINAPI EnumFontFamiliesA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumFontFamiliesW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumFontsA(HDC hdc,LPCSTR lpLogfont,FONTENUMPROCA lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumFontsW(HDC hdc,LPCWSTR lpLogfont,FONTENUMPROCW lpProc,LPARAM lParam); + WINGDIAPI int WINAPI EnumObjects(HDC hdc,int nType,GOBJENUMPROC lpFunc,LPARAM lParam); + WINGDIAPI WINBOOL WINAPI EqualRgn(HRGN hrgn1,HRGN hrgn2); + WINGDIAPI int WINAPI Escape(HDC hdc,int iEscape,int cjIn,LPCSTR pvIn,LPVOID pvOut); + WINGDIAPI int WINAPI ExtEscape(HDC hdc,int iEscape,int cjInput,LPCSTR lpInData,int cjOutput,LPSTR lpOutData); + WINGDIAPI int WINAPI ExcludeClipRect(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI HRGN WINAPI ExtCreateRegion(CONST XFORM *lpx,DWORD nCount,CONST RGNDATA *lpData); + WINGDIAPI WINBOOL WINAPI ExtFloodFill(HDC hdc,int x,int y,COLORREF color,UINT type); + WINGDIAPI WINBOOL WINAPI FillRgn(HDC hdc,HRGN hrgn,HBRUSH hbr); + WINGDIAPI WINBOOL WINAPI FloodFill(HDC hdc,int x,int y,COLORREF color); + WINGDIAPI WINBOOL WINAPI FrameRgn(HDC hdc,HRGN hrgn,HBRUSH hbr,int w,int h); + WINGDIAPI int WINAPI GetROP2(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetAspectRatioFilterEx(HDC hdc,LPSIZE lpsize); + WINGDIAPI COLORREF WINAPI GetBkColor(HDC hdc); + WINGDIAPI COLORREF WINAPI GetDCBrushColor(HDC hdc); + WINGDIAPI COLORREF WINAPI GetDCPenColor(HDC hdc); + WINGDIAPI int WINAPI GetBkMode(HDC hdc); + WINGDIAPI LONG WINAPI GetBitmapBits(HBITMAP hbit,LONG cb,LPVOID lpvBits); + WINGDIAPI WINBOOL WINAPI GetBitmapDimensionEx(HBITMAP hbit,LPSIZE lpsize); + WINGDIAPI UINT WINAPI GetBoundsRect(HDC hdc,LPRECT lprect,UINT flags); + WINGDIAPI WINBOOL WINAPI GetBrushOrgEx(HDC hdc,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI GetCharWidthA(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidthW(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidth32A(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidth32W(HDC hdc,UINT iFirst,UINT iLast,LPINT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidthFloatA(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharWidthFloatW(HDC hdc,UINT iFirst,UINT iLast,PFLOAT lpBuffer); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsA(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsW(HDC hdc,UINT wFirst,UINT wLast,LPABC lpABC); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatA(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsFloatW(HDC hdc,UINT iFirst,UINT iLast,LPABCFLOAT lpABC); + WINGDIAPI int WINAPI GetClipBox(HDC hdc,LPRECT lprect); + WINGDIAPI int WINAPI GetClipRgn(HDC hdc,HRGN hrgn); + WINGDIAPI int WINAPI GetMetaRgn(HDC hdc,HRGN hrgn); + WINGDIAPI HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type); + WINGDIAPI WINBOOL WINAPI GetCurrentPositionEx(HDC hdc,LPPOINT lppt); + WINGDIAPI int WINAPI GetDeviceCaps(HDC hdc,int index); + WINGDIAPI int WINAPI GetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,LPVOID lpvBits,LPBITMAPINFO lpbmi,UINT usage); + WINGDIAPI DWORD WINAPI GetFontData (HDC hdc,DWORD dwTable,DWORD dwOffset,PVOID pvBuffer,DWORD cjBuffer); + WINGDIAPI DWORD WINAPI GetGlyphOutlineA(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); + WINGDIAPI DWORD WINAPI GetGlyphOutlineW(HDC hdc,UINT uChar,UINT fuFormat,LPGLYPHMETRICS lpgm,DWORD cjBuffer,LPVOID pvBuffer,CONST MAT2 *lpmat2); + WINGDIAPI int WINAPI GetGraphicsMode(HDC hdc); + WINGDIAPI int WINAPI GetMapMode(HDC hdc); + WINGDIAPI UINT WINAPI GetMetaFileBitsEx(HMETAFILE hMF,UINT cbBuffer,LPVOID lpData); + WINGDIAPI HMETAFILE WINAPI GetMetaFileA(LPCSTR lpName); + WINGDIAPI HMETAFILE WINAPI GetMetaFileW(LPCWSTR lpName); + WINGDIAPI COLORREF WINAPI GetNearestColor(HDC hdc,COLORREF color); + WINGDIAPI UINT WINAPI GetNearestPaletteIndex(HPALETTE h,COLORREF color); + WINGDIAPI DWORD WINAPI GetObjectType(HGDIOBJ h); + +#ifndef NOTEXTMETRIC +#ifdef UNICODE +#define GetOutlineTextMetrics GetOutlineTextMetricsW +#else +#define GetOutlineTextMetrics GetOutlineTextMetricsA +#endif + + WINGDIAPI UINT WINAPI GetOutlineTextMetricsA(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICA potm); + WINGDIAPI UINT WINAPI GetOutlineTextMetricsW(HDC hdc,UINT cjCopy,LPOUTLINETEXTMETRICW potm); +#endif + +#ifdef UNICODE +#define GetTextExtentPoint GetTextExtentPointW +#define GetTextExtentPoint32 GetTextExtentPoint32W +#define GetTextExtentExPoint GetTextExtentExPointW +#define GetCharacterPlacement GetCharacterPlacementW +#else +#define GetTextExtentPoint GetTextExtentPointA +#define GetTextExtentPoint32 GetTextExtentPoint32A +#define GetTextExtentExPoint GetTextExtentExPointA +#define GetCharacterPlacement GetCharacterPlacementA +#endif + + WINGDIAPI UINT WINAPI GetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); + WINGDIAPI COLORREF WINAPI GetPixel(HDC hdc,int x,int y); + WINGDIAPI int WINAPI GetPixelFormat(HDC hdc); + WINGDIAPI int WINAPI GetPolyFillMode(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetRasterizerCaps(LPRASTERIZER_STATUS lpraststat,UINT cjBytes); + WINGDIAPI int WINAPI GetRandomRgn (HDC hdc,HRGN hrgn,INT i); + WINGDIAPI DWORD WINAPI GetRegionData(HRGN hrgn,DWORD nCount,LPRGNDATA lpRgnData); + WINGDIAPI int WINAPI GetRgnBox(HRGN hrgn,LPRECT lprc); + WINGDIAPI HGDIOBJ WINAPI GetStockObject(int i); + WINGDIAPI int WINAPI GetStretchBltMode(HDC hdc); + WINGDIAPI UINT WINAPI GetSystemPaletteEntries(HDC hdc,UINT iStart,UINT cEntries,LPPALETTEENTRY pPalEntries); + WINGDIAPI UINT WINAPI GetSystemPaletteUse(HDC hdc); + WINGDIAPI int WINAPI GetTextCharacterExtra(HDC hdc); + WINGDIAPI UINT WINAPI GetTextAlign(HDC hdc); + WINGDIAPI COLORREF WINAPI GetTextColor(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetTextExtentPointA(HDC hdc,LPCSTR lpString,int c,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI GetTextExtentPointW(HDC hdc,LPCWSTR lpString,int c,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32A(HDC hdc,LPCSTR lpString,int c,LPSIZE psizl); + WINGDIAPI WINBOOL WINAPI GetTextExtentPoint32W(HDC hdc,LPCWSTR lpString,int c,LPSIZE psizl); + WINGDIAPI WINBOOL WINAPI GetTextExtentExPointA(HDC hdc,LPCSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); + WINGDIAPI WINBOOL WINAPI GetTextExtentExPointW(HDC hdc,LPCWSTR lpszString,int cchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); + WINGDIAPI int WINAPI GetTextCharset(HDC hdc); + WINGDIAPI int WINAPI GetTextCharsetInfo(HDC hdc,LPFONTSIGNATURE lpSig,DWORD dwFlags); + WINGDIAPI WINBOOL WINAPI TranslateCharsetInfo(DWORD *lpSrc,LPCHARSETINFO lpCs,DWORD dwFlags); + WINGDIAPI DWORD WINAPI GetFontLanguageInfo(HDC hdc); + WINGDIAPI DWORD WINAPI GetCharacterPlacementA(HDC hdc,LPCSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSA lpResults,DWORD dwFlags); + WINGDIAPI DWORD WINAPI GetCharacterPlacementW(HDC hdc,LPCWSTR lpString,int nCount,int nMexExtent,LPGCP_RESULTSW lpResults,DWORD dwFlags); + + typedef struct tagWCRANGE { + WCHAR wcLow; + USHORT cGlyphs; + } WCRANGE,*PWCRANGE,*LPWCRANGE; + + typedef struct tagGLYPHSET { + DWORD cbThis; + DWORD flAccel; + DWORD cGlyphsSupported; + DWORD cRanges; + WCRANGE ranges[1]; + } GLYPHSET,*PGLYPHSET,*LPGLYPHSET; + +#define GS_8BIT_INDICES 0x00000001 + +#define GGI_MARK_NONEXISTING_GLYPHS 0X0001 + +#ifdef UNICODE +#define GetGlyphIndices GetGlyphIndicesW +#else +#define GetGlyphIndices GetGlyphIndicesA +#endif + + WINGDIAPI DWORD WINAPI GetFontUnicodeRanges(HDC hdc,LPGLYPHSET lpgs); + WINGDIAPI DWORD WINAPI GetGlyphIndicesA(HDC hdc,LPCSTR lpstr,int c,LPWORD pgi,DWORD fl); + WINGDIAPI DWORD WINAPI GetGlyphIndicesW(HDC hdc,LPCWSTR lpstr,int c,LPWORD pgi,DWORD fl); + WINGDIAPI WINBOOL WINAPI GetTextExtentPointI(HDC hdc,LPWORD pgiIn,int cgi,LPSIZE psize); + WINGDIAPI WINBOOL WINAPI GetTextExtentExPointI (HDC hdc,LPWORD lpwszString,int cwchString,int nMaxExtent,LPINT lpnFit,LPINT lpnDx,LPSIZE lpSize); + WINGDIAPI WINBOOL WINAPI GetCharWidthI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPINT piWidths); + WINGDIAPI WINBOOL WINAPI GetCharABCWidthsI(HDC hdc,UINT giFirst,UINT cgi,LPWORD pgi,LPABC pabc); + +#define STAMP_DESIGNVECTOR (0x8000000 + 'd' + ('v' << 8)) +#define STAMP_AXESLIST (0x8000000 + 'a' + ('l' << 8)) +#define MM_MAX_NUMAXES 16 + + typedef struct tagDESIGNVECTOR { + DWORD dvReserved; + DWORD dvNumAxes; + LONG dvValues[MM_MAX_NUMAXES]; + } DESIGNVECTOR,*PDESIGNVECTOR,*LPDESIGNVECTOR; + +#ifdef UNICODE +#define AddFontResourceEx AddFontResourceExW +#define RemoveFontResourceEx RemoveFontResourceExW +#else +#define AddFontResourceEx AddFontResourceExA +#define RemoveFontResourceEx RemoveFontResourceExA +#endif + + WINGDIAPI int WINAPI AddFontResourceExA(LPCSTR name,DWORD fl,PVOID res); + WINGDIAPI int WINAPI AddFontResourceExW(LPCWSTR name,DWORD fl,PVOID res); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceExA(LPCSTR name,DWORD fl,PVOID pdv); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceExW(LPCWSTR name,DWORD fl,PVOID pdv); + WINGDIAPI HANDLE WINAPI AddFontMemResourceEx(PVOID pFileView,DWORD cjSize,PVOID pvResrved,DWORD *pNumFonts); + WINGDIAPI WINBOOL WINAPI RemoveFontMemResourceEx(HANDLE h); + +#define FR_PRIVATE 0x10 +#define FR_NOT_ENUM 0x20 + +#define MM_MAX_AXES_NAMELEN 16 + + typedef struct tagAXISINFOA { + LONG axMinValue; + LONG axMaxValue; + BYTE axAxisName[MM_MAX_AXES_NAMELEN]; + } AXISINFOA,*PAXISINFOA,*LPAXISINFOA; + + typedef struct tagAXISINFOW { + LONG axMinValue; + LONG axMaxValue; + WCHAR axAxisName[MM_MAX_AXES_NAMELEN]; + } AXISINFOW,*PAXISINFOW,*LPAXISINFOW; +#ifdef UNICODE + typedef AXISINFOW AXISINFO; + typedef PAXISINFOW PAXISINFO; + typedef LPAXISINFOW LPAXISINFO; +#else + typedef AXISINFOA AXISINFO; + typedef PAXISINFOA PAXISINFO; + typedef LPAXISINFOA LPAXISINFO; +#endif + + typedef struct tagAXESLISTA { + DWORD axlReserved; + DWORD axlNumAxes; + AXISINFOA axlAxisInfo[MM_MAX_NUMAXES]; + } AXESLISTA,*PAXESLISTA,*LPAXESLISTA; + + typedef struct tagAXESLISTW { + DWORD axlReserved; + DWORD axlNumAxes; + AXISINFOW axlAxisInfo[MM_MAX_NUMAXES]; + } AXESLISTW,*PAXESLISTW,*LPAXESLISTW; +#ifdef UNICODE + typedef AXESLISTW AXESLIST; + typedef PAXESLISTW PAXESLIST; + typedef LPAXESLISTW LPAXESLIST; +#else + typedef AXESLISTA AXESLIST; + typedef PAXESLISTA PAXESLIST; + typedef LPAXESLISTA LPAXESLIST; +#endif + + typedef struct tagENUMLOGFONTEXDVA { + ENUMLOGFONTEXA elfEnumLogfontEx; + DESIGNVECTOR elfDesignVector; + } ENUMLOGFONTEXDVA,*PENUMLOGFONTEXDVA,*LPENUMLOGFONTEXDVA; + + typedef struct tagENUMLOGFONTEXDVW { + ENUMLOGFONTEXW elfEnumLogfontEx; + DESIGNVECTOR elfDesignVector; + } ENUMLOGFONTEXDVW,*PENUMLOGFONTEXDVW,*LPENUMLOGFONTEXDVW; +#ifdef UNICODE + typedef ENUMLOGFONTEXDVW ENUMLOGFONTEXDV; + typedef PENUMLOGFONTEXDVW PENUMLOGFONTEXDV; + typedef LPENUMLOGFONTEXDVW LPENUMLOGFONTEXDV; +#else + typedef ENUMLOGFONTEXDVA ENUMLOGFONTEXDV; + typedef PENUMLOGFONTEXDVA PENUMLOGFONTEXDV; + typedef LPENUMLOGFONTEXDVA LPENUMLOGFONTEXDV; +#endif + +#ifdef UNICODE +#define CreateFontIndirectEx CreateFontIndirectExW +#else +#define CreateFontIndirectEx CreateFontIndirectExA +#endif + + WINGDIAPI HFONT WINAPI CreateFontIndirectExA(CONST ENUMLOGFONTEXDVA *); + WINGDIAPI HFONT WINAPI CreateFontIndirectExW(CONST ENUMLOGFONTEXDVW *); + +#ifndef NOTEXTMETRIC + typedef struct tagENUMTEXTMETRICA { + NEWTEXTMETRICEXA etmNewTextMetricEx; + AXESLISTA etmAxesList; + } ENUMTEXTMETRICA,*PENUMTEXTMETRICA,*LPENUMTEXTMETRICA; + typedef struct tagENUMTEXTMETRICW + { + NEWTEXTMETRICEXW etmNewTextMetricEx; + AXESLISTW etmAxesList; + } ENUMTEXTMETRICW,*PENUMTEXTMETRICW,*LPENUMTEXTMETRICW; +#ifdef UNICODE + typedef ENUMTEXTMETRICW ENUMTEXTMETRIC; + typedef PENUMTEXTMETRICW PENUMTEXTMETRIC; + typedef LPENUMTEXTMETRICW LPENUMTEXTMETRIC; +#else + typedef ENUMTEXTMETRICA ENUMTEXTMETRIC; + typedef PENUMTEXTMETRICA PENUMTEXTMETRIC; + typedef LPENUMTEXTMETRICA LPENUMTEXTMETRIC; +#endif +#endif + +#ifdef UNICODE +#define ResetDC ResetDCW +#define RemoveFontResource RemoveFontResourceW +#else +#define ResetDC ResetDCA +#define RemoveFontResource RemoveFontResourceA +#endif + + WINGDIAPI WINBOOL WINAPI GetViewportExtEx(HDC hdc,LPSIZE lpsize); + WINGDIAPI WINBOOL WINAPI GetViewportOrgEx(HDC hdc,LPPOINT lppoint); + WINGDIAPI WINBOOL WINAPI GetWindowExtEx(HDC hdc,LPSIZE lpsize); + WINGDIAPI WINBOOL WINAPI GetWindowOrgEx(HDC hdc,LPPOINT lppoint); + WINGDIAPI int WINAPI IntersectClipRect(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI WINBOOL WINAPI InvertRgn(HDC hdc,HRGN hrgn); + WINGDIAPI WINBOOL WINAPI LineDDA(int xStart,int yStart,int xEnd,int yEnd,LINEDDAPROC lpProc,LPARAM data); + WINGDIAPI WINBOOL WINAPI LineTo(HDC hdc,int x,int y); + WINGDIAPI WINBOOL WINAPI MaskBlt(HDC hdcDest,int xDest,int yDest,int width,int height,HDC hdcSrc,int xSrc,int ySrc,HBITMAP hbmMask,int xMask,int yMask,DWORD rop); + WINGDIAPI WINBOOL WINAPI PlgBlt(HDC hdcDest,CONST POINT *lpPoint,HDC hdcSrc,int xSrc,int ySrc,int width,int height,HBITMAP hbmMask,int xMask,int yMask); + WINGDIAPI int WINAPI OffsetClipRgn(HDC hdc,int x,int y); + WINGDIAPI int WINAPI OffsetRgn(HRGN hrgn,int x,int y); + WINGDIAPI WINBOOL WINAPI PatBlt(HDC hdc,int x,int y,int w,int h,DWORD rop); + WINGDIAPI WINBOOL WINAPI Pie(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); + WINGDIAPI WINBOOL WINAPI PlayMetaFile(HDC hdc,HMETAFILE hmf); + WINGDIAPI WINBOOL WINAPI PaintRgn(HDC hdc,HRGN hrgn); + WINGDIAPI WINBOOL WINAPI PolyPolygon(HDC hdc,CONST POINT *apt,CONST INT *asz,int csz); + WINGDIAPI WINBOOL WINAPI PtInRegion(HRGN hrgn,int x,int y); + WINGDIAPI WINBOOL WINAPI PtVisible(HDC hdc,int x,int y); + WINGDIAPI WINBOOL WINAPI RectInRegion(HRGN hrgn,CONST RECT *lprect); + WINGDIAPI WINBOOL WINAPI RectVisible(HDC hdc,CONST RECT *lprect); + WINGDIAPI WINBOOL WINAPI Rectangle(HDC hdc,int left,int top,int right,int bottom); + WINGDIAPI WINBOOL WINAPI RestoreDC(HDC hdc,int nSavedDC); + WINGDIAPI HDC WINAPI ResetDCA(HDC hdc,CONST DEVMODEA *lpdm); + WINGDIAPI HDC WINAPI ResetDCW(HDC hdc,CONST DEVMODEW *lpdm); + WINGDIAPI UINT WINAPI RealizePalette(HDC hdc); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceA(LPCSTR lpFileName); + WINGDIAPI WINBOOL WINAPI RemoveFontResourceW(LPCWSTR lpFileName); + WINGDIAPI WINBOOL WINAPI RoundRect(HDC hdc,int left,int top,int right,int bottom,int width,int height); + WINGDIAPI WINBOOL WINAPI ResizePalette(HPALETTE hpal,UINT n); + WINGDIAPI int WINAPI SaveDC(HDC hdc); + WINGDIAPI int WINAPI SelectClipRgn(HDC hdc,HRGN hrgn); + WINGDIAPI int WINAPI ExtSelectClipRgn(HDC hdc,HRGN hrgn,int mode); + WINGDIAPI int WINAPI SetMetaRgn(HDC hdc); + WINGDIAPI HGDIOBJ WINAPI SelectObject(HDC hdc,HGDIOBJ h); + WINGDIAPI HPALETTE WINAPI SelectPalette(HDC hdc,HPALETTE hPal,WINBOOL bForceBkgd); + WINGDIAPI COLORREF WINAPI SetBkColor(HDC hdc,COLORREF color); + WINGDIAPI COLORREF WINAPI SetDCBrushColor(HDC hdc,COLORREF color); + WINGDIAPI COLORREF WINAPI SetDCPenColor(HDC hdc,COLORREF color); + WINGDIAPI int WINAPI SetBkMode(HDC hdc,int mode); + WINGDIAPI LONG WINAPI SetBitmapBits(HBITMAP hbm,DWORD cb,CONST VOID *pvBits); + WINGDIAPI UINT WINAPI SetBoundsRect(HDC hdc,CONST RECT *lprect,UINT flags); + WINGDIAPI int WINAPI SetDIBits(HDC hdc,HBITMAP hbm,UINT start,UINT cLines,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); + WINGDIAPI int WINAPI SetDIBitsToDevice(HDC hdc,int xDest,int yDest,DWORD w,DWORD h,int xSrc,int ySrc,UINT StartScan,UINT cLines,CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi,UINT ColorUse); + WINGDIAPI DWORD WINAPI SetMapperFlags(HDC hdc,DWORD flags); + WINGDIAPI int WINAPI SetGraphicsMode(HDC hdc,int iMode); + WINGDIAPI int WINAPI SetMapMode(HDC hdc,int iMode); + WINGDIAPI DWORD WINAPI SetLayout(HDC hdc,DWORD l); + WINGDIAPI DWORD WINAPI GetLayout(HDC hdc); + WINGDIAPI HMETAFILE WINAPI SetMetaFileBitsEx(UINT cbBuffer,CONST BYTE *lpData); + WINGDIAPI UINT WINAPI SetPaletteEntries(HPALETTE hpal,UINT iStart,UINT cEntries,CONST PALETTEENTRY *pPalEntries); + WINGDIAPI COLORREF WINAPI SetPixel(HDC hdc,int x,int y,COLORREF color); + WINGDIAPI WINBOOL WINAPI SetPixelV(HDC hdc,int x,int y,COLORREF color); + WINGDIAPI WINBOOL WINAPI SetPixelFormat(HDC hdc,int format,CONST PIXELFORMATDESCRIPTOR *ppfd); + WINGDIAPI int WINAPI SetPolyFillMode(HDC hdc,int mode); + WINGDIAPI WINBOOL WINAPI StretchBlt(HDC hdcDest,int xDest,int yDest,int wDest,int hDest,HDC hdcSrc,int xSrc,int ySrc,int wSrc,int hSrc,DWORD rop); + WINGDIAPI WINBOOL WINAPI SetRectRgn(HRGN hrgn,int left,int top,int right,int bottom); + WINGDIAPI int WINAPI StretchDIBits(HDC hdc,int xDest,int yDest,int DestWidth,int DestHeight,int xSrc,int ySrc,int SrcWidth,int SrcHeight,CONST VOID *lpBits,CONST BITMAPINFO *lpbmi,UINT iUsage,DWORD rop); + WINGDIAPI int WINAPI SetROP2(HDC hdc,int rop2); + WINGDIAPI int WINAPI SetStretchBltMode(HDC hdc,int mode); + WINGDIAPI UINT WINAPI SetSystemPaletteUse(HDC hdc,UINT use); + WINGDIAPI int WINAPI SetTextCharacterExtra(HDC hdc,int extra); + WINGDIAPI COLORREF WINAPI SetTextColor(HDC hdc,COLORREF color); + WINGDIAPI UINT WINAPI SetTextAlign(HDC hdc,UINT align); + WINGDIAPI WINBOOL WINAPI SetTextJustification(HDC hdc,int extra,int count); + WINGDIAPI WINBOOL WINAPI UpdateColors(HDC hdc); + + typedef USHORT COLOR16; + + typedef struct _TRIVERTEX { + LONG x; + LONG y; + COLOR16 Red; + COLOR16 Green; + COLOR16 Blue; + COLOR16 Alpha; + } TRIVERTEX,*PTRIVERTEX,*LPTRIVERTEX; + + typedef struct _GRADIENT_TRIANGLE { + ULONG Vertex1; + ULONG Vertex2; + ULONG Vertex3; + } GRADIENT_TRIANGLE,*PGRADIENT_TRIANGLE,*LPGRADIENT_TRIANGLE; + + typedef struct _GRADIENT_RECT { + ULONG UpperLeft; + ULONG LowerRight; + } GRADIENT_RECT,*PGRADIENT_RECT,*LPGRADIENT_RECT; + + typedef struct _BLENDFUNCTION { + BYTE BlendOp; + BYTE BlendFlags; + BYTE SourceConstantAlpha; + BYTE AlphaFormat; + } BLENDFUNCTION,*PBLENDFUNCTION; + +#define AC_SRC_OVER 0x00 +#define AC_SRC_ALPHA 0x01 + + WINGDIAPI WINBOOL WINAPI AlphaBlend(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,BLENDFUNCTION ftn); + WINGDIAPI WINBOOL WINAPI TransparentBlt(HDC hdcDest,int xoriginDest,int yoriginDest,int wDest,int hDest,HDC hdcSrc,int xoriginSrc,int yoriginSrc,int wSrc,int hSrc,UINT crTransparent); + +#define GRADIENT_FILL_RECT_H 0x00000000 +#define GRADIENT_FILL_RECT_V 0x00000001 +#define GRADIENT_FILL_TRIANGLE 0x00000002 +#define GRADIENT_FILL_OP_FLAG 0x000000ff + + WINGDIAPI WINBOOL WINAPI GradientFill(HDC hdc,PTRIVERTEX pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,ULONG ulMode); + +#ifndef NOMETAFILE + +#ifdef UNICODE +#define CopyEnhMetaFile CopyEnhMetaFileW +#define CreateEnhMetaFile CreateEnhMetaFileW +#define GetEnhMetaFile GetEnhMetaFileW +#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionW +#else +#define CopyEnhMetaFile CopyEnhMetaFileA +#define CreateEnhMetaFile CreateEnhMetaFileA +#define GetEnhMetaFile GetEnhMetaFileA +#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionA +#endif + + WINGDIAPI WINBOOL WINAPI PlayMetaFileRecord(HDC hdc,LPHANDLETABLE lpHandleTable,LPMETARECORD lpMR,UINT noObjs); + + typedef int (CALLBACK *MFENUMPROC)(HDC hdc,HANDLETABLE *lpht,METARECORD *lpMR,int nObj,LPARAM param); + + WINGDIAPI WINBOOL WINAPI EnumMetaFile(HDC hdc,HMETAFILE hmf,MFENUMPROC proc,LPARAM param); + + typedef int (CALLBACK *ENHMFENUMPROC)(HDC hdc,HANDLETABLE *lpht,CONST ENHMETARECORD *lpmr,int hHandles,LPARAM data); + + WINGDIAPI HENHMETAFILE WINAPI CloseEnhMetaFile(HDC hdc); + WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileA(HENHMETAFILE hEnh,LPCSTR lpFileName); + WINGDIAPI HENHMETAFILE WINAPI CopyEnhMetaFileW(HENHMETAFILE hEnh,LPCWSTR lpFileName); + WINGDIAPI HDC WINAPI CreateEnhMetaFileA(HDC hdc,LPCSTR lpFilename,CONST RECT *lprc,LPCSTR lpDesc); + WINGDIAPI HDC WINAPI CreateEnhMetaFileW(HDC hdc,LPCWSTR lpFilename,CONST RECT *lprc,LPCWSTR lpDesc); + WINGDIAPI WINBOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf); + WINGDIAPI WINBOOL WINAPI EnumEnhMetaFile(HDC hdc,HENHMETAFILE hmf,ENHMFENUMPROC proc,LPVOID param,CONST RECT *lpRect); + WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileA(LPCSTR lpName); + WINGDIAPI HENHMETAFILE WINAPI GetEnhMetaFileW(LPCWSTR lpName); + WINGDIAPI UINT WINAPI GetEnhMetaFileBits(HENHMETAFILE hEMF,UINT nSize,LPBYTE lpData); + WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionA(HENHMETAFILE hemf,UINT cchBuffer,LPSTR lpDescription); + WINGDIAPI UINT WINAPI GetEnhMetaFileDescriptionW(HENHMETAFILE hemf,UINT cchBuffer,LPWSTR lpDescription); + WINGDIAPI UINT WINAPI GetEnhMetaFileHeader(HENHMETAFILE hemf,UINT nSize,LPENHMETAHEADER lpEnhMetaHeader); + WINGDIAPI UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf,UINT nNumEntries,LPPALETTEENTRY lpPaletteEntries); + WINGDIAPI UINT WINAPI GetEnhMetaFilePixelFormat(HENHMETAFILE hemf,UINT cbBuffer,PIXELFORMATDESCRIPTOR *ppfd); + WINGDIAPI UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,UINT cbData16,LPBYTE pData16,INT iMapMode,HDC hdcRef); + WINGDIAPI WINBOOL WINAPI PlayEnhMetaFile(HDC hdc,HENHMETAFILE hmf,CONST RECT *lprect); + WINGDIAPI WINBOOL WINAPI PlayEnhMetaFileRecord(HDC hdc,LPHANDLETABLE pht,CONST ENHMETARECORD *pmr,UINT cht); + WINGDIAPI HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT nSize,CONST BYTE *pb); + WINGDIAPI HENHMETAFILE WINAPI SetWinMetaFileBits(UINT nSize,CONST BYTE *lpMeta16Data,HDC hdcRef,CONST METAFILEPICT *lpMFP); + WINGDIAPI WINBOOL WINAPI GdiComment(HDC hdc,UINT nSize,CONST BYTE *lpData); +#endif + +#ifndef NOTEXTMETRIC +#ifdef UNICODE +#define GetTextMetrics GetTextMetricsW +#else +#define GetTextMetrics GetTextMetricsA +#endif + + WINGDIAPI WINBOOL WINAPI GetTextMetricsA(HDC hdc,LPTEXTMETRICA lptm); + WINGDIAPI WINBOOL WINAPI GetTextMetricsW(HDC hdc,LPTEXTMETRICW lptm); +#endif + + typedef struct tagDIBSECTION { + BITMAP dsBm; + BITMAPINFOHEADER dsBmih; + DWORD dsBitfields[3]; + HANDLE dshSection; + DWORD dsOffset; + } DIBSECTION,*LPDIBSECTION,*PDIBSECTION; + + WINGDIAPI WINBOOL WINAPI AngleArc(HDC hdc,int x,int y,DWORD r,FLOAT StartAngle,FLOAT SweepAngle); + WINGDIAPI WINBOOL WINAPI PolyPolyline(HDC hdc,CONST POINT *apt,CONST DWORD *asz,DWORD csz); + WINGDIAPI WINBOOL WINAPI GetWorldTransform(HDC hdc,LPXFORM lpxf); + WINGDIAPI WINBOOL WINAPI SetWorldTransform(HDC hdc,CONST XFORM *lpxf); + WINGDIAPI WINBOOL WINAPI ModifyWorldTransform(HDC hdc,CONST XFORM *lpxf,DWORD mode); + WINGDIAPI WINBOOL WINAPI CombineTransform(LPXFORM lpxfOut,CONST XFORM *lpxf1,CONST XFORM *lpxf2); + WINGDIAPI HBITMAP WINAPI CreateDIBSection(HDC hdc,CONST BITMAPINFO *lpbmi,UINT usage,VOID **ppvBits,HANDLE hSection,DWORD offset); + WINGDIAPI UINT WINAPI GetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,RGBQUAD *prgbq); + WINGDIAPI UINT WINAPI SetDIBColorTable(HDC hdc,UINT iStart,UINT cEntries,CONST RGBQUAD *prgbq); + +#define CA_NEGATIVE 0x0001 +#define CA_LOG_FILTER 0x0002 + +#define ILLUMINANT_DEVICE_DEFAULT 0 +#define ILLUMINANT_A 1 +#define ILLUMINANT_B 2 +#define ILLUMINANT_C 3 +#define ILLUMINANT_D50 4 +#define ILLUMINANT_D55 5 +#define ILLUMINANT_D65 6 +#define ILLUMINANT_D75 7 +#define ILLUMINANT_F2 8 +#define ILLUMINANT_MAX_INDEX ILLUMINANT_F2 + +#define ILLUMINANT_TUNGSTEN ILLUMINANT_A +#define ILLUMINANT_DAYLIGHT ILLUMINANT_C +#define ILLUMINANT_FLUORESCENT ILLUMINANT_F2 +#define ILLUMINANT_NTSC ILLUMINANT_C + +#define RGB_GAMMA_MIN (WORD)02500 +#define RGB_GAMMA_MAX (WORD)65000 + +#define REFERENCE_WHITE_MIN (WORD)6000 +#define REFERENCE_WHITE_MAX (WORD)10000 +#define REFERENCE_BLACK_MIN (WORD)0 +#define REFERENCE_BLACK_MAX (WORD)4000 + +#define COLOR_ADJ_MIN (SHORT)-100 +#define COLOR_ADJ_MAX (SHORT)100 + + typedef struct tagCOLORADJUSTMENT { + WORD caSize; + WORD caFlags; + WORD caIlluminantIndex; + WORD caRedGamma; + WORD caGreenGamma; + WORD caBlueGamma; + WORD caReferenceBlack; + WORD caReferenceWhite; + SHORT caContrast; + SHORT caBrightness; + SHORT caColorfulness; + SHORT caRedGreenTint; + } COLORADJUSTMENT,*PCOLORADJUSTMENT,*LPCOLORADJUSTMENT; + + WINGDIAPI WINBOOL WINAPI SetColorAdjustment(HDC hdc,CONST COLORADJUSTMENT *lpca); + WINGDIAPI WINBOOL WINAPI GetColorAdjustment(HDC hdc,LPCOLORADJUSTMENT lpca); + WINGDIAPI HPALETTE WINAPI CreateHalftonePalette(HDC hdc); + + typedef WINBOOL (CALLBACK *ABORTPROC)(HDC,int); + + typedef struct _DOCINFOA { + int cbSize; + LPCSTR lpszDocName; + LPCSTR lpszOutput; + LPCSTR lpszDatatype; + DWORD fwType; + } DOCINFOA,*LPDOCINFOA; + + typedef struct _DOCINFOW { + int cbSize; + LPCWSTR lpszDocName; + LPCWSTR lpszOutput; + LPCWSTR lpszDatatype; + DWORD fwType; + } DOCINFOW,*LPDOCINFOW; + +#ifdef UNICODE + typedef DOCINFOW DOCINFO; + typedef LPDOCINFOW LPDOCINFO; +#else + typedef DOCINFOA DOCINFO; + typedef LPDOCINFOA LPDOCINFO; +#endif + +#define DI_APPBANDING 0x00000001 +#define DI_ROPS_READ_DESTINATION 0x00000002 + +#ifdef UNICODE +#define StartDoc StartDocW +#define GetObject GetObjectW +#define TextOut TextOutW +#define ExtTextOut ExtTextOutW +#define PolyTextOut PolyTextOutW +#define GetTextFace GetTextFaceW +#else +#define StartDoc StartDocA +#define GetObject GetObjectA +#define TextOut TextOutA +#define ExtTextOut ExtTextOutA +#define PolyTextOut PolyTextOutA +#define GetTextFace GetTextFaceA +#endif + + WINGDIAPI int WINAPI StartDocA(HDC hdc,CONST DOCINFOA *lpdi); + WINGDIAPI int WINAPI StartDocW(HDC hdc,CONST DOCINFOW *lpdi); + WINGDIAPI int WINAPI EndDoc(HDC hdc); + WINGDIAPI int WINAPI StartPage(HDC hdc); + WINGDIAPI int WINAPI EndPage(HDC hdc); + WINGDIAPI int WINAPI AbortDoc(HDC hdc); + WINGDIAPI int WINAPI SetAbortProc(HDC hdc,ABORTPROC proc); + WINGDIAPI WINBOOL WINAPI AbortPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI ArcTo(HDC hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); + WINGDIAPI WINBOOL WINAPI BeginPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI CloseFigure(HDC hdc); + WINGDIAPI WINBOOL WINAPI EndPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI FillPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI FlattenPath(HDC hdc); + WINGDIAPI int WINAPI GetPath(HDC hdc,LPPOINT apt,LPBYTE aj,int cpt); + WINGDIAPI HRGN WINAPI PathToRegion(HDC hdc); + WINGDIAPI WINBOOL WINAPI PolyDraw(HDC hdc,CONST POINT *apt,CONST BYTE *aj,int cpt); + WINGDIAPI WINBOOL WINAPI SelectClipPath(HDC hdc,int mode); + WINGDIAPI int WINAPI SetArcDirection(HDC hdc,int dir); + WINGDIAPI WINBOOL WINAPI SetMiterLimit(HDC hdc,FLOAT limit,PFLOAT old); + WINGDIAPI WINBOOL WINAPI StrokeAndFillPath(HDC hdc); + WINGDIAPI WINBOOL WINAPI StrokePath(HDC hdc); + WINGDIAPI WINBOOL WINAPI WidenPath(HDC hdc); + WINGDIAPI HPEN WINAPI ExtCreatePen(DWORD iPenStyle,DWORD cWidth,CONST LOGBRUSH *plbrush,DWORD cStyle,CONST DWORD *pstyle); + WINGDIAPI WINBOOL WINAPI GetMiterLimit(HDC hdc,PFLOAT plimit); + WINGDIAPI int WINAPI GetArcDirection(HDC hdc); + WINGDIAPI int WINAPI GetObjectA(HANDLE h,int c,LPVOID pv); + WINGDIAPI int WINAPI GetObjectW(HANDLE h,int c,LPVOID pv); + WINGDIAPI WINBOOL WINAPI MoveToEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI TextOutA(HDC hdc,int x,int y,LPCSTR lpString,int c); + WINGDIAPI WINBOOL WINAPI TextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int c); + WINGDIAPI WINBOOL WINAPI ExtTextOutA(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCSTR lpString,UINT c,CONST INT *lpDx); + WINGDIAPI WINBOOL WINAPI ExtTextOutW(HDC hdc,int x,int y,UINT options,CONST RECT *lprect,LPCWSTR lpString,UINT c,CONST INT *lpDx); + WINGDIAPI WINBOOL WINAPI PolyTextOutA(HDC hdc,CONST POLYTEXTA *ppt,int nstrings); + WINGDIAPI WINBOOL WINAPI PolyTextOutW(HDC hdc,CONST POLYTEXTW *ppt,int nstrings); + WINGDIAPI HRGN WINAPI CreatePolygonRgn(CONST POINT *pptl,int cPoint,int iMode); + WINGDIAPI WINBOOL WINAPI DPtoLP(HDC hdc,LPPOINT lppt,int c); + WINGDIAPI WINBOOL WINAPI LPtoDP(HDC hdc,LPPOINT lppt,int c); + WINGDIAPI WINBOOL WINAPI Polygon(HDC hdc,CONST POINT *apt,int cpt); + WINGDIAPI WINBOOL WINAPI Polyline(HDC hdc,CONST POINT *apt,int cpt); + WINGDIAPI WINBOOL WINAPI PolyBezier(HDC hdc,CONST POINT *apt,DWORD cpt); + WINGDIAPI WINBOOL WINAPI PolyBezierTo(HDC hdc,CONST POINT *apt,DWORD cpt); + WINGDIAPI WINBOOL WINAPI PolylineTo(HDC hdc,CONST POINT *apt,DWORD cpt); + WINGDIAPI WINBOOL WINAPI SetViewportExtEx(HDC hdc,int x,int y,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI SetWindowExtEx(HDC hdc,int x,int y,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI OffsetViewportOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI OffsetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI ScaleViewportExtEx(HDC hdc,int xn,int dx,int yn,int yd,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI ScaleWindowExtEx(HDC hdc,int xn,int xd,int yn,int yd,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetBitmapDimensionEx(HBITMAP hbm,int w,int h,LPSIZE lpsz); + WINGDIAPI WINBOOL WINAPI SetBrushOrgEx(HDC hdc,int x,int y,LPPOINT lppt); + WINGDIAPI int WINAPI GetTextFaceA(HDC hdc,int c,LPSTR lpName); + WINGDIAPI int WINAPI GetTextFaceW(HDC hdc,int c,LPWSTR lpName); + +#define FONTMAPPER_MAX 10 + + typedef struct tagKERNINGPAIR { + WORD wFirst; + WORD wSecond; + int iKernAmount; + } KERNINGPAIR,*LPKERNINGPAIR; + +#ifdef UNICODE +#define GetKerningPairs GetKerningPairsW +#else +#define GetKerningPairs GetKerningPairsA +#endif + + WINGDIAPI DWORD WINAPI GetKerningPairsA(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); + WINGDIAPI DWORD WINAPI GetKerningPairsW(HDC hdc,DWORD nPairs,LPKERNINGPAIR lpKernPair); + WINGDIAPI WINBOOL WINAPI GetDCOrgEx(HDC hdc,LPPOINT lppt); + WINGDIAPI WINBOOL WINAPI FixBrushOrgEx(HDC hdc,int x,int y,LPPOINT ptl); + WINGDIAPI WINBOOL WINAPI UnrealizeObject(HGDIOBJ h); + WINGDIAPI WINBOOL WINAPI GdiFlush(); + WINGDIAPI DWORD WINAPI GdiSetBatchLimit(DWORD dw); + WINGDIAPI DWORD WINAPI GdiGetBatchLimit(); + +#define ICM_OFF 1 +#define ICM_ON 2 +#define ICM_QUERY 3 +#define ICM_DONE_OUTSIDEDC 4 + + typedef int (CALLBACK *ICMENUMPROCA)(LPSTR,LPARAM); + typedef int (CALLBACK *ICMENUMPROCW)(LPWSTR,LPARAM); + +#ifdef UNICODE +#define ICMENUMPROC ICMENUMPROCW +#define EnumICMProfiles EnumICMProfilesW +#define UpdateICMRegKey UpdateICMRegKeyW +#define GetLogColorSpace GetLogColorSpaceW +#define CreateColorSpace CreateColorSpaceW +#define GetICMProfile GetICMProfileW +#define SetICMProfile SetICMProfileW +#else +#define ICMENUMPROC ICMENUMPROCA +#define EnumICMProfiles EnumICMProfilesA +#define UpdateICMRegKey UpdateICMRegKeyA +#define GetLogColorSpace GetLogColorSpaceA +#define CreateColorSpace CreateColorSpaceA +#define GetICMProfile GetICMProfileA +#define SetICMProfile SetICMProfileA +#endif + + WINGDIAPI int WINAPI SetICMMode(HDC hdc,int mode); + WINGDIAPI WINBOOL WINAPI CheckColorsInGamut(HDC hdc,LPVOID lpRGBTriple,LPVOID dlpBuffer,DWORD nCount); + WINGDIAPI HCOLORSPACE WINAPI GetColorSpace(HDC hdc); + WINGDIAPI WINBOOL WINAPI GetLogColorSpaceA(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEA lpBuffer,DWORD nSize); + WINGDIAPI WINBOOL WINAPI GetLogColorSpaceW(HCOLORSPACE hColorSpace,LPLOGCOLORSPACEW lpBuffer,DWORD nSize); + WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceA(LPLOGCOLORSPACEA lplcs); + WINGDIAPI HCOLORSPACE WINAPI CreateColorSpaceW(LPLOGCOLORSPACEW lplcs); + WINGDIAPI HCOLORSPACE WINAPI SetColorSpace(HDC hdc,HCOLORSPACE hcs); + WINGDIAPI WINBOOL WINAPI DeleteColorSpace(HCOLORSPACE hcs); + WINGDIAPI WINBOOL WINAPI GetICMProfileA(HDC hdc,LPDWORD pBufSize,LPSTR pszFilename); + WINGDIAPI WINBOOL WINAPI GetICMProfileW(HDC hdc,LPDWORD pBufSize,LPWSTR pszFilename); + WINGDIAPI WINBOOL WINAPI SetICMProfileA(HDC hdc,LPSTR lpFileName); + WINGDIAPI WINBOOL WINAPI SetICMProfileW(HDC hdc,LPWSTR lpFileName); + WINGDIAPI WINBOOL WINAPI GetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); + WINGDIAPI WINBOOL WINAPI SetDeviceGammaRamp(HDC hdc,LPVOID lpRamp); + WINGDIAPI WINBOOL WINAPI ColorMatchToTarget(HDC hdc,HDC hdcTarget,DWORD action); + WINGDIAPI int WINAPI EnumICMProfilesA(HDC hdc,ICMENUMPROCA proc,LPARAM param); + WINGDIAPI int WINAPI EnumICMProfilesW(HDC hdc,ICMENUMPROCW proc,LPARAM param); + WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyA(DWORD reserved,LPSTR lpszCMID,LPSTR lpszFileName,UINT command); + WINGDIAPI WINBOOL WINAPI UpdateICMRegKeyW(DWORD reserved,LPWSTR lpszCMID,LPWSTR lpszFileName,UINT command); + WINGDIAPI WINBOOL WINAPI ColorCorrectPalette(HDC hdc,HPALETTE hPal,DWORD deFirst,DWORD num); + +#ifndef NOMETAFILE + +#define ENHMETA_SIGNATURE 0x464D4520 +#define ENHMETA_STOCK_OBJECT 0x80000000 + +#define EMR_HEADER 1 +#define EMR_POLYBEZIER 2 +#define EMR_POLYGON 3 +#define EMR_POLYLINE 4 +#define EMR_POLYBEZIERTO 5 +#define EMR_POLYLINETO 6 +#define EMR_POLYPOLYLINE 7 +#define EMR_POLYPOLYGON 8 +#define EMR_SETWINDOWEXTEX 9 +#define EMR_SETWINDOWORGEX 10 +#define EMR_SETVIEWPORTEXTEX 11 +#define EMR_SETVIEWPORTORGEX 12 +#define EMR_SETBRUSHORGEX 13 +#define EMR_EOF 14 +#define EMR_SETPIXELV 15 +#define EMR_SETMAPPERFLAGS 16 +#define EMR_SETMAPMODE 17 +#define EMR_SETBKMODE 18 +#define EMR_SETPOLYFILLMODE 19 +#define EMR_SETROP2 20 +#define EMR_SETSTRETCHBLTMODE 21 +#define EMR_SETTEXTALIGN 22 +#define EMR_SETCOLORADJUSTMENT 23 +#define EMR_SETTEXTCOLOR 24 +#define EMR_SETBKCOLOR 25 +#define EMR_OFFSETCLIPRGN 26 +#define EMR_MOVETOEX 27 +#define EMR_SETMETARGN 28 +#define EMR_EXCLUDECLIPRECT 29 +#define EMR_INTERSECTCLIPRECT 30 +#define EMR_SCALEVIEWPORTEXTEX 31 +#define EMR_SCALEWINDOWEXTEX 32 +#define EMR_SAVEDC 33 +#define EMR_RESTOREDC 34 +#define EMR_SETWORLDTRANSFORM 35 +#define EMR_MODIFYWORLDTRANSFORM 36 +#define EMR_SELECTOBJECT 37 +#define EMR_CREATEPEN 38 +#define EMR_CREATEBRUSHINDIRECT 39 +#define EMR_DELETEOBJECT 40 +#define EMR_ANGLEARC 41 +#define EMR_ELLIPSE 42 +#define EMR_RECTANGLE 43 +#define EMR_ROUNDRECT 44 +#define EMR_ARC 45 +#define EMR_CHORD 46 +#define EMR_PIE 47 +#define EMR_SELECTPALETTE 48 +#define EMR_CREATEPALETTE 49 +#define EMR_SETPALETTEENTRIES 50 +#define EMR_RESIZEPALETTE 51 +#define EMR_REALIZEPALETTE 52 +#define EMR_EXTFLOODFILL 53 +#define EMR_LINETO 54 +#define EMR_ARCTO 55 +#define EMR_POLYDRAW 56 +#define EMR_SETARCDIRECTION 57 +#define EMR_SETMITERLIMIT 58 +#define EMR_BEGINPATH 59 +#define EMR_ENDPATH 60 +#define EMR_CLOSEFIGURE 61 +#define EMR_FILLPATH 62 +#define EMR_STROKEANDFILLPATH 63 +#define EMR_STROKEPATH 64 +#define EMR_FLATTENPATH 65 +#define EMR_WIDENPATH 66 +#define EMR_SELECTCLIPPATH 67 +#define EMR_ABORTPATH 68 + +#define EMR_GDICOMMENT 70 +#define EMR_FILLRGN 71 +#define EMR_FRAMERGN 72 +#define EMR_INVERTRGN 73 +#define EMR_PAINTRGN 74 +#define EMR_EXTSELECTCLIPRGN 75 +#define EMR_BITBLT 76 +#define EMR_STRETCHBLT 77 +#define EMR_MASKBLT 78 +#define EMR_PLGBLT 79 +#define EMR_SETDIBITSTODEVICE 80 +#define EMR_STRETCHDIBITS 81 +#define EMR_EXTCREATEFONTINDIRECTW 82 +#define EMR_EXTTEXTOUTA 83 +#define EMR_EXTTEXTOUTW 84 +#define EMR_POLYBEZIER16 85 +#define EMR_POLYGON16 86 +#define EMR_POLYLINE16 87 +#define EMR_POLYBEZIERTO16 88 +#define EMR_POLYLINETO16 89 +#define EMR_POLYPOLYLINE16 90 +#define EMR_POLYPOLYGON16 91 +#define EMR_POLYDRAW16 92 +#define EMR_CREATEMONOBRUSH 93 +#define EMR_CREATEDIBPATTERNBRUSHPT 94 +#define EMR_EXTCREATEPEN 95 +#define EMR_POLYTEXTOUTA 96 +#define EMR_POLYTEXTOUTW 97 + +#define EMR_SETICMMODE 98 +#define EMR_CREATECOLORSPACE 99 +#define EMR_SETCOLORSPACE 100 +#define EMR_DELETECOLORSPACE 101 +#define EMR_GLSRECORD 102 +#define EMR_GLSBOUNDEDRECORD 103 +#define EMR_PIXELFORMAT 104 +#define EMR_RESERVED_105 105 +#define EMR_RESERVED_106 106 +#define EMR_RESERVED_107 107 +#define EMR_RESERVED_108 108 +#define EMR_RESERVED_109 109 +#define EMR_RESERVED_110 110 +#define EMR_COLORCORRECTPALETTE 111 +#define EMR_SETICMPROFILEA 112 +#define EMR_SETICMPROFILEW 113 +#define EMR_ALPHABLEND 114 +#define EMR_SETLAYOUT 115 +#define EMR_TRANSPARENTBLT 116 +#define EMR_RESERVED_117 117 +#define EMR_GRADIENTFILL 118 +#define EMR_RESERVED_119 119 +#define EMR_RESERVED_120 120 +#define EMR_COLORMATCHTOTARGETW 121 +#define EMR_CREATECOLORSPACEW 122 + +#define EMR_MIN 1 + +#define EMR_MAX 122 + + typedef struct tagEMR { + DWORD iType; + DWORD nSize; + } EMR,*PEMR; + + typedef struct tagEMRTEXT { + POINTL ptlReference; + DWORD nChars; + DWORD offString; + DWORD fOptions; + RECTL rcl; + DWORD offDx; + } EMRTEXT,*PEMRTEXT; + + typedef struct tagABORTPATH { + EMR emr; + } EMRABORTPATH,*PEMRABORTPATH,EMRBEGINPATH,*PEMRBEGINPATH,EMRENDPATH,*PEMRENDPATH,EMRCLOSEFIGURE,*PEMRCLOSEFIGURE,EMRFLATTENPATH,*PEMRFLATTENPATH,EMRWIDENPATH,*PEMRWIDENPATH,EMRSETMETARGN,*PEMRSETMETARGN,EMRSAVEDC,*PEMRSAVEDC,EMRREALIZEPALETTE,*PEMRREALIZEPALETTE; + + typedef struct tagEMRSELECTCLIPPATH { + EMR emr; + DWORD iMode; + } EMRSELECTCLIPPATH,*PEMRSELECTCLIPPATH,EMRSETBKMODE,*PEMRSETBKMODE,EMRSETMAPMODE,*PEMRSETMAPMODE,EMRSETLAYOUT,*PEMRSETLAYOUT, + EMRSETPOLYFILLMODE,*PEMRSETPOLYFILLMODE,EMRSETROP2,*PEMRSETROP2,EMRSETSTRETCHBLTMODE,*PEMRSETSTRETCHBLTMODE,EMRSETICMMODE, + *PEMRSETICMMODE,EMRSETTEXTALIGN,*PEMRSETTEXTALIGN; + + typedef struct tagEMRSETMITERLIMIT { + EMR emr; + FLOAT eMiterLimit; + } EMRSETMITERLIMIT,*PEMRSETMITERLIMIT; + + typedef struct tagEMRRESTOREDC { + EMR emr; + LONG iRelative; + } EMRRESTOREDC,*PEMRRESTOREDC; + + typedef struct tagEMRSETARCDIRECTION { + EMR emr; + DWORD iArcDirection; + + } EMRSETARCDIRECTION,*PEMRSETARCDIRECTION; + + typedef struct tagEMRSETMAPPERFLAGS { + EMR emr; + DWORD dwFlags; + } EMRSETMAPPERFLAGS,*PEMRSETMAPPERFLAGS; + + typedef struct tagEMRSETTEXTCOLOR { + EMR emr; + COLORREF crColor; + } EMRSETBKCOLOR,*PEMRSETBKCOLOR,EMRSETTEXTCOLOR,*PEMRSETTEXTCOLOR; + + typedef struct tagEMRSELECTOBJECT { + EMR emr; + DWORD ihObject; + } EMRSELECTOBJECT,*PEMRSELECTOBJECT,EMRDELETEOBJECT,*PEMRDELETEOBJECT; + + typedef struct tagEMRSELECTPALETTE { + EMR emr; + DWORD ihPal; + } EMRSELECTPALETTE,*PEMRSELECTPALETTE; + + typedef struct tagEMRRESIZEPALETTE { + EMR emr; + DWORD ihPal; + DWORD cEntries; + } EMRRESIZEPALETTE,*PEMRRESIZEPALETTE; + + typedef struct tagEMRSETPALETTEENTRIES { + EMR emr; + DWORD ihPal; + DWORD iStart; + DWORD cEntries; + PALETTEENTRY aPalEntries[1]; + } EMRSETPALETTEENTRIES,*PEMRSETPALETTEENTRIES; + + typedef struct tagEMRSETCOLORADJUSTMENT { + EMR emr; + COLORADJUSTMENT ColorAdjustment; + } EMRSETCOLORADJUSTMENT,*PEMRSETCOLORADJUSTMENT; + + typedef struct tagEMRGDICOMMENT { + EMR emr; + DWORD cbData; + BYTE Data[1]; + } EMRGDICOMMENT,*PEMRGDICOMMENT; + + typedef struct tagEMREOF { + EMR emr; + DWORD nPalEntries; + DWORD offPalEntries; + DWORD nSizeLast; + } EMREOF,*PEMREOF; + + typedef struct tagEMRLINETO { + EMR emr; + POINTL ptl; + } EMRLINETO,*PEMRLINETO,EMRMOVETOEX,*PEMRMOVETOEX; + + typedef struct tagEMROFFSETCLIPRGN { + EMR emr; + POINTL ptlOffset; + } EMROFFSETCLIPRGN,*PEMROFFSETCLIPRGN; + + typedef struct tagEMRFILLPATH { + EMR emr; + RECTL rclBounds; + } EMRFILLPATH,*PEMRFILLPATH,EMRSTROKEANDFILLPATH,*PEMRSTROKEANDFILLPATH,EMRSTROKEPATH,*PEMRSTROKEPATH; + + typedef struct tagEMREXCLUDECLIPRECT { + EMR emr; + RECTL rclClip; + } EMREXCLUDECLIPRECT,*PEMREXCLUDECLIPRECT,EMRINTERSECTCLIPRECT,*PEMRINTERSECTCLIPRECT; + + typedef struct tagEMRSETVIEWPORTORGEX { + EMR emr; + POINTL ptlOrigin; + } EMRSETVIEWPORTORGEX,*PEMRSETVIEWPORTORGEX,EMRSETWINDOWORGEX,*PEMRSETWINDOWORGEX,EMRSETBRUSHORGEX,*PEMRSETBRUSHORGEX; + + typedef struct tagEMRSETVIEWPORTEXTEX { + EMR emr; + SIZEL szlExtent; + } EMRSETVIEWPORTEXTEX,*PEMRSETVIEWPORTEXTEX,EMRSETWINDOWEXTEX,*PEMRSETWINDOWEXTEX; + + typedef struct tagEMRSCALEVIEWPORTEXTEX { + EMR emr; + LONG xNum; + LONG xDenom; + LONG yNum; + LONG yDenom; + } EMRSCALEVIEWPORTEXTEX,*PEMRSCALEVIEWPORTEXTEX,EMRSCALEWINDOWEXTEX,*PEMRSCALEWINDOWEXTEX; + + typedef struct tagEMRSETWORLDTRANSFORM { + EMR emr; + XFORM xform; + } EMRSETWORLDTRANSFORM,*PEMRSETWORLDTRANSFORM; + + typedef struct tagEMRMODIFYWORLDTRANSFORM { + EMR emr; + XFORM xform; + DWORD iMode; + } EMRMODIFYWORLDTRANSFORM,*PEMRMODIFYWORLDTRANSFORM; + + typedef struct tagEMRSETPIXELV { + EMR emr; + POINTL ptlPixel; + COLORREF crColor; + } EMRSETPIXELV,*PEMRSETPIXELV; + + typedef struct tagEMREXTFLOODFILL { + EMR emr; + POINTL ptlStart; + COLORREF crColor; + DWORD iMode; + } EMREXTFLOODFILL,*PEMREXTFLOODFILL; + + typedef struct tagEMRELLIPSE { + EMR emr; + RECTL rclBox; + } EMRELLIPSE,*PEMRELLIPSE,EMRRECTANGLE,*PEMRRECTANGLE; + + typedef struct tagEMRROUNDRECT { + EMR emr; + RECTL rclBox; + SIZEL szlCorner; + } EMRROUNDRECT,*PEMRROUNDRECT; + + typedef struct tagEMRARC { + EMR emr; + RECTL rclBox; + POINTL ptlStart; + POINTL ptlEnd; + } EMRARC,*PEMRARC,EMRARCTO,*PEMRARCTO,EMRCHORD,*PEMRCHORD,EMRPIE,*PEMRPIE; + + typedef struct tagEMRANGLEARC { + EMR emr; + POINTL ptlCenter; + DWORD nRadius; + FLOAT eStartAngle; + FLOAT eSweepAngle; + } EMRANGLEARC,*PEMRANGLEARC; + + typedef struct tagEMRPOLYLINE { + EMR emr; + RECTL rclBounds; + DWORD cptl; + POINTL aptl[1]; + } EMRPOLYLINE,*PEMRPOLYLINE,EMRPOLYBEZIER,*PEMRPOLYBEZIER,EMRPOLYGON,*PEMRPOLYGON,EMRPOLYBEZIERTO,*PEMRPOLYBEZIERTO,EMRPOLYLINETO,*PEMRPOLYLINETO; + + typedef struct tagEMRPOLYLINE16 { + EMR emr; + RECTL rclBounds; + DWORD cpts; + POINTS apts[1]; + } EMRPOLYLINE16,*PEMRPOLYLINE16,EMRPOLYBEZIER16,*PEMRPOLYBEZIER16,EMRPOLYGON16,*PEMRPOLYGON16,EMRPOLYBEZIERTO16,*PEMRPOLYBEZIERTO16,EMRPOLYLINETO16,*PEMRPOLYLINETO16; + + typedef struct tagEMRPOLYDRAW { + EMR emr; + RECTL rclBounds; + DWORD cptl; + POINTL aptl[1]; + BYTE abTypes[1]; + } EMRPOLYDRAW,*PEMRPOLYDRAW; + + typedef struct tagEMRPOLYDRAW16 { + EMR emr; + RECTL rclBounds; + DWORD cpts; + POINTS apts[1]; + BYTE abTypes[1]; + } EMRPOLYDRAW16,*PEMRPOLYDRAW16; + + typedef struct tagEMRPOLYPOLYLINE { + EMR emr; + RECTL rclBounds; + DWORD nPolys; + DWORD cptl; + DWORD aPolyCounts[1]; + POINTL aptl[1]; + } EMRPOLYPOLYLINE,*PEMRPOLYPOLYLINE,EMRPOLYPOLYGON,*PEMRPOLYPOLYGON; + + typedef struct tagEMRPOLYPOLYLINE16 { + EMR emr; + RECTL rclBounds; + DWORD nPolys; + DWORD cpts; + DWORD aPolyCounts[1]; + POINTS apts[1]; + } EMRPOLYPOLYLINE16,*PEMRPOLYPOLYLINE16,EMRPOLYPOLYGON16,*PEMRPOLYPOLYGON16; + + typedef struct tagEMRINVERTRGN { + EMR emr; + RECTL rclBounds; + DWORD cbRgnData; + BYTE RgnData[1]; + } EMRINVERTRGN,*PEMRINVERTRGN,EMRPAINTRGN,*PEMRPAINTRGN; + + typedef struct tagEMRFILLRGN { + EMR emr; + RECTL rclBounds; + DWORD cbRgnData; + DWORD ihBrush; + BYTE RgnData[1]; + } EMRFILLRGN,*PEMRFILLRGN; + + typedef struct tagEMRFRAMERGN { + EMR emr; + RECTL rclBounds; + DWORD cbRgnData; + DWORD ihBrush; + SIZEL szlStroke; + BYTE RgnData[1]; + } EMRFRAMERGN,*PEMRFRAMERGN; + + typedef struct tagEMREXTSELECTCLIPRGN { + EMR emr; + DWORD cbRgnData; + DWORD iMode; + BYTE RgnData[1]; + } EMREXTSELECTCLIPRGN,*PEMREXTSELECTCLIPRGN; + + typedef struct tagEMREXTTEXTOUTA { + EMR emr; + RECTL rclBounds; + DWORD iGraphicsMode; + FLOAT exScale; + FLOAT eyScale; + EMRTEXT emrtext; + } EMREXTTEXTOUTA,*PEMREXTTEXTOUTA,EMREXTTEXTOUTW,*PEMREXTTEXTOUTW; + + typedef struct tagEMRPOLYTEXTOUTA { + EMR emr; + RECTL rclBounds; + DWORD iGraphicsMode; + FLOAT exScale; + FLOAT eyScale; + LONG cStrings; + EMRTEXT aemrtext[1]; + } EMRPOLYTEXTOUTA,*PEMRPOLYTEXTOUTA,EMRPOLYTEXTOUTW,*PEMRPOLYTEXTOUTW; + + typedef struct tagEMRBITBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + } EMRBITBLT,*PEMRBITBLT; + + typedef struct tagEMRSTRETCHBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG cxSrc; + LONG cySrc; + } EMRSTRETCHBLT,*PEMRSTRETCHBLT; + + typedef struct tagEMRMASKBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG xMask; + LONG yMask; + DWORD iUsageMask; + DWORD offBmiMask; + DWORD cbBmiMask; + DWORD offBitsMask; + DWORD cbBitsMask; + } EMRMASKBLT,*PEMRMASKBLT; + + typedef struct tagEMRPLGBLT { + EMR emr; + RECTL rclBounds; + POINTL aptlDest[3]; + LONG xSrc; + LONG ySrc; + LONG cxSrc; + LONG cySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG xMask; + LONG yMask; + DWORD iUsageMask; + DWORD offBmiMask; + DWORD cbBmiMask; + DWORD offBitsMask; + DWORD cbBitsMask; + } EMRPLGBLT,*PEMRPLGBLT; + + typedef struct tagEMRSETDIBITSTODEVICE { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG xSrc; + LONG ySrc; + LONG cxSrc; + LONG cySrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + DWORD iUsageSrc; + DWORD iStartScan; + DWORD cScans; + } EMRSETDIBITSTODEVICE,*PEMRSETDIBITSTODEVICE; + + typedef struct tagEMRSTRETCHDIBITS { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG xSrc; + LONG ySrc; + LONG cxSrc; + LONG cySrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + DWORD iUsageSrc; + DWORD dwRop; + LONG cxDest; + LONG cyDest; + } EMRSTRETCHDIBITS,*PEMRSTRETCHDIBITS; + + typedef struct tagEMREXTCREATEFONTINDIRECTW { + EMR emr; + DWORD ihFont; + EXTLOGFONTW elfw; + } EMREXTCREATEFONTINDIRECTW,*PEMREXTCREATEFONTINDIRECTW; + + typedef struct tagEMRCREATEPALETTE { + EMR emr; + DWORD ihPal; + LOGPALETTE lgpl; + } EMRCREATEPALETTE,*PEMRCREATEPALETTE; + + typedef struct tagEMRCREATEPEN { + EMR emr; + DWORD ihPen; + LOGPEN lopn; + } EMRCREATEPEN,*PEMRCREATEPEN; + + typedef struct tagEMREXTCREATEPEN { + EMR emr; + DWORD ihPen; + DWORD offBmi; + DWORD cbBmi; + DWORD offBits; + DWORD cbBits; + EXTLOGPEN elp; + } EMREXTCREATEPEN,*PEMREXTCREATEPEN; + + typedef struct tagEMRCREATEBRUSHINDIRECT { + EMR emr; + DWORD ihBrush; + LOGBRUSH32 lb; + } EMRCREATEBRUSHINDIRECT,*PEMRCREATEBRUSHINDIRECT; + + typedef struct tagEMRCREATEMONOBRUSH { + EMR emr; + DWORD ihBrush; + DWORD iUsage; + DWORD offBmi; + DWORD cbBmi; + DWORD offBits; + DWORD cbBits; + } EMRCREATEMONOBRUSH,*PEMRCREATEMONOBRUSH; + + typedef struct tagEMRCREATEDIBPATTERNBRUSHPT { + EMR emr; + DWORD ihBrush; + DWORD iUsage; + DWORD offBmi; + DWORD cbBmi; + DWORD offBits; + DWORD cbBits; + } EMRCREATEDIBPATTERNBRUSHPT,*PEMRCREATEDIBPATTERNBRUSHPT; + + typedef struct tagEMRFORMAT { + DWORD dSignature; + DWORD nVersion; + DWORD cbData; + DWORD offData; + } EMRFORMAT,*PEMRFORMAT; + + typedef struct tagEMRGLSRECORD { + EMR emr; + DWORD cbData; + BYTE Data[1]; + } EMRGLSRECORD,*PEMRGLSRECORD; + + typedef struct tagEMRGLSBOUNDEDRECORD { + EMR emr; + RECTL rclBounds; + DWORD cbData; + BYTE Data[1]; + } EMRGLSBOUNDEDRECORD,*PEMRGLSBOUNDEDRECORD; + + typedef struct tagEMRPIXELFORMAT { + EMR emr; + PIXELFORMATDESCRIPTOR pfd; + } EMRPIXELFORMAT,*PEMRPIXELFORMAT; + + typedef struct tagEMRCREATECOLORSPACE { + EMR emr; + DWORD ihCS; + LOGCOLORSPACEA lcs; + } EMRCREATECOLORSPACE,*PEMRCREATECOLORSPACE; + + typedef struct tagEMRSETCOLORSPACE { + EMR emr; + DWORD ihCS; + } EMRSETCOLORSPACE,*PEMRSETCOLORSPACE,EMRSELECTCOLORSPACE,*PEMRSELECTCOLORSPACE,EMRDELETECOLORSPACE,*PEMRDELETECOLORSPACE; + + typedef struct tagEMREXTESCAPE { + EMR emr; + INT iEscape; + INT cbEscData; + BYTE EscData[1]; + } EMREXTESCAPE,*PEMREXTESCAPE,EMRDRAWESCAPE,*PEMRDRAWESCAPE; + + typedef struct tagEMRNAMEDESCAPE { + EMR emr; + INT iEscape; + INT cbDriver; + INT cbEscData; + BYTE EscData[1]; + } EMRNAMEDESCAPE,*PEMRNAMEDESCAPE; + +#define SETICMPROFILE_EMBEDED 0x00000001 + + typedef struct tagEMRSETICMPROFILE { + EMR emr; + DWORD dwFlags; + DWORD cbName; + DWORD cbData; + BYTE Data[1]; + } EMRSETICMPROFILE,*PEMRSETICMPROFILE,EMRSETICMPROFILEA,*PEMRSETICMPROFILEA,EMRSETICMPROFILEW,*PEMRSETICMPROFILEW; + +#define CREATECOLORSPACE_EMBEDED 0x00000001 + + typedef struct tagEMRCREATECOLORSPACEW { + EMR emr; + DWORD ihCS; + LOGCOLORSPACEW lcs; + DWORD dwFlags; + DWORD cbData; + BYTE Data[1]; + } EMRCREATECOLORSPACEW,*PEMRCREATECOLORSPACEW; + +#define COLORMATCHTOTARGET_EMBEDED 0x00000001 + + typedef struct tagCOLORMATCHTOTARGET { + EMR emr; + DWORD dwAction; + DWORD dwFlags; + DWORD cbName; + DWORD cbData; + BYTE Data[1]; + } EMRCOLORMATCHTOTARGET,*PEMRCOLORMATCHTOTARGET; + + typedef struct tagCOLORCORRECTPALETTE { + EMR emr; + DWORD ihPalette; + DWORD nFirstEntry; + DWORD nPalEntries; + DWORD nReserved; + } EMRCOLORCORRECTPALETTE,*PEMRCOLORCORRECTPALETTE; + + typedef struct tagEMRALPHABLEND { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG cxSrc; + LONG cySrc; + } EMRALPHABLEND,*PEMRALPHABLEND; + + typedef struct tagEMRGRADIENTFILL { + EMR emr; + RECTL rclBounds; + DWORD nVer; + DWORD nTri; + ULONG ulMode; + TRIVERTEX Ver[1]; + } EMRGRADIENTFILL,*PEMRGRADIENTFILL; + + typedef struct tagEMRTRANSPARENTBLT { + EMR emr; + RECTL rclBounds; + LONG xDest; + LONG yDest; + LONG cxDest; + LONG cyDest; + DWORD dwRop; + LONG xSrc; + LONG ySrc; + XFORM xformSrc; + COLORREF crBkColorSrc; + DWORD iUsageSrc; + DWORD offBmiSrc; + DWORD cbBmiSrc; + DWORD offBitsSrc; + DWORD cbBitsSrc; + LONG cxSrc; + LONG cySrc; + } EMRTRANSPARENTBLT,*PEMRTRANSPARENTBLT; + +#define GDICOMMENT_IDENTIFIER 0x43494447 +#define GDICOMMENT_WINDOWS_METAFILE 0x80000001 +#define GDICOMMENT_BEGINGROUP 0x00000002 +#define GDICOMMENT_ENDGROUP 0x00000003 +#define GDICOMMENT_MULTIFORMATS 0x40000004 +#define EPS_SIGNATURE 0x46535045 +#define GDICOMMENT_UNICODE_STRING 0x00000040 +#define GDICOMMENT_UNICODE_END 0x00000080 +#endif + +#ifdef UNICODE +#define wglUseFontBitmaps wglUseFontBitmapsW +#else +#define wglUseFontBitmaps wglUseFontBitmapsA +#endif + + WINGDIAPI WINBOOL WINAPI wglCopyContext(HGLRC,HGLRC,UINT); + WINGDIAPI HGLRC WINAPI wglCreateContext(HDC); + WINGDIAPI HGLRC WINAPI wglCreateLayerContext(HDC,int); + WINGDIAPI WINBOOL WINAPI wglDeleteContext(HGLRC); + WINGDIAPI HGLRC WINAPI wglGetCurrentContext(VOID); + WINGDIAPI HDC WINAPI wglGetCurrentDC(VOID); + WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR); + WINGDIAPI WINBOOL WINAPI wglMakeCurrent(HDC,HGLRC); + WINGDIAPI WINBOOL WINAPI wglShareLists(HGLRC,HGLRC); + WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsA(HDC,DWORD,DWORD,DWORD); + WINGDIAPI WINBOOL WINAPI wglUseFontBitmapsW(HDC,DWORD,DWORD,DWORD); + WINGDIAPI WINBOOL WINAPI SwapBuffers(HDC); + + typedef struct _POINTFLOAT { + FLOAT x; + FLOAT y; + } POINTFLOAT,*PPOINTFLOAT; + + typedef struct _GLYPHMETRICSFLOAT { + FLOAT gmfBlackBoxX; + FLOAT gmfBlackBoxY; + POINTFLOAT gmfptGlyphOrigin; + FLOAT gmfCellIncX; + FLOAT gmfCellIncY; + } GLYPHMETRICSFLOAT,*PGLYPHMETRICSFLOAT,*LPGLYPHMETRICSFLOAT; + +#define WGL_FONT_LINES 0 +#define WGL_FONT_POLYGONS 1 + +#ifdef UNICODE +#define wglUseFontOutlines wglUseFontOutlinesW +#else +#define wglUseFontOutlines wglUseFontOutlinesA +#endif + + WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesA(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); + WINGDIAPI WINBOOL WINAPI wglUseFontOutlinesW(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT); + + typedef struct tagLAYERPLANEDESCRIPTOR { + WORD nSize; + WORD nVersion; + DWORD dwFlags; + BYTE iPixelType; + BYTE cColorBits; + BYTE cRedBits; + BYTE cRedShift; + BYTE cGreenBits; + BYTE cGreenShift; + BYTE cBlueBits; + BYTE cBlueShift; + BYTE cAlphaBits; + BYTE cAlphaShift; + BYTE cAccumBits; + BYTE cAccumRedBits; + BYTE cAccumGreenBits; + BYTE cAccumBlueBits; + BYTE cAccumAlphaBits; + BYTE cDepthBits; + BYTE cStencilBits; + BYTE cAuxBuffers; + BYTE iLayerPlane; + BYTE bReserved; + COLORREF crTransparent; + } LAYERPLANEDESCRIPTOR,*PLAYERPLANEDESCRIPTOR,*LPLAYERPLANEDESCRIPTOR; + +#define LPD_DOUBLEBUFFER 0x00000001 +#define LPD_STEREO 0x00000002 +#define LPD_SUPPORT_GDI 0x00000010 +#define LPD_SUPPORT_OPENGL 0x00000020 +#define LPD_SHARE_DEPTH 0x00000040 +#define LPD_SHARE_STENCIL 0x00000080 +#define LPD_SHARE_ACCUM 0x00000100 +#define LPD_SWAP_EXCHANGE 0x00000200 +#define LPD_SWAP_COPY 0x00000400 +#define LPD_TRANSPARENT 0x00001000 + +#define LPD_TYPE_RGBA 0 +#define LPD_TYPE_COLORINDEX 1 + +#define WGL_SWAP_MAIN_PLANE 0x00000001 +#define WGL_SWAP_OVERLAY1 0x00000002 +#define WGL_SWAP_OVERLAY2 0x00000004 +#define WGL_SWAP_OVERLAY3 0x00000008 +#define WGL_SWAP_OVERLAY4 0x00000010 +#define WGL_SWAP_OVERLAY5 0x00000020 +#define WGL_SWAP_OVERLAY6 0x00000040 +#define WGL_SWAP_OVERLAY7 0x00000080 +#define WGL_SWAP_OVERLAY8 0x00000100 +#define WGL_SWAP_OVERLAY9 0x00000200 +#define WGL_SWAP_OVERLAY10 0x00000400 +#define WGL_SWAP_OVERLAY11 0x00000800 +#define WGL_SWAP_OVERLAY12 0x00001000 +#define WGL_SWAP_OVERLAY13 0x00002000 +#define WGL_SWAP_OVERLAY14 0x00004000 +#define WGL_SWAP_OVERLAY15 0x00008000 +#define WGL_SWAP_UNDERLAY1 0x00010000 +#define WGL_SWAP_UNDERLAY2 0x00020000 +#define WGL_SWAP_UNDERLAY3 0x00040000 +#define WGL_SWAP_UNDERLAY4 0x00080000 +#define WGL_SWAP_UNDERLAY5 0x00100000 +#define WGL_SWAP_UNDERLAY6 0x00200000 +#define WGL_SWAP_UNDERLAY7 0x00400000 +#define WGL_SWAP_UNDERLAY8 0x00800000 +#define WGL_SWAP_UNDERLAY9 0x01000000 +#define WGL_SWAP_UNDERLAY10 0x02000000 +#define WGL_SWAP_UNDERLAY11 0x04000000 +#define WGL_SWAP_UNDERLAY12 0x08000000 +#define WGL_SWAP_UNDERLAY13 0x10000000 +#define WGL_SWAP_UNDERLAY14 0x20000000 +#define WGL_SWAP_UNDERLAY15 0x40000000 + + WINGDIAPI WINBOOL WINAPI wglDescribeLayerPlane(HDC,int,int,UINT,LPLAYERPLANEDESCRIPTOR); + WINGDIAPI int WINAPI wglSetLayerPaletteEntries(HDC,int,int,int,CONST COLORREF *); + WINGDIAPI int WINAPI wglGetLayerPaletteEntries(HDC,int,int,int,COLORREF *); + WINGDIAPI WINBOOL WINAPI wglRealizeLayerPalette(HDC,int,WINBOOL); + WINGDIAPI WINBOOL WINAPI wglSwapLayerBuffers(HDC,UINT); + + typedef struct _WGLSWAP { + HDC hdc; + UINT uiFlags; + } WGLSWAP,*PWGLSWAP,*LPWGLSWAP; + +#define WGL_SWAPMULTIPLE_MAX 16 + + WINGDIAPI DWORD WINAPI wglSwapMultipleBuffers(UINT,CONST WGLSWAP *); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/winnls.h b/tcc/include/winapi/winnls.h index 4f17c7a0..296b4cb3 100644 --- a/tcc/include/winapi/winnls.h +++ b/tcc/include/winapi/winnls.h @@ -1,778 +1,778 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINNLS_ -#define _WINNLS_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef NONLS - -#define MAX_LEADBYTES 12 -#define MAX_DEFAULTCHAR 2 - -#define MB_PRECOMPOSED 0x00000001 -#define MB_COMPOSITE 0x00000002 -#define MB_USEGLYPHCHARS 0x00000004 -#define MB_ERR_INVALID_CHARS 0x00000008 - -#define WC_COMPOSITECHECK 0x00000200 -#define WC_DISCARDNS 0x00000010 -#define WC_SEPCHARS 0x00000020 -#define WC_DEFAULTCHAR 0x00000040 -#define WC_NO_BEST_FIT_CHARS 0x00000400 - -#define CT_CTYPE1 0x00000001 -#define CT_CTYPE2 0x00000002 -#define CT_CTYPE3 0x00000004 - -#define C1_UPPER 0x0001 -#define C1_LOWER 0x0002 -#define C1_DIGIT 0x0004 -#define C1_SPACE 0x0008 -#define C1_PUNCT 0x0010 -#define C1_CNTRL 0x0020 -#define C1_BLANK 0x0040 -#define C1_XDIGIT 0x0080 -#define C1_ALPHA 0x0100 -#define C1_DEFINED 0x0200 - -#define C2_LEFTTORIGHT 0x0001 -#define C2_RIGHTTOLEFT 0x0002 - -#define C2_EUROPENUMBER 0x0003 -#define C2_EUROPESEPARATOR 0x0004 -#define C2_EUROPETERMINATOR 0x0005 -#define C2_ARABICNUMBER 0x0006 -#define C2_COMMONSEPARATOR 0x0007 - -#define C2_BLOCKSEPARATOR 0x0008 -#define C2_SEGMENTSEPARATOR 0x0009 -#define C2_WHITESPACE 0x000A -#define C2_OTHERNEUTRAL 0x000B - -#define C2_NOTAPPLICABLE 0x0000 - -#define C3_NONSPACING 0x0001 -#define C3_DIACRITIC 0x0002 -#define C3_VOWELMARK 0x0004 -#define C3_SYMBOL 0x0008 - -#define C3_KATAKANA 0x0010 -#define C3_HIRAGANA 0x0020 -#define C3_HALFWIDTH 0x0040 -#define C3_FULLWIDTH 0x0080 -#define C3_IDEOGRAPH 0x0100 -#define C3_KASHIDA 0x0200 -#define C3_LEXICAL 0x0400 - -#define C3_ALPHA 0x8000 - -#define C3_NOTAPPLICABLE 0x0000 - -#define NORM_IGNORECASE 0x00000001 -#define NORM_IGNORENONSPACE 0x00000002 -#define NORM_IGNORESYMBOLS 0x00000004 - -#define NORM_IGNOREKANATYPE 0x00010000 -#define NORM_IGNOREWIDTH 0x00020000 - -#define MAP_FOLDCZONE 0x00000010 -#define MAP_PRECOMPOSED 0x00000020 -#define MAP_COMPOSITE 0x00000040 -#define MAP_FOLDDIGITS 0x00000080 -#define MAP_EXPAND_LIGATURES 0x00002000 - -#define LCMAP_LOWERCASE 0x00000100 -#define LCMAP_UPPERCASE 0x00000200 -#define LCMAP_SORTKEY 0x00000400 -#define LCMAP_BYTEREV 0x00000800 - -#define LCMAP_HIRAGANA 0x00100000 -#define LCMAP_KATAKANA 0x00200000 -#define LCMAP_HALFWIDTH 0x00400000 -#define LCMAP_FULLWIDTH 0x00800000 - -#define LCMAP_LINGUISTIC_CASING 0x01000000 - -#define LCMAP_SIMPLIFIED_CHINESE 0x02000000 -#define LCMAP_TRADITIONAL_CHINESE 0x04000000 - -#define LGRPID_INSTALLED 0x00000001 -#define LGRPID_SUPPORTED 0x00000002 - -#define LCID_INSTALLED 0x00000001 -#define LCID_SUPPORTED 0x00000002 -#define LCID_ALTERNATE_SORTS 0x00000004 - -#define CP_INSTALLED 0x00000001 -#define CP_SUPPORTED 0x00000002 - -#define SORT_STRINGSORT 0x00001000 - -#define CSTR_LESS_THAN 1 -#define CSTR_EQUAL 2 -#define CSTR_GREATER_THAN 3 - -#define CP_ACP 0 -#define CP_OEMCP 1 -#define CP_MACCP 2 -#define CP_THREAD_ACP 3 -#define CP_SYMBOL 42 - -#define CP_UTF7 65000 -#define CP_UTF8 65001 - -#define CTRY_DEFAULT 0 - -#define CTRY_ALBANIA 355 -#define CTRY_ALGERIA 213 -#define CTRY_ARGENTINA 54 -#define CTRY_ARMENIA 374 -#define CTRY_AUSTRALIA 61 -#define CTRY_AUSTRIA 43 -#define CTRY_AZERBAIJAN 994 -#define CTRY_BAHRAIN 973 -#define CTRY_BELARUS 375 -#define CTRY_BELGIUM 32 -#define CTRY_BELIZE 501 -#define CTRY_BOLIVIA 591 -#define CTRY_BRAZIL 55 -#define CTRY_BRUNEI_DARUSSALAM 673 -#define CTRY_BULGARIA 359 -#define CTRY_CANADA 2 -#define CTRY_CARIBBEAN 1 -#define CTRY_CHILE 56 -#define CTRY_COLOMBIA 57 -#define CTRY_COSTA_RICA 506 -#define CTRY_CROATIA 385 -#define CTRY_CZECH 420 -#define CTRY_DENMARK 45 -#define CTRY_DOMINICAN_REPUBLIC 1 -#define CTRY_ECUADOR 593 -#define CTRY_EGYPT 20 -#define CTRY_EL_SALVADOR 503 -#define CTRY_ESTONIA 372 -#define CTRY_FAEROE_ISLANDS 298 -#define CTRY_FINLAND 358 -#define CTRY_FRANCE 33 -#define CTRY_GEORGIA 995 -#define CTRY_GERMANY 49 -#define CTRY_GREECE 30 -#define CTRY_GUATEMALA 502 -#define CTRY_HONDURAS 504 -#define CTRY_HONG_KONG 852 -#define CTRY_HUNGARY 36 -#define CTRY_ICELAND 354 -#define CTRY_INDIA 91 -#define CTRY_INDONESIA 62 -#define CTRY_IRAN 981 -#define CTRY_IRAQ 964 -#define CTRY_IRELAND 353 -#define CTRY_ISRAEL 972 -#define CTRY_ITALY 39 -#define CTRY_JAMAICA 1 -#define CTRY_JAPAN 81 -#define CTRY_JORDAN 962 -#define CTRY_KAZAKSTAN 7 -#define CTRY_KENYA 254 -#define CTRY_KUWAIT 965 -#define CTRY_KYRGYZSTAN 996 -#define CTRY_LATVIA 371 -#define CTRY_LEBANON 961 -#define CTRY_LIBYA 218 -#define CTRY_LIECHTENSTEIN 41 -#define CTRY_LITHUANIA 370 -#define CTRY_LUXEMBOURG 352 -#define CTRY_MACAU 853 -#define CTRY_MACEDONIA 389 -#define CTRY_MALAYSIA 60 -#define CTRY_MALDIVES 960 -#define CTRY_MEXICO 52 -#define CTRY_MONACO 33 -#define CTRY_MONGOLIA 976 -#define CTRY_MOROCCO 212 -#define CTRY_NETHERLANDS 31 -#define CTRY_NEW_ZEALAND 64 -#define CTRY_NICARAGUA 505 -#define CTRY_NORWAY 47 -#define CTRY_OMAN 968 -#define CTRY_PAKISTAN 92 -#define CTRY_PANAMA 507 -#define CTRY_PARAGUAY 595 -#define CTRY_PERU 51 -#define CTRY_PHILIPPINES 63 -#define CTRY_POLAND 48 -#define CTRY_PORTUGAL 351 -#define CTRY_PRCHINA 86 -#define CTRY_PUERTO_RICO 1 -#define CTRY_QATAR 974 -#define CTRY_ROMANIA 40 -#define CTRY_RUSSIA 7 -#define CTRY_SAUDI_ARABIA 966 -#define CTRY_SERBIA 381 -#define CTRY_SINGAPORE 65 -#define CTRY_SLOVAK 421 -#define CTRY_SLOVENIA 386 -#define CTRY_SOUTH_AFRICA 27 -#define CTRY_SOUTH_KOREA 82 -#define CTRY_SPAIN 34 -#define CTRY_SWEDEN 46 -#define CTRY_SWITZERLAND 41 -#define CTRY_SYRIA 963 -#define CTRY_TAIWAN 886 -#define CTRY_TATARSTAN 7 -#define CTRY_THAILAND 66 -#define CTRY_TRINIDAD_Y_TOBAGO 1 -#define CTRY_TUNISIA 216 -#define CTRY_TURKEY 90 -#define CTRY_UAE 971 -#define CTRY_UKRAINE 380 -#define CTRY_UNITED_KINGDOM 44 -#define CTRY_UNITED_STATES 1 -#define CTRY_URUGUAY 598 -#define CTRY_UZBEKISTAN 7 -#define CTRY_VENEZUELA 58 -#define CTRY_VIET_NAM 84 -#define CTRY_YEMEN 967 -#define CTRY_ZIMBABWE 263 - -#define LOCALE_NOUSEROVERRIDE 0x80000000 -#define LOCALE_USE_CP_ACP 0x40000000 -#define LOCALE_RETURN_NUMBER 0x20000000 - -#define LOCALE_ILANGUAGE 0x00000001 -#define LOCALE_SLANGUAGE 0x00000002 -#define LOCALE_SENGLANGUAGE 0x00001001 -#define LOCALE_SABBREVLANGNAME 0x00000003 -#define LOCALE_SNATIVELANGNAME 0x00000004 - -#define LOCALE_ICOUNTRY 0x00000005 -#define LOCALE_SCOUNTRY 0x00000006 -#define LOCALE_SENGCOUNTRY 0x00001002 -#define LOCALE_SABBREVCTRYNAME 0x00000007 -#define LOCALE_SNATIVECTRYNAME 0x00000008 - -#define LOCALE_IDEFAULTLANGUAGE 0x00000009 -#define LOCALE_IDEFAULTCOUNTRY 0x0000000A -#define LOCALE_IDEFAULTCODEPAGE 0x0000000B -#define LOCALE_IDEFAULTANSICODEPAGE 0x00001004 -#define LOCALE_IDEFAULTMACCODEPAGE 0x00001011 - -#define LOCALE_SLIST 0x0000000C -#define LOCALE_IMEASURE 0x0000000D - -#define LOCALE_SDECIMAL 0x0000000E -#define LOCALE_STHOUSAND 0x0000000F -#define LOCALE_SGROUPING 0x00000010 -#define LOCALE_IDIGITS 0x00000011 -#define LOCALE_ILZERO 0x00000012 -#define LOCALE_INEGNUMBER 0x00001010 -#define LOCALE_SNATIVEDIGITS 0x00000013 - -#define LOCALE_SCURRENCY 0x00000014 -#define LOCALE_SINTLSYMBOL 0x00000015 -#define LOCALE_SMONDECIMALSEP 0x00000016 -#define LOCALE_SMONTHOUSANDSEP 0x00000017 -#define LOCALE_SMONGROUPING 0x00000018 -#define LOCALE_ICURRDIGITS 0x00000019 -#define LOCALE_IINTLCURRDIGITS 0x0000001A -#define LOCALE_ICURRENCY 0x0000001B -#define LOCALE_INEGCURR 0x0000001C - -#define LOCALE_SDATE 0x0000001D -#define LOCALE_STIME 0x0000001E -#define LOCALE_SSHORTDATE 0x0000001F -#define LOCALE_SLONGDATE 0x00000020 -#define LOCALE_STIMEFORMAT 0x00001003 -#define LOCALE_IDATE 0x00000021 -#define LOCALE_ILDATE 0x00000022 -#define LOCALE_ITIME 0x00000023 -#define LOCALE_ITIMEMARKPOSN 0x00001005 -#define LOCALE_ICENTURY 0x00000024 -#define LOCALE_ITLZERO 0x00000025 -#define LOCALE_IDAYLZERO 0x00000026 -#define LOCALE_IMONLZERO 0x00000027 -#define LOCALE_S1159 0x00000028 -#define LOCALE_S2359 0x00000029 - -#define LOCALE_ICALENDARTYPE 0x00001009 -#define LOCALE_IOPTIONALCALENDAR 0x0000100B -#define LOCALE_IFIRSTDAYOFWEEK 0x0000100C -#define LOCALE_IFIRSTWEEKOFYEAR 0x0000100D - -#define LOCALE_SDAYNAME1 0x0000002A -#define LOCALE_SDAYNAME2 0x0000002B -#define LOCALE_SDAYNAME3 0x0000002C -#define LOCALE_SDAYNAME4 0x0000002D -#define LOCALE_SDAYNAME5 0x0000002E -#define LOCALE_SDAYNAME6 0x0000002F -#define LOCALE_SDAYNAME7 0x00000030 -#define LOCALE_SABBREVDAYNAME1 0x00000031 -#define LOCALE_SABBREVDAYNAME2 0x00000032 -#define LOCALE_SABBREVDAYNAME3 0x00000033 -#define LOCALE_SABBREVDAYNAME4 0x00000034 -#define LOCALE_SABBREVDAYNAME5 0x00000035 -#define LOCALE_SABBREVDAYNAME6 0x00000036 -#define LOCALE_SABBREVDAYNAME7 0x00000037 -#define LOCALE_SMONTHNAME1 0x00000038 -#define LOCALE_SMONTHNAME2 0x00000039 -#define LOCALE_SMONTHNAME3 0x0000003A -#define LOCALE_SMONTHNAME4 0x0000003B -#define LOCALE_SMONTHNAME5 0x0000003C -#define LOCALE_SMONTHNAME6 0x0000003D -#define LOCALE_SMONTHNAME7 0x0000003E -#define LOCALE_SMONTHNAME8 0x0000003F -#define LOCALE_SMONTHNAME9 0x00000040 -#define LOCALE_SMONTHNAME10 0x00000041 -#define LOCALE_SMONTHNAME11 0x00000042 -#define LOCALE_SMONTHNAME12 0x00000043 -#define LOCALE_SMONTHNAME13 0x0000100E -#define LOCALE_SABBREVMONTHNAME1 0x00000044 -#define LOCALE_SABBREVMONTHNAME2 0x00000045 -#define LOCALE_SABBREVMONTHNAME3 0x00000046 -#define LOCALE_SABBREVMONTHNAME4 0x00000047 -#define LOCALE_SABBREVMONTHNAME5 0x00000048 -#define LOCALE_SABBREVMONTHNAME6 0x00000049 -#define LOCALE_SABBREVMONTHNAME7 0x0000004A -#define LOCALE_SABBREVMONTHNAME8 0x0000004B -#define LOCALE_SABBREVMONTHNAME9 0x0000004C -#define LOCALE_SABBREVMONTHNAME10 0x0000004D -#define LOCALE_SABBREVMONTHNAME11 0x0000004E -#define LOCALE_SABBREVMONTHNAME12 0x0000004F -#define LOCALE_SABBREVMONTHNAME13 0x0000100F - -#define LOCALE_SPOSITIVESIGN 0x00000050 -#define LOCALE_SNEGATIVESIGN 0x00000051 -#define LOCALE_IPOSSIGNPOSN 0x00000052 -#define LOCALE_INEGSIGNPOSN 0x00000053 -#define LOCALE_IPOSSYMPRECEDES 0x00000054 -#define LOCALE_IPOSSEPBYSPACE 0x00000055 -#define LOCALE_INEGSYMPRECEDES 0x00000056 -#define LOCALE_INEGSEPBYSPACE 0x00000057 -#define LOCALE_FONTSIGNATURE 0x00000058 -#define LOCALE_SISO639LANGNAME 0x00000059 -#define LOCALE_SISO3166CTRYNAME 0x0000005A - -#define LOCALE_IDEFAULTEBCDICCODEPAGE 0x00001012 -#define LOCALE_IPAPERSIZE 0x0000100A -#define LOCALE_SENGCURRNAME 0x00001007 -#define LOCALE_SNATIVECURRNAME 0x00001008 -#define LOCALE_SYEARMONTH 0x00001006 -#define LOCALE_SSORTNAME 0x00001013 -#define LOCALE_IDIGITSUBSTITUTION 0x00001014 - -#define TIME_NOMINUTESORSECONDS 0x00000001 -#define TIME_NOSECONDS 0x00000002 -#define TIME_NOTIMEMARKER 0x00000004 -#define TIME_FORCE24HOURFORMAT 0x00000008 - -#define DATE_SHORTDATE 0x00000001 -#define DATE_LONGDATE 0x00000002 -#define DATE_USE_ALT_CALENDAR 0x00000004 -#define DATE_YEARMONTH 0x00000008 -#define DATE_LTRREADING 0x00000010 -#define DATE_RTLREADING 0x00000020 - -#define CAL_NOUSEROVERRIDE LOCALE_NOUSEROVERRIDE -#define CAL_USE_CP_ACP LOCALE_USE_CP_ACP -#define CAL_RETURN_NUMBER LOCALE_RETURN_NUMBER - -#define CAL_ICALINTVALUE 0x00000001 -#define CAL_SCALNAME 0x00000002 -#define CAL_IYEAROFFSETRANGE 0x00000003 -#define CAL_SERASTRING 0x00000004 -#define CAL_SSHORTDATE 0x00000005 -#define CAL_SLONGDATE 0x00000006 -#define CAL_SDAYNAME1 0x00000007 -#define CAL_SDAYNAME2 0x00000008 -#define CAL_SDAYNAME3 0x00000009 -#define CAL_SDAYNAME4 0x0000000a -#define CAL_SDAYNAME5 0x0000000b -#define CAL_SDAYNAME6 0x0000000c -#define CAL_SDAYNAME7 0x0000000d -#define CAL_SABBREVDAYNAME1 0x0000000e -#define CAL_SABBREVDAYNAME2 0x0000000f -#define CAL_SABBREVDAYNAME3 0x00000010 -#define CAL_SABBREVDAYNAME4 0x00000011 -#define CAL_SABBREVDAYNAME5 0x00000012 -#define CAL_SABBREVDAYNAME6 0x00000013 -#define CAL_SABBREVDAYNAME7 0x00000014 -#define CAL_SMONTHNAME1 0x00000015 -#define CAL_SMONTHNAME2 0x00000016 -#define CAL_SMONTHNAME3 0x00000017 -#define CAL_SMONTHNAME4 0x00000018 -#define CAL_SMONTHNAME5 0x00000019 -#define CAL_SMONTHNAME6 0x0000001a -#define CAL_SMONTHNAME7 0x0000001b -#define CAL_SMONTHNAME8 0x0000001c -#define CAL_SMONTHNAME9 0x0000001d -#define CAL_SMONTHNAME10 0x0000001e -#define CAL_SMONTHNAME11 0x0000001f -#define CAL_SMONTHNAME12 0x00000020 -#define CAL_SMONTHNAME13 0x00000021 -#define CAL_SABBREVMONTHNAME1 0x00000022 -#define CAL_SABBREVMONTHNAME2 0x00000023 -#define CAL_SABBREVMONTHNAME3 0x00000024 -#define CAL_SABBREVMONTHNAME4 0x00000025 -#define CAL_SABBREVMONTHNAME5 0x00000026 -#define CAL_SABBREVMONTHNAME6 0x00000027 -#define CAL_SABBREVMONTHNAME7 0x00000028 -#define CAL_SABBREVMONTHNAME8 0x00000029 -#define CAL_SABBREVMONTHNAME9 0x0000002a -#define CAL_SABBREVMONTHNAME10 0x0000002b -#define CAL_SABBREVMONTHNAME11 0x0000002c -#define CAL_SABBREVMONTHNAME12 0x0000002d -#define CAL_SABBREVMONTHNAME13 0x0000002e -#define CAL_SYEARMONTH 0x0000002f -#define CAL_ITWODIGITYEARMAX 0x00000030 - -#define ENUM_ALL_CALENDARS 0xffffffff - -#define CAL_GREGORIAN 1 -#define CAL_GREGORIAN_US 2 -#define CAL_JAPAN 3 -#define CAL_TAIWAN 4 -#define CAL_KOREA 5 -#define CAL_HIJRI 6 -#define CAL_THAI 7 -#define CAL_HEBREW 8 -#define CAL_GREGORIAN_ME_FRENCH 9 -#define CAL_GREGORIAN_ARABIC 10 -#define CAL_GREGORIAN_XLIT_ENGLISH 11 -#define CAL_GREGORIAN_XLIT_FRENCH 12 - -#define LGRPID_WESTERN_EUROPE 0x0001 -#define LGRPID_CENTRAL_EUROPE 0x0002 -#define LGRPID_BALTIC 0x0003 -#define LGRPID_GREEK 0x0004 -#define LGRPID_CYRILLIC 0x0005 -#define LGRPID_TURKISH 0x0006 -#define LGRPID_JAPANESE 0x0007 -#define LGRPID_KOREAN 0x0008 -#define LGRPID_TRADITIONAL_CHINESE 0x0009 -#define LGRPID_SIMPLIFIED_CHINESE 0x000a -#define LGRPID_THAI 0x000b -#define LGRPID_HEBREW 0x000c -#define LGRPID_ARABIC 0x000d -#define LGRPID_VIETNAMESE 0x000e -#define LGRPID_INDIC 0x000f -#define LGRPID_GEORGIAN 0x0010 -#define LGRPID_ARMENIAN 0x0011 - - typedef DWORD LGRPID; - typedef DWORD LCTYPE; - typedef DWORD CALTYPE; - typedef DWORD CALID; - - typedef struct _cpinfo { - UINT MaxCharSize; - BYTE DefaultChar[MAX_DEFAULTCHAR]; - BYTE LeadByte[MAX_LEADBYTES]; - } CPINFO,*LPCPINFO; - - typedef struct _cpinfoexA { - UINT MaxCharSize; - BYTE DefaultChar[MAX_DEFAULTCHAR]; - BYTE LeadByte[MAX_LEADBYTES]; - WCHAR UnicodeDefaultChar; - UINT CodePage; - CHAR CodePageName[MAX_PATH]; - } CPINFOEXA,*LPCPINFOEXA; - - typedef struct _cpinfoexW { - UINT MaxCharSize; - BYTE DefaultChar[MAX_DEFAULTCHAR]; - BYTE LeadByte[MAX_LEADBYTES]; - WCHAR UnicodeDefaultChar; - UINT CodePage; - WCHAR CodePageName[MAX_PATH]; - } CPINFOEXW,*LPCPINFOEXW; - -#ifdef UNICODE - typedef CPINFOEXW CPINFOEX; - typedef LPCPINFOEXW LPCPINFOEX; -#else - typedef CPINFOEXA CPINFOEX; - typedef LPCPINFOEXA LPCPINFOEX; -#endif - - typedef struct _numberfmtA { - UINT NumDigits; - UINT LeadingZero; - UINT Grouping; - LPSTR lpDecimalSep; - LPSTR lpThousandSep; - UINT NegativeOrder; - } NUMBERFMTA,*LPNUMBERFMTA; - - typedef struct _numberfmtW { - UINT NumDigits; - UINT LeadingZero; - UINT Grouping; - LPWSTR lpDecimalSep; - LPWSTR lpThousandSep; - UINT NegativeOrder; - } NUMBERFMTW,*LPNUMBERFMTW; - -#ifdef UNICODE - typedef NUMBERFMTW NUMBERFMT; - typedef LPNUMBERFMTW LPNUMBERFMT; -#else - typedef NUMBERFMTA NUMBERFMT; - typedef LPNUMBERFMTA LPNUMBERFMT; -#endif - - typedef struct _currencyfmtA { - UINT NumDigits; - UINT LeadingZero; - UINT Grouping; - LPSTR lpDecimalSep; - LPSTR lpThousandSep; - UINT NegativeOrder; - UINT PositiveOrder; - LPSTR lpCurrencySymbol; - } CURRENCYFMTA,*LPCURRENCYFMTA; - - typedef struct _currencyfmtW { - UINT NumDigits; - UINT LeadingZero; - UINT Grouping; - LPWSTR lpDecimalSep; - LPWSTR lpThousandSep; - UINT NegativeOrder; - UINT PositiveOrder; - LPWSTR lpCurrencySymbol; - } CURRENCYFMTW,*LPCURRENCYFMTW; - -#ifdef UNICODE - typedef CURRENCYFMTW CURRENCYFMT; - typedef LPCURRENCYFMTW LPCURRENCYFMT; -#else - typedef CURRENCYFMTA CURRENCYFMT; - typedef LPCURRENCYFMTA LPCURRENCYFMT; -#endif - - enum SYSNLS_FUNCTION { - COMPARE_STRING = 0x0001 - }; - - typedef DWORD NLS_FUNCTION; - - typedef struct _nlsversioninfo{ - DWORD dwNLSVersionInfoSize; - DWORD dwNLSVersion; - DWORD dwDefinedVersion; - } NLSVERSIONINFO,*LPNLSVERSIONINFO; - - typedef LONG GEOID; - typedef DWORD GEOTYPE; - typedef DWORD GEOCLASS; - -#define GEOID_NOT_AVAILABLE -1 - - enum SYSGEOTYPE { - GEO_NATION = 0x0001,GEO_LATITUDE = 0x0002,GEO_LONGITUDE = 0x0003,GEO_ISO2 = 0x0004,GEO_ISO3 = 0x0005,GEO_RFC1766 = 0x0006,GEO_LCID = 0x0007, - GEO_FRIENDLYNAME= 0x0008,GEO_OFFICIALNAME= 0x0009,GEO_TIMEZONES = 0x000A,GEO_OFFICIALLANGUAGES = 0x000B - }; - - enum SYSGEOCLASS { - GEOCLASS_NATION = 16,GEOCLASS_REGION = 14 - }; - - typedef enum _NORM_FORM { - NormalizationOther = 0, - NormalizationC = 0x1, - NormalizationD = 0x2, - NormalizationKC = 0x5, - NormalizationKD = 0x6 -} NORM_FORM; - - typedef WINBOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCA)(LGRPID,LPSTR,LPSTR,DWORD,LONG_PTR); - typedef WINBOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCA)(LGRPID,LCID,LPSTR,LONG_PTR); - typedef WINBOOL (CALLBACK *UILANGUAGE_ENUMPROCA)(LPSTR,LONG_PTR); - typedef WINBOOL (CALLBACK *LOCALE_ENUMPROCA)(LPSTR); - typedef WINBOOL (CALLBACK *CODEPAGE_ENUMPROCA)(LPSTR); - typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCA)(LPSTR); - typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCEXA)(LPSTR,CALID); - typedef WINBOOL (CALLBACK *TIMEFMT_ENUMPROCA)(LPSTR); - typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCA)(LPSTR); - typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCEXA)(LPSTR,CALID); - typedef WINBOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCW)(LGRPID,LPWSTR,LPWSTR,DWORD,LONG_PTR); - typedef WINBOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCW)(LGRPID,LCID,LPWSTR,LONG_PTR); - typedef WINBOOL (CALLBACK *UILANGUAGE_ENUMPROCW)(LPWSTR,LONG_PTR); - typedef WINBOOL (CALLBACK *LOCALE_ENUMPROCW)(LPWSTR); - typedef WINBOOL (CALLBACK *CODEPAGE_ENUMPROCW)(LPWSTR); - typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCW)(LPWSTR); - typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCEXW)(LPWSTR,CALID); - typedef WINBOOL (CALLBACK *TIMEFMT_ENUMPROCW)(LPWSTR); - typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCW)(LPWSTR); - typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCEXW)(LPWSTR,CALID); - typedef WINBOOL (CALLBACK *GEO_ENUMPROC)(GEOID); - -#ifdef UNICODE -#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCW -#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCW -#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCW -#define LOCALE_ENUMPROC LOCALE_ENUMPROCW -#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCW -#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCW -#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXW -#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCW -#define CALINFO_ENUMPROC CALINFO_ENUMPROCW -#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXW -#else -#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCA -#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCA -#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCA -#define LOCALE_ENUMPROC LOCALE_ENUMPROCA -#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCA -#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCA -#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXA -#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCA -#define CALINFO_ENUMPROC CALINFO_ENUMPROCA -#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXA -#endif - -#ifdef UNICODE -#define GetCPInfoEx GetCPInfoExW -#define CompareString CompareStringW -#define LCMapString LCMapStringW -#define GetLocaleInfo GetLocaleInfoW -#define SetLocaleInfo SetLocaleInfoW -#define GetCalendarInfo GetCalendarInfoW -#define SetCalendarInfo SetCalendarInfoW -#define GetTimeFormat GetTimeFormatW -#define GetDateFormat GetDateFormatW -#define GetNumberFormat GetNumberFormatW -#define GetCurrencyFormat GetCurrencyFormatW -#define EnumCalendarInfo EnumCalendarInfoW -#define EnumCalendarInfoEx EnumCalendarInfoExW -#define EnumTimeFormats EnumTimeFormatsW -#define EnumDateFormats EnumDateFormatsW -#define EnumDateFormatsEx EnumDateFormatsExW -#define GetGeoInfo GetGeoInfoW -#define GetStringTypeEx GetStringTypeExW -#define FoldString FoldStringW -#define EnumSystemLanguageGroups EnumSystemLanguageGroupsW -#define EnumLanguageGroupLocales EnumLanguageGroupLocalesW -#define EnumUILanguages EnumUILanguagesW -#define EnumSystemLocales EnumSystemLocalesW -#define EnumSystemCodePages EnumSystemCodePagesW -#else -#define GetCPInfoEx GetCPInfoExA -#define CompareString CompareStringA -#define LCMapString LCMapStringA -#define GetLocaleInfo GetLocaleInfoA -#define SetLocaleInfo SetLocaleInfoA -#define GetCalendarInfo GetCalendarInfoA -#define SetCalendarInfo SetCalendarInfoA -#define GetTimeFormat GetTimeFormatA -#define GetDateFormat GetDateFormatA -#define GetNumberFormat GetNumberFormatA -#define GetCurrencyFormat GetCurrencyFormatA -#define EnumCalendarInfo EnumCalendarInfoA -#define EnumCalendarInfoEx EnumCalendarInfoExA -#define EnumTimeFormats EnumTimeFormatsA -#define EnumDateFormats EnumDateFormatsA -#define EnumDateFormatsEx EnumDateFormatsExA -#define GetGeoInfo GetGeoInfoA -#define GetStringTypeEx GetStringTypeExA -#define FoldString FoldStringA -#define EnumSystemLanguageGroups EnumSystemLanguageGroupsA -#define EnumLanguageGroupLocales EnumLanguageGroupLocalesA -#define EnumUILanguages EnumUILanguagesA -#define EnumSystemLocales EnumSystemLocalesA -#define EnumSystemCodePages EnumSystemCodePagesA -#endif - - WINBASEAPI WINBOOL WINAPI IsValidCodePage(UINT CodePage); - WINBASEAPI UINT WINAPI GetACP(void); - WINBASEAPI UINT WINAPI GetOEMCP(void); - WINBASEAPI WINBOOL WINAPI GetCPInfo(UINT CodePage,LPCPINFO lpCPInfo); - WINBASEAPI WINBOOL WINAPI GetCPInfoExA(UINT CodePage,DWORD dwFlags,LPCPINFOEXA lpCPInfoEx); - WINBASEAPI WINBOOL WINAPI GetCPInfoExW(UINT CodePage,DWORD dwFlags,LPCPINFOEXW lpCPInfoEx); - WINBASEAPI WINBOOL WINAPI IsDBCSLeadByte(BYTE TestChar); - WINBASEAPI WINBOOL WINAPI IsDBCSLeadByteEx(UINT CodePage,BYTE TestChar); - WINBASEAPI int WINAPI MultiByteToWideChar(UINT CodePage,DWORD dwFlags,LPCSTR lpMultiByteStr,int cbMultiByte,LPWSTR lpWideCharStr,int cchWideChar); - WINBASEAPI int WINAPI WideCharToMultiByte(UINT CodePage,DWORD dwFlags,LPCWSTR lpWideCharStr,int cchWideChar,LPSTR lpMultiByteStr,int cbMultiByte,LPCSTR lpDefaultChar,LPBOOL lpUsedDefaultChar); - WINBASEAPI int WINAPI CompareStringA(LCID Locale,DWORD dwCmpFlags,LPCSTR lpString1,int cchCount1,LPCSTR lpString2,int cchCount2); - WINBASEAPI int WINAPI CompareStringW(LCID Locale,DWORD dwCmpFlags,LPCWSTR lpString1,int cchCount1,LPCWSTR lpString2,int cchCount2); - WINBASEAPI int WINAPI LCMapStringA(LCID Locale,DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest); - WINBASEAPI int WINAPI LCMapStringW(LCID Locale,DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest); - WINBASEAPI int WINAPI GetLocaleInfoA(LCID Locale,LCTYPE LCType,LPSTR lpLCData,int cchData); - WINBASEAPI int WINAPI GetLocaleInfoW(LCID Locale,LCTYPE LCType,LPWSTR lpLCData,int cchData); - WINBASEAPI WINBOOL WINAPI SetLocaleInfoA(LCID Locale,LCTYPE LCType,LPCSTR lpLCData); - WINBASEAPI WINBOOL WINAPI SetLocaleInfoW(LCID Locale,LCTYPE LCType,LPCWSTR lpLCData); - WINBASEAPI int WINAPI GetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPSTR lpCalData,int cchData,LPDWORD lpValue); - WINBASEAPI int WINAPI GetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPWSTR lpCalData,int cchData,LPDWORD lpValue); - WINBASEAPI WINBOOL WINAPI SetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPCSTR lpCalData); - WINBASEAPI WINBOOL WINAPI SetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPCWSTR lpCalData); - WINBASEAPI int WINAPI GetTimeFormatA(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpTime,LPCSTR lpFormat,LPSTR lpTimeStr,int cchTime); - WINBASEAPI int WINAPI GetTimeFormatW(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpTime,LPCWSTR lpFormat,LPWSTR lpTimeStr,int cchTime); - WINBASEAPI int WINAPI GetDateFormatA(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpDate,LPCSTR lpFormat,LPSTR lpDateStr,int cchDate); - WINBASEAPI int WINAPI GetDateFormatW(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpDate,LPCWSTR lpFormat,LPWSTR lpDateStr,int cchDate); - WINBASEAPI int WINAPI GetNumberFormatA(LCID Locale,DWORD dwFlags,LPCSTR lpValue,CONST NUMBERFMTA *lpFormat,LPSTR lpNumberStr,int cchNumber); - WINBASEAPI int WINAPI GetNumberFormatW(LCID Locale,DWORD dwFlags,LPCWSTR lpValue,CONST NUMBERFMTW *lpFormat,LPWSTR lpNumberStr,int cchNumber); - WINBASEAPI int WINAPI GetCurrencyFormatA(LCID Locale,DWORD dwFlags,LPCSTR lpValue,CONST CURRENCYFMTA *lpFormat,LPSTR lpCurrencyStr,int cchCurrency); - WINBASEAPI int WINAPI GetCurrencyFormatW(LCID Locale,DWORD dwFlags,LPCWSTR lpValue,CONST CURRENCYFMTW *lpFormat,LPWSTR lpCurrencyStr,int cchCurrency); - WINBASEAPI WINBOOL WINAPI EnumCalendarInfoA(CALINFO_ENUMPROCA lpCalInfoEnumProc,LCID Locale,CALID Calendar,CALTYPE CalType); - WINBASEAPI WINBOOL WINAPI EnumCalendarInfoW(CALINFO_ENUMPROCW lpCalInfoEnumProc,LCID Locale,CALID Calendar,CALTYPE CalType); - WINBASEAPI WINBOOL WINAPI EnumCalendarInfoExA(CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx,LCID Locale,CALID Calendar,CALTYPE CalType); - WINBASEAPI WINBOOL WINAPI EnumCalendarInfoExW(CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx,LCID Locale,CALID Calendar,CALTYPE CalType); - WINBASEAPI WINBOOL WINAPI EnumTimeFormatsA(TIMEFMT_ENUMPROCA lpTimeFmtEnumProc,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumTimeFormatsW(TIMEFMT_ENUMPROCW lpTimeFmtEnumProc,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA lpDateFmtEnumProc,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumDateFormatsW(DATEFMT_ENUMPROCW lpDateFmtEnumProc,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumDateFormatsExA(DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumDateFormatsExW(DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx,LCID Locale,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI IsValidLanguageGroup(LGRPID LanguageGroup,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI GetNLSVersion(NLS_FUNCTION Function,LCID Locale,LPNLSVERSIONINFO lpVersionInformation); - WINBASEAPI WINBOOL WINAPI IsNLSDefinedString(NLS_FUNCTION Function,DWORD dwFlags,LPNLSVERSIONINFO lpVersionInformation,LPCWSTR lpString,INT cchStr); - WINBASEAPI WINBOOL WINAPI IsValidLocale(LCID Locale,DWORD dwFlags); - WINBASEAPI int WINAPI GetGeoInfoA(GEOID Location,GEOTYPE GeoType,LPSTR lpGeoData,int cchData,LANGID LangId); - WINBASEAPI int WINAPI GetGeoInfoW(GEOID Location,GEOTYPE GeoType,LPWSTR lpGeoData,int cchData,LANGID LangId); - WINBASEAPI WINBOOL WINAPI EnumSystemGeoID(GEOCLASS GeoClass,GEOID ParentGeoId,GEO_ENUMPROC lpGeoEnumProc); - WINBASEAPI GEOID WINAPI GetUserGeoID(GEOCLASS GeoClass); - WINBASEAPI WINBOOL WINAPI SetUserGeoID(GEOID GeoId); - WINBASEAPI LCID WINAPI ConvertDefaultLocale(LCID Locale); - WINBASEAPI LCID WINAPI GetThreadLocale(void); - WINBASEAPI WINBOOL WINAPI SetThreadLocale(LCID Locale); - WINBASEAPI LANGID WINAPI GetSystemDefaultUILanguage(void); - WINBASEAPI LANGID WINAPI GetUserDefaultUILanguage(void); - WINBASEAPI LANGID WINAPI GetSystemDefaultLangID(void); - WINBASEAPI LANGID WINAPI GetUserDefaultLangID(void); - WINBASEAPI LCID WINAPI GetSystemDefaultLCID(void); - WINBASEAPI LCID WINAPI GetUserDefaultLCID(void); - WINBASEAPI WINBOOL WINAPI GetStringTypeExA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType); - WINBASEAPI WINBOOL WINAPI GetStringTypeExW(LCID Locale,DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType); - WINBASEAPI WINBOOL WINAPI GetStringTypeA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType); - WINBASEAPI WINBOOL WINAPI GetStringTypeW(DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType); - WINBASEAPI int WINAPI FoldStringA(DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest); - WINBASEAPI int WINAPI FoldStringW(DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest); - WINBASEAPI WINBOOL WINAPI EnumSystemLanguageGroupsA(LANGUAGEGROUP_ENUMPROCA lpLanguageGroupEnumProc,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumSystemLanguageGroupsW(LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumLanguageGroupLocalesA(LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc,LGRPID LanguageGroup,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumLanguageGroupLocalesW(LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc,LGRPID LanguageGroup,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumUILanguagesA(UILANGUAGE_ENUMPROCA lpUILanguageEnumProc,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumUILanguagesW(UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,DWORD dwFlags,LONG_PTR lParam); - WINBASEAPI WINBOOL WINAPI EnumSystemLocalesA(LOCALE_ENUMPROCA lpLocaleEnumProc,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumSystemLocalesW(LOCALE_ENUMPROCW lpLocaleEnumProc,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumSystemCodePagesA(CODEPAGE_ENUMPROCA lpCodePageEnumProc,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI EnumSystemCodePagesW(CODEPAGE_ENUMPROCW lpCodePageEnumProc,DWORD dwFlags); - WINBASEAPI WINBOOL WINAPI IsNormalizedString(NORM_FORM NormForm,LPCWSTR lpString,int cwLength); - WINBASEAPI int WINAPI NormalizeString(NORM_FORM NormForm,LPCWSTR lpSrcString,int cwSrcLength,LPWSTR lpDstString,int cwDstLength); - WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,LPCWSTR lpUnicodeCharStr,int cchUnicodeChar,LPWSTR lpASCIICharStr,int cchASCIIChar); - WINBASEAPI int WINAPI IdnToNameprepUnicode(DWORD dwFlags,LPCWSTR lpUnicodeCharStr,int cchUnicodeChar,LPWSTR lpNameprepCharStr,int cchNameprepChar); - WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,LPCWSTR lpASCIICharStr,int cchASCIIChar,LPWSTR lpUnicodeCharStr,int cchUnicodeChar); - -#endif - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINNLS_ +#define _WINNLS_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NONLS + +#define MAX_LEADBYTES 12 +#define MAX_DEFAULTCHAR 2 + +#define MB_PRECOMPOSED 0x00000001 +#define MB_COMPOSITE 0x00000002 +#define MB_USEGLYPHCHARS 0x00000004 +#define MB_ERR_INVALID_CHARS 0x00000008 + +#define WC_COMPOSITECHECK 0x00000200 +#define WC_DISCARDNS 0x00000010 +#define WC_SEPCHARS 0x00000020 +#define WC_DEFAULTCHAR 0x00000040 +#define WC_NO_BEST_FIT_CHARS 0x00000400 + +#define CT_CTYPE1 0x00000001 +#define CT_CTYPE2 0x00000002 +#define CT_CTYPE3 0x00000004 + +#define C1_UPPER 0x0001 +#define C1_LOWER 0x0002 +#define C1_DIGIT 0x0004 +#define C1_SPACE 0x0008 +#define C1_PUNCT 0x0010 +#define C1_CNTRL 0x0020 +#define C1_BLANK 0x0040 +#define C1_XDIGIT 0x0080 +#define C1_ALPHA 0x0100 +#define C1_DEFINED 0x0200 + +#define C2_LEFTTORIGHT 0x0001 +#define C2_RIGHTTOLEFT 0x0002 + +#define C2_EUROPENUMBER 0x0003 +#define C2_EUROPESEPARATOR 0x0004 +#define C2_EUROPETERMINATOR 0x0005 +#define C2_ARABICNUMBER 0x0006 +#define C2_COMMONSEPARATOR 0x0007 + +#define C2_BLOCKSEPARATOR 0x0008 +#define C2_SEGMENTSEPARATOR 0x0009 +#define C2_WHITESPACE 0x000A +#define C2_OTHERNEUTRAL 0x000B + +#define C2_NOTAPPLICABLE 0x0000 + +#define C3_NONSPACING 0x0001 +#define C3_DIACRITIC 0x0002 +#define C3_VOWELMARK 0x0004 +#define C3_SYMBOL 0x0008 + +#define C3_KATAKANA 0x0010 +#define C3_HIRAGANA 0x0020 +#define C3_HALFWIDTH 0x0040 +#define C3_FULLWIDTH 0x0080 +#define C3_IDEOGRAPH 0x0100 +#define C3_KASHIDA 0x0200 +#define C3_LEXICAL 0x0400 + +#define C3_ALPHA 0x8000 + +#define C3_NOTAPPLICABLE 0x0000 + +#define NORM_IGNORECASE 0x00000001 +#define NORM_IGNORENONSPACE 0x00000002 +#define NORM_IGNORESYMBOLS 0x00000004 + +#define NORM_IGNOREKANATYPE 0x00010000 +#define NORM_IGNOREWIDTH 0x00020000 + +#define MAP_FOLDCZONE 0x00000010 +#define MAP_PRECOMPOSED 0x00000020 +#define MAP_COMPOSITE 0x00000040 +#define MAP_FOLDDIGITS 0x00000080 +#define MAP_EXPAND_LIGATURES 0x00002000 + +#define LCMAP_LOWERCASE 0x00000100 +#define LCMAP_UPPERCASE 0x00000200 +#define LCMAP_SORTKEY 0x00000400 +#define LCMAP_BYTEREV 0x00000800 + +#define LCMAP_HIRAGANA 0x00100000 +#define LCMAP_KATAKANA 0x00200000 +#define LCMAP_HALFWIDTH 0x00400000 +#define LCMAP_FULLWIDTH 0x00800000 + +#define LCMAP_LINGUISTIC_CASING 0x01000000 + +#define LCMAP_SIMPLIFIED_CHINESE 0x02000000 +#define LCMAP_TRADITIONAL_CHINESE 0x04000000 + +#define LGRPID_INSTALLED 0x00000001 +#define LGRPID_SUPPORTED 0x00000002 + +#define LCID_INSTALLED 0x00000001 +#define LCID_SUPPORTED 0x00000002 +#define LCID_ALTERNATE_SORTS 0x00000004 + +#define CP_INSTALLED 0x00000001 +#define CP_SUPPORTED 0x00000002 + +#define SORT_STRINGSORT 0x00001000 + +#define CSTR_LESS_THAN 1 +#define CSTR_EQUAL 2 +#define CSTR_GREATER_THAN 3 + +#define CP_ACP 0 +#define CP_OEMCP 1 +#define CP_MACCP 2 +#define CP_THREAD_ACP 3 +#define CP_SYMBOL 42 + +#define CP_UTF7 65000 +#define CP_UTF8 65001 + +#define CTRY_DEFAULT 0 + +#define CTRY_ALBANIA 355 +#define CTRY_ALGERIA 213 +#define CTRY_ARGENTINA 54 +#define CTRY_ARMENIA 374 +#define CTRY_AUSTRALIA 61 +#define CTRY_AUSTRIA 43 +#define CTRY_AZERBAIJAN 994 +#define CTRY_BAHRAIN 973 +#define CTRY_BELARUS 375 +#define CTRY_BELGIUM 32 +#define CTRY_BELIZE 501 +#define CTRY_BOLIVIA 591 +#define CTRY_BRAZIL 55 +#define CTRY_BRUNEI_DARUSSALAM 673 +#define CTRY_BULGARIA 359 +#define CTRY_CANADA 2 +#define CTRY_CARIBBEAN 1 +#define CTRY_CHILE 56 +#define CTRY_COLOMBIA 57 +#define CTRY_COSTA_RICA 506 +#define CTRY_CROATIA 385 +#define CTRY_CZECH 420 +#define CTRY_DENMARK 45 +#define CTRY_DOMINICAN_REPUBLIC 1 +#define CTRY_ECUADOR 593 +#define CTRY_EGYPT 20 +#define CTRY_EL_SALVADOR 503 +#define CTRY_ESTONIA 372 +#define CTRY_FAEROE_ISLANDS 298 +#define CTRY_FINLAND 358 +#define CTRY_FRANCE 33 +#define CTRY_GEORGIA 995 +#define CTRY_GERMANY 49 +#define CTRY_GREECE 30 +#define CTRY_GUATEMALA 502 +#define CTRY_HONDURAS 504 +#define CTRY_HONG_KONG 852 +#define CTRY_HUNGARY 36 +#define CTRY_ICELAND 354 +#define CTRY_INDIA 91 +#define CTRY_INDONESIA 62 +#define CTRY_IRAN 981 +#define CTRY_IRAQ 964 +#define CTRY_IRELAND 353 +#define CTRY_ISRAEL 972 +#define CTRY_ITALY 39 +#define CTRY_JAMAICA 1 +#define CTRY_JAPAN 81 +#define CTRY_JORDAN 962 +#define CTRY_KAZAKSTAN 7 +#define CTRY_KENYA 254 +#define CTRY_KUWAIT 965 +#define CTRY_KYRGYZSTAN 996 +#define CTRY_LATVIA 371 +#define CTRY_LEBANON 961 +#define CTRY_LIBYA 218 +#define CTRY_LIECHTENSTEIN 41 +#define CTRY_LITHUANIA 370 +#define CTRY_LUXEMBOURG 352 +#define CTRY_MACAU 853 +#define CTRY_MACEDONIA 389 +#define CTRY_MALAYSIA 60 +#define CTRY_MALDIVES 960 +#define CTRY_MEXICO 52 +#define CTRY_MONACO 33 +#define CTRY_MONGOLIA 976 +#define CTRY_MOROCCO 212 +#define CTRY_NETHERLANDS 31 +#define CTRY_NEW_ZEALAND 64 +#define CTRY_NICARAGUA 505 +#define CTRY_NORWAY 47 +#define CTRY_OMAN 968 +#define CTRY_PAKISTAN 92 +#define CTRY_PANAMA 507 +#define CTRY_PARAGUAY 595 +#define CTRY_PERU 51 +#define CTRY_PHILIPPINES 63 +#define CTRY_POLAND 48 +#define CTRY_PORTUGAL 351 +#define CTRY_PRCHINA 86 +#define CTRY_PUERTO_RICO 1 +#define CTRY_QATAR 974 +#define CTRY_ROMANIA 40 +#define CTRY_RUSSIA 7 +#define CTRY_SAUDI_ARABIA 966 +#define CTRY_SERBIA 381 +#define CTRY_SINGAPORE 65 +#define CTRY_SLOVAK 421 +#define CTRY_SLOVENIA 386 +#define CTRY_SOUTH_AFRICA 27 +#define CTRY_SOUTH_KOREA 82 +#define CTRY_SPAIN 34 +#define CTRY_SWEDEN 46 +#define CTRY_SWITZERLAND 41 +#define CTRY_SYRIA 963 +#define CTRY_TAIWAN 886 +#define CTRY_TATARSTAN 7 +#define CTRY_THAILAND 66 +#define CTRY_TRINIDAD_Y_TOBAGO 1 +#define CTRY_TUNISIA 216 +#define CTRY_TURKEY 90 +#define CTRY_UAE 971 +#define CTRY_UKRAINE 380 +#define CTRY_UNITED_KINGDOM 44 +#define CTRY_UNITED_STATES 1 +#define CTRY_URUGUAY 598 +#define CTRY_UZBEKISTAN 7 +#define CTRY_VENEZUELA 58 +#define CTRY_VIET_NAM 84 +#define CTRY_YEMEN 967 +#define CTRY_ZIMBABWE 263 + +#define LOCALE_NOUSEROVERRIDE 0x80000000 +#define LOCALE_USE_CP_ACP 0x40000000 +#define LOCALE_RETURN_NUMBER 0x20000000 + +#define LOCALE_ILANGUAGE 0x00000001 +#define LOCALE_SLANGUAGE 0x00000002 +#define LOCALE_SENGLANGUAGE 0x00001001 +#define LOCALE_SABBREVLANGNAME 0x00000003 +#define LOCALE_SNATIVELANGNAME 0x00000004 + +#define LOCALE_ICOUNTRY 0x00000005 +#define LOCALE_SCOUNTRY 0x00000006 +#define LOCALE_SENGCOUNTRY 0x00001002 +#define LOCALE_SABBREVCTRYNAME 0x00000007 +#define LOCALE_SNATIVECTRYNAME 0x00000008 + +#define LOCALE_IDEFAULTLANGUAGE 0x00000009 +#define LOCALE_IDEFAULTCOUNTRY 0x0000000A +#define LOCALE_IDEFAULTCODEPAGE 0x0000000B +#define LOCALE_IDEFAULTANSICODEPAGE 0x00001004 +#define LOCALE_IDEFAULTMACCODEPAGE 0x00001011 + +#define LOCALE_SLIST 0x0000000C +#define LOCALE_IMEASURE 0x0000000D + +#define LOCALE_SDECIMAL 0x0000000E +#define LOCALE_STHOUSAND 0x0000000F +#define LOCALE_SGROUPING 0x00000010 +#define LOCALE_IDIGITS 0x00000011 +#define LOCALE_ILZERO 0x00000012 +#define LOCALE_INEGNUMBER 0x00001010 +#define LOCALE_SNATIVEDIGITS 0x00000013 + +#define LOCALE_SCURRENCY 0x00000014 +#define LOCALE_SINTLSYMBOL 0x00000015 +#define LOCALE_SMONDECIMALSEP 0x00000016 +#define LOCALE_SMONTHOUSANDSEP 0x00000017 +#define LOCALE_SMONGROUPING 0x00000018 +#define LOCALE_ICURRDIGITS 0x00000019 +#define LOCALE_IINTLCURRDIGITS 0x0000001A +#define LOCALE_ICURRENCY 0x0000001B +#define LOCALE_INEGCURR 0x0000001C + +#define LOCALE_SDATE 0x0000001D +#define LOCALE_STIME 0x0000001E +#define LOCALE_SSHORTDATE 0x0000001F +#define LOCALE_SLONGDATE 0x00000020 +#define LOCALE_STIMEFORMAT 0x00001003 +#define LOCALE_IDATE 0x00000021 +#define LOCALE_ILDATE 0x00000022 +#define LOCALE_ITIME 0x00000023 +#define LOCALE_ITIMEMARKPOSN 0x00001005 +#define LOCALE_ICENTURY 0x00000024 +#define LOCALE_ITLZERO 0x00000025 +#define LOCALE_IDAYLZERO 0x00000026 +#define LOCALE_IMONLZERO 0x00000027 +#define LOCALE_S1159 0x00000028 +#define LOCALE_S2359 0x00000029 + +#define LOCALE_ICALENDARTYPE 0x00001009 +#define LOCALE_IOPTIONALCALENDAR 0x0000100B +#define LOCALE_IFIRSTDAYOFWEEK 0x0000100C +#define LOCALE_IFIRSTWEEKOFYEAR 0x0000100D + +#define LOCALE_SDAYNAME1 0x0000002A +#define LOCALE_SDAYNAME2 0x0000002B +#define LOCALE_SDAYNAME3 0x0000002C +#define LOCALE_SDAYNAME4 0x0000002D +#define LOCALE_SDAYNAME5 0x0000002E +#define LOCALE_SDAYNAME6 0x0000002F +#define LOCALE_SDAYNAME7 0x00000030 +#define LOCALE_SABBREVDAYNAME1 0x00000031 +#define LOCALE_SABBREVDAYNAME2 0x00000032 +#define LOCALE_SABBREVDAYNAME3 0x00000033 +#define LOCALE_SABBREVDAYNAME4 0x00000034 +#define LOCALE_SABBREVDAYNAME5 0x00000035 +#define LOCALE_SABBREVDAYNAME6 0x00000036 +#define LOCALE_SABBREVDAYNAME7 0x00000037 +#define LOCALE_SMONTHNAME1 0x00000038 +#define LOCALE_SMONTHNAME2 0x00000039 +#define LOCALE_SMONTHNAME3 0x0000003A +#define LOCALE_SMONTHNAME4 0x0000003B +#define LOCALE_SMONTHNAME5 0x0000003C +#define LOCALE_SMONTHNAME6 0x0000003D +#define LOCALE_SMONTHNAME7 0x0000003E +#define LOCALE_SMONTHNAME8 0x0000003F +#define LOCALE_SMONTHNAME9 0x00000040 +#define LOCALE_SMONTHNAME10 0x00000041 +#define LOCALE_SMONTHNAME11 0x00000042 +#define LOCALE_SMONTHNAME12 0x00000043 +#define LOCALE_SMONTHNAME13 0x0000100E +#define LOCALE_SABBREVMONTHNAME1 0x00000044 +#define LOCALE_SABBREVMONTHNAME2 0x00000045 +#define LOCALE_SABBREVMONTHNAME3 0x00000046 +#define LOCALE_SABBREVMONTHNAME4 0x00000047 +#define LOCALE_SABBREVMONTHNAME5 0x00000048 +#define LOCALE_SABBREVMONTHNAME6 0x00000049 +#define LOCALE_SABBREVMONTHNAME7 0x0000004A +#define LOCALE_SABBREVMONTHNAME8 0x0000004B +#define LOCALE_SABBREVMONTHNAME9 0x0000004C +#define LOCALE_SABBREVMONTHNAME10 0x0000004D +#define LOCALE_SABBREVMONTHNAME11 0x0000004E +#define LOCALE_SABBREVMONTHNAME12 0x0000004F +#define LOCALE_SABBREVMONTHNAME13 0x0000100F + +#define LOCALE_SPOSITIVESIGN 0x00000050 +#define LOCALE_SNEGATIVESIGN 0x00000051 +#define LOCALE_IPOSSIGNPOSN 0x00000052 +#define LOCALE_INEGSIGNPOSN 0x00000053 +#define LOCALE_IPOSSYMPRECEDES 0x00000054 +#define LOCALE_IPOSSEPBYSPACE 0x00000055 +#define LOCALE_INEGSYMPRECEDES 0x00000056 +#define LOCALE_INEGSEPBYSPACE 0x00000057 +#define LOCALE_FONTSIGNATURE 0x00000058 +#define LOCALE_SISO639LANGNAME 0x00000059 +#define LOCALE_SISO3166CTRYNAME 0x0000005A + +#define LOCALE_IDEFAULTEBCDICCODEPAGE 0x00001012 +#define LOCALE_IPAPERSIZE 0x0000100A +#define LOCALE_SENGCURRNAME 0x00001007 +#define LOCALE_SNATIVECURRNAME 0x00001008 +#define LOCALE_SYEARMONTH 0x00001006 +#define LOCALE_SSORTNAME 0x00001013 +#define LOCALE_IDIGITSUBSTITUTION 0x00001014 + +#define TIME_NOMINUTESORSECONDS 0x00000001 +#define TIME_NOSECONDS 0x00000002 +#define TIME_NOTIMEMARKER 0x00000004 +#define TIME_FORCE24HOURFORMAT 0x00000008 + +#define DATE_SHORTDATE 0x00000001 +#define DATE_LONGDATE 0x00000002 +#define DATE_USE_ALT_CALENDAR 0x00000004 +#define DATE_YEARMONTH 0x00000008 +#define DATE_LTRREADING 0x00000010 +#define DATE_RTLREADING 0x00000020 + +#define CAL_NOUSEROVERRIDE LOCALE_NOUSEROVERRIDE +#define CAL_USE_CP_ACP LOCALE_USE_CP_ACP +#define CAL_RETURN_NUMBER LOCALE_RETURN_NUMBER + +#define CAL_ICALINTVALUE 0x00000001 +#define CAL_SCALNAME 0x00000002 +#define CAL_IYEAROFFSETRANGE 0x00000003 +#define CAL_SERASTRING 0x00000004 +#define CAL_SSHORTDATE 0x00000005 +#define CAL_SLONGDATE 0x00000006 +#define CAL_SDAYNAME1 0x00000007 +#define CAL_SDAYNAME2 0x00000008 +#define CAL_SDAYNAME3 0x00000009 +#define CAL_SDAYNAME4 0x0000000a +#define CAL_SDAYNAME5 0x0000000b +#define CAL_SDAYNAME6 0x0000000c +#define CAL_SDAYNAME7 0x0000000d +#define CAL_SABBREVDAYNAME1 0x0000000e +#define CAL_SABBREVDAYNAME2 0x0000000f +#define CAL_SABBREVDAYNAME3 0x00000010 +#define CAL_SABBREVDAYNAME4 0x00000011 +#define CAL_SABBREVDAYNAME5 0x00000012 +#define CAL_SABBREVDAYNAME6 0x00000013 +#define CAL_SABBREVDAYNAME7 0x00000014 +#define CAL_SMONTHNAME1 0x00000015 +#define CAL_SMONTHNAME2 0x00000016 +#define CAL_SMONTHNAME3 0x00000017 +#define CAL_SMONTHNAME4 0x00000018 +#define CAL_SMONTHNAME5 0x00000019 +#define CAL_SMONTHNAME6 0x0000001a +#define CAL_SMONTHNAME7 0x0000001b +#define CAL_SMONTHNAME8 0x0000001c +#define CAL_SMONTHNAME9 0x0000001d +#define CAL_SMONTHNAME10 0x0000001e +#define CAL_SMONTHNAME11 0x0000001f +#define CAL_SMONTHNAME12 0x00000020 +#define CAL_SMONTHNAME13 0x00000021 +#define CAL_SABBREVMONTHNAME1 0x00000022 +#define CAL_SABBREVMONTHNAME2 0x00000023 +#define CAL_SABBREVMONTHNAME3 0x00000024 +#define CAL_SABBREVMONTHNAME4 0x00000025 +#define CAL_SABBREVMONTHNAME5 0x00000026 +#define CAL_SABBREVMONTHNAME6 0x00000027 +#define CAL_SABBREVMONTHNAME7 0x00000028 +#define CAL_SABBREVMONTHNAME8 0x00000029 +#define CAL_SABBREVMONTHNAME9 0x0000002a +#define CAL_SABBREVMONTHNAME10 0x0000002b +#define CAL_SABBREVMONTHNAME11 0x0000002c +#define CAL_SABBREVMONTHNAME12 0x0000002d +#define CAL_SABBREVMONTHNAME13 0x0000002e +#define CAL_SYEARMONTH 0x0000002f +#define CAL_ITWODIGITYEARMAX 0x00000030 + +#define ENUM_ALL_CALENDARS 0xffffffff + +#define CAL_GREGORIAN 1 +#define CAL_GREGORIAN_US 2 +#define CAL_JAPAN 3 +#define CAL_TAIWAN 4 +#define CAL_KOREA 5 +#define CAL_HIJRI 6 +#define CAL_THAI 7 +#define CAL_HEBREW 8 +#define CAL_GREGORIAN_ME_FRENCH 9 +#define CAL_GREGORIAN_ARABIC 10 +#define CAL_GREGORIAN_XLIT_ENGLISH 11 +#define CAL_GREGORIAN_XLIT_FRENCH 12 + +#define LGRPID_WESTERN_EUROPE 0x0001 +#define LGRPID_CENTRAL_EUROPE 0x0002 +#define LGRPID_BALTIC 0x0003 +#define LGRPID_GREEK 0x0004 +#define LGRPID_CYRILLIC 0x0005 +#define LGRPID_TURKISH 0x0006 +#define LGRPID_JAPANESE 0x0007 +#define LGRPID_KOREAN 0x0008 +#define LGRPID_TRADITIONAL_CHINESE 0x0009 +#define LGRPID_SIMPLIFIED_CHINESE 0x000a +#define LGRPID_THAI 0x000b +#define LGRPID_HEBREW 0x000c +#define LGRPID_ARABIC 0x000d +#define LGRPID_VIETNAMESE 0x000e +#define LGRPID_INDIC 0x000f +#define LGRPID_GEORGIAN 0x0010 +#define LGRPID_ARMENIAN 0x0011 + + typedef DWORD LGRPID; + typedef DWORD LCTYPE; + typedef DWORD CALTYPE; + typedef DWORD CALID; + + typedef struct _cpinfo { + UINT MaxCharSize; + BYTE DefaultChar[MAX_DEFAULTCHAR]; + BYTE LeadByte[MAX_LEADBYTES]; + } CPINFO,*LPCPINFO; + + typedef struct _cpinfoexA { + UINT MaxCharSize; + BYTE DefaultChar[MAX_DEFAULTCHAR]; + BYTE LeadByte[MAX_LEADBYTES]; + WCHAR UnicodeDefaultChar; + UINT CodePage; + CHAR CodePageName[MAX_PATH]; + } CPINFOEXA,*LPCPINFOEXA; + + typedef struct _cpinfoexW { + UINT MaxCharSize; + BYTE DefaultChar[MAX_DEFAULTCHAR]; + BYTE LeadByte[MAX_LEADBYTES]; + WCHAR UnicodeDefaultChar; + UINT CodePage; + WCHAR CodePageName[MAX_PATH]; + } CPINFOEXW,*LPCPINFOEXW; + +#ifdef UNICODE + typedef CPINFOEXW CPINFOEX; + typedef LPCPINFOEXW LPCPINFOEX; +#else + typedef CPINFOEXA CPINFOEX; + typedef LPCPINFOEXA LPCPINFOEX; +#endif + + typedef struct _numberfmtA { + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPSTR lpDecimalSep; + LPSTR lpThousandSep; + UINT NegativeOrder; + } NUMBERFMTA,*LPNUMBERFMTA; + + typedef struct _numberfmtW { + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPWSTR lpDecimalSep; + LPWSTR lpThousandSep; + UINT NegativeOrder; + } NUMBERFMTW,*LPNUMBERFMTW; + +#ifdef UNICODE + typedef NUMBERFMTW NUMBERFMT; + typedef LPNUMBERFMTW LPNUMBERFMT; +#else + typedef NUMBERFMTA NUMBERFMT; + typedef LPNUMBERFMTA LPNUMBERFMT; +#endif + + typedef struct _currencyfmtA { + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPSTR lpDecimalSep; + LPSTR lpThousandSep; + UINT NegativeOrder; + UINT PositiveOrder; + LPSTR lpCurrencySymbol; + } CURRENCYFMTA,*LPCURRENCYFMTA; + + typedef struct _currencyfmtW { + UINT NumDigits; + UINT LeadingZero; + UINT Grouping; + LPWSTR lpDecimalSep; + LPWSTR lpThousandSep; + UINT NegativeOrder; + UINT PositiveOrder; + LPWSTR lpCurrencySymbol; + } CURRENCYFMTW,*LPCURRENCYFMTW; + +#ifdef UNICODE + typedef CURRENCYFMTW CURRENCYFMT; + typedef LPCURRENCYFMTW LPCURRENCYFMT; +#else + typedef CURRENCYFMTA CURRENCYFMT; + typedef LPCURRENCYFMTA LPCURRENCYFMT; +#endif + + enum SYSNLS_FUNCTION { + COMPARE_STRING = 0x0001 + }; + + typedef DWORD NLS_FUNCTION; + + typedef struct _nlsversioninfo{ + DWORD dwNLSVersionInfoSize; + DWORD dwNLSVersion; + DWORD dwDefinedVersion; + } NLSVERSIONINFO,*LPNLSVERSIONINFO; + + typedef LONG GEOID; + typedef DWORD GEOTYPE; + typedef DWORD GEOCLASS; + +#define GEOID_NOT_AVAILABLE -1 + + enum SYSGEOTYPE { + GEO_NATION = 0x0001,GEO_LATITUDE = 0x0002,GEO_LONGITUDE = 0x0003,GEO_ISO2 = 0x0004,GEO_ISO3 = 0x0005,GEO_RFC1766 = 0x0006,GEO_LCID = 0x0007, + GEO_FRIENDLYNAME= 0x0008,GEO_OFFICIALNAME= 0x0009,GEO_TIMEZONES = 0x000A,GEO_OFFICIALLANGUAGES = 0x000B + }; + + enum SYSGEOCLASS { + GEOCLASS_NATION = 16,GEOCLASS_REGION = 14 + }; + + typedef enum _NORM_FORM { + NormalizationOther = 0, + NormalizationC = 0x1, + NormalizationD = 0x2, + NormalizationKC = 0x5, + NormalizationKD = 0x6 +} NORM_FORM; + + typedef WINBOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCA)(LGRPID,LPSTR,LPSTR,DWORD,LONG_PTR); + typedef WINBOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCA)(LGRPID,LCID,LPSTR,LONG_PTR); + typedef WINBOOL (CALLBACK *UILANGUAGE_ENUMPROCA)(LPSTR,LONG_PTR); + typedef WINBOOL (CALLBACK *LOCALE_ENUMPROCA)(LPSTR); + typedef WINBOOL (CALLBACK *CODEPAGE_ENUMPROCA)(LPSTR); + typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCA)(LPSTR); + typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCEXA)(LPSTR,CALID); + typedef WINBOOL (CALLBACK *TIMEFMT_ENUMPROCA)(LPSTR); + typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCA)(LPSTR); + typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCEXA)(LPSTR,CALID); + typedef WINBOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCW)(LGRPID,LPWSTR,LPWSTR,DWORD,LONG_PTR); + typedef WINBOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCW)(LGRPID,LCID,LPWSTR,LONG_PTR); + typedef WINBOOL (CALLBACK *UILANGUAGE_ENUMPROCW)(LPWSTR,LONG_PTR); + typedef WINBOOL (CALLBACK *LOCALE_ENUMPROCW)(LPWSTR); + typedef WINBOOL (CALLBACK *CODEPAGE_ENUMPROCW)(LPWSTR); + typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCW)(LPWSTR); + typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCEXW)(LPWSTR,CALID); + typedef WINBOOL (CALLBACK *TIMEFMT_ENUMPROCW)(LPWSTR); + typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCW)(LPWSTR); + typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCEXW)(LPWSTR,CALID); + typedef WINBOOL (CALLBACK *GEO_ENUMPROC)(GEOID); + +#ifdef UNICODE +#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCW +#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCW +#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCW +#define LOCALE_ENUMPROC LOCALE_ENUMPROCW +#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCW +#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCW +#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXW +#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCW +#define CALINFO_ENUMPROC CALINFO_ENUMPROCW +#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXW +#else +#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCA +#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCA +#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCA +#define LOCALE_ENUMPROC LOCALE_ENUMPROCA +#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCA +#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCA +#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXA +#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCA +#define CALINFO_ENUMPROC CALINFO_ENUMPROCA +#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXA +#endif + +#ifdef UNICODE +#define GetCPInfoEx GetCPInfoExW +#define CompareString CompareStringW +#define LCMapString LCMapStringW +#define GetLocaleInfo GetLocaleInfoW +#define SetLocaleInfo SetLocaleInfoW +#define GetCalendarInfo GetCalendarInfoW +#define SetCalendarInfo SetCalendarInfoW +#define GetTimeFormat GetTimeFormatW +#define GetDateFormat GetDateFormatW +#define GetNumberFormat GetNumberFormatW +#define GetCurrencyFormat GetCurrencyFormatW +#define EnumCalendarInfo EnumCalendarInfoW +#define EnumCalendarInfoEx EnumCalendarInfoExW +#define EnumTimeFormats EnumTimeFormatsW +#define EnumDateFormats EnumDateFormatsW +#define EnumDateFormatsEx EnumDateFormatsExW +#define GetGeoInfo GetGeoInfoW +#define GetStringTypeEx GetStringTypeExW +#define FoldString FoldStringW +#define EnumSystemLanguageGroups EnumSystemLanguageGroupsW +#define EnumLanguageGroupLocales EnumLanguageGroupLocalesW +#define EnumUILanguages EnumUILanguagesW +#define EnumSystemLocales EnumSystemLocalesW +#define EnumSystemCodePages EnumSystemCodePagesW +#else +#define GetCPInfoEx GetCPInfoExA +#define CompareString CompareStringA +#define LCMapString LCMapStringA +#define GetLocaleInfo GetLocaleInfoA +#define SetLocaleInfo SetLocaleInfoA +#define GetCalendarInfo GetCalendarInfoA +#define SetCalendarInfo SetCalendarInfoA +#define GetTimeFormat GetTimeFormatA +#define GetDateFormat GetDateFormatA +#define GetNumberFormat GetNumberFormatA +#define GetCurrencyFormat GetCurrencyFormatA +#define EnumCalendarInfo EnumCalendarInfoA +#define EnumCalendarInfoEx EnumCalendarInfoExA +#define EnumTimeFormats EnumTimeFormatsA +#define EnumDateFormats EnumDateFormatsA +#define EnumDateFormatsEx EnumDateFormatsExA +#define GetGeoInfo GetGeoInfoA +#define GetStringTypeEx GetStringTypeExA +#define FoldString FoldStringA +#define EnumSystemLanguageGroups EnumSystemLanguageGroupsA +#define EnumLanguageGroupLocales EnumLanguageGroupLocalesA +#define EnumUILanguages EnumUILanguagesA +#define EnumSystemLocales EnumSystemLocalesA +#define EnumSystemCodePages EnumSystemCodePagesA +#endif + + WINBASEAPI WINBOOL WINAPI IsValidCodePage(UINT CodePage); + WINBASEAPI UINT WINAPI GetACP(void); + WINBASEAPI UINT WINAPI GetOEMCP(void); + WINBASEAPI WINBOOL WINAPI GetCPInfo(UINT CodePage,LPCPINFO lpCPInfo); + WINBASEAPI WINBOOL WINAPI GetCPInfoExA(UINT CodePage,DWORD dwFlags,LPCPINFOEXA lpCPInfoEx); + WINBASEAPI WINBOOL WINAPI GetCPInfoExW(UINT CodePage,DWORD dwFlags,LPCPINFOEXW lpCPInfoEx); + WINBASEAPI WINBOOL WINAPI IsDBCSLeadByte(BYTE TestChar); + WINBASEAPI WINBOOL WINAPI IsDBCSLeadByteEx(UINT CodePage,BYTE TestChar); + WINBASEAPI int WINAPI MultiByteToWideChar(UINT CodePage,DWORD dwFlags,LPCSTR lpMultiByteStr,int cbMultiByte,LPWSTR lpWideCharStr,int cchWideChar); + WINBASEAPI int WINAPI WideCharToMultiByte(UINT CodePage,DWORD dwFlags,LPCWSTR lpWideCharStr,int cchWideChar,LPSTR lpMultiByteStr,int cbMultiByte,LPCSTR lpDefaultChar,LPBOOL lpUsedDefaultChar); + WINBASEAPI int WINAPI CompareStringA(LCID Locale,DWORD dwCmpFlags,LPCSTR lpString1,int cchCount1,LPCSTR lpString2,int cchCount2); + WINBASEAPI int WINAPI CompareStringW(LCID Locale,DWORD dwCmpFlags,LPCWSTR lpString1,int cchCount1,LPCWSTR lpString2,int cchCount2); + WINBASEAPI int WINAPI LCMapStringA(LCID Locale,DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest); + WINBASEAPI int WINAPI LCMapStringW(LCID Locale,DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest); + WINBASEAPI int WINAPI GetLocaleInfoA(LCID Locale,LCTYPE LCType,LPSTR lpLCData,int cchData); + WINBASEAPI int WINAPI GetLocaleInfoW(LCID Locale,LCTYPE LCType,LPWSTR lpLCData,int cchData); + WINBASEAPI WINBOOL WINAPI SetLocaleInfoA(LCID Locale,LCTYPE LCType,LPCSTR lpLCData); + WINBASEAPI WINBOOL WINAPI SetLocaleInfoW(LCID Locale,LCTYPE LCType,LPCWSTR lpLCData); + WINBASEAPI int WINAPI GetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPSTR lpCalData,int cchData,LPDWORD lpValue); + WINBASEAPI int WINAPI GetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPWSTR lpCalData,int cchData,LPDWORD lpValue); + WINBASEAPI WINBOOL WINAPI SetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPCSTR lpCalData); + WINBASEAPI WINBOOL WINAPI SetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPCWSTR lpCalData); + WINBASEAPI int WINAPI GetTimeFormatA(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpTime,LPCSTR lpFormat,LPSTR lpTimeStr,int cchTime); + WINBASEAPI int WINAPI GetTimeFormatW(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpTime,LPCWSTR lpFormat,LPWSTR lpTimeStr,int cchTime); + WINBASEAPI int WINAPI GetDateFormatA(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpDate,LPCSTR lpFormat,LPSTR lpDateStr,int cchDate); + WINBASEAPI int WINAPI GetDateFormatW(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpDate,LPCWSTR lpFormat,LPWSTR lpDateStr,int cchDate); + WINBASEAPI int WINAPI GetNumberFormatA(LCID Locale,DWORD dwFlags,LPCSTR lpValue,CONST NUMBERFMTA *lpFormat,LPSTR lpNumberStr,int cchNumber); + WINBASEAPI int WINAPI GetNumberFormatW(LCID Locale,DWORD dwFlags,LPCWSTR lpValue,CONST NUMBERFMTW *lpFormat,LPWSTR lpNumberStr,int cchNumber); + WINBASEAPI int WINAPI GetCurrencyFormatA(LCID Locale,DWORD dwFlags,LPCSTR lpValue,CONST CURRENCYFMTA *lpFormat,LPSTR lpCurrencyStr,int cchCurrency); + WINBASEAPI int WINAPI GetCurrencyFormatW(LCID Locale,DWORD dwFlags,LPCWSTR lpValue,CONST CURRENCYFMTW *lpFormat,LPWSTR lpCurrencyStr,int cchCurrency); + WINBASEAPI WINBOOL WINAPI EnumCalendarInfoA(CALINFO_ENUMPROCA lpCalInfoEnumProc,LCID Locale,CALID Calendar,CALTYPE CalType); + WINBASEAPI WINBOOL WINAPI EnumCalendarInfoW(CALINFO_ENUMPROCW lpCalInfoEnumProc,LCID Locale,CALID Calendar,CALTYPE CalType); + WINBASEAPI WINBOOL WINAPI EnumCalendarInfoExA(CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx,LCID Locale,CALID Calendar,CALTYPE CalType); + WINBASEAPI WINBOOL WINAPI EnumCalendarInfoExW(CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx,LCID Locale,CALID Calendar,CALTYPE CalType); + WINBASEAPI WINBOOL WINAPI EnumTimeFormatsA(TIMEFMT_ENUMPROCA lpTimeFmtEnumProc,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumTimeFormatsW(TIMEFMT_ENUMPROCW lpTimeFmtEnumProc,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA lpDateFmtEnumProc,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumDateFormatsW(DATEFMT_ENUMPROCW lpDateFmtEnumProc,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumDateFormatsExA(DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumDateFormatsExW(DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx,LCID Locale,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI IsValidLanguageGroup(LGRPID LanguageGroup,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI GetNLSVersion(NLS_FUNCTION Function,LCID Locale,LPNLSVERSIONINFO lpVersionInformation); + WINBASEAPI WINBOOL WINAPI IsNLSDefinedString(NLS_FUNCTION Function,DWORD dwFlags,LPNLSVERSIONINFO lpVersionInformation,LPCWSTR lpString,INT cchStr); + WINBASEAPI WINBOOL WINAPI IsValidLocale(LCID Locale,DWORD dwFlags); + WINBASEAPI int WINAPI GetGeoInfoA(GEOID Location,GEOTYPE GeoType,LPSTR lpGeoData,int cchData,LANGID LangId); + WINBASEAPI int WINAPI GetGeoInfoW(GEOID Location,GEOTYPE GeoType,LPWSTR lpGeoData,int cchData,LANGID LangId); + WINBASEAPI WINBOOL WINAPI EnumSystemGeoID(GEOCLASS GeoClass,GEOID ParentGeoId,GEO_ENUMPROC lpGeoEnumProc); + WINBASEAPI GEOID WINAPI GetUserGeoID(GEOCLASS GeoClass); + WINBASEAPI WINBOOL WINAPI SetUserGeoID(GEOID GeoId); + WINBASEAPI LCID WINAPI ConvertDefaultLocale(LCID Locale); + WINBASEAPI LCID WINAPI GetThreadLocale(void); + WINBASEAPI WINBOOL WINAPI SetThreadLocale(LCID Locale); + WINBASEAPI LANGID WINAPI GetSystemDefaultUILanguage(void); + WINBASEAPI LANGID WINAPI GetUserDefaultUILanguage(void); + WINBASEAPI LANGID WINAPI GetSystemDefaultLangID(void); + WINBASEAPI LANGID WINAPI GetUserDefaultLangID(void); + WINBASEAPI LCID WINAPI GetSystemDefaultLCID(void); + WINBASEAPI LCID WINAPI GetUserDefaultLCID(void); + WINBASEAPI WINBOOL WINAPI GetStringTypeExA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType); + WINBASEAPI WINBOOL WINAPI GetStringTypeExW(LCID Locale,DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType); + WINBASEAPI WINBOOL WINAPI GetStringTypeA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType); + WINBASEAPI WINBOOL WINAPI GetStringTypeW(DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType); + WINBASEAPI int WINAPI FoldStringA(DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest); + WINBASEAPI int WINAPI FoldStringW(DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest); + WINBASEAPI WINBOOL WINAPI EnumSystemLanguageGroupsA(LANGUAGEGROUP_ENUMPROCA lpLanguageGroupEnumProc,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumSystemLanguageGroupsW(LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumLanguageGroupLocalesA(LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc,LGRPID LanguageGroup,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumLanguageGroupLocalesW(LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc,LGRPID LanguageGroup,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumUILanguagesA(UILANGUAGE_ENUMPROCA lpUILanguageEnumProc,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumUILanguagesW(UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,DWORD dwFlags,LONG_PTR lParam); + WINBASEAPI WINBOOL WINAPI EnumSystemLocalesA(LOCALE_ENUMPROCA lpLocaleEnumProc,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumSystemLocalesW(LOCALE_ENUMPROCW lpLocaleEnumProc,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumSystemCodePagesA(CODEPAGE_ENUMPROCA lpCodePageEnumProc,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI EnumSystemCodePagesW(CODEPAGE_ENUMPROCW lpCodePageEnumProc,DWORD dwFlags); + WINBASEAPI WINBOOL WINAPI IsNormalizedString(NORM_FORM NormForm,LPCWSTR lpString,int cwLength); + WINBASEAPI int WINAPI NormalizeString(NORM_FORM NormForm,LPCWSTR lpSrcString,int cwSrcLength,LPWSTR lpDstString,int cwDstLength); + WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,LPCWSTR lpUnicodeCharStr,int cchUnicodeChar,LPWSTR lpASCIICharStr,int cchASCIIChar); + WINBASEAPI int WINAPI IdnToNameprepUnicode(DWORD dwFlags,LPCWSTR lpUnicodeCharStr,int cchUnicodeChar,LPWSTR lpNameprepCharStr,int cchNameprepChar); + WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,LPCWSTR lpASCIICharStr,int cchASCIIChar,LPWSTR lpUnicodeCharStr,int cchUnicodeChar); + +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/winnt.h b/tcc/include/winapi/winnt.h index 41a9aa2c..8c334047 100644 --- a/tcc/include/winapi/winnt.h +++ b/tcc/include/winapi/winnt.h @@ -1,5835 +1,5835 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINNT_ -#define _WINNT_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#define ANYSIZE_ARRAY 1 - -//gr #include - -#define RESTRICTED_POINTER - -#ifndef __CRT_UNALIGNED -#define __CRT_UNALIGNED -#endif - -#if defined(__ia64__) || defined(__x86_64) -#define UNALIGNED __CRT_UNALIGNED -#ifdef _WIN64 -#define UNALIGNED64 __CRT_UNALIGNED -#else -#define UNALIGNED64 -#endif -#else -#define UNALIGNED -#define UNALIGNED64 -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) -#define I_X86_ -#endif - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) -#define _AMD64_ -#endif - -#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) -#if !defined(_IA64_) -#define _IA64_ -#endif -#endif - - -#ifdef _WIN64 -#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) -#define MEMORY_ALLOCATION_ALIGNMENT 16 -#else -#define MAX_NATURAL_ALIGNMENT sizeof(DWORD) -#define MEMORY_ALLOCATION_ALIGNMENT 8 -#endif - -#ifdef __cplusplus -#define TYPE_ALIGNMENT(t) __alignof__ (t) -#else -#define TYPE_ALIGNMENT(t) FIELD_OFFSET(struct { char x; t test; },test) -#endif - -#ifdef _WIN64 -#ifdef _AMD64_ -#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) -#elif defined(_IA64_) -#define PROBE_ALIGNMENT(_s) (TYPE_ALIGNMENT(_s) > TYPE_ALIGNMENT(DWORD) ? TYPE_ALIGNMENT(_s) : TYPE_ALIGNMENT(DWORD)) -#else -#error No Target Architecture -#endif -#define PROBE_ALIGNMENT32(_s) TYPE_ALIGNMENT(DWORD) -#else -#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) -#endif - -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] - -#include - -#if defined(_X86_) || defined(__ia64__) || defined(__x86_64) -#define DECLSPEC_IMPORT __declspec(dllimport) -#else -#define DECLSPEC_IMPORT -#endif - -#ifndef DECLSPEC_NORETURN -#define DECLSPEC_NORETURN __declspec(noreturn) -#endif - -#ifndef DECLSPEC_ALIGN -#define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) -#endif - -#ifndef SYSTEM_CACHE_ALIGNMENT_SIZE -#if defined(_AMD64_) || defined(I_X86_) -#define SYSTEM_CACHE_ALIGNMENT_SIZE 64 -#else -#define SYSTEM_CACHE_ALIGNMENT_SIZE 128 -#endif -#endif - -#ifndef DECLSPEC_CACHEALIGN -#define DECLSPEC_CACHEALIGN DECLSPEC_ALIGN(SYSTEM_CACHE_ALIGNMENT_SIZE) -#endif - -#ifndef DECLSPEC_UUID -#define DECLSPEC_UUID(x) -#endif - -#ifndef DECLSPEC_NOVTABLE -#define DECLSPEC_NOVTABLE -#endif - -#ifndef DECLSPEC_SELECTANY -#define DECLSPEC_SELECTANY __declspec(selectany) -#endif - -#ifndef NOP_FUNCTION -#define NOP_FUNCTION (void)0 -#endif - -#ifndef DECLSPEC_NOINLINE -#define DECLSPEC_NOINLINE -#endif - -#ifndef FORCEINLINE -#define FORCEINLINE static __inline__ -#endif - -#ifndef DECLSPEC_DEPRECATED -#define DECLSPEC_DEPRECATED __declspec(deprecated) -#define DEPRECATE_SUPPORTED -#endif - -#define DECLSPEC_DEPRECATED_DDK -#define PRAGMA_DEPRECATED_DDK 0 - - typedef void *PVOID; - typedef void *PVOID64; - -#define NTAPI __stdcall -#define NTSYSAPI DECLSPEC_IMPORT -#define NTSYSCALLAPI DECLSPEC_IMPORT - -#ifndef VOID -#define VOID void - typedef char CHAR; - typedef short SHORT; - typedef long LONG; -#endif - - typedef wchar_t WCHAR; - typedef WCHAR *PWCHAR,*LPWCH,*PWCH; - typedef CONST WCHAR *LPCWCH,*PCWCH; - typedef WCHAR *NWPSTR,*LPWSTR,*PWSTR; - typedef PWSTR *PZPWSTR; - typedef CONST PWSTR *PCZPWSTR; - typedef WCHAR UNALIGNED *LPUWSTR,*PUWSTR; - typedef CONST WCHAR *LPCWSTR,*PCWSTR; - typedef PCWSTR *PZPCWSTR; - typedef CONST WCHAR UNALIGNED *LPCUWSTR,*PCUWSTR; - typedef CHAR *PCHAR,*LPCH,*PCH; - typedef CONST CHAR *LPCCH,*PCCH; - typedef CHAR *NPSTR,*LPSTR,*PSTR; - typedef PSTR *PZPSTR; - typedef CONST PSTR *PCZPSTR; - typedef CONST CHAR *LPCSTR,*PCSTR; - typedef PCSTR *PZPCSTR; - -#ifdef UNICODE -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED - typedef WCHAR TCHAR,*PTCHAR; - typedef WCHAR TBYTE ,*PTBYTE; -#endif - - typedef LPWSTR LPTCH,PTCH; - typedef LPWSTR PTSTR,LPTSTR; - typedef LPCWSTR PCTSTR,LPCTSTR; - typedef LPUWSTR PUTSTR,LPUTSTR; - typedef LPCUWSTR PCUTSTR,LPCUTSTR; - typedef LPWSTR LP; -#define __TEXT(quote) L##quote -#else -#ifndef _TCHAR_DEFINED -#define _TCHAR_DEFINED - typedef char TCHAR,*PTCHAR; - typedef unsigned char TBYTE ,*PTBYTE; -#endif - - typedef LPSTR LPTCH,PTCH; - typedef LPSTR PTSTR,LPTSTR,PUTSTR,LPUTSTR; - typedef LPCSTR PCTSTR,LPCTSTR,PCUTSTR,LPCUTSTR; -#define __TEXT(quote) quote -#endif - -#define TEXT(quote) __TEXT(quote) - - typedef SHORT *PSHORT; - typedef LONG *PLONG; - - typedef void *HANDLE; -#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name - typedef HANDLE *PHANDLE; - - typedef BYTE FCHAR; - typedef WORD FSHORT; - typedef DWORD FLONG; - -#ifndef _HRESULT_DEFINED -#define _HRESULT_DEFINED - typedef LONG HRESULT; -#endif - -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C extern -#endif - -#define STDMETHODCALLTYPE WINAPI -#define STDMETHODVCALLTYPE __cdecl -#define STDAPICALLTYPE WINAPI -#define STDAPIVCALLTYPE __cdecl -#define STDAPI EXTERN_C HRESULT WINAPI -#define STDAPI_(type) EXTERN_C type WINAPI -#define STDMETHODIMP HRESULT WINAPI -#define STDMETHODIMP_(type) type WINAPI -#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE -#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE -#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE -#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE - - typedef char CCHAR; -#ifndef _LCID_DEFINED -#define _LCID_DEFINED -typedef DWORD LCID; -#endif - typedef PDWORD PLCID; -#ifndef _LANGID_DEFINED -#define _LANGID_DEFINED - typedef WORD LANGID; -#endif -#define APPLICATION_ERROR_MASK 0x20000000 -#define ERROR_SEVERITY_SUCCESS 0x00000000 -#define ERROR_SEVERITY_INFORMATIONAL 0x40000000 -#define ERROR_SEVERITY_WARNING 0x80000000 -#define ERROR_SEVERITY_ERROR 0xC0000000 - -#ifdef __ia64__ - __declspec(align(16)) -#endif - typedef struct _FLOAT128 { - __int64 LowPart; - __int64 HighPart; - } FLOAT128; - - typedef FLOAT128 *PFLOAT128; - -#define _ULONGLONG_ -#if((!(defined(_X86_) && !defined(__x86_64)) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64))) - typedef __int64 LONGLONG; - typedef unsigned __int64 ULONGLONG; - -#define MAXLONGLONG (0x7fffffffffffffff) -#else - - typedef double LONGLONG; - typedef double ULONGLONG; -#endif - - typedef LONGLONG *PLONGLONG; - typedef ULONGLONG *PULONGLONG; - - typedef LONGLONG USN; - - typedef union _LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - }; - struct { - DWORD LowPart; - LONG HighPart; - } u; - LONGLONG QuadPart; - } LARGE_INTEGER; - - typedef LARGE_INTEGER *PLARGE_INTEGER; - - typedef union _ULARGE_INTEGER { - struct { - DWORD LowPart; - DWORD HighPart; - }; - struct { - DWORD LowPart; - DWORD HighPart; - } u; - ULONGLONG QuadPart; - } ULARGE_INTEGER; - - typedef ULARGE_INTEGER *PULARGE_INTEGER; - - typedef struct _LUID { - DWORD LowPart; - LONG HighPart; - } LUID,*PLUID; - -#define _DWORDLONG_ - typedef ULONGLONG DWORDLONG; - typedef DWORDLONG *PDWORDLONG; - -#ifdef RC_INVOKED -#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) -#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) -#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) -#elif (defined(_X86_) && !defined(__x86_64)) -#define Int32x32To64(a,b) (LONGLONG)((LONGLONG)(LONG)(a) *(LONG)(b)) -#define UInt32x32To64(a,b) (ULONGLONG)((ULONGLONG)(DWORD)(a) *(DWORD)(b)) -#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(b)) -#elif defined(__ia64__) || defined(__x86_64) -#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) -#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) -#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) -#else -#error Must define a target architecture. -#endif - -#define Int64ShraMod32(a,b) ((LONGLONG)(a) >> (b)) -#define Int64ShllMod32(a,b) ((ULONGLONG)(a) << (b)) - -#ifdef __cplusplus - extern "C" { -#endif - -#ifdef __x86_64 - -#define RotateLeft8 _rotl8 -#define RotateLeft16 _rotl16 -#define RotateRight8 _rotr8 -#define RotateRight16 _rotr16 - - unsigned char __cdecl _rotl8(unsigned char Value,unsigned char Shift); - unsigned short __cdecl _rotl16(unsigned short Value,unsigned char Shift); - unsigned char __cdecl _rotr8(unsigned char Value,unsigned char Shift); - unsigned short __cdecl _rotr16(unsigned short Value,unsigned char Shift); -#endif - -#define RotateLeft32 _rotl -#define RotateLeft64 _rotl64 -#define RotateRight32 _rotr -#define RotateRight64 _rotr64 - - unsigned int __cdecl _rotl(unsigned int Value,int Shift); - unsigned __int64 __cdecl _rotl64(unsigned __int64 Value,int Shift); - unsigned int __cdecl _rotr(unsigned int Value,int Shift); - unsigned __int64 __cdecl _rotr64(unsigned __int64 Value,int Shift); -#ifdef __cplusplus - } -#endif - -#define ANSI_NULL ((CHAR)0) -#define UNICODE_NULL ((WCHAR)0) -#define UNICODE_STRING_MAX_BYTES ((WORD) 65534) -#define UNICODE_STRING_MAX_CHARS (32767) - -#ifndef _BOOLEAN_ -#define _BOOLEAN_ - typedef BYTE BOOLEAN; -#endif - typedef BOOLEAN *PBOOLEAN; - - typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; - } LIST_ENTRY,*PLIST_ENTRY,*RESTRICTED_POINTER PRLIST_ENTRY; - - typedef struct _SINGLE_LIST_ENTRY { - struct _SINGLE_LIST_ENTRY *Next; - } SINGLE_LIST_ENTRY,*PSINGLE_LIST_ENTRY; - - typedef struct LIST_ENTRY32 { - DWORD Flink; - DWORD Blink; - } LIST_ENTRY32; - typedef LIST_ENTRY32 *PLIST_ENTRY32; - - typedef struct LIST_ENTRY64 { - ULONGLONG Flink; - ULONGLONG Blink; - } LIST_ENTRY64; - typedef LIST_ENTRY64 *PLIST_ENTRY64; - -#include - -#ifndef __OBJECTID_DEFINED -#define __OBJECTID_DEFINED - typedef struct _OBJECTID { - GUID Lineage; - DWORD Uniquifier; - } OBJECTID; -#endif - -#define MINCHAR 0x80 -#define MAXCHAR 0x7f -#define MINSHORT 0x8000 -#define MAXSHORT 0x7fff -#define MINLONG 0x80000000 -#define MAXLONG 0x7fffffff -#define MAXBYTE 0xff -#define MAXWORD 0xffff -#define MAXDWORD 0xffffffff - -#define FIELD_OFFSET(type,field) ((LONG)(LONG_PTR)&(((type *)0)->field)) -#define RTL_FIELD_SIZE(type,field) (sizeof(((type *)0)->field)) -#define RTL_SIZEOF_THROUGH_FIELD(type,field) (FIELD_OFFSET(type,field) + RTL_FIELD_SIZE(type,field)) -#define RTL_CONTAINS_FIELD(Struct,Size,Field) ((((PCHAR)(&(Struct)->Field)) + sizeof((Struct)->Field)) <= (((PCHAR)(Struct))+(Size))) -#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) -#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A) - -#ifdef ENABLE_RTL_NUMBER_OF_V2 -#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V2(A) -#else -#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V1(A) -#endif - -#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A) -#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) - -#define RTL_FIELD_TYPE(type,field) (((type*)0)->field) -#define RTL_NUMBER_OF_FIELD(type,field) (RTL_NUMBER_OF(RTL_FIELD_TYPE(type,field))) -#define RTL_PADDING_BETWEEN_FIELDS(T,F1,F2) ((FIELD_OFFSET(T,F2) > FIELD_OFFSET(T,F1)) ? (FIELD_OFFSET(T,F2) - FIELD_OFFSET(T,F1) - RTL_FIELD_SIZE(T,F1)) : (FIELD_OFFSET(T,F1) - FIELD_OFFSET(T,F2) - RTL_FIELD_SIZE(T,F2))) - -#ifdef __cplusplus -#define RTL_CONST_CAST(type) const_cast -#else -#define RTL_CONST_CAST(type) (type) -#endif - -#define RTL_BITS_OF(sizeOfArg) (sizeof(sizeOfArg) *8) -#define RTL_BITS_OF_FIELD(type,field) (RTL_BITS_OF(RTL_FIELD_TYPE(type,field))) -#define CONTAINING_RECORD(address,type,field) ((type *)((PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field))) - -#define VER_SERVER_NT 0x80000000 -#define VER_WORKSTATION_NT 0x40000000 -#define VER_SUITE_SMALLBUSINESS 0x00000001 -#define VER_SUITE_ENTERPRISE 0x00000002 -#define VER_SUITE_BACKOFFICE 0x00000004 -#define VER_SUITE_COMMUNICATIONS 0x00000008 -#define VER_SUITE_TERMINAL 0x00000010 -#define VER_SUITE_SMALLBUSINESS_RESTRICTED 0x00000020 -#define VER_SUITE_EMBEDDEDNT 0x00000040 -#define VER_SUITE_DATACENTER 0x00000080 -#define VER_SUITE_SINGLEUSERTS 0x00000100 -#define VER_SUITE_PERSONAL 0x00000200 -#define VER_SUITE_BLADE 0x00000400 -#define VER_SUITE_EMBEDDED_RESTRICTED 0x00000800 -#define VER_SUITE_SECURITY_APPLIANCE 0x00001000 -#define VER_SUITE_STORAGE_SERVER 0x00002000 -#define VER_SUITE_COMPUTE_SERVER 0x00004000 - -#define PRODUCT_UNDEFINED 0x0 - -#define PRODUCT_ULTIMATE 0x1 -#define PRODUCT_HOME_BASIC 0x2 -#define PRODUCT_HOME_PREMIUM 0x3 -#define PRODUCT_ENTERPRISE 0x4 -#define PRODUCT_HOME_BASIC_N 0x5 -#define PRODUCT_BUSINESS 0x6 -#define PRODUCT_STANDARD_SERVER 0x7 -#define PRODUCT_DATACENTER_SERVER 0x8 -#define PRODUCT_SMALLBUSINESS_SERVER 0x9 -#define PRODUCT_ENTERPRISE_SERVER 0xa -#define PRODUCT_STARTER 0xb -#define PRODUCT_DATACENTER_SERVER_CORE 0xc -#define PRODUCT_STANDARD_SERVER_CORE 0xd -#define PRODUCT_ENTERPRISE_SERVER_CORE 0xe -#define PRODUCT_ENTERPRISE_SERVER_IA64 0xf -#define PRODUCT_BUSINESS_N 0x10 -#define PRODUCT_WEB_SERVER 0x11 -#define PRODUCT_CLUSTER_SERVER 0x12 -#define PRODUCT_HOME_SERVER 0x13 -#define PRODUCT_STORAGE_EXPRESS_SERVER 0x14 -#define PRODUCT_STORAGE_STANDARD_SERVER 0x15 -#define PRODUCT_STORAGE_WORKGROUP_SERVER 0x16 -#define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x17 -#define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x18 -#define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x19 - -#define PRODUCT_UNLICENSED 0xabcdabcd - -#define LANG_NEUTRAL 0x00 -#define LANG_INVARIANT 0x7f - -#define LANG_AFRIKAANS 0x36 -#define LANG_ALBANIAN 0x1c -#define LANG_ALSATIAN 0x84 -#define LANG_AMHARIC 0x5e -#define LANG_ARABIC 0x01 -#define LANG_ARMENIAN 0x2b -#define LANG_ASSAMESE 0x4d -#define LANG_AZERI 0x2c -#define LANG_BASHKIR 0x6d -#define LANG_BASQUE 0x2d -#define LANG_BELARUSIAN 0x23 -#define LANG_BENGALI 0x45 -#define LANG_BRETON 0x7e -#define LANG_BOSNIAN 0x1a -#define LANG_BOSNIAN_NEUTRAL 0x781a -#define LANG_BULGARIAN 0x02 -#define LANG_CATALAN 0x03 -#define LANG_CHINESE 0x04 -#define LANG_CHINESE_SIMPLIFIED 0x04 -#define LANG_CHINESE_TRADITIONAL 0x7c04 -#define LANG_CORSICAN 0x83 -#define LANG_CROATIAN 0x1a -#define LANG_CZECH 0x05 -#define LANG_DANISH 0x06 -#define LANG_DARI 0x8c -#define LANG_DIVEHI 0x65 -#define LANG_DUTCH 0x13 -#define LANG_ENGLISH 0x09 -#define LANG_ESTONIAN 0x25 -#define LANG_FAEROESE 0x38 -#define LANG_FARSI 0x29 -#define LANG_FILIPINO 0x64 -#define LANG_FINNISH 0x0b -#define LANG_FRENCH 0x0c -#define LANG_FRISIAN 0x62 -#define LANG_GALICIAN 0x56 -#define LANG_GEORGIAN 0x37 -#define LANG_GERMAN 0x07 -#define LANG_GREEK 0x08 -#define LANG_GREENLANDIC 0x6f -#define LANG_GUJARATI 0x47 -#define LANG_HAUSA 0x68 -#define LANG_HEBREW 0x0d -#define LANG_HINDI 0x39 -#define LANG_HUNGARIAN 0x0e -#define LANG_ICELANDIC 0x0f -#define LANG_IGBO 0x70 -#define LANG_INDONESIAN 0x21 -#define LANG_INUKTITUT 0x5d -#define LANG_IRISH 0x3c -#define LANG_ITALIAN 0x10 -#define LANG_JAPANESE 0x11 -#define LANG_KANNADA 0x4b -#define LANG_KASHMIRI 0x60 -#define LANG_KAZAK 0x3f -#define LANG_KHMER 0x53 -#define LANG_KICHE 0x86 -#define LANG_KINYARWANDA 0x87 -#define LANG_KONKANI 0x57 -#define LANG_KOREAN 0x12 -#define LANG_KYRGYZ 0x40 -#define LANG_LAO 0x54 -#define LANG_LATVIAN 0x26 -#define LANG_LITHUANIAN 0x27 -#define LANG_LOWER_SORBIAN 0x2e -#define LANG_LUXEMBOURGISH 0x6e -#define LANG_MACEDONIAN 0x2f -#define LANG_MALAY 0x3e -#define LANG_MALAYALAM 0x4c -#define LANG_MALTESE 0x3a -#define LANG_MANIPURI 0x58 -#define LANG_MAORI 0x81 -#define LANG_MAPUDUNGUN 0x7a -#define LANG_MARATHI 0x4e -#define LANG_MOHAWK 0x7c -#define LANG_MONGOLIAN 0x50 -#define LANG_NEPALI 0x61 -#define LANG_NORWEGIAN 0x14 -#define LANG_OCCITAN 0x82 -#define LANG_ORIYA 0x48 -#define LANG_PASHTO 0x63 -#define LANG_PERSIAN 0x29 -#define LANG_POLISH 0x15 -#define LANG_PORTUGUESE 0x16 -#define LANG_PUNJABI 0x46 -#define LANG_QUECHUA 0x6b -#define LANG_ROMANIAN 0x18 -#define LANG_RUSSIAN 0x19 -#define LANG_SAMI 0x3b -#define LANG_ROMANSH 0x17 -#define LANG_SANSKRIT 0x4f -#define LANG_SERBIAN 0x1a -#define LANG_SERBIAN_NEUTRAL 0x7c1a -#define LANG_SINDHI 0x59 -#define LANG_SINHALESE 0x5b -#define LANG_SLOVAK 0x1b -#define LANG_SLOVENIAN 0x24 -#define LANG_SOTHO 0x6c -#define LANG_SPANISH 0x0a -#define LANG_SWAHILI 0x41 -#define LANG_SWEDISH 0x1d -#define LANG_SYRIAC 0x5a -#define LANG_TAJIK 0x28 -#define LANG_TAMAZIGHT 0x5f -#define LANG_TAMIL 0x49 -#define LANG_TATAR 0x44 -#define LANG_TELUGU 0x4a -#define LANG_THAI 0x1e -#define LANG_TIBETAN 0x51 -#define LANG_TIGRIGNA 0x73 -#define LANG_TSWANA 0x32 -#define LANG_TURKISH 0x1f -#define LANG_TURKMEN 0x42 -#define LANG_UIGHUR 0x80 -#define LANG_UKRAINIAN 0x22 -#define LANG_UPPER_SORBIAN 0x2e -#define LANG_URDU 0x20 -#define LANG_UZBEK 0x43 -#define LANG_VIETNAMESE 0x2a -#define LANG_WELSH 0x52 -#define LANG_WOLOF 0x88 -#define LANG_XHOSA 0x34 -#define LANG_YAKUT 0x85 -#define LANG_YI 0x78 -#define LANG_YORUBA 0x6a -#define LANG_ZULU 0x35 - -#define SUBLANG_NEUTRAL 0x0 -#define SUBLANG_DEFAULT 0x1 -#define SUBLANG_SYS_DEFAULT 0x2 -#define SUBLANG_CUSTOM_DEFAULT 0x3 -#define SUBLANG_CUSTOM_UNSPECIFIED 0x4 -#define SUBLANG_UI_CUSTOM_DEFAULT 0x5 - -#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 -#define SUBLANG_ARABIC_IRAQ 0x02 -#define SUBLANG_ARABIC_EGYPT 0x03 -#define SUBLANG_ARABIC_LIBYA 0x04 -#define SUBLANG_ARABIC_ALGERIA 0x05 -#define SUBLANG_ARABIC_MOROCCO 0x06 -#define SUBLANG_ARABIC_TUNISIA 0x07 -#define SUBLANG_ARABIC_OMAN 0x08 -#define SUBLANG_ARABIC_YEMEN 0x09 -#define SUBLANG_ARABIC_SYRIA 0x0a -#define SUBLANG_ARABIC_JORDAN 0x0b -#define SUBLANG_ARABIC_LEBANON 0x0c -#define SUBLANG_ARABIC_KUWAIT 0x0d -#define SUBLANG_ARABIC_UAE 0x0e -#define SUBLANG_ARABIC_BAHRAIN 0x0f -#define SUBLANG_ARABIC_QATAR 0x10 -#define SUBLANG_AZERI_LATIN 0x01 -#define SUBLANG_AZERI_CYRILLIC 0x02 -#define SUBLANG_CHINESE_TRADITIONAL 0x01 -#define SUBLANG_CHINESE_SIMPLIFIED 0x02 -#define SUBLANG_CHINESE_HONGKONG 0x03 -#define SUBLANG_CHINESE_SINGAPORE 0x04 -#define SUBLANG_CHINESE_MACAU 0x05 -#define SUBLANG_DUTCH 0x01 -#define SUBLANG_DUTCH_BELGIAN 0x02 -#define SUBLANG_ENGLISH_US 0x01 -#define SUBLANG_ENGLISH_UK 0x02 -#define SUBLANG_ENGLISH_AUS 0x03 -#define SUBLANG_ENGLISH_CAN 0x04 -#define SUBLANG_ENGLISH_NZ 0x05 -#define SUBLANG_ENGLISH_EIRE 0x06 -#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 -#define SUBLANG_ENGLISH_JAMAICA 0x08 -#define SUBLANG_ENGLISH_CARIBBEAN 0x09 -#define SUBLANG_ENGLISH_BELIZE 0x0a -#define SUBLANG_ENGLISH_TRINIDAD 0x0b -#define SUBLANG_ENGLISH_ZIMBABWE 0x0c -#define SUBLANG_ENGLISH_PHILIPPINES 0x0d -#define SUBLANG_FRENCH 0x01 -#define SUBLANG_FRENCH_BELGIAN 0x02 -#define SUBLANG_FRENCH_CANADIAN 0x03 -#define SUBLANG_FRENCH_SWISS 0x04 -#define SUBLANG_FRENCH_LUXEMBOURG 0x05 -#define SUBLANG_FRENCH_MONACO 0x06 -#define SUBLANG_GERMAN 0x01 -#define SUBLANG_GERMAN_SWISS 0x02 -#define SUBLANG_GERMAN_AUSTRIAN 0x03 -#define SUBLANG_GERMAN_LUXEMBOURG 0x04 -#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 -#define SUBLANG_ITALIAN 0x01 -#define SUBLANG_ITALIAN_SWISS 0x02 -#define SUBLANG_KASHMIRI_SASIA 0x02 -#define SUBLANG_KASHMIRI_INDIA 0x02 -#define SUBLANG_KOREAN 0x01 -#define SUBLANG_LITHUANIAN 0x01 -#define SUBLANG_MALAY_MALAYSIA 0x01 -#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 -#define SUBLANG_NEPALI_INDIA 0x02 -#define SUBLANG_NORWEGIAN_BOKMAL 0x01 -#define SUBLANG_NORWEGIAN_NYNORSK 0x02 -#define SUBLANG_PORTUGUESE 0x02 -#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01 -#define SUBLANG_SERBIAN_LATIN 0x02 -#define SUBLANG_SERBIAN_CYRILLIC 0x03 -#define SUBLANG_SPANISH 0x01 -#define SUBLANG_SPANISH_MEXICAN 0x02 -#define SUBLANG_SPANISH_MODERN 0x03 -#define SUBLANG_SPANISH_GUATEMALA 0x04 -#define SUBLANG_SPANISH_COSTA_RICA 0x05 -#define SUBLANG_SPANISH_PANAMA 0x06 -#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 -#define SUBLANG_SPANISH_VENEZUELA 0x08 -#define SUBLANG_SPANISH_COLOMBIA 0x09 -#define SUBLANG_SPANISH_PERU 0x0a -#define SUBLANG_SPANISH_ARGENTINA 0x0b -#define SUBLANG_SPANISH_ECUADOR 0x0c -#define SUBLANG_SPANISH_CHILE 0x0d -#define SUBLANG_SPANISH_URUGUAY 0x0e -#define SUBLANG_SPANISH_PARAGUAY 0x0f -#define SUBLANG_SPANISH_BOLIVIA 0x10 -#define SUBLANG_SPANISH_EL_SALVADOR 0x11 -#define SUBLANG_SPANISH_HONDURAS 0x12 -#define SUBLANG_SPANISH_NICARAGUA 0x13 -#define SUBLANG_SPANISH_PUERTO_RICO 0x14 -#define SUBLANG_SWEDISH 0x01 -#define SUBLANG_SWEDISH_FINLAND 0x02 -#define SUBLANG_URDU_PAKISTAN 0x01 -#define SUBLANG_URDU_INDIA 0x02 -#define SUBLANG_UZBEK_LATIN 0x01 -#define SUBLANG_UZBEK_CYRILLIC 0x02 - -#define SORT_DEFAULT 0x0 -#define SORT_INVARIANT_MATH 0x1 - -#define SORT_JAPANESE_XJIS 0x0 -#define SORT_JAPANESE_UNICODE 0x1 -#define SORT_JAPANESE_RADICALSTROKE 0x4 - -#define SORT_CHINESE_BIG5 0x0 -#define SORT_CHINESE_PRCP 0x0 -#define SORT_CHINESE_UNICODE 0x1 -#define SORT_CHINESE_PRC 0x2 -#define SORT_CHINESE_BOPOMOFO 0x3 - -#define SORT_KOREAN_KSC 0x0 -#define SORT_KOREAN_UNICODE 0x1 - -#define SORT_GERMAN_PHONE_BOOK 0x1 - -#define SORT_HUNGARIAN_DEFAULT 0x0 -#define SORT_HUNGARIAN_TECHNICAL 0x1 - -#define SORT_GEORGIAN_TRADITIONAL 0x0 -#define SORT_GEORGIAN_MODERN 0x1 - -#define MAKELANGID(p,s) ((((WORD)(s)) << 10) | (WORD)(p)) -#define PRIMARYLANGID(lgid) ((WORD)(lgid) & 0x3ff) -#define SUBLANGID(lgid) ((WORD)(lgid) >> 10) - -#define NLS_VALID_LOCALE_MASK 0x000fffff - -#define MAKELCID(lgid,srtid) ((DWORD)((((DWORD)((WORD)(srtid))) << 16) | ((DWORD)((WORD)(lgid))))) -#define MAKESORTLCID(lgid,srtid,ver) ((DWORD)((MAKELCID(lgid,srtid)) | (((DWORD)((WORD)(ver))) << 20))) -#define LANGIDFROMLCID(lcid) ((WORD)(lcid)) -#define SORTIDFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 16) & 0xf)) -#define SORTVERSIONFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 20) & 0xf)) - -#define LOCALE_NAME_MAX_LENGTH 85 -#define LANG_SYSTEM_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT)) -#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)) - -#define LOCALE_SYSTEM_DEFAULT (MAKELCID(LANG_SYSTEM_DEFAULT,SORT_DEFAULT)) -#define LOCALE_USER_DEFAULT (MAKELCID(LANG_USER_DEFAULT,SORT_DEFAULT)) - -#define LOCALE_NEUTRAL (MAKELCID(MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),SORT_DEFAULT)) - -#define LOCALE_CUSTOM_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), SORT_DEFAULT)) -#define LOCALE_CUSTOM_UNSPECIFIED (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED), SORT_DEFAULT)) -#define LOCALE_CUSTOM_UI_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT), SORT_DEFAULT)) - -#define LOCALE_INVARIANT (MAKELCID(MAKELANGID(LANG_INVARIANT,SUBLANG_NEUTRAL),SORT_DEFAULT)) - -#define UNREFERENCED_PARAMETER(P) (P) -#define DBG_UNREFERENCED_PARAMETER(P) (P) -#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (V) - -#define DEFAULT_UNREACHABLE - -#ifndef WIN32_NO_STATUS -#define STATUS_WAIT_0 ((DWORD)0x00000000L) -#define STATUS_ABANDONED_WAIT_0 ((DWORD)0x00000080L) -#define STATUS_USER_APC ((DWORD)0x000000C0L) -#define STATUS_TIMEOUT ((DWORD)0x00000102L) -#define STATUS_PENDING ((DWORD)0x00000103L) -#define DBG_EXCEPTION_HANDLED ((DWORD)0x00010001L) -#define DBG_CONTINUE ((DWORD)0x00010002L) -#define STATUS_SEGMENT_NOTIFICATION ((DWORD)0x40000005L) -#define DBG_TERMINATE_THREAD ((DWORD)0x40010003L) -#define DBG_TERMINATE_PROCESS ((DWORD)0x40010004L) -#define DBG_CONTROL_C ((DWORD)0x40010005L) -#define DBG_CONTROL_BREAK ((DWORD)0x40010008L) -#define DBG_COMMAND_EXCEPTION ((DWORD)0x40010009L) -#define STATUS_GUARD_PAGE_VIOLATION ((DWORD)0x80000001L) -#define STATUS_DATATYPE_MISALIGNMENT ((DWORD)0x80000002L) -#define STATUS_BREAKPOINT ((DWORD)0x80000003L) -#define STATUS_SINGLE_STEP ((DWORD)0x80000004L) -#define DBG_EXCEPTION_NOT_HANDLED ((DWORD)0x80010001L) -#define STATUS_ACCESS_VIOLATION ((DWORD)0xC0000005L) -#define STATUS_IN_PAGE_ERROR ((DWORD)0xC0000006L) -#define STATUS_INVALID_HANDLE ((DWORD)0xC0000008L) -#define STATUS_NO_MEMORY ((DWORD)0xC0000017L) -#define STATUS_ILLEGAL_INSTRUCTION ((DWORD)0xC000001DL) -#define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD)0xC0000025L) -#define STATUS_INVALID_DISPOSITION ((DWORD)0xC0000026L) -#define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD)0xC000008CL) -#define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD)0xC000008DL) -#define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD)0xC000008EL) -#define STATUS_FLOAT_INEXACT_RESULT ((DWORD)0xC000008FL) -#define STATUS_FLOAT_INVALID_OPERATION ((DWORD)0xC0000090L) -#define STATUS_FLOAT_OVERFLOW ((DWORD)0xC0000091L) -#define STATUS_FLOAT_STACK_CHECK ((DWORD)0xC0000092L) -#define STATUS_FLOAT_UNDERFLOW ((DWORD)0xC0000093L) -#define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD)0xC0000094L) -#define STATUS_INTEGER_OVERFLOW ((DWORD)0xC0000095L) -#define STATUS_PRIVILEGED_INSTRUCTION ((DWORD)0xC0000096L) -#define STATUS_STACK_OVERFLOW ((DWORD)0xC00000FDL) -#define STATUS_CONTROL_C_EXIT ((DWORD)0xC000013AL) -#define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD)0xC00002B4L) -#define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD)0xC00002B5L) -#define STATUS_REG_NAT_CONSUMPTION ((DWORD)0xC00002C9L) -#define STATUS_SXS_EARLY_DEACTIVATION ((DWORD)0xC015000FL) -#define STATUS_SXS_INVALID_DEACTIVATION ((DWORD)0xC0150010L) -#endif - -#define MAXIMUM_WAIT_OBJECTS 64 -#define MAXIMUM_SUSPEND_COUNT MAXCHAR - - typedef ULONG_PTR KSPIN_LOCK; - typedef KSPIN_LOCK *PKSPIN_LOCK; - -#ifdef _AMD64_ - -#if defined(__x86_64) && !defined(RC_INVOKED) - -#ifdef __cplusplus - extern "C" { -#endif - -#define BitTest _bittest -#define BitTestAndComplement _bittestandcomplement -#define BitTestAndSet _bittestandset -#define BitTestAndReset _bittestandreset -#define InterlockedBitTestAndSet _interlockedbittestandset -#define InterlockedBitTestAndReset _interlockedbittestandreset -#define BitTest64 _bittest64 -#define BitTestAndComplement64 _bittestandcomplement64 -#define BitTestAndSet64 _bittestandset64 -#define BitTestAndReset64 _bittestandreset64 -#define InterlockedBitTestAndSet64 _interlockedbittestandset64 -#define InterlockedBitTestAndReset64 _interlockedbittestandreset64 - - __CRT_INLINE BOOLEAN _bittest(LONG const *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandcomplement(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandreset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandreset(LONG *Base,LONG Offset) { - int old = 0; - __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittest64(LONG64 const *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandcomplement64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btcq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btsq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _bittestandreset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("btrq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("lock ; btsq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } - __CRT_INLINE BOOLEAN _interlockedbittestandreset64(LONG64 *Base,LONG64 Offset) { - int old = 0; - __asm__ __volatile__("lock ; btrq %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long long *) Base)) - :"Ir" (Offset)); - return (BOOLEAN) (old!=0); - } -#define BitScanForward _BitScanForward -#define BitScanReverse _BitScanReverse -#define BitScanForward64 _BitScanForward64 -#define BitScanReverse64 _BitScanReverse64 - - __CRT_INLINE BOOLEAN _BitScanForward(DWORD *Index,DWORD Mask) { - __asm__ __volatile__("bsfl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); - return Mask!=0; - } - __CRT_INLINE BOOLEAN _BitScanReverse(DWORD *Index,DWORD Mask) { - __asm__ __volatile__("bsrl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); - return Mask!=0; - } - __CRT_INLINE BOOLEAN _BitScanForward64(DWORD *Index,DWORD64 Mask) { - __asm__ __volatile__("bsfq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); - return Mask!=0; - } - __CRT_INLINE BOOLEAN _BitScanReverse64(DWORD *Index,DWORD64 Mask) { - __asm__ __volatile__("bsrq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); - return Mask!=0; - } - -#define InterlockedIncrement16 _InterlockedIncrement16 -#define InterlockedDecrement16 _InterlockedDecrement16 -#define InterlockedCompareExchange16 _InterlockedCompareExchange16 - -#define InterlockedAnd _InterlockedAnd -#define InterlockedOr _InterlockedOr -#define InterlockedXor _InterlockedXor -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedIncrementAcquire InterlockedIncrement -#define InterlockedIncrementRelease InterlockedIncrement -#define InterlockedDecrement _InterlockedDecrement -#define InterlockedDecrementAcquire InterlockedDecrement -#define InterlockedDecrementRelease InterlockedDecrement -#define InterlockedAdd _InterlockedAdd -#define InterlockedExchange _InterlockedExchange -#define InterlockedExchangeAdd _InterlockedExchangeAdd -#define InterlockedCompareExchange _InterlockedCompareExchange -#define InterlockedCompareExchangeAcquire InterlockedCompareExchange -#define InterlockedCompareExchangeRelease InterlockedCompareExchange - -#define InterlockedAnd64 _InterlockedAnd64 -#define InterlockedAndAffinity InterlockedAnd64 -#define InterlockedOr64 _InterlockedOr64 -#define InterlockedOrAffinity InterlockedOr64 -#define InterlockedXor64 _InterlockedXor64 -#define InterlockedIncrement64 _InterlockedIncrement64 -#define InterlockedDecrement64 _InterlockedDecrement64 -#define InterlockedAdd64 _InterlockedAdd64 -#define InterlockedExchange64 _InterlockedExchange64 -#define InterlockedExchangeAcquire64 InterlockedExchange64 -#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 -#define InterlockedCompareExchange64 _InterlockedCompareExchange64 -#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 -#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 - -#define InterlockedExchangePointer _InterlockedExchangePointer -#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer -#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer - -#define InterlockedExchangeAddSizeT(a,b) InterlockedExchangeAdd64((LONG64 *)a,b) -#define InterlockedIncrementSizeT(a) InterlockedIncrement64((LONG64 *)a) -#define InterlockedDecrementSizeT(a) InterlockedDecrement64((LONG64 *)a) - - __CRT_INLINE SHORT InterlockedIncrement16(SHORT volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; addw $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE SHORT InterlockedDecrement16(SHORT volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; subw $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE SHORT InterlockedCompareExchange16(SHORT volatile *Destination,SHORT ExChange,SHORT Comperand) { - SHORT prev; - __asm__ __volatile__("lock ; cmpxchgw %w1,%2" - :"=a"(prev) - :"q"(ExChange), "m"(*Destination), "0"(Comperand) - : "memory"); - return prev; - } - __CRT_INLINE LONG InterlockedAnd(LONG volatile *Destination,LONG Value) { - __asm__ __volatile__("lock ; andl %0,%1" - : :"r"(Value),"m"(*Destination) - : "memory"); - return *Destination; - } - __CRT_INLINE LONG InterlockedOr(LONG volatile *Destination,LONG Value) { - __asm__ __volatile__("lock ; orl %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG InterlockedXor(LONG volatile *Destination,LONG Value) { - __asm__ __volatile__("lock ; xorl %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - // $$$$ - __CRT_INLINE LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value) { - __asm__ __volatile__("lock ; andq %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value) { - __asm__ __volatile__("lock ; orq %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value) { - __asm__ __volatile__("lock ; xorq %0,%1" - : : "r"(Value),"m"(*Destination) : "memory"); - return *Destination; - } - __CRT_INLINE LONG InterlockedIncrement(LONG volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; addl $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG InterlockedDecrement(LONG volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; subl $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG InterlockedExchange(LONG volatile *Target,LONG Value) { - __asm__ __volatile("lock ; xchgl %0,%1" - : "=r"(Value) - : "m"(*Target),"0"(Value) - : "memory"); - return Value; - } - LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); - -#ifndef _X86AMD64_ - __CRT_INLINE LONG InterlockedAdd(LONG volatile *Addend,LONG Value) { return InterlockedExchangeAdd(Addend,Value) + Value; } -#endif - __CRT_INLINE LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand) { - LONG prev; - __asm__ __volatile__("lock ; cmpxchgl %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); - return prev; - } - __CRT_INLINE LONG64 InterlockedIncrement64(LONG64 volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; addq $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG64 InterlockedDecrement64(LONG64 volatile *Addend) { - unsigned char c; - unsigned char s; - __asm__ __volatile__( - "lock ; subq $1,%0; sete %1 ; sets %2" - :"=m" (*Addend), "=qm" (c), "=qm" (s) - :"m" (*Addend) : "memory"); - return (c != 0 ? 0 : (s != 0 ? -1 : 1)); - } - __CRT_INLINE LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value) { - __asm__ __volatile("lock ; xchgq %0,%1" - : "=r"(Value) - : "m"(*Target),"0"(Value) - : "memory"); - return Value; - } - LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); - -#ifndef _X86AMD64_ - __CRT_INLINE LONG64 InterlockedAdd64(LONG64 volatile *Addend,LONG64 Value) { return InterlockedExchangeAdd64(Addend,Value) + Value; } -#endif - - __CRT_INLINE LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand) { - LONG64 prev; - __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); - return prev; - } - __CRT_INLINE PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { - PVOID prev; - __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); - return prev; - } - __CRT_INLINE PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value) { - __asm__ __volatile("lock ; xchgq %0,%1" - : "=r"(Value) - : "m"(*Target),"0"(Value) - : "memory"); - return Value; - } - -#define CacheLineFlush(Address) _mm_clflush(Address) - - VOID _ReadWriteBarrier(VOID); - -#define FastFence __faststorefence -#define LoadFence _mm_lfence -#define MemoryFence _mm_mfence -#define StoreFence _mm_sfence - - VOID __faststorefence(VOID); - VOID _m_prefetchw(volatile CONST VOID *Source); - -//!__TINYC__: #include - -#define YieldProcessor _mm_pause -#define MemoryBarrier __faststorefence -#define PreFetchCacheLine(l,a) _mm_prefetch((CHAR CONST *) a,l) -#define PrefetchForWrite(p) _m_prefetchw(p) -#define ReadForWriteAccess(p) (_m_prefetchw(p),*(p)) - -#define PF_TEMPORAL_LEVEL_1 _MM_HINT_T0 -#define PF_TEMPORAL_LEVEL_2 _MM_HINT_T1 -#define PF_TEMPORAL_LEVEL_3 _MM_HINT_T2 -#define PF_NON_TEMPORAL_LEVEL_ALL _MM_HINT_NTA - -#define ReadMxCsr _mm_getcsr -#define WriteMxCsr _mm_setcsr - - VOID __int2c(VOID); - -#define DbgRaiseAssertionFailure() __int2c() -#define GetCallersEflags() __getcallerseflags() - - unsigned __int32 __getcallerseflags(VOID); - -#define GetSegmentLimit __segmentlimit - - DWORD __segmentlimit(DWORD Selector); - -#define ReadTimeStampCounter() __rdtsc() - - DWORD64 __rdtsc(VOID); - VOID __movsb(PBYTE Destination,BYTE const *Source,SIZE_T Count); - VOID __movsw(PWORD Destination,WORD const *Source,SIZE_T Count); - VOID __movsd(PDWORD Destination,DWORD const *Source,SIZE_T Count); - VOID __movsq(PDWORD64 Destination,DWORD64 const *Source,SIZE_T Count); - VOID __stosb(PBYTE Destination,BYTE Value,SIZE_T Count); - VOID __stosw(PWORD Destination,WORD Value,SIZE_T Count); - VOID __stosd(PDWORD Destination,DWORD Value,SIZE_T Count); - VOID __stosq(PDWORD64 Destination,DWORD64 Value,SIZE_T Count); - -#define MultiplyHigh __mulh -#define UnsignedMultiplyHigh __umulh - - LONGLONG MultiplyHigh(LONGLONG Multiplier,LONGLONG Multiplicand); - ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); - -#define ShiftLeft128 __shiftleft128 -#define ShiftRight128 __shiftright128 - - DWORD64 ShiftLeft128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); - DWORD64 ShiftRight128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); - -#define Multiply128 _mul128 - - LONG64 Multiply128(LONG64 Multiplier,LONG64 Multiplicand,LONG64 *HighProduct); - -#define UnsignedMultiply128 _umul128 - - DWORD64 UnsignedMultiply128(DWORD64 Multiplier,DWORD64 Multiplicand,DWORD64 *HighProduct); - - __CRT_INLINE LONG64 MultiplyExtract128(LONG64 Multiplier,LONG64 Multiplicand,BYTE Shift) { - LONG64 extractedProduct; - LONG64 highProduct; - LONG64 lowProduct; - lowProduct = Multiply128(Multiplier,Multiplicand,&highProduct); - extractedProduct = (LONG64)ShiftRight128((LONG64)lowProduct,(LONG64)highProduct,Shift); - return extractedProduct; - } - - __CRT_INLINE DWORD64 UnsignedMultiplyExtract128(DWORD64 Multiplier,DWORD64 Multiplicand,BYTE Shift) { - DWORD64 extractedProduct; - DWORD64 highProduct; - DWORD64 lowProduct; - lowProduct = UnsignedMultiply128(Multiplier,Multiplicand,&highProduct); - extractedProduct = ShiftRight128(lowProduct,highProduct,Shift); - return extractedProduct; - } - - __CRT_INLINE BYTE __readgsbyte(DWORD Offset) { - BYTE ret; - __asm__ volatile ("movb %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return ret; - } - __CRT_INLINE WORD __readgsword(DWORD Offset) { - WORD ret; - __asm__ volatile ("movw %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return ret; - } - __CRT_INLINE DWORD __readgsdword(DWORD Offset) { - DWORD ret; - __asm__ volatile ("movl %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return ret; - } - __CRT_INLINE DWORD64 __readgsqword(DWORD Offset) { - void *ret; - __asm__ volatile ("movq %%gs:%1,%0" - : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - return (DWORD64) ret; - } - __CRT_INLINE VOID __writegsbyte(DWORD Offset,BYTE Data) { - __asm__ volatile ("movb %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - __CRT_INLINE VOID __writegsword(DWORD Offset,WORD Data) { - __asm__ volatile ("movw %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - __CRT_INLINE VOID __writegsdword(DWORD Offset,DWORD Data) { - __asm__ volatile ("movl %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - __CRT_INLINE VOID __writegsqword(DWORD Offset,DWORD64 Data) { - __asm__ volatile ("movq %0,%%gs:%1" - : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); - } - -#ifdef __cplusplus - } -#endif -#endif - -#define EXCEPTION_READ_FAULT 0 -#define EXCEPTION_WRITE_FAULT 1 -#define EXCEPTION_EXECUTE_FAULT 8 - -#if !defined(RC_INVOKED) - -#define CONTEXT_AMD64 0x100000 - -#define CONTEXT_CONTROL (CONTEXT_AMD64 | 0x1L) -#define CONTEXT_INTEGER (CONTEXT_AMD64 | 0x2L) -#define CONTEXT_SEGMENTS (CONTEXT_AMD64 | 0x4L) -#define CONTEXT_FLOATING_POINT (CONTEXT_AMD64 | 0x8L) -#define CONTEXT_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L) - -#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) -#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS) - -#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 -#define CONTEXT_SERVICE_ACTIVE 0x10000000 -#define CONTEXT_EXCEPTION_REQUEST 0x40000000 -#define CONTEXT_EXCEPTION_REPORTING 0x80000000 -#endif - -#define INITIAL_MXCSR 0x1f80 -#define INITIAL_FPCSR 0x027f - - typedef struct DECLSPEC_ALIGN(16) _M128A { - ULONGLONG Low; - LONGLONG High; - } M128A,*PM128A; - - typedef struct _XMM_SAVE_AREA32 { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A FloatRegisters[8]; - M128A XmmRegisters[16]; - BYTE Reserved4[96]; - } XMM_SAVE_AREA32,*PXMM_SAVE_AREA32; - -#define LEGACY_SAVE_AREA_LENGTH sizeof(XMM_SAVE_AREA32) - - typedef struct DECLSPEC_ALIGN(16) _CONTEXT { - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; - union { - XMM_SAVE_AREA32 FltSave; - XMM_SAVE_AREA32 FloatSave; - struct { - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - }; - }; - M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; - } CONTEXT,*PCONTEXT; - -#define RUNTIME_FUNCTION_INDIRECT 0x1 - - typedef struct _RUNTIME_FUNCTION { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindData; - } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; - - typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); - typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); - -#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" - - NTSYSAPI VOID __cdecl RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); - NTSYSAPI BOOLEAN __cdecl RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,DWORD64 BaseAddress); - NTSYSAPI BOOLEAN __cdecl RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); - NTSYSAPI BOOLEAN __cdecl RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); -#endif - -#ifdef I_X86_ -#if(defined(_X86_) && !defined(__x86_64)) && !defined(RC_INVOKED) -#ifdef __cplusplus - extern "C" { -#endif - - __CRT_INLINE BOOLEAN InterlockedBitTestAndSet(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - - __CRT_INLINE BOOLEAN InterlockedBitTestAndReset(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - - __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { - int old = 0; - __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " - :"=r" (old),"=m" ((*(volatile long *) Base)) - :"Ir" (Bit)); - return (BOOLEAN) (old!=0); - } - -#ifdef _PREFIX_ - BYTE __readfsbyte(DWORD Offset); - WORD __readfsword(DWORD Offset); - DWORD __readfsdword(DWORD Offset); - VOID __writefsbyte(DWORD Offset,BYTE Data); - VOID __writefsword(DWORD Offset,WORD Data); - VOID __writefsdword(DWORD Offset,DWORD Data); -#endif - -#ifdef __cplusplus - } -#endif -#endif - -#if(defined(_X86_) && !defined(__x86_64)) - __CRT_INLINE VOID MemoryBarrier(VOID) { - LONG Barrier; - __asm__ __volatile__("xchgl %%eax,%0 " - :"=r" (Barrier)); - } -#define YieldProcessor() __asm__ __volatile__("rep nop "); - -#define PreFetchCacheLine(l,a) -#define ReadForWriteAccess(p) (*(p)) - -#define PF_TEMPORAL_LEVEL_1 -#define PF_NON_TEMPORAL_LEVEL_ALL - - __CRT_INLINE VOID DbgRaiseAssertionFailure(void) { - __asm__ __volatile__("int $0x2c "); - } - PVOID GetCurrentFiber(void); - __CRT_INLINE PVOID GetCurrentFiber(void) - { - void *ret; - __asm__ volatile ("movl %%fs:0x10,%0" - : "=r" (ret)); - return ret; - } - PVOID GetFiberData(void); - __CRT_INLINE PVOID GetFiberData(void) - { - void *ret; - __asm__ volatile ("movl %%fs:0x10,%0\n" - "movl (%0),%0" - : "=r" (ret)); - return ret; - } -#endif - -#define EXCEPTION_READ_FAULT 0 -#define EXCEPTION_WRITE_FAULT 1 -#define EXCEPTION_EXECUTE_FAULT 8 - -#define SIZE_OF_80387_REGISTERS 80 - -#if !defined(RC_INVOKED) - -#define CONTEXT_i386 0x00010000 -#define CONTEXT_i486 0x00010000 - -#define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) -#define CONTEXT_INTEGER (CONTEXT_i386 | 0x00000002L) -#define CONTEXT_SEGMENTS (CONTEXT_i386 | 0x00000004L) -#define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 0x00000008L) -#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) -#define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386 | 0x00000020L) - -#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) - -#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS) -#endif - -#define MAXIMUM_SUPPORTED_EXTENSION 512 - - typedef struct _FLOATING_SAVE_AREA { - DWORD ControlWord; - DWORD StatusWord; - DWORD TagWord; - DWORD ErrorOffset; - DWORD ErrorSelector; - DWORD DataOffset; - DWORD DataSelector; - BYTE RegisterArea[SIZE_OF_80387_REGISTERS]; - DWORD Cr0NpxState; - } FLOATING_SAVE_AREA; - - typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA; - - typedef struct _CONTEXT { - DWORD ContextFlags; - DWORD Dr0; - DWORD Dr1; - DWORD Dr2; - DWORD Dr3; - DWORD Dr6; - DWORD Dr7; - FLOATING_SAVE_AREA FloatSave; - DWORD SegGs; - DWORD SegFs; - DWORD SegEs; - DWORD SegDs; - - DWORD Edi; - DWORD Esi; - DWORD Ebx; - DWORD Edx; - DWORD Ecx; - DWORD Eax; - DWORD Ebp; - DWORD Eip; - DWORD SegCs; - DWORD EFlags; - DWORD Esp; - DWORD SegSs; - BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; - } CONTEXT; - - typedef CONTEXT *PCONTEXT; -#endif - -#ifndef _LDT_ENTRY_DEFINED -#define _LDT_ENTRY_DEFINED - - typedef struct _LDT_ENTRY { - WORD LimitLow; - WORD BaseLow; - union { - struct { - BYTE BaseMid; - BYTE Flags1; - BYTE Flags2; - BYTE BaseHi; - } Bytes; - struct { - DWORD BaseMid : 8; - DWORD Type : 5; - DWORD Dpl : 2; - DWORD Pres : 1; - DWORD LimitHi : 4; - DWORD Sys : 1; - DWORD Reserved_0 : 1; - DWORD Default_Big : 1; - DWORD Granularity : 1; - DWORD BaseHi : 8; - } Bits; - } HighWord; - } LDT_ENTRY,*PLDT_ENTRY; -#endif - -#if defined(__ia64__) && !defined(RC_INVOKED) - -#ifdef __cplusplus - extern "C" { -#endif - - BOOLEAN BitScanForward64(DWORD *Index,DWORD64 Mask); - BOOLEAN BitScanReverse64(DWORD *Index,DWORD64 Mask); - -#ifdef __cplusplus - } -#endif -#endif - -#if !defined(GENUTIL) && !defined(_GENIA64_) && defined(_IA64_) - - void *_cdecl _rdteb(void); -#ifdef __ia64__ - -#define NtCurrentTeb() ((struct _TEB *)_rdteb()) -#define GetCurrentFiber() (((PNT_TIB)NtCurrentTeb())->FiberData) -#define GetFiberData() (*(PVOID *)(GetCurrentFiber())) - -#ifdef __cplusplus - extern "C" { -#endif - - void __break(int); - void __yield(void); - void __mf(void); - void __lfetch(int Level,VOID CONST *Address); - void __lfetchfault(int Level,VOID CONST *Address); - void __lfetch_excl(int Level,VOID CONST *Address); - void __lfetchfault_excl(int Level,VOID CONST *Address); - -#define MD_LFHINT_NONE 0x00 -#define MD_LFHINT_NT1 0x01 -#define MD_LFHINT_NT2 0x02 -#define MD_LFHINT_NTA 0x03 - -#ifdef __cplusplus - } -#endif - -#define YieldProcessor __yield -#define MemoryBarrier __mf -#define PreFetchCacheLine __lfetch -#define ReadForWriteAccess(p) (*(p)) -#define DbgRaiseAssertionFailure() __break(ASSERT_BREAKPOINT) - -#define PF_TEMPORAL_LEVEL_1 MD_LFHINT_NONE -#define PF_NON_TEMPORAL_LEVEL_ALL MD_LFHINT_NTA - -#define UnsignedMultiplyHigh __UMULH - - ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); -#else - struct _TEB *NtCurrentTeb(void); -#endif -#endif - -#ifdef _IA64_ - -#define EXCEPTION_READ_FAULT 0 -#define EXCEPTION_WRITE_FAULT 1 -#define EXCEPTION_EXECUTE_FAULT 2 - -#if !defined(RC_INVOKED) - -#define CONTEXT_IA64 0x00080000 - -#define CONTEXT_CONTROL (CONTEXT_IA64 | 0x00000001L) -#define CONTEXT_LOWER_FLOATING_POINT (CONTEXT_IA64 | 0x00000002L) -#define CONTEXT_HIGHER_FLOATING_POINT (CONTEXT_IA64 | 0x00000004L) -#define CONTEXT_INTEGER (CONTEXT_IA64 | 0x00000008L) -#define CONTEXT_DEBUG (CONTEXT_IA64 | 0x00000010L) -#define CONTEXT_IA32_CONTROL (CONTEXT_IA64 | 0x00000020L) - -#define CONTEXT_FLOATING_POINT (CONTEXT_LOWER_FLOATING_POINT | CONTEXT_HIGHER_FLOATING_POINT) -#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_IA32_CONTROL) -#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_DEBUG | CONTEXT_IA32_CONTROL) - -#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 -#define CONTEXT_SERVICE_ACTIVE 0x10000000 -#define CONTEXT_EXCEPTION_REQUEST 0x40000000 -#define CONTEXT_EXCEPTION_REPORTING 0x80000000 -#endif - - typedef struct _CONTEXT { - DWORD ContextFlags; - DWORD Fill1[3]; - ULONGLONG DbI0; - ULONGLONG DbI1; - ULONGLONG DbI2; - ULONGLONG DbI3; - ULONGLONG DbI4; - ULONGLONG DbI5; - ULONGLONG DbI6; - ULONGLONG DbI7; - ULONGLONG DbD0; - ULONGLONG DbD1; - ULONGLONG DbD2; - ULONGLONG DbD3; - ULONGLONG DbD4; - ULONGLONG DbD5; - ULONGLONG DbD6; - ULONGLONG DbD7; - FLOAT128 FltS0; - FLOAT128 FltS1; - FLOAT128 FltS2; - FLOAT128 FltS3; - FLOAT128 FltT0; - FLOAT128 FltT1; - FLOAT128 FltT2; - FLOAT128 FltT3; - FLOAT128 FltT4; - FLOAT128 FltT5; - FLOAT128 FltT6; - FLOAT128 FltT7; - FLOAT128 FltT8; - FLOAT128 FltT9; - FLOAT128 FltS4; - FLOAT128 FltS5; - FLOAT128 FltS6; - FLOAT128 FltS7; - FLOAT128 FltS8; - FLOAT128 FltS9; - FLOAT128 FltS10; - FLOAT128 FltS11; - FLOAT128 FltS12; - FLOAT128 FltS13; - FLOAT128 FltS14; - FLOAT128 FltS15; - FLOAT128 FltS16; - FLOAT128 FltS17; - FLOAT128 FltS18; - FLOAT128 FltS19; - FLOAT128 FltF32; - FLOAT128 FltF33; - FLOAT128 FltF34; - FLOAT128 FltF35; - FLOAT128 FltF36; - FLOAT128 FltF37; - FLOAT128 FltF38; - FLOAT128 FltF39; - FLOAT128 FltF40; - FLOAT128 FltF41; - FLOAT128 FltF42; - FLOAT128 FltF43; - FLOAT128 FltF44; - FLOAT128 FltF45; - FLOAT128 FltF46; - FLOAT128 FltF47; - FLOAT128 FltF48; - FLOAT128 FltF49; - FLOAT128 FltF50; - FLOAT128 FltF51; - FLOAT128 FltF52; - FLOAT128 FltF53; - FLOAT128 FltF54; - FLOAT128 FltF55; - FLOAT128 FltF56; - FLOAT128 FltF57; - FLOAT128 FltF58; - FLOAT128 FltF59; - FLOAT128 FltF60; - FLOAT128 FltF61; - FLOAT128 FltF62; - FLOAT128 FltF63; - FLOAT128 FltF64; - FLOAT128 FltF65; - FLOAT128 FltF66; - FLOAT128 FltF67; - FLOAT128 FltF68; - FLOAT128 FltF69; - FLOAT128 FltF70; - FLOAT128 FltF71; - FLOAT128 FltF72; - FLOAT128 FltF73; - FLOAT128 FltF74; - FLOAT128 FltF75; - FLOAT128 FltF76; - FLOAT128 FltF77; - FLOAT128 FltF78; - FLOAT128 FltF79; - FLOAT128 FltF80; - FLOAT128 FltF81; - FLOAT128 FltF82; - FLOAT128 FltF83; - FLOAT128 FltF84; - FLOAT128 FltF85; - FLOAT128 FltF86; - FLOAT128 FltF87; - FLOAT128 FltF88; - FLOAT128 FltF89; - FLOAT128 FltF90; - FLOAT128 FltF91; - FLOAT128 FltF92; - FLOAT128 FltF93; - FLOAT128 FltF94; - FLOAT128 FltF95; - FLOAT128 FltF96; - FLOAT128 FltF97; - FLOAT128 FltF98; - FLOAT128 FltF99; - FLOAT128 FltF100; - FLOAT128 FltF101; - FLOAT128 FltF102; - FLOAT128 FltF103; - FLOAT128 FltF104; - FLOAT128 FltF105; - FLOAT128 FltF106; - FLOAT128 FltF107; - FLOAT128 FltF108; - FLOAT128 FltF109; - FLOAT128 FltF110; - FLOAT128 FltF111; - FLOAT128 FltF112; - FLOAT128 FltF113; - FLOAT128 FltF114; - FLOAT128 FltF115; - FLOAT128 FltF116; - FLOAT128 FltF117; - FLOAT128 FltF118; - FLOAT128 FltF119; - FLOAT128 FltF120; - FLOAT128 FltF121; - FLOAT128 FltF122; - FLOAT128 FltF123; - FLOAT128 FltF124; - FLOAT128 FltF125; - FLOAT128 FltF126; - FLOAT128 FltF127; - ULONGLONG StFPSR; - ULONGLONG IntGp; - ULONGLONG IntT0; - ULONGLONG IntT1; - ULONGLONG IntS0; - ULONGLONG IntS1; - ULONGLONG IntS2; - ULONGLONG IntS3; - ULONGLONG IntV0; - ULONGLONG IntT2; - ULONGLONG IntT3; - ULONGLONG IntT4; - ULONGLONG IntSp; - ULONGLONG IntTeb; - ULONGLONG IntT5; - ULONGLONG IntT6; - ULONGLONG IntT7; - ULONGLONG IntT8; - ULONGLONG IntT9; - ULONGLONG IntT10; - ULONGLONG IntT11; - ULONGLONG IntT12; - ULONGLONG IntT13; - ULONGLONG IntT14; - ULONGLONG IntT15; - ULONGLONG IntT16; - ULONGLONG IntT17; - ULONGLONG IntT18; - ULONGLONG IntT19; - ULONGLONG IntT20; - ULONGLONG IntT21; - ULONGLONG IntT22; - ULONGLONG IntNats; - ULONGLONG Preds; - ULONGLONG BrRp; - ULONGLONG BrS0; - ULONGLONG BrS1; - ULONGLONG BrS2; - ULONGLONG BrS3; - ULONGLONG BrS4; - ULONGLONG BrT0; - ULONGLONG BrT1; - ULONGLONG ApUNAT; - ULONGLONG ApLC; - ULONGLONG ApEC; - ULONGLONG ApCCV; - ULONGLONG ApDCR; - ULONGLONG RsPFS; - ULONGLONG RsBSP; - ULONGLONG RsBSPSTORE; - ULONGLONG RsRSC; - ULONGLONG RsRNAT; - ULONGLONG StIPSR; - ULONGLONG StIIP; - ULONGLONG StIFS; - ULONGLONG StFCR; - ULONGLONG Eflag; - ULONGLONG SegCSD; - ULONGLONG SegSSD; - ULONGLONG Cflag; - ULONGLONG StFSR; - ULONGLONG StFIR; - ULONGLONG StFDR; - ULONGLONG UNUSEDPACK; - } CONTEXT,*PCONTEXT; - - typedef struct _PLABEL_DESCRIPTOR { - ULONGLONG EntryPoint; - ULONGLONG GlobalPointer; - } PLABEL_DESCRIPTOR,*PPLABEL_DESCRIPTOR; - - typedef struct _RUNTIME_FUNCTION { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindInfoAddress; - } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; - - typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); - typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); - -#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" - - BOOLEAN RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,ULONGLONG BaseAddress,ULONGLONG TargetGp); - BOOLEAN RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,DWORD64 TargetGp,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); - BOOLEAN RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); - VOID RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); - VOID __jump_unwind(ULONGLONG TargetMsFrame,ULONGLONG TargetBsFrame,ULONGLONG TargetPc); -#endif - -#define EXCEPTION_NONCONTINUABLE 0x1 -#define EXCEPTION_MAXIMUM_PARAMETERS 15 - - typedef struct _EXCEPTION_RECORD { - DWORD ExceptionCode; - DWORD ExceptionFlags; - struct _EXCEPTION_RECORD *ExceptionRecord; - PVOID ExceptionAddress; - DWORD NumberParameters; - ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - } EXCEPTION_RECORD; - - typedef EXCEPTION_RECORD *PEXCEPTION_RECORD; - - typedef struct _EXCEPTION_RECORD32 { - DWORD ExceptionCode; - DWORD ExceptionFlags; - DWORD ExceptionRecord; - DWORD ExceptionAddress; - DWORD NumberParameters; - DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - } EXCEPTION_RECORD32,*PEXCEPTION_RECORD32; - - typedef struct _EXCEPTION_RECORD64 { - DWORD ExceptionCode; - DWORD ExceptionFlags; - DWORD64 ExceptionRecord; - DWORD64 ExceptionAddress; - DWORD NumberParameters; - DWORD __unusedAlignment; - DWORD64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - } EXCEPTION_RECORD64,*PEXCEPTION_RECORD64; - - typedef struct _EXCEPTION_POINTERS { - PEXCEPTION_RECORD ExceptionRecord; - PCONTEXT ContextRecord; - } EXCEPTION_POINTERS,*PEXCEPTION_POINTERS; - -#ifdef __x86_64 - - typedef EXCEPTION_DISPOSITION NTAPI EXCEPTION_ROUTINE (struct _EXCEPTION_RECORD *ExceptionRecord, PVOID EstablisherFrame, struct _CONTEXT *ContextRecord, PVOID DispatcherContext); -#ifndef __PEXCEPTION_ROUTINE_DEFINED -#define __PEXCEPTION_ROUTINE_DEFINED - typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE; -#endif - - /* http://msdn.microsoft.com/en-us/library/ms680597(VS.85).aspx */ - -#define UNWIND_HISTORY_TABLE_SIZE 12 - - typedef struct _UNWIND_HISTORY_TABLE_ENTRY { - ULONG64 ImageBase; - PRUNTIME_FUNCTION FunctionEntry; - } UNWIND_HISTORY_TABLE_ENTRY, *PUNWIND_HISTORY_TABLE_ENTRY; - -#define UNWIND_HISTORY_TABLE_NONE 0 -#define UNWIND_HISTORY_TABLE_GLOBAL 1 -#define UNWIND_HISTORY_TABLE_LOCAL 2 - - typedef struct _UNWIND_HISTORY_TABLE { - ULONG Count; - UCHAR Search; - ULONG64 LowAddress; - ULONG64 HighAddress; - UNWIND_HISTORY_TABLE_ENTRY Entry[UNWIND_HISTORY_TABLE_SIZE]; - } UNWIND_HISTORY_TABLE, *PUNWIND_HISTORY_TABLE; - - /* http://msdn.microsoft.com/en-us/library/b6sf5kbd(VS.80).aspx */ - - struct _DISPATCHER_CONTEXT; - typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; - typedef struct _DISPATCHER_CONTEXT *PDISPATCHER_CONTEXT; - - struct _DISPATCHER_CONTEXT { - ULONG64 ControlPc; - ULONG64 ImageBase; - PRUNTIME_FUNCTION FunctionEntry; - ULONG64 EstablisherFrame; - ULONG64 TargetIp; - PCONTEXT ContextRecord; - PEXCEPTION_ROUTINE LanguageHandler; - PVOID HandlerData; - /* http://www.nynaeve.net/?p=99 */ - PUNWIND_HISTORY_TABLE HistoryTable; - ULONG ScopeIndex; - ULONG Fill0; - }; - - /* http://msdn.microsoft.com/en-us/library/ms680617(VS.85).aspx */ - - typedef struct _KNONVOLATILE_CONTEXT_POINTERS - { - PM128A FloatingContext[16]; - PULONG64 IntegerContext[16]; - } KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS; -#endif /* defined(__x86_64) */ - - typedef PVOID PACCESS_TOKEN; - typedef PVOID PSECURITY_DESCRIPTOR; - typedef PVOID PSID; - - typedef DWORD ACCESS_MASK; - typedef ACCESS_MASK *PACCESS_MASK; - -#define DELETE (0x00010000L) -#define READ_CONTROL (0x00020000L) -#define WRITE_DAC (0x00040000L) -#define WRITE_OWNER (0x00080000L) -#define SYNCHRONIZE (0x00100000L) - -#define STANDARD_RIGHTS_REQUIRED (0x000F0000L) -#define STANDARD_RIGHTS_READ (READ_CONTROL) -#define STANDARD_RIGHTS_WRITE (READ_CONTROL) -#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL) -#define STANDARD_RIGHTS_ALL (0x001F0000L) - -#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL) - -#define ACCESS_SYSTEM_SECURITY (0x01000000L) - -#define MAXIMUM_ALLOWED (0x02000000L) - -#define GENERIC_READ (0x80000000L) -#define GENERIC_WRITE (0x40000000L) -#define GENERIC_EXECUTE (0x20000000L) -#define GENERIC_ALL (0x10000000L) - - typedef struct _GENERIC_MAPPING { - ACCESS_MASK GenericRead; - ACCESS_MASK GenericWrite; - ACCESS_MASK GenericExecute; - ACCESS_MASK GenericAll; - } GENERIC_MAPPING; - typedef GENERIC_MAPPING *PGENERIC_MAPPING; - -#include - - typedef struct _LUID_AND_ATTRIBUTES { - LUID Luid; - DWORD Attributes; - } LUID_AND_ATTRIBUTES,*PLUID_AND_ATTRIBUTES; - typedef LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; - typedef LUID_AND_ATTRIBUTES_ARRAY *PLUID_AND_ATTRIBUTES_ARRAY; - -#include - -#ifndef SID_IDENTIFIER_AUTHORITY_DEFINED -#define SID_IDENTIFIER_AUTHORITY_DEFINED - typedef struct _SID_IDENTIFIER_AUTHORITY { - BYTE Value[6]; - } SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY; -#endif - -#ifndef SID_DEFINED -#define SID_DEFINED - typedef struct _SID { - BYTE Revision; - BYTE SubAuthorityCount; - SID_IDENTIFIER_AUTHORITY IdentifierAuthority; - DWORD SubAuthority[ANYSIZE_ARRAY]; - } SID,*PISID; -#endif - -#define SID_REVISION (1) -#define SID_MAX_SUB_AUTHORITIES (15) -#define SID_RECOMMENDED_SUB_AUTHORITIES (1) - -#define SECURITY_MAX_SID_SIZE (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES *sizeof(DWORD))) - - typedef enum _SID_NAME_USE { - SidTypeUser = 1,SidTypeGroup,SidTypeDomain,SidTypeAlias,SidTypeWellKnownGroup,SidTypeDeletedAccount,SidTypeInvalid,SidTypeUnknown,SidTypeComputer - } SID_NAME_USE,*PSID_NAME_USE; - - typedef struct _SID_AND_ATTRIBUTES { - PSID Sid; - DWORD Attributes; - } SID_AND_ATTRIBUTES,*PSID_AND_ATTRIBUTES; - - typedef SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; - typedef SID_AND_ATTRIBUTES_ARRAY *PSID_AND_ATTRIBUTES_ARRAY; - -#define SECURITY_NULL_SID_AUTHORITY {0,0,0,0,0,0} -#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} -#define SECURITY_LOCAL_SID_AUTHORITY {0,0,0,0,0,2} -#define SECURITY_CREATOR_SID_AUTHORITY {0,0,0,0,0,3} -#define SECURITY_NON_UNIQUE_AUTHORITY {0,0,0,0,0,4} -#define SECURITY_RESOURCE_MANAGER_AUTHORITY {0,0,0,0,0,9} - -#define SECURITY_NULL_RID (0x00000000L) -#define SECURITY_WORLD_RID (0x00000000L) -#define SECURITY_LOCAL_RID (0x00000000L) - -#define SECURITY_CREATOR_OWNER_RID (0x00000000L) -#define SECURITY_CREATOR_GROUP_RID (0x00000001L) - -#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L) -#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L) - -#define SECURITY_NT_AUTHORITY {0,0,0,0,0,5} - -#define SECURITY_DIALUP_RID (0x00000001L) -#define SECURITY_NETWORK_RID (0x00000002L) -#define SECURITY_BATCH_RID (0x00000003L) -#define SECURITY_INTERACTIVE_RID (0x00000004L) -#define SECURITY_LOGON_IDS_RID (0x00000005L) -#define SECURITY_LOGON_IDS_RID_COUNT (3L) -#define SECURITY_SERVICE_RID (0x00000006L) -#define SECURITY_ANONYMOUS_LOGON_RID (0x00000007L) -#define SECURITY_PROXY_RID (0x00000008L) -#define SECURITY_ENTERPRISE_CONTROLLERS_RID (0x00000009L) -#define SECURITY_SERVER_LOGON_RID SECURITY_ENTERPRISE_CONTROLLERS_RID -#define SECURITY_PRINCIPAL_SELF_RID (0x0000000AL) -#define SECURITY_AUTHENTICATED_USER_RID (0x0000000BL) -#define SECURITY_RESTRICTED_CODE_RID (0x0000000CL) -#define SECURITY_TERMINAL_SERVER_RID (0x0000000DL) -#define SECURITY_REMOTE_LOGON_RID (0x0000000EL) -#define SECURITY_THIS_ORGANIZATION_RID (0x0000000FL) -#define SECURITY_IUSER_RID (0x00000011L) - -#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L) -#define SECURITY_LOCAL_SERVICE_RID (0x00000013L) -#define SECURITY_NETWORK_SERVICE_RID (0x00000014L) - -#define SECURITY_NT_NON_UNIQUE (0x00000015L) -#define SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT (3L) - -#define SECURITY_ENTERPRISE_READONLY_CONTROLLERS_RID (0x00000016L) - -#define SECURITY_BUILTIN_DOMAIN_RID (0x00000020L) -#define SECURITY_WRITE_RESTRICTED_CODE_RID (0x00000021L) - -#define SECURITY_PACKAGE_BASE_RID (0x00000040L) -#define SECURITY_PACKAGE_RID_COUNT (2L) -#define SECURITY_PACKAGE_NTLM_RID (0x0000000AL) -#define SECURITY_PACKAGE_SCHANNEL_RID (0x0000000EL) -#define SECURITY_PACKAGE_DIGEST_RID (0x00000015L) - -#define SECURITY_SERVICE_ID_BASE_RID (0x00000050L) -#define SECURITY_SERVICE_ID_RID_COUNT (6L) - -#define SECURITY_RESERVED_ID_BASE_RID (0x00000051L) - -#define SECURITY_MAX_ALWAYS_FILTERED (0x000003E7L) -#define SECURITY_MIN_NEVER_FILTERED (0x000003E8L) - -#define SECURITY_OTHER_ORGANIZATION_RID (0x000003E8L) - -#define FOREST_USER_RID_MAX (0x000001F3L) - -#define DOMAIN_USER_RID_ADMIN (0x000001F4L) -#define DOMAIN_USER_RID_GUEST (0x000001F5L) -#define DOMAIN_USER_RID_KRBTGT (0x000001F6L) - -#define DOMAIN_USER_RID_MAX (0x000003E7L) - -#define DOMAIN_GROUP_RID_ADMINS (0x00000200L) -#define DOMAIN_GROUP_RID_USERS (0x00000201L) -#define DOMAIN_GROUP_RID_GUESTS (0x00000202L) -#define DOMAIN_GROUP_RID_COMPUTERS (0x00000203L) -#define DOMAIN_GROUP_RID_CONTROLLERS (0x00000204L) -#define DOMAIN_GROUP_RID_CERT_ADMINS (0x00000205L) -#define DOMAIN_GROUP_RID_SCHEMA_ADMINS (0x00000206L) -#define DOMAIN_GROUP_RID_ENTERPRISE_ADMINS (0x00000207L) -#define DOMAIN_GROUP_RID_POLICY_ADMINS (0x00000208L) -#define DOMAIN_GROUP_RID_READONLY_CONTROLLERS (0x00000209L) - -#define DOMAIN_ALIAS_RID_ADMINS (0x00000220L) -#define DOMAIN_ALIAS_RID_USERS (0x00000221L) -#define DOMAIN_ALIAS_RID_GUESTS (0x00000222L) -#define DOMAIN_ALIAS_RID_POWER_USERS (0x00000223L) - -#define DOMAIN_ALIAS_RID_ACCOUNT_OPS (0x00000224L) -#define DOMAIN_ALIAS_RID_SYSTEM_OPS (0x00000225L) -#define DOMAIN_ALIAS_RID_PRINT_OPS (0x00000226L) -#define DOMAIN_ALIAS_RID_BACKUP_OPS (0x00000227L) - -#define DOMAIN_ALIAS_RID_REPLICATOR (0x00000228L) -#define DOMAIN_ALIAS_RID_RAS_SERVERS (0x00000229L) -#define DOMAIN_ALIAS_RID_PREW2KCOMPACCESS (0x0000022AL) -#define DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS (0x0000022BL) -#define DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS (0x0000022CL) -#define DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS (0x0000022DL) - -#define DOMAIN_ALIAS_RID_MONITORING_USERS (0x0000022EL) -#define DOMAIN_ALIAS_RID_LOGGING_USERS (0x0000022FL) -#define DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS (0x00000230L) -#define DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS (0x00000231L) -#define DOMAIN_ALIAS_RID_DCOM_USERS (0x00000232L) - -#define DOMAIN_ALIAS_RID_IUSERS (0x00000238L) -#define DOMAIN_ALIAS_RID_CRYPTO_OPERATORS (0x00000239L) -#define DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP (0x0000023BL) -#define DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP (0x0000023CL) -#define DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP (0x0000023DL) - -#define SECURITY_MANDATORY_LABEL_AUTHORITY {0,0,0,0,0,16} -#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L) -#define SECURITY_MANDATORY_LOW_RID (0x00001000L) -#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L) -#define SECURITY_MANDATORY_HIGH_RID (0x00003000L) -#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L) -#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L) - -#define SECURITY_MANDATORY_MAXIMUM_USER_RID SECURITY_MANDATORY_SYSTEM_RID - -#define MANDATORY_LEVEL_TO_MANDATORY_RID(IL) (IL * 0x1000) - - typedef enum { - WinNullSid = 0,WinWorldSid = 1,WinLocalSid = 2,WinCreatorOwnerSid = 3,WinCreatorGroupSid = 4,WinCreatorOwnerServerSid = 5,WinCreatorGroupServerSid = 6,WinNtAuthoritySid = 7,WinDialupSid = 8,WinNetworkSid = 9,WinBatchSid = 10,WinInteractiveSid = 11,WinServiceSid = 12,WinAnonymousSid = 13,WinProxySid = 14,WinEnterpriseControllersSid = 15,WinSelfSid = 16,WinAuthenticatedUserSid = 17,WinRestrictedCodeSid = 18,WinTerminalServerSid = 19,WinRemoteLogonIdSid = 20,WinLogonIdsSid = 21,WinLocalSystemSid = 22,WinLocalServiceSid = 23,WinNetworkServiceSid = 24,WinBuiltinDomainSid = 25,WinBuiltinAdministratorsSid = 26,WinBuiltinUsersSid = 27,WinBuiltinGuestsSid = 28,WinBuiltinPowerUsersSid = 29,WinBuiltinAccountOperatorsSid = 30,WinBuiltinSystemOperatorsSid = 31,WinBuiltinPrintOperatorsSid = 32,WinBuiltinBackupOperatorsSid = 33,WinBuiltinReplicatorSid = 34,WinBuiltinPreWindows2000CompatibleAccessSid = 35,WinBuiltinRemoteDesktopUsersSid = 36,WinBuiltinNetworkConfigurationOperatorsSid = 37,WinAccountAdministratorSid = 38,WinAccountGuestSid = 39,WinAccountKrbtgtSid = 40,WinAccountDomainAdminsSid = 41,WinAccountDomainUsersSid = 42,WinAccountDomainGuestsSid = 43,WinAccountComputersSid = 44,WinAccountControllersSid = 45,WinAccountCertAdminsSid = 46,WinAccountSchemaAdminsSid = 47,WinAccountEnterpriseAdminsSid = 48,WinAccountPolicyAdminsSid = 49,WinAccountRasAndIasServersSid = 50,WinNTLMAuthenticationSid = 51,WinDigestAuthenticationSid = 52,WinSChannelAuthenticationSid = 53,WinThisOrganizationSid = 54,WinOtherOrganizationSid = 55,WinBuiltinIncomingForestTrustBuildersSid = 56,WinBuiltinPerfMonitoringUsersSid = 57,WinBuiltinPerfLoggingUsersSid = 58,WinBuiltinAuthorizationAccessSid = 59,WinBuiltinTerminalServerLicenseServersSid = 60,WinBuiltinDCOMUsersSid = 61 - } WELL_KNOWN_SID_TYPE; - -#define SYSTEM_LUID { 0x3E7,0x0 } -#define ANONYMOUS_LOGON_LUID { 0x3e6,0x0 } -#define LOCALSERVICE_LUID { 0x3e5,0x0 } -#define NETWORKSERVICE_LUID { 0x3e4,0x0 } -#define IUSER_LUID { 0x3e3, 0x0 } - -#define SE_GROUP_MANDATORY (0x00000001L) -#define SE_GROUP_ENABLED_BY_DEFAULT (0x00000002L) -#define SE_GROUP_ENABLED (0x00000004L) -#define SE_GROUP_OWNER (0x00000008L) -#define SE_GROUP_USE_FOR_DENY_ONLY (0x00000010L) -#define SE_GROUP_INTEGRITY (0x00000020L) -#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L) -#define SE_GROUP_LOGON_ID (0xC0000000L) -#define SE_GROUP_RESOURCE (0x20000000L) - -#define ACL_REVISION (2) -#define ACL_REVISION_DS (4) - -#define ACL_REVISION1 (1) -#define MIN_ACL_REVISION ACL_REVISION2 -#define ACL_REVISION2 (2) -#define ACL_REVISION3 (3) -#define ACL_REVISION4 (4) -#define MAX_ACL_REVISION ACL_REVISION4 - - typedef struct _ACL { - BYTE AclRevision; - BYTE Sbz1; - WORD AclSize; - WORD AceCount; - WORD Sbz2; - } ACL; - typedef ACL *PACL; - - typedef struct _ACE_HEADER { - BYTE AceType; - BYTE AceFlags; - WORD AceSize; - } ACE_HEADER; - typedef ACE_HEADER *PACE_HEADER; - -#define ACCESS_MIN_MS_ACE_TYPE (0x0) -#define ACCESS_ALLOWED_ACE_TYPE (0x0) -#define ACCESS_DENIED_ACE_TYPE (0x1) -#define SYSTEM_AUDIT_ACE_TYPE (0x2) -#define SYSTEM_ALARM_ACE_TYPE (0x3) -#define ACCESS_MAX_MS_V2_ACE_TYPE (0x3) - -#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE (0x4) -#define ACCESS_MAX_MS_V3_ACE_TYPE (0x4) - -#define ACCESS_MIN_MS_OBJECT_ACE_TYPE (0x5) -#define ACCESS_ALLOWED_OBJECT_ACE_TYPE (0x5) -#define ACCESS_DENIED_OBJECT_ACE_TYPE (0x6) -#define SYSTEM_AUDIT_OBJECT_ACE_TYPE (0x7) -#define SYSTEM_ALARM_OBJECT_ACE_TYPE (0x8) -#define ACCESS_MAX_MS_OBJECT_ACE_TYPE (0x8) - -#define ACCESS_MAX_MS_V4_ACE_TYPE (0x8) -#define ACCESS_MAX_MS_ACE_TYPE (0x8) - -#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE (0x9) -#define ACCESS_DENIED_CALLBACK_ACE_TYPE (0xA) -#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE (0xB) -#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE (0xC) -#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE (0xD) -#define SYSTEM_ALARM_CALLBACK_ACE_TYPE (0xE) -#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE (0xF) -#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE (0x10) - -#define SYSTEM_MANDATORY_LABEL_ACE_TYPE (0x11) -#define ACCESS_MAX_MS_V5_ACE_TYPE (0x11) - -#define OBJECT_INHERIT_ACE (0x1) -#define CONTAINER_INHERIT_ACE (0x2) -#define NO_PROPAGATE_INHERIT_ACE (0x4) -#define INHERIT_ONLY_ACE (0x8) -#define INHERITED_ACE (0x10) -#define VALID_INHERIT_FLAGS (0x1F) - -#define SUCCESSFUL_ACCESS_ACE_FLAG (0x40) -#define FAILED_ACCESS_ACE_FLAG (0x80) - - typedef struct _ACCESS_ALLOWED_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } ACCESS_ALLOWED_ACE; - - typedef ACCESS_ALLOWED_ACE *PACCESS_ALLOWED_ACE; - - typedef struct _ACCESS_DENIED_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } ACCESS_DENIED_ACE; - typedef ACCESS_DENIED_ACE *PACCESS_DENIED_ACE; - - typedef struct _SYSTEM_AUDIT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } SYSTEM_AUDIT_ACE; - typedef SYSTEM_AUDIT_ACE *PSYSTEM_AUDIT_ACE; - - typedef struct _SYSTEM_ALARM_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - } SYSTEM_ALARM_ACE; - typedef SYSTEM_ALARM_ACE *PSYSTEM_ALARM_ACE; - - typedef struct _ACCESS_ALLOWED_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } ACCESS_ALLOWED_OBJECT_ACE,*PACCESS_ALLOWED_OBJECT_ACE; - - typedef struct _ACCESS_DENIED_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } ACCESS_DENIED_OBJECT_ACE,*PACCESS_DENIED_OBJECT_ACE; - - typedef struct _SYSTEM_AUDIT_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } SYSTEM_AUDIT_OBJECT_ACE,*PSYSTEM_AUDIT_OBJECT_ACE; - - typedef struct _SYSTEM_ALARM_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - } SYSTEM_ALARM_OBJECT_ACE,*PSYSTEM_ALARM_OBJECT_ACE; - - typedef struct _ACCESS_ALLOWED_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } ACCESS_ALLOWED_CALLBACK_ACE,*PACCESS_ALLOWED_CALLBACK_ACE; - - typedef struct _ACCESS_DENIED_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } ACCESS_DENIED_CALLBACK_ACE,*PACCESS_DENIED_CALLBACK_ACE; - - typedef struct _SYSTEM_AUDIT_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } SYSTEM_AUDIT_CALLBACK_ACE,*PSYSTEM_AUDIT_CALLBACK_ACE; - - typedef struct _SYSTEM_ALARM_CALLBACK_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD SidStart; - - } SYSTEM_ALARM_CALLBACK_ACE,*PSYSTEM_ALARM_CALLBACK_ACE; - - typedef struct _ACCESS_ALLOWED_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } ACCESS_ALLOWED_CALLBACK_OBJECT_ACE,*PACCESS_ALLOWED_CALLBACK_OBJECT_ACE; - - typedef struct _ACCESS_DENIED_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } ACCESS_DENIED_CALLBACK_OBJECT_ACE,*PACCESS_DENIED_CALLBACK_OBJECT_ACE; - - typedef struct _SYSTEM_AUDIT_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } SYSTEM_AUDIT_CALLBACK_OBJECT_ACE,*PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE; - - typedef struct _SYSTEM_ALARM_CALLBACK_OBJECT_ACE { - ACE_HEADER Header; - ACCESS_MASK Mask; - DWORD Flags; - GUID ObjectType; - GUID InheritedObjectType; - DWORD SidStart; - - } SYSTEM_ALARM_CALLBACK_OBJECT_ACE,*PSYSTEM_ALARM_CALLBACK_OBJECT_ACE; - -#define ACE_OBJECT_TYPE_PRESENT 0x1 -#define ACE_INHERITED_OBJECT_TYPE_PRESENT 0x2 - - typedef enum _ACL_INFORMATION_CLASS { - AclRevisionInformation = 1,AclSizeInformation - } ACL_INFORMATION_CLASS; - - typedef struct _ACL_REVISION_INFORMATION { - DWORD AclRevision; - } ACL_REVISION_INFORMATION; - typedef ACL_REVISION_INFORMATION *PACL_REVISION_INFORMATION; - - typedef struct _ACL_SIZE_INFORMATION { - DWORD AceCount; - DWORD AclBytesInUse; - DWORD AclBytesFree; - } ACL_SIZE_INFORMATION; - typedef ACL_SIZE_INFORMATION *PACL_SIZE_INFORMATION; - -#define SECURITY_DESCRIPTOR_REVISION (1) -#define SECURITY_DESCRIPTOR_REVISION1 (1) - -#define SECURITY_DESCRIPTOR_MIN_LENGTH (sizeof(SECURITY_DESCRIPTOR)) - - typedef WORD SECURITY_DESCRIPTOR_CONTROL,*PSECURITY_DESCRIPTOR_CONTROL; - -#define SE_OWNER_DEFAULTED (0x0001) -#define SE_GROUP_DEFAULTED (0x0002) -#define SE_DACL_PRESENT (0x0004) -#define SE_DACL_DEFAULTED (0x0008) -#define SE_SACL_PRESENT (0x0010) -#define SE_SACL_DEFAULTED (0x0020) -#define SE_DACL_AUTO_INHERIT_REQ (0x0100) -#define SE_SACL_AUTO_INHERIT_REQ (0x0200) -#define SE_DACL_AUTO_INHERITED (0x0400) -#define SE_SACL_AUTO_INHERITED (0x0800) -#define SE_DACL_PROTECTED (0x1000) -#define SE_SACL_PROTECTED (0x2000) -#define SE_RM_CONTROL_VALID (0x4000) -#define SE_SELF_RELATIVE (0x8000) - - typedef struct _SECURITY_DESCRIPTOR_RELATIVE { - BYTE Revision; - BYTE Sbz1; - SECURITY_DESCRIPTOR_CONTROL Control; - DWORD Owner; - DWORD Group; - DWORD Sacl; - DWORD Dacl; - } SECURITY_DESCRIPTOR_RELATIVE,*PISECURITY_DESCRIPTOR_RELATIVE; - - typedef struct _SECURITY_DESCRIPTOR { - BYTE Revision; - BYTE Sbz1; - SECURITY_DESCRIPTOR_CONTROL Control; - PSID Owner; - PSID Group; - PACL Sacl; - PACL Dacl; - - } SECURITY_DESCRIPTOR,*PISECURITY_DESCRIPTOR; - - typedef struct _OBJECT_TYPE_LIST { - WORD Level; - WORD Sbz; - GUID *ObjectType; - } OBJECT_TYPE_LIST,*POBJECT_TYPE_LIST; - -#define ACCESS_OBJECT_GUID 0 -#define ACCESS_PROPERTY_SET_GUID 1 -#define ACCESS_PROPERTY_GUID 2 - -#define ACCESS_MAX_LEVEL 4 - - typedef enum _AUDIT_EVENT_TYPE { - AuditEventObjectAccess,AuditEventDirectoryServiceAccess - } AUDIT_EVENT_TYPE,*PAUDIT_EVENT_TYPE; - -#define AUDIT_ALLOW_NO_PRIVILEGE 0x1 - -#define ACCESS_DS_SOURCE_A "DS" -#define ACCESS_DS_SOURCE_W L"DS" -#define ACCESS_DS_OBJECT_TYPE_NAME_A "Directory Service Object" -#define ACCESS_DS_OBJECT_TYPE_NAME_W L"Directory Service Object" - -#define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L) -#define SE_PRIVILEGE_ENABLED (0x00000002L) -#define SE_PRIVILEGE_REMOVED (0X00000004L) -#define SE_PRIVILEGE_USED_FOR_ACCESS (0x80000000L) - -#define PRIVILEGE_SET_ALL_NECESSARY (1) - - typedef struct _PRIVILEGE_SET { - DWORD PrivilegeCount; - DWORD Control; - LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]; - } PRIVILEGE_SET,*PPRIVILEGE_SET; - -#define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege") -#define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege") -#define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege") -#define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege") -#define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege") -#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege") -#define SE_TCB_NAME TEXT("SeTcbPrivilege") -#define SE_SECURITY_NAME TEXT("SeSecurityPrivilege") -#define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege") -#define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege") -#define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege") -#define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege") -#define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege") -#define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege") -#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege") -#define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege") -#define SE_BACKUP_NAME TEXT("SeBackupPrivilege") -#define SE_RESTORE_NAME TEXT("SeRestorePrivilege") -#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege") -#define SE_DEBUG_NAME TEXT("SeDebugPrivilege") -#define SE_AUDIT_NAME TEXT("SeAuditPrivilege") -#define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege") -#define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege") -#define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege") -#define SE_UNDOCK_NAME TEXT("SeUndockPrivilege") -#define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege") -#define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege") -#define SE_MANAGE_VOLUME_NAME TEXT("SeManageVolumePrivilege") -#define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege") -#define SE_CREATE_GLOBAL_NAME TEXT("SeCreateGlobalPrivilege") - - typedef enum _SECURITY_IMPERSONATION_LEVEL { - SecurityAnonymous,SecurityIdentification,SecurityImpersonation,SecurityDelegation - } SECURITY_IMPERSONATION_LEVEL,*PSECURITY_IMPERSONATION_LEVEL; - -#define SECURITY_MAX_IMPERSONATION_LEVEL SecurityDelegation -#define SECURITY_MIN_IMPERSONATION_LEVEL SecurityAnonymous -#define DEFAULT_IMPERSONATION_LEVEL SecurityImpersonation -#define VALID_IMPERSONATION_LEVEL(L) (((L) >= SECURITY_MIN_IMPERSONATION_LEVEL) && ((L) <= SECURITY_MAX_IMPERSONATION_LEVEL)) - -#define TOKEN_ASSIGN_PRIMARY (0x0001) -#define TOKEN_DUPLICATE (0x0002) -#define TOKEN_IMPERSONATE (0x0004) -#define TOKEN_QUERY (0x0008) -#define TOKEN_QUERY_SOURCE (0x0010) -#define TOKEN_ADJUST_PRIVILEGES (0x0020) -#define TOKEN_ADJUST_GROUPS (0x0040) -#define TOKEN_ADJUST_DEFAULT (0x0080) -#define TOKEN_ADJUST_SESSIONID (0x0100) - -#define TOKEN_ALL_ACCESS_P (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) -#define TOKEN_ALL_ACCESS (TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID) -#define TOKEN_READ (STANDARD_RIGHTS_READ | TOKEN_QUERY) - -#define TOKEN_WRITE (STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) - -#define TOKEN_EXECUTE (STANDARD_RIGHTS_EXECUTE) - - typedef enum _TOKEN_TYPE { - TokenPrimary = 1,TokenImpersonation - } TOKEN_TYPE; - typedef TOKEN_TYPE *PTOKEN_TYPE; - - typedef enum _TOKEN_INFORMATION_CLASS { - TokenUser = 1,TokenGroups,TokenPrivileges,TokenOwner,TokenPrimaryGroup,TokenDefaultDacl,TokenSource,TokenType,TokenImpersonationLevel, - TokenStatistics,TokenRestrictedSids,TokenSessionId,TokenGroupsAndPrivileges,TokenSessionReference,TokenSandBoxInert,TokenAuditPolicy, - TokenOrigin,MaxTokenInfoClass - } TOKEN_INFORMATION_CLASS,*PTOKEN_INFORMATION_CLASS; - - typedef struct _TOKEN_USER { - SID_AND_ATTRIBUTES User; - } TOKEN_USER,*PTOKEN_USER; - - typedef struct _TOKEN_GROUPS { - DWORD GroupCount; - SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; - } TOKEN_GROUPS,*PTOKEN_GROUPS; - - typedef struct _TOKEN_PRIVILEGES { - DWORD PrivilegeCount; - LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; - } TOKEN_PRIVILEGES,*PTOKEN_PRIVILEGES; - - typedef struct _TOKEN_OWNER { - PSID Owner; - } TOKEN_OWNER,*PTOKEN_OWNER; - - typedef struct _TOKEN_PRIMARY_GROUP { - PSID PrimaryGroup; - } TOKEN_PRIMARY_GROUP,*PTOKEN_PRIMARY_GROUP; - - typedef struct _TOKEN_DEFAULT_DACL { - PACL DefaultDacl; - } TOKEN_DEFAULT_DACL,*PTOKEN_DEFAULT_DACL; - - typedef struct _TOKEN_GROUPS_AND_PRIVILEGES { - DWORD SidCount; - DWORD SidLength; - PSID_AND_ATTRIBUTES Sids; - DWORD RestrictedSidCount; - DWORD RestrictedSidLength; - PSID_AND_ATTRIBUTES RestrictedSids; - DWORD PrivilegeCount; - DWORD PrivilegeLength; - PLUID_AND_ATTRIBUTES Privileges; - LUID AuthenticationId; - } TOKEN_GROUPS_AND_PRIVILEGES,*PTOKEN_GROUPS_AND_PRIVILEGES; - -#define TOKEN_AUDIT_SUCCESS_INCLUDE 0x1 -#define TOKEN_AUDIT_SUCCESS_EXCLUDE 0x2 -#define TOKEN_AUDIT_FAILURE_INCLUDE 0x4 -#define TOKEN_AUDIT_FAILURE_EXCLUDE 0x8 - -#define VALID_AUDIT_POLICY_BITS (TOKEN_AUDIT_SUCCESS_INCLUDE | TOKEN_AUDIT_SUCCESS_EXCLUDE | TOKEN_AUDIT_FAILURE_INCLUDE | TOKEN_AUDIT_FAILURE_EXCLUDE) -#define VALID_TOKEN_AUDIT_POLICY_ELEMENT(P) ((((P).PolicyMask & ~VALID_AUDIT_POLICY_BITS)==0) && ((P).Category <= AuditEventMaxType)) - - typedef struct _TOKEN_AUDIT_POLICY_ELEMENT { - DWORD Category; - DWORD PolicyMask; - } TOKEN_AUDIT_POLICY_ELEMENT,*PTOKEN_AUDIT_POLICY_ELEMENT; - - typedef struct _TOKEN_AUDIT_POLICY { - DWORD PolicyCount; - TOKEN_AUDIT_POLICY_ELEMENT Policy[ANYSIZE_ARRAY]; - } TOKEN_AUDIT_POLICY,*PTOKEN_AUDIT_POLICY; - -#define PER_USER_AUDITING_POLICY_SIZE(p) (sizeof(TOKEN_AUDIT_POLICY) + (((p)->PolicyCount > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((p)->PolicyCount - ANYSIZE_ARRAY)) : 0)) -#define PER_USER_AUDITING_POLICY_SIZE_BY_COUNT(C) (sizeof(TOKEN_AUDIT_POLICY) + (((C) > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((C) - ANYSIZE_ARRAY)) : 0)) - -#define TOKEN_SOURCE_LENGTH 8 - - typedef struct _TOKEN_SOURCE { - CHAR SourceName[TOKEN_SOURCE_LENGTH]; - LUID SourceIdentifier; - } TOKEN_SOURCE,*PTOKEN_SOURCE; - - typedef struct _TOKEN_STATISTICS { - LUID TokenId; - LUID AuthenticationId; - LARGE_INTEGER ExpirationTime; - TOKEN_TYPE TokenType; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - DWORD DynamicCharged; - DWORD DynamicAvailable; - DWORD GroupCount; - DWORD PrivilegeCount; - LUID ModifiedId; - } TOKEN_STATISTICS,*PTOKEN_STATISTICS; - - typedef struct _TOKEN_CONTROL { - LUID TokenId; - LUID AuthenticationId; - LUID ModifiedId; - TOKEN_SOURCE TokenSource; - } TOKEN_CONTROL,*PTOKEN_CONTROL; - - typedef struct _TOKEN_ORIGIN { - LUID OriginatingLogonSession; - } TOKEN_ORIGIN,*PTOKEN_ORIGIN; - -#define SECURITY_DYNAMIC_TRACKING (TRUE) -#define SECURITY_STATIC_TRACKING (FALSE) - - typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE,*PSECURITY_CONTEXT_TRACKING_MODE; - - typedef struct _SECURITY_QUALITY_OF_SERVICE { - DWORD Length; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode; - BOOLEAN EffectiveOnly; - } SECURITY_QUALITY_OF_SERVICE,*PSECURITY_QUALITY_OF_SERVICE; - - typedef struct _SE_IMPERSONATION_STATE { - PACCESS_TOKEN Token; - BOOLEAN CopyOnOpen; - BOOLEAN EffectiveOnly; - SECURITY_IMPERSONATION_LEVEL Level; - } SE_IMPERSONATION_STATE,*PSE_IMPERSONATION_STATE; - -#define DISABLE_MAX_PRIVILEGE 0x1 -#define SANDBOX_INERT 0x2 - - typedef DWORD SECURITY_INFORMATION,*PSECURITY_INFORMATION; - -#define OWNER_SECURITY_INFORMATION (0x00000001L) -#define GROUP_SECURITY_INFORMATION (0x00000002L) -#define DACL_SECURITY_INFORMATION (0x00000004L) -#define SACL_SECURITY_INFORMATION (0x00000008L) - -#define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L) -#define PROTECTED_SACL_SECURITY_INFORMATION (0x40000000L) -#define UNPROTECTED_DACL_SECURITY_INFORMATION (0x20000000L) -#define UNPROTECTED_SACL_SECURITY_INFORMATION (0x10000000L) - -#define PROCESS_TERMINATE (0x0001) -#define PROCESS_CREATE_THREAD (0x0002) -#define PROCESS_SET_SESSIONID (0x0004) -#define PROCESS_VM_OPERATION (0x0008) -#define PROCESS_VM_READ (0x0010) -#define PROCESS_VM_WRITE (0x0020) -#define PROCESS_DUP_HANDLE (0x0040) -#define PROCESS_CREATE_PROCESS (0x0080) -#define PROCESS_SET_QUOTA (0x0100) -#define PROCESS_SET_INFORMATION (0x0200) -#define PROCESS_QUERY_INFORMATION (0x0400) -#define PROCESS_SUSPEND_RESUME (0x0800) -#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF) - -#ifdef _WIN64 -#define MAXIMUM_PROCESSORS 64 -#else -#define MAXIMUM_PROCESSORS 32 -#endif - -#define THREAD_TERMINATE (0x0001) -#define THREAD_SUSPEND_RESUME (0x0002) -#define THREAD_GET_CONTEXT (0x0008) -#define THREAD_SET_CONTEXT (0x0010) -#define THREAD_SET_INFORMATION (0x0020) -#define THREAD_QUERY_INFORMATION (0x0040) -#define THREAD_SET_THREAD_TOKEN (0x0080) -#define THREAD_IMPERSONATE (0x0100) -#define THREAD_DIRECT_IMPERSONATION (0x0200) - -#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF) - -#define JOB_OBJECT_ASSIGN_PROCESS (0x0001) -#define JOB_OBJECT_SET_ATTRIBUTES (0x0002) -#define JOB_OBJECT_QUERY (0x0004) -#define JOB_OBJECT_TERMINATE (0x0008) -#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010) -#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1F) - - typedef struct _JOB_SET_ARRAY { - HANDLE JobHandle; - DWORD MemberLevel; - DWORD Flags; - } JOB_SET_ARRAY,*PJOB_SET_ARRAY; - -#define FLS_MAXIMUM_AVAILABLE 128 -#define TLS_MINIMUM_AVAILABLE 64 - -#ifndef _NT_TIB_DEFINED -#define _NT_TIB_DEFINED - typedef struct _NT_TIB { - struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; - PVOID StackBase; - PVOID StackLimit; - PVOID SubSystemTib; - union { - PVOID FiberData; - DWORD Version; - }; - PVOID ArbitraryUserPointer; - struct _NT_TIB *Self; - } NT_TIB; - typedef NT_TIB *PNT_TIB; -#endif - - typedef struct _NT_TIB32 { - DWORD ExceptionList; - DWORD StackBase; - DWORD StackLimit; - DWORD SubSystemTib; - union { - DWORD FiberData; - DWORD Version; - }; - DWORD ArbitraryUserPointer; - DWORD Self; - } NT_TIB32,*PNT_TIB32; - - typedef struct _NT_TIB64 { - DWORD64 ExceptionList; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD64 SubSystemTib; - union { - DWORD64 FiberData; - DWORD Version; - }; - DWORD64 ArbitraryUserPointer; - DWORD64 Self; - } NT_TIB64,*PNT_TIB64; - -#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) -#define WX86 -#endif - -#define THREAD_BASE_PRIORITY_LOWRT 15 -#define THREAD_BASE_PRIORITY_MAX 2 -#define THREAD_BASE_PRIORITY_MIN (-2) -#define THREAD_BASE_PRIORITY_IDLE (-15) - - typedef struct _QUOTA_LIMITS { - SIZE_T PagedPoolLimit; - SIZE_T NonPagedPoolLimit; - SIZE_T MinimumWorkingSetSize; - SIZE_T MaximumWorkingSetSize; - SIZE_T PagefileLimit; - LARGE_INTEGER TimeLimit; - } QUOTA_LIMITS,*PQUOTA_LIMITS; - -#define QUOTA_LIMITS_HARDWS_MIN_ENABLE 0x00000001 -#define QUOTA_LIMITS_HARDWS_MIN_DISABLE 0x00000002 -#define QUOTA_LIMITS_HARDWS_MAX_ENABLE 0x00000004 -#define QUOTA_LIMITS_HARDWS_MAX_DISABLE 0x00000008 - - typedef struct _QUOTA_LIMITS_EX { - SIZE_T PagedPoolLimit; - SIZE_T NonPagedPoolLimit; - SIZE_T MinimumWorkingSetSize; - SIZE_T MaximumWorkingSetSize; - SIZE_T PagefileLimit; - LARGE_INTEGER TimeLimit; - SIZE_T Reserved1; - SIZE_T Reserved2; - SIZE_T Reserved3; - SIZE_T Reserved4; - DWORD Flags; - DWORD Reserved5; - } QUOTA_LIMITS_EX,*PQUOTA_LIMITS_EX; - - typedef struct _IO_COUNTERS { - ULONGLONG ReadOperationCount; - ULONGLONG WriteOperationCount; - ULONGLONG OtherOperationCount; - ULONGLONG ReadTransferCount; - ULONGLONG WriteTransferCount; - ULONGLONG OtherTransferCount; - } IO_COUNTERS; - typedef IO_COUNTERS *PIO_COUNTERS; - - typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION { - LARGE_INTEGER TotalUserTime; - LARGE_INTEGER TotalKernelTime; - LARGE_INTEGER ThisPeriodTotalUserTime; - LARGE_INTEGER ThisPeriodTotalKernelTime; - DWORD TotalPageFaultCount; - DWORD TotalProcesses; - DWORD ActiveProcesses; - DWORD TotalTerminatedProcesses; - } JOBOBJECT_BASIC_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION; - - typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION { - LARGE_INTEGER PerProcessUserTimeLimit; - LARGE_INTEGER PerJobUserTimeLimit; - DWORD LimitFlags; - SIZE_T MinimumWorkingSetSize; - SIZE_T MaximumWorkingSetSize; - DWORD ActiveProcessLimit; - ULONG_PTR Affinity; - DWORD PriorityClass; - DWORD SchedulingClass; - } JOBOBJECT_BASIC_LIMIT_INFORMATION,*PJOBOBJECT_BASIC_LIMIT_INFORMATION; - - typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION { - JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; - IO_COUNTERS IoInfo; - SIZE_T ProcessMemoryLimit; - SIZE_T JobMemoryLimit; - SIZE_T PeakProcessMemoryUsed; - SIZE_T PeakJobMemoryUsed; - } JOBOBJECT_EXTENDED_LIMIT_INFORMATION,*PJOBOBJECT_EXTENDED_LIMIT_INFORMATION; - - typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST { - DWORD NumberOfAssignedProcesses; - DWORD NumberOfProcessIdsInList; - ULONG_PTR ProcessIdList[1]; - } JOBOBJECT_BASIC_PROCESS_ID_LIST,*PJOBOBJECT_BASIC_PROCESS_ID_LIST; - - typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS { - DWORD UIRestrictionsClass; - } JOBOBJECT_BASIC_UI_RESTRICTIONS,*PJOBOBJECT_BASIC_UI_RESTRICTIONS; - - typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION { - DWORD SecurityLimitFlags; - HANDLE JobToken; - PTOKEN_GROUPS SidsToDisable; - PTOKEN_PRIVILEGES PrivilegesToDelete; - PTOKEN_GROUPS RestrictedSids; - } JOBOBJECT_SECURITY_LIMIT_INFORMATION,*PJOBOBJECT_SECURITY_LIMIT_INFORMATION; - - typedef struct _JOBOBJECT_END_OF_JOB_TIME_INFORMATION { - DWORD EndOfJobTimeAction; - } JOBOBJECT_END_OF_JOB_TIME_INFORMATION,*PJOBOBJECT_END_OF_JOB_TIME_INFORMATION; - - typedef struct _JOBOBJECT_ASSOCIATE_COMPLETION_PORT { - PVOID CompletionKey; - HANDLE CompletionPort; - } JOBOBJECT_ASSOCIATE_COMPLETION_PORT,*PJOBOBJECT_ASSOCIATE_COMPLETION_PORT; - - typedef struct _JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION { - JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo; - IO_COUNTERS IoInfo; - } JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION; - - typedef struct _JOBOBJECT_JOBSET_INFORMATION { - DWORD MemberLevel; - } JOBOBJECT_JOBSET_INFORMATION,*PJOBOBJECT_JOBSET_INFORMATION; - -#define JOB_OBJECT_TERMINATE_AT_END_OF_JOB 0 -#define JOB_OBJECT_POST_AT_END_OF_JOB 1 - -#define JOB_OBJECT_MSG_END_OF_JOB_TIME 1 -#define JOB_OBJECT_MSG_END_OF_PROCESS_TIME 2 -#define JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT 3 -#define JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO 4 -#define JOB_OBJECT_MSG_NEW_PROCESS 6 -#define JOB_OBJECT_MSG_EXIT_PROCESS 7 -#define JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS 8 -#define JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT 9 -#define JOB_OBJECT_MSG_JOB_MEMORY_LIMIT 10 - -#define JOB_OBJECT_LIMIT_WORKINGSET 0x00000001 -#define JOB_OBJECT_LIMIT_PROCESS_TIME 0x00000002 -#define JOB_OBJECT_LIMIT_JOB_TIME 0x00000004 -#define JOB_OBJECT_LIMIT_ACTIVE_PROCESS 0x00000008 -#define JOB_OBJECT_LIMIT_AFFINITY 0x00000010 -#define JOB_OBJECT_LIMIT_PRIORITY_CLASS 0x00000020 -#define JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME 0x00000040 -#define JOB_OBJECT_LIMIT_SCHEDULING_CLASS 0x00000080 - -#define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100 -#define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200 -#define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400 -#define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800 -#define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000 -#define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 - -#define JOB_OBJECT_LIMIT_RESERVED2 0x00004000 -#define JOB_OBJECT_LIMIT_RESERVED3 0x00008000 -#define JOB_OBJECT_LIMIT_RESERVED4 0x00010000 -#define JOB_OBJECT_LIMIT_RESERVED5 0x00020000 -#define JOB_OBJECT_LIMIT_RESERVED6 0x00040000 - -#define JOB_OBJECT_LIMIT_VALID_FLAGS 0x0007ffff - -#define JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS 0x000000ff -#define JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS 0x00003fff -#define JOB_OBJECT_RESERVED_LIMIT_VALID_FLAGS 0x0007ffff - -#define JOB_OBJECT_UILIMIT_NONE 0x00000000 - -#define JOB_OBJECT_UILIMIT_HANDLES 0x00000001 -#define JOB_OBJECT_UILIMIT_READCLIPBOARD 0x00000002 -#define JOB_OBJECT_UILIMIT_WRITECLIPBOARD 0x00000004 -#define JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS 0x00000008 -#define JOB_OBJECT_UILIMIT_DISPLAYSETTINGS 0x00000010 -#define JOB_OBJECT_UILIMIT_GLOBALATOMS 0x00000020 -#define JOB_OBJECT_UILIMIT_DESKTOP 0x00000040 -#define JOB_OBJECT_UILIMIT_EXITWINDOWS 0x00000080 - -#define JOB_OBJECT_UILIMIT_ALL 0x000000FF - -#define JOB_OBJECT_UI_VALID_FLAGS 0x000000FF - -#define JOB_OBJECT_SECURITY_NO_ADMIN 0x00000001 -#define JOB_OBJECT_SECURITY_RESTRICTED_TOKEN 0x00000002 -#define JOB_OBJECT_SECURITY_ONLY_TOKEN 0x00000004 -#define JOB_OBJECT_SECURITY_FILTER_TOKENS 0x00000008 - -#define JOB_OBJECT_SECURITY_VALID_FLAGS 0x0000000f - - typedef enum _JOBOBJECTINFOCLASS { - JobObjectBasicAccountingInformation = 1,JobObjectBasicLimitInformation,JobObjectBasicProcessIdList,JobObjectBasicUIRestrictions, - JobObjectSecurityLimitInformation,JobObjectEndOfJobTimeInformation,JobObjectAssociateCompletionPortInformation, - JobObjectBasicAndIoAccountingInformation,JobObjectExtendedLimitInformation,JobObjectJobSetInformation,MaxJobObjectInfoClass - } JOBOBJECTINFOCLASS; - -#define EVENT_MODIFY_STATE 0x0002 -#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) - -#define MUTANT_QUERY_STATE 0x0001 - -#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| MUTANT_QUERY_STATE) -#define SEMAPHORE_MODIFY_STATE 0x0002 -#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) - -#define TIMER_QUERY_STATE 0x0001 -#define TIMER_MODIFY_STATE 0x0002 - -#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| TIMER_QUERY_STATE|TIMER_MODIFY_STATE) - -#define TIME_ZONE_ID_UNKNOWN 0 -#define TIME_ZONE_ID_STANDARD 1 -#define TIME_ZONE_ID_DAYLIGHT 2 - - typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { - RelationProcessorCore,RelationNumaNode,RelationCache - } LOGICAL_PROCESSOR_RELATIONSHIP; - -#define LTP_PC_SMT 0x1 - - typedef enum _PROCESSOR_CACHE_TYPE { - CacheUnified,CacheInstruction,CacheData,CacheTrace - } PROCESSOR_CACHE_TYPE; - -#define CACHE_FULLY_ASSOCIATIVE 0xFF - - typedef struct _CACHE_DESCRIPTOR { - BYTE Level; - BYTE Associativity; - WORD LineSize; - DWORD Size; - PROCESSOR_CACHE_TYPE Type; - } CACHE_DESCRIPTOR,*PCACHE_DESCRIPTOR; - - typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { - ULONG_PTR ProcessorMask; - LOGICAL_PROCESSOR_RELATIONSHIP Relationship; - union { - struct { - BYTE Flags; - } ProcessorCore; - struct { - DWORD NodeNumber; - } NumaNode; - CACHE_DESCRIPTOR Cache; - ULONGLONG Reserved[2]; - }; - } SYSTEM_LOGICAL_PROCESSOR_INFORMATION,*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; - -#define PROCESSOR_INTEL_386 386 -#define PROCESSOR_INTEL_486 486 -#define PROCESSOR_INTEL_PENTIUM 586 -#define PROCESSOR_INTEL_IA64 2200 -#define PROCESSOR_AMD_X8664 8664 -#define PROCESSOR_MIPS_R4000 4000 -#define PROCESSOR_ALPHA_21064 21064 -#define PROCESSOR_PPC_601 601 -#define PROCESSOR_PPC_603 603 -#define PROCESSOR_PPC_604 604 -#define PROCESSOR_PPC_620 620 -#define PROCESSOR_HITACHI_SH3 10003 -#define PROCESSOR_HITACHI_SH3E 10004 -#define PROCESSOR_HITACHI_SH4 10005 -#define PROCESSOR_MOTOROLA_821 821 -#define PROCESSOR_SHx_SH3 103 -#define PROCESSOR_SHx_SH4 104 -#define PROCESSOR_STRONGARM 2577 -#define PROCESSOR_ARM720 1824 -#define PROCESSOR_ARM820 2080 -#define PROCESSOR_ARM920 2336 -#define PROCESSOR_ARM_7TDMI 70001 -#define PROCESSOR_OPTIL 0x494f - -#define PROCESSOR_ARCHITECTURE_INTEL 0 -#define PROCESSOR_ARCHITECTURE_MIPS 1 -#define PROCESSOR_ARCHITECTURE_ALPHA 2 -#define PROCESSOR_ARCHITECTURE_PPC 3 -#define PROCESSOR_ARCHITECTURE_SHX 4 -#define PROCESSOR_ARCHITECTURE_ARM 5 -#define PROCESSOR_ARCHITECTURE_IA64 6 -#define PROCESSOR_ARCHITECTURE_ALPHA64 7 -#define PROCESSOR_ARCHITECTURE_MSIL 8 -#define PROCESSOR_ARCHITECTURE_AMD64 9 -#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 - -#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF - -#define PF_FLOATING_POINT_PRECISION_ERRATA 0 -#define PF_FLOATING_POINT_EMULATED 1 -#define PF_COMPARE_EXCHANGE_DOUBLE 2 -#define PF_MMX_INSTRUCTIONS_AVAILABLE 3 -#define PF_PPC_MOVEMEM_64BIT_OK 4 -#define PF_ALPHA_BYTE_INSTRUCTIONS 5 -#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6 -#define PF_3DNOW_INSTRUCTIONS_AVAILABLE 7 -#define PF_RDTSC_INSTRUCTION_AVAILABLE 8 -#define PF_PAE_ENABLED 9 -#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10 -#define PF_SSE_DAZ_MODE_AVAILABLE 11 -#define PF_NX_ENABLED 12 - - typedef struct _MEMORY_BASIC_INFORMATION { - PVOID BaseAddress; - PVOID AllocationBase; - DWORD AllocationProtect; - SIZE_T RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; - } MEMORY_BASIC_INFORMATION,*PMEMORY_BASIC_INFORMATION; - - typedef struct _MEMORY_BASIC_INFORMATION32 { - DWORD BaseAddress; - DWORD AllocationBase; - DWORD AllocationProtect; - DWORD RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; - } MEMORY_BASIC_INFORMATION32,*PMEMORY_BASIC_INFORMATION32; - - typedef struct DECLSPEC_ALIGN(16) _MEMORY_BASIC_INFORMATION64 { - ULONGLONG BaseAddress; - ULONGLONG AllocationBase; - DWORD AllocationProtect; - DWORD __alignment1; - ULONGLONG RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; - DWORD __alignment2; - } MEMORY_BASIC_INFORMATION64,*PMEMORY_BASIC_INFORMATION64; - -#define SECTION_QUERY 0x0001 -#define SECTION_MAP_WRITE 0x0002 -#define SECTION_MAP_READ 0x0004 -#define SECTION_MAP_EXECUTE 0x0008 -#define SECTION_EXTEND_SIZE 0x0010 -#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020 - -#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY| SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE) -#define PAGE_NOACCESS 0x01 -#define PAGE_READONLY 0x02 -#define PAGE_READWRITE 0x04 -#define PAGE_WRITECOPY 0x08 -#define PAGE_EXECUTE 0x10 -#define PAGE_EXECUTE_READ 0x20 -#define PAGE_EXECUTE_READWRITE 0x40 -#define PAGE_EXECUTE_WRITECOPY 0x80 -#define PAGE_GUARD 0x100 -#define PAGE_NOCACHE 0x200 -#define PAGE_WRITECOMBINE 0x400 -#define MEM_COMMIT 0x1000 -#define MEM_RESERVE 0x2000 -#define MEM_DECOMMIT 0x4000 -#define MEM_RELEASE 0x8000 -#define MEM_FREE 0x10000 -#define MEM_PRIVATE 0x20000 -#define MEM_MAPPED 0x40000 -#define MEM_RESET 0x80000 -#define MEM_TOP_DOWN 0x100000 -#define MEM_WRITE_WATCH 0x200000 -#define MEM_PHYSICAL 0x400000 -#define MEM_LARGE_PAGES 0x20000000 -#define MEM_4MB_PAGES 0x80000000 -#define SEC_FILE 0x800000 -#define SEC_IMAGE 0x1000000 -#define SEC_RESERVE 0x4000000 -#define SEC_COMMIT 0x8000000 -#define SEC_NOCACHE 0x10000000 -#define SEC_LARGE_PAGES 0x80000000 -#define MEM_IMAGE SEC_IMAGE -#define WRITE_WATCH_FLAG_RESET 0x01 - -#define FILE_READ_DATA (0x0001) -#define FILE_LIST_DIRECTORY (0x0001) - -#define FILE_WRITE_DATA (0x0002) -#define FILE_ADD_FILE (0x0002) - -#define FILE_APPEND_DATA (0x0004) -#define FILE_ADD_SUBDIRECTORY (0x0004) -#define FILE_CREATE_PIPE_INSTANCE (0x0004) - -#define FILE_READ_EA (0x0008) - -#define FILE_WRITE_EA (0x0010) - -#define FILE_EXECUTE (0x0020) -#define FILE_TRAVERSE (0x0020) - -#define FILE_DELETE_CHILD (0x0040) - -#define FILE_READ_ATTRIBUTES (0x0080) - -#define FILE_WRITE_ATTRIBUTES (0x0100) - -#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) -#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE) -#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE) -#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE) - -#define FILE_SHARE_READ 0x00000001 -#define FILE_SHARE_WRITE 0x00000002 -#define FILE_SHARE_DELETE 0x00000004 -#define FILE_ATTRIBUTE_READONLY 0x00000001 -#define FILE_ATTRIBUTE_HIDDEN 0x00000002 -#define FILE_ATTRIBUTE_SYSTEM 0x00000004 -#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 -#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 -#define FILE_ATTRIBUTE_DEVICE 0x00000040 -#define FILE_ATTRIBUTE_NORMAL 0x00000080 -#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 -#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 -#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 -#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 -#define FILE_ATTRIBUTE_OFFLINE 0x00001000 -#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 -#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 -#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 -#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 -#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 -#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 -#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 -#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 -#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 -#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 -#define FILE_ACTION_ADDED 0x00000001 -#define FILE_ACTION_REMOVED 0x00000002 -#define FILE_ACTION_MODIFIED 0x00000003 -#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 -#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 -#define MAILSLOT_NO_MESSAGE ((DWORD)-1) -#define MAILSLOT_WAIT_FOREVER ((DWORD)-1) -#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 -#define FILE_CASE_PRESERVED_NAMES 0x00000002 -#define FILE_UNICODE_ON_DISK 0x00000004 -#define FILE_PERSISTENT_ACLS 0x00000008 -#define FILE_FILE_COMPRESSION 0x00000010 -#define FILE_VOLUME_QUOTAS 0x00000020 -#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 -#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 -#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 -#define FILE_VOLUME_IS_COMPRESSED 0x00008000 -#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 -#define FILE_SUPPORTS_ENCRYPTION 0x00020000 -#define FILE_NAMED_STREAMS 0x00040000 -#define FILE_READ_ONLY_VOLUME 0x00080000 - - typedef struct _FILE_NOTIFY_INFORMATION { - DWORD NextEntryOffset; - DWORD Action; - DWORD FileNameLength; - WCHAR FileName[1]; - } FILE_NOTIFY_INFORMATION,*PFILE_NOTIFY_INFORMATION; - - typedef union _FILE_SEGMENT_ELEMENT { - PVOID64 Buffer; - ULONGLONG Alignment; - }FILE_SEGMENT_ELEMENT,*PFILE_SEGMENT_ELEMENT; - - typedef struct _REPARSE_GUID_DATA_BUFFER { - DWORD ReparseTag; - WORD ReparseDataLength; - WORD Reserved; - GUID ReparseGuid; - struct { - BYTE DataBuffer[1]; - } GenericReparseBuffer; - } REPARSE_GUID_DATA_BUFFER,*PREPARSE_GUID_DATA_BUFFER; - -#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER,GenericReparseBuffer) - -#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 *1024) - -#define IO_REPARSE_TAG_RESERVED_ZERO (0) -#define IO_REPARSE_TAG_RESERVED_ONE (1) - -#define IO_REPARSE_TAG_RESERVED_RANGE IO_REPARSE_TAG_RESERVED_ONE - -#define IsReparseTagMicrosoft(_tag) (((_tag) & 0x80000000)) -#define IsReparseTagNameSurrogate(_tag) (((_tag) & 0x20000000)) - -#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) -#define IO_REPARSE_TAG_HSM (0xC0000004L) -#define IO_REPARSE_TAG_SIS (0x80000007L) -#define IO_REPARSE_TAG_DFS (0x8000000AL) -#define IO_REPARSE_TAG_FILTER_MANAGER (0x8000000BL) -#define IO_COMPLETION_MODIFY_STATE 0x0002 -#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) -#define DUPLICATE_CLOSE_SOURCE 0x00000001 -#define DUPLICATE_SAME_ACCESS 0x00000002 - - typedef enum _SYSTEM_POWER_STATE { - PowerSystemUnspecified = 0,PowerSystemWorking = 1,PowerSystemSleeping1 = 2,PowerSystemSleeping2 = 3,PowerSystemSleeping3 = 4,PowerSystemHibernate = 5,PowerSystemShutdown = 6,PowerSystemMaximum = 7 - } SYSTEM_POWER_STATE,*PSYSTEM_POWER_STATE; - -#define POWER_SYSTEM_MAXIMUM 7 - - typedef enum { - PowerActionNone = 0,PowerActionReserved,PowerActionSleep,PowerActionHibernate,PowerActionShutdown,PowerActionShutdownReset,PowerActionShutdownOff,PowerActionWarmEject - } POWER_ACTION,*PPOWER_ACTION; - - typedef enum _DEVICE_POWER_STATE { - PowerDeviceUnspecified = 0,PowerDeviceD0,PowerDeviceD1,PowerDeviceD2,PowerDeviceD3,PowerDeviceMaximum - } DEVICE_POWER_STATE,*PDEVICE_POWER_STATE; - -#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001) -#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002) -#define ES_USER_PRESENT ((DWORD)0x00000004) -#define ES_CONTINUOUS ((DWORD)0x80000000) - - typedef DWORD EXECUTION_STATE; - - typedef enum { - LT_DONT_CARE,LT_LOWEST_LATENCY - } LATENCY_TIME; - -#define PDCAP_D0_SUPPORTED 0x00000001 -#define PDCAP_D1_SUPPORTED 0x00000002 -#define PDCAP_D2_SUPPORTED 0x00000004 -#define PDCAP_D3_SUPPORTED 0x00000008 -#define PDCAP_WAKE_FROM_D0_SUPPORTED 0x00000010 -#define PDCAP_WAKE_FROM_D1_SUPPORTED 0x00000020 -#define PDCAP_WAKE_FROM_D2_SUPPORTED 0x00000040 -#define PDCAP_WAKE_FROM_D3_SUPPORTED 0x00000080 -#define PDCAP_WARM_EJECT_SUPPORTED 0x00000100 - - typedef struct CM_Power_Data_s { - DWORD PD_Size; - DEVICE_POWER_STATE PD_MostRecentPowerState; - DWORD PD_Capabilities; - DWORD PD_D1Latency; - DWORD PD_D2Latency; - DWORD PD_D3Latency; - DEVICE_POWER_STATE PD_PowerStateMapping[POWER_SYSTEM_MAXIMUM]; - SYSTEM_POWER_STATE PD_DeepestSystemWake; - } CM_POWER_DATA,*PCM_POWER_DATA; - - typedef enum { - SystemPowerPolicyAc,SystemPowerPolicyDc,VerifySystemPolicyAc,VerifySystemPolicyDc,SystemPowerCapabilities,SystemBatteryState,SystemPowerStateHandler,ProcessorStateHandler,SystemPowerPolicyCurrent,AdministratorPowerPolicy,SystemReserveHiberFile,ProcessorInformation,SystemPowerInformation,ProcessorStateHandler2,LastWakeTime,LastSleepTime,SystemExecutionState,SystemPowerStateNotifyHandler,ProcessorPowerPolicyAc,ProcessorPowerPolicyDc,VerifyProcessorPowerPolicyAc,VerifyProcessorPowerPolicyDc,ProcessorPowerPolicyCurrent,SystemPowerStateLogging,SystemPowerLoggingEntry - } POWER_INFORMATION_LEVEL; - - typedef struct { - DWORD Granularity; - DWORD Capacity; - } BATTERY_REPORTING_SCALE,*PBATTERY_REPORTING_SCALE; - - typedef struct { - POWER_ACTION Action; - DWORD Flags; - DWORD EventCode; - } POWER_ACTION_POLICY,*PPOWER_ACTION_POLICY; - -#define POWER_ACTION_QUERY_ALLOWED 0x00000001 -#define POWER_ACTION_UI_ALLOWED 0x00000002 -#define POWER_ACTION_OVERRIDE_APPS 0x00000004 -#define POWER_ACTION_LIGHTEST_FIRST 0x10000000 -#define POWER_ACTION_LOCK_CONSOLE 0x20000000 -#define POWER_ACTION_DISABLE_WAKES 0x40000000 -#define POWER_ACTION_CRITICAL 0x80000000 - -#define POWER_LEVEL_USER_NOTIFY_TEXT 0x00000001 -#define POWER_LEVEL_USER_NOTIFY_SOUND 0x00000002 -#define POWER_LEVEL_USER_NOTIFY_EXEC 0x00000004 -#define POWER_USER_NOTIFY_BUTTON 0x00000008 -#define POWER_USER_NOTIFY_SHUTDOWN 0x00000010 -#define POWER_FORCE_TRIGGER_RESET 0x80000000 - - typedef struct { - BOOLEAN Enable; - BYTE Spare[3]; - DWORD BatteryLevel; - POWER_ACTION_POLICY PowerPolicy; - SYSTEM_POWER_STATE MinSystemState; - } SYSTEM_POWER_LEVEL,*PSYSTEM_POWER_LEVEL; - -#define NUM_DISCHARGE_POLICIES 4 -#define DISCHARGE_POLICY_CRITICAL 0 -#define DISCHARGE_POLICY_LOW 1 - -#define PO_THROTTLE_NONE 0 -#define PO_THROTTLE_CONSTANT 1 -#define PO_THROTTLE_DEGRADE 2 -#define PO_THROTTLE_ADAPTIVE 3 -#define PO_THROTTLE_MAXIMUM 4 - - typedef struct _SYSTEM_POWER_POLICY { - DWORD Revision; - POWER_ACTION_POLICY PowerButton; - POWER_ACTION_POLICY SleepButton; - POWER_ACTION_POLICY LidClose; - SYSTEM_POWER_STATE LidOpenWake; - DWORD Reserved; - POWER_ACTION_POLICY Idle; - DWORD IdleTimeout; - BYTE IdleSensitivity; - BYTE DynamicThrottle; - BYTE Spare2[2]; - SYSTEM_POWER_STATE MinSleep; - SYSTEM_POWER_STATE MaxSleep; - SYSTEM_POWER_STATE ReducedLatencySleep; - DWORD WinLogonFlags; - DWORD Spare3; - DWORD DozeS4Timeout; - DWORD BroadcastCapacityResolution; - SYSTEM_POWER_LEVEL DischargePolicy[NUM_DISCHARGE_POLICIES]; - DWORD VideoTimeout; - BOOLEAN VideoDimDisplay; - DWORD VideoReserved[3]; - DWORD SpindownTimeout; - BOOLEAN OptimizeForPower; - BYTE FanThrottleTolerance; - BYTE ForcedThrottle; - BYTE MinThrottle; - POWER_ACTION_POLICY OverThrottled; - } SYSTEM_POWER_POLICY,*PSYSTEM_POWER_POLICY; - - typedef struct _PROCESSOR_POWER_POLICY_INFO { - DWORD TimeCheck; - DWORD DemoteLimit; - DWORD PromoteLimit; - BYTE DemotePercent; - BYTE PromotePercent; - BYTE Spare[2]; - DWORD AllowDemotion:1; - DWORD AllowPromotion:1; - DWORD Reserved:30; - } PROCESSOR_POWER_POLICY_INFO,*PPROCESSOR_POWER_POLICY_INFO; - - typedef struct _PROCESSOR_POWER_POLICY { - DWORD Revision; - BYTE DynamicThrottle; - BYTE Spare[3]; - DWORD DisableCStates:1; - DWORD Reserved:31; - DWORD PolicyCount; - PROCESSOR_POWER_POLICY_INFO Policy[3]; - } PROCESSOR_POWER_POLICY,*PPROCESSOR_POWER_POLICY; - - typedef struct _ADMINISTRATOR_POWER_POLICY { - SYSTEM_POWER_STATE MinSleep; - SYSTEM_POWER_STATE MaxSleep; - DWORD MinVideoTimeout; - DWORD MaxVideoTimeout; - DWORD MinSpindownTimeout; - DWORD MaxSpindownTimeout; - } ADMINISTRATOR_POWER_POLICY,*PADMINISTRATOR_POWER_POLICY; - - typedef struct { - BOOLEAN PowerButtonPresent; - BOOLEAN SleepButtonPresent; - BOOLEAN LidPresent; - BOOLEAN SystemS1; - BOOLEAN SystemS2; - BOOLEAN SystemS3; - BOOLEAN SystemS4; - BOOLEAN SystemS5; - BOOLEAN HiberFilePresent; - BOOLEAN FullWake; - BOOLEAN VideoDimPresent; - BOOLEAN ApmPresent; - BOOLEAN UpsPresent; - BOOLEAN ThermalControl; - BOOLEAN ProcessorThrottle; - BYTE ProcessorMinThrottle; - BYTE ProcessorMaxThrottle; - BYTE spare2[4]; - BOOLEAN DiskSpinDown; - BYTE spare3[8]; - BOOLEAN SystemBatteriesPresent; - BOOLEAN BatteriesAreShortTerm; - BATTERY_REPORTING_SCALE BatteryScale[3]; - SYSTEM_POWER_STATE AcOnLineWake; - SYSTEM_POWER_STATE SoftLidWake; - SYSTEM_POWER_STATE RtcWake; - SYSTEM_POWER_STATE MinDeviceWakeState; - SYSTEM_POWER_STATE DefaultLowLatencyWake; - } SYSTEM_POWER_CAPABILITIES,*PSYSTEM_POWER_CAPABILITIES; - - typedef struct { - BOOLEAN AcOnLine; - BOOLEAN BatteryPresent; - BOOLEAN Charging; - BOOLEAN Discharging; - BOOLEAN Spare1[4]; - DWORD MaxCapacity; - DWORD RemainingCapacity; - DWORD Rate; - DWORD EstimatedTime; - DWORD DefaultAlert1; - DWORD DefaultAlert2; - } SYSTEM_BATTERY_STATE,*PSYSTEM_BATTERY_STATE; - -#include "pshpack4.h" - -#define IMAGE_DOS_SIGNATURE 0x5A4D -#define IMAGE_OS2_SIGNATURE 0x454E -#define IMAGE_OS2_SIGNATURE_LE 0x454C -#define IMAGE_VXD_SIGNATURE 0x454C -#define IMAGE_NT_SIGNATURE 0x00004550 - -#include "pshpack2.h" - - typedef struct _IMAGE_DOS_HEADER { - WORD e_magic; - WORD e_cblp; - WORD e_cp; - WORD e_crlc; - WORD e_cparhdr; - WORD e_minalloc; - WORD e_maxalloc; - WORD e_ss; - WORD e_sp; - WORD e_csum; - WORD e_ip; - WORD e_cs; - WORD e_lfarlc; - WORD e_ovno; - WORD e_res[4]; - WORD e_oemid; - WORD e_oeminfo; - WORD e_res2[10]; - LONG e_lfanew; - } IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER; - - typedef struct _IMAGE_OS2_HEADER { - WORD ne_magic; - CHAR ne_ver; - CHAR ne_rev; - WORD ne_enttab; - WORD ne_cbenttab; - LONG ne_crc; - WORD ne_flags; - WORD ne_autodata; - WORD ne_heap; - WORD ne_stack; - LONG ne_csip; - LONG ne_sssp; - WORD ne_cseg; - WORD ne_cmod; - WORD ne_cbnrestab; - WORD ne_segtab; - WORD ne_rsrctab; - WORD ne_restab; - WORD ne_modtab; - WORD ne_imptab; - LONG ne_nrestab; - WORD ne_cmovent; - WORD ne_align; - WORD ne_cres; - BYTE ne_exetyp; - BYTE ne_flagsothers; - WORD ne_pretthunks; - WORD ne_psegrefbytes; - WORD ne_swaparea; - WORD ne_expver; - } IMAGE_OS2_HEADER,*PIMAGE_OS2_HEADER; - - typedef struct _IMAGE_VXD_HEADER { - WORD e32_magic; - BYTE e32_border; - BYTE e32_worder; - DWORD e32_level; - WORD e32_cpu; - WORD e32_os; - DWORD e32_ver; - DWORD e32_mflags; - DWORD e32_mpages; - DWORD e32_startobj; - DWORD e32_eip; - DWORD e32_stackobj; - DWORD e32_esp; - DWORD e32_pagesize; - DWORD e32_lastpagesize; - DWORD e32_fixupsize; - DWORD e32_fixupsum; - DWORD e32_ldrsize; - DWORD e32_ldrsum; - DWORD e32_objtab; - DWORD e32_objcnt; - DWORD e32_objmap; - DWORD e32_itermap; - DWORD e32_rsrctab; - DWORD e32_rsrccnt; - DWORD e32_restab; - DWORD e32_enttab; - DWORD e32_dirtab; - DWORD e32_dircnt; - DWORD e32_fpagetab; - DWORD e32_frectab; - DWORD e32_impmod; - DWORD e32_impmodcnt; - DWORD e32_impproc; - DWORD e32_pagesum; - DWORD e32_datapage; - DWORD e32_preload; - DWORD e32_nrestab; - DWORD e32_cbnrestab; - DWORD e32_nressum; - DWORD e32_autodata; - DWORD e32_debuginfo; - DWORD e32_debuglen; - DWORD e32_instpreload; - DWORD e32_instdemand; - DWORD e32_heapsize; - BYTE e32_res3[12]; - DWORD e32_winresoff; - DWORD e32_winreslen; - WORD e32_devid; - WORD e32_ddkver; - } IMAGE_VXD_HEADER,*PIMAGE_VXD_HEADER; - -#include "poppack.h" - - typedef struct _IMAGE_FILE_HEADER { - WORD Machine; - WORD NumberOfSections; - DWORD TimeDateStamp; - DWORD PointerToSymbolTable; - DWORD NumberOfSymbols; - WORD SizeOfOptionalHeader; - WORD Characteristics; - } IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER; - -#define IMAGE_SIZEOF_FILE_HEADER 20 - -#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 -#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 -#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 -#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 -#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 -#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 -#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 -#define IMAGE_FILE_32BIT_MACHINE 0x0100 -#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 -#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 -#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 -#define IMAGE_FILE_SYSTEM 0x1000 -#define IMAGE_FILE_DLL 0x2000 -#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 -#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 - -#define IMAGE_FILE_MACHINE_UNKNOWN 0 -#define IMAGE_FILE_MACHINE_I386 0x014c -#define IMAGE_FILE_MACHINE_R3000 0x0162 -#define IMAGE_FILE_MACHINE_R4000 0x0166 -#define IMAGE_FILE_MACHINE_R10000 0x0168 -#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 -#define IMAGE_FILE_MACHINE_ALPHA 0x0184 -#define IMAGE_FILE_MACHINE_SH3 0x01a2 -#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 -#define IMAGE_FILE_MACHINE_SH3E 0x01a4 -#define IMAGE_FILE_MACHINE_SH4 0x01a6 -#define IMAGE_FILE_MACHINE_SH5 0x01a8 -#define IMAGE_FILE_MACHINE_ARM 0x01c0 -#define IMAGE_FILE_MACHINE_THUMB 0x01c2 -#define IMAGE_FILE_MACHINE_AM33 0x01d3 -#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 -#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 -#define IMAGE_FILE_MACHINE_IA64 0x0200 -#define IMAGE_FILE_MACHINE_MIPS16 0x0266 -#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 -#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 -#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 -#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 -#define IMAGE_FILE_MACHINE_TRICORE 0x0520 -#define IMAGE_FILE_MACHINE_CEF 0x0CEF -#define IMAGE_FILE_MACHINE_EBC 0x0EBC -#define IMAGE_FILE_MACHINE_AMD64 0x8664 -#define IMAGE_FILE_MACHINE_M32R 0x9041 -#define IMAGE_FILE_MACHINE_CEE 0xC0EE - - typedef struct _IMAGE_DATA_DIRECTORY { - DWORD VirtualAddress; - DWORD Size; - } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY; - -#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 - - typedef struct _IMAGE_OPTIONAL_HEADER { - - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; - DWORD BaseOfData; - DWORD ImageBase; - DWORD SectionAlignment; - DWORD FileAlignment; - WORD MajorOperatingSystemVersion; - WORD MinorOperatingSystemVersion; - WORD MajorImageVersion; - WORD MinorImageVersion; - WORD MajorSubsystemVersion; - WORD MinorSubsystemVersion; - DWORD Win32VersionValue; - DWORD SizeOfImage; - DWORD SizeOfHeaders; - DWORD CheckSum; - WORD Subsystem; - WORD DllCharacteristics; - DWORD SizeOfStackReserve; - DWORD SizeOfStackCommit; - DWORD SizeOfHeapReserve; - DWORD SizeOfHeapCommit; - DWORD LoaderFlags; - DWORD NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - } IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32; - - typedef struct _IMAGE_ROM_OPTIONAL_HEADER { - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; - DWORD BaseOfData; - DWORD BaseOfBss; - DWORD GprMask; - DWORD CprMask[4]; - DWORD GpValue; - } IMAGE_ROM_OPTIONAL_HEADER,*PIMAGE_ROM_OPTIONAL_HEADER; - - typedef struct _IMAGE_OPTIONAL_HEADER64 { - WORD Magic; - BYTE MajorLinkerVersion; - BYTE MinorLinkerVersion; - DWORD SizeOfCode; - DWORD SizeOfInitializedData; - DWORD SizeOfUninitializedData; - DWORD AddressOfEntryPoint; - DWORD BaseOfCode; - ULONGLONG ImageBase; - DWORD SectionAlignment; - DWORD FileAlignment; - WORD MajorOperatingSystemVersion; - WORD MinorOperatingSystemVersion; - WORD MajorImageVersion; - WORD MinorImageVersion; - WORD MajorSubsystemVersion; - WORD MinorSubsystemVersion; - DWORD Win32VersionValue; - DWORD SizeOfImage; - DWORD SizeOfHeaders; - DWORD CheckSum; - WORD Subsystem; - WORD DllCharacteristics; - ULONGLONG SizeOfStackReserve; - ULONGLONG SizeOfStackCommit; - ULONGLONG SizeOfHeapReserve; - ULONGLONG SizeOfHeapCommit; - DWORD LoaderFlags; - DWORD NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - } IMAGE_OPTIONAL_HEADER64,*PIMAGE_OPTIONAL_HEADER64; - -#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 -#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 -#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224 -#define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240 - -#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b -#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b -#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 - -#ifdef _WIN64 - typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; - typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; -#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL64_HEADER -#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC -#else - typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; - typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; -#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL32_HEADER -#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC -#endif - - typedef struct _IMAGE_NT_HEADERS64 { - DWORD Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER64 OptionalHeader; - } IMAGE_NT_HEADERS64,*PIMAGE_NT_HEADERS64; - - typedef struct _IMAGE_NT_HEADERS { - DWORD Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER32 OptionalHeader; - } IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32; - - typedef struct _IMAGE_ROM_HEADERS { - IMAGE_FILE_HEADER FileHeader; - IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; - } IMAGE_ROM_HEADERS,*PIMAGE_ROM_HEADERS; - -#ifdef _WIN64 - typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; - typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; -#else - typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; - typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; -#endif - -#define IMAGE_FIRST_SECTION(ntheader) ((PIMAGE_SECTION_HEADER) ((ULONG_PTR)ntheader + FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader) + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) - -#define IMAGE_SUBSYSTEM_UNKNOWN 0 -#define IMAGE_SUBSYSTEM_NATIVE 1 -#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 -#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 -#define IMAGE_SUBSYSTEM_OS2_CUI 5 -#define IMAGE_SUBSYSTEM_POSIX_CUI 7 -#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 -#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 -#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 -#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 -#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 -#define IMAGE_SUBSYSTEM_EFI_ROM 13 -#define IMAGE_SUBSYSTEM_XBOX 14 - -#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 -#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 -#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 -#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 -#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 - -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 - -#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 -#define IMAGE_DIRECTORY_ENTRY_TLS 9 -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 -#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 -#define IMAGE_DIRECTORY_ENTRY_IAT 12 -#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 -#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 - - typedef struct ANON_OBJECT_HEADER { - WORD Sig1; - WORD Sig2; - WORD Version; - WORD Machine; - DWORD TimeDateStamp; - CLSID ClassID; - DWORD SizeOfData; - } ANON_OBJECT_HEADER; - -#define IMAGE_SIZEOF_SHORT_NAME 8 - - typedef struct _IMAGE_SECTION_HEADER { - BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; - union { - DWORD PhysicalAddress; - DWORD VirtualSize; - } Misc; - DWORD VirtualAddress; - DWORD SizeOfRawData; - DWORD PointerToRawData; - DWORD PointerToRelocations; - DWORD PointerToLinenumbers; - WORD NumberOfRelocations; - WORD NumberOfLinenumbers; - DWORD Characteristics; - } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER; - -#define IMAGE_SIZEOF_SECTION_HEADER 40 - -#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 - -#define IMAGE_SCN_CNT_CODE 0x00000020 -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 -#define IMAGE_SCN_LNK_OTHER 0x00000100 -#define IMAGE_SCN_LNK_INFO 0x00000200 -#define IMAGE_SCN_LNK_REMOVE 0x00000800 -#define IMAGE_SCN_LNK_COMDAT 0x00001000 -#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 -#define IMAGE_SCN_GPREL 0x00008000 -#define IMAGE_SCN_MEM_FARDATA 0x00008000 -#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 -#define IMAGE_SCN_MEM_16BIT 0x00020000 -#define IMAGE_SCN_MEM_LOCKED 0x00040000 -#define IMAGE_SCN_MEM_PRELOAD 0x00080000 - -#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 -#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 -#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 -#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 -#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 -#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 -#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 -#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 -#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 -#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 -#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 -#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 -#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 -#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 - -#define IMAGE_SCN_ALIGN_MASK 0x00F00000 - -#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 -#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 -#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 -#define IMAGE_SCN_MEM_SHARED 0x10000000 -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 -#define IMAGE_SCN_MEM_READ 0x40000000 -#define IMAGE_SCN_MEM_WRITE 0x80000000 - -#define IMAGE_SCN_SCALE_INDEX 0x00000001 - -#include "pshpack2.h" - - typedef struct _IMAGE_SYMBOL { - union { - BYTE ShortName[8]; - struct { - DWORD Short; - DWORD Long; - } Name; - DWORD LongName[2]; - } N; - DWORD Value; - SHORT SectionNumber; - WORD Type; - BYTE StorageClass; - BYTE NumberOfAuxSymbols; - } IMAGE_SYMBOL; - typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL; - -#define IMAGE_SIZEOF_SYMBOL 18 - -#define IMAGE_SYM_UNDEFINED (SHORT)0 -#define IMAGE_SYM_ABSOLUTE (SHORT)-1 -#define IMAGE_SYM_DEBUG (SHORT)-2 -#define IMAGE_SYM_SECTION_MAX 0xFEFF - -#define IMAGE_SYM_TYPE_NULL 0x0000 -#define IMAGE_SYM_TYPE_VOID 0x0001 -#define IMAGE_SYM_TYPE_CHAR 0x0002 -#define IMAGE_SYM_TYPE_SHORT 0x0003 -#define IMAGE_SYM_TYPE_INT 0x0004 -#define IMAGE_SYM_TYPE_LONG 0x0005 -#define IMAGE_SYM_TYPE_FLOAT 0x0006 -#define IMAGE_SYM_TYPE_DOUBLE 0x0007 -#define IMAGE_SYM_TYPE_STRUCT 0x0008 -#define IMAGE_SYM_TYPE_UNION 0x0009 -#define IMAGE_SYM_TYPE_ENUM 0x000A -#define IMAGE_SYM_TYPE_MOE 0x000B -#define IMAGE_SYM_TYPE_BYTE 0x000C -#define IMAGE_SYM_TYPE_WORD 0x000D -#define IMAGE_SYM_TYPE_UINT 0x000E -#define IMAGE_SYM_TYPE_DWORD 0x000F -#define IMAGE_SYM_TYPE_PCODE 0x8000 - -#define IMAGE_SYM_DTYPE_NULL 0 -#define IMAGE_SYM_DTYPE_POINTER 1 -#define IMAGE_SYM_DTYPE_FUNCTION 2 -#define IMAGE_SYM_DTYPE_ARRAY 3 - -#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE)-1 -#define IMAGE_SYM_CLASS_NULL 0x0000 -#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 -#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 -#define IMAGE_SYM_CLASS_STATIC 0x0003 -#define IMAGE_SYM_CLASS_REGISTER 0x0004 -#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 -#define IMAGE_SYM_CLASS_LABEL 0x0006 -#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 -#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 -#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 -#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A -#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B -#define IMAGE_SYM_CLASS_UNION_TAG 0x000C -#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D -#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E -#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F -#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 -#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 -#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 -#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 -#define IMAGE_SYM_CLASS_BLOCK 0x0064 -#define IMAGE_SYM_CLASS_FUNCTION 0x0065 -#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 -#define IMAGE_SYM_CLASS_FILE 0x0067 -#define IMAGE_SYM_CLASS_SECTION 0x0068 -#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 -#define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B - -#define N_BTMASK 0x000F -#define N_TMASK 0x0030 -#define N_TMASK1 0x00C0 -#define N_TMASK2 0x00F0 -#define N_BTSHFT 4 -#define N_TSHIFT 2 - -#define BTYPE(x) ((x) & N_BTMASK) - -#ifndef ISPTR -#define ISPTR(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) -#endif - -#ifndef ISFCN -#define ISFCN(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) -#endif - -#ifndef ISARY -#define ISARY(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) -#endif - -#ifndef ISTAG -#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) -#endif - -#ifndef INCREF -#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) -#endif - - typedef union _IMAGE_AUX_SYMBOL { - struct { - DWORD TagIndex; - union { - struct { - WORD Linenumber; - WORD Size; - } LnSz; - DWORD TotalSize; - } Misc; - union { - struct { - DWORD PointerToLinenumber; - DWORD PointerToNextFunction; - } Function; - struct { - WORD Dimension[4]; - } Array; - } FcnAry; - WORD TvIndex; - } Sym; - struct { - BYTE Name[IMAGE_SIZEOF_SYMBOL]; - } File; - struct { - DWORD Length; - WORD NumberOfRelocations; - WORD NumberOfLinenumbers; - DWORD CheckSum; - SHORT Number; - BYTE Selection; - } Section; - } IMAGE_AUX_SYMBOL; - typedef IMAGE_AUX_SYMBOL UNALIGNED *PIMAGE_AUX_SYMBOL; - -#define IMAGE_SIZEOF_AUX_SYMBOL 18 - - typedef enum IMAGE_AUX_SYMBOL_TYPE { - IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF = 1 - } IMAGE_AUX_SYMBOL_TYPE; - -#include - - typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF { - BYTE bAuxType; - BYTE bReserved; - DWORD SymbolTableIndex; - BYTE rgbReserved[12]; - } IMAGE_AUX_SYMBOL_TOKEN_DEF; - - typedef IMAGE_AUX_SYMBOL_TOKEN_DEF UNALIGNED *PIMAGE_AUX_SYMBOL_TOKEN_DEF; - -#include - -#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 -#define IMAGE_COMDAT_SELECT_ANY 2 -#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 -#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 -#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 -#define IMAGE_COMDAT_SELECT_LARGEST 6 -#define IMAGE_COMDAT_SELECT_NEWEST 7 - -#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 -#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 -#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 - - typedef struct _IMAGE_RELOCATION { - union { - DWORD VirtualAddress; - DWORD RelocCount; - }; - DWORD SymbolTableIndex; - WORD Type; - } IMAGE_RELOCATION; - typedef IMAGE_RELOCATION UNALIGNED *PIMAGE_RELOCATION; - -#define IMAGE_SIZEOF_RELOCATION 10 - -#define IMAGE_REL_I386_ABSOLUTE 0x0000 -#define IMAGE_REL_I386_DIR16 0x0001 -#define IMAGE_REL_I386_REL16 0x0002 -#define IMAGE_REL_I386_DIR32 0x0006 -#define IMAGE_REL_I386_DIR32NB 0x0007 -#define IMAGE_REL_I386_SEG12 0x0009 -#define IMAGE_REL_I386_SECTION 0x000A -#define IMAGE_REL_I386_SECREL 0x000B -#define IMAGE_REL_I386_TOKEN 0x000C -#define IMAGE_REL_I386_SECREL7 0x000D -#define IMAGE_REL_I386_REL32 0x0014 - -#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 -#define IMAGE_REL_MIPS_REFHALF 0x0001 -#define IMAGE_REL_MIPS_REFWORD 0x0002 -#define IMAGE_REL_MIPS_JMPADDR 0x0003 -#define IMAGE_REL_MIPS_REFHI 0x0004 -#define IMAGE_REL_MIPS_REFLO 0x0005 -#define IMAGE_REL_MIPS_GPREL 0x0006 -#define IMAGE_REL_MIPS_LITERAL 0x0007 -#define IMAGE_REL_MIPS_SECTION 0x000A -#define IMAGE_REL_MIPS_SECREL 0x000B -#define IMAGE_REL_MIPS_SECRELLO 0x000C -#define IMAGE_REL_MIPS_SECRELHI 0x000D -#define IMAGE_REL_MIPS_TOKEN 0x000E -#define IMAGE_REL_MIPS_JMPADDR16 0x0010 -#define IMAGE_REL_MIPS_REFWORDNB 0x0022 -#define IMAGE_REL_MIPS_PAIR 0x0025 - -#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 -#define IMAGE_REL_ALPHA_REFLONG 0x0001 -#define IMAGE_REL_ALPHA_REFQUAD 0x0002 -#define IMAGE_REL_ALPHA_GPREL32 0x0003 -#define IMAGE_REL_ALPHA_LITERAL 0x0004 -#define IMAGE_REL_ALPHA_LITUSE 0x0005 -#define IMAGE_REL_ALPHA_GPDISP 0x0006 -#define IMAGE_REL_ALPHA_BRADDR 0x0007 -#define IMAGE_REL_ALPHA_HINT 0x0008 -#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 -#define IMAGE_REL_ALPHA_REFHI 0x000A -#define IMAGE_REL_ALPHA_REFLO 0x000B -#define IMAGE_REL_ALPHA_PAIR 0x000C -#define IMAGE_REL_ALPHA_MATCH 0x000D -#define IMAGE_REL_ALPHA_SECTION 0x000E -#define IMAGE_REL_ALPHA_SECREL 0x000F -#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 -#define IMAGE_REL_ALPHA_SECRELLO 0x0011 -#define IMAGE_REL_ALPHA_SECRELHI 0x0012 -#define IMAGE_REL_ALPHA_REFQ3 0x0013 -#define IMAGE_REL_ALPHA_REFQ2 0x0014 -#define IMAGE_REL_ALPHA_REFQ1 0x0015 -#define IMAGE_REL_ALPHA_GPRELLO 0x0016 -#define IMAGE_REL_ALPHA_GPRELHI 0x0017 - -#define IMAGE_REL_PPC_ABSOLUTE 0x0000 -#define IMAGE_REL_PPC_ADDR64 0x0001 -#define IMAGE_REL_PPC_ADDR32 0x0002 -#define IMAGE_REL_PPC_ADDR24 0x0003 -#define IMAGE_REL_PPC_ADDR16 0x0004 -#define IMAGE_REL_PPC_ADDR14 0x0005 -#define IMAGE_REL_PPC_REL24 0x0006 -#define IMAGE_REL_PPC_REL14 0x0007 -#define IMAGE_REL_PPC_TOCREL16 0x0008 -#define IMAGE_REL_PPC_TOCREL14 0x0009 -#define IMAGE_REL_PPC_ADDR32NB 0x000A -#define IMAGE_REL_PPC_SECREL 0x000B -#define IMAGE_REL_PPC_SECTION 0x000C -#define IMAGE_REL_PPC_IFGLUE 0x000D -#define IMAGE_REL_PPC_IMGLUE 0x000E -#define IMAGE_REL_PPC_SECREL16 0x000F -#define IMAGE_REL_PPC_REFHI 0x0010 -#define IMAGE_REL_PPC_REFLO 0x0011 -#define IMAGE_REL_PPC_PAIR 0x0012 -#define IMAGE_REL_PPC_SECRELLO 0x0013 -#define IMAGE_REL_PPC_SECRELHI 0x0014 -#define IMAGE_REL_PPC_GPREL 0x0015 -#define IMAGE_REL_PPC_TOKEN 0x0016 -#define IMAGE_REL_PPC_TYPEMASK 0x00FF -#define IMAGE_REL_PPC_NEG 0x0100 -#define IMAGE_REL_PPC_BRTAKEN 0x0200 -#define IMAGE_REL_PPC_BRNTAKEN 0x0400 -#define IMAGE_REL_PPC_TOCDEFN 0x0800 - -#define IMAGE_REL_SH3_ABSOLUTE 0x0000 -#define IMAGE_REL_SH3_DIRECT16 0x0001 -#define IMAGE_REL_SH3_DIRECT32 0x0002 -#define IMAGE_REL_SH3_DIRECT8 0x0003 -#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 -#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 -#define IMAGE_REL_SH3_DIRECT4 0x0006 -#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 -#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 -#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 -#define IMAGE_REL_SH3_PCREL8_LONG 0x000A -#define IMAGE_REL_SH3_PCREL12_WORD 0x000B -#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C -#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D -#define IMAGE_REL_SH3_SECTION 0x000E -#define IMAGE_REL_SH3_SECREL 0x000F -#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 -#define IMAGE_REL_SH3_GPREL4_LONG 0x0011 -#define IMAGE_REL_SH3_TOKEN 0x0012 - -#define IMAGE_REL_SHM_PCRELPT 0x0013 -#define IMAGE_REL_SHM_REFLO 0x0014 -#define IMAGE_REL_SHM_REFHALF 0x0015 -#define IMAGE_REL_SHM_RELLO 0x0016 -#define IMAGE_REL_SHM_RELHALF 0x0017 -#define IMAGE_REL_SHM_PAIR 0x0018 - -#define IMAGE_REL_SH_NOMODE 0x8000 - -#define IMAGE_REL_ARM_ABSOLUTE 0x0000 -#define IMAGE_REL_ARM_ADDR32 0x0001 -#define IMAGE_REL_ARM_ADDR32NB 0x0002 -#define IMAGE_REL_ARM_BRANCH24 0x0003 -#define IMAGE_REL_ARM_BRANCH11 0x0004 -#define IMAGE_REL_ARM_TOKEN 0x0005 -#define IMAGE_REL_ARM_GPREL12 0x0006 -#define IMAGE_REL_ARM_GPREL7 0x0007 -#define IMAGE_REL_ARM_BLX24 0x0008 -#define IMAGE_REL_ARM_BLX11 0x0009 -#define IMAGE_REL_ARM_SECTION 0x000E -#define IMAGE_REL_ARM_SECREL 0x000F - -#define IMAGE_REL_AM_ABSOLUTE 0x0000 -#define IMAGE_REL_AM_ADDR32 0x0001 -#define IMAGE_REL_AM_ADDR32NB 0x0002 -#define IMAGE_REL_AM_CALL32 0x0003 -#define IMAGE_REL_AM_FUNCINFO 0x0004 -#define IMAGE_REL_AM_REL32_1 0x0005 -#define IMAGE_REL_AM_REL32_2 0x0006 -#define IMAGE_REL_AM_SECREL 0x0007 -#define IMAGE_REL_AM_SECTION 0x0008 -#define IMAGE_REL_AM_TOKEN 0x0009 - -#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 -#define IMAGE_REL_AMD64_ADDR64 0x0001 -#define IMAGE_REL_AMD64_ADDR32 0x0002 -#define IMAGE_REL_AMD64_ADDR32NB 0x0003 -#define IMAGE_REL_AMD64_REL32 0x0004 -#define IMAGE_REL_AMD64_REL32_1 0x0005 -#define IMAGE_REL_AMD64_REL32_2 0x0006 -#define IMAGE_REL_AMD64_REL32_3 0x0007 -#define IMAGE_REL_AMD64_REL32_4 0x0008 -#define IMAGE_REL_AMD64_REL32_5 0x0009 -#define IMAGE_REL_AMD64_SECTION 0x000A -#define IMAGE_REL_AMD64_SECREL 0x000B -#define IMAGE_REL_AMD64_SECREL7 0x000C -#define IMAGE_REL_AMD64_TOKEN 0x000D -#define IMAGE_REL_AMD64_SREL32 0x000E -#define IMAGE_REL_AMD64_PAIR 0x000F -#define IMAGE_REL_AMD64_SSPAN32 0x0010 - -#define IMAGE_REL_IA64_ABSOLUTE 0x0000 -#define IMAGE_REL_IA64_IMM14 0x0001 -#define IMAGE_REL_IA64_IMM22 0x0002 -#define IMAGE_REL_IA64_IMM64 0x0003 -#define IMAGE_REL_IA64_DIR32 0x0004 -#define IMAGE_REL_IA64_DIR64 0x0005 -#define IMAGE_REL_IA64_PCREL21B 0x0006 -#define IMAGE_REL_IA64_PCREL21M 0x0007 -#define IMAGE_REL_IA64_PCREL21F 0x0008 -#define IMAGE_REL_IA64_GPREL22 0x0009 -#define IMAGE_REL_IA64_LTOFF22 0x000A -#define IMAGE_REL_IA64_SECTION 0x000B -#define IMAGE_REL_IA64_SECREL22 0x000C -#define IMAGE_REL_IA64_SECREL64I 0x000D -#define IMAGE_REL_IA64_SECREL32 0x000E - -#define IMAGE_REL_IA64_DIR32NB 0x0010 -#define IMAGE_REL_IA64_SREL14 0x0011 -#define IMAGE_REL_IA64_SREL22 0x0012 -#define IMAGE_REL_IA64_SREL32 0x0013 -#define IMAGE_REL_IA64_UREL32 0x0014 -#define IMAGE_REL_IA64_PCREL60X 0x0015 -#define IMAGE_REL_IA64_PCREL60B 0x0016 -#define IMAGE_REL_IA64_PCREL60F 0x0017 -#define IMAGE_REL_IA64_PCREL60I 0x0018 -#define IMAGE_REL_IA64_PCREL60M 0x0019 -#define IMAGE_REL_IA64_IMMGPREL64 0x001A -#define IMAGE_REL_IA64_TOKEN 0x001B -#define IMAGE_REL_IA64_GPREL32 0x001C -#define IMAGE_REL_IA64_ADDEND 0x001F - -#define IMAGE_REL_CEF_ABSOLUTE 0x0000 -#define IMAGE_REL_CEF_ADDR32 0x0001 -#define IMAGE_REL_CEF_ADDR64 0x0002 -#define IMAGE_REL_CEF_ADDR32NB 0x0003 -#define IMAGE_REL_CEF_SECTION 0x0004 -#define IMAGE_REL_CEF_SECREL 0x0005 -#define IMAGE_REL_CEF_TOKEN 0x0006 - -#define IMAGE_REL_CEE_ABSOLUTE 0x0000 -#define IMAGE_REL_CEE_ADDR32 0x0001 -#define IMAGE_REL_CEE_ADDR64 0x0002 -#define IMAGE_REL_CEE_ADDR32NB 0x0003 -#define IMAGE_REL_CEE_SECTION 0x0004 -#define IMAGE_REL_CEE_SECREL 0x0005 -#define IMAGE_REL_CEE_TOKEN 0x0006 - -#define IMAGE_REL_M32R_ABSOLUTE 0x0000 -#define IMAGE_REL_M32R_ADDR32 0x0001 -#define IMAGE_REL_M32R_ADDR32NB 0x0002 -#define IMAGE_REL_M32R_ADDR24 0x0003 -#define IMAGE_REL_M32R_GPREL16 0x0004 -#define IMAGE_REL_M32R_PCREL24 0x0005 -#define IMAGE_REL_M32R_PCREL16 0x0006 -#define IMAGE_REL_M32R_PCREL8 0x0007 -#define IMAGE_REL_M32R_REFHALF 0x0008 -#define IMAGE_REL_M32R_REFHI 0x0009 -#define IMAGE_REL_M32R_REFLO 0x000A -#define IMAGE_REL_M32R_PAIR 0x000B -#define IMAGE_REL_M32R_SECTION 0x000C -#define IMAGE_REL_M32R_SECREL32 0x000D -#define IMAGE_REL_M32R_TOKEN 0x000E - -#define EXT_IMM64(Value,Address,Size,InstPos,ValPos) Value |= (((ULONGLONG)((*(Address) >> InstPos) & (((ULONGLONG)1 << Size) - 1))) << ValPos) -#define INS_IMM64(Value,Address,Size,InstPos,ValPos) *(PDWORD)Address = (*(PDWORD)Address & ~(((1 << Size) - 1) << InstPos)) | ((DWORD)((((ULONGLONG)Value >> ValPos) & (((ULONGLONG)1 << Size) - 1))) << InstPos) - -#define EMARCH_ENC_I17_IMM7B_INST_WORD_X 3 -#define EMARCH_ENC_I17_IMM7B_SIZE_X 7 -#define EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X 4 -#define EMARCH_ENC_I17_IMM7B_VAL_POS_X 0 - -#define EMARCH_ENC_I17_IMM9D_INST_WORD_X 3 -#define EMARCH_ENC_I17_IMM9D_SIZE_X 9 -#define EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X 18 -#define EMARCH_ENC_I17_IMM9D_VAL_POS_X 7 - -#define EMARCH_ENC_I17_IMM5C_INST_WORD_X 3 -#define EMARCH_ENC_I17_IMM5C_SIZE_X 5 -#define EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X 13 -#define EMARCH_ENC_I17_IMM5C_VAL_POS_X 16 - -#define EMARCH_ENC_I17_IC_INST_WORD_X 3 -#define EMARCH_ENC_I17_IC_SIZE_X 1 -#define EMARCH_ENC_I17_IC_INST_WORD_POS_X 12 -#define EMARCH_ENC_I17_IC_VAL_POS_X 21 - -#define EMARCH_ENC_I17_IMM41a_INST_WORD_X 1 -#define EMARCH_ENC_I17_IMM41a_SIZE_X 10 -#define EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X 14 -#define EMARCH_ENC_I17_IMM41a_VAL_POS_X 22 - -#define EMARCH_ENC_I17_IMM41b_INST_WORD_X 1 -#define EMARCH_ENC_I17_IMM41b_SIZE_X 8 -#define EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X 24 -#define EMARCH_ENC_I17_IMM41b_VAL_POS_X 32 - -#define EMARCH_ENC_I17_IMM41c_INST_WORD_X 2 -#define EMARCH_ENC_I17_IMM41c_SIZE_X 23 -#define EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X 0 -#define EMARCH_ENC_I17_IMM41c_VAL_POS_X 40 - -#define EMARCH_ENC_I17_SIGN_INST_WORD_X 3 -#define EMARCH_ENC_I17_SIGN_SIZE_X 1 -#define EMARCH_ENC_I17_SIGN_INST_WORD_POS_X 27 -#define EMARCH_ENC_I17_SIGN_VAL_POS_X 63 - -#define X3_OPCODE_INST_WORD_X 3 -#define X3_OPCODE_SIZE_X 4 -#define X3_OPCODE_INST_WORD_POS_X 28 -#define X3_OPCODE_SIGN_VAL_POS_X 0 - -#define X3_I_INST_WORD_X 3 -#define X3_I_SIZE_X 1 -#define X3_I_INST_WORD_POS_X 27 -#define X3_I_SIGN_VAL_POS_X 59 - -#define X3_D_WH_INST_WORD_X 3 -#define X3_D_WH_SIZE_X 3 -#define X3_D_WH_INST_WORD_POS_X 24 -#define X3_D_WH_SIGN_VAL_POS_X 0 - -#define X3_IMM20_INST_WORD_X 3 -#define X3_IMM20_SIZE_X 20 -#define X3_IMM20_INST_WORD_POS_X 4 -#define X3_IMM20_SIGN_VAL_POS_X 0 - -#define X3_IMM39_1_INST_WORD_X 2 -#define X3_IMM39_1_SIZE_X 23 -#define X3_IMM39_1_INST_WORD_POS_X 0 -#define X3_IMM39_1_SIGN_VAL_POS_X 36 - -#define X3_IMM39_2_INST_WORD_X 1 -#define X3_IMM39_2_SIZE_X 16 -#define X3_IMM39_2_INST_WORD_POS_X 16 -#define X3_IMM39_2_SIGN_VAL_POS_X 20 - -#define X3_P_INST_WORD_X 3 -#define X3_P_SIZE_X 4 -#define X3_P_INST_WORD_POS_X 0 -#define X3_P_SIGN_VAL_POS_X 0 - -#define X3_TMPLT_INST_WORD_X 0 -#define X3_TMPLT_SIZE_X 4 -#define X3_TMPLT_INST_WORD_POS_X 0 -#define X3_TMPLT_SIGN_VAL_POS_X 0 - -#define X3_BTYPE_QP_INST_WORD_X 2 -#define X3_BTYPE_QP_SIZE_X 9 -#define X3_BTYPE_QP_INST_WORD_POS_X 23 -#define X3_BTYPE_QP_INST_VAL_POS_X 0 - -#define X3_EMPTY_INST_WORD_X 1 -#define X3_EMPTY_SIZE_X 2 -#define X3_EMPTY_INST_WORD_POS_X 14 -#define X3_EMPTY_INST_VAL_POS_X 0 - - typedef struct _IMAGE_LINENUMBER { - union { - DWORD SymbolTableIndex; - DWORD VirtualAddress; - } Type; - WORD Linenumber; - } IMAGE_LINENUMBER; - typedef IMAGE_LINENUMBER UNALIGNED *PIMAGE_LINENUMBER; - -#define IMAGE_SIZEOF_LINENUMBER 6 - -#include "poppack.h" - - typedef struct _IMAGE_BASE_RELOCATION { - DWORD VirtualAddress; - DWORD SizeOfBlock; - - } IMAGE_BASE_RELOCATION; - typedef IMAGE_BASE_RELOCATION UNALIGNED *PIMAGE_BASE_RELOCATION; - -#define IMAGE_SIZEOF_BASE_RELOCATION 8 - -#define IMAGE_REL_BASED_ABSOLUTE 0 -#define IMAGE_REL_BASED_HIGH 1 -#define IMAGE_REL_BASED_LOW 2 -#define IMAGE_REL_BASED_HIGHLOW 3 -#define IMAGE_REL_BASED_HIGHADJ 4 -#define IMAGE_REL_BASED_MIPS_JMPADDR 5 -#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 -#define IMAGE_REL_BASED_IA64_IMM64 9 -#define IMAGE_REL_BASED_DIR64 10 - -#define IMAGE_ARCHIVE_START_SIZE 8 -#define IMAGE_ARCHIVE_START "!\n" -#define IMAGE_ARCHIVE_END "`\n" -#define IMAGE_ARCHIVE_PAD "\n" -#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " -#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " - - typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { - BYTE Name[16]; - BYTE Date[12]; - BYTE UserID[6]; - BYTE GroupID[6]; - BYTE Mode[8]; - BYTE Size[10]; - BYTE EndHeader[2]; - } IMAGE_ARCHIVE_MEMBER_HEADER,*PIMAGE_ARCHIVE_MEMBER_HEADER; - -#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 - - typedef struct _IMAGE_EXPORT_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD Name; - DWORD Base; - DWORD NumberOfFunctions; - DWORD NumberOfNames; - DWORD AddressOfFunctions; - DWORD AddressOfNames; - DWORD AddressOfNameOrdinals; - } IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; - - typedef struct _IMAGE_IMPORT_BY_NAME { - WORD Hint; - BYTE Name[1]; - } IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; - -#include "pshpack8.h" - - typedef struct _IMAGE_THUNK_DATA64 { - union { - ULONGLONG ForwarderString; - ULONGLONG Function; - ULONGLONG Ordinal; - ULONGLONG AddressOfData; - } u1; - } IMAGE_THUNK_DATA64; - typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; - -#include "poppack.h" - - typedef struct _IMAGE_THUNK_DATA32 { - union { - DWORD ForwarderString; - DWORD Function; - DWORD Ordinal; - DWORD AddressOfData; - } u1; - } IMAGE_THUNK_DATA32; - typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; - -#define IMAGE_ORDINAL_FLAG64 0x8000000000000000ull -#define IMAGE_ORDINAL_FLAG32 0x80000000 -#define IMAGE_ORDINAL64(Ordinal) (Ordinal & 0xffffull) -#define IMAGE_ORDINAL32(Ordinal) (Ordinal & 0xffff) -#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64)!=0) -#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32)!=0) - - typedef VOID - (NTAPI *PIMAGE_TLS_CALLBACK)(PVOID DllHandle,DWORD Reason,PVOID Reserved); - - typedef struct _IMAGE_TLS_DIRECTORY64 { - ULONGLONG StartAddressOfRawData; - ULONGLONG EndAddressOfRawData; - ULONGLONG AddressOfIndex; - ULONGLONG AddressOfCallBacks; - DWORD SizeOfZeroFill; - DWORD Characteristics; - } IMAGE_TLS_DIRECTORY64; - typedef IMAGE_TLS_DIRECTORY64 *PIMAGE_TLS_DIRECTORY64; - - typedef struct _IMAGE_TLS_DIRECTORY32 { - DWORD StartAddressOfRawData; - DWORD EndAddressOfRawData; - DWORD AddressOfIndex; - DWORD AddressOfCallBacks; - DWORD SizeOfZeroFill; - DWORD Characteristics; - } IMAGE_TLS_DIRECTORY32; - typedef IMAGE_TLS_DIRECTORY32 *PIMAGE_TLS_DIRECTORY32; - -#ifdef _WIN64 -#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64 -#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL64(Ordinal) - typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; - typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; -#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL64(Ordinal) - typedef IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY; - typedef PIMAGE_TLS_DIRECTORY64 PIMAGE_TLS_DIRECTORY; -#else -#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32 -#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL32(Ordinal) - typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; - typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; -#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL32(Ordinal) - typedef IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY; - typedef PIMAGE_TLS_DIRECTORY32 PIMAGE_TLS_DIRECTORY; -#endif - - typedef struct _IMAGE_IMPORT_DESCRIPTOR { - union { - DWORD Characteristics; - DWORD OriginalFirstThunk; - }; - DWORD TimeDateStamp; - - DWORD ForwarderChain; - DWORD Name; - DWORD FirstThunk; - } IMAGE_IMPORT_DESCRIPTOR; - typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR; - - typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR { - DWORD TimeDateStamp; - WORD OffsetModuleName; - WORD NumberOfModuleForwarderRefs; - } IMAGE_BOUND_IMPORT_DESCRIPTOR,*PIMAGE_BOUND_IMPORT_DESCRIPTOR; - - typedef struct _IMAGE_BOUND_FORWARDER_REF { - DWORD TimeDateStamp; - WORD OffsetModuleName; - WORD Reserved; - } IMAGE_BOUND_FORWARDER_REF,*PIMAGE_BOUND_FORWARDER_REF; - - typedef struct _IMAGE_RESOURCE_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - WORD NumberOfNamedEntries; - WORD NumberOfIdEntries; - } IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; - -#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 -#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 - - typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { - union { - struct { - DWORD NameOffset:31; - DWORD NameIsString:1; - }; - DWORD Name; - WORD Id; - }; - union { - DWORD OffsetToData; - struct { - DWORD OffsetToDirectory:31; - DWORD DataIsDirectory:1; - }; - }; - } IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; - - typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { - WORD Length; - CHAR NameString[1]; - } IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; - - typedef struct _IMAGE_RESOURCE_DIR_STRING_U { - WORD Length; - WCHAR NameString[1]; - } IMAGE_RESOURCE_DIR_STRING_U,*PIMAGE_RESOURCE_DIR_STRING_U; - - typedef struct _IMAGE_RESOURCE_DATA_ENTRY { - DWORD OffsetToData; - DWORD Size; - DWORD CodePage; - DWORD Reserved; - } IMAGE_RESOURCE_DATA_ENTRY,*PIMAGE_RESOURCE_DATA_ENTRY; - - typedef struct { - DWORD Size; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD GlobalFlagsClear; - DWORD GlobalFlagsSet; - DWORD CriticalSectionDefaultTimeout; - DWORD DeCommitFreeBlockThreshold; - DWORD DeCommitTotalFreeThreshold; - DWORD LockPrefixTable; - DWORD MaximumAllocationSize; - DWORD VirtualMemoryThreshold; - DWORD ProcessHeapFlags; - DWORD ProcessAffinityMask; - WORD CSDVersion; - WORD Reserved1; - DWORD EditList; - DWORD SecurityCookie; - DWORD SEHandlerTable; - DWORD SEHandlerCount; - } IMAGE_LOAD_CONFIG_DIRECTORY32,*PIMAGE_LOAD_CONFIG_DIRECTORY32; - - typedef struct { - DWORD Size; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD GlobalFlagsClear; - DWORD GlobalFlagsSet; - DWORD CriticalSectionDefaultTimeout; - ULONGLONG DeCommitFreeBlockThreshold; - ULONGLONG DeCommitTotalFreeThreshold; - ULONGLONG LockPrefixTable; - ULONGLONG MaximumAllocationSize; - ULONGLONG VirtualMemoryThreshold; - ULONGLONG ProcessAffinityMask; - DWORD ProcessHeapFlags; - WORD CSDVersion; - WORD Reserved1; - ULONGLONG EditList; - ULONGLONG SecurityCookie; - ULONGLONG SEHandlerTable; - ULONGLONG SEHandlerCount; - } IMAGE_LOAD_CONFIG_DIRECTORY64,*PIMAGE_LOAD_CONFIG_DIRECTORY64; - -#ifdef _WIN64 - typedef IMAGE_LOAD_CONFIG_DIRECTORY64 IMAGE_LOAD_CONFIG_DIRECTORY; - typedef PIMAGE_LOAD_CONFIG_DIRECTORY64 PIMAGE_LOAD_CONFIG_DIRECTORY; -#else - typedef IMAGE_LOAD_CONFIG_DIRECTORY32 IMAGE_LOAD_CONFIG_DIRECTORY; - typedef PIMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY; -#endif - - typedef struct _IMAGE_CE_RUNTIME_FUNCTION_ENTRY { - DWORD FuncStart; - DWORD PrologLen : 8; - DWORD FuncLen : 22; - DWORD ThirtyTwoBit : 1; - DWORD ExceptionFlag : 1; - } IMAGE_CE_RUNTIME_FUNCTION_ENTRY,*PIMAGE_CE_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY { - ULONGLONG BeginAddress; - ULONGLONG EndAddress; - ULONGLONG ExceptionHandler; - ULONGLONG HandlerData; - ULONGLONG PrologEndAddress; - } IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY { - DWORD BeginAddress; - DWORD EndAddress; - DWORD ExceptionHandler; - DWORD HandlerData; - DWORD PrologEndAddress; - } IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { - DWORD BeginAddress; - DWORD EndAddress; - DWORD UnwindInfoAddress; - } _IMAGE_RUNTIME_FUNCTION_ENTRY,*_PIMAGE_RUNTIME_FUNCTION_ENTRY; - - typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_IA64_RUNTIME_FUNCTION_ENTRY; - typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY; - - typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_RUNTIME_FUNCTION_ENTRY; - typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_RUNTIME_FUNCTION_ENTRY; - - typedef struct _IMAGE_DEBUG_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD Type; - DWORD SizeOfData; - DWORD AddressOfRawData; - DWORD PointerToRawData; - } IMAGE_DEBUG_DIRECTORY,*PIMAGE_DEBUG_DIRECTORY; - -#define IMAGE_DEBUG_TYPE_UNKNOWN 0 -#define IMAGE_DEBUG_TYPE_COFF 1 -#define IMAGE_DEBUG_TYPE_CODEVIEW 2 -#define IMAGE_DEBUG_TYPE_FPO 3 -#define IMAGE_DEBUG_TYPE_MISC 4 -#define IMAGE_DEBUG_TYPE_EXCEPTION 5 -#define IMAGE_DEBUG_TYPE_FIXUP 6 -#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 -#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 -#define IMAGE_DEBUG_TYPE_BORLAND 9 -#define IMAGE_DEBUG_TYPE_RESERVED10 10 -#define IMAGE_DEBUG_TYPE_CLSID 11 - - typedef struct _IMAGE_COFF_SYMBOLS_HEADER { - DWORD NumberOfSymbols; - DWORD LvaToFirstSymbol; - DWORD NumberOfLinenumbers; - DWORD LvaToFirstLinenumber; - DWORD RvaToFirstByteOfCode; - DWORD RvaToLastByteOfCode; - DWORD RvaToFirstByteOfData; - DWORD RvaToLastByteOfData; - } IMAGE_COFF_SYMBOLS_HEADER,*PIMAGE_COFF_SYMBOLS_HEADER; - -#define FRAME_FPO 0 -#define FRAME_TRAP 1 -#define FRAME_TSS 2 -#define FRAME_NONFPO 3 - - typedef struct _FPO_DATA { - DWORD ulOffStart; - DWORD cbProcSize; - DWORD cdwLocals; - WORD cdwParams; - WORD cbProlog : 8; - WORD cbRegs : 3; - WORD fHasSEH : 1; - WORD fUseBP : 1; - WORD reserved : 1; - WORD cbFrame : 2; - } FPO_DATA,*PFPO_DATA; -#define SIZEOF_RFPO_DATA 16 - -#define IMAGE_DEBUG_MISC_EXENAME 1 - - typedef struct _IMAGE_DEBUG_MISC { - DWORD DataType; - DWORD Length; - BOOLEAN Unicode; - BYTE Reserved[3]; - BYTE Data[1]; - } IMAGE_DEBUG_MISC,*PIMAGE_DEBUG_MISC; - - typedef struct _IMAGE_FUNCTION_ENTRY { - DWORD StartingAddress; - DWORD EndingAddress; - DWORD EndOfPrologue; - } IMAGE_FUNCTION_ENTRY,*PIMAGE_FUNCTION_ENTRY; - - typedef struct _IMAGE_FUNCTION_ENTRY64 { - ULONGLONG StartingAddress; - ULONGLONG EndingAddress; - union { - ULONGLONG EndOfPrologue; - ULONGLONG UnwindInfoAddress; - }; - } IMAGE_FUNCTION_ENTRY64,*PIMAGE_FUNCTION_ENTRY64; - - typedef struct _IMAGE_SEPARATE_DEBUG_HEADER { - WORD Signature; - WORD Flags; - WORD Machine; - WORD Characteristics; - DWORD TimeDateStamp; - DWORD CheckSum; - DWORD ImageBase; - DWORD SizeOfImage; - DWORD NumberOfSections; - DWORD ExportedNamesSize; - DWORD DebugDirectorySize; - DWORD SectionAlignment; - DWORD Reserved[2]; - } IMAGE_SEPARATE_DEBUG_HEADER,*PIMAGE_SEPARATE_DEBUG_HEADER; - - typedef struct _NON_PAGED_DEBUG_INFO { - WORD Signature; - WORD Flags; - DWORD Size; - WORD Machine; - WORD Characteristics; - DWORD TimeDateStamp; - DWORD CheckSum; - DWORD SizeOfImage; - ULONGLONG ImageBase; - - } NON_PAGED_DEBUG_INFO,*PNON_PAGED_DEBUG_INFO; - -#define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944 -#define NON_PAGED_DEBUG_SIGNATURE 0x494E - -#define IMAGE_SEPARATE_DEBUG_FLAGS_MASK 0x8000 -#define IMAGE_SEPARATE_DEBUG_MISMATCH 0x8000 - - typedef struct _ImageArchitectureHeader { - unsigned int AmaskValue: 1; - int Adummy1 :7; - unsigned int AmaskShift: 8; - int Adummy2 :16; - DWORD FirstEntryRVA; - } IMAGE_ARCHITECTURE_HEADER,*PIMAGE_ARCHITECTURE_HEADER; - - typedef struct _ImageArchitectureEntry { - DWORD FixupInstRVA; - DWORD NewInst; - } IMAGE_ARCHITECTURE_ENTRY,*PIMAGE_ARCHITECTURE_ENTRY; - -#include "poppack.h" - -#define IMPORT_OBJECT_HDR_SIG2 0xffff - - typedef struct IMPORT_OBJECT_HEADER { - WORD Sig1; - WORD Sig2; - WORD Version; - WORD Machine; - DWORD TimeDateStamp; - DWORD SizeOfData; - union { - WORD Ordinal; - WORD Hint; - }; - WORD Type : 2; - WORD NameType : 3; - WORD Reserved : 11; - } IMPORT_OBJECT_HEADER; - - typedef enum IMPORT_OBJECT_TYPE { - IMPORT_OBJECT_CODE = 0,IMPORT_OBJECT_DATA = 1,IMPORT_OBJECT_CONST = 2 - } IMPORT_OBJECT_TYPE; - - typedef enum IMPORT_OBJECT_NAME_TYPE { - IMPORT_OBJECT_ORDINAL = 0,IMPORT_OBJECT_NAME = 1,IMPORT_OBJECT_NAME_NO_PREFIX = 2,IMPORT_OBJECT_NAME_UNDECORATE = 3 - } IMPORT_OBJECT_NAME_TYPE; - -#ifndef __IMAGE_COR20_HEADER_DEFINED__ -#define __IMAGE_COR20_HEADER_DEFINED__ - typedef enum ReplacesCorHdrNumericDefines { - COMIMAGE_FLAGS_ILONLY =0x00000001,COMIMAGE_FLAGS_32BITREQUIRED =0x00000002,COMIMAGE_FLAGS_IL_LIBRARY =0x00000004, - COMIMAGE_FLAGS_STRONGNAMESIGNED =0x00000008,COMIMAGE_FLAGS_TRACKDEBUGDATA =0x00010000,COR_VERSION_MAJOR_V2 =2, - COR_VERSION_MAJOR =COR_VERSION_MAJOR_V2,COR_VERSION_MINOR =0,COR_DELETED_NAME_LENGTH =8,COR_VTABLEGAP_NAME_LENGTH =8, - NATIVE_TYPE_MAX_CB =1,COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE=0xFF,IMAGE_COR_MIH_METHODRVA =0x01,IMAGE_COR_MIH_EHRVA =0x02, - IMAGE_COR_MIH_BASICBLOCK =0x08,COR_VTABLE_32BIT =0x01,COR_VTABLE_64BIT =0x02,COR_VTABLE_FROM_UNMANAGED =0x04, - COR_VTABLE_CALL_MOST_DERIVED =0x10,IMAGE_COR_EATJ_THUNK_SIZE =32,MAX_CLASS_NAME =1024,MAX_PACKAGE_NAME =1024 - } ReplacesCorHdrNumericDefines; - - typedef struct IMAGE_COR20_HEADER { - DWORD cb; - WORD MajorRuntimeVersion; - WORD MinorRuntimeVersion; - IMAGE_DATA_DIRECTORY MetaData; - DWORD Flags; - DWORD EntryPointToken; - IMAGE_DATA_DIRECTORY Resources; - IMAGE_DATA_DIRECTORY StrongNameSignature; - IMAGE_DATA_DIRECTORY CodeManagerTable; - IMAGE_DATA_DIRECTORY VTableFixups; - IMAGE_DATA_DIRECTORY ExportAddressTableJumps; - IMAGE_DATA_DIRECTORY ManagedNativeHeader; - } IMAGE_COR20_HEADER,*PIMAGE_COR20_HEADER; -#endif - -#if defined (__x86_64) - NTSYSAPI PRUNTIME_FUNCTION NTAPI RtlLookupFunctionEntry (DWORD64 ControlPc, PDWORD64 ImageBase, PUNWIND_HISTORY_TABLE HistoryTable); - NTSYSAPI VOID NTAPI RtlUnwindEx (PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable); -#endif - -#include - -#ifndef _SLIST_HEADER_ -#define _SLIST_HEADER_ - -#ifdef _WIN64 - typedef struct _SLIST_ENTRY *PSLIST_ENTRY; - typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY { - PSLIST_ENTRY Next; - } SLIST_ENTRY; -#else - -#define SLIST_ENTRY SINGLE_LIST_ENTRY -#define _SLIST_ENTRY _SINGLE_LIST_ENTRY -#define PSLIST_ENTRY PSINGLE_LIST_ENTRY -#endif - -#if defined(_WIN64) - - typedef struct DECLSPEC_ALIGN(16) _SLIST_HEADER { - ULONGLONG Alignment; - ULONGLONG Region; - } SLIST_HEADER; - - typedef struct _SLIST_HEADER *PSLIST_HEADER; -#else - - typedef union _SLIST_HEADER { - ULONGLONG Alignment; - struct { - SLIST_ENTRY Next; - WORD Depth; - WORD Sequence; - }; - } SLIST_HEADER,*PSLIST_HEADER; -#endif -#endif - - NTSYSAPI VOID NTAPI RtlInitializeSListHead(PSLIST_HEADER ListHead); - NTSYSAPI PSLIST_ENTRY NTAPI RtlFirstEntrySList(const SLIST_HEADER *ListHead); - NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPopEntrySList(PSLIST_HEADER ListHead); - NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); - NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedFlushSList(PSLIST_HEADER ListHead); - NTSYSAPI WORD NTAPI RtlQueryDepthSList(PSLIST_HEADER ListHead); - -#define HEAP_NO_SERIALIZE 0x00000001 -#define HEAP_GROWABLE 0x00000002 -#define HEAP_GENERATE_EXCEPTIONS 0x00000004 -#define HEAP_ZERO_MEMORY 0x00000008 -#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 -#define HEAP_TAIL_CHECKING_ENABLED 0x00000020 -#define HEAP_FREE_CHECKING_ENABLED 0x00000040 -#define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 -#define HEAP_CREATE_ALIGN_16 0x00010000 -#define HEAP_CREATE_ENABLE_TRACING 0x00020000 -#define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 -#define HEAP_MAXIMUM_TAG 0x0FFF -#define HEAP_PSEUDO_TAG_FLAG 0x8000 -#define HEAP_TAG_SHIFT 18 -#define HEAP_MAKE_TAG_FLAGS(b,o) ((DWORD)((b) + ((o) << 18))) - - NTSYSAPI VOID NTAPI RtlCaptureContext(PCONTEXT ContextRecord); - -#define IS_TEXT_UNICODE_ASCII16 0x0001 -#define IS_TEXT_UNICODE_REVERSE_ASCII16 0x0010 - -#define IS_TEXT_UNICODE_STATISTICS 0x0002 -#define IS_TEXT_UNICODE_REVERSE_STATISTICS 0x0020 - -#define IS_TEXT_UNICODE_CONTROLS 0x0004 -#define IS_TEXT_UNICODE_REVERSE_CONTROLS 0x0040 - -#define IS_TEXT_UNICODE_SIGNATURE 0x0008 -#define IS_TEXT_UNICODE_REVERSE_SIGNATURE 0x0080 - -#define IS_TEXT_UNICODE_ILLEGAL_CHARS 0x0100 -#define IS_TEXT_UNICODE_ODD_LENGTH 0x0200 -#define IS_TEXT_UNICODE_DBCS_LEADBYTE 0x0400 -#define IS_TEXT_UNICODE_NULL_BYTES 0x1000 - -#define IS_TEXT_UNICODE_UNICODE_MASK 0x000F -#define IS_TEXT_UNICODE_REVERSE_MASK 0x00F0 -#define IS_TEXT_UNICODE_NOT_UNICODE_MASK 0x0F00 -#define IS_TEXT_UNICODE_NOT_ASCII_MASK 0xF000 - -#define COMPRESSION_FORMAT_NONE (0x0000) -#define COMPRESSION_FORMAT_DEFAULT (0x0001) -#define COMPRESSION_FORMAT_LZNT1 (0x0002) -#define COMPRESSION_ENGINE_STANDARD (0x0000) -#define COMPRESSION_ENGINE_MAXIMUM (0x0100) -#define COMPRESSION_ENGINE_HIBER (0x0200) - -#if _DBG_MEMCPY_INLINE_ && !defined(_MEMCPY_INLINE_) && !defined(_CRTBLD) -#define _MEMCPY_INLINE_ - __CRT_INLINE PVOID __cdecl memcpy_inline(void *dst,const void *src,size_t size) { - if(((char *)dst > (char *)src) && ((char *)dst < ((char *)src + size))) { - __debugbreak(); - } - return memcpy(dst,src,size); - } -#define memcpy memcpy_inline -#endif - - NTSYSAPI SIZE_T NTAPI RtlCompareMemory(const VOID *Source1,const VOID *Source2,SIZE_T Length); - -#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length))) -#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length)) -#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length)) -#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length)) -#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) - - __CRT_INLINE PVOID RtlSecureZeroMemory(PVOID ptr,SIZE_T cnt) { - volatile char *vptr =(volatile char *)ptr; -#ifdef __x86_64 - __stosb((PBYTE)((DWORD64)vptr),0,cnt); -#else - while(cnt) { - *vptr = 0; - vptr++; - cnt--; - } -#endif - return ptr; - } - - typedef struct _MESSAGE_RESOURCE_ENTRY { - WORD Length; - WORD Flags; - BYTE Text[1]; - } MESSAGE_RESOURCE_ENTRY,*PMESSAGE_RESOURCE_ENTRY; - -#define MESSAGE_RESOURCE_UNICODE 0x0001 - - typedef struct _MESSAGE_RESOURCE_BLOCK { - DWORD LowId; - DWORD HighId; - DWORD OffsetToEntries; - } MESSAGE_RESOURCE_BLOCK,*PMESSAGE_RESOURCE_BLOCK; - - typedef struct _MESSAGE_RESOURCE_DATA { - DWORD NumberOfBlocks; - MESSAGE_RESOURCE_BLOCK Blocks[1]; - } MESSAGE_RESOURCE_DATA,*PMESSAGE_RESOURCE_DATA; - - typedef struct _OSVERSIONINFOA { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - CHAR szCSDVersion[128]; - } OSVERSIONINFOA,*POSVERSIONINFOA,*LPOSVERSIONINFOA; - - typedef struct _OSVERSIONINFOW { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - WCHAR szCSDVersion[128]; - } OSVERSIONINFOW,*POSVERSIONINFOW,*LPOSVERSIONINFOW,RTL_OSVERSIONINFOW,*PRTL_OSVERSIONINFOW; - -#ifdef UNICODE - typedef OSVERSIONINFOW OSVERSIONINFO; - typedef POSVERSIONINFOW POSVERSIONINFO; - typedef LPOSVERSIONINFOW LPOSVERSIONINFO; -#else - typedef OSVERSIONINFOA OSVERSIONINFO; - typedef POSVERSIONINFOA POSVERSIONINFO; - typedef LPOSVERSIONINFOA LPOSVERSIONINFO; -#endif - - typedef struct _OSVERSIONINFOEXA { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - CHAR szCSDVersion[128]; - WORD wServicePackMajor; - WORD wServicePackMinor; - WORD wSuiteMask; - BYTE wProductType; - BYTE wReserved; - } OSVERSIONINFOEXA,*POSVERSIONINFOEXA,*LPOSVERSIONINFOEXA; - - typedef struct _OSVERSIONINFOEXW { - DWORD dwOSVersionInfoSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformId; - WCHAR szCSDVersion[128]; - WORD wServicePackMajor; - WORD wServicePackMinor; - WORD wSuiteMask; - BYTE wProductType; - BYTE wReserved; - } OSVERSIONINFOEXW,*POSVERSIONINFOEXW,*LPOSVERSIONINFOEXW,RTL_OSVERSIONINFOEXW,*PRTL_OSVERSIONINFOEXW; -#ifdef UNICODE - typedef OSVERSIONINFOEXW OSVERSIONINFOEX; - typedef POSVERSIONINFOEXW POSVERSIONINFOEX; - typedef LPOSVERSIONINFOEXW LPOSVERSIONINFOEX; -#else - typedef OSVERSIONINFOEXA OSVERSIONINFOEX; - typedef POSVERSIONINFOEXA POSVERSIONINFOEX; - typedef LPOSVERSIONINFOEXA LPOSVERSIONINFOEX; -#endif - -#define VER_EQUAL 1 -#define VER_GREATER 2 -#define VER_GREATER_EQUAL 3 -#define VER_LESS 4 -#define VER_LESS_EQUAL 5 -#define VER_AND 6 -#define VER_OR 7 - -#define VER_CONDITION_MASK 7 -#define VER_NUM_BITS_PER_CONDITION_MASK 3 - -#define VER_MINORVERSION 0x0000001 -#define VER_MAJORVERSION 0x0000002 -#define VER_BUILDNUMBER 0x0000004 -#define VER_PLATFORMID 0x0000008 -#define VER_SERVICEPACKMINOR 0x0000010 -#define VER_SERVICEPACKMAJOR 0x0000020 -#define VER_SUITENAME 0x0000040 -#define VER_PRODUCT_TYPE 0x0000080 - -#define VER_NT_WORKSTATION 0x0000001 -#define VER_NT_DOMAIN_CONTROLLER 0x0000002 -#define VER_NT_SERVER 0x0000003 - -#define VER_PLATFORM_WIN32s 0 -#define VER_PLATFORM_WIN32_WINDOWS 1 -#define VER_PLATFORM_WIN32_NT 2 - -#define VER_SET_CONDITION(_m_,_t_,_c_) ((_m_)=VerSetConditionMask((_m_),(_t_),(_c_))) - - NTSYSAPI ULONGLONG NTAPI VerSetConditionMask(ULONGLONG ConditionMask,DWORD TypeMask,BYTE Condition); - - typedef struct _RTL_CRITICAL_SECTION_DEBUG { - WORD Type; - WORD CreatorBackTraceIndex; - struct _RTL_CRITICAL_SECTION *CriticalSection; - LIST_ENTRY ProcessLocksList; - DWORD EntryCount; - DWORD ContentionCount; - DWORD Spare[2]; - } RTL_CRITICAL_SECTION_DEBUG,*PRTL_CRITICAL_SECTION_DEBUG,RTL_RESOURCE_DEBUG,*PRTL_RESOURCE_DEBUG; - -#define RTL_CRITSECT_TYPE 0 -#define RTL_RESOURCE_TYPE 1 - - typedef struct _RTL_CRITICAL_SECTION { - PRTL_CRITICAL_SECTION_DEBUG DebugInfo; - LONG LockCount; - LONG RecursionCount; - HANDLE OwningThread; - HANDLE LockSemaphore; - ULONG_PTR SpinCount; - } RTL_CRITICAL_SECTION,*PRTL_CRITICAL_SECTION; - - typedef VOID (NTAPI *RTL_VERIFIER_DLL_LOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); - typedef VOID (NTAPI *RTL_VERIFIER_DLL_UNLOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); - typedef VOID (NTAPI *RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK)(PVOID AllocationBase,SIZE_T AllocationSize); - - typedef struct _RTL_VERIFIER_THUNK_DESCRIPTOR { - PCHAR ThunkName; - PVOID ThunkOldAddress; - PVOID ThunkNewAddress; - } RTL_VERIFIER_THUNK_DESCRIPTOR,*PRTL_VERIFIER_THUNK_DESCRIPTOR; - - typedef struct _RTL_VERIFIER_DLL_DESCRIPTOR { - PWCHAR DllName; - DWORD DllFlags; - PVOID DllAddress; - PRTL_VERIFIER_THUNK_DESCRIPTOR DllThunks; - } RTL_VERIFIER_DLL_DESCRIPTOR,*PRTL_VERIFIER_DLL_DESCRIPTOR; - - typedef struct _RTL_VERIFIER_PROVIDER_DESCRIPTOR { - DWORD Length; - PRTL_VERIFIER_DLL_DESCRIPTOR ProviderDlls; - RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback; - RTL_VERIFIER_DLL_UNLOAD_CALLBACK ProviderDllUnloadCallback; - PWSTR VerifierImage; - DWORD VerifierFlags; - DWORD VerifierDebug; - PVOID RtlpGetStackTraceAddress; - PVOID RtlpDebugPageHeapCreate; - PVOID RtlpDebugPageHeapDestroy; - RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK ProviderNtdllHeapFreeCallback; - } RTL_VERIFIER_PROVIDER_DESCRIPTOR,*PRTL_VERIFIER_PROVIDER_DESCRIPTOR; - -#define RTL_VRF_FLG_FULL_PAGE_HEAP 0x00000001 -#define RTL_VRF_FLG_RESERVED_DONOTUSE 0x00000002 -#define RTL_VRF_FLG_HANDLE_CHECKS 0x00000004 -#define RTL_VRF_FLG_STACK_CHECKS 0x00000008 -#define RTL_VRF_FLG_APPCOMPAT_CHECKS 0x00000010 -#define RTL_VRF_FLG_TLS_CHECKS 0x00000020 -#define RTL_VRF_FLG_DIRTY_STACKS 0x00000040 -#define RTL_VRF_FLG_RPC_CHECKS 0x00000080 -#define RTL_VRF_FLG_COM_CHECKS 0x00000100 -#define RTL_VRF_FLG_DANGEROUS_APIS 0x00000200 -#define RTL_VRF_FLG_RACE_CHECKS 0x00000400 -#define RTL_VRF_FLG_DEADLOCK_CHECKS 0x00000800 -#define RTL_VRF_FLG_FIRST_CHANCE_EXCEPTION_CHECKS 0x00001000 -#define RTL_VRF_FLG_VIRTUAL_MEM_CHECKS 0x00002000 -#define RTL_VRF_FLG_ENABLE_LOGGING 0x00004000 -#define RTL_VRF_FLG_FAST_FILL_HEAP 0x00008000 -#define RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING 0x00010000 -#define RTL_VRF_FLG_ENABLED_SYSTEM_WIDE 0x00020000 -#define RTL_VRF_FLG_MISCELLANEOUS_CHECKS 0x00020000 -#define RTL_VRF_FLG_LOCK_CHECKS 0x00040000 - -#define APPLICATION_VERIFIER_INTERNAL_ERROR 0x80000000 -#define APPLICATION_VERIFIER_INTERNAL_WARNING 0x40000000 -#define APPLICATION_VERIFIER_NO_BREAK 0x20000000 -#define APPLICATION_VERIFIER_CONTINUABLE_BREAK 0x10000000 - -#define APPLICATION_VERIFIER_UNKNOWN_ERROR 0x0001 -#define APPLICATION_VERIFIER_ACCESS_VIOLATION 0x0002 -#define APPLICATION_VERIFIER_UNSYNCHRONIZED_ACCESS 0x0003 -#define APPLICATION_VERIFIER_EXTREME_SIZE_REQUEST 0x0004 -#define APPLICATION_VERIFIER_BAD_HEAP_HANDLE 0x0005 -#define APPLICATION_VERIFIER_SWITCHED_HEAP_HANDLE 0x0006 -#define APPLICATION_VERIFIER_DOUBLE_FREE 0x0007 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK 0x0008 -#define APPLICATION_VERIFIER_DESTROY_PROCESS_HEAP 0x0009 -#define APPLICATION_VERIFIER_UNEXPECTED_EXCEPTION 0x000A -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_HEADER 0x000B -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_PROBING 0x000C -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_HEADER 0x000D -#define APPLICATION_VERIFIER_CORRUPTED_FREED_HEAP_BLOCK 0x000E -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_SUFFIX 0x000F -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_START_STAMP 0x0010 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_END_STAMP 0x0011 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_PREFIX 0x0012 -#define APPLICATION_VERIFIER_FIRST_CHANCE_ACCESS_VIOLATION 0x0013 -#define APPLICATION_VERIFIER_CORRUPTED_HEAP_LIST 0x0014 - -#define APPLICATION_VERIFIER_TERMINATE_THREAD_CALL 0x0100 -#define APPLICATION_VERIFIER_STACK_OVERFLOW 0x0101 -#define APPLICATION_VERIFIER_INVALID_EXIT_PROCESS_CALL 0x0102 - -#define APPLICATION_VERIFIER_EXIT_THREAD_OWNS_LOCK 0x0200 -#define APPLICATION_VERIFIER_LOCK_IN_UNLOADED_DLL 0x0201 -#define APPLICATION_VERIFIER_LOCK_IN_FREED_HEAP 0x0202 -#define APPLICATION_VERIFIER_LOCK_DOUBLE_INITIALIZE 0x0203 -#define APPLICATION_VERIFIER_LOCK_IN_FREED_MEMORY 0x0204 -#define APPLICATION_VERIFIER_LOCK_CORRUPTED 0x0205 -#define APPLICATION_VERIFIER_LOCK_INVALID_OWNER 0x0206 -#define APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT 0x0207 -#define APPLICATION_VERIFIER_LOCK_INVALID_LOCK_COUNT 0x0208 -#define APPLICATION_VERIFIER_LOCK_OVER_RELEASED 0x0209 -#define APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED 0x0210 -#define APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED 0x0211 -#define APPLICATION_VERIFIER_LOCK_IN_FREED_VMEM 0x0212 -#define APPLICATION_VERIFIER_LOCK_IN_UNMAPPED_MEM 0x0213 -#define APPLICATION_VERIFIER_THREAD_NOT_LOCK_OWNER 0x0214 - -#define APPLICATION_VERIFIER_INVALID_HANDLE 0x0300 -#define APPLICATION_VERIFIER_INVALID_TLS_VALUE 0x0301 -#define APPLICATION_VERIFIER_INCORRECT_WAIT_CALL 0x0302 -#define APPLICATION_VERIFIER_NULL_HANDLE 0x0303 -#define APPLICATION_VERIFIER_WAIT_IN_DLLMAIN 0x0304 - -#define APPLICATION_VERIFIER_COM_ERROR 0x0400 -#define APPLICATION_VERIFIER_COM_API_IN_DLLMAIN 0x0401 -#define APPLICATION_VERIFIER_COM_UNHANDLED_EXCEPTION 0x0402 -#define APPLICATION_VERIFIER_COM_UNBALANCED_COINIT 0x0403 -#define APPLICATION_VERIFIER_COM_UNBALANCED_OLEINIT 0x0404 -#define APPLICATION_VERIFIER_COM_UNBALANCED_SWC 0x0405 -#define APPLICATION_VERIFIER_COM_NULL_DACL 0x0406 -#define APPLICATION_VERIFIER_COM_UNSAFE_IMPERSONATION 0x0407 -#define APPLICATION_VERIFIER_COM_SMUGGLED_WRAPPER 0x0408 -#define APPLICATION_VERIFIER_COM_SMUGGLED_PROXY 0x0409 -#define APPLICATION_VERIFIER_COM_CF_SUCCESS_WITH_NULL 0x040A -#define APPLICATION_VERIFIER_COM_GCO_SUCCESS_WITH_NULL 0x040B -#define APPLICATION_VERIFIER_COM_OBJECT_IN_FREED_MEMORY 0x040C -#define APPLICATION_VERIFIER_COM_OBJECT_IN_UNLOADED_DLL 0x040D -#define APPLICATION_VERIFIER_COM_VTBL_IN_FREED_MEMORY 0x040E -#define APPLICATION_VERIFIER_COM_VTBL_IN_UNLOADED_DLL 0x040F -#define APPLICATION_VERIFIER_COM_HOLDING_LOCKS_ON_CALL 0x0410 - -#define APPLICATION_VERIFIER_RPC_ERROR 0x0500 - -#define APPLICATION_VERIFIER_INVALID_FREEMEM 0x0600 -#define APPLICATION_VERIFIER_INVALID_ALLOCMEM 0x0601 -#define APPLICATION_VERIFIER_INVALID_MAPVIEW 0x0602 -#define APPLICATION_VERIFIER_PROBE_INVALID_ADDRESS 0x0603 -#define APPLICATION_VERIFIER_PROBE_FREE_MEM 0x0604 -#define APPLICATION_VERIFIER_PROBE_GUARD_PAGE 0x0605 -#define APPLICATION_VERIFIER_PROBE_NULL 0x0606 -#define APPLICATION_VERIFIER_PROBE_INVALID_START_OR_SIZE 0x0607 -#define APPLICATION_VERIFIER_SIZE_HEAP_UNEXPECTED_EXCEPTION 0x0618 - -#define VERIFIER_STOP(Code,Msg,P1,S1,P2,S2,P3,S3,P4,S4) { RtlApplicationVerifierStop ((Code),(Msg),(ULONG_PTR)(P1),(S1),(ULONG_PTR)(P2),(S2),(ULONG_PTR)(P3),(S3),(ULONG_PTR)(P4),(S4)); } - - VOID NTAPI RtlApplicationVerifierStop(ULONG_PTR Code,PSTR Message,ULONG_PTR Param1,PSTR Description1,ULONG_PTR Param2,PSTR Description2,ULONG_PTR Param3,PSTR Description3,ULONG_PTR Param4,PSTR Description4); - - typedef LONG (NTAPI *PVECTORED_EXCEPTION_HANDLER)(struct _EXCEPTION_POINTERS *ExceptionInfo); -#define SEF_DACL_AUTO_INHERIT 0x01 -#define SEF_SACL_AUTO_INHERIT 0x02 -#define SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT 0x04 -#define SEF_AVOID_PRIVILEGE_CHECK 0x08 -#define SEF_AVOID_OWNER_CHECK 0x10 -#define SEF_DEFAULT_OWNER_FROM_PARENT 0x20 -#define SEF_DEFAULT_GROUP_FROM_PARENT 0x40 - - typedef enum _HEAP_INFORMATION_CLASS { - HeapCompatibilityInformation - } HEAP_INFORMATION_CLASS; - - NTSYSAPI DWORD NTAPI RtlSetHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); - NTSYSAPI DWORD NTAPI RtlQueryHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); - DWORD NTAPI RtlMultipleAllocateHeap(PVOID HeapHandle,DWORD Flags,SIZE_T Size,DWORD Count,PVOID *Array); - DWORD NTAPI RtlMultipleFreeHeap(PVOID HeapHandle,DWORD Flags,DWORD Count,PVOID *Array); - -#define WT_EXECUTEDEFAULT 0x00000000 -#define WT_EXECUTEINIOTHREAD 0x00000001 -#define WT_EXECUTEINUITHREAD 0x00000002 -#define WT_EXECUTEINWAITTHREAD 0x00000004 -#define WT_EXECUTEONLYONCE 0x00000008 -#define WT_EXECUTEINTIMERTHREAD 0x00000020 -#define WT_EXECUTELONGFUNCTION 0x00000010 -#define WT_EXECUTEINPERSISTENTIOTHREAD 0x00000040 -#define WT_EXECUTEINPERSISTENTTHREAD 0x00000080 -#define WT_TRANSFER_IMPERSONATION 0x00000100 -#define WT_SET_MAX_THREADPOOL_THREADS(Flags,Limit) ((Flags) |= (Limit)<<16) - typedef VOID (NTAPI *WAITORTIMERCALLBACKFUNC)(PVOID,BOOLEAN); - typedef VOID (NTAPI *WORKERCALLBACKFUNC)(PVOID); - typedef VOID (NTAPI *APC_CALLBACK_FUNCTION)(DWORD ,PVOID,PVOID); - typedef - VOID - (NTAPI *PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); -#define WT_EXECUTEINLONGTHREAD 0x00000010 -#define WT_EXECUTEDELETEWAIT 0x00000008 - - typedef enum _ACTIVATION_CONTEXT_INFO_CLASS { - ActivationContextBasicInformation = 1,ActivationContextDetailedInformation = 2,AssemblyDetailedInformationInActivationContext = 3,FileInformationInAssemblyOfAssemblyInActivationContext = 4,MaxActivationContextInfoClass,AssemblyDetailedInformationInActivationContxt = 3,FileInformationInAssemblyOfAssemblyInActivationContxt = 4 - } ACTIVATION_CONTEXT_INFO_CLASS; - -#define ACTIVATIONCONTEXTINFOCLASS ACTIVATION_CONTEXT_INFO_CLASS - - typedef struct _ACTIVATION_CONTEXT_QUERY_INDEX { - DWORD ulAssemblyIndex; - DWORD ulFileIndexInAssembly; - } ACTIVATION_CONTEXT_QUERY_INDEX,*PACTIVATION_CONTEXT_QUERY_INDEX; - - typedef const struct _ACTIVATION_CONTEXT_QUERY_INDEX *PCACTIVATION_CONTEXT_QUERY_INDEX; - -#define ACTIVATION_CONTEXT_PATH_TYPE_NONE (1) -#define ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE (2) -#define ACTIVATION_CONTEXT_PATH_TYPE_URL (3) -#define ACTIVATION_CONTEXT_PATH_TYPE_ASSEMBLYREF (4) - - typedef struct _ASSEMBLY_FILE_DETAILED_INFORMATION { - DWORD ulFlags; - DWORD ulFilenameLength; - DWORD ulPathLength; - - PCWSTR lpFileName; - PCWSTR lpFilePath; - } ASSEMBLY_FILE_DETAILED_INFORMATION,*PASSEMBLY_FILE_DETAILED_INFORMATION; - typedef const ASSEMBLY_FILE_DETAILED_INFORMATION *PCASSEMBLY_FILE_DETAILED_INFORMATION; - -#define _ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION _ASSEMBLY_FILE_DETAILED_INFORMATION -#define ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION ASSEMBLY_FILE_DETAILED_INFORMATION -#define PASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PASSEMBLY_FILE_DETAILED_INFORMATION -#define PCASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PCASSEMBLY_FILE_DETAILED_INFORMATION - - typedef struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION { - DWORD ulFlags; - DWORD ulEncodedAssemblyIdentityLength; - DWORD ulManifestPathType; - DWORD ulManifestPathLength; - LARGE_INTEGER liManifestLastWriteTime; - DWORD ulPolicyPathType; - DWORD ulPolicyPathLength; - LARGE_INTEGER liPolicyLastWriteTime; - DWORD ulMetadataSatelliteRosterIndex; - DWORD ulManifestVersionMajor; - DWORD ulManifestVersionMinor; - DWORD ulPolicyVersionMajor; - DWORD ulPolicyVersionMinor; - DWORD ulAssemblyDirectoryNameLength; - PCWSTR lpAssemblyEncodedAssemblyIdentity; - PCWSTR lpAssemblyManifestPath; - PCWSTR lpAssemblyPolicyPath; - PCWSTR lpAssemblyDirectoryName; - DWORD ulFileCount; - } ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; - - typedef const struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; - - typedef struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION { - DWORD dwFlags; - DWORD ulFormatVersion; - DWORD ulAssemblyCount; - DWORD ulRootManifestPathType; - DWORD ulRootManifestPathChars; - DWORD ulRootConfigurationPathType; - DWORD ulRootConfigurationPathChars; - DWORD ulAppDirPathType; - DWORD ulAppDirPathChars; - PCWSTR lpRootManifestPath; - PCWSTR lpRootConfigurationPath; - PCWSTR lpAppDirPath; - } ACTIVATION_CONTEXT_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_DETAILED_INFORMATION; - - typedef const struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_DETAILED_INFORMATION; - -#define DLL_PROCESS_ATTACH 1 -#define DLL_THREAD_ATTACH 2 -#define DLL_THREAD_DETACH 3 -#define DLL_PROCESS_DETACH 0 -#define DLL_PROCESS_VERIFIER 4 - -#define EVENTLOG_SEQUENTIAL_READ 0x0001 -#define EVENTLOG_SEEK_READ 0x0002 -#define EVENTLOG_FORWARDS_READ 0x0004 -#define EVENTLOG_BACKWARDS_READ 0x0008 - -#define EVENTLOG_SUCCESS 0x0000 -#define EVENTLOG_ERROR_TYPE 0x0001 -#define EVENTLOG_WARNING_TYPE 0x0002 -#define EVENTLOG_INFORMATION_TYPE 0x0004 -#define EVENTLOG_AUDIT_SUCCESS 0x0008 -#define EVENTLOG_AUDIT_FAILURE 0x0010 - -#define EVENTLOG_START_PAIRED_EVENT 0x0001 -#define EVENTLOG_END_PAIRED_EVENT 0x0002 -#define EVENTLOG_END_ALL_PAIRED_EVENTS 0x0004 -#define EVENTLOG_PAIRED_EVENT_ACTIVE 0x0008 -#define EVENTLOG_PAIRED_EVENT_INACTIVE 0x0010 - - typedef struct _EVENTLOGRECORD { - DWORD Length; - DWORD Reserved; - DWORD RecordNumber; - DWORD TimeGenerated; - DWORD TimeWritten; - DWORD EventID; - WORD EventType; - WORD NumStrings; - WORD EventCategory; - WORD ReservedFlags; - DWORD ClosingRecordNumber; - DWORD StringOffset; - DWORD UserSidLength; - DWORD UserSidOffset; - DWORD DataLength; - DWORD DataOffset; - } EVENTLOGRECORD,*PEVENTLOGRECORD; - -#define MAXLOGICALLOGNAMESIZE 256 - - typedef struct _EVENTSFORLOGFILE{ - DWORD ulSize; - WCHAR szLogicalLogFile[MAXLOGICALLOGNAMESIZE]; - DWORD ulNumRecords; - EVENTLOGRECORD pEventLogRecords[]; - } EVENTSFORLOGFILE,*PEVENTSFORLOGFILE; - - typedef struct _PACKEDEVENTINFO{ - DWORD ulSize; - DWORD ulNumEventsForLogFile; - DWORD ulOffsets[]; - } PACKEDEVENTINFO,*PPACKEDEVENTINFO; - -#define KEY_QUERY_VALUE (0x0001) -#define KEY_SET_VALUE (0x0002) -#define KEY_CREATE_SUB_KEY (0x0004) -#define KEY_ENUMERATE_SUB_KEYS (0x0008) -#define KEY_NOTIFY (0x0010) -#define KEY_CREATE_LINK (0x0020) -#define KEY_WOW64_32KEY (0x0200) -#define KEY_WOW64_64KEY (0x0100) -#define KEY_WOW64_RES (0x0300) - -#define KEY_READ ((STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & (~SYNCHRONIZE)) -#define KEY_WRITE ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE)) -#define KEY_EXECUTE ((KEY_READ) & (~SYNCHRONIZE)) -#define KEY_ALL_ACCESS ((STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & (~SYNCHRONIZE)) -#define REG_OPTION_RESERVED (0x00000000L) - -#define REG_OPTION_NON_VOLATILE (0x00000000L) -#define REG_OPTION_VOLATILE (0x00000001L) -#define REG_OPTION_CREATE_LINK (0x00000002L) -#define REG_OPTION_BACKUP_RESTORE (0x00000004L) -#define REG_OPTION_OPEN_LINK (0x00000008L) -#define REG_LEGAL_OPTION (REG_OPTION_RESERVED | REG_OPTION_NON_VOLATILE | REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK | REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK) -#define REG_CREATED_NEW_KEY (0x00000001L) -#define REG_OPENED_EXISTING_KEY (0x00000002L) -#define REG_STANDARD_FORMAT 1 -#define REG_LATEST_FORMAT 2 -#define REG_NO_COMPRESSION 4 -#define REG_WHOLE_HIVE_VOLATILE (0x00000001L) -#define REG_REFRESH_HIVE (0x00000002L) -#define REG_NO_LAZY_FLUSH (0x00000004L) -#define REG_FORCE_RESTORE (0x00000008L) -#define REG_FORCE_UNLOAD 1 - -#define REG_NOTIFY_CHANGE_NAME (0x00000001L) -#define REG_NOTIFY_CHANGE_ATTRIBUTES (0x00000002L) -#define REG_NOTIFY_CHANGE_LAST_SET (0x00000004L) -#define REG_NOTIFY_CHANGE_SECURITY (0x00000008L) - -#define REG_LEGAL_CHANGE_FILTER (REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY) - -#define REG_NONE (0) -#define REG_SZ (1) -#define REG_EXPAND_SZ (2) - -#define REG_BINARY (3) -#define REG_DWORD (4) -#define REG_DWORD_LITTLE_ENDIAN (4) -#define REG_DWORD_BIG_ENDIAN (5) -#define REG_LINK (6) -#define REG_MULTI_SZ (7) -#define REG_RESOURCE_LIST (8) -#define REG_FULL_RESOURCE_DESCRIPTOR (9) -#define REG_RESOURCE_REQUIREMENTS_LIST (10) -#define REG_QWORD (11) -#define REG_QWORD_LITTLE_ENDIAN (11) - -#define SERVICE_KERNEL_DRIVER 0x00000001 -#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 -#define SERVICE_ADAPTER 0x00000004 -#define SERVICE_RECOGNIZER_DRIVER 0x00000008 - -#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER) - -#define SERVICE_WIN32_OWN_PROCESS 0x00000010 -#define SERVICE_WIN32_SHARE_PROCESS 0x00000020 -#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS) - -#define SERVICE_INTERACTIVE_PROCESS 0x00000100 - -#define SERVICE_TYPE_ALL (SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS) - -#define SERVICE_BOOT_START 0x00000000 -#define SERVICE_SYSTEM_START 0x00000001 -#define SERVICE_AUTO_START 0x00000002 -#define SERVICE_DEMAND_START 0x00000003 -#define SERVICE_DISABLED 0x00000004 - -#define SERVICE_ERROR_IGNORE 0x00000000 -#define SERVICE_ERROR_NORMAL 0x00000001 -#define SERVICE_ERROR_SEVERE 0x00000002 -#define SERVICE_ERROR_CRITICAL 0x00000003 - - typedef enum _CM_SERVICE_NODE_TYPE { - DriverType = SERVICE_KERNEL_DRIVER,FileSystemType = SERVICE_FILE_SYSTEM_DRIVER,Win32ServiceOwnProcess = SERVICE_WIN32_OWN_PROCESS, - Win32ServiceShareProcess = SERVICE_WIN32_SHARE_PROCESS,AdapterType = SERVICE_ADAPTER,RecognizerType = SERVICE_RECOGNIZER_DRIVER - } SERVICE_NODE_TYPE; - - typedef enum _CM_SERVICE_LOAD_TYPE { - BootLoad = SERVICE_BOOT_START,SystemLoad = SERVICE_SYSTEM_START,AutoLoad = SERVICE_AUTO_START,DemandLoad = SERVICE_DEMAND_START, - DisableLoad = SERVICE_DISABLED - } SERVICE_LOAD_TYPE; - - typedef enum _CM_ERROR_CONTROL_TYPE { - IgnoreError = SERVICE_ERROR_IGNORE,NormalError = SERVICE_ERROR_NORMAL,SevereError = SERVICE_ERROR_SEVERE,CriticalError = SERVICE_ERROR_CRITICAL - } SERVICE_ERROR_TYPE; - -#define TAPE_ERASE_SHORT 0L -#define TAPE_ERASE_LONG 1L - - typedef struct _TAPE_ERASE { - DWORD Type; - BOOLEAN Immediate; - } TAPE_ERASE,*PTAPE_ERASE; - -#define TAPE_LOAD 0L -#define TAPE_UNLOAD 1L -#define TAPE_TENSION 2L -#define TAPE_LOCK 3L -#define TAPE_UNLOCK 4L -#define TAPE_FORMAT 5L - - typedef struct _TAPE_PREPARE { - DWORD Operation; - BOOLEAN Immediate; - } TAPE_PREPARE,*PTAPE_PREPARE; - -#define TAPE_SETMARKS 0L -#define TAPE_FILEMARKS 1L -#define TAPE_SHORT_FILEMARKS 2L -#define TAPE_LONG_FILEMARKS 3L - - typedef struct _TAPE_WRITE_MARKS { - DWORD Type; - DWORD Count; - BOOLEAN Immediate; - } TAPE_WRITE_MARKS,*PTAPE_WRITE_MARKS; - -#define TAPE_ABSOLUTE_POSITION 0L -#define TAPE_LOGICAL_POSITION 1L -#define TAPE_PSEUDO_LOGICAL_POSITION 2L - - typedef struct _TAPE_GET_POSITION { - DWORD Type; - DWORD Partition; - LARGE_INTEGER Offset; - } TAPE_GET_POSITION,*PTAPE_GET_POSITION; - -#define TAPE_REWIND 0L -#define TAPE_ABSOLUTE_BLOCK 1L -#define TAPE_LOGICAL_BLOCK 2L -#define TAPE_PSEUDO_LOGICAL_BLOCK 3L -#define TAPE_SPACE_END_OF_DATA 4L -#define TAPE_SPACE_RELATIVE_BLOCKS 5L -#define TAPE_SPACE_FILEMARKS 6L -#define TAPE_SPACE_SEQUENTIAL_FMKS 7L -#define TAPE_SPACE_SETMARKS 8L -#define TAPE_SPACE_SEQUENTIAL_SMKS 9L - - typedef struct _TAPE_SET_POSITION { - DWORD Method; - DWORD Partition; - LARGE_INTEGER Offset; - BOOLEAN Immediate; - } TAPE_SET_POSITION,*PTAPE_SET_POSITION; - -#define TAPE_DRIVE_FIXED 0x00000001 -#define TAPE_DRIVE_SELECT 0x00000002 -#define TAPE_DRIVE_INITIATOR 0x00000004 - -#define TAPE_DRIVE_ERASE_SHORT 0x00000010 -#define TAPE_DRIVE_ERASE_LONG 0x00000020 -#define TAPE_DRIVE_ERASE_BOP_ONLY 0x00000040 -#define TAPE_DRIVE_ERASE_IMMEDIATE 0x00000080 - -#define TAPE_DRIVE_TAPE_CAPACITY 0x00000100 -#define TAPE_DRIVE_TAPE_REMAINING 0x00000200 -#define TAPE_DRIVE_FIXED_BLOCK 0x00000400 -#define TAPE_DRIVE_VARIABLE_BLOCK 0x00000800 - -#define TAPE_DRIVE_WRITE_PROTECT 0x00001000 -#define TAPE_DRIVE_EOT_WZ_SIZE 0x00002000 - -#define TAPE_DRIVE_ECC 0x00010000 -#define TAPE_DRIVE_COMPRESSION 0x00020000 -#define TAPE_DRIVE_PADDING 0x00040000 -#define TAPE_DRIVE_REPORT_SMKS 0x00080000 - -#define TAPE_DRIVE_GET_ABSOLUTE_BLK 0x00100000 -#define TAPE_DRIVE_GET_LOGICAL_BLK 0x00200000 -#define TAPE_DRIVE_SET_EOT_WZ_SIZE 0x00400000 - -#define TAPE_DRIVE_EJECT_MEDIA 0x01000000 -#define TAPE_DRIVE_CLEAN_REQUESTS 0x02000000 -#define TAPE_DRIVE_SET_CMP_BOP_ONLY 0x04000000 - -#define TAPE_DRIVE_RESERVED_BIT 0x80000000 - -#define TAPE_DRIVE_LOAD_UNLOAD 0x80000001 -#define TAPE_DRIVE_TENSION 0x80000002 -#define TAPE_DRIVE_LOCK_UNLOCK 0x80000004 -#define TAPE_DRIVE_REWIND_IMMEDIATE 0x80000008 - -#define TAPE_DRIVE_SET_BLOCK_SIZE 0x80000010 -#define TAPE_DRIVE_LOAD_UNLD_IMMED 0x80000020 -#define TAPE_DRIVE_TENSION_IMMED 0x80000040 -#define TAPE_DRIVE_LOCK_UNLK_IMMED 0x80000080 - -#define TAPE_DRIVE_SET_ECC 0x80000100 -#define TAPE_DRIVE_SET_COMPRESSION 0x80000200 -#define TAPE_DRIVE_SET_PADDING 0x80000400 -#define TAPE_DRIVE_SET_REPORT_SMKS 0x80000800 - -#define TAPE_DRIVE_ABSOLUTE_BLK 0x80001000 -#define TAPE_DRIVE_ABS_BLK_IMMED 0x80002000 -#define TAPE_DRIVE_LOGICAL_BLK 0x80004000 -#define TAPE_DRIVE_LOG_BLK_IMMED 0x80008000 - -#define TAPE_DRIVE_END_OF_DATA 0x80010000 -#define TAPE_DRIVE_RELATIVE_BLKS 0x80020000 -#define TAPE_DRIVE_FILEMARKS 0x80040000 -#define TAPE_DRIVE_SEQUENTIAL_FMKS 0x80080000 - -#define TAPE_DRIVE_SETMARKS 0x80100000 -#define TAPE_DRIVE_SEQUENTIAL_SMKS 0x80200000 -#define TAPE_DRIVE_REVERSE_POSITION 0x80400000 -#define TAPE_DRIVE_SPACE_IMMEDIATE 0x80800000 - -#define TAPE_DRIVE_WRITE_SETMARKS 0x81000000 -#define TAPE_DRIVE_WRITE_FILEMARKS 0x82000000 -#define TAPE_DRIVE_WRITE_SHORT_FMKS 0x84000000 -#define TAPE_DRIVE_WRITE_LONG_FMKS 0x88000000 - -#define TAPE_DRIVE_WRITE_MARK_IMMED 0x90000000 -#define TAPE_DRIVE_FORMAT 0xA0000000 -#define TAPE_DRIVE_FORMAT_IMMEDIATE 0xC0000000 -#define TAPE_DRIVE_HIGH_FEATURES 0x80000000 - - typedef struct _TAPE_GET_DRIVE_PARAMETERS { - BOOLEAN ECC; - BOOLEAN Compression; - BOOLEAN DataPadding; - BOOLEAN ReportSetmarks; - DWORD DefaultBlockSize; - DWORD MaximumBlockSize; - DWORD MinimumBlockSize; - DWORD MaximumPartitionCount; - DWORD FeaturesLow; - DWORD FeaturesHigh; - DWORD EOTWarningZoneSize; - } TAPE_GET_DRIVE_PARAMETERS,*PTAPE_GET_DRIVE_PARAMETERS; - - typedef struct _TAPE_SET_DRIVE_PARAMETERS { - BOOLEAN ECC; - BOOLEAN Compression; - BOOLEAN DataPadding; - BOOLEAN ReportSetmarks; - DWORD EOTWarningZoneSize; - } TAPE_SET_DRIVE_PARAMETERS,*PTAPE_SET_DRIVE_PARAMETERS; - - typedef struct _TAPE_GET_MEDIA_PARAMETERS { - LARGE_INTEGER Capacity; - LARGE_INTEGER Remaining; - DWORD BlockSize; - DWORD PartitionCount; - BOOLEAN WriteProtected; - } TAPE_GET_MEDIA_PARAMETERS,*PTAPE_GET_MEDIA_PARAMETERS; - - typedef struct _TAPE_SET_MEDIA_PARAMETERS { - DWORD BlockSize; - } TAPE_SET_MEDIA_PARAMETERS,*PTAPE_SET_MEDIA_PARAMETERS; - -#define TAPE_FIXED_PARTITIONS 0L -#define TAPE_SELECT_PARTITIONS 1L -#define TAPE_INITIATOR_PARTITIONS 2L - - typedef struct _TAPE_CREATE_PARTITION { - DWORD Method; - DWORD Count; - DWORD Size; - } TAPE_CREATE_PARTITION,*PTAPE_CREATE_PARTITION; - -#define TAPE_QUERY_DRIVE_PARAMETERS 0L -#define TAPE_QUERY_MEDIA_CAPACITY 1L -#define TAPE_CHECK_FOR_DRIVE_PROBLEM 2L -#define TAPE_QUERY_IO_ERROR_DATA 3L -#define TAPE_QUERY_DEVICE_ERROR_DATA 4L - - typedef struct _TAPE_WMI_OPERATIONS { - DWORD Method; - DWORD DataBufferSize; - PVOID DataBuffer; - } TAPE_WMI_OPERATIONS,*PTAPE_WMI_OPERATIONS; - - typedef enum _TAPE_DRIVE_PROBLEM_TYPE { - TapeDriveProblemNone,TapeDriveReadWriteWarning,TapeDriveReadWriteError,TapeDriveReadWarning,TapeDriveWriteWarning,TapeDriveReadError,TapeDriveWriteError,TapeDriveHardwareError,TapeDriveUnsupportedMedia,TapeDriveScsiConnectionError,TapeDriveTimetoClean,TapeDriveCleanDriveNow,TapeDriveMediaLifeExpired,TapeDriveSnappedTape - } TAPE_DRIVE_PROBLEM_TYPE; - -#if defined(__x86_64) - __CRT_INLINE struct _TEB *NtCurrentTeb(VOID) { return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB,Self)); } - __CRT_INLINE PVOID GetCurrentFiber(VOID) { return(PVOID)__readgsqword(FIELD_OFFSET(NT_TIB,FiberData)); } - __CRT_INLINE PVOID GetFiberData(VOID) { - return *(PVOID *)GetCurrentFiber(); - } -#endif - -#if(defined(_X86_) && !defined(__x86_64)) -#define PcTeb 0x18 - __CRT_INLINE struct _TEB *NtCurrentTeb(void) { - struct _TEB *ret; - __asm__ volatile ("movl %%fs:0x18,%0" - : "=r" (ret)); - return ret; - } -#endif - -#define ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION (1) -#define ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION (2) -#define ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION (3) -#define ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION (4) -#define ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION (5) -#define ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION (6) -#define ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION (7) -#define ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE (8) -#define ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES (9) -#define ACTIVATION_CONTEXT_SECTION_APPLICATION_SETTINGS (10) - -#ifdef __cplusplus - } -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINNT_ +#define _WINNT_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#define ANYSIZE_ARRAY 1 + +//gr #include + +#define RESTRICTED_POINTER + +#ifndef __CRT_UNALIGNED +#define __CRT_UNALIGNED +#endif + +#if defined(__ia64__) || defined(__x86_64) +#define UNALIGNED __CRT_UNALIGNED +#ifdef _WIN64 +#define UNALIGNED64 __CRT_UNALIGNED +#else +#define UNALIGNED64 +#endif +#else +#define UNALIGNED +#define UNALIGNED64 +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && (defined(_X86_) && !defined(__x86_64)) +#define I_X86_ +#endif + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(__x86_64) +#define _AMD64_ +#endif + +#if !defined(I_X86_) && !(defined(_X86_) && !defined(__x86_64)) && !defined(_AMD64_) && defined(__ia64__) +#if !defined(_IA64_) +#define _IA64_ +#endif +#endif + + +#ifdef _WIN64 +#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) +#define MEMORY_ALLOCATION_ALIGNMENT 16 +#else +#define MAX_NATURAL_ALIGNMENT sizeof(DWORD) +#define MEMORY_ALLOCATION_ALIGNMENT 8 +#endif + +#ifdef __cplusplus +#define TYPE_ALIGNMENT(t) __alignof__ (t) +#else +#define TYPE_ALIGNMENT(t) FIELD_OFFSET(struct { char x; t test; },test) +#endif + +#ifdef _WIN64 +#ifdef _AMD64_ +#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) +#elif defined(_IA64_) +#define PROBE_ALIGNMENT(_s) (TYPE_ALIGNMENT(_s) > TYPE_ALIGNMENT(DWORD) ? TYPE_ALIGNMENT(_s) : TYPE_ALIGNMENT(DWORD)) +#else +#error No Target Architecture +#endif +#define PROBE_ALIGNMENT32(_s) TYPE_ALIGNMENT(DWORD) +#else +#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD) +#endif + +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] + +#include + +#if defined(_X86_) || defined(__ia64__) || defined(__x86_64) +#define DECLSPEC_IMPORT __declspec(dllimport) +#else +#define DECLSPEC_IMPORT +#endif + +#ifndef DECLSPEC_NORETURN +#define DECLSPEC_NORETURN __declspec(noreturn) +#endif + +#ifndef DECLSPEC_ALIGN +#define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) +#endif + +#ifndef SYSTEM_CACHE_ALIGNMENT_SIZE +#if defined(_AMD64_) || defined(I_X86_) +#define SYSTEM_CACHE_ALIGNMENT_SIZE 64 +#else +#define SYSTEM_CACHE_ALIGNMENT_SIZE 128 +#endif +#endif + +#ifndef DECLSPEC_CACHEALIGN +#define DECLSPEC_CACHEALIGN DECLSPEC_ALIGN(SYSTEM_CACHE_ALIGNMENT_SIZE) +#endif + +#ifndef DECLSPEC_UUID +#define DECLSPEC_UUID(x) +#endif + +#ifndef DECLSPEC_NOVTABLE +#define DECLSPEC_NOVTABLE +#endif + +#ifndef DECLSPEC_SELECTANY +#define DECLSPEC_SELECTANY __declspec(selectany) +#endif + +#ifndef NOP_FUNCTION +#define NOP_FUNCTION (void)0 +#endif + +#ifndef DECLSPEC_NOINLINE +#define DECLSPEC_NOINLINE +#endif + +#ifndef FORCEINLINE +#define FORCEINLINE static __inline__ +#endif + +#ifndef DECLSPEC_DEPRECATED +#define DECLSPEC_DEPRECATED __declspec(deprecated) +#define DEPRECATE_SUPPORTED +#endif + +#define DECLSPEC_DEPRECATED_DDK +#define PRAGMA_DEPRECATED_DDK 0 + + typedef void *PVOID; + typedef void *PVOID64; + +#define NTAPI __stdcall +#define NTSYSAPI DECLSPEC_IMPORT +#define NTSYSCALLAPI DECLSPEC_IMPORT + +#ifndef VOID +#define VOID void + typedef char CHAR; + typedef short SHORT; + typedef long LONG; +#endif + + typedef wchar_t WCHAR; + typedef WCHAR *PWCHAR,*LPWCH,*PWCH; + typedef CONST WCHAR *LPCWCH,*PCWCH; + typedef WCHAR *NWPSTR,*LPWSTR,*PWSTR; + typedef PWSTR *PZPWSTR; + typedef CONST PWSTR *PCZPWSTR; + typedef WCHAR UNALIGNED *LPUWSTR,*PUWSTR; + typedef CONST WCHAR *LPCWSTR,*PCWSTR; + typedef PCWSTR *PZPCWSTR; + typedef CONST WCHAR UNALIGNED *LPCUWSTR,*PCUWSTR; + typedef CHAR *PCHAR,*LPCH,*PCH; + typedef CONST CHAR *LPCCH,*PCCH; + typedef CHAR *NPSTR,*LPSTR,*PSTR; + typedef PSTR *PZPSTR; + typedef CONST PSTR *PCZPSTR; + typedef CONST CHAR *LPCSTR,*PCSTR; + typedef PCSTR *PZPCSTR; + +#ifdef UNICODE +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED + typedef WCHAR TCHAR,*PTCHAR; + typedef WCHAR TBYTE ,*PTBYTE; +#endif + + typedef LPWSTR LPTCH,PTCH; + typedef LPWSTR PTSTR,LPTSTR; + typedef LPCWSTR PCTSTR,LPCTSTR; + typedef LPUWSTR PUTSTR,LPUTSTR; + typedef LPCUWSTR PCUTSTR,LPCUTSTR; + typedef LPWSTR LP; +#define __TEXT(quote) L##quote +#else +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED + typedef char TCHAR,*PTCHAR; + typedef unsigned char TBYTE ,*PTBYTE; +#endif + + typedef LPSTR LPTCH,PTCH; + typedef LPSTR PTSTR,LPTSTR,PUTSTR,LPUTSTR; + typedef LPCSTR PCTSTR,LPCTSTR,PCUTSTR,LPCUTSTR; +#define __TEXT(quote) quote +#endif + +#define TEXT(quote) __TEXT(quote) + + typedef SHORT *PSHORT; + typedef LONG *PLONG; + + typedef void *HANDLE; +#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name + typedef HANDLE *PHANDLE; + + typedef BYTE FCHAR; + typedef WORD FSHORT; + typedef DWORD FLONG; + +#ifndef _HRESULT_DEFINED +#define _HRESULT_DEFINED + typedef LONG HRESULT; +#endif + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C extern +#endif + +#define STDMETHODCALLTYPE WINAPI +#define STDMETHODVCALLTYPE __cdecl +#define STDAPICALLTYPE WINAPI +#define STDAPIVCALLTYPE __cdecl +#define STDAPI EXTERN_C HRESULT WINAPI +#define STDAPI_(type) EXTERN_C type WINAPI +#define STDMETHODIMP HRESULT WINAPI +#define STDMETHODIMP_(type) type WINAPI +#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE +#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE +#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE +#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE + + typedef char CCHAR; +#ifndef _LCID_DEFINED +#define _LCID_DEFINED +typedef DWORD LCID; +#endif + typedef PDWORD PLCID; +#ifndef _LANGID_DEFINED +#define _LANGID_DEFINED + typedef WORD LANGID; +#endif +#define APPLICATION_ERROR_MASK 0x20000000 +#define ERROR_SEVERITY_SUCCESS 0x00000000 +#define ERROR_SEVERITY_INFORMATIONAL 0x40000000 +#define ERROR_SEVERITY_WARNING 0x80000000 +#define ERROR_SEVERITY_ERROR 0xC0000000 + +#ifdef __ia64__ + __declspec(align(16)) +#endif + typedef struct _FLOAT128 { + __int64 LowPart; + __int64 HighPart; + } FLOAT128; + + typedef FLOAT128 *PFLOAT128; + +#define _ULONGLONG_ +#if((!(defined(_X86_) && !defined(__x86_64)) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64))) + typedef __int64 LONGLONG; + typedef unsigned __int64 ULONGLONG; + +#define MAXLONGLONG (0x7fffffffffffffff) +#else + + typedef double LONGLONG; + typedef double ULONGLONG; +#endif + + typedef LONGLONG *PLONGLONG; + typedef ULONGLONG *PULONGLONG; + + typedef LONGLONG USN; + + typedef union _LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + }; + struct { + DWORD LowPart; + LONG HighPart; + } u; + LONGLONG QuadPart; + } LARGE_INTEGER; + + typedef LARGE_INTEGER *PLARGE_INTEGER; + + typedef union _ULARGE_INTEGER { + struct { + DWORD LowPart; + DWORD HighPart; + }; + struct { + DWORD LowPart; + DWORD HighPart; + } u; + ULONGLONG QuadPart; + } ULARGE_INTEGER; + + typedef ULARGE_INTEGER *PULARGE_INTEGER; + + typedef struct _LUID { + DWORD LowPart; + LONG HighPart; + } LUID,*PLUID; + +#define _DWORDLONG_ + typedef ULONGLONG DWORDLONG; + typedef DWORDLONG *PDWORDLONG; + +#ifdef RC_INVOKED +#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) +#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) +#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) +#elif (defined(_X86_) && !defined(__x86_64)) +#define Int32x32To64(a,b) (LONGLONG)((LONGLONG)(LONG)(a) *(LONG)(b)) +#define UInt32x32To64(a,b) (ULONGLONG)((ULONGLONG)(DWORD)(a) *(DWORD)(b)) +#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(b)) +#elif defined(__ia64__) || defined(__x86_64) +#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b))) +#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b))) +#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b)) +#else +#error Must define a target architecture. +#endif + +#define Int64ShraMod32(a,b) ((LONGLONG)(a) >> (b)) +#define Int64ShllMod32(a,b) ((ULONGLONG)(a) << (b)) + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __x86_64 + +#define RotateLeft8 _rotl8 +#define RotateLeft16 _rotl16 +#define RotateRight8 _rotr8 +#define RotateRight16 _rotr16 + + unsigned char __cdecl _rotl8(unsigned char Value,unsigned char Shift); + unsigned short __cdecl _rotl16(unsigned short Value,unsigned char Shift); + unsigned char __cdecl _rotr8(unsigned char Value,unsigned char Shift); + unsigned short __cdecl _rotr16(unsigned short Value,unsigned char Shift); +#endif + +#define RotateLeft32 _rotl +#define RotateLeft64 _rotl64 +#define RotateRight32 _rotr +#define RotateRight64 _rotr64 + + unsigned int __cdecl _rotl(unsigned int Value,int Shift); + unsigned __int64 __cdecl _rotl64(unsigned __int64 Value,int Shift); + unsigned int __cdecl _rotr(unsigned int Value,int Shift); + unsigned __int64 __cdecl _rotr64(unsigned __int64 Value,int Shift); +#ifdef __cplusplus + } +#endif + +#define ANSI_NULL ((CHAR)0) +#define UNICODE_NULL ((WCHAR)0) +#define UNICODE_STRING_MAX_BYTES ((WORD) 65534) +#define UNICODE_STRING_MAX_CHARS (32767) + +#ifndef _BOOLEAN_ +#define _BOOLEAN_ + typedef BYTE BOOLEAN; +#endif + typedef BOOLEAN *PBOOLEAN; + + typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; + } LIST_ENTRY,*PLIST_ENTRY,*RESTRICTED_POINTER PRLIST_ENTRY; + + typedef struct _SINGLE_LIST_ENTRY { + struct _SINGLE_LIST_ENTRY *Next; + } SINGLE_LIST_ENTRY,*PSINGLE_LIST_ENTRY; + + typedef struct LIST_ENTRY32 { + DWORD Flink; + DWORD Blink; + } LIST_ENTRY32; + typedef LIST_ENTRY32 *PLIST_ENTRY32; + + typedef struct LIST_ENTRY64 { + ULONGLONG Flink; + ULONGLONG Blink; + } LIST_ENTRY64; + typedef LIST_ENTRY64 *PLIST_ENTRY64; + +#include + +#ifndef __OBJECTID_DEFINED +#define __OBJECTID_DEFINED + typedef struct _OBJECTID { + GUID Lineage; + DWORD Uniquifier; + } OBJECTID; +#endif + +#define MINCHAR 0x80 +#define MAXCHAR 0x7f +#define MINSHORT 0x8000 +#define MAXSHORT 0x7fff +#define MINLONG 0x80000000 +#define MAXLONG 0x7fffffff +#define MAXBYTE 0xff +#define MAXWORD 0xffff +#define MAXDWORD 0xffffffff + +#define FIELD_OFFSET(type,field) ((LONG)(LONG_PTR)&(((type *)0)->field)) +#define RTL_FIELD_SIZE(type,field) (sizeof(((type *)0)->field)) +#define RTL_SIZEOF_THROUGH_FIELD(type,field) (FIELD_OFFSET(type,field) + RTL_FIELD_SIZE(type,field)) +#define RTL_CONTAINS_FIELD(Struct,Size,Field) ((((PCHAR)(&(Struct)->Field)) + sizeof((Struct)->Field)) <= (((PCHAR)(Struct))+(Size))) +#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) +#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A) + +#ifdef ENABLE_RTL_NUMBER_OF_V2 +#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V2(A) +#else +#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V1(A) +#endif + +#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A) +#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) + +#define RTL_FIELD_TYPE(type,field) (((type*)0)->field) +#define RTL_NUMBER_OF_FIELD(type,field) (RTL_NUMBER_OF(RTL_FIELD_TYPE(type,field))) +#define RTL_PADDING_BETWEEN_FIELDS(T,F1,F2) ((FIELD_OFFSET(T,F2) > FIELD_OFFSET(T,F1)) ? (FIELD_OFFSET(T,F2) - FIELD_OFFSET(T,F1) - RTL_FIELD_SIZE(T,F1)) : (FIELD_OFFSET(T,F1) - FIELD_OFFSET(T,F2) - RTL_FIELD_SIZE(T,F2))) + +#ifdef __cplusplus +#define RTL_CONST_CAST(type) const_cast +#else +#define RTL_CONST_CAST(type) (type) +#endif + +#define RTL_BITS_OF(sizeOfArg) (sizeof(sizeOfArg) *8) +#define RTL_BITS_OF_FIELD(type,field) (RTL_BITS_OF(RTL_FIELD_TYPE(type,field))) +#define CONTAINING_RECORD(address,type,field) ((type *)((PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field))) + +#define VER_SERVER_NT 0x80000000 +#define VER_WORKSTATION_NT 0x40000000 +#define VER_SUITE_SMALLBUSINESS 0x00000001 +#define VER_SUITE_ENTERPRISE 0x00000002 +#define VER_SUITE_BACKOFFICE 0x00000004 +#define VER_SUITE_COMMUNICATIONS 0x00000008 +#define VER_SUITE_TERMINAL 0x00000010 +#define VER_SUITE_SMALLBUSINESS_RESTRICTED 0x00000020 +#define VER_SUITE_EMBEDDEDNT 0x00000040 +#define VER_SUITE_DATACENTER 0x00000080 +#define VER_SUITE_SINGLEUSERTS 0x00000100 +#define VER_SUITE_PERSONAL 0x00000200 +#define VER_SUITE_BLADE 0x00000400 +#define VER_SUITE_EMBEDDED_RESTRICTED 0x00000800 +#define VER_SUITE_SECURITY_APPLIANCE 0x00001000 +#define VER_SUITE_STORAGE_SERVER 0x00002000 +#define VER_SUITE_COMPUTE_SERVER 0x00004000 + +#define PRODUCT_UNDEFINED 0x0 + +#define PRODUCT_ULTIMATE 0x1 +#define PRODUCT_HOME_BASIC 0x2 +#define PRODUCT_HOME_PREMIUM 0x3 +#define PRODUCT_ENTERPRISE 0x4 +#define PRODUCT_HOME_BASIC_N 0x5 +#define PRODUCT_BUSINESS 0x6 +#define PRODUCT_STANDARD_SERVER 0x7 +#define PRODUCT_DATACENTER_SERVER 0x8 +#define PRODUCT_SMALLBUSINESS_SERVER 0x9 +#define PRODUCT_ENTERPRISE_SERVER 0xa +#define PRODUCT_STARTER 0xb +#define PRODUCT_DATACENTER_SERVER_CORE 0xc +#define PRODUCT_STANDARD_SERVER_CORE 0xd +#define PRODUCT_ENTERPRISE_SERVER_CORE 0xe +#define PRODUCT_ENTERPRISE_SERVER_IA64 0xf +#define PRODUCT_BUSINESS_N 0x10 +#define PRODUCT_WEB_SERVER 0x11 +#define PRODUCT_CLUSTER_SERVER 0x12 +#define PRODUCT_HOME_SERVER 0x13 +#define PRODUCT_STORAGE_EXPRESS_SERVER 0x14 +#define PRODUCT_STORAGE_STANDARD_SERVER 0x15 +#define PRODUCT_STORAGE_WORKGROUP_SERVER 0x16 +#define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x17 +#define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x18 +#define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x19 + +#define PRODUCT_UNLICENSED 0xabcdabcd + +#define LANG_NEUTRAL 0x00 +#define LANG_INVARIANT 0x7f + +#define LANG_AFRIKAANS 0x36 +#define LANG_ALBANIAN 0x1c +#define LANG_ALSATIAN 0x84 +#define LANG_AMHARIC 0x5e +#define LANG_ARABIC 0x01 +#define LANG_ARMENIAN 0x2b +#define LANG_ASSAMESE 0x4d +#define LANG_AZERI 0x2c +#define LANG_BASHKIR 0x6d +#define LANG_BASQUE 0x2d +#define LANG_BELARUSIAN 0x23 +#define LANG_BENGALI 0x45 +#define LANG_BRETON 0x7e +#define LANG_BOSNIAN 0x1a +#define LANG_BOSNIAN_NEUTRAL 0x781a +#define LANG_BULGARIAN 0x02 +#define LANG_CATALAN 0x03 +#define LANG_CHINESE 0x04 +#define LANG_CHINESE_SIMPLIFIED 0x04 +#define LANG_CHINESE_TRADITIONAL 0x7c04 +#define LANG_CORSICAN 0x83 +#define LANG_CROATIAN 0x1a +#define LANG_CZECH 0x05 +#define LANG_DANISH 0x06 +#define LANG_DARI 0x8c +#define LANG_DIVEHI 0x65 +#define LANG_DUTCH 0x13 +#define LANG_ENGLISH 0x09 +#define LANG_ESTONIAN 0x25 +#define LANG_FAEROESE 0x38 +#define LANG_FARSI 0x29 +#define LANG_FILIPINO 0x64 +#define LANG_FINNISH 0x0b +#define LANG_FRENCH 0x0c +#define LANG_FRISIAN 0x62 +#define LANG_GALICIAN 0x56 +#define LANG_GEORGIAN 0x37 +#define LANG_GERMAN 0x07 +#define LANG_GREEK 0x08 +#define LANG_GREENLANDIC 0x6f +#define LANG_GUJARATI 0x47 +#define LANG_HAUSA 0x68 +#define LANG_HEBREW 0x0d +#define LANG_HINDI 0x39 +#define LANG_HUNGARIAN 0x0e +#define LANG_ICELANDIC 0x0f +#define LANG_IGBO 0x70 +#define LANG_INDONESIAN 0x21 +#define LANG_INUKTITUT 0x5d +#define LANG_IRISH 0x3c +#define LANG_ITALIAN 0x10 +#define LANG_JAPANESE 0x11 +#define LANG_KANNADA 0x4b +#define LANG_KASHMIRI 0x60 +#define LANG_KAZAK 0x3f +#define LANG_KHMER 0x53 +#define LANG_KICHE 0x86 +#define LANG_KINYARWANDA 0x87 +#define LANG_KONKANI 0x57 +#define LANG_KOREAN 0x12 +#define LANG_KYRGYZ 0x40 +#define LANG_LAO 0x54 +#define LANG_LATVIAN 0x26 +#define LANG_LITHUANIAN 0x27 +#define LANG_LOWER_SORBIAN 0x2e +#define LANG_LUXEMBOURGISH 0x6e +#define LANG_MACEDONIAN 0x2f +#define LANG_MALAY 0x3e +#define LANG_MALAYALAM 0x4c +#define LANG_MALTESE 0x3a +#define LANG_MANIPURI 0x58 +#define LANG_MAORI 0x81 +#define LANG_MAPUDUNGUN 0x7a +#define LANG_MARATHI 0x4e +#define LANG_MOHAWK 0x7c +#define LANG_MONGOLIAN 0x50 +#define LANG_NEPALI 0x61 +#define LANG_NORWEGIAN 0x14 +#define LANG_OCCITAN 0x82 +#define LANG_ORIYA 0x48 +#define LANG_PASHTO 0x63 +#define LANG_PERSIAN 0x29 +#define LANG_POLISH 0x15 +#define LANG_PORTUGUESE 0x16 +#define LANG_PUNJABI 0x46 +#define LANG_QUECHUA 0x6b +#define LANG_ROMANIAN 0x18 +#define LANG_RUSSIAN 0x19 +#define LANG_SAMI 0x3b +#define LANG_ROMANSH 0x17 +#define LANG_SANSKRIT 0x4f +#define LANG_SERBIAN 0x1a +#define LANG_SERBIAN_NEUTRAL 0x7c1a +#define LANG_SINDHI 0x59 +#define LANG_SINHALESE 0x5b +#define LANG_SLOVAK 0x1b +#define LANG_SLOVENIAN 0x24 +#define LANG_SOTHO 0x6c +#define LANG_SPANISH 0x0a +#define LANG_SWAHILI 0x41 +#define LANG_SWEDISH 0x1d +#define LANG_SYRIAC 0x5a +#define LANG_TAJIK 0x28 +#define LANG_TAMAZIGHT 0x5f +#define LANG_TAMIL 0x49 +#define LANG_TATAR 0x44 +#define LANG_TELUGU 0x4a +#define LANG_THAI 0x1e +#define LANG_TIBETAN 0x51 +#define LANG_TIGRIGNA 0x73 +#define LANG_TSWANA 0x32 +#define LANG_TURKISH 0x1f +#define LANG_TURKMEN 0x42 +#define LANG_UIGHUR 0x80 +#define LANG_UKRAINIAN 0x22 +#define LANG_UPPER_SORBIAN 0x2e +#define LANG_URDU 0x20 +#define LANG_UZBEK 0x43 +#define LANG_VIETNAMESE 0x2a +#define LANG_WELSH 0x52 +#define LANG_WOLOF 0x88 +#define LANG_XHOSA 0x34 +#define LANG_YAKUT 0x85 +#define LANG_YI 0x78 +#define LANG_YORUBA 0x6a +#define LANG_ZULU 0x35 + +#define SUBLANG_NEUTRAL 0x0 +#define SUBLANG_DEFAULT 0x1 +#define SUBLANG_SYS_DEFAULT 0x2 +#define SUBLANG_CUSTOM_DEFAULT 0x3 +#define SUBLANG_CUSTOM_UNSPECIFIED 0x4 +#define SUBLANG_UI_CUSTOM_DEFAULT 0x5 + +#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 +#define SUBLANG_ARABIC_IRAQ 0x02 +#define SUBLANG_ARABIC_EGYPT 0x03 +#define SUBLANG_ARABIC_LIBYA 0x04 +#define SUBLANG_ARABIC_ALGERIA 0x05 +#define SUBLANG_ARABIC_MOROCCO 0x06 +#define SUBLANG_ARABIC_TUNISIA 0x07 +#define SUBLANG_ARABIC_OMAN 0x08 +#define SUBLANG_ARABIC_YEMEN 0x09 +#define SUBLANG_ARABIC_SYRIA 0x0a +#define SUBLANG_ARABIC_JORDAN 0x0b +#define SUBLANG_ARABIC_LEBANON 0x0c +#define SUBLANG_ARABIC_KUWAIT 0x0d +#define SUBLANG_ARABIC_UAE 0x0e +#define SUBLANG_ARABIC_BAHRAIN 0x0f +#define SUBLANG_ARABIC_QATAR 0x10 +#define SUBLANG_AZERI_LATIN 0x01 +#define SUBLANG_AZERI_CYRILLIC 0x02 +#define SUBLANG_CHINESE_TRADITIONAL 0x01 +#define SUBLANG_CHINESE_SIMPLIFIED 0x02 +#define SUBLANG_CHINESE_HONGKONG 0x03 +#define SUBLANG_CHINESE_SINGAPORE 0x04 +#define SUBLANG_CHINESE_MACAU 0x05 +#define SUBLANG_DUTCH 0x01 +#define SUBLANG_DUTCH_BELGIAN 0x02 +#define SUBLANG_ENGLISH_US 0x01 +#define SUBLANG_ENGLISH_UK 0x02 +#define SUBLANG_ENGLISH_AUS 0x03 +#define SUBLANG_ENGLISH_CAN 0x04 +#define SUBLANG_ENGLISH_NZ 0x05 +#define SUBLANG_ENGLISH_EIRE 0x06 +#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 +#define SUBLANG_ENGLISH_JAMAICA 0x08 +#define SUBLANG_ENGLISH_CARIBBEAN 0x09 +#define SUBLANG_ENGLISH_BELIZE 0x0a +#define SUBLANG_ENGLISH_TRINIDAD 0x0b +#define SUBLANG_ENGLISH_ZIMBABWE 0x0c +#define SUBLANG_ENGLISH_PHILIPPINES 0x0d +#define SUBLANG_FRENCH 0x01 +#define SUBLANG_FRENCH_BELGIAN 0x02 +#define SUBLANG_FRENCH_CANADIAN 0x03 +#define SUBLANG_FRENCH_SWISS 0x04 +#define SUBLANG_FRENCH_LUXEMBOURG 0x05 +#define SUBLANG_FRENCH_MONACO 0x06 +#define SUBLANG_GERMAN 0x01 +#define SUBLANG_GERMAN_SWISS 0x02 +#define SUBLANG_GERMAN_AUSTRIAN 0x03 +#define SUBLANG_GERMAN_LUXEMBOURG 0x04 +#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 +#define SUBLANG_ITALIAN 0x01 +#define SUBLANG_ITALIAN_SWISS 0x02 +#define SUBLANG_KASHMIRI_SASIA 0x02 +#define SUBLANG_KASHMIRI_INDIA 0x02 +#define SUBLANG_KOREAN 0x01 +#define SUBLANG_LITHUANIAN 0x01 +#define SUBLANG_MALAY_MALAYSIA 0x01 +#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 +#define SUBLANG_NEPALI_INDIA 0x02 +#define SUBLANG_NORWEGIAN_BOKMAL 0x01 +#define SUBLANG_NORWEGIAN_NYNORSK 0x02 +#define SUBLANG_PORTUGUESE 0x02 +#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01 +#define SUBLANG_SERBIAN_LATIN 0x02 +#define SUBLANG_SERBIAN_CYRILLIC 0x03 +#define SUBLANG_SPANISH 0x01 +#define SUBLANG_SPANISH_MEXICAN 0x02 +#define SUBLANG_SPANISH_MODERN 0x03 +#define SUBLANG_SPANISH_GUATEMALA 0x04 +#define SUBLANG_SPANISH_COSTA_RICA 0x05 +#define SUBLANG_SPANISH_PANAMA 0x06 +#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 +#define SUBLANG_SPANISH_VENEZUELA 0x08 +#define SUBLANG_SPANISH_COLOMBIA 0x09 +#define SUBLANG_SPANISH_PERU 0x0a +#define SUBLANG_SPANISH_ARGENTINA 0x0b +#define SUBLANG_SPANISH_ECUADOR 0x0c +#define SUBLANG_SPANISH_CHILE 0x0d +#define SUBLANG_SPANISH_URUGUAY 0x0e +#define SUBLANG_SPANISH_PARAGUAY 0x0f +#define SUBLANG_SPANISH_BOLIVIA 0x10 +#define SUBLANG_SPANISH_EL_SALVADOR 0x11 +#define SUBLANG_SPANISH_HONDURAS 0x12 +#define SUBLANG_SPANISH_NICARAGUA 0x13 +#define SUBLANG_SPANISH_PUERTO_RICO 0x14 +#define SUBLANG_SWEDISH 0x01 +#define SUBLANG_SWEDISH_FINLAND 0x02 +#define SUBLANG_URDU_PAKISTAN 0x01 +#define SUBLANG_URDU_INDIA 0x02 +#define SUBLANG_UZBEK_LATIN 0x01 +#define SUBLANG_UZBEK_CYRILLIC 0x02 + +#define SORT_DEFAULT 0x0 +#define SORT_INVARIANT_MATH 0x1 + +#define SORT_JAPANESE_XJIS 0x0 +#define SORT_JAPANESE_UNICODE 0x1 +#define SORT_JAPANESE_RADICALSTROKE 0x4 + +#define SORT_CHINESE_BIG5 0x0 +#define SORT_CHINESE_PRCP 0x0 +#define SORT_CHINESE_UNICODE 0x1 +#define SORT_CHINESE_PRC 0x2 +#define SORT_CHINESE_BOPOMOFO 0x3 + +#define SORT_KOREAN_KSC 0x0 +#define SORT_KOREAN_UNICODE 0x1 + +#define SORT_GERMAN_PHONE_BOOK 0x1 + +#define SORT_HUNGARIAN_DEFAULT 0x0 +#define SORT_HUNGARIAN_TECHNICAL 0x1 + +#define SORT_GEORGIAN_TRADITIONAL 0x0 +#define SORT_GEORGIAN_MODERN 0x1 + +#define MAKELANGID(p,s) ((((WORD)(s)) << 10) | (WORD)(p)) +#define PRIMARYLANGID(lgid) ((WORD)(lgid) & 0x3ff) +#define SUBLANGID(lgid) ((WORD)(lgid) >> 10) + +#define NLS_VALID_LOCALE_MASK 0x000fffff + +#define MAKELCID(lgid,srtid) ((DWORD)((((DWORD)((WORD)(srtid))) << 16) | ((DWORD)((WORD)(lgid))))) +#define MAKESORTLCID(lgid,srtid,ver) ((DWORD)((MAKELCID(lgid,srtid)) | (((DWORD)((WORD)(ver))) << 20))) +#define LANGIDFROMLCID(lcid) ((WORD)(lcid)) +#define SORTIDFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 16) & 0xf)) +#define SORTVERSIONFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 20) & 0xf)) + +#define LOCALE_NAME_MAX_LENGTH 85 +#define LANG_SYSTEM_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT)) +#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)) + +#define LOCALE_SYSTEM_DEFAULT (MAKELCID(LANG_SYSTEM_DEFAULT,SORT_DEFAULT)) +#define LOCALE_USER_DEFAULT (MAKELCID(LANG_USER_DEFAULT,SORT_DEFAULT)) + +#define LOCALE_NEUTRAL (MAKELCID(MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),SORT_DEFAULT)) + +#define LOCALE_CUSTOM_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), SORT_DEFAULT)) +#define LOCALE_CUSTOM_UNSPECIFIED (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED), SORT_DEFAULT)) +#define LOCALE_CUSTOM_UI_DEFAULT (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT), SORT_DEFAULT)) + +#define LOCALE_INVARIANT (MAKELCID(MAKELANGID(LANG_INVARIANT,SUBLANG_NEUTRAL),SORT_DEFAULT)) + +#define UNREFERENCED_PARAMETER(P) (P) +#define DBG_UNREFERENCED_PARAMETER(P) (P) +#define DBG_UNREFERENCED_LOCAL_VARIABLE(V) (V) + +#define DEFAULT_UNREACHABLE + +#ifndef WIN32_NO_STATUS +#define STATUS_WAIT_0 ((DWORD)0x00000000L) +#define STATUS_ABANDONED_WAIT_0 ((DWORD)0x00000080L) +#define STATUS_USER_APC ((DWORD)0x000000C0L) +#define STATUS_TIMEOUT ((DWORD)0x00000102L) +#define STATUS_PENDING ((DWORD)0x00000103L) +#define DBG_EXCEPTION_HANDLED ((DWORD)0x00010001L) +#define DBG_CONTINUE ((DWORD)0x00010002L) +#define STATUS_SEGMENT_NOTIFICATION ((DWORD)0x40000005L) +#define DBG_TERMINATE_THREAD ((DWORD)0x40010003L) +#define DBG_TERMINATE_PROCESS ((DWORD)0x40010004L) +#define DBG_CONTROL_C ((DWORD)0x40010005L) +#define DBG_CONTROL_BREAK ((DWORD)0x40010008L) +#define DBG_COMMAND_EXCEPTION ((DWORD)0x40010009L) +#define STATUS_GUARD_PAGE_VIOLATION ((DWORD)0x80000001L) +#define STATUS_DATATYPE_MISALIGNMENT ((DWORD)0x80000002L) +#define STATUS_BREAKPOINT ((DWORD)0x80000003L) +#define STATUS_SINGLE_STEP ((DWORD)0x80000004L) +#define DBG_EXCEPTION_NOT_HANDLED ((DWORD)0x80010001L) +#define STATUS_ACCESS_VIOLATION ((DWORD)0xC0000005L) +#define STATUS_IN_PAGE_ERROR ((DWORD)0xC0000006L) +#define STATUS_INVALID_HANDLE ((DWORD)0xC0000008L) +#define STATUS_NO_MEMORY ((DWORD)0xC0000017L) +#define STATUS_ILLEGAL_INSTRUCTION ((DWORD)0xC000001DL) +#define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD)0xC0000025L) +#define STATUS_INVALID_DISPOSITION ((DWORD)0xC0000026L) +#define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD)0xC000008CL) +#define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD)0xC000008DL) +#define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD)0xC000008EL) +#define STATUS_FLOAT_INEXACT_RESULT ((DWORD)0xC000008FL) +#define STATUS_FLOAT_INVALID_OPERATION ((DWORD)0xC0000090L) +#define STATUS_FLOAT_OVERFLOW ((DWORD)0xC0000091L) +#define STATUS_FLOAT_STACK_CHECK ((DWORD)0xC0000092L) +#define STATUS_FLOAT_UNDERFLOW ((DWORD)0xC0000093L) +#define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD)0xC0000094L) +#define STATUS_INTEGER_OVERFLOW ((DWORD)0xC0000095L) +#define STATUS_PRIVILEGED_INSTRUCTION ((DWORD)0xC0000096L) +#define STATUS_STACK_OVERFLOW ((DWORD)0xC00000FDL) +#define STATUS_CONTROL_C_EXIT ((DWORD)0xC000013AL) +#define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD)0xC00002B4L) +#define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD)0xC00002B5L) +#define STATUS_REG_NAT_CONSUMPTION ((DWORD)0xC00002C9L) +#define STATUS_SXS_EARLY_DEACTIVATION ((DWORD)0xC015000FL) +#define STATUS_SXS_INVALID_DEACTIVATION ((DWORD)0xC0150010L) +#endif + +#define MAXIMUM_WAIT_OBJECTS 64 +#define MAXIMUM_SUSPEND_COUNT MAXCHAR + + typedef ULONG_PTR KSPIN_LOCK; + typedef KSPIN_LOCK *PKSPIN_LOCK; + +#ifdef _AMD64_ + +#if defined(__x86_64) && !defined(RC_INVOKED) + +#ifdef __cplusplus + extern "C" { +#endif + +#define BitTest _bittest +#define BitTestAndComplement _bittestandcomplement +#define BitTestAndSet _bittestandset +#define BitTestAndReset _bittestandreset +#define InterlockedBitTestAndSet _interlockedbittestandset +#define InterlockedBitTestAndReset _interlockedbittestandreset +#define BitTest64 _bittest64 +#define BitTestAndComplement64 _bittestandcomplement64 +#define BitTestAndSet64 _bittestandset64 +#define BitTestAndReset64 _bittestandreset64 +#define InterlockedBitTestAndSet64 _interlockedbittestandset64 +#define InterlockedBitTestAndReset64 _interlockedbittestandreset64 + + __CRT_INLINE BOOLEAN _bittest(LONG const *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandcomplement(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandreset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandreset(LONG *Base,LONG Offset) { + int old = 0; + __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittest64(LONG64 const *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandcomplement64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btcq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btsq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _bittestandreset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("btrq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("lock ; btsq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } + __CRT_INLINE BOOLEAN _interlockedbittestandreset64(LONG64 *Base,LONG64 Offset) { + int old = 0; + __asm__ __volatile__("lock ; btrq %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long long *) Base)) + :"Ir" (Offset)); + return (BOOLEAN) (old!=0); + } +#define BitScanForward _BitScanForward +#define BitScanReverse _BitScanReverse +#define BitScanForward64 _BitScanForward64 +#define BitScanReverse64 _BitScanReverse64 + + __CRT_INLINE BOOLEAN _BitScanForward(DWORD *Index,DWORD Mask) { + __asm__ __volatile__("bsfl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); + return Mask!=0; + } + __CRT_INLINE BOOLEAN _BitScanReverse(DWORD *Index,DWORD Mask) { + __asm__ __volatile__("bsrl %1,%0" : "=r" (Mask),"=m" ((*(volatile long *)Index))); + return Mask!=0; + } + __CRT_INLINE BOOLEAN _BitScanForward64(DWORD *Index,DWORD64 Mask) { + __asm__ __volatile__("bsfq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); + return Mask!=0; + } + __CRT_INLINE BOOLEAN _BitScanReverse64(DWORD *Index,DWORD64 Mask) { + __asm__ __volatile__("bsrq %1,%0" : "=r" (Mask),"=m" ((*(volatile long long *)Index))); + return Mask!=0; + } + +#define InterlockedIncrement16 _InterlockedIncrement16 +#define InterlockedDecrement16 _InterlockedDecrement16 +#define InterlockedCompareExchange16 _InterlockedCompareExchange16 + +#define InterlockedAnd _InterlockedAnd +#define InterlockedOr _InterlockedOr +#define InterlockedXor _InterlockedXor +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedIncrementAcquire InterlockedIncrement +#define InterlockedIncrementRelease InterlockedIncrement +#define InterlockedDecrement _InterlockedDecrement +#define InterlockedDecrementAcquire InterlockedDecrement +#define InterlockedDecrementRelease InterlockedDecrement +#define InterlockedAdd _InterlockedAdd +#define InterlockedExchange _InterlockedExchange +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedCompareExchangeAcquire InterlockedCompareExchange +#define InterlockedCompareExchangeRelease InterlockedCompareExchange + +#define InterlockedAnd64 _InterlockedAnd64 +#define InterlockedAndAffinity InterlockedAnd64 +#define InterlockedOr64 _InterlockedOr64 +#define InterlockedOrAffinity InterlockedOr64 +#define InterlockedXor64 _InterlockedXor64 +#define InterlockedIncrement64 _InterlockedIncrement64 +#define InterlockedDecrement64 _InterlockedDecrement64 +#define InterlockedAdd64 _InterlockedAdd64 +#define InterlockedExchange64 _InterlockedExchange64 +#define InterlockedExchangeAcquire64 InterlockedExchange64 +#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 +#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64 +#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64 + +#define InterlockedExchangePointer _InterlockedExchangePointer +#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerAcquire _InterlockedCompareExchangePointer +#define InterlockedCompareExchangePointerRelease _InterlockedCompareExchangePointer + +#define InterlockedExchangeAddSizeT(a,b) InterlockedExchangeAdd64((LONG64 *)a,b) +#define InterlockedIncrementSizeT(a) InterlockedIncrement64((LONG64 *)a) +#define InterlockedDecrementSizeT(a) InterlockedDecrement64((LONG64 *)a) + + __CRT_INLINE SHORT InterlockedIncrement16(SHORT volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; addw $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE SHORT InterlockedDecrement16(SHORT volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; subw $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE SHORT InterlockedCompareExchange16(SHORT volatile *Destination,SHORT ExChange,SHORT Comperand) { + SHORT prev; + __asm__ __volatile__("lock ; cmpxchgw %w1,%2" + :"=a"(prev) + :"q"(ExChange), "m"(*Destination), "0"(Comperand) + : "memory"); + return prev; + } + __CRT_INLINE LONG InterlockedAnd(LONG volatile *Destination,LONG Value) { + __asm__ __volatile__("lock ; andl %0,%1" + : :"r"(Value),"m"(*Destination) + : "memory"); + return *Destination; + } + __CRT_INLINE LONG InterlockedOr(LONG volatile *Destination,LONG Value) { + __asm__ __volatile__("lock ; orl %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG InterlockedXor(LONG volatile *Destination,LONG Value) { + __asm__ __volatile__("lock ; xorl %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + // $$$$ + __CRT_INLINE LONG64 InterlockedAnd64(LONG64 volatile *Destination,LONG64 Value) { + __asm__ __volatile__("lock ; andq %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG64 InterlockedOr64(LONG64 volatile *Destination,LONG64 Value) { + __asm__ __volatile__("lock ; orq %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG64 InterlockedXor64(LONG64 volatile *Destination,LONG64 Value) { + __asm__ __volatile__("lock ; xorq %0,%1" + : : "r"(Value),"m"(*Destination) : "memory"); + return *Destination; + } + __CRT_INLINE LONG InterlockedIncrement(LONG volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; addl $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG InterlockedDecrement(LONG volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; subl $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG InterlockedExchange(LONG volatile *Target,LONG Value) { + __asm__ __volatile("lock ; xchgl %0,%1" + : "=r"(Value) + : "m"(*Target),"0"(Value) + : "memory"); + return Value; + } + LONG InterlockedExchangeAdd(LONG volatile *Addend,LONG Value); + +#ifndef _X86AMD64_ + __CRT_INLINE LONG InterlockedAdd(LONG volatile *Addend,LONG Value) { return InterlockedExchangeAdd(Addend,Value) + Value; } +#endif + __CRT_INLINE LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand) { + LONG prev; + __asm__ __volatile__("lock ; cmpxchgl %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); + return prev; + } + __CRT_INLINE LONG64 InterlockedIncrement64(LONG64 volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; addq $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG64 InterlockedDecrement64(LONG64 volatile *Addend) { + unsigned char c; + unsigned char s; + __asm__ __volatile__( + "lock ; subq $1,%0; sete %1 ; sets %2" + :"=m" (*Addend), "=qm" (c), "=qm" (s) + :"m" (*Addend) : "memory"); + return (c != 0 ? 0 : (s != 0 ? -1 : 1)); + } + __CRT_INLINE LONG64 InterlockedExchange64(LONG64 volatile *Target,LONG64 Value) { + __asm__ __volatile("lock ; xchgq %0,%1" + : "=r"(Value) + : "m"(*Target),"0"(Value) + : "memory"); + return Value; + } + LONG64 InterlockedExchangeAdd64(LONG64 volatile *Addend,LONG64 Value); + +#ifndef _X86AMD64_ + __CRT_INLINE LONG64 InterlockedAdd64(LONG64 volatile *Addend,LONG64 Value) { return InterlockedExchangeAdd64(Addend,Value) + Value; } +#endif + + __CRT_INLINE LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination,LONG64 ExChange,LONG64 Comperand) { + LONG64 prev; + __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); + return prev; + } + __CRT_INLINE PVOID InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) { + PVOID prev; + __asm__ __volatile__("lock ; cmpxchgq %1,%2" : "=a" (prev) : "q" (ExChange),"m" (*Destination), "0" (Comperand) : "memory"); + return prev; + } + __CRT_INLINE PVOID InterlockedExchangePointer(PVOID volatile *Target,PVOID Value) { + __asm__ __volatile("lock ; xchgq %0,%1" + : "=r"(Value) + : "m"(*Target),"0"(Value) + : "memory"); + return Value; + } + +#define CacheLineFlush(Address) _mm_clflush(Address) + + VOID _ReadWriteBarrier(VOID); + +#define FastFence __faststorefence +#define LoadFence _mm_lfence +#define MemoryFence _mm_mfence +#define StoreFence _mm_sfence + + VOID __faststorefence(VOID); + VOID _m_prefetchw(volatile CONST VOID *Source); + +//!__TINYC__: #include + +#define YieldProcessor _mm_pause +#define MemoryBarrier __faststorefence +#define PreFetchCacheLine(l,a) _mm_prefetch((CHAR CONST *) a,l) +#define PrefetchForWrite(p) _m_prefetchw(p) +#define ReadForWriteAccess(p) (_m_prefetchw(p),*(p)) + +#define PF_TEMPORAL_LEVEL_1 _MM_HINT_T0 +#define PF_TEMPORAL_LEVEL_2 _MM_HINT_T1 +#define PF_TEMPORAL_LEVEL_3 _MM_HINT_T2 +#define PF_NON_TEMPORAL_LEVEL_ALL _MM_HINT_NTA + +#define ReadMxCsr _mm_getcsr +#define WriteMxCsr _mm_setcsr + + VOID __int2c(VOID); + +#define DbgRaiseAssertionFailure() __int2c() +#define GetCallersEflags() __getcallerseflags() + + unsigned __int32 __getcallerseflags(VOID); + +#define GetSegmentLimit __segmentlimit + + DWORD __segmentlimit(DWORD Selector); + +#define ReadTimeStampCounter() __rdtsc() + + DWORD64 __rdtsc(VOID); + VOID __movsb(PBYTE Destination,BYTE const *Source,SIZE_T Count); + VOID __movsw(PWORD Destination,WORD const *Source,SIZE_T Count); + VOID __movsd(PDWORD Destination,DWORD const *Source,SIZE_T Count); + VOID __movsq(PDWORD64 Destination,DWORD64 const *Source,SIZE_T Count); + VOID __stosb(PBYTE Destination,BYTE Value,SIZE_T Count); + VOID __stosw(PWORD Destination,WORD Value,SIZE_T Count); + VOID __stosd(PDWORD Destination,DWORD Value,SIZE_T Count); + VOID __stosq(PDWORD64 Destination,DWORD64 Value,SIZE_T Count); + +#define MultiplyHigh __mulh +#define UnsignedMultiplyHigh __umulh + + LONGLONG MultiplyHigh(LONGLONG Multiplier,LONGLONG Multiplicand); + ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); + +#define ShiftLeft128 __shiftleft128 +#define ShiftRight128 __shiftright128 + + DWORD64 ShiftLeft128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); + DWORD64 ShiftRight128(DWORD64 LowPart,DWORD64 HighPart,BYTE Shift); + +#define Multiply128 _mul128 + + LONG64 Multiply128(LONG64 Multiplier,LONG64 Multiplicand,LONG64 *HighProduct); + +#define UnsignedMultiply128 _umul128 + + DWORD64 UnsignedMultiply128(DWORD64 Multiplier,DWORD64 Multiplicand,DWORD64 *HighProduct); + + __CRT_INLINE LONG64 MultiplyExtract128(LONG64 Multiplier,LONG64 Multiplicand,BYTE Shift) { + LONG64 extractedProduct; + LONG64 highProduct; + LONG64 lowProduct; + lowProduct = Multiply128(Multiplier,Multiplicand,&highProduct); + extractedProduct = (LONG64)ShiftRight128((LONG64)lowProduct,(LONG64)highProduct,Shift); + return extractedProduct; + } + + __CRT_INLINE DWORD64 UnsignedMultiplyExtract128(DWORD64 Multiplier,DWORD64 Multiplicand,BYTE Shift) { + DWORD64 extractedProduct; + DWORD64 highProduct; + DWORD64 lowProduct; + lowProduct = UnsignedMultiply128(Multiplier,Multiplicand,&highProduct); + extractedProduct = ShiftRight128(lowProduct,highProduct,Shift); + return extractedProduct; + } + + __CRT_INLINE BYTE __readgsbyte(DWORD Offset) { + BYTE ret; + __asm__ volatile ("movb %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return ret; + } + __CRT_INLINE WORD __readgsword(DWORD Offset) { + WORD ret; + __asm__ volatile ("movw %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return ret; + } + __CRT_INLINE DWORD __readgsdword(DWORD Offset) { + DWORD ret; + __asm__ volatile ("movl %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return ret; + } + __CRT_INLINE DWORD64 __readgsqword(DWORD Offset) { + void *ret; + __asm__ volatile ("movq %%gs:%1,%0" + : "=r" (ret) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + return (DWORD64) ret; + } + __CRT_INLINE VOID __writegsbyte(DWORD Offset,BYTE Data) { + __asm__ volatile ("movb %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + __CRT_INLINE VOID __writegsword(DWORD Offset,WORD Data) { + __asm__ volatile ("movw %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + __CRT_INLINE VOID __writegsdword(DWORD Offset,DWORD Data) { + __asm__ volatile ("movl %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + __CRT_INLINE VOID __writegsqword(DWORD Offset,DWORD64 Data) { + __asm__ volatile ("movq %0,%%gs:%1" + : "=r" (Data) ,"=m" ((*(volatile long *) (DWORD64) Offset))); + } + +#ifdef __cplusplus + } +#endif +#endif + +#define EXCEPTION_READ_FAULT 0 +#define EXCEPTION_WRITE_FAULT 1 +#define EXCEPTION_EXECUTE_FAULT 8 + +#if !defined(RC_INVOKED) + +#define CONTEXT_AMD64 0x100000 + +#define CONTEXT_CONTROL (CONTEXT_AMD64 | 0x1L) +#define CONTEXT_INTEGER (CONTEXT_AMD64 | 0x2L) +#define CONTEXT_SEGMENTS (CONTEXT_AMD64 | 0x4L) +#define CONTEXT_FLOATING_POINT (CONTEXT_AMD64 | 0x8L) +#define CONTEXT_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L) + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS) + +#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 +#define CONTEXT_SERVICE_ACTIVE 0x10000000 +#define CONTEXT_EXCEPTION_REQUEST 0x40000000 +#define CONTEXT_EXCEPTION_REPORTING 0x80000000 +#endif + +#define INITIAL_MXCSR 0x1f80 +#define INITIAL_FPCSR 0x027f + + typedef struct DECLSPEC_ALIGN(16) _M128A { + ULONGLONG Low; + LONGLONG High; + } M128A,*PM128A; + + typedef struct _XMM_SAVE_AREA32 { + WORD ControlWord; + WORD StatusWord; + BYTE TagWord; + BYTE Reserved1; + WORD ErrorOpcode; + DWORD ErrorOffset; + WORD ErrorSelector; + WORD Reserved2; + DWORD DataOffset; + WORD DataSelector; + WORD Reserved3; + DWORD MxCsr; + DWORD MxCsr_Mask; + M128A FloatRegisters[8]; + M128A XmmRegisters[16]; + BYTE Reserved4[96]; + } XMM_SAVE_AREA32,*PXMM_SAVE_AREA32; + +#define LEGACY_SAVE_AREA_LENGTH sizeof(XMM_SAVE_AREA32) + + typedef struct DECLSPEC_ALIGN(16) _CONTEXT { + DWORD64 P1Home; + DWORD64 P2Home; + DWORD64 P3Home; + DWORD64 P4Home; + DWORD64 P5Home; + DWORD64 P6Home; + DWORD ContextFlags; + DWORD MxCsr; + WORD SegCs; + WORD SegDs; + WORD SegEs; + WORD SegFs; + WORD SegGs; + WORD SegSs; + DWORD EFlags; + DWORD64 Dr0; + DWORD64 Dr1; + DWORD64 Dr2; + DWORD64 Dr3; + DWORD64 Dr6; + DWORD64 Dr7; + DWORD64 Rax; + DWORD64 Rcx; + DWORD64 Rdx; + DWORD64 Rbx; + DWORD64 Rsp; + DWORD64 Rbp; + DWORD64 Rsi; + DWORD64 Rdi; + DWORD64 R8; + DWORD64 R9; + DWORD64 R10; + DWORD64 R11; + DWORD64 R12; + DWORD64 R13; + DWORD64 R14; + DWORD64 R15; + DWORD64 Rip; + union { + XMM_SAVE_AREA32 FltSave; + XMM_SAVE_AREA32 FloatSave; + struct { + M128A Header[2]; + M128A Legacy[8]; + M128A Xmm0; + M128A Xmm1; + M128A Xmm2; + M128A Xmm3; + M128A Xmm4; + M128A Xmm5; + M128A Xmm6; + M128A Xmm7; + M128A Xmm8; + M128A Xmm9; + M128A Xmm10; + M128A Xmm11; + M128A Xmm12; + M128A Xmm13; + M128A Xmm14; + M128A Xmm15; + }; + }; + M128A VectorRegister[26]; + DWORD64 VectorControl; + DWORD64 DebugControl; + DWORD64 LastBranchToRip; + DWORD64 LastBranchFromRip; + DWORD64 LastExceptionToRip; + DWORD64 LastExceptionFromRip; + } CONTEXT,*PCONTEXT; + +#define RUNTIME_FUNCTION_INDIRECT 0x1 + + typedef struct _RUNTIME_FUNCTION { + DWORD BeginAddress; + DWORD EndAddress; + DWORD UnwindData; + } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; + + typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); + typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); + +#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" + + NTSYSAPI VOID __cdecl RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); + NTSYSAPI BOOLEAN __cdecl RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,DWORD64 BaseAddress); + NTSYSAPI BOOLEAN __cdecl RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); + NTSYSAPI BOOLEAN __cdecl RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); +#endif + +#ifdef I_X86_ +#if(defined(_X86_) && !defined(__x86_64)) && !defined(RC_INVOKED) +#ifdef __cplusplus + extern "C" { +#endif + + __CRT_INLINE BOOLEAN InterlockedBitTestAndSet(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btsl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + + __CRT_INLINE BOOLEAN InterlockedBitTestAndReset(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btrl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + + __CRT_INLINE BOOLEAN InterlockedBitTestAndComplement(LONG *Base,LONG Bit) { + int old = 0; + __asm__ __volatile__("lock ; btcl %2,%1\n\tsbbl %0,%0 " + :"=r" (old),"=m" ((*(volatile long *) Base)) + :"Ir" (Bit)); + return (BOOLEAN) (old!=0); + } + +#ifdef _PREFIX_ + BYTE __readfsbyte(DWORD Offset); + WORD __readfsword(DWORD Offset); + DWORD __readfsdword(DWORD Offset); + VOID __writefsbyte(DWORD Offset,BYTE Data); + VOID __writefsword(DWORD Offset,WORD Data); + VOID __writefsdword(DWORD Offset,DWORD Data); +#endif + +#ifdef __cplusplus + } +#endif +#endif + +#if(defined(_X86_) && !defined(__x86_64)) + __CRT_INLINE VOID MemoryBarrier(VOID) { + LONG Barrier; + __asm__ __volatile__("xchgl %%eax,%0 " + :"=r" (Barrier)); + } +#define YieldProcessor() __asm__ __volatile__("rep nop "); + +#define PreFetchCacheLine(l,a) +#define ReadForWriteAccess(p) (*(p)) + +#define PF_TEMPORAL_LEVEL_1 +#define PF_NON_TEMPORAL_LEVEL_ALL + + __CRT_INLINE VOID DbgRaiseAssertionFailure(void) { + __asm__ __volatile__("int $0x2c "); + } + PVOID GetCurrentFiber(void); + __CRT_INLINE PVOID GetCurrentFiber(void) + { + void *ret; + __asm__ volatile ("movl %%fs:0x10,%0" + : "=r" (ret)); + return ret; + } + PVOID GetFiberData(void); + __CRT_INLINE PVOID GetFiberData(void) + { + void *ret; + __asm__ volatile ("movl %%fs:0x10,%0\n" + "movl (%0),%0" + : "=r" (ret)); + return ret; + } +#endif + +#define EXCEPTION_READ_FAULT 0 +#define EXCEPTION_WRITE_FAULT 1 +#define EXCEPTION_EXECUTE_FAULT 8 + +#define SIZE_OF_80387_REGISTERS 80 + +#if !defined(RC_INVOKED) + +#define CONTEXT_i386 0x00010000 +#define CONTEXT_i486 0x00010000 + +#define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) +#define CONTEXT_INTEGER (CONTEXT_i386 | 0x00000002L) +#define CONTEXT_SEGMENTS (CONTEXT_i386 | 0x00000004L) +#define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 0x00000008L) +#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) +#define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386 | 0x00000020L) + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) + +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS) +#endif + +#define MAXIMUM_SUPPORTED_EXTENSION 512 + + typedef struct _FLOATING_SAVE_AREA { + DWORD ControlWord; + DWORD StatusWord; + DWORD TagWord; + DWORD ErrorOffset; + DWORD ErrorSelector; + DWORD DataOffset; + DWORD DataSelector; + BYTE RegisterArea[SIZE_OF_80387_REGISTERS]; + DWORD Cr0NpxState; + } FLOATING_SAVE_AREA; + + typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA; + + typedef struct _CONTEXT { + DWORD ContextFlags; + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr6; + DWORD Dr7; + FLOATING_SAVE_AREA FloatSave; + DWORD SegGs; + DWORD SegFs; + DWORD SegEs; + DWORD SegDs; + + DWORD Edi; + DWORD Esi; + DWORD Ebx; + DWORD Edx; + DWORD Ecx; + DWORD Eax; + DWORD Ebp; + DWORD Eip; + DWORD SegCs; + DWORD EFlags; + DWORD Esp; + DWORD SegSs; + BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; + } CONTEXT; + + typedef CONTEXT *PCONTEXT; +#endif + +#ifndef _LDT_ENTRY_DEFINED +#define _LDT_ENTRY_DEFINED + + typedef struct _LDT_ENTRY { + WORD LimitLow; + WORD BaseLow; + union { + struct { + BYTE BaseMid; + BYTE Flags1; + BYTE Flags2; + BYTE BaseHi; + } Bytes; + struct { + DWORD BaseMid : 8; + DWORD Type : 5; + DWORD Dpl : 2; + DWORD Pres : 1; + DWORD LimitHi : 4; + DWORD Sys : 1; + DWORD Reserved_0 : 1; + DWORD Default_Big : 1; + DWORD Granularity : 1; + DWORD BaseHi : 8; + } Bits; + } HighWord; + } LDT_ENTRY,*PLDT_ENTRY; +#endif + +#if defined(__ia64__) && !defined(RC_INVOKED) + +#ifdef __cplusplus + extern "C" { +#endif + + BOOLEAN BitScanForward64(DWORD *Index,DWORD64 Mask); + BOOLEAN BitScanReverse64(DWORD *Index,DWORD64 Mask); + +#ifdef __cplusplus + } +#endif +#endif + +#if !defined(GENUTIL) && !defined(_GENIA64_) && defined(_IA64_) + + void *_cdecl _rdteb(void); +#ifdef __ia64__ + +#define NtCurrentTeb() ((struct _TEB *)_rdteb()) +#define GetCurrentFiber() (((PNT_TIB)NtCurrentTeb())->FiberData) +#define GetFiberData() (*(PVOID *)(GetCurrentFiber())) + +#ifdef __cplusplus + extern "C" { +#endif + + void __break(int); + void __yield(void); + void __mf(void); + void __lfetch(int Level,VOID CONST *Address); + void __lfetchfault(int Level,VOID CONST *Address); + void __lfetch_excl(int Level,VOID CONST *Address); + void __lfetchfault_excl(int Level,VOID CONST *Address); + +#define MD_LFHINT_NONE 0x00 +#define MD_LFHINT_NT1 0x01 +#define MD_LFHINT_NT2 0x02 +#define MD_LFHINT_NTA 0x03 + +#ifdef __cplusplus + } +#endif + +#define YieldProcessor __yield +#define MemoryBarrier __mf +#define PreFetchCacheLine __lfetch +#define ReadForWriteAccess(p) (*(p)) +#define DbgRaiseAssertionFailure() __break(ASSERT_BREAKPOINT) + +#define PF_TEMPORAL_LEVEL_1 MD_LFHINT_NONE +#define PF_NON_TEMPORAL_LEVEL_ALL MD_LFHINT_NTA + +#define UnsignedMultiplyHigh __UMULH + + ULONGLONG UnsignedMultiplyHigh(ULONGLONG Multiplier,ULONGLONG Multiplicand); +#else + struct _TEB *NtCurrentTeb(void); +#endif +#endif + +#ifdef _IA64_ + +#define EXCEPTION_READ_FAULT 0 +#define EXCEPTION_WRITE_FAULT 1 +#define EXCEPTION_EXECUTE_FAULT 2 + +#if !defined(RC_INVOKED) + +#define CONTEXT_IA64 0x00080000 + +#define CONTEXT_CONTROL (CONTEXT_IA64 | 0x00000001L) +#define CONTEXT_LOWER_FLOATING_POINT (CONTEXT_IA64 | 0x00000002L) +#define CONTEXT_HIGHER_FLOATING_POINT (CONTEXT_IA64 | 0x00000004L) +#define CONTEXT_INTEGER (CONTEXT_IA64 | 0x00000008L) +#define CONTEXT_DEBUG (CONTEXT_IA64 | 0x00000010L) +#define CONTEXT_IA32_CONTROL (CONTEXT_IA64 | 0x00000020L) + +#define CONTEXT_FLOATING_POINT (CONTEXT_LOWER_FLOATING_POINT | CONTEXT_HIGHER_FLOATING_POINT) +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_IA32_CONTROL) +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_DEBUG | CONTEXT_IA32_CONTROL) + +#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 +#define CONTEXT_SERVICE_ACTIVE 0x10000000 +#define CONTEXT_EXCEPTION_REQUEST 0x40000000 +#define CONTEXT_EXCEPTION_REPORTING 0x80000000 +#endif + + typedef struct _CONTEXT { + DWORD ContextFlags; + DWORD Fill1[3]; + ULONGLONG DbI0; + ULONGLONG DbI1; + ULONGLONG DbI2; + ULONGLONG DbI3; + ULONGLONG DbI4; + ULONGLONG DbI5; + ULONGLONG DbI6; + ULONGLONG DbI7; + ULONGLONG DbD0; + ULONGLONG DbD1; + ULONGLONG DbD2; + ULONGLONG DbD3; + ULONGLONG DbD4; + ULONGLONG DbD5; + ULONGLONG DbD6; + ULONGLONG DbD7; + FLOAT128 FltS0; + FLOAT128 FltS1; + FLOAT128 FltS2; + FLOAT128 FltS3; + FLOAT128 FltT0; + FLOAT128 FltT1; + FLOAT128 FltT2; + FLOAT128 FltT3; + FLOAT128 FltT4; + FLOAT128 FltT5; + FLOAT128 FltT6; + FLOAT128 FltT7; + FLOAT128 FltT8; + FLOAT128 FltT9; + FLOAT128 FltS4; + FLOAT128 FltS5; + FLOAT128 FltS6; + FLOAT128 FltS7; + FLOAT128 FltS8; + FLOAT128 FltS9; + FLOAT128 FltS10; + FLOAT128 FltS11; + FLOAT128 FltS12; + FLOAT128 FltS13; + FLOAT128 FltS14; + FLOAT128 FltS15; + FLOAT128 FltS16; + FLOAT128 FltS17; + FLOAT128 FltS18; + FLOAT128 FltS19; + FLOAT128 FltF32; + FLOAT128 FltF33; + FLOAT128 FltF34; + FLOAT128 FltF35; + FLOAT128 FltF36; + FLOAT128 FltF37; + FLOAT128 FltF38; + FLOAT128 FltF39; + FLOAT128 FltF40; + FLOAT128 FltF41; + FLOAT128 FltF42; + FLOAT128 FltF43; + FLOAT128 FltF44; + FLOAT128 FltF45; + FLOAT128 FltF46; + FLOAT128 FltF47; + FLOAT128 FltF48; + FLOAT128 FltF49; + FLOAT128 FltF50; + FLOAT128 FltF51; + FLOAT128 FltF52; + FLOAT128 FltF53; + FLOAT128 FltF54; + FLOAT128 FltF55; + FLOAT128 FltF56; + FLOAT128 FltF57; + FLOAT128 FltF58; + FLOAT128 FltF59; + FLOAT128 FltF60; + FLOAT128 FltF61; + FLOAT128 FltF62; + FLOAT128 FltF63; + FLOAT128 FltF64; + FLOAT128 FltF65; + FLOAT128 FltF66; + FLOAT128 FltF67; + FLOAT128 FltF68; + FLOAT128 FltF69; + FLOAT128 FltF70; + FLOAT128 FltF71; + FLOAT128 FltF72; + FLOAT128 FltF73; + FLOAT128 FltF74; + FLOAT128 FltF75; + FLOAT128 FltF76; + FLOAT128 FltF77; + FLOAT128 FltF78; + FLOAT128 FltF79; + FLOAT128 FltF80; + FLOAT128 FltF81; + FLOAT128 FltF82; + FLOAT128 FltF83; + FLOAT128 FltF84; + FLOAT128 FltF85; + FLOAT128 FltF86; + FLOAT128 FltF87; + FLOAT128 FltF88; + FLOAT128 FltF89; + FLOAT128 FltF90; + FLOAT128 FltF91; + FLOAT128 FltF92; + FLOAT128 FltF93; + FLOAT128 FltF94; + FLOAT128 FltF95; + FLOAT128 FltF96; + FLOAT128 FltF97; + FLOAT128 FltF98; + FLOAT128 FltF99; + FLOAT128 FltF100; + FLOAT128 FltF101; + FLOAT128 FltF102; + FLOAT128 FltF103; + FLOAT128 FltF104; + FLOAT128 FltF105; + FLOAT128 FltF106; + FLOAT128 FltF107; + FLOAT128 FltF108; + FLOAT128 FltF109; + FLOAT128 FltF110; + FLOAT128 FltF111; + FLOAT128 FltF112; + FLOAT128 FltF113; + FLOAT128 FltF114; + FLOAT128 FltF115; + FLOAT128 FltF116; + FLOAT128 FltF117; + FLOAT128 FltF118; + FLOAT128 FltF119; + FLOAT128 FltF120; + FLOAT128 FltF121; + FLOAT128 FltF122; + FLOAT128 FltF123; + FLOAT128 FltF124; + FLOAT128 FltF125; + FLOAT128 FltF126; + FLOAT128 FltF127; + ULONGLONG StFPSR; + ULONGLONG IntGp; + ULONGLONG IntT0; + ULONGLONG IntT1; + ULONGLONG IntS0; + ULONGLONG IntS1; + ULONGLONG IntS2; + ULONGLONG IntS3; + ULONGLONG IntV0; + ULONGLONG IntT2; + ULONGLONG IntT3; + ULONGLONG IntT4; + ULONGLONG IntSp; + ULONGLONG IntTeb; + ULONGLONG IntT5; + ULONGLONG IntT6; + ULONGLONG IntT7; + ULONGLONG IntT8; + ULONGLONG IntT9; + ULONGLONG IntT10; + ULONGLONG IntT11; + ULONGLONG IntT12; + ULONGLONG IntT13; + ULONGLONG IntT14; + ULONGLONG IntT15; + ULONGLONG IntT16; + ULONGLONG IntT17; + ULONGLONG IntT18; + ULONGLONG IntT19; + ULONGLONG IntT20; + ULONGLONG IntT21; + ULONGLONG IntT22; + ULONGLONG IntNats; + ULONGLONG Preds; + ULONGLONG BrRp; + ULONGLONG BrS0; + ULONGLONG BrS1; + ULONGLONG BrS2; + ULONGLONG BrS3; + ULONGLONG BrS4; + ULONGLONG BrT0; + ULONGLONG BrT1; + ULONGLONG ApUNAT; + ULONGLONG ApLC; + ULONGLONG ApEC; + ULONGLONG ApCCV; + ULONGLONG ApDCR; + ULONGLONG RsPFS; + ULONGLONG RsBSP; + ULONGLONG RsBSPSTORE; + ULONGLONG RsRSC; + ULONGLONG RsRNAT; + ULONGLONG StIPSR; + ULONGLONG StIIP; + ULONGLONG StIFS; + ULONGLONG StFCR; + ULONGLONG Eflag; + ULONGLONG SegCSD; + ULONGLONG SegSSD; + ULONGLONG Cflag; + ULONGLONG StFSR; + ULONGLONG StFIR; + ULONGLONG StFDR; + ULONGLONG UNUSEDPACK; + } CONTEXT,*PCONTEXT; + + typedef struct _PLABEL_DESCRIPTOR { + ULONGLONG EntryPoint; + ULONGLONG GlobalPointer; + } PLABEL_DESCRIPTOR,*PPLABEL_DESCRIPTOR; + + typedef struct _RUNTIME_FUNCTION { + DWORD BeginAddress; + DWORD EndAddress; + DWORD UnwindInfoAddress; + } RUNTIME_FUNCTION,*PRUNTIME_FUNCTION; + + typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); + typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); + +#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" + + BOOLEAN RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,ULONGLONG BaseAddress,ULONGLONG TargetGp); + BOOLEAN RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,DWORD64 TargetGp,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll); + BOOLEAN RtlDeleteFunctionTable(PRUNTIME_FUNCTION FunctionTable); + VOID RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord); + VOID __jump_unwind(ULONGLONG TargetMsFrame,ULONGLONG TargetBsFrame,ULONGLONG TargetPc); +#endif + +#define EXCEPTION_NONCONTINUABLE 0x1 +#define EXCEPTION_MAXIMUM_PARAMETERS 15 + + typedef struct _EXCEPTION_RECORD { + DWORD ExceptionCode; + DWORD ExceptionFlags; + struct _EXCEPTION_RECORD *ExceptionRecord; + PVOID ExceptionAddress; + DWORD NumberParameters; + ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } EXCEPTION_RECORD; + + typedef EXCEPTION_RECORD *PEXCEPTION_RECORD; + + typedef struct _EXCEPTION_RECORD32 { + DWORD ExceptionCode; + DWORD ExceptionFlags; + DWORD ExceptionRecord; + DWORD ExceptionAddress; + DWORD NumberParameters; + DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } EXCEPTION_RECORD32,*PEXCEPTION_RECORD32; + + typedef struct _EXCEPTION_RECORD64 { + DWORD ExceptionCode; + DWORD ExceptionFlags; + DWORD64 ExceptionRecord; + DWORD64 ExceptionAddress; + DWORD NumberParameters; + DWORD __unusedAlignment; + DWORD64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; + } EXCEPTION_RECORD64,*PEXCEPTION_RECORD64; + + typedef struct _EXCEPTION_POINTERS { + PEXCEPTION_RECORD ExceptionRecord; + PCONTEXT ContextRecord; + } EXCEPTION_POINTERS,*PEXCEPTION_POINTERS; + +#ifdef __x86_64 + + typedef EXCEPTION_DISPOSITION NTAPI EXCEPTION_ROUTINE (struct _EXCEPTION_RECORD *ExceptionRecord, PVOID EstablisherFrame, struct _CONTEXT *ContextRecord, PVOID DispatcherContext); +#ifndef __PEXCEPTION_ROUTINE_DEFINED +#define __PEXCEPTION_ROUTINE_DEFINED + typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE; +#endif + + /* http://msdn.microsoft.com/en-us/library/ms680597(VS.85).aspx */ + +#define UNWIND_HISTORY_TABLE_SIZE 12 + + typedef struct _UNWIND_HISTORY_TABLE_ENTRY { + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + } UNWIND_HISTORY_TABLE_ENTRY, *PUNWIND_HISTORY_TABLE_ENTRY; + +#define UNWIND_HISTORY_TABLE_NONE 0 +#define UNWIND_HISTORY_TABLE_GLOBAL 1 +#define UNWIND_HISTORY_TABLE_LOCAL 2 + + typedef struct _UNWIND_HISTORY_TABLE { + ULONG Count; + UCHAR Search; + ULONG64 LowAddress; + ULONG64 HighAddress; + UNWIND_HISTORY_TABLE_ENTRY Entry[UNWIND_HISTORY_TABLE_SIZE]; + } UNWIND_HISTORY_TABLE, *PUNWIND_HISTORY_TABLE; + + /* http://msdn.microsoft.com/en-us/library/b6sf5kbd(VS.80).aspx */ + + struct _DISPATCHER_CONTEXT; + typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; + typedef struct _DISPATCHER_CONTEXT *PDISPATCHER_CONTEXT; + + struct _DISPATCHER_CONTEXT { + ULONG64 ControlPc; + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + ULONG64 EstablisherFrame; + ULONG64 TargetIp; + PCONTEXT ContextRecord; + PEXCEPTION_ROUTINE LanguageHandler; + PVOID HandlerData; + /* http://www.nynaeve.net/?p=99 */ + PUNWIND_HISTORY_TABLE HistoryTable; + ULONG ScopeIndex; + ULONG Fill0; + }; + + /* http://msdn.microsoft.com/en-us/library/ms680617(VS.85).aspx */ + + typedef struct _KNONVOLATILE_CONTEXT_POINTERS + { + PM128A FloatingContext[16]; + PULONG64 IntegerContext[16]; + } KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS; +#endif /* defined(__x86_64) */ + + typedef PVOID PACCESS_TOKEN; + typedef PVOID PSECURITY_DESCRIPTOR; + typedef PVOID PSID; + + typedef DWORD ACCESS_MASK; + typedef ACCESS_MASK *PACCESS_MASK; + +#define DELETE (0x00010000L) +#define READ_CONTROL (0x00020000L) +#define WRITE_DAC (0x00040000L) +#define WRITE_OWNER (0x00080000L) +#define SYNCHRONIZE (0x00100000L) + +#define STANDARD_RIGHTS_REQUIRED (0x000F0000L) +#define STANDARD_RIGHTS_READ (READ_CONTROL) +#define STANDARD_RIGHTS_WRITE (READ_CONTROL) +#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL) +#define STANDARD_RIGHTS_ALL (0x001F0000L) + +#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL) + +#define ACCESS_SYSTEM_SECURITY (0x01000000L) + +#define MAXIMUM_ALLOWED (0x02000000L) + +#define GENERIC_READ (0x80000000L) +#define GENERIC_WRITE (0x40000000L) +#define GENERIC_EXECUTE (0x20000000L) +#define GENERIC_ALL (0x10000000L) + + typedef struct _GENERIC_MAPPING { + ACCESS_MASK GenericRead; + ACCESS_MASK GenericWrite; + ACCESS_MASK GenericExecute; + ACCESS_MASK GenericAll; + } GENERIC_MAPPING; + typedef GENERIC_MAPPING *PGENERIC_MAPPING; + +#include + + typedef struct _LUID_AND_ATTRIBUTES { + LUID Luid; + DWORD Attributes; + } LUID_AND_ATTRIBUTES,*PLUID_AND_ATTRIBUTES; + typedef LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; + typedef LUID_AND_ATTRIBUTES_ARRAY *PLUID_AND_ATTRIBUTES_ARRAY; + +#include + +#ifndef SID_IDENTIFIER_AUTHORITY_DEFINED +#define SID_IDENTIFIER_AUTHORITY_DEFINED + typedef struct _SID_IDENTIFIER_AUTHORITY { + BYTE Value[6]; + } SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY; +#endif + +#ifndef SID_DEFINED +#define SID_DEFINED + typedef struct _SID { + BYTE Revision; + BYTE SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + DWORD SubAuthority[ANYSIZE_ARRAY]; + } SID,*PISID; +#endif + +#define SID_REVISION (1) +#define SID_MAX_SUB_AUTHORITIES (15) +#define SID_RECOMMENDED_SUB_AUTHORITIES (1) + +#define SECURITY_MAX_SID_SIZE (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES *sizeof(DWORD))) + + typedef enum _SID_NAME_USE { + SidTypeUser = 1,SidTypeGroup,SidTypeDomain,SidTypeAlias,SidTypeWellKnownGroup,SidTypeDeletedAccount,SidTypeInvalid,SidTypeUnknown,SidTypeComputer + } SID_NAME_USE,*PSID_NAME_USE; + + typedef struct _SID_AND_ATTRIBUTES { + PSID Sid; + DWORD Attributes; + } SID_AND_ATTRIBUTES,*PSID_AND_ATTRIBUTES; + + typedef SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY]; + typedef SID_AND_ATTRIBUTES_ARRAY *PSID_AND_ATTRIBUTES_ARRAY; + +#define SECURITY_NULL_SID_AUTHORITY {0,0,0,0,0,0} +#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} +#define SECURITY_LOCAL_SID_AUTHORITY {0,0,0,0,0,2} +#define SECURITY_CREATOR_SID_AUTHORITY {0,0,0,0,0,3} +#define SECURITY_NON_UNIQUE_AUTHORITY {0,0,0,0,0,4} +#define SECURITY_RESOURCE_MANAGER_AUTHORITY {0,0,0,0,0,9} + +#define SECURITY_NULL_RID (0x00000000L) +#define SECURITY_WORLD_RID (0x00000000L) +#define SECURITY_LOCAL_RID (0x00000000L) + +#define SECURITY_CREATOR_OWNER_RID (0x00000000L) +#define SECURITY_CREATOR_GROUP_RID (0x00000001L) + +#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L) +#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L) + +#define SECURITY_NT_AUTHORITY {0,0,0,0,0,5} + +#define SECURITY_DIALUP_RID (0x00000001L) +#define SECURITY_NETWORK_RID (0x00000002L) +#define SECURITY_BATCH_RID (0x00000003L) +#define SECURITY_INTERACTIVE_RID (0x00000004L) +#define SECURITY_LOGON_IDS_RID (0x00000005L) +#define SECURITY_LOGON_IDS_RID_COUNT (3L) +#define SECURITY_SERVICE_RID (0x00000006L) +#define SECURITY_ANONYMOUS_LOGON_RID (0x00000007L) +#define SECURITY_PROXY_RID (0x00000008L) +#define SECURITY_ENTERPRISE_CONTROLLERS_RID (0x00000009L) +#define SECURITY_SERVER_LOGON_RID SECURITY_ENTERPRISE_CONTROLLERS_RID +#define SECURITY_PRINCIPAL_SELF_RID (0x0000000AL) +#define SECURITY_AUTHENTICATED_USER_RID (0x0000000BL) +#define SECURITY_RESTRICTED_CODE_RID (0x0000000CL) +#define SECURITY_TERMINAL_SERVER_RID (0x0000000DL) +#define SECURITY_REMOTE_LOGON_RID (0x0000000EL) +#define SECURITY_THIS_ORGANIZATION_RID (0x0000000FL) +#define SECURITY_IUSER_RID (0x00000011L) + +#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L) +#define SECURITY_LOCAL_SERVICE_RID (0x00000013L) +#define SECURITY_NETWORK_SERVICE_RID (0x00000014L) + +#define SECURITY_NT_NON_UNIQUE (0x00000015L) +#define SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT (3L) + +#define SECURITY_ENTERPRISE_READONLY_CONTROLLERS_RID (0x00000016L) + +#define SECURITY_BUILTIN_DOMAIN_RID (0x00000020L) +#define SECURITY_WRITE_RESTRICTED_CODE_RID (0x00000021L) + +#define SECURITY_PACKAGE_BASE_RID (0x00000040L) +#define SECURITY_PACKAGE_RID_COUNT (2L) +#define SECURITY_PACKAGE_NTLM_RID (0x0000000AL) +#define SECURITY_PACKAGE_SCHANNEL_RID (0x0000000EL) +#define SECURITY_PACKAGE_DIGEST_RID (0x00000015L) + +#define SECURITY_SERVICE_ID_BASE_RID (0x00000050L) +#define SECURITY_SERVICE_ID_RID_COUNT (6L) + +#define SECURITY_RESERVED_ID_BASE_RID (0x00000051L) + +#define SECURITY_MAX_ALWAYS_FILTERED (0x000003E7L) +#define SECURITY_MIN_NEVER_FILTERED (0x000003E8L) + +#define SECURITY_OTHER_ORGANIZATION_RID (0x000003E8L) + +#define FOREST_USER_RID_MAX (0x000001F3L) + +#define DOMAIN_USER_RID_ADMIN (0x000001F4L) +#define DOMAIN_USER_RID_GUEST (0x000001F5L) +#define DOMAIN_USER_RID_KRBTGT (0x000001F6L) + +#define DOMAIN_USER_RID_MAX (0x000003E7L) + +#define DOMAIN_GROUP_RID_ADMINS (0x00000200L) +#define DOMAIN_GROUP_RID_USERS (0x00000201L) +#define DOMAIN_GROUP_RID_GUESTS (0x00000202L) +#define DOMAIN_GROUP_RID_COMPUTERS (0x00000203L) +#define DOMAIN_GROUP_RID_CONTROLLERS (0x00000204L) +#define DOMAIN_GROUP_RID_CERT_ADMINS (0x00000205L) +#define DOMAIN_GROUP_RID_SCHEMA_ADMINS (0x00000206L) +#define DOMAIN_GROUP_RID_ENTERPRISE_ADMINS (0x00000207L) +#define DOMAIN_GROUP_RID_POLICY_ADMINS (0x00000208L) +#define DOMAIN_GROUP_RID_READONLY_CONTROLLERS (0x00000209L) + +#define DOMAIN_ALIAS_RID_ADMINS (0x00000220L) +#define DOMAIN_ALIAS_RID_USERS (0x00000221L) +#define DOMAIN_ALIAS_RID_GUESTS (0x00000222L) +#define DOMAIN_ALIAS_RID_POWER_USERS (0x00000223L) + +#define DOMAIN_ALIAS_RID_ACCOUNT_OPS (0x00000224L) +#define DOMAIN_ALIAS_RID_SYSTEM_OPS (0x00000225L) +#define DOMAIN_ALIAS_RID_PRINT_OPS (0x00000226L) +#define DOMAIN_ALIAS_RID_BACKUP_OPS (0x00000227L) + +#define DOMAIN_ALIAS_RID_REPLICATOR (0x00000228L) +#define DOMAIN_ALIAS_RID_RAS_SERVERS (0x00000229L) +#define DOMAIN_ALIAS_RID_PREW2KCOMPACCESS (0x0000022AL) +#define DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS (0x0000022BL) +#define DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS (0x0000022CL) +#define DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS (0x0000022DL) + +#define DOMAIN_ALIAS_RID_MONITORING_USERS (0x0000022EL) +#define DOMAIN_ALIAS_RID_LOGGING_USERS (0x0000022FL) +#define DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS (0x00000230L) +#define DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS (0x00000231L) +#define DOMAIN_ALIAS_RID_DCOM_USERS (0x00000232L) + +#define DOMAIN_ALIAS_RID_IUSERS (0x00000238L) +#define DOMAIN_ALIAS_RID_CRYPTO_OPERATORS (0x00000239L) +#define DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP (0x0000023BL) +#define DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP (0x0000023CL) +#define DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP (0x0000023DL) + +#define SECURITY_MANDATORY_LABEL_AUTHORITY {0,0,0,0,0,16} +#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L) +#define SECURITY_MANDATORY_LOW_RID (0x00001000L) +#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L) +#define SECURITY_MANDATORY_HIGH_RID (0x00003000L) +#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L) +#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L) + +#define SECURITY_MANDATORY_MAXIMUM_USER_RID SECURITY_MANDATORY_SYSTEM_RID + +#define MANDATORY_LEVEL_TO_MANDATORY_RID(IL) (IL * 0x1000) + + typedef enum { + WinNullSid = 0,WinWorldSid = 1,WinLocalSid = 2,WinCreatorOwnerSid = 3,WinCreatorGroupSid = 4,WinCreatorOwnerServerSid = 5,WinCreatorGroupServerSid = 6,WinNtAuthoritySid = 7,WinDialupSid = 8,WinNetworkSid = 9,WinBatchSid = 10,WinInteractiveSid = 11,WinServiceSid = 12,WinAnonymousSid = 13,WinProxySid = 14,WinEnterpriseControllersSid = 15,WinSelfSid = 16,WinAuthenticatedUserSid = 17,WinRestrictedCodeSid = 18,WinTerminalServerSid = 19,WinRemoteLogonIdSid = 20,WinLogonIdsSid = 21,WinLocalSystemSid = 22,WinLocalServiceSid = 23,WinNetworkServiceSid = 24,WinBuiltinDomainSid = 25,WinBuiltinAdministratorsSid = 26,WinBuiltinUsersSid = 27,WinBuiltinGuestsSid = 28,WinBuiltinPowerUsersSid = 29,WinBuiltinAccountOperatorsSid = 30,WinBuiltinSystemOperatorsSid = 31,WinBuiltinPrintOperatorsSid = 32,WinBuiltinBackupOperatorsSid = 33,WinBuiltinReplicatorSid = 34,WinBuiltinPreWindows2000CompatibleAccessSid = 35,WinBuiltinRemoteDesktopUsersSid = 36,WinBuiltinNetworkConfigurationOperatorsSid = 37,WinAccountAdministratorSid = 38,WinAccountGuestSid = 39,WinAccountKrbtgtSid = 40,WinAccountDomainAdminsSid = 41,WinAccountDomainUsersSid = 42,WinAccountDomainGuestsSid = 43,WinAccountComputersSid = 44,WinAccountControllersSid = 45,WinAccountCertAdminsSid = 46,WinAccountSchemaAdminsSid = 47,WinAccountEnterpriseAdminsSid = 48,WinAccountPolicyAdminsSid = 49,WinAccountRasAndIasServersSid = 50,WinNTLMAuthenticationSid = 51,WinDigestAuthenticationSid = 52,WinSChannelAuthenticationSid = 53,WinThisOrganizationSid = 54,WinOtherOrganizationSid = 55,WinBuiltinIncomingForestTrustBuildersSid = 56,WinBuiltinPerfMonitoringUsersSid = 57,WinBuiltinPerfLoggingUsersSid = 58,WinBuiltinAuthorizationAccessSid = 59,WinBuiltinTerminalServerLicenseServersSid = 60,WinBuiltinDCOMUsersSid = 61 + } WELL_KNOWN_SID_TYPE; + +#define SYSTEM_LUID { 0x3E7,0x0 } +#define ANONYMOUS_LOGON_LUID { 0x3e6,0x0 } +#define LOCALSERVICE_LUID { 0x3e5,0x0 } +#define NETWORKSERVICE_LUID { 0x3e4,0x0 } +#define IUSER_LUID { 0x3e3, 0x0 } + +#define SE_GROUP_MANDATORY (0x00000001L) +#define SE_GROUP_ENABLED_BY_DEFAULT (0x00000002L) +#define SE_GROUP_ENABLED (0x00000004L) +#define SE_GROUP_OWNER (0x00000008L) +#define SE_GROUP_USE_FOR_DENY_ONLY (0x00000010L) +#define SE_GROUP_INTEGRITY (0x00000020L) +#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L) +#define SE_GROUP_LOGON_ID (0xC0000000L) +#define SE_GROUP_RESOURCE (0x20000000L) + +#define ACL_REVISION (2) +#define ACL_REVISION_DS (4) + +#define ACL_REVISION1 (1) +#define MIN_ACL_REVISION ACL_REVISION2 +#define ACL_REVISION2 (2) +#define ACL_REVISION3 (3) +#define ACL_REVISION4 (4) +#define MAX_ACL_REVISION ACL_REVISION4 + + typedef struct _ACL { + BYTE AclRevision; + BYTE Sbz1; + WORD AclSize; + WORD AceCount; + WORD Sbz2; + } ACL; + typedef ACL *PACL; + + typedef struct _ACE_HEADER { + BYTE AceType; + BYTE AceFlags; + WORD AceSize; + } ACE_HEADER; + typedef ACE_HEADER *PACE_HEADER; + +#define ACCESS_MIN_MS_ACE_TYPE (0x0) +#define ACCESS_ALLOWED_ACE_TYPE (0x0) +#define ACCESS_DENIED_ACE_TYPE (0x1) +#define SYSTEM_AUDIT_ACE_TYPE (0x2) +#define SYSTEM_ALARM_ACE_TYPE (0x3) +#define ACCESS_MAX_MS_V2_ACE_TYPE (0x3) + +#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE (0x4) +#define ACCESS_MAX_MS_V3_ACE_TYPE (0x4) + +#define ACCESS_MIN_MS_OBJECT_ACE_TYPE (0x5) +#define ACCESS_ALLOWED_OBJECT_ACE_TYPE (0x5) +#define ACCESS_DENIED_OBJECT_ACE_TYPE (0x6) +#define SYSTEM_AUDIT_OBJECT_ACE_TYPE (0x7) +#define SYSTEM_ALARM_OBJECT_ACE_TYPE (0x8) +#define ACCESS_MAX_MS_OBJECT_ACE_TYPE (0x8) + +#define ACCESS_MAX_MS_V4_ACE_TYPE (0x8) +#define ACCESS_MAX_MS_ACE_TYPE (0x8) + +#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE (0x9) +#define ACCESS_DENIED_CALLBACK_ACE_TYPE (0xA) +#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE (0xB) +#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE (0xC) +#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE (0xD) +#define SYSTEM_ALARM_CALLBACK_ACE_TYPE (0xE) +#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE (0xF) +#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE (0x10) + +#define SYSTEM_MANDATORY_LABEL_ACE_TYPE (0x11) +#define ACCESS_MAX_MS_V5_ACE_TYPE (0x11) + +#define OBJECT_INHERIT_ACE (0x1) +#define CONTAINER_INHERIT_ACE (0x2) +#define NO_PROPAGATE_INHERIT_ACE (0x4) +#define INHERIT_ONLY_ACE (0x8) +#define INHERITED_ACE (0x10) +#define VALID_INHERIT_FLAGS (0x1F) + +#define SUCCESSFUL_ACCESS_ACE_FLAG (0x40) +#define FAILED_ACCESS_ACE_FLAG (0x80) + + typedef struct _ACCESS_ALLOWED_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } ACCESS_ALLOWED_ACE; + + typedef ACCESS_ALLOWED_ACE *PACCESS_ALLOWED_ACE; + + typedef struct _ACCESS_DENIED_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } ACCESS_DENIED_ACE; + typedef ACCESS_DENIED_ACE *PACCESS_DENIED_ACE; + + typedef struct _SYSTEM_AUDIT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } SYSTEM_AUDIT_ACE; + typedef SYSTEM_AUDIT_ACE *PSYSTEM_AUDIT_ACE; + + typedef struct _SYSTEM_ALARM_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + } SYSTEM_ALARM_ACE; + typedef SYSTEM_ALARM_ACE *PSYSTEM_ALARM_ACE; + + typedef struct _ACCESS_ALLOWED_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } ACCESS_ALLOWED_OBJECT_ACE,*PACCESS_ALLOWED_OBJECT_ACE; + + typedef struct _ACCESS_DENIED_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } ACCESS_DENIED_OBJECT_ACE,*PACCESS_DENIED_OBJECT_ACE; + + typedef struct _SYSTEM_AUDIT_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } SYSTEM_AUDIT_OBJECT_ACE,*PSYSTEM_AUDIT_OBJECT_ACE; + + typedef struct _SYSTEM_ALARM_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + } SYSTEM_ALARM_OBJECT_ACE,*PSYSTEM_ALARM_OBJECT_ACE; + + typedef struct _ACCESS_ALLOWED_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } ACCESS_ALLOWED_CALLBACK_ACE,*PACCESS_ALLOWED_CALLBACK_ACE; + + typedef struct _ACCESS_DENIED_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } ACCESS_DENIED_CALLBACK_ACE,*PACCESS_DENIED_CALLBACK_ACE; + + typedef struct _SYSTEM_AUDIT_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } SYSTEM_AUDIT_CALLBACK_ACE,*PSYSTEM_AUDIT_CALLBACK_ACE; + + typedef struct _SYSTEM_ALARM_CALLBACK_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; + + } SYSTEM_ALARM_CALLBACK_ACE,*PSYSTEM_ALARM_CALLBACK_ACE; + + typedef struct _ACCESS_ALLOWED_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } ACCESS_ALLOWED_CALLBACK_OBJECT_ACE,*PACCESS_ALLOWED_CALLBACK_OBJECT_ACE; + + typedef struct _ACCESS_DENIED_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } ACCESS_DENIED_CALLBACK_OBJECT_ACE,*PACCESS_DENIED_CALLBACK_OBJECT_ACE; + + typedef struct _SYSTEM_AUDIT_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } SYSTEM_AUDIT_CALLBACK_OBJECT_ACE,*PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE; + + typedef struct _SYSTEM_ALARM_CALLBACK_OBJECT_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD Flags; + GUID ObjectType; + GUID InheritedObjectType; + DWORD SidStart; + + } SYSTEM_ALARM_CALLBACK_OBJECT_ACE,*PSYSTEM_ALARM_CALLBACK_OBJECT_ACE; + +#define ACE_OBJECT_TYPE_PRESENT 0x1 +#define ACE_INHERITED_OBJECT_TYPE_PRESENT 0x2 + + typedef enum _ACL_INFORMATION_CLASS { + AclRevisionInformation = 1,AclSizeInformation + } ACL_INFORMATION_CLASS; + + typedef struct _ACL_REVISION_INFORMATION { + DWORD AclRevision; + } ACL_REVISION_INFORMATION; + typedef ACL_REVISION_INFORMATION *PACL_REVISION_INFORMATION; + + typedef struct _ACL_SIZE_INFORMATION { + DWORD AceCount; + DWORD AclBytesInUse; + DWORD AclBytesFree; + } ACL_SIZE_INFORMATION; + typedef ACL_SIZE_INFORMATION *PACL_SIZE_INFORMATION; + +#define SECURITY_DESCRIPTOR_REVISION (1) +#define SECURITY_DESCRIPTOR_REVISION1 (1) + +#define SECURITY_DESCRIPTOR_MIN_LENGTH (sizeof(SECURITY_DESCRIPTOR)) + + typedef WORD SECURITY_DESCRIPTOR_CONTROL,*PSECURITY_DESCRIPTOR_CONTROL; + +#define SE_OWNER_DEFAULTED (0x0001) +#define SE_GROUP_DEFAULTED (0x0002) +#define SE_DACL_PRESENT (0x0004) +#define SE_DACL_DEFAULTED (0x0008) +#define SE_SACL_PRESENT (0x0010) +#define SE_SACL_DEFAULTED (0x0020) +#define SE_DACL_AUTO_INHERIT_REQ (0x0100) +#define SE_SACL_AUTO_INHERIT_REQ (0x0200) +#define SE_DACL_AUTO_INHERITED (0x0400) +#define SE_SACL_AUTO_INHERITED (0x0800) +#define SE_DACL_PROTECTED (0x1000) +#define SE_SACL_PROTECTED (0x2000) +#define SE_RM_CONTROL_VALID (0x4000) +#define SE_SELF_RELATIVE (0x8000) + + typedef struct _SECURITY_DESCRIPTOR_RELATIVE { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + DWORD Owner; + DWORD Group; + DWORD Sacl; + DWORD Dacl; + } SECURITY_DESCRIPTOR_RELATIVE,*PISECURITY_DESCRIPTOR_RELATIVE; + + typedef struct _SECURITY_DESCRIPTOR { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + PSID Owner; + PSID Group; + PACL Sacl; + PACL Dacl; + + } SECURITY_DESCRIPTOR,*PISECURITY_DESCRIPTOR; + + typedef struct _OBJECT_TYPE_LIST { + WORD Level; + WORD Sbz; + GUID *ObjectType; + } OBJECT_TYPE_LIST,*POBJECT_TYPE_LIST; + +#define ACCESS_OBJECT_GUID 0 +#define ACCESS_PROPERTY_SET_GUID 1 +#define ACCESS_PROPERTY_GUID 2 + +#define ACCESS_MAX_LEVEL 4 + + typedef enum _AUDIT_EVENT_TYPE { + AuditEventObjectAccess,AuditEventDirectoryServiceAccess + } AUDIT_EVENT_TYPE,*PAUDIT_EVENT_TYPE; + +#define AUDIT_ALLOW_NO_PRIVILEGE 0x1 + +#define ACCESS_DS_SOURCE_A "DS" +#define ACCESS_DS_SOURCE_W L"DS" +#define ACCESS_DS_OBJECT_TYPE_NAME_A "Directory Service Object" +#define ACCESS_DS_OBJECT_TYPE_NAME_W L"Directory Service Object" + +#define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L) +#define SE_PRIVILEGE_ENABLED (0x00000002L) +#define SE_PRIVILEGE_REMOVED (0X00000004L) +#define SE_PRIVILEGE_USED_FOR_ACCESS (0x80000000L) + +#define PRIVILEGE_SET_ALL_NECESSARY (1) + + typedef struct _PRIVILEGE_SET { + DWORD PrivilegeCount; + DWORD Control; + LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]; + } PRIVILEGE_SET,*PPRIVILEGE_SET; + +#define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege") +#define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege") +#define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege") +#define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege") +#define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege") +#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege") +#define SE_TCB_NAME TEXT("SeTcbPrivilege") +#define SE_SECURITY_NAME TEXT("SeSecurityPrivilege") +#define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege") +#define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege") +#define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege") +#define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege") +#define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege") +#define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege") +#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege") +#define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege") +#define SE_BACKUP_NAME TEXT("SeBackupPrivilege") +#define SE_RESTORE_NAME TEXT("SeRestorePrivilege") +#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege") +#define SE_DEBUG_NAME TEXT("SeDebugPrivilege") +#define SE_AUDIT_NAME TEXT("SeAuditPrivilege") +#define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege") +#define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege") +#define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege") +#define SE_UNDOCK_NAME TEXT("SeUndockPrivilege") +#define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege") +#define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege") +#define SE_MANAGE_VOLUME_NAME TEXT("SeManageVolumePrivilege") +#define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege") +#define SE_CREATE_GLOBAL_NAME TEXT("SeCreateGlobalPrivilege") + + typedef enum _SECURITY_IMPERSONATION_LEVEL { + SecurityAnonymous,SecurityIdentification,SecurityImpersonation,SecurityDelegation + } SECURITY_IMPERSONATION_LEVEL,*PSECURITY_IMPERSONATION_LEVEL; + +#define SECURITY_MAX_IMPERSONATION_LEVEL SecurityDelegation +#define SECURITY_MIN_IMPERSONATION_LEVEL SecurityAnonymous +#define DEFAULT_IMPERSONATION_LEVEL SecurityImpersonation +#define VALID_IMPERSONATION_LEVEL(L) (((L) >= SECURITY_MIN_IMPERSONATION_LEVEL) && ((L) <= SECURITY_MAX_IMPERSONATION_LEVEL)) + +#define TOKEN_ASSIGN_PRIMARY (0x0001) +#define TOKEN_DUPLICATE (0x0002) +#define TOKEN_IMPERSONATE (0x0004) +#define TOKEN_QUERY (0x0008) +#define TOKEN_QUERY_SOURCE (0x0010) +#define TOKEN_ADJUST_PRIVILEGES (0x0020) +#define TOKEN_ADJUST_GROUPS (0x0040) +#define TOKEN_ADJUST_DEFAULT (0x0080) +#define TOKEN_ADJUST_SESSIONID (0x0100) + +#define TOKEN_ALL_ACCESS_P (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) +#define TOKEN_ALL_ACCESS (TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID) +#define TOKEN_READ (STANDARD_RIGHTS_READ | TOKEN_QUERY) + +#define TOKEN_WRITE (STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT) + +#define TOKEN_EXECUTE (STANDARD_RIGHTS_EXECUTE) + + typedef enum _TOKEN_TYPE { + TokenPrimary = 1,TokenImpersonation + } TOKEN_TYPE; + typedef TOKEN_TYPE *PTOKEN_TYPE; + + typedef enum _TOKEN_INFORMATION_CLASS { + TokenUser = 1,TokenGroups,TokenPrivileges,TokenOwner,TokenPrimaryGroup,TokenDefaultDacl,TokenSource,TokenType,TokenImpersonationLevel, + TokenStatistics,TokenRestrictedSids,TokenSessionId,TokenGroupsAndPrivileges,TokenSessionReference,TokenSandBoxInert,TokenAuditPolicy, + TokenOrigin,MaxTokenInfoClass + } TOKEN_INFORMATION_CLASS,*PTOKEN_INFORMATION_CLASS; + + typedef struct _TOKEN_USER { + SID_AND_ATTRIBUTES User; + } TOKEN_USER,*PTOKEN_USER; + + typedef struct _TOKEN_GROUPS { + DWORD GroupCount; + SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; + } TOKEN_GROUPS,*PTOKEN_GROUPS; + + typedef struct _TOKEN_PRIVILEGES { + DWORD PrivilegeCount; + LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; + } TOKEN_PRIVILEGES,*PTOKEN_PRIVILEGES; + + typedef struct _TOKEN_OWNER { + PSID Owner; + } TOKEN_OWNER,*PTOKEN_OWNER; + + typedef struct _TOKEN_PRIMARY_GROUP { + PSID PrimaryGroup; + } TOKEN_PRIMARY_GROUP,*PTOKEN_PRIMARY_GROUP; + + typedef struct _TOKEN_DEFAULT_DACL { + PACL DefaultDacl; + } TOKEN_DEFAULT_DACL,*PTOKEN_DEFAULT_DACL; + + typedef struct _TOKEN_GROUPS_AND_PRIVILEGES { + DWORD SidCount; + DWORD SidLength; + PSID_AND_ATTRIBUTES Sids; + DWORD RestrictedSidCount; + DWORD RestrictedSidLength; + PSID_AND_ATTRIBUTES RestrictedSids; + DWORD PrivilegeCount; + DWORD PrivilegeLength; + PLUID_AND_ATTRIBUTES Privileges; + LUID AuthenticationId; + } TOKEN_GROUPS_AND_PRIVILEGES,*PTOKEN_GROUPS_AND_PRIVILEGES; + +#define TOKEN_AUDIT_SUCCESS_INCLUDE 0x1 +#define TOKEN_AUDIT_SUCCESS_EXCLUDE 0x2 +#define TOKEN_AUDIT_FAILURE_INCLUDE 0x4 +#define TOKEN_AUDIT_FAILURE_EXCLUDE 0x8 + +#define VALID_AUDIT_POLICY_BITS (TOKEN_AUDIT_SUCCESS_INCLUDE | TOKEN_AUDIT_SUCCESS_EXCLUDE | TOKEN_AUDIT_FAILURE_INCLUDE | TOKEN_AUDIT_FAILURE_EXCLUDE) +#define VALID_TOKEN_AUDIT_POLICY_ELEMENT(P) ((((P).PolicyMask & ~VALID_AUDIT_POLICY_BITS)==0) && ((P).Category <= AuditEventMaxType)) + + typedef struct _TOKEN_AUDIT_POLICY_ELEMENT { + DWORD Category; + DWORD PolicyMask; + } TOKEN_AUDIT_POLICY_ELEMENT,*PTOKEN_AUDIT_POLICY_ELEMENT; + + typedef struct _TOKEN_AUDIT_POLICY { + DWORD PolicyCount; + TOKEN_AUDIT_POLICY_ELEMENT Policy[ANYSIZE_ARRAY]; + } TOKEN_AUDIT_POLICY,*PTOKEN_AUDIT_POLICY; + +#define PER_USER_AUDITING_POLICY_SIZE(p) (sizeof(TOKEN_AUDIT_POLICY) + (((p)->PolicyCount > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((p)->PolicyCount - ANYSIZE_ARRAY)) : 0)) +#define PER_USER_AUDITING_POLICY_SIZE_BY_COUNT(C) (sizeof(TOKEN_AUDIT_POLICY) + (((C) > ANYSIZE_ARRAY) ? (sizeof(TOKEN_AUDIT_POLICY_ELEMENT) *((C) - ANYSIZE_ARRAY)) : 0)) + +#define TOKEN_SOURCE_LENGTH 8 + + typedef struct _TOKEN_SOURCE { + CHAR SourceName[TOKEN_SOURCE_LENGTH]; + LUID SourceIdentifier; + } TOKEN_SOURCE,*PTOKEN_SOURCE; + + typedef struct _TOKEN_STATISTICS { + LUID TokenId; + LUID AuthenticationId; + LARGE_INTEGER ExpirationTime; + TOKEN_TYPE TokenType; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + DWORD DynamicCharged; + DWORD DynamicAvailable; + DWORD GroupCount; + DWORD PrivilegeCount; + LUID ModifiedId; + } TOKEN_STATISTICS,*PTOKEN_STATISTICS; + + typedef struct _TOKEN_CONTROL { + LUID TokenId; + LUID AuthenticationId; + LUID ModifiedId; + TOKEN_SOURCE TokenSource; + } TOKEN_CONTROL,*PTOKEN_CONTROL; + + typedef struct _TOKEN_ORIGIN { + LUID OriginatingLogonSession; + } TOKEN_ORIGIN,*PTOKEN_ORIGIN; + +#define SECURITY_DYNAMIC_TRACKING (TRUE) +#define SECURITY_STATIC_TRACKING (FALSE) + + typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE,*PSECURITY_CONTEXT_TRACKING_MODE; + + typedef struct _SECURITY_QUALITY_OF_SERVICE { + DWORD Length; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode; + BOOLEAN EffectiveOnly; + } SECURITY_QUALITY_OF_SERVICE,*PSECURITY_QUALITY_OF_SERVICE; + + typedef struct _SE_IMPERSONATION_STATE { + PACCESS_TOKEN Token; + BOOLEAN CopyOnOpen; + BOOLEAN EffectiveOnly; + SECURITY_IMPERSONATION_LEVEL Level; + } SE_IMPERSONATION_STATE,*PSE_IMPERSONATION_STATE; + +#define DISABLE_MAX_PRIVILEGE 0x1 +#define SANDBOX_INERT 0x2 + + typedef DWORD SECURITY_INFORMATION,*PSECURITY_INFORMATION; + +#define OWNER_SECURITY_INFORMATION (0x00000001L) +#define GROUP_SECURITY_INFORMATION (0x00000002L) +#define DACL_SECURITY_INFORMATION (0x00000004L) +#define SACL_SECURITY_INFORMATION (0x00000008L) + +#define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L) +#define PROTECTED_SACL_SECURITY_INFORMATION (0x40000000L) +#define UNPROTECTED_DACL_SECURITY_INFORMATION (0x20000000L) +#define UNPROTECTED_SACL_SECURITY_INFORMATION (0x10000000L) + +#define PROCESS_TERMINATE (0x0001) +#define PROCESS_CREATE_THREAD (0x0002) +#define PROCESS_SET_SESSIONID (0x0004) +#define PROCESS_VM_OPERATION (0x0008) +#define PROCESS_VM_READ (0x0010) +#define PROCESS_VM_WRITE (0x0020) +#define PROCESS_DUP_HANDLE (0x0040) +#define PROCESS_CREATE_PROCESS (0x0080) +#define PROCESS_SET_QUOTA (0x0100) +#define PROCESS_SET_INFORMATION (0x0200) +#define PROCESS_QUERY_INFORMATION (0x0400) +#define PROCESS_SUSPEND_RESUME (0x0800) +#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF) + +#ifdef _WIN64 +#define MAXIMUM_PROCESSORS 64 +#else +#define MAXIMUM_PROCESSORS 32 +#endif + +#define THREAD_TERMINATE (0x0001) +#define THREAD_SUSPEND_RESUME (0x0002) +#define THREAD_GET_CONTEXT (0x0008) +#define THREAD_SET_CONTEXT (0x0010) +#define THREAD_SET_INFORMATION (0x0020) +#define THREAD_QUERY_INFORMATION (0x0040) +#define THREAD_SET_THREAD_TOKEN (0x0080) +#define THREAD_IMPERSONATE (0x0100) +#define THREAD_DIRECT_IMPERSONATION (0x0200) + +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF) + +#define JOB_OBJECT_ASSIGN_PROCESS (0x0001) +#define JOB_OBJECT_SET_ATTRIBUTES (0x0002) +#define JOB_OBJECT_QUERY (0x0004) +#define JOB_OBJECT_TERMINATE (0x0008) +#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010) +#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1F) + + typedef struct _JOB_SET_ARRAY { + HANDLE JobHandle; + DWORD MemberLevel; + DWORD Flags; + } JOB_SET_ARRAY,*PJOB_SET_ARRAY; + +#define FLS_MAXIMUM_AVAILABLE 128 +#define TLS_MINIMUM_AVAILABLE 64 + +#ifndef _NT_TIB_DEFINED +#define _NT_TIB_DEFINED + typedef struct _NT_TIB { + struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; + PVOID StackBase; + PVOID StackLimit; + PVOID SubSystemTib; + union { + PVOID FiberData; + DWORD Version; + }; + PVOID ArbitraryUserPointer; + struct _NT_TIB *Self; + } NT_TIB; + typedef NT_TIB *PNT_TIB; +#endif + + typedef struct _NT_TIB32 { + DWORD ExceptionList; + DWORD StackBase; + DWORD StackLimit; + DWORD SubSystemTib; + union { + DWORD FiberData; + DWORD Version; + }; + DWORD ArbitraryUserPointer; + DWORD Self; + } NT_TIB32,*PNT_TIB32; + + typedef struct _NT_TIB64 { + DWORD64 ExceptionList; + DWORD64 StackBase; + DWORD64 StackLimit; + DWORD64 SubSystemTib; + union { + DWORD64 FiberData; + DWORD Version; + }; + DWORD64 ArbitraryUserPointer; + DWORD64 Self; + } NT_TIB64,*PNT_TIB64; + +#if !defined(I_X86_) && !defined(_IA64_) && !defined(_AMD64_) +#define WX86 +#endif + +#define THREAD_BASE_PRIORITY_LOWRT 15 +#define THREAD_BASE_PRIORITY_MAX 2 +#define THREAD_BASE_PRIORITY_MIN (-2) +#define THREAD_BASE_PRIORITY_IDLE (-15) + + typedef struct _QUOTA_LIMITS { + SIZE_T PagedPoolLimit; + SIZE_T NonPagedPoolLimit; + SIZE_T MinimumWorkingSetSize; + SIZE_T MaximumWorkingSetSize; + SIZE_T PagefileLimit; + LARGE_INTEGER TimeLimit; + } QUOTA_LIMITS,*PQUOTA_LIMITS; + +#define QUOTA_LIMITS_HARDWS_MIN_ENABLE 0x00000001 +#define QUOTA_LIMITS_HARDWS_MIN_DISABLE 0x00000002 +#define QUOTA_LIMITS_HARDWS_MAX_ENABLE 0x00000004 +#define QUOTA_LIMITS_HARDWS_MAX_DISABLE 0x00000008 + + typedef struct _QUOTA_LIMITS_EX { + SIZE_T PagedPoolLimit; + SIZE_T NonPagedPoolLimit; + SIZE_T MinimumWorkingSetSize; + SIZE_T MaximumWorkingSetSize; + SIZE_T PagefileLimit; + LARGE_INTEGER TimeLimit; + SIZE_T Reserved1; + SIZE_T Reserved2; + SIZE_T Reserved3; + SIZE_T Reserved4; + DWORD Flags; + DWORD Reserved5; + } QUOTA_LIMITS_EX,*PQUOTA_LIMITS_EX; + + typedef struct _IO_COUNTERS { + ULONGLONG ReadOperationCount; + ULONGLONG WriteOperationCount; + ULONGLONG OtherOperationCount; + ULONGLONG ReadTransferCount; + ULONGLONG WriteTransferCount; + ULONGLONG OtherTransferCount; + } IO_COUNTERS; + typedef IO_COUNTERS *PIO_COUNTERS; + + typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION { + LARGE_INTEGER TotalUserTime; + LARGE_INTEGER TotalKernelTime; + LARGE_INTEGER ThisPeriodTotalUserTime; + LARGE_INTEGER ThisPeriodTotalKernelTime; + DWORD TotalPageFaultCount; + DWORD TotalProcesses; + DWORD ActiveProcesses; + DWORD TotalTerminatedProcesses; + } JOBOBJECT_BASIC_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION; + + typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION { + LARGE_INTEGER PerProcessUserTimeLimit; + LARGE_INTEGER PerJobUserTimeLimit; + DWORD LimitFlags; + SIZE_T MinimumWorkingSetSize; + SIZE_T MaximumWorkingSetSize; + DWORD ActiveProcessLimit; + ULONG_PTR Affinity; + DWORD PriorityClass; + DWORD SchedulingClass; + } JOBOBJECT_BASIC_LIMIT_INFORMATION,*PJOBOBJECT_BASIC_LIMIT_INFORMATION; + + typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION { + JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; + IO_COUNTERS IoInfo; + SIZE_T ProcessMemoryLimit; + SIZE_T JobMemoryLimit; + SIZE_T PeakProcessMemoryUsed; + SIZE_T PeakJobMemoryUsed; + } JOBOBJECT_EXTENDED_LIMIT_INFORMATION,*PJOBOBJECT_EXTENDED_LIMIT_INFORMATION; + + typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST { + DWORD NumberOfAssignedProcesses; + DWORD NumberOfProcessIdsInList; + ULONG_PTR ProcessIdList[1]; + } JOBOBJECT_BASIC_PROCESS_ID_LIST,*PJOBOBJECT_BASIC_PROCESS_ID_LIST; + + typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS { + DWORD UIRestrictionsClass; + } JOBOBJECT_BASIC_UI_RESTRICTIONS,*PJOBOBJECT_BASIC_UI_RESTRICTIONS; + + typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION { + DWORD SecurityLimitFlags; + HANDLE JobToken; + PTOKEN_GROUPS SidsToDisable; + PTOKEN_PRIVILEGES PrivilegesToDelete; + PTOKEN_GROUPS RestrictedSids; + } JOBOBJECT_SECURITY_LIMIT_INFORMATION,*PJOBOBJECT_SECURITY_LIMIT_INFORMATION; + + typedef struct _JOBOBJECT_END_OF_JOB_TIME_INFORMATION { + DWORD EndOfJobTimeAction; + } JOBOBJECT_END_OF_JOB_TIME_INFORMATION,*PJOBOBJECT_END_OF_JOB_TIME_INFORMATION; + + typedef struct _JOBOBJECT_ASSOCIATE_COMPLETION_PORT { + PVOID CompletionKey; + HANDLE CompletionPort; + } JOBOBJECT_ASSOCIATE_COMPLETION_PORT,*PJOBOBJECT_ASSOCIATE_COMPLETION_PORT; + + typedef struct _JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION { + JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo; + IO_COUNTERS IoInfo; + } JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION,*PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION; + + typedef struct _JOBOBJECT_JOBSET_INFORMATION { + DWORD MemberLevel; + } JOBOBJECT_JOBSET_INFORMATION,*PJOBOBJECT_JOBSET_INFORMATION; + +#define JOB_OBJECT_TERMINATE_AT_END_OF_JOB 0 +#define JOB_OBJECT_POST_AT_END_OF_JOB 1 + +#define JOB_OBJECT_MSG_END_OF_JOB_TIME 1 +#define JOB_OBJECT_MSG_END_OF_PROCESS_TIME 2 +#define JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT 3 +#define JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO 4 +#define JOB_OBJECT_MSG_NEW_PROCESS 6 +#define JOB_OBJECT_MSG_EXIT_PROCESS 7 +#define JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS 8 +#define JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT 9 +#define JOB_OBJECT_MSG_JOB_MEMORY_LIMIT 10 + +#define JOB_OBJECT_LIMIT_WORKINGSET 0x00000001 +#define JOB_OBJECT_LIMIT_PROCESS_TIME 0x00000002 +#define JOB_OBJECT_LIMIT_JOB_TIME 0x00000004 +#define JOB_OBJECT_LIMIT_ACTIVE_PROCESS 0x00000008 +#define JOB_OBJECT_LIMIT_AFFINITY 0x00000010 +#define JOB_OBJECT_LIMIT_PRIORITY_CLASS 0x00000020 +#define JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME 0x00000040 +#define JOB_OBJECT_LIMIT_SCHEDULING_CLASS 0x00000080 + +#define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100 +#define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200 +#define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400 +#define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800 +#define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000 +#define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 + +#define JOB_OBJECT_LIMIT_RESERVED2 0x00004000 +#define JOB_OBJECT_LIMIT_RESERVED3 0x00008000 +#define JOB_OBJECT_LIMIT_RESERVED4 0x00010000 +#define JOB_OBJECT_LIMIT_RESERVED5 0x00020000 +#define JOB_OBJECT_LIMIT_RESERVED6 0x00040000 + +#define JOB_OBJECT_LIMIT_VALID_FLAGS 0x0007ffff + +#define JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS 0x000000ff +#define JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS 0x00003fff +#define JOB_OBJECT_RESERVED_LIMIT_VALID_FLAGS 0x0007ffff + +#define JOB_OBJECT_UILIMIT_NONE 0x00000000 + +#define JOB_OBJECT_UILIMIT_HANDLES 0x00000001 +#define JOB_OBJECT_UILIMIT_READCLIPBOARD 0x00000002 +#define JOB_OBJECT_UILIMIT_WRITECLIPBOARD 0x00000004 +#define JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS 0x00000008 +#define JOB_OBJECT_UILIMIT_DISPLAYSETTINGS 0x00000010 +#define JOB_OBJECT_UILIMIT_GLOBALATOMS 0x00000020 +#define JOB_OBJECT_UILIMIT_DESKTOP 0x00000040 +#define JOB_OBJECT_UILIMIT_EXITWINDOWS 0x00000080 + +#define JOB_OBJECT_UILIMIT_ALL 0x000000FF + +#define JOB_OBJECT_UI_VALID_FLAGS 0x000000FF + +#define JOB_OBJECT_SECURITY_NO_ADMIN 0x00000001 +#define JOB_OBJECT_SECURITY_RESTRICTED_TOKEN 0x00000002 +#define JOB_OBJECT_SECURITY_ONLY_TOKEN 0x00000004 +#define JOB_OBJECT_SECURITY_FILTER_TOKENS 0x00000008 + +#define JOB_OBJECT_SECURITY_VALID_FLAGS 0x0000000f + + typedef enum _JOBOBJECTINFOCLASS { + JobObjectBasicAccountingInformation = 1,JobObjectBasicLimitInformation,JobObjectBasicProcessIdList,JobObjectBasicUIRestrictions, + JobObjectSecurityLimitInformation,JobObjectEndOfJobTimeInformation,JobObjectAssociateCompletionPortInformation, + JobObjectBasicAndIoAccountingInformation,JobObjectExtendedLimitInformation,JobObjectJobSetInformation,MaxJobObjectInfoClass + } JOBOBJECTINFOCLASS; + +#define EVENT_MODIFY_STATE 0x0002 +#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define MUTANT_QUERY_STATE 0x0001 + +#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| MUTANT_QUERY_STATE) +#define SEMAPHORE_MODIFY_STATE 0x0002 +#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define TIMER_QUERY_STATE 0x0001 +#define TIMER_MODIFY_STATE 0x0002 + +#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE| TIMER_QUERY_STATE|TIMER_MODIFY_STATE) + +#define TIME_ZONE_ID_UNKNOWN 0 +#define TIME_ZONE_ID_STANDARD 1 +#define TIME_ZONE_ID_DAYLIGHT 2 + + typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { + RelationProcessorCore,RelationNumaNode,RelationCache + } LOGICAL_PROCESSOR_RELATIONSHIP; + +#define LTP_PC_SMT 0x1 + + typedef enum _PROCESSOR_CACHE_TYPE { + CacheUnified,CacheInstruction,CacheData,CacheTrace + } PROCESSOR_CACHE_TYPE; + +#define CACHE_FULLY_ASSOCIATIVE 0xFF + + typedef struct _CACHE_DESCRIPTOR { + BYTE Level; + BYTE Associativity; + WORD LineSize; + DWORD Size; + PROCESSOR_CACHE_TYPE Type; + } CACHE_DESCRIPTOR,*PCACHE_DESCRIPTOR; + + typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { + ULONG_PTR ProcessorMask; + LOGICAL_PROCESSOR_RELATIONSHIP Relationship; + union { + struct { + BYTE Flags; + } ProcessorCore; + struct { + DWORD NodeNumber; + } NumaNode; + CACHE_DESCRIPTOR Cache; + ULONGLONG Reserved[2]; + }; + } SYSTEM_LOGICAL_PROCESSOR_INFORMATION,*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; + +#define PROCESSOR_INTEL_386 386 +#define PROCESSOR_INTEL_486 486 +#define PROCESSOR_INTEL_PENTIUM 586 +#define PROCESSOR_INTEL_IA64 2200 +#define PROCESSOR_AMD_X8664 8664 +#define PROCESSOR_MIPS_R4000 4000 +#define PROCESSOR_ALPHA_21064 21064 +#define PROCESSOR_PPC_601 601 +#define PROCESSOR_PPC_603 603 +#define PROCESSOR_PPC_604 604 +#define PROCESSOR_PPC_620 620 +#define PROCESSOR_HITACHI_SH3 10003 +#define PROCESSOR_HITACHI_SH3E 10004 +#define PROCESSOR_HITACHI_SH4 10005 +#define PROCESSOR_MOTOROLA_821 821 +#define PROCESSOR_SHx_SH3 103 +#define PROCESSOR_SHx_SH4 104 +#define PROCESSOR_STRONGARM 2577 +#define PROCESSOR_ARM720 1824 +#define PROCESSOR_ARM820 2080 +#define PROCESSOR_ARM920 2336 +#define PROCESSOR_ARM_7TDMI 70001 +#define PROCESSOR_OPTIL 0x494f + +#define PROCESSOR_ARCHITECTURE_INTEL 0 +#define PROCESSOR_ARCHITECTURE_MIPS 1 +#define PROCESSOR_ARCHITECTURE_ALPHA 2 +#define PROCESSOR_ARCHITECTURE_PPC 3 +#define PROCESSOR_ARCHITECTURE_SHX 4 +#define PROCESSOR_ARCHITECTURE_ARM 5 +#define PROCESSOR_ARCHITECTURE_IA64 6 +#define PROCESSOR_ARCHITECTURE_ALPHA64 7 +#define PROCESSOR_ARCHITECTURE_MSIL 8 +#define PROCESSOR_ARCHITECTURE_AMD64 9 +#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 + +#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF + +#define PF_FLOATING_POINT_PRECISION_ERRATA 0 +#define PF_FLOATING_POINT_EMULATED 1 +#define PF_COMPARE_EXCHANGE_DOUBLE 2 +#define PF_MMX_INSTRUCTIONS_AVAILABLE 3 +#define PF_PPC_MOVEMEM_64BIT_OK 4 +#define PF_ALPHA_BYTE_INSTRUCTIONS 5 +#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6 +#define PF_3DNOW_INSTRUCTIONS_AVAILABLE 7 +#define PF_RDTSC_INSTRUCTION_AVAILABLE 8 +#define PF_PAE_ENABLED 9 +#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10 +#define PF_SSE_DAZ_MODE_AVAILABLE 11 +#define PF_NX_ENABLED 12 + + typedef struct _MEMORY_BASIC_INFORMATION { + PVOID BaseAddress; + PVOID AllocationBase; + DWORD AllocationProtect; + SIZE_T RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; + } MEMORY_BASIC_INFORMATION,*PMEMORY_BASIC_INFORMATION; + + typedef struct _MEMORY_BASIC_INFORMATION32 { + DWORD BaseAddress; + DWORD AllocationBase; + DWORD AllocationProtect; + DWORD RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; + } MEMORY_BASIC_INFORMATION32,*PMEMORY_BASIC_INFORMATION32; + + typedef struct DECLSPEC_ALIGN(16) _MEMORY_BASIC_INFORMATION64 { + ULONGLONG BaseAddress; + ULONGLONG AllocationBase; + DWORD AllocationProtect; + DWORD __alignment1; + ULONGLONG RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; + DWORD __alignment2; + } MEMORY_BASIC_INFORMATION64,*PMEMORY_BASIC_INFORMATION64; + +#define SECTION_QUERY 0x0001 +#define SECTION_MAP_WRITE 0x0002 +#define SECTION_MAP_READ 0x0004 +#define SECTION_MAP_EXECUTE 0x0008 +#define SECTION_EXTEND_SIZE 0x0010 +#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020 + +#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY| SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE) +#define PAGE_NOACCESS 0x01 +#define PAGE_READONLY 0x02 +#define PAGE_READWRITE 0x04 +#define PAGE_WRITECOPY 0x08 +#define PAGE_EXECUTE 0x10 +#define PAGE_EXECUTE_READ 0x20 +#define PAGE_EXECUTE_READWRITE 0x40 +#define PAGE_EXECUTE_WRITECOPY 0x80 +#define PAGE_GUARD 0x100 +#define PAGE_NOCACHE 0x200 +#define PAGE_WRITECOMBINE 0x400 +#define MEM_COMMIT 0x1000 +#define MEM_RESERVE 0x2000 +#define MEM_DECOMMIT 0x4000 +#define MEM_RELEASE 0x8000 +#define MEM_FREE 0x10000 +#define MEM_PRIVATE 0x20000 +#define MEM_MAPPED 0x40000 +#define MEM_RESET 0x80000 +#define MEM_TOP_DOWN 0x100000 +#define MEM_WRITE_WATCH 0x200000 +#define MEM_PHYSICAL 0x400000 +#define MEM_LARGE_PAGES 0x20000000 +#define MEM_4MB_PAGES 0x80000000 +#define SEC_FILE 0x800000 +#define SEC_IMAGE 0x1000000 +#define SEC_RESERVE 0x4000000 +#define SEC_COMMIT 0x8000000 +#define SEC_NOCACHE 0x10000000 +#define SEC_LARGE_PAGES 0x80000000 +#define MEM_IMAGE SEC_IMAGE +#define WRITE_WATCH_FLAG_RESET 0x01 + +#define FILE_READ_DATA (0x0001) +#define FILE_LIST_DIRECTORY (0x0001) + +#define FILE_WRITE_DATA (0x0002) +#define FILE_ADD_FILE (0x0002) + +#define FILE_APPEND_DATA (0x0004) +#define FILE_ADD_SUBDIRECTORY (0x0004) +#define FILE_CREATE_PIPE_INSTANCE (0x0004) + +#define FILE_READ_EA (0x0008) + +#define FILE_WRITE_EA (0x0010) + +#define FILE_EXECUTE (0x0020) +#define FILE_TRAVERSE (0x0020) + +#define FILE_DELETE_CHILD (0x0040) + +#define FILE_READ_ATTRIBUTES (0x0080) + +#define FILE_WRITE_ATTRIBUTES (0x0100) + +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF) +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE) +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE) +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE) + +#define FILE_SHARE_READ 0x00000001 +#define FILE_SHARE_WRITE 0x00000002 +#define FILE_SHARE_DELETE 0x00000004 +#define FILE_ATTRIBUTE_READONLY 0x00000001 +#define FILE_ATTRIBUTE_HIDDEN 0x00000002 +#define FILE_ATTRIBUTE_SYSTEM 0x00000004 +#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 +#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 +#define FILE_ATTRIBUTE_DEVICE 0x00000040 +#define FILE_ATTRIBUTE_NORMAL 0x00000080 +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 +#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 +#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 +#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 +#define FILE_ATTRIBUTE_OFFLINE 0x00001000 +#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 +#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 +#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 +#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 +#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 +#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 +#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 +#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 +#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 +#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 +#define FILE_ACTION_ADDED 0x00000001 +#define FILE_ACTION_REMOVED 0x00000002 +#define FILE_ACTION_MODIFIED 0x00000003 +#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 +#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 +#define MAILSLOT_NO_MESSAGE ((DWORD)-1) +#define MAILSLOT_WAIT_FOREVER ((DWORD)-1) +#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 +#define FILE_CASE_PRESERVED_NAMES 0x00000002 +#define FILE_UNICODE_ON_DISK 0x00000004 +#define FILE_PERSISTENT_ACLS 0x00000008 +#define FILE_FILE_COMPRESSION 0x00000010 +#define FILE_VOLUME_QUOTAS 0x00000020 +#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 +#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 +#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 +#define FILE_VOLUME_IS_COMPRESSED 0x00008000 +#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 +#define FILE_SUPPORTS_ENCRYPTION 0x00020000 +#define FILE_NAMED_STREAMS 0x00040000 +#define FILE_READ_ONLY_VOLUME 0x00080000 + + typedef struct _FILE_NOTIFY_INFORMATION { + DWORD NextEntryOffset; + DWORD Action; + DWORD FileNameLength; + WCHAR FileName[1]; + } FILE_NOTIFY_INFORMATION,*PFILE_NOTIFY_INFORMATION; + + typedef union _FILE_SEGMENT_ELEMENT { + PVOID64 Buffer; + ULONGLONG Alignment; + }FILE_SEGMENT_ELEMENT,*PFILE_SEGMENT_ELEMENT; + + typedef struct _REPARSE_GUID_DATA_BUFFER { + DWORD ReparseTag; + WORD ReparseDataLength; + WORD Reserved; + GUID ReparseGuid; + struct { + BYTE DataBuffer[1]; + } GenericReparseBuffer; + } REPARSE_GUID_DATA_BUFFER,*PREPARSE_GUID_DATA_BUFFER; + +#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER,GenericReparseBuffer) + +#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 *1024) + +#define IO_REPARSE_TAG_RESERVED_ZERO (0) +#define IO_REPARSE_TAG_RESERVED_ONE (1) + +#define IO_REPARSE_TAG_RESERVED_RANGE IO_REPARSE_TAG_RESERVED_ONE + +#define IsReparseTagMicrosoft(_tag) (((_tag) & 0x80000000)) +#define IsReparseTagNameSurrogate(_tag) (((_tag) & 0x20000000)) + +#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) +#define IO_REPARSE_TAG_HSM (0xC0000004L) +#define IO_REPARSE_TAG_SIS (0x80000007L) +#define IO_REPARSE_TAG_DFS (0x8000000AL) +#define IO_REPARSE_TAG_FILTER_MANAGER (0x8000000BL) +#define IO_COMPLETION_MODIFY_STATE 0x0002 +#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) +#define DUPLICATE_CLOSE_SOURCE 0x00000001 +#define DUPLICATE_SAME_ACCESS 0x00000002 + + typedef enum _SYSTEM_POWER_STATE { + PowerSystemUnspecified = 0,PowerSystemWorking = 1,PowerSystemSleeping1 = 2,PowerSystemSleeping2 = 3,PowerSystemSleeping3 = 4,PowerSystemHibernate = 5,PowerSystemShutdown = 6,PowerSystemMaximum = 7 + } SYSTEM_POWER_STATE,*PSYSTEM_POWER_STATE; + +#define POWER_SYSTEM_MAXIMUM 7 + + typedef enum { + PowerActionNone = 0,PowerActionReserved,PowerActionSleep,PowerActionHibernate,PowerActionShutdown,PowerActionShutdownReset,PowerActionShutdownOff,PowerActionWarmEject + } POWER_ACTION,*PPOWER_ACTION; + + typedef enum _DEVICE_POWER_STATE { + PowerDeviceUnspecified = 0,PowerDeviceD0,PowerDeviceD1,PowerDeviceD2,PowerDeviceD3,PowerDeviceMaximum + } DEVICE_POWER_STATE,*PDEVICE_POWER_STATE; + +#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001) +#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002) +#define ES_USER_PRESENT ((DWORD)0x00000004) +#define ES_CONTINUOUS ((DWORD)0x80000000) + + typedef DWORD EXECUTION_STATE; + + typedef enum { + LT_DONT_CARE,LT_LOWEST_LATENCY + } LATENCY_TIME; + +#define PDCAP_D0_SUPPORTED 0x00000001 +#define PDCAP_D1_SUPPORTED 0x00000002 +#define PDCAP_D2_SUPPORTED 0x00000004 +#define PDCAP_D3_SUPPORTED 0x00000008 +#define PDCAP_WAKE_FROM_D0_SUPPORTED 0x00000010 +#define PDCAP_WAKE_FROM_D1_SUPPORTED 0x00000020 +#define PDCAP_WAKE_FROM_D2_SUPPORTED 0x00000040 +#define PDCAP_WAKE_FROM_D3_SUPPORTED 0x00000080 +#define PDCAP_WARM_EJECT_SUPPORTED 0x00000100 + + typedef struct CM_Power_Data_s { + DWORD PD_Size; + DEVICE_POWER_STATE PD_MostRecentPowerState; + DWORD PD_Capabilities; + DWORD PD_D1Latency; + DWORD PD_D2Latency; + DWORD PD_D3Latency; + DEVICE_POWER_STATE PD_PowerStateMapping[POWER_SYSTEM_MAXIMUM]; + SYSTEM_POWER_STATE PD_DeepestSystemWake; + } CM_POWER_DATA,*PCM_POWER_DATA; + + typedef enum { + SystemPowerPolicyAc,SystemPowerPolicyDc,VerifySystemPolicyAc,VerifySystemPolicyDc,SystemPowerCapabilities,SystemBatteryState,SystemPowerStateHandler,ProcessorStateHandler,SystemPowerPolicyCurrent,AdministratorPowerPolicy,SystemReserveHiberFile,ProcessorInformation,SystemPowerInformation,ProcessorStateHandler2,LastWakeTime,LastSleepTime,SystemExecutionState,SystemPowerStateNotifyHandler,ProcessorPowerPolicyAc,ProcessorPowerPolicyDc,VerifyProcessorPowerPolicyAc,VerifyProcessorPowerPolicyDc,ProcessorPowerPolicyCurrent,SystemPowerStateLogging,SystemPowerLoggingEntry + } POWER_INFORMATION_LEVEL; + + typedef struct { + DWORD Granularity; + DWORD Capacity; + } BATTERY_REPORTING_SCALE,*PBATTERY_REPORTING_SCALE; + + typedef struct { + POWER_ACTION Action; + DWORD Flags; + DWORD EventCode; + } POWER_ACTION_POLICY,*PPOWER_ACTION_POLICY; + +#define POWER_ACTION_QUERY_ALLOWED 0x00000001 +#define POWER_ACTION_UI_ALLOWED 0x00000002 +#define POWER_ACTION_OVERRIDE_APPS 0x00000004 +#define POWER_ACTION_LIGHTEST_FIRST 0x10000000 +#define POWER_ACTION_LOCK_CONSOLE 0x20000000 +#define POWER_ACTION_DISABLE_WAKES 0x40000000 +#define POWER_ACTION_CRITICAL 0x80000000 + +#define POWER_LEVEL_USER_NOTIFY_TEXT 0x00000001 +#define POWER_LEVEL_USER_NOTIFY_SOUND 0x00000002 +#define POWER_LEVEL_USER_NOTIFY_EXEC 0x00000004 +#define POWER_USER_NOTIFY_BUTTON 0x00000008 +#define POWER_USER_NOTIFY_SHUTDOWN 0x00000010 +#define POWER_FORCE_TRIGGER_RESET 0x80000000 + + typedef struct { + BOOLEAN Enable; + BYTE Spare[3]; + DWORD BatteryLevel; + POWER_ACTION_POLICY PowerPolicy; + SYSTEM_POWER_STATE MinSystemState; + } SYSTEM_POWER_LEVEL,*PSYSTEM_POWER_LEVEL; + +#define NUM_DISCHARGE_POLICIES 4 +#define DISCHARGE_POLICY_CRITICAL 0 +#define DISCHARGE_POLICY_LOW 1 + +#define PO_THROTTLE_NONE 0 +#define PO_THROTTLE_CONSTANT 1 +#define PO_THROTTLE_DEGRADE 2 +#define PO_THROTTLE_ADAPTIVE 3 +#define PO_THROTTLE_MAXIMUM 4 + + typedef struct _SYSTEM_POWER_POLICY { + DWORD Revision; + POWER_ACTION_POLICY PowerButton; + POWER_ACTION_POLICY SleepButton; + POWER_ACTION_POLICY LidClose; + SYSTEM_POWER_STATE LidOpenWake; + DWORD Reserved; + POWER_ACTION_POLICY Idle; + DWORD IdleTimeout; + BYTE IdleSensitivity; + BYTE DynamicThrottle; + BYTE Spare2[2]; + SYSTEM_POWER_STATE MinSleep; + SYSTEM_POWER_STATE MaxSleep; + SYSTEM_POWER_STATE ReducedLatencySleep; + DWORD WinLogonFlags; + DWORD Spare3; + DWORD DozeS4Timeout; + DWORD BroadcastCapacityResolution; + SYSTEM_POWER_LEVEL DischargePolicy[NUM_DISCHARGE_POLICIES]; + DWORD VideoTimeout; + BOOLEAN VideoDimDisplay; + DWORD VideoReserved[3]; + DWORD SpindownTimeout; + BOOLEAN OptimizeForPower; + BYTE FanThrottleTolerance; + BYTE ForcedThrottle; + BYTE MinThrottle; + POWER_ACTION_POLICY OverThrottled; + } SYSTEM_POWER_POLICY,*PSYSTEM_POWER_POLICY; + + typedef struct _PROCESSOR_POWER_POLICY_INFO { + DWORD TimeCheck; + DWORD DemoteLimit; + DWORD PromoteLimit; + BYTE DemotePercent; + BYTE PromotePercent; + BYTE Spare[2]; + DWORD AllowDemotion:1; + DWORD AllowPromotion:1; + DWORD Reserved:30; + } PROCESSOR_POWER_POLICY_INFO,*PPROCESSOR_POWER_POLICY_INFO; + + typedef struct _PROCESSOR_POWER_POLICY { + DWORD Revision; + BYTE DynamicThrottle; + BYTE Spare[3]; + DWORD DisableCStates:1; + DWORD Reserved:31; + DWORD PolicyCount; + PROCESSOR_POWER_POLICY_INFO Policy[3]; + } PROCESSOR_POWER_POLICY,*PPROCESSOR_POWER_POLICY; + + typedef struct _ADMINISTRATOR_POWER_POLICY { + SYSTEM_POWER_STATE MinSleep; + SYSTEM_POWER_STATE MaxSleep; + DWORD MinVideoTimeout; + DWORD MaxVideoTimeout; + DWORD MinSpindownTimeout; + DWORD MaxSpindownTimeout; + } ADMINISTRATOR_POWER_POLICY,*PADMINISTRATOR_POWER_POLICY; + + typedef struct { + BOOLEAN PowerButtonPresent; + BOOLEAN SleepButtonPresent; + BOOLEAN LidPresent; + BOOLEAN SystemS1; + BOOLEAN SystemS2; + BOOLEAN SystemS3; + BOOLEAN SystemS4; + BOOLEAN SystemS5; + BOOLEAN HiberFilePresent; + BOOLEAN FullWake; + BOOLEAN VideoDimPresent; + BOOLEAN ApmPresent; + BOOLEAN UpsPresent; + BOOLEAN ThermalControl; + BOOLEAN ProcessorThrottle; + BYTE ProcessorMinThrottle; + BYTE ProcessorMaxThrottle; + BYTE spare2[4]; + BOOLEAN DiskSpinDown; + BYTE spare3[8]; + BOOLEAN SystemBatteriesPresent; + BOOLEAN BatteriesAreShortTerm; + BATTERY_REPORTING_SCALE BatteryScale[3]; + SYSTEM_POWER_STATE AcOnLineWake; + SYSTEM_POWER_STATE SoftLidWake; + SYSTEM_POWER_STATE RtcWake; + SYSTEM_POWER_STATE MinDeviceWakeState; + SYSTEM_POWER_STATE DefaultLowLatencyWake; + } SYSTEM_POWER_CAPABILITIES,*PSYSTEM_POWER_CAPABILITIES; + + typedef struct { + BOOLEAN AcOnLine; + BOOLEAN BatteryPresent; + BOOLEAN Charging; + BOOLEAN Discharging; + BOOLEAN Spare1[4]; + DWORD MaxCapacity; + DWORD RemainingCapacity; + DWORD Rate; + DWORD EstimatedTime; + DWORD DefaultAlert1; + DWORD DefaultAlert2; + } SYSTEM_BATTERY_STATE,*PSYSTEM_BATTERY_STATE; + +#include "pshpack4.h" + +#define IMAGE_DOS_SIGNATURE 0x5A4D +#define IMAGE_OS2_SIGNATURE 0x454E +#define IMAGE_OS2_SIGNATURE_LE 0x454C +#define IMAGE_VXD_SIGNATURE 0x454C +#define IMAGE_NT_SIGNATURE 0x00004550 + +#include "pshpack2.h" + + typedef struct _IMAGE_DOS_HEADER { + WORD e_magic; + WORD e_cblp; + WORD e_cp; + WORD e_crlc; + WORD e_cparhdr; + WORD e_minalloc; + WORD e_maxalloc; + WORD e_ss; + WORD e_sp; + WORD e_csum; + WORD e_ip; + WORD e_cs; + WORD e_lfarlc; + WORD e_ovno; + WORD e_res[4]; + WORD e_oemid; + WORD e_oeminfo; + WORD e_res2[10]; + LONG e_lfanew; + } IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER; + + typedef struct _IMAGE_OS2_HEADER { + WORD ne_magic; + CHAR ne_ver; + CHAR ne_rev; + WORD ne_enttab; + WORD ne_cbenttab; + LONG ne_crc; + WORD ne_flags; + WORD ne_autodata; + WORD ne_heap; + WORD ne_stack; + LONG ne_csip; + LONG ne_sssp; + WORD ne_cseg; + WORD ne_cmod; + WORD ne_cbnrestab; + WORD ne_segtab; + WORD ne_rsrctab; + WORD ne_restab; + WORD ne_modtab; + WORD ne_imptab; + LONG ne_nrestab; + WORD ne_cmovent; + WORD ne_align; + WORD ne_cres; + BYTE ne_exetyp; + BYTE ne_flagsothers; + WORD ne_pretthunks; + WORD ne_psegrefbytes; + WORD ne_swaparea; + WORD ne_expver; + } IMAGE_OS2_HEADER,*PIMAGE_OS2_HEADER; + + typedef struct _IMAGE_VXD_HEADER { + WORD e32_magic; + BYTE e32_border; + BYTE e32_worder; + DWORD e32_level; + WORD e32_cpu; + WORD e32_os; + DWORD e32_ver; + DWORD e32_mflags; + DWORD e32_mpages; + DWORD e32_startobj; + DWORD e32_eip; + DWORD e32_stackobj; + DWORD e32_esp; + DWORD e32_pagesize; + DWORD e32_lastpagesize; + DWORD e32_fixupsize; + DWORD e32_fixupsum; + DWORD e32_ldrsize; + DWORD e32_ldrsum; + DWORD e32_objtab; + DWORD e32_objcnt; + DWORD e32_objmap; + DWORD e32_itermap; + DWORD e32_rsrctab; + DWORD e32_rsrccnt; + DWORD e32_restab; + DWORD e32_enttab; + DWORD e32_dirtab; + DWORD e32_dircnt; + DWORD e32_fpagetab; + DWORD e32_frectab; + DWORD e32_impmod; + DWORD e32_impmodcnt; + DWORD e32_impproc; + DWORD e32_pagesum; + DWORD e32_datapage; + DWORD e32_preload; + DWORD e32_nrestab; + DWORD e32_cbnrestab; + DWORD e32_nressum; + DWORD e32_autodata; + DWORD e32_debuginfo; + DWORD e32_debuglen; + DWORD e32_instpreload; + DWORD e32_instdemand; + DWORD e32_heapsize; + BYTE e32_res3[12]; + DWORD e32_winresoff; + DWORD e32_winreslen; + WORD e32_devid; + WORD e32_ddkver; + } IMAGE_VXD_HEADER,*PIMAGE_VXD_HEADER; + +#include "poppack.h" + + typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; + } IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER; + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_R3000 0x0162 +#define IMAGE_FILE_MACHINE_R4000 0x0166 +#define IMAGE_FILE_MACHINE_R10000 0x0168 +#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 +#define IMAGE_FILE_MACHINE_ALPHA 0x0184 +#define IMAGE_FILE_MACHINE_SH3 0x01a2 +#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 +#define IMAGE_FILE_MACHINE_SH3E 0x01a4 +#define IMAGE_FILE_MACHINE_SH4 0x01a6 +#define IMAGE_FILE_MACHINE_SH5 0x01a8 +#define IMAGE_FILE_MACHINE_ARM 0x01c0 +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 +#define IMAGE_FILE_MACHINE_AM33 0x01d3 +#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 +#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_MIPS16 0x0266 +#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 +#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 +#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 +#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 +#define IMAGE_FILE_MACHINE_TRICORE 0x0520 +#define IMAGE_FILE_MACHINE_CEF 0x0CEF +#define IMAGE_FILE_MACHINE_EBC 0x0EBC +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_M32R 0x9041 +#define IMAGE_FILE_MACHINE_CEE 0xC0EE + + typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; + } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + + typedef struct _IMAGE_OPTIONAL_HEADER { + + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + } IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32; + + typedef struct _IMAGE_ROM_OPTIONAL_HEADER { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD BaseOfBss; + DWORD GprMask; + DWORD CprMask[4]; + DWORD GpValue; + } IMAGE_ROM_OPTIONAL_HEADER,*PIMAGE_ROM_OPTIONAL_HEADER; + + typedef struct _IMAGE_OPTIONAL_HEADER64 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + } IMAGE_OPTIONAL_HEADER64,*PIMAGE_OPTIONAL_HEADER64; + +#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 +#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 +#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224 +#define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240 + +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +#ifdef _WIN64 + typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; + typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL64_HEADER +#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC +#else + typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; + typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL32_HEADER +#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC +#endif + + typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; + } IMAGE_NT_HEADERS64,*PIMAGE_NT_HEADERS64; + + typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; + } IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32; + + typedef struct _IMAGE_ROM_HEADERS { + IMAGE_FILE_HEADER FileHeader; + IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; + } IMAGE_ROM_HEADERS,*PIMAGE_ROM_HEADERS; + +#ifdef _WIN64 + typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; + typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; +#else + typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; + typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; +#endif + +#define IMAGE_FIRST_SECTION(ntheader) ((PIMAGE_SECTION_HEADER) ((ULONG_PTR)ntheader + FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader) + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 +#define IMAGE_SUBSYSTEM_NATIVE 1 +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 +#define IMAGE_SUBSYSTEM_OS2_CUI 5 +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 +#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 +#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define IMAGE_SUBSYSTEM_EFI_ROM 13 +#define IMAGE_SUBSYSTEM_XBOX 14 + +#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 +#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 +#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 +#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 +#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 + +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 +#define IMAGE_DIRECTORY_ENTRY_IAT 12 +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + + typedef struct ANON_OBJECT_HEADER { + WORD Sig1; + WORD Sig2; + WORD Version; + WORD Machine; + DWORD TimeDateStamp; + CLSID ClassID; + DWORD SizeOfData; + } ANON_OBJECT_HEADER; + +#define IMAGE_SIZEOF_SHORT_NAME 8 + + typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; + } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 +#define IMAGE_SCN_LNK_OTHER 0x00000100 +#define IMAGE_SCN_LNK_INFO 0x00000200 +#define IMAGE_SCN_LNK_REMOVE 0x00000800 +#define IMAGE_SCN_LNK_COMDAT 0x00001000 +#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 +#define IMAGE_SCN_GPREL 0x00008000 +#define IMAGE_SCN_MEM_FARDATA 0x00008000 +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 +#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 +#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 +#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 +#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 + +#define IMAGE_SCN_ALIGN_MASK 0x00F00000 + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +#define IMAGE_SCN_SCALE_INDEX 0x00000001 + +#include "pshpack2.h" + + typedef struct _IMAGE_SYMBOL { + union { + BYTE ShortName[8]; + struct { + DWORD Short; + DWORD Long; + } Name; + DWORD LongName[2]; + } N; + DWORD Value; + SHORT SectionNumber; + WORD Type; + BYTE StorageClass; + BYTE NumberOfAuxSymbols; + } IMAGE_SYMBOL; + typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL; + +#define IMAGE_SIZEOF_SYMBOL 18 + +#define IMAGE_SYM_UNDEFINED (SHORT)0 +#define IMAGE_SYM_ABSOLUTE (SHORT)-1 +#define IMAGE_SYM_DEBUG (SHORT)-2 +#define IMAGE_SYM_SECTION_MAX 0xFEFF + +#define IMAGE_SYM_TYPE_NULL 0x0000 +#define IMAGE_SYM_TYPE_VOID 0x0001 +#define IMAGE_SYM_TYPE_CHAR 0x0002 +#define IMAGE_SYM_TYPE_SHORT 0x0003 +#define IMAGE_SYM_TYPE_INT 0x0004 +#define IMAGE_SYM_TYPE_LONG 0x0005 +#define IMAGE_SYM_TYPE_FLOAT 0x0006 +#define IMAGE_SYM_TYPE_DOUBLE 0x0007 +#define IMAGE_SYM_TYPE_STRUCT 0x0008 +#define IMAGE_SYM_TYPE_UNION 0x0009 +#define IMAGE_SYM_TYPE_ENUM 0x000A +#define IMAGE_SYM_TYPE_MOE 0x000B +#define IMAGE_SYM_TYPE_BYTE 0x000C +#define IMAGE_SYM_TYPE_WORD 0x000D +#define IMAGE_SYM_TYPE_UINT 0x000E +#define IMAGE_SYM_TYPE_DWORD 0x000F +#define IMAGE_SYM_TYPE_PCODE 0x8000 + +#define IMAGE_SYM_DTYPE_NULL 0 +#define IMAGE_SYM_DTYPE_POINTER 1 +#define IMAGE_SYM_DTYPE_FUNCTION 2 +#define IMAGE_SYM_DTYPE_ARRAY 3 + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE)-1 +#define IMAGE_SYM_CLASS_NULL 0x0000 +#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 +#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 +#define IMAGE_SYM_CLASS_STATIC 0x0003 +#define IMAGE_SYM_CLASS_REGISTER 0x0004 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 +#define IMAGE_SYM_CLASS_LABEL 0x0006 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 +#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 +#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B +#define IMAGE_SYM_CLASS_UNION_TAG 0x000C +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E +#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 +#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 +#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 +#define IMAGE_SYM_CLASS_BLOCK 0x0064 +#define IMAGE_SYM_CLASS_FUNCTION 0x0065 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 +#define IMAGE_SYM_CLASS_FILE 0x0067 +#define IMAGE_SYM_CLASS_SECTION 0x0068 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 +#define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B + +#define N_BTMASK 0x000F +#define N_TMASK 0x0030 +#define N_TMASK1 0x00C0 +#define N_TMASK2 0x00F0 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +#define BTYPE(x) ((x) & N_BTMASK) + +#ifndef ISPTR +#define ISPTR(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) +#endif + +#ifndef ISFCN +#define ISFCN(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) +#endif + +#ifndef ISARY +#define ISARY(x) (((x) & N_TMASK)==(IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) +#endif + +#ifndef ISTAG +#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) +#endif + +#ifndef INCREF +#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) +#endif + + typedef union _IMAGE_AUX_SYMBOL { + struct { + DWORD TagIndex; + union { + struct { + WORD Linenumber; + WORD Size; + } LnSz; + DWORD TotalSize; + } Misc; + union { + struct { + DWORD PointerToLinenumber; + DWORD PointerToNextFunction; + } Function; + struct { + WORD Dimension[4]; + } Array; + } FcnAry; + WORD TvIndex; + } Sym; + struct { + BYTE Name[IMAGE_SIZEOF_SYMBOL]; + } File; + struct { + DWORD Length; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD CheckSum; + SHORT Number; + BYTE Selection; + } Section; + } IMAGE_AUX_SYMBOL; + typedef IMAGE_AUX_SYMBOL UNALIGNED *PIMAGE_AUX_SYMBOL; + +#define IMAGE_SIZEOF_AUX_SYMBOL 18 + + typedef enum IMAGE_AUX_SYMBOL_TYPE { + IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF = 1 + } IMAGE_AUX_SYMBOL_TYPE; + +#include + + typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF { + BYTE bAuxType; + BYTE bReserved; + DWORD SymbolTableIndex; + BYTE rgbReserved[12]; + } IMAGE_AUX_SYMBOL_TOKEN_DEF; + + typedef IMAGE_AUX_SYMBOL_TOKEN_DEF UNALIGNED *PIMAGE_AUX_SYMBOL_TOKEN_DEF; + +#include + +#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define IMAGE_COMDAT_SELECT_ANY 2 +#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 +#define IMAGE_COMDAT_SELECT_LARGEST 6 +#define IMAGE_COMDAT_SELECT_NEWEST 7 + +#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + + typedef struct _IMAGE_RELOCATION { + union { + DWORD VirtualAddress; + DWORD RelocCount; + }; + DWORD SymbolTableIndex; + WORD Type; + } IMAGE_RELOCATION; + typedef IMAGE_RELOCATION UNALIGNED *PIMAGE_RELOCATION; + +#define IMAGE_SIZEOF_RELOCATION 10 + +#define IMAGE_REL_I386_ABSOLUTE 0x0000 +#define IMAGE_REL_I386_DIR16 0x0001 +#define IMAGE_REL_I386_REL16 0x0002 +#define IMAGE_REL_I386_DIR32 0x0006 +#define IMAGE_REL_I386_DIR32NB 0x0007 +#define IMAGE_REL_I386_SEG12 0x0009 +#define IMAGE_REL_I386_SECTION 0x000A +#define IMAGE_REL_I386_SECREL 0x000B +#define IMAGE_REL_I386_TOKEN 0x000C +#define IMAGE_REL_I386_SECREL7 0x000D +#define IMAGE_REL_I386_REL32 0x0014 + +#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 +#define IMAGE_REL_MIPS_REFHALF 0x0001 +#define IMAGE_REL_MIPS_REFWORD 0x0002 +#define IMAGE_REL_MIPS_JMPADDR 0x0003 +#define IMAGE_REL_MIPS_REFHI 0x0004 +#define IMAGE_REL_MIPS_REFLO 0x0005 +#define IMAGE_REL_MIPS_GPREL 0x0006 +#define IMAGE_REL_MIPS_LITERAL 0x0007 +#define IMAGE_REL_MIPS_SECTION 0x000A +#define IMAGE_REL_MIPS_SECREL 0x000B +#define IMAGE_REL_MIPS_SECRELLO 0x000C +#define IMAGE_REL_MIPS_SECRELHI 0x000D +#define IMAGE_REL_MIPS_TOKEN 0x000E +#define IMAGE_REL_MIPS_JMPADDR16 0x0010 +#define IMAGE_REL_MIPS_REFWORDNB 0x0022 +#define IMAGE_REL_MIPS_PAIR 0x0025 + +#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 +#define IMAGE_REL_ALPHA_REFLONG 0x0001 +#define IMAGE_REL_ALPHA_REFQUAD 0x0002 +#define IMAGE_REL_ALPHA_GPREL32 0x0003 +#define IMAGE_REL_ALPHA_LITERAL 0x0004 +#define IMAGE_REL_ALPHA_LITUSE 0x0005 +#define IMAGE_REL_ALPHA_GPDISP 0x0006 +#define IMAGE_REL_ALPHA_BRADDR 0x0007 +#define IMAGE_REL_ALPHA_HINT 0x0008 +#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 +#define IMAGE_REL_ALPHA_REFHI 0x000A +#define IMAGE_REL_ALPHA_REFLO 0x000B +#define IMAGE_REL_ALPHA_PAIR 0x000C +#define IMAGE_REL_ALPHA_MATCH 0x000D +#define IMAGE_REL_ALPHA_SECTION 0x000E +#define IMAGE_REL_ALPHA_SECREL 0x000F +#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 +#define IMAGE_REL_ALPHA_SECRELLO 0x0011 +#define IMAGE_REL_ALPHA_SECRELHI 0x0012 +#define IMAGE_REL_ALPHA_REFQ3 0x0013 +#define IMAGE_REL_ALPHA_REFQ2 0x0014 +#define IMAGE_REL_ALPHA_REFQ1 0x0015 +#define IMAGE_REL_ALPHA_GPRELLO 0x0016 +#define IMAGE_REL_ALPHA_GPRELHI 0x0017 + +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 +#define IMAGE_REL_PPC_ADDR64 0x0001 +#define IMAGE_REL_PPC_ADDR32 0x0002 +#define IMAGE_REL_PPC_ADDR24 0x0003 +#define IMAGE_REL_PPC_ADDR16 0x0004 +#define IMAGE_REL_PPC_ADDR14 0x0005 +#define IMAGE_REL_PPC_REL24 0x0006 +#define IMAGE_REL_PPC_REL14 0x0007 +#define IMAGE_REL_PPC_TOCREL16 0x0008 +#define IMAGE_REL_PPC_TOCREL14 0x0009 +#define IMAGE_REL_PPC_ADDR32NB 0x000A +#define IMAGE_REL_PPC_SECREL 0x000B +#define IMAGE_REL_PPC_SECTION 0x000C +#define IMAGE_REL_PPC_IFGLUE 0x000D +#define IMAGE_REL_PPC_IMGLUE 0x000E +#define IMAGE_REL_PPC_SECREL16 0x000F +#define IMAGE_REL_PPC_REFHI 0x0010 +#define IMAGE_REL_PPC_REFLO 0x0011 +#define IMAGE_REL_PPC_PAIR 0x0012 +#define IMAGE_REL_PPC_SECRELLO 0x0013 +#define IMAGE_REL_PPC_SECRELHI 0x0014 +#define IMAGE_REL_PPC_GPREL 0x0015 +#define IMAGE_REL_PPC_TOKEN 0x0016 +#define IMAGE_REL_PPC_TYPEMASK 0x00FF +#define IMAGE_REL_PPC_NEG 0x0100 +#define IMAGE_REL_PPC_BRTAKEN 0x0200 +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 +#define IMAGE_REL_PPC_TOCDEFN 0x0800 + +#define IMAGE_REL_SH3_ABSOLUTE 0x0000 +#define IMAGE_REL_SH3_DIRECT16 0x0001 +#define IMAGE_REL_SH3_DIRECT32 0x0002 +#define IMAGE_REL_SH3_DIRECT8 0x0003 +#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 +#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 +#define IMAGE_REL_SH3_DIRECT4 0x0006 +#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 +#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 +#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 +#define IMAGE_REL_SH3_PCREL8_LONG 0x000A +#define IMAGE_REL_SH3_PCREL12_WORD 0x000B +#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C +#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D +#define IMAGE_REL_SH3_SECTION 0x000E +#define IMAGE_REL_SH3_SECREL 0x000F +#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 +#define IMAGE_REL_SH3_GPREL4_LONG 0x0011 +#define IMAGE_REL_SH3_TOKEN 0x0012 + +#define IMAGE_REL_SHM_PCRELPT 0x0013 +#define IMAGE_REL_SHM_REFLO 0x0014 +#define IMAGE_REL_SHM_REFHALF 0x0015 +#define IMAGE_REL_SHM_RELLO 0x0016 +#define IMAGE_REL_SHM_RELHALF 0x0017 +#define IMAGE_REL_SHM_PAIR 0x0018 + +#define IMAGE_REL_SH_NOMODE 0x8000 + +#define IMAGE_REL_ARM_ABSOLUTE 0x0000 +#define IMAGE_REL_ARM_ADDR32 0x0001 +#define IMAGE_REL_ARM_ADDR32NB 0x0002 +#define IMAGE_REL_ARM_BRANCH24 0x0003 +#define IMAGE_REL_ARM_BRANCH11 0x0004 +#define IMAGE_REL_ARM_TOKEN 0x0005 +#define IMAGE_REL_ARM_GPREL12 0x0006 +#define IMAGE_REL_ARM_GPREL7 0x0007 +#define IMAGE_REL_ARM_BLX24 0x0008 +#define IMAGE_REL_ARM_BLX11 0x0009 +#define IMAGE_REL_ARM_SECTION 0x000E +#define IMAGE_REL_ARM_SECREL 0x000F + +#define IMAGE_REL_AM_ABSOLUTE 0x0000 +#define IMAGE_REL_AM_ADDR32 0x0001 +#define IMAGE_REL_AM_ADDR32NB 0x0002 +#define IMAGE_REL_AM_CALL32 0x0003 +#define IMAGE_REL_AM_FUNCINFO 0x0004 +#define IMAGE_REL_AM_REL32_1 0x0005 +#define IMAGE_REL_AM_REL32_2 0x0006 +#define IMAGE_REL_AM_SECREL 0x0007 +#define IMAGE_REL_AM_SECTION 0x0008 +#define IMAGE_REL_AM_TOKEN 0x0009 + +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 +#define IMAGE_REL_AMD64_ADDR32 0x0002 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 +#define IMAGE_REL_AMD64_REL32_1 0x0005 +#define IMAGE_REL_AMD64_REL32_2 0x0006 +#define IMAGE_REL_AMD64_REL32_3 0x0007 +#define IMAGE_REL_AMD64_REL32_4 0x0008 +#define IMAGE_REL_AMD64_REL32_5 0x0009 +#define IMAGE_REL_AMD64_SECTION 0x000A +#define IMAGE_REL_AMD64_SECREL 0x000B +#define IMAGE_REL_AMD64_SECREL7 0x000C +#define IMAGE_REL_AMD64_TOKEN 0x000D +#define IMAGE_REL_AMD64_SREL32 0x000E +#define IMAGE_REL_AMD64_PAIR 0x000F +#define IMAGE_REL_AMD64_SSPAN32 0x0010 + +#define IMAGE_REL_IA64_ABSOLUTE 0x0000 +#define IMAGE_REL_IA64_IMM14 0x0001 +#define IMAGE_REL_IA64_IMM22 0x0002 +#define IMAGE_REL_IA64_IMM64 0x0003 +#define IMAGE_REL_IA64_DIR32 0x0004 +#define IMAGE_REL_IA64_DIR64 0x0005 +#define IMAGE_REL_IA64_PCREL21B 0x0006 +#define IMAGE_REL_IA64_PCREL21M 0x0007 +#define IMAGE_REL_IA64_PCREL21F 0x0008 +#define IMAGE_REL_IA64_GPREL22 0x0009 +#define IMAGE_REL_IA64_LTOFF22 0x000A +#define IMAGE_REL_IA64_SECTION 0x000B +#define IMAGE_REL_IA64_SECREL22 0x000C +#define IMAGE_REL_IA64_SECREL64I 0x000D +#define IMAGE_REL_IA64_SECREL32 0x000E + +#define IMAGE_REL_IA64_DIR32NB 0x0010 +#define IMAGE_REL_IA64_SREL14 0x0011 +#define IMAGE_REL_IA64_SREL22 0x0012 +#define IMAGE_REL_IA64_SREL32 0x0013 +#define IMAGE_REL_IA64_UREL32 0x0014 +#define IMAGE_REL_IA64_PCREL60X 0x0015 +#define IMAGE_REL_IA64_PCREL60B 0x0016 +#define IMAGE_REL_IA64_PCREL60F 0x0017 +#define IMAGE_REL_IA64_PCREL60I 0x0018 +#define IMAGE_REL_IA64_PCREL60M 0x0019 +#define IMAGE_REL_IA64_IMMGPREL64 0x001A +#define IMAGE_REL_IA64_TOKEN 0x001B +#define IMAGE_REL_IA64_GPREL32 0x001C +#define IMAGE_REL_IA64_ADDEND 0x001F + +#define IMAGE_REL_CEF_ABSOLUTE 0x0000 +#define IMAGE_REL_CEF_ADDR32 0x0001 +#define IMAGE_REL_CEF_ADDR64 0x0002 +#define IMAGE_REL_CEF_ADDR32NB 0x0003 +#define IMAGE_REL_CEF_SECTION 0x0004 +#define IMAGE_REL_CEF_SECREL 0x0005 +#define IMAGE_REL_CEF_TOKEN 0x0006 + +#define IMAGE_REL_CEE_ABSOLUTE 0x0000 +#define IMAGE_REL_CEE_ADDR32 0x0001 +#define IMAGE_REL_CEE_ADDR64 0x0002 +#define IMAGE_REL_CEE_ADDR32NB 0x0003 +#define IMAGE_REL_CEE_SECTION 0x0004 +#define IMAGE_REL_CEE_SECREL 0x0005 +#define IMAGE_REL_CEE_TOKEN 0x0006 + +#define IMAGE_REL_M32R_ABSOLUTE 0x0000 +#define IMAGE_REL_M32R_ADDR32 0x0001 +#define IMAGE_REL_M32R_ADDR32NB 0x0002 +#define IMAGE_REL_M32R_ADDR24 0x0003 +#define IMAGE_REL_M32R_GPREL16 0x0004 +#define IMAGE_REL_M32R_PCREL24 0x0005 +#define IMAGE_REL_M32R_PCREL16 0x0006 +#define IMAGE_REL_M32R_PCREL8 0x0007 +#define IMAGE_REL_M32R_REFHALF 0x0008 +#define IMAGE_REL_M32R_REFHI 0x0009 +#define IMAGE_REL_M32R_REFLO 0x000A +#define IMAGE_REL_M32R_PAIR 0x000B +#define IMAGE_REL_M32R_SECTION 0x000C +#define IMAGE_REL_M32R_SECREL32 0x000D +#define IMAGE_REL_M32R_TOKEN 0x000E + +#define EXT_IMM64(Value,Address,Size,InstPos,ValPos) Value |= (((ULONGLONG)((*(Address) >> InstPos) & (((ULONGLONG)1 << Size) - 1))) << ValPos) +#define INS_IMM64(Value,Address,Size,InstPos,ValPos) *(PDWORD)Address = (*(PDWORD)Address & ~(((1 << Size) - 1) << InstPos)) | ((DWORD)((((ULONGLONG)Value >> ValPos) & (((ULONGLONG)1 << Size) - 1))) << InstPos) + +#define EMARCH_ENC_I17_IMM7B_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM7B_SIZE_X 7 +#define EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X 4 +#define EMARCH_ENC_I17_IMM7B_VAL_POS_X 0 + +#define EMARCH_ENC_I17_IMM9D_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM9D_SIZE_X 9 +#define EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X 18 +#define EMARCH_ENC_I17_IMM9D_VAL_POS_X 7 + +#define EMARCH_ENC_I17_IMM5C_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM5C_SIZE_X 5 +#define EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X 13 +#define EMARCH_ENC_I17_IMM5C_VAL_POS_X 16 + +#define EMARCH_ENC_I17_IC_INST_WORD_X 3 +#define EMARCH_ENC_I17_IC_SIZE_X 1 +#define EMARCH_ENC_I17_IC_INST_WORD_POS_X 12 +#define EMARCH_ENC_I17_IC_VAL_POS_X 21 + +#define EMARCH_ENC_I17_IMM41a_INST_WORD_X 1 +#define EMARCH_ENC_I17_IMM41a_SIZE_X 10 +#define EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X 14 +#define EMARCH_ENC_I17_IMM41a_VAL_POS_X 22 + +#define EMARCH_ENC_I17_IMM41b_INST_WORD_X 1 +#define EMARCH_ENC_I17_IMM41b_SIZE_X 8 +#define EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X 24 +#define EMARCH_ENC_I17_IMM41b_VAL_POS_X 32 + +#define EMARCH_ENC_I17_IMM41c_INST_WORD_X 2 +#define EMARCH_ENC_I17_IMM41c_SIZE_X 23 +#define EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X 0 +#define EMARCH_ENC_I17_IMM41c_VAL_POS_X 40 + +#define EMARCH_ENC_I17_SIGN_INST_WORD_X 3 +#define EMARCH_ENC_I17_SIGN_SIZE_X 1 +#define EMARCH_ENC_I17_SIGN_INST_WORD_POS_X 27 +#define EMARCH_ENC_I17_SIGN_VAL_POS_X 63 + +#define X3_OPCODE_INST_WORD_X 3 +#define X3_OPCODE_SIZE_X 4 +#define X3_OPCODE_INST_WORD_POS_X 28 +#define X3_OPCODE_SIGN_VAL_POS_X 0 + +#define X3_I_INST_WORD_X 3 +#define X3_I_SIZE_X 1 +#define X3_I_INST_WORD_POS_X 27 +#define X3_I_SIGN_VAL_POS_X 59 + +#define X3_D_WH_INST_WORD_X 3 +#define X3_D_WH_SIZE_X 3 +#define X3_D_WH_INST_WORD_POS_X 24 +#define X3_D_WH_SIGN_VAL_POS_X 0 + +#define X3_IMM20_INST_WORD_X 3 +#define X3_IMM20_SIZE_X 20 +#define X3_IMM20_INST_WORD_POS_X 4 +#define X3_IMM20_SIGN_VAL_POS_X 0 + +#define X3_IMM39_1_INST_WORD_X 2 +#define X3_IMM39_1_SIZE_X 23 +#define X3_IMM39_1_INST_WORD_POS_X 0 +#define X3_IMM39_1_SIGN_VAL_POS_X 36 + +#define X3_IMM39_2_INST_WORD_X 1 +#define X3_IMM39_2_SIZE_X 16 +#define X3_IMM39_2_INST_WORD_POS_X 16 +#define X3_IMM39_2_SIGN_VAL_POS_X 20 + +#define X3_P_INST_WORD_X 3 +#define X3_P_SIZE_X 4 +#define X3_P_INST_WORD_POS_X 0 +#define X3_P_SIGN_VAL_POS_X 0 + +#define X3_TMPLT_INST_WORD_X 0 +#define X3_TMPLT_SIZE_X 4 +#define X3_TMPLT_INST_WORD_POS_X 0 +#define X3_TMPLT_SIGN_VAL_POS_X 0 + +#define X3_BTYPE_QP_INST_WORD_X 2 +#define X3_BTYPE_QP_SIZE_X 9 +#define X3_BTYPE_QP_INST_WORD_POS_X 23 +#define X3_BTYPE_QP_INST_VAL_POS_X 0 + +#define X3_EMPTY_INST_WORD_X 1 +#define X3_EMPTY_SIZE_X 2 +#define X3_EMPTY_INST_WORD_POS_X 14 +#define X3_EMPTY_INST_VAL_POS_X 0 + + typedef struct _IMAGE_LINENUMBER { + union { + DWORD SymbolTableIndex; + DWORD VirtualAddress; + } Type; + WORD Linenumber; + } IMAGE_LINENUMBER; + typedef IMAGE_LINENUMBER UNALIGNED *PIMAGE_LINENUMBER; + +#define IMAGE_SIZEOF_LINENUMBER 6 + +#include "poppack.h" + + typedef struct _IMAGE_BASE_RELOCATION { + DWORD VirtualAddress; + DWORD SizeOfBlock; + + } IMAGE_BASE_RELOCATION; + typedef IMAGE_BASE_RELOCATION UNALIGNED *PIMAGE_BASE_RELOCATION; + +#define IMAGE_SIZEOF_BASE_RELOCATION 8 + +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define IMAGE_REL_BASED_IA64_IMM64 9 +#define IMAGE_REL_BASED_DIR64 10 + +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + + typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { + BYTE Name[16]; + BYTE Date[12]; + BYTE UserID[6]; + BYTE GroupID[6]; + BYTE Mode[8]; + BYTE Size[10]; + BYTE EndHeader[2]; + } IMAGE_ARCHIVE_MEMBER_HEADER,*PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + + typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; + } IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; + + typedef struct _IMAGE_IMPORT_BY_NAME { + WORD Hint; + BYTE Name[1]; + } IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; + +#include "pshpack8.h" + + typedef struct _IMAGE_THUNK_DATA64 { + union { + ULONGLONG ForwarderString; + ULONGLONG Function; + ULONGLONG Ordinal; + ULONGLONG AddressOfData; + } u1; + } IMAGE_THUNK_DATA64; + typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; + +#include "poppack.h" + + typedef struct _IMAGE_THUNK_DATA32 { + union { + DWORD ForwarderString; + DWORD Function; + DWORD Ordinal; + DWORD AddressOfData; + } u1; + } IMAGE_THUNK_DATA32; + typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; + +#define IMAGE_ORDINAL_FLAG64 0x8000000000000000ull +#define IMAGE_ORDINAL_FLAG32 0x80000000 +#define IMAGE_ORDINAL64(Ordinal) (Ordinal & 0xffffull) +#define IMAGE_ORDINAL32(Ordinal) (Ordinal & 0xffff) +#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64)!=0) +#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32)!=0) + + typedef VOID + (NTAPI *PIMAGE_TLS_CALLBACK)(PVOID DllHandle,DWORD Reason,PVOID Reserved); + + typedef struct _IMAGE_TLS_DIRECTORY64 { + ULONGLONG StartAddressOfRawData; + ULONGLONG EndAddressOfRawData; + ULONGLONG AddressOfIndex; + ULONGLONG AddressOfCallBacks; + DWORD SizeOfZeroFill; + DWORD Characteristics; + } IMAGE_TLS_DIRECTORY64; + typedef IMAGE_TLS_DIRECTORY64 *PIMAGE_TLS_DIRECTORY64; + + typedef struct _IMAGE_TLS_DIRECTORY32 { + DWORD StartAddressOfRawData; + DWORD EndAddressOfRawData; + DWORD AddressOfIndex; + DWORD AddressOfCallBacks; + DWORD SizeOfZeroFill; + DWORD Characteristics; + } IMAGE_TLS_DIRECTORY32; + typedef IMAGE_TLS_DIRECTORY32 *PIMAGE_TLS_DIRECTORY32; + +#ifdef _WIN64 +#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64 +#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL64(Ordinal) + typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; + typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL64(Ordinal) + typedef IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY; + typedef PIMAGE_TLS_DIRECTORY64 PIMAGE_TLS_DIRECTORY; +#else +#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32 +#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL32(Ordinal) + typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; + typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL32(Ordinal) + typedef IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY; + typedef PIMAGE_TLS_DIRECTORY32 PIMAGE_TLS_DIRECTORY; +#endif + + typedef struct _IMAGE_IMPORT_DESCRIPTOR { + union { + DWORD Characteristics; + DWORD OriginalFirstThunk; + }; + DWORD TimeDateStamp; + + DWORD ForwarderChain; + DWORD Name; + DWORD FirstThunk; + } IMAGE_IMPORT_DESCRIPTOR; + typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR; + + typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR { + DWORD TimeDateStamp; + WORD OffsetModuleName; + WORD NumberOfModuleForwarderRefs; + } IMAGE_BOUND_IMPORT_DESCRIPTOR,*PIMAGE_BOUND_IMPORT_DESCRIPTOR; + + typedef struct _IMAGE_BOUND_FORWARDER_REF { + DWORD TimeDateStamp; + WORD OffsetModuleName; + WORD Reserved; + } IMAGE_BOUND_FORWARDER_REF,*PIMAGE_BOUND_FORWARDER_REF; + + typedef struct _IMAGE_RESOURCE_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + WORD NumberOfNamedEntries; + WORD NumberOfIdEntries; + } IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; + +#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 +#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 + + typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { + union { + struct { + DWORD NameOffset:31; + DWORD NameIsString:1; + }; + DWORD Name; + WORD Id; + }; + union { + DWORD OffsetToData; + struct { + DWORD OffsetToDirectory:31; + DWORD DataIsDirectory:1; + }; + }; + } IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; + + typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { + WORD Length; + CHAR NameString[1]; + } IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; + + typedef struct _IMAGE_RESOURCE_DIR_STRING_U { + WORD Length; + WCHAR NameString[1]; + } IMAGE_RESOURCE_DIR_STRING_U,*PIMAGE_RESOURCE_DIR_STRING_U; + + typedef struct _IMAGE_RESOURCE_DATA_ENTRY { + DWORD OffsetToData; + DWORD Size; + DWORD CodePage; + DWORD Reserved; + } IMAGE_RESOURCE_DATA_ENTRY,*PIMAGE_RESOURCE_DATA_ENTRY; + + typedef struct { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + DWORD DeCommitFreeBlockThreshold; + DWORD DeCommitTotalFreeThreshold; + DWORD LockPrefixTable; + DWORD MaximumAllocationSize; + DWORD VirtualMemoryThreshold; + DWORD ProcessHeapFlags; + DWORD ProcessAffinityMask; + WORD CSDVersion; + WORD Reserved1; + DWORD EditList; + DWORD SecurityCookie; + DWORD SEHandlerTable; + DWORD SEHandlerCount; + } IMAGE_LOAD_CONFIG_DIRECTORY32,*PIMAGE_LOAD_CONFIG_DIRECTORY32; + + typedef struct { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + ULONGLONG DeCommitFreeBlockThreshold; + ULONGLONG DeCommitTotalFreeThreshold; + ULONGLONG LockPrefixTable; + ULONGLONG MaximumAllocationSize; + ULONGLONG VirtualMemoryThreshold; + ULONGLONG ProcessAffinityMask; + DWORD ProcessHeapFlags; + WORD CSDVersion; + WORD Reserved1; + ULONGLONG EditList; + ULONGLONG SecurityCookie; + ULONGLONG SEHandlerTable; + ULONGLONG SEHandlerCount; + } IMAGE_LOAD_CONFIG_DIRECTORY64,*PIMAGE_LOAD_CONFIG_DIRECTORY64; + +#ifdef _WIN64 + typedef IMAGE_LOAD_CONFIG_DIRECTORY64 IMAGE_LOAD_CONFIG_DIRECTORY; + typedef PIMAGE_LOAD_CONFIG_DIRECTORY64 PIMAGE_LOAD_CONFIG_DIRECTORY; +#else + typedef IMAGE_LOAD_CONFIG_DIRECTORY32 IMAGE_LOAD_CONFIG_DIRECTORY; + typedef PIMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY; +#endif + + typedef struct _IMAGE_CE_RUNTIME_FUNCTION_ENTRY { + DWORD FuncStart; + DWORD PrologLen : 8; + DWORD FuncLen : 22; + DWORD ThirtyTwoBit : 1; + DWORD ExceptionFlag : 1; + } IMAGE_CE_RUNTIME_FUNCTION_ENTRY,*PIMAGE_CE_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY { + ULONGLONG BeginAddress; + ULONGLONG EndAddress; + ULONGLONG ExceptionHandler; + ULONGLONG HandlerData; + ULONGLONG PrologEndAddress; + } IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY { + DWORD BeginAddress; + DWORD EndAddress; + DWORD ExceptionHandler; + DWORD HandlerData; + DWORD PrologEndAddress; + } IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY,*PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { + DWORD BeginAddress; + DWORD EndAddress; + DWORD UnwindInfoAddress; + } _IMAGE_RUNTIME_FUNCTION_ENTRY,*_PIMAGE_RUNTIME_FUNCTION_ENTRY; + + typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_IA64_RUNTIME_FUNCTION_ENTRY; + typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY; + + typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_RUNTIME_FUNCTION_ENTRY; + typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_RUNTIME_FUNCTION_ENTRY; + + typedef struct _IMAGE_DEBUG_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Type; + DWORD SizeOfData; + DWORD AddressOfRawData; + DWORD PointerToRawData; + } IMAGE_DEBUG_DIRECTORY,*PIMAGE_DEBUG_DIRECTORY; + +#define IMAGE_DEBUG_TYPE_UNKNOWN 0 +#define IMAGE_DEBUG_TYPE_COFF 1 +#define IMAGE_DEBUG_TYPE_CODEVIEW 2 +#define IMAGE_DEBUG_TYPE_FPO 3 +#define IMAGE_DEBUG_TYPE_MISC 4 +#define IMAGE_DEBUG_TYPE_EXCEPTION 5 +#define IMAGE_DEBUG_TYPE_FIXUP 6 +#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 +#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 +#define IMAGE_DEBUG_TYPE_BORLAND 9 +#define IMAGE_DEBUG_TYPE_RESERVED10 10 +#define IMAGE_DEBUG_TYPE_CLSID 11 + + typedef struct _IMAGE_COFF_SYMBOLS_HEADER { + DWORD NumberOfSymbols; + DWORD LvaToFirstSymbol; + DWORD NumberOfLinenumbers; + DWORD LvaToFirstLinenumber; + DWORD RvaToFirstByteOfCode; + DWORD RvaToLastByteOfCode; + DWORD RvaToFirstByteOfData; + DWORD RvaToLastByteOfData; + } IMAGE_COFF_SYMBOLS_HEADER,*PIMAGE_COFF_SYMBOLS_HEADER; + +#define FRAME_FPO 0 +#define FRAME_TRAP 1 +#define FRAME_TSS 2 +#define FRAME_NONFPO 3 + + typedef struct _FPO_DATA { + DWORD ulOffStart; + DWORD cbProcSize; + DWORD cdwLocals; + WORD cdwParams; + WORD cbProlog : 8; + WORD cbRegs : 3; + WORD fHasSEH : 1; + WORD fUseBP : 1; + WORD reserved : 1; + WORD cbFrame : 2; + } FPO_DATA,*PFPO_DATA; +#define SIZEOF_RFPO_DATA 16 + +#define IMAGE_DEBUG_MISC_EXENAME 1 + + typedef struct _IMAGE_DEBUG_MISC { + DWORD DataType; + DWORD Length; + BOOLEAN Unicode; + BYTE Reserved[3]; + BYTE Data[1]; + } IMAGE_DEBUG_MISC,*PIMAGE_DEBUG_MISC; + + typedef struct _IMAGE_FUNCTION_ENTRY { + DWORD StartingAddress; + DWORD EndingAddress; + DWORD EndOfPrologue; + } IMAGE_FUNCTION_ENTRY,*PIMAGE_FUNCTION_ENTRY; + + typedef struct _IMAGE_FUNCTION_ENTRY64 { + ULONGLONG StartingAddress; + ULONGLONG EndingAddress; + union { + ULONGLONG EndOfPrologue; + ULONGLONG UnwindInfoAddress; + }; + } IMAGE_FUNCTION_ENTRY64,*PIMAGE_FUNCTION_ENTRY64; + + typedef struct _IMAGE_SEPARATE_DEBUG_HEADER { + WORD Signature; + WORD Flags; + WORD Machine; + WORD Characteristics; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD ImageBase; + DWORD SizeOfImage; + DWORD NumberOfSections; + DWORD ExportedNamesSize; + DWORD DebugDirectorySize; + DWORD SectionAlignment; + DWORD Reserved[2]; + } IMAGE_SEPARATE_DEBUG_HEADER,*PIMAGE_SEPARATE_DEBUG_HEADER; + + typedef struct _NON_PAGED_DEBUG_INFO { + WORD Signature; + WORD Flags; + DWORD Size; + WORD Machine; + WORD Characteristics; + DWORD TimeDateStamp; + DWORD CheckSum; + DWORD SizeOfImage; + ULONGLONG ImageBase; + + } NON_PAGED_DEBUG_INFO,*PNON_PAGED_DEBUG_INFO; + +#define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944 +#define NON_PAGED_DEBUG_SIGNATURE 0x494E + +#define IMAGE_SEPARATE_DEBUG_FLAGS_MASK 0x8000 +#define IMAGE_SEPARATE_DEBUG_MISMATCH 0x8000 + + typedef struct _ImageArchitectureHeader { + unsigned int AmaskValue: 1; + int Adummy1 :7; + unsigned int AmaskShift: 8; + int Adummy2 :16; + DWORD FirstEntryRVA; + } IMAGE_ARCHITECTURE_HEADER,*PIMAGE_ARCHITECTURE_HEADER; + + typedef struct _ImageArchitectureEntry { + DWORD FixupInstRVA; + DWORD NewInst; + } IMAGE_ARCHITECTURE_ENTRY,*PIMAGE_ARCHITECTURE_ENTRY; + +#include "poppack.h" + +#define IMPORT_OBJECT_HDR_SIG2 0xffff + + typedef struct IMPORT_OBJECT_HEADER { + WORD Sig1; + WORD Sig2; + WORD Version; + WORD Machine; + DWORD TimeDateStamp; + DWORD SizeOfData; + union { + WORD Ordinal; + WORD Hint; + }; + WORD Type : 2; + WORD NameType : 3; + WORD Reserved : 11; + } IMPORT_OBJECT_HEADER; + + typedef enum IMPORT_OBJECT_TYPE { + IMPORT_OBJECT_CODE = 0,IMPORT_OBJECT_DATA = 1,IMPORT_OBJECT_CONST = 2 + } IMPORT_OBJECT_TYPE; + + typedef enum IMPORT_OBJECT_NAME_TYPE { + IMPORT_OBJECT_ORDINAL = 0,IMPORT_OBJECT_NAME = 1,IMPORT_OBJECT_NAME_NO_PREFIX = 2,IMPORT_OBJECT_NAME_UNDECORATE = 3 + } IMPORT_OBJECT_NAME_TYPE; + +#ifndef __IMAGE_COR20_HEADER_DEFINED__ +#define __IMAGE_COR20_HEADER_DEFINED__ + typedef enum ReplacesCorHdrNumericDefines { + COMIMAGE_FLAGS_ILONLY =0x00000001,COMIMAGE_FLAGS_32BITREQUIRED =0x00000002,COMIMAGE_FLAGS_IL_LIBRARY =0x00000004, + COMIMAGE_FLAGS_STRONGNAMESIGNED =0x00000008,COMIMAGE_FLAGS_TRACKDEBUGDATA =0x00010000,COR_VERSION_MAJOR_V2 =2, + COR_VERSION_MAJOR =COR_VERSION_MAJOR_V2,COR_VERSION_MINOR =0,COR_DELETED_NAME_LENGTH =8,COR_VTABLEGAP_NAME_LENGTH =8, + NATIVE_TYPE_MAX_CB =1,COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE=0xFF,IMAGE_COR_MIH_METHODRVA =0x01,IMAGE_COR_MIH_EHRVA =0x02, + IMAGE_COR_MIH_BASICBLOCK =0x08,COR_VTABLE_32BIT =0x01,COR_VTABLE_64BIT =0x02,COR_VTABLE_FROM_UNMANAGED =0x04, + COR_VTABLE_CALL_MOST_DERIVED =0x10,IMAGE_COR_EATJ_THUNK_SIZE =32,MAX_CLASS_NAME =1024,MAX_PACKAGE_NAME =1024 + } ReplacesCorHdrNumericDefines; + + typedef struct IMAGE_COR20_HEADER { + DWORD cb; + WORD MajorRuntimeVersion; + WORD MinorRuntimeVersion; + IMAGE_DATA_DIRECTORY MetaData; + DWORD Flags; + DWORD EntryPointToken; + IMAGE_DATA_DIRECTORY Resources; + IMAGE_DATA_DIRECTORY StrongNameSignature; + IMAGE_DATA_DIRECTORY CodeManagerTable; + IMAGE_DATA_DIRECTORY VTableFixups; + IMAGE_DATA_DIRECTORY ExportAddressTableJumps; + IMAGE_DATA_DIRECTORY ManagedNativeHeader; + } IMAGE_COR20_HEADER,*PIMAGE_COR20_HEADER; +#endif + +#if defined (__x86_64) + NTSYSAPI PRUNTIME_FUNCTION NTAPI RtlLookupFunctionEntry (DWORD64 ControlPc, PDWORD64 ImageBase, PUNWIND_HISTORY_TABLE HistoryTable); + NTSYSAPI VOID NTAPI RtlUnwindEx (PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue, PCONTEXT ContextRecord, PUNWIND_HISTORY_TABLE HistoryTable); +#endif + +#include + +#ifndef _SLIST_HEADER_ +#define _SLIST_HEADER_ + +#ifdef _WIN64 + typedef struct _SLIST_ENTRY *PSLIST_ENTRY; + typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY { + PSLIST_ENTRY Next; + } SLIST_ENTRY; +#else + +#define SLIST_ENTRY SINGLE_LIST_ENTRY +#define _SLIST_ENTRY _SINGLE_LIST_ENTRY +#define PSLIST_ENTRY PSINGLE_LIST_ENTRY +#endif + +#if defined(_WIN64) + + typedef struct DECLSPEC_ALIGN(16) _SLIST_HEADER { + ULONGLONG Alignment; + ULONGLONG Region; + } SLIST_HEADER; + + typedef struct _SLIST_HEADER *PSLIST_HEADER; +#else + + typedef union _SLIST_HEADER { + ULONGLONG Alignment; + struct { + SLIST_ENTRY Next; + WORD Depth; + WORD Sequence; + }; + } SLIST_HEADER,*PSLIST_HEADER; +#endif +#endif + + NTSYSAPI VOID NTAPI RtlInitializeSListHead(PSLIST_HEADER ListHead); + NTSYSAPI PSLIST_ENTRY NTAPI RtlFirstEntrySList(const SLIST_HEADER *ListHead); + NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPopEntrySList(PSLIST_HEADER ListHead); + NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedPushEntrySList(PSLIST_HEADER ListHead,PSLIST_ENTRY ListEntry); + NTSYSAPI PSLIST_ENTRY NTAPI RtlInterlockedFlushSList(PSLIST_HEADER ListHead); + NTSYSAPI WORD NTAPI RtlQueryDepthSList(PSLIST_HEADER ListHead); + +#define HEAP_NO_SERIALIZE 0x00000001 +#define HEAP_GROWABLE 0x00000002 +#define HEAP_GENERATE_EXCEPTIONS 0x00000004 +#define HEAP_ZERO_MEMORY 0x00000008 +#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 +#define HEAP_TAIL_CHECKING_ENABLED 0x00000020 +#define HEAP_FREE_CHECKING_ENABLED 0x00000040 +#define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 +#define HEAP_CREATE_ALIGN_16 0x00010000 +#define HEAP_CREATE_ENABLE_TRACING 0x00020000 +#define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 +#define HEAP_MAXIMUM_TAG 0x0FFF +#define HEAP_PSEUDO_TAG_FLAG 0x8000 +#define HEAP_TAG_SHIFT 18 +#define HEAP_MAKE_TAG_FLAGS(b,o) ((DWORD)((b) + ((o) << 18))) + + NTSYSAPI VOID NTAPI RtlCaptureContext(PCONTEXT ContextRecord); + +#define IS_TEXT_UNICODE_ASCII16 0x0001 +#define IS_TEXT_UNICODE_REVERSE_ASCII16 0x0010 + +#define IS_TEXT_UNICODE_STATISTICS 0x0002 +#define IS_TEXT_UNICODE_REVERSE_STATISTICS 0x0020 + +#define IS_TEXT_UNICODE_CONTROLS 0x0004 +#define IS_TEXT_UNICODE_REVERSE_CONTROLS 0x0040 + +#define IS_TEXT_UNICODE_SIGNATURE 0x0008 +#define IS_TEXT_UNICODE_REVERSE_SIGNATURE 0x0080 + +#define IS_TEXT_UNICODE_ILLEGAL_CHARS 0x0100 +#define IS_TEXT_UNICODE_ODD_LENGTH 0x0200 +#define IS_TEXT_UNICODE_DBCS_LEADBYTE 0x0400 +#define IS_TEXT_UNICODE_NULL_BYTES 0x1000 + +#define IS_TEXT_UNICODE_UNICODE_MASK 0x000F +#define IS_TEXT_UNICODE_REVERSE_MASK 0x00F0 +#define IS_TEXT_UNICODE_NOT_UNICODE_MASK 0x0F00 +#define IS_TEXT_UNICODE_NOT_ASCII_MASK 0xF000 + +#define COMPRESSION_FORMAT_NONE (0x0000) +#define COMPRESSION_FORMAT_DEFAULT (0x0001) +#define COMPRESSION_FORMAT_LZNT1 (0x0002) +#define COMPRESSION_ENGINE_STANDARD (0x0000) +#define COMPRESSION_ENGINE_MAXIMUM (0x0100) +#define COMPRESSION_ENGINE_HIBER (0x0200) + +#if _DBG_MEMCPY_INLINE_ && !defined(_MEMCPY_INLINE_) && !defined(_CRTBLD) +#define _MEMCPY_INLINE_ + __CRT_INLINE PVOID __cdecl memcpy_inline(void *dst,const void *src,size_t size) { + if(((char *)dst > (char *)src) && ((char *)dst < ((char *)src + size))) { + __debugbreak(); + } + return memcpy(dst,src,size); + } +#define memcpy memcpy_inline +#endif + + NTSYSAPI SIZE_T NTAPI RtlCompareMemory(const VOID *Source1,const VOID *Source2,SIZE_T Length); + +#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length))) +#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length)) +#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length)) +#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length)) +#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) + + __CRT_INLINE PVOID RtlSecureZeroMemory(PVOID ptr,SIZE_T cnt) { + volatile char *vptr =(volatile char *)ptr; +#ifdef __x86_64 + __stosb((PBYTE)((DWORD64)vptr),0,cnt); +#else + while(cnt) { + *vptr = 0; + vptr++; + cnt--; + } +#endif + return ptr; + } + + typedef struct _MESSAGE_RESOURCE_ENTRY { + WORD Length; + WORD Flags; + BYTE Text[1]; + } MESSAGE_RESOURCE_ENTRY,*PMESSAGE_RESOURCE_ENTRY; + +#define MESSAGE_RESOURCE_UNICODE 0x0001 + + typedef struct _MESSAGE_RESOURCE_BLOCK { + DWORD LowId; + DWORD HighId; + DWORD OffsetToEntries; + } MESSAGE_RESOURCE_BLOCK,*PMESSAGE_RESOURCE_BLOCK; + + typedef struct _MESSAGE_RESOURCE_DATA { + DWORD NumberOfBlocks; + MESSAGE_RESOURCE_BLOCK Blocks[1]; + } MESSAGE_RESOURCE_DATA,*PMESSAGE_RESOURCE_DATA; + + typedef struct _OSVERSIONINFOA { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + CHAR szCSDVersion[128]; + } OSVERSIONINFOA,*POSVERSIONINFOA,*LPOSVERSIONINFOA; + + typedef struct _OSVERSIONINFOW { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + WCHAR szCSDVersion[128]; + } OSVERSIONINFOW,*POSVERSIONINFOW,*LPOSVERSIONINFOW,RTL_OSVERSIONINFOW,*PRTL_OSVERSIONINFOW; + +#ifdef UNICODE + typedef OSVERSIONINFOW OSVERSIONINFO; + typedef POSVERSIONINFOW POSVERSIONINFO; + typedef LPOSVERSIONINFOW LPOSVERSIONINFO; +#else + typedef OSVERSIONINFOA OSVERSIONINFO; + typedef POSVERSIONINFOA POSVERSIONINFO; + typedef LPOSVERSIONINFOA LPOSVERSIONINFO; +#endif + + typedef struct _OSVERSIONINFOEXA { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + CHAR szCSDVersion[128]; + WORD wServicePackMajor; + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; + BYTE wReserved; + } OSVERSIONINFOEXA,*POSVERSIONINFOEXA,*LPOSVERSIONINFOEXA; + + typedef struct _OSVERSIONINFOEXW { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + WCHAR szCSDVersion[128]; + WORD wServicePackMajor; + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; + BYTE wReserved; + } OSVERSIONINFOEXW,*POSVERSIONINFOEXW,*LPOSVERSIONINFOEXW,RTL_OSVERSIONINFOEXW,*PRTL_OSVERSIONINFOEXW; +#ifdef UNICODE + typedef OSVERSIONINFOEXW OSVERSIONINFOEX; + typedef POSVERSIONINFOEXW POSVERSIONINFOEX; + typedef LPOSVERSIONINFOEXW LPOSVERSIONINFOEX; +#else + typedef OSVERSIONINFOEXA OSVERSIONINFOEX; + typedef POSVERSIONINFOEXA POSVERSIONINFOEX; + typedef LPOSVERSIONINFOEXA LPOSVERSIONINFOEX; +#endif + +#define VER_EQUAL 1 +#define VER_GREATER 2 +#define VER_GREATER_EQUAL 3 +#define VER_LESS 4 +#define VER_LESS_EQUAL 5 +#define VER_AND 6 +#define VER_OR 7 + +#define VER_CONDITION_MASK 7 +#define VER_NUM_BITS_PER_CONDITION_MASK 3 + +#define VER_MINORVERSION 0x0000001 +#define VER_MAJORVERSION 0x0000002 +#define VER_BUILDNUMBER 0x0000004 +#define VER_PLATFORMID 0x0000008 +#define VER_SERVICEPACKMINOR 0x0000010 +#define VER_SERVICEPACKMAJOR 0x0000020 +#define VER_SUITENAME 0x0000040 +#define VER_PRODUCT_TYPE 0x0000080 + +#define VER_NT_WORKSTATION 0x0000001 +#define VER_NT_DOMAIN_CONTROLLER 0x0000002 +#define VER_NT_SERVER 0x0000003 + +#define VER_PLATFORM_WIN32s 0 +#define VER_PLATFORM_WIN32_WINDOWS 1 +#define VER_PLATFORM_WIN32_NT 2 + +#define VER_SET_CONDITION(_m_,_t_,_c_) ((_m_)=VerSetConditionMask((_m_),(_t_),(_c_))) + + NTSYSAPI ULONGLONG NTAPI VerSetConditionMask(ULONGLONG ConditionMask,DWORD TypeMask,BYTE Condition); + + typedef struct _RTL_CRITICAL_SECTION_DEBUG { + WORD Type; + WORD CreatorBackTraceIndex; + struct _RTL_CRITICAL_SECTION *CriticalSection; + LIST_ENTRY ProcessLocksList; + DWORD EntryCount; + DWORD ContentionCount; + DWORD Spare[2]; + } RTL_CRITICAL_SECTION_DEBUG,*PRTL_CRITICAL_SECTION_DEBUG,RTL_RESOURCE_DEBUG,*PRTL_RESOURCE_DEBUG; + +#define RTL_CRITSECT_TYPE 0 +#define RTL_RESOURCE_TYPE 1 + + typedef struct _RTL_CRITICAL_SECTION { + PRTL_CRITICAL_SECTION_DEBUG DebugInfo; + LONG LockCount; + LONG RecursionCount; + HANDLE OwningThread; + HANDLE LockSemaphore; + ULONG_PTR SpinCount; + } RTL_CRITICAL_SECTION,*PRTL_CRITICAL_SECTION; + + typedef VOID (NTAPI *RTL_VERIFIER_DLL_LOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); + typedef VOID (NTAPI *RTL_VERIFIER_DLL_UNLOAD_CALLBACK) (PWSTR DllName,PVOID DllBase,SIZE_T DllSize,PVOID Reserved); + typedef VOID (NTAPI *RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK)(PVOID AllocationBase,SIZE_T AllocationSize); + + typedef struct _RTL_VERIFIER_THUNK_DESCRIPTOR { + PCHAR ThunkName; + PVOID ThunkOldAddress; + PVOID ThunkNewAddress; + } RTL_VERIFIER_THUNK_DESCRIPTOR,*PRTL_VERIFIER_THUNK_DESCRIPTOR; + + typedef struct _RTL_VERIFIER_DLL_DESCRIPTOR { + PWCHAR DllName; + DWORD DllFlags; + PVOID DllAddress; + PRTL_VERIFIER_THUNK_DESCRIPTOR DllThunks; + } RTL_VERIFIER_DLL_DESCRIPTOR,*PRTL_VERIFIER_DLL_DESCRIPTOR; + + typedef struct _RTL_VERIFIER_PROVIDER_DESCRIPTOR { + DWORD Length; + PRTL_VERIFIER_DLL_DESCRIPTOR ProviderDlls; + RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback; + RTL_VERIFIER_DLL_UNLOAD_CALLBACK ProviderDllUnloadCallback; + PWSTR VerifierImage; + DWORD VerifierFlags; + DWORD VerifierDebug; + PVOID RtlpGetStackTraceAddress; + PVOID RtlpDebugPageHeapCreate; + PVOID RtlpDebugPageHeapDestroy; + RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK ProviderNtdllHeapFreeCallback; + } RTL_VERIFIER_PROVIDER_DESCRIPTOR,*PRTL_VERIFIER_PROVIDER_DESCRIPTOR; + +#define RTL_VRF_FLG_FULL_PAGE_HEAP 0x00000001 +#define RTL_VRF_FLG_RESERVED_DONOTUSE 0x00000002 +#define RTL_VRF_FLG_HANDLE_CHECKS 0x00000004 +#define RTL_VRF_FLG_STACK_CHECKS 0x00000008 +#define RTL_VRF_FLG_APPCOMPAT_CHECKS 0x00000010 +#define RTL_VRF_FLG_TLS_CHECKS 0x00000020 +#define RTL_VRF_FLG_DIRTY_STACKS 0x00000040 +#define RTL_VRF_FLG_RPC_CHECKS 0x00000080 +#define RTL_VRF_FLG_COM_CHECKS 0x00000100 +#define RTL_VRF_FLG_DANGEROUS_APIS 0x00000200 +#define RTL_VRF_FLG_RACE_CHECKS 0x00000400 +#define RTL_VRF_FLG_DEADLOCK_CHECKS 0x00000800 +#define RTL_VRF_FLG_FIRST_CHANCE_EXCEPTION_CHECKS 0x00001000 +#define RTL_VRF_FLG_VIRTUAL_MEM_CHECKS 0x00002000 +#define RTL_VRF_FLG_ENABLE_LOGGING 0x00004000 +#define RTL_VRF_FLG_FAST_FILL_HEAP 0x00008000 +#define RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING 0x00010000 +#define RTL_VRF_FLG_ENABLED_SYSTEM_WIDE 0x00020000 +#define RTL_VRF_FLG_MISCELLANEOUS_CHECKS 0x00020000 +#define RTL_VRF_FLG_LOCK_CHECKS 0x00040000 + +#define APPLICATION_VERIFIER_INTERNAL_ERROR 0x80000000 +#define APPLICATION_VERIFIER_INTERNAL_WARNING 0x40000000 +#define APPLICATION_VERIFIER_NO_BREAK 0x20000000 +#define APPLICATION_VERIFIER_CONTINUABLE_BREAK 0x10000000 + +#define APPLICATION_VERIFIER_UNKNOWN_ERROR 0x0001 +#define APPLICATION_VERIFIER_ACCESS_VIOLATION 0x0002 +#define APPLICATION_VERIFIER_UNSYNCHRONIZED_ACCESS 0x0003 +#define APPLICATION_VERIFIER_EXTREME_SIZE_REQUEST 0x0004 +#define APPLICATION_VERIFIER_BAD_HEAP_HANDLE 0x0005 +#define APPLICATION_VERIFIER_SWITCHED_HEAP_HANDLE 0x0006 +#define APPLICATION_VERIFIER_DOUBLE_FREE 0x0007 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK 0x0008 +#define APPLICATION_VERIFIER_DESTROY_PROCESS_HEAP 0x0009 +#define APPLICATION_VERIFIER_UNEXPECTED_EXCEPTION 0x000A +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_HEADER 0x000B +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_PROBING 0x000C +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_HEADER 0x000D +#define APPLICATION_VERIFIER_CORRUPTED_FREED_HEAP_BLOCK 0x000E +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_SUFFIX 0x000F +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_START_STAMP 0x0010 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_END_STAMP 0x0011 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_PREFIX 0x0012 +#define APPLICATION_VERIFIER_FIRST_CHANCE_ACCESS_VIOLATION 0x0013 +#define APPLICATION_VERIFIER_CORRUPTED_HEAP_LIST 0x0014 + +#define APPLICATION_VERIFIER_TERMINATE_THREAD_CALL 0x0100 +#define APPLICATION_VERIFIER_STACK_OVERFLOW 0x0101 +#define APPLICATION_VERIFIER_INVALID_EXIT_PROCESS_CALL 0x0102 + +#define APPLICATION_VERIFIER_EXIT_THREAD_OWNS_LOCK 0x0200 +#define APPLICATION_VERIFIER_LOCK_IN_UNLOADED_DLL 0x0201 +#define APPLICATION_VERIFIER_LOCK_IN_FREED_HEAP 0x0202 +#define APPLICATION_VERIFIER_LOCK_DOUBLE_INITIALIZE 0x0203 +#define APPLICATION_VERIFIER_LOCK_IN_FREED_MEMORY 0x0204 +#define APPLICATION_VERIFIER_LOCK_CORRUPTED 0x0205 +#define APPLICATION_VERIFIER_LOCK_INVALID_OWNER 0x0206 +#define APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT 0x0207 +#define APPLICATION_VERIFIER_LOCK_INVALID_LOCK_COUNT 0x0208 +#define APPLICATION_VERIFIER_LOCK_OVER_RELEASED 0x0209 +#define APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED 0x0210 +#define APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED 0x0211 +#define APPLICATION_VERIFIER_LOCK_IN_FREED_VMEM 0x0212 +#define APPLICATION_VERIFIER_LOCK_IN_UNMAPPED_MEM 0x0213 +#define APPLICATION_VERIFIER_THREAD_NOT_LOCK_OWNER 0x0214 + +#define APPLICATION_VERIFIER_INVALID_HANDLE 0x0300 +#define APPLICATION_VERIFIER_INVALID_TLS_VALUE 0x0301 +#define APPLICATION_VERIFIER_INCORRECT_WAIT_CALL 0x0302 +#define APPLICATION_VERIFIER_NULL_HANDLE 0x0303 +#define APPLICATION_VERIFIER_WAIT_IN_DLLMAIN 0x0304 + +#define APPLICATION_VERIFIER_COM_ERROR 0x0400 +#define APPLICATION_VERIFIER_COM_API_IN_DLLMAIN 0x0401 +#define APPLICATION_VERIFIER_COM_UNHANDLED_EXCEPTION 0x0402 +#define APPLICATION_VERIFIER_COM_UNBALANCED_COINIT 0x0403 +#define APPLICATION_VERIFIER_COM_UNBALANCED_OLEINIT 0x0404 +#define APPLICATION_VERIFIER_COM_UNBALANCED_SWC 0x0405 +#define APPLICATION_VERIFIER_COM_NULL_DACL 0x0406 +#define APPLICATION_VERIFIER_COM_UNSAFE_IMPERSONATION 0x0407 +#define APPLICATION_VERIFIER_COM_SMUGGLED_WRAPPER 0x0408 +#define APPLICATION_VERIFIER_COM_SMUGGLED_PROXY 0x0409 +#define APPLICATION_VERIFIER_COM_CF_SUCCESS_WITH_NULL 0x040A +#define APPLICATION_VERIFIER_COM_GCO_SUCCESS_WITH_NULL 0x040B +#define APPLICATION_VERIFIER_COM_OBJECT_IN_FREED_MEMORY 0x040C +#define APPLICATION_VERIFIER_COM_OBJECT_IN_UNLOADED_DLL 0x040D +#define APPLICATION_VERIFIER_COM_VTBL_IN_FREED_MEMORY 0x040E +#define APPLICATION_VERIFIER_COM_VTBL_IN_UNLOADED_DLL 0x040F +#define APPLICATION_VERIFIER_COM_HOLDING_LOCKS_ON_CALL 0x0410 + +#define APPLICATION_VERIFIER_RPC_ERROR 0x0500 + +#define APPLICATION_VERIFIER_INVALID_FREEMEM 0x0600 +#define APPLICATION_VERIFIER_INVALID_ALLOCMEM 0x0601 +#define APPLICATION_VERIFIER_INVALID_MAPVIEW 0x0602 +#define APPLICATION_VERIFIER_PROBE_INVALID_ADDRESS 0x0603 +#define APPLICATION_VERIFIER_PROBE_FREE_MEM 0x0604 +#define APPLICATION_VERIFIER_PROBE_GUARD_PAGE 0x0605 +#define APPLICATION_VERIFIER_PROBE_NULL 0x0606 +#define APPLICATION_VERIFIER_PROBE_INVALID_START_OR_SIZE 0x0607 +#define APPLICATION_VERIFIER_SIZE_HEAP_UNEXPECTED_EXCEPTION 0x0618 + +#define VERIFIER_STOP(Code,Msg,P1,S1,P2,S2,P3,S3,P4,S4) { RtlApplicationVerifierStop ((Code),(Msg),(ULONG_PTR)(P1),(S1),(ULONG_PTR)(P2),(S2),(ULONG_PTR)(P3),(S3),(ULONG_PTR)(P4),(S4)); } + + VOID NTAPI RtlApplicationVerifierStop(ULONG_PTR Code,PSTR Message,ULONG_PTR Param1,PSTR Description1,ULONG_PTR Param2,PSTR Description2,ULONG_PTR Param3,PSTR Description3,ULONG_PTR Param4,PSTR Description4); + + typedef LONG (NTAPI *PVECTORED_EXCEPTION_HANDLER)(struct _EXCEPTION_POINTERS *ExceptionInfo); +#define SEF_DACL_AUTO_INHERIT 0x01 +#define SEF_SACL_AUTO_INHERIT 0x02 +#define SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT 0x04 +#define SEF_AVOID_PRIVILEGE_CHECK 0x08 +#define SEF_AVOID_OWNER_CHECK 0x10 +#define SEF_DEFAULT_OWNER_FROM_PARENT 0x20 +#define SEF_DEFAULT_GROUP_FROM_PARENT 0x40 + + typedef enum _HEAP_INFORMATION_CLASS { + HeapCompatibilityInformation + } HEAP_INFORMATION_CLASS; + + NTSYSAPI DWORD NTAPI RtlSetHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength); + NTSYSAPI DWORD NTAPI RtlQueryHeapInformation(PVOID HeapHandle,HEAP_INFORMATION_CLASS HeapInformationClass,PVOID HeapInformation,SIZE_T HeapInformationLength,PSIZE_T ReturnLength); + DWORD NTAPI RtlMultipleAllocateHeap(PVOID HeapHandle,DWORD Flags,SIZE_T Size,DWORD Count,PVOID *Array); + DWORD NTAPI RtlMultipleFreeHeap(PVOID HeapHandle,DWORD Flags,DWORD Count,PVOID *Array); + +#define WT_EXECUTEDEFAULT 0x00000000 +#define WT_EXECUTEINIOTHREAD 0x00000001 +#define WT_EXECUTEINUITHREAD 0x00000002 +#define WT_EXECUTEINWAITTHREAD 0x00000004 +#define WT_EXECUTEONLYONCE 0x00000008 +#define WT_EXECUTEINTIMERTHREAD 0x00000020 +#define WT_EXECUTELONGFUNCTION 0x00000010 +#define WT_EXECUTEINPERSISTENTIOTHREAD 0x00000040 +#define WT_EXECUTEINPERSISTENTTHREAD 0x00000080 +#define WT_TRANSFER_IMPERSONATION 0x00000100 +#define WT_SET_MAX_THREADPOOL_THREADS(Flags,Limit) ((Flags) |= (Limit)<<16) + typedef VOID (NTAPI *WAITORTIMERCALLBACKFUNC)(PVOID,BOOLEAN); + typedef VOID (NTAPI *WORKERCALLBACKFUNC)(PVOID); + typedef VOID (NTAPI *APC_CALLBACK_FUNCTION)(DWORD ,PVOID,PVOID); + typedef + VOID + (NTAPI *PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); +#define WT_EXECUTEINLONGTHREAD 0x00000010 +#define WT_EXECUTEDELETEWAIT 0x00000008 + + typedef enum _ACTIVATION_CONTEXT_INFO_CLASS { + ActivationContextBasicInformation = 1,ActivationContextDetailedInformation = 2,AssemblyDetailedInformationInActivationContext = 3,FileInformationInAssemblyOfAssemblyInActivationContext = 4,MaxActivationContextInfoClass,AssemblyDetailedInformationInActivationContxt = 3,FileInformationInAssemblyOfAssemblyInActivationContxt = 4 + } ACTIVATION_CONTEXT_INFO_CLASS; + +#define ACTIVATIONCONTEXTINFOCLASS ACTIVATION_CONTEXT_INFO_CLASS + + typedef struct _ACTIVATION_CONTEXT_QUERY_INDEX { + DWORD ulAssemblyIndex; + DWORD ulFileIndexInAssembly; + } ACTIVATION_CONTEXT_QUERY_INDEX,*PACTIVATION_CONTEXT_QUERY_INDEX; + + typedef const struct _ACTIVATION_CONTEXT_QUERY_INDEX *PCACTIVATION_CONTEXT_QUERY_INDEX; + +#define ACTIVATION_CONTEXT_PATH_TYPE_NONE (1) +#define ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE (2) +#define ACTIVATION_CONTEXT_PATH_TYPE_URL (3) +#define ACTIVATION_CONTEXT_PATH_TYPE_ASSEMBLYREF (4) + + typedef struct _ASSEMBLY_FILE_DETAILED_INFORMATION { + DWORD ulFlags; + DWORD ulFilenameLength; + DWORD ulPathLength; + + PCWSTR lpFileName; + PCWSTR lpFilePath; + } ASSEMBLY_FILE_DETAILED_INFORMATION,*PASSEMBLY_FILE_DETAILED_INFORMATION; + typedef const ASSEMBLY_FILE_DETAILED_INFORMATION *PCASSEMBLY_FILE_DETAILED_INFORMATION; + +#define _ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION _ASSEMBLY_FILE_DETAILED_INFORMATION +#define ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION ASSEMBLY_FILE_DETAILED_INFORMATION +#define PASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PASSEMBLY_FILE_DETAILED_INFORMATION +#define PCASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION PCASSEMBLY_FILE_DETAILED_INFORMATION + + typedef struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION { + DWORD ulFlags; + DWORD ulEncodedAssemblyIdentityLength; + DWORD ulManifestPathType; + DWORD ulManifestPathLength; + LARGE_INTEGER liManifestLastWriteTime; + DWORD ulPolicyPathType; + DWORD ulPolicyPathLength; + LARGE_INTEGER liPolicyLastWriteTime; + DWORD ulMetadataSatelliteRosterIndex; + DWORD ulManifestVersionMajor; + DWORD ulManifestVersionMinor; + DWORD ulPolicyVersionMajor; + DWORD ulPolicyVersionMinor; + DWORD ulAssemblyDirectoryNameLength; + PCWSTR lpAssemblyEncodedAssemblyIdentity; + PCWSTR lpAssemblyManifestPath; + PCWSTR lpAssemblyPolicyPath; + PCWSTR lpAssemblyDirectoryName; + DWORD ulFileCount; + } ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; + + typedef const struct _ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; + + typedef struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION { + DWORD dwFlags; + DWORD ulFormatVersion; + DWORD ulAssemblyCount; + DWORD ulRootManifestPathType; + DWORD ulRootManifestPathChars; + DWORD ulRootConfigurationPathType; + DWORD ulRootConfigurationPathChars; + DWORD ulAppDirPathType; + DWORD ulAppDirPathChars; + PCWSTR lpRootManifestPath; + PCWSTR lpRootConfigurationPath; + PCWSTR lpAppDirPath; + } ACTIVATION_CONTEXT_DETAILED_INFORMATION,*PACTIVATION_CONTEXT_DETAILED_INFORMATION; + + typedef const struct _ACTIVATION_CONTEXT_DETAILED_INFORMATION *PCACTIVATION_CONTEXT_DETAILED_INFORMATION; + +#define DLL_PROCESS_ATTACH 1 +#define DLL_THREAD_ATTACH 2 +#define DLL_THREAD_DETACH 3 +#define DLL_PROCESS_DETACH 0 +#define DLL_PROCESS_VERIFIER 4 + +#define EVENTLOG_SEQUENTIAL_READ 0x0001 +#define EVENTLOG_SEEK_READ 0x0002 +#define EVENTLOG_FORWARDS_READ 0x0004 +#define EVENTLOG_BACKWARDS_READ 0x0008 + +#define EVENTLOG_SUCCESS 0x0000 +#define EVENTLOG_ERROR_TYPE 0x0001 +#define EVENTLOG_WARNING_TYPE 0x0002 +#define EVENTLOG_INFORMATION_TYPE 0x0004 +#define EVENTLOG_AUDIT_SUCCESS 0x0008 +#define EVENTLOG_AUDIT_FAILURE 0x0010 + +#define EVENTLOG_START_PAIRED_EVENT 0x0001 +#define EVENTLOG_END_PAIRED_EVENT 0x0002 +#define EVENTLOG_END_ALL_PAIRED_EVENTS 0x0004 +#define EVENTLOG_PAIRED_EVENT_ACTIVE 0x0008 +#define EVENTLOG_PAIRED_EVENT_INACTIVE 0x0010 + + typedef struct _EVENTLOGRECORD { + DWORD Length; + DWORD Reserved; + DWORD RecordNumber; + DWORD TimeGenerated; + DWORD TimeWritten; + DWORD EventID; + WORD EventType; + WORD NumStrings; + WORD EventCategory; + WORD ReservedFlags; + DWORD ClosingRecordNumber; + DWORD StringOffset; + DWORD UserSidLength; + DWORD UserSidOffset; + DWORD DataLength; + DWORD DataOffset; + } EVENTLOGRECORD,*PEVENTLOGRECORD; + +#define MAXLOGICALLOGNAMESIZE 256 + + typedef struct _EVENTSFORLOGFILE{ + DWORD ulSize; + WCHAR szLogicalLogFile[MAXLOGICALLOGNAMESIZE]; + DWORD ulNumRecords; + EVENTLOGRECORD pEventLogRecords[]; + } EVENTSFORLOGFILE,*PEVENTSFORLOGFILE; + + typedef struct _PACKEDEVENTINFO{ + DWORD ulSize; + DWORD ulNumEventsForLogFile; + DWORD ulOffsets[]; + } PACKEDEVENTINFO,*PPACKEDEVENTINFO; + +#define KEY_QUERY_VALUE (0x0001) +#define KEY_SET_VALUE (0x0002) +#define KEY_CREATE_SUB_KEY (0x0004) +#define KEY_ENUMERATE_SUB_KEYS (0x0008) +#define KEY_NOTIFY (0x0010) +#define KEY_CREATE_LINK (0x0020) +#define KEY_WOW64_32KEY (0x0200) +#define KEY_WOW64_64KEY (0x0100) +#define KEY_WOW64_RES (0x0300) + +#define KEY_READ ((STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & (~SYNCHRONIZE)) +#define KEY_WRITE ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE)) +#define KEY_EXECUTE ((KEY_READ) & (~SYNCHRONIZE)) +#define KEY_ALL_ACCESS ((STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & (~SYNCHRONIZE)) +#define REG_OPTION_RESERVED (0x00000000L) + +#define REG_OPTION_NON_VOLATILE (0x00000000L) +#define REG_OPTION_VOLATILE (0x00000001L) +#define REG_OPTION_CREATE_LINK (0x00000002L) +#define REG_OPTION_BACKUP_RESTORE (0x00000004L) +#define REG_OPTION_OPEN_LINK (0x00000008L) +#define REG_LEGAL_OPTION (REG_OPTION_RESERVED | REG_OPTION_NON_VOLATILE | REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK | REG_OPTION_BACKUP_RESTORE | REG_OPTION_OPEN_LINK) +#define REG_CREATED_NEW_KEY (0x00000001L) +#define REG_OPENED_EXISTING_KEY (0x00000002L) +#define REG_STANDARD_FORMAT 1 +#define REG_LATEST_FORMAT 2 +#define REG_NO_COMPRESSION 4 +#define REG_WHOLE_HIVE_VOLATILE (0x00000001L) +#define REG_REFRESH_HIVE (0x00000002L) +#define REG_NO_LAZY_FLUSH (0x00000004L) +#define REG_FORCE_RESTORE (0x00000008L) +#define REG_FORCE_UNLOAD 1 + +#define REG_NOTIFY_CHANGE_NAME (0x00000001L) +#define REG_NOTIFY_CHANGE_ATTRIBUTES (0x00000002L) +#define REG_NOTIFY_CHANGE_LAST_SET (0x00000004L) +#define REG_NOTIFY_CHANGE_SECURITY (0x00000008L) + +#define REG_LEGAL_CHANGE_FILTER (REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY) + +#define REG_NONE (0) +#define REG_SZ (1) +#define REG_EXPAND_SZ (2) + +#define REG_BINARY (3) +#define REG_DWORD (4) +#define REG_DWORD_LITTLE_ENDIAN (4) +#define REG_DWORD_BIG_ENDIAN (5) +#define REG_LINK (6) +#define REG_MULTI_SZ (7) +#define REG_RESOURCE_LIST (8) +#define REG_FULL_RESOURCE_DESCRIPTOR (9) +#define REG_RESOURCE_REQUIREMENTS_LIST (10) +#define REG_QWORD (11) +#define REG_QWORD_LITTLE_ENDIAN (11) + +#define SERVICE_KERNEL_DRIVER 0x00000001 +#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 +#define SERVICE_ADAPTER 0x00000004 +#define SERVICE_RECOGNIZER_DRIVER 0x00000008 + +#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER) + +#define SERVICE_WIN32_OWN_PROCESS 0x00000010 +#define SERVICE_WIN32_SHARE_PROCESS 0x00000020 +#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS) + +#define SERVICE_INTERACTIVE_PROCESS 0x00000100 + +#define SERVICE_TYPE_ALL (SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS) + +#define SERVICE_BOOT_START 0x00000000 +#define SERVICE_SYSTEM_START 0x00000001 +#define SERVICE_AUTO_START 0x00000002 +#define SERVICE_DEMAND_START 0x00000003 +#define SERVICE_DISABLED 0x00000004 + +#define SERVICE_ERROR_IGNORE 0x00000000 +#define SERVICE_ERROR_NORMAL 0x00000001 +#define SERVICE_ERROR_SEVERE 0x00000002 +#define SERVICE_ERROR_CRITICAL 0x00000003 + + typedef enum _CM_SERVICE_NODE_TYPE { + DriverType = SERVICE_KERNEL_DRIVER,FileSystemType = SERVICE_FILE_SYSTEM_DRIVER,Win32ServiceOwnProcess = SERVICE_WIN32_OWN_PROCESS, + Win32ServiceShareProcess = SERVICE_WIN32_SHARE_PROCESS,AdapterType = SERVICE_ADAPTER,RecognizerType = SERVICE_RECOGNIZER_DRIVER + } SERVICE_NODE_TYPE; + + typedef enum _CM_SERVICE_LOAD_TYPE { + BootLoad = SERVICE_BOOT_START,SystemLoad = SERVICE_SYSTEM_START,AutoLoad = SERVICE_AUTO_START,DemandLoad = SERVICE_DEMAND_START, + DisableLoad = SERVICE_DISABLED + } SERVICE_LOAD_TYPE; + + typedef enum _CM_ERROR_CONTROL_TYPE { + IgnoreError = SERVICE_ERROR_IGNORE,NormalError = SERVICE_ERROR_NORMAL,SevereError = SERVICE_ERROR_SEVERE,CriticalError = SERVICE_ERROR_CRITICAL + } SERVICE_ERROR_TYPE; + +#define TAPE_ERASE_SHORT 0L +#define TAPE_ERASE_LONG 1L + + typedef struct _TAPE_ERASE { + DWORD Type; + BOOLEAN Immediate; + } TAPE_ERASE,*PTAPE_ERASE; + +#define TAPE_LOAD 0L +#define TAPE_UNLOAD 1L +#define TAPE_TENSION 2L +#define TAPE_LOCK 3L +#define TAPE_UNLOCK 4L +#define TAPE_FORMAT 5L + + typedef struct _TAPE_PREPARE { + DWORD Operation; + BOOLEAN Immediate; + } TAPE_PREPARE,*PTAPE_PREPARE; + +#define TAPE_SETMARKS 0L +#define TAPE_FILEMARKS 1L +#define TAPE_SHORT_FILEMARKS 2L +#define TAPE_LONG_FILEMARKS 3L + + typedef struct _TAPE_WRITE_MARKS { + DWORD Type; + DWORD Count; + BOOLEAN Immediate; + } TAPE_WRITE_MARKS,*PTAPE_WRITE_MARKS; + +#define TAPE_ABSOLUTE_POSITION 0L +#define TAPE_LOGICAL_POSITION 1L +#define TAPE_PSEUDO_LOGICAL_POSITION 2L + + typedef struct _TAPE_GET_POSITION { + DWORD Type; + DWORD Partition; + LARGE_INTEGER Offset; + } TAPE_GET_POSITION,*PTAPE_GET_POSITION; + +#define TAPE_REWIND 0L +#define TAPE_ABSOLUTE_BLOCK 1L +#define TAPE_LOGICAL_BLOCK 2L +#define TAPE_PSEUDO_LOGICAL_BLOCK 3L +#define TAPE_SPACE_END_OF_DATA 4L +#define TAPE_SPACE_RELATIVE_BLOCKS 5L +#define TAPE_SPACE_FILEMARKS 6L +#define TAPE_SPACE_SEQUENTIAL_FMKS 7L +#define TAPE_SPACE_SETMARKS 8L +#define TAPE_SPACE_SEQUENTIAL_SMKS 9L + + typedef struct _TAPE_SET_POSITION { + DWORD Method; + DWORD Partition; + LARGE_INTEGER Offset; + BOOLEAN Immediate; + } TAPE_SET_POSITION,*PTAPE_SET_POSITION; + +#define TAPE_DRIVE_FIXED 0x00000001 +#define TAPE_DRIVE_SELECT 0x00000002 +#define TAPE_DRIVE_INITIATOR 0x00000004 + +#define TAPE_DRIVE_ERASE_SHORT 0x00000010 +#define TAPE_DRIVE_ERASE_LONG 0x00000020 +#define TAPE_DRIVE_ERASE_BOP_ONLY 0x00000040 +#define TAPE_DRIVE_ERASE_IMMEDIATE 0x00000080 + +#define TAPE_DRIVE_TAPE_CAPACITY 0x00000100 +#define TAPE_DRIVE_TAPE_REMAINING 0x00000200 +#define TAPE_DRIVE_FIXED_BLOCK 0x00000400 +#define TAPE_DRIVE_VARIABLE_BLOCK 0x00000800 + +#define TAPE_DRIVE_WRITE_PROTECT 0x00001000 +#define TAPE_DRIVE_EOT_WZ_SIZE 0x00002000 + +#define TAPE_DRIVE_ECC 0x00010000 +#define TAPE_DRIVE_COMPRESSION 0x00020000 +#define TAPE_DRIVE_PADDING 0x00040000 +#define TAPE_DRIVE_REPORT_SMKS 0x00080000 + +#define TAPE_DRIVE_GET_ABSOLUTE_BLK 0x00100000 +#define TAPE_DRIVE_GET_LOGICAL_BLK 0x00200000 +#define TAPE_DRIVE_SET_EOT_WZ_SIZE 0x00400000 + +#define TAPE_DRIVE_EJECT_MEDIA 0x01000000 +#define TAPE_DRIVE_CLEAN_REQUESTS 0x02000000 +#define TAPE_DRIVE_SET_CMP_BOP_ONLY 0x04000000 + +#define TAPE_DRIVE_RESERVED_BIT 0x80000000 + +#define TAPE_DRIVE_LOAD_UNLOAD 0x80000001 +#define TAPE_DRIVE_TENSION 0x80000002 +#define TAPE_DRIVE_LOCK_UNLOCK 0x80000004 +#define TAPE_DRIVE_REWIND_IMMEDIATE 0x80000008 + +#define TAPE_DRIVE_SET_BLOCK_SIZE 0x80000010 +#define TAPE_DRIVE_LOAD_UNLD_IMMED 0x80000020 +#define TAPE_DRIVE_TENSION_IMMED 0x80000040 +#define TAPE_DRIVE_LOCK_UNLK_IMMED 0x80000080 + +#define TAPE_DRIVE_SET_ECC 0x80000100 +#define TAPE_DRIVE_SET_COMPRESSION 0x80000200 +#define TAPE_DRIVE_SET_PADDING 0x80000400 +#define TAPE_DRIVE_SET_REPORT_SMKS 0x80000800 + +#define TAPE_DRIVE_ABSOLUTE_BLK 0x80001000 +#define TAPE_DRIVE_ABS_BLK_IMMED 0x80002000 +#define TAPE_DRIVE_LOGICAL_BLK 0x80004000 +#define TAPE_DRIVE_LOG_BLK_IMMED 0x80008000 + +#define TAPE_DRIVE_END_OF_DATA 0x80010000 +#define TAPE_DRIVE_RELATIVE_BLKS 0x80020000 +#define TAPE_DRIVE_FILEMARKS 0x80040000 +#define TAPE_DRIVE_SEQUENTIAL_FMKS 0x80080000 + +#define TAPE_DRIVE_SETMARKS 0x80100000 +#define TAPE_DRIVE_SEQUENTIAL_SMKS 0x80200000 +#define TAPE_DRIVE_REVERSE_POSITION 0x80400000 +#define TAPE_DRIVE_SPACE_IMMEDIATE 0x80800000 + +#define TAPE_DRIVE_WRITE_SETMARKS 0x81000000 +#define TAPE_DRIVE_WRITE_FILEMARKS 0x82000000 +#define TAPE_DRIVE_WRITE_SHORT_FMKS 0x84000000 +#define TAPE_DRIVE_WRITE_LONG_FMKS 0x88000000 + +#define TAPE_DRIVE_WRITE_MARK_IMMED 0x90000000 +#define TAPE_DRIVE_FORMAT 0xA0000000 +#define TAPE_DRIVE_FORMAT_IMMEDIATE 0xC0000000 +#define TAPE_DRIVE_HIGH_FEATURES 0x80000000 + + typedef struct _TAPE_GET_DRIVE_PARAMETERS { + BOOLEAN ECC; + BOOLEAN Compression; + BOOLEAN DataPadding; + BOOLEAN ReportSetmarks; + DWORD DefaultBlockSize; + DWORD MaximumBlockSize; + DWORD MinimumBlockSize; + DWORD MaximumPartitionCount; + DWORD FeaturesLow; + DWORD FeaturesHigh; + DWORD EOTWarningZoneSize; + } TAPE_GET_DRIVE_PARAMETERS,*PTAPE_GET_DRIVE_PARAMETERS; + + typedef struct _TAPE_SET_DRIVE_PARAMETERS { + BOOLEAN ECC; + BOOLEAN Compression; + BOOLEAN DataPadding; + BOOLEAN ReportSetmarks; + DWORD EOTWarningZoneSize; + } TAPE_SET_DRIVE_PARAMETERS,*PTAPE_SET_DRIVE_PARAMETERS; + + typedef struct _TAPE_GET_MEDIA_PARAMETERS { + LARGE_INTEGER Capacity; + LARGE_INTEGER Remaining; + DWORD BlockSize; + DWORD PartitionCount; + BOOLEAN WriteProtected; + } TAPE_GET_MEDIA_PARAMETERS,*PTAPE_GET_MEDIA_PARAMETERS; + + typedef struct _TAPE_SET_MEDIA_PARAMETERS { + DWORD BlockSize; + } TAPE_SET_MEDIA_PARAMETERS,*PTAPE_SET_MEDIA_PARAMETERS; + +#define TAPE_FIXED_PARTITIONS 0L +#define TAPE_SELECT_PARTITIONS 1L +#define TAPE_INITIATOR_PARTITIONS 2L + + typedef struct _TAPE_CREATE_PARTITION { + DWORD Method; + DWORD Count; + DWORD Size; + } TAPE_CREATE_PARTITION,*PTAPE_CREATE_PARTITION; + +#define TAPE_QUERY_DRIVE_PARAMETERS 0L +#define TAPE_QUERY_MEDIA_CAPACITY 1L +#define TAPE_CHECK_FOR_DRIVE_PROBLEM 2L +#define TAPE_QUERY_IO_ERROR_DATA 3L +#define TAPE_QUERY_DEVICE_ERROR_DATA 4L + + typedef struct _TAPE_WMI_OPERATIONS { + DWORD Method; + DWORD DataBufferSize; + PVOID DataBuffer; + } TAPE_WMI_OPERATIONS,*PTAPE_WMI_OPERATIONS; + + typedef enum _TAPE_DRIVE_PROBLEM_TYPE { + TapeDriveProblemNone,TapeDriveReadWriteWarning,TapeDriveReadWriteError,TapeDriveReadWarning,TapeDriveWriteWarning,TapeDriveReadError,TapeDriveWriteError,TapeDriveHardwareError,TapeDriveUnsupportedMedia,TapeDriveScsiConnectionError,TapeDriveTimetoClean,TapeDriveCleanDriveNow,TapeDriveMediaLifeExpired,TapeDriveSnappedTape + } TAPE_DRIVE_PROBLEM_TYPE; + +#if defined(__x86_64) + __CRT_INLINE struct _TEB *NtCurrentTeb(VOID) { return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB,Self)); } + __CRT_INLINE PVOID GetCurrentFiber(VOID) { return(PVOID)__readgsqword(FIELD_OFFSET(NT_TIB,FiberData)); } + __CRT_INLINE PVOID GetFiberData(VOID) { + return *(PVOID *)GetCurrentFiber(); + } +#endif + +#if(defined(_X86_) && !defined(__x86_64)) +#define PcTeb 0x18 + __CRT_INLINE struct _TEB *NtCurrentTeb(void) { + struct _TEB *ret; + __asm__ volatile ("movl %%fs:0x18,%0" + : "=r" (ret)); + return ret; + } +#endif + +#define ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION (1) +#define ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION (2) +#define ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION (3) +#define ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION (4) +#define ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION (5) +#define ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION (6) +#define ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION (7) +#define ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE (8) +#define ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES (9) +#define ACTIVATION_CONTEXT_SECTION_APPLICATION_SETTINGS (10) + +#ifdef __cplusplus + } +#endif +#endif diff --git a/tcc/include/winapi/winreg.h b/tcc/include/winapi/winreg.h index a3b5eb3b..f158d282 100644 --- a/tcc/include/winapi/winreg.h +++ b/tcc/include/winapi/winreg.h @@ -1,272 +1,272 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINREG_ -#define _WINREG_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#define RRF_RT_REG_NONE 0x00000001 -#define RRF_RT_REG_SZ 0x00000002 -#define RRF_RT_REG_EXPAND_SZ 0x00000004 -#define RRF_RT_REG_BINARY 0x00000008 -#define RRF_RT_REG_DWORD 0x00000010 -#define RRF_RT_REG_MULTI_SZ 0x00000020 -#define RRF_RT_REG_QWORD 0x00000040 - -#define RRF_RT_DWORD (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD) -#define RRF_RT_QWORD (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD) -#define RRF_RT_ANY 0x0000ffff - -#define RRF_NOEXPAND 0x10000000 -#define RRF_ZEROONFAILURE 0x20000000 - - typedef ACCESS_MASK REGSAM; - -#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000)) -#define HKEY_CURRENT_USER ((HKEY) (ULONG_PTR)((LONG)0x80000001)) -#define HKEY_LOCAL_MACHINE ((HKEY) (ULONG_PTR)((LONG)0x80000002)) -#define HKEY_USERS ((HKEY) (ULONG_PTR)((LONG)0x80000003)) -#define HKEY_PERFORMANCE_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000004)) -#define HKEY_PERFORMANCE_TEXT ((HKEY) (ULONG_PTR)((LONG)0x80000050)) -#define HKEY_PERFORMANCE_NLSTEXT ((HKEY) (ULONG_PTR)((LONG)0x80000060)) -#define HKEY_CURRENT_CONFIG ((HKEY) (ULONG_PTR)((LONG)0x80000005)) -#define HKEY_DYN_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000006)) - -#define REG_SECURE_CONNECTION 1 - -#ifndef _PROVIDER_STRUCTS_DEFINED -#define _PROVIDER_STRUCTS_DEFINED - -#define PROVIDER_KEEPS_VALUE_LENGTH 0x1 - struct val_context { - int valuelen; - LPVOID value_context; - LPVOID val_buff_ptr; - }; - - typedef struct val_context *PVALCONTEXT; - - typedef struct pvalueA { - LPSTR pv_valuename; - int pv_valuelen; - LPVOID pv_value_context; - DWORD pv_type; - }PVALUEA,*PPVALUEA; - - typedef struct pvalueW { - LPWSTR pv_valuename; - int pv_valuelen; - LPVOID pv_value_context; - DWORD pv_type; - }PVALUEW,*PPVALUEW; - -#ifdef UNICODE - typedef PVALUEW PVALUE; - typedef PPVALUEW PPVALUE; -#else - typedef PVALUEA PVALUE; - typedef PPVALUEA PPVALUE; -#endif - - typedef DWORD __cdecl QUERYHANDLER(LPVOID keycontext,PVALCONTEXT val_list,DWORD num_vals,LPVOID outputbuffer,DWORD *total_outlen,DWORD input_blen); - - typedef QUERYHANDLER *PQUERYHANDLER; - - typedef struct provider_info { - PQUERYHANDLER pi_R0_1val; - PQUERYHANDLER pi_R0_allvals; - PQUERYHANDLER pi_R3_1val; - PQUERYHANDLER pi_R3_allvals; - DWORD pi_flags; - LPVOID pi_key_context; - } REG_PROVIDER; - - typedef struct provider_info *PPROVIDER; - - typedef struct value_entA { - LPSTR ve_valuename; - DWORD ve_valuelen; - DWORD_PTR ve_valueptr; - DWORD ve_type; - } VALENTA,*PVALENTA; - - typedef struct value_entW { - LPWSTR ve_valuename; - DWORD ve_valuelen; - DWORD_PTR ve_valueptr; - DWORD ve_type; - } VALENTW,*PVALENTW; - -#ifdef UNICODE - typedef VALENTW VALENT; - typedef PVALENTW PVALENT; -#else - typedef VALENTA VALENT; - typedef PVALENTA PVALENT; -#endif -#endif - -#define WIN31_CLASS NULL - -#ifdef UNICODE -#define RegConnectRegistry RegConnectRegistryW -#define RegConnectRegistryEx RegConnectRegistryExW -#define RegCreateKey RegCreateKeyW -#define RegCreateKeyEx RegCreateKeyExW -#define RegDeleteKey RegDeleteKeyW -#define RegDeleteKeyEx RegDeleteKeyExW -#define RegDeleteValue RegDeleteValueW -#define RegEnumKey RegEnumKeyW -#define RegEnumKeyEx RegEnumKeyExW -#define RegEnumValue RegEnumValueW -#define RegLoadKey RegLoadKeyW -#define RegOpenKey RegOpenKeyW -#define RegOpenKeyEx RegOpenKeyExW -#define RegQueryInfoKey RegQueryInfoKeyW -#define RegQueryValue RegQueryValueW -#define RegQueryMultipleValues RegQueryMultipleValuesW -#define RegQueryValueEx RegQueryValueExW -#define RegReplaceKey RegReplaceKeyW -#define RegRestoreKey RegRestoreKeyW -#define RegSaveKey RegSaveKeyW -#define RegSetValue RegSetValueW -#define RegSetValueEx RegSetValueExW -#define RegUnLoadKey RegUnLoadKeyW -#define RegGetValue RegGetValueW -#define InitiateSystemShutdown InitiateSystemShutdownW -#define AbortSystemShutdown AbortSystemShutdownW -#else -#define RegConnectRegistry RegConnectRegistryA -#define RegConnectRegistryEx RegConnectRegistryExA -#define RegCreateKey RegCreateKeyA -#define RegCreateKeyEx RegCreateKeyExA -#define RegDeleteKey RegDeleteKeyA -#define RegDeleteKeyEx RegDeleteKeyExA -#define RegDeleteValue RegDeleteValueA -#define RegEnumKey RegEnumKeyA -#define RegEnumKeyEx RegEnumKeyExA -#define RegEnumValue RegEnumValueA -#define RegLoadKey RegLoadKeyA -#define RegOpenKey RegOpenKeyA -#define RegOpenKeyEx RegOpenKeyExA -#define RegQueryInfoKey RegQueryInfoKeyA -#define RegQueryValue RegQueryValueA -#define RegQueryMultipleValues RegQueryMultipleValuesA -#define RegQueryValueEx RegQueryValueExA -#define RegReplaceKey RegReplaceKeyA -#define RegRestoreKey RegRestoreKeyA -#define RegSaveKey RegSaveKeyA -#define RegSetValue RegSetValueA -#define RegSetValueEx RegSetValueExA -#define RegUnLoadKey RegUnLoadKeyA -#define RegGetValue RegGetValueA -#define InitiateSystemShutdown InitiateSystemShutdownA -#define AbortSystemShutdown AbortSystemShutdownA -#endif - - WINADVAPI LONG WINAPI RegCloseKey(HKEY hKey); - WINADVAPI LONG WINAPI RegOverridePredefKey(HKEY hKey,HKEY hNewHKey); - WINADVAPI LONG WINAPI RegOpenUserClassesRoot(HANDLE hToken,DWORD dwOptions,REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenCurrentUser(REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegDisablePredefinedCache(); - WINADVAPI LONG WINAPI RegConnectRegistryA(LPCSTR lpMachineName,HKEY hKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegConnectRegistryW(LPCWSTR lpMachineName,HKEY hKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegConnectRegistryExA(LPCSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); - WINADVAPI LONG WINAPI RegConnectRegistryExW(LPCWSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); - WINADVAPI LONG WINAPI RegCreateKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegCreateKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegCreateKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD Reserved,LPSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); - WINADVAPI LONG WINAPI RegCreateKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD Reserved,LPWSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); - WINADVAPI LONG WINAPI RegDeleteKeyA(HKEY hKey,LPCSTR lpSubKey); - WINADVAPI LONG WINAPI RegDeleteKeyW(HKEY hKey,LPCWSTR lpSubKey); - WINADVAPI LONG WINAPI RegDeleteKeyExA(HKEY hKey,LPCSTR lpSubKey,REGSAM samDesired,DWORD Reserved); - WINADVAPI LONG WINAPI RegDeleteKeyExW(HKEY hKey,LPCWSTR lpSubKey,REGSAM samDesired,DWORD Reserved); - WINADVAPI LONG WINAPI RegDisableReflectionKey(HKEY hBase); - WINADVAPI LONG WINAPI RegEnableReflectionKey(HKEY hBase); - WINADVAPI LONG WINAPI RegQueryReflectionKey(HKEY hBase,WINBOOL *bIsReflectionDisabled); - WINADVAPI LONG WINAPI RegDeleteValueA(HKEY hKey,LPCSTR lpValueName); - WINADVAPI LONG WINAPI RegDeleteValueW(HKEY hKey,LPCWSTR lpValueName); - WINADVAPI LONG WINAPI RegEnumKeyA(HKEY hKey,DWORD dwIndex,LPSTR lpName,DWORD cchName); - WINADVAPI LONG WINAPI RegEnumKeyW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,DWORD cchName); - WINADVAPI LONG WINAPI RegEnumKeyExA(HKEY hKey,DWORD dwIndex,LPSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegEnumKeyExW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPWSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegEnumValueA(HKEY hKey,DWORD dwIndex,LPSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegEnumValueW(HKEY hKey,DWORD dwIndex,LPWSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegFlushKey(HKEY hKey); - WINADVAPI LONG WINAPI RegGetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,LPDWORD lpcbSecurityDescriptor); - WINADVAPI LONG WINAPI RegLoadKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpFile); - WINADVAPI LONG WINAPI RegLoadKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpFile); - WINADVAPI LONG WINAPI RegNotifyChangeKeyValue(HKEY hKey,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,HANDLE hEvent,WINBOOL fAsynchronous); - WINADVAPI LONG WINAPI RegOpenKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegOpenKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); - WINADVAPI LONG WINAPI RegQueryInfoKeyA(HKEY hKey,LPSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegQueryInfoKeyW(HKEY hKey,LPWSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); - WINADVAPI LONG WINAPI RegQueryValueA(HKEY hKey,LPCSTR lpSubKey,LPSTR lpData,PLONG lpcbData); - WINADVAPI LONG WINAPI RegQueryValueW(HKEY hKey,LPCWSTR lpSubKey,LPWSTR lpData,PLONG lpcbData); - WINADVAPI LONG WINAPI RegQueryMultipleValuesA(HKEY hKey,PVALENTA val_list,DWORD num_vals,LPSTR lpValueBuf,LPDWORD ldwTotsize); - WINADVAPI LONG WINAPI RegQueryMultipleValuesW(HKEY hKey,PVALENTW val_list,DWORD num_vals,LPWSTR lpValueBuf,LPDWORD ldwTotsize); - WINADVAPI LONG WINAPI RegQueryValueExA(HKEY hKey,LPCSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegQueryValueExW(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); - WINADVAPI LONG WINAPI RegReplaceKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpNewFile,LPCSTR lpOldFile); - WINADVAPI LONG WINAPI RegReplaceKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpNewFile,LPCWSTR lpOldFile); - WINADVAPI LONG WINAPI RegRestoreKeyA(HKEY hKey,LPCSTR lpFile,DWORD dwFlags); - WINADVAPI LONG WINAPI RegRestoreKeyW(HKEY hKey,LPCWSTR lpFile,DWORD dwFlags); - WINADVAPI LONG WINAPI RegSaveKeyA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINADVAPI LONG WINAPI RegSaveKeyW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); - WINADVAPI LONG WINAPI RegSetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); - WINADVAPI LONG WINAPI RegSetValueA(HKEY hKey,LPCSTR lpSubKey,DWORD dwType,LPCSTR lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegSetValueW(HKEY hKey,LPCWSTR lpSubKey,DWORD dwType,LPCWSTR lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegSetValueExA(HKEY hKey,LPCSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegSetValueExW(HKEY hKey,LPCWSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); - WINADVAPI LONG WINAPI RegUnLoadKeyA(HKEY hKey,LPCSTR lpSubKey); - WINADVAPI LONG WINAPI RegUnLoadKeyW(HKEY hKey,LPCWSTR lpSubKey); - WINADVAPI LONG WINAPI RegGetValueA(HKEY hkey,LPCSTR lpSubKey,LPCSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); - WINADVAPI LONG WINAPI RegGetValueW(HKEY hkey,LPCWSTR lpSubKey,LPCWSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); - WINADVAPI WINBOOL WINAPI AbortSystemShutdownA(LPSTR lpMachineName); - WINADVAPI WINBOOL WINAPI AbortSystemShutdownW(LPWSTR lpMachineName); - -//gr #include - -#define REASON_SWINSTALL SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_INSTALLATION -#define REASON_HWINSTALL SHTDN_REASON_MAJOR_HARDWARE|SHTDN_REASON_MINOR_INSTALLATION -#define REASON_SERVICEHANG SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_HUNG -#define REASON_UNSTABLE SHTDN_REASON_MAJOR_SYSTEM|SHTDN_REASON_MINOR_UNSTABLE -#define REASON_SWHWRECONF SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_RECONFIG -#define REASON_OTHER SHTDN_REASON_MAJOR_OTHER|SHTDN_REASON_MINOR_OTHER -#define REASON_UNKNOWN SHTDN_REASON_UNKNOWN -#define REASON_LEGACY_API SHTDN_REASON_LEGACY_API -#define REASON_PLANNED_FLAG SHTDN_REASON_FLAG_PLANNED - -#define MAX_SHUTDOWN_TIMEOUT (10*365*24*60*60) - -#ifdef UNICODE -#define InitiateSystemShutdownEx InitiateSystemShutdownExW -#define RegSaveKeyEx RegSaveKeyExW -#else -#define InitiateSystemShutdownEx InitiateSystemShutdownExA -#define RegSaveKeyEx RegSaveKeyExA -#endif - - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); - WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); - WINADVAPI LONG WINAPI RegSaveKeyExA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); - WINADVAPI LONG WINAPI RegSaveKeyExW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); - WINADVAPI LONG WINAPI Wow64Win32ApiEntry (DWORD dwFuncNumber,DWORD dwFlag,DWORD dwRes); - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINREG_ +#define _WINREG_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#define RRF_RT_REG_NONE 0x00000001 +#define RRF_RT_REG_SZ 0x00000002 +#define RRF_RT_REG_EXPAND_SZ 0x00000004 +#define RRF_RT_REG_BINARY 0x00000008 +#define RRF_RT_REG_DWORD 0x00000010 +#define RRF_RT_REG_MULTI_SZ 0x00000020 +#define RRF_RT_REG_QWORD 0x00000040 + +#define RRF_RT_DWORD (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD) +#define RRF_RT_QWORD (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD) +#define RRF_RT_ANY 0x0000ffff + +#define RRF_NOEXPAND 0x10000000 +#define RRF_ZEROONFAILURE 0x20000000 + + typedef ACCESS_MASK REGSAM; + +#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000)) +#define HKEY_CURRENT_USER ((HKEY) (ULONG_PTR)((LONG)0x80000001)) +#define HKEY_LOCAL_MACHINE ((HKEY) (ULONG_PTR)((LONG)0x80000002)) +#define HKEY_USERS ((HKEY) (ULONG_PTR)((LONG)0x80000003)) +#define HKEY_PERFORMANCE_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000004)) +#define HKEY_PERFORMANCE_TEXT ((HKEY) (ULONG_PTR)((LONG)0x80000050)) +#define HKEY_PERFORMANCE_NLSTEXT ((HKEY) (ULONG_PTR)((LONG)0x80000060)) +#define HKEY_CURRENT_CONFIG ((HKEY) (ULONG_PTR)((LONG)0x80000005)) +#define HKEY_DYN_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000006)) + +#define REG_SECURE_CONNECTION 1 + +#ifndef _PROVIDER_STRUCTS_DEFINED +#define _PROVIDER_STRUCTS_DEFINED + +#define PROVIDER_KEEPS_VALUE_LENGTH 0x1 + struct val_context { + int valuelen; + LPVOID value_context; + LPVOID val_buff_ptr; + }; + + typedef struct val_context *PVALCONTEXT; + + typedef struct pvalueA { + LPSTR pv_valuename; + int pv_valuelen; + LPVOID pv_value_context; + DWORD pv_type; + }PVALUEA,*PPVALUEA; + + typedef struct pvalueW { + LPWSTR pv_valuename; + int pv_valuelen; + LPVOID pv_value_context; + DWORD pv_type; + }PVALUEW,*PPVALUEW; + +#ifdef UNICODE + typedef PVALUEW PVALUE; + typedef PPVALUEW PPVALUE; +#else + typedef PVALUEA PVALUE; + typedef PPVALUEA PPVALUE; +#endif + + typedef DWORD __cdecl QUERYHANDLER(LPVOID keycontext,PVALCONTEXT val_list,DWORD num_vals,LPVOID outputbuffer,DWORD *total_outlen,DWORD input_blen); + + typedef QUERYHANDLER *PQUERYHANDLER; + + typedef struct provider_info { + PQUERYHANDLER pi_R0_1val; + PQUERYHANDLER pi_R0_allvals; + PQUERYHANDLER pi_R3_1val; + PQUERYHANDLER pi_R3_allvals; + DWORD pi_flags; + LPVOID pi_key_context; + } REG_PROVIDER; + + typedef struct provider_info *PPROVIDER; + + typedef struct value_entA { + LPSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; + } VALENTA,*PVALENTA; + + typedef struct value_entW { + LPWSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; + } VALENTW,*PVALENTW; + +#ifdef UNICODE + typedef VALENTW VALENT; + typedef PVALENTW PVALENT; +#else + typedef VALENTA VALENT; + typedef PVALENTA PVALENT; +#endif +#endif + +#define WIN31_CLASS NULL + +#ifdef UNICODE +#define RegConnectRegistry RegConnectRegistryW +#define RegConnectRegistryEx RegConnectRegistryExW +#define RegCreateKey RegCreateKeyW +#define RegCreateKeyEx RegCreateKeyExW +#define RegDeleteKey RegDeleteKeyW +#define RegDeleteKeyEx RegDeleteKeyExW +#define RegDeleteValue RegDeleteValueW +#define RegEnumKey RegEnumKeyW +#define RegEnumKeyEx RegEnumKeyExW +#define RegEnumValue RegEnumValueW +#define RegLoadKey RegLoadKeyW +#define RegOpenKey RegOpenKeyW +#define RegOpenKeyEx RegOpenKeyExW +#define RegQueryInfoKey RegQueryInfoKeyW +#define RegQueryValue RegQueryValueW +#define RegQueryMultipleValues RegQueryMultipleValuesW +#define RegQueryValueEx RegQueryValueExW +#define RegReplaceKey RegReplaceKeyW +#define RegRestoreKey RegRestoreKeyW +#define RegSaveKey RegSaveKeyW +#define RegSetValue RegSetValueW +#define RegSetValueEx RegSetValueExW +#define RegUnLoadKey RegUnLoadKeyW +#define RegGetValue RegGetValueW +#define InitiateSystemShutdown InitiateSystemShutdownW +#define AbortSystemShutdown AbortSystemShutdownW +#else +#define RegConnectRegistry RegConnectRegistryA +#define RegConnectRegistryEx RegConnectRegistryExA +#define RegCreateKey RegCreateKeyA +#define RegCreateKeyEx RegCreateKeyExA +#define RegDeleteKey RegDeleteKeyA +#define RegDeleteKeyEx RegDeleteKeyExA +#define RegDeleteValue RegDeleteValueA +#define RegEnumKey RegEnumKeyA +#define RegEnumKeyEx RegEnumKeyExA +#define RegEnumValue RegEnumValueA +#define RegLoadKey RegLoadKeyA +#define RegOpenKey RegOpenKeyA +#define RegOpenKeyEx RegOpenKeyExA +#define RegQueryInfoKey RegQueryInfoKeyA +#define RegQueryValue RegQueryValueA +#define RegQueryMultipleValues RegQueryMultipleValuesA +#define RegQueryValueEx RegQueryValueExA +#define RegReplaceKey RegReplaceKeyA +#define RegRestoreKey RegRestoreKeyA +#define RegSaveKey RegSaveKeyA +#define RegSetValue RegSetValueA +#define RegSetValueEx RegSetValueExA +#define RegUnLoadKey RegUnLoadKeyA +#define RegGetValue RegGetValueA +#define InitiateSystemShutdown InitiateSystemShutdownA +#define AbortSystemShutdown AbortSystemShutdownA +#endif + + WINADVAPI LONG WINAPI RegCloseKey(HKEY hKey); + WINADVAPI LONG WINAPI RegOverridePredefKey(HKEY hKey,HKEY hNewHKey); + WINADVAPI LONG WINAPI RegOpenUserClassesRoot(HANDLE hToken,DWORD dwOptions,REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenCurrentUser(REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegDisablePredefinedCache(); + WINADVAPI LONG WINAPI RegConnectRegistryA(LPCSTR lpMachineName,HKEY hKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegConnectRegistryW(LPCWSTR lpMachineName,HKEY hKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegConnectRegistryExA(LPCSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); + WINADVAPI LONG WINAPI RegConnectRegistryExW(LPCWSTR lpMachineName,HKEY hKey,ULONG Flags,PHKEY phkResult); + WINADVAPI LONG WINAPI RegCreateKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegCreateKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegCreateKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD Reserved,LPSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); + WINADVAPI LONG WINAPI RegCreateKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD Reserved,LPWSTR lpClass,DWORD dwOptions,REGSAM samDesired,LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition); + WINADVAPI LONG WINAPI RegDeleteKeyA(HKEY hKey,LPCSTR lpSubKey); + WINADVAPI LONG WINAPI RegDeleteKeyW(HKEY hKey,LPCWSTR lpSubKey); + WINADVAPI LONG WINAPI RegDeleteKeyExA(HKEY hKey,LPCSTR lpSubKey,REGSAM samDesired,DWORD Reserved); + WINADVAPI LONG WINAPI RegDeleteKeyExW(HKEY hKey,LPCWSTR lpSubKey,REGSAM samDesired,DWORD Reserved); + WINADVAPI LONG WINAPI RegDisableReflectionKey(HKEY hBase); + WINADVAPI LONG WINAPI RegEnableReflectionKey(HKEY hBase); + WINADVAPI LONG WINAPI RegQueryReflectionKey(HKEY hBase,WINBOOL *bIsReflectionDisabled); + WINADVAPI LONG WINAPI RegDeleteValueA(HKEY hKey,LPCSTR lpValueName); + WINADVAPI LONG WINAPI RegDeleteValueW(HKEY hKey,LPCWSTR lpValueName); + WINADVAPI LONG WINAPI RegEnumKeyA(HKEY hKey,DWORD dwIndex,LPSTR lpName,DWORD cchName); + WINADVAPI LONG WINAPI RegEnumKeyW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,DWORD cchName); + WINADVAPI LONG WINAPI RegEnumKeyExA(HKEY hKey,DWORD dwIndex,LPSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegEnumKeyExW(HKEY hKey,DWORD dwIndex,LPWSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPWSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegEnumValueA(HKEY hKey,DWORD dwIndex,LPSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegEnumValueW(HKEY hKey,DWORD dwIndex,LPWSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegFlushKey(HKEY hKey); + WINADVAPI LONG WINAPI RegGetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor,LPDWORD lpcbSecurityDescriptor); + WINADVAPI LONG WINAPI RegLoadKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpFile); + WINADVAPI LONG WINAPI RegLoadKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpFile); + WINADVAPI LONG WINAPI RegNotifyChangeKeyValue(HKEY hKey,WINBOOL bWatchSubtree,DWORD dwNotifyFilter,HANDLE hEvent,WINBOOL fAsynchronous); + WINADVAPI LONG WINAPI RegOpenKeyA(HKEY hKey,LPCSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenKeyExA(HKEY hKey,LPCSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegOpenKeyExW(HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult); + WINADVAPI LONG WINAPI RegQueryInfoKeyA(HKEY hKey,LPSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegQueryInfoKeyW(HKEY hKey,LPWSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime); + WINADVAPI LONG WINAPI RegQueryValueA(HKEY hKey,LPCSTR lpSubKey,LPSTR lpData,PLONG lpcbData); + WINADVAPI LONG WINAPI RegQueryValueW(HKEY hKey,LPCWSTR lpSubKey,LPWSTR lpData,PLONG lpcbData); + WINADVAPI LONG WINAPI RegQueryMultipleValuesA(HKEY hKey,PVALENTA val_list,DWORD num_vals,LPSTR lpValueBuf,LPDWORD ldwTotsize); + WINADVAPI LONG WINAPI RegQueryMultipleValuesW(HKEY hKey,PVALENTW val_list,DWORD num_vals,LPWSTR lpValueBuf,LPDWORD ldwTotsize); + WINADVAPI LONG WINAPI RegQueryValueExA(HKEY hKey,LPCSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegQueryValueExW(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData); + WINADVAPI LONG WINAPI RegReplaceKeyA(HKEY hKey,LPCSTR lpSubKey,LPCSTR lpNewFile,LPCSTR lpOldFile); + WINADVAPI LONG WINAPI RegReplaceKeyW(HKEY hKey,LPCWSTR lpSubKey,LPCWSTR lpNewFile,LPCWSTR lpOldFile); + WINADVAPI LONG WINAPI RegRestoreKeyA(HKEY hKey,LPCSTR lpFile,DWORD dwFlags); + WINADVAPI LONG WINAPI RegRestoreKeyW(HKEY hKey,LPCWSTR lpFile,DWORD dwFlags); + WINADVAPI LONG WINAPI RegSaveKeyA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINADVAPI LONG WINAPI RegSaveKeyW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes); + WINADVAPI LONG WINAPI RegSetKeySecurity(HKEY hKey,SECURITY_INFORMATION SecurityInformation,PSECURITY_DESCRIPTOR pSecurityDescriptor); + WINADVAPI LONG WINAPI RegSetValueA(HKEY hKey,LPCSTR lpSubKey,DWORD dwType,LPCSTR lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegSetValueW(HKEY hKey,LPCWSTR lpSubKey,DWORD dwType,LPCWSTR lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegSetValueExA(HKEY hKey,LPCSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegSetValueExW(HKEY hKey,LPCWSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE *lpData,DWORD cbData); + WINADVAPI LONG WINAPI RegUnLoadKeyA(HKEY hKey,LPCSTR lpSubKey); + WINADVAPI LONG WINAPI RegUnLoadKeyW(HKEY hKey,LPCWSTR lpSubKey); + WINADVAPI LONG WINAPI RegGetValueA(HKEY hkey,LPCSTR lpSubKey,LPCSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); + WINADVAPI LONG WINAPI RegGetValueW(HKEY hkey,LPCWSTR lpSubKey,LPCWSTR lpValue,DWORD dwFlags,LPDWORD pdwType,PVOID pvData,LPDWORD pcbData); + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown); + WINADVAPI WINBOOL WINAPI AbortSystemShutdownA(LPSTR lpMachineName); + WINADVAPI WINBOOL WINAPI AbortSystemShutdownW(LPWSTR lpMachineName); + +//gr #include + +#define REASON_SWINSTALL SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_INSTALLATION +#define REASON_HWINSTALL SHTDN_REASON_MAJOR_HARDWARE|SHTDN_REASON_MINOR_INSTALLATION +#define REASON_SERVICEHANG SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_HUNG +#define REASON_UNSTABLE SHTDN_REASON_MAJOR_SYSTEM|SHTDN_REASON_MINOR_UNSTABLE +#define REASON_SWHWRECONF SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_RECONFIG +#define REASON_OTHER SHTDN_REASON_MAJOR_OTHER|SHTDN_REASON_MINOR_OTHER +#define REASON_UNKNOWN SHTDN_REASON_UNKNOWN +#define REASON_LEGACY_API SHTDN_REASON_LEGACY_API +#define REASON_PLANNED_FLAG SHTDN_REASON_FLAG_PLANNED + +#define MAX_SHUTDOWN_TIMEOUT (10*365*24*60*60) + +#ifdef UNICODE +#define InitiateSystemShutdownEx InitiateSystemShutdownExW +#define RegSaveKeyEx RegSaveKeyExW +#else +#define InitiateSystemShutdownEx InitiateSystemShutdownExA +#define RegSaveKeyEx RegSaveKeyExA +#endif + + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExA(LPSTR lpMachineName,LPSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); + WINADVAPI WINBOOL WINAPI InitiateSystemShutdownExW(LPWSTR lpMachineName,LPWSTR lpMessage,DWORD dwTimeout,WINBOOL bForceAppsClosed,WINBOOL bRebootAfterShutdown,DWORD dwReason); + WINADVAPI LONG WINAPI RegSaveKeyExA(HKEY hKey,LPCSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); + WINADVAPI LONG WINAPI RegSaveKeyExW(HKEY hKey,LPCWSTR lpFile,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD Flags); + WINADVAPI LONG WINAPI Wow64Win32ApiEntry (DWORD dwFuncNumber,DWORD dwFlag,DWORD dwRes); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/winsock2.h b/tcc/include/winapi/winsock2.h index e3d9eaa9..365ace64 100644 --- a/tcc/include/winapi/winsock2.h +++ b/tcc/include/winapi/winsock2.h @@ -1,1474 +1,1474 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ - -#ifndef _WINSOCK2API_ -#define _WINSOCK2API_ - -#ifndef INCL_WINSOCK_API_TYPEDEFS -#define INCL_WINSOCK_API_TYPEDEFS 0 -#endif - -#ifndef _INC_WINDOWS -#include -#endif - -#ifndef MAKEWORD -#define MAKEWORD(low,high) ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8)) -#endif - -#ifndef WINSOCK_VERSION -#define WINSOCK_VERSION MAKEWORD(2,2) -#endif - -#ifndef WINSOCK_API_LINKAGE -#ifdef DECLSPEC_IMPORT -#define WINSOCK_API_LINKAGE DECLSPEC_IMPORT -#else -#define WINSOCK_API_LINKAGE -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _WINSOCK_SOCKET_DEFINED -#define _WINSOCK_SOCKET_DEFINED - typedef unsigned char u_char; - typedef unsigned short u_short; - typedef unsigned int u_int; - typedef unsigned long u_long; - __MINGW_EXTENSION typedef unsigned __int64 u_int64; - typedef INT_PTR SOCKET; -#endif - -#ifndef FD_SETSIZE -#define FD_SETSIZE 64 -#endif - - typedef struct fd_set { - u_int fd_count; - SOCKET fd_array[FD_SETSIZE]; - } fd_set; - - extern int WINAPI __WSAFDIsSet(SOCKET,fd_set *); - -#define FD_CLR(fd,set) do { u_int __i; for(__i = 0;__i < ((fd_set *)(set))->fd_count;__i++) { if (((fd_set *)(set))->fd_array[__i]==fd) { while (__i < ((fd_set *)(set))->fd_count-1) { ((fd_set *)(set))->fd_array[__i] = ((fd_set *)(set))->fd_array[__i+1]; __i++; } ((fd_set *)(set))->fd_count--; break; } } } while(0) -#define FD_SET(fd,set) do { u_int __i; for(__i = 0;__i < ((fd_set *)(set))->fd_count;__i++) { if (((fd_set *)(set))->fd_array[__i]==(fd)) { break; } } if (__i==((fd_set *)(set))->fd_count) { if (((fd_set *)(set))->fd_count < FD_SETSIZE) { ((fd_set *)(set))->fd_array[__i] = (fd); ((fd_set *)(set))->fd_count++; } } } while(0) -#define FD_ZERO(set) (((fd_set *)(set))->fd_count=0) -#define FD_ISSET(fd,set) __WSAFDIsSet((SOCKET)(fd),(fd_set *)(set)) - -#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ -#define _TIMEVAL_DEFINED - struct timeval { - long tv_sec; - long tv_usec; - }; - -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif /* _TIMEVAL_DEFINED */ - -#define IOCPARM_MASK 0x7f -#define IOC_VOID 0x20000000 -#define IOC_OUT 0x40000000 -#define IOC_IN 0x80000000 -#define IOC_INOUT (IOC_IN|IOC_OUT) - -#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) -#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) -#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) - -#define FIONREAD _IOR('f',127,u_long) -#define FIONBIO _IOW('f',126,u_long) -#define FIOASYNC _IOW('f',125,u_long) - -#define SIOCSHIWAT _IOW('s',0,u_long) -#define SIOCGHIWAT _IOR('s',1,u_long) -#define SIOCSLOWAT _IOW('s',2,u_long) -#define SIOCGLOWAT _IOR('s',3,u_long) -#define SIOCATMARK _IOR('s',7,u_long) - -#define h_addr h_addr_list[0] - - struct hostent { - char *h_name; - char **h_aliases; - short h_addrtype; - short h_length; - char **h_addr_list; - }; - - struct netent { - char *n_name; - char **n_aliases; - short n_addrtype; - u_long n_net; - }; - - struct servent { - char *s_name; - char **s_aliases; -#ifdef _WIN64 - char *s_proto; - short s_port; -#else - short s_port; - char *s_proto; -#endif - }; - - struct protoent { - char *p_name; - char **p_aliases; - short p_proto; - }; - -#define IPPROTO_IP 0 -#define IPPROTO_HOPOPTS 0 -#define IPPROTO_ICMP 1 -#define IPPROTO_IGMP 2 -#define IPPROTO_GGP 3 -#define IPPROTO_IPV4 4 -#define IPPROTO_TCP 6 -#define IPPROTO_PUP 12 -#define IPPROTO_UDP 17 -#define IPPROTO_IDP 22 -#define IPPROTO_IPV6 41 -#define IPPROTO_ROUTING 43 -#define IPPROTO_FRAGMENT 44 -#define IPPROTO_ESP 50 -#define IPPROTO_AH 51 -#define IPPROTO_ICMPV6 58 -#define IPPROTO_NONE 59 -#define IPPROTO_DSTOPTS 60 -#define IPPROTO_ND 77 -#define IPPROTO_ICLFXBM 78 - -#define IPPROTO_RAW 255 -#define IPPROTO_MAX 256 - -#define IPPORT_ECHO 7 -#define IPPORT_DISCARD 9 -#define IPPORT_SYSTAT 11 -#define IPPORT_DAYTIME 13 -#define IPPORT_NETSTAT 15 -#define IPPORT_FTP 21 -#define IPPORT_TELNET 23 -#define IPPORT_SMTP 25 -#define IPPORT_TIMESERVER 37 -#define IPPORT_NAMESERVER 42 -#define IPPORT_WHOIS 43 -#define IPPORT_MTP 57 - -#define IPPORT_TFTP 69 -#define IPPORT_RJE 77 -#define IPPORT_FINGER 79 -#define IPPORT_TTYLINK 87 -#define IPPORT_SUPDUP 95 - -#define IPPORT_EXECSERVER 512 -#define IPPORT_LOGINSERVER 513 -#define IPPORT_CMDSERVER 514 -#define IPPORT_EFSSERVER 520 - -#define IPPORT_BIFFUDP 512 -#define IPPORT_WHOSERVER 513 -#define IPPORT_ROUTESERVER 520 - -#define IPPORT_RESERVED 1024 - -#define IMPLINK_IP 155 -#define IMPLINK_LOWEXPER 156 -#define IMPLINK_HIGHEXPER 158 - -#ifndef s_addr - - struct in_addr { - union { - struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; - struct { u_short s_w1,s_w2; } S_un_w; - u_long S_addr; - } S_un; - }; - -#define s_addr S_un.S_addr -#define s_host S_un.S_un_b.s_b2 -#define s_net S_un.S_un_b.s_b1 -#define s_imp S_un.S_un_w.s_w2 -#define s_impno S_un.S_un_b.s_b4 -#define s_lh S_un.S_un_b.s_b3 - -#endif - -#define IN_CLASSA(i) (((long)(i) & 0x80000000)==0) -#define IN_CLASSA_NET 0xff000000 -#define IN_CLASSA_NSHIFT 24 -#define IN_CLASSA_HOST 0x00ffffff -#define IN_CLASSA_MAX 128 - -#define IN_CLASSB(i) (((long)(i) & 0xc0000000)==0x80000000) -#define IN_CLASSB_NET 0xffff0000 -#define IN_CLASSB_NSHIFT 16 -#define IN_CLASSB_HOST 0x0000ffff -#define IN_CLASSB_MAX 65536 - -#define IN_CLASSC(i) (((long)(i) & 0xe0000000)==0xc0000000) -#define IN_CLASSC_NET 0xffffff00 -#define IN_CLASSC_NSHIFT 8 -#define IN_CLASSC_HOST 0x000000ff - -#define IN_CLASSD(i) (((long)(i) & 0xf0000000)==0xe0000000) -#define IN_CLASSD_NET 0xf0000000 -#define IN_CLASSD_NSHIFT 28 -#define IN_CLASSD_HOST 0x0fffffff -#define IN_MULTICAST(i) IN_CLASSD(i) - -#define INADDR_ANY (u_long)0x00000000 -#define INADDR_LOOPBACK 0x7f000001 -#define INADDR_BROADCAST (u_long)0xffffffff -#define INADDR_NONE 0xffffffff - -#define ADDR_ANY INADDR_ANY - - struct sockaddr_in { - short sin_family; - u_short sin_port; - struct in_addr sin_addr; - char sin_zero[8]; - }; - -#define WSADESCRIPTION_LEN 256 -#define WSASYS_STATUS_LEN 128 - - typedef struct WSAData { - WORD wVersion; - WORD wHighVersion; -#ifdef _WIN64 - unsigned short iMaxSockets; - unsigned short iMaxUdpDg; - char *lpVendorInfo; - char szDescription[WSADESCRIPTION_LEN+1]; - char szSystemStatus[WSASYS_STATUS_LEN+1]; -#else - char szDescription[WSADESCRIPTION_LEN+1]; - char szSystemStatus[WSASYS_STATUS_LEN+1]; - unsigned short iMaxSockets; - unsigned short iMaxUdpDg; - char *lpVendorInfo; -#endif - } WSADATA,*LPWSADATA; - -#define INVALID_SOCKET (SOCKET)(~0) -#define SOCKET_ERROR (-1) - -#define FROM_PROTOCOL_INFO (-1) - -#define SOCK_STREAM 1 -#define SOCK_DGRAM 2 -#define SOCK_RAW 3 -#define SOCK_RDM 4 -#define SOCK_SEQPACKET 5 - -#define SO_DEBUG 0x0001 -#define SO_ACCEPTCONN 0x0002 -#define SO_REUSEADDR 0x0004 -#define SO_KEEPALIVE 0x0008 -#define SO_DONTROUTE 0x0010 -#define SO_BROADCAST 0x0020 -#define SO_USELOOPBACK 0x0040 -#define SO_LINGER 0x0080 -#define SO_OOBINLINE 0x0100 - -#define SO_DONTLINGER (int)(~SO_LINGER) -#define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR)) - -#define SO_SNDBUF 0x1001 -#define SO_RCVBUF 0x1002 -#define SO_SNDLOWAT 0x1003 -#define SO_RCVLOWAT 0x1004 -#define SO_SNDTIMEO 0x1005 -#define SO_RCVTIMEO 0x1006 -#define SO_ERROR 0x1007 -#define SO_TYPE 0x1008 - -#define SO_GROUP_ID 0x2001 -#define SO_GROUP_PRIORITY 0x2002 -#define SO_MAX_MSG_SIZE 0x2003 -#define SO_PROTOCOL_INFOA 0x2004 -#define SO_PROTOCOL_INFOW 0x2005 -#ifdef UNICODE -#define SO_PROTOCOL_INFO SO_PROTOCOL_INFOW -#else -#define SO_PROTOCOL_INFO SO_PROTOCOL_INFOA -#endif -#define PVD_CONFIG 0x3001 -#define SO_CONDITIONAL_ACCEPT 0x3002 - -#define TCP_NODELAY 0x0001 - -#define AF_UNSPEC 0 - -#define AF_UNIX 1 -#define AF_INET 2 -#define AF_IMPLINK 3 -#define AF_PUP 4 -#define AF_CHAOS 5 -#define AF_NS 6 -#define AF_IPX AF_NS -#define AF_ISO 7 -#define AF_OSI AF_ISO -#define AF_ECMA 8 -#define AF_DATAKIT 9 -#define AF_CCITT 10 -#define AF_SNA 11 -#define AF_DECnet 12 -#define AF_DLI 13 -#define AF_LAT 14 -#define AF_HYLINK 15 -#define AF_APPLETALK 16 -#define AF_NETBIOS 17 -#define AF_VOICEVIEW 18 -#define AF_FIREFOX 19 -#define AF_UNKNOWN1 20 -#define AF_BAN 21 -#define AF_ATM 22 -#define AF_INET6 23 -#define AF_CLUSTER 24 -#define AF_12844 25 -#define AF_IRDA 26 -#define AF_NETDES 28 -#define AF_TCNPROCESS 29 -#define AF_TCNMESSAGE 30 -#define AF_ICLFXBM 31 - -#define AF_MAX 32 - - struct sockaddr { - u_short sa_family; - char sa_data[14]; - }; - -#define _SS_MAXSIZE 128 -#define _SS_ALIGNSIZE (8) - -#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (short)) -#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (short) + _SS_PAD1SIZE + _SS_ALIGNSIZE)) - - struct sockaddr_storage { - short ss_family; - char __ss_pad1[_SS_PAD1SIZE]; - - __MINGW_EXTENSION __int64 __ss_align; - char __ss_pad2[_SS_PAD2SIZE]; - - }; - - struct sockproto { - u_short sp_family; - u_short sp_protocol; - }; - -#define PF_UNSPEC AF_UNSPEC -#define PF_UNIX AF_UNIX -#define PF_INET AF_INET -#define PF_IMPLINK AF_IMPLINK -#define PF_PUP AF_PUP -#define PF_CHAOS AF_CHAOS -#define PF_NS AF_NS -#define PF_IPX AF_IPX -#define PF_ISO AF_ISO -#define PF_OSI AF_OSI -#define PF_ECMA AF_ECMA -#define PF_DATAKIT AF_DATAKIT -#define PF_CCITT AF_CCITT -#define PF_SNA AF_SNA -#define PF_DECnet AF_DECnet -#define PF_DLI AF_DLI -#define PF_LAT AF_LAT -#define PF_HYLINK AF_HYLINK -#define PF_APPLETALK AF_APPLETALK -#define PF_VOICEVIEW AF_VOICEVIEW -#define PF_FIREFOX AF_FIREFOX -#define PF_UNKNOWN1 AF_UNKNOWN1 -#define PF_BAN AF_BAN -#define PF_ATM AF_ATM -#define PF_INET6 AF_INET6 - -#define PF_MAX AF_MAX - - struct linger { - u_short l_onoff; - u_short l_linger; - }; - -#define SOL_SOCKET 0xffff - -#define SOMAXCONN 0x7fffffff - -#define MSG_OOB 0x1 -#define MSG_PEEK 0x2 -#define MSG_DONTROUTE 0x4 -#define MSG_WAITALL 0x8 - -#define MSG_PARTIAL 0x8000 - -#define MSG_INTERRUPT 0x10 - -#define MSG_MAXIOVLEN 16 - -#define MAXGETHOSTSTRUCT 1024 - -#define FD_READ_BIT 0 -#define FD_READ (1 << FD_READ_BIT) - -#define FD_WRITE_BIT 1 -#define FD_WRITE (1 << FD_WRITE_BIT) - -#define FD_OOB_BIT 2 -#define FD_OOB (1 << FD_OOB_BIT) - -#define FD_ACCEPT_BIT 3 -#define FD_ACCEPT (1 << FD_ACCEPT_BIT) - -#define FD_CONNECT_BIT 4 -#define FD_CONNECT (1 << FD_CONNECT_BIT) - -#define FD_CLOSE_BIT 5 -#define FD_CLOSE (1 << FD_CLOSE_BIT) - -#define FD_QOS_BIT 6 -#define FD_QOS (1 << FD_QOS_BIT) - -#define FD_GROUP_QOS_BIT 7 -#define FD_GROUP_QOS (1 << FD_GROUP_QOS_BIT) - -#define FD_ROUTING_INTERFACE_CHANGE_BIT 8 -#define FD_ROUTING_INTERFACE_CHANGE (1 << FD_ROUTING_INTERFACE_CHANGE_BIT) - -#define FD_ADDRESS_LIST_CHANGE_BIT 9 -#define FD_ADDRESS_LIST_CHANGE (1 << FD_ADDRESS_LIST_CHANGE_BIT) - -#define FD_MAX_EVENTS 10 -#define FD_ALL_EVENTS ((1 << FD_MAX_EVENTS) - 1) - -#ifndef WSABASEERR - -#define WSABASEERR 10000 - -#define WSAEINTR (WSABASEERR+4) -#define WSAEBADF (WSABASEERR+9) -#define WSAEACCES (WSABASEERR+13) -#define WSAEFAULT (WSABASEERR+14) -#define WSAEINVAL (WSABASEERR+22) -#define WSAEMFILE (WSABASEERR+24) - -#define WSAEWOULDBLOCK (WSABASEERR+35) -#define WSAEINPROGRESS (WSABASEERR+36) -#define WSAEALREADY (WSABASEERR+37) -#define WSAENOTSOCK (WSABASEERR+38) -#define WSAEDESTADDRREQ (WSABASEERR+39) -#define WSAEMSGSIZE (WSABASEERR+40) -#define WSAEPROTOTYPE (WSABASEERR+41) -#define WSAENOPROTOOPT (WSABASEERR+42) -#define WSAEPROTONOSUPPORT (WSABASEERR+43) -#define WSAESOCKTNOSUPPORT (WSABASEERR+44) -#define WSAEOPNOTSUPP (WSABASEERR+45) -#define WSAEPFNOSUPPORT (WSABASEERR+46) -#define WSAEAFNOSUPPORT (WSABASEERR+47) -#define WSAEADDRINUSE (WSABASEERR+48) -#define WSAEADDRNOTAVAIL (WSABASEERR+49) -#define WSAENETDOWN (WSABASEERR+50) -#define WSAENETUNREACH (WSABASEERR+51) -#define WSAENETRESET (WSABASEERR+52) -#define WSAECONNABORTED (WSABASEERR+53) -#define WSAECONNRESET (WSABASEERR+54) -#define WSAENOBUFS (WSABASEERR+55) -#define WSAEISCONN (WSABASEERR+56) -#define WSAENOTCONN (WSABASEERR+57) -#define WSAESHUTDOWN (WSABASEERR+58) -#define WSAETOOMANYREFS (WSABASEERR+59) -#define WSAETIMEDOUT (WSABASEERR+60) -#define WSAECONNREFUSED (WSABASEERR+61) -#define WSAELOOP (WSABASEERR+62) -#define WSAENAMETOOLONG (WSABASEERR+63) -#define WSAEHOSTDOWN (WSABASEERR+64) -#define WSAEHOSTUNREACH (WSABASEERR+65) -#define WSAENOTEMPTY (WSABASEERR+66) -#define WSAEPROCLIM (WSABASEERR+67) -#define WSAEUSERS (WSABASEERR+68) -#define WSAEDQUOT (WSABASEERR+69) -#define WSAESTALE (WSABASEERR+70) -#define WSAEREMOTE (WSABASEERR+71) - -#define WSASYSNOTREADY (WSABASEERR+91) -#define WSAVERNOTSUPPORTED (WSABASEERR+92) -#define WSANOTINITIALISED (WSABASEERR+93) -#define WSAEDISCON (WSABASEERR+101) -#ifndef WSAHOST_NOT_FOUND -#define WSAHOST_NOT_FOUND (WSABASEERR+1001) -#endif -#ifndef WSATRY_AGAIN -#define WSATRY_AGAIN (WSABASEERR+1002) -#endif -#ifndef WSANO_RECOVERY -#define WSANO_RECOVERY (WSABASEERR+1003) -#endif -#ifndef WSANO_DATA -#define WSANO_DATA (WSABASEERR+1004) -#endif - -#define WSAENOMORE (WSABASEERR+102) -#define WSAECANCELLED (WSABASEERR+103) -#define WSAEINVALIDPROCTABLE (WSABASEERR+104) -#define WSAEINVALIDPROVIDER (WSABASEERR+105) -#define WSAEPROVIDERFAILEDINIT (WSABASEERR+106) -#define WSASYSCALLFAILURE (WSABASEERR+107) -#define WSASERVICE_NOT_FOUND (WSABASEERR+108) -#define WSATYPE_NOT_FOUND (WSABASEERR+109) -#define WSA_E_NO_MORE (WSABASEERR+110) -#define WSA_E_CANCELLED (WSABASEERR+111) -#define WSAEREFUSED (WSABASEERR+112) -#ifndef WSA_QOS_RECEIVERS -#define WSA_QOS_RECEIVERS (WSABASEERR + 1005) -#endif -#ifndef WSA_QOS_SENDERS -#define WSA_QOS_SENDERS (WSABASEERR + 1006) -#endif -#ifndef WSA_QOS_NO_SENDERS -#define WSA_QOS_NO_SENDERS (WSABASEERR + 1007) -#define WSA_QOS_NO_RECEIVERS (WSABASEERR + 1008) -#define WSA_QOS_REQUEST_CONFIRMED (WSABASEERR + 1009) -#define WSA_QOS_ADMISSION_FAILURE (WSABASEERR + 1010) -#define WSA_QOS_POLICY_FAILURE (WSABASEERR + 1011) -#define WSA_QOS_BAD_STYLE (WSABASEERR + 1012) -#define WSA_QOS_BAD_OBJECT (WSABASEERR + 1013) -#define WSA_QOS_TRAFFIC_CTRL_ERROR (WSABASEERR + 1014) -#define WSA_QOS_GENERIC_ERROR (WSABASEERR + 1015) -#define WSA_QOS_ESERVICETYPE (WSABASEERR + 1016) -#define WSA_QOS_EFLOWSPEC (WSABASEERR + 1017) -#define WSA_QOS_EPROVSPECBUF (WSABASEERR + 1018) -#endif -#ifndef WSA_QOS_EFILTERSTYLE -#define WSA_QOS_EFILTERSTYLE (WSABASEERR + 1019) -#endif -#ifndef WSA_QOS_EFILTERTYPE -#define WSA_QOS_EFILTERTYPE (WSABASEERR + 1020) -#endif -#ifndef WSA_QOS_EFILTERCOUNT -#define WSA_QOS_EFILTERCOUNT (WSABASEERR + 1021) -#endif -#ifndef WSA_QOS_EOBJLENGTH -#define WSA_QOS_EOBJLENGTH (WSABASEERR + 1022) -#endif -#ifndef WSA_QOS_EFLOWCOUNT -#define WSA_QOS_EFLOWCOUNT (WSABASEERR + 1023) -#endif -#ifndef WSA_QOS_EUNKNOWNPSOBJ -#define WSA_QOS_EUNKNOWNPSOBJ (WSABASEERR + 1024) -#endif -#ifndef WSA_QOS_EPOLICYOBJ -#define WSA_QOS_EPOLICYOBJ (WSABASEERR + 1025) -#endif -#ifndef WSA_QOS_EFLOWDESC -#define WSA_QOS_EFLOWDESC (WSABASEERR + 1026) -#endif -#ifndef WSA_QOS_EPSFLOWSPEC -#define WSA_QOS_EPSFLOWSPEC (WSABASEERR + 1027) -#endif -#ifndef WSA_QOS_EPSFILTERSPEC -#define WSA_QOS_EPSFILTERSPEC (WSABASEERR + 1028) -#endif -#ifndef WSA_QOS_ESDMODEOBJ -#define WSA_QOS_ESDMODEOBJ (WSABASEERR + 1029) -#endif -#ifndef WSA_QOS_ESHAPERATEOBJ -#define WSA_QOS_ESHAPERATEOBJ (WSABASEERR + 1030) -#endif -#ifndef WSA_QOS_RESERVED_PETYPE -#define WSA_QOS_RESERVED_PETYPE (WSABASEERR + 1031) -#endif -#endif // WSABASEERR - -#define h_errno WSAGetLastError() -#define HOST_NOT_FOUND WSAHOST_NOT_FOUND -#define TRY_AGAIN WSATRY_AGAIN -#define NO_RECOVERY WSANO_RECOVERY -#define NO_DATA WSANO_DATA - -#define WSANO_ADDRESS WSANO_DATA -#define NO_ADDRESS WSANO_ADDRESS - -#if 0 -#define EWOULDBLOCK WSAEWOULDBLOCK -#define EINPROGRESS WSAEINPROGRESS -#define EALREADY WSAEALREADY -#define ENOTSOCK WSAENOTSOCK -#define EDESTADDRREQ WSAEDESTADDRREQ -#define EMSGSIZE WSAEMSGSIZE -#define EPROTOTYPE WSAEPROTOTYPE -#define ENOPROTOOPT WSAENOPROTOOPT -#define EPROTONOSUPPORT WSAEPROTONOSUPPORT -#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT -#define EOPNOTSUPP WSAEOPNOTSUPP -#define EPFNOSUPPORT WSAEPFNOSUPPORT -#define EAFNOSUPPORT WSAEAFNOSUPPORT -#define EADDRINUSE WSAEADDRINUSE -#define EADDRNOTAVAIL WSAEADDRNOTAVAIL -#define ENETDOWN WSAENETDOWN -#define ENETUNREACH WSAENETUNREACH -#define ENETRESET WSAENETRESET -#define ECONNABORTED WSAECONNABORTED -#define ECONNRESET WSAECONNRESET -#define ENOBUFS WSAENOBUFS -#define EISCONN WSAEISCONN -#define ENOTCONN WSAENOTCONN -#define ESHUTDOWN WSAESHUTDOWN -#define ETOOMANYREFS WSAETOOMANYREFS -#define ETIMEDOUT WSAETIMEDOUT -#define ECONNREFUSED WSAECONNREFUSED -#define ELOOP WSAELOOP -#define ENAMETOOLONG WSAENAMETOOLONG -#define EHOSTDOWN WSAEHOSTDOWN -#define EHOSTUNREACH WSAEHOSTUNREACH -#define ENOTEMPTY WSAENOTEMPTY -#define EPROCLIM WSAEPROCLIM -#define EUSERS WSAEUSERS -#define EDQUOT WSAEDQUOT -#define ESTALE WSAESTALE -#define EREMOTE WSAEREMOTE -#endif - -#define WSAAPI WINAPI -#define WSAEVENT HANDLE -#define LPWSAEVENT LPHANDLE -#define WSAOVERLAPPED OVERLAPPED - typedef struct _OVERLAPPED *LPWSAOVERLAPPED; - -#define WSA_IO_PENDING (ERROR_IO_PENDING) -#define WSA_IO_INCOMPLETE (ERROR_IO_INCOMPLETE) -#define WSA_INVALID_HANDLE (ERROR_INVALID_HANDLE) -#define WSA_INVALID_PARAMETER (ERROR_INVALID_PARAMETER) -#define WSA_NOT_ENOUGH_MEMORY (ERROR_NOT_ENOUGH_MEMORY) -#define WSA_OPERATION_ABORTED (ERROR_OPERATION_ABORTED) - -#define WSA_INVALID_EVENT ((WSAEVENT)NULL) -#define WSA_MAXIMUM_WAIT_EVENTS (MAXIMUM_WAIT_OBJECTS) -#define WSA_WAIT_FAILED (WAIT_FAILED) -#define WSA_WAIT_EVENT_0 (WAIT_OBJECT_0) -#define WSA_WAIT_IO_COMPLETION (WAIT_IO_COMPLETION) -#define WSA_WAIT_TIMEOUT (WAIT_TIMEOUT) -#define WSA_INFINITE (INFINITE) - - typedef struct _WSABUF { - u_long len; - char *buf; - } WSABUF,*LPWSABUF; - -#include - - typedef struct _QualityOfService { - FLOWSPEC SendingFlowspec; - FLOWSPEC ReceivingFlowspec; - WSABUF ProviderSpecific; - } QOS,*LPQOS; - -#define CF_ACCEPT 0x0000 -#define CF_REJECT 0x0001 -#define CF_DEFER 0x0002 - -#define SD_RECEIVE 0x00 -#define SD_SEND 0x01 -#define SD_BOTH 0x02 - - typedef unsigned int GROUP; - -#define SG_UNCONSTRAINED_GROUP 0x01 -#define SG_CONSTRAINED_GROUP 0x02 - - typedef struct _WSANETWORKEVENTS { - long lNetworkEvents; - int iErrorCode[FD_MAX_EVENTS]; - } WSANETWORKEVENTS,*LPWSANETWORKEVENTS; - -#ifndef GUID_DEFINED -#include -#endif - -#define MAX_PROTOCOL_CHAIN 7 - -#define BASE_PROTOCOL 1 -#define LAYERED_PROTOCOL 0 - - typedef struct _WSAPROTOCOLCHAIN { - int ChainLen; - - DWORD ChainEntries[MAX_PROTOCOL_CHAIN]; - } WSAPROTOCOLCHAIN,*LPWSAPROTOCOLCHAIN; - -#define WSAPROTOCOL_LEN 255 - - typedef struct _WSAPROTOCOL_INFOA { - DWORD dwServiceFlags1; - DWORD dwServiceFlags2; - DWORD dwServiceFlags3; - DWORD dwServiceFlags4; - DWORD dwProviderFlags; - GUID ProviderId; - DWORD dwCatalogEntryId; - WSAPROTOCOLCHAIN ProtocolChain; - int iVersion; - int iAddressFamily; - int iMaxSockAddr; - int iMinSockAddr; - int iSocketType; - int iProtocol; - int iProtocolMaxOffset; - int iNetworkByteOrder; - int iSecurityScheme; - DWORD dwMessageSize; - DWORD dwProviderReserved; - CHAR szProtocol[WSAPROTOCOL_LEN+1]; - } WSAPROTOCOL_INFOA,*LPWSAPROTOCOL_INFOA; - typedef struct _WSAPROTOCOL_INFOW { - DWORD dwServiceFlags1; - DWORD dwServiceFlags2; - DWORD dwServiceFlags3; - DWORD dwServiceFlags4; - DWORD dwProviderFlags; - GUID ProviderId; - DWORD dwCatalogEntryId; - WSAPROTOCOLCHAIN ProtocolChain; - int iVersion; - int iAddressFamily; - int iMaxSockAddr; - int iMinSockAddr; - int iSocketType; - int iProtocol; - int iProtocolMaxOffset; - int iNetworkByteOrder; - int iSecurityScheme; - DWORD dwMessageSize; - DWORD dwProviderReserved; - WCHAR szProtocol[WSAPROTOCOL_LEN+1]; - } WSAPROTOCOL_INFOW,*LPWSAPROTOCOL_INFOW; -#ifdef UNICODE - typedef WSAPROTOCOL_INFOW WSAPROTOCOL_INFO; - typedef LPWSAPROTOCOL_INFOW LPWSAPROTOCOL_INFO; -#else - typedef WSAPROTOCOL_INFOA WSAPROTOCOL_INFO; - typedef LPWSAPROTOCOL_INFOA LPWSAPROTOCOL_INFO; -#endif - -#define PFL_MULTIPLE_PROTO_ENTRIES 0x00000001 -#define PFL_RECOMMENDED_PROTO_ENTRY 0x00000002 -#define PFL_HIDDEN 0x00000004 -#define PFL_MATCHES_PROTOCOL_ZERO 0x00000008 - -#define XP1_CONNECTIONLESS 0x00000001 -#define XP1_GUARANTEED_DELIVERY 0x00000002 -#define XP1_GUARANTEED_ORDER 0x00000004 -#define XP1_MESSAGE_ORIENTED 0x00000008 -#define XP1_PSEUDO_STREAM 0x00000010 -#define XP1_GRACEFUL_CLOSE 0x00000020 -#define XP1_EXPEDITED_DATA 0x00000040 -#define XP1_CONNECT_DATA 0x00000080 -#define XP1_DISCONNECT_DATA 0x00000100 -#define XP1_SUPPORT_BROADCAST 0x00000200 -#define XP1_SUPPORT_MULTIPOINT 0x00000400 -#define XP1_MULTIPOINT_CONTROL_PLANE 0x00000800 -#define XP1_MULTIPOINT_DATA_PLANE 0x00001000 -#define XP1_QOS_SUPPORTED 0x00002000 -#define XP1_INTERRUPT 0x00004000 -#define XP1_UNI_SEND 0x00008000 -#define XP1_UNI_RECV 0x00010000 -#define XP1_IFS_HANDLES 0x00020000 -#define XP1_PARTIAL_MESSAGE 0x00040000 - -#define BIGENDIAN 0x0000 -#define LITTLEENDIAN 0x0001 - -#define SECURITY_PROTOCOL_NONE 0x0000 - -#define JL_SENDER_ONLY 0x01 -#define JL_RECEIVER_ONLY 0x02 -#define JL_BOTH 0x04 - -#define WSA_FLAG_OVERLAPPED 0x01 -#define WSA_FLAG_MULTIPOINT_C_ROOT 0x02 -#define WSA_FLAG_MULTIPOINT_C_LEAF 0x04 -#define WSA_FLAG_MULTIPOINT_D_ROOT 0x08 -#define WSA_FLAG_MULTIPOINT_D_LEAF 0x10 - -#define IOC_UNIX 0x00000000 -#define IOC_WS2 0x08000000 -#define IOC_PROTOCOL 0x10000000 -#define IOC_VENDOR 0x18000000 - -#define _WSAIO(x,y) (IOC_VOID|(x)|(y)) -#define _WSAIOR(x,y) (IOC_OUT|(x)|(y)) -#define _WSAIOW(x,y) (IOC_IN|(x)|(y)) -#define _WSAIORW(x,y) (IOC_INOUT|(x)|(y)) - -#define SIO_ASSOCIATE_HANDLE _WSAIOW(IOC_WS2,1) -#define SIO_ENABLE_CIRCULAR_QUEUEING _WSAIO(IOC_WS2,2) -#define SIO_FIND_ROUTE _WSAIOR(IOC_WS2,3) -#define SIO_FLUSH _WSAIO(IOC_WS2,4) -#define SIO_GET_BROADCAST_ADDRESS _WSAIOR(IOC_WS2,5) -#define SIO_GET_EXTENSION_FUNCTION_POINTER _WSAIORW(IOC_WS2,6) -#define SIO_GET_QOS _WSAIORW(IOC_WS2,7) -#define SIO_GET_GROUP_QOS _WSAIORW(IOC_WS2,8) -#define SIO_MULTIPOINT_LOOPBACK _WSAIOW(IOC_WS2,9) -#define SIO_MULTICAST_SCOPE _WSAIOW(IOC_WS2,10) -#define SIO_SET_QOS _WSAIOW(IOC_WS2,11) -#define SIO_SET_GROUP_QOS _WSAIOW(IOC_WS2,12) -#define SIO_TRANSLATE_HANDLE _WSAIORW(IOC_WS2,13) -#define SIO_ROUTING_INTERFACE_QUERY _WSAIORW(IOC_WS2,20) -#define SIO_ROUTING_INTERFACE_CHANGE _WSAIOW(IOC_WS2,21) -#define SIO_ADDRESS_LIST_QUERY _WSAIOR(IOC_WS2,22) -#define SIO_ADDRESS_LIST_CHANGE _WSAIO(IOC_WS2,23) -#define SIO_QUERY_TARGET_PNP_HANDLE _WSAIOR(IOC_WS2,24) -#define SIO_ADDRESS_LIST_SORT _WSAIORW(IOC_WS2,25) - - typedef int (CALLBACK *LPCONDITIONPROC)(LPWSABUF lpCallerId,LPWSABUF lpCallerData,LPQOS lpSQOS,LPQOS lpGQOS,LPWSABUF lpCalleeId,LPWSABUF lpCalleeData,GROUP *g,DWORD_PTR dwCallbackData); - typedef void (CALLBACK *LPWSAOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwError,DWORD cbTransferred,LPWSAOVERLAPPED lpOverlapped,DWORD dwFlags); - -#define SIO_NSP_NOTIFY_CHANGE _WSAIOW(IOC_WS2,25) - - typedef enum _WSACOMPLETIONTYPE { - NSP_NOTIFY_IMMEDIATELY = 0,NSP_NOTIFY_HWND,NSP_NOTIFY_EVENT,NSP_NOTIFY_PORT,NSP_NOTIFY_APC - } WSACOMPLETIONTYPE,*PWSACOMPLETIONTYPE,*LPWSACOMPLETIONTYPE; - - typedef struct _WSACOMPLETION { - WSACOMPLETIONTYPE Type; - union { - struct { - HWND hWnd; - UINT uMsg; - WPARAM context; - } WindowMessage; - struct { - LPWSAOVERLAPPED lpOverlapped; - } Event; - struct { - LPWSAOVERLAPPED lpOverlapped; - LPWSAOVERLAPPED_COMPLETION_ROUTINE lpfnCompletionProc; - } Apc; - struct { - LPWSAOVERLAPPED lpOverlapped; - HANDLE hPort; - ULONG_PTR Key; - } Port; - } Parameters; - } WSACOMPLETION,*PWSACOMPLETION,*LPWSACOMPLETION; - -#define TH_NETDEV 0x00000001 -#define TH_TAPI 0x00000002 - - typedef struct sockaddr SOCKADDR; - typedef struct sockaddr *PSOCKADDR; - typedef struct sockaddr *LPSOCKADDR; - typedef struct sockaddr_storage SOCKADDR_STORAGE; - typedef struct sockaddr_storage *PSOCKADDR_STORAGE; - typedef struct sockaddr_storage *LPSOCKADDR_STORAGE; - -#ifndef _tagBLOB_DEFINED -#define _tagBLOB_DEFINED -#define _BLOB_DEFINED -#define _LPBLOB_DEFINED - typedef struct _BLOB { - ULONG cbSize; - BYTE *pBlobData; - } BLOB,*LPBLOB; -#endif - -#define SERVICE_MULTIPLE (0x00000001) - -#define NS_ALL (0) - -#define NS_SAP (1) -#define NS_NDS (2) -#define NS_PEER_BROWSE (3) -#define NS_SLP (5) -#define NS_DHCP (6) - -#define NS_TCPIP_LOCAL (10) -#define NS_TCPIP_HOSTS (11) -#define NS_DNS (12) -#define NS_NETBT (13) -#define NS_WINS (14) -#define NS_NLA (15) - -#define NS_NBP (20) - -#define NS_MS (30) -#define NS_STDA (31) -#define NS_NTDS (32) - -#define NS_X500 (40) -#define NS_NIS (41) -#define NS_NISPLUS (42) - -#define NS_WRQ (50) - -#define NS_NETDES (60) - -#define RES_UNUSED_1 (0x00000001) -#define RES_FLUSH_CACHE (0x00000002) -#ifndef RES_SERVICE -#define RES_SERVICE (0x00000004) -#endif - -#define SERVICE_TYPE_VALUE_IPXPORTA "IpxSocket" -#define SERVICE_TYPE_VALUE_IPXPORTW L"IpxSocket" -#define SERVICE_TYPE_VALUE_SAPIDA "SapId" -#define SERVICE_TYPE_VALUE_SAPIDW L"SapId" - -#define SERVICE_TYPE_VALUE_TCPPORTA "TcpPort" -#define SERVICE_TYPE_VALUE_TCPPORTW L"TcpPort" - -#define SERVICE_TYPE_VALUE_UDPPORTA "UdpPort" -#define SERVICE_TYPE_VALUE_UDPPORTW L"UdpPort" - -#define SERVICE_TYPE_VALUE_OBJECTIDA "ObjectId" -#define SERVICE_TYPE_VALUE_OBJECTIDW L"ObjectId" - -#ifdef UNICODE - -#define SERVICE_TYPE_VALUE_SAPID SERVICE_TYPE_VALUE_SAPIDW -#define SERVICE_TYPE_VALUE_TCPPORT SERVICE_TYPE_VALUE_TCPPORTW -#define SERVICE_TYPE_VALUE_UDPPORT SERVICE_TYPE_VALUE_UDPPORTW -#define SERVICE_TYPE_VALUE_OBJECTID SERVICE_TYPE_VALUE_OBJECTIDW -#else - -#define SERVICE_TYPE_VALUE_SAPID SERVICE_TYPE_VALUE_SAPIDA -#define SERVICE_TYPE_VALUE_TCPPORT SERVICE_TYPE_VALUE_TCPPORTA -#define SERVICE_TYPE_VALUE_UDPPORT SERVICE_TYPE_VALUE_UDPPORTA -#define SERVICE_TYPE_VALUE_OBJECTID SERVICE_TYPE_VALUE_OBJECTIDA -#endif - -#ifndef __CSADDR_DEFINED__ -#define __CSADDR_DEFINED__ - - typedef struct _SOCKET_ADDRESS { - LPSOCKADDR lpSockaddr; - INT iSockaddrLength; - } SOCKET_ADDRESS,*PSOCKET_ADDRESS,*LPSOCKET_ADDRESS; - - typedef struct _CSADDR_INFO { - SOCKET_ADDRESS LocalAddr; - SOCKET_ADDRESS RemoteAddr; - INT iSocketType; - INT iProtocol; - } CSADDR_INFO,*PCSADDR_INFO,*LPCSADDR_INFO; -#endif - - typedef struct _SOCKET_ADDRESS_LIST { - INT iAddressCount; - SOCKET_ADDRESS Address[1]; - } SOCKET_ADDRESS_LIST,*LPSOCKET_ADDRESS_LIST; - - typedef struct _AFPROTOCOLS { - INT iAddressFamily; - INT iProtocol; - } AFPROTOCOLS,*PAFPROTOCOLS,*LPAFPROTOCOLS; - - typedef enum _WSAEcomparator { - COMP_EQUAL = 0,COMP_NOTLESS - } WSAECOMPARATOR,*PWSAECOMPARATOR,*LPWSAECOMPARATOR; - - typedef struct _WSAVersion { - DWORD dwVersion; - WSAECOMPARATOR ecHow; - } WSAVERSION,*PWSAVERSION,*LPWSAVERSION; - - typedef struct _WSAQuerySetA { - DWORD dwSize; - LPSTR lpszServiceInstanceName; - LPGUID lpServiceClassId; - LPWSAVERSION lpVersion; - LPSTR lpszComment; - DWORD dwNameSpace; - LPGUID lpNSProviderId; - LPSTR lpszContext; - DWORD dwNumberOfProtocols; - LPAFPROTOCOLS lpafpProtocols; - LPSTR lpszQueryString; - DWORD dwNumberOfCsAddrs; - LPCSADDR_INFO lpcsaBuffer; - DWORD dwOutputFlags; - LPBLOB lpBlob; - } WSAQUERYSETA,*PWSAQUERYSETA,*LPWSAQUERYSETA; - - typedef struct _WSAQuerySetW { - DWORD dwSize; - LPWSTR lpszServiceInstanceName; - LPGUID lpServiceClassId; - LPWSAVERSION lpVersion; - LPWSTR lpszComment; - DWORD dwNameSpace; - LPGUID lpNSProviderId; - LPWSTR lpszContext; - DWORD dwNumberOfProtocols; - LPAFPROTOCOLS lpafpProtocols; - LPWSTR lpszQueryString; - DWORD dwNumberOfCsAddrs; - LPCSADDR_INFO lpcsaBuffer; - DWORD dwOutputFlags; - LPBLOB lpBlob; - } WSAQUERYSETW,*PWSAQUERYSETW,*LPWSAQUERYSETW; - -#ifdef UNICODE - typedef WSAQUERYSETW WSAQUERYSET; - typedef PWSAQUERYSETW PWSAQUERYSET; - typedef LPWSAQUERYSETW LPWSAQUERYSET; -#else - typedef WSAQUERYSETA WSAQUERYSET; - typedef PWSAQUERYSETA PWSAQUERYSET; - typedef LPWSAQUERYSETA LPWSAQUERYSET; -#endif - -#define LUP_DEEP 0x0001 -#define LUP_CONTAINERS 0x0002 -#define LUP_NOCONTAINERS 0x0004 -#define LUP_NEAREST 0x0008 -#define LUP_RETURN_NAME 0x0010 -#define LUP_RETURN_TYPE 0x0020 -#define LUP_RETURN_VERSION 0x0040 -#define LUP_RETURN_COMMENT 0x0080 -#define LUP_RETURN_ADDR 0x0100 -#define LUP_RETURN_BLOB 0x0200 -#define LUP_RETURN_ALIASES 0x0400 -#define LUP_RETURN_QUERY_STRING 0x0800 -#define LUP_RETURN_ALL 0x0FF0 -#define LUP_RES_SERVICE 0x8000 - -#define LUP_FLUSHCACHE 0x1000 -#define LUP_FLUSHPREVIOUS 0x2000 - -#define RESULT_IS_ALIAS 0x0001 -#define RESULT_IS_ADDED 0x0010 -#define RESULT_IS_CHANGED 0x0020 -#define RESULT_IS_DELETED 0x0040 - - typedef enum _WSAESETSERVICEOP { - RNRSERVICE_REGISTER=0,RNRSERVICE_DEREGISTER,RNRSERVICE_DELETE - } WSAESETSERVICEOP,*PWSAESETSERVICEOP,*LPWSAESETSERVICEOP; - - typedef struct _WSANSClassInfoA { - LPSTR lpszName; - DWORD dwNameSpace; - DWORD dwValueType; - DWORD dwValueSize; - LPVOID lpValue; - } WSANSCLASSINFOA,*PWSANSCLASSINFOA,*LPWSANSCLASSINFOA; - - typedef struct _WSANSClassInfoW { - LPWSTR lpszName; - DWORD dwNameSpace; - DWORD dwValueType; - DWORD dwValueSize; - LPVOID lpValue; - } WSANSCLASSINFOW,*PWSANSCLASSINFOW,*LPWSANSCLASSINFOW; - -#ifdef UNICODE - typedef WSANSCLASSINFOW WSANSCLASSINFO; - typedef PWSANSCLASSINFOW PWSANSCLASSINFO; - typedef LPWSANSCLASSINFOW LPWSANSCLASSINFO; -#else - typedef WSANSCLASSINFOA WSANSCLASSINFO; - typedef PWSANSCLASSINFOA PWSANSCLASSINFO; - typedef LPWSANSCLASSINFOA LPWSANSCLASSINFO; -#endif - - typedef struct _WSAServiceClassInfoA { - LPGUID lpServiceClassId; - LPSTR lpszServiceClassName; - DWORD dwCount; - LPWSANSCLASSINFOA lpClassInfos; - } WSASERVICECLASSINFOA,*PWSASERVICECLASSINFOA,*LPWSASERVICECLASSINFOA; - - typedef struct _WSAServiceClassInfoW { - LPGUID lpServiceClassId; - LPWSTR lpszServiceClassName; - DWORD dwCount; - LPWSANSCLASSINFOW lpClassInfos; - } WSASERVICECLASSINFOW,*PWSASERVICECLASSINFOW,*LPWSASERVICECLASSINFOW; - -#ifdef UNICODE - typedef WSASERVICECLASSINFOW WSASERVICECLASSINFO; - typedef PWSASERVICECLASSINFOW PWSASERVICECLASSINFO; - typedef LPWSASERVICECLASSINFOW LPWSASERVICECLASSINFO; -#else - typedef WSASERVICECLASSINFOA WSASERVICECLASSINFO; - typedef PWSASERVICECLASSINFOA PWSASERVICECLASSINFO; - typedef LPWSASERVICECLASSINFOA LPWSASERVICECLASSINFO; -#endif - - typedef struct _WSANAMESPACE_INFOA { - GUID NSProviderId; - DWORD dwNameSpace; - WINBOOL fActive; - DWORD dwVersion; - LPSTR lpszIdentifier; - } WSANAMESPACE_INFOA,*PWSANAMESPACE_INFOA,*LPWSANAMESPACE_INFOA; - - typedef struct _WSANAMESPACE_INFOW { - GUID NSProviderId; - DWORD dwNameSpace; - WINBOOL fActive; - DWORD dwVersion; - LPWSTR lpszIdentifier; - } WSANAMESPACE_INFOW,*PWSANAMESPACE_INFOW,*LPWSANAMESPACE_INFOW; - -#ifdef UNICODE - typedef WSANAMESPACE_INFOW WSANAMESPACE_INFO; - typedef PWSANAMESPACE_INFOW PWSANAMESPACE_INFO; - typedef LPWSANAMESPACE_INFOW LPWSANAMESPACE_INFO; -#else - typedef WSANAMESPACE_INFOA WSANAMESPACE_INFO; - typedef PWSANAMESPACE_INFOA PWSANAMESPACE_INFO; - typedef LPWSANAMESPACE_INFOA LPWSANAMESPACE_INFO; -#endif - -#if INCL_WINSOCK_API_TYPEDEFS -#ifdef UNICODE -#define LPFN_WSADUPLICATESOCKET LPFN_WSADUPLICATESOCKETW -#define LPFN_WSAENUMPROTOCOLS LPFN_WSAENUMPROTOCOLSW -#define LPFN_WSASOCKET LPFN_WSASOCKETW -#define LPFN_WSAADDRESSTOSTRING LPFN_WSAADDRESSTOSTRINGW -#define LPFN_WSASTRINGTOADDRESS LPFN_WSASTRINGTOADDRESSW -#define LPFN_WSALOOKUPSERVICEBEGIN LPFN_WSALOOKUPSERVICEBEGINW -#define LPFN_WSALOOKUPSERVICENEXT LPFN_WSALOOKUPSERVICENEXTW -#define LPFN_WSAINSTALLSERVICECLASS LPFN_WSAINSTALLSERVICECLASSW -#define LPFN_WSAGETSERVICECLASSINFO LPFN_WSAGETSERVICECLASSINFOW -#define LPFN_WSAENUMNAMESPACEPROVIDERS LPFN_WSAENUMNAMESPACEPROVIDERSW -#define LPFN_WSAGETSERVICECLASSNAMEBYCLASSID LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDW -#define LPFN_WSASETSERVICE LPFN_WSASETSERVICEW -#else -#define LPFN_WSADUPLICATESOCKET LPFN_WSADUPLICATESOCKETA -#define LPFN_WSAENUMPROTOCOLS LPFN_WSAENUMPROTOCOLSA -#define LPFN_WSASOCKET LPFN_WSASOCKETA -#define LPFN_WSAADDRESSTOSTRING LPFN_WSAADDRESSTOSTRINGA -#define LPFN_WSASTRINGTOADDRESS LPFN_WSASTRINGTOADDRESSA -#define LPFN_WSALOOKUPSERVICEBEGIN LPFN_WSALOOKUPSERVICEBEGINA -#define LPFN_WSALOOKUPSERVICENEXT LPFN_WSALOOKUPSERVICENEXTA -#define LPFN_WSAINSTALLSERVICECLASS LPFN_WSAINSTALLSERVICECLASSA -#define LPFN_WSAGETSERVICECLASSINFO LPFN_WSAGETSERVICECLASSINFOA -#define LPFN_WSAENUMNAMESPACEPROVIDERS LPFN_WSAENUMNAMESPACEPROVIDERSA -#define LPFN_WSAGETSERVICECLASSNAMEBYCLASSID LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDA -#define LPFN_WSASETSERVICE LPFN_WSASETSERVICEA -#endif - - typedef SOCKET (WSAAPI *LPFN_ACCEPT)(SOCKET s,struct sockaddr *addr,int *addrlen); - typedef int (WSAAPI *LPFN_BIND)(SOCKET s,const struct sockaddr *name,int namelen); - typedef int (WSAAPI *LPFN_CLOSESOCKET)(SOCKET s); - typedef int (WSAAPI *LPFN_CONNECT)(SOCKET s,const struct sockaddr *name,int namelen); - typedef int (WSAAPI *LPFN_IOCTLSOCKET)(SOCKET s,long cmd,u_long *argp); - typedef int (WSAAPI *LPFN_GETPEERNAME)(SOCKET s,struct sockaddr *name,int *namelen); - typedef int (WSAAPI *LPFN_GETSOCKNAME)(SOCKET s,struct sockaddr *name,int *namelen); - typedef int (WSAAPI *LPFN_GETSOCKOPT)(SOCKET s,int level,int optname,char *optval,int *optlen); - typedef u_long (WSAAPI *LPFN_HTONL)(u_long hostlong); - typedef u_short (WSAAPI *LPFN_HTONS)(u_short hostshort); - typedef unsigned long (WSAAPI *LPFN_INET_ADDR)(const char *cp); - typedef char *(WSAAPI *LPFN_INET_NTOA)(struct in_addr in); - typedef int (WSAAPI *LPFN_LISTEN)(SOCKET s,int backlog); - typedef u_long (WSAAPI *LPFN_NTOHL)(u_long netlong); - typedef u_short (WSAAPI *LPFN_NTOHS)(u_short netshort); - typedef int (WSAAPI *LPFN_RECV)(SOCKET s,char *buf,int len,int flags); - typedef int (WSAAPI *LPFN_RECVFROM)(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen); - typedef int (WSAAPI *LPFN_SELECT)(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout); - typedef int (WSAAPI *LPFN_SEND)(SOCKET s,const char *buf,int len,int flags); - typedef int (WSAAPI *LPFN_SENDTO)(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen); - typedef int (WSAAPI *LPFN_SETSOCKOPT)(SOCKET s,int level,int optname,const char *optval,int optlen); - typedef int (WSAAPI *LPFN_SHUTDOWN)(SOCKET s,int how); - typedef SOCKET (WSAAPI *LPFN_SOCKET)(int af,int type,int protocol); - typedef struct hostent *(WSAAPI *LPFN_GETHOSTBYADDR)(const char *addr,int len,int type); - typedef struct hostent *(WSAAPI *LPFN_GETHOSTBYNAME)(const char *name); - typedef int (WSAAPI *LPFN_GETHOSTNAME)(char *name,int namelen); - typedef struct servent *(WSAAPI *LPFN_GETSERVBYPORT)(int port,const char *proto); - typedef struct servent *(WSAAPI *LPFN_GETSERVBYNAME)(const char *name,const char *proto); - typedef struct protoent *(WSAAPI *LPFN_GETPROTOBYNUMBER)(int number); - typedef struct protoent *(WSAAPI *LPFN_GETPROTOBYNAME)(const char *name); - typedef int (WSAAPI *LPFN_WSASTARTUP)(WORD wVersionRequested,LPWSADATA lpWSAData); - typedef int (WSAAPI *LPFN_WSACLEANUP)(void); - typedef void (WSAAPI *LPFN_WSASETLASTERROR)(int iError); - typedef int (WSAAPI *LPFN_WSAGETLASTERROR)(void); - typedef WINBOOL (WSAAPI *LPFN_WSAISBLOCKING)(void); - typedef int (WSAAPI *LPFN_WSAUNHOOKBLOCKINGHOOK)(void); - typedef FARPROC (WSAAPI *LPFN_WSASETBLOCKINGHOOK)(FARPROC lpBlockFunc); - typedef int (WSAAPI *LPFN_WSACANCELBLOCKINGCALL)(void); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETSERVBYNAME)(HWND hWnd,u_int wMsg,const char *name,const char *proto,char *buf,int buflen); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETSERVBYPORT)(HWND hWnd,u_int wMsg,int port,const char *proto,char *buf,int buflen); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETPROTOBYNAME)(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETPROTOBYNUMBER)(HWND hWnd,u_int wMsg,int number,char *buf,int buflen); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETHOSTBYNAME)(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); - typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETHOSTBYADDR)(HWND hWnd,u_int wMsg,const char *addr,int len,int type,char *buf,int buflen); - typedef int (WSAAPI *LPFN_WSACANCELASYNCREQUEST)(HANDLE hAsyncTaskHandle); - typedef int (WSAAPI *LPFN_WSAASYNCSELECT)(SOCKET s,HWND hWnd,u_int wMsg,long lEvent); - typedef SOCKET (WSAAPI *LPFN_WSAACCEPT)(SOCKET s,struct sockaddr *addr,LPINT addrlen,LPCONDITIONPROC lpfnCondition,DWORD_PTR dwCallbackData); - typedef WINBOOL (WSAAPI *LPFN_WSACLOSEEVENT)(WSAEVENT hEvent); - typedef int (WSAAPI *LPFN_WSACONNECT)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS); - typedef WSAEVENT (WSAAPI *LPFN_WSACREATEEVENT)(void); - typedef int (WSAAPI *LPFN_WSADUPLICATESOCKETA)(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOA lpProtocolInfo); - typedef int (WSAAPI *LPFN_WSADUPLICATESOCKETW)(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOW lpProtocolInfo); - typedef int (WSAAPI *LPFN_WSAENUMNETWORKEVENTS)(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents); - typedef int (WSAAPI *LPFN_WSAENUMPROTOCOLSA)(LPINT lpiProtocols,LPWSAPROTOCOL_INFOA lpProtocolBuffer,LPDWORD lpdwBufferLength); - typedef int (WSAAPI *LPFN_WSAENUMPROTOCOLSW)(LPINT lpiProtocols,LPWSAPROTOCOL_INFOW lpProtocolBuffer,LPDWORD lpdwBufferLength); - typedef int (WSAAPI *LPFN_WSAEVENTSELECT)(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents); - typedef WINBOOL (WSAAPI *LPFN_WSAGETOVERLAPPEDRESULT)(SOCKET s,LPWSAOVERLAPPED lpOverlapped,LPDWORD lpcbTransfer,WINBOOL fWait,LPDWORD lpdwFlags); - typedef WINBOOL (WSAAPI *LPFN_WSAGETQOSBYNAME)(SOCKET s,LPWSABUF lpQOSName,LPQOS lpQOS); - typedef int (WSAAPI *LPFN_WSAHTONL)(SOCKET s,u_long hostlong,u_long *lpnetlong); - typedef int (WSAAPI *LPFN_WSAHTONS)(SOCKET s,u_short hostshort,u_short *lpnetshort); - typedef int (WSAAPI *LPFN_WSAIOCTL)(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - typedef SOCKET (WSAAPI *LPFN_WSAJOINLEAF)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,DWORD dwFlags); - typedef int (WSAAPI *LPFN_WSANTOHL)(SOCKET s,u_long netlong,u_long *lphostlong); - typedef int (WSAAPI *LPFN_WSANTOHS)(SOCKET s,u_short netshort,u_short *lphostshort); - typedef int (WSAAPI *LPFN_WSARECV)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - typedef int (WSAAPI *LPFN_WSARECVDISCONNECT)(SOCKET s,LPWSABUF lpInboundDisconnectData); - typedef int (WSAAPI *LPFN_WSARECVFROM)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,struct sockaddr *lpFrom,LPINT lpFromlen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - typedef WINBOOL (WSAAPI *LPFN_WSARESETEVENT)(WSAEVENT hEvent); - typedef int (WSAAPI *LPFN_WSASEND)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - typedef int (WSAAPI *LPFN_WSASENDDISCONNECT)(SOCKET s,LPWSABUF lpOutboundDisconnectData); - typedef int (WSAAPI *LPFN_WSASENDTO)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,const struct sockaddr *lpTo,int iTolen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - typedef WINBOOL (WSAAPI *LPFN_WSASETEVENT)(WSAEVENT hEvent); - typedef SOCKET (WSAAPI *LPFN_WSASOCKETA)(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags); - typedef SOCKET (WSAAPI *LPFN_WSASOCKETW)(int af,int type,int protocol,LPWSAPROTOCOL_INFOW lpProtocolInfo,GROUP g,DWORD dwFlags); - typedef DWORD (WSAAPI *LPFN_WSAWAITFORMULTIPLEEVENTS)(DWORD cEvents,const WSAEVENT *lphEvents,WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable); - typedef INT (WSAAPI *LPFN_WSAADDRESSTOSTRINGA)(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSTR lpszAddressString,LPDWORD lpdwAddressStringLength); - typedef INT (WSAAPI *LPFN_WSAADDRESSTOSTRINGW)(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPWSTR lpszAddressString,LPDWORD lpdwAddressStringLength); - typedef INT (WSAAPI *LPFN_WSASTRINGTOADDRESSA)(LPSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); - typedef INT (WSAAPI *LPFN_WSASTRINGTOADDRESSW)(LPWSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); - typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEBEGINA)(LPWSAQUERYSETA lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); - typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEBEGINW)(LPWSAQUERYSETW lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); - typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICENEXTA)(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETA lpqsResults); - typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICENEXTW)(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETW lpqsResults); - typedef INT (WSAAPI *LPFN_WSANSPIOCTL)(HANDLE hLookup,DWORD dwControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSACOMPLETION lpCompletion); - typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEEND)(HANDLE hLookup); - typedef INT (WSAAPI *LPFN_WSAINSTALLSERVICECLASSA)(LPWSASERVICECLASSINFOA lpServiceClassInfo); - typedef INT (WSAAPI *LPFN_WSAINSTALLSERVICECLASSW)(LPWSASERVICECLASSINFOW lpServiceClassInfo); - typedef INT (WSAAPI *LPFN_WSAREMOVESERVICECLASS)(LPGUID lpServiceClassId); - typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSINFOA)(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOA lpServiceClassInfo); - typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSINFOW)(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOW lpServiceClassInfo); - typedef INT (WSAAPI *LPFN_WSAENUMNAMESPACEPROVIDERSA)(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOA lpnspBuffer); - typedef INT (WSAAPI *LPFN_WSAENUMNAMESPACEPROVIDERSW)(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOW lpnspBuffer); - typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDA)(LPGUID lpServiceClassId,LPSTR lpszServiceClassName,LPDWORD lpdwBufferLength); - typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDW)(LPGUID lpServiceClassId,LPWSTR lpszServiceClassName,LPDWORD lpdwBufferLength); - typedef INT (WSAAPI *LPFN_WSASETSERVICEA)(LPWSAQUERYSETA lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); - typedef INT (WSAAPI *LPFN_WSASETSERVICEW)(LPWSAQUERYSETW lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); - typedef INT (WSAAPI *LPFN_WSAPROVIDERCONFIGCHANGE)(LPHANDLE lpNotificationHandle,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); -#endif - -#ifdef UNICODE -#define WSADuplicateSocket WSADuplicateSocketW -#define WSAEnumProtocols WSAEnumProtocolsW -#define WSAAddressToString WSAAddressToStringW -#define WSASocket WSASocketW -#define WSAStringToAddress WSAStringToAddressW -#define WSALookupServiceBegin WSALookupServiceBeginW -#define WSALookupServiceNext WSALookupServiceNextW -#define WSAInstallServiceClass WSAInstallServiceClassW -#define WSAGetServiceClassInfo WSAGetServiceClassInfoW -#define WSAEnumNameSpaceProviders WSAEnumNameSpaceProvidersW -#define WSAGetServiceClassNameByClassId WSAGetServiceClassNameByClassIdW -#define WSASetService WSASetServiceW -#else -#define WSADuplicateSocket WSADuplicateSocketA -#define WSAEnumProtocols WSAEnumProtocolsA -#define WSASocket WSASocketA -#define WSAAddressToString WSAAddressToStringA -#define WSAStringToAddress WSAStringToAddressA -#define WSALookupServiceBegin WSALookupServiceBeginA -#define WSALookupServiceNext WSALookupServiceNextA -#define WSAInstallServiceClass WSAInstallServiceClassA -#define WSAGetServiceClassInfo WSAGetServiceClassInfoA -#define WSAEnumNameSpaceProviders WSAEnumNameSpaceProvidersA -#define WSAGetServiceClassNameByClassId WSAGetServiceClassNameByClassIdA -#define WSASetService WSASetServiceA -#endif - - WINSOCK_API_LINKAGE SOCKET WSAAPI accept(SOCKET s,struct sockaddr *addr,int *addrlen); - WINSOCK_API_LINKAGE int WSAAPI bind(SOCKET s,const struct sockaddr *name,int namelen); - WINSOCK_API_LINKAGE int WSAAPI closesocket(SOCKET s); - WINSOCK_API_LINKAGE int WSAAPI connect(SOCKET s,const struct sockaddr *name,int namelen); - WINSOCK_API_LINKAGE int WSAAPI ioctlsocket(SOCKET s,long cmd,u_long *argp); - WINSOCK_API_LINKAGE int WSAAPI getpeername(SOCKET s,struct sockaddr *name,int *namelen); - WINSOCK_API_LINKAGE int WSAAPI getsockname(SOCKET s,struct sockaddr *name,int *namelen); - WINSOCK_API_LINKAGE int WSAAPI getsockopt(SOCKET s,int level,int optname,char *optval,int *optlen); - WINSOCK_API_LINKAGE u_long WSAAPI htonl(u_long hostlong); - WINSOCK_API_LINKAGE u_short WSAAPI htons(u_short hostshort); - WINSOCK_API_LINKAGE unsigned long WSAAPI inet_addr(const char *cp); - WINSOCK_API_LINKAGE char *WSAAPI inet_ntoa(struct in_addr in); - WINSOCK_API_LINKAGE int WSAAPI listen(SOCKET s,int backlog); - WINSOCK_API_LINKAGE u_long WSAAPI ntohl(u_long netlong); - WINSOCK_API_LINKAGE u_short WSAAPI ntohs(u_short netshort); - WINSOCK_API_LINKAGE int WSAAPI recv(SOCKET s,char *buf,int len,int flags); - WINSOCK_API_LINKAGE int WSAAPI recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen); - WINSOCK_API_LINKAGE int WSAAPI select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout); - WINSOCK_API_LINKAGE int WSAAPI send(SOCKET s,const char *buf,int len,int flags); - WINSOCK_API_LINKAGE int WSAAPI sendto(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen); - WINSOCK_API_LINKAGE int WSAAPI setsockopt(SOCKET s,int level,int optname,const char *optval,int optlen); - WINSOCK_API_LINKAGE int WSAAPI shutdown(SOCKET s,int how); - WINSOCK_API_LINKAGE SOCKET WSAAPI socket(int af,int type,int protocol); - WINSOCK_API_LINKAGE struct hostent *WSAAPI gethostbyaddr(const char *addr,int len,int type); - WINSOCK_API_LINKAGE struct hostent *WSAAPI gethostbyname(const char *name); - WINSOCK_API_LINKAGE int WSAAPI gethostname(char *name,int namelen); - WINSOCK_API_LINKAGE struct servent *WSAAPI getservbyport(int port,const char *proto); - WINSOCK_API_LINKAGE struct servent *WSAAPI getservbyname(const char *name,const char *proto); - WINSOCK_API_LINKAGE struct protoent *WSAAPI getprotobynumber(int number); - WINSOCK_API_LINKAGE struct protoent *WSAAPI getprotobyname(const char *name); - WINSOCK_API_LINKAGE int WSAAPI WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData); - WINSOCK_API_LINKAGE int WSAAPI WSACleanup(void); - WINSOCK_API_LINKAGE void WSAAPI WSASetLastError(int iError); - WINSOCK_API_LINKAGE int WSAAPI WSAGetLastError(void); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAIsBlocking(void); - WINSOCK_API_LINKAGE int WSAAPI WSAUnhookBlockingHook(void); - WINSOCK_API_LINKAGE FARPROC WSAAPI WSASetBlockingHook(FARPROC lpBlockFunc); - WINSOCK_API_LINKAGE int WSAAPI WSACancelBlockingCall(void); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetServByName(HWND hWnd,u_int wMsg,const char *name,const char *proto,char *buf,int buflen); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetServByPort(HWND hWnd,u_int wMsg,int port,const char *proto,char *buf,int buflen); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetProtoByName(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetProtoByNumber(HWND hWnd,u_int wMsg,int number,char *buf,int buflen); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetHostByName(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); - WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetHostByAddr(HWND hWnd,u_int wMsg,const char *addr,int len,int type,char *buf,int buflen); - WINSOCK_API_LINKAGE int WSAAPI WSACancelAsyncRequest(HANDLE hAsyncTaskHandle); - WINSOCK_API_LINKAGE int WSAAPI WSAAsyncSelect(SOCKET s,HWND hWnd,u_int wMsg,long lEvent); - WINSOCK_API_LINKAGE SOCKET WSAAPI WSAAccept(SOCKET s,struct sockaddr *addr,LPINT addrlen,LPCONDITIONPROC lpfnCondition,DWORD_PTR dwCallbackData); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSACloseEvent(WSAEVENT hEvent); - WINSOCK_API_LINKAGE int WSAAPI WSAConnect(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS); - WINSOCK_API_LINKAGE WSAEVENT WSAAPI WSACreateEvent(void); - WINSOCK_API_LINKAGE int WSAAPI WSADuplicateSocketA(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOA lpProtocolInfo); - WINSOCK_API_LINKAGE int WSAAPI WSADuplicateSocketW(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOW lpProtocolInfo); - WINSOCK_API_LINKAGE int WSAAPI WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents); - WINSOCK_API_LINKAGE int WSAAPI WSAEnumProtocolsA(LPINT lpiProtocols,LPWSAPROTOCOL_INFOA lpProtocolBuffer,LPDWORD lpdwBufferLength); - WINSOCK_API_LINKAGE int WSAAPI WSAEnumProtocolsW(LPINT lpiProtocols,LPWSAPROTOCOL_INFOW lpProtocolBuffer,LPDWORD lpdwBufferLength); - WINSOCK_API_LINKAGE int WSAAPI WSAEventSelect(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAGetOverlappedResult(SOCKET s,LPWSAOVERLAPPED lpOverlapped,LPDWORD lpcbTransfer,WINBOOL fWait,LPDWORD lpdwFlags); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAGetQOSByName(SOCKET s,LPWSABUF lpQOSName,LPQOS lpQOS); - WINSOCK_API_LINKAGE int WSAAPI WSAHtonl(SOCKET s,u_long hostlong,u_long *lpnetlong); - WINSOCK_API_LINKAGE int WSAAPI WSAHtons(SOCKET s,u_short hostshort,u_short *lpnetshort); - WINSOCK_API_LINKAGE int WSAAPI WSAIoctl(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINSOCK_API_LINKAGE SOCKET WSAAPI WSAJoinLeaf(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,DWORD dwFlags); - WINSOCK_API_LINKAGE int WSAAPI WSANtohl(SOCKET s,u_long netlong,u_long *lphostlong); - WINSOCK_API_LINKAGE int WSAAPI WSANtohs(SOCKET s,u_short netshort,u_short *lphostshort); - WINSOCK_API_LINKAGE int WSAAPI WSARecv(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINSOCK_API_LINKAGE int WSAAPI WSARecvDisconnect(SOCKET s,LPWSABUF lpInboundDisconnectData); - WINSOCK_API_LINKAGE int WSAAPI WSARecvFrom(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,struct sockaddr *lpFrom,LPINT lpFromlen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAResetEvent(WSAEVENT hEvent); - WINSOCK_API_LINKAGE int WSAAPI WSASend(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINSOCK_API_LINKAGE int WSAAPI WSASendDisconnect(SOCKET s,LPWSABUF lpOutboundDisconnectData); - WINSOCK_API_LINKAGE int WSAAPI WSASendTo(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,const struct sockaddr *lpTo,int iTolen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - WINSOCK_API_LINKAGE WINBOOL WSAAPI WSASetEvent(WSAEVENT hEvent); - WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketA(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags); - WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketW(int af,int type,int protocol,LPWSAPROTOCOL_INFOW lpProtocolInfo,GROUP g,DWORD dwFlags); - WINSOCK_API_LINKAGE DWORD WSAAPI WSAWaitForMultipleEvents(DWORD cEvents,const WSAEVENT *lphEvents,WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable); - WINSOCK_API_LINKAGE INT WSAAPI WSAAddressToStringA(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSTR lpszAddressString,LPDWORD lpdwAddressStringLength); - WINSOCK_API_LINKAGE INT WSAAPI WSAAddressToStringW(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPWSTR lpszAddressString,LPDWORD lpdwAddressStringLength); - WINSOCK_API_LINKAGE INT WSAAPI WSAStringToAddressA(LPSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); - WINSOCK_API_LINKAGE INT WSAAPI WSAStringToAddressW(LPWSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); - WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceBeginA(LPWSAQUERYSETA lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); - WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceBeginW(LPWSAQUERYSETW lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); - WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceNextA(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETA lpqsResults); - WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceNextW(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETW lpqsResults); - WINSOCK_API_LINKAGE INT WSAAPI WSANSPIoctl(HANDLE hLookup,DWORD dwControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSACOMPLETION lpCompletion); - WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceEnd(HANDLE hLookup); - WINSOCK_API_LINKAGE INT WSAAPI WSAInstallServiceClassA(LPWSASERVICECLASSINFOA lpServiceClassInfo); - WINSOCK_API_LINKAGE INT WSAAPI WSAInstallServiceClassW(LPWSASERVICECLASSINFOW lpServiceClassInfo); - WINSOCK_API_LINKAGE INT WSAAPI WSARemoveServiceClass(LPGUID lpServiceClassId); - WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassInfoA(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOA lpServiceClassInfo); - WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassInfoW(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOW lpServiceClassInfo); - WINSOCK_API_LINKAGE INT WSAAPI WSAEnumNameSpaceProvidersA(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOA lpnspBuffer); - WINSOCK_API_LINKAGE INT WSAAPI WSAEnumNameSpaceProvidersW(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOW lpnspBuffer); - WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassNameByClassIdA(LPGUID lpServiceClassId,LPSTR lpszServiceClassName,LPDWORD lpdwBufferLength); - WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassNameByClassIdW(LPGUID lpServiceClassId,LPWSTR lpszServiceClassName,LPDWORD lpdwBufferLength); - WINSOCK_API_LINKAGE INT WSAAPI WSASetServiceA(LPWSAQUERYSETA lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); - WINSOCK_API_LINKAGE INT WSAAPI WSASetServiceW(LPWSAQUERYSETW lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); - WINSOCK_API_LINKAGE INT WSAAPI WSAProviderConfigChange(LPHANDLE lpNotificationHandle,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - - typedef struct sockaddr_in SOCKADDR_IN; - typedef struct sockaddr_in *PSOCKADDR_IN; - typedef struct sockaddr_in *LPSOCKADDR_IN; - - typedef struct linger LINGER; - typedef struct linger *PLINGER; - typedef struct linger *LPLINGER; - - typedef struct in_addr IN_ADDR; - typedef struct in_addr *PIN_ADDR; - typedef struct in_addr *LPIN_ADDR; - - typedef struct fd_set FD_SET; - typedef struct fd_set *PFD_SET; - typedef struct fd_set *LPFD_SET; - - typedef struct hostent HOSTENT; - typedef struct hostent *PHOSTENT; - typedef struct hostent *LPHOSTENT; - - typedef struct servent SERVENT; - typedef struct servent *PSERVENT; - typedef struct servent *LPSERVENT; - - typedef struct protoent PROTOENT; - typedef struct protoent *PPROTOENT; - typedef struct protoent *LPPROTOENT; - - typedef struct timeval TIMEVAL; - typedef struct timeval *PTIMEVAL; - typedef struct timeval *LPTIMEVAL; - -#define WSAMAKEASYNCREPLY(buflen,error) MAKELONG(buflen,error) -#define WSAMAKESELECTREPLY(event,error) MAKELONG(event,error) -#define WSAGETASYNCBUFLEN(lParam) LOWORD(lParam) -#define WSAGETASYNCERROR(lParam) HIWORD(lParam) -#define WSAGETSELECTEVENT(lParam) LOWORD(lParam) -#define WSAGETSELECTERROR(lParam) HIWORD(lParam) - -/* #if (_WIN32_WINNT >= 0x0600) */ -#define POLLRDNORM 0x0100 -#define POLLRDBAND 0x0200 -#define POLLIN (POLLRDNORM | POLLRDBAND) -#define POLLPRI 0x0400 - -#define POLLWRNORM 0x0010 -#define POLLOUT (POLLWRNORM) -#define POLLWRBAND 0x0020 - -#define POLLERR 0x0001 -#define POLLHUP 0x0002 -#define POLLNVAL 0x0004 - -typedef struct pollfd { - SOCKET fd; - SHORT events; - SHORT revents; -} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; - -WINSOCK_API_LINKAGE int WSAAPI WSAPoll(LPWSAPOLLFD fdArray, ULONG fds, INT timeout); -/* #endif // (_WIN32_WINNT >= 0x0600) */ - -#ifdef __cplusplus -} -#endif - -#ifdef _NEED_POPPACK -#include -#endif - -#ifdef IPV6STRICT -#include -#endif - -#ifndef _WINSOCKAPI_ -#define _WINSOCKAPI_ -#endif - -#ifdef _INC_WINSOCK_H -#include -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _WINSOCK2API_ +#define _WINSOCK2API_ + +#ifndef INCL_WINSOCK_API_TYPEDEFS +#define INCL_WINSOCK_API_TYPEDEFS 0 +#endif + +#ifndef _INC_WINDOWS +#include +#endif + +#ifndef MAKEWORD +#define MAKEWORD(low,high) ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8)) +#endif + +#ifndef WINSOCK_VERSION +#define WINSOCK_VERSION MAKEWORD(2,2) +#endif + +#ifndef WINSOCK_API_LINKAGE +#ifdef DECLSPEC_IMPORT +#define WINSOCK_API_LINKAGE DECLSPEC_IMPORT +#else +#define WINSOCK_API_LINKAGE +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _WINSOCK_SOCKET_DEFINED +#define _WINSOCK_SOCKET_DEFINED + typedef unsigned char u_char; + typedef unsigned short u_short; + typedef unsigned int u_int; + typedef unsigned long u_long; + __MINGW_EXTENSION typedef unsigned __int64 u_int64; + typedef INT_PTR SOCKET; +#endif + +#ifndef FD_SETSIZE +#define FD_SETSIZE 64 +#endif + + typedef struct fd_set { + u_int fd_count; + SOCKET fd_array[FD_SETSIZE]; + } fd_set; + + extern int WINAPI __WSAFDIsSet(SOCKET,fd_set *); + +#define FD_CLR(fd,set) do { u_int __i; for(__i = 0;__i < ((fd_set *)(set))->fd_count;__i++) { if (((fd_set *)(set))->fd_array[__i]==fd) { while (__i < ((fd_set *)(set))->fd_count-1) { ((fd_set *)(set))->fd_array[__i] = ((fd_set *)(set))->fd_array[__i+1]; __i++; } ((fd_set *)(set))->fd_count--; break; } } } while(0) +#define FD_SET(fd,set) do { u_int __i; for(__i = 0;__i < ((fd_set *)(set))->fd_count;__i++) { if (((fd_set *)(set))->fd_array[__i]==(fd)) { break; } } if (__i==((fd_set *)(set))->fd_count) { if (((fd_set *)(set))->fd_count < FD_SETSIZE) { ((fd_set *)(set))->fd_array[__i] = (fd); ((fd_set *)(set))->fd_count++; } } } while(0) +#define FD_ZERO(set) (((fd_set *)(set))->fd_count=0) +#define FD_ISSET(fd,set) __WSAFDIsSet((SOCKET)(fd),(fd_set *)(set)) + +#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */ +#define _TIMEVAL_DEFINED + struct timeval { + long tv_sec; + long tv_usec; + }; + +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) +#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif /* _TIMEVAL_DEFINED */ + +#define IOCPARM_MASK 0x7f +#define IOC_VOID 0x20000000 +#define IOC_OUT 0x40000000 +#define IOC_IN 0x80000000 +#define IOC_INOUT (IOC_IN|IOC_OUT) + +#define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) +#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define FIONREAD _IOR('f',127,u_long) +#define FIONBIO _IOW('f',126,u_long) +#define FIOASYNC _IOW('f',125,u_long) + +#define SIOCSHIWAT _IOW('s',0,u_long) +#define SIOCGHIWAT _IOR('s',1,u_long) +#define SIOCSLOWAT _IOW('s',2,u_long) +#define SIOCGLOWAT _IOR('s',3,u_long) +#define SIOCATMARK _IOR('s',7,u_long) + +#define h_addr h_addr_list[0] + + struct hostent { + char *h_name; + char **h_aliases; + short h_addrtype; + short h_length; + char **h_addr_list; + }; + + struct netent { + char *n_name; + char **n_aliases; + short n_addrtype; + u_long n_net; + }; + + struct servent { + char *s_name; + char **s_aliases; +#ifdef _WIN64 + char *s_proto; + short s_port; +#else + short s_port; + char *s_proto; +#endif + }; + + struct protoent { + char *p_name; + char **p_aliases; + short p_proto; + }; + +#define IPPROTO_IP 0 +#define IPPROTO_HOPOPTS 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_IGMP 2 +#define IPPROTO_GGP 3 +#define IPPROTO_IPV4 4 +#define IPPROTO_TCP 6 +#define IPPROTO_PUP 12 +#define IPPROTO_UDP 17 +#define IPPROTO_IDP 22 +#define IPPROTO_IPV6 41 +#define IPPROTO_ROUTING 43 +#define IPPROTO_FRAGMENT 44 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_NONE 59 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_ND 77 +#define IPPROTO_ICLFXBM 78 + +#define IPPROTO_RAW 255 +#define IPPROTO_MAX 256 + +#define IPPORT_ECHO 7 +#define IPPORT_DISCARD 9 +#define IPPORT_SYSTAT 11 +#define IPPORT_DAYTIME 13 +#define IPPORT_NETSTAT 15 +#define IPPORT_FTP 21 +#define IPPORT_TELNET 23 +#define IPPORT_SMTP 25 +#define IPPORT_TIMESERVER 37 +#define IPPORT_NAMESERVER 42 +#define IPPORT_WHOIS 43 +#define IPPORT_MTP 57 + +#define IPPORT_TFTP 69 +#define IPPORT_RJE 77 +#define IPPORT_FINGER 79 +#define IPPORT_TTYLINK 87 +#define IPPORT_SUPDUP 95 + +#define IPPORT_EXECSERVER 512 +#define IPPORT_LOGINSERVER 513 +#define IPPORT_CMDSERVER 514 +#define IPPORT_EFSSERVER 520 + +#define IPPORT_BIFFUDP 512 +#define IPPORT_WHOSERVER 513 +#define IPPORT_ROUTESERVER 520 + +#define IPPORT_RESERVED 1024 + +#define IMPLINK_IP 155 +#define IMPLINK_LOWEXPER 156 +#define IMPLINK_HIGHEXPER 158 + +#ifndef s_addr + + struct in_addr { + union { + struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; + struct { u_short s_w1,s_w2; } S_un_w; + u_long S_addr; + } S_un; + }; + +#define s_addr S_un.S_addr +#define s_host S_un.S_un_b.s_b2 +#define s_net S_un.S_un_b.s_b1 +#define s_imp S_un.S_un_w.s_w2 +#define s_impno S_un.S_un_b.s_b4 +#define s_lh S_un.S_un_b.s_b3 + +#endif + +#define IN_CLASSA(i) (((long)(i) & 0x80000000)==0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST 0x00ffffff +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(i) (((long)(i) & 0xc0000000)==0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST 0x0000ffff +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(i) (((long)(i) & 0xe0000000)==0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST 0x000000ff + +#define IN_CLASSD(i) (((long)(i) & 0xf0000000)==0xe0000000) +#define IN_CLASSD_NET 0xf0000000 +#define IN_CLASSD_NSHIFT 28 +#define IN_CLASSD_HOST 0x0fffffff +#define IN_MULTICAST(i) IN_CLASSD(i) + +#define INADDR_ANY (u_long)0x00000000 +#define INADDR_LOOPBACK 0x7f000001 +#define INADDR_BROADCAST (u_long)0xffffffff +#define INADDR_NONE 0xffffffff + +#define ADDR_ANY INADDR_ANY + + struct sockaddr_in { + short sin_family; + u_short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; + }; + +#define WSADESCRIPTION_LEN 256 +#define WSASYS_STATUS_LEN 128 + + typedef struct WSAData { + WORD wVersion; + WORD wHighVersion; +#ifdef _WIN64 + unsigned short iMaxSockets; + unsigned short iMaxUdpDg; + char *lpVendorInfo; + char szDescription[WSADESCRIPTION_LEN+1]; + char szSystemStatus[WSASYS_STATUS_LEN+1]; +#else + char szDescription[WSADESCRIPTION_LEN+1]; + char szSystemStatus[WSASYS_STATUS_LEN+1]; + unsigned short iMaxSockets; + unsigned short iMaxUdpDg; + char *lpVendorInfo; +#endif + } WSADATA,*LPWSADATA; + +#define INVALID_SOCKET (SOCKET)(~0) +#define SOCKET_ERROR (-1) + +#define FROM_PROTOCOL_INFO (-1) + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 +#define SOCK_RDM 4 +#define SOCK_SEQPACKET 5 + +#define SO_DEBUG 0x0001 +#define SO_ACCEPTCONN 0x0002 +#define SO_REUSEADDR 0x0004 +#define SO_KEEPALIVE 0x0008 +#define SO_DONTROUTE 0x0010 +#define SO_BROADCAST 0x0020 +#define SO_USELOOPBACK 0x0040 +#define SO_LINGER 0x0080 +#define SO_OOBINLINE 0x0100 + +#define SO_DONTLINGER (int)(~SO_LINGER) +#define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR)) + +#define SO_SNDBUF 0x1001 +#define SO_RCVBUF 0x1002 +#define SO_SNDLOWAT 0x1003 +#define SO_RCVLOWAT 0x1004 +#define SO_SNDTIMEO 0x1005 +#define SO_RCVTIMEO 0x1006 +#define SO_ERROR 0x1007 +#define SO_TYPE 0x1008 + +#define SO_GROUP_ID 0x2001 +#define SO_GROUP_PRIORITY 0x2002 +#define SO_MAX_MSG_SIZE 0x2003 +#define SO_PROTOCOL_INFOA 0x2004 +#define SO_PROTOCOL_INFOW 0x2005 +#ifdef UNICODE +#define SO_PROTOCOL_INFO SO_PROTOCOL_INFOW +#else +#define SO_PROTOCOL_INFO SO_PROTOCOL_INFOA +#endif +#define PVD_CONFIG 0x3001 +#define SO_CONDITIONAL_ACCEPT 0x3002 + +#define TCP_NODELAY 0x0001 + +#define AF_UNSPEC 0 + +#define AF_UNIX 1 +#define AF_INET 2 +#define AF_IMPLINK 3 +#define AF_PUP 4 +#define AF_CHAOS 5 +#define AF_NS 6 +#define AF_IPX AF_NS +#define AF_ISO 7 +#define AF_OSI AF_ISO +#define AF_ECMA 8 +#define AF_DATAKIT 9 +#define AF_CCITT 10 +#define AF_SNA 11 +#define AF_DECnet 12 +#define AF_DLI 13 +#define AF_LAT 14 +#define AF_HYLINK 15 +#define AF_APPLETALK 16 +#define AF_NETBIOS 17 +#define AF_VOICEVIEW 18 +#define AF_FIREFOX 19 +#define AF_UNKNOWN1 20 +#define AF_BAN 21 +#define AF_ATM 22 +#define AF_INET6 23 +#define AF_CLUSTER 24 +#define AF_12844 25 +#define AF_IRDA 26 +#define AF_NETDES 28 +#define AF_TCNPROCESS 29 +#define AF_TCNMESSAGE 30 +#define AF_ICLFXBM 31 + +#define AF_MAX 32 + + struct sockaddr { + u_short sa_family; + char sa_data[14]; + }; + +#define _SS_MAXSIZE 128 +#define _SS_ALIGNSIZE (8) + +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (short)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (short) + _SS_PAD1SIZE + _SS_ALIGNSIZE)) + + struct sockaddr_storage { + short ss_family; + char __ss_pad1[_SS_PAD1SIZE]; + + __MINGW_EXTENSION __int64 __ss_align; + char __ss_pad2[_SS_PAD2SIZE]; + + }; + + struct sockproto { + u_short sp_family; + u_short sp_protocol; + }; + +#define PF_UNSPEC AF_UNSPEC +#define PF_UNIX AF_UNIX +#define PF_INET AF_INET +#define PF_IMPLINK AF_IMPLINK +#define PF_PUP AF_PUP +#define PF_CHAOS AF_CHAOS +#define PF_NS AF_NS +#define PF_IPX AF_IPX +#define PF_ISO AF_ISO +#define PF_OSI AF_OSI +#define PF_ECMA AF_ECMA +#define PF_DATAKIT AF_DATAKIT +#define PF_CCITT AF_CCITT +#define PF_SNA AF_SNA +#define PF_DECnet AF_DECnet +#define PF_DLI AF_DLI +#define PF_LAT AF_LAT +#define PF_HYLINK AF_HYLINK +#define PF_APPLETALK AF_APPLETALK +#define PF_VOICEVIEW AF_VOICEVIEW +#define PF_FIREFOX AF_FIREFOX +#define PF_UNKNOWN1 AF_UNKNOWN1 +#define PF_BAN AF_BAN +#define PF_ATM AF_ATM +#define PF_INET6 AF_INET6 + +#define PF_MAX AF_MAX + + struct linger { + u_short l_onoff; + u_short l_linger; + }; + +#define SOL_SOCKET 0xffff + +#define SOMAXCONN 0x7fffffff + +#define MSG_OOB 0x1 +#define MSG_PEEK 0x2 +#define MSG_DONTROUTE 0x4 +#define MSG_WAITALL 0x8 + +#define MSG_PARTIAL 0x8000 + +#define MSG_INTERRUPT 0x10 + +#define MSG_MAXIOVLEN 16 + +#define MAXGETHOSTSTRUCT 1024 + +#define FD_READ_BIT 0 +#define FD_READ (1 << FD_READ_BIT) + +#define FD_WRITE_BIT 1 +#define FD_WRITE (1 << FD_WRITE_BIT) + +#define FD_OOB_BIT 2 +#define FD_OOB (1 << FD_OOB_BIT) + +#define FD_ACCEPT_BIT 3 +#define FD_ACCEPT (1 << FD_ACCEPT_BIT) + +#define FD_CONNECT_BIT 4 +#define FD_CONNECT (1 << FD_CONNECT_BIT) + +#define FD_CLOSE_BIT 5 +#define FD_CLOSE (1 << FD_CLOSE_BIT) + +#define FD_QOS_BIT 6 +#define FD_QOS (1 << FD_QOS_BIT) + +#define FD_GROUP_QOS_BIT 7 +#define FD_GROUP_QOS (1 << FD_GROUP_QOS_BIT) + +#define FD_ROUTING_INTERFACE_CHANGE_BIT 8 +#define FD_ROUTING_INTERFACE_CHANGE (1 << FD_ROUTING_INTERFACE_CHANGE_BIT) + +#define FD_ADDRESS_LIST_CHANGE_BIT 9 +#define FD_ADDRESS_LIST_CHANGE (1 << FD_ADDRESS_LIST_CHANGE_BIT) + +#define FD_MAX_EVENTS 10 +#define FD_ALL_EVENTS ((1 << FD_MAX_EVENTS) - 1) + +#ifndef WSABASEERR + +#define WSABASEERR 10000 + +#define WSAEINTR (WSABASEERR+4) +#define WSAEBADF (WSABASEERR+9) +#define WSAEACCES (WSABASEERR+13) +#define WSAEFAULT (WSABASEERR+14) +#define WSAEINVAL (WSABASEERR+22) +#define WSAEMFILE (WSABASEERR+24) + +#define WSAEWOULDBLOCK (WSABASEERR+35) +#define WSAEINPROGRESS (WSABASEERR+36) +#define WSAEALREADY (WSABASEERR+37) +#define WSAENOTSOCK (WSABASEERR+38) +#define WSAEDESTADDRREQ (WSABASEERR+39) +#define WSAEMSGSIZE (WSABASEERR+40) +#define WSAEPROTOTYPE (WSABASEERR+41) +#define WSAENOPROTOOPT (WSABASEERR+42) +#define WSAEPROTONOSUPPORT (WSABASEERR+43) +#define WSAESOCKTNOSUPPORT (WSABASEERR+44) +#define WSAEOPNOTSUPP (WSABASEERR+45) +#define WSAEPFNOSUPPORT (WSABASEERR+46) +#define WSAEAFNOSUPPORT (WSABASEERR+47) +#define WSAEADDRINUSE (WSABASEERR+48) +#define WSAEADDRNOTAVAIL (WSABASEERR+49) +#define WSAENETDOWN (WSABASEERR+50) +#define WSAENETUNREACH (WSABASEERR+51) +#define WSAENETRESET (WSABASEERR+52) +#define WSAECONNABORTED (WSABASEERR+53) +#define WSAECONNRESET (WSABASEERR+54) +#define WSAENOBUFS (WSABASEERR+55) +#define WSAEISCONN (WSABASEERR+56) +#define WSAENOTCONN (WSABASEERR+57) +#define WSAESHUTDOWN (WSABASEERR+58) +#define WSAETOOMANYREFS (WSABASEERR+59) +#define WSAETIMEDOUT (WSABASEERR+60) +#define WSAECONNREFUSED (WSABASEERR+61) +#define WSAELOOP (WSABASEERR+62) +#define WSAENAMETOOLONG (WSABASEERR+63) +#define WSAEHOSTDOWN (WSABASEERR+64) +#define WSAEHOSTUNREACH (WSABASEERR+65) +#define WSAENOTEMPTY (WSABASEERR+66) +#define WSAEPROCLIM (WSABASEERR+67) +#define WSAEUSERS (WSABASEERR+68) +#define WSAEDQUOT (WSABASEERR+69) +#define WSAESTALE (WSABASEERR+70) +#define WSAEREMOTE (WSABASEERR+71) + +#define WSASYSNOTREADY (WSABASEERR+91) +#define WSAVERNOTSUPPORTED (WSABASEERR+92) +#define WSANOTINITIALISED (WSABASEERR+93) +#define WSAEDISCON (WSABASEERR+101) +#ifndef WSAHOST_NOT_FOUND +#define WSAHOST_NOT_FOUND (WSABASEERR+1001) +#endif +#ifndef WSATRY_AGAIN +#define WSATRY_AGAIN (WSABASEERR+1002) +#endif +#ifndef WSANO_RECOVERY +#define WSANO_RECOVERY (WSABASEERR+1003) +#endif +#ifndef WSANO_DATA +#define WSANO_DATA (WSABASEERR+1004) +#endif + +#define WSAENOMORE (WSABASEERR+102) +#define WSAECANCELLED (WSABASEERR+103) +#define WSAEINVALIDPROCTABLE (WSABASEERR+104) +#define WSAEINVALIDPROVIDER (WSABASEERR+105) +#define WSAEPROVIDERFAILEDINIT (WSABASEERR+106) +#define WSASYSCALLFAILURE (WSABASEERR+107) +#define WSASERVICE_NOT_FOUND (WSABASEERR+108) +#define WSATYPE_NOT_FOUND (WSABASEERR+109) +#define WSA_E_NO_MORE (WSABASEERR+110) +#define WSA_E_CANCELLED (WSABASEERR+111) +#define WSAEREFUSED (WSABASEERR+112) +#ifndef WSA_QOS_RECEIVERS +#define WSA_QOS_RECEIVERS (WSABASEERR + 1005) +#endif +#ifndef WSA_QOS_SENDERS +#define WSA_QOS_SENDERS (WSABASEERR + 1006) +#endif +#ifndef WSA_QOS_NO_SENDERS +#define WSA_QOS_NO_SENDERS (WSABASEERR + 1007) +#define WSA_QOS_NO_RECEIVERS (WSABASEERR + 1008) +#define WSA_QOS_REQUEST_CONFIRMED (WSABASEERR + 1009) +#define WSA_QOS_ADMISSION_FAILURE (WSABASEERR + 1010) +#define WSA_QOS_POLICY_FAILURE (WSABASEERR + 1011) +#define WSA_QOS_BAD_STYLE (WSABASEERR + 1012) +#define WSA_QOS_BAD_OBJECT (WSABASEERR + 1013) +#define WSA_QOS_TRAFFIC_CTRL_ERROR (WSABASEERR + 1014) +#define WSA_QOS_GENERIC_ERROR (WSABASEERR + 1015) +#define WSA_QOS_ESERVICETYPE (WSABASEERR + 1016) +#define WSA_QOS_EFLOWSPEC (WSABASEERR + 1017) +#define WSA_QOS_EPROVSPECBUF (WSABASEERR + 1018) +#endif +#ifndef WSA_QOS_EFILTERSTYLE +#define WSA_QOS_EFILTERSTYLE (WSABASEERR + 1019) +#endif +#ifndef WSA_QOS_EFILTERTYPE +#define WSA_QOS_EFILTERTYPE (WSABASEERR + 1020) +#endif +#ifndef WSA_QOS_EFILTERCOUNT +#define WSA_QOS_EFILTERCOUNT (WSABASEERR + 1021) +#endif +#ifndef WSA_QOS_EOBJLENGTH +#define WSA_QOS_EOBJLENGTH (WSABASEERR + 1022) +#endif +#ifndef WSA_QOS_EFLOWCOUNT +#define WSA_QOS_EFLOWCOUNT (WSABASEERR + 1023) +#endif +#ifndef WSA_QOS_EUNKNOWNPSOBJ +#define WSA_QOS_EUNKNOWNPSOBJ (WSABASEERR + 1024) +#endif +#ifndef WSA_QOS_EPOLICYOBJ +#define WSA_QOS_EPOLICYOBJ (WSABASEERR + 1025) +#endif +#ifndef WSA_QOS_EFLOWDESC +#define WSA_QOS_EFLOWDESC (WSABASEERR + 1026) +#endif +#ifndef WSA_QOS_EPSFLOWSPEC +#define WSA_QOS_EPSFLOWSPEC (WSABASEERR + 1027) +#endif +#ifndef WSA_QOS_EPSFILTERSPEC +#define WSA_QOS_EPSFILTERSPEC (WSABASEERR + 1028) +#endif +#ifndef WSA_QOS_ESDMODEOBJ +#define WSA_QOS_ESDMODEOBJ (WSABASEERR + 1029) +#endif +#ifndef WSA_QOS_ESHAPERATEOBJ +#define WSA_QOS_ESHAPERATEOBJ (WSABASEERR + 1030) +#endif +#ifndef WSA_QOS_RESERVED_PETYPE +#define WSA_QOS_RESERVED_PETYPE (WSABASEERR + 1031) +#endif +#endif // WSABASEERR + +#define h_errno WSAGetLastError() +#define HOST_NOT_FOUND WSAHOST_NOT_FOUND +#define TRY_AGAIN WSATRY_AGAIN +#define NO_RECOVERY WSANO_RECOVERY +#define NO_DATA WSANO_DATA + +#define WSANO_ADDRESS WSANO_DATA +#define NO_ADDRESS WSANO_ADDRESS + +#if 0 +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINPROGRESS WSAEINPROGRESS +#define EALREADY WSAEALREADY +#define ENOTSOCK WSAENOTSOCK +#define EDESTADDRREQ WSAEDESTADDRREQ +#define EMSGSIZE WSAEMSGSIZE +#define EPROTOTYPE WSAEPROTOTYPE +#define ENOPROTOOPT WSAENOPROTOOPT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EADDRINUSE WSAEADDRINUSE +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define ENETDOWN WSAENETDOWN +#define ENETUNREACH WSAENETUNREACH +#define ENETRESET WSAENETRESET +#define ECONNABORTED WSAECONNABORTED +#define ECONNRESET WSAECONNRESET +#define ENOBUFS WSAENOBUFS +#define EISCONN WSAEISCONN +#define ENOTCONN WSAENOTCONN +#define ESHUTDOWN WSAESHUTDOWN +#define ETOOMANYREFS WSAETOOMANYREFS +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define ELOOP WSAELOOP +#define ENAMETOOLONG WSAENAMETOOLONG +#define EHOSTDOWN WSAEHOSTDOWN +#define EHOSTUNREACH WSAEHOSTUNREACH +#define ENOTEMPTY WSAENOTEMPTY +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE +#endif + +#define WSAAPI WINAPI +#define WSAEVENT HANDLE +#define LPWSAEVENT LPHANDLE +#define WSAOVERLAPPED OVERLAPPED + typedef struct _OVERLAPPED *LPWSAOVERLAPPED; + +#define WSA_IO_PENDING (ERROR_IO_PENDING) +#define WSA_IO_INCOMPLETE (ERROR_IO_INCOMPLETE) +#define WSA_INVALID_HANDLE (ERROR_INVALID_HANDLE) +#define WSA_INVALID_PARAMETER (ERROR_INVALID_PARAMETER) +#define WSA_NOT_ENOUGH_MEMORY (ERROR_NOT_ENOUGH_MEMORY) +#define WSA_OPERATION_ABORTED (ERROR_OPERATION_ABORTED) + +#define WSA_INVALID_EVENT ((WSAEVENT)NULL) +#define WSA_MAXIMUM_WAIT_EVENTS (MAXIMUM_WAIT_OBJECTS) +#define WSA_WAIT_FAILED (WAIT_FAILED) +#define WSA_WAIT_EVENT_0 (WAIT_OBJECT_0) +#define WSA_WAIT_IO_COMPLETION (WAIT_IO_COMPLETION) +#define WSA_WAIT_TIMEOUT (WAIT_TIMEOUT) +#define WSA_INFINITE (INFINITE) + + typedef struct _WSABUF { + u_long len; + char *buf; + } WSABUF,*LPWSABUF; + +#include + + typedef struct _QualityOfService { + FLOWSPEC SendingFlowspec; + FLOWSPEC ReceivingFlowspec; + WSABUF ProviderSpecific; + } QOS,*LPQOS; + +#define CF_ACCEPT 0x0000 +#define CF_REJECT 0x0001 +#define CF_DEFER 0x0002 + +#define SD_RECEIVE 0x00 +#define SD_SEND 0x01 +#define SD_BOTH 0x02 + + typedef unsigned int GROUP; + +#define SG_UNCONSTRAINED_GROUP 0x01 +#define SG_CONSTRAINED_GROUP 0x02 + + typedef struct _WSANETWORKEVENTS { + long lNetworkEvents; + int iErrorCode[FD_MAX_EVENTS]; + } WSANETWORKEVENTS,*LPWSANETWORKEVENTS; + +#ifndef GUID_DEFINED +#include +#endif + +#define MAX_PROTOCOL_CHAIN 7 + +#define BASE_PROTOCOL 1 +#define LAYERED_PROTOCOL 0 + + typedef struct _WSAPROTOCOLCHAIN { + int ChainLen; + + DWORD ChainEntries[MAX_PROTOCOL_CHAIN]; + } WSAPROTOCOLCHAIN,*LPWSAPROTOCOLCHAIN; + +#define WSAPROTOCOL_LEN 255 + + typedef struct _WSAPROTOCOL_INFOA { + DWORD dwServiceFlags1; + DWORD dwServiceFlags2; + DWORD dwServiceFlags3; + DWORD dwServiceFlags4; + DWORD dwProviderFlags; + GUID ProviderId; + DWORD dwCatalogEntryId; + WSAPROTOCOLCHAIN ProtocolChain; + int iVersion; + int iAddressFamily; + int iMaxSockAddr; + int iMinSockAddr; + int iSocketType; + int iProtocol; + int iProtocolMaxOffset; + int iNetworkByteOrder; + int iSecurityScheme; + DWORD dwMessageSize; + DWORD dwProviderReserved; + CHAR szProtocol[WSAPROTOCOL_LEN+1]; + } WSAPROTOCOL_INFOA,*LPWSAPROTOCOL_INFOA; + typedef struct _WSAPROTOCOL_INFOW { + DWORD dwServiceFlags1; + DWORD dwServiceFlags2; + DWORD dwServiceFlags3; + DWORD dwServiceFlags4; + DWORD dwProviderFlags; + GUID ProviderId; + DWORD dwCatalogEntryId; + WSAPROTOCOLCHAIN ProtocolChain; + int iVersion; + int iAddressFamily; + int iMaxSockAddr; + int iMinSockAddr; + int iSocketType; + int iProtocol; + int iProtocolMaxOffset; + int iNetworkByteOrder; + int iSecurityScheme; + DWORD dwMessageSize; + DWORD dwProviderReserved; + WCHAR szProtocol[WSAPROTOCOL_LEN+1]; + } WSAPROTOCOL_INFOW,*LPWSAPROTOCOL_INFOW; +#ifdef UNICODE + typedef WSAPROTOCOL_INFOW WSAPROTOCOL_INFO; + typedef LPWSAPROTOCOL_INFOW LPWSAPROTOCOL_INFO; +#else + typedef WSAPROTOCOL_INFOA WSAPROTOCOL_INFO; + typedef LPWSAPROTOCOL_INFOA LPWSAPROTOCOL_INFO; +#endif + +#define PFL_MULTIPLE_PROTO_ENTRIES 0x00000001 +#define PFL_RECOMMENDED_PROTO_ENTRY 0x00000002 +#define PFL_HIDDEN 0x00000004 +#define PFL_MATCHES_PROTOCOL_ZERO 0x00000008 + +#define XP1_CONNECTIONLESS 0x00000001 +#define XP1_GUARANTEED_DELIVERY 0x00000002 +#define XP1_GUARANTEED_ORDER 0x00000004 +#define XP1_MESSAGE_ORIENTED 0x00000008 +#define XP1_PSEUDO_STREAM 0x00000010 +#define XP1_GRACEFUL_CLOSE 0x00000020 +#define XP1_EXPEDITED_DATA 0x00000040 +#define XP1_CONNECT_DATA 0x00000080 +#define XP1_DISCONNECT_DATA 0x00000100 +#define XP1_SUPPORT_BROADCAST 0x00000200 +#define XP1_SUPPORT_MULTIPOINT 0x00000400 +#define XP1_MULTIPOINT_CONTROL_PLANE 0x00000800 +#define XP1_MULTIPOINT_DATA_PLANE 0x00001000 +#define XP1_QOS_SUPPORTED 0x00002000 +#define XP1_INTERRUPT 0x00004000 +#define XP1_UNI_SEND 0x00008000 +#define XP1_UNI_RECV 0x00010000 +#define XP1_IFS_HANDLES 0x00020000 +#define XP1_PARTIAL_MESSAGE 0x00040000 + +#define BIGENDIAN 0x0000 +#define LITTLEENDIAN 0x0001 + +#define SECURITY_PROTOCOL_NONE 0x0000 + +#define JL_SENDER_ONLY 0x01 +#define JL_RECEIVER_ONLY 0x02 +#define JL_BOTH 0x04 + +#define WSA_FLAG_OVERLAPPED 0x01 +#define WSA_FLAG_MULTIPOINT_C_ROOT 0x02 +#define WSA_FLAG_MULTIPOINT_C_LEAF 0x04 +#define WSA_FLAG_MULTIPOINT_D_ROOT 0x08 +#define WSA_FLAG_MULTIPOINT_D_LEAF 0x10 + +#define IOC_UNIX 0x00000000 +#define IOC_WS2 0x08000000 +#define IOC_PROTOCOL 0x10000000 +#define IOC_VENDOR 0x18000000 + +#define _WSAIO(x,y) (IOC_VOID|(x)|(y)) +#define _WSAIOR(x,y) (IOC_OUT|(x)|(y)) +#define _WSAIOW(x,y) (IOC_IN|(x)|(y)) +#define _WSAIORW(x,y) (IOC_INOUT|(x)|(y)) + +#define SIO_ASSOCIATE_HANDLE _WSAIOW(IOC_WS2,1) +#define SIO_ENABLE_CIRCULAR_QUEUEING _WSAIO(IOC_WS2,2) +#define SIO_FIND_ROUTE _WSAIOR(IOC_WS2,3) +#define SIO_FLUSH _WSAIO(IOC_WS2,4) +#define SIO_GET_BROADCAST_ADDRESS _WSAIOR(IOC_WS2,5) +#define SIO_GET_EXTENSION_FUNCTION_POINTER _WSAIORW(IOC_WS2,6) +#define SIO_GET_QOS _WSAIORW(IOC_WS2,7) +#define SIO_GET_GROUP_QOS _WSAIORW(IOC_WS2,8) +#define SIO_MULTIPOINT_LOOPBACK _WSAIOW(IOC_WS2,9) +#define SIO_MULTICAST_SCOPE _WSAIOW(IOC_WS2,10) +#define SIO_SET_QOS _WSAIOW(IOC_WS2,11) +#define SIO_SET_GROUP_QOS _WSAIOW(IOC_WS2,12) +#define SIO_TRANSLATE_HANDLE _WSAIORW(IOC_WS2,13) +#define SIO_ROUTING_INTERFACE_QUERY _WSAIORW(IOC_WS2,20) +#define SIO_ROUTING_INTERFACE_CHANGE _WSAIOW(IOC_WS2,21) +#define SIO_ADDRESS_LIST_QUERY _WSAIOR(IOC_WS2,22) +#define SIO_ADDRESS_LIST_CHANGE _WSAIO(IOC_WS2,23) +#define SIO_QUERY_TARGET_PNP_HANDLE _WSAIOR(IOC_WS2,24) +#define SIO_ADDRESS_LIST_SORT _WSAIORW(IOC_WS2,25) + + typedef int (CALLBACK *LPCONDITIONPROC)(LPWSABUF lpCallerId,LPWSABUF lpCallerData,LPQOS lpSQOS,LPQOS lpGQOS,LPWSABUF lpCalleeId,LPWSABUF lpCalleeData,GROUP *g,DWORD_PTR dwCallbackData); + typedef void (CALLBACK *LPWSAOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwError,DWORD cbTransferred,LPWSAOVERLAPPED lpOverlapped,DWORD dwFlags); + +#define SIO_NSP_NOTIFY_CHANGE _WSAIOW(IOC_WS2,25) + + typedef enum _WSACOMPLETIONTYPE { + NSP_NOTIFY_IMMEDIATELY = 0,NSP_NOTIFY_HWND,NSP_NOTIFY_EVENT,NSP_NOTIFY_PORT,NSP_NOTIFY_APC + } WSACOMPLETIONTYPE,*PWSACOMPLETIONTYPE,*LPWSACOMPLETIONTYPE; + + typedef struct _WSACOMPLETION { + WSACOMPLETIONTYPE Type; + union { + struct { + HWND hWnd; + UINT uMsg; + WPARAM context; + } WindowMessage; + struct { + LPWSAOVERLAPPED lpOverlapped; + } Event; + struct { + LPWSAOVERLAPPED lpOverlapped; + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpfnCompletionProc; + } Apc; + struct { + LPWSAOVERLAPPED lpOverlapped; + HANDLE hPort; + ULONG_PTR Key; + } Port; + } Parameters; + } WSACOMPLETION,*PWSACOMPLETION,*LPWSACOMPLETION; + +#define TH_NETDEV 0x00000001 +#define TH_TAPI 0x00000002 + + typedef struct sockaddr SOCKADDR; + typedef struct sockaddr *PSOCKADDR; + typedef struct sockaddr *LPSOCKADDR; + typedef struct sockaddr_storage SOCKADDR_STORAGE; + typedef struct sockaddr_storage *PSOCKADDR_STORAGE; + typedef struct sockaddr_storage *LPSOCKADDR_STORAGE; + +#ifndef _tagBLOB_DEFINED +#define _tagBLOB_DEFINED +#define _BLOB_DEFINED +#define _LPBLOB_DEFINED + typedef struct _BLOB { + ULONG cbSize; + BYTE *pBlobData; + } BLOB,*LPBLOB; +#endif + +#define SERVICE_MULTIPLE (0x00000001) + +#define NS_ALL (0) + +#define NS_SAP (1) +#define NS_NDS (2) +#define NS_PEER_BROWSE (3) +#define NS_SLP (5) +#define NS_DHCP (6) + +#define NS_TCPIP_LOCAL (10) +#define NS_TCPIP_HOSTS (11) +#define NS_DNS (12) +#define NS_NETBT (13) +#define NS_WINS (14) +#define NS_NLA (15) + +#define NS_NBP (20) + +#define NS_MS (30) +#define NS_STDA (31) +#define NS_NTDS (32) + +#define NS_X500 (40) +#define NS_NIS (41) +#define NS_NISPLUS (42) + +#define NS_WRQ (50) + +#define NS_NETDES (60) + +#define RES_UNUSED_1 (0x00000001) +#define RES_FLUSH_CACHE (0x00000002) +#ifndef RES_SERVICE +#define RES_SERVICE (0x00000004) +#endif + +#define SERVICE_TYPE_VALUE_IPXPORTA "IpxSocket" +#define SERVICE_TYPE_VALUE_IPXPORTW L"IpxSocket" +#define SERVICE_TYPE_VALUE_SAPIDA "SapId" +#define SERVICE_TYPE_VALUE_SAPIDW L"SapId" + +#define SERVICE_TYPE_VALUE_TCPPORTA "TcpPort" +#define SERVICE_TYPE_VALUE_TCPPORTW L"TcpPort" + +#define SERVICE_TYPE_VALUE_UDPPORTA "UdpPort" +#define SERVICE_TYPE_VALUE_UDPPORTW L"UdpPort" + +#define SERVICE_TYPE_VALUE_OBJECTIDA "ObjectId" +#define SERVICE_TYPE_VALUE_OBJECTIDW L"ObjectId" + +#ifdef UNICODE + +#define SERVICE_TYPE_VALUE_SAPID SERVICE_TYPE_VALUE_SAPIDW +#define SERVICE_TYPE_VALUE_TCPPORT SERVICE_TYPE_VALUE_TCPPORTW +#define SERVICE_TYPE_VALUE_UDPPORT SERVICE_TYPE_VALUE_UDPPORTW +#define SERVICE_TYPE_VALUE_OBJECTID SERVICE_TYPE_VALUE_OBJECTIDW +#else + +#define SERVICE_TYPE_VALUE_SAPID SERVICE_TYPE_VALUE_SAPIDA +#define SERVICE_TYPE_VALUE_TCPPORT SERVICE_TYPE_VALUE_TCPPORTA +#define SERVICE_TYPE_VALUE_UDPPORT SERVICE_TYPE_VALUE_UDPPORTA +#define SERVICE_TYPE_VALUE_OBJECTID SERVICE_TYPE_VALUE_OBJECTIDA +#endif + +#ifndef __CSADDR_DEFINED__ +#define __CSADDR_DEFINED__ + + typedef struct _SOCKET_ADDRESS { + LPSOCKADDR lpSockaddr; + INT iSockaddrLength; + } SOCKET_ADDRESS,*PSOCKET_ADDRESS,*LPSOCKET_ADDRESS; + + typedef struct _CSADDR_INFO { + SOCKET_ADDRESS LocalAddr; + SOCKET_ADDRESS RemoteAddr; + INT iSocketType; + INT iProtocol; + } CSADDR_INFO,*PCSADDR_INFO,*LPCSADDR_INFO; +#endif + + typedef struct _SOCKET_ADDRESS_LIST { + INT iAddressCount; + SOCKET_ADDRESS Address[1]; + } SOCKET_ADDRESS_LIST,*LPSOCKET_ADDRESS_LIST; + + typedef struct _AFPROTOCOLS { + INT iAddressFamily; + INT iProtocol; + } AFPROTOCOLS,*PAFPROTOCOLS,*LPAFPROTOCOLS; + + typedef enum _WSAEcomparator { + COMP_EQUAL = 0,COMP_NOTLESS + } WSAECOMPARATOR,*PWSAECOMPARATOR,*LPWSAECOMPARATOR; + + typedef struct _WSAVersion { + DWORD dwVersion; + WSAECOMPARATOR ecHow; + } WSAVERSION,*PWSAVERSION,*LPWSAVERSION; + + typedef struct _WSAQuerySetA { + DWORD dwSize; + LPSTR lpszServiceInstanceName; + LPGUID lpServiceClassId; + LPWSAVERSION lpVersion; + LPSTR lpszComment; + DWORD dwNameSpace; + LPGUID lpNSProviderId; + LPSTR lpszContext; + DWORD dwNumberOfProtocols; + LPAFPROTOCOLS lpafpProtocols; + LPSTR lpszQueryString; + DWORD dwNumberOfCsAddrs; + LPCSADDR_INFO lpcsaBuffer; + DWORD dwOutputFlags; + LPBLOB lpBlob; + } WSAQUERYSETA,*PWSAQUERYSETA,*LPWSAQUERYSETA; + + typedef struct _WSAQuerySetW { + DWORD dwSize; + LPWSTR lpszServiceInstanceName; + LPGUID lpServiceClassId; + LPWSAVERSION lpVersion; + LPWSTR lpszComment; + DWORD dwNameSpace; + LPGUID lpNSProviderId; + LPWSTR lpszContext; + DWORD dwNumberOfProtocols; + LPAFPROTOCOLS lpafpProtocols; + LPWSTR lpszQueryString; + DWORD dwNumberOfCsAddrs; + LPCSADDR_INFO lpcsaBuffer; + DWORD dwOutputFlags; + LPBLOB lpBlob; + } WSAQUERYSETW,*PWSAQUERYSETW,*LPWSAQUERYSETW; + +#ifdef UNICODE + typedef WSAQUERYSETW WSAQUERYSET; + typedef PWSAQUERYSETW PWSAQUERYSET; + typedef LPWSAQUERYSETW LPWSAQUERYSET; +#else + typedef WSAQUERYSETA WSAQUERYSET; + typedef PWSAQUERYSETA PWSAQUERYSET; + typedef LPWSAQUERYSETA LPWSAQUERYSET; +#endif + +#define LUP_DEEP 0x0001 +#define LUP_CONTAINERS 0x0002 +#define LUP_NOCONTAINERS 0x0004 +#define LUP_NEAREST 0x0008 +#define LUP_RETURN_NAME 0x0010 +#define LUP_RETURN_TYPE 0x0020 +#define LUP_RETURN_VERSION 0x0040 +#define LUP_RETURN_COMMENT 0x0080 +#define LUP_RETURN_ADDR 0x0100 +#define LUP_RETURN_BLOB 0x0200 +#define LUP_RETURN_ALIASES 0x0400 +#define LUP_RETURN_QUERY_STRING 0x0800 +#define LUP_RETURN_ALL 0x0FF0 +#define LUP_RES_SERVICE 0x8000 + +#define LUP_FLUSHCACHE 0x1000 +#define LUP_FLUSHPREVIOUS 0x2000 + +#define RESULT_IS_ALIAS 0x0001 +#define RESULT_IS_ADDED 0x0010 +#define RESULT_IS_CHANGED 0x0020 +#define RESULT_IS_DELETED 0x0040 + + typedef enum _WSAESETSERVICEOP { + RNRSERVICE_REGISTER=0,RNRSERVICE_DEREGISTER,RNRSERVICE_DELETE + } WSAESETSERVICEOP,*PWSAESETSERVICEOP,*LPWSAESETSERVICEOP; + + typedef struct _WSANSClassInfoA { + LPSTR lpszName; + DWORD dwNameSpace; + DWORD dwValueType; + DWORD dwValueSize; + LPVOID lpValue; + } WSANSCLASSINFOA,*PWSANSCLASSINFOA,*LPWSANSCLASSINFOA; + + typedef struct _WSANSClassInfoW { + LPWSTR lpszName; + DWORD dwNameSpace; + DWORD dwValueType; + DWORD dwValueSize; + LPVOID lpValue; + } WSANSCLASSINFOW,*PWSANSCLASSINFOW,*LPWSANSCLASSINFOW; + +#ifdef UNICODE + typedef WSANSCLASSINFOW WSANSCLASSINFO; + typedef PWSANSCLASSINFOW PWSANSCLASSINFO; + typedef LPWSANSCLASSINFOW LPWSANSCLASSINFO; +#else + typedef WSANSCLASSINFOA WSANSCLASSINFO; + typedef PWSANSCLASSINFOA PWSANSCLASSINFO; + typedef LPWSANSCLASSINFOA LPWSANSCLASSINFO; +#endif + + typedef struct _WSAServiceClassInfoA { + LPGUID lpServiceClassId; + LPSTR lpszServiceClassName; + DWORD dwCount; + LPWSANSCLASSINFOA lpClassInfos; + } WSASERVICECLASSINFOA,*PWSASERVICECLASSINFOA,*LPWSASERVICECLASSINFOA; + + typedef struct _WSAServiceClassInfoW { + LPGUID lpServiceClassId; + LPWSTR lpszServiceClassName; + DWORD dwCount; + LPWSANSCLASSINFOW lpClassInfos; + } WSASERVICECLASSINFOW,*PWSASERVICECLASSINFOW,*LPWSASERVICECLASSINFOW; + +#ifdef UNICODE + typedef WSASERVICECLASSINFOW WSASERVICECLASSINFO; + typedef PWSASERVICECLASSINFOW PWSASERVICECLASSINFO; + typedef LPWSASERVICECLASSINFOW LPWSASERVICECLASSINFO; +#else + typedef WSASERVICECLASSINFOA WSASERVICECLASSINFO; + typedef PWSASERVICECLASSINFOA PWSASERVICECLASSINFO; + typedef LPWSASERVICECLASSINFOA LPWSASERVICECLASSINFO; +#endif + + typedef struct _WSANAMESPACE_INFOA { + GUID NSProviderId; + DWORD dwNameSpace; + WINBOOL fActive; + DWORD dwVersion; + LPSTR lpszIdentifier; + } WSANAMESPACE_INFOA,*PWSANAMESPACE_INFOA,*LPWSANAMESPACE_INFOA; + + typedef struct _WSANAMESPACE_INFOW { + GUID NSProviderId; + DWORD dwNameSpace; + WINBOOL fActive; + DWORD dwVersion; + LPWSTR lpszIdentifier; + } WSANAMESPACE_INFOW,*PWSANAMESPACE_INFOW,*LPWSANAMESPACE_INFOW; + +#ifdef UNICODE + typedef WSANAMESPACE_INFOW WSANAMESPACE_INFO; + typedef PWSANAMESPACE_INFOW PWSANAMESPACE_INFO; + typedef LPWSANAMESPACE_INFOW LPWSANAMESPACE_INFO; +#else + typedef WSANAMESPACE_INFOA WSANAMESPACE_INFO; + typedef PWSANAMESPACE_INFOA PWSANAMESPACE_INFO; + typedef LPWSANAMESPACE_INFOA LPWSANAMESPACE_INFO; +#endif + +#if INCL_WINSOCK_API_TYPEDEFS +#ifdef UNICODE +#define LPFN_WSADUPLICATESOCKET LPFN_WSADUPLICATESOCKETW +#define LPFN_WSAENUMPROTOCOLS LPFN_WSAENUMPROTOCOLSW +#define LPFN_WSASOCKET LPFN_WSASOCKETW +#define LPFN_WSAADDRESSTOSTRING LPFN_WSAADDRESSTOSTRINGW +#define LPFN_WSASTRINGTOADDRESS LPFN_WSASTRINGTOADDRESSW +#define LPFN_WSALOOKUPSERVICEBEGIN LPFN_WSALOOKUPSERVICEBEGINW +#define LPFN_WSALOOKUPSERVICENEXT LPFN_WSALOOKUPSERVICENEXTW +#define LPFN_WSAINSTALLSERVICECLASS LPFN_WSAINSTALLSERVICECLASSW +#define LPFN_WSAGETSERVICECLASSINFO LPFN_WSAGETSERVICECLASSINFOW +#define LPFN_WSAENUMNAMESPACEPROVIDERS LPFN_WSAENUMNAMESPACEPROVIDERSW +#define LPFN_WSAGETSERVICECLASSNAMEBYCLASSID LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDW +#define LPFN_WSASETSERVICE LPFN_WSASETSERVICEW +#else +#define LPFN_WSADUPLICATESOCKET LPFN_WSADUPLICATESOCKETA +#define LPFN_WSAENUMPROTOCOLS LPFN_WSAENUMPROTOCOLSA +#define LPFN_WSASOCKET LPFN_WSASOCKETA +#define LPFN_WSAADDRESSTOSTRING LPFN_WSAADDRESSTOSTRINGA +#define LPFN_WSASTRINGTOADDRESS LPFN_WSASTRINGTOADDRESSA +#define LPFN_WSALOOKUPSERVICEBEGIN LPFN_WSALOOKUPSERVICEBEGINA +#define LPFN_WSALOOKUPSERVICENEXT LPFN_WSALOOKUPSERVICENEXTA +#define LPFN_WSAINSTALLSERVICECLASS LPFN_WSAINSTALLSERVICECLASSA +#define LPFN_WSAGETSERVICECLASSINFO LPFN_WSAGETSERVICECLASSINFOA +#define LPFN_WSAENUMNAMESPACEPROVIDERS LPFN_WSAENUMNAMESPACEPROVIDERSA +#define LPFN_WSAGETSERVICECLASSNAMEBYCLASSID LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDA +#define LPFN_WSASETSERVICE LPFN_WSASETSERVICEA +#endif + + typedef SOCKET (WSAAPI *LPFN_ACCEPT)(SOCKET s,struct sockaddr *addr,int *addrlen); + typedef int (WSAAPI *LPFN_BIND)(SOCKET s,const struct sockaddr *name,int namelen); + typedef int (WSAAPI *LPFN_CLOSESOCKET)(SOCKET s); + typedef int (WSAAPI *LPFN_CONNECT)(SOCKET s,const struct sockaddr *name,int namelen); + typedef int (WSAAPI *LPFN_IOCTLSOCKET)(SOCKET s,long cmd,u_long *argp); + typedef int (WSAAPI *LPFN_GETPEERNAME)(SOCKET s,struct sockaddr *name,int *namelen); + typedef int (WSAAPI *LPFN_GETSOCKNAME)(SOCKET s,struct sockaddr *name,int *namelen); + typedef int (WSAAPI *LPFN_GETSOCKOPT)(SOCKET s,int level,int optname,char *optval,int *optlen); + typedef u_long (WSAAPI *LPFN_HTONL)(u_long hostlong); + typedef u_short (WSAAPI *LPFN_HTONS)(u_short hostshort); + typedef unsigned long (WSAAPI *LPFN_INET_ADDR)(const char *cp); + typedef char *(WSAAPI *LPFN_INET_NTOA)(struct in_addr in); + typedef int (WSAAPI *LPFN_LISTEN)(SOCKET s,int backlog); + typedef u_long (WSAAPI *LPFN_NTOHL)(u_long netlong); + typedef u_short (WSAAPI *LPFN_NTOHS)(u_short netshort); + typedef int (WSAAPI *LPFN_RECV)(SOCKET s,char *buf,int len,int flags); + typedef int (WSAAPI *LPFN_RECVFROM)(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen); + typedef int (WSAAPI *LPFN_SELECT)(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout); + typedef int (WSAAPI *LPFN_SEND)(SOCKET s,const char *buf,int len,int flags); + typedef int (WSAAPI *LPFN_SENDTO)(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen); + typedef int (WSAAPI *LPFN_SETSOCKOPT)(SOCKET s,int level,int optname,const char *optval,int optlen); + typedef int (WSAAPI *LPFN_SHUTDOWN)(SOCKET s,int how); + typedef SOCKET (WSAAPI *LPFN_SOCKET)(int af,int type,int protocol); + typedef struct hostent *(WSAAPI *LPFN_GETHOSTBYADDR)(const char *addr,int len,int type); + typedef struct hostent *(WSAAPI *LPFN_GETHOSTBYNAME)(const char *name); + typedef int (WSAAPI *LPFN_GETHOSTNAME)(char *name,int namelen); + typedef struct servent *(WSAAPI *LPFN_GETSERVBYPORT)(int port,const char *proto); + typedef struct servent *(WSAAPI *LPFN_GETSERVBYNAME)(const char *name,const char *proto); + typedef struct protoent *(WSAAPI *LPFN_GETPROTOBYNUMBER)(int number); + typedef struct protoent *(WSAAPI *LPFN_GETPROTOBYNAME)(const char *name); + typedef int (WSAAPI *LPFN_WSASTARTUP)(WORD wVersionRequested,LPWSADATA lpWSAData); + typedef int (WSAAPI *LPFN_WSACLEANUP)(void); + typedef void (WSAAPI *LPFN_WSASETLASTERROR)(int iError); + typedef int (WSAAPI *LPFN_WSAGETLASTERROR)(void); + typedef WINBOOL (WSAAPI *LPFN_WSAISBLOCKING)(void); + typedef int (WSAAPI *LPFN_WSAUNHOOKBLOCKINGHOOK)(void); + typedef FARPROC (WSAAPI *LPFN_WSASETBLOCKINGHOOK)(FARPROC lpBlockFunc); + typedef int (WSAAPI *LPFN_WSACANCELBLOCKINGCALL)(void); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETSERVBYNAME)(HWND hWnd,u_int wMsg,const char *name,const char *proto,char *buf,int buflen); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETSERVBYPORT)(HWND hWnd,u_int wMsg,int port,const char *proto,char *buf,int buflen); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETPROTOBYNAME)(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETPROTOBYNUMBER)(HWND hWnd,u_int wMsg,int number,char *buf,int buflen); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETHOSTBYNAME)(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); + typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETHOSTBYADDR)(HWND hWnd,u_int wMsg,const char *addr,int len,int type,char *buf,int buflen); + typedef int (WSAAPI *LPFN_WSACANCELASYNCREQUEST)(HANDLE hAsyncTaskHandle); + typedef int (WSAAPI *LPFN_WSAASYNCSELECT)(SOCKET s,HWND hWnd,u_int wMsg,long lEvent); + typedef SOCKET (WSAAPI *LPFN_WSAACCEPT)(SOCKET s,struct sockaddr *addr,LPINT addrlen,LPCONDITIONPROC lpfnCondition,DWORD_PTR dwCallbackData); + typedef WINBOOL (WSAAPI *LPFN_WSACLOSEEVENT)(WSAEVENT hEvent); + typedef int (WSAAPI *LPFN_WSACONNECT)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS); + typedef WSAEVENT (WSAAPI *LPFN_WSACREATEEVENT)(void); + typedef int (WSAAPI *LPFN_WSADUPLICATESOCKETA)(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOA lpProtocolInfo); + typedef int (WSAAPI *LPFN_WSADUPLICATESOCKETW)(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOW lpProtocolInfo); + typedef int (WSAAPI *LPFN_WSAENUMNETWORKEVENTS)(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents); + typedef int (WSAAPI *LPFN_WSAENUMPROTOCOLSA)(LPINT lpiProtocols,LPWSAPROTOCOL_INFOA lpProtocolBuffer,LPDWORD lpdwBufferLength); + typedef int (WSAAPI *LPFN_WSAENUMPROTOCOLSW)(LPINT lpiProtocols,LPWSAPROTOCOL_INFOW lpProtocolBuffer,LPDWORD lpdwBufferLength); + typedef int (WSAAPI *LPFN_WSAEVENTSELECT)(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents); + typedef WINBOOL (WSAAPI *LPFN_WSAGETOVERLAPPEDRESULT)(SOCKET s,LPWSAOVERLAPPED lpOverlapped,LPDWORD lpcbTransfer,WINBOOL fWait,LPDWORD lpdwFlags); + typedef WINBOOL (WSAAPI *LPFN_WSAGETQOSBYNAME)(SOCKET s,LPWSABUF lpQOSName,LPQOS lpQOS); + typedef int (WSAAPI *LPFN_WSAHTONL)(SOCKET s,u_long hostlong,u_long *lpnetlong); + typedef int (WSAAPI *LPFN_WSAHTONS)(SOCKET s,u_short hostshort,u_short *lpnetshort); + typedef int (WSAAPI *LPFN_WSAIOCTL)(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + typedef SOCKET (WSAAPI *LPFN_WSAJOINLEAF)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,DWORD dwFlags); + typedef int (WSAAPI *LPFN_WSANTOHL)(SOCKET s,u_long netlong,u_long *lphostlong); + typedef int (WSAAPI *LPFN_WSANTOHS)(SOCKET s,u_short netshort,u_short *lphostshort); + typedef int (WSAAPI *LPFN_WSARECV)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + typedef int (WSAAPI *LPFN_WSARECVDISCONNECT)(SOCKET s,LPWSABUF lpInboundDisconnectData); + typedef int (WSAAPI *LPFN_WSARECVFROM)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,struct sockaddr *lpFrom,LPINT lpFromlen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + typedef WINBOOL (WSAAPI *LPFN_WSARESETEVENT)(WSAEVENT hEvent); + typedef int (WSAAPI *LPFN_WSASEND)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + typedef int (WSAAPI *LPFN_WSASENDDISCONNECT)(SOCKET s,LPWSABUF lpOutboundDisconnectData); + typedef int (WSAAPI *LPFN_WSASENDTO)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,const struct sockaddr *lpTo,int iTolen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + typedef WINBOOL (WSAAPI *LPFN_WSASETEVENT)(WSAEVENT hEvent); + typedef SOCKET (WSAAPI *LPFN_WSASOCKETA)(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags); + typedef SOCKET (WSAAPI *LPFN_WSASOCKETW)(int af,int type,int protocol,LPWSAPROTOCOL_INFOW lpProtocolInfo,GROUP g,DWORD dwFlags); + typedef DWORD (WSAAPI *LPFN_WSAWAITFORMULTIPLEEVENTS)(DWORD cEvents,const WSAEVENT *lphEvents,WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable); + typedef INT (WSAAPI *LPFN_WSAADDRESSTOSTRINGA)(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSTR lpszAddressString,LPDWORD lpdwAddressStringLength); + typedef INT (WSAAPI *LPFN_WSAADDRESSTOSTRINGW)(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPWSTR lpszAddressString,LPDWORD lpdwAddressStringLength); + typedef INT (WSAAPI *LPFN_WSASTRINGTOADDRESSA)(LPSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); + typedef INT (WSAAPI *LPFN_WSASTRINGTOADDRESSW)(LPWSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); + typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEBEGINA)(LPWSAQUERYSETA lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); + typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEBEGINW)(LPWSAQUERYSETW lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); + typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICENEXTA)(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETA lpqsResults); + typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICENEXTW)(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETW lpqsResults); + typedef INT (WSAAPI *LPFN_WSANSPIOCTL)(HANDLE hLookup,DWORD dwControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSACOMPLETION lpCompletion); + typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEEND)(HANDLE hLookup); + typedef INT (WSAAPI *LPFN_WSAINSTALLSERVICECLASSA)(LPWSASERVICECLASSINFOA lpServiceClassInfo); + typedef INT (WSAAPI *LPFN_WSAINSTALLSERVICECLASSW)(LPWSASERVICECLASSINFOW lpServiceClassInfo); + typedef INT (WSAAPI *LPFN_WSAREMOVESERVICECLASS)(LPGUID lpServiceClassId); + typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSINFOA)(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOA lpServiceClassInfo); + typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSINFOW)(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOW lpServiceClassInfo); + typedef INT (WSAAPI *LPFN_WSAENUMNAMESPACEPROVIDERSA)(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOA lpnspBuffer); + typedef INT (WSAAPI *LPFN_WSAENUMNAMESPACEPROVIDERSW)(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOW lpnspBuffer); + typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDA)(LPGUID lpServiceClassId,LPSTR lpszServiceClassName,LPDWORD lpdwBufferLength); + typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDW)(LPGUID lpServiceClassId,LPWSTR lpszServiceClassName,LPDWORD lpdwBufferLength); + typedef INT (WSAAPI *LPFN_WSASETSERVICEA)(LPWSAQUERYSETA lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); + typedef INT (WSAAPI *LPFN_WSASETSERVICEW)(LPWSAQUERYSETW lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); + typedef INT (WSAAPI *LPFN_WSAPROVIDERCONFIGCHANGE)(LPHANDLE lpNotificationHandle,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); +#endif + +#ifdef UNICODE +#define WSADuplicateSocket WSADuplicateSocketW +#define WSAEnumProtocols WSAEnumProtocolsW +#define WSAAddressToString WSAAddressToStringW +#define WSASocket WSASocketW +#define WSAStringToAddress WSAStringToAddressW +#define WSALookupServiceBegin WSALookupServiceBeginW +#define WSALookupServiceNext WSALookupServiceNextW +#define WSAInstallServiceClass WSAInstallServiceClassW +#define WSAGetServiceClassInfo WSAGetServiceClassInfoW +#define WSAEnumNameSpaceProviders WSAEnumNameSpaceProvidersW +#define WSAGetServiceClassNameByClassId WSAGetServiceClassNameByClassIdW +#define WSASetService WSASetServiceW +#else +#define WSADuplicateSocket WSADuplicateSocketA +#define WSAEnumProtocols WSAEnumProtocolsA +#define WSASocket WSASocketA +#define WSAAddressToString WSAAddressToStringA +#define WSAStringToAddress WSAStringToAddressA +#define WSALookupServiceBegin WSALookupServiceBeginA +#define WSALookupServiceNext WSALookupServiceNextA +#define WSAInstallServiceClass WSAInstallServiceClassA +#define WSAGetServiceClassInfo WSAGetServiceClassInfoA +#define WSAEnumNameSpaceProviders WSAEnumNameSpaceProvidersA +#define WSAGetServiceClassNameByClassId WSAGetServiceClassNameByClassIdA +#define WSASetService WSASetServiceA +#endif + + WINSOCK_API_LINKAGE SOCKET WSAAPI accept(SOCKET s,struct sockaddr *addr,int *addrlen); + WINSOCK_API_LINKAGE int WSAAPI bind(SOCKET s,const struct sockaddr *name,int namelen); + WINSOCK_API_LINKAGE int WSAAPI closesocket(SOCKET s); + WINSOCK_API_LINKAGE int WSAAPI connect(SOCKET s,const struct sockaddr *name,int namelen); + WINSOCK_API_LINKAGE int WSAAPI ioctlsocket(SOCKET s,long cmd,u_long *argp); + WINSOCK_API_LINKAGE int WSAAPI getpeername(SOCKET s,struct sockaddr *name,int *namelen); + WINSOCK_API_LINKAGE int WSAAPI getsockname(SOCKET s,struct sockaddr *name,int *namelen); + WINSOCK_API_LINKAGE int WSAAPI getsockopt(SOCKET s,int level,int optname,char *optval,int *optlen); + WINSOCK_API_LINKAGE u_long WSAAPI htonl(u_long hostlong); + WINSOCK_API_LINKAGE u_short WSAAPI htons(u_short hostshort); + WINSOCK_API_LINKAGE unsigned long WSAAPI inet_addr(const char *cp); + WINSOCK_API_LINKAGE char *WSAAPI inet_ntoa(struct in_addr in); + WINSOCK_API_LINKAGE int WSAAPI listen(SOCKET s,int backlog); + WINSOCK_API_LINKAGE u_long WSAAPI ntohl(u_long netlong); + WINSOCK_API_LINKAGE u_short WSAAPI ntohs(u_short netshort); + WINSOCK_API_LINKAGE int WSAAPI recv(SOCKET s,char *buf,int len,int flags); + WINSOCK_API_LINKAGE int WSAAPI recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen); + WINSOCK_API_LINKAGE int WSAAPI select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout); + WINSOCK_API_LINKAGE int WSAAPI send(SOCKET s,const char *buf,int len,int flags); + WINSOCK_API_LINKAGE int WSAAPI sendto(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen); + WINSOCK_API_LINKAGE int WSAAPI setsockopt(SOCKET s,int level,int optname,const char *optval,int optlen); + WINSOCK_API_LINKAGE int WSAAPI shutdown(SOCKET s,int how); + WINSOCK_API_LINKAGE SOCKET WSAAPI socket(int af,int type,int protocol); + WINSOCK_API_LINKAGE struct hostent *WSAAPI gethostbyaddr(const char *addr,int len,int type); + WINSOCK_API_LINKAGE struct hostent *WSAAPI gethostbyname(const char *name); + WINSOCK_API_LINKAGE int WSAAPI gethostname(char *name,int namelen); + WINSOCK_API_LINKAGE struct servent *WSAAPI getservbyport(int port,const char *proto); + WINSOCK_API_LINKAGE struct servent *WSAAPI getservbyname(const char *name,const char *proto); + WINSOCK_API_LINKAGE struct protoent *WSAAPI getprotobynumber(int number); + WINSOCK_API_LINKAGE struct protoent *WSAAPI getprotobyname(const char *name); + WINSOCK_API_LINKAGE int WSAAPI WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData); + WINSOCK_API_LINKAGE int WSAAPI WSACleanup(void); + WINSOCK_API_LINKAGE void WSAAPI WSASetLastError(int iError); + WINSOCK_API_LINKAGE int WSAAPI WSAGetLastError(void); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAIsBlocking(void); + WINSOCK_API_LINKAGE int WSAAPI WSAUnhookBlockingHook(void); + WINSOCK_API_LINKAGE FARPROC WSAAPI WSASetBlockingHook(FARPROC lpBlockFunc); + WINSOCK_API_LINKAGE int WSAAPI WSACancelBlockingCall(void); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetServByName(HWND hWnd,u_int wMsg,const char *name,const char *proto,char *buf,int buflen); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetServByPort(HWND hWnd,u_int wMsg,int port,const char *proto,char *buf,int buflen); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetProtoByName(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetProtoByNumber(HWND hWnd,u_int wMsg,int number,char *buf,int buflen); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetHostByName(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen); + WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetHostByAddr(HWND hWnd,u_int wMsg,const char *addr,int len,int type,char *buf,int buflen); + WINSOCK_API_LINKAGE int WSAAPI WSACancelAsyncRequest(HANDLE hAsyncTaskHandle); + WINSOCK_API_LINKAGE int WSAAPI WSAAsyncSelect(SOCKET s,HWND hWnd,u_int wMsg,long lEvent); + WINSOCK_API_LINKAGE SOCKET WSAAPI WSAAccept(SOCKET s,struct sockaddr *addr,LPINT addrlen,LPCONDITIONPROC lpfnCondition,DWORD_PTR dwCallbackData); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSACloseEvent(WSAEVENT hEvent); + WINSOCK_API_LINKAGE int WSAAPI WSAConnect(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS); + WINSOCK_API_LINKAGE WSAEVENT WSAAPI WSACreateEvent(void); + WINSOCK_API_LINKAGE int WSAAPI WSADuplicateSocketA(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOA lpProtocolInfo); + WINSOCK_API_LINKAGE int WSAAPI WSADuplicateSocketW(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOW lpProtocolInfo); + WINSOCK_API_LINKAGE int WSAAPI WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents); + WINSOCK_API_LINKAGE int WSAAPI WSAEnumProtocolsA(LPINT lpiProtocols,LPWSAPROTOCOL_INFOA lpProtocolBuffer,LPDWORD lpdwBufferLength); + WINSOCK_API_LINKAGE int WSAAPI WSAEnumProtocolsW(LPINT lpiProtocols,LPWSAPROTOCOL_INFOW lpProtocolBuffer,LPDWORD lpdwBufferLength); + WINSOCK_API_LINKAGE int WSAAPI WSAEventSelect(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAGetOverlappedResult(SOCKET s,LPWSAOVERLAPPED lpOverlapped,LPDWORD lpcbTransfer,WINBOOL fWait,LPDWORD lpdwFlags); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAGetQOSByName(SOCKET s,LPWSABUF lpQOSName,LPQOS lpQOS); + WINSOCK_API_LINKAGE int WSAAPI WSAHtonl(SOCKET s,u_long hostlong,u_long *lpnetlong); + WINSOCK_API_LINKAGE int WSAAPI WSAHtons(SOCKET s,u_short hostshort,u_short *lpnetshort); + WINSOCK_API_LINKAGE int WSAAPI WSAIoctl(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINSOCK_API_LINKAGE SOCKET WSAAPI WSAJoinLeaf(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,DWORD dwFlags); + WINSOCK_API_LINKAGE int WSAAPI WSANtohl(SOCKET s,u_long netlong,u_long *lphostlong); + WINSOCK_API_LINKAGE int WSAAPI WSANtohs(SOCKET s,u_short netshort,u_short *lphostshort); + WINSOCK_API_LINKAGE int WSAAPI WSARecv(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINSOCK_API_LINKAGE int WSAAPI WSARecvDisconnect(SOCKET s,LPWSABUF lpInboundDisconnectData); + WINSOCK_API_LINKAGE int WSAAPI WSARecvFrom(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,struct sockaddr *lpFrom,LPINT lpFromlen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAResetEvent(WSAEVENT hEvent); + WINSOCK_API_LINKAGE int WSAAPI WSASend(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINSOCK_API_LINKAGE int WSAAPI WSASendDisconnect(SOCKET s,LPWSABUF lpOutboundDisconnectData); + WINSOCK_API_LINKAGE int WSAAPI WSASendTo(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,const struct sockaddr *lpTo,int iTolen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + WINSOCK_API_LINKAGE WINBOOL WSAAPI WSASetEvent(WSAEVENT hEvent); + WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketA(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags); + WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketW(int af,int type,int protocol,LPWSAPROTOCOL_INFOW lpProtocolInfo,GROUP g,DWORD dwFlags); + WINSOCK_API_LINKAGE DWORD WSAAPI WSAWaitForMultipleEvents(DWORD cEvents,const WSAEVENT *lphEvents,WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable); + WINSOCK_API_LINKAGE INT WSAAPI WSAAddressToStringA(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSTR lpszAddressString,LPDWORD lpdwAddressStringLength); + WINSOCK_API_LINKAGE INT WSAAPI WSAAddressToStringW(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPWSTR lpszAddressString,LPDWORD lpdwAddressStringLength); + WINSOCK_API_LINKAGE INT WSAAPI WSAStringToAddressA(LPSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); + WINSOCK_API_LINKAGE INT WSAAPI WSAStringToAddressW(LPWSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength); + WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceBeginA(LPWSAQUERYSETA lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); + WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceBeginW(LPWSAQUERYSETW lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup); + WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceNextA(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETA lpqsResults); + WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceNextW(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETW lpqsResults); + WINSOCK_API_LINKAGE INT WSAAPI WSANSPIoctl(HANDLE hLookup,DWORD dwControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSACOMPLETION lpCompletion); + WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceEnd(HANDLE hLookup); + WINSOCK_API_LINKAGE INT WSAAPI WSAInstallServiceClassA(LPWSASERVICECLASSINFOA lpServiceClassInfo); + WINSOCK_API_LINKAGE INT WSAAPI WSAInstallServiceClassW(LPWSASERVICECLASSINFOW lpServiceClassInfo); + WINSOCK_API_LINKAGE INT WSAAPI WSARemoveServiceClass(LPGUID lpServiceClassId); + WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassInfoA(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOA lpServiceClassInfo); + WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassInfoW(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOW lpServiceClassInfo); + WINSOCK_API_LINKAGE INT WSAAPI WSAEnumNameSpaceProvidersA(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOA lpnspBuffer); + WINSOCK_API_LINKAGE INT WSAAPI WSAEnumNameSpaceProvidersW(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOW lpnspBuffer); + WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassNameByClassIdA(LPGUID lpServiceClassId,LPSTR lpszServiceClassName,LPDWORD lpdwBufferLength); + WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassNameByClassIdW(LPGUID lpServiceClassId,LPWSTR lpszServiceClassName,LPDWORD lpdwBufferLength); + WINSOCK_API_LINKAGE INT WSAAPI WSASetServiceA(LPWSAQUERYSETA lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); + WINSOCK_API_LINKAGE INT WSAAPI WSASetServiceW(LPWSAQUERYSETW lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags); + WINSOCK_API_LINKAGE INT WSAAPI WSAProviderConfigChange(LPHANDLE lpNotificationHandle,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); + + typedef struct sockaddr_in SOCKADDR_IN; + typedef struct sockaddr_in *PSOCKADDR_IN; + typedef struct sockaddr_in *LPSOCKADDR_IN; + + typedef struct linger LINGER; + typedef struct linger *PLINGER; + typedef struct linger *LPLINGER; + + typedef struct in_addr IN_ADDR; + typedef struct in_addr *PIN_ADDR; + typedef struct in_addr *LPIN_ADDR; + + typedef struct fd_set FD_SET; + typedef struct fd_set *PFD_SET; + typedef struct fd_set *LPFD_SET; + + typedef struct hostent HOSTENT; + typedef struct hostent *PHOSTENT; + typedef struct hostent *LPHOSTENT; + + typedef struct servent SERVENT; + typedef struct servent *PSERVENT; + typedef struct servent *LPSERVENT; + + typedef struct protoent PROTOENT; + typedef struct protoent *PPROTOENT; + typedef struct protoent *LPPROTOENT; + + typedef struct timeval TIMEVAL; + typedef struct timeval *PTIMEVAL; + typedef struct timeval *LPTIMEVAL; + +#define WSAMAKEASYNCREPLY(buflen,error) MAKELONG(buflen,error) +#define WSAMAKESELECTREPLY(event,error) MAKELONG(event,error) +#define WSAGETASYNCBUFLEN(lParam) LOWORD(lParam) +#define WSAGETASYNCERROR(lParam) HIWORD(lParam) +#define WSAGETSELECTEVENT(lParam) LOWORD(lParam) +#define WSAGETSELECTERROR(lParam) HIWORD(lParam) + +/* #if (_WIN32_WINNT >= 0x0600) */ +#define POLLRDNORM 0x0100 +#define POLLRDBAND 0x0200 +#define POLLIN (POLLRDNORM | POLLRDBAND) +#define POLLPRI 0x0400 + +#define POLLWRNORM 0x0010 +#define POLLOUT (POLLWRNORM) +#define POLLWRBAND 0x0020 + +#define POLLERR 0x0001 +#define POLLHUP 0x0002 +#define POLLNVAL 0x0004 + +typedef struct pollfd { + SOCKET fd; + SHORT events; + SHORT revents; +} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; + +WINSOCK_API_LINKAGE int WSAAPI WSAPoll(LPWSAPOLLFD fdArray, ULONG fds, INT timeout); +/* #endif // (_WIN32_WINNT >= 0x0600) */ + +#ifdef __cplusplus +} +#endif + +#ifdef _NEED_POPPACK +#include +#endif + +#ifdef IPV6STRICT +#include +#endif + +#ifndef _WINSOCKAPI_ +#define _WINSOCKAPI_ +#endif + +#ifdef _INC_WINSOCK_H +#include +#endif + +#endif diff --git a/tcc/include/winapi/winuser.h b/tcc/include/winapi/winuser.h index a28526fb..4cd9ffb5 100644 --- a/tcc/include/winapi/winuser.h +++ b/tcc/include/winapi/winuser.h @@ -1,5651 +1,5651 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WINUSER_ -#define _WINUSER_ - -#define WINUSERAPI DECLSPEC_IMPORT - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WINVER -#define WINVER 0x0502 -#endif - -#include - -#ifndef NOUSER - typedef HANDLE HDWP; - typedef VOID MENUTEMPLATEA; - typedef VOID MENUTEMPLATEW; - typedef PVOID LPMENUTEMPLATEA; - typedef PVOID LPMENUTEMPLATEW; - -#ifdef UNICODE - typedef MENUTEMPLATEW MENUTEMPLATE; - typedef LPMENUTEMPLATEW LPMENUTEMPLATE; -#else - typedef MENUTEMPLATEA MENUTEMPLATE; - typedef LPMENUTEMPLATEA LPMENUTEMPLATE; -#endif - - typedef LRESULT (CALLBACK *WNDPROC)(HWND,UINT,WPARAM,LPARAM); - typedef INT_PTR (CALLBACK *DLGPROC)(HWND,UINT,WPARAM,LPARAM); - typedef VOID (CALLBACK *TIMERPROC)(HWND,UINT,UINT_PTR,DWORD); - typedef WINBOOL (CALLBACK *GRAYSTRINGPROC)(HDC,LPARAM,int); - typedef WINBOOL (CALLBACK *WNDENUMPROC)(HWND,LPARAM); - typedef LRESULT (CALLBACK *HOOKPROC)(int code,WPARAM wParam,LPARAM lParam); - typedef VOID (CALLBACK *SENDASYNCPROC)(HWND,UINT,ULONG_PTR,LRESULT); - typedef WINBOOL (CALLBACK *PROPENUMPROCA)(HWND,LPCSTR,HANDLE); - typedef WINBOOL (CALLBACK *PROPENUMPROCW)(HWND,LPCWSTR,HANDLE); - typedef WINBOOL (CALLBACK *PROPENUMPROCEXA)(HWND,LPSTR,HANDLE,ULONG_PTR); - typedef WINBOOL (CALLBACK *PROPENUMPROCEXW)(HWND,LPWSTR,HANDLE,ULONG_PTR); - typedef int (CALLBACK *EDITWORDBREAKPROCA)(LPSTR lpch,int ichCurrent,int cch,int code); - typedef int (CALLBACK *EDITWORDBREAKPROCW)(LPWSTR lpch,int ichCurrent,int cch,int code); - typedef WINBOOL (CALLBACK *DRAWSTATEPROC)(HDC hdc,LPARAM lData,WPARAM wData,int cx,int cy); - -#ifdef UNICODE - typedef PROPENUMPROCW PROPENUMPROC; - typedef PROPENUMPROCEXW PROPENUMPROCEX; - typedef EDITWORDBREAKPROCW EDITWORDBREAKPROC; -#else - typedef PROPENUMPROCA PROPENUMPROC; - typedef PROPENUMPROCEXA PROPENUMPROCEX; - typedef EDITWORDBREAKPROCA EDITWORDBREAKPROC; -#endif - - typedef WINBOOL (CALLBACK *NAMEENUMPROCA)(LPSTR,LPARAM); - typedef WINBOOL (CALLBACK *NAMEENUMPROCW)(LPWSTR,LPARAM); - typedef NAMEENUMPROCA WINSTAENUMPROCA; - typedef NAMEENUMPROCA DESKTOPENUMPROCA; - typedef NAMEENUMPROCW WINSTAENUMPROCW; - typedef NAMEENUMPROCW DESKTOPENUMPROCW; - -#ifdef UNICODE - typedef WINSTAENUMPROCW WINSTAENUMPROC; - typedef DESKTOPENUMPROCW DESKTOPENUMPROC; -#else - typedef WINSTAENUMPROCA WINSTAENUMPROC; - typedef DESKTOPENUMPROCA DESKTOPENUMPROC; -#endif - -#define IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16)==0) -#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i)))) -#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i)))) -#ifdef UNICODE -#define MAKEINTRESOURCE MAKEINTRESOURCEW -#else -#define MAKEINTRESOURCE MAKEINTRESOURCEA -#endif - -#ifndef NORESOURCE - -#define RT_CURSOR MAKEINTRESOURCE(1) -#define RT_BITMAP MAKEINTRESOURCE(2) -#define RT_ICON MAKEINTRESOURCE(3) -#define RT_MENU MAKEINTRESOURCE(4) -#define RT_DIALOG MAKEINTRESOURCE(5) -#define RT_STRING MAKEINTRESOURCE(6) -#define RT_FONTDIR MAKEINTRESOURCE(7) -#define RT_FONT MAKEINTRESOURCE(8) -#define RT_ACCELERATOR MAKEINTRESOURCE(9) -#define RT_RCDATA MAKEINTRESOURCE(10) -#define RT_MESSAGETABLE MAKEINTRESOURCE(11) - -#define DIFFERENCE 11 -#define RT_GROUP_CURSOR MAKEINTRESOURCE((ULONG_PTR)RT_CURSOR + DIFFERENCE) -#define RT_GROUP_ICON MAKEINTRESOURCE((ULONG_PTR)RT_ICON + DIFFERENCE) -#define RT_VERSION MAKEINTRESOURCE(16) -#define RT_DLGINCLUDE MAKEINTRESOURCE(17) -#define RT_PLUGPLAY MAKEINTRESOURCE(19) -#define RT_VXD MAKEINTRESOURCE(20) -#define RT_ANICURSOR MAKEINTRESOURCE(21) -#define RT_ANIICON MAKEINTRESOURCE(22) -#define RT_HTML MAKEINTRESOURCE(23) -#ifdef RC_INVOKED -#define RT_MANIFEST 24 -#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 -#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 -#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3 -#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID 1 -#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID 16 -#else -#define RT_MANIFEST MAKEINTRESOURCE(24) -#define CREATEPROCESS_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) -#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(2) -#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(3) -#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) -#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(16) -#endif -#endif - -#ifdef UNICODE -#define wvsprintf wvsprintfW -#define wsprintf wsprintfW -#else -#define wvsprintf wvsprintfA -#define wsprintf wsprintfA -#endif - - WINUSERAPI int WINAPI wvsprintfA(LPSTR,LPCSTR,va_list arglist); - WINUSERAPI int WINAPI wvsprintfW(LPWSTR,LPCWSTR,va_list arglist); - WINUSERAPI int WINAPIV wsprintfA(LPSTR,LPCSTR,...); - WINUSERAPI int WINAPIV wsprintfW(LPWSTR,LPCWSTR,...); - -#define SETWALLPAPER_DEFAULT ((LPWSTR)-1) - -#ifndef NOSCROLL -#define SB_HORZ 0 -#define SB_VERT 1 -#define SB_CTL 2 -#define SB_BOTH 3 - -#define SB_LINEUP 0 -#define SB_LINELEFT 0 -#define SB_LINEDOWN 1 -#define SB_LINERIGHT 1 -#define SB_PAGEUP 2 -#define SB_PAGELEFT 2 -#define SB_PAGEDOWN 3 -#define SB_PAGERIGHT 3 -#define SB_THUMBPOSITION 4 -#define SB_THUMBTRACK 5 -#define SB_TOP 6 -#define SB_LEFT 6 -#define SB_BOTTOM 7 -#define SB_RIGHT 7 -#define SB_ENDSCROLL 8 -#endif - -#ifndef NOSHOWWINDOW -#define SW_HIDE 0 -#define SW_SHOWNORMAL 1 -#define SW_NORMAL 1 -#define SW_SHOWMINIMIZED 2 -#define SW_SHOWMAXIMIZED 3 -#define SW_MAXIMIZE 3 -#define SW_SHOWNOACTIVATE 4 -#define SW_SHOW 5 -#define SW_MINIMIZE 6 -#define SW_SHOWMINNOACTIVE 7 -#define SW_SHOWNA 8 -#define SW_RESTORE 9 -#define SW_SHOWDEFAULT 10 -#define SW_FORCEMINIMIZE 11 -#define SW_MAX 11 - -#define HIDE_WINDOW 0 -#define SHOW_OPENWINDOW 1 -#define SHOW_ICONWINDOW 2 -#define SHOW_FULLSCREEN 3 -#define SHOW_OPENNOACTIVATE 4 - -#define SW_PARENTCLOSING 1 -#define SW_OTHERZOOM 2 -#define SW_PARENTOPENING 3 -#define SW_OTHERUNZOOM 4 -#endif - -#define AW_HOR_POSITIVE 0x00000001 -#define AW_HOR_NEGATIVE 0x00000002 -#define AW_VER_POSITIVE 0x00000004 -#define AW_VER_NEGATIVE 0x00000008 -#define AW_CENTER 0x00000010 -#define AW_HIDE 0x00010000 -#define AW_ACTIVATE 0x00020000 -#define AW_SLIDE 0x00040000 -#define AW_BLEND 0x00080000 - -#define KF_EXTENDED 0x0100 -#define KF_DLGMODE 0x0800 -#define KF_MENUMODE 0x1000 -#define KF_ALTDOWN 0x2000 -#define KF_REPEAT 0x4000 -#define KF_UP 0x8000 - -#ifndef NOVIRTUALKEYCODES - -#define VK_LBUTTON 0x01 -#define VK_RBUTTON 0x02 -#define VK_CANCEL 0x03 -#define VK_MBUTTON 0x04 -#define VK_XBUTTON1 0x05 -#define VK_XBUTTON2 0x06 -#define VK_BACK 0x08 -#define VK_TAB 0x09 -#define VK_CLEAR 0x0C -#define VK_RETURN 0x0D -#define VK_SHIFT 0x10 -#define VK_CONTROL 0x11 -#define VK_MENU 0x12 -#define VK_PAUSE 0x13 -#define VK_CAPITAL 0x14 -#define VK_KANA 0x15 -#define VK_HANGEUL 0x15 -#define VK_HANGUL 0x15 -#define VK_JUNJA 0x17 -#define VK_FINAL 0x18 -#define VK_HANJA 0x19 -#define VK_KANJI 0x19 -#define VK_ESCAPE 0x1B -#define VK_CONVERT 0x1C -#define VK_NONCONVERT 0x1D -#define VK_ACCEPT 0x1E -#define VK_MODECHANGE 0x1F -#define VK_SPACE 0x20 -#define VK_PRIOR 0x21 -#define VK_NEXT 0x22 -#define VK_END 0x23 -#define VK_HOME 0x24 -#define VK_LEFT 0x25 -#define VK_UP 0x26 -#define VK_RIGHT 0x27 -#define VK_DOWN 0x28 -#define VK_SELECT 0x29 -#define VK_PRINT 0x2A -#define VK_EXECUTE 0x2B -#define VK_SNAPSHOT 0x2C -#define VK_INSERT 0x2D -#define VK_DELETE 0x2E -#define VK_HELP 0x2F - -#define VK_LWIN 0x5B -#define VK_RWIN 0x5C -#define VK_APPS 0x5D -#define VK_SLEEP 0x5F -#define VK_NUMPAD0 0x60 -#define VK_NUMPAD1 0x61 -#define VK_NUMPAD2 0x62 -#define VK_NUMPAD3 0x63 -#define VK_NUMPAD4 0x64 -#define VK_NUMPAD5 0x65 -#define VK_NUMPAD6 0x66 -#define VK_NUMPAD7 0x67 -#define VK_NUMPAD8 0x68 -#define VK_NUMPAD9 0x69 -#define VK_MULTIPLY 0x6A -#define VK_ADD 0x6B -#define VK_SEPARATOR 0x6C -#define VK_SUBTRACT 0x6D -#define VK_DECIMAL 0x6E -#define VK_DIVIDE 0x6F -#define VK_F1 0x70 -#define VK_F2 0x71 -#define VK_F3 0x72 -#define VK_F4 0x73 -#define VK_F5 0x74 -#define VK_F6 0x75 -#define VK_F7 0x76 -#define VK_F8 0x77 -#define VK_F9 0x78 -#define VK_F10 0x79 -#define VK_F11 0x7A -#define VK_F12 0x7B -#define VK_F13 0x7C -#define VK_F14 0x7D -#define VK_F15 0x7E -#define VK_F16 0x7F -#define VK_F17 0x80 -#define VK_F18 0x81 -#define VK_F19 0x82 -#define VK_F20 0x83 -#define VK_F21 0x84 -#define VK_F22 0x85 -#define VK_F23 0x86 -#define VK_F24 0x87 -#define VK_NUMLOCK 0x90 -#define VK_SCROLL 0x91 -#define VK_OEM_NEC_EQUAL 0x92 -#define VK_OEM_FJ_JISHO 0x92 -#define VK_OEM_FJ_MASSHOU 0x93 -#define VK_OEM_FJ_TOUROKU 0x94 -#define VK_OEM_FJ_LOYA 0x95 -#define VK_OEM_FJ_ROYA 0x96 -#define VK_LSHIFT 0xA0 -#define VK_RSHIFT 0xA1 -#define VK_LCONTROL 0xA2 -#define VK_RCONTROL 0xA3 -#define VK_LMENU 0xA4 -#define VK_RMENU 0xA5 -#define VK_BROWSER_BACK 0xA6 -#define VK_BROWSER_FORWARD 0xA7 -#define VK_BROWSER_REFRESH 0xA8 -#define VK_BROWSER_STOP 0xA9 -#define VK_BROWSER_SEARCH 0xAA -#define VK_BROWSER_FAVORITES 0xAB -#define VK_BROWSER_HOME 0xAC -#define VK_VOLUME_MUTE 0xAD -#define VK_VOLUME_DOWN 0xAE -#define VK_VOLUME_UP 0xAF -#define VK_MEDIA_NEXT_TRACK 0xB0 -#define VK_MEDIA_PREV_TRACK 0xB1 -#define VK_MEDIA_STOP 0xB2 -#define VK_MEDIA_PLAY_PAUSE 0xB3 -#define VK_LAUNCH_MAIL 0xB4 -#define VK_LAUNCH_MEDIA_SELECT 0xB5 -#define VK_LAUNCH_APP1 0xB6 -#define VK_LAUNCH_APP2 0xB7 -#define VK_OEM_1 0xBA -#define VK_OEM_PLUS 0xBB -#define VK_OEM_COMMA 0xBC -#define VK_OEM_MINUS 0xBD -#define VK_OEM_PERIOD 0xBE -#define VK_OEM_2 0xBF -#define VK_OEM_3 0xC0 -#define VK_OEM_4 0xDB -#define VK_OEM_5 0xDC -#define VK_OEM_6 0xDD -#define VK_OEM_7 0xDE -#define VK_OEM_8 0xDF -#define VK_OEM_AX 0xE1 -#define VK_OEM_102 0xE2 -#define VK_ICO_HELP 0xE3 -#define VK_ICO_00 0xE4 -#define VK_PROCESSKEY 0xE5 -#define VK_ICO_CLEAR 0xE6 -#define VK_PACKET 0xE7 -#define VK_OEM_RESET 0xE9 -#define VK_OEM_JUMP 0xEA -#define VK_OEM_PA1 0xEB -#define VK_OEM_PA2 0xEC -#define VK_OEM_PA3 0xED -#define VK_OEM_WSCTRL 0xEE -#define VK_OEM_CUSEL 0xEF -#define VK_OEM_ATTN 0xF0 -#define VK_OEM_FINISH 0xF1 -#define VK_OEM_COPY 0xF2 -#define VK_OEM_AUTO 0xF3 -#define VK_OEM_ENLW 0xF4 -#define VK_OEM_BACKTAB 0xF5 -#define VK_ATTN 0xF6 -#define VK_CRSEL 0xF7 -#define VK_EXSEL 0xF8 -#define VK_EREOF 0xF9 -#define VK_PLAY 0xFA -#define VK_ZOOM 0xFB -#define VK_NONAME 0xFC -#define VK_PA1 0xFD -#define VK_OEM_CLEAR 0xFE -#endif - -#ifndef NOWH - -#define WH_MIN (-1) -#define WH_MSGFILTER (-1) -#define WH_JOURNALRECORD 0 -#define WH_JOURNALPLAYBACK 1 -#define WH_KEYBOARD 2 -#define WH_GETMESSAGE 3 -#define WH_CALLWNDPROC 4 -#define WH_CBT 5 -#define WH_SYSMSGFILTER 6 -#define WH_MOUSE 7 -#define WH_HARDWARE 8 -#define WH_DEBUG 9 -#define WH_SHELL 10 -#define WH_FOREGROUNDIDLE 11 -#define WH_CALLWNDPROCRET 12 - -#define WH_KEYBOARD_LL 13 -#define WH_MOUSE_LL 14 - -#define WH_MAX 14 - -#define WH_MINHOOK WH_MIN -#define WH_MAXHOOK WH_MAX - -#define HC_ACTION 0 -#define HC_GETNEXT 1 -#define HC_SKIP 2 -#define HC_NOREMOVE 3 -#define HC_NOREM HC_NOREMOVE -#define HC_SYSMODALON 4 -#define HC_SYSMODALOFF 5 - -#define HCBT_MOVESIZE 0 -#define HCBT_MINMAX 1 -#define HCBT_QS 2 -#define HCBT_CREATEWND 3 -#define HCBT_DESTROYWND 4 -#define HCBT_ACTIVATE 5 -#define HCBT_CLICKSKIPPED 6 -#define HCBT_KEYSKIPPED 7 -#define HCBT_SYSCOMMAND 8 -#define HCBT_SETFOCUS 9 - - typedef struct tagCBT_CREATEWNDA { - struct tagCREATESTRUCTA *lpcs; - HWND hwndInsertAfter; - } CBT_CREATEWNDA,*LPCBT_CREATEWNDA; - - typedef struct tagCBT_CREATEWNDW { - struct tagCREATESTRUCTW *lpcs; - HWND hwndInsertAfter; - } CBT_CREATEWNDW,*LPCBT_CREATEWNDW; -#ifdef UNICODE - typedef CBT_CREATEWNDW CBT_CREATEWND; - typedef LPCBT_CREATEWNDW LPCBT_CREATEWND; -#else - typedef CBT_CREATEWNDA CBT_CREATEWND; - typedef LPCBT_CREATEWNDA LPCBT_CREATEWND; -#endif - - typedef struct tagCBTACTIVATESTRUCT - { - WINBOOL fMouse; - HWND hWndActive; - } CBTACTIVATESTRUCT,*LPCBTACTIVATESTRUCT; - - typedef struct tagWTSSESSION_NOTIFICATION { - DWORD cbSize; - DWORD dwSessionId; - - } WTSSESSION_NOTIFICATION,*PWTSSESSION_NOTIFICATION; - -#define WTS_CONSOLE_CONNECT 0x1 -#define WTS_CONSOLE_DISCONNECT 0x2 -#define WTS_REMOTE_CONNECT 0x3 -#define WTS_REMOTE_DISCONNECT 0x4 -#define WTS_SESSION_LOGON 0x5 -#define WTS_SESSION_LOGOFF 0x6 -#define WTS_SESSION_LOCK 0x7 -#define WTS_SESSION_UNLOCK 0x8 -#define WTS_SESSION_REMOTE_CONTROL 0x9 - -#define MSGF_DIALOGBOX 0 -#define MSGF_MESSAGEBOX 1 -#define MSGF_MENU 2 -#define MSGF_SCROLLBAR 5 -#define MSGF_NEXTWINDOW 6 -#define MSGF_MAX 8 -#define MSGF_USER 4096 - -#define HSHELL_WINDOWCREATED 1 -#define HSHELL_WINDOWDESTROYED 2 -#define HSHELL_ACTIVATESHELLWINDOW 3 - -#define HSHELL_WINDOWACTIVATED 4 -#define HSHELL_GETMINRECT 5 -#define HSHELL_REDRAW 6 -#define HSHELL_TASKMAN 7 -#define HSHELL_LANGUAGE 8 -#define HSHELL_SYSMENU 9 -#define HSHELL_ENDTASK 10 -#define HSHELL_ACCESSIBILITYSTATE 11 -#define HSHELL_APPCOMMAND 12 -#define HSHELL_WINDOWREPLACED 13 -#define HSHELL_WINDOWREPLACING 14 -#define HSHELL_HIGHBIT 0x8000 -#define HSHELL_FLASH (HSHELL_REDRAW|HSHELL_HIGHBIT) -#define HSHELL_RUDEAPPACTIVATED (HSHELL_WINDOWACTIVATED|HSHELL_HIGHBIT) - -#define ACCESS_STICKYKEYS 0x0001 -#define ACCESS_FILTERKEYS 0x0002 -#define ACCESS_MOUSEKEYS 0x0003 - -#define APPCOMMAND_BROWSER_BACKWARD 1 -#define APPCOMMAND_BROWSER_FORWARD 2 -#define APPCOMMAND_BROWSER_REFRESH 3 -#define APPCOMMAND_BROWSER_STOP 4 -#define APPCOMMAND_BROWSER_SEARCH 5 -#define APPCOMMAND_BROWSER_FAVORITES 6 -#define APPCOMMAND_BROWSER_HOME 7 -#define APPCOMMAND_VOLUME_MUTE 8 -#define APPCOMMAND_VOLUME_DOWN 9 -#define APPCOMMAND_VOLUME_UP 10 -#define APPCOMMAND_MEDIA_NEXTTRACK 11 -#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12 -#define APPCOMMAND_MEDIA_STOP 13 -#define APPCOMMAND_MEDIA_PLAY_PAUSE 14 -#define APPCOMMAND_LAUNCH_MAIL 15 -#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16 -#define APPCOMMAND_LAUNCH_APP1 17 -#define APPCOMMAND_LAUNCH_APP2 18 -#define APPCOMMAND_BASS_DOWN 19 -#define APPCOMMAND_BASS_BOOST 20 -#define APPCOMMAND_BASS_UP 21 -#define APPCOMMAND_TREBLE_DOWN 22 -#define APPCOMMAND_TREBLE_UP 23 -#define APPCOMMAND_MICROPHONE_VOLUME_MUTE 24 -#define APPCOMMAND_MICROPHONE_VOLUME_DOWN 25 -#define APPCOMMAND_MICROPHONE_VOLUME_UP 26 -#define APPCOMMAND_HELP 27 -#define APPCOMMAND_FIND 28 -#define APPCOMMAND_NEW 29 -#define APPCOMMAND_OPEN 30 -#define APPCOMMAND_CLOSE 31 -#define APPCOMMAND_SAVE 32 -#define APPCOMMAND_PRINT 33 -#define APPCOMMAND_UNDO 34 -#define APPCOMMAND_REDO 35 -#define APPCOMMAND_COPY 36 -#define APPCOMMAND_CUT 37 -#define APPCOMMAND_PASTE 38 -#define APPCOMMAND_REPLY_TO_MAIL 39 -#define APPCOMMAND_FORWARD_MAIL 40 -#define APPCOMMAND_SEND_MAIL 41 -#define APPCOMMAND_SPELL_CHECK 42 -#define APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE 43 -#define APPCOMMAND_MIC_ON_OFF_TOGGLE 44 -#define APPCOMMAND_CORRECTION_LIST 45 -#define APPCOMMAND_MEDIA_PLAY 46 -#define APPCOMMAND_MEDIA_PAUSE 47 -#define APPCOMMAND_MEDIA_RECORD 48 -#define APPCOMMAND_MEDIA_FAST_FORWARD 49 -#define APPCOMMAND_MEDIA_REWIND 50 -#define APPCOMMAND_MEDIA_CHANNEL_UP 51 -#define APPCOMMAND_MEDIA_CHANNEL_DOWN 52 - -#define FAPPCOMMAND_MOUSE 0x8000 -#define FAPPCOMMAND_KEY 0 -#define FAPPCOMMAND_OEM 0x1000 -#define FAPPCOMMAND_MASK 0xF000 - -#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK)) -#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK)) -#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM -#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam)) -#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam) - - typedef struct { - HWND hwnd; - RECT rc; - } SHELLHOOKINFO,*LPSHELLHOOKINFO; - - typedef struct tagEVENTMSG { - UINT message; - UINT paramL; - UINT paramH; - DWORD time; - HWND hwnd; - } EVENTMSG,*PEVENTMSGMSG,*NPEVENTMSGMSG,*LPEVENTMSGMSG; - - typedef struct tagEVENTMSG *PEVENTMSG,*NPEVENTMSG,*LPEVENTMSG; - - typedef struct tagCWPSTRUCT { - LPARAM lParam; - WPARAM wParam; - UINT message; - HWND hwnd; - } CWPSTRUCT,*PCWPSTRUCT,*NPCWPSTRUCT,*LPCWPSTRUCT; - - typedef struct tagCWPRETSTRUCT { - LRESULT lResult; - LPARAM lParam; - WPARAM wParam; - UINT message; - HWND hwnd; - } CWPRETSTRUCT,*PCWPRETSTRUCT,*NPCWPRETSTRUCT,*LPCWPRETSTRUCT; - -#define LLKHF_EXTENDED (KF_EXTENDED >> 8) -#define LLKHF_INJECTED 0x00000010 -#define LLKHF_ALTDOWN (KF_ALTDOWN >> 8) -#define LLKHF_UP (KF_UP >> 8) - -#define LLMHF_INJECTED 0x00000001 - - typedef struct tagKBDLLHOOKSTRUCT { - DWORD vkCode; - DWORD scanCode; - DWORD flags; - DWORD time; - ULONG_PTR dwExtraInfo; - } KBDLLHOOKSTRUCT,*LPKBDLLHOOKSTRUCT,*PKBDLLHOOKSTRUCT; - - typedef struct tagMSLLHOOKSTRUCT { - POINT pt; - DWORD mouseData; - DWORD flags; - DWORD time; - ULONG_PTR dwExtraInfo; - } MSLLHOOKSTRUCT,*LPMSLLHOOKSTRUCT,*PMSLLHOOKSTRUCT; - - typedef struct tagDEBUGHOOKINFO { - DWORD idThread; - DWORD idThreadInstaller; - LPARAM lParam; - WPARAM wParam; - int code; - } DEBUGHOOKINFO,*PDEBUGHOOKINFO,*NPDEBUGHOOKINFO,*LPDEBUGHOOKINFO; - - typedef struct tagMOUSEHOOKSTRUCT { - POINT pt; - HWND hwnd; - UINT wHitTestCode; - ULONG_PTR dwExtraInfo; - } MOUSEHOOKSTRUCT,*LPMOUSEHOOKSTRUCT,*PMOUSEHOOKSTRUCT; - -#ifdef __cplusplus - typedef struct tagMOUSEHOOKSTRUCTEX : public tagMOUSEHOOKSTRUCT { - DWORD mouseData; - } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; -#else - typedef struct tagMOUSEHOOKSTRUCTEX { - MOUSEHOOKSTRUCT _unnamed; - DWORD mouseData; - } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; -#endif - - typedef struct tagHARDWAREHOOKSTRUCT { - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; - } HARDWAREHOOKSTRUCT,*LPHARDWAREHOOKSTRUCT,*PHARDWAREHOOKSTRUCT; -#endif - -#define HKL_PREV 0 -#define HKL_NEXT 1 - -#define KLF_ACTIVATE 0x00000001 -#define KLF_SUBSTITUTE_OK 0x00000002 -#define KLF_REORDER 0x00000008 -#define KLF_REPLACELANG 0x00000010 -#define KLF_NOTELLSHELL 0x00000080 -#define KLF_SETFORPROCESS 0x00000100 -#define KLF_SHIFTLOCK 0x00010000 -#define KLF_RESET 0x40000000 - -#define INPUTLANGCHANGE_SYSCHARSET 0x0001 -#define INPUTLANGCHANGE_FORWARD 0x0002 -#define INPUTLANGCHANGE_BACKWARD 0x0004 - -#define KL_NAMELENGTH 9 - -#ifdef UNICODE -#define LoadKeyboardLayout LoadKeyboardLayoutW -#define GetKeyboardLayoutName GetKeyboardLayoutNameW -#else -#define LoadKeyboardLayout LoadKeyboardLayoutA -#define GetKeyboardLayoutName GetKeyboardLayoutNameA -#endif - - WINUSERAPI HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID,UINT Flags); - WINUSERAPI HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID,UINT Flags); - WINUSERAPI HKL WINAPI ActivateKeyboardLayout(HKL hkl,UINT Flags); - WINUSERAPI int WINAPI ToUnicodeEx(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags,HKL dwhkl); - WINUSERAPI WINBOOL WINAPI UnloadKeyboardLayout(HKL hkl); - WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameA(LPSTR pwszKLID); - WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID); - WINUSERAPI int WINAPI GetKeyboardLayoutList(int nBuff,HKL *lpList); - WINUSERAPI HKL WINAPI GetKeyboardLayout(DWORD idThread); - - typedef struct tagMOUSEMOVEPOINT { - int x; - int y; - DWORD time; - ULONG_PTR dwExtraInfo; - } MOUSEMOVEPOINT,*PMOUSEMOVEPOINT,*LPMOUSEMOVEPOINT; - -#define GMMP_USE_DISPLAY_POINTS 1 -#define GMMP_USE_HIGH_RESOLUTION_POINTS 2 - - WINUSERAPI int WINAPI GetMouseMovePointsEx(UINT cbSize,LPMOUSEMOVEPOINT lppt,LPMOUSEMOVEPOINT lpptBuf,int nBufPoints,DWORD resolution); - -#ifndef NODESKTOP - -#define DESKTOP_READOBJECTS 0x0001L -#define DESKTOP_CREATEWINDOW 0x0002L -#define DESKTOP_CREATEMENU 0x0004L -#define DESKTOP_HOOKCONTROL 0x0008L -#define DESKTOP_JOURNALRECORD 0x0010L -#define DESKTOP_JOURNALPLAYBACK 0x0020L -#define DESKTOP_ENUMERATE 0x0040L -#define DESKTOP_WRITEOBJECTS 0x0080L -#define DESKTOP_SWITCHDESKTOP 0x0100L - -#define DF_ALLOWOTHERACCOUNTHOOK 0x0001L - -#ifdef _WINGDI_ -#ifndef NOGDI -#ifdef UNICODE -#define CreateDesktop CreateDesktopW -#else -#define CreateDesktop CreateDesktopA -#endif - - WINUSERAPI HDESK WINAPI CreateDesktopA(LPCSTR lpszDesktop,LPCSTR lpszDevice,LPDEVMODEA pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); - WINUSERAPI HDESK WINAPI CreateDesktopW(LPCWSTR lpszDesktop,LPCWSTR lpszDevice,LPDEVMODEW pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); -#endif -#endif - -#ifdef UNICODE -#define OpenDesktop OpenDesktopW -#define EnumDesktops EnumDesktopsW -#else -#define OpenDesktop OpenDesktopA -#define EnumDesktops EnumDesktopsA -#endif - - WINUSERAPI HDESK WINAPI OpenDesktopA(LPCSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI HDESK WINAPI OpenDesktopW(LPCWSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI HDESK WINAPI OpenInputDesktop(DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI WINBOOL WINAPI EnumDesktopsA(HWINSTA hwinsta,DESKTOPENUMPROCA lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumDesktopsW(HWINSTA hwinsta,DESKTOPENUMPROCW lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumDesktopWindows(HDESK hDesktop,WNDENUMPROC lpfn,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI SwitchDesktop(HDESK hDesktop); - WINUSERAPI WINBOOL WINAPI SetThreadDesktop(HDESK hDesktop); - WINUSERAPI WINBOOL WINAPI CloseDesktop(HDESK hDesktop); - WINUSERAPI HDESK WINAPI GetThreadDesktop(DWORD dwThreadId); -#endif - -#ifndef NOWINDOWSTATION -#define WINSTA_ENUMDESKTOPS 0x0001L -#define WINSTA_READATTRIBUTES 0x0002L -#define WINSTA_ACCESSCLIPBOARD 0x0004L -#define WINSTA_CREATEDESKTOP 0x0008L -#define WINSTA_WRITEATTRIBUTES 0x0010L -#define WINSTA_ACCESSGLOBALATOMS 0x0020L -#define WINSTA_EXITWINDOWS 0x0040L -#define WINSTA_ENUMERATE 0x0100L -#define WINSTA_READSCREEN 0x0200L -#define WINSTA_ALL_ACCESS (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN) - -#define CWF_CREATE_ONLY 0x0001L - -#define WSF_VISIBLE 0x0001L - -#ifdef UNICODE -#define CreateWindowStation CreateWindowStationW -#define OpenWindowStation OpenWindowStationW -#define EnumWindowStations EnumWindowStationsW -#else -#define CreateWindowStation CreateWindowStationA -#define OpenWindowStation OpenWindowStationA -#define EnumWindowStations EnumWindowStationsA -#endif - - WINUSERAPI HWINSTA WINAPI CreateWindowStationA(LPCSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); - WINUSERAPI HWINSTA WINAPI CreateWindowStationW(LPCWSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); - WINUSERAPI HWINSTA WINAPI OpenWindowStationA(LPCSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI HWINSTA WINAPI OpenWindowStationW(LPCWSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); - WINUSERAPI WINBOOL WINAPI EnumWindowStationsA(WINSTAENUMPROCA lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumWindowStationsW(WINSTAENUMPROCW lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI CloseWindowStation(HWINSTA hWinSta); - WINUSERAPI WINBOOL WINAPI SetProcessWindowStation(HWINSTA hWinSta); - WINUSERAPI HWINSTA WINAPI GetProcessWindowStation(VOID); -#endif - -#ifndef NOSECURITY - WINUSERAPI WINBOOL WINAPI SetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID); - WINUSERAPI WINBOOL WINAPI GetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID,DWORD nLength,LPDWORD lpnLengthNeeded); - -#define UOI_FLAGS 1 -#define UOI_NAME 2 -#define UOI_TYPE 3 -#define UOI_USER_SID 4 - - typedef struct tagUSEROBJECTFLAGS { - WINBOOL fInherit; - WINBOOL fReserved; - DWORD dwFlags; - } USEROBJECTFLAGS,*PUSEROBJECTFLAGS; - -#ifdef UNICODE -#define GetUserObjectInformation GetUserObjectInformationW -#define SetUserObjectInformation SetUserObjectInformationW -#else -#define GetUserObjectInformation GetUserObjectInformationA -#define SetUserObjectInformation SetUserObjectInformationA -#endif - - WINUSERAPI WINBOOL WINAPI GetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); - WINUSERAPI WINBOOL WINAPI GetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); - WINUSERAPI WINBOOL WINAPI SetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); - WINUSERAPI WINBOOL WINAPI SetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); -#endif - - typedef struct tagWNDCLASSEXA { - UINT cbSize; - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCSTR lpszMenuName; - LPCSTR lpszClassName; - HICON hIconSm; - } WNDCLASSEXA,*PWNDCLASSEXA,*NPWNDCLASSEXA,*LPWNDCLASSEXA; - - typedef struct tagWNDCLASSEXW { - UINT cbSize; - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCWSTR lpszMenuName; - LPCWSTR lpszClassName; - - HICON hIconSm; - } WNDCLASSEXW,*PWNDCLASSEXW,*NPWNDCLASSEXW,*LPWNDCLASSEXW; - -#ifdef UNICODE - typedef WNDCLASSEXW WNDCLASSEX; - typedef PWNDCLASSEXW PWNDCLASSEX; - typedef NPWNDCLASSEXW NPWNDCLASSEX; - typedef LPWNDCLASSEXW LPWNDCLASSEX; -#else - typedef WNDCLASSEXA WNDCLASSEX; - typedef PWNDCLASSEXA PWNDCLASSEX; - typedef NPWNDCLASSEXA NPWNDCLASSEX; - typedef LPWNDCLASSEXA LPWNDCLASSEX; -#endif - - typedef struct tagWNDCLASSA { - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCSTR lpszMenuName; - LPCSTR lpszClassName; - } WNDCLASSA,*PWNDCLASSA,*NPWNDCLASSA,*LPWNDCLASSA; - - typedef struct tagWNDCLASSW { - UINT style; - WNDPROC lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HINSTANCE hInstance; - HICON hIcon; - HCURSOR hCursor; - HBRUSH hbrBackground; - LPCWSTR lpszMenuName; - LPCWSTR lpszClassName; - } WNDCLASSW,*PWNDCLASSW,*NPWNDCLASSW,*LPWNDCLASSW; - -#ifdef UNICODE - typedef WNDCLASSW WNDCLASS; - typedef PWNDCLASSW PWNDCLASS; - typedef NPWNDCLASSW NPWNDCLASS; - typedef LPWNDCLASSW LPWNDCLASS; -#else - typedef WNDCLASSA WNDCLASS; - typedef PWNDCLASSA PWNDCLASS; - typedef NPWNDCLASSA NPWNDCLASS; - typedef LPWNDCLASSA LPWNDCLASS; -#endif - - WINUSERAPI WINBOOL WINAPI IsHungAppWindow(HWND hwnd); - WINUSERAPI VOID WINAPI DisableProcessWindowsGhosting(VOID); - -#ifndef NOMSG - typedef struct tagMSG { - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; - DWORD time; - POINT pt; - } MSG,*PMSG,*NPMSG,*LPMSG; - -#define POINTSTOPOINT(pt,pts) { (pt).x = (LONG)(SHORT)LOWORD(*(LONG*)&pts); (pt).y = (LONG)(SHORT)HIWORD(*(LONG*)&pts); } - -#define POINTTOPOINTS(pt) (MAKELONG((short)((pt).x),(short)((pt).y))) -#define MAKEWPARAM(l,h) ((WPARAM)(DWORD)MAKELONG(l,h)) -#define MAKELPARAM(l,h) ((LPARAM)(DWORD)MAKELONG(l,h)) -#define MAKELRESULT(l,h) ((LRESULT)(DWORD)MAKELONG(l,h)) -#endif - -#ifndef NOWINOFFSETS -#define GWL_WNDPROC (-4) -#define GWL_HINSTANCE (-6) -#define GWL_HWNDPARENT (-8) -#define GWL_STYLE (-16) -#define GWL_EXSTYLE (-20) -#define GWL_USERDATA (-21) -#define GWL_ID (-12) - -#ifdef _WIN64 -#undef GWL_WNDPROC -#undef GWL_HINSTANCE -#undef GWL_HWNDPARENT -#undef GWL_USERDATA -#endif - -#define GWLP_WNDPROC (-4) -#define GWLP_HINSTANCE (-6) -#define GWLP_HWNDPARENT (-8) -#define GWLP_USERDATA (-21) -#define GWLP_ID (-12) - -#define GCL_MENUNAME (-8) -#define GCL_HBRBACKGROUND (-10) -#define GCL_HCURSOR (-12) -#define GCL_HICON (-14) -#define GCL_HMODULE (-16) -#define GCL_CBWNDEXTRA (-18) -#define GCL_CBCLSEXTRA (-20) -#define GCL_WNDPROC (-24) -#define GCL_STYLE (-26) -#define GCW_ATOM (-32) -#define GCL_HICONSM (-34) - -#ifdef _WIN64 - -#undef GCL_MENUNAME -#undef GCL_HBRBACKGROUND -#undef GCL_HCURSOR -#undef GCL_HICON -#undef GCL_HMODULE -#undef GCL_WNDPROC -#undef GCL_HICONSM -#endif - -#define GCLP_MENUNAME (-8) -#define GCLP_HBRBACKGROUND (-10) -#define GCLP_HCURSOR (-12) -#define GCLP_HICON (-14) -#define GCLP_HMODULE (-16) -#define GCLP_WNDPROC (-24) -#define GCLP_HICONSM (-34) -#endif - -#ifndef NOWINMESSAGES - -#define WM_NULL 0x0000 -#define WM_CREATE 0x0001 -#define WM_DESTROY 0x0002 -#define WM_MOVE 0x0003 -#define WM_SIZE 0x0005 - -#define WM_ACTIVATE 0x0006 - -#define WA_INACTIVE 0 -#define WA_ACTIVE 1 -#define WA_CLICKACTIVE 2 - -#define WM_SETFOCUS 0x0007 -#define WM_KILLFOCUS 0x0008 -#define WM_ENABLE 0x000A -#define WM_SETREDRAW 0x000B -#define WM_SETTEXT 0x000C -#define WM_GETTEXT 0x000D -#define WM_GETTEXTLENGTH 0x000E -#define WM_PAINT 0x000F -#define WM_CLOSE 0x0010 -#ifndef _WIN32_WCE -#define WM_QUERYENDSESSION 0x0011 -#define WM_QUERYOPEN 0x0013 -#define WM_ENDSESSION 0x0016 -#endif -#define WM_QUIT 0x0012 -#define WM_ERASEBKGND 0x0014 -#define WM_SYSCOLORCHANGE 0x0015 -#define WM_SHOWWINDOW 0x0018 -#define WM_WININICHANGE 0x001A -#define WM_SETTINGCHANGE WM_WININICHANGE -#define WM_DEVMODECHANGE 0x001B -#define WM_ACTIVATEAPP 0x001C -#define WM_FONTCHANGE 0x001D -#define WM_TIMECHANGE 0x001E -#define WM_CANCELMODE 0x001F -#define WM_SETCURSOR 0x0020 -#define WM_MOUSEACTIVATE 0x0021 -#define WM_CHILDACTIVATE 0x0022 -#define WM_QUEUESYNC 0x0023 - -#define WM_GETMINMAXINFO 0x0024 - - typedef struct tagMINMAXINFO { - POINT ptReserved; - POINT ptMaxSize; - POINT ptMaxPosition; - POINT ptMinTrackSize; - POINT ptMaxTrackSize; - } MINMAXINFO,*PMINMAXINFO,*LPMINMAXINFO; - -#define WM_PAINTICON 0x0026 -#define WM_ICONERASEBKGND 0x0027 -#define WM_NEXTDLGCTL 0x0028 -#define WM_SPOOLERSTATUS 0x002A -#define WM_DRAWITEM 0x002B -#define WM_MEASUREITEM 0x002C -#define WM_DELETEITEM 0x002D -#define WM_VKEYTOITEM 0x002E -#define WM_CHARTOITEM 0x002F -#define WM_SETFONT 0x0030 -#define WM_GETFONT 0x0031 -#define WM_SETHOTKEY 0x0032 -#define WM_GETHOTKEY 0x0033 -#define WM_QUERYDRAGICON 0x0037 -#define WM_COMPAREITEM 0x0039 -#ifndef _WIN32_WCE -#define WM_GETOBJECT 0x003D -#endif -#define WM_COMPACTING 0x0041 -#define WM_COMMNOTIFY 0x0044 -#define WM_WINDOWPOSCHANGING 0x0046 -#define WM_WINDOWPOSCHANGED 0x0047 - -#define WM_POWER 0x0048 - -#define PWR_OK 1 -#define PWR_FAIL (-1) -#define PWR_SUSPENDREQUEST 1 -#define PWR_SUSPENDRESUME 2 -#define PWR_CRITICALRESUME 3 - -#define WM_COPYDATA 0x004A -#define WM_CANCELJOURNAL 0x004B - - typedef struct tagCOPYDATASTRUCT { - ULONG_PTR dwData; - DWORD cbData; - PVOID lpData; - } COPYDATASTRUCT,*PCOPYDATASTRUCT; - - typedef struct tagMDINEXTMENU { - HMENU hmenuIn; - HMENU hmenuNext; - HWND hwndNext; - } MDINEXTMENU,*PMDINEXTMENU,*LPMDINEXTMENU; - -#define WM_NOTIFY 0x004E -#define WM_INPUTLANGCHANGEREQUEST 0x0050 -#define WM_INPUTLANGCHANGE 0x0051 -#define WM_TCARD 0x0052 -#define WM_HELP 0x0053 -#define WM_USERCHANGED 0x0054 -#define WM_NOTIFYFORMAT 0x0055 - -#define NFR_ANSI 1 -#define NFR_UNICODE 2 -#define NF_QUERY 3 -#define NF_REQUERY 4 - -#define WM_CONTEXTMENU 0x007B -#define WM_STYLECHANGING 0x007C -#define WM_STYLECHANGED 0x007D -#define WM_DISPLAYCHANGE 0x007E -#define WM_GETICON 0x007F -#define WM_SETICON 0x0080 - -#define WM_NCCREATE 0x0081 -#define WM_NCDESTROY 0x0082 -#define WM_NCCALCSIZE 0x0083 -#define WM_NCHITTEST 0x0084 -#define WM_NCPAINT 0x0085 -#define WM_NCACTIVATE 0x0086 -#define WM_GETDLGCODE 0x0087 -#ifndef _WIN32_WCE -#define WM_SYNCPAINT 0x0088 -#endif -#define WM_NCMOUSEMOVE 0x00A0 -#define WM_NCLBUTTONDOWN 0x00A1 -#define WM_NCLBUTTONUP 0x00A2 -#define WM_NCLBUTTONDBLCLK 0x00A3 -#define WM_NCRBUTTONDOWN 0x00A4 -#define WM_NCRBUTTONUP 0x00A5 -#define WM_NCRBUTTONDBLCLK 0x00A6 -#define WM_NCMBUTTONDOWN 0x00A7 -#define WM_NCMBUTTONUP 0x00A8 -#define WM_NCMBUTTONDBLCLK 0x00A9 - -#define WM_NCXBUTTONDOWN 0x00AB -#define WM_NCXBUTTONUP 0x00AC -#define WM_NCXBUTTONDBLCLK 0x00AD -#define WM_INPUT 0x00FF -#define WM_KEYFIRST 0x0100 -#define WM_KEYDOWN 0x0100 -#define WM_KEYUP 0x0101 -#define WM_CHAR 0x0102 -#define WM_DEADCHAR 0x0103 -#define WM_SYSKEYDOWN 0x0104 -#define WM_SYSKEYUP 0x0105 -#define WM_SYSCHAR 0x0106 -#define WM_SYSDEADCHAR 0x0107 -#define WM_UNICHAR 0x0109 -#define WM_KEYLAST 0x0109 -#define UNICODE_NOCHAR 0xFFFF -#define WM_IME_STARTCOMPOSITION 0x010D -#define WM_IME_ENDCOMPOSITION 0x010E -#define WM_IME_COMPOSITION 0x010F -#define WM_IME_KEYLAST 0x010F -#define WM_INITDIALOG 0x0110 -#define WM_COMMAND 0x0111 -#define WM_SYSCOMMAND 0x0112 -#define WM_TIMER 0x0113 -#define WM_HSCROLL 0x0114 -#define WM_VSCROLL 0x0115 -#define WM_INITMENU 0x0116 -#define WM_INITMENUPOPUP 0x0117 -#define WM_MENUSELECT 0x011F -#define WM_MENUCHAR 0x0120 -#define WM_ENTERIDLE 0x0121 -#ifndef _WIN32_WCE -#define WM_MENURBUTTONUP 0x0122 -#define WM_MENUDRAG 0x0123 -#define WM_MENUGETOBJECT 0x0124 -#define WM_UNINITMENUPOPUP 0x0125 -#define WM_MENUCOMMAND 0x0126 - -#ifndef _WIN32_WCE -#define WM_CHANGEUISTATE 0x0127 -#define WM_UPDATEUISTATE 0x0128 -#define WM_QUERYUISTATE 0x0129 - -#define UIS_SET 1 -#define UIS_CLEAR 2 -#define UIS_INITIALIZE 3 - -#define UISF_HIDEFOCUS 0x1 -#define UISF_HIDEACCEL 0x2 -#define UISF_ACTIVE 0x4 -#endif -#endif - -#define WM_CTLCOLORMSGBOX 0x0132 -#define WM_CTLCOLOREDIT 0x0133 -#define WM_CTLCOLORLISTBOX 0x0134 -#define WM_CTLCOLORBTN 0x0135 -#define WM_CTLCOLORDLG 0x0136 -#define WM_CTLCOLORSCROLLBAR 0x0137 -#define WM_CTLCOLORSTATIC 0x0138 -#define MN_GETHMENU 0x01E1 - -#define WM_MOUSEFIRST 0x0200 -#define WM_MOUSEMOVE 0x0200 -#define WM_LBUTTONDOWN 0x0201 -#define WM_LBUTTONUP 0x0202 -#define WM_LBUTTONDBLCLK 0x0203 -#define WM_RBUTTONDOWN 0x0204 -#define WM_RBUTTONUP 0x0205 -#define WM_RBUTTONDBLCLK 0x0206 -#define WM_MBUTTONDOWN 0x0207 -#define WM_MBUTTONUP 0x0208 -#define WM_MBUTTONDBLCLK 0x0209 -#define WM_MOUSEWHEEL 0x020A -#define WM_XBUTTONDOWN 0x020B -#define WM_XBUTTONUP 0x020C -#define WM_XBUTTONDBLCLK 0x020D -#define WM_MOUSELAST 0x020D - -#define WHEEL_DELTA 120 -#define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) - -#define WHEEL_PAGESCROLL (UINT_MAX) - -#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam)) -#define GET_NCHITTEST_WPARAM(wParam) ((short)LOWORD(wParam)) -#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) - -#define XBUTTON1 0x0001 -#define XBUTTON2 0x0002 - -#define WM_PARENTNOTIFY 0x0210 -#define WM_ENTERMENULOOP 0x0211 -#define WM_EXITMENULOOP 0x0212 - -#define WM_NEXTMENU 0x0213 -#define WM_SIZING 0x0214 -#define WM_CAPTURECHANGED 0x0215 -#define WM_MOVING 0x0216 - -#define WM_POWERBROADCAST 0x0218 - -#ifndef _WIN32_WCE -#define PBT_APMQUERYSUSPEND 0x0000 -#define PBT_APMQUERYSTANDBY 0x0001 - -#define PBT_APMQUERYSUSPENDFAILED 0x0002 -#define PBT_APMQUERYSTANDBYFAILED 0x0003 - -#define PBT_APMSUSPEND 0x0004 -#define PBT_APMSTANDBY 0x0005 - -#define PBT_APMRESUMECRITICAL 0x0006 -#define PBT_APMRESUMESUSPEND 0x0007 -#define PBT_APMRESUMESTANDBY 0x0008 - -#define PBTF_APMRESUMEFROMFAILURE 0x00000001 - -#define PBT_APMBATTERYLOW 0x0009 -#define PBT_APMPOWERSTATUSCHANGE 0x000A - -#define PBT_APMOEMEVENT 0x000B -#define PBT_APMRESUMEAUTOMATIC 0x0012 -#endif - -#define WM_DEVICECHANGE 0x0219 - -#define WM_MDICREATE 0x0220 -#define WM_MDIDESTROY 0x0221 -#define WM_MDIACTIVATE 0x0222 -#define WM_MDIRESTORE 0x0223 -#define WM_MDINEXT 0x0224 -#define WM_MDIMAXIMIZE 0x0225 -#define WM_MDITILE 0x0226 -#define WM_MDICASCADE 0x0227 -#define WM_MDIICONARRANGE 0x0228 -#define WM_MDIGETACTIVE 0x0229 - -#define WM_MDISETMENU 0x0230 -#define WM_ENTERSIZEMOVE 0x0231 -#define WM_EXITSIZEMOVE 0x0232 -#define WM_DROPFILES 0x0233 -#define WM_MDIREFRESHMENU 0x0234 - -#define WM_IME_SETCONTEXT 0x0281 -#define WM_IME_NOTIFY 0x0282 -#define WM_IME_CONTROL 0x0283 -#define WM_IME_COMPOSITIONFULL 0x0284 -#define WM_IME_SELECT 0x0285 -#define WM_IME_CHAR 0x0286 -#define WM_IME_REQUEST 0x0288 -#define WM_IME_KEYDOWN 0x0290 -#define WM_IME_KEYUP 0x0291 - -#define WM_MOUSEHOVER 0x02A1 -#define WM_MOUSELEAVE 0x02A3 -#define WM_NCMOUSEHOVER 0x02A0 -#define WM_NCMOUSELEAVE 0x02A2 -#define WM_WTSSESSION_CHANGE 0x02B1 -#define WM_TABLET_FIRST 0x02c0 -#define WM_TABLET_LAST 0x02df -#define WM_CUT 0x0300 -#define WM_COPY 0x0301 -#define WM_PASTE 0x0302 -#define WM_CLEAR 0x0303 -#define WM_UNDO 0x0304 -#define WM_RENDERFORMAT 0x0305 -#define WM_RENDERALLFORMATS 0x0306 -#define WM_DESTROYCLIPBOARD 0x0307 -#define WM_DRAWCLIPBOARD 0x0308 -#define WM_PAINTCLIPBOARD 0x0309 -#define WM_VSCROLLCLIPBOARD 0x030A -#define WM_SIZECLIPBOARD 0x030B -#define WM_ASKCBFORMATNAME 0x030C -#define WM_CHANGECBCHAIN 0x030D -#define WM_HSCROLLCLIPBOARD 0x030E -#define WM_QUERYNEWPALETTE 0x030F -#define WM_PALETTEISCHANGING 0x0310 -#define WM_PALETTECHANGED 0x0311 -#define WM_HOTKEY 0x0312 -#define WM_PRINT 0x0317 -#define WM_PRINTCLIENT 0x0318 -#define WM_APPCOMMAND 0x0319 -#define WM_THEMECHANGED 0x031A -#define WM_HANDHELDFIRST 0x0358 -#define WM_HANDHELDLAST 0x035F -#define WM_AFXFIRST 0x0360 -#define WM_AFXLAST 0x037F -#define WM_PENWINFIRST 0x0380 -#define WM_PENWINLAST 0x038F -#define WM_APP 0x8000 -#define WM_USER 0x0400 - -#define WMSZ_LEFT 1 -#define WMSZ_RIGHT 2 -#define WMSZ_TOP 3 -#define WMSZ_TOPLEFT 4 -#define WMSZ_TOPRIGHT 5 -#define WMSZ_BOTTOM 6 -#define WMSZ_BOTTOMLEFT 7 -#define WMSZ_BOTTOMRIGHT 8 - -#ifndef NONCMESSAGES - -#define HTERROR (-2) -#define HTTRANSPARENT (-1) -#define HTNOWHERE 0 -#define HTCLIENT 1 -#define HTCAPTION 2 -#define HTSYSMENU 3 -#define HTGROWBOX 4 -#define HTSIZE HTGROWBOX -#define HTMENU 5 -#define HTHSCROLL 6 -#define HTVSCROLL 7 -#define HTMINBUTTON 8 -#define HTMAXBUTTON 9 -#define HTLEFT 10 -#define HTRIGHT 11 -#define HTTOP 12 -#define HTTOPLEFT 13 -#define HTTOPRIGHT 14 -#define HTBOTTOM 15 -#define HTBOTTOMLEFT 16 -#define HTBOTTOMRIGHT 17 -#define HTBORDER 18 -#define HTREDUCE HTMINBUTTON -#define HTZOOM HTMAXBUTTON -#define HTSIZEFIRST HTLEFT -#define HTSIZELAST HTBOTTOMRIGHT -#define HTOBJECT 19 -#define HTCLOSE 20 -#define HTHELP 21 - -#define SMTO_NORMAL 0x0000 -#define SMTO_BLOCK 0x0001 -#define SMTO_ABORTIFHUNG 0x0002 -#define SMTO_NOTIMEOUTIFNOTHUNG 0x0008 -#endif - -#define MA_ACTIVATE 1 -#define MA_ACTIVATEANDEAT 2 -#define MA_NOACTIVATE 3 -#define MA_NOACTIVATEANDEAT 4 - -#define ICON_SMALL 0 -#define ICON_BIG 1 -#define ICON_SMALL2 2 - -#ifdef UNICODE -#define RegisterWindowMessage RegisterWindowMessageW -#else -#define RegisterWindowMessage RegisterWindowMessageA -#endif - - WINUSERAPI UINT WINAPI RegisterWindowMessageA(LPCSTR lpString); - WINUSERAPI UINT WINAPI RegisterWindowMessageW(LPCWSTR lpString); - -#define SIZE_RESTORED 0 -#define SIZE_MINIMIZED 1 -#define SIZE_MAXIMIZED 2 -#define SIZE_MAXSHOW 3 -#define SIZE_MAXHIDE 4 - -#define SIZENORMAL SIZE_RESTORED -#define SIZEICONIC SIZE_MINIMIZED -#define SIZEFULLSCREEN SIZE_MAXIMIZED -#define SIZEZOOMSHOW SIZE_MAXSHOW -#define SIZEZOOMHIDE SIZE_MAXHIDE - - typedef struct tagWINDOWPOS { - HWND hwnd; - HWND hwndInsertAfter; - int x; - int y; - int cx; - int cy; - UINT flags; - } WINDOWPOS,*LPWINDOWPOS,*PWINDOWPOS; - - typedef struct tagNCCALCSIZE_PARAMS { - RECT rgrc[3]; - PWINDOWPOS lppos; - } NCCALCSIZE_PARAMS,*LPNCCALCSIZE_PARAMS; - -#define WVR_ALIGNTOP 0x0010 -#define WVR_ALIGNLEFT 0x0020 -#define WVR_ALIGNBOTTOM 0x0040 -#define WVR_ALIGNRIGHT 0x0080 -#define WVR_HREDRAW 0x0100 -#define WVR_VREDRAW 0x0200 -#define WVR_REDRAW (WVR_HREDRAW | WVR_VREDRAW) -#define WVR_VALIDRECTS 0x0400 - -#ifndef NOKEYSTATES - -#define MK_LBUTTON 0x0001 -#define MK_RBUTTON 0x0002 -#define MK_SHIFT 0x0004 -#define MK_CONTROL 0x0008 -#define MK_MBUTTON 0x0010 -#define MK_XBUTTON1 0x0020 -#define MK_XBUTTON2 0x0040 -#endif - -#ifndef NOTRACKMOUSEEVENT -#define TME_HOVER 0x00000001 -#define TME_LEAVE 0x00000002 -#define TME_NONCLIENT 0x00000010 -#define TME_QUERY 0x40000000 -#define TME_CANCEL 0x80000000 - -#define HOVER_DEFAULT 0xFFFFFFFF -#endif - - typedef struct tagTRACKMOUSEEVENT { - DWORD cbSize; - DWORD dwFlags; - HWND hwndTrack; - DWORD dwHoverTime; - } TRACKMOUSEEVENT,*LPTRACKMOUSEEVENT; - - WINUSERAPI WINBOOL WINAPI TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack); -#endif - -#ifndef NOWINSTYLES - -#define WS_OVERLAPPED 0x00000000L -#define WS_POPUP 0x80000000L -#define WS_CHILD 0x40000000L -#define WS_MINIMIZE 0x20000000L -#define WS_VISIBLE 0x10000000L -#define WS_DISABLED 0x08000000L -#define WS_CLIPSIBLINGS 0x04000000L -#define WS_CLIPCHILDREN 0x02000000L -#define WS_MAXIMIZE 0x01000000L -#define WS_CAPTION 0x00C00000L -#define WS_BORDER 0x00800000L -#define WS_DLGFRAME 0x00400000L -#define WS_VSCROLL 0x00200000L -#define WS_HSCROLL 0x00100000L -#define WS_SYSMENU 0x00080000L -#define WS_THICKFRAME 0x00040000L -#define WS_GROUP 0x00020000L -#define WS_TABSTOP 0x00010000L -#define WS_MINIMIZEBOX 0x00020000L -#define WS_MAXIMIZEBOX 0x00010000L -#define WS_TILED WS_OVERLAPPED -#define WS_ICONIC WS_MINIMIZE -#define WS_SIZEBOX WS_THICKFRAME -#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW -#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) -#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU) -#define WS_CHILDWINDOW (WS_CHILD) - -#define WS_EX_DLGMODALFRAME 0x00000001L -#define WS_EX_NOPARENTNOTIFY 0x00000004L -#define WS_EX_TOPMOST 0x00000008L -#define WS_EX_ACCEPTFILES 0x00000010L -#define WS_EX_TRANSPARENT 0x00000020L -#define WS_EX_MDICHILD 0x00000040L -#define WS_EX_TOOLWINDOW 0x00000080L -#define WS_EX_WINDOWEDGE 0x00000100L -#define WS_EX_CLIENTEDGE 0x00000200L -#define WS_EX_CONTEXTHELP 0x00000400L -#define WS_EX_RIGHT 0x00001000L -#define WS_EX_LEFT 0x00000000L -#define WS_EX_RTLREADING 0x00002000L -#define WS_EX_LTRREADING 0x00000000L -#define WS_EX_LEFTSCROLLBAR 0x00004000L -#define WS_EX_RIGHTSCROLLBAR 0x00000000L -#define WS_EX_CONTROLPARENT 0x00010000L -#define WS_EX_STATICEDGE 0x00020000L -#define WS_EX_APPWINDOW 0x00040000L -#define WS_EX_OVERLAPPEDWINDOW (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE) -#define WS_EX_PALETTEWINDOW (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST) -#define WS_EX_LAYERED 0x00080000 -#define WS_EX_NOINHERITLAYOUT 0x00100000L -#define WS_EX_LAYOUTRTL 0x00400000L -#define WS_EX_COMPOSITED 0x02000000L -#define WS_EX_NOACTIVATE 0x08000000L - -#define CS_VREDRAW 0x0001 -#define CS_HREDRAW 0x0002 -#define CS_DBLCLKS 0x0008 -#define CS_OWNDC 0x0020 -#define CS_CLASSDC 0x0040 -#define CS_PARENTDC 0x0080 -#define CS_NOCLOSE 0x0200 -#define CS_SAVEBITS 0x0800 -#define CS_BYTEALIGNCLIENT 0x1000 -#define CS_BYTEALIGNWINDOW 0x2000 -#define CS_GLOBALCLASS 0x4000 -#define CS_IME 0x00010000 -#define CS_DROPSHADOW 0x00020000 -#endif - -#define PRF_CHECKVISIBLE 0x00000001L -#define PRF_NONCLIENT 0x00000002L -#define PRF_CLIENT 0x00000004L -#define PRF_ERASEBKGND 0x00000008L -#define PRF_CHILDREN 0x00000010L -#define PRF_OWNED 0x00000020L - -#define BDR_RAISEDOUTER 0x0001 -#define BDR_SUNKENOUTER 0x0002 -#define BDR_RAISEDINNER 0x0004 -#define BDR_SUNKENINNER 0x0008 - -#define BDR_OUTER (BDR_RAISEDOUTER | BDR_SUNKENOUTER) -#define BDR_INNER (BDR_RAISEDINNER | BDR_SUNKENINNER) -#define BDR_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) -#define BDR_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) - -#define EDGE_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) -#define EDGE_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) -#define EDGE_ETCHED (BDR_SUNKENOUTER | BDR_RAISEDINNER) -#define EDGE_BUMP (BDR_RAISEDOUTER | BDR_SUNKENINNER) - -#define BF_LEFT 0x0001 -#define BF_TOP 0x0002 -#define BF_RIGHT 0x0004 -#define BF_BOTTOM 0x0008 - -#define BF_TOPLEFT (BF_TOP | BF_LEFT) -#define BF_TOPRIGHT (BF_TOP | BF_RIGHT) -#define BF_BOTTOMLEFT (BF_BOTTOM | BF_LEFT) -#define BF_BOTTOMRIGHT (BF_BOTTOM | BF_RIGHT) -#define BF_RECT (BF_LEFT | BF_TOP | BF_RIGHT | BF_BOTTOM) - -#define BF_DIAGONAL 0x0010 - -#define BF_DIAGONAL_ENDTOPRIGHT (BF_DIAGONAL | BF_TOP | BF_RIGHT) -#define BF_DIAGONAL_ENDTOPLEFT (BF_DIAGONAL | BF_TOP | BF_LEFT) -#define BF_DIAGONAL_ENDBOTTOMLEFT (BF_DIAGONAL | BF_BOTTOM | BF_LEFT) -#define BF_DIAGONAL_ENDBOTTOMRIGHT (BF_DIAGONAL | BF_BOTTOM | BF_RIGHT) - -#define BF_MIDDLE 0x0800 -#define BF_SOFT 0x1000 -#define BF_ADJUST 0x2000 -#define BF_FLAT 0x4000 -#define BF_MONO 0x8000 - - WINUSERAPI WINBOOL WINAPI DrawEdge(HDC hdc,LPRECT qrc,UINT edge,UINT grfFlags); - -#define DFC_CAPTION 1 -#define DFC_MENU 2 -#define DFC_SCROLL 3 -#define DFC_BUTTON 4 -#define DFC_POPUPMENU 5 - -#define DFCS_CAPTIONCLOSE 0x0000 -#define DFCS_CAPTIONMIN 0x0001 -#define DFCS_CAPTIONMAX 0x0002 -#define DFCS_CAPTIONRESTORE 0x0003 -#define DFCS_CAPTIONHELP 0x0004 - -#define DFCS_MENUARROW 0x0000 -#define DFCS_MENUCHECK 0x0001 -#define DFCS_MENUBULLET 0x0002 -#define DFCS_MENUARROWRIGHT 0x0004 -#define DFCS_SCROLLUP 0x0000 -#define DFCS_SCROLLDOWN 0x0001 -#define DFCS_SCROLLLEFT 0x0002 -#define DFCS_SCROLLRIGHT 0x0003 -#define DFCS_SCROLLCOMBOBOX 0x0005 -#define DFCS_SCROLLSIZEGRIP 0x0008 -#define DFCS_SCROLLSIZEGRIPRIGHT 0x0010 - -#define DFCS_BUTTONCHECK 0x0000 -#define DFCS_BUTTONRADIOIMAGE 0x0001 -#define DFCS_BUTTONRADIOMASK 0x0002 -#define DFCS_BUTTONRADIO 0x0004 -#define DFCS_BUTTON3STATE 0x0008 -#define DFCS_BUTTONPUSH 0x0010 - -#define DFCS_INACTIVE 0x0100 -#define DFCS_PUSHED 0x0200 -#define DFCS_CHECKED 0x0400 - -#define DFCS_TRANSPARENT 0x0800 -#define DFCS_HOT 0x1000 - -#define DFCS_ADJUSTRECT 0x2000 -#define DFCS_FLAT 0x4000 -#define DFCS_MONO 0x8000 - - WINUSERAPI WINBOOL WINAPI DrawFrameControl(HDC,LPRECT,UINT,UINT); - -#define DC_ACTIVE 0x0001 -#define DC_SMALLCAP 0x0002 -#define DC_ICON 0x0004 -#define DC_TEXT 0x0008 -#define DC_INBUTTON 0x0010 -#define DC_GRADIENT 0x0020 -#define DC_BUTTONS 0x1000 - - WINUSERAPI WINBOOL WINAPI DrawCaption(HWND hwnd,HDC hdc,CONST RECT *lprect,UINT flags); - -#define IDANI_OPEN 1 -#define IDANI_CAPTION 3 - - WINUSERAPI WINBOOL WINAPI DrawAnimatedRects(HWND hwnd,int idAni,CONST RECT *lprcFrom,CONST RECT *lprcTo); - -#ifndef NOCLIPBOARD - -#define CF_TEXT 1 -#define CF_BITMAP 2 -#define CF_METAFILEPICT 3 -#define CF_SYLK 4 -#define CF_DIF 5 -#define CF_TIFF 6 -#define CF_OEMTEXT 7 -#define CF_DIB 8 -#define CF_PALETTE 9 -#define CF_PENDATA 10 -#define CF_RIFF 11 -#define CF_WAVE 12 -#define CF_UNICODETEXT 13 -#define CF_ENHMETAFILE 14 -#define CF_HDROP 15 -#define CF_LOCALE 16 -#define CF_DIBV5 17 -#define CF_MAX 18 - -#define CF_OWNERDISPLAY 0x0080 -#define CF_DSPTEXT 0x0081 -#define CF_DSPBITMAP 0x0082 -#define CF_DSPMETAFILEPICT 0x0083 -#define CF_DSPENHMETAFILE 0x008E - -#define CF_PRIVATEFIRST 0x0200 -#define CF_PRIVATELAST 0x02FF - -#define CF_GDIOBJFIRST 0x0300 -#define CF_GDIOBJLAST 0x03FF -#endif - -#define FVIRTKEY TRUE -#define FNOINVERT 0x02 -#define FSHIFT 0x04 -#define FCONTROL 0x08 -#define FALT 0x10 - - typedef struct tagACCEL { - BYTE fVirt; - WORD key; - WORD cmd; - } ACCEL,*LPACCEL; - - typedef struct tagPAINTSTRUCT { - HDC hdc; - WINBOOL fErase; - RECT rcPaint; - WINBOOL fRestore; - WINBOOL fIncUpdate; - BYTE rgbReserved[32]; - } PAINTSTRUCT,*PPAINTSTRUCT,*NPPAINTSTRUCT,*LPPAINTSTRUCT; - - typedef struct tagCREATESTRUCTA { - LPVOID lpCreateParams; - HINSTANCE hInstance; - HMENU hMenu; - HWND hwndParent; - int cy; - int cx; - int y; - int x; - LONG style; - LPCSTR lpszName; - LPCSTR lpszClass; - DWORD dwExStyle; - } CREATESTRUCTA,*LPCREATESTRUCTA; - - typedef struct tagCREATESTRUCTW { - LPVOID lpCreateParams; - HINSTANCE hInstance; - HMENU hMenu; - HWND hwndParent; - int cy; - int cx; - int y; - int x; - LONG style; - LPCWSTR lpszName; - LPCWSTR lpszClass; - DWORD dwExStyle; - } CREATESTRUCTW,*LPCREATESTRUCTW; - -#ifdef UNICODE - typedef CREATESTRUCTW CREATESTRUCT; - typedef LPCREATESTRUCTW LPCREATESTRUCT; -#else - typedef CREATESTRUCTA CREATESTRUCT; - typedef LPCREATESTRUCTA LPCREATESTRUCT; -#endif - - typedef struct tagWINDOWPLACEMENT { - UINT length; - UINT flags; - UINT showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - } WINDOWPLACEMENT; - typedef WINDOWPLACEMENT *PWINDOWPLACEMENT,*LPWINDOWPLACEMENT; - -#define WPF_SETMINPOSITION 0x0001 -#define WPF_RESTORETOMAXIMIZED 0x0002 -#define WPF_ASYNCWINDOWPLACEMENT 0x0004 - - typedef struct tagNMHDR { - HWND hwndFrom; - UINT_PTR idFrom; - UINT code; - } NMHDR; - - typedef NMHDR *LPNMHDR; - - typedef struct tagSTYLESTRUCT { - DWORD styleOld; - DWORD styleNew; - } STYLESTRUCT,*LPSTYLESTRUCT; - -#define ODT_MENU 1 -#define ODT_LISTBOX 2 -#define ODT_COMBOBOX 3 -#define ODT_BUTTON 4 -#define ODT_STATIC 5 - -#define ODA_DRAWENTIRE 0x0001 -#define ODA_SELECT 0x0002 -#define ODA_FOCUS 0x0004 - -#define ODS_SELECTED 0x0001 -#define ODS_GRAYED 0x0002 -#define ODS_DISABLED 0x0004 -#define ODS_CHECKED 0x0008 -#define ODS_FOCUS 0x0010 -#define ODS_DEFAULT 0x0020 -#define ODS_COMBOBOXEDIT 0x1000 -#define ODS_HOTLIGHT 0x0040 -#define ODS_INACTIVE 0x0080 -#define ODS_NOACCEL 0x0100 -#define ODS_NOFOCUSRECT 0x0200 - - typedef struct tagMEASUREITEMSTRUCT { - UINT CtlType; - UINT CtlID; - UINT itemID; - UINT itemWidth; - UINT itemHeight; - ULONG_PTR itemData; - } MEASUREITEMSTRUCT,*PMEASUREITEMSTRUCT,*LPMEASUREITEMSTRUCT; - - typedef struct tagDRAWITEMSTRUCT { - UINT CtlType; - UINT CtlID; - UINT itemID; - UINT itemAction; - UINT itemState; - HWND hwndItem; - HDC hDC; - RECT rcItem; - ULONG_PTR itemData; - } DRAWITEMSTRUCT,*PDRAWITEMSTRUCT,*LPDRAWITEMSTRUCT; - - typedef struct tagDELETEITEMSTRUCT { - UINT CtlType; - UINT CtlID; - UINT itemID; - HWND hwndItem; - ULONG_PTR itemData; - } DELETEITEMSTRUCT,*PDELETEITEMSTRUCT,*LPDELETEITEMSTRUCT; - - typedef struct tagCOMPAREITEMSTRUCT { - UINT CtlType; - UINT CtlID; - HWND hwndItem; - UINT itemID1; - ULONG_PTR itemData1; - UINT itemID2; - ULONG_PTR itemData2; - DWORD dwLocaleId; - } COMPAREITEMSTRUCT,*PCOMPAREITEMSTRUCT,*LPCOMPAREITEMSTRUCT; - -#ifndef NOMSG -#ifdef UNICODE -#define GetMessage GetMessageW -#define DispatchMessage DispatchMessageW -#define PeekMessage PeekMessageW -#else -#define GetMessage GetMessageA -#define DispatchMessage DispatchMessageA -#define PeekMessage PeekMessageA -#endif - - WINUSERAPI WINBOOL WINAPI GetMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); - WINUSERAPI WINBOOL WINAPI GetMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); - WINUSERAPI WINBOOL WINAPI TranslateMessage(CONST MSG *lpMsg); - WINUSERAPI LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg); - WINUSERAPI LRESULT WINAPI DispatchMessageW(CONST MSG *lpMsg); - WINUSERAPI WINBOOL WINAPI SetMessageQueue(int cMessagesMax); - WINUSERAPI WINBOOL WINAPI PeekMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); - WINUSERAPI WINBOOL WINAPI PeekMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); - -#define PM_NOREMOVE 0x0000 -#define PM_REMOVE 0x0001 -#define PM_NOYIELD 0x0002 -#define PM_QS_INPUT (QS_INPUT << 16) -#define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16) -#define PM_QS_PAINT (QS_PAINT << 16) -#define PM_QS_SENDMESSAGE (QS_SENDMESSAGE << 16) -#endif - - WINUSERAPI WINBOOL WINAPI RegisterHotKey(HWND hWnd,int id,UINT fsModifiers,UINT vk); - WINUSERAPI WINBOOL WINAPI UnregisterHotKey(HWND hWnd,int id); - -#define MOD_ALT 0x0001 -#define MOD_CONTROL 0x0002 -#define MOD_SHIFT 0x0004 -#define MOD_WIN 0x0008 - -#define IDHOT_SNAPWINDOW (-1) -#define IDHOT_SNAPDESKTOP (-2) - -#ifdef WIN_INTERNAL -#ifndef LSTRING -#define NOLSTRING -#endif -#ifndef LFILEIO -#define NOLFILEIO -#endif -#endif - -#define ENDSESSION_LOGOFF 0x80000000 - -#define EWX_LOGOFF 0 -#define EWX_SHUTDOWN 0x00000001 -#define EWX_REBOOT 0x00000002 -#define EWX_FORCE 0x00000004 -#define EWX_POWEROFF 0x00000008 -#define EWX_FORCEIFHUNG 0x00000010 - -#define ExitWindows(dwReserved,Code) ExitWindowsEx(EWX_LOGOFF,0xFFFFFFFF) - -#ifdef UNICODE -#define SendMessage SendMessageW -#define SendMessageTimeout SendMessageTimeoutW -#define SendNotifyMessage SendNotifyMessageW -#define SendMessageCallback SendMessageCallbackW -#else -#define SendMessage SendMessageA -#define SendMessageTimeout SendMessageTimeoutA -#define SendNotifyMessage SendNotifyMessageA -#define SendMessageCallback SendMessageCallbackA -#endif - - WINUSERAPI WINBOOL WINAPI ExitWindowsEx(UINT uFlags,DWORD dwReason); - WINUSERAPI WINBOOL WINAPI SwapMouseButton(WINBOOL fSwap); - WINUSERAPI DWORD WINAPI GetMessagePos(VOID); - WINUSERAPI LONG WINAPI GetMessageTime(VOID); - WINUSERAPI LPARAM WINAPI GetMessageExtraInfo(VOID); - WINUSERAPI WINBOOL WINAPI IsWow64Message(VOID); - WINUSERAPI LPARAM WINAPI SetMessageExtraInfo(LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendMessageTimeoutA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); - WINUSERAPI LRESULT WINAPI SendMessageTimeoutW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); - WINUSERAPI WINBOOL WINAPI SendNotifyMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI SendNotifyMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI SendMessageCallbackA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); - WINUSERAPI WINBOOL WINAPI SendMessageCallbackW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); - - typedef struct { - UINT cbSize; - HDESK hdesk; - HWND hwnd; - LUID luid; - } BSMINFO,*PBSMINFO; - -#ifdef UNICODE -#define BroadcastSystemMessageEx BroadcastSystemMessageExW -#define BroadcastSystemMessage BroadcastSystemMessageW -#else -#define BroadcastSystemMessageEx BroadcastSystemMessageExA -#define BroadcastSystemMessage BroadcastSystemMessageA -#endif - - WINUSERAPI long WINAPI BroadcastSystemMessageExA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); - WINUSERAPI long WINAPI BroadcastSystemMessageExW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); - WINUSERAPI long WINAPI BroadcastSystemMessageA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI long WINAPI BroadcastSystemMessageW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); - -#define BSM_ALLCOMPONENTS 0x00000000 -#define BSM_VXDS 0x00000001 -#define BSM_NETDRIVER 0x00000002 -#define BSM_INSTALLABLEDRIVERS 0x00000004 -#define BSM_APPLICATIONS 0x00000008 -#define BSM_ALLDESKTOPS 0x00000010 - -#define BSF_QUERY 0x00000001 -#define BSF_IGNORECURRENTTASK 0x00000002 -#define BSF_FLUSHDISK 0x00000004 -#define BSF_NOHANG 0x00000008 -#define BSF_POSTMESSAGE 0x00000010 -#define BSF_FORCEIFHUNG 0x00000020 -#define BSF_NOTIMEOUTIFNOTHUNG 0x00000040 -#define BSF_ALLOWSFW 0x00000080 -#define BSF_SENDNOTIFYMESSAGE 0x00000100 -#define BSF_RETURNHDESK 0x00000200 -#define BSF_LUID 0x00000400 - -#define BROADCAST_QUERY_DENY 0x424D5144 - - typedef PVOID HDEVNOTIFY; - typedef HDEVNOTIFY *PHDEVNOTIFY; - -#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000 -#define DEVICE_NOTIFY_SERVICE_HANDLE 0x00000001 -#define DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 0x00000004 - -#ifdef UNICODE -#define RegisterDeviceNotification RegisterDeviceNotificationW -#define PostMessage PostMessageW -#define PostThreadMessage PostThreadMessageW -#define PostAppMessage PostAppMessageW -#define DefWindowProc DefWindowProcW -#define CallWindowProc CallWindowProcW -#define RegisterClass RegisterClassW -#define UnregisterClass UnregisterClassW -#define GetClassInfo GetClassInfoW -#define RegisterClassEx RegisterClassExW -#define GetClassInfoEx GetClassInfoExW -#else -#define RegisterDeviceNotification RegisterDeviceNotificationA -#define PostMessage PostMessageA -#define PostThreadMessage PostThreadMessageA -#define PostAppMessage PostAppMessageA -#define DefWindowProc DefWindowProcA -#define CallWindowProc CallWindowProcA -#define RegisterClass RegisterClassA -#define UnregisterClass UnregisterClassA -#define GetClassInfo GetClassInfoA -#define RegisterClassEx RegisterClassExA -#define GetClassInfoEx GetClassInfoExA -#endif - - WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); - WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationW(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); - WINUSERAPI WINBOOL WINAPI UnregisterDeviceNotification(HDEVNOTIFY Handle); - WINUSERAPI WINBOOL WINAPI PostMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI PostMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI PostThreadMessageA(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI PostThreadMessageW(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); -#define PostAppMessageA(idThread,wMsg,wParam,lParam) PostThreadMessageA((DWORD)idThread,wMsg,wParam,lParam) -#define PostAppMessageW(idThread,wMsg,wParam,lParam) PostThreadMessageW((DWORD)idThread,wMsg,wParam,lParam) - -#define HWND_BROADCAST ((HWND)0xffff) -#define HWND_MESSAGE ((HWND)-3) - - WINUSERAPI WINBOOL WINAPI AttachThreadInput(DWORD idAttach,DWORD idAttachTo,WINBOOL fAttach); - WINUSERAPI WINBOOL WINAPI ReplyMessage(LRESULT lResult); - WINUSERAPI WINBOOL WINAPI WaitMessage(VOID); - WINUSERAPI DWORD WINAPI WaitForInputIdle(HANDLE hProcess,DWORD dwMilliseconds); - WINUSERAPI LRESULT WINAPI DefWindowProcA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefWindowProcW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI VOID WINAPI PostQuitMessage(int nExitCode); - WINUSERAPI LRESULT WINAPI CallWindowProcA(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI CallWindowProcW(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI InSendMessage(VOID); - WINUSERAPI DWORD WINAPI InSendMessageEx(LPVOID lpReserved); - -#define ISMEX_NOSEND 0x00000000 -#define ISMEX_SEND 0x00000001 -#define ISMEX_NOTIFY 0x00000002 -#define ISMEX_CALLBACK 0x00000004 -#define ISMEX_REPLIED 0x00000008 - - WINUSERAPI UINT WINAPI GetDoubleClickTime(VOID); - WINUSERAPI WINBOOL WINAPI SetDoubleClickTime(UINT); - WINUSERAPI ATOM WINAPI RegisterClassA(CONST WNDCLASSA *lpWndClass); - WINUSERAPI ATOM WINAPI RegisterClassW(CONST WNDCLASSW *lpWndClass); - WINUSERAPI WINBOOL WINAPI UnregisterClassA(LPCSTR lpClassName,HINSTANCE hInstance); - WINUSERAPI WINBOOL WINAPI UnregisterClassW(LPCWSTR lpClassName,HINSTANCE hInstance); - WINUSERAPI WINBOOL WINAPI GetClassInfoA(HINSTANCE hInstance,LPCSTR lpClassName,LPWNDCLASSA lpWndClass); - WINUSERAPI WINBOOL WINAPI GetClassInfoW(HINSTANCE hInstance,LPCWSTR lpClassName,LPWNDCLASSW lpWndClass); - WINUSERAPI ATOM WINAPI RegisterClassExA(CONST WNDCLASSEXA *); - WINUSERAPI ATOM WINAPI RegisterClassExW(CONST WNDCLASSEXW *); - WINUSERAPI WINBOOL WINAPI GetClassInfoExA(HINSTANCE hInstance,LPCSTR lpszClass,LPWNDCLASSEXA lpwcx); - WINUSERAPI WINBOOL WINAPI GetClassInfoExW(HINSTANCE hInstance,LPCWSTR lpszClass,LPWNDCLASSEXW lpwcx); - -#define CW_USEDEFAULT ((int)0x80000000) - -#define HWND_DESKTOP ((HWND)0) - - typedef BOOLEAN (WINAPI *PREGISTERCLASSNAMEW)(LPCWSTR); - -#ifdef UNICODE -#define CreateWindowEx CreateWindowExW -#define CreateWindow CreateWindowW -#else -#define CreateWindowEx CreateWindowExA -#define CreateWindow CreateWindowA -#endif - - WINUSERAPI HWND WINAPI CreateWindowExA(DWORD dwExStyle,LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); - WINUSERAPI HWND WINAPI CreateWindowExW(DWORD dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); -#define CreateWindowA(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExA(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) -#define CreateWindowW(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExW(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) - WINUSERAPI WINBOOL WINAPI IsWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI IsMenu(HMENU hMenu); - WINUSERAPI WINBOOL WINAPI IsChild(HWND hWndParent,HWND hWnd); - WINUSERAPI WINBOOL WINAPI DestroyWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI ShowWindow(HWND hWnd,int nCmdShow); - WINUSERAPI WINBOOL WINAPI AnimateWindow(HWND hWnd,DWORD dwTime,DWORD dwFlags); - -#if defined(_WINGDI_) && !defined(NOGDI) - WINUSERAPI WINBOOL WINAPI UpdateLayeredWindow(HWND hWnd,HDC hdcDst,POINT *pptDst,SIZE *psize,HDC hdcSrc,POINT *pptSrc,COLORREF crKey,BLENDFUNCTION *pblend,DWORD dwFlags); - - typedef struct tagUPDATELAYEREDWINDOWINFO { - DWORD cbSize; - HDC hdcDst; - POINT CONST *pptDst; - SIZE CONST *psize; - HDC hdcSrc; - POINT CONST *pptSrc; - COLORREF crKey; - BLENDFUNCTION CONST *pblend; - DWORD dwFlags; - RECT CONST *prcDirty; - } UPDATELAYEREDWINDOWINFO,*PUPDATELAYEREDWINDOWINFO; - - WINUSERAPI WINBOOL WINAPI UpdateLayeredWindowIndirect(HWND hWnd,UPDATELAYEREDWINDOWINFO CONST *pULWInfo); - WINUSERAPI WINBOOL WINAPI GetLayeredWindowAttributes(HWND hwnd,COLORREF *pcrKey,BYTE *pbAlpha,DWORD *pdwFlags); - -#define PW_CLIENTONLY 0x00000001 - - WINUSERAPI WINBOOL WINAPI PrintWindow(HWND hwnd,HDC hdcBlt,UINT nFlags); - WINUSERAPI WINBOOL WINAPI SetLayeredWindowAttributes(HWND hwnd,COLORREF crKey,BYTE bAlpha,DWORD dwFlags); - -#define LWA_COLORKEY 0x00000001 -#define LWA_ALPHA 0x00000002 - -#define ULW_COLORKEY 0x00000001 -#define ULW_ALPHA 0x00000002 -#define ULW_OPAQUE 0x00000004 - -#define ULW_EX_NORESIZE 0x00000008 - - WINUSERAPI WINBOOL WINAPI ShowWindowAsync(HWND hWnd,int nCmdShow); - WINUSERAPI WINBOOL WINAPI FlashWindow(HWND hWnd,WINBOOL bInvert); - - typedef struct { - UINT cbSize; - HWND hwnd; - DWORD dwFlags; - UINT uCount; - DWORD dwTimeout; - } FLASHWINFO,*PFLASHWINFO; - - WINUSERAPI WINBOOL WINAPI FlashWindowEx(PFLASHWINFO pfwi); - -#define FLASHW_STOP 0 -#define FLASHW_CAPTION 0x00000001 -#define FLASHW_TRAY 0x00000002 -#define FLASHW_ALL (FLASHW_CAPTION | FLASHW_TRAY) -#define FLASHW_TIMER 0x00000004 -#define FLASHW_TIMERNOFG 0x0000000C - - WINUSERAPI WINBOOL WINAPI ShowOwnedPopups(HWND hWnd,WINBOOL fShow); - WINUSERAPI WINBOOL WINAPI OpenIcon(HWND hWnd); - WINUSERAPI WINBOOL WINAPI CloseWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI MoveWindow(HWND hWnd,int X,int Y,int nWidth,int nHeight,WINBOOL bRepaint); - WINUSERAPI WINBOOL WINAPI SetWindowPos(HWND hWnd,HWND hWndInsertAfter,int X,int Y,int cx,int cy,UINT uFlags); - WINUSERAPI WINBOOL WINAPI GetWindowPlacement(HWND hWnd,WINDOWPLACEMENT *lpwndpl); - WINUSERAPI WINBOOL WINAPI SetWindowPlacement(HWND hWnd,CONST WINDOWPLACEMENT *lpwndpl); - -#ifndef NODEFERWINDOWPOS - WINUSERAPI HDWP WINAPI BeginDeferWindowPos(int nNumWindows); - WINUSERAPI HDWP WINAPI DeferWindowPos(HDWP hWinPosInfo,HWND hWnd,HWND hWndInsertAfter,int x,int y,int cx,int cy,UINT uFlags); - WINUSERAPI WINBOOL WINAPI EndDeferWindowPos(HDWP hWinPosInfo); -#endif - - WINUSERAPI WINBOOL WINAPI IsWindowVisible(HWND hWnd); - WINUSERAPI WINBOOL WINAPI IsIconic(HWND hWnd); - WINUSERAPI WINBOOL WINAPI AnyPopup(VOID); - WINUSERAPI WINBOOL WINAPI BringWindowToTop(HWND hWnd); - WINUSERAPI WINBOOL WINAPI IsZoomed(HWND hWnd); - -#define SWP_NOSIZE 0x0001 -#define SWP_NOMOVE 0x0002 -#define SWP_NOZORDER 0x0004 -#define SWP_NOREDRAW 0x0008 -#define SWP_NOACTIVATE 0x0010 -#define SWP_FRAMECHANGED 0x0020 -#define SWP_SHOWWINDOW 0x0040 -#define SWP_HIDEWINDOW 0x0080 -#define SWP_NOCOPYBITS 0x0100 -#define SWP_NOOWNERZORDER 0x0200 -#define SWP_NOSENDCHANGING 0x0400 - -#define SWP_DRAWFRAME SWP_FRAMECHANGED -#define SWP_NOREPOSITION SWP_NOOWNERZORDER -#define SWP_DEFERERASE 0x2000 -#define SWP_ASYNCWINDOWPOS 0x4000 - -#define HWND_TOP ((HWND)0) -#define HWND_BOTTOM ((HWND)1) -#define HWND_TOPMOST ((HWND)-1) -#define HWND_NOTOPMOST ((HWND)-2) - -#ifndef NOCTLMGR - -#include - - typedef struct { - DWORD style; - DWORD dwExtendedStyle; - WORD cdit; - short x; - short y; - short cx; - short cy; - } DLGTEMPLATE; - - typedef DLGTEMPLATE *LPDLGTEMPLATEA; - typedef DLGTEMPLATE *LPDLGTEMPLATEW; - -#ifdef UNICODE - typedef LPDLGTEMPLATEW LPDLGTEMPLATE; -#else - typedef LPDLGTEMPLATEA LPDLGTEMPLATE; -#endif - - typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEA; - typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEW; - -#ifdef UNICODE - typedef LPCDLGTEMPLATEW LPCDLGTEMPLATE; -#else - typedef LPCDLGTEMPLATEA LPCDLGTEMPLATE; -#endif - - typedef struct { - DWORD style; - DWORD dwExtendedStyle; - short x; - short y; - short cx; - short cy; - WORD id; - } DLGITEMTEMPLATE; - - typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEA; - typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEW; - -#ifdef UNICODE - typedef PDLGITEMTEMPLATEW PDLGITEMTEMPLATE; -#else - typedef PDLGITEMTEMPLATEA PDLGITEMTEMPLATE; -#endif - - typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEA; - typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEW; - -#ifdef UNICODE - typedef LPDLGITEMTEMPLATEW LPDLGITEMTEMPLATE; -#else - typedef LPDLGITEMTEMPLATEA LPDLGITEMTEMPLATE; -#endif - -#include - -#ifdef UNICODE -#define CreateDialogParam CreateDialogParamW -#define CreateDialogIndirectParam CreateDialogIndirectParamW -#define CreateDialog CreateDialogW -#define CreateDialogIndirect CreateDialogIndirectW -#define DialogBoxParam DialogBoxParamW -#define DialogBoxIndirectParam DialogBoxIndirectParamW -#define DialogBox DialogBoxW -#define DialogBoxIndirect DialogBoxIndirectW -#define SetDlgItemText SetDlgItemTextW -#define GetDlgItemText GetDlgItemTextW -#define SendDlgItemMessage SendDlgItemMessageW -#define DefDlgProc DefDlgProcW -#else -#define CreateDialogParam CreateDialogParamA -#define CreateDialogIndirectParam CreateDialogIndirectParamA -#define CreateDialog CreateDialogA -#define CreateDialogIndirect CreateDialogIndirectA -#define DialogBoxParam DialogBoxParamA -#define DialogBoxIndirectParam DialogBoxIndirectParamA -#define DialogBox DialogBoxA -#define DialogBoxIndirect DialogBoxIndirectA -#define SetDlgItemText SetDlgItemTextA -#define GetDlgItemText GetDlgItemTextA -#define SendDlgItemMessage SendDlgItemMessageA -#define DefDlgProc DefDlgProcA -#endif - - WINUSERAPI HWND WINAPI CreateDialogParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI HWND WINAPI CreateDialogParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI HWND WINAPI CreateDialogIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI HWND WINAPI CreateDialogIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); -#define CreateDialogA(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamA(hInstance,lpName,hWndParent,lpDialogFunc,0L) -#define CreateDialogW(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamW(hInstance,lpName,hWndParent,lpDialogFunc,0L) -#define CreateDialogIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define CreateDialogIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) - WINUSERAPI INT_PTR WINAPI DialogBoxParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI INT_PTR WINAPI DialogBoxParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); - WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); -#define DialogBoxA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define DialogBoxW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define DialogBoxIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) -#define DialogBoxIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) - WINUSERAPI WINBOOL WINAPI EndDialog(HWND hDlg,INT_PTR nResult); - WINUSERAPI HWND WINAPI GetDlgItem(HWND hDlg,int nIDDlgItem); - WINUSERAPI WINBOOL WINAPI SetDlgItemInt(HWND hDlg,int nIDDlgItem,UINT uValue,WINBOOL bSigned); - WINUSERAPI UINT WINAPI GetDlgItemInt(HWND hDlg,int nIDDlgItem,WINBOOL *lpTranslated,WINBOOL bSigned); - WINUSERAPI WINBOOL WINAPI SetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPCSTR lpString); - WINUSERAPI WINBOOL WINAPI SetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPCWSTR lpString); - WINUSERAPI UINT WINAPI GetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPSTR lpString,int cchMax); - WINUSERAPI UINT WINAPI GetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPWSTR lpString,int cchMax); - WINUSERAPI WINBOOL WINAPI CheckDlgButton(HWND hDlg,int nIDButton,UINT uCheck); - WINUSERAPI WINBOOL WINAPI CheckRadioButton(HWND hDlg,int nIDFirstButton,int nIDLastButton,int nIDCheckButton); - WINUSERAPI UINT WINAPI IsDlgButtonChecked(HWND hDlg,int nIDButton); - WINUSERAPI LRESULT WINAPI SendDlgItemMessageA(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI SendDlgItemMessageW(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI HWND WINAPI GetNextDlgGroupItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); - WINUSERAPI HWND WINAPI GetNextDlgTabItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); - WINUSERAPI int WINAPI GetDlgCtrlID(HWND hWnd); - WINUSERAPI long WINAPI GetDialogBaseUnits(VOID); - WINUSERAPI LRESULT WINAPI DefDlgProcA(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefDlgProcW(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); - -#define DLGWINDOWEXTRA 30 -#endif - -#ifndef NOMSG - -#ifdef UNICODE -#define CallMsgFilter CallMsgFilterW -#else -#define CallMsgFilter CallMsgFilterA -#endif - - WINUSERAPI WINBOOL WINAPI CallMsgFilterA(LPMSG lpMsg,int nCode); - WINUSERAPI WINBOOL WINAPI CallMsgFilterW(LPMSG lpMsg,int nCode); -#endif - -#ifndef NOCLIPBOARD - -#ifdef UNICODE -#define RegisterClipboardFormat RegisterClipboardFormatW -#define GetClipboardFormatName GetClipboardFormatNameW -#else -#define RegisterClipboardFormat RegisterClipboardFormatA -#define GetClipboardFormatName GetClipboardFormatNameA -#endif - - WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner); - WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID); - WINUSERAPI DWORD WINAPI GetClipboardSequenceNumber(VOID); - WINUSERAPI HWND WINAPI GetClipboardOwner(VOID); - WINUSERAPI HWND WINAPI SetClipboardViewer(HWND hWndNewViewer); - WINUSERAPI HWND WINAPI GetClipboardViewer(VOID); - WINUSERAPI WINBOOL WINAPI ChangeClipboardChain(HWND hWndRemove,HWND hWndNewNext); - WINUSERAPI HANDLE WINAPI SetClipboardData(UINT uFormat,HANDLE hMem); - WINUSERAPI HANDLE WINAPI GetClipboardData(UINT uFormat); - WINUSERAPI UINT WINAPI RegisterClipboardFormatA(LPCSTR lpszFormat); - WINUSERAPI UINT WINAPI RegisterClipboardFormatW(LPCWSTR lpszFormat); - WINUSERAPI int WINAPI CountClipboardFormats(VOID); - WINUSERAPI UINT WINAPI EnumClipboardFormats(UINT format); - WINUSERAPI int WINAPI GetClipboardFormatNameA(UINT format,LPSTR lpszFormatName,int cchMaxCount); - WINUSERAPI int WINAPI GetClipboardFormatNameW(UINT format,LPWSTR lpszFormatName,int cchMaxCount); - WINUSERAPI WINBOOL WINAPI EmptyClipboard(VOID); - WINUSERAPI WINBOOL WINAPI IsClipboardFormatAvailable(UINT format); - WINUSERAPI int WINAPI GetPriorityClipboardFormat(UINT *paFormatPriorityList,int cFormats); - WINUSERAPI HWND WINAPI GetOpenClipboardWindow(VOID); -#endif - -#ifdef UNICODE -#define CharToOem CharToOemW -#define OemToChar OemToCharW -#define CharToOemBuff CharToOemBuffW -#define OemToCharBuff OemToCharBuffW -#define CharUpper CharUpperW -#define CharUpperBuff CharUpperBuffW -#define CharLower CharLowerW -#define CharLowerBuff CharLowerBuffW -#define CharNext CharNextW -#define CharPrev CharPrevW -#else -#define CharToOem CharToOemA -#define OemToChar OemToCharA -#define CharToOemBuff CharToOemBuffA -#define OemToCharBuff OemToCharBuffA -#define CharUpper CharUpperA -#define CharUpperBuff CharUpperBuffA -#define CharLower CharLowerA -#define CharLowerBuff CharLowerBuffA -#define CharNext CharNextA -#define CharPrev CharPrevA -#endif - - WINUSERAPI WINBOOL WINAPI CharToOemA(LPCSTR lpszSrc,LPSTR lpszDst); - WINUSERAPI WINBOOL WINAPI CharToOemW(LPCWSTR lpszSrc,LPSTR lpszDst); - WINUSERAPI WINBOOL WINAPI OemToCharA(LPCSTR lpszSrc,LPSTR lpszDst); - WINUSERAPI WINBOOL WINAPI OemToCharW(LPCSTR lpszSrc,LPWSTR lpszDst); - WINUSERAPI WINBOOL WINAPI CharToOemBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); - WINUSERAPI WINBOOL WINAPI CharToOemBuffW(LPCWSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); - WINUSERAPI WINBOOL WINAPI OemToCharBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); - WINUSERAPI WINBOOL WINAPI OemToCharBuffW(LPCSTR lpszSrc,LPWSTR lpszDst,DWORD cchDstLength); - WINUSERAPI LPSTR WINAPI CharUpperA(LPSTR lpsz); - WINUSERAPI LPWSTR WINAPI CharUpperW(LPWSTR lpsz); - WINUSERAPI DWORD WINAPI CharUpperBuffA(LPSTR lpsz,DWORD cchLength); - WINUSERAPI DWORD WINAPI CharUpperBuffW(LPWSTR lpsz,DWORD cchLength); - WINUSERAPI LPSTR WINAPI CharLowerA(LPSTR lpsz); - WINUSERAPI LPWSTR WINAPI CharLowerW(LPWSTR lpsz); - WINUSERAPI DWORD WINAPI CharLowerBuffA(LPSTR lpsz,DWORD cchLength); - WINUSERAPI DWORD WINAPI CharLowerBuffW(LPWSTR lpsz,DWORD cchLength); - WINUSERAPI LPSTR WINAPI CharNextA(LPCSTR lpsz); - WINUSERAPI LPWSTR WINAPI CharNextW(LPCWSTR lpsz); - WINUSERAPI LPSTR WINAPI CharPrevA(LPCSTR lpszStart,LPCSTR lpszCurrent); - WINUSERAPI LPWSTR WINAPI CharPrevW(LPCWSTR lpszStart,LPCWSTR lpszCurrent); - WINUSERAPI LPSTR WINAPI CharNextExA(WORD CodePage,LPCSTR lpCurrentChar,DWORD dwFlags); - WINUSERAPI LPSTR WINAPI CharPrevExA(WORD CodePage,LPCSTR lpStart,LPCSTR lpCurrentChar,DWORD dwFlags); - -#define AnsiToOem CharToOemA -#define OemToAnsi OemToCharA -#define AnsiToOemBuff CharToOemBuffA -#define OemToAnsiBuff OemToCharBuffA -#define AnsiUpper CharUpperA -#define AnsiUpperBuff CharUpperBuffA -#define AnsiLower CharLowerA -#define AnsiLowerBuff CharLowerBuffA -#define AnsiNext CharNextA -#define AnsiPrev CharPrevA - -#ifndef NOLANGUAGE - -#ifdef UNICODE -#define IsCharAlpha IsCharAlphaW -#define IsCharAlphaNumeric IsCharAlphaNumericW -#define IsCharUpper IsCharUpperW -#define IsCharLower IsCharLowerW -#else -#define IsCharAlpha IsCharAlphaA -#define IsCharAlphaNumeric IsCharAlphaNumericA -#define IsCharUpper IsCharUpperA -#define IsCharLower IsCharLowerA -#endif - - WINUSERAPI WINBOOL WINAPI IsCharAlphaA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharAlphaW(WCHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericW(WCHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharUpperA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharUpperW(WCHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharLowerA(CHAR ch); - WINUSERAPI WINBOOL WINAPI IsCharLowerW(WCHAR ch); -#endif - -#ifdef UNICODE -#define GetKeyNameText GetKeyNameTextW -#define VkKeyScan VkKeyScanW -#define VkKeyScanEx VkKeyScanExW -#else -#define GetKeyNameText GetKeyNameTextA -#define VkKeyScan VkKeyScanA -#define VkKeyScanEx VkKeyScanExA -#endif - - WINUSERAPI HWND WINAPI SetFocus(HWND hWnd); - WINUSERAPI HWND WINAPI GetActiveWindow(VOID); - WINUSERAPI HWND WINAPI GetFocus(VOID); - WINUSERAPI UINT WINAPI GetKBCodePage(VOID); - WINUSERAPI SHORT WINAPI GetKeyState(int nVirtKey); - WINUSERAPI SHORT WINAPI GetAsyncKeyState(int vKey); - WINUSERAPI WINBOOL WINAPI GetKeyboardState(PBYTE lpKeyState); - WINUSERAPI WINBOOL WINAPI SetKeyboardState(LPBYTE lpKeyState); - WINUSERAPI int WINAPI GetKeyNameTextA(LONG lParam,LPSTR lpString,int cchSize); - WINUSERAPI int WINAPI GetKeyNameTextW(LONG lParam,LPWSTR lpString,int cchSize); - WINUSERAPI int WINAPI GetKeyboardType(int nTypeFlag); - WINUSERAPI int WINAPI ToAscii(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags); - WINUSERAPI int WINAPI ToAsciiEx(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags,HKL dwhkl); - WINUSERAPI int WINAPI ToUnicode(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags); - WINUSERAPI DWORD WINAPI OemKeyScan(WORD wOemChar); - WINUSERAPI SHORT WINAPI VkKeyScanA(CHAR ch); - WINUSERAPI SHORT WINAPI VkKeyScanW(WCHAR ch); - WINUSERAPI SHORT WINAPI VkKeyScanExA(CHAR ch,HKL dwhkl); - WINUSERAPI SHORT WINAPI VkKeyScanExW(WCHAR ch,HKL dwhkl); - -#define KEYEVENTF_EXTENDEDKEY 0x0001 -#define KEYEVENTF_KEYUP 0x0002 -#define KEYEVENTF_UNICODE 0x0004 -#define KEYEVENTF_SCANCODE 0x0008 - - WINUSERAPI VOID WINAPI keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,ULONG_PTR dwExtraInfo); - -#define MOUSEEVENTF_MOVE 0x0001 -#define MOUSEEVENTF_LEFTDOWN 0x0002 -#define MOUSEEVENTF_LEFTUP 0x0004 -#define MOUSEEVENTF_RIGHTDOWN 0x0008 -#define MOUSEEVENTF_RIGHTUP 0x0010 -#define MOUSEEVENTF_MIDDLEDOWN 0x0020 -#define MOUSEEVENTF_MIDDLEUP 0x0040 -#define MOUSEEVENTF_XDOWN 0x0080 -#define MOUSEEVENTF_XUP 0x0100 -#define MOUSEEVENTF_WHEEL 0x0800 -#define MOUSEEVENTF_VIRTUALDESK 0x4000 -#define MOUSEEVENTF_ABSOLUTE 0x8000 - - WINUSERAPI VOID WINAPI mouse_event(DWORD dwFlags,DWORD dx,DWORD dy,DWORD dwData,ULONG_PTR dwExtraInfo); - - typedef struct tagMOUSEINPUT { - LONG dx; - LONG dy; - DWORD mouseData; - DWORD dwFlags; - DWORD time; - ULONG_PTR dwExtraInfo; - } MOUSEINPUT,*PMOUSEINPUT,*LPMOUSEINPUT; - - typedef struct tagKEYBDINPUT { - WORD wVk; - WORD wScan; - DWORD dwFlags; - DWORD time; - ULONG_PTR dwExtraInfo; - } KEYBDINPUT,*PKEYBDINPUT,*LPKEYBDINPUT; - - typedef struct tagHARDWAREINPUT { - DWORD uMsg; - WORD wParamL; - WORD wParamH; - } HARDWAREINPUT,*PHARDWAREINPUT,*LPHARDWAREINPUT; - -#define INPUT_MOUSE 0 -#define INPUT_KEYBOARD 1 -#define INPUT_HARDWARE 2 - - typedef struct tagINPUT { - DWORD type; - union { - MOUSEINPUT mi; - KEYBDINPUT ki; - HARDWAREINPUT hi; - }; - } INPUT,*PINPUT,*LPINPUT; - - WINUSERAPI UINT WINAPI SendInput(UINT cInputs,LPINPUT pInputs,int cbSize); - - typedef struct tagLASTINPUTINFO { - UINT cbSize; - DWORD dwTime; - } LASTINPUTINFO,*PLASTINPUTINFO; - -#ifdef UNICODE -#define MapVirtualKey MapVirtualKeyW -#define MapVirtualKeyEx MapVirtualKeyExW -#else -#define MapVirtualKey MapVirtualKeyA -#define MapVirtualKeyEx MapVirtualKeyExA -#endif - - WINUSERAPI WINBOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii); - WINUSERAPI UINT WINAPI MapVirtualKeyA(UINT uCode,UINT uMapType); - WINUSERAPI UINT WINAPI MapVirtualKeyW(UINT uCode,UINT uMapType); - WINUSERAPI UINT WINAPI MapVirtualKeyExA(UINT uCode,UINT uMapType,HKL dwhkl); - WINUSERAPI UINT WINAPI MapVirtualKeyExW(UINT uCode,UINT uMapType,HKL dwhkl); - WINUSERAPI WINBOOL WINAPI GetInputState(VOID); - WINUSERAPI DWORD WINAPI GetQueueStatus(UINT flags); - WINUSERAPI HWND WINAPI GetCapture(VOID); - WINUSERAPI HWND WINAPI SetCapture(HWND hWnd); - WINUSERAPI WINBOOL WINAPI ReleaseCapture(VOID); - WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjects(DWORD nCount,CONST HANDLE *pHandles,WINBOOL fWaitAll,DWORD dwMilliseconds,DWORD dwWakeMask); - WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *pHandles,DWORD dwMilliseconds,DWORD dwWakeMask,DWORD dwFlags); - -#define MWMO_WAITALL 0x0001 -#define MWMO_ALERTABLE 0x0002 -#define MWMO_INPUTAVAILABLE 0x0004 - -#define QS_KEY 0x0001 -#define QS_MOUSEMOVE 0x0002 -#define QS_MOUSEBUTTON 0x0004 -#define QS_POSTMESSAGE 0x0008 -#define QS_TIMER 0x0010 -#define QS_PAINT 0x0020 -#define QS_SENDMESSAGE 0x0040 -#define QS_HOTKEY 0x0080 -#define QS_ALLPOSTMESSAGE 0x0100 -#define QS_RAWINPUT 0x0400 -#define QS_MOUSE (QS_MOUSEMOVE | QS_MOUSEBUTTON) -#define QS_INPUT (QS_MOUSE | QS_KEY | QS_RAWINPUT) -#define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) -#define QS_ALLINPUT (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE) - -#define USER_TIMER_MAXIMUM 0x7FFFFFFF -#define USER_TIMER_MINIMUM 0x0000000A - -#ifdef UNICODE -#define LoadAccelerators LoadAcceleratorsW -#define CreateAcceleratorTable CreateAcceleratorTableW -#define CopyAcceleratorTable CopyAcceleratorTableW -#else -#define LoadAccelerators LoadAcceleratorsA -#define CreateAcceleratorTable CreateAcceleratorTableA -#define CopyAcceleratorTable CopyAcceleratorTableA -#endif - - WINUSERAPI UINT_PTR WINAPI SetTimer(HWND hWnd,UINT_PTR nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc); - WINUSERAPI WINBOOL WINAPI KillTimer(HWND hWnd,UINT_PTR uIDEvent); - WINUSERAPI WINBOOL WINAPI IsWindowUnicode(HWND hWnd); - WINUSERAPI WINBOOL WINAPI EnableWindow(HWND hWnd,WINBOOL bEnable); - WINUSERAPI WINBOOL WINAPI IsWindowEnabled(HWND hWnd); - WINUSERAPI HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance,LPCSTR lpTableName); - WINUSERAPI HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance,LPCWSTR lpTableName); - WINUSERAPI HACCEL WINAPI CreateAcceleratorTableA(LPACCEL paccel,int cAccel); - WINUSERAPI HACCEL WINAPI CreateAcceleratorTableW(LPACCEL paccel,int cAccel); - WINUSERAPI WINBOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel); - WINUSERAPI int WINAPI CopyAcceleratorTableA(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); - WINUSERAPI int WINAPI CopyAcceleratorTableW(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); - -#ifndef NOMSG - -#ifdef UNICODE -#define TranslateAccelerator TranslateAcceleratorW -#else -#define TranslateAccelerator TranslateAcceleratorA -#endif - - WINUSERAPI int WINAPI TranslateAcceleratorA(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); - WINUSERAPI int WINAPI TranslateAcceleratorW(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); -#endif - -#ifndef NOSYSMETRICS - -#define SM_CXSCREEN 0 -#define SM_CYSCREEN 1 -#define SM_CXVSCROLL 2 -#define SM_CYHSCROLL 3 -#define SM_CYCAPTION 4 -#define SM_CXBORDER 5 -#define SM_CYBORDER 6 -#define SM_CXDLGFRAME 7 -#define SM_CYDLGFRAME 8 -#define SM_CYVTHUMB 9 -#define SM_CXHTHUMB 10 -#define SM_CXICON 11 -#define SM_CYICON 12 -#define SM_CXCURSOR 13 -#define SM_CYCURSOR 14 -#define SM_CYMENU 15 -#define SM_CXFULLSCREEN 16 -#define SM_CYFULLSCREEN 17 -#define SM_CYKANJIWINDOW 18 -#define SM_MOUSEPRESENT 19 -#define SM_CYVSCROLL 20 -#define SM_CXHSCROLL 21 -#define SM_DEBUG 22 -#define SM_SWAPBUTTON 23 -#define SM_RESERVED1 24 -#define SM_RESERVED2 25 -#define SM_RESERVED3 26 -#define SM_RESERVED4 27 -#define SM_CXMIN 28 -#define SM_CYMIN 29 -#define SM_CXSIZE 30 -#define SM_CYSIZE 31 -#define SM_CXFRAME 32 -#define SM_CYFRAME 33 -#define SM_CXMINTRACK 34 -#define SM_CYMINTRACK 35 -#define SM_CXDOUBLECLK 36 -#define SM_CYDOUBLECLK 37 -#define SM_CXICONSPACING 38 -#define SM_CYICONSPACING 39 -#define SM_MENUDROPALIGNMENT 40 -#define SM_PENWINDOWS 41 -#define SM_DBCSENABLED 42 -#define SM_CMOUSEBUTTONS 43 - -#define SM_CXFIXEDFRAME SM_CXDLGFRAME -#define SM_CYFIXEDFRAME SM_CYDLGFRAME -#define SM_CXSIZEFRAME SM_CXFRAME -#define SM_CYSIZEFRAME SM_CYFRAME - -#define SM_SECURE 44 -#define SM_CXEDGE 45 -#define SM_CYEDGE 46 -#define SM_CXMINSPACING 47 -#define SM_CYMINSPACING 48 -#define SM_CXSMICON 49 -#define SM_CYSMICON 50 -#define SM_CYSMCAPTION 51 -#define SM_CXSMSIZE 52 -#define SM_CYSMSIZE 53 -#define SM_CXMENUSIZE 54 -#define SM_CYMENUSIZE 55 -#define SM_ARRANGE 56 -#define SM_CXMINIMIZED 57 -#define SM_CYMINIMIZED 58 -#define SM_CXMAXTRACK 59 -#define SM_CYMAXTRACK 60 -#define SM_CXMAXIMIZED 61 -#define SM_CYMAXIMIZED 62 -#define SM_NETWORK 63 -#define SM_CLEANBOOT 67 -#define SM_CXDRAG 68 -#define SM_CYDRAG 69 -#define SM_SHOWSOUNDS 70 -#define SM_CXMENUCHECK 71 -#define SM_CYMENUCHECK 72 -#define SM_SLOWMACHINE 73 -#define SM_MIDEASTENABLED 74 -#define SM_MOUSEWHEELPRESENT 75 -#define SM_XVIRTUALSCREEN 76 -#define SM_YVIRTUALSCREEN 77 -#define SM_CXVIRTUALSCREEN 78 -#define SM_CYVIRTUALSCREEN 79 -#define SM_CMONITORS 80 -#define SM_SAMEDISPLAYFORMAT 81 -#define SM_IMMENABLED 82 -#define SM_CXFOCUSBORDER 83 -#define SM_CYFOCUSBORDER 84 -#define SM_TABLETPC 86 -#define SM_MEDIACENTER 87 -#define SM_STARTER 88 -#define SM_SERVERR2 89 -#define SM_CMETRICS 90 -#define SM_REMOTESESSION 0x1000 -#define SM_SHUTTINGDOWN 0x2000 -#define SM_REMOTECONTROL 0x2001 -#define SM_CARETBLINKINGENABLED 0x2002 - - WINUSERAPI int WINAPI GetSystemMetrics(int nIndex); -#endif - -#ifndef NOMENUS - -#ifdef UNICODE -#define LoadMenu LoadMenuW -#define LoadMenuIndirect LoadMenuIndirectW -#define ChangeMenu ChangeMenuW -#define GetMenuString GetMenuStringW -#define InsertMenu InsertMenuW -#define AppendMenu AppendMenuW -#define ModifyMenu ModifyMenuW -#else -#define LoadMenu LoadMenuA -#define LoadMenuIndirect LoadMenuIndirectA -#define ChangeMenu ChangeMenuA -#define GetMenuString GetMenuStringA -#define InsertMenu InsertMenuA -#define AppendMenu AppendMenuA -#define ModifyMenu ModifyMenuA -#endif - - WINUSERAPI HMENU WINAPI LoadMenuA(HINSTANCE hInstance,LPCSTR lpMenuName); - WINUSERAPI HMENU WINAPI LoadMenuW(HINSTANCE hInstance,LPCWSTR lpMenuName); - WINUSERAPI HMENU WINAPI LoadMenuIndirectA(CONST MENUTEMPLATEA *lpMenuTemplate); - WINUSERAPI HMENU WINAPI LoadMenuIndirectW(CONST MENUTEMPLATEW *lpMenuTemplate); - WINUSERAPI HMENU WINAPI GetMenu(HWND hWnd); - WINUSERAPI WINBOOL WINAPI SetMenu(HWND hWnd,HMENU hMenu); - WINUSERAPI WINBOOL WINAPI ChangeMenuA(HMENU hMenu,UINT cmd,LPCSTR lpszNewItem,UINT cmdInsert,UINT flags); - WINUSERAPI WINBOOL WINAPI ChangeMenuW(HMENU hMenu,UINT cmd,LPCWSTR lpszNewItem,UINT cmdInsert,UINT flags); - WINUSERAPI WINBOOL WINAPI HiliteMenuItem(HWND hWnd,HMENU hMenu,UINT uIDHiliteItem,UINT uHilite); - WINUSERAPI int WINAPI GetMenuStringA(HMENU hMenu,UINT uIDItem,LPSTR lpString,int cchMax,UINT flags); - WINUSERAPI int WINAPI GetMenuStringW(HMENU hMenu,UINT uIDItem,LPWSTR lpString,int cchMax,UINT flags); - WINUSERAPI UINT WINAPI GetMenuState(HMENU hMenu,UINT uId,UINT uFlags); - WINUSERAPI WINBOOL WINAPI DrawMenuBar(HWND hWnd); - -#define PMB_ACTIVE 0x00000001 - - WINUSERAPI HMENU WINAPI GetSystemMenu(HWND hWnd,WINBOOL bRevert); - WINUSERAPI HMENU WINAPI CreateMenu(VOID); - WINUSERAPI HMENU WINAPI CreatePopupMenu(VOID); - WINUSERAPI WINBOOL WINAPI DestroyMenu(HMENU hMenu); - WINUSERAPI DWORD WINAPI CheckMenuItem(HMENU hMenu,UINT uIDCheckItem,UINT uCheck); - WINUSERAPI WINBOOL WINAPI EnableMenuItem(HMENU hMenu,UINT uIDEnableItem,UINT uEnable); - WINUSERAPI HMENU WINAPI GetSubMenu(HMENU hMenu,int nPos); - WINUSERAPI UINT WINAPI GetMenuItemID(HMENU hMenu,int nPos); - WINUSERAPI int WINAPI GetMenuItemCount(HMENU hMenu); - WINUSERAPI WINBOOL WINAPI InsertMenuA(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI InsertMenuW(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI AppendMenuA(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI AppendMenuW(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI ModifyMenuA(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI ModifyMenuW(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); - WINUSERAPI WINBOOL WINAPI RemoveMenu(HMENU hMenu,UINT uPosition,UINT uFlags); - WINUSERAPI WINBOOL WINAPI DeleteMenu(HMENU hMenu,UINT uPosition,UINT uFlags); - WINUSERAPI WINBOOL WINAPI SetMenuItemBitmaps(HMENU hMenu,UINT uPosition,UINT uFlags,HBITMAP hBitmapUnchecked,HBITMAP hBitmapChecked); - WINUSERAPI LONG WINAPI GetMenuCheckMarkDimensions(VOID); - WINUSERAPI WINBOOL WINAPI TrackPopupMenu(HMENU hMenu,UINT uFlags,int x,int y,int nReserved,HWND hWnd,CONST RECT *prcRect); - -#define MNC_IGNORE 0 -#define MNC_CLOSE 1 -#define MNC_EXECUTE 2 -#define MNC_SELECT 3 - - typedef struct tagTPMPARAMS { - UINT cbSize; - RECT rcExclude; - } TPMPARAMS; - - typedef TPMPARAMS *LPTPMPARAMS; - - WINUSERAPI WINBOOL WINAPI TrackPopupMenuEx(HMENU,UINT,int,int,HWND,LPTPMPARAMS); - -#define MNS_NOCHECK 0x80000000 -#define MNS_MODELESS 0x40000000 -#define MNS_DRAGDROP 0x20000000 -#define MNS_AUTODISMISS 0x10000000 -#define MNS_NOTIFYBYPOS 0x08000000 -#define MNS_CHECKORBMP 0x04000000 - -#define MIM_MAXHEIGHT 0x00000001 -#define MIM_BACKGROUND 0x00000002 -#define MIM_HELPID 0x00000004 -#define MIM_MENUDATA 0x00000008 -#define MIM_STYLE 0x00000010 -#define MIM_APPLYTOSUBMENUS 0x80000000 - - typedef struct tagMENUINFO { - DWORD cbSize; - DWORD fMask; - DWORD dwStyle; - UINT cyMax; - HBRUSH hbrBack; - DWORD dwContextHelpID; - ULONG_PTR dwMenuData; - } MENUINFO,*LPMENUINFO; - - typedef MENUINFO CONST *LPCMENUINFO; - - WINUSERAPI WINBOOL WINAPI GetMenuInfo(HMENU,LPMENUINFO); - WINUSERAPI WINBOOL WINAPI SetMenuInfo(HMENU,LPCMENUINFO); - WINUSERAPI WINBOOL WINAPI EndMenu(VOID); - -#define MND_CONTINUE 0 -#define MND_ENDMENU 1 - - typedef struct tagMENUGETOBJECTINFO { - DWORD dwFlags; - UINT uPos; - HMENU hmenu; - PVOID riid; - PVOID pvObj; - } MENUGETOBJECTINFO,*PMENUGETOBJECTINFO; - -#define MNGOF_TOPGAP 0x00000001 -#define MNGOF_BOTTOMGAP 0x00000002 - -#define MNGO_NOINTERFACE 0x00000000 -#define MNGO_NOERROR 0x00000001 - -#define MIIM_STATE 0x00000001 -#define MIIM_ID 0x00000002 -#define MIIM_SUBMENU 0x00000004 -#define MIIM_CHECKMARKS 0x00000008 -#define MIIM_TYPE 0x00000010 -#define MIIM_DATA 0x00000020 - -#define MIIM_STRING 0x00000040 -#define MIIM_BITMAP 0x00000080 -#define MIIM_FTYPE 0x00000100 - -#define HBMMENU_CALLBACK ((HBITMAP) -1) -#define HBMMENU_SYSTEM ((HBITMAP) 1) -#define HBMMENU_MBAR_RESTORE ((HBITMAP) 2) -#define HBMMENU_MBAR_MINIMIZE ((HBITMAP) 3) -#define HBMMENU_MBAR_CLOSE ((HBITMAP) 5) -#define HBMMENU_MBAR_CLOSE_D ((HBITMAP) 6) -#define HBMMENU_MBAR_MINIMIZE_D ((HBITMAP) 7) -#define HBMMENU_POPUP_CLOSE ((HBITMAP) 8) -#define HBMMENU_POPUP_RESTORE ((HBITMAP) 9) -#define HBMMENU_POPUP_MAXIMIZE ((HBITMAP) 10) -#define HBMMENU_POPUP_MINIMIZE ((HBITMAP) 11) - - typedef struct tagMENUITEMINFOA { - UINT cbSize; - UINT fMask; - UINT fType; - UINT fState; - UINT wID; - HMENU hSubMenu; - HBITMAP hbmpChecked; - HBITMAP hbmpUnchecked; - ULONG_PTR dwItemData; - LPSTR dwTypeData; - UINT cch; - HBITMAP hbmpItem; - } MENUITEMINFOA,*LPMENUITEMINFOA; - - typedef struct tagMENUITEMINFOW { - UINT cbSize; - UINT fMask; - UINT fType; - UINT fState; - UINT wID; - HMENU hSubMenu; - HBITMAP hbmpChecked; - HBITMAP hbmpUnchecked; - ULONG_PTR dwItemData; - LPWSTR dwTypeData; - UINT cch; - HBITMAP hbmpItem; - } MENUITEMINFOW,*LPMENUITEMINFOW; - -#ifdef UNICODE - typedef MENUITEMINFOW MENUITEMINFO; - typedef LPMENUITEMINFOW LPMENUITEMINFO; -#else - typedef MENUITEMINFOA MENUITEMINFO; - typedef LPMENUITEMINFOA LPMENUITEMINFO; -#endif - typedef MENUITEMINFOA CONST *LPCMENUITEMINFOA; - typedef MENUITEMINFOW CONST *LPCMENUITEMINFOW; -#ifdef UNICODE - typedef LPCMENUITEMINFOW LPCMENUITEMINFO; -#else - typedef LPCMENUITEMINFOA LPCMENUITEMINFO; -#endif - -#ifdef UNICODE -#define InsertMenuItem InsertMenuItemW -#define GetMenuItemInfo GetMenuItemInfoW -#define SetMenuItemInfo SetMenuItemInfoW -#else -#define InsertMenuItem InsertMenuItemA -#define GetMenuItemInfo GetMenuItemInfoA -#define SetMenuItemInfo SetMenuItemInfoA -#endif - - WINUSERAPI WINBOOL WINAPI InsertMenuItemA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOA lpmi); - WINUSERAPI WINBOOL WINAPI InsertMenuItemW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOW lpmi); - WINUSERAPI WINBOOL WINAPI GetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOA lpmii); - WINUSERAPI WINBOOL WINAPI GetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOW lpmii); - WINUSERAPI WINBOOL WINAPI SetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOA lpmii); - WINUSERAPI WINBOOL WINAPI SetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOW lpmii); - -#define GMDI_USEDISABLED 0x0001L -#define GMDI_GOINTOPOPUPS 0x0002L - - WINUSERAPI UINT WINAPI GetMenuDefaultItem(HMENU hMenu,UINT fByPos,UINT gmdiFlags); - WINUSERAPI WINBOOL WINAPI SetMenuDefaultItem(HMENU hMenu,UINT uItem,UINT fByPos); - WINUSERAPI WINBOOL WINAPI GetMenuItemRect(HWND hWnd,HMENU hMenu,UINT uItem,LPRECT lprcItem); - WINUSERAPI int WINAPI MenuItemFromPoint(HWND hWnd,HMENU hMenu,POINT ptScreen); - -#define TPM_LEFTBUTTON 0x0000L -#define TPM_RIGHTBUTTON 0x0002L -#define TPM_LEFTALIGN 0x0000L -#define TPM_CENTERALIGN 0x0004L -#define TPM_RIGHTALIGN 0x0008L -#define TPM_TOPALIGN 0x0000L -#define TPM_VCENTERALIGN 0x0010L -#define TPM_BOTTOMALIGN 0x0020L - -#define TPM_HORIZONTAL 0x0000L -#define TPM_VERTICAL 0x0040L -#define TPM_NONOTIFY 0x0080L -#define TPM_RETURNCMD 0x0100L -#define TPM_RECURSE 0x0001L -#define TPM_HORPOSANIMATION 0x0400L -#define TPM_HORNEGANIMATION 0x0800L -#define TPM_VERPOSANIMATION 0x1000L -#define TPM_VERNEGANIMATION 0x2000L -#define TPM_NOANIMATION 0x4000L -#define TPM_LAYOUTRTL 0x8000L -#endif - - typedef struct tagDROPSTRUCT { - HWND hwndSource; - HWND hwndSink; - DWORD wFmt; - ULONG_PTR dwData; - POINT ptDrop; - DWORD dwControlData; - } DROPSTRUCT,*PDROPSTRUCT,*LPDROPSTRUCT; - -#define DOF_EXECUTABLE 0x8001 -#define DOF_DOCUMENT 0x8002 -#define DOF_DIRECTORY 0x8003 -#define DOF_MULTIPLE 0x8004 -#define DOF_PROGMAN 0x0001 -#define DOF_SHELLDATA 0x0002 - -#define DO_DROPFILE 0x454C4946L -#define DO_PRINTFILE 0x544E5250L - - WINUSERAPI DWORD WINAPI DragObject(HWND hwndParent,HWND hwndFrom,UINT fmt,ULONG_PTR data,HCURSOR hcur); - WINUSERAPI WINBOOL WINAPI DragDetect(HWND hwnd,POINT pt); - WINUSERAPI WINBOOL WINAPI DrawIcon(HDC hDC,int X,int Y,HICON hIcon); - -#ifndef NODRAWTEXT - -#define DT_TOP 0x00000000 -#define DT_LEFT 0x00000000 -#define DT_CENTER 0x00000001 -#define DT_RIGHT 0x00000002 -#define DT_VCENTER 0x00000004 -#define DT_BOTTOM 0x00000008 -#define DT_WORDBREAK 0x00000010 -#define DT_SINGLELINE 0x00000020 -#define DT_EXPANDTABS 0x00000040 -#define DT_TABSTOP 0x00000080 -#define DT_NOCLIP 0x00000100 -#define DT_EXTERNALLEADING 0x00000200 -#define DT_CALCRECT 0x00000400 -#define DT_NOPREFIX 0x00000800 -#define DT_INTERNAL 0x00001000 - -#define DT_EDITCONTROL 0x00002000 -#define DT_PATH_ELLIPSIS 0x00004000 -#define DT_END_ELLIPSIS 0x00008000 -#define DT_MODIFYSTRING 0x00010000 -#define DT_RTLREADING 0x00020000 -#define DT_WORD_ELLIPSIS 0x00040000 -#define DT_NOFULLWIDTHCHARBREAK 0x00080000 -#define DT_HIDEPREFIX 0x00100000 -#define DT_PREFIXONLY 0x00200000 - - typedef struct tagDRAWTEXTPARAMS { - UINT cbSize; - int iTabLength; - int iLeftMargin; - int iRightMargin; - UINT uiLengthDrawn; - } DRAWTEXTPARAMS,*LPDRAWTEXTPARAMS; - -#ifdef UNICODE -#define DrawText DrawTextW -#define DrawTextEx DrawTextExW -#else -#define DrawText DrawTextA -#define DrawTextEx DrawTextExA -#endif - - WINUSERAPI int WINAPI DrawTextA(HDC hdc,LPCSTR lpchText,int cchText,LPRECT lprc,UINT format); - WINUSERAPI int WINAPI DrawTextW(HDC hdc,LPCWSTR lpchText,int cchText,LPRECT lprc,UINT format); - WINUSERAPI int WINAPI DrawTextExA(HDC hdc,LPSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); - WINUSERAPI int WINAPI DrawTextExW(HDC hdc,LPWSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); -#endif - -#ifdef UNICODE -#define GrayString GrayStringW -#define DrawState DrawStateW -#define TabbedTextOut TabbedTextOutW -#define GetTabbedTextExtent GetTabbedTextExtentW -#else -#define GrayString GrayStringA -#define DrawState DrawStateA -#define TabbedTextOut TabbedTextOutA -#define GetTabbedTextExtent GetTabbedTextExtentA -#endif - - WINUSERAPI WINBOOL WINAPI GrayStringA(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); - WINUSERAPI WINBOOL WINAPI GrayStringW(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); - -#define DST_COMPLEX 0x0000 -#define DST_TEXT 0x0001 -#define DST_PREFIXTEXT 0x0002 -#define DST_ICON 0x0003 -#define DST_BITMAP 0x0004 - -#define DSS_NORMAL 0x0000 -#define DSS_UNION 0x0010 -#define DSS_DISABLED 0x0020 -#define DSS_MONO 0x0080 -#define DSS_HIDEPREFIX 0x0200 -#define DSS_PREFIXONLY 0x0400 -#define DSS_RIGHT 0x8000 - - WINUSERAPI WINBOOL WINAPI DrawStateA(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); - WINUSERAPI WINBOOL WINAPI DrawStateW(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); - WINUSERAPI LONG WINAPI TabbedTextOutA(HDC hdc,int x,int y,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); - WINUSERAPI LONG WINAPI TabbedTextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); - WINUSERAPI DWORD WINAPI GetTabbedTextExtentA(HDC hdc,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); - WINUSERAPI DWORD WINAPI GetTabbedTextExtentW(HDC hdc,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); - WINUSERAPI WINBOOL WINAPI UpdateWindow(HWND hWnd); - WINUSERAPI HWND WINAPI SetActiveWindow(HWND hWnd); - WINUSERAPI HWND WINAPI GetForegroundWindow(VOID); - WINUSERAPI WINBOOL WINAPI PaintDesktop(HDC hdc); - WINUSERAPI VOID WINAPI SwitchToThisWindow(HWND hwnd,WINBOOL fUnknown); - WINUSERAPI WINBOOL WINAPI SetForegroundWindow(HWND hWnd); - WINUSERAPI WINBOOL WINAPI AllowSetForegroundWindow(DWORD dwProcessId); - -#define ASFW_ANY ((DWORD)-1) - - WINUSERAPI WINBOOL WINAPI LockSetForegroundWindow(UINT uLockCode); - -#define LSFW_LOCK 1 -#define LSFW_UNLOCK 2 - - WINUSERAPI HWND WINAPI WindowFromDC(HDC hDC); - WINUSERAPI HDC WINAPI GetDC(HWND hWnd); - WINUSERAPI HDC WINAPI GetDCEx(HWND hWnd,HRGN hrgnClip,DWORD flags); - -#define DCX_WINDOW 0x00000001L -#define DCX_CACHE 0x00000002L -#define DCX_NORESETATTRS 0x00000004L -#define DCX_CLIPCHILDREN 0x00000008L -#define DCX_CLIPSIBLINGS 0x00000010L -#define DCX_PARENTCLIP 0x00000020L -#define DCX_EXCLUDERGN 0x00000040L -#define DCX_INTERSECTRGN 0x00000080L -#define DCX_EXCLUDEUPDATE 0x00000100L -#define DCX_INTERSECTUPDATE 0x00000200L -#define DCX_LOCKWINDOWUPDATE 0x00000400L - -#define DCX_VALIDATE 0x00200000L - - WINUSERAPI HDC WINAPI GetWindowDC(HWND hWnd); - WINUSERAPI int WINAPI ReleaseDC(HWND hWnd,HDC hDC); - WINUSERAPI HDC WINAPI BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint); - WINUSERAPI WINBOOL WINAPI EndPaint(HWND hWnd,CONST PAINTSTRUCT *lpPaint); - WINUSERAPI WINBOOL WINAPI GetUpdateRect(HWND hWnd,LPRECT lpRect,WINBOOL bErase); - WINUSERAPI int WINAPI GetUpdateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); - WINUSERAPI int WINAPI SetWindowRgn(HWND hWnd,HRGN hRgn,WINBOOL bRedraw); - WINUSERAPI int WINAPI GetWindowRgn(HWND hWnd,HRGN hRgn); - WINUSERAPI int WINAPI GetWindowRgnBox(HWND hWnd,LPRECT lprc); - WINUSERAPI int WINAPI ExcludeUpdateRgn(HDC hDC,HWND hWnd); - WINUSERAPI WINBOOL WINAPI InvalidateRect(HWND hWnd,CONST RECT *lpRect,WINBOOL bErase); - WINUSERAPI WINBOOL WINAPI ValidateRect(HWND hWnd,CONST RECT *lpRect); - WINUSERAPI WINBOOL WINAPI InvalidateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); - WINUSERAPI WINBOOL WINAPI ValidateRgn(HWND hWnd,HRGN hRgn); - WINUSERAPI WINBOOL WINAPI RedrawWindow(HWND hWnd,CONST RECT *lprcUpdate,HRGN hrgnUpdate,UINT flags); - -#define RDW_INVALIDATE 0x0001 -#define RDW_INTERNALPAINT 0x0002 -#define RDW_ERASE 0x0004 - -#define RDW_VALIDATE 0x0008 -#define RDW_NOINTERNALPAINT 0x0010 -#define RDW_NOERASE 0x0020 - -#define RDW_NOCHILDREN 0x0040 -#define RDW_ALLCHILDREN 0x0080 - -#define RDW_UPDATENOW 0x0100 -#define RDW_ERASENOW 0x0200 - -#define RDW_FRAME 0x0400 -#define RDW_NOFRAME 0x0800 - - WINUSERAPI WINBOOL WINAPI LockWindowUpdate(HWND hWndLock); - WINUSERAPI WINBOOL WINAPI ScrollWindow(HWND hWnd,int XAmount,int YAmount,CONST RECT *lpRect,CONST RECT *lpClipRect); - WINUSERAPI WINBOOL WINAPI ScrollDC(HDC hDC,int dx,int dy,CONST RECT *lprcScroll,CONST RECT *lprcClip,HRGN hrgnUpdate,LPRECT lprcUpdate); - WINUSERAPI int WINAPI ScrollWindowEx(HWND hWnd,int dx,int dy,CONST RECT *prcScroll,CONST RECT *prcClip,HRGN hrgnUpdate,LPRECT prcUpdate,UINT flags); - -#define SW_SCROLLCHILDREN 0x0001 -#define SW_INVALIDATE 0x0002 -#define SW_ERASE 0x0004 -#define SW_SMOOTHSCROLL 0x0010 - -#ifndef NOSCROLL - WINUSERAPI int WINAPI SetScrollPos(HWND hWnd,int nBar,int nPos,WINBOOL bRedraw); - WINUSERAPI int WINAPI GetScrollPos(HWND hWnd,int nBar); - WINUSERAPI WINBOOL WINAPI SetScrollRange(HWND hWnd,int nBar,int nMinPos,int nMaxPos,WINBOOL bRedraw); - WINUSERAPI WINBOOL WINAPI GetScrollRange(HWND hWnd,int nBar,LPINT lpMinPos,LPINT lpMaxPos); - WINUSERAPI WINBOOL WINAPI ShowScrollBar(HWND hWnd,int wBar,WINBOOL bShow); - WINUSERAPI WINBOOL WINAPI EnableScrollBar(HWND hWnd,UINT wSBflags,UINT wArrows); - -#define ESB_ENABLE_BOTH 0x0000 -#define ESB_DISABLE_BOTH 0x0003 - -#define ESB_DISABLE_LEFT 0x0001 -#define ESB_DISABLE_RIGHT 0x0002 - -#define ESB_DISABLE_UP 0x0001 -#define ESB_DISABLE_DOWN 0x0002 - -#define ESB_DISABLE_LTUP ESB_DISABLE_LEFT -#define ESB_DISABLE_RTDN ESB_DISABLE_RIGHT -#endif - -#ifdef UNICODE -#define SetProp SetPropW -#define GetProp GetPropW -#define RemoveProp RemovePropW -#define EnumPropsEx EnumPropsExW -#define EnumProps EnumPropsW -#define SetWindowText SetWindowTextW -#define GetWindowText GetWindowTextW -#define GetWindowTextLength GetWindowTextLengthW -#else -#define SetProp SetPropA -#define GetProp GetPropA -#define RemoveProp RemovePropA -#define EnumPropsEx EnumPropsExA -#define EnumProps EnumPropsA -#define SetWindowText SetWindowTextA -#define GetWindowText GetWindowTextA -#define GetWindowTextLength GetWindowTextLengthA -#endif - - WINUSERAPI WINBOOL WINAPI SetPropA(HWND hWnd,LPCSTR lpString,HANDLE hData); - WINUSERAPI WINBOOL WINAPI SetPropW(HWND hWnd,LPCWSTR lpString,HANDLE hData); - WINUSERAPI HANDLE WINAPI GetPropA(HWND hWnd,LPCSTR lpString); - WINUSERAPI HANDLE WINAPI GetPropW(HWND hWnd,LPCWSTR lpString); - WINUSERAPI HANDLE WINAPI RemovePropA(HWND hWnd,LPCSTR lpString); - WINUSERAPI HANDLE WINAPI RemovePropW(HWND hWnd,LPCWSTR lpString); - WINUSERAPI int WINAPI EnumPropsExA(HWND hWnd,PROPENUMPROCEXA lpEnumFunc,LPARAM lParam); - WINUSERAPI int WINAPI EnumPropsExW(HWND hWnd,PROPENUMPROCEXW lpEnumFunc,LPARAM lParam); - WINUSERAPI int WINAPI EnumPropsA(HWND hWnd,PROPENUMPROCA lpEnumFunc); - WINUSERAPI int WINAPI EnumPropsW(HWND hWnd,PROPENUMPROCW lpEnumFunc); - WINUSERAPI WINBOOL WINAPI SetWindowTextA(HWND hWnd,LPCSTR lpString); - WINUSERAPI WINBOOL WINAPI SetWindowTextW(HWND hWnd,LPCWSTR lpString); - WINUSERAPI int WINAPI GetWindowTextA(HWND hWnd,LPSTR lpString,int nMaxCount); - WINUSERAPI int WINAPI GetWindowTextW(HWND hWnd,LPWSTR lpString,int nMaxCount); - WINUSERAPI int WINAPI GetWindowTextLengthA(HWND hWnd); - WINUSERAPI int WINAPI GetWindowTextLengthW(HWND hWnd); - WINUSERAPI WINBOOL WINAPI GetClientRect(HWND hWnd,LPRECT lpRect); - WINUSERAPI WINBOOL WINAPI GetWindowRect(HWND hWnd,LPRECT lpRect); - WINUSERAPI WINBOOL WINAPI AdjustWindowRect(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu); - WINUSERAPI WINBOOL WINAPI AdjustWindowRectEx(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu,DWORD dwExStyle); - -#define HELPINFO_WINDOW 0x0001 -#define HELPINFO_MENUITEM 0x0002 - - typedef struct tagHELPINFO { - UINT cbSize; - int iContextType; - int iCtrlId; - HANDLE hItemHandle; - DWORD_PTR dwContextId; - POINT MousePos; - } HELPINFO,*LPHELPINFO; - - WINUSERAPI WINBOOL WINAPI SetWindowContextHelpId(HWND,DWORD); - WINUSERAPI DWORD WINAPI GetWindowContextHelpId(HWND); - WINUSERAPI WINBOOL WINAPI SetMenuContextHelpId(HMENU,DWORD); - WINUSERAPI DWORD WINAPI GetMenuContextHelpId(HMENU); - -#ifndef NOMB - -#define MB_OK 0x00000000L -#define MB_OKCANCEL 0x00000001L -#define MB_ABORTRETRYIGNORE 0x00000002L -#define MB_YESNOCANCEL 0x00000003L -#define MB_YESNO 0x00000004L -#define MB_RETRYCANCEL 0x00000005L -#define MB_CANCELTRYCONTINUE 0x00000006L -#define MB_ICONHAND 0x00000010L -#define MB_ICONQUESTION 0x00000020L -#define MB_ICONEXCLAMATION 0x00000030L -#define MB_ICONASTERISK 0x00000040L -#define MB_USERICON 0x00000080L -#define MB_ICONWARNING MB_ICONEXCLAMATION -#define MB_ICONERROR MB_ICONHAND -#define MB_ICONINFORMATION MB_ICONASTERISK -#define MB_ICONSTOP MB_ICONHAND -#define MB_DEFBUTTON1 0x00000000L -#define MB_DEFBUTTON2 0x00000100L -#define MB_DEFBUTTON3 0x00000200L -#define MB_DEFBUTTON4 0x00000300L -#define MB_APPLMODAL 0x00000000L -#define MB_SYSTEMMODAL 0x00001000L -#define MB_TASKMODAL 0x00002000L -#define MB_HELP 0x00004000L -#define MB_NOFOCUS 0x00008000L -#define MB_SETFOREGROUND 0x00010000L -#define MB_DEFAULT_DESKTOP_ONLY 0x00020000L -#define MB_TOPMOST 0x00040000L -#define MB_RIGHT 0x00080000L -#define MB_RTLREADING 0x00100000L -#define MB_SERVICE_NOTIFICATION 0x00200000L -#define MB_SERVICE_NOTIFICATION_NT3X 0x00040000L -#define MB_TYPEMASK 0x0000000FL -#define MB_ICONMASK 0x000000F0L -#define MB_DEFMASK 0x00000F00L -#define MB_MODEMASK 0x00003000L -#define MB_MISCMASK 0x0000C000L - -#ifdef UNICODE -#define MessageBox MessageBoxW -#define MessageBoxEx MessageBoxExW -#else -#define MessageBox MessageBoxA -#define MessageBoxEx MessageBoxExA -#endif - - WINUSERAPI int WINAPI MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); - WINUSERAPI int WINAPI MessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); - WINUSERAPI int WINAPI MessageBoxExA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType,WORD wLanguageId); - WINUSERAPI int WINAPI MessageBoxExW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType,WORD wLanguageId); - - typedef VOID (CALLBACK *MSGBOXCALLBACK)(LPHELPINFO lpHelpInfo); - - typedef struct tagMSGBOXPARAMSA { - UINT cbSize; - HWND hwndOwner; - HINSTANCE hInstance; - LPCSTR lpszText; - LPCSTR lpszCaption; - DWORD dwStyle; - LPCSTR lpszIcon; - DWORD_PTR dwContextHelpId; - MSGBOXCALLBACK lpfnMsgBoxCallback; - DWORD dwLanguageId; - } MSGBOXPARAMSA,*PMSGBOXPARAMSA,*LPMSGBOXPARAMSA; - - typedef struct tagMSGBOXPARAMSW { - UINT cbSize; - HWND hwndOwner; - HINSTANCE hInstance; - LPCWSTR lpszText; - LPCWSTR lpszCaption; - DWORD dwStyle; - LPCWSTR lpszIcon; - DWORD_PTR dwContextHelpId; - MSGBOXCALLBACK lpfnMsgBoxCallback; - DWORD dwLanguageId; - } MSGBOXPARAMSW,*PMSGBOXPARAMSW,*LPMSGBOXPARAMSW; - -#ifdef UNICODE - typedef MSGBOXPARAMSW MSGBOXPARAMS; - typedef PMSGBOXPARAMSW PMSGBOXPARAMS; - typedef LPMSGBOXPARAMSW LPMSGBOXPARAMS; -#else - typedef MSGBOXPARAMSA MSGBOXPARAMS; - typedef PMSGBOXPARAMSA PMSGBOXPARAMS; - typedef LPMSGBOXPARAMSA LPMSGBOXPARAMS; -#endif - -#ifdef UNICODE -#define MessageBoxIndirect MessageBoxIndirectW -#else -#define MessageBoxIndirect MessageBoxIndirectA -#endif - - WINUSERAPI int WINAPI MessageBoxIndirectA(CONST MSGBOXPARAMSA *lpmbp); - WINUSERAPI int WINAPI MessageBoxIndirectW(CONST MSGBOXPARAMSW *lpmbp); - WINUSERAPI WINBOOL WINAPI MessageBeep(UINT uType); -#endif - - WINUSERAPI int WINAPI ShowCursor(WINBOOL bShow); - WINUSERAPI WINBOOL WINAPI SetCursorPos(int X,int Y); - WINUSERAPI HCURSOR WINAPI SetCursor(HCURSOR hCursor); - WINUSERAPI WINBOOL WINAPI GetCursorPos(LPPOINT lpPoint); - WINUSERAPI WINBOOL WINAPI ClipCursor(CONST RECT *lpRect); - WINUSERAPI WINBOOL WINAPI GetClipCursor(LPRECT lpRect); - WINUSERAPI HCURSOR WINAPI GetCursor(VOID); - WINUSERAPI WINBOOL WINAPI CreateCaret(HWND hWnd,HBITMAP hBitmap,int nWidth,int nHeight); - WINUSERAPI UINT WINAPI GetCaretBlinkTime(VOID); - WINUSERAPI WINBOOL WINAPI SetCaretBlinkTime(UINT uMSeconds); - WINUSERAPI WINBOOL WINAPI DestroyCaret(VOID); - WINUSERAPI WINBOOL WINAPI HideCaret(HWND hWnd); - WINUSERAPI WINBOOL WINAPI ShowCaret(HWND hWnd); - WINUSERAPI WINBOOL WINAPI SetCaretPos(int X,int Y); - WINUSERAPI WINBOOL WINAPI GetCaretPos(LPPOINT lpPoint); - WINUSERAPI WINBOOL WINAPI ClientToScreen(HWND hWnd,LPPOINT lpPoint); - WINUSERAPI WINBOOL WINAPI ScreenToClient(HWND hWnd,LPPOINT lpPoint); - WINUSERAPI int WINAPI MapWindowPoints(HWND hWndFrom,HWND hWndTo,LPPOINT lpPoints,UINT cPoints); - WINUSERAPI HWND WINAPI WindowFromPoint(POINT Point); - WINUSERAPI HWND WINAPI ChildWindowFromPoint(HWND hWndParent,POINT Point); - -#define CWP_ALL 0x0000 -#define CWP_SKIPINVISIBLE 0x0001 -#define CWP_SKIPDISABLED 0x0002 -#define CWP_SKIPTRANSPARENT 0x0004 - - WINUSERAPI HWND WINAPI ChildWindowFromPointEx(HWND hwnd,POINT pt,UINT flags); - -#ifndef NOCOLOR - -#define CTLCOLOR_MSGBOX 0 -#define CTLCOLOR_EDIT 1 -#define CTLCOLOR_LISTBOX 2 -#define CTLCOLOR_BTN 3 -#define CTLCOLOR_DLG 4 -#define CTLCOLOR_SCROLLBAR 5 -#define CTLCOLOR_STATIC 6 -#define CTLCOLOR_MAX 7 - -#define COLOR_SCROLLBAR 0 -#define COLOR_BACKGROUND 1 -#define COLOR_ACTIVECAPTION 2 -#define COLOR_INACTIVECAPTION 3 -#define COLOR_MENU 4 -#define COLOR_WINDOW 5 -#define COLOR_WINDOWFRAME 6 -#define COLOR_MENUTEXT 7 -#define COLOR_WINDOWTEXT 8 -#define COLOR_CAPTIONTEXT 9 -#define COLOR_ACTIVEBORDER 10 -#define COLOR_INACTIVEBORDER 11 -#define COLOR_APPWORKSPACE 12 -#define COLOR_HIGHLIGHT 13 -#define COLOR_HIGHLIGHTTEXT 14 -#define COLOR_BTNFACE 15 -#define COLOR_BTNSHADOW 16 -#define COLOR_GRAYTEXT 17 -#define COLOR_BTNTEXT 18 -#define COLOR_INACTIVECAPTIONTEXT 19 -#define COLOR_BTNHIGHLIGHT 20 - -#define COLOR_3DDKSHADOW 21 -#define COLOR_3DLIGHT 22 -#define COLOR_INFOTEXT 23 -#define COLOR_INFOBK 24 - -#define COLOR_HOTLIGHT 26 -#define COLOR_GRADIENTACTIVECAPTION 27 -#define COLOR_GRADIENTINACTIVECAPTION 28 -#define COLOR_MENUHILIGHT 29 -#define COLOR_MENUBAR 30 - -#define COLOR_DESKTOP COLOR_BACKGROUND -#define COLOR_3DFACE COLOR_BTNFACE -#define COLOR_3DSHADOW COLOR_BTNSHADOW -#define COLOR_3DHIGHLIGHT COLOR_BTNHIGHLIGHT -#define COLOR_3DHILIGHT COLOR_BTNHIGHLIGHT -#define COLOR_BTNHILIGHT COLOR_BTNHIGHLIGHT - - WINUSERAPI DWORD WINAPI GetSysColor(int nIndex); - WINUSERAPI HBRUSH WINAPI GetSysColorBrush(int nIndex); - WINUSERAPI WINBOOL WINAPI SetSysColors(int cElements,CONST INT *lpaElements,CONST COLORREF *lpaRgbValues); -#endif - - WINUSERAPI WINBOOL WINAPI DrawFocusRect(HDC hDC,CONST RECT *lprc); - WINUSERAPI int WINAPI FillRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); - WINUSERAPI int WINAPI FrameRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); - WINUSERAPI WINBOOL WINAPI InvertRect(HDC hDC,CONST RECT *lprc); - WINUSERAPI WINBOOL WINAPI SetRect(LPRECT lprc,int xLeft,int yTop,int xRight,int yBottom); - WINUSERAPI WINBOOL WINAPI SetRectEmpty(LPRECT lprc); - WINUSERAPI WINBOOL WINAPI CopyRect(LPRECT lprcDst,CONST RECT *lprcSrc); - WINUSERAPI WINBOOL WINAPI InflateRect(LPRECT lprc,int dx,int dy); - WINUSERAPI WINBOOL WINAPI IntersectRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); - WINUSERAPI WINBOOL WINAPI UnionRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); - WINUSERAPI WINBOOL WINAPI SubtractRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); - WINUSERAPI WINBOOL WINAPI OffsetRect(LPRECT lprc,int dx,int dy); - WINUSERAPI WINBOOL WINAPI IsRectEmpty(CONST RECT *lprc); - WINUSERAPI WINBOOL WINAPI EqualRect(CONST RECT *lprc1,CONST RECT *lprc2); - WINUSERAPI WINBOOL WINAPI PtInRect(CONST RECT *lprc,POINT pt); - -#ifndef NOWINOFFSETS - -#ifdef UNICODE -#define GetWindowLong GetWindowLongW -#define SetWindowLong SetWindowLongW -#else -#define GetWindowLong GetWindowLongA -#define SetWindowLong SetWindowLongA -#endif - - WINUSERAPI WORD WINAPI GetWindowWord(HWND hWnd,int nIndex); - WINUSERAPI WORD WINAPI SetWindowWord(HWND hWnd,int nIndex,WORD wNewWord); - WINUSERAPI LONG WINAPI GetWindowLongA(HWND hWnd,int nIndex); - WINUSERAPI LONG WINAPI GetWindowLongW(HWND hWnd,int nIndex); - WINUSERAPI LONG WINAPI SetWindowLongA(HWND hWnd,int nIndex,LONG dwNewLong); - WINUSERAPI LONG WINAPI SetWindowLongW(HWND hWnd,int nIndex,LONG dwNewLong); - -#ifdef _WIN64 - -#ifdef UNICODE -#define GetWindowLongPtr GetWindowLongPtrW -#define SetWindowLongPtr SetWindowLongPtrW -#else -#define GetWindowLongPtr GetWindowLongPtrA -#define SetWindowLongPtr SetWindowLongPtrA -#endif - - WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrA(HWND hWnd,int nIndex); - WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrW(HWND hWnd,int nIndex); - WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); - WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); -#else - -#ifdef UNICODE -#define GetWindowLongPtr GetWindowLongPtrW -#define SetWindowLongPtr SetWindowLongPtrW -#else -#define GetWindowLongPtr GetWindowLongPtrA -#define SetWindowLongPtr SetWindowLongPtrA -#endif - -#define GetWindowLongPtrA GetWindowLongA -#define GetWindowLongPtrW GetWindowLongW -#define SetWindowLongPtrA SetWindowLongA -#define SetWindowLongPtrW SetWindowLongW -#endif - -#ifdef UNICODE -#define GetClassLong GetClassLongW -#define SetClassLong SetClassLongW -#else -#define GetClassLong GetClassLongA -#define SetClassLong SetClassLongA -#endif - - WINUSERAPI WORD WINAPI GetClassWord(HWND hWnd,int nIndex); - WINUSERAPI WORD WINAPI SetClassWord(HWND hWnd,int nIndex,WORD wNewWord); - WINUSERAPI DWORD WINAPI GetClassLongA(HWND hWnd,int nIndex); - WINUSERAPI DWORD WINAPI GetClassLongW(HWND hWnd,int nIndex); - WINUSERAPI DWORD WINAPI SetClassLongA(HWND hWnd,int nIndex,LONG dwNewLong); - WINUSERAPI DWORD WINAPI SetClassLongW(HWND hWnd,int nIndex,LONG dwNewLong); - -#ifdef _WIN64 - -#ifdef UNICODE -#define GetClassLongPtr GetClassLongPtrW -#define SetClassLongPtr SetClassLongPtrW -#else -#define GetClassLongPtr GetClassLongPtrA -#define SetClassLongPtr SetClassLongPtrA -#endif - - WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrA(HWND hWnd,int nIndex); - WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrW(HWND hWnd,int nIndex); - WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); - WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); -#else -#ifdef UNICODE -#define GetClassLongPtr GetClassLongPtrW -#define SetClassLongPtr SetClassLongPtrW -#else -#define GetClassLongPtr GetClassLongPtrA -#define SetClassLongPtr SetClassLongPtrA -#endif - -#define GetClassLongPtrA GetClassLongA -#define GetClassLongPtrW GetClassLongW -#define SetClassLongPtrA SetClassLongA -#define SetClassLongPtrW SetClassLongW -#endif -#endif - -#ifdef UNICODE -#define FindWindow FindWindowW -#define FindWindowEx FindWindowExW -#define GetClassName GetClassNameW -#else -#define FindWindow FindWindowA -#define FindWindowEx FindWindowExA -#define GetClassName GetClassNameA -#endif - - WINUSERAPI WINBOOL WINAPI GetProcessDefaultLayout(DWORD *pdwDefaultLayout); - WINUSERAPI WINBOOL WINAPI SetProcessDefaultLayout(DWORD dwDefaultLayout); - WINUSERAPI HWND WINAPI GetDesktopWindow(VOID); - WINUSERAPI HWND WINAPI GetParent(HWND hWnd); - WINUSERAPI HWND WINAPI SetParent(HWND hWndChild,HWND hWndNewParent); - WINUSERAPI WINBOOL WINAPI EnumChildWindows(HWND hWndParent,WNDENUMPROC lpEnumFunc,LPARAM lParam); - WINUSERAPI HWND WINAPI FindWindowA(LPCSTR lpClassName,LPCSTR lpWindowName); - WINUSERAPI HWND WINAPI FindWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName); - WINUSERAPI HWND WINAPI FindWindowExA(HWND hWndParent,HWND hWndChildAfter,LPCSTR lpszClass,LPCSTR lpszWindow); - WINUSERAPI HWND WINAPI FindWindowExW(HWND hWndParent,HWND hWndChildAfter,LPCWSTR lpszClass,LPCWSTR lpszWindow); - WINUSERAPI HWND WINAPI GetShellWindow(VOID); - WINUSERAPI WINBOOL WINAPI RegisterShellHookWindow(HWND hwnd); - WINUSERAPI WINBOOL WINAPI DeregisterShellHookWindow(HWND hwnd); - WINUSERAPI WINBOOL WINAPI EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam); - WINUSERAPI WINBOOL WINAPI EnumThreadWindows(DWORD dwThreadId,WNDENUMPROC lpfn,LPARAM lParam); - -#define EnumTaskWindows(hTask,lpfn,lParam) EnumThreadWindows(HandleToUlong(hTask),lpfn,lParam) - - WINUSERAPI int WINAPI GetClassNameA(HWND hWnd,LPSTR lpClassName,int nMaxCount); - WINUSERAPI int WINAPI GetClassNameW(HWND hWnd,LPWSTR lpClassName,int nMaxCount); - WINUSERAPI HWND WINAPI GetTopWindow(HWND hWnd); - -#define GetNextWindow(hWnd,wCmd) GetWindow(hWnd,wCmd) -#define GetSysModalWindow() (NULL) -#define SetSysModalWindow(hWnd) (NULL) - - WINUSERAPI DWORD WINAPI GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId); - WINUSERAPI WINBOOL WINAPI IsGUIThread(WINBOOL bConvert); - -#define GetWindowTask(hWnd) ((HANDLE)(DWORD_PTR)GetWindowThreadProcessId(hWnd,NULL)) - - WINUSERAPI HWND WINAPI GetLastActivePopup(HWND hWnd); - -#define GW_HWNDFIRST 0 -#define GW_HWNDLAST 1 -#define GW_HWNDNEXT 2 -#define GW_HWNDPREV 3 -#define GW_OWNER 4 -#define GW_CHILD 5 -#define GW_ENABLEDPOPUP 6 -#define GW_MAX 6 - - WINUSERAPI HWND WINAPI GetWindow(HWND hWnd,UINT uCmd); - -#ifndef NOWH - -#ifdef UNICODE -#define SetWindowsHook SetWindowsHookW -#define SetWindowsHookEx SetWindowsHookExW -#else -#define SetWindowsHook SetWindowsHookA -#define SetWindowsHookEx SetWindowsHookExA -#endif - - WINUSERAPI HHOOK WINAPI SetWindowsHookA(int nFilterType,HOOKPROC pfnFilterProc); - WINUSERAPI HHOOK WINAPI SetWindowsHookW(int nFilterType,HOOKPROC pfnFilterProc); - WINUSERAPI WINBOOL WINAPI UnhookWindowsHook(int nCode,HOOKPROC pfnFilterProc); - WINUSERAPI HHOOK WINAPI SetWindowsHookExA(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); - WINUSERAPI HHOOK WINAPI SetWindowsHookExW(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); - WINUSERAPI WINBOOL WINAPI UnhookWindowsHookEx(HHOOK hhk); - WINUSERAPI LRESULT WINAPI CallNextHookEx(HHOOK hhk,int nCode,WPARAM wParam,LPARAM lParam); -#define DefHookProc(nCode,wParam,lParam,phhk) CallNextHookEx(*phhk,nCode,wParam,lParam) -#endif - -#ifndef NOMENUS - -#define MF_INSERT 0x00000000L -#define MF_CHANGE 0x00000080L -#define MF_APPEND 0x00000100L -#define MF_DELETE 0x00000200L -#define MF_REMOVE 0x00001000L -#define MF_BYCOMMAND 0x00000000L -#define MF_BYPOSITION 0x00000400L -#define MF_SEPARATOR 0x00000800L -#define MF_ENABLED 0x00000000L -#define MF_GRAYED 0x00000001L -#define MF_DISABLED 0x00000002L -#define MF_UNCHECKED 0x00000000L -#define MF_CHECKED 0x00000008L -#define MF_USECHECKBITMAPS 0x00000200L -#define MF_STRING 0x00000000L -#define MF_BITMAP 0x00000004L -#define MF_OWNERDRAW 0x00000100L -#define MF_POPUP 0x00000010L -#define MF_MENUBARBREAK 0x00000020L -#define MF_MENUBREAK 0x00000040L -#define MF_UNHILITE 0x00000000L -#define MF_HILITE 0x00000080L -#define MF_DEFAULT 0x00001000L -#define MF_SYSMENU 0x00002000L -#define MF_HELP 0x00004000L -#define MF_RIGHTJUSTIFY 0x00004000L -#define MF_MOUSESELECT 0x00008000L -#define MF_END 0x00000080L - -#define MFT_STRING MF_STRING -#define MFT_BITMAP MF_BITMAP -#define MFT_MENUBARBREAK MF_MENUBARBREAK -#define MFT_MENUBREAK MF_MENUBREAK -#define MFT_OWNERDRAW MF_OWNERDRAW -#define MFT_RADIOCHECK 0x00000200L -#define MFT_SEPARATOR MF_SEPARATOR -#define MFT_RIGHTORDER 0x00002000L -#define MFT_RIGHTJUSTIFY MF_RIGHTJUSTIFY - -#define MFS_GRAYED 0x00000003L -#define MFS_DISABLED MFS_GRAYED -#define MFS_CHECKED MF_CHECKED -#define MFS_HILITE MF_HILITE -#define MFS_ENABLED MF_ENABLED -#define MFS_UNCHECKED MF_UNCHECKED -#define MFS_UNHILITE MF_UNHILITE -#define MFS_DEFAULT MF_DEFAULT - - WINUSERAPI WINBOOL WINAPI CheckMenuRadioItem(HMENU hmenu,UINT first,UINT last,UINT check,UINT flags); - - typedef struct { - WORD versionNumber; - WORD offset; - } MENUITEMTEMPLATEHEADER,*PMENUITEMTEMPLATEHEADER; - - typedef struct { - WORD mtOption; - WORD mtID; - WCHAR mtString[1]; - } MENUITEMTEMPLATE,*PMENUITEMTEMPLATE; -#define MF_END 0x00000080L -#endif - -#ifndef NOSYSCOMMANDS - -#define SC_SIZE 0xF000 -#define SC_MOVE 0xF010 -#define SC_MINIMIZE 0xF020 -#define SC_MAXIMIZE 0xF030 -#define SC_NEXTWINDOW 0xF040 -#define SC_PREVWINDOW 0xF050 -#define SC_CLOSE 0xF060 -#define SC_VSCROLL 0xF070 -#define SC_HSCROLL 0xF080 -#define SC_MOUSEMENU 0xF090 -#define SC_KEYMENU 0xF100 -#define SC_ARRANGE 0xF110 -#define SC_RESTORE 0xF120 -#define SC_TASKLIST 0xF130 -#define SC_SCREENSAVE 0xF140 -#define SC_HOTKEY 0xF150 -#define SC_DEFAULT 0xF160 -#define SC_MONITORPOWER 0xF170 -#define SC_CONTEXTHELP 0xF180 -#define SC_SEPARATOR 0xF00F -#define SC_ICON SC_MINIMIZE -#define SC_ZOOM SC_MAXIMIZE -#endif - -#ifdef UNICODE -#define LoadBitmap LoadBitmapW -#define LoadCursor LoadCursorW -#define LoadCursorFromFile LoadCursorFromFileW -#else -#define LoadBitmap LoadBitmapA -#define LoadCursor LoadCursorA -#define LoadCursorFromFile LoadCursorFromFileA -#endif - - WINUSERAPI HBITMAP WINAPI LoadBitmapA(HINSTANCE hInstance,LPCSTR lpBitmapName); - WINUSERAPI HBITMAP WINAPI LoadBitmapW(HINSTANCE hInstance,LPCWSTR lpBitmapName); - WINUSERAPI HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance,LPCSTR lpCursorName); - WINUSERAPI HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance,LPCWSTR lpCursorName); - WINUSERAPI HCURSOR WINAPI LoadCursorFromFileA(LPCSTR lpFileName); - WINUSERAPI HCURSOR WINAPI LoadCursorFromFileW(LPCWSTR lpFileName); - WINUSERAPI HCURSOR WINAPI CreateCursor(HINSTANCE hInst,int xHotSpot,int yHotSpot,int nWidth,int nHeight,CONST VOID *pvANDPlane,CONST VOID *pvXORPlane); - WINUSERAPI WINBOOL WINAPI DestroyCursor(HCURSOR hCursor); - -#define CopyCursor(pcur) ((HCURSOR)CopyIcon((HICON)(pcur))) - -#define IDC_ARROW MAKEINTRESOURCE(32512) -#define IDC_IBEAM MAKEINTRESOURCE(32513) -#define IDC_WAIT MAKEINTRESOURCE(32514) -#define IDC_CROSS MAKEINTRESOURCE(32515) -#define IDC_UPARROW MAKEINTRESOURCE(32516) -#define IDC_SIZE MAKEINTRESOURCE(32640) -#define IDC_ICON MAKEINTRESOURCE(32641) -#define IDC_SIZENWSE MAKEINTRESOURCE(32642) -#define IDC_SIZENESW MAKEINTRESOURCE(32643) -#define IDC_SIZEWE MAKEINTRESOURCE(32644) -#define IDC_SIZENS MAKEINTRESOURCE(32645) -#define IDC_SIZEALL MAKEINTRESOURCE(32646) -#define IDC_NO MAKEINTRESOURCE(32648) -#define IDC_HAND MAKEINTRESOURCE(32649) -#define IDC_APPSTARTING MAKEINTRESOURCE(32650) -#define IDC_HELP MAKEINTRESOURCE(32651) - - WINUSERAPI WINBOOL WINAPI SetSystemCursor(HCURSOR hcur,DWORD id); - - typedef struct _ICONINFO { - WINBOOL fIcon; - DWORD xHotspot; - DWORD yHotspot; - HBITMAP hbmMask; - HBITMAP hbmColor; - } ICONINFO; - typedef ICONINFO *PICONINFO; - -#ifdef UNICODE -#define LoadIcon LoadIconW -#define PrivateExtractIcons PrivateExtractIconsW -#else -#define LoadIcon LoadIconA -#define PrivateExtractIcons PrivateExtractIconsA -#endif - - WINUSERAPI HICON WINAPI LoadIconA(HINSTANCE hInstance,LPCSTR lpIconName); - WINUSERAPI HICON WINAPI LoadIconW(HINSTANCE hInstance,LPCWSTR lpIconName); - WINUSERAPI UINT WINAPI PrivateExtractIconsA(LPCSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); - WINUSERAPI UINT WINAPI PrivateExtractIconsW(LPCWSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); - WINUSERAPI HICON WINAPI CreateIcon(HINSTANCE hInstance,int nWidth,int nHeight,BYTE cPlanes,BYTE cBitsPixel,CONST BYTE *lpbANDbits,CONST BYTE *lpbXORbits); - WINUSERAPI WINBOOL WINAPI DestroyIcon(HICON hIcon); - WINUSERAPI int WINAPI LookupIconIdFromDirectory(PBYTE presbits,WINBOOL fIcon); - WINUSERAPI int WINAPI LookupIconIdFromDirectoryEx(PBYTE presbits,WINBOOL fIcon,int cxDesired,int cyDesired,UINT Flags); - WINUSERAPI HICON WINAPI CreateIconFromResource(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer); - WINUSERAPI HICON WINAPI CreateIconFromResourceEx(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer,int cxDesired,int cyDesired,UINT Flags); - - typedef struct tagCURSORSHAPE { - int xHotSpot; - int yHotSpot; - int cx; - int cy; - int cbWidth; - BYTE Planes; - BYTE BitsPixel; - } CURSORSHAPE,*LPCURSORSHAPE; - -#define IMAGE_BITMAP 0 -#define IMAGE_ICON 1 -#define IMAGE_CURSOR 2 -#define IMAGE_ENHMETAFILE 3 - -#define LR_DEFAULTCOLOR 0x0000 -#define LR_MONOCHROME 0x0001 -#define LR_COLOR 0x0002 -#define LR_COPYRETURNORG 0x0004 -#define LR_COPYDELETEORG 0x0008 -#define LR_LOADFROMFILE 0x0010 -#define LR_LOADTRANSPARENT 0x0020 -#define LR_DEFAULTSIZE 0x0040 -#define LR_VGACOLOR 0x0080 -#define LR_LOADMAP3DCOLORS 0x1000 -#define LR_CREATEDIBSECTION 0x2000 -#define LR_COPYFROMRESOURCE 0x4000 -#define LR_SHARED 0x8000 - -#ifdef UNICODE -#define LoadImage LoadImageW -#else -#define LoadImage LoadImageA -#endif - - WINUSERAPI HANDLE WINAPI LoadImageA(HINSTANCE hInst,LPCSTR name,UINT type,int cx,int cy,UINT fuLoad); - WINUSERAPI HANDLE WINAPI LoadImageW(HINSTANCE hInst,LPCWSTR name,UINT type,int cx,int cy,UINT fuLoad); - WINUSERAPI HANDLE WINAPI CopyImage(HANDLE h,UINT type,int cx,int cy,UINT flags); - -#define DI_MASK 0x0001 -#define DI_IMAGE 0x0002 -#define DI_NORMAL 0x0003 -#define DI_COMPAT 0x0004 -#define DI_DEFAULTSIZE 0x0008 -#define DI_NOMIRROR 0x0010 - - WINUSERAPI WINBOOL WINAPI DrawIconEx(HDC hdc,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyWidth,UINT istepIfAniCur,HBRUSH hbrFlickerFreeDraw,UINT diFlags); - WINUSERAPI HICON WINAPI CreateIconIndirect(PICONINFO piconinfo); - WINUSERAPI HICON WINAPI CopyIcon(HICON hIcon); - WINUSERAPI WINBOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO piconinfo); - -#define RES_ICON 1 -#define RES_CURSOR 2 - -#ifdef OEMRESOURCE - -#define OBM_CLOSE 32754 -#define OBM_UPARROW 32753 -#define OBM_DNARROW 32752 -#define OBM_RGARROW 32751 -#define OBM_LFARROW 32750 -#define OBM_REDUCE 32749 -#define OBM_ZOOM 32748 -#define OBM_RESTORE 32747 -#define OBM_REDUCED 32746 -#define OBM_ZOOMD 32745 -#define OBM_RESTORED 32744 -#define OBM_UPARROWD 32743 -#define OBM_DNARROWD 32742 -#define OBM_RGARROWD 32741 -#define OBM_LFARROWD 32740 -#define OBM_MNARROW 32739 -#define OBM_COMBO 32738 -#define OBM_UPARROWI 32737 -#define OBM_DNARROWI 32736 -#define OBM_RGARROWI 32735 -#define OBM_LFARROWI 32734 - -#define OBM_OLD_CLOSE 32767 -#define OBM_SIZE 32766 -#define OBM_OLD_UPARROW 32765 -#define OBM_OLD_DNARROW 32764 -#define OBM_OLD_RGARROW 32763 -#define OBM_OLD_LFARROW 32762 -#define OBM_BTSIZE 32761 -#define OBM_CHECK 32760 -#define OBM_CHECKBOXES 32759 -#define OBM_BTNCORNERS 32758 -#define OBM_OLD_REDUCE 32757 -#define OBM_OLD_ZOOM 32756 -#define OBM_OLD_RESTORE 32755 - -#define OCR_NORMAL 32512 -#define OCR_IBEAM 32513 -#define OCR_WAIT 32514 -#define OCR_CROSS 32515 -#define OCR_UP 32516 -#define OCR_SIZE 32640 -#define OCR_ICON 32641 -#define OCR_SIZENWSE 32642 -#define OCR_SIZENESW 32643 -#define OCR_SIZEWE 32644 -#define OCR_SIZENS 32645 -#define OCR_SIZEALL 32646 -#define OCR_ICOCUR 32647 -#define OCR_NO 32648 -#define OCR_HAND 32649 -#define OCR_APPSTARTING 32650 - -#define OIC_SAMPLE 32512 -#define OIC_HAND 32513 -#define OIC_QUES 32514 -#define OIC_BANG 32515 -#define OIC_NOTE 32516 -#define OIC_WINLOGO 32517 -#define OIC_WARNING OIC_BANG -#define OIC_ERROR OIC_HAND -#define OIC_INFORMATION OIC_NOTE -#endif - -#define ORD_LANGDRIVER 1 - -#ifndef NOICONS - -#ifdef RC_INVOKED -#define IDI_APPLICATION 32512 -#define IDI_HAND 32513 -#define IDI_QUESTION 32514 -#define IDI_EXCLAMATION 32515 -#define IDI_ASTERISK 32516 -#define IDI_WINLOGO 32517 -#else -#define IDI_APPLICATION MAKEINTRESOURCE(32512) -#define IDI_HAND MAKEINTRESOURCE(32513) -#define IDI_QUESTION MAKEINTRESOURCE(32514) -#define IDI_EXCLAMATION MAKEINTRESOURCE(32515) -#define IDI_ASTERISK MAKEINTRESOURCE(32516) -#define IDI_WINLOGO MAKEINTRESOURCE(32517) -#endif - -#define IDI_WARNING IDI_EXCLAMATION -#define IDI_ERROR IDI_HAND -#define IDI_INFORMATION IDI_ASTERISK -#endif - -#ifdef UNICODE -#define LoadString LoadStringW -#else -#define LoadString LoadStringA -#endif - - WINUSERAPI int WINAPI LoadStringA(HINSTANCE hInstance,UINT uID,LPSTR lpBuffer,int cchBufferMax); - WINUSERAPI int WINAPI LoadStringW(HINSTANCE hInstance,UINT uID,LPWSTR lpBuffer,int cchBufferMax); - -#define IDOK 1 -#define IDCANCEL 2 -#define IDABORT 3 -#define IDRETRY 4 -#define IDIGNORE 5 -#define IDYES 6 -#define IDNO 7 -#define IDCLOSE 8 -#define IDHELP 9 -#define IDTRYAGAIN 10 -#define IDCONTINUE 11 - -#ifndef IDTIMEOUT -#define IDTIMEOUT 32000 -#endif - -#ifndef NOCTLMGR - -#ifndef NOWINSTYLES -#define ES_LEFT 0x0000L -#define ES_CENTER 0x0001L -#define ES_RIGHT 0x0002L -#define ES_MULTILINE 0x0004L -#define ES_UPPERCASE 0x0008L -#define ES_LOWERCASE 0x0010L -#define ES_PASSWORD 0x0020L -#define ES_AUTOVSCROLL 0x0040L -#define ES_AUTOHSCROLL 0x0080L -#define ES_NOHIDESEL 0x0100L -#define ES_OEMCONVERT 0x0400L -#define ES_READONLY 0x0800L -#define ES_WANTRETURN 0x1000L -#define ES_NUMBER 0x2000L -#endif - -#define EN_SETFOCUS 0x0100 -#define EN_KILLFOCUS 0x0200 -#define EN_CHANGE 0x0300 -#define EN_UPDATE 0x0400 -#define EN_ERRSPACE 0x0500 -#define EN_MAXTEXT 0x0501 -#define EN_HSCROLL 0x0601 -#define EN_VSCROLL 0x0602 -#define EN_ALIGN_LTR_EC 0x0700 -#define EN_ALIGN_RTL_EC 0x0701 - -#define EC_LEFTMARGIN 0x0001 -#define EC_RIGHTMARGIN 0x0002 -#define EC_USEFONTINFO 0xffff - -#define EMSIS_COMPOSITIONSTRING 0x0001 - -#define EIMES_GETCOMPSTRATONCE 0x0001 -#define EIMES_CANCELCOMPSTRINFOCUS 0x0002 -#define EIMES_COMPLETECOMPSTRKILLFOCUS 0x0004 - -#ifndef NOWINMESSAGES - -#define EM_GETSEL 0x00B0 -#define EM_SETSEL 0x00B1 -#define EM_GETRECT 0x00B2 -#define EM_SETRECT 0x00B3 -#define EM_SETRECTNP 0x00B4 -#define EM_SCROLL 0x00B5 -#define EM_LINESCROLL 0x00B6 -#define EM_SCROLLCARET 0x00B7 -#define EM_GETMODIFY 0x00B8 -#define EM_SETMODIFY 0x00B9 -#define EM_GETLINECOUNT 0x00BA -#define EM_LINEINDEX 0x00BB -#define EM_SETHANDLE 0x00BC -#define EM_GETHANDLE 0x00BD -#define EM_GETTHUMB 0x00BE -#define EM_LINELENGTH 0x00C1 -#define EM_REPLACESEL 0x00C2 -#define EM_GETLINE 0x00C4 -#define EM_LIMITTEXT 0x00C5 -#define EM_CANUNDO 0x00C6 -#define EM_UNDO 0x00C7 -#define EM_FMTLINES 0x00C8 -#define EM_LINEFROMCHAR 0x00C9 -#define EM_SETTABSTOPS 0x00CB -#define EM_SETPASSWORDCHAR 0x00CC -#define EM_EMPTYUNDOBUFFER 0x00CD -#define EM_GETFIRSTVISIBLELINE 0x00CE -#define EM_SETREADONLY 0x00CF -#define EM_SETWORDBREAKPROC 0x00D0 -#define EM_GETWORDBREAKPROC 0x00D1 -#define EM_GETPASSWORDCHAR 0x00D2 -#define EM_SETMARGINS 0x00D3 -#define EM_GETMARGINS 0x00D4 -#define EM_SETLIMITTEXT EM_LIMITTEXT -#define EM_GETLIMITTEXT 0x00D5 -#define EM_POSFROMCHAR 0x00D6 -#define EM_CHARFROMPOS 0x00D7 -#define EM_SETIMESTATUS 0x00D8 -#define EM_GETIMESTATUS 0x00D9 -#endif - -#define WB_LEFT 0 -#define WB_RIGHT 1 -#define WB_ISDELIMITER 2 - -#define BS_PUSHBUTTON 0x00000000L -#define BS_DEFPUSHBUTTON 0x00000001L -#define BS_CHECKBOX 0x00000002L -#define BS_AUTOCHECKBOX 0x00000003L -#define BS_RADIOBUTTON 0x00000004L -#define BS_3STATE 0x00000005L -#define BS_AUTO3STATE 0x00000006L -#define BS_GROUPBOX 0x00000007L -#define BS_USERBUTTON 0x00000008L -#define BS_AUTORADIOBUTTON 0x00000009L -#define BS_PUSHBOX 0x0000000AL -#define BS_OWNERDRAW 0x0000000BL -#define BS_TYPEMASK 0x0000000FL -#define BS_LEFTTEXT 0x00000020L -#define BS_TEXT 0x00000000L -#define BS_ICON 0x00000040L -#define BS_BITMAP 0x00000080L -#define BS_LEFT 0x00000100L -#define BS_RIGHT 0x00000200L -#define BS_CENTER 0x00000300L -#define BS_TOP 0x00000400L -#define BS_BOTTOM 0x00000800L -#define BS_VCENTER 0x00000C00L -#define BS_PUSHLIKE 0x00001000L -#define BS_MULTILINE 0x00002000L -#define BS_NOTIFY 0x00004000L -#define BS_FLAT 0x00008000L -#define BS_RIGHTBUTTON BS_LEFTTEXT - -#define BN_CLICKED 0 -#define BN_PAINT 1 -#define BN_HILITE 2 -#define BN_UNHILITE 3 -#define BN_DISABLE 4 -#define BN_DOUBLECLICKED 5 -#define BN_PUSHED BN_HILITE -#define BN_UNPUSHED BN_UNHILITE -#define BN_DBLCLK BN_DOUBLECLICKED -#define BN_SETFOCUS 6 -#define BN_KILLFOCUS 7 - -#define BM_GETCHECK 0x00F0 -#define BM_SETCHECK 0x00F1 -#define BM_GETSTATE 0x00F2 -#define BM_SETSTATE 0x00F3 -#define BM_SETSTYLE 0x00F4 -#define BM_CLICK 0x00F5 -#define BM_GETIMAGE 0x00F6 -#define BM_SETIMAGE 0x00F7 - -#define BST_UNCHECKED 0x0000 -#define BST_CHECKED 0x0001 -#define BST_INDETERMINATE 0x0002 -#define BST_PUSHED 0x0004 -#define BST_FOCUS 0x0008 - -#define SS_LEFT 0x00000000L -#define SS_CENTER 0x00000001L -#define SS_RIGHT 0x00000002L -#define SS_ICON 0x00000003L -#define SS_BLACKRECT 0x00000004L -#define SS_GRAYRECT 0x00000005L -#define SS_WHITERECT 0x00000006L -#define SS_BLACKFRAME 0x00000007L -#define SS_GRAYFRAME 0x00000008L -#define SS_WHITEFRAME 0x00000009L -#define SS_USERITEM 0x0000000AL -#define SS_SIMPLE 0x0000000BL -#define SS_LEFTNOWORDWRAP 0x0000000CL -#define SS_OWNERDRAW 0x0000000DL -#define SS_BITMAP 0x0000000EL -#define SS_ENHMETAFILE 0x0000000FL -#define SS_ETCHEDHORZ 0x00000010L -#define SS_ETCHEDVERT 0x00000011L -#define SS_ETCHEDFRAME 0x00000012L -#define SS_TYPEMASK 0x0000001FL -#define SS_REALSIZECONTROL 0x00000040L -#define SS_NOPREFIX 0x00000080L -#define SS_NOTIFY 0x00000100L -#define SS_CENTERIMAGE 0x00000200L -#define SS_RIGHTJUST 0x00000400L -#define SS_REALSIZEIMAGE 0x00000800L -#define SS_SUNKEN 0x00001000L -#define SS_EDITCONTROL 0x00002000L -#define SS_ENDELLIPSIS 0x00004000L -#define SS_PATHELLIPSIS 0x00008000L -#define SS_WORDELLIPSIS 0x0000C000L -#define SS_ELLIPSISMASK 0x0000C000L - -#ifndef NOWINMESSAGES - -#define STM_SETICON 0x0170 -#define STM_GETICON 0x0171 -#define STM_SETIMAGE 0x0172 -#define STM_GETIMAGE 0x0173 -#define STN_CLICKED 0 -#define STN_DBLCLK 1 -#define STN_ENABLE 2 -#define STN_DISABLE 3 -#define STM_MSGMAX 0x0174 -#endif - -#define WC_DIALOG (MAKEINTATOM(0x8002)) - -#define DWL_MSGRESULT 0 -#define DWL_DLGPROC 4 -#define DWL_USER 8 - -#ifdef _WIN64 - -#undef DWL_MSGRESULT -#undef DWL_DLGPROC -#undef DWL_USER -#endif - -#define DWLP_MSGRESULT 0 -#define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) -#define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) - -#ifndef NOMSG - -#ifdef UNICODE -#define IsDialogMessage IsDialogMessageW -#else -#define IsDialogMessage IsDialogMessageA -#endif - - WINUSERAPI WINBOOL WINAPI IsDialogMessageA(HWND hDlg,LPMSG lpMsg); - WINUSERAPI WINBOOL WINAPI IsDialogMessageW(HWND hDlg,LPMSG lpMsg); -#endif - -#ifdef UNICODE -#define DlgDirList DlgDirListW -#define DlgDirSelectEx DlgDirSelectExW -#define DlgDirListComboBox DlgDirListComboBoxW -#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExW -#else -#define DlgDirList DlgDirListA -#define DlgDirSelectEx DlgDirSelectExA -#define DlgDirListComboBox DlgDirListComboBoxA -#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExA -#endif - - WINUSERAPI WINBOOL WINAPI MapDialogRect(HWND hDlg,LPRECT lpRect); - WINUSERAPI int WINAPI DlgDirListA(HWND hDlg,LPSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); - WINUSERAPI int WINAPI DlgDirListW(HWND hDlg,LPWSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); - -#define DDL_READWRITE 0x0000 -#define DDL_READONLY 0x0001 -#define DDL_HIDDEN 0x0002 -#define DDL_SYSTEM 0x0004 -#define DDL_DIRECTORY 0x0010 -#define DDL_ARCHIVE 0x0020 - -#define DDL_POSTMSGS 0x2000 -#define DDL_DRIVES 0x4000 -#define DDL_EXCLUSIVE 0x8000 - - WINUSERAPI WINBOOL WINAPI DlgDirSelectExA(HWND hwndDlg,LPSTR lpString,int chCount,int idListBox); - WINUSERAPI WINBOOL WINAPI DlgDirSelectExW(HWND hwndDlg,LPWSTR lpString,int chCount,int idListBox); - WINUSERAPI int WINAPI DlgDirListComboBoxA(HWND hDlg,LPSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); - WINUSERAPI int WINAPI DlgDirListComboBoxW(HWND hDlg,LPWSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); - WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExA(HWND hwndDlg,LPSTR lpString,int cchOut,int idComboBox); - WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExW(HWND hwndDlg,LPWSTR lpString,int cchOut,int idComboBox); - -#define DS_ABSALIGN 0x01L -#define DS_SYSMODAL 0x02L -#define DS_LOCALEDIT 0x20L -#define DS_SETFONT 0x40L -#define DS_MODALFRAME 0x80L -#define DS_NOIDLEMSG 0x100L -#define DS_SETFOREGROUND 0x200L - -#define DS_3DLOOK 0x0004L -#define DS_FIXEDSYS 0x0008L -#define DS_NOFAILCREATE 0x0010L -#define DS_CONTROL 0x0400L -#define DS_CENTER 0x0800L -#define DS_CENTERMOUSE 0x1000L -#define DS_CONTEXTHELP 0x2000L - -#define DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS) - -#if(_WIN32_WCE >= 0x0500) -#define DS_USEPIXELS 0x8000L -#endif - -#define DM_GETDEFID (WM_USER+0) -#define DM_SETDEFID (WM_USER+1) -#define DM_REPOSITION (WM_USER+2) - -#define DC_HASDEFID 0x534B - -#define DLGC_WANTARROWS 0x0001 -#define DLGC_WANTTAB 0x0002 -#define DLGC_WANTALLKEYS 0x0004 -#define DLGC_WANTMESSAGE 0x0004 -#define DLGC_HASSETSEL 0x0008 -#define DLGC_DEFPUSHBUTTON 0x0010 -#define DLGC_UNDEFPUSHBUTTON 0x0020 -#define DLGC_RADIOBUTTON 0x0040 -#define DLGC_WANTCHARS 0x0080 -#define DLGC_STATIC 0x0100 -#define DLGC_BUTTON 0x2000 - -#define LB_CTLCODE 0L - -#define LB_OKAY 0 -#define LB_ERR (-1) -#define LB_ERRSPACE (-2) - -#define LBN_ERRSPACE (-2) -#define LBN_SELCHANGE 1 -#define LBN_DBLCLK 2 -#define LBN_SELCANCEL 3 -#define LBN_SETFOCUS 4 -#define LBN_KILLFOCUS 5 - -#ifndef NOWINMESSAGES - -#define LB_ADDSTRING 0x0180 -#define LB_INSERTSTRING 0x0181 -#define LB_DELETESTRING 0x0182 -#define LB_SELITEMRANGEEX 0x0183 -#define LB_RESETCONTENT 0x0184 -#define LB_SETSEL 0x0185 -#define LB_SETCURSEL 0x0186 -#define LB_GETSEL 0x0187 -#define LB_GETCURSEL 0x0188 -#define LB_GETTEXT 0x0189 -#define LB_GETTEXTLEN 0x018A -#define LB_GETCOUNT 0x018B -#define LB_SELECTSTRING 0x018C -#define LB_DIR 0x018D -#define LB_GETTOPINDEX 0x018E -#define LB_FINDSTRING 0x018F -#define LB_GETSELCOUNT 0x0190 -#define LB_GETSELITEMS 0x0191 -#define LB_SETTABSTOPS 0x0192 -#define LB_GETHORIZONTALEXTENT 0x0193 -#define LB_SETHORIZONTALEXTENT 0x0194 -#define LB_SETCOLUMNWIDTH 0x0195 -#define LB_ADDFILE 0x0196 -#define LB_SETTOPINDEX 0x0197 -#define LB_GETITEMRECT 0x0198 -#define LB_GETITEMDATA 0x0199 -#define LB_SETITEMDATA 0x019A -#define LB_SELITEMRANGE 0x019B -#define LB_SETANCHORINDEX 0x019C -#define LB_GETANCHORINDEX 0x019D -#define LB_SETCARETINDEX 0x019E -#define LB_GETCARETINDEX 0x019F -#define LB_SETITEMHEIGHT 0x01A0 -#define LB_GETITEMHEIGHT 0x01A1 -#define LB_FINDSTRINGEXACT 0x01A2 -#define LB_SETLOCALE 0x01A5 -#define LB_GETLOCALE 0x01A6 -#define LB_SETCOUNT 0x01A7 -#define LB_INITSTORAGE 0x01A8 -#define LB_ITEMFROMPOINT 0x01A9 -#if(_WIN32_WCE >= 0x0400) -#define LB_MULTIPLEADDSTRING 0x01B1 -#endif -#define LB_GETLISTBOXINFO 0x01B2 -#define LB_MSGMAX 0x01B3 -#endif - -#ifndef NOWINSTYLES - -#define LBS_NOTIFY 0x0001L -#define LBS_SORT 0x0002L -#define LBS_NOREDRAW 0x0004L -#define LBS_MULTIPLESEL 0x0008L -#define LBS_OWNERDRAWFIXED 0x0010L -#define LBS_OWNERDRAWVARIABLE 0x0020L -#define LBS_HASSTRINGS 0x0040L -#define LBS_USETABSTOPS 0x0080L -#define LBS_NOINTEGRALHEIGHT 0x0100L -#define LBS_MULTICOLUMN 0x0200L -#define LBS_WANTKEYBOARDINPUT 0x0400L -#define LBS_EXTENDEDSEL 0x0800L -#define LBS_DISABLENOSCROLL 0x1000L -#define LBS_NODATA 0x2000L -#define LBS_NOSEL 0x4000L -#define LBS_COMBOBOX 0x8000L - -#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER) -#endif - -#define CB_OKAY 0 -#define CB_ERR (-1) -#define CB_ERRSPACE (-2) - -#define CBN_ERRSPACE (-1) -#define CBN_SELCHANGE 1 -#define CBN_DBLCLK 2 -#define CBN_SETFOCUS 3 -#define CBN_KILLFOCUS 4 -#define CBN_EDITCHANGE 5 -#define CBN_EDITUPDATE 6 -#define CBN_DROPDOWN 7 -#define CBN_CLOSEUP 8 -#define CBN_SELENDOK 9 -#define CBN_SELENDCANCEL 10 - -#ifndef NOWINSTYLES - -#define CBS_SIMPLE 0x0001L -#define CBS_DROPDOWN 0x0002L -#define CBS_DROPDOWNLIST 0x0003L -#define CBS_OWNERDRAWFIXED 0x0010L -#define CBS_OWNERDRAWVARIABLE 0x0020L -#define CBS_AUTOHSCROLL 0x0040L -#define CBS_OEMCONVERT 0x0080L -#define CBS_SORT 0x0100L -#define CBS_HASSTRINGS 0x0200L -#define CBS_NOINTEGRALHEIGHT 0x0400L -#define CBS_DISABLENOSCROLL 0x0800L -#define CBS_UPPERCASE 0x2000L -#define CBS_LOWERCASE 0x4000L -#endif - -#ifndef NOWINMESSAGES -#define CB_GETEDITSEL 0x0140 -#define CB_LIMITTEXT 0x0141 -#define CB_SETEDITSEL 0x0142 -#define CB_ADDSTRING 0x0143 -#define CB_DELETESTRING 0x0144 -#define CB_DIR 0x0145 -#define CB_GETCOUNT 0x0146 -#define CB_GETCURSEL 0x0147 -#define CB_GETLBTEXT 0x0148 -#define CB_GETLBTEXTLEN 0x0149 -#define CB_INSERTSTRING 0x014A -#define CB_RESETCONTENT 0x014B -#define CB_FINDSTRING 0x014C -#define CB_SELECTSTRING 0x014D -#define CB_SETCURSEL 0x014E -#define CB_SHOWDROPDOWN 0x014F -#define CB_GETITEMDATA 0x0150 -#define CB_SETITEMDATA 0x0151 -#define CB_GETDROPPEDCONTROLRECT 0x0152 -#define CB_SETITEMHEIGHT 0x0153 -#define CB_GETITEMHEIGHT 0x0154 -#define CB_SETEXTENDEDUI 0x0155 -#define CB_GETEXTENDEDUI 0x0156 -#define CB_GETDROPPEDSTATE 0x0157 -#define CB_FINDSTRINGEXACT 0x0158 -#define CB_SETLOCALE 0x0159 -#define CB_GETLOCALE 0x015A -#define CB_GETTOPINDEX 0x015b -#define CB_SETTOPINDEX 0x015c -#define CB_GETHORIZONTALEXTENT 0x015d -#define CB_SETHORIZONTALEXTENT 0x015e -#define CB_GETDROPPEDWIDTH 0x015f -#define CB_SETDROPPEDWIDTH 0x0160 -#define CB_INITSTORAGE 0x0161 -#if(_WIN32_WCE >= 0x0400) -#define CB_MULTIPLEADDSTRING 0x0163 -#endif -#define CB_GETCOMBOBOXINFO 0x0164 -#define CB_MSGMAX 0x0165 -#endif - -#ifndef NOWINSTYLES - -#define SBS_HORZ 0x0000L -#define SBS_VERT 0x0001L -#define SBS_TOPALIGN 0x0002L -#define SBS_LEFTALIGN 0x0002L -#define SBS_BOTTOMALIGN 0x0004L -#define SBS_RIGHTALIGN 0x0004L -#define SBS_SIZEBOXTOPLEFTALIGN 0x0002L -#define SBS_SIZEBOXBOTTOMRIGHTALIGN 0x0004L -#define SBS_SIZEBOX 0x0008L -#define SBS_SIZEGRIP 0x0010L -#endif - -#ifndef NOWINMESSAGES -#define SBM_SETPOS 0x00E0 -#define SBM_GETPOS 0x00E1 -#define SBM_SETRANGE 0x00E2 -#define SBM_SETRANGEREDRAW 0x00E6 -#define SBM_GETRANGE 0x00E3 -#define SBM_ENABLE_ARROWS 0x00E4 -#define SBM_SETSCROLLINFO 0x00E9 -#define SBM_GETSCROLLINFO 0x00EA -#define SBM_GETSCROLLBARINFO 0x00EB - -#define SIF_RANGE 0x0001 -#define SIF_PAGE 0x0002 -#define SIF_POS 0x0004 -#define SIF_DISABLENOSCROLL 0x0008 -#define SIF_TRACKPOS 0x0010 -#define SIF_ALL (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS) - - typedef struct tagSCROLLINFO { - UINT cbSize; - UINT fMask; - int nMin; - int nMax; - UINT nPage; - int nPos; - int nTrackPos; - } SCROLLINFO,*LPSCROLLINFO; - typedef SCROLLINFO CONST *LPCSCROLLINFO; - - WINUSERAPI int WINAPI SetScrollInfo(HWND hwnd,int nBar,LPCSCROLLINFO lpsi,WINBOOL redraw); - WINUSERAPI WINBOOL WINAPI GetScrollInfo(HWND hwnd,int nBar,LPSCROLLINFO lpsi); -#endif -#endif - -#ifndef NOMDI - -#define MDIS_ALLCHILDSTYLES 0x0001 - -#define MDITILE_VERTICAL 0x0000 -#define MDITILE_HORIZONTAL 0x0001 -#define MDITILE_SKIPDISABLED 0x0002 -#define MDITILE_ZORDER 0x0004 - - typedef struct tagMDICREATESTRUCTA { - LPCSTR szClass; - LPCSTR szTitle; - HANDLE hOwner; - int x; - int y; - int cx; - int cy; - DWORD style; - LPARAM lParam; - } MDICREATESTRUCTA,*LPMDICREATESTRUCTA; - - typedef struct tagMDICREATESTRUCTW { - LPCWSTR szClass; - LPCWSTR szTitle; - HANDLE hOwner; - int x; - int y; - int cx; - int cy; - DWORD style; - LPARAM lParam; - } MDICREATESTRUCTW,*LPMDICREATESTRUCTW; - -#ifdef UNICODE - typedef MDICREATESTRUCTW MDICREATESTRUCT; - typedef LPMDICREATESTRUCTW LPMDICREATESTRUCT; -#else - typedef MDICREATESTRUCTA MDICREATESTRUCT; - typedef LPMDICREATESTRUCTA LPMDICREATESTRUCT; -#endif - - typedef struct tagCLIENTCREATESTRUCT { - HANDLE hWindowMenu; - UINT idFirstChild; - } CLIENTCREATESTRUCT,*LPCLIENTCREATESTRUCT; - -#ifdef UNICODE -#define DefFrameProc DefFrameProcW -#define DefMDIChildProc DefMDIChildProcW -#define CreateMDIWindow CreateMDIWindowW -#else -#define DefFrameProc DefFrameProcA -#define DefMDIChildProc DefMDIChildProcA -#define CreateMDIWindow CreateMDIWindowA -#endif - - WINUSERAPI LRESULT WINAPI DefFrameProcA(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefFrameProcW(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefMDIChildProcA(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); - WINUSERAPI LRESULT WINAPI DefMDIChildProcW(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); - -#ifndef NOMSG - WINUSERAPI WINBOOL WINAPI TranslateMDISysAccel(HWND hWndClient,LPMSG lpMsg); -#endif - - WINUSERAPI UINT WINAPI ArrangeIconicWindows(HWND hWnd); - WINUSERAPI HWND WINAPI CreateMDIWindowA(LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); - WINUSERAPI HWND WINAPI CreateMDIWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); - WINUSERAPI WORD WINAPI TileWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); - WINUSERAPI WORD WINAPI CascadeWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); -#endif -#endif - -#ifndef NOHELP - - typedef DWORD HELPPOLY; - typedef struct tagMULTIKEYHELPA { - DWORD mkSize; - CHAR mkKeylist; - CHAR szKeyphrase[1]; - } MULTIKEYHELPA,*PMULTIKEYHELPA,*LPMULTIKEYHELPA; - - typedef struct tagMULTIKEYHELPW { - DWORD mkSize; - WCHAR mkKeylist; - WCHAR szKeyphrase[1]; - } MULTIKEYHELPW,*PMULTIKEYHELPW,*LPMULTIKEYHELPW; - -#ifdef UNICODE - typedef MULTIKEYHELPW MULTIKEYHELP; - typedef PMULTIKEYHELPW PMULTIKEYHELP; - typedef LPMULTIKEYHELPW LPMULTIKEYHELP; -#else - typedef MULTIKEYHELPA MULTIKEYHELP; - typedef PMULTIKEYHELPA PMULTIKEYHELP; - typedef LPMULTIKEYHELPA LPMULTIKEYHELP; -#endif - - typedef struct tagHELPWININFOA { - int wStructSize; - int x; - int y; - int dx; - int dy; - int wMax; - CHAR rgchMember[2]; - } HELPWININFOA,*PHELPWININFOA,*LPHELPWININFOA; - - typedef struct tagHELPWININFOW { - int wStructSize; - int x; - int y; - int dx; - int dy; - int wMax; - WCHAR rgchMember[2]; - } HELPWININFOW,*PHELPWININFOW,*LPHELPWININFOW; - -#ifdef UNICODE - typedef HELPWININFOW HELPWININFO; - typedef PHELPWININFOW PHELPWININFO; - typedef LPHELPWININFOW LPHELPWININFO; -#else - typedef HELPWININFOA HELPWININFO; - typedef PHELPWININFOA PHELPWININFO; - typedef LPHELPWININFOA LPHELPWININFO; -#endif - -#define HELP_CONTEXT 0x0001L -#define HELP_QUIT 0x0002L -#define HELP_INDEX 0x0003L -#define HELP_CONTENTS 0x0003L -#define HELP_HELPONHELP 0x0004L -#define HELP_SETINDEX 0x0005L -#define HELP_SETCONTENTS 0x0005L -#define HELP_CONTEXTPOPUP 0x0008L -#define HELP_FORCEFILE 0x0009L -#define HELP_KEY 0x0101L -#define HELP_COMMAND 0x0102L -#define HELP_PARTIALKEY 0x0105L -#define HELP_MULTIKEY 0x0201L -#define HELP_SETWINPOS 0x0203L -#define HELP_CONTEXTMENU 0x000a -#define HELP_FINDER 0x000b -#define HELP_WM_HELP 0x000c -#define HELP_SETPOPUP_POS 0x000d - -#define HELP_TCARD 0x8000 -#define HELP_TCARD_DATA 0x0010 -#define HELP_TCARD_OTHER_CALLER 0x0011 - -#define IDH_NO_HELP 28440 -#define IDH_MISSING_CONTEXT 28441 -#define IDH_GENERIC_HELP_BUTTON 28442 -#define IDH_OK 28443 -#define IDH_CANCEL 28444 -#define IDH_HELP 28445 - -#ifdef UNICODE -#define WinHelp WinHelpW -#else -#define WinHelp WinHelpA -#endif - - WINUSERAPI WINBOOL WINAPI WinHelpA(HWND hWndMain,LPCSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); - WINUSERAPI WINBOOL WINAPI WinHelpW(HWND hWndMain,LPCWSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); -#endif - -#define GR_GDIOBJECTS 0 -#define GR_USEROBJECTS 1 - - WINUSERAPI DWORD WINAPI GetGuiResources(HANDLE hProcess,DWORD uiFlags); - -#ifndef NOSYSPARAMSINFO - -#define SPI_GETBEEP 0x0001 -#define SPI_SETBEEP 0x0002 -#define SPI_GETMOUSE 0x0003 -#define SPI_SETMOUSE 0x0004 -#define SPI_GETBORDER 0x0005 -#define SPI_SETBORDER 0x0006 -#define SPI_GETKEYBOARDSPEED 0x000A -#define SPI_SETKEYBOARDSPEED 0x000B -#define SPI_LANGDRIVER 0x000C -#define SPI_ICONHORIZONTALSPACING 0x000D -#define SPI_GETSCREENSAVETIMEOUT 0x000E -#define SPI_SETSCREENSAVETIMEOUT 0x000F -#define SPI_GETSCREENSAVEACTIVE 0x0010 -#define SPI_SETSCREENSAVEACTIVE 0x0011 -#define SPI_GETGRIDGRANULARITY 0x0012 -#define SPI_SETGRIDGRANULARITY 0x0013 -#define SPI_SETDESKWALLPAPER 0x0014 -#define SPI_SETDESKPATTERN 0x0015 -#define SPI_GETKEYBOARDDELAY 0x0016 -#define SPI_SETKEYBOARDDELAY 0x0017 -#define SPI_ICONVERTICALSPACING 0x0018 -#define SPI_GETICONTITLEWRAP 0x0019 -#define SPI_SETICONTITLEWRAP 0x001A -#define SPI_GETMENUDROPALIGNMENT 0x001B -#define SPI_SETMENUDROPALIGNMENT 0x001C -#define SPI_SETDOUBLECLKWIDTH 0x001D -#define SPI_SETDOUBLECLKHEIGHT 0x001E -#define SPI_GETICONTITLELOGFONT 0x001F -#define SPI_SETDOUBLECLICKTIME 0x0020 -#define SPI_SETMOUSEBUTTONSWAP 0x0021 -#define SPI_SETICONTITLELOGFONT 0x0022 -#define SPI_GETFASTTASKSWITCH 0x0023 -#define SPI_SETFASTTASKSWITCH 0x0024 -#define SPI_SETDRAGFULLWINDOWS 0x0025 -#define SPI_GETDRAGFULLWINDOWS 0x0026 -#define SPI_GETNONCLIENTMETRICS 0x0029 -#define SPI_SETNONCLIENTMETRICS 0x002A -#define SPI_GETMINIMIZEDMETRICS 0x002B -#define SPI_SETMINIMIZEDMETRICS 0x002C -#define SPI_GETICONMETRICS 0x002D -#define SPI_SETICONMETRICS 0x002E -#define SPI_SETWORKAREA 0x002F -#define SPI_GETWORKAREA 0x0030 -#define SPI_SETPENWINDOWS 0x0031 - -#define SPI_GETHIGHCONTRAST 0x0042 -#define SPI_SETHIGHCONTRAST 0x0043 -#define SPI_GETKEYBOARDPREF 0x0044 -#define SPI_SETKEYBOARDPREF 0x0045 -#define SPI_GETSCREENREADER 0x0046 -#define SPI_SETSCREENREADER 0x0047 -#define SPI_GETANIMATION 0x0048 -#define SPI_SETANIMATION 0x0049 -#define SPI_GETFONTSMOOTHING 0x004A -#define SPI_SETFONTSMOOTHING 0x004B -#define SPI_SETDRAGWIDTH 0x004C -#define SPI_SETDRAGHEIGHT 0x004D -#define SPI_SETHANDHELD 0x004E -#define SPI_GETLOWPOWERTIMEOUT 0x004F -#define SPI_GETPOWEROFFTIMEOUT 0x0050 -#define SPI_SETLOWPOWERTIMEOUT 0x0051 -#define SPI_SETPOWEROFFTIMEOUT 0x0052 -#define SPI_GETLOWPOWERACTIVE 0x0053 -#define SPI_GETPOWEROFFACTIVE 0x0054 -#define SPI_SETLOWPOWERACTIVE 0x0055 -#define SPI_SETPOWEROFFACTIVE 0x0056 -#define SPI_SETCURSORS 0x0057 -#define SPI_SETICONS 0x0058 -#define SPI_GETDEFAULTINPUTLANG 0x0059 -#define SPI_SETDEFAULTINPUTLANG 0x005A -#define SPI_SETLANGTOGGLE 0x005B -#define SPI_GETWINDOWSEXTENSION 0x005C -#define SPI_SETMOUSETRAILS 0x005D -#define SPI_GETMOUSETRAILS 0x005E -#define SPI_SETSCREENSAVERRUNNING 0x0061 -#define SPI_SCREENSAVERRUNNING SPI_SETSCREENSAVERRUNNING -#define SPI_GETFILTERKEYS 0x0032 -#define SPI_SETFILTERKEYS 0x0033 -#define SPI_GETTOGGLEKEYS 0x0034 -#define SPI_SETTOGGLEKEYS 0x0035 -#define SPI_GETMOUSEKEYS 0x0036 -#define SPI_SETMOUSEKEYS 0x0037 -#define SPI_GETSHOWSOUNDS 0x0038 -#define SPI_SETSHOWSOUNDS 0x0039 -#define SPI_GETSTICKYKEYS 0x003A -#define SPI_SETSTICKYKEYS 0x003B -#define SPI_GETACCESSTIMEOUT 0x003C -#define SPI_SETACCESSTIMEOUT 0x003D -#define SPI_GETSERIALKEYS 0x003E -#define SPI_SETSERIALKEYS 0x003F -#define SPI_GETSOUNDSENTRY 0x0040 -#define SPI_SETSOUNDSENTRY 0x0041 -#define SPI_GETSNAPTODEFBUTTON 0x005F -#define SPI_SETSNAPTODEFBUTTON 0x0060 -#define SPI_GETMOUSEHOVERWIDTH 0x0062 -#define SPI_SETMOUSEHOVERWIDTH 0x0063 -#define SPI_GETMOUSEHOVERHEIGHT 0x0064 -#define SPI_SETMOUSEHOVERHEIGHT 0x0065 -#define SPI_GETMOUSEHOVERTIME 0x0066 -#define SPI_SETMOUSEHOVERTIME 0x0067 -#define SPI_GETWHEELSCROLLLINES 0x0068 -#define SPI_SETWHEELSCROLLLINES 0x0069 -#define SPI_GETMENUSHOWDELAY 0x006A -#define SPI_SETMENUSHOWDELAY 0x006B -#define SPI_GETSHOWIMEUI 0x006E -#define SPI_SETSHOWIMEUI 0x006F -#define SPI_GETMOUSESPEED 0x0070 -#define SPI_SETMOUSESPEED 0x0071 -#define SPI_GETSCREENSAVERRUNNING 0x0072 -#define SPI_GETDESKWALLPAPER 0x0073 - -#define SPI_GETACTIVEWINDOWTRACKING 0x1000 -#define SPI_SETACTIVEWINDOWTRACKING 0x1001 -#define SPI_GETMENUANIMATION 0x1002 -#define SPI_SETMENUANIMATION 0x1003 -#define SPI_GETCOMBOBOXANIMATION 0x1004 -#define SPI_SETCOMBOBOXANIMATION 0x1005 -#define SPI_GETLISTBOXSMOOTHSCROLLING 0x1006 -#define SPI_SETLISTBOXSMOOTHSCROLLING 0x1007 -#define SPI_GETGRADIENTCAPTIONS 0x1008 -#define SPI_SETGRADIENTCAPTIONS 0x1009 -#define SPI_GETKEYBOARDCUES 0x100A -#define SPI_SETKEYBOARDCUES 0x100B -#define SPI_GETMENUUNDERLINES SPI_GETKEYBOARDCUES -#define SPI_SETMENUUNDERLINES SPI_SETKEYBOARDCUES -#define SPI_GETACTIVEWNDTRKZORDER 0x100C -#define SPI_SETACTIVEWNDTRKZORDER 0x100D -#define SPI_GETHOTTRACKING 0x100E -#define SPI_SETHOTTRACKING 0x100F -#define SPI_GETMENUFADE 0x1012 -#define SPI_SETMENUFADE 0x1013 -#define SPI_GETSELECTIONFADE 0x1014 -#define SPI_SETSELECTIONFADE 0x1015 -#define SPI_GETTOOLTIPANIMATION 0x1016 -#define SPI_SETTOOLTIPANIMATION 0x1017 -#define SPI_GETTOOLTIPFADE 0x1018 -#define SPI_SETTOOLTIPFADE 0x1019 -#define SPI_GETCURSORSHADOW 0x101A -#define SPI_SETCURSORSHADOW 0x101B -#define SPI_GETMOUSESONAR 0x101C -#define SPI_SETMOUSESONAR 0x101D -#define SPI_GETMOUSECLICKLOCK 0x101E -#define SPI_SETMOUSECLICKLOCK 0x101F -#define SPI_GETMOUSEVANISH 0x1020 -#define SPI_SETMOUSEVANISH 0x1021 -#define SPI_GETFLATMENU 0x1022 -#define SPI_SETFLATMENU 0x1023 -#define SPI_GETDROPSHADOW 0x1024 -#define SPI_SETDROPSHADOW 0x1025 -#define SPI_GETBLOCKSENDINPUTRESETS 0x1026 -#define SPI_SETBLOCKSENDINPUTRESETS 0x1027 -#define SPI_GETUIEFFECTS 0x103E -#define SPI_SETUIEFFECTS 0x103F -#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 -#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 -#define SPI_GETACTIVEWNDTRKTIMEOUT 0x2002 -#define SPI_SETACTIVEWNDTRKTIMEOUT 0x2003 -#define SPI_GETFOREGROUNDFLASHCOUNT 0x2004 -#define SPI_SETFOREGROUNDFLASHCOUNT 0x2005 -#define SPI_GETCARETWIDTH 0x2006 -#define SPI_SETCARETWIDTH 0x2007 -#define SPI_GETMOUSECLICKLOCKTIME 0x2008 -#define SPI_SETMOUSECLICKLOCKTIME 0x2009 -#define SPI_GETFONTSMOOTHINGTYPE 0x200A -#define SPI_SETFONTSMOOTHINGTYPE 0x200B - -#define FE_FONTSMOOTHINGSTANDARD 0x0001 -#define FE_FONTSMOOTHINGCLEARTYPE 0x0002 -#define FE_FONTSMOOTHINGDOCKING 0x8000 - -#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C -#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D -#define SPI_GETFOCUSBORDERWIDTH 0x200E -#define SPI_SETFOCUSBORDERWIDTH 0x200F -#define SPI_GETFOCUSBORDERHEIGHT 0x2010 -#define SPI_SETFOCUSBORDERHEIGHT 0x2011 -#define SPI_GETFONTSMOOTHINGORIENTATION 0x2012 -#define SPI_SETFONTSMOOTHINGORIENTATION 0x2013 - -#define FE_FONTSMOOTHINGORIENTATIONBGR 0x0000 -#define FE_FONTSMOOTHINGORIENTATIONRGB 0x0001 - -#define SPIF_UPDATEINIFILE 0x0001 -#define SPIF_SENDWININICHANGE 0x0002 -#define SPIF_SENDCHANGE SPIF_SENDWININICHANGE - -#define METRICS_USEDEFAULT -1 -#ifdef _WINGDI_ -#ifndef NOGDI - typedef struct tagNONCLIENTMETRICSA { - UINT cbSize; - int iBorderWidth; - int iScrollWidth; - int iScrollHeight; - int iCaptionWidth; - int iCaptionHeight; - LOGFONTA lfCaptionFont; - int iSmCaptionWidth; - int iSmCaptionHeight; - LOGFONTA lfSmCaptionFont; - int iMenuWidth; - int iMenuHeight; - LOGFONTA lfMenuFont; - LOGFONTA lfStatusFont; - LOGFONTA lfMessageFont; - } NONCLIENTMETRICSA,*PNONCLIENTMETRICSA,*LPNONCLIENTMETRICSA; - - typedef struct tagNONCLIENTMETRICSW { - UINT cbSize; - int iBorderWidth; - int iScrollWidth; - int iScrollHeight; - int iCaptionWidth; - int iCaptionHeight; - LOGFONTW lfCaptionFont; - int iSmCaptionWidth; - int iSmCaptionHeight; - LOGFONTW lfSmCaptionFont; - int iMenuWidth; - int iMenuHeight; - LOGFONTW lfMenuFont; - LOGFONTW lfStatusFont; - LOGFONTW lfMessageFont; - } NONCLIENTMETRICSW,*PNONCLIENTMETRICSW,*LPNONCLIENTMETRICSW; - -#ifdef UNICODE - typedef NONCLIENTMETRICSW NONCLIENTMETRICS; - typedef PNONCLIENTMETRICSW PNONCLIENTMETRICS; - typedef LPNONCLIENTMETRICSW LPNONCLIENTMETRICS; -#else - typedef NONCLIENTMETRICSA NONCLIENTMETRICS; - typedef PNONCLIENTMETRICSA PNONCLIENTMETRICS; - typedef LPNONCLIENTMETRICSA LPNONCLIENTMETRICS; -#endif -#endif -#endif - -#define ARW_BOTTOMLEFT 0x0000L -#define ARW_BOTTOMRIGHT 0x0001L -#define ARW_TOPLEFT 0x0002L -#define ARW_TOPRIGHT 0x0003L -#define ARW_STARTMASK 0x0003L -#define ARW_STARTRIGHT 0x0001L -#define ARW_STARTTOP 0x0002L - -#define ARW_LEFT 0x0000L -#define ARW_RIGHT 0x0000L -#define ARW_UP 0x0004L -#define ARW_DOWN 0x0004L -#define ARW_HIDE 0x0008L - - typedef struct tagMINIMIZEDMETRICS { - UINT cbSize; - int iWidth; - int iHorzGap; - int iVertGap; - int iArrange; - } MINIMIZEDMETRICS,*PMINIMIZEDMETRICS,*LPMINIMIZEDMETRICS; - -#ifdef _WINGDI_ -#ifndef NOGDI - typedef struct tagICONMETRICSA { - UINT cbSize; - int iHorzSpacing; - int iVertSpacing; - int iTitleWrap; - LOGFONTA lfFont; - } ICONMETRICSA,*PICONMETRICSA,*LPICONMETRICSA; - - typedef struct tagICONMETRICSW { - UINT cbSize; - int iHorzSpacing; - int iVertSpacing; - int iTitleWrap; - LOGFONTW lfFont; - } ICONMETRICSW,*PICONMETRICSW,*LPICONMETRICSW; - -#ifdef UNICODE - typedef ICONMETRICSW ICONMETRICS; - typedef PICONMETRICSW PICONMETRICS; - typedef LPICONMETRICSW LPICONMETRICS; -#else - typedef ICONMETRICSA ICONMETRICS; - typedef PICONMETRICSA PICONMETRICS; - typedef LPICONMETRICSA LPICONMETRICS; -#endif -#endif -#endif - - typedef struct tagANIMATIONINFO { - UINT cbSize; - int iMinAnimate; - } ANIMATIONINFO,*LPANIMATIONINFO; - - typedef struct tagSERIALKEYSA { - UINT cbSize; - DWORD dwFlags; - LPSTR lpszActivePort; - LPSTR lpszPort; - UINT iBaudRate; - UINT iPortState; - UINT iActive; - } SERIALKEYSA,*LPSERIALKEYSA; - - typedef struct tagSERIALKEYSW { - UINT cbSize; - DWORD dwFlags; - LPWSTR lpszActivePort; - LPWSTR lpszPort; - UINT iBaudRate; - UINT iPortState; - UINT iActive; - } SERIALKEYSW,*LPSERIALKEYSW; - -#ifdef UNICODE - typedef SERIALKEYSW SERIALKEYS; - typedef LPSERIALKEYSW LPSERIALKEYS; -#else - typedef SERIALKEYSA SERIALKEYS; - typedef LPSERIALKEYSA LPSERIALKEYS; -#endif - -#define SERKF_SERIALKEYSON 0x00000001 -#define SERKF_AVAILABLE 0x00000002 -#define SERKF_INDICATOR 0x00000004 - - typedef struct tagHIGHCONTRASTA { - UINT cbSize; - DWORD dwFlags; - LPSTR lpszDefaultScheme; - } HIGHCONTRASTA,*LPHIGHCONTRASTA; - - typedef struct tagHIGHCONTRASTW { - UINT cbSize; - DWORD dwFlags; - LPWSTR lpszDefaultScheme; - } HIGHCONTRASTW,*LPHIGHCONTRASTW; - -#ifdef UNICODE - typedef HIGHCONTRASTW HIGHCONTRAST; - typedef LPHIGHCONTRASTW LPHIGHCONTRAST; -#else - typedef HIGHCONTRASTA HIGHCONTRAST; - typedef LPHIGHCONTRASTA LPHIGHCONTRAST; -#endif - -#define HCF_HIGHCONTRASTON 0x00000001 -#define HCF_AVAILABLE 0x00000002 -#define HCF_HOTKEYACTIVE 0x00000004 -#define HCF_CONFIRMHOTKEY 0x00000008 -#define HCF_HOTKEYSOUND 0x00000010 -#define HCF_INDICATOR 0x00000020 -#define HCF_HOTKEYAVAILABLE 0x00000040 -#define HCF_LOGONDESKTOP 0x00000100 -#define HCF_DEFAULTDESKTOP 0x00000200 - -#define CDS_UPDATEREGISTRY 0x00000001 -#define CDS_TEST 0x00000002 -#define CDS_FULLSCREEN 0x00000004 -#define CDS_GLOBAL 0x00000008 -#define CDS_SET_PRIMARY 0x00000010 -#define CDS_VIDEOPARAMETERS 0x00000020 -#define CDS_RESET 0x40000000 -#define CDS_NORESET 0x10000000 - -//gr #include - -#define DISP_CHANGE_SUCCESSFUL 0 -#define DISP_CHANGE_RESTART 1 -#define DISP_CHANGE_FAILED -1 -#define DISP_CHANGE_BADMODE -2 -#define DISP_CHANGE_NOTUPDATED -3 -#define DISP_CHANGE_BADFLAGS -4 -#define DISP_CHANGE_BADPARAM -5 -#define DISP_CHANGE_BADDUALVIEW -6 - -#ifdef _WINGDI_ -#ifndef NOGDI - -#ifdef UNICODE -#define ChangeDisplaySettings ChangeDisplaySettingsW -#define ChangeDisplaySettingsEx ChangeDisplaySettingsExW -#define EnumDisplaySettings EnumDisplaySettingsW -#define EnumDisplaySettingsEx EnumDisplaySettingsExW -#define EnumDisplayDevices EnumDisplayDevicesW -#else -#define ChangeDisplaySettings ChangeDisplaySettingsA -#define ChangeDisplaySettingsEx ChangeDisplaySettingsExA -#define EnumDisplaySettings EnumDisplaySettingsA -#define EnumDisplaySettingsEx EnumDisplaySettingsExA -#define EnumDisplayDevices EnumDisplayDevicesA -#endif - - WINUSERAPI LONG WINAPI ChangeDisplaySettingsA(LPDEVMODEA lpDevMode,DWORD dwFlags); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsW(LPDEVMODEW lpDevMode,DWORD dwFlags); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsExA(LPCSTR lpszDeviceName,LPDEVMODEA lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName,LPDEVMODEW lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); - -#define ENUM_CURRENT_SETTINGS ((DWORD)-1) -#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) - - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode); - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode); - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode,DWORD dwFlags); - WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode,DWORD dwFlags); - -#define EDS_RAWMODE 0x00000002 - - WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesA(LPCSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEA lpDisplayDevice,DWORD dwFlags); - WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesW(LPCWSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEW lpDisplayDevice,DWORD dwFlags); -#endif -#endif - -#ifdef UNICODE -#define SystemParametersInfo SystemParametersInfoW -#else -#define SystemParametersInfo SystemParametersInfoA -#endif - - WINUSERAPI WINBOOL WINAPI SystemParametersInfoA(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); - WINUSERAPI WINBOOL WINAPI SystemParametersInfoW(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); -#endif - - typedef struct tagFILTERKEYS { - UINT cbSize; - DWORD dwFlags; - DWORD iWaitMSec; - DWORD iDelayMSec; - DWORD iRepeatMSec; - DWORD iBounceMSec; - } FILTERKEYS,*LPFILTERKEYS; - -#define FKF_FILTERKEYSON 0x00000001 -#define FKF_AVAILABLE 0x00000002 -#define FKF_HOTKEYACTIVE 0x00000004 -#define FKF_CONFIRMHOTKEY 0x00000008 -#define FKF_HOTKEYSOUND 0x00000010 -#define FKF_INDICATOR 0x00000020 -#define FKF_CLICKON 0x00000040 - - typedef struct tagSTICKYKEYS { - UINT cbSize; - DWORD dwFlags; - } STICKYKEYS,*LPSTICKYKEYS; - -#define SKF_STICKYKEYSON 0x00000001 -#define SKF_AVAILABLE 0x00000002 -#define SKF_HOTKEYACTIVE 0x00000004 -#define SKF_CONFIRMHOTKEY 0x00000008 -#define SKF_HOTKEYSOUND 0x00000010 -#define SKF_INDICATOR 0x00000020 -#define SKF_AUDIBLEFEEDBACK 0x00000040 -#define SKF_TRISTATE 0x00000080 -#define SKF_TWOKEYSOFF 0x00000100 -#define SKF_LALTLATCHED 0x10000000 -#define SKF_LCTLLATCHED 0x04000000 -#define SKF_LSHIFTLATCHED 0x01000000 -#define SKF_RALTLATCHED 0x20000000 -#define SKF_RCTLLATCHED 0x08000000 -#define SKF_RSHIFTLATCHED 0x02000000 -#define SKF_LWINLATCHED 0x40000000 -#define SKF_RWINLATCHED 0x80000000 -#define SKF_LALTLOCKED 0x00100000 -#define SKF_LCTLLOCKED 0x00040000 -#define SKF_LSHIFTLOCKED 0x00010000 -#define SKF_RALTLOCKED 0x00200000 -#define SKF_RCTLLOCKED 0x00080000 -#define SKF_RSHIFTLOCKED 0x00020000 -#define SKF_LWINLOCKED 0x00400000 -#define SKF_RWINLOCKED 0x00800000 - - typedef struct tagMOUSEKEYS { - UINT cbSize; - DWORD dwFlags; - DWORD iMaxSpeed; - DWORD iTimeToMaxSpeed; - DWORD iCtrlSpeed; - DWORD dwReserved1; - DWORD dwReserved2; - } MOUSEKEYS,*LPMOUSEKEYS; - -#define MKF_MOUSEKEYSON 0x00000001 -#define MKF_AVAILABLE 0x00000002 -#define MKF_HOTKEYACTIVE 0x00000004 -#define MKF_CONFIRMHOTKEY 0x00000008 -#define MKF_HOTKEYSOUND 0x00000010 -#define MKF_INDICATOR 0x00000020 -#define MKF_MODIFIERS 0x00000040 -#define MKF_REPLACENUMBERS 0x00000080 -#define MKF_LEFTBUTTONSEL 0x10000000 -#define MKF_RIGHTBUTTONSEL 0x20000000 -#define MKF_LEFTBUTTONDOWN 0x01000000 -#define MKF_RIGHTBUTTONDOWN 0x02000000 -#define MKF_MOUSEMODE 0x80000000 - - typedef struct tagACCESSTIMEOUT { - UINT cbSize; - DWORD dwFlags; - DWORD iTimeOutMSec; - } ACCESSTIMEOUT,*LPACCESSTIMEOUT; - -#define ATF_TIMEOUTON 0x00000001 -#define ATF_ONOFFFEEDBACK 0x00000002 - -#define SSGF_NONE 0 -#define SSGF_DISPLAY 3 - -#define SSTF_NONE 0 -#define SSTF_CHARS 1 -#define SSTF_BORDER 2 -#define SSTF_DISPLAY 3 - -#define SSWF_NONE 0 -#define SSWF_TITLE 1 -#define SSWF_WINDOW 2 -#define SSWF_DISPLAY 3 -#define SSWF_CUSTOM 4 - - typedef struct tagSOUNDSENTRYA { - UINT cbSize; - DWORD dwFlags; - DWORD iFSTextEffect; - DWORD iFSTextEffectMSec; - DWORD iFSTextEffectColorBits; - DWORD iFSGrafEffect; - DWORD iFSGrafEffectMSec; - DWORD iFSGrafEffectColor; - DWORD iWindowsEffect; - DWORD iWindowsEffectMSec; - LPSTR lpszWindowsEffectDLL; - DWORD iWindowsEffectOrdinal; - } SOUNDSENTRYA,*LPSOUNDSENTRYA; - - typedef struct tagSOUNDSENTRYW { - UINT cbSize; - DWORD dwFlags; - DWORD iFSTextEffect; - DWORD iFSTextEffectMSec; - DWORD iFSTextEffectColorBits; - DWORD iFSGrafEffect; - DWORD iFSGrafEffectMSec; - DWORD iFSGrafEffectColor; - DWORD iWindowsEffect; - DWORD iWindowsEffectMSec; - LPWSTR lpszWindowsEffectDLL; - DWORD iWindowsEffectOrdinal; - } SOUNDSENTRYW,*LPSOUNDSENTRYW; - -#ifdef UNICODE - typedef SOUNDSENTRYW SOUNDSENTRY; - typedef LPSOUNDSENTRYW LPSOUNDSENTRY; -#else - typedef SOUNDSENTRYA SOUNDSENTRY; - typedef LPSOUNDSENTRYA LPSOUNDSENTRY; -#endif - -#define SSF_SOUNDSENTRYON 0x00000001 -#define SSF_AVAILABLE 0x00000002 -#define SSF_INDICATOR 0x00000004 - - typedef struct tagTOGGLEKEYS { - UINT cbSize; - DWORD dwFlags; - } TOGGLEKEYS,*LPTOGGLEKEYS; - -#define TKF_TOGGLEKEYSON 0x00000001 -#define TKF_AVAILABLE 0x00000002 -#define TKF_HOTKEYACTIVE 0x00000004 -#define TKF_CONFIRMHOTKEY 0x00000008 -#define TKF_HOTKEYSOUND 0x00000010 -#define TKF_INDICATOR 0x00000020 - - WINUSERAPI VOID WINAPI SetDebugErrorLevel(DWORD dwLevel); - -#define SLE_ERROR 0x00000001 -#define SLE_MINORERROR 0x00000002 -#define SLE_WARNING 0x00000003 - - WINUSERAPI VOID WINAPI SetLastErrorEx(DWORD dwErrCode,DWORD dwType); - WINUSERAPI int WINAPI InternalGetWindowText(HWND hWnd,LPWSTR pString,int cchMaxCount); - -#ifdef WINNT - WINUSERAPI WINBOOL WINAPI EndTask(HWND hWnd,WINBOOL fShutDown,WINBOOL fForce); -#endif - -#define MONITOR_DEFAULTTONULL 0x00000000 -#define MONITOR_DEFAULTTOPRIMARY 0x00000001 -#define MONITOR_DEFAULTTONEAREST 0x00000002 - - WINUSERAPI HMONITOR WINAPI MonitorFromPoint(POINT pt,DWORD dwFlags); - WINUSERAPI HMONITOR WINAPI MonitorFromRect(LPCRECT lprc,DWORD dwFlags); - WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd,DWORD dwFlags); - -#define MONITORINFOF_PRIMARY 0x00000001 - -#ifndef CCHDEVICENAME -#define CCHDEVICENAME 32 -#endif - - typedef struct tagMONITORINFO { - DWORD cbSize; - RECT rcMonitor; - RECT rcWork; - DWORD dwFlags; - } MONITORINFO,*LPMONITORINFO; - -#ifdef __cplusplus - typedef struct tagMONITORINFOEXA : public tagMONITORINFO { - CHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXA,*LPMONITORINFOEXA; - - typedef struct tagMONITORINFOEXW : public tagMONITORINFO { - WCHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXW,*LPMONITORINFOEXW; - -#ifdef UNICODE - typedef MONITORINFOEXW MONITORINFOEX; - typedef LPMONITORINFOEXW LPMONITORINFOEX; -#else - typedef MONITORINFOEXA MONITORINFOEX; - typedef LPMONITORINFOEXA LPMONITORINFOEX; -#endif -#else - typedef struct tagMONITORINFOEXA { - MONITORINFO mi; - CHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXA,*LPMONITORINFOEXA; - - typedef struct tagMONITORINFOEXW { - MONITORINFO mi; - WCHAR szDevice[CCHDEVICENAME]; - } MONITORINFOEXW,*LPMONITORINFOEXW; -#ifdef UNICODE - typedef MONITORINFOEXW MONITORINFOEX; - typedef LPMONITORINFOEXW LPMONITORINFOEX; -#else - typedef MONITORINFOEXA MONITORINFOEX; - typedef LPMONITORINFOEXA LPMONITORINFOEX; -#endif -#endif - -#ifdef UNICODE -#define GetMonitorInfo GetMonitorInfoW -#else -#define GetMonitorInfo GetMonitorInfoA -#endif - - WINUSERAPI WINBOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor,LPMONITORINFO lpmi); - WINUSERAPI WINBOOL WINAPI GetMonitorInfoW(HMONITOR hMonitor,LPMONITORINFO lpmi); - - typedef WINBOOL (CALLBACK *MONITORENUMPROC)(HMONITOR,HDC,LPRECT,LPARAM); - - WINUSERAPI WINBOOL WINAPI EnumDisplayMonitors(HDC hdc,LPCRECT lprcClip,MONITORENUMPROC lpfnEnum,LPARAM dwData); - -#ifndef NOWINABLE - WINUSERAPI VOID WINAPI NotifyWinEvent(DWORD event,HWND hwnd,LONG idObject,LONG idChild); - - typedef VOID (CALLBACK *WINEVENTPROC)(HWINEVENTHOOK hWinEventHook,DWORD event,HWND hwnd,LONG idObject,LONG idChild,DWORD idEventThread,DWORD dwmsEventTime); - - WINUSERAPI HWINEVENTHOOK WINAPI SetWinEventHook(DWORD eventMin,DWORD eventMax,HMODULE hmodWinEventProc,WINEVENTPROC pfnWinEventProc,DWORD idProcess,DWORD idThread,DWORD dwFlags); - WINUSERAPI WINBOOL WINAPI IsWinEventHookInstalled(DWORD event); - -#define WINEVENT_OUTOFCONTEXT 0x0000 -#define WINEVENT_SKIPOWNTHREAD 0x0001 -#define WINEVENT_SKIPOWNPROCESS 0x0002 -#define WINEVENT_INCONTEXT 0x0004 - - WINUSERAPI WINBOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hWinEventHook); - -#define CHILDID_SELF 0 -#define INDEXID_OBJECT 0 -#define INDEXID_CONTAINER 0 - -#define OBJID_WINDOW ((LONG)0x00000000) -#define OBJID_SYSMENU ((LONG)0xFFFFFFFF) -#define OBJID_TITLEBAR ((LONG)0xFFFFFFFE) -#define OBJID_MENU ((LONG)0xFFFFFFFD) -#define OBJID_CLIENT ((LONG)0xFFFFFFFC) -#define OBJID_VSCROLL ((LONG)0xFFFFFFFB) -#define OBJID_HSCROLL ((LONG)0xFFFFFFFA) -#define OBJID_SIZEGRIP ((LONG)0xFFFFFFF9) -#define OBJID_CARET ((LONG)0xFFFFFFF8) -#define OBJID_CURSOR ((LONG)0xFFFFFFF7) -#define OBJID_ALERT ((LONG)0xFFFFFFF6) -#define OBJID_SOUND ((LONG)0xFFFFFFF5) -#define OBJID_QUERYCLASSNAMEIDX ((LONG)0xFFFFFFF4) -#define OBJID_NATIVEOM ((LONG)0xFFFFFFF0) - -#define EVENT_MIN 0x00000001 -#define EVENT_MAX 0x7FFFFFFF - -#define EVENT_SYSTEM_SOUND 0x0001 -#define EVENT_SYSTEM_ALERT 0x0002 -#define EVENT_SYSTEM_FOREGROUND 0x0003 -#define EVENT_SYSTEM_MENUSTART 0x0004 -#define EVENT_SYSTEM_MENUEND 0x0005 -#define EVENT_SYSTEM_MENUPOPUPSTART 0x0006 -#define EVENT_SYSTEM_MENUPOPUPEND 0x0007 -#define EVENT_SYSTEM_CAPTURESTART 0x0008 -#define EVENT_SYSTEM_CAPTUREEND 0x0009 -#define EVENT_SYSTEM_MOVESIZESTART 0x000A -#define EVENT_SYSTEM_MOVESIZEEND 0x000B -#define EVENT_SYSTEM_CONTEXTHELPSTART 0x000C -#define EVENT_SYSTEM_CONTEXTHELPEND 0x000D -#define EVENT_SYSTEM_DRAGDROPSTART 0x000E -#define EVENT_SYSTEM_DRAGDROPEND 0x000F -#define EVENT_SYSTEM_DIALOGSTART 0x0010 -#define EVENT_SYSTEM_DIALOGEND 0x0011 -#define EVENT_SYSTEM_SCROLLINGSTART 0x0012 -#define EVENT_SYSTEM_SCROLLINGEND 0x0013 -#define EVENT_SYSTEM_SWITCHSTART 0x0014 -#define EVENT_SYSTEM_SWITCHEND 0x0015 -#define EVENT_SYSTEM_MINIMIZESTART 0x0016 -#define EVENT_SYSTEM_MINIMIZEEND 0x0017 - -#define EVENT_CONSOLE_CARET 0x4001 -#define EVENT_CONSOLE_UPDATE_REGION 0x4002 -#define EVENT_CONSOLE_UPDATE_SIMPLE 0x4003 -#define EVENT_CONSOLE_UPDATE_SCROLL 0x4004 -#define EVENT_CONSOLE_LAYOUT 0x4005 -#define EVENT_CONSOLE_START_APPLICATION 0x4006 -#define EVENT_CONSOLE_END_APPLICATION 0x4007 - -#define CONSOLE_APPLICATION_16BIT 0x0001 - -#define CONSOLE_CARET_SELECTION 0x0001 -#define CONSOLE_CARET_VISIBLE 0x0002 - -#define EVENT_OBJECT_CREATE 0x8000 -#define EVENT_OBJECT_DESTROY 0x8001 -#define EVENT_OBJECT_SHOW 0x8002 -#define EVENT_OBJECT_HIDE 0x8003 -#define EVENT_OBJECT_REORDER 0x8004 - -#define EVENT_OBJECT_FOCUS 0x8005 -#define EVENT_OBJECT_SELECTION 0x8006 -#define EVENT_OBJECT_SELECTIONADD 0x8007 -#define EVENT_OBJECT_SELECTIONREMOVE 0x8008 -#define EVENT_OBJECT_SELECTIONWITHIN 0x8009 - -#define EVENT_OBJECT_STATECHANGE 0x800A - -#define EVENT_OBJECT_LOCATIONCHANGE 0x800B - -#define EVENT_OBJECT_NAMECHANGE 0x800C -#define EVENT_OBJECT_DESCRIPTIONCHANGE 0x800D -#define EVENT_OBJECT_VALUECHANGE 0x800E -#define EVENT_OBJECT_PARENTCHANGE 0x800F -#define EVENT_OBJECT_HELPCHANGE 0x8010 -#define EVENT_OBJECT_DEFACTIONCHANGE 0x8011 -#define EVENT_OBJECT_ACCELERATORCHANGE 0x8012 - -#define SOUND_SYSTEM_STARTUP 1 -#define SOUND_SYSTEM_SHUTDOWN 2 -#define SOUND_SYSTEM_BEEP 3 -#define SOUND_SYSTEM_ERROR 4 -#define SOUND_SYSTEM_QUESTION 5 -#define SOUND_SYSTEM_WARNING 6 -#define SOUND_SYSTEM_INFORMATION 7 -#define SOUND_SYSTEM_MAXIMIZE 8 -#define SOUND_SYSTEM_MINIMIZE 9 -#define SOUND_SYSTEM_RESTOREUP 10 -#define SOUND_SYSTEM_RESTOREDOWN 11 -#define SOUND_SYSTEM_APPSTART 12 -#define SOUND_SYSTEM_FAULT 13 -#define SOUND_SYSTEM_APPEND 14 -#define SOUND_SYSTEM_MENUCOMMAND 15 -#define SOUND_SYSTEM_MENUPOPUP 16 -#define CSOUND_SYSTEM 16 - -#define ALERT_SYSTEM_INFORMATIONAL 1 -#define ALERT_SYSTEM_WARNING 2 -#define ALERT_SYSTEM_ERROR 3 -#define ALERT_SYSTEM_QUERY 4 -#define ALERT_SYSTEM_CRITICAL 5 -#define CALERT_SYSTEM 6 - - typedef struct tagGUITHREADINFO { - DWORD cbSize; - DWORD flags; - HWND hwndActive; - HWND hwndFocus; - HWND hwndCapture; - HWND hwndMenuOwner; - HWND hwndMoveSize; - HWND hwndCaret; - RECT rcCaret; - } GUITHREADINFO,*PGUITHREADINFO,*LPGUITHREADINFO; - -#define GUI_CARETBLINKING 0x00000001 -#define GUI_INMOVESIZE 0x00000002 -#define GUI_INMENUMODE 0x00000004 -#define GUI_SYSTEMMENUMODE 0x00000008 -#define GUI_POPUPMENUMODE 0x00000010 -#define GUI_16BITTASK 0x00000020 - -#ifdef UNICODE -#define GetWindowModuleFileName GetWindowModuleFileNameW -#else -#define GetWindowModuleFileName GetWindowModuleFileNameA -#endif - - WINUSERAPI WINBOOL WINAPI GetGUIThreadInfo(DWORD idThread,PGUITHREADINFO pgui); - WINUSERAPI UINT WINAPI GetWindowModuleFileNameA(HWND hwnd,LPSTR pszFileName,UINT cchFileNameMax); - WINUSERAPI UINT WINAPI GetWindowModuleFileNameW(HWND hwnd,LPWSTR pszFileName,UINT cchFileNameMax); - -#ifndef NO_STATE_FLAGS -#define STATE_SYSTEM_UNAVAILABLE 0x00000001 -#define STATE_SYSTEM_SELECTED 0x00000002 -#define STATE_SYSTEM_FOCUSED 0x00000004 -#define STATE_SYSTEM_PRESSED 0x00000008 -#define STATE_SYSTEM_CHECKED 0x00000010 -#define STATE_SYSTEM_MIXED 0x00000020 -#define STATE_SYSTEM_INDETERMINATE STATE_SYSTEM_MIXED -#define STATE_SYSTEM_READONLY 0x00000040 -#define STATE_SYSTEM_HOTTRACKED 0x00000080 -#define STATE_SYSTEM_DEFAULT 0x00000100 -#define STATE_SYSTEM_EXPANDED 0x00000200 -#define STATE_SYSTEM_COLLAPSED 0x00000400 -#define STATE_SYSTEM_BUSY 0x00000800 -#define STATE_SYSTEM_FLOATING 0x00001000 -#define STATE_SYSTEM_MARQUEED 0x00002000 -#define STATE_SYSTEM_ANIMATED 0x00004000 -#define STATE_SYSTEM_INVISIBLE 0x00008000 -#define STATE_SYSTEM_OFFSCREEN 0x00010000 -#define STATE_SYSTEM_SIZEABLE 0x00020000 -#define STATE_SYSTEM_MOVEABLE 0x00040000 -#define STATE_SYSTEM_SELFVOICING 0x00080000 -#define STATE_SYSTEM_FOCUSABLE 0x00100000 -#define STATE_SYSTEM_SELECTABLE 0x00200000 -#define STATE_SYSTEM_LINKED 0x00400000 -#define STATE_SYSTEM_TRAVERSED 0x00800000 -#define STATE_SYSTEM_MULTISELECTABLE 0x01000000 -#define STATE_SYSTEM_EXTSELECTABLE 0x02000000 -#define STATE_SYSTEM_ALERT_LOW 0x04000000 -#define STATE_SYSTEM_ALERT_MEDIUM 0x08000000 -#define STATE_SYSTEM_ALERT_HIGH 0x10000000 -#define STATE_SYSTEM_PROTECTED 0x20000000 -#define STATE_SYSTEM_VALID 0x3FFFFFFF -#endif - -#define CCHILDREN_TITLEBAR 5 -#define CCHILDREN_SCROLLBAR 5 - - typedef struct tagCURSORINFO { - DWORD cbSize; - DWORD flags; - HCURSOR hCursor; - POINT ptScreenPos; - } CURSORINFO,*PCURSORINFO,*LPCURSORINFO; - -#define CURSOR_SHOWING 0x00000001 - - WINUSERAPI WINBOOL WINAPI GetCursorInfo(PCURSORINFO pci); - - typedef struct tagWINDOWINFO { - DWORD cbSize; - RECT rcWindow; - RECT rcClient; - DWORD dwStyle; - DWORD dwExStyle; - DWORD dwWindowStatus; - UINT cxWindowBorders; - UINT cyWindowBorders; - ATOM atomWindowType; - WORD wCreatorVersion; - } WINDOWINFO,*PWINDOWINFO,*LPWINDOWINFO; - -#define WS_ACTIVECAPTION 0x0001 - - WINUSERAPI WINBOOL WINAPI GetWindowInfo(HWND hwnd,PWINDOWINFO pwi); - - typedef struct tagTITLEBARINFO { - DWORD cbSize; - RECT rcTitleBar; - DWORD rgstate[CCHILDREN_TITLEBAR + 1]; - } TITLEBARINFO,*PTITLEBARINFO,*LPTITLEBARINFO; - - WINUSERAPI WINBOOL WINAPI GetTitleBarInfo(HWND hwnd,PTITLEBARINFO pti); - - typedef struct tagMENUBARINFO { - DWORD cbSize; - RECT rcBar; - HMENU hMenu; - HWND hwndMenu; - WINBOOL fBarFocused:1; - WINBOOL fFocused:1; - } MENUBARINFO,*PMENUBARINFO,*LPMENUBARINFO; - - WINUSERAPI WINBOOL WINAPI GetMenuBarInfo(HWND hwnd,LONG idObject,LONG idItem,PMENUBARINFO pmbi); - - typedef struct tagSCROLLBARINFO { - DWORD cbSize; - RECT rcScrollBar; - int dxyLineButton; - int xyThumbTop; - int xyThumbBottom; - int reserved; - DWORD rgstate[CCHILDREN_SCROLLBAR + 1]; - } SCROLLBARINFO,*PSCROLLBARINFO,*LPSCROLLBARINFO; - - WINUSERAPI WINBOOL WINAPI GetScrollBarInfo(HWND hwnd,LONG idObject,PSCROLLBARINFO psbi); - - typedef struct tagCOMBOBOXINFO { - DWORD cbSize; - RECT rcItem; - RECT rcButton; - DWORD stateButton; - HWND hwndCombo; - HWND hwndItem; - HWND hwndList; - } COMBOBOXINFO,*PCOMBOBOXINFO,*LPCOMBOBOXINFO; - - WINUSERAPI WINBOOL WINAPI GetComboBoxInfo(HWND hwndCombo,PCOMBOBOXINFO pcbi); - -#define GA_PARENT 1 -#define GA_ROOT 2 -#define GA_ROOTOWNER 3 - - WINUSERAPI HWND WINAPI GetAncestor(HWND hwnd,UINT gaFlags); - WINUSERAPI HWND WINAPI RealChildWindowFromPoint(HWND hwndParent,POINT ptParentClientCoords); - WINUSERAPI UINT WINAPI RealGetWindowClassA(HWND hwnd,LPSTR ptszClassName,UINT cchClassNameMax); - WINUSERAPI UINT WINAPI RealGetWindowClassW(HWND hwnd,LPWSTR ptszClassName,UINT cchClassNameMax); -#ifdef UNICODE -#define RealGetWindowClass RealGetWindowClassW -#else -#define RealGetWindowClass RealGetWindowClassA -#endif - - typedef struct tagALTTABINFO { - DWORD cbSize; - int cItems; - int cColumns; - int cRows; - int iColFocus; - int iRowFocus; - int cxItem; - int cyItem; - POINT ptStart; - } ALTTABINFO,*PALTTABINFO,*LPALTTABINFO; - -#ifdef UNICODE -#define GetAltTabInfo GetAltTabInfoW -#else -#define GetAltTabInfo GetAltTabInfoA -#endif - - WINUSERAPI WINBOOL WINAPI GetAltTabInfoA(HWND hwnd,int iItem,PALTTABINFO pati,LPSTR pszItemText,UINT cchItemText); - WINUSERAPI WINBOOL WINAPI GetAltTabInfoW(HWND hwnd,int iItem,PALTTABINFO pati,LPWSTR pszItemText,UINT cchItemText); - WINUSERAPI DWORD WINAPI GetListBoxInfo(HWND hwnd); -#endif - - WINUSERAPI WINBOOL WINAPI LockWorkStation(VOID); - WINUSERAPI WINBOOL WINAPI UserHandleGrantAccess(HANDLE hUserHandle,HANDLE hJob,WINBOOL bGrant); - - DECLARE_HANDLE(HRAWINPUT); - -#define GET_RAWINPUT_CODE_WPARAM(wParam) ((wParam) & 0xff) - -#define RIM_INPUT 0 -#define RIM_INPUTSINK 1 - - typedef struct tagRAWINPUTHEADER { - DWORD dwType; - DWORD dwSize; - HANDLE hDevice; - WPARAM wParam; - } RAWINPUTHEADER,*PRAWINPUTHEADER,*LPRAWINPUTHEADER; - -#define RIM_TYPEMOUSE 0 -#define RIM_TYPEKEYBOARD 1 -#define RIM_TYPEHID 2 - - typedef struct tagRAWMOUSE { - USHORT usFlags; - union { - ULONG ulButtons; - struct { - USHORT usButtonFlags; - USHORT usButtonData; - }; - }; - ULONG ulRawButtons; - LONG lLastX; - LONG lLastY; - ULONG ulExtraInformation; - } RAWMOUSE,*PRAWMOUSE,*LPRAWMOUSE; - -#define RI_MOUSE_LEFT_BUTTON_DOWN 0x0001 -#define RI_MOUSE_LEFT_BUTTON_UP 0x0002 -#define RI_MOUSE_RIGHT_BUTTON_DOWN 0x0004 -#define RI_MOUSE_RIGHT_BUTTON_UP 0x0008 -#define RI_MOUSE_MIDDLE_BUTTON_DOWN 0x0010 -#define RI_MOUSE_MIDDLE_BUTTON_UP 0x0020 - -#define RI_MOUSE_BUTTON_1_DOWN RI_MOUSE_LEFT_BUTTON_DOWN -#define RI_MOUSE_BUTTON_1_UP RI_MOUSE_LEFT_BUTTON_UP -#define RI_MOUSE_BUTTON_2_DOWN RI_MOUSE_RIGHT_BUTTON_DOWN -#define RI_MOUSE_BUTTON_2_UP RI_MOUSE_RIGHT_BUTTON_UP -#define RI_MOUSE_BUTTON_3_DOWN RI_MOUSE_MIDDLE_BUTTON_DOWN -#define RI_MOUSE_BUTTON_3_UP RI_MOUSE_MIDDLE_BUTTON_UP - -#define RI_MOUSE_BUTTON_4_DOWN 0x0040 -#define RI_MOUSE_BUTTON_4_UP 0x0080 -#define RI_MOUSE_BUTTON_5_DOWN 0x0100 -#define RI_MOUSE_BUTTON_5_UP 0x0200 - -#define RI_MOUSE_WHEEL 0x0400 - -#define MOUSE_MOVE_RELATIVE 0 -#define MOUSE_MOVE_ABSOLUTE 1 -#define MOUSE_VIRTUAL_DESKTOP 0x02 -#define MOUSE_ATTRIBUTES_CHANGED 0x04 - - typedef struct tagRAWKEYBOARD { - USHORT MakeCode; - USHORT Flags; - USHORT Reserved; - USHORT VKey; - UINT Message; - ULONG ExtraInformation; - } RAWKEYBOARD,*PRAWKEYBOARD,*LPRAWKEYBOARD; - -#define KEYBOARD_OVERRUN_MAKE_CODE 0xFF - -#define RI_KEY_MAKE 0 -#define RI_KEY_BREAK 1 -#define RI_KEY_E0 2 -#define RI_KEY_E1 4 -#define RI_KEY_TERMSRV_SET_LED 8 -#define RI_KEY_TERMSRV_SHADOW 0x10 - - typedef struct tagRAWHID { - DWORD dwSizeHid; - DWORD dwCount; - BYTE bRawData[1]; - } RAWHID,*PRAWHID,*LPRAWHID; - - typedef struct tagRAWINPUT { - RAWINPUTHEADER header; - union { - RAWMOUSE mouse; - RAWKEYBOARD keyboard; - RAWHID hid; - } data; - } RAWINPUT,*PRAWINPUT,*LPRAWINPUT; - -#ifdef _WIN64 -#define RAWINPUT_ALIGN(x) (((x) + sizeof(QWORD) - 1) & ~(sizeof(QWORD) - 1)) -#else -#define RAWINPUT_ALIGN(x) (((x) + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1)) -#endif - -#define NEXTRAWINPUTBLOCK(ptr) ((PRAWINPUT)RAWINPUT_ALIGN((ULONG_PTR)((PBYTE)(ptr) + (ptr)->header.dwSize))) - -#define RID_INPUT 0x10000003 -#define RID_HEADER 0x10000005 - - WINUSERAPI UINT WINAPI GetRawInputData(HRAWINPUT hRawInput,UINT uiCommand,LPVOID pData,PUINT pcbSize,UINT cbSizeHeader); - -#define RIDI_PREPARSEDDATA 0x20000005 -#define RIDI_DEVICENAME 0x20000007 -#define RIDI_DEVICEINFO 0x2000000b - - typedef struct tagRID_DEVICE_INFO_MOUSE { - DWORD dwId; - DWORD dwNumberOfButtons; - DWORD dwSampleRate; - } RID_DEVICE_INFO_MOUSE,*PRID_DEVICE_INFO_MOUSE; - - typedef struct tagRID_DEVICE_INFO_KEYBOARD { - DWORD dwType; - DWORD dwSubType; - DWORD dwKeyboardMode; - DWORD dwNumberOfFunctionKeys; - DWORD dwNumberOfIndicators; - DWORD dwNumberOfKeysTotal; - } RID_DEVICE_INFO_KEYBOARD,*PRID_DEVICE_INFO_KEYBOARD; - - typedef struct tagRID_DEVICE_INFO_HID { - DWORD dwVendorId; - DWORD dwProductId; - DWORD dwVersionNumber; - USHORT usUsagePage; - USHORT usUsage; - } RID_DEVICE_INFO_HID,*PRID_DEVICE_INFO_HID; - - typedef struct tagRID_DEVICE_INFO { - DWORD cbSize; - DWORD dwType; - union { - RID_DEVICE_INFO_MOUSE mouse; - RID_DEVICE_INFO_KEYBOARD keyboard; - RID_DEVICE_INFO_HID hid; - }; - } RID_DEVICE_INFO,*PRID_DEVICE_INFO,*LPRID_DEVICE_INFO; - -#ifdef UNICODE -#define GetRawInputDeviceInfo GetRawInputDeviceInfoW -#else -#define GetRawInputDeviceInfo GetRawInputDeviceInfoA -#endif - - WINUSERAPI UINT WINAPI GetRawInputDeviceInfoA(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); - WINUSERAPI UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); - WINUSERAPI UINT WINAPI GetRawInputBuffer(PRAWINPUT pData,PUINT pcbSize,UINT cbSizeHeader); - - typedef struct tagRAWINPUTDEVICE { - USHORT usUsagePage; - USHORT usUsage; - DWORD dwFlags; - HWND hwndTarget; - } RAWINPUTDEVICE,*PRAWINPUTDEVICE,*LPRAWINPUTDEVICE; - - typedef CONST RAWINPUTDEVICE *PCRAWINPUTDEVICE; - -#define RIDEV_REMOVE 0x00000001 -#define RIDEV_EXCLUDE 0x00000010 -#define RIDEV_PAGEONLY 0x00000020 -#define RIDEV_NOLEGACY 0x00000030 -#define RIDEV_INPUTSINK 0x00000100 -#define RIDEV_CAPTUREMOUSE 0x00000200 -#define RIDEV_NOHOTKEYS 0x00000200 -#define RIDEV_APPKEYS 0x00000400 -#define RIDEV_EXMODEMASK 0x000000F0 -#define RIDEV_EXMODE(mode) ((mode) & RIDEV_EXMODEMASK) - - WINUSERAPI WINBOOL WINAPI RegisterRawInputDevices(PCRAWINPUTDEVICE pRawInputDevices,UINT uiNumDevices,UINT cbSize); - WINUSERAPI UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices,PUINT puiNumDevices,UINT cbSize); - - typedef struct tagRAWINPUTDEVICELIST { - HANDLE hDevice; - DWORD dwType; - } RAWINPUTDEVICELIST,*PRAWINPUTDEVICELIST; - - WINUSERAPI UINT WINAPI GetRawInputDeviceList(PRAWINPUTDEVICELIST pRawInputDeviceList,PUINT puiNumDevices,UINT cbSize); - WINUSERAPI LRESULT WINAPI DefRawInputProc(PRAWINPUT *paRawInput,INT nInput,UINT cbSizeHeader); - -#endif /* NOUSER */ - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WINUSER_ +#define _WINUSER_ + +#define WINUSERAPI DECLSPEC_IMPORT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINVER +#define WINVER 0x0502 +#endif + +#include + +#ifndef NOUSER + typedef HANDLE HDWP; + typedef VOID MENUTEMPLATEA; + typedef VOID MENUTEMPLATEW; + typedef PVOID LPMENUTEMPLATEA; + typedef PVOID LPMENUTEMPLATEW; + +#ifdef UNICODE + typedef MENUTEMPLATEW MENUTEMPLATE; + typedef LPMENUTEMPLATEW LPMENUTEMPLATE; +#else + typedef MENUTEMPLATEA MENUTEMPLATE; + typedef LPMENUTEMPLATEA LPMENUTEMPLATE; +#endif + + typedef LRESULT (CALLBACK *WNDPROC)(HWND,UINT,WPARAM,LPARAM); + typedef INT_PTR (CALLBACK *DLGPROC)(HWND,UINT,WPARAM,LPARAM); + typedef VOID (CALLBACK *TIMERPROC)(HWND,UINT,UINT_PTR,DWORD); + typedef WINBOOL (CALLBACK *GRAYSTRINGPROC)(HDC,LPARAM,int); + typedef WINBOOL (CALLBACK *WNDENUMPROC)(HWND,LPARAM); + typedef LRESULT (CALLBACK *HOOKPROC)(int code,WPARAM wParam,LPARAM lParam); + typedef VOID (CALLBACK *SENDASYNCPROC)(HWND,UINT,ULONG_PTR,LRESULT); + typedef WINBOOL (CALLBACK *PROPENUMPROCA)(HWND,LPCSTR,HANDLE); + typedef WINBOOL (CALLBACK *PROPENUMPROCW)(HWND,LPCWSTR,HANDLE); + typedef WINBOOL (CALLBACK *PROPENUMPROCEXA)(HWND,LPSTR,HANDLE,ULONG_PTR); + typedef WINBOOL (CALLBACK *PROPENUMPROCEXW)(HWND,LPWSTR,HANDLE,ULONG_PTR); + typedef int (CALLBACK *EDITWORDBREAKPROCA)(LPSTR lpch,int ichCurrent,int cch,int code); + typedef int (CALLBACK *EDITWORDBREAKPROCW)(LPWSTR lpch,int ichCurrent,int cch,int code); + typedef WINBOOL (CALLBACK *DRAWSTATEPROC)(HDC hdc,LPARAM lData,WPARAM wData,int cx,int cy); + +#ifdef UNICODE + typedef PROPENUMPROCW PROPENUMPROC; + typedef PROPENUMPROCEXW PROPENUMPROCEX; + typedef EDITWORDBREAKPROCW EDITWORDBREAKPROC; +#else + typedef PROPENUMPROCA PROPENUMPROC; + typedef PROPENUMPROCEXA PROPENUMPROCEX; + typedef EDITWORDBREAKPROCA EDITWORDBREAKPROC; +#endif + + typedef WINBOOL (CALLBACK *NAMEENUMPROCA)(LPSTR,LPARAM); + typedef WINBOOL (CALLBACK *NAMEENUMPROCW)(LPWSTR,LPARAM); + typedef NAMEENUMPROCA WINSTAENUMPROCA; + typedef NAMEENUMPROCA DESKTOPENUMPROCA; + typedef NAMEENUMPROCW WINSTAENUMPROCW; + typedef NAMEENUMPROCW DESKTOPENUMPROCW; + +#ifdef UNICODE + typedef WINSTAENUMPROCW WINSTAENUMPROC; + typedef DESKTOPENUMPROCW DESKTOPENUMPROC; +#else + typedef WINSTAENUMPROCA WINSTAENUMPROC; + typedef DESKTOPENUMPROCA DESKTOPENUMPROC; +#endif + +#define IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16)==0) +#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i)))) +#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i)))) +#ifdef UNICODE +#define MAKEINTRESOURCE MAKEINTRESOURCEW +#else +#define MAKEINTRESOURCE MAKEINTRESOURCEA +#endif + +#ifndef NORESOURCE + +#define RT_CURSOR MAKEINTRESOURCE(1) +#define RT_BITMAP MAKEINTRESOURCE(2) +#define RT_ICON MAKEINTRESOURCE(3) +#define RT_MENU MAKEINTRESOURCE(4) +#define RT_DIALOG MAKEINTRESOURCE(5) +#define RT_STRING MAKEINTRESOURCE(6) +#define RT_FONTDIR MAKEINTRESOURCE(7) +#define RT_FONT MAKEINTRESOURCE(8) +#define RT_ACCELERATOR MAKEINTRESOURCE(9) +#define RT_RCDATA MAKEINTRESOURCE(10) +#define RT_MESSAGETABLE MAKEINTRESOURCE(11) + +#define DIFFERENCE 11 +#define RT_GROUP_CURSOR MAKEINTRESOURCE((ULONG_PTR)RT_CURSOR + DIFFERENCE) +#define RT_GROUP_ICON MAKEINTRESOURCE((ULONG_PTR)RT_ICON + DIFFERENCE) +#define RT_VERSION MAKEINTRESOURCE(16) +#define RT_DLGINCLUDE MAKEINTRESOURCE(17) +#define RT_PLUGPLAY MAKEINTRESOURCE(19) +#define RT_VXD MAKEINTRESOURCE(20) +#define RT_ANICURSOR MAKEINTRESOURCE(21) +#define RT_ANIICON MAKEINTRESOURCE(22) +#define RT_HTML MAKEINTRESOURCE(23) +#ifdef RC_INVOKED +#define RT_MANIFEST 24 +#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 +#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 +#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3 +#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID 1 +#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID 16 +#else +#define RT_MANIFEST MAKEINTRESOURCE(24) +#define CREATEPROCESS_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) +#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(2) +#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(3) +#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(1) +#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(16) +#endif +#endif + +#ifdef UNICODE +#define wvsprintf wvsprintfW +#define wsprintf wsprintfW +#else +#define wvsprintf wvsprintfA +#define wsprintf wsprintfA +#endif + + WINUSERAPI int WINAPI wvsprintfA(LPSTR,LPCSTR,va_list arglist); + WINUSERAPI int WINAPI wvsprintfW(LPWSTR,LPCWSTR,va_list arglist); + WINUSERAPI int WINAPIV wsprintfA(LPSTR,LPCSTR,...); + WINUSERAPI int WINAPIV wsprintfW(LPWSTR,LPCWSTR,...); + +#define SETWALLPAPER_DEFAULT ((LPWSTR)-1) + +#ifndef NOSCROLL +#define SB_HORZ 0 +#define SB_VERT 1 +#define SB_CTL 2 +#define SB_BOTH 3 + +#define SB_LINEUP 0 +#define SB_LINELEFT 0 +#define SB_LINEDOWN 1 +#define SB_LINERIGHT 1 +#define SB_PAGEUP 2 +#define SB_PAGELEFT 2 +#define SB_PAGEDOWN 3 +#define SB_PAGERIGHT 3 +#define SB_THUMBPOSITION 4 +#define SB_THUMBTRACK 5 +#define SB_TOP 6 +#define SB_LEFT 6 +#define SB_BOTTOM 7 +#define SB_RIGHT 7 +#define SB_ENDSCROLL 8 +#endif + +#ifndef NOSHOWWINDOW +#define SW_HIDE 0 +#define SW_SHOWNORMAL 1 +#define SW_NORMAL 1 +#define SW_SHOWMINIMIZED 2 +#define SW_SHOWMAXIMIZED 3 +#define SW_MAXIMIZE 3 +#define SW_SHOWNOACTIVATE 4 +#define SW_SHOW 5 +#define SW_MINIMIZE 6 +#define SW_SHOWMINNOACTIVE 7 +#define SW_SHOWNA 8 +#define SW_RESTORE 9 +#define SW_SHOWDEFAULT 10 +#define SW_FORCEMINIMIZE 11 +#define SW_MAX 11 + +#define HIDE_WINDOW 0 +#define SHOW_OPENWINDOW 1 +#define SHOW_ICONWINDOW 2 +#define SHOW_FULLSCREEN 3 +#define SHOW_OPENNOACTIVATE 4 + +#define SW_PARENTCLOSING 1 +#define SW_OTHERZOOM 2 +#define SW_PARENTOPENING 3 +#define SW_OTHERUNZOOM 4 +#endif + +#define AW_HOR_POSITIVE 0x00000001 +#define AW_HOR_NEGATIVE 0x00000002 +#define AW_VER_POSITIVE 0x00000004 +#define AW_VER_NEGATIVE 0x00000008 +#define AW_CENTER 0x00000010 +#define AW_HIDE 0x00010000 +#define AW_ACTIVATE 0x00020000 +#define AW_SLIDE 0x00040000 +#define AW_BLEND 0x00080000 + +#define KF_EXTENDED 0x0100 +#define KF_DLGMODE 0x0800 +#define KF_MENUMODE 0x1000 +#define KF_ALTDOWN 0x2000 +#define KF_REPEAT 0x4000 +#define KF_UP 0x8000 + +#ifndef NOVIRTUALKEYCODES + +#define VK_LBUTTON 0x01 +#define VK_RBUTTON 0x02 +#define VK_CANCEL 0x03 +#define VK_MBUTTON 0x04 +#define VK_XBUTTON1 0x05 +#define VK_XBUTTON2 0x06 +#define VK_BACK 0x08 +#define VK_TAB 0x09 +#define VK_CLEAR 0x0C +#define VK_RETURN 0x0D +#define VK_SHIFT 0x10 +#define VK_CONTROL 0x11 +#define VK_MENU 0x12 +#define VK_PAUSE 0x13 +#define VK_CAPITAL 0x14 +#define VK_KANA 0x15 +#define VK_HANGEUL 0x15 +#define VK_HANGUL 0x15 +#define VK_JUNJA 0x17 +#define VK_FINAL 0x18 +#define VK_HANJA 0x19 +#define VK_KANJI 0x19 +#define VK_ESCAPE 0x1B +#define VK_CONVERT 0x1C +#define VK_NONCONVERT 0x1D +#define VK_ACCEPT 0x1E +#define VK_MODECHANGE 0x1F +#define VK_SPACE 0x20 +#define VK_PRIOR 0x21 +#define VK_NEXT 0x22 +#define VK_END 0x23 +#define VK_HOME 0x24 +#define VK_LEFT 0x25 +#define VK_UP 0x26 +#define VK_RIGHT 0x27 +#define VK_DOWN 0x28 +#define VK_SELECT 0x29 +#define VK_PRINT 0x2A +#define VK_EXECUTE 0x2B +#define VK_SNAPSHOT 0x2C +#define VK_INSERT 0x2D +#define VK_DELETE 0x2E +#define VK_HELP 0x2F + +#define VK_LWIN 0x5B +#define VK_RWIN 0x5C +#define VK_APPS 0x5D +#define VK_SLEEP 0x5F +#define VK_NUMPAD0 0x60 +#define VK_NUMPAD1 0x61 +#define VK_NUMPAD2 0x62 +#define VK_NUMPAD3 0x63 +#define VK_NUMPAD4 0x64 +#define VK_NUMPAD5 0x65 +#define VK_NUMPAD6 0x66 +#define VK_NUMPAD7 0x67 +#define VK_NUMPAD8 0x68 +#define VK_NUMPAD9 0x69 +#define VK_MULTIPLY 0x6A +#define VK_ADD 0x6B +#define VK_SEPARATOR 0x6C +#define VK_SUBTRACT 0x6D +#define VK_DECIMAL 0x6E +#define VK_DIVIDE 0x6F +#define VK_F1 0x70 +#define VK_F2 0x71 +#define VK_F3 0x72 +#define VK_F4 0x73 +#define VK_F5 0x74 +#define VK_F6 0x75 +#define VK_F7 0x76 +#define VK_F8 0x77 +#define VK_F9 0x78 +#define VK_F10 0x79 +#define VK_F11 0x7A +#define VK_F12 0x7B +#define VK_F13 0x7C +#define VK_F14 0x7D +#define VK_F15 0x7E +#define VK_F16 0x7F +#define VK_F17 0x80 +#define VK_F18 0x81 +#define VK_F19 0x82 +#define VK_F20 0x83 +#define VK_F21 0x84 +#define VK_F22 0x85 +#define VK_F23 0x86 +#define VK_F24 0x87 +#define VK_NUMLOCK 0x90 +#define VK_SCROLL 0x91 +#define VK_OEM_NEC_EQUAL 0x92 +#define VK_OEM_FJ_JISHO 0x92 +#define VK_OEM_FJ_MASSHOU 0x93 +#define VK_OEM_FJ_TOUROKU 0x94 +#define VK_OEM_FJ_LOYA 0x95 +#define VK_OEM_FJ_ROYA 0x96 +#define VK_LSHIFT 0xA0 +#define VK_RSHIFT 0xA1 +#define VK_LCONTROL 0xA2 +#define VK_RCONTROL 0xA3 +#define VK_LMENU 0xA4 +#define VK_RMENU 0xA5 +#define VK_BROWSER_BACK 0xA6 +#define VK_BROWSER_FORWARD 0xA7 +#define VK_BROWSER_REFRESH 0xA8 +#define VK_BROWSER_STOP 0xA9 +#define VK_BROWSER_SEARCH 0xAA +#define VK_BROWSER_FAVORITES 0xAB +#define VK_BROWSER_HOME 0xAC +#define VK_VOLUME_MUTE 0xAD +#define VK_VOLUME_DOWN 0xAE +#define VK_VOLUME_UP 0xAF +#define VK_MEDIA_NEXT_TRACK 0xB0 +#define VK_MEDIA_PREV_TRACK 0xB1 +#define VK_MEDIA_STOP 0xB2 +#define VK_MEDIA_PLAY_PAUSE 0xB3 +#define VK_LAUNCH_MAIL 0xB4 +#define VK_LAUNCH_MEDIA_SELECT 0xB5 +#define VK_LAUNCH_APP1 0xB6 +#define VK_LAUNCH_APP2 0xB7 +#define VK_OEM_1 0xBA +#define VK_OEM_PLUS 0xBB +#define VK_OEM_COMMA 0xBC +#define VK_OEM_MINUS 0xBD +#define VK_OEM_PERIOD 0xBE +#define VK_OEM_2 0xBF +#define VK_OEM_3 0xC0 +#define VK_OEM_4 0xDB +#define VK_OEM_5 0xDC +#define VK_OEM_6 0xDD +#define VK_OEM_7 0xDE +#define VK_OEM_8 0xDF +#define VK_OEM_AX 0xE1 +#define VK_OEM_102 0xE2 +#define VK_ICO_HELP 0xE3 +#define VK_ICO_00 0xE4 +#define VK_PROCESSKEY 0xE5 +#define VK_ICO_CLEAR 0xE6 +#define VK_PACKET 0xE7 +#define VK_OEM_RESET 0xE9 +#define VK_OEM_JUMP 0xEA +#define VK_OEM_PA1 0xEB +#define VK_OEM_PA2 0xEC +#define VK_OEM_PA3 0xED +#define VK_OEM_WSCTRL 0xEE +#define VK_OEM_CUSEL 0xEF +#define VK_OEM_ATTN 0xF0 +#define VK_OEM_FINISH 0xF1 +#define VK_OEM_COPY 0xF2 +#define VK_OEM_AUTO 0xF3 +#define VK_OEM_ENLW 0xF4 +#define VK_OEM_BACKTAB 0xF5 +#define VK_ATTN 0xF6 +#define VK_CRSEL 0xF7 +#define VK_EXSEL 0xF8 +#define VK_EREOF 0xF9 +#define VK_PLAY 0xFA +#define VK_ZOOM 0xFB +#define VK_NONAME 0xFC +#define VK_PA1 0xFD +#define VK_OEM_CLEAR 0xFE +#endif + +#ifndef NOWH + +#define WH_MIN (-1) +#define WH_MSGFILTER (-1) +#define WH_JOURNALRECORD 0 +#define WH_JOURNALPLAYBACK 1 +#define WH_KEYBOARD 2 +#define WH_GETMESSAGE 3 +#define WH_CALLWNDPROC 4 +#define WH_CBT 5 +#define WH_SYSMSGFILTER 6 +#define WH_MOUSE 7 +#define WH_HARDWARE 8 +#define WH_DEBUG 9 +#define WH_SHELL 10 +#define WH_FOREGROUNDIDLE 11 +#define WH_CALLWNDPROCRET 12 + +#define WH_KEYBOARD_LL 13 +#define WH_MOUSE_LL 14 + +#define WH_MAX 14 + +#define WH_MINHOOK WH_MIN +#define WH_MAXHOOK WH_MAX + +#define HC_ACTION 0 +#define HC_GETNEXT 1 +#define HC_SKIP 2 +#define HC_NOREMOVE 3 +#define HC_NOREM HC_NOREMOVE +#define HC_SYSMODALON 4 +#define HC_SYSMODALOFF 5 + +#define HCBT_MOVESIZE 0 +#define HCBT_MINMAX 1 +#define HCBT_QS 2 +#define HCBT_CREATEWND 3 +#define HCBT_DESTROYWND 4 +#define HCBT_ACTIVATE 5 +#define HCBT_CLICKSKIPPED 6 +#define HCBT_KEYSKIPPED 7 +#define HCBT_SYSCOMMAND 8 +#define HCBT_SETFOCUS 9 + + typedef struct tagCBT_CREATEWNDA { + struct tagCREATESTRUCTA *lpcs; + HWND hwndInsertAfter; + } CBT_CREATEWNDA,*LPCBT_CREATEWNDA; + + typedef struct tagCBT_CREATEWNDW { + struct tagCREATESTRUCTW *lpcs; + HWND hwndInsertAfter; + } CBT_CREATEWNDW,*LPCBT_CREATEWNDW; +#ifdef UNICODE + typedef CBT_CREATEWNDW CBT_CREATEWND; + typedef LPCBT_CREATEWNDW LPCBT_CREATEWND; +#else + typedef CBT_CREATEWNDA CBT_CREATEWND; + typedef LPCBT_CREATEWNDA LPCBT_CREATEWND; +#endif + + typedef struct tagCBTACTIVATESTRUCT + { + WINBOOL fMouse; + HWND hWndActive; + } CBTACTIVATESTRUCT,*LPCBTACTIVATESTRUCT; + + typedef struct tagWTSSESSION_NOTIFICATION { + DWORD cbSize; + DWORD dwSessionId; + + } WTSSESSION_NOTIFICATION,*PWTSSESSION_NOTIFICATION; + +#define WTS_CONSOLE_CONNECT 0x1 +#define WTS_CONSOLE_DISCONNECT 0x2 +#define WTS_REMOTE_CONNECT 0x3 +#define WTS_REMOTE_DISCONNECT 0x4 +#define WTS_SESSION_LOGON 0x5 +#define WTS_SESSION_LOGOFF 0x6 +#define WTS_SESSION_LOCK 0x7 +#define WTS_SESSION_UNLOCK 0x8 +#define WTS_SESSION_REMOTE_CONTROL 0x9 + +#define MSGF_DIALOGBOX 0 +#define MSGF_MESSAGEBOX 1 +#define MSGF_MENU 2 +#define MSGF_SCROLLBAR 5 +#define MSGF_NEXTWINDOW 6 +#define MSGF_MAX 8 +#define MSGF_USER 4096 + +#define HSHELL_WINDOWCREATED 1 +#define HSHELL_WINDOWDESTROYED 2 +#define HSHELL_ACTIVATESHELLWINDOW 3 + +#define HSHELL_WINDOWACTIVATED 4 +#define HSHELL_GETMINRECT 5 +#define HSHELL_REDRAW 6 +#define HSHELL_TASKMAN 7 +#define HSHELL_LANGUAGE 8 +#define HSHELL_SYSMENU 9 +#define HSHELL_ENDTASK 10 +#define HSHELL_ACCESSIBILITYSTATE 11 +#define HSHELL_APPCOMMAND 12 +#define HSHELL_WINDOWREPLACED 13 +#define HSHELL_WINDOWREPLACING 14 +#define HSHELL_HIGHBIT 0x8000 +#define HSHELL_FLASH (HSHELL_REDRAW|HSHELL_HIGHBIT) +#define HSHELL_RUDEAPPACTIVATED (HSHELL_WINDOWACTIVATED|HSHELL_HIGHBIT) + +#define ACCESS_STICKYKEYS 0x0001 +#define ACCESS_FILTERKEYS 0x0002 +#define ACCESS_MOUSEKEYS 0x0003 + +#define APPCOMMAND_BROWSER_BACKWARD 1 +#define APPCOMMAND_BROWSER_FORWARD 2 +#define APPCOMMAND_BROWSER_REFRESH 3 +#define APPCOMMAND_BROWSER_STOP 4 +#define APPCOMMAND_BROWSER_SEARCH 5 +#define APPCOMMAND_BROWSER_FAVORITES 6 +#define APPCOMMAND_BROWSER_HOME 7 +#define APPCOMMAND_VOLUME_MUTE 8 +#define APPCOMMAND_VOLUME_DOWN 9 +#define APPCOMMAND_VOLUME_UP 10 +#define APPCOMMAND_MEDIA_NEXTTRACK 11 +#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12 +#define APPCOMMAND_MEDIA_STOP 13 +#define APPCOMMAND_MEDIA_PLAY_PAUSE 14 +#define APPCOMMAND_LAUNCH_MAIL 15 +#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16 +#define APPCOMMAND_LAUNCH_APP1 17 +#define APPCOMMAND_LAUNCH_APP2 18 +#define APPCOMMAND_BASS_DOWN 19 +#define APPCOMMAND_BASS_BOOST 20 +#define APPCOMMAND_BASS_UP 21 +#define APPCOMMAND_TREBLE_DOWN 22 +#define APPCOMMAND_TREBLE_UP 23 +#define APPCOMMAND_MICROPHONE_VOLUME_MUTE 24 +#define APPCOMMAND_MICROPHONE_VOLUME_DOWN 25 +#define APPCOMMAND_MICROPHONE_VOLUME_UP 26 +#define APPCOMMAND_HELP 27 +#define APPCOMMAND_FIND 28 +#define APPCOMMAND_NEW 29 +#define APPCOMMAND_OPEN 30 +#define APPCOMMAND_CLOSE 31 +#define APPCOMMAND_SAVE 32 +#define APPCOMMAND_PRINT 33 +#define APPCOMMAND_UNDO 34 +#define APPCOMMAND_REDO 35 +#define APPCOMMAND_COPY 36 +#define APPCOMMAND_CUT 37 +#define APPCOMMAND_PASTE 38 +#define APPCOMMAND_REPLY_TO_MAIL 39 +#define APPCOMMAND_FORWARD_MAIL 40 +#define APPCOMMAND_SEND_MAIL 41 +#define APPCOMMAND_SPELL_CHECK 42 +#define APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE 43 +#define APPCOMMAND_MIC_ON_OFF_TOGGLE 44 +#define APPCOMMAND_CORRECTION_LIST 45 +#define APPCOMMAND_MEDIA_PLAY 46 +#define APPCOMMAND_MEDIA_PAUSE 47 +#define APPCOMMAND_MEDIA_RECORD 48 +#define APPCOMMAND_MEDIA_FAST_FORWARD 49 +#define APPCOMMAND_MEDIA_REWIND 50 +#define APPCOMMAND_MEDIA_CHANNEL_UP 51 +#define APPCOMMAND_MEDIA_CHANNEL_DOWN 52 + +#define FAPPCOMMAND_MOUSE 0x8000 +#define FAPPCOMMAND_KEY 0 +#define FAPPCOMMAND_OEM 0x1000 +#define FAPPCOMMAND_MASK 0xF000 + +#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK)) +#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK)) +#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM +#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam)) +#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam) + + typedef struct { + HWND hwnd; + RECT rc; + } SHELLHOOKINFO,*LPSHELLHOOKINFO; + + typedef struct tagEVENTMSG { + UINT message; + UINT paramL; + UINT paramH; + DWORD time; + HWND hwnd; + } EVENTMSG,*PEVENTMSGMSG,*NPEVENTMSGMSG,*LPEVENTMSGMSG; + + typedef struct tagEVENTMSG *PEVENTMSG,*NPEVENTMSG,*LPEVENTMSG; + + typedef struct tagCWPSTRUCT { + LPARAM lParam; + WPARAM wParam; + UINT message; + HWND hwnd; + } CWPSTRUCT,*PCWPSTRUCT,*NPCWPSTRUCT,*LPCWPSTRUCT; + + typedef struct tagCWPRETSTRUCT { + LRESULT lResult; + LPARAM lParam; + WPARAM wParam; + UINT message; + HWND hwnd; + } CWPRETSTRUCT,*PCWPRETSTRUCT,*NPCWPRETSTRUCT,*LPCWPRETSTRUCT; + +#define LLKHF_EXTENDED (KF_EXTENDED >> 8) +#define LLKHF_INJECTED 0x00000010 +#define LLKHF_ALTDOWN (KF_ALTDOWN >> 8) +#define LLKHF_UP (KF_UP >> 8) + +#define LLMHF_INJECTED 0x00000001 + + typedef struct tagKBDLLHOOKSTRUCT { + DWORD vkCode; + DWORD scanCode; + DWORD flags; + DWORD time; + ULONG_PTR dwExtraInfo; + } KBDLLHOOKSTRUCT,*LPKBDLLHOOKSTRUCT,*PKBDLLHOOKSTRUCT; + + typedef struct tagMSLLHOOKSTRUCT { + POINT pt; + DWORD mouseData; + DWORD flags; + DWORD time; + ULONG_PTR dwExtraInfo; + } MSLLHOOKSTRUCT,*LPMSLLHOOKSTRUCT,*PMSLLHOOKSTRUCT; + + typedef struct tagDEBUGHOOKINFO { + DWORD idThread; + DWORD idThreadInstaller; + LPARAM lParam; + WPARAM wParam; + int code; + } DEBUGHOOKINFO,*PDEBUGHOOKINFO,*NPDEBUGHOOKINFO,*LPDEBUGHOOKINFO; + + typedef struct tagMOUSEHOOKSTRUCT { + POINT pt; + HWND hwnd; + UINT wHitTestCode; + ULONG_PTR dwExtraInfo; + } MOUSEHOOKSTRUCT,*LPMOUSEHOOKSTRUCT,*PMOUSEHOOKSTRUCT; + +#ifdef __cplusplus + typedef struct tagMOUSEHOOKSTRUCTEX : public tagMOUSEHOOKSTRUCT { + DWORD mouseData; + } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; +#else + typedef struct tagMOUSEHOOKSTRUCTEX { + MOUSEHOOKSTRUCT _unnamed; + DWORD mouseData; + } MOUSEHOOKSTRUCTEX,*LPMOUSEHOOKSTRUCTEX,*PMOUSEHOOKSTRUCTEX; +#endif + + typedef struct tagHARDWAREHOOKSTRUCT { + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + } HARDWAREHOOKSTRUCT,*LPHARDWAREHOOKSTRUCT,*PHARDWAREHOOKSTRUCT; +#endif + +#define HKL_PREV 0 +#define HKL_NEXT 1 + +#define KLF_ACTIVATE 0x00000001 +#define KLF_SUBSTITUTE_OK 0x00000002 +#define KLF_REORDER 0x00000008 +#define KLF_REPLACELANG 0x00000010 +#define KLF_NOTELLSHELL 0x00000080 +#define KLF_SETFORPROCESS 0x00000100 +#define KLF_SHIFTLOCK 0x00010000 +#define KLF_RESET 0x40000000 + +#define INPUTLANGCHANGE_SYSCHARSET 0x0001 +#define INPUTLANGCHANGE_FORWARD 0x0002 +#define INPUTLANGCHANGE_BACKWARD 0x0004 + +#define KL_NAMELENGTH 9 + +#ifdef UNICODE +#define LoadKeyboardLayout LoadKeyboardLayoutW +#define GetKeyboardLayoutName GetKeyboardLayoutNameW +#else +#define LoadKeyboardLayout LoadKeyboardLayoutA +#define GetKeyboardLayoutName GetKeyboardLayoutNameA +#endif + + WINUSERAPI HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID,UINT Flags); + WINUSERAPI HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID,UINT Flags); + WINUSERAPI HKL WINAPI ActivateKeyboardLayout(HKL hkl,UINT Flags); + WINUSERAPI int WINAPI ToUnicodeEx(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags,HKL dwhkl); + WINUSERAPI WINBOOL WINAPI UnloadKeyboardLayout(HKL hkl); + WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameA(LPSTR pwszKLID); + WINUSERAPI WINBOOL WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID); + WINUSERAPI int WINAPI GetKeyboardLayoutList(int nBuff,HKL *lpList); + WINUSERAPI HKL WINAPI GetKeyboardLayout(DWORD idThread); + + typedef struct tagMOUSEMOVEPOINT { + int x; + int y; + DWORD time; + ULONG_PTR dwExtraInfo; + } MOUSEMOVEPOINT,*PMOUSEMOVEPOINT,*LPMOUSEMOVEPOINT; + +#define GMMP_USE_DISPLAY_POINTS 1 +#define GMMP_USE_HIGH_RESOLUTION_POINTS 2 + + WINUSERAPI int WINAPI GetMouseMovePointsEx(UINT cbSize,LPMOUSEMOVEPOINT lppt,LPMOUSEMOVEPOINT lpptBuf,int nBufPoints,DWORD resolution); + +#ifndef NODESKTOP + +#define DESKTOP_READOBJECTS 0x0001L +#define DESKTOP_CREATEWINDOW 0x0002L +#define DESKTOP_CREATEMENU 0x0004L +#define DESKTOP_HOOKCONTROL 0x0008L +#define DESKTOP_JOURNALRECORD 0x0010L +#define DESKTOP_JOURNALPLAYBACK 0x0020L +#define DESKTOP_ENUMERATE 0x0040L +#define DESKTOP_WRITEOBJECTS 0x0080L +#define DESKTOP_SWITCHDESKTOP 0x0100L + +#define DF_ALLOWOTHERACCOUNTHOOK 0x0001L + +#ifdef _WINGDI_ +#ifndef NOGDI +#ifdef UNICODE +#define CreateDesktop CreateDesktopW +#else +#define CreateDesktop CreateDesktopA +#endif + + WINUSERAPI HDESK WINAPI CreateDesktopA(LPCSTR lpszDesktop,LPCSTR lpszDevice,LPDEVMODEA pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); + WINUSERAPI HDESK WINAPI CreateDesktopW(LPCWSTR lpszDesktop,LPCWSTR lpszDevice,LPDEVMODEW pDevmode,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); +#endif +#endif + +#ifdef UNICODE +#define OpenDesktop OpenDesktopW +#define EnumDesktops EnumDesktopsW +#else +#define OpenDesktop OpenDesktopA +#define EnumDesktops EnumDesktopsA +#endif + + WINUSERAPI HDESK WINAPI OpenDesktopA(LPCSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI HDESK WINAPI OpenDesktopW(LPCWSTR lpszDesktop,DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI HDESK WINAPI OpenInputDesktop(DWORD dwFlags,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI WINBOOL WINAPI EnumDesktopsA(HWINSTA hwinsta,DESKTOPENUMPROCA lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumDesktopsW(HWINSTA hwinsta,DESKTOPENUMPROCW lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumDesktopWindows(HDESK hDesktop,WNDENUMPROC lpfn,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI SwitchDesktop(HDESK hDesktop); + WINUSERAPI WINBOOL WINAPI SetThreadDesktop(HDESK hDesktop); + WINUSERAPI WINBOOL WINAPI CloseDesktop(HDESK hDesktop); + WINUSERAPI HDESK WINAPI GetThreadDesktop(DWORD dwThreadId); +#endif + +#ifndef NOWINDOWSTATION +#define WINSTA_ENUMDESKTOPS 0x0001L +#define WINSTA_READATTRIBUTES 0x0002L +#define WINSTA_ACCESSCLIPBOARD 0x0004L +#define WINSTA_CREATEDESKTOP 0x0008L +#define WINSTA_WRITEATTRIBUTES 0x0010L +#define WINSTA_ACCESSGLOBALATOMS 0x0020L +#define WINSTA_EXITWINDOWS 0x0040L +#define WINSTA_ENUMERATE 0x0100L +#define WINSTA_READSCREEN 0x0200L +#define WINSTA_ALL_ACCESS (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN) + +#define CWF_CREATE_ONLY 0x0001L + +#define WSF_VISIBLE 0x0001L + +#ifdef UNICODE +#define CreateWindowStation CreateWindowStationW +#define OpenWindowStation OpenWindowStationW +#define EnumWindowStations EnumWindowStationsW +#else +#define CreateWindowStation CreateWindowStationA +#define OpenWindowStation OpenWindowStationA +#define EnumWindowStations EnumWindowStationsA +#endif + + WINUSERAPI HWINSTA WINAPI CreateWindowStationA(LPCSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); + WINUSERAPI HWINSTA WINAPI CreateWindowStationW(LPCWSTR lpwinsta,DWORD dwFlags,ACCESS_MASK dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa); + WINUSERAPI HWINSTA WINAPI OpenWindowStationA(LPCSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI HWINSTA WINAPI OpenWindowStationW(LPCWSTR lpszWinSta,WINBOOL fInherit,ACCESS_MASK dwDesiredAccess); + WINUSERAPI WINBOOL WINAPI EnumWindowStationsA(WINSTAENUMPROCA lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumWindowStationsW(WINSTAENUMPROCW lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI CloseWindowStation(HWINSTA hWinSta); + WINUSERAPI WINBOOL WINAPI SetProcessWindowStation(HWINSTA hWinSta); + WINUSERAPI HWINSTA WINAPI GetProcessWindowStation(VOID); +#endif + +#ifndef NOSECURITY + WINUSERAPI WINBOOL WINAPI SetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID); + WINUSERAPI WINBOOL WINAPI GetUserObjectSecurity(HANDLE hObj,PSECURITY_INFORMATION pSIRequested,PSECURITY_DESCRIPTOR pSID,DWORD nLength,LPDWORD lpnLengthNeeded); + +#define UOI_FLAGS 1 +#define UOI_NAME 2 +#define UOI_TYPE 3 +#define UOI_USER_SID 4 + + typedef struct tagUSEROBJECTFLAGS { + WINBOOL fInherit; + WINBOOL fReserved; + DWORD dwFlags; + } USEROBJECTFLAGS,*PUSEROBJECTFLAGS; + +#ifdef UNICODE +#define GetUserObjectInformation GetUserObjectInformationW +#define SetUserObjectInformation SetUserObjectInformationW +#else +#define GetUserObjectInformation GetUserObjectInformationA +#define SetUserObjectInformation SetUserObjectInformationA +#endif + + WINUSERAPI WINBOOL WINAPI GetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); + WINUSERAPI WINBOOL WINAPI GetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength,LPDWORD lpnLengthNeeded); + WINUSERAPI WINBOOL WINAPI SetUserObjectInformationA(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); + WINUSERAPI WINBOOL WINAPI SetUserObjectInformationW(HANDLE hObj,int nIndex,PVOID pvInfo,DWORD nLength); +#endif + + typedef struct tagWNDCLASSEXA { + UINT cbSize; + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName; + LPCSTR lpszClassName; + HICON hIconSm; + } WNDCLASSEXA,*PWNDCLASSEXA,*NPWNDCLASSEXA,*LPWNDCLASSEXA; + + typedef struct tagWNDCLASSEXW { + UINT cbSize; + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCWSTR lpszMenuName; + LPCWSTR lpszClassName; + + HICON hIconSm; + } WNDCLASSEXW,*PWNDCLASSEXW,*NPWNDCLASSEXW,*LPWNDCLASSEXW; + +#ifdef UNICODE + typedef WNDCLASSEXW WNDCLASSEX; + typedef PWNDCLASSEXW PWNDCLASSEX; + typedef NPWNDCLASSEXW NPWNDCLASSEX; + typedef LPWNDCLASSEXW LPWNDCLASSEX; +#else + typedef WNDCLASSEXA WNDCLASSEX; + typedef PWNDCLASSEXA PWNDCLASSEX; + typedef NPWNDCLASSEXA NPWNDCLASSEX; + typedef LPWNDCLASSEXA LPWNDCLASSEX; +#endif + + typedef struct tagWNDCLASSA { + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCSTR lpszMenuName; + LPCSTR lpszClassName; + } WNDCLASSA,*PWNDCLASSA,*NPWNDCLASSA,*LPWNDCLASSA; + + typedef struct tagWNDCLASSW { + UINT style; + WNDPROC lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + HINSTANCE hInstance; + HICON hIcon; + HCURSOR hCursor; + HBRUSH hbrBackground; + LPCWSTR lpszMenuName; + LPCWSTR lpszClassName; + } WNDCLASSW,*PWNDCLASSW,*NPWNDCLASSW,*LPWNDCLASSW; + +#ifdef UNICODE + typedef WNDCLASSW WNDCLASS; + typedef PWNDCLASSW PWNDCLASS; + typedef NPWNDCLASSW NPWNDCLASS; + typedef LPWNDCLASSW LPWNDCLASS; +#else + typedef WNDCLASSA WNDCLASS; + typedef PWNDCLASSA PWNDCLASS; + typedef NPWNDCLASSA NPWNDCLASS; + typedef LPWNDCLASSA LPWNDCLASS; +#endif + + WINUSERAPI WINBOOL WINAPI IsHungAppWindow(HWND hwnd); + WINUSERAPI VOID WINAPI DisableProcessWindowsGhosting(VOID); + +#ifndef NOMSG + typedef struct tagMSG { + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + DWORD time; + POINT pt; + } MSG,*PMSG,*NPMSG,*LPMSG; + +#define POINTSTOPOINT(pt,pts) { (pt).x = (LONG)(SHORT)LOWORD(*(LONG*)&pts); (pt).y = (LONG)(SHORT)HIWORD(*(LONG*)&pts); } + +#define POINTTOPOINTS(pt) (MAKELONG((short)((pt).x),(short)((pt).y))) +#define MAKEWPARAM(l,h) ((WPARAM)(DWORD)MAKELONG(l,h)) +#define MAKELPARAM(l,h) ((LPARAM)(DWORD)MAKELONG(l,h)) +#define MAKELRESULT(l,h) ((LRESULT)(DWORD)MAKELONG(l,h)) +#endif + +#ifndef NOWINOFFSETS +#define GWL_WNDPROC (-4) +#define GWL_HINSTANCE (-6) +#define GWL_HWNDPARENT (-8) +#define GWL_STYLE (-16) +#define GWL_EXSTYLE (-20) +#define GWL_USERDATA (-21) +#define GWL_ID (-12) + +#ifdef _WIN64 +#undef GWL_WNDPROC +#undef GWL_HINSTANCE +#undef GWL_HWNDPARENT +#undef GWL_USERDATA +#endif + +#define GWLP_WNDPROC (-4) +#define GWLP_HINSTANCE (-6) +#define GWLP_HWNDPARENT (-8) +#define GWLP_USERDATA (-21) +#define GWLP_ID (-12) + +#define GCL_MENUNAME (-8) +#define GCL_HBRBACKGROUND (-10) +#define GCL_HCURSOR (-12) +#define GCL_HICON (-14) +#define GCL_HMODULE (-16) +#define GCL_CBWNDEXTRA (-18) +#define GCL_CBCLSEXTRA (-20) +#define GCL_WNDPROC (-24) +#define GCL_STYLE (-26) +#define GCW_ATOM (-32) +#define GCL_HICONSM (-34) + +#ifdef _WIN64 + +#undef GCL_MENUNAME +#undef GCL_HBRBACKGROUND +#undef GCL_HCURSOR +#undef GCL_HICON +#undef GCL_HMODULE +#undef GCL_WNDPROC +#undef GCL_HICONSM +#endif + +#define GCLP_MENUNAME (-8) +#define GCLP_HBRBACKGROUND (-10) +#define GCLP_HCURSOR (-12) +#define GCLP_HICON (-14) +#define GCLP_HMODULE (-16) +#define GCLP_WNDPROC (-24) +#define GCLP_HICONSM (-34) +#endif + +#ifndef NOWINMESSAGES + +#define WM_NULL 0x0000 +#define WM_CREATE 0x0001 +#define WM_DESTROY 0x0002 +#define WM_MOVE 0x0003 +#define WM_SIZE 0x0005 + +#define WM_ACTIVATE 0x0006 + +#define WA_INACTIVE 0 +#define WA_ACTIVE 1 +#define WA_CLICKACTIVE 2 + +#define WM_SETFOCUS 0x0007 +#define WM_KILLFOCUS 0x0008 +#define WM_ENABLE 0x000A +#define WM_SETREDRAW 0x000B +#define WM_SETTEXT 0x000C +#define WM_GETTEXT 0x000D +#define WM_GETTEXTLENGTH 0x000E +#define WM_PAINT 0x000F +#define WM_CLOSE 0x0010 +#ifndef _WIN32_WCE +#define WM_QUERYENDSESSION 0x0011 +#define WM_QUERYOPEN 0x0013 +#define WM_ENDSESSION 0x0016 +#endif +#define WM_QUIT 0x0012 +#define WM_ERASEBKGND 0x0014 +#define WM_SYSCOLORCHANGE 0x0015 +#define WM_SHOWWINDOW 0x0018 +#define WM_WININICHANGE 0x001A +#define WM_SETTINGCHANGE WM_WININICHANGE +#define WM_DEVMODECHANGE 0x001B +#define WM_ACTIVATEAPP 0x001C +#define WM_FONTCHANGE 0x001D +#define WM_TIMECHANGE 0x001E +#define WM_CANCELMODE 0x001F +#define WM_SETCURSOR 0x0020 +#define WM_MOUSEACTIVATE 0x0021 +#define WM_CHILDACTIVATE 0x0022 +#define WM_QUEUESYNC 0x0023 + +#define WM_GETMINMAXINFO 0x0024 + + typedef struct tagMINMAXINFO { + POINT ptReserved; + POINT ptMaxSize; + POINT ptMaxPosition; + POINT ptMinTrackSize; + POINT ptMaxTrackSize; + } MINMAXINFO,*PMINMAXINFO,*LPMINMAXINFO; + +#define WM_PAINTICON 0x0026 +#define WM_ICONERASEBKGND 0x0027 +#define WM_NEXTDLGCTL 0x0028 +#define WM_SPOOLERSTATUS 0x002A +#define WM_DRAWITEM 0x002B +#define WM_MEASUREITEM 0x002C +#define WM_DELETEITEM 0x002D +#define WM_VKEYTOITEM 0x002E +#define WM_CHARTOITEM 0x002F +#define WM_SETFONT 0x0030 +#define WM_GETFONT 0x0031 +#define WM_SETHOTKEY 0x0032 +#define WM_GETHOTKEY 0x0033 +#define WM_QUERYDRAGICON 0x0037 +#define WM_COMPAREITEM 0x0039 +#ifndef _WIN32_WCE +#define WM_GETOBJECT 0x003D +#endif +#define WM_COMPACTING 0x0041 +#define WM_COMMNOTIFY 0x0044 +#define WM_WINDOWPOSCHANGING 0x0046 +#define WM_WINDOWPOSCHANGED 0x0047 + +#define WM_POWER 0x0048 + +#define PWR_OK 1 +#define PWR_FAIL (-1) +#define PWR_SUSPENDREQUEST 1 +#define PWR_SUSPENDRESUME 2 +#define PWR_CRITICALRESUME 3 + +#define WM_COPYDATA 0x004A +#define WM_CANCELJOURNAL 0x004B + + typedef struct tagCOPYDATASTRUCT { + ULONG_PTR dwData; + DWORD cbData; + PVOID lpData; + } COPYDATASTRUCT,*PCOPYDATASTRUCT; + + typedef struct tagMDINEXTMENU { + HMENU hmenuIn; + HMENU hmenuNext; + HWND hwndNext; + } MDINEXTMENU,*PMDINEXTMENU,*LPMDINEXTMENU; + +#define WM_NOTIFY 0x004E +#define WM_INPUTLANGCHANGEREQUEST 0x0050 +#define WM_INPUTLANGCHANGE 0x0051 +#define WM_TCARD 0x0052 +#define WM_HELP 0x0053 +#define WM_USERCHANGED 0x0054 +#define WM_NOTIFYFORMAT 0x0055 + +#define NFR_ANSI 1 +#define NFR_UNICODE 2 +#define NF_QUERY 3 +#define NF_REQUERY 4 + +#define WM_CONTEXTMENU 0x007B +#define WM_STYLECHANGING 0x007C +#define WM_STYLECHANGED 0x007D +#define WM_DISPLAYCHANGE 0x007E +#define WM_GETICON 0x007F +#define WM_SETICON 0x0080 + +#define WM_NCCREATE 0x0081 +#define WM_NCDESTROY 0x0082 +#define WM_NCCALCSIZE 0x0083 +#define WM_NCHITTEST 0x0084 +#define WM_NCPAINT 0x0085 +#define WM_NCACTIVATE 0x0086 +#define WM_GETDLGCODE 0x0087 +#ifndef _WIN32_WCE +#define WM_SYNCPAINT 0x0088 +#endif +#define WM_NCMOUSEMOVE 0x00A0 +#define WM_NCLBUTTONDOWN 0x00A1 +#define WM_NCLBUTTONUP 0x00A2 +#define WM_NCLBUTTONDBLCLK 0x00A3 +#define WM_NCRBUTTONDOWN 0x00A4 +#define WM_NCRBUTTONUP 0x00A5 +#define WM_NCRBUTTONDBLCLK 0x00A6 +#define WM_NCMBUTTONDOWN 0x00A7 +#define WM_NCMBUTTONUP 0x00A8 +#define WM_NCMBUTTONDBLCLK 0x00A9 + +#define WM_NCXBUTTONDOWN 0x00AB +#define WM_NCXBUTTONUP 0x00AC +#define WM_NCXBUTTONDBLCLK 0x00AD +#define WM_INPUT 0x00FF +#define WM_KEYFIRST 0x0100 +#define WM_KEYDOWN 0x0100 +#define WM_KEYUP 0x0101 +#define WM_CHAR 0x0102 +#define WM_DEADCHAR 0x0103 +#define WM_SYSKEYDOWN 0x0104 +#define WM_SYSKEYUP 0x0105 +#define WM_SYSCHAR 0x0106 +#define WM_SYSDEADCHAR 0x0107 +#define WM_UNICHAR 0x0109 +#define WM_KEYLAST 0x0109 +#define UNICODE_NOCHAR 0xFFFF +#define WM_IME_STARTCOMPOSITION 0x010D +#define WM_IME_ENDCOMPOSITION 0x010E +#define WM_IME_COMPOSITION 0x010F +#define WM_IME_KEYLAST 0x010F +#define WM_INITDIALOG 0x0110 +#define WM_COMMAND 0x0111 +#define WM_SYSCOMMAND 0x0112 +#define WM_TIMER 0x0113 +#define WM_HSCROLL 0x0114 +#define WM_VSCROLL 0x0115 +#define WM_INITMENU 0x0116 +#define WM_INITMENUPOPUP 0x0117 +#define WM_MENUSELECT 0x011F +#define WM_MENUCHAR 0x0120 +#define WM_ENTERIDLE 0x0121 +#ifndef _WIN32_WCE +#define WM_MENURBUTTONUP 0x0122 +#define WM_MENUDRAG 0x0123 +#define WM_MENUGETOBJECT 0x0124 +#define WM_UNINITMENUPOPUP 0x0125 +#define WM_MENUCOMMAND 0x0126 + +#ifndef _WIN32_WCE +#define WM_CHANGEUISTATE 0x0127 +#define WM_UPDATEUISTATE 0x0128 +#define WM_QUERYUISTATE 0x0129 + +#define UIS_SET 1 +#define UIS_CLEAR 2 +#define UIS_INITIALIZE 3 + +#define UISF_HIDEFOCUS 0x1 +#define UISF_HIDEACCEL 0x2 +#define UISF_ACTIVE 0x4 +#endif +#endif + +#define WM_CTLCOLORMSGBOX 0x0132 +#define WM_CTLCOLOREDIT 0x0133 +#define WM_CTLCOLORLISTBOX 0x0134 +#define WM_CTLCOLORBTN 0x0135 +#define WM_CTLCOLORDLG 0x0136 +#define WM_CTLCOLORSCROLLBAR 0x0137 +#define WM_CTLCOLORSTATIC 0x0138 +#define MN_GETHMENU 0x01E1 + +#define WM_MOUSEFIRST 0x0200 +#define WM_MOUSEMOVE 0x0200 +#define WM_LBUTTONDOWN 0x0201 +#define WM_LBUTTONUP 0x0202 +#define WM_LBUTTONDBLCLK 0x0203 +#define WM_RBUTTONDOWN 0x0204 +#define WM_RBUTTONUP 0x0205 +#define WM_RBUTTONDBLCLK 0x0206 +#define WM_MBUTTONDOWN 0x0207 +#define WM_MBUTTONUP 0x0208 +#define WM_MBUTTONDBLCLK 0x0209 +#define WM_MOUSEWHEEL 0x020A +#define WM_XBUTTONDOWN 0x020B +#define WM_XBUTTONUP 0x020C +#define WM_XBUTTONDBLCLK 0x020D +#define WM_MOUSELAST 0x020D + +#define WHEEL_DELTA 120 +#define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) + +#define WHEEL_PAGESCROLL (UINT_MAX) + +#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam)) +#define GET_NCHITTEST_WPARAM(wParam) ((short)LOWORD(wParam)) +#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) + +#define XBUTTON1 0x0001 +#define XBUTTON2 0x0002 + +#define WM_PARENTNOTIFY 0x0210 +#define WM_ENTERMENULOOP 0x0211 +#define WM_EXITMENULOOP 0x0212 + +#define WM_NEXTMENU 0x0213 +#define WM_SIZING 0x0214 +#define WM_CAPTURECHANGED 0x0215 +#define WM_MOVING 0x0216 + +#define WM_POWERBROADCAST 0x0218 + +#ifndef _WIN32_WCE +#define PBT_APMQUERYSUSPEND 0x0000 +#define PBT_APMQUERYSTANDBY 0x0001 + +#define PBT_APMQUERYSUSPENDFAILED 0x0002 +#define PBT_APMQUERYSTANDBYFAILED 0x0003 + +#define PBT_APMSUSPEND 0x0004 +#define PBT_APMSTANDBY 0x0005 + +#define PBT_APMRESUMECRITICAL 0x0006 +#define PBT_APMRESUMESUSPEND 0x0007 +#define PBT_APMRESUMESTANDBY 0x0008 + +#define PBTF_APMRESUMEFROMFAILURE 0x00000001 + +#define PBT_APMBATTERYLOW 0x0009 +#define PBT_APMPOWERSTATUSCHANGE 0x000A + +#define PBT_APMOEMEVENT 0x000B +#define PBT_APMRESUMEAUTOMATIC 0x0012 +#endif + +#define WM_DEVICECHANGE 0x0219 + +#define WM_MDICREATE 0x0220 +#define WM_MDIDESTROY 0x0221 +#define WM_MDIACTIVATE 0x0222 +#define WM_MDIRESTORE 0x0223 +#define WM_MDINEXT 0x0224 +#define WM_MDIMAXIMIZE 0x0225 +#define WM_MDITILE 0x0226 +#define WM_MDICASCADE 0x0227 +#define WM_MDIICONARRANGE 0x0228 +#define WM_MDIGETACTIVE 0x0229 + +#define WM_MDISETMENU 0x0230 +#define WM_ENTERSIZEMOVE 0x0231 +#define WM_EXITSIZEMOVE 0x0232 +#define WM_DROPFILES 0x0233 +#define WM_MDIREFRESHMENU 0x0234 + +#define WM_IME_SETCONTEXT 0x0281 +#define WM_IME_NOTIFY 0x0282 +#define WM_IME_CONTROL 0x0283 +#define WM_IME_COMPOSITIONFULL 0x0284 +#define WM_IME_SELECT 0x0285 +#define WM_IME_CHAR 0x0286 +#define WM_IME_REQUEST 0x0288 +#define WM_IME_KEYDOWN 0x0290 +#define WM_IME_KEYUP 0x0291 + +#define WM_MOUSEHOVER 0x02A1 +#define WM_MOUSELEAVE 0x02A3 +#define WM_NCMOUSEHOVER 0x02A0 +#define WM_NCMOUSELEAVE 0x02A2 +#define WM_WTSSESSION_CHANGE 0x02B1 +#define WM_TABLET_FIRST 0x02c0 +#define WM_TABLET_LAST 0x02df +#define WM_CUT 0x0300 +#define WM_COPY 0x0301 +#define WM_PASTE 0x0302 +#define WM_CLEAR 0x0303 +#define WM_UNDO 0x0304 +#define WM_RENDERFORMAT 0x0305 +#define WM_RENDERALLFORMATS 0x0306 +#define WM_DESTROYCLIPBOARD 0x0307 +#define WM_DRAWCLIPBOARD 0x0308 +#define WM_PAINTCLIPBOARD 0x0309 +#define WM_VSCROLLCLIPBOARD 0x030A +#define WM_SIZECLIPBOARD 0x030B +#define WM_ASKCBFORMATNAME 0x030C +#define WM_CHANGECBCHAIN 0x030D +#define WM_HSCROLLCLIPBOARD 0x030E +#define WM_QUERYNEWPALETTE 0x030F +#define WM_PALETTEISCHANGING 0x0310 +#define WM_PALETTECHANGED 0x0311 +#define WM_HOTKEY 0x0312 +#define WM_PRINT 0x0317 +#define WM_PRINTCLIENT 0x0318 +#define WM_APPCOMMAND 0x0319 +#define WM_THEMECHANGED 0x031A +#define WM_HANDHELDFIRST 0x0358 +#define WM_HANDHELDLAST 0x035F +#define WM_AFXFIRST 0x0360 +#define WM_AFXLAST 0x037F +#define WM_PENWINFIRST 0x0380 +#define WM_PENWINLAST 0x038F +#define WM_APP 0x8000 +#define WM_USER 0x0400 + +#define WMSZ_LEFT 1 +#define WMSZ_RIGHT 2 +#define WMSZ_TOP 3 +#define WMSZ_TOPLEFT 4 +#define WMSZ_TOPRIGHT 5 +#define WMSZ_BOTTOM 6 +#define WMSZ_BOTTOMLEFT 7 +#define WMSZ_BOTTOMRIGHT 8 + +#ifndef NONCMESSAGES + +#define HTERROR (-2) +#define HTTRANSPARENT (-1) +#define HTNOWHERE 0 +#define HTCLIENT 1 +#define HTCAPTION 2 +#define HTSYSMENU 3 +#define HTGROWBOX 4 +#define HTSIZE HTGROWBOX +#define HTMENU 5 +#define HTHSCROLL 6 +#define HTVSCROLL 7 +#define HTMINBUTTON 8 +#define HTMAXBUTTON 9 +#define HTLEFT 10 +#define HTRIGHT 11 +#define HTTOP 12 +#define HTTOPLEFT 13 +#define HTTOPRIGHT 14 +#define HTBOTTOM 15 +#define HTBOTTOMLEFT 16 +#define HTBOTTOMRIGHT 17 +#define HTBORDER 18 +#define HTREDUCE HTMINBUTTON +#define HTZOOM HTMAXBUTTON +#define HTSIZEFIRST HTLEFT +#define HTSIZELAST HTBOTTOMRIGHT +#define HTOBJECT 19 +#define HTCLOSE 20 +#define HTHELP 21 + +#define SMTO_NORMAL 0x0000 +#define SMTO_BLOCK 0x0001 +#define SMTO_ABORTIFHUNG 0x0002 +#define SMTO_NOTIMEOUTIFNOTHUNG 0x0008 +#endif + +#define MA_ACTIVATE 1 +#define MA_ACTIVATEANDEAT 2 +#define MA_NOACTIVATE 3 +#define MA_NOACTIVATEANDEAT 4 + +#define ICON_SMALL 0 +#define ICON_BIG 1 +#define ICON_SMALL2 2 + +#ifdef UNICODE +#define RegisterWindowMessage RegisterWindowMessageW +#else +#define RegisterWindowMessage RegisterWindowMessageA +#endif + + WINUSERAPI UINT WINAPI RegisterWindowMessageA(LPCSTR lpString); + WINUSERAPI UINT WINAPI RegisterWindowMessageW(LPCWSTR lpString); + +#define SIZE_RESTORED 0 +#define SIZE_MINIMIZED 1 +#define SIZE_MAXIMIZED 2 +#define SIZE_MAXSHOW 3 +#define SIZE_MAXHIDE 4 + +#define SIZENORMAL SIZE_RESTORED +#define SIZEICONIC SIZE_MINIMIZED +#define SIZEFULLSCREEN SIZE_MAXIMIZED +#define SIZEZOOMSHOW SIZE_MAXSHOW +#define SIZEZOOMHIDE SIZE_MAXHIDE + + typedef struct tagWINDOWPOS { + HWND hwnd; + HWND hwndInsertAfter; + int x; + int y; + int cx; + int cy; + UINT flags; + } WINDOWPOS,*LPWINDOWPOS,*PWINDOWPOS; + + typedef struct tagNCCALCSIZE_PARAMS { + RECT rgrc[3]; + PWINDOWPOS lppos; + } NCCALCSIZE_PARAMS,*LPNCCALCSIZE_PARAMS; + +#define WVR_ALIGNTOP 0x0010 +#define WVR_ALIGNLEFT 0x0020 +#define WVR_ALIGNBOTTOM 0x0040 +#define WVR_ALIGNRIGHT 0x0080 +#define WVR_HREDRAW 0x0100 +#define WVR_VREDRAW 0x0200 +#define WVR_REDRAW (WVR_HREDRAW | WVR_VREDRAW) +#define WVR_VALIDRECTS 0x0400 + +#ifndef NOKEYSTATES + +#define MK_LBUTTON 0x0001 +#define MK_RBUTTON 0x0002 +#define MK_SHIFT 0x0004 +#define MK_CONTROL 0x0008 +#define MK_MBUTTON 0x0010 +#define MK_XBUTTON1 0x0020 +#define MK_XBUTTON2 0x0040 +#endif + +#ifndef NOTRACKMOUSEEVENT +#define TME_HOVER 0x00000001 +#define TME_LEAVE 0x00000002 +#define TME_NONCLIENT 0x00000010 +#define TME_QUERY 0x40000000 +#define TME_CANCEL 0x80000000 + +#define HOVER_DEFAULT 0xFFFFFFFF +#endif + + typedef struct tagTRACKMOUSEEVENT { + DWORD cbSize; + DWORD dwFlags; + HWND hwndTrack; + DWORD dwHoverTime; + } TRACKMOUSEEVENT,*LPTRACKMOUSEEVENT; + + WINUSERAPI WINBOOL WINAPI TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack); +#endif + +#ifndef NOWINSTYLES + +#define WS_OVERLAPPED 0x00000000L +#define WS_POPUP 0x80000000L +#define WS_CHILD 0x40000000L +#define WS_MINIMIZE 0x20000000L +#define WS_VISIBLE 0x10000000L +#define WS_DISABLED 0x08000000L +#define WS_CLIPSIBLINGS 0x04000000L +#define WS_CLIPCHILDREN 0x02000000L +#define WS_MAXIMIZE 0x01000000L +#define WS_CAPTION 0x00C00000L +#define WS_BORDER 0x00800000L +#define WS_DLGFRAME 0x00400000L +#define WS_VSCROLL 0x00200000L +#define WS_HSCROLL 0x00100000L +#define WS_SYSMENU 0x00080000L +#define WS_THICKFRAME 0x00040000L +#define WS_GROUP 0x00020000L +#define WS_TABSTOP 0x00010000L +#define WS_MINIMIZEBOX 0x00020000L +#define WS_MAXIMIZEBOX 0x00010000L +#define WS_TILED WS_OVERLAPPED +#define WS_ICONIC WS_MINIMIZE +#define WS_SIZEBOX WS_THICKFRAME +#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW +#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) +#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU) +#define WS_CHILDWINDOW (WS_CHILD) + +#define WS_EX_DLGMODALFRAME 0x00000001L +#define WS_EX_NOPARENTNOTIFY 0x00000004L +#define WS_EX_TOPMOST 0x00000008L +#define WS_EX_ACCEPTFILES 0x00000010L +#define WS_EX_TRANSPARENT 0x00000020L +#define WS_EX_MDICHILD 0x00000040L +#define WS_EX_TOOLWINDOW 0x00000080L +#define WS_EX_WINDOWEDGE 0x00000100L +#define WS_EX_CLIENTEDGE 0x00000200L +#define WS_EX_CONTEXTHELP 0x00000400L +#define WS_EX_RIGHT 0x00001000L +#define WS_EX_LEFT 0x00000000L +#define WS_EX_RTLREADING 0x00002000L +#define WS_EX_LTRREADING 0x00000000L +#define WS_EX_LEFTSCROLLBAR 0x00004000L +#define WS_EX_RIGHTSCROLLBAR 0x00000000L +#define WS_EX_CONTROLPARENT 0x00010000L +#define WS_EX_STATICEDGE 0x00020000L +#define WS_EX_APPWINDOW 0x00040000L +#define WS_EX_OVERLAPPEDWINDOW (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE) +#define WS_EX_PALETTEWINDOW (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST) +#define WS_EX_LAYERED 0x00080000 +#define WS_EX_NOINHERITLAYOUT 0x00100000L +#define WS_EX_LAYOUTRTL 0x00400000L +#define WS_EX_COMPOSITED 0x02000000L +#define WS_EX_NOACTIVATE 0x08000000L + +#define CS_VREDRAW 0x0001 +#define CS_HREDRAW 0x0002 +#define CS_DBLCLKS 0x0008 +#define CS_OWNDC 0x0020 +#define CS_CLASSDC 0x0040 +#define CS_PARENTDC 0x0080 +#define CS_NOCLOSE 0x0200 +#define CS_SAVEBITS 0x0800 +#define CS_BYTEALIGNCLIENT 0x1000 +#define CS_BYTEALIGNWINDOW 0x2000 +#define CS_GLOBALCLASS 0x4000 +#define CS_IME 0x00010000 +#define CS_DROPSHADOW 0x00020000 +#endif + +#define PRF_CHECKVISIBLE 0x00000001L +#define PRF_NONCLIENT 0x00000002L +#define PRF_CLIENT 0x00000004L +#define PRF_ERASEBKGND 0x00000008L +#define PRF_CHILDREN 0x00000010L +#define PRF_OWNED 0x00000020L + +#define BDR_RAISEDOUTER 0x0001 +#define BDR_SUNKENOUTER 0x0002 +#define BDR_RAISEDINNER 0x0004 +#define BDR_SUNKENINNER 0x0008 + +#define BDR_OUTER (BDR_RAISEDOUTER | BDR_SUNKENOUTER) +#define BDR_INNER (BDR_RAISEDINNER | BDR_SUNKENINNER) +#define BDR_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) +#define BDR_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) + +#define EDGE_RAISED (BDR_RAISEDOUTER | BDR_RAISEDINNER) +#define EDGE_SUNKEN (BDR_SUNKENOUTER | BDR_SUNKENINNER) +#define EDGE_ETCHED (BDR_SUNKENOUTER | BDR_RAISEDINNER) +#define EDGE_BUMP (BDR_RAISEDOUTER | BDR_SUNKENINNER) + +#define BF_LEFT 0x0001 +#define BF_TOP 0x0002 +#define BF_RIGHT 0x0004 +#define BF_BOTTOM 0x0008 + +#define BF_TOPLEFT (BF_TOP | BF_LEFT) +#define BF_TOPRIGHT (BF_TOP | BF_RIGHT) +#define BF_BOTTOMLEFT (BF_BOTTOM | BF_LEFT) +#define BF_BOTTOMRIGHT (BF_BOTTOM | BF_RIGHT) +#define BF_RECT (BF_LEFT | BF_TOP | BF_RIGHT | BF_BOTTOM) + +#define BF_DIAGONAL 0x0010 + +#define BF_DIAGONAL_ENDTOPRIGHT (BF_DIAGONAL | BF_TOP | BF_RIGHT) +#define BF_DIAGONAL_ENDTOPLEFT (BF_DIAGONAL | BF_TOP | BF_LEFT) +#define BF_DIAGONAL_ENDBOTTOMLEFT (BF_DIAGONAL | BF_BOTTOM | BF_LEFT) +#define BF_DIAGONAL_ENDBOTTOMRIGHT (BF_DIAGONAL | BF_BOTTOM | BF_RIGHT) + +#define BF_MIDDLE 0x0800 +#define BF_SOFT 0x1000 +#define BF_ADJUST 0x2000 +#define BF_FLAT 0x4000 +#define BF_MONO 0x8000 + + WINUSERAPI WINBOOL WINAPI DrawEdge(HDC hdc,LPRECT qrc,UINT edge,UINT grfFlags); + +#define DFC_CAPTION 1 +#define DFC_MENU 2 +#define DFC_SCROLL 3 +#define DFC_BUTTON 4 +#define DFC_POPUPMENU 5 + +#define DFCS_CAPTIONCLOSE 0x0000 +#define DFCS_CAPTIONMIN 0x0001 +#define DFCS_CAPTIONMAX 0x0002 +#define DFCS_CAPTIONRESTORE 0x0003 +#define DFCS_CAPTIONHELP 0x0004 + +#define DFCS_MENUARROW 0x0000 +#define DFCS_MENUCHECK 0x0001 +#define DFCS_MENUBULLET 0x0002 +#define DFCS_MENUARROWRIGHT 0x0004 +#define DFCS_SCROLLUP 0x0000 +#define DFCS_SCROLLDOWN 0x0001 +#define DFCS_SCROLLLEFT 0x0002 +#define DFCS_SCROLLRIGHT 0x0003 +#define DFCS_SCROLLCOMBOBOX 0x0005 +#define DFCS_SCROLLSIZEGRIP 0x0008 +#define DFCS_SCROLLSIZEGRIPRIGHT 0x0010 + +#define DFCS_BUTTONCHECK 0x0000 +#define DFCS_BUTTONRADIOIMAGE 0x0001 +#define DFCS_BUTTONRADIOMASK 0x0002 +#define DFCS_BUTTONRADIO 0x0004 +#define DFCS_BUTTON3STATE 0x0008 +#define DFCS_BUTTONPUSH 0x0010 + +#define DFCS_INACTIVE 0x0100 +#define DFCS_PUSHED 0x0200 +#define DFCS_CHECKED 0x0400 + +#define DFCS_TRANSPARENT 0x0800 +#define DFCS_HOT 0x1000 + +#define DFCS_ADJUSTRECT 0x2000 +#define DFCS_FLAT 0x4000 +#define DFCS_MONO 0x8000 + + WINUSERAPI WINBOOL WINAPI DrawFrameControl(HDC,LPRECT,UINT,UINT); + +#define DC_ACTIVE 0x0001 +#define DC_SMALLCAP 0x0002 +#define DC_ICON 0x0004 +#define DC_TEXT 0x0008 +#define DC_INBUTTON 0x0010 +#define DC_GRADIENT 0x0020 +#define DC_BUTTONS 0x1000 + + WINUSERAPI WINBOOL WINAPI DrawCaption(HWND hwnd,HDC hdc,CONST RECT *lprect,UINT flags); + +#define IDANI_OPEN 1 +#define IDANI_CAPTION 3 + + WINUSERAPI WINBOOL WINAPI DrawAnimatedRects(HWND hwnd,int idAni,CONST RECT *lprcFrom,CONST RECT *lprcTo); + +#ifndef NOCLIPBOARD + +#define CF_TEXT 1 +#define CF_BITMAP 2 +#define CF_METAFILEPICT 3 +#define CF_SYLK 4 +#define CF_DIF 5 +#define CF_TIFF 6 +#define CF_OEMTEXT 7 +#define CF_DIB 8 +#define CF_PALETTE 9 +#define CF_PENDATA 10 +#define CF_RIFF 11 +#define CF_WAVE 12 +#define CF_UNICODETEXT 13 +#define CF_ENHMETAFILE 14 +#define CF_HDROP 15 +#define CF_LOCALE 16 +#define CF_DIBV5 17 +#define CF_MAX 18 + +#define CF_OWNERDISPLAY 0x0080 +#define CF_DSPTEXT 0x0081 +#define CF_DSPBITMAP 0x0082 +#define CF_DSPMETAFILEPICT 0x0083 +#define CF_DSPENHMETAFILE 0x008E + +#define CF_PRIVATEFIRST 0x0200 +#define CF_PRIVATELAST 0x02FF + +#define CF_GDIOBJFIRST 0x0300 +#define CF_GDIOBJLAST 0x03FF +#endif + +#define FVIRTKEY TRUE +#define FNOINVERT 0x02 +#define FSHIFT 0x04 +#define FCONTROL 0x08 +#define FALT 0x10 + + typedef struct tagACCEL { + BYTE fVirt; + WORD key; + WORD cmd; + } ACCEL,*LPACCEL; + + typedef struct tagPAINTSTRUCT { + HDC hdc; + WINBOOL fErase; + RECT rcPaint; + WINBOOL fRestore; + WINBOOL fIncUpdate; + BYTE rgbReserved[32]; + } PAINTSTRUCT,*PPAINTSTRUCT,*NPPAINTSTRUCT,*LPPAINTSTRUCT; + + typedef struct tagCREATESTRUCTA { + LPVOID lpCreateParams; + HINSTANCE hInstance; + HMENU hMenu; + HWND hwndParent; + int cy; + int cx; + int y; + int x; + LONG style; + LPCSTR lpszName; + LPCSTR lpszClass; + DWORD dwExStyle; + } CREATESTRUCTA,*LPCREATESTRUCTA; + + typedef struct tagCREATESTRUCTW { + LPVOID lpCreateParams; + HINSTANCE hInstance; + HMENU hMenu; + HWND hwndParent; + int cy; + int cx; + int y; + int x; + LONG style; + LPCWSTR lpszName; + LPCWSTR lpszClass; + DWORD dwExStyle; + } CREATESTRUCTW,*LPCREATESTRUCTW; + +#ifdef UNICODE + typedef CREATESTRUCTW CREATESTRUCT; + typedef LPCREATESTRUCTW LPCREATESTRUCT; +#else + typedef CREATESTRUCTA CREATESTRUCT; + typedef LPCREATESTRUCTA LPCREATESTRUCT; +#endif + + typedef struct tagWINDOWPLACEMENT { + UINT length; + UINT flags; + UINT showCmd; + POINT ptMinPosition; + POINT ptMaxPosition; + RECT rcNormalPosition; + } WINDOWPLACEMENT; + typedef WINDOWPLACEMENT *PWINDOWPLACEMENT,*LPWINDOWPLACEMENT; + +#define WPF_SETMINPOSITION 0x0001 +#define WPF_RESTORETOMAXIMIZED 0x0002 +#define WPF_ASYNCWINDOWPLACEMENT 0x0004 + + typedef struct tagNMHDR { + HWND hwndFrom; + UINT_PTR idFrom; + UINT code; + } NMHDR; + + typedef NMHDR *LPNMHDR; + + typedef struct tagSTYLESTRUCT { + DWORD styleOld; + DWORD styleNew; + } STYLESTRUCT,*LPSTYLESTRUCT; + +#define ODT_MENU 1 +#define ODT_LISTBOX 2 +#define ODT_COMBOBOX 3 +#define ODT_BUTTON 4 +#define ODT_STATIC 5 + +#define ODA_DRAWENTIRE 0x0001 +#define ODA_SELECT 0x0002 +#define ODA_FOCUS 0x0004 + +#define ODS_SELECTED 0x0001 +#define ODS_GRAYED 0x0002 +#define ODS_DISABLED 0x0004 +#define ODS_CHECKED 0x0008 +#define ODS_FOCUS 0x0010 +#define ODS_DEFAULT 0x0020 +#define ODS_COMBOBOXEDIT 0x1000 +#define ODS_HOTLIGHT 0x0040 +#define ODS_INACTIVE 0x0080 +#define ODS_NOACCEL 0x0100 +#define ODS_NOFOCUSRECT 0x0200 + + typedef struct tagMEASUREITEMSTRUCT { + UINT CtlType; + UINT CtlID; + UINT itemID; + UINT itemWidth; + UINT itemHeight; + ULONG_PTR itemData; + } MEASUREITEMSTRUCT,*PMEASUREITEMSTRUCT,*LPMEASUREITEMSTRUCT; + + typedef struct tagDRAWITEMSTRUCT { + UINT CtlType; + UINT CtlID; + UINT itemID; + UINT itemAction; + UINT itemState; + HWND hwndItem; + HDC hDC; + RECT rcItem; + ULONG_PTR itemData; + } DRAWITEMSTRUCT,*PDRAWITEMSTRUCT,*LPDRAWITEMSTRUCT; + + typedef struct tagDELETEITEMSTRUCT { + UINT CtlType; + UINT CtlID; + UINT itemID; + HWND hwndItem; + ULONG_PTR itemData; + } DELETEITEMSTRUCT,*PDELETEITEMSTRUCT,*LPDELETEITEMSTRUCT; + + typedef struct tagCOMPAREITEMSTRUCT { + UINT CtlType; + UINT CtlID; + HWND hwndItem; + UINT itemID1; + ULONG_PTR itemData1; + UINT itemID2; + ULONG_PTR itemData2; + DWORD dwLocaleId; + } COMPAREITEMSTRUCT,*PCOMPAREITEMSTRUCT,*LPCOMPAREITEMSTRUCT; + +#ifndef NOMSG +#ifdef UNICODE +#define GetMessage GetMessageW +#define DispatchMessage DispatchMessageW +#define PeekMessage PeekMessageW +#else +#define GetMessage GetMessageA +#define DispatchMessage DispatchMessageA +#define PeekMessage PeekMessageA +#endif + + WINUSERAPI WINBOOL WINAPI GetMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); + WINUSERAPI WINBOOL WINAPI GetMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); + WINUSERAPI WINBOOL WINAPI TranslateMessage(CONST MSG *lpMsg); + WINUSERAPI LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg); + WINUSERAPI LRESULT WINAPI DispatchMessageW(CONST MSG *lpMsg); + WINUSERAPI WINBOOL WINAPI SetMessageQueue(int cMessagesMax); + WINUSERAPI WINBOOL WINAPI PeekMessageA(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); + WINUSERAPI WINBOOL WINAPI PeekMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); + +#define PM_NOREMOVE 0x0000 +#define PM_REMOVE 0x0001 +#define PM_NOYIELD 0x0002 +#define PM_QS_INPUT (QS_INPUT << 16) +#define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16) +#define PM_QS_PAINT (QS_PAINT << 16) +#define PM_QS_SENDMESSAGE (QS_SENDMESSAGE << 16) +#endif + + WINUSERAPI WINBOOL WINAPI RegisterHotKey(HWND hWnd,int id,UINT fsModifiers,UINT vk); + WINUSERAPI WINBOOL WINAPI UnregisterHotKey(HWND hWnd,int id); + +#define MOD_ALT 0x0001 +#define MOD_CONTROL 0x0002 +#define MOD_SHIFT 0x0004 +#define MOD_WIN 0x0008 + +#define IDHOT_SNAPWINDOW (-1) +#define IDHOT_SNAPDESKTOP (-2) + +#ifdef WIN_INTERNAL +#ifndef LSTRING +#define NOLSTRING +#endif +#ifndef LFILEIO +#define NOLFILEIO +#endif +#endif + +#define ENDSESSION_LOGOFF 0x80000000 + +#define EWX_LOGOFF 0 +#define EWX_SHUTDOWN 0x00000001 +#define EWX_REBOOT 0x00000002 +#define EWX_FORCE 0x00000004 +#define EWX_POWEROFF 0x00000008 +#define EWX_FORCEIFHUNG 0x00000010 + +#define ExitWindows(dwReserved,Code) ExitWindowsEx(EWX_LOGOFF,0xFFFFFFFF) + +#ifdef UNICODE +#define SendMessage SendMessageW +#define SendMessageTimeout SendMessageTimeoutW +#define SendNotifyMessage SendNotifyMessageW +#define SendMessageCallback SendMessageCallbackW +#else +#define SendMessage SendMessageA +#define SendMessageTimeout SendMessageTimeoutA +#define SendNotifyMessage SendNotifyMessageA +#define SendMessageCallback SendMessageCallbackA +#endif + + WINUSERAPI WINBOOL WINAPI ExitWindowsEx(UINT uFlags,DWORD dwReason); + WINUSERAPI WINBOOL WINAPI SwapMouseButton(WINBOOL fSwap); + WINUSERAPI DWORD WINAPI GetMessagePos(VOID); + WINUSERAPI LONG WINAPI GetMessageTime(VOID); + WINUSERAPI LPARAM WINAPI GetMessageExtraInfo(VOID); + WINUSERAPI WINBOOL WINAPI IsWow64Message(VOID); + WINUSERAPI LPARAM WINAPI SetMessageExtraInfo(LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendMessageTimeoutA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); + WINUSERAPI LRESULT WINAPI SendMessageTimeoutW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,UINT fuFlags,UINT uTimeout,PDWORD_PTR lpdwResult); + WINUSERAPI WINBOOL WINAPI SendNotifyMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI SendNotifyMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI SendMessageCallbackA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); + WINUSERAPI WINBOOL WINAPI SendMessageCallbackW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,SENDASYNCPROC lpResultCallBack,ULONG_PTR dwData); + + typedef struct { + UINT cbSize; + HDESK hdesk; + HWND hwnd; + LUID luid; + } BSMINFO,*PBSMINFO; + +#ifdef UNICODE +#define BroadcastSystemMessageEx BroadcastSystemMessageExW +#define BroadcastSystemMessage BroadcastSystemMessageW +#else +#define BroadcastSystemMessageEx BroadcastSystemMessageExA +#define BroadcastSystemMessage BroadcastSystemMessageA +#endif + + WINUSERAPI long WINAPI BroadcastSystemMessageExA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); + WINUSERAPI long WINAPI BroadcastSystemMessageExW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam,PBSMINFO pbsmInfo); + WINUSERAPI long WINAPI BroadcastSystemMessageA(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI long WINAPI BroadcastSystemMessageW(DWORD flags,LPDWORD lpInfo,UINT Msg,WPARAM wParam,LPARAM lParam); + +#define BSM_ALLCOMPONENTS 0x00000000 +#define BSM_VXDS 0x00000001 +#define BSM_NETDRIVER 0x00000002 +#define BSM_INSTALLABLEDRIVERS 0x00000004 +#define BSM_APPLICATIONS 0x00000008 +#define BSM_ALLDESKTOPS 0x00000010 + +#define BSF_QUERY 0x00000001 +#define BSF_IGNORECURRENTTASK 0x00000002 +#define BSF_FLUSHDISK 0x00000004 +#define BSF_NOHANG 0x00000008 +#define BSF_POSTMESSAGE 0x00000010 +#define BSF_FORCEIFHUNG 0x00000020 +#define BSF_NOTIMEOUTIFNOTHUNG 0x00000040 +#define BSF_ALLOWSFW 0x00000080 +#define BSF_SENDNOTIFYMESSAGE 0x00000100 +#define BSF_RETURNHDESK 0x00000200 +#define BSF_LUID 0x00000400 + +#define BROADCAST_QUERY_DENY 0x424D5144 + + typedef PVOID HDEVNOTIFY; + typedef HDEVNOTIFY *PHDEVNOTIFY; + +#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000 +#define DEVICE_NOTIFY_SERVICE_HANDLE 0x00000001 +#define DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 0x00000004 + +#ifdef UNICODE +#define RegisterDeviceNotification RegisterDeviceNotificationW +#define PostMessage PostMessageW +#define PostThreadMessage PostThreadMessageW +#define PostAppMessage PostAppMessageW +#define DefWindowProc DefWindowProcW +#define CallWindowProc CallWindowProcW +#define RegisterClass RegisterClassW +#define UnregisterClass UnregisterClassW +#define GetClassInfo GetClassInfoW +#define RegisterClassEx RegisterClassExW +#define GetClassInfoEx GetClassInfoExW +#else +#define RegisterDeviceNotification RegisterDeviceNotificationA +#define PostMessage PostMessageA +#define PostThreadMessage PostThreadMessageA +#define PostAppMessage PostAppMessageA +#define DefWindowProc DefWindowProcA +#define CallWindowProc CallWindowProcA +#define RegisterClass RegisterClassA +#define UnregisterClass UnregisterClassA +#define GetClassInfo GetClassInfoA +#define RegisterClassEx RegisterClassExA +#define GetClassInfoEx GetClassInfoExA +#endif + + WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); + WINUSERAPI HDEVNOTIFY WINAPI RegisterDeviceNotificationW(HANDLE hRecipient,LPVOID NotificationFilter,DWORD Flags); + WINUSERAPI WINBOOL WINAPI UnregisterDeviceNotification(HDEVNOTIFY Handle); + WINUSERAPI WINBOOL WINAPI PostMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI PostMessageW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI PostThreadMessageA(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI PostThreadMessageW(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam); +#define PostAppMessageA(idThread,wMsg,wParam,lParam) PostThreadMessageA((DWORD)idThread,wMsg,wParam,lParam) +#define PostAppMessageW(idThread,wMsg,wParam,lParam) PostThreadMessageW((DWORD)idThread,wMsg,wParam,lParam) + +#define HWND_BROADCAST ((HWND)0xffff) +#define HWND_MESSAGE ((HWND)-3) + + WINUSERAPI WINBOOL WINAPI AttachThreadInput(DWORD idAttach,DWORD idAttachTo,WINBOOL fAttach); + WINUSERAPI WINBOOL WINAPI ReplyMessage(LRESULT lResult); + WINUSERAPI WINBOOL WINAPI WaitMessage(VOID); + WINUSERAPI DWORD WINAPI WaitForInputIdle(HANDLE hProcess,DWORD dwMilliseconds); + WINUSERAPI LRESULT WINAPI DefWindowProcA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefWindowProcW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI VOID WINAPI PostQuitMessage(int nExitCode); + WINUSERAPI LRESULT WINAPI CallWindowProcA(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI CallWindowProcW(WNDPROC lpPrevWndFunc,HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI InSendMessage(VOID); + WINUSERAPI DWORD WINAPI InSendMessageEx(LPVOID lpReserved); + +#define ISMEX_NOSEND 0x00000000 +#define ISMEX_SEND 0x00000001 +#define ISMEX_NOTIFY 0x00000002 +#define ISMEX_CALLBACK 0x00000004 +#define ISMEX_REPLIED 0x00000008 + + WINUSERAPI UINT WINAPI GetDoubleClickTime(VOID); + WINUSERAPI WINBOOL WINAPI SetDoubleClickTime(UINT); + WINUSERAPI ATOM WINAPI RegisterClassA(CONST WNDCLASSA *lpWndClass); + WINUSERAPI ATOM WINAPI RegisterClassW(CONST WNDCLASSW *lpWndClass); + WINUSERAPI WINBOOL WINAPI UnregisterClassA(LPCSTR lpClassName,HINSTANCE hInstance); + WINUSERAPI WINBOOL WINAPI UnregisterClassW(LPCWSTR lpClassName,HINSTANCE hInstance); + WINUSERAPI WINBOOL WINAPI GetClassInfoA(HINSTANCE hInstance,LPCSTR lpClassName,LPWNDCLASSA lpWndClass); + WINUSERAPI WINBOOL WINAPI GetClassInfoW(HINSTANCE hInstance,LPCWSTR lpClassName,LPWNDCLASSW lpWndClass); + WINUSERAPI ATOM WINAPI RegisterClassExA(CONST WNDCLASSEXA *); + WINUSERAPI ATOM WINAPI RegisterClassExW(CONST WNDCLASSEXW *); + WINUSERAPI WINBOOL WINAPI GetClassInfoExA(HINSTANCE hInstance,LPCSTR lpszClass,LPWNDCLASSEXA lpwcx); + WINUSERAPI WINBOOL WINAPI GetClassInfoExW(HINSTANCE hInstance,LPCWSTR lpszClass,LPWNDCLASSEXW lpwcx); + +#define CW_USEDEFAULT ((int)0x80000000) + +#define HWND_DESKTOP ((HWND)0) + + typedef BOOLEAN (WINAPI *PREGISTERCLASSNAMEW)(LPCWSTR); + +#ifdef UNICODE +#define CreateWindowEx CreateWindowExW +#define CreateWindow CreateWindowW +#else +#define CreateWindowEx CreateWindowExA +#define CreateWindow CreateWindowA +#endif + + WINUSERAPI HWND WINAPI CreateWindowExA(DWORD dwExStyle,LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); + WINUSERAPI HWND WINAPI CreateWindowExW(DWORD dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); +#define CreateWindowA(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExA(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) +#define CreateWindowW(lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) CreateWindowExW(0L,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam) + WINUSERAPI WINBOOL WINAPI IsWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI IsMenu(HMENU hMenu); + WINUSERAPI WINBOOL WINAPI IsChild(HWND hWndParent,HWND hWnd); + WINUSERAPI WINBOOL WINAPI DestroyWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI ShowWindow(HWND hWnd,int nCmdShow); + WINUSERAPI WINBOOL WINAPI AnimateWindow(HWND hWnd,DWORD dwTime,DWORD dwFlags); + +#if defined(_WINGDI_) && !defined(NOGDI) + WINUSERAPI WINBOOL WINAPI UpdateLayeredWindow(HWND hWnd,HDC hdcDst,POINT *pptDst,SIZE *psize,HDC hdcSrc,POINT *pptSrc,COLORREF crKey,BLENDFUNCTION *pblend,DWORD dwFlags); + + typedef struct tagUPDATELAYEREDWINDOWINFO { + DWORD cbSize; + HDC hdcDst; + POINT CONST *pptDst; + SIZE CONST *psize; + HDC hdcSrc; + POINT CONST *pptSrc; + COLORREF crKey; + BLENDFUNCTION CONST *pblend; + DWORD dwFlags; + RECT CONST *prcDirty; + } UPDATELAYEREDWINDOWINFO,*PUPDATELAYEREDWINDOWINFO; + + WINUSERAPI WINBOOL WINAPI UpdateLayeredWindowIndirect(HWND hWnd,UPDATELAYEREDWINDOWINFO CONST *pULWInfo); + WINUSERAPI WINBOOL WINAPI GetLayeredWindowAttributes(HWND hwnd,COLORREF *pcrKey,BYTE *pbAlpha,DWORD *pdwFlags); + +#define PW_CLIENTONLY 0x00000001 + + WINUSERAPI WINBOOL WINAPI PrintWindow(HWND hwnd,HDC hdcBlt,UINT nFlags); + WINUSERAPI WINBOOL WINAPI SetLayeredWindowAttributes(HWND hwnd,COLORREF crKey,BYTE bAlpha,DWORD dwFlags); + +#define LWA_COLORKEY 0x00000001 +#define LWA_ALPHA 0x00000002 + +#define ULW_COLORKEY 0x00000001 +#define ULW_ALPHA 0x00000002 +#define ULW_OPAQUE 0x00000004 + +#define ULW_EX_NORESIZE 0x00000008 + + WINUSERAPI WINBOOL WINAPI ShowWindowAsync(HWND hWnd,int nCmdShow); + WINUSERAPI WINBOOL WINAPI FlashWindow(HWND hWnd,WINBOOL bInvert); + + typedef struct { + UINT cbSize; + HWND hwnd; + DWORD dwFlags; + UINT uCount; + DWORD dwTimeout; + } FLASHWINFO,*PFLASHWINFO; + + WINUSERAPI WINBOOL WINAPI FlashWindowEx(PFLASHWINFO pfwi); + +#define FLASHW_STOP 0 +#define FLASHW_CAPTION 0x00000001 +#define FLASHW_TRAY 0x00000002 +#define FLASHW_ALL (FLASHW_CAPTION | FLASHW_TRAY) +#define FLASHW_TIMER 0x00000004 +#define FLASHW_TIMERNOFG 0x0000000C + + WINUSERAPI WINBOOL WINAPI ShowOwnedPopups(HWND hWnd,WINBOOL fShow); + WINUSERAPI WINBOOL WINAPI OpenIcon(HWND hWnd); + WINUSERAPI WINBOOL WINAPI CloseWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI MoveWindow(HWND hWnd,int X,int Y,int nWidth,int nHeight,WINBOOL bRepaint); + WINUSERAPI WINBOOL WINAPI SetWindowPos(HWND hWnd,HWND hWndInsertAfter,int X,int Y,int cx,int cy,UINT uFlags); + WINUSERAPI WINBOOL WINAPI GetWindowPlacement(HWND hWnd,WINDOWPLACEMENT *lpwndpl); + WINUSERAPI WINBOOL WINAPI SetWindowPlacement(HWND hWnd,CONST WINDOWPLACEMENT *lpwndpl); + +#ifndef NODEFERWINDOWPOS + WINUSERAPI HDWP WINAPI BeginDeferWindowPos(int nNumWindows); + WINUSERAPI HDWP WINAPI DeferWindowPos(HDWP hWinPosInfo,HWND hWnd,HWND hWndInsertAfter,int x,int y,int cx,int cy,UINT uFlags); + WINUSERAPI WINBOOL WINAPI EndDeferWindowPos(HDWP hWinPosInfo); +#endif + + WINUSERAPI WINBOOL WINAPI IsWindowVisible(HWND hWnd); + WINUSERAPI WINBOOL WINAPI IsIconic(HWND hWnd); + WINUSERAPI WINBOOL WINAPI AnyPopup(VOID); + WINUSERAPI WINBOOL WINAPI BringWindowToTop(HWND hWnd); + WINUSERAPI WINBOOL WINAPI IsZoomed(HWND hWnd); + +#define SWP_NOSIZE 0x0001 +#define SWP_NOMOVE 0x0002 +#define SWP_NOZORDER 0x0004 +#define SWP_NOREDRAW 0x0008 +#define SWP_NOACTIVATE 0x0010 +#define SWP_FRAMECHANGED 0x0020 +#define SWP_SHOWWINDOW 0x0040 +#define SWP_HIDEWINDOW 0x0080 +#define SWP_NOCOPYBITS 0x0100 +#define SWP_NOOWNERZORDER 0x0200 +#define SWP_NOSENDCHANGING 0x0400 + +#define SWP_DRAWFRAME SWP_FRAMECHANGED +#define SWP_NOREPOSITION SWP_NOOWNERZORDER +#define SWP_DEFERERASE 0x2000 +#define SWP_ASYNCWINDOWPOS 0x4000 + +#define HWND_TOP ((HWND)0) +#define HWND_BOTTOM ((HWND)1) +#define HWND_TOPMOST ((HWND)-1) +#define HWND_NOTOPMOST ((HWND)-2) + +#ifndef NOCTLMGR + +#include + + typedef struct { + DWORD style; + DWORD dwExtendedStyle; + WORD cdit; + short x; + short y; + short cx; + short cy; + } DLGTEMPLATE; + + typedef DLGTEMPLATE *LPDLGTEMPLATEA; + typedef DLGTEMPLATE *LPDLGTEMPLATEW; + +#ifdef UNICODE + typedef LPDLGTEMPLATEW LPDLGTEMPLATE; +#else + typedef LPDLGTEMPLATEA LPDLGTEMPLATE; +#endif + + typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEA; + typedef CONST DLGTEMPLATE *LPCDLGTEMPLATEW; + +#ifdef UNICODE + typedef LPCDLGTEMPLATEW LPCDLGTEMPLATE; +#else + typedef LPCDLGTEMPLATEA LPCDLGTEMPLATE; +#endif + + typedef struct { + DWORD style; + DWORD dwExtendedStyle; + short x; + short y; + short cx; + short cy; + WORD id; + } DLGITEMTEMPLATE; + + typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEA; + typedef DLGITEMTEMPLATE *PDLGITEMTEMPLATEW; + +#ifdef UNICODE + typedef PDLGITEMTEMPLATEW PDLGITEMTEMPLATE; +#else + typedef PDLGITEMTEMPLATEA PDLGITEMTEMPLATE; +#endif + + typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEA; + typedef DLGITEMTEMPLATE *LPDLGITEMTEMPLATEW; + +#ifdef UNICODE + typedef LPDLGITEMTEMPLATEW LPDLGITEMTEMPLATE; +#else + typedef LPDLGITEMTEMPLATEA LPDLGITEMTEMPLATE; +#endif + +#include + +#ifdef UNICODE +#define CreateDialogParam CreateDialogParamW +#define CreateDialogIndirectParam CreateDialogIndirectParamW +#define CreateDialog CreateDialogW +#define CreateDialogIndirect CreateDialogIndirectW +#define DialogBoxParam DialogBoxParamW +#define DialogBoxIndirectParam DialogBoxIndirectParamW +#define DialogBox DialogBoxW +#define DialogBoxIndirect DialogBoxIndirectW +#define SetDlgItemText SetDlgItemTextW +#define GetDlgItemText GetDlgItemTextW +#define SendDlgItemMessage SendDlgItemMessageW +#define DefDlgProc DefDlgProcW +#else +#define CreateDialogParam CreateDialogParamA +#define CreateDialogIndirectParam CreateDialogIndirectParamA +#define CreateDialog CreateDialogA +#define CreateDialogIndirect CreateDialogIndirectA +#define DialogBoxParam DialogBoxParamA +#define DialogBoxIndirectParam DialogBoxIndirectParamA +#define DialogBox DialogBoxA +#define DialogBoxIndirect DialogBoxIndirectA +#define SetDlgItemText SetDlgItemTextA +#define GetDlgItemText GetDlgItemTextA +#define SendDlgItemMessage SendDlgItemMessageA +#define DefDlgProc DefDlgProcA +#endif + + WINUSERAPI HWND WINAPI CreateDialogParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI HWND WINAPI CreateDialogParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI HWND WINAPI CreateDialogIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI HWND WINAPI CreateDialogIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW lpTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); +#define CreateDialogA(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamA(hInstance,lpName,hWndParent,lpDialogFunc,0L) +#define CreateDialogW(hInstance,lpName,hWndParent,lpDialogFunc) CreateDialogParamW(hInstance,lpName,hWndParent,lpDialogFunc,0L) +#define CreateDialogIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define CreateDialogIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) CreateDialogIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) + WINUSERAPI INT_PTR WINAPI DialogBoxParamA(HINSTANCE hInstance,LPCSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI INT_PTR WINAPI DialogBoxParamW(HINSTANCE hInstance,LPCWSTR lpTemplateName,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamA(HINSTANCE hInstance,LPCDLGTEMPLATEA hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); + WINUSERAPI INT_PTR WINAPI DialogBoxIndirectParamW(HINSTANCE hInstance,LPCDLGTEMPLATEW hDialogTemplate,HWND hWndParent,DLGPROC lpDialogFunc,LPARAM dwInitParam); +#define DialogBoxA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define DialogBoxW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define DialogBoxIndirectA(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamA(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) +#define DialogBoxIndirectW(hInstance,lpTemplate,hWndParent,lpDialogFunc) DialogBoxIndirectParamW(hInstance,lpTemplate,hWndParent,lpDialogFunc,0L) + WINUSERAPI WINBOOL WINAPI EndDialog(HWND hDlg,INT_PTR nResult); + WINUSERAPI HWND WINAPI GetDlgItem(HWND hDlg,int nIDDlgItem); + WINUSERAPI WINBOOL WINAPI SetDlgItemInt(HWND hDlg,int nIDDlgItem,UINT uValue,WINBOOL bSigned); + WINUSERAPI UINT WINAPI GetDlgItemInt(HWND hDlg,int nIDDlgItem,WINBOOL *lpTranslated,WINBOOL bSigned); + WINUSERAPI WINBOOL WINAPI SetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPCSTR lpString); + WINUSERAPI WINBOOL WINAPI SetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPCWSTR lpString); + WINUSERAPI UINT WINAPI GetDlgItemTextA(HWND hDlg,int nIDDlgItem,LPSTR lpString,int cchMax); + WINUSERAPI UINT WINAPI GetDlgItemTextW(HWND hDlg,int nIDDlgItem,LPWSTR lpString,int cchMax); + WINUSERAPI WINBOOL WINAPI CheckDlgButton(HWND hDlg,int nIDButton,UINT uCheck); + WINUSERAPI WINBOOL WINAPI CheckRadioButton(HWND hDlg,int nIDFirstButton,int nIDLastButton,int nIDCheckButton); + WINUSERAPI UINT WINAPI IsDlgButtonChecked(HWND hDlg,int nIDButton); + WINUSERAPI LRESULT WINAPI SendDlgItemMessageA(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI SendDlgItemMessageW(HWND hDlg,int nIDDlgItem,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI HWND WINAPI GetNextDlgGroupItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); + WINUSERAPI HWND WINAPI GetNextDlgTabItem(HWND hDlg,HWND hCtl,WINBOOL bPrevious); + WINUSERAPI int WINAPI GetDlgCtrlID(HWND hWnd); + WINUSERAPI long WINAPI GetDialogBaseUnits(VOID); + WINUSERAPI LRESULT WINAPI DefDlgProcA(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefDlgProcW(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam); + +#define DLGWINDOWEXTRA 30 +#endif + +#ifndef NOMSG + +#ifdef UNICODE +#define CallMsgFilter CallMsgFilterW +#else +#define CallMsgFilter CallMsgFilterA +#endif + + WINUSERAPI WINBOOL WINAPI CallMsgFilterA(LPMSG lpMsg,int nCode); + WINUSERAPI WINBOOL WINAPI CallMsgFilterW(LPMSG lpMsg,int nCode); +#endif + +#ifndef NOCLIPBOARD + +#ifdef UNICODE +#define RegisterClipboardFormat RegisterClipboardFormatW +#define GetClipboardFormatName GetClipboardFormatNameW +#else +#define RegisterClipboardFormat RegisterClipboardFormatA +#define GetClipboardFormatName GetClipboardFormatNameA +#endif + + WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner); + WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID); + WINUSERAPI DWORD WINAPI GetClipboardSequenceNumber(VOID); + WINUSERAPI HWND WINAPI GetClipboardOwner(VOID); + WINUSERAPI HWND WINAPI SetClipboardViewer(HWND hWndNewViewer); + WINUSERAPI HWND WINAPI GetClipboardViewer(VOID); + WINUSERAPI WINBOOL WINAPI ChangeClipboardChain(HWND hWndRemove,HWND hWndNewNext); + WINUSERAPI HANDLE WINAPI SetClipboardData(UINT uFormat,HANDLE hMem); + WINUSERAPI HANDLE WINAPI GetClipboardData(UINT uFormat); + WINUSERAPI UINT WINAPI RegisterClipboardFormatA(LPCSTR lpszFormat); + WINUSERAPI UINT WINAPI RegisterClipboardFormatW(LPCWSTR lpszFormat); + WINUSERAPI int WINAPI CountClipboardFormats(VOID); + WINUSERAPI UINT WINAPI EnumClipboardFormats(UINT format); + WINUSERAPI int WINAPI GetClipboardFormatNameA(UINT format,LPSTR lpszFormatName,int cchMaxCount); + WINUSERAPI int WINAPI GetClipboardFormatNameW(UINT format,LPWSTR lpszFormatName,int cchMaxCount); + WINUSERAPI WINBOOL WINAPI EmptyClipboard(VOID); + WINUSERAPI WINBOOL WINAPI IsClipboardFormatAvailable(UINT format); + WINUSERAPI int WINAPI GetPriorityClipboardFormat(UINT *paFormatPriorityList,int cFormats); + WINUSERAPI HWND WINAPI GetOpenClipboardWindow(VOID); +#endif + +#ifdef UNICODE +#define CharToOem CharToOemW +#define OemToChar OemToCharW +#define CharToOemBuff CharToOemBuffW +#define OemToCharBuff OemToCharBuffW +#define CharUpper CharUpperW +#define CharUpperBuff CharUpperBuffW +#define CharLower CharLowerW +#define CharLowerBuff CharLowerBuffW +#define CharNext CharNextW +#define CharPrev CharPrevW +#else +#define CharToOem CharToOemA +#define OemToChar OemToCharA +#define CharToOemBuff CharToOemBuffA +#define OemToCharBuff OemToCharBuffA +#define CharUpper CharUpperA +#define CharUpperBuff CharUpperBuffA +#define CharLower CharLowerA +#define CharLowerBuff CharLowerBuffA +#define CharNext CharNextA +#define CharPrev CharPrevA +#endif + + WINUSERAPI WINBOOL WINAPI CharToOemA(LPCSTR lpszSrc,LPSTR lpszDst); + WINUSERAPI WINBOOL WINAPI CharToOemW(LPCWSTR lpszSrc,LPSTR lpszDst); + WINUSERAPI WINBOOL WINAPI OemToCharA(LPCSTR lpszSrc,LPSTR lpszDst); + WINUSERAPI WINBOOL WINAPI OemToCharW(LPCSTR lpszSrc,LPWSTR lpszDst); + WINUSERAPI WINBOOL WINAPI CharToOemBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); + WINUSERAPI WINBOOL WINAPI CharToOemBuffW(LPCWSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); + WINUSERAPI WINBOOL WINAPI OemToCharBuffA(LPCSTR lpszSrc,LPSTR lpszDst,DWORD cchDstLength); + WINUSERAPI WINBOOL WINAPI OemToCharBuffW(LPCSTR lpszSrc,LPWSTR lpszDst,DWORD cchDstLength); + WINUSERAPI LPSTR WINAPI CharUpperA(LPSTR lpsz); + WINUSERAPI LPWSTR WINAPI CharUpperW(LPWSTR lpsz); + WINUSERAPI DWORD WINAPI CharUpperBuffA(LPSTR lpsz,DWORD cchLength); + WINUSERAPI DWORD WINAPI CharUpperBuffW(LPWSTR lpsz,DWORD cchLength); + WINUSERAPI LPSTR WINAPI CharLowerA(LPSTR lpsz); + WINUSERAPI LPWSTR WINAPI CharLowerW(LPWSTR lpsz); + WINUSERAPI DWORD WINAPI CharLowerBuffA(LPSTR lpsz,DWORD cchLength); + WINUSERAPI DWORD WINAPI CharLowerBuffW(LPWSTR lpsz,DWORD cchLength); + WINUSERAPI LPSTR WINAPI CharNextA(LPCSTR lpsz); + WINUSERAPI LPWSTR WINAPI CharNextW(LPCWSTR lpsz); + WINUSERAPI LPSTR WINAPI CharPrevA(LPCSTR lpszStart,LPCSTR lpszCurrent); + WINUSERAPI LPWSTR WINAPI CharPrevW(LPCWSTR lpszStart,LPCWSTR lpszCurrent); + WINUSERAPI LPSTR WINAPI CharNextExA(WORD CodePage,LPCSTR lpCurrentChar,DWORD dwFlags); + WINUSERAPI LPSTR WINAPI CharPrevExA(WORD CodePage,LPCSTR lpStart,LPCSTR lpCurrentChar,DWORD dwFlags); + +#define AnsiToOem CharToOemA +#define OemToAnsi OemToCharA +#define AnsiToOemBuff CharToOemBuffA +#define OemToAnsiBuff OemToCharBuffA +#define AnsiUpper CharUpperA +#define AnsiUpperBuff CharUpperBuffA +#define AnsiLower CharLowerA +#define AnsiLowerBuff CharLowerBuffA +#define AnsiNext CharNextA +#define AnsiPrev CharPrevA + +#ifndef NOLANGUAGE + +#ifdef UNICODE +#define IsCharAlpha IsCharAlphaW +#define IsCharAlphaNumeric IsCharAlphaNumericW +#define IsCharUpper IsCharUpperW +#define IsCharLower IsCharLowerW +#else +#define IsCharAlpha IsCharAlphaA +#define IsCharAlphaNumeric IsCharAlphaNumericA +#define IsCharUpper IsCharUpperA +#define IsCharLower IsCharLowerA +#endif + + WINUSERAPI WINBOOL WINAPI IsCharAlphaA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharAlphaW(WCHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharAlphaNumericW(WCHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharUpperA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharUpperW(WCHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharLowerA(CHAR ch); + WINUSERAPI WINBOOL WINAPI IsCharLowerW(WCHAR ch); +#endif + +#ifdef UNICODE +#define GetKeyNameText GetKeyNameTextW +#define VkKeyScan VkKeyScanW +#define VkKeyScanEx VkKeyScanExW +#else +#define GetKeyNameText GetKeyNameTextA +#define VkKeyScan VkKeyScanA +#define VkKeyScanEx VkKeyScanExA +#endif + + WINUSERAPI HWND WINAPI SetFocus(HWND hWnd); + WINUSERAPI HWND WINAPI GetActiveWindow(VOID); + WINUSERAPI HWND WINAPI GetFocus(VOID); + WINUSERAPI UINT WINAPI GetKBCodePage(VOID); + WINUSERAPI SHORT WINAPI GetKeyState(int nVirtKey); + WINUSERAPI SHORT WINAPI GetAsyncKeyState(int vKey); + WINUSERAPI WINBOOL WINAPI GetKeyboardState(PBYTE lpKeyState); + WINUSERAPI WINBOOL WINAPI SetKeyboardState(LPBYTE lpKeyState); + WINUSERAPI int WINAPI GetKeyNameTextA(LONG lParam,LPSTR lpString,int cchSize); + WINUSERAPI int WINAPI GetKeyNameTextW(LONG lParam,LPWSTR lpString,int cchSize); + WINUSERAPI int WINAPI GetKeyboardType(int nTypeFlag); + WINUSERAPI int WINAPI ToAscii(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags); + WINUSERAPI int WINAPI ToAsciiEx(UINT uVirtKey,UINT uScanCode,CONST BYTE *lpKeyState,LPWORD lpChar,UINT uFlags,HKL dwhkl); + WINUSERAPI int WINAPI ToUnicode(UINT wVirtKey,UINT wScanCode,CONST BYTE *lpKeyState,LPWSTR pwszBuff,int cchBuff,UINT wFlags); + WINUSERAPI DWORD WINAPI OemKeyScan(WORD wOemChar); + WINUSERAPI SHORT WINAPI VkKeyScanA(CHAR ch); + WINUSERAPI SHORT WINAPI VkKeyScanW(WCHAR ch); + WINUSERAPI SHORT WINAPI VkKeyScanExA(CHAR ch,HKL dwhkl); + WINUSERAPI SHORT WINAPI VkKeyScanExW(WCHAR ch,HKL dwhkl); + +#define KEYEVENTF_EXTENDEDKEY 0x0001 +#define KEYEVENTF_KEYUP 0x0002 +#define KEYEVENTF_UNICODE 0x0004 +#define KEYEVENTF_SCANCODE 0x0008 + + WINUSERAPI VOID WINAPI keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,ULONG_PTR dwExtraInfo); + +#define MOUSEEVENTF_MOVE 0x0001 +#define MOUSEEVENTF_LEFTDOWN 0x0002 +#define MOUSEEVENTF_LEFTUP 0x0004 +#define MOUSEEVENTF_RIGHTDOWN 0x0008 +#define MOUSEEVENTF_RIGHTUP 0x0010 +#define MOUSEEVENTF_MIDDLEDOWN 0x0020 +#define MOUSEEVENTF_MIDDLEUP 0x0040 +#define MOUSEEVENTF_XDOWN 0x0080 +#define MOUSEEVENTF_XUP 0x0100 +#define MOUSEEVENTF_WHEEL 0x0800 +#define MOUSEEVENTF_VIRTUALDESK 0x4000 +#define MOUSEEVENTF_ABSOLUTE 0x8000 + + WINUSERAPI VOID WINAPI mouse_event(DWORD dwFlags,DWORD dx,DWORD dy,DWORD dwData,ULONG_PTR dwExtraInfo); + + typedef struct tagMOUSEINPUT { + LONG dx; + LONG dy; + DWORD mouseData; + DWORD dwFlags; + DWORD time; + ULONG_PTR dwExtraInfo; + } MOUSEINPUT,*PMOUSEINPUT,*LPMOUSEINPUT; + + typedef struct tagKEYBDINPUT { + WORD wVk; + WORD wScan; + DWORD dwFlags; + DWORD time; + ULONG_PTR dwExtraInfo; + } KEYBDINPUT,*PKEYBDINPUT,*LPKEYBDINPUT; + + typedef struct tagHARDWAREINPUT { + DWORD uMsg; + WORD wParamL; + WORD wParamH; + } HARDWAREINPUT,*PHARDWAREINPUT,*LPHARDWAREINPUT; + +#define INPUT_MOUSE 0 +#define INPUT_KEYBOARD 1 +#define INPUT_HARDWARE 2 + + typedef struct tagINPUT { + DWORD type; + union { + MOUSEINPUT mi; + KEYBDINPUT ki; + HARDWAREINPUT hi; + }; + } INPUT,*PINPUT,*LPINPUT; + + WINUSERAPI UINT WINAPI SendInput(UINT cInputs,LPINPUT pInputs,int cbSize); + + typedef struct tagLASTINPUTINFO { + UINT cbSize; + DWORD dwTime; + } LASTINPUTINFO,*PLASTINPUTINFO; + +#ifdef UNICODE +#define MapVirtualKey MapVirtualKeyW +#define MapVirtualKeyEx MapVirtualKeyExW +#else +#define MapVirtualKey MapVirtualKeyA +#define MapVirtualKeyEx MapVirtualKeyExA +#endif + + WINUSERAPI WINBOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii); + WINUSERAPI UINT WINAPI MapVirtualKeyA(UINT uCode,UINT uMapType); + WINUSERAPI UINT WINAPI MapVirtualKeyW(UINT uCode,UINT uMapType); + WINUSERAPI UINT WINAPI MapVirtualKeyExA(UINT uCode,UINT uMapType,HKL dwhkl); + WINUSERAPI UINT WINAPI MapVirtualKeyExW(UINT uCode,UINT uMapType,HKL dwhkl); + WINUSERAPI WINBOOL WINAPI GetInputState(VOID); + WINUSERAPI DWORD WINAPI GetQueueStatus(UINT flags); + WINUSERAPI HWND WINAPI GetCapture(VOID); + WINUSERAPI HWND WINAPI SetCapture(HWND hWnd); + WINUSERAPI WINBOOL WINAPI ReleaseCapture(VOID); + WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjects(DWORD nCount,CONST HANDLE *pHandles,WINBOOL fWaitAll,DWORD dwMilliseconds,DWORD dwWakeMask); + WINUSERAPI DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD nCount,CONST HANDLE *pHandles,DWORD dwMilliseconds,DWORD dwWakeMask,DWORD dwFlags); + +#define MWMO_WAITALL 0x0001 +#define MWMO_ALERTABLE 0x0002 +#define MWMO_INPUTAVAILABLE 0x0004 + +#define QS_KEY 0x0001 +#define QS_MOUSEMOVE 0x0002 +#define QS_MOUSEBUTTON 0x0004 +#define QS_POSTMESSAGE 0x0008 +#define QS_TIMER 0x0010 +#define QS_PAINT 0x0020 +#define QS_SENDMESSAGE 0x0040 +#define QS_HOTKEY 0x0080 +#define QS_ALLPOSTMESSAGE 0x0100 +#define QS_RAWINPUT 0x0400 +#define QS_MOUSE (QS_MOUSEMOVE | QS_MOUSEBUTTON) +#define QS_INPUT (QS_MOUSE | QS_KEY | QS_RAWINPUT) +#define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) +#define QS_ALLINPUT (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE) + +#define USER_TIMER_MAXIMUM 0x7FFFFFFF +#define USER_TIMER_MINIMUM 0x0000000A + +#ifdef UNICODE +#define LoadAccelerators LoadAcceleratorsW +#define CreateAcceleratorTable CreateAcceleratorTableW +#define CopyAcceleratorTable CopyAcceleratorTableW +#else +#define LoadAccelerators LoadAcceleratorsA +#define CreateAcceleratorTable CreateAcceleratorTableA +#define CopyAcceleratorTable CopyAcceleratorTableA +#endif + + WINUSERAPI UINT_PTR WINAPI SetTimer(HWND hWnd,UINT_PTR nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc); + WINUSERAPI WINBOOL WINAPI KillTimer(HWND hWnd,UINT_PTR uIDEvent); + WINUSERAPI WINBOOL WINAPI IsWindowUnicode(HWND hWnd); + WINUSERAPI WINBOOL WINAPI EnableWindow(HWND hWnd,WINBOOL bEnable); + WINUSERAPI WINBOOL WINAPI IsWindowEnabled(HWND hWnd); + WINUSERAPI HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance,LPCSTR lpTableName); + WINUSERAPI HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance,LPCWSTR lpTableName); + WINUSERAPI HACCEL WINAPI CreateAcceleratorTableA(LPACCEL paccel,int cAccel); + WINUSERAPI HACCEL WINAPI CreateAcceleratorTableW(LPACCEL paccel,int cAccel); + WINUSERAPI WINBOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel); + WINUSERAPI int WINAPI CopyAcceleratorTableA(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); + WINUSERAPI int WINAPI CopyAcceleratorTableW(HACCEL hAccelSrc,LPACCEL lpAccelDst,int cAccelEntries); + +#ifndef NOMSG + +#ifdef UNICODE +#define TranslateAccelerator TranslateAcceleratorW +#else +#define TranslateAccelerator TranslateAcceleratorA +#endif + + WINUSERAPI int WINAPI TranslateAcceleratorA(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); + WINUSERAPI int WINAPI TranslateAcceleratorW(HWND hWnd,HACCEL hAccTable,LPMSG lpMsg); +#endif + +#ifndef NOSYSMETRICS + +#define SM_CXSCREEN 0 +#define SM_CYSCREEN 1 +#define SM_CXVSCROLL 2 +#define SM_CYHSCROLL 3 +#define SM_CYCAPTION 4 +#define SM_CXBORDER 5 +#define SM_CYBORDER 6 +#define SM_CXDLGFRAME 7 +#define SM_CYDLGFRAME 8 +#define SM_CYVTHUMB 9 +#define SM_CXHTHUMB 10 +#define SM_CXICON 11 +#define SM_CYICON 12 +#define SM_CXCURSOR 13 +#define SM_CYCURSOR 14 +#define SM_CYMENU 15 +#define SM_CXFULLSCREEN 16 +#define SM_CYFULLSCREEN 17 +#define SM_CYKANJIWINDOW 18 +#define SM_MOUSEPRESENT 19 +#define SM_CYVSCROLL 20 +#define SM_CXHSCROLL 21 +#define SM_DEBUG 22 +#define SM_SWAPBUTTON 23 +#define SM_RESERVED1 24 +#define SM_RESERVED2 25 +#define SM_RESERVED3 26 +#define SM_RESERVED4 27 +#define SM_CXMIN 28 +#define SM_CYMIN 29 +#define SM_CXSIZE 30 +#define SM_CYSIZE 31 +#define SM_CXFRAME 32 +#define SM_CYFRAME 33 +#define SM_CXMINTRACK 34 +#define SM_CYMINTRACK 35 +#define SM_CXDOUBLECLK 36 +#define SM_CYDOUBLECLK 37 +#define SM_CXICONSPACING 38 +#define SM_CYICONSPACING 39 +#define SM_MENUDROPALIGNMENT 40 +#define SM_PENWINDOWS 41 +#define SM_DBCSENABLED 42 +#define SM_CMOUSEBUTTONS 43 + +#define SM_CXFIXEDFRAME SM_CXDLGFRAME +#define SM_CYFIXEDFRAME SM_CYDLGFRAME +#define SM_CXSIZEFRAME SM_CXFRAME +#define SM_CYSIZEFRAME SM_CYFRAME + +#define SM_SECURE 44 +#define SM_CXEDGE 45 +#define SM_CYEDGE 46 +#define SM_CXMINSPACING 47 +#define SM_CYMINSPACING 48 +#define SM_CXSMICON 49 +#define SM_CYSMICON 50 +#define SM_CYSMCAPTION 51 +#define SM_CXSMSIZE 52 +#define SM_CYSMSIZE 53 +#define SM_CXMENUSIZE 54 +#define SM_CYMENUSIZE 55 +#define SM_ARRANGE 56 +#define SM_CXMINIMIZED 57 +#define SM_CYMINIMIZED 58 +#define SM_CXMAXTRACK 59 +#define SM_CYMAXTRACK 60 +#define SM_CXMAXIMIZED 61 +#define SM_CYMAXIMIZED 62 +#define SM_NETWORK 63 +#define SM_CLEANBOOT 67 +#define SM_CXDRAG 68 +#define SM_CYDRAG 69 +#define SM_SHOWSOUNDS 70 +#define SM_CXMENUCHECK 71 +#define SM_CYMENUCHECK 72 +#define SM_SLOWMACHINE 73 +#define SM_MIDEASTENABLED 74 +#define SM_MOUSEWHEELPRESENT 75 +#define SM_XVIRTUALSCREEN 76 +#define SM_YVIRTUALSCREEN 77 +#define SM_CXVIRTUALSCREEN 78 +#define SM_CYVIRTUALSCREEN 79 +#define SM_CMONITORS 80 +#define SM_SAMEDISPLAYFORMAT 81 +#define SM_IMMENABLED 82 +#define SM_CXFOCUSBORDER 83 +#define SM_CYFOCUSBORDER 84 +#define SM_TABLETPC 86 +#define SM_MEDIACENTER 87 +#define SM_STARTER 88 +#define SM_SERVERR2 89 +#define SM_CMETRICS 90 +#define SM_REMOTESESSION 0x1000 +#define SM_SHUTTINGDOWN 0x2000 +#define SM_REMOTECONTROL 0x2001 +#define SM_CARETBLINKINGENABLED 0x2002 + + WINUSERAPI int WINAPI GetSystemMetrics(int nIndex); +#endif + +#ifndef NOMENUS + +#ifdef UNICODE +#define LoadMenu LoadMenuW +#define LoadMenuIndirect LoadMenuIndirectW +#define ChangeMenu ChangeMenuW +#define GetMenuString GetMenuStringW +#define InsertMenu InsertMenuW +#define AppendMenu AppendMenuW +#define ModifyMenu ModifyMenuW +#else +#define LoadMenu LoadMenuA +#define LoadMenuIndirect LoadMenuIndirectA +#define ChangeMenu ChangeMenuA +#define GetMenuString GetMenuStringA +#define InsertMenu InsertMenuA +#define AppendMenu AppendMenuA +#define ModifyMenu ModifyMenuA +#endif + + WINUSERAPI HMENU WINAPI LoadMenuA(HINSTANCE hInstance,LPCSTR lpMenuName); + WINUSERAPI HMENU WINAPI LoadMenuW(HINSTANCE hInstance,LPCWSTR lpMenuName); + WINUSERAPI HMENU WINAPI LoadMenuIndirectA(CONST MENUTEMPLATEA *lpMenuTemplate); + WINUSERAPI HMENU WINAPI LoadMenuIndirectW(CONST MENUTEMPLATEW *lpMenuTemplate); + WINUSERAPI HMENU WINAPI GetMenu(HWND hWnd); + WINUSERAPI WINBOOL WINAPI SetMenu(HWND hWnd,HMENU hMenu); + WINUSERAPI WINBOOL WINAPI ChangeMenuA(HMENU hMenu,UINT cmd,LPCSTR lpszNewItem,UINT cmdInsert,UINT flags); + WINUSERAPI WINBOOL WINAPI ChangeMenuW(HMENU hMenu,UINT cmd,LPCWSTR lpszNewItem,UINT cmdInsert,UINT flags); + WINUSERAPI WINBOOL WINAPI HiliteMenuItem(HWND hWnd,HMENU hMenu,UINT uIDHiliteItem,UINT uHilite); + WINUSERAPI int WINAPI GetMenuStringA(HMENU hMenu,UINT uIDItem,LPSTR lpString,int cchMax,UINT flags); + WINUSERAPI int WINAPI GetMenuStringW(HMENU hMenu,UINT uIDItem,LPWSTR lpString,int cchMax,UINT flags); + WINUSERAPI UINT WINAPI GetMenuState(HMENU hMenu,UINT uId,UINT uFlags); + WINUSERAPI WINBOOL WINAPI DrawMenuBar(HWND hWnd); + +#define PMB_ACTIVE 0x00000001 + + WINUSERAPI HMENU WINAPI GetSystemMenu(HWND hWnd,WINBOOL bRevert); + WINUSERAPI HMENU WINAPI CreateMenu(VOID); + WINUSERAPI HMENU WINAPI CreatePopupMenu(VOID); + WINUSERAPI WINBOOL WINAPI DestroyMenu(HMENU hMenu); + WINUSERAPI DWORD WINAPI CheckMenuItem(HMENU hMenu,UINT uIDCheckItem,UINT uCheck); + WINUSERAPI WINBOOL WINAPI EnableMenuItem(HMENU hMenu,UINT uIDEnableItem,UINT uEnable); + WINUSERAPI HMENU WINAPI GetSubMenu(HMENU hMenu,int nPos); + WINUSERAPI UINT WINAPI GetMenuItemID(HMENU hMenu,int nPos); + WINUSERAPI int WINAPI GetMenuItemCount(HMENU hMenu); + WINUSERAPI WINBOOL WINAPI InsertMenuA(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI InsertMenuW(HMENU hMenu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI AppendMenuA(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI AppendMenuW(HMENU hMenu,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI ModifyMenuA(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI ModifyMenuW(HMENU hMnu,UINT uPosition,UINT uFlags,UINT_PTR uIDNewItem,LPCWSTR lpNewItem); + WINUSERAPI WINBOOL WINAPI RemoveMenu(HMENU hMenu,UINT uPosition,UINT uFlags); + WINUSERAPI WINBOOL WINAPI DeleteMenu(HMENU hMenu,UINT uPosition,UINT uFlags); + WINUSERAPI WINBOOL WINAPI SetMenuItemBitmaps(HMENU hMenu,UINT uPosition,UINT uFlags,HBITMAP hBitmapUnchecked,HBITMAP hBitmapChecked); + WINUSERAPI LONG WINAPI GetMenuCheckMarkDimensions(VOID); + WINUSERAPI WINBOOL WINAPI TrackPopupMenu(HMENU hMenu,UINT uFlags,int x,int y,int nReserved,HWND hWnd,CONST RECT *prcRect); + +#define MNC_IGNORE 0 +#define MNC_CLOSE 1 +#define MNC_EXECUTE 2 +#define MNC_SELECT 3 + + typedef struct tagTPMPARAMS { + UINT cbSize; + RECT rcExclude; + } TPMPARAMS; + + typedef TPMPARAMS *LPTPMPARAMS; + + WINUSERAPI WINBOOL WINAPI TrackPopupMenuEx(HMENU,UINT,int,int,HWND,LPTPMPARAMS); + +#define MNS_NOCHECK 0x80000000 +#define MNS_MODELESS 0x40000000 +#define MNS_DRAGDROP 0x20000000 +#define MNS_AUTODISMISS 0x10000000 +#define MNS_NOTIFYBYPOS 0x08000000 +#define MNS_CHECKORBMP 0x04000000 + +#define MIM_MAXHEIGHT 0x00000001 +#define MIM_BACKGROUND 0x00000002 +#define MIM_HELPID 0x00000004 +#define MIM_MENUDATA 0x00000008 +#define MIM_STYLE 0x00000010 +#define MIM_APPLYTOSUBMENUS 0x80000000 + + typedef struct tagMENUINFO { + DWORD cbSize; + DWORD fMask; + DWORD dwStyle; + UINT cyMax; + HBRUSH hbrBack; + DWORD dwContextHelpID; + ULONG_PTR dwMenuData; + } MENUINFO,*LPMENUINFO; + + typedef MENUINFO CONST *LPCMENUINFO; + + WINUSERAPI WINBOOL WINAPI GetMenuInfo(HMENU,LPMENUINFO); + WINUSERAPI WINBOOL WINAPI SetMenuInfo(HMENU,LPCMENUINFO); + WINUSERAPI WINBOOL WINAPI EndMenu(VOID); + +#define MND_CONTINUE 0 +#define MND_ENDMENU 1 + + typedef struct tagMENUGETOBJECTINFO { + DWORD dwFlags; + UINT uPos; + HMENU hmenu; + PVOID riid; + PVOID pvObj; + } MENUGETOBJECTINFO,*PMENUGETOBJECTINFO; + +#define MNGOF_TOPGAP 0x00000001 +#define MNGOF_BOTTOMGAP 0x00000002 + +#define MNGO_NOINTERFACE 0x00000000 +#define MNGO_NOERROR 0x00000001 + +#define MIIM_STATE 0x00000001 +#define MIIM_ID 0x00000002 +#define MIIM_SUBMENU 0x00000004 +#define MIIM_CHECKMARKS 0x00000008 +#define MIIM_TYPE 0x00000010 +#define MIIM_DATA 0x00000020 + +#define MIIM_STRING 0x00000040 +#define MIIM_BITMAP 0x00000080 +#define MIIM_FTYPE 0x00000100 + +#define HBMMENU_CALLBACK ((HBITMAP) -1) +#define HBMMENU_SYSTEM ((HBITMAP) 1) +#define HBMMENU_MBAR_RESTORE ((HBITMAP) 2) +#define HBMMENU_MBAR_MINIMIZE ((HBITMAP) 3) +#define HBMMENU_MBAR_CLOSE ((HBITMAP) 5) +#define HBMMENU_MBAR_CLOSE_D ((HBITMAP) 6) +#define HBMMENU_MBAR_MINIMIZE_D ((HBITMAP) 7) +#define HBMMENU_POPUP_CLOSE ((HBITMAP) 8) +#define HBMMENU_POPUP_RESTORE ((HBITMAP) 9) +#define HBMMENU_POPUP_MAXIMIZE ((HBITMAP) 10) +#define HBMMENU_POPUP_MINIMIZE ((HBITMAP) 11) + + typedef struct tagMENUITEMINFOA { + UINT cbSize; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + ULONG_PTR dwItemData; + LPSTR dwTypeData; + UINT cch; + HBITMAP hbmpItem; + } MENUITEMINFOA,*LPMENUITEMINFOA; + + typedef struct tagMENUITEMINFOW { + UINT cbSize; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + ULONG_PTR dwItemData; + LPWSTR dwTypeData; + UINT cch; + HBITMAP hbmpItem; + } MENUITEMINFOW,*LPMENUITEMINFOW; + +#ifdef UNICODE + typedef MENUITEMINFOW MENUITEMINFO; + typedef LPMENUITEMINFOW LPMENUITEMINFO; +#else + typedef MENUITEMINFOA MENUITEMINFO; + typedef LPMENUITEMINFOA LPMENUITEMINFO; +#endif + typedef MENUITEMINFOA CONST *LPCMENUITEMINFOA; + typedef MENUITEMINFOW CONST *LPCMENUITEMINFOW; +#ifdef UNICODE + typedef LPCMENUITEMINFOW LPCMENUITEMINFO; +#else + typedef LPCMENUITEMINFOA LPCMENUITEMINFO; +#endif + +#ifdef UNICODE +#define InsertMenuItem InsertMenuItemW +#define GetMenuItemInfo GetMenuItemInfoW +#define SetMenuItemInfo SetMenuItemInfoW +#else +#define InsertMenuItem InsertMenuItemA +#define GetMenuItemInfo GetMenuItemInfoA +#define SetMenuItemInfo SetMenuItemInfoA +#endif + + WINUSERAPI WINBOOL WINAPI InsertMenuItemA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOA lpmi); + WINUSERAPI WINBOOL WINAPI InsertMenuItemW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPCMENUITEMINFOW lpmi); + WINUSERAPI WINBOOL WINAPI GetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOA lpmii); + WINUSERAPI WINBOOL WINAPI GetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPosition,LPMENUITEMINFOW lpmii); + WINUSERAPI WINBOOL WINAPI SetMenuItemInfoA(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOA lpmii); + WINUSERAPI WINBOOL WINAPI SetMenuItemInfoW(HMENU hmenu,UINT item,WINBOOL fByPositon,LPCMENUITEMINFOW lpmii); + +#define GMDI_USEDISABLED 0x0001L +#define GMDI_GOINTOPOPUPS 0x0002L + + WINUSERAPI UINT WINAPI GetMenuDefaultItem(HMENU hMenu,UINT fByPos,UINT gmdiFlags); + WINUSERAPI WINBOOL WINAPI SetMenuDefaultItem(HMENU hMenu,UINT uItem,UINT fByPos); + WINUSERAPI WINBOOL WINAPI GetMenuItemRect(HWND hWnd,HMENU hMenu,UINT uItem,LPRECT lprcItem); + WINUSERAPI int WINAPI MenuItemFromPoint(HWND hWnd,HMENU hMenu,POINT ptScreen); + +#define TPM_LEFTBUTTON 0x0000L +#define TPM_RIGHTBUTTON 0x0002L +#define TPM_LEFTALIGN 0x0000L +#define TPM_CENTERALIGN 0x0004L +#define TPM_RIGHTALIGN 0x0008L +#define TPM_TOPALIGN 0x0000L +#define TPM_VCENTERALIGN 0x0010L +#define TPM_BOTTOMALIGN 0x0020L + +#define TPM_HORIZONTAL 0x0000L +#define TPM_VERTICAL 0x0040L +#define TPM_NONOTIFY 0x0080L +#define TPM_RETURNCMD 0x0100L +#define TPM_RECURSE 0x0001L +#define TPM_HORPOSANIMATION 0x0400L +#define TPM_HORNEGANIMATION 0x0800L +#define TPM_VERPOSANIMATION 0x1000L +#define TPM_VERNEGANIMATION 0x2000L +#define TPM_NOANIMATION 0x4000L +#define TPM_LAYOUTRTL 0x8000L +#endif + + typedef struct tagDROPSTRUCT { + HWND hwndSource; + HWND hwndSink; + DWORD wFmt; + ULONG_PTR dwData; + POINT ptDrop; + DWORD dwControlData; + } DROPSTRUCT,*PDROPSTRUCT,*LPDROPSTRUCT; + +#define DOF_EXECUTABLE 0x8001 +#define DOF_DOCUMENT 0x8002 +#define DOF_DIRECTORY 0x8003 +#define DOF_MULTIPLE 0x8004 +#define DOF_PROGMAN 0x0001 +#define DOF_SHELLDATA 0x0002 + +#define DO_DROPFILE 0x454C4946L +#define DO_PRINTFILE 0x544E5250L + + WINUSERAPI DWORD WINAPI DragObject(HWND hwndParent,HWND hwndFrom,UINT fmt,ULONG_PTR data,HCURSOR hcur); + WINUSERAPI WINBOOL WINAPI DragDetect(HWND hwnd,POINT pt); + WINUSERAPI WINBOOL WINAPI DrawIcon(HDC hDC,int X,int Y,HICON hIcon); + +#ifndef NODRAWTEXT + +#define DT_TOP 0x00000000 +#define DT_LEFT 0x00000000 +#define DT_CENTER 0x00000001 +#define DT_RIGHT 0x00000002 +#define DT_VCENTER 0x00000004 +#define DT_BOTTOM 0x00000008 +#define DT_WORDBREAK 0x00000010 +#define DT_SINGLELINE 0x00000020 +#define DT_EXPANDTABS 0x00000040 +#define DT_TABSTOP 0x00000080 +#define DT_NOCLIP 0x00000100 +#define DT_EXTERNALLEADING 0x00000200 +#define DT_CALCRECT 0x00000400 +#define DT_NOPREFIX 0x00000800 +#define DT_INTERNAL 0x00001000 + +#define DT_EDITCONTROL 0x00002000 +#define DT_PATH_ELLIPSIS 0x00004000 +#define DT_END_ELLIPSIS 0x00008000 +#define DT_MODIFYSTRING 0x00010000 +#define DT_RTLREADING 0x00020000 +#define DT_WORD_ELLIPSIS 0x00040000 +#define DT_NOFULLWIDTHCHARBREAK 0x00080000 +#define DT_HIDEPREFIX 0x00100000 +#define DT_PREFIXONLY 0x00200000 + + typedef struct tagDRAWTEXTPARAMS { + UINT cbSize; + int iTabLength; + int iLeftMargin; + int iRightMargin; + UINT uiLengthDrawn; + } DRAWTEXTPARAMS,*LPDRAWTEXTPARAMS; + +#ifdef UNICODE +#define DrawText DrawTextW +#define DrawTextEx DrawTextExW +#else +#define DrawText DrawTextA +#define DrawTextEx DrawTextExA +#endif + + WINUSERAPI int WINAPI DrawTextA(HDC hdc,LPCSTR lpchText,int cchText,LPRECT lprc,UINT format); + WINUSERAPI int WINAPI DrawTextW(HDC hdc,LPCWSTR lpchText,int cchText,LPRECT lprc,UINT format); + WINUSERAPI int WINAPI DrawTextExA(HDC hdc,LPSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); + WINUSERAPI int WINAPI DrawTextExW(HDC hdc,LPWSTR lpchText,int cchText,LPRECT lprc,UINT format,LPDRAWTEXTPARAMS lpdtp); +#endif + +#ifdef UNICODE +#define GrayString GrayStringW +#define DrawState DrawStateW +#define TabbedTextOut TabbedTextOutW +#define GetTabbedTextExtent GetTabbedTextExtentW +#else +#define GrayString GrayStringA +#define DrawState DrawStateA +#define TabbedTextOut TabbedTextOutA +#define GetTabbedTextExtent GetTabbedTextExtentA +#endif + + WINUSERAPI WINBOOL WINAPI GrayStringA(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); + WINUSERAPI WINBOOL WINAPI GrayStringW(HDC hDC,HBRUSH hBrush,GRAYSTRINGPROC lpOutputFunc,LPARAM lpData,int nCount,int X,int Y,int nWidth,int nHeight); + +#define DST_COMPLEX 0x0000 +#define DST_TEXT 0x0001 +#define DST_PREFIXTEXT 0x0002 +#define DST_ICON 0x0003 +#define DST_BITMAP 0x0004 + +#define DSS_NORMAL 0x0000 +#define DSS_UNION 0x0010 +#define DSS_DISABLED 0x0020 +#define DSS_MONO 0x0080 +#define DSS_HIDEPREFIX 0x0200 +#define DSS_PREFIXONLY 0x0400 +#define DSS_RIGHT 0x8000 + + WINUSERAPI WINBOOL WINAPI DrawStateA(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); + WINUSERAPI WINBOOL WINAPI DrawStateW(HDC hdc,HBRUSH hbrFore,DRAWSTATEPROC qfnCallBack,LPARAM lData,WPARAM wData,int x,int y,int cx,int cy,UINT uFlags); + WINUSERAPI LONG WINAPI TabbedTextOutA(HDC hdc,int x,int y,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); + WINUSERAPI LONG WINAPI TabbedTextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions,int nTabOrigin); + WINUSERAPI DWORD WINAPI GetTabbedTextExtentA(HDC hdc,LPCSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); + WINUSERAPI DWORD WINAPI GetTabbedTextExtentW(HDC hdc,LPCWSTR lpString,int chCount,int nTabPositions,CONST INT *lpnTabStopPositions); + WINUSERAPI WINBOOL WINAPI UpdateWindow(HWND hWnd); + WINUSERAPI HWND WINAPI SetActiveWindow(HWND hWnd); + WINUSERAPI HWND WINAPI GetForegroundWindow(VOID); + WINUSERAPI WINBOOL WINAPI PaintDesktop(HDC hdc); + WINUSERAPI VOID WINAPI SwitchToThisWindow(HWND hwnd,WINBOOL fUnknown); + WINUSERAPI WINBOOL WINAPI SetForegroundWindow(HWND hWnd); + WINUSERAPI WINBOOL WINAPI AllowSetForegroundWindow(DWORD dwProcessId); + +#define ASFW_ANY ((DWORD)-1) + + WINUSERAPI WINBOOL WINAPI LockSetForegroundWindow(UINT uLockCode); + +#define LSFW_LOCK 1 +#define LSFW_UNLOCK 2 + + WINUSERAPI HWND WINAPI WindowFromDC(HDC hDC); + WINUSERAPI HDC WINAPI GetDC(HWND hWnd); + WINUSERAPI HDC WINAPI GetDCEx(HWND hWnd,HRGN hrgnClip,DWORD flags); + +#define DCX_WINDOW 0x00000001L +#define DCX_CACHE 0x00000002L +#define DCX_NORESETATTRS 0x00000004L +#define DCX_CLIPCHILDREN 0x00000008L +#define DCX_CLIPSIBLINGS 0x00000010L +#define DCX_PARENTCLIP 0x00000020L +#define DCX_EXCLUDERGN 0x00000040L +#define DCX_INTERSECTRGN 0x00000080L +#define DCX_EXCLUDEUPDATE 0x00000100L +#define DCX_INTERSECTUPDATE 0x00000200L +#define DCX_LOCKWINDOWUPDATE 0x00000400L + +#define DCX_VALIDATE 0x00200000L + + WINUSERAPI HDC WINAPI GetWindowDC(HWND hWnd); + WINUSERAPI int WINAPI ReleaseDC(HWND hWnd,HDC hDC); + WINUSERAPI HDC WINAPI BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint); + WINUSERAPI WINBOOL WINAPI EndPaint(HWND hWnd,CONST PAINTSTRUCT *lpPaint); + WINUSERAPI WINBOOL WINAPI GetUpdateRect(HWND hWnd,LPRECT lpRect,WINBOOL bErase); + WINUSERAPI int WINAPI GetUpdateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); + WINUSERAPI int WINAPI SetWindowRgn(HWND hWnd,HRGN hRgn,WINBOOL bRedraw); + WINUSERAPI int WINAPI GetWindowRgn(HWND hWnd,HRGN hRgn); + WINUSERAPI int WINAPI GetWindowRgnBox(HWND hWnd,LPRECT lprc); + WINUSERAPI int WINAPI ExcludeUpdateRgn(HDC hDC,HWND hWnd); + WINUSERAPI WINBOOL WINAPI InvalidateRect(HWND hWnd,CONST RECT *lpRect,WINBOOL bErase); + WINUSERAPI WINBOOL WINAPI ValidateRect(HWND hWnd,CONST RECT *lpRect); + WINUSERAPI WINBOOL WINAPI InvalidateRgn(HWND hWnd,HRGN hRgn,WINBOOL bErase); + WINUSERAPI WINBOOL WINAPI ValidateRgn(HWND hWnd,HRGN hRgn); + WINUSERAPI WINBOOL WINAPI RedrawWindow(HWND hWnd,CONST RECT *lprcUpdate,HRGN hrgnUpdate,UINT flags); + +#define RDW_INVALIDATE 0x0001 +#define RDW_INTERNALPAINT 0x0002 +#define RDW_ERASE 0x0004 + +#define RDW_VALIDATE 0x0008 +#define RDW_NOINTERNALPAINT 0x0010 +#define RDW_NOERASE 0x0020 + +#define RDW_NOCHILDREN 0x0040 +#define RDW_ALLCHILDREN 0x0080 + +#define RDW_UPDATENOW 0x0100 +#define RDW_ERASENOW 0x0200 + +#define RDW_FRAME 0x0400 +#define RDW_NOFRAME 0x0800 + + WINUSERAPI WINBOOL WINAPI LockWindowUpdate(HWND hWndLock); + WINUSERAPI WINBOOL WINAPI ScrollWindow(HWND hWnd,int XAmount,int YAmount,CONST RECT *lpRect,CONST RECT *lpClipRect); + WINUSERAPI WINBOOL WINAPI ScrollDC(HDC hDC,int dx,int dy,CONST RECT *lprcScroll,CONST RECT *lprcClip,HRGN hrgnUpdate,LPRECT lprcUpdate); + WINUSERAPI int WINAPI ScrollWindowEx(HWND hWnd,int dx,int dy,CONST RECT *prcScroll,CONST RECT *prcClip,HRGN hrgnUpdate,LPRECT prcUpdate,UINT flags); + +#define SW_SCROLLCHILDREN 0x0001 +#define SW_INVALIDATE 0x0002 +#define SW_ERASE 0x0004 +#define SW_SMOOTHSCROLL 0x0010 + +#ifndef NOSCROLL + WINUSERAPI int WINAPI SetScrollPos(HWND hWnd,int nBar,int nPos,WINBOOL bRedraw); + WINUSERAPI int WINAPI GetScrollPos(HWND hWnd,int nBar); + WINUSERAPI WINBOOL WINAPI SetScrollRange(HWND hWnd,int nBar,int nMinPos,int nMaxPos,WINBOOL bRedraw); + WINUSERAPI WINBOOL WINAPI GetScrollRange(HWND hWnd,int nBar,LPINT lpMinPos,LPINT lpMaxPos); + WINUSERAPI WINBOOL WINAPI ShowScrollBar(HWND hWnd,int wBar,WINBOOL bShow); + WINUSERAPI WINBOOL WINAPI EnableScrollBar(HWND hWnd,UINT wSBflags,UINT wArrows); + +#define ESB_ENABLE_BOTH 0x0000 +#define ESB_DISABLE_BOTH 0x0003 + +#define ESB_DISABLE_LEFT 0x0001 +#define ESB_DISABLE_RIGHT 0x0002 + +#define ESB_DISABLE_UP 0x0001 +#define ESB_DISABLE_DOWN 0x0002 + +#define ESB_DISABLE_LTUP ESB_DISABLE_LEFT +#define ESB_DISABLE_RTDN ESB_DISABLE_RIGHT +#endif + +#ifdef UNICODE +#define SetProp SetPropW +#define GetProp GetPropW +#define RemoveProp RemovePropW +#define EnumPropsEx EnumPropsExW +#define EnumProps EnumPropsW +#define SetWindowText SetWindowTextW +#define GetWindowText GetWindowTextW +#define GetWindowTextLength GetWindowTextLengthW +#else +#define SetProp SetPropA +#define GetProp GetPropA +#define RemoveProp RemovePropA +#define EnumPropsEx EnumPropsExA +#define EnumProps EnumPropsA +#define SetWindowText SetWindowTextA +#define GetWindowText GetWindowTextA +#define GetWindowTextLength GetWindowTextLengthA +#endif + + WINUSERAPI WINBOOL WINAPI SetPropA(HWND hWnd,LPCSTR lpString,HANDLE hData); + WINUSERAPI WINBOOL WINAPI SetPropW(HWND hWnd,LPCWSTR lpString,HANDLE hData); + WINUSERAPI HANDLE WINAPI GetPropA(HWND hWnd,LPCSTR lpString); + WINUSERAPI HANDLE WINAPI GetPropW(HWND hWnd,LPCWSTR lpString); + WINUSERAPI HANDLE WINAPI RemovePropA(HWND hWnd,LPCSTR lpString); + WINUSERAPI HANDLE WINAPI RemovePropW(HWND hWnd,LPCWSTR lpString); + WINUSERAPI int WINAPI EnumPropsExA(HWND hWnd,PROPENUMPROCEXA lpEnumFunc,LPARAM lParam); + WINUSERAPI int WINAPI EnumPropsExW(HWND hWnd,PROPENUMPROCEXW lpEnumFunc,LPARAM lParam); + WINUSERAPI int WINAPI EnumPropsA(HWND hWnd,PROPENUMPROCA lpEnumFunc); + WINUSERAPI int WINAPI EnumPropsW(HWND hWnd,PROPENUMPROCW lpEnumFunc); + WINUSERAPI WINBOOL WINAPI SetWindowTextA(HWND hWnd,LPCSTR lpString); + WINUSERAPI WINBOOL WINAPI SetWindowTextW(HWND hWnd,LPCWSTR lpString); + WINUSERAPI int WINAPI GetWindowTextA(HWND hWnd,LPSTR lpString,int nMaxCount); + WINUSERAPI int WINAPI GetWindowTextW(HWND hWnd,LPWSTR lpString,int nMaxCount); + WINUSERAPI int WINAPI GetWindowTextLengthA(HWND hWnd); + WINUSERAPI int WINAPI GetWindowTextLengthW(HWND hWnd); + WINUSERAPI WINBOOL WINAPI GetClientRect(HWND hWnd,LPRECT lpRect); + WINUSERAPI WINBOOL WINAPI GetWindowRect(HWND hWnd,LPRECT lpRect); + WINUSERAPI WINBOOL WINAPI AdjustWindowRect(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu); + WINUSERAPI WINBOOL WINAPI AdjustWindowRectEx(LPRECT lpRect,DWORD dwStyle,WINBOOL bMenu,DWORD dwExStyle); + +#define HELPINFO_WINDOW 0x0001 +#define HELPINFO_MENUITEM 0x0002 + + typedef struct tagHELPINFO { + UINT cbSize; + int iContextType; + int iCtrlId; + HANDLE hItemHandle; + DWORD_PTR dwContextId; + POINT MousePos; + } HELPINFO,*LPHELPINFO; + + WINUSERAPI WINBOOL WINAPI SetWindowContextHelpId(HWND,DWORD); + WINUSERAPI DWORD WINAPI GetWindowContextHelpId(HWND); + WINUSERAPI WINBOOL WINAPI SetMenuContextHelpId(HMENU,DWORD); + WINUSERAPI DWORD WINAPI GetMenuContextHelpId(HMENU); + +#ifndef NOMB + +#define MB_OK 0x00000000L +#define MB_OKCANCEL 0x00000001L +#define MB_ABORTRETRYIGNORE 0x00000002L +#define MB_YESNOCANCEL 0x00000003L +#define MB_YESNO 0x00000004L +#define MB_RETRYCANCEL 0x00000005L +#define MB_CANCELTRYCONTINUE 0x00000006L +#define MB_ICONHAND 0x00000010L +#define MB_ICONQUESTION 0x00000020L +#define MB_ICONEXCLAMATION 0x00000030L +#define MB_ICONASTERISK 0x00000040L +#define MB_USERICON 0x00000080L +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND +#define MB_DEFBUTTON1 0x00000000L +#define MB_DEFBUTTON2 0x00000100L +#define MB_DEFBUTTON3 0x00000200L +#define MB_DEFBUTTON4 0x00000300L +#define MB_APPLMODAL 0x00000000L +#define MB_SYSTEMMODAL 0x00001000L +#define MB_TASKMODAL 0x00002000L +#define MB_HELP 0x00004000L +#define MB_NOFOCUS 0x00008000L +#define MB_SETFOREGROUND 0x00010000L +#define MB_DEFAULT_DESKTOP_ONLY 0x00020000L +#define MB_TOPMOST 0x00040000L +#define MB_RIGHT 0x00080000L +#define MB_RTLREADING 0x00100000L +#define MB_SERVICE_NOTIFICATION 0x00200000L +#define MB_SERVICE_NOTIFICATION_NT3X 0x00040000L +#define MB_TYPEMASK 0x0000000FL +#define MB_ICONMASK 0x000000F0L +#define MB_DEFMASK 0x00000F00L +#define MB_MODEMASK 0x00003000L +#define MB_MISCMASK 0x0000C000L + +#ifdef UNICODE +#define MessageBox MessageBoxW +#define MessageBoxEx MessageBoxExW +#else +#define MessageBox MessageBoxA +#define MessageBoxEx MessageBoxExA +#endif + + WINUSERAPI int WINAPI MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); + WINUSERAPI int WINAPI MessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); + WINUSERAPI int WINAPI MessageBoxExA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType,WORD wLanguageId); + WINUSERAPI int WINAPI MessageBoxExW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType,WORD wLanguageId); + + typedef VOID (CALLBACK *MSGBOXCALLBACK)(LPHELPINFO lpHelpInfo); + + typedef struct tagMSGBOXPARAMSA { + UINT cbSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCSTR lpszText; + LPCSTR lpszCaption; + DWORD dwStyle; + LPCSTR lpszIcon; + DWORD_PTR dwContextHelpId; + MSGBOXCALLBACK lpfnMsgBoxCallback; + DWORD dwLanguageId; + } MSGBOXPARAMSA,*PMSGBOXPARAMSA,*LPMSGBOXPARAMSA; + + typedef struct tagMSGBOXPARAMSW { + UINT cbSize; + HWND hwndOwner; + HINSTANCE hInstance; + LPCWSTR lpszText; + LPCWSTR lpszCaption; + DWORD dwStyle; + LPCWSTR lpszIcon; + DWORD_PTR dwContextHelpId; + MSGBOXCALLBACK lpfnMsgBoxCallback; + DWORD dwLanguageId; + } MSGBOXPARAMSW,*PMSGBOXPARAMSW,*LPMSGBOXPARAMSW; + +#ifdef UNICODE + typedef MSGBOXPARAMSW MSGBOXPARAMS; + typedef PMSGBOXPARAMSW PMSGBOXPARAMS; + typedef LPMSGBOXPARAMSW LPMSGBOXPARAMS; +#else + typedef MSGBOXPARAMSA MSGBOXPARAMS; + typedef PMSGBOXPARAMSA PMSGBOXPARAMS; + typedef LPMSGBOXPARAMSA LPMSGBOXPARAMS; +#endif + +#ifdef UNICODE +#define MessageBoxIndirect MessageBoxIndirectW +#else +#define MessageBoxIndirect MessageBoxIndirectA +#endif + + WINUSERAPI int WINAPI MessageBoxIndirectA(CONST MSGBOXPARAMSA *lpmbp); + WINUSERAPI int WINAPI MessageBoxIndirectW(CONST MSGBOXPARAMSW *lpmbp); + WINUSERAPI WINBOOL WINAPI MessageBeep(UINT uType); +#endif + + WINUSERAPI int WINAPI ShowCursor(WINBOOL bShow); + WINUSERAPI WINBOOL WINAPI SetCursorPos(int X,int Y); + WINUSERAPI HCURSOR WINAPI SetCursor(HCURSOR hCursor); + WINUSERAPI WINBOOL WINAPI GetCursorPos(LPPOINT lpPoint); + WINUSERAPI WINBOOL WINAPI ClipCursor(CONST RECT *lpRect); + WINUSERAPI WINBOOL WINAPI GetClipCursor(LPRECT lpRect); + WINUSERAPI HCURSOR WINAPI GetCursor(VOID); + WINUSERAPI WINBOOL WINAPI CreateCaret(HWND hWnd,HBITMAP hBitmap,int nWidth,int nHeight); + WINUSERAPI UINT WINAPI GetCaretBlinkTime(VOID); + WINUSERAPI WINBOOL WINAPI SetCaretBlinkTime(UINT uMSeconds); + WINUSERAPI WINBOOL WINAPI DestroyCaret(VOID); + WINUSERAPI WINBOOL WINAPI HideCaret(HWND hWnd); + WINUSERAPI WINBOOL WINAPI ShowCaret(HWND hWnd); + WINUSERAPI WINBOOL WINAPI SetCaretPos(int X,int Y); + WINUSERAPI WINBOOL WINAPI GetCaretPos(LPPOINT lpPoint); + WINUSERAPI WINBOOL WINAPI ClientToScreen(HWND hWnd,LPPOINT lpPoint); + WINUSERAPI WINBOOL WINAPI ScreenToClient(HWND hWnd,LPPOINT lpPoint); + WINUSERAPI int WINAPI MapWindowPoints(HWND hWndFrom,HWND hWndTo,LPPOINT lpPoints,UINT cPoints); + WINUSERAPI HWND WINAPI WindowFromPoint(POINT Point); + WINUSERAPI HWND WINAPI ChildWindowFromPoint(HWND hWndParent,POINT Point); + +#define CWP_ALL 0x0000 +#define CWP_SKIPINVISIBLE 0x0001 +#define CWP_SKIPDISABLED 0x0002 +#define CWP_SKIPTRANSPARENT 0x0004 + + WINUSERAPI HWND WINAPI ChildWindowFromPointEx(HWND hwnd,POINT pt,UINT flags); + +#ifndef NOCOLOR + +#define CTLCOLOR_MSGBOX 0 +#define CTLCOLOR_EDIT 1 +#define CTLCOLOR_LISTBOX 2 +#define CTLCOLOR_BTN 3 +#define CTLCOLOR_DLG 4 +#define CTLCOLOR_SCROLLBAR 5 +#define CTLCOLOR_STATIC 6 +#define CTLCOLOR_MAX 7 + +#define COLOR_SCROLLBAR 0 +#define COLOR_BACKGROUND 1 +#define COLOR_ACTIVECAPTION 2 +#define COLOR_INACTIVECAPTION 3 +#define COLOR_MENU 4 +#define COLOR_WINDOW 5 +#define COLOR_WINDOWFRAME 6 +#define COLOR_MENUTEXT 7 +#define COLOR_WINDOWTEXT 8 +#define COLOR_CAPTIONTEXT 9 +#define COLOR_ACTIVEBORDER 10 +#define COLOR_INACTIVEBORDER 11 +#define COLOR_APPWORKSPACE 12 +#define COLOR_HIGHLIGHT 13 +#define COLOR_HIGHLIGHTTEXT 14 +#define COLOR_BTNFACE 15 +#define COLOR_BTNSHADOW 16 +#define COLOR_GRAYTEXT 17 +#define COLOR_BTNTEXT 18 +#define COLOR_INACTIVECAPTIONTEXT 19 +#define COLOR_BTNHIGHLIGHT 20 + +#define COLOR_3DDKSHADOW 21 +#define COLOR_3DLIGHT 22 +#define COLOR_INFOTEXT 23 +#define COLOR_INFOBK 24 + +#define COLOR_HOTLIGHT 26 +#define COLOR_GRADIENTACTIVECAPTION 27 +#define COLOR_GRADIENTINACTIVECAPTION 28 +#define COLOR_MENUHILIGHT 29 +#define COLOR_MENUBAR 30 + +#define COLOR_DESKTOP COLOR_BACKGROUND +#define COLOR_3DFACE COLOR_BTNFACE +#define COLOR_3DSHADOW COLOR_BTNSHADOW +#define COLOR_3DHIGHLIGHT COLOR_BTNHIGHLIGHT +#define COLOR_3DHILIGHT COLOR_BTNHIGHLIGHT +#define COLOR_BTNHILIGHT COLOR_BTNHIGHLIGHT + + WINUSERAPI DWORD WINAPI GetSysColor(int nIndex); + WINUSERAPI HBRUSH WINAPI GetSysColorBrush(int nIndex); + WINUSERAPI WINBOOL WINAPI SetSysColors(int cElements,CONST INT *lpaElements,CONST COLORREF *lpaRgbValues); +#endif + + WINUSERAPI WINBOOL WINAPI DrawFocusRect(HDC hDC,CONST RECT *lprc); + WINUSERAPI int WINAPI FillRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); + WINUSERAPI int WINAPI FrameRect(HDC hDC,CONST RECT *lprc,HBRUSH hbr); + WINUSERAPI WINBOOL WINAPI InvertRect(HDC hDC,CONST RECT *lprc); + WINUSERAPI WINBOOL WINAPI SetRect(LPRECT lprc,int xLeft,int yTop,int xRight,int yBottom); + WINUSERAPI WINBOOL WINAPI SetRectEmpty(LPRECT lprc); + WINUSERAPI WINBOOL WINAPI CopyRect(LPRECT lprcDst,CONST RECT *lprcSrc); + WINUSERAPI WINBOOL WINAPI InflateRect(LPRECT lprc,int dx,int dy); + WINUSERAPI WINBOOL WINAPI IntersectRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); + WINUSERAPI WINBOOL WINAPI UnionRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); + WINUSERAPI WINBOOL WINAPI SubtractRect(LPRECT lprcDst,CONST RECT *lprcSrc1,CONST RECT *lprcSrc2); + WINUSERAPI WINBOOL WINAPI OffsetRect(LPRECT lprc,int dx,int dy); + WINUSERAPI WINBOOL WINAPI IsRectEmpty(CONST RECT *lprc); + WINUSERAPI WINBOOL WINAPI EqualRect(CONST RECT *lprc1,CONST RECT *lprc2); + WINUSERAPI WINBOOL WINAPI PtInRect(CONST RECT *lprc,POINT pt); + +#ifndef NOWINOFFSETS + +#ifdef UNICODE +#define GetWindowLong GetWindowLongW +#define SetWindowLong SetWindowLongW +#else +#define GetWindowLong GetWindowLongA +#define SetWindowLong SetWindowLongA +#endif + + WINUSERAPI WORD WINAPI GetWindowWord(HWND hWnd,int nIndex); + WINUSERAPI WORD WINAPI SetWindowWord(HWND hWnd,int nIndex,WORD wNewWord); + WINUSERAPI LONG WINAPI GetWindowLongA(HWND hWnd,int nIndex); + WINUSERAPI LONG WINAPI GetWindowLongW(HWND hWnd,int nIndex); + WINUSERAPI LONG WINAPI SetWindowLongA(HWND hWnd,int nIndex,LONG dwNewLong); + WINUSERAPI LONG WINAPI SetWindowLongW(HWND hWnd,int nIndex,LONG dwNewLong); + +#ifdef _WIN64 + +#ifdef UNICODE +#define GetWindowLongPtr GetWindowLongPtrW +#define SetWindowLongPtr SetWindowLongPtrW +#else +#define GetWindowLongPtr GetWindowLongPtrA +#define SetWindowLongPtr SetWindowLongPtrA +#endif + + WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrA(HWND hWnd,int nIndex); + WINUSERAPI LONG_PTR WINAPI GetWindowLongPtrW(HWND hWnd,int nIndex); + WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); + WINUSERAPI LONG_PTR WINAPI SetWindowLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); +#else + +#ifdef UNICODE +#define GetWindowLongPtr GetWindowLongPtrW +#define SetWindowLongPtr SetWindowLongPtrW +#else +#define GetWindowLongPtr GetWindowLongPtrA +#define SetWindowLongPtr SetWindowLongPtrA +#endif + +#define GetWindowLongPtrA GetWindowLongA +#define GetWindowLongPtrW GetWindowLongW +#define SetWindowLongPtrA SetWindowLongA +#define SetWindowLongPtrW SetWindowLongW +#endif + +#ifdef UNICODE +#define GetClassLong GetClassLongW +#define SetClassLong SetClassLongW +#else +#define GetClassLong GetClassLongA +#define SetClassLong SetClassLongA +#endif + + WINUSERAPI WORD WINAPI GetClassWord(HWND hWnd,int nIndex); + WINUSERAPI WORD WINAPI SetClassWord(HWND hWnd,int nIndex,WORD wNewWord); + WINUSERAPI DWORD WINAPI GetClassLongA(HWND hWnd,int nIndex); + WINUSERAPI DWORD WINAPI GetClassLongW(HWND hWnd,int nIndex); + WINUSERAPI DWORD WINAPI SetClassLongA(HWND hWnd,int nIndex,LONG dwNewLong); + WINUSERAPI DWORD WINAPI SetClassLongW(HWND hWnd,int nIndex,LONG dwNewLong); + +#ifdef _WIN64 + +#ifdef UNICODE +#define GetClassLongPtr GetClassLongPtrW +#define SetClassLongPtr SetClassLongPtrW +#else +#define GetClassLongPtr GetClassLongPtrA +#define SetClassLongPtr SetClassLongPtrA +#endif + + WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrA(HWND hWnd,int nIndex); + WINUSERAPI ULONG_PTR WINAPI GetClassLongPtrW(HWND hWnd,int nIndex); + WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong); + WINUSERAPI ULONG_PTR WINAPI SetClassLongPtrW(HWND hWnd,int nIndex,LONG_PTR dwNewLong); +#else +#ifdef UNICODE +#define GetClassLongPtr GetClassLongPtrW +#define SetClassLongPtr SetClassLongPtrW +#else +#define GetClassLongPtr GetClassLongPtrA +#define SetClassLongPtr SetClassLongPtrA +#endif + +#define GetClassLongPtrA GetClassLongA +#define GetClassLongPtrW GetClassLongW +#define SetClassLongPtrA SetClassLongA +#define SetClassLongPtrW SetClassLongW +#endif +#endif + +#ifdef UNICODE +#define FindWindow FindWindowW +#define FindWindowEx FindWindowExW +#define GetClassName GetClassNameW +#else +#define FindWindow FindWindowA +#define FindWindowEx FindWindowExA +#define GetClassName GetClassNameA +#endif + + WINUSERAPI WINBOOL WINAPI GetProcessDefaultLayout(DWORD *pdwDefaultLayout); + WINUSERAPI WINBOOL WINAPI SetProcessDefaultLayout(DWORD dwDefaultLayout); + WINUSERAPI HWND WINAPI GetDesktopWindow(VOID); + WINUSERAPI HWND WINAPI GetParent(HWND hWnd); + WINUSERAPI HWND WINAPI SetParent(HWND hWndChild,HWND hWndNewParent); + WINUSERAPI WINBOOL WINAPI EnumChildWindows(HWND hWndParent,WNDENUMPROC lpEnumFunc,LPARAM lParam); + WINUSERAPI HWND WINAPI FindWindowA(LPCSTR lpClassName,LPCSTR lpWindowName); + WINUSERAPI HWND WINAPI FindWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName); + WINUSERAPI HWND WINAPI FindWindowExA(HWND hWndParent,HWND hWndChildAfter,LPCSTR lpszClass,LPCSTR lpszWindow); + WINUSERAPI HWND WINAPI FindWindowExW(HWND hWndParent,HWND hWndChildAfter,LPCWSTR lpszClass,LPCWSTR lpszWindow); + WINUSERAPI HWND WINAPI GetShellWindow(VOID); + WINUSERAPI WINBOOL WINAPI RegisterShellHookWindow(HWND hwnd); + WINUSERAPI WINBOOL WINAPI DeregisterShellHookWindow(HWND hwnd); + WINUSERAPI WINBOOL WINAPI EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam); + WINUSERAPI WINBOOL WINAPI EnumThreadWindows(DWORD dwThreadId,WNDENUMPROC lpfn,LPARAM lParam); + +#define EnumTaskWindows(hTask,lpfn,lParam) EnumThreadWindows(HandleToUlong(hTask),lpfn,lParam) + + WINUSERAPI int WINAPI GetClassNameA(HWND hWnd,LPSTR lpClassName,int nMaxCount); + WINUSERAPI int WINAPI GetClassNameW(HWND hWnd,LPWSTR lpClassName,int nMaxCount); + WINUSERAPI HWND WINAPI GetTopWindow(HWND hWnd); + +#define GetNextWindow(hWnd,wCmd) GetWindow(hWnd,wCmd) +#define GetSysModalWindow() (NULL) +#define SetSysModalWindow(hWnd) (NULL) + + WINUSERAPI DWORD WINAPI GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId); + WINUSERAPI WINBOOL WINAPI IsGUIThread(WINBOOL bConvert); + +#define GetWindowTask(hWnd) ((HANDLE)(DWORD_PTR)GetWindowThreadProcessId(hWnd,NULL)) + + WINUSERAPI HWND WINAPI GetLastActivePopup(HWND hWnd); + +#define GW_HWNDFIRST 0 +#define GW_HWNDLAST 1 +#define GW_HWNDNEXT 2 +#define GW_HWNDPREV 3 +#define GW_OWNER 4 +#define GW_CHILD 5 +#define GW_ENABLEDPOPUP 6 +#define GW_MAX 6 + + WINUSERAPI HWND WINAPI GetWindow(HWND hWnd,UINT uCmd); + +#ifndef NOWH + +#ifdef UNICODE +#define SetWindowsHook SetWindowsHookW +#define SetWindowsHookEx SetWindowsHookExW +#else +#define SetWindowsHook SetWindowsHookA +#define SetWindowsHookEx SetWindowsHookExA +#endif + + WINUSERAPI HHOOK WINAPI SetWindowsHookA(int nFilterType,HOOKPROC pfnFilterProc); + WINUSERAPI HHOOK WINAPI SetWindowsHookW(int nFilterType,HOOKPROC pfnFilterProc); + WINUSERAPI WINBOOL WINAPI UnhookWindowsHook(int nCode,HOOKPROC pfnFilterProc); + WINUSERAPI HHOOK WINAPI SetWindowsHookExA(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); + WINUSERAPI HHOOK WINAPI SetWindowsHookExW(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId); + WINUSERAPI WINBOOL WINAPI UnhookWindowsHookEx(HHOOK hhk); + WINUSERAPI LRESULT WINAPI CallNextHookEx(HHOOK hhk,int nCode,WPARAM wParam,LPARAM lParam); +#define DefHookProc(nCode,wParam,lParam,phhk) CallNextHookEx(*phhk,nCode,wParam,lParam) +#endif + +#ifndef NOMENUS + +#define MF_INSERT 0x00000000L +#define MF_CHANGE 0x00000080L +#define MF_APPEND 0x00000100L +#define MF_DELETE 0x00000200L +#define MF_REMOVE 0x00001000L +#define MF_BYCOMMAND 0x00000000L +#define MF_BYPOSITION 0x00000400L +#define MF_SEPARATOR 0x00000800L +#define MF_ENABLED 0x00000000L +#define MF_GRAYED 0x00000001L +#define MF_DISABLED 0x00000002L +#define MF_UNCHECKED 0x00000000L +#define MF_CHECKED 0x00000008L +#define MF_USECHECKBITMAPS 0x00000200L +#define MF_STRING 0x00000000L +#define MF_BITMAP 0x00000004L +#define MF_OWNERDRAW 0x00000100L +#define MF_POPUP 0x00000010L +#define MF_MENUBARBREAK 0x00000020L +#define MF_MENUBREAK 0x00000040L +#define MF_UNHILITE 0x00000000L +#define MF_HILITE 0x00000080L +#define MF_DEFAULT 0x00001000L +#define MF_SYSMENU 0x00002000L +#define MF_HELP 0x00004000L +#define MF_RIGHTJUSTIFY 0x00004000L +#define MF_MOUSESELECT 0x00008000L +#define MF_END 0x00000080L + +#define MFT_STRING MF_STRING +#define MFT_BITMAP MF_BITMAP +#define MFT_MENUBARBREAK MF_MENUBARBREAK +#define MFT_MENUBREAK MF_MENUBREAK +#define MFT_OWNERDRAW MF_OWNERDRAW +#define MFT_RADIOCHECK 0x00000200L +#define MFT_SEPARATOR MF_SEPARATOR +#define MFT_RIGHTORDER 0x00002000L +#define MFT_RIGHTJUSTIFY MF_RIGHTJUSTIFY + +#define MFS_GRAYED 0x00000003L +#define MFS_DISABLED MFS_GRAYED +#define MFS_CHECKED MF_CHECKED +#define MFS_HILITE MF_HILITE +#define MFS_ENABLED MF_ENABLED +#define MFS_UNCHECKED MF_UNCHECKED +#define MFS_UNHILITE MF_UNHILITE +#define MFS_DEFAULT MF_DEFAULT + + WINUSERAPI WINBOOL WINAPI CheckMenuRadioItem(HMENU hmenu,UINT first,UINT last,UINT check,UINT flags); + + typedef struct { + WORD versionNumber; + WORD offset; + } MENUITEMTEMPLATEHEADER,*PMENUITEMTEMPLATEHEADER; + + typedef struct { + WORD mtOption; + WORD mtID; + WCHAR mtString[1]; + } MENUITEMTEMPLATE,*PMENUITEMTEMPLATE; +#define MF_END 0x00000080L +#endif + +#ifndef NOSYSCOMMANDS + +#define SC_SIZE 0xF000 +#define SC_MOVE 0xF010 +#define SC_MINIMIZE 0xF020 +#define SC_MAXIMIZE 0xF030 +#define SC_NEXTWINDOW 0xF040 +#define SC_PREVWINDOW 0xF050 +#define SC_CLOSE 0xF060 +#define SC_VSCROLL 0xF070 +#define SC_HSCROLL 0xF080 +#define SC_MOUSEMENU 0xF090 +#define SC_KEYMENU 0xF100 +#define SC_ARRANGE 0xF110 +#define SC_RESTORE 0xF120 +#define SC_TASKLIST 0xF130 +#define SC_SCREENSAVE 0xF140 +#define SC_HOTKEY 0xF150 +#define SC_DEFAULT 0xF160 +#define SC_MONITORPOWER 0xF170 +#define SC_CONTEXTHELP 0xF180 +#define SC_SEPARATOR 0xF00F +#define SC_ICON SC_MINIMIZE +#define SC_ZOOM SC_MAXIMIZE +#endif + +#ifdef UNICODE +#define LoadBitmap LoadBitmapW +#define LoadCursor LoadCursorW +#define LoadCursorFromFile LoadCursorFromFileW +#else +#define LoadBitmap LoadBitmapA +#define LoadCursor LoadCursorA +#define LoadCursorFromFile LoadCursorFromFileA +#endif + + WINUSERAPI HBITMAP WINAPI LoadBitmapA(HINSTANCE hInstance,LPCSTR lpBitmapName); + WINUSERAPI HBITMAP WINAPI LoadBitmapW(HINSTANCE hInstance,LPCWSTR lpBitmapName); + WINUSERAPI HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance,LPCSTR lpCursorName); + WINUSERAPI HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance,LPCWSTR lpCursorName); + WINUSERAPI HCURSOR WINAPI LoadCursorFromFileA(LPCSTR lpFileName); + WINUSERAPI HCURSOR WINAPI LoadCursorFromFileW(LPCWSTR lpFileName); + WINUSERAPI HCURSOR WINAPI CreateCursor(HINSTANCE hInst,int xHotSpot,int yHotSpot,int nWidth,int nHeight,CONST VOID *pvANDPlane,CONST VOID *pvXORPlane); + WINUSERAPI WINBOOL WINAPI DestroyCursor(HCURSOR hCursor); + +#define CopyCursor(pcur) ((HCURSOR)CopyIcon((HICON)(pcur))) + +#define IDC_ARROW MAKEINTRESOURCE(32512) +#define IDC_IBEAM MAKEINTRESOURCE(32513) +#define IDC_WAIT MAKEINTRESOURCE(32514) +#define IDC_CROSS MAKEINTRESOURCE(32515) +#define IDC_UPARROW MAKEINTRESOURCE(32516) +#define IDC_SIZE MAKEINTRESOURCE(32640) +#define IDC_ICON MAKEINTRESOURCE(32641) +#define IDC_SIZENWSE MAKEINTRESOURCE(32642) +#define IDC_SIZENESW MAKEINTRESOURCE(32643) +#define IDC_SIZEWE MAKEINTRESOURCE(32644) +#define IDC_SIZENS MAKEINTRESOURCE(32645) +#define IDC_SIZEALL MAKEINTRESOURCE(32646) +#define IDC_NO MAKEINTRESOURCE(32648) +#define IDC_HAND MAKEINTRESOURCE(32649) +#define IDC_APPSTARTING MAKEINTRESOURCE(32650) +#define IDC_HELP MAKEINTRESOURCE(32651) + + WINUSERAPI WINBOOL WINAPI SetSystemCursor(HCURSOR hcur,DWORD id); + + typedef struct _ICONINFO { + WINBOOL fIcon; + DWORD xHotspot; + DWORD yHotspot; + HBITMAP hbmMask; + HBITMAP hbmColor; + } ICONINFO; + typedef ICONINFO *PICONINFO; + +#ifdef UNICODE +#define LoadIcon LoadIconW +#define PrivateExtractIcons PrivateExtractIconsW +#else +#define LoadIcon LoadIconA +#define PrivateExtractIcons PrivateExtractIconsA +#endif + + WINUSERAPI HICON WINAPI LoadIconA(HINSTANCE hInstance,LPCSTR lpIconName); + WINUSERAPI HICON WINAPI LoadIconW(HINSTANCE hInstance,LPCWSTR lpIconName); + WINUSERAPI UINT WINAPI PrivateExtractIconsA(LPCSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); + WINUSERAPI UINT WINAPI PrivateExtractIconsW(LPCWSTR szFileName,int nIconIndex,int cxIcon,int cyIcon,HICON *phicon,UINT *piconid,UINT nIcons,UINT flags); + WINUSERAPI HICON WINAPI CreateIcon(HINSTANCE hInstance,int nWidth,int nHeight,BYTE cPlanes,BYTE cBitsPixel,CONST BYTE *lpbANDbits,CONST BYTE *lpbXORbits); + WINUSERAPI WINBOOL WINAPI DestroyIcon(HICON hIcon); + WINUSERAPI int WINAPI LookupIconIdFromDirectory(PBYTE presbits,WINBOOL fIcon); + WINUSERAPI int WINAPI LookupIconIdFromDirectoryEx(PBYTE presbits,WINBOOL fIcon,int cxDesired,int cyDesired,UINT Flags); + WINUSERAPI HICON WINAPI CreateIconFromResource(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer); + WINUSERAPI HICON WINAPI CreateIconFromResourceEx(PBYTE presbits,DWORD dwResSize,WINBOOL fIcon,DWORD dwVer,int cxDesired,int cyDesired,UINT Flags); + + typedef struct tagCURSORSHAPE { + int xHotSpot; + int yHotSpot; + int cx; + int cy; + int cbWidth; + BYTE Planes; + BYTE BitsPixel; + } CURSORSHAPE,*LPCURSORSHAPE; + +#define IMAGE_BITMAP 0 +#define IMAGE_ICON 1 +#define IMAGE_CURSOR 2 +#define IMAGE_ENHMETAFILE 3 + +#define LR_DEFAULTCOLOR 0x0000 +#define LR_MONOCHROME 0x0001 +#define LR_COLOR 0x0002 +#define LR_COPYRETURNORG 0x0004 +#define LR_COPYDELETEORG 0x0008 +#define LR_LOADFROMFILE 0x0010 +#define LR_LOADTRANSPARENT 0x0020 +#define LR_DEFAULTSIZE 0x0040 +#define LR_VGACOLOR 0x0080 +#define LR_LOADMAP3DCOLORS 0x1000 +#define LR_CREATEDIBSECTION 0x2000 +#define LR_COPYFROMRESOURCE 0x4000 +#define LR_SHARED 0x8000 + +#ifdef UNICODE +#define LoadImage LoadImageW +#else +#define LoadImage LoadImageA +#endif + + WINUSERAPI HANDLE WINAPI LoadImageA(HINSTANCE hInst,LPCSTR name,UINT type,int cx,int cy,UINT fuLoad); + WINUSERAPI HANDLE WINAPI LoadImageW(HINSTANCE hInst,LPCWSTR name,UINT type,int cx,int cy,UINT fuLoad); + WINUSERAPI HANDLE WINAPI CopyImage(HANDLE h,UINT type,int cx,int cy,UINT flags); + +#define DI_MASK 0x0001 +#define DI_IMAGE 0x0002 +#define DI_NORMAL 0x0003 +#define DI_COMPAT 0x0004 +#define DI_DEFAULTSIZE 0x0008 +#define DI_NOMIRROR 0x0010 + + WINUSERAPI WINBOOL WINAPI DrawIconEx(HDC hdc,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyWidth,UINT istepIfAniCur,HBRUSH hbrFlickerFreeDraw,UINT diFlags); + WINUSERAPI HICON WINAPI CreateIconIndirect(PICONINFO piconinfo); + WINUSERAPI HICON WINAPI CopyIcon(HICON hIcon); + WINUSERAPI WINBOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO piconinfo); + +#define RES_ICON 1 +#define RES_CURSOR 2 + +#ifdef OEMRESOURCE + +#define OBM_CLOSE 32754 +#define OBM_UPARROW 32753 +#define OBM_DNARROW 32752 +#define OBM_RGARROW 32751 +#define OBM_LFARROW 32750 +#define OBM_REDUCE 32749 +#define OBM_ZOOM 32748 +#define OBM_RESTORE 32747 +#define OBM_REDUCED 32746 +#define OBM_ZOOMD 32745 +#define OBM_RESTORED 32744 +#define OBM_UPARROWD 32743 +#define OBM_DNARROWD 32742 +#define OBM_RGARROWD 32741 +#define OBM_LFARROWD 32740 +#define OBM_MNARROW 32739 +#define OBM_COMBO 32738 +#define OBM_UPARROWI 32737 +#define OBM_DNARROWI 32736 +#define OBM_RGARROWI 32735 +#define OBM_LFARROWI 32734 + +#define OBM_OLD_CLOSE 32767 +#define OBM_SIZE 32766 +#define OBM_OLD_UPARROW 32765 +#define OBM_OLD_DNARROW 32764 +#define OBM_OLD_RGARROW 32763 +#define OBM_OLD_LFARROW 32762 +#define OBM_BTSIZE 32761 +#define OBM_CHECK 32760 +#define OBM_CHECKBOXES 32759 +#define OBM_BTNCORNERS 32758 +#define OBM_OLD_REDUCE 32757 +#define OBM_OLD_ZOOM 32756 +#define OBM_OLD_RESTORE 32755 + +#define OCR_NORMAL 32512 +#define OCR_IBEAM 32513 +#define OCR_WAIT 32514 +#define OCR_CROSS 32515 +#define OCR_UP 32516 +#define OCR_SIZE 32640 +#define OCR_ICON 32641 +#define OCR_SIZENWSE 32642 +#define OCR_SIZENESW 32643 +#define OCR_SIZEWE 32644 +#define OCR_SIZENS 32645 +#define OCR_SIZEALL 32646 +#define OCR_ICOCUR 32647 +#define OCR_NO 32648 +#define OCR_HAND 32649 +#define OCR_APPSTARTING 32650 + +#define OIC_SAMPLE 32512 +#define OIC_HAND 32513 +#define OIC_QUES 32514 +#define OIC_BANG 32515 +#define OIC_NOTE 32516 +#define OIC_WINLOGO 32517 +#define OIC_WARNING OIC_BANG +#define OIC_ERROR OIC_HAND +#define OIC_INFORMATION OIC_NOTE +#endif + +#define ORD_LANGDRIVER 1 + +#ifndef NOICONS + +#ifdef RC_INVOKED +#define IDI_APPLICATION 32512 +#define IDI_HAND 32513 +#define IDI_QUESTION 32514 +#define IDI_EXCLAMATION 32515 +#define IDI_ASTERISK 32516 +#define IDI_WINLOGO 32517 +#else +#define IDI_APPLICATION MAKEINTRESOURCE(32512) +#define IDI_HAND MAKEINTRESOURCE(32513) +#define IDI_QUESTION MAKEINTRESOURCE(32514) +#define IDI_EXCLAMATION MAKEINTRESOURCE(32515) +#define IDI_ASTERISK MAKEINTRESOURCE(32516) +#define IDI_WINLOGO MAKEINTRESOURCE(32517) +#endif + +#define IDI_WARNING IDI_EXCLAMATION +#define IDI_ERROR IDI_HAND +#define IDI_INFORMATION IDI_ASTERISK +#endif + +#ifdef UNICODE +#define LoadString LoadStringW +#else +#define LoadString LoadStringA +#endif + + WINUSERAPI int WINAPI LoadStringA(HINSTANCE hInstance,UINT uID,LPSTR lpBuffer,int cchBufferMax); + WINUSERAPI int WINAPI LoadStringW(HINSTANCE hInstance,UINT uID,LPWSTR lpBuffer,int cchBufferMax); + +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 +#define IDCLOSE 8 +#define IDHELP 9 +#define IDTRYAGAIN 10 +#define IDCONTINUE 11 + +#ifndef IDTIMEOUT +#define IDTIMEOUT 32000 +#endif + +#ifndef NOCTLMGR + +#ifndef NOWINSTYLES +#define ES_LEFT 0x0000L +#define ES_CENTER 0x0001L +#define ES_RIGHT 0x0002L +#define ES_MULTILINE 0x0004L +#define ES_UPPERCASE 0x0008L +#define ES_LOWERCASE 0x0010L +#define ES_PASSWORD 0x0020L +#define ES_AUTOVSCROLL 0x0040L +#define ES_AUTOHSCROLL 0x0080L +#define ES_NOHIDESEL 0x0100L +#define ES_OEMCONVERT 0x0400L +#define ES_READONLY 0x0800L +#define ES_WANTRETURN 0x1000L +#define ES_NUMBER 0x2000L +#endif + +#define EN_SETFOCUS 0x0100 +#define EN_KILLFOCUS 0x0200 +#define EN_CHANGE 0x0300 +#define EN_UPDATE 0x0400 +#define EN_ERRSPACE 0x0500 +#define EN_MAXTEXT 0x0501 +#define EN_HSCROLL 0x0601 +#define EN_VSCROLL 0x0602 +#define EN_ALIGN_LTR_EC 0x0700 +#define EN_ALIGN_RTL_EC 0x0701 + +#define EC_LEFTMARGIN 0x0001 +#define EC_RIGHTMARGIN 0x0002 +#define EC_USEFONTINFO 0xffff + +#define EMSIS_COMPOSITIONSTRING 0x0001 + +#define EIMES_GETCOMPSTRATONCE 0x0001 +#define EIMES_CANCELCOMPSTRINFOCUS 0x0002 +#define EIMES_COMPLETECOMPSTRKILLFOCUS 0x0004 + +#ifndef NOWINMESSAGES + +#define EM_GETSEL 0x00B0 +#define EM_SETSEL 0x00B1 +#define EM_GETRECT 0x00B2 +#define EM_SETRECT 0x00B3 +#define EM_SETRECTNP 0x00B4 +#define EM_SCROLL 0x00B5 +#define EM_LINESCROLL 0x00B6 +#define EM_SCROLLCARET 0x00B7 +#define EM_GETMODIFY 0x00B8 +#define EM_SETMODIFY 0x00B9 +#define EM_GETLINECOUNT 0x00BA +#define EM_LINEINDEX 0x00BB +#define EM_SETHANDLE 0x00BC +#define EM_GETHANDLE 0x00BD +#define EM_GETTHUMB 0x00BE +#define EM_LINELENGTH 0x00C1 +#define EM_REPLACESEL 0x00C2 +#define EM_GETLINE 0x00C4 +#define EM_LIMITTEXT 0x00C5 +#define EM_CANUNDO 0x00C6 +#define EM_UNDO 0x00C7 +#define EM_FMTLINES 0x00C8 +#define EM_LINEFROMCHAR 0x00C9 +#define EM_SETTABSTOPS 0x00CB +#define EM_SETPASSWORDCHAR 0x00CC +#define EM_EMPTYUNDOBUFFER 0x00CD +#define EM_GETFIRSTVISIBLELINE 0x00CE +#define EM_SETREADONLY 0x00CF +#define EM_SETWORDBREAKPROC 0x00D0 +#define EM_GETWORDBREAKPROC 0x00D1 +#define EM_GETPASSWORDCHAR 0x00D2 +#define EM_SETMARGINS 0x00D3 +#define EM_GETMARGINS 0x00D4 +#define EM_SETLIMITTEXT EM_LIMITTEXT +#define EM_GETLIMITTEXT 0x00D5 +#define EM_POSFROMCHAR 0x00D6 +#define EM_CHARFROMPOS 0x00D7 +#define EM_SETIMESTATUS 0x00D8 +#define EM_GETIMESTATUS 0x00D9 +#endif + +#define WB_LEFT 0 +#define WB_RIGHT 1 +#define WB_ISDELIMITER 2 + +#define BS_PUSHBUTTON 0x00000000L +#define BS_DEFPUSHBUTTON 0x00000001L +#define BS_CHECKBOX 0x00000002L +#define BS_AUTOCHECKBOX 0x00000003L +#define BS_RADIOBUTTON 0x00000004L +#define BS_3STATE 0x00000005L +#define BS_AUTO3STATE 0x00000006L +#define BS_GROUPBOX 0x00000007L +#define BS_USERBUTTON 0x00000008L +#define BS_AUTORADIOBUTTON 0x00000009L +#define BS_PUSHBOX 0x0000000AL +#define BS_OWNERDRAW 0x0000000BL +#define BS_TYPEMASK 0x0000000FL +#define BS_LEFTTEXT 0x00000020L +#define BS_TEXT 0x00000000L +#define BS_ICON 0x00000040L +#define BS_BITMAP 0x00000080L +#define BS_LEFT 0x00000100L +#define BS_RIGHT 0x00000200L +#define BS_CENTER 0x00000300L +#define BS_TOP 0x00000400L +#define BS_BOTTOM 0x00000800L +#define BS_VCENTER 0x00000C00L +#define BS_PUSHLIKE 0x00001000L +#define BS_MULTILINE 0x00002000L +#define BS_NOTIFY 0x00004000L +#define BS_FLAT 0x00008000L +#define BS_RIGHTBUTTON BS_LEFTTEXT + +#define BN_CLICKED 0 +#define BN_PAINT 1 +#define BN_HILITE 2 +#define BN_UNHILITE 3 +#define BN_DISABLE 4 +#define BN_DOUBLECLICKED 5 +#define BN_PUSHED BN_HILITE +#define BN_UNPUSHED BN_UNHILITE +#define BN_DBLCLK BN_DOUBLECLICKED +#define BN_SETFOCUS 6 +#define BN_KILLFOCUS 7 + +#define BM_GETCHECK 0x00F0 +#define BM_SETCHECK 0x00F1 +#define BM_GETSTATE 0x00F2 +#define BM_SETSTATE 0x00F3 +#define BM_SETSTYLE 0x00F4 +#define BM_CLICK 0x00F5 +#define BM_GETIMAGE 0x00F6 +#define BM_SETIMAGE 0x00F7 + +#define BST_UNCHECKED 0x0000 +#define BST_CHECKED 0x0001 +#define BST_INDETERMINATE 0x0002 +#define BST_PUSHED 0x0004 +#define BST_FOCUS 0x0008 + +#define SS_LEFT 0x00000000L +#define SS_CENTER 0x00000001L +#define SS_RIGHT 0x00000002L +#define SS_ICON 0x00000003L +#define SS_BLACKRECT 0x00000004L +#define SS_GRAYRECT 0x00000005L +#define SS_WHITERECT 0x00000006L +#define SS_BLACKFRAME 0x00000007L +#define SS_GRAYFRAME 0x00000008L +#define SS_WHITEFRAME 0x00000009L +#define SS_USERITEM 0x0000000AL +#define SS_SIMPLE 0x0000000BL +#define SS_LEFTNOWORDWRAP 0x0000000CL +#define SS_OWNERDRAW 0x0000000DL +#define SS_BITMAP 0x0000000EL +#define SS_ENHMETAFILE 0x0000000FL +#define SS_ETCHEDHORZ 0x00000010L +#define SS_ETCHEDVERT 0x00000011L +#define SS_ETCHEDFRAME 0x00000012L +#define SS_TYPEMASK 0x0000001FL +#define SS_REALSIZECONTROL 0x00000040L +#define SS_NOPREFIX 0x00000080L +#define SS_NOTIFY 0x00000100L +#define SS_CENTERIMAGE 0x00000200L +#define SS_RIGHTJUST 0x00000400L +#define SS_REALSIZEIMAGE 0x00000800L +#define SS_SUNKEN 0x00001000L +#define SS_EDITCONTROL 0x00002000L +#define SS_ENDELLIPSIS 0x00004000L +#define SS_PATHELLIPSIS 0x00008000L +#define SS_WORDELLIPSIS 0x0000C000L +#define SS_ELLIPSISMASK 0x0000C000L + +#ifndef NOWINMESSAGES + +#define STM_SETICON 0x0170 +#define STM_GETICON 0x0171 +#define STM_SETIMAGE 0x0172 +#define STM_GETIMAGE 0x0173 +#define STN_CLICKED 0 +#define STN_DBLCLK 1 +#define STN_ENABLE 2 +#define STN_DISABLE 3 +#define STM_MSGMAX 0x0174 +#endif + +#define WC_DIALOG (MAKEINTATOM(0x8002)) + +#define DWL_MSGRESULT 0 +#define DWL_DLGPROC 4 +#define DWL_USER 8 + +#ifdef _WIN64 + +#undef DWL_MSGRESULT +#undef DWL_DLGPROC +#undef DWL_USER +#endif + +#define DWLP_MSGRESULT 0 +#define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) +#define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) + +#ifndef NOMSG + +#ifdef UNICODE +#define IsDialogMessage IsDialogMessageW +#else +#define IsDialogMessage IsDialogMessageA +#endif + + WINUSERAPI WINBOOL WINAPI IsDialogMessageA(HWND hDlg,LPMSG lpMsg); + WINUSERAPI WINBOOL WINAPI IsDialogMessageW(HWND hDlg,LPMSG lpMsg); +#endif + +#ifdef UNICODE +#define DlgDirList DlgDirListW +#define DlgDirSelectEx DlgDirSelectExW +#define DlgDirListComboBox DlgDirListComboBoxW +#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExW +#else +#define DlgDirList DlgDirListA +#define DlgDirSelectEx DlgDirSelectExA +#define DlgDirListComboBox DlgDirListComboBoxA +#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExA +#endif + + WINUSERAPI WINBOOL WINAPI MapDialogRect(HWND hDlg,LPRECT lpRect); + WINUSERAPI int WINAPI DlgDirListA(HWND hDlg,LPSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); + WINUSERAPI int WINAPI DlgDirListW(HWND hDlg,LPWSTR lpPathSpec,int nIDListBox,int nIDStaticPath,UINT uFileType); + +#define DDL_READWRITE 0x0000 +#define DDL_READONLY 0x0001 +#define DDL_HIDDEN 0x0002 +#define DDL_SYSTEM 0x0004 +#define DDL_DIRECTORY 0x0010 +#define DDL_ARCHIVE 0x0020 + +#define DDL_POSTMSGS 0x2000 +#define DDL_DRIVES 0x4000 +#define DDL_EXCLUSIVE 0x8000 + + WINUSERAPI WINBOOL WINAPI DlgDirSelectExA(HWND hwndDlg,LPSTR lpString,int chCount,int idListBox); + WINUSERAPI WINBOOL WINAPI DlgDirSelectExW(HWND hwndDlg,LPWSTR lpString,int chCount,int idListBox); + WINUSERAPI int WINAPI DlgDirListComboBoxA(HWND hDlg,LPSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); + WINUSERAPI int WINAPI DlgDirListComboBoxW(HWND hDlg,LPWSTR lpPathSpec,int nIDComboBox,int nIDStaticPath,UINT uFiletype); + WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExA(HWND hwndDlg,LPSTR lpString,int cchOut,int idComboBox); + WINUSERAPI WINBOOL WINAPI DlgDirSelectComboBoxExW(HWND hwndDlg,LPWSTR lpString,int cchOut,int idComboBox); + +#define DS_ABSALIGN 0x01L +#define DS_SYSMODAL 0x02L +#define DS_LOCALEDIT 0x20L +#define DS_SETFONT 0x40L +#define DS_MODALFRAME 0x80L +#define DS_NOIDLEMSG 0x100L +#define DS_SETFOREGROUND 0x200L + +#define DS_3DLOOK 0x0004L +#define DS_FIXEDSYS 0x0008L +#define DS_NOFAILCREATE 0x0010L +#define DS_CONTROL 0x0400L +#define DS_CENTER 0x0800L +#define DS_CENTERMOUSE 0x1000L +#define DS_CONTEXTHELP 0x2000L + +#define DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS) + +#if(_WIN32_WCE >= 0x0500) +#define DS_USEPIXELS 0x8000L +#endif + +#define DM_GETDEFID (WM_USER+0) +#define DM_SETDEFID (WM_USER+1) +#define DM_REPOSITION (WM_USER+2) + +#define DC_HASDEFID 0x534B + +#define DLGC_WANTARROWS 0x0001 +#define DLGC_WANTTAB 0x0002 +#define DLGC_WANTALLKEYS 0x0004 +#define DLGC_WANTMESSAGE 0x0004 +#define DLGC_HASSETSEL 0x0008 +#define DLGC_DEFPUSHBUTTON 0x0010 +#define DLGC_UNDEFPUSHBUTTON 0x0020 +#define DLGC_RADIOBUTTON 0x0040 +#define DLGC_WANTCHARS 0x0080 +#define DLGC_STATIC 0x0100 +#define DLGC_BUTTON 0x2000 + +#define LB_CTLCODE 0L + +#define LB_OKAY 0 +#define LB_ERR (-1) +#define LB_ERRSPACE (-2) + +#define LBN_ERRSPACE (-2) +#define LBN_SELCHANGE 1 +#define LBN_DBLCLK 2 +#define LBN_SELCANCEL 3 +#define LBN_SETFOCUS 4 +#define LBN_KILLFOCUS 5 + +#ifndef NOWINMESSAGES + +#define LB_ADDSTRING 0x0180 +#define LB_INSERTSTRING 0x0181 +#define LB_DELETESTRING 0x0182 +#define LB_SELITEMRANGEEX 0x0183 +#define LB_RESETCONTENT 0x0184 +#define LB_SETSEL 0x0185 +#define LB_SETCURSEL 0x0186 +#define LB_GETSEL 0x0187 +#define LB_GETCURSEL 0x0188 +#define LB_GETTEXT 0x0189 +#define LB_GETTEXTLEN 0x018A +#define LB_GETCOUNT 0x018B +#define LB_SELECTSTRING 0x018C +#define LB_DIR 0x018D +#define LB_GETTOPINDEX 0x018E +#define LB_FINDSTRING 0x018F +#define LB_GETSELCOUNT 0x0190 +#define LB_GETSELITEMS 0x0191 +#define LB_SETTABSTOPS 0x0192 +#define LB_GETHORIZONTALEXTENT 0x0193 +#define LB_SETHORIZONTALEXTENT 0x0194 +#define LB_SETCOLUMNWIDTH 0x0195 +#define LB_ADDFILE 0x0196 +#define LB_SETTOPINDEX 0x0197 +#define LB_GETITEMRECT 0x0198 +#define LB_GETITEMDATA 0x0199 +#define LB_SETITEMDATA 0x019A +#define LB_SELITEMRANGE 0x019B +#define LB_SETANCHORINDEX 0x019C +#define LB_GETANCHORINDEX 0x019D +#define LB_SETCARETINDEX 0x019E +#define LB_GETCARETINDEX 0x019F +#define LB_SETITEMHEIGHT 0x01A0 +#define LB_GETITEMHEIGHT 0x01A1 +#define LB_FINDSTRINGEXACT 0x01A2 +#define LB_SETLOCALE 0x01A5 +#define LB_GETLOCALE 0x01A6 +#define LB_SETCOUNT 0x01A7 +#define LB_INITSTORAGE 0x01A8 +#define LB_ITEMFROMPOINT 0x01A9 +#if(_WIN32_WCE >= 0x0400) +#define LB_MULTIPLEADDSTRING 0x01B1 +#endif +#define LB_GETLISTBOXINFO 0x01B2 +#define LB_MSGMAX 0x01B3 +#endif + +#ifndef NOWINSTYLES + +#define LBS_NOTIFY 0x0001L +#define LBS_SORT 0x0002L +#define LBS_NOREDRAW 0x0004L +#define LBS_MULTIPLESEL 0x0008L +#define LBS_OWNERDRAWFIXED 0x0010L +#define LBS_OWNERDRAWVARIABLE 0x0020L +#define LBS_HASSTRINGS 0x0040L +#define LBS_USETABSTOPS 0x0080L +#define LBS_NOINTEGRALHEIGHT 0x0100L +#define LBS_MULTICOLUMN 0x0200L +#define LBS_WANTKEYBOARDINPUT 0x0400L +#define LBS_EXTENDEDSEL 0x0800L +#define LBS_DISABLENOSCROLL 0x1000L +#define LBS_NODATA 0x2000L +#define LBS_NOSEL 0x4000L +#define LBS_COMBOBOX 0x8000L + +#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER) +#endif + +#define CB_OKAY 0 +#define CB_ERR (-1) +#define CB_ERRSPACE (-2) + +#define CBN_ERRSPACE (-1) +#define CBN_SELCHANGE 1 +#define CBN_DBLCLK 2 +#define CBN_SETFOCUS 3 +#define CBN_KILLFOCUS 4 +#define CBN_EDITCHANGE 5 +#define CBN_EDITUPDATE 6 +#define CBN_DROPDOWN 7 +#define CBN_CLOSEUP 8 +#define CBN_SELENDOK 9 +#define CBN_SELENDCANCEL 10 + +#ifndef NOWINSTYLES + +#define CBS_SIMPLE 0x0001L +#define CBS_DROPDOWN 0x0002L +#define CBS_DROPDOWNLIST 0x0003L +#define CBS_OWNERDRAWFIXED 0x0010L +#define CBS_OWNERDRAWVARIABLE 0x0020L +#define CBS_AUTOHSCROLL 0x0040L +#define CBS_OEMCONVERT 0x0080L +#define CBS_SORT 0x0100L +#define CBS_HASSTRINGS 0x0200L +#define CBS_NOINTEGRALHEIGHT 0x0400L +#define CBS_DISABLENOSCROLL 0x0800L +#define CBS_UPPERCASE 0x2000L +#define CBS_LOWERCASE 0x4000L +#endif + +#ifndef NOWINMESSAGES +#define CB_GETEDITSEL 0x0140 +#define CB_LIMITTEXT 0x0141 +#define CB_SETEDITSEL 0x0142 +#define CB_ADDSTRING 0x0143 +#define CB_DELETESTRING 0x0144 +#define CB_DIR 0x0145 +#define CB_GETCOUNT 0x0146 +#define CB_GETCURSEL 0x0147 +#define CB_GETLBTEXT 0x0148 +#define CB_GETLBTEXTLEN 0x0149 +#define CB_INSERTSTRING 0x014A +#define CB_RESETCONTENT 0x014B +#define CB_FINDSTRING 0x014C +#define CB_SELECTSTRING 0x014D +#define CB_SETCURSEL 0x014E +#define CB_SHOWDROPDOWN 0x014F +#define CB_GETITEMDATA 0x0150 +#define CB_SETITEMDATA 0x0151 +#define CB_GETDROPPEDCONTROLRECT 0x0152 +#define CB_SETITEMHEIGHT 0x0153 +#define CB_GETITEMHEIGHT 0x0154 +#define CB_SETEXTENDEDUI 0x0155 +#define CB_GETEXTENDEDUI 0x0156 +#define CB_GETDROPPEDSTATE 0x0157 +#define CB_FINDSTRINGEXACT 0x0158 +#define CB_SETLOCALE 0x0159 +#define CB_GETLOCALE 0x015A +#define CB_GETTOPINDEX 0x015b +#define CB_SETTOPINDEX 0x015c +#define CB_GETHORIZONTALEXTENT 0x015d +#define CB_SETHORIZONTALEXTENT 0x015e +#define CB_GETDROPPEDWIDTH 0x015f +#define CB_SETDROPPEDWIDTH 0x0160 +#define CB_INITSTORAGE 0x0161 +#if(_WIN32_WCE >= 0x0400) +#define CB_MULTIPLEADDSTRING 0x0163 +#endif +#define CB_GETCOMBOBOXINFO 0x0164 +#define CB_MSGMAX 0x0165 +#endif + +#ifndef NOWINSTYLES + +#define SBS_HORZ 0x0000L +#define SBS_VERT 0x0001L +#define SBS_TOPALIGN 0x0002L +#define SBS_LEFTALIGN 0x0002L +#define SBS_BOTTOMALIGN 0x0004L +#define SBS_RIGHTALIGN 0x0004L +#define SBS_SIZEBOXTOPLEFTALIGN 0x0002L +#define SBS_SIZEBOXBOTTOMRIGHTALIGN 0x0004L +#define SBS_SIZEBOX 0x0008L +#define SBS_SIZEGRIP 0x0010L +#endif + +#ifndef NOWINMESSAGES +#define SBM_SETPOS 0x00E0 +#define SBM_GETPOS 0x00E1 +#define SBM_SETRANGE 0x00E2 +#define SBM_SETRANGEREDRAW 0x00E6 +#define SBM_GETRANGE 0x00E3 +#define SBM_ENABLE_ARROWS 0x00E4 +#define SBM_SETSCROLLINFO 0x00E9 +#define SBM_GETSCROLLINFO 0x00EA +#define SBM_GETSCROLLBARINFO 0x00EB + +#define SIF_RANGE 0x0001 +#define SIF_PAGE 0x0002 +#define SIF_POS 0x0004 +#define SIF_DISABLENOSCROLL 0x0008 +#define SIF_TRACKPOS 0x0010 +#define SIF_ALL (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS) + + typedef struct tagSCROLLINFO { + UINT cbSize; + UINT fMask; + int nMin; + int nMax; + UINT nPage; + int nPos; + int nTrackPos; + } SCROLLINFO,*LPSCROLLINFO; + typedef SCROLLINFO CONST *LPCSCROLLINFO; + + WINUSERAPI int WINAPI SetScrollInfo(HWND hwnd,int nBar,LPCSCROLLINFO lpsi,WINBOOL redraw); + WINUSERAPI WINBOOL WINAPI GetScrollInfo(HWND hwnd,int nBar,LPSCROLLINFO lpsi); +#endif +#endif + +#ifndef NOMDI + +#define MDIS_ALLCHILDSTYLES 0x0001 + +#define MDITILE_VERTICAL 0x0000 +#define MDITILE_HORIZONTAL 0x0001 +#define MDITILE_SKIPDISABLED 0x0002 +#define MDITILE_ZORDER 0x0004 + + typedef struct tagMDICREATESTRUCTA { + LPCSTR szClass; + LPCSTR szTitle; + HANDLE hOwner; + int x; + int y; + int cx; + int cy; + DWORD style; + LPARAM lParam; + } MDICREATESTRUCTA,*LPMDICREATESTRUCTA; + + typedef struct tagMDICREATESTRUCTW { + LPCWSTR szClass; + LPCWSTR szTitle; + HANDLE hOwner; + int x; + int y; + int cx; + int cy; + DWORD style; + LPARAM lParam; + } MDICREATESTRUCTW,*LPMDICREATESTRUCTW; + +#ifdef UNICODE + typedef MDICREATESTRUCTW MDICREATESTRUCT; + typedef LPMDICREATESTRUCTW LPMDICREATESTRUCT; +#else + typedef MDICREATESTRUCTA MDICREATESTRUCT; + typedef LPMDICREATESTRUCTA LPMDICREATESTRUCT; +#endif + + typedef struct tagCLIENTCREATESTRUCT { + HANDLE hWindowMenu; + UINT idFirstChild; + } CLIENTCREATESTRUCT,*LPCLIENTCREATESTRUCT; + +#ifdef UNICODE +#define DefFrameProc DefFrameProcW +#define DefMDIChildProc DefMDIChildProcW +#define CreateMDIWindow CreateMDIWindowW +#else +#define DefFrameProc DefFrameProcA +#define DefMDIChildProc DefMDIChildProcA +#define CreateMDIWindow CreateMDIWindowA +#endif + + WINUSERAPI LRESULT WINAPI DefFrameProcA(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefFrameProcW(HWND hWnd,HWND hWndMDIClient,UINT uMsg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefMDIChildProcA(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); + WINUSERAPI LRESULT WINAPI DefMDIChildProcW(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); + +#ifndef NOMSG + WINUSERAPI WINBOOL WINAPI TranslateMDISysAccel(HWND hWndClient,LPMSG lpMsg); +#endif + + WINUSERAPI UINT WINAPI ArrangeIconicWindows(HWND hWnd); + WINUSERAPI HWND WINAPI CreateMDIWindowA(LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); + WINUSERAPI HWND WINAPI CreateMDIWindowW(LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HINSTANCE hInstance,LPARAM lParam); + WINUSERAPI WORD WINAPI TileWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); + WINUSERAPI WORD WINAPI CascadeWindows(HWND hwndParent,UINT wHow,CONST RECT *lpRect,UINT cKids,const HWND *lpKids); +#endif +#endif + +#ifndef NOHELP + + typedef DWORD HELPPOLY; + typedef struct tagMULTIKEYHELPA { + DWORD mkSize; + CHAR mkKeylist; + CHAR szKeyphrase[1]; + } MULTIKEYHELPA,*PMULTIKEYHELPA,*LPMULTIKEYHELPA; + + typedef struct tagMULTIKEYHELPW { + DWORD mkSize; + WCHAR mkKeylist; + WCHAR szKeyphrase[1]; + } MULTIKEYHELPW,*PMULTIKEYHELPW,*LPMULTIKEYHELPW; + +#ifdef UNICODE + typedef MULTIKEYHELPW MULTIKEYHELP; + typedef PMULTIKEYHELPW PMULTIKEYHELP; + typedef LPMULTIKEYHELPW LPMULTIKEYHELP; +#else + typedef MULTIKEYHELPA MULTIKEYHELP; + typedef PMULTIKEYHELPA PMULTIKEYHELP; + typedef LPMULTIKEYHELPA LPMULTIKEYHELP; +#endif + + typedef struct tagHELPWININFOA { + int wStructSize; + int x; + int y; + int dx; + int dy; + int wMax; + CHAR rgchMember[2]; + } HELPWININFOA,*PHELPWININFOA,*LPHELPWININFOA; + + typedef struct tagHELPWININFOW { + int wStructSize; + int x; + int y; + int dx; + int dy; + int wMax; + WCHAR rgchMember[2]; + } HELPWININFOW,*PHELPWININFOW,*LPHELPWININFOW; + +#ifdef UNICODE + typedef HELPWININFOW HELPWININFO; + typedef PHELPWININFOW PHELPWININFO; + typedef LPHELPWININFOW LPHELPWININFO; +#else + typedef HELPWININFOA HELPWININFO; + typedef PHELPWININFOA PHELPWININFO; + typedef LPHELPWININFOA LPHELPWININFO; +#endif + +#define HELP_CONTEXT 0x0001L +#define HELP_QUIT 0x0002L +#define HELP_INDEX 0x0003L +#define HELP_CONTENTS 0x0003L +#define HELP_HELPONHELP 0x0004L +#define HELP_SETINDEX 0x0005L +#define HELP_SETCONTENTS 0x0005L +#define HELP_CONTEXTPOPUP 0x0008L +#define HELP_FORCEFILE 0x0009L +#define HELP_KEY 0x0101L +#define HELP_COMMAND 0x0102L +#define HELP_PARTIALKEY 0x0105L +#define HELP_MULTIKEY 0x0201L +#define HELP_SETWINPOS 0x0203L +#define HELP_CONTEXTMENU 0x000a +#define HELP_FINDER 0x000b +#define HELP_WM_HELP 0x000c +#define HELP_SETPOPUP_POS 0x000d + +#define HELP_TCARD 0x8000 +#define HELP_TCARD_DATA 0x0010 +#define HELP_TCARD_OTHER_CALLER 0x0011 + +#define IDH_NO_HELP 28440 +#define IDH_MISSING_CONTEXT 28441 +#define IDH_GENERIC_HELP_BUTTON 28442 +#define IDH_OK 28443 +#define IDH_CANCEL 28444 +#define IDH_HELP 28445 + +#ifdef UNICODE +#define WinHelp WinHelpW +#else +#define WinHelp WinHelpA +#endif + + WINUSERAPI WINBOOL WINAPI WinHelpA(HWND hWndMain,LPCSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); + WINUSERAPI WINBOOL WINAPI WinHelpW(HWND hWndMain,LPCWSTR lpszHelp,UINT uCommand,ULONG_PTR dwData); +#endif + +#define GR_GDIOBJECTS 0 +#define GR_USEROBJECTS 1 + + WINUSERAPI DWORD WINAPI GetGuiResources(HANDLE hProcess,DWORD uiFlags); + +#ifndef NOSYSPARAMSINFO + +#define SPI_GETBEEP 0x0001 +#define SPI_SETBEEP 0x0002 +#define SPI_GETMOUSE 0x0003 +#define SPI_SETMOUSE 0x0004 +#define SPI_GETBORDER 0x0005 +#define SPI_SETBORDER 0x0006 +#define SPI_GETKEYBOARDSPEED 0x000A +#define SPI_SETKEYBOARDSPEED 0x000B +#define SPI_LANGDRIVER 0x000C +#define SPI_ICONHORIZONTALSPACING 0x000D +#define SPI_GETSCREENSAVETIMEOUT 0x000E +#define SPI_SETSCREENSAVETIMEOUT 0x000F +#define SPI_GETSCREENSAVEACTIVE 0x0010 +#define SPI_SETSCREENSAVEACTIVE 0x0011 +#define SPI_GETGRIDGRANULARITY 0x0012 +#define SPI_SETGRIDGRANULARITY 0x0013 +#define SPI_SETDESKWALLPAPER 0x0014 +#define SPI_SETDESKPATTERN 0x0015 +#define SPI_GETKEYBOARDDELAY 0x0016 +#define SPI_SETKEYBOARDDELAY 0x0017 +#define SPI_ICONVERTICALSPACING 0x0018 +#define SPI_GETICONTITLEWRAP 0x0019 +#define SPI_SETICONTITLEWRAP 0x001A +#define SPI_GETMENUDROPALIGNMENT 0x001B +#define SPI_SETMENUDROPALIGNMENT 0x001C +#define SPI_SETDOUBLECLKWIDTH 0x001D +#define SPI_SETDOUBLECLKHEIGHT 0x001E +#define SPI_GETICONTITLELOGFONT 0x001F +#define SPI_SETDOUBLECLICKTIME 0x0020 +#define SPI_SETMOUSEBUTTONSWAP 0x0021 +#define SPI_SETICONTITLELOGFONT 0x0022 +#define SPI_GETFASTTASKSWITCH 0x0023 +#define SPI_SETFASTTASKSWITCH 0x0024 +#define SPI_SETDRAGFULLWINDOWS 0x0025 +#define SPI_GETDRAGFULLWINDOWS 0x0026 +#define SPI_GETNONCLIENTMETRICS 0x0029 +#define SPI_SETNONCLIENTMETRICS 0x002A +#define SPI_GETMINIMIZEDMETRICS 0x002B +#define SPI_SETMINIMIZEDMETRICS 0x002C +#define SPI_GETICONMETRICS 0x002D +#define SPI_SETICONMETRICS 0x002E +#define SPI_SETWORKAREA 0x002F +#define SPI_GETWORKAREA 0x0030 +#define SPI_SETPENWINDOWS 0x0031 + +#define SPI_GETHIGHCONTRAST 0x0042 +#define SPI_SETHIGHCONTRAST 0x0043 +#define SPI_GETKEYBOARDPREF 0x0044 +#define SPI_SETKEYBOARDPREF 0x0045 +#define SPI_GETSCREENREADER 0x0046 +#define SPI_SETSCREENREADER 0x0047 +#define SPI_GETANIMATION 0x0048 +#define SPI_SETANIMATION 0x0049 +#define SPI_GETFONTSMOOTHING 0x004A +#define SPI_SETFONTSMOOTHING 0x004B +#define SPI_SETDRAGWIDTH 0x004C +#define SPI_SETDRAGHEIGHT 0x004D +#define SPI_SETHANDHELD 0x004E +#define SPI_GETLOWPOWERTIMEOUT 0x004F +#define SPI_GETPOWEROFFTIMEOUT 0x0050 +#define SPI_SETLOWPOWERTIMEOUT 0x0051 +#define SPI_SETPOWEROFFTIMEOUT 0x0052 +#define SPI_GETLOWPOWERACTIVE 0x0053 +#define SPI_GETPOWEROFFACTIVE 0x0054 +#define SPI_SETLOWPOWERACTIVE 0x0055 +#define SPI_SETPOWEROFFACTIVE 0x0056 +#define SPI_SETCURSORS 0x0057 +#define SPI_SETICONS 0x0058 +#define SPI_GETDEFAULTINPUTLANG 0x0059 +#define SPI_SETDEFAULTINPUTLANG 0x005A +#define SPI_SETLANGTOGGLE 0x005B +#define SPI_GETWINDOWSEXTENSION 0x005C +#define SPI_SETMOUSETRAILS 0x005D +#define SPI_GETMOUSETRAILS 0x005E +#define SPI_SETSCREENSAVERRUNNING 0x0061 +#define SPI_SCREENSAVERRUNNING SPI_SETSCREENSAVERRUNNING +#define SPI_GETFILTERKEYS 0x0032 +#define SPI_SETFILTERKEYS 0x0033 +#define SPI_GETTOGGLEKEYS 0x0034 +#define SPI_SETTOGGLEKEYS 0x0035 +#define SPI_GETMOUSEKEYS 0x0036 +#define SPI_SETMOUSEKEYS 0x0037 +#define SPI_GETSHOWSOUNDS 0x0038 +#define SPI_SETSHOWSOUNDS 0x0039 +#define SPI_GETSTICKYKEYS 0x003A +#define SPI_SETSTICKYKEYS 0x003B +#define SPI_GETACCESSTIMEOUT 0x003C +#define SPI_SETACCESSTIMEOUT 0x003D +#define SPI_GETSERIALKEYS 0x003E +#define SPI_SETSERIALKEYS 0x003F +#define SPI_GETSOUNDSENTRY 0x0040 +#define SPI_SETSOUNDSENTRY 0x0041 +#define SPI_GETSNAPTODEFBUTTON 0x005F +#define SPI_SETSNAPTODEFBUTTON 0x0060 +#define SPI_GETMOUSEHOVERWIDTH 0x0062 +#define SPI_SETMOUSEHOVERWIDTH 0x0063 +#define SPI_GETMOUSEHOVERHEIGHT 0x0064 +#define SPI_SETMOUSEHOVERHEIGHT 0x0065 +#define SPI_GETMOUSEHOVERTIME 0x0066 +#define SPI_SETMOUSEHOVERTIME 0x0067 +#define SPI_GETWHEELSCROLLLINES 0x0068 +#define SPI_SETWHEELSCROLLLINES 0x0069 +#define SPI_GETMENUSHOWDELAY 0x006A +#define SPI_SETMENUSHOWDELAY 0x006B +#define SPI_GETSHOWIMEUI 0x006E +#define SPI_SETSHOWIMEUI 0x006F +#define SPI_GETMOUSESPEED 0x0070 +#define SPI_SETMOUSESPEED 0x0071 +#define SPI_GETSCREENSAVERRUNNING 0x0072 +#define SPI_GETDESKWALLPAPER 0x0073 + +#define SPI_GETACTIVEWINDOWTRACKING 0x1000 +#define SPI_SETACTIVEWINDOWTRACKING 0x1001 +#define SPI_GETMENUANIMATION 0x1002 +#define SPI_SETMENUANIMATION 0x1003 +#define SPI_GETCOMBOBOXANIMATION 0x1004 +#define SPI_SETCOMBOBOXANIMATION 0x1005 +#define SPI_GETLISTBOXSMOOTHSCROLLING 0x1006 +#define SPI_SETLISTBOXSMOOTHSCROLLING 0x1007 +#define SPI_GETGRADIENTCAPTIONS 0x1008 +#define SPI_SETGRADIENTCAPTIONS 0x1009 +#define SPI_GETKEYBOARDCUES 0x100A +#define SPI_SETKEYBOARDCUES 0x100B +#define SPI_GETMENUUNDERLINES SPI_GETKEYBOARDCUES +#define SPI_SETMENUUNDERLINES SPI_SETKEYBOARDCUES +#define SPI_GETACTIVEWNDTRKZORDER 0x100C +#define SPI_SETACTIVEWNDTRKZORDER 0x100D +#define SPI_GETHOTTRACKING 0x100E +#define SPI_SETHOTTRACKING 0x100F +#define SPI_GETMENUFADE 0x1012 +#define SPI_SETMENUFADE 0x1013 +#define SPI_GETSELECTIONFADE 0x1014 +#define SPI_SETSELECTIONFADE 0x1015 +#define SPI_GETTOOLTIPANIMATION 0x1016 +#define SPI_SETTOOLTIPANIMATION 0x1017 +#define SPI_GETTOOLTIPFADE 0x1018 +#define SPI_SETTOOLTIPFADE 0x1019 +#define SPI_GETCURSORSHADOW 0x101A +#define SPI_SETCURSORSHADOW 0x101B +#define SPI_GETMOUSESONAR 0x101C +#define SPI_SETMOUSESONAR 0x101D +#define SPI_GETMOUSECLICKLOCK 0x101E +#define SPI_SETMOUSECLICKLOCK 0x101F +#define SPI_GETMOUSEVANISH 0x1020 +#define SPI_SETMOUSEVANISH 0x1021 +#define SPI_GETFLATMENU 0x1022 +#define SPI_SETFLATMENU 0x1023 +#define SPI_GETDROPSHADOW 0x1024 +#define SPI_SETDROPSHADOW 0x1025 +#define SPI_GETBLOCKSENDINPUTRESETS 0x1026 +#define SPI_SETBLOCKSENDINPUTRESETS 0x1027 +#define SPI_GETUIEFFECTS 0x103E +#define SPI_SETUIEFFECTS 0x103F +#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 +#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 +#define SPI_GETACTIVEWNDTRKTIMEOUT 0x2002 +#define SPI_SETACTIVEWNDTRKTIMEOUT 0x2003 +#define SPI_GETFOREGROUNDFLASHCOUNT 0x2004 +#define SPI_SETFOREGROUNDFLASHCOUNT 0x2005 +#define SPI_GETCARETWIDTH 0x2006 +#define SPI_SETCARETWIDTH 0x2007 +#define SPI_GETMOUSECLICKLOCKTIME 0x2008 +#define SPI_SETMOUSECLICKLOCKTIME 0x2009 +#define SPI_GETFONTSMOOTHINGTYPE 0x200A +#define SPI_SETFONTSMOOTHINGTYPE 0x200B + +#define FE_FONTSMOOTHINGSTANDARD 0x0001 +#define FE_FONTSMOOTHINGCLEARTYPE 0x0002 +#define FE_FONTSMOOTHINGDOCKING 0x8000 + +#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C +#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D +#define SPI_GETFOCUSBORDERWIDTH 0x200E +#define SPI_SETFOCUSBORDERWIDTH 0x200F +#define SPI_GETFOCUSBORDERHEIGHT 0x2010 +#define SPI_SETFOCUSBORDERHEIGHT 0x2011 +#define SPI_GETFONTSMOOTHINGORIENTATION 0x2012 +#define SPI_SETFONTSMOOTHINGORIENTATION 0x2013 + +#define FE_FONTSMOOTHINGORIENTATIONBGR 0x0000 +#define FE_FONTSMOOTHINGORIENTATIONRGB 0x0001 + +#define SPIF_UPDATEINIFILE 0x0001 +#define SPIF_SENDWININICHANGE 0x0002 +#define SPIF_SENDCHANGE SPIF_SENDWININICHANGE + +#define METRICS_USEDEFAULT -1 +#ifdef _WINGDI_ +#ifndef NOGDI + typedef struct tagNONCLIENTMETRICSA { + UINT cbSize; + int iBorderWidth; + int iScrollWidth; + int iScrollHeight; + int iCaptionWidth; + int iCaptionHeight; + LOGFONTA lfCaptionFont; + int iSmCaptionWidth; + int iSmCaptionHeight; + LOGFONTA lfSmCaptionFont; + int iMenuWidth; + int iMenuHeight; + LOGFONTA lfMenuFont; + LOGFONTA lfStatusFont; + LOGFONTA lfMessageFont; + } NONCLIENTMETRICSA,*PNONCLIENTMETRICSA,*LPNONCLIENTMETRICSA; + + typedef struct tagNONCLIENTMETRICSW { + UINT cbSize; + int iBorderWidth; + int iScrollWidth; + int iScrollHeight; + int iCaptionWidth; + int iCaptionHeight; + LOGFONTW lfCaptionFont; + int iSmCaptionWidth; + int iSmCaptionHeight; + LOGFONTW lfSmCaptionFont; + int iMenuWidth; + int iMenuHeight; + LOGFONTW lfMenuFont; + LOGFONTW lfStatusFont; + LOGFONTW lfMessageFont; + } NONCLIENTMETRICSW,*PNONCLIENTMETRICSW,*LPNONCLIENTMETRICSW; + +#ifdef UNICODE + typedef NONCLIENTMETRICSW NONCLIENTMETRICS; + typedef PNONCLIENTMETRICSW PNONCLIENTMETRICS; + typedef LPNONCLIENTMETRICSW LPNONCLIENTMETRICS; +#else + typedef NONCLIENTMETRICSA NONCLIENTMETRICS; + typedef PNONCLIENTMETRICSA PNONCLIENTMETRICS; + typedef LPNONCLIENTMETRICSA LPNONCLIENTMETRICS; +#endif +#endif +#endif + +#define ARW_BOTTOMLEFT 0x0000L +#define ARW_BOTTOMRIGHT 0x0001L +#define ARW_TOPLEFT 0x0002L +#define ARW_TOPRIGHT 0x0003L +#define ARW_STARTMASK 0x0003L +#define ARW_STARTRIGHT 0x0001L +#define ARW_STARTTOP 0x0002L + +#define ARW_LEFT 0x0000L +#define ARW_RIGHT 0x0000L +#define ARW_UP 0x0004L +#define ARW_DOWN 0x0004L +#define ARW_HIDE 0x0008L + + typedef struct tagMINIMIZEDMETRICS { + UINT cbSize; + int iWidth; + int iHorzGap; + int iVertGap; + int iArrange; + } MINIMIZEDMETRICS,*PMINIMIZEDMETRICS,*LPMINIMIZEDMETRICS; + +#ifdef _WINGDI_ +#ifndef NOGDI + typedef struct tagICONMETRICSA { + UINT cbSize; + int iHorzSpacing; + int iVertSpacing; + int iTitleWrap; + LOGFONTA lfFont; + } ICONMETRICSA,*PICONMETRICSA,*LPICONMETRICSA; + + typedef struct tagICONMETRICSW { + UINT cbSize; + int iHorzSpacing; + int iVertSpacing; + int iTitleWrap; + LOGFONTW lfFont; + } ICONMETRICSW,*PICONMETRICSW,*LPICONMETRICSW; + +#ifdef UNICODE + typedef ICONMETRICSW ICONMETRICS; + typedef PICONMETRICSW PICONMETRICS; + typedef LPICONMETRICSW LPICONMETRICS; +#else + typedef ICONMETRICSA ICONMETRICS; + typedef PICONMETRICSA PICONMETRICS; + typedef LPICONMETRICSA LPICONMETRICS; +#endif +#endif +#endif + + typedef struct tagANIMATIONINFO { + UINT cbSize; + int iMinAnimate; + } ANIMATIONINFO,*LPANIMATIONINFO; + + typedef struct tagSERIALKEYSA { + UINT cbSize; + DWORD dwFlags; + LPSTR lpszActivePort; + LPSTR lpszPort; + UINT iBaudRate; + UINT iPortState; + UINT iActive; + } SERIALKEYSA,*LPSERIALKEYSA; + + typedef struct tagSERIALKEYSW { + UINT cbSize; + DWORD dwFlags; + LPWSTR lpszActivePort; + LPWSTR lpszPort; + UINT iBaudRate; + UINT iPortState; + UINT iActive; + } SERIALKEYSW,*LPSERIALKEYSW; + +#ifdef UNICODE + typedef SERIALKEYSW SERIALKEYS; + typedef LPSERIALKEYSW LPSERIALKEYS; +#else + typedef SERIALKEYSA SERIALKEYS; + typedef LPSERIALKEYSA LPSERIALKEYS; +#endif + +#define SERKF_SERIALKEYSON 0x00000001 +#define SERKF_AVAILABLE 0x00000002 +#define SERKF_INDICATOR 0x00000004 + + typedef struct tagHIGHCONTRASTA { + UINT cbSize; + DWORD dwFlags; + LPSTR lpszDefaultScheme; + } HIGHCONTRASTA,*LPHIGHCONTRASTA; + + typedef struct tagHIGHCONTRASTW { + UINT cbSize; + DWORD dwFlags; + LPWSTR lpszDefaultScheme; + } HIGHCONTRASTW,*LPHIGHCONTRASTW; + +#ifdef UNICODE + typedef HIGHCONTRASTW HIGHCONTRAST; + typedef LPHIGHCONTRASTW LPHIGHCONTRAST; +#else + typedef HIGHCONTRASTA HIGHCONTRAST; + typedef LPHIGHCONTRASTA LPHIGHCONTRAST; +#endif + +#define HCF_HIGHCONTRASTON 0x00000001 +#define HCF_AVAILABLE 0x00000002 +#define HCF_HOTKEYACTIVE 0x00000004 +#define HCF_CONFIRMHOTKEY 0x00000008 +#define HCF_HOTKEYSOUND 0x00000010 +#define HCF_INDICATOR 0x00000020 +#define HCF_HOTKEYAVAILABLE 0x00000040 +#define HCF_LOGONDESKTOP 0x00000100 +#define HCF_DEFAULTDESKTOP 0x00000200 + +#define CDS_UPDATEREGISTRY 0x00000001 +#define CDS_TEST 0x00000002 +#define CDS_FULLSCREEN 0x00000004 +#define CDS_GLOBAL 0x00000008 +#define CDS_SET_PRIMARY 0x00000010 +#define CDS_VIDEOPARAMETERS 0x00000020 +#define CDS_RESET 0x40000000 +#define CDS_NORESET 0x10000000 + +//gr #include + +#define DISP_CHANGE_SUCCESSFUL 0 +#define DISP_CHANGE_RESTART 1 +#define DISP_CHANGE_FAILED -1 +#define DISP_CHANGE_BADMODE -2 +#define DISP_CHANGE_NOTUPDATED -3 +#define DISP_CHANGE_BADFLAGS -4 +#define DISP_CHANGE_BADPARAM -5 +#define DISP_CHANGE_BADDUALVIEW -6 + +#ifdef _WINGDI_ +#ifndef NOGDI + +#ifdef UNICODE +#define ChangeDisplaySettings ChangeDisplaySettingsW +#define ChangeDisplaySettingsEx ChangeDisplaySettingsExW +#define EnumDisplaySettings EnumDisplaySettingsW +#define EnumDisplaySettingsEx EnumDisplaySettingsExW +#define EnumDisplayDevices EnumDisplayDevicesW +#else +#define ChangeDisplaySettings ChangeDisplaySettingsA +#define ChangeDisplaySettingsEx ChangeDisplaySettingsExA +#define EnumDisplaySettings EnumDisplaySettingsA +#define EnumDisplaySettingsEx EnumDisplaySettingsExA +#define EnumDisplayDevices EnumDisplayDevicesA +#endif + + WINUSERAPI LONG WINAPI ChangeDisplaySettingsA(LPDEVMODEA lpDevMode,DWORD dwFlags); + WINUSERAPI LONG WINAPI ChangeDisplaySettingsW(LPDEVMODEW lpDevMode,DWORD dwFlags); + WINUSERAPI LONG WINAPI ChangeDisplaySettingsExA(LPCSTR lpszDeviceName,LPDEVMODEA lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); + WINUSERAPI LONG WINAPI ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName,LPDEVMODEW lpDevMode,HWND hwnd,DWORD dwflags,LPVOID lParam); + +#define ENUM_CURRENT_SETTINGS ((DWORD)-1) +#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) + + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode); + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode); + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEA lpDevMode,DWORD dwFlags); + WINUSERAPI WINBOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName,DWORD iModeNum,LPDEVMODEW lpDevMode,DWORD dwFlags); + +#define EDS_RAWMODE 0x00000002 + + WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesA(LPCSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEA lpDisplayDevice,DWORD dwFlags); + WINUSERAPI WINBOOL WINAPI EnumDisplayDevicesW(LPCWSTR lpDevice,DWORD iDevNum,PDISPLAY_DEVICEW lpDisplayDevice,DWORD dwFlags); +#endif +#endif + +#ifdef UNICODE +#define SystemParametersInfo SystemParametersInfoW +#else +#define SystemParametersInfo SystemParametersInfoA +#endif + + WINUSERAPI WINBOOL WINAPI SystemParametersInfoA(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); + WINUSERAPI WINBOOL WINAPI SystemParametersInfoW(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni); +#endif + + typedef struct tagFILTERKEYS { + UINT cbSize; + DWORD dwFlags; + DWORD iWaitMSec; + DWORD iDelayMSec; + DWORD iRepeatMSec; + DWORD iBounceMSec; + } FILTERKEYS,*LPFILTERKEYS; + +#define FKF_FILTERKEYSON 0x00000001 +#define FKF_AVAILABLE 0x00000002 +#define FKF_HOTKEYACTIVE 0x00000004 +#define FKF_CONFIRMHOTKEY 0x00000008 +#define FKF_HOTKEYSOUND 0x00000010 +#define FKF_INDICATOR 0x00000020 +#define FKF_CLICKON 0x00000040 + + typedef struct tagSTICKYKEYS { + UINT cbSize; + DWORD dwFlags; + } STICKYKEYS,*LPSTICKYKEYS; + +#define SKF_STICKYKEYSON 0x00000001 +#define SKF_AVAILABLE 0x00000002 +#define SKF_HOTKEYACTIVE 0x00000004 +#define SKF_CONFIRMHOTKEY 0x00000008 +#define SKF_HOTKEYSOUND 0x00000010 +#define SKF_INDICATOR 0x00000020 +#define SKF_AUDIBLEFEEDBACK 0x00000040 +#define SKF_TRISTATE 0x00000080 +#define SKF_TWOKEYSOFF 0x00000100 +#define SKF_LALTLATCHED 0x10000000 +#define SKF_LCTLLATCHED 0x04000000 +#define SKF_LSHIFTLATCHED 0x01000000 +#define SKF_RALTLATCHED 0x20000000 +#define SKF_RCTLLATCHED 0x08000000 +#define SKF_RSHIFTLATCHED 0x02000000 +#define SKF_LWINLATCHED 0x40000000 +#define SKF_RWINLATCHED 0x80000000 +#define SKF_LALTLOCKED 0x00100000 +#define SKF_LCTLLOCKED 0x00040000 +#define SKF_LSHIFTLOCKED 0x00010000 +#define SKF_RALTLOCKED 0x00200000 +#define SKF_RCTLLOCKED 0x00080000 +#define SKF_RSHIFTLOCKED 0x00020000 +#define SKF_LWINLOCKED 0x00400000 +#define SKF_RWINLOCKED 0x00800000 + + typedef struct tagMOUSEKEYS { + UINT cbSize; + DWORD dwFlags; + DWORD iMaxSpeed; + DWORD iTimeToMaxSpeed; + DWORD iCtrlSpeed; + DWORD dwReserved1; + DWORD dwReserved2; + } MOUSEKEYS,*LPMOUSEKEYS; + +#define MKF_MOUSEKEYSON 0x00000001 +#define MKF_AVAILABLE 0x00000002 +#define MKF_HOTKEYACTIVE 0x00000004 +#define MKF_CONFIRMHOTKEY 0x00000008 +#define MKF_HOTKEYSOUND 0x00000010 +#define MKF_INDICATOR 0x00000020 +#define MKF_MODIFIERS 0x00000040 +#define MKF_REPLACENUMBERS 0x00000080 +#define MKF_LEFTBUTTONSEL 0x10000000 +#define MKF_RIGHTBUTTONSEL 0x20000000 +#define MKF_LEFTBUTTONDOWN 0x01000000 +#define MKF_RIGHTBUTTONDOWN 0x02000000 +#define MKF_MOUSEMODE 0x80000000 + + typedef struct tagACCESSTIMEOUT { + UINT cbSize; + DWORD dwFlags; + DWORD iTimeOutMSec; + } ACCESSTIMEOUT,*LPACCESSTIMEOUT; + +#define ATF_TIMEOUTON 0x00000001 +#define ATF_ONOFFFEEDBACK 0x00000002 + +#define SSGF_NONE 0 +#define SSGF_DISPLAY 3 + +#define SSTF_NONE 0 +#define SSTF_CHARS 1 +#define SSTF_BORDER 2 +#define SSTF_DISPLAY 3 + +#define SSWF_NONE 0 +#define SSWF_TITLE 1 +#define SSWF_WINDOW 2 +#define SSWF_DISPLAY 3 +#define SSWF_CUSTOM 4 + + typedef struct tagSOUNDSENTRYA { + UINT cbSize; + DWORD dwFlags; + DWORD iFSTextEffect; + DWORD iFSTextEffectMSec; + DWORD iFSTextEffectColorBits; + DWORD iFSGrafEffect; + DWORD iFSGrafEffectMSec; + DWORD iFSGrafEffectColor; + DWORD iWindowsEffect; + DWORD iWindowsEffectMSec; + LPSTR lpszWindowsEffectDLL; + DWORD iWindowsEffectOrdinal; + } SOUNDSENTRYA,*LPSOUNDSENTRYA; + + typedef struct tagSOUNDSENTRYW { + UINT cbSize; + DWORD dwFlags; + DWORD iFSTextEffect; + DWORD iFSTextEffectMSec; + DWORD iFSTextEffectColorBits; + DWORD iFSGrafEffect; + DWORD iFSGrafEffectMSec; + DWORD iFSGrafEffectColor; + DWORD iWindowsEffect; + DWORD iWindowsEffectMSec; + LPWSTR lpszWindowsEffectDLL; + DWORD iWindowsEffectOrdinal; + } SOUNDSENTRYW,*LPSOUNDSENTRYW; + +#ifdef UNICODE + typedef SOUNDSENTRYW SOUNDSENTRY; + typedef LPSOUNDSENTRYW LPSOUNDSENTRY; +#else + typedef SOUNDSENTRYA SOUNDSENTRY; + typedef LPSOUNDSENTRYA LPSOUNDSENTRY; +#endif + +#define SSF_SOUNDSENTRYON 0x00000001 +#define SSF_AVAILABLE 0x00000002 +#define SSF_INDICATOR 0x00000004 + + typedef struct tagTOGGLEKEYS { + UINT cbSize; + DWORD dwFlags; + } TOGGLEKEYS,*LPTOGGLEKEYS; + +#define TKF_TOGGLEKEYSON 0x00000001 +#define TKF_AVAILABLE 0x00000002 +#define TKF_HOTKEYACTIVE 0x00000004 +#define TKF_CONFIRMHOTKEY 0x00000008 +#define TKF_HOTKEYSOUND 0x00000010 +#define TKF_INDICATOR 0x00000020 + + WINUSERAPI VOID WINAPI SetDebugErrorLevel(DWORD dwLevel); + +#define SLE_ERROR 0x00000001 +#define SLE_MINORERROR 0x00000002 +#define SLE_WARNING 0x00000003 + + WINUSERAPI VOID WINAPI SetLastErrorEx(DWORD dwErrCode,DWORD dwType); + WINUSERAPI int WINAPI InternalGetWindowText(HWND hWnd,LPWSTR pString,int cchMaxCount); + +#ifdef WINNT + WINUSERAPI WINBOOL WINAPI EndTask(HWND hWnd,WINBOOL fShutDown,WINBOOL fForce); +#endif + +#define MONITOR_DEFAULTTONULL 0x00000000 +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +#define MONITOR_DEFAULTTONEAREST 0x00000002 + + WINUSERAPI HMONITOR WINAPI MonitorFromPoint(POINT pt,DWORD dwFlags); + WINUSERAPI HMONITOR WINAPI MonitorFromRect(LPCRECT lprc,DWORD dwFlags); + WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd,DWORD dwFlags); + +#define MONITORINFOF_PRIMARY 0x00000001 + +#ifndef CCHDEVICENAME +#define CCHDEVICENAME 32 +#endif + + typedef struct tagMONITORINFO { + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; + } MONITORINFO,*LPMONITORINFO; + +#ifdef __cplusplus + typedef struct tagMONITORINFOEXA : public tagMONITORINFO { + CHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXA,*LPMONITORINFOEXA; + + typedef struct tagMONITORINFOEXW : public tagMONITORINFO { + WCHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXW,*LPMONITORINFOEXW; + +#ifdef UNICODE + typedef MONITORINFOEXW MONITORINFOEX; + typedef LPMONITORINFOEXW LPMONITORINFOEX; +#else + typedef MONITORINFOEXA MONITORINFOEX; + typedef LPMONITORINFOEXA LPMONITORINFOEX; +#endif +#else + typedef struct tagMONITORINFOEXA { + MONITORINFO mi; + CHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXA,*LPMONITORINFOEXA; + + typedef struct tagMONITORINFOEXW { + MONITORINFO mi; + WCHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEXW,*LPMONITORINFOEXW; +#ifdef UNICODE + typedef MONITORINFOEXW MONITORINFOEX; + typedef LPMONITORINFOEXW LPMONITORINFOEX; +#else + typedef MONITORINFOEXA MONITORINFOEX; + typedef LPMONITORINFOEXA LPMONITORINFOEX; +#endif +#endif + +#ifdef UNICODE +#define GetMonitorInfo GetMonitorInfoW +#else +#define GetMonitorInfo GetMonitorInfoA +#endif + + WINUSERAPI WINBOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor,LPMONITORINFO lpmi); + WINUSERAPI WINBOOL WINAPI GetMonitorInfoW(HMONITOR hMonitor,LPMONITORINFO lpmi); + + typedef WINBOOL (CALLBACK *MONITORENUMPROC)(HMONITOR,HDC,LPRECT,LPARAM); + + WINUSERAPI WINBOOL WINAPI EnumDisplayMonitors(HDC hdc,LPCRECT lprcClip,MONITORENUMPROC lpfnEnum,LPARAM dwData); + +#ifndef NOWINABLE + WINUSERAPI VOID WINAPI NotifyWinEvent(DWORD event,HWND hwnd,LONG idObject,LONG idChild); + + typedef VOID (CALLBACK *WINEVENTPROC)(HWINEVENTHOOK hWinEventHook,DWORD event,HWND hwnd,LONG idObject,LONG idChild,DWORD idEventThread,DWORD dwmsEventTime); + + WINUSERAPI HWINEVENTHOOK WINAPI SetWinEventHook(DWORD eventMin,DWORD eventMax,HMODULE hmodWinEventProc,WINEVENTPROC pfnWinEventProc,DWORD idProcess,DWORD idThread,DWORD dwFlags); + WINUSERAPI WINBOOL WINAPI IsWinEventHookInstalled(DWORD event); + +#define WINEVENT_OUTOFCONTEXT 0x0000 +#define WINEVENT_SKIPOWNTHREAD 0x0001 +#define WINEVENT_SKIPOWNPROCESS 0x0002 +#define WINEVENT_INCONTEXT 0x0004 + + WINUSERAPI WINBOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hWinEventHook); + +#define CHILDID_SELF 0 +#define INDEXID_OBJECT 0 +#define INDEXID_CONTAINER 0 + +#define OBJID_WINDOW ((LONG)0x00000000) +#define OBJID_SYSMENU ((LONG)0xFFFFFFFF) +#define OBJID_TITLEBAR ((LONG)0xFFFFFFFE) +#define OBJID_MENU ((LONG)0xFFFFFFFD) +#define OBJID_CLIENT ((LONG)0xFFFFFFFC) +#define OBJID_VSCROLL ((LONG)0xFFFFFFFB) +#define OBJID_HSCROLL ((LONG)0xFFFFFFFA) +#define OBJID_SIZEGRIP ((LONG)0xFFFFFFF9) +#define OBJID_CARET ((LONG)0xFFFFFFF8) +#define OBJID_CURSOR ((LONG)0xFFFFFFF7) +#define OBJID_ALERT ((LONG)0xFFFFFFF6) +#define OBJID_SOUND ((LONG)0xFFFFFFF5) +#define OBJID_QUERYCLASSNAMEIDX ((LONG)0xFFFFFFF4) +#define OBJID_NATIVEOM ((LONG)0xFFFFFFF0) + +#define EVENT_MIN 0x00000001 +#define EVENT_MAX 0x7FFFFFFF + +#define EVENT_SYSTEM_SOUND 0x0001 +#define EVENT_SYSTEM_ALERT 0x0002 +#define EVENT_SYSTEM_FOREGROUND 0x0003 +#define EVENT_SYSTEM_MENUSTART 0x0004 +#define EVENT_SYSTEM_MENUEND 0x0005 +#define EVENT_SYSTEM_MENUPOPUPSTART 0x0006 +#define EVENT_SYSTEM_MENUPOPUPEND 0x0007 +#define EVENT_SYSTEM_CAPTURESTART 0x0008 +#define EVENT_SYSTEM_CAPTUREEND 0x0009 +#define EVENT_SYSTEM_MOVESIZESTART 0x000A +#define EVENT_SYSTEM_MOVESIZEEND 0x000B +#define EVENT_SYSTEM_CONTEXTHELPSTART 0x000C +#define EVENT_SYSTEM_CONTEXTHELPEND 0x000D +#define EVENT_SYSTEM_DRAGDROPSTART 0x000E +#define EVENT_SYSTEM_DRAGDROPEND 0x000F +#define EVENT_SYSTEM_DIALOGSTART 0x0010 +#define EVENT_SYSTEM_DIALOGEND 0x0011 +#define EVENT_SYSTEM_SCROLLINGSTART 0x0012 +#define EVENT_SYSTEM_SCROLLINGEND 0x0013 +#define EVENT_SYSTEM_SWITCHSTART 0x0014 +#define EVENT_SYSTEM_SWITCHEND 0x0015 +#define EVENT_SYSTEM_MINIMIZESTART 0x0016 +#define EVENT_SYSTEM_MINIMIZEEND 0x0017 + +#define EVENT_CONSOLE_CARET 0x4001 +#define EVENT_CONSOLE_UPDATE_REGION 0x4002 +#define EVENT_CONSOLE_UPDATE_SIMPLE 0x4003 +#define EVENT_CONSOLE_UPDATE_SCROLL 0x4004 +#define EVENT_CONSOLE_LAYOUT 0x4005 +#define EVENT_CONSOLE_START_APPLICATION 0x4006 +#define EVENT_CONSOLE_END_APPLICATION 0x4007 + +#define CONSOLE_APPLICATION_16BIT 0x0001 + +#define CONSOLE_CARET_SELECTION 0x0001 +#define CONSOLE_CARET_VISIBLE 0x0002 + +#define EVENT_OBJECT_CREATE 0x8000 +#define EVENT_OBJECT_DESTROY 0x8001 +#define EVENT_OBJECT_SHOW 0x8002 +#define EVENT_OBJECT_HIDE 0x8003 +#define EVENT_OBJECT_REORDER 0x8004 + +#define EVENT_OBJECT_FOCUS 0x8005 +#define EVENT_OBJECT_SELECTION 0x8006 +#define EVENT_OBJECT_SELECTIONADD 0x8007 +#define EVENT_OBJECT_SELECTIONREMOVE 0x8008 +#define EVENT_OBJECT_SELECTIONWITHIN 0x8009 + +#define EVENT_OBJECT_STATECHANGE 0x800A + +#define EVENT_OBJECT_LOCATIONCHANGE 0x800B + +#define EVENT_OBJECT_NAMECHANGE 0x800C +#define EVENT_OBJECT_DESCRIPTIONCHANGE 0x800D +#define EVENT_OBJECT_VALUECHANGE 0x800E +#define EVENT_OBJECT_PARENTCHANGE 0x800F +#define EVENT_OBJECT_HELPCHANGE 0x8010 +#define EVENT_OBJECT_DEFACTIONCHANGE 0x8011 +#define EVENT_OBJECT_ACCELERATORCHANGE 0x8012 + +#define SOUND_SYSTEM_STARTUP 1 +#define SOUND_SYSTEM_SHUTDOWN 2 +#define SOUND_SYSTEM_BEEP 3 +#define SOUND_SYSTEM_ERROR 4 +#define SOUND_SYSTEM_QUESTION 5 +#define SOUND_SYSTEM_WARNING 6 +#define SOUND_SYSTEM_INFORMATION 7 +#define SOUND_SYSTEM_MAXIMIZE 8 +#define SOUND_SYSTEM_MINIMIZE 9 +#define SOUND_SYSTEM_RESTOREUP 10 +#define SOUND_SYSTEM_RESTOREDOWN 11 +#define SOUND_SYSTEM_APPSTART 12 +#define SOUND_SYSTEM_FAULT 13 +#define SOUND_SYSTEM_APPEND 14 +#define SOUND_SYSTEM_MENUCOMMAND 15 +#define SOUND_SYSTEM_MENUPOPUP 16 +#define CSOUND_SYSTEM 16 + +#define ALERT_SYSTEM_INFORMATIONAL 1 +#define ALERT_SYSTEM_WARNING 2 +#define ALERT_SYSTEM_ERROR 3 +#define ALERT_SYSTEM_QUERY 4 +#define ALERT_SYSTEM_CRITICAL 5 +#define CALERT_SYSTEM 6 + + typedef struct tagGUITHREADINFO { + DWORD cbSize; + DWORD flags; + HWND hwndActive; + HWND hwndFocus; + HWND hwndCapture; + HWND hwndMenuOwner; + HWND hwndMoveSize; + HWND hwndCaret; + RECT rcCaret; + } GUITHREADINFO,*PGUITHREADINFO,*LPGUITHREADINFO; + +#define GUI_CARETBLINKING 0x00000001 +#define GUI_INMOVESIZE 0x00000002 +#define GUI_INMENUMODE 0x00000004 +#define GUI_SYSTEMMENUMODE 0x00000008 +#define GUI_POPUPMENUMODE 0x00000010 +#define GUI_16BITTASK 0x00000020 + +#ifdef UNICODE +#define GetWindowModuleFileName GetWindowModuleFileNameW +#else +#define GetWindowModuleFileName GetWindowModuleFileNameA +#endif + + WINUSERAPI WINBOOL WINAPI GetGUIThreadInfo(DWORD idThread,PGUITHREADINFO pgui); + WINUSERAPI UINT WINAPI GetWindowModuleFileNameA(HWND hwnd,LPSTR pszFileName,UINT cchFileNameMax); + WINUSERAPI UINT WINAPI GetWindowModuleFileNameW(HWND hwnd,LPWSTR pszFileName,UINT cchFileNameMax); + +#ifndef NO_STATE_FLAGS +#define STATE_SYSTEM_UNAVAILABLE 0x00000001 +#define STATE_SYSTEM_SELECTED 0x00000002 +#define STATE_SYSTEM_FOCUSED 0x00000004 +#define STATE_SYSTEM_PRESSED 0x00000008 +#define STATE_SYSTEM_CHECKED 0x00000010 +#define STATE_SYSTEM_MIXED 0x00000020 +#define STATE_SYSTEM_INDETERMINATE STATE_SYSTEM_MIXED +#define STATE_SYSTEM_READONLY 0x00000040 +#define STATE_SYSTEM_HOTTRACKED 0x00000080 +#define STATE_SYSTEM_DEFAULT 0x00000100 +#define STATE_SYSTEM_EXPANDED 0x00000200 +#define STATE_SYSTEM_COLLAPSED 0x00000400 +#define STATE_SYSTEM_BUSY 0x00000800 +#define STATE_SYSTEM_FLOATING 0x00001000 +#define STATE_SYSTEM_MARQUEED 0x00002000 +#define STATE_SYSTEM_ANIMATED 0x00004000 +#define STATE_SYSTEM_INVISIBLE 0x00008000 +#define STATE_SYSTEM_OFFSCREEN 0x00010000 +#define STATE_SYSTEM_SIZEABLE 0x00020000 +#define STATE_SYSTEM_MOVEABLE 0x00040000 +#define STATE_SYSTEM_SELFVOICING 0x00080000 +#define STATE_SYSTEM_FOCUSABLE 0x00100000 +#define STATE_SYSTEM_SELECTABLE 0x00200000 +#define STATE_SYSTEM_LINKED 0x00400000 +#define STATE_SYSTEM_TRAVERSED 0x00800000 +#define STATE_SYSTEM_MULTISELECTABLE 0x01000000 +#define STATE_SYSTEM_EXTSELECTABLE 0x02000000 +#define STATE_SYSTEM_ALERT_LOW 0x04000000 +#define STATE_SYSTEM_ALERT_MEDIUM 0x08000000 +#define STATE_SYSTEM_ALERT_HIGH 0x10000000 +#define STATE_SYSTEM_PROTECTED 0x20000000 +#define STATE_SYSTEM_VALID 0x3FFFFFFF +#endif + +#define CCHILDREN_TITLEBAR 5 +#define CCHILDREN_SCROLLBAR 5 + + typedef struct tagCURSORINFO { + DWORD cbSize; + DWORD flags; + HCURSOR hCursor; + POINT ptScreenPos; + } CURSORINFO,*PCURSORINFO,*LPCURSORINFO; + +#define CURSOR_SHOWING 0x00000001 + + WINUSERAPI WINBOOL WINAPI GetCursorInfo(PCURSORINFO pci); + + typedef struct tagWINDOWINFO { + DWORD cbSize; + RECT rcWindow; + RECT rcClient; + DWORD dwStyle; + DWORD dwExStyle; + DWORD dwWindowStatus; + UINT cxWindowBorders; + UINT cyWindowBorders; + ATOM atomWindowType; + WORD wCreatorVersion; + } WINDOWINFO,*PWINDOWINFO,*LPWINDOWINFO; + +#define WS_ACTIVECAPTION 0x0001 + + WINUSERAPI WINBOOL WINAPI GetWindowInfo(HWND hwnd,PWINDOWINFO pwi); + + typedef struct tagTITLEBARINFO { + DWORD cbSize; + RECT rcTitleBar; + DWORD rgstate[CCHILDREN_TITLEBAR + 1]; + } TITLEBARINFO,*PTITLEBARINFO,*LPTITLEBARINFO; + + WINUSERAPI WINBOOL WINAPI GetTitleBarInfo(HWND hwnd,PTITLEBARINFO pti); + + typedef struct tagMENUBARINFO { + DWORD cbSize; + RECT rcBar; + HMENU hMenu; + HWND hwndMenu; + WINBOOL fBarFocused:1; + WINBOOL fFocused:1; + } MENUBARINFO,*PMENUBARINFO,*LPMENUBARINFO; + + WINUSERAPI WINBOOL WINAPI GetMenuBarInfo(HWND hwnd,LONG idObject,LONG idItem,PMENUBARINFO pmbi); + + typedef struct tagSCROLLBARINFO { + DWORD cbSize; + RECT rcScrollBar; + int dxyLineButton; + int xyThumbTop; + int xyThumbBottom; + int reserved; + DWORD rgstate[CCHILDREN_SCROLLBAR + 1]; + } SCROLLBARINFO,*PSCROLLBARINFO,*LPSCROLLBARINFO; + + WINUSERAPI WINBOOL WINAPI GetScrollBarInfo(HWND hwnd,LONG idObject,PSCROLLBARINFO psbi); + + typedef struct tagCOMBOBOXINFO { + DWORD cbSize; + RECT rcItem; + RECT rcButton; + DWORD stateButton; + HWND hwndCombo; + HWND hwndItem; + HWND hwndList; + } COMBOBOXINFO,*PCOMBOBOXINFO,*LPCOMBOBOXINFO; + + WINUSERAPI WINBOOL WINAPI GetComboBoxInfo(HWND hwndCombo,PCOMBOBOXINFO pcbi); + +#define GA_PARENT 1 +#define GA_ROOT 2 +#define GA_ROOTOWNER 3 + + WINUSERAPI HWND WINAPI GetAncestor(HWND hwnd,UINT gaFlags); + WINUSERAPI HWND WINAPI RealChildWindowFromPoint(HWND hwndParent,POINT ptParentClientCoords); + WINUSERAPI UINT WINAPI RealGetWindowClassA(HWND hwnd,LPSTR ptszClassName,UINT cchClassNameMax); + WINUSERAPI UINT WINAPI RealGetWindowClassW(HWND hwnd,LPWSTR ptszClassName,UINT cchClassNameMax); +#ifdef UNICODE +#define RealGetWindowClass RealGetWindowClassW +#else +#define RealGetWindowClass RealGetWindowClassA +#endif + + typedef struct tagALTTABINFO { + DWORD cbSize; + int cItems; + int cColumns; + int cRows; + int iColFocus; + int iRowFocus; + int cxItem; + int cyItem; + POINT ptStart; + } ALTTABINFO,*PALTTABINFO,*LPALTTABINFO; + +#ifdef UNICODE +#define GetAltTabInfo GetAltTabInfoW +#else +#define GetAltTabInfo GetAltTabInfoA +#endif + + WINUSERAPI WINBOOL WINAPI GetAltTabInfoA(HWND hwnd,int iItem,PALTTABINFO pati,LPSTR pszItemText,UINT cchItemText); + WINUSERAPI WINBOOL WINAPI GetAltTabInfoW(HWND hwnd,int iItem,PALTTABINFO pati,LPWSTR pszItemText,UINT cchItemText); + WINUSERAPI DWORD WINAPI GetListBoxInfo(HWND hwnd); +#endif + + WINUSERAPI WINBOOL WINAPI LockWorkStation(VOID); + WINUSERAPI WINBOOL WINAPI UserHandleGrantAccess(HANDLE hUserHandle,HANDLE hJob,WINBOOL bGrant); + + DECLARE_HANDLE(HRAWINPUT); + +#define GET_RAWINPUT_CODE_WPARAM(wParam) ((wParam) & 0xff) + +#define RIM_INPUT 0 +#define RIM_INPUTSINK 1 + + typedef struct tagRAWINPUTHEADER { + DWORD dwType; + DWORD dwSize; + HANDLE hDevice; + WPARAM wParam; + } RAWINPUTHEADER,*PRAWINPUTHEADER,*LPRAWINPUTHEADER; + +#define RIM_TYPEMOUSE 0 +#define RIM_TYPEKEYBOARD 1 +#define RIM_TYPEHID 2 + + typedef struct tagRAWMOUSE { + USHORT usFlags; + union { + ULONG ulButtons; + struct { + USHORT usButtonFlags; + USHORT usButtonData; + }; + }; + ULONG ulRawButtons; + LONG lLastX; + LONG lLastY; + ULONG ulExtraInformation; + } RAWMOUSE,*PRAWMOUSE,*LPRAWMOUSE; + +#define RI_MOUSE_LEFT_BUTTON_DOWN 0x0001 +#define RI_MOUSE_LEFT_BUTTON_UP 0x0002 +#define RI_MOUSE_RIGHT_BUTTON_DOWN 0x0004 +#define RI_MOUSE_RIGHT_BUTTON_UP 0x0008 +#define RI_MOUSE_MIDDLE_BUTTON_DOWN 0x0010 +#define RI_MOUSE_MIDDLE_BUTTON_UP 0x0020 + +#define RI_MOUSE_BUTTON_1_DOWN RI_MOUSE_LEFT_BUTTON_DOWN +#define RI_MOUSE_BUTTON_1_UP RI_MOUSE_LEFT_BUTTON_UP +#define RI_MOUSE_BUTTON_2_DOWN RI_MOUSE_RIGHT_BUTTON_DOWN +#define RI_MOUSE_BUTTON_2_UP RI_MOUSE_RIGHT_BUTTON_UP +#define RI_MOUSE_BUTTON_3_DOWN RI_MOUSE_MIDDLE_BUTTON_DOWN +#define RI_MOUSE_BUTTON_3_UP RI_MOUSE_MIDDLE_BUTTON_UP + +#define RI_MOUSE_BUTTON_4_DOWN 0x0040 +#define RI_MOUSE_BUTTON_4_UP 0x0080 +#define RI_MOUSE_BUTTON_5_DOWN 0x0100 +#define RI_MOUSE_BUTTON_5_UP 0x0200 + +#define RI_MOUSE_WHEEL 0x0400 + +#define MOUSE_MOVE_RELATIVE 0 +#define MOUSE_MOVE_ABSOLUTE 1 +#define MOUSE_VIRTUAL_DESKTOP 0x02 +#define MOUSE_ATTRIBUTES_CHANGED 0x04 + + typedef struct tagRAWKEYBOARD { + USHORT MakeCode; + USHORT Flags; + USHORT Reserved; + USHORT VKey; + UINT Message; + ULONG ExtraInformation; + } RAWKEYBOARD,*PRAWKEYBOARD,*LPRAWKEYBOARD; + +#define KEYBOARD_OVERRUN_MAKE_CODE 0xFF + +#define RI_KEY_MAKE 0 +#define RI_KEY_BREAK 1 +#define RI_KEY_E0 2 +#define RI_KEY_E1 4 +#define RI_KEY_TERMSRV_SET_LED 8 +#define RI_KEY_TERMSRV_SHADOW 0x10 + + typedef struct tagRAWHID { + DWORD dwSizeHid; + DWORD dwCount; + BYTE bRawData[1]; + } RAWHID,*PRAWHID,*LPRAWHID; + + typedef struct tagRAWINPUT { + RAWINPUTHEADER header; + union { + RAWMOUSE mouse; + RAWKEYBOARD keyboard; + RAWHID hid; + } data; + } RAWINPUT,*PRAWINPUT,*LPRAWINPUT; + +#ifdef _WIN64 +#define RAWINPUT_ALIGN(x) (((x) + sizeof(QWORD) - 1) & ~(sizeof(QWORD) - 1)) +#else +#define RAWINPUT_ALIGN(x) (((x) + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1)) +#endif + +#define NEXTRAWINPUTBLOCK(ptr) ((PRAWINPUT)RAWINPUT_ALIGN((ULONG_PTR)((PBYTE)(ptr) + (ptr)->header.dwSize))) + +#define RID_INPUT 0x10000003 +#define RID_HEADER 0x10000005 + + WINUSERAPI UINT WINAPI GetRawInputData(HRAWINPUT hRawInput,UINT uiCommand,LPVOID pData,PUINT pcbSize,UINT cbSizeHeader); + +#define RIDI_PREPARSEDDATA 0x20000005 +#define RIDI_DEVICENAME 0x20000007 +#define RIDI_DEVICEINFO 0x2000000b + + typedef struct tagRID_DEVICE_INFO_MOUSE { + DWORD dwId; + DWORD dwNumberOfButtons; + DWORD dwSampleRate; + } RID_DEVICE_INFO_MOUSE,*PRID_DEVICE_INFO_MOUSE; + + typedef struct tagRID_DEVICE_INFO_KEYBOARD { + DWORD dwType; + DWORD dwSubType; + DWORD dwKeyboardMode; + DWORD dwNumberOfFunctionKeys; + DWORD dwNumberOfIndicators; + DWORD dwNumberOfKeysTotal; + } RID_DEVICE_INFO_KEYBOARD,*PRID_DEVICE_INFO_KEYBOARD; + + typedef struct tagRID_DEVICE_INFO_HID { + DWORD dwVendorId; + DWORD dwProductId; + DWORD dwVersionNumber; + USHORT usUsagePage; + USHORT usUsage; + } RID_DEVICE_INFO_HID,*PRID_DEVICE_INFO_HID; + + typedef struct tagRID_DEVICE_INFO { + DWORD cbSize; + DWORD dwType; + union { + RID_DEVICE_INFO_MOUSE mouse; + RID_DEVICE_INFO_KEYBOARD keyboard; + RID_DEVICE_INFO_HID hid; + }; + } RID_DEVICE_INFO,*PRID_DEVICE_INFO,*LPRID_DEVICE_INFO; + +#ifdef UNICODE +#define GetRawInputDeviceInfo GetRawInputDeviceInfoW +#else +#define GetRawInputDeviceInfo GetRawInputDeviceInfoA +#endif + + WINUSERAPI UINT WINAPI GetRawInputDeviceInfoA(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); + WINUSERAPI UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice,UINT uiCommand,LPVOID pData,PUINT pcbSize); + WINUSERAPI UINT WINAPI GetRawInputBuffer(PRAWINPUT pData,PUINT pcbSize,UINT cbSizeHeader); + + typedef struct tagRAWINPUTDEVICE { + USHORT usUsagePage; + USHORT usUsage; + DWORD dwFlags; + HWND hwndTarget; + } RAWINPUTDEVICE,*PRAWINPUTDEVICE,*LPRAWINPUTDEVICE; + + typedef CONST RAWINPUTDEVICE *PCRAWINPUTDEVICE; + +#define RIDEV_REMOVE 0x00000001 +#define RIDEV_EXCLUDE 0x00000010 +#define RIDEV_PAGEONLY 0x00000020 +#define RIDEV_NOLEGACY 0x00000030 +#define RIDEV_INPUTSINK 0x00000100 +#define RIDEV_CAPTUREMOUSE 0x00000200 +#define RIDEV_NOHOTKEYS 0x00000200 +#define RIDEV_APPKEYS 0x00000400 +#define RIDEV_EXMODEMASK 0x000000F0 +#define RIDEV_EXMODE(mode) ((mode) & RIDEV_EXMODEMASK) + + WINUSERAPI WINBOOL WINAPI RegisterRawInputDevices(PCRAWINPUTDEVICE pRawInputDevices,UINT uiNumDevices,UINT cbSize); + WINUSERAPI UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices,PUINT puiNumDevices,UINT cbSize); + + typedef struct tagRAWINPUTDEVICELIST { + HANDLE hDevice; + DWORD dwType; + } RAWINPUTDEVICELIST,*PRAWINPUTDEVICELIST; + + WINUSERAPI UINT WINAPI GetRawInputDeviceList(PRAWINPUTDEVICELIST pRawInputDeviceList,PUINT puiNumDevices,UINT cbSize); + WINUSERAPI LRESULT WINAPI DefRawInputProc(PRAWINPUT *paRawInput,INT nInput,UINT cbSizeHeader); + +#endif /* NOUSER */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/winver.h b/tcc/include/winapi/winver.h index bebd0453..5c0f036b 100644 --- a/tcc/include/winapi/winver.h +++ b/tcc/include/winapi/winver.h @@ -1,160 +1,160 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef VER_H -#define VER_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define VS_FILE_INFO RT_VERSION -#define VS_VERSION_INFO 1 -#define VS_USER_DEFINED 100 - -#define VS_FFI_SIGNATURE 0xFEEF04BDL -#define VS_FFI_STRUCVERSION 0x00010000L -#define VS_FFI_FILEFLAGSMASK 0x0000003FL - -#define VS_FF_DEBUG 0x00000001L -#define VS_FF_PRERELEASE 0x00000002L -#define VS_FF_PATCHED 0x00000004L -#define VS_FF_PRIVATEBUILD 0x00000008L -#define VS_FF_INFOINFERRED 0x00000010L -#define VS_FF_SPECIALBUILD 0x00000020L - -#define VOS_UNKNOWN 0x00000000L -#define VOS_DOS 0x00010000L -#define VOS_OS216 0x00020000L -#define VOS_OS232 0x00030000L -#define VOS_NT 0x00040000L -#define VOS_WINCE 0x00050000L - -#define VOS__BASE 0x00000000L -#define VOS__WINDOWS16 0x00000001L -#define VOS__PM16 0x00000002L -#define VOS__PM32 0x00000003L -#define VOS__WINDOWS32 0x00000004L - -#define VOS_DOS_WINDOWS16 0x00010001L -#define VOS_DOS_WINDOWS32 0x00010004L -#define VOS_OS216_PM16 0x00020002L -#define VOS_OS232_PM32 0x00030003L -#define VOS_NT_WINDOWS32 0x00040004L - -#define VFT_UNKNOWN 0x00000000L -#define VFT_APP 0x00000001L -#define VFT_DLL 0x00000002L -#define VFT_DRV 0x00000003L -#define VFT_FONT 0x00000004L -#define VFT_VXD 0x00000005L -#define VFT_STATIC_LIB 0x00000007L - -#define VFT2_UNKNOWN 0x00000000L -#define VFT2_DRV_PRINTER 0x00000001L -#define VFT2_DRV_KEYBOARD 0x00000002L -#define VFT2_DRV_LANGUAGE 0x00000003L -#define VFT2_DRV_DISPLAY 0x00000004L -#define VFT2_DRV_MOUSE 0x00000005L -#define VFT2_DRV_NETWORK 0x00000006L -#define VFT2_DRV_SYSTEM 0x00000007L -#define VFT2_DRV_INSTALLABLE 0x00000008L -#define VFT2_DRV_SOUND 0x00000009L -#define VFT2_DRV_COMM 0x0000000AL -#define VFT2_DRV_INPUTMETHOD 0x0000000BL -#define VFT2_DRV_VERSIONED_PRINTER 0x0000000CL - -#define VFT2_FONT_RASTER 0x00000001L -#define VFT2_FONT_VECTOR 0x00000002L -#define VFT2_FONT_TRUETYPE 0x00000003L - -#define VFFF_ISSHAREDFILE 0x0001 - -#define VFF_CURNEDEST 0x0001 -#define VFF_FILEINUSE 0x0002 -#define VFF_BUFFTOOSMALL 0x0004 - -#define VIFF_FORCEINSTALL 0x0001 -#define VIFF_DONTDELETEOLD 0x0002 - -#define VIF_TEMPFILE 0x00000001L -#define VIF_MISMATCH 0x00000002L -#define VIF_SRCOLD 0x00000004L - -#define VIF_DIFFLANG 0x00000008L -#define VIF_DIFFCODEPG 0x00000010L -#define VIF_DIFFTYPE 0x00000020L - -#define VIF_WRITEPROT 0x00000040L -#define VIF_FILEINUSE 0x00000080L -#define VIF_OUTOFSPACE 0x00000100L -#define VIF_ACCESSVIOLATION 0x00000200L -#define VIF_SHARINGVIOLATION 0x00000400L -#define VIF_CANNOTCREATE 0x00000800L -#define VIF_CANNOTDELETE 0x00001000L -#define VIF_CANNOTRENAME 0x00002000L -#define VIF_CANNOTDELETECUR 0x00004000L -#define VIF_OUTOFMEMORY 0x00008000L - -#define VIF_CANNOTREADSRC 0x00010000L -#define VIF_CANNOTREADDST 0x00020000L - -#define VIF_BUFFTOOSMALL 0x00040000L -#define VIF_CANNOTLOADLZ32 0x00080000L -#define VIF_CANNOTLOADCABINET 0x00100000L - -#ifndef RC_INVOKED - - typedef struct tagVS_FIXEDFILEINFO - { - DWORD dwSignature; - DWORD dwStrucVersion; - DWORD dwFileVersionMS; - DWORD dwFileVersionLS; - DWORD dwProductVersionMS; - DWORD dwProductVersionLS; - DWORD dwFileFlagsMask; - DWORD dwFileFlags; - DWORD dwFileOS; - DWORD dwFileType; - DWORD dwFileSubtype; - DWORD dwFileDateMS; - DWORD dwFileDateLS; - } VS_FIXEDFILEINFO; - -#ifdef UNICODE -#define VerFindFile VerFindFileW -#define VerInstallFile VerInstallFileW -#define GetFileVersionInfoSize GetFileVersionInfoSizeW -#define GetFileVersionInfo GetFileVersionInfoW -#define VerLanguageName VerLanguageNameW -#define VerQueryValue VerQueryValueW -#else -#define VerFindFile VerFindFileA -#define VerInstallFile VerInstallFileA -#define GetFileVersionInfoSize GetFileVersionInfoSizeA -#define GetFileVersionInfo GetFileVersionInfoA -#define VerLanguageName VerLanguageNameA -#define VerQueryValue VerQueryValueA -#endif - - DWORD WINAPI VerFindFileA(DWORD uFlags,LPSTR szFileName,LPSTR szWinDir,LPSTR szAppDir,LPSTR szCurDir,PUINT lpuCurDirLen,LPSTR szDestDir,PUINT lpuDestDirLen); - DWORD WINAPI VerFindFileW(DWORD uFlags,LPWSTR szFileName,LPWSTR szWinDir,LPWSTR szAppDir,LPWSTR szCurDir,PUINT lpuCurDirLen,LPWSTR szDestDir,PUINT lpuDestDirLen); - DWORD WINAPI VerInstallFileA(DWORD uFlags,LPSTR szSrcFileName,LPSTR szDestFileName,LPSTR szSrcDir,LPSTR szDestDir,LPSTR szCurDir,LPSTR szTmpFile,PUINT lpuTmpFileLen); - DWORD WINAPI VerInstallFileW(DWORD uFlags,LPWSTR szSrcFileName,LPWSTR szDestFileName,LPWSTR szSrcDir,LPWSTR szDestDir,LPWSTR szCurDir,LPWSTR szTmpFile,PUINT lpuTmpFileLen); - DWORD WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename,LPDWORD lpdwHandle); - DWORD WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename,LPDWORD lpdwHandle); - WINBOOL WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); - WINBOOL WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); - DWORD WINAPI VerLanguageNameA(DWORD wLang,LPSTR szLang,DWORD nSize); - DWORD WINAPI VerLanguageNameW(DWORD wLang,LPWSTR szLang,DWORD nSize); - WINBOOL WINAPI VerQueryValueA(const LPVOID pBlock,LPSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); - WINBOOL WINAPI VerQueryValueW(const LPVOID pBlock,LPWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); -#endif - -#ifdef __cplusplus -} -#endif -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef VER_H +#define VER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define VS_FILE_INFO RT_VERSION +#define VS_VERSION_INFO 1 +#define VS_USER_DEFINED 100 + +#define VS_FFI_SIGNATURE 0xFEEF04BDL +#define VS_FFI_STRUCVERSION 0x00010000L +#define VS_FFI_FILEFLAGSMASK 0x0000003FL + +#define VS_FF_DEBUG 0x00000001L +#define VS_FF_PRERELEASE 0x00000002L +#define VS_FF_PATCHED 0x00000004L +#define VS_FF_PRIVATEBUILD 0x00000008L +#define VS_FF_INFOINFERRED 0x00000010L +#define VS_FF_SPECIALBUILD 0x00000020L + +#define VOS_UNKNOWN 0x00000000L +#define VOS_DOS 0x00010000L +#define VOS_OS216 0x00020000L +#define VOS_OS232 0x00030000L +#define VOS_NT 0x00040000L +#define VOS_WINCE 0x00050000L + +#define VOS__BASE 0x00000000L +#define VOS__WINDOWS16 0x00000001L +#define VOS__PM16 0x00000002L +#define VOS__PM32 0x00000003L +#define VOS__WINDOWS32 0x00000004L + +#define VOS_DOS_WINDOWS16 0x00010001L +#define VOS_DOS_WINDOWS32 0x00010004L +#define VOS_OS216_PM16 0x00020002L +#define VOS_OS232_PM32 0x00030003L +#define VOS_NT_WINDOWS32 0x00040004L + +#define VFT_UNKNOWN 0x00000000L +#define VFT_APP 0x00000001L +#define VFT_DLL 0x00000002L +#define VFT_DRV 0x00000003L +#define VFT_FONT 0x00000004L +#define VFT_VXD 0x00000005L +#define VFT_STATIC_LIB 0x00000007L + +#define VFT2_UNKNOWN 0x00000000L +#define VFT2_DRV_PRINTER 0x00000001L +#define VFT2_DRV_KEYBOARD 0x00000002L +#define VFT2_DRV_LANGUAGE 0x00000003L +#define VFT2_DRV_DISPLAY 0x00000004L +#define VFT2_DRV_MOUSE 0x00000005L +#define VFT2_DRV_NETWORK 0x00000006L +#define VFT2_DRV_SYSTEM 0x00000007L +#define VFT2_DRV_INSTALLABLE 0x00000008L +#define VFT2_DRV_SOUND 0x00000009L +#define VFT2_DRV_COMM 0x0000000AL +#define VFT2_DRV_INPUTMETHOD 0x0000000BL +#define VFT2_DRV_VERSIONED_PRINTER 0x0000000CL + +#define VFT2_FONT_RASTER 0x00000001L +#define VFT2_FONT_VECTOR 0x00000002L +#define VFT2_FONT_TRUETYPE 0x00000003L + +#define VFFF_ISSHAREDFILE 0x0001 + +#define VFF_CURNEDEST 0x0001 +#define VFF_FILEINUSE 0x0002 +#define VFF_BUFFTOOSMALL 0x0004 + +#define VIFF_FORCEINSTALL 0x0001 +#define VIFF_DONTDELETEOLD 0x0002 + +#define VIF_TEMPFILE 0x00000001L +#define VIF_MISMATCH 0x00000002L +#define VIF_SRCOLD 0x00000004L + +#define VIF_DIFFLANG 0x00000008L +#define VIF_DIFFCODEPG 0x00000010L +#define VIF_DIFFTYPE 0x00000020L + +#define VIF_WRITEPROT 0x00000040L +#define VIF_FILEINUSE 0x00000080L +#define VIF_OUTOFSPACE 0x00000100L +#define VIF_ACCESSVIOLATION 0x00000200L +#define VIF_SHARINGVIOLATION 0x00000400L +#define VIF_CANNOTCREATE 0x00000800L +#define VIF_CANNOTDELETE 0x00001000L +#define VIF_CANNOTRENAME 0x00002000L +#define VIF_CANNOTDELETECUR 0x00004000L +#define VIF_OUTOFMEMORY 0x00008000L + +#define VIF_CANNOTREADSRC 0x00010000L +#define VIF_CANNOTREADDST 0x00020000L + +#define VIF_BUFFTOOSMALL 0x00040000L +#define VIF_CANNOTLOADLZ32 0x00080000L +#define VIF_CANNOTLOADCABINET 0x00100000L + +#ifndef RC_INVOKED + + typedef struct tagVS_FIXEDFILEINFO + { + DWORD dwSignature; + DWORD dwStrucVersion; + DWORD dwFileVersionMS; + DWORD dwFileVersionLS; + DWORD dwProductVersionMS; + DWORD dwProductVersionLS; + DWORD dwFileFlagsMask; + DWORD dwFileFlags; + DWORD dwFileOS; + DWORD dwFileType; + DWORD dwFileSubtype; + DWORD dwFileDateMS; + DWORD dwFileDateLS; + } VS_FIXEDFILEINFO; + +#ifdef UNICODE +#define VerFindFile VerFindFileW +#define VerInstallFile VerInstallFileW +#define GetFileVersionInfoSize GetFileVersionInfoSizeW +#define GetFileVersionInfo GetFileVersionInfoW +#define VerLanguageName VerLanguageNameW +#define VerQueryValue VerQueryValueW +#else +#define VerFindFile VerFindFileA +#define VerInstallFile VerInstallFileA +#define GetFileVersionInfoSize GetFileVersionInfoSizeA +#define GetFileVersionInfo GetFileVersionInfoA +#define VerLanguageName VerLanguageNameA +#define VerQueryValue VerQueryValueA +#endif + + DWORD WINAPI VerFindFileA(DWORD uFlags,LPSTR szFileName,LPSTR szWinDir,LPSTR szAppDir,LPSTR szCurDir,PUINT lpuCurDirLen,LPSTR szDestDir,PUINT lpuDestDirLen); + DWORD WINAPI VerFindFileW(DWORD uFlags,LPWSTR szFileName,LPWSTR szWinDir,LPWSTR szAppDir,LPWSTR szCurDir,PUINT lpuCurDirLen,LPWSTR szDestDir,PUINT lpuDestDirLen); + DWORD WINAPI VerInstallFileA(DWORD uFlags,LPSTR szSrcFileName,LPSTR szDestFileName,LPSTR szSrcDir,LPSTR szDestDir,LPSTR szCurDir,LPSTR szTmpFile,PUINT lpuTmpFileLen); + DWORD WINAPI VerInstallFileW(DWORD uFlags,LPWSTR szSrcFileName,LPWSTR szDestFileName,LPWSTR szSrcDir,LPWSTR szDestDir,LPWSTR szCurDir,LPWSTR szTmpFile,PUINT lpuTmpFileLen); + DWORD WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename,LPDWORD lpdwHandle); + DWORD WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename,LPDWORD lpdwHandle); + WINBOOL WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); + WINBOOL WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); + DWORD WINAPI VerLanguageNameA(DWORD wLang,LPSTR szLang,DWORD nSize); + DWORD WINAPI VerLanguageNameW(DWORD wLang,LPWSTR szLang,DWORD nSize); + WINBOOL WINAPI VerQueryValueA(const LPVOID pBlock,LPSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); + WINBOOL WINAPI VerQueryValueW(const LPVOID pBlock,LPWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tcc/include/winapi/ws2ipdef.h b/tcc/include/winapi/ws2ipdef.h index 46ea46f1..1f6c1c06 100644 --- a/tcc/include/winapi/ws2ipdef.h +++ b/tcc/include/winapi/ws2ipdef.h @@ -1,21 +1,21 @@ -#ifndef _WS2IPDEF_H -#define _WS2IPDEF_H - -#if __GNUC__ >=3 -#pragma GCC system_header -#endif - -#include - -struct ip_mreq { - struct in_addr imr_multiaddr; - struct in_addr imr_interface; -}; - -struct ip_mreq_source { - struct in_addr imr_multiaddr; - struct in_addr imr_sourceaddr; - struct in_addr imr_interface; -}; - -#endif +#ifndef _WS2IPDEF_H +#define _WS2IPDEF_H + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#include + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_sourceaddr; + struct in_addr imr_interface; +}; + +#endif diff --git a/tcc/include/winapi/ws2tcpip.h b/tcc/include/winapi/ws2tcpip.h index bdcf8b45..ac45767d 100644 --- a/tcc/include/winapi/ws2tcpip.h +++ b/tcc/include/winapi/ws2tcpip.h @@ -1,391 +1,391 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the w64 mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within this package. - */ -#ifndef _WS2TCPIP_H -#define _WS2TCPIP_H - -#if __GNUC__ >=3 -#pragma GCC system_header -#endif - -#include - -struct ip_msfilter { - struct in_addr imsf_multiaddr; - struct in_addr imsf_interface; - u_long imsf_fmode; - u_long imsf_numsrc; - struct in_addr imsf_slist[1]; -}; - -#define IP_MSFILTER_SIZE(numsrc) (sizeof(struct ip_msfilter)-sizeof(struct in_addr) + (numsrc)*sizeof(struct in_addr)) - -#define MCAST_INCLUDE 0 -#define MCAST_EXCLUDE 1 - -#define SIO_GET_INTERFACE_LIST _IOR('t',127,u_long) - -#define SIO_GET_INTERFACE_LIST_EX _IOR('t',126,u_long) -#define SIO_SET_MULTICAST_FILTER _IOW('t',125,u_long) -#define SIO_GET_MULTICAST_FILTER _IOW('t',124 | IOC_IN,u_long) - -#define IP_OPTIONS 1 -#define IP_HDRINCL 2 -#define IP_TOS 3 -#define IP_TTL 4 -#define IP_MULTICAST_IF 9 -#define IP_MULTICAST_TTL 10 -#define IP_MULTICAST_LOOP 11 -#define IP_ADD_MEMBERSHIP 12 -#define IP_DROP_MEMBERSHIP 13 -#define IP_DONTFRAGMENT 14 -#define IP_ADD_SOURCE_MEMBERSHIP 15 -#define IP_DROP_SOURCE_MEMBERSHIP 16 -#define IP_BLOCK_SOURCE 17 -#define IP_UNBLOCK_SOURCE 18 -#define IP_PKTINFO 19 -#define IP_RECEIVE_BROADCAST 22 - -#define IPV6_HDRINCL 2 -#define IPV6_UNICAST_HOPS 4 -#define IPV6_MULTICAST_IF 9 -#define IPV6_MULTICAST_HOPS 10 -#define IPV6_MULTICAST_LOOP 11 -#define IPV6_ADD_MEMBERSHIP 12 -#define IPV6_DROP_MEMBERSHIP 13 -#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP -#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP -#define IPV6_PKTINFO 19 -#define IPV6_HOPLIMIT 21 -#define IPV6_PROTECTION_LEVEL 23 - -#define PROTECTION_LEVEL_UNRESTRICTED 10 -#define PROTECTION_LEVEL_DEFAULT 20 -#define PROTECTION_LEVEL_RESTRICTED 30 - -#define UDP_NOCHECKSUM 1 -#define UDP_CHECKSUM_COVERAGE 20 - -#define TCP_EXPEDITED_1122 0x0002 - -#ifndef s6_addr - -struct in6_addr { - __MINGW_EXTENSION union { - u_char Byte[16]; - u_short Word[8]; - } u; -}; - -#define in_addr6 in6_addr - -#define _S6_un u -#define _S6_u8 Byte -#define s6_addr _S6_un._S6_u8 - -#define s6_bytes u.Byte -#define s6_words u.Word -#endif - -typedef struct ipv6_mreq { - struct in6_addr ipv6mr_multiaddr; - unsigned int ipv6mr_interface; -} IPV6_MREQ; - -struct sockaddr_in6_old { - short sin6_family; - u_short sin6_port; - u_long sin6_flowinfo; - struct in6_addr sin6_addr; -}; - -struct sockaddr_in6 { - short sin6_family; - u_short sin6_port; - u_long sin6_flowinfo; - struct in6_addr sin6_addr; - u_long sin6_scope_id; -}; - -typedef struct in6_addr IN6_ADDR; -typedef struct in6_addr *PIN6_ADDR; -typedef struct in6_addr *LPIN6_ADDR; - -typedef struct sockaddr_in6 SOCKADDR_IN6; -typedef struct sockaddr_in6 *PSOCKADDR_IN6; -typedef struct sockaddr_in6 *LPSOCKADDR_IN6; - -#define SS_PORT(ssp) (((struct sockaddr_in*)(ssp))->sin_port) - -#define IN6ADDR_ANY_INIT { 0 } -#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } - -#ifdef __cplusplus -extern "C" { -#endif - - extern const struct in6_addr in6addr_any; - extern const struct in6_addr in6addr_loopback; - -#ifdef __cplusplus -} -#endif - -#define WS2TCPIP_INLINE __CRT_INLINE - -int IN6_ADDR_EQUAL(const struct in6_addr *,const struct in6_addr *); -int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *); -int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *); -int IN6_IS_ADDR_MULTICAST(const struct in6_addr *); -int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *); -int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *); -int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *); -int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *); -int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *); -int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *); -int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *); -int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *); -int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *); -int IN6ADDR_ISANY(const struct sockaddr_in6 *); -int IN6ADDR_ISLOOPBACK(const struct sockaddr_in6 *); -void IN6_SET_ADDR_UNSPECIFIED(struct in6_addr *); -void IN6_SET_ADDR_LOOPBACK(struct in6_addr *); -void IN6ADDR_SETANY(struct sockaddr_in6 *); -void IN6ADDR_SETLOOPBACK(struct sockaddr_in6 *); - -#ifndef __CRT__NO_INLINE -WS2TCPIP_INLINE int IN6_ADDR_EQUAL(const struct in6_addr *a,const struct in6_addr *b) { return (memcmp(a,b,sizeof(struct in6_addr))==0); } -WS2TCPIP_INLINE int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && (a->s6_words[6]==0) && (a->s6_words[7]==0)); } -WS2TCPIP_INLINE int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && (a->s6_words[6]==0) && (a->s6_words[7]==0x0100)); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MULTICAST(const struct in6_addr *a) { return (a->s6_bytes[0]==0xff); } -WS2TCPIP_INLINE int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *a) { return ((a->s6_bytes[0]==0xfe) && ((a->s6_bytes[1] & 0xc0)==0x80)); } -WS2TCPIP_INLINE int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *a) { return ((a->s6_bytes[0]==0xfe) && ((a->s6_bytes[1] & 0xc0)==0xc0)); } -WS2TCPIP_INLINE int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0xffff)); } -WS2TCPIP_INLINE int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && !((a->s6_words[6]==0) && (a->s6_addr[14]==0) && ((a->s6_addr[15]==0) || (a->s6_addr[15]==1)))); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==1); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==2); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==5); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==8); } -WS2TCPIP_INLINE int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==0xe); } -WS2TCPIP_INLINE int IN6ADDR_ISANY(const struct sockaddr_in6 *a) { return ((a->sin6_family==AF_INET6) && IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)); } -WS2TCPIP_INLINE int IN6ADDR_ISLOOPBACK(const struct sockaddr_in6 *a) { return ((a->sin6_family==AF_INET6) && IN6_IS_ADDR_LOOPBACK(&a->sin6_addr)); } -WS2TCPIP_INLINE void IN6_SET_ADDR_UNSPECIFIED(struct in6_addr *a) { memset(a->s6_bytes,0,sizeof(struct in6_addr)); } -WS2TCPIP_INLINE void IN6_SET_ADDR_LOOPBACK(struct in6_addr *a) { - memset(a->s6_bytes,0,sizeof(struct in6_addr)); - a->s6_bytes[15] = 1; -} -WS2TCPIP_INLINE void IN6ADDR_SETANY(struct sockaddr_in6 *a) { - a->sin6_family = AF_INET6; - a->sin6_port = 0; - a->sin6_flowinfo = 0; - IN6_SET_ADDR_UNSPECIFIED(&a->sin6_addr); - a->sin6_scope_id = 0; -} -WS2TCPIP_INLINE void IN6ADDR_SETLOOPBACK(struct sockaddr_in6 *a) { - a->sin6_family = AF_INET6; - a->sin6_port = 0; - a->sin6_flowinfo = 0; - IN6_SET_ADDR_LOOPBACK(&a->sin6_addr); - a->sin6_scope_id = 0; -} -#endif /* !__CRT__NO_INLINE */ - -typedef union sockaddr_gen { - struct sockaddr Address; - struct sockaddr_in AddressIn; - struct sockaddr_in6_old AddressIn6; -} sockaddr_gen; - -typedef struct _INTERFACE_INFO { - u_long iiFlags; - sockaddr_gen iiAddress; - sockaddr_gen iiBroadcastAddress; - sockaddr_gen iiNetmask; -} INTERFACE_INFO,*LPINTERFACE_INFO; - -typedef struct _INTERFACE_INFO_EX { - u_long iiFlags; - SOCKET_ADDRESS iiAddress; - SOCKET_ADDRESS iiBroadcastAddress; - SOCKET_ADDRESS iiNetmask; -} INTERFACE_INFO_EX,*LPINTERFACE_INFO_EX; - -#define IFF_UP 0x00000001 -#define IFF_BROADCAST 0x00000002 -#define IFF_LOOPBACK 0x00000004 -#define IFF_POINTTOPOINT 0x00000008 -#define IFF_MULTICAST 0x00000010 - -typedef struct in_pktinfo { - IN_ADDR ipi_addr; - UINT ipi_ifindex; -} IN_PKTINFO; - -C_ASSERT(sizeof(IN_PKTINFO)==8); - -typedef struct in6_pktinfo { - IN6_ADDR ipi6_addr; - UINT ipi6_ifindex; -} IN6_PKTINFO; - -C_ASSERT(sizeof(IN6_PKTINFO)==20); - -#define EAI_AGAIN WSATRY_AGAIN -#define EAI_BADFLAGS WSAEINVAL -#define EAI_FAIL WSANO_RECOVERY -#define EAI_FAMILY WSAEAFNOSUPPORT -#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY - -#define EAI_NONAME WSAHOST_NOT_FOUND -#define EAI_SERVICE WSATYPE_NOT_FOUND -#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT - -#define EAI_NODATA EAI_NONAME - -typedef struct addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - size_t ai_addrlen; - char *ai_canonname; - struct sockaddr *ai_addr; - struct addrinfo *ai_next; -} ADDRINFOA,*PADDRINFOA; - -typedef struct addrinfoW { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - size_t ai_addrlen; - PWSTR ai_canonname; - struct sockaddr *ai_addr; - struct addrinfoW *ai_next; -} ADDRINFOW,*PADDRINFOW; - -#ifdef UNICODE -typedef ADDRINFOW ADDRINFOT,*PADDRINFOT; -#else -typedef ADDRINFOA ADDRINFOT,*PADDRINFOT; -#endif - -typedef ADDRINFOA ADDRINFO,*LPADDRINFO; - -#define AI_PASSIVE 0x1 -#define AI_CANONNAME 0x2 -#define AI_NUMERICHOST 0x4 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef UNICODE -#define GetAddrInfo GetAddrInfoW -#else -#define GetAddrInfo GetAddrInfoA -#endif - - WINSOCK_API_LINKAGE int WSAAPI getaddrinfo(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res); - WINSOCK_API_LINKAGE int WSAAPI GetAddrInfoW(PCWSTR pNodeName,PCWSTR pServiceName,const ADDRINFOW *pHints,PADDRINFOW *ppResult); - -#define GetAddrInfoA getaddrinfo - -#if INCL_WINSOCK_API_TYPEDEFS - typedef int (WSAAPI *LPFN_GETADDRINFO)(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res); - typedef int (WSAAPI *LPFN_GETADDRINFOW)(PCWSTR pNodeName,PCWSTR pServiceName,const ADDRINFOW *pHints,PADDRINFOW *ppResult); - -#define LPFN_GETADDRINFOA LPFN_GETADDRINFO - -#ifdef UNICODE -#define LPFN_GETADDRINFOT LPFN_GETADDRINFOW -#else -#define LPFN_GETADDRINFOT LPFN_GETADDRINFOA -#endif -#endif - -#ifdef UNICODE -#define FreeAddrInfo FreeAddrInfoW -#else -#define FreeAddrInfo FreeAddrInfoA -#endif - - WINSOCK_API_LINKAGE void WSAAPI freeaddrinfo(LPADDRINFO pAddrInfo); - WINSOCK_API_LINKAGE void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo); - -#define FreeAddrInfoA freeaddrinfo - -#if INCL_WINSOCK_API_TYPEDEFS - typedef void (WSAAPI *LPFN_FREEADDRINFO)(struct addrinfo *ai); - typedef void (WSAAPI *LPFN_FREEADDRINFOW)(PADDRINFOW pAddrInfo); - -#define LPFN_FREEADDRINFOA LPFN_FREEADDRINFO - -#ifdef UNICODE -#define LPFN_FREEADDRINFOT LPFN_FREEADDRINFOW -#else -#define LPFN_FREEADDRINFOT LPFN_FREEADDRINFOA -#endif -#endif - -#pragma push_macro("socklen_t") -#undef socklen_t - - typedef int socklen_t; - -#ifdef UNICODE -#define GetNameInfo GetNameInfoW -#else -#define GetNameInfo GetNameInfoA -#endif - - WINSOCK_API_LINKAGE int WSAAPI getnameinfo(const struct sockaddr *sa,socklen_t salen,char *host,DWORD hostlen,char *serv,DWORD servlen,int flags); - WINSOCK_API_LINKAGE INT WSAAPI GetNameInfoW(const SOCKADDR *pSockaddr,socklen_t SockaddrLength,PWCHAR pNodeBuffer,DWORD NodeBufferSize,PWCHAR pServiceBuffer,DWORD ServiceBufferSize,INT Flags); - -#define GetNameInfoA getnameinfo - -#if INCL_WINSOCK_API_TYPEDEFS - typedef int (WSAAPI *LPFN_GETNAMEINFO)(const struct sockaddr *sa,socklen_t salen,char *host,DWORD hostlen,char *serv,DWORD servlen,int flags); - typedef INT (WSAAPI *LPFN_GETNAMEINFOW)(const SOCKADDR *pSockaddr,socklen_t SockaddrLength,PWCHAR pNodeBuffer,DWORD NodeBufferSize,PWCHAR pServiceBuffer,DWORD ServiceBufferSize,INT Flags); - -#define LPFN_GETNAMEINFOA LPFN_GETNAMEINFO - -#ifdef UNICODE -#define LPFN_GETNAMEINFOT LPFN_GETNAMEINFOW -#else -#define LPFN_GETNAMEINFOT LPFN_GETNAMEINFOA -#endif -#endif - -#pragma pop_macro("socklen_t") - -#ifdef UNICODE -#define gai_strerror gai_strerrorW -#else -#define gai_strerror gai_strerrorA -#endif - -#define GAI_STRERROR_BUFFER_SIZE 1024 - -char *gai_strerrorA (int); -WCHAR *gai_strerrorW(int); - -#define NI_MAXHOST 1025 -#define NI_MAXSERV 32 - -#define INET_ADDRSTRLEN 22 -#define INET6_ADDRSTRLEN 65 - -#define NI_NOFQDN 0x01 -#define NI_NUMERICHOST 0x02 -#define NI_NAMEREQD 0x04 -#define NI_NUMERICSERV 0x08 -#define NI_DGRAM 0x10 - -#ifdef __cplusplus -} -#endif - -#endif +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef _WS2TCPIP_H +#define _WS2TCPIP_H + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#include + +struct ip_msfilter { + struct in_addr imsf_multiaddr; + struct in_addr imsf_interface; + u_long imsf_fmode; + u_long imsf_numsrc; + struct in_addr imsf_slist[1]; +}; + +#define IP_MSFILTER_SIZE(numsrc) (sizeof(struct ip_msfilter)-sizeof(struct in_addr) + (numsrc)*sizeof(struct in_addr)) + +#define MCAST_INCLUDE 0 +#define MCAST_EXCLUDE 1 + +#define SIO_GET_INTERFACE_LIST _IOR('t',127,u_long) + +#define SIO_GET_INTERFACE_LIST_EX _IOR('t',126,u_long) +#define SIO_SET_MULTICAST_FILTER _IOW('t',125,u_long) +#define SIO_GET_MULTICAST_FILTER _IOW('t',124 | IOC_IN,u_long) + +#define IP_OPTIONS 1 +#define IP_HDRINCL 2 +#define IP_TOS 3 +#define IP_TTL 4 +#define IP_MULTICAST_IF 9 +#define IP_MULTICAST_TTL 10 +#define IP_MULTICAST_LOOP 11 +#define IP_ADD_MEMBERSHIP 12 +#define IP_DROP_MEMBERSHIP 13 +#define IP_DONTFRAGMENT 14 +#define IP_ADD_SOURCE_MEMBERSHIP 15 +#define IP_DROP_SOURCE_MEMBERSHIP 16 +#define IP_BLOCK_SOURCE 17 +#define IP_UNBLOCK_SOURCE 18 +#define IP_PKTINFO 19 +#define IP_RECEIVE_BROADCAST 22 + +#define IPV6_HDRINCL 2 +#define IPV6_UNICAST_HOPS 4 +#define IPV6_MULTICAST_IF 9 +#define IPV6_MULTICAST_HOPS 10 +#define IPV6_MULTICAST_LOOP 11 +#define IPV6_ADD_MEMBERSHIP 12 +#define IPV6_DROP_MEMBERSHIP 13 +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#define IPV6_PKTINFO 19 +#define IPV6_HOPLIMIT 21 +#define IPV6_PROTECTION_LEVEL 23 + +#define PROTECTION_LEVEL_UNRESTRICTED 10 +#define PROTECTION_LEVEL_DEFAULT 20 +#define PROTECTION_LEVEL_RESTRICTED 30 + +#define UDP_NOCHECKSUM 1 +#define UDP_CHECKSUM_COVERAGE 20 + +#define TCP_EXPEDITED_1122 0x0002 + +#ifndef s6_addr + +struct in6_addr { + __MINGW_EXTENSION union { + u_char Byte[16]; + u_short Word[8]; + } u; +}; + +#define in_addr6 in6_addr + +#define _S6_un u +#define _S6_u8 Byte +#define s6_addr _S6_un._S6_u8 + +#define s6_bytes u.Byte +#define s6_words u.Word +#endif + +typedef struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned int ipv6mr_interface; +} IPV6_MREQ; + +struct sockaddr_in6_old { + short sin6_family; + u_short sin6_port; + u_long sin6_flowinfo; + struct in6_addr sin6_addr; +}; + +struct sockaddr_in6 { + short sin6_family; + u_short sin6_port; + u_long sin6_flowinfo; + struct in6_addr sin6_addr; + u_long sin6_scope_id; +}; + +typedef struct in6_addr IN6_ADDR; +typedef struct in6_addr *PIN6_ADDR; +typedef struct in6_addr *LPIN6_ADDR; + +typedef struct sockaddr_in6 SOCKADDR_IN6; +typedef struct sockaddr_in6 *PSOCKADDR_IN6; +typedef struct sockaddr_in6 *LPSOCKADDR_IN6; + +#define SS_PORT(ssp) (((struct sockaddr_in*)(ssp))->sin_port) + +#define IN6ADDR_ANY_INIT { 0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } + +#ifdef __cplusplus +extern "C" { +#endif + + extern const struct in6_addr in6addr_any; + extern const struct in6_addr in6addr_loopback; + +#ifdef __cplusplus +} +#endif + +#define WS2TCPIP_INLINE __CRT_INLINE + +int IN6_ADDR_EQUAL(const struct in6_addr *,const struct in6_addr *); +int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *); +int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *); +int IN6_IS_ADDR_MULTICAST(const struct in6_addr *); +int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *); +int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *); +int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *); +int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *); +int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *); +int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *); +int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *); +int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *); +int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *); +int IN6ADDR_ISANY(const struct sockaddr_in6 *); +int IN6ADDR_ISLOOPBACK(const struct sockaddr_in6 *); +void IN6_SET_ADDR_UNSPECIFIED(struct in6_addr *); +void IN6_SET_ADDR_LOOPBACK(struct in6_addr *); +void IN6ADDR_SETANY(struct sockaddr_in6 *); +void IN6ADDR_SETLOOPBACK(struct sockaddr_in6 *); + +#ifndef __CRT__NO_INLINE +WS2TCPIP_INLINE int IN6_ADDR_EQUAL(const struct in6_addr *a,const struct in6_addr *b) { return (memcmp(a,b,sizeof(struct in6_addr))==0); } +WS2TCPIP_INLINE int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && (a->s6_words[6]==0) && (a->s6_words[7]==0)); } +WS2TCPIP_INLINE int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && (a->s6_words[6]==0) && (a->s6_words[7]==0x0100)); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MULTICAST(const struct in6_addr *a) { return (a->s6_bytes[0]==0xff); } +WS2TCPIP_INLINE int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *a) { return ((a->s6_bytes[0]==0xfe) && ((a->s6_bytes[1] & 0xc0)==0x80)); } +WS2TCPIP_INLINE int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *a) { return ((a->s6_bytes[0]==0xfe) && ((a->s6_bytes[1] & 0xc0)==0xc0)); } +WS2TCPIP_INLINE int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0xffff)); } +WS2TCPIP_INLINE int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && !((a->s6_words[6]==0) && (a->s6_addr[14]==0) && ((a->s6_addr[15]==0) || (a->s6_addr[15]==1)))); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==1); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==2); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==5); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==8); } +WS2TCPIP_INLINE int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==0xe); } +WS2TCPIP_INLINE int IN6ADDR_ISANY(const struct sockaddr_in6 *a) { return ((a->sin6_family==AF_INET6) && IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)); } +WS2TCPIP_INLINE int IN6ADDR_ISLOOPBACK(const struct sockaddr_in6 *a) { return ((a->sin6_family==AF_INET6) && IN6_IS_ADDR_LOOPBACK(&a->sin6_addr)); } +WS2TCPIP_INLINE void IN6_SET_ADDR_UNSPECIFIED(struct in6_addr *a) { memset(a->s6_bytes,0,sizeof(struct in6_addr)); } +WS2TCPIP_INLINE void IN6_SET_ADDR_LOOPBACK(struct in6_addr *a) { + memset(a->s6_bytes,0,sizeof(struct in6_addr)); + a->s6_bytes[15] = 1; +} +WS2TCPIP_INLINE void IN6ADDR_SETANY(struct sockaddr_in6 *a) { + a->sin6_family = AF_INET6; + a->sin6_port = 0; + a->sin6_flowinfo = 0; + IN6_SET_ADDR_UNSPECIFIED(&a->sin6_addr); + a->sin6_scope_id = 0; +} +WS2TCPIP_INLINE void IN6ADDR_SETLOOPBACK(struct sockaddr_in6 *a) { + a->sin6_family = AF_INET6; + a->sin6_port = 0; + a->sin6_flowinfo = 0; + IN6_SET_ADDR_LOOPBACK(&a->sin6_addr); + a->sin6_scope_id = 0; +} +#endif /* !__CRT__NO_INLINE */ + +typedef union sockaddr_gen { + struct sockaddr Address; + struct sockaddr_in AddressIn; + struct sockaddr_in6_old AddressIn6; +} sockaddr_gen; + +typedef struct _INTERFACE_INFO { + u_long iiFlags; + sockaddr_gen iiAddress; + sockaddr_gen iiBroadcastAddress; + sockaddr_gen iiNetmask; +} INTERFACE_INFO,*LPINTERFACE_INFO; + +typedef struct _INTERFACE_INFO_EX { + u_long iiFlags; + SOCKET_ADDRESS iiAddress; + SOCKET_ADDRESS iiBroadcastAddress; + SOCKET_ADDRESS iiNetmask; +} INTERFACE_INFO_EX,*LPINTERFACE_INFO_EX; + +#define IFF_UP 0x00000001 +#define IFF_BROADCAST 0x00000002 +#define IFF_LOOPBACK 0x00000004 +#define IFF_POINTTOPOINT 0x00000008 +#define IFF_MULTICAST 0x00000010 + +typedef struct in_pktinfo { + IN_ADDR ipi_addr; + UINT ipi_ifindex; +} IN_PKTINFO; + +C_ASSERT(sizeof(IN_PKTINFO)==8); + +typedef struct in6_pktinfo { + IN6_ADDR ipi6_addr; + UINT ipi6_ifindex; +} IN6_PKTINFO; + +C_ASSERT(sizeof(IN6_PKTINFO)==20); + +#define EAI_AGAIN WSATRY_AGAIN +#define EAI_BADFLAGS WSAEINVAL +#define EAI_FAIL WSANO_RECOVERY +#define EAI_FAMILY WSAEAFNOSUPPORT +#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY + +#define EAI_NONAME WSAHOST_NOT_FOUND +#define EAI_SERVICE WSATYPE_NOT_FOUND +#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT + +#define EAI_NODATA EAI_NONAME + +typedef struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +} ADDRINFOA,*PADDRINFOA; + +typedef struct addrinfoW { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + PWSTR ai_canonname; + struct sockaddr *ai_addr; + struct addrinfoW *ai_next; +} ADDRINFOW,*PADDRINFOW; + +#ifdef UNICODE +typedef ADDRINFOW ADDRINFOT,*PADDRINFOT; +#else +typedef ADDRINFOA ADDRINFOT,*PADDRINFOT; +#endif + +typedef ADDRINFOA ADDRINFO,*LPADDRINFO; + +#define AI_PASSIVE 0x1 +#define AI_CANONNAME 0x2 +#define AI_NUMERICHOST 0x4 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef UNICODE +#define GetAddrInfo GetAddrInfoW +#else +#define GetAddrInfo GetAddrInfoA +#endif + + WINSOCK_API_LINKAGE int WSAAPI getaddrinfo(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res); + WINSOCK_API_LINKAGE int WSAAPI GetAddrInfoW(PCWSTR pNodeName,PCWSTR pServiceName,const ADDRINFOW *pHints,PADDRINFOW *ppResult); + +#define GetAddrInfoA getaddrinfo + +#if INCL_WINSOCK_API_TYPEDEFS + typedef int (WSAAPI *LPFN_GETADDRINFO)(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res); + typedef int (WSAAPI *LPFN_GETADDRINFOW)(PCWSTR pNodeName,PCWSTR pServiceName,const ADDRINFOW *pHints,PADDRINFOW *ppResult); + +#define LPFN_GETADDRINFOA LPFN_GETADDRINFO + +#ifdef UNICODE +#define LPFN_GETADDRINFOT LPFN_GETADDRINFOW +#else +#define LPFN_GETADDRINFOT LPFN_GETADDRINFOA +#endif +#endif + +#ifdef UNICODE +#define FreeAddrInfo FreeAddrInfoW +#else +#define FreeAddrInfo FreeAddrInfoA +#endif + + WINSOCK_API_LINKAGE void WSAAPI freeaddrinfo(LPADDRINFO pAddrInfo); + WINSOCK_API_LINKAGE void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo); + +#define FreeAddrInfoA freeaddrinfo + +#if INCL_WINSOCK_API_TYPEDEFS + typedef void (WSAAPI *LPFN_FREEADDRINFO)(struct addrinfo *ai); + typedef void (WSAAPI *LPFN_FREEADDRINFOW)(PADDRINFOW pAddrInfo); + +#define LPFN_FREEADDRINFOA LPFN_FREEADDRINFO + +#ifdef UNICODE +#define LPFN_FREEADDRINFOT LPFN_FREEADDRINFOW +#else +#define LPFN_FREEADDRINFOT LPFN_FREEADDRINFOA +#endif +#endif + +#pragma push_macro("socklen_t") +#undef socklen_t + + typedef int socklen_t; + +#ifdef UNICODE +#define GetNameInfo GetNameInfoW +#else +#define GetNameInfo GetNameInfoA +#endif + + WINSOCK_API_LINKAGE int WSAAPI getnameinfo(const struct sockaddr *sa,socklen_t salen,char *host,DWORD hostlen,char *serv,DWORD servlen,int flags); + WINSOCK_API_LINKAGE INT WSAAPI GetNameInfoW(const SOCKADDR *pSockaddr,socklen_t SockaddrLength,PWCHAR pNodeBuffer,DWORD NodeBufferSize,PWCHAR pServiceBuffer,DWORD ServiceBufferSize,INT Flags); + +#define GetNameInfoA getnameinfo + +#if INCL_WINSOCK_API_TYPEDEFS + typedef int (WSAAPI *LPFN_GETNAMEINFO)(const struct sockaddr *sa,socklen_t salen,char *host,DWORD hostlen,char *serv,DWORD servlen,int flags); + typedef INT (WSAAPI *LPFN_GETNAMEINFOW)(const SOCKADDR *pSockaddr,socklen_t SockaddrLength,PWCHAR pNodeBuffer,DWORD NodeBufferSize,PWCHAR pServiceBuffer,DWORD ServiceBufferSize,INT Flags); + +#define LPFN_GETNAMEINFOA LPFN_GETNAMEINFO + +#ifdef UNICODE +#define LPFN_GETNAMEINFOT LPFN_GETNAMEINFOW +#else +#define LPFN_GETNAMEINFOT LPFN_GETNAMEINFOA +#endif +#endif + +#pragma pop_macro("socklen_t") + +#ifdef UNICODE +#define gai_strerror gai_strerrorW +#else +#define gai_strerror gai_strerrorA +#endif + +#define GAI_STRERROR_BUFFER_SIZE 1024 + +char *gai_strerrorA (int); +WCHAR *gai_strerrorW(int); + +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 + +#define INET_ADDRSTRLEN 22 +#define INET6_ADDRSTRLEN 65 + +#define NI_NOFQDN 0x01 +#define NI_NUMERICHOST 0x02 +#define NI_NAMEREQD 0x04 +#define NI_NUMERICSERV 0x08 +#define NI_DGRAM 0x10 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tcc/lib/kernel32.def b/tcc/lib/kernel32.def index 41383556..f03e17ba 100644 --- a/tcc/lib/kernel32.def +++ b/tcc/lib/kernel32.def @@ -1,770 +1,770 @@ -LIBRARY kernel32.dll - -EXPORTS -AddAtomA -AddAtomW -AllocConsole -AllocLSCallback -AllocSLCallback -AreFileApisANSI -BackupRead -BackupSeek -BackupWrite -Beep -BeginUpdateResourceA -BeginUpdateResourceW -BuildCommDCBA -BuildCommDCBAndTimeoutsA -BuildCommDCBAndTimeoutsW -BuildCommDCBW -CallNamedPipeA -CallNamedPipeW -Callback12 -Callback16 -Callback20 -Callback24 -Callback28 -Callback32 -Callback36 -Callback4 -Callback40 -Callback44 -Callback48 -Callback52 -Callback56 -Callback60 -Callback64 -Callback8 -CancelDeviceWakeupRequest -CancelIo -CancelWaitableTimer -ClearCommBreak -ClearCommError -CloseHandle -CloseProfileUserMapping -CloseSystemHandle -CommConfigDialogA -CommConfigDialogW -CompareFileTime -CompareStringA -CompareStringW -ConnectNamedPipe -ContinueDebugEvent -ConvertDefaultLocale -ConvertThreadToFiber -ConvertToGlobalHandle -CopyFileA -CopyFileExA -CopyFileExW -CopyFileW -CreateConsoleScreenBuffer -CreateDirectoryA -CreateDirectoryExA -CreateDirectoryExW -CreateDirectoryW -CreateEventA -CreateEventW -CreateFiber -CreateFileA -CreateFileMappingA -CreateFileMappingW -CreateFileW -CreateIoCompletionPort -CreateKernelThread -CreateMailslotA -CreateMailslotW -CreateMutexA -CreateMutexW -CreateNamedPipeA -CreateNamedPipeW -CreatePipe -CreateProcessA -CreateProcessW -CreateRemoteThread -CreateSemaphoreA -CreateSemaphoreW -CreateSocketHandle -CreateTapePartition -CreateThread -CreateToolhelp32Snapshot -CreateWaitableTimerA -CreateWaitableTimerW -DebugActiveProcess -DebugBreak -DefineDosDeviceA -DefineDosDeviceW -DeleteAtom -DeleteCriticalSection -DeleteFiber -DeleteFileA -DeleteFileW -DeviceIoControl -DisableThreadLibraryCalls -DisconnectNamedPipe -DosDateTimeToFileTime -DuplicateHandle -EndUpdateResourceA -EndUpdateResourceW -EnterCriticalSection -EnumCalendarInfoA -EnumCalendarInfoExA -EnumCalendarInfoExW -EnumCalendarInfoW -EnumDateFormatsA -EnumDateFormatsExA -EnumDateFormatsExW -EnumDateFormatsW -EnumLanguageGroupLocalesA -EnumLanguageGroupLocalesW -EnumResourceLanguagesA -EnumResourceLanguagesW -EnumResourceNamesA -EnumResourceNamesW -EnumResourceTypesA -EnumResourceTypesW -EnumSystemCodePagesA -EnumSystemCodePagesW -EnumSystemGeoID -EnumSystemLanguageGroupsA -EnumSystemLanguageGroupsW -EnumSystemLocalesA -EnumSystemLocalesW -EnumTimeFormatsA -EnumTimeFormatsW -EnumUILanguagesA -EnumUILanguagesW -EraseTape -EscapeCommFunction -ExitProcess -ExitThread -ExpandEnvironmentStringsA -ExpandEnvironmentStringsW -FT_Exit0 -FT_Exit12 -FT_Exit16 -FT_Exit20 -FT_Exit24 -FT_Exit28 -FT_Exit32 -FT_Exit36 -FT_Exit4 -FT_Exit40 -FT_Exit44 -FT_Exit48 -FT_Exit52 -FT_Exit56 -FT_Exit8 -FT_Prolog -FT_Thunk -FatalAppExitA -FatalAppExitW -FatalExit -FileTimeToDosDateTime -FileTimeToLocalFileTime -FileTimeToSystemTime -FillConsoleOutputAttribute -FillConsoleOutputCharacterA -FillConsoleOutputCharacterW -FindAtomA -FindAtomW -FindClose -FindCloseChangeNotification -FindFirstChangeNotificationA -FindFirstChangeNotificationW -FindFirstFileA -FindFirstFileExA -FindFirstFileExW -FindFirstFileW -FindNextChangeNotification -FindNextFileA -FindNextFileW -FindResourceA -FindResourceExA -FindResourceExW -FindResourceW -FlushConsoleInputBuffer -FlushFileBuffers -FlushInstructionCache -FlushViewOfFile -FoldStringA -FoldStringW -FormatMessageA -FormatMessageW -FreeConsole -FreeEnvironmentStringsA -FreeEnvironmentStringsW -FreeLSCallback -FreeLibrary -FreeLibraryAndExitThread -FreeResource -FreeSLCallback -GenerateConsoleCtrlEvent -GetACP -GetAtomNameA -GetAtomNameW -GetBinaryType -GetBinaryTypeA -GetBinaryTypeW -GetCPInfo -GetCPInfoExA -GetCPInfoExW -GetCalendarInfoA -GetCalendarInfoW -GetCommConfig -GetCommMask -GetCommModemStatus -GetCommProperties -GetCommState -GetCommTimeouts -GetCommandLineA -GetCommandLineW -GetCompressedFileSizeA -GetCompressedFileSizeW -GetComputerNameA -GetComputerNameW -GetConsoleCP -GetConsoleCursorInfo -GetConsoleMode -GetConsoleOutputCP -GetConsoleScreenBufferInfo -GetConsoleTitleA -GetConsoleTitleW -GetCurrencyFormatA -GetCurrencyFormatW -GetCurrentDirectoryA -GetCurrentDirectoryW -GetCurrentProcess -GetCurrentProcessId -GetCurrentThread -GetCurrentThreadId -GetDateFormatA -GetDateFormatW -GetDaylightFlag -GetDefaultCommConfigA -GetDefaultCommConfigW -GetDevicePowerState -GetDiskFreeSpaceA -GetDiskFreeSpaceExA -GetDiskFreeSpaceExW -GetDiskFreeSpaceW -GetDriveTypeA -GetDriveTypeW -GetEnvironmentStrings -GetEnvironmentStringsA -GetEnvironmentStringsW -GetEnvironmentVariableA -GetEnvironmentVariableW -GetErrorMode -GetExitCodeProcess -GetExitCodeThread -GetFileAttributesA -GetFileAttributesExA -GetFileAttributesExW -GetFileAttributesW -GetFileInformationByHandle -GetFileSize -GetFileTime -GetFileType -GetFullPathNameA -GetFullPathNameW -GetGeoInfoA -GetGeoInfoW -GetHandleContext -GetHandleInformation -GetLSCallbackTarget -GetLSCallbackTemplate -GetLargestConsoleWindowSize -GetLastError -GetLocalTime -GetLocaleInfoA -GetLocaleInfoW -GetLogicalDriveStringsA -GetLogicalDriveStringsW -GetLogicalDrives -GetLongPathNameA -GetLongPathNameW -GetMailslotInfo -GetModuleFileNameA -GetModuleFileNameW -GetModuleHandleA -GetModuleHandleW -GetModuleHandleExA -GetModuleHandleExW -GetNamedPipeHandleStateA -GetNamedPipeHandleStateW -GetNamedPipeInfo -GetNumberFormatA -GetNumberFormatW -GetNumberOfConsoleInputEvents -GetNumberOfConsoleMouseButtons -GetOEMCP -GetOverlappedResult -GetPriorityClass -GetPrivateProfileIntA -GetPrivateProfileIntW -GetPrivateProfileSectionA -GetPrivateProfileSectionNamesA -GetPrivateProfileSectionNamesW -GetPrivateProfileSectionW -GetPrivateProfileStringA -GetPrivateProfileStringW -GetPrivateProfileStructA -GetPrivateProfileStructW -GetProcAddress -GetProcessAffinityMask -GetProcessFlags -GetProcessHeap -GetProcessHeaps -GetProcessPriorityBoost -GetProcessShutdownParameters -GetProcessTimes -GetProcessVersion -GetProcessWorkingSetSize -GetProductName -GetProfileIntA -GetProfileIntW -GetProfileSectionA -GetProfileSectionW -GetProfileStringA -GetProfileStringW -GetQueuedCompletionStatus -GetSLCallbackTarget -GetSLCallbackTemplate -GetShortPathNameA -GetShortPathNameW -GetStartupInfoA -GetStartupInfoW -GetStdHandle -GetStringTypeA -GetStringTypeExA -GetStringTypeExW -GetStringTypeW -GetSystemDefaultLCID -GetSystemDefaultLangID -GetSystemDefaultUILanguage -GetSystemDirectoryA -GetSystemDirectoryW -GetSystemInfo -GetSystemPowerStatus -GetSystemTime -GetSystemTimeAdjustment -GetSystemTimeAsFileTime -GetTapeParameters -GetTapePosition -GetTapeStatus -GetTempFileNameA -GetTempFileNameW -GetTempPathA -GetTempPathW -GetThreadContext -GetThreadLocale -GetThreadPriority -GetThreadPriorityBoost -GetThreadSelectorEntry -GetThreadTimes -GetTickCount -GetTimeFormatA -GetTimeFormatW -GetTimeZoneInformation -GetUserDefaultLCID -GetUserDefaultLangID -GetUserDefaultUILanguage -GetUserGeoID -GetVersion -GetVersionExA -GetVersionExW -GetVolumeInformationA -GetVolumeInformationW -GetWindowsDirectoryA -GetWindowsDirectoryW -GetWriteWatch -GlobalAddAtomA -GlobalAddAtomW -GlobalAlloc -GlobalCompact -GlobalDeleteAtom -GlobalFindAtomA -GlobalFindAtomW -GlobalFix -GlobalFlags -GlobalFree -GlobalGetAtomNameA -GlobalGetAtomNameW -GlobalHandle -GlobalLock -GlobalMemoryStatus -GlobalReAlloc -GlobalSize -GlobalUnWire -GlobalUnfix -GlobalUnlock -GlobalWire -Heap32First -Heap32ListFirst -Heap32ListNext -Heap32Next -HeapAlloc -HeapCompact -HeapCreate -HeapDestroy -HeapFree -HeapLock -HeapReAlloc -HeapSetFlags -HeapSize -HeapUnlock -HeapValidate -HeapWalk -InitAtomTable -InitializeCriticalSection -InitializeCriticalSectionAndSpinCount -InterlockedCompareExchange -InterlockedDecrement -InterlockedExchange -InterlockedExchangeAdd -InterlockedIncrement -InvalidateNLSCache -IsBadCodePtr -IsBadHugeReadPtr -IsBadHugeWritePtr -IsBadReadPtr -IsBadStringPtrA -IsBadStringPtrW -IsBadWritePtr -IsDBCSLeadByte -IsDBCSLeadByteEx -IsDebuggerPresent -IsLSCallback -IsProcessorFeaturePresent -IsSLCallback -IsSystemResumeAutomatic -IsValidCodePage -IsValidLanguageGroup -IsValidLocale -K32Thk1632Epilog -K32Thk1632Prolog -K32_NtCreateFile -K32_RtlNtStatusToDosError -LCMapStringA -LCMapStringW -LeaveCriticalSection -LoadLibraryA -LoadLibraryExA -LoadLibraryExW -LoadLibraryW -LoadModule -LoadResource -LocalAlloc -LocalCompact -LocalFileTimeToFileTime -LocalFlags -LocalFree -LocalHandle -LocalLock -LocalReAlloc -LocalShrink -LocalSize -LocalUnlock -LockFile -LockFileEx -LockResource -MakeCriticalSectionGlobal -MapHInstLS -MapHInstLS_PN -MapHInstSL -MapHInstSL_PN -MapHModuleLS -MapHModuleSL -MapLS -MapSL -MapSLFix -MapViewOfFile -MapViewOfFileEx -Module32First -Module32Next -MoveFileA -MoveFileExA -MoveFileExW -MoveFileW -MulDiv -MultiByteToWideChar -NotifyNLSUserCache -OpenEventA -OpenEventW -OpenFile -OpenFileMappingA -OpenFileMappingW -OpenMutexA -OpenMutexW -OpenProcess -OpenProfileUserMapping -OpenSemaphoreA -OpenSemaphoreW -OpenThread -OpenVxDHandle -OpenWaitableTimerA -OpenWaitableTimerW -OutputDebugStringA -OutputDebugStringW -PeekConsoleInputA -PeekConsoleInputW -PeekNamedPipe -PostQueuedCompletionStatus -PrepareTape -Process32First -Process32Next -PulseEvent -PurgeComm -QT_Thunk -QueryDosDeviceA -QueryDosDeviceW -QueryNumberOfEventLogRecords -QueryOldestEventLogRecord -QueryPerformanceCounter -QueryPerformanceFrequency -QueueUserAPC -RaiseException -ReadConsoleA -ReadConsoleInputA -ReadConsoleInputW -ReadConsoleOutputA -ReadConsoleOutputAttribute -ReadConsoleOutputCharacterA -ReadConsoleOutputCharacterW -ReadConsoleOutputW -ReadConsoleW -ReadDirectoryChangesW -ReadFile -ReadFileEx -ReadFileScatter -ReadProcessMemory -RegisterServiceProcess -RegisterSysMsgHandler -ReinitializeCriticalSection -ReleaseMutex -ReleaseSemaphore -RemoveDirectoryA -RemoveDirectoryW -RequestDeviceWakeup -RequestWakeupLatency -ResetEvent -ResetNLSUserInfoCache -ResetWriteWatch -ResumeThread -RtlAddFunctionTable -RtlDeleteFunctionTable -RtlFillMemory -RtlInstallFunctionTableCallback -RtlMoveMemory -RtlUnwind -RtlUnwindEx -RtlZeroMemory -SMapLS -SMapLS_IP_EBP_12 -SMapLS_IP_EBP_16 -SMapLS_IP_EBP_20 -SMapLS_IP_EBP_24 -SMapLS_IP_EBP_28 -SMapLS_IP_EBP_32 -SMapLS_IP_EBP_36 -SMapLS_IP_EBP_40 -SMapLS_IP_EBP_8 -SUnMapLS -SUnMapLS_IP_EBP_12 -SUnMapLS_IP_EBP_16 -SUnMapLS_IP_EBP_20 -SUnMapLS_IP_EBP_24 -SUnMapLS_IP_EBP_28 -SUnMapLS_IP_EBP_32 -SUnMapLS_IP_EBP_36 -SUnMapLS_IP_EBP_40 -SUnMapLS_IP_EBP_8 -ScrollConsoleScreenBufferA -ScrollConsoleScreenBufferW -SearchPathA -SearchPathW -SetCalendarInfoA -SetCalendarInfoW -SetCommBreak -SetCommConfig -SetCommMask -SetCommState -SetCommTimeouts -SetComputerNameA -SetComputerNameW -SetConsoleActiveScreenBuffer -SetConsoleCP -SetConsoleCtrlHandler -SetConsoleCursorInfo -SetConsoleCursorPosition -SetConsoleMode -SetConsoleOutputCP -SetConsoleScreenBufferSize -SetConsoleTextAttribute -SetConsoleTitleA -SetConsoleTitleW -SetConsoleWindowInfo -SetCriticalSectionSpinCount -SetCurrentDirectoryA -SetCurrentDirectoryW -SetDaylightFlag -SetDefaultCommConfigA -SetDefaultCommConfigW -SetEndOfFile -SetEnvironmentVariableA -SetEnvironmentVariableW -SetErrorMode -SetEvent -SetFileApisToANSI -SetFileApisToOEM -SetFileAttributesA -SetFileAttributesW -SetFilePointer -SetFilePointerEx -SetFileTime -SetHandleContext -SetHandleCount -SetHandleInformation -SetLastError -SetLocalTime -SetLocaleInfoA -SetLocaleInfoW -SetMailslotInfo -SetMessageWaitingIndicator -SetNamedPipeHandleState -SetPriorityClass -SetProcessAffinityMask -SetProcessPriorityBoost -SetProcessShutdownParameters -SetProcessWorkingSetSize -SetStdHandle -SetSystemPowerState -SetSystemTime -SetSystemTimeAdjustment -SetTapeParameters -SetTapePosition -SetThreadAffinityMask -SetThreadContext -SetThreadExecutionState -SetThreadIdealProcessor -SetThreadLocale -SetThreadPriority -SetThreadPriorityBoost -SetTimeZoneInformation -SetUnhandledExceptionFilter -SetUserGeoID -SetVolumeLabelA -SetVolumeLabelW -SetWaitableTimer -SetupComm -SignalObjectAndWait -SignalSysMsgHandlers -SizeofResource -Sleep -SleepEx -SuspendThread -SwitchToFiber -SwitchToThread -SystemTimeToFileTime -SystemTimeToTzSpecificLocalTime -TerminateProcess -TerminateThread -Thread32First -Thread32Next -ThunkConnect32 -TlsAlloc -TlsAllocInternal -TlsFree -TlsFreeInternal -TlsGetValue -TlsSetValue -Toolhelp32ReadProcessMemory -TransactNamedPipe -TransmitCommChar -TryEnterCriticalSection -UTRegister -UTUnRegister -UnMapLS -UnMapSLFixArray -UnhandledExceptionFilter -UninitializeCriticalSection -UnlockFile -UnlockFileEx -UnmapViewOfFile -UpdateResourceA -UpdateResourceW -VerLanguageNameA -VerLanguageNameW -VirtualAlloc -VirtualAllocEx -VirtualFree -VirtualFreeEx -VirtualLock -VirtualProtect -VirtualProtectEx -VirtualQuery -VirtualQueryEx -VirtualUnlock -WaitCommEvent -WaitForDebugEvent -WaitForMultipleObjects -WaitForMultipleObjectsEx -WaitForSingleObject -WaitForSingleObjectEx -WaitNamedPipeA -WaitNamedPipeW -WideCharToMultiByte -WinExec -WriteConsoleA -WriteConsoleInputA -WriteConsoleInputW -WriteConsoleOutputA -WriteConsoleOutputAttribute -WriteConsoleOutputCharacterA -WriteConsoleOutputCharacterW -WriteConsoleOutputW -WriteConsoleW -WriteFile -WriteFileEx -WriteFileGather -WritePrivateProfileSectionA -WritePrivateProfileSectionW -WritePrivateProfileStringA -WritePrivateProfileStringW -WritePrivateProfileStructA -WritePrivateProfileStructW -WriteProcessMemory -WriteProfileSectionA -WriteProfileSectionW -WriteProfileStringA -WriteProfileStringW -WriteTapemark -_DebugOut -_DebugPrintf -_hread -_hwrite -_lclose -_lcreat -_llseek -_lopen -_lread -_lwrite -dprintf -lstrcat -lstrcatA -lstrcatW -lstrcmp -lstrcmpA -lstrcmpW -lstrcmpi -lstrcmpiA -lstrcmpiW -lstrcpy -lstrcpyA -lstrcpyW -lstrcpyn -lstrcpynA -lstrcpynW -lstrlen -lstrlenA -lstrlenW +LIBRARY kernel32.dll + +EXPORTS +AddAtomA +AddAtomW +AllocConsole +AllocLSCallback +AllocSLCallback +AreFileApisANSI +BackupRead +BackupSeek +BackupWrite +Beep +BeginUpdateResourceA +BeginUpdateResourceW +BuildCommDCBA +BuildCommDCBAndTimeoutsA +BuildCommDCBAndTimeoutsW +BuildCommDCBW +CallNamedPipeA +CallNamedPipeW +Callback12 +Callback16 +Callback20 +Callback24 +Callback28 +Callback32 +Callback36 +Callback4 +Callback40 +Callback44 +Callback48 +Callback52 +Callback56 +Callback60 +Callback64 +Callback8 +CancelDeviceWakeupRequest +CancelIo +CancelWaitableTimer +ClearCommBreak +ClearCommError +CloseHandle +CloseProfileUserMapping +CloseSystemHandle +CommConfigDialogA +CommConfigDialogW +CompareFileTime +CompareStringA +CompareStringW +ConnectNamedPipe +ContinueDebugEvent +ConvertDefaultLocale +ConvertThreadToFiber +ConvertToGlobalHandle +CopyFileA +CopyFileExA +CopyFileExW +CopyFileW +CreateConsoleScreenBuffer +CreateDirectoryA +CreateDirectoryExA +CreateDirectoryExW +CreateDirectoryW +CreateEventA +CreateEventW +CreateFiber +CreateFileA +CreateFileMappingA +CreateFileMappingW +CreateFileW +CreateIoCompletionPort +CreateKernelThread +CreateMailslotA +CreateMailslotW +CreateMutexA +CreateMutexW +CreateNamedPipeA +CreateNamedPipeW +CreatePipe +CreateProcessA +CreateProcessW +CreateRemoteThread +CreateSemaphoreA +CreateSemaphoreW +CreateSocketHandle +CreateTapePartition +CreateThread +CreateToolhelp32Snapshot +CreateWaitableTimerA +CreateWaitableTimerW +DebugActiveProcess +DebugBreak +DefineDosDeviceA +DefineDosDeviceW +DeleteAtom +DeleteCriticalSection +DeleteFiber +DeleteFileA +DeleteFileW +DeviceIoControl +DisableThreadLibraryCalls +DisconnectNamedPipe +DosDateTimeToFileTime +DuplicateHandle +EndUpdateResourceA +EndUpdateResourceW +EnterCriticalSection +EnumCalendarInfoA +EnumCalendarInfoExA +EnumCalendarInfoExW +EnumCalendarInfoW +EnumDateFormatsA +EnumDateFormatsExA +EnumDateFormatsExW +EnumDateFormatsW +EnumLanguageGroupLocalesA +EnumLanguageGroupLocalesW +EnumResourceLanguagesA +EnumResourceLanguagesW +EnumResourceNamesA +EnumResourceNamesW +EnumResourceTypesA +EnumResourceTypesW +EnumSystemCodePagesA +EnumSystemCodePagesW +EnumSystemGeoID +EnumSystemLanguageGroupsA +EnumSystemLanguageGroupsW +EnumSystemLocalesA +EnumSystemLocalesW +EnumTimeFormatsA +EnumTimeFormatsW +EnumUILanguagesA +EnumUILanguagesW +EraseTape +EscapeCommFunction +ExitProcess +ExitThread +ExpandEnvironmentStringsA +ExpandEnvironmentStringsW +FT_Exit0 +FT_Exit12 +FT_Exit16 +FT_Exit20 +FT_Exit24 +FT_Exit28 +FT_Exit32 +FT_Exit36 +FT_Exit4 +FT_Exit40 +FT_Exit44 +FT_Exit48 +FT_Exit52 +FT_Exit56 +FT_Exit8 +FT_Prolog +FT_Thunk +FatalAppExitA +FatalAppExitW +FatalExit +FileTimeToDosDateTime +FileTimeToLocalFileTime +FileTimeToSystemTime +FillConsoleOutputAttribute +FillConsoleOutputCharacterA +FillConsoleOutputCharacterW +FindAtomA +FindAtomW +FindClose +FindCloseChangeNotification +FindFirstChangeNotificationA +FindFirstChangeNotificationW +FindFirstFileA +FindFirstFileExA +FindFirstFileExW +FindFirstFileW +FindNextChangeNotification +FindNextFileA +FindNextFileW +FindResourceA +FindResourceExA +FindResourceExW +FindResourceW +FlushConsoleInputBuffer +FlushFileBuffers +FlushInstructionCache +FlushViewOfFile +FoldStringA +FoldStringW +FormatMessageA +FormatMessageW +FreeConsole +FreeEnvironmentStringsA +FreeEnvironmentStringsW +FreeLSCallback +FreeLibrary +FreeLibraryAndExitThread +FreeResource +FreeSLCallback +GenerateConsoleCtrlEvent +GetACP +GetAtomNameA +GetAtomNameW +GetBinaryType +GetBinaryTypeA +GetBinaryTypeW +GetCPInfo +GetCPInfoExA +GetCPInfoExW +GetCalendarInfoA +GetCalendarInfoW +GetCommConfig +GetCommMask +GetCommModemStatus +GetCommProperties +GetCommState +GetCommTimeouts +GetCommandLineA +GetCommandLineW +GetCompressedFileSizeA +GetCompressedFileSizeW +GetComputerNameA +GetComputerNameW +GetConsoleCP +GetConsoleCursorInfo +GetConsoleMode +GetConsoleOutputCP +GetConsoleScreenBufferInfo +GetConsoleTitleA +GetConsoleTitleW +GetCurrencyFormatA +GetCurrencyFormatW +GetCurrentDirectoryA +GetCurrentDirectoryW +GetCurrentProcess +GetCurrentProcessId +GetCurrentThread +GetCurrentThreadId +GetDateFormatA +GetDateFormatW +GetDaylightFlag +GetDefaultCommConfigA +GetDefaultCommConfigW +GetDevicePowerState +GetDiskFreeSpaceA +GetDiskFreeSpaceExA +GetDiskFreeSpaceExW +GetDiskFreeSpaceW +GetDriveTypeA +GetDriveTypeW +GetEnvironmentStrings +GetEnvironmentStringsA +GetEnvironmentStringsW +GetEnvironmentVariableA +GetEnvironmentVariableW +GetErrorMode +GetExitCodeProcess +GetExitCodeThread +GetFileAttributesA +GetFileAttributesExA +GetFileAttributesExW +GetFileAttributesW +GetFileInformationByHandle +GetFileSize +GetFileTime +GetFileType +GetFullPathNameA +GetFullPathNameW +GetGeoInfoA +GetGeoInfoW +GetHandleContext +GetHandleInformation +GetLSCallbackTarget +GetLSCallbackTemplate +GetLargestConsoleWindowSize +GetLastError +GetLocalTime +GetLocaleInfoA +GetLocaleInfoW +GetLogicalDriveStringsA +GetLogicalDriveStringsW +GetLogicalDrives +GetLongPathNameA +GetLongPathNameW +GetMailslotInfo +GetModuleFileNameA +GetModuleFileNameW +GetModuleHandleA +GetModuleHandleW +GetModuleHandleExA +GetModuleHandleExW +GetNamedPipeHandleStateA +GetNamedPipeHandleStateW +GetNamedPipeInfo +GetNumberFormatA +GetNumberFormatW +GetNumberOfConsoleInputEvents +GetNumberOfConsoleMouseButtons +GetOEMCP +GetOverlappedResult +GetPriorityClass +GetPrivateProfileIntA +GetPrivateProfileIntW +GetPrivateProfileSectionA +GetPrivateProfileSectionNamesA +GetPrivateProfileSectionNamesW +GetPrivateProfileSectionW +GetPrivateProfileStringA +GetPrivateProfileStringW +GetPrivateProfileStructA +GetPrivateProfileStructW +GetProcAddress +GetProcessAffinityMask +GetProcessFlags +GetProcessHeap +GetProcessHeaps +GetProcessPriorityBoost +GetProcessShutdownParameters +GetProcessTimes +GetProcessVersion +GetProcessWorkingSetSize +GetProductName +GetProfileIntA +GetProfileIntW +GetProfileSectionA +GetProfileSectionW +GetProfileStringA +GetProfileStringW +GetQueuedCompletionStatus +GetSLCallbackTarget +GetSLCallbackTemplate +GetShortPathNameA +GetShortPathNameW +GetStartupInfoA +GetStartupInfoW +GetStdHandle +GetStringTypeA +GetStringTypeExA +GetStringTypeExW +GetStringTypeW +GetSystemDefaultLCID +GetSystemDefaultLangID +GetSystemDefaultUILanguage +GetSystemDirectoryA +GetSystemDirectoryW +GetSystemInfo +GetSystemPowerStatus +GetSystemTime +GetSystemTimeAdjustment +GetSystemTimeAsFileTime +GetTapeParameters +GetTapePosition +GetTapeStatus +GetTempFileNameA +GetTempFileNameW +GetTempPathA +GetTempPathW +GetThreadContext +GetThreadLocale +GetThreadPriority +GetThreadPriorityBoost +GetThreadSelectorEntry +GetThreadTimes +GetTickCount +GetTimeFormatA +GetTimeFormatW +GetTimeZoneInformation +GetUserDefaultLCID +GetUserDefaultLangID +GetUserDefaultUILanguage +GetUserGeoID +GetVersion +GetVersionExA +GetVersionExW +GetVolumeInformationA +GetVolumeInformationW +GetWindowsDirectoryA +GetWindowsDirectoryW +GetWriteWatch +GlobalAddAtomA +GlobalAddAtomW +GlobalAlloc +GlobalCompact +GlobalDeleteAtom +GlobalFindAtomA +GlobalFindAtomW +GlobalFix +GlobalFlags +GlobalFree +GlobalGetAtomNameA +GlobalGetAtomNameW +GlobalHandle +GlobalLock +GlobalMemoryStatus +GlobalReAlloc +GlobalSize +GlobalUnWire +GlobalUnfix +GlobalUnlock +GlobalWire +Heap32First +Heap32ListFirst +Heap32ListNext +Heap32Next +HeapAlloc +HeapCompact +HeapCreate +HeapDestroy +HeapFree +HeapLock +HeapReAlloc +HeapSetFlags +HeapSize +HeapUnlock +HeapValidate +HeapWalk +InitAtomTable +InitializeCriticalSection +InitializeCriticalSectionAndSpinCount +InterlockedCompareExchange +InterlockedDecrement +InterlockedExchange +InterlockedExchangeAdd +InterlockedIncrement +InvalidateNLSCache +IsBadCodePtr +IsBadHugeReadPtr +IsBadHugeWritePtr +IsBadReadPtr +IsBadStringPtrA +IsBadStringPtrW +IsBadWritePtr +IsDBCSLeadByte +IsDBCSLeadByteEx +IsDebuggerPresent +IsLSCallback +IsProcessorFeaturePresent +IsSLCallback +IsSystemResumeAutomatic +IsValidCodePage +IsValidLanguageGroup +IsValidLocale +K32Thk1632Epilog +K32Thk1632Prolog +K32_NtCreateFile +K32_RtlNtStatusToDosError +LCMapStringA +LCMapStringW +LeaveCriticalSection +LoadLibraryA +LoadLibraryExA +LoadLibraryExW +LoadLibraryW +LoadModule +LoadResource +LocalAlloc +LocalCompact +LocalFileTimeToFileTime +LocalFlags +LocalFree +LocalHandle +LocalLock +LocalReAlloc +LocalShrink +LocalSize +LocalUnlock +LockFile +LockFileEx +LockResource +MakeCriticalSectionGlobal +MapHInstLS +MapHInstLS_PN +MapHInstSL +MapHInstSL_PN +MapHModuleLS +MapHModuleSL +MapLS +MapSL +MapSLFix +MapViewOfFile +MapViewOfFileEx +Module32First +Module32Next +MoveFileA +MoveFileExA +MoveFileExW +MoveFileW +MulDiv +MultiByteToWideChar +NotifyNLSUserCache +OpenEventA +OpenEventW +OpenFile +OpenFileMappingA +OpenFileMappingW +OpenMutexA +OpenMutexW +OpenProcess +OpenProfileUserMapping +OpenSemaphoreA +OpenSemaphoreW +OpenThread +OpenVxDHandle +OpenWaitableTimerA +OpenWaitableTimerW +OutputDebugStringA +OutputDebugStringW +PeekConsoleInputA +PeekConsoleInputW +PeekNamedPipe +PostQueuedCompletionStatus +PrepareTape +Process32First +Process32Next +PulseEvent +PurgeComm +QT_Thunk +QueryDosDeviceA +QueryDosDeviceW +QueryNumberOfEventLogRecords +QueryOldestEventLogRecord +QueryPerformanceCounter +QueryPerformanceFrequency +QueueUserAPC +RaiseException +ReadConsoleA +ReadConsoleInputA +ReadConsoleInputW +ReadConsoleOutputA +ReadConsoleOutputAttribute +ReadConsoleOutputCharacterA +ReadConsoleOutputCharacterW +ReadConsoleOutputW +ReadConsoleW +ReadDirectoryChangesW +ReadFile +ReadFileEx +ReadFileScatter +ReadProcessMemory +RegisterServiceProcess +RegisterSysMsgHandler +ReinitializeCriticalSection +ReleaseMutex +ReleaseSemaphore +RemoveDirectoryA +RemoveDirectoryW +RequestDeviceWakeup +RequestWakeupLatency +ResetEvent +ResetNLSUserInfoCache +ResetWriteWatch +ResumeThread +RtlAddFunctionTable +RtlDeleteFunctionTable +RtlFillMemory +RtlInstallFunctionTableCallback +RtlMoveMemory +RtlUnwind +RtlUnwindEx +RtlZeroMemory +SMapLS +SMapLS_IP_EBP_12 +SMapLS_IP_EBP_16 +SMapLS_IP_EBP_20 +SMapLS_IP_EBP_24 +SMapLS_IP_EBP_28 +SMapLS_IP_EBP_32 +SMapLS_IP_EBP_36 +SMapLS_IP_EBP_40 +SMapLS_IP_EBP_8 +SUnMapLS +SUnMapLS_IP_EBP_12 +SUnMapLS_IP_EBP_16 +SUnMapLS_IP_EBP_20 +SUnMapLS_IP_EBP_24 +SUnMapLS_IP_EBP_28 +SUnMapLS_IP_EBP_32 +SUnMapLS_IP_EBP_36 +SUnMapLS_IP_EBP_40 +SUnMapLS_IP_EBP_8 +ScrollConsoleScreenBufferA +ScrollConsoleScreenBufferW +SearchPathA +SearchPathW +SetCalendarInfoA +SetCalendarInfoW +SetCommBreak +SetCommConfig +SetCommMask +SetCommState +SetCommTimeouts +SetComputerNameA +SetComputerNameW +SetConsoleActiveScreenBuffer +SetConsoleCP +SetConsoleCtrlHandler +SetConsoleCursorInfo +SetConsoleCursorPosition +SetConsoleMode +SetConsoleOutputCP +SetConsoleScreenBufferSize +SetConsoleTextAttribute +SetConsoleTitleA +SetConsoleTitleW +SetConsoleWindowInfo +SetCriticalSectionSpinCount +SetCurrentDirectoryA +SetCurrentDirectoryW +SetDaylightFlag +SetDefaultCommConfigA +SetDefaultCommConfigW +SetEndOfFile +SetEnvironmentVariableA +SetEnvironmentVariableW +SetErrorMode +SetEvent +SetFileApisToANSI +SetFileApisToOEM +SetFileAttributesA +SetFileAttributesW +SetFilePointer +SetFilePointerEx +SetFileTime +SetHandleContext +SetHandleCount +SetHandleInformation +SetLastError +SetLocalTime +SetLocaleInfoA +SetLocaleInfoW +SetMailslotInfo +SetMessageWaitingIndicator +SetNamedPipeHandleState +SetPriorityClass +SetProcessAffinityMask +SetProcessPriorityBoost +SetProcessShutdownParameters +SetProcessWorkingSetSize +SetStdHandle +SetSystemPowerState +SetSystemTime +SetSystemTimeAdjustment +SetTapeParameters +SetTapePosition +SetThreadAffinityMask +SetThreadContext +SetThreadExecutionState +SetThreadIdealProcessor +SetThreadLocale +SetThreadPriority +SetThreadPriorityBoost +SetTimeZoneInformation +SetUnhandledExceptionFilter +SetUserGeoID +SetVolumeLabelA +SetVolumeLabelW +SetWaitableTimer +SetupComm +SignalObjectAndWait +SignalSysMsgHandlers +SizeofResource +Sleep +SleepEx +SuspendThread +SwitchToFiber +SwitchToThread +SystemTimeToFileTime +SystemTimeToTzSpecificLocalTime +TerminateProcess +TerminateThread +Thread32First +Thread32Next +ThunkConnect32 +TlsAlloc +TlsAllocInternal +TlsFree +TlsFreeInternal +TlsGetValue +TlsSetValue +Toolhelp32ReadProcessMemory +TransactNamedPipe +TransmitCommChar +TryEnterCriticalSection +UTRegister +UTUnRegister +UnMapLS +UnMapSLFixArray +UnhandledExceptionFilter +UninitializeCriticalSection +UnlockFile +UnlockFileEx +UnmapViewOfFile +UpdateResourceA +UpdateResourceW +VerLanguageNameA +VerLanguageNameW +VirtualAlloc +VirtualAllocEx +VirtualFree +VirtualFreeEx +VirtualLock +VirtualProtect +VirtualProtectEx +VirtualQuery +VirtualQueryEx +VirtualUnlock +WaitCommEvent +WaitForDebugEvent +WaitForMultipleObjects +WaitForMultipleObjectsEx +WaitForSingleObject +WaitForSingleObjectEx +WaitNamedPipeA +WaitNamedPipeW +WideCharToMultiByte +WinExec +WriteConsoleA +WriteConsoleInputA +WriteConsoleInputW +WriteConsoleOutputA +WriteConsoleOutputAttribute +WriteConsoleOutputCharacterA +WriteConsoleOutputCharacterW +WriteConsoleOutputW +WriteConsoleW +WriteFile +WriteFileEx +WriteFileGather +WritePrivateProfileSectionA +WritePrivateProfileSectionW +WritePrivateProfileStringA +WritePrivateProfileStringW +WritePrivateProfileStructA +WritePrivateProfileStructW +WriteProcessMemory +WriteProfileSectionA +WriteProfileSectionW +WriteProfileStringA +WriteProfileStringW +WriteTapemark +_DebugOut +_DebugPrintf +_hread +_hwrite +_lclose +_lcreat +_llseek +_lopen +_lread +_lwrite +dprintf +lstrcat +lstrcatA +lstrcatW +lstrcmp +lstrcmpA +lstrcmpW +lstrcmpi +lstrcmpiA +lstrcmpiW +lstrcpy +lstrcpyA +lstrcpyW +lstrcpyn +lstrcpynA +lstrcpynW +lstrlen +lstrlenA +lstrlenW diff --git a/tcc/lib/msvcrt.def b/tcc/lib/msvcrt.def index 4321b5d6..e8f6ab91 100644 --- a/tcc/lib/msvcrt.def +++ b/tcc/lib/msvcrt.def @@ -1,1320 +1,1320 @@ -LIBRARY msvcrt.dll - -EXPORTS -??0__non_rtti_object@@QEAA@AEBV0@@Z -??0__non_rtti_object@@QEAA@PEBD@Z -??0bad_cast@@AAE@PBQBD@Z -??0bad_cast@@AEAA@PEBQEBD@Z -??0bad_cast@@QAE@ABQBD@Z -??0bad_cast@@QEAA@AEBQEBD@Z -??0bad_cast@@QEAA@AEBV0@@Z -??0bad_cast@@QEAA@PEBD@Z -??0bad_typeid@@QEAA@AEBV0@@Z -??0bad_typeid@@QEAA@PEBD@Z -??0exception@@QEAA@AEBQEBD@Z -??0exception@@QEAA@AEBQEBDH@Z -??0exception@@QEAA@AEBV0@@Z -??0exception@@QEAA@XZ -??1__non_rtti_object@@UEAA@XZ -??1bad_cast@@UEAA@XZ -??1bad_typeid@@UEAA@XZ -??1exception@@UEAA@XZ -??1type_info@@UEAA@XZ -??2@YAPEAX_K@Z -??2@YAPEAX_KHPEBDH@Z -??3@YAXPEAX@Z -??4__non_rtti_object@@QEAAAEAV0@AEBV0@@Z -??4bad_cast@@QEAAAEAV0@AEBV0@@Z -??4bad_typeid@@QEAAAEAV0@AEBV0@@Z -??4exception@@QEAAAEAV0@AEBV0@@Z -??8type_info@@QEBAHAEBV0@@Z -??9type_info@@QEBAHAEBV0@@Z -??_7__non_rtti_object@@6B@ -??_7bad_cast@@6B@ -??_7bad_typeid@@6B@ -??_7exception@@6B@ -??_Fbad_cast@@QEAAXXZ -??_Fbad_typeid@@QEAAXXZ -??_U@YAPEAX_K@Z -??_U@YAPEAX_KHPEBDH@Z -??_V@YAXPEAX@Z -?_query_new_handler@@YAP6AH_K@ZXZ -?_query_new_mode@@YAHXZ -?_set_new_handler@@YAP6AH_K@ZP6AH0@Z@Z -?_set_new_mode@@YAHH@Z -?_set_se_translator@@YAP6AXIPEAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z -?before@type_info@@QEBAHAEBV1@@Z -?name@type_info@@QEBAPEBDXZ -?raw_name@type_info@@QEBAPEBDXZ -?set_new_handler@@YAP6AXXZP6AXXZ@Z -?set_terminate@@YAP6AXXZP6AXXZ@Z -?set_unexpected@@YAP6AXXZP6AXXZ@Z -?terminate@@YAXXZ -?unexpected@@YAXXZ -?what@exception@@UEBAPEBDXZ -_CrtCheckMemory -_CrtDbgBreak -_CrtDbgReport -_CrtDbgReportV -_CrtDbgReportW -_CrtDbgReportWV -_CrtDoForAllClientObjects -_CrtDumpMemoryLeaks -_CrtIsMemoryBlock -_CrtIsValidHeapPointer -_CrtIsValidPointer -_CrtMemCheckpoint -_CrtMemDifference -_CrtMemDumpAllObjectsSince -_CrtMemDumpStatistics -_CrtReportBlockType -_CrtSetAllocHook -_CrtSetBreakAlloc -_CrtSetDbgBlockType -_CrtSetDbgFlag -_CrtSetDumpClient -_CrtSetReportFile -_CrtSetReportHook -_CrtSetReportHook2 -_CrtSetReportMode -_CxxThrowException -_Getdays -_Getmonths -_Gettnames -_HUGE -_Strftime -_W_Getdays -_W_Getmonths -_W_Gettnames -_Wcsftime -_XcptFilter -__AdjustPointer -__C_specific_handler -__CppXcptFilter -__CxxFrameHandler -__CxxFrameHandler2 -__CxxFrameHandler3 -__DestructExceptionObject -__ExceptionPtrAssign -__ExceptionPtrCompare -__ExceptionPtrCopy -__ExceptionPtrCopyException -__ExceptionPtrCreate -__ExceptionPtrCurrentException -__ExceptionPtrDestroy -__ExceptionPtrRethrow -__ExceptionPtrSwap -__ExceptionPtrToBool -__RTCastToVoid -__RTDynamicCast -__RTtypeid -__STRINGTOLD -___lc_codepage_func -___lc_collate_cp_func -___lc_handle_func -___mb_cur_max_func -___setlc_active_func -___unguarded_readlc_active_add_func -__argc -__argv -__badioinfo -__crtCompareStringA -__crtCompareStringW -__crtGetLocaleInfoW -__crtGetStringTypeW -__crtLCMapStringA -__crtLCMapStringW -__daylight -__dllonexit -__doserrno -__dstbias -__fpecode -__getmainargs -__initenv -__iob_func -__isascii -__iscsym -__iscsymf -__lc_codepage -__lc_collate_cp -__lc_handle -__lconv_init -__mb_cur_max -__pctype_func -__pioinfo -__pwctype_func -__pxcptinfoptrs -__set_app_type -__setlc_active -__setusermatherr -__strncnt -__threadhandle -__threadid -__toascii -__unDName -__unDNameEx -__uncaught_exception -__unguarded_readlc_active -__wargv -__wcserror -__wcserror_s -__wcsncnt -__wgetmainargs -__winitenv -_abs64 -_access -_access_s -_acmdln -_aexit_rtn -_aligned_free -_aligned_free_dbg -_aligned_malloc -_aligned_malloc_dbg -_aligned_offset_malloc -_aligned_offset_malloc_dbg -_aligned_offset_realloc -_aligned_offset_realloc_dbg -_aligned_realloc -_aligned_realloc_dbg -_amsg_exit -_assert -_atodbl -_atodbl_l -_atof_l -_atoflt_l -_atoi64 -_atoi64_l -_atoi_l -_atol_l -_atoldbl -_atoldbl_l -_beep -_beginthread -_beginthreadex -_c_exit -_cabs -_callnewh -_calloc_dbg -_cexit -_cgets -_cgets_s -_cgetws -_cgetws_s -_chdir -_chdrive -_chgsign -_chgsignf -_chmod -_chsize -_chsize_s -_chvalidator -_chvalidator_l -_clearfp -_close -_commit -_commode -_control87 -_controlfp -_controlfp_s -_copysign -_copysignf -_cprintf -_cprintf_l -_cprintf_p -_cprintf_p_l -_cprintf_s -_cprintf_s_l -_cputs -_cputws -_creat -_create_locale -_crtAssertBusy -_crtBreakAlloc -_crtDbgFlag -_cscanf -_cscanf_l -_cscanf_s -_cscanf_s_l -_ctime32 -_ctime32_s -_ctime64 -_ctime64_s -_ctype -_cwait -_cwprintf -_cwprintf_l -_cwprintf_p -_cwprintf_p_l -_cwprintf_s -_cwprintf_s_l -_cwscanf -_cwscanf_l -_cwscanf_s -_cwscanf_s_l -_daylight -_difftime32 -_difftime64 -_dstbias -_dup -_dup2 -_ecvt -_ecvt_s -_endthread -_endthreadex -_environ -_eof -_errno -_execl -_execle -_execlp -_execlpe -_execv -_execve -_execvp -_execvpe -_exit -_expand -_expand_dbg -_fcloseall -_fcvt -_fcvt_s -_fdopen -_fgetchar -_fgetwchar -_filbuf -_fileinfo -_filelength -_filelengthi64 -_fileno -_findclose -_findfirst -_findfirst64 -_findfirsti64 -_findnext -_findnext64 -_findnexti64 -_finite -_finitef -_flsbuf -_flushall -_fmode -_fpclass -_fpclassf -_fpreset -_fprintf_l -_fprintf_p -_fprintf_p_l -_fprintf_s_l -_fputchar -_fputwchar -_free_dbg -_free_locale -_freea -_freea_s -_fscanf_l -_fscanf_s_l -_fseeki64 -_fsopen -_fstat -_fstat64 -_fstati64 -_ftime -_ftime32 -_ftime32_s -_ftime64 -_ftime64_s -_fullpath -_fullpath_dbg -_futime -_futime32 -_futime64 -_fwprintf_l -_fwprintf_p -_fwprintf_p_l -_fwprintf_s_l -_fwscanf_l -_fwscanf_s_l -_gcvt -_gcvt_s -_get_current_locale -_get_doserrno -_get_environ -_get_errno -_get_fileinfo -_get_fmode -_get_heap_handle -_get_osfhandle -_get_osplatform -_get_osver -_get_output_format -_get_pgmptr -_get_sbh_threshold -_get_wenviron -_get_winmajor -_get_winminor -_get_winver -_get_wpgmptr -_getch -_getche -_getcwd -_getdcwd -_getdiskfree -_getdrive -_getdrives -_getmaxstdio -_getmbcp -_getpid -_getsystime -_getw -_getwch -_getwche -_getws -_gmtime32 -_gmtime32_s -_gmtime64 -_gmtime64_s -_heapchk -_heapmin -_heapset -_heapwalk -_hypot -_hypotf -_i64toa -_i64toa_s -_i64tow -_i64tow_s -_initterm -_initterm_e -_invalid_parameter -_iob -_isalnum_l -_isalpha_l -_isatty -_iscntrl_l -_isctype -_isctype_l -_isdigit_l -_isgraph_l -_isleadbyte_l -_islower_l -_ismbbalnum -_ismbbalnum_l -_ismbbalpha -_ismbbalpha_l -_ismbbgraph -_ismbbgraph_l -_ismbbkalnum -_ismbbkalnum_l -_ismbbkana -_ismbbkana_l -_ismbbkprint -_ismbbkprint_l -_ismbbkpunct -_ismbbkpunct_l -_ismbblead -_ismbblead_l -_ismbbprint -_ismbbprint_l -_ismbbpunct -_ismbbpunct_l -_ismbbtrail -_ismbbtrail_l -_ismbcalnum -_ismbcalnum_l -_ismbcalpha -_ismbcalpha_l -_ismbcdigit -_ismbcdigit_l -_ismbcgraph -_ismbcgraph_l -_ismbchira -_ismbchira_l -_ismbckata -_ismbckata_l -_ismbcl0 -_ismbcl0_l -_ismbcl1 -_ismbcl1_l -_ismbcl2 -_ismbcl2_l -_ismbclegal -_ismbclegal_l -_ismbclower -_ismbclower_l -_ismbcprint -_ismbcprint_l -_ismbcpunct -_ismbcpunct_l -_ismbcspace -_ismbcspace_l -_ismbcsymbol -_ismbcsymbol_l -_ismbcupper -_ismbcupper_l -_ismbslead -_ismbslead_l -_ismbstrail -_ismbstrail_l -_isnan -_isnanf -_isprint_l -_isspace_l -_isupper_l -_iswalnum_l -_iswalpha_l -_iswcntrl_l -_iswctype_l -_iswdigit_l -_iswgraph_l -_iswlower_l -_iswprint_l -_iswpunct_l -_iswspace_l -_iswupper_l -_iswxdigit_l -_isxdigit_l -_itoa -_itoa_s -_itow -_itow_s -_j0 -_j1 -_jn -_kbhit -_lfind -_lfind_s -_local_unwind -_localtime32 -_localtime32_s -_localtime64 -_localtime64_s -_lock -_locking -_logb -_logbf -_lrotl -_lrotr -_lsearch -_lsearch_s -_lseek -_lseeki64 -_ltoa -_ltoa_s -_ltow -_ltow_s -_makepath -_makepath_s -_malloc_dbg -_mbbtombc -_mbbtombc_l -_mbbtype -_mbcasemap -_mbccpy -_mbccpy_l -_mbccpy_s -_mbccpy_s_l -_mbcjistojms -_mbcjistojms_l -_mbcjmstojis -_mbcjmstojis_l -_mbclen -_mbclen_l -_mbctohira -_mbctohira_l -_mbctokata -_mbctokata_l -_mbctolower -_mbctolower_l -_mbctombb -_mbctombb_l -_mbctoupper -_mbctoupper_l -_mbctype -_mblen_l -_mbsbtype -_mbsbtype_l -_mbscat -_mbscat_s -_mbscat_s_l -_mbschr -_mbschr_l -_mbscmp -_mbscmp_l -_mbscoll -_mbscoll_l -_mbscpy -_mbscpy_s -_mbscpy_s_l -_mbscspn -_mbscspn_l -_mbsdec -_mbsdec_l -_mbsdup -_mbsicmp -_mbsicmp_l -_mbsicoll -_mbsicoll_l -_mbsinc -_mbsinc_l -_mbslen -_mbslen_l -_mbslwr -_mbslwr_l -_mbslwr_s -_mbslwr_s_l -_mbsnbcat -_mbsnbcat_l -_mbsnbcat_s -_mbsnbcat_s_l -_mbsnbcmp -_mbsnbcmp_l -_mbsnbcnt -_mbsnbcnt_l -_mbsnbcoll -_mbsnbcoll_l -_mbsnbcpy -_mbsnbcpy_l -_mbsnbcpy_s -_mbsnbcpy_s_l -_mbsnbicmp -_mbsnbicmp_l -_mbsnbicoll -_mbsnbicoll_l -_mbsnbset -_mbsnbset_l -_mbsnbset_s -_mbsnbset_s_l -_mbsncat -_mbsncat_l -_mbsncat_s -_mbsncat_s_l -_mbsnccnt -_mbsnccnt_l -_mbsncmp -_mbsncmp_l -_mbsncoll -_mbsncoll_l -_mbsncpy -_mbsncpy_l -_mbsncpy_s -_mbsncpy_s_l -_mbsnextc -_mbsnextc_l -_mbsnicmp -_mbsnicmp_l -_mbsnicoll -_mbsnicoll_l -_mbsninc -_mbsninc_l -_mbsnlen -_mbsnlen_l -_mbsnset -_mbsnset_l -_mbsnset_s -_mbsnset_s_l -_mbspbrk -_mbspbrk_l -_mbsrchr -_mbsrchr_l -_mbsrev -_mbsrev_l -_mbsset -_mbsset_l -_mbsset_s -_mbsset_s_l -_mbsspn -_mbsspn_l -_mbsspnp -_mbsspnp_l -_mbsstr -_mbsstr_l -_mbstok -_mbstok_l -_mbstok_s -_mbstok_s_l -_mbstowcs_l -_mbstowcs_s_l -_mbstrlen -_mbstrlen_l -_mbstrnlen -_mbstrnlen_l -_mbsupr -_mbsupr_l -_mbsupr_s -_mbsupr_s_l -_mbtowc_l -_memccpy -_memicmp -_memicmp_l -_mkdir -_mkgmtime -_mkgmtime32 -_mkgmtime64 -_mktemp -_mktemp_s -_mktime32 -_mktime64 -_msize -_msize_dbg -_nextafter -_nextafterf -_onexit -_open -_open_osfhandle -_osplatform -_osver -_pclose -_pctype -_pgmptr -_pipe -_popen -_printf_l -_printf_p -_printf_p_l -_printf_s_l -_purecall -_putch -_putenv -_putenv_s -_putw -_putwch -_putws -_pwctype -_read -_realloc_dbg -_resetstkoflw -_rmdir -_rmtmp -_rotl -_rotl64 -_rotr -_rotr64 -_scalb -_scalbf -_scanf_l -_scanf_s_l -_scprintf -_scprintf_l -_scprintf_p_l -_scwprintf -_scwprintf_l -_scwprintf_p_l -_searchenv -_searchenv_s -_set_controlfp -_set_doserrno -_set_errno -_set_error_mode -_set_fileinfo -_set_fmode -_set_output_format -_set_sbh_threshold -_seterrormode -_setjmp -_setjmpex -_setmaxstdio -_setmbcp -_setmode -_setsystime -_sleep -_snprintf -_snprintf_c -_snprintf_c_l -_snprintf_l -_snprintf_s -_snprintf_s_l -_snscanf -_snscanf_l -_snscanf_s -_snscanf_s_l -_snwprintf -_snwprintf_l -_snwprintf_s -_snwprintf_s_l -_snwscanf -_snwscanf_l -_snwscanf_s -_snwscanf_s_l -_sopen -_sopen_s -_spawnl -_spawnle -_spawnlp -_spawnlpe -_spawnv -_spawnve -_spawnvp -_spawnvpe -_splitpath -_splitpath_s -_sprintf_l -_sprintf_p_l -_sprintf_s_l -_sscanf_l -_sscanf_s_l -_stat -_stat64 -_stati64 -_statusfp -_strcmpi -_strcoll_l -_strdate -_strdate_s -_strdup -_strdup_dbg -_strerror -_strerror_s -_stricmp -_stricmp_l -_stricoll -_stricoll_l -_strlwr -_strlwr_l -_strlwr_s -_strlwr_s_l -_strncoll -_strncoll_l -_strnicmp -_strnicmp_l -_strnicoll -_strnicoll_l -_strnset -_strnset_s -_strrev -_strset -_strset_s -_strtime -_strtime_s -_strtod_l -_strtoi64 -_strtoi64_l -_strtol_l -_strtoui64 -_strtoui64_l -_strtoul_l -_strupr -_strupr_l -_strupr_s -_strupr_s_l -_strxfrm_l -_swab -_swprintf -_swprintf_c -_swprintf_c_l -_swprintf_p_l -_swprintf_s_l -_swscanf_l -_swscanf_s_l -_sys_errlist -_sys_nerr -_tell -_telli64 -_tempnam -_tempnam_dbg -_time32 -_time64 -_timezone -_tolower -_tolower_l -_toupper -_toupper_l -_towlower_l -_towupper_l -_tzname -_tzset -_ui64toa -_ui64toa_s -_ui64tow -_ui64tow_s -_ultoa -_ultoa_s -_ultow -_ultow_s -_umask -_umask_s -_ungetch -_ungetwch -_unlink -_unlock -_utime -_utime32 -_utime64 -_vcprintf -_vcprintf_l -_vcprintf_p -_vcprintf_p_l -_vcprintf_s -_vcprintf_s_l -_vcwprintf -_vcwprintf_l -_vcwprintf_p -_vcwprintf_p_l -_vcwprintf_s -_vcwprintf_s_l -_vfprintf_l -_vfprintf_p -_vfprintf_p_l -_vfprintf_s_l -_vfwprintf_l -_vfwprintf_p -_vfwprintf_p_l -_vfwprintf_s_l -_vprintf_l -_vprintf_p -_vprintf_p_l -_vprintf_s_l -_vscprintf -_vscprintf_l -_vscprintf_p_l -_vscwprintf -_vscwprintf_l -_vscwprintf_p_l -_vsnprintf -_vsnprintf_c -_vsnprintf_c_l -_vsnprintf_l -_vsnprintf_s -_vsnprintf_s_l -_vsnwprintf -_vsnwprintf_l -_vsnwprintf_s -_vsnwprintf_s_l -_vsprintf_l -_vsprintf_p -_vsprintf_p_l -_vsprintf_s_l -_vswprintf -_vswprintf_c -_vswprintf_c_l -_vswprintf_l -_vswprintf_p_l -_vswprintf_s_l -_vwprintf_l -_vwprintf_p -_vwprintf_p_l -_vwprintf_s_l -_waccess -_waccess_s -_wasctime -_wasctime_s -_wassert -_wchdir -_wchmod -_wcmdln -_wcreat -_wcscoll_l -_wcsdup -_wcsdup_dbg -_wcserror -_wcserror_s -_wcsftime_l -_wcsicmp -_wcsicmp_l -_wcsicoll -_wcsicoll_l -_wcslwr -_wcslwr_l -_wcslwr_s -_wcslwr_s_l -_wcsncoll -_wcsncoll_l -_wcsnicmp -_wcsnicmp_l -_wcsnicoll -_wcsnicoll_l -_wcsnset -_wcsnset_s -_wcsrev -_wcsset -_wcsset_s -_wcstod_l -_wcstoi64 -_wcstoi64_l -_wcstol_l -_wcstombs_l -_wcstombs_s_l -_wcstoui64 -_wcstoui64_l -_wcstoul_l -_wcsupr -_wcsupr_l -_wcsupr_s -_wcsupr_s_l -_wcsxfrm_l -_wctime -_wctime32 -_wctime32_s -_wctime64 -_wctime64_s -_wctomb_l -_wctomb_s_l -_wctype -_wenviron -_wexecl -_wexecle -_wexeclp -_wexeclpe -_wexecv -_wexecve -_wexecvp -_wexecvpe -_wfdopen -_wfindfirst -_wfindfirst64 -_wfindfirsti64 -_wfindnext -_wfindnext64 -_wfindnexti64 -_wfopen -_wfopen_s -_wfreopen -_wfreopen_s -_wfsopen -_wfullpath -_wfullpath_dbg -_wgetcwd -_wgetdcwd -_wgetenv -_wgetenv_s -_winmajor -_winminor -_winput_s -_winver -_wmakepath -_wmakepath_s -_wmkdir -_wmktemp -_wmktemp_s -_wopen -_woutput_s -_wperror -_wpgmptr -_wpopen -_wprintf_l -_wprintf_p -_wprintf_p_l -_wprintf_s_l -_wputenv -_wputenv_s -_wremove -_wrename -_write -_wrmdir -_wscanf_l -_wscanf_s_l -_wsearchenv -_wsearchenv_s -_wsetlocale -_wsopen -_wsopen_s -_wspawnl -_wspawnle -_wspawnlp -_wspawnlpe -_wspawnv -_wspawnve -_wspawnvp -_wspawnvpe -_wsplitpath -_wsplitpath_s -_wstat -_wstat64 -_wstati64 -_wstrdate -_wstrdate_s -_wstrtime -_wstrtime_s -_wsystem -_wtempnam -_wtempnam_dbg -_wtmpnam -_wtmpnam_s -_wtof -_wtof_l -_wtoi -_wtoi64 -_wtoi64_l -_wtoi_l -_wtol -_wtol_l -_wunlink -_wutime -_wutime32 -_wutime64 -_y0 -_y1 -_yn -abort -abs -acos -acosf -asctime -asctime_s -asin -asinf -atan -atan2 -atan2f -atanf -atexit -atof -atoi -atol -bsearch -bsearch_s -btowc -calloc -ceil -ceilf -clearerr -clearerr_s -clock -cos -cosf -cosh -coshf -ctime -difftime -div -exit -exp -expf -fabs -fclose -feof -ferror -fflush -fgetc -fgetpos -fgets -fgetwc -fgetws -floor -floorf -fmod -fmodf -fopen -fopen_s -fprintf -fprintf_s -fputc -fputs -fputwc -fputws -fread -free -freopen -freopen_s -frexp -fscanf -fscanf_s -fseek -fsetpos -ftell -fwprintf -fwprintf_s -fwrite -fwscanf -fwscanf_s -getc -getchar -getenv -getenv_s -gets -getwc -getwchar -gmtime -is_wctype -isalnum -isalpha -iscntrl -isdigit -isgraph -isleadbyte -islower -isprint -ispunct -isspace -isupper -iswalnum -iswalpha -iswascii -iswcntrl -iswctype -iswdigit -iswgraph -iswlower -iswprint -iswpunct -iswspace -iswupper -iswxdigit -isxdigit -labs -ldexp -ldiv -localeconv -localtime -log -log10 -log10f -logf -longjmp -malloc -mblen -mbrlen -mbrtowc -mbsdup_dbg -mbsrtowcs -mbsrtowcs_s -mbstowcs -mbstowcs_s -mbtowc -memchr -memcmp -memcpy -memcpy_s -memmove -memmove_s -memset -mktime -modf -modff -perror -pow -powf -printf -printf_s -putc -putchar -puts -putwc -putwchar -qsort -qsort_s -raise -rand -rand_s -realloc -remove -rename -rewind -scanf -scanf_s -setbuf -setjmp -setlocale -setvbuf -signal -sin -sinf -sinh -sinhf -sprintf -sprintf_s -sqrt -sqrtf -srand -sscanf -sscanf_s -strcat -strcat_s -strchr -strcmp -strcoll -strcpy -strcpy_s -strcspn -strerror -strerror_s -strftime -strlen -strncat -strncat_s -strncmp -strncpy -strncpy_s -strnlen -strpbrk -strrchr -strspn -strstr -strtod -strtok -strtok_s -strtol -strtoul -strxfrm -swprintf -swprintf_s -swscanf -swscanf_s -system -tan -tanf -tanh -tanhf -time -tmpfile -tmpfile_s -tmpnam -tmpnam_s -tolower -toupper -towlower -towupper -ungetc -ungetwc -utime -vfprintf -vfprintf_s -vfwprintf -vfwprintf_s -vprintf -vprintf_s -vsnprintf -vsprintf -vsprintf_s -vswprintf -vswprintf_s -vwprintf -vwprintf_s -wcrtomb -wcrtomb_s -wcscat -wcscat_s -wcschr -wcscmp -wcscoll -wcscpy -wcscpy_s -wcscspn -wcsftime -wcslen -wcsncat -wcsncat_s -wcsncmp -wcsncpy -wcsncpy_s -wcsnlen -wcspbrk -wcsrchr -wcsrtombs -wcsrtombs_s -wcsspn -wcsstr -wcstod -wcstok -wcstok_s -wcstol -wcstombs -wcstombs_s -wcstoul -wcsxfrm -wctob -wctomb -wctomb_s -wprintf -wprintf_s -wscanf -wscanf_s +LIBRARY msvcrt.dll + +EXPORTS +??0__non_rtti_object@@QEAA@AEBV0@@Z +??0__non_rtti_object@@QEAA@PEBD@Z +??0bad_cast@@AAE@PBQBD@Z +??0bad_cast@@AEAA@PEBQEBD@Z +??0bad_cast@@QAE@ABQBD@Z +??0bad_cast@@QEAA@AEBQEBD@Z +??0bad_cast@@QEAA@AEBV0@@Z +??0bad_cast@@QEAA@PEBD@Z +??0bad_typeid@@QEAA@AEBV0@@Z +??0bad_typeid@@QEAA@PEBD@Z +??0exception@@QEAA@AEBQEBD@Z +??0exception@@QEAA@AEBQEBDH@Z +??0exception@@QEAA@AEBV0@@Z +??0exception@@QEAA@XZ +??1__non_rtti_object@@UEAA@XZ +??1bad_cast@@UEAA@XZ +??1bad_typeid@@UEAA@XZ +??1exception@@UEAA@XZ +??1type_info@@UEAA@XZ +??2@YAPEAX_K@Z +??2@YAPEAX_KHPEBDH@Z +??3@YAXPEAX@Z +??4__non_rtti_object@@QEAAAEAV0@AEBV0@@Z +??4bad_cast@@QEAAAEAV0@AEBV0@@Z +??4bad_typeid@@QEAAAEAV0@AEBV0@@Z +??4exception@@QEAAAEAV0@AEBV0@@Z +??8type_info@@QEBAHAEBV0@@Z +??9type_info@@QEBAHAEBV0@@Z +??_7__non_rtti_object@@6B@ +??_7bad_cast@@6B@ +??_7bad_typeid@@6B@ +??_7exception@@6B@ +??_Fbad_cast@@QEAAXXZ +??_Fbad_typeid@@QEAAXXZ +??_U@YAPEAX_K@Z +??_U@YAPEAX_KHPEBDH@Z +??_V@YAXPEAX@Z +?_query_new_handler@@YAP6AH_K@ZXZ +?_query_new_mode@@YAHXZ +?_set_new_handler@@YAP6AH_K@ZP6AH0@Z@Z +?_set_new_mode@@YAHH@Z +?_set_se_translator@@YAP6AXIPEAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z +?before@type_info@@QEBAHAEBV1@@Z +?name@type_info@@QEBAPEBDXZ +?raw_name@type_info@@QEBAPEBDXZ +?set_new_handler@@YAP6AXXZP6AXXZ@Z +?set_terminate@@YAP6AXXZP6AXXZ@Z +?set_unexpected@@YAP6AXXZP6AXXZ@Z +?terminate@@YAXXZ +?unexpected@@YAXXZ +?what@exception@@UEBAPEBDXZ +_CrtCheckMemory +_CrtDbgBreak +_CrtDbgReport +_CrtDbgReportV +_CrtDbgReportW +_CrtDbgReportWV +_CrtDoForAllClientObjects +_CrtDumpMemoryLeaks +_CrtIsMemoryBlock +_CrtIsValidHeapPointer +_CrtIsValidPointer +_CrtMemCheckpoint +_CrtMemDifference +_CrtMemDumpAllObjectsSince +_CrtMemDumpStatistics +_CrtReportBlockType +_CrtSetAllocHook +_CrtSetBreakAlloc +_CrtSetDbgBlockType +_CrtSetDbgFlag +_CrtSetDumpClient +_CrtSetReportFile +_CrtSetReportHook +_CrtSetReportHook2 +_CrtSetReportMode +_CxxThrowException +_Getdays +_Getmonths +_Gettnames +_HUGE +_Strftime +_W_Getdays +_W_Getmonths +_W_Gettnames +_Wcsftime +_XcptFilter +__AdjustPointer +__C_specific_handler +__CppXcptFilter +__CxxFrameHandler +__CxxFrameHandler2 +__CxxFrameHandler3 +__DestructExceptionObject +__ExceptionPtrAssign +__ExceptionPtrCompare +__ExceptionPtrCopy +__ExceptionPtrCopyException +__ExceptionPtrCreate +__ExceptionPtrCurrentException +__ExceptionPtrDestroy +__ExceptionPtrRethrow +__ExceptionPtrSwap +__ExceptionPtrToBool +__RTCastToVoid +__RTDynamicCast +__RTtypeid +__STRINGTOLD +___lc_codepage_func +___lc_collate_cp_func +___lc_handle_func +___mb_cur_max_func +___setlc_active_func +___unguarded_readlc_active_add_func +__argc +__argv +__badioinfo +__crtCompareStringA +__crtCompareStringW +__crtGetLocaleInfoW +__crtGetStringTypeW +__crtLCMapStringA +__crtLCMapStringW +__daylight +__dllonexit +__doserrno +__dstbias +__fpecode +__getmainargs +__initenv +__iob_func +__isascii +__iscsym +__iscsymf +__lc_codepage +__lc_collate_cp +__lc_handle +__lconv_init +__mb_cur_max +__pctype_func +__pioinfo +__pwctype_func +__pxcptinfoptrs +__set_app_type +__setlc_active +__setusermatherr +__strncnt +__threadhandle +__threadid +__toascii +__unDName +__unDNameEx +__uncaught_exception +__unguarded_readlc_active +__wargv +__wcserror +__wcserror_s +__wcsncnt +__wgetmainargs +__winitenv +_abs64 +_access +_access_s +_acmdln +_aexit_rtn +_aligned_free +_aligned_free_dbg +_aligned_malloc +_aligned_malloc_dbg +_aligned_offset_malloc +_aligned_offset_malloc_dbg +_aligned_offset_realloc +_aligned_offset_realloc_dbg +_aligned_realloc +_aligned_realloc_dbg +_amsg_exit +_assert +_atodbl +_atodbl_l +_atof_l +_atoflt_l +_atoi64 +_atoi64_l +_atoi_l +_atol_l +_atoldbl +_atoldbl_l +_beep +_beginthread +_beginthreadex +_c_exit +_cabs +_callnewh +_calloc_dbg +_cexit +_cgets +_cgets_s +_cgetws +_cgetws_s +_chdir +_chdrive +_chgsign +_chgsignf +_chmod +_chsize +_chsize_s +_chvalidator +_chvalidator_l +_clearfp +_close +_commit +_commode +_control87 +_controlfp +_controlfp_s +_copysign +_copysignf +_cprintf +_cprintf_l +_cprintf_p +_cprintf_p_l +_cprintf_s +_cprintf_s_l +_cputs +_cputws +_creat +_create_locale +_crtAssertBusy +_crtBreakAlloc +_crtDbgFlag +_cscanf +_cscanf_l +_cscanf_s +_cscanf_s_l +_ctime32 +_ctime32_s +_ctime64 +_ctime64_s +_ctype +_cwait +_cwprintf +_cwprintf_l +_cwprintf_p +_cwprintf_p_l +_cwprintf_s +_cwprintf_s_l +_cwscanf +_cwscanf_l +_cwscanf_s +_cwscanf_s_l +_daylight +_difftime32 +_difftime64 +_dstbias +_dup +_dup2 +_ecvt +_ecvt_s +_endthread +_endthreadex +_environ +_eof +_errno +_execl +_execle +_execlp +_execlpe +_execv +_execve +_execvp +_execvpe +_exit +_expand +_expand_dbg +_fcloseall +_fcvt +_fcvt_s +_fdopen +_fgetchar +_fgetwchar +_filbuf +_fileinfo +_filelength +_filelengthi64 +_fileno +_findclose +_findfirst +_findfirst64 +_findfirsti64 +_findnext +_findnext64 +_findnexti64 +_finite +_finitef +_flsbuf +_flushall +_fmode +_fpclass +_fpclassf +_fpreset +_fprintf_l +_fprintf_p +_fprintf_p_l +_fprintf_s_l +_fputchar +_fputwchar +_free_dbg +_free_locale +_freea +_freea_s +_fscanf_l +_fscanf_s_l +_fseeki64 +_fsopen +_fstat +_fstat64 +_fstati64 +_ftime +_ftime32 +_ftime32_s +_ftime64 +_ftime64_s +_fullpath +_fullpath_dbg +_futime +_futime32 +_futime64 +_fwprintf_l +_fwprintf_p +_fwprintf_p_l +_fwprintf_s_l +_fwscanf_l +_fwscanf_s_l +_gcvt +_gcvt_s +_get_current_locale +_get_doserrno +_get_environ +_get_errno +_get_fileinfo +_get_fmode +_get_heap_handle +_get_osfhandle +_get_osplatform +_get_osver +_get_output_format +_get_pgmptr +_get_sbh_threshold +_get_wenviron +_get_winmajor +_get_winminor +_get_winver +_get_wpgmptr +_getch +_getche +_getcwd +_getdcwd +_getdiskfree +_getdrive +_getdrives +_getmaxstdio +_getmbcp +_getpid +_getsystime +_getw +_getwch +_getwche +_getws +_gmtime32 +_gmtime32_s +_gmtime64 +_gmtime64_s +_heapchk +_heapmin +_heapset +_heapwalk +_hypot +_hypotf +_i64toa +_i64toa_s +_i64tow +_i64tow_s +_initterm +_initterm_e +_invalid_parameter +_iob +_isalnum_l +_isalpha_l +_isatty +_iscntrl_l +_isctype +_isctype_l +_isdigit_l +_isgraph_l +_isleadbyte_l +_islower_l +_ismbbalnum +_ismbbalnum_l +_ismbbalpha +_ismbbalpha_l +_ismbbgraph +_ismbbgraph_l +_ismbbkalnum +_ismbbkalnum_l +_ismbbkana +_ismbbkana_l +_ismbbkprint +_ismbbkprint_l +_ismbbkpunct +_ismbbkpunct_l +_ismbblead +_ismbblead_l +_ismbbprint +_ismbbprint_l +_ismbbpunct +_ismbbpunct_l +_ismbbtrail +_ismbbtrail_l +_ismbcalnum +_ismbcalnum_l +_ismbcalpha +_ismbcalpha_l +_ismbcdigit +_ismbcdigit_l +_ismbcgraph +_ismbcgraph_l +_ismbchira +_ismbchira_l +_ismbckata +_ismbckata_l +_ismbcl0 +_ismbcl0_l +_ismbcl1 +_ismbcl1_l +_ismbcl2 +_ismbcl2_l +_ismbclegal +_ismbclegal_l +_ismbclower +_ismbclower_l +_ismbcprint +_ismbcprint_l +_ismbcpunct +_ismbcpunct_l +_ismbcspace +_ismbcspace_l +_ismbcsymbol +_ismbcsymbol_l +_ismbcupper +_ismbcupper_l +_ismbslead +_ismbslead_l +_ismbstrail +_ismbstrail_l +_isnan +_isnanf +_isprint_l +_isspace_l +_isupper_l +_iswalnum_l +_iswalpha_l +_iswcntrl_l +_iswctype_l +_iswdigit_l +_iswgraph_l +_iswlower_l +_iswprint_l +_iswpunct_l +_iswspace_l +_iswupper_l +_iswxdigit_l +_isxdigit_l +_itoa +_itoa_s +_itow +_itow_s +_j0 +_j1 +_jn +_kbhit +_lfind +_lfind_s +_local_unwind +_localtime32 +_localtime32_s +_localtime64 +_localtime64_s +_lock +_locking +_logb +_logbf +_lrotl +_lrotr +_lsearch +_lsearch_s +_lseek +_lseeki64 +_ltoa +_ltoa_s +_ltow +_ltow_s +_makepath +_makepath_s +_malloc_dbg +_mbbtombc +_mbbtombc_l +_mbbtype +_mbcasemap +_mbccpy +_mbccpy_l +_mbccpy_s +_mbccpy_s_l +_mbcjistojms +_mbcjistojms_l +_mbcjmstojis +_mbcjmstojis_l +_mbclen +_mbclen_l +_mbctohira +_mbctohira_l +_mbctokata +_mbctokata_l +_mbctolower +_mbctolower_l +_mbctombb +_mbctombb_l +_mbctoupper +_mbctoupper_l +_mbctype +_mblen_l +_mbsbtype +_mbsbtype_l +_mbscat +_mbscat_s +_mbscat_s_l +_mbschr +_mbschr_l +_mbscmp +_mbscmp_l +_mbscoll +_mbscoll_l +_mbscpy +_mbscpy_s +_mbscpy_s_l +_mbscspn +_mbscspn_l +_mbsdec +_mbsdec_l +_mbsdup +_mbsicmp +_mbsicmp_l +_mbsicoll +_mbsicoll_l +_mbsinc +_mbsinc_l +_mbslen +_mbslen_l +_mbslwr +_mbslwr_l +_mbslwr_s +_mbslwr_s_l +_mbsnbcat +_mbsnbcat_l +_mbsnbcat_s +_mbsnbcat_s_l +_mbsnbcmp +_mbsnbcmp_l +_mbsnbcnt +_mbsnbcnt_l +_mbsnbcoll +_mbsnbcoll_l +_mbsnbcpy +_mbsnbcpy_l +_mbsnbcpy_s +_mbsnbcpy_s_l +_mbsnbicmp +_mbsnbicmp_l +_mbsnbicoll +_mbsnbicoll_l +_mbsnbset +_mbsnbset_l +_mbsnbset_s +_mbsnbset_s_l +_mbsncat +_mbsncat_l +_mbsncat_s +_mbsncat_s_l +_mbsnccnt +_mbsnccnt_l +_mbsncmp +_mbsncmp_l +_mbsncoll +_mbsncoll_l +_mbsncpy +_mbsncpy_l +_mbsncpy_s +_mbsncpy_s_l +_mbsnextc +_mbsnextc_l +_mbsnicmp +_mbsnicmp_l +_mbsnicoll +_mbsnicoll_l +_mbsninc +_mbsninc_l +_mbsnlen +_mbsnlen_l +_mbsnset +_mbsnset_l +_mbsnset_s +_mbsnset_s_l +_mbspbrk +_mbspbrk_l +_mbsrchr +_mbsrchr_l +_mbsrev +_mbsrev_l +_mbsset +_mbsset_l +_mbsset_s +_mbsset_s_l +_mbsspn +_mbsspn_l +_mbsspnp +_mbsspnp_l +_mbsstr +_mbsstr_l +_mbstok +_mbstok_l +_mbstok_s +_mbstok_s_l +_mbstowcs_l +_mbstowcs_s_l +_mbstrlen +_mbstrlen_l +_mbstrnlen +_mbstrnlen_l +_mbsupr +_mbsupr_l +_mbsupr_s +_mbsupr_s_l +_mbtowc_l +_memccpy +_memicmp +_memicmp_l +_mkdir +_mkgmtime +_mkgmtime32 +_mkgmtime64 +_mktemp +_mktemp_s +_mktime32 +_mktime64 +_msize +_msize_dbg +_nextafter +_nextafterf +_onexit +_open +_open_osfhandle +_osplatform +_osver +_pclose +_pctype +_pgmptr +_pipe +_popen +_printf_l +_printf_p +_printf_p_l +_printf_s_l +_purecall +_putch +_putenv +_putenv_s +_putw +_putwch +_putws +_pwctype +_read +_realloc_dbg +_resetstkoflw +_rmdir +_rmtmp +_rotl +_rotl64 +_rotr +_rotr64 +_scalb +_scalbf +_scanf_l +_scanf_s_l +_scprintf +_scprintf_l +_scprintf_p_l +_scwprintf +_scwprintf_l +_scwprintf_p_l +_searchenv +_searchenv_s +_set_controlfp +_set_doserrno +_set_errno +_set_error_mode +_set_fileinfo +_set_fmode +_set_output_format +_set_sbh_threshold +_seterrormode +_setjmp +_setjmpex +_setmaxstdio +_setmbcp +_setmode +_setsystime +_sleep +_snprintf +_snprintf_c +_snprintf_c_l +_snprintf_l +_snprintf_s +_snprintf_s_l +_snscanf +_snscanf_l +_snscanf_s +_snscanf_s_l +_snwprintf +_snwprintf_l +_snwprintf_s +_snwprintf_s_l +_snwscanf +_snwscanf_l +_snwscanf_s +_snwscanf_s_l +_sopen +_sopen_s +_spawnl +_spawnle +_spawnlp +_spawnlpe +_spawnv +_spawnve +_spawnvp +_spawnvpe +_splitpath +_splitpath_s +_sprintf_l +_sprintf_p_l +_sprintf_s_l +_sscanf_l +_sscanf_s_l +_stat +_stat64 +_stati64 +_statusfp +_strcmpi +_strcoll_l +_strdate +_strdate_s +_strdup +_strdup_dbg +_strerror +_strerror_s +_stricmp +_stricmp_l +_stricoll +_stricoll_l +_strlwr +_strlwr_l +_strlwr_s +_strlwr_s_l +_strncoll +_strncoll_l +_strnicmp +_strnicmp_l +_strnicoll +_strnicoll_l +_strnset +_strnset_s +_strrev +_strset +_strset_s +_strtime +_strtime_s +_strtod_l +_strtoi64 +_strtoi64_l +_strtol_l +_strtoui64 +_strtoui64_l +_strtoul_l +_strupr +_strupr_l +_strupr_s +_strupr_s_l +_strxfrm_l +_swab +_swprintf +_swprintf_c +_swprintf_c_l +_swprintf_p_l +_swprintf_s_l +_swscanf_l +_swscanf_s_l +_sys_errlist +_sys_nerr +_tell +_telli64 +_tempnam +_tempnam_dbg +_time32 +_time64 +_timezone +_tolower +_tolower_l +_toupper +_toupper_l +_towlower_l +_towupper_l +_tzname +_tzset +_ui64toa +_ui64toa_s +_ui64tow +_ui64tow_s +_ultoa +_ultoa_s +_ultow +_ultow_s +_umask +_umask_s +_ungetch +_ungetwch +_unlink +_unlock +_utime +_utime32 +_utime64 +_vcprintf +_vcprintf_l +_vcprintf_p +_vcprintf_p_l +_vcprintf_s +_vcprintf_s_l +_vcwprintf +_vcwprintf_l +_vcwprintf_p +_vcwprintf_p_l +_vcwprintf_s +_vcwprintf_s_l +_vfprintf_l +_vfprintf_p +_vfprintf_p_l +_vfprintf_s_l +_vfwprintf_l +_vfwprintf_p +_vfwprintf_p_l +_vfwprintf_s_l +_vprintf_l +_vprintf_p +_vprintf_p_l +_vprintf_s_l +_vscprintf +_vscprintf_l +_vscprintf_p_l +_vscwprintf +_vscwprintf_l +_vscwprintf_p_l +_vsnprintf +_vsnprintf_c +_vsnprintf_c_l +_vsnprintf_l +_vsnprintf_s +_vsnprintf_s_l +_vsnwprintf +_vsnwprintf_l +_vsnwprintf_s +_vsnwprintf_s_l +_vsprintf_l +_vsprintf_p +_vsprintf_p_l +_vsprintf_s_l +_vswprintf +_vswprintf_c +_vswprintf_c_l +_vswprintf_l +_vswprintf_p_l +_vswprintf_s_l +_vwprintf_l +_vwprintf_p +_vwprintf_p_l +_vwprintf_s_l +_waccess +_waccess_s +_wasctime +_wasctime_s +_wassert +_wchdir +_wchmod +_wcmdln +_wcreat +_wcscoll_l +_wcsdup +_wcsdup_dbg +_wcserror +_wcserror_s +_wcsftime_l +_wcsicmp +_wcsicmp_l +_wcsicoll +_wcsicoll_l +_wcslwr +_wcslwr_l +_wcslwr_s +_wcslwr_s_l +_wcsncoll +_wcsncoll_l +_wcsnicmp +_wcsnicmp_l +_wcsnicoll +_wcsnicoll_l +_wcsnset +_wcsnset_s +_wcsrev +_wcsset +_wcsset_s +_wcstod_l +_wcstoi64 +_wcstoi64_l +_wcstol_l +_wcstombs_l +_wcstombs_s_l +_wcstoui64 +_wcstoui64_l +_wcstoul_l +_wcsupr +_wcsupr_l +_wcsupr_s +_wcsupr_s_l +_wcsxfrm_l +_wctime +_wctime32 +_wctime32_s +_wctime64 +_wctime64_s +_wctomb_l +_wctomb_s_l +_wctype +_wenviron +_wexecl +_wexecle +_wexeclp +_wexeclpe +_wexecv +_wexecve +_wexecvp +_wexecvpe +_wfdopen +_wfindfirst +_wfindfirst64 +_wfindfirsti64 +_wfindnext +_wfindnext64 +_wfindnexti64 +_wfopen +_wfopen_s +_wfreopen +_wfreopen_s +_wfsopen +_wfullpath +_wfullpath_dbg +_wgetcwd +_wgetdcwd +_wgetenv +_wgetenv_s +_winmajor +_winminor +_winput_s +_winver +_wmakepath +_wmakepath_s +_wmkdir +_wmktemp +_wmktemp_s +_wopen +_woutput_s +_wperror +_wpgmptr +_wpopen +_wprintf_l +_wprintf_p +_wprintf_p_l +_wprintf_s_l +_wputenv +_wputenv_s +_wremove +_wrename +_write +_wrmdir +_wscanf_l +_wscanf_s_l +_wsearchenv +_wsearchenv_s +_wsetlocale +_wsopen +_wsopen_s +_wspawnl +_wspawnle +_wspawnlp +_wspawnlpe +_wspawnv +_wspawnve +_wspawnvp +_wspawnvpe +_wsplitpath +_wsplitpath_s +_wstat +_wstat64 +_wstati64 +_wstrdate +_wstrdate_s +_wstrtime +_wstrtime_s +_wsystem +_wtempnam +_wtempnam_dbg +_wtmpnam +_wtmpnam_s +_wtof +_wtof_l +_wtoi +_wtoi64 +_wtoi64_l +_wtoi_l +_wtol +_wtol_l +_wunlink +_wutime +_wutime32 +_wutime64 +_y0 +_y1 +_yn +abort +abs +acos +acosf +asctime +asctime_s +asin +asinf +atan +atan2 +atan2f +atanf +atexit +atof +atoi +atol +bsearch +bsearch_s +btowc +calloc +ceil +ceilf +clearerr +clearerr_s +clock +cos +cosf +cosh +coshf +ctime +difftime +div +exit +exp +expf +fabs +fclose +feof +ferror +fflush +fgetc +fgetpos +fgets +fgetwc +fgetws +floor +floorf +fmod +fmodf +fopen +fopen_s +fprintf +fprintf_s +fputc +fputs +fputwc +fputws +fread +free +freopen +freopen_s +frexp +fscanf +fscanf_s +fseek +fsetpos +ftell +fwprintf +fwprintf_s +fwrite +fwscanf +fwscanf_s +getc +getchar +getenv +getenv_s +gets +getwc +getwchar +gmtime +is_wctype +isalnum +isalpha +iscntrl +isdigit +isgraph +isleadbyte +islower +isprint +ispunct +isspace +isupper +iswalnum +iswalpha +iswascii +iswcntrl +iswctype +iswdigit +iswgraph +iswlower +iswprint +iswpunct +iswspace +iswupper +iswxdigit +isxdigit +labs +ldexp +ldiv +localeconv +localtime +log +log10 +log10f +logf +longjmp +malloc +mblen +mbrlen +mbrtowc +mbsdup_dbg +mbsrtowcs +mbsrtowcs_s +mbstowcs +mbstowcs_s +mbtowc +memchr +memcmp +memcpy +memcpy_s +memmove +memmove_s +memset +mktime +modf +modff +perror +pow +powf +printf +printf_s +putc +putchar +puts +putwc +putwchar +qsort +qsort_s +raise +rand +rand_s +realloc +remove +rename +rewind +scanf +scanf_s +setbuf +setjmp +setlocale +setvbuf +signal +sin +sinf +sinh +sinhf +sprintf +sprintf_s +sqrt +sqrtf +srand +sscanf +sscanf_s +strcat +strcat_s +strchr +strcmp +strcoll +strcpy +strcpy_s +strcspn +strerror +strerror_s +strftime +strlen +strncat +strncat_s +strncmp +strncpy +strncpy_s +strnlen +strpbrk +strrchr +strspn +strstr +strtod +strtok +strtok_s +strtol +strtoul +strxfrm +swprintf +swprintf_s +swscanf +swscanf_s +system +tan +tanf +tanh +tanhf +time +tmpfile +tmpfile_s +tmpnam +tmpnam_s +tolower +toupper +towlower +towupper +ungetc +ungetwc +utime +vfprintf +vfprintf_s +vfwprintf +vfwprintf_s +vprintf +vprintf_s +vsnprintf +vsprintf +vsprintf_s +vswprintf +vswprintf_s +vwprintf +vwprintf_s +wcrtomb +wcrtomb_s +wcscat +wcscat_s +wcschr +wcscmp +wcscoll +wcscpy +wcscpy_s +wcscspn +wcsftime +wcslen +wcsncat +wcsncat_s +wcsncmp +wcsncpy +wcsncpy_s +wcsnlen +wcspbrk +wcsrchr +wcsrtombs +wcsrtombs_s +wcsspn +wcsstr +wcstod +wcstok +wcstok_s +wcstol +wcstombs +wcstombs_s +wcstoul +wcsxfrm +wctob +wctomb +wctomb_s +wprintf +wprintf_s +wscanf +wscanf_s diff --git a/tcc/lib/user32.def b/tcc/lib/user32.def index f9863c54..a034dac2 100644 --- a/tcc/lib/user32.def +++ b/tcc/lib/user32.def @@ -1,658 +1,658 @@ -LIBRARY user32.dll - -EXPORTS -ActivateKeyboardLayout -AdjustWindowRect -AdjustWindowRectEx -AlignRects -AllowSetForegroundWindow -AnimateWindow -AnyPopup -AppendMenuA -AppendMenuW -ArrangeIconicWindows -AttachThreadInput -BeginDeferWindowPos -BeginPaint -BlockInput -BringWindowToTop -BroadcastSystemMessage -BroadcastSystemMessageA -BroadcastSystemMessageW -CalcChildScroll -CallMsgFilter -CallMsgFilterA -CallMsgFilterW -CallNextHookEx -CallWindowProcA -CallWindowProcW -CascadeChildWindows -CascadeWindows -ChangeClipboardChain -ChangeDisplaySettingsA -ChangeDisplaySettingsExA -ChangeDisplaySettingsExW -ChangeDisplaySettingsW -ChangeMenuA -ChangeMenuW -CharLowerA -CharLowerBuffA -CharLowerBuffW -CharLowerW -CharNextA -CharNextExA -CharNextExW -CharNextW -CharPrevA -CharPrevExA -CharPrevExW -CharPrevW -CharToOemA -CharToOemBuffA -CharToOemBuffW -CharToOemW -CharUpperA -CharUpperBuffA -CharUpperBuffW -CharUpperW -CheckDlgButton -CheckMenuItem -CheckMenuRadioItem -CheckRadioButton -ChildWindowFromPoint -ChildWindowFromPointEx -ClientThreadConnect -ClientToScreen -ClipCursor -CloseClipboard -CloseDesktop -CloseWindow -CloseWindowStation -CopyAcceleratorTableA -CopyAcceleratorTableW -CopyIcon -CopyImage -CopyRect -CountClipboardFormats -CreateAcceleratorTableA -CreateAcceleratorTableW -CreateCaret -CreateCursor -CreateDesktopA -CreateDesktopW -CreateDialogIndirectParamA -CreateDialogIndirectParamW -CreateDialogParamA -CreateDialogParamW -CreateIcon -CreateIconFromResource -CreateIconFromResourceEx -CreateIconIndirect -CreateMDIWindowA -CreateMDIWindowW -CreateMenu -CreatePopupMenu -CreateWindowExA -CreateWindowExW -CreateWindowStationA -CreateWindowStationW -DdeAbandonTransaction -DdeAccessData -DdeAddData -DdeClientTransaction -DdeCmpStringHandles -DdeConnect -DdeConnectList -DdeCreateDataHandle -DdeCreateStringHandleA -DdeCreateStringHandleW -DdeDisconnect -DdeDisconnectList -DdeEnableCallback -DdeFreeDataHandle -DdeFreeStringHandle -DdeGetData -DdeGetLastError -DdeImpersonateClient -DdeInitializeA -DdeInitializeW -DdeKeepStringHandle -DdeNameService -DdePostAdvise -DdeQueryConvInfo -DdeQueryNextServer -DdeQueryStringA -DdeQueryStringW -DdeReconnect -DdeSetQualityOfService -DdeSetUserHandle -DdeUnaccessData -DdeUninitialize -DefDlgProcA -DefDlgProcW -DefFrameProcA -DefFrameProcW -DefMDIChildProcA -DefMDIChildProcW -DefWindowProcA -DefWindowProcW -DeferWindowPos -DeleteMenu -DestroyAcceleratorTable -DestroyCaret -DestroyCursor -DestroyIcon -DestroyMenu -DestroyWindow -DialogBoxIndirectParamA -DialogBoxIndirectParamW -DialogBoxParamA -DialogBoxParamW -DispatchMessageA -DispatchMessageW -DlgDirListA -DlgDirListComboBoxA -DlgDirListComboBoxW -DlgDirListW -DlgDirSelectComboBoxExA -DlgDirSelectComboBoxExW -DlgDirSelectExA -DlgDirSelectExW -DragDetect -DragObject -DrawAnimatedRects -DrawCaption -DrawCaptionTempA -DrawCaptionTempW -DrawEdge -DrawFocusRect -DrawFrame -DrawFrameControl -DrawIcon -DrawIconEx -DrawMenuBar -DrawMenuBarTemp -DrawStateA -DrawStateW -DrawTextA -DrawTextExA -DrawTextExW -DrawTextW -EditWndProc -EmptyClipboard -EnableMenuItem -EnableScrollBar -EnableWindow -EndDeferWindowPos -EndDialog -EndMenu -EndPaint -EndTask -EnumChildWindows -EnumClipboardFormats -EnumDesktopWindows -EnumDesktopsA -EnumDesktopsW -EnumDisplayDevicesA -EnumDisplayDevicesW -EnumDisplayMonitors -EnumDisplaySettingsA -EnumDisplaySettingsExA -EnumDisplaySettingsExW -EnumDisplaySettingsW -EnumPropsA -EnumPropsExA -EnumPropsExW -EnumPropsW -EnumThreadWindows -EnumWindowStationsA -EnumWindowStationsW -EnumWindows -EqualRect -ExcludeUpdateRgn -ExitWindowsEx -FillRect -FindWindowA -FindWindowExA -FindWindowExW -FindWindowW -FlashWindow -FlashWindowEx -FrameRect -FreeDDElParam -GetActiveWindow -GetAltTabInfo -GetAncestor -GetAsyncKeyState -GetCapture -GetCaretBlinkTime -GetCaretPos -GetClassInfoA -GetClassInfoExA -GetClassInfoExW -GetClassInfoW -GetClassLongA -GetClassLongW -GetClassNameA -GetClassNameW -GetClassWord -GetClientRect -GetClipCursor -GetClipboardData -GetClipboardFormatNameA -GetClipboardFormatNameW -GetClipboardOwner -GetClipboardSequenceNumber -GetClipboardViewer -GetComboBoxInfo -GetCursor -GetCursorInfo -GetCursorPos -GetDC -GetDCEx -GetDesktopWindow -GetDialogBaseUnits -GetDlgCtrlID -GetDlgItem -GetDlgItemInt -GetDlgItemTextA -GetDlgItemTextW -GetDoubleClickTime -GetFocus -GetForegroundWindow -GetGUIThreadInfo -GetGuiResources -GetIconInfo -GetInputDesktop -GetInputState -GetInternalWindowPos -GetKBCodePage -GetKeyNameTextA -GetKeyNameTextW -GetKeyState -GetKeyboardLayout -GetKeyboardLayoutList -GetKeyboardLayoutNameA -GetKeyboardLayoutNameW -GetKeyboardState -GetKeyboardType -GetLastActivePopup -GetListBoxInfo -GetMenu -GetMenuBarInfo -GetMenuCheckMarkDimensions -GetMenuContextHelpId -GetMenuDefaultItem -GetMenuInfo -GetMenuItemCount -GetMenuItemID -GetMenuItemInfoA -GetMenuItemInfoW -GetMenuItemRect -GetMenuState -GetMenuStringA -GetMenuStringW -GetMessageA -GetMessageExtraInfo -GetMessagePos -GetMessageTime -GetMessageW -GetMonitorInfoA -GetMonitorInfoW -GetMouseMovePoints -GetMouseMovePointsEx -GetNextDlgGroupItem -GetNextDlgTabItem -GetNextQueueWindow -GetOpenClipboardWindow -GetParent -GetPriorityClipboardFormat -GetProcessDefaultLayout -GetProcessWindowStation -GetPropA -GetPropW -GetQueueStatus -GetScrollBarInfo -GetScrollInfo -GetScrollPos -GetScrollRange -GetShellWindow -GetSubMenu -GetSysColor -GetSysColorBrush -GetSystemMenu -GetSystemMetrics -GetTabbedTextExtentA -GetTabbedTextExtentW -GetThreadDesktop -GetTitleBarInfo -GetTopWindow -GetUpdateRect -GetUpdateRgn -GetUserObjectInformationA -GetUserObjectInformationW -GetUserObjectSecurity -GetWindow -GetWindowContextHelpId -GetWindowDC -GetWindowInfo -GetWindowLongPtrA -GetWindowLongPtrW -SetWindowLongPtrA -SetWindowLongPtrW -GetWindowLongA -GetWindowLongW -GetWindowModuleFileNameA -GetWindowModuleFileNameW -GetWindowPlacement -GetWindowRect -GetWindowRgn -GetWindowTextA -GetWindowTextLengthA -GetWindowTextLengthW -GetWindowTextW -GetWindowThreadProcessId -GetWindowWord -GrayStringA -GrayStringW -HasSystemSleepStarted -HideCaret -HiliteMenuItem -IMPGetIMEA -IMPGetIMEW -IMPQueryIMEA -IMPQueryIMEW -IMPSetIMEA -IMPSetIMEW -ImpersonateDdeClientWindow -InSendMessage -InSendMessageEx -InflateRect -InitSharedTable -InitTask -InsertMenuA -InsertMenuItemA -InsertMenuItemW -InsertMenuW -InternalGetWindowText -IntersectRect -InvalidateRect -InvalidateRgn -InvertRect -IsCharAlphaA -IsCharAlphaNumericA -IsCharAlphaNumericW -IsCharAlphaW -IsCharLowerA -IsCharLowerW -IsCharUpperA -IsCharUpperW -IsChild -IsClipboardFormatAvailable -IsDialogMessage -IsDialogMessageA -IsDialogMessageW -IsDlgButtonChecked -IsHungThread -IsIconic -IsMenu -IsRectEmpty -IsWindow -IsWindowEnabled -IsWindowUnicode -IsWindowVisible -IsZoomed -KillTimer -LoadAcceleratorsA -LoadAcceleratorsW -LoadBitmapA -LoadBitmapW -LoadCursorA -LoadCursorFromFileA -LoadCursorFromFileW -LoadCursorW -LoadIconA -LoadIconW -LoadImageA -LoadImageW -LoadKeyboardLayoutA -LoadKeyboardLayoutW -LoadMenuA -LoadMenuIndirectA -LoadMenuIndirectW -LoadMenuW -LoadStringA -LoadStringW -LockSetForegroundWindow -LockWindowStation -LockWindowUpdate -LookupIconIdFromDirectory -LookupIconIdFromDirectoryEx -MapDialogRect -MapVirtualKeyA -MapVirtualKeyExA -MapVirtualKeyExW -MapVirtualKeyW -MapWindowPoints -MenuItemFromPoint -MessageBeep -MessageBoxA -MessageBoxExA -MessageBoxExW -MessageBoxIndirectA -MessageBoxIndirectW -MessageBoxW -ModifyAccess -ModifyMenuA -ModifyMenuW -MonitorFromPoint -MonitorFromRect -MonitorFromWindow -MoveWindow -MsgWaitForMultipleObjects -MsgWaitForMultipleObjectsEx -NotifyWinEvent -OemKeyScan -OemToCharA -OemToCharBuffA -OemToCharBuffW -OemToCharW -OffsetRect -OpenClipboard -OpenDesktopA -OpenDesktopW -OpenIcon -OpenInputDesktop -OpenWindowStationA -OpenWindowStationW -PackDDElParam -PaintDesktop -PeekMessageA -PeekMessageW -PlaySoundEvent -PostMessageA -PostMessageW -PostQuitMessage -PostThreadMessageA -PostThreadMessageW -PtInRect -RealChildWindowFromPoint -RealGetWindowClass -RedrawWindow -RegisterClassA -RegisterClassExA -RegisterClassExW -RegisterClassW -RegisterClipboardFormatA -RegisterClipboardFormatW -RegisterDeviceNotificationA -RegisterDeviceNotificationW -RegisterHotKey -RegisterLogonProcess -RegisterNetworkCapabilities -RegisterSystemThread -RegisterTasklist -RegisterWindowMessageA -RegisterWindowMessageW -ReleaseCapture -ReleaseDC -RemoveMenu -RemovePropA -RemovePropW -ReplyMessage -ReuseDDElParam -ScreenToClient -ScrollDC -ScrollWindow -ScrollWindowEx -SendDlgItemMessageA -SendDlgItemMessageW -SendIMEMessageExA -SendIMEMessageExW -SendInput -SendMessageA -SendMessageCallbackA -SendMessageCallbackW -SendMessageTimeoutA -SendMessageTimeoutW -SendMessageW -SendNotifyMessageA -SendNotifyMessageW -SetActiveWindow -SetCapture -SetCaretBlinkTime -SetCaretPos -SetClassLongA -SetClassLongW -SetClassWord -SetClipboardData -SetClipboardViewer -SetCursor -SetCursorPos -SetDebugErrorLevel -SetDeskWallpaper -SetDesktopBitmap -SetDlgItemInt -SetDlgItemTextA -SetDlgItemTextW -SetDoubleClickTime -SetFocus -SetForegroundWindow -SetInternalWindowPos -SetKeyboardState -SetLastErrorEx -SetLogonNotifyWindow -SetMenu -SetMenuContextHelpId -SetMenuDefaultItem -SetMenuInfo -SetMenuItemBitmaps -SetMenuItemInfoA -SetMenuItemInfoW -SetMessageExtraInfo -SetMessageQueue -SetParent -SetProcessDefaultLayout -SetProcessWindowStation -SetPropA -SetPropW -SetRect -SetRectEmpty -SetScrollInfo -SetScrollPos -SetScrollRange -SetShellWindow -SetSysColors -SetSysColorsTemp -SetSystemCursor -SetThreadDesktop -SetTimer -SetUserObjectInformationA -SetUserObjectInformationW -SetUserObjectSecurity -SetWinEventHook -SetWindowContextHelpId -SetWindowFullScreenState -SetWindowLongA -SetWindowLongW -SetWindowPlacement -SetWindowPos -SetWindowRgn -SetWindowTextA -SetWindowTextW -SetWindowWord -SetWindowsHookA -SetWindowsHookExA -SetWindowsHookExW -SetWindowsHookW -ShowCaret -ShowCursor -ShowOwnedPopups -ShowScrollBar -ShowWindow -ShowWindowAsync -SubtractRect -SwapMouseButton -SwitchDesktop -SwitchToThisWindow -SysErrorBox -SystemParametersInfoA -SystemParametersInfoW -TabbedTextOutA -TabbedTextOutW -TileChildWindows -TileWindows -ToAscii -ToAsciiEx -ToUnicode -ToUnicodeEx -TrackMouseEvent -TrackPopupMenu -TrackPopupMenuEx -TranslateAccelerator -TranslateAcceleratorA -TranslateAcceleratorW -TranslateMDISysAccel -TranslateMessage -UnhookWinEvent -UnhookWindowsHook -UnhookWindowsHookEx -UnionRect -UnloadKeyboardLayout -UnlockWindowStation -UnpackDDElParam -UnregisterClassA -UnregisterClassW -UnregisterDeviceNotification -UnregisterHotKey -UpdateWindow -UserClientDllInitialize -UserIsSystemResumeAutomatic -UserSetDeviceHoldState -UserSignalProc -UserTickleTimer -ValidateRect -ValidateRgn -VkKeyScanA -VkKeyScanExA -VkKeyScanExW -VkKeyScanW -WINNLSEnableIME -WINNLSGetEnableStatus -WINNLSGetIMEHotkey -WNDPROC_CALLBACK -WaitForInputIdle -WaitMessage -WinHelpA -WinHelpW -WinOldAppHackoMatic -WindowFromDC -WindowFromPoint -YieldTask -_SetProcessDefaultLayout -keybd_event -mouse_event -wsprintfA -wsprintfW -wvsprintfA -wvsprintfW +LIBRARY user32.dll + +EXPORTS +ActivateKeyboardLayout +AdjustWindowRect +AdjustWindowRectEx +AlignRects +AllowSetForegroundWindow +AnimateWindow +AnyPopup +AppendMenuA +AppendMenuW +ArrangeIconicWindows +AttachThreadInput +BeginDeferWindowPos +BeginPaint +BlockInput +BringWindowToTop +BroadcastSystemMessage +BroadcastSystemMessageA +BroadcastSystemMessageW +CalcChildScroll +CallMsgFilter +CallMsgFilterA +CallMsgFilterW +CallNextHookEx +CallWindowProcA +CallWindowProcW +CascadeChildWindows +CascadeWindows +ChangeClipboardChain +ChangeDisplaySettingsA +ChangeDisplaySettingsExA +ChangeDisplaySettingsExW +ChangeDisplaySettingsW +ChangeMenuA +ChangeMenuW +CharLowerA +CharLowerBuffA +CharLowerBuffW +CharLowerW +CharNextA +CharNextExA +CharNextExW +CharNextW +CharPrevA +CharPrevExA +CharPrevExW +CharPrevW +CharToOemA +CharToOemBuffA +CharToOemBuffW +CharToOemW +CharUpperA +CharUpperBuffA +CharUpperBuffW +CharUpperW +CheckDlgButton +CheckMenuItem +CheckMenuRadioItem +CheckRadioButton +ChildWindowFromPoint +ChildWindowFromPointEx +ClientThreadConnect +ClientToScreen +ClipCursor +CloseClipboard +CloseDesktop +CloseWindow +CloseWindowStation +CopyAcceleratorTableA +CopyAcceleratorTableW +CopyIcon +CopyImage +CopyRect +CountClipboardFormats +CreateAcceleratorTableA +CreateAcceleratorTableW +CreateCaret +CreateCursor +CreateDesktopA +CreateDesktopW +CreateDialogIndirectParamA +CreateDialogIndirectParamW +CreateDialogParamA +CreateDialogParamW +CreateIcon +CreateIconFromResource +CreateIconFromResourceEx +CreateIconIndirect +CreateMDIWindowA +CreateMDIWindowW +CreateMenu +CreatePopupMenu +CreateWindowExA +CreateWindowExW +CreateWindowStationA +CreateWindowStationW +DdeAbandonTransaction +DdeAccessData +DdeAddData +DdeClientTransaction +DdeCmpStringHandles +DdeConnect +DdeConnectList +DdeCreateDataHandle +DdeCreateStringHandleA +DdeCreateStringHandleW +DdeDisconnect +DdeDisconnectList +DdeEnableCallback +DdeFreeDataHandle +DdeFreeStringHandle +DdeGetData +DdeGetLastError +DdeImpersonateClient +DdeInitializeA +DdeInitializeW +DdeKeepStringHandle +DdeNameService +DdePostAdvise +DdeQueryConvInfo +DdeQueryNextServer +DdeQueryStringA +DdeQueryStringW +DdeReconnect +DdeSetQualityOfService +DdeSetUserHandle +DdeUnaccessData +DdeUninitialize +DefDlgProcA +DefDlgProcW +DefFrameProcA +DefFrameProcW +DefMDIChildProcA +DefMDIChildProcW +DefWindowProcA +DefWindowProcW +DeferWindowPos +DeleteMenu +DestroyAcceleratorTable +DestroyCaret +DestroyCursor +DestroyIcon +DestroyMenu +DestroyWindow +DialogBoxIndirectParamA +DialogBoxIndirectParamW +DialogBoxParamA +DialogBoxParamW +DispatchMessageA +DispatchMessageW +DlgDirListA +DlgDirListComboBoxA +DlgDirListComboBoxW +DlgDirListW +DlgDirSelectComboBoxExA +DlgDirSelectComboBoxExW +DlgDirSelectExA +DlgDirSelectExW +DragDetect +DragObject +DrawAnimatedRects +DrawCaption +DrawCaptionTempA +DrawCaptionTempW +DrawEdge +DrawFocusRect +DrawFrame +DrawFrameControl +DrawIcon +DrawIconEx +DrawMenuBar +DrawMenuBarTemp +DrawStateA +DrawStateW +DrawTextA +DrawTextExA +DrawTextExW +DrawTextW +EditWndProc +EmptyClipboard +EnableMenuItem +EnableScrollBar +EnableWindow +EndDeferWindowPos +EndDialog +EndMenu +EndPaint +EndTask +EnumChildWindows +EnumClipboardFormats +EnumDesktopWindows +EnumDesktopsA +EnumDesktopsW +EnumDisplayDevicesA +EnumDisplayDevicesW +EnumDisplayMonitors +EnumDisplaySettingsA +EnumDisplaySettingsExA +EnumDisplaySettingsExW +EnumDisplaySettingsW +EnumPropsA +EnumPropsExA +EnumPropsExW +EnumPropsW +EnumThreadWindows +EnumWindowStationsA +EnumWindowStationsW +EnumWindows +EqualRect +ExcludeUpdateRgn +ExitWindowsEx +FillRect +FindWindowA +FindWindowExA +FindWindowExW +FindWindowW +FlashWindow +FlashWindowEx +FrameRect +FreeDDElParam +GetActiveWindow +GetAltTabInfo +GetAncestor +GetAsyncKeyState +GetCapture +GetCaretBlinkTime +GetCaretPos +GetClassInfoA +GetClassInfoExA +GetClassInfoExW +GetClassInfoW +GetClassLongA +GetClassLongW +GetClassNameA +GetClassNameW +GetClassWord +GetClientRect +GetClipCursor +GetClipboardData +GetClipboardFormatNameA +GetClipboardFormatNameW +GetClipboardOwner +GetClipboardSequenceNumber +GetClipboardViewer +GetComboBoxInfo +GetCursor +GetCursorInfo +GetCursorPos +GetDC +GetDCEx +GetDesktopWindow +GetDialogBaseUnits +GetDlgCtrlID +GetDlgItem +GetDlgItemInt +GetDlgItemTextA +GetDlgItemTextW +GetDoubleClickTime +GetFocus +GetForegroundWindow +GetGUIThreadInfo +GetGuiResources +GetIconInfo +GetInputDesktop +GetInputState +GetInternalWindowPos +GetKBCodePage +GetKeyNameTextA +GetKeyNameTextW +GetKeyState +GetKeyboardLayout +GetKeyboardLayoutList +GetKeyboardLayoutNameA +GetKeyboardLayoutNameW +GetKeyboardState +GetKeyboardType +GetLastActivePopup +GetListBoxInfo +GetMenu +GetMenuBarInfo +GetMenuCheckMarkDimensions +GetMenuContextHelpId +GetMenuDefaultItem +GetMenuInfo +GetMenuItemCount +GetMenuItemID +GetMenuItemInfoA +GetMenuItemInfoW +GetMenuItemRect +GetMenuState +GetMenuStringA +GetMenuStringW +GetMessageA +GetMessageExtraInfo +GetMessagePos +GetMessageTime +GetMessageW +GetMonitorInfoA +GetMonitorInfoW +GetMouseMovePoints +GetMouseMovePointsEx +GetNextDlgGroupItem +GetNextDlgTabItem +GetNextQueueWindow +GetOpenClipboardWindow +GetParent +GetPriorityClipboardFormat +GetProcessDefaultLayout +GetProcessWindowStation +GetPropA +GetPropW +GetQueueStatus +GetScrollBarInfo +GetScrollInfo +GetScrollPos +GetScrollRange +GetShellWindow +GetSubMenu +GetSysColor +GetSysColorBrush +GetSystemMenu +GetSystemMetrics +GetTabbedTextExtentA +GetTabbedTextExtentW +GetThreadDesktop +GetTitleBarInfo +GetTopWindow +GetUpdateRect +GetUpdateRgn +GetUserObjectInformationA +GetUserObjectInformationW +GetUserObjectSecurity +GetWindow +GetWindowContextHelpId +GetWindowDC +GetWindowInfo +GetWindowLongPtrA +GetWindowLongPtrW +SetWindowLongPtrA +SetWindowLongPtrW +GetWindowLongA +GetWindowLongW +GetWindowModuleFileNameA +GetWindowModuleFileNameW +GetWindowPlacement +GetWindowRect +GetWindowRgn +GetWindowTextA +GetWindowTextLengthA +GetWindowTextLengthW +GetWindowTextW +GetWindowThreadProcessId +GetWindowWord +GrayStringA +GrayStringW +HasSystemSleepStarted +HideCaret +HiliteMenuItem +IMPGetIMEA +IMPGetIMEW +IMPQueryIMEA +IMPQueryIMEW +IMPSetIMEA +IMPSetIMEW +ImpersonateDdeClientWindow +InSendMessage +InSendMessageEx +InflateRect +InitSharedTable +InitTask +InsertMenuA +InsertMenuItemA +InsertMenuItemW +InsertMenuW +InternalGetWindowText +IntersectRect +InvalidateRect +InvalidateRgn +InvertRect +IsCharAlphaA +IsCharAlphaNumericA +IsCharAlphaNumericW +IsCharAlphaW +IsCharLowerA +IsCharLowerW +IsCharUpperA +IsCharUpperW +IsChild +IsClipboardFormatAvailable +IsDialogMessage +IsDialogMessageA +IsDialogMessageW +IsDlgButtonChecked +IsHungThread +IsIconic +IsMenu +IsRectEmpty +IsWindow +IsWindowEnabled +IsWindowUnicode +IsWindowVisible +IsZoomed +KillTimer +LoadAcceleratorsA +LoadAcceleratorsW +LoadBitmapA +LoadBitmapW +LoadCursorA +LoadCursorFromFileA +LoadCursorFromFileW +LoadCursorW +LoadIconA +LoadIconW +LoadImageA +LoadImageW +LoadKeyboardLayoutA +LoadKeyboardLayoutW +LoadMenuA +LoadMenuIndirectA +LoadMenuIndirectW +LoadMenuW +LoadStringA +LoadStringW +LockSetForegroundWindow +LockWindowStation +LockWindowUpdate +LookupIconIdFromDirectory +LookupIconIdFromDirectoryEx +MapDialogRect +MapVirtualKeyA +MapVirtualKeyExA +MapVirtualKeyExW +MapVirtualKeyW +MapWindowPoints +MenuItemFromPoint +MessageBeep +MessageBoxA +MessageBoxExA +MessageBoxExW +MessageBoxIndirectA +MessageBoxIndirectW +MessageBoxW +ModifyAccess +ModifyMenuA +ModifyMenuW +MonitorFromPoint +MonitorFromRect +MonitorFromWindow +MoveWindow +MsgWaitForMultipleObjects +MsgWaitForMultipleObjectsEx +NotifyWinEvent +OemKeyScan +OemToCharA +OemToCharBuffA +OemToCharBuffW +OemToCharW +OffsetRect +OpenClipboard +OpenDesktopA +OpenDesktopW +OpenIcon +OpenInputDesktop +OpenWindowStationA +OpenWindowStationW +PackDDElParam +PaintDesktop +PeekMessageA +PeekMessageW +PlaySoundEvent +PostMessageA +PostMessageW +PostQuitMessage +PostThreadMessageA +PostThreadMessageW +PtInRect +RealChildWindowFromPoint +RealGetWindowClass +RedrawWindow +RegisterClassA +RegisterClassExA +RegisterClassExW +RegisterClassW +RegisterClipboardFormatA +RegisterClipboardFormatW +RegisterDeviceNotificationA +RegisterDeviceNotificationW +RegisterHotKey +RegisterLogonProcess +RegisterNetworkCapabilities +RegisterSystemThread +RegisterTasklist +RegisterWindowMessageA +RegisterWindowMessageW +ReleaseCapture +ReleaseDC +RemoveMenu +RemovePropA +RemovePropW +ReplyMessage +ReuseDDElParam +ScreenToClient +ScrollDC +ScrollWindow +ScrollWindowEx +SendDlgItemMessageA +SendDlgItemMessageW +SendIMEMessageExA +SendIMEMessageExW +SendInput +SendMessageA +SendMessageCallbackA +SendMessageCallbackW +SendMessageTimeoutA +SendMessageTimeoutW +SendMessageW +SendNotifyMessageA +SendNotifyMessageW +SetActiveWindow +SetCapture +SetCaretBlinkTime +SetCaretPos +SetClassLongA +SetClassLongW +SetClassWord +SetClipboardData +SetClipboardViewer +SetCursor +SetCursorPos +SetDebugErrorLevel +SetDeskWallpaper +SetDesktopBitmap +SetDlgItemInt +SetDlgItemTextA +SetDlgItemTextW +SetDoubleClickTime +SetFocus +SetForegroundWindow +SetInternalWindowPos +SetKeyboardState +SetLastErrorEx +SetLogonNotifyWindow +SetMenu +SetMenuContextHelpId +SetMenuDefaultItem +SetMenuInfo +SetMenuItemBitmaps +SetMenuItemInfoA +SetMenuItemInfoW +SetMessageExtraInfo +SetMessageQueue +SetParent +SetProcessDefaultLayout +SetProcessWindowStation +SetPropA +SetPropW +SetRect +SetRectEmpty +SetScrollInfo +SetScrollPos +SetScrollRange +SetShellWindow +SetSysColors +SetSysColorsTemp +SetSystemCursor +SetThreadDesktop +SetTimer +SetUserObjectInformationA +SetUserObjectInformationW +SetUserObjectSecurity +SetWinEventHook +SetWindowContextHelpId +SetWindowFullScreenState +SetWindowLongA +SetWindowLongW +SetWindowPlacement +SetWindowPos +SetWindowRgn +SetWindowTextA +SetWindowTextW +SetWindowWord +SetWindowsHookA +SetWindowsHookExA +SetWindowsHookExW +SetWindowsHookW +ShowCaret +ShowCursor +ShowOwnedPopups +ShowScrollBar +ShowWindow +ShowWindowAsync +SubtractRect +SwapMouseButton +SwitchDesktop +SwitchToThisWindow +SysErrorBox +SystemParametersInfoA +SystemParametersInfoW +TabbedTextOutA +TabbedTextOutW +TileChildWindows +TileWindows +ToAscii +ToAsciiEx +ToUnicode +ToUnicodeEx +TrackMouseEvent +TrackPopupMenu +TrackPopupMenuEx +TranslateAccelerator +TranslateAcceleratorA +TranslateAcceleratorW +TranslateMDISysAccel +TranslateMessage +UnhookWinEvent +UnhookWindowsHook +UnhookWindowsHookEx +UnionRect +UnloadKeyboardLayout +UnlockWindowStation +UnpackDDElParam +UnregisterClassA +UnregisterClassW +UnregisterDeviceNotification +UnregisterHotKey +UpdateWindow +UserClientDllInitialize +UserIsSystemResumeAutomatic +UserSetDeviceHoldState +UserSignalProc +UserTickleTimer +ValidateRect +ValidateRgn +VkKeyScanA +VkKeyScanExA +VkKeyScanExW +VkKeyScanW +WINNLSEnableIME +WINNLSGetEnableStatus +WINNLSGetIMEHotkey +WNDPROC_CALLBACK +WaitForInputIdle +WaitMessage +WinHelpA +WinHelpW +WinOldAppHackoMatic +WindowFromDC +WindowFromPoint +YieldTask +_SetProcessDefaultLayout +keybd_event +mouse_event +wsprintfA +wsprintfW +wvsprintfA +wvsprintfW diff --git a/tcc/libtcc/libtcc.def b/tcc/libtcc/libtcc.def index c4f357af..ae5751e5 100644 --- a/tcc/libtcc/libtcc.def +++ b/tcc/libtcc/libtcc.def @@ -1,41 +1,41 @@ -LIBRARY libtcc.dll - -EXPORTS -_tcc_error -_tcc_error_noabort -_tcc_warning -tcc_add_file -tcc_add_include_path -tcc_add_library -tcc_add_library_err -tcc_add_library_path -tcc_add_symbol -tcc_add_sysinclude_path -tcc_basename -tcc_compile_string -tcc_define_symbol -tcc_delete -tcc_enter_state -tcc_exit_state -tcc_fileextension -tcc_free -tcc_get_dllexports -tcc_get_error_func -tcc_get_error_opaque -tcc_get_symbol -tcc_list_symbols -tcc_malloc -tcc_mallocz -tcc_new -tcc_output_file -tcc_parse_args -tcc_print_stats -tcc_realloc -tcc_relocate -tcc_run -tcc_set_error_func -tcc_set_lib_path -tcc_set_options -tcc_set_output_type -tcc_strdup -tcc_undefine_symbol +LIBRARY libtcc.dll + +EXPORTS +_tcc_error +_tcc_error_noabort +_tcc_warning +tcc_add_file +tcc_add_include_path +tcc_add_library +tcc_add_library_err +tcc_add_library_path +tcc_add_symbol +tcc_add_sysinclude_path +tcc_basename +tcc_compile_string +tcc_define_symbol +tcc_delete +tcc_enter_state +tcc_exit_state +tcc_fileextension +tcc_free +tcc_get_dllexports +tcc_get_error_func +tcc_get_error_opaque +tcc_get_symbol +tcc_list_symbols +tcc_malloc +tcc_mallocz +tcc_new +tcc_output_file +tcc_parse_args +tcc_print_stats +tcc_realloc +tcc_relocate +tcc_run +tcc_set_error_func +tcc_set_lib_path +tcc_set_options +tcc_set_output_type +tcc_strdup +tcc_undefine_symbol diff --git a/tcc/libtcc/libtcc.h b/tcc/libtcc/libtcc.h index 3c4e3bc2..25d247a7 100644 --- a/tcc/libtcc/libtcc.h +++ b/tcc/libtcc/libtcc.h @@ -1,111 +1,111 @@ -#ifndef LIBTCC_H -#define LIBTCC_H - -#ifndef LIBTCCAPI -# define LIBTCCAPI -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct TCCState; - -typedef struct TCCState TCCState; - -typedef void (*TCCErrorFunc)(void *opaque, const char *msg); - -/* create a new TCC compilation context */ -LIBTCCAPI TCCState *tcc_new(void); - -/* free a TCC compilation context */ -LIBTCCAPI void tcc_delete(TCCState *s); - -/* set CONFIG_TCCDIR at runtime */ -LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); - -/* set error/warning display callback */ -LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func); - -/* return error/warning callback */ -LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s); - -/* return error/warning callback opaque pointer */ -LIBTCCAPI void *tcc_get_error_opaque(TCCState *s); - -/* set options as from command line (multiple supported) */ -LIBTCCAPI void tcc_set_options(TCCState *s, const char *str); - -/*****************************/ -/* preprocessor */ - -/* add include path */ -LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname); - -/* add in system include path */ -LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname); - -/* define preprocessor symbol 'sym'. value can be NULL, sym can be "sym=val" */ -LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value); - -/* undefine preprocess symbol 'sym' */ -LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym); - -/*****************************/ -/* compiling */ - -/* add a file (C file, dll, object, library, ld script). Return -1 if error. */ -LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); - -/* compile a string containing a C source. Return -1 if error. */ -LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); - -/*****************************/ -/* linking commands */ - -/* set output type. MUST BE CALLED before any compilation */ -LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); -#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */ -#define TCC_OUTPUT_EXE 2 /* executable file */ -#define TCC_OUTPUT_DLL 3 /* dynamic library */ -#define TCC_OUTPUT_OBJ 4 /* object file */ -#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */ - -/* equivalent to -Lpath option */ -LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); - -/* the library name is the same as the argument of the '-l' option */ -LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname); - -/* add a symbol to the compiled program */ -LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val); - -/* output an executable, library or object file. DO NOT call - tcc_relocate() before. */ -LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename); - -/* link and run main() function and return its value. DO NOT call - tcc_relocate() before. */ -LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); - -/* do all relocations (needed before using tcc_get_symbol()) */ -LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); -/* possible values for 'ptr': - - TCC_RELOCATE_AUTO : Allocate and manage memory internally - - NULL : return required memory size for the step below - - memory address : copy code to memory passed by the caller - returns -1 if error. */ -#define TCC_RELOCATE_AUTO (void*)1 - -/* return symbol value or NULL if not found */ -LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); - -/* return symbol value or NULL if not found */ -LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, - void (*symbol_cb)(void *ctx, const char *name, const void *val)); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef LIBTCC_H +#define LIBTCC_H + +#ifndef LIBTCCAPI +# define LIBTCCAPI +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct TCCState; + +typedef struct TCCState TCCState; + +typedef void (*TCCErrorFunc)(void *opaque, const char *msg); + +/* create a new TCC compilation context */ +LIBTCCAPI TCCState *tcc_new(void); + +/* free a TCC compilation context */ +LIBTCCAPI void tcc_delete(TCCState *s); + +/* set CONFIG_TCCDIR at runtime */ +LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); + +/* set error/warning display callback */ +LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func); + +/* return error/warning callback */ +LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s); + +/* return error/warning callback opaque pointer */ +LIBTCCAPI void *tcc_get_error_opaque(TCCState *s); + +/* set options as from command line (multiple supported) */ +LIBTCCAPI void tcc_set_options(TCCState *s, const char *str); + +/*****************************/ +/* preprocessor */ + +/* add include path */ +LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname); + +/* add in system include path */ +LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname); + +/* define preprocessor symbol 'sym'. value can be NULL, sym can be "sym=val" */ +LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value); + +/* undefine preprocess symbol 'sym' */ +LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym); + +/*****************************/ +/* compiling */ + +/* add a file (C file, dll, object, library, ld script). Return -1 if error. */ +LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); + +/* compile a string containing a C source. Return -1 if error. */ +LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); + +/*****************************/ +/* linking commands */ + +/* set output type. MUST BE CALLED before any compilation */ +LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); +#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */ +#define TCC_OUTPUT_EXE 2 /* executable file */ +#define TCC_OUTPUT_DLL 3 /* dynamic library */ +#define TCC_OUTPUT_OBJ 4 /* object file */ +#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */ + +/* equivalent to -Lpath option */ +LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); + +/* the library name is the same as the argument of the '-l' option */ +LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname); + +/* add a symbol to the compiled program */ +LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val); + +/* output an executable, library or object file. DO NOT call + tcc_relocate() before. */ +LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename); + +/* link and run main() function and return its value. DO NOT call + tcc_relocate() before. */ +LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); + +/* do all relocations (needed before using tcc_get_symbol()) */ +LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); +/* possible values for 'ptr': + - TCC_RELOCATE_AUTO : Allocate and manage memory internally + - NULL : return required memory size for the step below + - memory address : copy code to memory passed by the caller + returns -1 if error. */ +#define TCC_RELOCATE_AUTO (void*)1 + +/* return symbol value or NULL if not found */ +LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); + +/* return symbol value or NULL if not found */ +LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, + void (*symbol_cb)(void *ctx, const char *name, const void *val)); + +#ifdef __cplusplus +} +#endif + +#endif From 1ef481c4b2f906e629b6c19a9b73eb96926a26b6 Mon Sep 17 00:00:00 2001 From: gxia0005 Date: Fri, 1 May 2026 00:18:28 +1000 Subject: [PATCH 8/9] remove redundant method --- injected_code.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/injected_code.c b/injected_code.c index 2503c205..65e3ff2a 100644 --- a/injected_code.c +++ b/injected_code.c @@ -12923,7 +12923,6 @@ reset_district_state (bool reset_tile_map) { clear_all_tracked_workers (); deinit_district_images (); - deinit_district_command_buttons (); clear_highlighted_worker_tiles_for_districts (); FOR_TABLE_ENTRIES (tei, &is->district_building_prereqs) { @@ -21621,7 +21620,6 @@ patch_load_scenario (BIC * this, int edx, char * param_1, unsigned * param_2) // This scenario might use different mod art assets than the old one deinit_stackable_command_buttons (); - deinit_district_command_buttons (); deinit_disabled_command_buttons (); deinit_trade_scroll_buttons (); deinit_unit_rcm_icons (); From da876efb6d98441e2dde39f2371b8aefff07de82 Mon Sep 17 00:00:00 2001 From: gxia0005 Date: Sat, 2 May 2026 14:23:06 +1000 Subject: [PATCH 9/9] Feat: Add combat_experience condition to counter_rule - Added a new condition to counter_rule that checks the combat_experience of the unit. - This allows for more dynamic and challenging combat scenarios based on the unit's experience level. --- C3X.h | 14 +- default.c3x_config.ini | 18 ++- injected_code.c | 304 +++++++++++++++++++++++++++++++++++------ 3 files changed, 286 insertions(+), 50 deletions(-) diff --git a/C3X.h b/C3X.h index a72b4d99..d1d4a508 100644 --- a/C3X.h +++ b/C3X.h @@ -217,12 +217,14 @@ struct counter_rule { // Environment conditions (0 / false means no restriction) unsigned int terrain_mask; // SquareTypes mask, 0 = no restriction - bool only_in_city; - int district_id; // -1 = no restriction - char * district_name; // Resolved after district configs are loaded - bool ignore_terrain; // true = set defender terrain defense to 0 - - // Effects (percent values, 100 = no change) + bool only_in_city; + int district_id; // -1 = no restriction + char * district_name; // Resolved after district configs are loaded + unsigned int self_experience_mask; // 0 = no restriction + unsigned int enemy_experience_mask; // 0 = no restriction + bool ignore_terrain; // true = set defender terrain defense to 0 + + // Effects (percent values, 100 = no change) int self_atk_pct; int self_def_pct; int enemy_atk_pct; diff --git a/default.c3x_config.ini b/default.c3x_config.ini index 6216d2d0..aaf06bc8 100644 --- a/default.c3x_config.ini +++ b/default.c3x_config.ini @@ -902,7 +902,7 @@ override_barbarian_activity_level_for_scenario_maps = none ; types at the start of the game so they behave like normal MGLs spawned during a game. initialize_preplaced_scenario_leaders_as_mgls = false -enable_unit_counters = false +enable_unit_counters = true ; Civ 4 style best defender selection. ; When this is on (and enable_unit_counters is also true), every time an attack happens the engine picks the @@ -947,7 +947,11 @@ unit_group = [] ; ignore-terrain —— Ignores the enemy’s terrain defence bonus (sets their terrain bonus to zero) ; Can be used in conjunction with enemy-def; when used together, ignore-terrain takes precedence ; district district_name -- Only takes effect when the enemy is in a specified district (enable_districts must be enabled) -; District names are resolved after districts_config loads, so dynamic district names are supported. +; District names are resolved after districts_config loads, so dynamic district names are supported. +; self-exp exp_name -- Only takes effect when the self unit has one of the specified combat experiences. +; enemy-exp exp_name -- Only takes effect when the enemy unit has one of the specified combat experiences. +; Accepts one or more scenario experience names, numeric IDs(in standard game, 0 is represents conscript, 1 is represents regular and so on), +; or English aliases: conscript, regular, veteran, elite. ; ; 【Examples】 ; counter_rule = [ranged vs melee self-atk 125] @@ -963,11 +967,15 @@ unit_group = [] ; → When a Knight attacks any unit, its attack power is multiplied by 1.5 and it ignores the enemy’s terrain bonus. ; counter_rule = [Archer vs Swordsman self-atk 130 self-def 120] ; → When an archer attacks a swordsman: Archer’s attack power ×130% -; When a swordsman attacks an archer: Archer’s defence ×120% -; +; When a swordsman attacks an archer: Archer’s defence ×120% +; counter_rule = ["*" vs "*" self-exp veteran enemy-exp regular self-atk 125] +; -> When a veteran self unit attacks a regular enemy unit, its attack power is multiplied by 1.25. +; counter_rule = ["*" vs "*" self-exp 2 3 enemy-exp 0 1 self-atk 125] +; -> When self has experience ID 2 or 3, and enemy has experience ID 0 or 1, self attack is multiplied by 1.25. +; ; ───────────────────────────────────────────────────────────────────────────── -counter_rule = [] +counter_rule = ["*" vs "*" self-exp 2 3 enemy-exp 0 1 self-atk 2000] [==================] [=== AESTHETICS ===] diff --git a/injected_code.c b/injected_code.c index 65e3ff2a..539a2c10 100644 --- a/injected_code.c +++ b/injected_code.c @@ -7879,11 +7879,11 @@ unit_type_in_group (struct unit_counter_group * g, int type_id) } bool -unit_matches_counter_side (struct c3x_config * cfg, int type_id, - int match, char * group_name) -{ - if (match == UCM_ANY) - return true; +unit_matches_counter_side (struct c3x_config * cfg, int type_id, + int match, char * group_name) +{ + if (match == UCM_ANY) + return true; if (match == UCM_GROUP) { struct unit_counter_group * g = find_unit_counter_group_by_name (cfg, group_name); @@ -7891,14 +7891,210 @@ unit_matches_counter_side (struct c3x_config * cfg, int type_id, } // Direct unit type match: compare by name rather than exact ID so that // AI strategy duplicates (same name, different ID) are also matched. - return strcmp (p_bic_data->UnitTypes[match].Name, - p_bic_data->UnitTypes[type_id].Name) == 0; -} - -enum recognizable_parse_result -parse_unit_counter_group (char ** p_cursor, - struct error_line ** p_unrecognized_lines, - void * out_group) + return strcmp (p_bic_data->UnitTypes[match].Name, + p_bic_data->UnitTypes[type_id].Name) == 0; +} + +bool +slice_matches_str_case_insensitive (struct string_slice const * slice, char const * str) +{ + int str_len = strlen (str); + if (slice->len != str_len) + return false; + for (int i = 0; i < str_len; i++) + if (tolower ((unsigned char)slice->str[i]) != + tolower ((unsigned char)str[i])) + return false; + return true; +} + +bool +read_counter_rule_experience_value (struct string_slice const * exp_name, int * out_id) +{ + if ((exp_name == NULL) || (out_id == NULL)) + return false; + + struct string_slice trimmed = trim_string_slice (exp_name, 1); + if (trimmed.len <= 0) + return false; + + if (slice_matches_str (&trimmed, "*") || + slice_matches_str_case_insensitive (&trimmed, "any")) { + *out_id = -1; + return true; + } + + for (int i = 0; i < p_bic_data->CombatExperienceCount; i++) { + if (slice_matches_str_case_insensitive ( + &trimmed, p_bic_data->CombatExperience[i].Name.S)) { + *out_id = i; + return true; + } + } + + struct { + char const * name; + int rank; + } const default_aliases[] = { + { "conscript", 0 }, + { "regular", 1 }, + { "veteran", 2 }, + { "elite", 3 }, + }; + + for (int i = 0; i < ARRAY_LEN (default_aliases); i++) { + if (slice_matches_str_case_insensitive (&trimmed, default_aliases[i].name)) { + int count = p_bic_data->CombatExperienceCount; + if ((default_aliases[i].rank >= 0) && + (default_aliases[i].rank < count)) { + int * ids = malloc (count * sizeof ids[0]); + if (ids == NULL) + return false; + for (int j = 0; j < count; j++) + ids[j] = j; + for (int j = 0; j < count - 1; j++) { + for (int k = j + 1; k < count; k++) { + int j_id = ids[j], + k_id = ids[k], + j_hp = p_bic_data->CombatExperience[j_id].Base_Hit_Points, + k_hp = p_bic_data->CombatExperience[k_id].Base_Hit_Points; + if ((k_hp < j_hp) || ((k_hp == j_hp) && (k_id < j_id))) { + ids[j] = k_id; + ids[k] = j_id; + } + } + } + *out_id = ids[default_aliases[i].rank]; + free (ids); + return true; + } + } + } + + int id; + if (read_int (&trimmed, &id) && + (id >= 0) && + (id < p_bic_data->CombatExperienceCount)) { + *out_id = id; + return true; + } + + return false; +} + +bool +is_counter_rule_self_experience_token (struct string_slice const * token) +{ + return slice_matches_str (token, "self-exp") || + slice_matches_str (token, "self-experience") || + slice_matches_str (token, "self-combat-exp") || + slice_matches_str (token, "self-combat-experience") || + slice_matches_str (token, "self_combat_experience"); +} + +bool +is_counter_rule_enemy_experience_token (struct string_slice const * token) +{ + return slice_matches_str (token, "enemy-exp") || + slice_matches_str (token, "enemy-experience") || + slice_matches_str (token, "enemy-combat-exp") || + slice_matches_str (token, "enemy-combat-experience") || + slice_matches_str (token, "enemy_combat_experience"); +} + +bool +is_counter_rule_option_token (struct string_slice const * token) +{ + return slice_matches_str (token, "in-city") || + slice_matches_str (token, "ignore-terrain") || + slice_matches_str (token, "self-atk") || + slice_matches_str (token, "self-def") || + slice_matches_str (token, "enemy-atk") || + slice_matches_str (token, "enemy-def") || + slice_matches_str (token, "terrain") || + slice_matches_str (token, "district") || + is_counter_rule_self_experience_token (token) || + is_counter_rule_enemy_experience_token (token); +} + +enum recognizable_parse_result +read_counter_rule_experience_mask (char ** p_cursor, + struct error_line ** p_unrecognized_lines, + unsigned int * out_mask) +{ + char * cur = *p_cursor; + unsigned int mask = 0; + bool got_any_value = false; + bool unrestricted = false; + + while (1) { + char * before = cur; + struct string_slice exp_name; + if (! parse_string (&cur, &exp_name)) + break; + + if (is_counter_rule_option_token (&exp_name)) { + cur = before; + break; + } + + int exp_id; + if (! read_counter_rule_experience_value (&exp_name, &exp_id)) { + add_unrecognized_line (p_unrecognized_lines, &exp_name); + *p_cursor = cur; + return RPR_UNRECOGNIZED; + } + + got_any_value = true; + if (exp_id < 0) { + mask = 0; + unrestricted = true; + } else if (unrestricted) { + ; + } else if (exp_id < 8 * sizeof mask) { + mask |= 1U << exp_id; + } else { + add_unrecognized_line (p_unrecognized_lines, &exp_name); + *p_cursor = cur; + return RPR_UNRECOGNIZED; + } + } + + if (! got_any_value) { + *p_cursor = cur; + return RPR_PARSE_ERROR; + } + + *out_mask = mask; + *p_cursor = cur; + return RPR_OK; +} + +bool +counter_rule_experience_mask_matches (unsigned int mask, int experience_id) +{ + if (mask == 0) + return true; + if ((experience_id < 0) || (experience_id >= 8 * sizeof mask)) + return false; + return (mask & (1U << experience_id)) != 0; +} + +bool +counter_rule_experience_conditions_match (struct counter_rule * r, + int self_experience_id, + int enemy_experience_id) +{ + return counter_rule_experience_mask_matches (r->self_experience_mask, + self_experience_id) && + counter_rule_experience_mask_matches (r->enemy_experience_mask, + enemy_experience_id); +} + +enum recognizable_parse_result +parse_unit_counter_group (char ** p_cursor, + struct error_line ** p_unrecognized_lines, + void * out_group) { char * cur = *p_cursor; struct string_slice group_name; @@ -7954,15 +8150,17 @@ parse_counter_rule (char ** p_cursor, struct counter_rule * r = out_rule; *r = (struct counter_rule) { .attacker_match = UCM_ANY, - .defender_match = UCM_ANY, - .terrain_mask = 0, - .district_id = -1, - .district_name = NULL, - .self_atk_pct = 100, - .self_def_pct = 100, - .enemy_atk_pct = 100, - .enemy_def_pct = 100, - }; + .defender_match = UCM_ANY, + .terrain_mask = 0, + .district_id = -1, + .district_name = NULL, + .self_experience_mask = 0, + .enemy_experience_mask = 0, + .self_atk_pct = 100, + .self_def_pct = 100, + .enemy_atk_pct = 100, + .enemy_def_pct = 100, + }; if (! slice_matches_str (&attacker_name, "*")) { int type_id; @@ -7996,16 +8194,30 @@ parse_counter_rule (char ** p_cursor, } else if (slice_matches_str (&token, "self-def")) { if (! parse_int (&cur, &r->self_def_pct)) return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "enemy-atk")) { - if (! parse_int (&cur, &r->enemy_atk_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "enemy-def")) { - if (! parse_int (&cur, &r->enemy_def_pct)) - return RPR_PARSE_ERROR; - } else if (slice_matches_str (&token, "terrain")) { - struct string_slice terrain_name; - if (! parse_string (&cur, &terrain_name)) - return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "enemy-atk")) { + if (! parse_int (&cur, &r->enemy_atk_pct)) + return RPR_PARSE_ERROR; + } else if (slice_matches_str (&token, "enemy-def")) { + if (! parse_int (&cur, &r->enemy_def_pct)) + return RPR_PARSE_ERROR; + } else if (is_counter_rule_self_experience_token (&token)) { + enum recognizable_parse_result res = + read_counter_rule_experience_mask (&cur, + p_unrecognized_lines, + &r->self_experience_mask); + if (res != RPR_OK) + return res; + } else if (is_counter_rule_enemy_experience_token (&token)) { + enum recognizable_parse_result res = + read_counter_rule_experience_mask (&cur, + p_unrecognized_lines, + &r->enemy_experience_mask); + if (res != RPR_OK) + return res; + } else if (slice_matches_str (&token, "terrain")) { + struct string_slice terrain_name; + if (! parse_string (&cur, &terrain_name)) + return RPR_PARSE_ERROR; if (! read_counter_rule_terrain_mask (&terrain_name, &r->terrain_mask)) { add_unrecognized_line (p_unrecognized_lines, &terrain_name); return RPR_UNRECOGNIZED; @@ -8051,13 +8263,27 @@ apply_counter_rules (struct c3x_config * cfg, // Check reverse match (attacker=rule defender side, defender=rule attacker side) // Applied fields: self-def (rule attacker side is now defending), enemy-atk (rule defender side is now attacking) - bool reverse = unit_matches_counter_side (cfg, a_type, - r->defender_match, r->defender_group) && - unit_matches_counter_side (cfg, d_type, - r->attacker_match, r->attacker_group); - - if (! forward && ! reverse) - continue; + bool reverse = unit_matches_counter_side (cfg, a_type, + r->defender_match, r->defender_group) && + unit_matches_counter_side (cfg, d_type, + r->attacker_match, r->attacker_group); + + if (forward && + ! counter_rule_experience_conditions_match ( + r, + attacker->Body.Combat_Experience, + defender->Body.Combat_Experience)) + forward = false; + + if (reverse && + ! counter_rule_experience_conditions_match ( + r, + defender->Body.Combat_Experience, + attacker->Body.Combat_Experience)) + reverse = false; + + if (! forward && ! reverse) + continue; // Environment checks are based on the defender's tile if (r->only_in_city && ! in_city)